diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/changelog v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/changelog --- v4l-dvb-dkms-0~20110324.git235676.160/debian/changelog 2011-03-24 07:53:51.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/changelog 2011-06-25 16:18:19.000000000 +0000 @@ -1,4 +1,4 @@ -v4l-dvb-dkms (0~20110324.git235676.160) lucid; urgency=low +v4l-dvb-dkms (0~20110625.git255868.188~lucid) lucid; urgency=medium * Automatically packaged by DKMS. - -- Steffen Barszus Thu, 24 Mar 2011 08:53:51 +0100 + -- Steffen Barszus Sat, 25 Jun 2011 18:18:19 +0200 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/control v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/control --- v4l-dvb-dkms-0~20110324.git235676.160/debian/control 2011-03-24 07:53:51.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/control 2011-06-25 16:18:19.000000000 +0000 @@ -1,11 +1,13 @@ Source: v4l-dvb-dkms Section: misc Priority: optional -Maintainer: Dynamic Kernel Modules Support Team -Build-Depends: debhelper (>= 7), dkms +Maintainer: Steffen Barszus +Build-Depends: debhelper (>= 7), dkms, libproc-processtable-perl Standards-Version: 3.8.1 Package: v4l-dvb-dkms Architecture: all -Depends: dkms (>= 1.95), ${misc:Depends} +Depends: dkms (>= 1.95), ${misc:Depends}, libproc-processtable-perl +Conflicts: s2-liplianin-dkms +Replaces: s2-liplianin-dkms Description: v4l-dvb driver in DKMS format. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/prerm v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/prerm --- v4l-dvb-dkms-0~20110324.git235676.160/debian/prerm 2011-03-24 07:53:51.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/prerm 2011-06-25 16:18:19.000000000 +0000 @@ -1,7 +1,7 @@ #!/bin/sh NAME=v4l-dvb -VERSION=0~20110324.git235676.160 +VERSION=0~20110625.git255868.188~lucid set -e diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/rules v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/rules --- v4l-dvb-dkms-0~20110324.git235676.160/debian/rules 2011-03-24 07:53:51.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/rules 2011-06-25 16:18:19.000000000 +0000 @@ -6,7 +6,7 @@ DEB_NAME=v4l-dvb NAME=v4l-dvb -VERSION=0~20110324.git235676.160 +VERSION=0~20110625.git255868.188~lucid configure: configure-stamp configure-stamp: diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/all-wcprops v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/all-wcprops --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/all-wcprops 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/all-wcprops 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 66 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian -END -control -K 25 -svn:wc:ra_dav:version-url -V 74 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/control -END -dirs -K 25 -svn:wc:ra_dav:version-url -V 71 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/dirs -END -compat -K 25 -svn:wc:ra_dav:version-url -V 73 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/compat -END -postinst -K 25 -svn:wc:ra_dav:version-url -V 75 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/postinst -END -prerm -K 25 -svn:wc:ra_dav:version-url -V 72 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/prerm -END -changelog -K 25 -svn:wc:ra_dav:version-url -V 76 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/changelog -END -copyright -K 25 -svn:wc:ra_dav:version-url -V 76 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/copyright -END -rules -K 25 -svn:wc:ra_dav:version-url -V 72 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/rules -END -README.Debian -K 25 -svn:wc:ra_dav:version-url -V 80 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/README.Debian -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/entries v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/entries --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/entries 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/entries 1970-01-01 00:00:00.000000000 +0000 @@ -1,334 +0,0 @@ -10 - -dir -2682 -https://svn.origo.ethz.ch/yavdr/trunk/misc/make-dkms/templates/v4l-dvb/debian -https://svn.origo.ethz.ch/yavdr - - - -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - -4b10c2f0-612b-4a6c-a5b7-95c0885a526e - -control -file - - - - -2011-02-26T06:31:32.000000Z -932cd11859c7c153a8c458325e74497f -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -353 - -dirs -file - - - - -2011-02-26T06:31:32.000000Z -ea7a90f4a1be2e0054c3d4920c29e33f -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -8 - -compat -file - - - - -2011-02-26T06:31:32.000000Z -84bc3da1b3e33a18e8d5e1bdd7a18d7a -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -2 - -postinst -file - - - - -2011-02-26T06:31:32.000000Z -9332e9792ca4b1d4f79a2f79fe32b9a3 -2011-02-06T14:38:24.074405Z -2612 -steffen_b -has-props - - - - - - - - - - - - - - - - - - - - -1191 - -prerm -file - - - - -2011-02-26T06:31:32.000000Z -e7c0c39003edb2255d22a775efa907e5 -2011-02-06T14:38:24.074405Z -2612 -steffen_b -has-props - - - - - - - - - - - - - - - - - - - - -360 - -changelog -file - - - - -2011-02-26T06:31:32.000000Z -d967421f6c040076e29a8e3c594c9f1d -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -151 - -copyright -file - - - - -2011-02-26T06:31:32.000000Z -de471e376ba2c3886424b5c4649c42d6 -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -70 - -rules -file - - - - -2011-02-26T06:31:32.000000Z -c385ec9e8f6c6745ad9b9665c38cbd84 -2011-02-06T14:38:24.074405Z -2612 -steffen_b -has-props - - - - - - - - - - - - - - - - - - - - -881 - -README.Debian -file - - - - -2011-02-26T06:31:32.000000Z -6707f5716bc3a2d65fa1b05d81ba8add -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -150 - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/prop-base/postinst.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/prop-base/postinst.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/prop-base/postinst.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/prop-base/postinst.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -K 14 -svn:executable -V 1 -* -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/prop-base/prerm.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/prop-base/prerm.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/prop-base/prerm.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/prop-base/prerm.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -K 14 -svn:executable -V 1 -* -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/prop-base/rules.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/prop-base/rules.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/prop-base/rules.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/prop-base/rules.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -K 14 -svn:executable -V 1 -* -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/changelog.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/changelog.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/changelog.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/changelog.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -DEBIAN_PACKAGE-dkms (MODULE_VERSION) lucid; urgency=low - * Automatically packaged by DKMS. - - -- Steffen Barszus DATE_STAMP diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/compat.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/compat.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/compat.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/compat.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -7 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/control.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/control.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/control.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/control.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -Source: DEBIAN_PACKAGE-dkms -Section: misc -Priority: optional -Maintainer: Dynamic Kernel Modules Support Team -Build-Depends: debhelper (>= 7), dkms -Standards-Version: 3.8.1 - -Package: DEBIAN_PACKAGE-dkms -Architecture: all -Depends: dkms (>= 1.95), ${misc:Depends} -Description: DEBIAN_PACKAGE driver in DKMS format. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/copyright.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/copyright.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/copyright.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/copyright.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ - -This copyright has not been completed by the author of this package. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/dirs.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/dirs.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/dirs.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/dirs.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/src diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/postinst.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/postinst.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/postinst.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/postinst.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#!/bin/sh -# Copyright (C) 2002-2005 Flavio Stanchina -# Copyright (C) 2005-2006 Aric Cyr -# Copyright (C) 2007 Mario Limonciello -# Copyright (C) 2009 Alberto Milone - -set -e - -NAME=MODULE_NAME -PACKAGE_NAME=$NAME-dkms -CVERSION=`dpkg-query -W -f='${Version}' $PACKAGE_NAME | awk -F "-" '{print $1}' | cut -d\: -f2` -ARCH=`dpkg --print-architecture` - -dkms_configure () { - for POSTINST in /usr/lib/dkms/common.postinst "/usr/share/$PACKAGE_NAME/postinst"; do - if [ -f "$POSTINST" ]; then - "$POSTINST" "$NAME" "$CVERSION" "/usr/share/$PACKAGE_NAME" "$ARCH" "$2" - return $? - fi - echo "WARNING: $POSTINST does not exist." >&2 - done - echo "ERROR: DKMS version is too old and $PACKAGE_NAME was not" >&2 - echo "built with legacy DKMS support." >&2 - echo "You must either rebuild $PACKAGE_NAME with legacy postinst" >&2 - echo "support or upgrade DKMS to a more current version." >&2 - return 1 -} - -case "$1" in - configure) - dkms_configure - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/prerm.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/prerm.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/prerm.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/prerm.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -#!/bin/sh - -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -set -e - -case "$1" in - remove|upgrade|deconfigure) - if [ "`dkms status -m $NAME`" ]; then - dkms remove -m $NAME -v $VERSION --all - fi - ;; - - failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/README.Debian.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/README.Debian.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/README.Debian.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/README.Debian.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -MODULE_NAME DKMS module for Debian - -This package was automatically generated by the DKMS system, -for distribution on Debian based operating systems. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/rules.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/rules.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/debian/.svn/text-base/rules.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/debian/.svn/text-base/rules.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -DEB_NAME=DEBIAN_PACKAGE -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -configure: configure-stamp -configure-stamp: - dh_testdir - touch configure-stamp - - -build: build-stamp - -build-stamp: configure-stamp - dh_testdir - $(MAKE) - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-stamp configure-stamp - -$(MAKE) clean - dh_clean - -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs - $(MAKE) DESTDIR=$(CURDIR)/debian/$(DEB_NAME)-dkms NAME=$(NAME) VERSION=$(VERSION) install - -binary-arch: build install - -binary-indep: build install - dh_testdir - dh_testroot - dh_link - dh_strip - dh_compress - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install configure diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/dkms_binaries_only/dkms.conf v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_binaries_only/dkms.conf --- v4l-dvb-dkms-0~20110324.git235676.160/dkms_binaries_only/dkms.conf 2011-03-24 07:53:52.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_binaries_only/dkms.conf 2011-06-25 16:18:20.000000000 +0000 @@ -1,37 +1,45 @@ PACKAGE_NAME=v4l-dvb -PACKAGE_VERSION=0~20110324.git235676.160 +PACKAGE_VERSION=0~20110625.git255868.188~lucid AUTOINSTALL=y MAKE[0]="make -j5 VER=$kernelver" PATCH[0]=v2.6.37_dont_use_alloc_ordered_workqueue.patch PATCH_MATCH[0]="^2\.6\.([0-9]|[1-2][0-9]|3[2-6])[^0-9]" PATCH[1]=v2.6.36_input_getkeycode.patch PATCH_MATCH[1]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[2]=v2.6.35_work_handler.patch +PATCH[2]=v2.6.36_dvb_usb_input_getkeycode.patch PATCH_MATCH[2]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[3]=v2.6.35_vm_prev.patch -PATCH_MATCH[3]="^2\.6\.([0-9]|[1-2][0-9]|3[3-6])[^0-9]" -PATCH[4]=v2.6.35_i2c_new_probed_device.patch -PATCH_MATCH[4]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[5]=v2.6.35_firedtv_handle_fcp.patch +PATCH[3]=v2.6.35_work_handler.patch +PATCH_MATCH[3]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[4]=v2.6.35_vm_prev.patch +PATCH_MATCH[4]="^2\.6\.([0-9]|[1-2][0-9]|3[3-6])[^0-9]" +PATCH[5]=v2.6.35_i2c_new_probed_device.patch PATCH_MATCH[5]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[6]=v2.6.34_fix_define_warnings.patch +PATCH[6]=v2.6.35_firedtv_handle_fcp.patch PATCH_MATCH[6]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[7]=v2.6.34_dvb_net.patch +PATCH[7]=v2.6.34_fix_define_warnings.patch PATCH_MATCH[7]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[8]=v2.6.33_pvrusb2_sysfs.patch +PATCH[8]=v2.6.34_dvb_net.patch PATCH_MATCH[8]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[9]=v2.6.33_input_handlers_are_int.patch +PATCH[9]=v2.6.33_pvrusb2_sysfs.patch PATCH_MATCH[9]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[10]=v2.6.32_kfifo.patch +PATCH[10]=v2.6.33_input_handlers_are_int.patch PATCH_MATCH[10]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[11]=v2.6.31_nodename.patch -PATCH_MATCH[11]="^2\.6\.([0-9]|[1-2][0-9]|3[0-1])[^0-9]" -PATCH[12]=v2.6.31_device_type.patch +PATCH[11]=v2.6.32_kfifo.patch +PATCH_MATCH[11]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[12]=v2.6.31_nodename.patch PATCH_MATCH[12]="^2\.6\.([0-9]|[1-2][0-9]|3[0-1])[^0-9]" -PATCH[13]=v2-V4L-DVB-faster-DVB-S-lock-for-mantis-cards-using-stb0899-demod.patch -PATCH[14]=tt-s2-double-fix.patch -PATCH[15]=Refactor-Mantis-DMA-transfer-to-deliver-16Kb-TS-data-per-interrupt.patch -PATCH[16]=Avoid-unnecessary-data-copying-inside-dvb_dmx_swfilter_204-function.patch +PATCH[13]=v2.6.31_device_type.patch +PATCH_MATCH[13]="^2\.6\.([0-9]|[1-2][0-9]|3[0-1])[^0-9]" +PATCH[14]=v2-V4L-DVB-faster-DVB-S-lock-for-mantis-cards-using-stb0899-demod.patch +PATCH[15]=tt-s2-double-fix.patch +PATCH[16]=fixes_stb0899_not_locking.patch +PATCH[17]=fec34-fix.patch +PATCH[18]=anysee-keymap.patch +PATCH[19]=Refactor-Mantis-DMA-transfer-to-deliver-16Kb-TS-data-per-interrupt.patch +PATCH[20]=1090-add-driver-saa716x.patch +PATCH[21]=1010-saa716x_keymap.patch +PATCH[22]=0001-Add-remote-control-support-for-mantis.patch +PATCH[23]=0000-stv090x-ber-counter-scaled.patch BUILT_MODULE_NAME[0]=ir-jvc-decoder BUILT_MODULE_LOCATION[0]=./v4l DEST_MODULE_LOCATION[0]=/updates/dkms @@ -74,1278 +82,1263 @@ BUILT_MODULE_NAME[13]=zl10039 BUILT_MODULE_LOCATION[13]=./v4l DEST_MODULE_LOCATION[13]=/updates/dkms -BUILT_MODULE_NAME[14]=radio-gemtek +BUILT_MODULE_NAME[14]=rc-dntv-live-dvbt-pro BUILT_MODULE_LOCATION[14]=./v4l DEST_MODULE_LOCATION[14]=/updates/dkms -BUILT_MODULE_NAME[15]=rc-dntv-live-dvbt-pro +BUILT_MODULE_NAME[15]=rc-cinergy-1400 BUILT_MODULE_LOCATION[15]=./v4l DEST_MODULE_LOCATION[15]=/updates/dkms -BUILT_MODULE_NAME[16]=radio-maestro +BUILT_MODULE_NAME[16]=cx24110 BUILT_MODULE_LOCATION[16]=./v4l DEST_MODULE_LOCATION[16]=/updates/dkms -BUILT_MODULE_NAME[17]=rc-cinergy-1400 +BUILT_MODULE_NAME[17]=rc-pinnacle-pctv-hd BUILT_MODULE_LOCATION[17]=./v4l DEST_MODULE_LOCATION[17]=/updates/dkms -BUILT_MODULE_NAME[18]=cx24110 +BUILT_MODULE_NAME[18]=videobuf-vmalloc BUILT_MODULE_LOCATION[18]=./v4l DEST_MODULE_LOCATION[18]=/updates/dkms -BUILT_MODULE_NAME[19]=rc-pinnacle-pctv-hd +BUILT_MODULE_NAME[19]=rc-winfast-usbii-deluxe BUILT_MODULE_LOCATION[19]=./v4l DEST_MODULE_LOCATION[19]=/updates/dkms -BUILT_MODULE_NAME[20]=videobuf-vmalloc +BUILT_MODULE_NAME[20]=rc-core BUILT_MODULE_LOCATION[20]=./v4l DEST_MODULE_LOCATION[20]=/updates/dkms -BUILT_MODULE_NAME[21]=rc-winfast-usbii-deluxe +BUILT_MODULE_NAME[21]=dvb-usb-dw2102 BUILT_MODULE_LOCATION[21]=./v4l DEST_MODULE_LOCATION[21]=/updates/dkms -BUILT_MODULE_NAME[22]=rc-core +BUILT_MODULE_NAME[22]=wm8775 BUILT_MODULE_LOCATION[22]=./v4l DEST_MODULE_LOCATION[22]=/updates/dkms -BUILT_MODULE_NAME[23]=dvb-usb-dw2102 +BUILT_MODULE_NAME[23]=gspca_nw80x BUILT_MODULE_LOCATION[23]=./v4l DEST_MODULE_LOCATION[23]=/updates/dkms -BUILT_MODULE_NAME[24]=wm8775 +BUILT_MODULE_NAME[24]=ir-rc5-decoder BUILT_MODULE_LOCATION[24]=./v4l DEST_MODULE_LOCATION[24]=/updates/dkms -BUILT_MODULE_NAME[25]=radio-aimslab +BUILT_MODULE_NAME[25]=s5h1420 BUILT_MODULE_LOCATION[25]=./v4l DEST_MODULE_LOCATION[25]=/updates/dkms -BUILT_MODULE_NAME[26]=ir-rc5-decoder +BUILT_MODULE_NAME[26]=rc-avermedia-m733a-rm-k6 BUILT_MODULE_LOCATION[26]=./v4l DEST_MODULE_LOCATION[26]=/updates/dkms -BUILT_MODULE_NAME[27]=s5h1420 +BUILT_MODULE_NAME[27]=tda18271 BUILT_MODULE_LOCATION[27]=./v4l DEST_MODULE_LOCATION[27]=/updates/dkms -BUILT_MODULE_NAME[28]=rc-avermedia-m733a-rm-k6 +BUILT_MODULE_NAME[28]=rc-avermedia-m135a BUILT_MODULE_LOCATION[28]=./v4l DEST_MODULE_LOCATION[28]=/updates/dkms -BUILT_MODULE_NAME[29]=tda18271 +BUILT_MODULE_NAME[29]=rc-gotview7135 BUILT_MODULE_LOCATION[29]=./v4l DEST_MODULE_LOCATION[29]=/updates/dkms -BUILT_MODULE_NAME[30]=rc-avermedia-m135a +BUILT_MODULE_NAME[30]=vivi BUILT_MODULE_LOCATION[30]=./v4l DEST_MODULE_LOCATION[30]=/updates/dkms -BUILT_MODULE_NAME[31]=rc-gotview7135 +BUILT_MODULE_NAME[31]=ngene BUILT_MODULE_LOCATION[31]=./v4l DEST_MODULE_LOCATION[31]=/updates/dkms -BUILT_MODULE_NAME[32]=vivi +BUILT_MODULE_NAME[32]=smssdio BUILT_MODULE_LOCATION[32]=./v4l DEST_MODULE_LOCATION[32]=/updates/dkms -BUILT_MODULE_NAME[33]=ngene +BUILT_MODULE_NAME[33]=dvb-usb-m920x BUILT_MODULE_LOCATION[33]=./v4l DEST_MODULE_LOCATION[33]=/updates/dkms -BUILT_MODULE_NAME[34]=smssdio +BUILT_MODULE_NAME[34]=rc-behold-columbus BUILT_MODULE_LOCATION[34]=./v4l DEST_MODULE_LOCATION[34]=/updates/dkms -BUILT_MODULE_NAME[35]=dvb-usb-m920x +BUILT_MODULE_NAME[35]=em28xx-alsa BUILT_MODULE_LOCATION[35]=./v4l DEST_MODULE_LOCATION[35]=/updates/dkms -BUILT_MODULE_NAME[36]=rc-behold-columbus +BUILT_MODULE_NAME[36]=c-qcam BUILT_MODULE_LOCATION[36]=./v4l DEST_MODULE_LOCATION[36]=/updates/dkms -BUILT_MODULE_NAME[37]=videobuf2-dma-sg +BUILT_MODULE_NAME[37]=saa6588 BUILT_MODULE_LOCATION[37]=./v4l DEST_MODULE_LOCATION[37]=/updates/dkms -BUILT_MODULE_NAME[38]=em28xx-alsa +BUILT_MODULE_NAME[38]=isl6423 BUILT_MODULE_LOCATION[38]=./v4l DEST_MODULE_LOCATION[38]=/updates/dkms -BUILT_MODULE_NAME[39]=radio-terratec +BUILT_MODULE_NAME[39]=ttusb_dec BUILT_MODULE_LOCATION[39]=./v4l DEST_MODULE_LOCATION[39]=/updates/dkms -BUILT_MODULE_NAME[40]=c-qcam +BUILT_MODULE_NAME[40]=adv7180 BUILT_MODULE_LOCATION[40]=./v4l DEST_MODULE_LOCATION[40]=/updates/dkms -BUILT_MODULE_NAME[41]=saa6588 +BUILT_MODULE_NAME[41]=tea5767 BUILT_MODULE_LOCATION[41]=./v4l DEST_MODULE_LOCATION[41]=/updates/dkms -BUILT_MODULE_NAME[42]=isl6423 +BUILT_MODULE_NAME[42]=rc-real-audio-220-32-keys BUILT_MODULE_LOCATION[42]=./v4l DEST_MODULE_LOCATION[42]=/updates/dkms -BUILT_MODULE_NAME[43]=ttusb_dec +BUILT_MODULE_NAME[43]=noon010pc30 BUILT_MODULE_LOCATION[43]=./v4l DEST_MODULE_LOCATION[43]=/updates/dkms -BUILT_MODULE_NAME[44]=adv7180 +BUILT_MODULE_NAME[44]=rc-msi-digivox-iii BUILT_MODULE_LOCATION[44]=./v4l DEST_MODULE_LOCATION[44]=/updates/dkms -BUILT_MODULE_NAME[45]=tea5767 +BUILT_MODULE_NAME[45]=rc-tbs-nec BUILT_MODULE_LOCATION[45]=./v4l DEST_MODULE_LOCATION[45]=/updates/dkms -BUILT_MODULE_NAME[46]=rc-real-audio-220-32-keys +BUILT_MODULE_NAME[46]=bttv BUILT_MODULE_LOCATION[46]=./v4l DEST_MODULE_LOCATION[46]=/updates/dkms -BUILT_MODULE_NAME[47]=noon010pc30 +BUILT_MODULE_NAME[47]=lirc_dev BUILT_MODULE_LOCATION[47]=./v4l DEST_MODULE_LOCATION[47]=/updates/dkms -BUILT_MODULE_NAME[48]=rc-msi-digivox-iii +BUILT_MODULE_NAME[48]=rc-pixelview-002t BUILT_MODULE_LOCATION[48]=./v4l DEST_MODULE_LOCATION[48]=/updates/dkms -BUILT_MODULE_NAME[49]=rc-tbs-nec +BUILT_MODULE_NAME[49]=videobuf-core BUILT_MODULE_LOCATION[49]=./v4l DEST_MODULE_LOCATION[49]=/updates/dkms -BUILT_MODULE_NAME[50]=bttv +BUILT_MODULE_NAME[50]=rc-avermedia-rm-ks BUILT_MODULE_LOCATION[50]=./v4l DEST_MODULE_LOCATION[50]=/updates/dkms -BUILT_MODULE_NAME[51]=rc-pixelview-002t +BUILT_MODULE_NAME[51]=rc-behold BUILT_MODULE_LOCATION[51]=./v4l DEST_MODULE_LOCATION[51]=/updates/dkms -BUILT_MODULE_NAME[52]=videobuf-core +BUILT_MODULE_NAME[52]=gspca_spca1528 BUILT_MODULE_LOCATION[52]=./v4l DEST_MODULE_LOCATION[52]=/updates/dkms -BUILT_MODULE_NAME[53]=rc-avermedia-rm-ks +BUILT_MODULE_NAME[53]=rc-loopback BUILT_MODULE_LOCATION[53]=./v4l DEST_MODULE_LOCATION[53]=/updates/dkms -BUILT_MODULE_NAME[54]=rc-behold +BUILT_MODULE_NAME[54]=rc-tt-1500 BUILT_MODULE_LOCATION[54]=./v4l DEST_MODULE_LOCATION[54]=/updates/dkms -BUILT_MODULE_NAME[55]=gspca_spca1528 +BUILT_MODULE_NAME[55]=wm8739 BUILT_MODULE_LOCATION[55]=./v4l DEST_MODULE_LOCATION[55]=/updates/dkms -BUILT_MODULE_NAME[56]=rc-loopback +BUILT_MODULE_NAME[56]=mantis_core BUILT_MODULE_LOCATION[56]=./v4l DEST_MODULE_LOCATION[56]=/updates/dkms -BUILT_MODULE_NAME[57]=rc-tt-1500 +BUILT_MODULE_NAME[57]=stv0288 BUILT_MODULE_LOCATION[57]=./v4l DEST_MODULE_LOCATION[57]=/updates/dkms -BUILT_MODULE_NAME[58]=wm8739 +BUILT_MODULE_NAME[58]=ir-rc6-decoder BUILT_MODULE_LOCATION[58]=./v4l DEST_MODULE_LOCATION[58]=/updates/dkms -BUILT_MODULE_NAME[59]=mantis_core +BUILT_MODULE_NAME[59]=mt20xx BUILT_MODULE_LOCATION[59]=./v4l DEST_MODULE_LOCATION[59]=/updates/dkms -BUILT_MODULE_NAME[60]=stv0288 +BUILT_MODULE_NAME[60]=rc-asus-pc39 BUILT_MODULE_LOCATION[60]=./v4l DEST_MODULE_LOCATION[60]=/updates/dkms -BUILT_MODULE_NAME[61]=ir-rc6-decoder +BUILT_MODULE_NAME[61]=hdpvr BUILT_MODULE_LOCATION[61]=./v4l DEST_MODULE_LOCATION[61]=/updates/dkms -BUILT_MODULE_NAME[62]=pms +BUILT_MODULE_NAME[62]=dvb_dummy_fe BUILT_MODULE_LOCATION[62]=./v4l DEST_MODULE_LOCATION[62]=/updates/dkms -BUILT_MODULE_NAME[63]=mt20xx +BUILT_MODULE_NAME[63]=mantis BUILT_MODULE_LOCATION[63]=./v4l DEST_MODULE_LOCATION[63]=/updates/dkms -BUILT_MODULE_NAME[64]=rc-asus-pc39 +BUILT_MODULE_NAME[64]=bcm3510 BUILT_MODULE_LOCATION[64]=./v4l DEST_MODULE_LOCATION[64]=/updates/dkms -BUILT_MODULE_NAME[65]=hdpvr +BUILT_MODULE_NAME[65]=gspca_spca561 BUILT_MODULE_LOCATION[65]=./v4l DEST_MODULE_LOCATION[65]=/updates/dkms -BUILT_MODULE_NAME[66]=dvb_dummy_fe +BUILT_MODULE_NAME[66]=rc-kworld-plus-tv-analog BUILT_MODULE_LOCATION[66]=./v4l DEST_MODULE_LOCATION[66]=/updates/dkms -BUILT_MODULE_NAME[67]=mantis +BUILT_MODULE_NAME[67]=tda827x BUILT_MODULE_LOCATION[67]=./v4l DEST_MODULE_LOCATION[67]=/updates/dkms -BUILT_MODULE_NAME[68]=bcm3510 +BUILT_MODULE_NAME[68]=videobuf-dvb BUILT_MODULE_LOCATION[68]=./v4l DEST_MODULE_LOCATION[68]=/updates/dkms -BUILT_MODULE_NAME[69]=gspca_spca561 +BUILT_MODULE_NAME[69]=stv6110x BUILT_MODULE_LOCATION[69]=./v4l DEST_MODULE_LOCATION[69]=/updates/dkms -BUILT_MODULE_NAME[70]=rc-kworld-plus-tv-analog +BUILT_MODULE_NAME[70]=dvb-usb-umt-010 BUILT_MODULE_LOCATION[70]=./v4l DEST_MODULE_LOCATION[70]=/updates/dkms -BUILT_MODULE_NAME[71]=tda827x +BUILT_MODULE_NAME[71]=w9966 BUILT_MODULE_LOCATION[71]=./v4l DEST_MODULE_LOCATION[71]=/updates/dkms -BUILT_MODULE_NAME[72]=videobuf-dvb +BUILT_MODULE_NAME[72]=stv0367 BUILT_MODULE_LOCATION[72]=./v4l DEST_MODULE_LOCATION[72]=/updates/dkms -BUILT_MODULE_NAME[73]=stv6110x +BUILT_MODULE_NAME[73]=saa717x BUILT_MODULE_LOCATION[73]=./v4l DEST_MODULE_LOCATION[73]=/updates/dkms -BUILT_MODULE_NAME[74]=dvb-usb-umt-010 +BUILT_MODULE_NAME[74]=saa7146_vv BUILT_MODULE_LOCATION[74]=./v4l DEST_MODULE_LOCATION[74]=/updates/dkms -BUILT_MODULE_NAME[75]=w9966 +BUILT_MODULE_NAME[75]=xc5000 BUILT_MODULE_LOCATION[75]=./v4l DEST_MODULE_LOCATION[75]=/updates/dkms -BUILT_MODULE_NAME[76]=stv0367 +BUILT_MODULE_NAME[76]=tea5761 BUILT_MODULE_LOCATION[76]=./v4l DEST_MODULE_LOCATION[76]=/updates/dkms -BUILT_MODULE_NAME[77]=saa717x +BUILT_MODULE_NAME[77]=rc-videomate-tv-pvr BUILT_MODULE_LOCATION[77]=./v4l DEST_MODULE_LOCATION[77]=/updates/dkms -BUILT_MODULE_NAME[78]=saa7146_vv +BUILT_MODULE_NAME[78]=ds3000 BUILT_MODULE_LOCATION[78]=./v4l DEST_MODULE_LOCATION[78]=/updates/dkms -BUILT_MODULE_NAME[79]=xc5000 +BUILT_MODULE_NAME[79]=rc-flyvideo BUILT_MODULE_LOCATION[79]=./v4l DEST_MODULE_LOCATION[79]=/updates/dkms -BUILT_MODULE_NAME[80]=tea5761 +BUILT_MODULE_NAME[80]=zl10353 BUILT_MODULE_LOCATION[80]=./v4l DEST_MODULE_LOCATION[80]=/updates/dkms -BUILT_MODULE_NAME[81]=rc-videomate-tv-pvr +BUILT_MODULE_NAME[81]=adv7170 BUILT_MODULE_LOCATION[81]=./v4l DEST_MODULE_LOCATION[81]=/updates/dkms -BUILT_MODULE_NAME[82]=ds3000 +BUILT_MODULE_NAME[82]=uvcvideo BUILT_MODULE_LOCATION[82]=./v4l DEST_MODULE_LOCATION[82]=/updates/dkms -BUILT_MODULE_NAME[83]=rc-flyvideo +BUILT_MODULE_NAME[83]=meye BUILT_MODULE_LOCATION[83]=./v4l DEST_MODULE_LOCATION[83]=/updates/dkms -BUILT_MODULE_NAME[84]=zl10353 +BUILT_MODULE_NAME[84]=adv7343 BUILT_MODULE_LOCATION[84]=./v4l DEST_MODULE_LOCATION[84]=/updates/dkms -BUILT_MODULE_NAME[85]=adv7170 +BUILT_MODULE_NAME[85]=tcm825x BUILT_MODULE_LOCATION[85]=./v4l DEST_MODULE_LOCATION[85]=/updates/dkms -BUILT_MODULE_NAME[86]=uvcvideo +BUILT_MODULE_NAME[86]=stb6100 BUILT_MODULE_LOCATION[86]=./v4l DEST_MODULE_LOCATION[86]=/updates/dkms -BUILT_MODULE_NAME[87]=meye +BUILT_MODULE_NAME[87]=mxb BUILT_MODULE_LOCATION[87]=./v4l DEST_MODULE_LOCATION[87]=/updates/dkms -BUILT_MODULE_NAME[88]=adv7343 +BUILT_MODULE_NAME[88]=rc-winfast BUILT_MODULE_LOCATION[88]=./v4l DEST_MODULE_LOCATION[88]=/updates/dkms -BUILT_MODULE_NAME[89]=tcm825x +BUILT_MODULE_NAME[89]=gspca_vc032x BUILT_MODULE_LOCATION[89]=./v4l DEST_MODULE_LOCATION[89]=/updates/dkms -BUILT_MODULE_NAME[90]=stb6100 +BUILT_MODULE_NAME[90]=cx88-dvb BUILT_MODULE_LOCATION[90]=./v4l DEST_MODULE_LOCATION[90]=/updates/dkms -BUILT_MODULE_NAME[91]=mxb +BUILT_MODULE_NAME[91]=gspca_sq930x BUILT_MODULE_LOCATION[91]=./v4l DEST_MODULE_LOCATION[91]=/updates/dkms -BUILT_MODULE_NAME[92]=rc-winfast +BUILT_MODULE_NAME[92]=rc-imon-pad BUILT_MODULE_LOCATION[92]=./v4l DEST_MODULE_LOCATION[92]=/updates/dkms -BUILT_MODULE_NAME[93]=gspca_vc032x +BUILT_MODULE_NAME[93]=rc-pv951 BUILT_MODULE_LOCATION[93]=./v4l DEST_MODULE_LOCATION[93]=/updates/dkms -BUILT_MODULE_NAME[94]=cx88-dvb +BUILT_MODULE_NAME[94]=em28xx BUILT_MODULE_LOCATION[94]=./v4l DEST_MODULE_LOCATION[94]=/updates/dkms -BUILT_MODULE_NAME[95]=gspca_sq930x +BUILT_MODULE_NAME[95]=gspca_benq BUILT_MODULE_LOCATION[95]=./v4l DEST_MODULE_LOCATION[95]=/updates/dkms -BUILT_MODULE_NAME[96]=rc-imon-pad +BUILT_MODULE_NAME[96]=gspca_spca505 BUILT_MODULE_LOCATION[96]=./v4l DEST_MODULE_LOCATION[96]=/updates/dkms -BUILT_MODULE_NAME[97]=rc-pv951 +BUILT_MODULE_NAME[97]=rc-evga-indtube BUILT_MODULE_LOCATION[97]=./v4l DEST_MODULE_LOCATION[97]=/updates/dkms -BUILT_MODULE_NAME[98]=em28xx +BUILT_MODULE_NAME[98]=tda18218 BUILT_MODULE_LOCATION[98]=./v4l DEST_MODULE_LOCATION[98]=/updates/dkms -BUILT_MODULE_NAME[99]=gspca_benq +BUILT_MODULE_NAME[99]=dvb-usb-ce6230 BUILT_MODULE_LOCATION[99]=./v4l DEST_MODULE_LOCATION[99]=/updates/dkms -BUILT_MODULE_NAME[100]=gspca_spca505 +BUILT_MODULE_NAME[100]=tveeprom BUILT_MODULE_LOCATION[100]=./v4l DEST_MODULE_LOCATION[100]=/updates/dkms -BUILT_MODULE_NAME[101]=radio-miropcm20 +BUILT_MODULE_NAME[101]=cpia2 BUILT_MODULE_LOCATION[101]=./v4l DEST_MODULE_LOCATION[101]=/updates/dkms -BUILT_MODULE_NAME[102]=rc-evga-indtube +BUILT_MODULE_NAME[102]=radio-usb-si470x BUILT_MODULE_LOCATION[102]=./v4l DEST_MODULE_LOCATION[102]=/updates/dkms -BUILT_MODULE_NAME[103]=tda18218 +BUILT_MODULE_NAME[103]=rc-tivo BUILT_MODULE_LOCATION[103]=./v4l DEST_MODULE_LOCATION[103]=/updates/dkms -BUILT_MODULE_NAME[104]=dvb-usb-ce6230 +BUILT_MODULE_NAME[104]=gspca_stv06xx BUILT_MODULE_LOCATION[104]=./v4l DEST_MODULE_LOCATION[104]=/updates/dkms -BUILT_MODULE_NAME[105]=tveeprom +BUILT_MODULE_NAME[105]=cx24113 BUILT_MODULE_LOCATION[105]=./v4l DEST_MODULE_LOCATION[105]=/updates/dkms -BUILT_MODULE_NAME[106]=cpia2 +BUILT_MODULE_NAME[106]=dsbr100 BUILT_MODULE_LOCATION[106]=./v4l DEST_MODULE_LOCATION[106]=/updates/dkms -BUILT_MODULE_NAME[107]=radio-usb-si470x +BUILT_MODULE_NAME[107]=gspca_stk014 BUILT_MODULE_LOCATION[107]=./v4l DEST_MODULE_LOCATION[107]=/updates/dkms -BUILT_MODULE_NAME[108]=gspca_stv06xx +BUILT_MODULE_NAME[108]=pvrusb2 BUILT_MODULE_LOCATION[108]=./v4l DEST_MODULE_LOCATION[108]=/updates/dkms -BUILT_MODULE_NAME[109]=cx24113 +BUILT_MODULE_NAME[109]=poseidon BUILT_MODULE_LOCATION[109]=./v4l DEST_MODULE_LOCATION[109]=/updates/dkms -BUILT_MODULE_NAME[110]=dsbr100 +BUILT_MODULE_NAME[110]=dvb-usb-dibusb-mb BUILT_MODULE_LOCATION[110]=./v4l DEST_MODULE_LOCATION[110]=/updates/dkms -BUILT_MODULE_NAME[111]=gspca_stk014 +BUILT_MODULE_NAME[111]=saa7127 BUILT_MODULE_LOCATION[111]=./v4l DEST_MODULE_LOCATION[111]=/updates/dkms -BUILT_MODULE_NAME[112]=pvrusb2 +BUILT_MODULE_NAME[112]=cx231xx-alsa BUILT_MODULE_LOCATION[112]=./v4l DEST_MODULE_LOCATION[112]=/updates/dkms -BUILT_MODULE_NAME[113]=snd-tea575x-tuner +BUILT_MODULE_NAME[113]=b2c2-flexcop BUILT_MODULE_LOCATION[113]=./v4l DEST_MODULE_LOCATION[113]=/updates/dkms -BUILT_MODULE_NAME[114]=poseidon +BUILT_MODULE_NAME[114]=gspca_sn9c20x BUILT_MODULE_LOCATION[114]=./v4l DEST_MODULE_LOCATION[114]=/updates/dkms -BUILT_MODULE_NAME[115]=dvb-usb-dibusb-mb +BUILT_MODULE_NAME[115]=tda7432 BUILT_MODULE_LOCATION[115]=./v4l DEST_MODULE_LOCATION[115]=/updates/dkms -BUILT_MODULE_NAME[116]=saa7127 +BUILT_MODULE_NAME[116]=cxd2820r BUILT_MODULE_LOCATION[116]=./v4l DEST_MODULE_LOCATION[116]=/updates/dkms -BUILT_MODULE_NAME[117]=radio-sf16fmi +BUILT_MODULE_NAME[117]=rc-digitalnow-tinytwin BUILT_MODULE_LOCATION[117]=./v4l DEST_MODULE_LOCATION[117]=/updates/dkms -BUILT_MODULE_NAME[118]=cx231xx-alsa +BUILT_MODULE_NAME[118]=tda8261 BUILT_MODULE_LOCATION[118]=./v4l DEST_MODULE_LOCATION[118]=/updates/dkms -BUILT_MODULE_NAME[119]=b2c2-flexcop +BUILT_MODULE_NAME[119]=rc-avermedia-a16d BUILT_MODULE_LOCATION[119]=./v4l DEST_MODULE_LOCATION[119]=/updates/dkms -BUILT_MODULE_NAME[120]=gspca_sn9c20x +BUILT_MODULE_NAME[120]=gspca_ov534_9 BUILT_MODULE_LOCATION[120]=./v4l DEST_MODULE_LOCATION[120]=/updates/dkms -BUILT_MODULE_NAME[121]=tda7432 +BUILT_MODULE_NAME[121]=rc-manli BUILT_MODULE_LOCATION[121]=./v4l DEST_MODULE_LOCATION[121]=/updates/dkms -BUILT_MODULE_NAME[122]=rc-digitalnow-tinytwin +BUILT_MODULE_NAME[122]=sp8870 BUILT_MODULE_LOCATION[122]=./v4l DEST_MODULE_LOCATION[122]=/updates/dkms -BUILT_MODULE_NAME[123]=tda8261 +BUILT_MODULE_NAME[123]=rc-pixelview-new BUILT_MODULE_LOCATION[123]=./v4l DEST_MODULE_LOCATION[123]=/updates/dkms -BUILT_MODULE_NAME[124]=rc-avermedia-a16d +BUILT_MODULE_NAME[124]=videocodec BUILT_MODULE_LOCATION[124]=./v4l DEST_MODULE_LOCATION[124]=/updates/dkms -BUILT_MODULE_NAME[125]=gspca_ov534_9 +BUILT_MODULE_NAME[125]=rc-digittrade BUILT_MODULE_LOCATION[125]=./v4l DEST_MODULE_LOCATION[125]=/updates/dkms -BUILT_MODULE_NAME[126]=rc-manli +BUILT_MODULE_NAME[126]=gspca_gl860 BUILT_MODULE_LOCATION[126]=./v4l DEST_MODULE_LOCATION[126]=/updates/dkms -BUILT_MODULE_NAME[127]=sp8870 +BUILT_MODULE_NAME[127]=dvb-usb-technisat-usb2 BUILT_MODULE_LOCATION[127]=./v4l DEST_MODULE_LOCATION[127]=/updates/dkms -BUILT_MODULE_NAME[128]=rc-pixelview-new +BUILT_MODULE_NAME[128]=winbond-cir BUILT_MODULE_LOCATION[128]=./v4l DEST_MODULE_LOCATION[128]=/updates/dkms -BUILT_MODULE_NAME[129]=videocodec +BUILT_MODULE_NAME[129]=rc-encore-enltv BUILT_MODULE_LOCATION[129]=./v4l DEST_MODULE_LOCATION[129]=/updates/dkms -BUILT_MODULE_NAME[130]=rc-digittrade +BUILT_MODULE_NAME[130]=gspca_main BUILT_MODULE_LOCATION[130]=./v4l DEST_MODULE_LOCATION[130]=/updates/dkms -BUILT_MODULE_NAME[131]=gspca_gl860 +BUILT_MODULE_NAME[131]=rc-adstech-dvb-t-pci BUILT_MODULE_LOCATION[131]=./v4l DEST_MODULE_LOCATION[131]=/updates/dkms -BUILT_MODULE_NAME[132]=dvb-usb-technisat-usb2 +BUILT_MODULE_NAME[132]=stb6000 BUILT_MODULE_LOCATION[132]=./v4l DEST_MODULE_LOCATION[132]=/updates/dkms -BUILT_MODULE_NAME[133]=winbond-cir +BUILT_MODULE_NAME[133]=rc-pinnacle-color BUILT_MODULE_LOCATION[133]=./v4l DEST_MODULE_LOCATION[133]=/updates/dkms -BUILT_MODULE_NAME[134]=rc-encore-enltv +BUILT_MODULE_NAME[134]=gspca_sonixj BUILT_MODULE_LOCATION[134]=./v4l DEST_MODULE_LOCATION[134]=/updates/dkms -BUILT_MODULE_NAME[135]=gspca_main +BUILT_MODULE_NAME[135]=radio-mr800 BUILT_MODULE_LOCATION[135]=./v4l DEST_MODULE_LOCATION[135]=/updates/dkms -BUILT_MODULE_NAME[136]=rc-adstech-dvb-t-pci +BUILT_MODULE_NAME[136]=dvb-usb-vp702x BUILT_MODULE_LOCATION[136]=./v4l DEST_MODULE_LOCATION[136]=/updates/dkms -BUILT_MODULE_NAME[137]=stb6000 +BUILT_MODULE_NAME[137]=zr36016 BUILT_MODULE_LOCATION[137]=./v4l DEST_MODULE_LOCATION[137]=/updates/dkms -BUILT_MODULE_NAME[138]=rc-pinnacle-color +BUILT_MODULE_NAME[138]=rc-rc6-mce BUILT_MODULE_LOCATION[138]=./v4l DEST_MODULE_LOCATION[138]=/updates/dkms -BUILT_MODULE_NAME[139]=gspca_sonixj +BUILT_MODULE_NAME[139]=rc-npgtech BUILT_MODULE_LOCATION[139]=./v4l DEST_MODULE_LOCATION[139]=/updates/dkms -BUILT_MODULE_NAME[140]=radio-mr800 +BUILT_MODULE_NAME[140]=cs53l32a BUILT_MODULE_LOCATION[140]=./v4l DEST_MODULE_LOCATION[140]=/updates/dkms -BUILT_MODULE_NAME[141]=dvb-usb-vp702x +BUILT_MODULE_NAME[141]=dvb-usb-af9015 BUILT_MODULE_LOCATION[141]=./v4l DEST_MODULE_LOCATION[141]=/updates/dkms -BUILT_MODULE_NAME[142]=zr36016 +BUILT_MODULE_NAME[142]=s921 BUILT_MODULE_LOCATION[142]=./v4l DEST_MODULE_LOCATION[142]=/updates/dkms -BUILT_MODULE_NAME[143]=rc-rc6-mce +BUILT_MODULE_NAME[143]=mt2131 BUILT_MODULE_LOCATION[143]=./v4l DEST_MODULE_LOCATION[143]=/updates/dkms -BUILT_MODULE_NAME[144]=rc-npgtech +BUILT_MODULE_NAME[144]=rc-dib0700-rc5 BUILT_MODULE_LOCATION[144]=./v4l DEST_MODULE_LOCATION[144]=/updates/dkms -BUILT_MODULE_NAME[145]=drx397xD +BUILT_MODULE_NAME[145]=dvb-usb-cxusb BUILT_MODULE_LOCATION[145]=./v4l DEST_MODULE_LOCATION[145]=/updates/dkms -BUILT_MODULE_NAME[146]=cs53l32a +BUILT_MODULE_NAME[146]=imon BUILT_MODULE_LOCATION[146]=./v4l DEST_MODULE_LOCATION[146]=/updates/dkms -BUILT_MODULE_NAME[147]=dvb-usb-af9015 +BUILT_MODULE_NAME[147]=ves1820 BUILT_MODULE_LOCATION[147]=./v4l DEST_MODULE_LOCATION[147]=/updates/dkms -BUILT_MODULE_NAME[148]=s921 +BUILT_MODULE_NAME[148]=dvb-usb-vp7045 BUILT_MODULE_LOCATION[148]=./v4l DEST_MODULE_LOCATION[148]=/updates/dkms -BUILT_MODULE_NAME[149]=mt2131 +BUILT_MODULE_NAME[149]=gspca_sn9c2028 BUILT_MODULE_LOCATION[149]=./v4l DEST_MODULE_LOCATION[149]=/updates/dkms -BUILT_MODULE_NAME[150]=rc-dib0700-rc5 +BUILT_MODULE_NAME[150]=ves1x93 BUILT_MODULE_LOCATION[150]=./v4l DEST_MODULE_LOCATION[150]=/updates/dkms -BUILT_MODULE_NAME[151]=dvb-usb-cxusb +BUILT_MODULE_NAME[151]=ths7303 BUILT_MODULE_LOCATION[151]=./v4l DEST_MODULE_LOCATION[151]=/updates/dkms -BUILT_MODULE_NAME[152]=imon +BUILT_MODULE_NAME[152]=rc-dntv-live-dvb-t BUILT_MODULE_LOCATION[152]=./v4l DEST_MODULE_LOCATION[152]=/updates/dkms -BUILT_MODULE_NAME[153]=ves1820 +BUILT_MODULE_NAME[153]=rc-leadtek-y04g0051 BUILT_MODULE_LOCATION[153]=./v4l DEST_MODULE_LOCATION[153]=/updates/dkms -BUILT_MODULE_NAME[154]=dvb-usb-vp7045 +BUILT_MODULE_NAME[154]=lnbp21 BUILT_MODULE_LOCATION[154]=./v4l DEST_MODULE_LOCATION[154]=/updates/dkms -BUILT_MODULE_NAME[155]=gspca_sn9c2028 +BUILT_MODULE_NAME[155]=rc-lme2510 BUILT_MODULE_LOCATION[155]=./v4l DEST_MODULE_LOCATION[155]=/updates/dkms -BUILT_MODULE_NAME[156]=ves1x93 +BUILT_MODULE_NAME[156]=rc-kworld-315u BUILT_MODULE_LOCATION[156]=./v4l DEST_MODULE_LOCATION[156]=/updates/dkms -BUILT_MODULE_NAME[157]=ths7303 +BUILT_MODULE_NAME[157]=stkwebcam BUILT_MODULE_LOCATION[157]=./v4l DEST_MODULE_LOCATION[157]=/updates/dkms -BUILT_MODULE_NAME[158]=rc-dntv-live-dvb-t +BUILT_MODULE_NAME[158]=rc-trekstor BUILT_MODULE_LOCATION[158]=./v4l DEST_MODULE_LOCATION[158]=/updates/dkms -BUILT_MODULE_NAME[159]=rc-leadtek-y04g0051 +BUILT_MODULE_NAME[159]=qt1010 BUILT_MODULE_LOCATION[159]=./v4l DEST_MODULE_LOCATION[159]=/updates/dkms -BUILT_MODULE_NAME[160]=lnbp21 +BUILT_MODULE_NAME[160]=or51211 BUILT_MODULE_LOCATION[160]=./v4l DEST_MODULE_LOCATION[160]=/updates/dkms -BUILT_MODULE_NAME[161]=rc-lme2510 +BUILT_MODULE_NAME[161]=rc-pinnacle-grey BUILT_MODULE_LOCATION[161]=./v4l DEST_MODULE_LOCATION[161]=/updates/dkms -BUILT_MODULE_NAME[162]=radio-zoltrix +BUILT_MODULE_NAME[162]=cx18 BUILT_MODULE_LOCATION[162]=./v4l DEST_MODULE_LOCATION[162]=/updates/dkms -BUILT_MODULE_NAME[163]=rc-kworld-315u +BUILT_MODULE_NAME[163]=saa7146 BUILT_MODULE_LOCATION[163]=./v4l DEST_MODULE_LOCATION[163]=/updates/dkms -BUILT_MODULE_NAME[164]=stkwebcam +BUILT_MODULE_NAME[164]=dvb-usb-gl861 BUILT_MODULE_LOCATION[164]=./v4l DEST_MODULE_LOCATION[164]=/updates/dkms -BUILT_MODULE_NAME[165]=rc-trekstor +BUILT_MODULE_NAME[165]=budget-patch BUILT_MODULE_LOCATION[165]=./v4l DEST_MODULE_LOCATION[165]=/updates/dkms -BUILT_MODULE_NAME[166]=qt1010 +BUILT_MODULE_NAME[166]=saa716x_hybrid BUILT_MODULE_LOCATION[166]=./v4l DEST_MODULE_LOCATION[166]=/updates/dkms -BUILT_MODULE_NAME[167]=or51211 +BUILT_MODULE_NAME[167]=saa7134-empress BUILT_MODULE_LOCATION[167]=./v4l DEST_MODULE_LOCATION[167]=/updates/dkms -BUILT_MODULE_NAME[168]=rc-pinnacle-grey +BUILT_MODULE_NAME[168]=ec100 BUILT_MODULE_LOCATION[168]=./v4l DEST_MODULE_LOCATION[168]=/updates/dkms -BUILT_MODULE_NAME[169]=cx18 +BUILT_MODULE_NAME[169]=dib0090 BUILT_MODULE_LOCATION[169]=./v4l DEST_MODULE_LOCATION[169]=/updates/dkms -BUILT_MODULE_NAME[170]=saa7146 +BUILT_MODULE_NAME[170]=cx25840 BUILT_MODULE_LOCATION[170]=./v4l DEST_MODULE_LOCATION[170]=/updates/dkms -BUILT_MODULE_NAME[171]=dvb-usb-gl861 +BUILT_MODULE_NAME[171]=upd64083 BUILT_MODULE_LOCATION[171]=./v4l DEST_MODULE_LOCATION[171]=/updates/dkms -BUILT_MODULE_NAME[172]=budget-patch +BUILT_MODULE_NAME[172]=stv0299 BUILT_MODULE_LOCATION[172]=./v4l DEST_MODULE_LOCATION[172]=/updates/dkms -BUILT_MODULE_NAME[173]=radio-rtrack2 +BUILT_MODULE_NAME[173]=dib3000mb BUILT_MODULE_LOCATION[173]=./v4l DEST_MODULE_LOCATION[173]=/updates/dkms -BUILT_MODULE_NAME[174]=saa7134-empress +BUILT_MODULE_NAME[174]=gspca_stv0680 BUILT_MODULE_LOCATION[174]=./v4l DEST_MODULE_LOCATION[174]=/updates/dkms -BUILT_MODULE_NAME[175]=ec100 +BUILT_MODULE_NAME[175]=budget-av BUILT_MODULE_LOCATION[175]=./v4l DEST_MODULE_LOCATION[175]=/updates/dkms -BUILT_MODULE_NAME[176]=dib0090 +BUILT_MODULE_NAME[176]=dst_ca BUILT_MODULE_LOCATION[176]=./v4l DEST_MODULE_LOCATION[176]=/updates/dkms -BUILT_MODULE_NAME[177]=cx25840 +BUILT_MODULE_NAME[177]=tvaudio BUILT_MODULE_LOCATION[177]=./v4l DEST_MODULE_LOCATION[177]=/updates/dkms -BUILT_MODULE_NAME[178]=upd64083 +BUILT_MODULE_NAME[178]=rc-avermedia-cardbus BUILT_MODULE_LOCATION[178]=./v4l DEST_MODULE_LOCATION[178]=/updates/dkms -BUILT_MODULE_NAME[179]=stv0299 +BUILT_MODULE_NAME[179]=stv0900 BUILT_MODULE_LOCATION[179]=./v4l DEST_MODULE_LOCATION[179]=/updates/dkms -BUILT_MODULE_NAME[180]=dib3000mb +BUILT_MODULE_NAME[180]=videobuf-dma-sg BUILT_MODULE_LOCATION[180]=./v4l DEST_MODULE_LOCATION[180]=/updates/dkms -BUILT_MODULE_NAME[181]=gspca_stv0680 +BUILT_MODULE_NAME[181]=rc-gadmei-rm008z BUILT_MODULE_LOCATION[181]=./v4l DEST_MODULE_LOCATION[181]=/updates/dkms -BUILT_MODULE_NAME[182]=budget-av +BUILT_MODULE_NAME[182]=s2255drv BUILT_MODULE_LOCATION[182]=./v4l DEST_MODULE_LOCATION[182]=/updates/dkms -BUILT_MODULE_NAME[183]=dst_ca +BUILT_MODULE_NAME[183]=rc-pixelview BUILT_MODULE_LOCATION[183]=./v4l DEST_MODULE_LOCATION[183]=/updates/dkms -BUILT_MODULE_NAME[184]=tvaudio +BUILT_MODULE_NAME[184]=saa716x_ff BUILT_MODULE_LOCATION[184]=./v4l DEST_MODULE_LOCATION[184]=/updates/dkms -BUILT_MODULE_NAME[185]=rc-avermedia-cardbus +BUILT_MODULE_NAME[185]=videobuf2-core BUILT_MODULE_LOCATION[185]=./v4l DEST_MODULE_LOCATION[185]=/updates/dkms -BUILT_MODULE_NAME[186]=stv0900 +BUILT_MODULE_NAME[186]=cx22702 BUILT_MODULE_LOCATION[186]=./v4l DEST_MODULE_LOCATION[186]=/updates/dkms -BUILT_MODULE_NAME[187]=videobuf-dma-sg +BUILT_MODULE_NAME[187]=saa7134 BUILT_MODULE_LOCATION[187]=./v4l DEST_MODULE_LOCATION[187]=/updates/dkms -BUILT_MODULE_NAME[188]=rc-gadmei-rm008z +BUILT_MODULE_NAME[188]=dvb-usb-af9005-remote BUILT_MODULE_LOCATION[188]=./v4l DEST_MODULE_LOCATION[188]=/updates/dkms -BUILT_MODULE_NAME[189]=s2255drv +BUILT_MODULE_NAME[189]=dvb-usb-friio BUILT_MODULE_LOCATION[189]=./v4l DEST_MODULE_LOCATION[189]=/updates/dkms -BUILT_MODULE_NAME[190]=rc-pixelview +BUILT_MODULE_NAME[190]=ttpci-eeprom BUILT_MODULE_LOCATION[190]=./v4l DEST_MODULE_LOCATION[190]=/updates/dkms -BUILT_MODULE_NAME[191]=videobuf2-core +BUILT_MODULE_NAME[191]=rc-ati-tv-wonder-hd-600 BUILT_MODULE_LOCATION[191]=./v4l DEST_MODULE_LOCATION[191]=/updates/dkms -BUILT_MODULE_NAME[192]=cx22702 +BUILT_MODULE_NAME[192]=tuner-types BUILT_MODULE_LOCATION[192]=./v4l DEST_MODULE_LOCATION[192]=/updates/dkms -BUILT_MODULE_NAME[193]=saa7134 +BUILT_MODULE_NAME[193]=nuvoton-cir BUILT_MODULE_LOCATION[193]=./v4l DEST_MODULE_LOCATION[193]=/updates/dkms -BUILT_MODULE_NAME[194]=dvb-usb-af9005-remote +BUILT_MODULE_NAME[194]=dib9000 BUILT_MODULE_LOCATION[194]=./v4l DEST_MODULE_LOCATION[194]=/updates/dkms -BUILT_MODULE_NAME[195]=dvb-usb-friio +BUILT_MODULE_NAME[195]=snd-bt87x BUILT_MODULE_LOCATION[195]=./v4l DEST_MODULE_LOCATION[195]=/updates/dkms -BUILT_MODULE_NAME[196]=ttpci-eeprom +BUILT_MODULE_NAME[196]=rc-anysee BUILT_MODULE_LOCATION[196]=./v4l DEST_MODULE_LOCATION[196]=/updates/dkms -BUILT_MODULE_NAME[197]=rc-ati-tv-wonder-hd-600 +BUILT_MODULE_NAME[197]=sp887x BUILT_MODULE_LOCATION[197]=./v4l DEST_MODULE_LOCATION[197]=/updates/dkms -BUILT_MODULE_NAME[198]=tuner-types +BUILT_MODULE_NAME[198]=gspca_ov534 BUILT_MODULE_LOCATION[198]=./v4l DEST_MODULE_LOCATION[198]=/updates/dkms -BUILT_MODULE_NAME[199]=nuvoton-cir +BUILT_MODULE_NAME[199]=radio-maxiradio BUILT_MODULE_LOCATION[199]=./v4l DEST_MODULE_LOCATION[199]=/updates/dkms -BUILT_MODULE_NAME[200]=dib9000 +BUILT_MODULE_NAME[200]=dvb-usb-dibusb-common BUILT_MODULE_LOCATION[200]=./v4l DEST_MODULE_LOCATION[200]=/updates/dkms -BUILT_MODULE_NAME[201]=snd-bt87x +BUILT_MODULE_NAME[201]=msp3400 BUILT_MODULE_LOCATION[201]=./v4l DEST_MODULE_LOCATION[201]=/updates/dkms -BUILT_MODULE_NAME[202]=rc-anysee +BUILT_MODULE_NAME[202]=dvb-usb-digitv BUILT_MODULE_LOCATION[202]=./v4l DEST_MODULE_LOCATION[202]=/updates/dkms -BUILT_MODULE_NAME[203]=sp887x +BUILT_MODULE_NAME[203]=rc-streamzap BUILT_MODULE_LOCATION[203]=./v4l DEST_MODULE_LOCATION[203]=/updates/dkms -BUILT_MODULE_NAME[204]=gspca_ov534 +BUILT_MODULE_NAME[204]=bw-qcam BUILT_MODULE_LOCATION[204]=./v4l DEST_MODULE_LOCATION[204]=/updates/dkms -BUILT_MODULE_NAME[205]=radio-maxiradio +BUILT_MODULE_NAME[205]=videobuf2-vmalloc BUILT_MODULE_LOCATION[205]=./v4l DEST_MODULE_LOCATION[205]=/updates/dkms -BUILT_MODULE_NAME[206]=dvb-usb-dibusb-common +BUILT_MODULE_NAME[206]=tuner BUILT_MODULE_LOCATION[206]=./v4l DEST_MODULE_LOCATION[206]=/updates/dkms -BUILT_MODULE_NAME[207]=msp3400 +BUILT_MODULE_NAME[207]=radio-tea5764 BUILT_MODULE_LOCATION[207]=./v4l DEST_MODULE_LOCATION[207]=/updates/dkms -BUILT_MODULE_NAME[208]=dvb-usb-digitv +BUILT_MODULE_NAME[208]=dibx000_common BUILT_MODULE_LOCATION[208]=./v4l DEST_MODULE_LOCATION[208]=/updates/dkms -BUILT_MODULE_NAME[209]=rc-streamzap +BUILT_MODULE_NAME[209]=mb86a20s BUILT_MODULE_LOCATION[209]=./v4l DEST_MODULE_LOCATION[209]=/updates/dkms -BUILT_MODULE_NAME[210]=bw-qcam +BUILT_MODULE_NAME[210]=cx24116 BUILT_MODULE_LOCATION[210]=./v4l DEST_MODULE_LOCATION[210]=/updates/dkms -BUILT_MODULE_NAME[211]=videobuf2-vmalloc +BUILT_MODULE_NAME[211]=rc-twinhan-dtv-cab-ci BUILT_MODULE_LOCATION[211]=./v4l DEST_MODULE_LOCATION[211]=/updates/dkms -BUILT_MODULE_NAME[212]=radio-sf16fmr2 +BUILT_MODULE_NAME[212]=mxl5007t BUILT_MODULE_LOCATION[212]=./v4l DEST_MODULE_LOCATION[212]=/updates/dkms -BUILT_MODULE_NAME[213]=tuner +BUILT_MODULE_NAME[213]=stv090x BUILT_MODULE_LOCATION[213]=./v4l DEST_MODULE_LOCATION[213]=/updates/dkms -BUILT_MODULE_NAME[214]=radio-tea5764 +BUILT_MODULE_NAME[214]=rc-flydvb BUILT_MODULE_LOCATION[214]=./v4l DEST_MODULE_LOCATION[214]=/updates/dkms -BUILT_MODULE_NAME[215]=dibx000_common +BUILT_MODULE_NAME[215]=hopper BUILT_MODULE_LOCATION[215]=./v4l DEST_MODULE_LOCATION[215]=/updates/dkms -BUILT_MODULE_NAME[216]=mb86a20s +BUILT_MODULE_NAME[216]=mt312 BUILT_MODULE_LOCATION[216]=./v4l DEST_MODULE_LOCATION[216]=/updates/dkms -BUILT_MODULE_NAME[217]=cx24116 +BUILT_MODULE_NAME[217]=isl6421 BUILT_MODULE_LOCATION[217]=./v4l DEST_MODULE_LOCATION[217]=/updates/dkms -BUILT_MODULE_NAME[218]=mxl5007t +BUILT_MODULE_NAME[218]=gspca_sq905c BUILT_MODULE_LOCATION[218]=./v4l DEST_MODULE_LOCATION[218]=/updates/dkms -BUILT_MODULE_NAME[219]=stv090x +BUILT_MODULE_NAME[219]=lgs8gl5 BUILT_MODULE_LOCATION[219]=./v4l DEST_MODULE_LOCATION[219]=/updates/dkms -BUILT_MODULE_NAME[220]=rc-flydvb +BUILT_MODULE_NAME[220]=gspca_spca508 BUILT_MODULE_LOCATION[220]=./v4l DEST_MODULE_LOCATION[220]=/updates/dkms -BUILT_MODULE_NAME[221]=hopper +BUILT_MODULE_NAME[221]=tuner-simple BUILT_MODULE_LOCATION[221]=./v4l DEST_MODULE_LOCATION[221]=/updates/dkms -BUILT_MODULE_NAME[222]=mt312 +BUILT_MODULE_NAME[222]=gspca_etoms BUILT_MODULE_LOCATION[222]=./v4l DEST_MODULE_LOCATION[222]=/updates/dkms -BUILT_MODULE_NAME[223]=isl6421 +BUILT_MODULE_NAME[223]=v4l2-common BUILT_MODULE_LOCATION[223]=./v4l DEST_MODULE_LOCATION[223]=/updates/dkms -BUILT_MODULE_NAME[224]=gspca_sq905c +BUILT_MODULE_NAME[224]=adv7175 BUILT_MODULE_LOCATION[224]=./v4l DEST_MODULE_LOCATION[224]=/updates/dkms -BUILT_MODULE_NAME[225]=lgs8gl5 +BUILT_MODULE_NAME[225]=cx231xx-dvb BUILT_MODULE_LOCATION[225]=./v4l DEST_MODULE_LOCATION[225]=/updates/dkms -BUILT_MODULE_NAME[226]=gspca_spca508 +BUILT_MODULE_NAME[226]=ir-nec-decoder BUILT_MODULE_LOCATION[226]=./v4l DEST_MODULE_LOCATION[226]=/updates/dkms -BUILT_MODULE_NAME[227]=tuner-simple +BUILT_MODULE_NAME[227]=rc-tevii-nec BUILT_MODULE_LOCATION[227]=./v4l DEST_MODULE_LOCATION[227]=/updates/dkms -BUILT_MODULE_NAME[228]=gspca_etoms +BUILT_MODULE_NAME[228]=ivtvfb BUILT_MODULE_LOCATION[228]=./v4l DEST_MODULE_LOCATION[228]=/updates/dkms -BUILT_MODULE_NAME[229]=v4l2-common +BUILT_MODULE_NAME[229]=lgs8gxx BUILT_MODULE_LOCATION[229]=./v4l DEST_MODULE_LOCATION[229]=/updates/dkms -BUILT_MODULE_NAME[230]=adv7175 +BUILT_MODULE_NAME[230]=rc-dm1105-nec BUILT_MODULE_LOCATION[230]=./v4l DEST_MODULE_LOCATION[230]=/updates/dkms -BUILT_MODULE_NAME[231]=cx231xx-dvb +BUILT_MODULE_NAME[231]=max2165 BUILT_MODULE_LOCATION[231]=./v4l DEST_MODULE_LOCATION[231]=/updates/dkms -BUILT_MODULE_NAME[232]=ir-nec-decoder +BUILT_MODULE_NAME[232]=gspca_tv8532 BUILT_MODULE_LOCATION[232]=./v4l DEST_MODULE_LOCATION[232]=/updates/dkms -BUILT_MODULE_NAME[233]=rc-tevii-nec +BUILT_MODULE_NAME[233]=cx24123 BUILT_MODULE_LOCATION[233]=./v4l DEST_MODULE_LOCATION[233]=/updates/dkms -BUILT_MODULE_NAME[234]=ivtvfb +BUILT_MODULE_NAME[234]=dst BUILT_MODULE_LOCATION[234]=./v4l DEST_MODULE_LOCATION[234]=/updates/dkms -BUILT_MODULE_NAME[235]=lgs8gxx +BUILT_MODULE_NAME[235]=tda10021 BUILT_MODULE_LOCATION[235]=./v4l DEST_MODULE_LOCATION[235]=/updates/dkms -BUILT_MODULE_NAME[236]=rc-dm1105-nec +BUILT_MODULE_NAME[236]=tua6100 BUILT_MODULE_LOCATION[236]=./v4l DEST_MODULE_LOCATION[236]=/updates/dkms -BUILT_MODULE_NAME[237]=max2165 +BUILT_MODULE_NAME[237]=dvb-bt8xx BUILT_MODULE_LOCATION[237]=./v4l DEST_MODULE_LOCATION[237]=/updates/dkms -BUILT_MODULE_NAME[238]=gspca_tv8532 +BUILT_MODULE_NAME[238]=si21xx BUILT_MODULE_LOCATION[238]=./v4l DEST_MODULE_LOCATION[238]=/updates/dkms -BUILT_MODULE_NAME[239]=cx24123 +BUILT_MODULE_NAME[239]=rc-msi-digivox-ii BUILT_MODULE_LOCATION[239]=./v4l DEST_MODULE_LOCATION[239]=/updates/dkms -BUILT_MODULE_NAME[240]=dst +BUILT_MODULE_NAME[240]=nxt200x BUILT_MODULE_LOCATION[240]=./v4l DEST_MODULE_LOCATION[240]=/updates/dkms -BUILT_MODULE_NAME[241]=tda10021 +BUILT_MODULE_NAME[241]=cx18-alsa BUILT_MODULE_LOCATION[241]=./v4l DEST_MODULE_LOCATION[241]=/updates/dkms -BUILT_MODULE_NAME[242]=tua6100 +BUILT_MODULE_NAME[242]=saa7185 BUILT_MODULE_LOCATION[242]=./v4l DEST_MODULE_LOCATION[242]=/updates/dkms -BUILT_MODULE_NAME[243]=dvb-bt8xx +BUILT_MODULE_NAME[243]=mb86a16 BUILT_MODULE_LOCATION[243]=./v4l DEST_MODULE_LOCATION[243]=/updates/dkms -BUILT_MODULE_NAME[244]=si21xx +BUILT_MODULE_NAME[244]=tea6420 BUILT_MODULE_LOCATION[244]=./v4l DEST_MODULE_LOCATION[244]=/updates/dkms -BUILT_MODULE_NAME[245]=rc-msi-digivox-ii +BUILT_MODULE_NAME[245]=gspca_mr97310a BUILT_MODULE_LOCATION[245]=./v4l DEST_MODULE_LOCATION[245]=/updates/dkms -BUILT_MODULE_NAME[246]=nxt200x +BUILT_MODULE_NAME[246]=m52790 BUILT_MODULE_LOCATION[246]=./v4l DEST_MODULE_LOCATION[246]=/updates/dkms -BUILT_MODULE_NAME[247]=cx18-alsa +BUILT_MODULE_NAME[247]=gspca_spca506 BUILT_MODULE_LOCATION[247]=./v4l DEST_MODULE_LOCATION[247]=/updates/dkms -BUILT_MODULE_NAME[248]=saa7185 +BUILT_MODULE_NAME[248]=dvb-usb-nova-t-usb2 BUILT_MODULE_LOCATION[248]=./v4l DEST_MODULE_LOCATION[248]=/updates/dkms -BUILT_MODULE_NAME[249]=mb86a16 +BUILT_MODULE_NAME[249]=budget BUILT_MODULE_LOCATION[249]=./v4l DEST_MODULE_LOCATION[249]=/updates/dkms -BUILT_MODULE_NAME[250]=tea6420 +BUILT_MODULE_NAME[250]=gspca_sq905 BUILT_MODULE_LOCATION[250]=./v4l DEST_MODULE_LOCATION[250]=/updates/dkms -BUILT_MODULE_NAME[251]=gspca_mr97310a +BUILT_MODULE_NAME[251]=rc-terratec-cinergy-s2-hd BUILT_MODULE_LOCATION[251]=./v4l DEST_MODULE_LOCATION[251]=/updates/dkms -BUILT_MODULE_NAME[252]=m52790 +BUILT_MODULE_NAME[252]=dib0070 BUILT_MODULE_LOCATION[252]=./v4l DEST_MODULE_LOCATION[252]=/updates/dkms -BUILT_MODULE_NAME[253]=gspca_spca506 +BUILT_MODULE_NAME[253]=cx88-blackbird BUILT_MODULE_LOCATION[253]=./v4l DEST_MODULE_LOCATION[253]=/updates/dkms -BUILT_MODULE_NAME[254]=dvb-usb-nova-t-usb2 +BUILT_MODULE_NAME[254]=gspca_mars BUILT_MODULE_LOCATION[254]=./v4l DEST_MODULE_LOCATION[254]=/updates/dkms -BUILT_MODULE_NAME[255]=budget +BUILT_MODULE_NAME[255]=rc-terratec-cinergy-xs BUILT_MODULE_LOCATION[255]=./v4l DEST_MODULE_LOCATION[255]=/updates/dkms -BUILT_MODULE_NAME[256]=gspca_sq905 +BUILT_MODULE_NAME[256]=gspca_xirlink_cit BUILT_MODULE_LOCATION[256]=./v4l DEST_MODULE_LOCATION[256]=/updates/dkms -BUILT_MODULE_NAME[257]=dib0070 +BUILT_MODULE_NAME[257]=cx8800 BUILT_MODULE_LOCATION[257]=./v4l DEST_MODULE_LOCATION[257]=/updates/dkms -BUILT_MODULE_NAME[258]=cx88-blackbird +BUILT_MODULE_NAME[258]=rc-norwood BUILT_MODULE_LOCATION[258]=./v4l DEST_MODULE_LOCATION[258]=/updates/dkms -BUILT_MODULE_NAME[259]=gspca_mars +BUILT_MODULE_NAME[259]=gspca_spca501 BUILT_MODULE_LOCATION[259]=./v4l DEST_MODULE_LOCATION[259]=/updates/dkms -BUILT_MODULE_NAME[260]=rc-terratec-cinergy-xs +BUILT_MODULE_NAME[260]=gspca_vicam BUILT_MODULE_LOCATION[260]=./v4l DEST_MODULE_LOCATION[260]=/updates/dkms -BUILT_MODULE_NAME[261]=gspca_xirlink_cit +BUILT_MODULE_NAME[261]=gspca_jeilinj BUILT_MODULE_LOCATION[261]=./v4l DEST_MODULE_LOCATION[261]=/updates/dkms -BUILT_MODULE_NAME[262]=cx8800 +BUILT_MODULE_NAME[262]=cx23885 BUILT_MODULE_LOCATION[262]=./v4l DEST_MODULE_LOCATION[262]=/updates/dkms -BUILT_MODULE_NAME[263]=rc-norwood +BUILT_MODULE_NAME[263]=mxl5005s BUILT_MODULE_LOCATION[263]=./v4l DEST_MODULE_LOCATION[263]=/updates/dkms -BUILT_MODULE_NAME[264]=gspca_spca501 +BUILT_MODULE_NAME[264]=sn9c102 BUILT_MODULE_LOCATION[264]=./v4l DEST_MODULE_LOCATION[264]=/updates/dkms -BUILT_MODULE_NAME[265]=gspca_vicam +BUILT_MODULE_NAME[265]=dvb-usb-dtv5100 BUILT_MODULE_LOCATION[265]=./v4l DEST_MODULE_LOCATION[265]=/updates/dkms -BUILT_MODULE_NAME[266]=gspca_jeilinj +BUILT_MODULE_NAME[266]=isl6405 BUILT_MODULE_LOCATION[266]=./v4l DEST_MODULE_LOCATION[266]=/updates/dkms -BUILT_MODULE_NAME[267]=cx23885 +BUILT_MODULE_NAME[267]=itd1000 BUILT_MODULE_LOCATION[267]=./v4l DEST_MODULE_LOCATION[267]=/updates/dkms -BUILT_MODULE_NAME[268]=mxl5005s +BUILT_MODULE_NAME[268]=au8522 BUILT_MODULE_LOCATION[268]=./v4l DEST_MODULE_LOCATION[268]=/updates/dkms -BUILT_MODULE_NAME[269]=sn9c102 +BUILT_MODULE_NAME[269]=tda9887 BUILT_MODULE_LOCATION[269]=./v4l DEST_MODULE_LOCATION[269]=/updates/dkms -BUILT_MODULE_NAME[270]=dvb-usb-dtv5100 +BUILT_MODULE_NAME[270]=dvb-usb-gp8psk BUILT_MODULE_LOCATION[270]=./v4l DEST_MODULE_LOCATION[270]=/updates/dkms -BUILT_MODULE_NAME[271]=isl6405 +BUILT_MODULE_NAME[271]=dvb-usb-anysee BUILT_MODULE_LOCATION[271]=./v4l DEST_MODULE_LOCATION[271]=/updates/dkms -BUILT_MODULE_NAME[272]=itd1000 +BUILT_MODULE_NAME[272]=nxt6000 BUILT_MODULE_LOCATION[272]=./v4l DEST_MODULE_LOCATION[272]=/updates/dkms -BUILT_MODULE_NAME[273]=au8522 +BUILT_MODULE_NAME[273]=saa7115 BUILT_MODULE_LOCATION[273]=./v4l DEST_MODULE_LOCATION[273]=/updates/dkms -BUILT_MODULE_NAME[274]=tda9887 +BUILT_MODULE_NAME[274]=au0828 BUILT_MODULE_LOCATION[274]=./v4l DEST_MODULE_LOCATION[274]=/updates/dkms -BUILT_MODULE_NAME[275]=dvb-usb-gp8psk +BUILT_MODULE_NAME[275]=rc-avermedia BUILT_MODULE_LOCATION[275]=./v4l DEST_MODULE_LOCATION[275]=/updates/dkms -BUILT_MODULE_NAME[276]=dvb-usb-anysee +BUILT_MODULE_NAME[276]=hexium_gemini BUILT_MODULE_LOCATION[276]=./v4l DEST_MODULE_LOCATION[276]=/updates/dkms -BUILT_MODULE_NAME[277]=nxt6000 +BUILT_MODULE_NAME[277]=rc-eztv BUILT_MODULE_LOCATION[277]=./v4l DEST_MODULE_LOCATION[277]=/updates/dkms -BUILT_MODULE_NAME[278]=saa7115 +BUILT_MODULE_NAME[278]=pwc BUILT_MODULE_LOCATION[278]=./v4l DEST_MODULE_LOCATION[278]=/updates/dkms -BUILT_MODULE_NAME[279]=au0828 +BUILT_MODULE_NAME[279]=rc-encore-enltv-fm53 BUILT_MODULE_LOCATION[279]=./v4l DEST_MODULE_LOCATION[279]=/updates/dkms -BUILT_MODULE_NAME[280]=rc-avermedia +BUILT_MODULE_NAME[280]=budget-core BUILT_MODULE_LOCATION[280]=./v4l DEST_MODULE_LOCATION[280]=/updates/dkms -BUILT_MODULE_NAME[281]=hexium_gemini +BUILT_MODULE_NAME[281]=gspca_conex BUILT_MODULE_LOCATION[281]=./v4l DEST_MODULE_LOCATION[281]=/updates/dkms -BUILT_MODULE_NAME[282]=rc-eztv +BUILT_MODULE_NAME[282]=gspca_pac7311 BUILT_MODULE_LOCATION[282]=./v4l DEST_MODULE_LOCATION[282]=/updates/dkms -BUILT_MODULE_NAME[283]=pwc +BUILT_MODULE_NAME[283]=dvb-ttusb-budget BUILT_MODULE_LOCATION[283]=./v4l DEST_MODULE_LOCATION[283]=/updates/dkms -BUILT_MODULE_NAME[284]=rc-encore-enltv-fm53 +BUILT_MODULE_NAME[284]=tda8083 BUILT_MODULE_LOCATION[284]=./v4l DEST_MODULE_LOCATION[284]=/updates/dkms -BUILT_MODULE_NAME[285]=budget-core +BUILT_MODULE_NAME[285]=gspca_pac207 BUILT_MODULE_LOCATION[285]=./v4l DEST_MODULE_LOCATION[285]=/updates/dkms -BUILT_MODULE_NAME[286]=gspca_conex +BUILT_MODULE_NAME[286]=ix2505v BUILT_MODULE_LOCATION[286]=./v4l DEST_MODULE_LOCATION[286]=/updates/dkms -BUILT_MODULE_NAME[287]=gspca_pac7311 +BUILT_MODULE_NAME[287]=zr36060 BUILT_MODULE_LOCATION[287]=./v4l DEST_MODULE_LOCATION[287]=/updates/dkms -BUILT_MODULE_NAME[288]=dvb-ttusb-budget +BUILT_MODULE_NAME[288]=rc-technisat-usb2 BUILT_MODULE_LOCATION[288]=./v4l DEST_MODULE_LOCATION[288]=/updates/dkms -BUILT_MODULE_NAME[289]=tda8083 +BUILT_MODULE_NAME[289]=v4l2-int-device BUILT_MODULE_LOCATION[289]=./v4l DEST_MODULE_LOCATION[289]=/updates/dkms -BUILT_MODULE_NAME[290]=gspca_pac207 +BUILT_MODULE_NAME[290]=gspca_finepix BUILT_MODULE_LOCATION[290]=./v4l DEST_MODULE_LOCATION[290]=/updates/dkms -BUILT_MODULE_NAME[291]=ix2505v +BUILT_MODULE_NAME[291]=dvb-usb-au6610 BUILT_MODULE_LOCATION[291]=./v4l DEST_MODULE_LOCATION[291]=/updates/dkms -BUILT_MODULE_NAME[292]=zr36060 +BUILT_MODULE_NAME[292]=rc-nec-terratec-cinergy-xs BUILT_MODULE_LOCATION[292]=./v4l DEST_MODULE_LOCATION[292]=/updates/dkms -BUILT_MODULE_NAME[293]=rc-technisat-usb2 +BUILT_MODULE_NAME[293]=gspca_t613 BUILT_MODULE_LOCATION[293]=./v4l DEST_MODULE_LOCATION[293]=/updates/dkms -BUILT_MODULE_NAME[294]=firedtv +BUILT_MODULE_NAME[294]=saa7191 BUILT_MODULE_LOCATION[294]=./v4l DEST_MODULE_LOCATION[294]=/updates/dkms -BUILT_MODULE_NAME[295]=v4l2-int-device +BUILT_MODULE_NAME[295]=vp27smpx BUILT_MODULE_LOCATION[295]=./v4l DEST_MODULE_LOCATION[295]=/updates/dkms -BUILT_MODULE_NAME[296]=gspca_finepix +BUILT_MODULE_NAME[296]=rc-budget-ci-old BUILT_MODULE_LOCATION[296]=./v4l DEST_MODULE_LOCATION[296]=/updates/dkms -BUILT_MODULE_NAME[297]=dvb-usb-au6610 +BUILT_MODULE_NAME[297]=s5h1411 BUILT_MODULE_LOCATION[297]=./v4l DEST_MODULE_LOCATION[297]=/updates/dkms -BUILT_MODULE_NAME[298]=rc-nec-terratec-cinergy-xs +BUILT_MODULE_NAME[298]=gspca_zc3xx BUILT_MODULE_LOCATION[298]=./v4l DEST_MODULE_LOCATION[298]=/updates/dkms -BUILT_MODULE_NAME[299]=gspca_t613 +BUILT_MODULE_NAME[299]=dvb-usb BUILT_MODULE_LOCATION[299]=./v4l DEST_MODULE_LOCATION[299]=/updates/dkms -BUILT_MODULE_NAME[300]=radio-trust +BUILT_MODULE_NAME[300]=dvb-usb-dibusb-mc BUILT_MODULE_LOCATION[300]=./v4l DEST_MODULE_LOCATION[300]=/updates/dkms -BUILT_MODULE_NAME[301]=saa7191 +BUILT_MODULE_NAME[301]=dvb-pll BUILT_MODULE_LOCATION[301]=./v4l DEST_MODULE_LOCATION[301]=/updates/dkms -BUILT_MODULE_NAME[302]=vp27smpx +BUILT_MODULE_NAME[302]=ir-kbd-i2c BUILT_MODULE_LOCATION[302]=./v4l DEST_MODULE_LOCATION[302]=/updates/dkms -BUILT_MODULE_NAME[303]=rc-budget-ci-old +BUILT_MODULE_NAME[303]=sr030pc30 BUILT_MODULE_LOCATION[303]=./v4l DEST_MODULE_LOCATION[303]=/updates/dkms -BUILT_MODULE_NAME[304]=s5h1411 +BUILT_MODULE_NAME[304]=tda826x BUILT_MODULE_LOCATION[304]=./v4l DEST_MODULE_LOCATION[304]=/updates/dkms -BUILT_MODULE_NAME[305]=gspca_zc3xx +BUILT_MODULE_NAME[305]=tea6415c BUILT_MODULE_LOCATION[305]=./v4l DEST_MODULE_LOCATION[305]=/updates/dkms -BUILT_MODULE_NAME[306]=dvb-usb +BUILT_MODULE_NAME[306]=zr36050 BUILT_MODULE_LOCATION[306]=./v4l DEST_MODULE_LOCATION[306]=/updates/dkms -BUILT_MODULE_NAME[307]=dvb-usb-dibusb-mc +BUILT_MODULE_NAME[307]=rc-kaiomy BUILT_MODULE_LOCATION[307]=./v4l DEST_MODULE_LOCATION[307]=/updates/dkms -BUILT_MODULE_NAME[308]=dvb-pll +BUILT_MODULE_NAME[308]=ov7670 BUILT_MODULE_LOCATION[308]=./v4l DEST_MODULE_LOCATION[308]=/updates/dkms -BUILT_MODULE_NAME[309]=ir-kbd-i2c +BUILT_MODULE_NAME[309]=rc-videomate-s350 BUILT_MODULE_LOCATION[309]=./v4l DEST_MODULE_LOCATION[309]=/updates/dkms -BUILT_MODULE_NAME[310]=sr030pc30 +BUILT_MODULE_NAME[310]=lgdt3305 BUILT_MODULE_LOCATION[310]=./v4l DEST_MODULE_LOCATION[310]=/updates/dkms -BUILT_MODULE_NAME[311]=tda826x +BUILT_MODULE_NAME[311]=rc-azurewave-ad-tu700 BUILT_MODULE_LOCATION[311]=./v4l DEST_MODULE_LOCATION[311]=/updates/dkms -BUILT_MODULE_NAME[312]=tea6415c +BUILT_MODULE_NAME[312]=l64781 BUILT_MODULE_LOCATION[312]=./v4l DEST_MODULE_LOCATION[312]=/updates/dkms -BUILT_MODULE_NAME[313]=zr36050 +BUILT_MODULE_NAME[313]=rc-terratec-slim-2 BUILT_MODULE_LOCATION[313]=./v4l DEST_MODULE_LOCATION[313]=/updates/dkms -BUILT_MODULE_NAME[314]=videobuf2-dma-contig +BUILT_MODULE_NAME[314]=tvp5150 BUILT_MODULE_LOCATION[314]=./v4l DEST_MODULE_LOCATION[314]=/updates/dkms -BUILT_MODULE_NAME[315]=rc-kaiomy +BUILT_MODULE_NAME[315]=rc-hauppauge BUILT_MODULE_LOCATION[315]=./v4l DEST_MODULE_LOCATION[315]=/updates/dkms -BUILT_MODULE_NAME[316]=ov7670 +BUILT_MODULE_NAME[316]=gspca_ov519 BUILT_MODULE_LOCATION[316]=./v4l DEST_MODULE_LOCATION[316]=/updates/dkms -BUILT_MODULE_NAME[317]=rc-videomate-s350 +BUILT_MODULE_NAME[317]=saa716x_budget BUILT_MODULE_LOCATION[317]=./v4l DEST_MODULE_LOCATION[317]=/updates/dkms -BUILT_MODULE_NAME[318]=lgdt3305 +BUILT_MODULE_NAME[318]=streamzap BUILT_MODULE_LOCATION[318]=./v4l DEST_MODULE_LOCATION[318]=/updates/dkms -BUILT_MODULE_NAME[319]=rc-azurewave-ad-tu700 +BUILT_MODULE_NAME[319]=tda665x BUILT_MODULE_LOCATION[319]=./v4l DEST_MODULE_LOCATION[319]=/updates/dkms -BUILT_MODULE_NAME[320]=l64781 +BUILT_MODULE_NAME[320]=cx88xx BUILT_MODULE_LOCATION[320]=./v4l DEST_MODULE_LOCATION[320]=/updates/dkms -BUILT_MODULE_NAME[321]=rc-terratec-slim-2 +BUILT_MODULE_NAME[321]=mt2060 BUILT_MODULE_LOCATION[321]=./v4l DEST_MODULE_LOCATION[321]=/updates/dkms -BUILT_MODULE_NAME[322]=tvp5150 +BUILT_MODULE_NAME[322]=tda8290 BUILT_MODULE_LOCATION[322]=./v4l DEST_MODULE_LOCATION[322]=/updates/dkms -BUILT_MODULE_NAME[323]=rc-hauppauge +BUILT_MODULE_NAME[323]=rc-msi-tvanywhere-plus BUILT_MODULE_LOCATION[323]=./v4l DEST_MODULE_LOCATION[323]=/updates/dkms -BUILT_MODULE_NAME[324]=gspca_ov519 +BUILT_MODULE_NAME[324]=tda10086 BUILT_MODULE_LOCATION[324]=./v4l DEST_MODULE_LOCATION[324]=/updates/dkms -BUILT_MODULE_NAME[325]=streamzap +BUILT_MODULE_NAME[325]=stv6110 BUILT_MODULE_LOCATION[325]=./v4l DEST_MODULE_LOCATION[325]=/updates/dkms -BUILT_MODULE_NAME[326]=tda665x +BUILT_MODULE_NAME[326]=dib8000 BUILT_MODULE_LOCATION[326]=./v4l DEST_MODULE_LOCATION[326]=/updates/dkms -BUILT_MODULE_NAME[327]=cx88xx +BUILT_MODULE_NAME[327]=saa7134-alsa BUILT_MODULE_LOCATION[327]=./v4l DEST_MODULE_LOCATION[327]=/updates/dkms -BUILT_MODULE_NAME[328]=radio-typhoon +BUILT_MODULE_NAME[328]=upd64031a BUILT_MODULE_LOCATION[328]=./v4l DEST_MODULE_LOCATION[328]=/updates/dkms -BUILT_MODULE_NAME[329]=mt2060 +BUILT_MODULE_NAME[329]=ivtv BUILT_MODULE_LOCATION[329]=./v4l DEST_MODULE_LOCATION[329]=/updates/dkms -BUILT_MODULE_NAME[330]=tda8290 +BUILT_MODULE_NAME[330]=videodev BUILT_MODULE_LOCATION[330]=./v4l DEST_MODULE_LOCATION[330]=/updates/dkms -BUILT_MODULE_NAME[331]=rc-msi-tvanywhere-plus +BUILT_MODULE_NAME[331]=tda1004x BUILT_MODULE_LOCATION[331]=./v4l DEST_MODULE_LOCATION[331]=/updates/dkms -BUILT_MODULE_NAME[332]=tda10086 +BUILT_MODULE_NAME[332]=gspca_sonixb BUILT_MODULE_LOCATION[332]=./v4l DEST_MODULE_LOCATION[332]=/updates/dkms -BUILT_MODULE_NAME[333]=stv6110 +BUILT_MODULE_NAME[333]=earth-pt1 BUILT_MODULE_LOCATION[333]=./v4l DEST_MODULE_LOCATION[333]=/updates/dkms -BUILT_MODULE_NAME[334]=dib8000 +BUILT_MODULE_NAME[334]=zl10036 BUILT_MODULE_LOCATION[334]=./v4l DEST_MODULE_LOCATION[334]=/updates/dkms -BUILT_MODULE_NAME[335]=saa7134-alsa +BUILT_MODULE_NAME[335]=cx88-vp3054-i2c BUILT_MODULE_LOCATION[335]=./v4l DEST_MODULE_LOCATION[335]=/updates/dkms -BUILT_MODULE_NAME[336]=upd64031a +BUILT_MODULE_NAME[336]=cx2341x BUILT_MODULE_LOCATION[336]=./v4l DEST_MODULE_LOCATION[336]=/updates/dkms -BUILT_MODULE_NAME[337]=ivtv +BUILT_MODULE_NAME[337]=vpx3220 BUILT_MODULE_LOCATION[337]=./v4l DEST_MODULE_LOCATION[337]=/updates/dkms -BUILT_MODULE_NAME[338]=videodev +BUILT_MODULE_NAME[338]=em28xx-dvb BUILT_MODULE_LOCATION[338]=./v4l DEST_MODULE_LOCATION[338]=/updates/dkms -BUILT_MODULE_NAME[339]=radio-cadet +BUILT_MODULE_NAME[339]=rc-avermedia-dvbt BUILT_MODULE_LOCATION[339]=./v4l DEST_MODULE_LOCATION[339]=/updates/dkms -BUILT_MODULE_NAME[340]=tda1004x +BUILT_MODULE_NAME[340]=ir-lirc-codec BUILT_MODULE_LOCATION[340]=./v4l DEST_MODULE_LOCATION[340]=/updates/dkms -BUILT_MODULE_NAME[341]=gspca_sonixb +BUILT_MODULE_NAME[341]=bt856 BUILT_MODULE_LOCATION[341]=./v4l DEST_MODULE_LOCATION[341]=/updates/dkms -BUILT_MODULE_NAME[342]=earth-pt1 +BUILT_MODULE_NAME[342]=tef6862 BUILT_MODULE_LOCATION[342]=./v4l DEST_MODULE_LOCATION[342]=/updates/dkms -BUILT_MODULE_NAME[343]=zl10036 +BUILT_MODULE_NAME[343]=videobuf2-memops BUILT_MODULE_LOCATION[343]=./v4l DEST_MODULE_LOCATION[343]=/updates/dkms -BUILT_MODULE_NAME[344]=cx88-vp3054-i2c +BUILT_MODULE_NAME[344]=gspca_konica BUILT_MODULE_LOCATION[344]=./v4l DEST_MODULE_LOCATION[344]=/updates/dkms -BUILT_MODULE_NAME[345]=cx2341x +BUILT_MODULE_NAME[345]=rc-videomate-m1f BUILT_MODULE_LOCATION[345]=./v4l DEST_MODULE_LOCATION[345]=/updates/dkms -BUILT_MODULE_NAME[346]=vpx3220 +BUILT_MODULE_NAME[346]=radio-si4713 BUILT_MODULE_LOCATION[346]=./v4l DEST_MODULE_LOCATION[346]=/updates/dkms -BUILT_MODULE_NAME[347]=em28xx-dvb +BUILT_MODULE_NAME[347]=dvb-usb-a800 BUILT_MODULE_LOCATION[347]=./v4l DEST_MODULE_LOCATION[347]=/updates/dkms -BUILT_MODULE_NAME[348]=rc-avermedia-dvbt +BUILT_MODULE_NAME[348]=s5h1432 BUILT_MODULE_LOCATION[348]=./v4l DEST_MODULE_LOCATION[348]=/updates/dkms -BUILT_MODULE_NAME[349]=bt856 +BUILT_MODULE_NAME[349]=ir-sony-decoder BUILT_MODULE_LOCATION[349]=./v4l DEST_MODULE_LOCATION[349]=/updates/dkms -BUILT_MODULE_NAME[350]=tef6862 +BUILT_MODULE_NAME[350]=rc-msi-tvanywhere BUILT_MODULE_LOCATION[350]=./v4l DEST_MODULE_LOCATION[350]=/updates/dkms -BUILT_MODULE_NAME[351]=videobuf2-memops +BUILT_MODULE_NAME[351]=dm1105 BUILT_MODULE_LOCATION[351]=./v4l DEST_MODULE_LOCATION[351]=/updates/dkms -BUILT_MODULE_NAME[352]=gspca_konica +BUILT_MODULE_NAME[352]=mt352 BUILT_MODULE_LOCATION[352]=./v4l DEST_MODULE_LOCATION[352]=/updates/dkms -BUILT_MODULE_NAME[353]=rc-videomate-m1f +BUILT_MODULE_NAME[353]=ir-rc5-sz-decoder BUILT_MODULE_LOCATION[353]=./v4l DEST_MODULE_LOCATION[353]=/updates/dkms -BUILT_MODULE_NAME[354]=radio-si4713 +BUILT_MODULE_NAME[354]=rc-fusionhdtv-mce BUILT_MODULE_LOCATION[354]=./v4l DEST_MODULE_LOCATION[354]=/updates/dkms -BUILT_MODULE_NAME[355]=dvb-usb-a800 +BUILT_MODULE_NAME[355]=rc-dib0700-nec BUILT_MODULE_LOCATION[355]=./v4l DEST_MODULE_LOCATION[355]=/updates/dkms -BUILT_MODULE_NAME[356]=s5h1432 +BUILT_MODULE_NAME[356]=cafe_ccic BUILT_MODULE_LOCATION[356]=./v4l DEST_MODULE_LOCATION[356]=/updates/dkms -BUILT_MODULE_NAME[357]=ir-sony-decoder +BUILT_MODULE_NAME[357]=dvb-usb-dtt200u BUILT_MODULE_LOCATION[357]=./v4l DEST_MODULE_LOCATION[357]=/updates/dkms -BUILT_MODULE_NAME[358]=rc-msi-tvanywhere +BUILT_MODULE_NAME[358]=mceusb BUILT_MODULE_LOCATION[358]=./v4l DEST_MODULE_LOCATION[358]=/updates/dkms -BUILT_MODULE_NAME[359]=dm1105 +BUILT_MODULE_NAME[359]=drxd BUILT_MODULE_LOCATION[359]=./v4l DEST_MODULE_LOCATION[359]=/updates/dkms -BUILT_MODULE_NAME[360]=videobuf-dma-contig +BUILT_MODULE_NAME[360]=smsusb BUILT_MODULE_LOCATION[360]=./v4l DEST_MODULE_LOCATION[360]=/updates/dkms -BUILT_MODULE_NAME[361]=mt352 +BUILT_MODULE_NAME[361]=bt878 BUILT_MODULE_LOCATION[361]=./v4l DEST_MODULE_LOCATION[361]=/updates/dkms -BUILT_MODULE_NAME[362]=ir-rc5-sz-decoder +BUILT_MODULE_NAME[362]=pluto2 BUILT_MODULE_LOCATION[362]=./v4l DEST_MODULE_LOCATION[362]=/updates/dkms -BUILT_MODULE_NAME[363]=rc-fusionhdtv-mce +BUILT_MODULE_NAME[363]=b2c2-flexcop-usb BUILT_MODULE_LOCATION[363]=./v4l DEST_MODULE_LOCATION[363]=/updates/dkms -BUILT_MODULE_NAME[364]=rc-dib0700-nec +BUILT_MODULE_NAME[364]=mt2266 BUILT_MODULE_LOCATION[364]=./v4l DEST_MODULE_LOCATION[364]=/updates/dkms -BUILT_MODULE_NAME[365]=cafe_ccic +BUILT_MODULE_NAME[365]=dvb-usb-af9005 BUILT_MODULE_LOCATION[365]=./v4l DEST_MODULE_LOCATION[365]=/updates/dkms -BUILT_MODULE_NAME[366]=dvb-usb-dtt200u +BUILT_MODULE_NAME[366]=dvb-core BUILT_MODULE_LOCATION[366]=./v4l DEST_MODULE_LOCATION[366]=/updates/dkms -BUILT_MODULE_NAME[367]=mceusb +BUILT_MODULE_NAME[367]=rc-total-media-in-hand BUILT_MODULE_LOCATION[367]=./v4l DEST_MODULE_LOCATION[367]=/updates/dkms -BUILT_MODULE_NAME[368]=smsusb +BUILT_MODULE_NAME[368]=rc-cinergy BUILT_MODULE_LOCATION[368]=./v4l DEST_MODULE_LOCATION[368]=/updates/dkms -BUILT_MODULE_NAME[369]=bt878 +BUILT_MODULE_NAME[369]=lgdt330x BUILT_MODULE_LOCATION[369]=./v4l DEST_MODULE_LOCATION[369]=/updates/dkms -BUILT_MODULE_NAME[370]=pluto2 +BUILT_MODULE_NAME[370]=dvb-usb-dib0700 BUILT_MODULE_LOCATION[370]=./v4l DEST_MODULE_LOCATION[370]=/updates/dkms -BUILT_MODULE_NAME[371]=b2c2-flexcop-usb +BUILT_MODULE_NAME[371]=saa716x_core BUILT_MODULE_LOCATION[371]=./v4l DEST_MODULE_LOCATION[371]=/updates/dkms -BUILT_MODULE_NAME[372]=mt2266 +BUILT_MODULE_NAME[372]=rc-pctv-sedna BUILT_MODULE_LOCATION[372]=./v4l DEST_MODULE_LOCATION[372]=/updates/dkms -BUILT_MODULE_NAME[373]=dvb-usb-af9005 +BUILT_MODULE_NAME[373]=zr36067 BUILT_MODULE_LOCATION[373]=./v4l DEST_MODULE_LOCATION[373]=/updates/dkms -BUILT_MODULE_NAME[374]=dvb-core +BUILT_MODULE_NAME[374]=af9013 BUILT_MODULE_LOCATION[374]=./v4l DEST_MODULE_LOCATION[374]=/updates/dkms -BUILT_MODULE_NAME[375]=rc-total-media-in-hand +BUILT_MODULE_NAME[375]=usbvision BUILT_MODULE_LOCATION[375]=./v4l DEST_MODULE_LOCATION[375]=/updates/dkms -BUILT_MODULE_NAME[376]=rc-cinergy +BUILT_MODULE_NAME[376]=dvb-usb-ttusb2 BUILT_MODULE_LOCATION[376]=./v4l DEST_MODULE_LOCATION[376]=/updates/dkms -BUILT_MODULE_NAME[377]=lgdt330x +BUILT_MODULE_NAME[377]=zr364xx BUILT_MODULE_LOCATION[377]=./v4l DEST_MODULE_LOCATION[377]=/updates/dkms -BUILT_MODULE_NAME[378]=dvb-usb-dib0700 +BUILT_MODULE_NAME[378]=tda10048 BUILT_MODULE_LOCATION[378]=./v4l DEST_MODULE_LOCATION[378]=/updates/dkms -BUILT_MODULE_NAME[379]=rc-pctv-sedna +BUILT_MODULE_NAME[379]=tda10023 BUILT_MODULE_LOCATION[379]=./v4l DEST_MODULE_LOCATION[379]=/updates/dkms -BUILT_MODULE_NAME[380]=zr36067 +BUILT_MODULE_NAME[380]=tda9840 BUILT_MODULE_LOCATION[380]=./v4l DEST_MODULE_LOCATION[380]=/updates/dkms -BUILT_MODULE_NAME[381]=af9013 +BUILT_MODULE_NAME[381]=bt819 BUILT_MODULE_LOCATION[381]=./v4l DEST_MODULE_LOCATION[381]=/updates/dkms -BUILT_MODULE_NAME[382]=usbvision +BUILT_MODULE_NAME[382]=smsmdtv BUILT_MODULE_LOCATION[382]=./v4l DEST_MODULE_LOCATION[382]=/updates/dkms -BUILT_MODULE_NAME[383]=dvb-usb-ttusb2 +BUILT_MODULE_NAME[383]=dib3000mc BUILT_MODULE_LOCATION[383]=./v4l DEST_MODULE_LOCATION[383]=/updates/dkms -BUILT_MODULE_NAME[384]=zr364xx +BUILT_MODULE_NAME[384]=mc44s803 BUILT_MODULE_LOCATION[384]=./v4l DEST_MODULE_LOCATION[384]=/updates/dkms -BUILT_MODULE_NAME[385]=tda10048 +BUILT_MODULE_NAME[385]=rc-em-terratec BUILT_MODULE_LOCATION[385]=./v4l DEST_MODULE_LOCATION[385]=/updates/dkms -BUILT_MODULE_NAME[386]=tda10023 +BUILT_MODULE_NAME[386]=btcx-risc BUILT_MODULE_LOCATION[386]=./v4l DEST_MODULE_LOCATION[386]=/updates/dkms -BUILT_MODULE_NAME[387]=tda9840 +BUILT_MODULE_NAME[387]=dvb-ttpci BUILT_MODULE_LOCATION[387]=./v4l DEST_MODULE_LOCATION[387]=/updates/dkms -BUILT_MODULE_NAME[388]=bt819 +BUILT_MODULE_NAME[388]=tvp514x BUILT_MODULE_LOCATION[388]=./v4l DEST_MODULE_LOCATION[388]=/updates/dkms -BUILT_MODULE_NAME[389]=smsmdtv +BUILT_MODULE_NAME[389]=dib7000p BUILT_MODULE_LOCATION[389]=./v4l DEST_MODULE_LOCATION[389]=/updates/dkms -BUILT_MODULE_NAME[390]=dib3000mc +BUILT_MODULE_NAME[390]=rc-avertv-303 BUILT_MODULE_LOCATION[390]=./v4l DEST_MODULE_LOCATION[390]=/updates/dkms -BUILT_MODULE_NAME[391]=mc44s803 +BUILT_MODULE_NAME[391]=rc-lirc BUILT_MODULE_LOCATION[391]=./v4l DEST_MODULE_LOCATION[391]=/updates/dkms -BUILT_MODULE_NAME[392]=rc-em-terratec +BUILT_MODULE_NAME[392]=rc-iodata-bctv7e BUILT_MODULE_LOCATION[392]=./v4l DEST_MODULE_LOCATION[392]=/updates/dkms -BUILT_MODULE_NAME[393]=btcx-risc +BUILT_MODULE_NAME[393]=s5h1409 BUILT_MODULE_LOCATION[393]=./v4l DEST_MODULE_LOCATION[393]=/updates/dkms -BUILT_MODULE_NAME[394]=dvb-ttpci +BUILT_MODULE_NAME[394]=stb0899 BUILT_MODULE_LOCATION[394]=./v4l DEST_MODULE_LOCATION[394]=/updates/dkms -BUILT_MODULE_NAME[395]=tvp514x +BUILT_MODULE_NAME[395]=smsdvb BUILT_MODULE_LOCATION[395]=./v4l DEST_MODULE_LOCATION[395]=/updates/dkms -BUILT_MODULE_NAME[396]=dib7000p +BUILT_MODULE_NAME[396]=tuner-xc2028 BUILT_MODULE_LOCATION[396]=./v4l DEST_MODULE_LOCATION[396]=/updates/dkms -BUILT_MODULE_NAME[397]=rc-avertv-303 +BUILT_MODULE_NAME[397]=hexium_orion BUILT_MODULE_LOCATION[397]=./v4l DEST_MODULE_LOCATION[397]=/updates/dkms -BUILT_MODULE_NAME[398]=rc-lirc +BUILT_MODULE_NAME[398]=saa6752hs BUILT_MODULE_LOCATION[398]=./v4l DEST_MODULE_LOCATION[398]=/updates/dkms -BUILT_MODULE_NAME[399]=rc-iodata-bctv7e +BUILT_MODULE_NAME[399]=ene_ir BUILT_MODULE_LOCATION[399]=./v4l DEST_MODULE_LOCATION[399]=/updates/dkms -BUILT_MODULE_NAME[400]=s5h1409 +BUILT_MODULE_NAME[400]=dvb-usb-cinergyT2 BUILT_MODULE_LOCATION[400]=./v4l DEST_MODULE_LOCATION[400]=/updates/dkms -BUILT_MODULE_NAME[401]=stb0899 +BUILT_MODULE_NAME[401]=si4713-i2c BUILT_MODULE_LOCATION[401]=./v4l DEST_MODULE_LOCATION[401]=/updates/dkms -BUILT_MODULE_NAME[402]=smsdvb +BUILT_MODULE_NAME[402]=tda18212 BUILT_MODULE_LOCATION[402]=./v4l DEST_MODULE_LOCATION[402]=/updates/dkms -BUILT_MODULE_NAME[403]=tuner-xc2028 +BUILT_MODULE_NAME[403]=gspca_kinect BUILT_MODULE_LOCATION[403]=./v4l DEST_MODULE_LOCATION[403]=/updates/dkms -BUILT_MODULE_NAME[404]=hexium_orion +BUILT_MODULE_NAME[404]=gspca_pac7302 BUILT_MODULE_LOCATION[404]=./v4l DEST_MODULE_LOCATION[404]=/updates/dkms -BUILT_MODULE_NAME[405]=saa6752hs +BUILT_MODULE_NAME[405]=ks0127 BUILT_MODULE_LOCATION[405]=./v4l DEST_MODULE_LOCATION[405]=/updates/dkms -BUILT_MODULE_NAME[406]=ene_ir +BUILT_MODULE_NAME[406]=rc-encore-enltv2 BUILT_MODULE_LOCATION[406]=./v4l DEST_MODULE_LOCATION[406]=/updates/dkms -BUILT_MODULE_NAME[407]=dvb-usb-cinergyT2 +BUILT_MODULE_NAME[407]=gspca_m5602 BUILT_MODULE_LOCATION[407]=./v4l DEST_MODULE_LOCATION[407]=/updates/dkms -BUILT_MODULE_NAME[408]=si4713-i2c +BUILT_MODULE_NAME[408]=cx88-alsa BUILT_MODULE_LOCATION[408]=./v4l DEST_MODULE_LOCATION[408]=/updates/dkms -BUILT_MODULE_NAME[409]=gspca_pac7302 +BUILT_MODULE_NAME[409]=dib7000m BUILT_MODULE_LOCATION[409]=./v4l DEST_MODULE_LOCATION[409]=/updates/dkms -BUILT_MODULE_NAME[410]=ks0127 +BUILT_MODULE_NAME[410]=et61x251 BUILT_MODULE_LOCATION[410]=./v4l DEST_MODULE_LOCATION[410]=/updates/dkms -BUILT_MODULE_NAME[411]=rc-encore-enltv2 +BUILT_MODULE_NAME[411]=rc-terratec-slim BUILT_MODULE_LOCATION[411]=./v4l DEST_MODULE_LOCATION[411]=/updates/dkms -BUILT_MODULE_NAME[412]=gspca_m5602 +BUILT_MODULE_NAME[412]=rc-imon-mce BUILT_MODULE_LOCATION[412]=./v4l DEST_MODULE_LOCATION[412]=/updates/dkms -BUILT_MODULE_NAME[413]=cx88-alsa +BUILT_MODULE_NAME[413]=rc-purpletv BUILT_MODULE_LOCATION[413]=./v4l DEST_MODULE_LOCATION[413]=/updates/dkms -BUILT_MODULE_NAME[414]=dib7000m +BUILT_MODULE_NAME[414]=cx8802 BUILT_MODULE_LOCATION[414]=./v4l DEST_MODULE_LOCATION[414]=/updates/dkms -BUILT_MODULE_NAME[415]=et61x251 +BUILT_MODULE_NAME[415]=rc-terratec-cinergy-c-pci BUILT_MODULE_LOCATION[415]=./v4l DEST_MODULE_LOCATION[415]=/updates/dkms -BUILT_MODULE_NAME[416]=rc-terratec-slim +BUILT_MODULE_NAME[416]=rc-nebula BUILT_MODULE_LOCATION[416]=./v4l DEST_MODULE_LOCATION[416]=/updates/dkms -BUILT_MODULE_NAME[417]=rc-imon-mce +BUILT_MODULE_NAME[417]=budget-ci BUILT_MODULE_LOCATION[417]=./v4l DEST_MODULE_LOCATION[417]=/updates/dkms -BUILT_MODULE_NAME[418]=rc-purpletv +BUILT_MODULE_NAME[418]=saa7110 BUILT_MODULE_LOCATION[418]=./v4l DEST_MODULE_LOCATION[418]=/updates/dkms -BUILT_MODULE_NAME[419]=cx8802 +BUILT_MODULE_NAME[419]=rc-twinhan1027 BUILT_MODULE_LOCATION[419]=./v4l DEST_MODULE_LOCATION[419]=/updates/dkms -BUILT_MODULE_NAME[420]=rc-nebula +BUILT_MODULE_NAME[420]=gspca_cpia1 BUILT_MODULE_LOCATION[420]=./v4l DEST_MODULE_LOCATION[420]=/updates/dkms -BUILT_MODULE_NAME[421]=budget-ci +BUILT_MODULE_NAME[421]=atbm8830 BUILT_MODULE_LOCATION[421]=./v4l DEST_MODULE_LOCATION[421]=/updates/dkms -BUILT_MODULE_NAME[422]=saa7110 +BUILT_MODULE_NAME[422]=tlv320aic23b BUILT_MODULE_LOCATION[422]=./v4l DEST_MODULE_LOCATION[422]=/updates/dkms -BUILT_MODULE_NAME[423]=rc-twinhan1027 +BUILT_MODULE_NAME[423]=dvb-usb-lmedm04 BUILT_MODULE_LOCATION[423]=./v4l DEST_MODULE_LOCATION[423]=/updates/dkms -BUILT_MODULE_NAME[424]=gspca_cpia1 +BUILT_MODULE_NAME[424]=or51132 BUILT_MODULE_LOCATION[424]=./v4l DEST_MODULE_LOCATION[424]=/updates/dkms -BUILT_MODULE_NAME[425]=atbm8830 +BUILT_MODULE_NAME[425]=cs5345 BUILT_MODULE_LOCATION[425]=./v4l DEST_MODULE_LOCATION[425]=/updates/dkms -BUILT_MODULE_NAME[426]=tlv320aic23b +BUILT_MODULE_NAME[426]=dvb-usb-ec168 BUILT_MODULE_LOCATION[426]=./v4l DEST_MODULE_LOCATION[426]=/updates/dkms -BUILT_MODULE_NAME[427]=dvb-usb-lmedm04 +BUILT_MODULE_NAME[427]=rc-pixelview-mk12 BUILT_MODULE_LOCATION[427]=./v4l DEST_MODULE_LOCATION[427]=/updates/dkms -BUILT_MODULE_NAME[428]=or51132 +BUILT_MODULE_NAME[428]=gspca_spca500 BUILT_MODULE_LOCATION[428]=./v4l DEST_MODULE_LOCATION[428]=/updates/dkms -BUILT_MODULE_NAME[429]=radio-aztech +BUILT_MODULE_NAME[429]=rc-powercolor-real-angel BUILT_MODULE_LOCATION[429]=./v4l DEST_MODULE_LOCATION[429]=/updates/dkms -BUILT_MODULE_NAME[430]=cs5345 +BUILT_MODULE_NAME[430]=mt9v011 BUILT_MODULE_LOCATION[430]=./v4l DEST_MODULE_LOCATION[430]=/updates/dkms -BUILT_MODULE_NAME[431]=dvb-usb-ec168 +BUILT_MODULE_NAME[431]=ttusbdecfe BUILT_MODULE_LOCATION[431]=./v4l DEST_MODULE_LOCATION[431]=/updates/dkms -BUILT_MODULE_NAME[432]=rc-pixelview-mk12 +BUILT_MODULE_NAME[432]=rc-alink-dtu-m BUILT_MODULE_LOCATION[432]=./v4l DEST_MODULE_LOCATION[432]=/updates/dkms -BUILT_MODULE_NAME[433]=gspca_spca500 +BUILT_MODULE_NAME[433]=saa7134-dvb BUILT_MODULE_LOCATION[433]=./v4l DEST_MODULE_LOCATION[433]=/updates/dkms -BUILT_MODULE_NAME[434]=rc-powercolor-real-angel -BUILT_MODULE_LOCATION[434]=./v4l -DEST_MODULE_LOCATION[434]=/updates/dkms -BUILT_MODULE_NAME[435]=mt9v011 -BUILT_MODULE_LOCATION[435]=./v4l -DEST_MODULE_LOCATION[435]=/updates/dkms -BUILT_MODULE_NAME[436]=ttusbdecfe -BUILT_MODULE_LOCATION[436]=./v4l -DEST_MODULE_LOCATION[436]=/updates/dkms -BUILT_MODULE_NAME[437]=rc-alink-dtu-m -BUILT_MODULE_LOCATION[437]=./v4l -DEST_MODULE_LOCATION[437]=/updates/dkms -BUILT_MODULE_NAME[438]=saa7134-dvb -BUILT_MODULE_LOCATION[438]=./v4l -DEST_MODULE_LOCATION[438]=/updates/dkms diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/dkms_binaries_only/PACKAGE_VERSION v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_binaries_only/PACKAGE_VERSION --- v4l-dvb-dkms-0~20110324.git235676.160/dkms_binaries_only/PACKAGE_VERSION 2011-03-24 07:53:52.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_binaries_only/PACKAGE_VERSION 2011-06-25 16:18:20.000000000 +0000 @@ -1 +1 @@ -0~20110324.git235676.160 +0~20110625.git255868.188~lucid diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/log/make.log v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/log/make.log --- v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/log/make.log 2011-03-24 07:53:52.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/log/make.log 1970-01-01 00:00:00.000000000 +0000 @@ -1,1800 +0,0 @@ -DKMS make.log for v4l-dvb-0~20110324.git235676.160 for kernel 2.6.32-30-generic (i686) -Thu Mar 24 08:51:47 CET 2011 -make -C /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l -make[1]: Entering directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l' -scripts/make_makefile.pl -Forcing kernel version to 2.6.32-30-generic. -Updating/Creating .config -make[2]: Entering directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/linux' -Applying patches for kernel v2.6.32-30-generic -cat: ../backports/v2.6.32-30-generic_series: No such file or directory -Patched drivers/media/dvb/dvb-core/dvbdev.c -Patched drivers/media/video/v4l2-dev.c -Patched drivers/media/rc/rc-main.c -make[2]: Leaving directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/linux' -./scripts/make_kconfig.pl /lib/modules/2.6.32-30-generic/build /lib/modules/2.6.32-30-generic/build -Preparing to compile for kernel version 2.6.32 - -***WARNING:*** You do not have the full kernel sources installed. -This does not prevent you from building the v4l-dvb tree if you have the -kernel headers, but the full kernel source may be required in order to use -make menuconfig / xconfig / qconfig. - -If you are experiencing problems building the v4l-dvb tree, please try -building against a vanilla kernel before reporting a bug. - -Vanilla kernels are available at http://kernel.org. -On most distros, this will compile a newly downloaded kernel: - -cp /boot/config-`uname -r` /.config -cd -make all modules_install install - -Please see your distro's web site for instructions to build a new kernel. - -WARNING: This is the V4L/DVB backport tree, with experimental drivers - backported to run on legacy kernels from the development tree at: - http://git.linuxtv.org/media-tree.git. - It is generally safe to use it for testing a new driver or - feature, but its usage on production environments is risky. - Don't use it in production. You've been warned. -V4L2_MEM2MEM_DEV: Requires at least kernel 2.6.33 -VIDEO_TVP7002: Requires at least kernel 2.6.34 -VIDEO_AK881X: Requires at least kernel 2.6.33 -VIDEO_VIA_CAMERA: Requires at least kernel 2.6.37 -SOC_CAMERA: Requires at least kernel 2.6.33 -SOC_CAMERA_MT9M001: Requires at least kernel 2.6.33 -SOC_CAMERA_MT9M111: Requires at least kernel 2.6.33 -SOC_CAMERA_MT9T031: Requires at least kernel 2.6.33 -SOC_CAMERA_MT9V022: Requires at least kernel 2.6.33 -SOC_CAMERA_TW9910: Requires at least kernel 2.6.33 -SOC_CAMERA_PLATFORM: Requires at least kernel 2.6.33 -SOC_CAMERA_OV772X: Requires at least kernel 2.6.33 -RADIO_SAA7706H: Requires at least kernel 2.6.34 -RADIO_WL1273: Requires at least kernel 2.6.39 -./scripts/make_myconfig.pl -make[1]: Leaving directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l' -make[1]: Entering directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l' -perl scripts/make_config_compat.pl /lib/modules/2.6.32-30-generic/build ./.myconfig ./config-compat.h -make -C firmware prep -creating symbolic links... -make[2]: Entering directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firmware' -make[2]: Leaving directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firmware' -make -C firmware -make[2]: Entering directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firmware' - CC ihex2fw -Generating vicam/firmware.fw -Generating dabusb/firmware.fw -Generating dabusb/bitstream.bin -Generating ttusb-budget/dspbootcode.bin -Generating cpia2/stv0672_vp4.bin -Generating av7110/bootcode.bin -make[2]: Leaving directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firmware' -Kernel build directory is /lib/modules/2.6.32-30-generic/build -make -C ../linux apply_patches -make[2]: Entering directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/linux' -Patches for v2.6.32-30-generic already applied. -make[2]: Leaving directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/linux' -make -C /lib/modules/2.6.32-30-generic/build SUBDIRS=/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l modules -make[2]: Entering directory `/usr/src/linux-headers-2.6.32-30-generic' - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-xc2028.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-simple.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-types.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt20xx.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda8290.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea5767.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea5761.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda9887.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda827x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au0828-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au0828-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au0828-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au0828-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au0828-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au0828-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au8522_dig.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au8522_decoder.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop-pci.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop-usb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop-fe-tuner.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop-sram.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop-eeprom.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop-misc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop-hw-filter.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/flexcop-dma.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv-driver.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv-if.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv-risc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv-gpio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv-input.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv-audio-hook.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cpia2_v4l.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cpia2_usb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cpia2_core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-alsa-main.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-alsa-pcm.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-driver.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-firmware.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-gpio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-queue.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-streams.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-fileops.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-ioctl.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-controls.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-mailbox.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-audio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-irq.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-av-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-av-audio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-av-firmware.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-av-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-scb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-io.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-audio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-avcore.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-417.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-pcb-cfg.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-input.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-417.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-ioctl.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-ir.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-av.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-input.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23888-ir.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/netup-init.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cimax2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/netup-eeprom.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885-f300.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx25840-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx25840-audio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx25840-firmware.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx25840-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx25840-ir.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-mpeg.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-tvaudio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-dsp.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-input.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvbdev.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dmxdev.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_demux.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_filter.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_ca_en50221.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_frontend.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_net.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_ringbuffer.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_math.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/av7110_hw.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/av7110_v4l.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/av7110_av.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/av7110_ca.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/av7110.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/av7110_ipack.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/av7110_ir.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/a800.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/af9005-remote.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/af9005.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/af9005-fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/af9015.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/anysee.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au6610.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/az6027.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ce6230.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cinergyT2-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cinergyT2-fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cxusb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib0700_core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib0700_devices.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dibusb-common.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dibusb-mb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dibusb-mc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/digitv.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dtt200u.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dtt200u-fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dtv5100.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dw2102.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ec168.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/friio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/friio-fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gl861.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gp8psk-fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gp8psk.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lmedm04.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m920x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nova-t-usb2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/opera1.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/technisat-usb2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttusb2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/umt-010.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vp702x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vp702x-fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vp7045.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vp7045-fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-firmware.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-init.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-urb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-remote.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/usb-urb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pt1.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/va1j5jf8007s.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/va1j5jf8007t.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-audio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-input.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/et61x251_core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/et61x251_tas5130d1b.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firedtv-avc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firedtv-ci.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firedtv-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firedtv-fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firedtv-fw.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firedtv-rc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/benq.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/conex.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cpia1.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/etoms.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/finepix.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gl860.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gl860-mi1320.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gl860-ov2640.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gl860-ov9655.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gl860-mi2020.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/jeilinj.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/konica.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m5602_core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m5602_ov9650.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m5602_ov7660.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m5602_mt9m111.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m5602_po1030.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m5602_s5k83a.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m5602_s5k4aa.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mars.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mr97310a.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ov519.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ov534.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ov534_9.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pac207.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pac7302.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pac7311.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c2028.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c20x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sonixb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sonixj.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/spca1528.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/spca500.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/spca501.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/spca505.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/spca506.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/spca508.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/spca561.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sq905.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sq905c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sq930x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stk014.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0680.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv06xx.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv06xx_vv6410.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv06xx_hdcs.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv06xx_pb0100.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv06xx_st6422.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sunplus.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/t613.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tv8532.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vc032x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vicam.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/xirlink_cit.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zc3xx.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hdpvr-control.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hdpvr-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hdpvr-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hdpvr-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hopper_cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hopper_vp3028.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-routing.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-controls.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-driver.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-fileops.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-firmware.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-gpio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-ioctl.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-irq.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-mailbox.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-queue.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-streams.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-udma.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv-yuv.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_vp1033.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_vp1034.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_vp1041.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_vp2033.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_vp2040.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_vp3030.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_ioc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_uart.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_dma.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_pci.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_evm.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_hif.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_ca.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_pcmcia.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_input.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/msp3400-driver.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/msp3400-kthreads.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ngene-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ngene-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ngene-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ngene-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pd-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pd-alsa.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pd-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pd-radio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pd-main.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-i2c-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-audio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-encoder.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-video-v4l.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-eeprom.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-main.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-hdw.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-v4l2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-ctrl.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-std.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-devattr.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-context.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-io.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-ioread.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-cx2584x-v4l.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-wm8775.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-cs53l32a.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-sysfs.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2-debugifc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc-if.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc-misc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc-ctrl.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc-v4l.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc-uncompress.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc-dec1.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc-dec23.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc-kiara.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc-timon.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-si470x-usb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-si470x-common.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-main.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-raw.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-ts.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-tvaudio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-input.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146_i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146_core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146_fops.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146_video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146_hlp.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146_vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-fw.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-bus.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-cmd.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-api.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-buffer.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-encoder.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164-vbi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smscoreapi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sms-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsendian.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsir.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_hv7131d.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_hv7131r.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_mi0343.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_mi0360.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_mt9v111.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_ov7630.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_ov7660.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_pas106b.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_pas202bcb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_tas5110c1b.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_tas5110d.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102_tas5130d1b.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt87x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea575x-tuner.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb0899_drv.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb0899_algo.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stk-webcam.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stk-sensor.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0900_core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0900_sw.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda18271-maps.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda18271-common.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda18271-fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/usbvision-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/usbvision-video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/usbvision-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/usbvision-cards.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvc_driver.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvc_queue.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvc_v4l2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvc_video.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvc_ctrl.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvc_status.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvc_isight.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-dev.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-ioctl.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-device.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-fh.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-event.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-ctrls.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-subdev.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zoran_procfs.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zoran_device.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zoran_driver.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zoran_card.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/xc5000.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt2060.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt2266.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/qt1010.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt2131.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mxl5005s.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mxl5007t.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mc44s803.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/max2165.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda18218.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146_vv.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-adstech-dvb-t-pci.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-alink-dtu-m.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-anysee.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-apac-viewcomp.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-asus-pc39.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-ati-tv-wonder-hd-600.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-a16d.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-cardbus.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-dvbt.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-m135a.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-m733a-rm-k6.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-rm-ks.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avertv-303.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-azurewave-ad-tu700.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-behold.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-behold-columbus.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-budget-ci-old.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-cinergy-1400.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-cinergy.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dib0700-nec.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dib0700-rc5.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-digitalnow-tinytwin.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-digittrade.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dm1105-nec.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dntv-live-dvb-t.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dntv-live-dvbt-pro.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-em-terratec.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-encore-enltv2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-encore-enltv.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-encore-enltv-fm53.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-evga-indtube.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-eztv.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-flydvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-flyvideo.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-fusionhdtv-mce.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-gadmei-rm008z.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-genius-tvgo-a11mce.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-gotview7135.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-imon-mce.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-imon-pad.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-iodata-bctv7e.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-kaiomy.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-kworld-315u.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-kworld-plus-tv-analog.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-leadtek-y04g0051.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-lirc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-lme2510.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-manli.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-digivox-ii.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-digivox-iii.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-tvanywhere.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-tvanywhere-plus.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-nebula.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-nec-terratec-cinergy-xs.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-norwood.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-npgtech.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pctv-sedna.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pinnacle-color.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pinnacle-grey.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pinnacle-pctv-hd.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview-mk12.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview-002t.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview-new.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-powercolor-real-angel.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-proteus-2309.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-purpletv.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pv951.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-hauppauge.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-rc6-mce.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-real-audio-220-32-keys.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-streamzap.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-tbs-nec.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-technisat-usb2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-terratec-cinergy-xs.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-terratec-slim.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-terratec-slim-2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-tevii-nec.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-total-media-in-hand.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-trekstor.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-tt-1500.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-twinhan1027.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-videomate-m1f.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-videomate-s350.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-videomate-tv-pvr.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-winfast.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-winfast-usbii-deluxe.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-nec-decoder.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-rc5-decoder.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-rc6-decoder.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-jvc-decoder.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-sony-decoder.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-rc5-sz-decoder.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/imon.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mceusb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nuvoton-cir.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ene_ir.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/streamzap.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/winbond-cir.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-loopback.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videodev.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-int-device.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-common.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tvaudio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda7432.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa6588.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda9840.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea6415c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea6420.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7110.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7115.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa717x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7127.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7185.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7191.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7170.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7175.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7180.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7343.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vpx3220.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt819.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt856.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt866.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ks0127.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ths7303.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tvp5150.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tvp514x.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/msp3400.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cs5345.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cs53l32a.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m52790.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tlv320aic23b.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/wm8775.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/wm8739.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vp27smpx.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx25840.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/upd64031a.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/upd64083.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ov7670.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tcm825x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tveeprom.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt9v011.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sr030pc30.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/noon010pc30.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36067.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videocodec.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36050.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36016.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36060.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/c-qcam.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bw-qcam.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/w9966.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pms.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/meye.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa6752hs.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-empress.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-alsa.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-dvb.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88xx.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx8800.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx8802.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-alsa.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-blackbird.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-vp3054-i2c.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-alsa.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-dvb.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/poseidon.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-alsa.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-dvb.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/usbvision.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cpia2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mxb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hexium_orion.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hexium_gemini.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-dma-sg.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-dma-contig.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-vmalloc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-dvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/btcx-risc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-memops.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-vmalloc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-dma-contig.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-dma-sg.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx2341x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cafe_ccic.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr364xx.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stkwebcam.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/et61x251.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_main.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_benq.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_conex.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_cpia1.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_etoms.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_finepix.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_jeilinj.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_konica.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_mars.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_mr97310a.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_ov519.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_ov534.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_ov534_9.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_pac207.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_pac7302.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_pac7311.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sn9c2028.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sn9c20x.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sonixb.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sonixj.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca500.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca501.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca505.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca506.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca508.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca561.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca1528.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sq905.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sq905c.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sq930x.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sunplus.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_stk014.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_stv0680.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_t613.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_tv8532.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_vc032x.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_vicam.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_xirlink_cit.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_zc3xx.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_m5602.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_stv06xx.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_gl860.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hdpvr.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s2255drv.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtvfb.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-alsa.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vivi.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au0828.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvcvideo.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-kbd-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-aztech.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-rtrack2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-sf16fmi.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-sf16fmr2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-cadet.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-typhoon.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-terratec.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-maxiradio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-aimslab.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-zoltrix.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-gemtek.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-trust.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/si4713-i2c.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-si4713.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-maestro.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-miropcm20.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dsbr100.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-usb-si470x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-mr800.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-tea5764.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tef6862.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-pll.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0299.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb0899.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb6100.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sp8870.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx22700.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1432.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24110.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda8083.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/l64781.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib3000mb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib3000mc.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dibx000_common.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib7000m.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib7000p.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib8000.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib9000.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt312.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ves1820.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ves1x93.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda1004x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sp887x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nxt6000.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt352.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zl10036.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zl10039.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zl10353.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx22702.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/drx397xD.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10021.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10023.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0297.o -/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/drx397xD.c:20:1: warning: "DEBUG" redefined -: warning: this is the location of the previous definition - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nxt200x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/or51211.o -/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/drx397xD.c:20:1: warning: "DEBUG" redefined -: warning: this is the location of the previous definition - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/or51132.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bcm3510.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1420.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgdt330x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgdt3305.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24123.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lnbp21.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/isl6405.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/isl6421.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10086.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda826x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda8261.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib0070.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib0090.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tua6100.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1409.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/itd1000.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au8522.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10048.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24113.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1411.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgs8gl5.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda665x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgs8gxx.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/atbm8830.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_dummy_fe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/af9013.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24116.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/si21xx.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0288.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb6000.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s921.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv6110.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0900.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv090x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv6110x.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/isl6423.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ec100.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ds3000.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mb86a16.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mb86a20s.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ix2505v.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0367.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttpci-eeprom.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-core.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-av.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-ci.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-patch.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-ttpci.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttusb_dec.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttusbdecfe.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-ttusb-budget.o -/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-ttusb-budget.c:137:1: warning: "DEBUG" redefined -: warning: this is the location of the previous definition - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/b2c2-flexcop.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/b2c2-flexcop-pci.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/b2c2-flexcop-usb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt878.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-bt8xx.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dst.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dst_ca.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-vp7045.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-vp702x.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-gp8psk.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dtt200u.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dibusb-common.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-a800.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dibusb-mb.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dibusb-mc.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-nova-t-usb2.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-umt-010.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-m920x.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-gl861.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-au6610.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-digitv.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-cxusb.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-ttusb2.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dib0700.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-opera.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-af9005.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-af9005-remote.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-anysee.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dw2102.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dtv5100.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-af9015.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-cinergyT2.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-ce6230.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-friio.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-ec168.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-az6027.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-lmedm04.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-technisat-usb2.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pluto2.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsmdtv.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsdvb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsusb.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smssdio.o - CC [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dm1105.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/earth-pt1.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_core.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hopper.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ngene.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firedtv.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/snd-bt87x.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/snd-tea575x-tuner.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda18271.o - Building modules, stage 2. - MODPOST 439 modules -WARNING: "snd_aci_get_aci" [/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-miropcm20.ko] undefined! -WARNING: "snd_aci_cmd" [/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-miropcm20.ko] undefined! - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7170.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7175.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7180.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7343.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/af9013.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/atbm8830.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au0828.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au8522.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/b2c2-flexcop-pci.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/b2c2-flexcop-usb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/b2c2-flexcop.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bcm3510.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt819.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt856.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt866.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt878.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/btcx-risc.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-av.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-ci.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-core.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-patch.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bw-qcam.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/c-qcam.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cafe_ccic.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cpia2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cs5345.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cs53l32a.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-alsa.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx22700.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx22702.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-alsa.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-dvb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx2341x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24110.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24113.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24116.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24123.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx25840.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-alsa.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-blackbird.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-dvb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-vp3054-i2c.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx8800.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx8802.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88xx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib0070.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib0090.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib3000mb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib3000mc.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib7000m.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib7000p.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib8000.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib9000.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dibx000_common.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dm1105.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/drx397xD.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ds3000.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dsbr100.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dst.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dst_ca.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-bt8xx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-core.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-pll.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-ttpci.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-ttusb-budget.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-a800.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-af9005-remote.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-af9005.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-af9015.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-anysee.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-au6610.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-az6027.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-ce6230.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-cinergyT2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-cxusb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dib0700.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dibusb-common.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dibusb-mb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dibusb-mc.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-digitv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dtt200u.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dtv5100.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dw2102.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-ec168.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-friio.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-gl861.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-gp8psk.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-lmedm04.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-m920x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-nova-t-usb2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-opera.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-technisat-usb2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-ttusb2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-umt-010.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-vp702x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-vp7045.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_dummy_fe.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/earth-pt1.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ec100.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-alsa.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-dvb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ene_ir.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/et61x251.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firedtv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_benq.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_conex.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_cpia1.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_etoms.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_finepix.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_gl860.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_jeilinj.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_konica.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_m5602.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_main.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_mars.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_mr97310a.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_ov519.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_ov534.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_ov534_9.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_pac207.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_pac7302.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_pac7311.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sn9c2028.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sn9c20x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sonixb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sonixj.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca1528.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca500.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca501.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca505.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca506.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca508.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca561.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sq905.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sq905c.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sq930x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_stk014.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_stv0680.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_stv06xx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sunplus.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_t613.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_tv8532.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_vc032x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_vicam.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_xirlink_cit.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_zc3xx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hdpvr.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hexium_gemini.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hexium_orion.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hopper.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/imon.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-jvc-decoder.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-kbd-i2c.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-nec-decoder.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-rc5-decoder.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-rc5-sz-decoder.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-rc6-decoder.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-sony-decoder.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/isl6405.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/isl6421.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/isl6423.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/itd1000.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtvfb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ix2505v.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ks0127.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/l64781.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgdt3305.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgdt330x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgs8gl5.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgs8gxx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lnbp21.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m52790.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_core.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/max2165.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mb86a16.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mb86a20s.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mc44s803.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mceusb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/meye.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/msp3400.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt2060.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt20xx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt2131.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt2266.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt312.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt352.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt9v011.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mxb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mxl5005s.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mxl5007t.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ngene.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/noon010pc30.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nuvoton-cir.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nxt200x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nxt6000.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/or51132.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/or51211.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ov7670.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pluto2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pms.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/poseidon.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/qt1010.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-aimslab.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-aztech.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-cadet.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-gemtek.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-maestro.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-maxiradio.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-miropcm20.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-mr800.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-rtrack2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-sf16fmi.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-sf16fmr2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-si4713.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-tea5764.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-terratec.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-trust.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-typhoon.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-usb-si470x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-zoltrix.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-adstech-dvb-t-pci.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-alink-dtu-m.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-anysee.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-apac-viewcomp.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-asus-pc39.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-ati-tv-wonder-hd-600.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-a16d.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-cardbus.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-dvbt.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-m135a.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-m733a-rm-k6.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-rm-ks.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avertv-303.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-azurewave-ad-tu700.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-behold-columbus.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-behold.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-budget-ci-old.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-cinergy-1400.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-cinergy.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-core.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dib0700-nec.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dib0700-rc5.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-digitalnow-tinytwin.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-digittrade.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dm1105-nec.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dntv-live-dvb-t.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dntv-live-dvbt-pro.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-em-terratec.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-encore-enltv-fm53.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-encore-enltv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-encore-enltv2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-evga-indtube.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-eztv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-flydvb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-flyvideo.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-fusionhdtv-mce.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-gadmei-rm008z.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-genius-tvgo-a11mce.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-gotview7135.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-hauppauge.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-imon-mce.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-imon-pad.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-iodata-bctv7e.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-kaiomy.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-kworld-315u.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-kworld-plus-tv-analog.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-leadtek-y04g0051.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-lirc.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-lme2510.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-loopback.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-manli.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-digivox-ii.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-digivox-iii.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-tvanywhere-plus.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-tvanywhere.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-nebula.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-nec-terratec-cinergy-xs.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-norwood.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-npgtech.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pctv-sedna.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pinnacle-color.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pinnacle-grey.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pinnacle-pctv-hd.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview-002t.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview-mk12.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview-new.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-powercolor-real-angel.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-proteus-2309.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-purpletv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pv951.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-rc6-mce.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-real-audio-220-32-keys.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-streamzap.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-tbs-nec.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-technisat-usb2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-terratec-cinergy-xs.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-terratec-slim-2.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-terratec-slim.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-tevii-nec.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-total-media-in-hand.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-trekstor.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-tt-1500.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-twinhan1027.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-videomate-m1f.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-videomate-s350.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-videomate-tv-pvr.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-winfast-usbii-deluxe.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-winfast.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s2255drv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1409.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1411.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1420.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1432.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s921.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa6588.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa6752hs.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7110.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7115.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7127.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-alsa.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-dvb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-empress.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146_vv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa717x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7185.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7191.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/si21xx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/si4713-i2c.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsdvb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsmdtv.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smssdio.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsusb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/snd-bt87x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/snd-tea575x-tuner.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sp8870.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sp887x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sr030pc30.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb0899.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb6000.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb6100.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stkwebcam.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/streamzap.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0288.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0297.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0299.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0367.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0900.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv090x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv6110.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv6110x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tcm825x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10021.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10023.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10048.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda1004x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10086.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda18218.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda18271.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda665x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda7432.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda8083.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda8261.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda826x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda827x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda8290.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda9840.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda9887.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea5761.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea5767.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea6415c.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea6420.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tef6862.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ths7303.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tlv320aic23b.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttpci-eeprom.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttusb_dec.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttusbdecfe.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tua6100.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-simple.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-types.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-xc2028.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tvaudio.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tveeprom.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tvp514x.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tvp5150.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/upd64031a.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/upd64083.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/usbvision.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvcvideo.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-common.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-int-device.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ves1820.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ves1x93.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-core.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-dma-contig.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-dma-sg.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-dvb.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-vmalloc.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-core.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-dma-contig.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-dma-sg.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-memops.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-vmalloc.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videocodec.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videodev.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vivi.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vp27smpx.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vpx3220.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/w9966.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/winbond-cir.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/wm8739.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/wm8775.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/xc5000.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zl10036.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zl10039.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zl10353.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36016.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36050.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36060.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36067.mod.o - CC /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr364xx.mod.o - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7170.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7175.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7180.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/adv7343.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/af9013.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/atbm8830.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au0828.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/au8522.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/b2c2-flexcop-pci.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/b2c2-flexcop-usb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/b2c2-flexcop.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bcm3510.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt819.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt856.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt866.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bt878.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/btcx-risc.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bttv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-av.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-ci.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-core.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget-patch.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/budget.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/bw-qcam.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/c-qcam.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cafe_ccic.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cpia2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cs5345.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cs53l32a.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18-alsa.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx18.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx22700.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx22702.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-alsa.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx-dvb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx231xx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx2341x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx23885.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24110.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24113.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24116.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx24123.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx25840.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-alsa.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-blackbird.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-dvb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88-vp3054-i2c.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx8800.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx8802.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/cx88xx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib0070.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib0090.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib3000mb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib3000mc.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib7000m.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib7000p.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib8000.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dib9000.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dibx000_common.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dm1105.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/drx397xD.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ds3000.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dsbr100.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dst.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dst_ca.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-bt8xx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-core.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-pll.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-ttpci.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-ttusb-budget.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-a800.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-af9005-remote.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-af9005.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-af9015.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-anysee.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-au6610.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-az6027.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-ce6230.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-cinergyT2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-cxusb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dib0700.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dibusb-common.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dibusb-mb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dibusb-mc.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-digitv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dtt200u.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dtv5100.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-dw2102.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-ec168.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-friio.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-gl861.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-gp8psk.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-lmedm04.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-m920x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-nova-t-usb2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-opera.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-technisat-usb2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-ttusb2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-umt-010.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-vp702x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb-vp7045.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb-usb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/dvb_dummy_fe.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/earth-pt1.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ec100.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-alsa.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx-dvb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/em28xx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ene_ir.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/et61x251.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/firedtv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_benq.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_conex.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_cpia1.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_etoms.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_finepix.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_gl860.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_jeilinj.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_konica.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_m5602.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_main.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_mars.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_mr97310a.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_ov519.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_ov534.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_ov534_9.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_pac207.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_pac7302.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_pac7311.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sn9c2028.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sn9c20x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sonixb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sonixj.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca1528.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca500.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca501.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca505.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca506.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca508.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_spca561.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sq905.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sq905c.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sq930x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_stk014.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_stv0680.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_stv06xx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_sunplus.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_t613.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_tv8532.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_vc032x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_vicam.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_xirlink_cit.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/gspca_zc3xx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hdpvr.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hexium_gemini.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hexium_orion.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/hopper.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/imon.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-jvc-decoder.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-kbd-i2c.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-nec-decoder.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-rc5-decoder.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-rc5-sz-decoder.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-rc6-decoder.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ir-sony-decoder.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/isl6405.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/isl6421.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/isl6423.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/itd1000.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ivtvfb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ix2505v.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ks0127.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/l64781.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgdt3305.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgdt330x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgs8gl5.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lgs8gxx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/lnbp21.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/m52790.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mantis_core.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/max2165.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mb86a16.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mb86a20s.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mc44s803.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mceusb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/meye.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/msp3400.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt2060.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt20xx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt2131.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt2266.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt312.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt352.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mt9v011.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mxb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mxl5005s.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/mxl5007t.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ngene.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/noon010pc30.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nuvoton-cir.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nxt200x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/nxt6000.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/or51132.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/or51211.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ov7670.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pluto2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pms.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/poseidon.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pvrusb2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/pwc.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/qt1010.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-aimslab.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-aztech.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-cadet.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-gemtek.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-maestro.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-maxiradio.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-miropcm20.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-mr800.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-rtrack2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-sf16fmi.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-sf16fmr2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-si4713.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-tea5764.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-terratec.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-trust.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-typhoon.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-usb-si470x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/radio-zoltrix.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-adstech-dvb-t-pci.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-alink-dtu-m.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-anysee.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-apac-viewcomp.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-asus-pc39.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-ati-tv-wonder-hd-600.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-a16d.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-cardbus.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-dvbt.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-m135a.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-m733a-rm-k6.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia-rm-ks.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avermedia.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-avertv-303.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-azurewave-ad-tu700.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-behold-columbus.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-behold.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-budget-ci-old.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-cinergy-1400.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-cinergy.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-core.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dib0700-nec.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dib0700-rc5.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-digitalnow-tinytwin.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-digittrade.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dm1105-nec.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dntv-live-dvb-t.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-dntv-live-dvbt-pro.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-em-terratec.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-encore-enltv-fm53.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-encore-enltv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-encore-enltv2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-evga-indtube.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-eztv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-flydvb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-flyvideo.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-fusionhdtv-mce.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-gadmei-rm008z.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-genius-tvgo-a11mce.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-gotview7135.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-hauppauge.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-imon-mce.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-imon-pad.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-iodata-bctv7e.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-kaiomy.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-kworld-315u.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-kworld-plus-tv-analog.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-leadtek-y04g0051.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-lirc.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-lme2510.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-loopback.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-manli.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-digivox-ii.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-digivox-iii.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-tvanywhere-plus.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-msi-tvanywhere.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-nebula.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-nec-terratec-cinergy-xs.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-norwood.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-npgtech.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pctv-sedna.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pinnacle-color.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pinnacle-grey.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pinnacle-pctv-hd.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview-002t.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview-mk12.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview-new.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pixelview.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-powercolor-real-angel.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-proteus-2309.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-purpletv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-pv951.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-rc6-mce.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-real-audio-220-32-keys.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-streamzap.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-tbs-nec.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-technisat-usb2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-terratec-cinergy-xs.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-terratec-slim-2.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-terratec-slim.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-tevii-nec.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-total-media-in-hand.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-trekstor.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-tt-1500.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-twinhan1027.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-videomate-m1f.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-videomate-s350.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-videomate-tv-pvr.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-winfast-usbii-deluxe.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/rc-winfast.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s2255drv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1409.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1411.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1420.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s5h1432.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/s921.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa6588.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa6752hs.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7110.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7115.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7127.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-alsa.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-dvb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134-empress.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7134.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7146_vv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7164.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa717x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7185.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/saa7191.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/si21xx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/si4713-i2c.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsdvb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsmdtv.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smssdio.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/smsusb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sn9c102.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/snd-bt87x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/snd-tea575x-tuner.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sp8870.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sp887x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/sr030pc30.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb0899.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb6000.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stb6100.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stkwebcam.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/streamzap.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0288.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0297.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0299.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0367.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv0900.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv090x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv6110.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/stv6110x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tcm825x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10021.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10023.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10048.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda1004x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda10086.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda18218.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda18271.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda665x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda7432.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda8083.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda8261.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda826x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda827x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda8290.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda9840.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tda9887.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea5761.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea5767.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea6415c.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tea6420.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tef6862.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ths7303.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tlv320aic23b.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttpci-eeprom.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttusb_dec.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ttusbdecfe.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tua6100.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-simple.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-types.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner-xc2028.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tuner.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tvaudio.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tveeprom.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tvp514x.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/tvp5150.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/upd64031a.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/upd64083.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/usbvision.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/uvcvideo.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-common.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/v4l2-int-device.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ves1820.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/ves1x93.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-core.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-dma-contig.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-dma-sg.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-dvb.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf-vmalloc.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-core.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-dma-contig.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-dma-sg.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-memops.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videobuf2-vmalloc.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videocodec.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/videodev.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vivi.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vp27smpx.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/vpx3220.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/w9966.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/winbond-cir.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/wm8739.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/wm8775.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/xc5000.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zl10036.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zl10039.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zl10353.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36016.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36050.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36060.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr36067.ko - LD [M] /root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l/zr364xx.ko -make[2]: Leaving directory `/usr/src/linux-headers-2.6.32-30-generic' -./scripts/rmmod.pl check -found 439 modules -make[1]: Leaving directory `/root/make-dkms/tmp.GvrlUjQXaH/v4l-dvb/0~20110324.git235676.160/build/v4l' Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/adv7170.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/adv7170.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/adv7175.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/adv7175.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/adv7180.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/adv7180.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/adv7343.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/adv7343.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/af9013.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/af9013.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/atbm8830.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/atbm8830.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/au0828.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/au0828.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/au8522.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/au8522.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/b2c2-flexcop.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/b2c2-flexcop.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/b2c2-flexcop-pci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/b2c2-flexcop-pci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/b2c2-flexcop-usb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/b2c2-flexcop-usb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/bcm3510.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/bcm3510.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/bt819.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/bt819.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/bt856.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/bt856.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/bt866.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/bt866.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/bt878.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/bt878.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/btcx-risc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/btcx-risc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/bttv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/bttv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/budget-av.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/budget-av.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/budget-ci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/budget-ci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/budget-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/budget-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/budget.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/budget.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/budget-patch.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/budget-patch.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/bw-qcam.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/bw-qcam.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cafe_ccic.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cafe_ccic.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cpia2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cpia2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/c-qcam.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/c-qcam.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cs5345.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cs5345.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cs53l32a.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cs53l32a.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx18-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx18-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx18.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx18.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx22700.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx22700.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx22702.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx22702.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx231xx-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx231xx-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx231xx-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx231xx-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx231xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx231xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx2341x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx2341x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx23885.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx23885.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx24110.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx24110.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx24113.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx24113.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx24116.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx24116.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx24123.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx24123.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx25840.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx25840.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx8800.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx8800.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx8802.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx8802.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx88-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx88-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx88-blackbird.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx88-blackbird.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx88-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx88-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx88-vp3054-i2c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx88-vp3054-i2c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/cx88xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/cx88xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dib0070.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dib0070.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dib0090.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dib0090.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dib3000mb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dib3000mb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dib3000mc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dib3000mc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dib7000m.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dib7000m.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dib7000p.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dib7000p.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dib8000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dib8000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dib9000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dib9000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dibx000_common.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dibx000_common.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dm1105.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dm1105.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/drx397xD.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/drx397xD.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ds3000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ds3000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dsbr100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dsbr100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dst_ca.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dst_ca.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dst.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dst.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-bt8xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-bt8xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb_dummy_fe.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb_dummy_fe.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-pll.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-pll.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-ttpci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-ttpci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-ttusb-budget.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-ttusb-budget.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-a800.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-a800.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-af9005.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-af9005.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-af9005-remote.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-af9005-remote.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-af9015.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-af9015.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-anysee.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-anysee.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-au6610.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-au6610.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-az6027.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-az6027.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-ce6230.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-ce6230.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-cinergyT2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-cinergyT2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-cxusb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-cxusb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dib0700.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dib0700.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dibusb-common.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dibusb-common.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dibusb-mb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dibusb-mb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dibusb-mc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dibusb-mc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-digitv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-digitv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dtt200u.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dtt200u.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dtv5100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dtv5100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dw2102.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-dw2102.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-ec168.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-ec168.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-friio.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-friio.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-gl861.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-gl861.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-gp8psk.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-gp8psk.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-lmedm04.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-lmedm04.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-m920x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-m920x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-nova-t-usb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-nova-t-usb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-opera.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-opera.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-technisat-usb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-technisat-usb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-ttusb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-ttusb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-umt-010.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-umt-010.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-vp702x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-vp702x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-vp7045.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/dvb-usb-vp7045.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/earth-pt1.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/earth-pt1.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ec100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ec100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/em28xx-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/em28xx-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/em28xx-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/em28xx-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/em28xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/em28xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ene_ir.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ene_ir.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/et61x251.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/et61x251.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/firedtv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/firedtv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_benq.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_benq.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_conex.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_conex.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_cpia1.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_cpia1.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_etoms.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_etoms.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_finepix.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_finepix.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_gl860.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_gl860.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_jeilinj.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_jeilinj.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_konica.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_konica.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_m5602.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_m5602.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_main.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_main.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_mars.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_mars.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_mr97310a.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_mr97310a.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_ov519.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_ov519.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_ov534_9.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_ov534_9.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_ov534.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_ov534.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_pac207.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_pac207.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_pac7302.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_pac7302.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_pac7311.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_pac7311.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sn9c2028.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sn9c2028.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sn9c20x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sn9c20x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sonixb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sonixb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sonixj.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sonixj.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca1528.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca1528.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca500.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca500.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca501.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca501.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca505.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca505.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca506.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca506.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca508.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca508.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca561.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_spca561.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sq905c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sq905c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sq905.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sq905.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sq930x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sq930x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_stk014.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_stk014.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_stv0680.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_stv0680.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_stv06xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_stv06xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sunplus.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_sunplus.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_t613.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_t613.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_tv8532.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_tv8532.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_vc032x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_vc032x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_vicam.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_vicam.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_xirlink_cit.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_xirlink_cit.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_zc3xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/gspca_zc3xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/hdpvr.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/hdpvr.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/hexium_gemini.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/hexium_gemini.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/hexium_orion.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/hexium_orion.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/hopper.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/hopper.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/imon.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/imon.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ir-jvc-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ir-jvc-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ir-kbd-i2c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ir-kbd-i2c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ir-nec-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ir-nec-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ir-rc5-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ir-rc5-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ir-rc5-sz-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ir-rc5-sz-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ir-rc6-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ir-rc6-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ir-sony-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ir-sony-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/isl6405.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/isl6405.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/isl6421.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/isl6421.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/isl6423.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/isl6423.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/itd1000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/itd1000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ivtvfb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ivtvfb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ivtv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ivtv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ix2505v.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ix2505v.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ks0127.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ks0127.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/l64781.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/l64781.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/lgdt3305.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/lgdt3305.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/lgdt330x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/lgdt330x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/lgs8gl5.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/lgs8gl5.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/lgs8gxx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/lgs8gxx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/lnbp21.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/lnbp21.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/m52790.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/m52790.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mantis_core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mantis_core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mantis.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mantis.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/max2165.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/max2165.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mb86a16.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mb86a16.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mb86a20s.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mb86a20s.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mc44s803.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mc44s803.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mceusb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mceusb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/meye.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/meye.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/msp3400.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/msp3400.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mt2060.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mt2060.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mt20xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mt20xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mt2131.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mt2131.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mt2266.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mt2266.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mt312.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mt312.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mt352.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mt352.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mt9v011.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mt9v011.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mxb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mxb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mxl5005s.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mxl5005s.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/mxl5007t.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/mxl5007t.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ngene.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ngene.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/noon010pc30.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/noon010pc30.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/nuvoton-cir.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/nuvoton-cir.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/nxt200x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/nxt200x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/nxt6000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/nxt6000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/or51132.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/or51132.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/or51211.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/or51211.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ov7670.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ov7670.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/pluto2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/pluto2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/pms.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/pms.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/poseidon.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/poseidon.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/pvrusb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/pvrusb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/pwc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/pwc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/qt1010.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/qt1010.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-aimslab.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-aimslab.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-aztech.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-aztech.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-cadet.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-cadet.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-gemtek.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-gemtek.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-maestro.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-maestro.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-maxiradio.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-maxiradio.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-miropcm20.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-miropcm20.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-mr800.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-mr800.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-rtrack2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-rtrack2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-sf16fmi.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-sf16fmi.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-sf16fmr2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-sf16fmr2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-si4713.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-si4713.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-tea5764.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-tea5764.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-terratec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-terratec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-trust.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-trust.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-typhoon.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-typhoon.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-usb-si470x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-usb-si470x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/radio-zoltrix.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/radio-zoltrix.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-adstech-dvb-t-pci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-adstech-dvb-t-pci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-alink-dtu-m.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-alink-dtu-m.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-anysee.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-anysee.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-apac-viewcomp.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-apac-viewcomp.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-asus-pc39.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-asus-pc39.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-ati-tv-wonder-hd-600.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-ati-tv-wonder-hd-600.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-a16d.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-a16d.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-cardbus.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-cardbus.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-dvbt.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-dvbt.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-m135a.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-m135a.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-m733a-rm-k6.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-m733a-rm-k6.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-rm-ks.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avermedia-rm-ks.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avertv-303.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-avertv-303.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-azurewave-ad-tu700.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-azurewave-ad-tu700.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-behold-columbus.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-behold-columbus.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-behold.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-behold.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-budget-ci-old.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-budget-ci-old.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-cinergy-1400.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-cinergy-1400.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-cinergy.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-cinergy.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dib0700-nec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dib0700-nec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dib0700-rc5.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dib0700-rc5.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-digitalnow-tinytwin.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-digitalnow-tinytwin.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-digittrade.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-digittrade.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dm1105-nec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dm1105-nec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dntv-live-dvb-t.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dntv-live-dvb-t.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dntv-live-dvbt-pro.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-dntv-live-dvbt-pro.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-em-terratec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-em-terratec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-encore-enltv2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-encore-enltv2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-encore-enltv-fm53.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-encore-enltv-fm53.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-encore-enltv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-encore-enltv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-evga-indtube.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-evga-indtube.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-eztv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-eztv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-flydvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-flydvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-flyvideo.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-flyvideo.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-fusionhdtv-mce.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-fusionhdtv-mce.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-gadmei-rm008z.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-gadmei-rm008z.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-genius-tvgo-a11mce.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-genius-tvgo-a11mce.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-gotview7135.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-gotview7135.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-hauppauge.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-hauppauge.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-imon-mce.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-imon-mce.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-imon-pad.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-imon-pad.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-iodata-bctv7e.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-iodata-bctv7e.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-kaiomy.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-kaiomy.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-kworld-315u.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-kworld-315u.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-kworld-plus-tv-analog.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-kworld-plus-tv-analog.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-leadtek-y04g0051.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-leadtek-y04g0051.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-lirc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-lirc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-lme2510.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-lme2510.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-loopback.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-loopback.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-manli.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-manli.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-msi-digivox-iii.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-msi-digivox-iii.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-msi-digivox-ii.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-msi-digivox-ii.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-msi-tvanywhere.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-msi-tvanywhere.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-msi-tvanywhere-plus.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-msi-tvanywhere-plus.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-nebula.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-nebula.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-nec-terratec-cinergy-xs.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-nec-terratec-cinergy-xs.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-norwood.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-norwood.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-npgtech.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-npgtech.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pctv-sedna.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pctv-sedna.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pinnacle-color.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pinnacle-color.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pinnacle-grey.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pinnacle-grey.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pinnacle-pctv-hd.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pinnacle-pctv-hd.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pixelview-002t.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pixelview-002t.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pixelview.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pixelview.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pixelview-mk12.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pixelview-mk12.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pixelview-new.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pixelview-new.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-powercolor-real-angel.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-powercolor-real-angel.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-proteus-2309.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-proteus-2309.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-purpletv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-purpletv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pv951.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-pv951.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-rc6-mce.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-rc6-mce.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-real-audio-220-32-keys.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-real-audio-220-32-keys.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-streamzap.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-streamzap.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-tbs-nec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-tbs-nec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-technisat-usb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-technisat-usb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-terratec-cinergy-xs.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-terratec-cinergy-xs.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-terratec-slim-2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-terratec-slim-2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-terratec-slim.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-terratec-slim.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-tevii-nec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-tevii-nec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-total-media-in-hand.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-total-media-in-hand.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-trekstor.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-trekstor.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-tt-1500.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-tt-1500.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-twinhan1027.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-twinhan1027.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-videomate-m1f.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-videomate-m1f.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-videomate-s350.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-videomate-s350.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-videomate-tv-pvr.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-videomate-tv-pvr.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-winfast.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-winfast.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/rc-winfast-usbii-deluxe.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/rc-winfast-usbii-deluxe.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/s2255drv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/s2255drv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/s5h1409.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/s5h1409.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/s5h1411.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/s5h1411.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/s5h1420.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/s5h1420.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/s5h1432.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/s5h1432.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/s921.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/s921.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa6588.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa6588.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa6752hs.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa6752hs.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7110.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7110.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7115.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7115.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7127.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7127.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7134-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7134-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7134-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7134-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7134-empress.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7134-empress.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7134.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7134.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7146.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7146.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7146_vv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7146_vv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7164.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7164.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa717x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa717x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7185.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7185.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/saa7191.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/saa7191.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/si21xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/si21xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/si4713-i2c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/si4713-i2c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/smsdvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/smsdvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/smsmdtv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/smsmdtv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/smssdio.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/smssdio.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/smsusb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/smsusb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/sn9c102.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/sn9c102.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/snd-bt87x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/snd-bt87x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/snd-tea575x-tuner.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/snd-tea575x-tuner.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/sp8870.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/sp8870.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/sp887x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/sp887x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/sr030pc30.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/sr030pc30.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stb0899.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stb0899.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stb6000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stb6000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stb6100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stb6100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stkwebcam.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stkwebcam.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/streamzap.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/streamzap.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stv0288.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stv0288.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stv0297.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stv0297.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stv0299.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stv0299.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stv0367.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stv0367.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stv0900.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stv0900.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stv090x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stv090x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stv6110.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stv6110.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/stv6110x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/stv6110x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tcm825x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tcm825x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda10021.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda10021.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda10023.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda10023.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda10048.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda10048.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda1004x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda1004x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda10086.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda10086.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda18218.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda18218.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda18271.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda18271.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda665x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda665x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda7432.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda7432.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda8083.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda8083.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda8261.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda8261.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda826x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda826x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda827x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda827x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda8290.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda8290.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda9840.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda9840.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tda9887.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tda9887.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tea5761.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tea5761.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tea5767.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tea5767.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tea6415c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tea6415c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tea6420.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tea6420.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tef6862.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tef6862.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ths7303.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ths7303.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tlv320aic23b.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tlv320aic23b.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ttpci-eeprom.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ttpci-eeprom.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ttusbdecfe.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ttusbdecfe.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ttusb_dec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ttusb_dec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tua6100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tua6100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tuner.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tuner.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tuner-simple.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tuner-simple.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tuner-types.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tuner-types.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tuner-xc2028.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tuner-xc2028.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tvaudio.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tvaudio.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tveeprom.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tveeprom.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tvp514x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tvp514x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/tvp5150.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/tvp5150.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/upd64031a.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/upd64031a.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/upd64083.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/upd64083.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/usbvision.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/usbvision.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/uvcvideo.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/uvcvideo.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/v4l2-common.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/v4l2-common.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/v4l2-int-device.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/v4l2-int-device.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ves1820.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ves1820.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/ves1x93.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/ves1x93.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-dma-contig.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-dma-contig.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-dma-sg.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-dma-sg.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-memops.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-memops.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-vmalloc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf2-vmalloc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-dma-contig.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-dma-contig.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-dma-sg.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-dma-sg.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-vmalloc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videobuf-vmalloc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videocodec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videocodec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/videodev.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/videodev.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/vivi.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/vivi.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/vp27smpx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/vp27smpx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/vpx3220.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/vpx3220.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/w9966.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/w9966.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/winbond-cir.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/winbond-cir.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/wm8739.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/wm8739.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/wm8775.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/wm8775.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/xc5000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/xc5000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/zl10036.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/zl10036.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/zl10039.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/zl10039.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/zl10353.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/zl10353.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/zr36016.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/zr36016.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/zr36050.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/zr36050.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/zr36060.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/zr36060.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/zr36067.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/zr36067.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-30-generic/i686/module/zr364xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-30-generic/i686/module/zr364xx.ko differ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/log/make.log v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/log/make.log --- v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/log/make.log 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/log/make.log 2011-06-25 16:18:19.000000000 +0000 @@ -0,0 +1,1802 @@ +DKMS make.log for v4l-dvb-0~20110625.git255868.188~lucid for kernel 2.6.32-32-generic (i686) +Sat Jun 25 18:16:11 CEST 2011 +make -C /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l +make[1]: Entering directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l' +scripts/make_makefile.pl +Forcing kernel version to 2.6.32-32-generic. +Updating/Creating .config +make[2]: Entering directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/linux' +Applying patches for kernel v2.6.32-32-generic +cat: ../backports/v2.6.32-32-generic_series: No such file or directory +Patched drivers/media/dvb/dvb-core/dvbdev.c +Patched drivers/media/video/v4l2-dev.c +Patched drivers/media/rc/rc-main.c +make[2]: Leaving directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/linux' +./scripts/make_kconfig.pl /lib/modules/2.6.32-32-generic/build /lib/modules/2.6.32-32-generic/build +Preparing to compile for kernel version 2.6.32 + +***WARNING:*** You do not have the full kernel sources installed. +This does not prevent you from building the v4l-dvb tree if you have the +kernel headers, but the full kernel source may be required in order to use +make menuconfig / xconfig / qconfig. + +If you are experiencing problems building the v4l-dvb tree, please try +building against a vanilla kernel before reporting a bug. + +Vanilla kernels are available at http://kernel.org. +On most distros, this will compile a newly downloaded kernel: + +cp /boot/config-`uname -r` /.config +cd +make all modules_install install + +Please see your distro's web site for instructions to build a new kernel. + +WARNING: This is the V4L/DVB backport tree, with experimental drivers + backported to run on legacy kernels from the development tree at: + http://git.linuxtv.org/media-tree.git. + It is generally safe to use it for testing a new driver or + feature, but its usage on production environments is risky. + Don't use it in production. You've been warned. +V4L2_MEM2MEM_DEV: Requires at least kernel 2.6.33 +VIDEO_TVP7002: Requires at least kernel 2.6.34 +VIDEO_AK881X: Requires at least kernel 2.6.33 +VIDEO_TIMBERDALE: Requires at least kernel 2.6.39 +VIDEO_VIA_CAMERA: Requires at least kernel 2.6.37 +SOC_CAMERA: Requires at least kernel 2.6.33 +SOC_CAMERA_MT9M001: Requires at least kernel 2.6.33 +SOC_CAMERA_MT9M111: Requires at least kernel 2.6.33 +SOC_CAMERA_MT9T031: Requires at least kernel 2.6.33 +SOC_CAMERA_MT9V022: Requires at least kernel 2.6.33 +SOC_CAMERA_TW9910: Requires at least kernel 2.6.33 +SOC_CAMERA_PLATFORM: Requires at least kernel 2.6.33 +SOC_CAMERA_OV772X: Requires at least kernel 2.6.33 +RADIO_SAA7706H: Requires at least kernel 2.6.34 +RADIO_TIMBERDALE: Requires at least kernel 2.6.39 +RADIO_WL1273: Requires at least kernel 2.6.39 +DVB_FIREDTV: Requires at least kernel 3.0.0 +./scripts/make_myconfig.pl +make[1]: Leaving directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l' +make[1]: Entering directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l' +perl scripts/make_config_compat.pl /lib/modules/2.6.32-32-generic/build ./.myconfig ./config-compat.h +make -C firmware prep +creating symbolic links... +make[2]: Entering directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/firmware' +make[2]: Leaving directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/firmware' +make -C firmware +make[2]: Entering directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/firmware' + CC ihex2fw +Generating vicam/firmware.fw +Generating dabusb/firmware.fw +Generating dabusb/bitstream.bin +Generating ttusb-budget/dspbootcode.bin +Generating cpia2/stv0672_vp4.bin +Generating av7110/bootcode.bin +make[2]: Leaving directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/firmware' +Kernel build directory is /lib/modules/2.6.32-32-generic/build +make -C ../linux apply_patches +make[2]: Entering directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/linux' +Patches for v2.6.32-32-generic already applied. +make[2]: Leaving directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/linux' +make -C /lib/modules/2.6.32-32-generic/build SUBDIRS=/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l modules +make[2]: Entering directory `/usr/src/linux-headers-2.6.32-32-generic' + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-xc2028.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-simple.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-types.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt20xx.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda8290.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea5767.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea5761.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda9887.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda827x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au0828-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au0828-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au0828-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au0828-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au0828-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au0828-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au8522_dig.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au8522_decoder.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop-pci.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop-usb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop-fe-tuner.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop-eeprom.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop-sram.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop-misc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop-hw-filter.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/flexcop-dma.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv-driver.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv-if.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv-risc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv-gpio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv-input.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv-audio-hook.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cafe-driver.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mcam-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cpia2_v4l.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cpia2_usb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cpia2_core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-alsa-main.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-alsa-pcm.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-driver.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-firmware.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-gpio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-queue.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-streams.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-fileops.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-ioctl.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-controls.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-mailbox.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-audio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-irq.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-av-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-av-audio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-av-firmware.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-av-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-scb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-io.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-audio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-avcore.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-417.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-pcb-cfg.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-input.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-417.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-ioctl.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-ir.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-av.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-input.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23888-ir.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/netup-init.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cimax2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/netup-eeprom.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885-f300.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx25840-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx25840-audio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx25840-firmware.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx25840-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx25840-ir.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-mpeg.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-tvaudio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-dsp.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-input.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cxd2820r_core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cxd2820r_c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cxd2820r_t.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cxd2820r_t2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/drxd_firm.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/drxd_hard.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvbdev.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dmxdev.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb_demux.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb_filter.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb_ca_en50221.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb_frontend.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb_ringbuffer.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb_math.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/av7110_hw.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/av7110_v4l.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/av7110_av.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/av7110_ca.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/av7110.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/av7110_ipack.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/av7110_ir.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/a800.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/af9005-remote.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/af9005.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/af9005-fe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/af9015.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/anysee.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au6610.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/az6027.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ce6230.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cinergyT2-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cinergyT2-fe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cxusb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib0700_core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib0700_devices.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dibusb-common.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dibusb-mb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dibusb-mc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/digitv.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dtt200u.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dtt200u-fe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dtv5100.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dw2102.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ec168.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/friio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/friio-fe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gl861.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gp8psk.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gp8psk-fe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lmedm04.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m920x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nova-t-usb2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/opera1.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/technisat-usb2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttusb2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/umt-010.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vp702x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vp702x-fe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vp7045.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vp7045-fe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-firmware.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-init.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-urb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-remote.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/usb-urb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pt1.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/va1j5jf8007s.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/va1j5jf8007t.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-audio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/et61x251_core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/et61x251_tas5130d1b.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/benq.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/conex.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cpia1.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/etoms.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/finepix.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gl860.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gl860-mi1320.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gl860-ov2640.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gl860-ov9655.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gl860-mi2020.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/jeilinj.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/kinect.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/konica.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m5602_core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m5602_ov9650.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m5602_ov7660.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m5602_mt9m111.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m5602_po1030.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m5602_s5k83a.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m5602_s5k4aa.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mars.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mr97310a.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nw80x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ov519.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ov534.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ov534_9.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pac207.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pac7302.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pac7311.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c2028.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c20x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sonixb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sonixj.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/spca1528.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/spca500.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/spca501.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/spca505.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/spca506.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/spca508.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/spca561.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sq905.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sq905c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sq930x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stk014.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0680.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv06xx.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv06xx_vv6410.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv06xx_hdcs.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv06xx_pb0100.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv06xx_st6422.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sunplus.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/t613.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tv8532.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vc032x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vicam.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/xirlink_cit.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zc3xx.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hdpvr-control.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hdpvr-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hdpvr-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hdpvr-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hopper_cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hopper_vp3028.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-routing.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-controls.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-driver.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-fileops.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-firmware.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-gpio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-ioctl.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-irq.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-mailbox.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-queue.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-streams.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-udma.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv-yuv.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_vp1033.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_vp1034.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_vp1041.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_vp2033.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_vp2040.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_vp3030.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_ioc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_uart.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_dma.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_pci.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_evm.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_hif.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_ca.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_pcmcia.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_input.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/msp3400-driver.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/msp3400-kthreads.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ngene-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ngene-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ngene-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ngene-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pd-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pd-alsa.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pd-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pd-radio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pd-main.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-i2c-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-audio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-encoder.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-video-v4l.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-eeprom.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-main.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-hdw.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-v4l2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-ctrl.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-std.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-devattr.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-context.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-io.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-ioread.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-cx2584x-v4l.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-wm8775.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-cs53l32a.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-sysfs.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2-debugifc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc-if.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc-misc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc-ctrl.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc-v4l.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc-uncompress.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc-dec1.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc-dec23.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc-kiara.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc-timon.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-si470x-usb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-si470x-common.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-main.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-raw.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-ts.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-tvaudio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-input.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146_i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146_core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146_fops.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146_video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146_hlp.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146_vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-fw.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-bus.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-cmd.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-api.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-buffer.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-encoder.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164-vbi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_pci.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_i2c.o +/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_pci.c:20: warning: 'saa716x_msi_handler' defined but not used + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_cgu.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_msi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_dma.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_vip.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_aip.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_phi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_boot.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_fgpi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_adap.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_gpio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_greg.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_rom.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_spi.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_ff_main.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_ff_ir.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smscoreapi.o +/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_rom.c: In function 'saa716x_eeprom_data': +/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_rom.c:1017: warning: the frame size of 1096 bytes is larger than 1024 bytes + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sms-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsendian.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsir.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_hv7131d.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_hv7131r.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_mi0343.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_mi0360.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_mt9v111.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_ov7630.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_ov7660.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_pas106b.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_pas202bcb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_tas5110c1b.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_tas5110d.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102_tas5130d1b.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt87x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb0899_drv.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb0899_algo.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stk-webcam.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stk-sensor.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0900_core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0900_sw.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18271-maps.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18271-common.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18271-fe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/usbvision-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/usbvision-video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/usbvision-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/usbvision-cards.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvc_driver.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvc_queue.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvc_v4l2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvc_video.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvc_ctrl.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvc_status.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvc_isight.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-dev.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-ioctl.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-device.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-fh.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-event.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-ctrls.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-subdev.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zoran_procfs.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zoran_device.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zoran_driver.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zoran_card.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/xc5000.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt2060.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt2266.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/qt1010.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt2131.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mxl5005s.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mxl5007t.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mc44s803.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/max2165.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18218.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18212.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146_vv.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_budget.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_hybrid.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_ff.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-adstech-dvb-t-pci.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-alink-dtu-m.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-anysee.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-apac-viewcomp.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-asus-pc39.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-ati-tv-wonder-hd-600.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-a16d.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-cardbus.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-dvbt.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-m135a.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-m733a-rm-k6.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-rm-ks.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avertv-303.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-azurewave-ad-tu700.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-behold.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-behold-columbus.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-budget-ci-old.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-cinergy-1400.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-cinergy.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dib0700-nec.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dib0700-rc5.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-digitalnow-tinytwin.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-digittrade.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dm1105-nec.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dntv-live-dvb-t.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dntv-live-dvbt-pro.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-em-terratec.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-encore-enltv2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-encore-enltv.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-encore-enltv-fm53.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-evga-indtube.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-eztv.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-flydvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-flyvideo.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-fusionhdtv-mce.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-gadmei-rm008z.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-genius-tvgo-a11mce.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-gotview7135.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-imon-mce.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-imon-pad.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-iodata-bctv7e.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-kaiomy.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-kworld-315u.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-kworld-plus-tv-analog.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-leadtek-y04g0051.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-lirc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-lme2510.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-manli.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-digivox-ii.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-digivox-iii.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-tvanywhere.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-tvanywhere-plus.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-nebula.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-nec-terratec-cinergy-xs.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-norwood.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-npgtech.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pctv-sedna.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pinnacle-color.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pinnacle-grey.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pinnacle-pctv-hd.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview-mk12.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview-002t.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview-new.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-powercolor-real-angel.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-proteus-2309.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-purpletv.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pv951.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-hauppauge.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-rc6-mce.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-real-audio-220-32-keys.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-streamzap.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tbs-nec.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-technisat-usb2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-cinergy-c-pci.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-cinergy-s2-hd.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-cinergy-xs.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-slim.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-slim-2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tevii-nec.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tivo.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-total-media-in-hand.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-trekstor.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tt-1500.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-twinhan-dtv-cab-ci.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-twinhan1027.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-videomate-m1f.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-videomate-s350.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-videomate-tv-pvr.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-winfast.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-winfast-usbii-deluxe.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lirc_dev.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-nec-decoder.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-rc5-decoder.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-rc6-decoder.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-jvc-decoder.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-sony-decoder.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-rc5-sz-decoder.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-lirc-codec.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/imon.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mceusb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nuvoton-cir.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ene_ir.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/streamzap.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/winbond-cir.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-loopback.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videodev.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-int-device.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-common.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tvaudio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda7432.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa6588.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda9840.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea6415c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea6420.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7110.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7115.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa717x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7127.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7185.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7191.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7170.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7175.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7180.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7343.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vpx3220.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt819.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt856.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt866.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ks0127.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ths7303.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tvp5150.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tvp514x.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/msp3400.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cs5345.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cs53l32a.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m52790.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tlv320aic23b.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/wm8775.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/wm8739.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vp27smpx.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx25840.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/upd64031a.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/upd64083.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ov7670.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tcm825x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tveeprom.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt9v011.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sr030pc30.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/noon010pc30.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36067.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videocodec.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36050.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36016.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36060.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/c-qcam.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bw-qcam.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/w9966.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/meye.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa6752hs.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-empress.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-alsa.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-dvb.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88xx.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx8800.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx8802.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-alsa.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-blackbird.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-vp3054-i2c.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-alsa.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-dvb.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/poseidon.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-alsa.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-dvb.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/usbvision.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cpia2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mxb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hexium_orion.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hexium_gemini.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-dma-sg.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-vmalloc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-dvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/btcx-risc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf2-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf2-memops.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf2-vmalloc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx2341x.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cafe_ccic.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr364xx.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stkwebcam.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/et61x251.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_main.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_benq.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_conex.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_cpia1.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_etoms.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_finepix.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_jeilinj.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_kinect.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_konica.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_mars.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_mr97310a.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_nw80x.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_ov519.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_ov534.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_ov534_9.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_pac207.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_pac7302.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_pac7311.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sn9c2028.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sn9c20x.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sonixb.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sonixj.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca500.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca501.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca505.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca506.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca508.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca561.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca1528.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sq905.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sq905c.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sq930x.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sunplus.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_stk014.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_stv0680.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_t613.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_tv8532.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_vc032x.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_vicam.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_xirlink_cit.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_zc3xx.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_m5602.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_stv06xx.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_gl860.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hdpvr.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s2255drv.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtvfb.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-alsa.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vivi.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au0828.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvcvideo.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-kbd-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-maxiradio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/si4713-i2c.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-si4713.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dsbr100.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-usb-si470x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-mr800.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-tea5764.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tef6862.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-pll.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0299.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb0899.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb6100.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sp8870.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx22700.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1432.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24110.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda8083.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/l64781.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib3000mb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib3000mc.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dibx000_common.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib7000m.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib7000p.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib8000.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib9000.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt312.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ves1820.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ves1x93.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda1004x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sp887x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nxt6000.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt352.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zl10036.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zl10039.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zl10353.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx22702.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/drxd.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10021.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10023.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0297.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nxt200x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/or51211.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/or51132.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bcm3510.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1420.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgdt330x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgdt3305.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24123.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lnbp21.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/isl6405.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/isl6421.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10086.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda826x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda8261.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib0070.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib0090.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tua6100.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1409.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/itd1000.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au8522.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10048.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24113.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1411.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgs8gl5.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda665x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgs8gxx.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/atbm8830.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb_dummy_fe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/af9013.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24116.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/si21xx.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0288.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb6000.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s921.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv6110.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0900.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv090x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv6110x.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/isl6423.o +/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv090x.c:3548: warning: 'stv090x_read_per' defined but not used + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ec100.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ds3000.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mb86a16.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mb86a20s.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ix2505v.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0367.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cxd2820r.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttpci-eeprom.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-core.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-av.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-ci.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-patch.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-ttpci.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttusb_dec.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttusbdecfe.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-ttusb-budget.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/b2c2-flexcop.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/b2c2-flexcop-pci.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/b2c2-flexcop-usb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt878.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-bt8xx.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dst.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dst_ca.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-vp7045.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-vp702x.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-gp8psk.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dtt200u.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dibusb-common.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-a800.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dibusb-mb.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dibusb-mc.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-nova-t-usb2.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-umt-010.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-m920x.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-gl861.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-au6610.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-digitv.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-cxusb.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-ttusb2.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dib0700.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-opera.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-af9005.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-af9005-remote.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-anysee.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dw2102.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dtv5100.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-af9015.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-cinergyT2.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-ce6230.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-friio.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-ec168.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-az6027.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-lmedm04.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-technisat-usb2.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pluto2.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsmdtv.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsdvb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsusb.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smssdio.o + CC [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dm1105.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/earth-pt1.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_core.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hopper.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ngene.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/snd-bt87x.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18271.o + Building modules, stage 2. + MODPOST 434 modules + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7170.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7175.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7180.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7343.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/af9013.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/atbm8830.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au0828.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au8522.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/b2c2-flexcop-pci.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/b2c2-flexcop-usb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/b2c2-flexcop.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bcm3510.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt819.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt856.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt866.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt878.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/btcx-risc.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-av.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-ci.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-core.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-patch.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bw-qcam.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/c-qcam.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cafe_ccic.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cpia2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cs5345.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cs53l32a.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-alsa.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx22700.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx22702.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-alsa.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-dvb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx2341x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24110.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24113.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24116.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24123.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx25840.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-alsa.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-blackbird.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-dvb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-vp3054-i2c.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx8800.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx8802.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88xx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cxd2820r.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib0070.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib0090.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib3000mb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib3000mc.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib7000m.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib7000p.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib8000.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib9000.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dibx000_common.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dm1105.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/drxd.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ds3000.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dsbr100.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dst.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dst_ca.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-bt8xx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-core.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-pll.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-ttpci.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-ttusb-budget.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-a800.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-af9005-remote.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-af9005.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-af9015.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-anysee.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-au6610.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-az6027.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-ce6230.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-cinergyT2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-cxusb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dib0700.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dibusb-common.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dibusb-mb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dibusb-mc.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-digitv.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dtt200u.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dtv5100.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dw2102.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-ec168.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-friio.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-gl861.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-gp8psk.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-lmedm04.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-m920x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-nova-t-usb2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-opera.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-technisat-usb2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-ttusb2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-umt-010.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-vp702x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-vp7045.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb_dummy_fe.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/earth-pt1.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ec100.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-alsa.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-dvb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ene_ir.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/et61x251.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_benq.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_conex.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_cpia1.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_etoms.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_finepix.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_gl860.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_jeilinj.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_kinect.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_konica.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_m5602.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_main.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_mars.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_mr97310a.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_nw80x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_ov519.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_ov534.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_ov534_9.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_pac207.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_pac7302.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_pac7311.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sn9c2028.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sn9c20x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sonixb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sonixj.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca1528.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca500.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca501.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca505.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca506.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca508.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca561.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sq905.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sq905c.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sq930x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_stk014.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_stv0680.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_stv06xx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sunplus.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_t613.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_tv8532.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_vc032x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_vicam.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_xirlink_cit.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_zc3xx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hdpvr.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hexium_gemini.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hexium_orion.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hopper.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/imon.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-jvc-decoder.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-kbd-i2c.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-lirc-codec.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-nec-decoder.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-rc5-decoder.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-rc5-sz-decoder.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-rc6-decoder.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-sony-decoder.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/isl6405.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/isl6421.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/isl6423.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/itd1000.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtvfb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ix2505v.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ks0127.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/l64781.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgdt3305.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgdt330x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgs8gl5.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgs8gxx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lirc_dev.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lnbp21.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m52790.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_core.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/max2165.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mb86a16.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mb86a20s.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mc44s803.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mceusb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/meye.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/msp3400.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt2060.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt20xx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt2131.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt2266.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt312.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt352.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt9v011.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mxb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mxl5005s.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mxl5007t.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ngene.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/noon010pc30.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nuvoton-cir.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nxt200x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nxt6000.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/or51132.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/or51211.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ov7670.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pluto2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/poseidon.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/qt1010.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-maxiradio.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-mr800.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-si4713.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-tea5764.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-usb-si470x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-adstech-dvb-t-pci.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-alink-dtu-m.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-anysee.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-apac-viewcomp.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-asus-pc39.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-ati-tv-wonder-hd-600.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-a16d.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-cardbus.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-dvbt.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-m135a.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-m733a-rm-k6.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-rm-ks.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avertv-303.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-azurewave-ad-tu700.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-behold-columbus.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-behold.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-budget-ci-old.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-cinergy-1400.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-cinergy.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-core.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dib0700-nec.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dib0700-rc5.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-digitalnow-tinytwin.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-digittrade.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dm1105-nec.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dntv-live-dvb-t.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dntv-live-dvbt-pro.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-em-terratec.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-encore-enltv-fm53.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-encore-enltv.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-encore-enltv2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-evga-indtube.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-eztv.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-flydvb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-flyvideo.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-fusionhdtv-mce.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-gadmei-rm008z.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-genius-tvgo-a11mce.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-gotview7135.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-hauppauge.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-imon-mce.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-imon-pad.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-iodata-bctv7e.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-kaiomy.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-kworld-315u.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-kworld-plus-tv-analog.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-leadtek-y04g0051.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-lirc.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-lme2510.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-loopback.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-manli.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-digivox-ii.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-digivox-iii.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-tvanywhere-plus.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-tvanywhere.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-nebula.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-nec-terratec-cinergy-xs.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-norwood.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-npgtech.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pctv-sedna.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pinnacle-color.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pinnacle-grey.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pinnacle-pctv-hd.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview-002t.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview-mk12.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview-new.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-powercolor-real-angel.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-proteus-2309.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-purpletv.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pv951.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-rc6-mce.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-real-audio-220-32-keys.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-streamzap.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tbs-nec.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-technisat-usb2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-cinergy-c-pci.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-cinergy-s2-hd.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-cinergy-xs.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-slim-2.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-slim.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tevii-nec.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tivo.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-total-media-in-hand.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-trekstor.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tt-1500.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-twinhan-dtv-cab-ci.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-twinhan1027.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-videomate-m1f.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-videomate-s350.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-videomate-tv-pvr.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-winfast-usbii-deluxe.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-winfast.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s2255drv.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1409.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1411.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1420.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1432.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s921.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa6588.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa6752hs.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7110.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7115.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7127.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-alsa.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-dvb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-empress.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146_vv.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_budget.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_core.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_ff.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_hybrid.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa717x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7185.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7191.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/si21xx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/si4713-i2c.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsdvb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsmdtv.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smssdio.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsusb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/snd-bt87x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sp8870.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sp887x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sr030pc30.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb0899.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb6000.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb6100.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stkwebcam.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/streamzap.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0288.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0297.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0299.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0367.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0900.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv090x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv6110.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv6110x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tcm825x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10021.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10023.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10048.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda1004x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10086.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18212.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18218.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18271.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda665x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda7432.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda8083.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda8261.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda826x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda827x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda8290.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda9840.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda9887.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea5761.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea5767.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea6415c.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea6420.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tef6862.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ths7303.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tlv320aic23b.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttpci-eeprom.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttusb_dec.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttusbdecfe.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tua6100.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-simple.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-types.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-xc2028.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tvaudio.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tveeprom.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tvp514x.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tvp5150.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/upd64031a.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/upd64083.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/usbvision.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvcvideo.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-common.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-int-device.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ves1820.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ves1x93.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-core.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-dma-sg.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-dvb.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-vmalloc.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf2-core.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf2-memops.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf2-vmalloc.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videocodec.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videodev.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vivi.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vp27smpx.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vpx3220.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/w9966.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/winbond-cir.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/wm8739.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/wm8775.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/xc5000.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zl10036.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zl10039.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zl10353.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36016.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36050.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36060.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36067.mod.o + CC /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr364xx.mod.o + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7170.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7175.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7180.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/adv7343.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/af9013.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/atbm8830.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au0828.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/au8522.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/b2c2-flexcop-pci.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/b2c2-flexcop-usb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/b2c2-flexcop.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bcm3510.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt819.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt856.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt866.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bt878.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/btcx-risc.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bttv.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-av.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-ci.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-core.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget-patch.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/budget.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/bw-qcam.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/c-qcam.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cafe_ccic.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cpia2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cs5345.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cs53l32a.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18-alsa.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx18.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx22700.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx22702.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-alsa.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx-dvb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx231xx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx2341x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx23885.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24110.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24113.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24116.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx24123.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx25840.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-alsa.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-blackbird.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-dvb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88-vp3054-i2c.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx8800.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx8802.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cx88xx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/cxd2820r.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib0070.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib0090.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib3000mb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib3000mc.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib7000m.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib7000p.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib8000.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dib9000.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dibx000_common.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dm1105.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/drxd.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ds3000.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dsbr100.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dst.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dst_ca.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-bt8xx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-core.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-pll.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-ttpci.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-ttusb-budget.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-a800.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-af9005-remote.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-af9005.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-af9015.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-anysee.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-au6610.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-az6027.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-ce6230.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-cinergyT2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-cxusb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dib0700.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dibusb-common.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dibusb-mb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dibusb-mc.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-digitv.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dtt200u.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dtv5100.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-dw2102.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-ec168.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-friio.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-gl861.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-gp8psk.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-lmedm04.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-m920x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-nova-t-usb2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-opera.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-technisat-usb2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-ttusb2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-umt-010.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-vp702x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb-vp7045.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb-usb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/dvb_dummy_fe.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/earth-pt1.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ec100.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-alsa.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx-dvb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/em28xx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ene_ir.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/et61x251.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_benq.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_conex.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_cpia1.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_etoms.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_finepix.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_gl860.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_jeilinj.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_kinect.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_konica.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_m5602.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_main.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_mars.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_mr97310a.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_nw80x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_ov519.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_ov534.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_ov534_9.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_pac207.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_pac7302.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_pac7311.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sn9c2028.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sn9c20x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sonixb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sonixj.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca1528.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca500.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca501.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca505.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca506.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca508.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_spca561.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sq905.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sq905c.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sq930x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_stk014.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_stv0680.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_stv06xx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_sunplus.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_t613.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_tv8532.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_vc032x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_vicam.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_xirlink_cit.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/gspca_zc3xx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hdpvr.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hexium_gemini.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hexium_orion.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/hopper.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/imon.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-jvc-decoder.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-kbd-i2c.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-lirc-codec.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-nec-decoder.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-rc5-decoder.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-rc5-sz-decoder.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-rc6-decoder.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ir-sony-decoder.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/isl6405.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/isl6421.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/isl6423.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/itd1000.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtv.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ivtvfb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ix2505v.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ks0127.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/l64781.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgdt3305.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgdt330x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgs8gl5.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lgs8gxx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lirc_dev.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/lnbp21.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/m52790.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mantis_core.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/max2165.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mb86a16.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mb86a20s.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mc44s803.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mceusb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/meye.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/msp3400.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt2060.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt20xx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt2131.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt2266.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt312.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt352.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mt9v011.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mxb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mxl5005s.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/mxl5007t.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ngene.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/noon010pc30.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nuvoton-cir.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nxt200x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/nxt6000.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/or51132.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/or51211.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ov7670.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pluto2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/poseidon.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pvrusb2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/pwc.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/qt1010.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-maxiradio.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-mr800.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-si4713.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-tea5764.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/radio-usb-si470x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-adstech-dvb-t-pci.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-alink-dtu-m.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-anysee.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-apac-viewcomp.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-asus-pc39.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-ati-tv-wonder-hd-600.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-a16d.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-cardbus.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-dvbt.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-m135a.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-m733a-rm-k6.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia-rm-ks.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avermedia.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-avertv-303.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-azurewave-ad-tu700.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-behold-columbus.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-behold.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-budget-ci-old.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-cinergy-1400.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-cinergy.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-core.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dib0700-nec.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dib0700-rc5.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-digitalnow-tinytwin.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-digittrade.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dm1105-nec.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dntv-live-dvb-t.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-dntv-live-dvbt-pro.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-em-terratec.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-encore-enltv-fm53.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-encore-enltv.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-encore-enltv2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-evga-indtube.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-eztv.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-flydvb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-flyvideo.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-fusionhdtv-mce.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-gadmei-rm008z.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-genius-tvgo-a11mce.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-gotview7135.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-hauppauge.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-imon-mce.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-imon-pad.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-iodata-bctv7e.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-kaiomy.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-kworld-315u.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-kworld-plus-tv-analog.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-leadtek-y04g0051.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-lirc.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-lme2510.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-loopback.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-manli.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-digivox-ii.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-digivox-iii.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-tvanywhere-plus.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-msi-tvanywhere.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-nebula.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-nec-terratec-cinergy-xs.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-norwood.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-npgtech.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pctv-sedna.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pinnacle-color.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pinnacle-grey.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pinnacle-pctv-hd.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview-002t.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview-mk12.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview-new.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pixelview.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-powercolor-real-angel.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-proteus-2309.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-purpletv.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-pv951.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-rc6-mce.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-real-audio-220-32-keys.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-streamzap.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tbs-nec.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-technisat-usb2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-cinergy-c-pci.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-cinergy-s2-hd.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-cinergy-xs.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-slim-2.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-terratec-slim.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tevii-nec.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tivo.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-total-media-in-hand.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-trekstor.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-tt-1500.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-twinhan-dtv-cab-ci.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-twinhan1027.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-videomate-m1f.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-videomate-s350.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-videomate-tv-pvr.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-winfast-usbii-deluxe.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/rc-winfast.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s2255drv.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1409.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1411.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1420.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s5h1432.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/s921.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa6588.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa6752hs.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7110.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7115.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7127.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-alsa.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-dvb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134-empress.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7134.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7146_vv.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7164.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_budget.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_core.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_ff.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa716x_hybrid.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa717x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7185.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/saa7191.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/si21xx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/si4713-i2c.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsdvb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsmdtv.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smssdio.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/smsusb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sn9c102.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/snd-bt87x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sp8870.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sp887x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/sr030pc30.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb0899.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb6000.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stb6100.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stkwebcam.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/streamzap.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0288.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0297.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0299.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0367.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv0900.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv090x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv6110.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/stv6110x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tcm825x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10021.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10023.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10048.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda1004x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda10086.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18212.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18218.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda18271.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda665x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda7432.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda8083.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda8261.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda826x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda827x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda8290.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda9840.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tda9887.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea5761.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea5767.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea6415c.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tea6420.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tef6862.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ths7303.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tlv320aic23b.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttpci-eeprom.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttusb_dec.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ttusbdecfe.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tua6100.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-simple.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-types.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner-xc2028.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tuner.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tvaudio.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tveeprom.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tvp514x.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/tvp5150.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/upd64031a.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/upd64083.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/usbvision.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/uvcvideo.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-common.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/v4l2-int-device.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ves1820.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/ves1x93.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-core.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-dma-sg.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-dvb.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf-vmalloc.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf2-core.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf2-memops.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videobuf2-vmalloc.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videocodec.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/videodev.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vivi.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vp27smpx.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/vpx3220.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/w9966.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/winbond-cir.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/wm8739.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/wm8775.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/xc5000.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zl10036.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zl10039.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zl10353.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36016.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36050.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36060.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr36067.ko + LD [M] /root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l/zr364xx.ko +make[2]: Leaving directory `/usr/src/linux-headers-2.6.32-32-generic' +./scripts/rmmod.pl check +found 434 modules +make[1]: Leaving directory `/root/yavdr-dkms-scripts/tmp.6yxoECx7gf/v4l-dvb/0~20110625.git255868.188~lucid/build/v4l' Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/adv7170.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/adv7170.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/adv7175.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/adv7175.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/adv7180.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/adv7180.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/adv7343.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/adv7343.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/af9013.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/af9013.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/atbm8830.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/atbm8830.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/au0828.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/au0828.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/au8522.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/au8522.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/b2c2-flexcop.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/b2c2-flexcop.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/b2c2-flexcop-pci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/b2c2-flexcop-pci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/b2c2-flexcop-usb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/b2c2-flexcop-usb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/bcm3510.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/bcm3510.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/bt819.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/bt819.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/bt856.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/bt856.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/bt866.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/bt866.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/bt878.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/bt878.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/btcx-risc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/btcx-risc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/bttv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/bttv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/budget-av.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/budget-av.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/budget-ci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/budget-ci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/budget-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/budget-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/budget.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/budget.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/budget-patch.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/budget-patch.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/bw-qcam.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/bw-qcam.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cafe_ccic.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cafe_ccic.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cpia2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cpia2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/c-qcam.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/c-qcam.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cs5345.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cs5345.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cs53l32a.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cs53l32a.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx18-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx18-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx18.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx18.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx22700.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx22700.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx22702.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx22702.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx231xx-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx231xx-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx231xx-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx231xx-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx231xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx231xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx2341x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx2341x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx23885.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx23885.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx24110.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx24110.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx24113.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx24113.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx24116.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx24116.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx24123.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx24123.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx25840.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx25840.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx8800.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx8800.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx8802.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx8802.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx88-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx88-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx88-blackbird.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx88-blackbird.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx88-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx88-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx88-vp3054-i2c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx88-vp3054-i2c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cx88xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cx88xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/cxd2820r.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/cxd2820r.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dib0070.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dib0070.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dib0090.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dib0090.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dib3000mb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dib3000mb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dib3000mc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dib3000mc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dib7000m.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dib7000m.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dib7000p.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dib7000p.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dib8000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dib8000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dib9000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dib9000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dibx000_common.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dibx000_common.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dm1105.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dm1105.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/drxd.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/drxd.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ds3000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ds3000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dsbr100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dsbr100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dst_ca.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dst_ca.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dst.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dst.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-bt8xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-bt8xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb_dummy_fe.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb_dummy_fe.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-pll.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-pll.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-ttpci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-ttpci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-ttusb-budget.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-ttusb-budget.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-a800.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-a800.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-af9005.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-af9005.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-af9005-remote.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-af9005-remote.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-af9015.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-af9015.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-anysee.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-anysee.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-au6610.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-au6610.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-az6027.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-az6027.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-ce6230.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-ce6230.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-cinergyT2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-cinergyT2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-cxusb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-cxusb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dib0700.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dib0700.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dibusb-common.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dibusb-common.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dibusb-mb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dibusb-mb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dibusb-mc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dibusb-mc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-digitv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-digitv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dtt200u.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dtt200u.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dtv5100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dtv5100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dw2102.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-dw2102.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-ec168.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-ec168.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-friio.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-friio.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-gl861.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-gl861.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-gp8psk.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-gp8psk.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-lmedm04.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-lmedm04.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-m920x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-m920x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-nova-t-usb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-nova-t-usb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-opera.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-opera.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-technisat-usb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-technisat-usb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-ttusb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-ttusb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-umt-010.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-umt-010.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-vp702x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-vp702x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-vp7045.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/dvb-usb-vp7045.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/earth-pt1.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/earth-pt1.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ec100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ec100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/em28xx-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/em28xx-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/em28xx-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/em28xx-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/em28xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/em28xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ene_ir.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ene_ir.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/et61x251.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/et61x251.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_benq.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_benq.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_conex.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_conex.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_cpia1.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_cpia1.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_etoms.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_etoms.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_finepix.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_finepix.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_gl860.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_gl860.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_jeilinj.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_jeilinj.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_kinect.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_kinect.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_konica.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_konica.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_m5602.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_m5602.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_main.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_main.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_mars.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_mars.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_mr97310a.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_mr97310a.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_nw80x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_nw80x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_ov519.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_ov519.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_ov534_9.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_ov534_9.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_ov534.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_ov534.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_pac207.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_pac207.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_pac7302.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_pac7302.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_pac7311.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_pac7311.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sn9c2028.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sn9c2028.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sn9c20x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sn9c20x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sonixb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sonixb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sonixj.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sonixj.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca1528.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca1528.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca500.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca500.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca501.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca501.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca505.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca505.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca506.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca506.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca508.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca508.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca561.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_spca561.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sq905c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sq905c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sq905.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sq905.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sq930x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sq930x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_stk014.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_stk014.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_stv0680.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_stv0680.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_stv06xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_stv06xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sunplus.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_sunplus.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_t613.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_t613.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_tv8532.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_tv8532.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_vc032x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_vc032x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_vicam.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_vicam.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_xirlink_cit.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_xirlink_cit.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_zc3xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/gspca_zc3xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/hdpvr.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/hdpvr.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/hexium_gemini.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/hexium_gemini.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/hexium_orion.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/hexium_orion.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/hopper.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/hopper.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/imon.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/imon.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ir-jvc-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ir-jvc-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ir-kbd-i2c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ir-kbd-i2c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ir-lirc-codec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ir-lirc-codec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ir-nec-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ir-nec-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ir-rc5-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ir-rc5-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ir-rc5-sz-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ir-rc5-sz-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ir-rc6-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ir-rc6-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ir-sony-decoder.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ir-sony-decoder.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/isl6405.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/isl6405.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/isl6421.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/isl6421.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/isl6423.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/isl6423.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/itd1000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/itd1000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ivtvfb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ivtvfb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ivtv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ivtv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ix2505v.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ix2505v.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ks0127.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ks0127.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/l64781.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/l64781.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/lgdt3305.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/lgdt3305.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/lgdt330x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/lgdt330x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/lgs8gl5.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/lgs8gl5.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/lgs8gxx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/lgs8gxx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/lirc_dev.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/lirc_dev.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/lnbp21.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/lnbp21.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/m52790.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/m52790.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mantis_core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mantis_core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mantis.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mantis.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/max2165.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/max2165.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mb86a16.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mb86a16.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mb86a20s.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mb86a20s.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mc44s803.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mc44s803.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mceusb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mceusb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/meye.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/meye.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/msp3400.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/msp3400.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mt2060.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mt2060.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mt20xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mt20xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mt2131.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mt2131.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mt2266.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mt2266.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mt312.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mt312.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mt352.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mt352.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mt9v011.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mt9v011.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mxb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mxb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mxl5005s.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mxl5005s.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/mxl5007t.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/mxl5007t.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ngene.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ngene.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/noon010pc30.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/noon010pc30.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/nuvoton-cir.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/nuvoton-cir.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/nxt200x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/nxt200x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/nxt6000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/nxt6000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/or51132.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/or51132.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/or51211.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/or51211.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ov7670.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ov7670.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/pluto2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/pluto2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/poseidon.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/poseidon.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/pvrusb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/pvrusb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/pwc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/pwc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/qt1010.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/qt1010.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/radio-maxiradio.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/radio-maxiradio.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/radio-mr800.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/radio-mr800.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/radio-si4713.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/radio-si4713.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/radio-tea5764.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/radio-tea5764.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/radio-usb-si470x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/radio-usb-si470x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-adstech-dvb-t-pci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-adstech-dvb-t-pci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-alink-dtu-m.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-alink-dtu-m.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-anysee.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-anysee.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-apac-viewcomp.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-apac-viewcomp.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-asus-pc39.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-asus-pc39.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-ati-tv-wonder-hd-600.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-ati-tv-wonder-hd-600.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-a16d.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-a16d.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-cardbus.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-cardbus.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-dvbt.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-dvbt.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-m135a.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-m135a.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-m733a-rm-k6.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-m733a-rm-k6.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-rm-ks.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avermedia-rm-ks.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avertv-303.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-avertv-303.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-azurewave-ad-tu700.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-azurewave-ad-tu700.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-behold-columbus.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-behold-columbus.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-behold.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-behold.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-budget-ci-old.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-budget-ci-old.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-cinergy-1400.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-cinergy-1400.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-cinergy.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-cinergy.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dib0700-nec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dib0700-nec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dib0700-rc5.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dib0700-rc5.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-digitalnow-tinytwin.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-digitalnow-tinytwin.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-digittrade.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-digittrade.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dm1105-nec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dm1105-nec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dntv-live-dvb-t.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dntv-live-dvb-t.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dntv-live-dvbt-pro.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-dntv-live-dvbt-pro.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-em-terratec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-em-terratec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-encore-enltv2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-encore-enltv2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-encore-enltv-fm53.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-encore-enltv-fm53.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-encore-enltv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-encore-enltv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-evga-indtube.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-evga-indtube.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-eztv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-eztv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-flydvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-flydvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-flyvideo.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-flyvideo.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-fusionhdtv-mce.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-fusionhdtv-mce.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-gadmei-rm008z.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-gadmei-rm008z.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-genius-tvgo-a11mce.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-genius-tvgo-a11mce.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-gotview7135.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-gotview7135.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-hauppauge.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-hauppauge.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-imon-mce.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-imon-mce.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-imon-pad.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-imon-pad.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-iodata-bctv7e.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-iodata-bctv7e.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-kaiomy.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-kaiomy.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-kworld-315u.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-kworld-315u.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-kworld-plus-tv-analog.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-kworld-plus-tv-analog.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-leadtek-y04g0051.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-leadtek-y04g0051.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-lirc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-lirc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-lme2510.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-lme2510.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-loopback.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-loopback.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-manli.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-manli.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-msi-digivox-iii.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-msi-digivox-iii.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-msi-digivox-ii.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-msi-digivox-ii.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-msi-tvanywhere.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-msi-tvanywhere.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-msi-tvanywhere-plus.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-msi-tvanywhere-plus.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-nebula.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-nebula.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-nec-terratec-cinergy-xs.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-nec-terratec-cinergy-xs.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-norwood.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-norwood.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-npgtech.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-npgtech.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pctv-sedna.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pctv-sedna.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pinnacle-color.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pinnacle-color.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pinnacle-grey.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pinnacle-grey.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pinnacle-pctv-hd.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pinnacle-pctv-hd.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pixelview-002t.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pixelview-002t.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pixelview.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pixelview.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pixelview-mk12.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pixelview-mk12.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pixelview-new.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pixelview-new.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-powercolor-real-angel.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-powercolor-real-angel.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-proteus-2309.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-proteus-2309.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-purpletv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-purpletv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pv951.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-pv951.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-rc6-mce.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-rc6-mce.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-real-audio-220-32-keys.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-real-audio-220-32-keys.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-streamzap.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-streamzap.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-tbs-nec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-tbs-nec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-technisat-usb2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-technisat-usb2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-cinergy-c-pci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-cinergy-c-pci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-cinergy-s2-hd.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-cinergy-s2-hd.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-cinergy-xs.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-cinergy-xs.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-slim-2.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-slim-2.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-slim.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-terratec-slim.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-tevii-nec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-tevii-nec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-tivo.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-tivo.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-total-media-in-hand.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-total-media-in-hand.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-trekstor.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-trekstor.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-tt-1500.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-tt-1500.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-twinhan1027.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-twinhan1027.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-twinhan-dtv-cab-ci.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-twinhan-dtv-cab-ci.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-videomate-m1f.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-videomate-m1f.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-videomate-s350.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-videomate-s350.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-videomate-tv-pvr.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-videomate-tv-pvr.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-winfast.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-winfast.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/rc-winfast-usbii-deluxe.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/rc-winfast-usbii-deluxe.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/s2255drv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/s2255drv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/s5h1409.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/s5h1409.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/s5h1411.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/s5h1411.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/s5h1420.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/s5h1420.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/s5h1432.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/s5h1432.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/s921.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/s921.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa6588.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa6588.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa6752hs.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa6752hs.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7110.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7110.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7115.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7115.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7127.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7127.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7134-alsa.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7134-alsa.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7134-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7134-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7134-empress.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7134-empress.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7134.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7134.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7146.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7146.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7146_vv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7146_vv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7164.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7164.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa716x_budget.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa716x_budget.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa716x_core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa716x_core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa716x_ff.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa716x_ff.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa716x_hybrid.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa716x_hybrid.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa717x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa717x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7185.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7185.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/saa7191.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/saa7191.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/si21xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/si21xx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/si4713-i2c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/si4713-i2c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/smsdvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/smsdvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/smsmdtv.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/smsmdtv.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/smssdio.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/smssdio.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/smsusb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/smsusb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/sn9c102.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/sn9c102.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/snd-bt87x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/snd-bt87x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/sp8870.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/sp8870.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/sp887x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/sp887x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/sr030pc30.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/sr030pc30.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stb0899.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stb0899.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stb6000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stb6000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stb6100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stb6100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stkwebcam.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stkwebcam.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/streamzap.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/streamzap.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stv0288.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stv0288.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stv0297.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stv0297.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stv0299.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stv0299.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stv0367.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stv0367.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stv0900.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stv0900.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stv090x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stv090x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stv6110.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stv6110.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/stv6110x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/stv6110x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tcm825x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tcm825x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda10021.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda10021.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda10023.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda10023.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda10048.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda10048.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda1004x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda1004x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda10086.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda10086.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda18212.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda18212.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda18218.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda18218.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda18271.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda18271.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda665x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda665x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda7432.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda7432.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda8083.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda8083.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda8261.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda8261.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda826x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda826x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda827x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda827x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda8290.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda8290.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda9840.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda9840.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tda9887.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tda9887.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tea5761.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tea5761.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tea5767.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tea5767.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tea6415c.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tea6415c.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tea6420.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tea6420.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tef6862.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tef6862.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ths7303.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ths7303.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tlv320aic23b.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tlv320aic23b.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ttpci-eeprom.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ttpci-eeprom.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ttusbdecfe.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ttusbdecfe.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ttusb_dec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ttusb_dec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tua6100.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tua6100.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tuner.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tuner.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tuner-simple.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tuner-simple.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tuner-types.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tuner-types.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tuner-xc2028.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tuner-xc2028.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tvaudio.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tvaudio.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tveeprom.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tveeprom.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tvp514x.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tvp514x.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/tvp5150.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/tvp5150.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/upd64031a.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/upd64031a.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/upd64083.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/upd64083.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/usbvision.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/usbvision.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/uvcvideo.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/uvcvideo.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/v4l2-common.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/v4l2-common.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/v4l2-int-device.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/v4l2-int-device.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ves1820.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ves1820.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/ves1x93.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/ves1x93.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf2-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf2-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf2-memops.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf2-memops.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf2-vmalloc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf2-vmalloc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf-core.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf-core.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf-dma-sg.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf-dma-sg.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf-dvb.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf-dvb.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf-vmalloc.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/videobuf-vmalloc.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/videocodec.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/videocodec.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/videodev.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/videodev.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/vivi.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/vivi.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/vp27smpx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/vp27smpx.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/vpx3220.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/vpx3220.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/w9966.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/w9966.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/winbond-cir.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/winbond-cir.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/wm8739.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/wm8739.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/wm8775.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/wm8775.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/xc5000.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/xc5000.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/zl10036.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/zl10036.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/zl10039.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/zl10039.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/zl10353.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/zl10353.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/zr36016.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/zr36016.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/zr36050.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/zr36050.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/zr36060.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/zr36060.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/zr36067.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/zr36067.ko differ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/dkms_main_tree/2.6.32-32-generic/i686/module/zr364xx.ko and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/dkms_main_tree/2.6.32-32-generic/i686/module/zr364xx.ko differ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/.svn/all-wcprops v4l-dvb-dkms-0~20110625.git255868.188~lucid/.svn/all-wcprops --- v4l-dvb-dkms-0~20110324.git235676.160/.svn/all-wcprops 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/.svn/all-wcprops 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 59 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb -END -Makefile -K 25 -svn:wc:ra_dav:version-url -V 68 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/Makefile -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/.svn/entries v4l-dvb-dkms-0~20110625.git255868.188~lucid/.svn/entries --- v4l-dvb-dkms-0~20110324.git235676.160/.svn/entries 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/.svn/entries 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -10 - -dir -2682 -https://svn.origo.ethz.ch/yavdr/trunk/misc/make-dkms/templates/v4l-dvb -https://svn.origo.ethz.ch/yavdr - - - -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - -4b10c2f0-612b-4a6c-a5b7-95c0885a526e - -debian -dir - -Makefile -file - - - - -2011-02-26T06:31:32.000000Z -0e59a61816086c652ba76743b3759d3f -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -657 - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/.svn/text-base/Makefile.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/.svn/text-base/Makefile.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/.svn/text-base/Makefile.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/.svn/text-base/Makefile.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#/usr/bin/make -SRC = $(DESTDIR)/usr/src -SHARE = $(DESTDIR)/usr/share/$(NAME)-dkms - -all: - -clean: - -install: - -#source tree -ifeq ("$(wildcard $(NAME)-$(VERSION))", "$(NAME)-$(VERSION)") - install -d "$(SRC)" - cp -a $(NAME)-$(VERSION) $(SRC) -endif - -#tarball, possibly with binaries -ifeq ("$(wildcard $(NAME)-$(VERSION).dkms.tar.gz)", "$(NAME)-$(VERSION).dkms.tar.gz") - install -d "$(SHARE)" - install -m 644 $(NAME)-$(VERSION).dkms.tar.gz "$(SHARE)" -endif - -#postinst, only if we are supporting legacy mode -ifeq ("$(wildcard common.postinst)", "common.postinst") - install -d "$(SHARE)" - install -m 755 $(PREFIX)/usr/lib/dkms/common.postinst $(SHARE)/postinst -endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_device_type.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_device_type.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_device_type.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_device_type.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ ---- linux/drivers/media/rc/rc-main.c.orig 2011-03-11 18:44:43.734443972 +0100 -+++ linux/drivers/media/rc/rc-main.c 2011-03-11 18:44:56.371948200 +0100 -@@ -904,7 +904,7 @@ - .attrs = rc_dev_attrs, - }; - --static const struct attribute_group *rc_dev_attr_groups[] = { -+static struct attribute_group *rc_dev_attr_groups[] = { - &rc_dev_attr_grp, - NULL - }; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_nodename.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_nodename.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_nodename.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_nodename.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c ---- a/drivers/media/dvb/dvb-core/dvbdev.c -+++ b/drivers/media/dvb/dvb-core/dvbdev.c -@@ -449,7 +449,7 @@ static int dvb_uevent(struct device *dev - return 0; - } - --static char *dvb_devnode(struct device *dev, mode_t *mode) -+static char *dvb_nodename(struct device *dev) - { - struct dvb_device *dvbdev = dev_get_drvdata(dev); - -@@ -480,7 +480,7 @@ static int __init init_dvbdev(void) - goto error; - } - dvb_class->dev_uevent = dvb_uevent; -- dvb_class->devnode = dvb_devnode; -+ dvb_class->nodename = dvb_nodename; - return 0; - - error: -diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c ---- a/drivers/media/rc/rc-main.c -+++ b/drivers/media/rc/rc-main.c -@@ -673,14 +673,14 @@ static void ir_close(struct input_dev *i - } - - /* class for /sys/class/rc */ --static char *ir_devnode(struct device *dev, mode_t *mode) -+static char *ir_nodename(struct device *dev) - { - return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev)); - } - - static struct class ir_input_class = { - .name = "rc", -- .devnode = ir_devnode, -+ .nodename = ir_nodename, - }; - - static struct { diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_series 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_series 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -v2.6.37_dont_use_alloc_ordered_workqueue.patch -v2.6.36_input_getkeycode.patch -v2.6.35_vm_prev.patch -v2.6.35_firedtv_handle_fcp.patch -v2.6.35_i2c_new_probed_device.patch -v2.6.35_work_handler.patch -v2.6.34_dvb_net.patch -v2.6.34_fix_define_warnings.patch -v2.6.33_input_handlers_are_int.patch -v2.6.33_pvrusb2_sysfs.patch -v2.6.32_kfifo.patch -v2.6.31_nodename.patch -v2.6.31_vm_ops.patch -v2.6.31_device_type.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_vm_ops.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_vm_ops.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_vm_ops.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.31_vm_ops.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,189 +0,0 @@ -diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c -index 55ffd60..b8d9ca6 100644 ---- a/drivers/media/video/cafe_ccic.c -+++ b/drivers/media/video/cafe_ccic.c -@@ -1368,7 +1368,7 @@ static void cafe_v4l_vm_close(struct vm_area_struct *vma) - mutex_unlock(&sbuf->cam->s_mutex); - } - --static const struct vm_operations_struct cafe_v4l_vm_ops = { -+static struct vm_operations_struct cafe_v4l_vm_ops = { - .open = cafe_v4l_vm_open, - .close = cafe_v4l_vm_close - }; -diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c -index a982750..3ad0d25 100644 ---- a/drivers/media/video/et61x251/et61x251_core.c -+++ b/drivers/media/video/et61x251/et61x251_core.c -@@ -1499,7 +1499,7 @@ static void et61x251_vm_close(struct vm_area_struct* vma) - } - - --static const struct vm_operations_struct et61x251_vm_ops = { -+static struct vm_operations_struct et61x251_vm_ops = { - .open = et61x251_vm_open, - .close = et61x251_vm_close, - }; -diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c -index f21f2a2..0d5e677 100644 ---- a/drivers/media/video/gspca/gspca.c -+++ b/drivers/media/video/gspca/gspca.c -@@ -107,7 +107,7 @@ static void gspca_vm_close(struct vm_area_struct *vma) - frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_MAPPED; - } - --static const struct vm_operations_struct gspca_vm_ops = { -+static struct vm_operations_struct gspca_vm_ops = { - .open = gspca_vm_open, - .close = gspca_vm_close, - }; -diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c -index 48d2c24..4e70832 100644 ---- a/drivers/media/video/meye.c -+++ b/drivers/media/video/meye.c -@@ -1598,7 +1598,7 @@ static void meye_vm_close(struct vm_area_struct *vma) - meye.vma_use_count[idx]--; - } - --static const struct vm_operations_struct meye_vm_ops = { -+static struct vm_operations_struct meye_vm_ops = { - .open = meye_vm_open, - .close = meye_vm_close, - }; -diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c -index ce56a1c..cc091b2 100644 ---- a/drivers/media/video/sn9c102/sn9c102_core.c -+++ b/drivers/media/video/sn9c102/sn9c102_core.c -@@ -2078,7 +2078,7 @@ static void sn9c102_vm_close(struct vm_area_struct* vma) - } - - --static const struct vm_operations_struct sn9c102_vm_ops = { -+static struct vm_operations_struct sn9c102_vm_ops = { - .open = sn9c102_vm_open, - .close = sn9c102_vm_close, - }; -diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c -index d1a2cef..b24988a 100644 ---- a/drivers/media/video/stk-webcam.c -+++ b/drivers/media/video/stk-webcam.c -@@ -672,7 +672,7 @@ static void stk_v4l_vm_close(struct vm_area_struct *vma) - if (sbuf->mapcount == 0) - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; - } --static const struct vm_operations_struct stk_v4l_vm_ops = { -+static struct vm_operations_struct stk_v4l_vm_ops = { - .open = stk_v4l_vm_open, - .close = stk_v4l_vm_close - }; -diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c -index f14581b..f628414 100644 ---- a/drivers/media/video/uvc/uvc_queue.c -+++ b/drivers/media/video/uvc/uvc_queue.c -@@ -394,7 +394,7 @@ static void uvc_vm_close(struct vm_area_struct *vma) - buffer->vma_use_count--; - } - --static const struct vm_operations_struct uvc_vm_ops = { -+static struct vm_operations_struct uvc_vm_ops = { - .open = uvc_vm_open, - .close = uvc_vm_close, - }; -diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c -index c969111..2411516 100644 ---- a/drivers/media/video/videobuf-dma-contig.c -+++ b/drivers/media/video/videobuf-dma-contig.c -@@ -106,7 +106,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma) - } - } - --static const struct vm_operations_struct videobuf_vm_ops = { -+static struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, - }; -diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c -index ddb8f4b..3ef135a 100644 ---- a/drivers/media/video/videobuf-dma-sg.c -+++ b/drivers/media/video/videobuf-dma-sg.c -@@ -402,7 +402,7 @@ static int videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) - return 0; - } - --static const struct vm_operations_struct videobuf_vm_ops = { -+static struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, - .fault = videobuf_vm_fault, -diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c -index df14258..9b9631f 100644 ---- a/drivers/media/video/videobuf-vmalloc.c -+++ b/drivers/media/video/videobuf-vmalloc.c -@@ -120,7 +120,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma) - return; - } - --static const struct vm_operations_struct videobuf_vm_ops = { -+static struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, - }; -diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c -index a3eb656..e479bc2 100644 ---- a/drivers/media/video/videobuf2-memops.c -+++ b/drivers/media/video/videobuf2-memops.c -@@ -156,7 +156,7 @@ EXPORT_SYMBOL_GPL(vb2_get_contig_userptr); - */ - int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, - unsigned long size, -- const struct vm_operations_struct *vm_ops, -+ struct vm_operations_struct *vm_ops, - void *priv) - { - int ret; -@@ -224,7 +224,7 @@ static void vb2_common_vm_close(struct vm_area_struct *vma) - * vb2_common_vm_ops - common vm_ops used for tracking refcount of mmaped - * video buffers - */ --const struct vm_operations_struct vb2_common_vm_ops = { -+struct vm_operations_struct vb2_common_vm_ops = { - .open = vb2_common_vm_open, - .close = vb2_common_vm_close, - }; -diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c -index 7c3921d..40a4cd3 100644 ---- a/drivers/media/video/zoran/zoran_driver.c -+++ b/drivers/media/video/zoran/zoran_driver.c -@@ -2850,7 +2850,7 @@ zoran_vm_close (struct vm_area_struct *vma) - mutex_unlock(&zr->resource_lock); - } - --static const struct vm_operations_struct zoran_vm_ops = { -+static struct vm_operations_struct zoran_vm_ops = { - .open = zoran_vm_open, - .close = zoran_vm_close, - }; -diff --git a/drivers/staging/vme/bridges/Module.symvers b/drivers/staging/vme/bridges/Module.symvers -deleted file mode 100644 -index e69de29..0000000 -diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h -index fee1703..3e83625 100644 ---- a/include/media/videobuf2-memops.h -+++ b/include/media/videobuf2-memops.h -@@ -28,14 +28,14 @@ struct vb2_vmarea_handler { - void *arg; - }; - --extern const struct vm_operations_struct vb2_common_vm_ops; -+extern struct vm_operations_struct vb2_common_vm_ops; - - int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, - struct vm_area_struct **res_vma, dma_addr_t *res_pa); - - int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, - unsigned long size, -- const struct vm_operations_struct *vm_ops, -+ struct vm_operations_struct *vm_ops, - void *priv); - - struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.32_kfifo.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.32_kfifo.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.32_kfifo.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.32_kfifo.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,540 +0,0 @@ -diff -r c4cd3d2e5902 drivers/media/rc/rc-core-priv.h ---- a/drivers/media/rc/rc-core-priv.h Mon Nov 29 08:40:01 2010 -0200 -+++ b/drivers/media/rc/rc-core-priv.h Mon Nov 29 08:42:43 2010 -0200 -@@ -35,7 +35,7 @@ struct ir_raw_event_ctrl { - struct list_head list; /* to keep track of raw clients */ - struct task_struct *thread; - spinlock_t lock; -- struct kfifo kfifo; /* fifo for the pulse/space durations */ -+ struct kfifo *kfifo; /* fifo for the pulse/space durations */ - ktime_t last_event; /* when last event occurred */ - enum raw_event_type last_type; /* last event type */ - struct rc_dev *dev; /* pointer to the parent rc_dev */ -diff -r c4cd3d2e5902 drivers/media/rc/ir-raw.c ---- a/drivers/media/rc/ir-raw.c Mon Nov 29 08:40:01 2010 -0200 -+++ b/drivers/media/rc/ir-raw.c Mon Nov 29 08:42:43 2010 -0200 -@@ -44,7 +44,7 @@ static int ir_raw_event_thread(void *dat - while (!kthread_should_stop()) { - - spin_lock_irq(&raw->lock); -- retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev)); -+ retval = __kfifo_get(raw->kfifo, (void *)&ev, sizeof(ev)); - - if (!retval) { - set_current_state(TASK_INTERRUPTIBLE); -@@ -90,7 +90,7 @@ int ir_raw_event_store(struct rc_dev *de - IR_dprintk(2, "sample: (%05dus %s)\n", - TO_US(ev->duration), TO_STR(ev->pulse)); - -- if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) -+ if (__kfifo_put(dev->raw->kfifo, (void *)ev, sizeof(*ev)) != sizeof(*ev)) - return -ENOMEM; - - return 0; -@@ -259,11 +259,11 @@ int ir_raw_event_register(struct rc_dev - - dev->raw->dev = dev; - dev->raw->enabled_protocols = ~0; -- rc = kfifo_alloc(&dev->raw->kfifo, -- sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, -- GFP_KERNEL); -- if (rc < 0) -+ dev->raw->kfifo = kfifo_alloc(sizeof(s64) * MAX_IR_EVENT_SIZE, GFP_KERNEL, NULL); -+ if (IS_ERR(dev->raw->kfifo)) { -+ rc = PTR_ERR(dev->raw->kfifo); - goto out; -+ } - - spin_lock_init(&dev->raw->lock); - dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, -@@ -305,7 +305,7 @@ void ir_raw_event_unregister(struct rc_d - handler->raw_unregister(dev); - mutex_unlock(&ir_raw_handler_lock); - -- kfifo_free(&dev->raw->kfifo); -+ kfifo_free(dev->raw->kfifo); - kfree(dev->raw); - dev->raw = NULL; - } -diff -r c4cd3d2e5902 drivers/media/video/cx23885/cx23888-ir.c ---- a/drivers/media/video/cx23885/cx23888-ir.c Mon Nov 29 08:40:01 2010 -0200 -+++ b/drivers/media/video/cx23885/cx23888-ir.c Mon Nov 29 08:42:43 2010 -0200 -@@ -138,7 +138,7 @@ struct cx23888_ir_state { - atomic_t rxclk_divider; - atomic_t rx_invert; - -- struct kfifo rx_kfifo; -+ struct kfifo *rx_kfifo; - spinlock_t rx_kfifo_lock; - - struct v4l2_subdev_ir_parameters tx_params; -@@ -540,7 +540,6 @@ static int cx23888_ir_irq_handler(struct - { - struct cx23888_ir_state *state = to_state(sd); - struct cx23885_dev *dev = state->dev; -- unsigned long flags; - - u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); - u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); -@@ -613,10 +612,9 @@ static int cx23888_ir_irq_handler(struct - } - if (i == 0) - break; -- j = i * sizeof(union cx23888_ir_fifo_rec); -- k = kfifo_in_locked(&state->rx_kfifo, -- (unsigned char *) rx_data, j, -- &state->rx_kfifo_lock); -+ j = i * sizeof(u32); -+ k = kfifo_put(state->rx_kfifo, -+ (unsigned char *) rx_data, j); - if (k != j) - kror++; /* rx_kfifo over run */ - } -@@ -653,10 +651,8 @@ static int cx23888_ir_irq_handler(struct - *handled = true; - } - -- spin_lock_irqsave(&state->rx_kfifo_lock, flags); -- if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) -+ if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) - events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; -- spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); - - if (events) - v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); -@@ -682,7 +678,7 @@ static int cx23888_ir_rx_read(struct v4l - return 0; - } - -- n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock); -+ n = kfifo_get(state->rx_kfifo, buf, n); - - n /= sizeof(union cx23888_ir_fifo_rec); - *num = n * sizeof(union cx23888_ir_fifo_rec); -@@ -817,12 +813,7 @@ static int cx23888_ir_rx_s_parameters(st - o->interrupt_enable = p->interrupt_enable; - o->enable = p->enable; - if (p->enable) { -- unsigned long flags; -- -- spin_lock_irqsave(&state->rx_kfifo_lock, flags); -- kfifo_reset(&state->rx_kfifo); -- /* reset tx_fifo too if there is one... */ -- spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); -+ kfifo_reset(state->rx_kfifo); - if (p->interrupt_enable) - irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); - control_rx_enable(dev, p->enable); -@@ -1210,8 +1201,10 @@ int cx23888_ir_probe(struct cx23885_dev - return -ENOMEM; - - spin_lock_init(&state->rx_kfifo_lock); -- if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL)) -- return -ENOMEM; -+ state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL, -+ &state->rx_kfifo_lock); -+ if (IS_ERR(state->rx_kfifo)) -+ return IS_ERR(state->rx_kfifo); - - state->dev = dev; - state->id = V4L2_IDENT_CX23888_IR; -@@ -1243,7 +1236,7 @@ int cx23888_ir_probe(struct cx23885_dev - sizeof(struct v4l2_subdev_ir_parameters)); - v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); - } else { -- kfifo_free(&state->rx_kfifo); -+ kfifo_free(state->rx_kfifo); - } - return ret; - } -@@ -1262,7 +1255,7 @@ int cx23888_ir_remove(struct cx23885_dev - - state = to_state(sd); - v4l2_device_unregister_subdev(sd); -- kfifo_free(&state->rx_kfifo); -+ kfifo_free(state->rx_kfifo); - kfree(state); - /* Nothing more to free() as state held the actual v4l2_subdev object */ - return 0; -diff -r c4cd3d2e5902 drivers/media/video/cx25840/cx25840-ir.c ---- a/drivers/media/video/cx25840/cx25840-ir.c Mon Nov 29 08:40:01 2010 -0200 -+++ b/drivers/media/video/cx25840/cx25840-ir.c Mon Nov 29 08:42:43 2010 -0200 -@@ -116,7 +116,7 @@ struct cx25840_ir_state { - atomic_t rxclk_divider; - atomic_t rx_invert; - -- struct kfifo rx_kfifo; -+ struct kfifo *rx_kfifo; - spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */ - - struct v4l2_subdev_ir_parameters tx_params; -@@ -525,7 +525,6 @@ int cx25840_ir_irq_handler(struct v4l2_s - struct cx25840_state *state = to_state(sd); - struct cx25840_ir_state *ir_state = to_ir_state(sd); - struct i2c_client *c = NULL; -- unsigned long flags; - - union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; - unsigned int i, j, k; -@@ -611,9 +610,8 @@ int cx25840_ir_irq_handler(struct v4l2_s - if (i == 0) - break; - j = i * sizeof(union cx25840_ir_fifo_rec); -- k = kfifo_in_locked(&ir_state->rx_kfifo, -- (unsigned char *) rx_data, j, -- &ir_state->rx_kfifo_lock); -+ k = kfifo_put(ir_state->rx_kfifo, -+ (unsigned char *) rx_data, j); - if (k != j) - kror++; /* rx_kfifo over run */ - } -@@ -649,10 +647,8 @@ int cx25840_ir_irq_handler(struct v4l2_s - cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl); - *handled = true; - } -- spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); -- if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) -+ if (kfifo_len(ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) - events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; -- spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); - - if (events) - v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); -@@ -683,8 +679,7 @@ static int cx25840_ir_rx_read(struct v4l - return 0; - } - -- n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n, -- &ir_state->rx_kfifo_lock); -+ n = kfifo_get(ir_state->rx_kfifo, buf, n); - - n /= sizeof(union cx25840_ir_fifo_rec); - *num = n * sizeof(union cx25840_ir_fifo_rec); -@@ -836,11 +831,7 @@ static int cx25840_ir_rx_s_parameters(st - o->interrupt_enable = p->interrupt_enable; - o->enable = p->enable; - if (p->enable) { -- unsigned long flags; -- -- spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); -- kfifo_reset(&ir_state->rx_kfifo); -- spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); -+ kfifo_reset(ir_state->rx_kfifo); - if (p->interrupt_enable) - irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); - control_rx_enable(c, p->enable); -@@ -1234,8 +1225,9 @@ int cx25840_ir_probe(struct v4l2_subdev - return -ENOMEM; - - spin_lock_init(&ir_state->rx_kfifo_lock); -- if (kfifo_alloc(&ir_state->rx_kfifo, -- CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) { -+ ir_state->rx_kfifo = kfifo_alloc(CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL, -+ &ir_state->rx_kfifo_lock); -+ if (IS_ERR(ir_state->rx_kfifo)) { - kfree(ir_state); - return -ENOMEM; - } -@@ -1273,7 +1265,7 @@ int cx25840_ir_remove(struct v4l2_subdev - cx25840_ir_rx_shutdown(sd); - cx25840_ir_tx_shutdown(sd); - -- kfifo_free(&ir_state->rx_kfifo); -+ kfifo_free(ir_state->rx_kfifo); - kfree(ir_state); - state->ir_state = NULL; - return 0; -diff -r c4cd3d2e5902 drivers/media/video/meye.c ---- a/drivers/media/video/meye.c Mon Nov 29 08:40:01 2010 -0200 -+++ b/drivers/media/video/meye.c Mon Nov 29 08:42:43 2010 -0200 -@@ -802,8 +802,8 @@ again: - return IRQ_HANDLED; - - if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) { -- if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, -- sizeof(int), &meye.grabq_lock) != sizeof(int)) { -+ if (kfifo_get(meye.grabq, (unsigned char *)&reqnr, -+ sizeof(int)) != sizeof(int)) { - mchip_free_frame(); - return IRQ_HANDLED; - } -@@ -813,8 +813,7 @@ again: - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); - meye.grab_buffer[reqnr].sequence = sequence++; -- kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, -- sizeof(int), &meye.doneq_lock); -+ kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); - wake_up_interruptible(&meye.proc_list); - } else { - int size; -@@ -823,8 +822,8 @@ again: - mchip_free_frame(); - goto again; - } -- if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, -- sizeof(int), &meye.grabq_lock) != sizeof(int)) { -+ if (kfifo_get(meye.grabq, (unsigned char *)&reqnr, -+ sizeof(int)) != sizeof(int)) { - mchip_free_frame(); - goto again; - } -@@ -834,8 +833,7 @@ again: - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); - meye.grab_buffer[reqnr].sequence = sequence++; -- kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, -- sizeof(int), &meye.doneq_lock); -+ kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); - wake_up_interruptible(&meye.proc_list); - } - mchip_free_frame(); -@@ -863,8 +861,8 @@ static int meye_open(struct file *file) - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; -- kfifo_reset(&meye.grabq); -- kfifo_reset(&meye.doneq); -+ kfifo_reset(meye.grabq); -+ kfifo_reset(meye.doneq); - return 0; - } - -@@ -937,8 +935,7 @@ static int meyeioc_qbuf_capt(int *nb) - mchip_cont_compression_start(); - - meye.grab_buffer[*nb].state = MEYE_BUF_USING; -- kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int), -- &meye.grabq_lock); -+ kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int)); - mutex_unlock(&meye.lock); - - return 0; -@@ -970,9 +967,7 @@ static int meyeioc_sync(struct file *fil - /* fall through */ - case MEYE_BUF_DONE: - meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; -- if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused, -- sizeof(int), &meye.doneq_lock) != sizeof(int)) -- break; -+ kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int)); - } - *i = meye.grab_buffer[*i].size; - mutex_unlock(&meye.lock); -@@ -1459,8 +1454,7 @@ static int vidioc_qbuf(struct file *file - buf->flags |= V4L2_BUF_FLAG_QUEUED; - buf->flags &= ~V4L2_BUF_FLAG_DONE; - meye.grab_buffer[buf->index].state = MEYE_BUF_USING; -- kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index, -- sizeof(int), &meye.grabq_lock); -+ kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int)); - mutex_unlock(&meye.lock); - - return 0; -@@ -1475,19 +1469,19 @@ static int vidioc_dqbuf(struct file *fil - - mutex_lock(&meye.lock); - -- if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { -+ if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - - if (wait_event_interruptible(meye.proc_list, -- kfifo_len(&meye.doneq) != 0) < 0) { -+ kfifo_len(meye.doneq) != 0) < 0) { - mutex_unlock(&meye.lock); - return -EINTR; - } - -- if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr, -- sizeof(int), &meye.doneq_lock)) { -+ if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr, -+ sizeof(int))) { - mutex_unlock(&meye.lock); - return -EBUSY; - } -@@ -1537,8 +1531,8 @@ static int vidioc_streamoff(struct file - { - mutex_lock(&meye.lock); - mchip_hic_stop(); -- kfifo_reset(&meye.grabq); -- kfifo_reset(&meye.doneq); -+ kfifo_reset(meye.grabq); -+ kfifo_reset(meye.doneq); - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; -@@ -1580,7 +1574,7 @@ static unsigned int meye_poll(struct fil - - mutex_lock(&meye.lock); - poll_wait(file, &meye.proc_list, wait); -- if (kfifo_len(&meye.doneq)) -+ if (kfifo_len(meye.doneq)) - res = POLLIN | POLLRDNORM; - mutex_unlock(&meye.lock); - return res; -@@ -1759,14 +1753,16 @@ static int __devinit meye_probe(struct p - } - - spin_lock_init(&meye.grabq_lock); -- if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, -- GFP_KERNEL)) { -+ meye.grabq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL, -+ &meye.grabq_lock); -+ if (IS_ERR(meye.grabq)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); - goto outkfifoalloc1; - } - spin_lock_init(&meye.doneq_lock); -- if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, -- GFP_KERNEL)) { -+ meye.doneq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL, -+ &meye.doneq_lock); -+ if (IS_ERR(meye.doneq)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); - goto outkfifoalloc2; - } -@@ -1877,9 +1873,9 @@ outregions: - outenabledev: - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); - outsonypienable: -- kfifo_free(&meye.doneq); -+ kfifo_free(meye.doneq); - outkfifoalloc2: -- kfifo_free(&meye.grabq); -+ kfifo_free(meye.grabq); - outkfifoalloc1: - vfree(meye.grab_temp); - outvmalloc: -@@ -1910,8 +1906,8 @@ static void __devexit meye_remove(struct - - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); - -- kfifo_free(&meye.doneq); -- kfifo_free(&meye.grabq); -+ kfifo_free(meye.doneq); -+ kfifo_free(meye.grabq); - - vfree(meye.grab_temp); - -diff -r c4cd3d2e5902 drivers/media/video/meye.h ---- a/drivers/media/video/meye.h Mon Nov 29 08:40:01 2010 -0200 -+++ b/drivers/media/video/meye.h Mon Nov 29 08:42:43 2010 -0200 -@@ -304,9 +304,9 @@ struct meye { - struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; - int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */ - struct mutex lock; /* mutex for open/mmap... */ -- struct kfifo grabq; /* queue for buffers to be grabbed */ -+ struct kfifo *grabq; /* queue for buffers to be grabbed */ - spinlock_t grabq_lock; /* lock protecting the queue */ -- struct kfifo doneq; /* queue for grabbed buffers */ -+ struct kfifo *doneq; /* queue for grabbed buffers */ - spinlock_t doneq_lock; /* lock protecting the queue */ - wait_queue_head_t proc_list; /* wait queue */ - struct video_device *vdev; /* video device parameters */ -diff -r c4cd3d2e5902 include/media/lirc_dev.h ---- a/include/media/lirc_dev.h Mon Nov 29 08:40:01 2010 -0200 -+++ b/include/media/lirc_dev.h Mon Nov 29 08:42:43 2010 -0200 -@@ -28,19 +28,15 @@ struct lirc_buffer { - unsigned int size; /* in chunks */ - /* Using chunks instead of bytes pretends to simplify boundary checking - * And should allow for some performance fine tunning later */ -- struct kfifo fifo; -+ struct kfifo *fifo; - u8 fifo_initialized; - }; - - static inline void lirc_buffer_clear(struct lirc_buffer *buf) - { -- unsigned long flags; -- -- if (buf->fifo_initialized) { -- spin_lock_irqsave(&buf->fifo_lock, flags); -- kfifo_reset(&buf->fifo); -- spin_unlock_irqrestore(&buf->fifo_lock, flags); -- } else -+ if (buf->fifo) -+ kfifo_reset(buf->fifo); -+ else - WARN(1, "calling %s on an uninitialized lirc_buffer\n", - __func__); - } -@@ -49,25 +45,23 @@ static inline int lirc_buffer_init(struc - unsigned int chunk_size, - unsigned int size) - { -- int ret; -- - init_waitqueue_head(&buf->wait_poll); - spin_lock_init(&buf->fifo_lock); - buf->chunk_size = chunk_size; - buf->size = size; -- ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL); -- if (ret == 0) -- buf->fifo_initialized = 1; -+ buf->fifo = kfifo_alloc(size * chunk_size, GFP_KERNEL, -+ &buf->fifo_lock); -+ if (IS_ERR(buf->fifo)) -+ return IS_ERR(buf->fifo); - -- return ret; -+ return 0; - } - - static inline void lirc_buffer_free(struct lirc_buffer *buf) - { -- if (buf->fifo_initialized) { -- kfifo_free(&buf->fifo); -- buf->fifo_initialized = 0; -- } else -+ if (buf->fifo) -+ kfifo_free(buf->fifo); -+ else - WARN(1, "calling %s on an uninitialized lirc_buffer\n", - __func__); - } -@@ -75,11 +69,8 @@ static inline void lirc_buffer_free(stru - static inline int lirc_buffer_len(struct lirc_buffer *buf) - { - int len; -- unsigned long flags; - -- spin_lock_irqsave(&buf->fifo_lock, flags); -- len = kfifo_len(&buf->fifo); -- spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ len = kfifo_len(buf->fifo); - - return len; - } -@@ -102,24 +93,19 @@ static inline int lirc_buffer_available( - static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf, - unsigned char *dest) - { -- unsigned int ret = 0; -+ if (lirc_buffer_len(buf) >= buf->chunk_size) -+ kfifo_get(buf->fifo, dest, buf->chunk_size); - -- if (lirc_buffer_len(buf) >= buf->chunk_size) -- ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size, -- &buf->fifo_lock); -- return ret; -+ return 0; - - } - - static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, - unsigned char *orig) - { -- unsigned int ret; -+ kfifo_put(buf->fifo, orig, buf->chunk_size); - -- ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size, -- &buf->fifo_lock); -- -- return ret; -+ return 0; - } - - struct lirc_driver { diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.32_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.32_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.32_series 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.32_series 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -v2.6.37_dont_use_alloc_ordered_workqueue.patch -v2.6.36_input_getkeycode.patch -v2.6.35_vm_prev.patch -v2.6.35_firedtv_handle_fcp.patch -v2.6.35_i2c_new_probed_device.patch -v2.6.35_work_handler.patch -v2.6.34_dvb_net.patch -v2.6.34_fix_define_warnings.patch -v2.6.33_input_handlers_are_int.patch -v2.6.33_pvrusb2_sysfs.patch -v2.6.32_kfifo.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_input_handlers_are_int.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_input_handlers_are_int.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_input_handlers_are_int.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_input_handlers_are_int.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c ---- a/drivers/media/rc/rc-main.c -+++ b/drivers/media/rc/rc-main.c -@@ -318,7 +318,7 @@ static unsigned int ir_establish_scancod - * This routine is used to handle evdev EVIOCSKEY ioctl. - */ - static int ir_setkeycode(struct input_dev *idev, -- unsigned int scancode, unsigned int keycode) -+ int scancode, int keycode) - { - struct rc_dev *rdev = input_get_drvdata(idev); - struct ir_scancode_table *rc_tab = &rdev->rc_tab; -@@ -423,7 +423,7 @@ static unsigned int ir_lookup_by_scancod - * This routine is used to handle evdev EVIOCGKEY ioctl. - */ - static int ir_getkeycode(struct input_dev *idev, -- unsigned int scancode, unsigned int *keycode) -+ int scancode, int *keycode) - { - struct rc_dev *rdev = input_get_drvdata(idev); - struct ir_scancode_table *rc_tab = &rdev->rc_tab; -diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c ---- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c -+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c -@@ -9,7 +9,7 @@ - #include - - static int legacy_dvb_usb_getkeycode(struct input_dev *dev, -- unsigned int scancode, unsigned int *keycode) -+ int scancode, int *keycode) - { - struct dvb_usb_device *d = input_get_drvdata(dev); - -@@ -39,7 +39,7 @@ static int legacy_dvb_usb_getkeycode(str - } - - static int legacy_dvb_usb_setkeycode(struct input_dev *dev, -- unsigned int scancode, unsigned int keycode) -+ int scancode, int keycode) - { - struct dvb_usb_device *d = input_get_drvdata(dev); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_pvrusb2_sysfs.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_pvrusb2_sysfs.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_pvrusb2_sysfs.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_pvrusb2_sysfs.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -diff -r 5254948f88c4 drivers/media/video/pvrusb2/pvrusb2-sysfs.c ---- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c Sun Oct 17 19:59:28 2010 -0200 -+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c Sun Oct 17 20:09:02 2010 -0200 -@@ -423,12 +423,10 @@ - - dip = kzalloc(sizeof(*dip),GFP_KERNEL); - if (!dip) return; -- sysfs_attr_init(&dip->attr_debugcmd.attr); - dip->attr_debugcmd.attr.name = "debugcmd"; - dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP; - dip->attr_debugcmd.show = debugcmd_show; - dip->attr_debugcmd.store = debugcmd_store; -- sysfs_attr_init(&dip->attr_debuginfo.attr); - dip->attr_debuginfo.attr.name = "debuginfo"; - dip->attr_debuginfo.attr.mode = S_IRUGO; - dip->attr_debuginfo.show = debuginfo_show; -@@ -650,8 +648,6 @@ - kfree(class_dev); - return; - } -- -- sysfs_attr_init(&sfp->attr_v4l_minor_number.attr); - sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number"; - sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; - sfp->attr_v4l_minor_number.show = v4l_minor_number_show; -@@ -665,8 +661,6 @@ - } else { - sfp->v4l_minor_number_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_v4l_radio_minor_number.attr); - sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number"; - sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; - sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; -@@ -680,8 +674,6 @@ - } else { - sfp->v4l_radio_minor_number_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_unit_number.attr); - sfp->attr_unit_number.attr.name = "unit_number"; - sfp->attr_unit_number.attr.mode = S_IRUGO; - sfp->attr_unit_number.show = unit_number_show; -@@ -694,8 +686,6 @@ - } else { - sfp->unit_number_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_bus_info.attr); - sfp->attr_bus_info.attr.name = "bus_info_str"; - sfp->attr_bus_info.attr.mode = S_IRUGO; - sfp->attr_bus_info.show = bus_info_show; -@@ -709,8 +699,6 @@ - } else { - sfp->bus_info_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_hdw_name.attr); - sfp->attr_hdw_name.attr.name = "device_hardware_type"; - sfp->attr_hdw_name.attr.mode = S_IRUGO; - sfp->attr_hdw_name.show = hdw_name_show; -@@ -724,8 +712,6 @@ - } else { - sfp->hdw_name_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_hdw_desc.attr); - sfp->attr_hdw_desc.attr.name = "device_hardware_description"; - sfp->attr_hdw_desc.attr.mode = S_IRUGO; - sfp->attr_hdw_desc.show = hdw_desc_show; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_series 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.33_series 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -v2.6.37_dont_use_alloc_ordered_workqueue.patch -v2.6.36_input_getkeycode.patch -v2.6.35_vm_prev.patch -v2.6.35_firedtv_handle_fcp.patch -v2.6.35_i2c_new_probed_device.patch -v2.6.35_work_handler.patch -v2.6.34_dvb_net.patch -v2.6.34_fix_define_warnings.patch -v2.6.33_input_handlers_are_int.patch -v2.6.33_pvrusb2_sysfs.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_dvb_net.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_dvb_net.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_dvb_net.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_dvb_net.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -diff -r 5254948f88c4 drivers/media/dvb/dvb-core/dvb_net.c ---- a/drivers/media/dvb/dvb-core/dvb_net.c Sun Oct 17 19:59:28 2010 -0200 -+++ b/drivers/media/dvb/dvb-core/dvb_net.c Sun Oct 17 20:09:51 2010 -0200 -@@ -1119,14 +1119,14 @@ - } - - --static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr) -+static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) - { - struct dvb_net_priv *priv = netdev_priv(dev); - - if (priv->multi_num == DVB_NET_MULTICAST_MAX) - return -ENOMEM; - -- memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN); -+ memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6); - - priv->multi_num++; - return 0; -@@ -1150,16 +1150,15 @@ - dprintk("%s: allmulti mode\n", dev->name); - priv->rx_mode = RX_MODE_ALL_MULTI; - } else if (!netdev_mc_empty(dev)) { -- struct netdev_hw_addr *ha; -- -+ struct dev_mc_list *mc; - dprintk("%s: set_mc_list, %d entries\n", - dev->name, netdev_mc_count(dev)); - - priv->rx_mode = RX_MODE_MULTI; - priv->multi_num = 0; - -- netdev_for_each_mc_addr(ha, dev) -- dvb_set_mc_filter(dev, ha->addr); -+ netdev_for_each_mc_addr(mc, dev) -+ dvb_set_mc_filter(dev, mc); - } - - netif_addr_unlock_bh(dev); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_fix_define_warnings.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_fix_define_warnings.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_fix_define_warnings.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_fix_define_warnings.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -diff -r a0ea01e58ec5 drivers/media/rc/imon.c ---- a/drivers/media/rc/imon.c Wed Oct 27 20:58:38 2010 -0200 -+++ b/drivers/media/rc/imon.c Wed Oct 27 21:07:04 2010 -0200 -@@ -26,6 +26,7 @@ - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -+#undef pr_fmt - #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - - #include -diff -r a0ea01e58ec5 drivers/media/dvb/frontends/tua6100.c ---- a/drivers/media/dvb/frontends/tua6100.c Wed Oct 27 20:58:38 2010 -0200 -+++ b/drivers/media/dvb/frontends/tua6100.c Wed Oct 27 21:07:04 2010 -0200 -@@ -80,6 +80,7 @@ - struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 }; - struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 }; - -+#undef _P - #define _R 4 - #define _P 32 - #define _ri 4000000 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_series 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.34_series 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -v2.6.37_dont_use_alloc_ordered_workqueue.patch -v2.6.36_input_getkeycode.patch -v2.6.35_vm_prev.patch -v2.6.35_firedtv_handle_fcp.patch -v2.6.35_i2c_new_probed_device.patch -v2.6.35_work_handler.patch -v2.6.34_dvb_net.patch -v2.6.34_fix_define_warnings.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_firedtv_handle_fcp.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_firedtv_handle_fcp.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_firedtv_handle_fcp.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_firedtv_handle_fcp.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -diff -r 22cb011c456d drivers/media/dvb/firewire/firedtv-fw.c ---- a/drivers/media/dvb/firewire/firedtv-fw.c Tue Oct 26 14:18:02 2010 -0200 -+++ b/drivers/media/dvb/firewire/firedtv-fw.c Wed Oct 27 21:35:30 2010 -0200 -@@ -193,9 +193,9 @@ - }; - - static void handle_fcp(struct fw_card *card, struct fw_request *request, -- int tcode, int destination, int source, int generation, -- unsigned long long offset, void *payload, size_t length, -- void *callback_data) -+ int tcode, int destination, int source, int generation, -+ int speed, unsigned long long offset, -+ void *payload, size_t length, void *callback_data) - { - struct firedtv *f, *fdtv = NULL; - struct fw_device *device; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_i2c_new_probed_device.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_i2c_new_probed_device.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_i2c_new_probed_device.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_i2c_new_probed_device.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c ---- a/drivers/media/video/bt8xx/bttv-input.c -+++ b/drivers/media/video/bt8xx/bttv-input.c -@@ -401,7 +401,7 @@ void __devinit init_bttv_i2c_ir(struct b - * That's why we probe 0x1a (~0x34) first. CB - */ - -- i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); -+ i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list); - return; - } - -diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c ---- a/drivers/media/video/cx18/cx18-i2c.c -+++ b/drivers/media/video/cx18/cx18-i2c.c -@@ -104,7 +104,7 @@ static int cx18_i2c_new_ir(struct cx18 * - break; - } - -- return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? -+ return i2c_new_probed_device(adap, &info, addr_list) == NULL ? - -1 : 0; - } - -diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c ---- a/drivers/media/video/cx23885/cx23885-i2c.c -+++ b/drivers/media/video/cx23885/cx23885-i2c.c -@@ -354,7 +354,8 @@ int cx23885_i2c_register(struct cx23885_ - } else - printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", - dev->name, bus->nr); -- -+#if 0 -+ /* This probe function won't work on older devices */ - /* Instantiate the IR receiver device, if present */ - if (0 == bus->i2c_rc) { - struct i2c_board_info info; -@@ -369,7 +370,7 @@ int cx23885_i2c_register(struct cx23885_ - i2c_new_probed_device(&bus->i2c_adap, &info, addr_list, - i2c_probe_func_quick_read); - } -- -+#endif - return bus->i2c_rc; - } - -diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c ---- a/drivers/media/video/em28xx/em28xx-cards.c -+++ b/drivers/media/video/em28xx/em28xx-cards.c -@@ -2446,7 +2446,7 @@ void em28xx_register_i2c_ir(struct em28x - - if (dev->init_data.name) - info.platform_data = &dev->init_data; -- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL); -+ i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); - } - - void em28xx_card_setup(struct em28xx *dev) -diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c ---- a/drivers/media/video/ivtv/ivtv-i2c.c -+++ b/drivers/media/video/ivtv/ivtv-i2c.c -@@ -186,7 +186,7 @@ static int ivtv_i2c_new_ir(struct ivtv * - return -1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, type, I2C_NAME_SIZE); -- return i2c_new_probed_device(adap, &info, addr_list, NULL) -+ return i2c_new_probed_device(adap, &info, addr_list) - == NULL ? -1 : 0; - } - -@@ -231,7 +231,7 @@ static int ivtv_i2c_new_ir(struct ivtv * - info.platform_data = init_data; - strlcpy(info.type, type, I2C_NAME_SIZE); - -- return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? -+ return i2c_new_probed_device(adap, &info, addr_list) == NULL ? - -1 : 0; - } - -@@ -258,7 +258,7 @@ struct i2c_client *ivtv_i2c_new_ir_legac - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); -- return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list, NULL); -+ return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list); - } - - int ivtv_i2c_register(struct ivtv *itv, unsigned idx) -diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c ---- a/drivers/media/video/v4l2-common.c -+++ b/drivers/media/video/v4l2-common.c -@@ -380,8 +380,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_ - - /* Create the i2c client */ - if (info->addr == 0 && probe_addrs) -- client = i2c_new_probed_device(adapter, info, probe_addrs, -- NULL); -+ client = i2c_new_probed_device(adapter, info, probe_addrs); - else - client = i2c_new_device(adapter, info); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_series 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_series 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -v2.6.37_dont_use_alloc_ordered_workqueue.patch -v2.6.36_input_getkeycode.patch -v2.6.35_vm_prev.patch -v2.6.35_firedtv_handle_fcp.patch -v2.6.35_i2c_new_probed_device.patch -v2.6.35_work_handler.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_vm_prev.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_vm_prev.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_vm_prev.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_vm_prev.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c -index 053c157..c47f56e 100644 ---- a/drivers/media/video/videobuf2-memops.c -+++ b/drivers/media/video/videobuf2-memops.c -@@ -52,7 +52,6 @@ struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma) - - vma_copy->vm_mm = NULL; - vma_copy->vm_next = NULL; -- vma_copy->vm_prev = NULL; - - return vma_copy; - } diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_work_handler.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_work_handler.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_work_handler.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.35_work_handler.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -diff -r a14b248a9a18 drivers/media/video/ivtv/ivtv-driver.c ---- a/drivers/media/video/ivtv/ivtv-driver.c Tue Oct 26 23:13:59 2010 -0200 -+++ b/drivers/media/video/ivtv/ivtv-driver.c Tue Oct 26 23:16:20 2010 -0200 -@@ -706,8 +706,6 @@ - */ - static int __devinit ivtv_init_struct1(struct ivtv *itv) - { -- struct sched_param param = { .sched_priority = 99 }; -- - itv->base_addr = pci_resource_start(itv->pdev, 0); - itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ - itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ -@@ -719,17 +717,13 @@ - spin_lock_init(&itv->lock); - spin_lock_init(&itv->dma_reg_lock); - -- init_kthread_worker(&itv->irq_worker); -- itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker, -- itv->v4l2_dev.name); -- if (IS_ERR(itv->irq_worker_task)) { -- IVTV_ERR("Could not create ivtv task\n"); -+ itv->irq_work_queues = create_singlethread_workqueue(itv->v4l2_dev.name); -+ if (itv->irq_work_queues == NULL) { -+ IVTV_ERR("Could not create ivtv workqueue\n"); - return -1; - } -- /* must use the FIFO scheduler as it is realtime sensitive */ -- sched_setscheduler(itv->irq_worker_task, SCHED_FIFO, ¶m); - -- init_kthread_work(&itv->irq_work, ivtv_irq_work_handler); -+ INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler); - - /* start counting open_id at 1 */ - itv->open_id = 1; -@@ -1019,7 +1013,7 @@ - /* PCI Device Setup */ - retval = ivtv_setup_pci(itv, pdev, pci_id); - if (retval == -EIO) -- goto free_worker; -+ goto free_workqueue; - if (retval == -ENXIO) - goto free_mem; - -@@ -1231,8 +1225,8 @@ - release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - if (itv->has_cx23415) - release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); --free_worker: -- kthread_stop(itv->irq_worker_task); -+free_workqueue: -+ destroy_workqueue(itv->irq_work_queues); - err: - if (retval == 0) - retval = -ENODEV; -@@ -1371,9 +1365,9 @@ - ivtv_set_irq_mask(itv, 0xffffffff); - del_timer_sync(&itv->dma_timer); - -- /* Kill irq worker */ -- flush_kthread_worker(&itv->irq_worker); -- kthread_stop(itv->irq_worker_task); -+ /* Stop all Work Queues */ -+ flush_workqueue(itv->irq_work_queues); -+ destroy_workqueue(itv->irq_work_queues); - - ivtv_streams_cleanup(itv, 1); - ivtv_udma_free(itv); -diff -r a14b248a9a18 drivers/media/video/ivtv/ivtv-driver.h ---- a/drivers/media/video/ivtv/ivtv-driver.h Tue Oct 26 23:13:59 2010 -0200 -+++ b/drivers/media/video/ivtv/ivtv-driver.h Tue Oct 26 23:16:20 2010 -0200 -@@ -51,7 +51,7 @@ - #include - #include - #include --#include -+#include - #include - #include - #include -@@ -261,6 +261,7 @@ - #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ - #define IVTV_F_I_INITED 21 /* set after first open */ - #define IVTV_F_I_FAILED 22 /* set if first open failed */ -+#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */ - - /* Event notifications */ - #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ -@@ -667,9 +668,8 @@ - /* Interrupts & DMA */ - u32 irqmask; /* active interrupts */ - u32 irq_rr_idx; /* round-robin stream index */ -- struct kthread_worker irq_worker; /* kthread worker for PIO/YUV/VBI actions */ -- struct task_struct *irq_worker_task; /* task for irq_worker */ -- struct kthread_work irq_work; /* kthread work entry */ -+ struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */ -+ struct work_struct irq_work_queue; /* work entry */ - spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ - int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */ - int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */ -diff -r a14b248a9a18 drivers/media/video/ivtv/ivtv-irq.c ---- a/drivers/media/video/ivtv/ivtv-irq.c Tue Oct 26 23:13:59 2010 -0200 -+++ b/drivers/media/video/ivtv/ivtv-irq.c Tue Oct 26 23:16:20 2010 -0200 -@@ -71,10 +71,19 @@ - write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); - } - --void ivtv_irq_work_handler(struct kthread_work *work) -+void ivtv_irq_work_handler(struct work_struct *work) - { -- struct ivtv *itv = container_of(work, struct ivtv, irq_work); -+ struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue); - -+ DEFINE_WAIT(wait); -+ -+ if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) { -+ struct sched_param param = { .sched_priority = 99 }; -+ -+ /* This thread must use the FIFO scheduler as it -+ is realtime sensitive. */ -+ sched_setscheduler(current, SCHED_FIFO, ¶m); -+ } - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) - ivtv_pio_work_handler(itv); - -@@ -966,7 +975,7 @@ - } - - if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { -- queue_kthread_work(&itv->irq_worker, &itv->irq_work); -+ queue_work(itv->irq_work_queues, &itv->irq_work_queue); - } - - spin_unlock(&itv->dma_reg_lock); -diff -r a14b248a9a18 drivers/media/video/ivtv/ivtv-irq.h ---- a/drivers/media/video/ivtv/ivtv-irq.h Tue Oct 26 23:13:59 2010 -0200 -+++ b/drivers/media/video/ivtv/ivtv-irq.h Tue Oct 26 23:16:20 2010 -0200 -@@ -46,7 +46,7 @@ - - irqreturn_t ivtv_irq_handler(int irq, void *dev_id); - --void ivtv_irq_work_handler(struct kthread_work *work); -+void ivtv_irq_work_handler(struct work_struct *work); - void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); - void ivtv_unfinished_dma(unsigned long arg); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.36_input_getkeycode.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.36_input_getkeycode.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.36_input_getkeycode.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.36_input_getkeycode.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c ---- a/drivers/media/rc/rc-main.c -+++ b/drivers/media/rc/rc-main.c -@@ -318,37 +318,23 @@ - * This routine is used to handle evdev EVIOCSKEY ioctl. - */ - static int ir_setkeycode(struct input_dev *idev, -- const struct input_keymap_entry *ke, -- unsigned int *old_keycode) -+ unsigned int scancode, unsigned int keycode) - { - struct rc_dev *rdev = input_get_drvdata(idev); - struct rc_map *rc_map = &rdev->rc_map; - unsigned int index; -- unsigned int scancode; - int retval = 0; - unsigned long flags; - - spin_lock_irqsave(&rc_map->lock, flags); - -- if (ke->flags & INPUT_KEYMAP_BY_INDEX) { -- index = ke->index; -- if (index >= rc_map->len) { -- retval = -EINVAL; -- goto out; -- } -- } else { -- retval = input_scancode_to_scalar(ke, &scancode); -- if (retval) -- goto out; -- -- index = ir_establish_scancode(rdev, rc_map, scancode, true); -- if (index >= rc_map->len) { -- retval = -ENOMEM; -- goto out; -- } -+ index = ir_establish_scancode(rdev, rc_map, scancode, true); -+ if (index >= rc_map->len) { -+ retval = -ENOMEM; -+ goto out; - } - -- *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode); -+ ir_update_mapping(rdev, rc_map, index, keycode); - - out: - spin_unlock_irqrestore(&rc_map->lock, flags); -@@ -436,48 +422,25 @@ - * This routine is used to handle evdev EVIOCGKEY ioctl. - */ - static int ir_getkeycode(struct input_dev *idev, -- struct input_keymap_entry *ke) -+ unsigned int scancode, unsigned int *keycode) - { - struct rc_dev *rdev = input_get_drvdata(idev); - struct rc_map *rc_map = &rdev->rc_map; -- struct rc_map_table *entry; - unsigned long flags; - unsigned int index; -- unsigned int scancode; - int retval; - - spin_lock_irqsave(&rc_map->lock, flags); - -- if (ke->flags & INPUT_KEYMAP_BY_INDEX) { -- index = ke->index; -- } else { -- retval = input_scancode_to_scalar(ke, &scancode); -- if (retval) -- goto out; -- -- index = ir_lookup_by_scancode(rc_map, scancode); -- } -- -- if (index < rc_map->len) { -- entry = &rc_map->scan[index]; -- -- ke->index = index; -- ke->keycode = entry->keycode; -- ke->len = sizeof(entry->scancode); -- memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode)); -- -- } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) { -- /* -- * We do not really know the valid range of scancodes -- * so let's respond with KEY_RESERVED to anything we -- * do not have mapping for [yet]. -- */ -- ke->index = index; -- ke->keycode = KEY_RESERVED; -- } else { -- retval = -EINVAL; -- goto out; -- } -+ index = ir_lookup_by_scancode(rc_map, scancode); -+ -+ if (index >= rc_map->len) { -+ *keycode = KEY_RESERVED; -+ retval = 0; -+ goto out; -+ } -+ -+ *keycode = rc_map->scan[index].keycode; - - retval = 0; - -@@ -966,8 +929,8 @@ - return NULL; - } - -- dev->input_dev->getkeycode_new = ir_getkeycode; -- dev->input_dev->setkeycode_new = ir_setkeycode; -+ dev->input_dev->getkeycode = ir_getkeycode; -+ dev->input_dev->setkeycode = ir_setkeycode; - input_set_drvdata(dev->input_dev, dev); - - spin_lock_init(&dev->rc_map.lock); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.36_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.36_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.36_series 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.36_series 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -v2.6.37_dont_use_alloc_ordered_workqueue.patch -v2.6.36_input_getkeycode.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.37_dont_use_alloc_ordered_workqueue.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.37_dont_use_alloc_ordered_workqueue.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.37_dont_use_alloc_ordered_workqueue.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.37_dont_use_alloc_ordered_workqueue.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c -index 869690b..e712607 100644 ---- a/drivers/media/video/cx18/cx18-driver.c -+++ b/drivers/media/video/cx18/cx18-driver.c -@@ -665,7 +665,7 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx) - { - snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", - cx->v4l2_dev.name); -- cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0); -+ cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name); - if (cx->in_work_queue == NULL) { - CX18_ERR("Unable to create incoming mailbox handler thread\n"); - return -ENOMEM; -@@ -673,6 +673,18 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx) - return 0; - } - -+static int __devinit cx18_create_out_workq(struct cx18 *cx) -+{ -+ snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out", -+ cx->v4l2_dev.name); -+ cx->out_work_queue = create_workqueue(cx->out_workq_name); -+ if (cx->out_work_queue == NULL) { -+ CX18_ERR("Unable to create outgoing mailbox handler threads\n"); -+ return -ENOMEM; -+ } -+ return 0; -+} -+ - static void __devinit cx18_init_in_work_orders(struct cx18 *cx) - { - int i; -@@ -699,10 +711,16 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) - mutex_init(&cx->epu2apu_mb_lock); - mutex_init(&cx->epu2cpu_mb_lock); - -- ret = cx18_create_in_workq(cx); -+ ret = cx18_create_out_workq(cx); - if (ret) - return ret; - -+ ret = cx18_create_in_workq(cx); -+ if (ret) { -+ destroy_workqueue(cx->out_work_queue); -+ return ret; -+ } -+ - cx18_init_in_work_orders(cx); - - /* start counting open_id at 1 */ -@@ -1095,6 +1113,7 @@ free_mem: - release_mem_region(cx->base_addr, CX18_MEM_SIZE); - free_workqueues: - destroy_workqueue(cx->in_work_queue); -+ destroy_workqueue(cx->out_work_queue); - err: - if (retval == 0) - retval = -ENODEV; -@@ -1246,6 +1265,7 @@ static void cx18_remove(struct pci_dev *pci_dev) - cx18_halt_firmware(cx); - - destroy_workqueue(cx->in_work_queue); -+ destroy_workqueue(cx->out_work_queue); - - cx18_streams_cleanup(cx, 1); - -diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h -index 26eb910..d050a0a 100644 ---- a/drivers/media/video/cx18/cx18-driver.h -+++ b/drivers/media/video/cx18/cx18-driver.h -@@ -617,6 +617,9 @@ struct cx18 { - struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; - char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ - -+ struct workqueue_struct *out_work_queue; -+ char out_workq_name[12]; /* "cx18-NN-out" */ -+ - /* i2c */ - struct i2c_adapter i2c_adap[2]; - struct i2c_algo_bit_data i2c_algo[2]; -diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h -index 713b0e6..51765eb 100644 ---- a/drivers/media/video/cx18/cx18-streams.h -+++ b/drivers/media/video/cx18/cx18-streams.h -@@ -42,7 +42,8 @@ static inline bool cx18_stream_enabled(struct cx18_stream *s) - /* Related to submission of mdls to firmware */ - static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) - { -- schedule_work(&s->out_work_order); -+ struct cx18 *cx = s->cx; -+ queue_work(cx->out_work_queue, &s->out_work_order); - } - - static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s, diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.37_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.37_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/backports/v2.6.37_series 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/backports/v2.6.37_series 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -v2.6.37_dont_use_alloc_ordered_workqueue.patch - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/build.sh v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/build.sh --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/build.sh 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/build.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -run () -{ - echo $@ - $@ - if [ "$?" != "0" ]; then - echo "*** ERROR. Aborting ***" - exit -1 - fi -} - -echo "Checking if the needed tools are present" -run ./check_needs.pl -echo "Checking for Digest::SHA1 (package perl-Digest-SHA1)" -run perl -MDigest::SHA1 -e 1 -echo -echo "************************************************************" -echo "* This script will download the latest tarball and build it*" -echo "* Assuming that your kernel is compatible with the latest *" -echo "* drivers. If not, you'll need to add some extra backports,*" -echo "* ./backports/ directory. *" -echo "* It will also update this tree to be sure that all compat *" -echo "* bits are there, to avoid compilation failures *" -echo "************************************************************" -echo -sleep 5 -run git pull git://linuxtv.org/media_build.git master - -run make -C linux/ download -run make -C linux/ untar -run make - -echo "**********************************************************" -echo "* Compilation finished. Use "make install" to install them" -echo "**********************************************************" - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/check_needs.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/check_needs.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/check_needs.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/check_needs.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#!/usr/bin/perl - -sub findprog($) -{ - foreach(split(/:/, $ENV{PATH})) { - return "$_/$_[0]" if(-x "$_/$_[0]"); - } -} - -sub need_program -{ - my $prog = shift; - my $pkgname = shift; - - return if findprog($prog); - print "please install \"$prog\", otherwise, build won't work."; - print " This program is generally found at \"$pkgname\" package." if ($pkgname); - print "\n"; - - die "need $prog"; -} - -need_program "git"; -need_program "make"; -need_program "gcc"; -need_program "patch"; -need_program "lsdiff", "patchutils"; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/dkms.conf v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/dkms.conf --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/dkms.conf 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/dkms.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,1351 +0,0 @@ -PACKAGE_NAME=v4l-dvb -PACKAGE_VERSION=0~20110324.git235676.160 -AUTOINSTALL=y -MAKE[0]="make -j5 VER=$kernelver" -PATCH[0]=v2.6.37_dont_use_alloc_ordered_workqueue.patch -PATCH_MATCH[0]="^2\.6\.([0-9]|[1-2][0-9]|3[2-6])[^0-9]" -PATCH[1]=v2.6.36_input_getkeycode.patch -PATCH_MATCH[1]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[2]=v2.6.35_work_handler.patch -PATCH_MATCH[2]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[3]=v2.6.35_vm_prev.patch -PATCH_MATCH[3]="^2\.6\.([0-9]|[1-2][0-9]|3[3-6])[^0-9]" -PATCH[4]=v2.6.35_i2c_new_probed_device.patch -PATCH_MATCH[4]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[5]=v2.6.35_firedtv_handle_fcp.patch -PATCH_MATCH[5]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[6]=v2.6.34_fix_define_warnings.patch -PATCH_MATCH[6]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[7]=v2.6.34_dvb_net.patch -PATCH_MATCH[7]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[8]=v2.6.33_pvrusb2_sysfs.patch -PATCH_MATCH[8]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[9]=v2.6.33_input_handlers_are_int.patch -PATCH_MATCH[9]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[10]=v2.6.32_kfifo.patch -PATCH_MATCH[10]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" -PATCH[11]=v2.6.31_nodename.patch -PATCH_MATCH[11]="^2\.6\.([0-9]|[1-2][0-9]|3[0-1])[^0-9]" -PATCH[12]=v2.6.31_device_type.patch -PATCH_MATCH[12]="^2\.6\.([0-9]|[1-2][0-9]|3[0-1])[^0-9]" -PATCH[13]=v2-V4L-DVB-faster-DVB-S-lock-for-mantis-cards-using-stb0899-demod.patch -PATCH[14]=tt-s2-double-fix.patch -PATCH[15]=Refactor-Mantis-DMA-transfer-to-deliver-16Kb-TS-data-per-interrupt.patch -PATCH[16]=Avoid-unnecessary-data-copying-inside-dvb_dmx_swfilter_204-function.patch -BUILT_MODULE_NAME[0]=ir-jvc-decoder -BUILT_MODULE_LOCATION[0]=./v4l -DEST_MODULE_LOCATION[0]=/updates/dkms -BUILT_MODULE_NAME[1]=rc-proteus-2309 -BUILT_MODULE_LOCATION[1]=./v4l -DEST_MODULE_LOCATION[1]=/updates/dkms -BUILT_MODULE_NAME[2]=bt866 -BUILT_MODULE_LOCATION[2]=./v4l -DEST_MODULE_LOCATION[2]=/updates/dkms -BUILT_MODULE_NAME[3]=cx22700 -BUILT_MODULE_LOCATION[3]=./v4l -DEST_MODULE_LOCATION[3]=/updates/dkms -BUILT_MODULE_NAME[4]=dvb-usb-opera -BUILT_MODULE_LOCATION[4]=./v4l -DEST_MODULE_LOCATION[4]=/updates/dkms -BUILT_MODULE_NAME[5]=cx231xx -BUILT_MODULE_LOCATION[5]=./v4l -DEST_MODULE_LOCATION[5]=/updates/dkms -BUILT_MODULE_NAME[6]=b2c2-flexcop-pci -BUILT_MODULE_LOCATION[6]=./v4l -DEST_MODULE_LOCATION[6]=/updates/dkms -BUILT_MODULE_NAME[7]=saa7164 -BUILT_MODULE_LOCATION[7]=./v4l -DEST_MODULE_LOCATION[7]=/updates/dkms -BUILT_MODULE_NAME[8]=dvb-usb-az6027 -BUILT_MODULE_LOCATION[8]=./v4l -DEST_MODULE_LOCATION[8]=/updates/dkms -BUILT_MODULE_NAME[9]=stv0297 -BUILT_MODULE_LOCATION[9]=./v4l -DEST_MODULE_LOCATION[9]=/updates/dkms -BUILT_MODULE_NAME[10]=rc-genius-tvgo-a11mce -BUILT_MODULE_LOCATION[10]=./v4l -DEST_MODULE_LOCATION[10]=/updates/dkms -BUILT_MODULE_NAME[11]=gspca_sunplus -BUILT_MODULE_LOCATION[11]=./v4l -DEST_MODULE_LOCATION[11]=/updates/dkms -BUILT_MODULE_NAME[12]=rc-apac-viewcomp -BUILT_MODULE_LOCATION[12]=./v4l -DEST_MODULE_LOCATION[12]=/updates/dkms -BUILT_MODULE_NAME[13]=zl10039 -BUILT_MODULE_LOCATION[13]=./v4l -DEST_MODULE_LOCATION[13]=/updates/dkms -BUILT_MODULE_NAME[14]=radio-gemtek -BUILT_MODULE_LOCATION[14]=./v4l -DEST_MODULE_LOCATION[14]=/updates/dkms -BUILT_MODULE_NAME[15]=rc-dntv-live-dvbt-pro -BUILT_MODULE_LOCATION[15]=./v4l -DEST_MODULE_LOCATION[15]=/updates/dkms -BUILT_MODULE_NAME[16]=radio-maestro -BUILT_MODULE_LOCATION[16]=./v4l -DEST_MODULE_LOCATION[16]=/updates/dkms -BUILT_MODULE_NAME[17]=rc-cinergy-1400 -BUILT_MODULE_LOCATION[17]=./v4l -DEST_MODULE_LOCATION[17]=/updates/dkms -BUILT_MODULE_NAME[18]=cx24110 -BUILT_MODULE_LOCATION[18]=./v4l -DEST_MODULE_LOCATION[18]=/updates/dkms -BUILT_MODULE_NAME[19]=rc-pinnacle-pctv-hd -BUILT_MODULE_LOCATION[19]=./v4l -DEST_MODULE_LOCATION[19]=/updates/dkms -BUILT_MODULE_NAME[20]=videobuf-vmalloc -BUILT_MODULE_LOCATION[20]=./v4l -DEST_MODULE_LOCATION[20]=/updates/dkms -BUILT_MODULE_NAME[21]=rc-winfast-usbii-deluxe -BUILT_MODULE_LOCATION[21]=./v4l -DEST_MODULE_LOCATION[21]=/updates/dkms -BUILT_MODULE_NAME[22]=rc-core -BUILT_MODULE_LOCATION[22]=./v4l -DEST_MODULE_LOCATION[22]=/updates/dkms -BUILT_MODULE_NAME[23]=dvb-usb-dw2102 -BUILT_MODULE_LOCATION[23]=./v4l -DEST_MODULE_LOCATION[23]=/updates/dkms -BUILT_MODULE_NAME[24]=wm8775 -BUILT_MODULE_LOCATION[24]=./v4l -DEST_MODULE_LOCATION[24]=/updates/dkms -BUILT_MODULE_NAME[25]=radio-aimslab -BUILT_MODULE_LOCATION[25]=./v4l -DEST_MODULE_LOCATION[25]=/updates/dkms -BUILT_MODULE_NAME[26]=ir-rc5-decoder -BUILT_MODULE_LOCATION[26]=./v4l -DEST_MODULE_LOCATION[26]=/updates/dkms -BUILT_MODULE_NAME[27]=s5h1420 -BUILT_MODULE_LOCATION[27]=./v4l -DEST_MODULE_LOCATION[27]=/updates/dkms -BUILT_MODULE_NAME[28]=rc-avermedia-m733a-rm-k6 -BUILT_MODULE_LOCATION[28]=./v4l -DEST_MODULE_LOCATION[28]=/updates/dkms -BUILT_MODULE_NAME[29]=tda18271 -BUILT_MODULE_LOCATION[29]=./v4l -DEST_MODULE_LOCATION[29]=/updates/dkms -BUILT_MODULE_NAME[30]=rc-avermedia-m135a -BUILT_MODULE_LOCATION[30]=./v4l -DEST_MODULE_LOCATION[30]=/updates/dkms -BUILT_MODULE_NAME[31]=rc-gotview7135 -BUILT_MODULE_LOCATION[31]=./v4l -DEST_MODULE_LOCATION[31]=/updates/dkms -BUILT_MODULE_NAME[32]=vivi -BUILT_MODULE_LOCATION[32]=./v4l -DEST_MODULE_LOCATION[32]=/updates/dkms -BUILT_MODULE_NAME[33]=ngene -BUILT_MODULE_LOCATION[33]=./v4l -DEST_MODULE_LOCATION[33]=/updates/dkms -BUILT_MODULE_NAME[34]=smssdio -BUILT_MODULE_LOCATION[34]=./v4l -DEST_MODULE_LOCATION[34]=/updates/dkms -BUILT_MODULE_NAME[35]=dvb-usb-m920x -BUILT_MODULE_LOCATION[35]=./v4l -DEST_MODULE_LOCATION[35]=/updates/dkms -BUILT_MODULE_NAME[36]=rc-behold-columbus -BUILT_MODULE_LOCATION[36]=./v4l -DEST_MODULE_LOCATION[36]=/updates/dkms -BUILT_MODULE_NAME[37]=videobuf2-dma-sg -BUILT_MODULE_LOCATION[37]=./v4l -DEST_MODULE_LOCATION[37]=/updates/dkms -BUILT_MODULE_NAME[38]=em28xx-alsa -BUILT_MODULE_LOCATION[38]=./v4l -DEST_MODULE_LOCATION[38]=/updates/dkms -BUILT_MODULE_NAME[39]=radio-terratec -BUILT_MODULE_LOCATION[39]=./v4l -DEST_MODULE_LOCATION[39]=/updates/dkms -BUILT_MODULE_NAME[40]=c-qcam -BUILT_MODULE_LOCATION[40]=./v4l -DEST_MODULE_LOCATION[40]=/updates/dkms -BUILT_MODULE_NAME[41]=saa6588 -BUILT_MODULE_LOCATION[41]=./v4l -DEST_MODULE_LOCATION[41]=/updates/dkms -BUILT_MODULE_NAME[42]=isl6423 -BUILT_MODULE_LOCATION[42]=./v4l -DEST_MODULE_LOCATION[42]=/updates/dkms -BUILT_MODULE_NAME[43]=ttusb_dec -BUILT_MODULE_LOCATION[43]=./v4l -DEST_MODULE_LOCATION[43]=/updates/dkms -BUILT_MODULE_NAME[44]=adv7180 -BUILT_MODULE_LOCATION[44]=./v4l -DEST_MODULE_LOCATION[44]=/updates/dkms -BUILT_MODULE_NAME[45]=tea5767 -BUILT_MODULE_LOCATION[45]=./v4l -DEST_MODULE_LOCATION[45]=/updates/dkms -BUILT_MODULE_NAME[46]=rc-real-audio-220-32-keys -BUILT_MODULE_LOCATION[46]=./v4l -DEST_MODULE_LOCATION[46]=/updates/dkms -BUILT_MODULE_NAME[47]=noon010pc30 -BUILT_MODULE_LOCATION[47]=./v4l -DEST_MODULE_LOCATION[47]=/updates/dkms -BUILT_MODULE_NAME[48]=rc-msi-digivox-iii -BUILT_MODULE_LOCATION[48]=./v4l -DEST_MODULE_LOCATION[48]=/updates/dkms -BUILT_MODULE_NAME[49]=rc-tbs-nec -BUILT_MODULE_LOCATION[49]=./v4l -DEST_MODULE_LOCATION[49]=/updates/dkms -BUILT_MODULE_NAME[50]=bttv -BUILT_MODULE_LOCATION[50]=./v4l -DEST_MODULE_LOCATION[50]=/updates/dkms -BUILT_MODULE_NAME[51]=rc-pixelview-002t -BUILT_MODULE_LOCATION[51]=./v4l -DEST_MODULE_LOCATION[51]=/updates/dkms -BUILT_MODULE_NAME[52]=videobuf-core -BUILT_MODULE_LOCATION[52]=./v4l -DEST_MODULE_LOCATION[52]=/updates/dkms -BUILT_MODULE_NAME[53]=rc-avermedia-rm-ks -BUILT_MODULE_LOCATION[53]=./v4l -DEST_MODULE_LOCATION[53]=/updates/dkms -BUILT_MODULE_NAME[54]=rc-behold -BUILT_MODULE_LOCATION[54]=./v4l -DEST_MODULE_LOCATION[54]=/updates/dkms -BUILT_MODULE_NAME[55]=gspca_spca1528 -BUILT_MODULE_LOCATION[55]=./v4l -DEST_MODULE_LOCATION[55]=/updates/dkms -BUILT_MODULE_NAME[56]=rc-loopback -BUILT_MODULE_LOCATION[56]=./v4l -DEST_MODULE_LOCATION[56]=/updates/dkms -BUILT_MODULE_NAME[57]=rc-tt-1500 -BUILT_MODULE_LOCATION[57]=./v4l -DEST_MODULE_LOCATION[57]=/updates/dkms -BUILT_MODULE_NAME[58]=wm8739 -BUILT_MODULE_LOCATION[58]=./v4l -DEST_MODULE_LOCATION[58]=/updates/dkms -BUILT_MODULE_NAME[59]=mantis_core -BUILT_MODULE_LOCATION[59]=./v4l -DEST_MODULE_LOCATION[59]=/updates/dkms -BUILT_MODULE_NAME[60]=stv0288 -BUILT_MODULE_LOCATION[60]=./v4l -DEST_MODULE_LOCATION[60]=/updates/dkms -BUILT_MODULE_NAME[61]=ir-rc6-decoder -BUILT_MODULE_LOCATION[61]=./v4l -DEST_MODULE_LOCATION[61]=/updates/dkms -BUILT_MODULE_NAME[62]=pms -BUILT_MODULE_LOCATION[62]=./v4l -DEST_MODULE_LOCATION[62]=/updates/dkms -BUILT_MODULE_NAME[63]=mt20xx -BUILT_MODULE_LOCATION[63]=./v4l -DEST_MODULE_LOCATION[63]=/updates/dkms -BUILT_MODULE_NAME[64]=rc-asus-pc39 -BUILT_MODULE_LOCATION[64]=./v4l -DEST_MODULE_LOCATION[64]=/updates/dkms -BUILT_MODULE_NAME[65]=hdpvr -BUILT_MODULE_LOCATION[65]=./v4l -DEST_MODULE_LOCATION[65]=/updates/dkms -BUILT_MODULE_NAME[66]=dvb_dummy_fe -BUILT_MODULE_LOCATION[66]=./v4l -DEST_MODULE_LOCATION[66]=/updates/dkms -BUILT_MODULE_NAME[67]=mantis -BUILT_MODULE_LOCATION[67]=./v4l -DEST_MODULE_LOCATION[67]=/updates/dkms -BUILT_MODULE_NAME[68]=bcm3510 -BUILT_MODULE_LOCATION[68]=./v4l -DEST_MODULE_LOCATION[68]=/updates/dkms -BUILT_MODULE_NAME[69]=gspca_spca561 -BUILT_MODULE_LOCATION[69]=./v4l -DEST_MODULE_LOCATION[69]=/updates/dkms -BUILT_MODULE_NAME[70]=rc-kworld-plus-tv-analog -BUILT_MODULE_LOCATION[70]=./v4l -DEST_MODULE_LOCATION[70]=/updates/dkms -BUILT_MODULE_NAME[71]=tda827x -BUILT_MODULE_LOCATION[71]=./v4l -DEST_MODULE_LOCATION[71]=/updates/dkms -BUILT_MODULE_NAME[72]=videobuf-dvb -BUILT_MODULE_LOCATION[72]=./v4l -DEST_MODULE_LOCATION[72]=/updates/dkms -BUILT_MODULE_NAME[73]=stv6110x -BUILT_MODULE_LOCATION[73]=./v4l -DEST_MODULE_LOCATION[73]=/updates/dkms -BUILT_MODULE_NAME[74]=dvb-usb-umt-010 -BUILT_MODULE_LOCATION[74]=./v4l -DEST_MODULE_LOCATION[74]=/updates/dkms -BUILT_MODULE_NAME[75]=w9966 -BUILT_MODULE_LOCATION[75]=./v4l -DEST_MODULE_LOCATION[75]=/updates/dkms -BUILT_MODULE_NAME[76]=stv0367 -BUILT_MODULE_LOCATION[76]=./v4l -DEST_MODULE_LOCATION[76]=/updates/dkms -BUILT_MODULE_NAME[77]=saa717x -BUILT_MODULE_LOCATION[77]=./v4l -DEST_MODULE_LOCATION[77]=/updates/dkms -BUILT_MODULE_NAME[78]=saa7146_vv -BUILT_MODULE_LOCATION[78]=./v4l -DEST_MODULE_LOCATION[78]=/updates/dkms -BUILT_MODULE_NAME[79]=xc5000 -BUILT_MODULE_LOCATION[79]=./v4l -DEST_MODULE_LOCATION[79]=/updates/dkms -BUILT_MODULE_NAME[80]=tea5761 -BUILT_MODULE_LOCATION[80]=./v4l -DEST_MODULE_LOCATION[80]=/updates/dkms -BUILT_MODULE_NAME[81]=rc-videomate-tv-pvr -BUILT_MODULE_LOCATION[81]=./v4l -DEST_MODULE_LOCATION[81]=/updates/dkms -BUILT_MODULE_NAME[82]=ds3000 -BUILT_MODULE_LOCATION[82]=./v4l -DEST_MODULE_LOCATION[82]=/updates/dkms -BUILT_MODULE_NAME[83]=rc-flyvideo -BUILT_MODULE_LOCATION[83]=./v4l -DEST_MODULE_LOCATION[83]=/updates/dkms -BUILT_MODULE_NAME[84]=zl10353 -BUILT_MODULE_LOCATION[84]=./v4l -DEST_MODULE_LOCATION[84]=/updates/dkms -BUILT_MODULE_NAME[85]=adv7170 -BUILT_MODULE_LOCATION[85]=./v4l -DEST_MODULE_LOCATION[85]=/updates/dkms -BUILT_MODULE_NAME[86]=uvcvideo -BUILT_MODULE_LOCATION[86]=./v4l -DEST_MODULE_LOCATION[86]=/updates/dkms -BUILT_MODULE_NAME[87]=meye -BUILT_MODULE_LOCATION[87]=./v4l -DEST_MODULE_LOCATION[87]=/updates/dkms -BUILT_MODULE_NAME[88]=adv7343 -BUILT_MODULE_LOCATION[88]=./v4l -DEST_MODULE_LOCATION[88]=/updates/dkms -BUILT_MODULE_NAME[89]=tcm825x -BUILT_MODULE_LOCATION[89]=./v4l -DEST_MODULE_LOCATION[89]=/updates/dkms -BUILT_MODULE_NAME[90]=stb6100 -BUILT_MODULE_LOCATION[90]=./v4l -DEST_MODULE_LOCATION[90]=/updates/dkms -BUILT_MODULE_NAME[91]=mxb -BUILT_MODULE_LOCATION[91]=./v4l -DEST_MODULE_LOCATION[91]=/updates/dkms -BUILT_MODULE_NAME[92]=rc-winfast -BUILT_MODULE_LOCATION[92]=./v4l -DEST_MODULE_LOCATION[92]=/updates/dkms -BUILT_MODULE_NAME[93]=gspca_vc032x -BUILT_MODULE_LOCATION[93]=./v4l -DEST_MODULE_LOCATION[93]=/updates/dkms -BUILT_MODULE_NAME[94]=cx88-dvb -BUILT_MODULE_LOCATION[94]=./v4l -DEST_MODULE_LOCATION[94]=/updates/dkms -BUILT_MODULE_NAME[95]=gspca_sq930x -BUILT_MODULE_LOCATION[95]=./v4l -DEST_MODULE_LOCATION[95]=/updates/dkms -BUILT_MODULE_NAME[96]=rc-imon-pad -BUILT_MODULE_LOCATION[96]=./v4l -DEST_MODULE_LOCATION[96]=/updates/dkms -BUILT_MODULE_NAME[97]=rc-pv951 -BUILT_MODULE_LOCATION[97]=./v4l -DEST_MODULE_LOCATION[97]=/updates/dkms -BUILT_MODULE_NAME[98]=em28xx -BUILT_MODULE_LOCATION[98]=./v4l -DEST_MODULE_LOCATION[98]=/updates/dkms -BUILT_MODULE_NAME[99]=gspca_benq -BUILT_MODULE_LOCATION[99]=./v4l -DEST_MODULE_LOCATION[99]=/updates/dkms -BUILT_MODULE_NAME[100]=gspca_spca505 -BUILT_MODULE_LOCATION[100]=./v4l -DEST_MODULE_LOCATION[100]=/updates/dkms -BUILT_MODULE_NAME[101]=radio-miropcm20 -BUILT_MODULE_LOCATION[101]=./v4l -DEST_MODULE_LOCATION[101]=/updates/dkms -BUILT_MODULE_NAME[102]=rc-evga-indtube -BUILT_MODULE_LOCATION[102]=./v4l -DEST_MODULE_LOCATION[102]=/updates/dkms -BUILT_MODULE_NAME[103]=tda18218 -BUILT_MODULE_LOCATION[103]=./v4l -DEST_MODULE_LOCATION[103]=/updates/dkms -BUILT_MODULE_NAME[104]=dvb-usb-ce6230 -BUILT_MODULE_LOCATION[104]=./v4l -DEST_MODULE_LOCATION[104]=/updates/dkms -BUILT_MODULE_NAME[105]=tveeprom -BUILT_MODULE_LOCATION[105]=./v4l -DEST_MODULE_LOCATION[105]=/updates/dkms -BUILT_MODULE_NAME[106]=cpia2 -BUILT_MODULE_LOCATION[106]=./v4l -DEST_MODULE_LOCATION[106]=/updates/dkms -BUILT_MODULE_NAME[107]=radio-usb-si470x -BUILT_MODULE_LOCATION[107]=./v4l -DEST_MODULE_LOCATION[107]=/updates/dkms -BUILT_MODULE_NAME[108]=gspca_stv06xx -BUILT_MODULE_LOCATION[108]=./v4l -DEST_MODULE_LOCATION[108]=/updates/dkms -BUILT_MODULE_NAME[109]=cx24113 -BUILT_MODULE_LOCATION[109]=./v4l -DEST_MODULE_LOCATION[109]=/updates/dkms -BUILT_MODULE_NAME[110]=dsbr100 -BUILT_MODULE_LOCATION[110]=./v4l -DEST_MODULE_LOCATION[110]=/updates/dkms -BUILT_MODULE_NAME[111]=gspca_stk014 -BUILT_MODULE_LOCATION[111]=./v4l -DEST_MODULE_LOCATION[111]=/updates/dkms -BUILT_MODULE_NAME[112]=pvrusb2 -BUILT_MODULE_LOCATION[112]=./v4l -DEST_MODULE_LOCATION[112]=/updates/dkms -BUILT_MODULE_NAME[113]=snd-tea575x-tuner -BUILT_MODULE_LOCATION[113]=./v4l -DEST_MODULE_LOCATION[113]=/updates/dkms -BUILT_MODULE_NAME[114]=poseidon -BUILT_MODULE_LOCATION[114]=./v4l -DEST_MODULE_LOCATION[114]=/updates/dkms -BUILT_MODULE_NAME[115]=dvb-usb-dibusb-mb -BUILT_MODULE_LOCATION[115]=./v4l -DEST_MODULE_LOCATION[115]=/updates/dkms -BUILT_MODULE_NAME[116]=saa7127 -BUILT_MODULE_LOCATION[116]=./v4l -DEST_MODULE_LOCATION[116]=/updates/dkms -BUILT_MODULE_NAME[117]=radio-sf16fmi -BUILT_MODULE_LOCATION[117]=./v4l -DEST_MODULE_LOCATION[117]=/updates/dkms -BUILT_MODULE_NAME[118]=cx231xx-alsa -BUILT_MODULE_LOCATION[118]=./v4l -DEST_MODULE_LOCATION[118]=/updates/dkms -BUILT_MODULE_NAME[119]=b2c2-flexcop -BUILT_MODULE_LOCATION[119]=./v4l -DEST_MODULE_LOCATION[119]=/updates/dkms -BUILT_MODULE_NAME[120]=gspca_sn9c20x -BUILT_MODULE_LOCATION[120]=./v4l -DEST_MODULE_LOCATION[120]=/updates/dkms -BUILT_MODULE_NAME[121]=tda7432 -BUILT_MODULE_LOCATION[121]=./v4l -DEST_MODULE_LOCATION[121]=/updates/dkms -BUILT_MODULE_NAME[122]=rc-digitalnow-tinytwin -BUILT_MODULE_LOCATION[122]=./v4l -DEST_MODULE_LOCATION[122]=/updates/dkms -BUILT_MODULE_NAME[123]=tda8261 -BUILT_MODULE_LOCATION[123]=./v4l -DEST_MODULE_LOCATION[123]=/updates/dkms -BUILT_MODULE_NAME[124]=rc-avermedia-a16d -BUILT_MODULE_LOCATION[124]=./v4l -DEST_MODULE_LOCATION[124]=/updates/dkms -BUILT_MODULE_NAME[125]=gspca_ov534_9 -BUILT_MODULE_LOCATION[125]=./v4l -DEST_MODULE_LOCATION[125]=/updates/dkms -BUILT_MODULE_NAME[126]=rc-manli -BUILT_MODULE_LOCATION[126]=./v4l -DEST_MODULE_LOCATION[126]=/updates/dkms -BUILT_MODULE_NAME[127]=sp8870 -BUILT_MODULE_LOCATION[127]=./v4l -DEST_MODULE_LOCATION[127]=/updates/dkms -BUILT_MODULE_NAME[128]=rc-pixelview-new -BUILT_MODULE_LOCATION[128]=./v4l -DEST_MODULE_LOCATION[128]=/updates/dkms -BUILT_MODULE_NAME[129]=videocodec -BUILT_MODULE_LOCATION[129]=./v4l -DEST_MODULE_LOCATION[129]=/updates/dkms -BUILT_MODULE_NAME[130]=rc-digittrade -BUILT_MODULE_LOCATION[130]=./v4l -DEST_MODULE_LOCATION[130]=/updates/dkms -BUILT_MODULE_NAME[131]=gspca_gl860 -BUILT_MODULE_LOCATION[131]=./v4l -DEST_MODULE_LOCATION[131]=/updates/dkms -BUILT_MODULE_NAME[132]=dvb-usb-technisat-usb2 -BUILT_MODULE_LOCATION[132]=./v4l -DEST_MODULE_LOCATION[132]=/updates/dkms -BUILT_MODULE_NAME[133]=winbond-cir -BUILT_MODULE_LOCATION[133]=./v4l -DEST_MODULE_LOCATION[133]=/updates/dkms -BUILT_MODULE_NAME[134]=rc-encore-enltv -BUILT_MODULE_LOCATION[134]=./v4l -DEST_MODULE_LOCATION[134]=/updates/dkms -BUILT_MODULE_NAME[135]=gspca_main -BUILT_MODULE_LOCATION[135]=./v4l -DEST_MODULE_LOCATION[135]=/updates/dkms -BUILT_MODULE_NAME[136]=rc-adstech-dvb-t-pci -BUILT_MODULE_LOCATION[136]=./v4l -DEST_MODULE_LOCATION[136]=/updates/dkms -BUILT_MODULE_NAME[137]=stb6000 -BUILT_MODULE_LOCATION[137]=./v4l -DEST_MODULE_LOCATION[137]=/updates/dkms -BUILT_MODULE_NAME[138]=rc-pinnacle-color -BUILT_MODULE_LOCATION[138]=./v4l -DEST_MODULE_LOCATION[138]=/updates/dkms -BUILT_MODULE_NAME[139]=gspca_sonixj -BUILT_MODULE_LOCATION[139]=./v4l -DEST_MODULE_LOCATION[139]=/updates/dkms -BUILT_MODULE_NAME[140]=radio-mr800 -BUILT_MODULE_LOCATION[140]=./v4l -DEST_MODULE_LOCATION[140]=/updates/dkms -BUILT_MODULE_NAME[141]=dvb-usb-vp702x -BUILT_MODULE_LOCATION[141]=./v4l -DEST_MODULE_LOCATION[141]=/updates/dkms -BUILT_MODULE_NAME[142]=zr36016 -BUILT_MODULE_LOCATION[142]=./v4l -DEST_MODULE_LOCATION[142]=/updates/dkms -BUILT_MODULE_NAME[143]=rc-rc6-mce -BUILT_MODULE_LOCATION[143]=./v4l -DEST_MODULE_LOCATION[143]=/updates/dkms -BUILT_MODULE_NAME[144]=rc-npgtech -BUILT_MODULE_LOCATION[144]=./v4l -DEST_MODULE_LOCATION[144]=/updates/dkms -BUILT_MODULE_NAME[145]=drx397xD -BUILT_MODULE_LOCATION[145]=./v4l -DEST_MODULE_LOCATION[145]=/updates/dkms -BUILT_MODULE_NAME[146]=cs53l32a -BUILT_MODULE_LOCATION[146]=./v4l -DEST_MODULE_LOCATION[146]=/updates/dkms -BUILT_MODULE_NAME[147]=dvb-usb-af9015 -BUILT_MODULE_LOCATION[147]=./v4l -DEST_MODULE_LOCATION[147]=/updates/dkms -BUILT_MODULE_NAME[148]=s921 -BUILT_MODULE_LOCATION[148]=./v4l -DEST_MODULE_LOCATION[148]=/updates/dkms -BUILT_MODULE_NAME[149]=mt2131 -BUILT_MODULE_LOCATION[149]=./v4l -DEST_MODULE_LOCATION[149]=/updates/dkms -BUILT_MODULE_NAME[150]=rc-dib0700-rc5 -BUILT_MODULE_LOCATION[150]=./v4l -DEST_MODULE_LOCATION[150]=/updates/dkms -BUILT_MODULE_NAME[151]=dvb-usb-cxusb -BUILT_MODULE_LOCATION[151]=./v4l -DEST_MODULE_LOCATION[151]=/updates/dkms -BUILT_MODULE_NAME[152]=imon -BUILT_MODULE_LOCATION[152]=./v4l -DEST_MODULE_LOCATION[152]=/updates/dkms -BUILT_MODULE_NAME[153]=ves1820 -BUILT_MODULE_LOCATION[153]=./v4l -DEST_MODULE_LOCATION[153]=/updates/dkms -BUILT_MODULE_NAME[154]=dvb-usb-vp7045 -BUILT_MODULE_LOCATION[154]=./v4l -DEST_MODULE_LOCATION[154]=/updates/dkms -BUILT_MODULE_NAME[155]=gspca_sn9c2028 -BUILT_MODULE_LOCATION[155]=./v4l -DEST_MODULE_LOCATION[155]=/updates/dkms -BUILT_MODULE_NAME[156]=ves1x93 -BUILT_MODULE_LOCATION[156]=./v4l -DEST_MODULE_LOCATION[156]=/updates/dkms -BUILT_MODULE_NAME[157]=ths7303 -BUILT_MODULE_LOCATION[157]=./v4l -DEST_MODULE_LOCATION[157]=/updates/dkms -BUILT_MODULE_NAME[158]=rc-dntv-live-dvb-t -BUILT_MODULE_LOCATION[158]=./v4l -DEST_MODULE_LOCATION[158]=/updates/dkms -BUILT_MODULE_NAME[159]=rc-leadtek-y04g0051 -BUILT_MODULE_LOCATION[159]=./v4l -DEST_MODULE_LOCATION[159]=/updates/dkms -BUILT_MODULE_NAME[160]=lnbp21 -BUILT_MODULE_LOCATION[160]=./v4l -DEST_MODULE_LOCATION[160]=/updates/dkms -BUILT_MODULE_NAME[161]=rc-lme2510 -BUILT_MODULE_LOCATION[161]=./v4l -DEST_MODULE_LOCATION[161]=/updates/dkms -BUILT_MODULE_NAME[162]=radio-zoltrix -BUILT_MODULE_LOCATION[162]=./v4l -DEST_MODULE_LOCATION[162]=/updates/dkms -BUILT_MODULE_NAME[163]=rc-kworld-315u -BUILT_MODULE_LOCATION[163]=./v4l -DEST_MODULE_LOCATION[163]=/updates/dkms -BUILT_MODULE_NAME[164]=stkwebcam -BUILT_MODULE_LOCATION[164]=./v4l -DEST_MODULE_LOCATION[164]=/updates/dkms -BUILT_MODULE_NAME[165]=rc-trekstor -BUILT_MODULE_LOCATION[165]=./v4l -DEST_MODULE_LOCATION[165]=/updates/dkms -BUILT_MODULE_NAME[166]=qt1010 -BUILT_MODULE_LOCATION[166]=./v4l -DEST_MODULE_LOCATION[166]=/updates/dkms -BUILT_MODULE_NAME[167]=or51211 -BUILT_MODULE_LOCATION[167]=./v4l -DEST_MODULE_LOCATION[167]=/updates/dkms -BUILT_MODULE_NAME[168]=rc-pinnacle-grey -BUILT_MODULE_LOCATION[168]=./v4l -DEST_MODULE_LOCATION[168]=/updates/dkms -BUILT_MODULE_NAME[169]=cx18 -BUILT_MODULE_LOCATION[169]=./v4l -DEST_MODULE_LOCATION[169]=/updates/dkms -BUILT_MODULE_NAME[170]=saa7146 -BUILT_MODULE_LOCATION[170]=./v4l -DEST_MODULE_LOCATION[170]=/updates/dkms -BUILT_MODULE_NAME[171]=dvb-usb-gl861 -BUILT_MODULE_LOCATION[171]=./v4l -DEST_MODULE_LOCATION[171]=/updates/dkms -BUILT_MODULE_NAME[172]=budget-patch -BUILT_MODULE_LOCATION[172]=./v4l -DEST_MODULE_LOCATION[172]=/updates/dkms -BUILT_MODULE_NAME[173]=radio-rtrack2 -BUILT_MODULE_LOCATION[173]=./v4l -DEST_MODULE_LOCATION[173]=/updates/dkms -BUILT_MODULE_NAME[174]=saa7134-empress -BUILT_MODULE_LOCATION[174]=./v4l -DEST_MODULE_LOCATION[174]=/updates/dkms -BUILT_MODULE_NAME[175]=ec100 -BUILT_MODULE_LOCATION[175]=./v4l -DEST_MODULE_LOCATION[175]=/updates/dkms -BUILT_MODULE_NAME[176]=dib0090 -BUILT_MODULE_LOCATION[176]=./v4l -DEST_MODULE_LOCATION[176]=/updates/dkms -BUILT_MODULE_NAME[177]=cx25840 -BUILT_MODULE_LOCATION[177]=./v4l -DEST_MODULE_LOCATION[177]=/updates/dkms -BUILT_MODULE_NAME[178]=upd64083 -BUILT_MODULE_LOCATION[178]=./v4l -DEST_MODULE_LOCATION[178]=/updates/dkms -BUILT_MODULE_NAME[179]=stv0299 -BUILT_MODULE_LOCATION[179]=./v4l -DEST_MODULE_LOCATION[179]=/updates/dkms -BUILT_MODULE_NAME[180]=dib3000mb -BUILT_MODULE_LOCATION[180]=./v4l -DEST_MODULE_LOCATION[180]=/updates/dkms -BUILT_MODULE_NAME[181]=gspca_stv0680 -BUILT_MODULE_LOCATION[181]=./v4l -DEST_MODULE_LOCATION[181]=/updates/dkms -BUILT_MODULE_NAME[182]=budget-av -BUILT_MODULE_LOCATION[182]=./v4l -DEST_MODULE_LOCATION[182]=/updates/dkms -BUILT_MODULE_NAME[183]=dst_ca -BUILT_MODULE_LOCATION[183]=./v4l -DEST_MODULE_LOCATION[183]=/updates/dkms -BUILT_MODULE_NAME[184]=tvaudio -BUILT_MODULE_LOCATION[184]=./v4l -DEST_MODULE_LOCATION[184]=/updates/dkms -BUILT_MODULE_NAME[185]=rc-avermedia-cardbus -BUILT_MODULE_LOCATION[185]=./v4l -DEST_MODULE_LOCATION[185]=/updates/dkms -BUILT_MODULE_NAME[186]=stv0900 -BUILT_MODULE_LOCATION[186]=./v4l -DEST_MODULE_LOCATION[186]=/updates/dkms -BUILT_MODULE_NAME[187]=videobuf-dma-sg -BUILT_MODULE_LOCATION[187]=./v4l -DEST_MODULE_LOCATION[187]=/updates/dkms -BUILT_MODULE_NAME[188]=rc-gadmei-rm008z -BUILT_MODULE_LOCATION[188]=./v4l -DEST_MODULE_LOCATION[188]=/updates/dkms -BUILT_MODULE_NAME[189]=s2255drv -BUILT_MODULE_LOCATION[189]=./v4l -DEST_MODULE_LOCATION[189]=/updates/dkms -BUILT_MODULE_NAME[190]=rc-pixelview -BUILT_MODULE_LOCATION[190]=./v4l -DEST_MODULE_LOCATION[190]=/updates/dkms -BUILT_MODULE_NAME[191]=videobuf2-core -BUILT_MODULE_LOCATION[191]=./v4l -DEST_MODULE_LOCATION[191]=/updates/dkms -BUILT_MODULE_NAME[192]=cx22702 -BUILT_MODULE_LOCATION[192]=./v4l -DEST_MODULE_LOCATION[192]=/updates/dkms -BUILT_MODULE_NAME[193]=saa7134 -BUILT_MODULE_LOCATION[193]=./v4l -DEST_MODULE_LOCATION[193]=/updates/dkms -BUILT_MODULE_NAME[194]=dvb-usb-af9005-remote -BUILT_MODULE_LOCATION[194]=./v4l -DEST_MODULE_LOCATION[194]=/updates/dkms -BUILT_MODULE_NAME[195]=dvb-usb-friio -BUILT_MODULE_LOCATION[195]=./v4l -DEST_MODULE_LOCATION[195]=/updates/dkms -BUILT_MODULE_NAME[196]=ttpci-eeprom -BUILT_MODULE_LOCATION[196]=./v4l -DEST_MODULE_LOCATION[196]=/updates/dkms -BUILT_MODULE_NAME[197]=rc-ati-tv-wonder-hd-600 -BUILT_MODULE_LOCATION[197]=./v4l -DEST_MODULE_LOCATION[197]=/updates/dkms -BUILT_MODULE_NAME[198]=tuner-types -BUILT_MODULE_LOCATION[198]=./v4l -DEST_MODULE_LOCATION[198]=/updates/dkms -BUILT_MODULE_NAME[199]=nuvoton-cir -BUILT_MODULE_LOCATION[199]=./v4l -DEST_MODULE_LOCATION[199]=/updates/dkms -BUILT_MODULE_NAME[200]=dib9000 -BUILT_MODULE_LOCATION[200]=./v4l -DEST_MODULE_LOCATION[200]=/updates/dkms -BUILT_MODULE_NAME[201]=snd-bt87x -BUILT_MODULE_LOCATION[201]=./v4l -DEST_MODULE_LOCATION[201]=/updates/dkms -BUILT_MODULE_NAME[202]=rc-anysee -BUILT_MODULE_LOCATION[202]=./v4l -DEST_MODULE_LOCATION[202]=/updates/dkms -BUILT_MODULE_NAME[203]=sp887x -BUILT_MODULE_LOCATION[203]=./v4l -DEST_MODULE_LOCATION[203]=/updates/dkms -BUILT_MODULE_NAME[204]=gspca_ov534 -BUILT_MODULE_LOCATION[204]=./v4l -DEST_MODULE_LOCATION[204]=/updates/dkms -BUILT_MODULE_NAME[205]=radio-maxiradio -BUILT_MODULE_LOCATION[205]=./v4l -DEST_MODULE_LOCATION[205]=/updates/dkms -BUILT_MODULE_NAME[206]=dvb-usb-dibusb-common -BUILT_MODULE_LOCATION[206]=./v4l -DEST_MODULE_LOCATION[206]=/updates/dkms -BUILT_MODULE_NAME[207]=msp3400 -BUILT_MODULE_LOCATION[207]=./v4l -DEST_MODULE_LOCATION[207]=/updates/dkms -BUILT_MODULE_NAME[208]=dvb-usb-digitv -BUILT_MODULE_LOCATION[208]=./v4l -DEST_MODULE_LOCATION[208]=/updates/dkms -BUILT_MODULE_NAME[209]=rc-streamzap -BUILT_MODULE_LOCATION[209]=./v4l -DEST_MODULE_LOCATION[209]=/updates/dkms -BUILT_MODULE_NAME[210]=bw-qcam -BUILT_MODULE_LOCATION[210]=./v4l -DEST_MODULE_LOCATION[210]=/updates/dkms -BUILT_MODULE_NAME[211]=videobuf2-vmalloc -BUILT_MODULE_LOCATION[211]=./v4l -DEST_MODULE_LOCATION[211]=/updates/dkms -BUILT_MODULE_NAME[212]=radio-sf16fmr2 -BUILT_MODULE_LOCATION[212]=./v4l -DEST_MODULE_LOCATION[212]=/updates/dkms -BUILT_MODULE_NAME[213]=tuner -BUILT_MODULE_LOCATION[213]=./v4l -DEST_MODULE_LOCATION[213]=/updates/dkms -BUILT_MODULE_NAME[214]=radio-tea5764 -BUILT_MODULE_LOCATION[214]=./v4l -DEST_MODULE_LOCATION[214]=/updates/dkms -BUILT_MODULE_NAME[215]=dibx000_common -BUILT_MODULE_LOCATION[215]=./v4l -DEST_MODULE_LOCATION[215]=/updates/dkms -BUILT_MODULE_NAME[216]=mb86a20s -BUILT_MODULE_LOCATION[216]=./v4l -DEST_MODULE_LOCATION[216]=/updates/dkms -BUILT_MODULE_NAME[217]=cx24116 -BUILT_MODULE_LOCATION[217]=./v4l -DEST_MODULE_LOCATION[217]=/updates/dkms -BUILT_MODULE_NAME[218]=mxl5007t -BUILT_MODULE_LOCATION[218]=./v4l -DEST_MODULE_LOCATION[218]=/updates/dkms -BUILT_MODULE_NAME[219]=stv090x -BUILT_MODULE_LOCATION[219]=./v4l -DEST_MODULE_LOCATION[219]=/updates/dkms -BUILT_MODULE_NAME[220]=rc-flydvb -BUILT_MODULE_LOCATION[220]=./v4l -DEST_MODULE_LOCATION[220]=/updates/dkms -BUILT_MODULE_NAME[221]=hopper -BUILT_MODULE_LOCATION[221]=./v4l -DEST_MODULE_LOCATION[221]=/updates/dkms -BUILT_MODULE_NAME[222]=mt312 -BUILT_MODULE_LOCATION[222]=./v4l -DEST_MODULE_LOCATION[222]=/updates/dkms -BUILT_MODULE_NAME[223]=isl6421 -BUILT_MODULE_LOCATION[223]=./v4l -DEST_MODULE_LOCATION[223]=/updates/dkms -BUILT_MODULE_NAME[224]=gspca_sq905c -BUILT_MODULE_LOCATION[224]=./v4l -DEST_MODULE_LOCATION[224]=/updates/dkms -BUILT_MODULE_NAME[225]=lgs8gl5 -BUILT_MODULE_LOCATION[225]=./v4l -DEST_MODULE_LOCATION[225]=/updates/dkms -BUILT_MODULE_NAME[226]=gspca_spca508 -BUILT_MODULE_LOCATION[226]=./v4l -DEST_MODULE_LOCATION[226]=/updates/dkms -BUILT_MODULE_NAME[227]=tuner-simple -BUILT_MODULE_LOCATION[227]=./v4l -DEST_MODULE_LOCATION[227]=/updates/dkms -BUILT_MODULE_NAME[228]=gspca_etoms -BUILT_MODULE_LOCATION[228]=./v4l -DEST_MODULE_LOCATION[228]=/updates/dkms -BUILT_MODULE_NAME[229]=v4l2-common -BUILT_MODULE_LOCATION[229]=./v4l -DEST_MODULE_LOCATION[229]=/updates/dkms -BUILT_MODULE_NAME[230]=adv7175 -BUILT_MODULE_LOCATION[230]=./v4l -DEST_MODULE_LOCATION[230]=/updates/dkms -BUILT_MODULE_NAME[231]=cx231xx-dvb -BUILT_MODULE_LOCATION[231]=./v4l -DEST_MODULE_LOCATION[231]=/updates/dkms -BUILT_MODULE_NAME[232]=ir-nec-decoder -BUILT_MODULE_LOCATION[232]=./v4l -DEST_MODULE_LOCATION[232]=/updates/dkms -BUILT_MODULE_NAME[233]=rc-tevii-nec -BUILT_MODULE_LOCATION[233]=./v4l -DEST_MODULE_LOCATION[233]=/updates/dkms -BUILT_MODULE_NAME[234]=ivtvfb -BUILT_MODULE_LOCATION[234]=./v4l -DEST_MODULE_LOCATION[234]=/updates/dkms -BUILT_MODULE_NAME[235]=lgs8gxx -BUILT_MODULE_LOCATION[235]=./v4l -DEST_MODULE_LOCATION[235]=/updates/dkms -BUILT_MODULE_NAME[236]=rc-dm1105-nec -BUILT_MODULE_LOCATION[236]=./v4l -DEST_MODULE_LOCATION[236]=/updates/dkms -BUILT_MODULE_NAME[237]=max2165 -BUILT_MODULE_LOCATION[237]=./v4l -DEST_MODULE_LOCATION[237]=/updates/dkms -BUILT_MODULE_NAME[238]=gspca_tv8532 -BUILT_MODULE_LOCATION[238]=./v4l -DEST_MODULE_LOCATION[238]=/updates/dkms -BUILT_MODULE_NAME[239]=cx24123 -BUILT_MODULE_LOCATION[239]=./v4l -DEST_MODULE_LOCATION[239]=/updates/dkms -BUILT_MODULE_NAME[240]=dst -BUILT_MODULE_LOCATION[240]=./v4l -DEST_MODULE_LOCATION[240]=/updates/dkms -BUILT_MODULE_NAME[241]=tda10021 -BUILT_MODULE_LOCATION[241]=./v4l -DEST_MODULE_LOCATION[241]=/updates/dkms -BUILT_MODULE_NAME[242]=tua6100 -BUILT_MODULE_LOCATION[242]=./v4l -DEST_MODULE_LOCATION[242]=/updates/dkms -BUILT_MODULE_NAME[243]=dvb-bt8xx -BUILT_MODULE_LOCATION[243]=./v4l -DEST_MODULE_LOCATION[243]=/updates/dkms -BUILT_MODULE_NAME[244]=si21xx -BUILT_MODULE_LOCATION[244]=./v4l -DEST_MODULE_LOCATION[244]=/updates/dkms -BUILT_MODULE_NAME[245]=rc-msi-digivox-ii -BUILT_MODULE_LOCATION[245]=./v4l -DEST_MODULE_LOCATION[245]=/updates/dkms -BUILT_MODULE_NAME[246]=nxt200x -BUILT_MODULE_LOCATION[246]=./v4l -DEST_MODULE_LOCATION[246]=/updates/dkms -BUILT_MODULE_NAME[247]=cx18-alsa -BUILT_MODULE_LOCATION[247]=./v4l -DEST_MODULE_LOCATION[247]=/updates/dkms -BUILT_MODULE_NAME[248]=saa7185 -BUILT_MODULE_LOCATION[248]=./v4l -DEST_MODULE_LOCATION[248]=/updates/dkms -BUILT_MODULE_NAME[249]=mb86a16 -BUILT_MODULE_LOCATION[249]=./v4l -DEST_MODULE_LOCATION[249]=/updates/dkms -BUILT_MODULE_NAME[250]=tea6420 -BUILT_MODULE_LOCATION[250]=./v4l -DEST_MODULE_LOCATION[250]=/updates/dkms -BUILT_MODULE_NAME[251]=gspca_mr97310a -BUILT_MODULE_LOCATION[251]=./v4l -DEST_MODULE_LOCATION[251]=/updates/dkms -BUILT_MODULE_NAME[252]=m52790 -BUILT_MODULE_LOCATION[252]=./v4l -DEST_MODULE_LOCATION[252]=/updates/dkms -BUILT_MODULE_NAME[253]=gspca_spca506 -BUILT_MODULE_LOCATION[253]=./v4l -DEST_MODULE_LOCATION[253]=/updates/dkms -BUILT_MODULE_NAME[254]=dvb-usb-nova-t-usb2 -BUILT_MODULE_LOCATION[254]=./v4l -DEST_MODULE_LOCATION[254]=/updates/dkms -BUILT_MODULE_NAME[255]=budget -BUILT_MODULE_LOCATION[255]=./v4l -DEST_MODULE_LOCATION[255]=/updates/dkms -BUILT_MODULE_NAME[256]=gspca_sq905 -BUILT_MODULE_LOCATION[256]=./v4l -DEST_MODULE_LOCATION[256]=/updates/dkms -BUILT_MODULE_NAME[257]=dib0070 -BUILT_MODULE_LOCATION[257]=./v4l -DEST_MODULE_LOCATION[257]=/updates/dkms -BUILT_MODULE_NAME[258]=cx88-blackbird -BUILT_MODULE_LOCATION[258]=./v4l -DEST_MODULE_LOCATION[258]=/updates/dkms -BUILT_MODULE_NAME[259]=gspca_mars -BUILT_MODULE_LOCATION[259]=./v4l -DEST_MODULE_LOCATION[259]=/updates/dkms -BUILT_MODULE_NAME[260]=rc-terratec-cinergy-xs -BUILT_MODULE_LOCATION[260]=./v4l -DEST_MODULE_LOCATION[260]=/updates/dkms -BUILT_MODULE_NAME[261]=gspca_xirlink_cit -BUILT_MODULE_LOCATION[261]=./v4l -DEST_MODULE_LOCATION[261]=/updates/dkms -BUILT_MODULE_NAME[262]=cx8800 -BUILT_MODULE_LOCATION[262]=./v4l -DEST_MODULE_LOCATION[262]=/updates/dkms -BUILT_MODULE_NAME[263]=rc-norwood -BUILT_MODULE_LOCATION[263]=./v4l -DEST_MODULE_LOCATION[263]=/updates/dkms -BUILT_MODULE_NAME[264]=gspca_spca501 -BUILT_MODULE_LOCATION[264]=./v4l -DEST_MODULE_LOCATION[264]=/updates/dkms -BUILT_MODULE_NAME[265]=gspca_vicam -BUILT_MODULE_LOCATION[265]=./v4l -DEST_MODULE_LOCATION[265]=/updates/dkms -BUILT_MODULE_NAME[266]=gspca_jeilinj -BUILT_MODULE_LOCATION[266]=./v4l -DEST_MODULE_LOCATION[266]=/updates/dkms -BUILT_MODULE_NAME[267]=cx23885 -BUILT_MODULE_LOCATION[267]=./v4l -DEST_MODULE_LOCATION[267]=/updates/dkms -BUILT_MODULE_NAME[268]=mxl5005s -BUILT_MODULE_LOCATION[268]=./v4l -DEST_MODULE_LOCATION[268]=/updates/dkms -BUILT_MODULE_NAME[269]=sn9c102 -BUILT_MODULE_LOCATION[269]=./v4l -DEST_MODULE_LOCATION[269]=/updates/dkms -BUILT_MODULE_NAME[270]=dvb-usb-dtv5100 -BUILT_MODULE_LOCATION[270]=./v4l -DEST_MODULE_LOCATION[270]=/updates/dkms -BUILT_MODULE_NAME[271]=isl6405 -BUILT_MODULE_LOCATION[271]=./v4l -DEST_MODULE_LOCATION[271]=/updates/dkms -BUILT_MODULE_NAME[272]=itd1000 -BUILT_MODULE_LOCATION[272]=./v4l -DEST_MODULE_LOCATION[272]=/updates/dkms -BUILT_MODULE_NAME[273]=au8522 -BUILT_MODULE_LOCATION[273]=./v4l -DEST_MODULE_LOCATION[273]=/updates/dkms -BUILT_MODULE_NAME[274]=tda9887 -BUILT_MODULE_LOCATION[274]=./v4l -DEST_MODULE_LOCATION[274]=/updates/dkms -BUILT_MODULE_NAME[275]=dvb-usb-gp8psk -BUILT_MODULE_LOCATION[275]=./v4l -DEST_MODULE_LOCATION[275]=/updates/dkms -BUILT_MODULE_NAME[276]=dvb-usb-anysee -BUILT_MODULE_LOCATION[276]=./v4l -DEST_MODULE_LOCATION[276]=/updates/dkms -BUILT_MODULE_NAME[277]=nxt6000 -BUILT_MODULE_LOCATION[277]=./v4l -DEST_MODULE_LOCATION[277]=/updates/dkms -BUILT_MODULE_NAME[278]=saa7115 -BUILT_MODULE_LOCATION[278]=./v4l -DEST_MODULE_LOCATION[278]=/updates/dkms -BUILT_MODULE_NAME[279]=au0828 -BUILT_MODULE_LOCATION[279]=./v4l -DEST_MODULE_LOCATION[279]=/updates/dkms -BUILT_MODULE_NAME[280]=rc-avermedia -BUILT_MODULE_LOCATION[280]=./v4l -DEST_MODULE_LOCATION[280]=/updates/dkms -BUILT_MODULE_NAME[281]=hexium_gemini -BUILT_MODULE_LOCATION[281]=./v4l -DEST_MODULE_LOCATION[281]=/updates/dkms -BUILT_MODULE_NAME[282]=rc-eztv -BUILT_MODULE_LOCATION[282]=./v4l -DEST_MODULE_LOCATION[282]=/updates/dkms -BUILT_MODULE_NAME[283]=pwc -BUILT_MODULE_LOCATION[283]=./v4l -DEST_MODULE_LOCATION[283]=/updates/dkms -BUILT_MODULE_NAME[284]=rc-encore-enltv-fm53 -BUILT_MODULE_LOCATION[284]=./v4l -DEST_MODULE_LOCATION[284]=/updates/dkms -BUILT_MODULE_NAME[285]=budget-core -BUILT_MODULE_LOCATION[285]=./v4l -DEST_MODULE_LOCATION[285]=/updates/dkms -BUILT_MODULE_NAME[286]=gspca_conex -BUILT_MODULE_LOCATION[286]=./v4l -DEST_MODULE_LOCATION[286]=/updates/dkms -BUILT_MODULE_NAME[287]=gspca_pac7311 -BUILT_MODULE_LOCATION[287]=./v4l -DEST_MODULE_LOCATION[287]=/updates/dkms -BUILT_MODULE_NAME[288]=dvb-ttusb-budget -BUILT_MODULE_LOCATION[288]=./v4l -DEST_MODULE_LOCATION[288]=/updates/dkms -BUILT_MODULE_NAME[289]=tda8083 -BUILT_MODULE_LOCATION[289]=./v4l -DEST_MODULE_LOCATION[289]=/updates/dkms -BUILT_MODULE_NAME[290]=gspca_pac207 -BUILT_MODULE_LOCATION[290]=./v4l -DEST_MODULE_LOCATION[290]=/updates/dkms -BUILT_MODULE_NAME[291]=ix2505v -BUILT_MODULE_LOCATION[291]=./v4l -DEST_MODULE_LOCATION[291]=/updates/dkms -BUILT_MODULE_NAME[292]=zr36060 -BUILT_MODULE_LOCATION[292]=./v4l -DEST_MODULE_LOCATION[292]=/updates/dkms -BUILT_MODULE_NAME[293]=rc-technisat-usb2 -BUILT_MODULE_LOCATION[293]=./v4l -DEST_MODULE_LOCATION[293]=/updates/dkms -BUILT_MODULE_NAME[294]=firedtv -BUILT_MODULE_LOCATION[294]=./v4l -DEST_MODULE_LOCATION[294]=/updates/dkms -BUILT_MODULE_NAME[295]=v4l2-int-device -BUILT_MODULE_LOCATION[295]=./v4l -DEST_MODULE_LOCATION[295]=/updates/dkms -BUILT_MODULE_NAME[296]=gspca_finepix -BUILT_MODULE_LOCATION[296]=./v4l -DEST_MODULE_LOCATION[296]=/updates/dkms -BUILT_MODULE_NAME[297]=dvb-usb-au6610 -BUILT_MODULE_LOCATION[297]=./v4l -DEST_MODULE_LOCATION[297]=/updates/dkms -BUILT_MODULE_NAME[298]=rc-nec-terratec-cinergy-xs -BUILT_MODULE_LOCATION[298]=./v4l -DEST_MODULE_LOCATION[298]=/updates/dkms -BUILT_MODULE_NAME[299]=gspca_t613 -BUILT_MODULE_LOCATION[299]=./v4l -DEST_MODULE_LOCATION[299]=/updates/dkms -BUILT_MODULE_NAME[300]=radio-trust -BUILT_MODULE_LOCATION[300]=./v4l -DEST_MODULE_LOCATION[300]=/updates/dkms -BUILT_MODULE_NAME[301]=saa7191 -BUILT_MODULE_LOCATION[301]=./v4l -DEST_MODULE_LOCATION[301]=/updates/dkms -BUILT_MODULE_NAME[302]=vp27smpx -BUILT_MODULE_LOCATION[302]=./v4l -DEST_MODULE_LOCATION[302]=/updates/dkms -BUILT_MODULE_NAME[303]=rc-budget-ci-old -BUILT_MODULE_LOCATION[303]=./v4l -DEST_MODULE_LOCATION[303]=/updates/dkms -BUILT_MODULE_NAME[304]=s5h1411 -BUILT_MODULE_LOCATION[304]=./v4l -DEST_MODULE_LOCATION[304]=/updates/dkms -BUILT_MODULE_NAME[305]=gspca_zc3xx -BUILT_MODULE_LOCATION[305]=./v4l -DEST_MODULE_LOCATION[305]=/updates/dkms -BUILT_MODULE_NAME[306]=dvb-usb -BUILT_MODULE_LOCATION[306]=./v4l -DEST_MODULE_LOCATION[306]=/updates/dkms -BUILT_MODULE_NAME[307]=dvb-usb-dibusb-mc -BUILT_MODULE_LOCATION[307]=./v4l -DEST_MODULE_LOCATION[307]=/updates/dkms -BUILT_MODULE_NAME[308]=dvb-pll -BUILT_MODULE_LOCATION[308]=./v4l -DEST_MODULE_LOCATION[308]=/updates/dkms -BUILT_MODULE_NAME[309]=ir-kbd-i2c -BUILT_MODULE_LOCATION[309]=./v4l -DEST_MODULE_LOCATION[309]=/updates/dkms -BUILT_MODULE_NAME[310]=sr030pc30 -BUILT_MODULE_LOCATION[310]=./v4l -DEST_MODULE_LOCATION[310]=/updates/dkms -BUILT_MODULE_NAME[311]=tda826x -BUILT_MODULE_LOCATION[311]=./v4l -DEST_MODULE_LOCATION[311]=/updates/dkms -BUILT_MODULE_NAME[312]=tea6415c -BUILT_MODULE_LOCATION[312]=./v4l -DEST_MODULE_LOCATION[312]=/updates/dkms -BUILT_MODULE_NAME[313]=zr36050 -BUILT_MODULE_LOCATION[313]=./v4l -DEST_MODULE_LOCATION[313]=/updates/dkms -BUILT_MODULE_NAME[314]=videobuf2-dma-contig -BUILT_MODULE_LOCATION[314]=./v4l -DEST_MODULE_LOCATION[314]=/updates/dkms -BUILT_MODULE_NAME[315]=rc-kaiomy -BUILT_MODULE_LOCATION[315]=./v4l -DEST_MODULE_LOCATION[315]=/updates/dkms -BUILT_MODULE_NAME[316]=ov7670 -BUILT_MODULE_LOCATION[316]=./v4l -DEST_MODULE_LOCATION[316]=/updates/dkms -BUILT_MODULE_NAME[317]=rc-videomate-s350 -BUILT_MODULE_LOCATION[317]=./v4l -DEST_MODULE_LOCATION[317]=/updates/dkms -BUILT_MODULE_NAME[318]=lgdt3305 -BUILT_MODULE_LOCATION[318]=./v4l -DEST_MODULE_LOCATION[318]=/updates/dkms -BUILT_MODULE_NAME[319]=rc-azurewave-ad-tu700 -BUILT_MODULE_LOCATION[319]=./v4l -DEST_MODULE_LOCATION[319]=/updates/dkms -BUILT_MODULE_NAME[320]=l64781 -BUILT_MODULE_LOCATION[320]=./v4l -DEST_MODULE_LOCATION[320]=/updates/dkms -BUILT_MODULE_NAME[321]=rc-terratec-slim-2 -BUILT_MODULE_LOCATION[321]=./v4l -DEST_MODULE_LOCATION[321]=/updates/dkms -BUILT_MODULE_NAME[322]=tvp5150 -BUILT_MODULE_LOCATION[322]=./v4l -DEST_MODULE_LOCATION[322]=/updates/dkms -BUILT_MODULE_NAME[323]=rc-hauppauge -BUILT_MODULE_LOCATION[323]=./v4l -DEST_MODULE_LOCATION[323]=/updates/dkms -BUILT_MODULE_NAME[324]=gspca_ov519 -BUILT_MODULE_LOCATION[324]=./v4l -DEST_MODULE_LOCATION[324]=/updates/dkms -BUILT_MODULE_NAME[325]=streamzap -BUILT_MODULE_LOCATION[325]=./v4l -DEST_MODULE_LOCATION[325]=/updates/dkms -BUILT_MODULE_NAME[326]=tda665x -BUILT_MODULE_LOCATION[326]=./v4l -DEST_MODULE_LOCATION[326]=/updates/dkms -BUILT_MODULE_NAME[327]=cx88xx -BUILT_MODULE_LOCATION[327]=./v4l -DEST_MODULE_LOCATION[327]=/updates/dkms -BUILT_MODULE_NAME[328]=radio-typhoon -BUILT_MODULE_LOCATION[328]=./v4l -DEST_MODULE_LOCATION[328]=/updates/dkms -BUILT_MODULE_NAME[329]=mt2060 -BUILT_MODULE_LOCATION[329]=./v4l -DEST_MODULE_LOCATION[329]=/updates/dkms -BUILT_MODULE_NAME[330]=tda8290 -BUILT_MODULE_LOCATION[330]=./v4l -DEST_MODULE_LOCATION[330]=/updates/dkms -BUILT_MODULE_NAME[331]=rc-msi-tvanywhere-plus -BUILT_MODULE_LOCATION[331]=./v4l -DEST_MODULE_LOCATION[331]=/updates/dkms -BUILT_MODULE_NAME[332]=tda10086 -BUILT_MODULE_LOCATION[332]=./v4l -DEST_MODULE_LOCATION[332]=/updates/dkms -BUILT_MODULE_NAME[333]=stv6110 -BUILT_MODULE_LOCATION[333]=./v4l -DEST_MODULE_LOCATION[333]=/updates/dkms -BUILT_MODULE_NAME[334]=dib8000 -BUILT_MODULE_LOCATION[334]=./v4l -DEST_MODULE_LOCATION[334]=/updates/dkms -BUILT_MODULE_NAME[335]=saa7134-alsa -BUILT_MODULE_LOCATION[335]=./v4l -DEST_MODULE_LOCATION[335]=/updates/dkms -BUILT_MODULE_NAME[336]=upd64031a -BUILT_MODULE_LOCATION[336]=./v4l -DEST_MODULE_LOCATION[336]=/updates/dkms -BUILT_MODULE_NAME[337]=ivtv -BUILT_MODULE_LOCATION[337]=./v4l -DEST_MODULE_LOCATION[337]=/updates/dkms -BUILT_MODULE_NAME[338]=videodev -BUILT_MODULE_LOCATION[338]=./v4l -DEST_MODULE_LOCATION[338]=/updates/dkms -BUILT_MODULE_NAME[339]=radio-cadet -BUILT_MODULE_LOCATION[339]=./v4l -DEST_MODULE_LOCATION[339]=/updates/dkms -BUILT_MODULE_NAME[340]=tda1004x -BUILT_MODULE_LOCATION[340]=./v4l -DEST_MODULE_LOCATION[340]=/updates/dkms -BUILT_MODULE_NAME[341]=gspca_sonixb -BUILT_MODULE_LOCATION[341]=./v4l -DEST_MODULE_LOCATION[341]=/updates/dkms -BUILT_MODULE_NAME[342]=earth-pt1 -BUILT_MODULE_LOCATION[342]=./v4l -DEST_MODULE_LOCATION[342]=/updates/dkms -BUILT_MODULE_NAME[343]=zl10036 -BUILT_MODULE_LOCATION[343]=./v4l -DEST_MODULE_LOCATION[343]=/updates/dkms -BUILT_MODULE_NAME[344]=cx88-vp3054-i2c -BUILT_MODULE_LOCATION[344]=./v4l -DEST_MODULE_LOCATION[344]=/updates/dkms -BUILT_MODULE_NAME[345]=cx2341x -BUILT_MODULE_LOCATION[345]=./v4l -DEST_MODULE_LOCATION[345]=/updates/dkms -BUILT_MODULE_NAME[346]=vpx3220 -BUILT_MODULE_LOCATION[346]=./v4l -DEST_MODULE_LOCATION[346]=/updates/dkms -BUILT_MODULE_NAME[347]=em28xx-dvb -BUILT_MODULE_LOCATION[347]=./v4l -DEST_MODULE_LOCATION[347]=/updates/dkms -BUILT_MODULE_NAME[348]=rc-avermedia-dvbt -BUILT_MODULE_LOCATION[348]=./v4l -DEST_MODULE_LOCATION[348]=/updates/dkms -BUILT_MODULE_NAME[349]=bt856 -BUILT_MODULE_LOCATION[349]=./v4l -DEST_MODULE_LOCATION[349]=/updates/dkms -BUILT_MODULE_NAME[350]=tef6862 -BUILT_MODULE_LOCATION[350]=./v4l -DEST_MODULE_LOCATION[350]=/updates/dkms -BUILT_MODULE_NAME[351]=videobuf2-memops -BUILT_MODULE_LOCATION[351]=./v4l -DEST_MODULE_LOCATION[351]=/updates/dkms -BUILT_MODULE_NAME[352]=gspca_konica -BUILT_MODULE_LOCATION[352]=./v4l -DEST_MODULE_LOCATION[352]=/updates/dkms -BUILT_MODULE_NAME[353]=rc-videomate-m1f -BUILT_MODULE_LOCATION[353]=./v4l -DEST_MODULE_LOCATION[353]=/updates/dkms -BUILT_MODULE_NAME[354]=radio-si4713 -BUILT_MODULE_LOCATION[354]=./v4l -DEST_MODULE_LOCATION[354]=/updates/dkms -BUILT_MODULE_NAME[355]=dvb-usb-a800 -BUILT_MODULE_LOCATION[355]=./v4l -DEST_MODULE_LOCATION[355]=/updates/dkms -BUILT_MODULE_NAME[356]=s5h1432 -BUILT_MODULE_LOCATION[356]=./v4l -DEST_MODULE_LOCATION[356]=/updates/dkms -BUILT_MODULE_NAME[357]=ir-sony-decoder -BUILT_MODULE_LOCATION[357]=./v4l -DEST_MODULE_LOCATION[357]=/updates/dkms -BUILT_MODULE_NAME[358]=rc-msi-tvanywhere -BUILT_MODULE_LOCATION[358]=./v4l -DEST_MODULE_LOCATION[358]=/updates/dkms -BUILT_MODULE_NAME[359]=dm1105 -BUILT_MODULE_LOCATION[359]=./v4l -DEST_MODULE_LOCATION[359]=/updates/dkms -BUILT_MODULE_NAME[360]=videobuf-dma-contig -BUILT_MODULE_LOCATION[360]=./v4l -DEST_MODULE_LOCATION[360]=/updates/dkms -BUILT_MODULE_NAME[361]=mt352 -BUILT_MODULE_LOCATION[361]=./v4l -DEST_MODULE_LOCATION[361]=/updates/dkms -BUILT_MODULE_NAME[362]=ir-rc5-sz-decoder -BUILT_MODULE_LOCATION[362]=./v4l -DEST_MODULE_LOCATION[362]=/updates/dkms -BUILT_MODULE_NAME[363]=rc-fusionhdtv-mce -BUILT_MODULE_LOCATION[363]=./v4l -DEST_MODULE_LOCATION[363]=/updates/dkms -BUILT_MODULE_NAME[364]=rc-dib0700-nec -BUILT_MODULE_LOCATION[364]=./v4l -DEST_MODULE_LOCATION[364]=/updates/dkms -BUILT_MODULE_NAME[365]=cafe_ccic -BUILT_MODULE_LOCATION[365]=./v4l -DEST_MODULE_LOCATION[365]=/updates/dkms -BUILT_MODULE_NAME[366]=dvb-usb-dtt200u -BUILT_MODULE_LOCATION[366]=./v4l -DEST_MODULE_LOCATION[366]=/updates/dkms -BUILT_MODULE_NAME[367]=mceusb -BUILT_MODULE_LOCATION[367]=./v4l -DEST_MODULE_LOCATION[367]=/updates/dkms -BUILT_MODULE_NAME[368]=smsusb -BUILT_MODULE_LOCATION[368]=./v4l -DEST_MODULE_LOCATION[368]=/updates/dkms -BUILT_MODULE_NAME[369]=bt878 -BUILT_MODULE_LOCATION[369]=./v4l -DEST_MODULE_LOCATION[369]=/updates/dkms -BUILT_MODULE_NAME[370]=pluto2 -BUILT_MODULE_LOCATION[370]=./v4l -DEST_MODULE_LOCATION[370]=/updates/dkms -BUILT_MODULE_NAME[371]=b2c2-flexcop-usb -BUILT_MODULE_LOCATION[371]=./v4l -DEST_MODULE_LOCATION[371]=/updates/dkms -BUILT_MODULE_NAME[372]=mt2266 -BUILT_MODULE_LOCATION[372]=./v4l -DEST_MODULE_LOCATION[372]=/updates/dkms -BUILT_MODULE_NAME[373]=dvb-usb-af9005 -BUILT_MODULE_LOCATION[373]=./v4l -DEST_MODULE_LOCATION[373]=/updates/dkms -BUILT_MODULE_NAME[374]=dvb-core -BUILT_MODULE_LOCATION[374]=./v4l -DEST_MODULE_LOCATION[374]=/updates/dkms -BUILT_MODULE_NAME[375]=rc-total-media-in-hand -BUILT_MODULE_LOCATION[375]=./v4l -DEST_MODULE_LOCATION[375]=/updates/dkms -BUILT_MODULE_NAME[376]=rc-cinergy -BUILT_MODULE_LOCATION[376]=./v4l -DEST_MODULE_LOCATION[376]=/updates/dkms -BUILT_MODULE_NAME[377]=lgdt330x -BUILT_MODULE_LOCATION[377]=./v4l -DEST_MODULE_LOCATION[377]=/updates/dkms -BUILT_MODULE_NAME[378]=dvb-usb-dib0700 -BUILT_MODULE_LOCATION[378]=./v4l -DEST_MODULE_LOCATION[378]=/updates/dkms -BUILT_MODULE_NAME[379]=rc-pctv-sedna -BUILT_MODULE_LOCATION[379]=./v4l -DEST_MODULE_LOCATION[379]=/updates/dkms -BUILT_MODULE_NAME[380]=zr36067 -BUILT_MODULE_LOCATION[380]=./v4l -DEST_MODULE_LOCATION[380]=/updates/dkms -BUILT_MODULE_NAME[381]=af9013 -BUILT_MODULE_LOCATION[381]=./v4l -DEST_MODULE_LOCATION[381]=/updates/dkms -BUILT_MODULE_NAME[382]=usbvision -BUILT_MODULE_LOCATION[382]=./v4l -DEST_MODULE_LOCATION[382]=/updates/dkms -BUILT_MODULE_NAME[383]=dvb-usb-ttusb2 -BUILT_MODULE_LOCATION[383]=./v4l -DEST_MODULE_LOCATION[383]=/updates/dkms -BUILT_MODULE_NAME[384]=zr364xx -BUILT_MODULE_LOCATION[384]=./v4l -DEST_MODULE_LOCATION[384]=/updates/dkms -BUILT_MODULE_NAME[385]=tda10048 -BUILT_MODULE_LOCATION[385]=./v4l -DEST_MODULE_LOCATION[385]=/updates/dkms -BUILT_MODULE_NAME[386]=tda10023 -BUILT_MODULE_LOCATION[386]=./v4l -DEST_MODULE_LOCATION[386]=/updates/dkms -BUILT_MODULE_NAME[387]=tda9840 -BUILT_MODULE_LOCATION[387]=./v4l -DEST_MODULE_LOCATION[387]=/updates/dkms -BUILT_MODULE_NAME[388]=bt819 -BUILT_MODULE_LOCATION[388]=./v4l -DEST_MODULE_LOCATION[388]=/updates/dkms -BUILT_MODULE_NAME[389]=smsmdtv -BUILT_MODULE_LOCATION[389]=./v4l -DEST_MODULE_LOCATION[389]=/updates/dkms -BUILT_MODULE_NAME[390]=dib3000mc -BUILT_MODULE_LOCATION[390]=./v4l -DEST_MODULE_LOCATION[390]=/updates/dkms -BUILT_MODULE_NAME[391]=mc44s803 -BUILT_MODULE_LOCATION[391]=./v4l -DEST_MODULE_LOCATION[391]=/updates/dkms -BUILT_MODULE_NAME[392]=rc-em-terratec -BUILT_MODULE_LOCATION[392]=./v4l -DEST_MODULE_LOCATION[392]=/updates/dkms -BUILT_MODULE_NAME[393]=btcx-risc -BUILT_MODULE_LOCATION[393]=./v4l -DEST_MODULE_LOCATION[393]=/updates/dkms -BUILT_MODULE_NAME[394]=dvb-ttpci -BUILT_MODULE_LOCATION[394]=./v4l -DEST_MODULE_LOCATION[394]=/updates/dkms -BUILT_MODULE_NAME[395]=tvp514x -BUILT_MODULE_LOCATION[395]=./v4l -DEST_MODULE_LOCATION[395]=/updates/dkms -BUILT_MODULE_NAME[396]=dib7000p -BUILT_MODULE_LOCATION[396]=./v4l -DEST_MODULE_LOCATION[396]=/updates/dkms -BUILT_MODULE_NAME[397]=rc-avertv-303 -BUILT_MODULE_LOCATION[397]=./v4l -DEST_MODULE_LOCATION[397]=/updates/dkms -BUILT_MODULE_NAME[398]=rc-lirc -BUILT_MODULE_LOCATION[398]=./v4l -DEST_MODULE_LOCATION[398]=/updates/dkms -BUILT_MODULE_NAME[399]=rc-iodata-bctv7e -BUILT_MODULE_LOCATION[399]=./v4l -DEST_MODULE_LOCATION[399]=/updates/dkms -BUILT_MODULE_NAME[400]=s5h1409 -BUILT_MODULE_LOCATION[400]=./v4l -DEST_MODULE_LOCATION[400]=/updates/dkms -BUILT_MODULE_NAME[401]=stb0899 -BUILT_MODULE_LOCATION[401]=./v4l -DEST_MODULE_LOCATION[401]=/updates/dkms -BUILT_MODULE_NAME[402]=smsdvb -BUILT_MODULE_LOCATION[402]=./v4l -DEST_MODULE_LOCATION[402]=/updates/dkms -BUILT_MODULE_NAME[403]=tuner-xc2028 -BUILT_MODULE_LOCATION[403]=./v4l -DEST_MODULE_LOCATION[403]=/updates/dkms -BUILT_MODULE_NAME[404]=hexium_orion -BUILT_MODULE_LOCATION[404]=./v4l -DEST_MODULE_LOCATION[404]=/updates/dkms -BUILT_MODULE_NAME[405]=saa6752hs -BUILT_MODULE_LOCATION[405]=./v4l -DEST_MODULE_LOCATION[405]=/updates/dkms -BUILT_MODULE_NAME[406]=ene_ir -BUILT_MODULE_LOCATION[406]=./v4l -DEST_MODULE_LOCATION[406]=/updates/dkms -BUILT_MODULE_NAME[407]=dvb-usb-cinergyT2 -BUILT_MODULE_LOCATION[407]=./v4l -DEST_MODULE_LOCATION[407]=/updates/dkms -BUILT_MODULE_NAME[408]=si4713-i2c -BUILT_MODULE_LOCATION[408]=./v4l -DEST_MODULE_LOCATION[408]=/updates/dkms -BUILT_MODULE_NAME[409]=gspca_pac7302 -BUILT_MODULE_LOCATION[409]=./v4l -DEST_MODULE_LOCATION[409]=/updates/dkms -BUILT_MODULE_NAME[410]=ks0127 -BUILT_MODULE_LOCATION[410]=./v4l -DEST_MODULE_LOCATION[410]=/updates/dkms -BUILT_MODULE_NAME[411]=rc-encore-enltv2 -BUILT_MODULE_LOCATION[411]=./v4l -DEST_MODULE_LOCATION[411]=/updates/dkms -BUILT_MODULE_NAME[412]=gspca_m5602 -BUILT_MODULE_LOCATION[412]=./v4l -DEST_MODULE_LOCATION[412]=/updates/dkms -BUILT_MODULE_NAME[413]=cx88-alsa -BUILT_MODULE_LOCATION[413]=./v4l -DEST_MODULE_LOCATION[413]=/updates/dkms -BUILT_MODULE_NAME[414]=dib7000m -BUILT_MODULE_LOCATION[414]=./v4l -DEST_MODULE_LOCATION[414]=/updates/dkms -BUILT_MODULE_NAME[415]=et61x251 -BUILT_MODULE_LOCATION[415]=./v4l -DEST_MODULE_LOCATION[415]=/updates/dkms -BUILT_MODULE_NAME[416]=rc-terratec-slim -BUILT_MODULE_LOCATION[416]=./v4l -DEST_MODULE_LOCATION[416]=/updates/dkms -BUILT_MODULE_NAME[417]=rc-imon-mce -BUILT_MODULE_LOCATION[417]=./v4l -DEST_MODULE_LOCATION[417]=/updates/dkms -BUILT_MODULE_NAME[418]=rc-purpletv -BUILT_MODULE_LOCATION[418]=./v4l -DEST_MODULE_LOCATION[418]=/updates/dkms -BUILT_MODULE_NAME[419]=cx8802 -BUILT_MODULE_LOCATION[419]=./v4l -DEST_MODULE_LOCATION[419]=/updates/dkms -BUILT_MODULE_NAME[420]=rc-nebula -BUILT_MODULE_LOCATION[420]=./v4l -DEST_MODULE_LOCATION[420]=/updates/dkms -BUILT_MODULE_NAME[421]=budget-ci -BUILT_MODULE_LOCATION[421]=./v4l -DEST_MODULE_LOCATION[421]=/updates/dkms -BUILT_MODULE_NAME[422]=saa7110 -BUILT_MODULE_LOCATION[422]=./v4l -DEST_MODULE_LOCATION[422]=/updates/dkms -BUILT_MODULE_NAME[423]=rc-twinhan1027 -BUILT_MODULE_LOCATION[423]=./v4l -DEST_MODULE_LOCATION[423]=/updates/dkms -BUILT_MODULE_NAME[424]=gspca_cpia1 -BUILT_MODULE_LOCATION[424]=./v4l -DEST_MODULE_LOCATION[424]=/updates/dkms -BUILT_MODULE_NAME[425]=atbm8830 -BUILT_MODULE_LOCATION[425]=./v4l -DEST_MODULE_LOCATION[425]=/updates/dkms -BUILT_MODULE_NAME[426]=tlv320aic23b -BUILT_MODULE_LOCATION[426]=./v4l -DEST_MODULE_LOCATION[426]=/updates/dkms -BUILT_MODULE_NAME[427]=dvb-usb-lmedm04 -BUILT_MODULE_LOCATION[427]=./v4l -DEST_MODULE_LOCATION[427]=/updates/dkms -BUILT_MODULE_NAME[428]=or51132 -BUILT_MODULE_LOCATION[428]=./v4l -DEST_MODULE_LOCATION[428]=/updates/dkms -BUILT_MODULE_NAME[429]=radio-aztech -BUILT_MODULE_LOCATION[429]=./v4l -DEST_MODULE_LOCATION[429]=/updates/dkms -BUILT_MODULE_NAME[430]=cs5345 -BUILT_MODULE_LOCATION[430]=./v4l -DEST_MODULE_LOCATION[430]=/updates/dkms -BUILT_MODULE_NAME[431]=dvb-usb-ec168 -BUILT_MODULE_LOCATION[431]=./v4l -DEST_MODULE_LOCATION[431]=/updates/dkms -BUILT_MODULE_NAME[432]=rc-pixelview-mk12 -BUILT_MODULE_LOCATION[432]=./v4l -DEST_MODULE_LOCATION[432]=/updates/dkms -BUILT_MODULE_NAME[433]=gspca_spca500 -BUILT_MODULE_LOCATION[433]=./v4l -DEST_MODULE_LOCATION[433]=/updates/dkms -BUILT_MODULE_NAME[434]=rc-powercolor-real-angel -BUILT_MODULE_LOCATION[434]=./v4l -DEST_MODULE_LOCATION[434]=/updates/dkms -BUILT_MODULE_NAME[435]=mt9v011 -BUILT_MODULE_LOCATION[435]=./v4l -DEST_MODULE_LOCATION[435]=/updates/dkms -BUILT_MODULE_NAME[436]=ttusbdecfe -BUILT_MODULE_LOCATION[436]=./v4l -DEST_MODULE_LOCATION[436]=/updates/dkms -BUILT_MODULE_NAME[437]=rc-alink-dtu-m -BUILT_MODULE_LOCATION[437]=./v4l -DEST_MODULE_LOCATION[437]=/updates/dkms -BUILT_MODULE_NAME[438]=saa7134-dvb -BUILT_MODULE_LOCATION[438]=./v4l -DEST_MODULE_LOCATION[438]=/updates/dkms diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/INSTALL v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/INSTALL --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/INSTALL 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/INSTALL 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -Mauro Carvalho Chehab 2006 Apr 26 - -V4L/DVB building procedures are based at the use of Makefile rules. -Those rules are close to the ones at Linux Kernel, to allow an easier -usage. - -======================================================================= -Quick building procedure is: - make all -====================================================================== - -For those who may want more than just build all stuff there are some -other interesting parameters to make: - -====================== -Normal building rules: -all - build all modules - -clean - Cleans compiled files from the tree, - but keeping the latest - used configuration and kernel version - -distclean - Cleans compiled files from the tree, - latest used configuration and kernel - version. - -default - Continues building the latest module selection - This is the behavior when just typed: - make - -install - Installs all modules at kernel's default dir - for V4L/DVB. Requires root access. - -rminstall - cleans previous installations of V4L/DVB modules - -sound-install - installs the sound modules related to V4L/DVB - tree. - -====================== -Firmware rules: - -firmware - Create the firmware files that are enclosed at the - tree. - Notice: Only a very few firmwares are currently here - -firmware_install- Install firmware files under /lib/firmware - -======================= -Module selection rules: -(Those may require write access to kernel tree) - -allmodconfig - Called by make all. Selects all modules that are known - to compile against the kernel version used. - -stagingconfig - Select all modules, plus all staging modules. The - staging drivers are there because they may have - bad userspace API's, serious bugs and/or not fill - into Kernel required level of quality. So, be - careful with those drivers. - -xconfig - Generate a xconfig menu. Requires full - kernel source, since it depends on kernel's - qconf stript; - -gconfig - Generate a qt menu. Requires full - kernel source, since it depends on kernel's - gconf stript; - -config - Generate a text-mode menu. Requires full - kernel source, since it depends on kernel's - conf stript; - -menuconfig - Generate a ncurses menu. Requires full - kernel source, since it depends on kernel's - mconf and lxconfig stripts; - -release - Allows changing kernel version. - Typical usage is: - make release VER=2.6.12-18mdk - (to force compiling to 2.6.12-18mdk) - (This will work only if - /lib/modules/2.6.12-18mdk/build/ - points to that kernel version) - Or - make release DIR=~/linux-git - (to force using kernel at a specific dir) - To use current kernel version instead: - make release - -====================== -Module handling rules: -(require root access) - -insmod - inserts all modules from V4L/DVB tree - -rmmod - removes all modules from V4L/DVB tree - -reload - removes then reinserts all modules - -=================== -Tree merging rules: - -ivtv - enable merged ivtv build, using the latest ivtv sources - from ivtvdriver.org (requires subversion) - -cx88-ivtv - enable cx88-blackbird ivtv API emulation - -ivtv-update - update ivtv sources from ivtvdriver.org - -========================================== -Patch preparation and tree handling rules: -(used by developers) - -kernel-links - Generate links to V4L/DVB at kernel tree. - Requires write access to kernel tree. - -cardlist - Updates Documentation/video4linux/CARDLIST.* - -update - updates the tree from master repository - -commit - commits the change, asking for a commit msg - -push - sends outgoing stuff to master repository - -checkemacs - checks codingstyle and reports to emacs - using "make checkemacs" at emacs compile menu, - will report the lines with errors inside emacs. - -checkpatch - checks codingstyle and reports using the same - format as c. This way, c error parsers will - handle it. - -checkterse - checks codingstyle and reports using terse - syntax, used on several compilaton tools. - -mismatch - checks for linker section mismatch. In other words, - check if some driver has functions not properly - declared with __init/__exit, and similar tags. - It will also be more pedantic by dealing with - compilation warnings as if they are errors. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -config VIDEO_SAA7146 - tristate - depends on I2C && PCI - -config VIDEO_SAA7146_VV - tristate - depends on VIDEO_V4L2 - select VIDEOBUF_DMA_SG - select VIDEO_SAA7146 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -saa7146-objs := saa7146_i2c.o saa7146_core.o -saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o - -obj-y += tuners/ -obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o -obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,600 +0,0 @@ -/* - saa7146.o - driver for generic saa7146-based hardware - - Copyright (C) 1998-2003 Michael Hunold - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include - -LIST_HEAD(saa7146_devices); -DEFINE_MUTEX(saa7146_devices_lock); - -static int saa7146_num; - -unsigned int saa7146_debug; - -module_param(saa7146_debug, uint, 0644); -MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)"); - -#if 0 -static void dump_registers(struct saa7146_dev* dev) -{ - int i = 0; - - INFO((" @ %li jiffies:\n",jiffies)); - for(i = 0; i <= 0x148; i+=4) { - printk("0x%03x: 0x%08x\n",i,saa7146_read(dev,i)); - } -} -#endif - -/**************************************************************************** - * gpio and debi helper functions - ****************************************************************************/ - -void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data) -{ - u32 value = 0; - - BUG_ON(port > 3); - - value = saa7146_read(dev, GPIO_CTRL); - value &= ~(0xff << (8*port)); - value |= (data << (8*port)); - saa7146_write(dev, GPIO_CTRL, value); -} - -/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */ -static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev, - unsigned long us1, unsigned long us2) -{ - unsigned long timeout; - int err; - - /* wait for registers to be programmed */ - timeout = jiffies + usecs_to_jiffies(us1); - while (1) { - err = time_after(jiffies, timeout); - if (saa7146_read(dev, MC2) & 2) - break; - if (err) { - printk(KERN_ERR "%s: %s timed out while waiting for " - "registers getting programmed\n", - dev->name, __func__); - return -ETIMEDOUT; - } - msleep(1); - } - - /* wait for transfer to complete */ - timeout = jiffies + usecs_to_jiffies(us2); - while (1) { - err = time_after(jiffies, timeout); - if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) - break; - saa7146_read(dev, MC2); - if (err) { - DEB_S(("%s: %s timed out while waiting for transfer " - "completion\n", dev->name, __func__)); - return -ETIMEDOUT; - } - msleep(1); - } - - return 0; -} - -static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev, - unsigned long us1, unsigned long us2) -{ - unsigned long loops; - - /* wait for registers to be programmed */ - loops = us1; - while (1) { - if (saa7146_read(dev, MC2) & 2) - break; - if (!loops--) { - printk(KERN_ERR "%s: %s timed out while waiting for " - "registers getting programmed\n", - dev->name, __func__); - return -ETIMEDOUT; - } - udelay(1); - } - - /* wait for transfer to complete */ - loops = us2 / 5; - while (1) { - if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) - break; - saa7146_read(dev, MC2); - if (!loops--) { - DEB_S(("%s: %s timed out while waiting for transfer " - "completion\n", dev->name, __func__)); - return -ETIMEDOUT; - } - udelay(5); - } - - return 0; -} - -int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) -{ - if (nobusyloop) - return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000); - else - return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000); -} - -/**************************************************************************** - * general helper functions - ****************************************************************************/ - -/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c - make sure virt has been allocated with vmalloc_32(), otherwise the BUG() - may be triggered on highmem machines */ -static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) -{ - struct scatterlist *sglist; - struct page *pg; - int i; - - sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); - if (NULL == sglist) - return NULL; - sg_init_table(sglist, nr_pages); - for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { - pg = vmalloc_to_page(virt); - if (NULL == pg) - goto err; - BUG_ON(PageHighMem(pg)); - sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); - } - return sglist; - - err: - kfree(sglist); - return NULL; -} - -/********************************************************************************/ -/* common page table functions */ - -void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) -{ - int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; - void *mem = vmalloc_32(length); - int slen = 0; - - if (NULL == mem) - goto err_null; - - if (!(pt->slist = vmalloc_to_sg(mem, pages))) - goto err_free_mem; - - if (saa7146_pgtable_alloc(pci, pt)) - goto err_free_slist; - - pt->nents = pages; - slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE); - if (0 == slen) - goto err_free_pgtable; - - if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) - goto err_unmap_sg; - - return mem; - -err_unmap_sg: - pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); -err_free_pgtable: - saa7146_pgtable_free(pci, pt); -err_free_slist: - kfree(pt->slist); - pt->slist = NULL; -err_free_mem: - vfree(mem); -err_null: - return NULL; -} - -void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt) -{ - pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); - saa7146_pgtable_free(pci, pt); - kfree(pt->slist); - pt->slist = NULL; - vfree(mem); -} - -void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) -{ - if (NULL == pt->cpu) - return; - pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); - pt->cpu = NULL; -} - -int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) -{ - __le32 *cpu; - dma_addr_t dma_addr = 0; - - cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr); - if (NULL == cpu) { - return -ENOMEM; - } - pt->size = PAGE_SIZE; - pt->cpu = cpu; - pt->dma = dma_addr; - - return 0; -} - -int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, - struct scatterlist *list, int sglen ) -{ - __le32 *ptr, fill; - int nr_pages = 0; - int i,p; - - BUG_ON(0 == sglen); - BUG_ON(list->offset > PAGE_SIZE); - - /* if we have a user buffer, the first page may not be - aligned to a page boundary. */ - pt->offset = list->offset; - - ptr = pt->cpu; - for (i = 0; i < sglen; i++, list++) { -/* - printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset); -*/ - for (p = 0; p * 4096 < list->length; p++, ptr++) { - *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096); - nr_pages++; - } - } - - - /* safety; fill the page table up with the last valid page */ - fill = *(ptr-1); - for(i=nr_pages;i<1024;i++) { - *ptr++ = fill; - } - -/* - ptr = pt->cpu; - printk("offset: %d\n",pt->offset); - for(i=0;i<5;i++) { - printk("ptr1 %d: 0x%08x\n",i,ptr[i]); - } -*/ - return 0; -} - -/********************************************************************************/ -/* interrupt handler */ -static irqreturn_t interrupt_hw(int irq, void *dev_id) -{ - struct saa7146_dev *dev = dev_id; - u32 isr; - u32 ack_isr; - - /* read out the interrupt status register */ - ack_isr = isr = saa7146_read(dev, ISR); - - /* is this our interrupt? */ - if ( 0 == isr ) { - /* nope, some other device */ - return IRQ_NONE; - } - - if (dev->ext) { - if (dev->ext->irq_mask & isr) { - if (dev->ext->irq_func) - dev->ext->irq_func(dev, &isr); - isr &= ~dev->ext->irq_mask; - } - } - if (0 != (isr & (MASK_27))) { - DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); - if (dev->vv_data && dev->vv_callback) - dev->vv_callback(dev,isr); - isr &= ~MASK_27; - } - if (0 != (isr & (MASK_28))) { - if (dev->vv_data && dev->vv_callback) - dev->vv_callback(dev,isr); - isr &= ~MASK_28; - } - if (0 != (isr & (MASK_16|MASK_17))) { - SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); - /* only wake up if we expect something */ - if (0 != dev->i2c_op) { - dev->i2c_op = 0; - wake_up(&dev->i2c_wq); - } else { - u32 psr = saa7146_read(dev, PSR); - u32 ssr = saa7146_read(dev, SSR); - printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", - dev->name, isr, psr, ssr); - } - isr &= ~(MASK_16|MASK_17); - } - if( 0 != isr ) { - ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr)); - ERR(("disabling interrupt source(s)!\n")); - SAA7146_IER_DISABLE(dev,isr); - } - saa7146_write(dev, ISR, ack_isr); - return IRQ_HANDLED; -} - -/*********************************************************************************/ -/* configuration-functions */ - -static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent) -{ - struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data; - struct saa7146_extension *ext = pci_ext->ext; - struct saa7146_dev *dev; - int err = -ENOMEM; - - /* clear out mem for sure */ - dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL); - if (!dev) { - ERR(("out of memory.\n")); - goto out; - } - - DEB_EE(("pci:%p\n",pci)); - - err = pci_enable_device(pci); - if (err < 0) { - ERR(("pci_enable_device() failed.\n")); - goto err_free; - } - - /* enable bus-mastering */ - pci_set_master(pci); - - dev->pci = pci; - - /* get chip-revision; this is needed to enable bug-fixes */ - err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision); - if (err < 0) { - ERR(("pci_read_config_dword() failed.\n")); - goto err_disable; - } - dev->revision &= 0xf; - - /* remap the memory from virtual to physical address */ - - err = pci_request_region(pci, 0, "saa7146"); - if (err < 0) - goto err_disable; - - dev->mem = ioremap(pci_resource_start(pci, 0), - pci_resource_len(pci, 0)); - if (!dev->mem) { - ERR(("ioremap() failed.\n")); - err = -ENODEV; - goto err_release; - } - - /* we don't do a master reset here anymore, it screws up - some boards that don't have an i2c-eeprom for configuration - values */ -/* - saa7146_write(dev, MC1, MASK_31); -*/ - - /* disable all irqs */ - saa7146_write(dev, IER, 0); - - /* shut down all dma transfers and rps tasks */ - saa7146_write(dev, MC1, 0x30ff0000); - - /* clear out any rps-signals pending */ - saa7146_write(dev, MC2, 0xf8000000); - - /* request an interrupt for the saa7146 */ - err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED, - dev->name, dev); - if (err < 0) { - ERR(("request_irq() failed.\n")); - goto err_unmap; - } - - err = -ENOMEM; - - /* get memory for various stuff */ - dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, - &dev->d_rps0.dma_handle); - if (!dev->d_rps0.cpu_addr) - goto err_free_irq; - memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM); - - dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, - &dev->d_rps1.dma_handle); - if (!dev->d_rps1.cpu_addr) - goto err_free_rps0; - memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM); - - dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, - &dev->d_i2c.dma_handle); - if (!dev->d_i2c.cpu_addr) - goto err_free_rps1; - memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM); - - /* the rest + print status message */ - - /* create a nice device name */ - sprintf(dev->name, "saa7146 (%d)", saa7146_num); - - INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device)); - dev->ext = ext; - - mutex_init(&dev->v4l2_lock); - spin_lock_init(&dev->int_slock); - spin_lock_init(&dev->slock); - - mutex_init(&dev->i2c_lock); - - dev->module = THIS_MODULE; - init_waitqueue_head(&dev->i2c_wq); - - /* set some sane pci arbitrition values */ - saa7146_write(dev, PCI_BT_V1, 0x1c00101f); - - /* TODO: use the status code of the callback */ - - err = -ENODEV; - - if (ext->probe && ext->probe(dev)) { - DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); - goto err_free_i2c; - } - - if (ext->attach(dev, pci_ext)) { - DEB_D(("ext->attach() failed for %p. skipping device.\n",dev)); - goto err_free_i2c; - } - /* V4L extensions will set the pci drvdata to the v4l2_device in the - attach() above. So for those cards that do not use V4L we have to - set it explicitly. */ - pci_set_drvdata(pci, &dev->v4l2_dev); - - INIT_LIST_HEAD(&dev->item); - list_add_tail(&dev->item,&saa7146_devices); - saa7146_num++; - - err = 0; -out: - return err; - -err_free_i2c: - pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, - dev->d_i2c.dma_handle); -err_free_rps1: - pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, - dev->d_rps1.dma_handle); -err_free_rps0: - pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, - dev->d_rps0.dma_handle); -err_free_irq: - free_irq(pci->irq, (void *)dev); -err_unmap: - iounmap(dev->mem); -err_release: - pci_release_region(pci, 0); -err_disable: - pci_disable_device(pci); -err_free: - kfree(dev); - goto out; -} - -static void saa7146_remove_one(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); - struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev); - struct { - void *addr; - dma_addr_t dma; - } dev_map[] = { - { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle }, - { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle }, - { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle }, - { NULL, 0 } - }, *p; - - DEB_EE(("dev:%p\n",dev)); - - dev->ext->detach(dev); - /* Zero the PCI drvdata after use. */ - pci_set_drvdata(pdev, NULL); - - /* shut down all video dma transfers */ - saa7146_write(dev, MC1, 0x00ff0000); - - /* disable all irqs, release irq-routine */ - saa7146_write(dev, IER, 0); - - free_irq(pdev->irq, dev); - - for (p = dev_map; p->addr; p++) - pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma); - - iounmap(dev->mem); - pci_release_region(pdev, 0); - list_del(&dev->item); - pci_disable_device(pdev); - kfree(dev); - - saa7146_num--; -} - -/*********************************************************************************/ -/* extension handling functions */ - -int saa7146_register_extension(struct saa7146_extension* ext) -{ - DEB_EE(("ext:%p\n",ext)); - - ext->driver.name = ext->name; - ext->driver.id_table = ext->pci_tbl; - ext->driver.probe = saa7146_init_one; - ext->driver.remove = saa7146_remove_one; - - printk("saa7146: register extension '%s'.\n",ext->name); - return pci_register_driver(&ext->driver); -} - -int saa7146_unregister_extension(struct saa7146_extension* ext) -{ - DEB_EE(("ext:%p\n",ext)); - printk("saa7146: unregister extension '%s'.\n",ext->name); - pci_unregister_driver(&ext->driver); - return 0; -} - -EXPORT_SYMBOL_GPL(saa7146_register_extension); -EXPORT_SYMBOL_GPL(saa7146_unregister_extension); - -/* misc functions used by extension modules */ -EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc); -EXPORT_SYMBOL_GPL(saa7146_pgtable_free); -EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single); -EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable); -EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable); -EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); - -EXPORT_SYMBOL_GPL(saa7146_setgpio); - -EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); - -EXPORT_SYMBOL_GPL(saa7146_debug); -EXPORT_SYMBOL_GPL(saa7146_devices); -EXPORT_SYMBOL_GPL(saa7146_devices_lock); - -MODULE_AUTHOR("Michael Hunold "); -MODULE_DESCRIPTION("driver for generic saa7146-based hardware"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_fops.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_fops.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_fops.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_fops.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,551 +0,0 @@ -#include - -/****************************************************************************/ -/* resource management functions, shamelessly stolen from saa7134 driver */ - -int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - - if (fh->resources & bit) { - DEB_D(("already allocated! want: 0x%02x, cur:0x%02x\n",bit,vv->resources)); - /* have it already allocated */ - return 1; - } - - /* is it free? */ - if (vv->resources & bit) { - DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit)); - /* no, someone else uses it */ - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - vv->resources |= bit; - DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources)); - return 1; -} - -void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - - BUG_ON((fh->resources & bits) != bits); - - fh->resources &= ~bits; - vv->resources &= ~bits; - DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources)); -} - - -/********************************************************************************/ -/* common dma functions */ - -void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, - struct saa7146_buf *buf) -{ - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - DEB_EE(("dev:%p, buf:%p\n",dev,buf)); - - BUG_ON(in_interrupt()); - - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - - -/********************************************************************************/ -/* common buffer functions */ - -int saa7146_buffer_queue(struct saa7146_dev *dev, - struct saa7146_dmaqueue *q, - struct saa7146_buf *buf) -{ - assert_spin_locked(&dev->slock); - DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf)); - - BUG_ON(!q); - - if (NULL == q->curr) { - q->curr = buf; - DEB_D(("immediately activating buffer %p\n", buf)); - buf->activate(dev,buf,NULL); - } else { - list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = VIDEOBUF_QUEUED; - DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); - } - return 0; -} - -void saa7146_buffer_finish(struct saa7146_dev *dev, - struct saa7146_dmaqueue *q, - int state) -{ - assert_spin_locked(&dev->slock); - DEB_EE(("dev:%p, dmaq:%p, state:%d\n", dev, q, state)); - DEB_EE(("q->curr:%p\n",q->curr)); - - BUG_ON(!q->curr); - - /* finish current buffer */ - if (NULL == q->curr) { - DEB_D(("aiii. no current buffer\n")); - return; - } - - q->curr->vb.state = state; - do_gettimeofday(&q->curr->vb.ts); - wake_up(&q->curr->vb.done); - - q->curr = NULL; -} - -void saa7146_buffer_next(struct saa7146_dev *dev, - struct saa7146_dmaqueue *q, int vbi) -{ - struct saa7146_buf *buf,*next = NULL; - - BUG_ON(!q); - - DEB_INT(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi)); - - assert_spin_locked(&dev->slock); - if (!list_empty(&q->queue)) { - /* activate next one from queue */ - buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue); - list_del(&buf->vb.queue); - if (!list_empty(&q->queue)) - next = list_entry(q->queue.next,struct saa7146_buf, vb.queue); - q->curr = buf; - DEB_INT(("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev,q->queue.next)); - buf->activate(dev,buf,next); - } else { - DEB_INT(("no next buffer. stopping.\n")); - if( 0 != vbi ) { - /* turn off video-dma3 */ - saa7146_write(dev,MC1, MASK_20); - } else { - /* nothing to do -- just prevent next video-dma1 transfer - by lowering the protection address */ - - // fixme: fix this for vflip != 0 - - saa7146_write(dev, PROT_ADDR1, 0); - saa7146_write(dev, MC2, (MASK_02|MASK_18)); - - /* write the address of the rps-program */ - saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle); - /* turn on rps */ - saa7146_write(dev, MC1, (MASK_12 | MASK_28)); - -/* - printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); - printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); - printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); - printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); - printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); - printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); -*/ - } - del_timer(&q->timeout); - } -} - -void saa7146_buffer_timeout(unsigned long data) -{ - struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data; - struct saa7146_dev *dev = q->dev; - unsigned long flags; - - DEB_EE(("dev:%p, dmaq:%p\n", dev, q)); - - spin_lock_irqsave(&dev->slock,flags); - if (q->curr) { - DEB_D(("timeout on %p\n", q->curr)); - saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); - } - - /* we don't restart the transfer here like other drivers do. when - a streaming capture is disabled, the timeout function will be - called for the current buffer. if we activate the next buffer now, - we mess up our capture logic. if a timeout occurs on another buffer, - then something is seriously broken before, so no need to buffer the - next capture IMHO... */ -/* - saa7146_buffer_next(dev,q); -*/ - spin_unlock_irqrestore(&dev->slock,flags); -} - -/********************************************************************************/ -/* file operations */ - -static int fops_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct saa7146_dev *dev = video_drvdata(file); - struct saa7146_fh *fh = NULL; - int result = 0; - - enum v4l2_buf_type type; - - DEB_EE(("file:%p, dev:%s\n", file, video_device_node_name(vdev))); - - if (mutex_lock_interruptible(&saa7146_devices_lock)) - return -ERESTARTSYS; - - DEB_D(("using: %p\n",dev)); - - type = vdev->vfl_type == VFL_TYPE_GRABBER - ? V4L2_BUF_TYPE_VIDEO_CAPTURE - : V4L2_BUF_TYPE_VBI_CAPTURE; - - /* check if an extension is registered */ - if( NULL == dev->ext ) { - DEB_S(("no extension registered for this device.\n")); - result = -ENODEV; - goto out; - } - - /* allocate per open data */ - fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) { - DEB_S(("cannot allocate memory for per open data.\n")); - result = -ENOMEM; - goto out; - } - - file->private_data = fh; - fh->dev = dev; - fh->type = type; - - if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - DEB_S(("initializing vbi...\n")); - if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) - result = saa7146_vbi_uops.open(dev,file); - if (dev->ext_vv_data->vbi_fops.open) - dev->ext_vv_data->vbi_fops.open(file); - } else { - DEB_S(("initializing video...\n")); - result = saa7146_video_uops.open(dev,file); - } - - if (0 != result) { - goto out; - } - - if( 0 == try_module_get(dev->ext->module)) { - result = -EINVAL; - goto out; - } - - result = 0; -out: - if (fh && result != 0) { - kfree(fh); - file->private_data = NULL; - } - mutex_unlock(&saa7146_devices_lock); - return result; -} - -static int fops_release(struct file *file) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - - DEB_EE(("file:%p\n", file)); - - if (mutex_lock_interruptible(&saa7146_devices_lock)) - return -ERESTARTSYS; - - if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) - saa7146_vbi_uops.release(dev,file); - if (dev->ext_vv_data->vbi_fops.release) - dev->ext_vv_data->vbi_fops.release(file); - } else { - saa7146_video_uops.release(dev,file); - } - - module_put(dev->ext->module); - file->private_data = NULL; - kfree(fh); - - mutex_unlock(&saa7146_devices_lock); - - return 0; -} - -static int fops_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct saa7146_fh *fh = file->private_data; - struct videobuf_queue *q; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: { - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",file, vma)); - q = &fh->video_q; - break; - } - case V4L2_BUF_TYPE_VBI_CAPTURE: { - DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",file, vma)); - q = &fh->vbi_q; - break; - } - default: - BUG(); - return 0; - } - - return videobuf_mmap_mapper(q,vma); -} - -static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) -{ - struct saa7146_fh *fh = file->private_data; - struct videobuf_buffer *buf = NULL; - struct videobuf_queue *q; - - DEB_EE(("file:%p, poll:%p\n",file, wait)); - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - if( 0 == fh->vbi_q.streaming ) - return videobuf_poll_stream(file, &fh->vbi_q, wait); - q = &fh->vbi_q; - } else { - DEB_D(("using video queue.\n")); - q = &fh->video_q; - } - - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - - if (!buf) { - DEB_D(("buf == NULL!\n")); - return POLLERR; - } - - poll_wait(file, &buf->done, wait); - if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { - DEB_D(("poll succeeded!\n")); - return POLLIN|POLLRDNORM; - } - - DEB_D(("nothing to poll for, buf->state:%d\n",buf->state)); - return 0; -} - -static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct saa7146_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: { -// DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", file, data, (unsigned long)count)); - return saa7146_video_uops.read(file,data,count,ppos); - } - case V4L2_BUF_TYPE_VBI_CAPTURE: { -// DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count)); - if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) - return saa7146_vbi_uops.read(file,data,count,ppos); - else - return -EINVAL; - } - break; - default: - BUG(); - return 0; - } -} - -static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) -{ - struct saa7146_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return -EINVAL; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (fh->dev->ext_vv_data->vbi_fops.write) - return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos); - else - return -EINVAL; - default: - BUG(); - return -EINVAL; - } -} - -static const struct v4l2_file_operations video_fops = -{ - .owner = THIS_MODULE, - .open = fops_open, - .release = fops_release, - .read = fops_read, - .write = fops_write, - .poll = fops_poll, - .mmap = fops_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -static void vv_callback(struct saa7146_dev *dev, unsigned long status) -{ - u32 isr = status; - - DEB_INT(("dev:%p, isr:0x%08x\n",dev,(u32)status)); - - if (0 != (isr & (MASK_27))) { - DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); - saa7146_video_uops.irq_done(dev,isr); - } - - if (0 != (isr & (MASK_28))) { - u32 mc2 = saa7146_read(dev, MC2); - if( 0 != (mc2 & MASK_15)) { - DEB_INT(("irq: RPS1 vbi workaround (0x%08x).\n",isr)); - wake_up(&dev->vv_data->vbi_wq); - saa7146_write(dev,MC2, MASK_31); - return; - } - DEB_INT(("irq: RPS1 (0x%08x).\n",isr)); - saa7146_vbi_uops.irq_done(dev,isr); - } -} - -int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) -{ - struct saa7146_vv *vv; - int err; - - err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev); - if (err) - return err; - - vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL); - if (vv == NULL) { - ERR(("out of memory. aborting.\n")); - return -ENOMEM; - } - ext_vv->ops = saa7146_video_ioctl_ops; - ext_vv->core_ops = &saa7146_video_ioctl_ops; - - DEB_EE(("dev:%p\n",dev)); - - /* set default values for video parts of the saa7146 */ - saa7146_write(dev, BCS_CTRL, 0x80400040); - - /* enable video-port pins */ - saa7146_write(dev, MC1, (MASK_10 | MASK_26)); - - /* save per-device extension data (one extension can - handle different devices that might need different - configuration data) */ - dev->ext_vv_data = ext_vv; - - vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle); - if( NULL == vv->d_clipping.cpu_addr ) { - ERR(("out of memory. aborting.\n")); - kfree(vv); - return -1; - } - memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM); - - saa7146_video_uops.init(dev,vv); - if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) - saa7146_vbi_uops.init(dev,vv); - - dev->vv_data = vv; - dev->vv_callback = &vv_callback; - - return 0; -} -EXPORT_SYMBOL_GPL(saa7146_vv_init); - -int saa7146_vv_release(struct saa7146_dev* dev) -{ - struct saa7146_vv *vv = dev->vv_data; - - DEB_EE(("dev:%p\n",dev)); - - v4l2_device_unregister(&dev->v4l2_dev); - pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle); - kfree(vv); - dev->vv_data = NULL; - dev->vv_callback = NULL; - - return 0; -} -EXPORT_SYMBOL_GPL(saa7146_vv_release); - -int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, - char *name, int type) -{ - struct video_device *vfd; - int err; - int i; - - DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type)); - - // released by vfd->release - vfd = video_device_alloc(); - if (vfd == NULL) - return -ENOMEM; - - vfd->fops = &video_fops; - vfd->ioctl_ops = &dev->ext_vv_data->ops; - vfd->release = video_device_release; - vfd->lock = &dev->v4l2_lock; - vfd->tvnorms = 0; - for (i = 0; i < dev->ext_vv_data->num_stds; i++) - vfd->tvnorms |= dev->ext_vv_data->stds[i].id; - strlcpy(vfd->name, name, sizeof(vfd->name)); - video_set_drvdata(vfd, dev); - - err = video_register_device(vfd, type, -1); - if (err < 0) { - ERR(("cannot register v4l2 device. skipping.\n")); - video_device_release(vfd); - return err; - } - - INFO(("%s: registered device %s [v4l2]\n", - dev->name, video_device_node_name(vfd))); - - *vid = vfd; - return 0; -} -EXPORT_SYMBOL_GPL(saa7146_register_device); - -int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) -{ - DEB_EE(("dev:%p\n",dev)); - - video_unregister_device(*vid); - *vid = NULL; - - return 0; -} -EXPORT_SYMBOL_GPL(saa7146_unregister_device); - -static int __init saa7146_vv_init_module(void) -{ - return 0; -} - - -static void __exit saa7146_vv_cleanup_module(void) -{ -} - -module_init(saa7146_vv_init_module); -module_exit(saa7146_vv_cleanup_module); - -MODULE_AUTHOR("Michael Hunold "); -MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_hlp.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_hlp.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_hlp.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_hlp.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1044 +0,0 @@ -#include -#include - -static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format) -{ - /* clear out the necessary bits */ - *clip_format &= 0x0000ffff; - /* set these bits new */ - *clip_format |= (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16)); -} - -static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl) -{ - *hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28); - *hps_ctrl |= (source << 30) | (sync << 28); -} - -static void calculate_hxo_and_hyo(struct saa7146_vv *vv, u32* hps_h_scale, u32* hps_ctrl) -{ - int hyo = 0, hxo = 0; - - hyo = vv->standard->v_offset; - hxo = vv->standard->h_offset; - - *hps_h_scale &= ~(MASK_B0 | 0xf00); - *hps_h_scale |= (hxo << 0); - - *hps_ctrl &= ~(MASK_W0 | MASK_B2); - *hps_ctrl |= (hyo << 12); -} - -/* helper functions for the calculation of the horizontal- and vertical - scaling registers, clip-format-register etc ... - these functions take pointers to the (most-likely read-out - original-values) and manipulate them according to the requested - changes. -*/ - -/* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */ -static struct { - u16 hps_coeff; - u16 weight_sum; -} hps_h_coeff_tab [] = { - {0x00, 2}, {0x02, 4}, {0x00, 4}, {0x06, 8}, {0x02, 8}, - {0x08, 8}, {0x00, 8}, {0x1E, 16}, {0x0E, 8}, {0x26, 8}, - {0x06, 8}, {0x42, 8}, {0x02, 8}, {0x80, 8}, {0x00, 8}, - {0xFE, 16}, {0xFE, 8}, {0x7E, 8}, {0x7E, 8}, {0x3E, 8}, - {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, {0x0E, 8}, {0x0E, 8}, - {0x06, 8}, {0x06, 8}, {0x02, 8}, {0x02, 8}, {0x00, 8}, - {0x00, 8}, {0xFE, 16}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, - {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, - {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, - {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0x7E, 8}, - {0x7E, 8}, {0x3E, 8}, {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, - {0x0E, 8}, {0x0E, 8}, {0x06, 8}, {0x06, 8}, {0x02, 8}, - {0x02, 8}, {0x00, 8}, {0x00, 8}, {0xFE, 16} -}; - -/* table of attenuation values for horizontal scaling */ -static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0}; - -/* calculate horizontal scale registers */ -static int calculate_h_scale_registers(struct saa7146_dev *dev, - int in_x, int out_x, int flip_lr, - u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale) -{ - /* horizontal prescaler */ - u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0; - /* horizontal scaler */ - u32 xim = 0, xp = 0, xsci =0; - /* vertical scale & gain */ - u32 pfuv = 0; - - /* helper variables */ - u32 h_atten = 0, i = 0; - - if ( 0 == out_x ) { - return -EINVAL; - } - - /* mask out vanity-bit */ - *hps_ctrl &= ~MASK_29; - - /* calculate prescale-(xspc)-value: [n .. 1/2) : 1 - [1/2 .. 1/3) : 2 - [1/3 .. 1/4) : 3 - ... */ - if (in_x > out_x) { - xpsc = in_x / out_x; - } - else { - /* zooming */ - xpsc = 1; - } - - /* if flip_lr-bit is set, number of pixels after - horizontal prescaling must be < 384 */ - if ( 0 != flip_lr ) { - - /* set vanity bit */ - *hps_ctrl |= MASK_29; - - while (in_x / xpsc >= 384 ) - xpsc++; - } - /* if zooming is wanted, number of pixels after - horizontal prescaling must be < 768 */ - else { - while ( in_x / xpsc >= 768 ) - xpsc++; - } - - /* maximum prescale is 64 (p.69) */ - if ( xpsc > 64 ) - xpsc = 64; - - /* keep xacm clear*/ - xacm = 0; - - /* set horizontal filter parameters (CXY = CXUV) */ - cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff; - cxuv = cxy; - - /* calculate and set horizontal fine scale (xsci) */ - - /* bypass the horizontal scaler ? */ - if ( (in_x == out_x) && ( 1 == xpsc ) ) - xsci = 0x400; - else - xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc; - - /* set start phase for horizontal fine scale (xp) to 0 */ - xp = 0; - - /* set xim, if we bypass the horizontal scaler */ - if ( 0x400 == xsci ) - xim = 1; - else - xim = 0; - - /* if the prescaler is bypassed, enable horizontal - accumulation mode (xacm) and clear dcgx */ - if( 1 == xpsc ) { - xacm = 1; - dcgx = 0; - } else { - xacm = 0; - /* get best match in the table of attenuations - for horizontal scaling */ - h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum; - - for (i = 0; h_attenuation[i] != 0; i++) { - if (h_attenuation[i] >= h_atten) - break; - } - - dcgx = i; - } - - /* the horizontal scaling increment controls the UV filter - to reduce the bandwidth to improve the display quality, - so set it ... */ - if ( xsci == 0x400) - pfuv = 0x00; - else if ( xsci < 0x600) - pfuv = 0x01; - else if ( xsci < 0x680) - pfuv = 0x11; - else if ( xsci < 0x700) - pfuv = 0x22; - else - pfuv = 0x33; - - - *hps_v_gain &= MASK_W0|MASK_B2; - *hps_v_gain |= (pfuv << 24); - - *hps_h_scale &= ~(MASK_W1 | 0xf000); - *hps_h_scale |= (xim << 31) | (xp << 24) | (xsci << 12); - - *hps_h_prescale |= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0); - - return 0; -} - -static struct { - u16 hps_coeff; - u16 weight_sum; -} hps_v_coeff_tab [] = { - {0x0100, 2}, {0x0102, 4}, {0x0300, 4}, {0x0106, 8}, {0x0502, 8}, - {0x0708, 8}, {0x0F00, 8}, {0x011E, 16}, {0x110E, 16}, {0x1926, 16}, - {0x3906, 16}, {0x3D42, 16}, {0x7D02, 16}, {0x7F80, 16}, {0xFF00, 16}, - {0x01FE, 32}, {0x01FE, 32}, {0x817E, 32}, {0x817E, 32}, {0xC13E, 32}, - {0xC13E, 32}, {0xE11E, 32}, {0xE11E, 32}, {0xF10E, 32}, {0xF10E, 32}, - {0xF906, 32}, {0xF906, 32}, {0xFD02, 32}, {0xFD02, 32}, {0xFF00, 32}, - {0xFF00, 32}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, - {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, - {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, - {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x817E, 64}, - {0x817E, 64}, {0xC13E, 64}, {0xC13E, 64}, {0xE11E, 64}, {0xE11E, 64}, - {0xF10E, 64}, {0xF10E, 64}, {0xF906, 64}, {0xF906, 64}, {0xFD02, 64}, - {0xFD02, 64}, {0xFF00, 64}, {0xFF00, 64}, {0x01FE, 128} -}; - -/* table of attenuation values for vertical scaling */ -static u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0}; - -/* calculate vertical scale registers */ -static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field, - int in_y, int out_y, u32* hps_v_scale, u32* hps_v_gain) -{ - int lpi = 0; - - /* vertical scaling */ - u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0; - /* vertical scale & gain */ - u32 dcgy = 0, cya_cyb = 0; - - /* helper variables */ - u32 v_atten = 0, i = 0; - - /* error, if vertical zooming */ - if ( in_y < out_y ) { - return -EINVAL; - } - - /* linear phase interpolation may be used - if scaling is between 1 and 1/2 (both fields used) - or scaling is between 1/2 and 1/4 (if only one field is used) */ - - if (V4L2_FIELD_HAS_BOTH(field)) { - if( 2*out_y >= in_y) { - lpi = 1; - } - } else if (field == V4L2_FIELD_TOP - || field == V4L2_FIELD_ALTERNATE - || field == V4L2_FIELD_BOTTOM) { - if( 4*out_y >= in_y ) { - lpi = 1; - } - out_y *= 2; - } - if( 0 != lpi ) { - - yacm = 0; - yacl = 0; - cya_cyb = 0x00ff; - - /* calculate scaling increment */ - if ( in_y > out_y ) - ysci = ((1024 * in_y) / (out_y + 1)) - 1024; - else - ysci = 0; - - dcgy = 0; - - /* calculate ype and ypo */ - ype = ysci / 16; - ypo = ype + (ysci / 64); - - } else { - yacm = 1; - - /* calculate scaling increment */ - ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10; - - /* calculate ype and ypo */ - ypo = ype = ((ysci + 15) / 16); - - /* the sequence length interval (yacl) has to be set according - to the prescale value, e.g. [n .. 1/2) : 0 - [1/2 .. 1/3) : 1 - [1/3 .. 1/4) : 2 - ... */ - if ( ysci < 512) { - yacl = 0; - } else { - yacl = ( ysci / (1024 - ysci) ); - } - - /* get filter coefficients for cya, cyb from table hps_v_coeff_tab */ - cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff; - - /* get best match in the table of attenuations for vertical scaling */ - v_atten = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].weight_sum; - - for (i = 0; v_attenuation[i] != 0; i++) { - if (v_attenuation[i] >= v_atten) - break; - } - - dcgy = i; - } - - /* ypo and ype swapped in spec ? */ - *hps_v_scale |= (yacm << 31) | (ysci << 21) | (yacl << 15) | (ypo << 8 ) | (ype << 1); - - *hps_v_gain &= ~(MASK_W0|MASK_B2); - *hps_v_gain |= (dcgy << 16) | (cya_cyb << 0); - - return 0; -} - -/* simple bubble-sort algorithm with duplicate elimination */ -static int sort_and_eliminate(u32* values, int* count) -{ - int low = 0, high = 0, top = 0, temp = 0; - int cur = 0, next = 0; - - /* sanity checks */ - if( (0 > *count) || (NULL == values) ) { - return -EINVAL; - } - - /* bubble sort the first @count items of the array @values */ - for( top = *count; top > 0; top--) { - for( low = 0, high = 1; high < top; low++, high++) { - if( values[low] > values[high] ) { - temp = values[low]; - values[low] = values[high]; - values[high] = temp; - } - } - } - - /* remove duplicate items */ - for( cur = 0, next = 1; next < *count; next++) { - if( values[cur] != values[next]) - values[++cur] = values[next]; - } - - *count = cur + 1; - - return 0; -} - -static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct saa7146_fh *fh, - struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field) -{ - struct saa7146_vv *vv = dev->vv_data; - __le32 *clipping = vv->d_clipping.cpu_addr; - - int width = fh->ov.win.w.width; - int height = fh->ov.win.w.height; - int clipcount = fh->ov.nclips; - - u32 line_list[32]; - u32 pixel_list[32]; - int numdwords = 0; - - int i = 0, j = 0; - int cnt_line = 0, cnt_pixel = 0; - - int x[32], y[32], w[32], h[32]; - - /* clear out memory */ - memset(&line_list[0], 0x00, sizeof(u32)*32); - memset(&pixel_list[0], 0x00, sizeof(u32)*32); - memset(clipping, 0x00, SAA7146_CLIPPING_MEM); - - /* fill the line and pixel-lists */ - for(i = 0; i < clipcount; i++) { - int l = 0, r = 0, t = 0, b = 0; - - x[i] = fh->ov.clips[i].c.left; - y[i] = fh->ov.clips[i].c.top; - w[i] = fh->ov.clips[i].c.width; - h[i] = fh->ov.clips[i].c.height; - - if( w[i] < 0) { - x[i] += w[i]; w[i] = -w[i]; - } - if( h[i] < 0) { - y[i] += h[i]; h[i] = -h[i]; - } - if( x[i] < 0) { - w[i] += x[i]; x[i] = 0; - } - if( y[i] < 0) { - h[i] += y[i]; y[i] = 0; - } - if( 0 != vv->vflip ) { - y[i] = height - y[i] - h[i]; - } - - l = x[i]; - r = x[i]+w[i]; - t = y[i]; - b = y[i]+h[i]; - - /* insert left/right coordinates */ - pixel_list[ 2*i ] = min_t(int, l, width); - pixel_list[(2*i)+1] = min_t(int, r, width); - /* insert top/bottom coordinates */ - line_list[ 2*i ] = min_t(int, t, height); - line_list[(2*i)+1] = min_t(int, b, height); - } - - /* sort and eliminate lists */ - cnt_line = cnt_pixel = 2*clipcount; - sort_and_eliminate( &pixel_list[0], &cnt_pixel ); - sort_and_eliminate( &line_list[0], &cnt_line ); - - /* calculate the number of used u32s */ - numdwords = max_t(int, (cnt_line+1), (cnt_pixel+1))*2; - numdwords = max_t(int, 4, numdwords); - numdwords = min_t(int, 64, numdwords); - - /* fill up cliptable */ - for(i = 0; i < cnt_pixel; i++) { - clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16); - } - for(i = 0; i < cnt_line; i++) { - clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16); - } - - /* fill up cliptable with the display infos */ - for(j = 0; j < clipcount; j++) { - - for(i = 0; i < cnt_pixel; i++) { - - if( x[j] < 0) - x[j] = 0; - - if( pixel_list[i] < (x[j] + w[j])) { - - if ( pixel_list[i] >= x[j] ) { - clipping[2*i] |= cpu_to_le32(1 << j); - } - } - } - for(i = 0; i < cnt_line; i++) { - - if( y[j] < 0) - y[j] = 0; - - if( line_list[i] < (y[j] + h[j]) ) { - - if( line_list[i] >= y[j] ) { - clipping[(2*i)+1] |= cpu_to_le32(1 << j); - } - } - } - } - - /* adjust arbitration control register */ - *arbtr_ctrl &= 0xffff00ff; - *arbtr_ctrl |= 0x00001c00; - - vdma2->base_even = vv->d_clipping.dma_handle; - vdma2->base_odd = vv->d_clipping.dma_handle; - vdma2->prot_addr = vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords)); - vdma2->base_page = 0x04; - vdma2->pitch = 0x00; - vdma2->num_line_byte = (0 << 16 | (sizeof(u32))*(numdwords-1) ); - - /* set clipping-mode. this depends on the field(s) used */ - *clip_format &= 0xfffffff7; - if (V4L2_FIELD_HAS_BOTH(field)) { - *clip_format |= 0x00000008; - } else { - *clip_format |= 0x00000000; - } -} - -/* disable clipping */ -static void saa7146_disable_clipping(struct saa7146_dev *dev) -{ - u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); - - /* mask out relevant bits (=lower word)*/ - clip_format &= MASK_W1; - - /* upload clipping-registers*/ - saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format); - saa7146_write(dev, MC2, (MASK_05 | MASK_21)); - - /* disable video dma2 */ - saa7146_write(dev, MC1, MASK_21); -} - -static void saa7146_set_clipping_rect(struct saa7146_fh *fh) -{ - struct saa7146_dev *dev = fh->dev; - enum v4l2_field field = fh->ov.win.field; - struct saa7146_video_dma vdma2; - u32 clip_format; - u32 arbtr_ctrl; - - /* check clipcount, disable clipping if clipcount == 0*/ - if( fh->ov.nclips == 0 ) { - saa7146_disable_clipping(dev); - return; - } - - clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); - arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); - - calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field); - - /* set clipping format */ - clip_format &= 0xffff0008; - clip_format |= (SAA7146_CLIPPING_RECT << 4); - - /* prepare video dma2 */ - saa7146_write(dev, BASE_EVEN2, vdma2.base_even); - saa7146_write(dev, BASE_ODD2, vdma2.base_odd); - saa7146_write(dev, PROT_ADDR2, vdma2.prot_addr); - saa7146_write(dev, BASE_PAGE2, vdma2.base_page); - saa7146_write(dev, PITCH2, vdma2.pitch); - saa7146_write(dev, NUM_LINE_BYTE2, vdma2.num_line_byte); - - /* prepare the rest */ - saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format); - saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); - - /* upload clip_control-register, clipping-registers, enable video dma2 */ - saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19)); - saa7146_write(dev, MC1, (MASK_05 | MASK_21)); -} - -static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field) -{ - struct saa7146_vv *vv = dev->vv_data; - - int source = vv->current_hps_source; - int sync = vv->current_hps_sync; - - u32 hps_v_scale = 0, hps_v_gain = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0; - - /* set vertical scale */ - hps_v_scale = 0; /* all bits get set by the function-call */ - hps_v_gain = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/ - calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain); - - /* set horizontal scale */ - hps_ctrl = 0; - hps_h_prescale = 0; /* all bits get set in the function */ - hps_h_scale = 0; - calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale); - - /* set hyo and hxo */ - calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl); - calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl); - - /* write out new register contents */ - saa7146_write(dev, HPS_V_SCALE, hps_v_scale); - saa7146_write(dev, HPS_V_GAIN, hps_v_gain); - saa7146_write(dev, HPS_CTRL, hps_ctrl); - saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale); - saa7146_write(dev, HPS_H_SCALE, hps_h_scale); - - /* upload shadow-ram registers */ - saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) ); -} - -/* calculate the new memory offsets for a desired position */ -static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat) -{ - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat); - - int b_depth = vv->ov_fmt->depth; - int b_bpl = vv->ov_fb.fmt.bytesperline; - /* The unsigned long cast is to remove a 64-bit compile warning since - it looks like a 64-bit address is cast to a 32-bit value, even - though the base pointer is really a 32-bit physical address that - goes into a 32-bit DMA register. - FIXME: might not work on some 64-bit platforms, but see the FIXME - in struct v4l2_framebuffer (videodev2.h) for that. - */ - u32 base = (u32)(unsigned long)vv->ov_fb.base; - - struct saa7146_video_dma vdma1; - - /* calculate memory offsets for picture, look if we shall top-down-flip */ - vdma1.pitch = 2*b_bpl; - if ( 0 == vv->vflip ) { - vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); - vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2); - vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2)); - } - else { - vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); - vdma1.base_odd = vdma1.base_even - (vdma1.pitch / 2); - vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2)); - } - - if (V4L2_FIELD_HAS_BOTH(field)) { - } else if (field == V4L2_FIELD_ALTERNATE) { - /* fixme */ - vdma1.base_odd = vdma1.prot_addr; - vdma1.pitch /= 2; - } else if (field == V4L2_FIELD_TOP) { - vdma1.base_odd = vdma1.prot_addr; - vdma1.pitch /= 2; - } else if (field == V4L2_FIELD_BOTTOM) { - vdma1.base_odd = vdma1.base_even; - vdma1.base_even = vdma1.prot_addr; - vdma1.pitch /= 2; - } - - if ( 0 != vv->vflip ) { - vdma1.pitch *= -1; - } - - vdma1.base_page = sfmt->swap; - vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels; - - saa7146_write_out_dma(dev, 1, &vdma1); -} - -static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette) -{ - u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); - - /* call helper function */ - calculate_output_format_register(dev,palette,&clip_format); - - /* update the hps registers */ - saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format); - saa7146_write(dev, MC2, (MASK_05 | MASK_21)); -} - -/* select input-source */ -void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync) -{ - struct saa7146_vv *vv = dev->vv_data; - u32 hps_ctrl = 0; - - /* read old state */ - hps_ctrl = saa7146_read(dev, HPS_CTRL); - - hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 ); - hps_ctrl |= (source << 30) | (sync << 28); - - /* write back & upload register */ - saa7146_write(dev, HPS_CTRL, hps_ctrl); - saa7146_write(dev, MC2, (MASK_05 | MASK_21)); - - vv->current_hps_source = source; - vv->current_hps_sync = sync; -} -EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync); - -int saa7146_enable_overlay(struct saa7146_fh *fh) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - - saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field); - saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field, vv->ov_fmt->pixelformat); - saa7146_set_output_format(dev, vv->ov_fmt->trans); - saa7146_set_clipping_rect(fh); - - /* enable video dma1 */ - saa7146_write(dev, MC1, (MASK_06 | MASK_22)); - return 0; -} - -void saa7146_disable_overlay(struct saa7146_fh *fh) -{ - struct saa7146_dev *dev = fh->dev; - - /* disable clipping + video dma1 */ - saa7146_disable_clipping(dev); - saa7146_write(dev, MC1, MASK_22); -} - -void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) -{ - int where = 0; - - if( which < 1 || which > 3) { - return; - } - - /* calculate starting address */ - where = (which-1)*0x18; - - saa7146_write(dev, where, vdma->base_odd); - saa7146_write(dev, where+0x04, vdma->base_even); - saa7146_write(dev, where+0x08, vdma->prot_addr); - saa7146_write(dev, where+0x0c, vdma->pitch); - saa7146_write(dev, where+0x10, vdma->base_page); - saa7146_write(dev, where+0x14, vdma->num_line_byte); - - /* upload */ - saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1))); -/* - printk("vdma%d.base_even: 0x%08x\n", which,vdma->base_even); - printk("vdma%d.base_odd: 0x%08x\n", which,vdma->base_odd); - printk("vdma%d.prot_addr: 0x%08x\n", which,vdma->prot_addr); - printk("vdma%d.base_page: 0x%08x\n", which,vdma->base_page); - printk("vdma%d.pitch: 0x%08x\n", which,vdma->pitch); - printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte); -*/ -} - -static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf) -{ - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_video_dma vdma1; - - struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); - - int width = buf->fmt->width; - int height = buf->fmt->height; - int bytesperline = buf->fmt->bytesperline; - enum v4l2_field field = buf->fmt->field; - - int depth = sfmt->depth; - - DEB_CAP(("[size=%dx%d,fields=%s]\n", - width,height,v4l2_field_names[field])); - - if( bytesperline != 0) { - vdma1.pitch = bytesperline*2; - } else { - vdma1.pitch = (width*depth*2)/8; - } - vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); - vdma1.base_page = buf->pt[0].dma | ME1 | sfmt->swap; - - if( 0 != vv->vflip ) { - vdma1.prot_addr = buf->pt[0].offset; - vdma1.base_even = buf->pt[0].offset+(vdma1.pitch/2)*height; - vdma1.base_odd = vdma1.base_even - (vdma1.pitch/2); - } else { - vdma1.base_even = buf->pt[0].offset; - vdma1.base_odd = vdma1.base_even + (vdma1.pitch/2); - vdma1.prot_addr = buf->pt[0].offset+(vdma1.pitch/2)*height; - } - - if (V4L2_FIELD_HAS_BOTH(field)) { - } else if (field == V4L2_FIELD_ALTERNATE) { - /* fixme */ - if ( vv->last_field == V4L2_FIELD_TOP ) { - vdma1.base_odd = vdma1.prot_addr; - vdma1.pitch /= 2; - } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { - vdma1.base_odd = vdma1.base_even; - vdma1.base_even = vdma1.prot_addr; - vdma1.pitch /= 2; - } - } else if (field == V4L2_FIELD_TOP) { - vdma1.base_odd = vdma1.prot_addr; - vdma1.pitch /= 2; - } else if (field == V4L2_FIELD_BOTTOM) { - vdma1.base_odd = vdma1.base_even; - vdma1.base_even = vdma1.prot_addr; - vdma1.pitch /= 2; - } - - if( 0 != vv->vflip ) { - vdma1.pitch *= -1; - } - - saa7146_write_out_dma(dev, 1, &vdma1); - return 0; -} - -static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) -{ - int height = buf->fmt->height; - int width = buf->fmt->width; - - vdma2->pitch = width; - vdma3->pitch = width; - - /* fixme: look at bytesperline! */ - - if( 0 != vv->vflip ) { - vdma2->prot_addr = buf->pt[1].offset; - vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[1].offset; - vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); - - vdma3->prot_addr = buf->pt[2].offset; - vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[2].offset; - vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); - } else { - vdma3->base_even = buf->pt[2].offset; - vdma3->base_odd = vdma3->base_even + (vdma3->pitch/2); - vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; - - vdma2->base_even = buf->pt[1].offset; - vdma2->base_odd = vdma2->base_even + (vdma2->pitch/2); - vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; - } - - return 0; -} - -static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) -{ - int height = buf->fmt->height; - int width = buf->fmt->width; - - vdma2->pitch = width/2; - vdma3->pitch = width/2; - - if( 0 != vv->vflip ) { - vdma2->prot_addr = buf->pt[2].offset; - vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[2].offset; - vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); - - vdma3->prot_addr = buf->pt[1].offset; - vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[1].offset; - vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); - - } else { - vdma3->base_even = buf->pt[2].offset; - vdma3->base_odd = vdma3->base_even + (vdma3->pitch); - vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; - - vdma2->base_even = buf->pt[1].offset; - vdma2->base_odd = vdma2->base_even + (vdma2->pitch); - vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; - } - return 0; -} - -static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf) -{ - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_video_dma vdma1; - struct saa7146_video_dma vdma2; - struct saa7146_video_dma vdma3; - - struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); - - int width = buf->fmt->width; - int height = buf->fmt->height; - enum v4l2_field field = buf->fmt->field; - - BUG_ON(0 == buf->pt[0].dma); - BUG_ON(0 == buf->pt[1].dma); - BUG_ON(0 == buf->pt[2].dma); - - DEB_CAP(("[size=%dx%d,fields=%s]\n", - width,height,v4l2_field_names[field])); - - /* fixme: look at bytesperline! */ - - /* fixme: what happens for user space buffers here?. The offsets are - most likely wrong, this version here only works for page-aligned - buffers, modifications to the pagetable-functions are necessary...*/ - - vdma1.pitch = width*2; - vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); - vdma1.base_page = buf->pt[0].dma | ME1; - - if( 0 != vv->vflip ) { - vdma1.prot_addr = buf->pt[0].offset; - vdma1.base_even = ((vdma1.pitch/2)*height)+buf->pt[0].offset; - vdma1.base_odd = vdma1.base_even - (vdma1.pitch/2); - } else { - vdma1.base_even = buf->pt[0].offset; - vdma1.base_odd = vdma1.base_even + (vdma1.pitch/2); - vdma1.prot_addr = (vdma1.pitch/2)*height+buf->pt[0].offset; - } - - vdma2.num_line_byte = 0; /* unused */ - vdma2.base_page = buf->pt[1].dma | ME1; - - vdma3.num_line_byte = 0; /* unused */ - vdma3.base_page = buf->pt[2].dma | ME1; - - switch( sfmt->depth ) { - case 12: { - calc_planar_420(vv,buf,&vdma2,&vdma3); - break; - } - case 16: { - calc_planar_422(vv,buf,&vdma2,&vdma3); - break; - } - default: { - return -1; - } - } - - if (V4L2_FIELD_HAS_BOTH(field)) { - } else if (field == V4L2_FIELD_ALTERNATE) { - /* fixme */ - vdma1.base_odd = vdma1.prot_addr; - vdma1.pitch /= 2; - vdma2.base_odd = vdma2.prot_addr; - vdma2.pitch /= 2; - vdma3.base_odd = vdma3.prot_addr; - vdma3.pitch /= 2; - } else if (field == V4L2_FIELD_TOP) { - vdma1.base_odd = vdma1.prot_addr; - vdma1.pitch /= 2; - vdma2.base_odd = vdma2.prot_addr; - vdma2.pitch /= 2; - vdma3.base_odd = vdma3.prot_addr; - vdma3.pitch /= 2; - } else if (field == V4L2_FIELD_BOTTOM) { - vdma1.base_odd = vdma1.base_even; - vdma1.base_even = vdma1.prot_addr; - vdma1.pitch /= 2; - vdma2.base_odd = vdma2.base_even; - vdma2.base_even = vdma2.prot_addr; - vdma2.pitch /= 2; - vdma3.base_odd = vdma3.base_even; - vdma3.base_even = vdma3.prot_addr; - vdma3.pitch /= 2; - } - - if( 0 != vv->vflip ) { - vdma1.pitch *= -1; - vdma2.pitch *= -1; - vdma3.pitch *= -1; - } - - saa7146_write_out_dma(dev, 1, &vdma1); - if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) { - saa7146_write_out_dma(dev, 3, &vdma2); - saa7146_write_out_dma(dev, 2, &vdma3); - } else { - saa7146_write_out_dma(dev, 2, &vdma2); - saa7146_write_out_dma(dev, 3, &vdma3); - } - return 0; -} - -static void program_capture_engine(struct saa7146_dev *dev, int planar) -{ - struct saa7146_vv *vv = dev->vv_data; - int count = 0; - - unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; - unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; - - /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/ - WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait); - WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait); - - /* set rps register 0 */ - WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4)); - WRITE_RPS0(MASK_27 | MASK_11); - - /* turn on video-dma1 */ - WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); - WRITE_RPS0(MASK_06 | MASK_22); /* => mask */ - WRITE_RPS0(MASK_06 | MASK_22); /* => values */ - if( 0 != planar ) { - /* turn on video-dma2 */ - WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); - WRITE_RPS0(MASK_05 | MASK_21); /* => mask */ - WRITE_RPS0(MASK_05 | MASK_21); /* => values */ - - /* turn on video-dma3 */ - WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); - WRITE_RPS0(MASK_04 | MASK_20); /* => mask */ - WRITE_RPS0(MASK_04 | MASK_20); /* => values */ - } - - /* wait for o_fid_a/b / e_fid_a/b toggle */ - if ( vv->last_field == V4L2_FIELD_INTERLACED ) { - WRITE_RPS0(CMD_PAUSE | o_wait); - WRITE_RPS0(CMD_PAUSE | e_wait); - } else if ( vv->last_field == V4L2_FIELD_TOP ) { - WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09)); - WRITE_RPS0(CMD_PAUSE | o_wait); - } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { - WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09)); - WRITE_RPS0(CMD_PAUSE | e_wait); - } - - /* turn off video-dma1 */ - WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); - WRITE_RPS0(MASK_22 | MASK_06); /* => mask */ - WRITE_RPS0(MASK_22); /* => values */ - if( 0 != planar ) { - /* turn off video-dma2 */ - WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); - WRITE_RPS0(MASK_05 | MASK_21); /* => mask */ - WRITE_RPS0(MASK_21); /* => values */ - - /* turn off video-dma3 */ - WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); - WRITE_RPS0(MASK_04 | MASK_20); /* => mask */ - WRITE_RPS0(MASK_20); /* => values */ - } - - /* generate interrupt */ - WRITE_RPS0(CMD_INTERRUPT); - - /* stop */ - WRITE_RPS0(CMD_STOP); -} - -void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) -{ - struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); - struct saa7146_vv *vv = dev->vv_data; - u32 vdma1_prot_addr; - - DEB_CAP(("buf:%p, next:%p\n",buf,next)); - - vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1); - if( 0 == vdma1_prot_addr ) { - /* clear out beginning of streaming bit (rps register 0)*/ - DEB_CAP(("forcing sync to new frame\n")); - saa7146_write(dev, MC2, MASK_27 ); - } - - saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field); - saa7146_set_output_format(dev, sfmt->trans); - saa7146_disable_clipping(dev); - - if ( vv->last_field == V4L2_FIELD_INTERLACED ) { - } else if ( vv->last_field == V4L2_FIELD_TOP ) { - vv->last_field = V4L2_FIELD_BOTTOM; - } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { - vv->last_field = V4L2_FIELD_TOP; - } - - if( 0 != IS_PLANAR(sfmt->trans)) { - calculate_video_dma_grab_planar(dev, buf); - program_capture_engine(dev,1); - } else { - calculate_video_dma_grab_packed(dev, buf); - program_capture_engine(dev,0); - } - -/* - printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); - printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); - printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); - printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); - printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); - printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); - printk("vdma%d => vptr : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1)); -*/ - - /* write the address of the rps-program */ - saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle); - - /* turn on rps */ - saa7146_write(dev, MC1, (MASK_12 | MASK_28)); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,421 +0,0 @@ -#include - -static u32 saa7146_i2c_func(struct i2c_adapter *adapter) -{ -//fm DEB_I2C(("'%s'.\n", adapter->name)); - - return I2C_FUNC_I2C - | I2C_FUNC_SMBUS_QUICK - | I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE - | I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; -} - -/* this function returns the status-register of our i2c-device */ -static inline u32 saa7146_i2c_status(struct saa7146_dev *dev) -{ - u32 iicsta = saa7146_read(dev, I2C_STATUS); -/* - DEB_I2C(("status: 0x%08x\n",iicsta)); -*/ - return iicsta; -} - -/* this function runs through the i2c-messages and prepares the data to be - sent through the saa7146. have a look at the specifications p. 122 ff - to understand this. it returns the number of u32s to send, or -1 - in case of an error. */ -static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op) -{ - int h1, h2; - int i, j, addr; - int mem = 0, op_count = 0; - - /* first determine size of needed memory */ - for(i = 0; i < num; i++) { - mem += m[i].len + 1; - } - - /* worst case: we need one u32 for three bytes to be send - plus one extra byte to address the device */ - mem = 1 + ((mem-1) / 3); - - /* we assume that op points to a memory of at least SAA7146_I2C_MEM bytes - size. if we exceed this limit... */ - if ( (4*mem) > SAA7146_I2C_MEM ) { -//fm DEB_I2C(("cannot prepare i2c-message.\n")); - return -ENOMEM; - } - - /* be careful: clear out the i2c-mem first */ - memset(op,0,sizeof(__le32)*mem); - - /* loop through all messages */ - for(i = 0; i < num; i++) { - - /* insert the address of the i2c-slave. - note: we get 7 bit i2c-addresses, - so we have to perform a translation */ - addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0); - h1 = op_count/3; h2 = op_count%3; - op[h1] |= cpu_to_le32( (u8)addr << ((3-h2)*8)); - op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2)); - op_count++; - - /* loop through all bytes of message i */ - for(j = 0; j < m[i].len; j++) { - /* insert the data bytes */ - h1 = op_count/3; h2 = op_count%3; - op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8)); - op[h1] |= cpu_to_le32( SAA7146_I2C_CONT << ((3-h2)*2)); - op_count++; - } - - } - - /* have a look at the last byte inserted: - if it was: ...CONT change it to ...STOP */ - h1 = (op_count-1)/3; h2 = (op_count-1)%3; - if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) { - op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2)); - op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2)); - } - - /* return the number of u32s to send */ - return mem; -} - -/* this functions loops through all i2c-messages. normally, it should determine - which bytes were read through the adapter and write them back to the corresponding - i2c-message. but instead, we simply write back all bytes. - fixme: this could be improved. */ -static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op) -{ - int i, j; - int op_count = 0; - - /* loop through all messages */ - for(i = 0; i < num; i++) { - - op_count++; - - /* loop through all bytes of message i */ - for(j = 0; j < m[i].len; j++) { - /* write back all bytes that could have been read */ - m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8)); - op_count++; - } - } - - return 0; -} - -/* this functions resets the i2c-device and returns 0 if everything was fine, otherwise -1 */ -static int saa7146_i2c_reset(struct saa7146_dev *dev) -{ - /* get current status */ - u32 status = saa7146_i2c_status(dev); - - /* clear registers for sure */ - saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); - saa7146_write(dev, I2C_TRANSFER, 0); - - /* check if any operation is still in progress */ - if ( 0 != ( status & SAA7146_I2C_BUSY) ) { - - /* yes, kill ongoing operation */ - DEB_I2C(("busy_state detected.\n")); - - /* set "ABORT-OPERATION"-bit (bit 7)*/ - saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); - saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - msleep(SAA7146_I2C_DELAY); - - /* clear all error-bits pending; this is needed because p.123, note 1 */ - saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); - saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - msleep(SAA7146_I2C_DELAY); - } - - /* check if any error is (still) present. (this can be necessary because p.123, note 1) */ - status = saa7146_i2c_status(dev); - - if ( dev->i2c_bitrate != status ) { - - DEB_I2C(("error_state detected. status:0x%08x\n",status)); - - /* Repeat the abort operation. This seems to be necessary - after serious protocol errors caused by e.g. the SAA7740 */ - saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); - saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - msleep(SAA7146_I2C_DELAY); - - /* clear all error-bits pending */ - saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); - saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - msleep(SAA7146_I2C_DELAY); - - /* the data sheet says it might be necessary to clear the status - twice after an abort */ - saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); - saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - msleep(SAA7146_I2C_DELAY); - } - - /* if any error is still present, a fatal error has occured ... */ - status = saa7146_i2c_status(dev); - if ( dev->i2c_bitrate != status ) { - DEB_I2C(("fatal error. status:0x%08x\n",status)); - return -1; - } - - return 0; -} - -/* this functions writes out the data-byte 'dword' to the i2c-device. - it returns 0 if ok, -1 if the transfer failed, -2 if the transfer - failed badly (e.g. address error) */ -static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay) -{ - u32 status = 0, mc2 = 0; - int trial = 0; - unsigned long timeout; - - /* write out i2c-command */ - DEB_I2C(("before: 0x%08x (status: 0x%08x), %d\n",*dword,saa7146_read(dev, I2C_STATUS), dev->i2c_op)); - - if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) { - - saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); - saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword)); - - dev->i2c_op = 1; - SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17); - SAA7146_IER_ENABLE(dev, MASK_16|MASK_17); - saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - - timeout = HZ/100 + 1; /* 10ms */ - timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout); - if (timeout == -ERESTARTSYS || dev->i2c_op) { - SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); - SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17); - if (timeout == -ERESTARTSYS) - /* a signal arrived */ - return -ERESTARTSYS; - - printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n", - dev->name, __func__); - return -EIO; - } - status = saa7146_read(dev, I2C_STATUS); - } else { - saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); - saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword)); - saa7146_write(dev, MC2, (MASK_00 | MASK_16)); - - /* do not poll for i2c-status before upload is complete */ - timeout = jiffies + HZ/100 + 1; /* 10ms */ - while(1) { - mc2 = (saa7146_read(dev, MC2) & 0x1); - if( 0 != mc2 ) { - break; - } - if (time_after(jiffies,timeout)) { - printk(KERN_WARNING "%s %s: timed out waiting for MC2\n", - dev->name, __func__); - return -EIO; - } - } - /* wait until we get a transfer done or error */ - timeout = jiffies + HZ/100 + 1; /* 10ms */ - /* first read usually delivers bogus results... */ - saa7146_i2c_status(dev); - while(1) { - status = saa7146_i2c_status(dev); - if ((status & 0x3) != 1) - break; - if (time_after(jiffies,timeout)) { - /* this is normal when probing the bus - * (no answer from nonexisistant device...) - */ - printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n", - dev->name, __func__); - return -EIO; - } - if (++trial < 50 && short_delay) - udelay(10); - else - msleep(1); - } - } - - /* give a detailed status report */ - if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR | - SAA7146_I2C_DTERR | SAA7146_I2C_DRERR | - SAA7146_I2C_AL | SAA7146_I2C_ERR | - SAA7146_I2C_BUSY)) ) { - - if ( 0 == (status & SAA7146_I2C_ERR) || - 0 == (status & SAA7146_I2C_BUSY) ) { - /* it may take some time until ERR goes high - ignore */ - DEB_I2C(("unexpected i2c status %04x\n", status)); - } - if( 0 != (status & SAA7146_I2C_SPERR) ) { - DEB_I2C(("error due to invalid start/stop condition.\n")); - } - if( 0 != (status & SAA7146_I2C_DTERR) ) { - DEB_I2C(("error in data transmission.\n")); - } - if( 0 != (status & SAA7146_I2C_DRERR) ) { - DEB_I2C(("error when receiving data.\n")); - } - if( 0 != (status & SAA7146_I2C_AL) ) { - DEB_I2C(("error because arbitration lost.\n")); - } - - /* we handle address-errors here */ - if( 0 != (status & SAA7146_I2C_APERR) ) { - DEB_I2C(("error in address phase.\n")); - return -EREMOTEIO; - } - - return -EIO; - } - - /* read back data, just in case we were reading ... */ - *dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER)); - - DEB_I2C(("after: 0x%08x\n",*dword)); - return 0; -} - -static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) -{ - int i = 0, count = 0; - __le32 *buffer = dev->d_i2c.cpu_addr; - int err = 0; - int short_delay = 0; - - if (mutex_lock_interruptible(&dev->i2c_lock)) - return -ERESTARTSYS; - - for(i=0;i count ) { - err = -1; - goto out; - } - - if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) ) - short_delay = 1; - - do { - /* reset the i2c-device if necessary */ - err = saa7146_i2c_reset(dev); - if ( 0 > err ) { - DEB_I2C(("could not reset i2c-device.\n")); - goto out; - } - - /* write out the u32s one after another */ - for(i = 0; i < count; i++) { - err = saa7146_i2c_writeout(dev, &buffer[i], short_delay); - if ( 0 != err) { - /* this one is unsatisfying: some i2c slaves on some - dvb cards don't acknowledge correctly, so the saa7146 - thinks that an address error occured. in that case, the - transaction should be retrying, even if an address error - occured. analog saa7146 based cards extensively rely on - i2c address probing, however, and address errors indicate that a - device is really *not* there. retrying in that case - increases the time the device needs to probe greatly, so - it should be avoided. So we bail out in irq mode after an - address error and trust the saa7146 address error detection. */ - if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) - goto out; - DEB_I2C(("error while sending message(s). starting again.\n")); - break; - } - } - if( 0 == err ) { - err = num; - break; - } - - /* delay a bit before retrying */ - msleep(10); - - } while (err != num && retries--); - - /* quit if any error occurred */ - if (err != num) - goto out; - - /* if any things had to be read, get the results */ - if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) { - DEB_I2C(("could not cleanup i2c-message.\n")); - err = -1; - goto out; - } - - /* return the number of delivered messages */ - DEB_I2C(("transmission successful. (msg:%d).\n",err)); -out: - /* another bug in revision 0: the i2c-registers get uploaded randomly by other - uploads, so we better clear them out before continueing */ - if( 0 == dev->revision ) { - __le32 zero = 0; - saa7146_i2c_reset(dev); - if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) { - INFO(("revision 0 error. this should never happen.\n")); - } - } - - mutex_unlock(&dev->i2c_lock); - return err; -} - -/* utility functions */ -static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) -{ - struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); - struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev); - - /* use helper function to transfer data */ - return saa7146_i2c_transfer(dev, msg, num, adapter->retries); -} - - -/*****************************************************************************/ -/* i2c-adapter helper functions */ - -/* exported algorithm data */ -static struct i2c_algorithm saa7146_algo = { - .master_xfer = saa7146_i2c_xfer, - .functionality = saa7146_i2c_func, -}; - -int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate) -{ - DEB_EE(("bitrate: 0x%08x\n",bitrate)); - - /* enable i2c-port pins */ - saa7146_write(dev, MC1, (MASK_08 | MASK_24)); - - dev->i2c_bitrate = bitrate; - saa7146_i2c_reset(dev); - - if (i2c_adapter) { - i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev); - i2c_adapter->dev.parent = &dev->pci->dev; - i2c_adapter->algo = &saa7146_algo; - i2c_adapter->algo_data = NULL; - i2c_adapter->timeout = SAA7146_I2C_TIMEOUT; - i2c_adapter->retries = SAA7146_I2C_RETRIES; - } - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_vbi.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,510 +0,0 @@ -#include - -static int vbi_pixel_to_capture = 720 * 2; - -static int vbi_workaround(struct saa7146_dev *dev) -{ - struct saa7146_vv *vv = dev->vv_data; - - u32 *cpu; - dma_addr_t dma_addr; - - int count = 0; - int i; - - DECLARE_WAITQUEUE(wait, current); - - DEB_VBI(("dev:%p\n",dev)); - - /* once again, a bug in the saa7146: the brs acquisition - is buggy and especially the BXO-counter does not work - as specified. there is this workaround, but please - don't let me explain it. ;-) */ - - cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr); - if (NULL == cpu) - return -ENOMEM; - - /* setup some basic programming, just for the workaround */ - saa7146_write(dev, BASE_EVEN3, dma_addr); - saa7146_write(dev, BASE_ODD3, dma_addr+vbi_pixel_to_capture); - saa7146_write(dev, PROT_ADDR3, dma_addr+4096); - saa7146_write(dev, PITCH3, vbi_pixel_to_capture); - saa7146_write(dev, BASE_PAGE3, 0x0); - saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0)); - saa7146_write(dev, MC2, MASK_04|MASK_20); - - /* load brs-control register */ - WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); - /* BXO = 1h, BRS to outbound */ - WRITE_RPS1(0xc000008c); - /* wait for vbi_a or vbi_b*/ - if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { - DEB_D(("...using port b\n")); - WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B); - WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B); -/* - WRITE_RPS1(CMD_PAUSE | MASK_09); -*/ - } else { - DEB_D(("...using port a\n")); - WRITE_RPS1(CMD_PAUSE | MASK_10); - } - /* upload brs */ - WRITE_RPS1(CMD_UPLOAD | MASK_08); - /* load brs-control register */ - WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); - /* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */ - WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19); - /* wait for brs_done */ - WRITE_RPS1(CMD_PAUSE | MASK_08); - /* upload brs */ - WRITE_RPS1(CMD_UPLOAD | MASK_08); - /* load video-dma3 NumLines3 and NumBytes3 */ - WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4)); - /* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */ - WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture)); - /* load brs-control register */ - WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); - /* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */ - WRITE_RPS1((540 << 7) | (5 << 19)); // 5 == vbi_start - /* wait for brs_done */ - WRITE_RPS1(CMD_PAUSE | MASK_08); - /* upload brs and video-dma3*/ - WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04); - /* load mc2 register: enable dma3 */ - WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4)); - WRITE_RPS1(MASK_20 | MASK_04); - /* generate interrupt */ - WRITE_RPS1(CMD_INTERRUPT); - /* stop rps1 */ - WRITE_RPS1(CMD_STOP); - - /* we have to do the workaround twice to be sure that - everything is ok */ - for(i = 0; i < 2; i++) { - - /* indicate to the irq handler that we do the workaround */ - saa7146_write(dev, MC2, MASK_31|MASK_15); - - saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0)); - saa7146_write(dev, MC2, MASK_04|MASK_20); - - /* enable rps1 irqs */ - SAA7146_IER_ENABLE(dev,MASK_28); - - /* prepare to wait to be woken up by the irq-handler */ - add_wait_queue(&vv->vbi_wq, &wait); - current->state = TASK_INTERRUPTIBLE; - - /* start rps1 to enable workaround */ - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - saa7146_write(dev, MC1, (MASK_13 | MASK_29)); - - schedule(); - - DEB_VBI(("brs bug workaround %d/1.\n",i)); - - remove_wait_queue(&vv->vbi_wq, &wait); - current->state = TASK_RUNNING; - - /* disable rps1 irqs */ - SAA7146_IER_DISABLE(dev,MASK_28); - - /* stop video-dma3 */ - saa7146_write(dev, MC1, MASK_20); - - if(signal_pending(current)) { - - DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1))); - - /* stop rps1 for sure */ - saa7146_write(dev, MC1, MASK_29); - - pci_free_consistent(dev->pci, 4096, cpu, dma_addr); - return -EINTR; - } - } - - pci_free_consistent(dev->pci, 4096, cpu, dma_addr); - return 0; -} - -static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) -{ - struct saa7146_vv *vv = dev->vv_data; - - struct saa7146_video_dma vdma3; - - int count = 0; - unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; - unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; - -/* - vdma3.base_even = 0xc8000000+2560*70; - vdma3.base_odd = 0xc8000000; - vdma3.prot_addr = 0xc8000000+2560*164; - vdma3.pitch = 2560; - vdma3.base_page = 0; - vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above! -*/ - vdma3.base_even = buf->pt[2].offset; - vdma3.base_odd = buf->pt[2].offset + 16 * vbi_pixel_to_capture; - vdma3.prot_addr = buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture; - vdma3.pitch = vbi_pixel_to_capture; - vdma3.base_page = buf->pt[2].dma | ME1; - vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture; - - saa7146_write_out_dma(dev, 3, &vdma3); - - /* write beginning of rps-program */ - count = 0; - - /* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */ - - /* we don't wait here for the first field anymore. this is different from the video - capture and might cause that the first buffer is only half filled (with only - one field). but since this is some sort of streaming data, this is not that negative. - but by doing this, we can use the whole engine from videobuf-dma-sg.c... */ - -/* - WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait); - WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait); -*/ - /* set bit 1 */ - WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4)); - WRITE_RPS1(MASK_28 | MASK_12); - - /* turn on video-dma3 */ - WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4)); - WRITE_RPS1(MASK_04 | MASK_20); /* => mask */ - WRITE_RPS1(MASK_04 | MASK_20); /* => values */ - - /* wait for o_fid_a/b / e_fid_a/b toggle */ - WRITE_RPS1(CMD_PAUSE | o_wait); - WRITE_RPS1(CMD_PAUSE | e_wait); - - /* generate interrupt */ - WRITE_RPS1(CMD_INTERRUPT); - - /* stop */ - WRITE_RPS1(CMD_STOP); - - /* enable rps1 irqs */ - SAA7146_IER_ENABLE(dev, MASK_28); - - /* write the address of the rps-program */ - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - - /* turn on rps */ - saa7146_write(dev, MC1, (MASK_13 | MASK_29)); -} - -static int buffer_activate(struct saa7146_dev *dev, - struct saa7146_buf *buf, - struct saa7146_buf *next) -{ - struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = VIDEOBUF_ACTIVE; - - DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next)); - saa7146_set_vbi_capture(dev,buf,next); - - mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT); - return 0; -} - -static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field) -{ - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_buf *buf = (struct saa7146_buf *)vb; - - int err = 0; - int lines, llength, size; - - lines = 16 * 2 ; /* 2 fields */ - llength = vbi_pixel_to_capture; - size = lines * llength; - - DEB_VBI(("vb:%p\n",vb)); - - if (0 != buf->vb.baddr && buf->vb.bsize < size) { - DEB_VBI(("size mismatch.\n")); - return -EINVAL; - } - - if (buf->vb.size != size) - saa7146_dma_free(dev,q,buf); - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - buf->vb.width = llength; - buf->vb.height = lines; - buf->vb.size = size; - buf->vb.field = field; // FIXME: check this - - saa7146_pgtable_free(dev->pci, &buf->pt[2]); - saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); - - err = videobuf_iolock(q,&buf->vb, NULL); - if (err) - goto oops; - err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], - dma->sglist, dma->sglen); - if (0 != err) - return err; - } - buf->vb.state = VIDEOBUF_PREPARED; - buf->activate = buffer_activate; - - return 0; - - oops: - DEB_VBI(("error out.\n")); - saa7146_dma_free(dev,q,buf); - - return err; -} - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - int llength,lines; - - lines = 16 * 2 ; /* 2 fields */ - llength = vbi_pixel_to_capture; - - *size = lines * llength; - *count = 2; - - DEB_VBI(("count:%d, size:%d\n",*count,*size)); - - return 0; -} - -static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_buf *buf = (struct saa7146_buf *)vb; - - DEB_VBI(("vb:%p\n",vb)); - saa7146_buffer_queue(dev,&vv->vbi_q,buf); -} - -static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_buf *buf = (struct saa7146_buf *)vb; - - DEB_VBI(("vb:%p\n",vb)); - saa7146_dma_free(dev,q,buf); -} - -static struct videobuf_queue_ops vbi_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ */ - -static void vbi_stop(struct saa7146_fh *fh, struct file *file) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - unsigned long flags; - DEB_VBI(("dev:%p, fh:%p\n",dev, fh)); - - spin_lock_irqsave(&dev->slock,flags); - - /* disable rps1 */ - saa7146_write(dev, MC1, MASK_29); - - /* disable rps1 irqs */ - SAA7146_IER_DISABLE(dev, MASK_28); - - /* shut down dma 3 transfers */ - saa7146_write(dev, MC1, MASK_20); - - if (vv->vbi_q.curr) { - saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); - } - - videobuf_queue_cancel(&fh->vbi_q); - - vv->vbi_streaming = NULL; - - del_timer(&vv->vbi_q.timeout); - del_timer(&fh->vbi_read_timeout); - - spin_unlock_irqrestore(&dev->slock, flags); -} - -static void vbi_read_timeout(unsigned long data) -{ - struct file *file = (struct file*)data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - - DEB_VBI(("dev:%p, fh:%p\n",dev, fh)); - - vbi_stop(fh, file); -} - -static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) -{ - DEB_VBI(("dev:%p\n",dev)); - - INIT_LIST_HEAD(&vv->vbi_q.queue); - - init_timer(&vv->vbi_q.timeout); - vv->vbi_q.timeout.function = saa7146_buffer_timeout; - vv->vbi_q.timeout.data = (unsigned long)(&vv->vbi_q); - vv->vbi_q.dev = dev; - - init_waitqueue_head(&vv->vbi_wq); -} - -static int vbi_open(struct saa7146_dev *dev, struct file *file) -{ - struct saa7146_fh *fh = file->private_data; - - u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); - int ret = 0; - - DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); - - ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS); - if (0 == ret) { - DEB_S(("cannot get vbi RESOURCE_DMA3_BRS resource\n")); - return -EBUSY; - } - - /* adjust arbitrition control for video dma 3 */ - arbtr_ctrl &= ~0x1f0000; - arbtr_ctrl |= 0x1d0000; - saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); - saa7146_write(dev, MC2, (MASK_04|MASK_20)); - - memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt)); - - fh->vbi_fmt.sampling_rate = 27000000; - fh->vbi_fmt.offset = 248; /* todo */ - fh->vbi_fmt.samples_per_line = vbi_pixel_to_capture; - fh->vbi_fmt.sample_format = V4L2_PIX_FMT_GREY; - - /* fixme: this only works for PAL */ - fh->vbi_fmt.start[0] = 5; - fh->vbi_fmt.count[0] = 16; - fh->vbi_fmt.start[1] = 312; - fh->vbi_fmt.count[1] = 16; - - videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, // FIXME: does this really work? - sizeof(struct saa7146_buf), - file, &dev->v4l2_lock); - - init_timer(&fh->vbi_read_timeout); - fh->vbi_read_timeout.function = vbi_read_timeout; - fh->vbi_read_timeout.data = (unsigned long)file; - - /* initialize the brs */ - if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { - saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19)); - } else { - saa7146_write(dev, BRS_CTRL, 0x00000001); - - if (0 != (ret = vbi_workaround(dev))) { - DEB_VBI(("vbi workaround failed!\n")); - /* return ret;*/ - } - } - - /* upload brs register */ - saa7146_write(dev, MC2, (MASK_08|MASK_24)); - return 0; -} - -static void vbi_close(struct saa7146_dev *dev, struct file *file) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_vv *vv = dev->vv_data; - DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); - - if( fh == vv->vbi_streaming ) { - vbi_stop(fh, file); - } - saa7146_res_free(fh, RESOURCE_DMA3_BRS); -} - -static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) -{ - struct saa7146_vv *vv = dev->vv_data; - spin_lock(&dev->slock); - - if (vv->vbi_q.curr) { - DEB_VBI(("dev:%p, curr:%p\n",dev,vv->vbi_q.curr)); - /* this must be += 2, one count for each field */ - vv->vbi_fieldcount+=2; - vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount; - saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); - } else { - DEB_VBI(("dev:%p\n",dev)); - } - saa7146_buffer_next(dev,&vv->vbi_q,1); - - spin_unlock(&dev->slock); -} - -static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - ssize_t ret = 0; - - DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); - - if( NULL == vv->vbi_streaming ) { - // fixme: check if dma3 is available - // fixme: activate vbi engine here if necessary. (really?) - vv->vbi_streaming = fh; - } - - if( fh != vv->vbi_streaming ) { - DEB_VBI(("open %p is already using vbi capture.",vv->vbi_streaming)); - return -EBUSY; - } - - mod_timer(&fh->vbi_read_timeout, jiffies+BUFFER_TIMEOUT); - ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); -/* - printk("BASE_ODD3: 0x%08x\n", saa7146_read(dev, BASE_ODD3)); - printk("BASE_EVEN3: 0x%08x\n", saa7146_read(dev, BASE_EVEN3)); - printk("PROT_ADDR3: 0x%08x\n", saa7146_read(dev, PROT_ADDR3)); - printk("PITCH3: 0x%08x\n", saa7146_read(dev, PITCH3)); - printk("BASE_PAGE3: 0x%08x\n", saa7146_read(dev, BASE_PAGE3)); - printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3)); - printk("BRS_CTRL: 0x%08x\n", saa7146_read(dev, BRS_CTRL)); -*/ - return ret; -} - -struct saa7146_use_ops saa7146_vbi_uops = { - .init = vbi_init, - .open = vbi_open, - .release = vbi_close, - .irq_done = vbi_irq_done, - .read = vbi_read, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/saa7146_video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1429 +0,0 @@ -#include -#include - -static int max_memory = 32; - -module_param(max_memory, int, 0644); -MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)"); - -#define IS_CAPTURE_ACTIVE(fh) \ - (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh)) - -#define IS_OVERLAY_ACTIVE(fh) \ - (((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh)) - -/* format descriptions for capture and preview */ -static struct saa7146_format formats[] = { - { - .name = "RGB-8 (3-3-2)", - .pixelformat = V4L2_PIX_FMT_RGB332, - .trans = RGB08_COMPOSED, - .depth = 8, - .flags = 0, - }, { - .name = "RGB-16 (5/B-6/G-5/R)", - .pixelformat = V4L2_PIX_FMT_RGB565, - .trans = RGB16_COMPOSED, - .depth = 16, - .flags = 0, - }, { - .name = "RGB-24 (B-G-R)", - .pixelformat = V4L2_PIX_FMT_BGR24, - .trans = RGB24_COMPOSED, - .depth = 24, - .flags = 0, - }, { - .name = "RGB-32 (B-G-R)", - .pixelformat = V4L2_PIX_FMT_BGR32, - .trans = RGB32_COMPOSED, - .depth = 32, - .flags = 0, - }, { - .name = "RGB-32 (R-G-B)", - .pixelformat = V4L2_PIX_FMT_RGB32, - .trans = RGB32_COMPOSED, - .depth = 32, - .flags = 0, - .swap = 0x2, - }, { - .name = "Greyscale-8", - .pixelformat = V4L2_PIX_FMT_GREY, - .trans = Y8, - .depth = 8, - .flags = 0, - }, { - .name = "YUV 4:2:2 planar (Y-Cb-Cr)", - .pixelformat = V4L2_PIX_FMT_YUV422P, - .trans = YUV422_DECOMPOSED, - .depth = 16, - .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, - }, { - .name = "YVU 4:2:0 planar (Y-Cb-Cr)", - .pixelformat = V4L2_PIX_FMT_YVU420, - .trans = YUV420_DECOMPOSED, - .depth = 12, - .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, - }, { - .name = "YUV 4:2:0 planar (Y-Cb-Cr)", - .pixelformat = V4L2_PIX_FMT_YUV420, - .trans = YUV420_DECOMPOSED, - .depth = 12, - .flags = FORMAT_IS_PLANAR, - }, { - .name = "YUV 4:2:2 (U-Y-V-Y)", - .pixelformat = V4L2_PIX_FMT_UYVY, - .trans = YUV422_COMPOSED, - .depth = 16, - .flags = 0, - } -}; - -/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps. - due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped - (like V4L2_PIX_FMT_YUYV) ... 8-( */ - -static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format); - -struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc) -{ - int i, j = NUM_FORMATS; - - for (i = 0; i < j; i++) { - if (formats[i].pixelformat == fourcc) { - return formats+i; - } - } - - DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc)); - return NULL; -} - -static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f); - -int saa7146_start_preview(struct saa7146_fh *fh) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - struct v4l2_format fmt; - int ret = 0, err = 0; - - DEB_EE(("dev:%p, fh:%p\n",dev,fh)); - - /* check if we have overlay informations */ - if( NULL == fh->ov.fh ) { - DEB_D(("no overlay data available. try S_FMT first.\n")); - return -EAGAIN; - } - - /* check if streaming capture is running */ - if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("streaming capture is active.\n")); - return -EBUSY; - } - - /* check if overlay is running */ - if (IS_OVERLAY_ACTIVE(fh) != 0) { - if (vv->video_fh == fh) { - DEB_D(("overlay is already active.\n")); - return 0; - } - DEB_D(("overlay is already active in another open.\n")); - return -EBUSY; - } - - if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { - DEB_D(("cannot get necessary overlay resources\n")); - return -EBUSY; - } - - fmt.fmt.win = fh->ov.win; - err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt); - if (0 != err) { - saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); - return -EBUSY; - } - fh->ov.win = fmt.fmt.win; - vv->ov_data = &fh->ov; - - DEB_D(("%dx%d+%d+%d %s field=%s\n", - fh->ov.win.w.width,fh->ov.win.w.height, - fh->ov.win.w.left,fh->ov.win.w.top, - vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field])); - - if (0 != (ret = saa7146_enable_overlay(fh))) { - DEB_D(("enabling overlay failed: %d\n",ret)); - saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); - return ret; - } - - vv->video_status = STATUS_OVERLAY; - vv->video_fh = fh; - - return 0; -} -EXPORT_SYMBOL_GPL(saa7146_start_preview); - -int saa7146_stop_preview(struct saa7146_fh *fh) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - - DEB_EE(("dev:%p, fh:%p\n",dev,fh)); - - /* check if streaming capture is running */ - if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("streaming capture is active.\n")); - return -EBUSY; - } - - /* check if overlay is running at all */ - if ((vv->video_status & STATUS_OVERLAY) == 0) { - DEB_D(("no active overlay.\n")); - return 0; - } - - if (vv->video_fh != fh) { - DEB_D(("overlay is active, but in another open.\n")); - return -EBUSY; - } - - vv->video_status = 0; - vv->video_fh = NULL; - - saa7146_disable_overlay(fh); - - saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); - - return 0; -} -EXPORT_SYMBOL_GPL(saa7146_stop_preview); - -/********************************************************************************/ -/* device controls */ - -static struct v4l2_queryctrl controls[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128, - .type = V4L2_CTRL_TYPE_INTEGER, - .flags = V4L2_CTRL_FLAG_SLIDER, - },{ - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .type = V4L2_CTRL_TYPE_INTEGER, - .flags = V4L2_CTRL_FLAG_SLIDER, - },{ - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .type = V4L2_CTRL_TYPE_INTEGER, - .flags = V4L2_CTRL_FLAG_SLIDER, - },{ - .id = V4L2_CID_VFLIP, - .name = "Vertical Flip", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_HFLIP, - .name = "Horizontal Flip", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, -}; -static int NUM_CONTROLS = sizeof(controls)/sizeof(struct v4l2_queryctrl); - -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 0) - -static struct v4l2_queryctrl* ctrl_by_id(int id) -{ - int i; - - for (i = 0; i < NUM_CONTROLS; i++) - if (controls[i].id == id) - return controls+i; - return NULL; -} - -/********************************************************************************/ -/* common pagetable functions */ - -static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) -{ - struct pci_dev *pci = dev->pci; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - struct scatterlist *list = dma->sglist; - int length = dma->sglen; - struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); - - DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); - - if( 0 != IS_PLANAR(sfmt->trans)) { - struct saa7146_pgtable *pt1 = &buf->pt[0]; - struct saa7146_pgtable *pt2 = &buf->pt[1]; - struct saa7146_pgtable *pt3 = &buf->pt[2]; - __le32 *ptr1, *ptr2, *ptr3; - __le32 fill; - - int size = buf->fmt->width*buf->fmt->height; - int i,p,m1,m2,m3,o1,o2; - - switch( sfmt->depth ) { - case 12: { - /* create some offsets inside the page table */ - m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; - m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1; - m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; - o1 = size%PAGE_SIZE; - o2 = (size+(size/4))%PAGE_SIZE; - DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); - break; - } - case 16: { - /* create some offsets inside the page table */ - m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; - m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; - m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1; - o1 = size%PAGE_SIZE; - o2 = (size+(size/2))%PAGE_SIZE; - DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); - break; - } - default: { - return -1; - } - } - - ptr1 = pt1->cpu; - ptr2 = pt2->cpu; - ptr3 = pt3->cpu; - - /* walk all pages, copy all page addresses to ptr1 */ - for (i = 0; i < length; i++, list++) { - for (p = 0; p * 4096 < list->length; p++, ptr1++) { - *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset); - } - } -/* - ptr1 = pt1->cpu; - for(j=0;j<40;j++) { - printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); - } -*/ - - /* if we have a user buffer, the first page may not be - aligned to a page boundary. */ - pt1->offset = dma->sglist->offset; - pt2->offset = pt1->offset+o1; - pt3->offset = pt1->offset+o2; - - /* create video-dma2 page table */ - ptr1 = pt1->cpu; - for(i = m1; i <= m2 ; i++, ptr2++) { - *ptr2 = ptr1[i]; - } - fill = *(ptr2-1); - for(;i<1024;i++,ptr2++) { - *ptr2 = fill; - } - /* create video-dma3 page table */ - ptr1 = pt1->cpu; - for(i = m2; i <= m3; i++,ptr3++) { - *ptr3 = ptr1[i]; - } - fill = *(ptr3-1); - for(;i<1024;i++,ptr3++) { - *ptr3 = fill; - } - /* finally: finish up video-dma1 page table */ - ptr1 = pt1->cpu+m1; - fill = pt1->cpu[m1]; - for(i=m1;i<1024;i++,ptr1++) { - *ptr1 = fill; - } -/* - ptr1 = pt1->cpu; - ptr2 = pt2->cpu; - ptr3 = pt3->cpu; - for(j=0;j<40;j++) { - printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); - } - for(j=0;j<40;j++) { - printk("ptr2 %d: 0x%08x\n",j,ptr2[j]); - } - for(j=0;j<40;j++) { - printk("ptr3 %d: 0x%08x\n",j,ptr3[j]); - } -*/ - } else { - struct saa7146_pgtable *pt = &buf->pt[0]; - return saa7146_pgtable_build_single(pci, pt, list, length); - } - - return 0; -} - - -/********************************************************************************/ -/* file operations */ - -static int video_begin(struct saa7146_fh *fh) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_format *fmt = NULL; - unsigned int resource; - int ret = 0, err = 0; - - DEB_EE(("dev:%p, fh:%p\n",dev,fh)); - - if ((vv->video_status & STATUS_CAPTURE) != 0) { - if (vv->video_fh == fh) { - DEB_S(("already capturing.\n")); - return 0; - } - DEB_S(("already capturing in another open.\n")); - return -EBUSY; - } - - if ((vv->video_status & STATUS_OVERLAY) != 0) { - DEB_S(("warning: suspending overlay video for streaming capture.\n")); - vv->ov_suspend = vv->video_fh; - err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ - if (0 != err) { - DEB_D(("suspending video failed. aborting\n")); - return err; - } - } - - fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); - /* we need to have a valid format set here */ - BUG_ON(NULL == fmt); - - if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { - resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; - } else { - resource = RESOURCE_DMA1_HPS; - } - - ret = saa7146_res_get(fh, resource); - if (0 == ret) { - DEB_S(("cannot get capture resource %d\n",resource)); - if (vv->ov_suspend != NULL) { - saa7146_start_preview(vv->ov_suspend); - vv->ov_suspend = NULL; - } - return -EBUSY; - } - - /* clear out beginning of streaming bit (rps register 0)*/ - saa7146_write(dev, MC2, MASK_27 ); - - /* enable rps0 irqs */ - SAA7146_IER_ENABLE(dev, MASK_27); - - vv->video_fh = fh; - vv->video_status = STATUS_CAPTURE; - - return 0; -} - -static int video_end(struct saa7146_fh *fh, struct file *file) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_format *fmt = NULL; - unsigned long flags; - unsigned int resource; - u32 dmas = 0; - DEB_EE(("dev:%p, fh:%p\n",dev,fh)); - - if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { - DEB_S(("not capturing.\n")); - return 0; - } - - if (vv->video_fh != fh) { - DEB_S(("capturing, but in another open.\n")); - return -EBUSY; - } - - fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); - /* we need to have a valid format set here */ - BUG_ON(NULL == fmt); - - if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { - resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; - dmas = MASK_22 | MASK_21 | MASK_20; - } else { - resource = RESOURCE_DMA1_HPS; - dmas = MASK_22; - } - spin_lock_irqsave(&dev->slock,flags); - - /* disable rps0 */ - saa7146_write(dev, MC1, MASK_28); - - /* disable rps0 irqs */ - SAA7146_IER_DISABLE(dev, MASK_27); - - /* shut down all used video dma transfers */ - saa7146_write(dev, MC1, dmas); - - spin_unlock_irqrestore(&dev->slock, flags); - - vv->video_fh = NULL; - vv->video_status = 0; - - saa7146_res_free(fh, resource); - - if (vv->ov_suspend != NULL) { - saa7146_start_preview(vv->ov_suspend); - vv->ov_suspend = NULL; - } - - return 0; -} - -static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - - strcpy((char *)cap->driver, "saa7146 v4l2"); - strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); - sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7146_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->capabilities |= dev->ext_vv_data->capabilities; - return 0; -} - -static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct saa7146_vv *vv = dev->vv_data; - - *fb = vv->ov_fb; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - return 0; -} - -static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_format *fmt; - - DEB_EE(("VIDIOC_S_FBUF\n")); - - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* check args */ - fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; - - /* planar formats are not allowed for overlay video, clipping and video dma would clash */ - if (fmt->flags & FORMAT_IS_PLANAR) - DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n", - (char *)&fmt->pixelformat)); - - /* check if overlay is running */ - if (IS_OVERLAY_ACTIVE(fh) != 0) { - if (vv->video_fh != fh) { - DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); - return -EBUSY; - } - } - - /* ok, accept it */ - vv->ov_fb = *fb; - vv->ov_fmt = fmt; - - if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) { - vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8; - DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline)); - } - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) -{ - if (f->index >= NUM_FORMATS) - return -EINVAL; - strlcpy((char *)f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].pixelformat; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - - ctrl = ctrl_by_id(c->id); - if (ctrl == NULL) - return -EINVAL; - - DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id)); - *c = *ctrl; - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct saa7146_vv *vv = dev->vv_data; - const struct v4l2_queryctrl *ctrl; - u32 value = 0; - - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) - return -EINVAL; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - value = saa7146_read(dev, BCS_CTRL); - c->value = 0xff & (value >> 24); - DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value)); - break; - case V4L2_CID_CONTRAST: - value = saa7146_read(dev, BCS_CTRL); - c->value = 0x7f & (value >> 16); - DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value)); - break; - case V4L2_CID_SATURATION: - value = saa7146_read(dev, BCS_CTRL); - c->value = 0x7f & (value >> 0); - DEB_D(("V4L2_CID_SATURATION: %d\n", c->value)); - break; - case V4L2_CID_VFLIP: - c->value = vv->vflip; - DEB_D(("V4L2_CID_VFLIP: %d\n", c->value)); - break; - case V4L2_CID_HFLIP: - c->value = vv->hflip; - DEB_D(("V4L2_CID_HFLIP: %d\n", c->value)); - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct saa7146_vv *vv = dev->vv_data; - const struct v4l2_queryctrl *ctrl; - - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) { - DEB_D(("unknown control %d\n", c->id)); - return -EINVAL; - } - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER: - if (c->value < ctrl->minimum) - c->value = ctrl->minimum; - if (c->value > ctrl->maximum) - c->value = ctrl->maximum; - break; - default: - /* nothing */; - } - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: { - u32 value = saa7146_read(dev, BCS_CTRL); - value &= 0x00ffffff; - value |= (c->value << 24); - saa7146_write(dev, BCS_CTRL, value); - saa7146_write(dev, MC2, MASK_22 | MASK_06); - break; - } - case V4L2_CID_CONTRAST: { - u32 value = saa7146_read(dev, BCS_CTRL); - value &= 0xff00ffff; - value |= (c->value << 16); - saa7146_write(dev, BCS_CTRL, value); - saa7146_write(dev, MC2, MASK_22 | MASK_06); - break; - } - case V4L2_CID_SATURATION: { - u32 value = saa7146_read(dev, BCS_CTRL); - value &= 0xffffff00; - value |= (c->value << 0); - saa7146_write(dev, BCS_CTRL, value); - saa7146_write(dev, MC2, MASK_22 | MASK_06); - break; - } - case V4L2_CID_HFLIP: - /* fixme: we can support changing VFLIP and HFLIP here... */ - if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("V4L2_CID_HFLIP while active capture.\n")); - return -EBUSY; - } - vv->hflip = c->value; - break; - case V4L2_CID_VFLIP: - if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("V4L2_CID_VFLIP while active capture.\n")); - return -EBUSY; - } - vv->vflip = c->value; - break; - default: - return -EINVAL; - } - - if (IS_OVERLAY_ACTIVE(fh) != 0) { - saa7146_stop_preview(fh); - saa7146_start_preview(fh); - } - return 0; -} - -static int vidioc_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct saa7146_vv *vv = dev->vv_data; - - parm->parm.capture.readbuffers = 1; - v4l2_video_std_frame_period(vv->standard->id, - &parm->parm.capture.timeperframe); - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) -{ - f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt; - return 0; -} - -static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) -{ - f->fmt.win = ((struct saa7146_fh *)fh)->ov.win; - return 0; -} - -static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f) -{ - f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt; - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_format *fmt; - enum v4l2_field field; - int maxw, maxh; - int calc_bpl; - - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); - - fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - maxw = vv->standard->h_max_out; - maxh = vv->standard->v_max_out; - - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh / 2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - switch (field) { - case V4L2_FIELD_ALTERNATE: - vv->last_field = V4L2_FIELD_TOP; - maxh = maxh / 2; - break; - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - vv->last_field = V4L2_FIELD_INTERLACED; - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - vv->last_field = V4L2_FIELD_INTERLACED; - break; - default: - DEB_D(("no known field mode '%d'.\n", field)); - return -EINVAL; - } - - f->fmt.pix.field = field; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - - calc_bpl = (f->fmt.pix.width * fmt->depth) / 8; - - if (f->fmt.pix.bytesperline < calc_bpl) - f->fmt.pix.bytesperline = calc_bpl; - - if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */ - f->fmt.pix.bytesperline = calc_bpl; - - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; - DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width, - f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage)); - - return 0; -} - - -static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct saa7146_vv *vv = dev->vv_data; - struct v4l2_window *win = &f->fmt.win; - enum v4l2_field field; - int maxw, maxh; - - DEB_EE(("dev:%p\n", dev)); - - if (NULL == vv->ov_fb.base) { - DEB_D(("no fb base set.\n")); - return -EINVAL; - } - if (NULL == vv->ov_fmt) { - DEB_D(("no fb fmt set.\n")); - return -EINVAL; - } - if (win->w.width < 48 || win->w.height < 32) { - DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height)); - return -EINVAL; - } - if (win->clipcount > 16) { - DEB_D(("clipcount too big.\n")); - return -EINVAL; - } - - field = win->field; - maxw = vv->standard->h_max_out; - maxh = vv->standard->v_max_out; - - if (V4L2_FIELD_ANY == field) { - field = (win->w.height > maxh / 2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - DEB_D(("no known field mode '%d'.\n", field)); - return -EINVAL; - } - - win->field = field; - if (win->w.width > maxw) - win->w.width = maxw; - if (win->w.height > maxh) - win->w.height = maxh; - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f) -{ - struct saa7146_fh *fh = __fh; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - int err; - - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); - if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_EE(("streaming capture is active\n")); - return -EBUSY; - } - err = vidioc_try_fmt_vid_cap(file, fh, f); - if (0 != err) - return err; - fh->video_fmt = f->fmt.pix; - DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat)); - return 0; -} - -static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f) -{ - struct saa7146_fh *fh = __fh; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - int err; - - DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh)); - err = vidioc_try_fmt_vid_overlay(file, fh, f); - if (0 != err) - return err; - fh->ov.win = f->fmt.win; - fh->ov.nclips = f->fmt.win.clipcount; - if (fh->ov.nclips > 16) - fh->ov.nclips = 16; - if (copy_from_user(fh->ov.clips, f->fmt.win.clips, - sizeof(struct v4l2_clip) * fh->ov.nclips)) { - return -EFAULT; - } - - /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ - fh->ov.fh = fh; - - /* check if our current overlay is active */ - if (IS_OVERLAY_ACTIVE(fh) != 0) { - saa7146_stop_preview(fh); - saa7146_start_preview(fh); - } - return 0; -} - -static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct saa7146_vv *vv = dev->vv_data; - - *norm = vv->standard->id; - return 0; -} - - /* the saa7146 supfhrts (used in conjunction with the saa7111a for example) - PAL / NTSC / SECAM. if your hardware does not (or does more) - -- override this function in your extension */ -/* - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - if (e->index < 0 ) - return -EINVAL; - if( e->index < dev->ext_vv_data->num_stds ) { - DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index)); - v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name); - return 0; - } - return -EINVAL; - } - */ - -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct saa7146_vv *vv = dev->vv_data; - int found = 0; - int err, i; - - DEB_EE(("VIDIOC_S_STD\n")); - - if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { - DEB_D(("cannot change video standard while streaming capture is active\n")); - return -EBUSY; - } - - if ((vv->video_status & STATUS_OVERLAY) != 0) { - vv->ov_suspend = vv->video_fh; - err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ - if (0 != err) { - DEB_D(("suspending video failed. aborting\n")); - return err; - } - } - - for (i = 0; i < dev->ext_vv_data->num_stds; i++) - if (*id & dev->ext_vv_data->stds[i].id) - break; - if (i != dev->ext_vv_data->num_stds) { - vv->standard = &dev->ext_vv_data->stds[i]; - if (NULL != dev->ext_vv_data->std_callback) - dev->ext_vv_data->std_callback(dev, vv->standard); - found = 1; - } - - if (vv->ov_suspend != NULL) { - saa7146_start_preview(vv->ov_suspend); - vv->ov_suspend = NULL; - } - - if (!found) { - DEB_EE(("VIDIOC_S_STD: standard not found.\n")); - return -EINVAL; - } - - DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name)); - return 0; -} - -static int vidioc_overlay(struct file *file, void *fh, unsigned int on) -{ - int err; - - DEB_D(("VIDIOC_OVERLAY on:%d\n", on)); - if (on) - err = saa7146_start_preview(fh); - else - err = saa7146_stop_preview(fh); - return err; -} - -static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b) -{ - struct saa7146_fh *fh = __fh; - - if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return videobuf_reqbufs(&fh->video_q, b); - if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE) - return videobuf_reqbufs(&fh->vbi_q, b); - return -EINVAL; -} - -static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) -{ - struct saa7146_fh *fh = __fh; - - if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return videobuf_querybuf(&fh->video_q, buf); - if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) - return videobuf_querybuf(&fh->vbi_q, buf); - return -EINVAL; -} - -static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) -{ - struct saa7146_fh *fh = __fh; - - if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return videobuf_qbuf(&fh->video_q, buf); - if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) - return videobuf_qbuf(&fh->vbi_q, buf); - return -EINVAL; -} - -static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) -{ - struct saa7146_fh *fh = __fh; - - if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK); - if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) - return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK); - return -EINVAL; -} - -static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) -{ - struct saa7146_fh *fh = __fh; - int err; - - DEB_D(("VIDIOC_STREAMON, type:%d\n", type)); - - err = video_begin(fh); - if (err) - return err; - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return videobuf_streamon(&fh->video_q); - if (type == V4L2_BUF_TYPE_VBI_CAPTURE) - return videobuf_streamon(&fh->vbi_q); - return -EINVAL; -} - -static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) -{ - struct saa7146_fh *fh = __fh; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - int err; - - DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type)); - - /* ugly: we need to copy some checks from video_end(), - because videobuf_streamoff() relies on the capture running. - check and fix this */ - if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { - DEB_S(("not capturing.\n")); - return 0; - } - - if (vv->video_fh != fh) { - DEB_S(("capturing, but in another open.\n")); - return -EBUSY; - } - - err = -EINVAL; - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - err = videobuf_streamoff(&fh->video_q); - else if (type == V4L2_BUF_TYPE_VBI_CAPTURE) - err = videobuf_streamoff(&fh->vbi_q); - if (0 != err) { - DEB_D(("warning: videobuf_streamoff() failed.\n")); - video_end(fh, file); - } else { - err = video_end(fh, file); - } - return err; -} - -static int vidioc_g_chip_ident(struct file *file, void *__fh, - struct v4l2_dbg_chip_ident *chip) -{ - struct saa7146_fh *fh = __fh; - struct saa7146_dev *dev = fh->dev; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (chip->match.type == V4L2_CHIP_MATCH_HOST && !chip->match.addr) { - chip->ident = V4L2_IDENT_SAA7146; - return 0; - } - return v4l2_device_call_until_err(&dev->v4l2_dev, 0, - core, g_chip_ident, chip); -} - -const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, - .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, - .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, - .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, - .vidioc_g_chip_ident = vidioc_g_chip_ident, - - .vidioc_overlay = vidioc_overlay, - .vidioc_g_fbuf = vidioc_g_fbuf, - .vidioc_s_fbuf = vidioc_s_fbuf, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_g_std = vidioc_g_std, - .vidioc_s_std = vidioc_s_std, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_parm = vidioc_g_parm, -}; - -/*********************************************************************************/ -/* buffer handling functions */ - -static int buffer_activate (struct saa7146_dev *dev, - struct saa7146_buf *buf, - struct saa7146_buf *next) -{ - struct saa7146_vv *vv = dev->vv_data; - - buf->vb.state = VIDEOBUF_ACTIVE; - saa7146_set_capture(dev,buf,next); - - mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT); - return 0; -} - -static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf) -{ - saa7146_pgtable_free(dev->pci, &buf->pt[0]); - saa7146_pgtable_free(dev->pci, &buf->pt[1]); - saa7146_pgtable_free(dev->pci, &buf->pt[2]); -} - -static int buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_buf *buf = (struct saa7146_buf *)vb; - int size,err = 0; - - DEB_CAP(("vbuf:%p\n",vb)); - - /* sanity checks */ - if (fh->video_fmt.width < 48 || - fh->video_fmt.height < 32 || - fh->video_fmt.width > vv->standard->h_max_out || - fh->video_fmt.height > vv->standard->v_max_out) { - DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height)); - return -EINVAL; - } - - size = fh->video_fmt.sizeimage; - if (0 != buf->vb.baddr && buf->vb.bsize < size) { - DEB_D(("size mismatch.\n")); - return -EINVAL; - } - - DEB_CAP(("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n", - fh->video_fmt.width,fh->video_fmt.height,size,v4l2_field_names[fh->video_fmt.field])); - if (buf->vb.width != fh->video_fmt.width || - buf->vb.bytesperline != fh->video_fmt.bytesperline || - buf->vb.height != fh->video_fmt.height || - buf->vb.size != size || - buf->vb.field != field || - buf->vb.field != fh->video_fmt.field || - buf->fmt != &fh->video_fmt) { - saa7146_dma_free(dev,q,buf); - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - struct saa7146_format *sfmt; - - buf->vb.bytesperline = fh->video_fmt.bytesperline; - buf->vb.width = fh->video_fmt.width; - buf->vb.height = fh->video_fmt.height; - buf->vb.size = size; - buf->vb.field = field; - buf->fmt = &fh->video_fmt; - buf->vb.field = fh->video_fmt.field; - - sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); - - release_all_pagetables(dev, buf); - if( 0 != IS_PLANAR(sfmt->trans)) { - saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); - saa7146_pgtable_alloc(dev->pci, &buf->pt[1]); - saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); - } else { - saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); - } - - err = videobuf_iolock(q,&buf->vb, &vv->ov_fb); - if (err) - goto oops; - err = saa7146_pgtable_build(dev,buf); - if (err) - goto oops; - } - buf->vb.state = VIDEOBUF_PREPARED; - buf->activate = buffer_activate; - - return 0; - - oops: - DEB_D(("error out.\n")); - saa7146_dma_free(dev,q,buf); - - return err; -} - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - - if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS) - *count = MAX_SAA7146_CAPTURE_BUFFERS; - - *size = fh->video_fmt.sizeimage; - - /* check if we exceed the "max_memory" parameter */ - if( (*count * *size) > (max_memory*1048576) ) { - *count = (max_memory*1048576) / *size; - } - - DEB_CAP(("%d buffers, %d bytes each.\n",*count,*size)); - - return 0; -} - -static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_buf *buf = (struct saa7146_buf *)vb; - - DEB_CAP(("vbuf:%p\n",vb)); - saa7146_buffer_queue(fh->dev,&vv->video_q,buf); -} - -static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct file *file = q->priv_data; - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_buf *buf = (struct saa7146_buf *)vb; - - DEB_CAP(("vbuf:%p\n",vb)); - - saa7146_dma_free(dev,q,buf); - - release_all_pagetables(dev, buf); -} - -static struct videobuf_queue_ops video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/********************************************************************************/ -/* file operations */ - -static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv) -{ - INIT_LIST_HEAD(&vv->video_q.queue); - - init_timer(&vv->video_q.timeout); - vv->video_q.timeout.function = saa7146_buffer_timeout; - vv->video_q.timeout.data = (unsigned long)(&vv->video_q); - vv->video_q.dev = dev; - - /* set some default values */ - vv->standard = &dev->ext_vv_data->stds[0]; - - /* FIXME: what's this? */ - vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A; - vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A; -} - - -static int video_open(struct saa7146_dev *dev, struct file *file) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_format *sfmt; - - fh->video_fmt.width = 384; - fh->video_fmt.height = 288; - fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24; - fh->video_fmt.bytesperline = 0; - fh->video_fmt.field = V4L2_FIELD_ANY; - sfmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); - fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; - - videobuf_queue_sg_init(&fh->video_q, &video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct saa7146_buf), - file, &dev->v4l2_lock); - - return 0; -} - - -static void video_close(struct saa7146_dev *dev, struct file *file) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_vv *vv = dev->vv_data; - struct videobuf_queue *q = &fh->video_q; - int err; - - if (IS_CAPTURE_ACTIVE(fh) != 0) { - err = video_end(fh, file); - } else if (IS_OVERLAY_ACTIVE(fh) != 0) { - err = saa7146_stop_preview(fh); - } - - videobuf_stop(q); - - /* hmm, why is this function declared void? */ - /* return err */ -} - - -static void video_irq_done(struct saa7146_dev *dev, unsigned long st) -{ - struct saa7146_vv *vv = dev->vv_data; - struct saa7146_dmaqueue *q = &vv->video_q; - - spin_lock(&dev->slock); - DEB_CAP(("called.\n")); - - /* only finish the buffer if we have one... */ - if( NULL != q->curr ) { - saa7146_buffer_finish(dev,q,VIDEOBUF_DONE); - } - saa7146_buffer_next(dev,q,0); - - spin_unlock(&dev->slock); -} - -static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - ssize_t ret = 0; - - DEB_EE(("called.\n")); - - if ((vv->video_status & STATUS_CAPTURE) != 0) { - /* fixme: should we allow read() captures while streaming capture? */ - if (vv->video_fh == fh) { - DEB_S(("already capturing.\n")); - return -EBUSY; - } - DEB_S(("already capturing in another open.\n")); - return -EBUSY; - } - - ret = video_begin(fh); - if( 0 != ret) { - goto out; - } - - ret = videobuf_read_one(&fh->video_q , data, count, ppos, - file->f_flags & O_NONBLOCK); - if (ret != 0) { - video_end(fh, file); - } else { - ret = video_end(fh, file); - } -out: - /* restart overlay if it was active before */ - if (vv->ov_suspend != NULL) { - saa7146_start_preview(vv->ov_suspend); - vv->ov_suspend = NULL; - } - - return ret; -} - -struct saa7146_use_ops saa7146_video_uops = { - .init = video_init, - .open = video_open, - .release = video_close, - .irq_done = video_irq_done, - .read = video_read, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,189 +0,0 @@ -config MEDIA_ATTACH - bool "Load and attach frontend and tuner driver modules as needed" - depends on VIDEO_MEDIA - depends on MODULES - help - Remove the static dependency of DVB card drivers on all - frontend modules for all possible card variants. Instead, - allow the card drivers to only load the frontend modules - they require. - - Also, tuner module will automatically load a tuner driver - when needed, for analog mode. - - This saves several KBytes of memory. - - Note: You will need module-init-tools v3.2 or later for this feature. - - If unsure say Y. - -config MEDIA_TUNER - tristate - default VIDEO_MEDIA && I2C - depends on VIDEO_MEDIA && I2C - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE - -config MEDIA_TUNER_CUSTOMISE - bool "Customize analog and hybrid tuner modules to build" - depends on MEDIA_TUNER - default y if EXPERT - help - This allows the user to deselect tuner drivers unnecessary - for their hardware from the build. Use this option with care - as deselecting tuner drivers which are in fact necessary will - result in V4L/DVB devices which cannot be tuned due to lack of - driver support - - If unsure say N. - -menu "Customize TV tuners" - visible if MEDIA_TUNER_CUSTOMISE - -config MEDIA_TUNER_SIMPLE - tristate "Simple tuner support" - depends on VIDEO_MEDIA && I2C - select MEDIA_TUNER_TDA9887 - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for various simple tuners. - -config MEDIA_TUNER_TDA8290 - tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" - depends on VIDEO_MEDIA && I2C - select MEDIA_TUNER_TDA827X - select MEDIA_TUNER_TDA18271 - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for Philips TDA8290+8275(a) tuner. - -config MEDIA_TUNER_TDA827X - tristate "Philips TDA827X silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A DVB-T silicon tuner module. Say Y when you want to support this tuner. - -config MEDIA_TUNER_TDA18271 - tristate "NXP TDA18271 silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A silicon tuner module. Say Y when you want to support this tuner. - -config MEDIA_TUNER_TDA9887 - tristate "TDA 9885/6/7 analog IF demodulator" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for Philips TDA9885/6/7 - analog IF demodulator. - -config MEDIA_TUNER_TEA5761 - tristate "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on VIDEO_MEDIA && I2C - depends on EXPERIMENTAL - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for the Philips TEA5761 radio tuner. - -config MEDIA_TUNER_TEA5767 - tristate "TEA 5767 radio tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for the Philips TEA5767 radio tuner. - -config MEDIA_TUNER_MT20XX - tristate "Microtune 2032 / 2050 tuners" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for the MT2032 / MT2050 tuner. - -config MEDIA_TUNER_MT2060 - tristate "Microtune MT2060 silicon IF tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon IF tuner MT2060 from Microtune. - -config MEDIA_TUNER_MT2266 - tristate "Microtune MT2266 silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon baseband tuner MT2266 from Microtune. - -config MEDIA_TUNER_MT2131 - tristate "Microtune MT2131 silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon baseband tuner MT2131 from Microtune. - -config MEDIA_TUNER_QT1010 - tristate "Quantek QT1010 silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner QT1010 from Quantek. - -config MEDIA_TUNER_XC2028 - tristate "XCeive xc2028/xc3028 tuners" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to include support for the xc2028/xc3028 tuners. - -config MEDIA_TUNER_XC5000 - tristate "Xceive XC5000 silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner XC5000 from Xceive. - This device is only used inside a SiP called together with a - demodulator for now. - -config MEDIA_TUNER_MXL5005S - tristate "MaxLinear MSL5005S silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner MXL5005S from MaxLinear. - -config MEDIA_TUNER_MXL5007T - tristate "MaxLinear MxL5007T silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner MxL5007T from MaxLinear. - -config MEDIA_TUNER_MC44S803 - tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Freescale MC44S803 based tuners - -config MEDIA_TUNER_MAX2165 - tristate "Maxim MAX2165 silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - A driver for the silicon tuner MAX2165 from Maxim. - -config MEDIA_TUNER_TDA18218 - tristate "NXP TDA18218 silicon tuner" - depends on VIDEO_MEDIA && I2C - default m if MEDIA_TUNER_CUSTOMISE - help - NXP TDA18218 silicon tuner driver. -endmenu diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -# -# Makefile for common V4L/DVB tuners -# - -tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o - -obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o -obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o -# tuner-types will be merged into tuner-simple, in the future -obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o -obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o -obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o -obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o -obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o -obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o -obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o -obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o -obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o -obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o -obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o -obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o -obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o -obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o -obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o -obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o -obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,441 +0,0 @@ -/* - * Driver for Maxim MAX2165 silicon tuner - * - * Copyright (c) 2009 David T. L. Wong - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "max2165.h" -#include "max2165_priv.h" -#include "tuner-i2c.h" - -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "max2165: " args); \ - } while (0) - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data) -{ - int ret; - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; - - msg.addr = priv->config->i2c_address; - - if (debug >= 2) - dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data); - - ret = i2c_transfer(priv->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", - __func__, reg, data, ret); - - return (ret != 1) ? -EIO : 0; -} - -static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data) -{ - int ret; - u8 dev_addr = priv->config->i2c_address; - - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 }, - { .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }, - }; - - ret = i2c_transfer(priv->i2c, msg, 2); - if (ret != 2) { - dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret); - return -EIO; - } - - *p_data = b1[0]; - if (debug >= 2) - dprintk("%s: reg=0x%02X, data=0x%02X\n", - __func__, reg, b1[0]); - return 0; -} - -static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg, - u8 mask, u8 data) -{ - int ret; - u8 v; - - data &= mask; - ret = max2165_read_reg(priv, reg, &v); - if (ret != 0) - return ret; - v &= ~mask; - v |= data; - ret = max2165_write_reg(priv, reg, v); - - return ret; -} - -static int max2165_read_rom_table(struct max2165_priv *priv) -{ - u8 dat[3]; - int i; - - for (i = 0; i < 3; i++) { - max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1); - max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]); - } - - priv->tf_ntch_low_cfg = dat[0] >> 4; - priv->tf_ntch_hi_cfg = dat[0] & 0x0F; - priv->tf_balun_low_ref = dat[1] & 0x0F; - priv->tf_balun_hi_ref = dat[1] >> 4; - priv->bb_filter_7mhz_cfg = dat[2] & 0x0F; - priv->bb_filter_8mhz_cfg = dat[2] >> 4; - - dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg); - dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg); - dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref); - dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref); - dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg); - dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg); - - return 0; -} - -static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/) -{ - u8 v; - - v = (osc / 2); - if (v == 2) - v = 0x7; - else - v -= 8; - - max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v); - - return 0; -} - -static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw) -{ - u8 val; - - if (bw == BANDWIDTH_8_MHZ) - val = priv->bb_filter_8mhz_cfg; - else - val = priv->bb_filter_7mhz_cfg; - - max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4); - - return 0; -} - -int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction) -{ - u32 remainder; - u32 q, f = 0; - int i; - - if (0 == divisor) - return -1; - - q = dividend / divisor; - remainder = dividend - q * divisor; - - for (i = 0; i < 31; i++) { - remainder <<= 1; - if (remainder >= divisor) { - f += 1; - remainder -= divisor; - } - f <<= 1; - } - - *quotient = q; - *fraction = f; - - return 0; -} - -static int max2165_set_rf(struct max2165_priv *priv, u32 freq) -{ - u8 tf; - u8 tf_ntch; - u32 t; - u32 quotient, fraction; - - /* Set PLL divider according to RF frequency */ - fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, - "ient, &fraction); - - /* 20-bit fraction */ - fraction >>= 12; - - max2165_write_reg(priv, REG_NDIV_INT, quotient); - max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16); - max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8); - max2165_write_reg(priv, REG_NDIV_FRAC0, fraction); - - /* Norch Filter */ - tf_ntch = (freq < 725000000) ? - priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg; - - /* Tracking filter balun */ - t = priv->tf_balun_low_ref; - t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref) - * (freq / 1000 - 470000) / (780000 - 470000); - - tf = t; - dprintk("tf = %X\n", tf); - tf |= tf_ntch << 4; - - max2165_write_reg(priv, REG_TRACK_FILTER, tf); - - return 0; -} - -static void max2165_debug_status(struct max2165_priv *priv) -{ - u8 status, autotune; - u8 auto_vco_success, auto_vco_active; - u8 pll_locked; - u8 dc_offset_low, dc_offset_hi; - u8 signal_lv_over_threshold; - u8 vco, vco_sub_band, adc; - - max2165_read_reg(priv, REG_STATUS, &status); - max2165_read_reg(priv, REG_AUTOTUNE, &autotune); - - auto_vco_success = (status >> 6) & 0x01; - auto_vco_active = (status >> 5) & 0x01; - pll_locked = (status >> 4) & 0x01; - dc_offset_low = (status >> 3) & 0x01; - dc_offset_hi = (status >> 2) & 0x01; - signal_lv_over_threshold = status & 0x01; - - vco = autotune >> 6; - vco_sub_band = (autotune >> 3) & 0x7; - adc = autotune & 0x7; - - dprintk("auto VCO active: %d, auto VCO success: %d\n", - auto_vco_active, auto_vco_success); - dprintk("PLL locked: %d\n", pll_locked); - dprintk("DC offset low: %d, DC offset high: %d\n", - dc_offset_low, dc_offset_hi); - dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold); - dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc); -} - -static int max2165_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct max2165_priv *priv = fe->tuner_priv; - int ret; - - dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency); - if (fe->ops.info.type == FE_ATSC) { - return -EINVAL; - } else if (fe->ops.info.type == FE_OFDM) { - dprintk("%s() OFDM\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - return -EINVAL; - case BANDWIDTH_7_MHZ: - case BANDWIDTH_8_MHZ: - priv->frequency = params->frequency; - priv->bandwidth = params->u.ofdm.bandwidth; - break; - default: - printk(KERN_ERR "MAX2165 bandwidth not set!\n"); - return -EINVAL; - } - } else { - printk(KERN_ERR "MAX2165 modulation type not supported!\n"); - return -EINVAL; - } - - dprintk("%s() frequency=%d\n", __func__, priv->frequency); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - max2165_set_bandwidth(priv, priv->bandwidth); - ret = max2165_set_rf(priv, priv->frequency); - mdelay(50); - max2165_debug_status(priv); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (ret != 0) - return -EREMOTEIO; - - return 0; -} - -static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq) -{ - struct max2165_priv *priv = fe->tuner_priv; - dprintk("%s()\n", __func__); - *freq = priv->frequency; - return 0; -} - -static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw) -{ - struct max2165_priv *priv = fe->tuner_priv; - dprintk("%s()\n", __func__); - - *bw = priv->bandwidth; - return 0; -} - -static int max2165_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct max2165_priv *priv = fe->tuner_priv; - u16 lock_status = 0; - - dprintk("%s()\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - max2165_debug_status(priv); - *status = lock_status; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int max2165_sleep(struct dvb_frontend *fe) -{ - dprintk("%s()\n", __func__); - return 0; -} - -static int max2165_init(struct dvb_frontend *fe) -{ - struct max2165_priv *priv = fe->tuner_priv; - dprintk("%s()\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* Setup initial values */ - /* Fractional Mode on */ - max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18); - /* LNA on */ - max2165_write_reg(priv, REG_LNA, 0x01); - max2165_write_reg(priv, REG_PLL_CFG, 0x7A); - max2165_write_reg(priv, REG_TEST, 0x08); - max2165_write_reg(priv, REG_SHUTDOWN, 0x40); - max2165_write_reg(priv, REG_VCO_CTRL, 0x84); - max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3); - max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75); - max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00); - max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00); - - max2165_set_osc(priv, priv->config->osc_clk); - - max2165_read_rom_table(priv); - - max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int max2165_release(struct dvb_frontend *fe) -{ - struct max2165_priv *priv = fe->tuner_priv; - dprintk("%s()\n", __func__); - - kfree(priv); - fe->tuner_priv = NULL; - - return 0; -} - -static const struct dvb_tuner_ops max2165_tuner_ops = { - .info = { - .name = "Maxim MAX2165", - .frequency_min = 470000000, - .frequency_max = 780000000, - .frequency_step = 50000, - }, - - .release = max2165_release, - .init = max2165_init, - .sleep = max2165_sleep, - - .set_params = max2165_set_params, - .set_analog_params = NULL, - .get_frequency = max2165_get_frequency, - .get_bandwidth = max2165_get_bandwidth, - .get_status = max2165_get_status -}; - -struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct max2165_config *cfg) -{ - struct max2165_priv *priv = NULL; - - dprintk("%s(%d-%04x)\n", __func__, - i2c ? i2c_adapter_id(i2c) : -1, - cfg ? cfg->i2c_address : -1); - - priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - priv->config = cfg; - priv->i2c = i2c; - fe->tuner_priv = priv; - - max2165_init(fe); - max2165_debug_status(priv); - - return fe; -} -EXPORT_SYMBOL(max2165_attach); - -MODULE_AUTHOR("David T. L. Wong "); -MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - * Driver for Maxim MAX2165 silicon tuner - * - * Copyright (c) 2009 David T. L. Wong - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __MAX2165_H__ -#define __MAX2165_H__ - -struct dvb_frontend; -struct i2c_adapter; - -struct max2165_config { - u8 i2c_address; - u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */ -}; - -#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \ - (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE)) -extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct max2165_config *cfg); -#else -static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct max2165_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/max2165_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/* - * Driver for Maxim MAX2165 silicon tuner - * - * Copyright (c) 2009 David T. L. Wong - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __MAX2165_PRIV_H__ -#define __MAX2165_PRIV_H__ - -#define REG_NDIV_INT 0x00 -#define REG_NDIV_FRAC2 0x01 -#define REG_NDIV_FRAC1 0x02 -#define REG_NDIV_FRAC0 0x03 -#define REG_TRACK_FILTER 0x04 -#define REG_LNA 0x05 -#define REG_PLL_CFG 0x06 -#define REG_TEST 0x07 -#define REG_SHUTDOWN 0x08 -#define REG_VCO_CTRL 0x09 -#define REG_BASEBAND_CTRL 0x0A -#define REG_DC_OFFSET_CTRL 0x0B -#define REG_DC_OFFSET_DAC 0x0C -#define REG_ROM_TABLE_ADDR 0x0D - -/* Read Only Registers */ -#define REG_ROM_TABLE_DATA 0x10 -#define REG_STATUS 0x11 -#define REG_AUTOTUNE 0x12 - -struct max2165_priv { - struct max2165_config *config; - struct i2c_adapter *i2c; - - u32 frequency; - u32 bandwidth; - - u8 tf_ntch_low_cfg; - u8 tf_ntch_hi_cfg; - u8 tf_balun_low_ref; - u8 tf_balun_hi_ref; - u8 bb_filter_7mhz_cfg; - u8 bb_filter_8mhz_cfg; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,372 +0,0 @@ -/* - * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner - * - * Copyright (c) 2009 Jochen Friedrich - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "mc44s803.h" -#include "mc44s803_priv.h" - -#define mc_printk(level, format, arg...) \ - printk(level "mc44s803: " format , ## arg) - -/* Writes a single register */ -static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val) -{ - u8 buf[3]; - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3 - }; - - buf[0] = (val & 0xff0000) >> 16; - buf[1] = (val & 0xff00) >> 8; - buf[2] = (val & 0xff); - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - mc_printk(KERN_WARNING, "I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -/* Reads a single register */ -static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val) -{ - u32 wval; - u8 buf[3]; - int ret; - struct i2c_msg msg[] = { - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, - .buf = buf, .len = 3 }, - }; - - wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) | - MC44S803_REG_SM(reg, MC44S803_D); - - ret = mc44s803_writereg(priv, wval); - if (ret) - return ret; - - if (i2c_transfer(priv->i2c, msg, 1) != 1) { - mc_printk(KERN_WARNING, "I2C read failed\n"); - return -EREMOTEIO; - } - - *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; - - return 0; -} - -static int mc44s803_release(struct dvb_frontend *fe) -{ - struct mc44s803_priv *priv = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(priv); - - return 0; -} - -static int mc44s803_init(struct dvb_frontend *fe) -{ - struct mc44s803_priv *priv = fe->tuner_priv; - u32 val; - int err; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - -/* Reset chip */ - val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_RS); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - -/* Power Up and Start Osc */ - - val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | - MC44S803_REG_SM(0xC0, MC44S803_REFOSC) | - MC44S803_REG_SM(1, MC44S803_OSCSEL); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) | - MC44S803_REG_SM(0x200, MC44S803_POWER); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - msleep(10); - - val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | - MC44S803_REG_SM(0x40, MC44S803_REFOSC) | - MC44S803_REG_SM(1, MC44S803_OSCSEL); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - msleep(20); - -/* Setup Mixer */ - - val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_TRI_STATE) | - MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - -/* Setup Cirquit Adjust */ - - val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_G1) | - MC44S803_REG_SM(1, MC44S803_G3) | - MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | - MC44S803_REG_SM(1, MC44S803_G6) | - MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | - MC44S803_REG_SM(0x3, MC44S803_LP) | - MC44S803_REG_SM(1, MC44S803_CLRF) | - MC44S803_REG_SM(1, MC44S803_CLIF); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_G1) | - MC44S803_REG_SM(1, MC44S803_G3) | - MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | - MC44S803_REG_SM(1, MC44S803_G6) | - MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | - MC44S803_REG_SM(0x3, MC44S803_LP); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - -/* Setup Digtune */ - - val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | - MC44S803_REG_SM(3, MC44S803_XOD); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - -/* Setup AGC */ - - val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_AT1) | - MC44S803_REG_SM(1, MC44S803_AT2) | - MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) | - MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) | - MC44S803_REG_SM(1, MC44S803_LNA0); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - return 0; - -exit: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - mc_printk(KERN_WARNING, "I/O Error\n"); - return err; -} - -static int mc44s803_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct mc44s803_priv *priv = fe->tuner_priv; - u32 r1, r2, n1, n2, lo1, lo2, freq, val; - int err; - - priv->frequency = params->frequency; - - r1 = MC44S803_OSC / 1000000; - r2 = MC44S803_OSC / 100000; - - n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000; - freq = MC44S803_OSC / r1 * n1; - lo1 = ((60 * n1) + (r1 / 2)) / r1; - freq = freq - params->frequency; - - n2 = (freq - MC44S803_IF2 + 50000) / 100000; - lo2 = ((60 * n2) + (r2 / 2)) / r2; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) | - MC44S803_REG_SM(r1-1, MC44S803_R1) | - MC44S803_REG_SM(r2-1, MC44S803_R2) | - MC44S803_REG_SM(1, MC44S803_REFBUF_EN); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) | - MC44S803_REG_SM(n1-2, MC44S803_LO1); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) | - MC44S803_REG_SM(n2-2, MC44S803_LO2); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | - MC44S803_REG_SM(1, MC44S803_DA) | - MC44S803_REG_SM(lo1, MC44S803_LO_REF) | - MC44S803_REG_SM(1, MC44S803_AT); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | - MC44S803_REG_SM(2, MC44S803_DA) | - MC44S803_REG_SM(lo2, MC44S803_LO_REF) | - MC44S803_REG_SM(1, MC44S803_AT); - - err = mc44s803_writereg(priv, val); - if (err) - goto exit; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; - -exit: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - mc_printk(KERN_WARNING, "I/O Error\n"); - return err; -} - -static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mc44s803_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static const struct dvb_tuner_ops mc44s803_tuner_ops = { - .info = { - .name = "Freescale MC44S803", - .frequency_min = 48000000, - .frequency_max = 1000000000, - .frequency_step = 100000, - }, - - .release = mc44s803_release, - .init = mc44s803_init, - .set_params = mc44s803_set_params, - .get_frequency = mc44s803_get_frequency -}; - -/* This functions tries to identify a MC44S803 tuner by reading the ID - register. This is hasty. */ -struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct mc44s803_config *cfg) -{ - struct mc44s803_priv *priv; - u32 reg; - u8 id; - int ret; - - reg = 0; - - priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - priv->fe = fe; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = mc44s803_readreg(priv, MC44S803_REG_ID, ®); - if (ret) - goto error; - - id = MC44S803_REG_MS(reg, MC44S803_ID); - - if (id != 0x14) { - mc_printk(KERN_ERR, "unsupported ID " - "(%x should be 0x14)\n", id); - goto error; - } - - mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id); - memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return fe; - -error: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - kfree(priv); - return NULL; -} -EXPORT_SYMBOL(mc44s803_attach); - -MODULE_AUTHOR("Jochen Friedrich"); -MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner - * - * Copyright (c) 2009 Jochen Friedrich - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef MC44S803_H -#define MC44S803_H - -struct dvb_frontend; -struct i2c_adapter; - -struct mc44s803_config { - u8 i2c_address; - u8 dig_out; -}; - -#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \ - (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE)) -extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct mc44s803_config *cfg); -#else -static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct mc44s803_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_MEDIA_TUNER_MC44S803 */ - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mc44s803_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,208 +0,0 @@ -/* - * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner - * - * Copyright (c) 2009 Jochen Friedrich - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef MC44S803_PRIV_H -#define MC44S803_PRIV_H - -/* This driver is based on the information available in the datasheet - http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf - - SPI or I2C Address : 0xc0-0xc6 - - Reg.No | Function - ------------------------------------------- - 00 | Power Down - 01 | Reference Oszillator - 02 | Reference Dividers - 03 | Mixer and Reference Buffer - 04 | Reset/Serial Out - 05 | LO 1 - 06 | LO 2 - 07 | Circuit Adjust - 08 | Test - 09 | Digital Tune - 0A | LNA AGC - 0B | Data Register Address - 0C | Regulator Test - 0D | VCO Test - 0E | LNA Gain/Input Power - 0F | ID Bits - -*/ - -#define MC44S803_OSC 26000000 /* 26 MHz */ -#define MC44S803_IF1 1086000000 /* 1086 MHz */ -#define MC44S803_IF2 36125000 /* 36.125 MHz */ - -#define MC44S803_REG_POWER 0 -#define MC44S803_REG_REFOSC 1 -#define MC44S803_REG_REFDIV 2 -#define MC44S803_REG_MIXER 3 -#define MC44S803_REG_RESET 4 -#define MC44S803_REG_LO1 5 -#define MC44S803_REG_LO2 6 -#define MC44S803_REG_CIRCADJ 7 -#define MC44S803_REG_TEST 8 -#define MC44S803_REG_DIGTUNE 9 -#define MC44S803_REG_LNAAGC 0x0A -#define MC44S803_REG_DATAREG 0x0B -#define MC44S803_REG_REGTEST 0x0C -#define MC44S803_REG_VCOTEST 0x0D -#define MC44S803_REG_LNAGAIN 0x0E -#define MC44S803_REG_ID 0x0F - -/* Register definitions */ -#define MC44S803_ADDR 0x0F -#define MC44S803_ADDR_S 0 -/* REG_POWER */ -#define MC44S803_POWER 0xFFFFF0 -#define MC44S803_POWER_S 4 -/* REG_REFOSC */ -#define MC44S803_REFOSC 0x1FF0 -#define MC44S803_REFOSC_S 4 -#define MC44S803_OSCSEL 0x2000 -#define MC44S803_OSCSEL_S 13 -/* REG_REFDIV */ -#define MC44S803_R2 0x1FF0 -#define MC44S803_R2_S 4 -#define MC44S803_REFBUF_EN 0x2000 -#define MC44S803_REFBUF_EN_S 13 -#define MC44S803_R1 0x7C000 -#define MC44S803_R1_S 14 -/* REG_MIXER */ -#define MC44S803_R3 0x70 -#define MC44S803_R3_S 4 -#define MC44S803_MUX3 0x80 -#define MC44S803_MUX3_S 7 -#define MC44S803_MUX4 0x100 -#define MC44S803_MUX4_S 8 -#define MC44S803_OSC_SCR 0x200 -#define MC44S803_OSC_SCR_S 9 -#define MC44S803_TRI_STATE 0x400 -#define MC44S803_TRI_STATE_S 10 -#define MC44S803_BUF_GAIN 0x800 -#define MC44S803_BUF_GAIN_S 11 -#define MC44S803_BUF_IO 0x1000 -#define MC44S803_BUF_IO_S 12 -#define MC44S803_MIXER_RES 0xFE000 -#define MC44S803_MIXER_RES_S 13 -/* REG_RESET */ -#define MC44S803_RS 0x10 -#define MC44S803_RS_S 4 -#define MC44S803_SO 0x20 -#define MC44S803_SO_S 5 -/* REG_LO1 */ -#define MC44S803_LO1 0xFFF0 -#define MC44S803_LO1_S 4 -/* REG_LO2 */ -#define MC44S803_LO2 0x7FFF0 -#define MC44S803_LO2_S 4 -/* REG_CIRCADJ */ -#define MC44S803_G1 0x20 -#define MC44S803_G1_S 5 -#define MC44S803_G3 0x80 -#define MC44S803_G3_S 7 -#define MC44S803_CIRCADJ_RES 0x300 -#define MC44S803_CIRCADJ_RES_S 8 -#define MC44S803_G6 0x400 -#define MC44S803_G6_S 10 -#define MC44S803_G7 0x800 -#define MC44S803_G7_S 11 -#define MC44S803_S1 0x1000 -#define MC44S803_S1_S 12 -#define MC44S803_LP 0x7E000 -#define MC44S803_LP_S 13 -#define MC44S803_CLRF 0x80000 -#define MC44S803_CLRF_S 19 -#define MC44S803_CLIF 0x100000 -#define MC44S803_CLIF_S 20 -/* REG_TEST */ -/* REG_DIGTUNE */ -#define MC44S803_DA 0xF0 -#define MC44S803_DA_S 4 -#define MC44S803_XOD 0x300 -#define MC44S803_XOD_S 8 -#define MC44S803_RST 0x10000 -#define MC44S803_RST_S 16 -#define MC44S803_LO_REF 0x1FFF00 -#define MC44S803_LO_REF_S 8 -#define MC44S803_AT 0x200000 -#define MC44S803_AT_S 21 -#define MC44S803_MT 0x400000 -#define MC44S803_MT_S 22 -/* REG_LNAAGC */ -#define MC44S803_G 0x3F0 -#define MC44S803_G_S 4 -#define MC44S803_AT1 0x400 -#define MC44S803_AT1_S 10 -#define MC44S803_AT2 0x800 -#define MC44S803_AT2_S 11 -#define MC44S803_HL_GR_EN 0x8000 -#define MC44S803_HL_GR_EN_S 15 -#define MC44S803_AGC_AN_DIG 0x10000 -#define MC44S803_AGC_AN_DIG_S 16 -#define MC44S803_ATTEN_EN 0x20000 -#define MC44S803_ATTEN_EN_S 17 -#define MC44S803_AGC_READ_EN 0x40000 -#define MC44S803_AGC_READ_EN_S 18 -#define MC44S803_LNA0 0x80000 -#define MC44S803_LNA0_S 19 -#define MC44S803_AGC_SEL 0x100000 -#define MC44S803_AGC_SEL_S 20 -#define MC44S803_AT0 0x200000 -#define MC44S803_AT0_S 21 -#define MC44S803_B 0xC00000 -#define MC44S803_B_S 22 -/* REG_DATAREG */ -#define MC44S803_D 0xF0 -#define MC44S803_D_S 4 -/* REG_REGTEST */ -/* REG_VCOTEST */ -/* REG_LNAGAIN */ -#define MC44S803_IF_PWR 0x700 -#define MC44S803_IF_PWR_S 8 -#define MC44S803_RF_PWR 0x3800 -#define MC44S803_RF_PWR_S 11 -#define MC44S803_LNA_GAIN 0xFC000 -#define MC44S803_LNA_GAIN_S 14 -/* REG_ID */ -#define MC44S803_ID 0x3E00 -#define MC44S803_ID_S 9 - -/* Some macros to read/write fields */ - -/* First shift, then mask */ -#define MC44S803_REG_SM(_val, _reg) \ - (((_val) << _reg##_S) & (_reg)) - -/* First mask, then shift */ -#define MC44S803_REG_MS(_val, _reg) \ - (((_val) & (_reg)) >> _reg##_S) - -struct mc44s803_priv { - struct mc44s803_config *cfg; - struct i2c_adapter *i2c; - struct dvb_frontend *fe; - - u32 frequency; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,404 +0,0 @@ -/* - * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" - * - * Copyright (c) 2006 Olivier DANET - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "mt2060.h" -#include "mt2060_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0) - -// Reads a single register -static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "mt2060 I2C read failed\n"); - return -EREMOTEIO; - } - return 0; -} - -// Writes a single register -static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 - }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2060 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -// Writes a set of consecutive registers -static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len) -{ - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len - }; - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len); - return -EREMOTEIO; - } - return 0; -} - -// Initialisation sequences -// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49 -static u8 mt2060_config1[] = { - REG_LO1C1, - 0x3F, 0x74, 0x00, 0x08, 0x93 -}; - -// FMCG=2, GP2=0, GP1=0 -static u8 mt2060_config2[] = { - REG_MISC_CTRL, - 0x20, 0x1E, 0x30, 0xff, 0x80, 0xff, 0x00, 0x2c, 0x42 -}; - -// VGAG=3, V1CSE=1 - -#ifdef MT2060_SPURCHECK -/* The function below calculates the frequency offset between the output frequency if2 - and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */ -static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2) -{ - int I,J; - int dia,diamin,diff; - diamin=1000000; - for (I = 1; I < 10; I++) { - J = ((2*I*lo1)/lo2+1)/2; - diff = I*(int)lo1-J*(int)lo2; - if (diff < 0) diff=-diff; - dia = (diff-(int)if2); - if (dia < 0) dia=-dia; - if (diamin > dia) diamin=dia; - } - return diamin; -} - -#define BANDWIDTH 4000 // kHz - -/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */ -static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2) -{ - u32 Spur,Sp1,Sp2; - int I,J; - I=0; - J=1000; - - Spur=mt2060_spurcalc(lo1,lo2,if2); - if (Spur < BANDWIDTH) { - /* Potential spurs detected */ - dprintk("Spurs before : f_lo1: %d f_lo2: %d (kHz)", - (int)lo1,(int)lo2); - I=1000; - Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2); - Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2); - - if (Sp1 < Sp2) { - J=-J; I=-I; Spur=Sp2; - } else - Spur=Sp1; - - while (Spur < BANDWIDTH) { - I += J; - Spur = mt2060_spurcalc(lo1+I,lo2+I,if2); - } - dprintk("Spurs after : f_lo1: %d f_lo2: %d (kHz)", - (int)(lo1+I),(int)(lo2+I)); - } - return I; -} -#endif - -#define IF2 36150 // IF2 frequency = 36.150 MHz -#define FREF 16000 // Quartz oscillator 16 MHz - -static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct mt2060_priv *priv; - int ret=0; - int i=0; - u32 freq; - u8 lnaband; - u32 f_lo1,f_lo2; - u32 div1,num1,div2,num2; - u8 b[8]; - u32 if1; - - priv = fe->tuner_priv; - - if1 = priv->if1_freq; - b[0] = REG_LO1B1; - b[1] = 0xFF; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - mt2060_writeregs(priv,b,2); - - freq = params->frequency / 1000; // Hz -> kHz - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - - f_lo1 = freq + if1 * 1000; - f_lo1 = (f_lo1 / 250) * 250; - f_lo2 = f_lo1 - freq - IF2; - // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise - f_lo2 = ((f_lo2 + 25) / 50) * 50; - priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000, - -#ifdef MT2060_SPURCHECK - // LO-related spurs detection and correction - num1 = mt2060_spurcheck(f_lo1,f_lo2,IF2); - f_lo1 += num1; - f_lo2 += num1; -#endif - //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 ) - num1 = f_lo1 / (FREF / 64); - div1 = num1 / 64; - num1 &= 0x3f; - - // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) - num2 = f_lo2 * 64 / (FREF / 128); - div2 = num2 / 8192; - num2 &= 0x1fff; - - if (freq <= 95000) lnaband = 0xB0; else - if (freq <= 180000) lnaband = 0xA0; else - if (freq <= 260000) lnaband = 0x90; else - if (freq <= 335000) lnaband = 0x80; else - if (freq <= 425000) lnaband = 0x70; else - if (freq <= 480000) lnaband = 0x60; else - if (freq <= 570000) lnaband = 0x50; else - if (freq <= 645000) lnaband = 0x40; else - if (freq <= 730000) lnaband = 0x30; else - if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10; - - b[0] = REG_LO1C1; - b[1] = lnaband | ((num1 >>2) & 0x0F); - b[2] = div1; - b[3] = (num2 & 0x0F) | ((num1 & 3) << 4); - b[4] = num2 >> 4; - b[5] = ((num2 >>12) & 1) | (div2 << 1); - - dprintk("IF1: %dMHz",(int)if1); - dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2); - dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2); - dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]); - - mt2060_writeregs(priv,b,6); - - //Waits for pll lock or timeout - i = 0; - do { - mt2060_readreg(priv,REG_LO_STATUS,b); - if ((b[0] & 0x88)==0x88) - break; - msleep(4); - i++; - } while (i<10); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return ret; -} - -static void mt2060_calibrate(struct mt2060_priv *priv) -{ - u8 b = 0; - int i = 0; - - if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1))) - return; - if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2))) - return; - - /* initialize the clock output */ - mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30); - - do { - b |= (1 << 6); // FM1SS; - mt2060_writereg(priv, REG_LO2C1,b); - msleep(20); - - if (i == 0) { - b |= (1 << 7); // FM1CA; - mt2060_writereg(priv, REG_LO2C1,b); - b &= ~(1 << 7); // FM1CA; - msleep(20); - } - - b &= ~(1 << 6); // FM1SS - mt2060_writereg(priv, REG_LO2C1,b); - - msleep(20); - i++; - } while (i < 9); - - i = 0; - while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0) - msleep(20); - - if (i <= 10) { - mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :) - dprintk("calibration was successful: %d", (int)priv->fmfreq); - } else - dprintk("FMCAL timed out"); -} - -static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mt2060_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mt2060_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static int mt2060_init(struct dvb_frontend *fe) -{ - struct mt2060_priv *priv = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = mt2060_writereg(priv, REG_VGAG, - (priv->cfg->clock_out << 6) | 0x33); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return ret; -} - -static int mt2060_sleep(struct dvb_frontend *fe) -{ - struct mt2060_priv *priv = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = mt2060_writereg(priv, REG_VGAG, - (priv->cfg->clock_out << 6) | 0x30); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return ret; -} - -static int mt2060_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops mt2060_tuner_ops = { - .info = { - .name = "Microtune MT2060", - .frequency_min = 48000000, - .frequency_max = 860000000, - .frequency_step = 50000, - }, - - .release = mt2060_release, - - .init = mt2060_init, - .sleep = mt2060_sleep, - - .set_params = mt2060_set_params, - .get_frequency = mt2060_get_frequency, - .get_bandwidth = mt2060_get_bandwidth -}; - -/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ -struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) -{ - struct mt2060_priv *priv = NULL; - u8 id = 0; - - priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - priv->if1_freq = if1; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) { - kfree(priv); - return NULL; - } - - if (id != PART_REV) { - kfree(priv); - return NULL; - } - printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1); - memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - - mt2060_calibrate(priv); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return fe; -} -EXPORT_SYMBOL(mt2060_attach); - -MODULE_AUTHOR("Olivier DANET"); -MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -/* - * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" - * - * Copyright (c) 2006 Olivier DANET - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef MT2060_H -#define MT2060_H - -struct dvb_frontend; -struct i2c_adapter; - -struct mt2060_config { - u8 i2c_address; - u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ -}; - -#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE)) -extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); -#else -static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_MEDIA_TUNER_MT2060 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2060_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/* - * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" - * - * Copyright (c) 2006 Olivier DANET - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef MT2060_PRIV_H -#define MT2060_PRIV_H - -// Uncomment the #define below to enable spurs checking. The results where quite unconvincing. -// #define MT2060_SPURCHECK - -/* This driver is based on the information available in the datasheet of the - "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map : - - I2C Address : 0x60 - - Reg.No | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | ( defaults ) - -------------------------------------------------------------------------------- - 00 | [ PART ] | [ REV ] | R = 0x63 - 01 | [ LNABAND ] | [ NUM1(5:2) ] | RW = 0x3F - 02 | [ DIV1 ] | RW = 0x74 - 03 | FM1CA | FM1SS | [ NUM1(1:0) ] | [ NUM2(3:0) ] | RW = 0x00 - 04 | NUM2(11:4) ] | RW = 0x08 - 05 | [ DIV2 ] |NUM2(12)| RW = 0x93 - 06 | L1LK | [ TAD1 ] | L2LK | [ TAD2 ] | R - 07 | [ FMF ] | R - 08 | ? | FMCAL | ? | ? | ? | ? | ? | TEMP | R - 09 | 0 | 0 | [ FMGC ] | 0 | GP02 | GP01 | 0 | RW = 0x20 - 0A | ?? - 0B | 0 | 0 | 1 | 1 | 0 | 0 | [ VGAG ] | RW = 0x30 - 0C | V1CSE | 1 | 1 | 1 | 1 | 1 | 1 | 1 | RW = 0xFF - 0D | 1 | 0 | [ V1CS ] | RW = 0xB0 - 0E | ?? - 0F | ?? - 10 | ?? - 11 | [ LOTO ] | 0 | 0 | 1 | 0 | RW = 0x42 - - PART : Part code : 6 for MT2060 - REV : Revision code : 3 for current revision - LNABAND : Input frequency range : ( See code for details ) - NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details ) - FM1CA : Calibration Start Bit - FM1SS : Calibration Single Step bit - L1LK : LO1 Lock Detect - TAD1 : Tune Line ADC ( ? ) - L2LK : LO2 Lock Detect - TAD2 : Tune Line ADC ( ? ) - FMF : Estimated first IF Center frequency Offset ( ? ) - FM1CAL : Calibration done bit - TEMP : On chip temperature sensor - FMCG : Mixer 1 Cap Gain ( ? ) - GP01 / GP02 : Programmable digital outputs. Unconnected pins ? - V1CSE : LO1 VCO Automatic Capacitor Select Enable ( ? ) - V1CS : LO1 Capacitor Selection Value ( ? ) - LOTO : LO Timeout ( ? ) - VGAG : Tuner Output gain -*/ - -#define I2C_ADDRESS 0x60 - -#define REG_PART_REV 0 -#define REG_LO1C1 1 -#define REG_LO1C2 2 -#define REG_LO2C1 3 -#define REG_LO2C2 4 -#define REG_LO2C3 5 -#define REG_LO_STATUS 6 -#define REG_FM_FREQ 7 -#define REG_MISC_STAT 8 -#define REG_MISC_CTRL 9 -#define REG_RESERVED_A 0x0A -#define REG_VGAG 0x0B -#define REG_LO1B1 0x0C -#define REG_LO1B2 0x0D -#define REG_LOTO 0x11 - -#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips - -struct mt2060_priv { - struct mt2060_config *cfg; - struct i2c_adapter *i2c; - - u32 frequency; - u32 bandwidth; - u16 if1_freq; - u8 fmfreq; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt20xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt20xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt20xx.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt20xx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,672 +0,0 @@ -/* - * i2c tv tuner chip device driver - * controls microtune tuners, mt2032 + mt2050 at the moment. - * - * This "mt20xx" module was split apart from the original "tuner" module. - */ -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "mt20xx.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -/* ---------------------------------------------------------------------- */ - -static unsigned int optimize_vco = 1; -module_param(optimize_vco, int, 0644); - -static unsigned int tv_antenna = 1; -module_param(tv_antenna, int, 0644); - -static unsigned int radio_antenna; -module_param(radio_antenna, int, 0644); - -/* ---------------------------------------------------------------------- */ - -#define MT2032 0x04 -#define MT2030 0x06 -#define MT2040 0x07 -#define MT2050 0x42 - -static char *microtune_part[] = { - [ MT2030 ] = "MT2030", - [ MT2032 ] = "MT2032", - [ MT2040 ] = "MT2040", - [ MT2050 ] = "MT2050", -}; - -struct microtune_priv { - struct tuner_i2c_props i2c_props; - - unsigned int xogc; - //unsigned int radio_if2; - - u32 frequency; -}; - -static int microtune_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - -static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct microtune_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -// IsSpurInBand()? -static int mt2032_spurcheck(struct dvb_frontend *fe, - int f1, int f2, int spectrum_from,int spectrum_to) -{ - struct microtune_priv *priv = fe->tuner_priv; - int n1=1,n2,f; - - f1=f1/1000; //scale to kHz to avoid 32bit overflows - f2=f2/1000; - spectrum_from/=1000; - spectrum_to/=1000; - - tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n", - f1,f2,spectrum_from,spectrum_to); - - do { - n2=-n1; - f=n1*(f1-f2); - do { - n2--; - f=f-f2; - tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); - - if( (f>spectrum_from) && (f(f2-spectrum_to)) || (n2>-5)); - n1++; - } while (n1<5); - - return 1; -} - -static int mt2032_compute_freq(struct dvb_frontend *fe, - unsigned int rfin, - unsigned int if1, unsigned int if2, - unsigned int spectrum_from, - unsigned int spectrum_to, - unsigned char *buf, - int *ret_sel, - unsigned int xogc) //all in Hz -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, - desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; - - fref= 5250 *1000; //5.25MHz - desired_lo1=rfin+if1; - - lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); - lo1n=lo1/8; - lo1a=lo1-(lo1n*8); - - s=rfin/1000/1000+1090; - - if(optimize_vco) { - if(s>1890) sel=0; - else if(s>1720) sel=1; - else if(s>1530) sel=2; - else if(s>1370) sel=3; - else sel=4; // >1090 - } - else { - if(s>1790) sel=0; // <1958 - else if(s>1617) sel=1; - else if(s>1449) sel=2; - else if(s>1291) sel=3; - else sel=4; // >1090 - } - *ret_sel=sel; - - lo1freq=(lo1a+8*lo1n)*fref; - - tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", - rfin,lo1,lo1n,lo1a,sel,lo1freq); - - desired_lo2=lo1freq-rfin-if2; - lo2=(desired_lo2)/fref; - lo2n=lo2/8; - lo2a=lo2-(lo2n*8); - lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith - lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; - - tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", - rfin,lo2,lo2n,lo2a,lo2num,lo2freq); - - if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 || - lo2n > 30) { - tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", - lo1a, lo1n, lo2a,lo2n); - return(-1); - } - - mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to); - // should recalculate lo1 (one step up/down) - - // set up MT2032 register map for transfer over i2c - buf[0]=lo1n-1; - buf[1]=lo1a | (sel<<4); - buf[2]=0x86; // LOGC - buf[3]=0x0f; //reserved - buf[4]=0x1f; - buf[5]=(lo2n-1) | (lo2a<<5); - if(rfin >400*1000*1000) - buf[6]=0xe4; - else - buf[6]=0xf4; // set PKEN per rev 1.2 - buf[7]=8+xogc; - buf[8]=0xc3; //reserved - buf[9]=0x4e; //reserved - buf[10]=0xec; //reserved - buf[11]=(lo2num&0xff); - buf[12]=(lo2num>>8) |0x80; // Lo2RST - - return 0; -} - -static int mt2032_check_lo_lock(struct dvb_frontend *fe) -{ - struct microtune_priv *priv = fe->tuner_priv; - int try,lock=0; - unsigned char buf[2]; - - for(try=0;try<10;try++) { - buf[0]=0x0e; - tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); - tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); - lock=buf[0] &0x06; - - if (lock==6) - break; - - tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); - udelay(1000); - } - return lock; -} - -static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned char buf[2]; - int tad1; - - buf[0]=0x0f; - tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); - tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); - tad1=buf[0]&0x07; - - if(tad1 ==0) return lock; - if(tad1 ==1) return lock; - - if(tad1==2) { - if(sel==0) - return lock; - else sel--; - } - else { - if(sel<4) - sel++; - else - return lock; - } - - tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel); - - buf[0]=0x0f; - buf[1]=sel; - tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - lock=mt2032_check_lo_lock(fe); - return lock; -} - - -static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, - unsigned int if1, unsigned int if2, - unsigned int from, unsigned int to) -{ - unsigned char buf[21]; - int lint_try,ret,sel,lock=0; - struct microtune_priv *priv = fe->tuner_priv; - - tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", - rfin,if1,if2,from,to); - - buf[0]=0; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); - - buf[0]=0; - ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); - if (ret<0) - return; - - // send only the relevant registers per Rev. 1.2 - buf[0]=0; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); - buf[5]=5; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); - buf[11]=11; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); - if(ret!=3) - tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); - - // wait for PLLs to lock (per manual), retry LINT if not. - for(lint_try=0; lint_try<2; lint_try++) { - lock=mt2032_check_lo_lock(fe); - - if(optimize_vco) - lock=mt2032_optimize_vco(fe,sel,lock); - if(lock==6) break; - - tuner_dbg("mt2032: re-init PLLs by LINT\n"); - buf[0]=7; - buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs - tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - mdelay(10); - buf[1]=8+priv->xogc; - tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - } - - if (lock!=6) - tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n"); - - buf[0]=2; - buf[1]=0x20; // LOGC for optimal phase noise - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - if (ret!=2) - tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); -} - - -static int mt2032_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - int if2,from,to; - - // signal bandwidth and picture carrier - if (params->std & V4L2_STD_525_60) { - // NTSC - from = 40750*1000; - to = 46750*1000; - if2 = 45750*1000; - } else { - // PAL - from = 32900*1000; - to = 39900*1000; - if2 = 38900*1000; - } - - mt2032_set_if_freq(fe, params->frequency*62500, - 1090*1000*1000, if2, from, to); - - return 0; -} - -static int mt2032_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct microtune_priv *priv = fe->tuner_priv; - int if2; - - if (params->std & V4L2_STD_525_60) { - tuner_dbg("pinnacle ntsc\n"); - if2 = 41300 * 1000; - } else { - tuner_dbg("pinnacle pal\n"); - if2 = 33300 * 1000; - } - - // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(fe, params->frequency * 125 / 2, - 1085*1000*1000,if2,if2,if2); - - return 0; -} - -static int mt2032_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct microtune_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - switch (params->mode) { - case V4L2_TUNER_RADIO: - ret = mt2032_set_radio_freq(fe, params); - priv->frequency = params->frequency * 125 / 2; - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = mt2032_set_tv_freq(fe, params); - priv->frequency = params->frequency * 62500; - break; - } - - return ret; -} - -static struct dvb_tuner_ops mt2032_tuner_ops = { - .set_analog_params = mt2032_set_params, - .release = microtune_release, - .get_frequency = microtune_get_frequency, -}; - -// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct dvb_frontend *fe) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned char buf[21]; - int ret,xogc,xok=0; - - // Initialize Registers per spec. - buf[1]=2; // Index to register 2 - buf[2]=0xff; - buf[3]=0x0f; - buf[4]=0x1f; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); - - buf[5]=6; // Index register 6 - buf[6]=0xe4; - buf[7]=0x8f; - buf[8]=0xc3; - buf[9]=0x4e; - buf[10]=0xec; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); - - buf[12]=13; // Index register 13 - buf[13]=0x32; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); - - // Adjust XOGC (register 7), wait for XOK - xogc=7; - do { - tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); - mdelay(10); - buf[0]=0x0e; - tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); - xok=buf[0]&0x01; - tuner_dbg("mt2032: xok = 0x%02x\n",xok); - if (xok == 1) break; - - xogc--; - tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); - if (xogc == 3) { - xogc=4; // min. 4 per spec - break; - } - buf[0]=0x07; - buf[1]=0x88 + xogc; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - if (ret!=2) - tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); - } while (xok != 1 ); - priv->xogc=xogc; - - memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); - - return(1); -} - -static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned char buf[2]; - int ret; - - buf[0] = 6; - buf[1] = antenna ? 0x11 : 0x10; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); -} - -static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned int if1=1218*1000*1000; - unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; - int ret; - unsigned char buf[6]; - - tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", - freq,if1,if2); - - f_lo1=freq+if1; - f_lo1=(f_lo1/1000000)*1000000; - - f_lo2=f_lo1-freq-if2; - f_lo2=(f_lo2/50000)*50000; - - lo1=f_lo1/4000000; - lo2=f_lo2/4000000; - - f_lo1_modulo= f_lo1-(lo1*4000000); - f_lo2_modulo= f_lo2-(lo2*4000000); - - num1=4*f_lo1_modulo/4000000; - num2=4096*(f_lo2_modulo/1000)/4000; - - // todo spurchecks - - div1a=(lo1/12)-1; - div1b=lo1-(div1a+1)*12; - - div2a=(lo2/8)-1; - div2b=lo2-(div2a+1)*8; - - if (debug > 1) { - tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); - tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", - num1,num2,div1a,div1b,div2a,div2b); - } - - buf[0]=1; - buf[1]= 4*div1b + num1; - if(freq<275*1000*1000) buf[1] = buf[1]|0x80; - - buf[2]=div1a; - buf[3]=32*div2b + num2/256; - buf[4]=num2-(num2/256)*256; - buf[5]=div2a; - if(num2!=0) buf[5]=buf[5]|0x40; - - if (debug > 1) { - int i; - tuner_dbg("bufs is: "); - for(i=0;i<6;i++) - printk("%x ",buf[i]); - printk("\n"); - } - - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); - if (ret!=6) - tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); -} - -static int mt2050_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned int if2; - - if (params->std & V4L2_STD_525_60) { - // NTSC - if2 = 45750*1000; - } else { - // PAL - if2 = 38900*1000; - } - if (V4L2_TUNER_DIGITAL_TV == params->mode) { - // DVB (pinnacle 300i) - if2 = 36150*1000; - } - mt2050_set_if_freq(fe, params->frequency*62500, if2); - mt2050_set_antenna(fe, tv_antenna); - - return 0; -} - -static int mt2050_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct microtune_priv *priv = fe->tuner_priv; - int if2; - - if (params->std & V4L2_STD_525_60) { - tuner_dbg("pinnacle ntsc\n"); - if2 = 41300 * 1000; - } else { - tuner_dbg("pinnacle pal\n"); - if2 = 33300 * 1000; - } - - mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); - mt2050_set_antenna(fe, radio_antenna); - - return 0; -} - -static int mt2050_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct microtune_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - switch (params->mode) { - case V4L2_TUNER_RADIO: - ret = mt2050_set_radio_freq(fe, params); - priv->frequency = params->frequency * 125 / 2; - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = mt2050_set_tv_freq(fe, params); - priv->frequency = params->frequency * 62500; - break; - } - - return ret; -} - -static struct dvb_tuner_ops mt2050_tuner_ops = { - .set_analog_params = mt2050_set_params, - .release = microtune_release, - .get_frequency = microtune_get_frequency, -}; - -static int mt2050_init(struct dvb_frontend *fe) -{ - struct microtune_priv *priv = fe->tuner_priv; - unsigned char buf[2]; - int ret; - - buf[0]=6; - buf[1]=0x10; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power - - buf[0]=0x0f; - buf[1]=0x0f; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo - - buf[0]=0x0d; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); - - tuner_dbg("mt2050: sro is %x\n",buf[0]); - - memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); - - return 0; -} - -struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - struct microtune_priv *priv = NULL; - char *name; - unsigned char buf[21]; - int company_code; - - priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->tuner_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->i2c_props.name = "mt20xx"; - - //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ - - memset(buf,0,sizeof(buf)); - - name = "unknown"; - - tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); - if (debug) { - int i; - tuner_dbg("MT20xx hexdump:"); - for(i=0;i<21;i++) { - printk(" %02x",buf[i]); - if(((i+1)%8)==0) printk(" "); - } - printk("\n"); - } - company_code = buf[0x11] << 8 | buf[0x12]; - tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", - company_code,buf[0x13],buf[0x14]); - - - if (buf[0x13] < ARRAY_SIZE(microtune_part) && - NULL != microtune_part[buf[0x13]]) - name = microtune_part[buf[0x13]]; - switch (buf[0x13]) { - case MT2032: - mt2032_init(fe); - break; - case MT2050: - mt2050_init(fe); - break; - default: - tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", - name); - return NULL; - } - - strlcpy(fe->ops.tuner_ops.info.name, name, - sizeof(fe->ops.tuner_ops.info.name)); - tuner_info("microtune %s found, OK\n",name); - return fe; -} - -EXPORT_SYMBOL_GPL(microtune_attach); - -MODULE_DESCRIPTION("Microtune tuner driver"); -MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt20xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt20xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt20xx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt20xx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MT20XX_H__ -#define __MT20XX_H__ - -#include -#include "dvb_frontend.h" - -#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE)) -extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr); -#else -static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __MT20XX_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,315 +0,0 @@ -/* - * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2006 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "mt2131.h" -#include "mt2131_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) - -static u8 mt2131_config1[] = { - 0x01, - 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, - 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, - 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, - 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 -}; - -static u8 mt2131_config2[] = { - 0x10, - 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 -}; - -static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, .flags = 0, - .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, - .buf = val, .len = 1 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "mt2131 I2C read failed\n"); - return -EREMOTEIO; - } - return 0; -} - -static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, - .buf = buf, .len = 2 }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2131 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) -{ - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, - .flags = 0, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", - (int)len); - return -EREMOTEIO; - } - return 0; -} - -static int mt2131_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct mt2131_priv *priv; - int ret=0, i; - u32 freq; - u8 if_band_center; - u32 f_lo1, f_lo2; - u32 div1, num1, div2, num2; - u8 b[8]; - u8 lockval = 0; - - priv = fe->tuner_priv; - if (fe->ops.info.type == FE_OFDM) - priv->bandwidth = params->u.ofdm.bandwidth; - else - priv->bandwidth = 0; - - freq = params->frequency / 1000; // Hz -> kHz - dprintk(1, "%s() freq=%d\n", __func__, freq); - - f_lo1 = freq + MT2131_IF1 * 1000; - f_lo1 = (f_lo1 / 250) * 250; - f_lo2 = f_lo1 - freq - MT2131_IF2; - - priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000; - - /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ - num1 = f_lo1 * 64 / (MT2131_FREF / 128); - div1 = num1 / 8192; - num1 &= 0x1fff; - - /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ - num2 = f_lo2 * 64 / (MT2131_FREF / 128); - div2 = num2 / 8192; - num2 &= 0x1fff; - - if (freq <= 82500) if_band_center = 0x00; else - if (freq <= 137500) if_band_center = 0x01; else - if (freq <= 192500) if_band_center = 0x02; else - if (freq <= 247500) if_band_center = 0x03; else - if (freq <= 302500) if_band_center = 0x04; else - if (freq <= 357500) if_band_center = 0x05; else - if (freq <= 412500) if_band_center = 0x06; else - if (freq <= 467500) if_band_center = 0x07; else - if (freq <= 522500) if_band_center = 0x08; else - if (freq <= 577500) if_band_center = 0x09; else - if (freq <= 632500) if_band_center = 0x0A; else - if (freq <= 687500) if_band_center = 0x0B; else - if (freq <= 742500) if_band_center = 0x0C; else - if (freq <= 797500) if_band_center = 0x0D; else - if (freq <= 852500) if_band_center = 0x0E; else - if (freq <= 907500) if_band_center = 0x0F; else - if (freq <= 962500) if_band_center = 0x10; else - if (freq <= 1017500) if_band_center = 0x11; else - if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; - - b[0] = 1; - b[1] = (num1 >> 5) & 0xFF; - b[2] = (num1 & 0x1F); - b[3] = div1; - b[4] = (num2 >> 5) & 0xFF; - b[5] = num2 & 0x1F; - b[6] = div2; - - dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); - dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); - dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); - dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", - (int)div1, (int)num1, (int)div2, (int)num2); - dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", - (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], - (int)b[6]); - - ret = mt2131_writeregs(priv,b,7); - if (ret < 0) - return ret; - - mt2131_writereg(priv, 0x0b, if_band_center); - - /* Wait for lock */ - i = 0; - do { - mt2131_readreg(priv, 0x08, &lockval); - if ((lockval & 0x88) == 0x88) - break; - msleep(4); - i++; - } while (i < 10); - - return ret; -} - -static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mt2131_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - *frequency = priv->frequency; - return 0; -} - -static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mt2131_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - *bandwidth = priv->bandwidth; - return 0; -} - -static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct mt2131_priv *priv = fe->tuner_priv; - u8 lock_status = 0; - u8 afc_status = 0; - - *status = 0; - - mt2131_readreg(priv, 0x08, &lock_status); - if ((lock_status & 0x88) == 0x88) - *status = TUNER_STATUS_LOCKED; - - mt2131_readreg(priv, 0x09, &afc_status); - dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", - __func__, lock_status, afc_status); - - return 0; -} - -static int mt2131_init(struct dvb_frontend *fe) -{ - struct mt2131_priv *priv = fe->tuner_priv; - int ret; - dprintk(1, "%s()\n", __func__); - - if ((ret = mt2131_writeregs(priv, mt2131_config1, - sizeof(mt2131_config1))) < 0) - return ret; - - mt2131_writereg(priv, 0x0b, 0x09); - mt2131_writereg(priv, 0x15, 0x47); - mt2131_writereg(priv, 0x07, 0xf2); - mt2131_writereg(priv, 0x0b, 0x01); - - if ((ret = mt2131_writeregs(priv, mt2131_config2, - sizeof(mt2131_config2))) < 0) - return ret; - - return ret; -} - -static int mt2131_release(struct dvb_frontend *fe) -{ - dprintk(1, "%s()\n", __func__); - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops mt2131_tuner_ops = { - .info = { - .name = "Microtune MT2131", - .frequency_min = 48000000, - .frequency_max = 860000000, - .frequency_step = 50000, - }, - - .release = mt2131_release, - .init = mt2131_init, - - .set_params = mt2131_set_params, - .get_frequency = mt2131_get_frequency, - .get_bandwidth = mt2131_get_bandwidth, - .get_status = mt2131_get_status -}; - -struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mt2131_config *cfg, u16 if1) -{ - struct mt2131_priv *priv = NULL; - u8 id = 0; - - dprintk(1, "%s()\n", __func__); - - priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->bandwidth = 6000000; /* 6MHz */ - priv->i2c = i2c; - - if (mt2131_readreg(priv, 0, &id) != 0) { - kfree(priv); - return NULL; - } - if ( (id != 0x3E) && (id != 0x3F) ) { - printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", - cfg->i2c_address); - kfree(priv); - return NULL; - } - - printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", - cfg->i2c_address); - memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - return fe; -} -EXPORT_SYMBOL(mt2131_attach); - -MODULE_AUTHOR("Steven Toth"); -MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* - * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2006 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __MT2131_H__ -#define __MT2131_H__ - -struct dvb_frontend; -struct i2c_adapter; - -struct mt2131_config { - u8 i2c_address; - u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ -}; - -#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE)) -extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mt2131_config *cfg, - u16 if1); -#else -static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mt2131_config *cfg, - u16 if1) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_MEDIA_TUNER_MT2131 */ - -#endif /* __MT2131_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2131_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2006 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __MT2131_PRIV_H__ -#define __MT2131_PRIV_H__ - -/* Regs */ -#define MT2131_PWR 0x07 -#define MT2131_UPC_1 0x0b -#define MT2131_AGC_RL 0x10 -#define MT2131_MISC_2 0x15 - -/* frequency values in KHz */ -#define MT2131_IF1 1220 -#define MT2131_IF2 44000 -#define MT2131_FREF 16000 - -struct mt2131_priv { - struct mt2131_config *cfg; - struct i2c_adapter *i2c; - - u32 frequency; - u32 bandwidth; -}; - -#endif /* __MT2131_PRIV_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2266.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2266.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2266.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2266.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,352 +0,0 @@ -/* - * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" - * - * Copyright (c) 2007 Olivier DANET - * - * 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, or - * (at your option) any later version. - * - * 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. - */ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "mt2266.h" - -#define I2C_ADDRESS 0x60 - -#define REG_PART_REV 0 -#define REG_TUNE 1 -#define REG_BAND 6 -#define REG_BANDWIDTH 8 -#define REG_LOCK 0x12 - -#define PART_REV 0x85 - -struct mt2266_priv { - struct mt2266_config *cfg; - struct i2c_adapter *i2c; - - u32 frequency; - u32 bandwidth; - u8 band; -}; - -#define MT2266_VHF 1 -#define MT2266_UHF 0 - -/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) - -// Reads a single register -static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, - }; - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "MT2266 I2C read failed\n"); - return -EREMOTEIO; - } - return 0; -} - -// Writes a single register -static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 - }; - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "MT2266 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -// Writes a set of consecutive registers -static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) -{ - struct i2c_msg msg = { - .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len - }; - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); - return -EREMOTEIO; - } - return 0; -} - -// Initialisation sequences -static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, - 0x00, 0x52, 0x99, 0x3f }; - -static u8 mt2266_init2[] = { - 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, - 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, - 0xff, 0x00, 0x77, 0x0f, 0x2d -}; - -static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22 }; - -static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32 }; - -static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7 }; - -static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, - 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; - -static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, - 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; - -#define FREF 30000 // Quartz oscillator 30 MHz - -static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct mt2266_priv *priv; - int ret=0; - u32 freq; - u32 tune; - u8 lnaband; - u8 b[10]; - int i; - u8 band; - - priv = fe->tuner_priv; - - freq = params->frequency / 1000; // Hz -> kHz - if (freq < 470000 && freq > 230000) - return -EINVAL; /* Gap between VHF and UHF bands */ - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - priv->frequency = freq * 1000; - - tune = 2 * freq * (8192/16) / (FREF/16); - band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; - if (band == MT2266_VHF) - tune *= 2; - - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - mt2266_writeregs(priv, mt2266_init_6mhz, - sizeof(mt2266_init_6mhz)); - break; - case BANDWIDTH_7_MHZ: - mt2266_writeregs(priv, mt2266_init_7mhz, - sizeof(mt2266_init_7mhz)); - break; - case BANDWIDTH_8_MHZ: - default: - mt2266_writeregs(priv, mt2266_init_8mhz, - sizeof(mt2266_init_8mhz)); - break; - } - - if (band == MT2266_VHF && priv->band == MT2266_UHF) { - dprintk("Switch from UHF to VHF"); - mt2266_writereg(priv, 0x05, 0x04); - mt2266_writereg(priv, 0x19, 0x61); - mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); - } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { - dprintk("Switch from VHF to UHF"); - mt2266_writereg(priv, 0x05, 0x52); - mt2266_writereg(priv, 0x19, 0x61); - mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); - } - msleep(10); - - if (freq <= 495000) - lnaband = 0xEE; - else if (freq <= 525000) - lnaband = 0xDD; - else if (freq <= 550000) - lnaband = 0xCC; - else if (freq <= 580000) - lnaband = 0xBB; - else if (freq <= 605000) - lnaband = 0xAA; - else if (freq <= 630000) - lnaband = 0x99; - else if (freq <= 655000) - lnaband = 0x88; - else if (freq <= 685000) - lnaband = 0x77; - else if (freq <= 710000) - lnaband = 0x66; - else if (freq <= 735000) - lnaband = 0x55; - else if (freq <= 765000) - lnaband = 0x44; - else if (freq <= 802000) - lnaband = 0x33; - else if (freq <= 840000) - lnaband = 0x22; - else - lnaband = 0x11; - - b[0] = REG_TUNE; - b[1] = (tune >> 8) & 0x1F; - b[2] = tune & 0xFF; - b[3] = tune >> 13; - mt2266_writeregs(priv,b,4); - - dprintk("set_parms: tune=%d band=%d %s", - (int) tune, (int) lnaband, - (band == MT2266_UHF) ? "UHF" : "VHF"); - dprintk("set_parms: [1..3]: %2x %2x %2x", - (int) b[1], (int) b[2], (int)b[3]); - - if (band == MT2266_UHF) { - b[0] = 0x05; - b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; - b[2] = lnaband; - mt2266_writeregs(priv, b, 3); - } - - /* Wait for pll lock or timeout */ - i = 0; - do { - mt2266_readreg(priv,REG_LOCK,b); - if (b[0] & 0x40) - break; - msleep(10); - i++; - } while (i<10); - dprintk("Lock when i=%i",(int)i); - - if (band == MT2266_UHF && priv->band == MT2266_VHF) - mt2266_writereg(priv, 0x05, 0x62); - - priv->band = band; - - return ret; -} - -static void mt2266_calibrate(struct mt2266_priv *priv) -{ - mt2266_writereg(priv, 0x11, 0x03); - mt2266_writereg(priv, 0x11, 0x01); - mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); - mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); - mt2266_writereg(priv, 0x33, 0x5e); - mt2266_writereg(priv, 0x10, 0x10); - mt2266_writereg(priv, 0x10, 0x00); - mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); - msleep(25); - mt2266_writereg(priv, 0x17, 0x6d); - mt2266_writereg(priv, 0x1c, 0x00); - msleep(75); - mt2266_writereg(priv, 0x17, 0x6d); - mt2266_writereg(priv, 0x1c, 0xff); -} - -static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mt2266_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mt2266_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static int mt2266_init(struct dvb_frontend *fe) -{ - int ret; - struct mt2266_priv *priv = fe->tuner_priv; - ret = mt2266_writereg(priv, 0x17, 0x6d); - if (ret < 0) - return ret; - ret = mt2266_writereg(priv, 0x1c, 0xff); - if (ret < 0) - return ret; - return 0; -} - -static int mt2266_sleep(struct dvb_frontend *fe) -{ - struct mt2266_priv *priv = fe->tuner_priv; - mt2266_writereg(priv, 0x17, 0x6d); - mt2266_writereg(priv, 0x1c, 0x00); - return 0; -} - -static int mt2266_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops mt2266_tuner_ops = { - .info = { - .name = "Microtune MT2266", - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_step = 50000, - }, - .release = mt2266_release, - .init = mt2266_init, - .sleep = mt2266_sleep, - .set_params = mt2266_set_params, - .get_frequency = mt2266_get_frequency, - .get_bandwidth = mt2266_get_bandwidth -}; - -struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) -{ - struct mt2266_priv *priv = NULL; - u8 id = 0; - - priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - priv->band = MT2266_UHF; - - if (mt2266_readreg(priv, 0, &id)) { - kfree(priv); - return NULL; - } - if (id != PART_REV) { - kfree(priv); - return NULL; - } - printk(KERN_INFO "MT2266: successfully identified\n"); - memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - mt2266_calibrate(priv); - return fe; -} -EXPORT_SYMBOL(mt2266_attach); - -MODULE_AUTHOR("Olivier DANET"); -MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2266.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2266.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2266.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mt2266.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* - * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" - * - * Copyright (c) 2007 Olivier DANET - * - * 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, or - * (at your option) any later version. - * - * 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. - */ - -#ifndef MT2266_H -#define MT2266_H - -struct dvb_frontend; -struct i2c_adapter; - -struct mt2266_config { - u8 i2c_address; -}; - -#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE)) -extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); -#else -static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_MEDIA_TUNER_MT2266 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5005s.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5005s.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5005s.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5005s.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,4116 +0,0 @@ -/* - MaxLinear MXL5005S VSB/QAM/DVBT tuner driver - - Copyright (C) 2008 MaxLinear - Copyright (C) 2006 Steven Toth - Functions: - mxl5005s_reset() - mxl5005s_writereg() - mxl5005s_writeregs() - mxl5005s_init() - mxl5005s_reconfigure() - mxl5005s_AssignTunerMode() - mxl5005s_set_params() - mxl5005s_get_frequency() - mxl5005s_get_bandwidth() - mxl5005s_release() - mxl5005s_attach() - - Copyright (C) 2008 Realtek - Copyright (C) 2008 Jan Hoogenraad - Functions: - mxl5005s_SetRfFreqHz() - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/* - History of this driver (Steven Toth): - I was given a public release of a linux driver that included - support for the MaxLinear MXL5005S silicon tuner. Analysis of - the tuner driver showed clearly three things. - - 1. The tuner driver didn't support the LinuxTV tuner API - so the code Realtek added had to be removed. - - 2. A significant amount of the driver is reference driver code - from MaxLinear, I felt it was important to identify and - preserve this. - - 3. New code has to be added to interface correctly with the - LinuxTV API, as a regular kernel module. - - Other than the reference driver enum's, I've clearly marked - sections of the code and retained the copyright of the - respective owners. -*/ -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "mxl5005s.h" - -static int debug; - -#define dprintk(level, arg...) do { \ - if (level <= debug) \ - printk(arg); \ - } while (0) - -#define TUNER_REGS_NUM 104 -#define INITCTRL_NUM 40 - -#ifdef _MXL_PRODUCTION -#define CHCTRL_NUM 39 -#else -#define CHCTRL_NUM 36 -#endif - -#define MXLCTRL_NUM 189 -#define MASTER_CONTROL_ADDR 9 - -/* Enumeration of Master Control Register State */ -enum master_control_state { - MC_LOAD_START = 1, - MC_POWER_DOWN, - MC_SYNTH_RESET, - MC_SEQ_OFF -}; - -/* Enumeration of MXL5005 Tuner Modulation Type */ -enum { - MXL_DEFAULT_MODULATION = 0, - MXL_DVBT, - MXL_ATSC, - MXL_QAM, - MXL_ANALOG_CABLE, - MXL_ANALOG_OTA -}; - -/* MXL5005 Tuner Register Struct */ -struct TunerReg { - u16 Reg_Num; /* Tuner Register Address */ - u16 Reg_Val; /* Current sw programmed value waiting to be writen */ -}; - -enum { - /* Initialization Control Names */ - DN_IQTN_AMP_CUT = 1, /* 1 */ - BB_MODE, /* 2 */ - BB_BUF, /* 3 */ - BB_BUF_OA, /* 4 */ - BB_ALPF_BANDSELECT, /* 5 */ - BB_IQSWAP, /* 6 */ - BB_DLPF_BANDSEL, /* 7 */ - RFSYN_CHP_GAIN, /* 8 */ - RFSYN_EN_CHP_HIGAIN, /* 9 */ - AGC_IF, /* 10 */ - AGC_RF, /* 11 */ - IF_DIVVAL, /* 12 */ - IF_VCO_BIAS, /* 13 */ - CHCAL_INT_MOD_IF, /* 14 */ - CHCAL_FRAC_MOD_IF, /* 15 */ - DRV_RES_SEL, /* 16 */ - I_DRIVER, /* 17 */ - EN_AAF, /* 18 */ - EN_3P, /* 19 */ - EN_AUX_3P, /* 20 */ - SEL_AAF_BAND, /* 21 */ - SEQ_ENCLK16_CLK_OUT, /* 22 */ - SEQ_SEL4_16B, /* 23 */ - XTAL_CAPSELECT, /* 24 */ - IF_SEL_DBL, /* 25 */ - RFSYN_R_DIV, /* 26 */ - SEQ_EXTSYNTHCALIF, /* 27 */ - SEQ_EXTDCCAL, /* 28 */ - AGC_EN_RSSI, /* 29 */ - RFA_ENCLKRFAGC, /* 30 */ - RFA_RSSI_REFH, /* 31 */ - RFA_RSSI_REF, /* 32 */ - RFA_RSSI_REFL, /* 33 */ - RFA_FLR, /* 34 */ - RFA_CEIL, /* 35 */ - SEQ_EXTIQFSMPULSE, /* 36 */ - OVERRIDE_1, /* 37 */ - BB_INITSTATE_DLPF_TUNE, /* 38 */ - TG_R_DIV, /* 39 */ - EN_CHP_LIN_B, /* 40 */ - - /* Channel Change Control Names */ - DN_POLY = 51, /* 51 */ - DN_RFGAIN, /* 52 */ - DN_CAP_RFLPF, /* 53 */ - DN_EN_VHFUHFBAR, /* 54 */ - DN_GAIN_ADJUST, /* 55 */ - DN_IQTNBUF_AMP, /* 56 */ - DN_IQTNGNBFBIAS_BST, /* 57 */ - RFSYN_EN_OUTMUX, /* 58 */ - RFSYN_SEL_VCO_OUT, /* 59 */ - RFSYN_SEL_VCO_HI, /* 60 */ - RFSYN_SEL_DIVM, /* 61 */ - RFSYN_RF_DIV_BIAS, /* 62 */ - DN_SEL_FREQ, /* 63 */ - RFSYN_VCO_BIAS, /* 64 */ - CHCAL_INT_MOD_RF, /* 65 */ - CHCAL_FRAC_MOD_RF, /* 66 */ - RFSYN_LPF_R, /* 67 */ - CHCAL_EN_INT_RF, /* 68 */ - TG_LO_DIVVAL, /* 69 */ - TG_LO_SELVAL, /* 70 */ - TG_DIV_VAL, /* 71 */ - TG_VCO_BIAS, /* 72 */ - SEQ_EXTPOWERUP, /* 73 */ - OVERRIDE_2, /* 74 */ - OVERRIDE_3, /* 75 */ - OVERRIDE_4, /* 76 */ - SEQ_FSM_PULSE, /* 77 */ - GPIO_4B, /* 78 */ - GPIO_3B, /* 79 */ - GPIO_4, /* 80 */ - GPIO_3, /* 81 */ - GPIO_1B, /* 82 */ - DAC_A_ENABLE, /* 83 */ - DAC_B_ENABLE, /* 84 */ - DAC_DIN_A, /* 85 */ - DAC_DIN_B, /* 86 */ -#ifdef _MXL_PRODUCTION - RFSYN_EN_DIV, /* 87 */ - RFSYN_DIVM, /* 88 */ - DN_BYPASS_AGC_I2C /* 89 */ -#endif -}; - -/* - * The following context is source code provided by MaxLinear. - * MaxLinear source code - Common_MXL.h (?) - */ - -/* Constants */ -#define MXL5005S_REG_WRITING_TABLE_LEN_MAX 104 -#define MXL5005S_LATCH_BYTE 0xfe - -/* Register address, MSB, and LSB */ -#define MXL5005S_BB_IQSWAP_ADDR 59 -#define MXL5005S_BB_IQSWAP_MSB 0 -#define MXL5005S_BB_IQSWAP_LSB 0 - -#define MXL5005S_BB_DLPF_BANDSEL_ADDR 53 -#define MXL5005S_BB_DLPF_BANDSEL_MSB 4 -#define MXL5005S_BB_DLPF_BANDSEL_LSB 3 - -/* Standard modes */ -enum { - MXL5005S_STANDARD_DVBT, - MXL5005S_STANDARD_ATSC, -}; -#define MXL5005S_STANDARD_MODE_NUM 2 - -/* Bandwidth modes */ -enum { - MXL5005S_BANDWIDTH_6MHZ = 6000000, - MXL5005S_BANDWIDTH_7MHZ = 7000000, - MXL5005S_BANDWIDTH_8MHZ = 8000000, -}; -#define MXL5005S_BANDWIDTH_MODE_NUM 3 - -/* MXL5005 Tuner Control Struct */ -struct TunerControl { - u16 Ctrl_Num; /* Control Number */ - u16 size; /* Number of bits to represent Value */ - u16 addr[25]; /* Array of Tuner Register Address for each bit pos */ - u16 bit[25]; /* Array of bit pos in Reg Addr for each bit pos */ - u16 val[25]; /* Binary representation of Value */ -}; - -/* MXL5005 Tuner Struct */ -struct mxl5005s_state { - u8 Mode; /* 0: Analog Mode ; 1: Digital Mode */ - u8 IF_Mode; /* for Analog Mode, 0: zero IF; 1: low IF */ - u32 Chan_Bandwidth; /* filter channel bandwidth (6, 7, 8) */ - u32 IF_OUT; /* Desired IF Out Frequency */ - u16 IF_OUT_LOAD; /* IF Out Load Resistor (200/300 Ohms) */ - u32 RF_IN; /* RF Input Frequency */ - u32 Fxtal; /* XTAL Frequency */ - u8 AGC_Mode; /* AGC Mode 0: Dual AGC; 1: Single AGC */ - u16 TOP; /* Value: take over point */ - u8 CLOCK_OUT; /* 0: turn off clk out; 1: turn on clock out */ - u8 DIV_OUT; /* 4MHz or 16MHz */ - u8 CAPSELECT; /* 0: disable On-Chip pulling cap; 1: enable */ - u8 EN_RSSI; /* 0: disable RSSI; 1: enable RSSI */ - - /* Modulation Type; */ - /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ - u8 Mod_Type; - - /* Tracking Filter Type */ - /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ - u8 TF_Type; - - /* Calculated Settings */ - u32 RF_LO; /* Synth RF LO Frequency */ - u32 IF_LO; /* Synth IF LO Frequency */ - u32 TG_LO; /* Synth TG_LO Frequency */ - - /* Pointers to ControlName Arrays */ - u16 Init_Ctrl_Num; /* Number of INIT Control Names */ - struct TunerControl - Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */ - - u16 CH_Ctrl_Num; /* Number of CH Control Names */ - struct TunerControl - CH_Ctrl[CHCTRL_NUM]; /* CH Control Name Array Pointer */ - - u16 MXL_Ctrl_Num; /* Number of MXL Control Names */ - struct TunerControl - MXL_Ctrl[MXLCTRL_NUM]; /* MXL Control Name Array Pointer */ - - /* Pointer to Tuner Register Array */ - u16 TunerRegs_Num; /* Number of Tuner Registers */ - struct TunerReg - TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */ - - /* Linux driver framework specific */ - struct mxl5005s_config *config; - struct dvb_frontend *frontend; - struct i2c_adapter *i2c; - - /* Cache values */ - u32 current_mode; - -}; - -static u16 MXL_GetMasterControl(u8 *MasterReg, int state); -static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value); -static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value); -static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, - u8 bitVal); -static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count); -static u32 MXL_Ceiling(u32 value, u32 resolution); -static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal); -static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, - u32 value, u16 controlGroup); -static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val); -static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count); -static u32 MXL_GetXtalInt(u32 Xtal_Freq); -static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq); -static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe); -static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe); -static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count); -static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, - u8 *datatable, u8 len); -static u16 MXL_IFSynthInit(struct dvb_frontend *fe); -static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, - u32 bandwidth); -static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, - u32 bandwidth); - -/* ---------------------------------------------------------------- - * Begin: Custom code salvaged from the Realtek driver. - * Copyright (C) 2008 Realtek - * Copyright (C) 2008 Jan Hoogenraad - * This code is placed under the terms of the GNU General Public License - * - * Released by Realtek under GPLv2. - * Thanks to Realtek for a lot of support we received ! - * - * Revision: 080314 - original version - */ - -static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz) -{ - struct mxl5005s_state *state = fe->tuner_priv; - unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; - unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; - int TableLen; - - u32 IfDivval = 0; - unsigned char MasterControlByte; - - dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz); - - /* Set MxL5005S tuner RF frequency according to example code. */ - - /* Tuner RF frequency setting stage 0 */ - MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); - AddrTable[0] = MASTER_CONTROL_ADDR; - ByteTable[0] |= state->config->AgcMasterByte; - - mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); - - /* Tuner RF frequency setting stage 1 */ - MXL_TuneRF(fe, RfFreqHz); - - MXL_ControlRead(fe, IF_DIVVAL, &IfDivval); - - MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0); - MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1); - MXL_ControlWrite(fe, IF_DIVVAL, 8); - MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen); - - MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); - AddrTable[TableLen] = MASTER_CONTROL_ADDR ; - ByteTable[TableLen] = MasterControlByte | - state->config->AgcMasterByte; - TableLen += 1; - - mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); - - /* Wait 30 ms. */ - msleep(150); - - /* Tuner RF frequency setting stage 2 */ - MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1); - MXL_ControlWrite(fe, IF_DIVVAL, IfDivval); - MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen); - - MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); - AddrTable[TableLen] = MASTER_CONTROL_ADDR ; - ByteTable[TableLen] = MasterControlByte | - state->config->AgcMasterByte ; - TableLen += 1; - - mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); - - msleep(100); - - return 0; -} -/* End: Custom code taken from the Realtek driver */ - -/* ---------------------------------------------------------------- - * Begin: Reference driver code found in the Realtek driver. - * Copyright (C) 2008 MaxLinear - */ -static u16 MXL5005_RegisterInit(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - state->TunerRegs_Num = TUNER_REGS_NUM ; - - state->TunerRegs[0].Reg_Num = 9 ; - state->TunerRegs[0].Reg_Val = 0x40 ; - - state->TunerRegs[1].Reg_Num = 11 ; - state->TunerRegs[1].Reg_Val = 0x19 ; - - state->TunerRegs[2].Reg_Num = 12 ; - state->TunerRegs[2].Reg_Val = 0x60 ; - - state->TunerRegs[3].Reg_Num = 13 ; - state->TunerRegs[3].Reg_Val = 0x00 ; - - state->TunerRegs[4].Reg_Num = 14 ; - state->TunerRegs[4].Reg_Val = 0x00 ; - - state->TunerRegs[5].Reg_Num = 15 ; - state->TunerRegs[5].Reg_Val = 0xC0 ; - - state->TunerRegs[6].Reg_Num = 16 ; - state->TunerRegs[6].Reg_Val = 0x00 ; - - state->TunerRegs[7].Reg_Num = 17 ; - state->TunerRegs[7].Reg_Val = 0x00 ; - - state->TunerRegs[8].Reg_Num = 18 ; - state->TunerRegs[8].Reg_Val = 0x00 ; - - state->TunerRegs[9].Reg_Num = 19 ; - state->TunerRegs[9].Reg_Val = 0x34 ; - - state->TunerRegs[10].Reg_Num = 21 ; - state->TunerRegs[10].Reg_Val = 0x00 ; - - state->TunerRegs[11].Reg_Num = 22 ; - state->TunerRegs[11].Reg_Val = 0x6B ; - - state->TunerRegs[12].Reg_Num = 23 ; - state->TunerRegs[12].Reg_Val = 0x35 ; - - state->TunerRegs[13].Reg_Num = 24 ; - state->TunerRegs[13].Reg_Val = 0x70 ; - - state->TunerRegs[14].Reg_Num = 25 ; - state->TunerRegs[14].Reg_Val = 0x3E ; - - state->TunerRegs[15].Reg_Num = 26 ; - state->TunerRegs[15].Reg_Val = 0x82 ; - - state->TunerRegs[16].Reg_Num = 31 ; - state->TunerRegs[16].Reg_Val = 0x00 ; - - state->TunerRegs[17].Reg_Num = 32 ; - state->TunerRegs[17].Reg_Val = 0x40 ; - - state->TunerRegs[18].Reg_Num = 33 ; - state->TunerRegs[18].Reg_Val = 0x53 ; - - state->TunerRegs[19].Reg_Num = 34 ; - state->TunerRegs[19].Reg_Val = 0x81 ; - - state->TunerRegs[20].Reg_Num = 35 ; - state->TunerRegs[20].Reg_Val = 0xC9 ; - - state->TunerRegs[21].Reg_Num = 36 ; - state->TunerRegs[21].Reg_Val = 0x01 ; - - state->TunerRegs[22].Reg_Num = 37 ; - state->TunerRegs[22].Reg_Val = 0x00 ; - - state->TunerRegs[23].Reg_Num = 41 ; - state->TunerRegs[23].Reg_Val = 0x00 ; - - state->TunerRegs[24].Reg_Num = 42 ; - state->TunerRegs[24].Reg_Val = 0xF8 ; - - state->TunerRegs[25].Reg_Num = 43 ; - state->TunerRegs[25].Reg_Val = 0x43 ; - - state->TunerRegs[26].Reg_Num = 44 ; - state->TunerRegs[26].Reg_Val = 0x20 ; - - state->TunerRegs[27].Reg_Num = 45 ; - state->TunerRegs[27].Reg_Val = 0x80 ; - - state->TunerRegs[28].Reg_Num = 46 ; - state->TunerRegs[28].Reg_Val = 0x88 ; - - state->TunerRegs[29].Reg_Num = 47 ; - state->TunerRegs[29].Reg_Val = 0x86 ; - - state->TunerRegs[30].Reg_Num = 48 ; - state->TunerRegs[30].Reg_Val = 0x00 ; - - state->TunerRegs[31].Reg_Num = 49 ; - state->TunerRegs[31].Reg_Val = 0x00 ; - - state->TunerRegs[32].Reg_Num = 53 ; - state->TunerRegs[32].Reg_Val = 0x94 ; - - state->TunerRegs[33].Reg_Num = 54 ; - state->TunerRegs[33].Reg_Val = 0xFA ; - - state->TunerRegs[34].Reg_Num = 55 ; - state->TunerRegs[34].Reg_Val = 0x92 ; - - state->TunerRegs[35].Reg_Num = 56 ; - state->TunerRegs[35].Reg_Val = 0x80 ; - - state->TunerRegs[36].Reg_Num = 57 ; - state->TunerRegs[36].Reg_Val = 0x41 ; - - state->TunerRegs[37].Reg_Num = 58 ; - state->TunerRegs[37].Reg_Val = 0xDB ; - - state->TunerRegs[38].Reg_Num = 59 ; - state->TunerRegs[38].Reg_Val = 0x00 ; - - state->TunerRegs[39].Reg_Num = 60 ; - state->TunerRegs[39].Reg_Val = 0x00 ; - - state->TunerRegs[40].Reg_Num = 61 ; - state->TunerRegs[40].Reg_Val = 0x00 ; - - state->TunerRegs[41].Reg_Num = 62 ; - state->TunerRegs[41].Reg_Val = 0x00 ; - - state->TunerRegs[42].Reg_Num = 65 ; - state->TunerRegs[42].Reg_Val = 0xF8 ; - - state->TunerRegs[43].Reg_Num = 66 ; - state->TunerRegs[43].Reg_Val = 0xE4 ; - - state->TunerRegs[44].Reg_Num = 67 ; - state->TunerRegs[44].Reg_Val = 0x90 ; - - state->TunerRegs[45].Reg_Num = 68 ; - state->TunerRegs[45].Reg_Val = 0xC0 ; - - state->TunerRegs[46].Reg_Num = 69 ; - state->TunerRegs[46].Reg_Val = 0x01 ; - - state->TunerRegs[47].Reg_Num = 70 ; - state->TunerRegs[47].Reg_Val = 0x50 ; - - state->TunerRegs[48].Reg_Num = 71 ; - state->TunerRegs[48].Reg_Val = 0x06 ; - - state->TunerRegs[49].Reg_Num = 72 ; - state->TunerRegs[49].Reg_Val = 0x00 ; - - state->TunerRegs[50].Reg_Num = 73 ; - state->TunerRegs[50].Reg_Val = 0x20 ; - - state->TunerRegs[51].Reg_Num = 76 ; - state->TunerRegs[51].Reg_Val = 0xBB ; - - state->TunerRegs[52].Reg_Num = 77 ; - state->TunerRegs[52].Reg_Val = 0x13 ; - - state->TunerRegs[53].Reg_Num = 81 ; - state->TunerRegs[53].Reg_Val = 0x04 ; - - state->TunerRegs[54].Reg_Num = 82 ; - state->TunerRegs[54].Reg_Val = 0x75 ; - - state->TunerRegs[55].Reg_Num = 83 ; - state->TunerRegs[55].Reg_Val = 0x00 ; - - state->TunerRegs[56].Reg_Num = 84 ; - state->TunerRegs[56].Reg_Val = 0x00 ; - - state->TunerRegs[57].Reg_Num = 85 ; - state->TunerRegs[57].Reg_Val = 0x00 ; - - state->TunerRegs[58].Reg_Num = 91 ; - state->TunerRegs[58].Reg_Val = 0x70 ; - - state->TunerRegs[59].Reg_Num = 92 ; - state->TunerRegs[59].Reg_Val = 0x00 ; - - state->TunerRegs[60].Reg_Num = 93 ; - state->TunerRegs[60].Reg_Val = 0x00 ; - - state->TunerRegs[61].Reg_Num = 94 ; - state->TunerRegs[61].Reg_Val = 0x00 ; - - state->TunerRegs[62].Reg_Num = 95 ; - state->TunerRegs[62].Reg_Val = 0x0C ; - - state->TunerRegs[63].Reg_Num = 96 ; - state->TunerRegs[63].Reg_Val = 0x00 ; - - state->TunerRegs[64].Reg_Num = 97 ; - state->TunerRegs[64].Reg_Val = 0x00 ; - - state->TunerRegs[65].Reg_Num = 98 ; - state->TunerRegs[65].Reg_Val = 0xE2 ; - - state->TunerRegs[66].Reg_Num = 99 ; - state->TunerRegs[66].Reg_Val = 0x00 ; - - state->TunerRegs[67].Reg_Num = 100 ; - state->TunerRegs[67].Reg_Val = 0x00 ; - - state->TunerRegs[68].Reg_Num = 101 ; - state->TunerRegs[68].Reg_Val = 0x12 ; - - state->TunerRegs[69].Reg_Num = 102 ; - state->TunerRegs[69].Reg_Val = 0x80 ; - - state->TunerRegs[70].Reg_Num = 103 ; - state->TunerRegs[70].Reg_Val = 0x32 ; - - state->TunerRegs[71].Reg_Num = 104 ; - state->TunerRegs[71].Reg_Val = 0xB4 ; - - state->TunerRegs[72].Reg_Num = 105 ; - state->TunerRegs[72].Reg_Val = 0x60 ; - - state->TunerRegs[73].Reg_Num = 106 ; - state->TunerRegs[73].Reg_Val = 0x83 ; - - state->TunerRegs[74].Reg_Num = 107 ; - state->TunerRegs[74].Reg_Val = 0x84 ; - - state->TunerRegs[75].Reg_Num = 108 ; - state->TunerRegs[75].Reg_Val = 0x9C ; - - state->TunerRegs[76].Reg_Num = 109 ; - state->TunerRegs[76].Reg_Val = 0x02 ; - - state->TunerRegs[77].Reg_Num = 110 ; - state->TunerRegs[77].Reg_Val = 0x81 ; - - state->TunerRegs[78].Reg_Num = 111 ; - state->TunerRegs[78].Reg_Val = 0xC0 ; - - state->TunerRegs[79].Reg_Num = 112 ; - state->TunerRegs[79].Reg_Val = 0x10 ; - - state->TunerRegs[80].Reg_Num = 131 ; - state->TunerRegs[80].Reg_Val = 0x8A ; - - state->TunerRegs[81].Reg_Num = 132 ; - state->TunerRegs[81].Reg_Val = 0x10 ; - - state->TunerRegs[82].Reg_Num = 133 ; - state->TunerRegs[82].Reg_Val = 0x24 ; - - state->TunerRegs[83].Reg_Num = 134 ; - state->TunerRegs[83].Reg_Val = 0x00 ; - - state->TunerRegs[84].Reg_Num = 135 ; - state->TunerRegs[84].Reg_Val = 0x00 ; - - state->TunerRegs[85].Reg_Num = 136 ; - state->TunerRegs[85].Reg_Val = 0x7E ; - - state->TunerRegs[86].Reg_Num = 137 ; - state->TunerRegs[86].Reg_Val = 0x40 ; - - state->TunerRegs[87].Reg_Num = 138 ; - state->TunerRegs[87].Reg_Val = 0x38 ; - - state->TunerRegs[88].Reg_Num = 146 ; - state->TunerRegs[88].Reg_Val = 0xF6 ; - - state->TunerRegs[89].Reg_Num = 147 ; - state->TunerRegs[89].Reg_Val = 0x1A ; - - state->TunerRegs[90].Reg_Num = 148 ; - state->TunerRegs[90].Reg_Val = 0x62 ; - - state->TunerRegs[91].Reg_Num = 149 ; - state->TunerRegs[91].Reg_Val = 0x33 ; - - state->TunerRegs[92].Reg_Num = 150 ; - state->TunerRegs[92].Reg_Val = 0x80 ; - - state->TunerRegs[93].Reg_Num = 156 ; - state->TunerRegs[93].Reg_Val = 0x56 ; - - state->TunerRegs[94].Reg_Num = 157 ; - state->TunerRegs[94].Reg_Val = 0x17 ; - - state->TunerRegs[95].Reg_Num = 158 ; - state->TunerRegs[95].Reg_Val = 0xA9 ; - - state->TunerRegs[96].Reg_Num = 159 ; - state->TunerRegs[96].Reg_Val = 0x00 ; - - state->TunerRegs[97].Reg_Num = 160 ; - state->TunerRegs[97].Reg_Val = 0x00 ; - - state->TunerRegs[98].Reg_Num = 161 ; - state->TunerRegs[98].Reg_Val = 0x00 ; - - state->TunerRegs[99].Reg_Num = 162 ; - state->TunerRegs[99].Reg_Val = 0x40 ; - - state->TunerRegs[100].Reg_Num = 166 ; - state->TunerRegs[100].Reg_Val = 0xAE ; - - state->TunerRegs[101].Reg_Num = 167 ; - state->TunerRegs[101].Reg_Val = 0x1B ; - - state->TunerRegs[102].Reg_Num = 168 ; - state->TunerRegs[102].Reg_Val = 0xF2 ; - - state->TunerRegs[103].Reg_Num = 195 ; - state->TunerRegs[103].Reg_Val = 0x00 ; - - return 0 ; -} - -static u16 MXL5005_ControlInit(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - state->Init_Ctrl_Num = INITCTRL_NUM; - - state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ; - state->Init_Ctrl[0].size = 1 ; - state->Init_Ctrl[0].addr[0] = 73; - state->Init_Ctrl[0].bit[0] = 7; - state->Init_Ctrl[0].val[0] = 0; - - state->Init_Ctrl[1].Ctrl_Num = BB_MODE ; - state->Init_Ctrl[1].size = 1 ; - state->Init_Ctrl[1].addr[0] = 53; - state->Init_Ctrl[1].bit[0] = 2; - state->Init_Ctrl[1].val[0] = 1; - - state->Init_Ctrl[2].Ctrl_Num = BB_BUF ; - state->Init_Ctrl[2].size = 2 ; - state->Init_Ctrl[2].addr[0] = 53; - state->Init_Ctrl[2].bit[0] = 1; - state->Init_Ctrl[2].val[0] = 0; - state->Init_Ctrl[2].addr[1] = 57; - state->Init_Ctrl[2].bit[1] = 0; - state->Init_Ctrl[2].val[1] = 1; - - state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ; - state->Init_Ctrl[3].size = 1 ; - state->Init_Ctrl[3].addr[0] = 53; - state->Init_Ctrl[3].bit[0] = 0; - state->Init_Ctrl[3].val[0] = 0; - - state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ; - state->Init_Ctrl[4].size = 3 ; - state->Init_Ctrl[4].addr[0] = 53; - state->Init_Ctrl[4].bit[0] = 5; - state->Init_Ctrl[4].val[0] = 0; - state->Init_Ctrl[4].addr[1] = 53; - state->Init_Ctrl[4].bit[1] = 6; - state->Init_Ctrl[4].val[1] = 0; - state->Init_Ctrl[4].addr[2] = 53; - state->Init_Ctrl[4].bit[2] = 7; - state->Init_Ctrl[4].val[2] = 1; - - state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ; - state->Init_Ctrl[5].size = 1 ; - state->Init_Ctrl[5].addr[0] = 59; - state->Init_Ctrl[5].bit[0] = 0; - state->Init_Ctrl[5].val[0] = 0; - - state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ; - state->Init_Ctrl[6].size = 2 ; - state->Init_Ctrl[6].addr[0] = 53; - state->Init_Ctrl[6].bit[0] = 3; - state->Init_Ctrl[6].val[0] = 0; - state->Init_Ctrl[6].addr[1] = 53; - state->Init_Ctrl[6].bit[1] = 4; - state->Init_Ctrl[6].val[1] = 1; - - state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ; - state->Init_Ctrl[7].size = 4 ; - state->Init_Ctrl[7].addr[0] = 22; - state->Init_Ctrl[7].bit[0] = 4; - state->Init_Ctrl[7].val[0] = 0; - state->Init_Ctrl[7].addr[1] = 22; - state->Init_Ctrl[7].bit[1] = 5; - state->Init_Ctrl[7].val[1] = 1; - state->Init_Ctrl[7].addr[2] = 22; - state->Init_Ctrl[7].bit[2] = 6; - state->Init_Ctrl[7].val[2] = 1; - state->Init_Ctrl[7].addr[3] = 22; - state->Init_Ctrl[7].bit[3] = 7; - state->Init_Ctrl[7].val[3] = 0; - - state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ; - state->Init_Ctrl[8].size = 1 ; - state->Init_Ctrl[8].addr[0] = 22; - state->Init_Ctrl[8].bit[0] = 2; - state->Init_Ctrl[8].val[0] = 0; - - state->Init_Ctrl[9].Ctrl_Num = AGC_IF ; - state->Init_Ctrl[9].size = 4 ; - state->Init_Ctrl[9].addr[0] = 76; - state->Init_Ctrl[9].bit[0] = 0; - state->Init_Ctrl[9].val[0] = 1; - state->Init_Ctrl[9].addr[1] = 76; - state->Init_Ctrl[9].bit[1] = 1; - state->Init_Ctrl[9].val[1] = 1; - state->Init_Ctrl[9].addr[2] = 76; - state->Init_Ctrl[9].bit[2] = 2; - state->Init_Ctrl[9].val[2] = 0; - state->Init_Ctrl[9].addr[3] = 76; - state->Init_Ctrl[9].bit[3] = 3; - state->Init_Ctrl[9].val[3] = 1; - - state->Init_Ctrl[10].Ctrl_Num = AGC_RF ; - state->Init_Ctrl[10].size = 4 ; - state->Init_Ctrl[10].addr[0] = 76; - state->Init_Ctrl[10].bit[0] = 4; - state->Init_Ctrl[10].val[0] = 1; - state->Init_Ctrl[10].addr[1] = 76; - state->Init_Ctrl[10].bit[1] = 5; - state->Init_Ctrl[10].val[1] = 1; - state->Init_Ctrl[10].addr[2] = 76; - state->Init_Ctrl[10].bit[2] = 6; - state->Init_Ctrl[10].val[2] = 0; - state->Init_Ctrl[10].addr[3] = 76; - state->Init_Ctrl[10].bit[3] = 7; - state->Init_Ctrl[10].val[3] = 1; - - state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ; - state->Init_Ctrl[11].size = 5 ; - state->Init_Ctrl[11].addr[0] = 43; - state->Init_Ctrl[11].bit[0] = 3; - state->Init_Ctrl[11].val[0] = 0; - state->Init_Ctrl[11].addr[1] = 43; - state->Init_Ctrl[11].bit[1] = 4; - state->Init_Ctrl[11].val[1] = 0; - state->Init_Ctrl[11].addr[2] = 43; - state->Init_Ctrl[11].bit[2] = 5; - state->Init_Ctrl[11].val[2] = 0; - state->Init_Ctrl[11].addr[3] = 43; - state->Init_Ctrl[11].bit[3] = 6; - state->Init_Ctrl[11].val[3] = 1; - state->Init_Ctrl[11].addr[4] = 43; - state->Init_Ctrl[11].bit[4] = 7; - state->Init_Ctrl[11].val[4] = 0; - - state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ; - state->Init_Ctrl[12].size = 6 ; - state->Init_Ctrl[12].addr[0] = 44; - state->Init_Ctrl[12].bit[0] = 2; - state->Init_Ctrl[12].val[0] = 0; - state->Init_Ctrl[12].addr[1] = 44; - state->Init_Ctrl[12].bit[1] = 3; - state->Init_Ctrl[12].val[1] = 0; - state->Init_Ctrl[12].addr[2] = 44; - state->Init_Ctrl[12].bit[2] = 4; - state->Init_Ctrl[12].val[2] = 0; - state->Init_Ctrl[12].addr[3] = 44; - state->Init_Ctrl[12].bit[3] = 5; - state->Init_Ctrl[12].val[3] = 1; - state->Init_Ctrl[12].addr[4] = 44; - state->Init_Ctrl[12].bit[4] = 6; - state->Init_Ctrl[12].val[4] = 0; - state->Init_Ctrl[12].addr[5] = 44; - state->Init_Ctrl[12].bit[5] = 7; - state->Init_Ctrl[12].val[5] = 0; - - state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ; - state->Init_Ctrl[13].size = 7 ; - state->Init_Ctrl[13].addr[0] = 11; - state->Init_Ctrl[13].bit[0] = 0; - state->Init_Ctrl[13].val[0] = 1; - state->Init_Ctrl[13].addr[1] = 11; - state->Init_Ctrl[13].bit[1] = 1; - state->Init_Ctrl[13].val[1] = 0; - state->Init_Ctrl[13].addr[2] = 11; - state->Init_Ctrl[13].bit[2] = 2; - state->Init_Ctrl[13].val[2] = 0; - state->Init_Ctrl[13].addr[3] = 11; - state->Init_Ctrl[13].bit[3] = 3; - state->Init_Ctrl[13].val[3] = 1; - state->Init_Ctrl[13].addr[4] = 11; - state->Init_Ctrl[13].bit[4] = 4; - state->Init_Ctrl[13].val[4] = 1; - state->Init_Ctrl[13].addr[5] = 11; - state->Init_Ctrl[13].bit[5] = 5; - state->Init_Ctrl[13].val[5] = 0; - state->Init_Ctrl[13].addr[6] = 11; - state->Init_Ctrl[13].bit[6] = 6; - state->Init_Ctrl[13].val[6] = 0; - - state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ; - state->Init_Ctrl[14].size = 16 ; - state->Init_Ctrl[14].addr[0] = 13; - state->Init_Ctrl[14].bit[0] = 0; - state->Init_Ctrl[14].val[0] = 0; - state->Init_Ctrl[14].addr[1] = 13; - state->Init_Ctrl[14].bit[1] = 1; - state->Init_Ctrl[14].val[1] = 0; - state->Init_Ctrl[14].addr[2] = 13; - state->Init_Ctrl[14].bit[2] = 2; - state->Init_Ctrl[14].val[2] = 0; - state->Init_Ctrl[14].addr[3] = 13; - state->Init_Ctrl[14].bit[3] = 3; - state->Init_Ctrl[14].val[3] = 0; - state->Init_Ctrl[14].addr[4] = 13; - state->Init_Ctrl[14].bit[4] = 4; - state->Init_Ctrl[14].val[4] = 0; - state->Init_Ctrl[14].addr[5] = 13; - state->Init_Ctrl[14].bit[5] = 5; - state->Init_Ctrl[14].val[5] = 0; - state->Init_Ctrl[14].addr[6] = 13; - state->Init_Ctrl[14].bit[6] = 6; - state->Init_Ctrl[14].val[6] = 0; - state->Init_Ctrl[14].addr[7] = 13; - state->Init_Ctrl[14].bit[7] = 7; - state->Init_Ctrl[14].val[7] = 0; - state->Init_Ctrl[14].addr[8] = 12; - state->Init_Ctrl[14].bit[8] = 0; - state->Init_Ctrl[14].val[8] = 0; - state->Init_Ctrl[14].addr[9] = 12; - state->Init_Ctrl[14].bit[9] = 1; - state->Init_Ctrl[14].val[9] = 0; - state->Init_Ctrl[14].addr[10] = 12; - state->Init_Ctrl[14].bit[10] = 2; - state->Init_Ctrl[14].val[10] = 0; - state->Init_Ctrl[14].addr[11] = 12; - state->Init_Ctrl[14].bit[11] = 3; - state->Init_Ctrl[14].val[11] = 0; - state->Init_Ctrl[14].addr[12] = 12; - state->Init_Ctrl[14].bit[12] = 4; - state->Init_Ctrl[14].val[12] = 0; - state->Init_Ctrl[14].addr[13] = 12; - state->Init_Ctrl[14].bit[13] = 5; - state->Init_Ctrl[14].val[13] = 1; - state->Init_Ctrl[14].addr[14] = 12; - state->Init_Ctrl[14].bit[14] = 6; - state->Init_Ctrl[14].val[14] = 1; - state->Init_Ctrl[14].addr[15] = 12; - state->Init_Ctrl[14].bit[15] = 7; - state->Init_Ctrl[14].val[15] = 0; - - state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ; - state->Init_Ctrl[15].size = 3 ; - state->Init_Ctrl[15].addr[0] = 147; - state->Init_Ctrl[15].bit[0] = 2; - state->Init_Ctrl[15].val[0] = 0; - state->Init_Ctrl[15].addr[1] = 147; - state->Init_Ctrl[15].bit[1] = 3; - state->Init_Ctrl[15].val[1] = 1; - state->Init_Ctrl[15].addr[2] = 147; - state->Init_Ctrl[15].bit[2] = 4; - state->Init_Ctrl[15].val[2] = 1; - - state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ; - state->Init_Ctrl[16].size = 2 ; - state->Init_Ctrl[16].addr[0] = 147; - state->Init_Ctrl[16].bit[0] = 0; - state->Init_Ctrl[16].val[0] = 0; - state->Init_Ctrl[16].addr[1] = 147; - state->Init_Ctrl[16].bit[1] = 1; - state->Init_Ctrl[16].val[1] = 1; - - state->Init_Ctrl[17].Ctrl_Num = EN_AAF ; - state->Init_Ctrl[17].size = 1 ; - state->Init_Ctrl[17].addr[0] = 147; - state->Init_Ctrl[17].bit[0] = 7; - state->Init_Ctrl[17].val[0] = 0; - - state->Init_Ctrl[18].Ctrl_Num = EN_3P ; - state->Init_Ctrl[18].size = 1 ; - state->Init_Ctrl[18].addr[0] = 147; - state->Init_Ctrl[18].bit[0] = 6; - state->Init_Ctrl[18].val[0] = 0; - - state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ; - state->Init_Ctrl[19].size = 1 ; - state->Init_Ctrl[19].addr[0] = 156; - state->Init_Ctrl[19].bit[0] = 0; - state->Init_Ctrl[19].val[0] = 0; - - state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ; - state->Init_Ctrl[20].size = 1 ; - state->Init_Ctrl[20].addr[0] = 147; - state->Init_Ctrl[20].bit[0] = 5; - state->Init_Ctrl[20].val[0] = 0; - - state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ; - state->Init_Ctrl[21].size = 1 ; - state->Init_Ctrl[21].addr[0] = 137; - state->Init_Ctrl[21].bit[0] = 4; - state->Init_Ctrl[21].val[0] = 0; - - state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ; - state->Init_Ctrl[22].size = 1 ; - state->Init_Ctrl[22].addr[0] = 137; - state->Init_Ctrl[22].bit[0] = 7; - state->Init_Ctrl[22].val[0] = 0; - - state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ; - state->Init_Ctrl[23].size = 1 ; - state->Init_Ctrl[23].addr[0] = 91; - state->Init_Ctrl[23].bit[0] = 5; - state->Init_Ctrl[23].val[0] = 1; - - state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ; - state->Init_Ctrl[24].size = 1 ; - state->Init_Ctrl[24].addr[0] = 43; - state->Init_Ctrl[24].bit[0] = 0; - state->Init_Ctrl[24].val[0] = 1; - - state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ; - state->Init_Ctrl[25].size = 2 ; - state->Init_Ctrl[25].addr[0] = 22; - state->Init_Ctrl[25].bit[0] = 0; - state->Init_Ctrl[25].val[0] = 1; - state->Init_Ctrl[25].addr[1] = 22; - state->Init_Ctrl[25].bit[1] = 1; - state->Init_Ctrl[25].val[1] = 1; - - state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ; - state->Init_Ctrl[26].size = 1 ; - state->Init_Ctrl[26].addr[0] = 134; - state->Init_Ctrl[26].bit[0] = 2; - state->Init_Ctrl[26].val[0] = 0; - - state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ; - state->Init_Ctrl[27].size = 1 ; - state->Init_Ctrl[27].addr[0] = 137; - state->Init_Ctrl[27].bit[0] = 3; - state->Init_Ctrl[27].val[0] = 0; - - state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ; - state->Init_Ctrl[28].size = 1 ; - state->Init_Ctrl[28].addr[0] = 77; - state->Init_Ctrl[28].bit[0] = 7; - state->Init_Ctrl[28].val[0] = 0; - - state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ; - state->Init_Ctrl[29].size = 1 ; - state->Init_Ctrl[29].addr[0] = 166; - state->Init_Ctrl[29].bit[0] = 7; - state->Init_Ctrl[29].val[0] = 1; - - state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ; - state->Init_Ctrl[30].size = 3 ; - state->Init_Ctrl[30].addr[0] = 166; - state->Init_Ctrl[30].bit[0] = 0; - state->Init_Ctrl[30].val[0] = 0; - state->Init_Ctrl[30].addr[1] = 166; - state->Init_Ctrl[30].bit[1] = 1; - state->Init_Ctrl[30].val[1] = 1; - state->Init_Ctrl[30].addr[2] = 166; - state->Init_Ctrl[30].bit[2] = 2; - state->Init_Ctrl[30].val[2] = 1; - - state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ; - state->Init_Ctrl[31].size = 3 ; - state->Init_Ctrl[31].addr[0] = 166; - state->Init_Ctrl[31].bit[0] = 3; - state->Init_Ctrl[31].val[0] = 1; - state->Init_Ctrl[31].addr[1] = 166; - state->Init_Ctrl[31].bit[1] = 4; - state->Init_Ctrl[31].val[1] = 0; - state->Init_Ctrl[31].addr[2] = 166; - state->Init_Ctrl[31].bit[2] = 5; - state->Init_Ctrl[31].val[2] = 1; - - state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ; - state->Init_Ctrl[32].size = 3 ; - state->Init_Ctrl[32].addr[0] = 167; - state->Init_Ctrl[32].bit[0] = 0; - state->Init_Ctrl[32].val[0] = 1; - state->Init_Ctrl[32].addr[1] = 167; - state->Init_Ctrl[32].bit[1] = 1; - state->Init_Ctrl[32].val[1] = 1; - state->Init_Ctrl[32].addr[2] = 167; - state->Init_Ctrl[32].bit[2] = 2; - state->Init_Ctrl[32].val[2] = 0; - - state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ; - state->Init_Ctrl[33].size = 4 ; - state->Init_Ctrl[33].addr[0] = 168; - state->Init_Ctrl[33].bit[0] = 0; - state->Init_Ctrl[33].val[0] = 0; - state->Init_Ctrl[33].addr[1] = 168; - state->Init_Ctrl[33].bit[1] = 1; - state->Init_Ctrl[33].val[1] = 1; - state->Init_Ctrl[33].addr[2] = 168; - state->Init_Ctrl[33].bit[2] = 2; - state->Init_Ctrl[33].val[2] = 0; - state->Init_Ctrl[33].addr[3] = 168; - state->Init_Ctrl[33].bit[3] = 3; - state->Init_Ctrl[33].val[3] = 0; - - state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ; - state->Init_Ctrl[34].size = 4 ; - state->Init_Ctrl[34].addr[0] = 168; - state->Init_Ctrl[34].bit[0] = 4; - state->Init_Ctrl[34].val[0] = 1; - state->Init_Ctrl[34].addr[1] = 168; - state->Init_Ctrl[34].bit[1] = 5; - state->Init_Ctrl[34].val[1] = 1; - state->Init_Ctrl[34].addr[2] = 168; - state->Init_Ctrl[34].bit[2] = 6; - state->Init_Ctrl[34].val[2] = 1; - state->Init_Ctrl[34].addr[3] = 168; - state->Init_Ctrl[34].bit[3] = 7; - state->Init_Ctrl[34].val[3] = 1; - - state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ; - state->Init_Ctrl[35].size = 1 ; - state->Init_Ctrl[35].addr[0] = 135; - state->Init_Ctrl[35].bit[0] = 0; - state->Init_Ctrl[35].val[0] = 0; - - state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ; - state->Init_Ctrl[36].size = 1 ; - state->Init_Ctrl[36].addr[0] = 56; - state->Init_Ctrl[36].bit[0] = 3; - state->Init_Ctrl[36].val[0] = 0; - - state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ; - state->Init_Ctrl[37].size = 7 ; - state->Init_Ctrl[37].addr[0] = 59; - state->Init_Ctrl[37].bit[0] = 1; - state->Init_Ctrl[37].val[0] = 0; - state->Init_Ctrl[37].addr[1] = 59; - state->Init_Ctrl[37].bit[1] = 2; - state->Init_Ctrl[37].val[1] = 0; - state->Init_Ctrl[37].addr[2] = 59; - state->Init_Ctrl[37].bit[2] = 3; - state->Init_Ctrl[37].val[2] = 0; - state->Init_Ctrl[37].addr[3] = 59; - state->Init_Ctrl[37].bit[3] = 4; - state->Init_Ctrl[37].val[3] = 0; - state->Init_Ctrl[37].addr[4] = 59; - state->Init_Ctrl[37].bit[4] = 5; - state->Init_Ctrl[37].val[4] = 0; - state->Init_Ctrl[37].addr[5] = 59; - state->Init_Ctrl[37].bit[5] = 6; - state->Init_Ctrl[37].val[5] = 0; - state->Init_Ctrl[37].addr[6] = 59; - state->Init_Ctrl[37].bit[6] = 7; - state->Init_Ctrl[37].val[6] = 0; - - state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ; - state->Init_Ctrl[38].size = 6 ; - state->Init_Ctrl[38].addr[0] = 32; - state->Init_Ctrl[38].bit[0] = 2; - state->Init_Ctrl[38].val[0] = 0; - state->Init_Ctrl[38].addr[1] = 32; - state->Init_Ctrl[38].bit[1] = 3; - state->Init_Ctrl[38].val[1] = 0; - state->Init_Ctrl[38].addr[2] = 32; - state->Init_Ctrl[38].bit[2] = 4; - state->Init_Ctrl[38].val[2] = 0; - state->Init_Ctrl[38].addr[3] = 32; - state->Init_Ctrl[38].bit[3] = 5; - state->Init_Ctrl[38].val[3] = 0; - state->Init_Ctrl[38].addr[4] = 32; - state->Init_Ctrl[38].bit[4] = 6; - state->Init_Ctrl[38].val[4] = 1; - state->Init_Ctrl[38].addr[5] = 32; - state->Init_Ctrl[38].bit[5] = 7; - state->Init_Ctrl[38].val[5] = 0; - - state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ; - state->Init_Ctrl[39].size = 1 ; - state->Init_Ctrl[39].addr[0] = 25; - state->Init_Ctrl[39].bit[0] = 3; - state->Init_Ctrl[39].val[0] = 1; - - - state->CH_Ctrl_Num = CHCTRL_NUM ; - - state->CH_Ctrl[0].Ctrl_Num = DN_POLY ; - state->CH_Ctrl[0].size = 2 ; - state->CH_Ctrl[0].addr[0] = 68; - state->CH_Ctrl[0].bit[0] = 6; - state->CH_Ctrl[0].val[0] = 1; - state->CH_Ctrl[0].addr[1] = 68; - state->CH_Ctrl[0].bit[1] = 7; - state->CH_Ctrl[0].val[1] = 1; - - state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ; - state->CH_Ctrl[1].size = 2 ; - state->CH_Ctrl[1].addr[0] = 70; - state->CH_Ctrl[1].bit[0] = 6; - state->CH_Ctrl[1].val[0] = 1; - state->CH_Ctrl[1].addr[1] = 70; - state->CH_Ctrl[1].bit[1] = 7; - state->CH_Ctrl[1].val[1] = 0; - - state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ; - state->CH_Ctrl[2].size = 9 ; - state->CH_Ctrl[2].addr[0] = 69; - state->CH_Ctrl[2].bit[0] = 5; - state->CH_Ctrl[2].val[0] = 0; - state->CH_Ctrl[2].addr[1] = 69; - state->CH_Ctrl[2].bit[1] = 6; - state->CH_Ctrl[2].val[1] = 0; - state->CH_Ctrl[2].addr[2] = 69; - state->CH_Ctrl[2].bit[2] = 7; - state->CH_Ctrl[2].val[2] = 0; - state->CH_Ctrl[2].addr[3] = 68; - state->CH_Ctrl[2].bit[3] = 0; - state->CH_Ctrl[2].val[3] = 0; - state->CH_Ctrl[2].addr[4] = 68; - state->CH_Ctrl[2].bit[4] = 1; - state->CH_Ctrl[2].val[4] = 0; - state->CH_Ctrl[2].addr[5] = 68; - state->CH_Ctrl[2].bit[5] = 2; - state->CH_Ctrl[2].val[5] = 0; - state->CH_Ctrl[2].addr[6] = 68; - state->CH_Ctrl[2].bit[6] = 3; - state->CH_Ctrl[2].val[6] = 0; - state->CH_Ctrl[2].addr[7] = 68; - state->CH_Ctrl[2].bit[7] = 4; - state->CH_Ctrl[2].val[7] = 0; - state->CH_Ctrl[2].addr[8] = 68; - state->CH_Ctrl[2].bit[8] = 5; - state->CH_Ctrl[2].val[8] = 0; - - state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ; - state->CH_Ctrl[3].size = 1 ; - state->CH_Ctrl[3].addr[0] = 70; - state->CH_Ctrl[3].bit[0] = 5; - state->CH_Ctrl[3].val[0] = 0; - - state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ; - state->CH_Ctrl[4].size = 3 ; - state->CH_Ctrl[4].addr[0] = 73; - state->CH_Ctrl[4].bit[0] = 4; - state->CH_Ctrl[4].val[0] = 0; - state->CH_Ctrl[4].addr[1] = 73; - state->CH_Ctrl[4].bit[1] = 5; - state->CH_Ctrl[4].val[1] = 1; - state->CH_Ctrl[4].addr[2] = 73; - state->CH_Ctrl[4].bit[2] = 6; - state->CH_Ctrl[4].val[2] = 0; - - state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ; - state->CH_Ctrl[5].size = 4 ; - state->CH_Ctrl[5].addr[0] = 70; - state->CH_Ctrl[5].bit[0] = 0; - state->CH_Ctrl[5].val[0] = 0; - state->CH_Ctrl[5].addr[1] = 70; - state->CH_Ctrl[5].bit[1] = 1; - state->CH_Ctrl[5].val[1] = 0; - state->CH_Ctrl[5].addr[2] = 70; - state->CH_Ctrl[5].bit[2] = 2; - state->CH_Ctrl[5].val[2] = 0; - state->CH_Ctrl[5].addr[3] = 70; - state->CH_Ctrl[5].bit[3] = 3; - state->CH_Ctrl[5].val[3] = 0; - - state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ; - state->CH_Ctrl[6].size = 1 ; - state->CH_Ctrl[6].addr[0] = 70; - state->CH_Ctrl[6].bit[0] = 4; - state->CH_Ctrl[6].val[0] = 1; - - state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ; - state->CH_Ctrl[7].size = 1 ; - state->CH_Ctrl[7].addr[0] = 111; - state->CH_Ctrl[7].bit[0] = 4; - state->CH_Ctrl[7].val[0] = 0; - - state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ; - state->CH_Ctrl[8].size = 1 ; - state->CH_Ctrl[8].addr[0] = 111; - state->CH_Ctrl[8].bit[0] = 7; - state->CH_Ctrl[8].val[0] = 1; - - state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ; - state->CH_Ctrl[9].size = 1 ; - state->CH_Ctrl[9].addr[0] = 111; - state->CH_Ctrl[9].bit[0] = 6; - state->CH_Ctrl[9].val[0] = 1; - - state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ; - state->CH_Ctrl[10].size = 1 ; - state->CH_Ctrl[10].addr[0] = 111; - state->CH_Ctrl[10].bit[0] = 5; - state->CH_Ctrl[10].val[0] = 0; - - state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ; - state->CH_Ctrl[11].size = 2 ; - state->CH_Ctrl[11].addr[0] = 110; - state->CH_Ctrl[11].bit[0] = 0; - state->CH_Ctrl[11].val[0] = 1; - state->CH_Ctrl[11].addr[1] = 110; - state->CH_Ctrl[11].bit[1] = 1; - state->CH_Ctrl[11].val[1] = 0; - - state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ; - state->CH_Ctrl[12].size = 3 ; - state->CH_Ctrl[12].addr[0] = 69; - state->CH_Ctrl[12].bit[0] = 2; - state->CH_Ctrl[12].val[0] = 0; - state->CH_Ctrl[12].addr[1] = 69; - state->CH_Ctrl[12].bit[1] = 3; - state->CH_Ctrl[12].val[1] = 0; - state->CH_Ctrl[12].addr[2] = 69; - state->CH_Ctrl[12].bit[2] = 4; - state->CH_Ctrl[12].val[2] = 0; - - state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ; - state->CH_Ctrl[13].size = 6 ; - state->CH_Ctrl[13].addr[0] = 110; - state->CH_Ctrl[13].bit[0] = 2; - state->CH_Ctrl[13].val[0] = 0; - state->CH_Ctrl[13].addr[1] = 110; - state->CH_Ctrl[13].bit[1] = 3; - state->CH_Ctrl[13].val[1] = 0; - state->CH_Ctrl[13].addr[2] = 110; - state->CH_Ctrl[13].bit[2] = 4; - state->CH_Ctrl[13].val[2] = 0; - state->CH_Ctrl[13].addr[3] = 110; - state->CH_Ctrl[13].bit[3] = 5; - state->CH_Ctrl[13].val[3] = 0; - state->CH_Ctrl[13].addr[4] = 110; - state->CH_Ctrl[13].bit[4] = 6; - state->CH_Ctrl[13].val[4] = 0; - state->CH_Ctrl[13].addr[5] = 110; - state->CH_Ctrl[13].bit[5] = 7; - state->CH_Ctrl[13].val[5] = 1; - - state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ; - state->CH_Ctrl[14].size = 7 ; - state->CH_Ctrl[14].addr[0] = 14; - state->CH_Ctrl[14].bit[0] = 0; - state->CH_Ctrl[14].val[0] = 0; - state->CH_Ctrl[14].addr[1] = 14; - state->CH_Ctrl[14].bit[1] = 1; - state->CH_Ctrl[14].val[1] = 0; - state->CH_Ctrl[14].addr[2] = 14; - state->CH_Ctrl[14].bit[2] = 2; - state->CH_Ctrl[14].val[2] = 0; - state->CH_Ctrl[14].addr[3] = 14; - state->CH_Ctrl[14].bit[3] = 3; - state->CH_Ctrl[14].val[3] = 0; - state->CH_Ctrl[14].addr[4] = 14; - state->CH_Ctrl[14].bit[4] = 4; - state->CH_Ctrl[14].val[4] = 0; - state->CH_Ctrl[14].addr[5] = 14; - state->CH_Ctrl[14].bit[5] = 5; - state->CH_Ctrl[14].val[5] = 0; - state->CH_Ctrl[14].addr[6] = 14; - state->CH_Ctrl[14].bit[6] = 6; - state->CH_Ctrl[14].val[6] = 0; - - state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ; - state->CH_Ctrl[15].size = 18 ; - state->CH_Ctrl[15].addr[0] = 17; - state->CH_Ctrl[15].bit[0] = 6; - state->CH_Ctrl[15].val[0] = 0; - state->CH_Ctrl[15].addr[1] = 17; - state->CH_Ctrl[15].bit[1] = 7; - state->CH_Ctrl[15].val[1] = 0; - state->CH_Ctrl[15].addr[2] = 16; - state->CH_Ctrl[15].bit[2] = 0; - state->CH_Ctrl[15].val[2] = 0; - state->CH_Ctrl[15].addr[3] = 16; - state->CH_Ctrl[15].bit[3] = 1; - state->CH_Ctrl[15].val[3] = 0; - state->CH_Ctrl[15].addr[4] = 16; - state->CH_Ctrl[15].bit[4] = 2; - state->CH_Ctrl[15].val[4] = 0; - state->CH_Ctrl[15].addr[5] = 16; - state->CH_Ctrl[15].bit[5] = 3; - state->CH_Ctrl[15].val[5] = 0; - state->CH_Ctrl[15].addr[6] = 16; - state->CH_Ctrl[15].bit[6] = 4; - state->CH_Ctrl[15].val[6] = 0; - state->CH_Ctrl[15].addr[7] = 16; - state->CH_Ctrl[15].bit[7] = 5; - state->CH_Ctrl[15].val[7] = 0; - state->CH_Ctrl[15].addr[8] = 16; - state->CH_Ctrl[15].bit[8] = 6; - state->CH_Ctrl[15].val[8] = 0; - state->CH_Ctrl[15].addr[9] = 16; - state->CH_Ctrl[15].bit[9] = 7; - state->CH_Ctrl[15].val[9] = 0; - state->CH_Ctrl[15].addr[10] = 15; - state->CH_Ctrl[15].bit[10] = 0; - state->CH_Ctrl[15].val[10] = 0; - state->CH_Ctrl[15].addr[11] = 15; - state->CH_Ctrl[15].bit[11] = 1; - state->CH_Ctrl[15].val[11] = 0; - state->CH_Ctrl[15].addr[12] = 15; - state->CH_Ctrl[15].bit[12] = 2; - state->CH_Ctrl[15].val[12] = 0; - state->CH_Ctrl[15].addr[13] = 15; - state->CH_Ctrl[15].bit[13] = 3; - state->CH_Ctrl[15].val[13] = 0; - state->CH_Ctrl[15].addr[14] = 15; - state->CH_Ctrl[15].bit[14] = 4; - state->CH_Ctrl[15].val[14] = 0; - state->CH_Ctrl[15].addr[15] = 15; - state->CH_Ctrl[15].bit[15] = 5; - state->CH_Ctrl[15].val[15] = 0; - state->CH_Ctrl[15].addr[16] = 15; - state->CH_Ctrl[15].bit[16] = 6; - state->CH_Ctrl[15].val[16] = 1; - state->CH_Ctrl[15].addr[17] = 15; - state->CH_Ctrl[15].bit[17] = 7; - state->CH_Ctrl[15].val[17] = 1; - - state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ; - state->CH_Ctrl[16].size = 5 ; - state->CH_Ctrl[16].addr[0] = 112; - state->CH_Ctrl[16].bit[0] = 0; - state->CH_Ctrl[16].val[0] = 0; - state->CH_Ctrl[16].addr[1] = 112; - state->CH_Ctrl[16].bit[1] = 1; - state->CH_Ctrl[16].val[1] = 0; - state->CH_Ctrl[16].addr[2] = 112; - state->CH_Ctrl[16].bit[2] = 2; - state->CH_Ctrl[16].val[2] = 0; - state->CH_Ctrl[16].addr[3] = 112; - state->CH_Ctrl[16].bit[3] = 3; - state->CH_Ctrl[16].val[3] = 0; - state->CH_Ctrl[16].addr[4] = 112; - state->CH_Ctrl[16].bit[4] = 4; - state->CH_Ctrl[16].val[4] = 1; - - state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ; - state->CH_Ctrl[17].size = 1 ; - state->CH_Ctrl[17].addr[0] = 14; - state->CH_Ctrl[17].bit[0] = 7; - state->CH_Ctrl[17].val[0] = 0; - - state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ; - state->CH_Ctrl[18].size = 4 ; - state->CH_Ctrl[18].addr[0] = 107; - state->CH_Ctrl[18].bit[0] = 3; - state->CH_Ctrl[18].val[0] = 0; - state->CH_Ctrl[18].addr[1] = 107; - state->CH_Ctrl[18].bit[1] = 4; - state->CH_Ctrl[18].val[1] = 0; - state->CH_Ctrl[18].addr[2] = 107; - state->CH_Ctrl[18].bit[2] = 5; - state->CH_Ctrl[18].val[2] = 0; - state->CH_Ctrl[18].addr[3] = 107; - state->CH_Ctrl[18].bit[3] = 6; - state->CH_Ctrl[18].val[3] = 0; - - state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ; - state->CH_Ctrl[19].size = 3 ; - state->CH_Ctrl[19].addr[0] = 107; - state->CH_Ctrl[19].bit[0] = 7; - state->CH_Ctrl[19].val[0] = 1; - state->CH_Ctrl[19].addr[1] = 106; - state->CH_Ctrl[19].bit[1] = 0; - state->CH_Ctrl[19].val[1] = 1; - state->CH_Ctrl[19].addr[2] = 106; - state->CH_Ctrl[19].bit[2] = 1; - state->CH_Ctrl[19].val[2] = 1; - - state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ; - state->CH_Ctrl[20].size = 11 ; - state->CH_Ctrl[20].addr[0] = 109; - state->CH_Ctrl[20].bit[0] = 2; - state->CH_Ctrl[20].val[0] = 0; - state->CH_Ctrl[20].addr[1] = 109; - state->CH_Ctrl[20].bit[1] = 3; - state->CH_Ctrl[20].val[1] = 0; - state->CH_Ctrl[20].addr[2] = 109; - state->CH_Ctrl[20].bit[2] = 4; - state->CH_Ctrl[20].val[2] = 0; - state->CH_Ctrl[20].addr[3] = 109; - state->CH_Ctrl[20].bit[3] = 5; - state->CH_Ctrl[20].val[3] = 0; - state->CH_Ctrl[20].addr[4] = 109; - state->CH_Ctrl[20].bit[4] = 6; - state->CH_Ctrl[20].val[4] = 0; - state->CH_Ctrl[20].addr[5] = 109; - state->CH_Ctrl[20].bit[5] = 7; - state->CH_Ctrl[20].val[5] = 0; - state->CH_Ctrl[20].addr[6] = 108; - state->CH_Ctrl[20].bit[6] = 0; - state->CH_Ctrl[20].val[6] = 0; - state->CH_Ctrl[20].addr[7] = 108; - state->CH_Ctrl[20].bit[7] = 1; - state->CH_Ctrl[20].val[7] = 0; - state->CH_Ctrl[20].addr[8] = 108; - state->CH_Ctrl[20].bit[8] = 2; - state->CH_Ctrl[20].val[8] = 1; - state->CH_Ctrl[20].addr[9] = 108; - state->CH_Ctrl[20].bit[9] = 3; - state->CH_Ctrl[20].val[9] = 1; - state->CH_Ctrl[20].addr[10] = 108; - state->CH_Ctrl[20].bit[10] = 4; - state->CH_Ctrl[20].val[10] = 1; - - state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ; - state->CH_Ctrl[21].size = 6 ; - state->CH_Ctrl[21].addr[0] = 106; - state->CH_Ctrl[21].bit[0] = 2; - state->CH_Ctrl[21].val[0] = 0; - state->CH_Ctrl[21].addr[1] = 106; - state->CH_Ctrl[21].bit[1] = 3; - state->CH_Ctrl[21].val[1] = 0; - state->CH_Ctrl[21].addr[2] = 106; - state->CH_Ctrl[21].bit[2] = 4; - state->CH_Ctrl[21].val[2] = 0; - state->CH_Ctrl[21].addr[3] = 106; - state->CH_Ctrl[21].bit[3] = 5; - state->CH_Ctrl[21].val[3] = 0; - state->CH_Ctrl[21].addr[4] = 106; - state->CH_Ctrl[21].bit[4] = 6; - state->CH_Ctrl[21].val[4] = 0; - state->CH_Ctrl[21].addr[5] = 106; - state->CH_Ctrl[21].bit[5] = 7; - state->CH_Ctrl[21].val[5] = 1; - - state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ; - state->CH_Ctrl[22].size = 1 ; - state->CH_Ctrl[22].addr[0] = 138; - state->CH_Ctrl[22].bit[0] = 4; - state->CH_Ctrl[22].val[0] = 1; - - state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ; - state->CH_Ctrl[23].size = 1 ; - state->CH_Ctrl[23].addr[0] = 17; - state->CH_Ctrl[23].bit[0] = 5; - state->CH_Ctrl[23].val[0] = 0; - - state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ; - state->CH_Ctrl[24].size = 1 ; - state->CH_Ctrl[24].addr[0] = 111; - state->CH_Ctrl[24].bit[0] = 3; - state->CH_Ctrl[24].val[0] = 0; - - state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ; - state->CH_Ctrl[25].size = 1 ; - state->CH_Ctrl[25].addr[0] = 112; - state->CH_Ctrl[25].bit[0] = 7; - state->CH_Ctrl[25].val[0] = 0; - - state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ; - state->CH_Ctrl[26].size = 1 ; - state->CH_Ctrl[26].addr[0] = 136; - state->CH_Ctrl[26].bit[0] = 7; - state->CH_Ctrl[26].val[0] = 0; - - state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ; - state->CH_Ctrl[27].size = 1 ; - state->CH_Ctrl[27].addr[0] = 149; - state->CH_Ctrl[27].bit[0] = 7; - state->CH_Ctrl[27].val[0] = 0; - - state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ; - state->CH_Ctrl[28].size = 1 ; - state->CH_Ctrl[28].addr[0] = 149; - state->CH_Ctrl[28].bit[0] = 6; - state->CH_Ctrl[28].val[0] = 0; - - state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ; - state->CH_Ctrl[29].size = 1 ; - state->CH_Ctrl[29].addr[0] = 149; - state->CH_Ctrl[29].bit[0] = 5; - state->CH_Ctrl[29].val[0] = 1; - - state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ; - state->CH_Ctrl[30].size = 1 ; - state->CH_Ctrl[30].addr[0] = 149; - state->CH_Ctrl[30].bit[0] = 4; - state->CH_Ctrl[30].val[0] = 1; - - state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ; - state->CH_Ctrl[31].size = 1 ; - state->CH_Ctrl[31].addr[0] = 149; - state->CH_Ctrl[31].bit[0] = 3; - state->CH_Ctrl[31].val[0] = 0; - - state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ; - state->CH_Ctrl[32].size = 1 ; - state->CH_Ctrl[32].addr[0] = 93; - state->CH_Ctrl[32].bit[0] = 1; - state->CH_Ctrl[32].val[0] = 0; - - state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ; - state->CH_Ctrl[33].size = 1 ; - state->CH_Ctrl[33].addr[0] = 93; - state->CH_Ctrl[33].bit[0] = 0; - state->CH_Ctrl[33].val[0] = 0; - - state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ; - state->CH_Ctrl[34].size = 6 ; - state->CH_Ctrl[34].addr[0] = 92; - state->CH_Ctrl[34].bit[0] = 2; - state->CH_Ctrl[34].val[0] = 0; - state->CH_Ctrl[34].addr[1] = 92; - state->CH_Ctrl[34].bit[1] = 3; - state->CH_Ctrl[34].val[1] = 0; - state->CH_Ctrl[34].addr[2] = 92; - state->CH_Ctrl[34].bit[2] = 4; - state->CH_Ctrl[34].val[2] = 0; - state->CH_Ctrl[34].addr[3] = 92; - state->CH_Ctrl[34].bit[3] = 5; - state->CH_Ctrl[34].val[3] = 0; - state->CH_Ctrl[34].addr[4] = 92; - state->CH_Ctrl[34].bit[4] = 6; - state->CH_Ctrl[34].val[4] = 0; - state->CH_Ctrl[34].addr[5] = 92; - state->CH_Ctrl[34].bit[5] = 7; - state->CH_Ctrl[34].val[5] = 0; - - state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ; - state->CH_Ctrl[35].size = 6 ; - state->CH_Ctrl[35].addr[0] = 93; - state->CH_Ctrl[35].bit[0] = 2; - state->CH_Ctrl[35].val[0] = 0; - state->CH_Ctrl[35].addr[1] = 93; - state->CH_Ctrl[35].bit[1] = 3; - state->CH_Ctrl[35].val[1] = 0; - state->CH_Ctrl[35].addr[2] = 93; - state->CH_Ctrl[35].bit[2] = 4; - state->CH_Ctrl[35].val[2] = 0; - state->CH_Ctrl[35].addr[3] = 93; - state->CH_Ctrl[35].bit[3] = 5; - state->CH_Ctrl[35].val[3] = 0; - state->CH_Ctrl[35].addr[4] = 93; - state->CH_Ctrl[35].bit[4] = 6; - state->CH_Ctrl[35].val[4] = 0; - state->CH_Ctrl[35].addr[5] = 93; - state->CH_Ctrl[35].bit[5] = 7; - state->CH_Ctrl[35].val[5] = 0; - -#ifdef _MXL_PRODUCTION - state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ; - state->CH_Ctrl[36].size = 1 ; - state->CH_Ctrl[36].addr[0] = 109; - state->CH_Ctrl[36].bit[0] = 1; - state->CH_Ctrl[36].val[0] = 1; - - state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ; - state->CH_Ctrl[37].size = 2 ; - state->CH_Ctrl[37].addr[0] = 112; - state->CH_Ctrl[37].bit[0] = 5; - state->CH_Ctrl[37].val[0] = 0; - state->CH_Ctrl[37].addr[1] = 112; - state->CH_Ctrl[37].bit[1] = 6; - state->CH_Ctrl[37].val[1] = 0; - - state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ; - state->CH_Ctrl[38].size = 1 ; - state->CH_Ctrl[38].addr[0] = 65; - state->CH_Ctrl[38].bit[0] = 1; - state->CH_Ctrl[38].val[0] = 0; -#endif - - return 0 ; -} - -static void InitTunerControls(struct dvb_frontend *fe) -{ - MXL5005_RegisterInit(fe); - MXL5005_ControlInit(fe); -#ifdef _MXL_INTERNAL - MXL5005_MXLControlInit(fe); -#endif -} - -static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, - u8 Mode, /* 0: Analog Mode ; 1: Digital Mode */ - u8 IF_mode, /* for Analog Mode, 0: zero IF; 1: low IF */ - u32 Bandwidth, /* filter channel bandwidth (6, 7, 8) */ - u32 IF_out, /* Desired IF Out Frequency */ - u32 Fxtal, /* XTAL Frequency */ - u8 AGC_Mode, /* AGC Mode - Dual AGC: 0, Single AGC: 1 */ - u16 TOP, /* 0: Dual AGC; Value: take over point */ - u16 IF_OUT_LOAD, /* IF Out Load Resistor (200 / 300 Ohms) */ - u8 CLOCK_OUT, /* 0: turn off clk out; 1: turn on clock out */ - u8 DIV_OUT, /* 0: Div-1; 1: Div-4 */ - u8 CAPSELECT, /* 0: disable On-Chip pulling cap; 1: enable */ - u8 EN_RSSI, /* 0: disable RSSI; 1: enable RSSI */ - - /* Modulation Type; */ - /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ - u8 Mod_Type, - - /* Tracking Filter */ - /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ - u8 TF_Type - ) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; - - state->Mode = Mode; - state->IF_Mode = IF_mode; - state->Chan_Bandwidth = Bandwidth; - state->IF_OUT = IF_out; - state->Fxtal = Fxtal; - state->AGC_Mode = AGC_Mode; - state->TOP = TOP; - state->IF_OUT_LOAD = IF_OUT_LOAD; - state->CLOCK_OUT = CLOCK_OUT; - state->DIV_OUT = DIV_OUT; - state->CAPSELECT = CAPSELECT; - state->EN_RSSI = EN_RSSI; - state->Mod_Type = Mod_Type; - state->TF_Type = TF_Type; - - /* Initialize all the controls and registers */ - InitTunerControls(fe); - - /* Synthesizer LO frequency calculation */ - MXL_SynthIFLO_Calc(fe); - - return status; -} - -static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - if (state->Mode == 1) /* Digital Mode */ - state->IF_LO = state->IF_OUT; - else /* Analog Mode */ { - if (state->IF_Mode == 0) /* Analog Zero IF mode */ - state->IF_LO = state->IF_OUT + 400000; - else /* Analog Low IF mode */ - state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2; - } -} - -static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - - if (state->Mode == 1) /* Digital Mode */ { - /* remove 20.48MHz setting for 2.6.10 */ - state->RF_LO = state->RF_IN; - /* change for 2.6.6 */ - state->TG_LO = state->RF_IN - 750000; - } else /* Analog Mode */ { - if (state->IF_Mode == 0) /* Analog Zero IF mode */ { - state->RF_LO = state->RF_IN - 400000; - state->TG_LO = state->RF_IN - 1750000; - } else /* Analog Low IF mode */ { - state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2; - state->TG_LO = state->RF_IN - - state->Chan_Bandwidth + 500000; - } - } -} - -static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe) -{ - u16 status = 0; - - status += MXL_ControlWrite(fe, OVERRIDE_1, 1); - status += MXL_ControlWrite(fe, OVERRIDE_2, 1); - status += MXL_ControlWrite(fe, OVERRIDE_3, 1); - status += MXL_ControlWrite(fe, OVERRIDE_4, 1); - - return status; -} - -static u16 MXL_BlockInit(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; - - status += MXL_OverwriteICDefault(fe); - - /* Downconverter Control Dig Ana */ - status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0); - - /* Filter Control Dig Ana */ - status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1); - status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2); - status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0); - status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1); - status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0); - - /* Initialize Low-Pass Filter */ - if (state->Mode) { /* Digital Mode */ - switch (state->Chan_Bandwidth) { - case 8000000: - status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0); - break; - case 7000000: - status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2); - break; - case 6000000: - status += MXL_ControlWrite(fe, - BB_DLPF_BANDSEL, 3); - break; - } - } else { /* Analog Mode */ - switch (state->Chan_Bandwidth) { - case 8000000: /* Low Zero */ - status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, - (state->IF_Mode ? 0 : 3)); - break; - case 7000000: - status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, - (state->IF_Mode ? 1 : 4)); - break; - case 6000000: - status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, - (state->IF_Mode ? 2 : 5)); - break; - } - } - - /* Charge Pump Control Dig Ana */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8); - status += MXL_ControlWrite(fe, - RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1); - status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0); - - /* AGC TOP Control */ - if (state->AGC_Mode == 0) /* Dual AGC */ { - status += MXL_ControlWrite(fe, AGC_IF, 15); - status += MXL_ControlWrite(fe, AGC_RF, 15); - } else /* Single AGC Mode Dig Ana */ - status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12); - - if (state->TOP == 55) /* TOP == 5.5 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x0); - - if (state->TOP == 72) /* TOP == 7.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x1); - - if (state->TOP == 92) /* TOP == 9.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x2); - - if (state->TOP == 110) /* TOP == 11.0 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x3); - - if (state->TOP == 129) /* TOP == 12.9 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x4); - - if (state->TOP == 147) /* TOP == 14.7 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x5); - - if (state->TOP == 168) /* TOP == 16.8 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x6); - - if (state->TOP == 194) /* TOP == 19.4 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x7); - - if (state->TOP == 212) /* TOP == 21.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0x9); - - if (state->TOP == 232) /* TOP == 23.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xA); - - if (state->TOP == 252) /* TOP == 25.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xB); - - if (state->TOP == 271) /* TOP == 27.1 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xC); - - if (state->TOP == 292) /* TOP == 29.2 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xD); - - if (state->TOP == 317) /* TOP == 31.7 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xE); - - if (state->TOP == 349) /* TOP == 34.9 */ - status += MXL_ControlWrite(fe, AGC_IF, 0xF); - - /* IF Synthesizer Control */ - status += MXL_IFSynthInit(fe); - - /* IF UpConverter Control */ - if (state->IF_OUT_LOAD == 200) { - status += MXL_ControlWrite(fe, DRV_RES_SEL, 6); - status += MXL_ControlWrite(fe, I_DRIVER, 2); - } - if (state->IF_OUT_LOAD == 300) { - status += MXL_ControlWrite(fe, DRV_RES_SEL, 4); - status += MXL_ControlWrite(fe, I_DRIVER, 1); - } - - /* Anti-Alias Filtering Control - * initialise Anti-Aliasing Filter - */ - if (state->Mode) { /* Digital Mode */ - if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) { - status += MXL_ControlWrite(fe, EN_AAF, 1); - status += MXL_ControlWrite(fe, EN_3P, 1); - status += MXL_ControlWrite(fe, EN_AUX_3P, 1); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); - } - if ((state->IF_OUT == 36125000UL) || - (state->IF_OUT == 36150000UL)) { - status += MXL_ControlWrite(fe, EN_AAF, 1); - status += MXL_ControlWrite(fe, EN_3P, 1); - status += MXL_ControlWrite(fe, EN_AUX_3P, 1); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); - } - if (state->IF_OUT > 36150000UL) { - status += MXL_ControlWrite(fe, EN_AAF, 0); - status += MXL_ControlWrite(fe, EN_3P, 1); - status += MXL_ControlWrite(fe, EN_AUX_3P, 1); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); - } - } else { /* Analog Mode */ - if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) { - status += MXL_ControlWrite(fe, EN_AAF, 1); - status += MXL_ControlWrite(fe, EN_3P, 1); - status += MXL_ControlWrite(fe, EN_AUX_3P, 1); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); - } - if (state->IF_OUT > 5000000UL) { - status += MXL_ControlWrite(fe, EN_AAF, 0); - status += MXL_ControlWrite(fe, EN_3P, 0); - status += MXL_ControlWrite(fe, EN_AUX_3P, 0); - status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); - } - } - - /* Demod Clock Out */ - if (state->CLOCK_OUT) - status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1); - else - status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0); - - if (state->DIV_OUT == 1) - status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1); - if (state->DIV_OUT == 0) - status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0); - - /* Crystal Control */ - if (state->CAPSELECT) - status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1); - else - status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0); - - if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) - status += MXL_ControlWrite(fe, IF_SEL_DBL, 1); - if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) - status += MXL_ControlWrite(fe, IF_SEL_DBL, 0); - - if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) - status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3); - if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL) - status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0); - - /* Misc Controls */ - if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */ - status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0); - else - status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1); - - /* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */ - - /* Set TG_R_DIV */ - status += MXL_ControlWrite(fe, TG_R_DIV, - MXL_Ceiling(state->Fxtal, 1000000)); - - /* Apply Default value to BB_INITSTATE_DLPF_TUNE */ - - /* RSSI Control */ - if (state->EN_RSSI) { - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); - - /* TOP point */ - status += MXL_ControlWrite(fe, RFA_FLR, 0); - status += MXL_ControlWrite(fe, RFA_CEIL, 12); - } - - /* Modulation type bit settings - * Override the control values preset - */ - if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ { - state->AGC_Mode = 1; /* Single AGC Mode */ - - /* Enable RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); - - /* TOP point */ - status += MXL_ControlWrite(fe, RFA_FLR, 2); - status += MXL_ControlWrite(fe, RFA_CEIL, 13); - if (state->IF_OUT <= 6280000UL) /* Low IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 0); - else /* High IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - - } - if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ { - state->AGC_Mode = 1; /* Single AGC Mode */ - - /* Enable RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); - - /* TOP point */ - status += MXL_ControlWrite(fe, RFA_FLR, 2); - status += MXL_ControlWrite(fe, RFA_CEIL, 13); - status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1); - /* Low Zero */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); - - if (state->IF_OUT <= 6280000UL) /* Low IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 0); - else /* High IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - } - if (state->Mod_Type == MXL_QAM) /* QAM Mode */ { - state->Mode = MXL_DIGITAL_MODE; - - /* state->AGC_Mode = 1; */ /* Single AGC Mode */ - - /* Disable RSSI */ /* change here for v2.6.5 */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); - /* change here for v2.6.5 */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); - - if (state->IF_OUT <= 6280000UL) /* Low IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 0); - else /* High IF */ - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); - - } - if (state->Mod_Type == MXL_ANALOG_CABLE) { - /* Analog Cable Mode */ - /* state->Mode = MXL_DIGITAL_MODE; */ - - state->AGC_Mode = 1; /* Single AGC Mode */ - - /* Disable RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - /* change for 2.6.3 */ - status += MXL_ControlWrite(fe, AGC_IF, 1); - status += MXL_ControlWrite(fe, AGC_RF, 15); - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - } - - if (state->Mod_Type == MXL_ANALOG_OTA) { - /* Analog OTA Terrestrial mode add for 2.6.7 */ - /* state->Mode = MXL_ANALOG_MODE; */ - - /* Enable RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); - status += MXL_ControlWrite(fe, BB_IQSWAP, 1); - } - - /* RSSI disable */ - if (state->EN_RSSI == 0) { - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - } - - return status; -} - -static u16 MXL_IFSynthInit(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0 ; - u32 Fref = 0 ; - u32 Kdbl, intModVal ; - u32 fracModVal ; - Kdbl = 2 ; - - if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) - Kdbl = 2 ; - if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) - Kdbl = 1 ; - - /* IF Synthesizer Control */ - if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ { - if (state->IF_LO == 41000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 328000000UL ; - } - if (state->IF_LO == 47000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 376000000UL ; - } - if (state->IF_LO == 54000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 324000000UL ; - } - if (state->IF_LO == 60000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 39250000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 314000000UL ; - } - if (state->IF_LO == 39650000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 317200000UL ; - } - if (state->IF_LO == 40150000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 321200000UL ; - } - if (state->IF_LO == 40650000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 325200000UL ; - } - } - - if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) { - if (state->IF_LO == 57000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 342000000UL ; - } - if (state->IF_LO == 44000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 352000000UL ; - } - if (state->IF_LO == 43750000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 350000000UL ; - } - if (state->IF_LO == 36650000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 366500000UL ; - } - if (state->IF_LO == 36150000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 361500000UL ; - } - if (state->IF_LO == 36000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 35250000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 352500000UL ; - } - if (state->IF_LO == 34750000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 347500000UL ; - } - if (state->IF_LO == 6280000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 376800000UL ; - } - if (state->IF_LO == 5000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 4500000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 4570000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 365600000UL ; - } - if (state->IF_LO == 4000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 57400000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 344400000UL ; - } - if (state->IF_LO == 44400000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 355200000UL ; - } - if (state->IF_LO == 44150000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 353200000UL ; - } - if (state->IF_LO == 37050000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 370500000UL ; - } - if (state->IF_LO == 36550000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 365500000UL ; - } - if (state->IF_LO == 36125000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 361250000UL ; - } - if (state->IF_LO == 6000000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 360000000UL ; - } - if (state->IF_LO == 5400000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 324000000UL ; - } - if (state->IF_LO == 5380000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); - Fref = 322800000UL ; - } - if (state->IF_LO == 5200000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 374400000UL ; - } - if (state->IF_LO == 4900000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 352800000UL ; - } - if (state->IF_LO == 4400000UL) { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 352000000UL ; - } - if (state->IF_LO == 4063000UL) /* add for 2.6.8 */ { - status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); - status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); - Fref = 365670000UL ; - } - } - /* CHCAL_INT_MOD_IF */ - /* CHCAL_FRAC_MOD_IF */ - intModVal = Fref / (state->Fxtal * Kdbl/2); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal); - - fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) * - intModVal); - - fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000); - status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal); - - return status ; -} - -static u32 MXL_GetXtalInt(u32 Xtal_Freq) -{ - if ((Xtal_Freq % 1000000) == 0) - return (Xtal_Freq / 10000); - else - return (((Xtal_Freq / 1000000) + 1)*100); -} - -static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; - u32 divider_val, E3, E4, E5, E5A; - u32 Fmax, Fmin, FmaxBin, FminBin; - u32 Kdbl_RF = 2; - u32 tg_divval; - u32 tg_lo; - u32 Xtal_Int; - - u32 Fref_TG; - u32 Fvco; - - Xtal_Int = MXL_GetXtalInt(state->Fxtal); - - state->RF_IN = RF_Freq; - - MXL_SynthRFTGLO_Calc(fe); - - if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) - Kdbl_RF = 2; - if (state->Fxtal > 22000000 && state->Fxtal <= 32000000) - Kdbl_RF = 1; - - /* Downconverter Controls - * Look-Up Table Implementation for: - * DN_POLY - * DN_RFGAIN - * DN_CAP_RFLPF - * DN_EN_VHFUHFBAR - * DN_GAIN_ADJUST - * Change the boundary reference from RF_IN to RF_LO - */ - if (state->RF_LO < 40000000UL) - return -1; - - if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 2); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 423); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); - } - if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 222); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); - } - if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 147); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); - } - if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 9); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); - } - if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 3); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); - } - if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 1); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); - } - if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) { - status += MXL_ControlWrite(fe, DN_POLY, 3); - status += MXL_ControlWrite(fe, DN_RFGAIN, 2); - status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); - status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); - status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); - } - if (state->RF_LO > 900000000UL) - return -1; - - /* DN_IQTNBUF_AMP */ - /* DN_IQTNGNBFBIAS_BST */ - if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); - } - if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); - } - if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) { - status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); - status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); - } - - /* - * Set RF Synth and LO Path Control - * - * Look-Up table implementation for: - * RFSYN_EN_OUTMUX - * RFSYN_SEL_VCO_OUT - * RFSYN_SEL_VCO_HI - * RFSYN_SEL_DIVM - * RFSYN_RF_DIV_BIAS - * DN_SEL_FREQ - * - * Set divider_val, Fmax, Fmix to use in Equations - */ - FminBin = 28000000UL ; - FmaxBin = 42500000UL ; - if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); - divider_val = 64 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 42500000UL ; - FmaxBin = 56000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); - divider_val = 64 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 56000000UL ; - FmaxBin = 85000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); - divider_val = 32 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 85000000UL ; - FmaxBin = 112000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); - divider_val = 32 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 112000000UL ; - FmaxBin = 170000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); - divider_val = 16 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 170000000UL ; - FmaxBin = 225000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); - divider_val = 16 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 225000000UL ; - FmaxBin = 300000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 4); - divider_val = 8 ; - Fmax = 340000000UL ; - Fmin = FminBin ; - } - FminBin = 300000000UL ; - FmaxBin = 340000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - divider_val = 8 ; - Fmax = FmaxBin ; - Fmin = 225000000UL ; - } - FminBin = 340000000UL ; - FmaxBin = 450000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 2); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - divider_val = 8 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 450000000UL ; - FmaxBin = 680000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - divider_val = 4 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 680000000UL ; - FmaxBin = 900000000UL ; - if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - divider_val = 4 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - - /* CHCAL_INT_MOD_RF - * CHCAL_FRAC_MOD_RF - * RFSYN_LPF_R - * CHCAL_EN_INT_RF - */ - /* Equation E3 RFSYN_VCO_BIAS */ - E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ; - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3); - - /* Equation E4 CHCAL_INT_MOD_RF */ - E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000); - MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4); - - /* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */ - E5 = ((2<<17)*(state->RF_LO/10000*divider_val - - (E4*(2*state->Fxtal*Kdbl_RF)/10000))) / - (2*state->Fxtal*Kdbl_RF/10000); - - status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); - - /* Equation E5A RFSYN_LPF_R */ - E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ; - status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A); - - /* Euqation E5B CHCAL_EN_INIT_RF */ - status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0)); - /*if (E5 == 0) - * status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1); - *else - * status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); - */ - - /* - * Set TG Synth - * - * Look-Up table implementation for: - * TG_LO_DIVVAL - * TG_LO_SELVAL - * - * Set divider_val, Fmax, Fmix to use in Equations - */ - if (state->TG_LO < 33000000UL) - return -1; - - FminBin = 33000000UL ; - FmaxBin = 50000000UL ; - if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x6); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); - divider_val = 36 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 50000000UL ; - FmaxBin = 67000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x1); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); - divider_val = 24 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 67000000UL ; - FmaxBin = 100000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0xC); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); - divider_val = 18 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 100000000UL ; - FmaxBin = 150000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); - divider_val = 12 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 150000000UL ; - FmaxBin = 200000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); - divider_val = 8 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 200000000UL ; - FmaxBin = 300000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); - divider_val = 6 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 300000000UL ; - FmaxBin = 400000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); - divider_val = 4 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 400000000UL ; - FmaxBin = 600000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); - divider_val = 3 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - FminBin = 600000000UL ; - FmaxBin = 900000000UL ; - if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { - status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); - status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); - divider_val = 2 ; - Fmax = FmaxBin ; - Fmin = FminBin ; - } - - /* TG_DIV_VAL */ - tg_divval = (state->TG_LO*divider_val/100000) * - (MXL_Ceiling(state->Fxtal, 1000000) * 100) / - (state->Fxtal/1000); - - status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval); - - if (state->TG_LO > 600000000UL) - status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1); - - Fmax = 1800000000UL ; - Fmin = 1200000000UL ; - - /* prevent overflow of 32 bit unsigned integer, use - * following equation. Edit for v2.6.4 - */ - /* Fref_TF = Fref_TG * 1000 */ - Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000); - - /* Fvco = Fvco/10 */ - Fvco = (state->TG_LO/10000) * divider_val * Fref_TG; - - tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8; - - /* below equation is same as above but much harder to debug. - * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) - - * ((state->TG_LO/10000)*divider_val * - * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 * - * Xtal_Int/100) + 8; - */ - - status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo); - - /* add for 2.6.5 Special setting for QAM */ - if (state->Mod_Type == MXL_QAM) { - if (state->config->qam_gain != 0) - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, - state->config->qam_gain); - else if (state->RF_IN < 680000000) - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); - else - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); - } - - /* Off Chip Tracking Filter Control */ - if (state->TF_Type == MXL_TF_OFF) { - /* Tracking Filter Off State; turn off all the banks */ - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */ - status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */ - status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */ - } - - if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_A, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - } - if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 4, 1); - } - if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 4, 0); - } - if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 0); - } - if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 29); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 0); - } - if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 0); - } - if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 16); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - } - if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 7); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - } - if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - } - } - - if (state->TF_Type == MXL_TF_C_H) { - - /* Tracking Filter type C-H for Hauppauge only */ - status += MXL_ControlWrite(fe, DAC_DIN_A, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - } - if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 0); - status += MXL_SetGPIO(fe, 1, 1); - } - if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 0); - status += MXL_SetGPIO(fe, 1, 0); - } - if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - } - if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - } - if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 0); - } - if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - } - if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - } - if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - } - } - - if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */ - - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_D_L) { - - /* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */ - status += MXL_ControlWrite(fe, DAC_DIN_A, 0); - - /* if UHF and terrestrial => Turn off Tracking Filter */ - if (state->RF_IN >= 471000000 && - (state->RF_IN - 471000000)%6000000 != 0) { - /* Turn off all the banks */ - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_ControlWrite(fe, AGC_IF, 10); - } else { - /* if VHF or cable => Turn on Tracking Filter */ - if (state->RF_IN >= 43000000 && - state->RF_IN < 140000000) { - - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 140000000 && - state->RF_IN < 240000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 240000000 && - state->RF_IN < 340000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 340000000 && - state->RF_IN < 430000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 430000000 && - state->RF_IN < 470000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 470000000 && - state->RF_IN < 570000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 570000000 && - state->RF_IN < 620000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 620000000 && - state->RF_IN < 760000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 760000000 && - state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - } - - if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ { - - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_F) { - - /* Tracking Filter type F */ - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_E_2) { - - /* Tracking Filter type E_2 */ - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_G) { - - /* Tracking Filter type G add for v2.6.8 */ - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) { - - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - - if (state->TF_Type == MXL_TF_E_NA) { - - /* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */ - status += MXL_ControlWrite(fe, DAC_DIN_B, 0); - - /* if UHF and terrestrial=> Turn off Tracking Filter */ - if (state->RF_IN >= 471000000 && - (state->RF_IN - 471000000)%6000000 != 0) { - - /* Turn off all the banks */ - status += MXL_SetGPIO(fe, 3, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - - /* 2.6.12 Turn on RSSI */ - status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); - status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); - status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); - - /* RSSI reference point */ - status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); - status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); - status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); - - /* following parameter is from analog OTA mode, - * can be change to seek better performance */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); - } else { - /* if VHF or Cable => Turn on Tracking Filter */ - - /* 2.6.12 Turn off RSSI */ - status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); - - /* change back from above condition */ - status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); - - - if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { - - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 0); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 1); - } - if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 0); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 0); - } - if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { - status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); - status += MXL_SetGPIO(fe, 4, 1); - status += MXL_SetGPIO(fe, 1, 1); - status += MXL_SetGPIO(fe, 3, 1); - } - } - } - return status ; -} - -static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val) -{ - u16 status = 0; - - if (GPIO_Num == 1) - status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1); - - /* GPIO2 is not available */ - - if (GPIO_Num == 3) { - if (GPIO_Val == 1) { - status += MXL_ControlWrite(fe, GPIO_3, 0); - status += MXL_ControlWrite(fe, GPIO_3B, 0); - } - if (GPIO_Val == 0) { - status += MXL_ControlWrite(fe, GPIO_3, 1); - status += MXL_ControlWrite(fe, GPIO_3B, 1); - } - if (GPIO_Val == 3) { /* tri-state */ - status += MXL_ControlWrite(fe, GPIO_3, 0); - status += MXL_ControlWrite(fe, GPIO_3B, 1); - } - } - if (GPIO_Num == 4) { - if (GPIO_Val == 1) { - status += MXL_ControlWrite(fe, GPIO_4, 0); - status += MXL_ControlWrite(fe, GPIO_4B, 0); - } - if (GPIO_Val == 0) { - status += MXL_ControlWrite(fe, GPIO_4, 1); - status += MXL_ControlWrite(fe, GPIO_4B, 1); - } - if (GPIO_Val == 3) { /* tri-state */ - status += MXL_ControlWrite(fe, GPIO_4, 0); - status += MXL_ControlWrite(fe, GPIO_4B, 1); - } - } - - return status; -} - -static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value) -{ - u16 status = 0; - - /* Will write ALL Matching Control Name */ - /* Write Matching INIT Control */ - status += MXL_ControlWrite_Group(fe, ControlNum, value, 1); - /* Write Matching CH Control */ - status += MXL_ControlWrite_Group(fe, ControlNum, value, 2); -#ifdef _MXL_INTERNAL - /* Write Matching MXL Control */ - status += MXL_ControlWrite_Group(fe, ControlNum, value, 3); -#endif - return status; -} - -static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, - u32 value, u16 controlGroup) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 i, j, k; - u32 highLimit; - u32 ctrlVal; - - if (controlGroup == 1) /* Initial Control */ { - - for (i = 0; i < state->Init_Ctrl_Num; i++) { - - if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { - - highLimit = 1 << state->Init_Ctrl[i].size; - if (value < highLimit) { - for (j = 0; j < state->Init_Ctrl[i].size; j++) { - state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); - MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]), - (u8)(state->Init_Ctrl[i].bit[j]), - (u8)((value>>j) & 0x01)); - } - ctrlVal = 0; - for (k = 0; k < state->Init_Ctrl[i].size; k++) - ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k); - } else - return -1; - } - } - } - if (controlGroup == 2) /* Chan change Control */ { - - for (i = 0; i < state->CH_Ctrl_Num; i++) { - - if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { - - highLimit = 1 << state->CH_Ctrl[i].size; - if (value < highLimit) { - for (j = 0; j < state->CH_Ctrl[i].size; j++) { - state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); - MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]), - (u8)(state->CH_Ctrl[i].bit[j]), - (u8)((value>>j) & 0x01)); - } - ctrlVal = 0; - for (k = 0; k < state->CH_Ctrl[i].size; k++) - ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); - } else - return -1; - } - } - } -#ifdef _MXL_INTERNAL - if (controlGroup == 3) /* Maxlinear Control */ { - - for (i = 0; i < state->MXL_Ctrl_Num; i++) { - - if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { - - highLimit = (1 << state->MXL_Ctrl[i].size); - if (value < highLimit) { - for (j = 0; j < state->MXL_Ctrl[i].size; j++) { - state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); - MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]), - (u8)(state->MXL_Ctrl[i].bit[j]), - (u8)((value>>j) & 0x01)); - } - ctrlVal = 0; - for (k = 0; k < state->MXL_Ctrl[i].size; k++) - ctrlVal += state-> - MXL_Ctrl[i].val[k] * - (1 << k); - } else - return -1; - } - } - } -#endif - return 0 ; /* successful return */ -} - -static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal) -{ - struct mxl5005s_state *state = fe->tuner_priv; - int i ; - - for (i = 0; i < 104; i++) { - if (RegNum == state->TunerRegs[i].Reg_Num) { - *RegVal = (u8)(state->TunerRegs[i].Reg_Val); - return 0; - } - } - - return 1; -} - -static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u32 ctrlVal ; - u16 i, k ; - - for (i = 0; i < state->Init_Ctrl_Num ; i++) { - - if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { - - ctrlVal = 0; - for (k = 0; k < state->Init_Ctrl[i].size; k++) - ctrlVal += state->Init_Ctrl[i].val[k] * (1<CH_Ctrl_Num ; i++) { - - if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { - - ctrlVal = 0; - for (k = 0; k < state->CH_Ctrl[i].size; k++) - ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); - *value = ctrlVal; - return 0; - - } - } - -#ifdef _MXL_INTERNAL - for (i = 0; i < state->MXL_Ctrl_Num ; i++) { - - if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { - - ctrlVal = 0; - for (k = 0; k < state->MXL_Ctrl[i].size; k++) - ctrlVal += state->MXL_Ctrl[i].val[k] * (1<tuner_priv; - int i ; - - const u8 AND_MAP[8] = { - 0xFE, 0xFD, 0xFB, 0xF7, - 0xEF, 0xDF, 0xBF, 0x7F } ; - - const u8 OR_MAP[8] = { - 0x01, 0x02, 0x04, 0x08, - 0x10, 0x20, 0x40, 0x80 } ; - - for (i = 0; i < state->TunerRegs_Num; i++) { - if (state->TunerRegs[i].Reg_Num == address) { - if (bitVal) - state->TunerRegs[i].Reg_Val |= OR_MAP[bit]; - else - state->TunerRegs[i].Reg_Val &= AND_MAP[bit]; - break ; - } - } -} - -static u32 MXL_Ceiling(u32 value, u32 resolution) -{ - return value / resolution + (value % resolution > 0 ? 1 : 0); -} - -/* Retrieve the Initialzation Registers */ -static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count) -{ - u16 status = 0; - int i ; - - u8 RegAddr[] = { - 11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73, - 76, 77, 91, 134, 135, 137, 147, - 156, 166, 167, 168, 25 }; - - *count = ARRAY_SIZE(RegAddr); - - status += MXL_BlockInit(fe); - - for (i = 0 ; i < *count; i++) { - RegNum[i] = RegAddr[i]; - status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); - } - - return status; -} - -static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, - int *count) -{ - u16 status = 0; - int i ; - -/* add 77, 166, 167, 168 register for 2.6.12 */ -#ifdef _MXL_PRODUCTION - u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106, - 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; -#else - u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106, - 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; - /* - u8 RegAddr[171]; - for (i = 0; i <= 170; i++) - RegAddr[i] = i; - */ -#endif - - *count = ARRAY_SIZE(RegAddr); - - for (i = 0 ; i < *count; i++) { - RegNum[i] = RegAddr[i]; - status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); - } - - return status; -} - -static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, - u8 *RegVal, int *count) -{ - u16 status = 0; - int i; - - u8 RegAddr[] = {43, 136}; - - *count = ARRAY_SIZE(RegAddr); - - for (i = 0; i < *count; i++) { - RegNum[i] = RegAddr[i]; - status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); - } - - return status; -} - -static u16 MXL_GetMasterControl(u8 *MasterReg, int state) -{ - if (state == 1) /* Load_Start */ - *MasterReg = 0xF3; - if (state == 2) /* Power_Down */ - *MasterReg = 0x41; - if (state == 3) /* Synth_Reset */ - *MasterReg = 0xB1; - if (state == 4) /* Seq_Off */ - *MasterReg = 0xF1; - - return 0; -} - -#ifdef _MXL_PRODUCTION -static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0 ; - - if (VCO_Range == 1) { - status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - if (state->Mode == 0 && state->IF_Mode == 1) { - /* Analog Low IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 180224); - } - if (state->Mode == 0 && state->IF_Mode == 0) { - /* Analog Zero IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 222822); - } - if (state->Mode == 1) /* Digital Mode */ { - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 229376); - } - } - - if (VCO_Range == 2) { - status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); - if (state->Mode == 0 && state->IF_Mode == 1) { - /* Analog Low IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 206438); - } - if (state->Mode == 0 && state->IF_Mode == 0) { - /* Analog Zero IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 206438); - } - if (state->Mode == 1) /* Digital Mode */ { - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 16384); - } - } - - if (VCO_Range == 3) { - status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); - if (state->Mode == 0 && state->IF_Mode == 1) { - /* Analog Low IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 173670); - } - if (state->Mode == 0 && state->IF_Mode == 0) { - /* Analog Zero IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 173670); - } - if (state->Mode == 1) /* Digital Mode */ { - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 245760); - } - } - - if (VCO_Range == 4) { - status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); - status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); - status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); - status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); - status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); - if (state->Mode == 0 && state->IF_Mode == 1) { - /* Analog Low IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 206438); - } - if (state->Mode == 0 && state->IF_Mode == 0) { - /* Analog Zero IF Mode */ - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 206438); - } - if (state->Mode == 1) /* Digital Mode */ { - status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); - status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); - status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); - status += MXL_ControlWrite(fe, - CHCAL_FRAC_MOD_RF, 212992); - } - } - - return status; -} - -static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; - - if (Hystersis == 1) - status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1); - - return status; -} -#endif -/* End: Reference driver code found in the Realtek driver that - * is copyright MaxLinear */ - -/* ---------------------------------------------------------------- - * Begin: Everything after here is new code to adapt the - * proprietary Realtek driver into a Linux API tuner. - * Copyright (C) 2008 Steven Toth - */ -static int mxl5005s_reset(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - int ret = 0; - - u8 buf[2] = { 0xff, 0x00 }; - struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, - .buf = buf, .len = 2 }; - - dprintk(2, "%s()\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mxl5005s I2C reset failed\n"); - ret = -EREMOTEIO; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -/* Write a single byte to a single reg, latch the value if required by - * following the transaction with the latch byte. - */ -static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE }; - struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, - .buf = buf, .len = 3 }; - - if (latch == 0) - msg.len = 2; - - dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr); - - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mxl5005s I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, - u8 *datatable, u8 len) -{ - int ret = 0, i; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - for (i = 0 ; i < len-1; i++) { - ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0); - if (ret < 0) - break; - } - - ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -static int mxl5005s_init(struct dvb_frontend *fe) -{ - struct mxl5005s_state *state = fe->tuner_priv; - - dprintk(1, "%s()\n", __func__); - state->current_mode = MXL_QAM; - return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ); -} - -static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, - u32 bandwidth) -{ - struct mxl5005s_state *state = fe->tuner_priv; - - u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; - u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; - int TableLen; - - dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth); - - mxl5005s_reset(fe); - - /* Tuner initialization stage 0 */ - MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); - AddrTable[0] = MASTER_CONTROL_ADDR; - ByteTable[0] |= state->config->AgcMasterByte; - - mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); - - mxl5005s_AssignTunerMode(fe, mod_type, bandwidth); - - /* Tuner initialization stage 1 */ - MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen); - - mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); - - return 0; -} - -static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, - u32 bandwidth) -{ - struct mxl5005s_state *state = fe->tuner_priv; - struct mxl5005s_config *c = state->config; - - InitTunerControls(fe); - - /* Set MxL5005S parameters. */ - MXL5005_TunerConfig( - fe, - c->mod_mode, - c->if_mode, - bandwidth, - c->if_freq, - c->xtal_freq, - c->agc_mode, - c->top, - c->output_load, - c->clock_out, - c->div_out, - c->cap_select, - c->rssi_enable, - mod_type, - c->tracking_filter); - - return 0; -} - -static int mxl5005s_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct mxl5005s_state *state = fe->tuner_priv; - u32 req_mode, req_bw = 0; - int ret; - - dprintk(1, "%s()\n", __func__); - - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - req_mode = MXL_ATSC; break; - default: - case QAM_64: - case QAM_256: - case QAM_AUTO: - req_mode = MXL_QAM; break; - } - } else - req_mode = MXL_DVBT; - - /* Change tuner for new modulation type if reqd */ - if (req_mode != state->current_mode) { - switch (req_mode) { - case MXL_ATSC: - case MXL_QAM: - req_bw = MXL5005S_BANDWIDTH_6MHZ; - break; - case MXL_DVBT: - default: - /* Assume DVB-T */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - req_bw = MXL5005S_BANDWIDTH_6MHZ; - break; - case BANDWIDTH_7_MHZ: - req_bw = MXL5005S_BANDWIDTH_7MHZ; - break; - case BANDWIDTH_AUTO: - case BANDWIDTH_8_MHZ: - req_bw = MXL5005S_BANDWIDTH_8MHZ; - break; - } - } - - state->current_mode = req_mode; - ret = mxl5005s_reconfigure(fe, req_mode, req_bw); - - } else - ret = 0; - - if (ret == 0) { - dprintk(1, "%s() freq=%d\n", __func__, params->frequency); - ret = mxl5005s_SetRfFreqHz(fe, params->frequency); - } - - return ret; -} - -static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mxl5005s_state *state = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - - *frequency = state->RF_IN; - - return 0; -} - -static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mxl5005s_state *state = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - - *bandwidth = state->Chan_Bandwidth; - - return 0; -} - -static int mxl5005s_release(struct dvb_frontend *fe) -{ - dprintk(1, "%s()\n", __func__); - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops mxl5005s_tuner_ops = { - .info = { - .name = "MaxLinear MXL5005S", - .frequency_min = 48000000, - .frequency_max = 860000000, - .frequency_step = 50000, - }, - - .release = mxl5005s_release, - .init = mxl5005s_init, - - .set_params = mxl5005s_set_params, - .get_frequency = mxl5005s_get_frequency, - .get_bandwidth = mxl5005s_get_bandwidth, -}; - -struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mxl5005s_config *config) -{ - struct mxl5005s_state *state = NULL; - dprintk(1, "%s()\n", __func__); - - state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->frontend = fe; - state->config = config; - state->i2c = i2c; - - printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n", - config->i2c_address); - - memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = state; - return fe; -} -EXPORT_SYMBOL(mxl5005s_attach); - -MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver"); -MODULE_AUTHOR("Steven Toth"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5005s.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5005s.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5005s.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5005s.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -/* - MaxLinear MXL5005S VSB/QAM/DVBT tuner driver - - Copyright (C) 2008 MaxLinear - Copyright (C) 2008 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __MXL5005S_H -#define __MXL5005S_H - -#include -#include "dvb_frontend.h" - -struct mxl5005s_config { - - /* 7 bit i2c address */ - u8 i2c_address; - -#define IF_FREQ_4570000HZ 4570000 -#define IF_FREQ_4571429HZ 4571429 -#define IF_FREQ_5380000HZ 5380000 -#define IF_FREQ_36000000HZ 36000000 -#define IF_FREQ_36125000HZ 36125000 -#define IF_FREQ_36166667HZ 36166667 -#define IF_FREQ_44000000HZ 44000000 - u32 if_freq; - -#define CRYSTAL_FREQ_4000000HZ 4000000 -#define CRYSTAL_FREQ_16000000HZ 16000000 -#define CRYSTAL_FREQ_25000000HZ 25000000 -#define CRYSTAL_FREQ_28800000HZ 28800000 - u32 xtal_freq; - -#define MXL_DUAL_AGC 0 -#define MXL_SINGLE_AGC 1 - u8 agc_mode; - -#define MXL_TF_DEFAULT 0 -#define MXL_TF_OFF 1 -#define MXL_TF_C 2 -#define MXL_TF_C_H 3 -#define MXL_TF_D 4 -#define MXL_TF_D_L 5 -#define MXL_TF_E 6 -#define MXL_TF_F 7 -#define MXL_TF_E_2 8 -#define MXL_TF_E_NA 9 -#define MXL_TF_G 10 - u8 tracking_filter; - -#define MXL_RSSI_DISABLE 0 -#define MXL_RSSI_ENABLE 1 - u8 rssi_enable; - -#define MXL_CAP_SEL_DISABLE 0 -#define MXL_CAP_SEL_ENABLE 1 - u8 cap_select; - -#define MXL_DIV_OUT_1 0 -#define MXL_DIV_OUT_4 1 - u8 div_out; - -#define MXL_CLOCK_OUT_DISABLE 0 -#define MXL_CLOCK_OUT_ENABLE 1 - u8 clock_out; - -#define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200 -#define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300 - u32 output_load; - -#define MXL5005S_TOP_5P5 55 -#define MXL5005S_TOP_7P2 72 -#define MXL5005S_TOP_9P2 92 -#define MXL5005S_TOP_11P0 110 -#define MXL5005S_TOP_12P9 129 -#define MXL5005S_TOP_14P7 147 -#define MXL5005S_TOP_16P8 168 -#define MXL5005S_TOP_19P4 194 -#define MXL5005S_TOP_21P2 212 -#define MXL5005S_TOP_23P2 232 -#define MXL5005S_TOP_25P2 252 -#define MXL5005S_TOP_27P1 271 -#define MXL5005S_TOP_29P2 292 -#define MXL5005S_TOP_31P7 317 -#define MXL5005S_TOP_34P9 349 - u32 top; - -#define MXL_ANALOG_MODE 0 -#define MXL_DIGITAL_MODE 1 - u8 mod_mode; - -#define MXL_ZERO_IF 0 -#define MXL_LOW_IF 1 - u8 if_mode; - - /* Some boards need to override the built-in logic for determining - the gain when in QAM mode (the HVR-1600 is one such case) */ - u8 qam_gain; - - /* Stuff I don't know what to do with */ - u8 AgcMasterByte; -}; - -#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \ - (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE)) -extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mxl5005s_config *config); -#else -static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct mxl5005s_config *config) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_TUNER_MXL5005S */ - -#endif /* __MXL5005S_H */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5007t.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5007t.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5007t.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5007t.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,882 +0,0 @@ -/* - * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner - * - * Copyright (C) 2008, 2009 Michael Krufky - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include "tuner-i2c.h" -#include "mxl5007t.h" - -static DEFINE_MUTEX(mxl5007t_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -static int mxl5007t_debug; -module_param_named(debug, mxl5007t_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level"); - -/* ------------------------------------------------------------------------- */ - -#define mxl_printk(kern, fmt, arg...) \ - printk(kern "%s: " fmt "\n", __func__, ##arg) - -#define mxl_err(fmt, arg...) \ - mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) - -#define mxl_warn(fmt, arg...) \ - mxl_printk(KERN_WARNING, fmt, ##arg) - -#define mxl_info(fmt, arg...) \ - mxl_printk(KERN_INFO, fmt, ##arg) - -#define mxl_debug(fmt, arg...) \ -({ \ - if (mxl5007t_debug) \ - mxl_printk(KERN_DEBUG, fmt, ##arg); \ -}) - -#define mxl_fail(ret) \ -({ \ - int __ret; \ - __ret = (ret < 0); \ - if (__ret) \ - mxl_printk(KERN_ERR, "error %d on line %d", \ - ret, __LINE__); \ - __ret; \ -}) - -/* ------------------------------------------------------------------------- */ - -#define MHz 1000000 - -enum mxl5007t_mode { - MxL_MODE_ISDBT = 0, - MxL_MODE_DVBT = 1, - MxL_MODE_ATSC = 2, - MxL_MODE_CABLE = 0x10, -}; - -enum mxl5007t_chip_version { - MxL_UNKNOWN_ID = 0x00, - MxL_5007_V1_F1 = 0x11, - MxL_5007_V1_F2 = 0x12, - MxL_5007_V4 = 0x14, - MxL_5007_V2_100_F1 = 0x21, - MxL_5007_V2_100_F2 = 0x22, - MxL_5007_V2_200_F1 = 0x23, - MxL_5007_V2_200_F2 = 0x24, -}; - -struct reg_pair_t { - u8 reg; - u8 val; -}; - -/* ------------------------------------------------------------------------- */ - -static struct reg_pair_t init_tab[] = { - { 0x02, 0x06 }, - { 0x03, 0x48 }, - { 0x05, 0x04 }, - { 0x06, 0x10 }, - { 0x2e, 0x15 }, /* OVERRIDE */ - { 0x30, 0x10 }, /* OVERRIDE */ - { 0x45, 0x58 }, /* OVERRIDE */ - { 0x48, 0x19 }, /* OVERRIDE */ - { 0x52, 0x03 }, /* OVERRIDE */ - { 0x53, 0x44 }, /* OVERRIDE */ - { 0x6a, 0x4b }, /* OVERRIDE */ - { 0x76, 0x00 }, /* OVERRIDE */ - { 0x78, 0x18 }, /* OVERRIDE */ - { 0x7a, 0x17 }, /* OVERRIDE */ - { 0x85, 0x06 }, /* OVERRIDE */ - { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ - { 0, 0 } -}; - -static struct reg_pair_t init_tab_cable[] = { - { 0x02, 0x06 }, - { 0x03, 0x48 }, - { 0x05, 0x04 }, - { 0x06, 0x10 }, - { 0x09, 0x3f }, - { 0x0a, 0x3f }, - { 0x0b, 0x3f }, - { 0x2e, 0x15 }, /* OVERRIDE */ - { 0x30, 0x10 }, /* OVERRIDE */ - { 0x45, 0x58 }, /* OVERRIDE */ - { 0x48, 0x19 }, /* OVERRIDE */ - { 0x52, 0x03 }, /* OVERRIDE */ - { 0x53, 0x44 }, /* OVERRIDE */ - { 0x6a, 0x4b }, /* OVERRIDE */ - { 0x76, 0x00 }, /* OVERRIDE */ - { 0x78, 0x18 }, /* OVERRIDE */ - { 0x7a, 0x17 }, /* OVERRIDE */ - { 0x85, 0x06 }, /* OVERRIDE */ - { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ - { 0, 0 } -}; - -/* ------------------------------------------------------------------------- */ - -static struct reg_pair_t reg_pair_rftune[] = { - { 0x0f, 0x00 }, /* abort tune */ - { 0x0c, 0x15 }, - { 0x0d, 0x40 }, - { 0x0e, 0x0e }, - { 0x1f, 0x87 }, /* OVERRIDE */ - { 0x20, 0x1f }, /* OVERRIDE */ - { 0x21, 0x87 }, /* OVERRIDE */ - { 0x22, 0x1f }, /* OVERRIDE */ - { 0x80, 0x01 }, /* freq dependent */ - { 0x0f, 0x01 }, /* start tune */ - { 0, 0 } -}; - -/* ------------------------------------------------------------------------- */ - -struct mxl5007t_state { - struct list_head hybrid_tuner_instance_list; - struct tuner_i2c_props i2c_props; - - struct mutex lock; - - struct mxl5007t_config *config; - - enum mxl5007t_chip_version chip_id; - - struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; - struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; - struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; - - u32 frequency; - u32 bandwidth; -}; - -/* ------------------------------------------------------------------------- */ - -/* called by _init and _rftun to manipulate the register arrays */ - -static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) -{ - unsigned int i = 0; - - while (reg_pair[i].reg || reg_pair[i].val) { - if (reg_pair[i].reg == reg) { - reg_pair[i].val &= ~mask; - reg_pair[i].val |= val; - } - i++; - - } - return; -} - -static void copy_reg_bits(struct reg_pair_t *reg_pair1, - struct reg_pair_t *reg_pair2) -{ - unsigned int i, j; - - i = j = 0; - - while (reg_pair1[i].reg || reg_pair1[i].val) { - while (reg_pair2[j].reg || reg_pair2[j].val) { - if (reg_pair1[i].reg != reg_pair2[j].reg) { - j++; - continue; - } - reg_pair2[j].val = reg_pair1[i].val; - break; - } - i++; - } - return; -} - -/* ------------------------------------------------------------------------- */ - -static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, - enum mxl5007t_mode mode, - s32 if_diff_out_level) -{ - switch (mode) { - case MxL_MODE_ATSC: - set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12); - break; - case MxL_MODE_DVBT: - set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11); - break; - case MxL_MODE_ISDBT: - set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10); - break; - case MxL_MODE_CABLE: - set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1); - set_reg_bits(state->tab_init_cable, 0x0a, 0xff, - 8 - if_diff_out_level); - set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17); - break; - default: - mxl_fail(-EINVAL); - } - return; -} - -static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, - enum mxl5007t_if_freq if_freq, - int invert_if) -{ - u8 val; - - switch (if_freq) { - case MxL_IF_4_MHZ: - val = 0x00; - break; - case MxL_IF_4_5_MHZ: - val = 0x02; - break; - case MxL_IF_4_57_MHZ: - val = 0x03; - break; - case MxL_IF_5_MHZ: - val = 0x04; - break; - case MxL_IF_5_38_MHZ: - val = 0x05; - break; - case MxL_IF_6_MHZ: - val = 0x06; - break; - case MxL_IF_6_28_MHZ: - val = 0x07; - break; - case MxL_IF_9_1915_MHZ: - val = 0x08; - break; - case MxL_IF_35_25_MHZ: - val = 0x09; - break; - case MxL_IF_36_15_MHZ: - val = 0x0a; - break; - case MxL_IF_44_MHZ: - val = 0x0b; - break; - default: - mxl_fail(-EINVAL); - return; - } - set_reg_bits(state->tab_init, 0x02, 0x0f, val); - - /* set inverted IF or normal IF */ - set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); - - return; -} - -static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, - enum mxl5007t_xtal_freq xtal_freq) -{ - switch (xtal_freq) { - case MxL_XTAL_16_MHZ: - /* select xtal freq & ref freq */ - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00); - break; - case MxL_XTAL_20_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01); - break; - case MxL_XTAL_20_25_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02); - break; - case MxL_XTAL_20_48_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03); - break; - case MxL_XTAL_24_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04); - break; - case MxL_XTAL_25_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05); - break; - case MxL_XTAL_25_14_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06); - break; - case MxL_XTAL_27_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07); - break; - case MxL_XTAL_28_8_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08); - break; - case MxL_XTAL_32_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09); - break; - case MxL_XTAL_40_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a); - break; - case MxL_XTAL_44_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b); - break; - case MxL_XTAL_48_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c); - break; - case MxL_XTAL_49_3811_MHZ: - set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0); - set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d); - break; - default: - mxl_fail(-EINVAL); - return; - } - - return; -} - -static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, - enum mxl5007t_mode mode) -{ - struct mxl5007t_config *cfg = state->config; - - memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); - memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); - - mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); - mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); - mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); - - set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable); - set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3); - set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp); - - if (mode >= MxL_MODE_CABLE) { - copy_reg_bits(state->tab_init, state->tab_init_cable); - return state->tab_init_cable; - } else - return state->tab_init; -} - -/* ------------------------------------------------------------------------- */ - -enum mxl5007t_bw_mhz { - MxL_BW_6MHz = 6, - MxL_BW_7MHz = 7, - MxL_BW_8MHz = 8, -}; - -static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, - enum mxl5007t_bw_mhz bw) -{ - u8 val; - - switch (bw) { - case MxL_BW_6MHz: - val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, - * and DIG_MODEINDEX_CSF */ - break; - case MxL_BW_7MHz: - val = 0x2a; - break; - case MxL_BW_8MHz: - val = 0x3f; - break; - default: - mxl_fail(-EINVAL); - return; - } - set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val); - - return; -} - -static struct -reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, - u32 rf_freq, enum mxl5007t_bw_mhz bw) -{ - u32 dig_rf_freq = 0; - u32 temp; - u32 frac_divider = 1000000; - unsigned int i; - - memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); - - mxl5007t_set_bw_bits(state, bw); - - /* Convert RF frequency into 16 bits => - * 10 bit integer (MHz) + 6 bit fraction */ - dig_rf_freq = rf_freq / MHz; - - temp = rf_freq % MHz; - - for (i = 0; i < 6; i++) { - dig_rf_freq <<= 1; - frac_divider /= 2; - if (temp > frac_divider) { - temp -= frac_divider; - dig_rf_freq++; - } - } - - /* add to have shift center point by 7.8124 kHz */ - if (temp > 7812) - dig_rf_freq++; - - set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq); - set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8)); - - if (rf_freq >= 333000000) - set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40); - - return state->tab_rftune; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) -{ - u8 buf[] = { reg, val }; - struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, - .buf = buf, .len = 2 }; - int ret; - - ret = i2c_transfer(state->i2c_props.adap, &msg, 1); - if (ret != 1) { - mxl_err("failed!"); - return -EREMOTEIO; - } - return 0; -} - -static int mxl5007t_write_regs(struct mxl5007t_state *state, - struct reg_pair_t *reg_pair) -{ - unsigned int i = 0; - int ret = 0; - - while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { - ret = mxl5007t_write_reg(state, - reg_pair[i].reg, reg_pair[i].val); - i++; - } - return ret; -} - -static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) -{ - struct i2c_msg msg[] = { - { .addr = state->i2c_props.addr, .flags = 0, - .buf = ®, .len = 1 }, - { .addr = state->i2c_props.addr, .flags = I2C_M_RD, - .buf = val, .len = 1 }, - }; - int ret; - - ret = i2c_transfer(state->i2c_props.adap, msg, 2); - if (ret != 2) { - mxl_err("failed!"); - return -EREMOTEIO; - } - return 0; -} - -static int mxl5007t_soft_reset(struct mxl5007t_state *state) -{ - u8 d = 0xff; - struct i2c_msg msg = { - .addr = state->i2c_props.addr, .flags = 0, - .buf = &d, .len = 1 - }; - int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); - - if (ret != 1) { - mxl_err("failed!"); - return -EREMOTEIO; - } - return 0; -} - -static int mxl5007t_tuner_init(struct mxl5007t_state *state, - enum mxl5007t_mode mode) -{ - struct reg_pair_t *init_regs; - int ret; - - ret = mxl5007t_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - - /* calculate initialization reg array */ - init_regs = mxl5007t_calc_init_regs(state, mode); - - ret = mxl5007t_write_regs(state, init_regs); - if (mxl_fail(ret)) - goto fail; - mdelay(1); -fail: - return ret; -} - -static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, - enum mxl5007t_bw_mhz bw) -{ - struct reg_pair_t *rf_tune_regs; - int ret; - - /* calculate channel change reg array */ - rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); - - ret = mxl5007t_write_regs(state, rf_tune_regs); - if (mxl_fail(ret)) - goto fail; - msleep(3); -fail: - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, - int *rf_locked, int *ref_locked) -{ - u8 d; - int ret; - - *rf_locked = 0; - *ref_locked = 0; - - ret = mxl5007t_read_reg(state, 0xd8, &d); - if (mxl_fail(ret)) - goto fail; - - if ((d & 0x0c) == 0x0c) - *rf_locked = 1; - - if ((d & 0x03) == 0x03) - *ref_locked = 1; -fail: - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct mxl5007t_state *state = fe->tuner_priv; - int rf_locked, ref_locked, ret; - - *status = 0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); - if (mxl_fail(ret)) - goto fail; - mxl_debug("%s%s", rf_locked ? "rf locked " : "", - ref_locked ? "ref locked" : ""); - - if ((rf_locked) || (ref_locked)) - *status |= TUNER_STATUS_LOCKED; -fail: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct mxl5007t_state *state = fe->tuner_priv; - enum mxl5007t_bw_mhz bw; - enum mxl5007t_mode mode; - int ret; - u32 freq = params->frequency; - - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - mode = MxL_MODE_ATSC; - break; - case QAM_64: - case QAM_256: - mode = MxL_MODE_CABLE; - break; - default: - mxl_err("modulation not set!"); - return -EINVAL; - } - bw = MxL_BW_6MHz; - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - bw = MxL_BW_6MHz; - break; - case BANDWIDTH_7_MHZ: - bw = MxL_BW_7MHz; - break; - case BANDWIDTH_8_MHZ: - bw = MxL_BW_8MHz; - break; - default: - mxl_err("bandwidth not set!"); - return -EINVAL; - } - mode = MxL_MODE_DVBT; - } else { - mxl_err("modulation type not supported!"); - return -EINVAL; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - mutex_lock(&state->lock); - - ret = mxl5007t_tuner_init(state, mode); - if (mxl_fail(ret)) - goto fail; - - ret = mxl5007t_tuner_rf_tune(state, freq, bw); - if (mxl_fail(ret)) - goto fail; - - state->frequency = freq; - state->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; -fail: - mutex_unlock(&state->lock); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_init(struct dvb_frontend *fe) -{ - struct mxl5007t_state *state = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* wake from standby */ - ret = mxl5007t_write_reg(state, 0x01, 0x01); - mxl_fail(ret); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -static int mxl5007t_sleep(struct dvb_frontend *fe) -{ - struct mxl5007t_state *state = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* enter standby mode */ - ret = mxl5007t_write_reg(state, 0x01, 0x00); - mxl_fail(ret); - ret = mxl5007t_write_reg(state, 0x0f, 0x00); - mxl_fail(ret); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return ret; -} - -/* ------------------------------------------------------------------------- */ - -static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct mxl5007t_state *state = fe->tuner_priv; - *frequency = state->frequency; - return 0; -} - -static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mxl5007t_state *state = fe->tuner_priv; - *bandwidth = state->bandwidth; - return 0; -} - -static int mxl5007t_release(struct dvb_frontend *fe) -{ - struct mxl5007t_state *state = fe->tuner_priv; - - mutex_lock(&mxl5007t_list_mutex); - - if (state) - hybrid_tuner_release_state(state); - - mutex_unlock(&mxl5007t_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -/* ------------------------------------------------------------------------- */ - -static struct dvb_tuner_ops mxl5007t_tuner_ops = { - .info = { - .name = "MaxLinear MxL5007T", - }, - .init = mxl5007t_init, - .sleep = mxl5007t_sleep, - .set_params = mxl5007t_set_params, - .get_status = mxl5007t_get_status, - .get_frequency = mxl5007t_get_frequency, - .get_bandwidth = mxl5007t_get_bandwidth, - .release = mxl5007t_release, -}; - -static int mxl5007t_get_chip_id(struct mxl5007t_state *state) -{ - char *name; - int ret; - u8 id; - - ret = mxl5007t_read_reg(state, 0xd9, &id); - if (mxl_fail(ret)) - goto fail; - - switch (id) { - case MxL_5007_V1_F1: - name = "MxL5007.v1.f1"; - break; - case MxL_5007_V1_F2: - name = "MxL5007.v1.f2"; - break; - case MxL_5007_V2_100_F1: - name = "MxL5007.v2.100.f1"; - break; - case MxL_5007_V2_100_F2: - name = "MxL5007.v2.100.f2"; - break; - case MxL_5007_V2_200_F1: - name = "MxL5007.v2.200.f1"; - break; - case MxL_5007_V2_200_F2: - name = "MxL5007.v2.200.f2"; - break; - case MxL_5007_V4: - name = "MxL5007T.v4"; - break; - default: - name = "MxL5007T"; - printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id); - id = MxL_UNKNOWN_ID; - } - state->chip_id = id; - mxl_info("%s detected @ %d-%04x", name, - i2c_adapter_id(state->i2c_props.adap), - state->i2c_props.addr); - return 0; -fail: - mxl_warn("unable to identify device @ %d-%04x", - i2c_adapter_id(state->i2c_props.adap), - state->i2c_props.addr); - - state->chip_id = MxL_UNKNOWN_ID; - return ret; -} - -struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 addr, - struct mxl5007t_config *cfg) -{ - struct mxl5007t_state *state = NULL; - int instance, ret; - - mutex_lock(&mxl5007t_list_mutex); - instance = hybrid_tuner_request_state(struct mxl5007t_state, state, - hybrid_tuner_instance_list, - i2c, addr, "mxl5007t"); - switch (instance) { - case 0: - goto fail; - case 1: - /* new tuner instance */ - state->config = cfg; - - mutex_init(&state->lock); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = mxl5007t_get_chip_id(state); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - /* check return value of mxl5007t_get_chip_id */ - if (mxl_fail(ret)) - goto fail; - break; - default: - /* existing tuner instance */ - break; - } - fe->tuner_priv = state; - mutex_unlock(&mxl5007t_list_mutex); - - memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - return fe; -fail: - mutex_unlock(&mxl5007t_list_mutex); - - mxl5007t_release(fe); - return NULL; -} -EXPORT_SYMBOL_GPL(mxl5007t_attach); -MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5007t.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5007t.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5007t.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/mxl5007t.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -/* - * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner - * - * Copyright (C) 2008 Michael Krufky - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __MXL5007T_H__ -#define __MXL5007T_H__ - -#include "dvb_frontend.h" - -/* ------------------------------------------------------------------------- */ - -enum mxl5007t_if_freq { - MxL_IF_4_MHZ, /* 4000000 */ - MxL_IF_4_5_MHZ, /* 4500000 */ - MxL_IF_4_57_MHZ, /* 4570000 */ - MxL_IF_5_MHZ, /* 5000000 */ - MxL_IF_5_38_MHZ, /* 5380000 */ - MxL_IF_6_MHZ, /* 6000000 */ - MxL_IF_6_28_MHZ, /* 6280000 */ - MxL_IF_9_1915_MHZ, /* 9191500 */ - MxL_IF_35_25_MHZ, /* 35250000 */ - MxL_IF_36_15_MHZ, /* 36150000 */ - MxL_IF_44_MHZ, /* 44000000 */ -}; - -enum mxl5007t_xtal_freq { - MxL_XTAL_16_MHZ, /* 16000000 */ - MxL_XTAL_20_MHZ, /* 20000000 */ - MxL_XTAL_20_25_MHZ, /* 20250000 */ - MxL_XTAL_20_48_MHZ, /* 20480000 */ - MxL_XTAL_24_MHZ, /* 24000000 */ - MxL_XTAL_25_MHZ, /* 25000000 */ - MxL_XTAL_25_14_MHZ, /* 25140000 */ - MxL_XTAL_27_MHZ, /* 27000000 */ - MxL_XTAL_28_8_MHZ, /* 28800000 */ - MxL_XTAL_32_MHZ, /* 32000000 */ - MxL_XTAL_40_MHZ, /* 40000000 */ - MxL_XTAL_44_MHZ, /* 44000000 */ - MxL_XTAL_48_MHZ, /* 48000000 */ - MxL_XTAL_49_3811_MHZ, /* 49381100 */ -}; - -enum mxl5007t_clkout_amp { - MxL_CLKOUT_AMP_0_94V = 0, - MxL_CLKOUT_AMP_0_53V = 1, - MxL_CLKOUT_AMP_0_37V = 2, - MxL_CLKOUT_AMP_0_28V = 3, - MxL_CLKOUT_AMP_0_23V = 4, - MxL_CLKOUT_AMP_0_20V = 5, - MxL_CLKOUT_AMP_0_17V = 6, - MxL_CLKOUT_AMP_0_15V = 7, -}; - -struct mxl5007t_config { - s32 if_diff_out_level; - enum mxl5007t_clkout_amp clk_out_amp; - enum mxl5007t_xtal_freq xtal_freq_hz; - enum mxl5007t_if_freq if_freq_hz; - unsigned int invert_if:1; - unsigned int loop_thru_enable:1; - unsigned int clk_out_enable:1; -}; - -#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE)) -extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 addr, - struct mxl5007t_config *cfg); -#else -static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - u8 addr, - struct mxl5007t_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __MXL5007T_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,482 +0,0 @@ -/* - * Driver for Quantek QT1010 silicon tuner - * - * Copyright (C) 2006 Antti Palosaari - * Aapo Tahkola - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include "qt1010.h" -#include "qt1010_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "QT1010: " args); \ - } while (0) - -/* read single register */ -static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, - .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, - .flags = I2C_M_RD, .buf = val, .len = 1 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "qt1010 I2C read failed\n"); - return -EREMOTEIO; - } - return 0; -} - -/* write single register */ -static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val) -{ - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, - .flags = 0, .buf = buf, .len = 2 }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "qt1010 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -/* dump all registers */ -static void qt1010_dump_regs(struct qt1010_priv *priv) -{ - u8 reg, val; - - for (reg = 0; ; reg++) { - if (reg % 16 == 0) { - if (reg) - printk(KERN_CONT "\n"); - printk(KERN_DEBUG "%02x:", reg); - } - if (qt1010_readreg(priv, reg, &val) == 0) - printk(KERN_CONT " %02x", val); - else - printk(KERN_CONT " --"); - if (reg == 0x2f) - break; - } - printk(KERN_CONT "\n"); -} - -static int qt1010_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct qt1010_priv *priv; - int err; - u32 freq, div, mod1, mod2; - u8 i, tmpval, reg05; - qt1010_i2c_oper_t rd[48] = { - { QT1010_WR, 0x01, 0x80 }, - { QT1010_WR, 0x02, 0x3f }, - { QT1010_WR, 0x05, 0xff }, /* 02 c write */ - { QT1010_WR, 0x06, 0x44 }, - { QT1010_WR, 0x07, 0xff }, /* 04 c write */ - { QT1010_WR, 0x08, 0x08 }, - { QT1010_WR, 0x09, 0xff }, /* 06 c write */ - { QT1010_WR, 0x0a, 0xff }, /* 07 c write */ - { QT1010_WR, 0x0b, 0xff }, /* 08 c write */ - { QT1010_WR, 0x0c, 0xe1 }, - { QT1010_WR, 0x1a, 0xff }, /* 10 c write */ - { QT1010_WR, 0x1b, 0x00 }, - { QT1010_WR, 0x1c, 0x89 }, - { QT1010_WR, 0x11, 0xff }, /* 13 c write */ - { QT1010_WR, 0x12, 0xff }, /* 14 c write */ - { QT1010_WR, 0x22, 0xff }, /* 15 c write */ - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, 0xd0 }, - { QT1010_RD, 0x22, 0xff }, /* 16 c read */ - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_RD, 0x05, 0xff }, /* 20 c read */ - { QT1010_RD, 0x22, 0xff }, /* 21 c read */ - { QT1010_WR, 0x23, 0xd0 }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, 0xe0 }, - { QT1010_RD, 0x23, 0xff }, /* 25 c read */ - { QT1010_RD, 0x23, 0xff }, /* 26 c read */ - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x24, 0xd0 }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, 0xf0 }, - { QT1010_RD, 0x24, 0xff }, /* 31 c read */ - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x14, 0x7f }, - { QT1010_WR, 0x15, 0x7f }, - { QT1010_WR, 0x05, 0xff }, /* 35 c write */ - { QT1010_WR, 0x06, 0x00 }, - { QT1010_WR, 0x15, 0x1f }, - { QT1010_WR, 0x16, 0xff }, - { QT1010_WR, 0x18, 0xff }, - { QT1010_WR, 0x1f, 0xff }, /* 40 c write */ - { QT1010_WR, 0x20, 0xff }, /* 41 c write */ - { QT1010_WR, 0x21, 0x53 }, - { QT1010_WR, 0x25, 0xff }, /* 43 c write */ - { QT1010_WR, 0x26, 0x15 }, - { QT1010_WR, 0x00, 0xff }, /* 45 c write */ - { QT1010_WR, 0x02, 0x00 }, - { QT1010_WR, 0x01, 0x00 } - }; - -#define FREQ1 32000000 /* 32 MHz */ -#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */ - - priv = fe->tuner_priv; - freq = params->frequency; - div = (freq + QT1010_OFFSET) / QT1010_STEP; - freq = (div * QT1010_STEP) - QT1010_OFFSET; - mod1 = (freq + QT1010_OFFSET) % FREQ1; - mod2 = (freq + QT1010_OFFSET) % FREQ2; - priv->bandwidth = - (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - priv->frequency = freq; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - /* reg 05 base value */ - if (freq < 290000000) reg05 = 0x14; /* 290 MHz */ - else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */ - else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */ - else reg05 = 0x74; - - /* 0x5 */ - rd[2].val = reg05; - - /* 07 - set frequency: 32 MHz scale */ - rd[4].val = (freq + QT1010_OFFSET) / FREQ1; - - /* 09 - changes every 8/24 MHz */ - if (mod1 < 8000000) rd[6].val = 0x1d; - else rd[6].val = 0x1c; - - /* 0a - set frequency: 4 MHz scale (max 28 MHz) */ - if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */ - else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */ - else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */ - else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */ - else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */ - else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */ - else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */ - else rd[7].val = 0x0a; /* +28 MHz */ - - /* 0b - changes every 2/2 MHz */ - if (mod2 < 2000000) rd[8].val = 0x45; - else rd[8].val = 0x44; - - /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/ - tmpval = 0x78; /* byte, overflows intentionally */ - rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08); - - /* 11 */ - rd[13].val = 0xfd; /* TODO: correct value calculation */ - - /* 12 */ - rd[14].val = 0x91; /* TODO: correct value calculation */ - - /* 22 */ - if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */ - else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */ - else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */ - else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */ - else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */ - else rd[15].val = 0xd0; - - /* 05 */ - rd[35].val = (reg05 & 0xf0); - - /* 1f */ - if (mod1 < 8000000) tmpval = 0x00; - else if (mod1 < 12000000) tmpval = 0x01; - else if (mod1 < 16000000) tmpval = 0x02; - else if (mod1 < 24000000) tmpval = 0x03; - else if (mod1 < 28000000) tmpval = 0x04; - else tmpval = 0x05; - rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval); - - /* 20 */ - if (mod1 < 8000000) tmpval = 0x00; - else if (mod1 < 12000000) tmpval = 0x01; - else if (mod1 < 20000000) tmpval = 0x02; - else if (mod1 < 24000000) tmpval = 0x03; - else if (mod1 < 28000000) tmpval = 0x04; - else tmpval = 0x05; - rd[41].val = (priv->reg20_init_val + 0x0d + tmpval); - - /* 25 */ - rd[43].val = priv->reg25_init_val; - - /* 00 */ - rd[45].val = 0x92; /* TODO: correct value calculation */ - - dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \ - "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \ - "20:%02x 25:%02x 00:%02x", \ - freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \ - rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \ - rd[40].val, rd[41].val, rd[43].val, rd[45].val); - - for (i = 0; i < ARRAY_SIZE(rd); i++) { - if (rd[i].oper == QT1010_WR) { - err = qt1010_writereg(priv, rd[i].reg, rd[i].val); - } else { /* read is required to proper locking */ - err = qt1010_readreg(priv, rd[i].reg, &tmpval); - } - if (err) return err; - } - - if (debug) - qt1010_dump_regs(priv); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return 0; -} - -static int qt1010_init_meas1(struct qt1010_priv *priv, - u8 oper, u8 reg, u8 reg_init_val, u8 *retval) -{ - u8 i, val1, val2; - int err; - - qt1010_i2c_oper_t i2c_data[] = { - { QT1010_WR, reg, reg_init_val }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, oper }, - { QT1010_RD, reg, 0xff } - }; - - for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { - if (i2c_data[i].oper == QT1010_WR) { - err = qt1010_writereg(priv, i2c_data[i].reg, - i2c_data[i].val); - } else { - err = qt1010_readreg(priv, i2c_data[i].reg, &val2); - } - if (err) return err; - } - - do { - val1 = val2; - err = qt1010_readreg(priv, reg, &val2); - if (err) return err; - dprintk("compare reg:%02x %02x %02x", reg, val1, val2); - } while (val1 != val2); - *retval = val1; - - return qt1010_writereg(priv, 0x1e, 0x00); -} - -static u8 qt1010_init_meas2(struct qt1010_priv *priv, - u8 reg_init_val, u8 *retval) -{ - u8 i, val; - int err; - qt1010_i2c_oper_t i2c_data[] = { - { QT1010_WR, 0x07, reg_init_val }, - { QT1010_WR, 0x22, 0xd0 }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x1e, 0xd0 }, - { QT1010_RD, 0x22, 0xff }, - { QT1010_WR, 0x1e, 0x00 }, - { QT1010_WR, 0x22, 0xff } - }; - for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { - if (i2c_data[i].oper == QT1010_WR) { - err = qt1010_writereg(priv, i2c_data[i].reg, - i2c_data[i].val); - } else { - err = qt1010_readreg(priv, i2c_data[i].reg, &val); - } - if (err) return err; - } - *retval = val; - return 0; -} - -static int qt1010_init(struct dvb_frontend *fe) -{ - struct qt1010_priv *priv = fe->tuner_priv; - struct dvb_frontend_parameters params; - int err = 0; - u8 i, tmpval, *valptr = NULL; - - qt1010_i2c_oper_t i2c_data[] = { - { QT1010_WR, 0x01, 0x80 }, - { QT1010_WR, 0x0d, 0x84 }, - { QT1010_WR, 0x0e, 0xb7 }, - { QT1010_WR, 0x2a, 0x23 }, - { QT1010_WR, 0x2c, 0xdc }, - { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */ - { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */ - { QT1010_WR, 0x2b, 0x70 }, - { QT1010_WR, 0x2a, 0x23 }, - { QT1010_M1, 0x26, 0x08 }, - { QT1010_M1, 0x82, 0xff }, - { QT1010_WR, 0x05, 0x14 }, - { QT1010_WR, 0x06, 0x44 }, - { QT1010_WR, 0x07, 0x28 }, - { QT1010_WR, 0x08, 0x0b }, - { QT1010_WR, 0x11, 0xfd }, - { QT1010_M1, 0x22, 0x0d }, - { QT1010_M1, 0xd0, 0xff }, - { QT1010_WR, 0x06, 0x40 }, - { QT1010_WR, 0x16, 0xf0 }, - { QT1010_WR, 0x02, 0x38 }, - { QT1010_WR, 0x03, 0x18 }, - { QT1010_WR, 0x20, 0xe0 }, - { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */ - { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */ - { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */ - { QT1010_WR, 0x03, 0x19 }, - { QT1010_WR, 0x02, 0x3f }, - { QT1010_WR, 0x21, 0x53 }, - { QT1010_RD, 0x21, 0xff }, - { QT1010_WR, 0x11, 0xfd }, - { QT1010_WR, 0x05, 0x34 }, - { QT1010_WR, 0x06, 0x44 }, - { QT1010_WR, 0x08, 0x08 } - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { - switch (i2c_data[i].oper) { - case QT1010_WR: - err = qt1010_writereg(priv, i2c_data[i].reg, - i2c_data[i].val); - break; - case QT1010_RD: - if (i2c_data[i].val == 0x20) - valptr = &priv->reg20_init_val; - else - valptr = &tmpval; - err = qt1010_readreg(priv, i2c_data[i].reg, valptr); - break; - case QT1010_M1: - if (i2c_data[i].val == 0x25) - valptr = &priv->reg25_init_val; - else if (i2c_data[i].val == 0x1f) - valptr = &priv->reg1f_init_val; - else - valptr = &tmpval; - err = qt1010_init_meas1(priv, i2c_data[i+1].reg, - i2c_data[i].reg, - i2c_data[i].val, valptr); - i++; - break; - } - if (err) return err; - } - - for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */ - if ((err = qt1010_init_meas2(priv, i, &tmpval))) - return err; - - params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */ - /* MSI Megasky 580 GL861 533000000 */ - return qt1010_set_params(fe, ¶ms); -} - -static int qt1010_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct qt1010_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct qt1010_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static const struct dvb_tuner_ops qt1010_tuner_ops = { - .info = { - .name = "Quantek QT1010", - .frequency_min = QT1010_MIN_FREQ, - .frequency_max = QT1010_MAX_FREQ, - .frequency_step = QT1010_STEP, - }, - - .release = qt1010_release, - .init = qt1010_init, - /* TODO: implement sleep */ - - .set_params = qt1010_set_params, - .get_frequency = qt1010_get_frequency, - .get_bandwidth = qt1010_get_bandwidth -}; - -struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct qt1010_config *cfg) -{ - struct qt1010_priv *priv = NULL; - u8 id; - - priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - - /* Try to detect tuner chip. Probably this is not correct register. */ - if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) { - kfree(priv); - return NULL; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - printk(KERN_INFO "Quantek QT1010 successfully identified.\n"); - memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - return fe; -} -EXPORT_SYMBOL(qt1010_attach); - -MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver"); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_AUTHOR("Aapo Tahkola "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/* - * Driver for Quantek QT1010 silicon tuner - * - * Copyright (C) 2006 Antti Palosaari - * Aapo Tahkola - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef QT1010_H -#define QT1010_H - -#include "dvb_frontend.h" - -struct qt1010_config { - u8 i2c_address; -}; - -/** - * Attach a qt1010 tuner to the supplied frontend structure. - * - * @param fe frontend to attach to - * @param i2c i2c adapter to use - * @param cfg tuner hw based configuration - * @return fe pointer on success, NULL on failure - */ -#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE)) -extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct qt1010_config *cfg); -#else -static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct qt1010_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_MEDIA_TUNER_QT1010 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/qt1010_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/* - * Driver for Quantek QT1010 silicon tuner - * - * Copyright (C) 2006 Antti Palosaari - * Aapo Tahkola - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef QT1010_PRIV_H -#define QT1010_PRIV_H - -/* -reg def meaning -=== === ======= -00 00 ? -01 a0 ? operation start/stop; start=80, stop=00 -02 00 ? -03 19 ? -04 00 ? -05 00 ? maybe band selection -06 00 ? -07 2b set frequency: 32 MHz scale, n*32 MHz -08 0b ? -09 10 ? changes every 8/24 MHz; values 1d/1c -0a 08 set frequency: 4 MHz scale, n*4 MHz -0b 41 ? changes every 2/2 MHz; values 45/45 -0c e1 ? -0d 94 ? -0e b6 ? -0f 2c ? -10 10 ? -11 f1 ? maybe device specified adjustment -12 11 ? maybe device specified adjustment -13 3f ? -14 1f ? -15 3f ? -16 ff ? -17 ff ? -18 f7 ? -19 80 ? -1a d0 set frequency: 125 kHz scale, n*125 kHz -1b 00 ? -1c 89 ? -1d 00 ? -1e 00 ? looks like operation register; write cmd here, read result from 1f-26 -1f 20 ? chip initialization -20 e0 ? chip initialization -21 20 ? -22 d0 ? -23 d0 ? -24 d0 ? -25 40 ? chip initialization -26 08 ? -27 29 ? -28 55 ? -29 39 ? -2a 13 ? -2b 01 ? -2c ea ? -2d 00 ? -2e 00 ? not used? -2f 00 ? not used? -*/ - -#define QT1010_STEP 125000 /* 125 kHz used by Windows drivers, - hw could be more precise but we don't - know how to use */ -#define QT1010_MIN_FREQ 48000000 /* 48 MHz */ -#define QT1010_MAX_FREQ 860000000 /* 860 MHz */ -#define QT1010_OFFSET 1246000000 /* 1246 MHz */ - -#define QT1010_WR 0 -#define QT1010_RD 1 -#define QT1010_M1 3 - -typedef struct { - u8 oper, reg, val; -} qt1010_i2c_oper_t; - -struct qt1010_priv { - struct qt1010_config *cfg; - struct i2c_adapter *i2c; - - u8 reg1f_init_val; - u8 reg20_init_val; - u8 reg25_init_val; - - u32 frequency; - u32 bandwidth; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,334 +0,0 @@ -/* - * NXP TDA18218HN silicon tuner driver - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "tda18218.h" -#include "tda18218_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -/* write multiple registers */ -static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) -{ - int ret = 0; - u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg->i2c_address, - .flags = 0, - .buf = buf, - } - }; - - msg_len_max = priv->cfg->i2c_wr_max - 1; - quotient = len / msg_len_max; - remainder = len % msg_len_max; - msg_len = msg_len_max; - for (i = 0; (i <= quotient && remainder); i++) { - if (i == quotient) /* set len of the last msg */ - msg_len = remainder; - - msg[0].len = msg_len + 1; - buf[0] = reg + i * msg_len_max; - memcpy(&buf[1], &val[i * msg_len_max], msg_len); - - ret = i2c_transfer(priv->i2c, msg, 1); - if (ret != 1) - break; - } - - if (ret == 1) { - ret = 0; - } else { - warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* read multiple registers */ -static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) -{ - int ret; - u8 buf[reg+len]; /* we must start read always from reg 0x00 */ - struct i2c_msg msg[2] = { - { - .addr = priv->cfg->i2c_address, - .flags = 0, - .len = 1, - .buf = "\x00", - }, { - .addr = priv->cfg->i2c_address, - .flags = I2C_M_RD, - .len = sizeof(buf), - .buf = buf, - } - }; - - ret = i2c_transfer(priv->i2c, msg, 2); - if (ret == 2) { - memcpy(val, &buf[reg], len); - ret = 0; - } else { - warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val) -{ - return tda18218_wr_regs(priv, reg, &val, 1); -} - -/* read single register */ - -static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val) -{ - return tda18218_rd_regs(priv, reg, val, 1); -} - -static int tda18218_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tda18218_priv *priv = fe->tuner_priv; - int ret; - u8 buf[3], i, BP_Filter, LP_Fc; - u32 LO_Frac; - /* TODO: find out correct AGC algorithm */ - u8 agc[][2] = { - { R20_AGC11, 0x60 }, - { R23_AGC21, 0x02 }, - { R20_AGC11, 0xa0 }, - { R23_AGC21, 0x09 }, - { R20_AGC11, 0xe0 }, - { R23_AGC21, 0x0c }, - { R20_AGC11, 0x40 }, - { R23_AGC21, 0x01 }, - { R20_AGC11, 0x80 }, - { R23_AGC21, 0x08 }, - { R20_AGC11, 0xc0 }, - { R23_AGC21, 0x0b }, - { R24_AGC22, 0x1c }, - { R24_AGC22, 0x0c }, - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - /* low-pass filter cut-off frequency */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - LP_Fc = 0; - LO_Frac = params->frequency + 4000000; - break; - case BANDWIDTH_7_MHZ: - LP_Fc = 1; - LO_Frac = params->frequency + 3500000; - break; - case BANDWIDTH_8_MHZ: - default: - LP_Fc = 2; - LO_Frac = params->frequency + 4000000; - break; - } - - /* band-pass filter */ - if (LO_Frac < 188000000) - BP_Filter = 3; - else if (LO_Frac < 253000000) - BP_Filter = 4; - else if (LO_Frac < 343000000) - BP_Filter = 5; - else - BP_Filter = 6; - - buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */ - buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */ - buf[2] = priv->regs[R1C_AGC2B]; - ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3); - if (ret) - goto error; - - buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */ - buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */ - buf[2] = (LO_Frac / 1000) << 4 | - (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */ - ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3); - if (ret) - goto error; - - buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */ - ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); - if (ret) - goto error; - - buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */ - ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); - if (ret) - goto error; - - /* trigger AGC */ - for (i = 0; i < ARRAY_SIZE(agc); i++) { - ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]); - if (ret) - goto error; - } - -error: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (ret) - dbg("%s: failed ret:%d", __func__, ret); - - return ret; -} - -static int tda18218_sleep(struct dvb_frontend *fe) -{ - struct tda18218_priv *priv = fe->tuner_priv; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - /* standby */ - ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (ret) - dbg("%s: failed ret:%d", __func__, ret); - - return ret; -} - -static int tda18218_init(struct dvb_frontend *fe) -{ - struct tda18218_priv *priv = fe->tuner_priv; - int ret; - - /* TODO: calibrations */ - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - if (ret) - dbg("%s: failed ret:%d", __func__, ret); - - return ret; -} - -static int tda18218_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops tda18218_tuner_ops = { - .info = { - .name = "NXP TDA18218", - - .frequency_min = 174000000, - .frequency_max = 864000000, - .frequency_step = 1000, - }, - - .release = tda18218_release, - .init = tda18218_init, - .sleep = tda18218_sleep, - - .set_params = tda18218_set_params, -}; - -struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18218_config *cfg) -{ - struct tda18218_priv *priv = NULL; - u8 val; - int ret; - /* chip default registers values */ - static u8 def_regs[] = { - 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40, - 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00, - 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01, - 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9, - 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00, - 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6 - }; - - priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->i2c = i2c; - fe->tuner_priv = priv; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - - /* check if the tuner is there */ - ret = tda18218_rd_reg(priv, R00_ID, &val); - dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); - if (ret || val != def_regs[R00_ID]) { - kfree(priv); - return NULL; - } - - info("NXP TDA18218HN successfully identified."); - - memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops, - sizeof(struct dvb_tuner_ops)); - memcpy(priv->regs, def_regs, sizeof(def_regs)); - - /* loop-through enabled chip default register values */ - if (priv->cfg->loop_through) { - priv->regs[R17_PD1] = 0xb0; - priv->regs[R18_PD2] = 0x59; - } - - /* standby */ - ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); - if (ret) - dbg("%s: failed ret:%d", __func__, ret); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - - return fe; -} -EXPORT_SYMBOL(tda18218_attach); - -MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver"); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/* - * NXP TDA18218HN silicon tuner driver - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef TDA18218_H -#define TDA18218_H - -#include "dvb_frontend.h" - -struct tda18218_config { - u8 i2c_address; - u8 i2c_wr_max; - u8 loop_through:1; -}; - -#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \ - (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18218_config *cfg); -#else -static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18218_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18218_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -/* - * NXP TDA18218HN silicon tuner driver - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef TDA18218_PRIV_H -#define TDA18218_PRIV_H - -#define LOG_PREFIX "tda18218" - -#undef dbg -#define dbg(f, arg...) \ - if (debug) \ - printk(KERN_DEBUG LOG_PREFIX": " f "\n" , ## arg) -#undef err -#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -#undef info -#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef warn -#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) - -#define R00_ID 0x00 /* ID byte */ -#define R01_R1 0x01 /* Read byte 1 */ -#define R02_R2 0x02 /* Read byte 2 */ -#define R03_R3 0x03 /* Read byte 3 */ -#define R04_R4 0x04 /* Read byte 4 */ -#define R05_R5 0x05 /* Read byte 5 */ -#define R06_R6 0x06 /* Read byte 6 */ -#define R07_MD1 0x07 /* Main divider byte 1 */ -#define R08_PSM1 0x08 /* PSM byte 1 */ -#define R09_MD2 0x09 /* Main divider byte 2 */ -#define R0A_MD3 0x0a /* Main divider byte 1 */ -#define R0B_MD4 0x0b /* Main divider byte 4 */ -#define R0C_MD5 0x0c /* Main divider byte 5 */ -#define R0D_MD6 0x0d /* Main divider byte 6 */ -#define R0E_MD7 0x0e /* Main divider byte 7 */ -#define R0F_MD8 0x0f /* Main divider byte 8 */ -#define R10_CD1 0x10 /* Call divider byte 1 */ -#define R11_CD2 0x11 /* Call divider byte 2 */ -#define R12_CD3 0x12 /* Call divider byte 3 */ -#define R13_CD4 0x13 /* Call divider byte 4 */ -#define R14_CD5 0x14 /* Call divider byte 5 */ -#define R15_CD6 0x15 /* Call divider byte 6 */ -#define R16_CD7 0x16 /* Call divider byte 7 */ -#define R17_PD1 0x17 /* Power-down byte 1 */ -#define R18_PD2 0x18 /* Power-down byte 2 */ -#define R19_XTOUT 0x19 /* XTOUT byte */ -#define R1A_IF1 0x1a /* IF byte 1 */ -#define R1B_IF2 0x1b /* IF byte 2 */ -#define R1C_AGC2B 0x1c /* AGC2b byte */ -#define R1D_PSM2 0x1d /* PSM byte 2 */ -#define R1E_PSM3 0x1e /* PSM byte 3 */ -#define R1F_PSM4 0x1f /* PSM byte 4 */ -#define R20_AGC11 0x20 /* AGC1 byte 1 */ -#define R21_AGC12 0x21 /* AGC1 byte 2 */ -#define R22_AGC13 0x22 /* AGC1 byte 3 */ -#define R23_AGC21 0x23 /* AGC2 byte 1 */ -#define R24_AGC22 0x24 /* AGC2 byte 2 */ -#define R25_AAGC 0x25 /* Analog AGC byte */ -#define R26_RC 0x26 /* RC byte */ -#define R27_RSSI 0x27 /* RSSI byte */ -#define R28_IRCAL1 0x28 /* IR CAL byte 1 */ -#define R29_IRCAL2 0x29 /* IR CAL byte 2 */ -#define R2A_IRCAL3 0x2a /* IR CAL byte 3 */ -#define R2B_IRCAL4 0x2b /* IR CAL byte 4 */ -#define R2C_RFCAL1 0x2c /* RF CAL byte 1 */ -#define R2D_RFCAL2 0x2d /* RF CAL byte 2 */ -#define R2E_RFCAL3 0x2e /* RF CAL byte 3 */ -#define R2F_RFCAL4 0x2f /* RF CAL byte 4 */ -#define R30_RFCAL5 0x30 /* RF CAL byte 5 */ -#define R31_RFCAL6 0x31 /* RF CAL byte 6 */ -#define R32_RFCAL7 0x32 /* RF CAL byte 7 */ -#define R33_RFCAL8 0x33 /* RF CAL byte 8 */ -#define R34_RFCAL9 0x34 /* RF CAL byte 9 */ -#define R35_RFCAL10 0x35 /* RF CAL byte 10 */ -#define R36_RFCALRAM1 0x36 /* RF CAL RAM byte 1 */ -#define R37_RFCALRAM2 0x37 /* RF CAL RAM byte 2 */ -#define R38_MARGIN 0x38 /* Margin byte */ -#define R39_FMAX1 0x39 /* Fmax byte 1 */ -#define R3A_FMAX2 0x3a /* Fmax byte 2 */ - -#define TDA18218_NUM_REGS 59 - -struct tda18218_priv { - struct tda18218_config *cfg; - struct i2c_adapter *i2c; - - u8 regs[TDA18218_NUM_REGS]; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-common.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,694 +0,0 @@ -/* - tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "tda18271-priv.h" - -static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct tda18271_priv *priv = fe->tuner_priv; - enum tda18271_i2c_gate gate; - int ret = 0; - - switch (priv->gate) { - case TDA18271_GATE_DIGITAL: - case TDA18271_GATE_ANALOG: - gate = priv->gate; - break; - case TDA18271_GATE_AUTO: - default: - switch (priv->mode) { - case TDA18271_DIGITAL: - gate = TDA18271_GATE_DIGITAL; - break; - case TDA18271_ANALOG: - default: - gate = TDA18271_GATE_ANALOG; - break; - } - } - - switch (gate) { - case TDA18271_GATE_ANALOG: - if (fe->ops.analog_ops.i2c_gate_ctrl) - ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); - break; - case TDA18271_GATE_DIGITAL: - if (fe->ops.i2c_gate_ctrl) - ret = fe->ops.i2c_gate_ctrl(fe, enable); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -}; - -/*---------------------------------------------------------------------*/ - -static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda_reg("=== TDA18271 REG DUMP ===\n"); - tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); - tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); - tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); - tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); - tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); - tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); - tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); - tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); - tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); - tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); - tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); - tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); - tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); - tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); - tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); - tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); - - /* only dump extended regs if DBG_ADV is set */ - if (!(tda18271_debug & DBG_ADV)) - return; - - /* W indicates write-only registers. - * Register dump for write-only registers shows last value written. */ - - tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); - tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); - tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); - tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); - tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); - tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); - tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); - tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); - tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); - tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); - tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); - tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); - tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); - tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); - tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); - tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); - tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); - tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); - tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); - tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); - tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); - tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); - tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); -} - -int tda18271_read_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf = 0x00; - int ret; - struct i2c_msg msg[] = { - { .addr = priv->i2c_props.addr, .flags = 0, - .buf = &buf, .len = 1 }, - { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, - .buf = regs, .len = 16 } - }; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* read all registers */ - ret = i2c_transfer(priv->i2c_props.adap, msg, 2); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 2) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); - - if (tda18271_debug & DBG_REG) - tda18271_dump_regs(fe, 0); - - return (ret == 2 ? 0 : ret); -} - -int tda18271_read_extended(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char regdump[TDA18271_NUM_REGS]; - unsigned char buf = 0x00; - int ret, i; - struct i2c_msg msg[] = { - { .addr = priv->i2c_props.addr, .flags = 0, - .buf = &buf, .len = 1 }, - { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, - .buf = regdump, .len = TDA18271_NUM_REGS } - }; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* read all registers */ - ret = i2c_transfer(priv->i2c_props.adap, msg, 2); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 2) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); - - for (i = 0; i < TDA18271_NUM_REGS; i++) { - /* don't update write-only registers */ - if ((i != R_EB9) && - (i != R_EB16) && - (i != R_EB17) && - (i != R_EB19) && - (i != R_EB20)) - regs[i] = regdump[i]; - } - - if (tda18271_debug & DBG_REG) - tda18271_dump_regs(fe, 1); - - return (ret == 2 ? 0 : ret); -} - -int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf[TDA18271_NUM_REGS + 1]; - struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0, - .buf = buf }; - int i, ret = 1, max; - - BUG_ON((len == 0) || (idx + len > sizeof(buf))); - - - switch (priv->small_i2c) { - case TDA18271_03_BYTE_CHUNK_INIT: - max = 3; - break; - case TDA18271_08_BYTE_CHUNK_INIT: - max = 8; - break; - case TDA18271_16_BYTE_CHUNK_INIT: - max = 16; - break; - case TDA18271_39_BYTE_CHUNK_INIT: - default: - max = 39; - } - - tda18271_i2c_gate_ctrl(fe, 1); - while (len) { - if (max > len) - max = len; - - buf[0] = idx; - for (i = 1; i <= max; i++) - buf[i] = regs[idx - 1 + i]; - - msg.len = max + 1; - - /* write registers */ - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if (ret != 1) - break; - - idx += max; - len -= max; - } - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 1) - tda_err("ERROR: idx = 0x%x, len = %d, " - "i2c_transfer returned: %d\n", idx, max, ret); - - return (ret == 1 ? 0 : ret); -} - -/*---------------------------------------------------------------------*/ - -int tda18271_charge_pump_source(struct dvb_frontend *fe, - enum tda18271_pll pll, int force) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4; - - regs[r_cp] &= ~0x20; - regs[r_cp] |= ((force & 1) << 5); - - return tda18271_write_regs(fe, r_cp, 1); -} - -int tda18271_init_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda_dbg("initializing registers for device @ %d-%04x\n", - i2c_adapter_id(priv->i2c_props.adap), - priv->i2c_props.addr); - - /* initialize registers */ - switch (priv->id) { - case TDA18271HDC1: - regs[R_ID] = 0x83; - break; - case TDA18271HDC2: - regs[R_ID] = 0x84; - break; - }; - - regs[R_TM] = 0x08; - regs[R_PL] = 0x80; - regs[R_EP1] = 0xc6; - regs[R_EP2] = 0xdf; - regs[R_EP3] = 0x16; - regs[R_EP4] = 0x60; - regs[R_EP5] = 0x80; - regs[R_CPD] = 0x80; - regs[R_CD1] = 0x00; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0x00; - regs[R_MD1] = 0x00; - regs[R_MD2] = 0x00; - regs[R_MD3] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB1] = 0xff; - break; - case TDA18271HDC2: - regs[R_EB1] = 0xfc; - break; - }; - - regs[R_EB2] = 0x01; - regs[R_EB3] = 0x84; - regs[R_EB4] = 0x41; - regs[R_EB5] = 0x01; - regs[R_EB6] = 0x84; - regs[R_EB7] = 0x40; - regs[R_EB8] = 0x07; - regs[R_EB9] = 0x00; - regs[R_EB10] = 0x00; - regs[R_EB11] = 0x96; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB12] = 0x0f; - break; - case TDA18271HDC2: - regs[R_EB12] = 0x33; - break; - }; - - regs[R_EB13] = 0xc1; - regs[R_EB14] = 0x00; - regs[R_EB15] = 0x8f; - regs[R_EB16] = 0x00; - regs[R_EB17] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB18] = 0x00; - break; - case TDA18271HDC2: - regs[R_EB18] = 0x8c; - break; - }; - - regs[R_EB19] = 0x00; - regs[R_EB20] = 0x20; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB21] = 0x33; - break; - case TDA18271HDC2: - regs[R_EB21] = 0xb3; - break; - }; - - regs[R_EB22] = 0x48; - regs[R_EB23] = 0xb0; - - tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); - - /* setup agc1 gain */ - regs[R_EB17] = 0x00; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x03; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x43; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x4c; - tda18271_write_regs(fe, R_EB17, 1); - - /* setup agc2 gain */ - if ((priv->id) == TDA18271HDC1) { - regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); - } - - /* image rejection calibration */ - - /* low-band */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x81; - regs[R_CPD] = 0xcc; - regs[R_CD1] = 0x6c; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0xcd; - regs[R_MD1] = 0x77; - regs[R_MD2] = 0x08; - regs[R_MD3] = 0x00; - - tda18271_write_regs(fe, R_EP3, 11); - - if ((priv->id) == TDA18271HDC2) { - /* main pll cp source on */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); - msleep(1); - - /* main pll cp source off */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); - } - - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted low measurement */ - - regs[R_EP5] = 0x85; - regs[R_CPD] = 0xcb; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0x70; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image low optimization completion */ - - /* mid-band */ - regs[R_EP5] = 0x82; - regs[R_CPD] = 0xa8; - regs[R_CD2] = 0x00; - regs[R_MPD] = 0xa9; - regs[R_MD1] = 0x73; - regs[R_MD2] = 0x1a; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted mid measurement */ - - regs[R_EP5] = 0x86; - regs[R_CPD] = 0xa8; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0xa0; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image mid optimization completion */ - - /* high-band */ - regs[R_EP5] = 0x83; - regs[R_CPD] = 0x98; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x00; - regs[R_MPD] = 0x99; - regs[R_MD1] = 0x71; - regs[R_MD2] = 0xcd; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted high measurement */ - - regs[R_EP5] = 0x87; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x50; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image high optimization completion */ - - /* return to normal mode */ - regs[R_EP4] = 0x64; - tda18271_write_regs(fe, R_EP4, 1); - - /* synchronize */ - tda18271_write_regs(fe, R_EP1, 1); - - return 0; -} - -/*---------------------------------------------------------------------*/ - -/* - * Standby modes, EP3 [7:5] - * - * | SM || SM_LT || SM_XT || mode description - * |=====\\=======\\=======\\=================================== - * | 0 || 0 || 0 || normal mode - * |-----||-------||-------||----------------------------------- - * | || || || standby mode w/ slave tuner output - * | 1 || 0 || 0 || & loop thru & xtal oscillator on - * |-----||-------||-------||----------------------------------- - * | 1 || 1 || 0 || standby mode w/ xtal oscillator on - * |-----||-------||-------||----------------------------------- - * | 1 || 1 || 1 || power off - * - */ - -int tda18271_set_standby_mode(struct dvb_frontend *fe, - int sm, int sm_lt, int sm_xt) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - if (tda18271_debug & DBG_ADV) - tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); - - regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ - regs[R_EP3] |= (sm ? (1 << 7) : 0) | - (sm_lt ? (1 << 6) : 0) | - (sm_xt ? (1 << 5) : 0); - - return tda18271_write_regs(fe, R_EP3, 1); -} - -/*---------------------------------------------------------------------*/ - -int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) -{ - /* sets main post divider & divider bytes, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 d, pd; - u32 div; - - int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); - if (tda_fail(ret)) - goto fail; - - regs[R_MPD] = (0x77 & pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } - - div = ((d * (freq / 1000)) << 7) / 125; - - regs[R_MD1] = 0x7f & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; -fail: - return ret; -} - -int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) -{ - /* sets cal post divider & divider bytes, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 d, pd; - u32 div; - - int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); - if (tda_fail(ret)) - goto fail; - - regs[R_CPD] = pd; - - div = ((d * (freq / 1000)) << 7) / 125; - - regs[R_CD1] = 0x7f & (div >> 16); - regs[R_CD2] = 0xff & (div >> 8); - regs[R_CD3] = 0xff & div; -fail: - return ret; -} - -/*---------------------------------------------------------------------*/ - -int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) -{ - /* sets bp filter bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EP1] &= ~0x07; /* clear bp filter bits */ - regs[R_EP1] |= (0x07 & val); -fail: - return ret; -} - -int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) -{ - /* sets K & M bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EB13] &= ~0x7c; /* clear k & m bits */ - regs[R_EB13] |= (0x7c & val); -fail: - return ret; -} - -int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) -{ - /* sets rf band bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EP2] &= ~0xe0; /* clear rf band bits */ - regs[R_EP2] |= (0xe0 & (val << 5)); -fail: - return ret; -} - -int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) -{ - /* sets gain taper bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ - regs[R_EP2] |= (0x1f & val); -fail: - return ret; -} - -int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) -{ - /* sets IR Meas bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); - if (tda_fail(ret)) - goto fail; - - regs[R_EP5] &= ~0x07; - regs[R_EP5] |= (0x07 & val); -fail: - return ret; -} - -int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) -{ - /* sets rf cal byte (RFC_Cprog), but does not write it */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); - /* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range - * for frequencies above 61.1 MHz. In these cases, the internal RF - * tracking filters calibration mechanism is used. - * - * There is no need to warn the user about this. - */ - if (ret < 0) - goto fail; - - regs[R_EB14] = val; -fail: - return ret; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-fe.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1340 +0,0 @@ -/* - tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include "tda18271-priv.h" - -int tda18271_debug; -module_param_named(debug, tda18271_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level " - "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); - -static int tda18271_cal_on_startup = -1; -module_param_named(cal, tda18271_cal_on_startup, int, 0644); -MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); - -static DEFINE_MUTEX(tda18271_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -/*---------------------------------------------------------------------*/ - -static int tda18271_toggle_output(struct dvb_frontend *fe, int standby) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0, - priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0, - priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0); - - if (tda_fail(ret)) - goto fail; - - tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n", - standby ? "standby" : "active", - priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on", - priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on"); -fail: - return ret; -} - -/*---------------------------------------------------------------------*/ - -static inline int charge_pump_source(struct dvb_frontend *fe, int force) -{ - struct tda18271_priv *priv = fe->tuner_priv; - return tda18271_charge_pump_source(fe, - (priv->role == TDA18271_SLAVE) ? - TDA18271_CAL_PLL : - TDA18271_MAIN_PLL, force); -} - -static inline void tda18271_set_if_notch(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x80; /* IF notch = 0 */ - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x80; /* IF notch = 1 */ - break; - } -} - -static int tda18271_channel_configuration(struct dvb_frontend *fe, - struct tda18271_std_map_item *map, - u32 freq, u32 bw) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - u32 N; - - /* update TV broadcast parameters */ - - /* set standard */ - regs[R_EP3] &= ~0x1f; /* clear std bits */ - regs[R_EP3] |= (map->agc_mode << 3) | map->std; - - if (priv->id == TDA18271HDC2) { - /* set rfagc to high speed mode */ - regs[R_EP3] &= ~0x04; - } - - /* set cal mode to normal */ - regs[R_EP4] &= ~0x03; - - /* update IF output level */ - regs[R_EP4] &= ~0x1c; /* clear if level bits */ - regs[R_EP4] |= (map->if_lvl << 2); - - /* update FM_RFn */ - regs[R_EP4] &= ~0x80; - regs[R_EP4] |= map->fm_rfn << 7; - - /* update rf top / if top */ - regs[R_EB22] = 0x00; - regs[R_EB22] |= map->rfagc_top; - ret = tda18271_write_regs(fe, R_EB22, 1); - if (tda_fail(ret)) - goto fail; - - /* --------------------------------------------------------------- */ - - /* disable Power Level Indicator */ - regs[R_EP1] |= 0x40; - - /* make sure thermometer is off */ - regs[R_TM] &= ~0x10; - - /* frequency dependent parameters */ - - tda18271_calc_ir_measure(fe, &freq); - - tda18271_calc_bp_filter(fe, &freq); - - tda18271_calc_rf_band(fe, &freq); - - tda18271_calc_gain_taper(fe, &freq); - - /* --------------------------------------------------------------- */ - - /* dual tuner and agc1 extra configuration */ - - switch (priv->role) { - case TDA18271_MASTER: - regs[R_EB1] |= 0x04; /* main vco */ - break; - case TDA18271_SLAVE: - regs[R_EB1] &= ~0x04; /* cal vco */ - break; - } - - /* agc1 always active */ - regs[R_EB1] &= ~0x02; - - /* agc1 has priority on agc2 */ - regs[R_EB1] &= ~0x01; - - ret = tda18271_write_regs(fe, R_EB1, 1); - if (tda_fail(ret)) - goto fail; - - /* --------------------------------------------------------------- */ - - N = map->if_freq * 1000 + freq; - - switch (priv->role) { - case TDA18271_MASTER: - tda18271_calc_main_pll(fe, N); - tda18271_set_if_notch(fe); - tda18271_write_regs(fe, R_MPD, 4); - break; - case TDA18271_SLAVE: - tda18271_calc_cal_pll(fe, N); - tda18271_write_regs(fe, R_CPD, 4); - - regs[R_MPD] = regs[R_CPD] & 0x7f; - tda18271_set_if_notch(fe); - tda18271_write_regs(fe, R_MPD, 1); - break; - } - - ret = tda18271_write_regs(fe, R_TM, 7); - if (tda_fail(ret)) - goto fail; - - /* force charge pump source */ - charge_pump_source(fe, 1); - - msleep(1); - - /* return pll to normal operation */ - charge_pump_source(fe, 0); - - msleep(20); - - if (priv->id == TDA18271HDC2) { - /* set rfagc to normal speed mode */ - if (map->fm_rfn) - regs[R_EP3] &= ~0x04; - else - regs[R_EP3] |= 0x04; - ret = tda18271_write_regs(fe, R_EP3, 1); - } -fail: - return ret; -} - -static int tda18271_read_thermometer(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int tm; - - /* switch thermometer on */ - regs[R_TM] |= 0x10; - tda18271_write_regs(fe, R_TM, 1); - - /* read thermometer info */ - tda18271_read_regs(fe); - - if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || - (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { - - if ((regs[R_TM] & 0x20) == 0x20) - regs[R_TM] &= ~0x20; - else - regs[R_TM] |= 0x20; - - tda18271_write_regs(fe, R_TM, 1); - - msleep(10); /* temperature sensing */ - - /* read thermometer info */ - tda18271_read_regs(fe); - } - - tm = tda18271_lookup_thermometer(fe); - - /* switch thermometer off */ - regs[R_TM] &= ~0x10; - tda18271_write_regs(fe, R_TM, 1); - - /* set CAL mode to normal */ - regs[R_EP4] &= ~0x03; - tda18271_write_regs(fe, R_EP4, 1); - - return tm; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, - u32 freq) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; - unsigned char *regs = priv->tda18271_regs; - int i, ret; - u8 tm_current, dc_over_dt, rf_tab; - s32 rfcal_comp, approx; - - /* power up */ - ret = tda18271_set_standby_mode(fe, 0, 0, 0); - if (tda_fail(ret)) - goto fail; - - /* read die current temperature */ - tm_current = tda18271_read_thermometer(fe); - - /* frequency dependent parameters */ - - tda18271_calc_rf_cal(fe, &freq); - rf_tab = regs[R_EB14]; - - i = tda18271_lookup_rf_band(fe, &freq, NULL); - if (tda_fail(i)) - return i; - - if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { - approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) + - map[i].rf_b1 + rf_tab; - } else { - approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) + - map[i].rf_b2 + rf_tab; - } - - if (approx < 0) - approx = 0; - if (approx > 255) - approx = 255; - - tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); - - /* calculate temperature compensation */ - rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000; - - regs[R_EB14] = (unsigned char)(approx + rfcal_comp); - ret = tda18271_write_regs(fe, R_EB14, 1); -fail: - return ret; -} - -static int tda18271_por(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - - /* power up detector 1 */ - regs[R_EB12] &= ~0x20; - ret = tda18271_write_regs(fe, R_EB12, 1); - if (tda_fail(ret)) - goto fail; - - regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ - regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - ret = tda18271_write_regs(fe, R_EB18, 1); - if (tda_fail(ret)) - goto fail; - - regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ - - /* POR mode */ - ret = tda18271_set_standby_mode(fe, 1, 0, 0); - if (tda_fail(ret)) - goto fail; - - /* disable 1.5 MHz low pass filter */ - regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ - regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ - ret = tda18271_write_regs(fe, R_EB21, 3); -fail: - return ret; -} - -static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u32 N; - - /* set CAL mode to normal */ - regs[R_EP4] &= ~0x03; - tda18271_write_regs(fe, R_EP4, 1); - - /* switch off agc1 */ - regs[R_EP3] |= 0x40; /* sm_lt = 1 */ - - regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ - tda18271_write_regs(fe, R_EB18, 1); - - /* frequency dependent parameters */ - - tda18271_calc_bp_filter(fe, &freq); - tda18271_calc_gain_taper(fe, &freq); - tda18271_calc_rf_band(fe, &freq); - tda18271_calc_km(fe, &freq); - - tda18271_write_regs(fe, R_EP1, 3); - tda18271_write_regs(fe, R_EB13, 1); - - /* main pll charge pump source */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); - - /* cal pll charge pump source */ - tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1); - - /* force dcdc converter to 0 V */ - regs[R_EB14] = 0x00; - tda18271_write_regs(fe, R_EB14, 1); - - /* disable plls lock */ - regs[R_EB20] &= ~0x20; - tda18271_write_regs(fe, R_EB20, 1); - - /* set CAL mode to RF tracking filter calibration */ - regs[R_EP4] |= 0x03; - tda18271_write_regs(fe, R_EP4, 2); - - /* --------------------------------------------------------------- */ - - /* set the internal calibration signal */ - N = freq; - - tda18271_calc_cal_pll(fe, N); - tda18271_write_regs(fe, R_CPD, 4); - - /* downconvert internal calibration */ - N += 1000000; - - tda18271_calc_main_pll(fe, N); - tda18271_write_regs(fe, R_MPD, 4); - - msleep(5); - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - - /* --------------------------------------------------------------- */ - - /* normal operation for the main pll */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); - - /* normal operation for the cal pll */ - tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0); - - msleep(10); /* plls locking */ - - /* launch the rf tracking filters calibration */ - regs[R_EB20] |= 0x20; - tda18271_write_regs(fe, R_EB20, 1); - - msleep(60); /* calibration */ - - /* --------------------------------------------------------------- */ - - /* set CAL mode to normal */ - regs[R_EP4] &= ~0x03; - - /* switch on agc1 */ - regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ - - regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - tda18271_write_regs(fe, R_EB18, 1); - - tda18271_write_regs(fe, R_EP3, 2); - - /* synchronization */ - tda18271_write_regs(fe, R_EP1, 1); - - /* get calibration result */ - tda18271_read_extended(fe); - - return regs[R_EB14]; -} - -static int tda18271_powerscan(struct dvb_frontend *fe, - u32 *freq_in, u32 *freq_out) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int sgn, bcal, count, wait, ret; - u8 cid_target; - u16 count_limit; - u32 freq; - - freq = *freq_in; - - tda18271_calc_rf_band(fe, &freq); - tda18271_calc_rf_cal(fe, &freq); - tda18271_calc_gain_taper(fe, &freq); - tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EB14, 1); - - /* downconvert frequency */ - freq += 1000000; - - tda18271_calc_main_pll(fe, freq); - tda18271_write_regs(fe, R_MPD, 4); - - msleep(5); /* pll locking */ - - /* detection mode */ - regs[R_EP4] &= ~0x03; - regs[R_EP4] |= 0x01; - tda18271_write_regs(fe, R_EP4, 1); - - /* launch power detection measurement */ - tda18271_write_regs(fe, R_EP2, 1); - - /* read power detection info, stored in EB10 */ - ret = tda18271_read_extended(fe); - if (tda_fail(ret)) - return ret; - - /* algorithm initialization */ - sgn = 1; - *freq_out = *freq_in; - bcal = 0; - count = 0; - wait = false; - - while ((regs[R_EB10] & 0x3f) < cid_target) { - /* downconvert updated freq to 1 MHz */ - freq = *freq_in + (sgn * count) + 1000000; - - tda18271_calc_main_pll(fe, freq); - tda18271_write_regs(fe, R_MPD, 4); - - if (wait) { - msleep(5); /* pll locking */ - wait = false; - } else - udelay(100); /* pll locking */ - - /* launch power detection measurement */ - tda18271_write_regs(fe, R_EP2, 1); - - /* read power detection info, stored in EB10 */ - ret = tda18271_read_extended(fe); - if (tda_fail(ret)) - return ret; - - count += 200; - - if (count <= count_limit) - continue; - - if (sgn <= 0) - break; - - sgn = -1 * sgn; - count = 200; - wait = true; - } - - if ((regs[R_EB10] & 0x3f) >= cid_target) { - bcal = 1; - *freq_out = freq - 1000000; - } else - bcal = 0; - - tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", - bcal, *freq_in, *freq_out, freq); - - return bcal; -} - -static int tda18271_powerscan_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - - /* set standard to digital */ - regs[R_EP3] &= ~0x1f; /* clear std bits */ - regs[R_EP3] |= 0x12; - - /* set cal mode to normal */ - regs[R_EP4] &= ~0x03; - - /* update IF output level */ - regs[R_EP4] &= ~0x1c; /* clear if level bits */ - - ret = tda18271_write_regs(fe, R_EP3, 2); - if (tda_fail(ret)) - goto fail; - - regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - ret = tda18271_write_regs(fe, R_EB18, 1); - if (tda_fail(ret)) - goto fail; - - regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ - - /* 1.5 MHz low pass filter */ - regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ - regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ - - ret = tda18271_write_regs(fe, R_EB21, 3); -fail: - return ret; -} - -static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; - unsigned char *regs = priv->tda18271_regs; - int bcal, rf, i; - s32 divisor, dividend; -#define RF1 0 -#define RF2 1 -#define RF3 2 - u32 rf_default[3]; - u32 rf_freq[3]; - u8 prog_cal[3]; - u8 prog_tab[3]; - - i = tda18271_lookup_rf_band(fe, &freq, NULL); - - if (tda_fail(i)) - return i; - - rf_default[RF1] = 1000 * map[i].rf1_def; - rf_default[RF2] = 1000 * map[i].rf2_def; - rf_default[RF3] = 1000 * map[i].rf3_def; - - for (rf = RF1; rf <= RF3; rf++) { - if (0 == rf_default[rf]) - return 0; - tda_cal("freq = %d, rf = %d\n", freq, rf); - - /* look for optimized calibration frequency */ - bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); - if (tda_fail(bcal)) - return bcal; - - tda18271_calc_rf_cal(fe, &rf_freq[rf]); - prog_tab[rf] = regs[R_EB14]; - - if (1 == bcal) - prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]); - else - prog_cal[rf] = prog_tab[rf]; - - switch (rf) { - case RF1: - map[i].rf_a1 = 0; - map[i].rf_b1 = (s32)(prog_cal[RF1] - prog_tab[RF1]); - map[i].rf1 = rf_freq[RF1] / 1000; - break; - case RF2: - dividend = (s32)(prog_cal[RF2] - prog_tab[RF2]) - - (s32)(prog_cal[RF1] + prog_tab[RF1]); - divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; - map[i].rf_a1 = (dividend / divisor); - map[i].rf2 = rf_freq[RF2] / 1000; - break; - case RF3: - dividend = (s32)(prog_cal[RF3] - prog_tab[RF3]) - - (s32)(prog_cal[RF2] + prog_tab[RF2]); - divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; - map[i].rf_a2 = (dividend / divisor); - map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]); - map[i].rf3 = rf_freq[RF3] / 1000; - break; - default: - BUG(); - } - } - - return 0; -} - -static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned int i; - int ret; - - tda_info("tda18271: performing RF tracking filter calibration\n"); - - /* wait for die temperature stabilization */ - msleep(200); - - ret = tda18271_powerscan_init(fe); - if (tda_fail(ret)) - goto fail; - - /* rf band calibration */ - for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) { - ret = - tda18271_rf_tracking_filters_init(fe, 1000 * - priv->rf_cal_state[i].rfmax); - if (tda_fail(ret)) - goto fail; - } - - priv->tm_rfcal = tda18271_read_thermometer(fe); -fail: - return ret; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271c2_rf_cal_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - - /* test RF_CAL_OK to see if we need init */ - if ((regs[R_EP1] & 0x10) == 0) - priv->cal_initialized = false; - - if (priv->cal_initialized) - return 0; - - ret = tda18271_calc_rf_filter_curve(fe); - if (tda_fail(ret)) - goto fail; - - ret = tda18271_por(fe); - if (tda_fail(ret)) - goto fail; - - tda_info("tda18271: RF tracking filter calibration complete\n"); - - priv->cal_initialized = true; - goto end; -fail: - tda_info("tda18271: RF tracking filter calibration failed!\n"); -end: - return ret; -} - -static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe, - u32 freq, u32 bw) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - u32 N = 0; - - /* calculate bp filter */ - tda18271_calc_bp_filter(fe, &freq); - tda18271_write_regs(fe, R_EP1, 1); - - regs[R_EB4] &= 0x07; - regs[R_EB4] |= 0x60; - tda18271_write_regs(fe, R_EB4, 1); - - regs[R_EB7] = 0x60; - tda18271_write_regs(fe, R_EB7, 1); - - regs[R_EB14] = 0x00; - tda18271_write_regs(fe, R_EB14, 1); - - regs[R_EB20] = 0xcc; - tda18271_write_regs(fe, R_EB20, 1); - - /* set cal mode to RF tracking filter calibration */ - regs[R_EP4] |= 0x03; - - /* calculate cal pll */ - - switch (priv->mode) { - case TDA18271_ANALOG: - N = freq - 1250000; - break; - case TDA18271_DIGITAL: - N = freq + bw / 2; - break; - } - - tda18271_calc_cal_pll(fe, N); - - /* calculate main pll */ - - switch (priv->mode) { - case TDA18271_ANALOG: - N = freq - 250000; - break; - case TDA18271_DIGITAL: - N = freq + bw / 2 + 1000000; - break; - } - - tda18271_calc_main_pll(fe, N); - - ret = tda18271_write_regs(fe, R_EP3, 11); - if (tda_fail(ret)) - return ret; - - msleep(5); /* RF tracking filter calibration initialization */ - - /* search for K,M,CO for RF calibration */ - tda18271_calc_km(fe, &freq); - tda18271_write_regs(fe, R_EB13, 1); - - /* search for rf band */ - tda18271_calc_rf_band(fe, &freq); - - /* search for gain taper */ - tda18271_calc_gain_taper(fe, &freq); - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - - regs[R_EB4] &= 0x07; - regs[R_EB4] |= 0x40; - tda18271_write_regs(fe, R_EB4, 1); - - regs[R_EB7] = 0x40; - tda18271_write_regs(fe, R_EB7, 1); - msleep(10); /* pll locking */ - - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); - msleep(60); /* RF tracking filter calibration completion */ - - regs[R_EP4] &= ~0x03; /* set cal mode to normal */ - tda18271_write_regs(fe, R_EP4, 1); - - tda18271_write_regs(fe, R_EP1, 1); - - /* RF tracking filter correction for VHF_Low band */ - if (0 == tda18271_calc_rf_cal(fe, &freq)) - tda18271_write_regs(fe, R_EB14, 1); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_ir_cal_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int ret; - - ret = tda18271_read_regs(fe); - if (tda_fail(ret)) - goto fail; - - /* test IR_CAL_OK to see if we need init */ - if ((regs[R_EP1] & 0x08) == 0) - ret = tda18271_init_regs(fe); -fail: - return ret; -} - -static int tda18271_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret; - - mutex_lock(&priv->lock); - - /* full power up */ - ret = tda18271_set_standby_mode(fe, 0, 0, 0); - if (tda_fail(ret)) - goto fail; - - /* initialization */ - ret = tda18271_ir_cal_init(fe); - if (tda_fail(ret)) - goto fail; - - if (priv->id == TDA18271HDC2) - tda18271c2_rf_cal_init(fe); -fail: - mutex_unlock(&priv->lock); - - return ret; -} - -static int tda18271_sleep(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret; - - mutex_lock(&priv->lock); - - /* enter standby mode, with required output features enabled */ - ret = tda18271_toggle_output(fe, 1); - - mutex_unlock(&priv->lock); - - return ret; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_agc(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret = 0; - - switch (priv->config) { - case 0: - /* no external agc configuration required */ - if (tda18271_debug & DBG_ADV) - tda_dbg("no agc configuration provided\n"); - break; - case 3: - /* switch with GPIO of saa713x */ - tda_dbg("invoking callback\n"); - if (fe->callback) - ret = fe->callback(priv->i2c_props.adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, - TDA18271_CALLBACK_CMD_AGC_ENABLE, - priv->mode); - break; - case 1: - case 2: - default: - /* n/a - currently not supported */ - tda_err("unsupported configuration: %d\n", priv->config); - ret = -EINVAL; - break; - } - return ret; -} - -static int tda18271_tune(struct dvb_frontend *fe, - struct tda18271_std_map_item *map, u32 freq, u32 bw) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret; - - tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n", - freq, map->if_freq, bw, map->agc_mode, map->std); - - ret = tda18271_agc(fe); - if (tda_fail(ret)) - tda_warn("failed to configure agc\n"); - - ret = tda18271_init(fe); - if (tda_fail(ret)) - goto fail; - - mutex_lock(&priv->lock); - - switch (priv->id) { - case TDA18271HDC1: - tda18271c1_rf_tracking_filter_calibration(fe, freq, bw); - break; - case TDA18271HDC2: - tda18271c2_rf_tracking_filters_correction(fe, freq); - break; - } - ret = tda18271_channel_configuration(fe, map, freq, bw); - - mutex_unlock(&priv->lock); -fail: - return ret; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std_map = &priv->std; - struct tda18271_std_map_item *map; - int ret; - u32 bw, freq = params->frequency; - - priv->mode = TDA18271_DIGITAL; - - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - map = &std_map->atsc_6; - break; - case QAM_64: - case QAM_256: - map = &std_map->qam_6; - break; - default: - tda_warn("modulation not set!\n"); - return -EINVAL; - } -#if 0 - /* userspace request is already center adjusted */ - freq += 1750000; /* Adjust to center (+1.75MHZ) */ -#endif - bw = 6000000; - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - bw = 6000000; - map = &std_map->dvbt_6; - break; - case BANDWIDTH_7_MHZ: - bw = 7000000; - map = &std_map->dvbt_7; - break; - case BANDWIDTH_8_MHZ: - bw = 8000000; - map = &std_map->dvbt_8; - break; - default: - tda_warn("bandwidth not set!\n"); - return -EINVAL; - } - } else { - tda_warn("modulation type not supported!\n"); - return -EINVAL; - } - - /* When tuning digital, the analog demod must be tri-stated */ - if (fe->ops.analog_ops.standby) - fe->ops.analog_ops.standby(fe); - - ret = tda18271_tune(fe, map, freq, bw); - - if (tda_fail(ret)) - goto fail; - - priv->frequency = freq; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; -fail: - return ret; -} - -static int tda18271_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std_map = &priv->std; - struct tda18271_std_map_item *map; - char *mode; - int ret; - u32 freq = params->frequency * 125 * - ((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2; - - priv->mode = TDA18271_ANALOG; - - if (params->mode == V4L2_TUNER_RADIO) { - map = &std_map->fm_radio; - mode = "fm"; - } else if (params->std & V4L2_STD_MN) { - map = &std_map->atv_mn; - mode = "MN"; - } else if (params->std & V4L2_STD_B) { - map = &std_map->atv_b; - mode = "B"; - } else if (params->std & V4L2_STD_GH) { - map = &std_map->atv_gh; - mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - map = &std_map->atv_i; - mode = "I"; - } else if (params->std & V4L2_STD_DK) { - map = &std_map->atv_dk; - mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - map = &std_map->atv_l; - mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - map = &std_map->atv_lc; - mode = "L'"; - } else { - map = &std_map->atv_i; - mode = "xx"; - } - - tda_dbg("setting tda18271 to system %s\n", mode); - - ret = tda18271_tune(fe, map, freq, 0); - - if (tda_fail(ret)) - goto fail; - - priv->frequency = freq; - priv->bandwidth = 0; -fail: - return ret; -} - -static int tda18271_release(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - mutex_lock(&tda18271_list_mutex); - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&tda18271_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda18271_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct tda18271_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -/* ------------------------------------------------------------------ */ - -#define tda18271_update_std(std_cfg, name) do { \ - if (map->std_cfg.if_freq + \ - map->std_cfg.agc_mode + map->std_cfg.std + \ - map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) { \ - tda_dbg("Using custom std config for %s\n", name); \ - memcpy(&std->std_cfg, &map->std_cfg, \ - sizeof(struct tda18271_std_map_item)); \ - } } while (0) - -#define tda18271_dump_std_item(std_cfg, name) do { \ - tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, " \ - "if_lvl = %d, rfagc_top = 0x%02x\n", \ - name, std->std_cfg.if_freq, \ - std->std_cfg.agc_mode, std->std_cfg.std, \ - std->std_cfg.if_lvl, std->std_cfg.rfagc_top); \ - } while (0) - -static int tda18271_dump_std_map(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std = &priv->std; - - tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); - tda18271_dump_std_item(fm_radio, " fm "); - tda18271_dump_std_item(atv_b, "atv b "); - tda18271_dump_std_item(atv_dk, "atv dk"); - tda18271_dump_std_item(atv_gh, "atv gh"); - tda18271_dump_std_item(atv_i, "atv i "); - tda18271_dump_std_item(atv_l, "atv l "); - tda18271_dump_std_item(atv_lc, "atv l'"); - tda18271_dump_std_item(atv_mn, "atv mn"); - tda18271_dump_std_item(atsc_6, "atsc 6"); - tda18271_dump_std_item(dvbt_6, "dvbt 6"); - tda18271_dump_std_item(dvbt_7, "dvbt 7"); - tda18271_dump_std_item(dvbt_8, "dvbt 8"); - tda18271_dump_std_item(qam_6, "qam 6 "); - tda18271_dump_std_item(qam_8, "qam 8 "); - - return 0; -} - -static int tda18271_update_std_map(struct dvb_frontend *fe, - struct tda18271_std_map *map) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std = &priv->std; - - if (!map) - return -EINVAL; - - tda18271_update_std(fm_radio, "fm"); - tda18271_update_std(atv_b, "atv b"); - tda18271_update_std(atv_dk, "atv dk"); - tda18271_update_std(atv_gh, "atv gh"); - tda18271_update_std(atv_i, "atv i"); - tda18271_update_std(atv_l, "atv l"); - tda18271_update_std(atv_lc, "atv l'"); - tda18271_update_std(atv_mn, "atv mn"); - tda18271_update_std(atsc_6, "atsc 6"); - tda18271_update_std(dvbt_6, "dvbt 6"); - tda18271_update_std(dvbt_7, "dvbt 7"); - tda18271_update_std(dvbt_8, "dvbt 8"); - tda18271_update_std(qam_6, "qam 6"); - tda18271_update_std(qam_8, "qam 8"); - - return 0; -} - -static int tda18271_get_id(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - char *name; - - mutex_lock(&priv->lock); - tda18271_read_regs(fe); - mutex_unlock(&priv->lock); - - switch (regs[R_ID] & 0x7f) { - case 3: - name = "TDA18271HD/C1"; - priv->id = TDA18271HDC1; - break; - case 4: - name = "TDA18271HD/C2"; - priv->id = TDA18271HDC2; - break; - default: - tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n", - regs[R_ID], i2c_adapter_id(priv->i2c_props.adap), - priv->i2c_props.addr); - return -EINVAL; - } - - tda_info("%s detected @ %d-%04x\n", name, - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); - - return 0; -} - -static int tda18271_setup_configuration(struct dvb_frontend *fe, - struct tda18271_config *cfg) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; - priv->role = (cfg) ? cfg->role : TDA18271_MASTER; - priv->config = (cfg) ? cfg->config : 0; - priv->small_i2c = (cfg) ? - cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT; - priv->output_opt = (cfg) ? - cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON; - - return 0; -} - -static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg) -{ - /* tda18271_cal_on_startup == -1 when cal module option is unset */ - return ((tda18271_cal_on_startup == -1) ? - /* honor configuration setting */ - ((cfg) && (cfg->rf_cal_on_startup)) : - /* module option overrides configuration setting */ - (tda18271_cal_on_startup)) ? 1 : 0; -} - -static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg; - - tda18271_setup_configuration(fe, cfg); - - if (tda18271_need_cal_on_startup(cfg)) - tda18271_init(fe); - - /* override default std map with values in config struct */ - if ((cfg) && (cfg->std_map)) - tda18271_update_std_map(fe, cfg->std_map); - - return 0; -} - -static struct dvb_tuner_ops tda18271_tuner_ops = { - .info = { - .name = "NXP TDA18271HD", - .frequency_min = 45000000, - .frequency_max = 864000000, - .frequency_step = 62500 - }, - .init = tda18271_init, - .sleep = tda18271_sleep, - .set_params = tda18271_set_params, - .set_analog_params = tda18271_set_analog_params, - .release = tda18271_release, - .set_config = tda18271_set_config, - .get_frequency = tda18271_get_frequency, - .get_bandwidth = tda18271_get_bandwidth, -}; - -struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c, - struct tda18271_config *cfg) -{ - struct tda18271_priv *priv = NULL; - int instance, ret; - - mutex_lock(&tda18271_list_mutex); - - instance = hybrid_tuner_request_state(struct tda18271_priv, priv, - hybrid_tuner_instance_list, - i2c, addr, "tda18271"); - switch (instance) { - case 0: - goto fail; - case 1: - /* new tuner instance */ - fe->tuner_priv = priv; - - tda18271_setup_configuration(fe, cfg); - - priv->cal_initialized = false; - mutex_init(&priv->lock); - - ret = tda18271_get_id(fe); - if (tda_fail(ret)) - goto fail; - - ret = tda18271_assign_map_layout(fe); - if (tda_fail(ret)) - goto fail; - - mutex_lock(&priv->lock); - tda18271_init_regs(fe); - - if ((tda18271_need_cal_on_startup(cfg)) && - (priv->id == TDA18271HDC2)) - tda18271c2_rf_cal_init(fe); - - mutex_unlock(&priv->lock); - break; - default: - /* existing tuner instance */ - fe->tuner_priv = priv; - - /* allow dvb driver to override configuration settings */ - if (cfg) { - if (cfg->gate != TDA18271_GATE_ANALOG) - priv->gate = cfg->gate; - if (cfg->role) - priv->role = cfg->role; - if (cfg->config) - priv->config = cfg->config; - if (cfg->small_i2c) - priv->small_i2c = cfg->small_i2c; - if (cfg->output_opt) - priv->output_opt = cfg->output_opt; - if (cfg->std_map) - tda18271_update_std_map(fe, cfg->std_map); - } - if (tda18271_need_cal_on_startup(cfg)) - tda18271_init(fe); - break; - } - - /* override default std map with values in config struct */ - if ((cfg) && (cfg->std_map)) - tda18271_update_std_map(fe, cfg->std_map); - - mutex_unlock(&tda18271_list_mutex); - - memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - if (tda18271_debug & (DBG_MAP | DBG_ADV)) - tda18271_dump_std_map(fe); - - return fe; -fail: - mutex_unlock(&tda18271_list_mutex); - - tda18271_release(fe); - return NULL; -} -EXPORT_SYMBOL_GPL(tda18271_attach); -MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -/* - tda18271.h - header for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TDA18271_H__ -#define __TDA18271_H__ - -#include -#include "dvb_frontend.h" - -struct tda18271_std_map_item { - u16 if_freq; - - /* EP3[4:3] */ - unsigned int agc_mode:2; - /* EP3[2:0] */ - unsigned int std:3; - /* EP4[7] */ - unsigned int fm_rfn:1; - /* EP4[4:2] */ - unsigned int if_lvl:3; - /* EB22[6:0] */ - unsigned int rfagc_top:7; -}; - -struct tda18271_std_map { - struct tda18271_std_map_item fm_radio; - struct tda18271_std_map_item atv_b; - struct tda18271_std_map_item atv_dk; - struct tda18271_std_map_item atv_gh; - struct tda18271_std_map_item atv_i; - struct tda18271_std_map_item atv_l; - struct tda18271_std_map_item atv_lc; - struct tda18271_std_map_item atv_mn; - struct tda18271_std_map_item atsc_6; - struct tda18271_std_map_item dvbt_6; - struct tda18271_std_map_item dvbt_7; - struct tda18271_std_map_item dvbt_8; - struct tda18271_std_map_item qam_6; - struct tda18271_std_map_item qam_8; -}; - -enum tda18271_role { - TDA18271_MASTER = 0, - TDA18271_SLAVE, -}; - -enum tda18271_i2c_gate { - TDA18271_GATE_AUTO = 0, - TDA18271_GATE_ANALOG, - TDA18271_GATE_DIGITAL, -}; - -enum tda18271_output_options { - /* slave tuner output & loop thru & xtal oscillator always on */ - TDA18271_OUTPUT_LT_XT_ON = 0, - - /* slave tuner output loop thru off */ - TDA18271_OUTPUT_LT_OFF = 1, - - /* xtal oscillator off */ - TDA18271_OUTPUT_XT_OFF = 2, -}; - -enum tda18271_small_i2c { - TDA18271_39_BYTE_CHUNK_INIT = 0, - TDA18271_16_BYTE_CHUNK_INIT = 16, - TDA18271_08_BYTE_CHUNK_INIT = 8, - TDA18271_03_BYTE_CHUNK_INIT = 3, -}; - -struct tda18271_config { - /* override default if freq / std settings (optional) */ - struct tda18271_std_map *std_map; - - /* master / slave tuner: master uses main pll, slave uses cal pll */ - enum tda18271_role role; - - /* use i2c gate provided by analog or digital demod */ - enum tda18271_i2c_gate gate; - - /* output options that can be disabled */ - enum tda18271_output_options output_opt; - - /* some i2c providers cant write all 39 registers at once */ - enum tda18271_small_i2c small_i2c; - - /* force rf tracking filter calibration on startup */ - unsigned int rf_cal_on_startup:1; - - /* interface to saa713x / tda829x */ - unsigned int config; -}; - -#define TDA18271_CALLBACK_CMD_AGC_ENABLE 0 - -enum tda18271_mode { - TDA18271_ANALOG = 0, - TDA18271_DIGITAL, -}; - -#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c, - struct tda18271_config *cfg); -#else -static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, - u8 addr, - struct i2c_adapter *i2c, - struct tda18271_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TDA18271_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-maps.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-maps.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-maps.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-maps.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1313 +0,0 @@ -/* - tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "tda18271-priv.h" - -struct tda18271_pll_map { - u32 lomax; - u8 pd; /* post div */ - u8 d; /* div */ -}; - -struct tda18271_map { - u32 rfmax; - u8 val; -}; - -/*---------------------------------------------------------------------*/ - -static struct tda18271_pll_map tda18271c1_main_pll[] = { - { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, - { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, - { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, - { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, - { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, - { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, - { .lomax = 54000, .pd = 0x59, .d = 0x90 }, - { .lomax = 61000, .pd = 0x58, .d = 0x80 }, - { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, - { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, - { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, - { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, - { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, - { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, - { .lomax = 109000, .pd = 0x49, .d = 0x48 }, - { .lomax = 123000, .pd = 0x48, .d = 0x40 }, - { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, - { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, - { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, - { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, - { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, - { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, - { .lomax = 219000, .pd = 0x39, .d = 0x24 }, - { .lomax = 246000, .pd = 0x38, .d = 0x20 }, - { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, - { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, - { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, - { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, - { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, - { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, - { .lomax = 438000, .pd = 0x29, .d = 0x12 }, - { .lomax = 493000, .pd = 0x28, .d = 0x10 }, - { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, - { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, - { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, - { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, - { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, - { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, - { .lomax = 877000, .pd = 0x19, .d = 0x09 }, - { .lomax = 987000, .pd = 0x18, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271c2_main_pll[] = { - { .lomax = 33125, .pd = 0x57, .d = 0xf0 }, - { .lomax = 35500, .pd = 0x56, .d = 0xe0 }, - { .lomax = 38188, .pd = 0x55, .d = 0xd0 }, - { .lomax = 41375, .pd = 0x54, .d = 0xc0 }, - { .lomax = 45125, .pd = 0x53, .d = 0xb0 }, - { .lomax = 49688, .pd = 0x52, .d = 0xa0 }, - { .lomax = 55188, .pd = 0x51, .d = 0x90 }, - { .lomax = 62125, .pd = 0x50, .d = 0x80 }, - { .lomax = 66250, .pd = 0x47, .d = 0x78 }, - { .lomax = 71000, .pd = 0x46, .d = 0x70 }, - { .lomax = 76375, .pd = 0x45, .d = 0x68 }, - { .lomax = 82750, .pd = 0x44, .d = 0x60 }, - { .lomax = 90250, .pd = 0x43, .d = 0x58 }, - { .lomax = 99375, .pd = 0x42, .d = 0x50 }, - { .lomax = 110375, .pd = 0x41, .d = 0x48 }, - { .lomax = 124250, .pd = 0x40, .d = 0x40 }, - { .lomax = 132500, .pd = 0x37, .d = 0x3c }, - { .lomax = 142000, .pd = 0x36, .d = 0x38 }, - { .lomax = 152750, .pd = 0x35, .d = 0x34 }, - { .lomax = 165500, .pd = 0x34, .d = 0x30 }, - { .lomax = 180500, .pd = 0x33, .d = 0x2c }, - { .lomax = 198750, .pd = 0x32, .d = 0x28 }, - { .lomax = 220750, .pd = 0x31, .d = 0x24 }, - { .lomax = 248500, .pd = 0x30, .d = 0x20 }, - { .lomax = 265000, .pd = 0x27, .d = 0x1e }, - { .lomax = 284000, .pd = 0x26, .d = 0x1c }, - { .lomax = 305500, .pd = 0x25, .d = 0x1a }, - { .lomax = 331000, .pd = 0x24, .d = 0x18 }, - { .lomax = 361000, .pd = 0x23, .d = 0x16 }, - { .lomax = 397500, .pd = 0x22, .d = 0x14 }, - { .lomax = 441500, .pd = 0x21, .d = 0x12 }, - { .lomax = 497000, .pd = 0x20, .d = 0x10 }, - { .lomax = 530000, .pd = 0x17, .d = 0x0f }, - { .lomax = 568000, .pd = 0x16, .d = 0x0e }, - { .lomax = 611000, .pd = 0x15, .d = 0x0d }, - { .lomax = 662000, .pd = 0x14, .d = 0x0c }, - { .lomax = 722000, .pd = 0x13, .d = 0x0b }, - { .lomax = 795000, .pd = 0x12, .d = 0x0a }, - { .lomax = 883000, .pd = 0x11, .d = 0x09 }, - { .lomax = 994000, .pd = 0x10, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271c1_cal_pll[] = { - { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, - { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, - { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, - { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, - { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, - { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, - { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, - { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, - { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, - { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, - { .lomax = 88000, .pd = 0xca, .d = 0x50 }, - { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, - { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, - { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, - { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, - { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, - { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, - { .lomax = 176000, .pd = 0xba, .d = 0x28 }, - { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, - { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, - { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, - { .lomax = 271000, .pd = 0xad, .d = 0x1a }, - { .lomax = 294000, .pd = 0xac, .d = 0x18 }, - { .lomax = 321000, .pd = 0xab, .d = 0x16 }, - { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, - { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, - { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, - { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, - { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, - { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, - { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, - { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, - { .lomax = 785000, .pd = 0x99, .d = 0x09 }, - { .lomax = 883000, .pd = 0x98, .d = 0x08 }, - { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271c2_cal_pll[] = { - { .lomax = 33813, .pd = 0xdd, .d = 0xd0 }, - { .lomax = 36625, .pd = 0xdc, .d = 0xc0 }, - { .lomax = 39938, .pd = 0xdb, .d = 0xb0 }, - { .lomax = 43938, .pd = 0xda, .d = 0xa0 }, - { .lomax = 48813, .pd = 0xd9, .d = 0x90 }, - { .lomax = 54938, .pd = 0xd8, .d = 0x80 }, - { .lomax = 62813, .pd = 0xd3, .d = 0x70 }, - { .lomax = 67625, .pd = 0xcd, .d = 0x68 }, - { .lomax = 73250, .pd = 0xcc, .d = 0x60 }, - { .lomax = 79875, .pd = 0xcb, .d = 0x58 }, - { .lomax = 87875, .pd = 0xca, .d = 0x50 }, - { .lomax = 97625, .pd = 0xc9, .d = 0x48 }, - { .lomax = 109875, .pd = 0xc8, .d = 0x40 }, - { .lomax = 125625, .pd = 0xc3, .d = 0x38 }, - { .lomax = 135250, .pd = 0xbd, .d = 0x34 }, - { .lomax = 146500, .pd = 0xbc, .d = 0x30 }, - { .lomax = 159750, .pd = 0xbb, .d = 0x2c }, - { .lomax = 175750, .pd = 0xba, .d = 0x28 }, - { .lomax = 195250, .pd = 0xb9, .d = 0x24 }, - { .lomax = 219750, .pd = 0xb8, .d = 0x20 }, - { .lomax = 251250, .pd = 0xb3, .d = 0x1c }, - { .lomax = 270500, .pd = 0xad, .d = 0x1a }, - { .lomax = 293000, .pd = 0xac, .d = 0x18 }, - { .lomax = 319500, .pd = 0xab, .d = 0x16 }, - { .lomax = 351500, .pd = 0xaa, .d = 0x14 }, - { .lomax = 390500, .pd = 0xa9, .d = 0x12 }, - { .lomax = 439500, .pd = 0xa8, .d = 0x10 }, - { .lomax = 502500, .pd = 0xa3, .d = 0x0e }, - { .lomax = 541000, .pd = 0x9d, .d = 0x0d }, - { .lomax = 586000, .pd = 0x9c, .d = 0x0c }, - { .lomax = 639000, .pd = 0x9b, .d = 0x0b }, - { .lomax = 703000, .pd = 0x9a, .d = 0x0a }, - { .lomax = 781000, .pd = 0x99, .d = 0x09 }, - { .lomax = 879000, .pd = 0x98, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_bp_filter[] = { - { .rfmax = 62000, .val = 0x00 }, - { .rfmax = 84000, .val = 0x01 }, - { .rfmax = 100000, .val = 0x02 }, - { .rfmax = 140000, .val = 0x03 }, - { .rfmax = 170000, .val = 0x04 }, - { .rfmax = 180000, .val = 0x05 }, - { .rfmax = 865000, .val = 0x06 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c1_km[] = { - { .rfmax = 61100, .val = 0x74 }, - { .rfmax = 350000, .val = 0x40 }, - { .rfmax = 720000, .val = 0x30 }, - { .rfmax = 865000, .val = 0x40 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c2_km[] = { - { .rfmax = 47900, .val = 0x38 }, - { .rfmax = 61100, .val = 0x44 }, - { .rfmax = 350000, .val = 0x30 }, - { .rfmax = 720000, .val = 0x24 }, - { .rfmax = 865000, .val = 0x3c }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_rf_band[] = { - { .rfmax = 47900, .val = 0x00 }, - { .rfmax = 61100, .val = 0x01 }, -/* { .rfmax = 152600, .val = 0x02 }, */ - { .rfmax = 121200, .val = 0x02 }, - { .rfmax = 164700, .val = 0x03 }, - { .rfmax = 203500, .val = 0x04 }, - { .rfmax = 457800, .val = 0x05 }, - { .rfmax = 865000, .val = 0x06 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_gain_taper[] = { - { .rfmax = 45400, .val = 0x1f }, - { .rfmax = 45800, .val = 0x1e }, - { .rfmax = 46200, .val = 0x1d }, - { .rfmax = 46700, .val = 0x1c }, - { .rfmax = 47100, .val = 0x1b }, - { .rfmax = 47500, .val = 0x1a }, - { .rfmax = 47900, .val = 0x19 }, - { .rfmax = 49600, .val = 0x17 }, - { .rfmax = 51200, .val = 0x16 }, - { .rfmax = 52900, .val = 0x15 }, - { .rfmax = 54500, .val = 0x14 }, - { .rfmax = 56200, .val = 0x13 }, - { .rfmax = 57800, .val = 0x12 }, - { .rfmax = 59500, .val = 0x11 }, - { .rfmax = 61100, .val = 0x10 }, - { .rfmax = 67600, .val = 0x0d }, - { .rfmax = 74200, .val = 0x0c }, - { .rfmax = 80700, .val = 0x0b }, - { .rfmax = 87200, .val = 0x0a }, - { .rfmax = 93800, .val = 0x09 }, - { .rfmax = 100300, .val = 0x08 }, - { .rfmax = 106900, .val = 0x07 }, - { .rfmax = 113400, .val = 0x06 }, - { .rfmax = 119900, .val = 0x05 }, - { .rfmax = 126500, .val = 0x04 }, - { .rfmax = 133000, .val = 0x03 }, - { .rfmax = 139500, .val = 0x02 }, - { .rfmax = 146100, .val = 0x01 }, - { .rfmax = 152600, .val = 0x00 }, - { .rfmax = 154300, .val = 0x1f }, - { .rfmax = 156100, .val = 0x1e }, - { .rfmax = 157800, .val = 0x1d }, - { .rfmax = 159500, .val = 0x1c }, - { .rfmax = 161200, .val = 0x1b }, - { .rfmax = 163000, .val = 0x1a }, - { .rfmax = 164700, .val = 0x19 }, - { .rfmax = 170200, .val = 0x17 }, - { .rfmax = 175800, .val = 0x16 }, - { .rfmax = 181300, .val = 0x15 }, - { .rfmax = 186900, .val = 0x14 }, - { .rfmax = 192400, .val = 0x13 }, - { .rfmax = 198000, .val = 0x12 }, - { .rfmax = 203500, .val = 0x11 }, - { .rfmax = 216200, .val = 0x14 }, - { .rfmax = 228900, .val = 0x13 }, - { .rfmax = 241600, .val = 0x12 }, - { .rfmax = 254400, .val = 0x11 }, - { .rfmax = 267100, .val = 0x10 }, - { .rfmax = 279800, .val = 0x0f }, - { .rfmax = 292500, .val = 0x0e }, - { .rfmax = 305200, .val = 0x0d }, - { .rfmax = 317900, .val = 0x0c }, - { .rfmax = 330700, .val = 0x0b }, - { .rfmax = 343400, .val = 0x0a }, - { .rfmax = 356100, .val = 0x09 }, - { .rfmax = 368800, .val = 0x08 }, - { .rfmax = 381500, .val = 0x07 }, - { .rfmax = 394200, .val = 0x06 }, - { .rfmax = 406900, .val = 0x05 }, - { .rfmax = 419700, .val = 0x04 }, - { .rfmax = 432400, .val = 0x03 }, - { .rfmax = 445100, .val = 0x02 }, - { .rfmax = 457800, .val = 0x01 }, - { .rfmax = 476300, .val = 0x19 }, - { .rfmax = 494800, .val = 0x18 }, - { .rfmax = 513300, .val = 0x17 }, - { .rfmax = 531800, .val = 0x16 }, - { .rfmax = 550300, .val = 0x15 }, - { .rfmax = 568900, .val = 0x14 }, - { .rfmax = 587400, .val = 0x13 }, - { .rfmax = 605900, .val = 0x12 }, - { .rfmax = 624400, .val = 0x11 }, - { .rfmax = 642900, .val = 0x10 }, - { .rfmax = 661400, .val = 0x0f }, - { .rfmax = 679900, .val = 0x0e }, - { .rfmax = 698400, .val = 0x0d }, - { .rfmax = 716900, .val = 0x0c }, - { .rfmax = 735400, .val = 0x0b }, - { .rfmax = 753900, .val = 0x0a }, - { .rfmax = 772500, .val = 0x09 }, - { .rfmax = 791000, .val = 0x08 }, - { .rfmax = 809500, .val = 0x07 }, - { .rfmax = 828000, .val = 0x06 }, - { .rfmax = 846500, .val = 0x05 }, - { .rfmax = 865000, .val = 0x04 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c1_rf_cal[] = { - { .rfmax = 41000, .val = 0x1e }, - { .rfmax = 43000, .val = 0x30 }, - { .rfmax = 45000, .val = 0x43 }, - { .rfmax = 46000, .val = 0x4d }, - { .rfmax = 47000, .val = 0x54 }, - { .rfmax = 47900, .val = 0x64 }, - { .rfmax = 49100, .val = 0x20 }, - { .rfmax = 50000, .val = 0x22 }, - { .rfmax = 51000, .val = 0x2a }, - { .rfmax = 53000, .val = 0x32 }, - { .rfmax = 55000, .val = 0x35 }, - { .rfmax = 56000, .val = 0x3c }, - { .rfmax = 57000, .val = 0x3f }, - { .rfmax = 58000, .val = 0x48 }, - { .rfmax = 59000, .val = 0x4d }, - { .rfmax = 60000, .val = 0x58 }, - { .rfmax = 61100, .val = 0x5f }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c2_rf_cal[] = { - { .rfmax = 41000, .val = 0x0f }, - { .rfmax = 43000, .val = 0x1c }, - { .rfmax = 45000, .val = 0x2f }, - { .rfmax = 46000, .val = 0x39 }, - { .rfmax = 47000, .val = 0x40 }, - { .rfmax = 47900, .val = 0x50 }, - { .rfmax = 49100, .val = 0x16 }, - { .rfmax = 50000, .val = 0x18 }, - { .rfmax = 51000, .val = 0x20 }, - { .rfmax = 53000, .val = 0x28 }, - { .rfmax = 55000, .val = 0x2b }, - { .rfmax = 56000, .val = 0x32 }, - { .rfmax = 57000, .val = 0x35 }, - { .rfmax = 58000, .val = 0x3e }, - { .rfmax = 59000, .val = 0x43 }, - { .rfmax = 60000, .val = 0x4e }, - { .rfmax = 61100, .val = 0x55 }, - { .rfmax = 63000, .val = 0x0f }, - { .rfmax = 64000, .val = 0x11 }, - { .rfmax = 65000, .val = 0x12 }, - { .rfmax = 66000, .val = 0x15 }, - { .rfmax = 67000, .val = 0x16 }, - { .rfmax = 68000, .val = 0x17 }, - { .rfmax = 70000, .val = 0x19 }, - { .rfmax = 71000, .val = 0x1c }, - { .rfmax = 72000, .val = 0x1d }, - { .rfmax = 73000, .val = 0x1f }, - { .rfmax = 74000, .val = 0x20 }, - { .rfmax = 75000, .val = 0x21 }, - { .rfmax = 76000, .val = 0x24 }, - { .rfmax = 77000, .val = 0x25 }, - { .rfmax = 78000, .val = 0x27 }, - { .rfmax = 80000, .val = 0x28 }, - { .rfmax = 81000, .val = 0x29 }, - { .rfmax = 82000, .val = 0x2d }, - { .rfmax = 83000, .val = 0x2e }, - { .rfmax = 84000, .val = 0x2f }, - { .rfmax = 85000, .val = 0x31 }, - { .rfmax = 86000, .val = 0x33 }, - { .rfmax = 87000, .val = 0x34 }, - { .rfmax = 88000, .val = 0x35 }, - { .rfmax = 89000, .val = 0x37 }, - { .rfmax = 90000, .val = 0x38 }, - { .rfmax = 91000, .val = 0x39 }, - { .rfmax = 93000, .val = 0x3c }, - { .rfmax = 94000, .val = 0x3e }, - { .rfmax = 95000, .val = 0x3f }, - { .rfmax = 96000, .val = 0x40 }, - { .rfmax = 97000, .val = 0x42 }, - { .rfmax = 99000, .val = 0x45 }, - { .rfmax = 100000, .val = 0x46 }, - { .rfmax = 102000, .val = 0x48 }, - { .rfmax = 103000, .val = 0x4a }, - { .rfmax = 105000, .val = 0x4d }, - { .rfmax = 106000, .val = 0x4e }, - { .rfmax = 107000, .val = 0x50 }, - { .rfmax = 108000, .val = 0x51 }, - { .rfmax = 110000, .val = 0x54 }, - { .rfmax = 111000, .val = 0x56 }, - { .rfmax = 112000, .val = 0x57 }, - { .rfmax = 113000, .val = 0x58 }, - { .rfmax = 114000, .val = 0x59 }, - { .rfmax = 115000, .val = 0x5c }, - { .rfmax = 116000, .val = 0x5d }, - { .rfmax = 117000, .val = 0x5f }, - { .rfmax = 119000, .val = 0x60 }, - { .rfmax = 120000, .val = 0x64 }, - { .rfmax = 121000, .val = 0x65 }, - { .rfmax = 122000, .val = 0x66 }, - { .rfmax = 123000, .val = 0x68 }, - { .rfmax = 124000, .val = 0x69 }, - { .rfmax = 125000, .val = 0x6c }, - { .rfmax = 126000, .val = 0x6d }, - { .rfmax = 127000, .val = 0x6e }, - { .rfmax = 128000, .val = 0x70 }, - { .rfmax = 129000, .val = 0x71 }, - { .rfmax = 130000, .val = 0x75 }, - { .rfmax = 131000, .val = 0x77 }, - { .rfmax = 132000, .val = 0x78 }, - { .rfmax = 133000, .val = 0x7b }, - { .rfmax = 134000, .val = 0x7e }, - { .rfmax = 135000, .val = 0x81 }, - { .rfmax = 136000, .val = 0x82 }, - { .rfmax = 137000, .val = 0x87 }, - { .rfmax = 138000, .val = 0x88 }, - { .rfmax = 139000, .val = 0x8d }, - { .rfmax = 140000, .val = 0x8e }, - { .rfmax = 141000, .val = 0x91 }, - { .rfmax = 142000, .val = 0x95 }, - { .rfmax = 143000, .val = 0x9a }, - { .rfmax = 144000, .val = 0x9d }, - { .rfmax = 145000, .val = 0xa1 }, - { .rfmax = 146000, .val = 0xa2 }, - { .rfmax = 147000, .val = 0xa4 }, - { .rfmax = 148000, .val = 0xa9 }, - { .rfmax = 149000, .val = 0xae }, - { .rfmax = 150000, .val = 0xb0 }, - { .rfmax = 151000, .val = 0xb1 }, - { .rfmax = 152000, .val = 0xb7 }, - { .rfmax = 153000, .val = 0xbd }, - { .rfmax = 154000, .val = 0x20 }, - { .rfmax = 155000, .val = 0x22 }, - { .rfmax = 156000, .val = 0x24 }, - { .rfmax = 157000, .val = 0x25 }, - { .rfmax = 158000, .val = 0x27 }, - { .rfmax = 159000, .val = 0x29 }, - { .rfmax = 160000, .val = 0x2c }, - { .rfmax = 161000, .val = 0x2d }, - { .rfmax = 163000, .val = 0x2e }, - { .rfmax = 164000, .val = 0x2f }, - { .rfmax = 165000, .val = 0x30 }, - { .rfmax = 166000, .val = 0x11 }, - { .rfmax = 167000, .val = 0x12 }, - { .rfmax = 168000, .val = 0x13 }, - { .rfmax = 169000, .val = 0x14 }, - { .rfmax = 170000, .val = 0x15 }, - { .rfmax = 172000, .val = 0x16 }, - { .rfmax = 173000, .val = 0x17 }, - { .rfmax = 174000, .val = 0x18 }, - { .rfmax = 175000, .val = 0x1a }, - { .rfmax = 176000, .val = 0x1b }, - { .rfmax = 178000, .val = 0x1d }, - { .rfmax = 179000, .val = 0x1e }, - { .rfmax = 180000, .val = 0x1f }, - { .rfmax = 181000, .val = 0x20 }, - { .rfmax = 182000, .val = 0x21 }, - { .rfmax = 183000, .val = 0x22 }, - { .rfmax = 184000, .val = 0x24 }, - { .rfmax = 185000, .val = 0x25 }, - { .rfmax = 186000, .val = 0x26 }, - { .rfmax = 187000, .val = 0x27 }, - { .rfmax = 188000, .val = 0x29 }, - { .rfmax = 189000, .val = 0x2a }, - { .rfmax = 190000, .val = 0x2c }, - { .rfmax = 191000, .val = 0x2d }, - { .rfmax = 192000, .val = 0x2e }, - { .rfmax = 193000, .val = 0x2f }, - { .rfmax = 194000, .val = 0x30 }, - { .rfmax = 195000, .val = 0x33 }, - { .rfmax = 196000, .val = 0x35 }, - { .rfmax = 198000, .val = 0x36 }, - { .rfmax = 200000, .val = 0x38 }, - { .rfmax = 201000, .val = 0x3c }, - { .rfmax = 202000, .val = 0x3d }, - { .rfmax = 203500, .val = 0x3e }, - { .rfmax = 206000, .val = 0x0e }, - { .rfmax = 208000, .val = 0x0f }, - { .rfmax = 212000, .val = 0x10 }, - { .rfmax = 216000, .val = 0x11 }, - { .rfmax = 217000, .val = 0x12 }, - { .rfmax = 218000, .val = 0x13 }, - { .rfmax = 220000, .val = 0x14 }, - { .rfmax = 222000, .val = 0x15 }, - { .rfmax = 225000, .val = 0x16 }, - { .rfmax = 228000, .val = 0x17 }, - { .rfmax = 231000, .val = 0x18 }, - { .rfmax = 234000, .val = 0x19 }, - { .rfmax = 235000, .val = 0x1a }, - { .rfmax = 236000, .val = 0x1b }, - { .rfmax = 237000, .val = 0x1c }, - { .rfmax = 240000, .val = 0x1d }, - { .rfmax = 242000, .val = 0x1f }, - { .rfmax = 247000, .val = 0x20 }, - { .rfmax = 249000, .val = 0x21 }, - { .rfmax = 252000, .val = 0x22 }, - { .rfmax = 253000, .val = 0x23 }, - { .rfmax = 254000, .val = 0x24 }, - { .rfmax = 256000, .val = 0x25 }, - { .rfmax = 259000, .val = 0x26 }, - { .rfmax = 262000, .val = 0x27 }, - { .rfmax = 264000, .val = 0x28 }, - { .rfmax = 267000, .val = 0x29 }, - { .rfmax = 269000, .val = 0x2a }, - { .rfmax = 271000, .val = 0x2b }, - { .rfmax = 273000, .val = 0x2c }, - { .rfmax = 275000, .val = 0x2d }, - { .rfmax = 277000, .val = 0x2e }, - { .rfmax = 279000, .val = 0x2f }, - { .rfmax = 282000, .val = 0x30 }, - { .rfmax = 284000, .val = 0x31 }, - { .rfmax = 286000, .val = 0x32 }, - { .rfmax = 287000, .val = 0x33 }, - { .rfmax = 290000, .val = 0x34 }, - { .rfmax = 293000, .val = 0x35 }, - { .rfmax = 295000, .val = 0x36 }, - { .rfmax = 297000, .val = 0x37 }, - { .rfmax = 300000, .val = 0x38 }, - { .rfmax = 303000, .val = 0x39 }, - { .rfmax = 305000, .val = 0x3a }, - { .rfmax = 306000, .val = 0x3b }, - { .rfmax = 307000, .val = 0x3c }, - { .rfmax = 310000, .val = 0x3d }, - { .rfmax = 312000, .val = 0x3e }, - { .rfmax = 315000, .val = 0x3f }, - { .rfmax = 318000, .val = 0x40 }, - { .rfmax = 320000, .val = 0x41 }, - { .rfmax = 323000, .val = 0x42 }, - { .rfmax = 324000, .val = 0x43 }, - { .rfmax = 325000, .val = 0x44 }, - { .rfmax = 327000, .val = 0x45 }, - { .rfmax = 331000, .val = 0x46 }, - { .rfmax = 334000, .val = 0x47 }, - { .rfmax = 337000, .val = 0x48 }, - { .rfmax = 339000, .val = 0x49 }, - { .rfmax = 340000, .val = 0x4a }, - { .rfmax = 341000, .val = 0x4b }, - { .rfmax = 343000, .val = 0x4c }, - { .rfmax = 345000, .val = 0x4d }, - { .rfmax = 349000, .val = 0x4e }, - { .rfmax = 352000, .val = 0x4f }, - { .rfmax = 353000, .val = 0x50 }, - { .rfmax = 355000, .val = 0x51 }, - { .rfmax = 357000, .val = 0x52 }, - { .rfmax = 359000, .val = 0x53 }, - { .rfmax = 361000, .val = 0x54 }, - { .rfmax = 362000, .val = 0x55 }, - { .rfmax = 364000, .val = 0x56 }, - { .rfmax = 368000, .val = 0x57 }, - { .rfmax = 370000, .val = 0x58 }, - { .rfmax = 372000, .val = 0x59 }, - { .rfmax = 375000, .val = 0x5a }, - { .rfmax = 376000, .val = 0x5b }, - { .rfmax = 377000, .val = 0x5c }, - { .rfmax = 379000, .val = 0x5d }, - { .rfmax = 382000, .val = 0x5e }, - { .rfmax = 384000, .val = 0x5f }, - { .rfmax = 385000, .val = 0x60 }, - { .rfmax = 386000, .val = 0x61 }, - { .rfmax = 388000, .val = 0x62 }, - { .rfmax = 390000, .val = 0x63 }, - { .rfmax = 393000, .val = 0x64 }, - { .rfmax = 394000, .val = 0x65 }, - { .rfmax = 396000, .val = 0x66 }, - { .rfmax = 397000, .val = 0x67 }, - { .rfmax = 398000, .val = 0x68 }, - { .rfmax = 400000, .val = 0x69 }, - { .rfmax = 402000, .val = 0x6a }, - { .rfmax = 403000, .val = 0x6b }, - { .rfmax = 407000, .val = 0x6c }, - { .rfmax = 408000, .val = 0x6d }, - { .rfmax = 409000, .val = 0x6e }, - { .rfmax = 410000, .val = 0x6f }, - { .rfmax = 411000, .val = 0x70 }, - { .rfmax = 412000, .val = 0x71 }, - { .rfmax = 413000, .val = 0x72 }, - { .rfmax = 414000, .val = 0x73 }, - { .rfmax = 417000, .val = 0x74 }, - { .rfmax = 418000, .val = 0x75 }, - { .rfmax = 420000, .val = 0x76 }, - { .rfmax = 422000, .val = 0x77 }, - { .rfmax = 423000, .val = 0x78 }, - { .rfmax = 424000, .val = 0x79 }, - { .rfmax = 427000, .val = 0x7a }, - { .rfmax = 428000, .val = 0x7b }, - { .rfmax = 429000, .val = 0x7d }, - { .rfmax = 432000, .val = 0x7f }, - { .rfmax = 434000, .val = 0x80 }, - { .rfmax = 435000, .val = 0x81 }, - { .rfmax = 436000, .val = 0x83 }, - { .rfmax = 437000, .val = 0x84 }, - { .rfmax = 438000, .val = 0x85 }, - { .rfmax = 439000, .val = 0x86 }, - { .rfmax = 440000, .val = 0x87 }, - { .rfmax = 441000, .val = 0x88 }, - { .rfmax = 442000, .val = 0x89 }, - { .rfmax = 445000, .val = 0x8a }, - { .rfmax = 446000, .val = 0x8b }, - { .rfmax = 447000, .val = 0x8c }, - { .rfmax = 448000, .val = 0x8e }, - { .rfmax = 449000, .val = 0x8f }, - { .rfmax = 450000, .val = 0x90 }, - { .rfmax = 452000, .val = 0x91 }, - { .rfmax = 453000, .val = 0x93 }, - { .rfmax = 454000, .val = 0x94 }, - { .rfmax = 456000, .val = 0x96 }, - { .rfmax = 457000, .val = 0x98 }, - { .rfmax = 461000, .val = 0x11 }, - { .rfmax = 468000, .val = 0x12 }, - { .rfmax = 472000, .val = 0x13 }, - { .rfmax = 473000, .val = 0x14 }, - { .rfmax = 474000, .val = 0x15 }, - { .rfmax = 481000, .val = 0x16 }, - { .rfmax = 486000, .val = 0x17 }, - { .rfmax = 491000, .val = 0x18 }, - { .rfmax = 498000, .val = 0x19 }, - { .rfmax = 499000, .val = 0x1a }, - { .rfmax = 501000, .val = 0x1b }, - { .rfmax = 506000, .val = 0x1c }, - { .rfmax = 511000, .val = 0x1d }, - { .rfmax = 516000, .val = 0x1e }, - { .rfmax = 520000, .val = 0x1f }, - { .rfmax = 521000, .val = 0x20 }, - { .rfmax = 525000, .val = 0x21 }, - { .rfmax = 529000, .val = 0x22 }, - { .rfmax = 533000, .val = 0x23 }, - { .rfmax = 539000, .val = 0x24 }, - { .rfmax = 541000, .val = 0x25 }, - { .rfmax = 547000, .val = 0x26 }, - { .rfmax = 549000, .val = 0x27 }, - { .rfmax = 551000, .val = 0x28 }, - { .rfmax = 556000, .val = 0x29 }, - { .rfmax = 561000, .val = 0x2a }, - { .rfmax = 563000, .val = 0x2b }, - { .rfmax = 565000, .val = 0x2c }, - { .rfmax = 569000, .val = 0x2d }, - { .rfmax = 571000, .val = 0x2e }, - { .rfmax = 577000, .val = 0x2f }, - { .rfmax = 580000, .val = 0x30 }, - { .rfmax = 582000, .val = 0x31 }, - { .rfmax = 584000, .val = 0x32 }, - { .rfmax = 588000, .val = 0x33 }, - { .rfmax = 591000, .val = 0x34 }, - { .rfmax = 596000, .val = 0x35 }, - { .rfmax = 598000, .val = 0x36 }, - { .rfmax = 603000, .val = 0x37 }, - { .rfmax = 604000, .val = 0x38 }, - { .rfmax = 606000, .val = 0x39 }, - { .rfmax = 612000, .val = 0x3a }, - { .rfmax = 615000, .val = 0x3b }, - { .rfmax = 617000, .val = 0x3c }, - { .rfmax = 621000, .val = 0x3d }, - { .rfmax = 622000, .val = 0x3e }, - { .rfmax = 625000, .val = 0x3f }, - { .rfmax = 632000, .val = 0x40 }, - { .rfmax = 633000, .val = 0x41 }, - { .rfmax = 634000, .val = 0x42 }, - { .rfmax = 642000, .val = 0x43 }, - { .rfmax = 643000, .val = 0x44 }, - { .rfmax = 647000, .val = 0x45 }, - { .rfmax = 650000, .val = 0x46 }, - { .rfmax = 652000, .val = 0x47 }, - { .rfmax = 657000, .val = 0x48 }, - { .rfmax = 661000, .val = 0x49 }, - { .rfmax = 662000, .val = 0x4a }, - { .rfmax = 665000, .val = 0x4b }, - { .rfmax = 667000, .val = 0x4c }, - { .rfmax = 670000, .val = 0x4d }, - { .rfmax = 673000, .val = 0x4e }, - { .rfmax = 676000, .val = 0x4f }, - { .rfmax = 677000, .val = 0x50 }, - { .rfmax = 681000, .val = 0x51 }, - { .rfmax = 683000, .val = 0x52 }, - { .rfmax = 686000, .val = 0x53 }, - { .rfmax = 688000, .val = 0x54 }, - { .rfmax = 689000, .val = 0x55 }, - { .rfmax = 691000, .val = 0x56 }, - { .rfmax = 695000, .val = 0x57 }, - { .rfmax = 698000, .val = 0x58 }, - { .rfmax = 703000, .val = 0x59 }, - { .rfmax = 704000, .val = 0x5a }, - { .rfmax = 705000, .val = 0x5b }, - { .rfmax = 707000, .val = 0x5c }, - { .rfmax = 710000, .val = 0x5d }, - { .rfmax = 712000, .val = 0x5e }, - { .rfmax = 717000, .val = 0x5f }, - { .rfmax = 718000, .val = 0x60 }, - { .rfmax = 721000, .val = 0x61 }, - { .rfmax = 722000, .val = 0x62 }, - { .rfmax = 723000, .val = 0x63 }, - { .rfmax = 725000, .val = 0x64 }, - { .rfmax = 727000, .val = 0x65 }, - { .rfmax = 730000, .val = 0x66 }, - { .rfmax = 732000, .val = 0x67 }, - { .rfmax = 735000, .val = 0x68 }, - { .rfmax = 740000, .val = 0x69 }, - { .rfmax = 741000, .val = 0x6a }, - { .rfmax = 742000, .val = 0x6b }, - { .rfmax = 743000, .val = 0x6c }, - { .rfmax = 745000, .val = 0x6d }, - { .rfmax = 747000, .val = 0x6e }, - { .rfmax = 748000, .val = 0x6f }, - { .rfmax = 750000, .val = 0x70 }, - { .rfmax = 752000, .val = 0x71 }, - { .rfmax = 754000, .val = 0x72 }, - { .rfmax = 757000, .val = 0x73 }, - { .rfmax = 758000, .val = 0x74 }, - { .rfmax = 760000, .val = 0x75 }, - { .rfmax = 763000, .val = 0x76 }, - { .rfmax = 764000, .val = 0x77 }, - { .rfmax = 766000, .val = 0x78 }, - { .rfmax = 767000, .val = 0x79 }, - { .rfmax = 768000, .val = 0x7a }, - { .rfmax = 773000, .val = 0x7b }, - { .rfmax = 774000, .val = 0x7c }, - { .rfmax = 776000, .val = 0x7d }, - { .rfmax = 777000, .val = 0x7e }, - { .rfmax = 778000, .val = 0x7f }, - { .rfmax = 779000, .val = 0x80 }, - { .rfmax = 781000, .val = 0x81 }, - { .rfmax = 783000, .val = 0x82 }, - { .rfmax = 784000, .val = 0x83 }, - { .rfmax = 785000, .val = 0x84 }, - { .rfmax = 786000, .val = 0x85 }, - { .rfmax = 793000, .val = 0x86 }, - { .rfmax = 794000, .val = 0x87 }, - { .rfmax = 795000, .val = 0x88 }, - { .rfmax = 797000, .val = 0x89 }, - { .rfmax = 799000, .val = 0x8a }, - { .rfmax = 801000, .val = 0x8b }, - { .rfmax = 802000, .val = 0x8c }, - { .rfmax = 803000, .val = 0x8d }, - { .rfmax = 804000, .val = 0x8e }, - { .rfmax = 810000, .val = 0x90 }, - { .rfmax = 811000, .val = 0x91 }, - { .rfmax = 812000, .val = 0x92 }, - { .rfmax = 814000, .val = 0x93 }, - { .rfmax = 816000, .val = 0x94 }, - { .rfmax = 817000, .val = 0x96 }, - { .rfmax = 818000, .val = 0x97 }, - { .rfmax = 820000, .val = 0x98 }, - { .rfmax = 821000, .val = 0x99 }, - { .rfmax = 822000, .val = 0x9a }, - { .rfmax = 828000, .val = 0x9b }, - { .rfmax = 829000, .val = 0x9d }, - { .rfmax = 830000, .val = 0x9f }, - { .rfmax = 831000, .val = 0xa0 }, - { .rfmax = 833000, .val = 0xa1 }, - { .rfmax = 835000, .val = 0xa2 }, - { .rfmax = 836000, .val = 0xa3 }, - { .rfmax = 837000, .val = 0xa4 }, - { .rfmax = 838000, .val = 0xa6 }, - { .rfmax = 840000, .val = 0xa8 }, - { .rfmax = 842000, .val = 0xa9 }, - { .rfmax = 845000, .val = 0xaa }, - { .rfmax = 846000, .val = 0xab }, - { .rfmax = 847000, .val = 0xad }, - { .rfmax = 848000, .val = 0xae }, - { .rfmax = 852000, .val = 0xaf }, - { .rfmax = 853000, .val = 0xb0 }, - { .rfmax = 858000, .val = 0xb1 }, - { .rfmax = 860000, .val = 0xb2 }, - { .rfmax = 861000, .val = 0xb3 }, - { .rfmax = 862000, .val = 0xb4 }, - { .rfmax = 863000, .val = 0xb6 }, - { .rfmax = 864000, .val = 0xb8 }, - { .rfmax = 865000, .val = 0xb9 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_ir_measure[] = { - { .rfmax = 30000, .val = 4 }, - { .rfmax = 200000, .val = 5 }, - { .rfmax = 600000, .val = 6 }, - { .rfmax = 865000, .val = 7 }, - { .rfmax = 0, .val = 0 }, /* end */ -}; - -static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = { - { .rfmax = 47900, .val = 0x00 }, - { .rfmax = 55000, .val = 0x00 }, - { .rfmax = 61100, .val = 0x0a }, - { .rfmax = 64000, .val = 0x0a }, - { .rfmax = 82000, .val = 0x14 }, - { .rfmax = 84000, .val = 0x19 }, - { .rfmax = 119000, .val = 0x1c }, - { .rfmax = 124000, .val = 0x20 }, - { .rfmax = 129000, .val = 0x2a }, - { .rfmax = 134000, .val = 0x32 }, - { .rfmax = 139000, .val = 0x39 }, - { .rfmax = 144000, .val = 0x3e }, - { .rfmax = 149000, .val = 0x3f }, - { .rfmax = 152600, .val = 0x40 }, - { .rfmax = 154000, .val = 0x40 }, - { .rfmax = 164700, .val = 0x41 }, - { .rfmax = 203500, .val = 0x32 }, - { .rfmax = 353000, .val = 0x19 }, - { .rfmax = 356000, .val = 0x1a }, - { .rfmax = 359000, .val = 0x1b }, - { .rfmax = 363000, .val = 0x1c }, - { .rfmax = 366000, .val = 0x1d }, - { .rfmax = 369000, .val = 0x1e }, - { .rfmax = 373000, .val = 0x1f }, - { .rfmax = 376000, .val = 0x20 }, - { .rfmax = 379000, .val = 0x21 }, - { .rfmax = 383000, .val = 0x22 }, - { .rfmax = 386000, .val = 0x23 }, - { .rfmax = 389000, .val = 0x24 }, - { .rfmax = 393000, .val = 0x25 }, - { .rfmax = 396000, .val = 0x26 }, - { .rfmax = 399000, .val = 0x27 }, - { .rfmax = 402000, .val = 0x28 }, - { .rfmax = 404000, .val = 0x29 }, - { .rfmax = 407000, .val = 0x2a }, - { .rfmax = 409000, .val = 0x2b }, - { .rfmax = 412000, .val = 0x2c }, - { .rfmax = 414000, .val = 0x2d }, - { .rfmax = 417000, .val = 0x2e }, - { .rfmax = 419000, .val = 0x2f }, - { .rfmax = 422000, .val = 0x30 }, - { .rfmax = 424000, .val = 0x31 }, - { .rfmax = 427000, .val = 0x32 }, - { .rfmax = 429000, .val = 0x33 }, - { .rfmax = 432000, .val = 0x34 }, - { .rfmax = 434000, .val = 0x35 }, - { .rfmax = 437000, .val = 0x36 }, - { .rfmax = 439000, .val = 0x37 }, - { .rfmax = 442000, .val = 0x38 }, - { .rfmax = 444000, .val = 0x39 }, - { .rfmax = 447000, .val = 0x3a }, - { .rfmax = 449000, .val = 0x3b }, - { .rfmax = 457800, .val = 0x3c }, - { .rfmax = 465000, .val = 0x0f }, - { .rfmax = 477000, .val = 0x12 }, - { .rfmax = 483000, .val = 0x14 }, - { .rfmax = 502000, .val = 0x19 }, - { .rfmax = 508000, .val = 0x1b }, - { .rfmax = 519000, .val = 0x1c }, - { .rfmax = 522000, .val = 0x1d }, - { .rfmax = 524000, .val = 0x1e }, - { .rfmax = 534000, .val = 0x1f }, - { .rfmax = 549000, .val = 0x20 }, - { .rfmax = 554000, .val = 0x22 }, - { .rfmax = 584000, .val = 0x24 }, - { .rfmax = 589000, .val = 0x26 }, - { .rfmax = 658000, .val = 0x27 }, - { .rfmax = 664000, .val = 0x2c }, - { .rfmax = 669000, .val = 0x2d }, - { .rfmax = 699000, .val = 0x2e }, - { .rfmax = 704000, .val = 0x30 }, - { .rfmax = 709000, .val = 0x31 }, - { .rfmax = 714000, .val = 0x32 }, - { .rfmax = 724000, .val = 0x33 }, - { .rfmax = 729000, .val = 0x36 }, - { .rfmax = 739000, .val = 0x38 }, - { .rfmax = 744000, .val = 0x39 }, - { .rfmax = 749000, .val = 0x3b }, - { .rfmax = 754000, .val = 0x3c }, - { .rfmax = 759000, .val = 0x3d }, - { .rfmax = 764000, .val = 0x3e }, - { .rfmax = 769000, .val = 0x3f }, - { .rfmax = 774000, .val = 0x40 }, - { .rfmax = 779000, .val = 0x41 }, - { .rfmax = 784000, .val = 0x43 }, - { .rfmax = 789000, .val = 0x46 }, - { .rfmax = 794000, .val = 0x48 }, - { .rfmax = 799000, .val = 0x4b }, - { .rfmax = 804000, .val = 0x4f }, - { .rfmax = 809000, .val = 0x54 }, - { .rfmax = 814000, .val = 0x59 }, - { .rfmax = 819000, .val = 0x5d }, - { .rfmax = 824000, .val = 0x61 }, - { .rfmax = 829000, .val = 0x68 }, - { .rfmax = 834000, .val = 0x6e }, - { .rfmax = 839000, .val = 0x75 }, - { .rfmax = 844000, .val = 0x7e }, - { .rfmax = 849000, .val = 0x82 }, - { .rfmax = 854000, .val = 0x84 }, - { .rfmax = 859000, .val = 0x8f }, - { .rfmax = 865000, .val = 0x9a }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -/*---------------------------------------------------------------------*/ - -struct tda18271_thermo_map { - u8 d; - u8 r0; - u8 r1; -}; - -static struct tda18271_thermo_map tda18271_thermometer[] = { - { .d = 0x00, .r0 = 60, .r1 = 92 }, - { .d = 0x01, .r0 = 62, .r1 = 94 }, - { .d = 0x02, .r0 = 66, .r1 = 98 }, - { .d = 0x03, .r0 = 64, .r1 = 96 }, - { .d = 0x04, .r0 = 74, .r1 = 106 }, - { .d = 0x05, .r0 = 72, .r1 = 104 }, - { .d = 0x06, .r0 = 68, .r1 = 100 }, - { .d = 0x07, .r0 = 70, .r1 = 102 }, - { .d = 0x08, .r0 = 90, .r1 = 122 }, - { .d = 0x09, .r0 = 88, .r1 = 120 }, - { .d = 0x0a, .r0 = 84, .r1 = 116 }, - { .d = 0x0b, .r0 = 86, .r1 = 118 }, - { .d = 0x0c, .r0 = 76, .r1 = 108 }, - { .d = 0x0d, .r0 = 78, .r1 = 110 }, - { .d = 0x0e, .r0 = 82, .r1 = 114 }, - { .d = 0x0f, .r0 = 80, .r1 = 112 }, - { .d = 0x00, .r0 = 0, .r1 = 0 }, /* end */ -}; - -int tda18271_lookup_thermometer(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int val, i = 0; - - while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) { - if (tda18271_thermometer[i + 1].d == 0) - break; - i++; - } - - if ((regs[R_TM] & 0x20) == 0x20) - val = tda18271_thermometer[i].r1; - else - val = tda18271_thermometer[i].r0; - - tda_map("(%d) tm = %d\n", i, val); - - return val; -} - -/*---------------------------------------------------------------------*/ - -struct tda18271_cid_target_map { - u32 rfmax; - u8 target; - u16 limit; -}; - -static struct tda18271_cid_target_map tda18271_cid_target[] = { - { .rfmax = 46000, .target = 0x04, .limit = 1800 }, - { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, - { .rfmax = 70100, .target = 0x01, .limit = 4000 }, - { .rfmax = 136800, .target = 0x18, .limit = 4000 }, - { .rfmax = 156700, .target = 0x18, .limit = 4000 }, - { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, - { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, - { .rfmax = 345000, .target = 0x18, .limit = 4000 }, - { .rfmax = 426000, .target = 0x0e, .limit = 4000 }, - { .rfmax = 489500, .target = 0x1e, .limit = 4000 }, - { .rfmax = 697500, .target = 0x32, .limit = 4000 }, - { .rfmax = 842000, .target = 0x3a, .limit = 4000 }, - { .rfmax = 0, .target = 0x00, .limit = 0 }, /* end */ -}; - -int tda18271_lookup_cid_target(struct dvb_frontend *fe, - u32 *freq, u8 *cid_target, u16 *count_limit) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int i = 0; - - while ((tda18271_cid_target[i].rfmax * 1000) < *freq) { - if (tda18271_cid_target[i + 1].rfmax == 0) - break; - i++; - } - *cid_target = tda18271_cid_target[i].target; - *count_limit = tda18271_cid_target[i].limit; - - tda_map("(%d) cid_target = %02x, count_limit = %d\n", i, - tda18271_cid_target[i].target, tda18271_cid_target[i].limit); - - return 0; -} - -/*---------------------------------------------------------------------*/ - -static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = { - { .rfmax = 47900, .rfband = 0x00, - .rf1_def = 46000, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 61100, .rfband = 0x01, - .rf1_def = 52200, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 152600, .rfband = 0x02, - .rf1_def = 70100, .rf2_def = 136800, .rf3_def = 0 }, - { .rfmax = 164700, .rfband = 0x03, - .rf1_def = 156700, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 203500, .rfband = 0x04, - .rf1_def = 186250, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 457800, .rfband = 0x05, - .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 }, - { .rfmax = 865000, .rfband = 0x06, - .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 }, - { .rfmax = 0, .rfband = 0x00, - .rf1_def = 0, .rf2_def = 0, .rf3_def = 0 }, /* end */ -}; - -int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; - int i = 0; - - while ((map[i].rfmax * 1000) < *freq) { - if (tda18271_debug & DBG_ADV) - tda_map("(%d) rfmax = %d < freq = %d, " - "rf1_def = %d, rf2_def = %d, rf3_def = %d, " - "rf1 = %d, rf2 = %d, rf3 = %d, " - "rf_a1 = %d, rf_a2 = %d, " - "rf_b1 = %d, rf_b2 = %d\n", - i, map[i].rfmax * 1000, *freq, - map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, - map[i].rf1, map[i].rf2, map[i].rf3, - map[i].rf_a1, map[i].rf_a2, - map[i].rf_b1, map[i].rf_b2); - if (map[i].rfmax == 0) - return -EINVAL; - i++; - } - if (rf_band) - *rf_band = map[i].rfband; - - tda_map("(%d) rf_band = %02x\n", i, map[i].rfband); - - return i; -} - -/*---------------------------------------------------------------------*/ - -struct tda18271_map_layout { - struct tda18271_pll_map *main_pll; - struct tda18271_pll_map *cal_pll; - - struct tda18271_map *rf_cal; - struct tda18271_map *rf_cal_kmco; - struct tda18271_map *rf_cal_dc_over_dt; - - struct tda18271_map *bp_filter; - struct tda18271_map *rf_band; - struct tda18271_map *gain_taper; - struct tda18271_map *ir_measure; -}; - -/*---------------------------------------------------------------------*/ - -int tda18271_lookup_pll_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *post_div, u8 *div) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_pll_map *map = NULL; - unsigned int i = 0; - char *map_name; - int ret = 0; - - BUG_ON(!priv->maps); - - switch (map_type) { - case MAIN_PLL: - map = priv->maps->main_pll; - map_name = "main_pll"; - break; - case CAL_PLL: - map = priv->maps->cal_pll; - map_name = "cal_pll"; - break; - default: - /* we should never get here */ - map_name = "undefined"; - break; - } - - if (!map) { - tda_warn("%s map is not set!\n", map_name); - ret = -EINVAL; - goto fail; - } - - while ((map[i].lomax * 1000) < *freq) { - if (map[i + 1].lomax == 0) { - tda_map("%s: frequency (%d) out of range\n", - map_name, *freq); - ret = -ERANGE; - break; - } - i++; - } - *post_div = map[i].pd; - *div = map[i].d; - - tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n", - i, map_name, *post_div, *div); -fail: - return ret; -} - -int tda18271_lookup_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *val) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_map *map = NULL; - unsigned int i = 0; - char *map_name; - int ret = 0; - - BUG_ON(!priv->maps); - - switch (map_type) { - case BP_FILTER: - map = priv->maps->bp_filter; - map_name = "bp_filter"; - break; - case RF_CAL_KMCO: - map = priv->maps->rf_cal_kmco; - map_name = "km"; - break; - case RF_BAND: - map = priv->maps->rf_band; - map_name = "rf_band"; - break; - case GAIN_TAPER: - map = priv->maps->gain_taper; - map_name = "gain_taper"; - break; - case RF_CAL: - map = priv->maps->rf_cal; - map_name = "rf_cal"; - break; - case IR_MEASURE: - map = priv->maps->ir_measure; - map_name = "ir_measure"; - break; - case RF_CAL_DC_OVER_DT: - map = priv->maps->rf_cal_dc_over_dt; - map_name = "rf_cal_dc_over_dt"; - break; - default: - /* we should never get here */ - map_name = "undefined"; - break; - } - - if (!map) { - tda_warn("%s map is not set!\n", map_name); - ret = -EINVAL; - goto fail; - } - - while ((map[i].rfmax * 1000) < *freq) { - if (map[i + 1].rfmax == 0) { - tda_map("%s: frequency (%d) out of range\n", - map_name, *freq); - ret = -ERANGE; - break; - } - i++; - } - *val = map[i].val; - - tda_map("(%d) %s: 0x%02x\n", i, map_name, *val); -fail: - return ret; -} - -/*---------------------------------------------------------------------*/ - -static struct tda18271_std_map tda18271c1_std_map = { - .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ - .atv_b = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_dk = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_gh = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_i = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_l = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ - .atv_mn = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ - .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_7 = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ - .dvbt_8 = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ - .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ - .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ -}; - -static struct tda18271_std_map tda18271c2_std_map = { - .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ - .atv_b = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ - .atv_dk = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_gh = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_i = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_l = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ - .atv_mn = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4, - .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */ - .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_7 = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ - .dvbt_8 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ - .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ - .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, - .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ -}; - -/*---------------------------------------------------------------------*/ - -static struct tda18271_map_layout tda18271c1_map_layout = { - .main_pll = tda18271c1_main_pll, - .cal_pll = tda18271c1_cal_pll, - - .rf_cal = tda18271c1_rf_cal, - .rf_cal_kmco = tda18271c1_km, - - .bp_filter = tda18271_bp_filter, - .rf_band = tda18271_rf_band, - .gain_taper = tda18271_gain_taper, - .ir_measure = tda18271_ir_measure, -}; - -static struct tda18271_map_layout tda18271c2_map_layout = { - .main_pll = tda18271c2_main_pll, - .cal_pll = tda18271c2_cal_pll, - - .rf_cal = tda18271c2_rf_cal, - .rf_cal_kmco = tda18271c2_km, - - .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt, - - .bp_filter = tda18271_bp_filter, - .rf_band = tda18271_rf_band, - .gain_taper = tda18271_gain_taper, - .ir_measure = tda18271_ir_measure, -}; - -int tda18271_assign_map_layout(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret = 0; - - switch (priv->id) { - case TDA18271HDC1: - priv->maps = &tda18271c1_map_layout; - memcpy(&priv->std, &tda18271c1_std_map, - sizeof(struct tda18271_std_map)); - break; - case TDA18271HDC2: - priv->maps = &tda18271c2_map_layout; - memcpy(&priv->std, &tda18271c2_std_map, - sizeof(struct tda18271_std_map)); - break; - default: - ret = -EINVAL; - break; - } - memcpy(priv->rf_cal_state, &tda18271_rf_band_template, - sizeof(tda18271_rf_band_template)); - - return ret; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda18271-priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,237 +0,0 @@ -/* - tda18271-priv.h - private header for the NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TDA18271_PRIV_H__ -#define __TDA18271_PRIV_H__ - -#include -#include -#include -#include "tuner-i2c.h" -#include "tda18271.h" - -#define R_ID 0x00 /* ID byte */ -#define R_TM 0x01 /* Thermo byte */ -#define R_PL 0x02 /* Power level byte */ -#define R_EP1 0x03 /* Easy Prog byte 1 */ -#define R_EP2 0x04 /* Easy Prog byte 2 */ -#define R_EP3 0x05 /* Easy Prog byte 3 */ -#define R_EP4 0x06 /* Easy Prog byte 4 */ -#define R_EP5 0x07 /* Easy Prog byte 5 */ -#define R_CPD 0x08 /* Cal Post-Divider byte */ -#define R_CD1 0x09 /* Cal Divider byte 1 */ -#define R_CD2 0x0a /* Cal Divider byte 2 */ -#define R_CD3 0x0b /* Cal Divider byte 3 */ -#define R_MPD 0x0c /* Main Post-Divider byte */ -#define R_MD1 0x0d /* Main Divider byte 1 */ -#define R_MD2 0x0e /* Main Divider byte 2 */ -#define R_MD3 0x0f /* Main Divider byte 3 */ -#define R_EB1 0x10 /* Extended byte 1 */ -#define R_EB2 0x11 /* Extended byte 2 */ -#define R_EB3 0x12 /* Extended byte 3 */ -#define R_EB4 0x13 /* Extended byte 4 */ -#define R_EB5 0x14 /* Extended byte 5 */ -#define R_EB6 0x15 /* Extended byte 6 */ -#define R_EB7 0x16 /* Extended byte 7 */ -#define R_EB8 0x17 /* Extended byte 8 */ -#define R_EB9 0x18 /* Extended byte 9 */ -#define R_EB10 0x19 /* Extended byte 10 */ -#define R_EB11 0x1a /* Extended byte 11 */ -#define R_EB12 0x1b /* Extended byte 12 */ -#define R_EB13 0x1c /* Extended byte 13 */ -#define R_EB14 0x1d /* Extended byte 14 */ -#define R_EB15 0x1e /* Extended byte 15 */ -#define R_EB16 0x1f /* Extended byte 16 */ -#define R_EB17 0x20 /* Extended byte 17 */ -#define R_EB18 0x21 /* Extended byte 18 */ -#define R_EB19 0x22 /* Extended byte 19 */ -#define R_EB20 0x23 /* Extended byte 20 */ -#define R_EB21 0x24 /* Extended byte 21 */ -#define R_EB22 0x25 /* Extended byte 22 */ -#define R_EB23 0x26 /* Extended byte 23 */ - -#define TDA18271_NUM_REGS 39 - -/*---------------------------------------------------------------------*/ - -struct tda18271_rf_tracking_filter_cal { - u32 rfmax; - u8 rfband; - u32 rf1_def; - u32 rf2_def; - u32 rf3_def; - u32 rf1; - u32 rf2; - u32 rf3; - s32 rf_a1; - s32 rf_b1; - s32 rf_a2; - s32 rf_b2; -}; - -enum tda18271_pll { - TDA18271_MAIN_PLL, - TDA18271_CAL_PLL, -}; - -struct tda18271_map_layout; - -enum tda18271_ver { - TDA18271HDC1, - TDA18271HDC2, -}; - -struct tda18271_priv { - unsigned char tda18271_regs[TDA18271_NUM_REGS]; - - struct list_head hybrid_tuner_instance_list; - struct tuner_i2c_props i2c_props; - - enum tda18271_mode mode; - enum tda18271_role role; - enum tda18271_i2c_gate gate; - enum tda18271_ver id; - enum tda18271_output_options output_opt; - enum tda18271_small_i2c small_i2c; - - unsigned int config; /* interface to saa713x / tda829x */ - unsigned int cal_initialized:1; - - u8 tm_rfcal; - - struct tda18271_map_layout *maps; - struct tda18271_std_map std; - struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; - - struct mutex lock; - - u32 frequency; - u32 bandwidth; -}; - -/*---------------------------------------------------------------------*/ - -extern int tda18271_debug; - -#define DBG_INFO 1 -#define DBG_MAP 2 -#define DBG_REG 4 -#define DBG_ADV 8 -#define DBG_CAL 16 - -#define tda_printk(st, kern, fmt, arg...) do {\ - if (st) { \ - struct tda18271_priv *state = st; \ - printk(kern "%s: [%d-%04x|%s] " fmt, __func__, \ - i2c_adapter_id(state->i2c_props.adap), \ - state->i2c_props.addr, \ - (state->role == TDA18271_MASTER) \ - ? "M" : "S", ##arg); \ - } else \ - printk(kern "%s: " fmt, __func__, ##arg); \ -} while (0) - -#define tda_dprintk(st, lvl, fmt, arg...) do {\ - if (tda18271_debug & lvl) \ - tda_printk(st, KERN_DEBUG, fmt, ##arg); } while (0) - -#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) -#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg) -#define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg) -#define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg) -#define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg) -#define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg) -#define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg) - -#define tda_fail(ret) \ -({ \ - int __ret; \ - __ret = (ret < 0); \ - if (__ret) \ - tda_printk(priv, KERN_ERR, \ - "error %d on line %d\n", ret, __LINE__); \ - __ret; \ -}) - -/*---------------------------------------------------------------------*/ - -enum tda18271_map_type { - /* tda18271_pll_map */ - MAIN_PLL, - CAL_PLL, - /* tda18271_map */ - RF_CAL, - RF_CAL_KMCO, - RF_CAL_DC_OVER_DT, - BP_FILTER, - RF_BAND, - GAIN_TAPER, - IR_MEASURE, -}; - -extern int tda18271_lookup_pll_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *post_div, u8 *div); -extern int tda18271_lookup_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *val); - -extern int tda18271_lookup_thermometer(struct dvb_frontend *fe); - -extern int tda18271_lookup_rf_band(struct dvb_frontend *fe, - u32 *freq, u8 *rf_band); - -extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, - u32 *freq, u8 *cid_target, - u16 *count_limit); - -extern int tda18271_assign_map_layout(struct dvb_frontend *fe); - -/*---------------------------------------------------------------------*/ - -extern int tda18271_read_regs(struct dvb_frontend *fe); -extern int tda18271_read_extended(struct dvb_frontend *fe); -extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); -extern int tda18271_init_regs(struct dvb_frontend *fe); - -extern int tda18271_charge_pump_source(struct dvb_frontend *fe, - enum tda18271_pll pll, int force); -extern int tda18271_set_standby_mode(struct dvb_frontend *fe, - int sm, int sm_lt, int sm_xt); - -extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); -extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); - -extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); - -#endif /* __TDA18271_PRIV_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda827x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda827x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda827x.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda827x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,913 +0,0 @@ -/* - * - * (c) 2005 Hartmut Hackmann - * (c) 2007 Michael Krufky - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "tda827x.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "tda827x: " args); \ - } while (0) - -struct tda827x_priv { - int i2c_addr; - struct i2c_adapter *i2c_adap; - struct tda827x_config *cfg; - - unsigned int sgIF; - unsigned char lpsel; - - u32 frequency; - u32 bandwidth; -}; - -static void tda827x_set_std(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - char *mode; - - priv->lpsel = 0; - if (params->std & V4L2_STD_MN) { - priv->sgIF = 92; - priv->lpsel = 1; - mode = "MN"; - } else if (params->std & V4L2_STD_B) { - priv->sgIF = 108; - mode = "B"; - } else if (params->std & V4L2_STD_GH) { - priv->sgIF = 124; - mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - priv->sgIF = 124; - mode = "I"; - } else if (params->std & V4L2_STD_DK) { - priv->sgIF = 124; - mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - priv->sgIF = 124; - mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - priv->sgIF = 20; - mode = "LC"; - } else { - priv->sgIF = 124; - mode = "xx"; - } - - if (params->mode == V4L2_TUNER_RADIO) { - priv->sgIF = 88; /* if frequency is 5.5 MHz */ - dprintk("setting tda827x to radio FM\n"); - } else - dprintk("setting tda827x to system %s\n", mode); -} - - -/* ------------------------------------------------------------------ */ - -struct tda827x_data { - u32 lomax; - u8 spd; - u8 bs; - u8 bp; - u8 cp; - u8 gc3; - u8 div1p5; -}; - -static const struct tda827x_data tda827x_table[] = { - { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, - { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, - { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, - { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, - { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, - { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, - { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, - { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, - { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, - { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} -}; - -static int tuner_transfer(struct dvb_frontend *fe, - struct i2c_msg *msg, - const int size) -{ - int rc; - struct tda827x_priv *priv = fe->tuner_priv; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - rc = i2c_transfer(priv->i2c_adap, msg, size); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (rc >= 0 && rc != size) - return -EIO; - - return rc; -} - -static int tda827xo_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - u8 buf[14]; - int rc; - - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - int i, tuner_freq, if_freq; - u32 N; - - dprintk("%s:\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - if_freq = 4000000; - break; - case BANDWIDTH_7_MHZ: - if_freq = 4500000; - break; - default: /* 8 MHz or Auto */ - if_freq = 5000000; - break; - } - tuner_freq = params->frequency + if_freq; - - i = 0; - while (tda827x_table[i].lomax < tuner_freq) { - if (tda827x_table[i + 1].lomax == 0) - break; - i++; - } - - N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); - buf[0] = 0; - buf[1] = (N>>8) | 0x40; - buf[2] = N & 0xff; - buf[3] = 0; - buf[4] = 0x52; - buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + - (tda827x_table[i].bs << 3) + - tda827x_table[i].bp; - buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; - buf[7] = 0xbf; - buf[8] = 0x2a; - buf[9] = 0x05; - buf[10] = 0xff; - buf[11] = 0x00; - buf[12] = 0x00; - buf[13] = 0x40; - - msg.len = 14; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - msleep(500); - /* correct CP value */ - buf[0] = 0x30; - buf[1] = 0x50 + tda827x_table[i].cp; - msg.len = 2; - - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - priv->frequency = params->frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - - return 0; - -err: - printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", - __func__, priv->i2c_addr << 1); - return rc; -} - -static int tda827xo_sleep(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - static u8 buf[] = { 0x30, 0xd0 }; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - dprintk("%s:\n", __func__); - tuner_transfer(fe, &msg, 1); - - if (priv->cfg && priv->cfg->sleep) - priv->cfg->sleep(fe); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int tda827xo_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[8]; - unsigned char reg2[2]; - u32 N; - int i; - struct tda827x_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; - unsigned int freq = params->frequency; - - tda827x_set_std(fe, params); - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - - i = 0; - while (tda827x_table[i].lomax < N * 62500) { - if (tda827x_table[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827x_table[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0x40; - tuner_reg[4] = 0x52 + (priv->lpsel << 5); - tuner_reg[5] = (tda827x_table[i].spd << 6) + - (tda827x_table[i].div1p5 << 5) + - (tda827x_table[i].bs << 3) + tda827x_table[i].bp; - tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); - tuner_reg[7] = 0x8f; - - msg.buf = tuner_reg; - msg.len = 8; - tuner_transfer(fe, &msg, 1); - - msg.buf = reg2; - msg.len = 2; - reg2[0] = 0x80; - reg2[1] = 0; - tuner_transfer(fe, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0xbf; - tuner_transfer(fe, &msg, 1); - - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 0x80; - tuner_transfer(fe, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 4; - tuner_transfer(fe, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4]; - tuner_transfer(fe, &msg, 1); - - msleep(550); - reg2[0] = 0x30; - reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; - tuner_transfer(fe, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0x3f; - tuner_transfer(fe, &msg, 1); - - reg2[0] = 0x80; - reg2[1] = 0x08; /* Vsync en */ - tuner_transfer(fe, &msg, 1); - - priv->frequency = params->frequency; - - return 0; -} - -static void tda827xo_agcf(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - unsigned char data[] = { 0x80, 0x0c }; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = data, .len = 2}; - - tuner_transfer(fe, &msg, 1); -} - -/* ------------------------------------------------------------------ */ - -struct tda827xa_data { - u32 lomax; - u8 svco; - u8 spd; - u8 scr; - u8 sbs; - u8 gc3; -}; - -static struct tda827xa_data tda827xa_dvbt[] = { - { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, - { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, - { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} -}; - -static struct tda827xa_data tda827xa_dvbc[] = { - { .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, - { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, - { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1}, - { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3}, - { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3}, - { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1}, - { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, - { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, - { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1}, - { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, - { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1}, - { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, - { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, - { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, - { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, - { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, - { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, - { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} -}; - -static struct tda827xa_data tda827xa_analog[] = { - { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, - { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, - { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, - { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, - { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, - { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} -}; - -static int tda827xa_sleep(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - static u8 buf[] = { 0x30, 0x90 }; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - dprintk("%s:\n", __func__); - - tuner_transfer(fe, &msg, 1); - - if (priv->cfg && priv->cfg->sleep) - priv->cfg->sleep(fe); - - return 0; -} - -static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, - struct analog_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - unsigned char buf[] = {0x22, 0x01}; - int arg; - int gp_func; - struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) }; - - if (NULL == priv->cfg) { - dprintk("tda827x_config not defined, cannot set LNA gain!\n"); - return; - } - msg.addr = priv->cfg->switch_addr; - if (priv->cfg->config) { - if (high) - dprintk("setting LNA to high gain\n"); - else - dprintk("setting LNA to low gain\n"); - } - switch (priv->cfg->config) { - case 0: /* no LNA */ - break; - case 1: /* switch is GPIO 0 of tda8290 */ - case 2: - if (params == NULL) { - gp_func = 0; - arg = 0; - } else { - /* turn Vsync on */ - gp_func = 1; - if (params->std & V4L2_STD_MN) - arg = 1; - else - arg = 0; - } - if (fe->callback) - fe->callback(priv->i2c_adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, - gp_func, arg); - buf[1] = high ? 0 : 1; - if (priv->cfg->config == 2) - buf[1] = high ? 1 : 0; - tuner_transfer(fe, &msg, 1); - break; - case 3: /* switch with GPIO of saa713x */ - if (fe->callback) - fe->callback(priv->i2c_adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, 0, high); - break; - } -} - -static int tda827xa_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - struct tda827xa_data *frequency_map = tda827xa_dvbt; - u8 buf[11]; - - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - int i, tuner_freq, if_freq, rc; - u32 N; - - dprintk("%s:\n", __func__); - - tda827xa_lna_gain(fe, 1, NULL); - msleep(20); - - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - if_freq = 4000000; - break; - case BANDWIDTH_7_MHZ: - if_freq = 4500000; - break; - default: /* 8 MHz or Auto */ - if_freq = 5000000; - break; - } - tuner_freq = params->frequency + if_freq; - - if (fe->ops.info.type == FE_QAM) { - dprintk("%s select tda827xa_dvbc\n", __func__); - frequency_map = tda827xa_dvbc; - } - - i = 0; - while (frequency_map[i].lomax < tuner_freq) { - if (frequency_map[i + 1].lomax == 0) - break; - i++; - } - - N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd; - buf[0] = 0; // subaddress - buf[1] = N >> 8; - buf[2] = N & 0xff; - buf[3] = 0; - buf[4] = 0x16; - buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) + - frequency_map[i].sbs; - buf[6] = 0x4b + (frequency_map[i].gc3 << 4); - buf[7] = 0x1c; - buf[8] = 0x06; - buf[9] = 0x24; - buf[10] = 0x00; - msg.len = 11; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - buf[0] = 0x90; - buf[1] = 0xff; - buf[2] = 0x60; - buf[3] = 0x00; - buf[4] = 0x59; // lpsel, for 6MHz + 2 - msg.len = 5; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - buf[0] = 0xa0; - buf[1] = 0x40; - msg.len = 2; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - msleep(11); - msg.flags = I2C_M_RD; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - msg.flags = 0; - - buf[1] >>= 4; - dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); - if ((buf[1]) < 2) { - tda827xa_lna_gain(fe, 0, NULL); - buf[0] = 0x60; - buf[1] = 0x0c; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - } - - buf[0] = 0xc0; - buf[1] = 0x99; // lpsel, for 6MHz + 2 - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - buf[0] = 0x60; - buf[1] = 0x3c; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - /* correct CP value */ - buf[0] = 0x30; - buf[1] = 0x10 + frequency_map[i].scr; - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - msleep(163); - buf[0] = 0xc0; - buf[1] = 0x39; // lpsel, for 6MHz + 2 - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - msleep(3); - /* freeze AGC1 */ - buf[0] = 0x50; - buf[1] = 0x4f + (frequency_map[i].gc3 << 4); - rc = tuner_transfer(fe, &msg, 1); - if (rc < 0) - goto err; - - priv->frequency = params->frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - - - return 0; - -err: - printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", - __func__, priv->i2c_addr << 1); - return rc; -} - - -static int tda827xa_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[11]; - u32 N; - int i; - struct tda827x_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = tuner_reg, .len = sizeof(tuner_reg) }; - unsigned int freq = params->frequency; - - tda827x_set_std(fe, params); - - tda827xa_lna_gain(fe, 1, params); - msleep(10); - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - - i = 0; - while (tda827xa_analog[i].lomax < N * 62500) { - if (tda827xa_analog[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827xa_analog[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0; - tuner_reg[4] = 0x16; - tuner_reg[5] = (tda827xa_analog[i].spd << 5) + - (tda827xa_analog[i].svco << 3) + - tda827xa_analog[i].sbs; - tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); - tuner_reg[7] = 0x1c; - tuner_reg[8] = 4; - tuner_reg[9] = 0x20; - tuner_reg[10] = 0x00; - msg.len = 11; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0x90; - tuner_reg[1] = 0xff; - tuner_reg[2] = 0xe0; - tuner_reg[3] = 0; - tuner_reg[4] = 0x99 + (priv->lpsel << 1); - msg.len = 5; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0xa0; - tuner_reg[1] = 0xc0; - msg.len = 2; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0x30; - tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; - tuner_transfer(fe, &msg, 1); - - msg.flags = I2C_M_RD; - tuner_transfer(fe, &msg, 1); - msg.flags = 0; - tuner_reg[1] >>= 4; - dprintk("AGC2 gain is: %d\n", tuner_reg[1]); - if (tuner_reg[1] < 1) - tda827xa_lna_gain(fe, 0, params); - - msleep(100); - tuner_reg[0] = 0x60; - tuner_reg[1] = 0x3c; - tuner_transfer(fe, &msg, 1); - - msleep(163); - tuner_reg[0] = 0x50; - tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0x80; - tuner_reg[1] = 0x28; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0xb0; - tuner_reg[1] = 0x01; - tuner_transfer(fe, &msg, 1); - - tuner_reg[0] = 0xc0; - tuner_reg[1] = 0x19 + (priv->lpsel << 1); - tuner_transfer(fe, &msg, 1); - - priv->frequency = params->frequency; - - return 0; -} - -static void tda827xa_agcf(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - unsigned char data[] = {0x80, 0x2c}; - struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, - .buf = data, .len = 2}; - tuner_transfer(fe, &msg, 1); -} - -/* ------------------------------------------------------------------ */ - -static int tda827x_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda827x_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct tda827x_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static int tda827x_init(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - dprintk("%s:\n", __func__); - if (priv->cfg && priv->cfg->init) - priv->cfg->init(fe); - - return 0; -} - -static int tda827x_probe_version(struct dvb_frontend *fe); - -static int tda827x_initial_init(struct dvb_frontend *fe) -{ - int ret; - ret = tda827x_probe_version(fe); - if (ret) - return ret; - return fe->ops.tuner_ops.init(fe); -} - -static int tda827x_initial_sleep(struct dvb_frontend *fe) -{ - int ret; - ret = tda827x_probe_version(fe); - if (ret) - return ret; - return fe->ops.tuner_ops.sleep(fe); -} - -static struct dvb_tuner_ops tda827xo_tuner_ops = { - .info = { - .name = "Philips TDA827X", - .frequency_min = 55000000, - .frequency_max = 860000000, - .frequency_step = 250000 - }, - .release = tda827x_release, - .init = tda827x_initial_init, - .sleep = tda827x_initial_sleep, - .set_params = tda827xo_set_params, - .set_analog_params = tda827xo_set_analog_params, - .get_frequency = tda827x_get_frequency, - .get_bandwidth = tda827x_get_bandwidth, -}; - -static struct dvb_tuner_ops tda827xa_tuner_ops = { - .info = { - .name = "Philips TDA827XA", - .frequency_min = 44000000, - .frequency_max = 906000000, - .frequency_step = 62500 - }, - .release = tda827x_release, - .init = tda827x_init, - .sleep = tda827xa_sleep, - .set_params = tda827xa_set_params, - .set_analog_params = tda827xa_set_analog_params, - .get_frequency = tda827x_get_frequency, - .get_bandwidth = tda827x_get_bandwidth, -}; - -static int tda827x_probe_version(struct dvb_frontend *fe) -{ - u8 data; - int rc; - struct tda827x_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, - .buf = &data, .len = 1 }; - - rc = tuner_transfer(fe, &msg, 1); - - if (rc < 0) { - printk("%s: could not read from tuner at addr: 0x%02x\n", - __func__, msg.addr << 1); - return rc; - } - if ((data & 0x3c) == 0) { - dprintk("tda827x tuner found\n"); - fe->ops.tuner_ops.init = tda827x_init; - fe->ops.tuner_ops.sleep = tda827xo_sleep; - if (priv->cfg) - priv->cfg->agcf = tda827xo_agcf; - } else { - dprintk("tda827xa tuner found\n"); - memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); - if (priv->cfg) - priv->cfg->agcf = tda827xa_agcf; - } - return 0; -} - -struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, - struct i2c_adapter *i2c, - struct tda827x_config *cfg) -{ - struct tda827x_priv *priv = NULL; - - dprintk("%s:\n", __func__); - priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c_addr = addr; - priv->i2c_adap = i2c; - priv->cfg = cfg; - memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - - dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); - - return fe; -} -EXPORT_SYMBOL_GPL(tda827x_attach); - -MODULE_DESCRIPTION("DVB TDA827x driver"); -MODULE_AUTHOR("Hartmut Hackmann "); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda827x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda827x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda827x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda827x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ - /* - DVB Driver for Philips tda827x / tda827xa Silicon tuners - - (c) 2005 Hartmut Hackmann - (c) 2007 Michael Krufky - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef __DVB_TDA827X_H__ -#define __DVB_TDA827X_H__ - -#include -#include "dvb_frontend.h" - -struct tda827x_config -{ - /* saa7134 - provided callbacks */ - int (*init) (struct dvb_frontend *fe); - int (*sleep) (struct dvb_frontend *fe); - - /* interface to tda829x driver */ - unsigned int config; - int switch_addr; - - void (*agcf)(struct dvb_frontend *fe); -}; - - -/** - * Attach a tda827x tuner to the supplied frontend structure. - * - * @param fe Frontend to attach to. - * @param addr i2c address of the tuner. - * @param i2c i2c adapter to use. - * @param cfg optional callback function pointers. - * @return FE pointer on success, NULL on failure. - */ -#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, - struct i2c_adapter *i2c, - struct tda827x_config *cfg); -#else -static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, - int addr, - struct i2c_adapter *i2c, - struct tda827x_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_MEDIA_TUNER_TDA827X - -#endif // __DVB_TDA827X_H__ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda8290.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda8290.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda8290.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda8290.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,874 +0,0 @@ -/* - - i2c tv tuner chip device driver - controls the philips tda8290+75 tuner chip combo. - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - This "tda8290" module was split apart from the original "tuner" module. -*/ - -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tda8290.h" -#include "tda827x.h" -#include "tda18271.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static int deemphasis_50; -module_param(deemphasis_50, int, 0644); -MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis"); - -/* ---------------------------------------------------------------------- */ - -struct tda8290_priv { - struct tuner_i2c_props i2c_props; - - unsigned char tda8290_easy_mode; - - unsigned char tda827x_addr; - - unsigned char ver; -#define TDA8290 1 -#define TDA8295 2 -#define TDA8275 4 -#define TDA8275A 8 -#define TDA18271 16 - - struct tda827x_config cfg; -}; - -/*---------------------------------------------------------------------*/ - -static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char enable[2] = { 0x21, 0xC0 }; - unsigned char disable[2] = { 0x21, 0x00 }; - unsigned char *msg; - - if (close) { - msg = enable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); - /* let the bridge stabilize */ - msleep(20); - } else { - msg = disable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); - } - - return 0; -} - -static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char enable[2] = { 0x45, 0xc1 }; - unsigned char disable[2] = { 0x46, 0x00 }; - unsigned char buf[3] = { 0x45, 0x01, 0x00 }; - unsigned char *msg; - - if (close) { - msg = enable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); - /* let the bridge stabilize */ - msleep(20); - } else { - msg = disable; - tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1); - - buf[2] = msg[1]; - buf[2] &= ~0x04; - tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); - msleep(5); - - msg[1] |= 0x04; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); - } - - return 0; -} - -/*---------------------------------------------------------------------*/ - -static void set_audio(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - char* mode; - - if (params->std & V4L2_STD_MN) { - priv->tda8290_easy_mode = 0x01; - mode = "MN"; - } else if (params->std & V4L2_STD_B) { - priv->tda8290_easy_mode = 0x02; - mode = "B"; - } else if (params->std & V4L2_STD_GH) { - priv->tda8290_easy_mode = 0x04; - mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - priv->tda8290_easy_mode = 0x08; - mode = "I"; - } else if (params->std & V4L2_STD_DK) { - priv->tda8290_easy_mode = 0x10; - mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - priv->tda8290_easy_mode = 0x20; - mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - priv->tda8290_easy_mode = 0x40; - mode = "LC"; - } else { - priv->tda8290_easy_mode = 0x10; - mode = "xx"; - } - - if (params->mode == V4L2_TUNER_RADIO) { - /* Set TDA8295 to FM radio; Start TDA8290 with MN values */ - priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01; - tuner_dbg("setting to radio FM\n"); - } else { - tuner_dbg("setting tda829x to system %s\n", mode); - } -} - -static struct { - unsigned char seq[2]; -} fm_mode[] = { - { { 0x01, 0x81} }, /* Put device into expert mode */ - { { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */ - { { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */ - { { 0x05, 0x04} }, /* ADC headroom */ - { { 0x06, 0x10} }, /* group delay flat */ - - { { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */ - { { 0x08, 0x00} }, - { { 0x09, 0x80} }, - { { 0x0a, 0xda} }, - { { 0x0b, 0x4b} }, - { { 0x0c, 0x68} }, - - { { 0x0d, 0x00} }, /* PLL off, no video carrier detect */ - { { 0x14, 0x00} }, /* disable auto mute if no video */ -}; - -static void tda8290_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char soft_reset[] = { 0x00, 0x00 }; - unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; - unsigned char expert_mode[] = { 0x01, 0x80 }; - unsigned char agc_out_on[] = { 0x02, 0x00 }; - unsigned char gainset_off[] = { 0x28, 0x14 }; - unsigned char if_agc_spd[] = { 0x0f, 0x88 }; - unsigned char adc_head_6[] = { 0x05, 0x04 }; - unsigned char adc_head_9[] = { 0x05, 0x02 }; - unsigned char adc_head_12[] = { 0x05, 0x01 }; - unsigned char pll_bw_nom[] = { 0x0d, 0x47 }; - unsigned char pll_bw_low[] = { 0x0d, 0x27 }; - unsigned char gainset_2[] = { 0x28, 0x64 }; - unsigned char agc_rst_on[] = { 0x0e, 0x0b }; - unsigned char agc_rst_off[] = { 0x0e, 0x09 }; - unsigned char if_agc_set[] = { 0x0f, 0x81 }; - unsigned char addr_adc_sat = 0x1a; - unsigned char addr_agc_stat = 0x1d; - unsigned char addr_pll_stat = 0x1b; - unsigned char adc_sat, agc_stat, - pll_stat; - int i; - - set_audio(fe, params); - - if (priv->cfg.config) - tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config); - tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); - tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); - tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); - msleep(1); - - if (params->mode == V4L2_TUNER_RADIO) { - unsigned char deemphasis[] = { 0x13, 1 }; - - /* FIXME: allow using a different deemphasis */ - - if (deemphasis_50) - deemphasis[1] = 2; - - for (i = 0; i < ARRAY_SIZE(fm_mode); i++) - tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2); - - tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2); - } else { - expert_mode[1] = priv->tda8290_easy_mode + 0x80; - tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); - tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); - tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); - if (priv->tda8290_easy_mode & 0x60) - tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); - else - tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); - tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - } - - - tda8290_i2c_bridge(fe, 1); - - if (fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, params); - - for (i = 0; i < 3; i++) { - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_pll_stat, 1, &pll_stat, 1); - if (pll_stat & 0x80) { - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_adc_sat, 1, - &adc_sat, 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_agc_stat, 1, - &agc_stat, 1); - tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); - break; - } else { - tuner_dbg("tda8290 not locked, no signal?\n"); - msleep(100); - } - } - /* adjust headroom resp. gain */ - if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { - tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", - agc_stat, adc_sat, pll_stat & 0x80); - tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); - msleep(100); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_agc_stat, 1, &agc_stat, 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_pll_stat, 1, &pll_stat, 1); - if ((agc_stat > 115) || !(pll_stat & 0x80)) { - tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", - agc_stat, pll_stat & 0x80); - if (priv->cfg.agcf) - priv->cfg.agcf(fe); - msleep(100); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_agc_stat, 1, - &agc_stat, 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_pll_stat, 1, - &pll_stat, 1); - if((agc_stat > 115) || !(pll_stat & 0x80)) { - tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); - tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); - tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); - msleep(100); - } - } - } - - /* l/ l' deadlock? */ - if(priv->tda8290_easy_mode & 0x60) { - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_adc_sat, 1, - &adc_sat, 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &addr_pll_stat, 1, - &pll_stat, 1); - if ((adc_sat > 20) || !(pll_stat & 0x80)) { - tuner_dbg("trying to resolve SECAM L deadlock\n"); - tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); - msleep(40); - tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); - } - } - - tda8290_i2c_bridge(fe, 0); - tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); -} - -/*---------------------------------------------------------------------*/ - -static void tda8295_power(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ - - tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); - - if (enable) - buf[1] = 0x01; - else - buf[1] = 0x03; - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); -} - -static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x01, 0x00 }; - - tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); - - if (enable) - buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ - else - buf[1] = 0x00; /* reset active bit */ - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); -} - -static void tda8295_set_video_std(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); - - tda8295_set_easy_mode(fe, 1); - msleep(20); - tda8295_set_easy_mode(fe, 0); -} - -/*---------------------------------------------------------------------*/ - -static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ - - tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); - - if (enable) - buf[1] &= ~0x40; - else - buf[1] |= 0x40; - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); -} - -static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char set_gpio_cf[] = { 0x44, 0x00 }; - unsigned char set_gpio_val[] = { 0x46, 0x00 }; - - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &set_gpio_cf[0], 1, &set_gpio_cf[1], 1); - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &set_gpio_val[0], 1, &set_gpio_val[1], 1); - - set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ - - if (enable) { - set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ - set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ - } - tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); -} - -static int tda8295_has_signal(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char hvpll_stat = 0x26; - unsigned char ret; - - tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); - return (ret & 0x01) ? 65535 : 0; -} - -/*---------------------------------------------------------------------*/ - -static void tda8295_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char blanking_mode[] = { 0x1d, 0x00 }; - - set_audio(fe, params); - - tuner_dbg("%s: freq = %d\n", __func__, params->frequency); - - tda8295_power(fe, 1); - tda8295_agc1_out(fe, 1); - - tuner_i2c_xfer_send_recv(&priv->i2c_props, - &blanking_mode[0], 1, &blanking_mode[1], 1); - - tda8295_set_video_std(fe); - - blanking_mode[1] = 0x03; - tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); - msleep(20); - - tda8295_i2c_bridge(fe, 1); - - if (fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, params); - - if (priv->cfg.agcf) - priv->cfg.agcf(fe); - - if (tda8295_has_signal(fe)) - tuner_dbg("tda8295 is locked\n"); - else - tuner_dbg("tda8295 not locked, no signal?\n"); - - tda8295_i2c_bridge(fe, 0); -} - -/*---------------------------------------------------------------------*/ - -static int tda8290_has_signal(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char i2c_get_afc[1] = { 0x1B }; - unsigned char afc = 0; - - tuner_i2c_xfer_send_recv(&priv->i2c_props, - i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); - return (afc & 0x80)? 65535:0; -} - -/*---------------------------------------------------------------------*/ - -static void tda8290_standby(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char cb1[] = { 0x30, 0xD0 }; - unsigned char tda8290_standby[] = { 0x00, 0x02 }; - unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - - tda8290_i2c_bridge(fe, 1); - if (priv->ver & TDA8275A) - cb1[1] = 0x90; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(fe, 0); - tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); - tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); -} - -static void tda8295_standby(struct dvb_frontend *fe) -{ - tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ - - tda8295_power(fe, 0); -} - -static void tda8290_init_if(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char set_VS[] = { 0x30, 0x6F }; - unsigned char set_GP00_CF[] = { 0x20, 0x01 }; - unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - - if ((priv->cfg.config == 1) || (priv->cfg.config == 2)) - tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); - else - tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); -} - -static void tda8295_init_if(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; - static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; - static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; - static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; - static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; - static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; - static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; - - tda8295_power(fe, 1); - - tda8295_set_easy_mode(fe, 0); - tda8295_set_video_std(fe); - - tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); - - tda8295_agc1_out(fe, 0); - tda8295_agc2_out(fe, 0); -} - -static void tda8290_init_tuner(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, - 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; - unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, - 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, - .buf=tda8275_init, .len = 14}; - if (priv->ver & TDA8275A) - msg.buf = tda8275a_init; - - tda8290_i2c_bridge(fe, 1); - i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(fe, 0); -} - -/*---------------------------------------------------------------------*/ - -static void tda829x_release(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - /* only try to release the tuner if we've - * attached it from within this module */ - if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); - - kfree(fe->analog_demod_priv); - fe->analog_demod_priv = NULL; -} - -static struct tda18271_config tda829x_tda18271_config = { - .gate = TDA18271_GATE_ANALOG, -}; - -static int tda829x_find_tuner(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; - int i, ret, tuners_found; - u32 tuner_addrs; - u8 data; - struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; - - if (!analog_ops->i2c_gate_ctrl) { - printk(KERN_ERR "tda8290: no gate control were provided!\n"); - - return -EINVAL; - } - - analog_ops->i2c_gate_ctrl(fe, 1); - - /* probe for tuner chip */ - tuners_found = 0; - tuner_addrs = 0; - for (i = 0x60; i <= 0x63; i++) { - msg.addr = i; - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if (ret == 1) { - tuners_found++; - tuner_addrs = (tuner_addrs << 8) + i; - } - } - /* if there is more than one tuner, we expect the right one is - behind the bridge and we choose the highest address that doesn't - give a response now - */ - - analog_ops->i2c_gate_ctrl(fe, 0); - - if (tuners_found > 1) - for (i = 0; i < tuners_found; i++) { - msg.addr = tuner_addrs & 0xff; - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if (ret == 1) - tuner_addrs = tuner_addrs >> 8; - else - break; - } - - if (tuner_addrs == 0) { - tuner_addrs = 0x60; - tuner_info("could not clearly identify tuner address, " - "defaulting to %x\n", tuner_addrs); - } else { - tuner_addrs = tuner_addrs & 0xff; - tuner_info("setting tuner address to %x\n", tuner_addrs); - } - priv->tda827x_addr = tuner_addrs; - msg.addr = tuner_addrs; - - analog_ops->i2c_gate_ctrl(fe, 1); - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - - if (ret != 1) { - tuner_warn("tuner access failed!\n"); - analog_ops->i2c_gate_ctrl(fe, 0); - return -EREMOTEIO; - } - - if ((data == 0x83) || (data == 0x84)) { - priv->ver |= TDA18271; - tda829x_tda18271_config.config = priv->cfg.config; - dvb_attach(tda18271_attach, fe, priv->tda827x_addr, - priv->i2c_props.adap, &tda829x_tda18271_config); - } else { - if ((data & 0x3c) == 0) - priv->ver |= TDA8275; - else - priv->ver |= TDA8275A; - - dvb_attach(tda827x_attach, fe, priv->tda827x_addr, - priv->i2c_props.adap, &priv->cfg); - priv->cfg.switch_addr = priv->i2c_props.addr; - } - if (fe->ops.tuner_ops.init) - fe->ops.tuner_ops.init(fe); - - if (fe->ops.tuner_ops.sleep) - fe->ops.tuner_ops.sleep(fe); - - analog_ops->i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int tda8290_probe(struct tuner_i2c_props *i2c_props) -{ -#define TDA8290_ID 0x89 - u8 reg = 0x1f, id; - struct i2c_msg msg_read[] = { - { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, - { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, - }; - - /* detect tda8290 */ - if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { - printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", - __func__, reg); - return -ENODEV; - } - - if (id == TDA8290_ID) { - if (debug) - printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", - __func__, i2c_adapter_id(i2c_props->adap), - i2c_props->addr); - return 0; - } - return -ENODEV; -} - -static int tda8295_probe(struct tuner_i2c_props *i2c_props) -{ -#define TDA8295_ID 0x8a -#define TDA8295C2_ID 0x8b - u8 reg = 0x2f, id; - struct i2c_msg msg_read[] = { - { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, - { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, - }; - - /* detect tda8295 */ - if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { - printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", - __func__, reg); - return -ENODEV; - } - - if ((id & 0xfe) == TDA8295_ID) { - if (debug) - printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n", - __func__, (id == TDA8295_ID) ? - "tda8295c1" : "tda8295c2", - i2c_adapter_id(i2c_props->adap), - i2c_props->addr); - return 0; - } - - return -ENODEV; -} - -static struct analog_demod_ops tda8290_ops = { - .set_params = tda8290_set_params, - .has_signal = tda8290_has_signal, - .standby = tda8290_standby, - .release = tda829x_release, - .i2c_gate_ctrl = tda8290_i2c_bridge, -}; - -static struct analog_demod_ops tda8295_ops = { - .set_params = tda8295_set_params, - .has_signal = tda8295_has_signal, - .standby = tda8295_standby, - .release = tda829x_release, - .i2c_gate_ctrl = tda8295_i2c_bridge, -}; - -struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, u8 i2c_addr, - struct tda829x_config *cfg) -{ - struct tda8290_priv *priv = NULL; - char *name; - - priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->analog_demod_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->i2c_props.name = "tda829x"; - if (cfg) - priv->cfg.config = cfg->lna_cfg; - - if (tda8290_probe(&priv->i2c_props) == 0) { - priv->ver = TDA8290; - memcpy(&fe->ops.analog_ops, &tda8290_ops, - sizeof(struct analog_demod_ops)); - } - - if (tda8295_probe(&priv->i2c_props) == 0) { - priv->ver = TDA8295; - memcpy(&fe->ops.analog_ops, &tda8295_ops, - sizeof(struct analog_demod_ops)); - } - - if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) { - tda8295_power(fe, 1); - if (tda829x_find_tuner(fe) < 0) - goto fail; - } - - switch (priv->ver) { - case TDA8290: - name = "tda8290"; - break; - case TDA8295: - name = "tda8295"; - break; - case TDA8290 | TDA8275: - name = "tda8290+75"; - break; - case TDA8295 | TDA8275: - name = "tda8295+75"; - break; - case TDA8290 | TDA8275A: - name = "tda8290+75a"; - break; - case TDA8295 | TDA8275A: - name = "tda8295+75a"; - break; - case TDA8290 | TDA18271: - name = "tda8290+18271"; - break; - case TDA8295 | TDA18271: - name = "tda8295+18271"; - break; - default: - goto fail; - } - tuner_info("type set to %s\n", name); - - fe->ops.analog_ops.info.name = name; - - if (priv->ver & TDA8290) { - if (priv->ver & (TDA8275 | TDA8275A)) - tda8290_init_tuner(fe); - tda8290_init_if(fe); - } else if (priv->ver & TDA8295) - tda8295_init_if(fe); - - return fe; - -fail: - memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); - - tda829x_release(fe); - return NULL; -} -EXPORT_SYMBOL_GPL(tda829x_attach); - -int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) -{ - struct tuner_i2c_props i2c_props = { - .adap = i2c_adap, - .addr = i2c_addr, - }; - - unsigned char soft_reset[] = { 0x00, 0x00 }; - unsigned char easy_mode_b[] = { 0x01, 0x02 }; - unsigned char easy_mode_g[] = { 0x01, 0x04 }; - unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; - unsigned char addr_dto_lsb = 0x07; - unsigned char data; -#define PROBE_BUFFER_SIZE 8 - unsigned char buf[PROBE_BUFFER_SIZE]; - int i; - - /* rule out tda9887, which would return the same byte repeatedly */ - tuner_i2c_xfer_send_recv(&i2c_props, - soft_reset, 1, buf, PROBE_BUFFER_SIZE); - for (i = 1; i < PROBE_BUFFER_SIZE; i++) { - if (buf[i] != buf[0]) - break; - } - - /* all bytes are equal, not a tda829x - probably a tda9887 */ - if (i == PROBE_BUFFER_SIZE) - return -ENODEV; - - if ((tda8290_probe(&i2c_props) == 0) || - (tda8295_probe(&i2c_props) == 0)) - return 0; - - /* fall back to old probing method */ - tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); - tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); - tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1); - if (data == 0) { - tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); - tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); - tuner_i2c_xfer_send_recv(&i2c_props, - &addr_dto_lsb, 1, &data, 1); - if (data == 0x7b) { - return 0; - } - } - tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); - return -ENODEV; -} -EXPORT_SYMBOL_GPL(tda829x_probe); - -MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); -MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda8290.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda8290.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda8290.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda8290.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TDA8290_H__ -#define __TDA8290_H__ - -#include -#include "dvb_frontend.h" - -struct tda829x_config { - unsigned int lna_cfg; - - unsigned int probe_tuner:1; -#define TDA829X_PROBE_TUNER 0 -#define TDA829X_DONT_PROBE 1 -}; - -#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE)) -extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); - -extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - struct tda829x_config *cfg); -#else -static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -EINVAL; -} - -static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - struct tda829x_config *cfg) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __func__); - return NULL; -} -#endif - -#endif /* __TDA8290_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda9887.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda9887.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda9887.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda9887.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,717 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tda9887.h" - - -/* Chips: - TDA9885 (PAL, NTSC) - TDA9886 (PAL, SECAM, NTSC) - TDA9887 (PAL, SECAM, NTSC, FM Radio) - - Used as part of several tuners -*/ - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static DEFINE_MUTEX(tda9887_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -struct tda9887_priv { - struct tuner_i2c_props i2c_props; - struct list_head hybrid_tuner_instance_list; - - unsigned char data[4]; - unsigned int config; - unsigned int mode; - unsigned int audmode; - v4l2_std_id std; - - bool standby; -}; - -/* ---------------------------------------------------------------------- */ - -#define UNSET (-1U) - -struct tvnorm { - v4l2_std_id std; - char *name; - unsigned char b; - unsigned char c; - unsigned char e; -}; - -/* ---------------------------------------------------------------------- */ - -// -// TDA defines -// - -//// first reg (b) -#define cVideoTrapBypassOFF 0x00 // bit b0 -#define cVideoTrapBypassON 0x01 // bit b0 - -#define cAutoMuteFmInactive 0x00 // bit b1 -#define cAutoMuteFmActive 0x02 // bit b1 - -#define cIntercarrier 0x00 // bit b2 -#define cQSS 0x04 // bit b2 - -#define cPositiveAmTV 0x00 // bit b3:4 -#define cFmRadio 0x08 // bit b3:4 -#define cNegativeFmTV 0x10 // bit b3:4 - - -#define cForcedMuteAudioON 0x20 // bit b5 -#define cForcedMuteAudioOFF 0x00 // bit b5 - -#define cOutputPort1Active 0x00 // bit b6 -#define cOutputPort1Inactive 0x40 // bit b6 - -#define cOutputPort2Active 0x00 // bit b7 -#define cOutputPort2Inactive 0x80 // bit b7 - - -//// second reg (c) -#define cDeemphasisOFF 0x00 // bit c5 -#define cDeemphasisON 0x20 // bit c5 - -#define cDeemphasis75 0x00 // bit c6 -#define cDeemphasis50 0x40 // bit c6 - -#define cAudioGain0 0x00 // bit c7 -#define cAudioGain6 0x80 // bit c7 - -#define cTopMask 0x1f // bit c0:4 -#define cTopDefault 0x10 // bit c0:4 - -//// third reg (e) -#define cAudioIF_4_5 0x00 // bit e0:1 -#define cAudioIF_5_5 0x01 // bit e0:1 -#define cAudioIF_6_0 0x02 // bit e0:1 -#define cAudioIF_6_5 0x03 // bit e0:1 - - -#define cVideoIFMask 0x1c // bit e2:4 -/* Video IF selection in TV Mode (bit B3=0) */ -#define cVideoIF_58_75 0x00 // bit e2:4 -#define cVideoIF_45_75 0x04 // bit e2:4 -#define cVideoIF_38_90 0x08 // bit e2:4 -#define cVideoIF_38_00 0x0C // bit e2:4 -#define cVideoIF_33_90 0x10 // bit e2:4 -#define cVideoIF_33_40 0x14 // bit e2:4 -#define cRadioIF_45_75 0x18 // bit e2:4 -#define cRadioIF_38_90 0x1C // bit e2:4 - -/* IF1 selection in Radio Mode (bit B3=1) */ -#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) -#define cRadioIF_41_30 0x04 // bit e2,4 - -/* Output of AFC pin in radio mode when bit E7=1 */ -#define cRadioAGC_SIF 0x00 // bit e3 -#define cRadioAGC_FM 0x08 // bit e3 - -#define cTunerGainNormal 0x00 // bit e5 -#define cTunerGainLow 0x20 // bit e5 - -#define cGating_18 0x00 // bit e6 -#define cGating_36 0x40 // bit e6 - -#define cAgcOutON 0x80 // bit e7 -#define cAgcOutOFF 0x00 // bit e7 - -/* ---------------------------------------------------------------------- */ - -static struct tvnorm tvnorms[] = { - { - .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N, - .name = "PAL-BGHN", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_5_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_PAL_I, - .name = "PAL-I", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_0 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_PAL_DK, - .name = "PAL-DK", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc, - .name = "PAL-M/Nc", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis75 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_4_5 | - cVideoIF_45_75 ), - },{ - .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, - .name = "SECAM-BGH", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cTopDefault), - .e = ( cAudioIF_5_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_SECAM_L, - .name = "SECAM-L", - .b = ( cPositiveAmTV | - cQSS ), - .c = ( cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_SECAM_LC, - .name = "SECAM-L'", - .b = ( cOutputPort2Inactive | - cPositiveAmTV | - cQSS ), - .c = ( cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_5 | - cVideoIF_33_90 ), - },{ - .std = V4L2_STD_SECAM_DK, - .name = "SECAM-DK", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_6_5 | - cVideoIF_38_90 ), - },{ - .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, - .name = "NTSC-M", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis75 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_4_5 | - cVideoIF_45_75 ), - },{ - .std = V4L2_STD_NTSC_M_JP, - .name = "NTSC-M-JP", - .b = ( cNegativeFmTV | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis50 | - cTopDefault), - .e = ( cGating_36 | - cAudioIF_4_5 | - cVideoIF_58_75 ), - } -}; - -static struct tvnorm radio_stereo = { - .name = "Radio Stereo", - .b = ( cFmRadio | - cQSS ), - .c = ( cDeemphasisOFF | - cAudioGain6 | - cTopDefault), - .e = ( cTunerGainLow | - cAudioIF_5_5 | - cRadioIF_38_90 ), -}; - -static struct tvnorm radio_mono = { - .name = "Radio Mono", - .b = ( cFmRadio | - cQSS ), - .c = ( cDeemphasisON | - cDeemphasis75 | - cTopDefault), - .e = ( cTunerGainLow | - cAudioIF_5_5 | - cRadioIF_38_90 ), -}; - -/* ---------------------------------------------------------------------- */ - -static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - static char *afc[16] = { - "- 12.5 kHz", - "- 37.5 kHz", - "- 62.5 kHz", - "- 87.5 kHz", - "-112.5 kHz", - "-137.5 kHz", - "-162.5 kHz", - "-187.5 kHz [min]", - "+187.5 kHz [max]", - "+162.5 kHz", - "+137.5 kHz", - "+112.5 kHz", - "+ 87.5 kHz", - "+ 62.5 kHz", - "+ 37.5 kHz", - "+ 12.5 kHz", - }; - tuner_info("read: 0x%2x\n", buf[0]); - tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); - tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); - tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); - tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); - tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); -} - -static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - static char *sound[4] = { - "AM/TV", - "FM/radio", - "FM/TV", - "FM/radio" - }; - static char *adjust[32] = { - "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9", - "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", - "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", - "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15" - }; - static char *deemph[4] = { - "no", "no", "75", "50" - }; - static char *carrier[4] = { - "4.5 MHz", - "5.5 MHz", - "6.0 MHz", - "6.5 MHz / AM" - }; - static char *vif[8] = { - "58.75 MHz", - "45.75 MHz", - "38.9 MHz", - "38.0 MHz", - "33.9 MHz", - "33.4 MHz", - "45.75 MHz + pin13", - "38.9 MHz + pin13", - }; - static char *rif[4] = { - "44 MHz", - "52 MHz", - "52 MHz", - "44 MHz", - }; - - tuner_info("write: byte B 0x%02x\n", buf[1]); - tuner_info(" B0 video mode : %s\n", - (buf[1] & 0x01) ? "video trap" : "sound trap"); - tuner_info(" B1 auto mute fm : %s\n", - (buf[1] & 0x02) ? "yes" : "no"); - tuner_info(" B2 carrier mode : %s\n", - (buf[1] & 0x04) ? "QSS" : "Intercarrier"); - tuner_info(" B3-4 tv sound/radio : %s\n", - sound[(buf[1] & 0x18) >> 3]); - tuner_info(" B5 force mute audio: %s\n", - (buf[1] & 0x20) ? "yes" : "no"); - tuner_info(" B6 output port 1 : %s\n", - (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); - tuner_info(" B7 output port 2 : %s\n", - (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); - - tuner_info("write: byte C 0x%02x\n", buf[2]); - tuner_info(" C0-4 top adjustment : %s dB\n", - adjust[buf[2] & 0x1f]); - tuner_info(" C5-6 de-emphasis : %s\n", - deemph[(buf[2] & 0x60) >> 5]); - tuner_info(" C7 audio gain : %s\n", - (buf[2] & 0x80) ? "-6" : "0"); - - tuner_info("write: byte E 0x%02x\n", buf[3]); - tuner_info(" E0-1 sound carrier : %s\n", - carrier[(buf[3] & 0x03)]); - tuner_info(" E6 l pll gating : %s\n", - (buf[3] & 0x40) ? "36" : "13"); - - if (buf[1] & 0x08) { - /* radio */ - tuner_info(" E2-4 video if : %s\n", - rif[(buf[3] & 0x0c) >> 2]); - tuner_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x10) ? "fm-agc radio" : - "sif-agc radio") - : "fm radio carrier afc"); - } else { - /* video */ - tuner_info(" E2-4 video if : %s\n", - vif[(buf[3] & 0x1c) >> 2]); - tuner_info(" E5 tuner gain : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x20) ? "external" : "normal") - : ((buf[3] & 0x20) ? "minimum" : "normal")); - tuner_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) ? ((buf[3] & 0x20) - ? "pin3 port, pin22 vif agc out" - : "pin22 port, pin3 vif acg ext in") - : "pin3+pin22 port"); - } - tuner_info("--\n"); -} - -/* ---------------------------------------------------------------------- */ - -static int tda9887_set_tvnorm(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - struct tvnorm *norm = NULL; - char *buf = priv->data; - int i; - - if (priv->mode == V4L2_TUNER_RADIO) { - if (priv->audmode == V4L2_TUNER_MODE_MONO) - norm = &radio_mono; - else - norm = &radio_stereo; - } else { - for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { - if (tvnorms[i].std & priv->std) { - norm = tvnorms+i; - break; - } - } - } - if (NULL == norm) { - tuner_dbg("Unsupported tvnorm entry - audio muted\n"); - return -1; - } - - tuner_dbg("configure for: %s\n", norm->name); - buf[1] = norm->b; - buf[2] = norm->c; - buf[3] = norm->e; - return 0; -} - -static unsigned int port1 = UNSET; -static unsigned int port2 = UNSET; -static unsigned int qss = UNSET; -static unsigned int adjust = UNSET; - -module_param(port1, int, 0644); -module_param(port2, int, 0644); -module_param(qss, int, 0644); -module_param(adjust, int, 0644); - -static int tda9887_set_insmod(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - char *buf = priv->data; - - if (UNSET != port1) { - if (port1) - buf[1] |= cOutputPort1Inactive; - else - buf[1] &= ~cOutputPort1Inactive; - } - if (UNSET != port2) { - if (port2) - buf[1] |= cOutputPort2Inactive; - else - buf[1] &= ~cOutputPort2Inactive; - } - - if (UNSET != qss) { - if (qss) - buf[1] |= cQSS; - else - buf[1] &= ~cQSS; - } - - if (adjust < 0x20) { - buf[2] &= ~cTopMask; - buf[2] |= adjust; - } - return 0; -} - -static int tda9887_do_config(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - char *buf = priv->data; - - if (priv->config & TDA9887_PORT1_ACTIVE) - buf[1] &= ~cOutputPort1Inactive; - if (priv->config & TDA9887_PORT1_INACTIVE) - buf[1] |= cOutputPort1Inactive; - if (priv->config & TDA9887_PORT2_ACTIVE) - buf[1] &= ~cOutputPort2Inactive; - if (priv->config & TDA9887_PORT2_INACTIVE) - buf[1] |= cOutputPort2Inactive; - - if (priv->config & TDA9887_QSS) - buf[1] |= cQSS; - if (priv->config & TDA9887_INTERCARRIER) - buf[1] &= ~cQSS; - - if (priv->config & TDA9887_AUTOMUTE) - buf[1] |= cAutoMuteFmActive; - if (priv->config & TDA9887_DEEMPHASIS_MASK) { - buf[2] &= ~0x60; - switch (priv->config & TDA9887_DEEMPHASIS_MASK) { - case TDA9887_DEEMPHASIS_NONE: - buf[2] |= cDeemphasisOFF; - break; - case TDA9887_DEEMPHASIS_50: - buf[2] |= cDeemphasisON | cDeemphasis50; - break; - case TDA9887_DEEMPHASIS_75: - buf[2] |= cDeemphasisON | cDeemphasis75; - break; - } - } - if (priv->config & TDA9887_TOP_SET) { - buf[2] &= ~cTopMask; - buf[2] |= (priv->config >> 8) & cTopMask; - } - if ((priv->config & TDA9887_INTERCARRIER_NTSC) && - (priv->std & V4L2_STD_NTSC)) - buf[1] &= ~cQSS; - if (priv->config & TDA9887_GATING_18) - buf[3] &= ~cGating_36; - - if (priv->mode == V4L2_TUNER_RADIO) { - if (priv->config & TDA9887_RIF_41_3) { - buf[3] &= ~cVideoIFMask; - buf[3] |= cRadioIF_41_30; - } - if (priv->config & TDA9887_GAIN_NORMAL) - buf[3] &= ~cTunerGainLow; - } - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static int tda9887_status(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - unsigned char buf[1]; - int rc; - - memset(buf,0,sizeof(buf)); - if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) - tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); - dump_read_message(fe, buf); - return 0; -} - -static void tda9887_configure(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - int rc; - - memset(priv->data,0,sizeof(priv->data)); - tda9887_set_tvnorm(fe); - - /* A note on the port settings: - These settings tend to depend on the specifics of the board. - By default they are set to inactive (bit value 1) by this driver, - overwriting any changes made by the tvnorm. This means that it - is the responsibility of the module using the tda9887 to set - these values in case of changes in the tvnorm. - In many cases port 2 should be made active (0) when selecting - SECAM-L, and port 2 should remain inactive (1) for SECAM-L'. - - For the other standards the tda9887 application note says that - the ports should be set to active (0), but, again, that may - differ depending on the precise hardware configuration. - */ - priv->data[1] |= cOutputPort1Inactive; - priv->data[1] |= cOutputPort2Inactive; - - tda9887_do_config(fe); - tda9887_set_insmod(fe); - - if (priv->standby) - priv->data[1] |= cForcedMuteAudioON; - - tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1], priv->data[2], priv->data[3]); - if (debug > 1) - dump_write_message(fe, priv->data); - - if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) - tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); - - if (debug > 2) { - msleep_interruptible(1000); - tda9887_status(fe); - } -} - -/* ---------------------------------------------------------------------- */ - -static void tda9887_tuner_status(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1], priv->data[2], priv->data[3]); -} - -static int tda9887_get_afc(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - static int AFC_BITS_2_kHz[] = { - -12500, -37500, -62500, -97500, - -112500, -137500, -162500, -187500, - 187500, 162500, 137500, 112500, - 97500 , 62500, 37500 , 12500 - }; - int afc=0; - __u8 reg = 0; - - if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) - afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; - - return afc; -} - -static void tda9887_standby(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - priv->standby = true; - - tda9887_configure(fe); -} - -static void tda9887_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - priv->standby = false; - priv->mode = params->mode; - priv->audmode = params->audmode; - priv->std = params->std; - tda9887_configure(fe); -} - -static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - priv->config = *(unsigned int *)priv_cfg; - tda9887_configure(fe); - - return 0; -} - -static void tda9887_release(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - mutex_lock(&tda9887_list_mutex); - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&tda9887_list_mutex); - - fe->analog_demod_priv = NULL; -} - -static struct analog_demod_ops tda9887_ops = { - .info = { - .name = "tda9887", - }, - .set_params = tda9887_set_params, - .standby = tda9887_standby, - .tuner_status = tda9887_tuner_status, - .get_afc = tda9887_get_afc, - .release = tda9887_release, - .set_config = tda9887_set_config, -}; - -struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr) -{ - struct tda9887_priv *priv = NULL; - int instance; - - mutex_lock(&tda9887_list_mutex); - - instance = hybrid_tuner_request_state(struct tda9887_priv, priv, - hybrid_tuner_instance_list, - i2c_adap, i2c_addr, "tda9887"); - switch (instance) { - case 0: - mutex_unlock(&tda9887_list_mutex); - return NULL; - case 1: - fe->analog_demod_priv = priv; - priv->standby = true; - tuner_info("tda988[5/6/7] found\n"); - break; - default: - fe->analog_demod_priv = priv; - break; - } - - mutex_unlock(&tda9887_list_mutex); - - memcpy(&fe->ops.analog_ops, &tda9887_ops, - sizeof(struct analog_demod_ops)); - - return fe; -} -EXPORT_SYMBOL_GPL(tda9887_attach); - -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda9887.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda9887.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda9887.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tda9887.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TDA9887_H__ -#define __TDA9887_H__ - -#include -#include "dvb_frontend.h" - -/* ------------------------------------------------------------------------ */ -#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr); -#else -static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TDA9887_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5761.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5761.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5761.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5761.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,348 +0,0 @@ -/* - * For Philips TEA5761 FM Chip - * I2C address is allways 0x20 (0x10 at 7-bit mode). - * - * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNUv2 General Public License - * - */ - -#include -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tea5761.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -struct tea5761_priv { - struct tuner_i2c_props i2c_props; - - u32 frequency; - bool standby; -}; - -/*****************************************************************************/ - -/*************************** - * TEA5761HN I2C registers * - ***************************/ - -/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */ - - /* first byte for reading */ -#define TEA5761_INTREG_IFFLAG 0x10 -#define TEA5761_INTREG_LEVFLAG 0x8 -#define TEA5761_INTREG_FRRFLAG 0x2 -#define TEA5761_INTREG_BLFLAG 0x1 - - /* second byte for reading / byte for writing */ -#define TEA5761_INTREG_IFMSK 0x10 -#define TEA5761_INTREG_LEVMSK 0x8 -#define TEA5761_INTREG_FRMSK 0x2 -#define TEA5761_INTREG_BLMSK 0x1 - -/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */ - - /* First byte */ -#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */ -#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */ - - /* Bits 0-5 for divider MSB */ - - /* Second byte */ - /* Bits 0-7 for divider LSB */ - -/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */ - - /* first byte */ - -#define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */ -#define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */ -#define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */ -#define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */ -#define TEA5761_TNCTRL_AFM 0x04 -#define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */ -#define TEA5761_TNCTRL_SNC 0x01 - - /* second byte */ - -#define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */ -#define TEA5761_TNCTRL_SSL_1 0x40 -#define TEA5761_TNCTRL_SSL_0 0x20 -#define TEA5761_TNCTRL_HLSI 0x10 -#define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */ -#define TEA5761_TNCTRL_SWP 0x04 -#define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */ -#define TEA5761_TNCTRL_AHLSI 0x01 - -/* FRQCHECK - Read: bytes 6 and 7 */ - /* First byte */ - - /* Bits 0-5 for divider MSB */ - - /* Second byte */ - /* Bits 0-7 for divider LSB */ - -/* TUNCHECK - Read: bytes 8 and 9 */ - - /* First byte */ -#define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */ -#define TEA5761_TUNCHECK_TUNTO 0x01 - - /* Second byte */ -#define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */ -#define TEA5761_TUNCHECK_LD 0x08 -#define TEA5761_TUNCHECK_STEREO 0x04 - -/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */ - - /* All zero = no test mode */ - -/* MANID - Read: bytes 12 and 13 */ - - /* First byte - should be 0x10 */ -#define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */ -#define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */ - - /* Second byte - Should be 0x2b */ - -#define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */ -#define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */ - -/* Chip ID - Read: bytes 14 and 15 */ - - /* First byte - should be 0x57 */ - - /* Second byte - should be 0x61 */ - -/*****************************************************************************/ - -#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ -static void tea5761_status_dump(unsigned char *buffer) -{ - unsigned int div, frq; - - div = ((buffer[2] & 0x3f) << 8) | buffer[3]; - - frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */ - - printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n", - frq / 1000, frq % 1000, div); -} - -/* Freq should be specifyed at 62.5 Hz */ -static int __set_radio_freq(struct dvb_frontend *fe, - unsigned int freq, - bool mono) -{ - struct tea5761_priv *priv = fe->tuner_priv; - unsigned int frq = freq; - unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; - unsigned div; - int rc; - - tuner_dbg("radio freq counter %d\n", frq); - - if (priv->standby) { - tuner_dbg("TEA5761 set to standby mode\n"); - buffer[5] |= TEA5761_TNCTRL_MU; - } else { - buffer[4] |= TEA5761_TNCTRL_PUPD_0; - } - - - if (mono) { - tuner_dbg("TEA5761 set to mono\n"); - buffer[5] |= TEA5761_TNCTRL_MST; - } else { - tuner_dbg("TEA5761 set to stereo\n"); - } - - div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15; - buffer[1] = (div >> 8) & 0x3f; - buffer[2] = div & 0xff; - - if (debug) - tea5761_status_dump(buffer); - - if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - - priv->frequency = frq * 125 / 2; - - return 0; -} - -static int set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tea5761_priv *priv = fe->analog_demod_priv; - - priv->standby = false; - - return __set_radio_freq(fe, params->frequency, - params->audmode == V4L2_TUNER_MODE_MONO); -} - -static int set_radio_sleep(struct dvb_frontend *fe) -{ - struct tea5761_priv *priv = fe->analog_demod_priv; - - priv->standby = true; - - return __set_radio_freq(fe, priv->frequency, false); -} - -static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) -{ - struct tea5761_priv *priv = fe->tuner_priv; - int rc; - - memset(buffer, 0, 16); - if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) { - tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc); - return -EREMOTEIO; - } - - return 0; -} - -static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer) -{ - struct tea5761_priv *priv = fe->tuner_priv; - - int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); - - tuner_dbg("Signal strength: %d\n", signal); - - return signal; -} - -static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer) -{ - struct tea5761_priv *priv = fe->tuner_priv; - - int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO; - - tuner_dbg("Radio ST GET = %02x\n", stereo); - - return (stereo ? V4L2_TUNER_SUB_STEREO : 0); -} - -static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) -{ - unsigned char buffer[16]; - - *status = 0; - - if (0 == tea5761_read_status(fe, buffer)) { - if (tea5761_signal(fe, buffer)) - *status = TUNER_STATUS_LOCKED; - if (tea5761_stereo(fe, buffer)) - *status |= TUNER_STATUS_STEREO; - } - - return 0; -} - -static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - unsigned char buffer[16]; - - *strength = 0; - - if (0 == tea5761_read_status(fe, buffer)) - *strength = tea5761_signal(fe, buffer); - - return 0; -} - -int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) -{ - unsigned char buffer[16]; - int rc; - struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; - - if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { - printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); - return -EINVAL; - } - - if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) { - printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x." - " It is not a TEA5761\n", - buffer[13], buffer[14], buffer[15]); - return -EINVAL; - } - printk(KERN_WARNING "tea5761: TEA%02x%02x detected. " - "Manufacturer ID= 0x%02x\n", - buffer[14], buffer[15], buffer[13]); - - return 0; -} - -static int tea5761_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - -static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tea5761_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static struct dvb_tuner_ops tea5761_tuner_ops = { - .info = { - .name = "tea5761", // Philips TEA5761HN FM Radio - }, - .set_analog_params = set_radio_freq, - .sleep = set_radio_sleep, - .release = tea5761_release, - .get_frequency = tea5761_get_frequency, - .get_status = tea5761_get_status, - .get_rf_strength = tea5761_get_rf_strength, -}; - -struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - struct tea5761_priv *priv = NULL; - - if (tea5761_autodetection(i2c_adap, i2c_addr) != 0) - return NULL; - - priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->tuner_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->i2c_props.name = "tea5761"; - - memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); - - return fe; -} - - -EXPORT_SYMBOL_GPL(tea5761_attach); -EXPORT_SYMBOL_GPL(tea5761_autodetection); - -MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5761.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5761.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5761.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5761.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TEA5761_H__ -#define __TEA5761_H__ - -#include -#include "dvb_frontend.h" - -#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) -extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); - -extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr); -#else -static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __func__); - return -EINVAL; -} - -static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TEA5761_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5767.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5767.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5767.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5767.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,475 +0,0 @@ -/* - * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview - * I2C address is allways 0xC0. - * - * - * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License - * - * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa - * from their contributions on DScaler. - */ - -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tea5767.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -/*****************************************************************************/ - -struct tea5767_priv { - struct tuner_i2c_props i2c_props; - u32 frequency; - struct tea5767_ctrl ctrl; -}; - -/*****************************************************************************/ - -/****************************** - * Write mode register values * - ******************************/ - -/* First register */ -#define TEA5767_MUTE 0x80 /* Mutes output */ -#define TEA5767_SEARCH 0x40 /* Activates station search */ -/* Bits 0-5 for divider MSB */ - -/* Second register */ -/* Bits 0-7 for divider LSB */ - -/* Third register */ - -/* Station search from botton to up */ -#define TEA5767_SEARCH_UP 0x80 - -/* Searches with ADC output = 10 */ -#define TEA5767_SRCH_HIGH_LVL 0x60 - -/* Searches with ADC output = 10 */ -#define TEA5767_SRCH_MID_LVL 0x40 - -/* Searches with ADC output = 5 */ -#define TEA5767_SRCH_LOW_LVL 0x20 - -/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */ -#define TEA5767_HIGH_LO_INJECT 0x10 - -/* Disable stereo */ -#define TEA5767_MONO 0x08 - -/* Disable right channel and turns to mono */ -#define TEA5767_MUTE_RIGHT 0x04 - -/* Disable left channel and turns to mono */ -#define TEA5767_MUTE_LEFT 0x02 - -#define TEA5767_PORT1_HIGH 0x01 - -/* Fourth register */ -#define TEA5767_PORT2_HIGH 0x80 -/* Chips stops working. Only I2C bus remains on */ -#define TEA5767_STDBY 0x40 - -/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */ -#define TEA5767_JAPAN_BAND 0x20 - -/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */ -#define TEA5767_XTAL_32768 0x10 - -/* Cuts weak signals */ -#define TEA5767_SOFT_MUTE 0x08 - -/* Activates high cut control */ -#define TEA5767_HIGH_CUT_CTRL 0x04 - -/* Activates stereo noise control */ -#define TEA5767_ST_NOISE_CTL 0x02 - -/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ -#define TEA5767_SRCH_IND 0x01 - -/* Fifth register */ - -/* By activating, it will use Xtal at 13 MHz as reference for divider */ -#define TEA5767_PLLREF_ENABLE 0x80 - -/* By activating, deemphasis=50, or else, deemphasis of 50us */ -#define TEA5767_DEEMPH_75 0X40 - -/***************************** - * Read mode register values * - *****************************/ - -/* First register */ -#define TEA5767_READY_FLAG_MASK 0x80 -#define TEA5767_BAND_LIMIT_MASK 0X40 -/* Bits 0-5 for divider MSB after search or preset */ - -/* Second register */ -/* Bits 0-7 for divider LSB after search or preset */ - -/* Third register */ -#define TEA5767_STEREO_MASK 0x80 -#define TEA5767_IF_CNTR_MASK 0x7f - -/* Fourth register */ -#define TEA5767_ADC_LEVEL_MASK 0xf0 - -/* should be 0 */ -#define TEA5767_CHIP_ID_MASK 0x0f - -/* Fifth register */ -/* Reserved for future extensions */ -#define TEA5767_RESERVED_MASK 0xff - -/*****************************************************************************/ - -static void tea5767_status_dump(struct tea5767_priv *priv, - unsigned char *buffer) -{ - unsigned int div, frq; - - if (TEA5767_READY_FLAG_MASK & buffer[0]) - tuner_info("Ready Flag ON\n"); - else - tuner_info("Ready Flag OFF\n"); - - if (TEA5767_BAND_LIMIT_MASK & buffer[0]) - tuner_info("Tuner at band limit\n"); - else - tuner_info("Tuner not at band limit\n"); - - div = ((buffer[0] & 0x3f) << 8) | buffer[1]; - - switch (priv->ctrl.xtal_freq) { - case TEA5767_HIGH_LO_13MHz: - frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ - break; - case TEA5767_LOW_LO_13MHz: - frq = (div * 50000 + 700000 + 225000) / 4; /* Freq in KHz */ - break; - case TEA5767_LOW_LO_32768: - frq = (div * 32768 + 700000 + 225000) / 4; /* Freq in KHz */ - break; - case TEA5767_HIGH_LO_32768: - default: - frq = (div * 32768 - 700000 - 225000) / 4; /* Freq in KHz */ - break; - } - buffer[0] = (div >> 8) & 0x3f; - buffer[1] = div & 0xff; - - tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n", - frq / 1000, frq % 1000, div); - - if (TEA5767_STEREO_MASK & buffer[2]) - tuner_info("Stereo\n"); - else - tuner_info("Mono\n"); - - tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); - - tuner_info("ADC Level = %d\n", - (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); - - tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); - - tuner_info("Reserved = 0x%02x\n", - (buffer[4] & TEA5767_RESERVED_MASK)); -} - -/* Freq should be specifyed at 62.5 Hz */ -static int set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tea5767_priv *priv = fe->tuner_priv; - unsigned int frq = params->frequency; - unsigned char buffer[5]; - unsigned div; - int rc; - - tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); - - buffer[2] = 0; - - if (priv->ctrl.port1) - buffer[2] |= TEA5767_PORT1_HIGH; - - if (params->audmode == V4L2_TUNER_MODE_MONO) { - tuner_dbg("TEA5767 set to mono\n"); - buffer[2] |= TEA5767_MONO; - } else { - tuner_dbg("TEA5767 set to stereo\n"); - } - - - buffer[3] = 0; - - if (priv->ctrl.port2) - buffer[3] |= TEA5767_PORT2_HIGH; - - if (priv->ctrl.high_cut) - buffer[3] |= TEA5767_HIGH_CUT_CTRL; - - if (priv->ctrl.st_noise) - buffer[3] |= TEA5767_ST_NOISE_CTL; - - if (priv->ctrl.soft_mute) - buffer[3] |= TEA5767_SOFT_MUTE; - - if (priv->ctrl.japan_band) - buffer[3] |= TEA5767_JAPAN_BAND; - - buffer[4] = 0; - - if (priv->ctrl.deemph_75) - buffer[4] |= TEA5767_DEEMPH_75; - - if (priv->ctrl.pllref) - buffer[4] |= TEA5767_PLLREF_ENABLE; - - - /* Rounds freq to next decimal value - for 62.5 KHz step */ - /* frq = 20*(frq/16)+radio_frq[frq%16]; */ - - switch (priv->ctrl.xtal_freq) { - case TEA5767_HIGH_LO_13MHz: - tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); - buffer[2] |= TEA5767_HIGH_LO_INJECT; - div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; - break; - case TEA5767_LOW_LO_13MHz: - tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); - - div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; - break; - case TEA5767_LOW_LO_32768: - tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); - buffer[3] |= TEA5767_XTAL_32768; - /* const 700=4000*175 Khz - to adjust freq to right value */ - div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; - break; - case TEA5767_HIGH_LO_32768: - default: - tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); - - buffer[2] |= TEA5767_HIGH_LO_INJECT; - buffer[3] |= TEA5767_XTAL_32768; - div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15; - break; - } - buffer[0] = (div >> 8) & 0x3f; - buffer[1] = div & 0xff; - - if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - - if (debug) { - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - else - tea5767_status_dump(priv, buffer); - } - - priv->frequency = frq * 125 / 2; - - return 0; -} - -static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) -{ - struct tea5767_priv *priv = fe->tuner_priv; - int rc; - - memset(buffer, 0, 5); - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - return -EREMOTEIO; - } - - return 0; -} - -static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) -{ - struct tea5767_priv *priv = fe->tuner_priv; - - int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); - - tuner_dbg("Signal strength: %d\n", signal); - - return signal; -} - -static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) -{ - struct tea5767_priv *priv = fe->tuner_priv; - - int stereo = buffer[2] & TEA5767_STEREO_MASK; - - tuner_dbg("Radio ST GET = %02x\n", stereo); - - return (stereo ? V4L2_TUNER_SUB_STEREO : 0); -} - -static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) -{ - unsigned char buffer[5]; - - *status = 0; - - if (0 == tea5767_read_status(fe, buffer)) { - if (tea5767_signal(fe, buffer)) - *status = TUNER_STATUS_LOCKED; - if (tea5767_stereo(fe, buffer)) - *status |= TUNER_STATUS_STEREO; - } - - return 0; -} - -static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - unsigned char buffer[5]; - - *strength = 0; - - if (0 == tea5767_read_status(fe, buffer)) - *strength = tea5767_signal(fe, buffer); - - return 0; -} - -static int tea5767_standby(struct dvb_frontend *fe) -{ - unsigned char buffer[5]; - struct tea5767_priv *priv = fe->tuner_priv; - unsigned div, rc; - - div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ - buffer[0] = (div >> 8) & 0x3f; - buffer[1] = div & 0xff; - buffer[2] = TEA5767_PORT1_HIGH; - buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | - TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; - buffer[4] = 0; - - if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - - return 0; -} - -int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) -{ - struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; - unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - int rc; - - if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { - printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); - return -EINVAL; - } - - /* If all bytes are the same then it's a TV tuner and not a tea5767 */ - if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && - buffer[0] == buffer[3] && buffer[0] == buffer[4]) { - printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); - return -EINVAL; - } - - /* Status bytes: - * Byte 4: bit 3:1 : CI (Chip Identification) == 0 - * bit 0 : internally set to 0 - * Byte 5: bit 7:0 : == 0 - */ - if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { - printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); - return -EINVAL; - } - - - return 0; -} - -static int tea5767_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - -static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tea5767_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - - return 0; -} - -static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) -{ - struct tea5767_priv *priv = fe->tuner_priv; - - memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); - - return 0; -} - -static struct dvb_tuner_ops tea5767_tuner_ops = { - .info = { - .name = "tea5767", // Philips TEA5767HN FM Radio - }, - - .set_analog_params = set_radio_freq, - .set_config = tea5767_set_config, - .sleep = tea5767_standby, - .release = tea5767_release, - .get_frequency = tea5767_get_frequency, - .get_status = tea5767_get_status, - .get_rf_strength = tea5767_get_rf_strength, -}; - -struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - struct tea5767_priv *priv = NULL; - - priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->tuner_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->i2c_props.name = "tea5767"; - - priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; - priv->ctrl.port1 = 1; - priv->ctrl.port2 = 1; - priv->ctrl.high_cut = 1; - priv->ctrl.st_noise = 1; - priv->ctrl.japan_band = 1; - - memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); - - return fe; -} - -EXPORT_SYMBOL_GPL(tea5767_attach); -EXPORT_SYMBOL_GPL(tea5767_autodetection); - -MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5767.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5767.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5767.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tea5767.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/* - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TEA5767_H__ -#define __TEA5767_H__ - -#include -#include "dvb_frontend.h" - -enum tea5767_xtal { - TEA5767_LOW_LO_32768 = 0, - TEA5767_HIGH_LO_32768 = 1, - TEA5767_LOW_LO_13MHz = 2, - TEA5767_HIGH_LO_13MHz = 3, -}; - -struct tea5767_ctrl { - unsigned int port1:1; - unsigned int port2:1; - unsigned int high_cut:1; - unsigned int st_noise:1; - unsigned int soft_mute:1; - unsigned int japan_band:1; - unsigned int deemph_75:1; - unsigned int pllref:1; - enum tea5767_xtal xtal_freq; -}; - -#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE)) -extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); - -extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr); -#else -static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __func__); - return -EINVAL; -} - -static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TEA5767_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-i2c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-i2c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -/* - tuner-i2c.h - i2c interface for different tuners - - Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TUNER_I2C_H__ -#define __TUNER_I2C_H__ - -#include -#include - -struct tuner_i2c_props { - u8 addr; - struct i2c_adapter *adap; - - /* used for tuner instance management */ - int count; - char *name; -}; - -static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) -{ - struct i2c_msg msg = { .addr = props->addr, .flags = 0, - .buf = buf, .len = len }; - int ret = i2c_transfer(props->adap, &msg, 1); - - return (ret == 1) ? len : ret; -} - -static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) -{ - struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, - .buf = buf, .len = len }; - int ret = i2c_transfer(props->adap, &msg, 1); - - return (ret == 1) ? len : ret; -} - -static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, - char *obuf, int olen, - char *ibuf, int ilen) -{ - struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, - .buf = obuf, .len = olen }, - { .addr = props->addr, .flags = I2C_M_RD, - .buf = ibuf, .len = ilen } }; - int ret = i2c_transfer(props->adap, msg, 2); - - return (ret == 2) ? ilen : ret; -} - -/* Callers must declare as a global for the module: - * - * static LIST_HEAD(hybrid_tuner_instance_list); - * - * hybrid_tuner_instance_list should be the third argument - * passed into hybrid_tuner_request_state(). - * - * state structure must contain the following: - * - * struct list_head hybrid_tuner_instance_list; - * struct tuner_i2c_props i2c_props; - * - * hybrid_tuner_instance_list (both within state structure and globally) - * is only required if the driver is using hybrid_tuner_request_state - * and hybrid_tuner_release_state to manage state sharing between - * multiple instances of hybrid tuners. - */ - -#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \ - printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \ - i2cprops.adap ? \ - i2c_adapter_id(i2cprops.adap) : -1, \ - i2cprops.addr, ##arg); \ - } while (0) - -/* TO DO: convert all callers of these macros to pass in - * struct tuner_i2c_props, then remove the macro wrappers */ - -#define __tuner_warn(i2cprops, fmt, arg...) do { \ - tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \ - } while (0) - -#define __tuner_info(i2cprops, fmt, arg...) do { \ - tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \ - } while (0) - -#define __tuner_err(i2cprops, fmt, arg...) do { \ - tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \ - } while (0) - -#define __tuner_dbg(i2cprops, fmt, arg...) do { \ - if ((debug)) \ - tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \ - } while (0) - -#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg) -#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg) -#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg) -#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg) - -/****************************************************************************/ - -/* The return value of hybrid_tuner_request_state indicates the number of - * instances using this tuner object. - * - * 0 - no instances, indicates an error - kzalloc must have failed - * - * 1 - one instance, indicates that the tuner object was created successfully - * - * 2 (or more) instances, indicates that an existing tuner object was found - */ - -#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\ -({ \ - int __ret = 0; \ - list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \ - if (((i2cadap) && (state->i2c_props.adap)) && \ - ((i2c_adapter_id(state->i2c_props.adap) == \ - i2c_adapter_id(i2cadap)) && \ - (i2caddr == state->i2c_props.addr))) { \ - __tuner_info(state->i2c_props, \ - "attaching existing instance\n"); \ - state->i2c_props.count++; \ - __ret = state->i2c_props.count; \ - break; \ - } \ - } \ - if (0 == __ret) { \ - state = kzalloc(sizeof(type), GFP_KERNEL); \ - if (NULL == state) \ - goto __fail; \ - state->i2c_props.addr = i2caddr; \ - state->i2c_props.adap = i2cadap; \ - state->i2c_props.name = devname; \ - __tuner_info(state->i2c_props, \ - "creating new instance\n"); \ - list_add_tail(&state->hybrid_tuner_instance_list, &list);\ - state->i2c_props.count++; \ - __ret = state->i2c_props.count; \ - } \ -__fail: \ - __ret; \ -}) - -#define hybrid_tuner_release_state(state) \ -({ \ - int __ret; \ - state->i2c_props.count--; \ - __ret = state->i2c_props.count; \ - if (!state->i2c_props.count) { \ - __tuner_info(state->i2c_props, "destroying instance\n");\ - list_del(&state->hybrid_tuner_instance_list); \ - kfree(state); \ - } \ - __ret; \ -}) - -#define hybrid_tuner_report_instance_count(state) \ -({ \ - int __ret = 0; \ - if (state) \ - __ret = state->i2c_props.count; \ - __ret; \ -}) - -#endif /* __TUNER_I2C_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-simple.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-simple.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-simple.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-simple.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1131 +0,0 @@ -/* - * i2c tv tuner chip device driver - * controls all those simple 4-control-bytes style tuners. - * - * This "tuner-simple" module was split apart from the original "tuner" module. - */ -#include -#include -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tuner-simple.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -#define TUNER_SIMPLE_MAX 64 -static unsigned int simple_devcount; - -static int offset; -module_param(offset, int, 0664); -MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner"); - -static unsigned int atv_input[TUNER_SIMPLE_MAX] = \ - { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; -static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \ - { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; -module_param_array(atv_input, int, NULL, 0644); -module_param_array(dtv_input, int, NULL, 0644); -MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect"); -MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect"); - -/* ---------------------------------------------------------------------- */ - -/* tv standard selection for Temic 4046 FM5 - this value takes the low bits of control byte 2 - from datasheet Rev.01, Feb.00 - standard BG I L L2 D - picture IF 38.9 38.9 38.9 33.95 38.9 - sound 1 33.4 32.9 32.4 40.45 32.4 - sound 2 33.16 - NICAM 33.05 32.348 33.05 33.05 - */ -#define TEMIC_SET_PAL_I 0x05 -#define TEMIC_SET_PAL_DK 0x09 -#define TEMIC_SET_PAL_L 0x0a /* SECAM ? */ -#define TEMIC_SET_PAL_L2 0x0b /* change IF ! */ -#define TEMIC_SET_PAL_BG 0x0c - -/* tv tuner system standard selection for Philips FQ1216ME - this value takes the low bits of control byte 2 - from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") - standard BG DK I L L` - picture carrier 38.90 38.90 38.90 38.90 33.95 - colour 34.47 34.47 34.47 34.47 38.38 - sound 1 33.40 32.40 32.90 32.40 40.45 - sound 2 33.16 - - - - - NICAM 33.05 33.05 32.35 33.05 39.80 - */ -#define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ -#define PHILIPS_SET_PAL_BGDK 0x09 -#define PHILIPS_SET_PAL_L2 0x0a -#define PHILIPS_SET_PAL_L 0x0b - -/* system switching for Philips FI1216MF MK2 - from datasheet "1996 Jul 09", - standard BG L L' - picture carrier 38.90 38.90 33.95 - colour 34.47 34.37 38.38 - sound 1 33.40 32.40 40.45 - sound 2 33.16 - - - NICAM 33.05 33.05 39.80 - */ -#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ -#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */ -#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */ - -/* Control byte */ - -#define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ -#define TUNER_RATIO_SELECT_50 0x00 -#define TUNER_RATIO_SELECT_32 0x02 -#define TUNER_RATIO_SELECT_166 0x04 -#define TUNER_RATIO_SELECT_62 0x06 - -#define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ - -/* Status byte */ - -#define TUNER_POR 0x80 -#define TUNER_FL 0x40 -#define TUNER_MODE 0x38 -#define TUNER_AFC 0x07 -#define TUNER_SIGNAL 0x07 -#define TUNER_STEREO 0x10 - -#define TUNER_PLL_LOCKED 0x40 -#define TUNER_STEREO_MK3 0x04 - -static DEFINE_MUTEX(tuner_simple_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -struct tuner_simple_priv { - unsigned int nr; - u16 last_div; - - struct tuner_i2c_props i2c_props; - struct list_head hybrid_tuner_instance_list; - - unsigned int type; - struct tunertype *tun; - - u32 frequency; - u32 bandwidth; -}; - -/* ---------------------------------------------------------------------- */ - -static int tuner_read_status(struct dvb_frontend *fe) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - unsigned char byte; - - if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1)) - return 0; - - return byte; -} - -static inline int tuner_signal(const int status) -{ - return (status & TUNER_SIGNAL) << 13; -} - -static inline int tuner_stereo(const int type, const int status) -{ - switch (type) { - case TUNER_PHILIPS_FM1216ME_MK3: - case TUNER_PHILIPS_FM1236_MK3: - case TUNER_PHILIPS_FM1256_IH3: - case TUNER_LG_NTSC_TAPE: - case TUNER_TCL_MF02GIP_5N: - return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); - case TUNER_PHILIPS_FM1216MK5: - return status | TUNER_STEREO; - default: - return status & TUNER_STEREO; - } -} - -static inline int tuner_islocked(const int status) -{ - return (status & TUNER_FL); -} - -static inline int tuner_afcstatus(const int status) -{ - return (status & TUNER_AFC) - 2; -} - - -static int simple_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int tuner_status; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - tuner_status = tuner_read_status(fe); - - *status = 0; - - if (tuner_islocked(tuner_status)) - *status = TUNER_STATUS_LOCKED; - if (tuner_stereo(priv->type, tuner_status)) - *status |= TUNER_STATUS_STEREO; - - tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); - - return 0; -} - -static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int signal; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - signal = tuner_signal(tuner_read_status(fe)); - - *strength = signal; - - tuner_dbg("Signal strength: %d\n", signal); - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static inline char *tuner_param_name(enum param_type type) -{ - char *name; - - switch (type) { - case TUNER_PARAM_TYPE_RADIO: - name = "radio"; - break; - case TUNER_PARAM_TYPE_PAL: - name = "pal"; - break; - case TUNER_PARAM_TYPE_SECAM: - name = "secam"; - break; - case TUNER_PARAM_TYPE_NTSC: - name = "ntsc"; - break; - case TUNER_PARAM_TYPE_DIGITAL: - name = "digital"; - break; - default: - name = "unknown"; - break; - } - return name; -} - -static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe, - enum param_type desired_type) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - struct tunertype *tun = priv->tun; - int i; - - for (i = 0; i < tun->count; i++) - if (desired_type == tun->params[i].type) - break; - - /* use default tuner params if desired_type not available */ - if (i == tun->count) { - tuner_dbg("desired params (%s) undefined for tuner %d\n", - tuner_param_name(desired_type), priv->type); - i = 0; - } - - tuner_dbg("using tuner params #%d (%s)\n", i, - tuner_param_name(tun->params[i].type)); - - return &tun->params[i]; -} - -static int simple_config_lookup(struct dvb_frontend *fe, - struct tuner_params *t_params, - unsigned *frequency, u8 *config, u8 *cb) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int i; - - for (i = 0; i < t_params->count; i++) { - if (*frequency > t_params->ranges[i].limit) - continue; - break; - } - if (i == t_params->count) { - tuner_dbg("frequency out of range (%d > %d)\n", - *frequency, t_params->ranges[i - 1].limit); - *frequency = t_params->ranges[--i].limit; - } - *config = t_params->ranges[i].config; - *cb = t_params->ranges[i].cb; - - tuner_dbg("freq = %d.%02d (%d), range = %d, " - "config = 0x%02x, cb = 0x%02x\n", - *frequency / 16, *frequency % 16 * 100 / 16, *frequency, - i, *config, *cb); - - return i; -} - -/* ---------------------------------------------------------------------- */ - -static void simple_set_rf_input(struct dvb_frontend *fe, - u8 *config, u8 *cb, unsigned int rf) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - switch (priv->type) { - case TUNER_PHILIPS_TUV1236D: - switch (rf) { - case 1: - *cb |= 0x08; - break; - default: - *cb &= ~0x08; - break; - } - break; - case TUNER_PHILIPS_FCV1236D: - switch (rf) { - case 1: - *cb |= 0x01; - break; - default: - *cb &= ~0x01; - break; - } - break; - default: - break; - } -} - -static int simple_std_setup(struct dvb_frontend *fe, - struct analog_parameters *params, - u8 *config, u8 *cb) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int rc; - - /* tv norm specific stuff for multi-norm tuners */ - switch (priv->type) { - case TUNER_PHILIPS_SECAM: /* FI1216MF */ - /* 0x01 -> ??? no change ??? */ - /* 0x02 -> PAL BDGHI / SECAM L */ - /* 0x04 -> ??? PAL others / SECAM others ??? */ - *cb &= ~0x03; - if (params->std & V4L2_STD_SECAM_L) - /* also valid for V4L2_STD_SECAM */ - *cb |= PHILIPS_MF_SET_STD_L; - else if (params->std & V4L2_STD_SECAM_LC) - *cb |= PHILIPS_MF_SET_STD_LC; - else /* V4L2_STD_B|V4L2_STD_GH */ - *cb |= PHILIPS_MF_SET_STD_BG; - break; - - case TUNER_TEMIC_4046FM5: - *cb &= ~0x0f; - - if (params->std & V4L2_STD_PAL_BG) { - *cb |= TEMIC_SET_PAL_BG; - - } else if (params->std & V4L2_STD_PAL_I) { - *cb |= TEMIC_SET_PAL_I; - - } else if (params->std & V4L2_STD_PAL_DK) { - *cb |= TEMIC_SET_PAL_DK; - - } else if (params->std & V4L2_STD_SECAM_L) { - *cb |= TEMIC_SET_PAL_L; - - } - break; - - case TUNER_PHILIPS_FQ1216ME: - *cb &= ~0x0f; - - if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { - *cb |= PHILIPS_SET_PAL_BGDK; - - } else if (params->std & V4L2_STD_PAL_I) { - *cb |= PHILIPS_SET_PAL_I; - - } else if (params->std & V4L2_STD_SECAM_L) { - *cb |= PHILIPS_SET_PAL_L; - - } - break; - - case TUNER_PHILIPS_FCV1236D: - /* 0x00 -> ATSC antenna input 1 */ - /* 0x01 -> ATSC antenna input 2 */ - /* 0x02 -> NTSC antenna input 1 */ - /* 0x03 -> NTSC antenna input 2 */ - *cb &= ~0x03; - if (!(params->std & V4L2_STD_ATSC)) - *cb |= 2; - break; - - case TUNER_MICROTUNE_4042FI5: - /* Set the charge pump for fast tuning */ - *config |= TUNER_CHARGE_PUMP; - break; - - case TUNER_PHILIPS_TUV1236D: - { - struct tuner_i2c_props i2c = priv->i2c_props; - /* 0x40 -> ATSC antenna input 1 */ - /* 0x48 -> ATSC antenna input 2 */ - /* 0x00 -> NTSC antenna input 1 */ - /* 0x08 -> NTSC antenna input 2 */ - u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00}; - *cb &= ~0x40; - if (params->std & V4L2_STD_ATSC) { - *cb |= 0x40; - buffer[1] = 0x04; - } - /* set to the correct mode (analog or digital) */ - i2c.addr = 0x0a; - rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2); - if (2 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 2)\n", rc); - rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2); - if (2 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 2)\n", rc); - break; - } - } - if (atv_input[priv->nr]) - simple_set_rf_input(fe, config, cb, atv_input[priv->nr]); - - return 0; -} - -static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int rc; - u8 buffer[2]; - - buffer[0] = (config & ~0x38) | 0x18; - buffer[1] = aux; - - tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]); - - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2); - if (2 != rc) - tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc); - - return rc == 2 ? 0 : rc; -} - -static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, - u16 div, u8 config, u8 cb) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int rc; - - switch (priv->type) { - case TUNER_LG_TDVS_H06XF: - simple_set_aux_byte(fe, config, 0x20); - break; - case TUNER_PHILIPS_FQ1216LME_MK3: - simple_set_aux_byte(fe, config, 0x60); /* External AGC */ - break; - case TUNER_MICROTUNE_4042FI5: - { - /* FIXME - this may also work for other tuners */ - unsigned long timeout = jiffies + msecs_to_jiffies(1); - u8 status_byte = 0; - - /* Wait until the PLL locks */ - for (;;) { - if (time_after(jiffies, timeout)) - return 0; - rc = tuner_i2c_xfer_recv(&priv->i2c_props, - &status_byte, 1); - if (1 != rc) { - tuner_warn("i2c i/o read error: rc == %d " - "(should be 1)\n", rc); - break; - } - if (status_byte & TUNER_PLL_LOCKED) - break; - udelay(10); - } - - /* Set the charge pump for optimized phase noise figure */ - config &= ~TUNER_CHARGE_PUMP; - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - buffer[2] = config; - buffer[3] = cb; - tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0], buffer[1], buffer[2], buffer[3]); - - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); - if (4 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 4)\n", rc); - break; - } - } - - return 0; -} - -static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - switch (priv->type) { - case TUNER_TENA_9533_DI: - case TUNER_YMEC_TVF_5533MF: - tuner_dbg("This tuner doesn't have FM. " - "Most cards have a TEA5767 for FM\n"); - return 0; - case TUNER_PHILIPS_FM1216ME_MK3: - case TUNER_PHILIPS_FM1236_MK3: - case TUNER_PHILIPS_FMD1216ME_MK3: - case TUNER_PHILIPS_FMD1216MEX_MK3: - case TUNER_LG_NTSC_TAPE: - case TUNER_PHILIPS_FM1256_IH3: - case TUNER_TCL_MF02GIP_5N: - buffer[3] = 0x19; - break; - case TUNER_PHILIPS_FM1216MK5: - buffer[2] = 0x88; - buffer[3] = 0x09; - break; - case TUNER_TNF_5335MF: - buffer[3] = 0x11; - break; - case TUNER_LG_PAL_FM: - buffer[3] = 0xa5; - break; - case TUNER_THOMSON_DTT761X: - buffer[3] = 0x39; - break; - case TUNER_PHILIPS_FQ1216LME_MK3: - case TUNER_PHILIPS_FQ1236_MK5: - tuner_err("This tuner doesn't have FM\n"); - /* Set the low band for sanity, since it covers 88-108 MHz */ - buffer[3] = 0x01; - break; - case TUNER_MICROTUNE_4049FM5: - default: - buffer[3] = 0xa4; - break; - } - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -static int simple_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - u8 config, cb; - u16 div; - u8 buffer[4]; - int rc, IFPCoff, i; - enum param_type desired_type; - struct tuner_params *t_params; - - /* IFPCoff = Video Intermediate Frequency - Vif: - 940 =16*58.75 NTSC/J (Japan) - 732 =16*45.75 M/N STD - 704 =16*44 ATSC (at DVB code) - 632 =16*39.50 I U.K. - 622.4=16*38.90 B/G D/K I, L STD - 592 =16*37.00 D China - 590 =16.36.875 B Australia - 543.2=16*33.95 L' STD - 171.2=16*10.70 FM Radio (at set_radio_freq) - */ - - if (params->std == V4L2_STD_NTSC_M_JP) { - IFPCoff = 940; - desired_type = TUNER_PARAM_TYPE_NTSC; - } else if ((params->std & V4L2_STD_MN) && - !(params->std & ~V4L2_STD_MN)) { - IFPCoff = 732; - desired_type = TUNER_PARAM_TYPE_NTSC; - } else if (params->std == V4L2_STD_SECAM_LC) { - IFPCoff = 543; - desired_type = TUNER_PARAM_TYPE_SECAM; - } else { - IFPCoff = 623; - desired_type = TUNER_PARAM_TYPE_PAL; - } - - t_params = simple_tuner_params(fe, desired_type); - - i = simple_config_lookup(fe, t_params, ¶ms->frequency, - &config, &cb); - - div = params->frequency + IFPCoff + offset; - - tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, " - "Offset=%d.%02d MHz, div=%0d\n", - params->frequency / 16, params->frequency % 16 * 100 / 16, - IFPCoff / 16, IFPCoff % 16 * 100 / 16, - offset / 16, offset % 16 * 100 / 16, div); - - /* tv norm specific stuff for multi-norm tuners */ - simple_std_setup(fe, params, &config, &cb); - - if (t_params->cb_first_if_lower_freq && div < priv->last_div) { - buffer[0] = config; - buffer[1] = cb; - buffer[2] = (div>>8) & 0x7f; - buffer[3] = div & 0xff; - } else { - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - buffer[2] = config; - buffer[3] = cb; - } - priv->last_div = div; - if (t_params->has_tda9887) { - struct v4l2_priv_tun_config tda9887_cfg; - int tda_config = 0; - int is_secam_l = (params->std & (V4L2_STD_SECAM_L | - V4L2_STD_SECAM_LC)) && - !(params->std & ~(V4L2_STD_SECAM_L | - V4L2_STD_SECAM_LC)); - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &tda_config; - - if (params->std == V4L2_STD_SECAM_LC) { - if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) - tda_config |= TDA9887_PORT1_ACTIVE; - if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) - tda_config |= TDA9887_PORT2_ACTIVE; - } else { - if (t_params->port1_active) - tda_config |= TDA9887_PORT1_ACTIVE; - if (t_params->port2_active) - tda_config |= TDA9887_PORT2_ACTIVE; - } - if (t_params->intercarrier_mode) - tda_config |= TDA9887_INTERCARRIER; - if (is_secam_l) { - if (i == 0 && t_params->default_top_secam_low) - tda_config |= TDA9887_TOP(t_params->default_top_secam_low); - else if (i == 1 && t_params->default_top_secam_mid) - tda_config |= TDA9887_TOP(t_params->default_top_secam_mid); - else if (t_params->default_top_secam_high) - tda_config |= TDA9887_TOP(t_params->default_top_secam_high); - } else { - if (i == 0 && t_params->default_top_low) - tda_config |= TDA9887_TOP(t_params->default_top_low); - else if (i == 1 && t_params->default_top_mid) - tda_config |= TDA9887_TOP(t_params->default_top_mid); - else if (t_params->default_top_high) - tda_config |= TDA9887_TOP(t_params->default_top_high); - } - if (t_params->default_pll_gating_18) - tda_config |= TDA9887_GATING_18; - i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, - &tda9887_cfg); - } - tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0], buffer[1], buffer[2], buffer[3]); - - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); - if (4 != rc) - tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); - - simple_post_tune(fe, &buffer[0], div, config, cb); - - return 0; -} - -static int simple_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tunertype *tun; - struct tuner_simple_priv *priv = fe->tuner_priv; - u8 buffer[4]; - u16 div; - int rc, j; - struct tuner_params *t_params; - unsigned int freq = params->frequency; - - tun = priv->tun; - - for (j = tun->count-1; j > 0; j--) - if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) - break; - /* default t_params (j=0) will be used if desired type wasn't found */ - t_params = &tun->params[j]; - - /* Select Radio 1st IF used */ - switch (t_params->radio_if) { - case 0: /* 10.7 MHz */ - freq += (unsigned int)(10.7*16000); - break; - case 1: /* 33.3 MHz */ - freq += (unsigned int)(33.3*16000); - break; - case 2: /* 41.3 MHz */ - freq += (unsigned int)(41.3*16000); - break; - default: - tuner_warn("Unsupported radio_if value %d\n", - t_params->radio_if); - return 0; - } - - buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | - TUNER_RATIO_SELECT_50; /* 50 kHz step */ - - /* Bandswitch byte */ - simple_radio_bandswitch(fe, &buffer[0]); - - /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps - freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = - freq * (1/800) */ - div = (freq + 400) / 800; - - if (t_params->cb_first_if_lower_freq && div < priv->last_div) { - buffer[0] = buffer[2]; - buffer[1] = buffer[3]; - buffer[2] = (div>>8) & 0x7f; - buffer[3] = div & 0xff; - } else { - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - } - - tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", - buffer[0], buffer[1], buffer[2], buffer[3]); - priv->last_div = div; - - if (t_params->has_tda9887) { - int config = 0; - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &config; - - if (t_params->port1_active && - !t_params->port1_fm_high_sensitivity) - config |= TDA9887_PORT1_ACTIVE; - if (t_params->port2_active && - !t_params->port2_fm_high_sensitivity) - config |= TDA9887_PORT2_ACTIVE; - if (t_params->intercarrier_mode) - config |= TDA9887_INTERCARRIER; -/* if (t_params->port1_set_for_fm_mono) - config &= ~TDA9887_PORT1_ACTIVE;*/ - if (t_params->fm_gain_normal) - config |= TDA9887_GAIN_NORMAL; - if (t_params->radio_if == 2) - config |= TDA9887_RIF_41_3; - i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, - &tda9887_cfg); - } - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); - if (4 != rc) - tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); - - return 0; -} - -static int simple_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - switch (params->mode) { - case V4L2_TUNER_RADIO: - ret = simple_set_radio_freq(fe, params); - priv->frequency = params->frequency * 125 / 2; - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = simple_set_tv_freq(fe, params); - priv->frequency = params->frequency * 62500; - break; - } - priv->bandwidth = 0; - - return ret; -} - -static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - switch (priv->type) { - case TUNER_PHILIPS_FMD1216ME_MK3: - case TUNER_PHILIPS_FMD1216MEX_MK3: - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && - params->frequency >= 158870000) - buf[3] |= 0x08; - break; - case TUNER_PHILIPS_TD1316: - /* determine band */ - buf[3] |= (params->frequency < 161000000) ? 1 : - (params->frequency < 444000000) ? 2 : 4; - - /* setup PLL filter */ - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) - buf[3] |= 1 << 3; - break; - case TUNER_PHILIPS_TUV1236D: - case TUNER_PHILIPS_FCV1236D: - { - unsigned int new_rf; - - if (dtv_input[priv->nr]) - new_rf = dtv_input[priv->nr]; - else - switch (params->u.vsb.modulation) { - case QAM_64: - case QAM_256: - new_rf = 1; - break; - case VSB_8: - default: - new_rf = 0; - break; - } - simple_set_rf_input(fe, &buf[2], &buf[3], new_rf); - break; - } - default: - break; - } -} - -static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) -{ - /* This function returns the tuned frequency on success, 0 on error */ - struct tuner_simple_priv *priv = fe->tuner_priv; - struct tunertype *tun = priv->tun; - static struct tuner_params *t_params; - u8 config, cb; - u32 div; - int ret; - unsigned frequency = params->frequency / 62500; - - if (!tun->stepsize) { - /* tuner-core was loaded before the digital tuner was - * configured and somehow picked the wrong tuner type */ - tuner_err("attempt to treat tuner %d (%s) as digital tuner " - "without stepsize defined.\n", - priv->type, priv->tun->name); - return 0; /* failure */ - } - - t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); - ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); - if (ret < 0) - return 0; /* failure */ - - div = ((frequency + t_params->iffreq) * 62500 + offset + - tun->stepsize/2) / tun->stepsize; - - buf[0] = div >> 8; - buf[1] = div & 0xff; - buf[2] = config; - buf[3] = cb; - - simple_set_dvb(fe, buf, params); - - tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", - tun->name, div, buf[0], buf[1], buf[2], buf[3]); - - /* calculate the frequency we set it to */ - return (div * tun->stepsize) - t_params->iffreq; -} - -static int simple_dvb_calc_regs(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, - u8 *buf, int buf_len) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - u32 frequency; - - if (buf_len < 5) - return -EINVAL; - - frequency = simple_dvb_configure(fe, buf+1, params); - if (frequency == 0) - return -EINVAL; - - buf[0] = priv->i2c_props.addr; - - priv->frequency = frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; - - return 5; -} - -static int simple_dvb_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - u32 prev_freq, prev_bw; - int ret; - u8 buf[5]; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - prev_freq = priv->frequency; - prev_bw = priv->bandwidth; - - ret = simple_dvb_calc_regs(fe, params, buf, 5); - if (ret != 5) - goto fail; - - /* put analog demod in standby when tuning digital */ - if (fe->ops.analog_ops.standby) - fe->ops.analog_ops.standby(fe); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* buf[0] contains the i2c address, but * - * we already have it in i2c_props.addr */ - ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4); - if (ret != 4) - goto fail; - - return 0; -fail: - /* calc_regs sets frequency and bandwidth. if we failed, unset them */ - priv->frequency = prev_freq; - priv->bandwidth = prev_bw; - - return ret; -} - -static int simple_init(struct dvb_frontend *fe) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - if (priv->tun->initdata) { - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = tuner_i2c_xfer_send(&priv->i2c_props, - priv->tun->initdata + 1, - priv->tun->initdata[0]); - if (ret != priv->tun->initdata[0]) - return ret; - } - - return 0; -} - -static int simple_sleep(struct dvb_frontend *fe) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - if (priv->tun->sleepdata) { - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = tuner_i2c_xfer_send(&priv->i2c_props, - priv->tun->sleepdata + 1, - priv->tun->sleepdata[0]); - if (ret != priv->tun->sleepdata[0]) - return ret; - } - - return 0; -} - -static int simple_release(struct dvb_frontend *fe) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - - mutex_lock(&tuner_simple_list_mutex); - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&tuner_simple_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct tuner_simple_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static struct dvb_tuner_ops simple_tuner_ops = { - .init = simple_init, - .sleep = simple_sleep, - .set_analog_params = simple_set_params, - .set_params = simple_dvb_set_params, - .calc_regs = simple_dvb_calc_regs, - .release = simple_release, - .get_frequency = simple_get_frequency, - .get_bandwidth = simple_get_bandwidth, - .get_status = simple_get_status, - .get_rf_strength = simple_get_rf_strength, -}; - -struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - unsigned int type) -{ - struct tuner_simple_priv *priv = NULL; - int instance; - - if (type >= tuner_count) { - printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n", - __func__, type, tuner_count-1); - return NULL; - } - - /* If i2c_adap is set, check that the tuner is at the correct address. - * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly - * by the digital demod via calc_regs. - */ - if (i2c_adap != NULL) { - u8 b[1]; - struct i2c_msg msg = { - .addr = i2c_addr, .flags = I2C_M_RD, - .buf = b, .len = 1, - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (1 != i2c_transfer(i2c_adap, &msg, 1)) - printk(KERN_WARNING "tuner-simple %d-%04x: " - "unable to probe %s, proceeding anyway.", - i2c_adapter_id(i2c_adap), i2c_addr, - tuners[type].name); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - mutex_lock(&tuner_simple_list_mutex); - - instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv, - hybrid_tuner_instance_list, - i2c_adap, i2c_addr, - "tuner-simple"); - switch (instance) { - case 0: - mutex_unlock(&tuner_simple_list_mutex); - return NULL; - case 1: - fe->tuner_priv = priv; - - priv->type = type; - priv->tun = &tuners[type]; - priv->nr = simple_devcount++; - break; - default: - fe->tuner_priv = priv; - break; - } - - mutex_unlock(&tuner_simple_list_mutex); - - memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - if (type != priv->type) - tuner_warn("couldn't set type to %d. Using %d (%s) instead\n", - type, priv->type, priv->tun->name); - else - tuner_info("type set to %d (%s)\n", - priv->type, priv->tun->name); - - if ((debug) || ((atv_input[priv->nr] > 0) || - (dtv_input[priv->nr] > 0))) { - if (0 == atv_input[priv->nr]) - tuner_info("tuner %d atv rf input will be " - "autoselected\n", priv->nr); - else - tuner_info("tuner %d atv rf input will be " - "set to input %d (insmod option)\n", - priv->nr, atv_input[priv->nr]); - if (0 == dtv_input[priv->nr]) - tuner_info("tuner %d dtv rf input will be " - "autoselected\n", priv->nr); - else - tuner_info("tuner %d dtv rf input will be " - "set to input %d (insmod option)\n", - priv->nr, dtv_input[priv->nr]); - } - - strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name, - sizeof(fe->ops.tuner_ops.info.name)); - - return fe; -} -EXPORT_SYMBOL_GPL(simple_tuner_attach); - -MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); -MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-simple.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-simple.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-simple.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-simple.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TUNER_SIMPLE_H__ -#define __TUNER_SIMPLE_H__ - -#include -#include "dvb_frontend.h" - -#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE)) -extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - unsigned int type); -#else -static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - unsigned int type) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* __TUNER_SIMPLE_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-types.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-types.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-types.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-types.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1874 +0,0 @@ -/* - * - * i2c tv tuner chip device type database. - * - */ - -#include -#include -#include - -/* ---------------------------------------------------------------------- */ - -/* - * The floats in the tuner struct are computed at compile time - * by gcc and cast back to integers. Thus we don't violate the - * "no float in kernel" rule. - * - * A tuner_range may be referenced by multiple tuner_params structs. - * There are many duplicates in here. Reusing tuner_range structs, - * rather than defining new ones for each tuner, will cut down on - * memory usage, and is preferred when possible. - * - * Each tuner_params array may contain one or more elements, one - * for each video standard. - * - * FIXME: tuner_params struct contains an element, tda988x. We must - * set this for all tuners that contain a tda988x chip, and then we - * can remove this setting from the various card structs. - * - * FIXME: Right now, all tuners are using the first tuner_params[] - * array element for analog mode. In the future, we will be merging - * similar tuner definitions together, such that each tuner definition - * will have a tuner_params struct for each available video standard. - * At that point, the tuner_params[] array element will be chosen - * based on the video standard in use. - */ - -/* The following was taken from dvb-pll.c: */ - -/* Set AGC TOP value to 103 dBuV: - * 0x80 = Control Byte - * 0x40 = 250 uA charge pump (irrelevant) - * 0x18 = Aux Byte to follow - * 0x06 = 64.5 kHz divider (irrelevant) - * 0x01 = Disable Vt (aka sleep) - * - * 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA) - * 0x50 = AGC Take over point = 103 dBuV - */ -static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; - -/* 0x04 = 166.67 kHz divider - * - * 0x80 = AGC Time constant 50ms Iagc = 9 uA - * 0x20 = AGC Take over point = 112 dBuV - */ -static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 }; - -/* 0-9 */ -/* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */ - -static struct tuner_range tuner_temic_pal_ranges[] = { - { 16 * 140.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, - { 16 * 999.99 , 0x8e, 0x01, }, -}; - -static struct tuner_params tuner_temic_pal_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_pal_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */ - -static struct tuner_range tuner_philips_pal_i_ranges[] = { - { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_pal_i_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_pal_i_ranges, - .count = ARRAY_SIZE(tuner_philips_pal_i_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */ - -static struct tuner_range tuner_philips_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 451.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_ntsc_ranges, - .count = ARRAY_SIZE(tuner_philips_ntsc_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */ - -static struct tuner_range tuner_philips_secam_ranges[] = { - { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, }, - { 16 * 447.25 /*MHz*/, 0x8e, 0x97, }, - { 16 * 999.99 , 0x8e, 0x37, }, -}; - -static struct tuner_params tuner_philips_secam_params[] = { - { - .type = TUNER_PARAM_TYPE_SECAM, - .ranges = tuner_philips_secam_ranges, - .count = ARRAY_SIZE(tuner_philips_secam_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_pal_ranges[] = { - { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 447.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_pal_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_pal_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */ - -static struct tuner_range tuner_temic_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, - { 16 * 999.99 , 0x8e, 0x01, }, -}; - -static struct tuner_params tuner_temic_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_ntsc_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */ - -static struct tuner_range tuner_temic_pal_i_ranges[] = { - { 16 * 170.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 450.00 /*MHz*/, 0x8e, 0x04, }, - { 16 * 999.99 , 0x8e, 0x01, }, -}; - -static struct tuner_params tuner_temic_pal_i_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_pal_i_ranges, - .count = ARRAY_SIZE(tuner_temic_pal_i_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */ - -static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_4036fy5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */ - -static struct tuner_range tuner_alps_tsb_1_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 385.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_alps_tsb_1_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), - }, -}; - -/* 10-19 */ -/* ------------ TUNER_ALPS_TSBE1_PAL - TEMIC PAL ------------ */ - -static struct tuner_params tuner_alps_tsb_1_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_alps_tsb_1_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */ - -static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = { - { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 351.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_alps_tsbb5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_alps_tsb_5_pal_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSBE5_PAL - Alps PAL ------------ */ - -static struct tuner_params tuner_alps_tsbe5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_alps_tsb_5_pal_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSBC5_PAL - Alps PAL ------------ */ - -static struct tuner_params tuner_alps_tsbc5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_alps_tsb_5_pal_ranges, - .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */ - -static struct tuner_range tuner_lg_pal_ranges[] = { - { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 450.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4006fh5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */ - -static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x14, }, - { 16 * 385.25 /*MHz*/, 0x8e, 0x12, }, - { 16 * 999.99 , 0x8e, 0x11, }, -}; - -static struct tuner_params tuner_alps_tshc6_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_alps_tshc6_ntsc_ranges, - .count = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */ - -static struct tuner_range tuner_temic_pal_dk_ranges[] = { - { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 456.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_pal_dk_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_pal_dk_ranges, - .count = ARRAY_SIZE(tuner_temic_pal_dk_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */ - -static struct tuner_range tuner_philips_ntsc_m_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_ntsc_m_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_ntsc_m_ranges, - .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */ - -static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = { - { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_40x6f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4006FN5_MULTI_PAL - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4006fn5_multi_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_40x6f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), - }, -}; - -/* 20-29 */ -/* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */ - -static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = { - { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 464.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4009f_5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4009f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */ - -static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = { - { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_temic_4039fr5_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4046fm5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_40x6f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */ - -static struct tuner_params tuner_philips_pal_dk_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1216ME - Philips PAL ------------ */ - -static struct tuner_params tuner_philips_fq1216me_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - }, -}; - -/* ------------ TUNER_LG_PAL_I_FM - LGINNOTEK PAL_I ------------ */ - -static struct tuner_params tuner_lg_pal_i_fm_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_LG_PAL_I - LGINNOTEK PAL_I ------------ */ - -static struct tuner_params tuner_lg_pal_i_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */ - -static struct tuner_range tuner_lg_ntsc_fm_ranges[] = { - { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 497.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_lg_ntsc_fm_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_ntsc_fm_ranges, - .count = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges), - }, -}; - -/* ------------ TUNER_LG_PAL_FM - LGINNOTEK PAL ------------ */ - -static struct tuner_params tuner_lg_pal_fm_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* ------------ TUNER_LG_PAL - LGINNOTEK PAL ------------ */ - -static struct tuner_params tuner_lg_pal_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_pal_ranges, - .count = ARRAY_SIZE(tuner_lg_pal_ranges), - }, -}; - -/* 30-39 */ -/* ------------ TUNER_TEMIC_4009FN5_MULTI_PAL_FM - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4009f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */ - -static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 317.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_sharp_2u5jf5540_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_sharp_2u5jf5540_ntsc_ranges, - .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges), - }, -}; - -/* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */ - -static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = { - { 16 * 169 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 464 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_samsung_pal_tcpm9091pd27_ranges, - .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4106FH5 - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4106fh5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4009f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */ - -static struct tuner_params tuner_temic_4012fy5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_pal_ranges), - }, -}; - -/* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */ - -static struct tuner_params tuner_temic_4136_fy5_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), - }, -}; - -/* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */ - -static struct tuner_range tuner_lg_new_tapc_ranges[] = { - { 16 * 170.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 450.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_lg_pal_new_tapc_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_new_tapc_ranges, - .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */ - -static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = { - { 16 * 158.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_fm1216me_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_fm1216me_mk3_pal_ranges, - .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), - .cb_first_if_lower_freq = 1, - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - .port1_fm_high_sensitivity = 1, - .default_top_mid = -2, - .default_top_secam_mid = -2, - .default_top_secam_high = -2, - }, -}; - -/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */ - -static struct tuner_range tuner_fm1216mk5_pal_ranges[] = { - { 16 * 158.00 /*MHz*/, 0xce, 0x01, }, - { 16 * 441.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 864.00 , 0xce, 0x04, }, -}; - -static struct tuner_params tuner_fm1216mk5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_fm1216mk5_pal_ranges, - .count = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges), - .cb_first_if_lower_freq = 1, - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - .port1_fm_high_sensitivity = 1, - .default_top_mid = -2, - .default_top_secam_mid = -2, - .default_top_secam_high = -2, - }, -}; - -/* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */ - -static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_new_tapc_ranges, - .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), - }, -}; - -/* 40-49 */ -/* ------------ TUNER_HITACHI_NTSC - HITACHI NTSC ------------ */ - -static struct tuner_params tuner_hitachi_ntsc_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_new_tapc_ranges, - .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = { - { 16 * 140.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, }, - { 16 * 999.99 , 0x8e, 0xcf, }, -}; - -static struct tuner_params tuner_philips_pal_mk_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_pal_mk_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges), - }, -}; - -/* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */ - -static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0xa2, }, - { 16 * 451.25 /*MHz*/, 0x8e, 0x92, }, - { 16 * 999.99 , 0x8e, 0x32, }, -}; - -static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = { - { 16 * 159.00 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_philips_fcv1236d_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_fcv1236d_ntsc_ranges, - .count = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_philips_fcv1236d_atsc_ranges, - .count = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges), - .iffreq = 16 * 44.00, - }, -}; - -/* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */ - -static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_fm1236_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - .cb_first_if_lower_freq = 1, - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port1_fm_high_sensitivity = 1, - }, -}; - -/* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */ - -static struct tuner_params tuner_philips_4in1_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - }, -}; - -/* ------------ TUNER_MICROTUNE_4049FM5 - Microtune PAL ------------ */ - -static struct tuner_params tuner_microtune_4049_fm5_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4009f_5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - .has_tda9887 = 1, - .port1_invert_for_secam_lc = 1, - .default_pll_gating_18 = 1, - .fm_gain_normal=1, - .radio_if = 1, /* 33.3 MHz */ - }, -}; - -/* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */ - -static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, - { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x08, }, -}; - -static struct tuner_params tuner_panasonic_vp27_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_panasonic_vp27_ntsc_ranges, - .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), - .has_tda9887 = 1, - .intercarrier_mode = 1, - .default_top_low = -3, - .default_top_mid = -3, - .default_top_high = -3, - }, -}; - -/* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */ - -static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = { - { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, - { 16 * 999.99 , 0x8e, 0x30, }, -}; - -static struct tuner_params tuner_tnf_8831bgff_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_tnf_8831bgff_pal_ranges, - .count = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges), - }, -}; - -/* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */ - -static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = { - { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, }, - { 16 * 457.00 /*MHz*/, 0x8e, 0x94, }, - { 16 * 999.99 , 0x8e, 0x31, }, -}; - -static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = { - { 16 * 162.00 /*MHz*/, 0x8e, 0xa1, }, - { 16 * 457.00 /*MHz*/, 0x8e, 0x91, }, - { 16 * 999.99 , 0x8e, 0x31, }, -}; - -static struct tuner_params tuner_microtune_4042fi5_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_microtune_4042fi5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_microtune_4042fi5_atsc_ranges, - .count = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges), - .iffreq = 16 * 44.00 /*MHz*/, - }, -}; - -/* 50-59 */ -/* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */ - -static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = { - { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_tcl_2002n_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tcl_2002n_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */ - -static struct tuner_params tuner_philips_fm1256_ih3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - .radio_if = 1, /* 33.3 MHz */ - }, -}; - -/* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */ - -/* single range used for both ntsc and atsc */ -static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x8e, 0x39, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, }, - { 16 * 999.99 , 0x8e, 0x3c, }, -}; - -static struct tuner_params tuner_thomson_dtt7610_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_thomson_dtt7610_ntsc_ranges, - .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_thomson_dtt7610_ntsc_ranges, - .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), - .iffreq = 16 * 44.00 /*MHz*/, - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */ - -static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x8e, 0x41, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x42, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_philips_fq1286_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_fq1286_ntsc_ranges, - .count = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges), - }, -}; - -/* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */ - -static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = { - { 16 * 170.00 /*MHz*/, 0xce, 0x01, }, - { 16 * 450.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x08, }, -}; - -static struct tuner_params tuner_tcl_2002mb_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_tcl_2002mb_pal_ranges, - .count = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, - { 16 * 442.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x04, }, -}; - -static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_fq12_6a___mk4_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_invert_for_secam_lc = 1, - .default_top_mid = -2, - .default_top_secam_low = -2, - .default_top_secam_mid = -2, - .default_top_secam_high = -2, - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1236A_MK4 - Philips NTSC ------------ */ - -static struct tuner_params tuner_philips_fq1236a_mk4_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - }, -}; - -/* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */ - -static struct tuner_params tuner_ymec_tvf_8531mf_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_ntsc_m_ranges, - .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), - }, -}; - -/* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */ - -static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_ymec_tvf_5533mf_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_ymec_tvf_5533mf_ntsc_ranges, - .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges), - }, -}; - -/* 60-69 */ -/* ------------ TUNER_THOMSON_DTT761X - THOMSON ATSC ------------ */ -/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ - -static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = { - { 16 * 145.25 /*MHz*/, 0x8e, 0x39, }, - { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, }, - { 16 * 999.99 , 0x8e, 0x3c, }, -}; - -static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = { - { 16 * 147.00 /*MHz*/, 0x8e, 0x39, }, - { 16 * 417.00 /*MHz*/, 0x8e, 0x3a, }, - { 16 * 999.99 , 0x8e, 0x3c, }, -}; - -static struct tuner_params tuner_thomson_dtt761x_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_thomson_dtt761x_ntsc_ranges, - .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), - .has_tda9887 = 1, - .fm_gain_normal = 1, - .radio_if = 2, /* 41.3 MHz */ - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_thomson_dtt761x_atsc_ranges, - .count = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges), - .iffreq = 16 * 44.00, /*MHz*/ - }, -}; - -/* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */ - -static struct tuner_range tuner_tena_9533_di_pal_ranges[] = { - { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_tena_9533_di_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_tena_9533_di_pal_ranges, - .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges), - }, -}; - -/* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */ - -static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = { - { 16 * 166.25 /*MHz*/, 0x86, 0x01, }, - { 16 * 466.25 /*MHz*/, 0x86, 0x02, }, - { 16 * 999.99 , 0x86, 0x08, }, -}; - -static struct tuner_params tuner_tena_tnf_5337_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tena_tnf_5337_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x86, 0x51, }, - { 16 * 442.00 /*MHz*/, 0x86, 0x52, }, - { 16 * 999.99 , 0x86, 0x54, }, -}; - -static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = { - { 16 * 143.87 /*MHz*/, 0xbc, 0x41 }, - { 16 * 158.87 /*MHz*/, 0xf4, 0x41 }, - { 16 * 329.87 /*MHz*/, 0xbc, 0x42 }, - { 16 * 441.87 /*MHz*/, 0xf4, 0x42 }, - { 16 * 625.87 /*MHz*/, 0xbc, 0x44 }, - { 16 * 803.87 /*MHz*/, 0xf4, 0x44 }, - { 16 * 999.99 , 0xfc, 0x44 }, -}; - -static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_fm_high_sensitivity = 1, - .port2_invert_for_secam_lc = 1, - .port1_set_for_fm_mono = 1, - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), - .iffreq = 16 * 36.125, /*MHz*/ - }, -}; - -static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_fm_high_sensitivity = 1, - .port2_invert_for_secam_lc = 1, - .port1_set_for_fm_mono = 1, - .radio_if = 1, - .fm_gain_normal = 1, - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), - .iffreq = 16 * 36.125, /*MHz*/ - }, -}; - -/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */ - -static struct tuner_range tuner_tua6034_ntsc_ranges[] = { - { 16 * 165.00 /*MHz*/, 0x8e, 0x01 }, - { 16 * 450.00 /*MHz*/, 0x8e, 0x02 }, - { 16 * 999.99 , 0x8e, 0x04 }, -}; - -static struct tuner_range tuner_tua6034_atsc_ranges[] = { - { 16 * 165.00 /*MHz*/, 0xce, 0x01 }, - { 16 * 450.00 /*MHz*/, 0xce, 0x02 }, - { 16 * 999.99 , 0xce, 0x04 }, -}; - -static struct tuner_params tuner_lg_tdvs_h06xf_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tua6034_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_tua6034_atsc_ranges, - .count = ARRAY_SIZE(tuner_tua6034_atsc_ranges), - .iffreq = 16 * 44.00, - }, -}; - -/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */ - -static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = { - { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges, - .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges), - }, -}; - -/* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */ - -static struct tuner_range tuner_lg_taln_ntsc_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 373.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = { - { 16 * 150.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 425.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_lg_taln_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_taln_ntsc_ranges, - .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges), - },{ - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_lg_taln_pal_secam_ranges, - .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */ - -static struct tuner_range tuner_philips_td1316_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, }, - { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, }, - { 16 * 999.99 , 0xc8, 0xa4, }, -}; - -static struct tuner_range tuner_philips_td1316_dvb_ranges[] = { - { 16 * 93.834 /*MHz*/, 0xca, 0x60, }, - { 16 * 123.834 /*MHz*/, 0xca, 0xa0, }, - { 16 * 163.834 /*MHz*/, 0xca, 0xc0, }, - { 16 * 253.834 /*MHz*/, 0xca, 0x60, }, - { 16 * 383.834 /*MHz*/, 0xca, 0xa0, }, - { 16 * 443.834 /*MHz*/, 0xca, 0xc0, }, - { 16 * 583.834 /*MHz*/, 0xca, 0x60, }, - { 16 * 793.834 /*MHz*/, 0xca, 0xa0, }, - { 16 * 999.999 , 0xca, 0xe0, }, -}; - -static struct tuner_params tuner_philips_td1316_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_td1316_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_philips_td1316_dvb_ranges, - .count = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges), - .iffreq = 16 * 36.166667 /*MHz*/, - }, -}; - -/* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */ - -static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0xce, 0x01, }, - { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, - { 16 * 999.99 , 0xce, 0x04, }, -}; - -static struct tuner_range tuner_tuv1236d_atsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0xc6, 0x41, }, - { 16 * 454.00 /*MHz*/, 0xc6, 0x42, }, - { 16 * 999.99 , 0xc6, 0x44, }, -}; - -static struct tuner_params tuner_tuv1236d_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tuv1236d_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_tuv1236d_atsc_ranges, - .count = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges), - .iffreq = 16 * 44.00, - }, -}; - -/* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */ -/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF - * but it is expected to work also with other Tenna/Ymec - * models based on TI SN 761677 chip on both PAL and NTSC - */ - -static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = { - { 16 * 168.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 471.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = { - { 16 * 169.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 469.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x08, }, -}; - -static struct tuner_params tuner_tnf_5335mf_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tnf_5335mf_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges), - }, - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_tnf_5335_d_if_pal_ranges, - .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges), - }, -}; - -/* 70-79 */ -/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */ - -/* '+ 4' turns on the Low Noise Amplifier */ -static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = { - { 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, }, - { 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, }, - { 16 * 999.99 , 0xce, 0x08 + 4, }, -}; - -static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, - .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), - }, -}; - -/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */ - -static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xfe, 0x11, }, - { 16 * 442.00 /*MHz*/, 0xf6, 0x12, }, - { 16 * 999.99 , 0xf6, 0x18, }, -}; - -static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = { - { 16 * 250.00 /*MHz*/, 0xb4, 0x12, }, - { 16 * 455.00 /*MHz*/, 0xfe, 0x11, }, - { 16 * 775.50 /*MHz*/, 0xbc, 0x18, }, - { 16 * 999.99 , 0xf4, 0x18, }, -}; - -static struct tuner_params tuner_thomson_fe6600_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_thomson_fe6600_pal_ranges, - .count = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges), - }, - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_thomson_fe6600_dvb_ranges, - .count = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges), - .iffreq = 16 * 36.125 /*MHz*/, - }, -}; - -/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */ - -/* '+ 4' turns on the Low Noise Amplifier */ -static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = { - { 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, }, - { 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, }, - { 16 * 999.99 , 0xce, 0x08 + 4, }, -}; - -static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges, - .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges), - .has_tda9887 = 1, - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - }, -}; - -/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */ - -static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = { - { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, - { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_tcl_mf02gip_5n_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges, - .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges), - .cb_first_if_lower_freq = 1, - }, -}; - -/* 80-89 */ -/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */ - -static struct tuner_params tuner_fq1216lme_mk3_params[] = { - { - .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_fm1216me_mk3_pal_ranges, - .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), - .cb_first_if_lower_freq = 1, /* not specified, but safe to do */ - .has_tda9887 = 1, /* TDA9886 */ - .port1_active = 1, - .port2_active = 1, - .port2_invert_for_secam_lc = 1, - .default_top_low = 4, - .default_top_mid = 4, - .default_top_high = 4, - .default_top_secam_low = 4, - .default_top_secam_mid = 4, - .default_top_secam_high = 4, - }, -}; - -/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */ - -static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = { - /* The datasheet specified channel ranges and the bandswitch byte */ - /* The control byte value of 0x8e is just a guess */ - { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels 2 - B */ - { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels C - W+11 */ - { 16 * 999.99 , 0x8e, 0x08, }, /* Channels W+12 - 69 */ -}; - -static struct tuner_params tuner_partsnic_pti_5nf05_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_partsnic_pti_5nf05_ranges, - .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges), - .cb_first_if_lower_freq = 1, /* not specified but safe to do */ - }, -}; - -/* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */ - -static struct tuner_range tuner_cu1216l_ranges[] = { - { 16 * 160.25 /*MHz*/, 0xce, 0x01 }, - { 16 * 444.25 /*MHz*/, 0xce, 0x02 }, - { 16 * 999.99 , 0xce, 0x04 }, -}; - -static struct tuner_params tuner_philips_cu1216l_params[] = { - { - .type = TUNER_PARAM_TYPE_DIGITAL, - .ranges = tuner_cu1216l_ranges, - .count = ARRAY_SIZE(tuner_cu1216l_ranges), - .iffreq = 16 * 36.125, /*MHz*/ - }, -}; - -/* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */ - -static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, - { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, - { 16 * 999.99 , 0x8e, 0x04, }, -}; - -static struct tuner_params tuner_sony_btf_pxn01z_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_sony_btf_pxn01z_ranges, - .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges), - }, -}; - -/* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */ - -static struct tuner_params tuner_philips_fq1236_mk5_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - .has_tda9887 = 1, /* TDA9885, no FM radio */ - }, -}; - -/* --------------------------------------------------------------------- */ - -struct tunertype tuners[] = { - /* 0-9 */ - [TUNER_TEMIC_PAL] = { /* TEMIC PAL */ - .name = "Temic PAL (4002 FH5)", - .params = tuner_temic_pal_params, - .count = ARRAY_SIZE(tuner_temic_pal_params), - }, - [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */ - .name = "Philips PAL_I (FI1246 and compatibles)", - .params = tuner_philips_pal_i_params, - .count = ARRAY_SIZE(tuner_philips_pal_i_params), - }, - [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */ - .name = "Philips NTSC (FI1236,FM1236 and compatibles)", - .params = tuner_philips_ntsc_params, - .count = ARRAY_SIZE(tuner_philips_ntsc_params), - }, - [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */ - .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", - .params = tuner_philips_secam_params, - .count = ARRAY_SIZE(tuner_philips_secam_params), - }, - [TUNER_ABSENT] = { /* Tuner Absent */ - .name = "NoTuner", - }, - [TUNER_PHILIPS_PAL] = { /* Philips PAL */ - .name = "Philips PAL_BG (FI1216 and compatibles)", - .params = tuner_philips_pal_params, - .count = ARRAY_SIZE(tuner_philips_pal_params), - }, - [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */ - .name = "Temic NTSC (4032 FY5)", - .params = tuner_temic_ntsc_params, - .count = ARRAY_SIZE(tuner_temic_ntsc_params), - }, - [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */ - .name = "Temic PAL_I (4062 FY5)", - .params = tuner_temic_pal_i_params, - .count = ARRAY_SIZE(tuner_temic_pal_i_params), - }, - [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */ - .name = "Temic NTSC (4036 FY5)", - .params = tuner_temic_4036fy5_ntsc_params, - .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params), - }, - [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */ - .name = "Alps HSBH1", - .params = tuner_alps_tsbh1_ntsc_params, - .count = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params), - }, - - /* 10-19 */ - [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */ - .name = "Alps TSBE1", - .params = tuner_alps_tsb_1_params, - .count = ARRAY_SIZE(tuner_alps_tsb_1_params), - }, - [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */ - .name = "Alps TSBB5", - .params = tuner_alps_tsbb5_params, - .count = ARRAY_SIZE(tuner_alps_tsbb5_params), - }, - [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */ - .name = "Alps TSBE5", - .params = tuner_alps_tsbe5_params, - .count = ARRAY_SIZE(tuner_alps_tsbe5_params), - }, - [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */ - .name = "Alps TSBC5", - .params = tuner_alps_tsbc5_params, - .count = ARRAY_SIZE(tuner_alps_tsbc5_params), - }, - [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */ - .name = "Temic PAL_BG (4006FH5)", - .params = tuner_temic_4006fh5_params, - .count = ARRAY_SIZE(tuner_temic_4006fh5_params), - }, - [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */ - .name = "Alps TSCH6", - .params = tuner_alps_tshc6_params, - .count = ARRAY_SIZE(tuner_alps_tshc6_params), - }, - [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */ - .name = "Temic PAL_DK (4016 FY5)", - .params = tuner_temic_pal_dk_params, - .count = ARRAY_SIZE(tuner_temic_pal_dk_params), - }, - [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */ - .name = "Philips NTSC_M (MK2)", - .params = tuner_philips_ntsc_m_params, - .count = ARRAY_SIZE(tuner_philips_ntsc_m_params), - }, - [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */ - .name = "Temic PAL_I (4066 FY5)", - .params = tuner_temic_4066fy5_pal_i_params, - .count = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params), - }, - [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */ - .name = "Temic PAL* auto (4006 FN5)", - .params = tuner_temic_4006fn5_multi_params, - .count = ARRAY_SIZE(tuner_temic_4006fn5_multi_params), - }, - - /* 20-29 */ - [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */ - .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", - .params = tuner_temic_4009f_5_params, - .count = ARRAY_SIZE(tuner_temic_4009f_5_params), - }, - [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */ - .name = "Temic NTSC (4039 FR5)", - .params = tuner_temic_4039fr5_params, - .count = ARRAY_SIZE(tuner_temic_4039fr5_params), - }, - [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */ - .name = "Temic PAL/SECAM multi (4046 FM5)", - .params = tuner_temic_4046fm5_params, - .count = ARRAY_SIZE(tuner_temic_4046fm5_params), - }, - [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */ - .name = "Philips PAL_DK (FI1256 and compatibles)", - .params = tuner_philips_pal_dk_params, - .count = ARRAY_SIZE(tuner_philips_pal_dk_params), - }, - [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */ - .name = "Philips PAL/SECAM multi (FQ1216ME)", - .params = tuner_philips_fq1216me_params, - .count = ARRAY_SIZE(tuner_philips_fq1216me_params), - }, - [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */ - .name = "LG PAL_I+FM (TAPC-I001D)", - .params = tuner_lg_pal_i_fm_params, - .count = ARRAY_SIZE(tuner_lg_pal_i_fm_params), - }, - [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */ - .name = "LG PAL_I (TAPC-I701D)", - .params = tuner_lg_pal_i_params, - .count = ARRAY_SIZE(tuner_lg_pal_i_params), - }, - [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */ - .name = "LG NTSC+FM (TPI8NSR01F)", - .params = tuner_lg_ntsc_fm_params, - .count = ARRAY_SIZE(tuner_lg_ntsc_fm_params), - }, - [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */ - .name = "LG PAL_BG+FM (TPI8PSB01D)", - .params = tuner_lg_pal_fm_params, - .count = ARRAY_SIZE(tuner_lg_pal_fm_params), - }, - [TUNER_LG_PAL] = { /* LGINNOTEK PAL */ - .name = "LG PAL_BG (TPI8PSB11D)", - .params = tuner_lg_pal_params, - .count = ARRAY_SIZE(tuner_lg_pal_params), - }, - - /* 30-39 */ - [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */ - .name = "Temic PAL* auto + FM (4009 FN5)", - .params = tuner_temic_4009_fn5_multi_pal_fm_params, - .count = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params), - }, - [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */ - .name = "SHARP NTSC_JP (2U5JF5540)", - .params = tuner_sharp_2u5jf5540_params, - .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_params), - }, - [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */ - .name = "Samsung PAL TCPM9091PD27", - .params = tuner_samsung_pal_tcpm9091pd27_params, - .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params), - }, - [TUNER_MT2032] = { /* Microtune PAL|NTSC */ - .name = "MT20xx universal", - /* see mt20xx.c for details */ }, - [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */ - .name = "Temic PAL_BG (4106 FH5)", - .params = tuner_temic_4106fh5_params, - .count = ARRAY_SIZE(tuner_temic_4106fh5_params), - }, - [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */ - .name = "Temic PAL_DK/SECAM_L (4012 FY5)", - .params = tuner_temic_4012fy5_params, - .count = ARRAY_SIZE(tuner_temic_4012fy5_params), - }, - [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */ - .name = "Temic NTSC (4136 FY5)", - .params = tuner_temic_4136_fy5_params, - .count = ARRAY_SIZE(tuner_temic_4136_fy5_params), - }, - [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */ - .name = "LG PAL (newer TAPC series)", - .params = tuner_lg_pal_new_tapc_params, - .count = ARRAY_SIZE(tuner_lg_pal_new_tapc_params), - }, - [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */ - .name = "Philips PAL/SECAM multi (FM1216ME MK3)", - .params = tuner_fm1216me_mk3_params, - .count = ARRAY_SIZE(tuner_fm1216me_mk3_params), - }, - [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */ - .name = "LG NTSC (newer TAPC series)", - .params = tuner_lg_ntsc_new_tapc_params, - .count = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params), - }, - - /* 40-49 */ - [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */ - .name = "HITACHI V7-J180AT", - .params = tuner_hitachi_ntsc_params, - .count = ARRAY_SIZE(tuner_hitachi_ntsc_params), - }, - [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */ - .name = "Philips PAL_MK (FI1216 MK)", - .params = tuner_philips_pal_mk_params, - .count = ARRAY_SIZE(tuner_philips_pal_mk_params), - }, - [TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */ - .name = "Philips FCV1236D ATSC/NTSC dual in", - .params = tuner_philips_fcv1236d_params, - .count = ARRAY_SIZE(tuner_philips_fcv1236d_params), - .min = 16 * 53.00, - .max = 16 * 803.00, - .stepsize = 62500, - }, - [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ - .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", - .params = tuner_fm1236_mk3_params, - .count = ARRAY_SIZE(tuner_fm1236_mk3_params), - }, - [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */ - .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", - .params = tuner_philips_4in1_params, - .count = ARRAY_SIZE(tuner_philips_4in1_params), - }, - [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */ - .name = "Microtune 4049 FM5", - .params = tuner_microtune_4049_fm5_params, - .count = ARRAY_SIZE(tuner_microtune_4049_fm5_params), - }, - [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */ - .name = "Panasonic VP27s/ENGE4324D", - .params = tuner_panasonic_vp27_params, - .count = ARRAY_SIZE(tuner_panasonic_vp27_params), - }, - [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ - .name = "LG NTSC (TAPE series)", - .params = tuner_fm1236_mk3_params, - .count = ARRAY_SIZE(tuner_fm1236_mk3_params), - }, - [TUNER_TNF_8831BGFF] = { /* Philips PAL */ - .name = "Tenna TNF 8831 BGFF)", - .params = tuner_tnf_8831bgff_params, - .count = ARRAY_SIZE(tuner_tnf_8831bgff_params), - }, - [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */ - .name = "Microtune 4042 FI5 ATSC/NTSC dual in", - .params = tuner_microtune_4042fi5_params, - .count = ARRAY_SIZE(tuner_microtune_4042fi5_params), - .min = 16 * 57.00, - .max = 16 * 858.00, - .stepsize = 62500, - }, - - /* 50-59 */ - [TUNER_TCL_2002N] = { /* TCL NTSC */ - .name = "TCL 2002N", - .params = tuner_tcl_2002n_params, - .count = ARRAY_SIZE(tuner_tcl_2002n_params), - }, - [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */ - .name = "Philips PAL/SECAM_D (FM 1256 I-H3)", - .params = tuner_philips_fm1256_ih3_params, - .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_params), - }, - [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ - .name = "Thomson DTT 7610 (ATSC/NTSC)", - .params = tuner_thomson_dtt7610_params, - .count = ARRAY_SIZE(tuner_thomson_dtt7610_params), - .min = 16 * 44.00, - .max = 16 * 958.00, - .stepsize = 62500, - }, - [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */ - .name = "Philips FQ1286", - .params = tuner_philips_fq1286_params, - .count = ARRAY_SIZE(tuner_philips_fq1286_params), - }, - [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ - .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", - /* see tda8290.c for details */ }, - [TUNER_TCL_2002MB] = { /* TCL PAL */ - .name = "TCL 2002MB", - .params = tuner_tcl_2002mb_params, - .count = ARRAY_SIZE(tuner_tcl_2002mb_params), - }, - [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */ - .name = "Philips PAL/SECAM multi (FQ1216AME MK4)", - .params = tuner_philips_fq1216ame_mk4_params, - .count = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params), - }, - [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */ - .name = "Philips FQ1236A MK4", - .params = tuner_philips_fq1236a_mk4_params, - .count = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params), - }, - [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */ - .name = "Ymec TVision TVF-8531MF/8831MF/8731MF", - .params = tuner_ymec_tvf_8531mf_params, - .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params), - }, - [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */ - .name = "Ymec TVision TVF-5533MF", - .params = tuner_ymec_tvf_5533mf_params, - .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params), - }, - - /* 60-69 */ - [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */ - /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ - .name = "Thomson DTT 761X (ATSC/NTSC)", - .params = tuner_thomson_dtt761x_params, - .count = ARRAY_SIZE(tuner_thomson_dtt761x_params), - .min = 16 * 57.00, - .max = 16 * 863.00, - .stepsize = 62500, - .initdata = tua603x_agc103, - }, - [TUNER_TENA_9533_DI] = { /* Philips PAL */ - .name = "Tena TNF9533-D/IF/TNF9533-B/DF", - .params = tuner_tena_9533_di_params, - .count = ARRAY_SIZE(tuner_tena_9533_di_params), - }, - [TUNER_TEA5767] = { /* Philips RADIO */ - .name = "Philips TEA5767HN FM Radio", - /* see tea5767.c for details */ - }, - [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */ - .name = "Philips FMD1216ME MK3 Hybrid Tuner", - .params = tuner_philips_fmd1216me_mk3_params, - .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params), - .min = 16 * 50.87, - .max = 16 * 858.00, - .stepsize = 166667, - .initdata = tua603x_agc112, - .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, - }, - [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */ - .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */ - .params = tuner_lg_tdvs_h06xf_params, - .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params), - .min = 16 * 54.00, - .max = 16 * 863.00, - .stepsize = 62500, - .initdata = tua603x_agc103, - }, - [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */ - .name = "Ymec TVF66T5-B/DFF", - .params = tuner_ymec_tvf66t5_b_dff_params, - .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params), - }, - [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */ - .name = "LG TALN series", - .params = tuner_lg_taln_params, - .count = ARRAY_SIZE(tuner_lg_taln_params), - }, - [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ - .name = "Philips TD1316 Hybrid Tuner", - .params = tuner_philips_td1316_params, - .count = ARRAY_SIZE(tuner_philips_td1316_params), - .min = 16 * 87.00, - .max = 16 * 895.00, - .stepsize = 166667, - }, - [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */ - .name = "Philips TUV1236D ATSC/NTSC dual in", - .params = tuner_tuv1236d_params, - .count = ARRAY_SIZE(tuner_tuv1236d_params), - .min = 16 * 54.00, - .max = 16 * 864.00, - .stepsize = 62500, - }, - [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */ - .name = "Tena TNF 5335 and similar models", - .params = tuner_tnf_5335mf_params, - .count = ARRAY_SIZE(tuner_tnf_5335mf_params), - }, - - /* 70-79 */ - [TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */ - .name = "Samsung TCPN 2121P30A", - .params = tuner_samsung_tcpn_2121p30a_params, - .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), - }, - [TUNER_XC2028] = { /* Xceive 2028 */ - .name = "Xceive xc2028/xc3028 tuner", - /* see tuner-xc2028.c for details */ - }, - [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ - .name = "Thomson FE6600", - .params = tuner_thomson_fe6600_params, - .count = ARRAY_SIZE(tuner_thomson_fe6600_params), - .min = 16 * 44.25, - .max = 16 * 858.00, - .stepsize = 166667, - }, - [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */ - .name = "Samsung TCPG 6121P30A", - .params = tuner_samsung_tcpg_6121p30a_params, - .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params), - }, - [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator. - This chip is part of some modern tuners */ - .name = "Philips TDA988[5,6,7] IF PLL Demodulator", - /* see tda9887.c for details */ - }, - [TUNER_TEA5761] = { /* Philips RADIO */ - .name = "Philips TEA5761 FM Radio", - /* see tea5767.c for details */ - }, - [TUNER_XC5000] = { /* Xceive 5000 */ - .name = "Xceive 5000 tuner", - /* see xc5000.c for details */ - }, - [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */ - .name = "TCL tuner MF02GIP-5N-E", - .params = tuner_tcl_mf02gip_5n_params, - .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params), - }, - [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */ - .name = "Philips FMD1216MEX MK3 Hybrid Tuner", - .params = tuner_philips_fmd1216mex_mk3_params, - .count = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params), - .min = 16 * 50.87, - .max = 16 * 858.00, - .stepsize = 166667, - .initdata = tua603x_agc112, - .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, - }, - [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */ - .name = "Philips PAL/SECAM multi (FM1216 MK5)", - .params = tuner_fm1216mk5_params, - .count = ARRAY_SIZE(tuner_fm1216mk5_params), - }, - - /* 80-89 */ - [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */ - .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough", - .params = tuner_fq1216lme_mk3_params, - .count = ARRAY_SIZE(tuner_fq1216lme_mk3_params), - }, - - [TUNER_PARTSNIC_PTI_5NF05] = { - .name = "Partsnic (Daewoo) PTI-5NF05", - .params = tuner_partsnic_pti_5nf05_params, - .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params), - }, - [TUNER_PHILIPS_CU1216L] = { - .name = "Philips CU1216L", - .params = tuner_philips_cu1216l_params, - .count = ARRAY_SIZE(tuner_philips_cu1216l_params), - .stepsize = 62500, - }, - [TUNER_NXP_TDA18271] = { - .name = "NXP TDA18271", - /* see tda18271-fe.c for details */ - }, - [TUNER_SONY_BTF_PXN01Z] = { - .name = "Sony BTF-Pxn01Z", - .params = tuner_sony_btf_pxn01z_params, - .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params), - }, - [TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */ - .name = "Philips FQ1236 MK5", - .params = tuner_philips_fq1236_mk5_params, - .count = ARRAY_SIZE(tuner_philips_fq1236_mk5_params), - }, - [TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */ - .name = "Tena TNF5337 MFD", - .params = tuner_tena_tnf_5337_params, - .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), - }, -}; -EXPORT_SYMBOL(tuners); - -unsigned const int tuner_count = ARRAY_SIZE(tuners); -EXPORT_SYMBOL(tuner_count); - -MODULE_DESCRIPTION("Simple tuner device type database"); -MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1356 +0,0 @@ -/* tuner-xc2028 - * - * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) - * - * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) - * - frontend interface - * - * This code is placed under the terms of the GNU General Public License v2 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tuner-xc2028.h" -#include "tuner-xc2028-types.h" - -#include -#include "dvb_frontend.h" - - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static int no_poweroff; -module_param(no_poweroff, int, 0644); -MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" - "1 keep device energized and with tuner ready all the times.\n" - " Faster, but consumes more power and keeps the device hotter\n"); - -static char audio_std[8]; -module_param_string(audio_std, audio_std, sizeof(audio_std), 0); -MODULE_PARM_DESC(audio_std, - "Audio standard. XC3028 audio decoder explicitly " - "needs to know what audio\n" - "standard is needed for some video standards with audio A2 or NICAM.\n" - "The valid values are:\n" - "A2\n" - "A2/A\n" - "A2/B\n" - "NICAM\n" - "NICAM/A\n" - "NICAM/B\n"); - -static char firmware_name[30]; -module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); -MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " - "default firmware name\n"); - -static LIST_HEAD(hybrid_tuner_instance_list); -static DEFINE_MUTEX(xc2028_list_mutex); - -/* struct for storing firmware table */ -struct firmware_description { - unsigned int type; - v4l2_std_id id; - __u16 int_freq; - unsigned char *ptr; - unsigned int size; -}; - -struct firmware_properties { - unsigned int type; - v4l2_std_id id; - v4l2_std_id std_req; - __u16 int_freq; - unsigned int scode_table; - int scode_nr; -}; - -struct xc2028_data { - struct list_head hybrid_tuner_instance_list; - struct tuner_i2c_props i2c_props; - __u32 frequency; - - struct firmware_description *firm; - int firm_size; - __u16 firm_version; - - __u16 hwmodel; - __u16 hwvers; - - struct xc2028_ctrl ctrl; - - struct firmware_properties cur_fw; - - struct mutex lock; -}; - -#define i2c_send(priv, buf, size) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ - if (size != _rc) \ - tuner_info("i2c output error: rc = %d (should be %d)\n",\ - _rc, (int)size); \ - if (priv->ctrl.msleep) \ - msleep(priv->ctrl.msleep); \ - _rc; \ -}) - -#define i2c_rcv(priv, buf, size) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ - if (size != _rc) \ - tuner_err("i2c input error: rc = %d (should be %d)\n", \ - _rc, (int)size); \ - _rc; \ -}) - -#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ - ibuf, isize); \ - if (isize != _rc) \ - tuner_err("i2c input error: rc = %d (should be %d)\n", \ - _rc, (int)isize); \ - if (priv->ctrl.msleep) \ - msleep(priv->ctrl.msleep); \ - _rc; \ -}) - -#define send_seq(priv, data...) ({ \ - static u8 _val[] = data; \ - int _rc; \ - if (sizeof(_val) != \ - (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ - _val, sizeof(_val)))) { \ - tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ - } else if (priv->ctrl.msleep) \ - msleep(priv->ctrl.msleep); \ - _rc; \ -}) - -static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) -{ - unsigned char buf[2]; - unsigned char ibuf[2]; - - tuner_dbg("%s %04x called\n", __func__, reg); - - buf[0] = reg >> 8; - buf[1] = (unsigned char) reg; - - if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) - return -EIO; - - *val = (ibuf[1]) | (ibuf[0] << 8); - return 0; -} - -#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) -static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) -{ - if (type & BASE) - printk("BASE "); - if (type & INIT1) - printk("INIT1 "); - if (type & F8MHZ) - printk("F8MHZ "); - if (type & MTS) - printk("MTS "); - if (type & D2620) - printk("D2620 "); - if (type & D2633) - printk("D2633 "); - if (type & DTV6) - printk("DTV6 "); - if (type & QAM) - printk("QAM "); - if (type & DTV7) - printk("DTV7 "); - if (type & DTV78) - printk("DTV78 "); - if (type & DTV8) - printk("DTV8 "); - if (type & FM) - printk("FM "); - if (type & INPUT1) - printk("INPUT1 "); - if (type & LCD) - printk("LCD "); - if (type & NOGD) - printk("NOGD "); - if (type & MONO) - printk("MONO "); - if (type & ATSC) - printk("ATSC "); - if (type & IF) - printk("IF "); - if (type & LG60) - printk("LG60 "); - if (type & ATI638) - printk("ATI638 "); - if (type & OREN538) - printk("OREN538 "); - if (type & OREN36) - printk("OREN36 "); - if (type & TOYOTA388) - printk("TOYOTA388 "); - if (type & TOYOTA794) - printk("TOYOTA794 "); - if (type & DIBCOM52) - printk("DIBCOM52 "); - if (type & ZARLINK456) - printk("ZARLINK456 "); - if (type & CHINA) - printk("CHINA "); - if (type & F6MHZ) - printk("F6MHZ "); - if (type & INPUT2) - printk("INPUT2 "); - if (type & SCODE) - printk("SCODE "); - if (type & HAS_IF) - printk("HAS_IF_%d ", int_freq); -} - -static v4l2_std_id parse_audio_std_option(void) -{ - if (strcasecmp(audio_std, "A2") == 0) - return V4L2_STD_A2; - if (strcasecmp(audio_std, "A2/A") == 0) - return V4L2_STD_A2_A; - if (strcasecmp(audio_std, "A2/B") == 0) - return V4L2_STD_A2_B; - if (strcasecmp(audio_std, "NICAM") == 0) - return V4L2_STD_NICAM; - if (strcasecmp(audio_std, "NICAM/A") == 0) - return V4L2_STD_NICAM_A; - if (strcasecmp(audio_std, "NICAM/B") == 0) - return V4L2_STD_NICAM_B; - - return 0; -} - -static void free_firmware(struct xc2028_data *priv) -{ - int i; - tuner_dbg("%s called\n", __func__); - - if (!priv->firm) - return; - - for (i = 0; i < priv->firm_size; i++) - kfree(priv->firm[i].ptr); - - kfree(priv->firm); - - priv->firm = NULL; - priv->firm_size = 0; - - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); -} - -static int load_all_firmwares(struct dvb_frontend *fe) -{ - struct xc2028_data *priv = fe->tuner_priv; - const struct firmware *fw = NULL; - const unsigned char *p, *endp; - int rc = 0; - int n, n_array; - char name[33]; - char *fname; - - tuner_dbg("%s called\n", __func__); - - if (!firmware_name[0]) - fname = priv->ctrl.fname; - else - fname = firmware_name; - - tuner_dbg("Reading firmware %s\n", fname); - rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); - if (rc < 0) { - if (rc == -ENOENT) - tuner_err("Error: firmware %s not found.\n", - fname); - else - tuner_err("Error %d while requesting firmware %s \n", - rc, fname); - - return rc; - } - p = fw->data; - endp = p + fw->size; - - if (fw->size < sizeof(name) - 1 + 2 + 2) { - tuner_err("Error: firmware file %s has invalid size!\n", - fname); - goto corrupt; - } - - memcpy(name, p, sizeof(name) - 1); - name[sizeof(name) - 1] = 0; - p += sizeof(name) - 1; - - priv->firm_version = get_unaligned_le16(p); - p += 2; - - n_array = get_unaligned_le16(p); - p += 2; - - tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", - n_array, fname, name, - priv->firm_version >> 8, priv->firm_version & 0xff); - - priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); - if (priv->firm == NULL) { - tuner_err("Not enough memory to load firmware file.\n"); - rc = -ENOMEM; - goto err; - } - priv->firm_size = n_array; - - n = -1; - while (p < endp) { - __u32 type, size; - v4l2_std_id id; - __u16 int_freq = 0; - - n++; - if (n >= n_array) { - tuner_err("More firmware images in file than " - "were expected!\n"); - goto corrupt; - } - - /* Checks if there's enough bytes to read */ - if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) - goto header; - - type = get_unaligned_le32(p); - p += sizeof(type); - - id = get_unaligned_le64(p); - p += sizeof(id); - - if (type & HAS_IF) { - int_freq = get_unaligned_le16(p); - p += sizeof(int_freq); - if (endp - p < sizeof(size)) - goto header; - } - - size = get_unaligned_le32(p); - p += sizeof(size); - - if (!size || size > endp - p) { - tuner_err("Firmware type "); - dump_firm_type(type); - printk("(%x), id %llx is corrupted " - "(size=%d, expected %d)\n", - type, (unsigned long long)id, - (unsigned)(endp - p), size); - goto corrupt; - } - - priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); - if (priv->firm[n].ptr == NULL) { - tuner_err("Not enough memory to load firmware file.\n"); - rc = -ENOMEM; - goto err; - } - tuner_dbg("Reading firmware type "); - if (debug) { - dump_firm_type_and_int_freq(type, int_freq); - printk("(%x), id %llx, size=%d.\n", - type, (unsigned long long)id, size); - } - - memcpy(priv->firm[n].ptr, p, size); - priv->firm[n].type = type; - priv->firm[n].id = id; - priv->firm[n].size = size; - priv->firm[n].int_freq = int_freq; - - p += size; - } - - if (n + 1 != priv->firm_size) { - tuner_err("Firmware file is incomplete!\n"); - goto corrupt; - } - - goto done; - -header: - tuner_err("Firmware header is incomplete!\n"); -corrupt: - rc = -EINVAL; - tuner_err("Error: firmware file is corrupted!\n"); - -err: - tuner_info("Releasing partially loaded firmware file.\n"); - free_firmware(priv); - -done: - release_firmware(fw); - if (rc == 0) - tuner_dbg("Firmware files loaded.\n"); - - return rc; -} - -static int seek_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id) -{ - struct xc2028_data *priv = fe->tuner_priv; - int i, best_i = -1, best_nr_matches = 0; - unsigned int type_mask = 0; - - tuner_dbg("%s called, want type=", __func__); - if (debug) { - dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); - } - - if (!priv->firm) { - tuner_err("Error! firmware not loaded\n"); - return -EINVAL; - } - - if (((type & ~SCODE) == 0) && (*id == 0)) - *id = V4L2_STD_PAL; - - if (type & BASE) - type_mask = BASE_TYPES; - else if (type & SCODE) { - type &= SCODE_TYPES; - type_mask = SCODE_TYPES & ~HAS_IF; - } else if (type & DTV_TYPES) - type_mask = DTV_TYPES; - else if (type & STD_SPECIFIC_TYPES) - type_mask = STD_SPECIFIC_TYPES; - - type &= type_mask; - - if (!(type & SCODE)) - type_mask = ~0; - - /* Seek for exact match */ - for (i = 0; i < priv->firm_size; i++) { - if ((type == (priv->firm[i].type & type_mask)) && - (*id == priv->firm[i].id)) - goto found; - } - - /* Seek for generic video standard match */ - for (i = 0; i < priv->firm_size; i++) { - v4l2_std_id match_mask; - int nr_matches; - - if (type != (priv->firm[i].type & type_mask)) - continue; - - match_mask = *id & priv->firm[i].id; - if (!match_mask) - continue; - - if ((*id & match_mask) == *id) - goto found; /* Supports all the requested standards */ - - nr_matches = hweight64(match_mask); - if (nr_matches > best_nr_matches) { - best_nr_matches = nr_matches; - best_i = i; - } - } - - if (best_nr_matches > 0) { - tuner_dbg("Selecting best matching firmware (%d bits) for " - "type=", best_nr_matches); - dump_firm_type(type); - printk("(%x), id %016llx:\n", type, (unsigned long long)*id); - i = best_i; - goto found; - } - - /*FIXME: Would make sense to seek for type "hint" match ? */ - - i = -ENOENT; - goto ret; - -found: - *id = priv->firm[i].id; - -ret: - tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); - if (debug) { - dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); - } - return i; -} - -static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg) -{ - struct xc2028_data *priv = fe->tuner_priv; - - /* analog side (tuner-core) uses i2c_adap->algo_data. - * digital side is not guaranteed to have algo_data defined. - * - * digital side will always have fe->dvb defined. - * analog side (tuner-core) doesn't (yet) define fe->dvb. - */ - - return (!fe->callback) ? -EINVAL : - fe->callback(((fe->dvb) && (fe->dvb->priv)) ? - fe->dvb->priv : priv->i2c_props.adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, cmd, arg); -} - -static int load_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id) -{ - struct xc2028_data *priv = fe->tuner_priv; - int pos, rc; - unsigned char *p, *endp, buf[priv->ctrl.max_len]; - - tuner_dbg("%s called\n", __func__); - - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; - - tuner_info("Loading firmware for type="); - dump_firm_type(priv->firm[pos].type); - printk("(%x), id %016llx.\n", priv->firm[pos].type, - (unsigned long long)*id); - - p = priv->firm[pos].ptr; - endp = p + priv->firm[pos].size; - - while (p < endp) { - __u16 size; - - /* Checks if there's enough bytes to read */ - if (p + sizeof(size) > endp) { - tuner_err("Firmware chunk size is wrong\n"); - return -EINVAL; - } - - size = le16_to_cpu(*(__u16 *) p); - p += sizeof(size); - - if (size == 0xffff) - return 0; - - if (!size) { - /* Special callback command received */ - rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); - if (rc < 0) { - tuner_err("Error at RESET code %d\n", - (*p) & 0x7f); - return -EINVAL; - } - continue; - } - if (size >= 0xff00) { - switch (size) { - case 0xff00: - rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0); - if (rc < 0) { - tuner_err("Error at RESET code %d\n", - (*p) & 0x7f); - return -EINVAL; - } - break; - default: - tuner_info("Invalid RESET code %d\n", - size & 0x7f); - return -EINVAL; - - } - continue; - } - - /* Checks for a sleep command */ - if (size & 0x8000) { - msleep(size & 0x7fff); - continue; - } - - if ((size + p > endp)) { - tuner_err("missing bytes: need %d, have %d\n", - size, (int)(endp - p)); - return -EINVAL; - } - - buf[0] = *p; - p++; - size--; - - /* Sends message chunks */ - while (size > 0) { - int len = (size < priv->ctrl.max_len - 1) ? - size : priv->ctrl.max_len - 1; - - memcpy(buf + 1, p, len); - - rc = i2c_send(priv, buf, len + 1); - if (rc < 0) { - tuner_err("%d returned from send\n", rc); - return -EINVAL; - } - - p += len; - size -= len; - } - } - return 0; -} - -static int load_scode(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id, __u16 int_freq, int scode) -{ - struct xc2028_data *priv = fe->tuner_priv; - int pos, rc; - unsigned char *p; - - tuner_dbg("%s called\n", __func__); - - if (!int_freq) { - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; - } else { - for (pos = 0; pos < priv->firm_size; pos++) { - if ((priv->firm[pos].int_freq == int_freq) && - (priv->firm[pos].type & HAS_IF)) - break; - } - if (pos == priv->firm_size) - return -ENOENT; - } - - p = priv->firm[pos].ptr; - - if (priv->firm[pos].type & HAS_IF) { - if (priv->firm[pos].size != 12 * 16 || scode >= 16) - return -EINVAL; - p += 12 * scode; - } else { - /* 16 SCODE entries per file; each SCODE entry is 12 bytes and - * has a 2-byte size header in the firmware format. */ - if (priv->firm[pos].size != 14 * 16 || scode >= 16 || - le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) - return -EINVAL; - p += 14 * scode + 2; - } - - tuner_info("Loading SCODE for type="); - dump_firm_type_and_int_freq(priv->firm[pos].type, - priv->firm[pos].int_freq); - printk("(%x), id %016llx.\n", priv->firm[pos].type, - (unsigned long long)*id); - - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); - else - rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); - if (rc < 0) - return -EIO; - - rc = i2c_send(priv, p, 12); - if (rc < 0) - return -EIO; - - rc = send_seq(priv, {0x00, 0x8c}); - if (rc < 0) - return -EIO; - - return 0; -} - -static int check_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id std, __u16 int_freq) -{ - struct xc2028_data *priv = fe->tuner_priv; - struct firmware_properties new_fw; - int rc = 0, retry_count = 0; - u16 version, hwmodel; - v4l2_std_id std0; - - tuner_dbg("%s called\n", __func__); - - if (!priv->firm) { - if (!priv->ctrl.fname) { - tuner_info("xc2028/3028 firmware name not set!\n"); - return -EINVAL; - } - - rc = load_all_firmwares(fe); - if (rc < 0) - return rc; - } - - if (priv->ctrl.mts && !(type & FM)) - type |= MTS; - -retry: - new_fw.type = type; - new_fw.id = std; - new_fw.std_req = std; - new_fw.scode_table = SCODE | priv->ctrl.scode_table; - new_fw.scode_nr = 0; - new_fw.int_freq = int_freq; - - tuner_dbg("checking firmware, user requested type="); - if (debug) { - dump_firm_type(new_fw.type); - printk("(%x), id %016llx, ", new_fw.type, - (unsigned long long)new_fw.std_req); - if (!int_freq) { - printk("scode_tbl "); - dump_firm_type(priv->ctrl.scode_table); - printk("(%x), ", priv->ctrl.scode_table); - } else - printk("int_freq %d, ", new_fw.int_freq); - printk("scode_nr %d\n", new_fw.scode_nr); - } - - /* No need to reload base firmware if it matches */ - if (((BASE | new_fw.type) & BASE_TYPES) == - (priv->cur_fw.type & BASE_TYPES)) { - tuner_dbg("BASE firmware not changed.\n"); - goto skip_base; - } - - /* Updating BASE - forget about all currently loaded firmware */ - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - - /* Reset is needed before loading firmware */ - rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); - if (rc < 0) - goto fail; - - /* BASE firmwares are all std0 */ - std0 = 0; - rc = load_firmware(fe, BASE | new_fw.type, &std0); - if (rc < 0) { - tuner_err("Error %d while loading base firmware\n", - rc); - goto fail; - } - - /* Load INIT1, if needed */ - tuner_dbg("Load init1 firmware, if exists\n"); - - rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); - if (rc == -ENOENT) - rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, - &std0); - if (rc < 0 && rc != -ENOENT) { - tuner_err("Error %d while loading init1 firmware\n", - rc); - goto fail; - } - -skip_base: - /* - * No need to reload standard specific firmware if base firmware - * was not reloaded and requested video standards have not changed. - */ - if (priv->cur_fw.type == (BASE | new_fw.type) && - priv->cur_fw.std_req == std) { - tuner_dbg("Std-specific firmware already loaded.\n"); - goto skip_std_specific; - } - - /* Reloading std-specific firmware forces a SCODE update */ - priv->cur_fw.scode_table = 0; - - rc = load_firmware(fe, new_fw.type, &new_fw.id); - if (rc == -ENOENT) - rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); - - if (rc < 0) - goto fail; - -skip_std_specific: - if (priv->cur_fw.scode_table == new_fw.scode_table && - priv->cur_fw.scode_nr == new_fw.scode_nr) { - tuner_dbg("SCODE firmware already loaded.\n"); - goto check_device; - } - - if (new_fw.type & FM) - goto check_device; - - /* Load SCODE firmware, if exists */ - tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); - - rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, - new_fw.int_freq, new_fw.scode_nr); - -check_device: - if (xc2028_get_reg(priv, 0x0004, &version) < 0 || - xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { - tuner_err("Unable to read tuner registers.\n"); - goto fail; - } - - tuner_dbg("Device is Xceive %d version %d.%d, " - "firmware version %d.%d\n", - hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, - (version & 0xf0) >> 4, version & 0xf); - - - if (priv->ctrl.read_not_reliable) - goto read_not_reliable; - - /* Check firmware version against what we downloaded. */ - if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { - if (!priv->ctrl.read_not_reliable) { - tuner_err("Incorrect readback of firmware version.\n"); - goto fail; - } else { - tuner_err("Returned an incorrect version. However, " - "read is not reliable enough. Ignoring it.\n"); - hwmodel = 3028; - } - } - - /* Check that the tuner hardware model remains consistent over time. */ - if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { - priv->hwmodel = hwmodel; - priv->hwvers = version & 0xff00; - } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || - priv->hwvers != (version & 0xff00)) { - tuner_err("Read invalid device hardware information - tuner " - "hung?\n"); - goto fail; - } - -read_not_reliable: - memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); - - /* - * By setting BASE in cur_fw.type only after successfully loading all - * firmwares, we can: - * 1. Identify that BASE firmware with type=0 has been loaded; - * 2. Tell whether BASE firmware was just changed the next time through. - */ - priv->cur_fw.type |= BASE; - - return 0; - -fail: - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - if (retry_count < 8) { - msleep(50); - retry_count++; - tuner_dbg("Retrying firmware load\n"); - goto retry; - } - - if (rc == -ENOENT) - rc = -EINVAL; - return rc; -} - -static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) -{ - struct xc2028_data *priv = fe->tuner_priv; - u16 frq_lock, signal = 0; - int rc; - - tuner_dbg("%s called\n", __func__); - - mutex_lock(&priv->lock); - - /* Sync Lock Indicator */ - rc = xc2028_get_reg(priv, 0x0002, &frq_lock); - if (rc < 0) - goto ret; - - /* Frequency is locked */ - if (frq_lock == 1) - signal = 32768; - - /* Get SNR of the video signal */ - rc = xc2028_get_reg(priv, 0x0040, &signal); - if (rc < 0) - goto ret; - - /* Use both frq_lock and signal to generate the result */ - signal = signal || ((signal & 0x07) << 12); - -ret: - mutex_unlock(&priv->lock); - - *strength = signal; - - tuner_dbg("signal strength is %d\n", signal); - - return rc; -} - -#define DIV 15625 - -static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, - enum v4l2_tuner_type new_type, - unsigned int type, - v4l2_std_id std, - u16 int_freq) -{ - struct xc2028_data *priv = fe->tuner_priv; - int rc = -EINVAL; - unsigned char buf[4]; - u32 div, offset = 0; - - tuner_dbg("%s called\n", __func__); - - mutex_lock(&priv->lock); - - tuner_dbg("should set frequency %d kHz\n", freq / 1000); - - if (check_firmware(fe, type, std, int_freq) < 0) - goto ret; - - /* On some cases xc2028 can disable video output, if - * very weak signals are received. By sending a soft - * reset, this is re-enabled. So, it is better to always - * send a soft reset before changing channels, to be sure - * that xc2028 will be in a safe state. - * Maybe this might also be needed for DTV. - */ - if (new_type == V4L2_TUNER_ANALOG_TV) { - rc = send_seq(priv, {0x00, 0x00}); - - /* Analog modes require offset = 0 */ - } else { - /* - * Digital modes require an offset to adjust to the - * proper frequency. The offset depends on what - * firmware version is used. - */ - - /* - * Adjust to the center frequency. This is calculated by the - * formula: offset = 1.25MHz - BW/2 - * For DTV 7/8, the firmware uses BW = 8000, so it needs a - * further adjustment to get the frequency center on VHF - */ - if (priv->cur_fw.type & DTV6) - offset = 1750000; - else if (priv->cur_fw.type & DTV7) - offset = 2250000; - else /* DTV8 or DTV78 */ - offset = 2750000; - if ((priv->cur_fw.type & DTV78) && freq < 470000000) - offset -= 500000; - - /* - * xc3028 additional "magic" - * Depending on the firmware version, it needs some adjustments - * to properly centralize the frequency. This seems to be - * needed to compensate the SCODE table adjustments made by - * newer firmwares - */ - -#if 1 - /* - * The proper adjustment would be to do it at s-code table. - * However, this didn't work, as reported by - * Robert Lowery - */ - - if (priv->cur_fw.type & DTV7) - offset += 500000; - -#else - /* - * Still need tests for XC3028L (firmware 3.2 or upper) - * So, for now, let's just comment the per-firmware - * version of this change. Reports with xc3028l working - * with and without the lines bellow are welcome - */ - - if (priv->firm_version < 0x0302) { - if (priv->cur_fw.type & DTV7) - offset += 500000; - } else { - if (priv->cur_fw.type & DTV7) - offset -= 300000; - else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */ - offset += 200000; - } -#endif - } - - div = (freq - offset + DIV / 2) / DIV; - - /* CMD= Set frequency */ - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00}); - else - rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00}); - if (rc < 0) - goto ret; - - /* Return code shouldn't be checked. - The reset CLK is needed only with tm6000. - Driver should work fine even if this fails. - */ - if (priv->ctrl.msleep) - msleep(priv->ctrl.msleep); - do_tuner_callback(fe, XC2028_RESET_CLK, 1); - - msleep(10); - - buf[0] = 0xff & (div >> 24); - buf[1] = 0xff & (div >> 16); - buf[2] = 0xff & (div >> 8); - buf[3] = 0xff & (div); - - rc = i2c_send(priv, buf, sizeof(buf)); - if (rc < 0) - goto ret; - msleep(100); - - priv->frequency = freq; - - tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n", - buf[0], buf[1], buf[2], buf[3], - freq / 1000000, (freq % 1000000) / 1000); - - rc = 0; - -ret: - mutex_unlock(&priv->lock); - - return rc; -} - -static int xc2028_set_analog_freq(struct dvb_frontend *fe, - struct analog_parameters *p) -{ - struct xc2028_data *priv = fe->tuner_priv; - unsigned int type=0; - - tuner_dbg("%s called\n", __func__); - - if (p->mode == V4L2_TUNER_RADIO) { - type |= FM; - if (priv->ctrl.input1) - type |= INPUT1; - return generic_set_freq(fe, (625l * p->frequency) / 10, - V4L2_TUNER_RADIO, type, 0, 0); - } - - /* if std is not defined, choose one */ - if (!p->std) - p->std = V4L2_STD_MN; - - /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ - if (!(p->std & V4L2_STD_MN)) - type |= F8MHZ; - - /* Add audio hack to std mask */ - p->std |= parse_audio_std_option(); - - return generic_set_freq(fe, 62500l * p->frequency, - V4L2_TUNER_ANALOG_TV, type, p->std, 0); -} - -static int xc2028_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct xc2028_data *priv = fe->tuner_priv; - unsigned int type=0; - fe_bandwidth_t bw = BANDWIDTH_8_MHZ; - u16 demod = 0; - - tuner_dbg("%s called\n", __func__); - - switch(fe->ops.info.type) { - case FE_OFDM: - bw = p->u.ofdm.bandwidth; - /* - * The only countries with 6MHz seem to be Taiwan/Uruguay. - * Both seem to require QAM firmware for OFDM decoding - * Tested in Taiwan by Terry Wu - */ - if (bw == BANDWIDTH_6_MHZ) - type |= QAM; - break; - case FE_ATSC: - bw = BANDWIDTH_6_MHZ; - /* The only ATSC firmware (at least on v2.7) is D2633 */ - type |= ATSC | D2633; - break; - /* DVB-S and pure QAM (FE_QAM) are not supported */ - default: - return -EINVAL; - } - - switch (bw) { - case BANDWIDTH_8_MHZ: - if (p->frequency < 470000000) - priv->ctrl.vhfbw7 = 0; - else - priv->ctrl.uhfbw8 = 1; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; - type |= F8MHZ; - break; - case BANDWIDTH_7_MHZ: - if (p->frequency < 470000000) - priv->ctrl.vhfbw7 = 1; - else - priv->ctrl.uhfbw8 = 0; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; - type |= F8MHZ; - break; - case BANDWIDTH_6_MHZ: - type |= DTV6; - priv->ctrl.vhfbw7 = 0; - priv->ctrl.uhfbw8 = 0; - break; - default: - tuner_err("error: bandwidth not supported.\n"); - }; - - /* - Selects between D2633 or D2620 firmware. - It doesn't make sense for ATSC, since it should be D2633 on all cases - */ - if (fe->ops.info.type != FE_ATSC) { - switch (priv->ctrl.type) { - case XC2028_D2633: - type |= D2633; - break; - case XC2028_D2620: - type |= D2620; - break; - case XC2028_AUTO: - default: - /* Zarlink seems to need D2633 */ - if (priv->ctrl.demod == XC3028_FE_ZARLINK456) - type |= D2633; - else - type |= D2620; - } - } - - /* All S-code tables need a 200kHz shift */ - if (priv->ctrl.demod) { - demod = priv->ctrl.demod; - - /* - * Newer firmwares require a 200 kHz offset only for ATSC - */ - if (type == ATSC || priv->firm_version < 0x0302) - demod += 200; - /* - * The DTV7 S-code table needs a 700 kHz shift. - * - * DTV7 is only used in Australia. Germany or Italy may also - * use this firmware after initialization, but a tune to a UHF - * channel should then cause DTV78 to be used. - * - * Unfortunately, on real-field tests, the s-code offset - * didn't work as expected, as reported by - * Robert Lowery - */ - } - - return generic_set_freq(fe, p->frequency, - V4L2_TUNER_DIGITAL_TV, type, 0, demod); -} - -static int xc2028_sleep(struct dvb_frontend *fe) -{ - struct xc2028_data *priv = fe->tuner_priv; - int rc = 0; - - /* Avoid firmware reload on slow devices or if PM disabled */ - if (no_poweroff || priv->ctrl.disable_power_mgmt) - return 0; - - tuner_dbg("Putting xc2028/3028 into poweroff mode.\n"); - if (debug > 1) { - tuner_dbg("Printing sleep stack trace:\n"); - dump_stack(); - } - - mutex_lock(&priv->lock); - - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00}); - else - rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00}); - - priv->cur_fw.type = 0; /* need firmware reload */ - - mutex_unlock(&priv->lock); - - return rc; -} - -static int xc2028_dvb_release(struct dvb_frontend *fe) -{ - struct xc2028_data *priv = fe->tuner_priv; - - tuner_dbg("%s called\n", __func__); - - mutex_lock(&xc2028_list_mutex); - - /* only perform final cleanup if this is the last instance */ - if (hybrid_tuner_report_instance_count(priv) == 1) { - kfree(priv->ctrl.fname); - free_firmware(priv); - } - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&xc2028_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct xc2028_data *priv = fe->tuner_priv; - - tuner_dbg("%s called\n", __func__); - - *frequency = priv->frequency; - - return 0; -} - -static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct xc2028_data *priv = fe->tuner_priv; - struct xc2028_ctrl *p = priv_cfg; - int rc = 0; - - tuner_dbg("%s called\n", __func__); - - mutex_lock(&priv->lock); - - memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); - if (priv->ctrl.max_len < 9) - priv->ctrl.max_len = 13; - - if (p->fname) { - if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) { - kfree(priv->ctrl.fname); - free_firmware(priv); - } - - priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); - if (priv->ctrl.fname == NULL) - rc = -ENOMEM; - } - - mutex_unlock(&priv->lock); - - return rc; -} - -static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { - .info = { - .name = "Xceive XC3028", - .frequency_min = 42000000, - .frequency_max = 864000000, - .frequency_step = 50000, - }, - - .set_config = xc2028_set_config, - .set_analog_params = xc2028_set_analog_freq, - .release = xc2028_dvb_release, - .get_frequency = xc2028_get_frequency, - .get_rf_strength = xc2028_signal, - .set_params = xc2028_set_params, - .sleep = xc2028_sleep, -}; - -struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg) -{ - struct xc2028_data *priv; - int instance; - - if (debug) - printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n"); - - if (NULL == cfg) - return NULL; - - if (!fe) { - printk(KERN_ERR "xc2028: No frontend!\n"); - return NULL; - } - - mutex_lock(&xc2028_list_mutex); - - instance = hybrid_tuner_request_state(struct xc2028_data, priv, - hybrid_tuner_instance_list, - cfg->i2c_adap, cfg->i2c_addr, - "xc2028"); - switch (instance) { - case 0: - /* memory allocation failure */ - goto fail; - break; - case 1: - /* new tuner instance */ - priv->ctrl.max_len = 13; - - mutex_init(&priv->lock); - - fe->tuner_priv = priv; - break; - case 2: - /* existing tuner instance */ - fe->tuner_priv = priv; - break; - } - - memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, - sizeof(xc2028_dvb_tuner_ops)); - - tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); - - if (cfg->ctrl) - xc2028_set_config(fe, cfg->ctrl); - - mutex_unlock(&xc2028_list_mutex); - - return fe; -fail: - mutex_unlock(&xc2028_list_mutex); - - xc2028_dvb_release(fe); - return NULL; -} - -EXPORT_SYMBOL(xc2028_attach); - -MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); -MODULE_AUTHOR("Michel Ludwig "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/* tuner-xc2028 - * - * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 - */ - -#ifndef __TUNER_XC2028_H__ -#define __TUNER_XC2028_H__ - -#include "dvb_frontend.h" - -#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" -#define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw" - -/* Dmoduler IF (kHz) */ -#define XC3028_FE_DEFAULT 0 /* Don't load SCODE */ -#define XC3028_FE_LG60 6000 -#define XC3028_FE_ATI638 6380 -#define XC3028_FE_OREN538 5380 -#define XC3028_FE_OREN36 3600 -#define XC3028_FE_TOYOTA388 3880 -#define XC3028_FE_TOYOTA794 7940 -#define XC3028_FE_DIBCOM52 5200 -#define XC3028_FE_ZARLINK456 4560 -#define XC3028_FE_CHINA 5200 - -enum firmware_type { - XC2028_AUTO = 0, /* By default, auto-detects */ - XC2028_D2633, - XC2028_D2620, -}; - -struct xc2028_ctrl { - char *fname; - int max_len; - int msleep; - unsigned int scode_table; - unsigned int mts :1; - unsigned int input1:1; - unsigned int vhfbw7:1; - unsigned int uhfbw8:1; - unsigned int disable_power_mgmt:1; - unsigned int read_not_reliable:1; - unsigned int demod; - enum firmware_type type:2; -}; - -struct xc2028_config { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; - struct xc2028_ctrl *ctrl; -}; - -/* xc2028 commands for callback */ -#define XC2028_TUNER_RESET 0 -#define XC2028_RESET_CLK 1 - -#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) -extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg); -#else -static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __func__); - return NULL; -} -#endif - -#endif /* __TUNER_XC2028_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028-types.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028-types.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028-types.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/tuner-xc2028-types.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/* tuner-xc2028_types - * - * This file includes internal tipes to be used inside tuner-xc2028. - * Shouldn't be included outside tuner-xc2028 - * - * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 - */ - -/* xc3028 firmware types */ - -/* BASE firmware should be loaded before any other firmware */ -#define BASE (1<<0) -#define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) - -/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ -#define F8MHZ (1<<1) - -/* Multichannel Television Sound (MTS) - Those firmwares are capable of using xc2038 DSP to decode audio and - produce a baseband audio output on some pins of the chip. - There are MTS firmwares for the most used video standards. It should be - required to use MTS firmwares, depending on the way audio is routed into - the bridge chip - */ -#define MTS (1<<2) - -/* FIXME: I have no idea what's the difference between - D2620 and D2633 firmwares - */ -#define D2620 (1<<3) -#define D2633 (1<<4) - -/* DTV firmwares for 6, 7 and 8 MHz - DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS - DTV8 - 8MHz - DVB-C/DVB-T - */ -#define DTV6 (1 << 5) -#define QAM (1 << 6) -#define DTV7 (1<<7) -#define DTV78 (1<<8) -#define DTV8 (1<<9) - -#define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) - -/* There's a FM | BASE firmware + FM specific firmware (std=0) */ -#define FM (1<<10) - -#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD) - -/* Applies only for FM firmware - Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) - */ -#define INPUT1 (1<<11) - - -/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) - and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) - There are variants both with and without NOGD - Those firmwares produce better result with LCD displays - */ -#define LCD (1<<12) - -/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) - and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) - The NOGD firmwares don't have group delay compensation filter - */ -#define NOGD (1<<13) - -/* Old firmwares were broken into init0 and init1 */ -#define INIT1 (1<<14) - -/* SCODE firmware selects particular behaviours */ -#define MONO (1 << 15) -#define ATSC (1 << 16) -#define IF (1 << 17) -#define LG60 (1 << 18) -#define ATI638 (1 << 19) -#define OREN538 (1 << 20) -#define OREN36 (1 << 21) -#define TOYOTA388 (1 << 22) -#define TOYOTA794 (1 << 23) -#define DIBCOM52 (1 << 24) -#define ZARLINK456 (1 << 25) -#define CHINA (1 << 26) -#define F6MHZ (1 << 27) -#define INPUT2 (1 << 28) -#define SCODE (1 << 29) - -/* This flag identifies that the scode table has a new format */ -#define HAS_IF (1 << 30) - -/* There are different scode tables for MTS and non-MTS. - The MTS firmwares support mono only - */ -#define SCODE_TYPES (SCODE | MTS) - - -/* Newer types not defined on videodev2.h. - The original idea were to move all those types to videodev2.h, but - it seemed overkill, since, with the exception of SECAM/K3, the other - types seem to be autodetected. - It is not clear where secam/k3 is used, nor we have a feedback of this - working or being autodetected by the standard secam firmware. - */ - -#define V4L2_STD_SECAM_K3 (0x04000000) - -/* Audio types */ - -#define V4L2_STD_A2_A (1LL<<32) -#define V4L2_STD_A2_B (1LL<<33) -#define V4L2_STD_NICAM_A (1LL<<34) -#define V4L2_STD_NICAM_B (1LL<<35) -#define V4L2_STD_AM (1LL<<36) -#define V4L2_STD_BTSC (1LL<<37) -#define V4L2_STD_EIAJ (1LL<<38) - -#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) -#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) - -/* To preserve backward compatibilty, - (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported - */ - -#define V4L2_STD_AUDIO (V4L2_STD_A2 | \ - V4L2_STD_NICAM | \ - V4L2_STD_AM | \ - V4L2_STD_BTSC | \ - V4L2_STD_EIAJ) - -/* Used standards with audio restrictions */ - -#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) -#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) -#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) -#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) -#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) -#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) -#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) -#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/xc5000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/xc5000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/xc5000.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/xc5000.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1181 +0,0 @@ -/* - * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2007 Xceive Corporation - * Copyright (c) 2007 Steven Toth - * Copyright (c) 2009 Devin Heitmueller - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "xc5000.h" -#include "tuner-i2c.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -static int no_poweroff; -module_param(no_poweroff, int, 0644); -MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" - "\t\t1 keep device energized and with tuner ready all the times.\n" - "\t\tFaster, but consumes more power and keeps the device hotter"); - -static DEFINE_MUTEX(xc5000_list_mutex); -static LIST_HEAD(hybrid_tuner_instance_list); - -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) - -#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" -#define XC5000_DEFAULT_FIRMWARE_SIZE 12401 - -struct xc5000_priv { - struct tuner_i2c_props i2c_props; - struct list_head hybrid_tuner_instance_list; - - u32 if_khz; - u32 freq_hz; - u32 bandwidth; - u8 video_standard; - u8 rf_mode; - u8 radio_input; -}; - -/* Misc Defines */ -#define MAX_TV_STANDARD 24 -#define XC_MAX_I2C_WRITE_LENGTH 64 - -/* Signal Types */ -#define XC_RF_MODE_AIR 0 -#define XC_RF_MODE_CABLE 1 - -/* Result codes */ -#define XC_RESULT_SUCCESS 0 -#define XC_RESULT_RESET_FAILURE 1 -#define XC_RESULT_I2C_WRITE_FAILURE 2 -#define XC_RESULT_I2C_READ_FAILURE 3 -#define XC_RESULT_OUT_OF_RANGE 5 - -/* Product id */ -#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 -#define XC_PRODUCT_ID_FW_LOADED 0x1388 - -/* Registers */ -#define XREG_INIT 0x00 -#define XREG_VIDEO_MODE 0x01 -#define XREG_AUDIO_MODE 0x02 -#define XREG_RF_FREQ 0x03 -#define XREG_D_CODE 0x04 -#define XREG_IF_OUT 0x05 -#define XREG_SEEK_MODE 0x07 -#define XREG_POWER_DOWN 0x0A /* Obsolete */ -/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */ -#define XREG_OUTPUT_AMP 0x0B -#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ -#define XREG_SMOOTHEDCVBS 0x0E -#define XREG_XTALFREQ 0x0F -#define XREG_FINERFREQ 0x10 -#define XREG_DDIMODE 0x11 - -#define XREG_ADC_ENV 0x00 -#define XREG_QUALITY 0x01 -#define XREG_FRAME_LINES 0x02 -#define XREG_HSYNC_FREQ 0x03 -#define XREG_LOCK 0x04 -#define XREG_FREQ_ERROR 0x05 -#define XREG_SNR 0x06 -#define XREG_VERSION 0x07 -#define XREG_PRODUCT_ID 0x08 -#define XREG_BUSY 0x09 -#define XREG_BUILD 0x0D - -/* - Basic firmware description. This will remain with - the driver for documentation purposes. - - This represents an I2C firmware file encoded as a - string of unsigned char. Format is as follows: - - char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB - char[1 ]=len0_LSB -> length of first write transaction - char[2 ]=data0 -> first byte to be sent - char[3 ]=data1 - char[4 ]=data2 - char[ ]=... - char[M ]=dataN -> last byte to be sent - char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB - char[M+2]=len1_LSB -> length of second write transaction - char[M+3]=data0 - char[M+4]=data1 - ... - etc. - - The [len] value should be interpreted as follows: - - len= len_MSB _ len_LSB - len=1111_1111_1111_1111 : End of I2C_SEQUENCE - len=0000_0000_0000_0000 : Reset command: Do hardware reset - len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) - len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms - - For the RESET and WAIT commands, the two following bytes will contain - immediately the length of the following transaction. - -*/ -struct XC_TV_STANDARD { - char *Name; - u16 AudioMode; - u16 VideoMode; -}; - -/* Tuner standards */ -#define MN_NTSC_PAL_BTSC 0 -#define MN_NTSC_PAL_A2 1 -#define MN_NTSC_PAL_EIAJ 2 -#define MN_NTSC_PAL_Mono 3 -#define BG_PAL_A2 4 -#define BG_PAL_NICAM 5 -#define BG_PAL_MONO 6 -#define I_PAL_NICAM 7 -#define I_PAL_NICAM_MONO 8 -#define DK_PAL_A2 9 -#define DK_PAL_NICAM 10 -#define DK_PAL_MONO 11 -#define DK_SECAM_A2DK1 12 -#define DK_SECAM_A2LDK3 13 -#define DK_SECAM_A2MONO 14 -#define L_SECAM_NICAM 15 -#define LC_SECAM_NICAM 16 -#define DTV6 17 -#define DTV8 18 -#define DTV7_8 19 -#define DTV7 20 -#define FM_Radio_INPUT2 21 -#define FM_Radio_INPUT1 22 -#define FM_Radio_INPUT1_MONO 23 - -static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { - {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, - {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, - {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, - {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, - {"B/G-PAL-A2", 0x0A00, 0x8049}, - {"B/G-PAL-NICAM", 0x0C04, 0x8049}, - {"B/G-PAL-MONO", 0x0878, 0x8059}, - {"I-PAL-NICAM", 0x1080, 0x8009}, - {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, - {"D/K-PAL-A2", 0x1600, 0x8009}, - {"D/K-PAL-NICAM", 0x0E80, 0x8009}, - {"D/K-PAL-MONO", 0x1478, 0x8009}, - {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, - {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009}, - {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, - {"L-SECAM-NICAM", 0x8E82, 0x0009}, - {"L'-SECAM-NICAM", 0x8E82, 0x4009}, - {"DTV6", 0x00C0, 0x8002}, - {"DTV8", 0x00C0, 0x800B}, - {"DTV7/8", 0x00C0, 0x801B}, - {"DTV7", 0x00C0, 0x8007}, - {"FM Radio-INPUT2", 0x9802, 0x9002}, - {"FM Radio-INPUT1", 0x0208, 0x9002}, - {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} -}; - -static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); -static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); -static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); -static int xc5000_TunerReset(struct dvb_frontend *fe); - -static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) -{ - struct i2c_msg msg = { .addr = priv->i2c_props.addr, - .flags = 0, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); - return XC_RESULT_I2C_WRITE_FAILURE; - } - return XC_RESULT_SUCCESS; -} - -#if 0 -/* This routine is never used because the only time we read data from the - i2c bus is when we read registers, and we want that to be an atomic i2c - transaction in case we are on a multi-master bus */ -static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) -{ - struct i2c_msg msg = { .addr = priv->i2c_props.addr, - .flags = I2C_M_RD, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); - return -EREMOTEIO; - } - return 0; -} -#endif - -static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) -{ - u8 buf[2] = { reg >> 8, reg & 0xff }; - u8 bval[2] = { 0, 0 }; - struct i2c_msg msg[2] = { - { .addr = priv->i2c_props.addr, - .flags = 0, .buf = &buf[0], .len = 2 }, - { .addr = priv->i2c_props.addr, - .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, - }; - - if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { - printk(KERN_WARNING "xc5000: I2C read failed\n"); - return -EREMOTEIO; - } - - *val = (bval[0] << 8) | bval[1]; - return XC_RESULT_SUCCESS; -} - -static void xc_wait(int wait_ms) -{ - msleep(wait_ms); -} - -static int xc5000_TunerReset(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - - dprintk(1, "%s()\n", __func__); - - if (fe->callback) { - ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? - fe->dvb->priv : - priv->i2c_props.adap->algo_data, - DVB_FRONTEND_COMPONENT_TUNER, - XC5000_TUNER_RESET, 0); - if (ret) { - printk(KERN_ERR "xc5000: reset failed\n"); - return XC_RESULT_RESET_FAILURE; - } - } else { - printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); - return XC_RESULT_RESET_FAILURE; - } - return XC_RESULT_SUCCESS; -} - -static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) -{ - u8 buf[4]; - int WatchDogTimer = 100; - int result; - - buf[0] = (regAddr >> 8) & 0xFF; - buf[1] = regAddr & 0xFF; - buf[2] = (i2cData >> 8) & 0xFF; - buf[3] = i2cData & 0xFF; - result = xc_send_i2c_data(priv, buf, 4); - if (result == XC_RESULT_SUCCESS) { - /* wait for busy flag to clear */ - while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { - result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf); - if (result == XC_RESULT_SUCCESS) { - if ((buf[0] == 0) && (buf[1] == 0)) { - /* busy flag cleared */ - break; - } else { - xc_wait(5); /* wait 5 ms */ - WatchDogTimer--; - } - } - } - } - if (WatchDogTimer < 0) - result = XC_RESULT_I2C_WRITE_FAILURE; - - return result; -} - -static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) -{ - struct xc5000_priv *priv = fe->tuner_priv; - - int i, nbytes_to_send, result; - unsigned int len, pos, index; - u8 buf[XC_MAX_I2C_WRITE_LENGTH]; - - index = 0; - while ((i2c_sequence[index] != 0xFF) || - (i2c_sequence[index + 1] != 0xFF)) { - len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; - if (len == 0x0000) { - /* RESET command */ - result = xc5000_TunerReset(fe); - index += 2; - if (result != XC_RESULT_SUCCESS) - return result; - } else if (len & 0x8000) { - /* WAIT command */ - xc_wait(len & 0x7FFF); - index += 2; - } else { - /* Send i2c data whilst ensuring individual transactions - * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. - */ - index += 2; - buf[0] = i2c_sequence[index]; - buf[1] = i2c_sequence[index + 1]; - pos = 2; - while (pos < len) { - if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) - nbytes_to_send = - XC_MAX_I2C_WRITE_LENGTH; - else - nbytes_to_send = (len - pos + 2); - for (i = 2; i < nbytes_to_send; i++) { - buf[i] = i2c_sequence[index + pos + - i - 2]; - } - result = xc_send_i2c_data(priv, buf, - nbytes_to_send); - - if (result != XC_RESULT_SUCCESS) - return result; - - pos += nbytes_to_send - 2; - } - index += len; - } - } - return XC_RESULT_SUCCESS; -} - -static int xc_initialize(struct xc5000_priv *priv) -{ - dprintk(1, "%s()\n", __func__); - return xc_write_reg(priv, XREG_INIT, 0); -} - -static int xc_SetTVStandard(struct xc5000_priv *priv, - u16 VideoMode, u16 AudioMode) -{ - int ret; - dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode); - dprintk(1, "%s() Standard = %s\n", - __func__, - XC5000_Standard[priv->video_standard].Name); - - ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); - if (ret == XC_RESULT_SUCCESS) - ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); - - return ret; -} - -static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) -{ - dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, - rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); - - if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { - rf_mode = XC_RF_MODE_CABLE; - printk(KERN_ERR - "%s(), Invalid mode, defaulting to CABLE", - __func__); - } - return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); -} - -static const struct dvb_tuner_ops xc5000_tuner_ops; - -static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) -{ - u16 freq_code; - - dprintk(1, "%s(%u)\n", __func__, freq_hz); - - if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || - (freq_hz < xc5000_tuner_ops.info.frequency_min)) - return XC_RESULT_OUT_OF_RANGE; - - freq_code = (u16)(freq_hz / 15625); - - /* Starting in firmware version 1.1.44, Xceive recommends using the - FINERFREQ for all normal tuning (the doc indicates reg 0x03 should - only be used for fast scanning for channel lock) */ - return xc_write_reg(priv, XREG_FINERFREQ, freq_code); -} - - -static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) -{ - u32 freq_code = (freq_khz * 1024)/1000; - dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", - __func__, freq_khz, freq_code); - - return xc_write_reg(priv, XREG_IF_OUT, freq_code); -} - - -static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) -{ - return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); -} - -static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) -{ - int result; - u16 regData; - u32 tmp; - - result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data); - if (result != XC_RESULT_SUCCESS) - return result; - - tmp = (u32)regData; - (*freq_error_hz) = (tmp * 15625) / 1000; - return result; -} - -static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) -{ - return xc5000_readreg(priv, XREG_LOCK, lock_status); -} - -static int xc_get_version(struct xc5000_priv *priv, - u8 *hw_majorversion, u8 *hw_minorversion, - u8 *fw_majorversion, u8 *fw_minorversion) -{ - u16 data; - int result; - - result = xc5000_readreg(priv, XREG_VERSION, &data); - if (result != XC_RESULT_SUCCESS) - return result; - - (*hw_majorversion) = (data >> 12) & 0x0F; - (*hw_minorversion) = (data >> 8) & 0x0F; - (*fw_majorversion) = (data >> 4) & 0x0F; - (*fw_minorversion) = data & 0x0F; - - return 0; -} - -static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) -{ - return xc5000_readreg(priv, XREG_BUILD, buildrev); -} - -static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) -{ - u16 regData; - int result; - - result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data); - if (result != XC_RESULT_SUCCESS) - return result; - - (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; - return result; -} - -static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) -{ - return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); -} - -static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) -{ - return xc5000_readreg(priv, XREG_QUALITY, quality); -} - -static u16 WaitForLock(struct xc5000_priv *priv) -{ - u16 lockState = 0; - int watchDogCount = 40; - - while ((lockState == 0) && (watchDogCount > 0)) { - xc_get_lock_status(priv, &lockState); - if (lockState != 1) { - xc_wait(5); - watchDogCount--; - } - } - return lockState; -} - -#define XC_TUNE_ANALOG 0 -#define XC_TUNE_DIGITAL 1 -static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) -{ - int found = 0; - - dprintk(1, "%s(%u)\n", __func__, freq_hz); - - if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) - return 0; - - if (mode == XC_TUNE_ANALOG) { - if (WaitForLock(priv) == 1) - found = 1; - } - - return found; -} - - -static int xc5000_fwupload(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - const struct firmware *fw; - int ret; - - /* request the firmware, this will block and timeout */ - printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", - XC5000_DEFAULT_FIRMWARE); - - ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, - priv->i2c_props.adap->dev.parent); - if (ret) { - printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); - ret = XC_RESULT_RESET_FAILURE; - goto out; - } else { - printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n", - fw->size); - ret = XC_RESULT_SUCCESS; - } - - if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { - printk(KERN_ERR "xc5000: firmware incorrect size\n"); - ret = XC_RESULT_RESET_FAILURE; - } else { - printk(KERN_INFO "xc5000: firmware uploading...\n"); - ret = xc_load_i2c_sequence(fe, fw->data); - printk(KERN_INFO "xc5000: firmware upload complete...\n"); - } - -out: - release_firmware(fw); - return ret; -} - -static void xc_debug_dump(struct xc5000_priv *priv) -{ - u16 adc_envelope; - u32 freq_error_hz = 0; - u16 lock_status; - u32 hsync_freq_hz = 0; - u16 frame_lines; - u16 quality; - u8 hw_majorversion = 0, hw_minorversion = 0; - u8 fw_majorversion = 0, fw_minorversion = 0; - u16 fw_buildversion = 0; - - /* Wait for stats to stabilize. - * Frame Lines needs two frame times after initial lock - * before it is valid. - */ - xc_wait(100); - - xc_get_ADC_Envelope(priv, &adc_envelope); - dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); - - xc_get_frequency_error(priv, &freq_error_hz); - dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); - - xc_get_lock_status(priv, &lock_status); - dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", - lock_status); - - xc_get_version(priv, &hw_majorversion, &hw_minorversion, - &fw_majorversion, &fw_minorversion); - xc_get_buildversion(priv, &fw_buildversion); - dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n", - hw_majorversion, hw_minorversion, - fw_majorversion, fw_minorversion, fw_buildversion); - - xc_get_hsync_freq(priv, &hsync_freq_hz); - dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); - - xc_get_frame_lines(priv, &frame_lines); - dprintk(1, "*** Frame lines = %d\n", frame_lines); - - xc_get_quality(priv, &quality); - dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); -} - -static int xc5000_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - - if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { - if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { - dprintk(1, "Unable to load firmware and init tuner\n"); - return -EINVAL; - } - } - - dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); - - if (fe->ops.info.type == FE_ATSC) { - dprintk(1, "%s() ATSC\n", __func__); - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - dprintk(1, "%s() VSB modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - default: - return -EINVAL; - } - } else if (fe->ops.info.type == FE_OFDM) { - dprintk(1, "%s() OFDM\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - priv->freq_hz = params->frequency - 1750000; - break; - case BANDWIDTH_7_MHZ: - printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n"); - return -EINVAL; - case BANDWIDTH_8_MHZ: - priv->bandwidth = BANDWIDTH_8_MHZ; - priv->video_standard = DTV8; - priv->freq_hz = params->frequency - 2750000; - break; - default: - printk(KERN_ERR "xc5000 bandwidth not set!\n"); - return -EINVAL; - } - priv->rf_mode = XC_RF_MODE_AIR; - } else if (fe->ops.info.type == FE_QAM) { - dprintk(1, "%s() QAM\n", __func__); - switch (params->u.qam.modulation) { - case QAM_16: - case QAM_32: - case QAM_64: - case QAM_128: - case QAM_256: - case QAM_AUTO: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->bandwidth = BANDWIDTH_8_MHZ; - priv->video_standard = DTV7_8; - priv->freq_hz = params->frequency - 2750000; - priv->rf_mode = XC_RF_MODE_CABLE; - break; - default: - return -EINVAL; - } - } else { - printk(KERN_ERR "xc5000 modulation type not supported!\n"); - return -EINVAL; - } - - dprintk(1, "%s() frequency=%d (compensated)\n", - __func__, priv->freq_hz); - - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - ret = xc_SetTVStandard(priv, - XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); - return -EREMOTEIO; - } - - ret = xc_set_IF_frequency(priv, priv->if_khz); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", - priv->if_khz); - return -EIO; - } - - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); - - xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); - - if (debug) - xc_debug_dump(priv); - - return 0; -} - -static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - u16 id; - - ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id); - if (ret == XC_RESULT_SUCCESS) { - if (id == XC_PRODUCT_ID_FW_NOT_LOADED) - ret = XC_RESULT_RESET_FAILURE; - else - ret = XC_RESULT_SUCCESS; - } - - dprintk(1, "%s() returns %s id = 0x%x\n", __func__, - ret == XC_RESULT_SUCCESS ? "True" : "False", id); - return ret; -} - -static int xc5000_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - - dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", - __func__, params->frequency); - - /* Fix me: it could be air. */ - priv->rf_mode = params->mode; - if (params->mode > XC_RF_MODE_CABLE) - priv->rf_mode = XC_RF_MODE_CABLE; - - /* params->frequency is in units of 62.5khz */ - priv->freq_hz = params->frequency * 62500; - - /* FIX ME: Some video standards may have several possible audio - standards. We simply default to one of them here. - */ - if (params->std & V4L2_STD_MN) { - /* default to BTSC audio standard */ - priv->video_standard = MN_NTSC_PAL_BTSC; - goto tune_channel; - } - - if (params->std & V4L2_STD_PAL_BG) { - /* default to NICAM audio standard */ - priv->video_standard = BG_PAL_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_PAL_I) { - /* default to NICAM audio standard */ - priv->video_standard = I_PAL_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_PAL_DK) { - /* default to NICAM audio standard */ - priv->video_standard = DK_PAL_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_SECAM_DK) { - /* default to A2 DK1 audio standard */ - priv->video_standard = DK_SECAM_A2DK1; - goto tune_channel; - } - - if (params->std & V4L2_STD_SECAM_L) { - priv->video_standard = L_SECAM_NICAM; - goto tune_channel; - } - - if (params->std & V4L2_STD_SECAM_LC) { - priv->video_standard = LC_SECAM_NICAM; - goto tune_channel; - } - -tune_channel: - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - ret = xc_SetTVStandard(priv, - XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); - return -EREMOTEIO; - } - - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); - - xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); - - if (debug) - xc_debug_dump(priv); - - return 0; -} - -static int xc5000_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - u8 radio_input; - - dprintk(1, "%s() frequency=%d (in units of khz)\n", - __func__, params->frequency); - - if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) { - dprintk(1, "%s() radio input not configured\n", __func__); - return -EINVAL; - } - - if (priv->radio_input == XC5000_RADIO_FM1) - radio_input = FM_Radio_INPUT1; - else if (priv->radio_input == XC5000_RADIO_FM2) - radio_input = FM_Radio_INPUT2; - else if (priv->radio_input == XC5000_RADIO_FM1_MONO) - radio_input = FM_Radio_INPUT1_MONO; - else { - dprintk(1, "%s() unknown radio input %d\n", __func__, - priv->radio_input); - return -EINVAL; - } - - priv->freq_hz = params->frequency * 125 / 2; - - priv->rf_mode = XC_RF_MODE_AIR; - - ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode, - XC5000_Standard[radio_input].AudioMode); - - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); - return -EREMOTEIO; - } - - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - if ((priv->radio_input == XC5000_RADIO_FM1) || - (priv->radio_input == XC5000_RADIO_FM2)) - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); - else if (priv->radio_input == XC5000_RADIO_FM1_MONO) - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06); - - xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); - - return 0; -} - -static int xc5000_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; - - if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { - if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { - dprintk(1, "Unable to load firmware and init tuner\n"); - return -EINVAL; - } - } - - switch (params->mode) { - case V4L2_TUNER_RADIO: - ret = xc5000_set_radio_freq(fe, params); - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = xc5000_set_tv_freq(fe, params); - break; - } - - return ret; -} - - -static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - *freq = priv->freq_hz; - return 0; -} - -static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - - *bw = priv->bandwidth; - return 0; -} - -static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct xc5000_priv *priv = fe->tuner_priv; - u16 lock_status = 0; - - xc_get_lock_status(priv, &lock_status); - - dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status); - - *status = lock_status; - - return 0; -} - -static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret = 0; - - if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { - ret = xc5000_fwupload(fe); - if (ret != XC_RESULT_SUCCESS) - return ret; - } - - /* Start the tuner self-calibration process */ - ret |= xc_initialize(priv); - - /* Wait for calibration to complete. - * We could continue but XC5000 will clock stretch subsequent - * I2C transactions until calibration is complete. This way we - * don't have to rely on clock stretching working. - */ - xc_wait(100); - - /* Default to "CABLE" mode */ - ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); - - return ret; -} - -static int xc5000_sleep(struct dvb_frontend *fe) -{ - int ret; - - dprintk(1, "%s()\n", __func__); - - /* Avoid firmware reload on slow devices */ - if (no_poweroff) - return 0; - - /* According to Xceive technical support, the "powerdown" register - was removed in newer versions of the firmware. The "supported" - way to sleep the tuner is to pull the reset pin low for 10ms */ - ret = xc5000_TunerReset(fe); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: %s() unable to shutdown tuner\n", - __func__); - return -EREMOTEIO; - } else - return XC_RESULT_SUCCESS; -} - -static int xc5000_init(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - - if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); - return -EREMOTEIO; - } - - if (debug) - xc_debug_dump(priv); - - return 0; -} - -static int xc5000_release(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - - dprintk(1, "%s()\n", __func__); - - mutex_lock(&xc5000_list_mutex); - - if (priv) - hybrid_tuner_release_state(priv); - - mutex_unlock(&xc5000_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct xc5000_priv *priv = fe->tuner_priv; - struct xc5000_config *p = priv_cfg; - - dprintk(1, "%s()\n", __func__); - - if (p->if_khz) - priv->if_khz = p->if_khz; - - if (p->radio_input) - priv->radio_input = p->radio_input; - - return 0; -} - - -static const struct dvb_tuner_ops xc5000_tuner_ops = { - .info = { - .name = "Xceive XC5000", - .frequency_min = 1000000, - .frequency_max = 1023000000, - .frequency_step = 50000, - }, - - .release = xc5000_release, - .init = xc5000_init, - .sleep = xc5000_sleep, - - .set_config = xc5000_set_config, - .set_params = xc5000_set_params, - .set_analog_params = xc5000_set_analog_params, - .get_frequency = xc5000_get_frequency, - .get_bandwidth = xc5000_get_bandwidth, - .get_status = xc5000_get_status -}; - -struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct xc5000_config *cfg) -{ - struct xc5000_priv *priv = NULL; - int instance; - u16 id = 0; - - dprintk(1, "%s(%d-%04x)\n", __func__, - i2c ? i2c_adapter_id(i2c) : -1, - cfg ? cfg->i2c_address : -1); - - mutex_lock(&xc5000_list_mutex); - - instance = hybrid_tuner_request_state(struct xc5000_priv, priv, - hybrid_tuner_instance_list, - i2c, cfg->i2c_address, "xc5000"); - switch (instance) { - case 0: - goto fail; - break; - case 1: - /* new tuner instance */ - priv->bandwidth = BANDWIDTH_6_MHZ; - fe->tuner_priv = priv; - break; - default: - /* existing tuner instance */ - fe->tuner_priv = priv; - break; - } - - if (priv->if_khz == 0) { - /* If the IF hasn't been set yet, use the value provided by - the caller (occurs in hybrid devices where the analog - call to xc5000_attach occurs before the digital side) */ - priv->if_khz = cfg->if_khz; - } - - if (priv->radio_input == 0) - priv->radio_input = cfg->radio_input; - - /* Check if firmware has been loaded. It is possible that another - instance of the driver has loaded the firmware. - */ - if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) - goto fail; - - switch (id) { - case XC_PRODUCT_ID_FW_LOADED: - printk(KERN_INFO - "xc5000: Successfully identified at address 0x%02x\n", - cfg->i2c_address); - printk(KERN_INFO - "xc5000: Firmware has been loaded previously\n"); - break; - case XC_PRODUCT_ID_FW_NOT_LOADED: - printk(KERN_INFO - "xc5000: Successfully identified at address 0x%02x\n", - cfg->i2c_address); - printk(KERN_INFO - "xc5000: Firmware has not been loaded previously\n"); - break; - default: - printk(KERN_ERR - "xc5000: Device not found at addr 0x%02x (0x%x)\n", - cfg->i2c_address, id); - goto fail; - } - - mutex_unlock(&xc5000_list_mutex); - - memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - return fe; -fail: - mutex_unlock(&xc5000_list_mutex); - - xc5000_release(fe); - return NULL; -} -EXPORT_SYMBOL(xc5000_attach); - -MODULE_AUTHOR("Steven Toth"); -MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/xc5000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/xc5000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/xc5000.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/common/tuners/xc5000.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -/* - * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2007 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __XC5000_H__ -#define __XC5000_H__ - -#include - -struct dvb_frontend; -struct i2c_adapter; - -struct xc5000_config { - u8 i2c_address; - u32 if_khz; - u8 radio_input; -}; - -/* xc5000 callback command */ -#define XC5000_TUNER_RESET 0 - -/* Possible Radio inputs */ -#define XC5000_RADIO_NOT_CONFIGURED 0 -#define XC5000_RADIO_FM1 1 -#define XC5000_RADIO_FM2 2 -#define XC5000_RADIO_FM1_MONO 3 - -/* For each bridge framework, when it attaches either analog or digital, - * it has to store a reference back to its _core equivalent structure, - * so that it can service the hardware by steering gpio's etc. - * Each bridge implementation is different so cast devptr accordingly. - * The xc5000 driver cares not for this value, other than ensuring - * it's passed back to a bridge during tuner_callback(). - */ - -#if defined(CONFIG_MEDIA_TUNER_XC5000) || \ - (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) -extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct xc5000_config *cfg); -#else -static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct xc5000_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,311 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop.c - main module part - * Copyright (C) 2004-9 Patrick Boettcher - * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc - * - * Acknowledgements: - * John Jurrius from BBTI, Inc. for extensive support - * with code examples and data books - * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting) - * - * Contributions to the skystar2-driver have been done by - * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes) - * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code) - * Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu) - * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac - * filtering) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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 "flexcop.h" - -#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip" -#define DRIVER_AUTHOR "Patrick Boettcher demux->priv; - return flexcop_pid_feed_control(fc, dvbdmxfeed, 1); -} - -static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct flexcop_device *fc = dvbdmxfeed->demux->priv; - return flexcop_pid_feed_control(fc, dvbdmxfeed, 0); -} - -static int flexcop_dvb_init(struct flexcop_device *fc) -{ - int ret = dvb_register_adapter(&fc->dvb_adapter, - "FlexCop Digital TV device", fc->owner, - fc->dev, adapter_nr); - if (ret < 0) { - err("error registering DVB adapter"); - return ret; - } - fc->dvb_adapter.priv = fc; - - fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING - | DMX_MEMORY_BASED_FILTERING); - fc->demux.priv = fc; - fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED; - fc->demux.start_feed = flexcop_dvb_start_feed; - fc->demux.stop_feed = flexcop_dvb_stop_feed; - fc->demux.write_to_decoder = NULL; - - if ((ret = dvb_dmx_init(&fc->demux)) < 0) { - err("dvb_dmx failed: error %d", ret); - goto err_dmx; - } - - fc->hw_frontend.source = DMX_FRONTEND_0; - - fc->dmxdev.filternum = fc->demux.feednum; - fc->dmxdev.demux = &fc->demux.dmx; - fc->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) { - err("dvb_dmxdev_init failed: error %d", ret); - goto err_dmx_dev; - } - - if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { - err("adding hw_frontend to dmx failed: error %d", ret); - goto err_dmx_add_hw_frontend; - } - - fc->mem_frontend.source = DMX_MEMORY_FE; - if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) { - err("adding mem_frontend to dmx failed: error %d", ret); - goto err_dmx_add_mem_frontend; - } - - if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { - err("connect frontend failed: error %d", ret); - goto err_connect_frontend; - } - - dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); - - fc->init_state |= FC_STATE_DVB_INIT; - return 0; - -err_connect_frontend: - fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend); -err_dmx_add_mem_frontend: - fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend); -err_dmx_add_hw_frontend: - dvb_dmxdev_release(&fc->dmxdev); -err_dmx_dev: - dvb_dmx_release(&fc->demux); -err_dmx: - dvb_unregister_adapter(&fc->dvb_adapter); - return ret; -} - -static void flexcop_dvb_exit(struct flexcop_device *fc) -{ - if (fc->init_state & FC_STATE_DVB_INIT) { - dvb_net_release(&fc->dvbnet); - - fc->demux.dmx.close(&fc->demux.dmx); - fc->demux.dmx.remove_frontend(&fc->demux.dmx, - &fc->mem_frontend); - fc->demux.dmx.remove_frontend(&fc->demux.dmx, - &fc->hw_frontend); - dvb_dmxdev_release(&fc->dmxdev); - dvb_dmx_release(&fc->demux); - dvb_unregister_adapter(&fc->dvb_adapter); - deb_info("deinitialized dvb stuff\n"); - } - fc->init_state &= ~FC_STATE_DVB_INIT; -} - -/* these methods are necessary to achieve the long-term-goal of hiding the - * struct flexcop_device from the bus-parts */ -void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len) -{ - dvb_dmx_swfilter(&fc->demux, buf, len); -} -EXPORT_SYMBOL(flexcop_pass_dmx_data); - -void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no) -{ - dvb_dmx_swfilter_packets(&fc->demux, buf, no); -} -EXPORT_SYMBOL(flexcop_pass_dmx_packets); - -static void flexcop_reset(struct flexcop_device *fc) -{ - flexcop_ibi_value v210, v204; - - /* reset the flexcop itself */ - fc->write_ibi_reg(fc,ctrl_208,ibi_zero); - - v210.raw = 0; - v210.sw_reset_210.reset_block_000 = 1; - v210.sw_reset_210.reset_block_100 = 1; - v210.sw_reset_210.reset_block_200 = 1; - v210.sw_reset_210.reset_block_300 = 1; - v210.sw_reset_210.reset_block_400 = 1; - v210.sw_reset_210.reset_block_500 = 1; - v210.sw_reset_210.reset_block_600 = 1; - v210.sw_reset_210.reset_block_700 = 1; - v210.sw_reset_210.Block_reset_enable = 0xb2; - v210.sw_reset_210.Special_controls = 0xc259; - fc->write_ibi_reg(fc,sw_reset_210,v210); - msleep(1); - - /* reset the periphical devices */ - - v204 = fc->read_ibi_reg(fc,misc_204); - v204.misc_204.Per_reset_sig = 0; - fc->write_ibi_reg(fc,misc_204,v204); - msleep(1); - v204.misc_204.Per_reset_sig = 1; - fc->write_ibi_reg(fc,misc_204,v204); -} - -void flexcop_reset_block_300(struct flexcop_device *fc) -{ - flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208), - v210 = fc->read_ibi_reg(fc, sw_reset_210); - - deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw); - fc->write_ibi_reg(fc,ctrl_208,ibi_zero); - - v210.sw_reset_210.reset_block_300 = 1; - v210.sw_reset_210.Block_reset_enable = 0xb2; - - fc->write_ibi_reg(fc,sw_reset_210,v210); - fc->write_ibi_reg(fc,ctrl_208,v208_save); -} - -struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) -{ - void *bus; - struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device), - GFP_KERNEL); - if (!fc) { - err("no memory"); - return NULL; - } - - bus = kzalloc(bus_specific_len, GFP_KERNEL); - if (!bus) { - err("no memory"); - kfree(fc); - return NULL; - } - - fc->bus_specific = bus; - - return fc; -} -EXPORT_SYMBOL(flexcop_device_kmalloc); - -void flexcop_device_kfree(struct flexcop_device *fc) -{ - kfree(fc->bus_specific); - kfree(fc); -} -EXPORT_SYMBOL(flexcop_device_kfree); - -int flexcop_device_initialize(struct flexcop_device *fc) -{ - int ret; - ibi_zero.raw = 0; - - flexcop_reset(fc); - flexcop_determine_revision(fc); - flexcop_sram_init(fc); - flexcop_hw_filter_init(fc); - flexcop_smc_ctrl(fc, 0); - - if ((ret = flexcop_dvb_init(fc))) - goto error; - - /* i2c has to be done before doing EEProm stuff - - * because the EEProm is accessed via i2c */ - ret = flexcop_i2c_init(fc); - if (ret) - goto error; - - /* do the MAC address reading after initializing the dvb_adapter */ - if (fc->get_mac_addr(fc, 0) == 0) { - u8 *b = fc->dvb_adapter.proposed_mac; - info("MAC address = %pM", b); - flexcop_set_mac_filter(fc,b); - flexcop_mac_filter_ctrl(fc,1); - } else - warn("reading of MAC address failed.\n"); - - if ((ret = flexcop_frontend_init(fc))) - goto error; - - flexcop_device_name(fc,"initialization of","complete"); - return 0; - -error: - flexcop_device_exit(fc); - return ret; -} -EXPORT_SYMBOL(flexcop_device_initialize); - -void flexcop_device_exit(struct flexcop_device *fc) -{ - flexcop_frontend_exit(fc); - flexcop_i2c_exit(fc); - flexcop_dvb_exit(fc); -} -EXPORT_SYMBOL(flexcop_device_exit); - -static int flexcop_module_init(void) -{ - info(DRIVER_NAME " loaded successfully"); - return 0; -} - -static void flexcop_module_cleanup(void) -{ - info(DRIVER_NAME " unloaded successfully"); -} - -module_init(flexcop_module_init); -module_exit(flexcop_module_cleanup); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_NAME); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-common.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,184 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-common.h - common header file for device-specific source files - * see flexcop.c for copyright information - */ -#ifndef __FLEXCOP_COMMON_H__ -#define __FLEXCOP_COMMON_H__ - -#include -#include - -#include "flexcop-reg.h" - -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_filter.h" -#include "dvb_net.h" -#include "dvb_frontend.h" - -#define FC_MAX_FEED 256 - -#ifndef FC_LOG_PREFIX -#warning please define a log prefix for your file, using a default one -#define FC_LOG_PREFIX "b2c2-undef" -#endif - -/* Steal from usb.h */ -#undef err -#define err(format, arg...) \ - printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg) -#undef info -#define info(format, arg...) \ - printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) \ - printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg) - -struct flexcop_dma { - struct pci_dev *pdev; - - u8 *cpu_addr0; - dma_addr_t dma_addr0; - u8 *cpu_addr1; - dma_addr_t dma_addr1; - u32 size; /* size of each address in bytes */ -}; - -struct flexcop_i2c_adapter { - struct flexcop_device *fc; - struct i2c_adapter i2c_adap; - - u8 no_base_addr; - flexcop_i2c_port_t port; -}; - -/* Control structure for data definitions that are common to - * the B2C2-based PCI and USB devices. - */ -struct flexcop_device { - /* general */ - struct device *dev; /* for firmware_class */ - -#define FC_STATE_DVB_INIT 0x01 -#define FC_STATE_I2C_INIT 0x02 -#define FC_STATE_FE_INIT 0x04 - int init_state; - - /* device information */ - int has_32_hw_pid_filter; - flexcop_revision_t rev; - flexcop_device_type_t dev_type; - flexcop_bus_t bus_type; - - /* dvb stuff */ - struct dvb_adapter dvb_adapter; - struct dvb_frontend *fe; - struct dvb_net dvbnet; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - int (*fe_sleep) (struct dvb_frontend *); - - struct flexcop_i2c_adapter fc_i2c_adap[3]; - struct mutex i2c_mutex; - struct module *owner; - - /* options and status */ - int extra_feedcount; - int feedcount; - int pid_filtering; - int fullts_streaming_state; - - /* bus specific callbacks */ - flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *, - flexcop_ibi_register); - int (*write_ibi_reg) (struct flexcop_device *, - flexcop_ibi_register, flexcop_ibi_value); - int (*i2c_request) (struct flexcop_i2c_adapter *, - flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); - int (*stream_control) (struct flexcop_device *, int); - int (*get_mac_addr) (struct flexcop_device *fc, int extended); - void *bus_specific; -}; - -/* exported prototypes */ - -/* from flexcop.c */ -void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len); -void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no); - -struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len); -void flexcop_device_kfree(struct flexcop_device *); - -int flexcop_device_initialize(struct flexcop_device *); -void flexcop_device_exit(struct flexcop_device *fc); -void flexcop_reset_block_300(struct flexcop_device *fc); - -/* from flexcop-dma.c */ -int flexcop_dma_allocate(struct pci_dev *pdev, - struct flexcop_dma *dma, u32 size); -void flexcop_dma_free(struct flexcop_dma *dma); - -int flexcop_dma_control_timer_irq(struct flexcop_device *fc, - flexcop_dma_index_t no, int onoff); -int flexcop_dma_control_size_irq(struct flexcop_device *fc, - flexcop_dma_index_t no, int onoff); -int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, - flexcop_dma_index_t dma_idx); -int flexcop_dma_xfer_control(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, - int onoff); -int flexcop_dma_config_timer(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, u8 cycles); - -/* from flexcop-eeprom.c */ -/* the PCI part uses this call to get the MAC address, the USB part has its own */ -int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended); - -/* from flexcop-i2c.c */ -/* the PCI part uses this a i2c_request callback, whereas the usb part has its own - * one. We have it in flexcop-i2c.c, because it is going via the actual - * I2C-channel of the flexcop. - */ -int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t, - u8 chipaddr, u8 addr, u8 *buf, u16 len); - -/* from flexcop-sram.c */ -int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, - flexcop_sram_dest_target_t target); -void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s); -void flexcop_sram_ctrl(struct flexcop_device *fc, - int usb_wan, int sramdma, int maximumfill); - -/* global prototypes for the flexcop-chip */ -/* from flexcop-fe-tuner.c */ -int flexcop_frontend_init(struct flexcop_device *fc); -void flexcop_frontend_exit(struct flexcop_device *fc); - -/* from flexcop-i2c.c */ -int flexcop_i2c_init(struct flexcop_device *fc); -void flexcop_i2c_exit(struct flexcop_device *fc); - -/* from flexcop-sram.c */ -int flexcop_sram_init(struct flexcop_device *fc); - -/* from flexcop-misc.c */ -void flexcop_determine_revision(struct flexcop_device *fc); -void flexcop_device_name(struct flexcop_device *fc, - const char *prefix, const char *suffix); -void flexcop_dump_reg(struct flexcop_device *fc, - flexcop_ibi_register reg, int num); - -/* from flexcop-hw-filter.c */ -int flexcop_pid_feed_control(struct flexcop_device *fc, - struct dvb_demux_feed *dvbdmxfeed, int onoff); -void flexcop_hw_filter_init(struct flexcop_device *fc); - -void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff); - -void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]); -void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-dma.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-dma.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-dma.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-dma.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,172 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-dma.c - configuring and controlling the DMA of the FlexCop - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -int flexcop_dma_allocate(struct pci_dev *pdev, - struct flexcop_dma *dma, u32 size) -{ - u8 *tcpu; - dma_addr_t tdma = 0; - - if (size % 2) { - err("dma buffersize has to be even."); - return -EINVAL; - } - - if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) { - dma->pdev = pdev; - dma->cpu_addr0 = tcpu; - dma->dma_addr0 = tdma; - dma->cpu_addr1 = tcpu + size/2; - dma->dma_addr1 = tdma + size/2; - dma->size = size/2; - return 0; - } - return -ENOMEM; -} -EXPORT_SYMBOL(flexcop_dma_allocate); - -void flexcop_dma_free(struct flexcop_dma *dma) -{ - pci_free_consistent(dma->pdev, dma->size*2, - dma->cpu_addr0, dma->dma_addr0); - memset(dma,0,sizeof(struct flexcop_dma)); -} -EXPORT_SYMBOL(flexcop_dma_free); - -int flexcop_dma_config(struct flexcop_device *fc, - struct flexcop_dma *dma, - flexcop_dma_index_t dma_idx) -{ - flexcop_ibi_value v0x0,v0x4,v0xc; - v0x0.raw = v0x4.raw = v0xc.raw = 0; - - v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; - v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; - v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; - - if ((dma_idx & FC_DMA_1) == dma_idx) { - fc->write_ibi_reg(fc,dma1_000,v0x0); - fc->write_ibi_reg(fc,dma1_004,v0x4); - fc->write_ibi_reg(fc,dma1_00c,v0xc); - } else if ((dma_idx & FC_DMA_2) == dma_idx) { - fc->write_ibi_reg(fc,dma2_010,v0x0); - fc->write_ibi_reg(fc,dma2_014,v0x4); - fc->write_ibi_reg(fc,dma2_01c,v0xc); - } else { - err("either DMA1 or DMA2 can be configured within one " - "flexcop_dma_config call."); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(flexcop_dma_config); - -/* start the DMA transfers, but not the DMA IRQs */ -int flexcop_dma_xfer_control(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, - flexcop_dma_addr_index_t index, - int onoff) -{ - flexcop_ibi_value v0x0,v0xc; - flexcop_ibi_register r0x0,r0xc; - - if ((dma_idx & FC_DMA_1) == dma_idx) { - r0x0 = dma1_000; - r0xc = dma1_00c; - } else if ((dma_idx & FC_DMA_2) == dma_idx) { - r0x0 = dma2_010; - r0xc = dma2_01c; - } else { - err("either transfer DMA1 or DMA2 can be started within one " - "flexcop_dma_xfer_control call."); - return -EINVAL; - } - - v0x0 = fc->read_ibi_reg(fc,r0x0); - v0xc = fc->read_ibi_reg(fc,r0xc); - - deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); - deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); - - if (index & FC_DMA_SUBADDR_0) - v0x0.dma_0x0.dma_0start = onoff; - - if (index & FC_DMA_SUBADDR_1) - v0xc.dma_0xc.dma_1start = onoff; - - fc->write_ibi_reg(fc,r0x0,v0x0); - fc->write_ibi_reg(fc,r0xc,v0xc); - - deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); - deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); - return 0; -} -EXPORT_SYMBOL(flexcop_dma_xfer_control); - -static int flexcop_dma_remap(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, - int onoff) -{ - flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; - flexcop_ibi_value v = fc->read_ibi_reg(fc,r); - deb_info("%s\n",__func__); - v.dma_0xc.remap_enable = onoff; - fc->write_ibi_reg(fc,r,v); - return 0; -} - -int flexcop_dma_control_size_irq(struct flexcop_device *fc, - flexcop_dma_index_t no, - int onoff) -{ - flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); - - if (no & FC_DMA_1) - v.ctrl_208.DMA1_IRQ_Enable_sig = onoff; - - if (no & FC_DMA_2) - v.ctrl_208.DMA2_IRQ_Enable_sig = onoff; - - fc->write_ibi_reg(fc,ctrl_208,v); - return 0; -} -EXPORT_SYMBOL(flexcop_dma_control_size_irq); - -int flexcop_dma_control_timer_irq(struct flexcop_device *fc, - flexcop_dma_index_t no, - int onoff) -{ - flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); - - if (no & FC_DMA_1) - v.ctrl_208.DMA1_Timer_Enable_sig = onoff; - - if (no & FC_DMA_2) - v.ctrl_208.DMA2_Timer_Enable_sig = onoff; - - fc->write_ibi_reg(fc,ctrl_208,v); - return 0; -} -EXPORT_SYMBOL(flexcop_dma_control_timer_irq); - -/* 1 cycles = 1.97 msec */ -int flexcop_dma_config_timer(struct flexcop_device *fc, - flexcop_dma_index_t dma_idx, u8 cycles) -{ - flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; - flexcop_ibi_value v = fc->read_ibi_reg(fc,r); - - flexcop_dma_remap(fc,dma_idx,0); - - deb_info("%s\n",__func__); - v.dma_0x4_write.dmatimer = cycles; - fc->write_ibi_reg(fc,r,v); - return 0; -} -EXPORT_SYMBOL(flexcop_dma_config_timer); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-eeprom.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-eeprom.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-eeprom.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-eeprom.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading) - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -#if 0 -/*EEPROM (Skystar2 has one "24LC08B" chip on board) */ -static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len) -{ - return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len); -} - -static int eeprom_lrc_write(struct adapter *adapter, u32 addr, - u32 len, u8 *wbuf, u8 *rbuf, int retries) -{ -int i; - -for (i = 0; i < retries; i++) { - if (eeprom_write(adapter, addr, wbuf, len) == len) { - if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1) - return 1; - } - } - return 0; -} - -/* These functions could be used to unlock SkyStar2 cards. */ - -static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len) -{ - u8 rbuf[20]; - u8 wbuf[20]; - - if (len != 16) - return 0; - - memcpy(wbuf, key, len); - wbuf[16] = 0; - wbuf[17] = 0; - wbuf[18] = 0; - wbuf[19] = calc_lrc(wbuf, 19); - return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4); -} - -static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len) -{ - u8 buf[20]; - - if (len != 16) - return 0; - - if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0) - return 0; - - memcpy(key, buf, len); - return 1; -} - -static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac) -{ - u8 tmp[8]; - - if (type != 0) { - tmp[0] = mac[0]; - tmp[1] = mac[1]; - tmp[2] = mac[2]; - tmp[3] = mac[5]; - tmp[4] = mac[6]; - tmp[5] = mac[7]; - } else { - tmp[0] = mac[0]; - tmp[1] = mac[1]; - tmp[2] = mac[2]; - tmp[3] = mac[3]; - tmp[4] = mac[4]; - tmp[5] = mac[5]; - } - - tmp[6] = 0; - tmp[7] = calc_lrc(tmp, 7); - - if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8) - return 1; - return 0; -} - -static int flexcop_eeprom_read(struct flexcop_device *fc, - u16 addr, u8 *buf, u16 len) -{ - return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len); -} - -#endif - -static u8 calc_lrc(u8 *buf, int len) -{ - int i; - u8 sum = 0; - for (i = 0; i < len; i++) - sum = sum ^ buf[i]; - return sum; -} - -static int flexcop_eeprom_request(struct flexcop_device *fc, - flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries) -{ - int i,ret = 0; - u8 chipaddr = 0x50 | ((addr >> 8) & 3); - for (i = 0; i < retries; i++) { - ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr, - addr & 0xff, buf, len); - if (ret == 0) - break; - } - return ret; -} - -static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, - u8 *buf, u16 len, int retries) -{ - int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries); - if (ret == 0) - if (calc_lrc(buf, len - 1) != buf[len - 1]) - ret = -EINVAL; - return ret; -} - -/* JJ's comment about extended == 1: it is not presently used anywhere but was - * added to the low-level functions for possible support of EUI64 */ -int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended) -{ - u8 buf[8]; - int ret = 0; - - if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) { - if (extended != 0) { - err("TODO: extended (EUI64) MAC addresses aren't " - "completely supported yet"); - ret = -EINVAL; - } else - memcpy(fc->dvb_adapter.proposed_mac,buf,6); - } - return ret; -} -EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,678 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling - * see flexcop.c for copyright information - */ -#include -#include "flexcop.h" -#include "mt312.h" -#include "stv0299.h" -#include "s5h1420.h" -#include "itd1000.h" -#include "cx24113.h" -#include "cx24123.h" -#include "isl6421.h" -#include "mt352.h" -#include "bcm3510.h" -#include "nxt200x.h" -#include "dvb-pll.h" -#include "lgdt330x.h" -#include "tuner-simple.h" -#include "stv0297.h" - - -/* Can we use the specified front-end? Remember that if we are compiled - * into the kernel we can't call code that's in modules. */ -#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \ - (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE))) - -/* lnb control */ -#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299) -static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct flexcop_device *fc = fe->dvb->priv; - flexcop_ibi_value v; - deb_tuner("polarity/voltage = %u\n", voltage); - - v = fc->read_ibi_reg(fc, misc_204); - switch (voltage) { - case SEC_VOLTAGE_OFF: - v.misc_204.ACPI1_sig = 1; - break; - case SEC_VOLTAGE_13: - v.misc_204.ACPI1_sig = 0; - v.misc_204.LNB_L_H_sig = 0; - break; - case SEC_VOLTAGE_18: - v.misc_204.ACPI1_sig = 0; - v.misc_204.LNB_L_H_sig = 1; - break; - default: - err("unknown SEC_VOLTAGE value"); - return -EINVAL; - } - return fc->write_ibi_reg(fc, misc_204, v); -} -#endif - -#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312) -static int flexcop_sleep(struct dvb_frontend* fe) -{ - struct flexcop_device *fc = fe->dvb->priv; - if (fc->fe_sleep) - return fc->fe_sleep(fe); - return 0; -} -#endif - -/* SkyStar2 DVB-S rev 2.3 */ -#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL) -static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ -/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ - struct flexcop_device *fc = fe->dvb->priv; - flexcop_ibi_value v; - u16 ax; - v.raw = 0; - deb_tuner("tone = %u\n",tone); - - switch (tone) { - case SEC_TONE_ON: - ax = 0x01ff; - break; - case SEC_TONE_OFF: - ax = 0; - break; - default: - err("unknown SEC_TONE value"); - return -EINVAL; - } - - v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ - v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax; - v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax; - return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); -} - -static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) -{ - flexcop_set_tone(fe, SEC_TONE_ON); - udelay(data ? 500 : 1000); - flexcop_set_tone(fe, SEC_TONE_OFF); - udelay(data ? 1000 : 500); -} - -static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) -{ - int i, par = 1, d; - for (i = 7; i >= 0; i--) { - d = (data >> i) & 1; - par ^= d; - flexcop_diseqc_send_bit(fe, d); - } - flexcop_diseqc_send_bit(fe, par); -} - -static int flexcop_send_diseqc_msg(struct dvb_frontend *fe, - int len, u8 *msg, unsigned long burst) -{ - int i; - - flexcop_set_tone(fe, SEC_TONE_OFF); - mdelay(16); - - for (i = 0; i < len; i++) - flexcop_diseqc_send_byte(fe,msg[i]); - mdelay(16); - - if (burst != -1) { - if (burst) - flexcop_diseqc_send_byte(fe, 0xff); - else { - flexcop_set_tone(fe, SEC_TONE_ON); - mdelay(12); - udelay(500); - flexcop_set_tone(fe, SEC_TONE_OFF); - } - msleep(20); - } - return 0; -} - -static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *cmd) -{ - return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); -} - -static int flexcop_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t minicmd) -{ - return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); -} - -static struct mt312_config skystar23_samsung_tbdu18132_config = { - .demod_address = 0x0e, -}; - -static int skystar2_rev23_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - struct dvb_frontend_ops *ops; - - fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c); - if (!fc->fe) - return 0; - - if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, - DVB_PLL_SAMSUNG_TBDU18132)) - return 0; - - ops = &fc->fe->ops; - ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; - ops->diseqc_send_burst = flexcop_diseqc_send_burst; - ops->set_tone = flexcop_set_tone; - ops->set_voltage = flexcop_set_voltage; - fc->fe_sleep = ops->sleep; - ops->sleep = flexcop_sleep; - return 1; -} -#else -#define skystar2_rev23_attach NULL -#endif - -/* SkyStar2 DVB-S rev 2.6 */ -#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL) -static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { - aclk = 0xb7; bclk = 0x47; - } else if (srate < 3000000) { - aclk = 0xb7; bclk = 0x4b; - } else if (srate < 7000000) { - aclk = 0xb7; bclk = 0x4f; - } else if (srate < 14000000) { - aclk = 0xb7; bclk = 0x53; - } else if (srate < 30000000) { - aclk = 0xb6; bclk = 0x53; - } else if (srate < 45000000) { - aclk = 0xb4; bclk = 0x51; - } - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, ratio & 0xf0); - return 0; -} - -static u8 samsung_tbmu24112_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7D, - 0x05, 0x35, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0xC3, - 0x0C, 0x00, - 0x0D, 0x81, - 0x0E, 0x23, - 0x0F, 0x12, - 0x10, 0x7E, - 0x11, 0x84, - 0x12, 0xB9, - 0x13, 0x88, - 0x14, 0x89, - 0x15, 0xC9, - 0x16, 0x00, - 0x17, 0x5C, - 0x18, 0x00, - 0x19, 0x00, - 0x1A, 0x00, - 0x1C, 0x00, - 0x1D, 0x00, - 0x1E, 0x00, - 0x1F, 0x3A, - 0x20, 0x2E, - 0x21, 0x80, - 0x22, 0xFF, - 0x23, 0xC1, - 0x28, 0x00, - 0x29, 0x1E, - 0x2A, 0x14, - 0x2B, 0x0F, - 0x2C, 0x09, - 0x2D, 0x05, - 0x31, 0x1F, - 0x32, 0x19, - 0x33, 0xFE, - 0x34, 0x93, - 0xff, 0xff, -}; - -static struct stv0299_config samsung_tbmu24112_config = { - .demod_address = 0x68, - .inittab = samsung_tbmu24112_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_LK, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, -}; - -static int skystar2_rev26_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); - if (!fc->fe) - return 0; - - if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, - DVB_PLL_SAMSUNG_TBMU24112)) - return 0; - - fc->fe->ops.set_voltage = flexcop_set_voltage; - fc->fe_sleep = fc->fe->ops.sleep; - fc->fe->ops.sleep = flexcop_sleep; - return 1; - -} -#else -#define skystar2_rev26_attach NULL -#endif - -/* SkyStar2 DVB-S rev 2.7 */ -#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000) -static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { - .demod_address = 0x53, - .invert = 1, - .repeated_start_workaround = 1, - .serial_mpeg = 1, -}; - -static struct itd1000_config skystar2_rev2_7_itd1000_config = { - .i2c_address = 0x61, -}; - -static int skystar2_rev27_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - flexcop_ibi_value r108; - struct i2c_adapter *i2c_tuner; - - /* enable no_base_addr - no repeated start when reading */ - fc->fc_i2c_adap[0].no_base_addr = 1; - fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, - i2c); - if (!fc->fe) - goto fail; - - i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe); - if (!i2c_tuner) - goto fail; - - fc->fe_sleep = fc->fe->ops.sleep; - fc->fe->ops.sleep = flexcop_sleep; - - /* enable no_base_addr - no repeated start when reading */ - fc->fc_i2c_adap[2].no_base_addr = 1; - if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, - 0x08, 1, 1)) { - err("ISL6421 could NOT be attached"); - goto fail_isl; - } - info("ISL6421 successfully attached"); - - /* the ITD1000 requires a lower i2c clock - is it a problem ? */ - r108.raw = 0x00000506; - fc->write_ibi_reg(fc, tw_sm_c_108, r108); - if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner, - &skystar2_rev2_7_itd1000_config)) { - err("ITD1000 could NOT be attached"); - /* Should i2c clock be restored? */ - goto fail_isl; - } - info("ITD1000 successfully attached"); - - return 1; - -fail_isl: - fc->fc_i2c_adap[2].no_base_addr = 0; -fail: - /* for the next devices we need it again */ - fc->fc_i2c_adap[0].no_base_addr = 0; - return 0; -} -#else -#define skystar2_rev27_attach NULL -#endif - -/* SkyStar2 rev 2.8 */ -#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113) -static struct cx24123_config skystar2_rev2_8_cx24123_config = { - .demod_address = 0x55, - .dont_use_pll = 1, - .agc_callback = cx24113_agc_callback, -}; - -static const struct cx24113_config skystar2_rev2_8_cx24113_config = { - .i2c_addr = 0x54, - .xtal_khz = 10111, -}; - -static int skystar2_rev28_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - struct i2c_adapter *i2c_tuner; - - fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config, - i2c); - if (!fc->fe) - return 0; - - i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe); - if (!i2c_tuner) - return 0; - - if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config, - i2c_tuner)) { - err("CX24113 could NOT be attached"); - return 0; - } - info("CX24113 successfully attached"); - - fc->fc_i2c_adap[2].no_base_addr = 1; - if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, - 0x08, 0, 0)) { - err("ISL6421 could NOT be attached"); - fc->fc_i2c_adap[2].no_base_addr = 0; - return 0; - } - info("ISL6421 successfully attached"); - /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an - * IR-receiver (PIC16F818) - but the card has no input for that ??? */ - return 1; -} -#else -#define skystar2_rev28_attach NULL -#endif - -/* AirStar DVB-T */ -#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL) -static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe) -{ - static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d }; - static u8 mt352_reset[] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - return 0; -} - -static struct mt352_config samsung_tdtc9251dh0_config = { - .demod_address = 0x0f, - .demod_init = samsung_tdtc9251dh0_demod_init, -}; - -static int airstar_dvbt_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); - if (!fc->fe) - return 0; - - return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, - DVB_PLL_SAMSUNG_TDTC9251DH0); -} -#else -#define airstar_dvbt_attach NULL -#endif - -/* AirStar ATSC 1st generation */ -#if FE_SUPPORTED(BCM3510) -static int flexcop_fe_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char* name) -{ - struct flexcop_device *fc = fe->dvb->priv; - return request_firmware(fw, name, fc->dev); -} - -static struct bcm3510_config air2pc_atsc_first_gen_config = { - .demod_address = 0x0f, - .request_firmware = flexcop_fe_request_firmware, -}; - -static int airstar_atsc1_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); - return fc->fe != NULL; -} -#else -#define airstar_atsc1_attach NULL -#endif - -/* AirStar ATSC 2nd generation */ -#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL) -static struct nxt200x_config samsung_tbmv_config = { - .demod_address = 0x0a, -}; - -static int airstar_atsc2_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); - if (!fc->fe) - return 0; - - return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, - DVB_PLL_SAMSUNG_TBMV); -} -#else -#define airstar_atsc2_attach NULL -#endif - -/* AirStar ATSC 3rd generation */ -#if FE_SUPPORTED(LGDT330X) -static struct lgdt330x_config air2pc_atsc_hd5000_config = { - .demod_address = 0x59, - .demod_chip = LGDT3303, - .serial_mpeg = 0x04, - .clock_polarity_flip = 1, -}; - -static int airstar_atsc3_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); - if (!fc->fe) - return 0; - - return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, - TUNER_LG_TDVS_H06XF); -} -#else -#define airstar_atsc3_attach NULL -#endif - -/* CableStar2 DVB-C */ -#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL) -static u8 alps_tdee4_stv0297_inittab[] = { - 0x80, 0x01, - 0x80, 0x00, - 0x81, 0x01, - 0x81, 0x00, - 0x00, 0x48, - 0x01, 0x58, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x30, 0xff, - 0x31, 0x9d, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x29, - 0x35, 0x55, - 0x36, 0x80, - 0x37, 0x6e, - 0x38, 0x9c, - 0x40, 0x1a, - 0x41, 0xfe, - 0x42, 0x33, - 0x43, 0x00, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0x51, - 0x4b, 0xf8, - 0x52, 0x30, - 0x53, 0x06, - 0x59, 0x06, - 0x5a, 0x5e, - 0x5b, 0x04, - 0x61, 0x49, - 0x62, 0x0a, - 0x70, 0xff, - 0x71, 0x04, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x20, - 0x81, 0x00, - 0x82, 0x30, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x22, - 0x86, 0x08, - 0x87, 0x1b, - 0x88, 0x00, - 0x89, 0x00, - 0x90, 0x00, - 0x91, 0x04, - 0xa0, 0x86, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x5b, - 0xc1, 0x10, - 0xc2, 0x12, - 0xd0, 0x02, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x02, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x01, - 0xff, 0xff, -}; - -static struct stv0297_config alps_tdee4_stv0297_config = { - .demod_address = 0x1c, - .inittab = alps_tdee4_stv0297_inittab, -}; - -static int cablestar2_attach(struct flexcop_device *fc, - struct i2c_adapter *i2c) -{ - fc->fc_i2c_adap[0].no_base_addr = 1; - fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); - if (!fc->fe) - goto fail; - - /* This tuner doesn't use the stv0297's I2C gate, but instead the - * tuner is connected to a different flexcop I2C adapter. */ - if (fc->fe->ops.i2c_gate_ctrl) - fc->fe->ops.i2c_gate_ctrl(fc->fe, 0); - fc->fe->ops.i2c_gate_ctrl = NULL; - - if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, - &fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4)) - goto fail; - - return 1; - -fail: - /* Reset for next frontend to try */ - fc->fc_i2c_adap[0].no_base_addr = 0; - return 0; -} -#else -#define cablestar2_attach NULL -#endif - -static struct { - flexcop_device_type_t type; - int (*attach)(struct flexcop_device *, struct i2c_adapter *); -} flexcop_frontends[] = { - { FC_SKY_REV27, skystar2_rev27_attach }, - { FC_SKY_REV28, skystar2_rev28_attach }, - { FC_SKY_REV26, skystar2_rev26_attach }, - { FC_AIR_DVBT, airstar_dvbt_attach }, - { FC_AIR_ATSC2, airstar_atsc2_attach }, - { FC_AIR_ATSC3, airstar_atsc3_attach }, - { FC_AIR_ATSC1, airstar_atsc1_attach }, - { FC_CABLE, cablestar2_attach }, - { FC_SKY_REV23, skystar2_rev23_attach }, -}; - -/* try to figure out the frontend */ -int flexcop_frontend_init(struct flexcop_device *fc) -{ - int i; - for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) { - if (!flexcop_frontends[i].attach) - continue; - /* type needs to be set before, because of some workarounds - * done based on the probed card type */ - fc->dev_type = flexcop_frontends[i].type; - if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap)) - goto fe_found; - /* Clean up partially attached frontend */ - if (fc->fe) { - dvb_frontend_detach(fc->fe); - fc->fe = NULL; - } - } - fc->dev_type = FC_UNK; - err("no frontend driver found for this B2C2/FlexCop adapter"); - return -ENODEV; - -fe_found: - info("found '%s' .", fc->fe->ops.info.name); - if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { - err("frontend registration failed!"); - dvb_frontend_detach(fc->fe); - fc->fe = NULL; - return -EINVAL; - } - fc->init_state |= FC_STATE_FE_INIT; - return 0; -} - -void flexcop_frontend_exit(struct flexcop_device *fc) -{ - if (fc->init_state & FC_STATE_FE_INIT) { - dvb_unregister_frontend(fc->fe); - dvb_frontend_detach(fc->fe); - } - fc->init_state &= ~FC_STATE_FE_INIT; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop.h - private header file for all flexcop-chip-source files - * see flexcop.c for copyright information - */ -#ifndef __FLEXCOP_H__ -#define __FLEXCOP_H___ - -#define FC_LOG_PREFIX "b2c2-flexcop" -#include "flexcop-common.h" - -extern int b2c2_flexcop_debug; - -/* debug */ -#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0) -#else -#define dprintk(level,args...) -#endif - -#define deb_info(args...) dprintk(0x01, args) -#define deb_tuner(args...) dprintk(0x02, args) -#define deb_i2c(args...) dprintk(0x04, args) -#define deb_ts(args...) dprintk(0x08, args) -#define deb_sram(args...) dprintk(0x10, args) -#define deb_rdump(args...) dprintk(0x20, args) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,232 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-hw-filter.c - pid and mac address filtering and control functions - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff); - deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off"); -} - -void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff); -} - -static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff); -} - -void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]) -{ - flexcop_ibi_value v418, v41c; - v41c = fc->read_ibi_reg(fc, mac_address_41c); - - v418.mac_address_418.MAC1 = mac[0]; - v418.mac_address_418.MAC2 = mac[1]; - v418.mac_address_418.MAC3 = mac[2]; - v418.mac_address_418.MAC6 = mac[3]; - v41c.mac_address_41c.MAC7 = mac[4]; - v41c.mac_address_41c.MAC8 = mac[5]; - - fc->write_ibi_reg(fc, mac_address_418, v418); - fc->write_ibi_reg(fc, mac_address_41c, v41c); -} - -void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff); -} - -static void flexcop_pid_group_filter(struct flexcop_device *fc, - u16 pid, u16 mask) -{ - /* index_reg_310.extra_index_reg need to 0 or 7 to work */ - flexcop_ibi_value v30c; - v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid; - v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask; - fc->write_ibi_reg(fc, pid_filter_30c, v30c); -} - -static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff) -{ - flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff); -} - -/* this fancy define reduces the code size of the quite similar PID controlling of - * the first 6 PIDs - */ - -#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \ - flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \ -v208 = fc->read_ibi_reg(fc, ctrl_208); \ -vpid.vregname.field = onoff ? pid : 0x1fff; \ -vpid.vregname.trans_field = transval; \ -v208.ctrl_208.enablefield = onoff; \ -fc->write_ibi_reg(fc, vregname, vpid); \ -fc->write_ibi_reg(fc, ctrl_208, v208); - -static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig, - Stream1_trans, 0); -} - -static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig, - Stream2_trans, 0); -} - -static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0); -} - -static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0); -} - -static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0); -} - -static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, - u16 pid, int onoff) -{ - pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0); -} - -static void flexcop_pid_control(struct flexcop_device *fc, - int index, u16 pid, int onoff) -{ - if (pid == 0x2000) - return; - - deb_ts("setting pid: %5d %04x at index %d '%s'\n", - pid, pid, index, onoff ? "on" : "off"); - - /* We could use bit magic here to reduce source code size. - * I decided against it, but to use the real register names */ - switch (index) { - case 0: - flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff); - break; - case 1: - flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff); - break; - case 2: - flexcop_pid_PCR_PID_ctrl(fc, pid, onoff); - break; - case 3: - flexcop_pid_PMT_PID_ctrl(fc, pid, onoff); - break; - case 4: - flexcop_pid_EMM_PID_ctrl(fc, pid, onoff); - break; - case 5: - flexcop_pid_ECM_PID_ctrl(fc, pid, onoff); - break; - default: - if (fc->has_32_hw_pid_filter && index < 38) { - flexcop_ibi_value vpid, vid; - - /* set the index */ - vid = fc->read_ibi_reg(fc, index_reg_310); - vid.index_reg_310.index_reg = index - 6; - fc->write_ibi_reg(fc, index_reg_310, vid); - - vpid = fc->read_ibi_reg(fc, pid_n_reg_314); - vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff; - vpid.pid_n_reg_314.PID_enable_bit = onoff; - fc->write_ibi_reg(fc, pid_n_reg_314, vpid); - } - break; - } -} - -static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff) -{ - if (fc->fullts_streaming_state != onoff) { - deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling"); - flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff)); - flexcop_pid_group_filter_ctrl(fc, onoff); - fc->fullts_streaming_state = onoff; - } - return 0; -} - -int flexcop_pid_feed_control(struct flexcop_device *fc, - struct dvb_demux_feed *dvbdmxfeed, int onoff) -{ - int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; - - fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */ - if (dvbdmxfeed->index >= max_pid_filter) - fc->extra_feedcount += onoff ? 1 : -1; - - /* toggle complete-TS-streaming when: - * - pid_filtering is not enabled and it is the first or last feed requested - * - pid_filtering is enabled, - * - but the number of requested feeds is exceeded - * - or the requested pid is 0x2000 */ - - if (!fc->pid_filtering && fc->feedcount == onoff) - flexcop_toggle_fullts_streaming(fc, onoff); - - if (fc->pid_filtering) { - flexcop_pid_control \ - (fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); - - if (fc->extra_feedcount > 0) - flexcop_toggle_fullts_streaming(fc, 1); - else if (dvbdmxfeed->pid == 0x2000) - flexcop_toggle_fullts_streaming(fc, onoff); - else - flexcop_toggle_fullts_streaming(fc, 0); - } - - /* if it was the first or last feed request change the stream-status */ - if (fc->feedcount == onoff) { - flexcop_rcv_data_ctrl(fc, onoff); - if (fc->stream_control) /* device specific stream control */ - fc->stream_control(fc, onoff); - - /* feeding stopped -> reset the flexcop filter*/ - if (onoff == 0) { - flexcop_reset_block_300(fc); - flexcop_hw_filter_init(fc); - } - } - return 0; -} -EXPORT_SYMBOL(flexcop_pid_feed_control); - -void flexcop_hw_filter_init(struct flexcop_device *fc) -{ - int i; - flexcop_ibi_value v; - for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++) - flexcop_pid_control(fc, i, 0x1fff, 0); - - flexcop_pid_group_filter(fc, 0, 0x1fe0); - flexcop_pid_group_filter_ctrl(fc, 0); - - v = fc->read_ibi_reg(fc, pid_filter_308); - v.pid_filter_308.EMM_filter_4 = 1; - v.pid_filter_308.EMM_filter_6 = 0; - fc->write_ibi_reg(fc, pid_filter_308, v); - - flexcop_null_filter_ctrl(fc, 1); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-i2c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,288 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -#define FC_MAX_I2C_RETRIES 100000 - -static int flexcop_i2c_operation(struct flexcop_device *fc, - flexcop_ibi_value *r100) -{ - int i; - flexcop_ibi_value r; - - r100->tw_sm_c_100.working_start = 1; - deb_i2c("r100 before: %08x\n",r100->raw); - - fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); - fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */ - - for (i = 0; i < FC_MAX_I2C_RETRIES; i++) { - r = fc->read_ibi_reg(fc, tw_sm_c_100); - - if (!r.tw_sm_c_100.no_base_addr_ack_error) { - if (r.tw_sm_c_100.st_done) { - *r100 = r; - deb_i2c("i2c success\n"); - return 0; - } - } else { - deb_i2c("suffering from an i2c ack_error\n"); - return -EREMOTEIO; - } - } - deb_i2c("tried %d times i2c operation, " - "never finished or too many ack errors.\n", i); - return -EREMOTEIO; -} - -static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c, - flexcop_ibi_value r100, u8 *buf) -{ - flexcop_ibi_value r104; - int len = r100.tw_sm_c_100.total_bytes, - /* remember total_bytes is buflen-1 */ - ret; - - /* work-around to have CableStar2 and SkyStar2 rev 2.7 work - * correctly: - * - * the ITD1000 is behind an i2c-gate which closes automatically - * after an i2c-transaction the STV0297 needs 2 consecutive reads - * one with no_base_addr = 0 and one with 1 - * - * those two work-arounds are conflictin: we check for the card - * type, it is set when probing the ITD1000 */ - if (i2c->fc->dev_type == FC_SKY_REV27) - r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; - - ret = flexcop_i2c_operation(i2c->fc, &r100); - if (ret != 0) { - deb_i2c("Retrying operation\n"); - r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; - ret = flexcop_i2c_operation(i2c->fc, &r100); - } - if (ret != 0) { - deb_i2c("read failed. %d\n", ret); - return ret; - } - - buf[0] = r100.tw_sm_c_100.data1_reg; - - if (len > 0) { - r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104); - deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw); - - /* there is at least one more byte, otherwise we wouldn't be here */ - buf[1] = r104.tw_sm_c_104.data2_reg; - if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; - if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; - } - return 0; -} - -static int flexcop_i2c_write4(struct flexcop_device *fc, - flexcop_ibi_value r100, u8 *buf) -{ - flexcop_ibi_value r104; - int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */ - r104.raw = 0; - - /* there is at least one byte, otherwise we wouldn't be here */ - r100.tw_sm_c_100.data1_reg = buf[0]; - r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0; - r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; - r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; - - deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw); - - /* write the additional i2c data before doing the actual i2c operation */ - fc->write_ibi_reg(fc, tw_sm_c_104, r104); - return flexcop_i2c_operation(fc, &r100); -} - -int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, - flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) -{ - int ret; - -#ifdef DUMP_I2C_MESSAGES - int i; -#endif - - u16 bytes_to_transfer; - flexcop_ibi_value r100; - - deb_i2c("op = %d\n",op); - r100.raw = 0; - r100.tw_sm_c_100.chipaddr = chipaddr; - r100.tw_sm_c_100.twoWS_rw = op; - r100.tw_sm_c_100.twoWS_port_reg = i2c->port; - -#ifdef DUMP_I2C_MESSAGES - printk(KERN_DEBUG "%d ", i2c->port); - if (op == FC_READ) - printk("rd("); - else - printk("wr("); - printk("%02x): %02x ", chipaddr, addr); -#endif - - /* in that case addr is the only value -> - * we write it twice as baseaddr and val0 - * BBTI is doing it like that for ISL6421 at least */ - if (i2c->no_base_addr && len == 0 && op == FC_WRITE) { - buf = &addr; - len = 1; - } - - while (len != 0) { - bytes_to_transfer = len > 4 ? 4 : len; - - r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; - r100.tw_sm_c_100.baseaddr = addr; - - if (op == FC_READ) - ret = flexcop_i2c_read4(i2c, r100, buf); - else - ret = flexcop_i2c_write4(i2c->fc, r100, buf); - -#ifdef DUMP_I2C_MESSAGES - for (i = 0; i < bytes_to_transfer; i++) - printk("%02x ", buf[i]); -#endif - - if (ret < 0) - return ret; - - buf += bytes_to_transfer; - addr += bytes_to_transfer; - len -= bytes_to_transfer; - } - -#ifdef DUMP_I2C_MESSAGES - printk("\n"); -#endif - - return 0; -} -/* exported for PCI i2c */ -EXPORT_SYMBOL(flexcop_i2c_request); - -/* master xfer callback for demodulator */ -static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) -{ - struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap); - int i, ret = 0; - - /* Some drivers use 1 byte or 0 byte reads as probes, which this - * driver doesn't support. These probes will always fail, so this - * hack makes them always succeed. If one knew how, it would of - * course be better to actually do the read. */ - if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1) - return 1; - - if (mutex_lock_interruptible(&i2c->fc->i2c_mutex)) - return -ERESTARTSYS; - - for (i = 0; i < num; i++) { - /* reading */ - if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) { - ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr, - msgs[i].buf[0], msgs[i+1].buf, - msgs[i+1].len); - i++; /* skip the following message */ - } else /* writing */ - ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr, - msgs[i].buf[0], &msgs[i].buf[1], - msgs[i].len - 1); - if (ret < 0) { - deb_i2c("i2c master_xfer failed"); - break; - } - } - - mutex_unlock(&i2c->fc->i2c_mutex); - - if (ret == 0) - ret = num; - return ret; -} - -static u32 flexcop_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm flexcop_algo = { - .master_xfer = flexcop_master_xfer, - .functionality = flexcop_i2c_func, -}; - -int flexcop_i2c_init(struct flexcop_device *fc) -{ - int ret; - mutex_init(&fc->i2c_mutex); - - fc->fc_i2c_adap[0].fc = fc; - fc->fc_i2c_adap[1].fc = fc; - fc->fc_i2c_adap[2].fc = fc; - fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD; - fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM; - fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER; - - strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod", - sizeof(fc->fc_i2c_adap[0].i2c_adap.name)); - strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom", - sizeof(fc->fc_i2c_adap[1].i2c_adap.name)); - strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner", - sizeof(fc->fc_i2c_adap[2].i2c_adap.name)); - - i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]); - i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]); - i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]); - - fc->fc_i2c_adap[0].i2c_adap.algo = - fc->fc_i2c_adap[1].i2c_adap.algo = - fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo; - fc->fc_i2c_adap[0].i2c_adap.algo_data = - fc->fc_i2c_adap[1].i2c_adap.algo_data = - fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL; - fc->fc_i2c_adap[0].i2c_adap.dev.parent = - fc->fc_i2c_adap[1].i2c_adap.dev.parent = - fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev; - - ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap); - if (ret < 0) - return ret; - - ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap); - if (ret < 0) - goto adap_1_failed; - - ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap); - if (ret < 0) - goto adap_2_failed; - - fc->init_state |= FC_STATE_I2C_INIT; - return 0; - -adap_2_failed: - i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); -adap_1_failed: - i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); - return ret; -} - -void flexcop_i2c_exit(struct flexcop_device *fc) -{ - if (fc->init_state & FC_STATE_I2C_INIT) { - i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap); - i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); - i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); - } - fc->init_state &= ~FC_STATE_I2C_INIT; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,455 +0,0 @@ -/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * register descriptions - * see flexcop.c for copyright information - */ -/* This file is automatically generated, do not edit things here. */ -#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ -#define __FLEXCOP_IBI_VALUE_INCLUDED__ - -typedef union { - u32 raw; - - struct { - u32 dma_address0 :30; - u32 dma_0No_update : 1; - u32 dma_0start : 1; - } dma_0x0; - - struct { - u32 dma_addr_size :24; - u32 DMA_maxpackets : 8; - } dma_0x4_remap; - - struct { - u32 dma_addr_size :24; - u32 unused : 1; - u32 dma1timer : 7; - } dma_0x4_read; - - struct { - u32 dma_addr_size :24; - u32 dmatimer : 7; - u32 unused : 1; - } dma_0x4_write; - - struct { - u32 dma_cur_addr :30; - u32 unused : 2; - } dma_0x8; - - struct { - u32 dma_address1 :30; - u32 remap_enable : 1; - u32 dma_1start : 1; - } dma_0xc; - - struct { - u32 st_done : 1; - u32 no_base_addr_ack_error : 1; - u32 twoWS_port_reg : 2; - u32 total_bytes : 2; - u32 twoWS_rw : 1; - u32 working_start : 1; - u32 data1_reg : 8; - u32 baseaddr : 8; - u32 reserved1 : 1; - u32 chipaddr : 7; - } tw_sm_c_100; - - struct { - u32 unused : 6; - u32 force_stop : 1; - u32 exlicit_stops : 1; - u32 data4_reg : 8; - u32 data3_reg : 8; - u32 data2_reg : 8; - } tw_sm_c_104; - - struct { - u32 reserved2 :19; - u32 tlo1 : 5; - u32 reserved1 : 2; - u32 thi1 : 6; - } tw_sm_c_108; - - struct { - u32 reserved2 :19; - u32 tlo1 : 5; - u32 reserved1 : 2; - u32 thi1 : 6; - } tw_sm_c_10c; - - struct { - u32 reserved2 :19; - u32 tlo1 : 5; - u32 reserved1 : 2; - u32 thi1 : 6; - } tw_sm_c_110; - - struct { - u32 LNB_CTLPrescaler_sig : 2; - u32 LNB_CTLLowCount_sig :15; - u32 LNB_CTLHighCount_sig :15; - } lnb_switch_freq_200; - - struct { - u32 Rev_N_sig_reserved2 : 1; - u32 Rev_N_sig_caps : 1; - u32 Rev_N_sig_reserved1 : 2; - u32 Rev_N_sig_revision_hi : 4; - u32 reserved :20; - u32 Per_reset_sig : 1; - u32 LNB_L_H_sig : 1; - u32 ACPI3_sig : 1; - u32 ACPI1_sig : 1; - } misc_204; - - struct { - u32 unused : 9; - u32 Mailbox_from_V8_Enable_sig : 1; - u32 DMA2_Size_IRQ_Enable_sig : 1; - u32 DMA1_Size_IRQ_Enable_sig : 1; - u32 DMA2_Timer_Enable_sig : 1; - u32 DMA2_IRQ_Enable_sig : 1; - u32 DMA1_Timer_Enable_sig : 1; - u32 DMA1_IRQ_Enable_sig : 1; - u32 Rcv_Data_sig : 1; - u32 MAC_filter_Mode_sig : 1; - u32 Multi2_Enable_sig : 1; - u32 Per_CA_Enable_sig : 1; - u32 SMC_Enable_sig : 1; - u32 CA_Enable_sig : 1; - u32 WAN_CA_Enable_sig : 1; - u32 WAN_Enable_sig : 1; - u32 Mask_filter_sig : 1; - u32 Null_filter_sig : 1; - u32 ECM_filter_sig : 1; - u32 EMM_filter_sig : 1; - u32 PMT_filter_sig : 1; - u32 PCR_filter_sig : 1; - u32 Stream2_filter_sig : 1; - u32 Stream1_filter_sig : 1; - } ctrl_208; - - struct { - u32 reserved :21; - u32 Transport_Error : 1; - u32 LLC_SNAP_FLAG_set : 1; - u32 Continuity_error_flag : 1; - u32 Data_receiver_error : 1; - u32 Mailbox_from_V8_Status_sig : 1; - u32 DMA2_Size_IRQ_Status : 1; - u32 DMA1_Size_IRQ_Status : 1; - u32 DMA2_Timer_Status : 1; - u32 DMA2_IRQ_Status : 1; - u32 DMA1_Timer_Status : 1; - u32 DMA1_IRQ_Status : 1; - } irq_20c; - - struct { - u32 Special_controls :16; - u32 Block_reset_enable : 8; - u32 reset_block_700 : 1; - u32 reset_block_600 : 1; - u32 reset_block_500 : 1; - u32 reset_block_400 : 1; - u32 reset_block_300 : 1; - u32 reset_block_200 : 1; - u32 reset_block_100 : 1; - u32 reset_block_000 : 1; - } sw_reset_210; - - struct { - u32 unused2 :20; - u32 polarity_PS_ERR_sig : 1; - u32 polarity_PS_SYNC_sig : 1; - u32 polarity_PS_VALID_sig : 1; - u32 polarity_PS_CLK_sig : 1; - u32 unused1 : 3; - u32 s2p_sel_sig : 1; - u32 section_pkg_enable_sig : 1; - u32 halt_V8_sig : 1; - u32 v2WS_oe_sig : 1; - u32 vuart_oe_sig : 1; - } misc_214; - - struct { - u32 Mailbox_from_V8 :32; - } mbox_v8_to_host_218; - - struct { - u32 sysramaccess_busmuster : 1; - u32 sysramaccess_write : 1; - u32 unused : 7; - u32 sysramaccess_addr :15; - u32 sysramaccess_data : 8; - } mbox_host_to_v8_21c; - - struct { - u32 debug_fifo_problem : 1; - u32 debug_flag_write_status00 : 1; - u32 Stream2_trans : 1; - u32 Stream2_PID :13; - u32 debug_flag_pid_saved : 1; - u32 MAC_Multicast_filter : 1; - u32 Stream1_trans : 1; - u32 Stream1_PID :13; - } pid_filter_300; - - struct { - u32 reserved : 2; - u32 PMT_trans : 1; - u32 PMT_PID :13; - u32 debug_overrun2 : 1; - u32 debug_overrun3 : 1; - u32 PCR_trans : 1; - u32 PCR_PID :13; - } pid_filter_304; - - struct { - u32 reserved : 2; - u32 ECM_trans : 1; - u32 ECM_PID :13; - u32 EMM_filter_6 : 1; - u32 EMM_filter_4 : 1; - u32 EMM_trans : 1; - u32 EMM_PID :13; - } pid_filter_308; - - struct { - u32 unused2 : 3; - u32 Group_mask :13; - u32 unused1 : 2; - u32 Group_trans : 1; - u32 Group_PID :13; - } pid_filter_30c_ext_ind_0_7; - - struct { - u32 unused :15; - u32 net_master_read :17; - } pid_filter_30c_ext_ind_1; - - struct { - u32 unused :15; - u32 net_master_write :17; - } pid_filter_30c_ext_ind_2; - - struct { - u32 unused :15; - u32 next_net_master_write :17; - } pid_filter_30c_ext_ind_3; - - struct { - u32 reserved2 : 5; - u32 stack_read :10; - u32 reserved1 : 6; - u32 state_write :10; - u32 unused1 : 1; - } pid_filter_30c_ext_ind_4; - - struct { - u32 unused :22; - u32 stack_cnt :10; - } pid_filter_30c_ext_ind_5; - - struct { - u32 unused : 4; - u32 data_size_reg :12; - u32 write_status4 : 2; - u32 write_status1 : 2; - u32 pid_fsm_save_reg300 : 2; - u32 pid_fsm_save_reg4 : 2; - u32 pid_fsm_save_reg3 : 2; - u32 pid_fsm_save_reg2 : 2; - u32 pid_fsm_save_reg1 : 2; - u32 pid_fsm_save_reg0 : 2; - } pid_filter_30c_ext_ind_6; - - struct { - u32 unused :22; - u32 pass_alltables : 1; - u32 AB_select : 1; - u32 extra_index_reg : 3; - u32 index_reg : 5; - } index_reg_310; - - struct { - u32 reserved :17; - u32 PID_enable_bit : 1; - u32 PID_trans : 1; - u32 PID :13; - } pid_n_reg_314; - - struct { - u32 reserved : 6; - u32 HighAB_bit : 1; - u32 Enable_bit : 1; - u32 A6_byte : 8; - u32 A5_byte : 8; - u32 A4_byte : 8; - } mac_low_reg_318; - - struct { - u32 reserved : 8; - u32 A3_byte : 8; - u32 A2_byte : 8; - u32 A1_byte : 8; - } mac_high_reg_31c; - - struct { - u32 data_Tag_ID :16; - u32 reserved :16; - } data_tag_400; - - struct { - u32 Card_IDbyte3 : 8; - u32 Card_IDbyte4 : 8; - u32 Card_IDbyte5 : 8; - u32 Card_IDbyte6 : 8; - } card_id_408; - - struct { - u32 Card_IDbyte1 : 8; - u32 Card_IDbyte2 : 8; - } card_id_40c; - - struct { - u32 MAC6 : 8; - u32 MAC3 : 8; - u32 MAC2 : 8; - u32 MAC1 : 8; - } mac_address_418; - - struct { - u32 reserved :16; - u32 MAC8 : 8; - u32 MAC7 : 8; - } mac_address_41c; - - struct { - u32 reserved :21; - u32 txbuffempty : 1; - u32 ReceiveByteFrameError : 1; - u32 ReceiveDataReady : 1; - u32 transmitter_data_byte : 8; - } ci_600; - - struct { - u32 pi_component_reg : 3; - u32 pi_rw : 1; - u32 pi_ha :20; - u32 pi_d : 8; - } pi_604; - - struct { - u32 pi_busy_n : 1; - u32 pi_wait_n : 1; - u32 pi_timeout_status : 1; - u32 pi_CiMax_IRQ_n : 1; - u32 config_cclk : 1; - u32 config_cs_n : 1; - u32 config_wr_n : 1; - u32 config_Prog_n : 1; - u32 config_Init_stat : 1; - u32 config_Done_stat : 1; - u32 pcmcia_b_mod_pwr_n : 1; - u32 pcmcia_a_mod_pwr_n : 1; - u32 reserved : 3; - u32 Timer_addr : 5; - u32 unused : 1; - u32 timer_data : 7; - u32 Timer_Load_req : 1; - u32 Timer_Read_req : 1; - u32 oncecycle_read : 1; - u32 serialReset : 1; - } pi_608; - - struct { - u32 reserved : 6; - u32 rw_flag : 1; - u32 dvb_en : 1; - u32 key_array_row : 5; - u32 key_array_col : 3; - u32 key_code : 2; - u32 key_enable : 1; - u32 PID :13; - } dvb_reg_60c; - - struct { - u32 start_sram_ibi : 1; - u32 reserved2 : 1; - u32 ce_pin_reg : 1; - u32 oe_pin_reg : 1; - u32 reserved1 : 3; - u32 sc_xfer_bit : 1; - u32 sram_data : 8; - u32 sram_rw : 1; - u32 sram_addr :15; - } sram_ctrl_reg_700; - - struct { - u32 net_addr_write :16; - u32 net_addr_read :16; - } net_buf_reg_704; - - struct { - u32 cai_cnt : 4; - u32 reserved2 : 6; - u32 cai_write :11; - u32 reserved1 : 5; - u32 cai_read :11; - } cai_buf_reg_708; - - struct { - u32 cao_cnt : 4; - u32 reserved2 : 6; - u32 cap_write :11; - u32 reserved1 : 5; - u32 cao_read :11; - } cao_buf_reg_70c; - - struct { - u32 media_cnt : 4; - u32 reserved2 : 6; - u32 media_write :11; - u32 reserved1 : 5; - u32 media_read :11; - } media_buf_reg_710; - - struct { - u32 reserved :17; - u32 ctrl_maximumfill : 1; - u32 ctrl_sramdma : 1; - u32 ctrl_usb_wan : 1; - u32 cao_ovflow_error : 1; - u32 cai_ovflow_error : 1; - u32 media_ovflow_error : 1; - u32 net_ovflow_error : 1; - u32 MEDIA_Dest : 2; - u32 CAO_Dest : 2; - u32 CAI_Dest : 2; - u32 NET_Dest : 2; - } sram_dest_reg_714; - - struct { - u32 reserved3 :11; - u32 net_addr_write : 1; - u32 reserved2 : 3; - u32 net_addr_read : 1; - u32 reserved1 : 4; - u32 net_cnt :12; - } net_buf_reg_718; - - struct { - u32 reserved3 : 4; - u32 wan_pkt_frame : 4; - u32 reserved2 : 4; - u32 sram_memmap : 2; - u32 sram_chip : 2; - u32 wan_wait_state : 8; - u32 reserved1 : 6; - u32 wan_speed_sig : 2; - } wan_ctrl_reg_71c; -} flexcop_ibi_value; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,455 +0,0 @@ -/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * register descriptions - * see flexcop.c for copyright information - */ -/* This file is automatically generated, do not edit things here. */ -#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ -#define __FLEXCOP_IBI_VALUE_INCLUDED__ - -typedef union { - u32 raw; - - struct { - u32 dma_0start : 1; - u32 dma_0No_update : 1; - u32 dma_address0 :30; - } dma_0x0; - - struct { - u32 DMA_maxpackets : 8; - u32 dma_addr_size :24; - } dma_0x4_remap; - - struct { - u32 dma1timer : 7; - u32 unused : 1; - u32 dma_addr_size :24; - } dma_0x4_read; - - struct { - u32 unused : 1; - u32 dmatimer : 7; - u32 dma_addr_size :24; - } dma_0x4_write; - - struct { - u32 unused : 2; - u32 dma_cur_addr :30; - } dma_0x8; - - struct { - u32 dma_1start : 1; - u32 remap_enable : 1; - u32 dma_address1 :30; - } dma_0xc; - - struct { - u32 chipaddr : 7; - u32 reserved1 : 1; - u32 baseaddr : 8; - u32 data1_reg : 8; - u32 working_start : 1; - u32 twoWS_rw : 1; - u32 total_bytes : 2; - u32 twoWS_port_reg : 2; - u32 no_base_addr_ack_error : 1; - u32 st_done : 1; - } tw_sm_c_100; - - struct { - u32 data2_reg : 8; - u32 data3_reg : 8; - u32 data4_reg : 8; - u32 exlicit_stops : 1; - u32 force_stop : 1; - u32 unused : 6; - } tw_sm_c_104; - - struct { - u32 thi1 : 6; - u32 reserved1 : 2; - u32 tlo1 : 5; - u32 reserved2 :19; - } tw_sm_c_108; - - struct { - u32 thi1 : 6; - u32 reserved1 : 2; - u32 tlo1 : 5; - u32 reserved2 :19; - } tw_sm_c_10c; - - struct { - u32 thi1 : 6; - u32 reserved1 : 2; - u32 tlo1 : 5; - u32 reserved2 :19; - } tw_sm_c_110; - - struct { - u32 LNB_CTLHighCount_sig :15; - u32 LNB_CTLLowCount_sig :15; - u32 LNB_CTLPrescaler_sig : 2; - } lnb_switch_freq_200; - - struct { - u32 ACPI1_sig : 1; - u32 ACPI3_sig : 1; - u32 LNB_L_H_sig : 1; - u32 Per_reset_sig : 1; - u32 reserved :20; - u32 Rev_N_sig_revision_hi : 4; - u32 Rev_N_sig_reserved1 : 2; - u32 Rev_N_sig_caps : 1; - u32 Rev_N_sig_reserved2 : 1; - } misc_204; - - struct { - u32 Stream1_filter_sig : 1; - u32 Stream2_filter_sig : 1; - u32 PCR_filter_sig : 1; - u32 PMT_filter_sig : 1; - u32 EMM_filter_sig : 1; - u32 ECM_filter_sig : 1; - u32 Null_filter_sig : 1; - u32 Mask_filter_sig : 1; - u32 WAN_Enable_sig : 1; - u32 WAN_CA_Enable_sig : 1; - u32 CA_Enable_sig : 1; - u32 SMC_Enable_sig : 1; - u32 Per_CA_Enable_sig : 1; - u32 Multi2_Enable_sig : 1; - u32 MAC_filter_Mode_sig : 1; - u32 Rcv_Data_sig : 1; - u32 DMA1_IRQ_Enable_sig : 1; - u32 DMA1_Timer_Enable_sig : 1; - u32 DMA2_IRQ_Enable_sig : 1; - u32 DMA2_Timer_Enable_sig : 1; - u32 DMA1_Size_IRQ_Enable_sig : 1; - u32 DMA2_Size_IRQ_Enable_sig : 1; - u32 Mailbox_from_V8_Enable_sig : 1; - u32 unused : 9; - } ctrl_208; - - struct { - u32 DMA1_IRQ_Status : 1; - u32 DMA1_Timer_Status : 1; - u32 DMA2_IRQ_Status : 1; - u32 DMA2_Timer_Status : 1; - u32 DMA1_Size_IRQ_Status : 1; - u32 DMA2_Size_IRQ_Status : 1; - u32 Mailbox_from_V8_Status_sig : 1; - u32 Data_receiver_error : 1; - u32 Continuity_error_flag : 1; - u32 LLC_SNAP_FLAG_set : 1; - u32 Transport_Error : 1; - u32 reserved :21; - } irq_20c; - - struct { - u32 reset_block_000 : 1; - u32 reset_block_100 : 1; - u32 reset_block_200 : 1; - u32 reset_block_300 : 1; - u32 reset_block_400 : 1; - u32 reset_block_500 : 1; - u32 reset_block_600 : 1; - u32 reset_block_700 : 1; - u32 Block_reset_enable : 8; - u32 Special_controls :16; - } sw_reset_210; - - struct { - u32 vuart_oe_sig : 1; - u32 v2WS_oe_sig : 1; - u32 halt_V8_sig : 1; - u32 section_pkg_enable_sig : 1; - u32 s2p_sel_sig : 1; - u32 unused1 : 3; - u32 polarity_PS_CLK_sig : 1; - u32 polarity_PS_VALID_sig : 1; - u32 polarity_PS_SYNC_sig : 1; - u32 polarity_PS_ERR_sig : 1; - u32 unused2 :20; - } misc_214; - - struct { - u32 Mailbox_from_V8 :32; - } mbox_v8_to_host_218; - - struct { - u32 sysramaccess_data : 8; - u32 sysramaccess_addr :15; - u32 unused : 7; - u32 sysramaccess_write : 1; - u32 sysramaccess_busmuster : 1; - } mbox_host_to_v8_21c; - - struct { - u32 Stream1_PID :13; - u32 Stream1_trans : 1; - u32 MAC_Multicast_filter : 1; - u32 debug_flag_pid_saved : 1; - u32 Stream2_PID :13; - u32 Stream2_trans : 1; - u32 debug_flag_write_status00 : 1; - u32 debug_fifo_problem : 1; - } pid_filter_300; - - struct { - u32 PCR_PID :13; - u32 PCR_trans : 1; - u32 debug_overrun3 : 1; - u32 debug_overrun2 : 1; - u32 PMT_PID :13; - u32 PMT_trans : 1; - u32 reserved : 2; - } pid_filter_304; - - struct { - u32 EMM_PID :13; - u32 EMM_trans : 1; - u32 EMM_filter_4 : 1; - u32 EMM_filter_6 : 1; - u32 ECM_PID :13; - u32 ECM_trans : 1; - u32 reserved : 2; - } pid_filter_308; - - struct { - u32 Group_PID :13; - u32 Group_trans : 1; - u32 unused1 : 2; - u32 Group_mask :13; - u32 unused2 : 3; - } pid_filter_30c_ext_ind_0_7; - - struct { - u32 net_master_read :17; - u32 unused :15; - } pid_filter_30c_ext_ind_1; - - struct { - u32 net_master_write :17; - u32 unused :15; - } pid_filter_30c_ext_ind_2; - - struct { - u32 next_net_master_write :17; - u32 unused :15; - } pid_filter_30c_ext_ind_3; - - struct { - u32 unused1 : 1; - u32 state_write :10; - u32 reserved1 : 6; - u32 stack_read :10; - u32 reserved2 : 5; - } pid_filter_30c_ext_ind_4; - - struct { - u32 stack_cnt :10; - u32 unused :22; - } pid_filter_30c_ext_ind_5; - - struct { - u32 pid_fsm_save_reg0 : 2; - u32 pid_fsm_save_reg1 : 2; - u32 pid_fsm_save_reg2 : 2; - u32 pid_fsm_save_reg3 : 2; - u32 pid_fsm_save_reg4 : 2; - u32 pid_fsm_save_reg300 : 2; - u32 write_status1 : 2; - u32 write_status4 : 2; - u32 data_size_reg :12; - u32 unused : 4; - } pid_filter_30c_ext_ind_6; - - struct { - u32 index_reg : 5; - u32 extra_index_reg : 3; - u32 AB_select : 1; - u32 pass_alltables : 1; - u32 unused :22; - } index_reg_310; - - struct { - u32 PID :13; - u32 PID_trans : 1; - u32 PID_enable_bit : 1; - u32 reserved :17; - } pid_n_reg_314; - - struct { - u32 A4_byte : 8; - u32 A5_byte : 8; - u32 A6_byte : 8; - u32 Enable_bit : 1; - u32 HighAB_bit : 1; - u32 reserved : 6; - } mac_low_reg_318; - - struct { - u32 A1_byte : 8; - u32 A2_byte : 8; - u32 A3_byte : 8; - u32 reserved : 8; - } mac_high_reg_31c; - - struct { - u32 reserved :16; - u32 data_Tag_ID :16; - } data_tag_400; - - struct { - u32 Card_IDbyte6 : 8; - u32 Card_IDbyte5 : 8; - u32 Card_IDbyte4 : 8; - u32 Card_IDbyte3 : 8; - } card_id_408; - - struct { - u32 Card_IDbyte2 : 8; - u32 Card_IDbyte1 : 8; - } card_id_40c; - - struct { - u32 MAC1 : 8; - u32 MAC2 : 8; - u32 MAC3 : 8; - u32 MAC6 : 8; - } mac_address_418; - - struct { - u32 MAC7 : 8; - u32 MAC8 : 8; - u32 reserved :16; - } mac_address_41c; - - struct { - u32 transmitter_data_byte : 8; - u32 ReceiveDataReady : 1; - u32 ReceiveByteFrameError : 1; - u32 txbuffempty : 1; - u32 reserved :21; - } ci_600; - - struct { - u32 pi_d : 8; - u32 pi_ha :20; - u32 pi_rw : 1; - u32 pi_component_reg : 3; - } pi_604; - - struct { - u32 serialReset : 1; - u32 oncecycle_read : 1; - u32 Timer_Read_req : 1; - u32 Timer_Load_req : 1; - u32 timer_data : 7; - u32 unused : 1; - u32 Timer_addr : 5; - u32 reserved : 3; - u32 pcmcia_a_mod_pwr_n : 1; - u32 pcmcia_b_mod_pwr_n : 1; - u32 config_Done_stat : 1; - u32 config_Init_stat : 1; - u32 config_Prog_n : 1; - u32 config_wr_n : 1; - u32 config_cs_n : 1; - u32 config_cclk : 1; - u32 pi_CiMax_IRQ_n : 1; - u32 pi_timeout_status : 1; - u32 pi_wait_n : 1; - u32 pi_busy_n : 1; - } pi_608; - - struct { - u32 PID :13; - u32 key_enable : 1; - u32 key_code : 2; - u32 key_array_col : 3; - u32 key_array_row : 5; - u32 dvb_en : 1; - u32 rw_flag : 1; - u32 reserved : 6; - } dvb_reg_60c; - - struct { - u32 sram_addr :15; - u32 sram_rw : 1; - u32 sram_data : 8; - u32 sc_xfer_bit : 1; - u32 reserved1 : 3; - u32 oe_pin_reg : 1; - u32 ce_pin_reg : 1; - u32 reserved2 : 1; - u32 start_sram_ibi : 1; - } sram_ctrl_reg_700; - - struct { - u32 net_addr_read :16; - u32 net_addr_write :16; - } net_buf_reg_704; - - struct { - u32 cai_read :11; - u32 reserved1 : 5; - u32 cai_write :11; - u32 reserved2 : 6; - u32 cai_cnt : 4; - } cai_buf_reg_708; - - struct { - u32 cao_read :11; - u32 reserved1 : 5; - u32 cap_write :11; - u32 reserved2 : 6; - u32 cao_cnt : 4; - } cao_buf_reg_70c; - - struct { - u32 media_read :11; - u32 reserved1 : 5; - u32 media_write :11; - u32 reserved2 : 6; - u32 media_cnt : 4; - } media_buf_reg_710; - - struct { - u32 NET_Dest : 2; - u32 CAI_Dest : 2; - u32 CAO_Dest : 2; - u32 MEDIA_Dest : 2; - u32 net_ovflow_error : 1; - u32 media_ovflow_error : 1; - u32 cai_ovflow_error : 1; - u32 cao_ovflow_error : 1; - u32 ctrl_usb_wan : 1; - u32 ctrl_sramdma : 1; - u32 ctrl_maximumfill : 1; - u32 reserved :17; - } sram_dest_reg_714; - - struct { - u32 net_cnt :12; - u32 reserved1 : 4; - u32 net_addr_read : 1; - u32 reserved2 : 3; - u32 net_addr_write : 1; - u32 reserved3 :11; - } net_buf_reg_718; - - struct { - u32 wan_speed_sig : 2; - u32 reserved1 : 6; - u32 wan_wait_state : 8; - u32 sram_chip : 2; - u32 sram_memmap : 2; - u32 reserved2 : 4; - u32 wan_pkt_frame : 4; - u32 reserved3 : 4; - } wan_ctrl_reg_71c; -} flexcop_ibi_value; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-misc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-misc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-misc.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-misc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-misc.c - miscellaneous functions - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -void flexcop_determine_revision(struct flexcop_device *fc) -{ - flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); - - switch (v.misc_204.Rev_N_sig_revision_hi) { - case 0x2: - deb_info("found a FlexCopII.\n"); - fc->rev = FLEXCOP_II; - break; - case 0x3: - deb_info("found a FlexCopIIb.\n"); - fc->rev = FLEXCOP_IIB; - break; - case 0x0: - deb_info("found a FlexCopIII.\n"); - fc->rev = FLEXCOP_III; - break; - default: - err("unknown FlexCop Revision: %x. Please report this to " - "linux-dvb@linuxtv.org.", - v.misc_204.Rev_N_sig_revision_hi); - break; - } - - if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps)) - deb_info("this FlexCop has " - "the additional 32 hardware pid filter.\n"); - else - deb_info("this FlexCop has " - "the 6 basic main hardware pid filter.\n"); - /* bus parts have to decide if hw pid filtering is used or not. */ -} - -static const char *flexcop_revision_names[] = { - "Unknown chip", - "FlexCopII", - "FlexCopIIb", - "FlexCopIII", -}; - -static const char *flexcop_device_names[] = { - [FC_UNK] = "Unknown device", - [FC_CABLE] = "Cable2PC/CableStar 2 DVB-C", - [FC_AIR_DVBT] = "Air2PC/AirStar 2 DVB-T", - [FC_AIR_ATSC1] = "Air2PC/AirStar 2 ATSC 1st generation", - [FC_AIR_ATSC2] = "Air2PC/AirStar 2 ATSC 2nd generation", - [FC_AIR_ATSC3] = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)", - [FC_SKY_REV23] = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)", - [FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6", - [FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u", - [FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8", -}; - -static const char *flexcop_bus_names[] = { - "USB", - "PCI", -}; - -void flexcop_device_name(struct flexcop_device *fc, - const char *prefix, const char *suffix) -{ - info("%s '%s' at the '%s' bus controlled by a '%s' %s", - prefix, flexcop_device_names[fc->dev_type], - flexcop_bus_names[fc->bus_type], - flexcop_revision_names[fc->rev], suffix); -} - -void flexcop_dump_reg(struct flexcop_device *fc, - flexcop_ibi_register reg, int num) -{ - flexcop_ibi_value v; - int i; - for (i = 0; i < num; i++) { - v = fc->read_ibi_reg(fc, reg+4*i); - deb_rdump("0x%03x: %08x, ", reg+4*i, v.raw); - } - deb_rdump("\n"); -} -EXPORT_SYMBOL(flexcop_dump_reg); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-pci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-pci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-pci.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-pci.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,452 +0,0 @@ -/* - * Linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-pci.c - covers the PCI part including DMA transfers - * see flexcop.c for copyright information - */ - -#define FC_LOG_PREFIX "flexcop-pci" -#include "flexcop-common.h" - -static int enable_pid_filtering = 1; -module_param(enable_pid_filtering, int, 0444); -MODULE_PARM_DESC(enable_pid_filtering, - "enable hardware pid filtering: supported values: 0 (fullts), 1"); - -static int irq_chk_intv = 100; -module_param(irq_chk_intv, int, 0644); -MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog."); - -#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((debug & level)) printk(args); } while (0) -#define DEBSTATUS "" -#else -#define dprintk(level,args...) -#define DEBSTATUS " (debugging is not enabled)" -#endif - -#define deb_info(args...) dprintk(0x01, args) -#define deb_reg(args...) dprintk(0x02, args) -#define deb_ts(args...) dprintk(0x04, args) -#define deb_irq(args...) dprintk(0x08, args) -#define deb_chk(args...) dprintk(0x10, args) - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))." - DEBSTATUS); - -#define DRIVER_VERSION "0.1" -#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" -#define DRIVER_AUTHOR "Patrick Boettcher " - -struct flexcop_pci { - struct pci_dev *pdev; - -#define FC_PCI_INIT 0x01 -#define FC_PCI_DMA_INIT 0x02 - int init_state; - - void __iomem *io_mem; - u32 irq; - /* buffersize (at least for DMA1, need to be % 188 == 0, - * this logic is required */ -#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188) -#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188) - struct flexcop_dma dma[2]; - - int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ - u32 last_dma1_cur_pos; - /* position of the pointer last time the timer/packet irq occured */ - int count; - int count_prev; - int stream_problem; - - spinlock_t irq_lock; - unsigned long last_irq; - - struct delayed_work irq_check_work; - struct flexcop_device *fc_dev; -}; - -static int lastwreg, lastwval, lastrreg, lastrval; - -static flexcop_ibi_value flexcop_pci_read_ibi_reg(struct flexcop_device *fc, - flexcop_ibi_register r) -{ - struct flexcop_pci *fc_pci = fc->bus_specific; - flexcop_ibi_value v; - v.raw = readl(fc_pci->io_mem + r); - - if (lastrreg != r || lastrval != v.raw) { - lastrreg = r; lastrval = v.raw; - deb_reg("new rd: %3x: %08x\n", r, v.raw); - } - - return v; -} - -static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, - flexcop_ibi_register r, flexcop_ibi_value v) -{ - struct flexcop_pci *fc_pci = fc->bus_specific; - - if (lastwreg != r || lastwval != v.raw) { - lastwreg = r; lastwval = v.raw; - deb_reg("new wr: %3x: %08x\n", r, v.raw); - } - - writel(v.raw, fc_pci->io_mem + r); - return 0; -} - -static void flexcop_pci_irq_check_work(struct work_struct *work) -{ - struct flexcop_pci *fc_pci = - container_of(work, struct flexcop_pci, irq_check_work.work); - struct flexcop_device *fc = fc_pci->fc_dev; - - if (fc->feedcount) { - - if (fc_pci->count == fc_pci->count_prev) { - deb_chk("no IRQ since the last check\n"); - if (fc_pci->stream_problem++ == 3) { - struct dvb_demux_feed *feed; - deb_info("flexcop-pci: stream problem, resetting pid filter\n"); - - spin_lock_irq(&fc->demux.lock); - list_for_each_entry(feed, &fc->demux.feed_list, - list_head) { - flexcop_pid_feed_control(fc, feed, 0); - } - - list_for_each_entry(feed, &fc->demux.feed_list, - list_head) { - flexcop_pid_feed_control(fc, feed, 1); - } - spin_unlock_irq(&fc->demux.lock); - - fc_pci->stream_problem = 0; - } - } else { - fc_pci->stream_problem = 0; - fc_pci->count_prev = fc_pci->count; - } - } - - schedule_delayed_work(&fc_pci->irq_check_work, - msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); -} - -/* When PID filtering is turned on, we use the timer IRQ, because small amounts - * of data need to be passed to the user space instantly as well. When PID - * filtering is turned off, we use the page-change-IRQ */ -static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) -{ - struct flexcop_pci *fc_pci = dev_id; - struct flexcop_device *fc = fc_pci->fc_dev; - unsigned long flags; - flexcop_ibi_value v; - irqreturn_t ret = IRQ_HANDLED; - - spin_lock_irqsave(&fc_pci->irq_lock, flags); - v = fc->read_ibi_reg(fc, irq_20c); - - /* errors */ - if (v.irq_20c.Data_receiver_error) - deb_chk("data receiver error\n"); - if (v.irq_20c.Continuity_error_flag) - deb_chk("Contunuity error flag is set\n"); - if (v.irq_20c.LLC_SNAP_FLAG_set) - deb_chk("LLC_SNAP_FLAG_set is set\n"); - if (v.irq_20c.Transport_Error) - deb_chk("Transport error\n"); - - if ((fc_pci->count % 1000) == 0) - deb_chk("%d valid irq took place so far\n", fc_pci->count); - - if (v.irq_20c.DMA1_IRQ_Status == 1) { - if (fc_pci->active_dma1_addr == 0) - flexcop_pass_dmx_packets(fc_pci->fc_dev, - fc_pci->dma[0].cpu_addr0, - fc_pci->dma[0].size / 188); - else - flexcop_pass_dmx_packets(fc_pci->fc_dev, - fc_pci->dma[0].cpu_addr1, - fc_pci->dma[0].size / 188); - - deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr); - fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr; - /* for the timer IRQ we only can use buffer dmx feeding, because we don't have - * complete TS packets when reading from the DMA memory */ - } else if (v.irq_20c.DMA1_Timer_Status == 1) { - dma_addr_t cur_addr = - fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; - u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; - - deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, " - "last_cur_pos: %08x ", - jiffies_to_usecs(jiffies - fc_pci->last_irq), - v.raw, (unsigned long long)cur_addr, cur_pos, - fc_pci->last_dma1_cur_pos); - fc_pci->last_irq = jiffies; - - /* buffer end was reached, restarted from the beginning - * pass the data from last_cur_pos to the buffer end to the demux - */ - if (cur_pos < fc_pci->last_dma1_cur_pos) { - deb_irq(" end was reached: passing %d bytes ", - (fc_pci->dma[0].size*2 - 1) - - fc_pci->last_dma1_cur_pos); - flexcop_pass_dmx_data(fc_pci->fc_dev, - fc_pci->dma[0].cpu_addr0 + - fc_pci->last_dma1_cur_pos, - (fc_pci->dma[0].size*2) - - fc_pci->last_dma1_cur_pos); - fc_pci->last_dma1_cur_pos = 0; - } - - if (cur_pos > fc_pci->last_dma1_cur_pos) { - deb_irq(" passing %d bytes ", - cur_pos - fc_pci->last_dma1_cur_pos); - flexcop_pass_dmx_data(fc_pci->fc_dev, - fc_pci->dma[0].cpu_addr0 + - fc_pci->last_dma1_cur_pos, - cur_pos - fc_pci->last_dma1_cur_pos); - } - deb_irq("\n"); - - fc_pci->last_dma1_cur_pos = cur_pos; - fc_pci->count++; - } else { - deb_irq("isr for flexcop called, " - "apparently without reason (%08x)\n", v.raw); - ret = IRQ_NONE; - } - - spin_unlock_irqrestore(&fc_pci->irq_lock, flags); - return ret; -} - -static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) -{ - struct flexcop_pci *fc_pci = fc->bus_specific; - if (onoff) { - flexcop_dma_config(fc, &fc_pci->dma[0], FC_DMA_1); - flexcop_dma_config(fc, &fc_pci->dma[1], FC_DMA_2); - flexcop_dma_config_timer(fc, FC_DMA_1, 0); - flexcop_dma_xfer_control(fc, FC_DMA_1, - FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 1); - deb_irq("DMA xfer enabled\n"); - - fc_pci->last_dma1_cur_pos = 0; - flexcop_dma_control_timer_irq(fc, FC_DMA_1, 1); - deb_irq("IRQ enabled\n"); - fc_pci->count_prev = fc_pci->count; - } else { - flexcop_dma_control_timer_irq(fc, FC_DMA_1, 0); - deb_irq("IRQ disabled\n"); - - flexcop_dma_xfer_control(fc, FC_DMA_1, - FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 0); - deb_irq("DMA xfer disabled\n"); - } - return 0; -} - -static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci) -{ - int ret; - ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[0], - FC_DEFAULT_DMA1_BUFSIZE); - if (ret != 0) - return ret; - - ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[1], - FC_DEFAULT_DMA2_BUFSIZE); - if (ret != 0) { - flexcop_dma_free(&fc_pci->dma[0]); - return ret; - } - - flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_MEDIA | - FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1); - flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_CAO | - FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); - fc_pci->init_state |= FC_PCI_DMA_INIT; - return ret; -} - -static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci) -{ - if (fc_pci->init_state & FC_PCI_DMA_INIT) { - flexcop_dma_free(&fc_pci->dma[0]); - flexcop_dma_free(&fc_pci->dma[1]); - } - fc_pci->init_state &= ~FC_PCI_DMA_INIT; -} - -static int flexcop_pci_init(struct flexcop_pci *fc_pci) -{ - int ret; - u8 card_rev; - - pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev); - info("card revision %x", card_rev); - - if ((ret = pci_enable_device(fc_pci->pdev)) != 0) - return ret; - pci_set_master(fc_pci->pdev); - - if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0) - goto err_pci_disable_device; - - fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800); - - if (!fc_pci->io_mem) { - err("cannot map io memory\n"); - ret = -EIO; - goto err_pci_release_regions; - } - - pci_set_drvdata(fc_pci->pdev, fc_pci); - spin_lock_init(&fc_pci->irq_lock); - if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, - IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) - goto err_pci_iounmap; - - fc_pci->init_state |= FC_PCI_INIT; - return ret; - -err_pci_iounmap: - pci_iounmap(fc_pci->pdev, fc_pci->io_mem); - pci_set_drvdata(fc_pci->pdev, NULL); -err_pci_release_regions: - pci_release_regions(fc_pci->pdev); -err_pci_disable_device: - pci_disable_device(fc_pci->pdev); - return ret; -} - -static void flexcop_pci_exit(struct flexcop_pci *fc_pci) -{ - if (fc_pci->init_state & FC_PCI_INIT) { - free_irq(fc_pci->pdev->irq, fc_pci); - pci_iounmap(fc_pci->pdev, fc_pci->io_mem); - pci_set_drvdata(fc_pci->pdev, NULL); - pci_release_regions(fc_pci->pdev); - pci_disable_device(fc_pci->pdev); - } - fc_pci->init_state &= ~FC_PCI_INIT; -} - -static int flexcop_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct flexcop_device *fc; - struct flexcop_pci *fc_pci; - int ret = -ENOMEM; - - if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) { - err("out of memory\n"); - return -ENOMEM; - } - - /* general flexcop init */ - fc_pci = fc->bus_specific; - fc_pci->fc_dev = fc; - - fc->read_ibi_reg = flexcop_pci_read_ibi_reg; - fc->write_ibi_reg = flexcop_pci_write_ibi_reg; - fc->i2c_request = flexcop_i2c_request; - fc->get_mac_addr = flexcop_eeprom_check_mac_addr; - fc->stream_control = flexcop_pci_stream_control; - - if (enable_pid_filtering) - info("will use the HW PID filter."); - else - info("will pass the complete TS to the demuxer."); - - fc->pid_filtering = enable_pid_filtering; - fc->bus_type = FC_PCI; - fc->dev = &pdev->dev; - fc->owner = THIS_MODULE; - - /* bus specific part */ - fc_pci->pdev = pdev; - if ((ret = flexcop_pci_init(fc_pci)) != 0) - goto err_kfree; - - /* init flexcop */ - if ((ret = flexcop_device_initialize(fc)) != 0) - goto err_pci_exit; - - /* init dma */ - if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) - goto err_fc_exit; - - INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work); - - if (irq_chk_intv > 0) - schedule_delayed_work(&fc_pci->irq_check_work, - msecs_to_jiffies(irq_chk_intv < 100 ? - 100 : - irq_chk_intv)); - return ret; - -err_fc_exit: - flexcop_device_exit(fc); -err_pci_exit: - flexcop_pci_exit(fc_pci); -err_kfree: - flexcop_device_kfree(fc); - return ret; -} - -/* in theory every _exit function should be called exactly two times, - * here and in the bail-out-part of the _init-function - */ -static void flexcop_pci_remove(struct pci_dev *pdev) -{ - struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); - - if (irq_chk_intv > 0) - cancel_delayed_work(&fc_pci->irq_check_work); - - flexcop_pci_dma_exit(fc_pci); - flexcop_device_exit(fc_pci->fc_dev); - flexcop_pci_exit(fc_pci); - flexcop_device_kfree(fc_pci->fc_dev); -} - -static struct pci_device_id flexcop_pci_tbl[] = { - { PCI_DEVICE(0x13d0, 0x2103) }, - { }, -}; - -MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); - -static struct pci_driver flexcop_pci_driver = { - .name = "b2c2_flexcop_pci", - .id_table = flexcop_pci_tbl, - .probe = flexcop_pci_probe, - .remove = flexcop_pci_remove, -}; - -static int __init flexcop_pci_module_init(void) -{ - return pci_register_driver(&flexcop_pci_driver); -} - -static void __exit flexcop_pci_module_exit(void) -{ - pci_unregister_driver(&flexcop_pci_driver); -} - -module_init(flexcop_pci_module_init); -module_exit(flexcop_pci_module_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_NAME); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,166 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII - * see flexcop.c for copyright information - */ -#ifndef __FLEXCOP_REG_H__ -#define __FLEXCOP_REG_H__ - -typedef enum { - FLEXCOP_UNK = 0, - FLEXCOP_II, - FLEXCOP_IIB, - FLEXCOP_III, -} flexcop_revision_t; - -typedef enum { - FC_UNK = 0, - FC_CABLE, - FC_AIR_DVBT, - FC_AIR_ATSC1, - FC_AIR_ATSC2, - FC_AIR_ATSC3, - FC_SKY_REV23, - FC_SKY_REV26, - FC_SKY_REV27, - FC_SKY_REV28, -} flexcop_device_type_t; - -typedef enum { - FC_USB = 0, - FC_PCI, -} flexcop_bus_t; - -/* FlexCop IBI Registers */ -#if defined(__LITTLE_ENDIAN) -#include "flexcop_ibi_value_le.h" -#else -#if defined(__BIG_ENDIAN) -#include "flexcop_ibi_value_be.h" -#else -#error no endian defined -#endif -#endif - -#define fc_data_Tag_ID_DVB 0x3e -#define fc_data_Tag_ID_ATSC 0x3f -#define fc_data_Tag_ID_IDSB 0x8b - -#define fc_key_code_default 0x1 -#define fc_key_code_even 0x2 -#define fc_key_code_odd 0x3 - -extern flexcop_ibi_value ibi_zero; - -typedef enum { - FC_I2C_PORT_DEMOD = 1, - FC_I2C_PORT_EEPROM = 2, - FC_I2C_PORT_TUNER = 3, -} flexcop_i2c_port_t; - -typedef enum { - FC_WRITE = 0, - FC_READ = 1, -} flexcop_access_op_t; - -typedef enum { - FC_SRAM_DEST_NET = 1, - FC_SRAM_DEST_CAI = 2, - FC_SRAM_DEST_CAO = 4, - FC_SRAM_DEST_MEDIA = 8 -} flexcop_sram_dest_t; - -typedef enum { - FC_SRAM_DEST_TARGET_WAN_USB = 0, - FC_SRAM_DEST_TARGET_DMA1 = 1, - FC_SRAM_DEST_TARGET_DMA2 = 2, - FC_SRAM_DEST_TARGET_FC3_CA = 3 -} flexcop_sram_dest_target_t; - -typedef enum { - FC_SRAM_2_32KB = 0, /* 64KB */ - FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */ - FC_SRAM_1_128KB = 2, /* 128KB */ - FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */ -} flexcop_sram_type_t; - -typedef enum { - FC_WAN_SPEED_4MBITS = 0, - FC_WAN_SPEED_8MBITS = 1, - FC_WAN_SPEED_12MBITS = 2, - FC_WAN_SPEED_16MBITS = 3, -} flexcop_wan_speed_t; - -typedef enum { - FC_DMA_1 = 1, - FC_DMA_2 = 2, -} flexcop_dma_index_t; - -typedef enum { - FC_DMA_SUBADDR_0 = 1, - FC_DMA_SUBADDR_1 = 2, -} flexcop_dma_addr_index_t; - -/* names of the particular registers */ -typedef enum { - dma1_000 = 0x000, - dma1_004 = 0x004, - dma1_008 = 0x008, - dma1_00c = 0x00c, - dma2_010 = 0x010, - dma2_014 = 0x014, - dma2_018 = 0x018, - dma2_01c = 0x01c, - - tw_sm_c_100 = 0x100, - tw_sm_c_104 = 0x104, - tw_sm_c_108 = 0x108, - tw_sm_c_10c = 0x10c, - tw_sm_c_110 = 0x110, - - lnb_switch_freq_200 = 0x200, - misc_204 = 0x204, - ctrl_208 = 0x208, - irq_20c = 0x20c, - sw_reset_210 = 0x210, - misc_214 = 0x214, - mbox_v8_to_host_218 = 0x218, - mbox_host_to_v8_21c = 0x21c, - - pid_filter_300 = 0x300, - pid_filter_304 = 0x304, - pid_filter_308 = 0x308, - pid_filter_30c = 0x30c, - index_reg_310 = 0x310, - pid_n_reg_314 = 0x314, - mac_low_reg_318 = 0x318, - mac_high_reg_31c = 0x31c, - - data_tag_400 = 0x400, - card_id_408 = 0x408, - card_id_40c = 0x40c, - mac_address_418 = 0x418, - mac_address_41c = 0x41c, - - ci_600 = 0x600, - pi_604 = 0x604, - pi_608 = 0x608, - dvb_reg_60c = 0x60c, - - sram_ctrl_reg_700 = 0x700, - net_buf_reg_704 = 0x704, - cai_buf_reg_708 = 0x708, - cao_buf_reg_70c = 0x70c, - media_buf_reg_710 = 0x710, - sram_dest_reg_714 = 0x714, - net_buf_reg_718 = 0x718, - wan_ctrl_reg_71c = 0x71c, -} flexcop_ibi_register; - -#define flexcop_set_ibi_value(reg,attr,val) { \ - flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \ - v.reg.attr = val; \ - fc->write_ibi_reg(fc,reg,v); \ -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-sram.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-sram.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-sram.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-sram.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,363 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-sram.c - functions for controlling the SRAM - * see flexcop.c for copyright information - */ -#include "flexcop.h" - -static void flexcop_sram_set_chip(struct flexcop_device *fc, - flexcop_sram_type_t type) -{ - flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type); -} - -int flexcop_sram_init(struct flexcop_device *fc) -{ - switch (fc->rev) { - case FLEXCOP_II: - case FLEXCOP_IIB: - flexcop_sram_set_chip(fc, FC_SRAM_1_32KB); - break; - case FLEXCOP_III: - flexcop_sram_set_chip(fc, FC_SRAM_1_48KB); - break; - default: - return -EINVAL; - } - return 0; -} - -int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, - flexcop_sram_dest_target_t target) -{ - flexcop_ibi_value v; - v = fc->read_ibi_reg(fc, sram_dest_reg_714); - - if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) { - err("SRAM destination target to available on FlexCopII(b)\n"); - return -EINVAL; - } - deb_sram("sram dest: %x target: %x\n", dest, target); - - if (dest & FC_SRAM_DEST_NET) - v.sram_dest_reg_714.NET_Dest = target; - if (dest & FC_SRAM_DEST_CAI) - v.sram_dest_reg_714.CAI_Dest = target; - if (dest & FC_SRAM_DEST_CAO) - v.sram_dest_reg_714.CAO_Dest = target; - if (dest & FC_SRAM_DEST_MEDIA) - v.sram_dest_reg_714.MEDIA_Dest = target; - - fc->write_ibi_reg(fc,sram_dest_reg_714,v); - udelay(1000); /* TODO delay really necessary */ - - return 0; -} -EXPORT_SYMBOL(flexcop_sram_set_dest); - -void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s) -{ - flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s); -} -EXPORT_SYMBOL(flexcop_wan_set_speed); - -void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill) -{ - flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); - v.sram_dest_reg_714.ctrl_usb_wan = usb_wan; - v.sram_dest_reg_714.ctrl_sramdma = sramdma; - v.sram_dest_reg_714.ctrl_maximumfill = maximumfill; - fc->write_ibi_reg(fc,sram_dest_reg_714,v); -} -EXPORT_SYMBOL(flexcop_sram_ctrl); - -#if 0 -static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) -{ - int i, retries; - u32 command; - - for (i = 0; i < len; i++) { - command = bank | addr | 0x04000000 | (*buf << 0x10); - - retries = 2; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __func__); - - write_reg_dw(adapter, 0x700, command); - - buf++; - addr++; - } -} - -static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) -{ - int i, retries; - u32 command, value; - - for (i = 0; i < len; i++) { - command = bank | addr | 0x04008000; - - retries = 10000; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __func__); - - write_reg_dw(adapter, 0x700, command); - - retries = 10000; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __func__); - - value = read_reg_dw(adapter, 0x700) >> 0x10; - - *buf = (value & 0xff); - - addr++; - buf++; - } -} - -static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) -{ - u32 bank; - - bank = 0; - - if (adapter->dw_sram_type == 0x20000) { - bank = (addr & 0x18000) << 0x0d; - } - - if (adapter->dw_sram_type == 0x00000) { - if ((addr >> 0x0f) == 0) - bank = 0x20000000; - else - bank = 0x10000000; - } - flex_sram_write(adapter, bank, addr & 0x7fff, buf, len); -} - -static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) -{ - u32 bank; - bank = 0; - - if (adapter->dw_sram_type == 0x20000) { - bank = (addr & 0x18000) << 0x0d; - } - - if (adapter->dw_sram_type == 0x00000) { - if ((addr >> 0x0f) == 0) - bank = 0x20000000; - else - bank = 0x10000000; - } - flex_sram_read(adapter, bank, addr & 0x7fff, buf, len); -} - -static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len) -{ - u32 length; - while (len != 0) { - length = len; - /* check if the address range belongs to the same - * 32K memory chip. If not, the data is read - * from one chip at a time */ - if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { - length = (((addr >> 0x0f) + 1) << 0x0f) - addr; - } - - sram_read_chunk(adapter, addr, buf, length); - addr = addr + length; - buf = buf + length; - len = len - length; - } -} - -static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len) -{ - u32 length; - while (len != 0) { - length = len; - - /* check if the address range belongs to the same - * 32K memory chip. If not, the data is - * written to one chip at a time */ - if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { - length = (((addr >> 0x0f) + 1) << 0x0f) - addr; - } - - sram_write_chunk(adapter, addr, buf, length); - addr = addr + length; - buf = buf + length; - len = len - length; - } -} - -static void sram_set_size(struct adapter *adapter, u32 mask) -{ - write_reg_dw(adapter, 0x71c, - (mask | (~0x30000 & read_reg_dw(adapter, 0x71c)))); -} - -static void sram_init(struct adapter *adapter) -{ - u32 tmp; - tmp = read_reg_dw(adapter, 0x71c); - write_reg_dw(adapter, 0x71c, 1); - - if (read_reg_dw(adapter, 0x71c) != 0) { - write_reg_dw(adapter, 0x71c, tmp); - adapter->dw_sram_type = tmp & 0x30000; - ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type); - } else { - adapter->dw_sram_type = 0x10000; - ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type); - } -} - -static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr) -{ - u8 tmp1, tmp2; - dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr); - - sram_set_size(adapter, mask); - sram_init(adapter); - - tmp2 = 0xa5; - tmp1 = 0x4f; - - sram_write(adapter, addr, &tmp2, 1); - sram_write(adapter, addr + 4, &tmp1, 1); - - tmp2 = 0; - mdelay(20); - - sram_read(adapter, addr, &tmp2, 1); - sram_read(adapter, addr, &tmp2, 1); - - dprintk("%s: wrote 0xa5, read 0x%2x\n", __func__, tmp2); - - if (tmp2 != 0xa5) - return 0; - - tmp2 = 0x5a; - tmp1 = 0xf4; - - sram_write(adapter, addr, &tmp2, 1); - sram_write(adapter, addr + 4, &tmp1, 1); - - tmp2 = 0; - mdelay(20); - - sram_read(adapter, addr, &tmp2, 1); - sram_read(adapter, addr, &tmp2, 1); - - dprintk("%s: wrote 0x5a, read 0x%2x\n", __func__, tmp2); - - if (tmp2 != 0x5a) - return 0; - return 1; -} - -static u32 sram_length(struct adapter *adapter) -{ - if (adapter->dw_sram_type == 0x10000) - return 32768; /* 32K */ - if (adapter->dw_sram_type == 0x00000) - return 65536; /* 64K */ - if (adapter->dw_sram_type == 0x20000) - return 131072; /* 128K */ - return 32768; /* 32K */ -} - -/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. - - for 128K there are 4x32K chips at bank 0,1,2,3. - - for 64K there are 2x32K chips at bank 1,2. - - for 32K there is one 32K chip at bank 0. - - FlexCop works only with one bank at a time. The bank is selected - by bits 28-29 of the 0x700 register. - - bank 0 covers addresses 0x00000-0x07fff - bank 1 covers addresses 0x08000-0x0ffff - bank 2 covers addresses 0x10000-0x17fff - bank 3 covers addresses 0x18000-0x1ffff */ - -static int flexcop_sram_detect(struct flexcop_device *fc) -{ - flexcop_ibi_value r208, r71c_0, vr71c_1; - r208 = fc->read_ibi_reg(fc, ctrl_208); - fc->write_ibi_reg(fc, ctrl_208, ibi_zero); - - r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c); - write_reg_dw(adapter, 0x71c, 1); - tmp3 = read_reg_dw(adapter, 0x71c); - dprintk("%s: tmp3 = %x\n", __func__, tmp3); - write_reg_dw(adapter, 0x71c, tmp2); - - // check for internal SRAM ??? - tmp3--; - if (tmp3 != 0) { - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: sram size = 32K\n", __func__); - return 32; - } - - if (sram_test_location(adapter, 0x20000, 0x18000) != 0) { - sram_set_size(adapter, 0x20000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: sram size = 128K\n", __func__); - return 128; - } - - if (sram_test_location(adapter, 0x00000, 0x10000) != 0) { - sram_set_size(adapter, 0x00000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: sram size = 64K\n", __func__); - return 64; - } - - if (sram_test_location(adapter, 0x10000, 0x00000) != 0) { - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: sram size = 32K\n", __func__); - return 32; - } - - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: SRAM detection failed. Set to 32K \n", __func__); - return 0; -} - -static void sll_detect_sram_size(struct adapter *adapter) -{ - sram_detect_for_flex2(adapter); -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-usb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-usb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-usb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-usb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,608 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-usb.c - covers the USB part - * see flexcop.c for copyright information - */ -#define FC_LOG_PREFIX "flexcop_usb" -#include "flexcop-usb.h" -#include "flexcop-common.h" - -/* Version information */ -#define DRIVER_VERSION "0.1" -#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver" -#define DRIVER_AUTHOR "Patrick Boettcher " - -/* debug */ -#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((debug & level)) printk(args); } while (0) - -#define debug_dump(b, l, method) do {\ - int i; \ - for (i = 0; i < l; i++) \ - method("%02x ", b[i]); \ - method("\n"); \ -} while (0) - -#define DEBSTATUS "" -#else -#define dprintk(level, args...) -#define debug_dump(b, l, method) -#define DEBSTATUS " (debugging is not enabled)" -#endif - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2," - "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS); -#undef DEBSTATUS - -#define deb_info(args...) dprintk(0x01, args) -#define deb_ts(args...) dprintk(0x02, args) -#define deb_ctrl(args...) dprintk(0x04, args) -#define deb_i2c(args...) dprintk(0x08, args) -#define deb_v8(args...) dprintk(0x10, args) - -/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits - * in the IBI address, to make the V8 code simpler. - * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used) - * in general: 0000 0HHH 000L LL00 - * IBI ADDRESS FORMAT: RHHH BLLL - * - * where R is the read(1)/write(0) bit, B is the busy bit - * and HHH and LLL are the two sets of three bits from the PCI address. - */ -#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \ - (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70)) -#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \ - (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4)) - -/* - * DKT 020228 - * - forget about this VENDOR_BUFFER_SIZE, read and write register - * deal with DWORD or 4 bytes, that should be should from now on - * - from now on, we don't support anything older than firm 1.00 - * I eliminated the write register as a 2 trip of writing hi word and lo word - * and force this to write only 4 bytes at a time. - * NOTE: this should work with all the firmware from 1.00 and newer - */ -static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read) -{ - struct flexcop_usb *fc_usb = fc->bus_specific; - u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG; - u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR; - u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | - (read ? 0x80 : 0); - - int len = usb_control_msg(fc_usb->udev, - read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT, - request, - request_type, /* 0xc0 read or 0x40 write */ - wAddress, - 0, - val, - sizeof(u32), - B2C2_WAIT_FOR_OPERATION_RDW * HZ); - - if (len != sizeof(u32)) { - err("error while %s dword from %d (%d).", read ? "reading" : - "writing", wAddress, wRegOffsPCI); - return -EIO; - } - return 0; -} -/* - * DKT 010817 - add support for V8 memory read/write and flash update - */ -static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb, - flexcop_usb_request_t req, u8 page, u16 wAddress, - u8 *pbBuffer, u32 buflen) -{ - u8 request_type = USB_TYPE_VENDOR; - u16 wIndex; - int nWaitTime, pipe, len; - wIndex = page << 8; - - switch (req) { - case B2C2_USB_READ_V8_MEM: - nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ; - request_type |= USB_DIR_IN; - pipe = B2C2_USB_CTRL_PIPE_IN; - break; - case B2C2_USB_WRITE_V8_MEM: - wIndex |= pbBuffer[0]; - request_type |= USB_DIR_OUT; - nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE; - pipe = B2C2_USB_CTRL_PIPE_OUT; - break; - case B2C2_USB_FLASH_BLOCK: - request_type |= USB_DIR_OUT; - nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH; - pipe = B2C2_USB_CTRL_PIPE_OUT; - break; - default: - deb_info("unsupported request for v8_mem_req %x.\n", req); - return -EINVAL; - } - deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req, - wAddress, wIndex, buflen); - - len = usb_control_msg(fc_usb->udev, pipe, - req, - request_type, - wAddress, - wIndex, - pbBuffer, - buflen, - nWaitTime * HZ); - - debug_dump(pbBuffer, len, deb_v8); - return len == buflen ? 0 : -EIO; -} - -#define bytes_left_to_read_on_page(paddr,buflen) \ - ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \ - ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK))) - -static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, - flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start, - u32 addr, int extended, u8 *buf, u32 len) -{ - int i,ret = 0; - u16 wMax; - u32 pagechunk = 0; - - switch(req) { - case B2C2_USB_READ_V8_MEM: - wMax = USB_MEM_READ_MAX; - break; - case B2C2_USB_WRITE_V8_MEM: - wMax = USB_MEM_WRITE_MAX; - break; - case B2C2_USB_FLASH_BLOCK: - wMax = USB_FLASH_MAX; - break; - default: - return -EINVAL; - break; - } - for (i = 0; i < len;) { - pagechunk = - wMax < bytes_left_to_read_on_page(addr, len) ? - wMax : - bytes_left_to_read_on_page(addr, len); - deb_info("%x\n", - (addr & V8_MEMORY_PAGE_MASK) | - (V8_MEMORY_EXTENDED*extended)); - - ret = flexcop_usb_v8_memory_req(fc_usb, req, - page_start + (addr / V8_MEMORY_PAGE_SIZE), - (addr & V8_MEMORY_PAGE_MASK) | - (V8_MEMORY_EXTENDED*extended), - &buf[i], pagechunk); - - if (ret < 0) - return ret; - addr += pagechunk; - len -= pagechunk; - } - return 0; -} - -static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended) -{ - return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM, - V8_MEMORY_PAGE_FLASH, 0x1f010, 1, - fc->dvb_adapter.proposed_mac, 6); -} - -#if 0 -static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set, - flexcop_usb_utility_function_t func, u8 extra, u16 wIndex, - u16 buflen, u8 *pvBuffer) -{ - u16 wValue; - u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR; - int nWaitTime = 2, - pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len; - wValue = (func << 8) | extra; - - len = usb_control_msg(fc_usb->udev,pipe, - B2C2_USB_UTILITY, - request_type, - wValue, - wIndex, - pvBuffer, - buflen, - nWaitTime * HZ); - return len == buflen ? 0 : -EIO; -} -#endif - -/* usb i2c stuff */ -static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c, - flexcop_usb_request_t req, flexcop_usb_i2c_function_t func, - u8 chipaddr, u8 addr, u8 *buf, u8 buflen) -{ - struct flexcop_usb *fc_usb = i2c->fc->bus_specific; - u16 wValue, wIndex; - int nWaitTime,pipe,len; - u8 request_type = USB_TYPE_VENDOR; - - switch (func) { - case USB_FUNC_I2C_WRITE: - case USB_FUNC_I2C_MULTIWRITE: - case USB_FUNC_I2C_REPEATWRITE: - /* DKT 020208 - add this to support special case of DiSEqC */ - case USB_FUNC_I2C_CHECKWRITE: - pipe = B2C2_USB_CTRL_PIPE_OUT; - nWaitTime = 2; - request_type |= USB_DIR_OUT; - break; - case USB_FUNC_I2C_READ: - case USB_FUNC_I2C_REPEATREAD: - pipe = B2C2_USB_CTRL_PIPE_IN; - nWaitTime = 2; - request_type |= USB_DIR_IN; - break; - default: - deb_info("unsupported function for i2c_req %x\n", func); - return -EINVAL; - } - wValue = (func << 8) | (i2c->port << 4); - wIndex = (chipaddr << 8 ) | addr; - - deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n", - func, request_type, req, - wValue & 0xff, wValue >> 8, - wIndex & 0xff, wIndex >> 8); - - len = usb_control_msg(fc_usb->udev,pipe, - req, - request_type, - wValue, - wIndex, - buf, - buflen, - nWaitTime * HZ); - return len == buflen ? 0 : -EREMOTEIO; -} - -/* actual bus specific access functions, - make sure prototype are/will be equal to pci */ -static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, - flexcop_ibi_register reg) -{ - flexcop_ibi_value val; - val.raw = 0; - flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1); - return val; -} - -static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, - flexcop_ibi_register reg, flexcop_ibi_value val) -{ - return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0); -} - -static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c, - flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) -{ - if (op == FC_READ) - return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, - USB_FUNC_I2C_READ, chipaddr, addr, buf, len); - else - return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, - USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len); -} - -static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, - u8 *buffer, int buffer_length) -{ - u8 *b; - int l; - - deb_ts("tmp_buffer_length=%d, buffer_length=%d\n", - fc_usb->tmp_buffer_length, buffer_length); - - if (fc_usb->tmp_buffer_length > 0) { - memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer, - buffer_length); - fc_usb->tmp_buffer_length += buffer_length; - b = fc_usb->tmp_buffer; - l = fc_usb->tmp_buffer_length; - } else { - b=buffer; - l=buffer_length; - } - - while (l >= 190) { - if (*b == 0xff) { - switch (*(b+1) & 0x03) { - case 0x01: /* media packet */ - if (*(b+2) == 0x47) - flexcop_pass_dmx_packets( - fc_usb->fc_dev, b+2, 1); - else - deb_ts( - "not ts packet %02x %02x %02x %02x \n", - *(b+2), *(b+3), - *(b+4), *(b+5)); - b += 190; - l -= 190; - break; - default: - deb_ts("wrong packet type\n"); - l = 0; - break; - } - } else { - deb_ts("wrong header\n"); - l = 0; - } - } - - if (l>0) - memcpy(fc_usb->tmp_buffer, b, l); - fc_usb->tmp_buffer_length = l; -} - -static void flexcop_usb_urb_complete(struct urb *urb) -{ - struct flexcop_usb *fc_usb = urb->context; - int i; - - if (urb->actual_length > 0) - deb_ts("urb completed, bufsize: %d actlen; %d\n", - urb->transfer_buffer_length, urb->actual_length); - - for (i = 0; i < urb->number_of_packets; i++) { - if (urb->iso_frame_desc[i].status < 0) { - err("iso frame descriptor %d has an error: %d\n", i, - urb->iso_frame_desc[i].status); - } else - if (urb->iso_frame_desc[i].actual_length > 0) { - deb_ts("passed %d bytes to the demux\n", - urb->iso_frame_desc[i].actual_length); - - flexcop_usb_process_frame(fc_usb, - urb->transfer_buffer + - urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - } - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - usb_submit_urb(urb,GFP_ATOMIC); -} - -static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff) -{ - /* submit/kill iso packets */ - return 0; -} - -static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) -{ - int i; - for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) - if (fc_usb->iso_urb[i] != NULL) { - deb_ts("unlinking/killing urb no. %d\n",i); - usb_kill_urb(fc_usb->iso_urb[i]); - usb_free_urb(fc_usb->iso_urb[i]); - } - - if (fc_usb->iso_buffer != NULL) - pci_free_consistent(NULL, - fc_usb->buffer_size, fc_usb->iso_buffer, - fc_usb->dma_addr); -} - -static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) -{ - u16 frame_size = le16_to_cpu( - fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize); - int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * - frame_size, i, j, ret; - int buffer_offset = 0; - - deb_ts("creating %d iso-urbs with %d frames " - "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB, - B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize); - - fc_usb->iso_buffer = pci_alloc_consistent(NULL, - bufsize, &fc_usb->dma_addr); - if (fc_usb->iso_buffer == NULL) - return -ENOMEM; - - memset(fc_usb->iso_buffer, 0, bufsize); - fc_usb->buffer_size = bufsize; - - /* creating iso urbs */ - for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { - fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO, - GFP_ATOMIC); - if (fc_usb->iso_urb[i] == NULL) { - ret = -ENOMEM; - goto urb_error; - } - } - - /* initialising and submitting iso urbs */ - for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { - int frame_offset = 0; - struct urb *urb = fc_usb->iso_urb[i]; - deb_ts("initializing and submitting urb no. %d " - "(buf_offset: %d).\n", i, buffer_offset); - - urb->dev = fc_usb->udev; - urb->context = fc_usb; - urb->complete = flexcop_usb_urb_complete; - urb->pipe = B2C2_USB_DATA_PIPE; - urb->transfer_flags = URB_ISO_ASAP; - urb->interval = 1; - urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO; - urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO; - urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset; - - buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO; - for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) { - deb_ts("urb no: %d, frame: %d, frame_offset: %d\n", - i, j, frame_offset); - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = frame_size; - frame_offset += frame_size; - } - - if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) { - err("submitting urb %d failed with %d.", i, ret); - goto urb_error; - } - deb_ts("submitted urb no. %d.\n",i); - } - - /* SRAM */ - flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA | - FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, - FC_SRAM_DEST_TARGET_WAN_USB); - flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS); - flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1); - return 0; - -urb_error: - flexcop_usb_transfer_exit(fc_usb); - return ret; -} - -static int flexcop_usb_init(struct flexcop_usb *fc_usb) -{ - /* use the alternate setting with the larges buffer */ - usb_set_interface(fc_usb->udev,0,1); - switch (fc_usb->udev->speed) { - case USB_SPEED_LOW: - err("cannot handle USB speed because it is too slow."); - return -ENODEV; - break; - case USB_SPEED_FULL: - info("running at FULL speed."); - break; - case USB_SPEED_HIGH: - info("running at HIGH speed."); - break; - case USB_SPEED_UNKNOWN: /* fall through */ - default: - err("cannot handle USB speed because it is unknown."); - return -ENODEV; - } - usb_set_intfdata(fc_usb->uintf, fc_usb); - return 0; -} - -static void flexcop_usb_exit(struct flexcop_usb *fc_usb) -{ - usb_set_intfdata(fc_usb->uintf, NULL); -} - -static int flexcop_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct flexcop_usb *fc_usb = NULL; - struct flexcop_device *fc = NULL; - int ret; - - if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { - err("out of memory\n"); - return -ENOMEM; - } - - /* general flexcop init */ - fc_usb = fc->bus_specific; - fc_usb->fc_dev = fc; - - fc->read_ibi_reg = flexcop_usb_read_ibi_reg; - fc->write_ibi_reg = flexcop_usb_write_ibi_reg; - fc->i2c_request = flexcop_usb_i2c_request; - fc->get_mac_addr = flexcop_usb_get_mac_addr; - - fc->stream_control = flexcop_usb_stream_control; - - fc->pid_filtering = 1; - fc->bus_type = FC_USB; - - fc->dev = &udev->dev; - fc->owner = THIS_MODULE; - - /* bus specific part */ - fc_usb->udev = udev; - fc_usb->uintf = intf; - if ((ret = flexcop_usb_init(fc_usb)) != 0) - goto err_kfree; - - /* init flexcop */ - if ((ret = flexcop_device_initialize(fc)) != 0) - goto err_usb_exit; - - /* xfer init */ - if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0) - goto err_fc_exit; - - info("%s successfully initialized and connected.", DRIVER_NAME); - return 0; - -err_fc_exit: - flexcop_device_exit(fc); -err_usb_exit: - flexcop_usb_exit(fc_usb); -err_kfree: - flexcop_device_kfree(fc); - return ret; -} - -static void flexcop_usb_disconnect(struct usb_interface *intf) -{ - struct flexcop_usb *fc_usb = usb_get_intfdata(intf); - flexcop_usb_transfer_exit(fc_usb); - flexcop_device_exit(fc_usb->fc_dev); - flexcop_usb_exit(fc_usb); - flexcop_device_kfree(fc_usb->fc_dev); - info("%s successfully deinitialized and disconnected.", DRIVER_NAME); -} - -static struct usb_device_id flexcop_usb_table [] = { - { USB_DEVICE(0x0af7, 0x0101) }, - { } -}; -MODULE_DEVICE_TABLE (usb, flexcop_usb_table); - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver flexcop_usb_driver = { - .name = "b2c2_flexcop_usb", - .probe = flexcop_usb_probe, - .disconnect = flexcop_usb_disconnect, - .id_table = flexcop_usb_table, -}; - -/* module stuff */ -static int __init flexcop_usb_module_init(void) -{ - int result; - if ((result = usb_register(&flexcop_usb_driver))) { - err("usb_register failed. (%d)", result); - return result; - } - return 0; -} - -static void __exit flexcop_usb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&flexcop_usb_driver); -} - -module_init(flexcop_usb_module_init); -module_exit(flexcop_usb_module_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_NAME); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-usb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-usb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-usb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/flexcop-usb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/* - * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III - * flexcop-usb.h - header file for the USB part - * see flexcop.c for copyright information - */ -#ifndef __FLEXCOP_USB_H_INCLUDED__ -#define __FLEXCOP_USB_H_INCLUDED__ - -#include - -/* transfer parameters */ -#define B2C2_USB_FRAMES_PER_ISO 4 -#define B2C2_USB_NUM_ISO_URB 4 - -#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev, 0) -#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev, 0) -#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 0x81) - -struct flexcop_usb { - struct usb_device *udev; - struct usb_interface *uintf; - - u8 *iso_buffer; - int buffer_size; - dma_addr_t dma_addr; - - struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; - struct flexcop_device *fc_dev; - - u8 tmp_buffer[1023+190]; - int tmp_buffer_length; -}; - -#if 0 -/* request types TODO What is its use?*/ -typedef enum { - -} flexcop_usb_request_type_t; -#endif - -/* request */ -typedef enum { - B2C2_USB_WRITE_V8_MEM = 0x04, - B2C2_USB_READ_V8_MEM = 0x05, - B2C2_USB_READ_REG = 0x08, - B2C2_USB_WRITE_REG = 0x0A, - B2C2_USB_WRITEREGHI = 0x0B, - B2C2_USB_FLASH_BLOCK = 0x10, - B2C2_USB_I2C_REQUEST = 0x11, - B2C2_USB_UTILITY = 0x12, -} flexcop_usb_request_t; - -/* function definition for I2C_REQUEST */ -typedef enum { - USB_FUNC_I2C_WRITE = 0x01, - USB_FUNC_I2C_MULTIWRITE = 0x02, - USB_FUNC_I2C_READ = 0x03, - USB_FUNC_I2C_REPEATWRITE = 0x04, - USB_FUNC_GET_DESCRIPTOR = 0x05, - USB_FUNC_I2C_REPEATREAD = 0x06, - /* DKT 020208 - add this to support special case of DiSEqC */ - USB_FUNC_I2C_CHECKWRITE = 0x07, - USB_FUNC_I2C_CHECKRESULT = 0x08, -} flexcop_usb_i2c_function_t; - -/* function definition for UTILITY request 0x12 - * DKT 020304 - new utility function */ -typedef enum { - UTILITY_SET_FILTER = 0x01, - UTILITY_DATA_ENABLE = 0x02, - UTILITY_FLEX_MULTIWRITE = 0x03, - UTILITY_SET_BUFFER_SIZE = 0x04, - UTILITY_FLEX_OPERATOR = 0x05, - UTILITY_FLEX_RESET300_START = 0x06, - UTILITY_FLEX_RESET300_STOP = 0x07, - UTILITY_FLEX_RESET300 = 0x08, - UTILITY_SET_ISO_SIZE = 0x09, - UTILITY_DATA_RESET = 0x0A, - UTILITY_GET_DATA_STATUS = 0x10, - UTILITY_GET_V8_REG = 0x11, - /* DKT 020326 - add function for v1.14 */ - UTILITY_SRAM_WRITE = 0x12, - UTILITY_SRAM_READ = 0x13, - UTILITY_SRAM_TESTFILL = 0x14, - UTILITY_SRAM_TESTSET = 0x15, - UTILITY_SRAM_TESTVERIFY = 0x16, -} flexcop_usb_utility_function_t; - -#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ) -#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ) -#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ) - -#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ) -#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ) -#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ) - -typedef enum { - V8_MEMORY_PAGE_DVB_CI = 0x20, - V8_MEMORY_PAGE_DVB_DS = 0x40, - V8_MEMORY_PAGE_MULTI2 = 0x60, - V8_MEMORY_PAGE_FLASH = 0x80 -} flexcop_usb_mem_page_t; - -#define V8_MEMORY_EXTENDED (1 << 15) -#define USB_MEM_READ_MAX 32 -#define USB_MEM_WRITE_MAX 1 -#define USB_FLASH_MAX 8 -#define V8_MEMORY_PAGE_SIZE 0x8000 /* 32K */ -#define V8_MEMORY_PAGE_MASK 0x7FFF - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -config DVB_B2C2_FLEXCOP - tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters" - depends on DVB_CORE && I2C - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_MT312 if !DVB_FE_CUSTOMISE - select DVB_NXT200X if !DVB_FE_CUSTOMISE - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_BCM3510 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_S5H1420 if !DVB_FE_CUSTOMISE - select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE - select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select DVB_CX24123 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE - help - Support for the digital TV receiver chip made by B2C2 Inc. included in - Technisats PCI cards and USB boxes. - - Say Y if you own such a device and want to use it. - -config DVB_B2C2_FLEXCOP_PCI - tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI" - depends on DVB_B2C2_FLEXCOP && PCI && I2C - help - Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2. - - Say Y if you own such a device and want to use it. - -config DVB_B2C2_FLEXCOP_USB - tristate "Technisat/B2C2 Air/Sky/Cable2PC USB" - depends on DVB_B2C2_FLEXCOP && USB && I2C - help - Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2, - - Say Y if you own such a device and want to use it. - -config DVB_B2C2_FLEXCOP_DEBUG - bool "Enable debug for the B2C2 FlexCop drivers" - depends on DVB_B2C2_FLEXCOP - help - Say Y if you want to enable the module option to control debug messages - of all B2C2 FlexCop drivers. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/b2c2/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \ - flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o -obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o - -ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),) -b2c2-flexcop-objs += flexcop-dma.o -endif - -b2c2-flexcop-pci-objs = flexcop-pci.o -obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o - -b2c2-flexcop-usb-objs = flexcop-usb.o -obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/bt878.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/bt878.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/bt878.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/bt878.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,609 +0,0 @@ -/* - * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card - * - * Copyright (C) 2002 Peter Hettkamp - * - * large parts based on the bttv driver - * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de) - * & Marcus Metzler (mocm@metzlerbros.de) - * (c) 1999,2000 Gerd Knorr - * - * 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, or (at your option) any later version. - * - - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "bt878.h" -#include "dst_priv.h" - - -/**************************************/ -/* Miscellaneous utility definitions */ -/**************************************/ - -static unsigned int bt878_verbose = 1; -static unsigned int bt878_debug; - -module_param_named(verbose, bt878_verbose, int, 0444); -MODULE_PARM_DESC(verbose, - "verbose startup messages, default is 1 (yes)"); -module_param_named(debug, bt878_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off)."); - -int bt878_num; -struct bt878 bt878[BT878_MAX]; - -EXPORT_SYMBOL(bt878_num); -EXPORT_SYMBOL(bt878); - -#define btwrite(dat,adr) bmtwrite((dat), (bt->bt878_mem+(adr))) -#define btread(adr) bmtread(bt->bt878_mem+(adr)) - -#define btand(dat,adr) btwrite((dat) & btread(adr), adr) -#define btor(dat,adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) - -#if defined(dprintk) -#undef dprintk -#endif -#define dprintk(fmt, arg...) \ - do { \ - if (bt878_debug) \ - printk(KERN_DEBUG fmt, ##arg); \ - } while (0) - -static void bt878_mem_free(struct bt878 *bt) -{ - if (bt->buf_cpu) { - pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu, - bt->buf_dma); - bt->buf_cpu = NULL; - } - - if (bt->risc_cpu) { - pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu, - bt->risc_dma); - bt->risc_cpu = NULL; - } -} - -static int bt878_mem_alloc(struct bt878 *bt) -{ - if (!bt->buf_cpu) { - bt->buf_size = 128 * 1024; - - bt->buf_cpu = - pci_alloc_consistent(bt->dev, bt->buf_size, - &bt->buf_dma); - - if (!bt->buf_cpu) - return -ENOMEM; - - memset(bt->buf_cpu, 0, bt->buf_size); - } - - if (!bt->risc_cpu) { - bt->risc_size = PAGE_SIZE; - bt->risc_cpu = - pci_alloc_consistent(bt->dev, bt->risc_size, - &bt->risc_dma); - - if (!bt->risc_cpu) { - bt878_mem_free(bt); - return -ENOMEM; - } - - memset(bt->risc_cpu, 0, bt->risc_size); - } - - return 0; -} - -/* RISC instructions */ -#define RISC_WRITE (0x01 << 28) -#define RISC_JUMP (0x07 << 28) -#define RISC_SYNC (0x08 << 28) - -/* RISC bits */ -#define RISC_WR_SOL (1 << 27) -#define RISC_WR_EOL (1 << 26) -#define RISC_IRQ (1 << 24) -#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16)) -#define RISC_SYNC_RESYNC (1 << 15) -#define RISC_SYNC_FM1 0x06 -#define RISC_SYNC_VRO 0x0C - -#define RISC_FLUSH() bt->risc_pos = 0 -#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr) - -static int bt878_make_risc(struct bt878 *bt) -{ - bt->block_bytes = bt->buf_size >> 4; - bt->block_count = 1 << 4; - bt->line_bytes = bt->block_bytes; - bt->line_count = bt->block_count; - - while (bt->line_bytes > 4095) { - bt->line_bytes >>= 1; - bt->line_count <<= 1; - } - - if (bt->line_count > 255) { - printk(KERN_ERR "bt878: buffer size error!\n"); - return -EINVAL; - } - return 0; -} - - -static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin) -{ - u32 buf_pos = 0; - u32 line; - - RISC_FLUSH(); - RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin); - RISC_INSTR(0); - - dprintk("bt878: risc len lines %u, bytes per line %u\n", - bt->line_count, bt->line_bytes); - for (line = 0; line < bt->line_count; line++) { - // At the beginning of every block we issue an IRQ with previous (finished) block number set - if (!(buf_pos % bt->block_bytes)) - RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | - RISC_IRQ | - RISC_STATUS(((buf_pos / - bt->block_bytes) + - (bt->block_count - - 1)) % - bt->block_count) | bt-> - line_bytes); - else - RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | - bt->line_bytes); - RISC_INSTR(bt->buf_dma + buf_pos); - buf_pos += bt->line_bytes; - } - - RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO); - RISC_INSTR(0); - - RISC_INSTR(RISC_JUMP); - RISC_INSTR(bt->risc_dma); - - btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN); -} - -/*****************************/ -/* Start/Stop grabbing funcs */ -/*****************************/ - -void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, - u32 irq_err_ignore) -{ - u32 int_mask; - - dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg); - /* complete the writing of the risc dma program now we have - * the card specifics - */ - bt878_risc_program(bt, op_sync_orin); - controlreg &= ~0x1f; - controlreg |= 0x1b; - - btwrite(bt->risc_dma, BT878_ARISC_START); - - /* original int mask had : - * 6 2 8 4 0 - * 1111 1111 1000 0000 0000 - * SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI - * Hacked for DST to: - * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI - */ - int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT | - BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT | - BT878_AFBUS | BT878_ARISCI; - - - /* ignore pesky bits */ - int_mask &= ~irq_err_ignore; - - btwrite(int_mask, BT878_AINT_MASK); - btwrite(controlreg, BT878_AGPIO_DMA_CTL); -} - -void bt878_stop(struct bt878 *bt) -{ - u32 stat; - int i = 0; - - dprintk("bt878 debug: bt878_stop\n"); - - btwrite(0, BT878_AINT_MASK); - btand(~0x13, BT878_AGPIO_DMA_CTL); - - do { - stat = btread(BT878_AINT_STAT); - if (!(stat & BT878_ARISC_EN)) - break; - i++; - } while (i < 500); - - dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n", - bt->nr, i, stat); -} - -EXPORT_SYMBOL(bt878_start); -EXPORT_SYMBOL(bt878_stop); - -/*****************************/ -/* Interrupt service routine */ -/*****************************/ - -static irqreturn_t bt878_irq(int irq, void *dev_id) -{ - u32 stat, astat, mask; - int count; - struct bt878 *bt; - - bt = (struct bt878 *) dev_id; - - count = 0; - while (1) { - stat = btread(BT878_AINT_STAT); - mask = btread(BT878_AINT_MASK); - if (!(astat = (stat & mask))) - return IRQ_NONE; /* this interrupt is not for me */ -/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */ - btwrite(astat, BT878_AINT_STAT); /* try to clear interrupt condition */ - - - if (astat & (BT878_ASCERR | BT878_AOCERR)) { - if (bt878_verbose) { - printk(KERN_INFO - "bt878(%d): irq%s%s risc_pc=%08x\n", - bt->nr, - (astat & BT878_ASCERR) ? " SCERR" : - "", - (astat & BT878_AOCERR) ? " OCERR" : - "", btread(BT878_ARISC_PC)); - } - } - if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) { - if (bt878_verbose) { - printk(KERN_INFO - "bt878(%d): irq%s%s%s risc_pc=%08x\n", - bt->nr, - (astat & BT878_APABORT) ? " PABORT" : - "", - (astat & BT878_ARIPERR) ? " RIPERR" : - "", - (astat & BT878_APPERR) ? " PPERR" : - "", btread(BT878_ARISC_PC)); - } - } - if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) { - if (bt878_verbose) { - printk(KERN_INFO - "bt878(%d): irq%s%s%s risc_pc=%08x\n", - bt->nr, - (astat & BT878_AFDSR) ? " FDSR" : "", - (astat & BT878_AFTRGT) ? " FTRGT" : - "", - (astat & BT878_AFBUS) ? " FBUS" : "", - btread(BT878_ARISC_PC)); - } - } - if (astat & BT878_ARISCI) { - bt->finished_block = (stat & BT878_ARISCS) >> 28; - tasklet_schedule(&bt->tasklet); - break; - } - count++; - if (count > 20) { - btwrite(0, BT878_AINT_MASK); - printk(KERN_ERR - "bt878(%d): IRQ lockup, cleared int mask\n", - bt->nr); - break; - } - } - return IRQ_HANDLED; -} - -int -bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp) -{ - int retval; - - retval = 0; - if (mutex_lock_interruptible(&bt->gpio_lock)) - return -ERESTARTSYS; - /* special gpio signal */ - switch (cmd) { - case DST_IG_ENABLE: - // dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable); - retval = bttv_gpio_enable(bt->bttv_nr, - mp->enb.mask, - mp->enb.enable); - break; - case DST_IG_WRITE: - // dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals); - retval = bttv_write_gpio(bt->bttv_nr, - mp->outp.mask, - mp->outp.highvals); - - break; - case DST_IG_READ: - /* read */ - retval = bttv_read_gpio(bt->bttv_nr, &mp->rd.value); - // dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value); - break; - case DST_IG_TS: - /* Set packet size */ - bt->TS_Size = mp->psize; - break; - - default: - retval = -EINVAL; - break; - } - mutex_unlock(&bt->gpio_lock); - return retval; -} - -EXPORT_SYMBOL(bt878_device_control); - -#define BROOKTREE_878_DEVICE(vend, dev, name) \ - { \ - .vendor = PCI_VENDOR_ID_BROOKTREE, \ - .device = PCI_DEVICE_ID_BROOKTREE_878, \ - .subvendor = (vend), .subdevice = (dev), \ - .driver_data = (unsigned long) name \ - } - -static struct pci_device_id bt878_pci_tbl[] __devinitdata = { - BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), - BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), - BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), - BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"), - BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"), - BROOKTREE_878_DEVICE(0x270f, 0xfc00, - "ChainTech digitop DST-1000 DVB-S"), - BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"), - BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"), - BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"), - BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"), - BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"), - BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"), - { } -}; - -MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); - -static const char * __devinit card_name(const struct pci_device_id *id) -{ - return id->driver_data ? (const char *)id->driver_data : "Unknown"; -} - -/***********************/ -/* PCI device handling */ -/***********************/ - -static int __devinit bt878_probe(struct pci_dev *dev, - const struct pci_device_id *pci_id) -{ - int result = 0; - unsigned char lat; - struct bt878 *bt; -#if defined(__powerpc__) - unsigned int cmd; -#endif - unsigned int cardid; - - printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", - bt878_num); - if (bt878_num >= BT878_MAX) { - printk(KERN_ERR "bt878: Too many devices inserted\n"); - result = -ENOMEM; - goto fail0; - } - if (pci_enable_device(dev)) - return -EIO; - - cardid = dev->subsystem_device << 16; - cardid |= dev->subsystem_vendor; - - printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n", - __func__, cardid, card_name(pci_id)); - - bt = &bt878[bt878_num]; - bt->dev = dev; - bt->nr = bt878_num; - bt->shutdown = 0; - - bt->id = dev->device; - bt->irq = dev->irq; - bt->bt878_adr = pci_resource_start(dev, 0); - if (!request_mem_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0), "bt878")) { - result = -EBUSY; - goto fail0; - } - - pci_read_config_byte(dev, PCI_CLASS_REVISION, &bt->revision); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - - - printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ", - bt878_num, bt->id, bt->revision, dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - printk("irq: %d, latency: %d, memory: 0x%lx\n", - bt->irq, lat, bt->bt878_adr); - - -#if defined(__powerpc__) - /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ - /* response on cards with no firmware is not enabled by OF */ - pci_read_config_dword(dev, PCI_COMMAND, &cmd); - cmd = (cmd | PCI_COMMAND_MEMORY); - pci_write_config_dword(dev, PCI_COMMAND, cmd); -#endif - -#ifdef __sparc__ - bt->bt878_mem = (unsigned char *) bt->bt878_adr; -#else - bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000); -#endif - - /* clear interrupt mask */ - btwrite(0, BT848_INT_MASK); - - result = request_irq(bt->irq, bt878_irq, - IRQF_SHARED | IRQF_DISABLED, "bt878", - (void *) bt); - if (result == -EINVAL) { - printk(KERN_ERR "bt878(%d): Bad irq number or handler\n", - bt878_num); - goto fail1; - } - if (result == -EBUSY) { - printk(KERN_ERR - "bt878(%d): IRQ %d busy, change your PnP config in BIOS\n", - bt878_num, bt->irq); - goto fail1; - } - if (result < 0) - goto fail1; - - pci_set_master(dev); - pci_set_drvdata(dev, bt); - - if ((result = bt878_mem_alloc(bt))) { - printk(KERN_ERR "bt878: failed to allocate memory!\n"); - goto fail2; - } - - bt878_make_risc(bt); - btwrite(0, BT878_AINT_MASK); - bt878_num++; - - return 0; - - fail2: - free_irq(bt->irq, bt); - fail1: - release_mem_region(pci_resource_start(bt->dev, 0), - pci_resource_len(bt->dev, 0)); - fail0: - pci_disable_device(dev); - return result; -} - -static void __devexit bt878_remove(struct pci_dev *pci_dev) -{ - u8 command; - struct bt878 *bt = pci_get_drvdata(pci_dev); - - if (bt878_verbose) - printk(KERN_INFO "bt878(%d): unloading\n", bt->nr); - - /* turn off all capturing, DMA and IRQs */ - btand(~0x13, BT878_AGPIO_DMA_CTL); - - /* first disable interrupts before unmapping the memory! */ - btwrite(0, BT878_AINT_MASK); - btwrite(~0U, BT878_AINT_STAT); - - /* disable PCI bus-mastering */ - pci_read_config_byte(bt->dev, PCI_COMMAND, &command); - /* Should this be &=~ ?? */ - command &= ~PCI_COMMAND_MASTER; - pci_write_config_byte(bt->dev, PCI_COMMAND, command); - - free_irq(bt->irq, bt); - printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem); - if (bt->bt878_mem) - iounmap(bt->bt878_mem); - - release_mem_region(pci_resource_start(bt->dev, 0), - pci_resource_len(bt->dev, 0)); - /* wake up any waiting processes - because shutdown flag is set, no new processes (in this queue) - are expected - */ - bt->shutdown = 1; - bt878_mem_free(bt); - - pci_set_drvdata(pci_dev, NULL); - pci_disable_device(pci_dev); - return; -} - -static struct pci_driver bt878_pci_driver = { - .name = "bt878", - .id_table = bt878_pci_tbl, - .probe = bt878_probe, - .remove = __devexit_p(bt878_remove), -}; - -/*******************************/ -/* Module management functions */ -/*******************************/ - -static int __init bt878_init_module(void) -{ - bt878_num = 0; - - printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n", - (BT878_VERSION_CODE >> 16) & 0xff, - (BT878_VERSION_CODE >> 8) & 0xff, - BT878_VERSION_CODE & 0xff); - - return pci_register_driver(&bt878_pci_driver); -} - -static void __exit bt878_cleanup_module(void) -{ - pci_unregister_driver(&bt878_pci_driver); -} - -module_init(bt878_init_module); -module_exit(bt878_cleanup_module); - -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/bt878.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/bt878.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/bt878.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/bt878.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -/* - bt878.h - Bt878 audio module (register offsets) - - Copyright (C) 2002 Peter Hettkamp - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _BT878_H_ -#define _BT878_H_ - -#include -#include -#include -#include -#include - -#include "bt848.h" -#include "bttv.h" - -#define BT878_VERSION_CODE 0x000000 - -#define BT878_AINT_STAT 0x100 -#define BT878_ARISCS (0xf<<28) -#define BT878_ARISC_EN (1<<27) -#define BT878_ASCERR (1<<19) -#define BT878_AOCERR (1<<18) -#define BT878_APABORT (1<<17) -#define BT878_ARIPERR (1<<16) -#define BT878_APPERR (1<<15) -#define BT878_AFDSR (1<<14) -#define BT878_AFTRGT (1<<13) -#define BT878_AFBUS (1<<12) -#define BT878_ARISCI (1<<11) -#define BT878_AOFLOW (1<<3) - -#define BT878_AINT_MASK 0x104 - -#define BT878_AGPIO_DMA_CTL 0x10c -#define BT878_A_GAIN (0xf<<28) -#define BT878_A_G2X (1<<27) -#define BT878_A_PWRDN (1<<26) -#define BT878_A_SEL (3<<24) -#define BT878_DA_SCE (1<<23) -#define BT878_DA_LRI (1<<22) -#define BT878_DA_MLB (1<<21) -#define BT878_DA_LRD (0x1f<<16) -#define BT878_DA_DPM (1<<15) -#define BT878_DA_SBR (1<<14) -#define BT878_DA_ES2 (1<<13) -#define BT878_DA_LMT (1<<12) -#define BT878_DA_SDR (0xf<<8) -#define BT878_DA_IOM (3<<6) -#define BT878_DA_APP (1<<5) -#define BT878_ACAP_EN (1<<4) -#define BT878_PKTP (3<<2) -#define BT878_RISC_EN (1<<1) -#define BT878_FIFO_EN 1 - -#define BT878_APACK_LEN 0x110 -#define BT878_AFP_LEN (0xff<<16) -#define BT878_ALP_LEN 0xfff - -#define BT878_ARISC_START 0x114 - -#define BT878_ARISC_PC 0x120 - -/* BT878 FUNCTION 0 REGISTERS */ -#define BT878_GPIO_DMA_CTL 0x10c - -/* Interrupt register */ -#define BT878_INT_STAT 0x100 -#define BT878_INT_MASK 0x104 -#define BT878_I2CRACK (1<<25) -#define BT878_I2CDONE (1<<8) - -#define BT878_MAX 4 - -#define BT878_RISC_SYNC_MASK (1 << 15) - - -#define BTTV_BOARD_UNKNOWN 0x00 -#define BTTV_BOARD_PINNACLESAT 0x5e -#define BTTV_BOARD_NEBULA_DIGITV 0x68 -#define BTTV_BOARD_PC_HDTV 0x70 -#define BTTV_BOARD_TWINHAN_DST 0x71 -#define BTTV_BOARD_AVDVBT_771 0x7b -#define BTTV_BOARD_AVDVBT_761 0x7c -#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 -#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 - -extern int bt878_num; - -struct bt878 { - struct mutex gpio_lock; - unsigned int nr; - unsigned int bttv_nr; - struct i2c_adapter *adapter; - struct pci_dev *dev; - unsigned int id; - unsigned int TS_Size; - unsigned char revision; - unsigned int irq; - unsigned long bt878_adr; - volatile void __iomem *bt878_mem; /* function 1 */ - - volatile u32 finished_block; - volatile u32 last_block; - u32 block_count; - u32 block_bytes; - u32 line_bytes; - u32 line_count; - - u32 buf_size; - u8 *buf_cpu; - dma_addr_t buf_dma; - - u32 risc_size; - __le32 *risc_cpu; - dma_addr_t risc_dma; - u32 risc_pos; - - struct tasklet_struct tasklet; - int shutdown; -}; - -extern struct bt878 bt878[BT878_MAX]; - -void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, - u32 irq_err_ignore); -void bt878_stop(struct bt878 *bt); - -#if defined(__powerpc__) /* big-endian */ -static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) -{ - st_le32(addr, val); - eieio(); -} - -#define bmtwrite(dat,adr) io_st_le32((adr),(dat)) -#define bmtread(adr) ld_le32((adr)) -#else -#define bmtwrite(dat,adr) writel((dat), (adr)) -#define bmtread(adr) readl(adr) -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1873 +0,0 @@ -/* - Frontend/Card driver for TwinHan DST Frontend - Copyright (C) 2003 Jamie Honan - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "dst_priv.h" -#include "dst_common.h" - -static unsigned int verbose = 1; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); - -static unsigned int dst_addons; -module_param(dst_addons, int, 0644); -MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); - -static unsigned int dst_algo; -module_param(dst_algo, int, 0644); -MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); - -#define HAS_LOCK 1 -#define ATTEMPT_TUNE 2 -#define HAS_POWER 4 - -#define DST_ERROR 0 -#define DST_NOTICE 1 -#define DST_INFO 2 -#define DST_DEBUG 3 - -#define dprintk(x, y, z, format, arg...) do { \ - if (z) { \ - if ((x > DST_ERROR) && (x > y)) \ - printk(KERN_ERR "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - else if ((x > DST_NOTICE) && (x > y)) \ - printk(KERN_NOTICE "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - else if ((x > DST_INFO) && (x > y)) \ - printk(KERN_INFO "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - else if ((x > DST_DEBUG) && (x > y)) \ - printk(KERN_DEBUG "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - } else { \ - if (x > y) \ - printk(format, ##arg); \ - } \ -} while(0) - -static int dst_command(struct dst_state *state, u8 *data, u8 len); - -static void dst_packsize(struct dst_state *state, int psize) -{ - union dst_gpio_packet bits; - - bits.psize = psize; - bt878_device_control(state->bt, DST_IG_TS, &bits); -} - -static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, - u32 outhigh, int delay) -{ - union dst_gpio_packet enb; - union dst_gpio_packet bits; - int err; - - enb.enb.mask = mask; - enb.enb.enable = enbb; - - dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh); - if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { - dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb); - return -EREMOTEIO; - } - udelay(1000); - /* because complete disabling means no output, no need to do output packet */ - if (enbb == 0) - return 0; - if (delay) - msleep(10); - bits.outp.mask = enbb; - bits.outp.highvals = outhigh; - if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { - dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh); - return -EREMOTEIO; - } - - return 0; -} - -static int dst_gpio_inb(struct dst_state *state, u8 *result) -{ - union dst_gpio_packet rd_packet; - int err; - - *result = 0; - if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err); - return -EREMOTEIO; - } - *result = (u8) rd_packet.rd.value; - - return 0; -} - -int rdc_reset_state(struct dst_state *state) -{ - dprintk(verbose, DST_INFO, 1, "Resetting state machine"); - if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - msleep(10); - if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - msleep(10); - return -1; - } - - return 0; -} -EXPORT_SYMBOL(rdc_reset_state); - -static int rdc_8820_reset(struct dst_state *state) -{ - dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); - if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - udelay(1000); - if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - - return 0; -} - -static int dst_pio_enable(struct dst_state *state) -{ - if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - udelay(1000); - - return 0; -} - -int dst_pio_disable(struct dst_state *state) -{ - if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); - return -1; - } - if (state->type_flags & DST_TYPE_HAS_FW_1) - udelay(1000); - - return 0; -} -EXPORT_SYMBOL(dst_pio_disable); - -int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) -{ - u8 reply; - int i; - - for (i = 0; i < 200; i++) { - if (dst_gpio_inb(state, &reply) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !"); - return -1; - } - if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { - dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i); - return 1; - } - msleep(10); - } - dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i); - - return 0; -} -EXPORT_SYMBOL(dst_wait_dst_ready); - -int dst_error_recovery(struct dst_state *state) -{ - dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors."); - dst_pio_disable(state); - msleep(10); - dst_pio_enable(state); - msleep(10); - - return 0; -} -EXPORT_SYMBOL(dst_error_recovery); - -int dst_error_bailout(struct dst_state *state) -{ - dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error."); - rdc_8820_reset(state); - dst_pio_disable(state); - msleep(10); - - return 0; -} -EXPORT_SYMBOL(dst_error_bailout); - -int dst_comm_init(struct dst_state *state) -{ - dprintk(verbose, DST_INFO, 1, "Initializing DST."); - if ((dst_pio_enable(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed"); - return -1; - } - if ((rdc_reset_state(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed."); - return -1; - } - if (state->type_flags & DST_TYPE_HAS_FW_1) - msleep(100); - else - msleep(5); - - return 0; -} -EXPORT_SYMBOL(dst_comm_init); - -int write_dst(struct dst_state *state, u8 *data, u8 len) -{ - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = 0, - .buf = data, - .len = len - }; - - int err; - u8 cnt, i; - - dprintk(verbose, DST_NOTICE, 0, "writing [ "); - for (i = 0; i < len; i++) - dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]); - dprintk(verbose, DST_NOTICE, 0, "]\n"); - - for (cnt = 0; cnt < 2; cnt++) { - if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]); - dst_error_recovery(state); - continue; - } else - break; - } - if (cnt >= 2) { - dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); - dst_error_bailout(state); - - return -1; - } - - return 0; -} -EXPORT_SYMBOL(write_dst); - -int read_dst(struct dst_state *state, u8 *ret, u8 len) -{ - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = ret, - .len = len - }; - - int err; - int cnt; - - for (cnt = 0; cnt < 2; cnt++) { - if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]); - dst_error_recovery(state); - continue; - } else - break; - } - if (cnt >= 2) { - dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); - dst_error_bailout(state); - - return -1; - } - dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]); - for (err = 1; err < len; err++) - dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]); - if (err > 1) - dprintk(verbose, DST_DEBUG, 0, "\n"); - - return 0; -} -EXPORT_SYMBOL(read_dst); - -static int dst_set_polarization(struct dst_state *state) -{ - switch (state->voltage) { - case SEC_VOLTAGE_13: /* Vertical */ - dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]"); - state->tx_tuna[8] &= ~0x40; - break; - case SEC_VOLTAGE_18: /* Horizontal */ - dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]"); - state->tx_tuna[8] |= 0x40; - break; - case SEC_VOLTAGE_OFF: - break; - } - - return 0; -} - -static int dst_set_freq(struct dst_state *state, u32 freq) -{ - state->frequency = freq; - dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq); - - if (state->dst_type == DST_TYPE_IS_SAT) { - freq = freq / 1000; - if (freq < 950 || freq > 2150) - return -EINVAL; - state->tx_tuna[2] = (freq >> 8); - state->tx_tuna[3] = (u8) freq; - state->tx_tuna[4] = 0x01; - state->tx_tuna[8] &= ~0x04; - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { - if (freq < 1531) - state->tx_tuna[8] |= 0x04; - } - } else if (state->dst_type == DST_TYPE_IS_TERR) { - freq = freq / 1000; - if (freq < 137000 || freq > 858000) - return -EINVAL; - state->tx_tuna[2] = (freq >> 16) & 0xff; - state->tx_tuna[3] = (freq >> 8) & 0xff; - state->tx_tuna[4] = (u8) freq; - } else if (state->dst_type == DST_TYPE_IS_CABLE) { - freq = freq / 1000; - state->tx_tuna[2] = (freq >> 16) & 0xff; - state->tx_tuna[3] = (freq >> 8) & 0xff; - state->tx_tuna[4] = (u8) freq; - } else if (state->dst_type == DST_TYPE_IS_ATSC) { - freq = freq / 1000; - if (freq < 51000 || freq > 858000) - return -EINVAL; - state->tx_tuna[2] = (freq >> 16) & 0xff; - state->tx_tuna[3] = (freq >> 8) & 0xff; - state->tx_tuna[4] = (u8) freq; - state->tx_tuna[5] = 0x00; /* ATSC */ - state->tx_tuna[6] = 0x00; - if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG) - state->tx_tuna[7] = 0x00; /* Digital */ - } else - return -EINVAL; - - return 0; -} - -static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) -{ - state->bandwidth = bandwidth; - - if (state->dst_type != DST_TYPE_IS_TERR) - return -EOPNOTSUPP; - - switch (bandwidth) { - case BANDWIDTH_6_MHZ: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x06; - else { - state->tx_tuna[6] = 0x06; - state->tx_tuna[7] = 0x00; - } - break; - case BANDWIDTH_7_MHZ: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x07; - else { - state->tx_tuna[6] = 0x07; - state->tx_tuna[7] = 0x00; - } - break; - case BANDWIDTH_8_MHZ: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x08; - else { - state->tx_tuna[6] = 0x08; - state->tx_tuna[7] = 0x00; - } - break; - default: - return -EINVAL; - } - - return 0; -} - -static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) -{ - state->inversion = inversion; - switch (inversion) { - case INVERSION_OFF: /* Inversion = Normal */ - state->tx_tuna[8] &= ~0x80; - break; - case INVERSION_ON: - state->tx_tuna[8] |= 0x80; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) -{ - state->fec = fec; - return 0; -} - -static fe_code_rate_t dst_get_fec(struct dst_state *state) -{ - return state->fec; -} - -static int dst_set_symbolrate(struct dst_state *state, u32 srate) -{ - u32 symcalc; - u64 sval; - - state->symbol_rate = srate; - if (state->dst_type == DST_TYPE_IS_TERR) { - return -EOPNOTSUPP; - } - dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); - srate /= 1000; - if (state->dst_type == DST_TYPE_IS_SAT) { - if (state->type_flags & DST_TYPE_HAS_SYMDIV) { - sval = srate; - sval <<= 20; - do_div(sval, 88000); - symcalc = (u32) sval; - dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); - state->tx_tuna[5] = (u8) (symcalc >> 12); - state->tx_tuna[6] = (u8) (symcalc >> 4); - state->tx_tuna[7] = (u8) (symcalc << 4); - } else { - state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; - state->tx_tuna[6] = (u8) (srate >> 8); - state->tx_tuna[7] = (u8) srate; - } - state->tx_tuna[8] &= ~0x20; - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { - if (srate > 8000) - state->tx_tuna[8] |= 0x20; - } - } else if (state->dst_type == DST_TYPE_IS_CABLE) { - dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name); - if (!strncmp(state->fw_name, "DCTNEW", 6)) { - state->tx_tuna[5] = (u8) (srate >> 8); - state->tx_tuna[6] = (u8) srate; - state->tx_tuna[7] = 0x00; - } else if (!strncmp(state->fw_name, "DCT-CI", 6)) { - state->tx_tuna[5] = 0x00; - state->tx_tuna[6] = (u8) (srate >> 8); - state->tx_tuna[7] = (u8) srate; - } - } - return 0; -} - -static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) -{ - if (state->dst_type != DST_TYPE_IS_CABLE) - return -EOPNOTSUPP; - - state->modulation = modulation; - switch (modulation) { - case QAM_16: - state->tx_tuna[8] = 0x10; - break; - case QAM_32: - state->tx_tuna[8] = 0x20; - break; - case QAM_64: - state->tx_tuna[8] = 0x40; - break; - case QAM_128: - state->tx_tuna[8] = 0x80; - break; - case QAM_256: - if (!strncmp(state->fw_name, "DCTNEW", 6)) - state->tx_tuna[8] = 0xff; - else if (!strncmp(state->fw_name, "DCT-CI", 6)) - state->tx_tuna[8] = 0x00; - break; - case QPSK: - case QAM_AUTO: - case VSB_8: - case VSB_16: - default: - return -EINVAL; - - } - - return 0; -} - -static fe_modulation_t dst_get_modulation(struct dst_state *state) -{ - return state->modulation; -} - - -u8 dst_check_sum(u8 *buf, u32 len) -{ - u32 i; - u8 val = 0; - if (!len) - return 0; - for (i = 0; i < len; i++) { - val += buf[i]; - } - return ((~val) + 1); -} -EXPORT_SYMBOL(dst_check_sum); - -static void dst_type_flags_print(struct dst_state *state) -{ - u32 type_flags = state->type_flags; - - dprintk(verbose, DST_ERROR, 0, "DST type flags :"); - if (type_flags & DST_TYPE_HAS_TS188) - dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188); - if (type_flags & DST_TYPE_HAS_NEWTUNE_2) - dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2); - if (type_flags & DST_TYPE_HAS_TS204) - dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); - if (type_flags & DST_TYPE_HAS_VLF) - dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF); - if (type_flags & DST_TYPE_HAS_SYMDIV) - dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); - if (type_flags & DST_TYPE_HAS_FW_1) - dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); - if (type_flags & DST_TYPE_HAS_FW_2) - dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); - if (type_flags & DST_TYPE_HAS_FW_3) - dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); - dprintk(verbose, DST_ERROR, 0, "\n"); -} - - -static int dst_type_print(struct dst_state *state, u8 type) -{ - char *otype; - switch (type) { - case DST_TYPE_IS_SAT: - otype = "satellite"; - break; - - case DST_TYPE_IS_TERR: - otype = "terrestrial"; - break; - - case DST_TYPE_IS_CABLE: - otype = "cable"; - break; - - case DST_TYPE_IS_ATSC: - otype = "atsc"; - break; - - default: - dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); - return -EINVAL; - } - dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); - - return 0; -} - -static struct tuner_types tuner_list[] = { - { - .tuner_type = TUNER_TYPE_L64724, - .tuner_name = "L 64724", - .board_name = "UNKNOWN", - .fw_name = "UNKNOWN" - }, - - { - .tuner_type = TUNER_TYPE_STV0299, - .tuner_name = "STV 0299", - .board_name = "VP1020", - .fw_name = "DST-MOT" - }, - - { - .tuner_type = TUNER_TYPE_STV0299, - .tuner_name = "STV 0299", - .board_name = "VP1020", - .fw_name = "DST-03T" - }, - - { - .tuner_type = TUNER_TYPE_MB86A15, - .tuner_name = "MB 86A15", - .board_name = "VP1022", - .fw_name = "DST-03T" - }, - - { - .tuner_type = TUNER_TYPE_MB86A15, - .tuner_name = "MB 86A15", - .board_name = "VP1025", - .fw_name = "DST-03T" - }, - - { - .tuner_type = TUNER_TYPE_STV0299, - .tuner_name = "STV 0299", - .board_name = "VP1030", - .fw_name = "DST-CI" - }, - - { - .tuner_type = TUNER_TYPE_STV0299, - .tuner_name = "STV 0299", - .board_name = "VP1030", - .fw_name = "DSTMCI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP2021", - .fw_name = "DCTNEW" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP2030", - .fw_name = "DCT-CI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP2031", - .fw_name = "DCT-CI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP2040", - .fw_name = "DCT-CI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP3020", - .fw_name = "DTTFTA" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP3021", - .fw_name = "DTTFTA" - }, - - { - .tuner_type = TUNER_TYPE_TDA10046, - .tuner_name = "TDA10046", - .board_name = "VP3040", - .fw_name = "DTT-CI" - }, - - { - .tuner_type = TUNER_TYPE_UNKNOWN, - .tuner_name = "UNKNOWN", - .board_name = "VP3051", - .fw_name = "DTTNXT" - }, - - { - .tuner_type = TUNER_TYPE_NXT200x, - .tuner_name = "NXT200x", - .board_name = "VP3220", - .fw_name = "ATSCDI" - }, - - { - .tuner_type = TUNER_TYPE_NXT200x, - .tuner_name = "NXT200x", - .board_name = "VP3250", - .fw_name = "ATSCAD" - }, -}; - -/* - Known cards list - Satellite - ------------------- - 200103A - VP-1020 DST-MOT LG(old), TS=188 - - VP-1020 DST-03T LG(new), TS=204 - VP-1022 DST-03T LG(new), TS=204 - VP-1025 DST-03T LG(new), TS=204 - - VP-1030 DSTMCI, LG(new), TS=188 - VP-1032 DSTMCI, LG(new), TS=188 - - Cable - ------------------- - VP-2030 DCT-CI, Samsung, TS=204 - VP-2021 DCT-CI, Unknown, TS=204 - VP-2031 DCT-CI, Philips, TS=188 - VP-2040 DCT-CI, Philips, TS=188, with CA daughter board - VP-2040 DCT-CI, Philips, TS=204, without CA daughter board - - Terrestrial - ------------------- - VP-3050 DTTNXT TS=188 - VP-3040 DTT-CI, Philips, TS=188 - VP-3040 DTT-CI, Philips, TS=204 - - ATSC - ------------------- - VP-3220 ATSCDI, TS=188 - VP-3250 ATSCAD, TS=188 - -*/ - -static struct dst_types dst_tlist[] = { - { - .device_id = "200103A", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, - .dst_feature = 0, - .tuner_type = 0 - }, /* obsolete */ - - { - .device_id = "DST-020", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, - .dst_feature = 0, - .tuner_type = 0 - }, /* obsolete */ - - { - .device_id = "DST-030", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, - .dst_feature = 0, - .tuner_type = 0 - }, /* obsolete */ - - { - .device_id = "DST-03T", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, - .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 - | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO, - .tuner_type = TUNER_TYPE_MULTI - }, - - { - .device_id = "DST-MOT", - .offset = 0, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, - .dst_feature = 0, - .tuner_type = 0 - }, /* obsolete */ - - { - .device_id = "DST-CI", - .offset = 1, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1, - .dst_feature = DST_TYPE_HAS_CA, - .tuner_type = 0 - }, /* An OEM board */ - - { - .device_id = "DSTMCI", - .offset = 1, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF, - .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 - | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC, - .tuner_type = TUNER_TYPE_MULTI - }, - - { - .device_id = "DSTFCI", - .offset = 1, - .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, - .dst_feature = 0, - .tuner_type = 0 - }, /* unknown to vendor */ - - { - .device_id = "DCT-CI", - .offset = 1, - .dst_type = DST_TYPE_IS_CABLE, - .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF, - .dst_feature = DST_TYPE_HAS_CA, - .tuner_type = 0 - }, - - { - .device_id = "DCTNEW", - .offset = 1, - .dst_type = DST_TYPE_IS_CABLE, - .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE, - .dst_feature = 0, - .tuner_type = 0 - }, - - { - .device_id = "DTT-CI", - .offset = 1, - .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF, - .dst_feature = DST_TYPE_HAS_CA, - .tuner_type = 0 - }, - - { - .device_id = "DTTDIG", - .offset = 1, - .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = 0, - .tuner_type = 0 - }, - - { - .device_id = "DTTNXT", - .offset = 1, - .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = DST_TYPE_HAS_ANALOG, - .tuner_type = 0 - }, - - { - .device_id = "ATSCDI", - .offset = 1, - .dst_type = DST_TYPE_IS_ATSC, - .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = 0, - .tuner_type = 0 - }, - - { - .device_id = "ATSCAD", - .offset = 1, - .dst_type = DST_TYPE_IS_ATSC, - .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, - .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG, - .tuner_type = 0 - }, - - { } - -}; - -static int dst_get_mac(struct dst_state *state) -{ - u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - get_mac[7] = dst_check_sum(get_mac, 7); - if (dst_command(state, get_mac, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; - } - memset(&state->mac_address, '\0', 8); - memcpy(&state->mac_address, &state->rxbuffer, 6); - dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address); - - return 0; -} - -static int dst_fw_ver(struct dst_state *state) -{ - u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - get_ver[7] = dst_check_sum(get_ver, 7); - if (dst_command(state, get_ver, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; - } - memcpy(&state->fw_version, &state->rxbuffer, 8); - dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", - state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, - state->fw_version[1], - state->fw_version[5], state->fw_version[6], - state->fw_version[4], state->fw_version[3], state->fw_version[2]); - - return 0; -} - -static int dst_card_type(struct dst_state *state) -{ - int j; - struct tuner_types *p_tuner_list = NULL; - - u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - get_type[7] = dst_check_sum(get_type, 7); - if (dst_command(state, get_type, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; - } - memset(&state->card_info, '\0', 8); - memcpy(&state->card_info, &state->rxbuffer, 7); - dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); - - for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { - if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) { - state->tuner_type = p_tuner_list->tuner_type; - dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]", - p_tuner_list->tuner_name, p_tuner_list->tuner_type); - } - } - - return 0; -} - -static int dst_get_vendor(struct dst_state *state) -{ - u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - get_vendor[7] = dst_check_sum(get_vendor, 7); - if (dst_command(state, get_vendor, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; - } - memset(&state->vendor, '\0', 8); - memcpy(&state->vendor, &state->rxbuffer, 7); - dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); - - return 0; -} - -static void debug_dst_buffer(struct dst_state *state) -{ - int i; - - if (verbose > 2) { - printk("%s: [", __func__); - for (i = 0; i < 8; i++) - printk(" %02x", state->rxbuffer[i]); - printk("]\n"); - } -} - -static int dst_check_stv0299(struct dst_state *state) -{ - u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - check_stv0299[7] = dst_check_sum(check_stv0299, 7); - if (dst_command(state, check_stv0299, 8) < 0) { - dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed"); - return -1; - } - debug_dst_buffer(state); - - if (memcmp(&check_stv0299, &state->rxbuffer, 8)) { - dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM"); - state->tuner_type = TUNER_TYPE_STV0299; - return 0; - } - - return -1; -} - -static int dst_check_mb86a15(struct dst_state *state) -{ - u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - check_mb86a15[7] = dst_check_sum(check_mb86a15, 7); - if (dst_command(state, check_mb86a15, 8) < 0) { - dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed"); - return -1; - } - debug_dst_buffer(state); - - if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) { - dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM"); - state->tuner_type = TUNER_TYPE_MB86A15; - return 0; - } - - return -1; -} - -static int dst_get_tuner_info(struct dst_state *state) -{ - u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); - get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); - dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE"); - if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { - if (dst_command(state, get_tuner_1, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported"); - goto force; - } - } else { - if (dst_command(state, get_tuner_2, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported"); - goto force; - } - } - memcpy(&state->board_info, &state->rxbuffer, 8); - if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { - dprintk(verbose, DST_ERROR, 1, "DST type has TS=188"); - } - if (state->board_info[0] == 0xbc) { - if (state->dst_type != DST_TYPE_IS_ATSC) - state->type_flags |= DST_TYPE_HAS_TS188; - else - state->type_flags |= DST_TYPE_HAS_NEWTUNE_2; - - if (state->board_info[1] == 0x01) { - state->dst_hw_cap |= DST_TYPE_HAS_DBOARD; - dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard"); - } - } - - return 0; -force: - if (!strncmp(state->fw_name, "DCT-CI", 6)) { - state->type_flags |= DST_TYPE_HAS_TS204; - dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name); - } - - return -1; -} - -static int dst_get_device_id(struct dst_state *state) -{ - u8 reply; - - int i, j; - struct dst_types *p_dst_type = NULL; - struct tuner_types *p_tuner_list = NULL; - - u8 use_dst_type = 0; - u32 use_type_flags = 0; - - static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; - - state->tuner_type = 0; - device_type[7] = dst_check_sum(device_type, 7); - - if (write_dst(state, device_type, FIXED_COMM)) - return -1; /* Write failed */ - if ((dst_pio_disable(state)) < 0) - return -1; - if (read_dst(state, &reply, GET_ACK)) - return -1; /* Read failure */ - if (reply != ACK) { - dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); - return -1; /* Unack'd write */ - } - if (!dst_wait_dst_ready(state, DEVICE_INIT)) - return -1; /* DST not ready yet */ - if (read_dst(state, state->rxbuffer, FIXED_COMM)) - return -1; - - dst_pio_disable(state); - if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk(verbose, DST_INFO, 1, "Checksum failure!"); - return -1; /* Checksum failure */ - } - state->rxbuffer[7] = '\0'; - - for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { - if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { - use_type_flags = p_dst_type->type_flags; - use_dst_type = p_dst_type->dst_type; - - /* Card capabilities */ - state->dst_hw_cap = p_dst_type->dst_feature; - dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id); - strncpy(&state->fw_name[0], p_dst_type->device_id, 6); - /* Multiple tuners */ - if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { - switch (use_dst_type) { - case DST_TYPE_IS_SAT: - /* STV0299 check */ - if (dst_check_stv0299(state) < 0) { - dprintk(verbose, DST_ERROR, 1, "Unsupported"); - state->tuner_type = TUNER_TYPE_MB86A15; - } - break; - default: - break; - } - if (dst_check_mb86a15(state) < 0) - dprintk(verbose, DST_ERROR, 1, "Unsupported"); - /* Single tuner */ - } else { - state->tuner_type = p_dst_type->tuner_type; - } - for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { - if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) && - p_tuner_list->tuner_type == state->tuner_type) { - dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]", - p_dst_type->device_id, p_tuner_list->tuner_name); - } - } - break; - } - } - - if (i >= ARRAY_SIZE(dst_tlist)) { - dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); - dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); - use_dst_type = DST_TYPE_IS_SAT; - use_type_flags = DST_TYPE_HAS_SYMDIV; - } - dst_type_print(state, use_dst_type); - state->type_flags = use_type_flags; - state->dst_type = use_dst_type; - dst_type_flags_print(state); - - return 0; -} - -static int dst_probe(struct dst_state *state) -{ - mutex_init(&state->dst_mutex); - if (dst_addons & DST_TYPE_HAS_CA) { - if ((rdc_8820_reset(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); - return -1; - } - msleep(4000); - } else { - msleep(100); - } - if ((dst_comm_init(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); - return -1; - } - msleep(100); - if (dst_get_device_id(state) < 0) { - dprintk(verbose, DST_ERROR, 1, "unknown device."); - return -1; - } - if (dst_get_mac(state) < 0) { - dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); - } - if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { - if (dst_get_tuner_info(state) < 0) - dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command"); - } - if (state->type_flags & DST_TYPE_HAS_TS204) { - dst_packsize(state, 204); - } - if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { - if (dst_fw_ver(state) < 0) { - dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); - return 0; - } - if (dst_card_type(state) < 0) { - dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); - return 0; - } - if (dst_get_vendor(state) < 0) { - dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); - return 0; - } - } - - return 0; -} - -static int dst_command(struct dst_state *state, u8 *data, u8 len) -{ - u8 reply; - - mutex_lock(&state->dst_mutex); - if ((dst_comm_init(state)) < 0) { - dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); - goto error; - } - if (write_dst(state, data, len)) { - dprintk(verbose, DST_INFO, 1, "Trying to recover.. "); - if ((dst_error_recovery(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); - goto error; - } - goto error; - } - if ((dst_pio_disable(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); - goto error; - } - if (state->type_flags & DST_TYPE_HAS_FW_1) - mdelay(3); - if (read_dst(state, &reply, GET_ACK)) { - dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); - if ((dst_error_recovery(state)) < 0) { - dprintk(verbose, DST_INFO, 1, "Recovery Failed."); - goto error; - } - goto error; - } - if (reply != ACK) { - dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); - goto error; - } - if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) - goto error; - if (state->type_flags & DST_TYPE_HAS_FW_1) - mdelay(3); - else - udelay(2000); - if (!dst_wait_dst_ready(state, NO_DELAY)) - goto error; - if (read_dst(state, state->rxbuffer, FIXED_COMM)) { - dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); - if ((dst_error_recovery(state)) < 0) { - dprintk(verbose, DST_INFO, 1, "Recovery failed."); - goto error; - } - goto error; - } - if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk(verbose, DST_INFO, 1, "checksum failure"); - goto error; - } - mutex_unlock(&state->dst_mutex); - return 0; - -error: - mutex_unlock(&state->dst_mutex); - return -EIO; - -} - -static int dst_get_signal(struct dst_state *state) -{ - int retval; - u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - //dprintk("%s: Getting Signal strength and other parameters\n", __func__); - if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { - state->decode_lock = state->decode_strength = state->decode_snr = 0; - return 0; - } - if (0 == (state->diseq_flags & HAS_LOCK)) { - state->decode_lock = state->decode_strength = state->decode_snr = 0; - return 0; - } - if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { - retval = dst_command(state, get_signal, 8); - if (retval < 0) - return retval; - if (state->dst_type == DST_TYPE_IS_SAT) { - state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; - state->decode_strength = state->rxbuffer[5] << 8; - state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; - } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { - state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; - state->decode_strength = state->rxbuffer[4] << 8; - state->decode_snr = state->rxbuffer[3] << 8; - } else if (state->dst_type == DST_TYPE_IS_ATSC) { - state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0; - state->decode_strength = state->rxbuffer[4] << 8; - state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; - } - state->cur_jiff = jiffies; - } - return 0; -} - -static int dst_tone_power_cmd(struct dst_state *state) -{ - u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; - - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - paket[4] = state->tx_tuna[4]; - paket[2] = state->tx_tuna[2]; - paket[3] = state->tx_tuna[3]; - paket[7] = dst_check_sum (paket, 7); - return dst_command(state, paket, 8); -} - -static int dst_get_tuna(struct dst_state *state) -{ - int retval; - - if ((state->diseq_flags & ATTEMPT_TUNE) == 0) - return 0; - state->diseq_flags &= ~(HAS_LOCK); - if (!dst_wait_dst_ready(state, NO_DELAY)) - return -EIO; - if ((state->type_flags & DST_TYPE_HAS_VLF) && - !(state->dst_type == DST_TYPE_IS_ATSC)) - - retval = read_dst(state, state->rx_tuna, 10); - else - retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); - if (retval < 0) { - dprintk(verbose, DST_DEBUG, 1, "read not successful"); - return retval; - } - if ((state->type_flags & DST_TYPE_HAS_VLF) && - !(state->dst_type == DST_TYPE_IS_ATSC)) { - - if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { - dprintk(verbose, DST_INFO, 1, "checksum failure ? "); - return -EIO; - } - } else { - if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { - dprintk(verbose, DST_INFO, 1, "checksum failure? "); - return -EIO; - } - } - if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) - return 0; - if (state->dst_type == DST_TYPE_IS_SAT) { - state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; - } else { - state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4]; - } - state->decode_freq = state->decode_freq * 1000; - state->decode_lock = 1; - state->diseq_flags |= HAS_LOCK; - - return 1; -} - -static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); - -static int dst_write_tuna(struct dvb_frontend *fe) -{ - struct dst_state *state = fe->demodulator_priv; - int retval; - u8 reply; - - dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); - state->decode_freq = 0; - state->decode_lock = state->decode_strength = state->decode_snr = 0; - if (state->dst_type == DST_TYPE_IS_SAT) { - if (!(state->diseq_flags & HAS_POWER)) - dst_set_voltage(fe, SEC_VOLTAGE_13); - } - state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); - mutex_lock(&state->dst_mutex); - if ((dst_comm_init(state)) < 0) { - dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); - goto error; - } -// if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { - if ((state->type_flags & DST_TYPE_HAS_VLF) && - (!(state->dst_type == DST_TYPE_IS_ATSC))) { - - state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); - retval = write_dst(state, &state->tx_tuna[0], 10); - } else { - state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); - retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); - } - if (retval < 0) { - dst_pio_disable(state); - dprintk(verbose, DST_DEBUG, 1, "write not successful"); - goto werr; - } - if ((dst_pio_disable(state)) < 0) { - dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); - goto error; - } - if ((read_dst(state, &reply, GET_ACK) < 0)) { - dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); - goto error; - } - if (reply != ACK) { - dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); - goto error; - } - state->diseq_flags |= ATTEMPT_TUNE; - retval = dst_get_tuna(state); -werr: - mutex_unlock(&state->dst_mutex); - return retval; - -error: - mutex_unlock(&state->dst_mutex); - return -EIO; -} - -/* - * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 - * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 - * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 - * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 - * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 - * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 - * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 - * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec - * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 - * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 - * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 - */ - -static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) -{ - struct dst_state *state = fe->demodulator_priv; - u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; - - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - if (cmd->msg_len > 0 && cmd->msg_len < 5) - memcpy(&paket[3], cmd->msg, cmd->msg_len); - else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5) - memcpy(&paket[2], cmd->msg, cmd->msg_len); - else - return -EINVAL; - paket[7] = dst_check_sum(&paket[0], 7); - return dst_command(state, paket, 8); -} - -static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - int need_cmd, retval = 0; - struct dst_state *state = fe->demodulator_priv; - - state->voltage = voltage; - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - - need_cmd = 0; - - switch (voltage) { - case SEC_VOLTAGE_13: - case SEC_VOLTAGE_18: - if ((state->diseq_flags & HAS_POWER) == 0) - need_cmd = 1; - state->diseq_flags |= HAS_POWER; - state->tx_tuna[4] = 0x01; - break; - case SEC_VOLTAGE_OFF: - need_cmd = 1; - state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); - state->tx_tuna[4] = 0x00; - break; - default: - return -EINVAL; - } - - if (need_cmd) - retval = dst_tone_power_cmd(state); - - return retval; -} - -static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct dst_state *state = fe->demodulator_priv; - - state->tone = tone; - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - - switch (tone) { - case SEC_TONE_OFF: - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - state->tx_tuna[2] = 0x00; - else - state->tx_tuna[2] = 0xff; - break; - - case SEC_TONE_ON: - state->tx_tuna[2] = 0x02; - break; - default: - return -EINVAL; - } - return dst_tone_power_cmd(state); -} - -static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) -{ - struct dst_state *state = fe->demodulator_priv; - - if (state->dst_type != DST_TYPE_IS_SAT) - return -EOPNOTSUPP; - state->minicmd = minicmd; - switch (minicmd) { - case SEC_MINI_A: - state->tx_tuna[3] = 0x02; - break; - case SEC_MINI_B: - state->tx_tuna[3] = 0xff; - break; - } - return dst_tone_power_cmd(state); -} - - -static int dst_init(struct dvb_frontend *fe) -{ - struct dst_state *state = fe->demodulator_priv; - - static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; - static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; - static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - - state->inversion = INVERSION_OFF; - state->voltage = SEC_VOLTAGE_13; - state->tone = SEC_TONE_OFF; - state->diseq_flags = 0; - state->k22 = 0x02; - state->bandwidth = BANDWIDTH_7_MHZ; - state->cur_jiff = jiffies; - if (state->dst_type == DST_TYPE_IS_SAT) - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); - else if (state->dst_type == DST_TYPE_IS_TERR) - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); - else if (state->dst_type == DST_TYPE_IS_CABLE) - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); - else if (state->dst_type == DST_TYPE_IS_ATSC) - memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner)); - - return 0; -} - -static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct dst_state *state = fe->demodulator_priv; - - *status = 0; - if (state->diseq_flags & HAS_LOCK) { -// dst_get_signal(state); // don't require(?) to ask MCU - if (state->decode_lock) - *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; - } - - return 0; -} - -static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct dst_state *state = fe->demodulator_priv; - - int retval = dst_get_signal(state); - *strength = state->decode_strength; - - return retval; -} - -static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct dst_state *state = fe->demodulator_priv; - - int retval = dst_get_signal(state); - *snr = state->decode_snr; - - return retval; -} - -static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - int retval = -EINVAL; - struct dst_state *state = fe->demodulator_priv; - - if (p != NULL) { - retval = dst_set_freq(state, p->frequency); - if(retval != 0) - return retval; - dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); - - if (state->dst_type == DST_TYPE_IS_SAT) { - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->u.qpsk.fec_inner); - dst_set_symbolrate(state, p->u.qpsk.symbol_rate); - dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); - - } else if (state->dst_type == DST_TYPE_IS_TERR) - dst_set_bandwidth(state, p->u.ofdm.bandwidth); - else if (state->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(state, p->u.qam.fec_inner); - dst_set_symbolrate(state, p->u.qam.symbol_rate); - dst_set_modulation(state, p->u.qam.modulation); - } - retval = dst_write_tuna(fe); - } - - return retval; -} - -static int dst_tune_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters* p, - unsigned int mode_flags, - unsigned int *delay, - fe_status_t *status) -{ - struct dst_state *state = fe->demodulator_priv; - - if (p != NULL) { - dst_set_freq(state, p->frequency); - dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); - - if (state->dst_type == DST_TYPE_IS_SAT) { - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->u.qpsk.fec_inner); - dst_set_symbolrate(state, p->u.qpsk.symbol_rate); - dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); - - } else if (state->dst_type == DST_TYPE_IS_TERR) - dst_set_bandwidth(state, p->u.ofdm.bandwidth); - else if (state->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(state, p->u.qam.fec_inner); - dst_set_symbolrate(state, p->u.qam.symbol_rate); - dst_set_modulation(state, p->u.qam.modulation); - } - dst_write_tuna(fe); - } - - if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) - dst_read_status(fe, status); - - *delay = HZ/10; - return 0; -} - -static int dst_get_tuning_algo(struct dvb_frontend *fe) -{ - return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; -} - -static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - struct dst_state *state = fe->demodulator_priv; - - p->frequency = state->decode_freq; - if (state->dst_type == DST_TYPE_IS_SAT) { - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - p->inversion = state->inversion; - p->u.qpsk.symbol_rate = state->symbol_rate; - p->u.qpsk.fec_inner = dst_get_fec(state); - } else if (state->dst_type == DST_TYPE_IS_TERR) { - p->u.ofdm.bandwidth = state->bandwidth; - } else if (state->dst_type == DST_TYPE_IS_CABLE) { - p->u.qam.symbol_rate = state->symbol_rate; - p->u.qam.fec_inner = dst_get_fec(state); - p->u.qam.modulation = dst_get_modulation(state); - } - - return 0; -} - -static void dst_release(struct dvb_frontend *fe) -{ - struct dst_state *state = fe->demodulator_priv; - if (state->dst_ca) { - dvb_unregister_device(state->dst_ca); -#ifdef CONFIG_MEDIA_ATTACH - symbol_put(dst_ca_attach); -#endif - } - kfree(state); -} - -static struct dvb_frontend_ops dst_dvbt_ops; -static struct dvb_frontend_ops dst_dvbs_ops; -static struct dvb_frontend_ops dst_dvbc_ops; -static struct dvb_frontend_ops dst_atsc_ops; - -struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) -{ - /* check if the ASIC is there */ - if (dst_probe(state) < 0) { - kfree(state); - return NULL; - } - /* determine settings based on type */ - /* create dvb_frontend */ - switch (state->dst_type) { - case DST_TYPE_IS_TERR: - memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); - break; - case DST_TYPE_IS_CABLE: - memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); - break; - case DST_TYPE_IS_SAT: - memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); - break; - case DST_TYPE_IS_ATSC: - memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops)); - break; - default: - dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); - kfree(state); - return NULL; - } - state->frontend.demodulator_priv = state; - - return state; /* Manu (DST is a card not a frontend) */ -} - -EXPORT_SYMBOL(dst_attach); - -static struct dvb_frontend_ops dst_dvbt_ops = { - - .info = { - .name = "DST DVB-T", - .type = FE_OFDM, - .frequency_min = 137000000, - .frequency_max = 858000000, - .frequency_stepsize = 166667, - .caps = FE_CAN_FEC_AUTO | - FE_CAN_QAM_AUTO | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO - }, - - .release = dst_release, - .init = dst_init, - .tune = dst_tune_frontend, - .set_frontend = dst_set_frontend, - .get_frontend = dst_get_frontend, - .get_frontend_algo = dst_get_tuning_algo, - .read_status = dst_read_status, - .read_signal_strength = dst_read_signal_strength, - .read_snr = dst_read_snr, -}; - -static struct dvb_frontend_ops dst_dvbs_ops = { - - .info = { - .name = "DST DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1000, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - /* . symbol_rate_tolerance = ???,*/ - .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK - }, - - .release = dst_release, - .init = dst_init, - .tune = dst_tune_frontend, - .set_frontend = dst_set_frontend, - .get_frontend = dst_get_frontend, - .get_frontend_algo = dst_get_tuning_algo, - .read_status = dst_read_status, - .read_signal_strength = dst_read_signal_strength, - .read_snr = dst_read_snr, - .diseqc_send_burst = dst_send_burst, - .diseqc_send_master_cmd = dst_set_diseqc, - .set_voltage = dst_set_voltage, - .set_tone = dst_set_tone, -}; - -static struct dvb_frontend_ops dst_dvbc_ops = { - - .info = { - .name = "DST DVB-C", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_FEC_AUTO | - FE_CAN_QAM_AUTO | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 - }, - - .release = dst_release, - .init = dst_init, - .tune = dst_tune_frontend, - .set_frontend = dst_set_frontend, - .get_frontend = dst_get_frontend, - .get_frontend_algo = dst_get_tuning_algo, - .read_status = dst_read_status, - .read_signal_strength = dst_read_signal_strength, - .read_snr = dst_read_snr, -}; - -static struct dvb_frontend_ops dst_atsc_ops = { - .info = { - .name = "DST ATSC", - .type = FE_ATSC, - .frequency_stepsize = 62500, - .frequency_min = 510000000, - .frequency_max = 858000000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - - .release = dst_release, - .init = dst_init, - .tune = dst_tune_frontend, - .set_frontend = dst_set_frontend, - .get_frontend = dst_get_frontend, - .get_frontend_algo = dst_get_tuning_algo, - .read_status = dst_read_status, - .read_signal_strength = dst_read_signal_strength, - .read_snr = dst_read_snr, -}; - -MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver"); -MODULE_AUTHOR("Jamie Honan, Manu Abraham"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_ca.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_ca.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_ca.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_ca.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,727 +0,0 @@ -/* - CA-driver for TwinHan DST Frontend/Card - - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "dvbdev.h" -#include "dvb_frontend.h" -#include "dst_ca.h" -#include "dst_common.h" - -#define DST_CA_ERROR 0 -#define DST_CA_NOTICE 1 -#define DST_CA_INFO 2 -#define DST_CA_DEBUG 3 - -#define dprintk(x, y, z, format, arg...) do { \ - if (z) { \ - if ((x > DST_CA_ERROR) && (x > y)) \ - printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ - else if ((x > DST_CA_NOTICE) && (x > y)) \ - printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ - else if ((x > DST_CA_INFO) && (x > y)) \ - printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ - else if ((x > DST_CA_DEBUG) && (x > y)) \ - printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ - } else { \ - if (x > y) \ - printk(format, ## arg); \ - } \ -} while(0) - - -static DEFINE_MUTEX(dst_ca_mutex); -static unsigned int verbose = 5; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); - -/* Need some more work */ -static int ca_set_slot_descr(void) -{ - /* We could make this more graceful ? */ - return -EOPNOTSUPP; -} - -/* Need some more work */ -static int ca_set_pid(void) -{ - /* We could make this more graceful ? */ - return -EOPNOTSUPP; -} - -static void put_command_and_length(u8 *data, int command, int length) -{ - data[0] = (command >> 16) & 0xff; - data[1] = (command >> 8) & 0xff; - data[2] = command & 0xff; - data[3] = length; -} - -static void put_checksum(u8 *check_string, int length) -{ - dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum."); - dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length); - check_string[length] = dst_check_sum (check_string, length); - dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]); -} - -static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read) -{ - u8 reply; - - mutex_lock(&state->dst_mutex); - dst_comm_init(state); - msleep(65); - - if (write_dst(state, data, len)) { - dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover"); - dst_error_recovery(state); - goto error; - } - if ((dst_pio_disable(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed."); - goto error; - } - if (read_dst(state, &reply, GET_ACK) < 0) { - dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); - dst_error_recovery(state); - goto error; - } - if (read) { - if (! dst_wait_dst_ready(state, LONG_DELAY)) { - dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready"); - goto error; - } - if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */ - dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); - dst_error_recovery(state); - goto error; - } - } - mutex_unlock(&state->dst_mutex); - return 0; - -error: - mutex_unlock(&state->dst_mutex); - return -EIO; -} - - -static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read) -{ - u8 dst_ca_comm_err = 0; - - while (dst_ca_comm_err < RETRIES) { - dprintk(verbose, DST_CA_NOTICE, 1, " Put Command"); - if (dst_ci_command(state, data, ca_string, len, read)) { // If error - dst_error_recovery(state); - dst_ca_comm_err++; // work required here. - } else { - break; - } - } - - if(dst_ca_comm_err == RETRIES) - return -1; - - return 0; -} - - - -static int ca_get_app_info(struct dst_state *state) -{ - int length, str_length; - static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff}; - - put_checksum(&command[0], command[0]); - if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; - } - dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); - dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================"); - dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]", - state->messages[7], (state->messages[8] << 8) | state->messages[9], - (state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12])); - dprintk(verbose, DST_CA_INFO, 1, " =================================================================================================="); - - // Transform dst message to correct application_info message - length = state->messages[5]; - str_length = length - 6; - if (str_length < 0) { - str_length = 0; - dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering."); - } - - // First, the command and length fields - put_command_and_length(&state->messages[0], CA_APP_INFO, length); - - // Copy application_type, application_manufacturer and manufacturer_code - memcpy(&state->messages[4], &state->messages[7], 5); - - // Set string length and copy string - state->messages[9] = str_length; - memcpy(&state->messages[10], &state->messages[12], str_length); - - return 0; -} - -static int ca_get_ca_info(struct dst_state *state) -{ - int srcPtr, dstPtr, i, num_ids; - static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff}; - const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7; - - put_checksum(&slot_command[0], slot_command[0]); - if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; - } - dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); - - // Print raw data - dprintk(verbose, DST_CA_INFO, 0, " DST data = ["); - for (i = 0; i < state->messages[0] + 1; i++) { - dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]); - } - dprintk(verbose, DST_CA_INFO, 0, "]\n"); - - // Set the command and length of the output - num_ids = state->messages[in_num_ids_pos]; - if (num_ids >= 100) { - num_ids = 100; - dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering."); - } - put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2); - - dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = ["); - srcPtr = in_system_id_pos; - dstPtr = out_system_id_pos; - for(i = 0; i < num_ids; i++) { - dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]); - // Append to output - state->messages[dstPtr + 0] = state->messages[srcPtr + 0]; - state->messages[dstPtr + 1] = state->messages[srcPtr + 1]; - srcPtr += 2; - dstPtr += 2; - } - dprintk(verbose, DST_CA_INFO, 0, "]\n"); - - return 0; -} - -static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg) -{ - int i; - u8 slot_cap[256]; - static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff}; - - put_checksum(&slot_command[0], slot_command[0]); - if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; - } - dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !"); - - /* Will implement the rest soon */ - - dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]); - dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); - for (i = 0; i < slot_cap[0] + 1; i++) - dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]); - dprintk(verbose, DST_CA_INFO, 0, "\n"); - - p_ca_caps->slot_num = 1; - p_ca_caps->slot_type = 1; - p_ca_caps->descr_num = slot_cap[7]; - p_ca_caps->descr_type = 1; - - if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps))) - return -EFAULT; - - return 0; -} - -/* Need some more work */ -static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) -{ - return -EOPNOTSUPP; -} - - -static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg) -{ - int i; - static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; - - u8 *slot_info = state->messages; - - put_checksum(&slot_command[0], 7); - if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; - } - dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); - - /* Will implement the rest soon */ - - dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]); - dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); - for (i = 0; i < 8; i++) - dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]); - dprintk(verbose, DST_CA_INFO, 0, "\n"); - - if (slot_info[4] & 0x80) { - p_ca_slot_info->flags = CA_CI_MODULE_PRESENT; - p_ca_slot_info->num = 1; - p_ca_slot_info->type = CA_CI; - } else if (slot_info[4] & 0x40) { - p_ca_slot_info->flags = CA_CI_MODULE_READY; - p_ca_slot_info->num = 1; - p_ca_slot_info->type = CA_CI; - } else - p_ca_slot_info->flags = 0; - - if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info))) - return -EFAULT; - - return 0; -} - - -static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) -{ - u8 i = 0; - u32 command = 0; - - if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) - return -EFAULT; - - if (p_ca_message->msg) { - dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%02x %02x %02x]", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]); - - for (i = 0; i < 3; i++) { - command = command | p_ca_message->msg[i]; - if (i < 2) - command = command << 8; - } - dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); - - switch (command) { - case CA_APP_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; - break; - case CA_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; - break; - } - } - - return 0; -} - -static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length) -{ - if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { - hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ - hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ - } else { - if (length > 247) { - dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !"); - return -1; - } - hw_buffer->msg[0] = (length & 0xff) + 7; - hw_buffer->msg[1] = 0x40; - hw_buffer->msg[2] = 0x03; - hw_buffer->msg[3] = 0x00; - hw_buffer->msg[4] = 0x03; - hw_buffer->msg[5] = length & 0xff; - hw_buffer->msg[6] = 0x00; - - /* - * Need to compute length for EN50221 section 8.3.2, for the time being - * assuming 8.3.2 is not applicable - */ - memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length); - } - - return 0; -} - -static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) -{ - if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed."); - dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST."); - rdc_reset_state(state); - return -1; - } - dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success."); - - return 0; -} - -static u32 asn_1_decode(u8 *asn_1_array) -{ - u8 length_field = 0, word_count = 0, count = 0; - u32 length = 0; - - length_field = asn_1_array[0]; - dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field); - if (length_field < 0x80) { - length = length_field & 0x7f; - dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length); - } else { - word_count = length_field & 0x7f; - for (count = 0; count < word_count; count++) { - length = length << 8; - length += asn_1_array[count + 1]; - dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length); - } - } - return length; -} - -static int debug_string(u8 *msg, u32 length, u32 offset) -{ - u32 i; - - dprintk(verbose, DST_CA_DEBUG, 0, " String=[ "); - for (i = offset; i < length; i++) - dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]); - dprintk(verbose, DST_CA_DEBUG, 0, "]\n"); - - return 0; -} - - -static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) -{ - u32 length = 0; - u8 tag_length = 8; - - length = asn_1_decode(&p_ca_message->msg[3]); - dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length); - debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */ - - memset(hw_buffer->msg, '\0', length); - handle_dst_tag(state, p_ca_message, hw_buffer, length); - put_checksum(hw_buffer->msg, hw_buffer->msg[0]); - - debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */ - write_to_8820(state, hw_buffer, (length + tag_length), reply); - - return 0; -} - - -/* Board supports CA PMT reply ? */ -static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) -{ - int ca_pmt_reply_test = 0; - - /* Do test board */ - /* Not there yet but soon */ - - /* CA PMT Reply capable */ - if (ca_pmt_reply_test) { - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); - return -1; - } - - /* Process CA PMT Reply */ - /* will implement soon */ - dprintk(verbose, DST_CA_ERROR, 1, " Not there yet"); - } - /* CA PMT Reply not capable */ - if (!ca_pmt_reply_test) { - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); - return -1; - } - dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !"); - /* put a dummy message */ - - } - return 0; -} - -static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) -{ - int i = 0; - unsigned int ca_message_header_len; - - u32 command = 0; - struct ca_msg *hw_buffer; - int result = 0; - - if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); - return -ENOMEM; - } - dprintk(verbose, DST_CA_DEBUG, 1, " "); - - if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) { - result = -EFAULT; - goto free_mem_and_exit; - } - - - if (p_ca_message->msg) { - ca_message_header_len = p_ca_message->length; /* Restore it back when you are done */ - /* EN50221 tag */ - command = 0; - - for (i = 0; i < 3; i++) { - command = command | p_ca_message->msg[i]; - if (i < 2) - command = command << 8; - } - dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); - - switch (command) { - case CA_PMT: - dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); - break; - case CA_PMT_REPLY: - dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); - /* Have to handle the 2 basic types of cards here */ - if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); - break; - case CA_APP_INFO_ENQUIRY: // only for debugging - dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); - - if ((ca_get_app_info(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); - break; - case CA_INFO_ENQUIRY: - dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); - - if ((ca_get_ca_info(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); - break; - } - } -free_mem_and_exit: - kfree (hw_buffer); - - return result; -} - -static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg) -{ - struct dvb_device *dvbdev; - struct dst_state *state; - struct ca_slot_info *p_ca_slot_info; - struct ca_caps *p_ca_caps; - struct ca_msg *p_ca_message; - void __user *arg = (void __user *)ioctl_arg; - int result = 0; - - mutex_lock(&dst_ca_mutex); - dvbdev = file->private_data; - state = (struct dst_state *)dvbdev->priv; - p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL); - p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL); - p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL); - if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) { - dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); - result = -ENOMEM; - goto free_mem_and_exit; - } - - /* We have now only the standard ioctl's, the driver is upposed to handle internals. */ - switch (cmd) { - case CA_SEND_MSG: - dprintk(verbose, DST_CA_INFO, 1, " Sending message"); - if ((ca_send_message(state, p_ca_message, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); - result = -1; - goto free_mem_and_exit; - } - break; - case CA_GET_MSG: - dprintk(verbose, DST_CA_INFO, 1, " Getting message"); - if ((ca_get_message(state, p_ca_message, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); - break; - case CA_RESET: - dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST"); - dst_error_bailout(state); - msleep(4000); - break; - case CA_GET_SLOT_INFO: - dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); - if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !"); - break; - case CA_GET_CAP: - dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); - if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); - break; - case CA_GET_DESCR_INFO: - dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); - if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); - break; - case CA_SET_DESCR: - dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); - if ((ca_set_slot_descr()) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); - break; - case CA_SET_PID: - dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); - if ((ca_set_pid()) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); - default: - result = -EOPNOTSUPP; - }; - free_mem_and_exit: - kfree (p_ca_message); - kfree (p_ca_slot_info); - kfree (p_ca_caps); - - mutex_unlock(&dst_ca_mutex); - return result; -} - -static int dst_ca_open(struct inode *inode, struct file *file) -{ - dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); - try_module_get(THIS_MODULE); - - return 0; -} - -static int dst_ca_release(struct inode *inode, struct file *file) -{ - dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); - module_put(THIS_MODULE); - - return 0; -} - -static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) -{ - ssize_t bytes_read = 0; - - dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); - - return bytes_read; -} - -static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) -{ - dprintk(verbose, DST_CA_DEBUG, 1, " Device write."); - - return 0; -} - -static const struct file_operations dst_ca_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = dst_ca_ioctl, - .open = dst_ca_open, - .release = dst_ca_release, - .read = dst_ca_read, - .write = dst_ca_write, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_ca = { - .priv = NULL, - .users = 1, - .readers = 1, - .writers = 1, - .fops = &dst_ca_fops -}; - -struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter) -{ - struct dvb_device *dvbdev; - - dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device"); - if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) { - dst->dst_ca = dvbdev; - return dst->dst_ca; - } - - return NULL; -} - -EXPORT_SYMBOL(dst_ca_attach); - -MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_ca.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_ca.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_ca.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_ca.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* - CA-driver for TwinHan DST Frontend/Card - - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _DST_CA_H_ -#define _DST_CA_H_ - -#define RETRIES 5 - - -#define CA_APP_INFO_ENQUIRY 0x9f8020 -#define CA_APP_INFO 0x9f8021 -#define CA_ENTER_MENU 0x9f8022 -#define CA_INFO_ENQUIRY 0x9f8030 -#define CA_INFO 0x9f8031 -#define CA_PMT 0x9f8032 -#define CA_PMT_REPLY 0x9f8033 - -#define CA_CLOSE_MMI 0x9f8800 -#define CA_DISPLAY_CONTROL 0x9f8801 -#define CA_DISPLAY_REPLY 0x9f8802 -#define CA_TEXT_LAST 0x9f8803 -#define CA_TEXT_MORE 0x9f8804 -#define CA_KEYPAD_CONTROL 0x9f8805 -#define CA_KEYPRESS 0x9f8806 - -#define CA_ENQUIRY 0x9f8807 -#define CA_ANSWER 0x9f8808 -#define CA_MENU_LAST 0x9f8809 -#define CA_MENU_MORE 0x9f880a -#define CA_MENU_ANSWER 0x9f880b -#define CA_LIST_LAST 0x9f880c -#define CA_LIST_MORE 0x9f880d - - -struct dst_ca_private { - struct dst_state *dst; - struct dvb_device *dvbdev; -}; - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_common.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -/* - Frontend-driver for TwinHan DST Frontend - - Copyright (C) 2003 Jamie Honan - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef DST_COMMON_H -#define DST_COMMON_H - -#include -#include -#include -#include "bt878.h" - -#include "dst_ca.h" - - -#define NO_DELAY 0 -#define LONG_DELAY 1 -#define DEVICE_INIT 2 - -#define DELAY 1 - -#define DST_TYPE_IS_SAT 0 -#define DST_TYPE_IS_TERR 1 -#define DST_TYPE_IS_CABLE 2 -#define DST_TYPE_IS_ATSC 3 - -#define DST_TYPE_HAS_TS188 1 -#define DST_TYPE_HAS_TS204 2 -#define DST_TYPE_HAS_SYMDIV 4 -#define DST_TYPE_HAS_FW_1 8 -#define DST_TYPE_HAS_FW_2 16 -#define DST_TYPE_HAS_FW_3 32 -#define DST_TYPE_HAS_FW_BUILD 64 -#define DST_TYPE_HAS_OBS_REGS 128 -#define DST_TYPE_HAS_INC_COUNT 256 -#define DST_TYPE_HAS_MULTI_FE 512 -#define DST_TYPE_HAS_NEWTUNE_2 1024 -#define DST_TYPE_HAS_DBOARD 2048 -#define DST_TYPE_HAS_VLF 4096 - -/* Card capability list */ - -#define DST_TYPE_HAS_MAC 1 -#define DST_TYPE_HAS_DISEQC3 2 -#define DST_TYPE_HAS_DISEQC4 4 -#define DST_TYPE_HAS_DISEQC5 8 -#define DST_TYPE_HAS_MOTO 16 -#define DST_TYPE_HAS_CA 32 -#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ -#define DST_TYPE_HAS_SESSION 128 - -#define TUNER_TYPE_MULTI 1 -#define TUNER_TYPE_UNKNOWN 2 -/* DVB-S */ -#define TUNER_TYPE_L64724 4 -#define TUNER_TYPE_STV0299 8 -#define TUNER_TYPE_MB86A15 16 - -/* DVB-T */ -#define TUNER_TYPE_TDA10046 32 - -/* ATSC */ -#define TUNER_TYPE_NXT200x 64 - - -#define RDC_8820_PIO_0_DISABLE 0 -#define RDC_8820_PIO_0_ENABLE 1 -#define RDC_8820_INT 2 -#define RDC_8820_RESET 4 - -/* DST Communication */ -#define GET_REPLY 1 -#define NO_REPLY 0 - -#define GET_ACK 1 -#define FIXED_COMM 8 - -#define ACK 0xff - -struct dst_state { - - struct i2c_adapter* i2c; - - struct bt878* bt; - - /* configuration settings */ - const struct dst_config* config; - - struct dvb_frontend frontend; - - /* private ASIC data */ - u8 tx_tuna[10]; - u8 rx_tuna[10]; - u8 rxbuffer[10]; - u8 diseq_flags; - u8 dst_type; - u32 type_flags; - u32 frequency; /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; - u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; - u32 decode_freq; - u8 decode_lock; - u16 decode_strength; - u16 decode_snr; - unsigned long cur_jiff; - u8 k22; - fe_bandwidth_t bandwidth; - u32 dst_hw_cap; - u8 dst_fw_version; - fe_sec_mini_cmd_t minicmd; - fe_modulation_t modulation; - u8 messages[256]; - u8 mac_address[8]; - u8 fw_version[8]; - u8 card_info[8]; - u8 vendor[8]; - u8 board_info[8]; - u32 tuner_type; - char *tuner_name; - struct mutex dst_mutex; - u8 fw_name[8]; - struct dvb_device *dst_ca; -}; - -struct tuner_types { - u32 tuner_type; - char *tuner_name; - char *board_name; - char *fw_name; -}; - -struct dst_types { - char *device_id; - int offset; - u8 dst_type; - u32 type_flags; - u32 dst_feature; - u32 tuner_type; -}; - -struct dst_config -{ - /* the ASIC i2c address */ - u8 demod_address; -}; - -int rdc_reset_state(struct dst_state *state); - -int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); -int dst_pio_disable(struct dst_state *state); -int dst_error_recovery(struct dst_state* state); -int dst_error_bailout(struct dst_state *state); -int dst_comm_init(struct dst_state* state); - -int write_dst(struct dst_state *state, u8 * data, u8 len); -int read_dst(struct dst_state *state, u8 * ret, u8 len); -u8 dst_check_sum(u8 * buf, u32 len); -struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); -struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); - - -#endif // DST_COMMON_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dst_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend - * - * Copyright (C) 2003 Jamie Honan - */ - -struct dst_gpio_enable { - u32 mask; - u32 enable; -}; - -struct dst_gpio_output { - u32 mask; - u32 highvals; -}; - -struct dst_gpio_read { - unsigned long value; -}; - -union dst_gpio_packet { - struct dst_gpio_enable enb; - struct dst_gpio_output outp; - struct dst_gpio_read rd; - int psize; -}; - -#define DST_IG_ENABLE 0 -#define DST_IG_WRITE 1 -#define DST_IG_READ 2 -#define DST_IG_TS 3 - -struct bt878; - -int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,970 +0,0 @@ -/* - * Bt8xx based DVB adapter driver - * - * Copyright (C) 2002,2003 Florian Schirmer - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb-bt8xx.h" -#include "bt878.h" - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk( args... ) \ - do { \ - if (debug) printk(KERN_DEBUG args); \ - } while (0) - -#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - -static void dvb_bt8xx_task(unsigned long data) -{ - struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data; - - //printk("%d ", card->bt->finished_block); - - while (card->bt->last_block != card->bt->finished_block) { - (card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) - (&card->demux, - &card->bt->buf_cpu[card->bt->last_block * - card->bt->block_bytes], - card->bt->block_bytes); - card->bt->last_block = (card->bt->last_block + 1) % - card->bt->block_count; - } -} - -static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux*dvbdmx = dvbdmxfeed->demux; - struct dvb_bt8xx_card *card = dvbdmx->priv; - int rc; - - dprintk("dvb_bt8xx: start_feed\n"); - - if (!dvbdmx->dmx.frontend) - return -EINVAL; - - mutex_lock(&card->lock); - card->nfeeds++; - rc = card->nfeeds; - if (card->nfeeds == 1) - bt878_start(card->bt, card->gpio_mode, - card->op_sync_orin, card->irq_err_ignore); - mutex_unlock(&card->lock); - return rc; -} - -static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct dvb_bt8xx_card *card = dvbdmx->priv; - - dprintk("dvb_bt8xx: stop_feed\n"); - - if (!dvbdmx->dmx.frontend) - return -EINVAL; - - mutex_lock(&card->lock); - card->nfeeds--; - if (card->nfeeds == 0) - bt878_stop(card->bt); - mutex_unlock(&card->lock); - - return 0; -} - -static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev) -{ - if ((adev->subsystem_vendor == bdev->subsystem_vendor) && - (adev->subsystem_device == bdev->subsystem_device) && - (adev->bus->number == bdev->bus->number) && - (PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn))) - return 1; - return 0; -} - -static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev) -{ - unsigned int card_nr; - - /* Hmm, n squared. Hope n is small */ - for (card_nr = 0; card_nr < bt878_num; card_nr++) - if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev)) - return &bt878[card_nr]; - return NULL; -} - -static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 }; - static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) -{ - u32 div; - unsigned char bs = 0; - unsigned char cp = 0; - - if (buf_len < 5) - return -EINVAL; - - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency < 542000000) - cp = 0xb4; - else if (params->frequency < 771000000) - cp = 0xbc; - else - cp = 0xf4; - - if (params->frequency == 0) - bs = 0x03; - else if (params->frequency < 443250000) - bs = 0x02; - else - bs = 0x08; - - pllbuf[0] = 0x60; - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = cp; - pllbuf[4] = bs; - - return 5; -} - -static struct mt352_config thomson_dtt7579_config = { - .demod_address = 0x0f, - .demod_init = thomson_dtt7579_demod_init, -}; - -static struct zl10353_config thomson_dtt7579_zl10353_config = { - .demod_address = 0x0f, -}; - -static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - u32 freq = params->frequency; - - int i, a, n, pump; - u32 band, pll; - - u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, - 1576000,1718000,1856000,2036000,2150000}; - u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, - 0x00102000,0x00104000,0x00108000,0x00110000, - 0x00120000,0x00140000}; - - #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ - printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq); - - /* This is really the bit driving the tuner chip cx24108 */ - - if (freq<950000) - freq = 950000; /* kHz */ - else if (freq>2150000) - freq = 2150000; /* satellite IF is 950..2150MHz */ - - /* decide which VCO to use for the input frequency */ - for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++); - printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq); - band=bandsel[i]; - /* the gain values must be set by SetSymbolrate */ - /* compute the pll divider needed, from Conexant data sheet, - resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4, - depending on the divider bit. It is set to /4 on the 2 lowest - bands */ - n=((i<=2?2:1)*freq*10L)/(XTAL/100); - a=n%32; n/=32; if(a==0) n--; - pump=(freq<(osci[i-1]+osci[i])/2); - pll=0xf8000000| - ((pump?1:2)<<(14+11))| - ((n&0x1ff)<<(5+11))| - ((a&0x1f)<<11); - /* everything is shifted left 11 bits to left-align the bits in the - 32bit word. Output to the tuner goes MSB-aligned, after all */ - printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a); - cx24110_pll_write(fe,band); - /* set vga and vca to their widest-band settings, as a precaution. - SetSymbolrate might not be called to set this up */ - cx24110_pll_write(fe,0x500c0000); - cx24110_pll_write(fe,0x83f1f800); - cx24110_pll_write(fe,pll); - //writereg(client,0x56,0x7f); - - return 0; -} - -static int pinnsat_tuner_init(struct dvb_frontend* fe) -{ - struct dvb_bt8xx_card *card = fe->dvb->priv; - - bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */ - bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */ - - return 0; -} - -static int pinnsat_tuner_sleep(struct dvb_frontend* fe) -{ - struct dvb_bt8xx_card *card = fe->dvb->priv; - - bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */ - - return 0; -} - -static struct cx24110_config pctvsat_config = { - .demod_address = 0x55, -}; - -static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; - u8 cfg, cpump, band_select; - u8 data[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (36000000 + params->frequency + 83333) / 166666; - cfg = 0x88; - - if (params->frequency < 175000000) - cpump = 2; - else if (params->frequency < 390000000) - cpump = 1; - else if (params->frequency < 470000000) - cpump = 2; - else if (params->frequency < 750000000) - cpump = 2; - else - cpump = 3; - - if (params->frequency < 175000000) - band_select = 0x0e; - else if (params->frequency < 470000000) - band_select = 0x05; - else - band_select = 0x03; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = ((div >> 10) & 0x60) | cfg; - data[3] = (cpump << 6) | band_select; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(card->i2c_adapter, &msg, 1); - return (div * 166666 - 36000000); -} - -static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ - struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; - - return request_firmware(fw, name, &bt->bt->dev->dev); -} - -static struct sp887x_config microtune_mt7202dtf_config = { - .demod_address = 0x70, - .request_firmware = microtune_mt7202dtf_request_firmware, -}; - -static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, - 0x00, 0xFF, 0x00, 0x40, 0x40 }; - static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); - udelay(2000); - mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) -{ - u32 div; - unsigned char bs = 0; - unsigned char cp = 0; - - if (buf_len < 5) return -EINVAL; - - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency < 150000000) - cp = 0xB4; - else if (params->frequency < 173000000) - cp = 0xBC; - else if (params->frequency < 250000000) - cp = 0xB4; - else if (params->frequency < 400000000) - cp = 0xBC; - else if (params->frequency < 420000000) - cp = 0xF4; - else if (params->frequency < 470000000) - cp = 0xFC; - else if (params->frequency < 600000000) - cp = 0xBC; - else if (params->frequency < 730000000) - cp = 0xF4; - else - cp = 0xFC; - - if (params->frequency < 150000000) - bs = 0x01; - else if (params->frequency < 173000000) - bs = 0x01; - else if (params->frequency < 250000000) - bs = 0x02; - else if (params->frequency < 400000000) - bs = 0x02; - else if (params->frequency < 420000000) - bs = 0x02; - else if (params->frequency < 470000000) - bs = 0x02; - else if (params->frequency < 600000000) - bs = 0x08; - else if (params->frequency < 730000000) - bs = 0x08; - else - bs = 0x08; - - pllbuf[0] = 0x61; - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = cp; - pllbuf[4] = bs; - - return 5; -} - -static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { - .demod_address = 0x0f, - .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, -}; - -static struct dst_config dst_config = { - .demod_address = 0x55, -}; - -static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ - struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; - - return request_firmware(fw, name, &bt->bt->dev->dev); -} - -static void or51211_setmode(struct dvb_frontend * fe, int mode) -{ - struct dvb_bt8xx_card *bt = fe->dvb->priv; - bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */ - msleep(20); -} - -static void or51211_reset(struct dvb_frontend * fe) -{ - struct dvb_bt8xx_card *bt = fe->dvb->priv; - - /* RESET DEVICE - * reset is controled by GPIO-0 - * when set to 0 causes reset and when to 1 for normal op - * must remain reset for 128 clock cycles on a 50Mhz clock - * also PRM1 PRM2 & PRM4 are controled by GPIO-1,GPIO-2 & GPIO-4 - * We assume that the reset has be held low long enough or we - * have been reset by a power on. When the driver is unloaded - * reset set to 0 so if reloaded we have been reset. - */ - /* reset & PRM1,2&4 are outputs */ - int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); - if (ret != 0) - printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret); - bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ - msleep(20); - /* Now set for normal operation */ - bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001); - /* wait for operation to begin */ - msleep(500); -} - -static void or51211_sleep(struct dvb_frontend * fe) -{ - struct dvb_bt8xx_card *bt = fe->dvb->priv; - bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000); -} - -static struct or51211_config or51211_config = { - .demod_address = 0x15, - .request_firmware = or51211_request_firmware, - .setmode = or51211_setmode, - .reset = or51211_reset, - .sleep = or51211_sleep, -}; - -static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; - - div = (params->frequency + 36166667) / 166667; - - buf[0] = (div >> 8) & 0x7F; - buf[1] = div & 0xFF; - buf[2] = 0x85; - if ((params->frequency >= 47000000) && (params->frequency < 153000000)) - buf[3] = 0x01; - else if ((params->frequency >= 153000000) && (params->frequency < 430000000)) - buf[3] = 0x02; - else if ((params->frequency >= 430000000) && (params->frequency < 824000000)) - buf[3] = 0x0C; - else if ((params->frequency >= 824000000) && (params->frequency < 863000000)) - buf[3] = 0x8C; - else - return -EINVAL; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(card->i2c_adapter, &msg, 1); - return 0; -} - -static struct nxt6000_config vp3021_alps_tded4_config = { - .demod_address = 0x0a, - .clock_inversion = 1, -}; - -static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) -{ - u32 div; - struct dvb_ofdm_parameters *op = ¶ms->u.ofdm; - - if (buf_len < 5) - return -EINVAL; - - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - pllbuf[0] = 0x61; - pllbuf[1] = (div >> 8) & 0x7F; - pllbuf[2] = div & 0xFF; - pllbuf[3] = 0x85; - - dprintk("frequency %u, div %u\n", params->frequency, div); - - if (params->frequency < 470000000) - pllbuf[4] = 0x02; - else if (params->frequency > 823000000) - pllbuf[4] = 0x88; - else - pllbuf[4] = 0x08; - - if (op->bandwidth == 8) - pllbuf[4] |= 0x04; - - return 5; -} - -static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) -{ - /* - * Reset the frontend, must be called before trying - * to initialise the MT352 or mt352_attach - * will fail. Same goes for the nxt6000 frontend. - * - */ - - int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08); - if (ret != 0) - printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret); - - /* Pulse the reset line */ - bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ - bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */ - msleep(100); - - bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ -} - -static struct mt352_config digitv_alps_tded4_config = { - .demod_address = 0x0a, - .demod_init = digitv_alps_tded4_demod_init, -}; - -static struct lgdt330x_config tdvs_tua6034_config = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, - .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ -}; - -static void lgdt330x_reset(struct dvb_bt8xx_card *bt) -{ - /* Set pin 27 of the lgdt3303 chip high to reset the frontend */ - - /* Pulse the reset line */ - bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ - bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */ - msleep(100); - - bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ - msleep(100); -} - -static void frontend_init(struct dvb_bt8xx_card *card, u32 type) -{ - struct dst_state* state = NULL; - - switch(type) { - case BTTV_BOARD_DVICO_DVBT_LITE: - card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter); - - if (card->fe == NULL) - card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config, - card->i2c_adapter); - - if (card->fe != NULL) { - card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs; - card->fe->ops.info.frequency_min = 174000000; - card->fe->ops.info.frequency_max = 862000000; - } - break; - - case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: - lgdt330x_reset(card); - card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); - if (card->fe != NULL) { - dvb_attach(simple_tuner_attach, card->fe, - card->i2c_adapter, 0x61, - TUNER_LG_TDVS_H06XF); - dprintk ("dvb_bt8xx: lgdt330x detected\n"); - } - break; - - case BTTV_BOARD_NEBULA_DIGITV: - /* - * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); - * this would be a cleaner solution than trying each frontend in turn. - */ - - /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ - digitv_alps_tded4_reset(card); - card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter); - if (card->fe != NULL) { - card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params; - dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); - break; - } - - /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */ - digitv_alps_tded4_reset(card); - card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter); - - if (card->fe != NULL) { - card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs; - dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); - } - break; - - case BTTV_BOARD_AVDVBT_761: - card->fe = dvb_attach(sp887x_attach, µtune_mt7202dtf_config, card->i2c_adapter); - if (card->fe) { - card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params; - } - break; - - case BTTV_BOARD_AVDVBT_771: - card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); - if (card->fe != NULL) { - card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs; - card->fe->ops.info.frequency_min = 174000000; - card->fe->ops.info.frequency_max = 862000000; - } - break; - - case BTTV_BOARD_TWINHAN_DST: - /* DST is not a frontend driver !!! */ - state = kmalloc(sizeof (struct dst_state), GFP_KERNEL); - if (!state) { - printk("dvb_bt8xx: No memory\n"); - break; - } - /* Setup the Card */ - state->config = &dst_config; - state->i2c = card->i2c_adapter; - state->bt = card->bt; - state->dst_ca = NULL; - /* DST is not a frontend, attaching the ASIC */ - if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) { - printk("%s: Could not find a Twinhan DST.\n", __func__); - break; - } - /* Attach other DST peripherals if any */ - /* Conditional Access device */ - card->fe = &state->frontend; - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - dvb_attach(dst_ca_attach, state, &card->dvb_adapter); - break; - - case BTTV_BOARD_PINNACLESAT: - card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter); - if (card->fe) { - card->fe->ops.tuner_ops.init = pinnsat_tuner_init; - card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep; - card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params; - } - break; - - case BTTV_BOARD_PC_HDTV: - card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter); - if (card->fe != NULL) - dvb_attach(simple_tuner_attach, card->fe, - card->i2c_adapter, 0x61, - TUNER_PHILIPS_FCV1236D); - break; - } - - if (card->fe == NULL) - printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - card->bt->dev->vendor, - card->bt->dev->device, - card->bt->dev->subsystem_vendor, - card->bt->dev->subsystem_device); - else - if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { - printk("dvb-bt8xx: Frontend registration failed!\n"); - dvb_frontend_detach(card->fe); - card->fe = NULL; - } -} - -static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) -{ - int result; - - result = dvb_register_adapter(&card->dvb_adapter, card->card_name, - THIS_MODULE, &card->bt->dev->dev, - adapter_nr); - if (result < 0) { - printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result); - return result; - } - card->dvb_adapter.priv = card; - - card->bt->adapter = card->i2c_adapter; - - memset(&card->demux, 0, sizeof(struct dvb_demux)); - - card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; - - card->demux.priv = card; - card->demux.filternum = 256; - card->demux.feednum = 256; - card->demux.start_feed = dvb_bt8xx_start_feed; - card->demux.stop_feed = dvb_bt8xx_stop_feed; - card->demux.write_to_decoder = NULL; - - if ((result = dvb_dmx_init(&card->demux)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - dvb_unregister_adapter(&card->dvb_adapter); - return result; - } - - card->dmxdev.filternum = 256; - card->dmxdev.demux = &card->demux.dmx; - card->dmxdev.capabilities = 0; - - if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) { - printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result); - - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; - } - - card->fe_hw.source = DMX_FRONTEND_0; - - if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; - } - - card->fe_mem.source = DMX_MEMORY_FE; - - if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; - } - - if ((result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; - } - - dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); - - tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); - - frontend_init(card, type); - - return 0; -} - -static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) -{ - struct dvb_bt8xx_card *card; - struct pci_dev* bttv_pci_dev; - int ret; - - if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL))) - return -ENOMEM; - - mutex_init(&card->lock); - card->bttv_nr = sub->core->nr; - strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name)); - card->i2c_adapter = &sub->core->i2c_adap; - - switch(sub->core->type) { - case BTTV_BOARD_PINNACLESAT: - card->gpio_mode = 0x0400c060; - /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, - BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - break; - - case BTTV_BOARD_DVICO_DVBT_LITE: - card->gpio_mode = 0x0400C060; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - /* 26, 15, 14, 6, 5 - * A_PWRDN DA_DPM DA_SBR DA_IOM_DA - * DA_APP(parallel) */ - break; - - case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: - card->gpio_mode = 0x0400c060; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - break; - - case BTTV_BOARD_NEBULA_DIGITV: - case BTTV_BOARD_AVDVBT_761: - card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - /* A_PWRDN DA_SBR DA_APP (high speed serial) */ - break; - - case BTTV_BOARD_AVDVBT_771: //case 0x07711461: - card->gpio_mode = 0x0400402B; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - /* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/ - break; - - case BTTV_BOARD_TWINHAN_DST: - card->gpio_mode = 0x2204f2c; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR | - BT878_APPERR | BT878_AFBUS; - /* 25,21,14,11,10,9,8,3,2 then - * 0x33 = 5,4,1,0 - * A_SEL=SML, DA_MLB, DA_SBR, - * DA_SDR=f, fifo trigger = 32 DWORDS - * IOM = 0 == audio A/D - * DPM = 0 == digital audio mode - * == async data parallel port - * then 0x33 (13 is set by start_capture) - * DA_APP = async data parallel port, - * ACAP_EN = 1, - * RISC+FIFO ENABLE */ - break; - - case BTTV_BOARD_PC_HDTV: - card->gpio_mode = 0x0100EC7B; - card->op_sync_orin = BT878_RISC_SYNC_MASK; - card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; - break; - - default: - printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n", - sub->core->type); - kfree(card); - return -ENODEV; - } - - dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name); - - if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) { - printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr); - kfree(card); - return -EFAULT; - } - - if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) { - printk("dvb_bt8xx: unable to determine DMA core of card %d,\n", - card->bttv_nr); - printk("dvb_bt8xx: if you have the ALSA bt87x audio driver " - "installed, try removing it.\n"); - - kfree(card); - return -EFAULT; - } - - mutex_init(&card->bt->gpio_lock); - card->bt->bttv_nr = sub->core->nr; - - if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) { - kfree(card); - return ret; - } - - dev_set_drvdata(&sub->dev, card); - return 0; -} - -static void dvb_bt8xx_remove(struct bttv_sub_device *sub) -{ - struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev); - - dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); - - bt878_stop(card->bt); - tasklet_kill(&card->bt->tasklet); - dvb_net_release(&card->dvbnet); - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - if (card->fe) { - dvb_unregister_frontend(card->fe); - dvb_frontend_detach(card->fe); - } - dvb_unregister_adapter(&card->dvb_adapter); - - kfree(card); -} - -static struct bttv_sub_driver driver = { - .drv = { - .name = "dvb-bt8xx", - }, - .probe = dvb_bt8xx_probe, - .remove = dvb_bt8xx_remove, - /* FIXME: - * .shutdown = dvb_bt8xx_shutdown, - * .suspend = dvb_bt8xx_suspend, - * .resume = dvb_bt8xx_resume, - */ -}; - -static int __init dvb_bt8xx_init(void) -{ - return bttv_sub_register(&driver, "dvb"); -} - -static void __exit dvb_bt8xx_exit(void) -{ - bttv_sub_unregister(&driver); -} - -module_init(dvb_bt8xx_init); -module_exit(dvb_bt8xx_exit); - -MODULE_DESCRIPTION("Bt8xx based DVB adapter driver"); -MODULE_AUTHOR("Florian Schirmer "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* - * Bt8xx based DVB adapter driver - * - * Copyright (C) 2002,2003 Florian Schirmer - * Copyright (C) 2002 Peter Hettkamp - * Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH - * Copyright (C) 1998,1999 Christian Theiss - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef DVB_BT8XX_H -#define DVB_BT8XX_H - -#include -#include -#include "dvbdev.h" -#include "dvb_net.h" -#include "bttv.h" -#include "mt352.h" -#include "sp887x.h" -#include "dst_common.h" -#include "nxt6000.h" -#include "cx24110.h" -#include "or51211.h" -#include "lgdt330x.h" -#include "zl10353.h" -#include "tuner-simple.h" - -struct dvb_bt8xx_card { - struct mutex lock; - int nfeeds; - char card_name[32]; - struct dvb_adapter dvb_adapter; - struct bt878 *bt; - unsigned int bttv_nr; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - u32 gpio_mode; - u32 op_sync_orin; - u32 irq_err_ignore; - struct i2c_adapter *i2c_adapter; - struct dvb_net dvbnet; - - struct dvb_frontend* fe; -}; - -#endif /* DVB_BT8XX_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -config DVB_BT8XX - tristate "BT8xx based PCI cards" - depends on DVB_CORE && PCI && I2C && VIDEO_BT848 - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_SP887X if !DVB_FE_CUSTOMISE - select DVB_NXT6000 if !DVB_FE_CUSTOMISE - select DVB_CX24110 if !DVB_FE_CUSTOMISE - select DVB_OR51211 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - help - Support for PCI cards based on the Bt8xx PCI bridge. Examples are - the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, - the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and - some AVerMedia cards. - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the PCI bus, so you need - an external software decoder to watch TV on your computer. - - Say Y if you own such a device and want to use it. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/bt8xx/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/video/bt8xx -EXTRA_CFLAGS += -Idrivers/media/common/tuners diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/dm1105.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/dm1105.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/dm1105.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/dm1105.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1044 +0,0 @@ -/* - * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip - * - * Copyright (C) 2008 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "demux.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "dvbdev.h" -#include "dvb-pll.h" - -#include "stv0299.h" -#include "stv0288.h" -#include "stb6000.h" -#include "si21xx.h" -#include "cx24116.h" -#include "z0194a.h" -#include "ds3000.h" - -#define MODULE_NAME "dm1105" - -#define UNSET (-1U) - -#define DM1105_BOARD_NOAUTO UNSET -#define DM1105_BOARD_UNKNOWN 0 -#define DM1105_BOARD_DVBWORLD_2002 1 -#define DM1105_BOARD_DVBWORLD_2004 2 -#define DM1105_BOARD_AXESS_DM05 3 - -/* ----------------------------------------------- */ -/* - * PCI ID's - */ -#ifndef PCI_VENDOR_ID_TRIGEM -#define PCI_VENDOR_ID_TRIGEM 0x109f -#endif -#ifndef PCI_VENDOR_ID_AXESS -#define PCI_VENDOR_ID_AXESS 0x195d -#endif -#ifndef PCI_DEVICE_ID_DM1105 -#define PCI_DEVICE_ID_DM1105 0x036f -#endif -#ifndef PCI_DEVICE_ID_DW2002 -#define PCI_DEVICE_ID_DW2002 0x2002 -#endif -#ifndef PCI_DEVICE_ID_DW2004 -#define PCI_DEVICE_ID_DW2004 0x2004 -#endif -#ifndef PCI_DEVICE_ID_DM05 -#define PCI_DEVICE_ID_DM05 0x1105 -#endif -/* ----------------------------------------------- */ -/* sdmc dm1105 registers */ - -/* TS Control */ -#define DM1105_TSCTR 0x00 -#define DM1105_DTALENTH 0x04 - -/* GPIO Interface */ -#define DM1105_GPIOVAL 0x08 -#define DM1105_GPIOCTR 0x0c - -/* PID serial number */ -#define DM1105_PIDN 0x10 - -/* Odd-even secret key select */ -#define DM1105_CWSEL 0x14 - -/* Host Command Interface */ -#define DM1105_HOST_CTR 0x18 -#define DM1105_HOST_AD 0x1c - -/* PCI Interface */ -#define DM1105_CR 0x30 -#define DM1105_RST 0x34 -#define DM1105_STADR 0x38 -#define DM1105_RLEN 0x3c -#define DM1105_WRP 0x40 -#define DM1105_INTCNT 0x44 -#define DM1105_INTMAK 0x48 -#define DM1105_INTSTS 0x4c - -/* CW Value */ -#define DM1105_ODD 0x50 -#define DM1105_EVEN 0x58 - -/* PID Value */ -#define DM1105_PID 0x60 - -/* IR Control */ -#define DM1105_IRCTR 0x64 -#define DM1105_IRMODE 0x68 -#define DM1105_SYSTEMCODE 0x6c -#define DM1105_IRCODE 0x70 - -/* Unknown Values */ -#define DM1105_ENCRYPT 0x74 -#define DM1105_VER 0x7c - -/* I2C Interface */ -#define DM1105_I2CCTR 0x80 -#define DM1105_I2CSTS 0x81 -#define DM1105_I2CDAT 0x82 -#define DM1105_I2C_RA 0x83 -/* ----------------------------------------------- */ -/* Interrupt Mask Bits */ - -#define INTMAK_TSIRQM 0x01 -#define INTMAK_HIRQM 0x04 -#define INTMAK_IRM 0x08 -#define INTMAK_ALLMASK (INTMAK_TSIRQM | \ - INTMAK_HIRQM | \ - INTMAK_IRM) -#define INTMAK_NONEMASK 0x00 - -/* Interrupt Status Bits */ -#define INTSTS_TSIRQ 0x01 -#define INTSTS_HIRQ 0x04 -#define INTSTS_IR 0x08 - -/* IR Control Bits */ -#define DM1105_IR_EN 0x01 -#define DM1105_SYS_CHK 0x02 -#define DM1105_REP_FLG 0x08 - -/* EEPROM addr */ -#define IIC_24C01_addr 0xa0 -/* Max board count */ -#define DM1105_MAX 0x04 - -#define DRIVER_NAME "dm1105" - -#define DM1105_DMA_PACKETS 47 -#define DM1105_DMA_PACKET_LENGTH (128*4) -#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS) - -/* GPIO's for LNB power control */ -#define DM1105_LNB_MASK 0x00000000 -#define DM1105_LNB_OFF 0x00020000 -#define DM1105_LNB_13V 0x00010100 -#define DM1105_LNB_18V 0x00000100 - -/* GPIO's for LNB power control for Axess DM05 */ -#define DM05_LNB_MASK 0x00000000 -#define DM05_LNB_OFF 0x00020000/* actually 13v */ -#define DM05_LNB_13V 0x00020000 -#define DM05_LNB_18V 0x00030000 - -static unsigned int card[] = {[0 ... 3] = UNSET }; -module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card, "card type"); - -static int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); - -static unsigned int dm1105_devcount; - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct dm1105_board { - char *name; -}; - -struct dm1105_subid { - u16 subvendor; - u16 subdevice; - u32 card; -}; - -static const struct dm1105_board dm1105_boards[] = { - [DM1105_BOARD_UNKNOWN] = { - .name = "UNKNOWN/GENERIC", - }, - [DM1105_BOARD_DVBWORLD_2002] = { - .name = "DVBWorld PCI 2002", - }, - [DM1105_BOARD_DVBWORLD_2004] = { - .name = "DVBWorld PCI 2004", - }, - [DM1105_BOARD_AXESS_DM05] = { - .name = "Axess/EasyTv DM05", - }, -}; - -static const struct dm1105_subid dm1105_subids[] = { - { - .subvendor = 0x0000, - .subdevice = 0x2002, - .card = DM1105_BOARD_DVBWORLD_2002, - }, { - .subvendor = 0x0001, - .subdevice = 0x2002, - .card = DM1105_BOARD_DVBWORLD_2002, - }, { - .subvendor = 0x0000, - .subdevice = 0x2004, - .card = DM1105_BOARD_DVBWORLD_2004, - }, { - .subvendor = 0x0001, - .subdevice = 0x2004, - .card = DM1105_BOARD_DVBWORLD_2004, - }, { - .subvendor = 0x195d, - .subdevice = 0x1105, - .card = DM1105_BOARD_AXESS_DM05, - }, -}; - -static void dm1105_card_list(struct pci_dev *pci) -{ - int i; - - if (0 == pci->subsystem_vendor && - 0 == pci->subsystem_device) { - printk(KERN_ERR - "dm1105: Your board has no valid PCI Subsystem ID\n" - "dm1105: and thus can't be autodetected\n" - "dm1105: Please pass card= insmod option to\n" - "dm1105: workaround that. Redirect complaints to\n" - "dm1105: the vendor of the TV card. Best regards,\n" - "dm1105: -- tux\n"); - } else { - printk(KERN_ERR - "dm1105: Your board isn't known (yet) to the driver.\n" - "dm1105: You can try to pick one of the existing\n" - "dm1105: card configs via card= insmod option.\n" - "dm1105: Updating to the latest version might help\n" - "dm1105: as well.\n"); - } - printk(KERN_ERR "Here is a list of valid choices for the card= " - "insmod option:\n"); - for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++) - printk(KERN_ERR "dm1105: card=%d -> %s\n", - i, dm1105_boards[i].name); -} - -/* infrared remote control */ -struct infrared { - struct rc_dev *dev; - char input_phys[32]; - struct work_struct work; - u32 ir_command; -}; - -struct dm1105_dev { - /* pci */ - struct pci_dev *pdev; - u8 __iomem *io_mem; - - /* ir */ - struct infrared ir; - - /* dvb */ - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - struct dmxdev dmxdev; - struct dvb_adapter dvb_adapter; - struct dvb_demux demux; - struct dvb_frontend *fe; - struct dvb_net dvbnet; - unsigned int full_ts_users; - unsigned int boardnr; - int nr; - - /* i2c */ - struct i2c_adapter i2c_adap; - - /* irq */ - struct work_struct work; - struct workqueue_struct *wq; - char wqn[16]; - - /* dma */ - dma_addr_t dma_addr; - unsigned char *ts_buf; - u32 wrp; - u32 nextwrp; - u32 buffer_size; - unsigned int PacketErrorCount; - unsigned int dmarst; - spinlock_t lock; -}; - -#define dm_io_mem(reg) ((unsigned long)(&dev->io_mem[reg])) - -#define dm_readb(reg) inb(dm_io_mem(reg)) -#define dm_writeb(reg, value) outb((value), (dm_io_mem(reg))) - -#define dm_readw(reg) inw(dm_io_mem(reg)) -#define dm_writew(reg, value) outw((value), (dm_io_mem(reg))) - -#define dm_readl(reg) inl(dm_io_mem(reg)) -#define dm_writel(reg, value) outl((value), (dm_io_mem(reg))) - -#define dm_andorl(reg, mask, value) \ - outl((inl(dm_io_mem(reg)) & ~(mask)) |\ - ((value) & (mask)), (dm_io_mem(reg))) - -#define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit)) -#define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0) - -static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, int num) -{ - struct dm1105_dev *dev ; - - int addr, rc, i, j, k, len, byte, data; - u8 status; - - dev = i2c_adap->algo_data; - for (i = 0; i < num; i++) { - dm_writeb(DM1105_I2CCTR, 0x00); - if (msgs[i].flags & I2C_M_RD) { - /* read bytes */ - addr = msgs[i].addr << 1; - addr |= 1; - dm_writeb(DM1105_I2CDAT, addr); - for (byte = 0; byte < msgs[i].len; byte++) - dm_writeb(DM1105_I2CDAT + byte + 1, 0); - - dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len); - for (j = 0; j < 55; j++) { - mdelay(10); - status = dm_readb(DM1105_I2CSTS); - if ((status & 0xc0) == 0x40) - break; - } - if (j >= 55) - return -1; - - for (byte = 0; byte < msgs[i].len; byte++) { - rc = dm_readb(DM1105_I2CDAT + byte + 1); - if (rc < 0) - goto err; - msgs[i].buf[byte] = rc; - } - } else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) { - /* prepaired for cx24116 firmware */ - /* Write in small blocks */ - len = msgs[i].len - 1; - k = 1; - do { - dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1); - dm_writeb(DM1105_I2CDAT + 1, 0xf7); - for (byte = 0; byte < (len > 48 ? 48 : len); byte++) { - data = msgs[i].buf[k + byte]; - dm_writeb(DM1105_I2CDAT + byte + 2, data); - } - dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len)); - for (j = 0; j < 25; j++) { - mdelay(10); - status = dm_readb(DM1105_I2CSTS); - if ((status & 0xc0) == 0x40) - break; - } - - if (j >= 25) - return -1; - - k += 48; - len -= 48; - } while (len > 0); - } else { - /* write bytes */ - dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1); - for (byte = 0; byte < msgs[i].len; byte++) { - data = msgs[i].buf[byte]; - dm_writeb(DM1105_I2CDAT + byte + 1, data); - } - dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len); - for (j = 0; j < 25; j++) { - mdelay(10); - status = dm_readb(DM1105_I2CSTS); - if ((status & 0xc0) == 0x40) - break; - } - - if (j >= 25) - return -1; - } - } - return num; - err: - return rc; -} - -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm dm1105_algo = { - .master_xfer = dm1105_i2c_xfer, - .functionality = functionality, -}; - -static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed) -{ - return container_of(feed->demux, struct dm1105_dev, demux); -} - -static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe) -{ - return container_of(fe->dvb, struct dm1105_dev, dvb_adapter); -} - -static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct dm1105_dev *dev = frontend_to_dm1105_dev(fe); - u32 lnb_mask, lnb_13v, lnb_18v, lnb_off; - - switch (dev->boardnr) { - case DM1105_BOARD_AXESS_DM05: - lnb_mask = DM05_LNB_MASK; - lnb_off = DM05_LNB_OFF; - lnb_13v = DM05_LNB_13V; - lnb_18v = DM05_LNB_18V; - break; - case DM1105_BOARD_DVBWORLD_2002: - case DM1105_BOARD_DVBWORLD_2004: - default: - lnb_mask = DM1105_LNB_MASK; - lnb_off = DM1105_LNB_OFF; - lnb_13v = DM1105_LNB_13V; - lnb_18v = DM1105_LNB_18V; - } - - dm_writel(DM1105_GPIOCTR, lnb_mask); - if (voltage == SEC_VOLTAGE_18) - dm_writel(DM1105_GPIOVAL, lnb_18v); - else if (voltage == SEC_VOLTAGE_13) - dm_writel(DM1105_GPIOVAL, lnb_13v); - else - dm_writel(DM1105_GPIOVAL, lnb_off); - - return 0; -} - -static void dm1105_set_dma_addr(struct dm1105_dev *dev) -{ - dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr)); -} - -static int __devinit dm1105_dma_map(struct dm1105_dev *dev) -{ - dev->ts_buf = pci_alloc_consistent(dev->pdev, - 6 * DM1105_DMA_BYTES, - &dev->dma_addr); - - return !dev->ts_buf; -} - -static void dm1105_dma_unmap(struct dm1105_dev *dev) -{ - pci_free_consistent(dev->pdev, - 6 * DM1105_DMA_BYTES, - dev->ts_buf, - dev->dma_addr); -} - -static void dm1105_enable_irqs(struct dm1105_dev *dev) -{ - dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK); - dm_writeb(DM1105_CR, 1); -} - -static void dm1105_disable_irqs(struct dm1105_dev *dev) -{ - dm_writeb(DM1105_INTMAK, INTMAK_IRM); - dm_writeb(DM1105_CR, 0); -} - -static int dm1105_start_feed(struct dvb_demux_feed *f) -{ - struct dm1105_dev *dev = feed_to_dm1105_dev(f); - - if (dev->full_ts_users++ == 0) - dm1105_enable_irqs(dev); - - return 0; -} - -static int dm1105_stop_feed(struct dvb_demux_feed *f) -{ - struct dm1105_dev *dev = feed_to_dm1105_dev(f); - - if (--dev->full_ts_users == 0) - dm1105_disable_irqs(dev); - - return 0; -} - -/* ir work handler */ -static void dm1105_emit_key(struct work_struct *work) -{ - struct infrared *ir = container_of(work, struct infrared, work); - u32 ircom = ir->ir_command; - u8 data; - - if (ir_debug) - printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom); - - data = (ircom >> 8) & 0x7f; - - rc_keydown(ir->dev, data, 0); -} - -/* work handler */ -static void dm1105_dmx_buffer(struct work_struct *work) -{ - struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work); - unsigned int nbpackets; - u32 oldwrp = dev->wrp; - u32 nextwrp = dev->nextwrp; - - if (!((dev->ts_buf[oldwrp] == 0x47) && - (dev->ts_buf[oldwrp + 188] == 0x47) && - (dev->ts_buf[oldwrp + 188 * 2] == 0x47))) { - dev->PacketErrorCount++; - /* bad packet found */ - if ((dev->PacketErrorCount >= 2) && - (dev->dmarst == 0)) { - dm_writeb(DM1105_RST, 1); - dev->wrp = 0; - dev->PacketErrorCount = 0; - dev->dmarst = 0; - return; - } - } - - if (nextwrp < oldwrp) { - memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp); - nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188; - } else - nbpackets = (nextwrp - oldwrp) / 188; - - dev->wrp = nextwrp; - dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets); -} - -static irqreturn_t dm1105_irq(int irq, void *dev_id) -{ - struct dm1105_dev *dev = dev_id; - - /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */ - unsigned int intsts = dm_readb(DM1105_INTSTS); - dm_writeb(DM1105_INTSTS, intsts); - - switch (intsts) { - case INTSTS_TSIRQ: - case (INTSTS_TSIRQ | INTSTS_IR): - dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR); - queue_work(dev->wq, &dev->work); - break; - case INTSTS_IR: - dev->ir.ir_command = dm_readl(DM1105_IRCODE); - schedule_work(&dev->ir.work); - break; - } - - return IRQ_HANDLED; -} - -int __devinit dm1105_ir_init(struct dm1105_dev *dm1105) -{ - struct rc_dev *dev; - int err = -ENOMEM; - - dev = rc_allocate_device(); - if (!dev) - return -ENOMEM; - - snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), - "pci-%s/ir0", pci_name(dm1105->pdev)); - - dev->driver_name = MODULE_NAME; - dev->map_name = RC_MAP_DM1105_NEC; - dev->driver_type = RC_DRIVER_SCANCODE; - dev->input_name = "DVB on-card IR receiver"; - dev->input_phys = dm1105->ir.input_phys; - dev->input_id.bustype = BUS_PCI; - dev->input_id.version = 1; - if (dm1105->pdev->subsystem_vendor) { - dev->input_id.vendor = dm1105->pdev->subsystem_vendor; - dev->input_id.product = dm1105->pdev->subsystem_device; - } else { - dev->input_id.vendor = dm1105->pdev->vendor; - dev->input_id.product = dm1105->pdev->device; - } - dev->dev.parent = &dm1105->pdev->dev; - - INIT_WORK(&dm1105->ir.work, dm1105_emit_key); - - err = rc_register_device(dev); - if (err < 0) { - rc_free_device(dev); - return err; - } - - dm1105->ir.dev = dev; - return 0; -} - -void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105) -{ - rc_unregister_device(dm1105->ir.dev); -} - -static int __devinit dm1105_hw_init(struct dm1105_dev *dev) -{ - dm1105_disable_irqs(dev); - - dm_writeb(DM1105_HOST_CTR, 0); - - /*DATALEN 188,*/ - dm_writeb(DM1105_DTALENTH, 188); - /*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/ - dm_writew(DM1105_TSCTR, 0xc10a); - - /* map DMA and set address */ - dm1105_dma_map(dev); - dm1105_set_dma_addr(dev); - /* big buffer */ - dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES); - dm_writeb(DM1105_INTCNT, 47); - - /* IR NEC mode enable */ - dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK)); - dm_writeb(DM1105_IRMODE, 0); - dm_writew(DM1105_SYSTEMCODE, 0); - - return 0; -} - -static void dm1105_hw_exit(struct dm1105_dev *dev) -{ - dm1105_disable_irqs(dev); - - /* IR disable */ - dm_writeb(DM1105_IRCTR, 0); - dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK); - - dm1105_dma_unmap(dev); -} - -static struct stv0299_config sharp_z0194a_config = { - .demod_address = 0x68, - .inittab = sharp_z0194a_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a_set_symbol_rate, -}; - -static struct stv0288_config earda_config = { - .demod_address = 0x68, - .min_delay_ms = 100, -}; - -static struct si21xx_config serit_config = { - .demod_address = 0x68, - .min_delay_ms = 100, - -}; - -static struct cx24116_config serit_sp2633_config = { - .demod_address = 0x55, -}; - -static struct ds3000_config dvbworld_ds3000_config = { - .demod_address = 0x68, -}; - -static int __devinit frontend_init(struct dm1105_dev *dev) -{ - int ret; - - switch (dev->boardnr) { - case DM1105_BOARD_DVBWORLD_2004: - dev->fe = dvb_attach( - cx24116_attach, &serit_sp2633_config, - &dev->i2c_adap); - if (dev->fe) { - dev->fe->ops.set_voltage = dm1105_set_voltage; - break; - } - - dev->fe = dvb_attach( - ds3000_attach, &dvbworld_ds3000_config, - &dev->i2c_adap); - if (dev->fe) - dev->fe->ops.set_voltage = dm1105_set_voltage; - - break; - case DM1105_BOARD_DVBWORLD_2002: - case DM1105_BOARD_AXESS_DM05: - default: - dev->fe = dvb_attach( - stv0299_attach, &sharp_z0194a_config, - &dev->i2c_adap); - if (dev->fe) { - dev->fe->ops.set_voltage = dm1105_set_voltage; - dvb_attach(dvb_pll_attach, dev->fe, 0x60, - &dev->i2c_adap, DVB_PLL_OPERA1); - break; - } - - dev->fe = dvb_attach( - stv0288_attach, &earda_config, - &dev->i2c_adap); - if (dev->fe) { - dev->fe->ops.set_voltage = dm1105_set_voltage; - dvb_attach(stb6000_attach, dev->fe, 0x61, - &dev->i2c_adap); - break; - } - - dev->fe = dvb_attach( - si21xx_attach, &serit_config, - &dev->i2c_adap); - if (dev->fe) - dev->fe->ops.set_voltage = dm1105_set_voltage; - - } - - if (!dev->fe) { - dev_err(&dev->pdev->dev, "could not attach frontend\n"); - return -ENODEV; - } - - ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe); - if (ret < 0) { - if (dev->fe->ops.release) - dev->fe->ops.release(dev->fe); - dev->fe = NULL; - return ret; - } - - return 0; -} - -static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac) -{ - static u8 command[1] = { 0x28 }; - - struct i2c_msg msg[] = { - { - .addr = IIC_24C01_addr >> 1, - .flags = 0, - .buf = command, - .len = 1 - }, { - .addr = IIC_24C01_addr >> 1, - .flags = I2C_M_RD, - .buf = mac, - .len = 6 - }, - }; - - dm1105_i2c_xfer(&dev->i2c_adap, msg , 2); - dev_info(&dev->pdev->dev, "MAC %pM\n", mac); -} - -static int __devinit dm1105_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct dm1105_dev *dev; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - int ret = -ENOMEM; - int i; - - dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - /* board config */ - dev->nr = dm1105_devcount; - dev->boardnr = UNSET; - if (card[dev->nr] < ARRAY_SIZE(dm1105_boards)) - dev->boardnr = card[dev->nr]; - for (i = 0; UNSET == dev->boardnr && - i < ARRAY_SIZE(dm1105_subids); i++) - if (pdev->subsystem_vendor == - dm1105_subids[i].subvendor && - pdev->subsystem_device == - dm1105_subids[i].subdevice) - dev->boardnr = dm1105_subids[i].card; - - if (UNSET == dev->boardnr) { - dev->boardnr = DM1105_BOARD_UNKNOWN; - dm1105_card_list(pdev); - } - - dm1105_devcount++; - dev->pdev = pdev; - dev->buffer_size = 5 * DM1105_DMA_BYTES; - dev->PacketErrorCount = 0; - dev->dmarst = 0; - - ret = pci_enable_device(pdev); - if (ret < 0) - goto err_kfree; - - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret < 0) - goto err_pci_disable_device; - - pci_set_master(pdev); - - ret = pci_request_regions(pdev, DRIVER_NAME); - if (ret < 0) - goto err_pci_disable_device; - - dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); - if (!dev->io_mem) { - ret = -EIO; - goto err_pci_release_regions; - } - - spin_lock_init(&dev->lock); - pci_set_drvdata(pdev, dev); - - ret = dm1105_hw_init(dev); - if (ret < 0) - goto err_pci_iounmap; - - /* i2c */ - i2c_set_adapdata(&dev->i2c_adap, dev); - strcpy(dev->i2c_adap.name, DRIVER_NAME); - dev->i2c_adap.owner = THIS_MODULE; - dev->i2c_adap.dev.parent = &pdev->dev; - dev->i2c_adap.algo = &dm1105_algo; - dev->i2c_adap.algo_data = dev; - ret = i2c_add_adapter(&dev->i2c_adap); - - if (ret < 0) - goto err_dm1105_hw_exit; - - /* dvb */ - ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME, - THIS_MODULE, &pdev->dev, adapter_nr); - if (ret < 0) - goto err_i2c_del_adapter; - - dvb_adapter = &dev->dvb_adapter; - - dm1105_read_mac(dev, dvb_adapter->proposed_mac); - - dvbdemux = &dev->demux; - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = dm1105_start_feed; - dvbdemux->stop_feed = dm1105_stop_feed; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); - ret = dvb_dmx_init(dvbdemux); - if (ret < 0) - goto err_dvb_unregister_adapter; - - dmx = &dvbdemux->dmx; - dev->dmxdev.filternum = 256; - dev->dmxdev.demux = dmx; - dev->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter); - if (ret < 0) - goto err_dvb_dmx_release; - - dev->hw_frontend.source = DMX_FRONTEND_0; - - ret = dmx->add_frontend(dmx, &dev->hw_frontend); - if (ret < 0) - goto err_dvb_dmxdev_release; - - dev->mem_frontend.source = DMX_MEMORY_FE; - - ret = dmx->add_frontend(dmx, &dev->mem_frontend); - if (ret < 0) - goto err_remove_hw_frontend; - - ret = dmx->connect_frontend(dmx, &dev->hw_frontend); - if (ret < 0) - goto err_remove_mem_frontend; - - ret = frontend_init(dev); - if (ret < 0) - goto err_disconnect_frontend; - - dvb_net_init(dvb_adapter, &dev->dvbnet, dmx); - dm1105_ir_init(dev); - - INIT_WORK(&dev->work, dm1105_dmx_buffer); - sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num); - dev->wq = create_singlethread_workqueue(dev->wqn); - if (!dev->wq) - goto err_dvb_net; - - ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED, - DRIVER_NAME, dev); - if (ret < 0) - goto err_workqueue; - - return 0; - -err_workqueue: - destroy_workqueue(dev->wq); -err_dvb_net: - dvb_net_release(&dev->dvbnet); -err_disconnect_frontend: - dmx->disconnect_frontend(dmx); -err_remove_mem_frontend: - dmx->remove_frontend(dmx, &dev->mem_frontend); -err_remove_hw_frontend: - dmx->remove_frontend(dmx, &dev->hw_frontend); -err_dvb_dmxdev_release: - dvb_dmxdev_release(&dev->dmxdev); -err_dvb_dmx_release: - dvb_dmx_release(dvbdemux); -err_dvb_unregister_adapter: - dvb_unregister_adapter(dvb_adapter); -err_i2c_del_adapter: - i2c_del_adapter(&dev->i2c_adap); -err_dm1105_hw_exit: - dm1105_hw_exit(dev); -err_pci_iounmap: - pci_iounmap(pdev, dev->io_mem); -err_pci_release_regions: - pci_release_regions(pdev); -err_pci_disable_device: - pci_disable_device(pdev); -err_kfree: - pci_set_drvdata(pdev, NULL); - kfree(dev); - return ret; -} - -static void __devexit dm1105_remove(struct pci_dev *pdev) -{ - struct dm1105_dev *dev = pci_get_drvdata(pdev); - struct dvb_adapter *dvb_adapter = &dev->dvb_adapter; - struct dvb_demux *dvbdemux = &dev->demux; - struct dmx_demux *dmx = &dvbdemux->dmx; - - dm1105_ir_exit(dev); - dmx->close(dmx); - dvb_net_release(&dev->dvbnet); - if (dev->fe) - dvb_unregister_frontend(dev->fe); - - dmx->disconnect_frontend(dmx); - dmx->remove_frontend(dmx, &dev->mem_frontend); - dmx->remove_frontend(dmx, &dev->hw_frontend); - dvb_dmxdev_release(&dev->dmxdev); - dvb_dmx_release(dvbdemux); - dvb_unregister_adapter(dvb_adapter); - if (&dev->i2c_adap) - i2c_del_adapter(&dev->i2c_adap); - - dm1105_hw_exit(dev); - synchronize_irq(pdev->irq); - free_irq(pdev->irq, dev); - pci_iounmap(pdev, dev->io_mem); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - dm1105_devcount--; - kfree(dev); -} - -static struct pci_device_id dm1105_id_table[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_TRIGEM, - .device = PCI_DEVICE_ID_DM1105, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { - .vendor = PCI_VENDOR_ID_AXESS, - .device = PCI_DEVICE_ID_DM05, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { - /* empty */ - }, -}; - -MODULE_DEVICE_TABLE(pci, dm1105_id_table); - -static struct pci_driver dm1105_driver = { - .name = DRIVER_NAME, - .id_table = dm1105_id_table, - .probe = dm1105_probe, - .remove = __devexit_p(dm1105_remove), -}; - -static int __init dm1105_init(void) -{ - return pci_register_driver(&dm1105_driver); -} - -static void __exit dm1105_exit(void) -{ - pci_unregister_driver(&dm1105_driver); -} - -module_init(dm1105_init); -module_exit(dm1105_exit); - -MODULE_AUTHOR("Igor M. Liplianin "); -MODULE_DESCRIPTION("SDMC DM1105 DVB driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -config DVB_DM1105 - tristate "SDMC DM1105 based PCI cards" - depends on DVB_CORE && PCI && I2C - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_SI21XX if !DVB_FE_CUSTOMISE - select DVB_DS3000 if !DVB_FE_CUSTOMISE - depends on RC_CORE - help - Support for cards based on the SDMC DM1105 PCI chip like - DvbWorld 2002 - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the PCI bus, so you need - an external software decoder to watch TV on your computer. - - Say Y or M if you own such a device and want to use it. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dm1105/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_DM1105) += dm1105.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/demux.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/demux.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/demux.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/demux.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,280 +0,0 @@ -/* - * demux.h - * - * Copyright (c) 2002 Convergence GmbH - * - * based on code: - * Copyright (c) 2000 Nokia Research Center - * Tampere, FINLAND - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef __DEMUX_H -#define __DEMUX_H - -#include -#include -#include -#include -#include - -/*--------------------------------------------------------------------------*/ -/* Common definitions */ -/*--------------------------------------------------------------------------*/ - -/* - * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter. - */ - -#ifndef DMX_MAX_FILTER_SIZE -#define DMX_MAX_FILTER_SIZE 18 -#endif - -/* - * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter. - */ - -#ifndef DMX_MAX_SECTION_SIZE -#define DMX_MAX_SECTION_SIZE 4096 -#endif -#ifndef DMX_MAX_SECFEED_SIZE -#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188) -#endif - - -/* - * enum dmx_success: Success codes for the Demux Callback API. - */ - -enum dmx_success { - DMX_OK = 0, /* Received Ok */ - DMX_LENGTH_ERROR, /* Incorrect length */ - DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */ - DMX_CRC_ERROR, /* Incorrect CRC */ - DMX_FRAME_ERROR, /* Frame alignment error */ - DMX_FIFO_ERROR, /* Receiver FIFO overrun */ - DMX_MISSED_ERROR /* Receiver missed packet */ -} ; - -/*--------------------------------------------------------------------------*/ -/* TS packet reception */ -/*--------------------------------------------------------------------------*/ - -/* TS filter type for set() */ - -#define TS_PACKET 1 /* send TS packets (188 bytes) to callback (default) */ -#define TS_PAYLOAD_ONLY 2 /* in case TS_PACKET is set, only send the TS - payload (<=184 bytes per packet) to callback */ -#define TS_DECODER 4 /* send stream to built-in decoder (if present) */ -#define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to - the demux device, not to the dvr device */ - -/* PES type for filters which write to built-in decoder */ -/* these should be kept identical to the types in dmx.h */ - -enum dmx_ts_pes -{ /* also send packets to decoder (if it exists) */ - DMX_TS_PES_AUDIO0, - DMX_TS_PES_VIDEO0, - DMX_TS_PES_TELETEXT0, - DMX_TS_PES_SUBTITLE0, - DMX_TS_PES_PCR0, - - DMX_TS_PES_AUDIO1, - DMX_TS_PES_VIDEO1, - DMX_TS_PES_TELETEXT1, - DMX_TS_PES_SUBTITLE1, - DMX_TS_PES_PCR1, - - DMX_TS_PES_AUDIO2, - DMX_TS_PES_VIDEO2, - DMX_TS_PES_TELETEXT2, - DMX_TS_PES_SUBTITLE2, - DMX_TS_PES_PCR2, - - DMX_TS_PES_AUDIO3, - DMX_TS_PES_VIDEO3, - DMX_TS_PES_TELETEXT3, - DMX_TS_PES_SUBTITLE3, - DMX_TS_PES_PCR3, - - DMX_TS_PES_OTHER -}; - -#define DMX_TS_PES_AUDIO DMX_TS_PES_AUDIO0 -#define DMX_TS_PES_VIDEO DMX_TS_PES_VIDEO0 -#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0 -#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0 -#define DMX_TS_PES_PCR DMX_TS_PES_PCR0 - - -struct dmx_ts_feed { - int is_filtering; /* Set to non-zero when filtering in progress */ - struct dmx_demux *parent; /* Back-pointer */ - void *priv; /* Pointer to private data of the API client */ - int (*set) (struct dmx_ts_feed *feed, - u16 pid, - int type, - enum dmx_ts_pes pes_type, - size_t circular_buffer_size, - struct timespec timeout); - int (*start_filtering) (struct dmx_ts_feed* feed); - int (*stop_filtering) (struct dmx_ts_feed* feed); -}; - -/*--------------------------------------------------------------------------*/ -/* Section reception */ -/*--------------------------------------------------------------------------*/ - -struct dmx_section_filter { - u8 filter_value [DMX_MAX_FILTER_SIZE]; - u8 filter_mask [DMX_MAX_FILTER_SIZE]; - u8 filter_mode [DMX_MAX_FILTER_SIZE]; - struct dmx_section_feed* parent; /* Back-pointer */ - void* priv; /* Pointer to private data of the API client */ -}; - -struct dmx_section_feed { - int is_filtering; /* Set to non-zero when filtering in progress */ - struct dmx_demux* parent; /* Back-pointer */ - void* priv; /* Pointer to private data of the API client */ - - int check_crc; - u32 crc_val; - - u8 *secbuf; - u8 secbuf_base[DMX_MAX_SECFEED_SIZE]; - u16 secbufp, seclen, tsfeedp; - - int (*set) (struct dmx_section_feed* feed, - u16 pid, - size_t circular_buffer_size, - int check_crc); - int (*allocate_filter) (struct dmx_section_feed* feed, - struct dmx_section_filter** filter); - int (*release_filter) (struct dmx_section_feed* feed, - struct dmx_section_filter* filter); - int (*start_filtering) (struct dmx_section_feed* feed); - int (*stop_filtering) (struct dmx_section_feed* feed); -}; - -/*--------------------------------------------------------------------------*/ -/* Callback functions */ -/*--------------------------------------------------------------------------*/ - -typedef int (*dmx_ts_cb) ( const u8 * buffer1, - size_t buffer1_length, - const u8 * buffer2, - size_t buffer2_length, - struct dmx_ts_feed* source, - enum dmx_success success); - -typedef int (*dmx_section_cb) ( const u8 * buffer1, - size_t buffer1_len, - const u8 * buffer2, - size_t buffer2_len, - struct dmx_section_filter * source, - enum dmx_success success); - -/*--------------------------------------------------------------------------*/ -/* DVB Front-End */ -/*--------------------------------------------------------------------------*/ - -enum dmx_frontend_source { - DMX_MEMORY_FE, - DMX_FRONTEND_0, - DMX_FRONTEND_1, - DMX_FRONTEND_2, - DMX_FRONTEND_3, - DMX_STREAM_0, /* external stream input, e.g. LVDS */ - DMX_STREAM_1, - DMX_STREAM_2, - DMX_STREAM_3 -}; - -struct dmx_frontend { - struct list_head connectivity_list; /* List of front-ends that can - be connected to a particular - demux */ - enum dmx_frontend_source source; -}; - -/*--------------------------------------------------------------------------*/ -/* MPEG-2 TS Demux */ -/*--------------------------------------------------------------------------*/ - -/* - * Flags OR'ed in the capabilities field of struct dmx_demux. - */ - -#define DMX_TS_FILTERING 1 -#define DMX_PES_FILTERING 2 -#define DMX_SECTION_FILTERING 4 -#define DMX_MEMORY_BASED_FILTERING 8 /* write() available */ -#define DMX_CRC_CHECKING 16 -#define DMX_TS_DESCRAMBLING 32 - -/* - * Demux resource type identifier. -*/ - -/* - * DMX_FE_ENTRY(): Casts elements in the list of registered - * front-ends from the generic type struct list_head - * to the type * struct dmx_frontend - *. -*/ - -#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list) - -struct dmx_demux { - u32 capabilities; /* Bitfield of capability flags */ - struct dmx_frontend* frontend; /* Front-end connected to the demux */ - void* priv; /* Pointer to private data of the API client */ - int (*open) (struct dmx_demux* demux); - int (*close) (struct dmx_demux* demux); - int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count); - int (*allocate_ts_feed) (struct dmx_demux* demux, - struct dmx_ts_feed** feed, - dmx_ts_cb callback); - int (*release_ts_feed) (struct dmx_demux* demux, - struct dmx_ts_feed* feed); - int (*allocate_section_feed) (struct dmx_demux* demux, - struct dmx_section_feed** feed, - dmx_section_cb callback); - int (*release_section_feed) (struct dmx_demux* demux, - struct dmx_section_feed* feed); - int (*add_frontend) (struct dmx_demux* demux, - struct dmx_frontend* frontend); - int (*remove_frontend) (struct dmx_demux* demux, - struct dmx_frontend* frontend); - struct list_head* (*get_frontends) (struct dmx_demux* demux); - int (*connect_frontend) (struct dmx_demux* demux, - struct dmx_frontend* frontend); - int (*disconnect_frontend) (struct dmx_demux* demux); - - int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids); - - int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps); - - int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src); - - int (*get_stc) (struct dmx_demux* demux, unsigned int num, - u64 *stc, unsigned int *base); -}; - -#endif /* #ifndef __DEMUX_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dmxdev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dmxdev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dmxdev.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dmxdev.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1278 +0,0 @@ -/* - * dmxdev.c - DVB demultiplexer device - * - * Copyright (C) 2000 Ralph Metzler & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dmxdev.h" - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk if (debug) printk - -static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, - const u8 *src, size_t len) -{ - ssize_t free; - - if (!len) - return 0; - if (!buf->data) - return 0; - - free = dvb_ringbuffer_free(buf); - if (len > free) { - dprintk("dmxdev: buffer overflow\n"); - return -EOVERFLOW; - } - - return dvb_ringbuffer_write(buf, src, len); -} - -static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, - int non_blocking, char __user *buf, - size_t count, loff_t *ppos) -{ - size_t todo; - ssize_t avail; - ssize_t ret = 0; - - if (!src->data) - return 0; - - if (src->error) { - ret = src->error; - dvb_ringbuffer_flush(src); - return ret; - } - - for (todo = count; todo > 0; todo -= ret) { - if (non_blocking && dvb_ringbuffer_empty(src)) { - ret = -EWOULDBLOCK; - break; - } - - ret = wait_event_interruptible(src->queue, - !dvb_ringbuffer_empty(src) || - (src->error != 0)); - if (ret < 0) - break; - - if (src->error) { - ret = src->error; - dvb_ringbuffer_flush(src); - break; - } - - avail = dvb_ringbuffer_avail(src); - if (avail > todo) - avail = todo; - - ret = dvb_ringbuffer_read_user(src, buf, avail); - if (ret < 0) - break; - - buf += ret; - } - - return (count - todo) ? (count - todo) : ret; -} - -static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type) -{ - struct list_head *head, *pos; - - head = demux->get_frontends(demux); - if (!head) - return NULL; - list_for_each(pos, head) - if (DMX_FE_ENTRY(pos)->source == type) - return DMX_FE_ENTRY(pos); - - return NULL; -} - -static int dvb_dvr_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - struct dmx_frontend *front; - - dprintk("function : %s\n", __func__); - - if (mutex_lock_interruptible(&dmxdev->mutex)) - return -ERESTARTSYS; - - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); - return -ENODEV; - } - - if ((file->f_flags & O_ACCMODE) == O_RDWR) { - if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { - mutex_unlock(&dmxdev->mutex); - return -EOPNOTSUPP; - } - } - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - void *mem; - if (!dvbdev->readers) { - mutex_unlock(&dmxdev->mutex); - return -EBUSY; - } - mem = vmalloc(DVR_BUFFER_SIZE); - if (!mem) { - mutex_unlock(&dmxdev->mutex); - return -ENOMEM; - } - dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); - dvbdev->readers--; - } - - if ((file->f_flags & O_ACCMODE) == O_WRONLY) { - dmxdev->dvr_orig_fe = dmxdev->demux->frontend; - - if (!dmxdev->demux->write) { - mutex_unlock(&dmxdev->mutex); - return -EOPNOTSUPP; - } - - front = get_fe(dmxdev->demux, DMX_MEMORY_FE); - - if (!front) { - mutex_unlock(&dmxdev->mutex); - return -EINVAL; - } - dmxdev->demux->disconnect_frontend(dmxdev->demux); - dmxdev->demux->connect_frontend(dmxdev->demux, front); - } - dvbdev->users++; - mutex_unlock(&dmxdev->mutex); - return 0; -} - -static int dvb_dvr_release(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - - mutex_lock(&dmxdev->mutex); - - if ((file->f_flags & O_ACCMODE) == O_WRONLY) { - dmxdev->demux->disconnect_frontend(dmxdev->demux); - dmxdev->demux->connect_frontend(dmxdev->demux, - dmxdev->dvr_orig_fe); - } - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - dvbdev->readers++; - if (dmxdev->dvr_buffer.data) { - void *mem = dmxdev->dvr_buffer.data; - mb(); - spin_lock_irq(&dmxdev->lock); - dmxdev->dvr_buffer.data = NULL; - spin_unlock_irq(&dmxdev->lock); - vfree(mem); - } - } - /* TODO */ - dvbdev->users--; - if (dvbdev->users == 1 && dmxdev->exit == 1) { - fops_put(file->f_op); - file->f_op = NULL; - mutex_unlock(&dmxdev->mutex); - wake_up(&dvbdev->wait_queue); - } else - mutex_unlock(&dmxdev->mutex); - - return 0; -} - -static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - int ret; - - if (!dmxdev->demux->write) - return -EOPNOTSUPP; - if ((file->f_flags & O_ACCMODE) != O_WRONLY) - return -EINVAL; - if (mutex_lock_interruptible(&dmxdev->mutex)) - return -ERESTARTSYS; - - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); - return -ENODEV; - } - ret = dmxdev->demux->write(dmxdev->demux, buf, count); - mutex_unlock(&dmxdev->mutex); - return ret; -} - -static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - - if (dmxdev->exit) - return -ENODEV; - - return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); -} - -static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, - unsigned long size) -{ - struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer; - void *newmem; - void *oldmem; - - dprintk("function : %s\n", __func__); - - if (buf->size == size) - return 0; - if (!size) - return -EINVAL; - - newmem = vmalloc(size); - if (!newmem) - return -ENOMEM; - - oldmem = buf->data; - - spin_lock_irq(&dmxdev->lock); - buf->data = newmem; - buf->size = size; - - /* reset and not flush in case the buffer shrinks */ - dvb_ringbuffer_reset(buf); - spin_unlock_irq(&dmxdev->lock); - - vfree(oldmem); - - return 0; -} - -static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter - *dmxdevfilter, int state) -{ - spin_lock_irq(&dmxdevfilter->dev->lock); - dmxdevfilter->state = state; - spin_unlock_irq(&dmxdevfilter->dev->lock); -} - -static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, - unsigned long size) -{ - struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; - void *newmem; - void *oldmem; - - if (buf->size == size) - return 0; - if (!size) - return -EINVAL; - if (dmxdevfilter->state >= DMXDEV_STATE_GO) - return -EBUSY; - - newmem = vmalloc(size); - if (!newmem) - return -ENOMEM; - - oldmem = buf->data; - - spin_lock_irq(&dmxdevfilter->dev->lock); - buf->data = newmem; - buf->size = size; - - /* reset and not flush in case the buffer shrinks */ - dvb_ringbuffer_reset(buf); - spin_unlock_irq(&dmxdevfilter->dev->lock); - - vfree(oldmem); - - return 0; -} - -static void dvb_dmxdev_filter_timeout(unsigned long data) -{ - struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; - - dmxdevfilter->buffer.error = -ETIMEDOUT; - spin_lock_irq(&dmxdevfilter->dev->lock); - dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; - spin_unlock_irq(&dmxdevfilter->dev->lock); - wake_up(&dmxdevfilter->buffer.queue); -} - -static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) -{ - struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec; - - del_timer(&dmxdevfilter->timer); - if (para->timeout) { - dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout; - dmxdevfilter->timer.data = (unsigned long)dmxdevfilter; - dmxdevfilter->timer.expires = - jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; - add_timer(&dmxdevfilter->timer); - } -} - -static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *filter, - enum dmx_success success) -{ - struct dmxdev_filter *dmxdevfilter = filter->priv; - int ret; - - if (dmxdevfilter->buffer.error) { - wake_up(&dmxdevfilter->buffer.queue); - return 0; - } - spin_lock(&dmxdevfilter->dev->lock); - if (dmxdevfilter->state != DMXDEV_STATE_GO) { - spin_unlock(&dmxdevfilter->dev->lock); - return 0; - } - del_timer(&dmxdevfilter->timer); - dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n", - buffer1[0], buffer1[1], - buffer1[2], buffer1[3], buffer1[4], buffer1[5]); - ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, - buffer1_len); - if (ret == buffer1_len) { - ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, - buffer2_len); - } - if (ret < 0) { - dvb_ringbuffer_flush(&dmxdevfilter->buffer); - dmxdevfilter->buffer.error = ret; - } - if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) - dmxdevfilter->state = DMXDEV_STATE_DONE; - spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&dmxdevfilter->buffer.queue); - return 0; -} - -static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed, - enum dmx_success success) -{ - struct dmxdev_filter *dmxdevfilter = feed->priv; - struct dvb_ringbuffer *buffer; - int ret; - - spin_lock(&dmxdevfilter->dev->lock); - if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { - spin_unlock(&dmxdevfilter->dev->lock); - return 0; - } - - if (dmxdevfilter->params.pes.output == DMX_OUT_TAP - || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) - buffer = &dmxdevfilter->buffer; - else - buffer = &dmxdevfilter->dev->dvr_buffer; - if (buffer->error) { - spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&buffer->queue); - return 0; - } - ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); - if (ret == buffer1_len) - ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); - if (ret < 0) { - dvb_ringbuffer_flush(buffer); - buffer->error = ret; - } - spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&buffer->queue); - return 0; -} - -/* stop feed but only mark the specified filter as stopped (state set) */ -static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) -{ - struct dmxdev_feed *feed; - - dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); - - switch (dmxdevfilter->type) { - case DMXDEV_TYPE_SEC: - del_timer(&dmxdevfilter->timer); - dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); - break; - case DMXDEV_TYPE_PES: - list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) - feed->ts->stop_filtering(feed->ts); - break; - default: - return -EINVAL; - } - return 0; -} - -/* start feed associated with the specified filter */ -static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) -{ - struct dmxdev_feed *feed; - int ret; - - dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); - - switch (filter->type) { - case DMXDEV_TYPE_SEC: - return filter->feed.sec->start_filtering(filter->feed.sec); - case DMXDEV_TYPE_PES: - list_for_each_entry(feed, &filter->feed.ts, next) { - ret = feed->ts->start_filtering(feed->ts); - if (ret < 0) { - dvb_dmxdev_feed_stop(filter); - return ret; - } - } - break; - default: - return -EINVAL; - } - - return 0; -} - -/* restart section feed if it has filters left associated with it, - otherwise release the feed */ -static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) -{ - int i; - struct dmxdev *dmxdev = filter->dev; - u16 pid = filter->params.sec.pid; - - for (i = 0; i < dmxdev->filternum; i++) - if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && - dmxdev->filter[i].type == DMXDEV_TYPE_SEC && - dmxdev->filter[i].params.sec.pid == pid) { - dvb_dmxdev_feed_start(&dmxdev->filter[i]); - return 0; - } - - filter->dev->demux->release_section_feed(dmxdev->demux, - filter->feed.sec); - - return 0; -} - -static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) -{ - struct dmxdev_feed *feed; - struct dmx_demux *demux; - - if (dmxdevfilter->state < DMXDEV_STATE_GO) - return 0; - - switch (dmxdevfilter->type) { - case DMXDEV_TYPE_SEC: - if (!dmxdevfilter->feed.sec) - break; - dvb_dmxdev_feed_stop(dmxdevfilter); - if (dmxdevfilter->filter.sec) - dmxdevfilter->feed.sec-> - release_filter(dmxdevfilter->feed.sec, - dmxdevfilter->filter.sec); - dvb_dmxdev_feed_restart(dmxdevfilter); - dmxdevfilter->feed.sec = NULL; - break; - case DMXDEV_TYPE_PES: - dvb_dmxdev_feed_stop(dmxdevfilter); - demux = dmxdevfilter->dev->demux; - list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { - demux->release_ts_feed(demux, feed->ts); - feed->ts = NULL; - } - break; - default: - if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) - return 0; - return -EINVAL; - } - - dvb_ringbuffer_flush(&dmxdevfilter->buffer); - return 0; -} - -static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter) -{ - struct dmxdev_feed *feed, *tmp; - - /* delete all PIDs */ - list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) { - list_del(&feed->next); - kfree(feed); - } - - BUG_ON(!list_empty(&dmxdevfilter->feed.ts)); -} - -static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) -{ - if (dmxdevfilter->state < DMXDEV_STATE_SET) - return 0; - - if (dmxdevfilter->type == DMXDEV_TYPE_PES) - dvb_dmxdev_delete_pids(dmxdevfilter); - - dmxdevfilter->type = DMXDEV_TYPE_NONE; - dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - return 0; -} - -static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, - struct dmxdev_filter *filter, - struct dmxdev_feed *feed) -{ - struct timespec timeout = { 0 }; - struct dmx_pes_filter_params *para = &filter->params.pes; - dmx_output_t otype; - int ret; - int ts_type; - dmx_pes_type_t ts_pes; - struct dmx_ts_feed *tsfeed; - - feed->ts = NULL; - otype = para->output; - - ts_pes = para->pes_type; - - if (ts_pes < DMX_PES_OTHER) - ts_type = TS_DECODER; - else - ts_type = 0; - - if (otype == DMX_OUT_TS_TAP) - ts_type |= TS_PACKET; - else if (otype == DMX_OUT_TSDEMUX_TAP) - ts_type |= TS_PACKET | TS_DEMUX; - else if (otype == DMX_OUT_TAP) - ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY; - - ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts, - dvb_dmxdev_ts_callback); - if (ret < 0) - return ret; - - tsfeed = feed->ts; - tsfeed->priv = filter; - - ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout); - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); - return ret; - } - - ret = tsfeed->start_filtering(tsfeed); - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); - return ret; - } - - return 0; -} - -static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) -{ - struct dmxdev *dmxdev = filter->dev; - struct dmxdev_feed *feed; - void *mem; - int ret, i; - - if (filter->state < DMXDEV_STATE_SET) - return -EINVAL; - - if (filter->state >= DMXDEV_STATE_GO) - dvb_dmxdev_filter_stop(filter); - - if (!filter->buffer.data) { - mem = vmalloc(filter->buffer.size); - if (!mem) - return -ENOMEM; - spin_lock_irq(&filter->dev->lock); - filter->buffer.data = mem; - spin_unlock_irq(&filter->dev->lock); - } - - dvb_ringbuffer_flush(&filter->buffer); - - switch (filter->type) { - case DMXDEV_TYPE_SEC: - { - struct dmx_sct_filter_params *para = &filter->params.sec; - struct dmx_section_filter **secfilter = &filter->filter.sec; - struct dmx_section_feed **secfeed = &filter->feed.sec; - - *secfilter = NULL; - *secfeed = NULL; - - - /* find active filter/feed with same PID */ - for (i = 0; i < dmxdev->filternum; i++) { - if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && - dmxdev->filter[i].type == DMXDEV_TYPE_SEC && - dmxdev->filter[i].params.sec.pid == para->pid) { - *secfeed = dmxdev->filter[i].feed.sec; - break; - } - } - - /* if no feed found, try to allocate new one */ - if (!*secfeed) { - ret = dmxdev->demux->allocate_section_feed(dmxdev->demux, - secfeed, - dvb_dmxdev_section_callback); - if (ret < 0) { - printk("DVB (%s): could not alloc feed\n", - __func__); - return ret; - } - - ret = (*secfeed)->set(*secfeed, para->pid, 32768, - (para->flags & DMX_CHECK_CRC) ? 1 : 0); - if (ret < 0) { - printk("DVB (%s): could not set feed\n", - __func__); - dvb_dmxdev_feed_restart(filter); - return ret; - } - } else { - dvb_dmxdev_feed_stop(filter); - } - - ret = (*secfeed)->allocate_filter(*secfeed, secfilter); - if (ret < 0) { - dvb_dmxdev_feed_restart(filter); - filter->feed.sec->start_filtering(*secfeed); - dprintk("could not get filter\n"); - return ret; - } - - (*secfilter)->priv = filter; - - memcpy(&((*secfilter)->filter_value[3]), - &(para->filter.filter[1]), DMX_FILTER_SIZE - 1); - memcpy(&(*secfilter)->filter_mask[3], - ¶->filter.mask[1], DMX_FILTER_SIZE - 1); - memcpy(&(*secfilter)->filter_mode[3], - ¶->filter.mode[1], DMX_FILTER_SIZE - 1); - - (*secfilter)->filter_value[0] = para->filter.filter[0]; - (*secfilter)->filter_mask[0] = para->filter.mask[0]; - (*secfilter)->filter_mode[0] = para->filter.mode[0]; - (*secfilter)->filter_mask[1] = 0; - (*secfilter)->filter_mask[2] = 0; - - filter->todo = 0; - - ret = filter->feed.sec->start_filtering(filter->feed.sec); - if (ret < 0) - return ret; - - dvb_dmxdev_filter_timer(filter); - break; - } - case DMXDEV_TYPE_PES: - list_for_each_entry(feed, &filter->feed.ts, next) { - ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); - if (ret < 0) { - dvb_dmxdev_filter_stop(filter); - return ret; - } - } - break; - default: - return -EINVAL; - } - - dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); - return 0; -} - -static int dvb_demux_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - int i; - struct dmxdev_filter *dmxdevfilter; - - if (!dmxdev->filter) - return -EINVAL; - - if (mutex_lock_interruptible(&dmxdev->mutex)) - return -ERESTARTSYS; - - for (i = 0; i < dmxdev->filternum; i++) - if (dmxdev->filter[i].state == DMXDEV_STATE_FREE) - break; - - if (i == dmxdev->filternum) { - mutex_unlock(&dmxdev->mutex); - return -EMFILE; - } - - dmxdevfilter = &dmxdev->filter[i]; - mutex_init(&dmxdevfilter->mutex); - file->private_data = dmxdevfilter; - - dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); - dmxdevfilter->type = DMXDEV_TYPE_NONE; - dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - init_timer(&dmxdevfilter->timer); - - dvbdev->users++; - - mutex_unlock(&dmxdev->mutex); - return 0; -} - -static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, - struct dmxdev_filter *dmxdevfilter) -{ - mutex_lock(&dmxdev->mutex); - mutex_lock(&dmxdevfilter->mutex); - - dvb_dmxdev_filter_stop(dmxdevfilter); - dvb_dmxdev_filter_reset(dmxdevfilter); - - if (dmxdevfilter->buffer.data) { - void *mem = dmxdevfilter->buffer.data; - - spin_lock_irq(&dmxdev->lock); - dmxdevfilter->buffer.data = NULL; - spin_unlock_irq(&dmxdev->lock); - vfree(mem); - } - - dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); - wake_up(&dmxdevfilter->buffer.queue); - mutex_unlock(&dmxdevfilter->mutex); - mutex_unlock(&dmxdev->mutex); - return 0; -} - -static inline void invert_mode(dmx_filter_t *filter) -{ - int i; - - for (i = 0; i < DMX_FILTER_SIZE; i++) - filter->mode[i] ^= 0xff; -} - -static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, - struct dmxdev_filter *filter, u16 pid) -{ - struct dmxdev_feed *feed; - - if ((filter->type != DMXDEV_TYPE_PES) || - (filter->state < DMXDEV_STATE_SET)) - return -EINVAL; - - /* only TS packet filters may have multiple PIDs */ - if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) && - (!list_empty(&filter->feed.ts))) - return -EINVAL; - - feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL); - if (feed == NULL) - return -ENOMEM; - - feed->pid = pid; - list_add(&feed->next, &filter->feed.ts); - - if (filter->state >= DMXDEV_STATE_GO) - return dvb_dmxdev_start_feed(dmxdev, filter, feed); - - return 0; -} - -static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev, - struct dmxdev_filter *filter, u16 pid) -{ - struct dmxdev_feed *feed, *tmp; - - if ((filter->type != DMXDEV_TYPE_PES) || - (filter->state < DMXDEV_STATE_SET)) - return -EINVAL; - - list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) { - if ((feed->pid == pid) && (feed->ts != NULL)) { - feed->ts->stop_filtering(feed->ts); - filter->dev->demux->release_ts_feed(filter->dev->demux, - feed->ts); - list_del(&feed->next); - kfree(feed); - } - } - - return 0; -} - -static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, - struct dmxdev_filter *dmxdevfilter, - struct dmx_sct_filter_params *params) -{ - dprintk("function : %s\n", __func__); - - dvb_dmxdev_filter_stop(dmxdevfilter); - - dmxdevfilter->type = DMXDEV_TYPE_SEC; - memcpy(&dmxdevfilter->params.sec, - params, sizeof(struct dmx_sct_filter_params)); - invert_mode(&dmxdevfilter->params.sec.filter); - dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); - - if (params->flags & DMX_IMMEDIATE_START) - return dvb_dmxdev_filter_start(dmxdevfilter); - - return 0; -} - -static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, - struct dmxdev_filter *dmxdevfilter, - struct dmx_pes_filter_params *params) -{ - int ret; - - dvb_dmxdev_filter_stop(dmxdevfilter); - dvb_dmxdev_filter_reset(dmxdevfilter); - - if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0) - return -EINVAL; - - dmxdevfilter->type = DMXDEV_TYPE_PES; - memcpy(&dmxdevfilter->params, params, - sizeof(struct dmx_pes_filter_params)); - INIT_LIST_HEAD(&dmxdevfilter->feed.ts); - - dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); - - ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, - dmxdevfilter->params.pes.pid); - if (ret < 0) - return ret; - - if (params->flags & DMX_IMMEDIATE_START) - return dvb_dmxdev_filter_start(dmxdevfilter); - - return 0; -} - -static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, - struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - int result, hcount; - int done = 0; - - if (dfil->todo <= 0) { - hcount = 3 + dfil->todo; - if (hcount > count) - hcount = count; - result = dvb_dmxdev_buffer_read(&dfil->buffer, - file->f_flags & O_NONBLOCK, - buf, hcount, ppos); - if (result < 0) { - dfil->todo = 0; - return result; - } - if (copy_from_user(dfil->secheader - dfil->todo, buf, result)) - return -EFAULT; - buf += result; - done = result; - count -= result; - dfil->todo -= result; - if (dfil->todo > -3) - return done; - dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff; - if (!count) - return done; - } - if (count > dfil->todo) - count = dfil->todo; - result = dvb_dmxdev_buffer_read(&dfil->buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); - if (result < 0) - return result; - dfil->todo -= result; - return (result + done); -} - -static ssize_t -dvb_demux_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct dmxdev_filter *dmxdevfilter = file->private_data; - int ret; - - if (mutex_lock_interruptible(&dmxdevfilter->mutex)) - return -ERESTARTSYS; - - if (dmxdevfilter->type == DMXDEV_TYPE_SEC) - ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); - else - ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); - - mutex_unlock(&dmxdevfilter->mutex); - return ret; -} - -static int dvb_demux_do_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dmxdev_filter *dmxdevfilter = file->private_data; - struct dmxdev *dmxdev = dmxdevfilter->dev; - unsigned long arg = (unsigned long)parg; - int ret = 0; - - if (mutex_lock_interruptible(&dmxdev->mutex)) - return -ERESTARTSYS; - - switch (cmd) { - case DMX_START: - if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { - mutex_unlock(&dmxdev->mutex); - return -ERESTARTSYS; - } - if (dmxdevfilter->state < DMXDEV_STATE_SET) - ret = -EINVAL; - else - ret = dvb_dmxdev_filter_start(dmxdevfilter); - mutex_unlock(&dmxdevfilter->mutex); - break; - - case DMX_STOP: - if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { - mutex_unlock(&dmxdev->mutex); - return -ERESTARTSYS; - } - ret = dvb_dmxdev_filter_stop(dmxdevfilter); - mutex_unlock(&dmxdevfilter->mutex); - break; - - case DMX_SET_FILTER: - if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { - mutex_unlock(&dmxdev->mutex); - return -ERESTARTSYS; - } - ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); - mutex_unlock(&dmxdevfilter->mutex); - break; - - case DMX_SET_PES_FILTER: - if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { - mutex_unlock(&dmxdev->mutex); - return -ERESTARTSYS; - } - ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); - mutex_unlock(&dmxdevfilter->mutex); - break; - - case DMX_SET_BUFFER_SIZE: - if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { - mutex_unlock(&dmxdev->mutex); - return -ERESTARTSYS; - } - ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); - mutex_unlock(&dmxdevfilter->mutex); - break; - - case DMX_GET_PES_PIDS: - if (!dmxdev->demux->get_pes_pids) { - ret = -EINVAL; - break; - } - dmxdev->demux->get_pes_pids(dmxdev->demux, parg); - break; - - case DMX_GET_CAPS: - if (!dmxdev->demux->get_caps) { - ret = -EINVAL; - break; - } - ret = dmxdev->demux->get_caps(dmxdev->demux, parg); - break; - - case DMX_SET_SOURCE: - if (!dmxdev->demux->set_source) { - ret = -EINVAL; - break; - } - ret = dmxdev->demux->set_source(dmxdev->demux, parg); - break; - - case DMX_GET_STC: - if (!dmxdev->demux->get_stc) { - ret = -EINVAL; - break; - } - ret = dmxdev->demux->get_stc(dmxdev->demux, - ((struct dmx_stc *)parg)->num, - &((struct dmx_stc *)parg)->stc, - &((struct dmx_stc *)parg)->base); - break; - - case DMX_ADD_PID: - if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { - ret = -ERESTARTSYS; - break; - } - ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg); - mutex_unlock(&dmxdevfilter->mutex); - break; - - case DMX_REMOVE_PID: - if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { - ret = -ERESTARTSYS; - break; - } - ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg); - mutex_unlock(&dmxdevfilter->mutex); - break; - - default: - ret = -EINVAL; - break; - } - mutex_unlock(&dmxdev->mutex); - return ret; -} - -static long dvb_demux_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); -} - -static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) -{ - struct dmxdev_filter *dmxdevfilter = file->private_data; - unsigned int mask = 0; - - if (!dmxdevfilter) - return -EINVAL; - - poll_wait(file, &dmxdevfilter->buffer.queue, wait); - - if (dmxdevfilter->state != DMXDEV_STATE_GO && - dmxdevfilter->state != DMXDEV_STATE_DONE && - dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) - return 0; - - if (dmxdevfilter->buffer.error) - mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); - - if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) - mask |= (POLLIN | POLLRDNORM | POLLPRI); - - return mask; -} - -static int dvb_demux_release(struct inode *inode, struct file *file) -{ - struct dmxdev_filter *dmxdevfilter = file->private_data; - struct dmxdev *dmxdev = dmxdevfilter->dev; - - int ret; - - ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); - - mutex_lock(&dmxdev->mutex); - dmxdev->dvbdev->users--; - if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) { - fops_put(file->f_op); - file->f_op = NULL; - mutex_unlock(&dmxdev->mutex); - wake_up(&dmxdev->dvbdev->wait_queue); - } else - mutex_unlock(&dmxdev->mutex); - - return ret; -} - -static const struct file_operations dvb_demux_fops = { - .owner = THIS_MODULE, - .read = dvb_demux_read, - .unlocked_ioctl = dvb_demux_ioctl, - .open = dvb_demux_open, - .release = dvb_demux_release, - .poll = dvb_demux_poll, - .llseek = default_llseek, -}; - -static struct dvb_device dvbdev_demux = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_demux_fops -}; - -static int dvb_dvr_do_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - unsigned long arg = (unsigned long)parg; - int ret; - - if (mutex_lock_interruptible(&dmxdev->mutex)) - return -ERESTARTSYS; - - switch (cmd) { - case DMX_SET_BUFFER_SIZE: - ret = dvb_dvr_set_buffer_size(dmxdev, arg); - break; - - default: - ret = -EINVAL; - break; - } - mutex_unlock(&dmxdev->mutex); - return ret; -} - -static long dvb_dvr_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); -} - -static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - unsigned int mask = 0; - - dprintk("function : %s\n", __func__); - - poll_wait(file, &dmxdev->dvr_buffer.queue, wait); - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - if (dmxdev->dvr_buffer.error) - mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); - - if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) - mask |= (POLLIN | POLLRDNORM | POLLPRI); - } else - mask |= (POLLOUT | POLLWRNORM | POLLPRI); - - return mask; -} - -static const struct file_operations dvb_dvr_fops = { - .owner = THIS_MODULE, - .read = dvb_dvr_read, - .write = dvb_dvr_write, - .unlocked_ioctl = dvb_dvr_ioctl, - .open = dvb_dvr_open, - .release = dvb_dvr_release, - .poll = dvb_dvr_poll, - .llseek = default_llseek, -}; - -static struct dvb_device dvbdev_dvr = { - .priv = NULL, - .readers = 1, - .users = 1, - .fops = &dvb_dvr_fops -}; - -int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) -{ - int i; - - if (dmxdev->demux->open(dmxdev->demux) < 0) - return -EUSERS; - - dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter)); - if (!dmxdev->filter) - return -ENOMEM; - - mutex_init(&dmxdev->mutex); - spin_lock_init(&dmxdev->lock); - for (i = 0; i < dmxdev->filternum; i++) { - dmxdev->filter[i].dev = dmxdev; - dmxdev->filter[i].buffer.data = NULL; - dvb_dmxdev_filter_state_set(&dmxdev->filter[i], - DMXDEV_STATE_FREE); - } - - dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, - DVB_DEVICE_DEMUX); - dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, - dmxdev, DVB_DEVICE_DVR); - - dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); - - return 0; -} - -EXPORT_SYMBOL(dvb_dmxdev_init); - -void dvb_dmxdev_release(struct dmxdev *dmxdev) -{ - dmxdev->exit=1; - if (dmxdev->dvbdev->users > 1) { - wait_event(dmxdev->dvbdev->wait_queue, - dmxdev->dvbdev->users==1); - } - if (dmxdev->dvr_dvbdev->users > 1) { - wait_event(dmxdev->dvr_dvbdev->wait_queue, - dmxdev->dvr_dvbdev->users==1); - } - - dvb_unregister_device(dmxdev->dvbdev); - dvb_unregister_device(dmxdev->dvr_dvbdev); - - vfree(dmxdev->filter); - dmxdev->filter = NULL; - dmxdev->demux->close(dmxdev->demux); -} - -EXPORT_SYMBOL(dvb_dmxdev_release); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dmxdev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dmxdev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dmxdev.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dmxdev.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -/* - * dmxdev.h - * - * Copyright (C) 2000 Ralph Metzler & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DMXDEV_H_ -#define _DMXDEV_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "dvbdev.h" -#include "demux.h" -#include "dvb_ringbuffer.h" - -enum dmxdev_type { - DMXDEV_TYPE_NONE, - DMXDEV_TYPE_SEC, - DMXDEV_TYPE_PES, -}; - -enum dmxdev_state { - DMXDEV_STATE_FREE, - DMXDEV_STATE_ALLOCATED, - DMXDEV_STATE_SET, - DMXDEV_STATE_GO, - DMXDEV_STATE_DONE, - DMXDEV_STATE_TIMEDOUT -}; - -struct dmxdev_feed { - u16 pid; - struct dmx_ts_feed *ts; - struct list_head next; -}; - -struct dmxdev_filter { - union { - struct dmx_section_filter *sec; - } filter; - - union { - /* list of TS and PES feeds (struct dmxdev_feed) */ - struct list_head ts; - struct dmx_section_feed *sec; - } feed; - - union { - struct dmx_sct_filter_params sec; - struct dmx_pes_filter_params pes; - } params; - - enum dmxdev_type type; - enum dmxdev_state state; - struct dmxdev *dev; - struct dvb_ringbuffer buffer; - - struct mutex mutex; - - /* only for sections */ - struct timer_list timer; - int todo; - u8 secheader[3]; -}; - - -struct dmxdev { - struct dvb_device *dvbdev; - struct dvb_device *dvr_dvbdev; - - struct dmxdev_filter *filter; - struct dmx_demux *demux; - - int filternum; - int capabilities; - - unsigned int exit:1; -#define DMXDEV_CAP_DUPLEX 1 - struct dmx_frontend *dvr_orig_fe; - - struct dvb_ringbuffer dvr_buffer; -#define DVR_BUFFER_SIZE (10*188*1024) - - struct mutex mutex; - spinlock_t lock; -}; - - -int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *); -void dvb_dmxdev_release(struct dmxdev *dmxdev); - -#endif /* _DMXDEV_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1749 +0,0 @@ -/* - * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces - * - * Copyright (C) 2004 Andrew de Quincey - * - * Parts of this file were based on sources as follows: - * - * Copyright (C) 2003 Ralph Metzler - * - * based on code: - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * 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, or (at your option) any later version. - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_ca_en50221.h" -#include "dvb_ringbuffer.h" - -static int dvb_ca_en50221_debug; - -module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644); -MODULE_PARM_DESC(cam_debug, "enable verbose debug messages"); - -#define dprintk if (dvb_ca_en50221_debug) printk - -#define INIT_TIMEOUT_SECS 10 - -#define HOST_LINK_BUF_SIZE 0x200 - -#define RX_BUFFER_SIZE 65535 - -#define MAX_RX_PACKETS_PER_ITERATION 10 - -#define CTRLIF_DATA 0 -#define CTRLIF_COMMAND 1 -#define CTRLIF_STATUS 1 -#define CTRLIF_SIZE_LOW 2 -#define CTRLIF_SIZE_HIGH 3 - -#define CMDREG_HC 1 /* Host control */ -#define CMDREG_SW 2 /* Size write */ -#define CMDREG_SR 4 /* Size read */ -#define CMDREG_RS 8 /* Reset interface */ -#define CMDREG_FRIE 0x40 /* Enable FR interrupt */ -#define CMDREG_DAIE 0x80 /* Enable DA interrupt */ -#define IRQEN (CMDREG_DAIE) - -#define STATUSREG_RE 1 /* read error */ -#define STATUSREG_WE 2 /* write error */ -#define STATUSREG_FR 0x40 /* module free */ -#define STATUSREG_DA 0x80 /* data available */ -#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE) /* general transfer error */ - - -#define DVB_CA_SLOTSTATE_NONE 0 -#define DVB_CA_SLOTSTATE_UNINITIALISED 1 -#define DVB_CA_SLOTSTATE_RUNNING 2 -#define DVB_CA_SLOTSTATE_INVALID 3 -#define DVB_CA_SLOTSTATE_WAITREADY 4 -#define DVB_CA_SLOTSTATE_VALIDATE 5 -#define DVB_CA_SLOTSTATE_WAITFR 6 -#define DVB_CA_SLOTSTATE_LINKINIT 7 - - -/* Information on a CA slot */ -struct dvb_ca_slot { - - /* current state of the CAM */ - int slot_state; - - /* mutex used for serializing access to one CI slot */ - struct mutex slot_lock; - - /* Number of CAMCHANGES that have occurred since last processing */ - atomic_t camchange_count; - - /* Type of last CAMCHANGE */ - int camchange_type; - - /* base address of CAM config */ - u32 config_base; - - /* value to write into Config Control register */ - u8 config_option; - - /* if 1, the CAM supports DA IRQs */ - u8 da_irq_supported:1; - - /* size of the buffer to use when talking to the CAM */ - int link_buf_size; - - /* buffer for incoming packets */ - struct dvb_ringbuffer rx_buffer; - - /* timer used during various states of the slot */ - unsigned long timeout; -}; - -/* Private CA-interface information */ -struct dvb_ca_private { - - /* pointer back to the public data structure */ - struct dvb_ca_en50221 *pub; - - /* the DVB device */ - struct dvb_device *dvbdev; - - /* Flags describing the interface (DVB_CA_FLAG_*) */ - u32 flags; - - /* number of slots supported by this CA interface */ - unsigned int slot_count; - - /* information on each slot */ - struct dvb_ca_slot *slot_info; - - /* wait queues for read() and write() operations */ - wait_queue_head_t wait_queue; - - /* PID of the monitoring thread */ - struct task_struct *thread; - - /* Flag indicating if the CA device is open */ - unsigned int open:1; - - /* Flag indicating the thread should wake up now */ - unsigned int wakeup:1; - - /* Delay the main thread should use */ - unsigned long delay; - - /* Slot to start looking for data to read from in the next user-space read operation */ - int next_read_slot; -}; - -static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); -static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); -static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); - - -/** - * Safely find needle in haystack. - * - * @param haystack Buffer to look in. - * @param hlen Number of bytes in haystack. - * @param needle Buffer to find. - * @param nlen Number of bytes in needle. - * @return Pointer into haystack needle was found at, or NULL if not found. - */ -static char *findstr(char * haystack, int hlen, char * needle, int nlen) -{ - int i; - - if (hlen < nlen) - return NULL; - - for (i = 0; i <= hlen - nlen; i++) { - if (!strncmp(haystack + i, needle, nlen)) - return haystack + i; - } - - return NULL; -} - - - -/* ******************************************************************************** */ -/* EN50221 physical interface functions */ - - -/** - * Check CAM status. - */ -static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) -{ - int slot_status; - int cam_present_now; - int cam_changed; - - /* IRQ mode */ - if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) { - return (atomic_read(&ca->slot_info[slot].camchange_count) != 0); - } - - /* poll mode */ - slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open); - - cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0; - cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0; - if (!cam_changed) { - int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE); - cam_changed = (cam_present_now != cam_present_old); - } - - if (cam_changed) { - if (!cam_present_now) { - ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; - } else { - ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED; - } - atomic_set(&ca->slot_info[slot].camchange_count, 1); - } else { - if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) && - (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) { - // move to validate state if reset is completed - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; - } - } - - return cam_changed; -} - - -/** - * Wait for flags to become set on the STATUS register on a CAM interface, - * checking for errors and timeout. - * - * @param ca CA instance. - * @param slot Slot on interface. - * @param waitfor Flags to wait for. - * @param timeout_ms Timeout in milliseconds. - * - * @return 0 on success, nonzero on error. - */ -static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, - u8 waitfor, int timeout_hz) -{ - unsigned long timeout; - unsigned long start; - - dprintk("%s\n", __func__); - - /* loop until timeout elapsed */ - start = jiffies; - timeout = jiffies + timeout_hz; - while (1) { - /* read the status and check for error */ - int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); - if (res < 0) - return -EIO; - - /* if we got the flags, it was successful! */ - if (res & waitfor) { - dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start); - return 0; - } - - /* check for timeout */ - if (time_after(jiffies, timeout)) { - break; - } - - /* wait for a bit */ - msleep(1); - } - - dprintk("%s failed timeout:%lu\n", __func__, jiffies - start); - - /* if we get here, we've timed out */ - return -ETIMEDOUT; -} - - -/** - * Initialise the link layer connection to a CAM. - * - * @param ca CA instance. - * @param slot Slot id. - * - * @return 0 on success, nonzero on failure. - */ -static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) -{ - int ret; - int buf_size; - u8 buf[2]; - - dprintk("%s\n", __func__); - - /* we'll be determining these during this function */ - ca->slot_info[slot].da_irq_supported = 0; - - /* set the host link buffer size temporarily. it will be overwritten with the - * real negotiated size later. */ - ca->slot_info[slot].link_buf_size = 2; - - /* read the buffer size from the CAM */ - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0) - return ret; - if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0) - return ret; - if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) - return -EIO; - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) - return ret; - - /* store it, and choose the minimum of our buffer and the CAM's buffer size */ - buf_size = (buf[0] << 8) | buf[1]; - if (buf_size > HOST_LINK_BUF_SIZE) - buf_size = HOST_LINK_BUF_SIZE; - ca->slot_info[slot].link_buf_size = buf_size; - buf[0] = buf_size >> 8; - buf[1] = buf_size & 0xff; - dprintk("Chosen link buffer size of %i\n", buf_size); - - /* write the buffer size to the CAM */ - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0) - return ret; - if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0) - return ret; - if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) - return -EIO; - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) - return ret; - - /* success */ - return 0; -} - -/** - * Read a tuple from attribute memory. - * - * @param ca CA instance. - * @param slot Slot id. - * @param address Address to read from. Updated. - * @param tupleType Tuple id byte. Updated. - * @param tupleLength Tuple length. Updated. - * @param tuple Dest buffer for tuple (must be 256 bytes). Updated. - * - * @return 0 on success, nonzero on error. - */ -static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, - int *address, int *tupleType, int *tupleLength, u8 * tuple) -{ - int i; - int _tupleType; - int _tupleLength; - int _address = *address; - - /* grab the next tuple length and type */ - if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) - return _tupleType; - if (_tupleType == 0xff) { - dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType); - *address += 2; - *tupleType = _tupleType; - *tupleLength = 0; - return 0; - } - if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0) - return _tupleLength; - _address += 4; - - dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength); - - /* read in the whole tuple */ - for (i = 0; i < _tupleLength; i++) { - tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2)); - dprintk(" 0x%02x: 0x%02x %c\n", - i, tuple[i] & 0xff, - ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.'); - } - _address += (_tupleLength * 2); - - // success - *tupleType = _tupleType; - *tupleLength = _tupleLength; - *address = _address; - return 0; -} - - -/** - * Parse attribute memory of a CAM module, extracting Config register, and checking - * it is a DVB CAM module. - * - * @param ca CA instance. - * @param slot Slot id. - * - * @return 0 on success, <0 on failure. - */ -static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) -{ - int address = 0; - int tupleLength; - int tupleType; - u8 tuple[257]; - char *dvb_str; - int rasz; - int status; - int got_cftableentry = 0; - int end_chain = 0; - int i; - u16 manfid = 0; - u16 devid = 0; - - - // CISTPL_DEVICE_0A - if ((status = - dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) - return status; - if (tupleType != 0x1D) - return -EINVAL; - - - - // CISTPL_DEVICE_0C - if ((status = - dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) - return status; - if (tupleType != 0x1C) - return -EINVAL; - - - - // CISTPL_VERS_1 - if ((status = - dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) - return status; - if (tupleType != 0x15) - return -EINVAL; - - - - // CISTPL_MANFID - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, - &tupleLength, tuple)) < 0) - return status; - if (tupleType != 0x20) - return -EINVAL; - if (tupleLength != 4) - return -EINVAL; - manfid = (tuple[1] << 8) | tuple[0]; - devid = (tuple[3] << 8) | tuple[2]; - - - - // CISTPL_CONFIG - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, - &tupleLength, tuple)) < 0) - return status; - if (tupleType != 0x1A) - return -EINVAL; - if (tupleLength < 3) - return -EINVAL; - - /* extract the configbase */ - rasz = tuple[0] & 3; - if (tupleLength < (3 + rasz + 14)) - return -EINVAL; - ca->slot_info[slot].config_base = 0; - for (i = 0; i < rasz + 1; i++) { - ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i)); - } - - /* check it contains the correct DVB string */ - dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8); - if (dvb_str == NULL) - return -EINVAL; - if (tupleLength < ((dvb_str - (char *) tuple) + 12)) - return -EINVAL; - - /* is it a version we support? */ - if (strncmp(dvb_str + 8, "1.00", 4)) { - printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n", - ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]); - return -EINVAL; - } - - /* process the CFTABLE_ENTRY tuples, and any after those */ - while ((!end_chain) && (address < 0x1000)) { - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, - &tupleLength, tuple)) < 0) - return status; - switch (tupleType) { - case 0x1B: // CISTPL_CFTABLE_ENTRY - if (tupleLength < (2 + 11 + 17)) - break; - - /* if we've already parsed one, just use it */ - if (got_cftableentry) - break; - - /* get the config option */ - ca->slot_info[slot].config_option = tuple[0] & 0x3f; - - /* OK, check it contains the correct strings */ - if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) || - (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) - break; - - got_cftableentry = 1; - break; - - case 0x14: // CISTPL_NO_LINK - break; - - case 0xFF: // CISTPL_END - end_chain = 1; - break; - - default: /* Unknown tuple type - just skip this tuple and move to the next one */ - dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType, - tupleLength); - break; - } - } - - if ((address > 0x1000) || (!got_cftableentry)) - return -EINVAL; - - dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n", - manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option); - - // success! - return 0; -} - - -/** - * Set CAM's configoption correctly. - * - * @param ca CA instance. - * @param slot Slot containing the CAM. - */ -static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot) -{ - int configoption; - - dprintk("%s\n", __func__); - - /* set the config option */ - ca->pub->write_attribute_mem(ca->pub, slot, - ca->slot_info[slot].config_base, - ca->slot_info[slot].config_option); - - /* check it */ - configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base); - dprintk("Set configoption 0x%x, read configoption 0x%x\n", - ca->slot_info[slot].config_option, configoption & 0x3f); - - /* fine! */ - return 0; - -} - - -/** - * This function talks to an EN50221 CAM control interface. It reads a buffer of - * data from the CAM. The data can either be stored in a supplied buffer, or - * automatically be added to the slot's rx_buffer. - * - * @param ca CA instance. - * @param slot Slot to read from. - * @param ebuf If non-NULL, the data will be written to this buffer. If NULL, - * the data will be added into the buffering system as a normal fragment. - * @param ecount Size of ebuf. Ignored if ebuf is NULL. - * - * @return Number of bytes read, or < 0 on error - */ -static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount) -{ - int bytes_read; - int status; - u8 buf[HOST_LINK_BUF_SIZE]; - int i; - - dprintk("%s\n", __func__); - - /* check if we have space for a link buf in the rx_buffer */ - if (ebuf == NULL) { - int buf_free; - - if (ca->slot_info[slot].rx_buffer.data == NULL) { - status = -EIO; - goto exit; - } - buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); - - if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) { - status = -EAGAIN; - goto exit; - } - } - - /* check if there is data available */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) - goto exit; - if (!(status & STATUSREG_DA)) { - /* no data */ - status = 0; - goto exit; - } - - /* read the amount of data */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0) - goto exit; - bytes_read = status << 8; - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0) - goto exit; - bytes_read |= status; - - /* check it will fit */ - if (ebuf == NULL) { - if (bytes_read > ca->slot_info[slot].link_buf_size) { - printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n", - ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; - status = -EIO; - goto exit; - } - if (bytes_read < 2) { - printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; - status = -EIO; - goto exit; - } - } else { - if (bytes_read > ecount) { - printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", - ca->dvbdev->adapter->num); - status = -EIO; - goto exit; - } - } - - /* fill the buffer */ - for (i = 0; i < bytes_read; i++) { - /* read byte and check */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0) - goto exit; - - /* OK, store it in the buffer */ - buf[i] = status; - } - - /* check for read error (RE should now be 0) */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) - goto exit; - if (status & STATUSREG_RE) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; - status = -EIO; - goto exit; - } - - /* OK, add it to the receive buffer, or copy into external buffer if supplied */ - if (ebuf == NULL) { - if (ca->slot_info[slot].rx_buffer.data == NULL) { - status = -EIO; - goto exit; - } - dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); - } else { - memcpy(ebuf, buf, bytes_read); - } - - dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot, - buf[0], (buf[1] & 0x80) == 0, bytes_read); - - /* wake up readers when a last_fragment is received */ - if ((buf[1] & 0x80) == 0x00) { - wake_up_interruptible(&ca->wait_queue); - } - status = bytes_read; - -exit: - return status; -} - - -/** - * This function talks to an EN50221 CAM control interface. It writes a buffer of data - * to a CAM. - * - * @param ca CA instance. - * @param slot Slot to write to. - * @param ebuf The data in this buffer is treated as a complete link-level packet to - * be written. - * @param count Size of ebuf. - * - * @return Number of bytes written, or < 0 on error. - */ -static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write) -{ - int status; - int i; - - dprintk("%s\n", __func__); - - - /* sanity check */ - if (bytes_write > ca->slot_info[slot].link_buf_size) - return -EINVAL; - - /* it is possible we are dealing with a single buffer implementation, - thus if there is data available for read or if there is even a read - already in progress, we do nothing but awake the kernel thread to - process the data if necessary. */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) - goto exitnowrite; - if (status & (STATUSREG_DA | STATUSREG_RE)) { - if (status & STATUSREG_DA) - dvb_ca_en50221_thread_wakeup(ca); - - status = -EAGAIN; - goto exitnowrite; - } - - /* OK, set HC bit */ - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, - IRQEN | CMDREG_HC)) != 0) - goto exit; - - /* check if interface is still free */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) - goto exit; - if (!(status & STATUSREG_FR)) { - /* it wasn't free => try again later */ - status = -EAGAIN; - goto exit; - } - - /* send the amount of data */ - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) - goto exit; - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, - bytes_write & 0xff)) != 0) - goto exit; - - /* send the buffer */ - for (i = 0; i < bytes_write; i++) { - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) - goto exit; - } - - /* check for write error (WE should now be 0) */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) - goto exit; - if (status & STATUSREG_WE) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; - status = -EIO; - goto exit; - } - status = bytes_write; - - dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot, - buf[0], (buf[1] & 0x80) == 0, bytes_write); - -exit: - ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); - -exitnowrite: - return status; -} -EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); - - - -/* ******************************************************************************** */ -/* EN50221 higher level functions */ - - -/** - * A CAM has been removed => shut it down. - * - * @param ca CA instance. - * @param slot Slot to shut down. - */ -static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) -{ - dprintk("%s\n", __func__); - - ca->pub->slot_shutdown(ca->pub, slot); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - - /* need to wake up all processes to check if they're now - trying to write to a defunct CAM */ - wake_up_interruptible(&ca->wait_queue); - - dprintk("Slot %i shutdown\n", slot); - - /* success */ - return 0; -} -EXPORT_SYMBOL(dvb_ca_en50221_camready_irq); - - -/** - * A CAMCHANGE IRQ has occurred. - * - * @param ca CA instance. - * @param slot Slot concerned. - * @param change_type One of the DVB_CA_CAMCHANGE_* values. - */ -void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type) -{ - struct dvb_ca_private *ca = pubca->private; - - dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type); - - switch (change_type) { - case DVB_CA_EN50221_CAMCHANGE_REMOVED: - case DVB_CA_EN50221_CAMCHANGE_INSERTED: - break; - - default: - return; - } - - ca->slot_info[slot].camchange_type = change_type; - atomic_inc(&ca->slot_info[slot].camchange_count); - dvb_ca_en50221_thread_wakeup(ca); -} -EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); - - -/** - * A CAMREADY IRQ has occurred. - * - * @param ca CA instance. - * @param slot Slot concerned. - */ -void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) -{ - struct dvb_ca_private *ca = pubca->private; - - dprintk("CAMREADY IRQ slot:%i\n", slot); - - if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; - dvb_ca_en50221_thread_wakeup(ca); - } -} - - -/** - * An FR or DA IRQ has occurred. - * - * @param ca CA instance. - * @param slot Slot concerned. - */ -void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) -{ - struct dvb_ca_private *ca = pubca->private; - int flags; - - dprintk("FR/DA IRQ slot:%i\n", slot); - - switch (ca->slot_info[slot].slot_state) { - case DVB_CA_SLOTSTATE_LINKINIT: - flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS); - if (flags & STATUSREG_DA) { - dprintk("CAM supports DA IRQ\n"); - ca->slot_info[slot].da_irq_supported = 1; - } - break; - - case DVB_CA_SLOTSTATE_RUNNING: - if (ca->open) - dvb_ca_en50221_thread_wakeup(ca); - break; - } -} - - - -/* ******************************************************************************** */ -/* EN50221 thread functions */ - -/** - * Wake up the DVB CA thread - * - * @param ca CA instance. - */ -static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) -{ - - dprintk("%s\n", __func__); - - ca->wakeup = 1; - mb(); - wake_up_process(ca->thread); -} - -/** - * Update the delay used by the thread. - * - * @param ca CA instance. - */ -static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) -{ - int delay; - int curdelay = 100000000; - int slot; - - /* Beware of too high polling frequency, because one polling - * call might take several hundred milliseconds until timeout! - */ - for (slot = 0; slot < ca->slot_count; slot++) { - switch (ca->slot_info[slot].slot_state) { - default: - case DVB_CA_SLOTSTATE_NONE: - delay = HZ * 60; /* 60s */ - if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) - delay = HZ * 5; /* 5s */ - break; - case DVB_CA_SLOTSTATE_INVALID: - delay = HZ * 60; /* 60s */ - if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) - delay = HZ / 10; /* 100ms */ - break; - - case DVB_CA_SLOTSTATE_UNINITIALISED: - case DVB_CA_SLOTSTATE_WAITREADY: - case DVB_CA_SLOTSTATE_VALIDATE: - case DVB_CA_SLOTSTATE_WAITFR: - case DVB_CA_SLOTSTATE_LINKINIT: - delay = HZ / 10; /* 100ms */ - break; - - case DVB_CA_SLOTSTATE_RUNNING: - delay = HZ * 60; /* 60s */ - if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) - delay = HZ / 10; /* 100ms */ - if (ca->open) { - if ((!ca->slot_info[slot].da_irq_supported) || - (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) - delay = HZ / 10; /* 100ms */ - } - break; - } - - if (delay < curdelay) - curdelay = delay; - } - - ca->delay = curdelay; -} - - - -/** - * Kernel thread which monitors CA slots for CAM changes, and performs data transfers. - */ -static int dvb_ca_en50221_thread(void *data) -{ - struct dvb_ca_private *ca = data; - int slot; - int flags; - int status; - int pktcount; - void *rxbuf; - - dprintk("%s\n", __func__); - - /* choose the correct initial delay */ - dvb_ca_en50221_thread_update_delay(ca); - - /* main loop */ - while (!kthread_should_stop()) { - /* sleep for a bit */ - if (!ca->wakeup) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(ca->delay); - if (kthread_should_stop()) - return 0; - } - ca->wakeup = 0; - - /* go through all the slots processing them */ - for (slot = 0; slot < ca->slot_count; slot++) { - - mutex_lock(&ca->slot_info[slot].slot_lock); - - // check the cam status + deal with CAMCHANGEs - while (dvb_ca_en50221_check_camstatus(ca, slot)) { - /* clear down an old CI slot if necessary */ - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) - dvb_ca_en50221_slot_shutdown(ca, slot); - - /* if a CAM is NOW present, initialise it */ - if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED; - } - - /* we've handled one CAMCHANGE */ - dvb_ca_en50221_thread_update_delay(ca); - atomic_dec(&ca->slot_info[slot].camchange_count); - } - - // CAM state machine - switch (ca->slot_info[slot].slot_state) { - case DVB_CA_SLOTSTATE_NONE: - case DVB_CA_SLOTSTATE_INVALID: - // no action needed - break; - - case DVB_CA_SLOTSTATE_UNINITIALISED: - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY; - ca->pub->slot_reset(ca->pub, slot); - ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); - break; - - case DVB_CA_SLOTSTATE_WAITREADY: - if (time_after(jiffies, ca->slot_info[slot].timeout)) { - printk("dvb_ca adaptor %d: PC card did not respond :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - // no other action needed; will automatically change state when ready - break; - - case DVB_CA_SLOTSTATE_VALIDATE: - if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) { - /* we need this extra check for annoying interfaces like the budget-av */ - if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && - (ca->pub->poll_slot_status)) { - status = ca->pub->poll_slot_status(ca->pub, slot, 0); - if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - } - - printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - if (dvb_ca_en50221_set_configoption(ca, slot) != 0) { - printk("dvb_ca adapter %d: Unable to initialise CAM :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - if (ca->pub->write_cam_control(ca->pub, slot, - CTRLIF_COMMAND, CMDREG_RS) != 0) { - printk("dvb_ca adapter %d: Unable to reset CAM IF\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - dprintk("DVB CAM validated successfully\n"); - - ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR; - ca->wakeup = 1; - break; - - case DVB_CA_SLOTSTATE_WAITFR: - if (time_after(jiffies, ca->slot_info[slot].timeout)) { - printk("dvb_ca adapter %d: DVB CAM did not respond :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - - flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); - if (flags & STATUSREG_FR) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; - ca->wakeup = 1; - } - break; - - case DVB_CA_SLOTSTATE_LINKINIT: - if (dvb_ca_en50221_link_init(ca, slot) != 0) { - /* we need this extra check for annoying interfaces like the budget-av */ - if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && - (ca->pub->poll_slot_status)) { - status = ca->pub->poll_slot_status(ca->pub, slot, 0); - if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - } - - printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - - if (ca->slot_info[slot].rx_buffer.data == NULL) { - rxbuf = vmalloc(RX_BUFFER_SIZE); - if (rxbuf == NULL) { - printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); - } - - ca->pub->slot_ts_enable(ca->pub, slot); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; - dvb_ca_en50221_thread_update_delay(ca); - printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num); - break; - - case DVB_CA_SLOTSTATE_RUNNING: - if (!ca->open) - break; - - // poll slots for data - pktcount = 0; - while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { - if (!ca->open) - break; - - /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */ - if (dvb_ca_en50221_check_camstatus(ca, slot)) { - // we dont want to sleep on the next iteration so we can handle the cam change - ca->wakeup = 1; - break; - } - - /* check if we've hit our limit this time */ - if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) { - // dont sleep; there is likely to be more data to read - ca->wakeup = 1; - break; - } - } - break; - } - - mutex_unlock(&ca->slot_info[slot].slot_lock); - } - } - - return 0; -} - - - -/* ******************************************************************************** */ -/* EN50221 IO interface functions */ - -/** - * Real ioctl implementation. - * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. - * - * @param inode Inode concerned. - * @param file File concerned. - * @param cmd IOCTL command. - * @param arg Associated argument. - * - * @return 0 on success, <0 on error. - */ -static int dvb_ca_en50221_io_do_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_ca_private *ca = dvbdev->priv; - int err = 0; - int slot; - - dprintk("%s\n", __func__); - - switch (cmd) { - case CA_RESET: - for (slot = 0; slot < ca->slot_count; slot++) { - mutex_lock(&ca->slot_info[slot].slot_lock); - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { - dvb_ca_en50221_slot_shutdown(ca, slot); - if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) - dvb_ca_en50221_camchange_irq(ca->pub, - slot, - DVB_CA_EN50221_CAMCHANGE_INSERTED); - } - mutex_unlock(&ca->slot_info[slot].slot_lock); - } - ca->next_read_slot = 0; - dvb_ca_en50221_thread_wakeup(ca); - break; - - case CA_GET_CAP: { - struct ca_caps *caps = parg; - - caps->slot_num = ca->slot_count; - caps->slot_type = CA_CI_LINK; - caps->descr_num = 0; - caps->descr_type = 0; - break; - } - - case CA_GET_SLOT_INFO: { - struct ca_slot_info *info = parg; - - if ((info->num > ca->slot_count) || (info->num < 0)) - return -EINVAL; - - info->type = CA_CI_LINK; - info->flags = 0; - if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) - && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) { - info->flags = CA_CI_MODULE_PRESENT; - } - if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) { - info->flags |= CA_CI_MODULE_READY; - } - break; - } - - default: - err = -EINVAL; - break; - } - - return err; -} - - -/** - * Wrapper for ioctl implementation. - * - * @param inode Inode concerned. - * @param file File concerned. - * @param cmd IOCTL command. - * @param arg Associated argument. - * - * @return 0 on success, <0 on error. - */ -static long dvb_ca_en50221_io_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl); -} - - -/** - * Implementation of write() syscall. - * - * @param file File structure. - * @param buf Source buffer. - * @param count Size of source buffer. - * @param ppos Position in file (ignored). - * - * @return Number of bytes read, or <0 on error. - */ -static ssize_t dvb_ca_en50221_io_write(struct file *file, - const char __user * buf, size_t count, loff_t * ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_ca_private *ca = dvbdev->priv; - u8 slot, connection_id; - int status; - u8 fragbuf[HOST_LINK_BUF_SIZE]; - int fragpos = 0; - int fraglen; - unsigned long timeout; - int written; - - dprintk("%s\n", __func__); - - /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ - if (count < 2) - return -EINVAL; - - /* extract slot & connection id */ - if (copy_from_user(&slot, buf, 1)) - return -EFAULT; - if (copy_from_user(&connection_id, buf + 1, 1)) - return -EFAULT; - buf += 2; - count -= 2; - - /* check if the slot is actually running */ - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) - return -EINVAL; - - /* fragment the packets & store in the buffer */ - while (fragpos < count) { - fraglen = ca->slot_info[slot].link_buf_size - 2; - if ((count - fragpos) < fraglen) - fraglen = count - fragpos; - - fragbuf[0] = connection_id; - fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00; - status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen); - if (status) { - status = -EFAULT; - goto exit; - } - - timeout = jiffies + HZ / 2; - written = 0; - while (!time_after(jiffies, timeout)) { - /* check the CAM hasn't been removed/reset in the meantime */ - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) { - status = -EIO; - goto exit; - } - - mutex_lock(&ca->slot_info[slot].slot_lock); - status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); - mutex_unlock(&ca->slot_info[slot].slot_lock); - if (status == (fraglen + 2)) { - written = 1; - break; - } - if (status != -EAGAIN) - goto exit; - - msleep(1); - } - if (!written) { - status = -EIO; - goto exit; - } - - fragpos += fraglen; - } - status = count + 2; - -exit: - return status; -} - - -/** - * Condition for waking up in dvb_ca_en50221_io_read_condition - */ -static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, - int *result, int *_slot) -{ - int slot; - int slot_count = 0; - int idx; - size_t fraglen; - int connection_id = -1; - int found = 0; - u8 hdr[2]; - - slot = ca->next_read_slot; - while ((slot_count < ca->slot_count) && (!found)) { - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) - goto nextslot; - - if (ca->slot_info[slot].rx_buffer.data == NULL) { - return 0; - } - - idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); - while (idx != -1) { - dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); - if (connection_id == -1) - connection_id = hdr[0]; - if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) { - *_slot = slot; - found = 1; - break; - } - - idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); - } - -nextslot: - slot = (slot + 1) % ca->slot_count; - slot_count++; - } - - ca->next_read_slot = slot; - return found; -} - - -/** - * Implementation of read() syscall. - * - * @param file File structure. - * @param buf Destination buffer. - * @param count Size of destination buffer. - * @param ppos Position in file (ignored). - * - * @return Number of bytes read, or <0 on error. - */ -static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, - size_t count, loff_t * ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_ca_private *ca = dvbdev->priv; - int status; - int result = 0; - u8 hdr[2]; - int slot; - int connection_id = -1; - size_t idx, idx2; - int last_fragment = 0; - size_t fraglen; - int pktlen; - int dispose = 0; - - dprintk("%s\n", __func__); - - /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ - if (count < 2) - return -EINVAL; - - /* wait for some data */ - if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) { - - /* if we're in nonblocking mode, exit immediately */ - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - - /* wait for some data */ - status = wait_event_interruptible(ca->wait_queue, - dvb_ca_en50221_io_read_condition - (ca, &result, &slot)); - } - if ((status < 0) || (result < 0)) { - if (result) - return result; - return status; - } - - idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); - pktlen = 2; - do { - if (idx == -1) { - printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num); - status = -EIO; - goto exit; - } - - dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); - if (connection_id == -1) - connection_id = hdr[0]; - if (hdr[0] == connection_id) { - if (pktlen < count) { - if ((pktlen + fraglen - 2) > count) { - fraglen = count - pktlen; - } else { - fraglen -= 2; - } - - if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2, - buf + pktlen, fraglen)) < 0) { - goto exit; - } - pktlen += fraglen; - } - - if ((hdr[1] & 0x80) == 0) - last_fragment = 1; - dispose = 1; - } - - idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); - if (dispose) - dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx); - idx = idx2; - dispose = 0; - } while (!last_fragment); - - hdr[0] = slot; - hdr[1] = connection_id; - status = copy_to_user(buf, hdr, 2); - if (status) { - status = -EFAULT; - goto exit; - } - status = pktlen; - -exit: - return status; -} - - -/** - * Implementation of file open syscall. - * - * @param inode Inode concerned. - * @param file File concerned. - * - * @return 0 on success, <0 on failure. - */ -static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_ca_private *ca = dvbdev->priv; - int err; - int i; - - dprintk("%s\n", __func__); - - if (!try_module_get(ca->pub->owner)) - return -EIO; - - err = dvb_generic_open(inode, file); - if (err < 0) { - module_put(ca->pub->owner); - return err; - } - - for (i = 0; i < ca->slot_count; i++) { - - if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { - if (ca->slot_info[i].rx_buffer.data != NULL) { - /* it is safe to call this here without locks because - * ca->open == 0. Data is not read in this case */ - dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); - } - } - } - - ca->open = 1; - dvb_ca_en50221_thread_update_delay(ca); - dvb_ca_en50221_thread_wakeup(ca); - - return 0; -} - - -/** - * Implementation of file close syscall. - * - * @param inode Inode concerned. - * @param file File concerned. - * - * @return 0 on success, <0 on failure. - */ -static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_ca_private *ca = dvbdev->priv; - int err; - - dprintk("%s\n", __func__); - - /* mark the CA device as closed */ - ca->open = 0; - dvb_ca_en50221_thread_update_delay(ca); - - err = dvb_generic_release(inode, file); - - module_put(ca->pub->owner); - - return err; -} - - -/** - * Implementation of poll() syscall. - * - * @param file File concerned. - * @param wait poll wait table. - * - * @return Standard poll mask. - */ -static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_ca_private *ca = dvbdev->priv; - unsigned int mask = 0; - int slot; - int result = 0; - - dprintk("%s\n", __func__); - - if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { - mask |= POLLIN; - } - - /* if there is something, return now */ - if (mask) - return mask; - - /* wait for something to happen */ - poll_wait(file, &ca->wait_queue, wait); - - if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { - mask |= POLLIN; - } - - return mask; -} -EXPORT_SYMBOL(dvb_ca_en50221_init); - - -static const struct file_operations dvb_ca_fops = { - .owner = THIS_MODULE, - .read = dvb_ca_en50221_io_read, - .write = dvb_ca_en50221_io_write, - .unlocked_ioctl = dvb_ca_en50221_io_ioctl, - .open = dvb_ca_en50221_io_open, - .release = dvb_ca_en50221_io_release, - .poll = dvb_ca_en50221_io_poll, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_ca = { - .priv = NULL, - .users = 1, - .readers = 1, - .writers = 1, - .fops = &dvb_ca_fops, -}; - - -/* ******************************************************************************** */ -/* Initialisation/shutdown functions */ - - -/** - * Initialise a new DVB CA EN50221 interface device. - * - * @param dvb_adapter DVB adapter to attach the new CA device to. - * @param ca The dvb_ca instance. - * @param flags Flags describing the CA device (DVB_CA_FLAG_*). - * @param slot_count Number of slots supported. - * - * @return 0 on success, nonzero on failure - */ -int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, - struct dvb_ca_en50221 *pubca, int flags, int slot_count) -{ - int ret; - struct dvb_ca_private *ca = NULL; - int i; - - dprintk("%s\n", __func__); - - if (slot_count < 1) - return -EINVAL; - - /* initialise the system data */ - if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { - ret = -ENOMEM; - goto error; - } - ca->pub = pubca; - ca->flags = flags; - ca->slot_count = slot_count; - if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) { - ret = -ENOMEM; - goto error; - } - init_waitqueue_head(&ca->wait_queue); - ca->open = 0; - ca->wakeup = 0; - ca->next_read_slot = 0; - pubca->private = ca; - - /* register the DVB device */ - ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); - if (ret) - goto error; - - /* now initialise each slot */ - for (i = 0; i < slot_count; i++) { - memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot)); - ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; - atomic_set(&ca->slot_info[i].camchange_count, 0); - ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; - mutex_init(&ca->slot_info[i].slot_lock); - } - - if (signal_pending(current)) { - ret = -EINTR; - goto error; - } - mb(); - - /* create a kthread for monitoring this CA device */ - ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i", - ca->dvbdev->adapter->num, ca->dvbdev->id); - if (IS_ERR(ca->thread)) { - ret = PTR_ERR(ca->thread); - printk("dvb_ca_init: failed to start kernel_thread (%d)\n", - ret); - goto error; - } - return 0; - -error: - if (ca != NULL) { - if (ca->dvbdev != NULL) - dvb_unregister_device(ca->dvbdev); - kfree(ca->slot_info); - kfree(ca); - } - pubca->private = NULL; - return ret; -} -EXPORT_SYMBOL(dvb_ca_en50221_release); - - - -/** - * Release a DVB CA EN50221 interface device. - * - * @param ca_dev The dvb_device_t instance for the CA device. - * @param ca The associated dvb_ca instance. - */ -void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) -{ - struct dvb_ca_private *ca = pubca->private; - int i; - - dprintk("%s\n", __func__); - - /* shutdown the thread if there was one */ - kthread_stop(ca->thread); - - for (i = 0; i < ca->slot_count; i++) { - dvb_ca_en50221_slot_shutdown(ca, i); - vfree(ca->slot_info[i].rx_buffer.data); - } - kfree(ca->slot_info); - dvb_unregister_device(ca->dvbdev); - kfree(ca); - pubca->private = NULL; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -/* - * dvb_ca.h: generic DVB functions for EN50221 CA interfaces - * - * Copyright (C) 2004 Andrew de Quincey - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - */ - -#ifndef _DVB_CA_EN50221_H_ -#define _DVB_CA_EN50221_H_ - -#include -#include - -#include "dvbdev.h" - -#define DVB_CA_EN50221_POLL_CAM_PRESENT 1 -#define DVB_CA_EN50221_POLL_CAM_CHANGED 2 -#define DVB_CA_EN50221_POLL_CAM_READY 4 - -#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE 1 -#define DVB_CA_EN50221_FLAG_IRQ_FR 2 -#define DVB_CA_EN50221_FLAG_IRQ_DA 4 - -#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0 -#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1 - - - -/* Structure describing a CA interface */ -struct dvb_ca_en50221 { - - /* the module owning this structure */ - struct module* owner; - - /* NOTE: the read_*, write_* and poll_slot_status functions will be - * called for different slots concurrently and need to use locks where - * and if appropriate. There will be no concurrent access to one slot. - */ - - /* functions for accessing attribute memory on the CAM */ - int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address); - int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value); - - /* functions for accessing the control interface on the CAM */ - int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address); - int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value); - - /* Functions for controlling slots */ - int (*slot_reset)(struct dvb_ca_en50221* ca, int slot); - int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot); - int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot); - - /* - * Poll slot status. - * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set - */ - int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open); - - /* private data, used by caller */ - void* data; - - /* Opaque data used by the dvb_ca core. Do not modify! */ - void* private; -}; - - - - -/* ******************************************************************************** */ -/* Functions for reporting IRQ events */ - -/** - * A CAMCHANGE IRQ has occurred. - * - * @param ca CA instance. - * @param slot Slot concerned. - * @param change_type One of the DVB_CA_CAMCHANGE_* values - */ -void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type); - -/** - * A CAMREADY IRQ has occurred. - * - * @param ca CA instance. - * @param slot Slot concerned. - */ -void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot); - -/** - * An FR or a DA IRQ has occurred. - * - * @param ca CA instance. - * @param slot Slot concerned. - */ -void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot); - - - -/* ******************************************************************************** */ -/* Initialisation/shutdown functions */ - -/** - * Initialise a new DVB CA device. - * - * @param dvb_adapter DVB adapter to attach the new CA device to. - * @param ca The dvb_ca instance. - * @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*). - * @param slot_count Number of slots supported. - * - * @return 0 on success, nonzero on failure - */ -extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count); - -/** - * Release a DVB CA device. - * - * @param ca The associated dvb_ca instance. - */ -extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca); - - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_demux.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_demux.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_demux.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_demux.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1302 +0,0 @@ -/* - * dvb_demux.c - DVB kernel demux API - * - * Copyright (C) 2000-2001 Ralph Metzler - * & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_demux.h" - -#define NOBUFS -/* -** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog -*/ -// #define DVB_DEMUX_SECTION_LOSS_LOG - -static int dvb_demux_tscheck; -module_param(dvb_demux_tscheck, int, 0644); -MODULE_PARM_DESC(dvb_demux_tscheck, - "enable transport stream continuity and TEI check"); - -static int dvb_demux_speedcheck; -module_param(dvb_demux_speedcheck, int, 0644); -MODULE_PARM_DESC(dvb_demux_speedcheck, - "enable transport stream speed check"); - -#define dprintk_tscheck(x...) do { \ - if (dvb_demux_tscheck && printk_ratelimit()) \ - printk(x); \ - } while (0) - -/****************************************************************************** - * static inlined helper functions - ******************************************************************************/ - -static inline u16 section_length(const u8 *buf) -{ - return 3 + ((buf[1] & 0x0f) << 8) + buf[2]; -} - -static inline u16 ts_pid(const u8 *buf) -{ - return ((buf[1] & 0x1f) << 8) + buf[2]; -} - -static inline u8 payload(const u8 *tsp) -{ - if (!(tsp[3] & 0x10)) // no payload? - return 0; - - if (tsp[3] & 0x20) { // adaptation field? - if (tsp[4] > 183) // corrupted data? - return 0; - else - return 184 - 1 - tsp[4]; - } - - return 184; -} - -static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len) -{ - return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len)); -} - -static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s, - size_t len) -{ - memcpy(d, s, len); -} - -/****************************************************************************** - * Software filter functions - ******************************************************************************/ - -static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, - const u8 *buf) -{ - int count = payload(buf); - int p; - //int ccok; - //u8 cc; - - if (count == 0) - return -1; - - p = 188 - count; - - /* - cc = buf[3] & 0x0f; - ccok = ((feed->cc + 1) & 0x0f) == cc; - feed->cc = cc; - if (!ccok) - printk("missed packet!\n"); - */ - - if (buf[1] & 0x40) // PUSI ? - feed->peslen = 0xfffa; - - feed->peslen += count; - - return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); -} - -static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, - struct dvb_demux_filter *f) -{ - u8 neq = 0; - int i; - - for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { - u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i]; - - if (f->maskandmode[i] & xor) - return 0; - - neq |= f->maskandnotmode[i] & xor; - } - - if (f->doneq && !neq) - return 0; - - return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, - NULL, 0, &f->filter, DMX_OK); -} - -static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct dvb_demux_filter *f = feed->filter; - struct dmx_section_feed *sec = &feed->feed.sec; - int section_syntax_indicator; - - if (!sec->is_filtering) - return 0; - - if (!f) - return 0; - - if (sec->check_crc) { - section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); - if (section_syntax_indicator && - demux->check_crc32(feed, sec->secbuf, sec->seclen)) - return -1; - } - - do { - if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0) - return -1; - } while ((f = f->next) && sec->is_filtering); - - sec->seclen = 0; - - return 0; -} - -static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) -{ - struct dmx_section_feed *sec = &feed->feed.sec; - -#ifdef DVB_DEMUX_SECTION_LOSS_LOG - if (sec->secbufp < sec->tsfeedp) { - int i, n = sec->tsfeedp - sec->secbufp; - - /* - * Section padding is done with 0xff bytes entirely. - * Due to speed reasons, we won't check all of them - * but just first and last. - */ - if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { - printk("dvb_demux.c section ts padding loss: %d/%d\n", - n, sec->tsfeedp); - printk("dvb_demux.c pad data:"); - for (i = 0; i < n; i++) - printk(" %02x", sec->secbuf[i]); - printk("\n"); - } - } -#endif - - sec->tsfeedp = sec->secbufp = sec->seclen = 0; - sec->secbuf = sec->secbuf_base; -} - -/* - * Losless Section Demux 1.4.1 by Emard - * Valsecchi Patrick: - * - middle of section A (no PUSI) - * - end of section A and start of section B - * (with PUSI pointing to the start of the second section) - * - * In this case, without feed->pusi_seen you'll receive a garbage section - * consisting of the end of section A. Basically because tsfeedp - * is incemented and the use=0 condition is not raised - * when the second packet arrives. - * - * Fix: - * when demux is started, let feed->pusi_seen = 0 to - * prevent initial feeding of garbage from the end of - * previous section. When you for the first time see PUSI=1 - * then set feed->pusi_seen = 1 - */ -static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, - const u8 *buf, u8 len) -{ - struct dvb_demux *demux = feed->demux; - struct dmx_section_feed *sec = &feed->feed.sec; - u16 limit, seclen, n; - - if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) - return 0; - - if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { -#ifdef DVB_DEMUX_SECTION_LOSS_LOG - printk("dvb_demux.c section buffer full loss: %d/%d\n", - sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, - DMX_MAX_SECFEED_SIZE); -#endif - len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; - } - - if (len <= 0) - return 0; - - demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len); - sec->tsfeedp += len; - - /* - * Dump all the sections we can find in the data (Emard) - */ - limit = sec->tsfeedp; - if (limit > DMX_MAX_SECFEED_SIZE) - return -1; /* internal error should never happen */ - - /* to be sure always set secbuf */ - sec->secbuf = sec->secbuf_base + sec->secbufp; - - for (n = 0; sec->secbufp + 2 < limit; n++) { - seclen = section_length(sec->secbuf); - if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE - || seclen + sec->secbufp > limit) - return 0; - sec->seclen = seclen; - sec->crc_val = ~0; - /* dump [secbuf .. secbuf+seclen) */ - if (feed->pusi_seen) - dvb_dmx_swfilter_section_feed(feed); -#ifdef DVB_DEMUX_SECTION_LOSS_LOG - else - printk("dvb_demux.c pusi not seen, discarding section data\n"); -#endif - sec->secbufp += seclen; /* secbufp and secbuf moving together is */ - sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ - } - - return 0; -} - -static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, - const u8 *buf) -{ - u8 p, count; - int ccok, dc_i = 0; - u8 cc; - - count = payload(buf); - - if (count == 0) /* count == 0 if no payload or out of range */ - return -1; - - p = 188 - count; /* payload start */ - - cc = buf[3] & 0x0f; - ccok = ((feed->cc + 1) & 0x0f) == cc; - feed->cc = cc; - - if (buf[3] & 0x20) { - /* adaption field present, check for discontinuity_indicator */ - if ((buf[4] > 0) && (buf[5] & 0x80)) - dc_i = 1; - } - - if (!ccok || dc_i) { -#ifdef DVB_DEMUX_SECTION_LOSS_LOG - printk("dvb_demux.c discontinuity detected %d bytes lost\n", - count); - /* - * those bytes under sume circumstances will again be reported - * in the following dvb_dmx_swfilter_section_new - */ -#endif - /* - * Discontinuity detected. Reset pusi_seen = 0 to - * stop feeding of suspicious data until next PUSI=1 arrives - */ - feed->pusi_seen = 0; - dvb_dmx_swfilter_section_new(feed); - } - - if (buf[1] & 0x40) { - /* PUSI=1 (is set), section boundary is here */ - if (count > 1 && buf[p] < count) { - const u8 *before = &buf[p + 1]; - u8 before_len = buf[p]; - const u8 *after = &before[before_len]; - u8 after_len = count - 1 - before_len; - - dvb_dmx_swfilter_section_copy_dump(feed, before, - before_len); - /* before start of new section, set pusi_seen = 1 */ - feed->pusi_seen = 1; - dvb_dmx_swfilter_section_new(feed); - dvb_dmx_swfilter_section_copy_dump(feed, after, - after_len); - } -#ifdef DVB_DEMUX_SECTION_LOSS_LOG - else if (count > 0) - printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); -#endif - } else { - /* PUSI=0 (is not set), no section boundary */ - dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); - } - - return 0; -} - -static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, - const u8 *buf) -{ - switch (feed->type) { - case DMX_TYPE_TS: - if (!feed->feed.ts.is_filtering) - break; - if (feed->ts_type & TS_PACKET) { - if (feed->ts_type & TS_PAYLOAD_ONLY) - dvb_dmx_swfilter_payload(feed, buf); - else - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, - DMX_OK); - } - if (feed->ts_type & TS_DECODER) - if (feed->demux->write_to_decoder) - feed->demux->write_to_decoder(feed, buf, 188); - break; - - case DMX_TYPE_SEC: - if (!feed->feed.sec.is_filtering) - break; - if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) - feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; - break; - - default: - break; - } -} - -#define DVR_FEED(f) \ - (((f)->type == DMX_TYPE_TS) && \ - ((f)->feed.ts.is_filtering) && \ - (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET)) - -static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) -{ - struct dvb_demux_feed *feed; - u16 pid = ts_pid(buf); - int dvr_done = 0; - - if (dvb_demux_speedcheck) { - struct timespec cur_time, delta_time; - u64 speed_bytes, speed_timedelta; - - demux->speed_pkts_cnt++; - - /* show speed every SPEED_PKTS_INTERVAL packets */ - if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { - cur_time = current_kernel_time(); - - if (demux->speed_last_time.tv_sec != 0 && - demux->speed_last_time.tv_nsec != 0) { - delta_time = timespec_sub(cur_time, - demux->speed_last_time); - speed_bytes = (u64)demux->speed_pkts_cnt - * 188 * 8; - /* convert to 1024 basis */ - speed_bytes = 1000 * div64_u64(speed_bytes, - 1024); - speed_timedelta = - (u64)timespec_to_ns(&delta_time); - speed_timedelta = div64_u64(speed_timedelta, - 1000000); /* nsec -> usec */ - printk(KERN_INFO "TS speed %llu Kbits/sec \n", - div64_u64(speed_bytes, - speed_timedelta)); - }; - - demux->speed_last_time = cur_time; - demux->speed_pkts_cnt = 0; - }; - }; - - if (demux->cnt_storage && dvb_demux_tscheck) { - /* check pkt counter */ - if (pid < MAX_PID) { - if (buf[1] & 0x80) - dprintk_tscheck("TEI detected. " - "PID=0x%x data1=0x%x\n", - pid, buf[1]); - - if ((buf[3] & 0xf) != demux->cnt_storage[pid]) - dprintk_tscheck("TS packet counter mismatch. " - "PID=0x%x expected 0x%x " - "got 0x%x\n", - pid, demux->cnt_storage[pid], - buf[3] & 0xf); - - demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf; - }; - /* end check */ - }; - - list_for_each_entry(feed, &demux->feed_list, list_head) { - if ((feed->pid != pid) && (feed->pid != 0x2000)) - continue; - - /* copy each packet only once to the dvr device, even - * if a PID is in multiple filters (e.g. video + PCR) */ - if ((DVR_FEED(feed)) && (dvr_done++)) - continue; - - if (feed->pid == pid) - dvb_dmx_swfilter_packet_type(feed, buf); - else if (feed->pid == 0x2000) - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); - } -} - -void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, - size_t count) -{ - spin_lock(&demux->lock); - - while (count--) { - if (buf[0] == 0x47) - dvb_dmx_swfilter_packet(demux, buf); - buf += 188; - } - - spin_unlock(&demux->lock); -} - -EXPORT_SYMBOL(dvb_dmx_swfilter_packets); - -void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) -{ - int p = 0, i, j; - - spin_lock(&demux->lock); - - if (demux->tsbufp) { - i = demux->tsbufp; - j = 188 - i; - if (count < j) { - memcpy(&demux->tsbuf[i], buf, count); - demux->tsbufp += count; - goto bailout; - } - memcpy(&demux->tsbuf[i], buf, j); - if (demux->tsbuf[0] == 0x47) - dvb_dmx_swfilter_packet(demux, demux->tsbuf); - demux->tsbufp = 0; - p += j; - } - - while (p < count) { - if (buf[p] == 0x47) { - if (count - p >= 188) { - dvb_dmx_swfilter_packet(demux, &buf[p]); - p += 188; - } else { - i = count - p; - memcpy(demux->tsbuf, &buf[p], i); - demux->tsbufp = i; - goto bailout; - } - } else - p++; - } - -bailout: - spin_unlock(&demux->lock); -} - -EXPORT_SYMBOL(dvb_dmx_swfilter); - -void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) -{ - int p = 0, i, j; - u8 tmppack[188]; - - spin_lock(&demux->lock); - - if (demux->tsbufp) { - i = demux->tsbufp; - j = 204 - i; - if (count < j) { - memcpy(&demux->tsbuf[i], buf, count); - demux->tsbufp += count; - goto bailout; - } - memcpy(&demux->tsbuf[i], buf, j); - if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) { - memcpy(tmppack, demux->tsbuf, 188); - if (tmppack[0] == 0xB8) - tmppack[0] = 0x47; - dvb_dmx_swfilter_packet(demux, tmppack); - } - demux->tsbufp = 0; - p += j; - } - - while (p < count) { - if ((buf[p] == 0x47) || (buf[p] == 0xB8)) { - if (count - p >= 204) { - memcpy(tmppack, &buf[p], 188); - if (tmppack[0] == 0xB8) - tmppack[0] = 0x47; - dvb_dmx_swfilter_packet(demux, tmppack); - p += 204; - } else { - i = count - p; - memcpy(demux->tsbuf, &buf[p], i); - demux->tsbufp = i; - goto bailout; - } - } else { - p++; - } - } - -bailout: - spin_unlock(&demux->lock); -} - -EXPORT_SYMBOL(dvb_dmx_swfilter_204); - -static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) -{ - int i; - - for (i = 0; i < demux->filternum; i++) - if (demux->filter[i].state == DMX_STATE_FREE) - break; - - if (i == demux->filternum) - return NULL; - - demux->filter[i].state = DMX_STATE_ALLOCATED; - - return &demux->filter[i]; -} - -static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) -{ - int i; - - for (i = 0; i < demux->feednum; i++) - if (demux->feed[i].state == DMX_STATE_FREE) - break; - - if (i == demux->feednum) - return NULL; - - demux->feed[i].state = DMX_STATE_ALLOCATED; - - return &demux->feed[i]; -} - -static int dvb_demux_feed_find(struct dvb_demux_feed *feed) -{ - struct dvb_demux_feed *entry; - - list_for_each_entry(entry, &feed->demux->feed_list, list_head) - if (entry == feed) - return 1; - - return 0; -} - -static void dvb_demux_feed_add(struct dvb_demux_feed *feed) -{ - spin_lock_irq(&feed->demux->lock); - if (dvb_demux_feed_find(feed)) { - printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n", - __func__, feed->type, feed->state, feed->pid); - goto out; - } - - list_add(&feed->list_head, &feed->demux->feed_list); -out: - spin_unlock_irq(&feed->demux->lock); -} - -static void dvb_demux_feed_del(struct dvb_demux_feed *feed) -{ - spin_lock_irq(&feed->demux->lock); - if (!(dvb_demux_feed_find(feed))) { - printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n", - __func__, feed->type, feed->state, feed->pid); - goto out; - } - - list_del(&feed->list_head); -out: - spin_unlock_irq(&feed->demux->lock); -} - -static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, - enum dmx_ts_pes pes_type, - size_t circular_buffer_size, struct timespec timeout) -{ - struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; - struct dvb_demux *demux = feed->demux; - - if (pid > DMX_MAX_PID) - return -EINVAL; - - if (mutex_lock_interruptible(&demux->mutex)) - return -ERESTARTSYS; - - if (ts_type & TS_DECODER) { - if (pes_type >= DMX_TS_PES_OTHER) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } - - if (demux->pesfilter[pes_type] && - demux->pesfilter[pes_type] != feed) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } - - demux->pesfilter[pes_type] = feed; - demux->pids[pes_type] = pid; - } - - dvb_demux_feed_add(feed); - - feed->pid = pid; - feed->buffer_size = circular_buffer_size; - feed->timeout = timeout; - feed->ts_type = ts_type; - feed->pes_type = pes_type; - - if (feed->buffer_size) { -#ifdef NOBUFS - feed->buffer = NULL; -#else - feed->buffer = vmalloc(feed->buffer_size); - if (!feed->buffer) { - mutex_unlock(&demux->mutex); - return -ENOMEM; - } -#endif - } - - feed->state = DMX_STATE_READY; - mutex_unlock(&demux->mutex); - - return 0; -} - -static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) -{ - struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; - struct dvb_demux *demux = feed->demux; - int ret; - - if (mutex_lock_interruptible(&demux->mutex)) - return -ERESTARTSYS; - - if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } - - if (!demux->start_feed) { - mutex_unlock(&demux->mutex); - return -ENODEV; - } - - if ((ret = demux->start_feed(feed)) < 0) { - mutex_unlock(&demux->mutex); - return ret; - } - - spin_lock_irq(&demux->lock); - ts_feed->is_filtering = 1; - feed->state = DMX_STATE_GO; - spin_unlock_irq(&demux->lock); - mutex_unlock(&demux->mutex); - - return 0; -} - -static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) -{ - struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; - struct dvb_demux *demux = feed->demux; - int ret; - - mutex_lock(&demux->mutex); - - if (feed->state < DMX_STATE_GO) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } - - if (!demux->stop_feed) { - mutex_unlock(&demux->mutex); - return -ENODEV; - } - - ret = demux->stop_feed(feed); - - spin_lock_irq(&demux->lock); - ts_feed->is_filtering = 0; - feed->state = DMX_STATE_ALLOCATED; - spin_unlock_irq(&demux->lock); - mutex_unlock(&demux->mutex); - - return ret; -} - -static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, - struct dmx_ts_feed **ts_feed, - dmx_ts_cb callback) -{ - struct dvb_demux *demux = (struct dvb_demux *)dmx; - struct dvb_demux_feed *feed; - - if (mutex_lock_interruptible(&demux->mutex)) - return -ERESTARTSYS; - - if (!(feed = dvb_dmx_feed_alloc(demux))) { - mutex_unlock(&demux->mutex); - return -EBUSY; - } - - feed->type = DMX_TYPE_TS; - feed->cb.ts = callback; - feed->demux = demux; - feed->pid = 0xffff; - feed->peslen = 0xfffa; - feed->buffer = NULL; - - (*ts_feed) = &feed->feed.ts; - (*ts_feed)->parent = dmx; - (*ts_feed)->priv = NULL; - (*ts_feed)->is_filtering = 0; - (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering; - (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; - (*ts_feed)->set = dmx_ts_feed_set; - - if (!(feed->filter = dvb_dmx_filter_alloc(demux))) { - feed->state = DMX_STATE_FREE; - mutex_unlock(&demux->mutex); - return -EBUSY; - } - - feed->filter->type = DMX_TYPE_TS; - feed->filter->feed = feed; - feed->filter->state = DMX_STATE_READY; - - mutex_unlock(&demux->mutex); - - return 0; -} - -static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, - struct dmx_ts_feed *ts_feed) -{ - struct dvb_demux *demux = (struct dvb_demux *)dmx; - struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; - - mutex_lock(&demux->mutex); - - if (feed->state == DMX_STATE_FREE) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } -#ifndef NOBUFS - vfree(feed->buffer); - feed->buffer = NULL; -#endif - - feed->state = DMX_STATE_FREE; - feed->filter->state = DMX_STATE_FREE; - - dvb_demux_feed_del(feed); - - feed->pid = 0xffff; - - if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) - demux->pesfilter[feed->pes_type] = NULL; - - mutex_unlock(&demux->mutex); - return 0; -} - -/****************************************************************************** - * dmx_section_feed API calls - ******************************************************************************/ - -static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed, - struct dmx_section_filter **filter) -{ - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; - struct dvb_demux *dvbdemux = dvbdmxfeed->demux; - struct dvb_demux_filter *dvbdmxfilter; - - if (mutex_lock_interruptible(&dvbdemux->mutex)) - return -ERESTARTSYS; - - dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux); - if (!dvbdmxfilter) { - mutex_unlock(&dvbdemux->mutex); - return -EBUSY; - } - - spin_lock_irq(&dvbdemux->lock); - *filter = &dvbdmxfilter->filter; - (*filter)->parent = feed; - (*filter)->priv = NULL; - dvbdmxfilter->feed = dvbdmxfeed; - dvbdmxfilter->type = DMX_TYPE_SEC; - dvbdmxfilter->state = DMX_STATE_READY; - dvbdmxfilter->next = dvbdmxfeed->filter; - dvbdmxfeed->filter = dvbdmxfilter; - spin_unlock_irq(&dvbdemux->lock); - - mutex_unlock(&dvbdemux->mutex); - return 0; -} - -static int dmx_section_feed_set(struct dmx_section_feed *feed, - u16 pid, size_t circular_buffer_size, - int check_crc) -{ - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - - if (pid > 0x1fff) - return -EINVAL; - - if (mutex_lock_interruptible(&dvbdmx->mutex)) - return -ERESTARTSYS; - - dvb_demux_feed_add(dvbdmxfeed); - - dvbdmxfeed->pid = pid; - dvbdmxfeed->buffer_size = circular_buffer_size; - dvbdmxfeed->feed.sec.check_crc = check_crc; - -#ifdef NOBUFS - dvbdmxfeed->buffer = NULL; -#else - dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size); - if (!dvbdmxfeed->buffer) { - mutex_unlock(&dvbdmx->mutex); - return -ENOMEM; - } -#endif - - dvbdmxfeed->state = DMX_STATE_READY; - mutex_unlock(&dvbdmx->mutex); - return 0; -} - -static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) -{ - int i; - struct dvb_demux_filter *f; - struct dmx_section_filter *sf; - u8 mask, mode, doneq; - - if (!(f = dvbdmxfeed->filter)) - return; - do { - sf = &f->filter; - doneq = 0; - for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { - mode = sf->filter_mode[i]; - mask = sf->filter_mask[i]; - f->maskandmode[i] = mask & mode; - doneq |= f->maskandnotmode[i] = mask & ~mode; - } - f->doneq = doneq ? 1 : 0; - } while ((f = f->next)); -} - -static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) -{ - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - int ret; - - if (mutex_lock_interruptible(&dvbdmx->mutex)) - return -ERESTARTSYS; - - if (feed->is_filtering) { - mutex_unlock(&dvbdmx->mutex); - return -EBUSY; - } - - if (!dvbdmxfeed->filter) { - mutex_unlock(&dvbdmx->mutex); - return -EINVAL; - } - - dvbdmxfeed->feed.sec.tsfeedp = 0; - dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; - dvbdmxfeed->feed.sec.secbufp = 0; - dvbdmxfeed->feed.sec.seclen = 0; - - if (!dvbdmx->start_feed) { - mutex_unlock(&dvbdmx->mutex); - return -ENODEV; - } - - prepare_secfilters(dvbdmxfeed); - - if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) { - mutex_unlock(&dvbdmx->mutex); - return ret; - } - - spin_lock_irq(&dvbdmx->lock); - feed->is_filtering = 1; - dvbdmxfeed->state = DMX_STATE_GO; - spin_unlock_irq(&dvbdmx->lock); - - mutex_unlock(&dvbdmx->mutex); - return 0; -} - -static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) -{ - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - int ret; - - mutex_lock(&dvbdmx->mutex); - - if (!dvbdmx->stop_feed) { - mutex_unlock(&dvbdmx->mutex); - return -ENODEV; - } - - ret = dvbdmx->stop_feed(dvbdmxfeed); - - spin_lock_irq(&dvbdmx->lock); - dvbdmxfeed->state = DMX_STATE_READY; - feed->is_filtering = 0; - spin_unlock_irq(&dvbdmx->lock); - - mutex_unlock(&dvbdmx->mutex); - return ret; -} - -static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, - struct dmx_section_filter *filter) -{ - struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f; - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - - mutex_lock(&dvbdmx->mutex); - - if (dvbdmxfilter->feed != dvbdmxfeed) { - mutex_unlock(&dvbdmx->mutex); - return -EINVAL; - } - - if (feed->is_filtering) - feed->stop_filtering(feed); - - spin_lock_irq(&dvbdmx->lock); - f = dvbdmxfeed->filter; - - if (f == dvbdmxfilter) { - dvbdmxfeed->filter = dvbdmxfilter->next; - } else { - while (f->next != dvbdmxfilter) - f = f->next; - f->next = f->next->next; - } - - dvbdmxfilter->state = DMX_STATE_FREE; - spin_unlock_irq(&dvbdmx->lock); - mutex_unlock(&dvbdmx->mutex); - return 0; -} - -static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, - struct dmx_section_feed **feed, - dmx_section_cb callback) -{ - struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; - struct dvb_demux_feed *dvbdmxfeed; - - if (mutex_lock_interruptible(&dvbdmx->mutex)) - return -ERESTARTSYS; - - if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) { - mutex_unlock(&dvbdmx->mutex); - return -EBUSY; - } - - dvbdmxfeed->type = DMX_TYPE_SEC; - dvbdmxfeed->cb.sec = callback; - dvbdmxfeed->demux = dvbdmx; - dvbdmxfeed->pid = 0xffff; - dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; - dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; - dvbdmxfeed->feed.sec.tsfeedp = 0; - dvbdmxfeed->filter = NULL; - dvbdmxfeed->buffer = NULL; - - (*feed) = &dvbdmxfeed->feed.sec; - (*feed)->is_filtering = 0; - (*feed)->parent = demux; - (*feed)->priv = NULL; - - (*feed)->set = dmx_section_feed_set; - (*feed)->allocate_filter = dmx_section_feed_allocate_filter; - (*feed)->start_filtering = dmx_section_feed_start_filtering; - (*feed)->stop_filtering = dmx_section_feed_stop_filtering; - (*feed)->release_filter = dmx_section_feed_release_filter; - - mutex_unlock(&dvbdmx->mutex); - return 0; -} - -static int dvbdmx_release_section_feed(struct dmx_demux *demux, - struct dmx_section_feed *feed) -{ - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; - struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; - - mutex_lock(&dvbdmx->mutex); - - if (dvbdmxfeed->state == DMX_STATE_FREE) { - mutex_unlock(&dvbdmx->mutex); - return -EINVAL; - } -#ifndef NOBUFS - vfree(dvbdmxfeed->buffer); - dvbdmxfeed->buffer = NULL; -#endif - dvbdmxfeed->state = DMX_STATE_FREE; - - dvb_demux_feed_del(dvbdmxfeed); - - dvbdmxfeed->pid = 0xffff; - - mutex_unlock(&dvbdmx->mutex); - return 0; -} - -/****************************************************************************** - * dvb_demux kernel data API calls - ******************************************************************************/ - -static int dvbdmx_open(struct dmx_demux *demux) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - - if (dvbdemux->users >= MAX_DVB_DEMUX_USERS) - return -EUSERS; - - dvbdemux->users++; - return 0; -} - -static int dvbdmx_close(struct dmx_demux *demux) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - - if (dvbdemux->users == 0) - return -ENODEV; - - dvbdemux->users--; - //FIXME: release any unneeded resources if users==0 - return 0; -} - -static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - void *p; - - if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) - return -EINVAL; - - p = memdup_user(buf, count); - if (IS_ERR(p)) - return PTR_ERR(p); - if (mutex_lock_interruptible(&dvbdemux->mutex)) { - kfree(p); - return -ERESTARTSYS; - } - dvb_dmx_swfilter(dvbdemux, p, count); - kfree(p); - mutex_unlock(&dvbdemux->mutex); - - if (signal_pending(current)) - return -EINTR; - return count; -} - -static int dvbdmx_add_frontend(struct dmx_demux *demux, - struct dmx_frontend *frontend) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - struct list_head *head = &dvbdemux->frontend_list; - - list_add(&(frontend->connectivity_list), head); - - return 0; -} - -static int dvbdmx_remove_frontend(struct dmx_demux *demux, - struct dmx_frontend *frontend) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - struct list_head *pos, *n, *head = &dvbdemux->frontend_list; - - list_for_each_safe(pos, n, head) { - if (DMX_FE_ENTRY(pos) == frontend) { - list_del(pos); - return 0; - } - } - - return -ENODEV; -} - -static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - - if (list_empty(&dvbdemux->frontend_list)) - return NULL; - - return &dvbdemux->frontend_list; -} - -static int dvbdmx_connect_frontend(struct dmx_demux *demux, - struct dmx_frontend *frontend) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - - if (demux->frontend) - return -EINVAL; - - mutex_lock(&dvbdemux->mutex); - - demux->frontend = frontend; - mutex_unlock(&dvbdemux->mutex); - return 0; -} - -static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - - mutex_lock(&dvbdemux->mutex); - - demux->frontend = NULL; - mutex_unlock(&dvbdemux->mutex); - return 0; -} - -static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - - memcpy(pids, dvbdemux->pids, 5 * sizeof(u16)); - return 0; -} - -int dvb_dmx_init(struct dvb_demux *dvbdemux) -{ - int i; - struct dmx_demux *dmx = &dvbdemux->dmx; - - dvbdemux->cnt_storage = NULL; - dvbdemux->users = 0; - dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); - - if (!dvbdemux->filter) - return -ENOMEM; - - dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed)); - if (!dvbdemux->feed) { - vfree(dvbdemux->filter); - dvbdemux->filter = NULL; - return -ENOMEM; - } - for (i = 0; i < dvbdemux->filternum; i++) { - dvbdemux->filter[i].state = DMX_STATE_FREE; - dvbdemux->filter[i].index = i; - } - for (i = 0; i < dvbdemux->feednum; i++) { - dvbdemux->feed[i].state = DMX_STATE_FREE; - dvbdemux->feed[i].index = i; - } - - dvbdemux->cnt_storage = vmalloc(MAX_PID + 1); - if (!dvbdemux->cnt_storage) - printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n"); - - INIT_LIST_HEAD(&dvbdemux->frontend_list); - - for (i = 0; i < DMX_TS_PES_OTHER; i++) { - dvbdemux->pesfilter[i] = NULL; - dvbdemux->pids[i] = 0xffff; - } - - INIT_LIST_HEAD(&dvbdemux->feed_list); - - dvbdemux->playing = 0; - dvbdemux->recording = 0; - dvbdemux->tsbufp = 0; - - if (!dvbdemux->check_crc32) - dvbdemux->check_crc32 = dvb_dmx_crc32; - - if (!dvbdemux->memcopy) - dvbdemux->memcopy = dvb_dmx_memcopy; - - dmx->frontend = NULL; - dmx->priv = dvbdemux; - dmx->open = dvbdmx_open; - dmx->close = dvbdmx_close; - dmx->write = dvbdmx_write; - dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed; - dmx->release_ts_feed = dvbdmx_release_ts_feed; - dmx->allocate_section_feed = dvbdmx_allocate_section_feed; - dmx->release_section_feed = dvbdmx_release_section_feed; - - dmx->add_frontend = dvbdmx_add_frontend; - dmx->remove_frontend = dvbdmx_remove_frontend; - dmx->get_frontends = dvbdmx_get_frontends; - dmx->connect_frontend = dvbdmx_connect_frontend; - dmx->disconnect_frontend = dvbdmx_disconnect_frontend; - dmx->get_pes_pids = dvbdmx_get_pes_pids; - - mutex_init(&dvbdemux->mutex); - spin_lock_init(&dvbdemux->lock); - - return 0; -} - -EXPORT_SYMBOL(dvb_dmx_init); - -void dvb_dmx_release(struct dvb_demux *dvbdemux) -{ - vfree(dvbdemux->cnt_storage); - vfree(dvbdemux->filter); - vfree(dvbdemux->feed); -} - -EXPORT_SYMBOL(dvb_dmx_release); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_demux.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_demux.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_demux.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_demux.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,149 +0,0 @@ -/* - * dvb_demux.h: DVB kernel demux API - * - * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVB_DEMUX_H_ -#define _DVB_DEMUX_H_ - -#include -#include -#include -#include - -#include "demux.h" - -#define DMX_TYPE_TS 0 -#define DMX_TYPE_SEC 1 -#define DMX_TYPE_PES 2 - -#define DMX_STATE_FREE 0 -#define DMX_STATE_ALLOCATED 1 -#define DMX_STATE_SET 2 -#define DMX_STATE_READY 3 -#define DMX_STATE_GO 4 - -#define DVB_DEMUX_MASK_MAX 18 - -#define MAX_PID 0x1fff - -#define SPEED_PKTS_INTERVAL 50000 - -struct dvb_demux_filter { - struct dmx_section_filter filter; - u8 maskandmode[DMX_MAX_FILTER_SIZE]; - u8 maskandnotmode[DMX_MAX_FILTER_SIZE]; - int doneq; - - struct dvb_demux_filter *next; - struct dvb_demux_feed *feed; - int index; - int state; - int type; - - u16 hw_handle; - struct timer_list timer; -}; - -#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) - -struct dvb_demux_feed { - union { - struct dmx_ts_feed ts; - struct dmx_section_feed sec; - } feed; - - union { - dmx_ts_cb ts; - dmx_section_cb sec; - } cb; - - struct dvb_demux *demux; - void *priv; - int type; - int state; - u16 pid; - u8 *buffer; - int buffer_size; - - struct timespec timeout; - struct dvb_demux_filter *filter; - - int ts_type; - enum dmx_ts_pes pes_type; - - int cc; - int pusi_seen; /* prevents feeding of garbage from previous section */ - - u16 peslen; - - struct list_head list_head; - unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ -}; - -struct dvb_demux { - struct dmx_demux dmx; - void *priv; - int filternum; - int feednum; - int (*start_feed)(struct dvb_demux_feed *feed); - int (*stop_feed)(struct dvb_demux_feed *feed); - int (*write_to_decoder)(struct dvb_demux_feed *feed, - const u8 *buf, size_t len); - u32 (*check_crc32)(struct dvb_demux_feed *feed, - const u8 *buf, size_t len); - void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst, - const u8 *src, size_t len); - - int users; -#define MAX_DVB_DEMUX_USERS 10 - struct dvb_demux_filter *filter; - struct dvb_demux_feed *feed; - - struct list_head frontend_list; - - struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; - u16 pids[DMX_TS_PES_OTHER]; - int playing; - int recording; - -#define DMX_MAX_PID 0x2000 - struct list_head feed_list; - u8 tsbuf[204]; - int tsbufp; - - struct mutex mutex; - spinlock_t lock; - - uint8_t *cnt_storage; /* for TS continuity check */ - - struct timespec speed_last_time; /* for TS speed check */ - uint32_t speed_pkts_cnt; /* for TS speed check */ -}; - -int dvb_dmx_init(struct dvb_demux *dvbdemux); -void dvb_dmx_release(struct dvb_demux *dvbdemux); -void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, - size_t count); -void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); -void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, - size_t count); - -#endif /* _DVB_DEMUX_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvbdev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvbdev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvbdev.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvbdev.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,506 +0,0 @@ -/* - * dvbdev.c - * - * Copyright (C) 2000 Ralph Metzler - * & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dvbdev.h" - -static DEFINE_MUTEX(dvbdev_mutex); -static int dvbdev_debug; - -module_param(dvbdev_debug, int, 0644); -MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off)."); - -#define dprintk if (dvbdev_debug) printk - -static LIST_HEAD(dvb_adapter_list); -static DEFINE_MUTEX(dvbdev_register_lock); - -static const char * const dnames[] = { - "video", "audio", "sec", "frontend", "demux", "dvr", "ca", - "net", "osd" -}; - -#ifdef CONFIG_DVB_DYNAMIC_MINORS -#define MAX_DVB_MINORS 256 -#define DVB_MAX_IDS MAX_DVB_MINORS -#else -#define DVB_MAX_IDS 4 -#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) -#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) -#endif - -static struct class *dvb_class; - -static struct dvb_device *dvb_minors[MAX_DVB_MINORS]; -static DECLARE_RWSEM(minor_rwsem); - -static int dvb_device_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev; - - mutex_lock(&dvbdev_mutex); - down_read(&minor_rwsem); - dvbdev = dvb_minors[iminor(inode)]; - - if (dvbdev && dvbdev->fops) { - int err = 0; - const struct file_operations *old_fops; - - file->private_data = dvbdev; - old_fops = file->f_op; - file->f_op = fops_get(dvbdev->fops); - if (file->f_op == NULL) { - file->f_op = old_fops; - goto fail; - } - if(file->f_op->open) - err = file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); - up_read(&minor_rwsem); - mutex_unlock(&dvbdev_mutex); - return err; - } -fail: - up_read(&minor_rwsem); - mutex_unlock(&dvbdev_mutex); - return -ENODEV; -} - - -static const struct file_operations dvb_device_fops = -{ - .owner = THIS_MODULE, - .open = dvb_device_open, - .llseek = noop_llseek, -}; - -static struct cdev dvb_device_cdev; - -int dvb_generic_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - - if (!dvbdev) - return -ENODEV; - - if (!dvbdev->users) - return -EBUSY; - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - if (!dvbdev->readers) - return -EBUSY; - dvbdev->readers--; - } else { - if (!dvbdev->writers) - return -EBUSY; - dvbdev->writers--; - } - - dvbdev->users--; - return 0; -} -EXPORT_SYMBOL(dvb_generic_open); - - -int dvb_generic_release(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - - if (!dvbdev) - return -ENODEV; - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - dvbdev->readers++; - } else { - dvbdev->writers++; - } - - dvbdev->users++; - return 0; -} -EXPORT_SYMBOL(dvb_generic_release); - - -long dvb_generic_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct dvb_device *dvbdev = file->private_data; - - if (!dvbdev) - return -ENODEV; - - if (!dvbdev->kernel_ioctl) - return -EINVAL; - - return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl); -} -EXPORT_SYMBOL(dvb_generic_ioctl); - - -static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) -{ - u32 id = 0; - - while (id < DVB_MAX_IDS) { - struct dvb_device *dev; - list_for_each_entry(dev, &adap->device_list, list_head) - if (dev->type == type && dev->id == id) - goto skip; - return id; -skip: - id++; - } - return -ENFILE; -} - - -int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, - const struct dvb_device *template, void *priv, int type) -{ - struct dvb_device *dvbdev; - struct file_operations *dvbdevfops; - struct device *clsdev; - int minor; - int id; - - mutex_lock(&dvbdev_register_lock); - - if ((id = dvbdev_get_free_id (adap, type)) < 0){ - mutex_unlock(&dvbdev_register_lock); - *pdvbdev = NULL; - printk(KERN_ERR "%s: couldn't find free device id\n", __func__); - return -ENFILE; - } - - *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); - - if (!dvbdev){ - mutex_unlock(&dvbdev_register_lock); - return -ENOMEM; - } - - dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); - - if (!dvbdevfops){ - kfree (dvbdev); - mutex_unlock(&dvbdev_register_lock); - return -ENOMEM; - } - - memcpy(dvbdev, template, sizeof(struct dvb_device)); - dvbdev->type = type; - dvbdev->id = id; - dvbdev->adapter = adap; - dvbdev->priv = priv; - dvbdev->fops = dvbdevfops; - init_waitqueue_head (&dvbdev->wait_queue); - - memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); - dvbdevfops->owner = adap->module; - - list_add_tail (&dvbdev->list_head, &adap->device_list); - - down_write(&minor_rwsem); -#ifdef CONFIG_DVB_DYNAMIC_MINORS - for (minor = 0; minor < MAX_DVB_MINORS; minor++) - if (dvb_minors[minor] == NULL) - break; - - if (minor == MAX_DVB_MINORS) { - kfree(dvbdevfops); - kfree(dvbdev); - mutex_unlock(&dvbdev_register_lock); - return -EINVAL; - } -#else - minor = nums2minor(adap->num, type, id); -#endif - - dvbdev->minor = minor; - dvb_minors[minor] = dvbdev; - up_write(&minor_rwsem); - - mutex_unlock(&dvbdev_register_lock); - - clsdev = device_create(dvb_class, adap->device, - MKDEV(DVB_MAJOR, minor), - dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); - if (IS_ERR(clsdev)) { - printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", - __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); - return PTR_ERR(clsdev); - } - - dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", - adap->num, dnames[type], id, minor, minor); - - return 0; -} -EXPORT_SYMBOL(dvb_register_device); - - -void dvb_unregister_device(struct dvb_device *dvbdev) -{ - if (!dvbdev) - return; - - down_write(&minor_rwsem); - dvb_minors[dvbdev->minor] = NULL; - up_write(&minor_rwsem); - - device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); - - list_del (&dvbdev->list_head); - kfree (dvbdev->fops); - kfree (dvbdev); -} -EXPORT_SYMBOL(dvb_unregister_device); - -static int dvbdev_check_free_adapter_num(int num) -{ - struct list_head *entry; - list_for_each(entry, &dvb_adapter_list) { - struct dvb_adapter *adap; - adap = list_entry(entry, struct dvb_adapter, list_head); - if (adap->num == num) - return 0; - } - return 1; -} - -static int dvbdev_get_free_adapter_num (void) -{ - int num = 0; - - while (num < DVB_MAX_ADAPTERS) { - if (dvbdev_check_free_adapter_num(num)) - return num; - num++; - } - - return -ENFILE; -} - - -int dvb_register_adapter(struct dvb_adapter *adap, const char *name, - struct module *module, struct device *device, - short *adapter_nums) -{ - int i, num; - - mutex_lock(&dvbdev_register_lock); - - for (i = 0; i < DVB_MAX_ADAPTERS; ++i) { - num = adapter_nums[i]; - if (num >= 0 && num < DVB_MAX_ADAPTERS) { - /* use the one the driver asked for */ - if (dvbdev_check_free_adapter_num(num)) - break; - } else { - num = dvbdev_get_free_adapter_num(); - break; - } - num = -1; - } - - if (num < 0) { - mutex_unlock(&dvbdev_register_lock); - return -ENFILE; - } - - memset (adap, 0, sizeof(struct dvb_adapter)); - INIT_LIST_HEAD (&adap->device_list); - - printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); - - adap->num = num; - adap->name = name; - adap->module = module; - adap->device = device; - adap->mfe_shared = 0; - adap->mfe_dvbdev = NULL; - mutex_init (&adap->mfe_lock); - - list_add_tail (&adap->list_head, &dvb_adapter_list); - - mutex_unlock(&dvbdev_register_lock); - - return num; -} -EXPORT_SYMBOL(dvb_register_adapter); - - -int dvb_unregister_adapter(struct dvb_adapter *adap) -{ - mutex_lock(&dvbdev_register_lock); - list_del (&adap->list_head); - mutex_unlock(&dvbdev_register_lock); - return 0; -} -EXPORT_SYMBOL(dvb_unregister_adapter); - -/* if the miracle happens and "generic_usercopy()" is included into - the kernel, then this can vanish. please don't make the mistake and - define this as video_usercopy(). this will introduce a dependecy - to the v4l "videodev.o" module, which is unnecessary for some - cards (ie. the budget dvb-cards don't need the v4l module...) */ -int dvb_usercopy(struct file *file, - unsigned int cmd, unsigned long arg, - int (*func)(struct file *file, - unsigned int cmd, void *arg)) -{ - char sbuf[128]; - void *mbuf = NULL; - void *parg = NULL; - int err = -EINVAL; - - /* Copy arguments into temp kernel buffer */ - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: - /* - * For this command, the pointer is actually an integer - * argument. - */ - parg = (void *) arg; - break; - case _IOC_READ: /* some v4l ioctls are marked wrong ... */ - case _IOC_WRITE: - case (_IOC_WRITE | _IOC_READ): - if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { - parg = sbuf; - } else { - /* too big to allocate from stack */ - mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); - if (NULL == mbuf) - return -ENOMEM; - parg = mbuf; - } - - err = -EFAULT; - if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) - goto out; - break; - } - - /* call driver */ - mutex_lock(&dvbdev_mutex); - if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) - err = -EINVAL; - mutex_unlock(&dvbdev_mutex); - - if (err < 0) - goto out; - - /* Copy results into user buffer */ - switch (_IOC_DIR(cmd)) - { - case _IOC_READ: - case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) - err = -EFAULT; - break; - } - -out: - kfree(mbuf); - return err; -} - -static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct dvb_device *dvbdev = dev_get_drvdata(dev); - - add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num); - add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]); - add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id); - return 0; -} - -static char *dvb_devnode(struct device *dev, mode_t *mode) -{ - struct dvb_device *dvbdev = dev_get_drvdata(dev); - - return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d", - dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id); -} - - -static int __init init_dvbdev(void) -{ - int retval; - dev_t dev = MKDEV(DVB_MAJOR, 0); - - if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { - printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); - return retval; - } - - cdev_init(&dvb_device_cdev, &dvb_device_fops); - if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { - printk(KERN_ERR "dvb-core: unable register character device\n"); - goto error; - } - - dvb_class = class_create(THIS_MODULE, "dvb"); - if (IS_ERR(dvb_class)) { - retval = PTR_ERR(dvb_class); - goto error; - } - dvb_class->dev_uevent = dvb_uevent; - dvb_class->devnode = dvb_devnode; - return 0; - -error: - cdev_del(&dvb_device_cdev); - unregister_chrdev_region(dev, MAX_DVB_MINORS); - return retval; -} - - -static void __exit exit_dvbdev(void) -{ - class_destroy(dvb_class); - cdev_del(&dvb_device_cdev); - unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); -} - -subsys_initcall(init_dvbdev); -module_exit(exit_dvbdev); - -MODULE_DESCRIPTION("DVB Core Driver"); -MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvbdev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvbdev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvbdev.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvbdev.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,172 +0,0 @@ -/* - * dvbdev.h - * - * Copyright (C) 2000 Ralph Metzler & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Lesser Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVBDEV_H_ -#define _DVBDEV_H_ - -#include -#include -#include -#include - -#define DVB_MAJOR 212 - -#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0 - #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS -#else - #define DVB_MAX_ADAPTERS 8 -#endif - -#define DVB_UNSET (-1) - -#define DVB_DEVICE_VIDEO 0 -#define DVB_DEVICE_AUDIO 1 -#define DVB_DEVICE_SEC 2 -#define DVB_DEVICE_FRONTEND 3 -#define DVB_DEVICE_DEMUX 4 -#define DVB_DEVICE_DVR 5 -#define DVB_DEVICE_CA 6 -#define DVB_DEVICE_NET 7 -#define DVB_DEVICE_OSD 8 - -#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \ - static short adapter_nr[] = \ - {[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \ - module_param_array(adapter_nr, short, NULL, 0444); \ - MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers") - -struct dvb_frontend; - -struct dvb_adapter { - int num; - struct list_head list_head; - struct list_head device_list; - const char *name; - u8 proposed_mac [6]; - void* priv; - - struct device *device; - - struct module *module; - - int mfe_shared; /* indicates mutually exclusive frontends */ - struct dvb_device *mfe_dvbdev; /* frontend device in use */ - struct mutex mfe_lock; /* access lock for thread creation */ - - /* Allow the adapter/bridge driver to perform an action before and/or - * after the core handles an ioctl: - * - * DVB_FE_IOCTL_PRE indicates that the ioctl has not yet been handled. - * DVB_FE_IOCTL_POST indicates that the ioctl has been handled. - * - * When DVB_FE_IOCTL_PRE is passed to the callback as the stage arg: - * - * return 0 to allow dvb-core to handle the ioctl. - * return a positive int to prevent dvb-core from handling the ioctl, - * and exit without error. - * return a negative int to prevent dvb-core from handling the ioctl, - * and return that value as an error. - * - * When DVB_FE_IOCTL_POST is passed to the callback as the stage arg: - * - * return 0 to allow the dvb_frontend ioctl handler to exit normally. - * return a negative int to cause the dvb_frontend ioctl handler to - * return that value as an error. - */ -#define DVB_FE_IOCTL_PRE 0 -#define DVB_FE_IOCTL_POST 1 - int (*fe_ioctl_override)(struct dvb_frontend *fe, - unsigned int cmd, void *parg, - unsigned int stage); -}; - - -struct dvb_device { - struct list_head list_head; - const struct file_operations *fops; - struct dvb_adapter *adapter; - int type; - int minor; - u32 id; - - /* in theory, 'users' can vanish now, - but I don't want to change too much now... */ - int readers; - int writers; - int users; - - wait_queue_head_t wait_queue; - /* don't really need those !? -- FIXME: use video_usercopy */ - int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg); - - void *priv; -}; - - -extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name, - struct module *module, struct device *device, - short *adapter_nums); -extern int dvb_unregister_adapter (struct dvb_adapter *adap); - -extern int dvb_register_device (struct dvb_adapter *adap, - struct dvb_device **pdvbdev, - const struct dvb_device *template, - void *priv, - int type); - -extern void dvb_unregister_device (struct dvb_device *dvbdev); - -extern int dvb_generic_open (struct inode *inode, struct file *file); -extern int dvb_generic_release (struct inode *inode, struct file *file); -extern long dvb_generic_ioctl (struct file *file, - unsigned int cmd, unsigned long arg); - -/* we don't mess with video_usercopy() any more, -we simply define out own dvb_usercopy(), which will hopefully become -generic_usercopy() someday... */ - -extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, - int (*func)(struct file *file, unsigned int cmd, void *arg)); - -/** generic DVB attach function. */ -#ifdef CONFIG_MEDIA_ATTACH -#define dvb_attach(FUNCTION, ARGS...) ({ \ - void *__r = NULL; \ - typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ - if (__a) { \ - __r = (void *) __a(ARGS); \ - if (__r == NULL) \ - symbol_put(FUNCTION); \ - } else { \ - printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \ - } \ - __r; \ -}) - -#else -#define dvb_attach(FUNCTION, ARGS...) ({ \ - FUNCTION(ARGS); \ -}) - -#endif - -#endif /* #ifndef _DVBDEV_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_filter.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_filter.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_filter.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_filter.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,603 +0,0 @@ -#include -#include -#include -#include "dvb_filter.h" - -#if 0 -static unsigned int bitrates[3][16] = -{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, - {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, - {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; -#endif - -static u32 freq[4] = {480, 441, 320, 0}; - -static unsigned int ac3_bitrates[32] = - {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, - 0,0,0,0,0,0,0,0,0,0,0,0,0}; - -static u32 ac3_frames[3][32] = - {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, - 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, - 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, - 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; - - - -#if 0 -static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, - void (*pes_write)(u8 *buf, int count, void *data), - void *priv) -{ - dvb_filter_ipack_init(pa, IPACKS, pes_write); - dvb_filter_ipack_init(pv, IPACKS, pes_write); - pa->pid = pida; - pv->pid = pidv; - pa->data = priv; - pv->data = priv; -} -#endif - -#if 0 -static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) -{ - u8 off = 0; - - if (!buf || !p ){ - printk("NULL POINTER IDIOT\n"); - return; - } - if (buf[1]&PAY_START) { - if (p->plength == MMAX_PLENGTH-6 && p->found>6){ - p->plength = p->found-6; - p->found = 0; - send_ipack(p); - dvb_filter_ipack_reset(p); - } - } - if (buf[3] & ADAPT_FIELD) { // adaptation field? - off = buf[4] + 1; - if (off+4 > 187) return; - } - dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p); -} -#endif - -#if 0 -/* needs 5 byte input, returns picture coding type*/ -static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr) -{ - u8 pct; - - if (pr) printk( "Pic header: "); - pic->temporal_reference[field] = (( headr[0] << 2 ) | - (headr[1] & 0x03) )& 0x03ff; - if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]); - - pct = ( headr[1] >> 2 ) & 0x07; - pic->picture_coding_type[field] = pct; - if (pr) { - switch(pct){ - case I_FRAME: - printk( " I-FRAME"); - break; - case B_FRAME: - printk( " B-FRAME"); - break; - case P_FRAME: - printk( " P-FRAME"); - break; - } - } - - - pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) | - ( (headr[3] & 0x1F) << 11) ) & 0xffff; - - if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay); - - pic->picture_header_parameter = ( headr[3] & 0xe0 ) | - ((headr[4] & 0x80) >> 3); - - if ( pct == B_FRAME ){ - pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f; - } - if (pr) printk( " pic head param: 0x%x", - pic->picture_header_parameter); - - return pct; -} -#endif - -#if 0 -/* needs 4 byte input */ -static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr) -{ - if (pr) printk("GOP header: "); - - pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) | - ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff; - - if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F, - ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F), - ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F)); - - if ( ( headr[3] & 0x40 ) != 0 ){ - pic->closed_gop = 1; - } else { - pic->closed_gop = 0; - } - if (pr) printk("closed: %d", pic->closed_gop); - - if ( ( headr[3] & 0x20 ) != 0 ){ - pic->broken_link = 1; - } else { - pic->broken_link = 0; - } - if (pr) printk(" broken: %d\n", pic->broken_link); - - return 0; -} -#endif - -#if 0 -/* needs 8 byte input */ -static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr) -{ - int sw; - int form = -1; - - if (pr) printk("Reading sequence header\n"); - - vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); - vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); - - sw = (int)((headr[3]&0xF0) >> 4) ; - - switch( sw ){ - case 1: - if (pr) - printk("Videostream: ASPECT: 1:1"); - vi->aspect_ratio = 100; - break; - case 2: - if (pr) - printk("Videostream: ASPECT: 4:3"); - vi->aspect_ratio = 133; - break; - case 3: - if (pr) - printk("Videostream: ASPECT: 16:9"); - vi->aspect_ratio = 177; - break; - case 4: - if (pr) - printk("Videostream: ASPECT: 2.21:1"); - vi->aspect_ratio = 221; - break; - - case 5 ... 15: - if (pr) - printk("Videostream: ASPECT: reserved"); - vi->aspect_ratio = 0; - break; - - default: - vi->aspect_ratio = 0; - return -1; - } - - if (pr) - printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); - - sw = (int)(headr[3]&0x0F); - - switch ( sw ) { - case 1: - if (pr) - printk(" FRate: 23.976 fps"); - vi->framerate = 23976; - form = -1; - break; - case 2: - if (pr) - printk(" FRate: 24 fps"); - vi->framerate = 24000; - form = -1; - break; - case 3: - if (pr) - printk(" FRate: 25 fps"); - vi->framerate = 25000; - form = VIDEO_MODE_PAL; - break; - case 4: - if (pr) - printk(" FRate: 29.97 fps"); - vi->framerate = 29970; - form = VIDEO_MODE_NTSC; - break; - case 5: - if (pr) - printk(" FRate: 30 fps"); - vi->framerate = 30000; - form = VIDEO_MODE_NTSC; - break; - case 6: - if (pr) - printk(" FRate: 50 fps"); - vi->framerate = 50000; - form = VIDEO_MODE_PAL; - break; - case 7: - if (pr) - printk(" FRate: 60 fps"); - vi->framerate = 60000; - form = VIDEO_MODE_NTSC; - break; - } - - vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03); - - vi->vbv_buffer_size - = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5); - - if (pr){ - printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000); - printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size)); - printk("\n"); - } - - vi->video_format = form; - - return 0; -} -#endif - - -#if 0 -static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr) -{ - u8 *headr; - int found = 0; - int c = 0; - - while (found < 4 && c+4 < count){ - u8 *b; - - b = mbuf+c; - if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 - && b[3] == 0xb3) found = 4; - else { - c++; - } - } - - if (! found) return -1; - c += 4; - if (c+12 >= count) return -1; - headr = mbuf+c; - if (read_sequence_header(headr, vi, pr) < 0) return -1; - vi->off = c-4; - return 0; -} -#endif - - -#if 0 -static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) -{ - u8 *headr; - int found = 0; - int c = 0; - int fr = 0; - - while (found < 2 && c < count){ - u8 b[2]; - memcpy( b, mbuf+c, 2); - - if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) - found = 2; - else { - c++; - } - } - - if (!found) return -1; - - if (c+3 >= count) return -1; - headr = mbuf+c; - - ai->layer = (headr[1] & 0x06) >> 1; - - if (pr) - printk("Audiostream: Layer: %d", 4-ai->layer); - - - ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; - - if (pr){ - if (ai->bit_rate == 0) - printk(" Bit rate: free"); - else if (ai->bit_rate == 0xf) - printk(" BRate: reserved"); - else - printk(" BRate: %d kb/s", ai->bit_rate/1000); - } - - fr = (headr[2] & 0x0c ) >> 2; - ai->frequency = freq[fr]*100; - if (pr){ - if (ai->frequency == 3) - printk(" Freq: reserved\n"); - else - printk(" Freq: %d kHz\n",ai->frequency); - - } - ai->off = c; - return 0; -} -#endif - - -int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) -{ - u8 *headr; - int found = 0; - int c = 0; - u8 frame = 0; - int fr = 0; - - while ( !found && c < count){ - u8 *b = mbuf+c; - - if ( b[0] == 0x0b && b[1] == 0x77 ) - found = 1; - else { - c++; - } - } - - if (!found) return -1; - if (pr) - printk("Audiostream: AC3"); - - ai->off = c; - if (c+5 >= count) return -1; - - ai->layer = 0; // 0 for AC3 - headr = mbuf+c+2; - - frame = (headr[2]&0x3f); - ai->bit_rate = ac3_bitrates[frame >> 1]*1000; - - if (pr) - printk(" BRate: %d kb/s", (int) ai->bit_rate/1000); - - ai->frequency = (headr[2] & 0xc0 ) >> 6; - fr = (headr[2] & 0xc0 ) >> 6; - ai->frequency = freq[fr]*100; - if (pr) printk (" Freq: %d Hz\n", (int) ai->frequency); - - - ai->framesize = ac3_frames[fr][frame >> 1]; - if ((frame & 1) && (fr == 1)) ai->framesize++; - ai->framesize = ai->framesize << 1; - if (pr) printk (" Framesize %d\n",(int) ai->framesize); - - - return 0; -} -EXPORT_SYMBOL(dvb_filter_get_ac3info); - - -#if 0 -static u8 *skip_pes_header(u8 **bufp) -{ - u8 *inbuf = *bufp; - u8 *buf = inbuf; - u8 *pts = NULL; - int skip = 0; - - static const int mpeg1_skip_table[16] = { - 1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff - }; - - - if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ - if (buf[7] & PTS_ONLY) - pts = buf+9; - else pts = NULL; - buf = inbuf + 9 + inbuf[8]; - } else { /* mpeg1 */ - for (buf = inbuf + 6; *buf == 0xff; buf++) - if (buf == inbuf + 6 + 16) { - break; - } - if ((*buf & 0xc0) == 0x40) - buf += 2; - skip = mpeg1_skip_table [*buf >> 4]; - if (skip == 5 || skip == 10) pts = buf; - else pts = NULL; - - buf += mpeg1_skip_table [*buf >> 4]; - } - - *bufp = buf; - return pts; -} -#endif - -#if 0 -static void initialize_quant_matrix( u32 *matrix ) -{ - int i; - - matrix[0] = 0x08101013; - matrix[1] = 0x10131616; - matrix[2] = 0x16161616; - matrix[3] = 0x1a181a1b; - matrix[4] = 0x1b1b1a1a; - matrix[5] = 0x1a1a1b1b; - matrix[6] = 0x1b1d1d1d; - matrix[7] = 0x2222221d; - matrix[8] = 0x1d1d1b1b; - matrix[9] = 0x1d1d2020; - matrix[10] = 0x22222526; - matrix[11] = 0x25232322; - matrix[12] = 0x23262628; - matrix[13] = 0x28283030; - matrix[14] = 0x2e2e3838; - matrix[15] = 0x3a454553; - - for ( i = 16 ; i < 32 ; i++ ) - matrix[i] = 0x10101010; -} -#endif - -#if 0 -static void initialize_mpg_picture(struct mpg_picture *pic) -{ - int i; - - /* set MPEG1 */ - pic->mpeg1_flag = 1; - pic->profile_and_level = 0x4A ; /* MP@LL */ - pic->progressive_sequence = 1; - pic->low_delay = 0; - - pic->sequence_display_extension_flag = 0; - for ( i = 0 ; i < 4 ; i++ ){ - pic->frame_centre_horizontal_offset[i] = 0; - pic->frame_centre_vertical_offset[i] = 0; - } - pic->last_frame_centre_horizontal_offset = 0; - pic->last_frame_centre_vertical_offset = 0; - - pic->picture_display_extension_flag[0] = 0; - pic->picture_display_extension_flag[1] = 0; - pic->sequence_header_flag = 0; - pic->gop_flag = 0; - pic->sequence_end_flag = 0; -} -#endif - -#if 0 -static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic ) -{ - int16_t last_h_offset; - int16_t last_v_offset; - - int16_t *p_h_offset; - int16_t *p_v_offset; - - if ( pic->mpeg1_flag ){ - pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE; - pic->top_field_first = 0; - pic->repeat_first_field = 0; - pic->progressive_frame = 1; - pic->picture_coding_parameter = 0x000010; - } - - /* Reset flag */ - pic->picture_display_extension_flag[field_type] = 0; - - last_h_offset = pic->last_frame_centre_horizontal_offset; - last_v_offset = pic->last_frame_centre_vertical_offset; - if ( field_type == FIRST_FIELD ){ - p_h_offset = pic->frame_centre_horizontal_offset; - p_v_offset = pic->frame_centre_vertical_offset; - *p_h_offset = last_h_offset; - *(p_h_offset + 1) = last_h_offset; - *(p_h_offset + 2) = last_h_offset; - *p_v_offset = last_v_offset; - *(p_v_offset + 1) = last_v_offset; - *(p_v_offset + 2) = last_v_offset; - } else { - pic->frame_centre_horizontal_offset[3] = last_h_offset; - pic->frame_centre_vertical_offset[3] = last_v_offset; - } -} -#endif - -#if 0 -static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type) -{ - pic->picture_header = 0; - pic->sequence_header_data - = ( INIT_HORIZONTAL_SIZE << 20 ) - | ( INIT_VERTICAL_SIZE << 8 ) - | ( INIT_ASPECT_RATIO << 4 ) - | ( INIT_FRAME_RATE ); - pic->mpeg1_flag = 0; - pic->vinfo.horizontal_size - = INIT_DISP_HORIZONTAL_SIZE; - pic->vinfo.vertical_size - = INIT_DISP_VERTICAL_SIZE; - pic->picture_display_extension_flag[field_type] - = 0; - pic->pts_flag[field_type] = 0; - - pic->sequence_gop_header = 0; - pic->picture_header = 0; - pic->sequence_header_flag = 0; - pic->gop_flag = 0; - pic->sequence_end_flag = 0; - pic->sequence_display_extension_flag = 0; - pic->last_frame_centre_horizontal_offset = 0; - pic->last_frame_centre_vertical_offset = 0; - pic->channel = chan; -} -#endif - -void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, - dvb_filter_pes2ts_cb_t *cb, void *priv) -{ - unsigned char *buf=p2ts->buf; - - buf[0]=0x47; - buf[1]=(pid>>8); - buf[2]=pid&0xff; - p2ts->cc=0; - p2ts->cb=cb; - p2ts->priv=priv; -} -EXPORT_SYMBOL(dvb_filter_pes2ts_init); - -int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, - int len, int payload_start) -{ - unsigned char *buf=p2ts->buf; - int ret=0, rest; - - //len=6+((pes[4]<<8)|pes[5]); - - if (payload_start) - buf[1]|=0x40; - else - buf[1]&=~0x40; - while (len>=184) { - buf[3]=0x10|((p2ts->cc++)&0x0f); - memcpy(buf+4, pes, 184); - if ((ret=p2ts->cb(p2ts->priv, buf))) - return ret; - len-=184; pes+=184; - buf[1]&=~0x40; - } - if (!len) - return 0; - buf[3]=0x30|((p2ts->cc++)&0x0f); - rest=183-len; - if (rest) { - buf[5]=0x00; - if (rest-1) - memset(buf+6, 0xff, rest-1); - } - buf[4]=rest; - memcpy(buf+5+rest, pes, len); - return p2ts->cb(p2ts->priv, buf); -} -EXPORT_SYMBOL(dvb_filter_pes2ts); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_filter.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_filter.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_filter.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_filter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,246 +0,0 @@ -/* - * dvb_filter.h - * - * Copyright (C) 2003 Convergence GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - */ - -#ifndef _DVB_FILTER_H_ -#define _DVB_FILTER_H_ - -#include - -#include "demux.h" - -typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); - -struct dvb_filter_pes2ts { - unsigned char buf[188]; - unsigned char cc; - dvb_filter_pes2ts_cb_t *cb; - void *priv; -}; - -void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, - dvb_filter_pes2ts_cb_t *cb, void *priv); - -int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, - int len, int payload_start); - - -#define PROG_STREAM_MAP 0xBC -#define PRIVATE_STREAM1 0xBD -#define PADDING_STREAM 0xBE -#define PRIVATE_STREAM2 0xBF -#define AUDIO_STREAM_S 0xC0 -#define AUDIO_STREAM_E 0xDF -#define VIDEO_STREAM_S 0xE0 -#define VIDEO_STREAM_E 0xEF -#define ECM_STREAM 0xF0 -#define EMM_STREAM 0xF1 -#define DSM_CC_STREAM 0xF2 -#define ISO13522_STREAM 0xF3 -#define PROG_STREAM_DIR 0xFF - -#define DVB_PICTURE_START 0x00 -#define DVB_USER_START 0xb2 -#define DVB_SEQUENCE_HEADER 0xb3 -#define DVB_SEQUENCE_ERROR 0xb4 -#define DVB_EXTENSION_START 0xb5 -#define DVB_SEQUENCE_END 0xb7 -#define DVB_GOP_START 0xb8 -#define DVB_EXCEPT_SLICE 0xb0 - -#define SEQUENCE_EXTENSION 0x01 -#define SEQUENCE_DISPLAY_EXTENSION 0x02 -#define PICTURE_CODING_EXTENSION 0x08 -#define QUANT_MATRIX_EXTENSION 0x03 -#define PICTURE_DISPLAY_EXTENSION 0x07 - -#define I_FRAME 0x01 -#define B_FRAME 0x02 -#define P_FRAME 0x03 - -/* Initialize sequence_data */ -#define INIT_HORIZONTAL_SIZE 720 -#define INIT_VERTICAL_SIZE 576 -#define INIT_ASPECT_RATIO 0x02 -#define INIT_FRAME_RATE 0x03 -#define INIT_DISP_HORIZONTAL_SIZE 540 -#define INIT_DISP_VERTICAL_SIZE 576 - - -//flags2 -#define PTS_DTS_FLAGS 0xC0 -#define ESCR_FLAG 0x20 -#define ES_RATE_FLAG 0x10 -#define DSM_TRICK_FLAG 0x08 -#define ADD_CPY_FLAG 0x04 -#define PES_CRC_FLAG 0x02 -#define PES_EXT_FLAG 0x01 - -//pts_dts flags -#define PTS_ONLY 0x80 -#define PTS_DTS 0xC0 - -#define TS_SIZE 188 -#define TRANS_ERROR 0x80 -#define PAY_START 0x40 -#define TRANS_PRIO 0x20 -#define PID_MASK_HI 0x1F -//flags -#define TRANS_SCRMBL1 0x80 -#define TRANS_SCRMBL2 0x40 -#define ADAPT_FIELD 0x20 -#define PAYLOAD 0x10 -#define COUNT_MASK 0x0F - -// adaptation flags -#define DISCON_IND 0x80 -#define RAND_ACC_IND 0x40 -#define ES_PRI_IND 0x20 -#define PCR_FLAG 0x10 -#define OPCR_FLAG 0x08 -#define SPLICE_FLAG 0x04 -#define TRANS_PRIV 0x02 -#define ADAP_EXT_FLAG 0x01 - -// adaptation extension flags -#define LTW_FLAG 0x80 -#define PIECE_RATE 0x40 -#define SEAM_SPLICE 0x20 - - -#define MAX_PLENGTH 0xFFFF -#define MMAX_PLENGTH (256*MAX_PLENGTH) - -#ifndef IPACKS -#define IPACKS 2048 -#endif - -struct ipack { - int size; - int found; - u8 *buf; - u8 cid; - u32 plength; - u8 plen[2]; - u8 flag1; - u8 flag2; - u8 hlength; - u8 pts[5]; - u16 *pid; - int mpeg; - u8 check; - int which; - int done; - void *data; - void (*func)(u8 *buf, int size, void *priv); - int count; - int repack_subids; -}; - -struct dvb_video_info { - u32 horizontal_size; - u32 vertical_size; - u32 aspect_ratio; - u32 framerate; - u32 video_format; - u32 bit_rate; - u32 comp_bit_rate; - u32 vbv_buffer_size; - s16 vbv_delay; - u32 CSPF; - u32 off; -}; - -#define OFF_SIZE 4 -#define FIRST_FIELD 0 -#define SECOND_FIELD 1 -#define VIDEO_FRAME_PICTURE 0x03 - -struct mpg_picture { - int channel; - struct dvb_video_info vinfo; - u32 *sequence_gop_header; - u32 *picture_header; - s32 time_code; - int low_delay; - int closed_gop; - int broken_link; - int sequence_header_flag; - int gop_flag; - int sequence_end_flag; - - u8 profile_and_level; - s32 picture_coding_parameter; - u32 matrix[32]; - s8 matrix_change_flag; - - u8 picture_header_parameter; - /* bit 0 - 2: bwd f code - bit 3 : fpb vector - bit 4 - 6: fwd f code - bit 7 : fpf vector */ - - int mpeg1_flag; - int progressive_sequence; - int sequence_display_extension_flag; - u32 sequence_header_data; - s16 last_frame_centre_horizontal_offset; - s16 last_frame_centre_vertical_offset; - - u32 pts[2]; /* [0] 1st field, [1] 2nd field */ - int top_field_first; - int repeat_first_field; - int progressive_frame; - int bank; - int forward_bank; - int backward_bank; - int compress; - s16 frame_centre_horizontal_offset[OFF_SIZE]; - /* [0-2] 1st field, [3] 2nd field */ - s16 frame_centre_vertical_offset[OFF_SIZE]; - /* [0-2] 1st field, [3] 2nd field */ - s16 temporal_reference[2]; - /* [0] 1st field, [1] 2nd field */ - - s8 picture_coding_type[2]; - /* [0] 1st field, [1] 2nd field */ - s8 picture_structure[2]; - /* [0] 1st field, [1] 2nd field */ - s8 picture_display_extension_flag[2]; - /* [0] 1st field, [1] 2nd field */ - /* picture_display_extenion() 0:no 1:exit*/ - s8 pts_flag[2]; - /* [0] 1st field, [1] 2nd field */ -}; - -struct dvb_audio_info { - int layer; - u32 bit_rate; - u32 frequency; - u32 mode; - u32 mode_extension ; - u32 emphasis; - u32 framesize; - u32 off; -}; - -int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr); - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_frontend.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_frontend.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_frontend.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_frontend.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2143 +0,0 @@ -/* - * dvb_frontend.c: DVB frontend tuning interface/thread - * - * - * Copyright (C) 1999-2001 Ralph Metzler - * Marcus Metzler - * Holger Waechtler - * for convergence integrated media GmbH - * - * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup) - * - * 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, or (at your option) any later version. - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvbdev.h" -#include - -static int dvb_frontend_debug; -static int dvb_shutdown_timeout; -static int dvb_force_auto_inversion; -static int dvb_override_tune_delay; -static int dvb_powerdown_on_sleep = 1; -static int dvb_mfe_wait_time = 5; - -module_param_named(frontend_debug, dvb_frontend_debug, int, 0644); -MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off)."); -module_param(dvb_shutdown_timeout, int, 0644); -MODULE_PARM_DESC(dvb_shutdown_timeout, "wait seconds after close() before suspending hardware"); -module_param(dvb_force_auto_inversion, int, 0644); -MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always"); -module_param(dvb_override_tune_delay, int, 0644); -MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt"); -module_param(dvb_powerdown_on_sleep, int, 0644); -MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)"); -module_param(dvb_mfe_wait_time, int, 0644); -MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to seconds on open() for multi-frontend to become available (default:5 seconds)"); - -#define dprintk if (dvb_frontend_debug) printk - -#define FESTATE_IDLE 1 -#define FESTATE_RETUNE 2 -#define FESTATE_TUNING_FAST 4 -#define FESTATE_TUNING_SLOW 8 -#define FESTATE_TUNED 16 -#define FESTATE_ZIGZAG_FAST 32 -#define FESTATE_ZIGZAG_SLOW 64 -#define FESTATE_DISEQC 128 -#define FESTATE_ERROR 256 -#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC) -#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST) -#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW) -#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW) - -#define FE_ALGO_HW 1 -/* - * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling. - * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune. - * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress. - * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower. - * FESTATE_TUNED. The frontend has successfully locked on. - * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it. - * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower. - * FESTATE_DISEQC. A DISEQC command has just been issued. - * FESTATE_WAITFORLOCK. When we're waiting for a lock. - * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan. - * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan. - * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again. - */ - -#define DVB_FE_NO_EXIT 0 -#define DVB_FE_NORMAL_EXIT 1 -#define DVB_FE_DEVICE_REMOVED 2 - -static DEFINE_MUTEX(frontend_mutex); - -struct dvb_frontend_private { - - /* thread/frontend values */ - struct dvb_device *dvbdev; - struct dvb_frontend_parameters parameters; - struct dvb_fe_events events; - struct semaphore sem; - struct list_head list_head; - wait_queue_head_t wait_queue; - struct task_struct *thread; - unsigned long release_jiffies; - unsigned int exit; - unsigned int wakeup; - fe_status_t status; - unsigned long tune_mode_flags; - unsigned int delay; - unsigned int reinitialise; - int tone; - int voltage; - - /* swzigzag values */ - unsigned int state; - unsigned int bending; - int lnb_drift; - unsigned int inversion; - unsigned int auto_step; - unsigned int auto_sub_step; - unsigned int started_auto_step; - unsigned int min_delay; - unsigned int max_drift; - unsigned int step_size; - int quality; - unsigned int check_wrapped; - enum dvbfe_search algo_status; -}; - -static void dvb_frontend_wakeup(struct dvb_frontend *fe); - -static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) -{ - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_fe_events *events = &fepriv->events; - struct dvb_frontend_event *e; - int wp; - - dprintk ("%s\n", __func__); - - if (mutex_lock_interruptible (&events->mtx)) - return; - - wp = (events->eventw + 1) % MAX_EVENT; - - if (wp == events->eventr) { - events->overflow = 1; - events->eventr = (events->eventr + 1) % MAX_EVENT; - } - - e = &events->events[events->eventw]; - - memcpy (&e->parameters, &fepriv->parameters, - sizeof (struct dvb_frontend_parameters)); - - if (status & FE_HAS_LOCK) - if (fe->ops.get_frontend) - fe->ops.get_frontend(fe, &e->parameters); - - events->eventw = wp; - - mutex_unlock(&events->mtx); - - e->status = status; - - wake_up_interruptible (&events->wait_queue); -} - -static int dvb_frontend_get_event(struct dvb_frontend *fe, - struct dvb_frontend_event *event, int flags) -{ - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_fe_events *events = &fepriv->events; - - dprintk ("%s\n", __func__); - - if (events->overflow) { - events->overflow = 0; - return -EOVERFLOW; - } - - if (events->eventw == events->eventr) { - int ret; - - if (flags & O_NONBLOCK) - return -EWOULDBLOCK; - - up(&fepriv->sem); - - ret = wait_event_interruptible (events->wait_queue, - events->eventw != events->eventr); - - if (down_interruptible (&fepriv->sem)) - return -ERESTARTSYS; - - if (ret < 0) - return ret; - } - - if (mutex_lock_interruptible (&events->mtx)) - return -ERESTARTSYS; - - memcpy (event, &events->events[events->eventr], - sizeof(struct dvb_frontend_event)); - - events->eventr = (events->eventr + 1) % MAX_EVENT; - - mutex_unlock(&events->mtx); - - return 0; -} - -static void dvb_frontend_init(struct dvb_frontend *fe) -{ - dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n", - fe->dvb->num, - fe->id, - fe->ops.info.name); - - if (fe->ops.init) - fe->ops.init(fe); - if (fe->ops.tuner_ops.init) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.init(fe); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } -} - -void dvb_frontend_reinitialise(struct dvb_frontend *fe) -{ - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - fepriv->reinitialise = 1; - dvb_frontend_wakeup(fe); -} -EXPORT_SYMBOL(dvb_frontend_reinitialise); - -static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked) -{ - int q2; - - dprintk ("%s\n", __func__); - - if (locked) - (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256; - else - (fepriv->quality) = (fepriv->quality * 220 + 0) / 256; - - q2 = fepriv->quality - 128; - q2 *= q2; - - fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128); -} - -/** - * Performs automatic twiddling of frontend parameters. - * - * @param fe The frontend concerned. - * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT - * @returns Number of complete iterations that have been performed. - */ -static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped) -{ - int autoinversion; - int ready = 0; - int fe_set_err = 0; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - int original_inversion = fepriv->parameters.inversion; - u32 original_frequency = fepriv->parameters.frequency; - - /* are we using autoinversion? */ - autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters.inversion == INVERSION_AUTO)); - - /* setup parameters correctly */ - while(!ready) { - /* calculate the lnb_drift */ - fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size; - - /* wrap the auto_step if we've exceeded the maximum drift */ - if (fepriv->lnb_drift > fepriv->max_drift) { - fepriv->auto_step = 0; - fepriv->auto_sub_step = 0; - fepriv->lnb_drift = 0; - } - - /* perform inversion and +/- zigzag */ - switch(fepriv->auto_sub_step) { - case 0: - /* try with the current inversion and current drift setting */ - ready = 1; - break; - - case 1: - if (!autoinversion) break; - - fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; - ready = 1; - break; - - case 2: - if (fepriv->lnb_drift == 0) break; - - fepriv->lnb_drift = -fepriv->lnb_drift; - ready = 1; - break; - - case 3: - if (fepriv->lnb_drift == 0) break; - if (!autoinversion) break; - - fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; - fepriv->lnb_drift = -fepriv->lnb_drift; - ready = 1; - break; - - default: - fepriv->auto_step++; - fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */ - break; - } - - if (!ready) fepriv->auto_sub_step++; - } - - /* if this attempt would hit where we started, indicate a complete - * iteration has occurred */ - if ((fepriv->auto_step == fepriv->started_auto_step) && - (fepriv->auto_sub_step == 0) && check_wrapped) { - return 1; - } - - dprintk("%s: drift:%i inversion:%i auto_step:%i " - "auto_sub_step:%i started_auto_step:%i\n", - __func__, fepriv->lnb_drift, fepriv->inversion, - fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step); - - /* set the frontend itself */ - fepriv->parameters.frequency += fepriv->lnb_drift; - if (autoinversion) - fepriv->parameters.inversion = fepriv->inversion; - if (fe->ops.set_frontend) - fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters); - if (fe_set_err < 0) { - fepriv->state = FESTATE_ERROR; - return fe_set_err; - } - - fepriv->parameters.frequency = original_frequency; - fepriv->parameters.inversion = original_inversion; - - fepriv->auto_sub_step++; - return 0; -} - -static void dvb_frontend_swzigzag(struct dvb_frontend *fe) -{ - fe_status_t s = 0; - int retval = 0; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - /* if we've got no parameters, just keep idling */ - if (fepriv->state & FESTATE_IDLE) { - fepriv->delay = 3*HZ; - fepriv->quality = 0; - return; - } - - /* in SCAN mode, we just set the frontend when asked and leave it alone */ - if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { - if (fepriv->state & FESTATE_RETUNE) { - if (fe->ops.set_frontend) - retval = fe->ops.set_frontend(fe, - &fepriv->parameters); - if (retval < 0) - fepriv->state = FESTATE_ERROR; - else - fepriv->state = FESTATE_TUNED; - } - fepriv->delay = 3*HZ; - fepriv->quality = 0; - return; - } - - /* get the frontend status */ - if (fepriv->state & FESTATE_RETUNE) { - s = 0; - } else { - if (fe->ops.read_status) - fe->ops.read_status(fe, &s); - if (s != fepriv->status) { - dvb_frontend_add_event(fe, s); - fepriv->status = s; - } - } - - /* if we're not tuned, and we have a lock, move to the TUNED state */ - if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { - dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); - fepriv->state = FESTATE_TUNED; - - /* if we're tuned, then we have determined the correct inversion */ - if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters.inversion == INVERSION_AUTO)) { - fepriv->parameters.inversion = fepriv->inversion; - } - return; - } - - /* if we are tuned already, check we're still locked */ - if (fepriv->state & FESTATE_TUNED) { - dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); - - /* we're tuned, and the lock is still good... */ - if (s & FE_HAS_LOCK) { - return; - } else { /* if we _WERE_ tuned, but now don't have a lock */ - fepriv->state = FESTATE_ZIGZAG_FAST; - fepriv->started_auto_step = fepriv->auto_step; - fepriv->check_wrapped = 0; - } - } - - /* don't actually do anything if we're in the LOSTLOCK state, - * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ - if ((fepriv->state & FESTATE_LOSTLOCK) && - (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { - dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); - return; - } - - /* don't do anything if we're in the DISEQC state, since this - * might be someone with a motorized dish controlled by DISEQC. - * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ - if (fepriv->state & FESTATE_DISEQC) { - dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); - return; - } - - /* if we're in the RETUNE state, set everything up for a brand - * new scan, keeping the current inversion setting, as the next - * tune is _very_ likely to require the same */ - if (fepriv->state & FESTATE_RETUNE) { - fepriv->lnb_drift = 0; - fepriv->auto_step = 0; - fepriv->auto_sub_step = 0; - fepriv->started_auto_step = 0; - fepriv->check_wrapped = 0; - } - - /* fast zigzag. */ - if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { - fepriv->delay = fepriv->min_delay; - - /* perform a tune */ - retval = dvb_frontend_swzigzag_autotune(fe, - fepriv->check_wrapped); - if (retval < 0) { - return; - } else if (retval) { - /* OK, if we've run out of trials at the fast speed. - * Drop back to slow for the _next_ attempt */ - fepriv->state = FESTATE_SEARCHING_SLOW; - fepriv->started_auto_step = fepriv->auto_step; - return; - } - fepriv->check_wrapped = 1; - - /* if we've just retuned, enter the ZIGZAG_FAST state. - * This ensures we cannot return from an - * FE_SET_FRONTEND ioctl before the first frontend tune - * occurs */ - if (fepriv->state & FESTATE_RETUNE) { - fepriv->state = FESTATE_TUNING_FAST; - } - } - - /* slow zigzag */ - if (fepriv->state & FESTATE_SEARCHING_SLOW) { - dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); - - /* Note: don't bother checking for wrapping; we stay in this - * state until we get a lock */ - dvb_frontend_swzigzag_autotune(fe, 0); - } -} - -static int dvb_frontend_is_exiting(struct dvb_frontend *fe) -{ - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - if (fepriv->exit != DVB_FE_NO_EXIT) - return 1; - - if (fepriv->dvbdev->writers == 1) - if (time_after(jiffies, fepriv->release_jiffies + - dvb_shutdown_timeout * HZ)) - return 1; - - return 0; -} - -static int dvb_frontend_should_wakeup(struct dvb_frontend *fe) -{ - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - if (fepriv->wakeup) { - fepriv->wakeup = 0; - return 1; - } - return dvb_frontend_is_exiting(fe); -} - -static void dvb_frontend_wakeup(struct dvb_frontend *fe) -{ - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - fepriv->wakeup = 1; - wake_up_interruptible(&fepriv->wait_queue); -} - -static int dvb_frontend_thread(void *data) -{ - struct dvb_frontend *fe = data; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - unsigned long timeout; - fe_status_t s; - enum dvbfe_algo algo; - - struct dvb_frontend_parameters *params; - - dprintk("%s\n", __func__); - - fepriv->check_wrapped = 0; - fepriv->quality = 0; - fepriv->delay = 3*HZ; - fepriv->status = 0; - fepriv->wakeup = 0; - fepriv->reinitialise = 0; - - dvb_frontend_init(fe); - - set_freezable(); - while (1) { - up(&fepriv->sem); /* is locked when we enter the thread... */ -restart: - timeout = wait_event_interruptible_timeout(fepriv->wait_queue, - dvb_frontend_should_wakeup(fe) || kthread_should_stop() - || freezing(current), - fepriv->delay); - - if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { - /* got signal or quitting */ - fepriv->exit = DVB_FE_NORMAL_EXIT; - break; - } - - if (try_to_freeze()) - goto restart; - - if (down_interruptible(&fepriv->sem)) - break; - - if (fepriv->reinitialise) { - dvb_frontend_init(fe); - if (fepriv->tone != -1) { - fe->ops.set_tone(fe, fepriv->tone); - } - if (fepriv->voltage != -1) { - fe->ops.set_voltage(fe, fepriv->voltage); - } - fepriv->reinitialise = 0; - } - - /* do an iteration of the tuning loop */ - if (fe->ops.get_frontend_algo) { - algo = fe->ops.get_frontend_algo(fe); - switch (algo) { - case DVBFE_ALGO_HW: - dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__); - params = NULL; /* have we been asked to RETUNE ? */ - - if (fepriv->state & FESTATE_RETUNE) { - dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); - params = &fepriv->parameters; - fepriv->state = FESTATE_TUNED; - } - - if (fe->ops.tune) - fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); - - if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) { - dprintk("%s: state changed, adding current state\n", __func__); - dvb_frontend_add_event(fe, s); - fepriv->status = s; - } - break; - case DVBFE_ALGO_SW: - dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__); - dvb_frontend_swzigzag(fe); - break; - case DVBFE_ALGO_CUSTOM: - params = NULL; /* have we been asked to RETUNE ? */ - dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state); - if (fepriv->state & FESTATE_RETUNE) { - dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__); - params = &fepriv->parameters; - fepriv->state = FESTATE_TUNED; - } - /* Case where we are going to search for a carrier - * User asked us to retune again for some reason, possibly - * requesting a search with a new set of parameters - */ - if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) { - if (fe->ops.search) { - fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters); - /* We did do a search as was requested, the flags are - * now unset as well and has the flags wrt to search. - */ - } else { - fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN; - } - } - /* Track the carrier if the search was successful */ - if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { - if (fe->ops.track) - fe->ops.track(fe, &fepriv->parameters); - } else { - fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; - fepriv->delay = HZ / 2; - } - fe->ops.read_status(fe, &s); - if (s != fepriv->status) { - dvb_frontend_add_event(fe, s); /* update event list */ - fepriv->status = s; - if (!(s & FE_HAS_LOCK)) { - fepriv->delay = HZ / 10; - fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; - } else { - fepriv->delay = 60 * HZ; - } - } - break; - default: - dprintk("%s: UNDEFINED ALGO !\n", __func__); - break; - } - } else { - dvb_frontend_swzigzag(fe); - } - } - - if (dvb_powerdown_on_sleep) { - if (fe->ops.set_voltage) - fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); - if (fe->ops.tuner_ops.sleep) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.sleep(fe); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - if (fe->ops.sleep) - fe->ops.sleep(fe); - } - - fepriv->thread = NULL; - if (kthread_should_stop()) - fepriv->exit = DVB_FE_DEVICE_REMOVED; - else - fepriv->exit = DVB_FE_NO_EXIT; - mb(); - - dvb_frontend_wakeup(fe); - return 0; -} - -static void dvb_frontend_stop(struct dvb_frontend *fe) -{ - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - dprintk ("%s\n", __func__); - - fepriv->exit = DVB_FE_NORMAL_EXIT; - mb(); - - if (!fepriv->thread) - return; - - kthread_stop(fepriv->thread); - - sema_init(&fepriv->sem, 1); - fepriv->state = FESTATE_IDLE; - - /* paranoia check in case a signal arrived */ - if (fepriv->thread) - printk("dvb_frontend_stop: warning: thread %p won't exit\n", - fepriv->thread); -} - -s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime) -{ - return ((curtime.tv_usec < lasttime.tv_usec) ? - 1000000 - lasttime.tv_usec + curtime.tv_usec : - curtime.tv_usec - lasttime.tv_usec); -} -EXPORT_SYMBOL(timeval_usec_diff); - -static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec) -{ - curtime->tv_usec += add_usec; - if (curtime->tv_usec >= 1000000) { - curtime->tv_usec -= 1000000; - curtime->tv_sec++; - } -} - -/* - * Sleep until gettimeofday() > waketime + add_usec - * This needs to be as precise as possible, but as the delay is - * usually between 2ms and 32ms, it is done using a scheduled msleep - * followed by usleep (normally a busy-wait loop) for the remainder - */ -void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec) -{ - struct timeval lasttime; - s32 delta, newdelta; - - timeval_usec_add(waketime, add_usec); - - do_gettimeofday(&lasttime); - delta = timeval_usec_diff(lasttime, *waketime); - if (delta > 2500) { - msleep((delta - 1500) / 1000); - do_gettimeofday(&lasttime); - newdelta = timeval_usec_diff(lasttime, *waketime); - delta = (newdelta > delta) ? 0 : newdelta; - } - if (delta > 0) - udelay(delta); -} -EXPORT_SYMBOL(dvb_frontend_sleep_until); - -static int dvb_frontend_start(struct dvb_frontend *fe) -{ - int ret; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct task_struct *fe_thread; - - dprintk ("%s\n", __func__); - - if (fepriv->thread) { - if (fepriv->exit == DVB_FE_NO_EXIT) - return 0; - else - dvb_frontend_stop (fe); - } - - if (signal_pending(current)) - return -EINTR; - if (down_interruptible (&fepriv->sem)) - return -EINTR; - - fepriv->state = FESTATE_IDLE; - fepriv->exit = DVB_FE_NO_EXIT; - fepriv->thread = NULL; - mb(); - - fe_thread = kthread_run(dvb_frontend_thread, fe, - "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id); - if (IS_ERR(fe_thread)) { - ret = PTR_ERR(fe_thread); - printk("dvb_frontend_start: failed to start kthread (%d)\n", ret); - up(&fepriv->sem); - return ret; - } - fepriv->thread = fe_thread; - return 0; -} - -static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, - u32 *freq_min, u32 *freq_max) -{ - *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); - - if (fe->ops.info.frequency_max == 0) - *freq_max = fe->ops.tuner_ops.info.frequency_max; - else if (fe->ops.tuner_ops.info.frequency_max == 0) - *freq_max = fe->ops.info.frequency_max; - else - *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); - - if (*freq_min == 0 || *freq_max == 0) - printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", - fe->dvb->num,fe->id); -} - -static int dvb_frontend_check_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *parms) -{ - u32 freq_min; - u32 freq_max; - - /* range check: frequency */ - dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max); - if ((freq_min && parms->frequency < freq_min) || - (freq_max && parms->frequency > freq_max)) { - printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max); - return -EINVAL; - } - - /* range check: symbol rate */ - if (fe->ops.info.type == FE_QPSK) { - if ((fe->ops.info.symbol_rate_min && - parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || - (fe->ops.info.symbol_rate_max && - parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { - printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate, - fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); - return -EINVAL; - } - - } else if (fe->ops.info.type == FE_QAM) { - if ((fe->ops.info.symbol_rate_min && - parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || - (fe->ops.info.symbol_rate_max && - parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { - printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, parms->u.qam.symbol_rate, - fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); - return -EINVAL; - } - } - - /* check for supported modulation */ - if (fe->ops.info.type == FE_QAM && - (parms->u.qam.modulation > QAM_AUTO || - !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) { - printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n", - fe->dvb->num, fe->id, parms->u.qam.modulation); - return -EINVAL; - } - - return 0; -} - -static int dvb_frontend_clear_cache(struct dvb_frontend *fe) -{ - int i; - - memset(&(fe->dtv_property_cache), 0, - sizeof(struct dtv_frontend_properties)); - - fe->dtv_property_cache.state = DTV_CLEAR; - fe->dtv_property_cache.delivery_system = SYS_UNDEFINED; - fe->dtv_property_cache.inversion = INVERSION_AUTO; - fe->dtv_property_cache.fec_inner = FEC_AUTO; - fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; - fe->dtv_property_cache.bandwidth_hz = BANDWIDTH_AUTO; - fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; - fe->dtv_property_cache.hierarchy = HIERARCHY_AUTO; - fe->dtv_property_cache.symbol_rate = QAM_AUTO; - fe->dtv_property_cache.code_rate_HP = FEC_AUTO; - fe->dtv_property_cache.code_rate_LP = FEC_AUTO; - - fe->dtv_property_cache.isdbt_partial_reception = -1; - fe->dtv_property_cache.isdbt_sb_mode = -1; - fe->dtv_property_cache.isdbt_sb_subchannel = -1; - fe->dtv_property_cache.isdbt_sb_segment_idx = -1; - fe->dtv_property_cache.isdbt_sb_segment_count = -1; - fe->dtv_property_cache.isdbt_layer_enabled = 0x7; - for (i = 0; i < 3; i++) { - fe->dtv_property_cache.layer[i].fec = FEC_AUTO; - fe->dtv_property_cache.layer[i].modulation = QAM_AUTO; - fe->dtv_property_cache.layer[i].interleaving = -1; - fe->dtv_property_cache.layer[i].segment_count = -1; - } - - return 0; -} - -#define _DTV_CMD(n, s, b) \ -[n] = { \ - .name = #n, \ - .cmd = n, \ - .set = s,\ - .buffer = b \ -} - -static struct dtv_cmds_h dtv_cmds[] = { - _DTV_CMD(DTV_TUNE, 1, 0), - _DTV_CMD(DTV_CLEAR, 1, 0), - - /* Set */ - _DTV_CMD(DTV_FREQUENCY, 1, 0), - _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0), - _DTV_CMD(DTV_MODULATION, 1, 0), - _DTV_CMD(DTV_INVERSION, 1, 0), - _DTV_CMD(DTV_DISEQC_MASTER, 1, 1), - _DTV_CMD(DTV_SYMBOL_RATE, 1, 0), - _DTV_CMD(DTV_INNER_FEC, 1, 0), - _DTV_CMD(DTV_VOLTAGE, 1, 0), - _DTV_CMD(DTV_TONE, 1, 0), - _DTV_CMD(DTV_PILOT, 1, 0), - _DTV_CMD(DTV_ROLLOFF, 1, 0), - _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0), - _DTV_CMD(DTV_HIERARCHY, 1, 0), - _DTV_CMD(DTV_CODE_RATE_HP, 1, 0), - _DTV_CMD(DTV_CODE_RATE_LP, 1, 0), - _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0), - _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0), - - _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0), - _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0), - _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0), - _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0), - _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0), - - _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 0, 0), - _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 0, 0), - _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 0, 0), - _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 0, 0), - _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0), - - _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0), - - /* Get */ - _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1), - _DTV_CMD(DTV_API_VERSION, 0, 0), - _DTV_CMD(DTV_CODE_RATE_HP, 0, 0), - _DTV_CMD(DTV_CODE_RATE_LP, 0, 0), - _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0), - _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0), - _DTV_CMD(DTV_HIERARCHY, 0, 0), -}; - -static void dtv_property_dump(struct dtv_property *tvp) -{ - int i; - - if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { - printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n", - __func__, tvp->cmd); - return; - } - - dprintk("%s() tvp.cmd = 0x%08x (%s)\n" - ,__func__ - ,tvp->cmd - ,dtv_cmds[ tvp->cmd ].name); - - if(dtv_cmds[ tvp->cmd ].buffer) { - - dprintk("%s() tvp.u.buffer.len = 0x%02x\n" - ,__func__ - ,tvp->u.buffer.len); - - for(i = 0; i < tvp->u.buffer.len; i++) - dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n" - ,__func__ - ,i - ,tvp->u.buffer.data[i]); - - } else - dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data); -} - -static int is_legacy_delivery_system(fe_delivery_system_t s) -{ - if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || - (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) || - (s == SYS_ATSC)) - return 1; - - return 0; -} - -/* Synchronise the legacy tuning parameters into the cache, so that demodulator - * drivers can use a single set_frontend tuning function, regardless of whether - * it's being used for the legacy or new API, reducing code and complexity. - */ -static void dtv_property_cache_sync(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - c->frequency = p->frequency; - c->inversion = p->inversion; - - switch (fe->ops.info.type) { - case FE_QPSK: - c->modulation = QPSK; /* implied for DVB-S in legacy API */ - c->rolloff = ROLLOFF_35;/* implied for DVB-S */ - c->symbol_rate = p->u.qpsk.symbol_rate; - c->fec_inner = p->u.qpsk.fec_inner; - c->delivery_system = SYS_DVBS; - break; - case FE_QAM: - c->symbol_rate = p->u.qam.symbol_rate; - c->fec_inner = p->u.qam.fec_inner; - c->modulation = p->u.qam.modulation; - c->delivery_system = SYS_DVBC_ANNEX_AC; - break; - case FE_OFDM: - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) - c->bandwidth_hz = 6000000; - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) - c->bandwidth_hz = 7000000; - else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) - c->bandwidth_hz = 8000000; - else - /* Including BANDWIDTH_AUTO */ - c->bandwidth_hz = 0; - c->code_rate_HP = p->u.ofdm.code_rate_HP; - c->code_rate_LP = p->u.ofdm.code_rate_LP; - c->modulation = p->u.ofdm.constellation; - c->transmission_mode = p->u.ofdm.transmission_mode; - c->guard_interval = p->u.ofdm.guard_interval; - c->hierarchy = p->u.ofdm.hierarchy_information; - c->delivery_system = SYS_DVBT; - break; - case FE_ATSC: - c->modulation = p->u.vsb.modulation; - if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) - c->delivery_system = SYS_ATSC; - else - c->delivery_system = SYS_DVBC_ANNEX_B; - break; - } -} - -/* Ensure the cached values are set correctly in the frontend - * legacy tuning structures, for the advanced tuning API. - */ -static void dtv_property_legacy_params_sync(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_frontend_parameters *p = &fepriv->parameters; - - p->frequency = c->frequency; - p->inversion = c->inversion; - - switch (fe->ops.info.type) { - case FE_QPSK: - dprintk("%s() Preparing QPSK req\n", __func__); - p->u.qpsk.symbol_rate = c->symbol_rate; - p->u.qpsk.fec_inner = c->fec_inner; - c->delivery_system = SYS_DVBS; - break; - case FE_QAM: - dprintk("%s() Preparing QAM req\n", __func__); - p->u.qam.symbol_rate = c->symbol_rate; - p->u.qam.fec_inner = c->fec_inner; - p->u.qam.modulation = c->modulation; - c->delivery_system = SYS_DVBC_ANNEX_AC; - break; - case FE_OFDM: - dprintk("%s() Preparing OFDM req\n", __func__); - if (c->bandwidth_hz == 6000000) - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - else if (c->bandwidth_hz == 7000000) - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - else if (c->bandwidth_hz == 8000000) - p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - else - p->u.ofdm.bandwidth = BANDWIDTH_AUTO; - p->u.ofdm.code_rate_HP = c->code_rate_HP; - p->u.ofdm.code_rate_LP = c->code_rate_LP; - p->u.ofdm.constellation = c->modulation; - p->u.ofdm.transmission_mode = c->transmission_mode; - p->u.ofdm.guard_interval = c->guard_interval; - p->u.ofdm.hierarchy_information = c->hierarchy; - c->delivery_system = SYS_DVBT; - break; - case FE_ATSC: - dprintk("%s() Preparing VSB req\n", __func__); - p->u.vsb.modulation = c->modulation; - if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) - c->delivery_system = SYS_ATSC; - else - c->delivery_system = SYS_DVBC_ANNEX_B; - break; - } -} - -/* Ensure the cached values are set correctly in the frontend - * legacy tuning structures, for the legacy tuning API. - */ -static void dtv_property_adv_params_sync(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_frontend_parameters *p = &fepriv->parameters; - - p->frequency = c->frequency; - p->inversion = c->inversion; - - switch(c->modulation) { - case PSK_8: - case APSK_16: - case APSK_32: - case QPSK: - p->u.qpsk.symbol_rate = c->symbol_rate; - p->u.qpsk.fec_inner = c->fec_inner; - break; - default: - break; - } - - if(c->delivery_system == SYS_ISDBT) { - /* Fake out a generic DVB-T request so we pass validation in the ioctl */ - p->frequency = c->frequency; - p->inversion = c->inversion; - p->u.ofdm.constellation = QAM_AUTO; - p->u.ofdm.code_rate_HP = FEC_AUTO; - p->u.ofdm.code_rate_LP = FEC_AUTO; - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; - if (c->bandwidth_hz == 8000000) - p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - else if (c->bandwidth_hz == 7000000) - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - else if (c->bandwidth_hz == 6000000) - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - else - p->u.ofdm.bandwidth = BANDWIDTH_AUTO; - } -} - -static void dtv_property_cache_submit(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - /* For legacy delivery systems we don't need the delivery_system to - * be specified, but we populate the older structures from the cache - * so we can call set_frontend on older drivers. - */ - if(is_legacy_delivery_system(c->delivery_system)) { - - dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation); - dtv_property_legacy_params_sync(fe); - - } else { - dprintk("%s() adv, modulation = %d\n", __func__, c->modulation); - - /* For advanced delivery systems / modulation types ... - * we seed the lecacy dvb_frontend_parameters structure - * so that the sanity checking code later in the IOCTL processing - * can validate our basic frequency ranges, symbolrates, modulation - * etc. - */ - dtv_property_adv_params_sync(fe); - } -} - -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg); -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg); - -static int dtv_property_process_get(struct dvb_frontend *fe, - struct dtv_property *tvp, - struct file *file) -{ - int r = 0; - - /* Allow the frontend to validate incoming properties */ - if (fe->ops.get_property) - r = fe->ops.get_property(fe, tvp); - - if (r < 0) - return r; - - switch(tvp->cmd) { - case DTV_FREQUENCY: - tvp->u.data = fe->dtv_property_cache.frequency; - break; - case DTV_MODULATION: - tvp->u.data = fe->dtv_property_cache.modulation; - break; - case DTV_BANDWIDTH_HZ: - tvp->u.data = fe->dtv_property_cache.bandwidth_hz; - break; - case DTV_INVERSION: - tvp->u.data = fe->dtv_property_cache.inversion; - break; - case DTV_SYMBOL_RATE: - tvp->u.data = fe->dtv_property_cache.symbol_rate; - break; - case DTV_INNER_FEC: - tvp->u.data = fe->dtv_property_cache.fec_inner; - break; - case DTV_PILOT: - tvp->u.data = fe->dtv_property_cache.pilot; - break; - case DTV_ROLLOFF: - tvp->u.data = fe->dtv_property_cache.rolloff; - break; - case DTV_DELIVERY_SYSTEM: - tvp->u.data = fe->dtv_property_cache.delivery_system; - break; - case DTV_VOLTAGE: - tvp->u.data = fe->dtv_property_cache.voltage; - break; - case DTV_TONE: - tvp->u.data = fe->dtv_property_cache.sectone; - break; - case DTV_API_VERSION: - tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR; - break; - case DTV_CODE_RATE_HP: - tvp->u.data = fe->dtv_property_cache.code_rate_HP; - break; - case DTV_CODE_RATE_LP: - tvp->u.data = fe->dtv_property_cache.code_rate_LP; - break; - case DTV_GUARD_INTERVAL: - tvp->u.data = fe->dtv_property_cache.guard_interval; - break; - case DTV_TRANSMISSION_MODE: - tvp->u.data = fe->dtv_property_cache.transmission_mode; - break; - case DTV_HIERARCHY: - tvp->u.data = fe->dtv_property_cache.hierarchy; - break; - - /* ISDB-T Support here */ - case DTV_ISDBT_PARTIAL_RECEPTION: - tvp->u.data = fe->dtv_property_cache.isdbt_partial_reception; - break; - case DTV_ISDBT_SOUND_BROADCASTING: - tvp->u.data = fe->dtv_property_cache.isdbt_sb_mode; - break; - case DTV_ISDBT_SB_SUBCHANNEL_ID: - tvp->u.data = fe->dtv_property_cache.isdbt_sb_subchannel; - break; - case DTV_ISDBT_SB_SEGMENT_IDX: - tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_idx; - break; - case DTV_ISDBT_SB_SEGMENT_COUNT: - tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_count; - break; - case DTV_ISDBT_LAYER_ENABLED: - tvp->u.data = fe->dtv_property_cache.isdbt_layer_enabled; - break; - case DTV_ISDBT_LAYERA_FEC: - tvp->u.data = fe->dtv_property_cache.layer[0].fec; - break; - case DTV_ISDBT_LAYERA_MODULATION: - tvp->u.data = fe->dtv_property_cache.layer[0].modulation; - break; - case DTV_ISDBT_LAYERA_SEGMENT_COUNT: - tvp->u.data = fe->dtv_property_cache.layer[0].segment_count; - break; - case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: - tvp->u.data = fe->dtv_property_cache.layer[0].interleaving; - break; - case DTV_ISDBT_LAYERB_FEC: - tvp->u.data = fe->dtv_property_cache.layer[1].fec; - break; - case DTV_ISDBT_LAYERB_MODULATION: - tvp->u.data = fe->dtv_property_cache.layer[1].modulation; - break; - case DTV_ISDBT_LAYERB_SEGMENT_COUNT: - tvp->u.data = fe->dtv_property_cache.layer[1].segment_count; - break; - case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: - tvp->u.data = fe->dtv_property_cache.layer[1].interleaving; - break; - case DTV_ISDBT_LAYERC_FEC: - tvp->u.data = fe->dtv_property_cache.layer[2].fec; - break; - case DTV_ISDBT_LAYERC_MODULATION: - tvp->u.data = fe->dtv_property_cache.layer[2].modulation; - break; - case DTV_ISDBT_LAYERC_SEGMENT_COUNT: - tvp->u.data = fe->dtv_property_cache.layer[2].segment_count; - break; - case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: - tvp->u.data = fe->dtv_property_cache.layer[2].interleaving; - break; - case DTV_ISDBS_TS_ID: - tvp->u.data = fe->dtv_property_cache.isdbs_ts_id; - break; - default: - r = -1; - } - - dtv_property_dump(tvp); - - return r; -} - -static int dtv_property_process_set(struct dvb_frontend *fe, - struct dtv_property *tvp, - struct file *file) -{ - int r = 0; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - dtv_property_dump(tvp); - - /* Allow the frontend to validate incoming properties */ - if (fe->ops.set_property) - r = fe->ops.set_property(fe, tvp); - - if (r < 0) - return r; - - switch(tvp->cmd) { - case DTV_CLEAR: - /* Reset a cache of data specific to the frontend here. This does - * not effect hardware. - */ - dvb_frontend_clear_cache(fe); - dprintk("%s() Flushing property cache\n", __func__); - break; - case DTV_TUNE: - /* interpret the cache of data, build either a traditional frontend - * tunerequest so we can pass validation in the FE_SET_FRONTEND - * ioctl. - */ - fe->dtv_property_cache.state = tvp->cmd; - dprintk("%s() Finalised property cache\n", __func__); - dtv_property_cache_submit(fe); - - r |= dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND, - &fepriv->parameters); - break; - case DTV_FREQUENCY: - fe->dtv_property_cache.frequency = tvp->u.data; - break; - case DTV_MODULATION: - fe->dtv_property_cache.modulation = tvp->u.data; - break; - case DTV_BANDWIDTH_HZ: - fe->dtv_property_cache.bandwidth_hz = tvp->u.data; - break; - case DTV_INVERSION: - fe->dtv_property_cache.inversion = tvp->u.data; - break; - case DTV_SYMBOL_RATE: - fe->dtv_property_cache.symbol_rate = tvp->u.data; - break; - case DTV_INNER_FEC: - fe->dtv_property_cache.fec_inner = tvp->u.data; - break; - case DTV_PILOT: - fe->dtv_property_cache.pilot = tvp->u.data; - break; - case DTV_ROLLOFF: - fe->dtv_property_cache.rolloff = tvp->u.data; - break; - case DTV_DELIVERY_SYSTEM: - fe->dtv_property_cache.delivery_system = tvp->u.data; - break; - case DTV_VOLTAGE: - fe->dtv_property_cache.voltage = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE, - (void *)fe->dtv_property_cache.voltage); - break; - case DTV_TONE: - fe->dtv_property_cache.sectone = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE, - (void *)fe->dtv_property_cache.sectone); - break; - case DTV_CODE_RATE_HP: - fe->dtv_property_cache.code_rate_HP = tvp->u.data; - break; - case DTV_CODE_RATE_LP: - fe->dtv_property_cache.code_rate_LP = tvp->u.data; - break; - case DTV_GUARD_INTERVAL: - fe->dtv_property_cache.guard_interval = tvp->u.data; - break; - case DTV_TRANSMISSION_MODE: - fe->dtv_property_cache.transmission_mode = tvp->u.data; - break; - case DTV_HIERARCHY: - fe->dtv_property_cache.hierarchy = tvp->u.data; - break; - - /* ISDB-T Support here */ - case DTV_ISDBT_PARTIAL_RECEPTION: - fe->dtv_property_cache.isdbt_partial_reception = tvp->u.data; - break; - case DTV_ISDBT_SOUND_BROADCASTING: - fe->dtv_property_cache.isdbt_sb_mode = tvp->u.data; - break; - case DTV_ISDBT_SB_SUBCHANNEL_ID: - fe->dtv_property_cache.isdbt_sb_subchannel = tvp->u.data; - break; - case DTV_ISDBT_SB_SEGMENT_IDX: - fe->dtv_property_cache.isdbt_sb_segment_idx = tvp->u.data; - break; - case DTV_ISDBT_SB_SEGMENT_COUNT: - fe->dtv_property_cache.isdbt_sb_segment_count = tvp->u.data; - break; - case DTV_ISDBT_LAYER_ENABLED: - fe->dtv_property_cache.isdbt_layer_enabled = tvp->u.data; - break; - case DTV_ISDBT_LAYERA_FEC: - fe->dtv_property_cache.layer[0].fec = tvp->u.data; - break; - case DTV_ISDBT_LAYERA_MODULATION: - fe->dtv_property_cache.layer[0].modulation = tvp->u.data; - break; - case DTV_ISDBT_LAYERA_SEGMENT_COUNT: - fe->dtv_property_cache.layer[0].segment_count = tvp->u.data; - break; - case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: - fe->dtv_property_cache.layer[0].interleaving = tvp->u.data; - break; - case DTV_ISDBT_LAYERB_FEC: - fe->dtv_property_cache.layer[1].fec = tvp->u.data; - break; - case DTV_ISDBT_LAYERB_MODULATION: - fe->dtv_property_cache.layer[1].modulation = tvp->u.data; - break; - case DTV_ISDBT_LAYERB_SEGMENT_COUNT: - fe->dtv_property_cache.layer[1].segment_count = tvp->u.data; - break; - case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: - fe->dtv_property_cache.layer[1].interleaving = tvp->u.data; - break; - case DTV_ISDBT_LAYERC_FEC: - fe->dtv_property_cache.layer[2].fec = tvp->u.data; - break; - case DTV_ISDBT_LAYERC_MODULATION: - fe->dtv_property_cache.layer[2].modulation = tvp->u.data; - break; - case DTV_ISDBT_LAYERC_SEGMENT_COUNT: - fe->dtv_property_cache.layer[2].segment_count = tvp->u.data; - break; - case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: - fe->dtv_property_cache.layer[2].interleaving = tvp->u.data; - break; - case DTV_ISDBS_TS_ID: - fe->dtv_property_cache.isdbs_ts_id = tvp->u.data; - break; - default: - r = -1; - } - - return r; -} - -static int dvb_frontend_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - int err = -EOPNOTSUPP; - - dprintk("%s (%d)\n", __func__, _IOC_NR(cmd)); - - if (fepriv->exit != DVB_FE_NO_EXIT) - return -ENODEV; - - if ((file->f_flags & O_ACCMODE) == O_RDONLY && - (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT || - cmd == FE_DISEQC_RECV_SLAVE_REPLY)) - return -EPERM; - - if (down_interruptible (&fepriv->sem)) - return -ERESTARTSYS; - - if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) - err = dvb_frontend_ioctl_properties(file, cmd, parg); - else { - fe->dtv_property_cache.state = DTV_UNDEFINED; - err = dvb_frontend_ioctl_legacy(file, cmd, parg); - } - - up(&fepriv->sem); - return err; -} - -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_frontend *fe = dvbdev->priv; - int err = 0; - - struct dtv_properties *tvps = NULL; - struct dtv_property *tvp = NULL; - int i; - - dprintk("%s\n", __func__); - - if(cmd == FE_SET_PROPERTY) { - tvps = (struct dtv_properties __user *)parg; - - dprintk("%s() properties.num = %d\n", __func__, tvps->num); - dprintk("%s() properties.props = %p\n", __func__, tvps->props); - - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; - - tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); - if (!tvp) { - err = -ENOMEM; - goto out; - } - - if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { - err = -EFAULT; - goto out; - } - - for (i = 0; i < tvps->num; i++) { - (tvp + i)->result = dtv_property_process_set(fe, tvp + i, file); - err |= (tvp + i)->result; - } - - if(fe->dtv_property_cache.state == DTV_TUNE) - dprintk("%s() Property cache is full, tuning\n", __func__); - - } else - if(cmd == FE_GET_PROPERTY) { - - tvps = (struct dtv_properties __user *)parg; - - dprintk("%s() properties.num = %d\n", __func__, tvps->num); - dprintk("%s() properties.props = %p\n", __func__, tvps->props); - - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; - - tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); - if (!tvp) { - err = -ENOMEM; - goto out; - } - - if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { - err = -EFAULT; - goto out; - } - - for (i = 0; i < tvps->num; i++) { - (tvp + i)->result = dtv_property_process_get(fe, tvp + i, file); - err |= (tvp + i)->result; - } - - if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { - err = -EFAULT; - goto out; - } - - } else - err = -EOPNOTSUPP; - -out: - kfree(tvp); - return err; -} - -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - int cb_err, err = -EOPNOTSUPP; - - if (fe->dvb->fe_ioctl_override) { - cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg, - DVB_FE_IOCTL_PRE); - if (cb_err < 0) - return cb_err; - if (cb_err > 0) - return 0; - /* fe_ioctl_override returning 0 allows - * dvb-core to continue handling the ioctl */ - } - - switch (cmd) { - case FE_GET_INFO: { - struct dvb_frontend_info* info = parg; - memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); - dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); - - /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't - * do it, it is done for it. */ - info->caps |= FE_CAN_INVERSION_AUTO; - err = 0; - break; - } - - case FE_READ_STATUS: { - fe_status_t* status = parg; - - /* if retune was requested but hasn't occured yet, prevent - * that user get signal state from previous tuning */ - if (fepriv->state == FESTATE_RETUNE || - fepriv->state == FESTATE_ERROR) { - err=0; - *status = 0; - break; - } - - if (fe->ops.read_status) - err = fe->ops.read_status(fe, status); - break; - } - case FE_READ_BER: - if (fe->ops.read_ber) - err = fe->ops.read_ber(fe, (__u32*) parg); - break; - - case FE_READ_SIGNAL_STRENGTH: - if (fe->ops.read_signal_strength) - err = fe->ops.read_signal_strength(fe, (__u16*) parg); - break; - - case FE_READ_SNR: - if (fe->ops.read_snr) - err = fe->ops.read_snr(fe, (__u16*) parg); - break; - - case FE_READ_UNCORRECTED_BLOCKS: - if (fe->ops.read_ucblocks) - err = fe->ops.read_ucblocks(fe, (__u32*) parg); - break; - - - case FE_DISEQC_RESET_OVERLOAD: - if (fe->ops.diseqc_reset_overload) { - err = fe->ops.diseqc_reset_overload(fe); - fepriv->state = FESTATE_DISEQC; - fepriv->status = 0; - } - break; - - case FE_DISEQC_SEND_MASTER_CMD: - if (fe->ops.diseqc_send_master_cmd) { - err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg); - fepriv->state = FESTATE_DISEQC; - fepriv->status = 0; - } - break; - - case FE_DISEQC_SEND_BURST: - if (fe->ops.diseqc_send_burst) { - err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg); - fepriv->state = FESTATE_DISEQC; - fepriv->status = 0; - } - break; - - case FE_SET_TONE: - if (fe->ops.set_tone) { - err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg); - fepriv->tone = (fe_sec_tone_mode_t) parg; - fepriv->state = FESTATE_DISEQC; - fepriv->status = 0; - } - break; - - case FE_SET_VOLTAGE: - if (fe->ops.set_voltage) { - err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg); - fepriv->voltage = (fe_sec_voltage_t) parg; - fepriv->state = FESTATE_DISEQC; - fepriv->status = 0; - } - break; - - case FE_DISHNETWORK_SEND_LEGACY_CMD: - if (fe->ops.dishnetwork_send_legacy_command) { - err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg); - fepriv->state = FESTATE_DISEQC; - fepriv->status = 0; - } else if (fe->ops.set_voltage) { - /* - * NOTE: This is a fallback condition. Some frontends - * (stv0299 for instance) take longer than 8msec to - * respond to a set_voltage command. Those switches - * need custom routines to switch properly. For all - * other frontends, the following should work ok. - * Dish network legacy switches (as used by Dish500) - * are controlled by sending 9-bit command words - * spaced 8msec apart. - * the actual command word is switch/port dependant - * so it is up to the userspace application to send - * the right command. - * The command must always start with a '0' after - * initialization, so parg is 8 bits and does not - * include the initialization or start bit - */ - unsigned long swcmd = ((unsigned long) parg) << 1; - struct timeval nexttime; - struct timeval tv[10]; - int i; - u8 last = 1; - if (dvb_frontend_debug) - printk("%s switch command: 0x%04lx\n", __func__, swcmd); - do_gettimeofday(&nexttime); - if (dvb_frontend_debug) - memcpy(&tv[0], &nexttime, sizeof(struct timeval)); - /* before sending a command, initialize by sending - * a 32ms 18V to the switch - */ - fe->ops.set_voltage(fe, SEC_VOLTAGE_18); - dvb_frontend_sleep_until(&nexttime, 32000); - - for (i = 0; i < 9; i++) { - if (dvb_frontend_debug) - do_gettimeofday(&tv[i + 1]); - if ((swcmd & 0x01) != last) { - /* set voltage to (last ? 13V : 18V) */ - fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); - last = (last) ? 0 : 1; - } - swcmd = swcmd >> 1; - if (i != 8) - dvb_frontend_sleep_until(&nexttime, 8000); - } - if (dvb_frontend_debug) { - printk("%s(%d): switch delay (should be 32k followed by all 8k\n", - __func__, fe->dvb->num); - for (i = 1; i < 10; i++) - printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); - } - err = 0; - fepriv->state = FESTATE_DISEQC; - fepriv->status = 0; - } - break; - - case FE_DISEQC_RECV_SLAVE_REPLY: - if (fe->ops.diseqc_recv_slave_reply) - err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); - break; - - case FE_ENABLE_HIGH_LNB_VOLTAGE: - if (fe->ops.enable_high_lnb_voltage) - err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); - break; - - case FE_SET_FRONTEND: { - struct dvb_frontend_tune_settings fetunesettings; - - if(fe->dtv_property_cache.state == DTV_TUNE) { - if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) { - err = -EINVAL; - break; - } - } else { - if (dvb_frontend_check_parameters(fe, parg) < 0) { - err = -EINVAL; - break; - } - - memcpy (&fepriv->parameters, parg, - sizeof (struct dvb_frontend_parameters)); - dtv_property_cache_sync(fe, &fepriv->parameters); - } - - memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); - memcpy(&fetunesettings.parameters, parg, - sizeof (struct dvb_frontend_parameters)); - - /* force auto frequency inversion if requested */ - if (dvb_force_auto_inversion) { - fepriv->parameters.inversion = INVERSION_AUTO; - fetunesettings.parameters.inversion = INVERSION_AUTO; - } - if (fe->ops.info.type == FE_OFDM) { - /* without hierarchical coding code_rate_LP is irrelevant, - * so we tolerate the otherwise invalid FEC_NONE setting */ - if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE && - fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE) - fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO; - } - - /* get frontend-specific tuning settings */ - if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { - fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; - fepriv->max_drift = fetunesettings.max_drift; - fepriv->step_size = fetunesettings.step_size; - } else { - /* default values */ - switch(fe->ops.info.type) { - case FE_QPSK: - fepriv->min_delay = HZ/20; - fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000; - fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000; - break; - - case FE_QAM: - fepriv->min_delay = HZ/20; - fepriv->step_size = 0; /* no zigzag */ - fepriv->max_drift = 0; - break; - - case FE_OFDM: - fepriv->min_delay = HZ/20; - fepriv->step_size = fe->ops.info.frequency_stepsize * 2; - fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; - break; - case FE_ATSC: - fepriv->min_delay = HZ/20; - fepriv->step_size = 0; - fepriv->max_drift = 0; - break; - } - } - if (dvb_override_tune_delay > 0) - fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; - - fepriv->state = FESTATE_RETUNE; - - /* Request the search algorithm to search */ - fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; - - dvb_frontend_wakeup(fe); - dvb_frontend_add_event(fe, 0); - fepriv->status = 0; - err = 0; - break; - } - - case FE_GET_EVENT: - err = dvb_frontend_get_event (fe, parg, file->f_flags); - break; - - case FE_GET_FRONTEND: - if (fe->ops.get_frontend) { - memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters)); - err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg); - } - break; - - case FE_SET_FRONTEND_TUNE_MODE: - fepriv->tune_mode_flags = (unsigned long) parg; - err = 0; - break; - }; - - if (fe->dvb->fe_ioctl_override) { - cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg, - DVB_FE_IOCTL_POST); - if (cb_err < 0) - return cb_err; - } - - return err; -} - - -static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - dprintk ("%s\n", __func__); - - poll_wait (file, &fepriv->events.wait_queue, wait); - - if (fepriv->events.eventw != fepriv->events.eventr) - return (POLLIN | POLLRDNORM | POLLPRI); - - return 0; -} - -static int dvb_frontend_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_adapter *adapter = fe->dvb; - int ret; - - dprintk ("%s\n", __func__); - if (fepriv->exit == DVB_FE_DEVICE_REMOVED) - return -ENODEV; - - if (adapter->mfe_shared) { - mutex_lock (&adapter->mfe_lock); - - if (adapter->mfe_dvbdev == NULL) - adapter->mfe_dvbdev = dvbdev; - - else if (adapter->mfe_dvbdev != dvbdev) { - struct dvb_device - *mfedev = adapter->mfe_dvbdev; - struct dvb_frontend - *mfe = mfedev->priv; - struct dvb_frontend_private - *mfepriv = mfe->frontend_priv; - int mferetry = (dvb_mfe_wait_time << 1); - - mutex_unlock (&adapter->mfe_lock); - while (mferetry-- && (mfedev->users != -1 || - mfepriv->thread != NULL)) { - if(msleep_interruptible(500)) { - if(signal_pending(current)) - return -EINTR; - } - } - - mutex_lock (&adapter->mfe_lock); - if(adapter->mfe_dvbdev != dvbdev) { - mfedev = adapter->mfe_dvbdev; - mfe = mfedev->priv; - mfepriv = mfe->frontend_priv; - if (mfedev->users != -1 || - mfepriv->thread != NULL) { - mutex_unlock (&adapter->mfe_lock); - return -EBUSY; - } - adapter->mfe_dvbdev = dvbdev; - } - } - } - - if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { - if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) - goto err0; - } - - if ((ret = dvb_generic_open (inode, file)) < 0) - goto err1; - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - /* normal tune mode when opened R/W */ - fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; - fepriv->tone = -1; - fepriv->voltage = -1; - - ret = dvb_frontend_start (fe); - if (ret) - goto err2; - - /* empty event queue */ - fepriv->events.eventr = fepriv->events.eventw = 0; - } - - if (adapter->mfe_shared) - mutex_unlock (&adapter->mfe_lock); - return ret; - -err2: - dvb_generic_release(inode, file); -err1: - if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) - fe->ops.ts_bus_ctrl(fe, 0); -err0: - if (adapter->mfe_shared) - mutex_unlock (&adapter->mfe_lock); - return ret; -} - -static int dvb_frontend_release(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - int ret; - - dprintk ("%s\n", __func__); - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) - fepriv->release_jiffies = jiffies; - - ret = dvb_generic_release (inode, file); - - if (dvbdev->users == -1) { - if (fepriv->exit != DVB_FE_NO_EXIT) { - fops_put(file->f_op); - file->f_op = NULL; - wake_up(&dvbdev->wait_queue); - } - if (fe->ops.ts_bus_ctrl) - fe->ops.ts_bus_ctrl(fe, 0); - } - - return ret; -} - -static const struct file_operations dvb_frontend_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = dvb_generic_ioctl, - .poll = dvb_frontend_poll, - .open = dvb_frontend_open, - .release = dvb_frontend_release, - .llseek = noop_llseek, -}; - -int dvb_register_frontend(struct dvb_adapter* dvb, - struct dvb_frontend* fe) -{ - struct dvb_frontend_private *fepriv; - static const struct dvb_device dvbdev_template = { - .users = ~0, - .writers = 1, - .readers = (~0)-1, - .fops = &dvb_frontend_fops, - .kernel_ioctl = dvb_frontend_ioctl - }; - - dprintk ("%s\n", __func__); - - if (mutex_lock_interruptible(&frontend_mutex)) - return -ERESTARTSYS; - - fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); - if (fe->frontend_priv == NULL) { - mutex_unlock(&frontend_mutex); - return -ENOMEM; - } - fepriv = fe->frontend_priv; - - sema_init(&fepriv->sem, 1); - init_waitqueue_head (&fepriv->wait_queue); - init_waitqueue_head (&fepriv->events.wait_queue); - mutex_init(&fepriv->events.mtx); - fe->dvb = dvb; - fepriv->inversion = INVERSION_OFF; - - printk ("DVB: registering adapter %i frontend %i (%s)...\n", - fe->dvb->num, - fe->id, - fe->ops.info.name); - - dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, - fe, DVB_DEVICE_FRONTEND); - - mutex_unlock(&frontend_mutex); - return 0; -} -EXPORT_SYMBOL(dvb_register_frontend); - -int dvb_unregister_frontend(struct dvb_frontend* fe) -{ - struct dvb_frontend_private *fepriv = fe->frontend_priv; - dprintk ("%s\n", __func__); - - mutex_lock(&frontend_mutex); - dvb_frontend_stop (fe); - mutex_unlock(&frontend_mutex); - - if (fepriv->dvbdev->users < -1) - wait_event(fepriv->dvbdev->wait_queue, - fepriv->dvbdev->users==-1); - - mutex_lock(&frontend_mutex); - dvb_unregister_device (fepriv->dvbdev); - - /* fe is invalid now */ - kfree(fepriv); - mutex_unlock(&frontend_mutex); - return 0; -} -EXPORT_SYMBOL(dvb_unregister_frontend); - -#ifdef CONFIG_MEDIA_ATTACH -void dvb_frontend_detach(struct dvb_frontend* fe) -{ - void *ptr; - - if (fe->ops.release_sec) { - fe->ops.release_sec(fe); - symbol_put_addr(fe->ops.release_sec); - } - if (fe->ops.tuner_ops.release) { - fe->ops.tuner_ops.release(fe); - symbol_put_addr(fe->ops.tuner_ops.release); - } - if (fe->ops.analog_ops.release) { - fe->ops.analog_ops.release(fe); - symbol_put_addr(fe->ops.analog_ops.release); - } - ptr = (void*)fe->ops.release; - if (ptr) { - fe->ops.release(fe); - symbol_put_addr(ptr); - } -} -#else -void dvb_frontend_detach(struct dvb_frontend* fe) -{ - if (fe->ops.release_sec) - fe->ops.release_sec(fe); - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); - if (fe->ops.analog_ops.release) - fe->ops.analog_ops.release(fe); - if (fe->ops.release) - fe->ops.release(fe); -} -#endif -EXPORT_SYMBOL(dvb_frontend_detach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_frontend.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_frontend.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_frontend.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_frontend.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,389 +0,0 @@ -/* - * dvb_frontend.h - * - * Copyright (C) 2001 convergence integrated media GmbH - * Copyright (C) 2004 convergence GmbH - * - * Written by Ralph Metzler - * Overhauled by Holger Waechtler - * Kernel I2C stuff by Michael Hunold - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVB_FRONTEND_H_ -#define _DVB_FRONTEND_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "dvbdev.h" - -struct dvb_frontend_tune_settings { - int min_delay_ms; - int step_size; - int max_drift; - struct dvb_frontend_parameters parameters; -}; - -struct dvb_frontend; - -struct dvb_tuner_info { - char name[128]; - - u32 frequency_min; - u32 frequency_max; - u32 frequency_step; - - u32 bandwidth_min; - u32 bandwidth_max; - u32 bandwidth_step; -}; - -struct analog_parameters { - unsigned int frequency; - unsigned int mode; - unsigned int audmode; - u64 std; -}; - -enum dvbfe_modcod { - DVBFE_MODCOD_DUMMY_PLFRAME = 0, - DVBFE_MODCOD_QPSK_1_4, - DVBFE_MODCOD_QPSK_1_3, - DVBFE_MODCOD_QPSK_2_5, - DVBFE_MODCOD_QPSK_1_2, - DVBFE_MODCOD_QPSK_3_5, - DVBFE_MODCOD_QPSK_2_3, - DVBFE_MODCOD_QPSK_3_4, - DVBFE_MODCOD_QPSK_4_5, - DVBFE_MODCOD_QPSK_5_6, - DVBFE_MODCOD_QPSK_8_9, - DVBFE_MODCOD_QPSK_9_10, - DVBFE_MODCOD_8PSK_3_5, - DVBFE_MODCOD_8PSK_2_3, - DVBFE_MODCOD_8PSK_3_4, - DVBFE_MODCOD_8PSK_5_6, - DVBFE_MODCOD_8PSK_8_9, - DVBFE_MODCOD_8PSK_9_10, - DVBFE_MODCOD_16APSK_2_3, - DVBFE_MODCOD_16APSK_3_4, - DVBFE_MODCOD_16APSK_4_5, - DVBFE_MODCOD_16APSK_5_6, - DVBFE_MODCOD_16APSK_8_9, - DVBFE_MODCOD_16APSK_9_10, - DVBFE_MODCOD_32APSK_3_4, - DVBFE_MODCOD_32APSK_4_5, - DVBFE_MODCOD_32APSK_5_6, - DVBFE_MODCOD_32APSK_8_9, - DVBFE_MODCOD_32APSK_9_10, - DVBFE_MODCOD_RESERVED_1, - DVBFE_MODCOD_BPSK_1_3, - DVBFE_MODCOD_BPSK_1_4, - DVBFE_MODCOD_RESERVED_2 -}; - -enum tuner_param { - DVBFE_TUNER_FREQUENCY = (1 << 0), - DVBFE_TUNER_TUNERSTEP = (1 << 1), - DVBFE_TUNER_IFFREQ = (1 << 2), - DVBFE_TUNER_BANDWIDTH = (1 << 3), - DVBFE_TUNER_REFCLOCK = (1 << 4), - DVBFE_TUNER_IQSENSE = (1 << 5), - DVBFE_TUNER_DUMMY = (1 << 31) -}; - -/* - * ALGO_HW: (Hardware Algorithm) - * ---------------------------------------------------------------- - * Devices that support this algorithm do everything in hardware - * and no software support is needed to handle them. - * Requesting these devices to LOCK is the only thing required, - * device is supposed to do everything in the hardware. - * - * ALGO_SW: (Software Algorithm) - * ---------------------------------------------------------------- - * These are dumb devices, that require software to do everything - * - * ALGO_CUSTOM: (Customizable Agorithm) - * ---------------------------------------------------------------- - * Devices having this algorithm can be customized to have specific - * algorithms in the frontend driver, rather than simply doing a - * software zig-zag. In this case the zigzag maybe hardware assisted - * or it maybe completely done in hardware. In all cases, usage of - * this algorithm, in conjunction with the search and track - * callbacks, utilizes the driver specific algorithm. - * - * ALGO_RECOVERY: (Recovery Algorithm) - * ---------------------------------------------------------------- - * These devices have AUTO recovery capabilities from LOCK failure - */ -enum dvbfe_algo { - DVBFE_ALGO_HW = (1 << 0), - DVBFE_ALGO_SW = (1 << 1), - DVBFE_ALGO_CUSTOM = (1 << 2), - DVBFE_ALGO_RECOVERY = (1 << 31) -}; - -struct tuner_state { - u32 frequency; - u32 tunerstep; - u32 ifreq; - u32 bandwidth; - u32 iqsense; - u32 refclock; -}; - -/* - * search callback possible return status - * - * DVBFE_ALGO_SEARCH_SUCCESS - * The frontend search algorithm completed and returned successfully - * - * DVBFE_ALGO_SEARCH_ASLEEP - * The frontend search algorithm is sleeping - * - * DVBFE_ALGO_SEARCH_FAILED - * The frontend search for a signal failed - * - * DVBFE_ALGO_SEARCH_INVALID - * The frontend search algorith was probably supplied with invalid - * parameters and the search is an invalid one - * - * DVBFE_ALGO_SEARCH_ERROR - * The frontend search algorithm failed due to some error - * - * DVBFE_ALGO_SEARCH_AGAIN - * The frontend search algorithm was requested to search again - */ -enum dvbfe_search { - DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0), - DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1), - DVBFE_ALGO_SEARCH_FAILED = (1 << 2), - DVBFE_ALGO_SEARCH_INVALID = (1 << 3), - DVBFE_ALGO_SEARCH_AGAIN = (1 << 4), - DVBFE_ALGO_SEARCH_ERROR = (1 << 31), -}; - - -struct dvb_tuner_ops { - - struct dvb_tuner_info info; - - int (*release)(struct dvb_frontend *fe); - int (*init)(struct dvb_frontend *fe); - int (*sleep)(struct dvb_frontend *fe); - - /** This is for simple PLLs - set all parameters in one go. */ - int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); - int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); - - /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ - int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); - - /** This is to allow setting tuner-specific configs */ - int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); - - int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); - int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); - -#define TUNER_STATUS_LOCKED 1 -#define TUNER_STATUS_STEREO 2 - int (*get_status)(struct dvb_frontend *fe, u32 *status); - int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); - - /** These are provided separately from set_params in order to facilitate silicon - * tuners which require sophisticated tuning loops, controlling each parameter separately. */ - int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); - int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); - - /* - * These are provided separately from set_params in order to facilitate silicon - * tuners which require sophisticated tuning loops, controlling each parameter separately. - */ - int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); - int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); -}; - -struct analog_demod_info { - char *name; -}; - -struct analog_demod_ops { - - struct analog_demod_info info; - - void (*set_params)(struct dvb_frontend *fe, - struct analog_parameters *params); - int (*has_signal)(struct dvb_frontend *fe); - int (*get_afc)(struct dvb_frontend *fe); - void (*tuner_status)(struct dvb_frontend *fe); - void (*standby)(struct dvb_frontend *fe); - void (*release)(struct dvb_frontend *fe); - int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); - - /** This is to allow setting tuner-specific configuration */ - int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); -}; - -struct dvb_frontend_ops { - - struct dvb_frontend_info info; - - void (*release)(struct dvb_frontend* fe); - void (*release_sec)(struct dvb_frontend* fe); - - int (*init)(struct dvb_frontend* fe); - int (*sleep)(struct dvb_frontend* fe); - - int (*write)(struct dvb_frontend* fe, const u8 buf[], int len); - - /* if this is set, it overrides the default swzigzag */ - int (*tune)(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params, - unsigned int mode_flags, - unsigned int *delay, - fe_status_t *status); - /* get frontend tuning algorithm from the module */ - enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); - - /* these two are only used for the swzigzag code */ - int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); - - int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - - int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); - int (*read_ber)(struct dvb_frontend* fe, u32* ber); - int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); - int (*read_snr)(struct dvb_frontend* fe, u16* snr); - int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks); - - int (*diseqc_reset_overload)(struct dvb_frontend* fe); - int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); - int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply); - int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); - int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); - int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); - int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg); - int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); - int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); - int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); - - /* These callbacks are for devices that implement their own - * tuning algorithms, rather than a simple swzigzag - */ - enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); - int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); - - struct dvb_tuner_ops tuner_ops; - struct analog_demod_ops analog_ops; - - int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); - int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); -}; - -#define MAX_EVENT 8 - -struct dvb_fe_events { - struct dvb_frontend_event events[MAX_EVENT]; - int eventw; - int eventr; - int overflow; - wait_queue_head_t wait_queue; - struct mutex mtx; -}; - -struct dtv_frontend_properties { - - /* Cache State */ - u32 state; - - u32 frequency; - fe_modulation_t modulation; - - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t sectone; - fe_spectral_inversion_t inversion; - fe_code_rate_t fec_inner; - fe_transmit_mode_t transmission_mode; - u32 bandwidth_hz; /* 0 = AUTO */ - fe_guard_interval_t guard_interval; - fe_hierarchy_t hierarchy; - u32 symbol_rate; - fe_code_rate_t code_rate_HP; - fe_code_rate_t code_rate_LP; - - fe_pilot_t pilot; - fe_rolloff_t rolloff; - - fe_delivery_system_t delivery_system; - - /* ISDB-T specifics */ - u8 isdbt_partial_reception; - u8 isdbt_sb_mode; - u8 isdbt_sb_subchannel; - u32 isdbt_sb_segment_idx; - u32 isdbt_sb_segment_count; - u8 isdbt_layer_enabled; - struct { - u8 segment_count; - fe_code_rate_t fec; - fe_modulation_t modulation; - u8 interleaving; - } layer[3]; - - /* ISDB-T specifics */ - u32 isdbs_ts_id; -}; - -struct dvb_frontend { - struct dvb_frontend_ops ops; - struct dvb_adapter *dvb; - void *demodulator_priv; - void *tuner_priv; - void *frontend_priv; - void *sec_priv; - void *analog_demod_priv; - struct dtv_frontend_properties dtv_property_cache; -#define DVB_FRONTEND_COMPONENT_TUNER 0 - int (*callback)(void *adapter_priv, int component, int cmd, int arg); - int id; -}; - -extern int dvb_register_frontend(struct dvb_adapter *dvb, - struct dvb_frontend *fe); - -extern int dvb_unregister_frontend(struct dvb_frontend *fe); - -extern void dvb_frontend_detach(struct dvb_frontend *fe); - -extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); - -extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec); -extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_math.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_math.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_math.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_math.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -/* - * dvb-math provides some complex fixed-point math - * operations shared between the dvb related stuff - * - * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include "dvb_math.h" - -static const unsigned short logtable[256] = { - 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, - 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508, - 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6, - 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37, - 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f, - 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41, - 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1, - 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142, - 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68, - 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355, - 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c, - 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490, - 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3, - 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507, - 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe, - 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca, - 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c, - 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7, - 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c, - 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c, - 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a, - 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065, - 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730, - 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc, - 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469, - 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9, - 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c, - 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765, - 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, - 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, - 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, - 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 -}; - -unsigned int intlog2(u32 value) -{ - /** - * returns: log2(value) * 2^24 - * wrong result if value = 0 (log2(0) is undefined) - */ - unsigned int msb; - unsigned int logentry; - unsigned int significand; - unsigned int interpolation; - - if (unlikely(value == 0)) { - WARN_ON(1); - return 0; - } - - /* first detect the msb (count begins at 0) */ - msb = fls(value) - 1; - - /** - * now we use a logtable after the following method: - * - * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24 - * where x = msb and therefore 1 <= y < 2 - * first y is determined by shifting the value left - * so that msb is bit 31 - * 0x00231f56 -> 0x8C7D5800 - * the result is y * 2^31 -> "significand" - * then the highest 9 bits are used for a table lookup - * the highest bit is discarded because it's always set - * the highest nine bits in our example are 100011000 - * so we would use the entry 0x18 - */ - significand = value << (31 - msb); - logentry = (significand >> 23) & 0xff; - - /** - * last step we do is interpolation because of the - * limitations of the log table the error is that part of - * the significand which isn't used for lookup then we - * compute the ratio between the error and the next table entry - * and interpolate it between the log table entry used and the - * next one the biggest error possible is 0x7fffff - * (in our example it's 0x7D5800) - * needed value for next table entry is 0x800000 - * so the interpolation is - * (error / 0x800000) * (logtable_next - logtable_current) - * in the implementation the division is moved to the end for - * better accuracy there is also an overflow correction if - * logtable_next is 256 - */ - interpolation = ((significand & 0x7fffff) * - ((logtable[(logentry + 1) & 0xff] - - logtable[logentry]) & 0xffff)) >> 15; - - /* now we return the result */ - return ((msb << 24) + (logtable[logentry] << 8) + interpolation); -} -EXPORT_SYMBOL(intlog2); - -unsigned int intlog10(u32 value) -{ - /** - * returns: log10(value) * 2^24 - * wrong result if value = 0 (log10(0) is undefined) - */ - u64 log; - - if (unlikely(value == 0)) { - WARN_ON(1); - return 0; - } - - log = intlog2(value); - - /** - * we use the following method: - * log10(x) = log2(x) * log10(2) - */ - - return (log * 646456993) >> 31; -} -EXPORT_SYMBOL(intlog10); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_math.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_math.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_math.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_math.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* - * dvb-math provides some complex fixed-point math - * operations shared between the dvb related stuff - * - * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __DVB_MATH_H -#define __DVB_MATH_H - -#include - -/** - * computes log2 of a value; the result is shifted left by 24 bits - * - * to use rational values you can use the following method: - * intlog2(value) = intlog2(value * 2^x) - x * 2^24 - * - * example: intlog2(8) will give 3 << 24 = 3 * 2^24 - * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24 - * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24 - * - * @param value The value (must be != 0) - * @return log2(value) * 2^24 - */ -extern unsigned int intlog2(u32 value); - -/** - * computes log10 of a value; the result is shifted left by 24 bits - * - * to use rational values you can use the following method: - * intlog10(value) = intlog10(value * 10^x) - x * 2^24 - * - * example: intlog10(1000) will give 3 << 24 = 3 * 2^24 - * due to the implementation intlog10(1000) might be not exactly 3 * 2^24 - * - * look at intlog2 for similar examples - * - * @param value The value (must be != 0) - * @return log10(value) * 2^24 - */ -extern unsigned int intlog10(u32 value); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_net.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_net.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_net.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_net.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1518 +0,0 @@ -/* - * dvb_net.c - * - * Copyright (C) 2001 Convergence integrated media GmbH - * Ralph Metzler - * Copyright (C) 2002 Ralph Metzler - * - * ULE Decapsulation code: - * Copyright (C) 2003, 2004 gcs - Global Communication & Services GmbH. - * and Department of Scientific Computing - * Paris Lodron University of Salzburg. - * Hilmar Linder - * and Wolfram Stering - * - * ULE Decaps according to RFC 4326. - * - * 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, or (at your option) any later version. - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -/* - * ULE ChangeLog: - * Feb 2004: hl/ws v1: Implementing draft-fair-ipdvb-ule-01.txt - * - * Dec 2004: hl/ws v2: Implementing draft-ietf-ipdvb-ule-03.txt: - * ULE Extension header handling. - * Bugreports by Moritz Vieth and Hanno Tersteegen, - * Fraunhofer Institute for Open Communication Systems - * Competence Center for Advanced Satellite Communications. - * Bugfixes and robustness improvements. - * Filtering on dest MAC addresses, if present (D-Bit = 0) - * ULE_DEBUG compile-time option. - * Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by - * Christian Praehauser , - * Paris Lodron University of Salzburg. - */ - -/* - * FIXME / TODO (dvb_net.c): - * - * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_demux.h" -#include "dvb_net.h" - -static int dvb_net_debug; -module_param(dvb_net_debug, int, 0444); -MODULE_PARM_DESC(dvb_net_debug, "enable debug messages"); - -#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0) - - -static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) -{ - unsigned int j; - for (j = 0; j < cnt; j++) - c = crc32_be( c, iov[j].iov_base, iov[j].iov_len ); - return c; -} - - -#define DVB_NET_MULTICAST_MAX 10 - -#undef ULE_DEBUG - -#ifdef ULE_DEBUG - -#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" -#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5] - -#define isprint(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) - -static void hexdump( const unsigned char *buf, unsigned short len ) -{ - char str[80], octet[10]; - int ofs, i, l; - - for (ofs = 0; ofs < len; ofs += 16) { - sprintf( str, "%03d: ", ofs ); - - for (i = 0; i < 16; i++) { - if ((i + ofs) < len) - sprintf( octet, "%02x ", buf[ofs + i] ); - else - strcpy( octet, " " ); - - strcat( str, octet ); - } - strcat( str, " " ); - l = strlen( str ); - - for (i = 0; (i < 16) && ((i + ofs) < len); i++) - str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.'; - - str[l] = '\0'; - printk( KERN_WARNING "%s\n", str ); - } -} - -#endif - -struct dvb_net_priv { - int in_use; - u16 pid; - struct net_device *net; - struct dvb_net *host; - struct dmx_demux *demux; - struct dmx_section_feed *secfeed; - struct dmx_section_filter *secfilter; - struct dmx_ts_feed *tsfeed; - int multi_num; - struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX]; - unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6]; - int rx_mode; -#define RX_MODE_UNI 0 -#define RX_MODE_MULTI 1 -#define RX_MODE_ALL_MULTI 2 -#define RX_MODE_PROMISC 3 - struct work_struct set_multicast_list_wq; - struct work_struct restart_net_feed_wq; - unsigned char feedtype; /* Either FEED_TYPE_ or FEED_TYPE_ULE */ - int need_pusi; /* Set to 1, if synchronization on PUSI required. */ - unsigned char tscc; /* TS continuity counter after sync on PUSI. */ - struct sk_buff *ule_skb; /* ULE SNDU decodes into this buffer. */ - unsigned char *ule_next_hdr; /* Pointer into skb to next ULE extension header. */ - unsigned short ule_sndu_len; /* ULE SNDU length in bytes, w/o D-Bit. */ - unsigned short ule_sndu_type; /* ULE SNDU type field, complete. */ - unsigned char ule_sndu_type_1; /* ULE SNDU type field, if split across 2 TS cells. */ - unsigned char ule_dbit; /* Whether the DestMAC address present - * or not (bit is set). */ - unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */ - int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */ - unsigned long ts_count; /* Current ts cell counter. */ - struct mutex mutex; -}; - - -/** - * Determine the packet's protocol ID. The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. - * - * stolen from eth.c out of the linux kernel, hacked for dvb-device - * by Michael Holzt - */ -static __be16 dvb_net_eth_type_trans(struct sk_buff *skb, - struct net_device *dev) -{ - struct ethhdr *eth; - unsigned char *rawp; - - skb_reset_mac_header(skb); - skb_pull(skb,dev->hard_header_len); - eth = eth_hdr(skb); - - if (*eth->h_dest & 1) { - if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) - skb->pkt_type=PACKET_BROADCAST; - else - skb->pkt_type=PACKET_MULTICAST; - } - - if (ntohs(eth->h_proto) >= 1536) - return eth->h_proto; - - rawp = skb->data; - - /** - * This is a magic hack to spot IPX packets. Older Novell breaks - * the protocol design and runs IPX over 802.3 without an 802.2 LLC - * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This - * won't work for fault tolerant netware but does for the rest. - */ - if (*(unsigned short *)rawp == 0xFFFF) - return htons(ETH_P_802_3); - - /** - * Real 802.2 LLC - */ - return htons(ETH_P_802_2); -} - -#define TS_SZ 188 -#define TS_SYNC 0x47 -#define TS_TEI 0x80 -#define TS_SC 0xC0 -#define TS_PUSI 0x40 -#define TS_AF_A 0x20 -#define TS_AF_D 0x10 - -/* ULE Extension Header handlers. */ - -#define ULE_TEST 0 -#define ULE_BRIDGED 1 - -#define ULE_OPTEXTHDR_PADDING 0 - -static int ule_test_sndu( struct dvb_net_priv *p ) -{ - return -1; -} - -static int ule_bridged_sndu( struct dvb_net_priv *p ) -{ - struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr; - if(ntohs(hdr->h_proto) < 1536) { - int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data); - /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */ - if(framelen != ntohs(hdr->h_proto)) { - return -1; - } - } - /* Note: - * From RFC4326: - * "A bridged SNDU is a Mandatory Extension Header of Type 1. - * It must be the final (or only) extension header specified in the header chain of a SNDU." - * The 'ule_bridged' flag will cause the extension header processing loop to terminate. - */ - p->ule_bridged = 1; - return 0; -} - -static int ule_exthdr_padding(struct dvb_net_priv *p) -{ - return 0; -} - -/** Handle ULE extension headers. - * Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding. - * Returns: >= 0: nr. of bytes consumed by next extension header - * -1: Mandatory extension header that is not recognized or TEST SNDU; discard. - */ -static int handle_one_ule_extension( struct dvb_net_priv *p ) -{ - /* Table of mandatory extension header handlers. The header type is the index. */ - static int (*ule_mandatory_ext_handlers[255])( struct dvb_net_priv *p ) = - { [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL, }; - - /* Table of optional extension header handlers. The header type is the index. */ - static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = - { [0] = ule_exthdr_padding, [1] = NULL, }; - - int ext_len = 0; - unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8; - unsigned char htype = p->ule_sndu_type & 0x00FF; - - /* Discriminate mandatory and optional extension headers. */ - if (hlen == 0) { - /* Mandatory extension header */ - if (ule_mandatory_ext_handlers[htype]) { - ext_len = ule_mandatory_ext_handlers[htype]( p ); - if(ext_len >= 0) { - p->ule_next_hdr += ext_len; - if (!p->ule_bridged) { - p->ule_sndu_type = ntohs(*(__be16 *)p->ule_next_hdr); - p->ule_next_hdr += 2; - } else { - p->ule_sndu_type = ntohs(*(__be16 *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN))); - /* This assures the extension handling loop will terminate. */ - } - } - // else: extension handler failed or SNDU should be discarded - } else - ext_len = -1; /* SNDU has to be discarded. */ - } else { - /* Optional extension header. Calculate the length. */ - ext_len = hlen << 1; - /* Process the optional extension header according to its type. */ - if (ule_optional_ext_handlers[htype]) - (void)ule_optional_ext_handlers[htype]( p ); - p->ule_next_hdr += ext_len; - p->ule_sndu_type = ntohs( *(__be16 *)(p->ule_next_hdr-2) ); - /* - * note: the length of the next header type is included in the - * length of THIS optional extension header - */ - } - - return ext_len; -} - -static int handle_ule_extensions( struct dvb_net_priv *p ) -{ - int total_ext_len = 0, l; - - p->ule_next_hdr = p->ule_skb->data; - do { - l = handle_one_ule_extension( p ); - if (l < 0) - return l; /* Stop extension header processing and discard SNDU. */ - total_ext_len += l; -#ifdef ULE_DEBUG - dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, " - "l=%i, total_ext_len=%i\n", p->ule_next_hdr, - (int) p->ule_sndu_type, l, total_ext_len); -#endif - - } while (p->ule_sndu_type < 1536); - - return total_ext_len; -} - - -/** Prepare for a new ULE SNDU: reset the decoder state. */ -static inline void reset_ule( struct dvb_net_priv *p ) -{ - p->ule_skb = NULL; - p->ule_next_hdr = NULL; - p->ule_sndu_len = 0; - p->ule_sndu_type = 0; - p->ule_sndu_type_1 = 0; - p->ule_sndu_remain = 0; - p->ule_dbit = 0xFF; - p->ule_bridged = 0; -} - -/** - * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of - * TS cells of a single PID. - */ -static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) -{ - struct dvb_net_priv *priv = netdev_priv(dev); - unsigned long skipped = 0L; - const u8 *ts, *ts_end, *from_where = NULL; - u8 ts_remain = 0, how_much = 0, new_ts = 1; - struct ethhdr *ethh = NULL; - bool error = false; - -#ifdef ULE_DEBUG - /* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */ - static unsigned char ule_hist[100*TS_SZ]; - static unsigned char *ule_where = ule_hist, ule_dump; -#endif - - /* For all TS cells in current buffer. - * Appearently, we are called for every single TS cell. - */ - for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) { - - if (new_ts) { - /* We are about to process a new TS cell. */ - -#ifdef ULE_DEBUG - if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist; - memcpy( ule_where, ts, TS_SZ ); - if (ule_dump) { - hexdump( ule_where, TS_SZ ); - ule_dump = 0; - } - ule_where += TS_SZ; -#endif - - /* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */ - if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) { - printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n", - priv->ts_count, ts[0], ts[1] & TS_TEI >> 7, ts[3] & 0xC0 >> 6); - - /* Drop partly decoded SNDU, reset state, resync on PUSI. */ - if (priv->ule_skb) { - dev_kfree_skb( priv->ule_skb ); - /* Prepare for next SNDU. */ - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; - } - reset_ule(priv); - priv->need_pusi = 1; - - /* Continue with next TS cell. */ - ts += TS_SZ; - priv->ts_count++; - continue; - } - - ts_remain = 184; - from_where = ts + 4; - } - /* Synchronize on PUSI, if required. */ - if (priv->need_pusi) { - if (ts[1] & TS_PUSI) { - /* Find beginning of first ULE SNDU in current TS cell. */ - /* Synchronize continuity counter. */ - priv->tscc = ts[3] & 0x0F; - /* There is a pointer field here. */ - if (ts[4] > ts_remain) { - printk(KERN_ERR "%lu: Invalid ULE packet " - "(pointer field %d)\n", priv->ts_count, ts[4]); - ts += TS_SZ; - priv->ts_count++; - continue; - } - /* Skip to destination of pointer field. */ - from_where = &ts[5] + ts[4]; - ts_remain -= 1 + ts[4]; - skipped = 0; - } else { - skipped++; - ts += TS_SZ; - priv->ts_count++; - continue; - } - } - - if (new_ts) { - /* Check continuity counter. */ - if ((ts[3] & 0x0F) == priv->tscc) - priv->tscc = (priv->tscc + 1) & 0x0F; - else { - /* TS discontinuity handling: */ - printk(KERN_WARNING "%lu: TS discontinuity: got %#x, " - "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc); - /* Drop partly decoded SNDU, reset state, resync on PUSI. */ - if (priv->ule_skb) { - dev_kfree_skb( priv->ule_skb ); - /* Prepare for next SNDU. */ - // reset_ule(priv); moved to below. - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; - } - reset_ule(priv); - /* skip to next PUSI. */ - priv->need_pusi = 1; - continue; - } - /* If we still have an incomplete payload, but PUSI is - * set; some TS cells are missing. - * This is only possible here, if we missed exactly 16 TS - * cells (continuity counter wrap). */ - if (ts[1] & TS_PUSI) { - if (! priv->need_pusi) { - if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) { - /* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */ - printk(KERN_WARNING "%lu: Invalid pointer " - "field: %u.\n", priv->ts_count, *from_where); - - /* Drop partly decoded SNDU, reset state, resync on PUSI. */ - if (priv->ule_skb) { - error = true; - dev_kfree_skb(priv->ule_skb); - } - - if (error || priv->ule_sndu_remain) { - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; - error = false; - } - - reset_ule(priv); - priv->need_pusi = 1; - continue; - } - /* Skip pointer field (we're processing a - * packed payload). */ - from_where += 1; - ts_remain -= 1; - } else - priv->need_pusi = 0; - - if (priv->ule_sndu_remain > 183) { - /* Current SNDU lacks more data than there could be available in the - * current TS cell. */ - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but " - "got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", - priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain); - dev_kfree_skb(priv->ule_skb); - /* Prepare for next SNDU. */ - reset_ule(priv); - /* Resync: go to where pointer field points to: start of next ULE SNDU. */ - from_where += ts[4]; - ts_remain -= ts[4]; - } - } - } - - /* Check if new payload needs to be started. */ - if (priv->ule_skb == NULL) { - /* Start a new payload with skb. - * Find ULE header. It is only guaranteed that the - * length field (2 bytes) is contained in the current - * TS. - * Check ts_remain has to be >= 2 here. */ - if (ts_remain < 2) { - printk(KERN_WARNING "Invalid payload packing: only %d " - "bytes left in TS. Resyncing.\n", ts_remain); - priv->ule_sndu_len = 0; - priv->need_pusi = 1; - ts += TS_SZ; - continue; - } - - if (! priv->ule_sndu_len) { - /* Got at least two bytes, thus extrace the SNDU length. */ - priv->ule_sndu_len = from_where[0] << 8 | from_where[1]; - if (priv->ule_sndu_len & 0x8000) { - /* D-Bit is set: no dest mac present. */ - priv->ule_sndu_len &= 0x7FFF; - priv->ule_dbit = 1; - } else - priv->ule_dbit = 0; - - if (priv->ule_sndu_len < 5) { - printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " - "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - priv->ule_sndu_len = 0; - priv->need_pusi = 1; - new_ts = 1; - ts += TS_SZ; - priv->ts_count++; - continue; - } - ts_remain -= 2; /* consume the 2 bytes SNDU length. */ - from_where += 2; - } - - priv->ule_sndu_remain = priv->ule_sndu_len + 2; - /* - * State of current TS: - * ts_remain (remaining bytes in the current TS cell) - * 0 ule_type is not available now, we need the next TS cell - * 1 the first byte of the ule_type is present - * >=2 full ULE header present, maybe some payload data as well. - */ - switch (ts_remain) { - case 1: - priv->ule_sndu_remain--; - priv->ule_sndu_type = from_where[0] << 8; - priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */ - ts_remain -= 1; from_where += 1; - /* Continue w/ next TS. */ - case 0: - new_ts = 1; - ts += TS_SZ; - priv->ts_count++; - continue; - - default: /* complete ULE header is present in current TS. */ - /* Extract ULE type field. */ - if (priv->ule_sndu_type_1) { - priv->ule_sndu_type_1 = 0; - priv->ule_sndu_type |= from_where[0]; - from_where += 1; /* points to payload start. */ - ts_remain -= 1; - } else { - /* Complete type is present in new TS. */ - priv->ule_sndu_type = from_where[0] << 8 | from_where[1]; - from_where += 2; /* points to payload start. */ - ts_remain -= 2; - } - break; - } - - /* Allocate the skb (decoder target buffer) with the correct size, as follows: - * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */ - priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN ); - if (priv->ule_skb == NULL) { - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", - dev->name); - dev->stats.rx_dropped++; - return; - } - - /* This includes the CRC32 _and_ dest mac, if !dbit. */ - priv->ule_sndu_remain = priv->ule_sndu_len; - priv->ule_skb->dev = dev; - /* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */ - skb_reserve( priv->ule_skb, ETH_HLEN + ETH_ALEN ); - } - - /* Copy data into our current skb. */ - how_much = min(priv->ule_sndu_remain, (int)ts_remain); - memcpy(skb_put(priv->ule_skb, how_much), from_where, how_much); - priv->ule_sndu_remain -= how_much; - ts_remain -= how_much; - from_where += how_much; - - /* Check for complete payload. */ - if (priv->ule_sndu_remain <= 0) { - /* Check CRC32, we've got it in our skb already. */ - __be16 ulen = htons(priv->ule_sndu_len); - __be16 utype = htons(priv->ule_sndu_type); - const u8 *tail; - struct kvec iov[3] = { - { &ulen, sizeof ulen }, - { &utype, sizeof utype }, - { priv->ule_skb->data, priv->ule_skb->len - 4 } - }; - u32 ule_crc = ~0L, expected_crc; - if (priv->ule_dbit) { - /* Set D-bit for CRC32 verification, - * if it was set originally. */ - ulen |= htons(0x8000); - } - - ule_crc = iov_crc32(ule_crc, iov, 3); - tail = skb_tail_pointer(priv->ule_skb); - expected_crc = *(tail - 4) << 24 | - *(tail - 3) << 16 | - *(tail - 2) << 8 | - *(tail - 1); - if (ule_crc != expected_crc) { - printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", - priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0); - -#ifdef ULE_DEBUG - hexdump( iov[0].iov_base, iov[0].iov_len ); - hexdump( iov[1].iov_base, iov[1].iov_len ); - hexdump( iov[2].iov_base, iov[2].iov_len ); - - if (ule_where == ule_hist) { - hexdump( &ule_hist[98*TS_SZ], TS_SZ ); - hexdump( &ule_hist[99*TS_SZ], TS_SZ ); - } else if (ule_where == &ule_hist[TS_SZ]) { - hexdump( &ule_hist[99*TS_SZ], TS_SZ ); - hexdump( ule_hist, TS_SZ ); - } else { - hexdump( ule_where - TS_SZ - TS_SZ, TS_SZ ); - hexdump( ule_where - TS_SZ, TS_SZ ); - } - ule_dump = 1; -#endif - - dev->stats.rx_errors++; - dev->stats.rx_crc_errors++; - dev_kfree_skb(priv->ule_skb); - } else { - /* CRC32 verified OK. */ - u8 dest_addr[ETH_ALEN]; - static const u8 bc_addr[ETH_ALEN] = - { [ 0 ... ETH_ALEN-1] = 0xff }; - - /* CRC32 was OK. Remove it from skb. */ - priv->ule_skb->tail -= 4; - priv->ule_skb->len -= 4; - - if (!priv->ule_dbit) { - /* - * The destination MAC address is the - * next data in the skb. It comes - * before any extension headers. - * - * Check if the payload of this SNDU - * should be passed up the stack. - */ - register int drop = 0; - if (priv->rx_mode != RX_MODE_PROMISC) { - if (priv->ule_skb->data[0] & 0x01) { - /* multicast or broadcast */ - if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) { - /* multicast */ - if (priv->rx_mode == RX_MODE_MULTI) { - int i; - for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++) - ; - if (i == priv->multi_num) - drop = 1; - } else if (priv->rx_mode != RX_MODE_ALL_MULTI) - drop = 1; /* no broadcast; */ - /* else: all multicast mode: accept all multicast packets */ - } - /* else: broadcast */ - } - else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN)) - drop = 1; - /* else: destination address matches the MAC address of our receiver device */ - } - /* else: promiscuous mode; pass everything up the stack */ - - if (drop) { -#ifdef ULE_DEBUG - dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n", - MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr)); -#endif - dev_kfree_skb(priv->ule_skb); - goto sndu_done; - } - else - { - skb_copy_from_linear_data(priv->ule_skb, - dest_addr, - ETH_ALEN); - skb_pull(priv->ule_skb, ETH_ALEN); - } - } - - /* Handle ULE Extension Headers. */ - if (priv->ule_sndu_type < 1536) { - /* There is an extension header. Handle it accordingly. */ - int l = handle_ule_extensions(priv); - if (l < 0) { - /* Mandatory extension header unknown or TEST SNDU. Drop it. */ - // printk( KERN_WARNING "Dropping SNDU, extension headers.\n" ); - dev_kfree_skb(priv->ule_skb); - goto sndu_done; - } - skb_pull(priv->ule_skb, l); - } - - /* - * Construct/assure correct ethernet header. - * Note: in bridged mode (priv->ule_bridged != - * 0) we already have the (original) ethernet - * header at the start of the payload (after - * optional dest. address and any extension - * headers). - */ - - if (!priv->ule_bridged) { - skb_push(priv->ule_skb, ETH_HLEN); - ethh = (struct ethhdr *)priv->ule_skb->data; - if (!priv->ule_dbit) { - /* dest_addr buffer is only valid if priv->ule_dbit == 0 */ - memcpy(ethh->h_dest, dest_addr, ETH_ALEN); - memset(ethh->h_source, 0, ETH_ALEN); - } - else /* zeroize source and dest */ - memset( ethh, 0, ETH_ALEN*2 ); - - ethh->h_proto = htons(priv->ule_sndu_type); - } - /* else: skb is in correct state; nothing to do. */ - priv->ule_bridged = 0; - - /* Stuff into kernel's protocol stack. */ - priv->ule_skb->protocol = dvb_net_eth_type_trans(priv->ule_skb, dev); - /* If D-bit is set (i.e. destination MAC address not present), - * receive the packet anyhow. */ - /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) - priv->ule_skb->pkt_type = PACKET_HOST; */ - dev->stats.rx_packets++; - dev->stats.rx_bytes += priv->ule_skb->len; - netif_rx(priv->ule_skb); - } - sndu_done: - /* Prepare for next SNDU. */ - reset_ule(priv); - } - - /* More data in current TS (look at the bytes following the CRC32)? */ - if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) { - /* Next ULE SNDU starts right there. */ - new_ts = 0; - priv->ule_skb = NULL; - priv->ule_sndu_type_1 = 0; - priv->ule_sndu_len = 0; - // printk(KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n", - // *(from_where + 0), *(from_where + 1), - // *(from_where + 2), *(from_where + 3)); - // printk(KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0); - // hexdump(ts, 188); - } else { - new_ts = 1; - ts += TS_SZ; - priv->ts_count++; - if (priv->ule_skb == NULL) { - priv->need_pusi = 1; - priv->ule_sndu_type_1 = 0; - priv->ule_sndu_len = 0; - } - } - } /* for all available TS cells */ -} - -static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed, enum dmx_success success) -{ - struct net_device *dev = feed->priv; - - if (buffer2) - printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2); - if (buffer1_len > 32768) - printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len); - /* printk("TS callback: %u bytes, %u TS cells @ %p.\n", - buffer1_len, buffer1_len / TS_SZ, buffer1); */ - dvb_net_ule(dev, buffer1, buffer1_len); - return 0; -} - - -static void dvb_net_sec(struct net_device *dev, - const u8 *pkt, int pkt_len) -{ - u8 *eth; - struct sk_buff *skb; - struct net_device_stats *stats = &dev->stats; - int snap = 0; - - /* note: pkt_len includes a 32bit checksum */ - if (pkt_len < 16) { - printk("%s: IP/MPE packet length = %d too small.\n", - dev->name, pkt_len); - stats->rx_errors++; - stats->rx_length_errors++; - return; - } -/* it seems some ISPs manage to screw up here, so we have to - * relax the error checks... */ -#if 0 - if ((pkt[5] & 0xfd) != 0xc1) { - /* drop scrambled or broken packets */ -#else - if ((pkt[5] & 0x3c) != 0x00) { - /* drop scrambled */ -#endif - stats->rx_errors++; - stats->rx_crc_errors++; - return; - } - if (pkt[5] & 0x02) { - /* handle LLC/SNAP, see rfc-1042 */ - if (pkt_len < 24 || memcmp(&pkt[12], "\xaa\xaa\x03\0\0\0", 6)) { - stats->rx_dropped++; - return; - } - snap = 8; - } - if (pkt[7]) { - /* FIXME: assemble datagram from multiple sections */ - stats->rx_errors++; - stats->rx_frame_errors++; - return; - } - - /* we have 14 byte ethernet header (ip header follows); - * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP - */ - if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) { - //printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); - stats->rx_dropped++; - return; - } - skb_reserve(skb, 2); /* longword align L3 header */ - skb->dev = dev; - - /* copy L3 payload */ - eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap); - memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap); - - /* create ethernet header: */ - eth[0]=pkt[0x0b]; - eth[1]=pkt[0x0a]; - eth[2]=pkt[0x09]; - eth[3]=pkt[0x08]; - eth[4]=pkt[0x04]; - eth[5]=pkt[0x03]; - - eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0; - - if (snap) { - eth[12] = pkt[18]; - eth[13] = pkt[19]; - } else { - /* protocol numbers are from rfc-1700 or - * http://www.iana.org/assignments/ethernet-numbers - */ - if (pkt[12] >> 4 == 6) { /* version field from IP header */ - eth[12] = 0x86; /* IPv6 */ - eth[13] = 0xdd; - } else { - eth[12] = 0x08; /* IPv4 */ - eth[13] = 0x00; - } - } - - skb->protocol = dvb_net_eth_type_trans(skb, dev); - - stats->rx_packets++; - stats->rx_bytes+=skb->len; - netif_rx(skb); -} - -static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *filter, - enum dmx_success success) -{ - struct net_device *dev = filter->priv; - - /** - * we rely on the DVB API definition where exactly one complete - * section is delivered in buffer1 - */ - dvb_net_sec (dev, buffer1, buffer1_len); - return 0; -} - -static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) -{ - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -static u8 mask_allmulti[6]={0xff, 0xff, 0xff, 0x00, 0x00, 0x00}; -static u8 mac_allmulti[6]={0x01, 0x00, 0x5e, 0x00, 0x00, 0x00}; -static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static int dvb_net_filter_sec_set(struct net_device *dev, - struct dmx_section_filter **secfilter, - u8 *mac, u8 *mac_mask) -{ - struct dvb_net_priv *priv = netdev_priv(dev); - int ret; - - *secfilter=NULL; - ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter); - if (ret<0) { - printk("%s: could not get filter\n", dev->name); - return ret; - } - - (*secfilter)->priv=(void *) dev; - - memset((*secfilter)->filter_value, 0x00, DMX_MAX_FILTER_SIZE); - memset((*secfilter)->filter_mask, 0x00, DMX_MAX_FILTER_SIZE); - memset((*secfilter)->filter_mode, 0xff, DMX_MAX_FILTER_SIZE); - - (*secfilter)->filter_value[0]=0x3e; - (*secfilter)->filter_value[3]=mac[5]; - (*secfilter)->filter_value[4]=mac[4]; - (*secfilter)->filter_value[8]=mac[3]; - (*secfilter)->filter_value[9]=mac[2]; - (*secfilter)->filter_value[10]=mac[1]; - (*secfilter)->filter_value[11]=mac[0]; - - (*secfilter)->filter_mask[0] = 0xff; - (*secfilter)->filter_mask[3] = mac_mask[5]; - (*secfilter)->filter_mask[4] = mac_mask[4]; - (*secfilter)->filter_mask[8] = mac_mask[3]; - (*secfilter)->filter_mask[9] = mac_mask[2]; - (*secfilter)->filter_mask[10] = mac_mask[1]; - (*secfilter)->filter_mask[11]=mac_mask[0]; - - dprintk("%s: filter mac=%pM\n", dev->name, mac); - dprintk("%s: filter mask=%pM\n", dev->name, mac_mask); - - return 0; -} - -static int dvb_net_feed_start(struct net_device *dev) -{ - int ret = 0, i; - struct dvb_net_priv *priv = netdev_priv(dev); - struct dmx_demux *demux = priv->demux; - unsigned char *mac = (unsigned char *) dev->dev_addr; - - dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode); - mutex_lock(&priv->mutex); - if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) - printk("%s: BUG %d\n", __func__, __LINE__); - - priv->secfeed=NULL; - priv->secfilter=NULL; - priv->tsfeed = NULL; - - if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { - dprintk("%s: alloc secfeed\n", __func__); - ret=demux->allocate_section_feed(demux, &priv->secfeed, - dvb_net_sec_callback); - if (ret<0) { - printk("%s: could not allocate section feed\n", dev->name); - goto error; - } - - ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); - - if (ret<0) { - printk("%s: could not set section feed\n", dev->name); - priv->demux->release_section_feed(priv->demux, priv->secfeed); - priv->secfeed=NULL; - goto error; - } - - if (priv->rx_mode != RX_MODE_PROMISC) { - dprintk("%s: set secfilter\n", __func__); - dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal); - } - - switch (priv->rx_mode) { - case RX_MODE_MULTI: - for (i = 0; i < priv->multi_num; i++) { - dprintk("%s: set multi_secfilter[%d]\n", __func__, i); - dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i], - priv->multi_macs[i], mask_normal); - } - break; - case RX_MODE_ALL_MULTI: - priv->multi_num=1; - dprintk("%s: set multi_secfilter[0]\n", __func__); - dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0], - mac_allmulti, mask_allmulti); - break; - case RX_MODE_PROMISC: - priv->multi_num=0; - dprintk("%s: set secfilter\n", __func__); - dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc); - break; - } - - dprintk("%s: start filtering\n", __func__); - priv->secfeed->start_filtering(priv->secfeed); - } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { - struct timespec timeout = { 0, 10000000 }; // 10 msec - - /* we have payloads encapsulated in TS */ - dprintk("%s: alloc tsfeed\n", __func__); - ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); - if (ret < 0) { - printk("%s: could not allocate ts feed\n", dev->name); - goto error; - } - - /* Set netdevice pointer for ts decaps callback. */ - priv->tsfeed->priv = (void *)dev; - ret = priv->tsfeed->set(priv->tsfeed, - priv->pid, /* pid */ - TS_PACKET, /* type */ - DMX_TS_PES_OTHER, /* pes type */ - 32768, /* circular buffer size */ - timeout /* timeout */ - ); - - if (ret < 0) { - printk("%s: could not set ts feed\n", dev->name); - priv->demux->release_ts_feed(priv->demux, priv->tsfeed); - priv->tsfeed = NULL; - goto error; - } - - dprintk("%s: start filtering\n", __func__); - priv->tsfeed->start_filtering(priv->tsfeed); - } else - ret = -EINVAL; - -error: - mutex_unlock(&priv->mutex); - return ret; -} - -static int dvb_net_feed_stop(struct net_device *dev) -{ - struct dvb_net_priv *priv = netdev_priv(dev); - int i, ret = 0; - - dprintk("%s\n", __func__); - mutex_lock(&priv->mutex); - if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { - if (priv->secfeed) { - if (priv->secfeed->is_filtering) { - dprintk("%s: stop secfeed\n", __func__); - priv->secfeed->stop_filtering(priv->secfeed); - } - - if (priv->secfilter) { - dprintk("%s: release secfilter\n", __func__); - priv->secfeed->release_filter(priv->secfeed, - priv->secfilter); - priv->secfilter=NULL; - } - - for (i=0; imulti_num; i++) { - if (priv->multi_secfilter[i]) { - dprintk("%s: release multi_filter[%d]\n", - __func__, i); - priv->secfeed->release_filter(priv->secfeed, - priv->multi_secfilter[i]); - priv->multi_secfilter[i] = NULL; - } - } - - priv->demux->release_section_feed(priv->demux, priv->secfeed); - priv->secfeed = NULL; - } else - printk("%s: no feed to stop\n", dev->name); - } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { - if (priv->tsfeed) { - if (priv->tsfeed->is_filtering) { - dprintk("%s: stop tsfeed\n", __func__); - priv->tsfeed->stop_filtering(priv->tsfeed); - } - priv->demux->release_ts_feed(priv->demux, priv->tsfeed); - priv->tsfeed = NULL; - } - else - printk("%s: no ts feed to stop\n", dev->name); - } else - ret = -EINVAL; - mutex_unlock(&priv->mutex); - return ret; -} - - -static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr) -{ - struct dvb_net_priv *priv = netdev_priv(dev); - - if (priv->multi_num == DVB_NET_MULTICAST_MAX) - return -ENOMEM; - - memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN); - - priv->multi_num++; - return 0; -} - - -static void wq_set_multicast_list (struct work_struct *work) -{ - struct dvb_net_priv *priv = - container_of(work, struct dvb_net_priv, set_multicast_list_wq); - struct net_device *dev = priv->net; - - dvb_net_feed_stop(dev); - priv->rx_mode = RX_MODE_UNI; - netif_addr_lock_bh(dev); - - if (dev->flags & IFF_PROMISC) { - dprintk("%s: promiscuous mode\n", dev->name); - priv->rx_mode = RX_MODE_PROMISC; - } else if ((dev->flags & IFF_ALLMULTI)) { - dprintk("%s: allmulti mode\n", dev->name); - priv->rx_mode = RX_MODE_ALL_MULTI; - } else if (!netdev_mc_empty(dev)) { - struct netdev_hw_addr *ha; - - dprintk("%s: set_mc_list, %d entries\n", - dev->name, netdev_mc_count(dev)); - - priv->rx_mode = RX_MODE_MULTI; - priv->multi_num = 0; - - netdev_for_each_mc_addr(ha, dev) - dvb_set_mc_filter(dev, ha->addr); - } - - netif_addr_unlock_bh(dev); - dvb_net_feed_start(dev); -} - - -static void dvb_net_set_multicast_list (struct net_device *dev) -{ - struct dvb_net_priv *priv = netdev_priv(dev); - schedule_work(&priv->set_multicast_list_wq); -} - - -static void wq_restart_net_feed (struct work_struct *work) -{ - struct dvb_net_priv *priv = - container_of(work, struct dvb_net_priv, restart_net_feed_wq); - struct net_device *dev = priv->net; - - if (netif_running(dev)) { - dvb_net_feed_stop(dev); - dvb_net_feed_start(dev); - } -} - - -static int dvb_net_set_mac (struct net_device *dev, void *p) -{ - struct dvb_net_priv *priv = netdev_priv(dev); - struct sockaddr *addr=p; - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - - if (netif_running(dev)) - schedule_work(&priv->restart_net_feed_wq); - - return 0; -} - - -static int dvb_net_open(struct net_device *dev) -{ - struct dvb_net_priv *priv = netdev_priv(dev); - - priv->in_use++; - dvb_net_feed_start(dev); - return 0; -} - - -static int dvb_net_stop(struct net_device *dev) -{ - struct dvb_net_priv *priv = netdev_priv(dev); - - priv->in_use--; - return dvb_net_feed_stop(dev); -} - -static const struct header_ops dvb_header_ops = { - .create = eth_header, - .parse = eth_header_parse, - .rebuild = eth_rebuild_header, -}; - - -static const struct net_device_ops dvb_netdev_ops = { - .ndo_open = dvb_net_open, - .ndo_stop = dvb_net_stop, - .ndo_start_xmit = dvb_net_tx, - .ndo_set_multicast_list = dvb_net_set_multicast_list, - .ndo_set_mac_address = dvb_net_set_mac, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, -}; - -static void dvb_net_setup(struct net_device *dev) -{ - ether_setup(dev); - - dev->header_ops = &dvb_header_ops; - dev->netdev_ops = &dvb_netdev_ops; - dev->mtu = 4096; - - dev->flags |= IFF_NOARP; -} - -static int get_if(struct dvb_net *dvbnet) -{ - int i; - - for (i=0; istate[i]) - break; - - if (i == DVB_NET_DEVICES_MAX) - return -1; - - dvbnet->state[i]=1; - return i; -} - -static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) -{ - struct net_device *net; - struct dvb_net_priv *priv; - int result; - int if_num; - - if (feedtype != DVB_NET_FEEDTYPE_MPE && feedtype != DVB_NET_FEEDTYPE_ULE) - return -EINVAL; - if ((if_num = get_if(dvbnet)) < 0) - return -EINVAL; - - net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup); - if (!net) - return -ENOMEM; - - if (dvbnet->dvbdev->id) - snprintf(net->name, IFNAMSIZ, "dvb%d%u%d", - dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num); - else - /* compatibility fix to keep dvb0_0 format */ - snprintf(net->name, IFNAMSIZ, "dvb%d_%d", - dvbnet->dvbdev->adapter->num, if_num); - - net->addr_len = 6; - memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6); - - dvbnet->device[if_num] = net; - - priv = netdev_priv(net); - priv->net = net; - priv->demux = dvbnet->demux; - priv->pid = pid; - priv->rx_mode = RX_MODE_UNI; - priv->need_pusi = 1; - priv->tscc = 0; - priv->feedtype = feedtype; - reset_ule(priv); - - INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list); - INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed); - mutex_init(&priv->mutex); - - net->base_addr = pid; - - if ((result = register_netdev(net)) < 0) { - dvbnet->device[if_num] = NULL; - free_netdev(net); - return result; - } - printk("dvb_net: created network interface %s\n", net->name); - - return if_num; -} - -static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num) -{ - struct net_device *net = dvbnet->device[num]; - struct dvb_net_priv *priv; - - if (!dvbnet->state[num]) - return -EINVAL; - priv = netdev_priv(net); - if (priv->in_use) - return -EBUSY; - - dvb_net_stop(net); - flush_work_sync(&priv->set_multicast_list_wq); - flush_work_sync(&priv->restart_net_feed_wq); - printk("dvb_net: removed network interface %s\n", net->name); - unregister_netdev(net); - dvbnet->state[num]=0; - dvbnet->device[num] = NULL; - free_netdev(net); - - return 0; -} - -static int dvb_net_do_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_net *dvbnet = dvbdev->priv; - - if (((file->f_flags&O_ACCMODE)==O_RDONLY)) - return -EPERM; - - switch (cmd) { - case NET_ADD_IF: - { - struct dvb_net_if *dvbnetif = parg; - int result; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!try_module_get(dvbdev->adapter->module)) - return -EPERM; - - result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype); - if (result<0) { - module_put(dvbdev->adapter->module); - return result; - } - dvbnetif->if_num=result; - break; - } - case NET_GET_IF: - { - struct net_device *netdev; - struct dvb_net_priv *priv_data; - struct dvb_net_if *dvbnetif = parg; - - if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || - !dvbnet->state[dvbnetif->if_num]) - return -EINVAL; - - netdev = dvbnet->device[dvbnetif->if_num]; - - priv_data = netdev_priv(netdev); - dvbnetif->pid=priv_data->pid; - dvbnetif->feedtype=priv_data->feedtype; - break; - } - case NET_REMOVE_IF: - { - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if ((unsigned long) parg >= DVB_NET_DEVICES_MAX) - return -EINVAL; - ret = dvb_net_remove_if(dvbnet, (unsigned long) parg); - if (!ret) - module_put(dvbdev->adapter->module); - return ret; - } - - /* binary compatibility cruft */ - case __NET_ADD_IF_OLD: - { - struct __dvb_net_if_old *dvbnetif = parg; - int result; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!try_module_get(dvbdev->adapter->module)) - return -EPERM; - - result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE); - if (result<0) { - module_put(dvbdev->adapter->module); - return result; - } - dvbnetif->if_num=result; - break; - } - case __NET_GET_IF_OLD: - { - struct net_device *netdev; - struct dvb_net_priv *priv_data; - struct __dvb_net_if_old *dvbnetif = parg; - - if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || - !dvbnet->state[dvbnetif->if_num]) - return -EINVAL; - - netdev = dvbnet->device[dvbnetif->if_num]; - - priv_data = netdev_priv(netdev); - dvbnetif->pid=priv_data->pid; - break; - } - default: - return -ENOTTY; - } - return 0; -} - -static long dvb_net_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl); -} - -static int dvb_net_close(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_net *dvbnet = dvbdev->priv; - - dvb_generic_release(inode, file); - - if(dvbdev->users == 1 && dvbnet->exit == 1) { - fops_put(file->f_op); - file->f_op = NULL; - wake_up(&dvbdev->wait_queue); - } - return 0; -} - - -static const struct file_operations dvb_net_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = dvb_net_ioctl, - .open = dvb_generic_open, - .release = dvb_net_close, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_net = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_net_fops, -}; - - -void dvb_net_release (struct dvb_net *dvbnet) -{ - int i; - - dvbnet->exit = 1; - if (dvbnet->dvbdev->users < 1) - wait_event(dvbnet->dvbdev->wait_queue, - dvbnet->dvbdev->users==1); - - dvb_unregister_device(dvbnet->dvbdev); - - for (i=0; istate[i]) - continue; - dvb_net_remove_if(dvbnet, i); - } -} -EXPORT_SYMBOL(dvb_net_release); - - -int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, - struct dmx_demux *dmx) -{ - int i; - - dvbnet->demux = dmx; - - for (i=0; istate[i] = 0; - - dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net, - dvbnet, DVB_DEVICE_NET); - - return 0; -} -EXPORT_SYMBOL(dvb_net_init); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_net.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_net.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_net.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_net.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * dvb_net.h - * - * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVB_NET_H_ -#define _DVB_NET_H_ - -#include -#include -#include -#include -#include - -#include "dvbdev.h" - -#define DVB_NET_DEVICES_MAX 10 - -struct dvb_net { - struct dvb_device *dvbdev; - struct net_device *device[DVB_NET_DEVICES_MAX]; - int state[DVB_NET_DEVICES_MAX]; - unsigned int exit:1; - struct dmx_demux *demux; -}; - - -void dvb_net_release(struct dvb_net *); -int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,299 +0,0 @@ -/* - * - * dvb_ringbuffer.c: ring buffer implementation for the dvb driver - * - * Copyright (C) 2003 Oliver Endriss - * Copyright (C) 2004 Andrew de Quincey - * - * based on code originally found in av7110.c & dvb_ci.c: - * Copyright (C) 1999-2003 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser 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 -#include -#include -#include -#include -#include - -#include "dvb_ringbuffer.h" - -#define PKT_READY 0 -#define PKT_DISPOSED 1 - - -void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) -{ - rbuf->pread=rbuf->pwrite=0; - rbuf->data=data; - rbuf->size=len; - rbuf->error=0; - - init_waitqueue_head(&rbuf->queue); - - spin_lock_init(&(rbuf->lock)); -} - - - -int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) -{ - return (rbuf->pread==rbuf->pwrite); -} - - - -ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf) -{ - ssize_t free; - - free = rbuf->pread - rbuf->pwrite; - if (free <= 0) - free += rbuf->size; - return free-1; -} - - - -ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) -{ - ssize_t avail; - - avail = rbuf->pwrite - rbuf->pread; - if (avail < 0) - avail += rbuf->size; - return avail; -} - - - -void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) -{ - rbuf->pread = rbuf->pwrite; - rbuf->error = 0; -} -EXPORT_SYMBOL(dvb_ringbuffer_flush); - -void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf) -{ - rbuf->pread = rbuf->pwrite = 0; - rbuf->error = 0; -} - -void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf) -{ - unsigned long flags; - - spin_lock_irqsave(&rbuf->lock, flags); - dvb_ringbuffer_flush(rbuf); - spin_unlock_irqrestore(&rbuf->lock, flags); - - wake_up(&rbuf->queue); -} - -ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len) -{ - size_t todo = len; - size_t split; - - split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; - if (split > 0) { - if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) - return -EFAULT; - buf += split; - todo -= split; - rbuf->pread = 0; - } - if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) - return -EFAULT; - - rbuf->pread = (rbuf->pread + todo) % rbuf->size; - - return len; -} - -void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len) -{ - size_t todo = len; - size_t split; - - split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; - if (split > 0) { - memcpy(buf, rbuf->data+rbuf->pread, split); - buf += split; - todo -= split; - rbuf->pread = 0; - } - memcpy(buf, rbuf->data+rbuf->pread, todo); - - rbuf->pread = (rbuf->pread + todo) % rbuf->size; -} - - -ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len) -{ - size_t todo = len; - size_t split; - - split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; - - if (split > 0) { - memcpy(rbuf->data+rbuf->pwrite, buf, split); - buf += split; - todo -= split; - rbuf->pwrite = 0; - } - memcpy(rbuf->data+rbuf->pwrite, buf, todo); - rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; - - return len; -} - -ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len) -{ - int status; - ssize_t oldpwrite = rbuf->pwrite; - - DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8); - DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff); - DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY); - status = dvb_ringbuffer_write(rbuf, buf, len); - - if (status < 0) rbuf->pwrite = oldpwrite; - return status; -} - -ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8 __user *buf, size_t len) -{ - size_t todo; - size_t split; - size_t pktlen; - - pktlen = rbuf->data[idx] << 8; - pktlen |= rbuf->data[(idx + 1) % rbuf->size]; - if (offset > pktlen) return -EINVAL; - if ((offset + len) > pktlen) len = pktlen - offset; - - idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; - todo = len; - split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; - if (split > 0) { - if (copy_to_user(buf, rbuf->data+idx, split)) - return -EFAULT; - buf += split; - todo -= split; - idx = 0; - } - if (copy_to_user(buf, rbuf->data+idx, todo)) - return -EFAULT; - - return len; -} - -ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len) -{ - size_t todo; - size_t split; - size_t pktlen; - - pktlen = rbuf->data[idx] << 8; - pktlen |= rbuf->data[(idx + 1) % rbuf->size]; - if (offset > pktlen) return -EINVAL; - if ((offset + len) > pktlen) len = pktlen - offset; - - idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; - todo = len; - split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; - if (split > 0) { - memcpy(buf, rbuf->data+idx, split); - buf += split; - todo -= split; - idx = 0; - } - memcpy(buf, rbuf->data+idx, todo); - return len; -} - -void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) -{ - size_t pktlen; - - rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED; - - // clean up disposed packets - while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) { - if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) { - pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8; - pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1); - DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE); - } else { - // first packet is not disposed, so we stop cleaning now - break; - } - } -} - -ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen) -{ - int consumed; - int curpktlen; - int curpktstatus; - - if (idx == -1) { - idx = rbuf->pread; - } else { - curpktlen = rbuf->data[idx] << 8; - curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; - idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; - } - - consumed = (idx - rbuf->pread) % rbuf->size; - - while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) { - - curpktlen = rbuf->data[idx] << 8; - curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; - curpktstatus = rbuf->data[(idx + 2) % rbuf->size]; - - if (curpktstatus == PKT_READY) { - *pktlen = curpktlen; - return idx; - } - - consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE; - idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; - } - - // no packets available - return -1; -} - - - -EXPORT_SYMBOL(dvb_ringbuffer_init); -EXPORT_SYMBOL(dvb_ringbuffer_empty); -EXPORT_SYMBOL(dvb_ringbuffer_free); -EXPORT_SYMBOL(dvb_ringbuffer_avail); -EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); -EXPORT_SYMBOL(dvb_ringbuffer_read_user); -EXPORT_SYMBOL(dvb_ringbuffer_read); -EXPORT_SYMBOL(dvb_ringbuffer_write); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,186 +0,0 @@ -/* - * - * dvb_ringbuffer.h: ring buffer implementation for the dvb driver - * - * Copyright (C) 2003 Oliver Endriss - * Copyright (C) 2004 Andrew de Quincey - * - * based on code originally found in av7110.c & dvb_ci.c: - * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser 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. - */ - -#ifndef _DVB_RINGBUFFER_H_ -#define _DVB_RINGBUFFER_H_ - -#include -#include - -struct dvb_ringbuffer { - u8 *data; - ssize_t size; - ssize_t pread; - ssize_t pwrite; - int error; - - wait_queue_head_t queue; - spinlock_t lock; -}; - -#define DVB_RINGBUFFER_PKTHDRSIZE 3 - - -/* -** Notes: -** ------ -** (1) For performance reasons read and write routines don't check buffer sizes -** and/or number of bytes free/available. This has to be done before these -** routines are called. For example: -** -** *** write bytes *** -** free = dvb_ringbuffer_free(rbuf); -** if (free >= buflen) -** count = dvb_ringbuffer_write(rbuf, buffer, buflen); -** else -** ... -** -** *** read min. 1000, max. bytes *** -** avail = dvb_ringbuffer_avail(rbuf); -** if (avail >= 1000) -** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize)); -** else -** ... -** -** (2) If there is exactly one reader and one writer, there is no need -** to lock read or write operations. -** Two or more readers must be locked against each other. -** Flushing the buffer counts as a read operation. -** Resetting the buffer counts as a read and write operation. -** Two or more writers must be locked against each other. -*/ - -/* initialize ring buffer, lock and queue */ -extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len); - -/* test whether buffer is empty */ -extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf); - -/* return the number of free bytes in the buffer */ -extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf); - -/* return the number of bytes waiting in the buffer */ -extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf); - - -/* -** Reset the read and write pointers to zero and flush the buffer -** This counts as a read and write operation -*/ -extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf); - - -/* read routines & macros */ -/* ---------------------- */ -/* flush buffer */ -extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf); - -/* flush buffer protected by spinlock and wake-up waiting task(s) */ -extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); - -/* peek at byte in the buffer */ -#define DVB_RINGBUFFER_PEEK(rbuf,offs) \ - (rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size] - -/* advance read ptr by bytes */ -#define DVB_RINGBUFFER_SKIP(rbuf,num) \ - (rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size - -/* -** read bytes from ring buffer into -** specifies whether resides in user space -** returns number of bytes transferred or -EFAULT -*/ -extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, - u8 __user *buf, size_t len); -extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, - u8 *buf, size_t len); - - -/* write routines & macros */ -/* ----------------------- */ -/* write single byte to ring buffer */ -#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte) \ - { (rbuf)->data[(rbuf)->pwrite]=(byte); \ - (rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; } -/* -** write bytes to ring buffer -** specifies whether resides in user space -** returns number of bytes transferred or -EFAULT -*/ -extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, - size_t len); - - -/** - * Write a packet into the ringbuffer. - * - * Ringbuffer to write to. - * Buffer to write. - * Length of buffer (currently limited to 65535 bytes max). - * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. - */ -extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, - size_t len); - -/** - * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this - * does NOT update the read pointer in the ringbuffer. You must use - * dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required. - * - * Ringbuffer concerned. - * Packet index as returned by dvb_ringbuffer_pkt_next(). - * Offset into packet to read from. - * Destination buffer for data. - * Size of destination buffer. - * Set to 1 if is in userspace. - * returns Number of bytes read, or -EFAULT. - */ -extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8 __user *buf, size_t len); -extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8 *buf, size_t len); - -/** - * Dispose of a packet in the ring buffer. - * - * Ring buffer concerned. - * Packet index as returned by dvb_ringbuffer_pkt_next(). - */ -extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx); - -/** - * Get the index of the next packet in a ringbuffer. - * - * Ringbuffer concerned. - * Previous packet index, or -1 to return the first packet index. - * On success, will be updated to contain the length of the packet in bytes. - * returns Packet index (if >=0), or -1 if no packets available. - */ -extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen); - - -#endif /* _DVB_RINGBUFFER_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-core/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -# -# Makefile for the kernel DVB device drivers. -# - -dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ - dvb_ca_en50221.o dvb_frontend.o \ - dvb_net.o dvb_ringbuffer.o dvb_math.o - -obj-$(CONFIG_DVB_CORE) += dvb-core.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/a800.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/a800.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/a800.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/a800.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,198 +0,0 @@ -/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T - * USB2.0 (A800) DVB-T receiver. - * - * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to - * - AVerMedia who kindly provided information and - * - Glen Harris who suffered from my mistakes during development. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_rc(args...) dprintk(debug,0x01,args) - -static int a800_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - /* do nothing for the AVerMedia */ - return 0; -} - -/* assure to put cold to 0 for iManufacturer == 1 */ -static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold) -{ - *cold = udev->descriptor.iManufacturer != 1; - return 0; -} - -static struct rc_map_table rc_map_a800_table[] = { - { 0x0201, KEY_MODE }, /* SOURCE */ - { 0x0200, KEY_POWER2 }, /* POWER */ - { 0x0205, KEY_1 }, /* 1 */ - { 0x0206, KEY_2 }, /* 2 */ - { 0x0207, KEY_3 }, /* 3 */ - { 0x0209, KEY_4 }, /* 4 */ - { 0x020a, KEY_5 }, /* 5 */ - { 0x020b, KEY_6 }, /* 6 */ - { 0x020d, KEY_7 }, /* 7 */ - { 0x020e, KEY_8 }, /* 8 */ - { 0x020f, KEY_9 }, /* 9 */ - { 0x0212, KEY_LEFT }, /* L / DISPLAY */ - { 0x0211, KEY_0 }, /* 0 */ - { 0x0213, KEY_RIGHT }, /* R / CH RTN */ - { 0x0217, KEY_CAMERA }, /* SNAP SHOT */ - { 0x0210, KEY_LAST }, /* 16-CH PREV */ - { 0x021e, KEY_VOLUMEDOWN }, /* VOL DOWN */ - { 0x020c, KEY_ZOOM }, /* FULL SCREEN */ - { 0x021f, KEY_VOLUMEUP }, /* VOL UP */ - { 0x0214, KEY_MUTE }, /* MUTE */ - { 0x0208, KEY_AUDIO }, /* AUDIO */ - { 0x0219, KEY_RECORD }, /* RECORD */ - { 0x0218, KEY_PLAY }, /* PLAY */ - { 0x021b, KEY_STOP }, /* STOP */ - { 0x021a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */ - { 0x021d, KEY_BACK }, /* << / RED */ - { 0x021c, KEY_FORWARD }, /* >> / YELLOW */ - { 0x0203, KEY_TEXT }, /* TELETEXT */ - { 0x0204, KEY_EPG }, /* EPG */ - { 0x0215, KEY_MENU }, /* MENU */ - - { 0x0303, KEY_CHANNELUP }, /* CH UP */ - { 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */ - { 0x0301, KEY_FIRST }, /* |<< / GREEN */ - { 0x0300, KEY_LAST }, /* >>| / BLUE */ - -}; - -static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key[5]; - if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0), - 0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5, - 2000) != 5) - return -ENODEV; - - /* call the universal NEC remote processor, to find out the key's state and event */ - dvb_usb_nec_rc_key_to_event(d,key,event,state); - if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); - return 0; -} - -/* USB Driver stuff */ -static struct dvb_usb_device_properties a800_properties; - -static int a800_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &a800_properties, - THIS_MODULE, NULL, adapter_nr); -} - -/* do not change the order of the ID table */ -static struct usb_device_id a800_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_WARM) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, a800_table); - -static struct dvb_usb_device_properties a800_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-avertv-a800-02.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - - .frontend_attach = dibusb_dib3000mc_frontend_attach, - .tuner_attach = dibusb_dib3000mc_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - - .size_of_priv = sizeof(struct dibusb_state), - }, - }, - - .power_ctrl = a800_power_ctrl, - .identify_state = a800_identify_state, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_a800_table, - .rc_map_size = ARRAY_SIZE(rc_map_a800_table), - .rc_query = a800_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 1, - .devices = { - { "AVerMedia AverTV DVB-T USB 2.0 (A800)", - { &a800_table[0], NULL }, - { &a800_table[1], NULL }, - }, - } -}; - -static struct usb_driver a800_driver = { - .name = "dvb_usb_a800", - .probe = a800_probe, - .disconnect = dvb_usb_device_exit, - .id_table = a800_table, -}; - -/* module stuff */ -static int __init a800_module_init(void) -{ - int result; - if ((result = usb_register(&a800_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit a800_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&a800_driver); -} - -module_init (a800_module_init); -module_exit (a800_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1104 +0,0 @@ -/* DVB USB compliant Linux driver for the Afatech 9005 - * USB1.1 DVB-T receiver. - * - * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) - * - * Thanks to Afatech who kindly provided information. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * see Documentation/dvb/REDME.dvb-usb for more information - */ -#include "af9005.h" - -/* debug */ -int dvb_usb_af9005_debug; -module_param_named(debug, dvb_usb_af9005_debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." - DVB_USB_DEBUG_STATUS); -/* enable obnoxious led */ -int dvb_usb_af9005_led = 1; -module_param_named(led, dvb_usb_af9005_led, bool, 0644); -MODULE_PARM_DESC(led, "enable led (default: 1)."); - -/* eeprom dump */ -static int dvb_usb_af9005_dump_eeprom; -module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); -MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -/* remote control decoder */ -static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len, - u32 *event, int *state); -static void *rc_keys; -static int *rc_keys_size; - -u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; - -struct af9005_device_state { - u8 sequence; - int led_state; -}; - -static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, - int readwrite, int type, u8 * values, int len) -{ - struct af9005_device_state *st = d->priv; - u8 obuf[16] = { 0 }; - u8 ibuf[17] = { 0 }; - u8 command; - int i; - int ret; - - if (len < 1) { - err("generic read/write, less than 1 byte. Makes no sense."); - return -EINVAL; - } - if (len > 8) { - err("generic read/write, more than 8 bytes. Not supported."); - return -EINVAL; - } - - obuf[0] = 14; /* rest of buffer length low */ - obuf[1] = 0; /* rest of buffer length high */ - - obuf[2] = AF9005_REGISTER_RW; /* register operation */ - obuf[3] = 12; /* rest of buffer length */ - - obuf[4] = st->sequence++; /* sequence number */ - - obuf[5] = (u8) (reg >> 8); /* register address */ - obuf[6] = (u8) (reg & 0xff); - - if (type == AF9005_OFDM_REG) { - command = AF9005_CMD_OFDM_REG; - } else { - command = AF9005_CMD_TUNER; - } - - if (len > 1) - command |= - AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3; - command |= readwrite; - if (readwrite == AF9005_CMD_WRITE) - for (i = 0; i < len; i++) - obuf[8 + i] = values[i]; - else if (type == AF9005_TUNER_REG) - /* read command for tuner, the first byte contains the i2c address */ - obuf[8] = values[0]; - obuf[7] = command; - - ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0); - if (ret) - return ret; - - /* sanity check */ - if (ibuf[2] != AF9005_REGISTER_RW_ACK) { - err("generic read/write, wrong reply code."); - return -EIO; - } - if (ibuf[3] != 0x0d) { - err("generic read/write, wrong length in reply."); - return -EIO; - } - if (ibuf[4] != obuf[4]) { - err("generic read/write, wrong sequence in reply."); - return -EIO; - } - /* - Windows driver doesn't check these fields, in fact sometimes - the register in the reply is different that what has been sent - - if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) { - err("generic read/write, wrong register in reply."); - return -EIO; - } - if (ibuf[7] != command) { - err("generic read/write wrong command in reply."); - return -EIO; - } - */ - if (ibuf[16] != 0x01) { - err("generic read/write wrong status code in reply."); - return -EIO; - } - if (readwrite == AF9005_CMD_READ) - for (i = 0; i < len; i++) - values[i] = ibuf[8 + i]; - - return 0; - -} - -int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value) -{ - int ret; - deb_reg("read register %x ", reg); - ret = af9005_generic_read_write(d, reg, - AF9005_CMD_READ, AF9005_OFDM_REG, - value, 1); - if (ret) - deb_reg("failed\n"); - else - deb_reg("value %x\n", *value); - return ret; -} - -int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len) -{ - int ret; - deb_reg("read %d registers %x ", len, reg); - ret = af9005_generic_read_write(d, reg, - AF9005_CMD_READ, AF9005_OFDM_REG, - values, len); - if (ret) - deb_reg("failed\n"); - else - debug_dump(values, len, deb_reg); - return ret; -} - -int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value) -{ - int ret; - u8 temp = value; - deb_reg("write register %x value %x ", reg, value); - ret = af9005_generic_read_write(d, reg, - AF9005_CMD_WRITE, AF9005_OFDM_REG, - &temp, 1); - if (ret) - deb_reg("failed\n"); - else - deb_reg("ok\n"); - return ret; -} - -int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len) -{ - int ret; - deb_reg("write %d registers %x values ", len, reg); - debug_dump(values, len, deb_reg); - - ret = af9005_generic_read_write(d, reg, - AF9005_CMD_WRITE, AF9005_OFDM_REG, - values, len); - if (ret) - deb_reg("failed\n"); - else - deb_reg("ok\n"); - return ret; -} - -int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, - u8 len, u8 * value) -{ - u8 temp; - int ret; - deb_reg("read bits %x %x %x", reg, pos, len); - ret = af9005_read_ofdm_register(d, reg, &temp); - if (ret) { - deb_reg(" failed\n"); - return ret; - } - *value = (temp >> pos) & regmask[len - 1]; - deb_reg(" value %x\n", *value); - return 0; - -} - -int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, - u8 len, u8 value) -{ - u8 temp, mask; - int ret; - deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value); - if (pos == 0 && len == 8) - return af9005_write_ofdm_register(d, reg, value); - ret = af9005_read_ofdm_register(d, reg, &temp); - if (ret) - return ret; - mask = regmask[len - 1] << pos; - temp = (temp & ~mask) | ((value << pos) & mask); - return af9005_write_ofdm_register(d, reg, temp); - -} - -static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d, - u16 reg, u8 * values, int len) -{ - return af9005_generic_read_write(d, reg, - AF9005_CMD_READ, AF9005_TUNER_REG, - values, len); -} - -static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d, - u16 reg, u8 * values, int len) -{ - return af9005_generic_read_write(d, reg, - AF9005_CMD_WRITE, - AF9005_TUNER_REG, values, len); -} - -int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len) -{ - /* don't let the name of this function mislead you: it's just used - as an interface from the firmware to the i2c bus. The actual - i2c addresses are contained in the data */ - int ret, i, done = 0, fail = 0; - u8 temp; - ret = af9005_usb_write_tuner_registers(d, reg, values, len); - if (ret) - return ret; - if (reg != 0xffff) { - /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */ - for (i = 0; i < 200; i++) { - ret = - af9005_read_ofdm_register(d, - xd_I2C_i2c_m_status_wdat_done, - &temp); - if (ret) - return ret; - done = temp & (regmask[i2c_m_status_wdat_done_len - 1] - << i2c_m_status_wdat_done_pos); - if (done) - break; - fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1] - << i2c_m_status_wdat_fail_pos); - if (fail) - break; - msleep(50); - } - if (i == 200) - return -ETIMEDOUT; - if (fail) { - /* clear write fail bit */ - af9005_write_register_bits(d, - xd_I2C_i2c_m_status_wdat_fail, - i2c_m_status_wdat_fail_pos, - i2c_m_status_wdat_fail_len, - 1); - return -EIO; - } - /* clear write done bit */ - ret = - af9005_write_register_bits(d, - xd_I2C_i2c_m_status_wdat_fail, - i2c_m_status_wdat_done_pos, - i2c_m_status_wdat_done_len, 1); - if (ret) - return ret; - } - return 0; -} - -int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr, - u8 * values, int len) -{ - /* don't let the name of this function mislead you: it's just used - as an interface from the firmware to the i2c bus. The actual - i2c addresses are contained in the data */ - int ret, i; - u8 temp, buf[2]; - - buf[0] = addr; /* tuner i2c address */ - buf[1] = values[0]; /* tuner register */ - - values[0] = addr + 0x01; /* i2c read address */ - - if (reg == APO_REG_I2C_RW_SILICON_TUNER) { - /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */ - ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2); - if (ret) - return ret; - } - - /* send read command to ofsm */ - ret = af9005_usb_read_tuner_registers(d, reg, values, 1); - if (ret) - return ret; - - /* check if read done */ - for (i = 0; i < 200; i++) { - ret = af9005_read_ofdm_register(d, 0xa408, &temp); - if (ret) - return ret; - if (temp & 0x01) - break; - msleep(50); - } - if (i == 200) - return -ETIMEDOUT; - - /* clear read done bit (by writing 1) */ - ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1); - if (ret) - return ret; - - /* get read data (available from 0xa400) */ - for (i = 0; i < len; i++) { - ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp); - if (ret) - return ret; - values[i] = temp; - } - return 0; -} - -static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg, - u8 * data, int len) -{ - int ret, i; - u8 buf[3]; - deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr, - reg, len); - debug_dump(data, len, deb_i2c); - - for (i = 0; i < len; i++) { - buf[0] = i2caddr; - buf[1] = reg + (u8) i; - buf[2] = data[i]; - ret = - af9005_write_tuner_registers(d, - APO_REG_I2C_RW_SILICON_TUNER, - buf, 3); - if (ret) { - deb_i2c("i2c_write failed\n"); - return ret; - } - } - deb_i2c("i2c_write ok\n"); - return 0; -} - -static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg, - u8 * data, int len) -{ - int ret, i; - u8 temp; - deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len); - for (i = 0; i < len; i++) { - temp = reg + i; - ret = - af9005_read_tuner_registers(d, - APO_REG_I2C_RW_SILICON_TUNER, - i2caddr, &temp, 1); - if (ret) { - deb_i2c("i2c_read failed\n"); - return ret; - } - data[i] = temp; - } - deb_i2c("i2c data read: "); - debug_dump(data, len, deb_i2c); - return 0; -} - -static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - /* only implements what the mt2060 module does, don't know how - to make it really generic */ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret; - u8 reg, addr; - u8 *value; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - if (num > 2) - warn("more than 2 i2c messages at a time is not handled yet. TODO."); - - if (num == 2) { - /* reads a single register */ - reg = *msg[0].buf; - addr = msg[0].addr; - value = msg[1].buf; - ret = af9005_i2c_read(d, addr, reg, value, 1); - if (ret == 0) - ret = 2; - } else { - /* write one or more registers */ - reg = msg[0].buf[0]; - addr = msg[0].addr; - value = &msg[0].buf[1]; - ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1); - if (ret == 0) - ret = 1; - } - - mutex_unlock(&d->i2c_mutex); - return ret; -} - -static u32 af9005_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm af9005_i2c_algo = { - .master_xfer = af9005_i2c_xfer, - .functionality = af9005_i2c_func, -}; - -int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf, - int wlen, u8 * rbuf, int rlen) -{ - struct af9005_device_state *st = d->priv; - - int ret, i, packet_len; - u8 buf[64]; - u8 ibuf[64]; - - if (wlen < 0) { - err("send command, wlen less than 0 bytes. Makes no sense."); - return -EINVAL; - } - if (wlen > 54) { - err("send command, wlen more than 54 bytes. Not supported."); - return -EINVAL; - } - if (rlen > 54) { - err("send command, rlen more than 54 bytes. Not supported."); - return -EINVAL; - } - packet_len = wlen + 5; - buf[0] = (u8) (packet_len & 0xff); - buf[1] = (u8) ((packet_len & 0xff00) >> 8); - - buf[2] = 0x26; /* packet type */ - buf[3] = wlen + 3; - buf[4] = st->sequence++; - buf[5] = command; - buf[6] = wlen; - for (i = 0; i < wlen; i++) - buf[7 + i] = wbuf[i]; - ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0); - if (ret) - return ret; - if (ibuf[2] != 0x27) { - err("send command, wrong reply code."); - return -EIO; - } - if (ibuf[4] != buf[4]) { - err("send command, wrong sequence in reply."); - return -EIO; - } - if (ibuf[5] != 0x01) { - err("send command, wrong status code in reply."); - return -EIO; - } - if (ibuf[6] != rlen) { - err("send command, invalid data length in reply."); - return -EIO; - } - for (i = 0; i < rlen; i++) - rbuf[i] = ibuf[i + 7]; - return 0; -} - -int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values, - int len) -{ - struct af9005_device_state *st = d->priv; - u8 obuf[16], ibuf[14]; - int ret, i; - - memset(obuf, 0, sizeof(obuf)); - memset(ibuf, 0, sizeof(ibuf)); - - obuf[0] = 14; /* length of rest of packet low */ - obuf[1] = 0; /* length of rest of packer high */ - - obuf[2] = 0x2a; /* read/write eeprom */ - - obuf[3] = 12; /* size */ - - obuf[4] = st->sequence++; - - obuf[5] = 0; /* read */ - - obuf[6] = len; - obuf[7] = address; - ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0); - if (ret) - return ret; - if (ibuf[2] != 0x2b) { - err("Read eeprom, invalid reply code"); - return -EIO; - } - if (ibuf[3] != 10) { - err("Read eeprom, invalid reply length"); - return -EIO; - } - if (ibuf[4] != obuf[4]) { - err("Read eeprom, wrong sequence in reply "); - return -EIO; - } - if (ibuf[5] != 1) { - err("Read eeprom, wrong status in reply "); - return -EIO; - } - for (i = 0; i < len; i++) { - values[i] = ibuf[6 + i]; - } - return 0; -} - -static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply) -{ - u8 buf[FW_BULKOUT_SIZE + 2]; - u16 checksum; - int act_len, i, ret; - memset(buf, 0, sizeof(buf)); - buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); - buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); - switch (type) { - case FW_CONFIG: - buf[2] = 0x11; - buf[3] = 0x04; - buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ - buf[5] = 0x03; - checksum = buf[4] + buf[5]; - buf[6] = (u8) ((checksum >> 8) & 0xff); - buf[7] = (u8) (checksum & 0xff); - break; - case FW_CONFIRM: - buf[2] = 0x11; - buf[3] = 0x04; - buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ - buf[5] = 0x01; - checksum = buf[4] + buf[5]; - buf[6] = (u8) ((checksum >> 8) & 0xff); - buf[7] = (u8) (checksum & 0xff); - break; - case FW_BOOT: - buf[2] = 0x10; - buf[3] = 0x08; - buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ - buf[5] = 0x97; - buf[6] = 0xaa; - buf[7] = 0x55; - buf[8] = 0xa5; - buf[9] = 0x5a; - checksum = 0; - for (i = 4; i <= 9; i++) - checksum += buf[i]; - buf[10] = (u8) ((checksum >> 8) & 0xff); - buf[11] = (u8) (checksum & 0xff); - break; - default: - err("boot packet invalid boot packet type"); - return -EINVAL; - } - deb_fw(">>> "); - debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); - - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x02), - buf, FW_BULKOUT_SIZE + 2, &act_len, 2000); - if (ret) - err("boot packet bulk message failed: %d (%d/%d)", ret, - FW_BULKOUT_SIZE + 2, act_len); - else - ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0; - if (ret) - return ret; - memset(buf, 0, 9); - ret = usb_bulk_msg(udev, - usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000); - if (ret) { - err("boot packet recv bulk message failed: %d", ret); - return ret; - } - deb_fw("<<< "); - debug_dump(buf, act_len, deb_fw); - checksum = 0; - switch (type) { - case FW_CONFIG: - if (buf[2] != 0x11) { - err("boot bad config header."); - return -EIO; - } - if (buf[3] != 0x05) { - err("boot bad config size."); - return -EIO; - } - if (buf[4] != 0x00) { - err("boot bad config sequence."); - return -EIO; - } - if (buf[5] != 0x04) { - err("boot bad config subtype."); - return -EIO; - } - for (i = 4; i <= 6; i++) - checksum += buf[i]; - if (buf[7] * 256 + buf[8] != checksum) { - err("boot bad config checksum."); - return -EIO; - } - *reply = buf[6]; - break; - case FW_CONFIRM: - if (buf[2] != 0x11) { - err("boot bad confirm header."); - return -EIO; - } - if (buf[3] != 0x05) { - err("boot bad confirm size."); - return -EIO; - } - if (buf[4] != 0x00) { - err("boot bad confirm sequence."); - return -EIO; - } - if (buf[5] != 0x02) { - err("boot bad confirm subtype."); - return -EIO; - } - for (i = 4; i <= 6; i++) - checksum += buf[i]; - if (buf[7] * 256 + buf[8] != checksum) { - err("boot bad confirm checksum."); - return -EIO; - } - *reply = buf[6]; - break; - case FW_BOOT: - if (buf[2] != 0x10) { - err("boot bad boot header."); - return -EIO; - } - if (buf[3] != 0x05) { - err("boot bad boot size."); - return -EIO; - } - if (buf[4] != 0x00) { - err("boot bad boot sequence."); - return -EIO; - } - if (buf[5] != 0x01) { - err("boot bad boot pattern 01."); - return -EIO; - } - if (buf[6] != 0x10) { - err("boot bad boot pattern 10."); - return -EIO; - } - for (i = 4; i <= 6; i++) - checksum += buf[i]; - if (buf[7] * 256 + buf[8] != checksum) { - err("boot bad boot checksum."); - return -EIO; - } - break; - - } - - return 0; -} - -static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) -{ - int i, packets, ret, act_len; - - u8 buf[FW_BULKOUT_SIZE + 2]; - u8 reply; - - ret = af9005_boot_packet(udev, FW_CONFIG, &reply); - if (ret) - return ret; - if (reply != 0x01) { - err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply); - return -EIO; - } - packets = fw->size / FW_BULKOUT_SIZE; - buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); - buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); - for (i = 0; i < packets; i++) { - memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE, - FW_BULKOUT_SIZE); - deb_fw(">>> "); - debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x02), - buf, FW_BULKOUT_SIZE + 2, &act_len, 1000); - if (ret) { - err("firmware download failed at packet %d with code %d", i, ret); - return ret; - } - } - ret = af9005_boot_packet(udev, FW_CONFIRM, &reply); - if (ret) - return ret; - if (reply != (u8) (packets & 0xff)) { - err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply); - return -EIO; - } - ret = af9005_boot_packet(udev, FW_BOOT, &reply); - if (ret) - return ret; - ret = af9005_boot_packet(udev, FW_CONFIG, &reply); - if (ret) - return ret; - if (reply != 0x02) { - err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply); - return -EIO; - } - - return 0; - -} - -int af9005_led_control(struct dvb_usb_device *d, int onoff) -{ - struct af9005_device_state *st = d->priv; - int temp, ret; - - if (onoff && dvb_usb_af9005_led) - temp = 1; - else - temp = 0; - if (st->led_state != temp) { - ret = - af9005_write_register_bits(d, xd_p_reg_top_locken1, - reg_top_locken1_pos, - reg_top_locken1_len, temp); - if (ret) - return ret; - ret = - af9005_write_register_bits(d, xd_p_reg_top_lock1, - reg_top_lock1_pos, - reg_top_lock1_len, temp); - if (ret) - return ret; - st->led_state = temp; - } - return 0; -} - -static int af9005_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 buf[8]; - int i; - - /* without these calls the first commands after downloading - the firmware fail. I put these calls here to simulate - what it is done in dvb-usb-init.c. - */ - struct usb_device *udev = adap->dev->udev; - usb_clear_halt(udev, usb_sndbulkpipe(udev, 2)); - usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1)); - if (dvb_usb_af9005_dump_eeprom) { - printk("EEPROM DUMP\n"); - for (i = 0; i < 255; i += 8) { - af9005_read_eeprom(adap->dev, i, buf, 8); - printk("ADDR %x ", i); - debug_dump(buf, 8, printk); - } - } - adap->fe = af9005_fe_attach(adap->dev); - return 0; -} - -static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state) -{ - struct af9005_device_state *st = d->priv; - int ret, len; - - u8 obuf[5]; - u8 ibuf[256]; - - *state = REMOTE_NO_KEY_PRESSED; - if (rc_decode == NULL) { - /* it shouldn't never come here */ - return 0; - } - /* deb_info("rc_query\n"); */ - obuf[0] = 3; /* rest of packet length low */ - obuf[1] = 0; /* rest of packet lentgh high */ - obuf[2] = 0x40; /* read remote */ - obuf[3] = 1; /* rest of packet length */ - obuf[4] = st->sequence++; /* sequence number */ - ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0); - if (ret) { - err("rc query failed"); - return ret; - } - if (ibuf[2] != 0x41) { - err("rc query bad header."); - return -EIO; - } - if (ibuf[4] != obuf[4]) { - err("rc query bad sequence."); - return -EIO; - } - len = ibuf[5]; - if (len > 246) { - err("rc query invalid length"); - return -EIO; - } - if (len > 0) { - deb_rc("rc data (%d) ", len); - debug_dump((ibuf + 6), len, deb_rc); - ret = rc_decode(d, &ibuf[6], len, event, state); - if (ret) { - err("rc_decode failed"); - return ret; - } else { - deb_rc("rc_decode state %x event %x\n", *state, *event); - if (*state == REMOTE_KEY_REPEAT) - *event = d->last_event; - } - } - return 0; -} - -static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - - return 0; -} - -static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - deb_info("pid filter control onoff %d\n", onoff); - if (onoff) { - ret = - af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); - if (ret) - return ret; - ret = - af9005_write_register_bits(adap->dev, - XD_MP2IF_DMX_CTRL, 1, 1, 1); - if (ret) - return ret; - ret = - af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); - } else - ret = - af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0); - if (ret) - return ret; - deb_info("pid filter control ok\n"); - return 0; -} - -static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index, - u16 pid, int onoff) -{ - u8 cmd = index & 0x1f; - int ret; - deb_info("set pid filter, index %d, pid %x, onoff %d\n", index, - pid, onoff); - if (onoff) { - /* cannot use it as pid_filter_ctrl since it has to be done - before setting the first pid */ - if (adap->feedcount == 1) { - deb_info("first pid set, enable pid table\n"); - ret = af9005_pid_filter_control(adap, onoff); - if (ret) - return ret; - } - ret = - af9005_write_ofdm_register(adap->dev, - XD_MP2IF_PID_DATA_L, - (u8) (pid & 0xff)); - if (ret) - return ret; - ret = - af9005_write_ofdm_register(adap->dev, - XD_MP2IF_PID_DATA_H, - (u8) (pid >> 8)); - if (ret) - return ret; - cmd |= 0x20 | 0x40; - } else { - if (adap->feedcount == 0) { - deb_info("last pid unset, disable pid table\n"); - ret = af9005_pid_filter_control(adap, onoff); - if (ret) - return ret; - } - } - ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd); - if (ret) - return ret; - deb_info("set pid ok\n"); - return 0; -} - -static int af9005_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - int ret; - u8 reply; - ret = af9005_boot_packet(udev, FW_CONFIG, &reply); - if (ret) - return ret; - deb_info("result of FW_CONFIG in identify state %d\n", reply); - if (reply == 0x01) - *cold = 1; - else if (reply == 0x02) - *cold = 0; - else - return -EIO; - deb_info("Identify state cold = %d\n", *cold); - return 0; -} - -static struct dvb_usb_device_properties af9005_properties; - -static int af9005_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &af9005_properties, - THIS_MODULE, NULL, adapter_nr); -} - -static struct usb_device_id af9005_usb_table[] = { - {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)}, - {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)}, - {0}, -}; - -MODULE_DEVICE_TABLE(usb, af9005_usb_table); - -static struct dvb_usb_device_properties af9005_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "af9005.fw", - .download_firmware = af9005_download_firmware, - .no_reconnect = 1, - - .size_of_priv = sizeof(struct af9005_device_state), - - .num_adapters = 1, - .adapter = { - { - .caps = - DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = af9005_pid_filter, - /* .pid_filter_ctrl = af9005_pid_filter_control, */ - .frontend_attach = af9005_frontend_attach, - /* .tuner_attach = af9005_tuner_attach, */ - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 4096, /* actual size seen is 3948 */ - } - } - }, - } - }, - .power_ctrl = af9005_power_ctrl, - .identify_state = af9005_identify_state, - - .i2c_algo = &af9005_i2c_algo, - - .rc.legacy = { - .rc_interval = 200, - .rc_map_table = NULL, - .rc_map_size = 0, - .rc_query = af9005_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 2, - .generic_bulk_ctrl_endpoint_response = 1, - - .num_device_descs = 3, - .devices = { - {.name = "Afatech DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[0], NULL}, - .warm_ids = {NULL}, - }, - {.name = "TerraTec Cinergy T USB XE", - .cold_ids = {&af9005_usb_table[1], NULL}, - .warm_ids = {NULL}, - }, - {.name = "Ansonic DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[2], NULL}, - .warm_ids = {NULL}, - }, - {NULL}, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver af9005_usb_driver = { - .name = "dvb_usb_af9005", - .probe = af9005_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = af9005_usb_table, -}; - -/* module stuff */ -static int __init af9005_usb_module_init(void) -{ - int result; - if ((result = usb_register(&af9005_usb_driver))) { - err("usb_register failed. (%d)", result); - return result; - } - rc_decode = symbol_request(af9005_rc_decode); - rc_keys = symbol_request(rc_map_af9005_table); - rc_keys_size = symbol_request(rc_map_af9005_table_size); - if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) { - err("af9005_rc_decode function not found, disabling remote"); - af9005_properties.rc.legacy.rc_query = NULL; - } else { - af9005_properties.rc.legacy.rc_map_table = rc_keys; - af9005_properties.rc.legacy.rc_map_size = *rc_keys_size; - } - - return 0; -} - -static void __exit af9005_usb_module_exit(void) -{ - /* release rc decode symbols */ - if (rc_decode != NULL) - symbol_put(af9005_rc_decode); - if (rc_keys != NULL) - symbol_put(rc_map_af9005_table); - if (rc_keys_size != NULL) - symbol_put(rc_map_af9005_table_size); - /* deregister this driver from the USB subsystem */ - usb_deregister(&af9005_usb_driver); -} - -module_init(af9005_usb_module_init); -module_exit(af9005_usb_module_exit); - -MODULE_AUTHOR("Luca Olivetti "); -MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-fe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1488 +0,0 @@ -/* Frontend part of the Linux driver for the Afatech 9005 - * USB1.1 DVB-T receiver. - * - * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) - * - * Thanks to Afatech who kindly provided information. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "af9005.h" -#include "af9005-script.h" -#include "mt2060.h" -#include "qt1010.h" -#include - -struct af9005_fe_state { - struct dvb_usb_device *d; - fe_status_t stat; - - /* retraining parameters */ - u32 original_fcw; - u16 original_rf_top; - u16 original_if_top; - u16 original_if_min; - u16 original_aci0_if_top; - u16 original_aci1_if_top; - u16 original_aci0_if_min; - u8 original_if_unplug_th; - u8 original_rf_unplug_th; - u8 original_dtop_if_unplug_th; - u8 original_dtop_rf_unplug_th; - - /* statistics */ - u32 pre_vit_error_count; - u32 pre_vit_bit_count; - u32 ber; - u32 post_vit_error_count; - u32 post_vit_bit_count; - u32 unc; - u16 abort_count; - - int opened; - int strong; - unsigned long next_status_check; - struct dvb_frontend frontend; -}; - -static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi, - u16 reglo, u8 pos, u8 len, u16 value) -{ - int ret; - u8 temp; - - if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff)))) - return ret; - temp = (u8) ((value & 0x0300) >> 8); - return af9005_write_register_bits(d, reghi, pos, len, - (u8) ((value & 0x300) >> 8)); -} - -static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi, - u16 reglo, u8 pos, u8 len, u16 * value) -{ - int ret; - u8 temp0, temp1; - - if ((ret = af9005_read_ofdm_register(d, reglo, &temp0))) - return ret; - if ((ret = af9005_read_ofdm_register(d, reghi, &temp1))) - return ret; - switch (pos) { - case 0: - *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0; - break; - case 2: - *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0; - break; - case 4: - *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0; - break; - case 6: - *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0; - break; - default: - err("invalid pos in read word agc"); - return -EINVAL; - } - return 0; - -} - -static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u8 temp; - - *available = false; - - ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, - fec_vtb_rsd_mon_en_pos, - fec_vtb_rsd_mon_en_len, &temp); - if (ret) - return ret; - if (temp & 1) { - ret = - af9005_read_register_bits(state->d, - xd_p_reg_ofsm_read_rbc_en, - reg_ofsm_read_rbc_en_pos, - reg_ofsm_read_rbc_en_len, &temp); - if (ret) - return ret; - if ((temp & 1) == 0) - *available = true; - - } - return 0; -} - -static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe, - u32 * post_err_count, - u32 * post_cw_count, - u16 * abort_count) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u32 err_count; - u32 cw_count; - u8 temp, temp0, temp1, temp2; - u16 loc_abort_count; - - *post_err_count = 0; - *post_cw_count = 0; - - /* check if error bit count is ready */ - ret = - af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy, - fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len, - &temp); - if (ret) - return ret; - if (!temp) { - deb_info("rsd counter not ready\n"); - return 100; - } - /* get abort count */ - ret = - af9005_read_ofdm_register(state->d, - xd_r_fec_rsd_abort_packet_cnt_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, - xd_r_fec_rsd_abort_packet_cnt_15_8, - &temp1); - if (ret) - return ret; - loc_abort_count = ((u16) temp1 << 8) + temp0; - - /* get error count */ - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8, - &temp1); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16, - &temp2); - if (ret) - return ret; - err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; - *post_err_count = err_count - (u32) loc_abort_count *8 * 8; - - /* get RSD packet number */ - ret = - af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, - &temp1); - if (ret) - return ret; - cw_count = ((u32) temp1 << 8) + temp0; - if (cw_count == 0) { - err("wrong RSD packet count"); - return -EIO; - } - deb_info("POST abort count %d err count %d rsd packets %d\n", - loc_abort_count, err_count, cw_count); - *post_cw_count = cw_count - (u32) loc_abort_count; - *abort_count = loc_abort_count; - return 0; - -} - -static int af9005_get_post_vit_ber(struct dvb_frontend *fe, - u32 * post_err_count, u32 * post_cw_count, - u16 * abort_count) -{ - u32 loc_cw_count = 0, loc_err_count; - u16 loc_abort_count = 0; - int ret; - - ret = - af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count, - &loc_abort_count); - if (ret) - return ret; - *post_err_count = loc_err_count; - *post_cw_count = loc_cw_count * 204 * 8; - *abort_count = loc_abort_count; - - return 0; -} - -static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, - u32 * pre_err_count, - u32 * pre_bit_count) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - u8 temp, temp0, temp1, temp2; - u32 super_frame_count, x, bits; - int ret; - - ret = - af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy, - fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len, - &temp); - if (ret) - return ret; - if (!temp) { - deb_info("viterbi counter not ready\n"); - return 101; /* ERR_APO_VTB_COUNTER_NOT_READY; */ - } - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8, - &temp1); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16, - &temp2); - if (ret) - return ret; - *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; - - ret = - af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, - &temp0); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, - &temp1); - if (ret) - return ret; - super_frame_count = ((u32) temp1 << 8) + temp0; - if (super_frame_count == 0) { - deb_info("super frame count 0\n"); - return 102; - } - - /* read fft mode */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, - reg_tpsd_txmod_pos, reg_tpsd_txmod_len, - &temp); - if (ret) - return ret; - if (temp == 0) { - /* 2K */ - x = 1512; - } else if (temp == 1) { - /* 8k */ - x = 6048; - } else { - err("Invalid fft mode"); - return -EINVAL; - } - - /* read constellation mode */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, - reg_tpsd_const_pos, reg_tpsd_const_len, - &temp); - if (ret) - return ret; - switch (temp) { - case 0: /* QPSK */ - bits = 2; - break; - case 1: /* QAM_16 */ - bits = 4; - break; - case 2: /* QAM_64 */ - bits = 6; - break; - default: - err("invalid constellation mode"); - return -EINVAL; - } - *pre_bit_count = super_frame_count * 68 * 4 * x * bits; - deb_info("PRE err count %d frame count %d bit count %d\n", - *pre_err_count, super_frame_count, *pre_bit_count); - return 0; -} - -static int af9005_reset_pre_viterbi(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - - /* set super frame count to 1 */ - ret = - af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, - 1 & 0xff); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, - 1 >> 8); - if (ret) - return ret; - /* reset pre viterbi error count */ - ret = - af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst, - fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len, - 1); - - return ret; -} - -static int af9005_reset_post_viterbi(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - - /* set packet unit */ - ret = - af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, - 10000 & 0xff); - if (ret) - return ret; - ret = - af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, - 10000 >> 8); - if (ret) - return ret; - /* reset post viterbi error count */ - ret = - af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst, - fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len, - 1); - - return ret; -} - -static int af9005_get_statistic(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret, fecavailable; - u64 numerator, denominator; - - deb_info("GET STATISTIC\n"); - ret = af9005_is_fecmon_available(fe, &fecavailable); - if (ret) - return ret; - if (!fecavailable) { - deb_info("fecmon not available\n"); - return 0; - } - - ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count, - &state->pre_vit_bit_count); - if (ret == 0) { - af9005_reset_pre_viterbi(fe); - if (state->pre_vit_bit_count > 0) { - /* according to v 0.0.4 of the dvb api ber should be a multiple - of 10E-9 so we have to multiply the error count by - 10E9=1000000000 */ - numerator = - (u64) state->pre_vit_error_count * (u64) 1000000000; - denominator = (u64) state->pre_vit_bit_count; - state->ber = do_div(numerator, denominator); - } else { - state->ber = 0xffffffff; - } - } - - ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count, - &state->post_vit_bit_count, - &state->abort_count); - if (ret == 0) { - ret = af9005_reset_post_viterbi(fe); - state->unc += state->abort_count; - if (ret) - return ret; - } - return 0; -} - -static int af9005_fe_refresh_state(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - if (time_after(jiffies, state->next_status_check)) { - deb_info("REFRESH STATE\n"); - - /* statistics */ - if (af9005_get_statistic(fe)) - err("get_statistic_failed"); - state->next_status_check = jiffies + 250 * HZ / 1000; - } - return 0; -} - -static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - u8 temp; - int ret; - - if (fe->ops.tuner_ops.release == NULL) - return -ENODEV; - - *stat = 0; - ret = af9005_read_register_bits(state->d, xd_p_agc_lock, - agc_lock_pos, agc_lock_len, &temp); - if (ret) - return ret; - if (temp) - *stat |= FE_HAS_SIGNAL; - - ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock, - fd_tpsd_lock_pos, fd_tpsd_lock_len, - &temp); - if (ret) - return ret; - if (temp) - *stat |= FE_HAS_CARRIER; - - ret = af9005_read_register_bits(state->d, - xd_r_mp2if_sync_byte_locked, - mp2if_sync_byte_locked_pos, - mp2if_sync_byte_locked_pos, &temp); - if (ret) - return ret; - if (temp) - *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK; - if (state->opened) - af9005_led_control(state->d, *stat & FE_HAS_LOCK); - - ret = - af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected, - reg_strong_sginal_detected_pos, - reg_strong_sginal_detected_len, &temp); - if (ret) - return ret; - if (temp != state->strong) { - deb_info("adjust for strong signal %d\n", temp); - state->strong = temp; - } - return 0; -} - -static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - if (fe->ops.tuner_ops.release == NULL) - return -ENODEV; - af9005_fe_refresh_state(fe); - *ber = state->ber; - return 0; -} - -static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - if (fe->ops.tuner_ops.release == NULL) - return -ENODEV; - af9005_fe_refresh_state(fe); - *unc = state->unc; - return 0; -} - -static int af9005_fe_read_signal_strength(struct dvb_frontend *fe, - u16 * strength) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u8 if_gain, rf_gain; - - if (fe->ops.tuner_ops.release == NULL) - return -ENODEV; - ret = - af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain, - &rf_gain); - if (ret) - return ret; - ret = - af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain, - &if_gain); - if (ret) - return ret; - /* this value has no real meaning, but i don't have the tables that relate - the rf and if gain with the dbm, so I just scale the value */ - *strength = (512 - rf_gain - if_gain) << 7; - return 0; -} - -static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr) -{ - /* the snr can be derived from the ber and the constellation - but I don't think this kind of complex calculations belong - in the driver. I may be wrong.... */ - return -ENOSYS; -} - -static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) -{ - u8 temp0, temp1, temp2, temp3, buf[4]; - int ret; - u32 NS_coeff1_2048Nu; - u32 NS_coeff1_8191Nu; - u32 NS_coeff1_8192Nu; - u32 NS_coeff1_8193Nu; - u32 NS_coeff2_2k; - u32 NS_coeff2_8k; - - switch (bw) { - case BANDWIDTH_6_MHZ: - NS_coeff1_2048Nu = 0x2ADB6DC; - NS_coeff1_8191Nu = 0xAB7313; - NS_coeff1_8192Nu = 0xAB6DB7; - NS_coeff1_8193Nu = 0xAB685C; - NS_coeff2_2k = 0x156DB6E; - NS_coeff2_8k = 0x55B6DC; - break; - - case BANDWIDTH_7_MHZ: - NS_coeff1_2048Nu = 0x3200001; - NS_coeff1_8191Nu = 0xC80640; - NS_coeff1_8192Nu = 0xC80000; - NS_coeff1_8193Nu = 0xC7F9C0; - NS_coeff2_2k = 0x1900000; - NS_coeff2_8k = 0x640000; - break; - - case BANDWIDTH_8_MHZ: - NS_coeff1_2048Nu = 0x3924926; - NS_coeff1_8191Nu = 0xE4996E; - NS_coeff1_8192Nu = 0xE49249; - NS_coeff1_8193Nu = 0xE48B25; - NS_coeff2_2k = 0x1C92493; - NS_coeff2_8k = 0x724925; - break; - default: - err("Invalid bandwith %d.", bw); - return -EINVAL; - } - - /* - * write NS_coeff1_2048Nu - */ - - temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF); - temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8); - temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16); - temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - /* cfoe_NS_2k_coeff1_25_24 */ - ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]); - if (ret) - return ret; - - /* cfoe_NS_2k_coeff1_23_16 */ - ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]); - if (ret) - return ret; - - /* cfoe_NS_2k_coeff1_15_8 */ - ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]); - if (ret) - return ret; - - /* cfoe_NS_2k_coeff1_7_0 */ - ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff2_2k - */ - - temp0 = (u8) ((NS_coeff2_2k & 0x0000003F)); - temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6); - temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14); - temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff1_8191Nu - */ - - temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF)); - temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8); - temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16); - temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff1_8192Nu - */ - - temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF); - temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8); - temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16); - temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff1_8193Nu - */ - - temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF)); - temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8); - temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16); - temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]); - if (ret) - return ret; - - /* - * write NS_coeff2_8k - */ - - temp0 = (u8) ((NS_coeff2_8k & 0x0000003F)); - temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6); - temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14); - temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22); - - /* big endian to make 8051 happy */ - buf[0] = temp3; - buf[1] = temp2; - buf[2] = temp1; - buf[3] = temp0; - - ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]); - if (ret) - return ret; - - ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]); - return ret; - -} - -static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw) -{ - u8 temp; - switch (bw) { - case BANDWIDTH_6_MHZ: - temp = 0; - break; - case BANDWIDTH_7_MHZ: - temp = 1; - break; - case BANDWIDTH_8_MHZ: - temp = 2; - break; - default: - err("Invalid bandwith %d.", bw); - return -EINVAL; - } - return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos, - reg_bw_len, temp); -} - -static int af9005_fe_power(struct dvb_frontend *fe, int on) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - u8 temp = on; - int ret; - deb_info("power %s tuner\n", on ? "on" : "off"); - ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); - return ret; -} - -static struct mt2060_config af9005_mt2060_config = { - 0xC0 -}; - -static struct qt1010_config af9005_qt1010_config = { - 0xC4 -}; - -static int af9005_fe_init(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - struct dvb_usb_adapter *adap = fe->dvb->priv; - int ret, i, scriptlen; - u8 temp, temp0 = 0, temp1 = 0, temp2 = 0; - u8 buf[2]; - u16 if1; - - deb_info("in af9005_fe_init\n"); - - /* reset */ - deb_info("reset\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en, - 4, 1, 0x01))) - return ret; - if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0))) - return ret; - /* clear ofdm reset */ - deb_info("clear ofdm reset\n"); - for (i = 0; i < 150; i++) { - if ((ret = - af9005_read_ofdm_register(state->d, - xd_I2C_reg_ofdm_rst, &temp))) - return ret; - if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos)) - break; - msleep(10); - } - if (i == 150) - return -ETIMEDOUT; - - /*FIXME in the dump - write B200 A9 - write xd_g_reg_ofsm_clk 7 - read eepr c6 (2) - read eepr c7 (2) - misc ctrl 3 -> 1 - read eepr ca (6) - write xd_g_reg_ofsm_clk 0 - write B200 a1 - */ - ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07); - if (ret) - return ret; - temp = 0x01; - ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1); - if (ret) - return ret; - - temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos; - if ((ret = - af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, - reg_ofdm_rst_pos, reg_ofdm_rst_len, 1))) - return ret; - ret = af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, - reg_ofdm_rst_pos, reg_ofdm_rst_len, 0); - - if (ret) - return ret; - /* don't know what register aefc is, but this is what the windows driver does */ - ret = af9005_write_ofdm_register(state->d, 0xaefc, 0); - if (ret) - return ret; - - /* set stand alone chip */ - deb_info("set stand alone chip\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone, - reg_dca_stand_alone_pos, - reg_dca_stand_alone_len, 1))) - return ret; - - /* set dca upper & lower chip */ - deb_info("set dca upper & lower chip\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip, - reg_dca_upper_chip_pos, - reg_dca_upper_chip_len, 0))) - return ret; - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip, - reg_dca_lower_chip_pos, - reg_dca_lower_chip_len, 0))) - return ret; - - /* set 2wire master clock to 0x14 (for 60KHz) */ - deb_info("set 2wire master clock to 0x14 (for 60KHz)\n"); - if ((ret = - af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14))) - return ret; - - /* clear dca enable chip */ - deb_info("clear dca enable chip\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_en, - reg_dca_en_pos, reg_dca_en_len, 0))) - return ret; - /* FIXME these are register bits, but I don't know which ones */ - ret = af9005_write_ofdm_register(state->d, 0xa16c, 1); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0); - if (ret) - return ret; - - /* init other parameters: program cfoe and select bandwith */ - deb_info("program cfoe\n"); - if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ))) - return ret; - /* set read-update bit for constellation */ - deb_info("set read-update bit for constellation\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_feq_read_update, - reg_feq_read_update_pos, - reg_feq_read_update_len, 1))) - return ret; - - /* sample code has a set MPEG TS code here - but sniffing reveals that it doesn't do it */ - - /* set read-update bit to 1 for DCA constellation */ - deb_info("set read-update bit 1 for DCA constellation\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_reg_dca_read_update, - reg_dca_read_update_pos, - reg_dca_read_update_len, 1))) - return ret; - - /* enable fec monitor */ - deb_info("enable fec monitor\n"); - if ((ret = - af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, - fec_vtb_rsd_mon_en_pos, - fec_vtb_rsd_mon_en_len, 1))) - return ret; - - /* FIXME should be register bits, I don't know which ones */ - ret = af9005_write_ofdm_register(state->d, 0xa601, 0); - - /* set api_retrain_never_freeze */ - deb_info("set api_retrain_never_freeze\n"); - if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01))) - return ret; - - /* load init script */ - deb_info("load init script\n"); - scriptlen = sizeof(script) / sizeof(RegDesc); - for (i = 0; i < scriptlen; i++) { - if ((ret = - af9005_write_register_bits(state->d, script[i].reg, - script[i].pos, - script[i].len, script[i].val))) - return ret; - /* save 3 bytes of original fcw */ - if (script[i].reg == 0xae18) - temp2 = script[i].val; - if (script[i].reg == 0xae19) - temp1 = script[i].val; - if (script[i].reg == 0xae1a) - temp0 = script[i].val; - - /* save original unplug threshold */ - if (script[i].reg == xd_p_reg_unplug_th) - state->original_if_unplug_th = script[i].val; - if (script[i].reg == xd_p_reg_unplug_rf_gain_th) - state->original_rf_unplug_th = script[i].val; - if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th) - state->original_dtop_if_unplug_th = script[i].val; - if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th) - state->original_dtop_rf_unplug_th = script[i].val; - - } - state->original_fcw = - ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0; - - - /* save original TOPs */ - deb_info("save original TOPs\n"); - - /* RF TOP */ - ret = - af9005_read_word_agc(state->d, - xd_p_reg_aagc_rf_top_numerator_9_8, - xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, - &state->original_rf_top); - if (ret) - return ret; - - /* IF TOP */ - ret = - af9005_read_word_agc(state->d, - xd_p_reg_aagc_if_top_numerator_9_8, - xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, - &state->original_if_top); - if (ret) - return ret; - - /* ACI 0 IF TOP */ - ret = - af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, - &state->original_aci0_if_top); - if (ret) - return ret; - - /* ACI 1 IF TOP */ - ret = - af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, - &state->original_aci1_if_top); - if (ret) - return ret; - - /* attach tuner and init */ - if (fe->ops.tuner_ops.release == NULL) { - /* read tuner and board id from eeprom */ - ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2); - if (ret) { - err("Impossible to read EEPROM\n"); - return ret; - } - deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]); - switch (buf[0]) { - case 2: /* MT2060 */ - /* read if1 from eeprom */ - ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2); - if (ret) { - err("Impossible to read EEPROM\n"); - return ret; - } - if1 = (u16) (buf[0] << 8) + buf[1]; - if (dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap, - &af9005_mt2060_config, if1) == NULL) { - deb_info("MT2060 attach failed\n"); - return -ENODEV; - } - break; - case 3: /* QT1010 */ - case 9: /* QT1010B */ - if (dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap, - &af9005_qt1010_config) ==NULL) { - deb_info("QT1010 attach failed\n"); - return -ENODEV; - } - break; - default: - err("Unsupported tuner type %d", buf[0]); - return -ENODEV; - } - ret = fe->ops.tuner_ops.init(fe); - if (ret) - return ret; - } - - deb_info("profit!\n"); - return 0; -} - -static int af9005_fe_sleep(struct dvb_frontend *fe) -{ - return af9005_fe_power(fe, 0); -} - -static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - - if (acquire) { - state->opened++; - } else { - - state->opened--; - if (!state->opened) - af9005_led_control(state->d, 0); - } - return 0; -} - -static int af9005_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u8 temp, temp0, temp1, temp2; - - deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency, - fep->u.ofdm.bandwidth); - if (fe->ops.tuner_ops.release == NULL) { - err("Tuner not attached"); - return -ENODEV; - } - - deb_info("turn off led\n"); - /* not in the log */ - ret = af9005_led_control(state->d, 0); - if (ret) - return ret; - /* not sure about the bits */ - ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0); - if (ret) - return ret; - - /* set FCW to default value */ - deb_info("set FCW to default value\n"); - temp0 = (u8) (state->original_fcw & 0x000000ff); - temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8); - temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16); - ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, 0xae19, temp1); - if (ret) - return ret; - ret = af9005_write_ofdm_register(state->d, 0xae18, temp2); - if (ret) - return ret; - - /* restore original TOPs */ - deb_info("restore original TOPs\n"); - ret = - af9005_write_word_agc(state->d, - xd_p_reg_aagc_rf_top_numerator_9_8, - xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, - state->original_rf_top); - if (ret) - return ret; - ret = - af9005_write_word_agc(state->d, - xd_p_reg_aagc_if_top_numerator_9_8, - xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, - state->original_if_top); - if (ret) - return ret; - ret = - af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, - state->original_aci0_if_top); - if (ret) - return ret; - ret = - af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, - state->original_aci1_if_top); - if (ret) - return ret; - - /* select bandwith */ - deb_info("select bandwidth"); - ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth); - if (ret) - return ret; - ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth); - if (ret) - return ret; - - /* clear easy mode flag */ - deb_info("clear easy mode flag\n"); - ret = af9005_write_ofdm_register(state->d, 0xaefd, 0); - if (ret) - return ret; - - /* set unplug threshold to original value */ - deb_info("set unplug threshold to original value\n"); - ret = - af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th, - state->original_if_unplug_th); - if (ret) - return ret; - /* set tuner */ - deb_info("set tuner\n"); - ret = fe->ops.tuner_ops.set_params(fe, fep); - if (ret) - return ret; - - /* trigger ofsm */ - deb_info("trigger ofsm\n"); - temp = 0; - ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1); - if (ret) - return ret; - - /* clear retrain and freeze flag */ - deb_info("clear retrain and freeze flag\n"); - ret = - af9005_write_register_bits(state->d, - xd_p_reg_api_retrain_request, - reg_api_retrain_request_pos, 2, 0); - if (ret) - return ret; - - /* reset pre viterbi and post viterbi registers and statistics */ - af9005_reset_pre_viterbi(fe); - af9005_reset_post_viterbi(fe); - state->pre_vit_error_count = 0; - state->pre_vit_bit_count = 0; - state->ber = 0; - state->post_vit_error_count = 0; - /* state->unc = 0; commented out since it should be ever increasing */ - state->abort_count = 0; - - state->next_status_check = jiffies; - state->strong = -1; - - return 0; -} - -static int af9005_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct af9005_fe_state *state = fe->demodulator_priv; - int ret; - u8 temp; - - /* mode */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, - reg_tpsd_const_pos, reg_tpsd_const_len, - &temp); - if (ret) - return ret; - deb_info("===== fe_get_frontend ==============\n"); - deb_info("CONSTELLATION "); - switch (temp) { - case 0: - fep->u.ofdm.constellation = QPSK; - deb_info("QPSK\n"); - break; - case 1: - fep->u.ofdm.constellation = QAM_16; - deb_info("QAM_16\n"); - break; - case 2: - fep->u.ofdm.constellation = QAM_64; - deb_info("QAM_64\n"); - break; - } - - /* tps hierarchy and alpha value */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier, - reg_tpsd_hier_pos, reg_tpsd_hier_len, - &temp); - if (ret) - return ret; - deb_info("HIERARCHY "); - switch (temp) { - case 0: - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; - deb_info("NONE\n"); - break; - case 1: - fep->u.ofdm.hierarchy_information = HIERARCHY_1; - deb_info("1\n"); - break; - case 2: - fep->u.ofdm.hierarchy_information = HIERARCHY_2; - deb_info("2\n"); - break; - case 3: - fep->u.ofdm.hierarchy_information = HIERARCHY_4; - deb_info("4\n"); - break; - } - - /* high/low priority */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_dec_pri, - reg_dec_pri_pos, reg_dec_pri_len, &temp); - if (ret) - return ret; - /* if temp is set = high priority */ - deb_info("PRIORITY %s\n", temp ? "high" : "low"); - - /* high coderate */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr, - reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len, - &temp); - if (ret) - return ret; - deb_info("CODERATE HP "); - switch (temp) { - case 0: - fep->u.ofdm.code_rate_HP = FEC_1_2; - deb_info("FEC_1_2\n"); - break; - case 1: - fep->u.ofdm.code_rate_HP = FEC_2_3; - deb_info("FEC_2_3\n"); - break; - case 2: - fep->u.ofdm.code_rate_HP = FEC_3_4; - deb_info("FEC_3_4\n"); - break; - case 3: - fep->u.ofdm.code_rate_HP = FEC_5_6; - deb_info("FEC_5_6\n"); - break; - case 4: - fep->u.ofdm.code_rate_HP = FEC_7_8; - deb_info("FEC_7_8\n"); - break; - } - - /* low coderate */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr, - reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len, - &temp); - if (ret) - return ret; - deb_info("CODERATE LP "); - switch (temp) { - case 0: - fep->u.ofdm.code_rate_LP = FEC_1_2; - deb_info("FEC_1_2\n"); - break; - case 1: - fep->u.ofdm.code_rate_LP = FEC_2_3; - deb_info("FEC_2_3\n"); - break; - case 2: - fep->u.ofdm.code_rate_LP = FEC_3_4; - deb_info("FEC_3_4\n"); - break; - case 3: - fep->u.ofdm.code_rate_LP = FEC_5_6; - deb_info("FEC_5_6\n"); - break; - case 4: - fep->u.ofdm.code_rate_LP = FEC_7_8; - deb_info("FEC_7_8\n"); - break; - } - - /* guard interval */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi, - reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp); - if (ret) - return ret; - deb_info("GUARD INTERVAL "); - switch (temp) { - case 0: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - deb_info("1_32\n"); - break; - case 1: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; - deb_info("1_16\n"); - break; - case 2: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; - deb_info("1_8\n"); - break; - case 3: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; - deb_info("1_4\n"); - break; - } - - /* fft */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, - reg_tpsd_txmod_pos, reg_tpsd_txmod_len, - &temp); - if (ret) - return ret; - deb_info("TRANSMISSION MODE "); - switch (temp) { - case 0: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - deb_info("2K\n"); - break; - case 1: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - deb_info("8K\n"); - break; - } - - /* bandwidth */ - ret = - af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos, - reg_bw_len, &temp); - deb_info("BANDWIDTH "); - switch (temp) { - case 0: - fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - deb_info("6\n"); - break; - case 1: - fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - deb_info("7\n"); - break; - case 2: - fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - deb_info("8\n"); - break; - } - return 0; -} - -static void af9005_fe_release(struct dvb_frontend *fe) -{ - struct af9005_fe_state *state = - (struct af9005_fe_state *)fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops af9005_fe_ops; - -struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d) -{ - struct af9005_fe_state *state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL); - if (state == NULL) - goto error; - - deb_info("attaching frontend af9005\n"); - - state->d = d; - state->opened = 0; - - memcpy(&state->frontend.ops, &af9005_fe_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - return &state->frontend; - error: - return NULL; -} - -static struct dvb_frontend_ops af9005_fe_ops = { - .info = { - .name = "AF9005 USB DVB-T", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = af9005_fe_release, - - .init = af9005_fe_init, - .sleep = af9005_fe_sleep, - .ts_bus_ctrl = af9005_ts_bus_ctrl, - - .set_frontend = af9005_fe_set_frontend, - .get_frontend = af9005_fe_get_frontend, - - .read_status = af9005_fe_read_status, - .read_ber = af9005_fe_read_ber, - .read_signal_strength = af9005_fe_read_signal_strength, - .read_snr = af9005_fe_read_snr, - .read_ucblocks = af9005_fe_read_unc_blocks, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,3496 +0,0 @@ -/* Common header-file of the Linux driver for the Afatech 9005 - * USB1.1 DVB-T receiver. - * - * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) - * - * Thanks to Afatech who kindly provided information. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_AF9005_H_ -#define _DVB_USB_AF9005_H_ - -#define DVB_USB_LOG_PREFIX "af9005" -#include "dvb-usb.h" - -extern int dvb_usb_af9005_debug; -#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_af9005_debug,0x04,args) -#define deb_reg(args...) dprintk(dvb_usb_af9005_debug,0x08,args) -#define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args) -#define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args) - -extern int dvb_usb_af9005_led; - -/* firmware */ -#define FW_BULKOUT_SIZE 250 -enum { - FW_CONFIG, - FW_CONFIRM, - FW_BOOT -}; - -/* af9005 commands */ -#define AF9005_OFDM_REG 0 -#define AF9005_TUNER_REG 1 - -#define AF9005_REGISTER_RW 0x20 -#define AF9005_REGISTER_RW_ACK 0x21 - -#define AF9005_CMD_OFDM_REG 0x00 -#define AF9005_CMD_TUNER 0x80 -#define AF9005_CMD_BURST 0x02 -#define AF9005_CMD_AUTOINC 0x04 -#define AF9005_CMD_READ 0x00 -#define AF9005_CMD_WRITE 0x01 - -/* af9005 registers */ -#define APO_REG_RESET 0xAEFF - -#define APO_REG_I2C_RW_CAN_TUNER 0xF000 -#define APO_REG_I2C_RW_SILICON_TUNER 0xF001 -#define APO_REG_GPIO_RW_SILICON_TUNER 0xFFFE /* also for OFSM */ -#define APO_REG_TRIGGER_OFSM 0xFFFF /* also for OFSM */ - -/*********************************************************************** - * Apollo Registers from VLSI * - ***********************************************************************/ -#define xd_p_reg_aagc_inverted_agc 0xA000 -#define reg_aagc_inverted_agc_pos 0 -#define reg_aagc_inverted_agc_len 1 -#define reg_aagc_inverted_agc_lsb 0 -#define xd_p_reg_aagc_sign_only 0xA000 -#define reg_aagc_sign_only_pos 1 -#define reg_aagc_sign_only_len 1 -#define reg_aagc_sign_only_lsb 0 -#define xd_p_reg_aagc_slow_adc_en 0xA000 -#define reg_aagc_slow_adc_en_pos 2 -#define reg_aagc_slow_adc_en_len 1 -#define reg_aagc_slow_adc_en_lsb 0 -#define xd_p_reg_aagc_slow_adc_scale 0xA000 -#define reg_aagc_slow_adc_scale_pos 3 -#define reg_aagc_slow_adc_scale_len 5 -#define reg_aagc_slow_adc_scale_lsb 0 -#define xd_p_reg_aagc_check_slow_adc_lock 0xA001 -#define reg_aagc_check_slow_adc_lock_pos 0 -#define reg_aagc_check_slow_adc_lock_len 1 -#define reg_aagc_check_slow_adc_lock_lsb 0 -#define xd_p_reg_aagc_init_control 0xA001 -#define reg_aagc_init_control_pos 1 -#define reg_aagc_init_control_len 1 -#define reg_aagc_init_control_lsb 0 -#define xd_p_reg_aagc_total_gain_sel 0xA001 -#define reg_aagc_total_gain_sel_pos 2 -#define reg_aagc_total_gain_sel_len 2 -#define reg_aagc_total_gain_sel_lsb 0 -#define xd_p_reg_aagc_out_inv 0xA001 -#define reg_aagc_out_inv_pos 5 -#define reg_aagc_out_inv_len 1 -#define reg_aagc_out_inv_lsb 0 -#define xd_p_reg_aagc_int_en 0xA001 -#define reg_aagc_int_en_pos 6 -#define reg_aagc_int_en_len 1 -#define reg_aagc_int_en_lsb 0 -#define xd_p_reg_aagc_lock_change_flag 0xA001 -#define reg_aagc_lock_change_flag_pos 7 -#define reg_aagc_lock_change_flag_len 1 -#define reg_aagc_lock_change_flag_lsb 0 -#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002 -#define reg_aagc_rf_loop_bw_scale_acquire_pos 0 -#define reg_aagc_rf_loop_bw_scale_acquire_len 5 -#define reg_aagc_rf_loop_bw_scale_acquire_lsb 0 -#define xd_p_reg_aagc_rf_loop_bw_scale_track 0xA003 -#define reg_aagc_rf_loop_bw_scale_track_pos 0 -#define reg_aagc_rf_loop_bw_scale_track_len 5 -#define reg_aagc_rf_loop_bw_scale_track_lsb 0 -#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004 -#define reg_aagc_if_loop_bw_scale_acquire_pos 0 -#define reg_aagc_if_loop_bw_scale_acquire_len 5 -#define reg_aagc_if_loop_bw_scale_acquire_lsb 0 -#define xd_p_reg_aagc_if_loop_bw_scale_track 0xA005 -#define reg_aagc_if_loop_bw_scale_track_pos 0 -#define reg_aagc_if_loop_bw_scale_track_len 5 -#define reg_aagc_if_loop_bw_scale_track_lsb 0 -#define xd_p_reg_aagc_max_rf_agc_7_0 0xA006 -#define reg_aagc_max_rf_agc_7_0_pos 0 -#define reg_aagc_max_rf_agc_7_0_len 8 -#define reg_aagc_max_rf_agc_7_0_lsb 0 -#define xd_p_reg_aagc_max_rf_agc_9_8 0xA007 -#define reg_aagc_max_rf_agc_9_8_pos 0 -#define reg_aagc_max_rf_agc_9_8_len 2 -#define reg_aagc_max_rf_agc_9_8_lsb 8 -#define xd_p_reg_aagc_min_rf_agc_7_0 0xA008 -#define reg_aagc_min_rf_agc_7_0_pos 0 -#define reg_aagc_min_rf_agc_7_0_len 8 -#define reg_aagc_min_rf_agc_7_0_lsb 0 -#define xd_p_reg_aagc_min_rf_agc_9_8 0xA009 -#define reg_aagc_min_rf_agc_9_8_pos 0 -#define reg_aagc_min_rf_agc_9_8_len 2 -#define reg_aagc_min_rf_agc_9_8_lsb 8 -#define xd_p_reg_aagc_max_if_agc_7_0 0xA00A -#define reg_aagc_max_if_agc_7_0_pos 0 -#define reg_aagc_max_if_agc_7_0_len 8 -#define reg_aagc_max_if_agc_7_0_lsb 0 -#define xd_p_reg_aagc_max_if_agc_9_8 0xA00B -#define reg_aagc_max_if_agc_9_8_pos 0 -#define reg_aagc_max_if_agc_9_8_len 2 -#define reg_aagc_max_if_agc_9_8_lsb 8 -#define xd_p_reg_aagc_min_if_agc_7_0 0xA00C -#define reg_aagc_min_if_agc_7_0_pos 0 -#define reg_aagc_min_if_agc_7_0_len 8 -#define reg_aagc_min_if_agc_7_0_lsb 0 -#define xd_p_reg_aagc_min_if_agc_9_8 0xA00D -#define reg_aagc_min_if_agc_9_8_pos 0 -#define reg_aagc_min_if_agc_9_8_len 2 -#define reg_aagc_min_if_agc_9_8_lsb 8 -#define xd_p_reg_aagc_lock_sample_scale 0xA00E -#define reg_aagc_lock_sample_scale_pos 0 -#define reg_aagc_lock_sample_scale_len 5 -#define reg_aagc_lock_sample_scale_lsb 0 -#define xd_p_reg_aagc_rf_agc_lock_scale_acquire 0xA00F -#define reg_aagc_rf_agc_lock_scale_acquire_pos 0 -#define reg_aagc_rf_agc_lock_scale_acquire_len 3 -#define reg_aagc_rf_agc_lock_scale_acquire_lsb 0 -#define xd_p_reg_aagc_rf_agc_lock_scale_track 0xA00F -#define reg_aagc_rf_agc_lock_scale_track_pos 3 -#define reg_aagc_rf_agc_lock_scale_track_len 3 -#define reg_aagc_rf_agc_lock_scale_track_lsb 0 -#define xd_p_reg_aagc_if_agc_lock_scale_acquire 0xA010 -#define reg_aagc_if_agc_lock_scale_acquire_pos 0 -#define reg_aagc_if_agc_lock_scale_acquire_len 3 -#define reg_aagc_if_agc_lock_scale_acquire_lsb 0 -#define xd_p_reg_aagc_if_agc_lock_scale_track 0xA010 -#define reg_aagc_if_agc_lock_scale_track_pos 3 -#define reg_aagc_if_agc_lock_scale_track_len 3 -#define reg_aagc_if_agc_lock_scale_track_lsb 0 -#define xd_p_reg_aagc_rf_top_numerator_7_0 0xA011 -#define reg_aagc_rf_top_numerator_7_0_pos 0 -#define reg_aagc_rf_top_numerator_7_0_len 8 -#define reg_aagc_rf_top_numerator_7_0_lsb 0 -#define xd_p_reg_aagc_rf_top_numerator_9_8 0xA012 -#define reg_aagc_rf_top_numerator_9_8_pos 0 -#define reg_aagc_rf_top_numerator_9_8_len 2 -#define reg_aagc_rf_top_numerator_9_8_lsb 8 -#define xd_p_reg_aagc_if_top_numerator_7_0 0xA013 -#define reg_aagc_if_top_numerator_7_0_pos 0 -#define reg_aagc_if_top_numerator_7_0_len 8 -#define reg_aagc_if_top_numerator_7_0_lsb 0 -#define xd_p_reg_aagc_if_top_numerator_9_8 0xA014 -#define reg_aagc_if_top_numerator_9_8_pos 0 -#define reg_aagc_if_top_numerator_9_8_len 2 -#define reg_aagc_if_top_numerator_9_8_lsb 8 -#define xd_p_reg_aagc_adc_out_desired_7_0 0xA015 -#define reg_aagc_adc_out_desired_7_0_pos 0 -#define reg_aagc_adc_out_desired_7_0_len 8 -#define reg_aagc_adc_out_desired_7_0_lsb 0 -#define xd_p_reg_aagc_adc_out_desired_8 0xA016 -#define reg_aagc_adc_out_desired_8_pos 0 -#define reg_aagc_adc_out_desired_8_len 1 -#define reg_aagc_adc_out_desired_8_lsb 0 -#define xd_p_reg_aagc_fixed_gain 0xA016 -#define reg_aagc_fixed_gain_pos 3 -#define reg_aagc_fixed_gain_len 1 -#define reg_aagc_fixed_gain_lsb 0 -#define xd_p_reg_aagc_lock_count_th 0xA016 -#define reg_aagc_lock_count_th_pos 4 -#define reg_aagc_lock_count_th_len 4 -#define reg_aagc_lock_count_th_lsb 0 -#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017 -#define reg_aagc_fixed_rf_agc_control_7_0_pos 0 -#define reg_aagc_fixed_rf_agc_control_7_0_len 8 -#define reg_aagc_fixed_rf_agc_control_7_0_lsb 0 -#define xd_p_reg_aagc_fixed_rf_agc_control_15_8 0xA018 -#define reg_aagc_fixed_rf_agc_control_15_8_pos 0 -#define reg_aagc_fixed_rf_agc_control_15_8_len 8 -#define reg_aagc_fixed_rf_agc_control_15_8_lsb 8 -#define xd_p_reg_aagc_fixed_rf_agc_control_23_16 0xA019 -#define reg_aagc_fixed_rf_agc_control_23_16_pos 0 -#define reg_aagc_fixed_rf_agc_control_23_16_len 8 -#define reg_aagc_fixed_rf_agc_control_23_16_lsb 16 -#define xd_p_reg_aagc_fixed_rf_agc_control_30_24 0xA01A -#define reg_aagc_fixed_rf_agc_control_30_24_pos 0 -#define reg_aagc_fixed_rf_agc_control_30_24_len 7 -#define reg_aagc_fixed_rf_agc_control_30_24_lsb 24 -#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B -#define reg_aagc_fixed_if_agc_control_7_0_pos 0 -#define reg_aagc_fixed_if_agc_control_7_0_len 8 -#define reg_aagc_fixed_if_agc_control_7_0_lsb 0 -#define xd_p_reg_aagc_fixed_if_agc_control_15_8 0xA01C -#define reg_aagc_fixed_if_agc_control_15_8_pos 0 -#define reg_aagc_fixed_if_agc_control_15_8_len 8 -#define reg_aagc_fixed_if_agc_control_15_8_lsb 8 -#define xd_p_reg_aagc_fixed_if_agc_control_23_16 0xA01D -#define reg_aagc_fixed_if_agc_control_23_16_pos 0 -#define reg_aagc_fixed_if_agc_control_23_16_len 8 -#define reg_aagc_fixed_if_agc_control_23_16_lsb 16 -#define xd_p_reg_aagc_fixed_if_agc_control_30_24 0xA01E -#define reg_aagc_fixed_if_agc_control_30_24_pos 0 -#define reg_aagc_fixed_if_agc_control_30_24_len 7 -#define reg_aagc_fixed_if_agc_control_30_24_lsb 24 -#define xd_p_reg_aagc_rf_agc_unlock_numerator 0xA01F -#define reg_aagc_rf_agc_unlock_numerator_pos 0 -#define reg_aagc_rf_agc_unlock_numerator_len 6 -#define reg_aagc_rf_agc_unlock_numerator_lsb 0 -#define xd_p_reg_aagc_if_agc_unlock_numerator 0xA020 -#define reg_aagc_if_agc_unlock_numerator_pos 0 -#define reg_aagc_if_agc_unlock_numerator_len 6 -#define reg_aagc_if_agc_unlock_numerator_lsb 0 -#define xd_p_reg_unplug_th 0xA021 -#define reg_unplug_th_pos 0 -#define reg_unplug_th_len 8 -#define reg_aagc_rf_x0_lsb 0 -#define xd_p_reg_weak_signal_rfagc_thr 0xA022 -#define reg_weak_signal_rfagc_thr_pos 0 -#define reg_weak_signal_rfagc_thr_len 8 -#define reg_weak_signal_rfagc_thr_lsb 0 -#define xd_p_reg_unplug_rf_gain_th 0xA023 -#define reg_unplug_rf_gain_th_pos 0 -#define reg_unplug_rf_gain_th_len 8 -#define reg_unplug_rf_gain_th_lsb 0 -#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024 -#define reg_unplug_dtop_rf_gain_th_pos 0 -#define reg_unplug_dtop_rf_gain_th_len 8 -#define reg_unplug_dtop_rf_gain_th_lsb 0 -#define xd_p_reg_unplug_dtop_if_gain_th 0xA025 -#define reg_unplug_dtop_if_gain_th_pos 0 -#define reg_unplug_dtop_if_gain_th_len 8 -#define reg_unplug_dtop_if_gain_th_lsb 0 -#define xd_p_reg_top_recover_at_unplug_en 0xA026 -#define reg_top_recover_at_unplug_en_pos 0 -#define reg_top_recover_at_unplug_en_len 1 -#define reg_top_recover_at_unplug_en_lsb 0 -#define xd_p_reg_aagc_rf_x6 0xA027 -#define reg_aagc_rf_x6_pos 0 -#define reg_aagc_rf_x6_len 8 -#define reg_aagc_rf_x6_lsb 0 -#define xd_p_reg_aagc_rf_x7 0xA028 -#define reg_aagc_rf_x7_pos 0 -#define reg_aagc_rf_x7_len 8 -#define reg_aagc_rf_x7_lsb 0 -#define xd_p_reg_aagc_rf_x8 0xA029 -#define reg_aagc_rf_x8_pos 0 -#define reg_aagc_rf_x8_len 8 -#define reg_aagc_rf_x8_lsb 0 -#define xd_p_reg_aagc_rf_x9 0xA02A -#define reg_aagc_rf_x9_pos 0 -#define reg_aagc_rf_x9_len 8 -#define reg_aagc_rf_x9_lsb 0 -#define xd_p_reg_aagc_rf_x10 0xA02B -#define reg_aagc_rf_x10_pos 0 -#define reg_aagc_rf_x10_len 8 -#define reg_aagc_rf_x10_lsb 0 -#define xd_p_reg_aagc_rf_x11 0xA02C -#define reg_aagc_rf_x11_pos 0 -#define reg_aagc_rf_x11_len 8 -#define reg_aagc_rf_x11_lsb 0 -#define xd_p_reg_aagc_rf_x12 0xA02D -#define reg_aagc_rf_x12_pos 0 -#define reg_aagc_rf_x12_len 8 -#define reg_aagc_rf_x12_lsb 0 -#define xd_p_reg_aagc_rf_x13 0xA02E -#define reg_aagc_rf_x13_pos 0 -#define reg_aagc_rf_x13_len 8 -#define reg_aagc_rf_x13_lsb 0 -#define xd_p_reg_aagc_if_x0 0xA02F -#define reg_aagc_if_x0_pos 0 -#define reg_aagc_if_x0_len 8 -#define reg_aagc_if_x0_lsb 0 -#define xd_p_reg_aagc_if_x1 0xA030 -#define reg_aagc_if_x1_pos 0 -#define reg_aagc_if_x1_len 8 -#define reg_aagc_if_x1_lsb 0 -#define xd_p_reg_aagc_if_x2 0xA031 -#define reg_aagc_if_x2_pos 0 -#define reg_aagc_if_x2_len 8 -#define reg_aagc_if_x2_lsb 0 -#define xd_p_reg_aagc_if_x3 0xA032 -#define reg_aagc_if_x3_pos 0 -#define reg_aagc_if_x3_len 8 -#define reg_aagc_if_x3_lsb 0 -#define xd_p_reg_aagc_if_x4 0xA033 -#define reg_aagc_if_x4_pos 0 -#define reg_aagc_if_x4_len 8 -#define reg_aagc_if_x4_lsb 0 -#define xd_p_reg_aagc_if_x5 0xA034 -#define reg_aagc_if_x5_pos 0 -#define reg_aagc_if_x5_len 8 -#define reg_aagc_if_x5_lsb 0 -#define xd_p_reg_aagc_if_x6 0xA035 -#define reg_aagc_if_x6_pos 0 -#define reg_aagc_if_x6_len 8 -#define reg_aagc_if_x6_lsb 0 -#define xd_p_reg_aagc_if_x7 0xA036 -#define reg_aagc_if_x7_pos 0 -#define reg_aagc_if_x7_len 8 -#define reg_aagc_if_x7_lsb 0 -#define xd_p_reg_aagc_if_x8 0xA037 -#define reg_aagc_if_x8_pos 0 -#define reg_aagc_if_x8_len 8 -#define reg_aagc_if_x8_lsb 0 -#define xd_p_reg_aagc_if_x9 0xA038 -#define reg_aagc_if_x9_pos 0 -#define reg_aagc_if_x9_len 8 -#define reg_aagc_if_x9_lsb 0 -#define xd_p_reg_aagc_if_x10 0xA039 -#define reg_aagc_if_x10_pos 0 -#define reg_aagc_if_x10_len 8 -#define reg_aagc_if_x10_lsb 0 -#define xd_p_reg_aagc_if_x11 0xA03A -#define reg_aagc_if_x11_pos 0 -#define reg_aagc_if_x11_len 8 -#define reg_aagc_if_x11_lsb 0 -#define xd_p_reg_aagc_if_x12 0xA03B -#define reg_aagc_if_x12_pos 0 -#define reg_aagc_if_x12_len 8 -#define reg_aagc_if_x12_lsb 0 -#define xd_p_reg_aagc_if_x13 0xA03C -#define reg_aagc_if_x13_pos 0 -#define reg_aagc_if_x13_len 8 -#define reg_aagc_if_x13_lsb 0 -#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca 0xA03D -#define reg_aagc_min_rf_ctl_8bit_for_dca_pos 0 -#define reg_aagc_min_rf_ctl_8bit_for_dca_len 8 -#define reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0 -#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca 0xA03E -#define reg_aagc_min_if_ctl_8bit_for_dca_pos 0 -#define reg_aagc_min_if_ctl_8bit_for_dca_len 8 -#define reg_aagc_min_if_ctl_8bit_for_dca_lsb 0 -#define xd_r_reg_aagc_total_gain_7_0 0xA070 -#define reg_aagc_total_gain_7_0_pos 0 -#define reg_aagc_total_gain_7_0_len 8 -#define reg_aagc_total_gain_7_0_lsb 0 -#define xd_r_reg_aagc_total_gain_15_8 0xA071 -#define reg_aagc_total_gain_15_8_pos 0 -#define reg_aagc_total_gain_15_8_len 8 -#define reg_aagc_total_gain_15_8_lsb 8 -#define xd_p_reg_aagc_in_sat_cnt_7_0 0xA074 -#define reg_aagc_in_sat_cnt_7_0_pos 0 -#define reg_aagc_in_sat_cnt_7_0_len 8 -#define reg_aagc_in_sat_cnt_7_0_lsb 0 -#define xd_p_reg_aagc_in_sat_cnt_15_8 0xA075 -#define reg_aagc_in_sat_cnt_15_8_pos 0 -#define reg_aagc_in_sat_cnt_15_8_len 8 -#define reg_aagc_in_sat_cnt_15_8_lsb 8 -#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076 -#define reg_aagc_in_sat_cnt_23_16_pos 0 -#define reg_aagc_in_sat_cnt_23_16_len 8 -#define reg_aagc_in_sat_cnt_23_16_lsb 16 -#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077 -#define reg_aagc_in_sat_cnt_31_24_pos 0 -#define reg_aagc_in_sat_cnt_31_24_len 8 -#define reg_aagc_in_sat_cnt_31_24_lsb 24 -#define xd_r_reg_aagc_digital_rf_volt_7_0 0xA078 -#define reg_aagc_digital_rf_volt_7_0_pos 0 -#define reg_aagc_digital_rf_volt_7_0_len 8 -#define reg_aagc_digital_rf_volt_7_0_lsb 0 -#define xd_r_reg_aagc_digital_rf_volt_9_8 0xA079 -#define reg_aagc_digital_rf_volt_9_8_pos 0 -#define reg_aagc_digital_rf_volt_9_8_len 2 -#define reg_aagc_digital_rf_volt_9_8_lsb 8 -#define xd_r_reg_aagc_digital_if_volt_7_0 0xA07A -#define reg_aagc_digital_if_volt_7_0_pos 0 -#define reg_aagc_digital_if_volt_7_0_len 8 -#define reg_aagc_digital_if_volt_7_0_lsb 0 -#define xd_r_reg_aagc_digital_if_volt_9_8 0xA07B -#define reg_aagc_digital_if_volt_9_8_pos 0 -#define reg_aagc_digital_if_volt_9_8_len 2 -#define reg_aagc_digital_if_volt_9_8_lsb 8 -#define xd_r_reg_aagc_rf_gain 0xA07C -#define reg_aagc_rf_gain_pos 0 -#define reg_aagc_rf_gain_len 8 -#define reg_aagc_rf_gain_lsb 0 -#define xd_r_reg_aagc_if_gain 0xA07D -#define reg_aagc_if_gain_pos 0 -#define reg_aagc_if_gain_len 8 -#define reg_aagc_if_gain_lsb 0 -#define xd_p_tinr_imp_indicator 0xA080 -#define tinr_imp_indicator_pos 0 -#define tinr_imp_indicator_len 2 -#define tinr_imp_indicator_lsb 0 -#define xd_p_reg_tinr_fifo_size 0xA080 -#define reg_tinr_fifo_size_pos 2 -#define reg_tinr_fifo_size_len 5 -#define reg_tinr_fifo_size_lsb 0 -#define xd_p_reg_tinr_saturation_cnt_th 0xA081 -#define reg_tinr_saturation_cnt_th_pos 0 -#define reg_tinr_saturation_cnt_th_len 4 -#define reg_tinr_saturation_cnt_th_lsb 0 -#define xd_p_reg_tinr_saturation_th_3_0 0xA081 -#define reg_tinr_saturation_th_3_0_pos 4 -#define reg_tinr_saturation_th_3_0_len 4 -#define reg_tinr_saturation_th_3_0_lsb 0 -#define xd_p_reg_tinr_saturation_th_8_4 0xA082 -#define reg_tinr_saturation_th_8_4_pos 0 -#define reg_tinr_saturation_th_8_4_len 5 -#define reg_tinr_saturation_th_8_4_lsb 4 -#define xd_p_reg_tinr_imp_duration_th_2k_7_0 0xA083 -#define reg_tinr_imp_duration_th_2k_7_0_pos 0 -#define reg_tinr_imp_duration_th_2k_7_0_len 8 -#define reg_tinr_imp_duration_th_2k_7_0_lsb 0 -#define xd_p_reg_tinr_imp_duration_th_2k_8 0xA084 -#define reg_tinr_imp_duration_th_2k_8_pos 0 -#define reg_tinr_imp_duration_th_2k_8_len 1 -#define reg_tinr_imp_duration_th_2k_8_lsb 0 -#define xd_p_reg_tinr_imp_duration_th_8k_7_0 0xA085 -#define reg_tinr_imp_duration_th_8k_7_0_pos 0 -#define reg_tinr_imp_duration_th_8k_7_0_len 8 -#define reg_tinr_imp_duration_th_8k_7_0_lsb 0 -#define xd_p_reg_tinr_imp_duration_th_8k_10_8 0xA086 -#define reg_tinr_imp_duration_th_8k_10_8_pos 0 -#define reg_tinr_imp_duration_th_8k_10_8_len 3 -#define reg_tinr_imp_duration_th_8k_10_8_lsb 8 -#define xd_p_reg_tinr_freq_ratio_6m_7_0 0xA087 -#define reg_tinr_freq_ratio_6m_7_0_pos 0 -#define reg_tinr_freq_ratio_6m_7_0_len 8 -#define reg_tinr_freq_ratio_6m_7_0_lsb 0 -#define xd_p_reg_tinr_freq_ratio_6m_12_8 0xA088 -#define reg_tinr_freq_ratio_6m_12_8_pos 0 -#define reg_tinr_freq_ratio_6m_12_8_len 5 -#define reg_tinr_freq_ratio_6m_12_8_lsb 8 -#define xd_p_reg_tinr_freq_ratio_7m_7_0 0xA089 -#define reg_tinr_freq_ratio_7m_7_0_pos 0 -#define reg_tinr_freq_ratio_7m_7_0_len 8 -#define reg_tinr_freq_ratio_7m_7_0_lsb 0 -#define xd_p_reg_tinr_freq_ratio_7m_12_8 0xA08A -#define reg_tinr_freq_ratio_7m_12_8_pos 0 -#define reg_tinr_freq_ratio_7m_12_8_len 5 -#define reg_tinr_freq_ratio_7m_12_8_lsb 8 -#define xd_p_reg_tinr_freq_ratio_8m_7_0 0xA08B -#define reg_tinr_freq_ratio_8m_7_0_pos 0 -#define reg_tinr_freq_ratio_8m_7_0_len 8 -#define reg_tinr_freq_ratio_8m_7_0_lsb 0 -#define xd_p_reg_tinr_freq_ratio_8m_12_8 0xA08C -#define reg_tinr_freq_ratio_8m_12_8_pos 0 -#define reg_tinr_freq_ratio_8m_12_8_len 5 -#define reg_tinr_freq_ratio_8m_12_8_lsb 8 -#define xd_p_reg_tinr_imp_duration_th_low_2k 0xA08D -#define reg_tinr_imp_duration_th_low_2k_pos 0 -#define reg_tinr_imp_duration_th_low_2k_len 8 -#define reg_tinr_imp_duration_th_low_2k_lsb 0 -#define xd_p_reg_tinr_imp_duration_th_low_8k 0xA08E -#define reg_tinr_imp_duration_th_low_8k_pos 0 -#define reg_tinr_imp_duration_th_low_8k_len 8 -#define reg_tinr_imp_duration_th_low_8k_lsb 0 -#define xd_r_reg_tinr_counter_7_0 0xA090 -#define reg_tinr_counter_7_0_pos 0 -#define reg_tinr_counter_7_0_len 8 -#define reg_tinr_counter_7_0_lsb 0 -#define xd_r_reg_tinr_counter_15_8 0xA091 -#define reg_tinr_counter_15_8_pos 0 -#define reg_tinr_counter_15_8_len 8 -#define reg_tinr_counter_15_8_lsb 8 -#define xd_p_reg_tinr_adative_tinr_en 0xA093 -#define reg_tinr_adative_tinr_en_pos 0 -#define reg_tinr_adative_tinr_en_len 1 -#define reg_tinr_adative_tinr_en_lsb 0 -#define xd_p_reg_tinr_peak_fifo_size 0xA093 -#define reg_tinr_peak_fifo_size_pos 1 -#define reg_tinr_peak_fifo_size_len 5 -#define reg_tinr_peak_fifo_size_lsb 0 -#define xd_p_reg_tinr_counter_rst 0xA093 -#define reg_tinr_counter_rst_pos 6 -#define reg_tinr_counter_rst_len 1 -#define reg_tinr_counter_rst_lsb 0 -#define xd_p_reg_tinr_search_period_7_0 0xA094 -#define reg_tinr_search_period_7_0_pos 0 -#define reg_tinr_search_period_7_0_len 8 -#define reg_tinr_search_period_7_0_lsb 0 -#define xd_p_reg_tinr_search_period_15_8 0xA095 -#define reg_tinr_search_period_15_8_pos 0 -#define reg_tinr_search_period_15_8_len 8 -#define reg_tinr_search_period_15_8_lsb 8 -#define xd_p_reg_ccifs_fcw_7_0 0xA0A0 -#define reg_ccifs_fcw_7_0_pos 0 -#define reg_ccifs_fcw_7_0_len 8 -#define reg_ccifs_fcw_7_0_lsb 0 -#define xd_p_reg_ccifs_fcw_12_8 0xA0A1 -#define reg_ccifs_fcw_12_8_pos 0 -#define reg_ccifs_fcw_12_8_len 5 -#define reg_ccifs_fcw_12_8_lsb 8 -#define xd_p_reg_ccifs_spec_inv 0xA0A1 -#define reg_ccifs_spec_inv_pos 5 -#define reg_ccifs_spec_inv_len 1 -#define reg_ccifs_spec_inv_lsb 0 -#define xd_p_reg_gp_trigger 0xA0A2 -#define reg_gp_trigger_pos 0 -#define reg_gp_trigger_len 1 -#define reg_gp_trigger_lsb 0 -#define xd_p_reg_trigger_sel 0xA0A2 -#define reg_trigger_sel_pos 1 -#define reg_trigger_sel_len 2 -#define reg_trigger_sel_lsb 0 -#define xd_p_reg_debug_ofdm 0xA0A2 -#define reg_debug_ofdm_pos 3 -#define reg_debug_ofdm_len 2 -#define reg_debug_ofdm_lsb 0 -#define xd_p_reg_trigger_module_sel 0xA0A3 -#define reg_trigger_module_sel_pos 0 -#define reg_trigger_module_sel_len 6 -#define reg_trigger_module_sel_lsb 0 -#define xd_p_reg_trigger_set_sel 0xA0A4 -#define reg_trigger_set_sel_pos 0 -#define reg_trigger_set_sel_len 6 -#define reg_trigger_set_sel_lsb 0 -#define xd_p_reg_fw_int_mask_n 0xA0A4 -#define reg_fw_int_mask_n_pos 6 -#define reg_fw_int_mask_n_len 1 -#define reg_fw_int_mask_n_lsb 0 -#define xd_p_reg_debug_group 0xA0A5 -#define reg_debug_group_pos 0 -#define reg_debug_group_len 4 -#define reg_debug_group_lsb 0 -#define xd_p_reg_odbg_clk_sel 0xA0A5 -#define reg_odbg_clk_sel_pos 4 -#define reg_odbg_clk_sel_len 2 -#define reg_odbg_clk_sel_lsb 0 -#define xd_p_reg_ccif_sc 0xA0C0 -#define reg_ccif_sc_pos 0 -#define reg_ccif_sc_len 4 -#define reg_ccif_sc_lsb 0 -#define xd_r_reg_ccif_saturate 0xA0C1 -#define reg_ccif_saturate_pos 0 -#define reg_ccif_saturate_len 2 -#define reg_ccif_saturate_lsb 0 -#define xd_r_reg_antif_saturate 0xA0C1 -#define reg_antif_saturate_pos 2 -#define reg_antif_saturate_len 4 -#define reg_antif_saturate_lsb 0 -#define xd_r_reg_acif_saturate 0xA0C2 -#define reg_acif_saturate_pos 0 -#define reg_acif_saturate_len 8 -#define reg_acif_saturate_lsb 0 -#define xd_p_reg_tmr_timer0_threshold_7_0 0xA0C8 -#define reg_tmr_timer0_threshold_7_0_pos 0 -#define reg_tmr_timer0_threshold_7_0_len 8 -#define reg_tmr_timer0_threshold_7_0_lsb 0 -#define xd_p_reg_tmr_timer0_threshold_15_8 0xA0C9 -#define reg_tmr_timer0_threshold_15_8_pos 0 -#define reg_tmr_timer0_threshold_15_8_len 8 -#define reg_tmr_timer0_threshold_15_8_lsb 8 -#define xd_p_reg_tmr_timer0_enable 0xA0CA -#define reg_tmr_timer0_enable_pos 0 -#define reg_tmr_timer0_enable_len 1 -#define reg_tmr_timer0_enable_lsb 0 -#define xd_p_reg_tmr_timer0_clk_sel 0xA0CA -#define reg_tmr_timer0_clk_sel_pos 1 -#define reg_tmr_timer0_clk_sel_len 1 -#define reg_tmr_timer0_clk_sel_lsb 0 -#define xd_p_reg_tmr_timer0_int 0xA0CA -#define reg_tmr_timer0_int_pos 2 -#define reg_tmr_timer0_int_len 1 -#define reg_tmr_timer0_int_lsb 0 -#define xd_p_reg_tmr_timer0_rst 0xA0CA -#define reg_tmr_timer0_rst_pos 3 -#define reg_tmr_timer0_rst_len 1 -#define reg_tmr_timer0_rst_lsb 0 -#define xd_r_reg_tmr_timer0_count_7_0 0xA0CB -#define reg_tmr_timer0_count_7_0_pos 0 -#define reg_tmr_timer0_count_7_0_len 8 -#define reg_tmr_timer0_count_7_0_lsb 0 -#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC -#define reg_tmr_timer0_count_15_8_pos 0 -#define reg_tmr_timer0_count_15_8_len 8 -#define reg_tmr_timer0_count_15_8_lsb 8 -#define xd_p_reg_suspend 0xA0CD -#define reg_suspend_pos 0 -#define reg_suspend_len 1 -#define reg_suspend_lsb 0 -#define xd_p_reg_suspend_rdy 0xA0CD -#define reg_suspend_rdy_pos 1 -#define reg_suspend_rdy_len 1 -#define reg_suspend_rdy_lsb 0 -#define xd_p_reg_resume 0xA0CD -#define reg_resume_pos 2 -#define reg_resume_len 1 -#define reg_resume_lsb 0 -#define xd_p_reg_resume_rdy 0xA0CD -#define reg_resume_rdy_pos 3 -#define reg_resume_rdy_len 1 -#define reg_resume_rdy_lsb 0 -#define xd_p_reg_fmf 0xA0CE -#define reg_fmf_pos 0 -#define reg_fmf_len 8 -#define reg_fmf_lsb 0 -#define xd_p_ccid_accumulate_num_2k_7_0 0xA100 -#define ccid_accumulate_num_2k_7_0_pos 0 -#define ccid_accumulate_num_2k_7_0_len 8 -#define ccid_accumulate_num_2k_7_0_lsb 0 -#define xd_p_ccid_accumulate_num_2k_12_8 0xA101 -#define ccid_accumulate_num_2k_12_8_pos 0 -#define ccid_accumulate_num_2k_12_8_len 5 -#define ccid_accumulate_num_2k_12_8_lsb 8 -#define xd_p_ccid_accumulate_num_8k_7_0 0xA102 -#define ccid_accumulate_num_8k_7_0_pos 0 -#define ccid_accumulate_num_8k_7_0_len 8 -#define ccid_accumulate_num_8k_7_0_lsb 0 -#define xd_p_ccid_accumulate_num_8k_14_8 0xA103 -#define ccid_accumulate_num_8k_14_8_pos 0 -#define ccid_accumulate_num_8k_14_8_len 7 -#define ccid_accumulate_num_8k_14_8_lsb 8 -#define xd_p_ccid_desired_level_0 0xA103 -#define ccid_desired_level_0_pos 7 -#define ccid_desired_level_0_len 1 -#define ccid_desired_level_0_lsb 0 -#define xd_p_ccid_desired_level_8_1 0xA104 -#define ccid_desired_level_8_1_pos 0 -#define ccid_desired_level_8_1_len 8 -#define ccid_desired_level_8_1_lsb 1 -#define xd_p_ccid_apply_delay 0xA105 -#define ccid_apply_delay_pos 0 -#define ccid_apply_delay_len 7 -#define ccid_apply_delay_lsb 0 -#define xd_p_ccid_CCID_Threshold1 0xA106 -#define ccid_CCID_Threshold1_pos 0 -#define ccid_CCID_Threshold1_len 8 -#define ccid_CCID_Threshold1_lsb 0 -#define xd_p_ccid_CCID_Threshold2 0xA107 -#define ccid_CCID_Threshold2_pos 0 -#define ccid_CCID_Threshold2_len 8 -#define ccid_CCID_Threshold2_lsb 0 -#define xd_p_reg_ccid_gain_scale 0xA108 -#define reg_ccid_gain_scale_pos 0 -#define reg_ccid_gain_scale_len 4 -#define reg_ccid_gain_scale_lsb 0 -#define xd_p_reg_ccid2_passband_gain_set 0xA108 -#define reg_ccid2_passband_gain_set_pos 4 -#define reg_ccid2_passband_gain_set_len 4 -#define reg_ccid2_passband_gain_set_lsb 0 -#define xd_r_ccid_multiplier_7_0 0xA109 -#define ccid_multiplier_7_0_pos 0 -#define ccid_multiplier_7_0_len 8 -#define ccid_multiplier_7_0_lsb 0 -#define xd_r_ccid_multiplier_15_8 0xA10A -#define ccid_multiplier_15_8_pos 0 -#define ccid_multiplier_15_8_len 8 -#define ccid_multiplier_15_8_lsb 8 -#define xd_r_ccid_right_shift_bits 0xA10B -#define ccid_right_shift_bits_pos 0 -#define ccid_right_shift_bits_len 4 -#define ccid_right_shift_bits_lsb 0 -#define xd_r_reg_ccid_sx_7_0 0xA10C -#define reg_ccid_sx_7_0_pos 0 -#define reg_ccid_sx_7_0_len 8 -#define reg_ccid_sx_7_0_lsb 0 -#define xd_r_reg_ccid_sx_15_8 0xA10D -#define reg_ccid_sx_15_8_pos 0 -#define reg_ccid_sx_15_8_len 8 -#define reg_ccid_sx_15_8_lsb 8 -#define xd_r_reg_ccid_sx_21_16 0xA10E -#define reg_ccid_sx_21_16_pos 0 -#define reg_ccid_sx_21_16_len 6 -#define reg_ccid_sx_21_16_lsb 16 -#define xd_r_reg_ccid_sy_7_0 0xA110 -#define reg_ccid_sy_7_0_pos 0 -#define reg_ccid_sy_7_0_len 8 -#define reg_ccid_sy_7_0_lsb 0 -#define xd_r_reg_ccid_sy_15_8 0xA111 -#define reg_ccid_sy_15_8_pos 0 -#define reg_ccid_sy_15_8_len 8 -#define reg_ccid_sy_15_8_lsb 8 -#define xd_r_reg_ccid_sy_23_16 0xA112 -#define reg_ccid_sy_23_16_pos 0 -#define reg_ccid_sy_23_16_len 8 -#define reg_ccid_sy_23_16_lsb 16 -#define xd_r_reg_ccid2_sz_7_0 0xA114 -#define reg_ccid2_sz_7_0_pos 0 -#define reg_ccid2_sz_7_0_len 8 -#define reg_ccid2_sz_7_0_lsb 0 -#define xd_r_reg_ccid2_sz_15_8 0xA115 -#define reg_ccid2_sz_15_8_pos 0 -#define reg_ccid2_sz_15_8_len 8 -#define reg_ccid2_sz_15_8_lsb 8 -#define xd_r_reg_ccid2_sz_23_16 0xA116 -#define reg_ccid2_sz_23_16_pos 0 -#define reg_ccid2_sz_23_16_len 8 -#define reg_ccid2_sz_23_16_lsb 16 -#define xd_r_reg_ccid2_sz_25_24 0xA117 -#define reg_ccid2_sz_25_24_pos 0 -#define reg_ccid2_sz_25_24_len 2 -#define reg_ccid2_sz_25_24_lsb 24 -#define xd_r_reg_ccid2_sy_7_0 0xA118 -#define reg_ccid2_sy_7_0_pos 0 -#define reg_ccid2_sy_7_0_len 8 -#define reg_ccid2_sy_7_0_lsb 0 -#define xd_r_reg_ccid2_sy_15_8 0xA119 -#define reg_ccid2_sy_15_8_pos 0 -#define reg_ccid2_sy_15_8_len 8 -#define reg_ccid2_sy_15_8_lsb 8 -#define xd_r_reg_ccid2_sy_23_16 0xA11A -#define reg_ccid2_sy_23_16_pos 0 -#define reg_ccid2_sy_23_16_len 8 -#define reg_ccid2_sy_23_16_lsb 16 -#define xd_r_reg_ccid2_sy_25_24 0xA11B -#define reg_ccid2_sy_25_24_pos 0 -#define reg_ccid2_sy_25_24_len 2 -#define reg_ccid2_sy_25_24_lsb 24 -#define xd_p_dagc1_accumulate_num_2k_7_0 0xA120 -#define dagc1_accumulate_num_2k_7_0_pos 0 -#define dagc1_accumulate_num_2k_7_0_len 8 -#define dagc1_accumulate_num_2k_7_0_lsb 0 -#define xd_p_dagc1_accumulate_num_2k_12_8 0xA121 -#define dagc1_accumulate_num_2k_12_8_pos 0 -#define dagc1_accumulate_num_2k_12_8_len 5 -#define dagc1_accumulate_num_2k_12_8_lsb 8 -#define xd_p_dagc1_accumulate_num_8k_7_0 0xA122 -#define dagc1_accumulate_num_8k_7_0_pos 0 -#define dagc1_accumulate_num_8k_7_0_len 8 -#define dagc1_accumulate_num_8k_7_0_lsb 0 -#define xd_p_dagc1_accumulate_num_8k_14_8 0xA123 -#define dagc1_accumulate_num_8k_14_8_pos 0 -#define dagc1_accumulate_num_8k_14_8_len 7 -#define dagc1_accumulate_num_8k_14_8_lsb 8 -#define xd_p_dagc1_desired_level_0 0xA123 -#define dagc1_desired_level_0_pos 7 -#define dagc1_desired_level_0_len 1 -#define dagc1_desired_level_0_lsb 0 -#define xd_p_dagc1_desired_level_8_1 0xA124 -#define dagc1_desired_level_8_1_pos 0 -#define dagc1_desired_level_8_1_len 8 -#define dagc1_desired_level_8_1_lsb 1 -#define xd_p_dagc1_apply_delay 0xA125 -#define dagc1_apply_delay_pos 0 -#define dagc1_apply_delay_len 7 -#define dagc1_apply_delay_lsb 0 -#define xd_p_dagc1_bypass_scale_ctl 0xA126 -#define dagc1_bypass_scale_ctl_pos 0 -#define dagc1_bypass_scale_ctl_len 2 -#define dagc1_bypass_scale_ctl_lsb 0 -#define xd_p_reg_dagc1_in_sat_cnt_7_0 0xA127 -#define reg_dagc1_in_sat_cnt_7_0_pos 0 -#define reg_dagc1_in_sat_cnt_7_0_len 8 -#define reg_dagc1_in_sat_cnt_7_0_lsb 0 -#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128 -#define reg_dagc1_in_sat_cnt_15_8_pos 0 -#define reg_dagc1_in_sat_cnt_15_8_len 8 -#define reg_dagc1_in_sat_cnt_15_8_lsb 8 -#define xd_p_reg_dagc1_in_sat_cnt_23_16 0xA129 -#define reg_dagc1_in_sat_cnt_23_16_pos 0 -#define reg_dagc1_in_sat_cnt_23_16_len 8 -#define reg_dagc1_in_sat_cnt_23_16_lsb 16 -#define xd_p_reg_dagc1_in_sat_cnt_31_24 0xA12A -#define reg_dagc1_in_sat_cnt_31_24_pos 0 -#define reg_dagc1_in_sat_cnt_31_24_len 8 -#define reg_dagc1_in_sat_cnt_31_24_lsb 24 -#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B -#define reg_dagc1_out_sat_cnt_7_0_pos 0 -#define reg_dagc1_out_sat_cnt_7_0_len 8 -#define reg_dagc1_out_sat_cnt_7_0_lsb 0 -#define xd_p_reg_dagc1_out_sat_cnt_15_8 0xA12C -#define reg_dagc1_out_sat_cnt_15_8_pos 0 -#define reg_dagc1_out_sat_cnt_15_8_len 8 -#define reg_dagc1_out_sat_cnt_15_8_lsb 8 -#define xd_p_reg_dagc1_out_sat_cnt_23_16 0xA12D -#define reg_dagc1_out_sat_cnt_23_16_pos 0 -#define reg_dagc1_out_sat_cnt_23_16_len 8 -#define reg_dagc1_out_sat_cnt_23_16_lsb 16 -#define xd_p_reg_dagc1_out_sat_cnt_31_24 0xA12E -#define reg_dagc1_out_sat_cnt_31_24_pos 0 -#define reg_dagc1_out_sat_cnt_31_24_len 8 -#define reg_dagc1_out_sat_cnt_31_24_lsb 24 -#define xd_r_dagc1_multiplier_7_0 0xA136 -#define dagc1_multiplier_7_0_pos 0 -#define dagc1_multiplier_7_0_len 8 -#define dagc1_multiplier_7_0_lsb 0 -#define xd_r_dagc1_multiplier_15_8 0xA137 -#define dagc1_multiplier_15_8_pos 0 -#define dagc1_multiplier_15_8_len 8 -#define dagc1_multiplier_15_8_lsb 8 -#define xd_r_dagc1_right_shift_bits 0xA138 -#define dagc1_right_shift_bits_pos 0 -#define dagc1_right_shift_bits_len 4 -#define dagc1_right_shift_bits_lsb 0 -#define xd_p_reg_bfs_fcw_7_0 0xA140 -#define reg_bfs_fcw_7_0_pos 0 -#define reg_bfs_fcw_7_0_len 8 -#define reg_bfs_fcw_7_0_lsb 0 -#define xd_p_reg_bfs_fcw_15_8 0xA141 -#define reg_bfs_fcw_15_8_pos 0 -#define reg_bfs_fcw_15_8_len 8 -#define reg_bfs_fcw_15_8_lsb 8 -#define xd_p_reg_bfs_fcw_22_16 0xA142 -#define reg_bfs_fcw_22_16_pos 0 -#define reg_bfs_fcw_22_16_len 7 -#define reg_bfs_fcw_22_16_lsb 16 -#define xd_p_reg_antif_sf_7_0 0xA144 -#define reg_antif_sf_7_0_pos 0 -#define reg_antif_sf_7_0_len 8 -#define reg_antif_sf_7_0_lsb 0 -#define xd_p_reg_antif_sf_11_8 0xA145 -#define reg_antif_sf_11_8_pos 0 -#define reg_antif_sf_11_8_len 4 -#define reg_antif_sf_11_8_lsb 8 -#define xd_r_bfs_fcw_q_7_0 0xA150 -#define bfs_fcw_q_7_0_pos 0 -#define bfs_fcw_q_7_0_len 8 -#define bfs_fcw_q_7_0_lsb 0 -#define xd_r_bfs_fcw_q_15_8 0xA151 -#define bfs_fcw_q_15_8_pos 0 -#define bfs_fcw_q_15_8_len 8 -#define bfs_fcw_q_15_8_lsb 8 -#define xd_r_bfs_fcw_q_22_16 0xA152 -#define bfs_fcw_q_22_16_pos 0 -#define bfs_fcw_q_22_16_len 7 -#define bfs_fcw_q_22_16_lsb 16 -#define xd_p_reg_dca_enu 0xA160 -#define reg_dca_enu_pos 0 -#define reg_dca_enu_len 1 -#define reg_dca_enu_lsb 0 -#define xd_p_reg_dca_enl 0xA160 -#define reg_dca_enl_pos 1 -#define reg_dca_enl_len 1 -#define reg_dca_enl_lsb 0 -#define xd_p_reg_dca_lower_chip 0xA160 -#define reg_dca_lower_chip_pos 2 -#define reg_dca_lower_chip_len 1 -#define reg_dca_lower_chip_lsb 0 -#define xd_p_reg_dca_upper_chip 0xA160 -#define reg_dca_upper_chip_pos 3 -#define reg_dca_upper_chip_len 1 -#define reg_dca_upper_chip_lsb 0 -#define xd_p_reg_dca_platch 0xA160 -#define reg_dca_platch_pos 4 -#define reg_dca_platch_len 1 -#define reg_dca_platch_lsb 0 -#define xd_p_reg_dca_th 0xA161 -#define reg_dca_th_pos 0 -#define reg_dca_th_len 5 -#define reg_dca_th_lsb 0 -#define xd_p_reg_dca_scale 0xA162 -#define reg_dca_scale_pos 0 -#define reg_dca_scale_len 4 -#define reg_dca_scale_lsb 0 -#define xd_p_reg_dca_tone_7_0 0xA163 -#define reg_dca_tone_7_0_pos 0 -#define reg_dca_tone_7_0_len 8 -#define reg_dca_tone_7_0_lsb 0 -#define xd_p_reg_dca_tone_12_8 0xA164 -#define reg_dca_tone_12_8_pos 0 -#define reg_dca_tone_12_8_len 5 -#define reg_dca_tone_12_8_lsb 8 -#define xd_p_reg_dca_time_7_0 0xA165 -#define reg_dca_time_7_0_pos 0 -#define reg_dca_time_7_0_len 8 -#define reg_dca_time_7_0_lsb 0 -#define xd_p_reg_dca_time_15_8 0xA166 -#define reg_dca_time_15_8_pos 0 -#define reg_dca_time_15_8_len 8 -#define reg_dca_time_15_8_lsb 8 -#define xd_r_dcasm 0xA167 -#define dcasm_pos 0 -#define dcasm_len 3 -#define dcasm_lsb 0 -#define xd_p_reg_qnt_valuew_7_0 0xA168 -#define reg_qnt_valuew_7_0_pos 0 -#define reg_qnt_valuew_7_0_len 8 -#define reg_qnt_valuew_7_0_lsb 0 -#define xd_p_reg_qnt_valuew_10_8 0xA169 -#define reg_qnt_valuew_10_8_pos 0 -#define reg_qnt_valuew_10_8_len 3 -#define reg_qnt_valuew_10_8_lsb 8 -#define xd_p_dca_sbx_gain_diff_7_0 0xA16A -#define dca_sbx_gain_diff_7_0_pos 0 -#define dca_sbx_gain_diff_7_0_len 8 -#define dca_sbx_gain_diff_7_0_lsb 0 -#define xd_p_dca_sbx_gain_diff_9_8 0xA16B -#define dca_sbx_gain_diff_9_8_pos 0 -#define dca_sbx_gain_diff_9_8_len 2 -#define dca_sbx_gain_diff_9_8_lsb 8 -#define xd_p_reg_dca_stand_alone 0xA16C -#define reg_dca_stand_alone_pos 0 -#define reg_dca_stand_alone_len 1 -#define reg_dca_stand_alone_lsb 0 -#define xd_p_reg_dca_upper_out_en 0xA16C -#define reg_dca_upper_out_en_pos 1 -#define reg_dca_upper_out_en_len 1 -#define reg_dca_upper_out_en_lsb 0 -#define xd_p_reg_dca_rc_en 0xA16C -#define reg_dca_rc_en_pos 2 -#define reg_dca_rc_en_len 1 -#define reg_dca_rc_en_lsb 0 -#define xd_p_reg_dca_retrain_send 0xA16C -#define reg_dca_retrain_send_pos 3 -#define reg_dca_retrain_send_len 1 -#define reg_dca_retrain_send_lsb 0 -#define xd_p_reg_dca_retrain_rec 0xA16C -#define reg_dca_retrain_rec_pos 4 -#define reg_dca_retrain_rec_len 1 -#define reg_dca_retrain_rec_lsb 0 -#define xd_p_reg_dca_api_tpsrdy 0xA16C -#define reg_dca_api_tpsrdy_pos 5 -#define reg_dca_api_tpsrdy_len 1 -#define reg_dca_api_tpsrdy_lsb 0 -#define xd_p_reg_dca_symbol_gap 0xA16D -#define reg_dca_symbol_gap_pos 0 -#define reg_dca_symbol_gap_len 4 -#define reg_dca_symbol_gap_lsb 0 -#define xd_p_reg_qnt_nfvaluew_7_0 0xA16E -#define reg_qnt_nfvaluew_7_0_pos 0 -#define reg_qnt_nfvaluew_7_0_len 8 -#define reg_qnt_nfvaluew_7_0_lsb 0 -#define xd_p_reg_qnt_nfvaluew_10_8 0xA16F -#define reg_qnt_nfvaluew_10_8_pos 0 -#define reg_qnt_nfvaluew_10_8_len 3 -#define reg_qnt_nfvaluew_10_8_lsb 8 -#define xd_p_reg_qnt_flatness_thr_7_0 0xA170 -#define reg_qnt_flatness_thr_7_0_pos 0 -#define reg_qnt_flatness_thr_7_0_len 8 -#define reg_qnt_flatness_thr_7_0_lsb 0 -#define xd_p_reg_qnt_flatness_thr_9_8 0xA171 -#define reg_qnt_flatness_thr_9_8_pos 0 -#define reg_qnt_flatness_thr_9_8_len 2 -#define reg_qnt_flatness_thr_9_8_lsb 8 -#define xd_p_reg_dca_tone_idx_5_0 0xA171 -#define reg_dca_tone_idx_5_0_pos 2 -#define reg_dca_tone_idx_5_0_len 6 -#define reg_dca_tone_idx_5_0_lsb 0 -#define xd_p_reg_dca_tone_idx_12_6 0xA172 -#define reg_dca_tone_idx_12_6_pos 0 -#define reg_dca_tone_idx_12_6_len 7 -#define reg_dca_tone_idx_12_6_lsb 6 -#define xd_p_reg_dca_data_vld 0xA173 -#define reg_dca_data_vld_pos 0 -#define reg_dca_data_vld_len 1 -#define reg_dca_data_vld_lsb 0 -#define xd_p_reg_dca_read_update 0xA173 -#define reg_dca_read_update_pos 1 -#define reg_dca_read_update_len 1 -#define reg_dca_read_update_lsb 0 -#define xd_r_reg_dca_data_re_5_0 0xA173 -#define reg_dca_data_re_5_0_pos 2 -#define reg_dca_data_re_5_0_len 6 -#define reg_dca_data_re_5_0_lsb 0 -#define xd_r_reg_dca_data_re_10_6 0xA174 -#define reg_dca_data_re_10_6_pos 0 -#define reg_dca_data_re_10_6_len 5 -#define reg_dca_data_re_10_6_lsb 6 -#define xd_r_reg_dca_data_im_7_0 0xA175 -#define reg_dca_data_im_7_0_pos 0 -#define reg_dca_data_im_7_0_len 8 -#define reg_dca_data_im_7_0_lsb 0 -#define xd_r_reg_dca_data_im_10_8 0xA176 -#define reg_dca_data_im_10_8_pos 0 -#define reg_dca_data_im_10_8_len 3 -#define reg_dca_data_im_10_8_lsb 8 -#define xd_r_reg_dca_data_h2_7_0 0xA178 -#define reg_dca_data_h2_7_0_pos 0 -#define reg_dca_data_h2_7_0_len 8 -#define reg_dca_data_h2_7_0_lsb 0 -#define xd_r_reg_dca_data_h2_9_8 0xA179 -#define reg_dca_data_h2_9_8_pos 0 -#define reg_dca_data_h2_9_8_len 2 -#define reg_dca_data_h2_9_8_lsb 8 -#define xd_p_reg_f_adc_7_0 0xA180 -#define reg_f_adc_7_0_pos 0 -#define reg_f_adc_7_0_len 8 -#define reg_f_adc_7_0_lsb 0 -#define xd_p_reg_f_adc_15_8 0xA181 -#define reg_f_adc_15_8_pos 0 -#define reg_f_adc_15_8_len 8 -#define reg_f_adc_15_8_lsb 8 -#define xd_p_reg_f_adc_23_16 0xA182 -#define reg_f_adc_23_16_pos 0 -#define reg_f_adc_23_16_len 8 -#define reg_f_adc_23_16_lsb 16 -#define xd_r_intp_mu_7_0 0xA190 -#define intp_mu_7_0_pos 0 -#define intp_mu_7_0_len 8 -#define intp_mu_7_0_lsb 0 -#define xd_r_intp_mu_15_8 0xA191 -#define intp_mu_15_8_pos 0 -#define intp_mu_15_8_len 8 -#define intp_mu_15_8_lsb 8 -#define xd_r_intp_mu_19_16 0xA192 -#define intp_mu_19_16_pos 0 -#define intp_mu_19_16_len 4 -#define intp_mu_19_16_lsb 16 -#define xd_p_reg_agc_rst 0xA1A0 -#define reg_agc_rst_pos 0 -#define reg_agc_rst_len 1 -#define reg_agc_rst_lsb 0 -#define xd_p_rf_agc_en 0xA1A0 -#define rf_agc_en_pos 1 -#define rf_agc_en_len 1 -#define rf_agc_en_lsb 0 -#define xd_p_rf_agc_dis 0xA1A0 -#define rf_agc_dis_pos 2 -#define rf_agc_dis_len 1 -#define rf_agc_dis_lsb 0 -#define xd_p_if_agc_rst 0xA1A0 -#define if_agc_rst_pos 3 -#define if_agc_rst_len 1 -#define if_agc_rst_lsb 0 -#define xd_p_if_agc_en 0xA1A0 -#define if_agc_en_pos 4 -#define if_agc_en_len 1 -#define if_agc_en_lsb 0 -#define xd_p_if_agc_dis 0xA1A0 -#define if_agc_dis_pos 5 -#define if_agc_dis_len 1 -#define if_agc_dis_lsb 0 -#define xd_p_agc_lock 0xA1A0 -#define agc_lock_pos 6 -#define agc_lock_len 1 -#define agc_lock_lsb 0 -#define xd_p_reg_tinr_rst 0xA1A1 -#define reg_tinr_rst_pos 0 -#define reg_tinr_rst_len 1 -#define reg_tinr_rst_lsb 0 -#define xd_p_reg_tinr_en 0xA1A1 -#define reg_tinr_en_pos 1 -#define reg_tinr_en_len 1 -#define reg_tinr_en_lsb 0 -#define xd_p_reg_ccifs_en 0xA1A2 -#define reg_ccifs_en_pos 0 -#define reg_ccifs_en_len 1 -#define reg_ccifs_en_lsb 0 -#define xd_p_reg_ccifs_dis 0xA1A2 -#define reg_ccifs_dis_pos 1 -#define reg_ccifs_dis_len 1 -#define reg_ccifs_dis_lsb 0 -#define xd_p_reg_ccifs_rst 0xA1A2 -#define reg_ccifs_rst_pos 2 -#define reg_ccifs_rst_len 1 -#define reg_ccifs_rst_lsb 0 -#define xd_p_reg_ccifs_byp 0xA1A2 -#define reg_ccifs_byp_pos 3 -#define reg_ccifs_byp_len 1 -#define reg_ccifs_byp_lsb 0 -#define xd_p_reg_ccif_en 0xA1A3 -#define reg_ccif_en_pos 0 -#define reg_ccif_en_len 1 -#define reg_ccif_en_lsb 0 -#define xd_p_reg_ccif_dis 0xA1A3 -#define reg_ccif_dis_pos 1 -#define reg_ccif_dis_len 1 -#define reg_ccif_dis_lsb 0 -#define xd_p_reg_ccif_rst 0xA1A3 -#define reg_ccif_rst_pos 2 -#define reg_ccif_rst_len 1 -#define reg_ccif_rst_lsb 0 -#define xd_p_reg_ccif_byp 0xA1A3 -#define reg_ccif_byp_pos 3 -#define reg_ccif_byp_len 1 -#define reg_ccif_byp_lsb 0 -#define xd_p_dagc1_rst 0xA1A4 -#define dagc1_rst_pos 0 -#define dagc1_rst_len 1 -#define dagc1_rst_lsb 0 -#define xd_p_dagc1_en 0xA1A4 -#define dagc1_en_pos 1 -#define dagc1_en_len 1 -#define dagc1_en_lsb 0 -#define xd_p_dagc1_mode 0xA1A4 -#define dagc1_mode_pos 2 -#define dagc1_mode_len 2 -#define dagc1_mode_lsb 0 -#define xd_p_dagc1_done 0xA1A4 -#define dagc1_done_pos 4 -#define dagc1_done_len 1 -#define dagc1_done_lsb 0 -#define xd_p_ccid_rst 0xA1A5 -#define ccid_rst_pos 0 -#define ccid_rst_len 1 -#define ccid_rst_lsb 0 -#define xd_p_ccid_en 0xA1A5 -#define ccid_en_pos 1 -#define ccid_en_len 1 -#define ccid_en_lsb 0 -#define xd_p_ccid_mode 0xA1A5 -#define ccid_mode_pos 2 -#define ccid_mode_len 2 -#define ccid_mode_lsb 0 -#define xd_p_ccid_done 0xA1A5 -#define ccid_done_pos 4 -#define ccid_done_len 1 -#define ccid_done_lsb 0 -#define xd_r_ccid_deted 0xA1A5 -#define ccid_deted_pos 5 -#define ccid_deted_len 1 -#define ccid_deted_lsb 0 -#define xd_p_ccid2_en 0xA1A5 -#define ccid2_en_pos 6 -#define ccid2_en_len 1 -#define ccid2_en_lsb 0 -#define xd_p_ccid2_done 0xA1A5 -#define ccid2_done_pos 7 -#define ccid2_done_len 1 -#define ccid2_done_lsb 0 -#define xd_p_reg_bfs_en 0xA1A6 -#define reg_bfs_en_pos 0 -#define reg_bfs_en_len 1 -#define reg_bfs_en_lsb 0 -#define xd_p_reg_bfs_dis 0xA1A6 -#define reg_bfs_dis_pos 1 -#define reg_bfs_dis_len 1 -#define reg_bfs_dis_lsb 0 -#define xd_p_reg_bfs_rst 0xA1A6 -#define reg_bfs_rst_pos 2 -#define reg_bfs_rst_len 1 -#define reg_bfs_rst_lsb 0 -#define xd_p_reg_bfs_byp 0xA1A6 -#define reg_bfs_byp_pos 3 -#define reg_bfs_byp_len 1 -#define reg_bfs_byp_lsb 0 -#define xd_p_reg_antif_en 0xA1A7 -#define reg_antif_en_pos 0 -#define reg_antif_en_len 1 -#define reg_antif_en_lsb 0 -#define xd_p_reg_antif_dis 0xA1A7 -#define reg_antif_dis_pos 1 -#define reg_antif_dis_len 1 -#define reg_antif_dis_lsb 0 -#define xd_p_reg_antif_rst 0xA1A7 -#define reg_antif_rst_pos 2 -#define reg_antif_rst_len 1 -#define reg_antif_rst_lsb 0 -#define xd_p_reg_antif_byp 0xA1A7 -#define reg_antif_byp_pos 3 -#define reg_antif_byp_len 1 -#define reg_antif_byp_lsb 0 -#define xd_p_intp_en 0xA1A8 -#define intp_en_pos 0 -#define intp_en_len 1 -#define intp_en_lsb 0 -#define xd_p_intp_dis 0xA1A8 -#define intp_dis_pos 1 -#define intp_dis_len 1 -#define intp_dis_lsb 0 -#define xd_p_intp_rst 0xA1A8 -#define intp_rst_pos 2 -#define intp_rst_len 1 -#define intp_rst_lsb 0 -#define xd_p_intp_byp 0xA1A8 -#define intp_byp_pos 3 -#define intp_byp_len 1 -#define intp_byp_lsb 0 -#define xd_p_reg_acif_en 0xA1A9 -#define reg_acif_en_pos 0 -#define reg_acif_en_len 1 -#define reg_acif_en_lsb 0 -#define xd_p_reg_acif_dis 0xA1A9 -#define reg_acif_dis_pos 1 -#define reg_acif_dis_len 1 -#define reg_acif_dis_lsb 0 -#define xd_p_reg_acif_rst 0xA1A9 -#define reg_acif_rst_pos 2 -#define reg_acif_rst_len 1 -#define reg_acif_rst_lsb 0 -#define xd_p_reg_acif_byp 0xA1A9 -#define reg_acif_byp_pos 3 -#define reg_acif_byp_len 1 -#define reg_acif_byp_lsb 0 -#define xd_p_reg_acif_sync_mode 0xA1A9 -#define reg_acif_sync_mode_pos 4 -#define reg_acif_sync_mode_len 1 -#define reg_acif_sync_mode_lsb 0 -#define xd_p_dagc2_rst 0xA1AA -#define dagc2_rst_pos 0 -#define dagc2_rst_len 1 -#define dagc2_rst_lsb 0 -#define xd_p_dagc2_en 0xA1AA -#define dagc2_en_pos 1 -#define dagc2_en_len 1 -#define dagc2_en_lsb 0 -#define xd_p_dagc2_mode 0xA1AA -#define dagc2_mode_pos 2 -#define dagc2_mode_len 2 -#define dagc2_mode_lsb 0 -#define xd_p_dagc2_done 0xA1AA -#define dagc2_done_pos 4 -#define dagc2_done_len 1 -#define dagc2_done_lsb 0 -#define xd_p_reg_dca_en 0xA1AB -#define reg_dca_en_pos 0 -#define reg_dca_en_len 1 -#define reg_dca_en_lsb 0 -#define xd_p_dagc2_accumulate_num_2k_7_0 0xA1C0 -#define dagc2_accumulate_num_2k_7_0_pos 0 -#define dagc2_accumulate_num_2k_7_0_len 8 -#define dagc2_accumulate_num_2k_7_0_lsb 0 -#define xd_p_dagc2_accumulate_num_2k_12_8 0xA1C1 -#define dagc2_accumulate_num_2k_12_8_pos 0 -#define dagc2_accumulate_num_2k_12_8_len 5 -#define dagc2_accumulate_num_2k_12_8_lsb 8 -#define xd_p_dagc2_accumulate_num_8k_7_0 0xA1C2 -#define dagc2_accumulate_num_8k_7_0_pos 0 -#define dagc2_accumulate_num_8k_7_0_len 8 -#define dagc2_accumulate_num_8k_7_0_lsb 0 -#define xd_p_dagc2_accumulate_num_8k_12_8 0xA1C3 -#define dagc2_accumulate_num_8k_12_8_pos 0 -#define dagc2_accumulate_num_8k_12_8_len 5 -#define dagc2_accumulate_num_8k_12_8_lsb 8 -#define xd_p_dagc2_desired_level_2_0 0xA1C3 -#define dagc2_desired_level_2_0_pos 5 -#define dagc2_desired_level_2_0_len 3 -#define dagc2_desired_level_2_0_lsb 0 -#define xd_p_dagc2_desired_level_8_3 0xA1C4 -#define dagc2_desired_level_8_3_pos 0 -#define dagc2_desired_level_8_3_len 6 -#define dagc2_desired_level_8_3_lsb 3 -#define xd_p_dagc2_apply_delay 0xA1C5 -#define dagc2_apply_delay_pos 0 -#define dagc2_apply_delay_len 7 -#define dagc2_apply_delay_lsb 0 -#define xd_p_dagc2_bypass_scale_ctl 0xA1C6 -#define dagc2_bypass_scale_ctl_pos 0 -#define dagc2_bypass_scale_ctl_len 3 -#define dagc2_bypass_scale_ctl_lsb 0 -#define xd_p_dagc2_programmable_shift1 0xA1C7 -#define dagc2_programmable_shift1_pos 0 -#define dagc2_programmable_shift1_len 8 -#define dagc2_programmable_shift1_lsb 0 -#define xd_p_dagc2_programmable_shift2 0xA1C8 -#define dagc2_programmable_shift2_pos 0 -#define dagc2_programmable_shift2_len 8 -#define dagc2_programmable_shift2_lsb 0 -#define xd_p_reg_dagc2_in_sat_cnt_7_0 0xA1C9 -#define reg_dagc2_in_sat_cnt_7_0_pos 0 -#define reg_dagc2_in_sat_cnt_7_0_len 8 -#define reg_dagc2_in_sat_cnt_7_0_lsb 0 -#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA -#define reg_dagc2_in_sat_cnt_15_8_pos 0 -#define reg_dagc2_in_sat_cnt_15_8_len 8 -#define reg_dagc2_in_sat_cnt_15_8_lsb 8 -#define xd_p_reg_dagc2_in_sat_cnt_23_16 0xA1CB -#define reg_dagc2_in_sat_cnt_23_16_pos 0 -#define reg_dagc2_in_sat_cnt_23_16_len 8 -#define reg_dagc2_in_sat_cnt_23_16_lsb 16 -#define xd_p_reg_dagc2_in_sat_cnt_31_24 0xA1CC -#define reg_dagc2_in_sat_cnt_31_24_pos 0 -#define reg_dagc2_in_sat_cnt_31_24_len 8 -#define reg_dagc2_in_sat_cnt_31_24_lsb 24 -#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD -#define reg_dagc2_out_sat_cnt_7_0_pos 0 -#define reg_dagc2_out_sat_cnt_7_0_len 8 -#define reg_dagc2_out_sat_cnt_7_0_lsb 0 -#define xd_p_reg_dagc2_out_sat_cnt_15_8 0xA1CE -#define reg_dagc2_out_sat_cnt_15_8_pos 0 -#define reg_dagc2_out_sat_cnt_15_8_len 8 -#define reg_dagc2_out_sat_cnt_15_8_lsb 8 -#define xd_p_reg_dagc2_out_sat_cnt_23_16 0xA1CF -#define reg_dagc2_out_sat_cnt_23_16_pos 0 -#define reg_dagc2_out_sat_cnt_23_16_len 8 -#define reg_dagc2_out_sat_cnt_23_16_lsb 16 -#define xd_p_reg_dagc2_out_sat_cnt_31_24 0xA1D0 -#define reg_dagc2_out_sat_cnt_31_24_pos 0 -#define reg_dagc2_out_sat_cnt_31_24_len 8 -#define reg_dagc2_out_sat_cnt_31_24_lsb 24 -#define xd_r_dagc2_multiplier_7_0 0xA1D6 -#define dagc2_multiplier_7_0_pos 0 -#define dagc2_multiplier_7_0_len 8 -#define dagc2_multiplier_7_0_lsb 0 -#define xd_r_dagc2_multiplier_15_8 0xA1D7 -#define dagc2_multiplier_15_8_pos 0 -#define dagc2_multiplier_15_8_len 8 -#define dagc2_multiplier_15_8_lsb 8 -#define xd_r_dagc2_right_shift_bits 0xA1D8 -#define dagc2_right_shift_bits_pos 0 -#define dagc2_right_shift_bits_len 4 -#define dagc2_right_shift_bits_lsb 0 -#define xd_p_cfoe_NS_coeff1_7_0 0xA200 -#define cfoe_NS_coeff1_7_0_pos 0 -#define cfoe_NS_coeff1_7_0_len 8 -#define cfoe_NS_coeff1_7_0_lsb 0 -#define xd_p_cfoe_NS_coeff1_15_8 0xA201 -#define cfoe_NS_coeff1_15_8_pos 0 -#define cfoe_NS_coeff1_15_8_len 8 -#define cfoe_NS_coeff1_15_8_lsb 8 -#define xd_p_cfoe_NS_coeff1_23_16 0xA202 -#define cfoe_NS_coeff1_23_16_pos 0 -#define cfoe_NS_coeff1_23_16_len 8 -#define cfoe_NS_coeff1_23_16_lsb 16 -#define xd_p_cfoe_NS_coeff1_25_24 0xA203 -#define cfoe_NS_coeff1_25_24_pos 0 -#define cfoe_NS_coeff1_25_24_len 2 -#define cfoe_NS_coeff1_25_24_lsb 24 -#define xd_p_cfoe_NS_coeff2_5_0 0xA203 -#define cfoe_NS_coeff2_5_0_pos 2 -#define cfoe_NS_coeff2_5_0_len 6 -#define cfoe_NS_coeff2_5_0_lsb 0 -#define xd_p_cfoe_NS_coeff2_13_6 0xA204 -#define cfoe_NS_coeff2_13_6_pos 0 -#define cfoe_NS_coeff2_13_6_len 8 -#define cfoe_NS_coeff2_13_6_lsb 6 -#define xd_p_cfoe_NS_coeff2_21_14 0xA205 -#define cfoe_NS_coeff2_21_14_pos 0 -#define cfoe_NS_coeff2_21_14_len 8 -#define cfoe_NS_coeff2_21_14_lsb 14 -#define xd_p_cfoe_NS_coeff2_24_22 0xA206 -#define cfoe_NS_coeff2_24_22_pos 0 -#define cfoe_NS_coeff2_24_22_len 3 -#define cfoe_NS_coeff2_24_22_lsb 22 -#define xd_p_cfoe_lf_c1_4_0 0xA206 -#define cfoe_lf_c1_4_0_pos 3 -#define cfoe_lf_c1_4_0_len 5 -#define cfoe_lf_c1_4_0_lsb 0 -#define xd_p_cfoe_lf_c1_12_5 0xA207 -#define cfoe_lf_c1_12_5_pos 0 -#define cfoe_lf_c1_12_5_len 8 -#define cfoe_lf_c1_12_5_lsb 5 -#define xd_p_cfoe_lf_c1_20_13 0xA208 -#define cfoe_lf_c1_20_13_pos 0 -#define cfoe_lf_c1_20_13_len 8 -#define cfoe_lf_c1_20_13_lsb 13 -#define xd_p_cfoe_lf_c1_25_21 0xA209 -#define cfoe_lf_c1_25_21_pos 0 -#define cfoe_lf_c1_25_21_len 5 -#define cfoe_lf_c1_25_21_lsb 21 -#define xd_p_cfoe_lf_c2_2_0 0xA209 -#define cfoe_lf_c2_2_0_pos 5 -#define cfoe_lf_c2_2_0_len 3 -#define cfoe_lf_c2_2_0_lsb 0 -#define xd_p_cfoe_lf_c2_10_3 0xA20A -#define cfoe_lf_c2_10_3_pos 0 -#define cfoe_lf_c2_10_3_len 8 -#define cfoe_lf_c2_10_3_lsb 3 -#define xd_p_cfoe_lf_c2_18_11 0xA20B -#define cfoe_lf_c2_18_11_pos 0 -#define cfoe_lf_c2_18_11_len 8 -#define cfoe_lf_c2_18_11_lsb 11 -#define xd_p_cfoe_lf_c2_25_19 0xA20C -#define cfoe_lf_c2_25_19_pos 0 -#define cfoe_lf_c2_25_19_len 7 -#define cfoe_lf_c2_25_19_lsb 19 -#define xd_p_cfoe_ifod_7_0 0xA20D -#define cfoe_ifod_7_0_pos 0 -#define cfoe_ifod_7_0_len 8 -#define cfoe_ifod_7_0_lsb 0 -#define xd_p_cfoe_ifod_10_8 0xA20E -#define cfoe_ifod_10_8_pos 0 -#define cfoe_ifod_10_8_len 3 -#define cfoe_ifod_10_8_lsb 8 -#define xd_p_cfoe_Divg_ctr_th 0xA20E -#define cfoe_Divg_ctr_th_pos 4 -#define cfoe_Divg_ctr_th_len 4 -#define cfoe_Divg_ctr_th_lsb 0 -#define xd_p_cfoe_FOT_divg_th 0xA20F -#define cfoe_FOT_divg_th_pos 0 -#define cfoe_FOT_divg_th_len 8 -#define cfoe_FOT_divg_th_lsb 0 -#define xd_p_cfoe_FOT_cnvg_th 0xA210 -#define cfoe_FOT_cnvg_th_pos 0 -#define cfoe_FOT_cnvg_th_len 8 -#define cfoe_FOT_cnvg_th_lsb 0 -#define xd_p_reg_cfoe_offset_7_0 0xA211 -#define reg_cfoe_offset_7_0_pos 0 -#define reg_cfoe_offset_7_0_len 8 -#define reg_cfoe_offset_7_0_lsb 0 -#define xd_p_reg_cfoe_offset_9_8 0xA212 -#define reg_cfoe_offset_9_8_pos 0 -#define reg_cfoe_offset_9_8_len 2 -#define reg_cfoe_offset_9_8_lsb 8 -#define xd_p_reg_cfoe_ifoe_sign_corr 0xA212 -#define reg_cfoe_ifoe_sign_corr_pos 2 -#define reg_cfoe_ifoe_sign_corr_len 1 -#define reg_cfoe_ifoe_sign_corr_lsb 0 -#define xd_r_cfoe_fot_LF_output_7_0 0xA218 -#define cfoe_fot_LF_output_7_0_pos 0 -#define cfoe_fot_LF_output_7_0_len 8 -#define cfoe_fot_LF_output_7_0_lsb 0 -#define xd_r_cfoe_fot_LF_output_15_8 0xA219 -#define cfoe_fot_LF_output_15_8_pos 0 -#define cfoe_fot_LF_output_15_8_len 8 -#define cfoe_fot_LF_output_15_8_lsb 8 -#define xd_r_cfoe_ifo_metric_7_0 0xA21A -#define cfoe_ifo_metric_7_0_pos 0 -#define cfoe_ifo_metric_7_0_len 8 -#define cfoe_ifo_metric_7_0_lsb 0 -#define xd_r_cfoe_ifo_metric_15_8 0xA21B -#define cfoe_ifo_metric_15_8_pos 0 -#define cfoe_ifo_metric_15_8_len 8 -#define cfoe_ifo_metric_15_8_lsb 8 -#define xd_r_cfoe_ifo_metric_23_16 0xA21C -#define cfoe_ifo_metric_23_16_pos 0 -#define cfoe_ifo_metric_23_16_len 8 -#define cfoe_ifo_metric_23_16_lsb 16 -#define xd_p_ste_Nu 0xA220 -#define ste_Nu_pos 0 -#define ste_Nu_len 2 -#define ste_Nu_lsb 0 -#define xd_p_ste_GI 0xA220 -#define ste_GI_pos 2 -#define ste_GI_len 3 -#define ste_GI_lsb 0 -#define xd_p_ste_symbol_num 0xA221 -#define ste_symbol_num_pos 0 -#define ste_symbol_num_len 2 -#define ste_symbol_num_lsb 0 -#define xd_p_ste_sample_num 0xA221 -#define ste_sample_num_pos 2 -#define ste_sample_num_len 2 -#define ste_sample_num_lsb 0 -#define xd_p_reg_ste_buf_en 0xA221 -#define reg_ste_buf_en_pos 7 -#define reg_ste_buf_en_len 1 -#define reg_ste_buf_en_lsb 0 -#define xd_p_ste_FFT_offset_7_0 0xA222 -#define ste_FFT_offset_7_0_pos 0 -#define ste_FFT_offset_7_0_len 8 -#define ste_FFT_offset_7_0_lsb 0 -#define xd_p_ste_FFT_offset_11_8 0xA223 -#define ste_FFT_offset_11_8_pos 0 -#define ste_FFT_offset_11_8_len 4 -#define ste_FFT_offset_11_8_lsb 8 -#define xd_p_reg_ste_tstmod 0xA223 -#define reg_ste_tstmod_pos 5 -#define reg_ste_tstmod_len 1 -#define reg_ste_tstmod_lsb 0 -#define xd_p_ste_adv_start_7_0 0xA224 -#define ste_adv_start_7_0_pos 0 -#define ste_adv_start_7_0_len 8 -#define ste_adv_start_7_0_lsb 0 -#define xd_p_ste_adv_start_10_8 0xA225 -#define ste_adv_start_10_8_pos 0 -#define ste_adv_start_10_8_len 3 -#define ste_adv_start_10_8_lsb 8 -#define xd_p_ste_adv_stop 0xA226 -#define ste_adv_stop_pos 0 -#define ste_adv_stop_len 8 -#define ste_adv_stop_lsb 0 -#define xd_r_ste_P_value_7_0 0xA228 -#define ste_P_value_7_0_pos 0 -#define ste_P_value_7_0_len 8 -#define ste_P_value_7_0_lsb 0 -#define xd_r_ste_P_value_10_8 0xA229 -#define ste_P_value_10_8_pos 0 -#define ste_P_value_10_8_len 3 -#define ste_P_value_10_8_lsb 8 -#define xd_r_ste_M_value_7_0 0xA22A -#define ste_M_value_7_0_pos 0 -#define ste_M_value_7_0_len 8 -#define ste_M_value_7_0_lsb 0 -#define xd_r_ste_M_value_10_8 0xA22B -#define ste_M_value_10_8_pos 0 -#define ste_M_value_10_8_len 3 -#define ste_M_value_10_8_lsb 8 -#define xd_r_ste_H1 0xA22C -#define ste_H1_pos 0 -#define ste_H1_len 7 -#define ste_H1_lsb 0 -#define xd_r_ste_H2 0xA22D -#define ste_H2_pos 0 -#define ste_H2_len 7 -#define ste_H2_lsb 0 -#define xd_r_ste_H3 0xA22E -#define ste_H3_pos 0 -#define ste_H3_len 7 -#define ste_H3_lsb 0 -#define xd_r_ste_H4 0xA22F -#define ste_H4_pos 0 -#define ste_H4_len 7 -#define ste_H4_lsb 0 -#define xd_r_ste_Corr_value_I_7_0 0xA230 -#define ste_Corr_value_I_7_0_pos 0 -#define ste_Corr_value_I_7_0_len 8 -#define ste_Corr_value_I_7_0_lsb 0 -#define xd_r_ste_Corr_value_I_15_8 0xA231 -#define ste_Corr_value_I_15_8_pos 0 -#define ste_Corr_value_I_15_8_len 8 -#define ste_Corr_value_I_15_8_lsb 8 -#define xd_r_ste_Corr_value_I_23_16 0xA232 -#define ste_Corr_value_I_23_16_pos 0 -#define ste_Corr_value_I_23_16_len 8 -#define ste_Corr_value_I_23_16_lsb 16 -#define xd_r_ste_Corr_value_I_27_24 0xA233 -#define ste_Corr_value_I_27_24_pos 0 -#define ste_Corr_value_I_27_24_len 4 -#define ste_Corr_value_I_27_24_lsb 24 -#define xd_r_ste_Corr_value_Q_7_0 0xA234 -#define ste_Corr_value_Q_7_0_pos 0 -#define ste_Corr_value_Q_7_0_len 8 -#define ste_Corr_value_Q_7_0_lsb 0 -#define xd_r_ste_Corr_value_Q_15_8 0xA235 -#define ste_Corr_value_Q_15_8_pos 0 -#define ste_Corr_value_Q_15_8_len 8 -#define ste_Corr_value_Q_15_8_lsb 8 -#define xd_r_ste_Corr_value_Q_23_16 0xA236 -#define ste_Corr_value_Q_23_16_pos 0 -#define ste_Corr_value_Q_23_16_len 8 -#define ste_Corr_value_Q_23_16_lsb 16 -#define xd_r_ste_Corr_value_Q_27_24 0xA237 -#define ste_Corr_value_Q_27_24_pos 0 -#define ste_Corr_value_Q_27_24_len 4 -#define ste_Corr_value_Q_27_24_lsb 24 -#define xd_r_ste_J_num_7_0 0xA238 -#define ste_J_num_7_0_pos 0 -#define ste_J_num_7_0_len 8 -#define ste_J_num_7_0_lsb 0 -#define xd_r_ste_J_num_15_8 0xA239 -#define ste_J_num_15_8_pos 0 -#define ste_J_num_15_8_len 8 -#define ste_J_num_15_8_lsb 8 -#define xd_r_ste_J_num_23_16 0xA23A -#define ste_J_num_23_16_pos 0 -#define ste_J_num_23_16_len 8 -#define ste_J_num_23_16_lsb 16 -#define xd_r_ste_J_num_31_24 0xA23B -#define ste_J_num_31_24_pos 0 -#define ste_J_num_31_24_len 8 -#define ste_J_num_31_24_lsb 24 -#define xd_r_ste_J_den_7_0 0xA23C -#define ste_J_den_7_0_pos 0 -#define ste_J_den_7_0_len 8 -#define ste_J_den_7_0_lsb 0 -#define xd_r_ste_J_den_15_8 0xA23D -#define ste_J_den_15_8_pos 0 -#define ste_J_den_15_8_len 8 -#define ste_J_den_15_8_lsb 8 -#define xd_r_ste_J_den_18_16 0xA23E -#define ste_J_den_18_16_pos 0 -#define ste_J_den_18_16_len 3 -#define ste_J_den_18_16_lsb 16 -#define xd_r_ste_Beacon_Indicator 0xA23E -#define ste_Beacon_Indicator_pos 4 -#define ste_Beacon_Indicator_len 1 -#define ste_Beacon_Indicator_lsb 0 -#define xd_r_tpsd_Frame_Num 0xA250 -#define tpsd_Frame_Num_pos 0 -#define tpsd_Frame_Num_len 2 -#define tpsd_Frame_Num_lsb 0 -#define xd_r_tpsd_Constel 0xA250 -#define tpsd_Constel_pos 2 -#define tpsd_Constel_len 2 -#define tpsd_Constel_lsb 0 -#define xd_r_tpsd_GI 0xA250 -#define tpsd_GI_pos 4 -#define tpsd_GI_len 2 -#define tpsd_GI_lsb 0 -#define xd_r_tpsd_Mode 0xA250 -#define tpsd_Mode_pos 6 -#define tpsd_Mode_len 2 -#define tpsd_Mode_lsb 0 -#define xd_r_tpsd_CR_HP 0xA251 -#define tpsd_CR_HP_pos 0 -#define tpsd_CR_HP_len 3 -#define tpsd_CR_HP_lsb 0 -#define xd_r_tpsd_CR_LP 0xA251 -#define tpsd_CR_LP_pos 3 -#define tpsd_CR_LP_len 3 -#define tpsd_CR_LP_lsb 0 -#define xd_r_tpsd_Hie 0xA252 -#define tpsd_Hie_pos 0 -#define tpsd_Hie_len 3 -#define tpsd_Hie_lsb 0 -#define xd_r_tpsd_Res_Bits 0xA252 -#define tpsd_Res_Bits_pos 3 -#define tpsd_Res_Bits_len 5 -#define tpsd_Res_Bits_lsb 0 -#define xd_r_tpsd_Res_Bits_0 0xA253 -#define tpsd_Res_Bits_0_pos 0 -#define tpsd_Res_Bits_0_len 1 -#define tpsd_Res_Bits_0_lsb 0 -#define xd_r_tpsd_LengthInd 0xA253 -#define tpsd_LengthInd_pos 1 -#define tpsd_LengthInd_len 6 -#define tpsd_LengthInd_lsb 0 -#define xd_r_tpsd_Cell_Id_7_0 0xA254 -#define tpsd_Cell_Id_7_0_pos 0 -#define tpsd_Cell_Id_7_0_len 8 -#define tpsd_Cell_Id_7_0_lsb 0 -#define xd_r_tpsd_Cell_Id_15_8 0xA255 -#define tpsd_Cell_Id_15_8_pos 0 -#define tpsd_Cell_Id_15_8_len 8 -#define tpsd_Cell_Id_15_8_lsb 0 -#define xd_p_reg_fft_mask_tone0_7_0 0xA260 -#define reg_fft_mask_tone0_7_0_pos 0 -#define reg_fft_mask_tone0_7_0_len 8 -#define reg_fft_mask_tone0_7_0_lsb 0 -#define xd_p_reg_fft_mask_tone0_12_8 0xA261 -#define reg_fft_mask_tone0_12_8_pos 0 -#define reg_fft_mask_tone0_12_8_len 5 -#define reg_fft_mask_tone0_12_8_lsb 8 -#define xd_p_reg_fft_mask_tone1_7_0 0xA262 -#define reg_fft_mask_tone1_7_0_pos 0 -#define reg_fft_mask_tone1_7_0_len 8 -#define reg_fft_mask_tone1_7_0_lsb 0 -#define xd_p_reg_fft_mask_tone1_12_8 0xA263 -#define reg_fft_mask_tone1_12_8_pos 0 -#define reg_fft_mask_tone1_12_8_len 5 -#define reg_fft_mask_tone1_12_8_lsb 8 -#define xd_p_reg_fft_mask_tone2_7_0 0xA264 -#define reg_fft_mask_tone2_7_0_pos 0 -#define reg_fft_mask_tone2_7_0_len 8 -#define reg_fft_mask_tone2_7_0_lsb 0 -#define xd_p_reg_fft_mask_tone2_12_8 0xA265 -#define reg_fft_mask_tone2_12_8_pos 0 -#define reg_fft_mask_tone2_12_8_len 5 -#define reg_fft_mask_tone2_12_8_lsb 8 -#define xd_p_reg_fft_mask_tone3_7_0 0xA266 -#define reg_fft_mask_tone3_7_0_pos 0 -#define reg_fft_mask_tone3_7_0_len 8 -#define reg_fft_mask_tone3_7_0_lsb 0 -#define xd_p_reg_fft_mask_tone3_12_8 0xA267 -#define reg_fft_mask_tone3_12_8_pos 0 -#define reg_fft_mask_tone3_12_8_len 5 -#define reg_fft_mask_tone3_12_8_lsb 8 -#define xd_p_reg_fft_mask_from0_7_0 0xA268 -#define reg_fft_mask_from0_7_0_pos 0 -#define reg_fft_mask_from0_7_0_len 8 -#define reg_fft_mask_from0_7_0_lsb 0 -#define xd_p_reg_fft_mask_from0_12_8 0xA269 -#define reg_fft_mask_from0_12_8_pos 0 -#define reg_fft_mask_from0_12_8_len 5 -#define reg_fft_mask_from0_12_8_lsb 8 -#define xd_p_reg_fft_mask_to0_7_0 0xA26A -#define reg_fft_mask_to0_7_0_pos 0 -#define reg_fft_mask_to0_7_0_len 8 -#define reg_fft_mask_to0_7_0_lsb 0 -#define xd_p_reg_fft_mask_to0_12_8 0xA26B -#define reg_fft_mask_to0_12_8_pos 0 -#define reg_fft_mask_to0_12_8_len 5 -#define reg_fft_mask_to0_12_8_lsb 8 -#define xd_p_reg_fft_mask_from1_7_0 0xA26C -#define reg_fft_mask_from1_7_0_pos 0 -#define reg_fft_mask_from1_7_0_len 8 -#define reg_fft_mask_from1_7_0_lsb 0 -#define xd_p_reg_fft_mask_from1_12_8 0xA26D -#define reg_fft_mask_from1_12_8_pos 0 -#define reg_fft_mask_from1_12_8_len 5 -#define reg_fft_mask_from1_12_8_lsb 8 -#define xd_p_reg_fft_mask_to1_7_0 0xA26E -#define reg_fft_mask_to1_7_0_pos 0 -#define reg_fft_mask_to1_7_0_len 8 -#define reg_fft_mask_to1_7_0_lsb 0 -#define xd_p_reg_fft_mask_to1_12_8 0xA26F -#define reg_fft_mask_to1_12_8_pos 0 -#define reg_fft_mask_to1_12_8_len 5 -#define reg_fft_mask_to1_12_8_lsb 8 -#define xd_p_reg_cge_idx0_7_0 0xA280 -#define reg_cge_idx0_7_0_pos 0 -#define reg_cge_idx0_7_0_len 8 -#define reg_cge_idx0_7_0_lsb 0 -#define xd_p_reg_cge_idx0_12_8 0xA281 -#define reg_cge_idx0_12_8_pos 0 -#define reg_cge_idx0_12_8_len 5 -#define reg_cge_idx0_12_8_lsb 8 -#define xd_p_reg_cge_idx1_7_0 0xA282 -#define reg_cge_idx1_7_0_pos 0 -#define reg_cge_idx1_7_0_len 8 -#define reg_cge_idx1_7_0_lsb 0 -#define xd_p_reg_cge_idx1_12_8 0xA283 -#define reg_cge_idx1_12_8_pos 0 -#define reg_cge_idx1_12_8_len 5 -#define reg_cge_idx1_12_8_lsb 8 -#define xd_p_reg_cge_idx2_7_0 0xA284 -#define reg_cge_idx2_7_0_pos 0 -#define reg_cge_idx2_7_0_len 8 -#define reg_cge_idx2_7_0_lsb 0 -#define xd_p_reg_cge_idx2_12_8 0xA285 -#define reg_cge_idx2_12_8_pos 0 -#define reg_cge_idx2_12_8_len 5 -#define reg_cge_idx2_12_8_lsb 8 -#define xd_p_reg_cge_idx3_7_0 0xA286 -#define reg_cge_idx3_7_0_pos 0 -#define reg_cge_idx3_7_0_len 8 -#define reg_cge_idx3_7_0_lsb 0 -#define xd_p_reg_cge_idx3_12_8 0xA287 -#define reg_cge_idx3_12_8_pos 0 -#define reg_cge_idx3_12_8_len 5 -#define reg_cge_idx3_12_8_lsb 8 -#define xd_p_reg_cge_idx4_7_0 0xA288 -#define reg_cge_idx4_7_0_pos 0 -#define reg_cge_idx4_7_0_len 8 -#define reg_cge_idx4_7_0_lsb 0 -#define xd_p_reg_cge_idx4_12_8 0xA289 -#define reg_cge_idx4_12_8_pos 0 -#define reg_cge_idx4_12_8_len 5 -#define reg_cge_idx4_12_8_lsb 8 -#define xd_p_reg_cge_idx5_7_0 0xA28A -#define reg_cge_idx5_7_0_pos 0 -#define reg_cge_idx5_7_0_len 8 -#define reg_cge_idx5_7_0_lsb 0 -#define xd_p_reg_cge_idx5_12_8 0xA28B -#define reg_cge_idx5_12_8_pos 0 -#define reg_cge_idx5_12_8_len 5 -#define reg_cge_idx5_12_8_lsb 8 -#define xd_p_reg_cge_idx6_7_0 0xA28C -#define reg_cge_idx6_7_0_pos 0 -#define reg_cge_idx6_7_0_len 8 -#define reg_cge_idx6_7_0_lsb 0 -#define xd_p_reg_cge_idx6_12_8 0xA28D -#define reg_cge_idx6_12_8_pos 0 -#define reg_cge_idx6_12_8_len 5 -#define reg_cge_idx6_12_8_lsb 8 -#define xd_p_reg_cge_idx7_7_0 0xA28E -#define reg_cge_idx7_7_0_pos 0 -#define reg_cge_idx7_7_0_len 8 -#define reg_cge_idx7_7_0_lsb 0 -#define xd_p_reg_cge_idx7_12_8 0xA28F -#define reg_cge_idx7_12_8_pos 0 -#define reg_cge_idx7_12_8_len 5 -#define reg_cge_idx7_12_8_lsb 8 -#define xd_p_reg_cge_idx8_7_0 0xA290 -#define reg_cge_idx8_7_0_pos 0 -#define reg_cge_idx8_7_0_len 8 -#define reg_cge_idx8_7_0_lsb 0 -#define xd_p_reg_cge_idx8_12_8 0xA291 -#define reg_cge_idx8_12_8_pos 0 -#define reg_cge_idx8_12_8_len 5 -#define reg_cge_idx8_12_8_lsb 8 -#define xd_p_reg_cge_idx9_7_0 0xA292 -#define reg_cge_idx9_7_0_pos 0 -#define reg_cge_idx9_7_0_len 8 -#define reg_cge_idx9_7_0_lsb 0 -#define xd_p_reg_cge_idx9_12_8 0xA293 -#define reg_cge_idx9_12_8_pos 0 -#define reg_cge_idx9_12_8_len 5 -#define reg_cge_idx9_12_8_lsb 8 -#define xd_p_reg_cge_idx10_7_0 0xA294 -#define reg_cge_idx10_7_0_pos 0 -#define reg_cge_idx10_7_0_len 8 -#define reg_cge_idx10_7_0_lsb 0 -#define xd_p_reg_cge_idx10_12_8 0xA295 -#define reg_cge_idx10_12_8_pos 0 -#define reg_cge_idx10_12_8_len 5 -#define reg_cge_idx10_12_8_lsb 8 -#define xd_p_reg_cge_idx11_7_0 0xA296 -#define reg_cge_idx11_7_0_pos 0 -#define reg_cge_idx11_7_0_len 8 -#define reg_cge_idx11_7_0_lsb 0 -#define xd_p_reg_cge_idx11_12_8 0xA297 -#define reg_cge_idx11_12_8_pos 0 -#define reg_cge_idx11_12_8_len 5 -#define reg_cge_idx11_12_8_lsb 8 -#define xd_p_reg_cge_idx12_7_0 0xA298 -#define reg_cge_idx12_7_0_pos 0 -#define reg_cge_idx12_7_0_len 8 -#define reg_cge_idx12_7_0_lsb 0 -#define xd_p_reg_cge_idx12_12_8 0xA299 -#define reg_cge_idx12_12_8_pos 0 -#define reg_cge_idx12_12_8_len 5 -#define reg_cge_idx12_12_8_lsb 8 -#define xd_p_reg_cge_idx13_7_0 0xA29A -#define reg_cge_idx13_7_0_pos 0 -#define reg_cge_idx13_7_0_len 8 -#define reg_cge_idx13_7_0_lsb 0 -#define xd_p_reg_cge_idx13_12_8 0xA29B -#define reg_cge_idx13_12_8_pos 0 -#define reg_cge_idx13_12_8_len 5 -#define reg_cge_idx13_12_8_lsb 8 -#define xd_p_reg_cge_idx14_7_0 0xA29C -#define reg_cge_idx14_7_0_pos 0 -#define reg_cge_idx14_7_0_len 8 -#define reg_cge_idx14_7_0_lsb 0 -#define xd_p_reg_cge_idx14_12_8 0xA29D -#define reg_cge_idx14_12_8_pos 0 -#define reg_cge_idx14_12_8_len 5 -#define reg_cge_idx14_12_8_lsb 8 -#define xd_p_reg_cge_idx15_7_0 0xA29E -#define reg_cge_idx15_7_0_pos 0 -#define reg_cge_idx15_7_0_len 8 -#define reg_cge_idx15_7_0_lsb 0 -#define xd_p_reg_cge_idx15_12_8 0xA29F -#define reg_cge_idx15_12_8_pos 0 -#define reg_cge_idx15_12_8_len 5 -#define reg_cge_idx15_12_8_lsb 8 -#define xd_r_reg_fft_crc 0xA2A8 -#define reg_fft_crc_pos 0 -#define reg_fft_crc_len 8 -#define reg_fft_crc_lsb 0 -#define xd_p_fd_fft_shift_max 0xA2A9 -#define fd_fft_shift_max_pos 0 -#define fd_fft_shift_max_len 4 -#define fd_fft_shift_max_lsb 0 -#define xd_r_fd_fft_shift 0xA2A9 -#define fd_fft_shift_pos 4 -#define fd_fft_shift_len 4 -#define fd_fft_shift_lsb 0 -#define xd_r_fd_fft_frame_num 0xA2AA -#define fd_fft_frame_num_pos 0 -#define fd_fft_frame_num_len 2 -#define fd_fft_frame_num_lsb 0 -#define xd_r_fd_fft_symbol_count 0xA2AB -#define fd_fft_symbol_count_pos 0 -#define fd_fft_symbol_count_len 7 -#define fd_fft_symbol_count_lsb 0 -#define xd_r_reg_fft_idx_max_7_0 0xA2AC -#define reg_fft_idx_max_7_0_pos 0 -#define reg_fft_idx_max_7_0_len 8 -#define reg_fft_idx_max_7_0_lsb 0 -#define xd_r_reg_fft_idx_max_12_8 0xA2AD -#define reg_fft_idx_max_12_8_pos 0 -#define reg_fft_idx_max_12_8_len 5 -#define reg_fft_idx_max_12_8_lsb 8 -#define xd_p_reg_cge_program 0xA2AE -#define reg_cge_program_pos 0 -#define reg_cge_program_len 1 -#define reg_cge_program_lsb 0 -#define xd_p_reg_cge_fixed 0xA2AE -#define reg_cge_fixed_pos 1 -#define reg_cge_fixed_len 1 -#define reg_cge_fixed_lsb 0 -#define xd_p_reg_fft_rotate_en 0xA2AE -#define reg_fft_rotate_en_pos 2 -#define reg_fft_rotate_en_len 1 -#define reg_fft_rotate_en_lsb 0 -#define xd_p_reg_fft_rotate_base_4_0 0xA2AE -#define reg_fft_rotate_base_4_0_pos 3 -#define reg_fft_rotate_base_4_0_len 5 -#define reg_fft_rotate_base_4_0_lsb 0 -#define xd_p_reg_fft_rotate_base_12_5 0xA2AF -#define reg_fft_rotate_base_12_5_pos 0 -#define reg_fft_rotate_base_12_5_len 8 -#define reg_fft_rotate_base_12_5_lsb 5 -#define xd_p_reg_gp_trigger_fd 0xA2B8 -#define reg_gp_trigger_fd_pos 0 -#define reg_gp_trigger_fd_len 1 -#define reg_gp_trigger_fd_lsb 0 -#define xd_p_reg_trigger_sel_fd 0xA2B8 -#define reg_trigger_sel_fd_pos 1 -#define reg_trigger_sel_fd_len 2 -#define reg_trigger_sel_fd_lsb 0 -#define xd_p_reg_trigger_module_sel_fd 0xA2B9 -#define reg_trigger_module_sel_fd_pos 0 -#define reg_trigger_module_sel_fd_len 6 -#define reg_trigger_module_sel_fd_lsb 0 -#define xd_p_reg_trigger_set_sel_fd 0xA2BA -#define reg_trigger_set_sel_fd_pos 0 -#define reg_trigger_set_sel_fd_len 6 -#define reg_trigger_set_sel_fd_lsb 0 -#define xd_p_reg_fd_noname_7_0 0xA2BC -#define reg_fd_noname_7_0_pos 0 -#define reg_fd_noname_7_0_len 8 -#define reg_fd_noname_7_0_lsb 0 -#define xd_p_reg_fd_noname_15_8 0xA2BD -#define reg_fd_noname_15_8_pos 0 -#define reg_fd_noname_15_8_len 8 -#define reg_fd_noname_15_8_lsb 8 -#define xd_p_reg_fd_noname_23_16 0xA2BE -#define reg_fd_noname_23_16_pos 0 -#define reg_fd_noname_23_16_len 8 -#define reg_fd_noname_23_16_lsb 16 -#define xd_p_reg_fd_noname_31_24 0xA2BF -#define reg_fd_noname_31_24_pos 0 -#define reg_fd_noname_31_24_len 8 -#define reg_fd_noname_31_24_lsb 24 -#define xd_r_fd_fpcc_cp_corr_signn 0xA2C0 -#define fd_fpcc_cp_corr_signn_pos 0 -#define fd_fpcc_cp_corr_signn_len 8 -#define fd_fpcc_cp_corr_signn_lsb 0 -#define xd_p_reg_feq_s1 0xA2C1 -#define reg_feq_s1_pos 0 -#define reg_feq_s1_len 5 -#define reg_feq_s1_lsb 0 -#define xd_p_fd_fpcc_cp_corr_tone_th 0xA2C2 -#define fd_fpcc_cp_corr_tone_th_pos 0 -#define fd_fpcc_cp_corr_tone_th_len 6 -#define fd_fpcc_cp_corr_tone_th_lsb 0 -#define xd_p_fd_fpcc_cp_corr_symbol_log_th 0xA2C3 -#define fd_fpcc_cp_corr_symbol_log_th_pos 0 -#define fd_fpcc_cp_corr_symbol_log_th_len 4 -#define fd_fpcc_cp_corr_symbol_log_th_lsb 0 -#define xd_p_fd_fpcc_cp_corr_int 0xA2C4 -#define fd_fpcc_cp_corr_int_pos 0 -#define fd_fpcc_cp_corr_int_len 1 -#define fd_fpcc_cp_corr_int_lsb 0 -#define xd_p_reg_sfoe_ns_7_0 0xA320 -#define reg_sfoe_ns_7_0_pos 0 -#define reg_sfoe_ns_7_0_len 8 -#define reg_sfoe_ns_7_0_lsb 0 -#define xd_p_reg_sfoe_ns_14_8 0xA321 -#define reg_sfoe_ns_14_8_pos 0 -#define reg_sfoe_ns_14_8_len 7 -#define reg_sfoe_ns_14_8_lsb 8 -#define xd_p_reg_sfoe_c1_7_0 0xA322 -#define reg_sfoe_c1_7_0_pos 0 -#define reg_sfoe_c1_7_0_len 8 -#define reg_sfoe_c1_7_0_lsb 0 -#define xd_p_reg_sfoe_c1_15_8 0xA323 -#define reg_sfoe_c1_15_8_pos 0 -#define reg_sfoe_c1_15_8_len 8 -#define reg_sfoe_c1_15_8_lsb 8 -#define xd_p_reg_sfoe_c1_17_16 0xA324 -#define reg_sfoe_c1_17_16_pos 0 -#define reg_sfoe_c1_17_16_len 2 -#define reg_sfoe_c1_17_16_lsb 16 -#define xd_p_reg_sfoe_c2_7_0 0xA325 -#define reg_sfoe_c2_7_0_pos 0 -#define reg_sfoe_c2_7_0_len 8 -#define reg_sfoe_c2_7_0_lsb 0 -#define xd_p_reg_sfoe_c2_15_8 0xA326 -#define reg_sfoe_c2_15_8_pos 0 -#define reg_sfoe_c2_15_8_len 8 -#define reg_sfoe_c2_15_8_lsb 8 -#define xd_p_reg_sfoe_c2_17_16 0xA327 -#define reg_sfoe_c2_17_16_pos 0 -#define reg_sfoe_c2_17_16_len 2 -#define reg_sfoe_c2_17_16_lsb 16 -#define xd_r_reg_sfoe_out_9_2 0xA328 -#define reg_sfoe_out_9_2_pos 0 -#define reg_sfoe_out_9_2_len 8 -#define reg_sfoe_out_9_2_lsb 0 -#define xd_r_reg_sfoe_out_1_0 0xA329 -#define reg_sfoe_out_1_0_pos 0 -#define reg_sfoe_out_1_0_len 2 -#define reg_sfoe_out_1_0_lsb 0 -#define xd_p_reg_sfoe_lm_counter_th 0xA32A -#define reg_sfoe_lm_counter_th_pos 0 -#define reg_sfoe_lm_counter_th_len 4 -#define reg_sfoe_lm_counter_th_lsb 0 -#define xd_p_reg_sfoe_convg_th 0xA32B -#define reg_sfoe_convg_th_pos 0 -#define reg_sfoe_convg_th_len 8 -#define reg_sfoe_convg_th_lsb 0 -#define xd_p_reg_sfoe_divg_th 0xA32C -#define reg_sfoe_divg_th_pos 0 -#define reg_sfoe_divg_th_len 8 -#define reg_sfoe_divg_th_lsb 0 -#define xd_p_fd_tpsd_en 0xA330 -#define fd_tpsd_en_pos 0 -#define fd_tpsd_en_len 1 -#define fd_tpsd_en_lsb 0 -#define xd_p_fd_tpsd_dis 0xA330 -#define fd_tpsd_dis_pos 1 -#define fd_tpsd_dis_len 1 -#define fd_tpsd_dis_lsb 0 -#define xd_p_fd_tpsd_rst 0xA330 -#define fd_tpsd_rst_pos 2 -#define fd_tpsd_rst_len 1 -#define fd_tpsd_rst_lsb 0 -#define xd_p_fd_tpsd_lock 0xA330 -#define fd_tpsd_lock_pos 3 -#define fd_tpsd_lock_len 1 -#define fd_tpsd_lock_lsb 0 -#define xd_r_fd_tpsd_s19 0xA330 -#define fd_tpsd_s19_pos 4 -#define fd_tpsd_s19_len 1 -#define fd_tpsd_s19_lsb 0 -#define xd_r_fd_tpsd_s17 0xA330 -#define fd_tpsd_s17_pos 5 -#define fd_tpsd_s17_len 1 -#define fd_tpsd_s17_lsb 0 -#define xd_p_fd_sfr_ste_en 0xA331 -#define fd_sfr_ste_en_pos 0 -#define fd_sfr_ste_en_len 1 -#define fd_sfr_ste_en_lsb 0 -#define xd_p_fd_sfr_ste_dis 0xA331 -#define fd_sfr_ste_dis_pos 1 -#define fd_sfr_ste_dis_len 1 -#define fd_sfr_ste_dis_lsb 0 -#define xd_p_fd_sfr_ste_rst 0xA331 -#define fd_sfr_ste_rst_pos 2 -#define fd_sfr_ste_rst_len 1 -#define fd_sfr_ste_rst_lsb 0 -#define xd_p_fd_sfr_ste_mode 0xA331 -#define fd_sfr_ste_mode_pos 3 -#define fd_sfr_ste_mode_len 1 -#define fd_sfr_ste_mode_lsb 0 -#define xd_p_fd_sfr_ste_done 0xA331 -#define fd_sfr_ste_done_pos 4 -#define fd_sfr_ste_done_len 1 -#define fd_sfr_ste_done_lsb 0 -#define xd_p_reg_cfoe_ffoe_en 0xA332 -#define reg_cfoe_ffoe_en_pos 0 -#define reg_cfoe_ffoe_en_len 1 -#define reg_cfoe_ffoe_en_lsb 0 -#define xd_p_reg_cfoe_ffoe_dis 0xA332 -#define reg_cfoe_ffoe_dis_pos 1 -#define reg_cfoe_ffoe_dis_len 1 -#define reg_cfoe_ffoe_dis_lsb 0 -#define xd_p_reg_cfoe_ffoe_rst 0xA332 -#define reg_cfoe_ffoe_rst_pos 2 -#define reg_cfoe_ffoe_rst_len 1 -#define reg_cfoe_ffoe_rst_lsb 0 -#define xd_p_reg_cfoe_ifoe_en 0xA332 -#define reg_cfoe_ifoe_en_pos 3 -#define reg_cfoe_ifoe_en_len 1 -#define reg_cfoe_ifoe_en_lsb 0 -#define xd_p_reg_cfoe_ifoe_dis 0xA332 -#define reg_cfoe_ifoe_dis_pos 4 -#define reg_cfoe_ifoe_dis_len 1 -#define reg_cfoe_ifoe_dis_lsb 0 -#define xd_p_reg_cfoe_ifoe_rst 0xA332 -#define reg_cfoe_ifoe_rst_pos 5 -#define reg_cfoe_ifoe_rst_len 1 -#define reg_cfoe_ifoe_rst_lsb 0 -#define xd_p_reg_cfoe_fot_en 0xA332 -#define reg_cfoe_fot_en_pos 6 -#define reg_cfoe_fot_en_len 1 -#define reg_cfoe_fot_en_lsb 0 -#define xd_p_reg_cfoe_fot_lm_en 0xA332 -#define reg_cfoe_fot_lm_en_pos 7 -#define reg_cfoe_fot_lm_en_len 1 -#define reg_cfoe_fot_lm_en_lsb 0 -#define xd_p_reg_cfoe_fot_rst 0xA333 -#define reg_cfoe_fot_rst_pos 0 -#define reg_cfoe_fot_rst_len 1 -#define reg_cfoe_fot_rst_lsb 0 -#define xd_r_fd_cfoe_ffoe_done 0xA333 -#define fd_cfoe_ffoe_done_pos 1 -#define fd_cfoe_ffoe_done_len 1 -#define fd_cfoe_ffoe_done_lsb 0 -#define xd_p_fd_cfoe_metric_vld 0xA333 -#define fd_cfoe_metric_vld_pos 2 -#define fd_cfoe_metric_vld_len 1 -#define fd_cfoe_metric_vld_lsb 0 -#define xd_p_reg_cfoe_ifod_vld 0xA333 -#define reg_cfoe_ifod_vld_pos 3 -#define reg_cfoe_ifod_vld_len 1 -#define reg_cfoe_ifod_vld_lsb 0 -#define xd_r_fd_cfoe_ifoe_done 0xA333 -#define fd_cfoe_ifoe_done_pos 4 -#define fd_cfoe_ifoe_done_len 1 -#define fd_cfoe_ifoe_done_lsb 0 -#define xd_r_fd_cfoe_fot_valid 0xA333 -#define fd_cfoe_fot_valid_pos 5 -#define fd_cfoe_fot_valid_len 1 -#define fd_cfoe_fot_valid_lsb 0 -#define xd_p_reg_cfoe_divg_int 0xA333 -#define reg_cfoe_divg_int_pos 6 -#define reg_cfoe_divg_int_len 1 -#define reg_cfoe_divg_int_lsb 0 -#define xd_r_reg_cfoe_divg_flag 0xA333 -#define reg_cfoe_divg_flag_pos 7 -#define reg_cfoe_divg_flag_len 1 -#define reg_cfoe_divg_flag_lsb 0 -#define xd_p_reg_sfoe_en 0xA334 -#define reg_sfoe_en_pos 0 -#define reg_sfoe_en_len 1 -#define reg_sfoe_en_lsb 0 -#define xd_p_reg_sfoe_dis 0xA334 -#define reg_sfoe_dis_pos 1 -#define reg_sfoe_dis_len 1 -#define reg_sfoe_dis_lsb 0 -#define xd_p_reg_sfoe_rst 0xA334 -#define reg_sfoe_rst_pos 2 -#define reg_sfoe_rst_len 1 -#define reg_sfoe_rst_lsb 0 -#define xd_p_reg_sfoe_vld_int 0xA334 -#define reg_sfoe_vld_int_pos 3 -#define reg_sfoe_vld_int_len 1 -#define reg_sfoe_vld_int_lsb 0 -#define xd_p_reg_sfoe_lm_en 0xA334 -#define reg_sfoe_lm_en_pos 4 -#define reg_sfoe_lm_en_len 1 -#define reg_sfoe_lm_en_lsb 0 -#define xd_p_reg_sfoe_divg_int 0xA334 -#define reg_sfoe_divg_int_pos 5 -#define reg_sfoe_divg_int_len 1 -#define reg_sfoe_divg_int_lsb 0 -#define xd_r_reg_sfoe_divg_flag 0xA334 -#define reg_sfoe_divg_flag_pos 6 -#define reg_sfoe_divg_flag_len 1 -#define reg_sfoe_divg_flag_lsb 0 -#define xd_p_reg_fft_rst 0xA335 -#define reg_fft_rst_pos 0 -#define reg_fft_rst_len 1 -#define reg_fft_rst_lsb 0 -#define xd_p_reg_fft_fast_beacon 0xA335 -#define reg_fft_fast_beacon_pos 1 -#define reg_fft_fast_beacon_len 1 -#define reg_fft_fast_beacon_lsb 0 -#define xd_p_reg_fft_fast_valid 0xA335 -#define reg_fft_fast_valid_pos 2 -#define reg_fft_fast_valid_len 1 -#define reg_fft_fast_valid_lsb 0 -#define xd_p_reg_fft_mask_en 0xA335 -#define reg_fft_mask_en_pos 3 -#define reg_fft_mask_en_len 1 -#define reg_fft_mask_en_lsb 0 -#define xd_p_reg_fft_crc_en 0xA335 -#define reg_fft_crc_en_pos 4 -#define reg_fft_crc_en_len 1 -#define reg_fft_crc_en_lsb 0 -#define xd_p_reg_finr_en 0xA336 -#define reg_finr_en_pos 0 -#define reg_finr_en_len 1 -#define reg_finr_en_lsb 0 -#define xd_p_fd_fste_en 0xA337 -#define fd_fste_en_pos 1 -#define fd_fste_en_len 1 -#define fd_fste_en_lsb 0 -#define xd_p_fd_sqi_tps_level_shift 0xA338 -#define fd_sqi_tps_level_shift_pos 0 -#define fd_sqi_tps_level_shift_len 8 -#define fd_sqi_tps_level_shift_lsb 0 -#define xd_p_fd_pilot_ma_len 0xA339 -#define fd_pilot_ma_len_pos 0 -#define fd_pilot_ma_len_len 6 -#define fd_pilot_ma_len_lsb 0 -#define xd_p_fd_tps_ma_len 0xA33A -#define fd_tps_ma_len_pos 0 -#define fd_tps_ma_len_len 6 -#define fd_tps_ma_len_lsb 0 -#define xd_p_fd_sqi_s3 0xA33B -#define fd_sqi_s3_pos 0 -#define fd_sqi_s3_len 8 -#define fd_sqi_s3_lsb 0 -#define xd_p_fd_sqi_dummy_reg_0 0xA33C -#define fd_sqi_dummy_reg_0_pos 0 -#define fd_sqi_dummy_reg_0_len 1 -#define fd_sqi_dummy_reg_0_lsb 0 -#define xd_p_fd_sqi_debug_sel 0xA33C -#define fd_sqi_debug_sel_pos 1 -#define fd_sqi_debug_sel_len 2 -#define fd_sqi_debug_sel_lsb 0 -#define xd_p_fd_sqi_s2 0xA33C -#define fd_sqi_s2_pos 3 -#define fd_sqi_s2_len 5 -#define fd_sqi_s2_lsb 0 -#define xd_p_fd_sqi_dummy_reg_1 0xA33D -#define fd_sqi_dummy_reg_1_pos 0 -#define fd_sqi_dummy_reg_1_len 1 -#define fd_sqi_dummy_reg_1_lsb 0 -#define xd_p_fd_inr_ignore 0xA33D -#define fd_inr_ignore_pos 1 -#define fd_inr_ignore_len 1 -#define fd_inr_ignore_lsb 0 -#define xd_p_fd_pilot_ignore 0xA33D -#define fd_pilot_ignore_pos 2 -#define fd_pilot_ignore_len 1 -#define fd_pilot_ignore_lsb 0 -#define xd_p_fd_etps_ignore 0xA33D -#define fd_etps_ignore_pos 3 -#define fd_etps_ignore_len 1 -#define fd_etps_ignore_lsb 0 -#define xd_p_fd_sqi_s1 0xA33D -#define fd_sqi_s1_pos 4 -#define fd_sqi_s1_len 4 -#define fd_sqi_s1_lsb 0 -#define xd_p_reg_fste_ehw_7_0 0xA33E -#define reg_fste_ehw_7_0_pos 0 -#define reg_fste_ehw_7_0_len 8 -#define reg_fste_ehw_7_0_lsb 0 -#define xd_p_reg_fste_ehw_9_8 0xA33F -#define reg_fste_ehw_9_8_pos 0 -#define reg_fste_ehw_9_8_len 2 -#define reg_fste_ehw_9_8_lsb 8 -#define xd_p_reg_fste_i_adj_vld 0xA33F -#define reg_fste_i_adj_vld_pos 2 -#define reg_fste_i_adj_vld_len 1 -#define reg_fste_i_adj_vld_lsb 0 -#define xd_p_reg_fste_phase_ini_7_0 0xA340 -#define reg_fste_phase_ini_7_0_pos 0 -#define reg_fste_phase_ini_7_0_len 8 -#define reg_fste_phase_ini_7_0_lsb 0 -#define xd_p_reg_fste_phase_ini_11_8 0xA341 -#define reg_fste_phase_ini_11_8_pos 0 -#define reg_fste_phase_ini_11_8_len 4 -#define reg_fste_phase_ini_11_8_lsb 8 -#define xd_p_reg_fste_phase_inc_3_0 0xA341 -#define reg_fste_phase_inc_3_0_pos 4 -#define reg_fste_phase_inc_3_0_len 4 -#define reg_fste_phase_inc_3_0_lsb 0 -#define xd_p_reg_fste_phase_inc_11_4 0xA342 -#define reg_fste_phase_inc_11_4_pos 0 -#define reg_fste_phase_inc_11_4_len 8 -#define reg_fste_phase_inc_11_4_lsb 4 -#define xd_p_reg_fste_acum_cost_cnt_max 0xA343 -#define reg_fste_acum_cost_cnt_max_pos 0 -#define reg_fste_acum_cost_cnt_max_len 4 -#define reg_fste_acum_cost_cnt_max_lsb 0 -#define xd_p_reg_fste_step_size_std 0xA343 -#define reg_fste_step_size_std_pos 4 -#define reg_fste_step_size_std_len 4 -#define reg_fste_step_size_std_lsb 0 -#define xd_p_reg_fste_step_size_max 0xA344 -#define reg_fste_step_size_max_pos 0 -#define reg_fste_step_size_max_len 4 -#define reg_fste_step_size_max_lsb 0 -#define xd_p_reg_fste_step_size_min 0xA344 -#define reg_fste_step_size_min_pos 4 -#define reg_fste_step_size_min_len 4 -#define reg_fste_step_size_min_lsb 0 -#define xd_p_reg_fste_frac_step_size_7_0 0xA345 -#define reg_fste_frac_step_size_7_0_pos 0 -#define reg_fste_frac_step_size_7_0_len 8 -#define reg_fste_frac_step_size_7_0_lsb 0 -#define xd_p_reg_fste_frac_step_size_15_8 0xA346 -#define reg_fste_frac_step_size_15_8_pos 0 -#define reg_fste_frac_step_size_15_8_len 8 -#define reg_fste_frac_step_size_15_8_lsb 8 -#define xd_p_reg_fste_frac_step_size_19_16 0xA347 -#define reg_fste_frac_step_size_19_16_pos 0 -#define reg_fste_frac_step_size_19_16_len 4 -#define reg_fste_frac_step_size_19_16_lsb 16 -#define xd_p_reg_fste_rpd_dir_cnt_max 0xA347 -#define reg_fste_rpd_dir_cnt_max_pos 4 -#define reg_fste_rpd_dir_cnt_max_len 4 -#define reg_fste_rpd_dir_cnt_max_lsb 0 -#define xd_p_reg_fste_ehs 0xA348 -#define reg_fste_ehs_pos 0 -#define reg_fste_ehs_len 4 -#define reg_fste_ehs_lsb 0 -#define xd_p_reg_fste_frac_cost_cnt_max_3_0 0xA348 -#define reg_fste_frac_cost_cnt_max_3_0_pos 4 -#define reg_fste_frac_cost_cnt_max_3_0_len 4 -#define reg_fste_frac_cost_cnt_max_3_0_lsb 0 -#define xd_p_reg_fste_frac_cost_cnt_max_9_4 0xA349 -#define reg_fste_frac_cost_cnt_max_9_4_pos 0 -#define reg_fste_frac_cost_cnt_max_9_4_len 6 -#define reg_fste_frac_cost_cnt_max_9_4_lsb 4 -#define xd_p_reg_fste_w0_7_0 0xA34A -#define reg_fste_w0_7_0_pos 0 -#define reg_fste_w0_7_0_len 8 -#define reg_fste_w0_7_0_lsb 0 -#define xd_p_reg_fste_w0_11_8 0xA34B -#define reg_fste_w0_11_8_pos 0 -#define reg_fste_w0_11_8_len 4 -#define reg_fste_w0_11_8_lsb 8 -#define xd_p_reg_fste_w1_3_0 0xA34B -#define reg_fste_w1_3_0_pos 4 -#define reg_fste_w1_3_0_len 4 -#define reg_fste_w1_3_0_lsb 0 -#define xd_p_reg_fste_w1_11_4 0xA34C -#define reg_fste_w1_11_4_pos 0 -#define reg_fste_w1_11_4_len 8 -#define reg_fste_w1_11_4_lsb 4 -#define xd_p_reg_fste_w2_7_0 0xA34D -#define reg_fste_w2_7_0_pos 0 -#define reg_fste_w2_7_0_len 8 -#define reg_fste_w2_7_0_lsb 0 -#define xd_p_reg_fste_w2_11_8 0xA34E -#define reg_fste_w2_11_8_pos 0 -#define reg_fste_w2_11_8_len 4 -#define reg_fste_w2_11_8_lsb 8 -#define xd_p_reg_fste_w3_3_0 0xA34E -#define reg_fste_w3_3_0_pos 4 -#define reg_fste_w3_3_0_len 4 -#define reg_fste_w3_3_0_lsb 0 -#define xd_p_reg_fste_w3_11_4 0xA34F -#define reg_fste_w3_11_4_pos 0 -#define reg_fste_w3_11_4_len 8 -#define reg_fste_w3_11_4_lsb 4 -#define xd_p_reg_fste_w4_7_0 0xA350 -#define reg_fste_w4_7_0_pos 0 -#define reg_fste_w4_7_0_len 8 -#define reg_fste_w4_7_0_lsb 0 -#define xd_p_reg_fste_w4_11_8 0xA351 -#define reg_fste_w4_11_8_pos 0 -#define reg_fste_w4_11_8_len 4 -#define reg_fste_w4_11_8_lsb 8 -#define xd_p_reg_fste_w5_3_0 0xA351 -#define reg_fste_w5_3_0_pos 4 -#define reg_fste_w5_3_0_len 4 -#define reg_fste_w5_3_0_lsb 0 -#define xd_p_reg_fste_w5_11_4 0xA352 -#define reg_fste_w5_11_4_pos 0 -#define reg_fste_w5_11_4_len 8 -#define reg_fste_w5_11_4_lsb 4 -#define xd_p_reg_fste_w6_7_0 0xA353 -#define reg_fste_w6_7_0_pos 0 -#define reg_fste_w6_7_0_len 8 -#define reg_fste_w6_7_0_lsb 0 -#define xd_p_reg_fste_w6_11_8 0xA354 -#define reg_fste_w6_11_8_pos 0 -#define reg_fste_w6_11_8_len 4 -#define reg_fste_w6_11_8_lsb 8 -#define xd_p_reg_fste_w7_3_0 0xA354 -#define reg_fste_w7_3_0_pos 4 -#define reg_fste_w7_3_0_len 4 -#define reg_fste_w7_3_0_lsb 0 -#define xd_p_reg_fste_w7_11_4 0xA355 -#define reg_fste_w7_11_4_pos 0 -#define reg_fste_w7_11_4_len 8 -#define reg_fste_w7_11_4_lsb 4 -#define xd_p_reg_fste_w8_7_0 0xA356 -#define reg_fste_w8_7_0_pos 0 -#define reg_fste_w8_7_0_len 8 -#define reg_fste_w8_7_0_lsb 0 -#define xd_p_reg_fste_w8_11_8 0xA357 -#define reg_fste_w8_11_8_pos 0 -#define reg_fste_w8_11_8_len 4 -#define reg_fste_w8_11_8_lsb 8 -#define xd_p_reg_fste_w9_3_0 0xA357 -#define reg_fste_w9_3_0_pos 4 -#define reg_fste_w9_3_0_len 4 -#define reg_fste_w9_3_0_lsb 0 -#define xd_p_reg_fste_w9_11_4 0xA358 -#define reg_fste_w9_11_4_pos 0 -#define reg_fste_w9_11_4_len 8 -#define reg_fste_w9_11_4_lsb 4 -#define xd_p_reg_fste_wa_7_0 0xA359 -#define reg_fste_wa_7_0_pos 0 -#define reg_fste_wa_7_0_len 8 -#define reg_fste_wa_7_0_lsb 0 -#define xd_p_reg_fste_wa_11_8 0xA35A -#define reg_fste_wa_11_8_pos 0 -#define reg_fste_wa_11_8_len 4 -#define reg_fste_wa_11_8_lsb 8 -#define xd_p_reg_fste_wb_3_0 0xA35A -#define reg_fste_wb_3_0_pos 4 -#define reg_fste_wb_3_0_len 4 -#define reg_fste_wb_3_0_lsb 0 -#define xd_p_reg_fste_wb_11_4 0xA35B -#define reg_fste_wb_11_4_pos 0 -#define reg_fste_wb_11_4_len 8 -#define reg_fste_wb_11_4_lsb 4 -#define xd_r_fd_fste_i_adj 0xA35C -#define fd_fste_i_adj_pos 0 -#define fd_fste_i_adj_len 5 -#define fd_fste_i_adj_lsb 0 -#define xd_r_fd_fste_f_adj_7_0 0xA35D -#define fd_fste_f_adj_7_0_pos 0 -#define fd_fste_f_adj_7_0_len 8 -#define fd_fste_f_adj_7_0_lsb 0 -#define xd_r_fd_fste_f_adj_15_8 0xA35E -#define fd_fste_f_adj_15_8_pos 0 -#define fd_fste_f_adj_15_8_len 8 -#define fd_fste_f_adj_15_8_lsb 8 -#define xd_r_fd_fste_f_adj_19_16 0xA35F -#define fd_fste_f_adj_19_16_pos 0 -#define fd_fste_f_adj_19_16_len 4 -#define fd_fste_f_adj_19_16_lsb 16 -#define xd_p_reg_feq_Leak_Bypass 0xA366 -#define reg_feq_Leak_Bypass_pos 0 -#define reg_feq_Leak_Bypass_len 1 -#define reg_feq_Leak_Bypass_lsb 0 -#define xd_p_reg_feq_Leak_Mneg1 0xA366 -#define reg_feq_Leak_Mneg1_pos 1 -#define reg_feq_Leak_Mneg1_len 3 -#define reg_feq_Leak_Mneg1_lsb 0 -#define xd_p_reg_feq_Leak_B_ShiftQ 0xA366 -#define reg_feq_Leak_B_ShiftQ_pos 4 -#define reg_feq_Leak_B_ShiftQ_len 4 -#define reg_feq_Leak_B_ShiftQ_lsb 0 -#define xd_p_reg_feq_Leak_B_Float0 0xA367 -#define reg_feq_Leak_B_Float0_pos 0 -#define reg_feq_Leak_B_Float0_len 8 -#define reg_feq_Leak_B_Float0_lsb 0 -#define xd_p_reg_feq_Leak_B_Float1 0xA368 -#define reg_feq_Leak_B_Float1_pos 0 -#define reg_feq_Leak_B_Float1_len 8 -#define reg_feq_Leak_B_Float1_lsb 0 -#define xd_p_reg_feq_Leak_B_Float2 0xA369 -#define reg_feq_Leak_B_Float2_pos 0 -#define reg_feq_Leak_B_Float2_len 8 -#define reg_feq_Leak_B_Float2_lsb 0 -#define xd_p_reg_feq_Leak_B_Float3 0xA36A -#define reg_feq_Leak_B_Float3_pos 0 -#define reg_feq_Leak_B_Float3_len 8 -#define reg_feq_Leak_B_Float3_lsb 0 -#define xd_p_reg_feq_Leak_B_Float4 0xA36B -#define reg_feq_Leak_B_Float4_pos 0 -#define reg_feq_Leak_B_Float4_len 8 -#define reg_feq_Leak_B_Float4_lsb 0 -#define xd_p_reg_feq_Leak_B_Float5 0xA36C -#define reg_feq_Leak_B_Float5_pos 0 -#define reg_feq_Leak_B_Float5_len 8 -#define reg_feq_Leak_B_Float5_lsb 0 -#define xd_p_reg_feq_Leak_B_Float6 0xA36D -#define reg_feq_Leak_B_Float6_pos 0 -#define reg_feq_Leak_B_Float6_len 8 -#define reg_feq_Leak_B_Float6_lsb 0 -#define xd_p_reg_feq_Leak_B_Float7 0xA36E -#define reg_feq_Leak_B_Float7_pos 0 -#define reg_feq_Leak_B_Float7_len 8 -#define reg_feq_Leak_B_Float7_lsb 0 -#define xd_r_reg_feq_data_h2_7_0 0xA36F -#define reg_feq_data_h2_7_0_pos 0 -#define reg_feq_data_h2_7_0_len 8 -#define reg_feq_data_h2_7_0_lsb 0 -#define xd_r_reg_feq_data_h2_9_8 0xA370 -#define reg_feq_data_h2_9_8_pos 0 -#define reg_feq_data_h2_9_8_len 2 -#define reg_feq_data_h2_9_8_lsb 8 -#define xd_p_reg_feq_leak_use_slice_tps 0xA371 -#define reg_feq_leak_use_slice_tps_pos 0 -#define reg_feq_leak_use_slice_tps_len 1 -#define reg_feq_leak_use_slice_tps_lsb 0 -#define xd_p_reg_feq_read_update 0xA371 -#define reg_feq_read_update_pos 1 -#define reg_feq_read_update_len 1 -#define reg_feq_read_update_lsb 0 -#define xd_p_reg_feq_data_vld 0xA371 -#define reg_feq_data_vld_pos 2 -#define reg_feq_data_vld_len 1 -#define reg_feq_data_vld_lsb 0 -#define xd_p_reg_feq_tone_idx_4_0 0xA371 -#define reg_feq_tone_idx_4_0_pos 3 -#define reg_feq_tone_idx_4_0_len 5 -#define reg_feq_tone_idx_4_0_lsb 0 -#define xd_p_reg_feq_tone_idx_12_5 0xA372 -#define reg_feq_tone_idx_12_5_pos 0 -#define reg_feq_tone_idx_12_5_len 8 -#define reg_feq_tone_idx_12_5_lsb 5 -#define xd_r_reg_feq_data_re_7_0 0xA373 -#define reg_feq_data_re_7_0_pos 0 -#define reg_feq_data_re_7_0_len 8 -#define reg_feq_data_re_7_0_lsb 0 -#define xd_r_reg_feq_data_re_10_8 0xA374 -#define reg_feq_data_re_10_8_pos 0 -#define reg_feq_data_re_10_8_len 3 -#define reg_feq_data_re_10_8_lsb 8 -#define xd_r_reg_feq_data_im_7_0 0xA375 -#define reg_feq_data_im_7_0_pos 0 -#define reg_feq_data_im_7_0_len 8 -#define reg_feq_data_im_7_0_lsb 0 -#define xd_r_reg_feq_data_im_10_8 0xA376 -#define reg_feq_data_im_10_8_pos 0 -#define reg_feq_data_im_10_8_len 3 -#define reg_feq_data_im_10_8_lsb 8 -#define xd_r_reg_feq_y_re 0xA377 -#define reg_feq_y_re_pos 0 -#define reg_feq_y_re_len 8 -#define reg_feq_y_re_lsb 0 -#define xd_r_reg_feq_y_im 0xA378 -#define reg_feq_y_im_pos 0 -#define reg_feq_y_im_len 8 -#define reg_feq_y_im_lsb 0 -#define xd_r_reg_feq_h_re_7_0 0xA379 -#define reg_feq_h_re_7_0_pos 0 -#define reg_feq_h_re_7_0_len 8 -#define reg_feq_h_re_7_0_lsb 0 -#define xd_r_reg_feq_h_re_8 0xA37A -#define reg_feq_h_re_8_pos 0 -#define reg_feq_h_re_8_len 1 -#define reg_feq_h_re_8_lsb 0 -#define xd_r_reg_feq_h_im_7_0 0xA37B -#define reg_feq_h_im_7_0_pos 0 -#define reg_feq_h_im_7_0_len 8 -#define reg_feq_h_im_7_0_lsb 0 -#define xd_r_reg_feq_h_im_8 0xA37C -#define reg_feq_h_im_8_pos 0 -#define reg_feq_h_im_8_len 1 -#define reg_feq_h_im_8_lsb 0 -#define xd_p_fec_super_frm_unit_7_0 0xA380 -#define fec_super_frm_unit_7_0_pos 0 -#define fec_super_frm_unit_7_0_len 8 -#define fec_super_frm_unit_7_0_lsb 0 -#define xd_p_fec_super_frm_unit_15_8 0xA381 -#define fec_super_frm_unit_15_8_pos 0 -#define fec_super_frm_unit_15_8_len 8 -#define fec_super_frm_unit_15_8_lsb 8 -#define xd_r_fec_vtb_err_bit_cnt_7_0 0xA382 -#define fec_vtb_err_bit_cnt_7_0_pos 0 -#define fec_vtb_err_bit_cnt_7_0_len 8 -#define fec_vtb_err_bit_cnt_7_0_lsb 0 -#define xd_r_fec_vtb_err_bit_cnt_15_8 0xA383 -#define fec_vtb_err_bit_cnt_15_8_pos 0 -#define fec_vtb_err_bit_cnt_15_8_len 8 -#define fec_vtb_err_bit_cnt_15_8_lsb 8 -#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384 -#define fec_vtb_err_bit_cnt_23_16_pos 0 -#define fec_vtb_err_bit_cnt_23_16_len 8 -#define fec_vtb_err_bit_cnt_23_16_lsb 16 -#define xd_p_fec_rsd_packet_unit_7_0 0xA385 -#define fec_rsd_packet_unit_7_0_pos 0 -#define fec_rsd_packet_unit_7_0_len 8 -#define fec_rsd_packet_unit_7_0_lsb 0 -#define xd_p_fec_rsd_packet_unit_15_8 0xA386 -#define fec_rsd_packet_unit_15_8_pos 0 -#define fec_rsd_packet_unit_15_8_len 8 -#define fec_rsd_packet_unit_15_8_lsb 8 -#define xd_r_fec_rsd_bit_err_cnt_7_0 0xA387 -#define fec_rsd_bit_err_cnt_7_0_pos 0 -#define fec_rsd_bit_err_cnt_7_0_len 8 -#define fec_rsd_bit_err_cnt_7_0_lsb 0 -#define xd_r_fec_rsd_bit_err_cnt_15_8 0xA388 -#define fec_rsd_bit_err_cnt_15_8_pos 0 -#define fec_rsd_bit_err_cnt_15_8_len 8 -#define fec_rsd_bit_err_cnt_15_8_lsb 8 -#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389 -#define fec_rsd_bit_err_cnt_23_16_pos 0 -#define fec_rsd_bit_err_cnt_23_16_len 8 -#define fec_rsd_bit_err_cnt_23_16_lsb 16 -#define xd_r_fec_rsd_abort_packet_cnt_7_0 0xA38A -#define fec_rsd_abort_packet_cnt_7_0_pos 0 -#define fec_rsd_abort_packet_cnt_7_0_len 8 -#define fec_rsd_abort_packet_cnt_7_0_lsb 0 -#define xd_r_fec_rsd_abort_packet_cnt_15_8 0xA38B -#define fec_rsd_abort_packet_cnt_15_8_pos 0 -#define fec_rsd_abort_packet_cnt_15_8_len 8 -#define fec_rsd_abort_packet_cnt_15_8_lsb 8 -#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0 0xA38C -#define fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0 -#define fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8 -#define fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0 -#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8 0xA38D -#define fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0 -#define fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8 -#define fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8 -#define xd_p_fec_RS_TH_1_7_0 0xA38E -#define fec_RS_TH_1_7_0_pos 0 -#define fec_RS_TH_1_7_0_len 8 -#define fec_RS_TH_1_7_0_lsb 0 -#define xd_p_fec_RS_TH_1_15_8 0xA38F -#define fec_RS_TH_1_15_8_pos 0 -#define fec_RS_TH_1_15_8_len 8 -#define fec_RS_TH_1_15_8_lsb 8 -#define xd_p_fec_RS_TH_2 0xA390 -#define fec_RS_TH_2_pos 0 -#define fec_RS_TH_2_len 8 -#define fec_RS_TH_2_lsb 0 -#define xd_p_fec_mon_en 0xA391 -#define fec_mon_en_pos 0 -#define fec_mon_en_len 1 -#define fec_mon_en_lsb 0 -#define xd_p_reg_b8to47 0xA391 -#define reg_b8to47_pos 1 -#define reg_b8to47_len 1 -#define reg_b8to47_lsb 0 -#define xd_p_reg_rsd_sync_rep 0xA391 -#define reg_rsd_sync_rep_pos 2 -#define reg_rsd_sync_rep_len 1 -#define reg_rsd_sync_rep_lsb 0 -#define xd_p_fec_rsd_retrain_rst 0xA391 -#define fec_rsd_retrain_rst_pos 3 -#define fec_rsd_retrain_rst_len 1 -#define fec_rsd_retrain_rst_lsb 0 -#define xd_r_fec_rsd_ber_rdy 0xA391 -#define fec_rsd_ber_rdy_pos 4 -#define fec_rsd_ber_rdy_len 1 -#define fec_rsd_ber_rdy_lsb 0 -#define xd_p_fec_rsd_ber_rst 0xA391 -#define fec_rsd_ber_rst_pos 5 -#define fec_rsd_ber_rst_len 1 -#define fec_rsd_ber_rst_lsb 0 -#define xd_r_fec_vtb_ber_rdy 0xA391 -#define fec_vtb_ber_rdy_pos 6 -#define fec_vtb_ber_rdy_len 1 -#define fec_vtb_ber_rdy_lsb 0 -#define xd_p_fec_vtb_ber_rst 0xA391 -#define fec_vtb_ber_rst_pos 7 -#define fec_vtb_ber_rst_len 1 -#define fec_vtb_ber_rst_lsb 0 -#define xd_p_reg_vtb_clk40en 0xA392 -#define reg_vtb_clk40en_pos 0 -#define reg_vtb_clk40en_len 1 -#define reg_vtb_clk40en_lsb 0 -#define xd_p_fec_vtb_rsd_mon_en 0xA392 -#define fec_vtb_rsd_mon_en_pos 1 -#define fec_vtb_rsd_mon_en_len 1 -#define fec_vtb_rsd_mon_en_lsb 0 -#define xd_p_reg_fec_data_en 0xA392 -#define reg_fec_data_en_pos 2 -#define reg_fec_data_en_len 1 -#define reg_fec_data_en_lsb 0 -#define xd_p_fec_dummy_reg_2 0xA392 -#define fec_dummy_reg_2_pos 3 -#define fec_dummy_reg_2_len 3 -#define fec_dummy_reg_2_lsb 0 -#define xd_p_reg_sync_chk 0xA392 -#define reg_sync_chk_pos 6 -#define reg_sync_chk_len 1 -#define reg_sync_chk_lsb 0 -#define xd_p_fec_rsd_bypass 0xA392 -#define fec_rsd_bypass_pos 7 -#define fec_rsd_bypass_len 1 -#define fec_rsd_bypass_lsb 0 -#define xd_p_fec_sw_rst 0xA393 -#define fec_sw_rst_pos 0 -#define fec_sw_rst_len 1 -#define fec_sw_rst_lsb 0 -#define xd_r_fec_vtb_pm_crc 0xA394 -#define fec_vtb_pm_crc_pos 0 -#define fec_vtb_pm_crc_len 8 -#define fec_vtb_pm_crc_lsb 0 -#define xd_r_fec_vtb_tb_7_crc 0xA395 -#define fec_vtb_tb_7_crc_pos 0 -#define fec_vtb_tb_7_crc_len 8 -#define fec_vtb_tb_7_crc_lsb 0 -#define xd_r_fec_vtb_tb_6_crc 0xA396 -#define fec_vtb_tb_6_crc_pos 0 -#define fec_vtb_tb_6_crc_len 8 -#define fec_vtb_tb_6_crc_lsb 0 -#define xd_r_fec_vtb_tb_5_crc 0xA397 -#define fec_vtb_tb_5_crc_pos 0 -#define fec_vtb_tb_5_crc_len 8 -#define fec_vtb_tb_5_crc_lsb 0 -#define xd_r_fec_vtb_tb_4_crc 0xA398 -#define fec_vtb_tb_4_crc_pos 0 -#define fec_vtb_tb_4_crc_len 8 -#define fec_vtb_tb_4_crc_lsb 0 -#define xd_r_fec_vtb_tb_3_crc 0xA399 -#define fec_vtb_tb_3_crc_pos 0 -#define fec_vtb_tb_3_crc_len 8 -#define fec_vtb_tb_3_crc_lsb 0 -#define xd_r_fec_vtb_tb_2_crc 0xA39A -#define fec_vtb_tb_2_crc_pos 0 -#define fec_vtb_tb_2_crc_len 8 -#define fec_vtb_tb_2_crc_lsb 0 -#define xd_r_fec_vtb_tb_1_crc 0xA39B -#define fec_vtb_tb_1_crc_pos 0 -#define fec_vtb_tb_1_crc_len 8 -#define fec_vtb_tb_1_crc_lsb 0 -#define xd_r_fec_vtb_tb_0_crc 0xA39C -#define fec_vtb_tb_0_crc_pos 0 -#define fec_vtb_tb_0_crc_len 8 -#define fec_vtb_tb_0_crc_lsb 0 -#define xd_r_fec_rsd_bank0_crc 0xA39D -#define fec_rsd_bank0_crc_pos 0 -#define fec_rsd_bank0_crc_len 8 -#define fec_rsd_bank0_crc_lsb 0 -#define xd_r_fec_rsd_bank1_crc 0xA39E -#define fec_rsd_bank1_crc_pos 0 -#define fec_rsd_bank1_crc_len 8 -#define fec_rsd_bank1_crc_lsb 0 -#define xd_r_fec_idi_vtb_crc 0xA39F -#define fec_idi_vtb_crc_pos 0 -#define fec_idi_vtb_crc_len 8 -#define fec_idi_vtb_crc_lsb 0 -#define xd_g_reg_tpsd_txmod 0xA3C0 -#define reg_tpsd_txmod_pos 0 -#define reg_tpsd_txmod_len 2 -#define reg_tpsd_txmod_lsb 0 -#define xd_g_reg_tpsd_gi 0xA3C0 -#define reg_tpsd_gi_pos 2 -#define reg_tpsd_gi_len 2 -#define reg_tpsd_gi_lsb 0 -#define xd_g_reg_tpsd_hier 0xA3C0 -#define reg_tpsd_hier_pos 4 -#define reg_tpsd_hier_len 3 -#define reg_tpsd_hier_lsb 0 -#define xd_g_reg_bw 0xA3C1 -#define reg_bw_pos 2 -#define reg_bw_len 2 -#define reg_bw_lsb 0 -#define xd_g_reg_dec_pri 0xA3C1 -#define reg_dec_pri_pos 4 -#define reg_dec_pri_len 1 -#define reg_dec_pri_lsb 0 -#define xd_g_reg_tpsd_const 0xA3C1 -#define reg_tpsd_const_pos 6 -#define reg_tpsd_const_len 2 -#define reg_tpsd_const_lsb 0 -#define xd_g_reg_tpsd_hpcr 0xA3C2 -#define reg_tpsd_hpcr_pos 0 -#define reg_tpsd_hpcr_len 3 -#define reg_tpsd_hpcr_lsb 0 -#define xd_g_reg_tpsd_lpcr 0xA3C2 -#define reg_tpsd_lpcr_pos 3 -#define reg_tpsd_lpcr_len 3 -#define reg_tpsd_lpcr_lsb 0 -#define xd_g_reg_ofsm_clk 0xA3D0 -#define reg_ofsm_clk_pos 0 -#define reg_ofsm_clk_len 3 -#define reg_ofsm_clk_lsb 0 -#define xd_g_reg_fclk_cfg 0xA3D1 -#define reg_fclk_cfg_pos 0 -#define reg_fclk_cfg_len 1 -#define reg_fclk_cfg_lsb 0 -#define xd_g_reg_fclk_idi 0xA3D1 -#define reg_fclk_idi_pos 1 -#define reg_fclk_idi_len 1 -#define reg_fclk_idi_lsb 0 -#define xd_g_reg_fclk_odi 0xA3D1 -#define reg_fclk_odi_pos 2 -#define reg_fclk_odi_len 1 -#define reg_fclk_odi_lsb 0 -#define xd_g_reg_fclk_rsd 0xA3D1 -#define reg_fclk_rsd_pos 3 -#define reg_fclk_rsd_len 1 -#define reg_fclk_rsd_lsb 0 -#define xd_g_reg_fclk_vtb 0xA3D1 -#define reg_fclk_vtb_pos 4 -#define reg_fclk_vtb_len 1 -#define reg_fclk_vtb_lsb 0 -#define xd_g_reg_fclk_cste 0xA3D1 -#define reg_fclk_cste_pos 5 -#define reg_fclk_cste_len 1 -#define reg_fclk_cste_lsb 0 -#define xd_g_reg_fclk_mp2if 0xA3D1 -#define reg_fclk_mp2if_pos 6 -#define reg_fclk_mp2if_len 1 -#define reg_fclk_mp2if_lsb 0 -#define xd_I2C_i2c_m_slave_addr 0xA400 -#define i2c_m_slave_addr_pos 0 -#define i2c_m_slave_addr_len 8 -#define i2c_m_slave_addr_lsb 0 -#define xd_I2C_i2c_m_data1 0xA401 -#define i2c_m_data1_pos 0 -#define i2c_m_data1_len 8 -#define i2c_m_data1_lsb 0 -#define xd_I2C_i2c_m_data2 0xA402 -#define i2c_m_data2_pos 0 -#define i2c_m_data2_len 8 -#define i2c_m_data2_lsb 0 -#define xd_I2C_i2c_m_data3 0xA403 -#define i2c_m_data3_pos 0 -#define i2c_m_data3_len 8 -#define i2c_m_data3_lsb 0 -#define xd_I2C_i2c_m_data4 0xA404 -#define i2c_m_data4_pos 0 -#define i2c_m_data4_len 8 -#define i2c_m_data4_lsb 0 -#define xd_I2C_i2c_m_data5 0xA405 -#define i2c_m_data5_pos 0 -#define i2c_m_data5_len 8 -#define i2c_m_data5_lsb 0 -#define xd_I2C_i2c_m_data6 0xA406 -#define i2c_m_data6_pos 0 -#define i2c_m_data6_len 8 -#define i2c_m_data6_lsb 0 -#define xd_I2C_i2c_m_data7 0xA407 -#define i2c_m_data7_pos 0 -#define i2c_m_data7_len 8 -#define i2c_m_data7_lsb 0 -#define xd_I2C_i2c_m_data8 0xA408 -#define i2c_m_data8_pos 0 -#define i2c_m_data8_len 8 -#define i2c_m_data8_lsb 0 -#define xd_I2C_i2c_m_data9 0xA409 -#define i2c_m_data9_pos 0 -#define i2c_m_data9_len 8 -#define i2c_m_data9_lsb 0 -#define xd_I2C_i2c_m_data10 0xA40A -#define i2c_m_data10_pos 0 -#define i2c_m_data10_len 8 -#define i2c_m_data10_lsb 0 -#define xd_I2C_i2c_m_data11 0xA40B -#define i2c_m_data11_pos 0 -#define i2c_m_data11_len 8 -#define i2c_m_data11_lsb 0 -#define xd_I2C_i2c_m_cmd_rw 0xA40C -#define i2c_m_cmd_rw_pos 0 -#define i2c_m_cmd_rw_len 1 -#define i2c_m_cmd_rw_lsb 0 -#define xd_I2C_i2c_m_cmd_rwlen 0xA40C -#define i2c_m_cmd_rwlen_pos 3 -#define i2c_m_cmd_rwlen_len 4 -#define i2c_m_cmd_rwlen_lsb 0 -#define xd_I2C_i2c_m_status_cmd_exe 0xA40D -#define i2c_m_status_cmd_exe_pos 0 -#define i2c_m_status_cmd_exe_len 1 -#define i2c_m_status_cmd_exe_lsb 0 -#define xd_I2C_i2c_m_status_wdat_done 0xA40D -#define i2c_m_status_wdat_done_pos 1 -#define i2c_m_status_wdat_done_len 1 -#define i2c_m_status_wdat_done_lsb 0 -#define xd_I2C_i2c_m_status_wdat_fail 0xA40D -#define i2c_m_status_wdat_fail_pos 2 -#define i2c_m_status_wdat_fail_len 1 -#define i2c_m_status_wdat_fail_lsb 0 -#define xd_I2C_i2c_m_period 0xA40E -#define i2c_m_period_pos 0 -#define i2c_m_period_len 8 -#define i2c_m_period_lsb 0 -#define xd_I2C_i2c_m_reg_msb_lsb 0xA40F -#define i2c_m_reg_msb_lsb_pos 0 -#define i2c_m_reg_msb_lsb_len 1 -#define i2c_m_reg_msb_lsb_lsb 0 -#define xd_I2C_reg_ofdm_rst 0xA40F -#define reg_ofdm_rst_pos 1 -#define reg_ofdm_rst_len 1 -#define reg_ofdm_rst_lsb 0 -#define xd_I2C_reg_sample_period_on_tuner 0xA40F -#define reg_sample_period_on_tuner_pos 2 -#define reg_sample_period_on_tuner_len 1 -#define reg_sample_period_on_tuner_lsb 0 -#define xd_I2C_reg_rst_i2c 0xA40F -#define reg_rst_i2c_pos 3 -#define reg_rst_i2c_len 1 -#define reg_rst_i2c_lsb 0 -#define xd_I2C_reg_ofdm_rst_en 0xA40F -#define reg_ofdm_rst_en_pos 4 -#define reg_ofdm_rst_en_len 1 -#define reg_ofdm_rst_en_lsb 0 -#define xd_I2C_reg_tuner_sda_sync_on 0xA40F -#define reg_tuner_sda_sync_on_pos 5 -#define reg_tuner_sda_sync_on_len 1 -#define reg_tuner_sda_sync_on_lsb 0 -#define xd_p_mp2if_data_access_disable_ofsm 0xA500 -#define mp2if_data_access_disable_ofsm_pos 0 -#define mp2if_data_access_disable_ofsm_len 1 -#define mp2if_data_access_disable_ofsm_lsb 0 -#define xd_p_reg_mp2_sw_rst_ofsm 0xA500 -#define reg_mp2_sw_rst_ofsm_pos 1 -#define reg_mp2_sw_rst_ofsm_len 1 -#define reg_mp2_sw_rst_ofsm_lsb 0 -#define xd_p_reg_mp2if_clk_en_ofsm 0xA500 -#define reg_mp2if_clk_en_ofsm_pos 2 -#define reg_mp2if_clk_en_ofsm_len 1 -#define reg_mp2if_clk_en_ofsm_lsb 0 -#define xd_r_mp2if_sync_byte_locked 0xA500 -#define mp2if_sync_byte_locked_pos 3 -#define mp2if_sync_byte_locked_len 1 -#define mp2if_sync_byte_locked_lsb 0 -#define xd_r_mp2if_ts_not_188 0xA500 -#define mp2if_ts_not_188_pos 4 -#define mp2if_ts_not_188_len 1 -#define mp2if_ts_not_188_lsb 0 -#define xd_r_mp2if_psb_empty 0xA500 -#define mp2if_psb_empty_pos 5 -#define mp2if_psb_empty_len 1 -#define mp2if_psb_empty_lsb 0 -#define xd_r_mp2if_psb_overflow 0xA500 -#define mp2if_psb_overflow_pos 6 -#define mp2if_psb_overflow_len 1 -#define mp2if_psb_overflow_lsb 0 -#define xd_p_mp2if_keep_sf_sync_byte_ofsm 0xA500 -#define mp2if_keep_sf_sync_byte_ofsm_pos 7 -#define mp2if_keep_sf_sync_byte_ofsm_len 1 -#define mp2if_keep_sf_sync_byte_ofsm_lsb 0 -#define xd_r_mp2if_psb_mp2if_num_pkt 0xA501 -#define mp2if_psb_mp2if_num_pkt_pos 0 -#define mp2if_psb_mp2if_num_pkt_len 6 -#define mp2if_psb_mp2if_num_pkt_lsb 0 -#define xd_p_reg_mpeg_full_speed_ofsm 0xA501 -#define reg_mpeg_full_speed_ofsm_pos 6 -#define reg_mpeg_full_speed_ofsm_len 1 -#define reg_mpeg_full_speed_ofsm_lsb 0 -#define xd_p_mp2if_mpeg_ser_mode_ofsm 0xA501 -#define mp2if_mpeg_ser_mode_ofsm_pos 7 -#define mp2if_mpeg_ser_mode_ofsm_len 1 -#define mp2if_mpeg_ser_mode_ofsm_lsb 0 -#define xd_p_reg_sw_mon51 0xA600 -#define reg_sw_mon51_pos 0 -#define reg_sw_mon51_len 8 -#define reg_sw_mon51_lsb 0 -#define xd_p_reg_top_pcsel 0xA601 -#define reg_top_pcsel_pos 0 -#define reg_top_pcsel_len 1 -#define reg_top_pcsel_lsb 0 -#define xd_p_reg_top_rs232 0xA601 -#define reg_top_rs232_pos 1 -#define reg_top_rs232_len 1 -#define reg_top_rs232_lsb 0 -#define xd_p_reg_top_pcout 0xA601 -#define reg_top_pcout_pos 2 -#define reg_top_pcout_len 1 -#define reg_top_pcout_lsb 0 -#define xd_p_reg_top_debug 0xA601 -#define reg_top_debug_pos 3 -#define reg_top_debug_len 1 -#define reg_top_debug_lsb 0 -#define xd_p_reg_top_adcdly 0xA601 -#define reg_top_adcdly_pos 4 -#define reg_top_adcdly_len 2 -#define reg_top_adcdly_lsb 0 -#define xd_p_reg_top_pwrdw 0xA601 -#define reg_top_pwrdw_pos 6 -#define reg_top_pwrdw_len 1 -#define reg_top_pwrdw_lsb 0 -#define xd_p_reg_top_pwrdw_inv 0xA601 -#define reg_top_pwrdw_inv_pos 7 -#define reg_top_pwrdw_inv_len 1 -#define reg_top_pwrdw_inv_lsb 0 -#define xd_p_reg_top_int_inv 0xA602 -#define reg_top_int_inv_pos 0 -#define reg_top_int_inv_len 1 -#define reg_top_int_inv_lsb 0 -#define xd_p_reg_top_dio_sel 0xA602 -#define reg_top_dio_sel_pos 1 -#define reg_top_dio_sel_len 1 -#define reg_top_dio_sel_lsb 0 -#define xd_p_reg_top_gpioon0 0xA603 -#define reg_top_gpioon0_pos 0 -#define reg_top_gpioon0_len 1 -#define reg_top_gpioon0_lsb 0 -#define xd_p_reg_top_gpioon1 0xA603 -#define reg_top_gpioon1_pos 1 -#define reg_top_gpioon1_len 1 -#define reg_top_gpioon1_lsb 0 -#define xd_p_reg_top_gpioon2 0xA603 -#define reg_top_gpioon2_pos 2 -#define reg_top_gpioon2_len 1 -#define reg_top_gpioon2_lsb 0 -#define xd_p_reg_top_gpioon3 0xA603 -#define reg_top_gpioon3_pos 3 -#define reg_top_gpioon3_len 1 -#define reg_top_gpioon3_lsb 0 -#define xd_p_reg_top_lockon1 0xA603 -#define reg_top_lockon1_pos 4 -#define reg_top_lockon1_len 1 -#define reg_top_lockon1_lsb 0 -#define xd_p_reg_top_lockon2 0xA603 -#define reg_top_lockon2_pos 5 -#define reg_top_lockon2_len 1 -#define reg_top_lockon2_lsb 0 -#define xd_p_reg_top_gpioo0 0xA604 -#define reg_top_gpioo0_pos 0 -#define reg_top_gpioo0_len 1 -#define reg_top_gpioo0_lsb 0 -#define xd_p_reg_top_gpioo1 0xA604 -#define reg_top_gpioo1_pos 1 -#define reg_top_gpioo1_len 1 -#define reg_top_gpioo1_lsb 0 -#define xd_p_reg_top_gpioo2 0xA604 -#define reg_top_gpioo2_pos 2 -#define reg_top_gpioo2_len 1 -#define reg_top_gpioo2_lsb 0 -#define xd_p_reg_top_gpioo3 0xA604 -#define reg_top_gpioo3_pos 3 -#define reg_top_gpioo3_len 1 -#define reg_top_gpioo3_lsb 0 -#define xd_p_reg_top_lock1 0xA604 -#define reg_top_lock1_pos 4 -#define reg_top_lock1_len 1 -#define reg_top_lock1_lsb 0 -#define xd_p_reg_top_lock2 0xA604 -#define reg_top_lock2_pos 5 -#define reg_top_lock2_len 1 -#define reg_top_lock2_lsb 0 -#define xd_p_reg_top_gpioen0 0xA605 -#define reg_top_gpioen0_pos 0 -#define reg_top_gpioen0_len 1 -#define reg_top_gpioen0_lsb 0 -#define xd_p_reg_top_gpioen1 0xA605 -#define reg_top_gpioen1_pos 1 -#define reg_top_gpioen1_len 1 -#define reg_top_gpioen1_lsb 0 -#define xd_p_reg_top_gpioen2 0xA605 -#define reg_top_gpioen2_pos 2 -#define reg_top_gpioen2_len 1 -#define reg_top_gpioen2_lsb 0 -#define xd_p_reg_top_gpioen3 0xA605 -#define reg_top_gpioen3_pos 3 -#define reg_top_gpioen3_len 1 -#define reg_top_gpioen3_lsb 0 -#define xd_p_reg_top_locken1 0xA605 -#define reg_top_locken1_pos 4 -#define reg_top_locken1_len 1 -#define reg_top_locken1_lsb 0 -#define xd_p_reg_top_locken2 0xA605 -#define reg_top_locken2_pos 5 -#define reg_top_locken2_len 1 -#define reg_top_locken2_lsb 0 -#define xd_r_reg_top_gpioi0 0xA606 -#define reg_top_gpioi0_pos 0 -#define reg_top_gpioi0_len 1 -#define reg_top_gpioi0_lsb 0 -#define xd_r_reg_top_gpioi1 0xA606 -#define reg_top_gpioi1_pos 1 -#define reg_top_gpioi1_len 1 -#define reg_top_gpioi1_lsb 0 -#define xd_r_reg_top_gpioi2 0xA606 -#define reg_top_gpioi2_pos 2 -#define reg_top_gpioi2_len 1 -#define reg_top_gpioi2_lsb 0 -#define xd_r_reg_top_gpioi3 0xA606 -#define reg_top_gpioi3_pos 3 -#define reg_top_gpioi3_len 1 -#define reg_top_gpioi3_lsb 0 -#define xd_r_reg_top_locki1 0xA606 -#define reg_top_locki1_pos 4 -#define reg_top_locki1_len 1 -#define reg_top_locki1_lsb 0 -#define xd_r_reg_top_locki2 0xA606 -#define reg_top_locki2_pos 5 -#define reg_top_locki2_len 1 -#define reg_top_locki2_lsb 0 -#define xd_p_reg_dummy_7_0 0xA608 -#define reg_dummy_7_0_pos 0 -#define reg_dummy_7_0_len 8 -#define reg_dummy_7_0_lsb 0 -#define xd_p_reg_dummy_15_8 0xA609 -#define reg_dummy_15_8_pos 0 -#define reg_dummy_15_8_len 8 -#define reg_dummy_15_8_lsb 8 -#define xd_p_reg_dummy_23_16 0xA60A -#define reg_dummy_23_16_pos 0 -#define reg_dummy_23_16_len 8 -#define reg_dummy_23_16_lsb 16 -#define xd_p_reg_dummy_31_24 0xA60B -#define reg_dummy_31_24_pos 0 -#define reg_dummy_31_24_len 8 -#define reg_dummy_31_24_lsb 24 -#define xd_p_reg_dummy_39_32 0xA60C -#define reg_dummy_39_32_pos 0 -#define reg_dummy_39_32_len 8 -#define reg_dummy_39_32_lsb 32 -#define xd_p_reg_dummy_47_40 0xA60D -#define reg_dummy_47_40_pos 0 -#define reg_dummy_47_40_len 8 -#define reg_dummy_47_40_lsb 40 -#define xd_p_reg_dummy_55_48 0xA60E -#define reg_dummy_55_48_pos 0 -#define reg_dummy_55_48_len 8 -#define reg_dummy_55_48_lsb 48 -#define xd_p_reg_dummy_63_56 0xA60F -#define reg_dummy_63_56_pos 0 -#define reg_dummy_63_56_len 8 -#define reg_dummy_63_56_lsb 56 -#define xd_p_reg_dummy_71_64 0xA610 -#define reg_dummy_71_64_pos 0 -#define reg_dummy_71_64_len 8 -#define reg_dummy_71_64_lsb 64 -#define xd_p_reg_dummy_79_72 0xA611 -#define reg_dummy_79_72_pos 0 -#define reg_dummy_79_72_len 8 -#define reg_dummy_79_72_lsb 72 -#define xd_p_reg_dummy_87_80 0xA612 -#define reg_dummy_87_80_pos 0 -#define reg_dummy_87_80_len 8 -#define reg_dummy_87_80_lsb 80 -#define xd_p_reg_dummy_95_88 0xA613 -#define reg_dummy_95_88_pos 0 -#define reg_dummy_95_88_len 8 -#define reg_dummy_95_88_lsb 88 -#define xd_p_reg_dummy_103_96 0xA614 -#define reg_dummy_103_96_pos 0 -#define reg_dummy_103_96_len 8 -#define reg_dummy_103_96_lsb 96 - -#define xd_p_reg_unplug_flag 0xA615 -#define reg_unplug_flag_pos 0 -#define reg_unplug_flag_len 1 -#define reg_unplug_flag_lsb 104 - -#define xd_p_reg_api_dca_stes_request 0xA615 -#define reg_api_dca_stes_request_pos 1 -#define reg_api_dca_stes_request_len 1 -#define reg_api_dca_stes_request_lsb 0 - -#define xd_p_reg_back_to_dca_flag 0xA615 -#define reg_back_to_dca_flag_pos 2 -#define reg_back_to_dca_flag_len 1 -#define reg_back_to_dca_flag_lsb 106 - -#define xd_p_reg_api_retrain_request 0xA615 -#define reg_api_retrain_request_pos 3 -#define reg_api_retrain_request_len 1 -#define reg_api_retrain_request_lsb 0 - -#define xd_p_reg_Dyn_Top_Try_flag 0xA615 -#define reg_Dyn_Top_Try_flag_pos 3 -#define reg_Dyn_Top_Try_flag_len 1 -#define reg_Dyn_Top_Try_flag_lsb 107 - -#define xd_p_reg_API_retrain_freeze_flag 0xA615 -#define reg_API_retrain_freeze_flag_pos 4 -#define reg_API_retrain_freeze_flag_len 1 -#define reg_API_retrain_freeze_flag_lsb 108 - -#define xd_p_reg_dummy_111_104 0xA615 -#define reg_dummy_111_104_pos 0 -#define reg_dummy_111_104_len 8 -#define reg_dummy_111_104_lsb 104 -#define xd_p_reg_dummy_119_112 0xA616 -#define reg_dummy_119_112_pos 0 -#define reg_dummy_119_112_len 8 -#define reg_dummy_119_112_lsb 112 -#define xd_p_reg_dummy_127_120 0xA617 -#define reg_dummy_127_120_pos 0 -#define reg_dummy_127_120_len 8 -#define reg_dummy_127_120_lsb 120 -#define xd_p_reg_dummy_135_128 0xA618 -#define reg_dummy_135_128_pos 0 -#define reg_dummy_135_128_len 8 -#define reg_dummy_135_128_lsb 128 - -#define xd_p_reg_dummy_143_136 0xA619 -#define reg_dummy_143_136_pos 0 -#define reg_dummy_143_136_len 8 -#define reg_dummy_143_136_lsb 136 - -#define xd_p_reg_CCIR_dis 0xA619 -#define reg_CCIR_dis_pos 0 -#define reg_CCIR_dis_len 1 -#define reg_CCIR_dis_lsb 0 - -#define xd_p_reg_dummy_151_144 0xA61A -#define reg_dummy_151_144_pos 0 -#define reg_dummy_151_144_len 8 -#define reg_dummy_151_144_lsb 144 - -#define xd_p_reg_dummy_159_152 0xA61B -#define reg_dummy_159_152_pos 0 -#define reg_dummy_159_152_len 8 -#define reg_dummy_159_152_lsb 152 - -#define xd_p_reg_dummy_167_160 0xA61C -#define reg_dummy_167_160_pos 0 -#define reg_dummy_167_160_len 8 -#define reg_dummy_167_160_lsb 160 - -#define xd_p_reg_dummy_175_168 0xA61D -#define reg_dummy_175_168_pos 0 -#define reg_dummy_175_168_len 8 -#define reg_dummy_175_168_lsb 168 - -#define xd_p_reg_dummy_183_176 0xA61E -#define reg_dummy_183_176_pos 0 -#define reg_dummy_183_176_len 8 -#define reg_dummy_183_176_lsb 176 - -#define xd_p_reg_ofsm_read_rbc_en 0xA61E -#define reg_ofsm_read_rbc_en_pos 2 -#define reg_ofsm_read_rbc_en_len 1 -#define reg_ofsm_read_rbc_en_lsb 0 - -#define xd_p_reg_ce_filter_selection_dis 0xA61E -#define reg_ce_filter_selection_dis_pos 1 -#define reg_ce_filter_selection_dis_len 1 -#define reg_ce_filter_selection_dis_lsb 0 - -#define xd_p_reg_OFSM_version_control_7_0 0xA611 -#define reg_OFSM_version_control_7_0_pos 0 -#define reg_OFSM_version_control_7_0_len 8 -#define reg_OFSM_version_control_7_0_lsb 0 - -#define xd_p_reg_OFSM_version_control_15_8 0xA61F -#define reg_OFSM_version_control_15_8_pos 0 -#define reg_OFSM_version_control_15_8_len 8 -#define reg_OFSM_version_control_15_8_lsb 0 - -#define xd_p_reg_OFSM_version_control_23_16 0xA620 -#define reg_OFSM_version_control_23_16_pos 0 -#define reg_OFSM_version_control_23_16_len 8 -#define reg_OFSM_version_control_23_16_lsb 0 - -#define xd_p_reg_dummy_191_184 0xA61F -#define reg_dummy_191_184_pos 0 -#define reg_dummy_191_184_len 8 -#define reg_dummy_191_184_lsb 184 - -#define xd_p_reg_dummy_199_192 0xA620 -#define reg_dummy_199_192_pos 0 -#define reg_dummy_199_192_len 8 -#define reg_dummy_199_192_lsb 192 - -#define xd_p_reg_ce_en 0xABC0 -#define reg_ce_en_pos 0 -#define reg_ce_en_len 1 -#define reg_ce_en_lsb 0 -#define xd_p_reg_ce_fctrl_en 0xABC0 -#define reg_ce_fctrl_en_pos 1 -#define reg_ce_fctrl_en_len 1 -#define reg_ce_fctrl_en_lsb 0 -#define xd_p_reg_ce_fste_tdi 0xABC0 -#define reg_ce_fste_tdi_pos 2 -#define reg_ce_fste_tdi_len 1 -#define reg_ce_fste_tdi_lsb 0 -#define xd_p_reg_ce_dynamic 0xABC0 -#define reg_ce_dynamic_pos 3 -#define reg_ce_dynamic_len 1 -#define reg_ce_dynamic_lsb 0 -#define xd_p_reg_ce_conf 0xABC0 -#define reg_ce_conf_pos 4 -#define reg_ce_conf_len 2 -#define reg_ce_conf_lsb 0 -#define xd_p_reg_ce_dyn12 0xABC0 -#define reg_ce_dyn12_pos 6 -#define reg_ce_dyn12_len 1 -#define reg_ce_dyn12_lsb 0 -#define xd_p_reg_ce_derot_en 0xABC0 -#define reg_ce_derot_en_pos 7 -#define reg_ce_derot_en_len 1 -#define reg_ce_derot_en_lsb 0 -#define xd_p_reg_ce_dynamic_th_7_0 0xABC1 -#define reg_ce_dynamic_th_7_0_pos 0 -#define reg_ce_dynamic_th_7_0_len 8 -#define reg_ce_dynamic_th_7_0_lsb 0 -#define xd_p_reg_ce_dynamic_th_15_8 0xABC2 -#define reg_ce_dynamic_th_15_8_pos 0 -#define reg_ce_dynamic_th_15_8_len 8 -#define reg_ce_dynamic_th_15_8_lsb 8 -#define xd_p_reg_ce_s1 0xABC3 -#define reg_ce_s1_pos 0 -#define reg_ce_s1_len 5 -#define reg_ce_s1_lsb 0 -#define xd_p_reg_ce_var_forced_value 0xABC3 -#define reg_ce_var_forced_value_pos 5 -#define reg_ce_var_forced_value_len 3 -#define reg_ce_var_forced_value_lsb 0 -#define xd_p_reg_ce_data_im_7_0 0xABC4 -#define reg_ce_data_im_7_0_pos 0 -#define reg_ce_data_im_7_0_len 8 -#define reg_ce_data_im_7_0_lsb 0 -#define xd_p_reg_ce_data_im_8 0xABC5 -#define reg_ce_data_im_8_pos 0 -#define reg_ce_data_im_8_len 1 -#define reg_ce_data_im_8_lsb 0 -#define xd_p_reg_ce_data_re_6_0 0xABC5 -#define reg_ce_data_re_6_0_pos 1 -#define reg_ce_data_re_6_0_len 7 -#define reg_ce_data_re_6_0_lsb 0 -#define xd_p_reg_ce_data_re_8_7 0xABC6 -#define reg_ce_data_re_8_7_pos 0 -#define reg_ce_data_re_8_7_len 2 -#define reg_ce_data_re_8_7_lsb 7 -#define xd_p_reg_ce_tone_5_0 0xABC6 -#define reg_ce_tone_5_0_pos 2 -#define reg_ce_tone_5_0_len 6 -#define reg_ce_tone_5_0_lsb 0 -#define xd_p_reg_ce_tone_12_6 0xABC7 -#define reg_ce_tone_12_6_pos 0 -#define reg_ce_tone_12_6_len 7 -#define reg_ce_tone_12_6_lsb 6 -#define xd_p_reg_ce_centroid_drift_th 0xABC8 -#define reg_ce_centroid_drift_th_pos 0 -#define reg_ce_centroid_drift_th_len 8 -#define reg_ce_centroid_drift_th_lsb 0 -#define xd_p_reg_ce_centroid_count_max 0xABC9 -#define reg_ce_centroid_count_max_pos 0 -#define reg_ce_centroid_count_max_len 4 -#define reg_ce_centroid_count_max_lsb 0 -#define xd_p_reg_ce_centroid_bias_inc_7_0 0xABCA -#define reg_ce_centroid_bias_inc_7_0_pos 0 -#define reg_ce_centroid_bias_inc_7_0_len 8 -#define reg_ce_centroid_bias_inc_7_0_lsb 0 -#define xd_p_reg_ce_centroid_bias_inc_8 0xABCB -#define reg_ce_centroid_bias_inc_8_pos 0 -#define reg_ce_centroid_bias_inc_8_len 1 -#define reg_ce_centroid_bias_inc_8_lsb 0 -#define xd_p_reg_ce_var_th0_7_0 0xABCC -#define reg_ce_var_th0_7_0_pos 0 -#define reg_ce_var_th0_7_0_len 8 -#define reg_ce_var_th0_7_0_lsb 0 -#define xd_p_reg_ce_var_th0_15_8 0xABCD -#define reg_ce_var_th0_15_8_pos 0 -#define reg_ce_var_th0_15_8_len 8 -#define reg_ce_var_th0_15_8_lsb 8 -#define xd_p_reg_ce_var_th1_7_0 0xABCE -#define reg_ce_var_th1_7_0_pos 0 -#define reg_ce_var_th1_7_0_len 8 -#define reg_ce_var_th1_7_0_lsb 0 -#define xd_p_reg_ce_var_th1_15_8 0xABCF -#define reg_ce_var_th1_15_8_pos 0 -#define reg_ce_var_th1_15_8_len 8 -#define reg_ce_var_th1_15_8_lsb 8 -#define xd_p_reg_ce_var_th2_7_0 0xABD0 -#define reg_ce_var_th2_7_0_pos 0 -#define reg_ce_var_th2_7_0_len 8 -#define reg_ce_var_th2_7_0_lsb 0 -#define xd_p_reg_ce_var_th2_15_8 0xABD1 -#define reg_ce_var_th2_15_8_pos 0 -#define reg_ce_var_th2_15_8_len 8 -#define reg_ce_var_th2_15_8_lsb 8 -#define xd_p_reg_ce_var_th3_7_0 0xABD2 -#define reg_ce_var_th3_7_0_pos 0 -#define reg_ce_var_th3_7_0_len 8 -#define reg_ce_var_th3_7_0_lsb 0 -#define xd_p_reg_ce_var_th3_15_8 0xABD3 -#define reg_ce_var_th3_15_8_pos 0 -#define reg_ce_var_th3_15_8_len 8 -#define reg_ce_var_th3_15_8_lsb 8 -#define xd_p_reg_ce_var_th4_7_0 0xABD4 -#define reg_ce_var_th4_7_0_pos 0 -#define reg_ce_var_th4_7_0_len 8 -#define reg_ce_var_th4_7_0_lsb 0 -#define xd_p_reg_ce_var_th4_15_8 0xABD5 -#define reg_ce_var_th4_15_8_pos 0 -#define reg_ce_var_th4_15_8_len 8 -#define reg_ce_var_th4_15_8_lsb 8 -#define xd_p_reg_ce_var_th5_7_0 0xABD6 -#define reg_ce_var_th5_7_0_pos 0 -#define reg_ce_var_th5_7_0_len 8 -#define reg_ce_var_th5_7_0_lsb 0 -#define xd_p_reg_ce_var_th5_15_8 0xABD7 -#define reg_ce_var_th5_15_8_pos 0 -#define reg_ce_var_th5_15_8_len 8 -#define reg_ce_var_th5_15_8_lsb 8 -#define xd_p_reg_ce_var_th6_7_0 0xABD8 -#define reg_ce_var_th6_7_0_pos 0 -#define reg_ce_var_th6_7_0_len 8 -#define reg_ce_var_th6_7_0_lsb 0 -#define xd_p_reg_ce_var_th6_15_8 0xABD9 -#define reg_ce_var_th6_15_8_pos 0 -#define reg_ce_var_th6_15_8_len 8 -#define reg_ce_var_th6_15_8_lsb 8 -#define xd_p_reg_ce_fctrl_reset 0xABDA -#define reg_ce_fctrl_reset_pos 0 -#define reg_ce_fctrl_reset_len 1 -#define reg_ce_fctrl_reset_lsb 0 -#define xd_p_reg_ce_cent_auto_clr_en 0xABDA -#define reg_ce_cent_auto_clr_en_pos 1 -#define reg_ce_cent_auto_clr_en_len 1 -#define reg_ce_cent_auto_clr_en_lsb 0 -#define xd_p_reg_ce_fctrl_auto_reset_en 0xABDA -#define reg_ce_fctrl_auto_reset_en_pos 2 -#define reg_ce_fctrl_auto_reset_en_len 1 -#define reg_ce_fctrl_auto_reset_en_lsb 0 -#define xd_p_reg_ce_var_forced_en 0xABDA -#define reg_ce_var_forced_en_pos 3 -#define reg_ce_var_forced_en_len 1 -#define reg_ce_var_forced_en_lsb 0 -#define xd_p_reg_ce_cent_forced_en 0xABDA -#define reg_ce_cent_forced_en_pos 4 -#define reg_ce_cent_forced_en_len 1 -#define reg_ce_cent_forced_en_lsb 0 -#define xd_p_reg_ce_var_max 0xABDA -#define reg_ce_var_max_pos 5 -#define reg_ce_var_max_len 3 -#define reg_ce_var_max_lsb 0 -#define xd_p_reg_ce_cent_forced_value_7_0 0xABDB -#define reg_ce_cent_forced_value_7_0_pos 0 -#define reg_ce_cent_forced_value_7_0_len 8 -#define reg_ce_cent_forced_value_7_0_lsb 0 -#define xd_p_reg_ce_cent_forced_value_11_8 0xABDC -#define reg_ce_cent_forced_value_11_8_pos 0 -#define reg_ce_cent_forced_value_11_8_len 4 -#define reg_ce_cent_forced_value_11_8_lsb 8 -#define xd_p_reg_ce_fctrl_rd 0xABDD -#define reg_ce_fctrl_rd_pos 0 -#define reg_ce_fctrl_rd_len 1 -#define reg_ce_fctrl_rd_lsb 0 -#define xd_p_reg_ce_centroid_max_6_0 0xABDD -#define reg_ce_centroid_max_6_0_pos 1 -#define reg_ce_centroid_max_6_0_len 7 -#define reg_ce_centroid_max_6_0_lsb 0 -#define xd_p_reg_ce_centroid_max_11_7 0xABDE -#define reg_ce_centroid_max_11_7_pos 0 -#define reg_ce_centroid_max_11_7_len 5 -#define reg_ce_centroid_max_11_7_lsb 7 -#define xd_p_reg_ce_var 0xABDF -#define reg_ce_var_pos 0 -#define reg_ce_var_len 3 -#define reg_ce_var_lsb 0 -#define xd_p_reg_ce_fctrl_rdy 0xABDF -#define reg_ce_fctrl_rdy_pos 3 -#define reg_ce_fctrl_rdy_len 1 -#define reg_ce_fctrl_rdy_lsb 0 -#define xd_p_reg_ce_centroid_out_3_0 0xABDF -#define reg_ce_centroid_out_3_0_pos 4 -#define reg_ce_centroid_out_3_0_len 4 -#define reg_ce_centroid_out_3_0_lsb 0 -#define xd_p_reg_ce_centroid_out_11_4 0xABE0 -#define reg_ce_centroid_out_11_4_pos 0 -#define reg_ce_centroid_out_11_4_len 8 -#define reg_ce_centroid_out_11_4_lsb 4 -#define xd_p_reg_ce_bias_7_0 0xABE1 -#define reg_ce_bias_7_0_pos 0 -#define reg_ce_bias_7_0_len 8 -#define reg_ce_bias_7_0_lsb 0 -#define xd_p_reg_ce_bias_11_8 0xABE2 -#define reg_ce_bias_11_8_pos 0 -#define reg_ce_bias_11_8_len 4 -#define reg_ce_bias_11_8_lsb 8 -#define xd_p_reg_ce_m1_3_0 0xABE2 -#define reg_ce_m1_3_0_pos 4 -#define reg_ce_m1_3_0_len 4 -#define reg_ce_m1_3_0_lsb 0 -#define xd_p_reg_ce_m1_11_4 0xABE3 -#define reg_ce_m1_11_4_pos 0 -#define reg_ce_m1_11_4_len 8 -#define reg_ce_m1_11_4_lsb 4 -#define xd_p_reg_ce_rh0_7_0 0xABE4 -#define reg_ce_rh0_7_0_pos 0 -#define reg_ce_rh0_7_0_len 8 -#define reg_ce_rh0_7_0_lsb 0 -#define xd_p_reg_ce_rh0_15_8 0xABE5 -#define reg_ce_rh0_15_8_pos 0 -#define reg_ce_rh0_15_8_len 8 -#define reg_ce_rh0_15_8_lsb 8 -#define xd_p_reg_ce_rh0_23_16 0xABE6 -#define reg_ce_rh0_23_16_pos 0 -#define reg_ce_rh0_23_16_len 8 -#define reg_ce_rh0_23_16_lsb 16 -#define xd_p_reg_ce_rh0_31_24 0xABE7 -#define reg_ce_rh0_31_24_pos 0 -#define reg_ce_rh0_31_24_len 8 -#define reg_ce_rh0_31_24_lsb 24 -#define xd_p_reg_ce_rh3_real_7_0 0xABE8 -#define reg_ce_rh3_real_7_0_pos 0 -#define reg_ce_rh3_real_7_0_len 8 -#define reg_ce_rh3_real_7_0_lsb 0 -#define xd_p_reg_ce_rh3_real_15_8 0xABE9 -#define reg_ce_rh3_real_15_8_pos 0 -#define reg_ce_rh3_real_15_8_len 8 -#define reg_ce_rh3_real_15_8_lsb 8 -#define xd_p_reg_ce_rh3_real_23_16 0xABEA -#define reg_ce_rh3_real_23_16_pos 0 -#define reg_ce_rh3_real_23_16_len 8 -#define reg_ce_rh3_real_23_16_lsb 16 -#define xd_p_reg_ce_rh3_real_31_24 0xABEB -#define reg_ce_rh3_real_31_24_pos 0 -#define reg_ce_rh3_real_31_24_len 8 -#define reg_ce_rh3_real_31_24_lsb 24 -#define xd_p_reg_ce_rh3_imag_7_0 0xABEC -#define reg_ce_rh3_imag_7_0_pos 0 -#define reg_ce_rh3_imag_7_0_len 8 -#define reg_ce_rh3_imag_7_0_lsb 0 -#define xd_p_reg_ce_rh3_imag_15_8 0xABED -#define reg_ce_rh3_imag_15_8_pos 0 -#define reg_ce_rh3_imag_15_8_len 8 -#define reg_ce_rh3_imag_15_8_lsb 8 -#define xd_p_reg_ce_rh3_imag_23_16 0xABEE -#define reg_ce_rh3_imag_23_16_pos 0 -#define reg_ce_rh3_imag_23_16_len 8 -#define reg_ce_rh3_imag_23_16_lsb 16 -#define xd_p_reg_ce_rh3_imag_31_24 0xABEF -#define reg_ce_rh3_imag_31_24_pos 0 -#define reg_ce_rh3_imag_31_24_len 8 -#define reg_ce_rh3_imag_31_24_lsb 24 -#define xd_p_reg_feq_fix_eh2_7_0 0xABF0 -#define reg_feq_fix_eh2_7_0_pos 0 -#define reg_feq_fix_eh2_7_0_len 8 -#define reg_feq_fix_eh2_7_0_lsb 0 -#define xd_p_reg_feq_fix_eh2_15_8 0xABF1 -#define reg_feq_fix_eh2_15_8_pos 0 -#define reg_feq_fix_eh2_15_8_len 8 -#define reg_feq_fix_eh2_15_8_lsb 8 -#define xd_p_reg_feq_fix_eh2_23_16 0xABF2 -#define reg_feq_fix_eh2_23_16_pos 0 -#define reg_feq_fix_eh2_23_16_len 8 -#define reg_feq_fix_eh2_23_16_lsb 16 -#define xd_p_reg_feq_fix_eh2_31_24 0xABF3 -#define reg_feq_fix_eh2_31_24_pos 0 -#define reg_feq_fix_eh2_31_24_len 8 -#define reg_feq_fix_eh2_31_24_lsb 24 -#define xd_p_reg_ce_m2_central_7_0 0xABF4 -#define reg_ce_m2_central_7_0_pos 0 -#define reg_ce_m2_central_7_0_len 8 -#define reg_ce_m2_central_7_0_lsb 0 -#define xd_p_reg_ce_m2_central_15_8 0xABF5 -#define reg_ce_m2_central_15_8_pos 0 -#define reg_ce_m2_central_15_8_len 8 -#define reg_ce_m2_central_15_8_lsb 8 -#define xd_p_reg_ce_fftshift 0xABF6 -#define reg_ce_fftshift_pos 0 -#define reg_ce_fftshift_len 4 -#define reg_ce_fftshift_lsb 0 -#define xd_p_reg_ce_fftshift1 0xABF6 -#define reg_ce_fftshift1_pos 4 -#define reg_ce_fftshift1_len 4 -#define reg_ce_fftshift1_lsb 0 -#define xd_p_reg_ce_fftshift2 0xABF7 -#define reg_ce_fftshift2_pos 0 -#define reg_ce_fftshift2_len 4 -#define reg_ce_fftshift2_lsb 0 -#define xd_p_reg_ce_top_mobile 0xABF7 -#define reg_ce_top_mobile_pos 4 -#define reg_ce_top_mobile_len 1 -#define reg_ce_top_mobile_lsb 0 -#define xd_p_reg_strong_sginal_detected 0xA2BC -#define reg_strong_sginal_detected_pos 2 -#define reg_strong_sginal_detected_len 1 -#define reg_strong_sginal_detected_lsb 0 - -#define XD_MP2IF_BASE 0xB000 -#define XD_MP2IF_CSR (0x00 + XD_MP2IF_BASE) -#define XD_MP2IF_DMX_CTRL (0x03 + XD_MP2IF_BASE) -#define XD_MP2IF_PID_IDX (0x04 + XD_MP2IF_BASE) -#define XD_MP2IF_PID_DATA_L (0x05 + XD_MP2IF_BASE) -#define XD_MP2IF_PID_DATA_H (0x06 + XD_MP2IF_BASE) -#define XD_MP2IF_MISC (0x07 + XD_MP2IF_BASE) - -extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d); -extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, - u8 * value); -extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len); -extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, - u8 value); -extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len); -extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, - u8 addr, u8 * values, int len); -extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, - u8 * values, int len); -extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, - u8 pos, u8 len, u8 * value); -extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, - u8 pos, u8 len, u8 value); -extern int af9005_send_command(struct dvb_usb_device *d, u8 command, - u8 * wbuf, int wlen, u8 * rbuf, int rlen); -extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, - u8 * values, int len); -extern int af9005_tuner_attach(struct dvb_usb_adapter *adap); -extern int af9005_led_control(struct dvb_usb_device *d, int onoff); - -extern u8 regmask[8]; - -/* remote control decoder */ -extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, - u32 * event, int *state); -extern struct rc_map_table rc_map_af9005_table[]; -extern int rc_map_af9005_table_size; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-remote.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-remote.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-remote.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-remote.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +0,0 @@ -/* DVB USB compliant Linux driver for the Afatech 9005 - * USB1.1 DVB-T receiver. - * - * Standard remote decode function - * - * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) - * - * Thanks to Afatech who kindly provided information. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * see Documentation/dvb/REDME.dvb-usb for more information - */ -#include "af9005.h" -/* debug */ -static int dvb_usb_af9005_remote_debug; -module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); -MODULE_PARM_DESC(debug, - "enable (1) or disable (0) debug messages." - DVB_USB_DEBUG_STATUS); - -#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args) - -struct rc_map_table rc_map_af9005_table[] = { - - {0x01b7, KEY_POWER}, - {0x01a7, KEY_VOLUMEUP}, - {0x0187, KEY_CHANNELUP}, - {0x017f, KEY_MUTE}, - {0x01bf, KEY_VOLUMEDOWN}, - {0x013f, KEY_CHANNELDOWN}, - {0x01df, KEY_1}, - {0x015f, KEY_2}, - {0x019f, KEY_3}, - {0x011f, KEY_4}, - {0x01ef, KEY_5}, - {0x016f, KEY_6}, - {0x01af, KEY_7}, - {0x0127, KEY_8}, - {0x0107, KEY_9}, - {0x01cf, KEY_ZOOM}, - {0x014f, KEY_0}, - {0x018f, KEY_GOTO}, /* marked jump on the remote */ - - {0x00bd, KEY_POWER}, - {0x007d, KEY_VOLUMEUP}, - {0x00fd, KEY_CHANNELUP}, - {0x009d, KEY_MUTE}, - {0x005d, KEY_VOLUMEDOWN}, - {0x00dd, KEY_CHANNELDOWN}, - {0x00ad, KEY_1}, - {0x006d, KEY_2}, - {0x00ed, KEY_3}, - {0x008d, KEY_4}, - {0x004d, KEY_5}, - {0x00cd, KEY_6}, - {0x00b5, KEY_7}, - {0x0075, KEY_8}, - {0x00f5, KEY_9}, - {0x0095, KEY_ZOOM}, - {0x0055, KEY_0}, - {0x00d5, KEY_GOTO}, /* marked jump on the remote */ -}; - -int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table); - -static int repeatable_keys[] = { - KEY_VOLUMEUP, - KEY_VOLUMEDOWN, - KEY_CHANNELUP, - KEY_CHANNELDOWN -}; - -int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event, - int *state) -{ - u16 mark, space; - u32 result; - u8 cust, dat, invdat; - int i; - - if (len >= 6) { - mark = (u16) (data[0] << 8) + data[1]; - space = (u16) (data[2] << 8) + data[3]; - if (space * 3 < mark) { - for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { - if (d->last_event == repeatable_keys[i]) { - *state = REMOTE_KEY_REPEAT; - *event = d->last_event; - deb_decode("repeat key, event %x\n", - *event); - return 0; - } - } - deb_decode("repeated key ignored (non repeatable)\n"); - return 0; - } else if (len >= 33 * 4) { /*32 bits + start code */ - result = 0; - for (i = 4; i < 4 + 32 * 4; i += 4) { - result <<= 1; - mark = (u16) (data[i] << 8) + data[i + 1]; - mark >>= 1; - space = (u16) (data[i + 2] << 8) + data[i + 3]; - space >>= 1; - if (mark * 2 > space) - result += 1; - } - deb_decode("key pressed, raw value %x\n", result); - if ((result & 0xff000000) != 0xfe000000) { - deb_decode - ("doesn't start with 0xfe, ignored\n"); - return 0; - } - cust = (result >> 16) & 0xff; - dat = (result >> 8) & 0xff; - invdat = (~result) & 0xff; - if (dat != invdat) { - deb_decode("code != inverted code\n"); - return 0; - } - for (i = 0; i < rc_map_af9005_table_size; i++) { - if (rc5_custom(&rc_map_af9005_table[i]) == cust - && rc5_data(&rc_map_af9005_table[i]) == dat) { - *event = rc_map_af9005_table[i].keycode; - *state = REMOTE_KEY_PRESSED; - deb_decode - ("key pressed, event %x\n", *event); - return 0; - } - } - deb_decode("not found in table\n"); - } - } - return 0; -} - -EXPORT_SYMBOL(rc_map_af9005_table); -EXPORT_SYMBOL(rc_map_af9005_table_size); -EXPORT_SYMBOL(af9005_rc_decode); - -MODULE_AUTHOR("Luca Olivetti "); -MODULE_DESCRIPTION - ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-script.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-script.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-script.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9005-script.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,203 +0,0 @@ -/* -File automatically generated by createinit.py using data -extracted from AF05BDA.sys (windows driver): - -dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110 -python createinit.py > af9005-script.h - -*/ - -typedef struct { - u16 reg; - u8 pos; - u8 len; - u8 val; -} RegDesc; - -static RegDesc script[] = { - {0xa180, 0x0, 0x8, 0xa}, - {0xa181, 0x0, 0x8, 0xd7}, - {0xa182, 0x0, 0x8, 0xa3}, - {0xa0a0, 0x0, 0x8, 0x0}, - {0xa0a1, 0x0, 0x5, 0x0}, - {0xa0a1, 0x5, 0x1, 0x1}, - {0xa0c0, 0x0, 0x4, 0x1}, - {0xa20e, 0x4, 0x4, 0xa}, - {0xa20f, 0x0, 0x8, 0x40}, - {0xa210, 0x0, 0x8, 0x8}, - {0xa32a, 0x0, 0x4, 0xa}, - {0xa32c, 0x0, 0x8, 0x20}, - {0xa32b, 0x0, 0x8, 0x15}, - {0xa1a0, 0x1, 0x1, 0x1}, - {0xa000, 0x0, 0x1, 0x1}, - {0xa000, 0x1, 0x1, 0x0}, - {0xa001, 0x1, 0x1, 0x1}, - {0xa001, 0x0, 0x1, 0x0}, - {0xa001, 0x5, 0x1, 0x0}, - {0xa00e, 0x0, 0x5, 0x10}, - {0xa00f, 0x0, 0x3, 0x4}, - {0xa00f, 0x3, 0x3, 0x5}, - {0xa010, 0x0, 0x3, 0x4}, - {0xa010, 0x3, 0x3, 0x5}, - {0xa016, 0x4, 0x4, 0x3}, - {0xa01f, 0x0, 0x6, 0xa}, - {0xa020, 0x0, 0x6, 0xa}, - {0xa2bc, 0x0, 0x1, 0x1}, - {0xa2bc, 0x5, 0x1, 0x1}, - {0xa015, 0x0, 0x8, 0x50}, - {0xa016, 0x0, 0x1, 0x0}, - {0xa02a, 0x0, 0x8, 0x50}, - {0xa029, 0x0, 0x8, 0x4b}, - {0xa614, 0x0, 0x8, 0x46}, - {0xa002, 0x0, 0x5, 0x19}, - {0xa003, 0x0, 0x5, 0x1a}, - {0xa004, 0x0, 0x5, 0x19}, - {0xa005, 0x0, 0x5, 0x1a}, - {0xa008, 0x0, 0x8, 0x69}, - {0xa009, 0x0, 0x2, 0x2}, - {0xae1b, 0x0, 0x8, 0x69}, - {0xae1c, 0x0, 0x8, 0x2}, - {0xae1d, 0x0, 0x8, 0x2a}, - {0xa022, 0x0, 0x8, 0xaa}, - {0xa006, 0x0, 0x8, 0xc8}, - {0xa007, 0x0, 0x2, 0x0}, - {0xa00c, 0x0, 0x8, 0xba}, - {0xa00d, 0x0, 0x2, 0x2}, - {0xa608, 0x0, 0x8, 0xba}, - {0xa60e, 0x0, 0x2, 0x2}, - {0xa609, 0x0, 0x8, 0x80}, - {0xa60e, 0x2, 0x2, 0x3}, - {0xa00a, 0x0, 0x8, 0xb6}, - {0xa00b, 0x0, 0x2, 0x0}, - {0xa011, 0x0, 0x8, 0xb9}, - {0xa012, 0x0, 0x2, 0x0}, - {0xa013, 0x0, 0x8, 0xbd}, - {0xa014, 0x0, 0x2, 0x2}, - {0xa366, 0x0, 0x1, 0x1}, - {0xa2bc, 0x3, 0x1, 0x0}, - {0xa2bd, 0x0, 0x8, 0xa}, - {0xa2be, 0x0, 0x8, 0x14}, - {0xa2bf, 0x0, 0x8, 0x8}, - {0xa60a, 0x0, 0x8, 0xbd}, - {0xa60e, 0x4, 0x2, 0x2}, - {0xa60b, 0x0, 0x8, 0x86}, - {0xa60e, 0x6, 0x2, 0x3}, - {0xa001, 0x2, 0x2, 0x1}, - {0xa1c7, 0x0, 0x8, 0xf5}, - {0xa03d, 0x0, 0x8, 0xb1}, - {0xa616, 0x0, 0x8, 0xff}, - {0xa617, 0x0, 0x8, 0xad}, - {0xa618, 0x0, 0x8, 0xad}, - {0xa61e, 0x3, 0x1, 0x1}, - {0xae1a, 0x0, 0x8, 0x0}, - {0xae19, 0x0, 0x8, 0xc8}, - {0xae18, 0x0, 0x8, 0x61}, - {0xa140, 0x0, 0x8, 0x0}, - {0xa141, 0x0, 0x8, 0xc8}, - {0xa142, 0x0, 0x7, 0x61}, - {0xa023, 0x0, 0x8, 0xff}, - {0xa021, 0x0, 0x8, 0xad}, - {0xa026, 0x0, 0x1, 0x0}, - {0xa024, 0x0, 0x8, 0xff}, - {0xa025, 0x0, 0x8, 0xff}, - {0xa1c8, 0x0, 0x8, 0xf}, - {0xa2bc, 0x1, 0x1, 0x0}, - {0xa60c, 0x0, 0x4, 0x5}, - {0xa60c, 0x4, 0x4, 0x6}, - {0xa60d, 0x0, 0x8, 0xa}, - {0xa371, 0x0, 0x1, 0x1}, - {0xa366, 0x1, 0x3, 0x7}, - {0xa338, 0x0, 0x8, 0x10}, - {0xa339, 0x0, 0x6, 0x7}, - {0xa33a, 0x0, 0x6, 0x1f}, - {0xa33b, 0x0, 0x8, 0xf6}, - {0xa33c, 0x3, 0x5, 0x4}, - {0xa33d, 0x4, 0x4, 0x0}, - {0xa33d, 0x1, 0x1, 0x1}, - {0xa33d, 0x2, 0x1, 0x1}, - {0xa33d, 0x3, 0x1, 0x1}, - {0xa16d, 0x0, 0x4, 0xf}, - {0xa161, 0x0, 0x5, 0x5}, - {0xa162, 0x0, 0x4, 0x5}, - {0xa165, 0x0, 0x8, 0xff}, - {0xa166, 0x0, 0x8, 0x9c}, - {0xa2c3, 0x0, 0x4, 0x5}, - {0xa61a, 0x0, 0x6, 0xf}, - {0xb200, 0x0, 0x8, 0xa1}, - {0xb201, 0x0, 0x8, 0x7}, - {0xa093, 0x0, 0x1, 0x0}, - {0xa093, 0x1, 0x5, 0xf}, - {0xa094, 0x0, 0x8, 0xff}, - {0xa095, 0x0, 0x8, 0xf}, - {0xa080, 0x2, 0x5, 0x3}, - {0xa081, 0x0, 0x4, 0x0}, - {0xa081, 0x4, 0x4, 0x9}, - {0xa082, 0x0, 0x5, 0x1f}, - {0xa08d, 0x0, 0x8, 0x1}, - {0xa083, 0x0, 0x8, 0x32}, - {0xa084, 0x0, 0x1, 0x0}, - {0xa08e, 0x0, 0x8, 0x3}, - {0xa085, 0x0, 0x8, 0x32}, - {0xa086, 0x0, 0x3, 0x0}, - {0xa087, 0x0, 0x8, 0x6e}, - {0xa088, 0x0, 0x5, 0x15}, - {0xa089, 0x0, 0x8, 0x0}, - {0xa08a, 0x0, 0x5, 0x19}, - {0xa08b, 0x0, 0x8, 0x92}, - {0xa08c, 0x0, 0x5, 0x1c}, - {0xa120, 0x0, 0x8, 0x0}, - {0xa121, 0x0, 0x5, 0x10}, - {0xa122, 0x0, 0x8, 0x0}, - {0xa123, 0x0, 0x7, 0x40}, - {0xa123, 0x7, 0x1, 0x0}, - {0xa124, 0x0, 0x8, 0x13}, - {0xa125, 0x0, 0x7, 0x10}, - {0xa1c0, 0x0, 0x8, 0x0}, - {0xa1c1, 0x0, 0x5, 0x4}, - {0xa1c2, 0x0, 0x8, 0x0}, - {0xa1c3, 0x0, 0x5, 0x10}, - {0xa1c3, 0x5, 0x3, 0x0}, - {0xa1c4, 0x0, 0x6, 0x0}, - {0xa1c5, 0x0, 0x7, 0x10}, - {0xa100, 0x0, 0x8, 0x0}, - {0xa101, 0x0, 0x5, 0x10}, - {0xa102, 0x0, 0x8, 0x0}, - {0xa103, 0x0, 0x7, 0x40}, - {0xa103, 0x7, 0x1, 0x0}, - {0xa104, 0x0, 0x8, 0x18}, - {0xa105, 0x0, 0x7, 0xa}, - {0xa106, 0x0, 0x8, 0x20}, - {0xa107, 0x0, 0x8, 0x40}, - {0xa108, 0x0, 0x4, 0x0}, - {0xa38c, 0x0, 0x8, 0xfc}, - {0xa38d, 0x0, 0x8, 0x0}, - {0xa38e, 0x0, 0x8, 0x7e}, - {0xa38f, 0x0, 0x8, 0x0}, - {0xa390, 0x0, 0x8, 0x2f}, - {0xa60f, 0x5, 0x1, 0x1}, - {0xa170, 0x0, 0x8, 0xdc}, - {0xa171, 0x0, 0x2, 0x0}, - {0xa2ae, 0x0, 0x1, 0x1}, - {0xa2ae, 0x1, 0x1, 0x1}, - {0xa392, 0x0, 0x1, 0x1}, - {0xa391, 0x2, 0x1, 0x0}, - {0xabc1, 0x0, 0x8, 0xff}, - {0xabc2, 0x0, 0x8, 0x0}, - {0xabc8, 0x0, 0x8, 0x8}, - {0xabca, 0x0, 0x8, 0x10}, - {0xabcb, 0x0, 0x1, 0x0}, - {0xabc3, 0x5, 0x3, 0x7}, - {0xabc0, 0x6, 0x1, 0x0}, - {0xabc0, 0x4, 0x2, 0x0}, - {0xa344, 0x4, 0x4, 0x1}, - {0xabc0, 0x7, 0x1, 0x1}, - {0xabc0, 0x2, 0x1, 0x1}, - {0xa345, 0x0, 0x8, 0x66}, - {0xa346, 0x0, 0x8, 0x66}, - {0xa347, 0x0, 0x4, 0x0}, - {0xa343, 0x0, 0x4, 0xa}, - {0xa347, 0x4, 0x4, 0x2}, - {0xa348, 0x0, 0x4, 0xc}, - {0xa348, 0x4, 0x4, 0x7}, - {0xa349, 0x0, 0x6, 0x2}, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9015.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9015.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9015.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9015.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1759 +0,0 @@ -/* - * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * Thanks to Afatech who kindly provided information. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include - -#include "af9015.h" -#include "af9013.h" -#include "mt2060.h" -#include "qt1010.h" -#include "tda18271.h" -#include "mxl5005s.h" -#include "mc44s803.h" -#include "tda18218.h" -#include "mxl5007t.h" - -static int dvb_usb_af9015_debug; -module_param_named(debug, dvb_usb_af9015_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -static int dvb_usb_af9015_remote; -module_param_named(remote, dvb_usb_af9015_remote, int, 0644); -MODULE_PARM_DESC(remote, "select remote"); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static DEFINE_MUTEX(af9015_usb_mutex); - -static struct af9015_config af9015_config; -static struct dvb_usb_device_properties af9015_properties[3]; -static int af9015_properties_count = ARRAY_SIZE(af9015_properties); - -static struct af9013_config af9015_af9013_config[] = { - { - .demod_address = AF9015_I2C_DEMOD, - .output_mode = AF9013_OUTPUT_MODE_USB, - .api_version = { 0, 1, 9, 0 }, - .gpio[0] = AF9013_GPIO_HI, - .gpio[3] = AF9013_GPIO_TUNER_ON, - - }, { - .output_mode = AF9013_OUTPUT_MODE_SERIAL, - .api_version = { 0, 1, 9, 0 }, - .gpio[0] = AF9013_GPIO_TUNER_ON, - .gpio[1] = AF9013_GPIO_LO, - } -}; - -static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) -{ -#define BUF_LEN 63 -#define REQ_HDR_LEN 8 /* send header size */ -#define ACK_HDR_LEN 2 /* rece header size */ - int act_len, ret; - u8 buf[BUF_LEN]; - u8 write = 1; - u8 msg_len = REQ_HDR_LEN; - static u8 seq; /* packet sequence number */ - - if (mutex_lock_interruptible(&af9015_usb_mutex) < 0) - return -EAGAIN; - - buf[0] = req->cmd; - buf[1] = seq++; - buf[2] = req->i2c_addr; - buf[3] = req->addr >> 8; - buf[4] = req->addr & 0xff; - buf[5] = req->mbox; - buf[6] = req->addr_len; - buf[7] = req->data_len; - - switch (req->cmd) { - case GET_CONFIG: - case READ_MEMORY: - case RECONNECT_USB: - case GET_IR_CODE: - write = 0; - break; - case READ_I2C: - write = 0; - buf[2] |= 0x01; /* set I2C direction */ - case WRITE_I2C: - buf[0] = READ_WRITE_I2C; - break; - case WRITE_MEMORY: - if (((req->addr & 0xff00) == 0xff00) || - ((req->addr & 0xff00) == 0xae00)) - buf[0] = WRITE_VIRTUAL_MEMORY; - case WRITE_VIRTUAL_MEMORY: - case COPY_FIRMWARE: - case DOWNLOAD_FIRMWARE: - case BOOT: - break; - default: - err("unknown command:%d", req->cmd); - ret = -1; - goto error_unlock; - } - - /* buffer overflow check */ - if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || - (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { - err("too much data; cmd:%d len:%d", req->cmd, req->data_len); - ret = -EINVAL; - goto error_unlock; - } - - /* write requested */ - if (write) { - memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); - msg_len += req->data_len; - } - - deb_xfer(">>> "); - debug_dump(buf, msg_len, deb_xfer); - - /* send req */ - ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, - &act_len, AF9015_USB_TIMEOUT); - if (ret) - err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len); - else - if (act_len != msg_len) - ret = -1; /* all data is not send */ - if (ret) - goto error_unlock; - - /* no ack for those packets */ - if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) - goto exit_unlock; - - /* write receives seq + status = 2 bytes - read receives seq + status + data = 2 + N bytes */ - msg_len = ACK_HDR_LEN; - if (!write) - msg_len += req->data_len; - - ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, - &act_len, AF9015_USB_TIMEOUT); - if (ret) { - err("recv bulk message failed:%d", ret); - ret = -1; - goto error_unlock; - } - - deb_xfer("<<< "); - debug_dump(buf, act_len, deb_xfer); - - /* remote controller query status is 1 if remote code is not received */ - if (req->cmd == GET_IR_CODE && buf[1] == 1) { - buf[1] = 0; /* clear command "error" status */ - memset(&buf[2], 0, req->data_len); - buf[3] = 1; /* no remote code received mark */ - } - - /* check status */ - if (buf[1]) { - err("command failed:%d", buf[1]); - ret = -1; - goto error_unlock; - } - - /* read request, copy returned data to return buf */ - if (!write) - memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len); - -error_unlock: -exit_unlock: - mutex_unlock(&af9015_usb_mutex); - - return ret; -} - -static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) -{ - return af9015_rw_udev(d->udev, req); -} - -static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, - u8 len) -{ - struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) -{ - return af9015_write_regs(d, addr, &val, 1); -} - -static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) -{ - struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) -{ - return af9015_read_regs(d, addr, val, 1); -} - -static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 val) -{ - struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; - - if (addr == af9015_af9013_config[0].demod_address || - addr == af9015_af9013_config[1].demod_address) - req.addr_len = 3; - - return af9015_ctrl_msg(d, &req); -} - -static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 *val) -{ - struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; - - if (addr == af9015_af9013_config[0].demod_address || - addr == af9015_af9013_config[1].demod_address) - req.addr_len = 3; - - return af9015_ctrl_msg(d, &req); -} - -static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0, i = 0; - u16 addr; - u8 uninitialized_var(mbox), addr_len; - struct req_t req; - -/* TODO: implement bus lock - -The bus lock is needed because there is two tuners both using same I2C-address. -Due to that the only way to select correct tuner is use demodulator I2C-gate. - -................................................ -. AF9015 includes integrated AF9013 demodulator. -. ____________ ____________ . ____________ -.| uC | | demod | . | tuner | -.|------------| |------------| . |------------| -.| AF9015 | | AF9013/5 | . | MXL5003 | -.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | -.| | | | addr 0x38 | . | addr 0xc6 | -.|____________| | |____________| . |____________| -.................|.............................. - | ____________ ____________ - | | demod | | tuner | - | |------------| |------------| - | | AF9013 | | MXL5003 | - +----I2C-------|-----/ -----|-------I2C-------| | - | addr 0x3a | | addr 0xc6 | - |____________| |____________| -*/ - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (msg[i].addr == af9015_af9013_config[0].demod_address || - msg[i].addr == af9015_af9013_config[1].demod_address) { - addr = msg[i].buf[0] << 8; - addr += msg[i].buf[1]; - mbox = msg[i].buf[2]; - addr_len = 3; - } else { - addr = msg[i].buf[0]; - addr_len = 1; - /* mbox is don't care in that case */ - } - - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].addr == - af9015_af9013_config[0].demod_address) - req.cmd = READ_MEMORY; - else - req.cmd = READ_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i+1].len; - req.data = &msg[i+1].buf[0]; - ret = af9015_ctrl_msg(d, &req); - i += 2; - } else if (msg[i].flags & I2C_M_RD) { - ret = -EINVAL; - if (msg[i].addr == - af9015_af9013_config[0].demod_address) - goto error; - else - req.cmd = READ_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i].len; - req.data = &msg[i].buf[0]; - ret = af9015_ctrl_msg(d, &req); - i += 1; - } else { - if (msg[i].addr == - af9015_af9013_config[0].demod_address) - req.cmd = WRITE_MEMORY; - else - req.cmd = WRITE_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i].len-addr_len; - req.data = &msg[i].buf[addr_len]; - ret = af9015_ctrl_msg(d, &req); - i += 1; - } - if (ret) - goto error; - - } - ret = i; - -error: - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static u32 af9015_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm af9015_i2c_algo = { - .master_xfer = af9015_i2c_xfer, - .functionality = af9015_i2c_func, -}; - -static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) -{ - int ret; - u8 val, mask = 0x01; - - ret = af9015_read_reg(d, addr, &val); - if (ret) - return ret; - - mask <<= bit; - if (op) { - /* set bit */ - val |= mask; - } else { - /* clear bit */ - mask ^= 0xff; - val &= mask; - } - - return af9015_write_reg(d, addr, val); -} - -static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 1); -} - -static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 0); -} - -static int af9015_init_endpoint(struct dvb_usb_device *d) -{ - int ret; - u16 frame_size; - u8 packet_size; - deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); - - /* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. - We use smaller - about 1/4 from the original, 5 and 87. */ -#define TS_PACKET_SIZE 188 - -#define TS_USB20_PACKET_COUNT 87 -#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) - -#define TS_USB11_PACKET_COUNT 5 -#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) - -#define TS_USB20_MAX_PACKET_SIZE 512 -#define TS_USB11_MAX_PACKET_SIZE 64 - - if (d->udev->speed == USB_SPEED_FULL) { - frame_size = TS_USB11_FRAME_SIZE/4; - packet_size = TS_USB11_MAX_PACKET_SIZE/4; - } else { - frame_size = TS_USB20_FRAME_SIZE/4; - packet_size = TS_USB20_MAX_PACKET_SIZE/4; - } - - ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ - if (ret) - goto error; - if (af9015_config.dual_mode) { - ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ - if (ret) - goto error; - } - ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ - if (ret) - goto error; - if (af9015_config.dual_mode) { - ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ - if (ret) - goto error; - } - /* EP4 xfer length */ - ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); - if (ret) - goto error; - /* EP5 xfer length */ - ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ - if (ret) - goto error; - if (af9015_config.dual_mode) { - ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ - if (ret) - goto error; - } - - /* enable / disable mp2if2 */ - if (af9015_config.dual_mode) - ret = af9015_set_reg_bit(d, 0xd50b, 0); - else - ret = af9015_clear_reg_bit(d, 0xd50b, 0); - -error: - if (ret) - err("endpoint init failed:%d", ret); - return ret; -} - -static int af9015_copy_firmware(struct dvb_usb_device *d) -{ - int ret; - u8 fw_params[4]; - u8 val, i; - struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), - fw_params }; - deb_info("%s:\n", __func__); - - fw_params[0] = af9015_config.firmware_size >> 8; - fw_params[1] = af9015_config.firmware_size & 0xff; - fw_params[2] = af9015_config.firmware_checksum >> 8; - fw_params[3] = af9015_config.firmware_checksum & 0xff; - - /* wait 2nd demodulator ready */ - msleep(100); - - ret = af9015_read_reg_i2c(d, - af9015_af9013_config[1].demod_address, 0x98be, &val); - if (ret) - goto error; - else - deb_info("%s: firmware status:%02x\n", __func__, val); - - if (val == 0x0c) /* fw is running, no need for download */ - goto exit; - - /* set I2C master clock to fast (to speed up firmware copy) */ - ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ - if (ret) - goto error; - - msleep(50); - - /* copy firmware */ - ret = af9015_ctrl_msg(d, &req); - if (ret) - err("firmware copy cmd failed:%d", ret); - deb_info("%s: firmware copy done\n", __func__); - - /* set I2C master clock back to normal */ - ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ - if (ret) - goto error; - - /* request boot firmware */ - ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address, - 0xe205, 1); - deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); - if (ret) - goto error; - - for (i = 0; i < 15; i++) { - msleep(100); - - /* check firmware status */ - ret = af9015_read_reg_i2c(d, - af9015_af9013_config[1].demod_address, 0x98be, &val); - deb_info("%s: firmware status cmd status:%d fw status:%02x\n", - __func__, ret, val); - if (ret) - goto error; - - if (val == 0x0c || val == 0x04) /* success or fail */ - break; - } - - if (val == 0x04) { - err("firmware did not run"); - ret = -1; - } else if (val != 0x0c) { - err("firmware boot timeout"); - ret = -1; - } - -error: -exit: - return ret; -} - -/* hash (and dump) eeprom */ -static int af9015_eeprom_hash(struct usb_device *udev) -{ - static const unsigned int eeprom_size = 256; - unsigned int reg; - int ret; - u8 val, *eeprom; - struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - - eeprom = kmalloc(eeprom_size, GFP_KERNEL); - if (eeprom == NULL) - return -ENOMEM; - - for (reg = 0; reg < eeprom_size; reg++) { - req.addr = reg; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto free; - eeprom[reg] = val; - } - - if (dvb_usb_af9015_debug & 0x01) - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom, - eeprom_size); - - BUG_ON(eeprom_size % 4); - - af9015_config.eeprom_sum = 0; - for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) { - af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32; - af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]); - } - - deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum); - - ret = 0; -free: - kfree(eeprom); - return ret; -} - -static int af9015_init(struct dvb_usb_device *d) -{ - int ret; - deb_info("%s:\n", __func__); - - /* init RC canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); - if (ret) - goto error; - - ret = af9015_init_endpoint(d); - if (ret) - goto error; - -error: - return ret; -} - -static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - deb_info("%s: onoff:%d\n", __func__, onoff); - - if (onoff) - ret = af9015_set_reg_bit(adap->dev, 0xd503, 0); - else - ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0); - - return ret; -} - -static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - int ret; - u8 idx; - - deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", - __func__, index, pid, onoff); - - ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff)); - if (ret) - goto error; - - ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8)); - if (ret) - goto error; - - idx = ((index & 0x1f) | (1 << 5)); - ret = af9015_write_reg(adap->dev, 0xd504, idx); - -error: - return ret; -} - -static int af9015_download_firmware(struct usb_device *udev, - const struct firmware *fw) -{ - int i, len, remaining, ret; - struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; - u16 checksum = 0; - - deb_info("%s:\n", __func__); - - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; - - af9015_config.firmware_size = fw->size; - af9015_config.firmware_checksum = checksum; - - #define FW_ADDR 0x5100 /* firmware start address */ - #define LEN_MAX 55 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - - req.data_len = len; - req.data = (u8 *) &fw->data[fw->size - remaining]; - req.addr = FW_ADDR + fw->size - remaining; - - ret = af9015_rw_udev(udev, &req); - if (ret) { - err("firmware download failed:%d", ret); - goto error; - } - } - - /* firmware loaded, request boot */ - req.cmd = BOOT; - ret = af9015_rw_udev(udev, &req); - if (ret) { - err("firmware boot failed:%d", ret); - goto error; - } - -error: - return ret; -} - -struct af9015_rc_setup { - unsigned int id; - char *rc_codes; -}; - -static char *af9015_rc_setup_match(unsigned int id, - const struct af9015_rc_setup *table) -{ - for (; table->rc_codes; table++) - if (table->id == id) - return table->rc_codes; - return NULL; -} - -static const struct af9015_rc_setup af9015_rc_setup_modparam[] = { - { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, - { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, - { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, - { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, - { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, - { } -}; - -static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { - { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, - { 0xa3703d00, RC_MAP_ALINK_DTU_M }, - { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ - { } -}; - -static const struct af9015_rc_setup af9015_rc_setup_usbids[] = { - { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_RC, - RC_MAP_TERRATEC_SLIM_2 }, - { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, - RC_MAP_TERRATEC_SLIM }, - { (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700, - RC_MAP_AZUREWAVE_AD_TU700 }, - { (USB_VID_VISIONPLUS << 16) + USB_PID_TINYTWIN, - RC_MAP_AZUREWAVE_AD_TU700 }, - { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III, - RC_MAP_MSI_DIGIVOX_III }, - { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD, - RC_MAP_LEADTEK_Y04G0051 }, - { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X, - RC_MAP_AVERMEDIA_M135A }, - { (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT, - RC_MAP_TREKSTOR }, - { (USB_VID_KWORLD_2 << 16) + USB_PID_TINYTWIN_2, - RC_MAP_DIGITALNOW_TINYTWIN }, - { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3, - RC_MAP_DIGITALNOW_TINYTWIN }, - { } -}; - -static void af9015_set_remote_config(struct usb_device *udev, - struct dvb_usb_device_properties *props) -{ - u16 vid = le16_to_cpu(udev->descriptor.idVendor); - u16 pid = le16_to_cpu(udev->descriptor.idProduct); - - /* try to load remote based module param */ - props->rc.core.rc_codes = af9015_rc_setup_match( - dvb_usb_af9015_remote, af9015_rc_setup_modparam); - - /* try to load remote based eeprom hash */ - if (!props->rc.core.rc_codes) - props->rc.core.rc_codes = af9015_rc_setup_match( - af9015_config.eeprom_sum, af9015_rc_setup_hashes); - - /* try to load remote based USB ID */ - if (!props->rc.core.rc_codes) - props->rc.core.rc_codes = af9015_rc_setup_match( - (vid << 16) + pid, af9015_rc_setup_usbids); - - /* try to load remote based USB iManufacturer string */ - if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) { - /* Check USB manufacturer and product strings and try - to determine correct remote in case of chip vendor - reference IDs are used. - DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ - char manufacturer[10]; - memset(manufacturer, 0, sizeof(manufacturer)); - usb_string(udev, udev->descriptor.iManufacturer, - manufacturer, sizeof(manufacturer)); - if (!strcmp("MSI", manufacturer)) { - /* iManufacturer 1 MSI - iProduct 2 MSI K-VOX */ - props->rc.core.rc_codes = af9015_rc_setup_match( - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, - af9015_rc_setup_modparam); - } - } - - /* finally load "empty" just for leaving IR receiver enabled */ - if (!props->rc.core.rc_codes) - props->rc.core.rc_codes = RC_MAP_EMPTY; - - return; -} - -static int af9015_read_config(struct usb_device *udev) -{ - int ret; - u8 val, i, offset = 0; - struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - - /* IR remote controller */ - req.addr = AF9015_EEPROM_IR_MODE; - /* first message will timeout often due to possible hw bug */ - for (i = 0; i < 4; i++) { - ret = af9015_rw_udev(udev, &req); - if (!ret) - break; - } - if (ret) - goto error; - - ret = af9015_eeprom_hash(udev); - if (ret) - goto error; - - deb_info("%s: IR mode:%d\n", __func__, val); - for (i = 0; i < af9015_properties_count; i++) { - if (val == AF9015_IR_MODE_DISABLED) - af9015_properties[i].rc.core.rc_codes = NULL; - else - af9015_set_remote_config(udev, &af9015_properties[i]); - } - - /* TS mode - one or two receivers */ - req.addr = AF9015_EEPROM_TS_MODE; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_config.dual_mode = val; - deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode); - - /* Set adapter0 buffer size according to USB port speed, adapter1 buffer - size can be static because it is enabled only USB2.0 */ - for (i = 0; i < af9015_properties_count; i++) { - /* USB1.1 set smaller buffersize and disable 2nd adapter */ - if (udev->speed == USB_SPEED_FULL) { - af9015_properties[i].adapter[0].stream.u.bulk.buffersize - = TS_USB11_FRAME_SIZE; - /* disable 2nd adapter because we don't have - PID-filters */ - af9015_config.dual_mode = 0; - } else { - af9015_properties[i].adapter[0].stream.u.bulk.buffersize - = TS_USB20_FRAME_SIZE; - } - } - - if (af9015_config.dual_mode) { - /* read 2nd demodulator I2C address */ - req.addr = AF9015_EEPROM_DEMOD2_I2C; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_af9013_config[1].demod_address = val; - - /* enable 2nd adapter */ - for (i = 0; i < af9015_properties_count; i++) - af9015_properties[i].num_adapters = 2; - - } else { - /* disable 2nd adapter */ - for (i = 0; i < af9015_properties_count; i++) - af9015_properties[i].num_adapters = 1; - } - - for (i = 0; i < af9015_properties[0].num_adapters; i++) { - if (i == 1) - offset = AF9015_EEPROM_OFFSET; - /* xtal */ - req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - switch (val) { - case 0: - af9015_af9013_config[i].adc_clock = 28800; - break; - case 1: - af9015_af9013_config[i].adc_clock = 20480; - break; - case 2: - af9015_af9013_config[i].adc_clock = 28000; - break; - case 3: - af9015_af9013_config[i].adc_clock = 25000; - break; - }; - deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i, - val, af9015_af9013_config[i].adc_clock); - - /* tuner IF */ - req.addr = AF9015_EEPROM_IF1H + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_af9013_config[i].tuner_if = val << 8; - req.addr = AF9015_EEPROM_IF1L + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_af9013_config[i].tuner_if += val; - deb_info("%s: [%d] IF1:%d\n", __func__, i, - af9015_af9013_config[0].tuner_if); - - /* MT2060 IF1 */ - req.addr = AF9015_EEPROM_MT2060_IF1H + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_config.mt2060_if1[i] = val << 8; - req.addr = AF9015_EEPROM_MT2060_IF1L + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_config.mt2060_if1[i] += val; - deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i, - af9015_config.mt2060_if1[i]); - - /* tuner */ - req.addr = AF9015_EEPROM_TUNER_ID1 + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - switch (val) { - case AF9013_TUNER_ENV77H11D5: - case AF9013_TUNER_MT2060: - case AF9013_TUNER_QT1010: - case AF9013_TUNER_UNKNOWN: - case AF9013_TUNER_MT2060_2: - case AF9013_TUNER_TDA18271: - case AF9013_TUNER_QT1010A: - case AF9013_TUNER_TDA18218: - af9015_af9013_config[i].rf_spec_inv = 1; - break; - case AF9013_TUNER_MXL5003D: - case AF9013_TUNER_MXL5005D: - case AF9013_TUNER_MXL5005R: - case AF9013_TUNER_MXL5007T: - af9015_af9013_config[i].rf_spec_inv = 0; - break; - case AF9013_TUNER_MC44S803: - af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO; - af9015_af9013_config[i].rf_spec_inv = 1; - break; - default: - warn("tuner id:%d not supported, please report!", val); - return -ENODEV; - }; - - af9015_af9013_config[i].tuner = val; - deb_info("%s: [%d] tuner id:%d\n", __func__, i, val); - } - -error: - if (ret) - err("eeprom read failed:%d", ret); - - /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM - content :-( Override some wrong values here. Ditto for the - AVerTV Red HD+ (A850T) device. */ - if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA && - ((le16_to_cpu(udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850) || - (le16_to_cpu(udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850T))) { - deb_info("%s: AverMedia A850: overriding config\n", __func__); - /* disable dual mode */ - af9015_config.dual_mode = 0; - /* disable 2nd adapter */ - for (i = 0; i < af9015_properties_count; i++) - af9015_properties[i].num_adapters = 1; - - /* set correct IF */ - af9015_af9013_config[0].tuner_if = 4570; - } - - return ret; -} - -static int af9015_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - int ret; - u8 reply; - struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; - - ret = af9015_rw_udev(udev, &req); - if (ret) - return ret; - - deb_info("%s: reply:%02x\n", __func__, reply); - if (reply == 0x02) - *cold = 0; - else - *cold = 1; - - return ret; -} - -static int af9015_rc_query(struct dvb_usb_device *d) -{ - struct af9015_state *priv = d->priv; - int ret; - u8 buf[17]; - - /* read registers needed to detect remote controller code */ - ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); - if (ret) - goto error; - - /* If any of these are non-zero, assume invalid data */ - if (buf[1] || buf[2] || buf[3]) - return ret; - - /* Check for repeat of previous code */ - if ((priv->rc_repeat != buf[6] || buf[0]) && - !memcmp(&buf[12], priv->rc_last, 4)) { - deb_rc("%s: key repeated\n", __func__); - rc_keydown(d->rc_dev, priv->rc_keycode, 0); - priv->rc_repeat = buf[6]; - return ret; - } - - /* Only process key if canary killed */ - if (buf[16] != 0xff && buf[0] != 0x01) { - deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__, - buf[12], buf[13], buf[14], buf[15]); - - /* Reset the canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); - if (ret) - goto error; - - /* Remember this key */ - memcpy(priv->rc_last, &buf[12], 4); - if (buf[14] == (u8) ~buf[15]) { - if (buf[12] == (u8) ~buf[13]) { - /* NEC */ - priv->rc_keycode = buf[12] << 8 | buf[14]; - } else { - /* NEC extended*/ - priv->rc_keycode = buf[12] << 16 | - buf[13] << 8 | buf[14]; - } - } else { - /* 32 bit NEC */ - priv->rc_keycode = buf[12] << 24 | buf[13] << 16 | - buf[14] << 8 | buf[15]; - } - rc_keydown(d->rc_dev, priv->rc_keycode, 0); - } else { - deb_rc("%s: no key press\n", __func__); - /* Invalidate last keypress */ - /* Not really needed, but helps with debug */ - priv->rc_last[2] = priv->rc_last[3]; - } - - priv->rc_repeat = buf[6]; - -error: - if (ret) - err("%s: failed:%d", __func__, ret); - - return ret; -} - -/* init 2nd I2C adapter */ -static int af9015_i2c_init(struct dvb_usb_device *d) -{ - int ret; - struct af9015_state *state = d->priv; - deb_info("%s:\n", __func__); - - strncpy(state->i2c_adap.name, d->desc->name, - sizeof(state->i2c_adap.name)); - state->i2c_adap.algo = d->props.i2c_algo; - state->i2c_adap.algo_data = NULL; - state->i2c_adap.dev.parent = &d->udev->dev; - - i2c_set_adapdata(&state->i2c_adap, d); - - ret = i2c_add_adapter(&state->i2c_adap); - if (ret < 0) - err("could not add i2c adapter"); - - return ret; -} - -static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) -{ - int ret; - struct af9015_state *state = adap->dev->priv; - struct i2c_adapter *i2c_adap; - - if (adap->id == 0) { - /* select I2C adapter */ - i2c_adap = &adap->dev->i2c_adap; - - deb_info("%s: init I2C\n", __func__); - ret = af9015_i2c_init(adap->dev); - } else { - /* select I2C adapter */ - i2c_adap = &state->i2c_adap; - - /* copy firmware to 2nd demodulator */ - if (af9015_config.dual_mode) { - ret = af9015_copy_firmware(adap->dev); - if (ret) { - err("firmware copy to 2nd frontend " \ - "failed, will disable it"); - af9015_config.dual_mode = 0; - return -ENODEV; - } - } else { - return -ENODEV; - } - } - - /* attach demodulator */ - adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], - i2c_adap); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static struct mt2060_config af9015_mt2060_config = { - .i2c_address = 0xc0, - .clock_out = 0, -}; - -static struct qt1010_config af9015_qt1010_config = { - .i2c_address = 0xc4, -}; - -static struct tda18271_config af9015_tda18271_config = { - .gate = TDA18271_GATE_DIGITAL, - .small_i2c = TDA18271_16_BYTE_CHUNK_INIT, -}; - -static struct mxl5005s_config af9015_mxl5003_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_DEFAULT, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static struct mxl5005s_config af9015_mxl5005_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_OFF, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static struct mc44s803_config af9015_mc44s803_config = { - .i2c_address = 0xc0, - .dig_out = 1, -}; - -static struct tda18218_config af9015_tda18218_config = { - .i2c_address = 0xc0, - .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ -}; - -static struct mxl5007t_config af9015_mxl5007t_config = { - .xtal_freq_hz = MxL_XTAL_24_MHZ, - .if_freq_hz = MxL_IF_4_57_MHZ, -}; - -static int af9015_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct af9015_state *state = adap->dev->priv; - struct i2c_adapter *i2c_adap; - int ret; - deb_info("%s:\n", __func__); - - /* select I2C adapter */ - if (adap->id == 0) - i2c_adap = &adap->dev->i2c_adap; - else - i2c_adap = &state->i2c_adap; - - switch (af9015_af9013_config[adap->id].tuner) { - case AF9013_TUNER_MT2060: - case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap, - &af9015_mt2060_config, - af9015_config.mt2060_if1[adap->id]) - == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_QT1010: - case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap, - &af9015_qt1010_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap, - &af9015_tda18271_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap, - &af9015_tda18218_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, - &af9015_mxl5003_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MXL5005D: - case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, - &af9015_mxl5005_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap, - DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap, - &af9015_mc44s803_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe, i2c_adap, - 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; - break; - case AF9013_TUNER_UNKNOWN: - default: - ret = -ENODEV; - err("Unknown tuner id:%d", - af9015_af9013_config[adap->id].tuner); - } - return ret; -} - -static struct usb_device_id af9015_usb_table[] = { -/* 0 */{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, - {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, - {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, - {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, -/* 5 */{USB_DEVICE(USB_VID_VISIONPLUS, - USB_PID_TINYTWIN)}, - {USB_DEVICE(USB_VID_VISIONPLUS, - USB_PID_AZUREWAVE_AD_TU700)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, -/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, - {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, - {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, -/* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, - {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, -/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, - {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, -/* 25 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)}, - {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, -/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)}, - {USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)}, -/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, - {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, - {0}, -}; -MODULE_DEVICE_TABLE(usb, af9015_usb_table); - -#define AF9015_RC_INTERVAL 500 -static struct dvb_usb_device_properties af9015_properties[] = { - { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = af9015_download_firmware, - .firmware = "dvb-usb-af9015.fw", - .no_reconnect = 1, - - .size_of_priv = sizeof(struct af9015_state), - - .num_adapters = 2, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, - - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, - }, - }, - { - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x85, - .u = { - .bulk = { - .buffersize = - TS_USB20_FRAME_SIZE, - } - } - }, - } - }, - - .identify_state = af9015_identify_state, - - .rc.core = { - .protocol = RC_TYPE_NEC, - .module_name = "af9015", - .rc_query = af9015_rc_query, - .rc_interval = AF9015_RC_INTERVAL, - .allowed_protos = RC_TYPE_NEC, - }, - - .i2c_algo = &af9015_i2c_algo, - - .num_device_descs = 12, /* check max from dvb-usb.h */ - .devices = { - { - .name = "Afatech AF9015 DVB-T USB2.0 stick", - .cold_ids = {&af9015_usb_table[0], - &af9015_usb_table[1], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "Leadtek WinFast DTV Dongle Gold", - .cold_ids = {&af9015_usb_table[2], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "Pinnacle PCTV 71e", - .cold_ids = {&af9015_usb_table[3], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "KWorld PlusTV Dual DVB-T Stick " \ - "(DVB-T 399U)", - .cold_ids = {&af9015_usb_table[4], - &af9015_usb_table[25], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "DigitalNow TinyTwin DVB-T Receiver", - .cold_ids = {&af9015_usb_table[5], - &af9015_usb_table[28], - &af9015_usb_table[36], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "TwinHan AzureWave AD-TU700(704J)", - .cold_ids = {&af9015_usb_table[6], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "TerraTec Cinergy T USB XE", - .cold_ids = {&af9015_usb_table[7], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "KWorld PlusTV Dual DVB-T PCI " \ - "(DVB-T PC160-2T)", - .cold_ids = {&af9015_usb_table[8], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "AVerMedia AVerTV DVB-T Volar X", - .cold_ids = {&af9015_usb_table[9], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "TerraTec Cinergy T Stick RC", - .cold_ids = {&af9015_usb_table[33], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "TerraTec Cinergy T Stick Dual RC", - .cold_ids = {&af9015_usb_table[34], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "AverMedia AVerTV Red HD+ (A850T)", - .cold_ids = {&af9015_usb_table[35], NULL}, - .warm_ids = {NULL}, - }, - } - }, { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = af9015_download_firmware, - .firmware = "dvb-usb-af9015.fw", - .no_reconnect = 1, - - .size_of_priv = sizeof(struct af9015_state), - - .num_adapters = 2, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, - - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, - }, - }, - { - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x85, - .u = { - .bulk = { - .buffersize = - TS_USB20_FRAME_SIZE, - } - } - }, - } - }, - - .identify_state = af9015_identify_state, - - .rc.core = { - .protocol = RC_TYPE_NEC, - .module_name = "af9015", - .rc_query = af9015_rc_query, - .rc_interval = AF9015_RC_INTERVAL, - .allowed_protos = RC_TYPE_NEC, - }, - - .i2c_algo = &af9015_i2c_algo, - - .num_device_descs = 9, /* check max from dvb-usb.h */ - .devices = { - { - .name = "Xtensions XD-380", - .cold_ids = {&af9015_usb_table[10], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "MSI DIGIVOX Duo", - .cold_ids = {&af9015_usb_table[11], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "Fujitsu-Siemens Slim Mobile USB DVB-T", - .cold_ids = {&af9015_usb_table[12], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "Telestar Starstick 2", - .cold_ids = {&af9015_usb_table[13], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "AVerMedia A309", - .cold_ids = {&af9015_usb_table[14], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "MSI Digi VOX mini III", - .cold_ids = {&af9015_usb_table[15], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "KWorld USB DVB-T TV Stick II " \ - "(VS-DVB-T 395U)", - .cold_ids = {&af9015_usb_table[16], - &af9015_usb_table[17], - &af9015_usb_table[18], - &af9015_usb_table[31], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "TrekStor DVB-T USB Stick", - .cold_ids = {&af9015_usb_table[19], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "AverMedia AVerTV Volar Black HD " \ - "(A850)", - .cold_ids = {&af9015_usb_table[20], NULL}, - .warm_ids = {NULL}, - }, - } - }, { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = af9015_download_firmware, - .firmware = "dvb-usb-af9015.fw", - .no_reconnect = 1, - - .size_of_priv = sizeof(struct af9015_state), - - .num_adapters = 2, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, - - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, - }, - }, - { - .frontend_attach = - af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x85, - .u = { - .bulk = { - .buffersize = - TS_USB20_FRAME_SIZE, - } - } - }, - } - }, - - .identify_state = af9015_identify_state, - - .rc.core = { - .protocol = RC_TYPE_NEC, - .module_name = "af9015", - .rc_query = af9015_rc_query, - .rc_interval = AF9015_RC_INTERVAL, - .allowed_protos = RC_TYPE_NEC, - }, - - .i2c_algo = &af9015_i2c_algo, - - .num_device_descs = 9, /* check max from dvb-usb.h */ - .devices = { - { - .name = "AverMedia AVerTV Volar GPS 805 (A805)", - .cold_ids = {&af9015_usb_table[21], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \ - "V3.0", - .cold_ids = {&af9015_usb_table[22], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "KWorld Digial MC-810", - .cold_ids = {&af9015_usb_table[23], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "Genius TVGo DVB-T03", - .cold_ids = {&af9015_usb_table[24], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "KWorld PlusTV DVB-T PCI Pro Card " \ - "(DVB-T PC160-T)", - .cold_ids = {&af9015_usb_table[26], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "Sveon STV20 Tuner USB DVB-T HDTV", - .cold_ids = {&af9015_usb_table[27], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "Leadtek WinFast DTV2000DS", - .cold_ids = {&af9015_usb_table[29], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "KWorld USB DVB-T Stick Mobile " \ - "(UB383-T)", - .cold_ids = {&af9015_usb_table[30], NULL}, - .warm_ids = {NULL}, - }, - { - .name = "AverMedia AVerTV Volar M (A815Mac)", - .cold_ids = {&af9015_usb_table[32], NULL}, - .warm_ids = {NULL}, - }, - } - }, -}; - -static int af9015_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret = 0; - struct dvb_usb_device *d = NULL; - struct usb_device *udev = interface_to_usbdev(intf); - u8 i; - - deb_info("%s: interface:%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - /* interface 0 is used by DVB-T receiver and - interface 1 is for remote controller (HID) */ - if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { - ret = af9015_read_config(udev); - if (ret) - return ret; - - for (i = 0; i < af9015_properties_count; i++) { - ret = dvb_usb_device_init(intf, &af9015_properties[i], - THIS_MODULE, &d, adapter_nr); - if (!ret) - break; - if (ret != -ENODEV) - return ret; - } - if (ret) - return ret; - - if (d) - ret = af9015_init(d); - } - - return ret; -} - -static void af9015_i2c_exit(struct dvb_usb_device *d) -{ - struct af9015_state *state = d->priv; - deb_info("%s:\n", __func__); - - /* remove 2nd I2C adapter */ - if (d->state & DVB_USB_STATE_I2C) - i2c_del_adapter(&state->i2c_adap); -} - -static void af9015_usb_device_exit(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - deb_info("%s:\n", __func__); - - /* remove 2nd I2C adapter */ - if (d != NULL && d->desc != NULL) - af9015_i2c_exit(d); - - dvb_usb_device_exit(intf); -} - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver af9015_usb_driver = { - .name = "dvb_usb_af9015", - .probe = af9015_usb_probe, - .disconnect = af9015_usb_device_exit, - .id_table = af9015_usb_table, -}; - -/* module stuff */ -static int __init af9015_usb_module_init(void) -{ - int ret; - ret = usb_register(&af9015_usb_driver); - if (ret) - err("module init failed:%d", ret); - - return ret; -} - -static void __exit af9015_usb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&af9015_usb_driver); -} - -module_init(af9015_usb_module_init); -module_exit(af9015_usb_module_exit); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9015.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9015.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9015.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/af9015.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -/* - * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * Thanks to Afatech who kindly provided information. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _DVB_USB_AF9015_H_ -#define _DVB_USB_AF9015_H_ - -#define DVB_USB_LOG_PREFIX "af9015" -#include "dvb-usb.h" - -#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) -#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) -#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args) -#define deb_reg(args...) dprintk(dvb_usb_af9015_debug, 0x08, args) -#define deb_i2c(args...) dprintk(dvb_usb_af9015_debug, 0x10, args) -#define deb_fw(args...) dprintk(dvb_usb_af9015_debug, 0x20, args) - -#define AF9015_I2C_EEPROM 0xa0 -#define AF9015_I2C_DEMOD 0x38 -#define AF9015_USB_TIMEOUT 2000 - -/* EEPROM locations */ -#define AF9015_EEPROM_IR_MODE 0x18 -#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34 -#define AF9015_EEPROM_TS_MODE 0x31 -#define AF9015_EEPROM_DEMOD2_I2C 0x32 - -#define AF9015_EEPROM_SAW_BW1 0x35 -#define AF9015_EEPROM_XTAL_TYPE1 0x36 -#define AF9015_EEPROM_SPEC_INV1 0x37 -#define AF9015_EEPROM_IF1L 0x38 -#define AF9015_EEPROM_IF1H 0x39 -#define AF9015_EEPROM_MT2060_IF1L 0x3a -#define AF9015_EEPROM_MT2060_IF1H 0x3b -#define AF9015_EEPROM_TUNER_ID1 0x3c - -#define AF9015_EEPROM_SAW_BW2 0x45 -#define AF9015_EEPROM_XTAL_TYPE2 0x46 -#define AF9015_EEPROM_SPEC_INV2 0x47 -#define AF9015_EEPROM_IF2L 0x48 -#define AF9015_EEPROM_IF2H 0x49 -#define AF9015_EEPROM_MT2060_IF2L 0x4a -#define AF9015_EEPROM_MT2060_IF2H 0x4b -#define AF9015_EEPROM_TUNER_ID2 0x4c - -#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1) - -struct req_t { - u8 cmd; /* [0] */ - /* seq */ /* [1] */ - u8 i2c_addr; /* [2] */ - u16 addr; /* [3|4] */ - u8 mbox; /* [5] */ - u8 addr_len; /* [6] */ - u8 data_len; /* [7] */ - u8 *data; -}; - -enum af9015_cmd { - GET_CONFIG = 0x10, - DOWNLOAD_FIRMWARE = 0x11, - BOOT = 0x13, - READ_MEMORY = 0x20, - WRITE_MEMORY = 0x21, - READ_WRITE_I2C = 0x22, - COPY_FIRMWARE = 0x23, - RECONNECT_USB = 0x5a, - WRITE_VIRTUAL_MEMORY = 0x26, - GET_IR_CODE = 0x27, - READ_I2C, - WRITE_I2C, -}; - -enum af9015_ir_mode { - AF9015_IR_MODE_DISABLED = 0, - AF9015_IR_MODE_HID, - AF9015_IR_MODE_RLC, - AF9015_IR_MODE_RC6, - AF9015_IR_MODE_POLLING, /* just guess */ -}; - -struct af9015_state { - struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */ - u8 rc_repeat; - u32 rc_keycode; - u8 rc_last[4]; -}; - -struct af9015_config { - u8 dual_mode:1; - u16 mt2060_if1[2]; - u16 firmware_size; - u16 firmware_checksum; - u32 eeprom_sum; -}; - -enum af9015_remote { - AF9015_REMOTE_NONE = 0, -/* 1 */ AF9015_REMOTE_A_LINK_DTU_M, - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, - AF9015_REMOTE_MYGICTV_U718, - AF9015_REMOTE_DIGITTRADE_DVB_T, -/* 5 */ AF9015_REMOTE_AVERMEDIA_KS, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/anysee.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/anysee.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/anysee.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/anysee.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,530 +0,0 @@ -/* - * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * TODO: - * - add smart card reader support for Conditional Access (CA) - * - * Card reader in Anysee is nothing more than ISO 7816 card reader. - * There is no hardware CAM in any Anysee device sold. - * In my understanding it should be implemented by making own module - * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This - * module registers serial interface that can be used to communicate - * with any ISO 7816 smart card. - * - * Any help according to implement serial smart card reader support - * is highly welcome! - */ - -#include "anysee.h" -#include "tda1002x.h" -#include "mt352.h" -#include "mt352_priv.h" -#include "zl10353.h" - -/* debug */ -static int dvb_usb_anysee_debug; -module_param_named(debug, dvb_usb_anysee_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -static int dvb_usb_anysee_delsys; -module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644); -MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)"); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static DEFINE_MUTEX(anysee_usb_mutex); - -static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, - u8 *rbuf, u8 rlen) -{ - struct anysee_state *state = d->priv; - int act_len, ret; - u8 buf[64]; - - if (slen > sizeof(buf)) - slen = sizeof(buf); - memcpy(&buf[0], sbuf, slen); - buf[60] = state->seq++; - - if (mutex_lock_interruptible(&anysee_usb_mutex) < 0) - return -EAGAIN; - - /* We need receive one message more after dvb_usb_generic_rw due - to weird transaction flow, which is 1 x send + 2 x receive. */ - ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); - - if (!ret) { - /* receive 2nd answer */ - ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf), - &act_len, 2000); - if (ret) - err("%s: recv bulk message failed: %d", __func__, ret); - else { - deb_xfer("<<< "); - debug_dump(buf, act_len, deb_xfer); - } - } - - /* read request, copy returned data to return buf */ - if (!ret && rbuf && rlen) - memcpy(rbuf, buf, rlen); - - mutex_unlock(&anysee_usb_mutex); - - return ret; -} - -static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val) -{ - u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01}; - int ret; - ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1); - deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val); - return ret; -} - -static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val) -{ - u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val}; - deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val); - return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); -} - -static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) -{ - u8 buf[] = {CMD_GET_HW_INFO}; - return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3); -} - -static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00}; - deb_info("%s: onoff:%02x\n", __func__, onoff); - return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0); -} - -static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval) -{ - u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval}; - deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval); - return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); -} - -static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) -{ - u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff}; - deb_info("%s: onoff:%02x\n", __func__, onoff); - return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); -} - -static int anysee_init(struct dvb_usb_device *d) -{ - int ret; - /* LED light */ - ret = anysee_led_ctrl(d, 0x01, 0x03); - if (ret) - return ret; - - /* enable IR */ - ret = anysee_ir_ctrl(d, 1); - if (ret) - return ret; - - return 0; -} - -/* I2C */ -static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0, inc, i = 0; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - u8 buf[6]; - buf[0] = CMD_I2C_READ; - buf[1] = msg[i].addr + 1; - buf[2] = msg[i].buf[0]; - buf[3] = 0x00; - buf[4] = 0x00; - buf[5] = 0x01; - ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf, - msg[i+1].len); - inc = 2; - } else { - u8 buf[4+msg[i].len]; - buf[0] = CMD_I2C_WRITE; - buf[1] = msg[i].addr; - buf[2] = msg[i].len; - buf[3] = 0x01; - memcpy(&buf[4], msg[i].buf, msg[i].len); - ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); - inc = 1; - } - if (ret) - break; - - i += inc; - } - - mutex_unlock(&d->i2c_mutex); - - return ret ? ret : i; -} - -static u32 anysee_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm anysee_i2c_algo = { - .master_xfer = anysee_master_xfer, - .functionality = anysee_i2c_func, -}; - -static int anysee_mt352_demod_init(struct dvb_frontend *fe) -{ - static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 }; - static u8 reset[] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; - static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - - return 0; -} - -/* Callbacks for DVB USB */ -static struct tda10023_config anysee_tda10023_config = { - .demod_address = 0x1a, - .invert = 0, - .xtal = 16000000, - .pll_m = 11, - .pll_p = 3, - .pll_n = 1, - .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, - .deltaf = 0xfeeb, -}; - -static struct mt352_config anysee_mt352_config = { - .demod_address = 0x1e, - .demod_init = anysee_mt352_demod_init, -}; - -static struct zl10353_config anysee_zl10353_config = { - .demod_address = 0x1e, - .parallel_ts = 1, -}; - -static int anysee_frontend_attach(struct dvb_usb_adapter *adap) -{ - int ret; - struct anysee_state *state = adap->dev->priv; - u8 hw_info[3]; - u8 io_d; /* IO port D */ - - /* check which hardware we have - We must do this call two times to get reliable values (hw bug). */ - ret = anysee_get_hw_info(adap->dev, hw_info); - if (ret) - return ret; - ret = anysee_get_hw_info(adap->dev, hw_info); - if (ret) - return ret; - - /* Meaning of these info bytes are guessed. */ - info("firmware version:%d.%d.%d hardware id:%d", - 0, hw_info[1], hw_info[2], hw_info[0]); - - ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */ - if (ret) - return ret; - deb_info("%s: IO port D:%02x\n", __func__, io_d); - - /* Select demod using trial and error method. */ - - /* Try to attach demodulator in following order: - model demod hw firmware - 1. E30 MT352 02 0.2.1 - 2. E30 ZL10353 02 0.2.1 - 3. E30 Combo ZL10353 0f 0.1.2 DVB-T/C combo - 4. E30 Plus ZL10353 06 0.1.0 - 5. E30C Plus TDA10023 0a 0.1.0 rev 0.2 - E30C Plus TDA10023 0f 0.1.2 rev 0.4 - E30 Combo TDA10023 0f 0.1.2 DVB-T/C combo - */ - - /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */ - adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config, - &adap->dev->i2c_adap); - if (adap->fe != NULL) { - state->tuner = DVB_PLL_THOMSON_DTT7579; - return 0; - } - - /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */ - adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &adap->dev->i2c_adap); - if (adap->fe != NULL) { - state->tuner = DVB_PLL_THOMSON_DTT7579; - return 0; - } - - /* for E30 Combo Plus DVB-T demodulator */ - if (dvb_usb_anysee_delsys) { - ret = anysee_write_reg(adap->dev, 0xb0, 0x01); - if (ret) - return ret; - - /* Zarlink ZL10353 DVB-T demod */ - adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &adap->dev->i2c_adap); - if (adap->fe != NULL) { - state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A; - return 0; - } - } - - /* connect demod on IO port D for TDA10023 & ZL10353 */ - ret = anysee_write_reg(adap->dev, 0xb0, 0x25); - if (ret) - return ret; - - /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */ - adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &adap->dev->i2c_adap); - if (adap->fe != NULL) { - state->tuner = DVB_PLL_THOMSON_DTT7579; - return 0; - } - - /* IO port E - E30C rev 0.4 board requires this */ - ret = anysee_write_reg(adap->dev, 0xb1, 0xa7); - if (ret) - return ret; - - /* Philips TDA10023 DVB-C demod */ - adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config, - &adap->dev->i2c_adap, 0x48); - if (adap->fe != NULL) { - state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A; - return 0; - } - - /* return IO port D to init value for safe */ - ret = anysee_write_reg(adap->dev, 0xb0, io_d); - if (ret) - return ret; - - err("Unknown Anysee version: %02x %02x %02x. "\ - "Please report the .", - hw_info[0], hw_info[1], hw_info[2]); - - return -ENODEV; -} - -static int anysee_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct anysee_state *state = adap->dev->priv; - deb_info("%s:\n", __func__); - - switch (state->tuner) { - case DVB_PLL_THOMSON_DTT7579: - /* Thomson dtt7579 (not sure) PLL inside of: - Samsung DNOS404ZH102A NIM - Samsung DNOS404ZH103A NIM */ - dvb_attach(dvb_pll_attach, adap->fe, 0x61, - NULL, DVB_PLL_THOMSON_DTT7579); - break; - case DVB_PLL_SAMSUNG_DTOS403IH102A: - /* Unknown PLL inside of Samsung DTOS403IH102A tuner module */ - dvb_attach(dvb_pll_attach, adap->fe, 0xc0, - &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); - break; - } - - return 0; -} - -static int anysee_rc_query(struct dvb_usb_device *d) -{ - u8 buf[] = {CMD_GET_IR_CODE}; - u8 ircode[2]; - int ret; - - /* Remote controller is basic NEC using address byte 0x08. - Anysee device RC query returns only two bytes, status and code, - address byte is dropped. Also it does not return any value for - NEC RCs having address byte other than 0x08. Due to that, we - cannot use that device as standard NEC receiver. - It could be possible make hack which reads whole code directly - from device memory... */ - - ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode)); - if (ret) - return ret; - - if (ircode[0]) { - deb_rc("%s: key pressed %02x\n", __func__, ircode[1]); - rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0); - } - - return 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties anysee_properties; - -static int anysee_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d; - struct usb_host_interface *alt; - int ret; - - /* There is one interface with two alternate settings. - Alternate setting 0 is for bulk transfer. - Alternate setting 1 is for isochronous transfer. - We use bulk transfer (alternate setting 0). */ - if (intf->num_altsetting < 1) - return -ENODEV; - - /* - * Anysee is always warm (its USB-bridge, Cypress FX2, uploads - * firmware from eeprom). If dvb_usb_device_init() succeeds that - * means d is a valid pointer. - */ - ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d, - adapter_nr); - if (ret) - return ret; - - alt = usb_altnum_to_altsetting(intf, 0); - if (alt == NULL) { - deb_info("%s: no alt found!\n", __func__); - return -ENODEV; - } - - ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - if (ret) - return ret; - - return anysee_init(d); -} - -static struct usb_device_id anysee_table[] = { - { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, - { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, anysee_table); - -static struct dvb_usb_device_properties anysee_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = sizeof(struct anysee_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = anysee_streaming_ctrl, - .frontend_attach = anysee_frontend_attach, - .tuner_attach = anysee_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = (16*512), - } - } - }, - } - }, - - .rc.core = { - .rc_codes = RC_MAP_ANYSEE, - .protocol = RC_TYPE_OTHER, - .module_name = "anysee", - .rc_query = anysee_rc_query, - .rc_interval = 250, /* windows driver uses 500ms */ - }, - - .i2c_algo = &anysee_i2c_algo, - - .generic_bulk_ctrl_endpoint = 1, - - .num_device_descs = 1, - .devices = { - { - .name = "Anysee DVB USB2.0", - .cold_ids = {NULL}, - .warm_ids = {&anysee_table[0], - &anysee_table[1], NULL}, - }, - } -}; - -static struct usb_driver anysee_driver = { - .name = "dvb_usb_anysee", - .probe = anysee_probe, - .disconnect = dvb_usb_device_exit, - .id_table = anysee_table, -}; - -/* module stuff */ -static int __init anysee_module_init(void) -{ - int ret; - - ret = usb_register(&anysee_driver); - if (ret) - err("%s: usb_register failed. Error number %d", __func__, ret); - - return ret; -} - -static void __exit anysee_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&anysee_driver); -} - -module_init(anysee_module_init); -module_exit(anysee_module_exit); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/anysee.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/anysee.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/anysee.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/anysee.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,304 +0,0 @@ -/* - * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver - * - * Copyright (C) 2007 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * TODO: - * - add smart card reader support for Conditional Access (CA) - * - * Card reader in Anysee is nothing more than ISO 7816 card reader. - * There is no hardware CAM in any Anysee device sold. - * In my understanding it should be implemented by making own module - * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This - * module registers serial interface that can be used to communicate - * with any ISO 7816 smart card. - * - * Any help according to implement serial smart card reader support - * is highly welcome! - */ - -#ifndef _DVB_USB_ANYSEE_H_ -#define _DVB_USB_ANYSEE_H_ - -#define DVB_USB_LOG_PREFIX "anysee" -#include "dvb-usb.h" - -#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) -#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) -#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args) -#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args) -#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args) -#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args) - -enum cmd { - CMD_I2C_READ = 0x33, - CMD_I2C_WRITE = 0x31, - CMD_REG_READ = 0xb0, - CMD_REG_WRITE = 0xb1, - CMD_STREAMING_CTRL = 0x12, - CMD_LED_AND_IR_CTRL = 0x16, - CMD_GET_IR_CODE = 0x41, - CMD_GET_HW_INFO = 0x19, - CMD_SMARTCARD = 0x34, -}; - -struct anysee_state { - u8 tuner; - u8 seq; -}; - -#endif - -/*************************************************************************** - * USB API description (reverse engineered) - *************************************************************************** - -Transaction flow: -================= -BULK[00001] >>> REQUEST PACKET 64 bytes -BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY) -BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY) - -General reply packet(s) are always used if not own reply defined. - -============================================================================ -| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY) -============================================================================ -| 00 | reply data (if any) from previous transaction -| | Just same reply packet as returned during previous transaction. -| | Needed only if reply is missed in previous transaction. -| | Just skip normally. ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY) -============================================================================ -| 00 | reply data (if any) ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | I2C WRITE REQUEST PACKET -============================================================================ -| 00 | 0x31 I2C write command ----------------------------------------------------------------------------- -| 01 | i2c address ----------------------------------------------------------------------------- -| 02 | data length -| | 0x02 (for typical I2C reg / val pair) ----------------------------------------------------------------------------- -| 03 | 0x01 ----------------------------------------------------------------------------- -| 04- | data ----------------------------------------------------------------------------- -| -59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | I2C READ REQUEST PACKET -============================================================================ -| 00 | 0x33 I2C read command ----------------------------------------------------------------------------- -| 01 | i2c address + 1 ----------------------------------------------------------------------------- -| 02 | register ----------------------------------------------------------------------------- -| 03 | 0x00 ----------------------------------------------------------------------------- -| 04 | 0x00 ----------------------------------------------------------------------------- -| 05 | 0x01 ----------------------------------------------------------------------------- -| 06-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET -============================================================================ -| 00 | 0xb1 register write command ----------------------------------------------------------------------------- -| 01-02 | register ----------------------------------------------------------------------------- -| 03 | 0x01 ----------------------------------------------------------------------------- -| 04 | value ----------------------------------------------------------------------------- -| 05-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET -============================================================================ -| 00 | 0xb0 register read command ----------------------------------------------------------------------------- -| 01-02 | register ----------------------------------------------------------------------------- -| 03 | 0x01 ----------------------------------------------------------------------------- -| 04-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | LED CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x16 LED and IR control command ----------------------------------------------------------------------------- -| 01 | 0x01 (LED) ----------------------------------------------------------------------------- -| 03 | 0x00 blink -| | 0x01 lights continuously ----------------------------------------------------------------------------- -| 04 | blink interval -| | 0x00 fastest (looks like LED lights continuously) -| | 0xff slowest ----------------------------------------------------------------------------- -| 05-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | IR CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x16 LED and IR control command ----------------------------------------------------------------------------- -| 01 | 0x02 (IR) ----------------------------------------------------------------------------- -| 03 | 0x00 IR disabled -| | 0x01 IR enabled ----------------------------------------------------------------------------- -| 04-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | STREAMING CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x12 streaming control command ----------------------------------------------------------------------------- -| 01 | 0x00 streaming disabled -| | 0x01 streaming enabled ----------------------------------------------------------------------------- -| 02 | 0x00 ----------------------------------------------------------------------------- -| 03-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | REMOTE CONTROL REQUEST PACKET -============================================================================ -| 00 | 0x41 remote control command ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | REMOTE CONTROL REPLY PACKET -============================================================================ -| 00 | 0x00 code not received -| | 0x01 code received ----------------------------------------------------------------------------- -| 01 | remote control code ----------------------------------------------------------------------------- -| 02-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | GET HARDWARE INFO REQUEST PACKET -============================================================================ -| 00 | 0x19 get hardware info command ----------------------------------------------------------------------------- -| 01-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | GET HARDWARE INFO REPLY PACKET -============================================================================ -| 00 | hardware id ----------------------------------------------------------------------------- -| 01-02 | firmware version ----------------------------------------------------------------------------- -| 03-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -============================================================================ -| 00-63 | SMART CARD READER PACKET -============================================================================ -| 00 | 0x34 smart card reader command ----------------------------------------------------------------------------- -| xx | ----------------------------------------------------------------------------- -| xx-59 | don't care ----------------------------------------------------------------------------- -| 60 | packet sequence number ----------------------------------------------------------------------------- -| 61-63 | don't care ----------------------------------------------------------------------------- - -*/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/au6610.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/au6610.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/au6610.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/au6610.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,257 +0,0 @@ -/* - * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. - * - * Copyright (C) 2006 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "au6610.h" -#include "zl10353.h" -#include "qt1010.h" - -/* debug */ -static int dvb_usb_au6610_debug; -module_param_named(debug, dvb_usb_au6610_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - int ret; - u16 index; - u8 usb_buf[6]; /* enough for all known requests, - read returns 5 and write 6 bytes */ - switch (wlen) { - case 1: - index = wbuf[0] << 8; - break; - case 2: - index = wbuf[0] << 8; - index += wbuf[1]; - break; - default: - warn("wlen = %x, aborting.", wlen); - return -EINVAL; - } - - ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, - USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, - usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT); - if (ret < 0) - return ret; - - switch (operation) { - case AU6610_REQ_I2C_READ: - case AU6610_REQ_USB_READ: - /* requested value is always 5th byte in buffer */ - rbuf[0] = usb_buf[4]; - } - - return ret; -} - -static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u8 request; - u8 wo = (rbuf == NULL || rlen == 0); /* write-only */ - - if (wo) { - request = AU6610_REQ_I2C_WRITE; - } else { /* rw */ - request = AU6610_REQ_I2C_READ; - } - - return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen); -} - - -/* I2C */ -static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, msg[i+1].buf, - msg[i+1].len) < 0) - break; - i++; - } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, NULL, 0) < 0) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - - -static u32 au6610_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm au6610_i2c_algo = { - .master_xfer = au6610_i2c_xfer, - .functionality = au6610_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config au6610_zl10353_config = { - .demod_address = 0x0f, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config, - &adap->dev->i2c_adap); - if (adap->fe == NULL) - return -ENODEV; - - return 0; -} - -static struct qt1010_config au6610_qt1010_config = { - .i2c_address = 0x62 -}; - -static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(qt1010_attach, - adap->fe, &adap->dev->i2c_adap, - &au6610_qt1010_config) == NULL ? -ENODEV : 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties au6610_properties; - -static int au6610_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d; - struct usb_host_interface *alt; - int ret; - - if (intf->num_altsetting < AU6610_ALTSETTING_COUNT) - return -ENODEV; - - ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d, - adapter_nr); - if (ret == 0) { - alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING); - - if (alt == NULL) { - deb_info("%s: no alt found!\n", __func__); - return -ENODEV; - } - ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - } - - return ret; -} - -static struct usb_device_id au6610_table [] = { - { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, au6610_table); - -static struct dvb_usb_device_properties au6610_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = 0, - - .num_adapters = 1, - .adapter = { - { - .frontend_attach = au6610_zl10353_frontend_attach, - .tuner_attach = au6610_qt1010_tuner_attach, - - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x82, - .u = { - .isoc = { - .framesperurb = 40, - .framesize = 942, - .interval = 1, - } - } - }, - } - }, - - .i2c_algo = &au6610_i2c_algo, - - .num_device_descs = 1, - .devices = { - { - .name = "Sigmatek DVB-110 DVB-T USB2.0", - .cold_ids = {NULL}, - .warm_ids = {&au6610_table[0], NULL}, - }, - } -}; - -static struct usb_driver au6610_driver = { - .name = "dvb_usb_au6610", - .probe = au6610_probe, - .disconnect = dvb_usb_device_exit, - .id_table = au6610_table, -}; - -/* module stuff */ -static int __init au6610_module_init(void) -{ - int ret; - - ret = usb_register(&au6610_driver); - if (ret) - err("usb_register failed. Error number %d", ret); - - return ret; -} - -static void __exit au6610_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&au6610_driver); -} - -module_init(au6610_module_init); -module_exit(au6610_module_exit); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/au6610.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/au6610.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/au6610.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/au6610.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. - * - * Copyright (C) 2006 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _DVB_USB_AU6610_H_ -#define _DVB_USB_AU6610_H_ - -#define DVB_USB_LOG_PREFIX "au6610" -#include "dvb-usb.h" - -#define deb_info(args...) dprintk(dvb_usb_au6610_debug, 0x01, args) - -#define AU6610_REQ_I2C_WRITE 0x14 -#define AU6610_REQ_I2C_READ 0x13 -#define AU6610_REQ_USB_WRITE 0x16 -#define AU6610_REQ_USB_READ 0x15 - -#define AU6610_USB_TIMEOUT 1000 - -#define AU6610_ALTSETTING_COUNT 6 -#define AU6610_ALTSETTING 5 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/az6027.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/az6027.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/az6027.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/az6027.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1202 +0,0 @@ -/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027) - * receiver. - * - * Copyright (C) 2009 Adams.Xu - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "az6027.h" - -#include "stb0899_drv.h" -#include "stb0899_reg.h" -#include "stb0899_cfg.h" - -#include "stb6100.h" -#include "stb6100_cfg.h" -#include "dvb_ca_en50221.h" - -int dvb_usb_az6027_debug; -module_param_named(debug, dvb_usb_az6027_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct az6027_device_state { - struct dvb_ca_en50221 ca; - struct mutex ca_mutex; - u8 power_state; -}; - -static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = { - - /* 0x0000000b, SYSREG */ - { STB0899_DEV_ID , 0x30 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISFIFO , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x99 }, - { STB0899_DISF22RX , 0xa8 }, - /* SYSREG ? */ - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0xfe }, - { STB0899_IRQSTATUS_2 , 0x03 }, - { STB0899_IRQSTATUS_1 , 0x7c }, - { STB0899_IRQSTATUS_0 , 0xf4 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x58 }, - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x33 }, - { STB0899_IOPVALUE3 , 0x6d }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x60 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x01 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x01 }, - { STB0899_AGC1REF , 0x10 }, - { STB0899_RTC , 0x23 }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x34 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xf7 }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xf1 }, - { STB0899_LDT2 , 0xe3 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfd }, - { STB0899_QDCCOMP , 0xff }, - { STB0899_POWERI , 0x0c }, - { STB0899_POWERQ , 0x0f }, - { STB0899_RCOMP , 0x6c }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x06 }, - { STB0899_AGC2I2 , 0x00 }, - { STB0899_TLIR , 0x30 }, - { STB0899_RTF , 0x7f }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xbc }, - { STB0899_CFRM , 0xea }, - { STB0899_CFRL , 0x31 }, - { STB0899_NIRM , 0x2b }, - { STB0899_NIRL , 0x80 }, - { STB0899_ISYMB , 0x1d }, - { STB0899_QSYMB , 0xa6 }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0x02 }, - { STB0899_EQUAQ1 , 0xff }, - { STB0899_EQUAI2 , 0x04 }, - { STB0899_EQUAQ2 , 0x05 }, - { STB0899_EQUAI3 , 0x02 }, - { STB0899_EQUAQ3 , 0xfd }, - { STB0899_EQUAI4 , 0x03 }, - { STB0899_EQUAQ4 , 0x07 }, - { STB0899_EQUAI5 , 0x08 }, - { STB0899_EQUAQ5 , 0xf5 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0x86 }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x0a }, - { STB0899_ECNT3L , 0xad }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xb0 }, - { STB0899_VTH23 , 0x7a }, - { STB0899_VTH34 , 0x58 }, - { STB0899_VTH56 , 0x38 }, - { STB0899_VTH67 , 0x34 }, - { STB0899_VTH78 , 0x24 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x41 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x00 }, - { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x1b }, - { STB0899_TSLLSTKL , 0xb3 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0x00 }, - { STB0899_PCKLENUL , 0xbc }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xbd }, - { STB0899_TSSTATUS , 0x90 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x95 }, - { STB0899_ERRCTRL3 , 0x8d }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x19 }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0xf0 }, - { STB0899_MATSTRL , 0x02 }, - { STB0899_UPLSTRM , 0x45 }, - { STB0899_UPLSTRL , 0x60 }, - { STB0899_DFLSTRM , 0xe3 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x47 }, - { STB0899_SYNCDSTRM , 0x05 }, - { STB0899_SYNCDSTRL , 0x18 }, - { STB0899_CFGPDELSTATUS1 , 0x19 }, - { STB0899_CFGPDELSTATUS2 , 0x2b }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x01 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - - - -struct stb0899_config az6027_stb0899_config = { - .init_dev = az6027_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = az6027_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .demod_address = 0xd0, /* 0x68, 0xd0 >> 1 */ - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_ON, /* 1 */ - - .lo_clk = 76500000, - .hi_clk = 99000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = stb6100_get_frequency, - .tuner_set_frequency = stb6100_set_frequency, - .tuner_set_bandwidth = stb6100_set_bandwidth, - .tuner_get_bandwidth = stb6100_get_bandwidth, - .tuner_set_rfsiggain = NULL, -}; - -struct stb6100_config az6027_stb6100_config = { - .tuner_address = 0xc0, - .refclock = 27000000, -}; - - -/* check for mutex FIXME */ -int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) -{ - int ret = -1; - if (mutex_lock_interruptible(&d->usb_mutex)) - return -EAGAIN; - - ret = usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev, 0), - req, - USB_TYPE_VENDOR | USB_DIR_IN, - value, - index, - b, - blen, - 2000); - - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EIO; - } else - ret = 0; - - deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index); - debug_dump(b, blen, deb_xfer); - - mutex_unlock(&d->usb_mutex); - return ret; -} - -static int az6027_usb_out_op(struct dvb_usb_device *d, - u8 req, - u16 value, - u16 index, - u8 *b, - int blen) -{ - int ret; - - deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index); - debug_dump(b, blen, deb_xfer); - - if (mutex_lock_interruptible(&d->usb_mutex)) - return -EAGAIN; - - ret = usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev, 0), - req, - USB_TYPE_VENDOR | USB_DIR_OUT, - value, - index, - b, - blen, - 2000); - - if (ret != blen) { - warn("usb out operation failed. (%d)", ret); - mutex_unlock(&d->usb_mutex); - return -EIO; - } else{ - mutex_unlock(&d->usb_mutex); - return 0; - } -} - -static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - deb_info("%s %d", __func__, onoff); - - req = 0xBC; - value = onoff; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - warn("usb out operation failed. (%d)", ret); - - return ret; -} - -/* keys for the enclosed remote control */ -static struct rc_map_table rc_map_az6027_table[] = { - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, -}; - -/* remote control stuff (does not work with my box) */ -static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - return 0; -} - -/* -int az6027_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 v = onoff; - return az6027_usb_out_op(d,0xBC,v,3,NULL,1); -} -*/ - -static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, - int address) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - if (slot != 0) - return -EINVAL; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - - mutex_lock(&state->ca_mutex); - - req = 0xC1; - value = address; - index = 0; - blen = 1; - - ret = az6027_usb_in_op(d, req, value, index, b, blen); - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EINVAL; - } else { - ret = b[0]; - } - - mutex_unlock(&state->ca_mutex); - kfree(b); - return ret; -} - -static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, - int address, - u8 value) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value1; - u16 index; - int blen; - - deb_info("%s %d", __func__, slot); - if (slot != 0) - return -EINVAL; - - mutex_lock(&state->ca_mutex); - req = 0xC2; - value1 = address; - index = value; - blen = 0; - - ret = az6027_usb_out_op(d, req, value1, index, NULL, blen); - if (ret != 0) - warn("usb out operation failed. (%d)", ret); - - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca, - int slot, - u8 address) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - if (slot != 0) - return -EINVAL; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - - mutex_lock(&state->ca_mutex); - - req = 0xC3; - value = address; - index = 0; - blen = 2; - - ret = az6027_usb_in_op(d, req, value, index, b, blen); - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EINVAL; - } else { - if (b[0] == 0) - warn("Read CI IO error"); - - ret = b[1]; - deb_info("read cam data = %x from 0x%x", b[1], value); - } - - mutex_unlock(&state->ca_mutex); - kfree(b); - return ret; -} - -static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca, - int slot, - u8 address, - u8 value) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value1; - u16 index; - int blen; - - if (slot != 0) - return -EINVAL; - - mutex_lock(&state->ca_mutex); - req = 0xC4; - value1 = address; - index = value; - blen = 0; - - ret = az6027_usb_out_op(d, req, value1, index, NULL, blen); - if (ret != 0) { - warn("usb out operation failed. (%d)", ret); - goto failed; - } - -failed: - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - - req = 0xC8; - value = 0; - index = 0; - blen = 1; - - ret = az6027_usb_in_op(d, req, value, index, b, blen); - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EIO; - } else{ - ret = b[0]; - } - kfree(b); - return ret; -} - -static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret, i; - u8 req; - u16 value; - u16 index; - int blen; - - mutex_lock(&state->ca_mutex); - - req = 0xC6; - value = 1; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(d, req, value, index, NULL, blen); - if (ret != 0) { - warn("usb out operation failed. (%d)", ret); - goto failed; - } - - msleep(500); - req = 0xC6; - value = 0; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(d, req, value, index, NULL, blen); - if (ret != 0) { - warn("usb out operation failed. (%d)", ret); - goto failed; - } - - for (i = 0; i < 15; i++) { - msleep(100); - - if (CI_CamReady(ca, slot)) { - deb_info("CAM Ready"); - break; - } - } - msleep(5000); - -failed: - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - return 0; -} - -static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - deb_info("%s", __func__); - mutex_lock(&state->ca_mutex); - req = 0xC7; - value = 1; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(d, req, value, index, NULL, blen); - if (ret != 0) { - warn("usb out operation failed. (%d)", ret); - goto failed; - } - -failed: - mutex_unlock(&state->ca_mutex); - return ret; -} - -static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - int ret; - u8 req; - u16 value; - u16 index; - int blen; - u8 *b; - - b = kmalloc(12, GFP_KERNEL); - if (!b) - return -ENOMEM; - mutex_lock(&state->ca_mutex); - - req = 0xC5; - value = 0; - index = 0; - blen = 1; - - ret = az6027_usb_in_op(d, req, value, index, b, blen); - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EIO; - } else - ret = 0; - - if (!ret && b[0] == 1) { - ret = DVB_CA_EN50221_POLL_CAM_PRESENT | - DVB_CA_EN50221_POLL_CAM_READY; - } - - mutex_unlock(&state->ca_mutex); - kfree(b); - return ret; -} - - -static void az6027_ci_uninit(struct dvb_usb_device *d) -{ - struct az6027_device_state *state; - - deb_info("%s", __func__); - - if (NULL == d) - return; - - state = (struct az6027_device_state *)d->priv; - if (NULL == state) - return; - - if (NULL == state->ca.data) - return; - - dvb_ca_en50221_release(&state->ca); - - memset(&state->ca, 0, sizeof(state->ca)); -} - - -static int az6027_ci_init(struct dvb_usb_adapter *a) -{ - struct dvb_usb_device *d = a->dev; - struct az6027_device_state *state = (struct az6027_device_state *)d->priv; - int ret; - - deb_info("%s", __func__); - - mutex_init(&state->ca_mutex); - - state->ca.owner = THIS_MODULE; - state->ca.read_attribute_mem = az6027_ci_read_attribute_mem; - state->ca.write_attribute_mem = az6027_ci_write_attribute_mem; - state->ca.read_cam_control = az6027_ci_read_cam_control; - state->ca.write_cam_control = az6027_ci_write_cam_control; - state->ca.slot_reset = az6027_ci_slot_reset; - state->ca.slot_shutdown = az6027_ci_slot_shutdown; - state->ca.slot_ts_enable = az6027_ci_slot_ts_enable; - state->ca.poll_slot_status = az6027_ci_poll_slot_status; - state->ca.data = d; - - ret = dvb_ca_en50221_init(&a->dvb_adap, - &state->ca, - 0, /* flags */ - 1);/* n_slots */ - if (ret != 0) { - err("Cannot initialize CI: Error %d.", ret); - memset(&state->ca, 0, sizeof(state->ca)); - return ret; - } - - deb_info("CI initialized."); - - return 0; -} - -/* -static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) -{ - az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6); - return 0; -} -*/ - -static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - - u8 buf; - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - - struct i2c_msg i2c_msg = { - .addr = 0x99, - .flags = 0, - .buf = &buf, - .len = 1 - }; - - /* - * 2 --18v - * 1 --13v - * 0 --off - */ - switch (voltage) { - case SEC_VOLTAGE_13: - buf = 1; - ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); - break; - - case SEC_VOLTAGE_18: - buf = 2; - ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); - break; - - case SEC_VOLTAGE_OFF: - buf = 0; - ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); - break; - - default: - return -EINVAL; - } - return 0; -} - - -static int az6027_frontend_poweron(struct dvb_usb_adapter *adap) -{ - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - req = 0xBC; - value = 1; /* power on */ - index = 3; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - return 0; -} -static int az6027_frontend_reset(struct dvb_usb_adapter *adap) -{ - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - /* reset demodulator */ - req = 0xC0; - value = 1; /* high */ - index = 3; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - req = 0xC0; - value = 0; /* low */ - index = 3; - blen = 0; - msleep_interruptible(200); - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - msleep_interruptible(200); - - req = 0xC0; - value = 1; /*high */ - index = 3; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - msleep_interruptible(200); - return 0; -} - -static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - u8 req; - u16 value; - u16 index; - int blen; - - /* TS passthrough */ - req = 0xC7; - value = onoff; - index = 0; - blen = 0; - - ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); - if (ret != 0) - return -EIO; - - return 0; -} - -static int az6027_frontend_attach(struct dvb_usb_adapter *adap) -{ - - az6027_frontend_poweron(adap); - az6027_frontend_reset(adap); - - deb_info("adap = %p, dev = %p\n", adap, adap->dev); - adap->fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); - - if (adap->fe) { - deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address); - if (stb6100_attach(adap->fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) { - deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address); - adap->fe->ops.set_voltage = az6027_set_voltage; - az6027_ci_init(adap); - } else { - adap->fe = NULL; - } - } else - warn("no front-end attached\n"); - - az6027_frontend_tsbypass(adap, 0); - - return 0; -} - -static struct dvb_usb_device_properties az6027_properties; - -static void az6027_usb_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - az6027_ci_uninit(d); - dvb_usb_device_exit(intf); -} - - -static int az6027_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, - &az6027_properties, - THIS_MODULE, - NULL, - adapter_nr); -} - -/* I2C */ -static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0, j = 0, len = 0; - int ret; - u16 index; - u16 value; - int length; - u8 req; - u8 *data; - - data = kmalloc(256, GFP_KERNEL); - if (!data) - return -ENOMEM; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) { - kfree(data); - return -EAGAIN; - } - - if (num > 2) - warn("more than 2 i2c messages at a time is not handled yet. TODO."); - - for (i = 0; i < num; i++) { - - if (msg[i].addr == 0x99) { - req = 0xBE; - index = 0; - value = msg[i].buf[0] & 0x00ff; - length = 1; - az6027_usb_out_op(d, req, value, index, data, length); - } - - if (msg[i].addr == 0xd0) { - /* write/read request */ - if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { - req = 0xB9; - index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); - value = msg[i].addr + (msg[i].len << 8); - length = msg[i + 1].len + 6; - ret = az6027_usb_in_op(d, req, value, index, data, length); - len = msg[i + 1].len; - for (j = 0; j < len; j++) - msg[i + 1].buf[j] = data[j + 5]; - - i++; - } else { - - /* demod 16bit addr */ - req = 0xBD; - index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); - value = msg[i].addr + (2 << 8); - length = msg[i].len - 2; - len = msg[i].len - 2; - for (j = 0; j < len; j++) - data[j] = msg[i].buf[j + 2]; - az6027_usb_out_op(d, req, value, index, data, length); - } - } - - if (msg[i].addr == 0xc0) { - if (msg[i].flags & I2C_M_RD) { - - req = 0xB9; - index = 0x0; - value = msg[i].addr; - length = msg[i].len + 6; - ret = az6027_usb_in_op(d, req, value, index, data, length); - len = msg[i].len; - for (j = 0; j < len; j++) - msg[i].buf[j] = data[j + 5]; - - } else { - - req = 0xBD; - index = msg[i].buf[0] & 0x00FF; - value = msg[i].addr + (1 << 8); - length = msg[i].len - 1; - len = msg[i].len - 1; - - for (j = 0; j < len; j++) - data[j] = msg[i].buf[j + 1]; - - az6027_usb_out_op(d, req, value, index, data, length); - } - } - } - mutex_unlock(&d->i2c_mutex); - kfree(data); - - return i; -} - - -static u32 az6027_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm az6027_i2c_algo = { - .master_xfer = az6027_i2c_xfer, - .functionality = az6027_i2c_func, -}; - -int az6027_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - u8 *b; - s16 ret; - - b = kmalloc(16, GFP_KERNEL); - if (!b) - return -ENOMEM; - - ret = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - 0xb7, - USB_TYPE_VENDOR | USB_DIR_IN, - 6, - 0, - b, - 6, - USB_CTRL_GET_TIMEOUT); - - *cold = ret <= 0; - kfree(b); - deb_info("cold: %d\n", *cold); - return 0; -} - - -static struct usb_device_id az6027_usb_table[] = { - { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V1) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V2) }, - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) }, - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, - { }, -}; - -MODULE_DEVICE_TABLE(usb, az6027_usb_table); - -static struct dvb_usb_device_properties az6027_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-az6027-03.fw", - .no_reconnect = 1, - - .size_of_priv = sizeof(struct az6027_device_state), - .identify_state = az6027_identify_state, - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = az6027_streaming_ctrl, - .frontend_attach = az6027_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, -/* - .power_ctrl = az6027_power_ctrl, - .read_mac_address = az6027_read_mac_addr, - */ - .rc.legacy = { - .rc_map_table = rc_map_az6027_table, - .rc_map_size = ARRAY_SIZE(rc_map_az6027_table), - .rc_interval = 400, - .rc_query = az6027_rc_query, - }, - - .i2c_algo = &az6027_i2c_algo, - - .num_device_descs = 6, - .devices = { - { - .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", - .cold_ids = { &az6027_usb_table[0], NULL }, - .warm_ids = { NULL }, - }, { - .name = "TERRATEC S7", - .cold_ids = { &az6027_usb_table[1], NULL }, - .warm_ids = { NULL }, - }, { - .name = "TERRATEC S7 MKII", - .cold_ids = { &az6027_usb_table[2], NULL }, - .warm_ids = { NULL }, - }, { - .name = "Technisat SkyStar USB 2 HD CI", - .cold_ids = { &az6027_usb_table[3], NULL }, - .warm_ids = { NULL }, - }, { - .name = "Technisat SkyStar USB 2 HD CI", - .cold_ids = { &az6027_usb_table[4], NULL }, - .warm_ids = { NULL }, - }, { - .name = "Elgato EyeTV Sat", - .cold_ids = { &az6027_usb_table[5], NULL }, - .warm_ids = { NULL }, - }, - { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver az6027_usb_driver = { - .name = "dvb_usb_az6027", - .probe = az6027_usb_probe, - .disconnect = az6027_usb_disconnect, - .id_table = az6027_usb_table, -}; - -/* module stuff */ -static int __init az6027_usb_module_init(void) -{ - int result; - - result = usb_register(&az6027_usb_driver); - if (result) { - err("usb_register failed. (%d)", result); - return result; - } - - return 0; -} - -static void __exit az6027_usb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&az6027_usb_driver); -} - -module_init(az6027_usb_module_init); -module_exit(az6027_usb_module_exit); - -MODULE_AUTHOR("Adams Xu "); -MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/az6027.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/az6027.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/az6027.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/az6027.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -#ifndef _DVB_USB_VP6027_H_ -#define _DVB_USB_VP6027_H_ - -#define DVB_USB_LOG_PREFIX "az6027" -#include "dvb-usb.h" - - -extern int dvb_usb_az6027_debug; -#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args) -#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args) -#define deb_rc(args...) dprintk(dvb_usb_az6027_debug, 0x04, args) -#define deb_fe(args...) dprintk(dvb_usb_az6027_debug, 0x08, args) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ce6230.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ce6230.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ce6230.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ce6230.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,334 +0,0 @@ -/* - * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "ce6230.h" -#include "zl10353.h" -#include "mxl5005s.h" - -/* debug */ -static int dvb_usb_ce6230_debug; -module_param_named(debug, dvb_usb_ce6230_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static struct zl10353_config ce6230_zl10353_config; - -static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req) -{ - int ret; - unsigned int pipe; - u8 request; - u8 requesttype; - u16 value; - u16 index; - u8 buf[req->data_len]; - - request = req->cmd; - value = req->value; - index = req->index; - - switch (req->cmd) { - case I2C_READ: - case DEMOD_READ: - case REG_READ: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - break; - case I2C_WRITE: - case DEMOD_WRITE: - case REG_WRITE: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - break; - default: - err("unknown command:%02x", req->cmd); - ret = -EPERM; - goto error; - } - - if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { - /* write */ - memcpy(buf, req->data, req->data_len); - pipe = usb_sndctrlpipe(udev, 0); - } else { - /* read */ - pipe = usb_rcvctrlpipe(udev, 0); - } - - msleep(1); /* avoid I2C errors */ - - ret = usb_control_msg(udev, pipe, request, requesttype, value, index, - buf, sizeof(buf), CE6230_USB_TIMEOUT); - - ce6230_debug_dump(request, requesttype, value, index, buf, - req->data_len, deb_xfer); - - if (ret < 0) - deb_info("%s: usb_control_msg failed:%d\n", __func__, ret); - else - ret = 0; - - /* read request, copy returned data to return buf */ - if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) - memcpy(req->data, buf, req->data_len); - -error: - return ret; -} - -static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) -{ - return ce6230_rw_udev(d->udev, req); -} - -/* I2C */ -static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0; - struct req_t req; - int ret = 0; - memset(&req, 0, sizeof(req)); - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].addr == - ce6230_zl10353_config.demod_address) { - req.cmd = DEMOD_READ; - req.value = msg[i].addr >> 1; - req.index = msg[i].buf[0]; - req.data_len = msg[i+1].len; - req.data = &msg[i+1].buf[0]; - ret = ce6230_ctrl_msg(d, &req); - } else { - err("i2c read not implemented"); - ret = -EPERM; - } - i += 2; - } else { - if (msg[i].addr == - ce6230_zl10353_config.demod_address) { - req.cmd = DEMOD_WRITE; - req.value = msg[i].addr >> 1; - req.index = msg[i].buf[0]; - req.data_len = msg[i].len-1; - req.data = &msg[i].buf[1]; - ret = ce6230_ctrl_msg(d, &req); - } else { - req.cmd = I2C_WRITE; - req.value = 0x2000 + (msg[i].addr >> 1); - req.index = 0x0000; - req.data_len = msg[i].len; - req.data = &msg[i].buf[0]; - ret = ce6230_ctrl_msg(d, &req); - } - i += 1; - } - if (ret) - break; - } - - mutex_unlock(&d->i2c_mutex); - return ret ? ret : i; -} - -static u32 ce6230_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm ce6230_i2c_algo = { - .master_xfer = ce6230_i2c_xfer, - .functionality = ce6230_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config ce6230_zl10353_config = { - .demod_address = 0x1e, - .adc_clock = 450000, - .if2 = 45700, - .no_tuner = 1, - .parallel_ts = 1, - .clock_ctl_1 = 0x34, - .pll_0 = 0x0e, -}; - -static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) -{ - deb_info("%s:\n", __func__); - adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config, - &adap->dev->i2c_adap); - if (adap->fe == NULL) - return -ENODEV; - return 0; -} - -static struct mxl5005s_config ce6230_mxl5003s_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_DEFAULT, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) -{ - int ret; - deb_info("%s:\n", __func__); - ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap, - &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; - return ret; -} - -static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - deb_info("%s: onoff:%d\n", __func__, onoff); - - /* InterfaceNumber 1 / AlternateSetting 0 idle - InterfaceNumber 1 / AlternateSetting 1 streaming */ - ret = usb_set_interface(d->udev, 1, onoff); - if (ret) - err("usb_set_interface failed with error:%d", ret); - - return ret; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties ce6230_properties; - -static int ce6230_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret = 0; - struct dvb_usb_device *d = NULL; - - deb_info("%s: interface:%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { - ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE, - &d, adapter_nr); - if (ret) - err("init failed with error:%d\n", ret); - } - - return ret; -} - -static struct usb_device_id ce6230_table[] = { - { USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, ce6230_table); - -static struct dvb_usb_device_properties ce6230_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .no_reconnect = 1, - - .size_of_priv = 0, - - .num_adapters = 1, - .adapter = { - { - .frontend_attach = ce6230_zl10353_frontend_attach, - .tuner_attach = ce6230_mxl5003s_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = (16*512), - } - } - }, - } - }, - - .power_ctrl = ce6230_power_ctrl, - - .i2c_algo = &ce6230_i2c_algo, - - .num_device_descs = 2, - .devices = { - { - .name = "Intel CE9500 reference design", - .cold_ids = {NULL}, - .warm_ids = {&ce6230_table[0], NULL}, - }, - { - .name = "AVerMedia A310 USB 2.0 DVB-T tuner", - .cold_ids = {NULL}, - .warm_ids = {&ce6230_table[1], NULL}, - }, - } -}; - -static struct usb_driver ce6230_driver = { - .name = "dvb_usb_ce6230", - .probe = ce6230_probe, - .disconnect = dvb_usb_device_exit, - .id_table = ce6230_table, -}; - -/* module stuff */ -static int __init ce6230_module_init(void) -{ - int ret; - deb_info("%s:\n", __func__); - ret = usb_register(&ce6230_driver); - if (ret) - err("usb_register failed with error:%d", ret); - - return ret; -} - -static void __exit ce6230_module_exit(void) -{ - deb_info("%s:\n", __func__); - /* deregister this driver from the USB subsystem */ - usb_deregister(&ce6230_driver); -} - -module_init(ce6230_module_init); -module_exit(ce6230_module_exit); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ce6230.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ce6230.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ce6230.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ce6230.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* - * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _DVB_USB_CE6230_H_ -#define _DVB_USB_CE6230_H_ - -#define DVB_USB_LOG_PREFIX "ce6230" -#include "dvb-usb.h" - -#define deb_info(args...) dprintk(dvb_usb_ce6230_debug, 0x01, args) -#define deb_rc(args...) dprintk(dvb_usb_ce6230_debug, 0x02, args) -#define deb_xfer(args...) dprintk(dvb_usb_ce6230_debug, 0x04, args) -#define deb_reg(args...) dprintk(dvb_usb_ce6230_debug, 0x08, args) -#define deb_i2c(args...) dprintk(dvb_usb_ce6230_debug, 0x10, args) -#define deb_fw(args...) dprintk(dvb_usb_ce6230_debug, 0x20, args) - -#define ce6230_debug_dump(r, t, v, i, b, l, func) { \ - int loop_; \ - func("%02x %02x %02x %02x %02x %02x %02x %02x", \ - t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \ - if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ - func(" >>> "); \ - else \ - func(" <<< "); \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ -} - -#define CE6230_USB_TIMEOUT 1000 - -struct req_t { - u8 cmd; /* [1] */ - u16 value; /* [2|3] */ - u16 index; /* [4|5] */ - u16 data_len; /* [6|7] */ - u8 *data; -}; - -enum ce6230_cmd { - CONFIG_READ = 0xd0, /* rd 0 (unclear) */ - UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */ - I2C_READ = 0xd9, /* rd 9 (unclear) */ - I2C_WRITE = 0xca, /* wr a */ - DEMOD_READ = 0xdb, /* rd b */ - DEMOD_WRITE = 0xcc, /* wr c */ - REG_READ = 0xde, /* rd e */ - REG_WRITE = 0xcf, /* wr f */ -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,269 +0,0 @@ -/* - * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. - * - * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) - * - * Based on the dvb-usb-framework code and the - * original Terratec Cinergy T2 driver by: - * - * Copyright (C) 2004 Daniel Mack and - * Holger Waechtler - * - * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "cinergyT2.h" - - -/* debug */ -int dvb_usb_cinergyt2_debug; - -module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " - "(or-able))."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct cinergyt2_state { - u8 rc_counter; -}; - -/* We are missing a release hook with usb_device data */ -static struct dvb_usb_device *cinergyt2_usb_device; - -static struct dvb_usb_device_properties cinergyt2_properties; - -static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable) -{ - char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; - char result[64]; - return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result, - sizeof(result), 0); -} - -static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable) -{ - char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 }; - char state[3]; - return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0); -} - -static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) -{ - char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION }; - char state[3]; - int ret; - - adap->fe = cinergyt2_fe_attach(adap->dev); - - ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, - sizeof(state), 0); - if (ret < 0) { - deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep " - "state info\n"); - } - - /* Copy this pointer as we are gonna need it in the release phase */ - cinergyt2_usb_device = adap->dev; - - return 0; -} - -static struct rc_map_table rc_map_cinergyt2_table[] = { - { 0x0401, KEY_POWER }, - { 0x0402, KEY_1 }, - { 0x0403, KEY_2 }, - { 0x0404, KEY_3 }, - { 0x0405, KEY_4 }, - { 0x0406, KEY_5 }, - { 0x0407, KEY_6 }, - { 0x0408, KEY_7 }, - { 0x0409, KEY_8 }, - { 0x040a, KEY_9 }, - { 0x040c, KEY_0 }, - { 0x040b, KEY_VIDEO }, - { 0x040d, KEY_REFRESH }, - { 0x040e, KEY_SELECT }, - { 0x040f, KEY_EPG }, - { 0x0410, KEY_UP }, - { 0x0414, KEY_DOWN }, - { 0x0411, KEY_LEFT }, - { 0x0413, KEY_RIGHT }, - { 0x0412, KEY_OK }, - { 0x0415, KEY_TEXT }, - { 0x0416, KEY_INFO }, - { 0x0417, KEY_RED }, - { 0x0418, KEY_GREEN }, - { 0x0419, KEY_YELLOW }, - { 0x041a, KEY_BLUE }, - { 0x041c, KEY_VOLUMEUP }, - { 0x041e, KEY_VOLUMEDOWN }, - { 0x041d, KEY_MUTE }, - { 0x041b, KEY_CHANNELUP }, - { 0x041f, KEY_CHANNELDOWN }, - { 0x0440, KEY_PAUSE }, - { 0x044c, KEY_PLAY }, - { 0x0458, KEY_RECORD }, - { 0x0454, KEY_PREVIOUS }, - { 0x0448, KEY_STOP }, - { 0x045c, KEY_NEXT } -}; - -/* Number of keypresses to ignore before detect repeating */ -#define RC_REPEAT_DELAY 3 - -static int repeatable_keys[] = { - KEY_UP, - KEY_DOWN, - KEY_LEFT, - KEY_RIGHT, - KEY_VOLUMEUP, - KEY_VOLUMEDOWN, - KEY_CHANNELUP, - KEY_CHANNELDOWN -}; - -static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - struct cinergyt2_state *st = d->priv; - u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS; - int i; - - *state = REMOTE_NO_KEY_PRESSED; - - dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0); - if (key[4] == 0xff) { - /* key repeat */ - st->rc_counter++; - if (st->rc_counter > RC_REPEAT_DELAY) { - for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { - if (d->last_event == repeatable_keys[i]) { - *state = REMOTE_KEY_REPEAT; - *event = d->last_event; - deb_rc("repeat key, event %x\n", - *event); - return 0; - } - } - deb_rc("repeated key (non repeatable)\n"); - } - return 0; - } - - /* hack to pass checksum on the custom field */ - key[2] = ~key[1]; - dvb_usb_nec_rc_key_to_event(d, key, event, state); - if (key[0] != 0) { - if (*event != d->last_event) - st->rc_counter = 0; - - deb_rc("key: %x %x %x %x %x\n", - key[0], key[1], key[2], key[3], key[4]); - } - return 0; -} - -static int cinergyt2_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &cinergyt2_properties, - THIS_MODULE, NULL, adapter_nr); -} - - -static struct usb_device_id cinergyt2_usb_table[] = { - { USB_DEVICE(USB_VID_TERRATEC, 0x0038) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table); - -static struct dvb_usb_device_properties cinergyt2_properties = { - .size_of_priv = sizeof(struct cinergyt2_state), - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cinergyt2_streaming_ctrl, - .frontend_attach = cinergyt2_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - } - }, - - .power_ctrl = cinergyt2_power_ctrl, - - .rc.legacy = { - .rc_interval = 50, - .rc_map_table = rc_map_cinergyt2_table, - .rc_map_size = ARRAY_SIZE(rc_map_cinergyt2_table), - .rc_query = cinergyt2_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 1, - - .num_device_descs = 1, - .devices = { - { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver", - .cold_ids = {NULL}, - .warm_ids = { &cinergyt2_usb_table[0], NULL }, - }, - { NULL }, - } -}; - - -static struct usb_driver cinergyt2_driver = { - .name = "cinergyT2", - .probe = cinergyt2_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = cinergyt2_usb_table -}; - -static int __init cinergyt2_usb_init(void) -{ - int err; - - err = usb_register(&cinergyt2_driver); - if (err) { - err("usb_register() failed! (err %i)\n", err); - return err; - } - return 0; -} - -static void __exit cinergyt2_usb_exit(void) -{ - usb_deregister(&cinergyt2_driver); -} - -module_init(cinergyt2_usb_init); -module_exit(cinergyt2_usb_exit); - -MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Tomi Orava"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,352 +0,0 @@ -/* - * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. - * - * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) - * - * Based on the dvb-usb-framework code and the - * original Terratec Cinergy T2 driver by: - * - * Copyright (C) 2004 Daniel Mack and - * Holger Waechtler - * - * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "cinergyT2.h" - - -/** - * convert linux-dvb frontend parameter set into TPS. - * See ETSI ETS-300744, section 4.6.2, table 9 for details. - * - * This function is probably reusable and may better get placed in a support - * library. - * - * We replace errornous fields by default TPS fields (the ones with value 0). - */ - -static uint16_t compute_tps(struct dvb_frontend_parameters *p) -{ - struct dvb_ofdm_parameters *op = &p->u.ofdm; - uint16_t tps = 0; - - switch (op->code_rate_HP) { - case FEC_2_3: - tps |= (1 << 7); - break; - case FEC_3_4: - tps |= (2 << 7); - break; - case FEC_5_6: - tps |= (3 << 7); - break; - case FEC_7_8: - tps |= (4 << 7); - break; - case FEC_1_2: - case FEC_AUTO: - default: - /* tps |= (0 << 7) */; - } - - switch (op->code_rate_LP) { - case FEC_2_3: - tps |= (1 << 4); - break; - case FEC_3_4: - tps |= (2 << 4); - break; - case FEC_5_6: - tps |= (3 << 4); - break; - case FEC_7_8: - tps |= (4 << 4); - break; - case FEC_1_2: - case FEC_AUTO: - default: - /* tps |= (0 << 4) */; - } - - switch (op->constellation) { - case QAM_16: - tps |= (1 << 13); - break; - case QAM_64: - tps |= (2 << 13); - break; - case QPSK: - default: - /* tps |= (0 << 13) */; - } - - switch (op->transmission_mode) { - case TRANSMISSION_MODE_8K: - tps |= (1 << 0); - break; - case TRANSMISSION_MODE_2K: - default: - /* tps |= (0 << 0) */; - } - - switch (op->guard_interval) { - case GUARD_INTERVAL_1_16: - tps |= (1 << 2); - break; - case GUARD_INTERVAL_1_8: - tps |= (2 << 2); - break; - case GUARD_INTERVAL_1_4: - tps |= (3 << 2); - break; - case GUARD_INTERVAL_1_32: - default: - /* tps |= (0 << 2) */; - } - - switch (op->hierarchy_information) { - case HIERARCHY_1: - tps |= (1 << 10); - break; - case HIERARCHY_2: - tps |= (2 << 10); - break; - case HIERARCHY_4: - tps |= (3 << 10); - break; - case HIERARCHY_NONE: - default: - /* tps |= (0 << 10) */; - } - - return tps; -} - -struct cinergyt2_fe_state { - struct dvb_frontend fe; - struct dvb_usb_device *d; -}; - -static int cinergyt2_fe_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg result; - u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result, - sizeof(result), 0); - if (ret < 0) - return ret; - - *status = 0; - - if (0xffff - le16_to_cpu(result.gain) > 30) - *status |= FE_HAS_SIGNAL; - if (result.lock_bits & (1 << 6)) - *status |= FE_HAS_LOCK; - if (result.lock_bits & (1 << 5)) - *status |= FE_HAS_SYNC; - if (result.lock_bits & (1 << 4)) - *status |= FE_HAS_CARRIER; - if (result.lock_bits & (1 << 1)) - *status |= FE_HAS_VITERBI; - - if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != - (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) - *status &= ~FE_HAS_LOCK; - - return 0; -} - -static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, - sizeof(status), 0); - if (ret < 0) - return ret; - - *ber = le32_to_cpu(status.viterbi_error_rate); - return 0; -} - -static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status, - sizeof(status), 0); - if (ret < 0) { - err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n", - ret); - return ret; - } - *unc = le32_to_cpu(status.uncorrected_block_count); - return 0; -} - -static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, - sizeof(status), 0); - if (ret < 0) { - err("cinergyt2_fe_read_signal_strength() Failed!" - " (Error=%d)\n", ret); - return ret; - } - *strength = (0xffff - le16_to_cpu(status.gain)); - return 0; -} - -static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_get_status_msg status; - char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - int ret; - - ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, - sizeof(status), 0); - if (ret < 0) { - err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret); - return ret; - } - *snr = (status.snr << 8) | status.snr; - return 0; -} - -static int cinergyt2_fe_init(struct dvb_frontend *fe) -{ - return 0; -} - -static int cinergyt2_fe_sleep(struct dvb_frontend *fe) -{ - deb_info("cinergyt2_fe_sleep() Called\n"); - return 0; -} - -static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 800; - return 0; -} - -static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - struct dvbt_set_parameters_msg param; - char result[2]; - int err; - - param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; - param.tps = cpu_to_le16(compute_tps(fep)); - param.freq = cpu_to_le32(fep->frequency / 1000); - param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; - param.flags = 0; - - err = dvb_usb_generic_rw(state->d, - (char *)¶m, sizeof(param), - result, sizeof(result), 0); - if (err < 0) - err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); - - return (err < 0) ? err : 0; -} - -static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - return 0; -} - -static void cinergyt2_fe_release(struct dvb_frontend *fe) -{ - struct cinergyt2_fe_state *state = fe->demodulator_priv; - if (state != NULL) - kfree(state); -} - -static struct dvb_frontend_ops cinergyt2_fe_ops; - -struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) -{ - struct cinergyt2_fe_state *s = kzalloc(sizeof( - struct cinergyt2_fe_state), GFP_KERNEL); - if (s == NULL) - return NULL; - - s->d = d; - memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); - s->fe.demodulator_priv = s; - return &s->fe; -} - - -static struct dvb_frontend_ops cinergyt2_fe_ops = { - .info = { - .name = DRIVER_NAME, - .type = FE_OFDM, - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 - | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 - | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 - | FE_CAN_FEC_AUTO | FE_CAN_QPSK - | FE_CAN_QAM_16 | FE_CAN_QAM_64 - | FE_CAN_QAM_AUTO - | FE_CAN_TRANSMISSION_MODE_AUTO - | FE_CAN_GUARD_INTERVAL_AUTO - | FE_CAN_HIERARCHY_AUTO - | FE_CAN_RECOVER - | FE_CAN_MUTE_TS - }, - - .release = cinergyt2_fe_release, - - .init = cinergyt2_fe_init, - .sleep = cinergyt2_fe_sleep, - - .set_frontend = cinergyt2_fe_set_frontend, - .get_frontend = cinergyt2_fe_get_frontend, - .get_tune_settings = cinergyt2_fe_get_tune_settings, - - .read_status = cinergyt2_fe_read_status, - .read_ber = cinergyt2_fe_read_ber, - .read_signal_strength = cinergyt2_fe_read_signal_strength, - .read_snr = cinergyt2_fe_read_snr, - .read_ucblocks = cinergyt2_fe_read_unc_blocks, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cinergyT2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* - * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. - * - * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) - * - * Based on the dvb-usb-framework code and the - * original Terratec Cinergy T2 driver by: - * - * Copyright (C) 2004 Daniel Mack and - * Holger Waechtler - * - * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _DVB_USB_CINERGYT2_H_ -#define _DVB_USB_CINERGYT2_H_ - -#include - -#define DVB_USB_LOG_PREFIX "cinergyT2" -#include "dvb-usb.h" - -#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" - -extern int dvb_usb_cinergyt2_debug; - -#define deb_info(args...) dprintk(dvb_usb_cinergyt2_debug, 0x001, args) -#define deb_xfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x002, args) -#define deb_pll(args...) dprintk(dvb_usb_cinergyt2_debug, 0x004, args) -#define deb_ts(args...) dprintk(dvb_usb_cinergyt2_debug, 0x008, args) -#define deb_err(args...) dprintk(dvb_usb_cinergyt2_debug, 0x010, args) -#define deb_rc(args...) dprintk(dvb_usb_cinergyt2_debug, 0x020, args) -#define deb_fw(args...) dprintk(dvb_usb_cinergyt2_debug, 0x040, args) -#define deb_mem(args...) dprintk(dvb_usb_cinergyt2_debug, 0x080, args) -#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x100, args) - - - -enum cinergyt2_ep1_cmd { - CINERGYT2_EP1_PID_TABLE_RESET = 0x01, - CINERGYT2_EP1_PID_SETUP = 0x02, - CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03, - CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04, - CINERGYT2_EP1_GET_TUNER_STATUS = 0x05, - CINERGYT2_EP1_START_SCAN = 0x06, - CINERGYT2_EP1_CONTINUE_SCAN = 0x07, - CINERGYT2_EP1_GET_RC_EVENTS = 0x08, - CINERGYT2_EP1_SLEEP_MODE = 0x09, - CINERGYT2_EP1_GET_FIRMWARE_VERSION = 0x0A -}; - - -struct dvbt_get_status_msg { - uint32_t freq; - uint8_t bandwidth; - uint16_t tps; - uint8_t flags; - __le16 gain; - uint8_t snr; - __le32 viterbi_error_rate; - uint32_t rs_error_rate; - __le32 uncorrected_block_count; - uint8_t lock_bits; - uint8_t prev_lock_bits; -} __attribute__((packed)); - - -struct dvbt_set_parameters_msg { - uint8_t cmd; - __le32 freq; - uint8_t bandwidth; - __le16 tps; - uint8_t flags; -} __attribute__((packed)); - - -extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d); - -#endif /* _DVB_USB_CINERGYT2_H_ */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cxusb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cxusb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cxusb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cxusb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2016 +0,0 @@ -/* DVB USB compliant linux driver for Conexant USB reference design. - * - * The Conexant reference design I saw on their website was only for analogue - * capturing (using the cx25842). The box I took to write this driver (reverse - * engineered) is the one labeled Medion MD95700. In addition to the cx25842 - * for analogue capturing it also has a cx22702 DVB-T demodulator on the main - * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard. - * - * Maybe it is a little bit premature to call this driver cxusb, but I assume - * the USB protocol is identical or at least inherited from the reference - * design, so it can be reused for the "analogue-only" device (if it will - * appear at all). - * - * TODO: Use the cx25840-driver for the analogue part - * - * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) - * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) - * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include -#include -#include - -#include "cxusb.h" - -#include "cx22702.h" -#include "lgdt330x.h" -#include "mt352.h" -#include "mt352_priv.h" -#include "zl10353.h" -#include "tuner-xc2028.h" -#include "tuner-simple.h" -#include "mxl5005s.h" -#include "max2165.h" -#include "dib7000p.h" -#include "dib0070.h" -#include "lgs8gxx.h" -#include "atbm8830.h" - -/* debug */ -static int dvb_usb_cxusb_debug; -module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args) -#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args) - -static int cxusb_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - u8 sndbuf[1+wlen]; - memset(sndbuf, 0, 1+wlen); - - sndbuf[0] = cmd; - memcpy(&sndbuf[1], wbuf, wlen); - if (wo) - return dvb_usb_generic_write(d, sndbuf, 1+wlen); - else - return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); -} - -/* GPIO */ -static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) -{ - struct cxusb_state *st = d->priv; - u8 o[2], i; - - if (st->gpio_write_state[GPIO_TUNER] == onoff) - return; - - o[0] = GPIO_TUNER; - o[1] = onoff; - cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); - - if (i != 0x01) - deb_info("gpio_write failed.\n"); - - st->gpio_write_state[GPIO_TUNER] = onoff; -} - -static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, - u8 newval) -{ - u8 o[2], gpio_state; - int rc; - - o[0] = 0xff & ~changemask; /* mask of bits to keep */ - o[1] = newval & changemask; /* new values for bits */ - - rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1); - if (rc < 0 || (gpio_state & changemask) != (newval & changemask)) - deb_info("bluebird_gpio_write failed.\n"); - - return rc < 0 ? rc : gpio_state; -} - -static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low) -{ - cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin); - msleep(5); - cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0); -} - -static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) -{ - cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); -} - -static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, - u8 addr, int onoff) -{ - u8 o[2] = {addr, onoff}; - u8 i; - int rc; - - rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); - - if (rc < 0) - return rc; - if (i == 0x01) - return 0; - else { - deb_info("gpio_write failed.\n"); - return -EIO; - } -} - -/* I2C */ -static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - - if (d->udev->descriptor.idVendor == USB_VID_MEDION) - switch (msg[i].addr) { - case 0x63: - cxusb_gpio_tuner(d, 0); - break; - default: - cxusb_gpio_tuner(d, 1); - break; - } - - if (msg[i].flags & I2C_M_RD) { - /* read only */ - u8 obuf[3], ibuf[1+msg[i].len]; - obuf[0] = 0; - obuf[1] = msg[i].len; - obuf[2] = msg[i].addr; - if (cxusb_ctrl_msg(d, CMD_I2C_READ, - obuf, 3, - ibuf, 1+msg[i].len) < 0) { - warn("i2c read failed"); - break; - } - memcpy(msg[i].buf, &ibuf[1], msg[i].len); - } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && - msg[i].addr == msg[i+1].addr) { - /* write to then read from same address */ - u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; - obuf[0] = msg[i].len; - obuf[1] = msg[i+1].len; - obuf[2] = msg[i].addr; - memcpy(&obuf[3], msg[i].buf, msg[i].len); - - if (cxusb_ctrl_msg(d, CMD_I2C_READ, - obuf, 3+msg[i].len, - ibuf, 1+msg[i+1].len) < 0) - break; - - if (ibuf[0] != 0x08) - deb_i2c("i2c read may have failed\n"); - - memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); - - i++; - } else { - /* write only */ - u8 obuf[2+msg[i].len], ibuf; - obuf[0] = msg[i].addr; - obuf[1] = msg[i].len; - memcpy(&obuf[2], msg[i].buf, msg[i].len); - - if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf, - 2+msg[i].len, &ibuf,1) < 0) - break; - if (ibuf != 0x08) - deb_i2c("i2c write may have failed\n"); - } - } - - mutex_unlock(&d->i2c_mutex); - return i == num ? num : -EREMOTEIO; -} - -static u32 cxusb_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm cxusb_i2c_algo = { - .master_xfer = cxusb_i2c_xfer, - .functionality = cxusb_i2c_func, -}; - -static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b = 0; - if (onoff) - return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); - else - return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); -} - -static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - if (!onoff) - return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0); - if (d->state == DVB_USB_STATE_INIT && - usb_set_interface(d->udev, 0, 0) < 0) - err("set interface failed"); - do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && - !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && - !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); - if (!ret) { - /* FIXME: We don't know why, but we need to configure the - * lgdt3303 with the register settings below on resume */ - int i; - u8 buf, bufs[] = { - 0x0e, 0x2, 0x00, 0x7f, - 0x0e, 0x2, 0x02, 0xfe, - 0x0e, 0x2, 0x02, 0x01, - 0x0e, 0x2, 0x00, 0x03, - 0x0e, 0x2, 0x0d, 0x40, - 0x0e, 0x2, 0x0e, 0x87, - 0x0e, 0x2, 0x0f, 0x8e, - 0x0e, 0x2, 0x10, 0x01, - 0x0e, 0x2, 0x14, 0xd7, - 0x0e, 0x2, 0x47, 0x88, - }; - msleep(20); - for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) { - ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE, - bufs+i, 4, &buf, 1); - if (ret) - break; - if (buf != 0x8) - return -EREMOTEIO; - } - } - return ret; -} - -static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b = 0; - if (onoff) - return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); - else - return 0; -} - -static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int rc = 0; - - rc = cxusb_power_ctrl(d, onoff); - if (!onoff) - cxusb_nano2_led(d, 0); - - return rc; -} - -static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - u8 b; - ret = cxusb_power_ctrl(d, onoff); - if (!onoff) - return ret; - - msleep(128); - cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1); - msleep(100); - return ret; -} - -static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - u8 buf[2] = { 0x03, 0x00 }; - if (onoff) - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0); - else - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); - - return 0; -} - -static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - if (onoff) - cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0); - else - cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF, - NULL, 0, NULL, 0); - return 0; -} - -static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) -{ - int ep = d->props.generic_bulk_ctrl_endpoint; - const int timeout = 100; - const int junk_len = 32; - u8 *junk; - int rd_count; - - /* Discard remaining data in video pipe */ - junk = kmalloc(junk_len, GFP_KERNEL); - if (!junk) - return; - while (1) { - if (usb_bulk_msg(d->udev, - usb_rcvbulkpipe(d->udev, ep), - junk, junk_len, &rd_count, timeout) < 0) - break; - if (!rd_count) - break; - } - kfree(junk); -} - -static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) -{ - struct usb_data_stream_properties *p = &d->props.adapter[0].stream; - const int timeout = 100; - const int junk_len = p->u.bulk.buffersize; - u8 *junk; - int rd_count; - - /* Discard remaining data in video pipe */ - junk = kmalloc(junk_len, GFP_KERNEL); - if (!junk) - return; - while (1) { - if (usb_bulk_msg(d->udev, - usb_rcvbulkpipe(d->udev, p->endpoint), - junk, junk_len, &rd_count, timeout) < 0) - break; - if (!rd_count) - break; - } - kfree(junk); -} - -static int cxusb_d680_dmb_streaming_ctrl( - struct dvb_usb_adapter *adap, int onoff) -{ - if (onoff) { - u8 buf[2] = { 0x03, 0x00 }; - cxusb_d680_dmb_drain_video(adap->dev); - return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, - buf, sizeof(buf), NULL, 0); - } else { - int ret = cxusb_ctrl_msg(adap->dev, - CMD_STREAMING_OFF, NULL, 0, NULL, 0); - return ret; - } -} - -static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - u8 ircode[4]; - int i; - - cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); - - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - if (rc5_custom(&keymap[i]) == ircode[2] && - rc5_data(&keymap[i]) == ircode[3]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - - return 0; - } - } - - return 0; -} - -static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, - int *state) -{ - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - u8 ircode[4]; - int i; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; - - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - - if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) - return 0; - - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - if (rc5_custom(&keymap[i]) == ircode[1] && - rc5_data(&keymap[i]) == ircode[2]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - - return 0; - } - } - - return 0; -} - -static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event, - int *state) -{ - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - u8 ircode[2]; - int i; - - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - - if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0) - return 0; - - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - if (rc5_custom(&keymap[i]) == ircode[0] && - rc5_data(&keymap[i]) == ircode[1]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - - return 0; - } - } - - return 0; -} - -static struct rc_map_table rc_map_dvico_mce_table[] = { - { 0xfe02, KEY_TV }, - { 0xfe0e, KEY_MP3 }, - { 0xfe1a, KEY_DVD }, - { 0xfe1e, KEY_FAVORITES }, - { 0xfe16, KEY_SETUP }, - { 0xfe46, KEY_POWER2 }, - { 0xfe0a, KEY_EPG }, - { 0xfe49, KEY_BACK }, - { 0xfe4d, KEY_MENU }, - { 0xfe51, KEY_UP }, - { 0xfe5b, KEY_LEFT }, - { 0xfe5f, KEY_RIGHT }, - { 0xfe53, KEY_DOWN }, - { 0xfe5e, KEY_OK }, - { 0xfe59, KEY_INFO }, - { 0xfe55, KEY_TAB }, - { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */ - { 0xfe12, KEY_NEXTSONG }, /* Skip */ - { 0xfe42, KEY_ENTER }, /* Windows/Start */ - { 0xfe15, KEY_VOLUMEUP }, - { 0xfe05, KEY_VOLUMEDOWN }, - { 0xfe11, KEY_CHANNELUP }, - { 0xfe09, KEY_CHANNELDOWN }, - { 0xfe52, KEY_CAMERA }, - { 0xfe5a, KEY_TUNER }, /* Live */ - { 0xfe19, KEY_OPEN }, - { 0xfe0b, KEY_1 }, - { 0xfe17, KEY_2 }, - { 0xfe1b, KEY_3 }, - { 0xfe07, KEY_4 }, - { 0xfe50, KEY_5 }, - { 0xfe54, KEY_6 }, - { 0xfe48, KEY_7 }, - { 0xfe4c, KEY_8 }, - { 0xfe58, KEY_9 }, - { 0xfe13, KEY_ANGLE }, /* Aspect */ - { 0xfe03, KEY_0 }, - { 0xfe1f, KEY_ZOOM }, - { 0xfe43, KEY_REWIND }, - { 0xfe47, KEY_PLAYPAUSE }, - { 0xfe4f, KEY_FASTFORWARD }, - { 0xfe57, KEY_MUTE }, - { 0xfe0d, KEY_STOP }, - { 0xfe01, KEY_RECORD }, - { 0xfe4e, KEY_POWER }, -}; - -static struct rc_map_table rc_map_dvico_portable_table[] = { - { 0xfc02, KEY_SETUP }, /* Profile */ - { 0xfc43, KEY_POWER2 }, - { 0xfc06, KEY_EPG }, - { 0xfc5a, KEY_BACK }, - { 0xfc05, KEY_MENU }, - { 0xfc47, KEY_INFO }, - { 0xfc01, KEY_TAB }, - { 0xfc42, KEY_PREVIOUSSONG },/* Replay */ - { 0xfc49, KEY_VOLUMEUP }, - { 0xfc09, KEY_VOLUMEDOWN }, - { 0xfc54, KEY_CHANNELUP }, - { 0xfc0b, KEY_CHANNELDOWN }, - { 0xfc16, KEY_CAMERA }, - { 0xfc40, KEY_TUNER }, /* ATV/DTV */ - { 0xfc45, KEY_OPEN }, - { 0xfc19, KEY_1 }, - { 0xfc18, KEY_2 }, - { 0xfc1b, KEY_3 }, - { 0xfc1a, KEY_4 }, - { 0xfc58, KEY_5 }, - { 0xfc59, KEY_6 }, - { 0xfc15, KEY_7 }, - { 0xfc14, KEY_8 }, - { 0xfc17, KEY_9 }, - { 0xfc44, KEY_ANGLE }, /* Aspect */ - { 0xfc55, KEY_0 }, - { 0xfc07, KEY_ZOOM }, - { 0xfc0a, KEY_REWIND }, - { 0xfc08, KEY_PLAYPAUSE }, - { 0xfc4b, KEY_FASTFORWARD }, - { 0xfc5b, KEY_MUTE }, - { 0xfc04, KEY_STOP }, - { 0xfc56, KEY_RECORD }, - { 0xfc57, KEY_POWER }, - { 0xfc41, KEY_UNKNOWN }, /* INPUT */ - { 0xfc00, KEY_UNKNOWN }, /* HD */ -}; - -static struct rc_map_table rc_map_d680_dmb_table[] = { - { 0x0038, KEY_UNKNOWN }, /* TV/AV */ - { 0x080c, KEY_ZOOM }, - { 0x0800, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0802, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0804, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0806, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0808, KEY_8 }, - { 0x0009, KEY_9 }, - { 0x000a, KEY_MUTE }, - { 0x0829, KEY_BACK }, - { 0x0012, KEY_CHANNELUP }, - { 0x0813, KEY_CHANNELDOWN }, - { 0x002b, KEY_VOLUMEUP }, - { 0x082c, KEY_VOLUMEDOWN }, - { 0x0020, KEY_UP }, - { 0x0821, KEY_DOWN }, - { 0x0011, KEY_LEFT }, - { 0x0810, KEY_RIGHT }, - { 0x000d, KEY_OK }, - { 0x081f, KEY_RECORD }, - { 0x0017, KEY_PLAYPAUSE }, - { 0x0816, KEY_PLAYPAUSE }, - { 0x000b, KEY_STOP }, - { 0x0827, KEY_FASTFORWARD }, - { 0x0026, KEY_REWIND }, - { 0x081e, KEY_UNKNOWN }, /* Time Shift */ - { 0x000e, KEY_UNKNOWN }, /* Snapshot */ - { 0x082d, KEY_UNKNOWN }, /* Mouse Cursor */ - { 0x000f, KEY_UNKNOWN }, /* Minimize/Maximize */ - { 0x0814, KEY_UNKNOWN }, /* Shuffle */ - { 0x0025, KEY_POWER }, -}; - -static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) -{ - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; - static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - - return 0; -} - -static int cxusb_mt352_demod_init(struct dvb_frontend* fe) -{ /* used in both lgz201 and th7579 */ - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x29 }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; - static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - return 0; -} - -static struct cx22702_config cxusb_cx22702_config = { - .demod_address = 0x63, - .output_mode = CX22702_PARALLEL_OUTPUT, -}; - -static struct lgdt330x_config cxusb_lgdt3303_config = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, -}; - -static struct lgdt330x_config cxusb_aver_lgdt3303_config = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, - .clock_polarity_flip = 2, -}; - -static struct mt352_config cxusb_dee1601_config = { - .demod_address = 0x0f, - .demod_init = cxusb_dee1601_demod_init, -}; - -static struct zl10353_config cxusb_zl10353_dee1601_config = { - .demod_address = 0x0f, - .parallel_ts = 1, -}; - -static struct mt352_config cxusb_mt352_config = { - /* used in both lgz201 and th7579 */ - .demod_address = 0x0f, - .demod_init = cxusb_mt352_demod_init, -}; - -static struct zl10353_config cxusb_zl10353_xc3028_config = { - .demod_address = 0x0f, - .if2 = 45600, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static struct zl10353_config cxusb_zl10353_xc3028_config_no_i2c_gate = { - .demod_address = 0x0f, - .if2 = 45600, - .no_tuner = 1, - .parallel_ts = 1, - .disable_i2c_gate_ctrl = 1, -}; - -static struct mt352_config cxusb_mt352_xc3028_config = { - .demod_address = 0x0f, - .if2 = 4560, - .no_tuner = 1, - .demod_init = cxusb_mt352_demod_init, -}; - -/* FIXME: needs tweaking */ -static struct mxl5005s_config aver_a868r_tuner = { - .i2c_address = 0x63, - .if_freq = 6000000UL, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_C, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -/* FIXME: needs tweaking */ -static struct mxl5005s_config d680_dmb_tuner = { - .i2c_address = 0x63, - .if_freq = 36125000UL, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_C, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static struct max2165_config mygica_d689_max2165_cfg = { - .i2c_address = 0x60, - .osc_clk = 20 -}; - -/* Callbacks for DVB USB */ -static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(simple_tuner_attach, adap->fe, - &adap->dev->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3); - return 0; -} - -static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe, 0x61, - NULL, DVB_PLL_THOMSON_DTT7579); - return 0; -} - -static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201); - return 0; -} - -static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe, 0x60, - NULL, DVB_PLL_THOMSON_DTT7579); - return 0; -} - -static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(simple_tuner_attach, adap->fe, - &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); - return 0; -} - -static int dvico_bluebird_xc2028_callback(void *ptr, int component, - int command, int arg) -{ - struct dvb_usb_adapter *adap = ptr; - struct dvb_usb_device *d = adap->dev; - - switch (command) { - case XC2028_TUNER_RESET: - deb_info("%s: XC2028_TUNER_RESET %d\n", __func__, arg); - cxusb_bluebird_gpio_pulse(d, 0x01, 1); - break; - case XC2028_RESET_CLK: - deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg); - break; - default: - deb_info("%s: unknown command %d, arg %d\n", __func__, - command, arg); - return -EINVAL; - } - - return 0; -} - -static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &adap->dev->i2c_adap, - .i2c_addr = 0x61, - }; - static struct xc2028_ctrl ctl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - }; - - /* FIXME: generalize & move to common area */ - adap->fe->callback = dvico_bluebird_xc2028_callback; - - fe = dvb_attach(xc2028_attach, adap->fe, &cfg); - if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) - return -EIO; - - fe->ops.tuner_ops.set_config(fe, &ctl); - - return 0; -} - -static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(mxl5005s_attach, adap->fe, - &adap->dev->i2c_adap, &aver_a868r_tuner); - return 0; -} - -static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe; - fe = dvb_attach(mxl5005s_attach, adap->fe, - &adap->dev->i2c_adap, &d680_dmb_tuner); - return (fe == NULL) ? -EIO : 0; -} - -static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe; - fe = dvb_attach(max2165_attach, adap->fe, - &adap->dev->i2c_adap, &mygica_d689_max2165_cfg); - return (fe == NULL) ? -EIO : 0; -} - -static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 b; - if (usb_set_interface(adap->dev->udev, 0, 6) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); - - if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, - &adap->dev->i2c_adap)) != NULL) - return 0; - - return -EIO; -} - -static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 7) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, - &adap->dev->i2c_adap)) != NULL) - return 0; - - return -EIO; -} - -static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, - &adap->dev->i2c_adap); - if (adap->fe != NULL) - return 0; - - return -EIO; -} - -static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) -{ - /* used in both lgz201 and th7579 */ - if (usb_set_interface(adap->dev->udev, 0, 0) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, - &adap->dev->i2c_adap)) != NULL) - return 0; - - return -EIO; -} - -static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 0) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, - &adap->dev->i2c_adap)) != NULL) || - ((adap->fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_dee1601_config, - &adap->dev->i2c_adap)) != NULL)) - return 0; - - return -EIO; -} - -static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 ircode[4]; - int i; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; - - if (usb_set_interface(adap->dev->udev, 0, 1) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - /* reset the tuner and demodulator */ - cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); - cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); - cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - - if ((adap->fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_xc3028_config_no_i2c_gate, - &adap->dev->i2c_adap)) == NULL) - return -EIO; - - /* try to determine if there is no IR decoder on the I2C bus */ - for (i = 0; adap->dev->props.rc.legacy.rc_map_table != NULL && i < 5; i++) { - msleep(20); - if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1) - goto no_IR; - if (ircode[0] == 0 && ircode[1] == 0) - continue; - if (ircode[2] + ircode[3] != 0xff) { -no_IR: - adap->dev->props.rc.legacy.rc_map_table = NULL; - info("No IR receiver detected on this device."); - break; - } - } - - return 0; -} - -static struct dibx000_agc_config dib7070_agc_config = { - .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, - - /* - * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 - */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | - (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - .inv_gain = 600, - .time_stabiliz = 10, - .alpha_level = 0, - .thlock = 118, - .wbd_inv = 0, - .wbd_ref = 3530, - .wbd_sel = 1, - .wbd_alpha = 5, - .agc1_max = 65535, - .agc1_min = 0, - .agc2_max = 65535, - .agc2_min = 0, - .agc1_pt1 = 0, - .agc1_pt2 = 40, - .agc1_pt3 = 183, - .agc1_slope1 = 206, - .agc1_slope2 = 255, - .agc2_pt1 = 72, - .agc2_pt2 = 152, - .agc2_slope1 = 88, - .agc2_slope2 = 90, - .alpha_mant = 17, - .alpha_exp = 27, - .beta_mant = 23, - .beta_exp = 51, - .perform_agc_softsplit = 0, -}; - -static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { - .internal = 60000, - .sampling = 15000, - .pll_prediv = 1, - .pll_ratio = 20, - .pll_range = 3, - .pll_reset = 1, - .pll_bypass = 0, - .enable_refdiv = 0, - .bypclk_div = 0, - .IO_CLK_en_core = 1, - .ADClkSrc = 1, - .modulo = 2, - /* refsel, sel, freq_15k */ - .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), - .ifreq = (0 << 25) | 0, - .timf = 20452225, - .xtal_hz = 12000000, -}; - -static struct dib7000p_config cxusb_dualdig4_rev2_config = { - .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = 0xfcef, - .gpio_val = 0x0110, - - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, -}; - -static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 1) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &cxusb_dualdig4_rev2_config) < 0) { - printk(KERN_WARNING "Unable to enumerate dib7000p\n"); - return -ENODEV; - } - - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, - &cxusb_dualdig4_rev2_config); - if (adap->fe == NULL) - return -EIO; - - return 0; -} - -static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) -{ - return dib7000p_set_gpio(fe, 8, 0, !onoff); -} - -static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - return 0; -} - -static struct dib0070_config dib7070p_dib0070_config = { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib7070_tuner_reset, - .sleep = dib7070_tuner_sleep, - .clock_khz = 12000, -}; - -struct dib0700_adapter_state { - int (*set_param_save) (struct dvb_frontend *, - struct dvb_frontend_parameters *); -}; - -static int dib7070_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - - u16 offset; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); - switch (band) { - case BAND_VHF: offset = 950; break; - default: - case BAND_UHF: offset = 550; break; - } - - dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - - return state->set_param_save(fe, fep); -} - -static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = - dib7000p_get_i2c_master(adap->fe, - DIBX000_I2C_INTERFACE_TUNER, 1); - - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, - &dib7070p_dib0070_config) == NULL) - return -ENODEV; - - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; - return 0; -} - -static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 1) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - /* reset the tuner and demodulator */ - cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); - cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); - cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - - if ((adap->fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_xc3028_config, - &adap->dev->i2c_adap)) != NULL) - return 0; - - if ((adap->fe = dvb_attach(mt352_attach, - &cxusb_mt352_xc3028_config, - &adap->dev->i2c_adap)) != NULL) - return 0; - - return -EIO; -} - -static struct lgs8gxx_config d680_lgs8gl5_cfg = { - .prod = LGS8GXX_PROD_LGS8GL5, - .demod_address = 0x19, - .serial_ts = 0, - .ts_clk_pol = 0, - .ts_clk_gated = 1, - .if_clk_freq = 30400, /* 30.4 MHz */ - .if_freq = 5725, /* 5.725 MHz */ - .if_neg_center = 0, - .ext_adc = 0, - .adc_signed = 0, - .if_neg_edge = 0, -}; - -static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap->dev; - int n; - - /* Select required USB configuration */ - if (usb_set_interface(d->udev, 0, 0) < 0) - err("set interface failed"); - - /* Unblock all USB pipes */ - usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); - - /* Drain USB pipes to avoid hang after reboot */ - for (n = 0; n < 5; n++) { - cxusb_d680_dmb_drain_message(d); - cxusb_d680_dmb_drain_video(d); - msleep(200); - } - - /* Reset the tuner */ - if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { - err("clear tuner gpio failed"); - return -EIO; - } - msleep(100); - if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { - err("set tuner gpio failed"); - return -EIO; - } - msleep(100); - - /* Attach frontend */ - adap->fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); - if (adap->fe == NULL) - return -EIO; - - return 0; -} - -static struct atbm8830_config mygica_d689_atbm8830_cfg = { - .prod = ATBM8830_PROD_8830, - .demod_address = 0x40, - .serial_ts = 0, - .ts_sampling_edge = 1, - .ts_clk_gated = 0, - .osc_clk_freq = 30400, /* in kHz */ - .if_freq = 0, /* zero IF */ - .zif_swap_iq = 1, - .agc_min = 0x2E, - .agc_max = 0x90, - .agc_hold_loop = 0, -}; - -static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap->dev; - - /* Select required USB configuration */ - if (usb_set_interface(d->udev, 0, 0) < 0) - err("set interface failed"); - - /* Unblock all USB pipes */ - usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); - - - /* Reset the tuner */ - if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { - err("clear tuner gpio failed"); - return -EIO; - } - msleep(100); - if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { - err("set tuner gpio failed"); - return -EIO; - } - msleep(100); - - /* Attach frontend */ - adap->fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, - &d->i2c_adap); - if (adap->fe == NULL) - return -EIO; - - return 0; -} - -/* - * DViCO has shipped two devices with the same USB ID, but only one of them - * needs a firmware download. Check the device class details to see if they - * have non-default values to decide whether the device is actually cold or - * not, and forget a match if it turns out we selected the wrong device. - */ -static int bluebird_fx2_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - int wascold = *cold; - - *cold = udev->descriptor.bDeviceClass == 0xff && - udev->descriptor.bDeviceSubClass == 0xff && - udev->descriptor.bDeviceProtocol == 0xff; - - if (*cold && !wascold) - *desc = NULL; - - return 0; -} - -/* - * DViCO bluebird firmware needs the "warm" product ID to be patched into the - * firmware file before download. - */ - -static const int dvico_firmware_id_offsets[] = { 6638, 3204 }; -static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, - const struct firmware *fw) -{ - int pos; - - for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) { - int idoff = dvico_firmware_id_offsets[pos]; - - if (fw->size < idoff + 4) - continue; - - if (fw->data[idoff] == (USB_VID_DVICO & 0xff) && - fw->data[idoff + 1] == USB_VID_DVICO >> 8) { - struct firmware new_fw; - u8 *new_fw_data = vmalloc(fw->size); - int ret; - - if (!new_fw_data) - return -ENOMEM; - - memcpy(new_fw_data, fw->data, fw->size); - new_fw.size = fw->size; - new_fw.data = new_fw_data; - - new_fw_data[idoff + 2] = - le16_to_cpu(udev->descriptor.idProduct) + 1; - new_fw_data[idoff + 3] = - le16_to_cpu(udev->descriptor.idProduct) >> 8; - - ret = usb_cypress_load_firmware(udev, &new_fw, - CYPRESS_FX2); - vfree(new_fw_data); - return ret; - } - } - - return -EINVAL; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties cxusb_medion_properties; -static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; -static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; -static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; -static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; -static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; -static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; -static struct dvb_usb_device_properties cxusb_aver_a868r_properties; -static struct dvb_usb_device_properties cxusb_d680_dmb_properties; -static struct dvb_usb_device_properties cxusb_mygica_d689_properties; - -static int cxusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &cxusb_bluebird_nano2_needsfirmware_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &cxusb_bluebird_dualdig4_rev2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, - THIS_MODULE, NULL, adapter_nr) || - 0) - return 0; - - return -EINVAL; -} - -static struct usb_device_id cxusb_table [] = { - { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, - { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, - { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) }, - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, cxusb_table); - -static struct dvb_usb_device_properties cxusb_medion_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_cx22702_frontend_attach, - .tuner_attach = cxusb_fmd1216me_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - - }, - }, - .power_ctrl = cxusb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Medion MD95700 (MDUSBTV-HYBRID)", - { NULL }, - { &cxusb_table[0], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-01.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_lgdt3303_frontend_attach, - .tuner_attach = cxusb_lgh064f_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV5 USB Gold", - { &cxusb_table[1], NULL }, - { &cxusb_table[2], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-01.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_dee1601_frontend_attach, - .tuner_attach = cxusb_dee1601_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .rc.legacy = { - .rc_interval = 150, - .rc_map_table = rc_map_dvico_mce_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), - .rc_query = cxusb_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 3, - .devices = { - { "DViCO FusionHDTV DVB-T Dual USB", - { &cxusb_table[3], NULL }, - { &cxusb_table[4], NULL }, - }, - { "DigitalNow DVB-T Dual USB", - { &cxusb_table[9], NULL }, - { &cxusb_table[10], NULL }, - }, - { "DViCO FusionHDTV DVB-T Dual Digital 2", - { &cxusb_table[11], NULL }, - { &cxusb_table[12], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-01.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 2, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_mt352_frontend_attach, - .tuner_attach = cxusb_lgz201_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T USB (LGZ201)", - { &cxusb_table[5], NULL }, - { &cxusb_table[6], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-01.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_mt352_frontend_attach, - .tuner_attach = cxusb_dtt7579_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T USB (TH7579)", - { &cxusb_table[7], NULL }, - { &cxusb_table[8], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_dualdig4_frontend_attach, - .tuner_attach = cxusb_dvico_xc3028_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_mce_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), - .rc_query = cxusb_bluebird2_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T Dual Digital 4", - { NULL }, - { &cxusb_table[13], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .identify_state = bluebird_fx2_identify_state, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_nano2_frontend_attach, - .tuner_attach = cxusb_dvico_xc3028_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_nano2_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_bluebird2_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T NANO2", - { NULL }, - { &cxusb_table[14], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-02.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - .identify_state = bluebird_fx2_identify_state, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_nano2_frontend_attach, - .tuner_attach = cxusb_dvico_xc3028_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_nano2_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_portable_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_query = cxusb_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", - { &cxusb_table[14], NULL }, - { &cxusb_table[15], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_aver_streaming_ctrl, - .frontend_attach = cxusb_aver_lgdt3303_frontend_attach, - .tuner_attach = cxusb_mxl5003s_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - - }, - }, - .power_ctrl = cxusb_aver_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "AVerMedia AVerTVHD Volar (A868R)", - { NULL }, - { &cxusb_table[16], NULL }, - }, - } -}; - -static -struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, - .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, - .size_of_priv = sizeof(struct dib0700_adapter_state), - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - }, - }, - - .power_ctrl = cxusb_bluebird_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_dvico_mce_table, - .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), - .rc_query = cxusb_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)", - { NULL }, - { &cxusb_table[17], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, - .frontend_attach = cxusb_d680_dmb_frontend_attach, - .tuner_attach = cxusb_d680_dmb_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_d680_dmb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_d680_dmb_table, - .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table), - .rc_query = cxusb_d680_dmb_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { - "Conexant DMB-TH Stick", - { NULL }, - { &cxusb_table[18], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, - .frontend_attach = cxusb_mygica_d689_frontend_attach, - .tuner_attach = cxusb_mygica_d689_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_d680_dmb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_d680_dmb_table, - .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table), - .rc_query = cxusb_d680_dmb_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { - "Mygica D689 DMB-TH", - { NULL }, - { &cxusb_table[19], NULL }, - }, - } -}; - -static struct usb_driver cxusb_driver = { - .name = "dvb_usb_cxusb", - .probe = cxusb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = cxusb_table, -}; - -/* module stuff */ -static int __init cxusb_module_init(void) -{ - int result; - if ((result = usb_register(&cxusb_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit cxusb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&cxusb_driver); -} - -module_init (cxusb_module_init); -module_exit (cxusb_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_AUTHOR("Michael Krufky "); -MODULE_AUTHOR("Chris Pascoe "); -MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cxusb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cxusb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cxusb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/cxusb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -#ifndef _DVB_USB_CXUSB_H_ -#define _DVB_USB_CXUSB_H_ - -#define DVB_USB_LOG_PREFIX "cxusb" -#include "dvb-usb.h" - -/* usb commands - some of it are guesses, don't have a reference yet */ -#define CMD_BLUEBIRD_GPIO_RW 0x05 - -#define CMD_I2C_WRITE 0x08 -#define CMD_I2C_READ 0x09 - -#define CMD_GPIO_READ 0x0d -#define CMD_GPIO_WRITE 0x0e -#define GPIO_TUNER 0x02 - -#define CMD_POWER_OFF 0xdc -#define CMD_POWER_ON 0xde - -#define CMD_STREAMING_ON 0x36 -#define CMD_STREAMING_OFF 0x37 - -#define CMD_AVER_STREAM_ON 0x18 -#define CMD_AVER_STREAM_OFF 0x19 - -#define CMD_GET_IR_CODE 0x47 - -#define CMD_ANALOG 0x50 -#define CMD_DIGITAL 0x51 - -struct cxusb_state { - u8 gpio_write_state[3]; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700_core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700_core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,750 +0,0 @@ -/* Linux driver for devices based on the DiBcom DiB0700 USB bridge - * - * 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, version 2. - * - * Copyright (C) 2005-6 DiBcom, SA - */ -#include "dib0700.h" - -/* debug */ -int dvb_usb_dib0700_debug; -module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); - -static int nb_packet_buffer_size = 21; -module_param(nb_packet_buffer_size, int, 0644); -MODULE_PARM_DESC(nb_packet_buffer_size, - "Set the dib0700 driver data buffer size. This parameter " - "corresponds to the number of TS packets. The actual size of " - "the data buffer corresponds to this parameter " - "multiplied by 188 (default: 21)"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - - -int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, - u32 *romversion, u32 *ramversion, u32 *fwtype) -{ - u8 b[16]; - int ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - REQUEST_GET_VERSION, - USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - b, sizeof(b), USB_CTRL_GET_TIMEOUT); - if (hwversion != NULL) - *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; - if (romversion != NULL) - *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; - if (ramversion != NULL) - *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; - if (fwtype != NULL) - *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15]; - return ret; -} - -/* expecting rx buffer: request data[0] data[1] ... data[2] */ -static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) -{ - int status; - - deb_data(">>> "); - debug_dump(tx, txlen, deb_data); - - status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), - tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen, - USB_CTRL_GET_TIMEOUT); - - if (status != txlen) - deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen); - - return status < 0 ? status : 0; -} - -/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ -int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) -{ - u16 index, value; - int status; - - if (txlen < 2) { - err("tx buffer length is smaller than 2. Makes no sense."); - return -EINVAL; - } - if (txlen > 4) { - err("tx buffer length is larger than 4. Not supported."); - return -EINVAL; - } - - deb_data(">>> "); - debug_dump(tx,txlen,deb_data); - - value = ((txlen - 2) << 8) | tx[1]; - index = 0; - if (txlen > 2) - index |= (tx[2] << 8); - if (txlen > 3) - index |= tx[3]; - - status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], - USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, - USB_CTRL_GET_TIMEOUT); - - if (status < 0) - deb_info("ep 0 read error (status = %d)\n",status); - - deb_data("<<< "); - debug_dump(rx, rxlen, deb_data); - - return status; /* length in case of success */ -} - -int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) -{ - u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) }; - return dib0700_ctrl_wr(d, buf, sizeof(buf)); -} - -static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) -{ - struct dib0700_state *st = d->priv; - u8 b[3]; - int ret; - - if (st->fw_version >= 0x10201) { - b[0] = REQUEST_SET_USB_XFER_LEN; - b[1] = (nb_ts_packets >> 8) & 0xff; - b[2] = nb_ts_packets & 0xff; - - deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); - - ret = dib0700_ctrl_wr(d, b, sizeof(b)); - } else { - deb_info("this firmware does not allow to change the USB xfer len\n"); - ret = -EIO; - } - - return ret; -} - -/* - * I2C master xfer function (supported in 1.20 firmware) - */ -static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, - int num) -{ - /* The new i2c firmware messages are more reliable and in particular - properly support i2c read calls not preceded by a write */ - - struct dvb_usb_device *d = i2c_get_adapdata(adap); - uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */ - uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */ - uint8_t en_start = 0; - uint8_t en_stop = 0; - uint8_t buf[255]; /* TBV: malloc ? */ - int result, i; - - /* Ensure nobody else hits the i2c bus while we're sending our - sequence of messages, (such as the remote control thread) */ - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - if (i == 0) { - /* First message in the transaction */ - en_start = 1; - } else if (!(msg[i].flags & I2C_M_NOSTART)) { - /* Device supports repeated-start */ - en_start = 1; - } else { - /* Not the first packet and device doesn't support - repeated start */ - en_start = 0; - } - if (i == (num - 1)) { - /* Last message in the transaction */ - en_stop = 1; - } - - if (msg[i].flags & I2C_M_RD) { - /* Read request */ - u16 index, value; - uint8_t i2c_dest; - - i2c_dest = (msg[i].addr << 1); - value = ((en_start << 7) | (en_stop << 6) | - (msg[i].len & 0x3F)) << 8 | i2c_dest; - /* I2C ctrl + FE bus; */ - index = ((gen_mode << 6) & 0xC0) | - ((bus_mode << 4) & 0x30); - - result = usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev, 0), - REQUEST_NEW_I2C_READ, - USB_TYPE_VENDOR | USB_DIR_IN, - value, index, msg[i].buf, - msg[i].len, - USB_CTRL_GET_TIMEOUT); - if (result < 0) { - deb_info("i2c read error (status = %d)\n", result); - break; - } - - deb_data("<<< "); - debug_dump(msg[i].buf, msg[i].len, deb_data); - - } else { - /* Write request */ - buf[0] = REQUEST_NEW_I2C_WRITE; - buf[1] = msg[i].addr << 1; - buf[2] = (en_start << 7) | (en_stop << 6) | - (msg[i].len & 0x3F); - /* I2C ctrl + FE bus; */ - buf[3] = ((gen_mode << 6) & 0xC0) | - ((bus_mode << 4) & 0x30); - /* The Actual i2c payload */ - memcpy(&buf[4], msg[i].buf, msg[i].len); - - deb_data(">>> "); - debug_dump(buf, msg[i].len + 4, deb_data); - - result = usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev, 0), - REQUEST_NEW_I2C_WRITE, - USB_TYPE_VENDOR | USB_DIR_OUT, - 0, 0, buf, msg[i].len + 4, - USB_CTRL_GET_TIMEOUT); - if (result < 0) { - deb_info("i2c write error (status = %d)\n", result); - break; - } - } - } - mutex_unlock(&d->i2c_mutex); - return i; -} - -/* - * I2C master xfer function (pre-1.20 firmware) - */ -static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, - struct i2c_msg *msg, int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i,len; - u8 buf[255]; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* fill in the address */ - buf[1] = msg[i].addr << 1; - /* fill the buffer */ - memcpy(&buf[2], msg[i].buf, msg[i].len); - - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - buf[0] = REQUEST_I2C_READ; - buf[1] |= 1; - - /* special thing in the current firmware: when length is zero the read-failed */ - if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) { - deb_info("I2C read failed on address 0x%02x\n", - msg[i].addr); - break; - } - - msg[i+1].len = len; - - i++; - } else { - buf[0] = REQUEST_I2C_WRITE; - if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0) - break; - } - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct dib0700_state *st = d->priv; - - if (st->fw_use_new_i2c_api == 1) { - /* User running at least fw 1.20 */ - return dib0700_i2c_xfer_new(adap, msg, num); - } else { - /* Use legacy calls */ - return dib0700_i2c_xfer_legacy(adap, msg, num); - } -} - -static u32 dib0700_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -struct i2c_algorithm dib0700_i2c_algo = { - .master_xfer = dib0700_i2c_xfer, - .functionality = dib0700_i2c_func, -}; - -int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold) -{ - u8 b[16]; - s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0), - REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT); - - deb_info("FW GET_VERSION length: %d\n",ret); - - *cold = ret <= 0; - - deb_info("cold: %d\n", *cold); - return 0; -} - -static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, - u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv, - u16 pll_loopdiv, u16 free_div, u16 dsuScaler) -{ - u8 b[10]; - b[0] = REQUEST_SET_CLOCK; - b[1] = (en_pll << 7) | (pll_src << 6) | (pll_range << 5) | (clock_gpio3 << 4); - b[2] = (pll_prediv >> 8) & 0xff; // MSB - b[3] = pll_prediv & 0xff; // LSB - b[4] = (pll_loopdiv >> 8) & 0xff; // MSB - b[5] = pll_loopdiv & 0xff; // LSB - b[6] = (free_div >> 8) & 0xff; // MSB - b[7] = free_div & 0xff; // LSB - b[8] = (dsuScaler >> 8) & 0xff; // MSB - b[9] = dsuScaler & 0xff; // LSB - - return dib0700_ctrl_wr(d, b, 10); -} - -int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) -{ - u16 divider; - u8 b[8]; - - if (scl_kHz == 0) - return -EINVAL; - - b[0] = REQUEST_SET_I2C_PARAM; - divider = (u16) (30000 / scl_kHz); - b[2] = (u8) (divider >> 8); - b[3] = (u8) (divider & 0xff); - divider = (u16) (72000 / scl_kHz); - b[4] = (u8) (divider >> 8); - b[5] = (u8) (divider & 0xff); - divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */ - b[6] = (u8) (divider >> 8); - b[7] = (u8) (divider & 0xff); - - deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", - (b[2] << 8) | (b[3]), (b[4] << 8) | b[5], (b[6] << 8) | b[7], scl_kHz); - return dib0700_ctrl_wr(d, b, 8); -} - - -int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3) -{ - switch (clk_MHz) { - case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break; - default: return -EINVAL; - } - return 0; -} - -static int dib0700_jumpram(struct usb_device *udev, u32 address) -{ - int ret, actlen; - u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0, - (address >> 24) & 0xff, - (address >> 16) & 0xff, - (address >> 8) & 0xff, - address & 0xff }; - - if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) { - deb_fw("jumpram to 0x%x failed\n",address); - return ret; - } - if (actlen != 8) { - deb_fw("jumpram to 0x%x failed\n",address); - return -EIO; - } - return 0; -} - -int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) -{ - struct hexline hx; - int pos = 0, ret, act_len, i, adap_num; - u8 b[16]; - u32 fw_version; - - u8 buf[260]; - - while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) { - deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n", - hx.addr, hx.len, hx.chk); - - buf[0] = hx.len; - buf[1] = (hx.addr >> 8) & 0xff; - buf[2] = hx.addr & 0xff; - buf[3] = hx.type; - memcpy(&buf[4],hx.data,hx.len); - buf[4+hx.len] = hx.chk; - - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x01), - buf, - hx.len + 5, - &act_len, - 1000); - - if (ret < 0) { - err("firmware download failed at %d with %d",pos,ret); - return ret; - } - } - - if (ret == 0) { - /* start the firmware */ - if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) { - info("firmware started successfully."); - msleep(500); - } - } else - ret = -EIO; - - /* the number of ts packet has to be at least 1 */ - if (nb_packet_buffer_size < 1) - nb_packet_buffer_size = 1; - - /* get the fimware version */ - usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - REQUEST_GET_VERSION, - USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - b, sizeof(b), USB_CTRL_GET_TIMEOUT); - fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; - - /* set the buffer size - DVB-USB is allocating URB buffers - * only after the firwmare download was successful */ - for (i = 0; i < dib0700_device_count; i++) { - for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters; - adap_num++) { - if (fw_version >= 0x10201) { - dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size; - } else { - /* for fw version older than 1.20.1, - * the buffersize has to be n times 512 */ - dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512; - if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512) - dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512; - } - } - } - - return ret; -} - -int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct dib0700_state *st = adap->dev->priv; - u8 b[4]; - int ret; - - if ((onoff != 0) && (st->fw_version >= 0x10201)) { - /* for firmware later than 1.20.1, - * the USB xfer length can be set */ - ret = dib0700_set_usb_xfer_len(adap->dev, - st->nb_packet_buffer_size); - if (ret < 0) { - deb_info("can not set the USB xfer len\n"); - return ret; - } - } - - b[0] = REQUEST_ENABLE_VIDEO; - b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ - - if (st->disable_streaming_master_mode == 1) - b[2] = 0x00; - else - b[2] = 0x01 << 4; /* Master mode */ - - b[3] = 0x00; - - deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); - - st->channel_state &= ~0x3; - if ((adap->stream.props.endpoint != 2) - && (adap->stream.props.endpoint != 3)) { - deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->stream.props.endpoint); - if (onoff) - st->channel_state |= 1 << (adap->id); - else - st->channel_state |= 1 << ~(adap->id); - } else { - if (onoff) - st->channel_state |= 1 << (adap->stream.props.endpoint-2); - else - st->channel_state |= 1 << (3-adap->stream.props.endpoint); - } - - b[2] |= st->channel_state; - - deb_info("data for streaming: %x %x\n", b[1], b[2]); - - return dib0700_ctrl_wr(adap->dev, b, 4); -} - -int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) -{ - struct dvb_usb_device *d = rc->priv; - struct dib0700_state *st = d->priv; - u8 rc_setup[3] = { REQUEST_SET_RC, 0, 0 }; - int new_proto, ret; - - /* Set the IR mode */ - if (rc_type == RC_TYPE_RC5) - new_proto = 1; - else if (rc_type == RC_TYPE_NEC) - new_proto = 0; - else if (rc_type == RC_TYPE_RC6) { - if (st->fw_version < 0x10200) - return -EINVAL; - - new_proto = 2; - } else - return -EINVAL; - - rc_setup[1] = new_proto; - - ret = dib0700_ctrl_wr(d, rc_setup, sizeof(rc_setup)); - if (ret < 0) { - err("ir protocol setup failed"); - return ret; - } - - d->props.rc.core.protocol = rc_type; - - return ret; -} - -/* Number of keypresses to ignore before start repeating */ -#define RC_REPEAT_DELAY_V1_20 10 - -/* This is the structure of the RC response packet starting in firmware 1.20 */ -struct dib0700_rc_response { - u8 report_id; - u8 data_state; - union { - u16 system16; - struct { - u8 not_system; - u8 system; - }; - }; - u8 data; - u8 not_data; -}; -#define RC_MSG_SIZE_V1_20 6 - -static void dib0700_rc_urb_completion(struct urb *purb) -{ - struct dvb_usb_device *d = purb->context; - struct dib0700_state *st; - struct dib0700_rc_response *poll_reply; - u32 uninitialized_var(keycode); - u8 toggle; - - deb_info("%s()\n", __func__); - if (d == NULL) - return; - - if (d->rc_dev == NULL) { - /* This will occur if disable_rc_polling=1 */ - usb_free_urb(purb); - return; - } - - st = d->priv; - poll_reply = purb->transfer_buffer; - - if (purb->status < 0) { - deb_info("discontinuing polling\n"); - usb_free_urb(purb); - return; - } - - if (purb->actual_length != RC_MSG_SIZE_V1_20) { - deb_info("malformed rc msg size=%d\n", purb->actual_length); - goto resubmit; - } - - deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n", - poll_reply->report_id, poll_reply->data_state, - poll_reply->system, poll_reply->not_system, - poll_reply->data, poll_reply->not_data, - purb->actual_length); - - switch (d->props.rc.core.protocol) { - case RC_TYPE_NEC: - toggle = 0; - - /* NEC protocol sends repeat code as 0 0 0 FF */ - if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00) - && (poll_reply->not_data == 0xff)) { - poll_reply->data_state = 2; - break; - } - - if ((poll_reply->system ^ poll_reply->not_system) != 0xff) { - deb_data("NEC extended protocol\n"); - /* NEC extended code - 24 bits */ - keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data; - } else { - deb_data("NEC normal protocol\n"); - /* normal NEC code - 16 bits */ - keycode = poll_reply->system << 8 | poll_reply->data; - } - - break; - default: - deb_data("RC5 protocol\n"); - /* RC5 Protocol */ - toggle = poll_reply->report_id; - keycode = poll_reply->system << 8 | poll_reply->data; - - break; - } - - if ((poll_reply->data + poll_reply->not_data) != 0xff) { - /* Key failed integrity check */ - err("key failed integrity check: %04x %02x %02x", - poll_reply->system, - poll_reply->data, poll_reply->not_data); - goto resubmit; - } - - rc_keydown(d->rc_dev, keycode, toggle); - -resubmit: - /* Clean the buffer before we requeue */ - memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20); - - /* Requeue URB */ - usb_submit_urb(purb, GFP_ATOMIC); -} - -int dib0700_rc_setup(struct dvb_usb_device *d) -{ - struct dib0700_state *st = d->priv; - struct urb *purb; - int ret; - - /* Poll-based. Don't initialize bulk mode */ - if (st->fw_version < 0x10200) - return 0; - - /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ - purb = usb_alloc_urb(0, GFP_KERNEL); - if (purb == NULL) { - err("rc usb alloc urb failed\n"); - return -ENOMEM; - } - - purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL); - if (purb->transfer_buffer == NULL) { - err("rc kzalloc failed\n"); - usb_free_urb(purb); - return -ENOMEM; - } - - purb->status = -EINPROGRESS; - usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1), - purb->transfer_buffer, RC_MSG_SIZE_V1_20, - dib0700_rc_urb_completion, d); - - ret = usb_submit_urb(purb, GFP_ATOMIC); - if (ret) - err("rc submit urb failed\n"); - - return ret; -} - -static int dib0700_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int i; - struct dvb_usb_device *dev; - - for (i = 0; i < dib0700_device_count; i++) - if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, - &dev, adapter_nr) == 0) { - struct dib0700_state *st = dev->priv; - u32 hwversion, romversion, fw_version, fwtype; - - dib0700_get_version(dev, &hwversion, &romversion, - &fw_version, &fwtype); - - deb_info("Firmware version: %x, %d, 0x%x, %d\n", - hwversion, romversion, fw_version, fwtype); - - st->fw_version = fw_version; - st->nb_packet_buffer_size = (u32)nb_packet_buffer_size; - - /* Disable polling mode on newer firmwares */ - if (st->fw_version >= 0x10200) - dev->props.rc.core.bulk_mode = true; - else - dev->props.rc.core.bulk_mode = false; - - dib0700_rc_setup(dev); - - return 0; - } - - return -ENODEV; -} - -static struct usb_driver dib0700_driver = { - .name = "dvb_usb_dib0700", - .probe = dib0700_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dib0700_usb_id_table, -}; - -/* module stuff */ -static int __init dib0700_module_init(void) -{ - int result; - info("loaded with support for %d different device-types", dib0700_device_count); - if ((result = usb_register(&dib0700_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit dib0700_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&dib0700_driver); -} - -module_init (dib0700_module_init); -module_exit (dib0700_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3774 +0,0 @@ -/* Linux driver for devices based on the DiBcom DiB0700 USB bridge - * - * 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, version 2. - * - * Copyright (C) 2005-9 DiBcom, SA et al - */ -#include "dib0700.h" - -#include "dib3000mc.h" -#include "dib7000m.h" -#include "dib7000p.h" -#include "dib8000.h" -#include "dib9000.h" -#include "mt2060.h" -#include "mt2266.h" -#include "tuner-xc2028.h" -#include "xc5000.h" -#include "s5h1411.h" -#include "dib0070.h" -#include "dib0090.h" -#include "lgdt3305.h" -#include "mxl5007t.h" - -static int force_lna_activation; -module_param(force_lna_activation, int, 0644); -MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " - "if applicable for the device (default: 0=automatic/off)."); - -struct dib0700_adapter_state { - int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *); - const struct firmware *frontend_firmware; -}; - -/* Hauppauge Nova-T 500 (aka Bristol) - * has a LNA on GPIO0 which is enabled by setting 1 */ -static struct mt2060_config bristol_mt2060_config[2] = { - { - .i2c_address = 0x60, - .clock_out = 3, - }, { - .i2c_address = 0x61, - } -}; - - -static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = { - .band_caps = BAND_VHF | BAND_UHF, - .setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0), - - .agc1_max = 42598, - .agc1_min = 17694, - .agc2_max = 45875, - .agc2_min = 0, - - .agc1_pt1 = 0, - .agc1_pt2 = 59, - - .agc1_slope1 = 0, - .agc1_slope2 = 69, - - .agc2_pt1 = 0, - .agc2_pt2 = 59, - - .agc2_slope1 = 111, - .agc2_slope2 = 28, -}; - -static struct dib3000mc_config bristol_dib3000mc_config[2] = { - { .agc = &bristol_dib3000p_mt2060_agc_config, - .max_time = 0x196, - .ln_adc_level = 0x1cc7, - .output_mpeg2_in_188_bytes = 1, - }, - { .agc = &bristol_dib3000p_mt2060_agc_config, - .max_time = 0x196, - .ln_adc_level = 0x1cc7, - .output_mpeg2_in_188_bytes = 1, - } -}; - -static int bristol_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - if (adap->id == 0) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); - - if (force_lna_activation) - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - else - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); - - if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); - return -ENODEV; - } - } - st->mt2060_if1[adap->id] = 1220; - return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, - (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; -} - -static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) -{ - struct i2c_msg msg[2] = { - { .addr = 0x50, .flags = 0, .buf = &adrs, .len = 1 }, - { .addr = 0x50, .flags = I2C_M_RD, .buf = pval, .len = 1 }, - }; - if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO; - return 0; -} - -static int bristol_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; - struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); - s8 a; - int if1=1220; - if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && - adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) { - if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; - } - return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id], - if1) == NULL ? -ENODEV : 0; -} - -/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ - -/* MT226x */ -static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { - { - BAND_UHF, - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - 1130, - 21, - - 0, - 118, - - 0, - 3530, - 1, - 0, - - 65535, - 33770, - 65535, - 23592, - - 0, - 62, - 255, - 64, - 64, - 132, - 192, - 80, - 80, - - 17, - 27, - 23, - 51, - - 1, - }, { - BAND_VHF | BAND_LBAND, - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), - - 2372, - 21, - - 0, - 118, - - 0, - 3530, - 1, - 0, - - 65535, - 0, - 65535, - 23592, - - 0, - 128, - 128, - 128, - 0, - 128, - 253, - 81, - 0, - - 17, - 27, - 23, - 51, - - 1, - } -}; - -static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { - 60000, 30000, - 1, 8, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (524 << 0), - 0, - 20452225, -}; - -static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { - { .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - - .agc_config_count = 2, - .agc = stk7700d_7000p_mt2266_agc_config, - .bw = &stk7700d_mt2266_pll_config, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - }, - { .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - - .agc_config_count = 2, - .agc = stk7700d_7000p_mt2266_agc_config, - .bw = &stk7700d_mt2266_pll_config, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - } -}; - -static struct mt2266_config stk7700d_mt2266_config[2] = { - { .i2c_address = 0x60 - }, - { .i2c_address = 0x60 - } -}; - -static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (adap->id == 0) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - stk7700d_dib7000p_mt2266_config) - != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - } - - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), - &stk7700d_dib7000p_mt2266_config[adap->id]); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (adap->id == 0) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, - stk7700d_dib7000p_mt2266_config) - != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - } - - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), - &stk7700d_dib7000p_mt2266_config[adap->id]); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *tun_i2c; - tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - return dvb_attach(mt2266_attach, adap->fe, tun_i2c, - &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0; -} - -/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */ -static struct dibx000_agc_config xc3028_agc_config = { - BAND_VHF | BAND_UHF, /* band_caps */ - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | - (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */ - - 712, /* inv_gain */ - 21, /* time_stabiliz */ - - 0, /* alpha_level */ - 118, /* thlock */ - - 0, /* wbd_inv */ - 2867, /* wbd_ref */ - 0, /* wbd_sel */ - 2, /* wbd_alpha */ - - 0, /* agc1_max */ - 0, /* agc1_min */ - 39718, /* agc2_max */ - 9930, /* agc2_min */ - 0, /* agc1_pt1 */ - 0, /* agc1_pt2 */ - 0, /* agc1_pt3 */ - 0, /* agc1_slope1 */ - 0, /* agc1_slope2 */ - 0, /* agc2_pt1 */ - 128, /* agc2_pt2 */ - 29, /* agc2_slope1 */ - 29, /* agc2_slope2 */ - - 17, /* alpha_mant */ - 27, /* alpha_exp */ - 23, /* beta_mant */ - 51, /* beta_exp */ - - 1, /* perform_agc_softsplit */ -}; - -/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */ -static struct dibx000_bandwidth_config xc3028_bw_config = { - 60000, 30000, /* internal, sampling */ - 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ - 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, - modulo */ - (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ - (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ - 20452225, /* timf */ - 30000000, /* xtal_hz */ -}; - -static struct dib7000p_config stk7700ph_dib7700_xc3028_config = { - .output_mpeg2_in_188_bytes = 1, - .tuner_is_baseband = 1, - - .agc_config_count = 1, - .agc = &xc3028_agc_config, - .bw = &xc3028_bw_config, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, -}; - -static int stk7700ph_xc3028_callback(void *ptr, int component, - int command, int arg) -{ - struct dvb_usb_adapter *adap = ptr; - - switch (command) { - case XC2028_TUNER_RESET: - /* Send the tuner in then out of reset */ - dib7000p_set_gpio(adap->fe, 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe, 8, 0, 1); - break; - case XC2028_RESET_CLK: - break; - default: - err("%s: unknown command %d, arg %d\n", __func__, - command, arg); - return -EINVAL; - } - return 0; -} - -static struct xc2028_ctrl stk7700ph_xc3028_ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_DIBCOM52, -}; - -static struct xc2028_config stk7700ph_xc3028_config = { - .i2c_addr = 0x61, - .ctrl = &stk7700ph_xc3028_ctrl, -}; - -static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct usb_device_descriptor *desc = &adap->dev->udev->descriptor; - - if (desc->idVendor == cpu_to_le16(USB_VID_PINNACLE) && - desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX)) - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - else - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - msleep(10); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &stk7700ph_dib7700_xc3028_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, - &stk7700ph_dib7700_xc3028_config); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *tun_i2c; - - tun_i2c = dib7000p_get_i2c_master(adap->fe, - DIBX000_I2C_INTERFACE_TUNER, 1); - - stk7700ph_xc3028_config.i2c_adap = tun_i2c; - - /* FIXME: generalize & move to common area */ - adap->fe->callback = stk7700ph_xc3028_callback; - - return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config) - == NULL ? -ENODEV : 0; -} - -#define DEFAULT_RC_INTERVAL 50 - -static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; - -/* Number of keypresses to ignore before start repeating */ -#define RC_REPEAT_DELAY 6 - -/* - * This function is used only when firmware is < 1.20 version. Newer - * firmwares use bulk mode, with functions implemented at dib0700_core, - * at dib0700_rc_urb_completion() - */ -static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) -{ - u8 key[4]; - u32 keycode; - u8 toggle; - int i; - struct dib0700_state *st = d->priv; - - if (st->fw_version >= 0x10200) { - /* For 1.20 firmware , We need to keep the RC polling - callback so we can reuse the input device setup in - dvb-usb-remote.c. However, the actual work is being done - in the bulk URB completion handler. */ - return 0; - } - - i = dib0700_ctrl_rd(d, rc_request, 2, key, 4); - if (i <= 0) { - err("RC Query Failed"); - return -1; - } - - /* losing half of KEY_0 events from Philipps rc5 remotes.. */ - if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0) - return 0; - - /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */ - - dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */ - - d->last_event = 0; - switch (d->props.rc.core.protocol) { - case RC_TYPE_NEC: - /* NEC protocol sends repeat code as 0 0 0 FF */ - if ((key[3-2] == 0x00) && (key[3-3] == 0x00) && - (key[3] == 0xff)) - keycode = d->last_event; - else { - keycode = key[3-2] << 8 | key[3-3]; - d->last_event = keycode; - } - - rc_keydown(d->rc_dev, keycode, 0); - break; - default: - /* RC-5 protocol changes toggle bit on new keypress */ - keycode = key[3-2] << 8 | key[3-3]; - toggle = key[3-1]; - rc_keydown(d->rc_dev, keycode, toggle); - - break; - } - return 0; -} - -/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ -static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { - BAND_UHF | BAND_VHF, - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), - - 712, - 41, - - 0, - 118, - - 0, - 4095, - 0, - 0, - - 42598, - 17694, - 45875, - 2621, - 0, - 76, - 139, - 52, - 59, - 107, - 172, - 57, - 70, - - 21, - 25, - 28, - 48, - - 1, - { 0, - 107, - 51800, - 24700 - }, -}; - -static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = { - BAND_UHF | BAND_VHF, - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), - - 712, - 41, - - 0, - 118, - - 0, - 4095, - 0, - 0, - - 42598, - 16384, - 42598, - 0, - - 0, - 137, - 255, - - 0, - 255, - - 0, - 0, - - 0, - 41, - - 15, - 25, - - 28, - 48, - - 0, -}; - -static struct dibx000_bandwidth_config stk7700p_pll_config = { - 60000, 30000, - 1, 8, 3, 1, 0, - 0, 0, 1, 1, 0, - (3 << 14) | (1 << 12) | (524 << 0), - 60258167, - 20452225, - 30000000, -}; - -static struct dib7000m_config stk7700p_dib7000m_config = { - .dvbt_mode = 1, - .output_mpeg2_in_188_bytes = 1, - .quartz_direct = 1, - - .agc_config_count = 1, - .agc = &stk7700p_7000m_mt2060_agc_config, - .bw = &stk7700p_pll_config, - - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, -}; - -static struct dib7000p_config stk7700p_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &stk7700p_7000p_mt2060_agc_config, - .bw = &stk7700p_pll_config, - - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, -}; - -static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - /* unless there is no real power management in DVB - we leave the device on GPIO6 */ - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(50); - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); - dib0700_ctrl_clock(adap->dev, 72, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100); - - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - st->mt2060_if1[0] = 1220; - - if (dib7000pc_detection(&adap->dev->i2c_adap)) { - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); - st->is_dib7000pc = 1; - } else - adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static struct mt2060_config stk7700p_mt2060_config = { - 0x60 -}; - -static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; - struct dib0700_state *st = adap->dev->priv; - struct i2c_adapter *tun_i2c; - s8 a; - int if1=1220; - if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && - adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) { - if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; - } - if (st->is_dib7000pc) - tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - else - tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - - return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config, - if1) == NULL ? -ENODEV : 0; -} - -/* DIB7070 generic */ -static struct dibx000_agc_config dib7070_agc_config = { - BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - 600, - 10, - - 0, - 118, - - 0, - 3530, - 1, - 5, - - 65535, - 0, - - 65535, - 0, - - 0, - 40, - 183, - 206, - 255, - 72, - 152, - 88, - 90, - - 17, - 27, - 23, - 51, - - 0, -}; - -static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) -{ - deb_info("reset: %d", onoff); - return dib7000p_set_gpio(fe, 8, 0, !onoff); -} - -static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - deb_info("sleep: %d", onoff); - return dib7000p_set_gpio(fe, 9, 0, onoff); -} - -static struct dib0070_config dib7070p_dib0070_config[2] = { - { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib7070_tuner_reset, - .sleep = dib7070_tuner_sleep, - .clock_khz = 12000, - .clock_pad_drive = 4, - .charge_pump = 2, - }, { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib7070_tuner_reset, - .sleep = dib7070_tuner_sleep, - .clock_khz = 12000, - .charge_pump = 2, - } -}; - -static struct dib0070_config dib7770p_dib0070_config = { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib7070_tuner_reset, - .sleep = dib7070_tuner_sleep, - .clock_khz = 12000, - .clock_pad_drive = 0, - .flip_chip = 1, - .charge_pump = 2, -}; - -static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - - u16 offset; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); - switch (band) { - case BAND_VHF: offset = 950; break; - case BAND_UHF: - default: offset = 550; break; - } - deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); - dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe, fep); -} - -static int dib7770_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - - u16 offset; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); - switch (band) { - case BAND_VHF: - dib7000p_set_gpio(fe, 0, 0, 1); - offset = 850; - break; - case BAND_UHF: - default: - dib7000p_set_gpio(fe, 0, 0, 0); - offset = 250; - break; - } - deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); - dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe, fep); -} - -static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, - DIBX000_I2C_INTERFACE_TUNER, 1); - - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, - &dib7770p_dib0070_config) == NULL) - return -ENODEV; - - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7770_set_param_override; - return 0; -} - -static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - - if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) - return -ENODEV; - } else { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) - return -ENODEV; - } - - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; - return 0; -} - -static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index, - u16 pid, int onoff) -{ - struct dib0700_state *st = adapter->dev->priv; - if (st->is_dib7000pc) - return dib7000p_pid_filter(adapter->fe, index, pid, onoff); - return dib7000m_pid_filter(adapter->fe, index, pid, onoff); -} - -static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) -{ - struct dib0700_state *st = adapter->dev->priv; - if (st->is_dib7000pc) - return dib7000p_pid_filter_ctrl(adapter->fe, onoff); - return dib7000m_pid_filter_ctrl(adapter->fe, onoff); -} - -static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) -{ - return dib7000p_pid_filter(adapter->fe, index, pid, onoff); -} - -static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) -{ - return dib7000p_pid_filter_ctrl(adapter->fe, onoff); -} - -static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { - 60000, 15000, - 1, 20, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (524 << 0), - (0 << 25) | 0, - 20452225, - 12000000, -}; - -static struct dib7000p_config dib7070p_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, -}; - -/* STK7070P */ -static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct usb_device_descriptor *p = &adap->dev->udev->descriptor; - if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && - p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - else - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &dib7070p_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, - &dib7070p_dib7000p_config); - return adap->fe == NULL ? -ENODEV : 0; -} - -/* STK7770P */ -static struct dib7000p_config dib7770p_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .enable_current_mirror = 1, - .disable_sample_and_hold = 0, -}; - -static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct usb_device_descriptor *p = &adap->dev->udev->descriptor; - if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && - p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - else - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &dib7770p_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, - &dib7770p_dib7000p_config); - return adap->fe == NULL ? -ENODEV : 0; -} - -/* DIB807x generic */ -static struct dibx000_agc_config dib807x_agc_config[2] = { - { - BAND_VHF, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, - * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, - * P_agc_inv_pwm2=0,P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, - * P_agc_write=0 */ - (0 << 15) | (0 << 14) | (7 << 11) | (0 << 10) | (0 << 9) | - (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | - (0 << 0), /* setup*/ - - 600, /* inv_gain*/ - 10, /* time_stabiliz*/ - - 0, /* alpha_level*/ - 118, /* thlock*/ - - 0, /* wbd_inv*/ - 3530, /* wbd_ref*/ - 1, /* wbd_sel*/ - 5, /* wbd_alpha*/ - - 65535, /* agc1_max*/ - 0, /* agc1_min*/ - - 65535, /* agc2_max*/ - 0, /* agc2_min*/ - - 0, /* agc1_pt1*/ - 40, /* agc1_pt2*/ - 183, /* agc1_pt3*/ - 206, /* agc1_slope1*/ - 255, /* agc1_slope2*/ - 72, /* agc2_pt1*/ - 152, /* agc2_pt2*/ - 88, /* agc2_slope1*/ - 90, /* agc2_slope2*/ - - 17, /* alpha_mant*/ - 27, /* alpha_exp*/ - 23, /* beta_mant*/ - 51, /* beta_exp*/ - - 0, /* perform_agc_softsplit*/ - }, { - BAND_UHF, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, - * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, - * P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, - * P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (0 << 10) | (0 << 9) | - (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | - (0 << 0), /* setup */ - - 600, /* inv_gain*/ - 10, /* time_stabiliz*/ - - 0, /* alpha_level*/ - 118, /* thlock*/ - - 0, /* wbd_inv*/ - 3530, /* wbd_ref*/ - 1, /* wbd_sel*/ - 5, /* wbd_alpha*/ - - 65535, /* agc1_max*/ - 0, /* agc1_min*/ - - 65535, /* agc2_max*/ - 0, /* agc2_min*/ - - 0, /* agc1_pt1*/ - 40, /* agc1_pt2*/ - 183, /* agc1_pt3*/ - 206, /* agc1_slope1*/ - 255, /* agc1_slope2*/ - 72, /* agc2_pt1*/ - 152, /* agc2_pt2*/ - 88, /* agc2_slope1*/ - 90, /* agc2_slope2*/ - - 17, /* alpha_mant*/ - 27, /* alpha_exp*/ - 23, /* beta_mant*/ - 51, /* beta_exp*/ - - 0, /* perform_agc_softsplit*/ - } -}; - -static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = { - 60000, 15000, /* internal, sampling*/ - 1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/ - 0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core, - ADClkSrc, modulo */ - (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/ - (0 << 25) | 0, /* ifreq = 0.000000 MHz*/ - 18179755, /* timf*/ - 12000000, /* xtal_hz*/ -}; - -static struct dib8000_config dib807x_dib8000_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 2, - .agc = dib807x_agc_config, - .pll = &dib807x_bw_config_12_mhz, - .tuner_is_baseband = 1, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .div_cfg = 1, - .agc_control = &dib0070_ctrl_agc_filter, - .output_mode = OUTMODE_MPEG2_FIFO, - .drives = 0x2d98, - }, { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 2, - .agc = dib807x_agc_config, - .pll = &dib807x_bw_config_12_mhz, - .tuner_is_baseband = 1, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .agc_control = &dib0070_ctrl_agc_filter, - .output_mode = OUTMODE_MPEG2_FIFO, - .drives = 0x2d98, - } -}; - -static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff) -{ - return dib8000_set_gpio(fe, 5, 0, !onoff); -} - -static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - return dib8000_set_gpio(fe, 0, 0, onoff); -} - -static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = { - { 240, 7}, - { 0xffff, 6}, -}; - -static struct dib0070_config dib807x_dib0070_config[2] = { - { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib80xx_tuner_reset, - .sleep = dib80xx_tuner_sleep, - .clock_khz = 12000, - .clock_pad_drive = 4, - .vga_filter = 1, - .force_crystal_mode = 1, - .enable_third_order_filter = 1, - .charge_pump = 0, - .wbd_gain = dib8070_wbd_gain_cfg, - .osc_buffer_state = 0, - .freq_offset_khz_uhf = -100, - .freq_offset_khz_vhf = -100, - }, { - .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib80xx_tuner_reset, - .sleep = dib80xx_tuner_sleep, - .clock_khz = 12000, - .clock_pad_drive = 2, - .vga_filter = 1, - .force_crystal_mode = 1, - .enable_third_order_filter = 1, - .charge_pump = 0, - .wbd_gain = dib8070_wbd_gain_cfg, - .osc_buffer_state = 0, - .freq_offset_khz_uhf = -25, - .freq_offset_khz_vhf = -25, - } -}; - -static int dib807x_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - - u16 offset = dib0070_wbd_offset(fe); - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); - switch (band) { - case BAND_VHF: - offset += 750; - break; - case BAND_UHF: /* fall-thru wanted */ - default: - offset += 250; break; - } - deb_info("WBD for DiB8000: %d\n", offset); - dib8000_set_wbd_ref(fe, offset); - - return state->set_param_save(fe, fep); -} - -static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, - DIBX000_I2C_INTERFACE_TUNER, 1); - - if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, - &dib807x_dib0070_config[0]) == NULL) - return -ENODEV; - } else { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, - &dib807x_dib0070_config[1]) == NULL) - return -ENODEV; - } - - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib807x_set_param_override; - return 0; -} - -static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, - u16 pid, int onoff) -{ - return dib8000_pid_filter(adapter->fe, index, pid, onoff); -} - -static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, - int onoff) -{ - return dib8000_pid_filter_ctrl(adapter->fe, onoff); -} - -/* STK807x */ -static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - 0x80); - - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, - &dib807x_dib8000_config[0]); - - return adap->fe == NULL ? -ENODEV : 0; -} - -/* STK807xPVR */ -static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(500); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - /* initialize IC 0 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); - - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, - &dib807x_dib8000_config[0]); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) -{ - /* initialize IC 1 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); - - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, - &dib807x_dib8000_config[1]); - - return adap->fe == NULL ? -ENODEV : 0; -} - -/* STK8096GP */ -struct dibx000_agc_config dib8090_agc_config[2] = { - { - BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - 787, - 10, - - 0, - 118, - - 0, - 3530, - 1, - 5, - - 65535, - 0, - - 65535, - 0, - - 0, - 32, - 114, - 143, - 144, - 114, - 227, - 116, - 117, - - 28, - 26, - 31, - 51, - - 0, - }, - { - BAND_CBAND, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - 787, - 10, - - 0, - 118, - - 0, - 3530, - 1, - 5, - - 0, - 0, - - 65535, - 0, - - 0, - 32, - 114, - 143, - 144, - 114, - 227, - 116, - 117, - - 28, - 26, - 31, - 51, - - 0, - } -}; - -static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = { - 54000, 13500, - 1, 18, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (599 << 0), - (0 << 25) | 0, - 20199727, - 12000000, -}; - -static int dib8090_get_adc_power(struct dvb_frontend *fe) -{ - return dib8000_get_adc_power(fe, 1); -} - -static struct dib8000_config dib809x_dib8000_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 2, - .agc = dib8090_agc_config, - .agc_control = dib0090_dcc_freq, - .pll = &dib8090_pll_config_12mhz, - .tuner_is_baseband = 1, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .div_cfg = 0x31, - .output_mode = OUTMODE_MPEG2_FIFO, - .drives = 0x2d98, - .diversity_delay = 48, - .refclksel = 3, - }, { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 2, - .agc = dib8090_agc_config, - .agc_control = dib0090_dcc_freq, - .pll = &dib8090_pll_config_12mhz, - .tuner_is_baseband = 1, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .div_cfg = 0x31, - .output_mode = OUTMODE_DIVERSITY, - .drives = 0x2d08, - .diversity_delay = 1, - .refclksel = 3, - } -}; - -static struct dib0090_wbd_slope dib8090_wbd_table[] = { - /* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */ - { 120, 0, 500, 0, 500, 4 }, /* CBAND */ - { 170, 0, 450, 0, 450, 4 }, /* CBAND */ - { 380, 48, 373, 28, 259, 6 }, /* VHF */ - { 860, 34, 700, 36, 616, 6 }, /* high UHF */ - { 0xFFFF, 34, 700, 36, 616, 6 }, /* default */ -}; - -static struct dib0090_config dib809x_dib0090_config = { - .io.pll_bypass = 1, - .io.pll_range = 1, - .io.pll_prediv = 1, - .io.pll_loopdiv = 20, - .io.adc_clock_ratio = 8, - .io.pll_int_loop_filt = 0, - .io.clock_khz = 12000, - .reset = dib80xx_tuner_reset, - .sleep = dib80xx_tuner_sleep, - .clkouttobamse = 1, - .analog_output = 1, - .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS, - .use_pwm_agc = 1, - .clkoutdrive = 1, - .get_adc_power = dib8090_get_adc_power, - .freq_offset_khz_uhf = -63, - .freq_offset_khz_vhf = -143, - .wbd = dib8090_wbd_table, - .fref_clock_ratio = 6, -}; - -static int dib8096_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); - u16 target; - int ret = 0; - enum frontend_tune_state tune_state = CT_SHUTDOWN; - u16 ltgain, rf_gain_limit; - - ret = state->set_param_save(fe, fep); - if (ret < 0) - return ret; - - target = (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2; - dib8000_set_wbd_ref(fe, target); - - - if (band == BAND_CBAND) { - deb_info("tuning in CBAND - soft-AGC startup\n"); - dib0090_set_tune_state(fe, CT_AGC_START); - do { - ret = dib0090_gain_control(fe); - msleep(ret); - tune_state = dib0090_get_tune_state(fe); - if (tune_state == CT_AGC_STEP_0) - dib8000_set_gpio(fe, 6, 0, 1); - else if (tune_state == CT_AGC_STEP_1) { - dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); - if (rf_gain_limit == 0) - dib8000_set_gpio(fe, 6, 0, 0); - } - } while (tune_state < CT_AGC_STOP); - dib0090_pwm_gain_reset(fe); - dib8000_pwm_agc_reset(fe); - dib8000_set_tune_state(fe, CT_DEMOD_START); - } else { - deb_info("not tuning in CBAND - standard AGC startup\n"); - dib0090_pwm_gain_reset(fe); - } - - return 0; -} - -static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) - return -ENODEV; - - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; - return 0; -} - -static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); - - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c; - struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe, 1); - - if (fe_slave) { - tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL) - return -ENODEV; - fe_slave->dvb = adap->fe->dvb; - fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override; - } - tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) - return -ENODEV; - - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; - - return 0; -} - -static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe_slave; - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(1000); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80); - - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - if (adap->fe == NULL) - return -ENODEV; - - fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); - dib8000_set_slave_frontend(adap->fe, fe_slave); - - return fe_slave == NULL ? -ENODEV : 0; -} - -/* STK9090M */ -static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) -{ - return dib9000_fw_pid_filter(adapter->fe, index, pid, onoff); -} - -static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) -{ - return dib9000_fw_pid_filter_ctrl(adapter->fe, onoff); -} - -static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff) -{ - return dib9000_set_gpio(fe, 5, 0, !onoff); -} - -static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - return dib9000_set_gpio(fe, 0, 0, onoff); -} - -static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len) -{ - u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 }; - u8 rb[2]; - struct i2c_msg msg[2] = { - {.addr = 0x1e >> 1, .flags = 0, .buf = wb, .len = 2}, - {.addr = 0x1e >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2}, - }; - u8 index_data; - - dibx000_i2c_set_speed(i2c, 250); - - if (i2c_transfer(i2c, msg, 2) != 2) - return -EIO; - - switch (rb[0] << 8 | rb[1]) { - case 0: - deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n"); - return -EIO; - case 1: - deb_info("Found DiB0170 rev2"); - break; - case 2: - deb_info("Found DiB0190 rev2"); - break; - default: - deb_info("DiB01x0 not found"); - return -EIO; - } - - for (index_data = 0; index_data < len; index_data += 2) { - wb[2] = (data[index_data + 1] >> 8) & 0xff; - wb[3] = (data[index_data + 1]) & 0xff; - - if (data[index_data] == 0) { - wb[0] = (data[index_data] >> 8) & 0xff; - wb[1] = (data[index_data]) & 0xff; - msg[0].len = 2; - if (i2c_transfer(i2c, msg, 2) != 2) - return -EIO; - wb[2] |= rb[0]; - wb[3] |= rb[1] & ~(3 << 4); - } - - wb[0] = (data[index_data] >> 8)&0xff; - wb[1] = (data[index_data])&0xff; - msg[0].len = 4; - if (i2c_transfer(i2c, &msg[0], 1) != 1) - return -EIO; - } - return 0; -} - -static struct dib9000_config stk9090m_config = { - .output_mpeg2_in_188_bytes = 1, - .output_mode = OUTMODE_MPEG2_FIFO, - .vcxo_timer = 279620, - .timing_frequency = 20452225, - .demod_clock_khz = 60000, - .xtal_clock_khz = 30000, - .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), - .subband = { - 2, - { - { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */ - { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */ - { 0 }, - }, - }, - .gpio_function = { - { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, - { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, - }, -}; - -static struct dib9000_config nim9090md_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - .output_mode = OUTMODE_MPEG2_FIFO, - .vcxo_timer = 279620, - .timing_frequency = 20452225, - .demod_clock_khz = 60000, - .xtal_clock_khz = 30000, - .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), - }, { - .output_mpeg2_in_188_bytes = 1, - .output_mode = OUTMODE_DIVERSITY, - .vcxo_timer = 279620, - .timing_frequency = 20452225, - .demod_clock_khz = 60000, - .xtal_clock_khz = 30000, - .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), - .subband = { - 2, - { - { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */ - { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */ - { 0 }, - }, - }, - .gpio_function = { - { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, - { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, - }, - } -}; - -static struct dib0090_config dib9090_dib0090_config = { - .io.pll_bypass = 0, - .io.pll_range = 1, - .io.pll_prediv = 1, - .io.pll_loopdiv = 8, - .io.adc_clock_ratio = 8, - .io.pll_int_loop_filt = 0, - .io.clock_khz = 30000, - .reset = dib90x0_tuner_reset, - .sleep = dib90x0_tuner_sleep, - .clkouttobamse = 0, - .analog_output = 0, - .use_pwm_agc = 0, - .clkoutdrive = 0, - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, -}; - -static struct dib0090_config nim9090md_dib0090_config[2] = { - { - .io.pll_bypass = 0, - .io.pll_range = 1, - .io.pll_prediv = 1, - .io.pll_loopdiv = 8, - .io.adc_clock_ratio = 8, - .io.pll_int_loop_filt = 0, - .io.clock_khz = 30000, - .reset = dib90x0_tuner_reset, - .sleep = dib90x0_tuner_sleep, - .clkouttobamse = 1, - .analog_output = 0, - .use_pwm_agc = 0, - .clkoutdrive = 0, - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, - }, { - .io.pll_bypass = 0, - .io.pll_range = 1, - .io.pll_prediv = 1, - .io.pll_loopdiv = 8, - .io.adc_clock_ratio = 8, - .io.pll_int_loop_filt = 0, - .io.clock_khz = 30000, - .reset = dib90x0_tuner_reset, - .sleep = dib90x0_tuner_sleep, - .clkouttobamse = 0, - .analog_output = 0, - .use_pwm_agc = 0, - .clkoutdrive = 0, - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, - } -}; - - -static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *state = adap->priv; - struct dib0700_state *st = adap->dev->priv; - u32 fw_version; - - /* Make use of the new i2c functions from FW 1.20 */ - dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); - if (fw_version >= 0x10200) - st->fw_use_new_i2c_api = 1; - dib0700_set_i2c_speed(adap->dev, 340); - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80); - - if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { - deb_info("%s: Upload failed. (file not found?)\n", __func__); - return -ENODEV; - } else { - deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); - } - stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size; - stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data; - - adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *state = adap->priv; - struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe); - u16 data_dib190[10] = { - 1, 0x1374, - 2, 0x01a2, - 7, 0x0020, - 0, 0x00ef, - 8, 0x0486, - }; - - if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &dib9090_dib0090_config) == NULL) - return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); - if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) - return -ENODEV; - dib0700_set_i2c_speed(adap->dev, 2000); - if (dib9000_firmware_post_pll_init(adap->fe) < 0) - return -ENODEV; - release_firmware(state->frontend_firmware); - return 0; -} - -static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *state = adap->priv; - struct dib0700_state *st = adap->dev->priv; - struct i2c_adapter *i2c; - struct dvb_frontend *fe_slave; - u32 fw_version; - - /* Make use of the new i2c functions from FW 1.20 */ - dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); - if (fw_version >= 0x10200) - st->fw_use_new_i2c_api = 1; - dib0700_set_i2c_speed(adap->dev, 340); - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { - deb_info("%s: Upload failed. (file not found?)\n", __func__); - return -EIO; - } else { - deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); - } - nim9090md_config[0].microcode_B_fe_size = state->frontend_firmware->size; - nim9090md_config[0].microcode_B_fe_buffer = state->frontend_firmware->data; - nim9090md_config[1].microcode_B_fe_size = state->frontend_firmware->size; - nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data; - - dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80); - adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); - - if (adap->fe == NULL) - return -ENODEV; - - i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0); - dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82); - - fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]); - dib9000_set_slave_frontend(adap->fe, fe_slave); - - return fe_slave == NULL ? -ENODEV : 0; -} - -static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *state = adap->priv; - struct i2c_adapter *i2c; - struct dvb_frontend *fe_slave; - u16 data_dib190[10] = { - 1, 0x5374, - 2, 0x01ae, - 7, 0x0020, - 0, 0x00ef, - 8, 0x0406, - }; - i2c = dib9000_get_tuner_interface(adap->fe); - if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &nim9090md_dib0090_config[0]) == NULL) - return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); - if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) - return -ENODEV; - dib0700_set_i2c_speed(adap->dev, 2000); - if (dib9000_firmware_post_pll_init(adap->fe) < 0) - return -ENODEV; - - fe_slave = dib9000_get_slave_frontend(adap->fe, 1); - if (fe_slave != NULL) { - i2c = dib9000_get_component_bus_interface(adap->fe); - dib9000_set_i2c_adapter(fe_slave, i2c); - - i2c = dib9000_get_tuner_interface(fe_slave); - if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) - return -ENODEV; - fe_slave->dvb = adap->fe->dvb; - dib9000_fw_set_component_bus_speed(adap->fe, 2000); - if (dib9000_firmware_post_pll_init(fe_slave) < 0) - return -ENODEV; - } - release_firmware(state->frontend_firmware); - - return 0; -} - -/* NIM7090 */ -struct dib7090p_best_adc { - u32 timf; - u32 pll_loopdiv; - u32 pll_prediv; -}; - -static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc) -{ - u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1; - - u16 xtal = 12000; - u32 fcp_min = 1900; /* PLL Minimum Frequency comparator KHz */ - u32 fcp_max = 20000; /* PLL Maximum Frequency comparator KHz */ - u32 fdem_max = 76000; - u32 fdem_min = 69500; - u32 fcp = 0, fs = 0, fdem = 0; - u32 harmonic_id = 0; - - adc->pll_loopdiv = loopdiv; - adc->pll_prediv = prediv; - adc->timf = 0; - - deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min); - - /* Find Min and Max prediv */ - while ((xtal/max_prediv) >= fcp_min) - max_prediv++; - - max_prediv--; - min_prediv = max_prediv; - while ((xtal/min_prediv) <= fcp_max) { - min_prediv--; - if (min_prediv == 1) - break; - } - deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv); - - min_prediv = 2; - - for (prediv = min_prediv ; prediv < max_prediv; prediv++) { - fcp = xtal / prediv; - if (fcp > fcp_min && fcp < fcp_max) { - for (loopdiv = 1 ; loopdiv < 64 ; loopdiv++) { - fdem = ((xtal/prediv) * loopdiv); - fs = fdem / 4; - /* test min/max system restrictions */ - - if ((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) { - spur = 0; - /* test fs harmonics positions */ - for (harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ; harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) { - if (((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) && ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) { - spur = 1; - break; - } - } - - if (!spur) { - adc->pll_loopdiv = loopdiv; - adc->pll_prediv = prediv; - adc->timf = 2396745143UL/fdem*(1 << 9); - adc->timf += ((2396745143UL%fdem) << 9)/fdem; - deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf); - break; - } - } - } - } - if (!spur) - break; - } - - - if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0) - return -EINVAL; - else - return 0; -} - -static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - struct dibx000_bandwidth_config pll; - u16 target; - struct dib7090p_best_adc adc; - int ret; - - ret = state->set_param_save(fe, fep); - if (ret < 0) - return ret; - - memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); - dib0090_pwm_gain_reset(fe); - target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2; - dib7000p_set_wbd_ref(fe, target); - - if (dib7090p_get_best_sampling(fe, &adc) == 0) { - pll.pll_ratio = adc.pll_loopdiv; - pll.pll_prediv = adc.pll_prediv; - - dib7000p_update_pll(fe, &pll); - dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); - } - return 0; -} - -static struct dib0090_wbd_slope dib7090_wbd_table[] = { - { 380, 81, 850, 64, 540, 4}, - { 860, 51, 866, 21, 375, 4}, - {1700, 0, 250, 0, 100, 6}, - {2600, 0, 250, 0, 100, 6}, - { 0xFFFF, 0, 0, 0, 0, 0}, -}; - -struct dibx000_agc_config dib7090_agc_config[2] = { - { - .band_caps = BAND_UHF, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - .inv_gain = 687, - .time_stabiliz = 10, - - .alpha_level = 0, - .thlock = 118, - - .wbd_inv = 0, - .wbd_ref = 1200, - .wbd_sel = 3, - .wbd_alpha = 5, - - .agc1_max = 65535, - .agc1_min = 0, - - .agc2_max = 65535, - .agc2_min = 0, - - .agc1_pt1 = 0, - .agc1_pt2 = 32, - .agc1_pt3 = 114, - .agc1_slope1 = 143, - .agc1_slope2 = 144, - .agc2_pt1 = 114, - .agc2_pt2 = 227, - .agc2_slope1 = 116, - .agc2_slope2 = 117, - - .alpha_mant = 18, - .alpha_exp = 0, - .beta_mant = 20, - .beta_exp = 59, - - .perform_agc_softsplit = 0, - } , { - .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - .inv_gain = 732, - .time_stabiliz = 10, - - .alpha_level = 0, - .thlock = 118, - - .wbd_inv = 0, - .wbd_ref = 1200, - .wbd_sel = 3, - .wbd_alpha = 5, - - .agc1_max = 65535, - .agc1_min = 0, - - .agc2_max = 65535, - .agc2_min = 0, - - .agc1_pt1 = 0, - .agc1_pt2 = 0, - .agc1_pt3 = 98, - .agc1_slope1 = 0, - .agc1_slope2 = 167, - .agc1_pt1 = 98, - .agc2_pt2 = 255, - .agc2_slope1 = 104, - .agc2_slope2 = 0, - - .alpha_mant = 18, - .alpha_exp = 0, - .beta_mant = 20, - .beta_exp = 59, - - .perform_agc_softsplit = 0, - } -}; - -static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = { - 60000, 15000, - 1, 5, 0, 0, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (524 << 0), - (0 << 25) | 0, - 20452225, - 15000000, -}; - -static struct dib7000p_config nim7090_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - .update_lna = NULL, - - .agc_config_count = 2, - .agc = dib7090_agc_config, - - .bw = &dib7090_clock_config_12_mhz, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - - .agc_control = dib7090_agc_restart, - - .spur_protect = 0, - .disable_sample_and_hold = 0, - .enable_current_mirror = 0, - .diversity_delay = 0, - - .output_mode = OUTMODE_MPEG2_FIFO, - .enMpegOutput = 1, -}; - -static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - .update_lna = NULL, - - .agc_config_count = 2, - .agc = dib7090_agc_config, - - .bw = &dib7090_clock_config_12_mhz, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - - .agc_control = dib7090_agc_restart, - - .spur_protect = 0, - .disable_sample_and_hold = 0, - .enable_current_mirror = 0, - .diversity_delay = 0, - - .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, - .default_i2c_addr = 0x90, - .enMpegOutput = 1, - }, { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - .update_lna = NULL, - - .agc_config_count = 2, - .agc = dib7090_agc_config, - - .bw = &dib7090_clock_config_12_mhz, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - - .agc_control = dib7090_agc_restart, - - .spur_protect = 0, - .disable_sample_and_hold = 0, - .enable_current_mirror = 0, - .diversity_delay = 0, - - .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, - .default_i2c_addr = 0x92, - .enMpegOutput = 0, - } -}; - -static const struct dib0090_config nim7090_dib0090_config = { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, - - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, - - .get_adc_power = dib7090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 0, - - .wbd = dib7090_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, -}; - -static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { - { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, - - .freq_offset_khz_uhf = 50, - .freq_offset_khz_vhf = 70, - - .get_adc_power = dib7090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 0, - - .wbd = dib7090_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, - }, { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, - - .freq_offset_khz_uhf = -50, - .freq_offset_khz_vhf = -70, - - .get_adc_power = dib7090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 0, - - .wbd = dib7090_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, - } -}; - -static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); - - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &nim7090_dib0090_config) == NULL) - return -ENODEV; - - dib7000p_set_gpio(adap->fe, 8, 0, 1); - - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; - return 0; -} - -static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - - /* The TFE7090 requires the dib0700 to not be in master mode */ - st->disable_streaming_master_mode = 1; - - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - /* initialize IC 0 */ - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - - dib0700_set_i2c_speed(adap->dev, 340); - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - - dib7090_slave_reset(adap->fe); - - if (adap->fe == NULL) - return -ENODEV; - - return 0; -} - -static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) -{ - struct i2c_adapter *i2c; - - if (adap->dev->adapter[0].fe == NULL) { - err("the master dib7090 has to be initialized first"); - return -ENODEV; /* the master device has not been initialized */ - } - - i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); - if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); - return -ENODEV; - } - - adap->fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); - dib0700_set_i2c_speed(adap->dev, 200); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); - - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) - return -ENODEV; - - dib7000p_set_gpio(adap->fe, 8, 0, 1); - - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; - return 0; -} - -static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); - - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) - return -ENODEV; - - dib7000p_set_gpio(adap->fe, 8, 0, 1); - - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; - return 0; -} - -/* STK7070PD */ -static struct dib7000p_config stk7070pd_dib7000p_config[2] = { - { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - }, { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 1, - .agc = &dib7070_agc_config, - .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - } -}; - -static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - dib0700_ctrl_clock(adap->dev, 72, 1); - - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, - stk7070pd_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); - return adap->fe == NULL ? -ENODEV : 0; -} - -static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) -{ - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); - return adap->fe == NULL ? -ENODEV : 0; -} - -/* S5H1411 */ -static struct s5h1411_config pinnacle_801e_config = { - .output_mode = S5H1411_PARALLEL_OUTPUT, - .gpio = S5H1411_GPIO_OFF, - .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, - .qam_if = S5H1411_IF_44000, - .vsb_if = S5H1411_IF_44000, - .inversion = S5H1411_INVERSION_OFF, - .status_mode = S5H1411_DEMODLOCKING -}; - -/* Pinnacle PCTV HD Pro 801e GPIOs map: - GPIO0 - currently unknown - GPIO1 - xc5000 tuner reset - GPIO2 - CX25843 sleep - GPIO3 - currently unknown - GPIO4 - currently unknown - GPIO6 - currently unknown - GPIO7 - currently unknown - GPIO9 - currently unknown - GPIO10 - CX25843 reset - */ -static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - - /* Make use of the new i2c functions from FW 1.20 */ - st->fw_use_new_i2c_api = 1; - - /* The s5h1411 requires the dib0700 to not be in master mode */ - st->disable_streaming_master_mode = 1; - - /* All msleep values taken from Windows USB trace */ - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); - dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(400); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(60); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0); - msleep(30); - - /* Put the CX25843 to sleep for now since we're in digital mode */ - dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); - - /* GPIOs are initialized, do the attach */ - adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, - &adap->dev->i2c_adap); - return adap->fe == NULL ? -ENODEV : 0; -} - -static int dib0700_xc5000_tuner_callback(void *priv, int component, - int command, int arg) -{ - struct dvb_usb_adapter *adap = priv; - - if (command == XC5000_TUNER_RESET) { - /* Reset the tuner */ - dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); - msleep(10); - } else { - err("xc5000: unknown tuner callback command: %d\n", command); - return -EINVAL; - } - - return 0; -} - -static struct xc5000_config s5h1411_xc5000_tunerconfig = { - .i2c_address = 0x64, - .if_khz = 5380, -}; - -static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) -{ - /* FIXME: generalize & move to common area */ - adap->fe->callback = dib0700_xc5000_tuner_callback; - - return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, - &s5h1411_xc5000_tunerconfig) - == NULL ? -ENODEV : 0; -} - -static struct lgdt3305_config hcw_lgdt3305_config = { - .i2c_addr = 0x0e, - .mpeg_mode = LGDT3305_MPEG_PARALLEL, - .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, - .tpvalid_polarity = LGDT3305_TP_VALID_LOW, - .deny_i2c_rptr = 0, - .spectral_inversion = 1, - .qam_if_khz = 6000, - .vsb_if_khz = 6000, - .usref_8vsb = 0x0500, -}; - -static struct mxl5007t_config hcw_mxl5007t_config = { - .xtal_freq_hz = MxL_XTAL_25_MHZ, - .if_freq_hz = MxL_IF_6_MHZ, - .invert_if = 1, -}; - -/* TIGER-ATSC map: - GPIO0 - LNA_CTR (H: LNA power enabled, L: LNA power disabled) - GPIO1 - ANT_SEL (H: VPA, L: MCX) - GPIO4 - SCL2 - GPIO6 - EN_TUNER - GPIO7 - SDA2 - GPIO10 - DEM_RST - - MXL is behind LG's i2c repeater. LG is on SCL2/SDA2 gpios on the DIB - */ -static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_state *st = adap->dev->priv; - - /* Make use of the new i2c functions from FW 1.20 */ - st->fw_use_new_i2c_api = 1; - - st->disable_streaming_master_mode = 1; - - /* fe power enable */ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(30); - - /* demod reset */ - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(30); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(30); - - adap->fe = dvb_attach(lgdt3305_attach, - &hcw_lgdt3305_config, - &adap->dev->i2c_adap); - - return adap->fe == NULL ? -ENODEV : 0; -} - -static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(mxl5007t_attach, adap->fe, - &adap->dev->i2c_adap, 0x60, - &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; -} - - -/* DVB-USB and USB stuff follows */ -struct usb_device_id dib0700_usb_id_table[] = { -/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, -/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, - { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, - { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, - { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, -/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, - { USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, -/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, - { USB_DEVICE(USB_VID_PINNACLE, - USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, - { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, -/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, - { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, - { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, -/* 25 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_USB_XE) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_EXPRESSCARD_320CX) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV72E) }, -/* 30 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73E) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_EC372S) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) }, - { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, -/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, - { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, -/* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_EXPRESS) }, - { USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) }, - { USB_DEVICE(USB_VID_SONY, USB_PID_SONY_PLAYTV) }, -/* 45 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_PD378S) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) }, -/* 50 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_Dlx) }, - { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, -/* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, - { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV73ESE) }, - { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV282E) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, -/* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, - { USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x000, 0x3f00) }, - { USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) }, -/* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096GP) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DIVERSITY) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090M) }, -/* 70 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM8096MD) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090MD) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM7090) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) }, - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) }, - { 0 } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); - -#define DIB0700_DEFAULT_DEVICE_PROPERTIES \ - .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ - .usb_ctrl = DEVICE_SPECIFIC, \ - .firmware = "dvb-usb-dib0700-1.20.fw", \ - .download_firmware = dib0700_download_firmware, \ - .no_reconnect = 1, \ - .size_of_priv = sizeof(struct dib0700_state), \ - .i2c_algo = &dib0700_i2c_algo, \ - .identify_state = dib0700_identify_state - -#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \ - .streaming_ctrl = dib0700_streaming_ctrl, \ - .stream = { \ - .type = USB_BULK, \ - .count = 4, \ - .endpoint = ep, \ - .u = { \ - .bulk = { \ - .buffersize = 39480, \ - } \ - } \ - } - -struct dvb_usb_device_properties dib0700_devices[] = { - { - DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk7700p_pid_filter, - .pid_filter_ctrl = stk7700p_pid_filter_ctrl, - .frontend_attach = stk7700p_frontend_attach, - .tuner_attach = stk7700p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }, - }, - - .num_device_descs = 8, - .devices = { - { "DiBcom STK7700P reference design", - { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, - { NULL }, - }, - { "Hauppauge Nova-T Stick", - { &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL }, - { NULL }, - }, - { "AVerMedia AVerTV DVB-T Volar", - { &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] }, - { NULL }, - }, - { "Compro Videomate U500", - { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] }, - { NULL }, - }, - { "Uniwill STK7700P based (Hama and others)", - { &dib0700_usb_id_table[7], NULL }, - { NULL }, - }, - { "Leadtek Winfast DTV Dongle (STK7700P based)", - { &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] }, - { NULL }, - }, - { "AVerMedia AVerTV DVB-T Express", - { &dib0700_usb_id_table[20] }, - { NULL }, - }, - { "Gigabyte U7000", - { &dib0700_usb_id_table[21], NULL }, - { NULL }, - } - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 2, - .adapter = { - { - .frontend_attach = bristol_frontend_attach, - .tuner_attach = bristol_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }, { - .frontend_attach = bristol_frontend_attach, - .tuner_attach = bristol_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - } - }, - - .num_device_descs = 1, - .devices = { - { "Hauppauge Nova-T 500 Dual DVB-T", - { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 2, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7700d_frontend_attach, - .tuner_attach = stk7700d_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }, { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7700d_frontend_attach, - .tuner_attach = stk7700d_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - } - }, - - .num_device_descs = 5, - .devices = { - { "Pinnacle PCTV 2000e", - { &dib0700_usb_id_table[11], NULL }, - { NULL }, - }, - { "Terratec Cinergy DT XS Diversity", - { &dib0700_usb_id_table[12], NULL }, - { NULL }, - }, - { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity", - { &dib0700_usb_id_table[13], NULL }, - { NULL }, - }, - { "DiBcom STK7700D reference design", - { &dib0700_usb_id_table[14], NULL }, - { NULL }, - }, - { "YUAN High-Tech DiBcom STK7700D", - { &dib0700_usb_id_table[55], NULL }, - { NULL }, - }, - - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7700P2_frontend_attach, - .tuner_attach = stk7700d_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }, - }, - - .num_device_descs = 3, - .devices = { - { "ASUS My Cinema U3000 Mini DVBT Tuner", - { &dib0700_usb_id_table[23], NULL }, - { NULL }, - }, - { "Yuan EC372S", - { &dib0700_usb_id_table[31], NULL }, - { NULL }, - }, - { "Terratec Cinergy T Express", - { &dib0700_usb_id_table[42], NULL }, - { NULL }, - } - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070p_frontend_attach, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 11, - .devices = { - { "DiBcom STK7070P reference design", - { &dib0700_usb_id_table[15], NULL }, - { NULL }, - }, - { "Pinnacle PCTV DVB-T Flash Stick", - { &dib0700_usb_id_table[16], NULL }, - { NULL }, - }, - { "Artec T14BR DVB-T", - { &dib0700_usb_id_table[22], NULL }, - { NULL }, - }, - { "ASUS My Cinema U3100 Mini DVBT Tuner", - { &dib0700_usb_id_table[24], NULL }, - { NULL }, - }, - { "Hauppauge Nova-T Stick", - { &dib0700_usb_id_table[25], NULL }, - { NULL }, - }, - { "Hauppauge Nova-T MyTV.t", - { &dib0700_usb_id_table[26], NULL }, - { NULL }, - }, - { "Pinnacle PCTV 72e", - { &dib0700_usb_id_table[29], NULL }, - { NULL }, - }, - { "Pinnacle PCTV 73e", - { &dib0700_usb_id_table[30], NULL }, - { NULL }, - }, - { "Elgato EyeTV DTT", - { &dib0700_usb_id_table[49], NULL }, - { NULL }, - }, - { "Yuan PD378S", - { &dib0700_usb_id_table[45], NULL }, - { NULL }, - }, - { "Elgato EyeTV Dtt Dlx PD378S", - { &dib0700_usb_id_table[50], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070p_frontend_attach, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 3, - .devices = { - { "Pinnacle PCTV 73A", - { &dib0700_usb_id_table[56], NULL }, - { NULL }, - }, - { "Pinnacle PCTV 73e SE", - { &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL }, - { NULL }, - }, - { "Pinnacle PCTV 282e", - { &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 2, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070pd_frontend_attach0, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = sizeof(struct dib0700_adapter_state), - }, { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070pd_frontend_attach1, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - - .size_of_priv = sizeof(struct dib0700_adapter_state), - } - }, - - .num_device_descs = 6, - .devices = { - { "DiBcom STK7070PD reference design", - { &dib0700_usb_id_table[17], NULL }, - { NULL }, - }, - { "Pinnacle PCTV Dual DVB-T Diversity Stick", - { &dib0700_usb_id_table[18], NULL }, - { NULL }, - }, - { "Hauppauge Nova-TD Stick (52009)", - { &dib0700_usb_id_table[35], NULL }, - { NULL }, - }, - { "Hauppauge Nova-TD-500 (84xxx)", - { &dib0700_usb_id_table[36], NULL }, - { NULL }, - }, - { "Terratec Cinergy DT USB XS Diversity/ T5", - { &dib0700_usb_id_table[43], - &dib0700_usb_id_table[53], NULL}, - { NULL }, - }, - { "Sony PlayTV", - { &dib0700_usb_id_table[44], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 2, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070pd_frontend_attach0, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = sizeof(struct dib0700_adapter_state), - }, { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7070pd_frontend_attach1, - .tuner_attach = dib7070p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - - .size_of_priv = sizeof(struct dib0700_adapter_state), - } - }, - - .num_device_descs = 1, - .devices = { - { "Elgato EyeTV Diversity", - { &dib0700_usb_id_table[68], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_NEC_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7700ph_frontend_attach, - .tuner_attach = stk7700ph_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = sizeof(struct - dib0700_adapter_state), - }, - }, - - .num_device_descs = 9, - .devices = { - { "Terratec Cinergy HT USB XE", - { &dib0700_usb_id_table[27], NULL }, - { NULL }, - }, - { "Pinnacle Expresscard 320cx", - { &dib0700_usb_id_table[28], NULL }, - { NULL }, - }, - { "Terratec Cinergy HT Express", - { &dib0700_usb_id_table[32], NULL }, - { NULL }, - }, - { "Gigabyte U8000-RH", - { &dib0700_usb_id_table[37], NULL }, - { NULL }, - }, - { "YUAN High-Tech STK7700PH", - { &dib0700_usb_id_table[38], NULL }, - { NULL }, - }, - { "Asus My Cinema-U3000Hybrid", - { &dib0700_usb_id_table[39], NULL }, - { NULL }, - }, - { "YUAN High-Tech MC770", - { &dib0700_usb_id_table[48], NULL }, - { NULL }, - }, - { "Leadtek WinFast DTV Dongle H", - { &dib0700_usb_id_table[51], NULL }, - { NULL }, - }, - { "YUAN High-Tech STK7700D", - { &dib0700_usb_id_table[54], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .frontend_attach = s5h1411_frontend_attach, - .tuner_attach = xc5000_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = sizeof(struct - dib0700_adapter_state), - }, - }, - - .num_device_descs = 2, - .devices = { - { "Pinnacle PCTV HD Pro USB Stick", - { &dib0700_usb_id_table[40], NULL }, - { NULL }, - }, - { "Pinnacle PCTV HD USB Stick", - { &dib0700_usb_id_table[41], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .frontend_attach = lgdt3305_frontend_attach, - .tuner_attach = mxl5007t_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = sizeof(struct - dib0700_adapter_state), - }, - }, - - .num_device_descs = 2, - .devices = { - { "Hauppauge ATSC MiniCard (B200)", - { &dib0700_usb_id_table[46], NULL }, - { NULL }, - }, - { "Hauppauge ATSC MiniCard (B210)", - { &dib0700_usb_id_table[47], NULL }, - { NULL }, - }, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = stk7770p_frontend_attach, - .tuner_attach = dib7770p_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 3, - .devices = { - { "DiBcom STK7770P reference design", - { &dib0700_usb_id_table[59], NULL }, - { NULL }, - }, - { "Terratec Cinergy T USB XXS (HD)/ T3", - { &dib0700_usb_id_table[33], - &dib0700_usb_id_table[52], - &dib0700_usb_id_table[60], NULL}, - { NULL }, - }, - { "TechniSat AirStar TeleStick 2", - { &dib0700_usb_id_table[74], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = stk807x_frontend_attach, - .tuner_attach = dib807x_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 3, - .devices = { - { "DiBcom STK807xP reference design", - { &dib0700_usb_id_table[62], NULL }, - { NULL }, - }, - { "Prolink Pixelview SBTVD", - { &dib0700_usb_id_table[63], NULL }, - { NULL }, - }, - { "EvolutePC TVWay+", - { &dib0700_usb_id_table[64], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_NEC_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 2, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = stk807xpvr_frontend_attach0, - .tuner_attach = dib807x_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = stk807xpvr_frontend_attach1, - .tuner_attach = dib807x_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom STK807xPVR reference design", - { &dib0700_usb_id_table[61], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = stk809x_frontend_attach, - .tuner_attach = dib809x_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom STK8096GP reference design", - { &dib0700_usb_id_table[67], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = dib90x0_pid_filter, - .pid_filter_ctrl = dib90x0_pid_filter_ctrl, - .frontend_attach = stk9090m_frontend_attach, - .tuner_attach = dib9090_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom STK9090M reference design", - { &dib0700_usb_id_table[69], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk80xx_pid_filter, - .pid_filter_ctrl = stk80xx_pid_filter_ctrl, - .frontend_attach = nim8096md_frontend_attach, - .tuner_attach = nim8096md_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom NIM8096MD reference design", - { &dib0700_usb_id_table[70], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = dib90x0_pid_filter, - .pid_filter_ctrl = dib90x0_pid_filter_ctrl, - .frontend_attach = nim9090md_frontend_attach, - .tuner_attach = nim9090md_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom NIM9090MD reference design", - { &dib0700_usb_id_table[71], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = nim7090_frontend_attach, - .tuner_attach = nim7090_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom NIM7090 reference design", - { &dib0700_usb_id_table[72], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 2, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = tfe7090pvr_frontend0_attach, - .tuner_attach = tfe7090pvr_tuner0_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = tfe7090pvr_frontend1_attach, - .tuner_attach = tfe7090pvr_tuner1_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom TFE7090PVR reference design", - { &dib0700_usb_id_table[73], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, -}; - -int dib0700_device_count = ARRAY_SIZE(dib0700_devices); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib0700.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/* Linux driver for devices based on the DiBcom DiB0700 USB bridge - * - * 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, version 2. - * - * Copyright (C) 2005-6 DiBcom, SA - */ -#ifndef _DIB0700_H_ -#define _DIB0700_H_ - -#define DVB_USB_LOG_PREFIX "dib0700" -#include "dvb-usb.h" - -#include "dib07x0.h" - -extern int dvb_usb_dib0700_debug; -#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args) -#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args) -#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) -#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) - -#define REQUEST_SET_USB_XFER_LEN 0x0 /* valid only for firmware version */ - /* higher than 1.21 */ -#define REQUEST_I2C_READ 0x2 -#define REQUEST_I2C_WRITE 0x3 -#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ -#define REQUEST_JUMPRAM 0x8 -#define REQUEST_SET_CLOCK 0xB -#define REQUEST_SET_GPIO 0xC -#define REQUEST_ENABLE_VIDEO 0xF - // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) - // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) - // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) -#define REQUEST_SET_I2C_PARAM 0x10 -#define REQUEST_SET_RC 0x11 -#define REQUEST_NEW_I2C_READ 0x12 -#define REQUEST_NEW_I2C_WRITE 0x13 -#define REQUEST_GET_VERSION 0x15 - -struct dib0700_state { - u8 channel_state; - u16 mt2060_if1[2]; - u8 rc_toggle; - u8 rc_counter; - u8 is_dib7000pc; - u8 fw_use_new_i2c_api; - u8 disable_streaming_master_mode; - u32 fw_version; - u32 nb_packet_buffer_size; -}; - -extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, - u32 *romversion, u32 *ramversion, u32 *fwtype); -extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); -extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); -extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); -extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); -extern int dib0700_rc_setup(struct dvb_usb_device *d); -extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); -extern struct i2c_algorithm dib0700_i2c_algo; -extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold); -extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type); -extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz); - -extern int dib0700_device_count; -extern int dvb_usb_dib0700_ir_proto; -extern struct dvb_usb_device_properties dib0700_devices[]; -extern struct usb_device_id dib0700_usb_id_table[]; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib07x0.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib07x0.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib07x0.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dib07x0.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -#ifndef _DIB07X0_H_ -#define _DIB07X0_H_ - -enum dib07x0_gpios { - GPIO0 = 0, - GPIO1 = 2, - GPIO2 = 3, - GPIO3 = 4, - GPIO4 = 5, - GPIO5 = 6, - GPIO6 = 8, - GPIO7 = 10, - GPIO8 = 11, - GPIO9 = 14, - GPIO10 = 15, -}; - -#define GPIO_IN 0 -#define GPIO_OUT 1 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-common.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,470 +0,0 @@ -/* Common methods for dibusb-based-receivers. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS); -MODULE_LICENSE("GPL"); - -#define deb_info(args...) dprintk(debug,0x01,args) - -/* common stuff used by the different dibusb modules */ -int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - if (st->ops.fifo_ctrl != NULL) - if (st->ops.fifo_ctrl(adap->fe,onoff)) { - err("error while controlling the fifo of the demod."); - return -ENODEV; - } - } - return 0; -} -EXPORT_SYMBOL(dibusb_streaming_ctrl); - -int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) -{ - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - if (st->ops.pid_ctrl != NULL) - st->ops.pid_ctrl(adap->fe,index,pid,onoff); - } - return 0; -} -EXPORT_SYMBOL(dibusb_pid_filter); - -int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - if (st->ops.pid_parse != NULL) - if (st->ops.pid_parse(adap->fe,onoff) < 0) - err("could not handle pid_parser"); - } - return 0; -} -EXPORT_SYMBOL(dibusb_pid_filter_ctrl); - -int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b[3]; - int ret; - b[0] = DIBUSB_REQ_SET_IOCTL; - b[1] = DIBUSB_IOCTL_CMD_POWER_MODE; - b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP; - ret = dvb_usb_generic_write(d,b,3); - msleep(10); - return ret; -} -EXPORT_SYMBOL(dibusb_power_ctrl); - -int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - u8 b[3] = { 0 }; - int ret; - - if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0) - return ret; - - if (onoff) { - b[0] = DIBUSB_REQ_SET_STREAMING_MODE; - b[1] = 0x00; - if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0) - return ret; - } - - b[0] = DIBUSB_REQ_SET_IOCTL; - b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; - return dvb_usb_generic_write(adap->dev,b,3); -} -EXPORT_SYMBOL(dibusb2_0_streaming_ctrl); - -int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - if (onoff) { - u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP }; - return dvb_usb_generic_write(d,b,3); - } else - return 0; -} -EXPORT_SYMBOL(dibusb2_0_power_ctrl); - -static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ - /* write only ? */ - int wo = (rbuf == NULL || rlen == 0), - len = 2 + wlen + (wo ? 0 : 2); - - sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; - sndbuf[1] = (addr << 1) | (wo ? 0 : 1); - - memcpy(&sndbuf[2],wbuf,wlen); - - if (!wo) { - sndbuf[wlen+2] = (rlen >> 8) & 0xff; - sndbuf[wlen+3] = rlen & 0xff; - } - - return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0); -} - -/* - * I2C master xfer function - */ -static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0 - && (msg[i+1].flags & I2C_M_RD)) { - if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len, - msg[i+1].buf,msg[i+1].len) < 0) - break; - i++; - } else if ((msg[i].flags & I2C_M_RD) == 0) { - if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) - break; - } else if (msg[i].addr != 0x50) { - /* 0x50 is the address of the eeprom - we need to protect it - * from dibusb's bad i2c implementation: reads without - * writing the offset before are forbidden */ - if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0) - break; - } - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 dibusb_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -struct i2c_algorithm dibusb_i2c_algo = { - .master_xfer = dibusb_i2c_xfer, - .functionality = dibusb_i2c_func, -}; -EXPORT_SYMBOL(dibusb_i2c_algo); - -int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) -{ - u8 wbuf[1] = { offs }; - return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1); -} -EXPORT_SYMBOL(dibusb_read_eeprom_byte); - -/* 3000MC/P stuff */ -// Config Adjacent channels Perf -cal22 -static struct dibx000_agc_config dib3000p_mt2060_agc_config = { - .band_caps = BAND_VHF | BAND_UHF, - .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), - - .agc1_max = 48497, - .agc1_min = 23593, - .agc2_max = 46531, - .agc2_min = 24904, - - .agc1_pt1 = 0x65, - .agc1_pt2 = 0x69, - - .agc1_slope1 = 0x51, - .agc1_slope2 = 0x27, - - .agc2_pt1 = 0, - .agc2_pt2 = 0x33, - - .agc2_slope1 = 0x35, - .agc2_slope2 = 0x37, -}; - -static struct dib3000mc_config stk3000p_dib3000p_config = { - &dib3000p_mt2060_agc_config, - - .max_time = 0x196, - .ln_adc_level = 0x1cc7, - - .output_mpeg2_in_188_bytes = 1, - - .agc_command1 = 1, - .agc_command2 = 1, -}; - -static struct dibx000_agc_config dib3000p_panasonic_agc_config = { - .band_caps = BAND_VHF | BAND_UHF, - .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), - - .agc1_max = 56361, - .agc1_min = 22282, - .agc2_max = 47841, - .agc2_min = 36045, - - .agc1_pt1 = 0x3b, - .agc1_pt2 = 0x6b, - - .agc1_slope1 = 0x55, - .agc1_slope2 = 0x1d, - - .agc2_pt1 = 0, - .agc2_pt2 = 0x0a, - - .agc2_slope1 = 0x95, - .agc2_slope2 = 0x1e, -}; - -#if defined(CONFIG_DVB_DIB3000MC) || \ - (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE)) - -static struct dib3000mc_config mod3000p_dib3000p_config = { - &dib3000p_panasonic_agc_config, - - .max_time = 0x51, - .ln_adc_level = 0x1cc7, - - .output_mpeg2_in_188_bytes = 1, - - .agc_command1 = 1, - .agc_command2 = 1, -}; - -int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && - adap->dev->udev->descriptor.idProduct == - USB_PID_LITEON_DVB_T_WARM) { - msleep(1000); - } - - if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || - (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - st->ops.pid_parse = dib3000mc_pid_parse; - st->ops.pid_ctrl = dib3000mc_pid_control; - } - return 0; - } - return -ENODEV; -} -EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); - -static struct mt2060_config stk3000p_mt2060_config = { - 0x60 -}; - -int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dibusb_state *st = adap->priv; - u8 a,b; - u16 if1 = 1220; - struct i2c_adapter *tun_i2c; - - // First IF calibration for Liteon Sticks - if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && - adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) { - - dibusb_read_eeprom_byte(adap->dev,0x7E,&a); - dibusb_read_eeprom_byte(adap->dev,0x7F,&b); - - if (a == 0x00) - if1 += b; - else if (a == 0x80) - if1 -= b; - else - warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); - - } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM && - adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) { - u8 desc; - dibusb_read_eeprom_byte(adap->dev, 7, &desc); - if (desc == 2) { - a = 127; - do { - dibusb_read_eeprom_byte(adap->dev, a, &desc); - a--; - } while (a > 7 && (desc == 0xff || desc == 0x00)); - if (desc & 0x80) - if1 -= (0xff - desc); - else - if1 += desc; - } - } - - tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); - if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { - /* not found - use panasonic pll parameters */ - if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) - return -ENOMEM; - } else { - st->mt2060_present = 1; - /* set the correct parameters for the dib3000p */ - dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config); - } - return 0; -} -EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); -#endif - -/* - * common remote control stuff - */ -struct rc_map_table rc_map_dibusb_table[] = { - /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */ - { 0x0016, KEY_POWER }, - { 0x0010, KEY_MUTE }, - { 0x0003, KEY_1 }, - { 0x0001, KEY_2 }, - { 0x0006, KEY_3 }, - { 0x0009, KEY_4 }, - { 0x001d, KEY_5 }, - { 0x001f, KEY_6 }, - { 0x000d, KEY_7 }, - { 0x0019, KEY_8 }, - { 0x001b, KEY_9 }, - { 0x0015, KEY_0 }, - { 0x0005, KEY_CHANNELUP }, - { 0x0002, KEY_CHANNELDOWN }, - { 0x001e, KEY_VOLUMEUP }, - { 0x000a, KEY_VOLUMEDOWN }, - { 0x0011, KEY_RECORD }, - { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */ - { 0x0014, KEY_PLAY }, - { 0x001a, KEY_STOP }, - { 0x0040, KEY_REWIND }, - { 0x0012, KEY_FASTFORWARD }, - { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */ - { 0x004c, KEY_PAUSE }, - { 0x004d, KEY_SCREEN }, /* Full screen mode. */ - { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ - /* additional keys TwinHan VisionPlus, the Artec seemingly not have */ - { 0x000c, KEY_CANCEL }, /* Cancel */ - { 0x001c, KEY_EPG }, /* EPG */ - { 0x0000, KEY_TAB }, /* Tab */ - { 0x0048, KEY_INFO }, /* Preview */ - { 0x0004, KEY_LIST }, /* RecordList */ - { 0x000f, KEY_TEXT }, /* Teletext */ - /* Key codes for the KWorld/ADSTech/JetWay remote. */ - { 0x8612, KEY_POWER }, - { 0x860f, KEY_SELECT }, /* source */ - { 0x860c, KEY_UNKNOWN }, /* scan */ - { 0x860b, KEY_EPG }, - { 0x8610, KEY_MUTE }, - { 0x8601, KEY_1 }, - { 0x8602, KEY_2 }, - { 0x8603, KEY_3 }, - { 0x8604, KEY_4 }, - { 0x8605, KEY_5 }, - { 0x8606, KEY_6 }, - { 0x8607, KEY_7 }, - { 0x8608, KEY_8 }, - { 0x8609, KEY_9 }, - { 0x860a, KEY_0 }, - { 0x8618, KEY_ZOOM }, - { 0x861c, KEY_UNKNOWN }, /* preview */ - { 0x8613, KEY_UNKNOWN }, /* snap */ - { 0x8600, KEY_UNDO }, - { 0x861d, KEY_RECORD }, - { 0x860d, KEY_STOP }, - { 0x860e, KEY_PAUSE }, - { 0x8616, KEY_PLAY }, - { 0x8611, KEY_BACK }, - { 0x8619, KEY_FORWARD }, - { 0x8614, KEY_UNKNOWN }, /* pip */ - { 0x8615, KEY_ESC }, - { 0x861a, KEY_UP }, - { 0x861e, KEY_DOWN }, - { 0x861f, KEY_LEFT }, - { 0x861b, KEY_RIGHT }, - - /* Key codes for the DiBcom MOD3000 remote. */ - { 0x8000, KEY_MUTE }, - { 0x8001, KEY_TEXT }, - { 0x8002, KEY_HOME }, - { 0x8003, KEY_POWER }, - - { 0x8004, KEY_RED }, - { 0x8005, KEY_GREEN }, - { 0x8006, KEY_YELLOW }, - { 0x8007, KEY_BLUE }, - - { 0x8008, KEY_DVD }, - { 0x8009, KEY_AUDIO }, - { 0x800a, KEY_MEDIA }, /* Pictures */ - { 0x800b, KEY_VIDEO }, - - { 0x800c, KEY_BACK }, - { 0x800d, KEY_UP }, - { 0x800e, KEY_RADIO }, - { 0x800f, KEY_EPG }, - - { 0x8010, KEY_LEFT }, - { 0x8011, KEY_OK }, - { 0x8012, KEY_RIGHT }, - { 0x8013, KEY_UNKNOWN }, /* SAP */ - - { 0x8014, KEY_TV }, - { 0x8015, KEY_DOWN }, - { 0x8016, KEY_MENU }, /* DVD Menu */ - { 0x8017, KEY_LAST }, - - { 0x8018, KEY_RECORD }, - { 0x8019, KEY_STOP }, - { 0x801a, KEY_PAUSE }, - { 0x801b, KEY_PLAY }, - - { 0x801c, KEY_PREVIOUS }, - { 0x801d, KEY_REWIND }, - { 0x801e, KEY_FASTFORWARD }, - { 0x801f, KEY_NEXT}, - - { 0x8040, KEY_1 }, - { 0x8041, KEY_2 }, - { 0x8042, KEY_3 }, - { 0x8043, KEY_CHANNELUP }, - - { 0x8044, KEY_4 }, - { 0x8045, KEY_5 }, - { 0x8046, KEY_6 }, - { 0x8047, KEY_CHANNELDOWN }, - - { 0x8048, KEY_7 }, - { 0x8049, KEY_8 }, - { 0x804a, KEY_9 }, - { 0x804b, KEY_VOLUMEUP }, - - { 0x804c, KEY_CLEAR }, - { 0x804d, KEY_0 }, - { 0x804e, KEY_ENTER }, - { 0x804f, KEY_VOLUMEDOWN }, -}; -EXPORT_SYMBOL(rc_map_dibusb_table); - -int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE; - dvb_usb_generic_rw(d,&cmd,1,key,5,0); - dvb_usb_nec_rc_key_to_event(d,key,event,state); - if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); - return 0; -} -EXPORT_SYMBOL(dibusb_rc_query); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -/* Header file for all dibusb-based-receivers. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_DIBUSB_H_ -#define _DVB_USB_DIBUSB_H_ - -#ifndef DVB_USB_LOG_PREFIX - #define DVB_USB_LOG_PREFIX "dibusb" -#endif -#include "dvb-usb.h" - -#include "dib3000.h" -#include "dib3000mc.h" -#include "mt2060.h" - -/* - * protocol of all dibusb related devices - */ - -/* - * bulk msg to/from endpoint 0x01 - * - * general structure: - * request_byte parameter_bytes - */ - -#define DIBUSB_REQ_START_READ 0x00 -#define DIBUSB_REQ_START_DEMOD 0x01 - -/* - * i2c read - * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word - * bulk read: byte_buffer (length_word bytes) - */ -#define DIBUSB_REQ_I2C_READ 0x02 - -/* - * i2c write - * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes - */ -#define DIBUSB_REQ_I2C_WRITE 0x03 - -/* - * polling the value of the remote control - * bulk write: 0x04 - * bulk read: byte_buffer (5 bytes) - */ -#define DIBUSB_REQ_POLL_REMOTE 0x04 - -/* additional status values for Hauppauge Remote Control Protocol */ -#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01 -#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03 - -/* streaming mode: - * bulk write: 0x05 mode_byte - * - * mode_byte is mostly 0x00 - */ -#define DIBUSB_REQ_SET_STREAMING_MODE 0x05 - -/* interrupt the internal read loop, when blocking */ -#define DIBUSB_REQ_INTR_READ 0x06 - -/* io control - * 0x07 cmd_byte param_bytes - * - * param_bytes can be up to 32 bytes - * - * cmd_byte function parameter name - * 0x00 power mode - * 0x00 sleep - * 0x01 wakeup - * - * 0x01 enable streaming - * 0x02 disable streaming - * - * - */ -#define DIBUSB_REQ_SET_IOCTL 0x07 - -/* IOCTL commands */ - -/* change the power mode in firmware */ -#define DIBUSB_IOCTL_CMD_POWER_MODE 0x00 -#define DIBUSB_IOCTL_POWER_SLEEP 0x00 -#define DIBUSB_IOCTL_POWER_WAKEUP 0x01 - -/* modify streaming of the FX2 */ -#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01 -#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02 - -struct dibusb_state { - struct dib_fe_xfer_ops ops; - int mt2060_present; - u8 tuner_addr; -}; - -struct dibusb_device_state { - /* for RC5 remote control */ - int old_toggle; - int last_repeat_count; -}; - -extern struct i2c_algorithm dibusb_i2c_algo; - -extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *); -extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *); - -extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int); -extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int); -extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int); -extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int); - -extern int dibusb_power_ctrl(struct dvb_usb_device *, int); -extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int); - -#define DEFAULT_RC_INTERVAL 150 -//#define DEFAULT_RC_INTERVAL 100000 - -extern struct rc_map_table rc_map_dibusb_table[]; -extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *); -extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-mb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-mb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-mb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-mb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,476 +0,0 @@ -/* DVB USB compliant linux driver for mobile DVB-T USB devices based on - * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B) - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * based on GPL code from DiBcom, which has - * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dibusb_state *st = adap->priv; - - return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr); -} - -static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dib3000_config demod_cfg; - struct dibusb_state *st = adap->priv; - - demod_cfg.demod_address = 0x8; - - if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg, - &adap->dev->i2c_adap, &st->ops)) == NULL) - return -ENODEV; - - adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; - - return 0; -} - -static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dibusb_state *st = adap->priv; - - st->tuner_addr = 0x61; - - dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap, - DVB_PLL_TUA6010XS); - return 0; -} - -static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dibusb_state *st = adap->priv; - - st->tuner_addr = 0x60; - - dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap, - DVB_PLL_TDA665X); - return 0; -} - -/* Some of the Artec 1.1 device aren't equipped with the default tuner - * (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures - * this out. */ -static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) -{ - u8 b[2] = { 0,0 }, b2[1]; - int ret = 0; - struct i2c_msg msg[2] = { - { .flags = 0, .buf = b, .len = 2 }, - { .flags = I2C_M_RD, .buf = b2, .len = 1 }, - }; - struct dibusb_state *st = adap->priv; - - /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ - msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; - - if (adap->fe->ops.i2c_gate_ctrl) - adap->fe->ops.i2c_gate_ctrl(adap->fe,1); - - if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { - err("tuner i2c write failed."); - ret = -EREMOTEIO; - } - - if (adap->fe->ops.i2c_gate_ctrl) - adap->fe->ops.i2c_gate_ctrl(adap->fe,0); - - if (b2[0] == 0xfe) { - info("This device has the Thomson Cable onboard. Which is default."); - ret = dibusb_thomson_tuner_attach(adap); - } else { - info("This device has the Panasonic ENV77H11D5 onboard."); - ret = dibusb_panasonic_tuner_attach(adap); - } - - return ret; -} - -/* USB Driver stuff */ -static struct dvb_usb_device_properties dibusb1_1_properties; -static struct dvb_usb_device_properties dibusb1_1_an2235_properties; -static struct dvb_usb_device_properties dibusb2_0b_properties; -static struct dvb_usb_device_properties artec_t1_usb2_properties; - -static int dibusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dibusb2_0b_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties, - THIS_MODULE, NULL, adapter_nr)) - return 0; - - return -EINVAL; -} - -/* do not change the order of the ID table */ -static struct usb_device_id dibusb_dib3000mb_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM) }, -/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, -/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, -/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) }, -/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) }, -/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) }, -/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, -/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, -/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) }, -/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) }, -/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) }, -/* 12 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) }, -/* 13 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) }, -/* 14 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) }, -/* 15 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_COLD) }, -/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) }, -/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) }, -/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) }, -/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, -/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, -/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, -/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, -/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) }, - -/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ -/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, -/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, -/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, - -/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) }, - -/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, -/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, - -/* - * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices - * we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that - * have been left on the device. If you don't have such a device but an Artec - * device that's supposed to work with this driver but is not detected by it, - * free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config. - */ - -#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY -/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, -#endif - - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); - -static struct dvb_usb_device_properties dibusb1_1_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_AN2135, - - .firmware = "dvb-usb-dibusb-5.0.0.11.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 16, - - .streaming_ctrl = dibusb_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_tuner_probe_and_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - - .power_ctrl = dibusb_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 9, - .devices = { - { "AVerMedia AverTV DVBT USB1.1", - { &dibusb_dib3000mb_table[0], NULL }, - { &dibusb_dib3000mb_table[1], NULL }, - }, - { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)", - { &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL}, - { &dibusb_dib3000mb_table[3], NULL }, - }, - { "DiBcom USB1.1 DVB-T reference design (MOD3000)", - { &dibusb_dib3000mb_table[5], NULL }, - { &dibusb_dib3000mb_table[6], NULL }, - }, - { "KWorld V-Stream XPERT DTV - DVB-T USB1.1", - { &dibusb_dib3000mb_table[7], NULL }, - { &dibusb_dib3000mb_table[8], NULL }, - }, - { "Grandtec USB1.1 DVB-T", - { &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL }, - { &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL }, - }, - { "Unknown USB1.1 DVB-T device ???? please report the name to the author", - { &dibusb_dib3000mb_table[13], NULL }, - { &dibusb_dib3000mb_table[14], NULL }, - }, - { "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device", - { &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL}, - { &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL}, - }, - { "Artec T1 USB1.1 TVBOX with AN2135", - { &dibusb_dib3000mb_table[19], NULL }, - { &dibusb_dib3000mb_table[20], NULL }, - }, - { "VideoWalker DVB-T USB", - { &dibusb_dib3000mb_table[25], NULL }, - { &dibusb_dib3000mb_table[26], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties dibusb1_1_an2235_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = CYPRESS_AN2235, - - .firmware = "dvb-usb-dibusb-an2235-01.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER, - .pid_filter_count = 16, - - .streaming_ctrl = dibusb_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_tuner_probe_and_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .size_of_priv = sizeof(struct dibusb_state), - }, - }, - .power_ctrl = dibusb_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - -#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY - .num_device_descs = 2, -#else - .num_device_descs = 1, -#endif - .devices = { - { "Artec T1 USB1.1 TVBOX with AN2235", - { &dibusb_dib3000mb_table[21], NULL }, - { &dibusb_dib3000mb_table[22], NULL }, - }, -#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY - { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", - { &dibusb_dib3000mb_table[30], NULL }, - { NULL }, - }, - { NULL }, -#endif - } -}; - -static struct dvb_usb_device_properties dibusb2_0b_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .firmware = "dvb-usb-adstech-usb2-02.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 16, - - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_thomson_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .power_ctrl = dibusb2_0_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 2, - .devices = { - { "KWorld/ADSTech Instant DVB-T USB2.0", - { &dibusb_dib3000mb_table[23], NULL }, - { &dibusb_dib3000mb_table[24], NULL }, - }, - { "KWorld Xpert DVB-T USB2.0", - { &dibusb_dib3000mb_table[27], NULL }, - { NULL } - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties artec_t1_usb2_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .firmware = "dvb-usb-dibusb-6.0.0.8.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 16, - - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_tuner_probe_and_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .power_ctrl = dibusb2_0_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Artec T1 USB2.0", - { &dibusb_dib3000mb_table[28], NULL }, - { &dibusb_dib3000mb_table[29], NULL }, - }, - { NULL }, - } -}; - -static struct usb_driver dibusb_driver = { - .name = "dvb_usb_dibusb_mb", - .probe = dibusb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dibusb_dib3000mb_table, -}; - -/* module stuff */ -static int __init dibusb_module_init(void) -{ - int result; - if ((result = usb_register(&dibusb_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit dibusb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&dibusb_driver); -} - -module_init (dibusb_module_init); -module_exit (dibusb_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,164 +0,0 @@ -/* DVB USB compliant linux driver for mobile DVB-T USB devices based on - * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P) - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * based on GPL code from DiBcom, which has - * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -/* USB Driver stuff */ -static struct dvb_usb_device_properties dibusb_mc_properties; - -static int dibusb_mc_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &dibusb_mc_properties, THIS_MODULE, - NULL, adapter_nr); -} - -/* do not change the order of the ID table */ -static struct usb_device_id dibusb_dib3000mc_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) }, -/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, -/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? ) -/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) }, -/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) }, -/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) }, -/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) }, -/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) }, -/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) }, -/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) }, -/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) }, -/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) }, -/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) }, -/* 14 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD) }, -/* 15 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table); - -static struct dvb_usb_device_properties dibusb_mc_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-dibusb-6.0.0.8.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mc_frontend_attach, - .tuner_attach = dibusb_dib3000mc_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .power_ctrl = dibusb2_0_power_ctrl, - - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_dibusb_table, - .rc_map_size = 111, /* FIXME */ - .rc_query = dibusb_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 8, - .devices = { - { "DiBcom USB2.0 DVB-T reference design (MOD3000P)", - { &dibusb_dib3000mc_table[0], NULL }, - { &dibusb_dib3000mc_table[1], NULL }, - }, - { "Artec T1 USB2.0 TVBOX (please check the warm ID)", - { &dibusb_dib3000mc_table[2], NULL }, - { &dibusb_dib3000mc_table[3], NULL }, - }, - { "LITE-ON USB2.0 DVB-T Tuner", - /* Also rebranded as Intuix S800, Toshiba */ - { &dibusb_dib3000mc_table[4], NULL }, - { &dibusb_dib3000mc_table[5], NULL }, - }, - { "MSI Digivox Mini SL", - { &dibusb_dib3000mc_table[6], NULL }, - { &dibusb_dib3000mc_table[7], NULL }, - }, - { "GRAND - USB2.0 DVB-T adapter", - { &dibusb_dib3000mc_table[8], NULL }, - { &dibusb_dib3000mc_table[9], NULL }, - }, - { "Artec T14 - USB2.0 DVB-T", - { &dibusb_dib3000mc_table[10], NULL }, - { &dibusb_dib3000mc_table[11], NULL }, - }, - { "Leadtek - USB2.0 Winfast DTV dongle", - { &dibusb_dib3000mc_table[12], NULL }, - { &dibusb_dib3000mc_table[13], NULL }, - }, - { "Humax/Coex DVB-T USB Stick 2.0 High Speed", - { &dibusb_dib3000mc_table[14], NULL }, - { &dibusb_dib3000mc_table[15], NULL }, - }, - { NULL }, - } -}; - -static struct usb_driver dibusb_mc_driver = { - .name = "dvb_usb_dibusb_mc", - .probe = dibusb_mc_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dibusb_dib3000mc_table, -}; - -/* module stuff */ -static int __init dibusb_mc_module_init(void) -{ - int result; - if ((result = usb_register(&dibusb_mc_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit dibusb_mc_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&dibusb_mc_driver); -} - -module_init (dibusb_mc_module_init); -module_exit (dibusb_mc_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/digitv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/digitv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/digitv.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/digitv.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,364 +0,0 @@ -/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0 - * receiver - * - * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) - * - * partly based on the SDK published by Nebula Electronics - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "digitv.h" - -#include "mt352.h" -#include "nxt6000.h" - -/* debug */ -static int dvb_usb_digitv_debug; -module_param_named(debug,dvb_usb_digitv_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) - -static int digitv_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - u8 sndbuf[7],rcvbuf[7]; - memset(sndbuf,0,7); memset(rcvbuf,0,7); - - sndbuf[0] = cmd; - sndbuf[1] = vv; - sndbuf[2] = wo ? wlen : rlen; - - if (wo) { - memcpy(&sndbuf[3],wbuf,wlen); - dvb_usb_generic_write(d,sndbuf,7); - } else { - dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10); - memcpy(rbuf,&rcvbuf[3],rlen); - } - return 0; -} - -/* I2C */ -static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - if (num > 2) - warn("more than 2 i2c messages at a time is not handled yet. TODO."); - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0, - msg[i+1].buf,msg[i+1].len) < 0) - break; - i++; - } else - if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0], - &msg[i].buf[1],msg[i].len-1,NULL,0) < 0) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 digitv_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm digitv_i2c_algo = { - .master_xfer = digitv_i2c_xfer, - .functionality = digitv_i2c_func, -}; - -/* Callbacks for DVB USB */ -static int digitv_identify_state (struct usb_device *udev, struct - dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, - int *cold) -{ - *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; - return 0; -} - -static int digitv_mt352_demod_init(struct dvb_frontend *fe) -{ - static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 }; - static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50, - 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00, - 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f, - 0x75, 0x32 }; - int i; - - for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2) - mt352_write(fe, &reset_buf[i], 2); - - msleep(1); - - for (i = 0; i < ARRAY_SIZE(init_buf); i += 2) - mt352_write(fe, &init_buf[i], 2); - - return 0; -} - -static struct mt352_config digitv_mt352_config = { - .demod_init = digitv_mt352_demod_init, -}; - -static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - u8 b[5]; - - fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b)); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); -} - -static struct nxt6000_config digitv_nxt6000_config = { - .clock_inversion = 1, -}; - -static int digitv_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct digitv_state *st = adap->dev->priv; - - if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { - st->is_nxt6000 = 0; - return 0; - } - if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { - st->is_nxt6000 = 1; - return 0; - } - return -EIO; -} - -static int digitv_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct digitv_state *st = adap->dev->priv; - - if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4)) - return -ENODEV; - - if (st->is_nxt6000) - adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; - - return 0; -} - -static struct rc_map_table rc_map_digitv_table[] = { - { 0x5f55, KEY_0 }, - { 0x6f55, KEY_1 }, - { 0x9f55, KEY_2 }, - { 0xaf55, KEY_3 }, - { 0x5f56, KEY_4 }, - { 0x6f56, KEY_5 }, - { 0x9f56, KEY_6 }, - { 0xaf56, KEY_7 }, - { 0x5f59, KEY_8 }, - { 0x6f59, KEY_9 }, - { 0x9f59, KEY_TV }, - { 0xaf59, KEY_AUX }, - { 0x5f5a, KEY_DVD }, - { 0x6f5a, KEY_POWER }, - { 0x9f5a, KEY_CAMERA }, /* labelled 'Picture' */ - { 0xaf5a, KEY_AUDIO }, - { 0x5f65, KEY_INFO }, - { 0x6f65, KEY_F13 }, /* 16:9 */ - { 0x9f65, KEY_F14 }, /* 14:9 */ - { 0xaf65, KEY_EPG }, - { 0x5f66, KEY_EXIT }, - { 0x6f66, KEY_MENU }, - { 0x9f66, KEY_UP }, - { 0xaf66, KEY_DOWN }, - { 0x5f69, KEY_LEFT }, - { 0x6f69, KEY_RIGHT }, - { 0x9f69, KEY_ENTER }, - { 0xaf69, KEY_CHANNELUP }, - { 0x5f6a, KEY_CHANNELDOWN }, - { 0x6f6a, KEY_VOLUMEUP }, - { 0x9f6a, KEY_VOLUMEDOWN }, - { 0xaf6a, KEY_RED }, - { 0x5f95, KEY_GREEN }, - { 0x6f95, KEY_YELLOW }, - { 0x9f95, KEY_BLUE }, - { 0xaf95, KEY_SUBTITLE }, - { 0x5f96, KEY_F15 }, /* AD */ - { 0x6f96, KEY_TEXT }, - { 0x9f96, KEY_MUTE }, - { 0xaf96, KEY_REWIND }, - { 0x5f99, KEY_STOP }, - { 0x6f99, KEY_PLAY }, - { 0x9f99, KEY_FASTFORWARD }, - { 0xaf99, KEY_F16 }, /* chapter */ - { 0x5f9a, KEY_PAUSE }, - { 0x6f9a, KEY_PLAY }, - { 0x9f9a, KEY_RECORD }, - { 0xaf9a, KEY_F17 }, /* picture in picture */ - { 0x5fa5, KEY_KPPLUS }, /* zoom in */ - { 0x6fa5, KEY_KPMINUS }, /* zoom out */ - { 0x9fa5, KEY_F18 }, /* capture */ - { 0xafa5, KEY_F19 }, /* web */ - { 0x5fa6, KEY_EMAIL }, - { 0x6fa6, KEY_PHONE }, - { 0x9fa6, KEY_PC }, -}; - -static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - int i; - u8 key[5]; - u8 b[4] = { 0 }; - - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - - digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4); - - /* Tell the device we've read the remote. Not sure how necessary - this is, but the Nebula SDK does it. */ - digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); - - /* if something is inside the buffer, simulate key press */ - if (key[1] != 0) - { - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] && - rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) { - *event = d->props.rc.legacy.rc_map_table[i].keycode; - *state = REMOTE_KEY_PRESSED; - return 0; - } - } - } - - if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); - return 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties digitv_properties; - -static int digitv_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d; - int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d, - adapter_nr); - if (ret == 0) { - u8 b[4] = { 0 }; - - if (d != NULL) { /* do that only when the firmware is loaded */ - b[0] = 1; - digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0); - - b[0] = 0; - digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); - } - } - return ret; -} - -static struct usb_device_id digitv_table [] = { - { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, digitv_table); - -static struct dvb_usb_device_properties digitv_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-digitv-02.fw", - - .size_of_priv = sizeof(struct digitv_state), - - .num_adapters = 1, - .adapter = { - { - .frontend_attach = digitv_frontend_attach, - .tuner_attach = digitv_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .identify_state = digitv_identify_state, - - .rc.legacy = { - .rc_interval = 1000, - .rc_map_table = rc_map_digitv_table, - .rc_map_size = ARRAY_SIZE(rc_map_digitv_table), - .rc_query = digitv_rc_query, - }, - - .i2c_algo = &digitv_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Nebula Electronics uDigiTV DVB-T USB2.0)", - { &digitv_table[0], NULL }, - { NULL }, - }, - { NULL }, - } -}; - -static struct usb_driver digitv_driver = { - .name = "dvb_usb_digitv", - .probe = digitv_probe, - .disconnect = dvb_usb_device_exit, - .id_table = digitv_table, -}; - -/* module stuff */ -static int __init digitv_module_init(void) -{ - int result; - if ((result = usb_register(&digitv_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit digitv_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&digitv_driver); -} - -module_init (digitv_module_init); -module_exit (digitv_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/digitv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/digitv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/digitv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/digitv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -#ifndef _DVB_USB_DIGITV_H_ -#define _DVB_USB_DIGITV_H_ - -#define DVB_USB_LOG_PREFIX "digitv" -#include "dvb-usb.h" - -struct digitv_state { - int is_nxt6000; -}; - -/* protocol (from usblogging and the SDK: - * - * Always 7 bytes bulk message(s) for controlling - * - * First byte describes the command. Reads are 2 consecutive transfer (as always). - * - * General structure: - * - * write or first message of a read: - * VV B0 B1 B2 B3 - * - * second message of a read - * VV R0 R1 R2 R3 - * - * whereas 0 < len <= 4 - * - * I2C address is stored somewhere inside the device. - * - * 0x01 read from EEPROM - * VV = offset; B* = 0; R* = value(s) - * - * 0x02 read register of the COFDM - * VV = register; B* = 0; R* = value(s) - * - * 0x05 write register of the COFDM - * VV = register; B* = value(s); - * - * 0x06 write to the tuner (only for NXT6000) - * VV = 0; B* = PLL data; len = 4; - * - * 0x03 read remote control - * VV = 0; B* = 0; len = 4; R* = key - * - * 0x07 write to the remote (don't know why one should this, resetting ?) - * VV = 0; B* = key; len = 4; - * - * 0x08 write remote type - * VV = 0; B[0] = 0x01, len = 4 - * - * 0x09 write device init - * TODO - */ -#define USB_READ_EEPROM 1 - -#define USB_READ_COFDM 2 -#define USB_WRITE_COFDM 5 - -#define USB_WRITE_TUNER 6 - -#define USB_READ_REMOTE 3 -#define USB_WRITE_REMOTE 7 -#define USB_WRITE_REMOTE_TYPE 8 - -#define USB_DEV_INIT 9 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,374 +0,0 @@ -/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to Steve Chang from WideView for providing support for the WT-220U. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dtt200u.h" - -/* debug */ -int dvb_usb_dtt200u_debug; -module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b = SET_INIT; - - if (onoff) - dvb_usb_generic_write(d,&b,2); - - return 0; -} - -static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - u8 b_streaming[2] = { SET_STREAMING, onoff }; - u8 b_rst_pid = RESET_PID_FILTER; - - dvb_usb_generic_write(adap->dev, b_streaming, 2); - - if (onoff == 0) - dvb_usb_generic_write(adap->dev, &b_rst_pid, 1); - return 0; -} - -static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) -{ - u8 b_pid[4]; - pid = onoff ? pid : 0; - - b_pid[0] = SET_PID_FILTER; - b_pid[1] = index; - b_pid[2] = pid & 0xff; - b_pid[3] = (pid >> 8) & 0x1f; - - return dvb_usb_generic_write(adap->dev, b_pid, 4); -} - -/* remote control */ -/* key list for the tiny remote control (Yakumo, don't know about the others) */ -static struct rc_map_table rc_map_dtt200u_table[] = { - { 0x8001, KEY_MUTE }, - { 0x8002, KEY_CHANNELDOWN }, - { 0x8003, KEY_VOLUMEDOWN }, - { 0x8004, KEY_1 }, - { 0x8005, KEY_2 }, - { 0x8006, KEY_3 }, - { 0x8007, KEY_4 }, - { 0x8008, KEY_5 }, - { 0x8009, KEY_6 }, - { 0x800a, KEY_7 }, - { 0x800c, KEY_ZOOM }, - { 0x800d, KEY_0 }, - { 0x800e, KEY_SELECT }, - { 0x8012, KEY_POWER }, - { 0x801a, KEY_CHANNELUP }, - { 0x801b, KEY_8 }, - { 0x801e, KEY_VOLUMEUP }, - { 0x801f, KEY_9 }, -}; - -static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key[5],cmd = GET_RC_CODE; - dvb_usb_generic_rw(d,&cmd,1,key,5,0); - dvb_usb_nec_rc_key_to_event(d,key,event,state); - if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); - return 0; -} - -static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe = dtt200u_fe_attach(adap->dev); - return 0; -} - -static struct dvb_usb_device_properties dtt200u_properties; -static struct dvb_usb_device_properties wt220u_fc_properties; -static struct dvb_usb_device_properties wt220u_properties; -static struct dvb_usb_device_properties wt220u_zl0353_properties; -static struct dvb_usb_device_properties wt220u_miglia_properties; - -static int dtt200u_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &dtt200u_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &wt220u_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &wt220u_fc_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &wt220u_miglia_properties, - THIS_MODULE, NULL, adapter_nr)) - return 0; - - return -ENODEV; -} - -static struct usb_device_id dtt200u_usb_table [] = { - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, - { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, - { 0 }, -}; -MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); - -static struct dvb_usb_device_properties dtt200u_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-dtt200u-01.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, - .pid_filter_count = 15, - - .streaming_ctrl = dtt200u_streaming_ctrl, - .pid_filter = dtt200u_pid_filter, - .frontend_attach = dtt200u_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .power_ctrl = dtt200u_power_ctrl, - - .rc.legacy = { - .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), - .rc_query = dtt200u_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)", - .cold_ids = { &dtt200u_usb_table[0], NULL }, - .warm_ids = { &dtt200u_usb_table[1], NULL }, - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties wt220u_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-02.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, - .pid_filter_count = 15, - - .streaming_ctrl = dtt200u_streaming_ctrl, - .pid_filter = dtt200u_pid_filter, - .frontend_attach = dtt200u_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .power_ctrl = dtt200u_power_ctrl, - - .rc.legacy = { - .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), - .rc_query = dtt200u_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", - .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL }, - .warm_ids = { &dtt200u_usb_table[3], NULL }, - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties wt220u_fc_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-fc03.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, - .pid_filter_count = 15, - - .streaming_ctrl = dtt200u_streaming_ctrl, - .pid_filter = dtt200u_pid_filter, - .frontend_attach = dtt200u_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .power_ctrl = dtt200u_power_ctrl, - - .rc.legacy = { - .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), - .rc_query = dtt200u_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", - .cold_ids = { &dtt200u_usb_table[6], NULL }, - .warm_ids = { &dtt200u_usb_table[7], NULL }, - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties wt220u_zl0353_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-zl0353-01.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, - .pid_filter_count = 15, - - .streaming_ctrl = dtt200u_streaming_ctrl, - .pid_filter = dtt200u_pid_filter, - .frontend_attach = dtt200u_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .power_ctrl = dtt200u_power_ctrl, - - .rc.legacy = { - .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), - .rc_query = dtt200u_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView WT-220U PenType Receiver (based on ZL353)", - .cold_ids = { &dtt200u_usb_table[4], NULL }, - .warm_ids = { &dtt200u_usb_table[5], NULL }, - }, - { NULL }, - } -}; - -static struct dvb_usb_device_properties wt220u_miglia_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-miglia-01.fw", - - .num_adapters = 1, - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { .name = "WideView WT-220U PenType Receiver (Miglia)", - .cold_ids = { &dtt200u_usb_table[9], NULL }, - /* This device turns into WT220U_ZL0353_WARM when fw - has been uploaded */ - .warm_ids = { NULL }, - }, - { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver dtt200u_usb_driver = { - .name = "dvb_usb_dtt200u", - .probe = dtt200u_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dtt200u_usb_table, -}; - -/* module stuff */ -static int __init dtt200u_usb_module_init(void) -{ - int result; - if ((result = usb_register(&dtt200u_usb_driver))) { - err("usb_register failed. (%d)",result); - return result; - } - - return 0; -} - -static void __exit dtt200u_usb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&dtt200u_usb_driver); -} - -module_init(dtt200u_usb_module_init); -module_exit(dtt200u_usb_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u-fe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u-fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,205 +0,0 @@ -/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan DVB-T USB2.0 receiver. - * - * Copyright (C) 2005 Patrick Boettcher - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dtt200u.h" - -struct dtt200u_fe_state { - struct dvb_usb_device *d; - - fe_status_t stat; - - struct dvb_frontend_parameters fep; - struct dvb_frontend frontend; -}; - -static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 st = GET_TUNE_STATUS, b[3]; - - dvb_usb_generic_rw(state->d,&st,1,b,3,0); - - switch (b[0]) { - case 0x01: - *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - break; - case 0x00: /* pending */ - *stat = FE_TIMEDOUT; /* during set_frontend */ - break; - default: - case 0x02: /* failed */ - *stat = 0; - break; - } - return 0; -} - -static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_VIT_ERR_CNT,b[3]; - dvb_usb_generic_rw(state->d,&bw,1,b,3,0); - *ber = (b[0] << 16) | (b[1] << 8) | b[2]; - return 0; -} - -static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_RS_UNCOR_BLK_CNT,b[2]; - - dvb_usb_generic_rw(state->d,&bw,1,b,2,0); - *unc = (b[0] << 8) | b[1]; - return 0; -} - -static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_AGC, b; - dvb_usb_generic_rw(state->d,&bw,1,&b,1,0); - *strength = (b << 8) | b; - return 0; -} - -static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_SNR,br; - dvb_usb_generic_rw(state->d,&bw,1,&br,1,0); - *snr = ~((br << 8) | br); - return 0; -} - -static int dtt200u_fe_init(struct dvb_frontend* fe) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 b = SET_INIT; - return dvb_usb_generic_write(state->d,&b,1); -} - -static int dtt200u_fe_sleep(struct dvb_frontend* fe) -{ - return dtt200u_fe_init(fe); -} - -static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1500; - tune->step_size = 0; - tune->max_drift = 0; - return 0; -} - -static int dtt200u_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - int i; - fe_status_t st; - u16 freq = fep->frequency / 250000; - u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 }; - - switch (fep->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break; - case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break; - case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break; - case BANDWIDTH_AUTO: return -EOPNOTSUPP; - default: - return -EINVAL; - } - - dvb_usb_generic_write(state->d,bwbuf,2); - - freqbuf[1] = freq & 0xff; - freqbuf[2] = (freq >> 8) & 0xff; - dvb_usb_generic_write(state->d,freqbuf,3); - - for (i = 0; i < 30; i++) { - msleep(20); - dtt200u_fe_read_status(fe, &st); - if (st & FE_TIMEDOUT) - continue; - } - - return 0; -} - -static int dtt200u_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters)); - return 0; -} - -static void dtt200u_fe_release(struct dvb_frontend* fe) -{ - struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops dtt200u_fe_ops; - -struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d) -{ - struct dtt200u_fe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL); - if (state == NULL) - goto error; - - deb_info("attaching frontend dtt200u\n"); - - state->d = d; - - memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - return &state->frontend; -error: - return NULL; -} - -static struct dvb_frontend_ops dtt200u_fe_ops = { - .info = { - .name = "WideView USB DVB-T", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = dtt200u_fe_release, - - .init = dtt200u_fe_init, - .sleep = dtt200u_fe_sleep, - - .set_frontend = dtt200u_fe_set_frontend, - .get_frontend = dtt200u_fe_get_frontend, - .get_tune_settings = dtt200u_fe_get_tune_settings, - - .read_status = dtt200u_fe_read_status, - .read_ber = dtt200u_fe_read_ber, - .read_signal_strength = dtt200u_fe_read_signal_strength, - .read_snr = dtt200u_fe_read_snr, - .read_ucblocks = dtt200u_fe_read_unc_blocks, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtt200u.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan DVB-T USB2.0 receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_DTT200U_H_ -#define _DVB_USB_DTT200U_H_ - -#define DVB_USB_LOG_PREFIX "dtt200u" - -#include "dvb-usb.h" - -extern int dvb_usb_dtt200u_debug; -#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args) - -/* guessed protocol description (reverse engineered): - * read - * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1 - * 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal) - */ - -#define GET_SPEED 0x00 -#define GET_TUNE_STATUS 0x81 -#define GET_RC_CODE 0x84 -#define GET_CONFIGURATION 0x88 -#define GET_AGC 0x89 -#define GET_SNR 0x8a -#define GET_VIT_ERR_CNT 0x8c -#define GET_RS_ERR_CNT 0x8d -#define GET_RS_UNCOR_BLK_CNT 0x8e - -/* write - * 01 - init - * 02 - frequency (divided by 250000) - * 03 - bandwidth - * 04 - pid table (index pid(7:0) pid(12:8)) - * 05 - reset the pid table - * 08 - transfer switch - */ - -#define SET_INIT 0x01 -#define SET_RF_FREQ 0x02 -#define SET_BANDWIDTH 0x03 -#define SET_PID_FILTER 0x04 -#define RESET_PID_FILTER 0x05 -#define SET_STREAMING 0x08 - -extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtv5100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtv5100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtv5100.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtv5100.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,240 +0,0 @@ -/* - * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T - * - * Copyright (C) 2008 Antoine Jacquet - * http://royale.zerezo.com/dtv5100/ - * - * Inspired by gl861.c and au6610.c drivers - * - * 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, or - * (at your option) any later version. - * - * 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 "dtv5100.h" -#include "zl10353.h" -#include "qt1010.h" - -/* debug */ -static int dvb_usb_dtv5100_debug; -module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u8 request; - u8 type; - u16 value; - u16 index; - - switch (wlen) { - case 1: - /* write { reg }, read { value } */ - request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ : - DTV5100_TUNER_READ); - type = USB_TYPE_VENDOR | USB_DIR_IN; - value = 0; - break; - case 2: - /* write { reg, value } */ - request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE : - DTV5100_TUNER_WRITE); - type = USB_TYPE_VENDOR | USB_DIR_OUT; - value = wbuf[1]; - break; - default: - warn("wlen = %x, aborting.", wlen); - return -EINVAL; - } - index = (addr << 8) + wbuf[0]; - - msleep(1); /* avoid I2C errors */ - return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request, - type, value, index, rbuf, rlen, - DTV5100_USB_TIMEOUT); -} - -/* I2C */ -static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, msg[i+1].buf, - msg[i+1].len) < 0) - break; - i++; - } else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, NULL, 0) < 0) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 dtv5100_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm dtv5100_i2c_algo = { - .master_xfer = dtv5100_i2c_xfer, - .functionality = dtv5100_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config dtv5100_zl10353_config = { - .demod_address = DTV5100_DEMOD_ADDR, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, - &adap->dev->i2c_adap); - if (adap->fe == NULL) - return -EIO; - - /* disable i2c gate, or it won't work... is this safe? */ - adap->fe->ops.i2c_gate_ctrl = NULL; - - return 0; -} - -static struct qt1010_config dtv5100_qt1010_config = { - .i2c_address = DTV5100_TUNER_ADDR -}; - -static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(qt1010_attach, - adap->fe, &adap->dev->i2c_adap, - &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties dtv5100_properties; - -static int dtv5100_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int i, ret; - struct usb_device *udev = interface_to_usbdev(intf); - - /* initialize non qt1010/zl10353 part? */ - for (i = 0; dtv5100_init[i].request; i++) { - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - dtv5100_init[i].request, - USB_TYPE_VENDOR | USB_DIR_OUT, - dtv5100_init[i].value, - dtv5100_init[i].index, NULL, 0, - DTV5100_USB_TIMEOUT); - if (ret) - return ret; - } - - ret = dvb_usb_device_init(intf, &dtv5100_properties, - THIS_MODULE, NULL, adapter_nr); - if (ret) - return ret; - - return 0; -} - -static struct usb_device_id dtv5100_table[] = { - { USB_DEVICE(0x06be, 0xa232) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, dtv5100_table); - -static struct dvb_usb_device_properties dtv5100_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = 0, - - .num_adapters = 1, - .adapter = {{ - .frontend_attach = dtv5100_frontend_attach, - .tuner_attach = dtv5100_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } }, - - .i2c_algo = &dtv5100_i2c_algo, - - .num_device_descs = 1, - .devices = { - { - .name = "AME DTV-5100 USB2.0 DVB-T", - .cold_ids = { NULL }, - .warm_ids = { &dtv5100_table[0], NULL }, - }, - } -}; - -static struct usb_driver dtv5100_driver = { - .name = "dvb_usb_dtv5100", - .probe = dtv5100_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dtv5100_table, -}; - -/* module stuff */ -static int __init dtv5100_module_init(void) -{ - int ret; - - ret = usb_register(&dtv5100_driver); - if (ret) - err("usb_register failed. Error number %d", ret); - - return ret; -} - -static void __exit dtv5100_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&dtv5100_driver); -} - -module_init(dtv5100_module_init); -module_exit(dtv5100_module_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtv5100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtv5100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtv5100.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dtv5100.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T - * - * Copyright (C) 2008 Antoine Jacquet - * http://royale.zerezo.com/dtv5100/ - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#ifndef _DVB_USB_DTV5100_H_ -#define _DVB_USB_DTV5100_H_ - -#define DVB_USB_LOG_PREFIX "dtv5100" -#include "dvb-usb.h" - -#define DTV5100_USB_TIMEOUT 500 - -#define DTV5100_DEMOD_ADDR 0x00 -#define DTV5100_DEMOD_WRITE 0xc0 -#define DTV5100_DEMOD_READ 0xc1 - -#define DTV5100_TUNER_ADDR 0xc4 -#define DTV5100_TUNER_WRITE 0xc7 -#define DTV5100_TUNER_READ 0xc8 - -#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" -#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T" - -static struct { - u8 request; - u8 value; - u16 index; -} dtv5100_init[] = { - { 0x000000c5, 0x00000000, 0x00000001 }, - { 0x000000c5, 0x00000001, 0x00000001 }, - { } /* Terminating entry */ -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-common.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* dvb-usb-common.h is part of the DVB USB library. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * a header file containing prototypes and types for internal use of the dvb-usb-lib - */ -#ifndef _DVB_USB_COMMON_H_ -#define _DVB_USB_COMMON_H_ - -#define DVB_USB_LOG_PREFIX "dvb-usb" -#include "dvb-usb.h" - -extern int dvb_usb_debug; -extern int dvb_usb_disable_rc_polling; - -#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args) -#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args) -#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args) -#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args) -#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args) -#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args) -#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args) -#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args) -#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args) - -/* commonly used methods */ -extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *); - -extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); - -extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props); -extern int usb_urb_exit(struct usb_data_stream *stream); -extern int usb_urb_submit(struct usb_data_stream *stream); -extern int usb_urb_kill(struct usb_data_stream *stream); - -extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap); - -extern int dvb_usb_i2c_init(struct dvb_usb_device *); -extern int dvb_usb_i2c_exit(struct dvb_usb_device *); - -extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, - short *adapter_nums); -extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap); - -extern int dvb_usb_remote_init(struct dvb_usb_device *); -extern int dvb_usb_remote_exit(struct dvb_usb_device *); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,205 +0,0 @@ -/* dvb-usb-dvb.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for initializing and handling the - * linux-dvb API. - */ -#include "dvb-usb-common.h" - -/* does the complete input transfer handling */ -static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) -{ - struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; - int newfeedcount,ret; - - if (adap == NULL) - return -ENODEV; - - newfeedcount = adap->feedcount + (onoff ? 1 : -1); - - /* stop feed before setting a new pid if there will be no pid anymore */ - if (newfeedcount == 0) { - deb_ts("stop feeding\n"); - usb_urb_kill(&adap->stream); - - if (adap->props.streaming_ctrl != NULL) - if ((ret = adap->props.streaming_ctrl(adap,0))) - err("error while stopping stream."); - } - - adap->feedcount = newfeedcount; - - /* activate the pid on the device specific pid_filter */ - deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->pid_filtering ? - "yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? - "on" : "off"); - if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->pid_filtering && - adap->props.pid_filter != NULL) - adap->props.pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid,onoff); - - /* start the feed if this was the first feed and there is still a feed - * for reception. - */ - if (adap->feedcount == onoff && adap->feedcount > 0) { - deb_ts("submitting all URBs\n"); - usb_urb_submit(&adap->stream); - - deb_ts("controlling pid parser\n"); - if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props.caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props.pid_filter_ctrl != NULL) - if (adap->props.pid_filter_ctrl(adap,adap->pid_filtering) < 0) - err("could not handle pid_parser"); - - deb_ts("start feeding\n"); - if (adap->props.streaming_ctrl != NULL) - if (adap->props.streaming_ctrl(adap,1)) { - err("error while enabling fifo."); - return -ENODEV; - } - - } - return 0; -} - -static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); - return dvb_usb_ctrl_feed(dvbdmxfeed,1); -} - -static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); - return dvb_usb_ctrl_feed(dvbdmxfeed,0); -} - -int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) -{ - int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, - adap->dev->owner, &adap->dev->udev->dev, - adapter_nums); - - if (ret < 0) { - deb_info("dvb_register_adapter failed: error %d", ret); - goto err; - } - adap->dvb_adap.priv = adap; - adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override; - - if (adap->dev->props.read_mac_address) { - if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) - info("MAC address: %pM",adap->dvb_adap.proposed_mac); - else - err("MAC address reading failed."); - } - - - adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - adap->demux.priv = adap; - - adap->demux.feednum = adap->demux.filternum = adap->max_feed_count; - adap->demux.start_feed = dvb_usb_start_feed; - adap->demux.stop_feed = dvb_usb_stop_feed; - adap->demux.write_to_decoder = NULL; - if ((ret = dvb_dmx_init(&adap->demux)) < 0) { - err("dvb_dmx_init failed: error %d",ret); - goto err_dmx; - } - - adap->dmxdev.filternum = adap->demux.filternum; - adap->dmxdev.demux = &adap->demux.dmx; - adap->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) { - err("dvb_dmxdev_init failed: error %d",ret); - goto err_dmx_dev; - } - - dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); - - adap->state |= DVB_USB_ADAP_STATE_DVB; - return 0; - -err_dmx_dev: - dvb_dmx_release(&adap->demux); -err_dmx: - dvb_unregister_adapter(&adap->dvb_adap); -err: - return ret; -} - -int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) -{ - if (adap->state & DVB_USB_ADAP_STATE_DVB) { - deb_info("unregistering DVB part\n"); - dvb_net_release(&adap->dvb_net); - adap->demux.dmx.close(&adap->demux.dmx); - dvb_dmxdev_release(&adap->dmxdev); - dvb_dmx_release(&adap->demux); - dvb_unregister_adapter(&adap->dvb_adap); - adap->state &= ~DVB_USB_ADAP_STATE_DVB; - } - return 0; -} - -static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - - dvb_usb_device_power_ctrl(adap->dev, 1); - - if (adap->fe_init) - adap->fe_init(fe); - - return 0; -} - -static int dvb_usb_fe_sleep(struct dvb_frontend *fe) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - - if (adap->fe_sleep) - adap->fe_sleep(fe); - - return dvb_usb_device_power_ctrl(adap->dev, 0); -} - -int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) -{ - if (adap->props.frontend_attach == NULL) { - err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id); - return 0; - } - - /* re-assign sleep and wakeup functions */ - if (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) { - adap->fe_init = adap->fe->ops.init; adap->fe->ops.init = dvb_usb_fe_wakeup; - adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep; - - if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { - err("Frontend registration failed."); - dvb_frontend_detach(adap->fe); - adap->fe = NULL; - return -ENODEV; - } - - /* only attach the tuner if the demod is there */ - if (adap->props.tuner_attach != NULL) - adap->props.tuner_attach(adap); - } else - err("no frontend was attached by '%s'",adap->dev->desc->name); - - return 0; -} - -int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) -{ - if (adap->fe != NULL) { - dvb_unregister_frontend(adap->fe); - dvb_frontend_detach(adap->fe); - } - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -/* dvb-usb-firmware.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices. - * - * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem. - */ -#include "dvb-usb-common.h" - -#include - -struct usb_cypress_controller { - int id; - const char *name; /* name of the usb controller */ - u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */ -}; - -static struct usb_cypress_controller cypress[] = { - { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 }, - { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, -}; - -/* - * load a firmware packet to the device - */ -static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) -{ - return usb_control_msg(udev, usb_sndctrlpipe(udev,0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); -} - -int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) -{ - struct hexline hx; - u8 reset; - int ret,pos=0; - - /* stop the CPU */ - reset = 1; - if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) - err("could not stop the USB controller CPU."); - - while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) { - deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); - ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); - - if (ret != hx.len) { - err("error while transferring firmware " - "(transferred size: %d, block size: %d)", - ret,hx.len); - ret = -EINVAL; - break; - } - } - if (ret < 0) { - err("firmware download failed at %d with %d",pos,ret); - return ret; - } - - if (ret == 0) { - /* restart the CPU */ - reset = 0; - if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - } else - ret = -EIO; - - return ret; -} -EXPORT_SYMBOL(usb_cypress_load_firmware); - -int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props) -{ - int ret; - const struct firmware *fw = NULL; - - if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", - props->firmware,ret); - return ret; - } - - info("downloading firmware from file '%s'",props->firmware); - - switch (props->usb_ctrl) { - case CYPRESS_AN2135: - case CYPRESS_AN2235: - case CYPRESS_FX2: - ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl); - break; - case DEVICE_SPECIFIC: - if (props->download_firmware) - ret = props->download_firmware(udev,fw); - else { - err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one."); - ret = -EINVAL; - } - break; - default: - ret = -EINVAL; - break; - } - - release_firmware(fw); - return ret; -} - -int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, - int *pos) -{ - u8 *b = (u8 *) &fw->data[*pos]; - int data_offs = 4; - if (*pos >= fw->size) - return 0; - - memset(hx,0,sizeof(struct hexline)); - - hx->len = b[0]; - - if ((*pos + hx->len + 4) >= fw->size) - return -EINVAL; - - hx->addr = b[1] | (b[2] << 8); - hx->type = b[3]; - - if (hx->type == 0x04) { - /* b[4] and b[5] are the Extended linear address record data field */ - hx->addr |= (b[4] << 24) | (b[5] << 16); -/* hx->len -= 2; - data_offs += 2; */ - } - memcpy(hx->data,&b[data_offs],hx->len); - hx->chk = b[hx->len + data_offs]; - - *pos += hx->len + 5; - - return *pos; -} -EXPORT_SYMBOL(dvb_usb_get_hexline); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,463 +0,0 @@ -/* dvb-usb.h is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * the headerfile, all dvb-usb-drivers have to include. - * - * TODO: clean-up the structures for unused fields and update the comments - */ -#ifndef __DVB_USB_H__ -#define __DVB_USB_H__ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvb_demux.h" -#include "dvb_net.h" -#include "dmxdev.h" - -#include "dvb-pll.h" - -#include "dvb-usb-ids.h" - -/* debug */ -#ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var,level,args...) \ - do { if ((var & level)) { printk(args); } } while (0) - -#define debug_dump(b,l,func) {\ - int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \ - func("\n");\ -} -#define DVB_USB_DEBUG_STATUS -#else -#define dprintk(args...) -#define debug_dump(b,l,func) - -#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" - -#endif - -/* generic log methods - taken from usb.h */ -#ifndef DVB_USB_LOG_PREFIX - #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)" -#endif - -#undef err -#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef info -#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) - -/** - * struct dvb_usb_device_description - name and its according USB IDs - * @name: real name of the box, regardless which DVB USB device class is in use - * @cold_ids: array of struct usb_device_id which describe the device in - * pre-firmware state - * @warm_ids: array of struct usb_device_id which describe the device in - * post-firmware state - * - * Each DVB USB device class can have one or more actual devices, this struct - * assigns a name to it. - */ -struct dvb_usb_device_description { - const char *name; - -#define DVB_USB_ID_MAX_NUM 15 - struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM]; - struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM]; -}; - -static inline u8 rc5_custom(struct rc_map_table *key) -{ - return (key->scancode >> 8) & 0xff; -} - -static inline u8 rc5_data(struct rc_map_table *key) -{ - return key->scancode & 0xff; -} - -static inline u8 rc5_scan(struct rc_map_table *key) -{ - return key->scancode & 0xffff; -} - -struct dvb_usb_device; -struct dvb_usb_adapter; -struct usb_data_stream; - -/** - * Properties of USB streaming - TODO this structure should be somewhere else - * describes the kind of USB transfer used for data-streaming. - * (BULK or ISOC) - */ -struct usb_data_stream_properties { -#define USB_BULK 1 -#define USB_ISOC 2 - int type; - int count; - int endpoint; - - union { - struct { - int buffersize; /* per URB */ - } bulk; - struct { - int framesperurb; - int framesize; - int interval; - } isoc; - } u; -}; - -/** - * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. - * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device. - * @caps: capabilities of the DVB USB device. - * @pid_filter_count: number of PID filter position in the optional hardware - * PID-filter. - * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the - * device (not URB submitting/killing). - * @pid_filter_ctrl: called to en/disable the PID filter, if any. - * @pid_filter: called to set/unset a PID for filtering. - * @frontend_attach: called to attach the possible frontends (fill fe-field - * of struct dvb_usb_device). - * @tuner_attach: called to attach the correct tuner and to fill pll_addr, - * pll_desc and pll_init_buf of struct dvb_usb_device). - * @stream: configuration of the USB streaming - */ -struct dvb_usb_adapter_properties { -#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 -#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 -#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 -#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 - int caps; - int pid_filter_count; - - int (*streaming_ctrl) (struct dvb_usb_adapter *, int); - int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); - int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); - - int (*frontend_attach) (struct dvb_usb_adapter *); - int (*tuner_attach) (struct dvb_usb_adapter *); - - struct usb_data_stream_properties stream; - - int size_of_priv; - - int (*fe_ioctl_override) (struct dvb_frontend *, - unsigned int, void *, unsigned int); -}; - -/** - * struct dvb_rc_legacy - old properties of remote controller - * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable - * remote control handling). - * @rc_map_size: number of items in @rc_map_table. - * @rc_query: called to query an event event. - * @rc_interval: time in ms between two queries. - */ -struct dvb_rc_legacy { -/* remote control properties */ -#define REMOTE_NO_KEY_PRESSED 0x00 -#define REMOTE_KEY_PRESSED 0x01 -#define REMOTE_KEY_REPEAT 0x02 - struct rc_map_table *rc_map_table; - int rc_map_size; - int (*rc_query) (struct dvb_usb_device *, u32 *, int *); - int rc_interval; -}; - -/** - * struct dvb_rc properties of remote controller, using rc-core - * @rc_codes: name of rc codes table - * @protocol: type of protocol(s) currently used by the driver - * @allowed_protos: protocol(s) supported by the driver - * @driver_type: Used to point if a device supports raw mode - * @change_protocol: callback to change protocol - * @rc_query: called to query an event event. - * @rc_interval: time in ms between two queries. - * @bulk_mode: device supports bulk mode for RC (disable polling mode) - */ -struct dvb_rc { - char *rc_codes; - u64 protocol; - u64 allowed_protos; - enum rc_driver_type driver_type; - int (*change_protocol)(struct rc_dev *dev, u64 rc_type); - char *module_name; - int (*rc_query) (struct dvb_usb_device *d); - int rc_interval; - bool bulk_mode; /* uses bulk mode */ -}; - -/** - * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one - * based on rc-core - * This is initialized/used only inside dvb-usb-remote.c. - * It shouldn't be set by the drivers. - */ -enum dvb_usb_mode { - DVB_RC_LEGACY, - DVB_RC_CORE, -}; - -/** - * struct dvb_usb_device_properties - properties of a dvb-usb-device - * @usb_ctrl: which USB device-side controller is in use. Needed for firmware - * download. - * @firmware: name of the firmware file. - * @download_firmware: called to download the firmware when the usb_ctrl is - * DEVICE_SPECIFIC. - * @no_reconnect: device doesn't do a reconnect after downloading the firmware, - * so do the warm initialization right after it - * - * @size_of_priv: how many bytes shall be allocated for the private field - * of struct dvb_usb_device. - * - * @power_ctrl: called to enable/disable power of the device. - * @read_mac_address: called to read the MAC address of the device. - * @identify_state: called to determine the state (cold or warm), when it - * is not distinguishable by the USB IDs. - * - * @rc: remote controller properties - * - * @i2c_algo: i2c_algorithm if the device has I2CoverUSB. - * - * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic - * endpoint which received control messages with bulk transfers. When this - * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write- - * helper functions. - * - * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate - * endpoint for responses to control messages sent with bulk transfers via - * the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used - * instead of the generic_bulk_ctrl_endpoint when reading usb responses in - * the dvb_usb_generic_rw helper function. - * - * @num_device_descs: number of struct dvb_usb_device_description in @devices - * @devices: array of struct dvb_usb_device_description compatibles with these - * properties. - */ -#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 -struct dvb_usb_device_properties { - -#define DVB_USB_IS_AN_I2C_ADAPTER 0x01 - int caps; - -#define DEVICE_SPECIFIC 0 -#define CYPRESS_AN2135 1 -#define CYPRESS_AN2235 2 -#define CYPRESS_FX2 3 - int usb_ctrl; - int (*download_firmware) (struct usb_device *, const struct firmware *); - const char *firmware; - int no_reconnect; - - int size_of_priv; - - int num_adapters; - struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; - - int (*power_ctrl) (struct dvb_usb_device *, int); - int (*read_mac_address) (struct dvb_usb_device *, u8 []); - int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *, - struct dvb_usb_device_description **, int *); - - struct { - enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */ - struct dvb_rc_legacy legacy; - struct dvb_rc core; - } rc; - - struct i2c_algorithm *i2c_algo; - - int generic_bulk_ctrl_endpoint; - int generic_bulk_ctrl_endpoint_response; - - int num_device_descs; - struct dvb_usb_device_description devices[12]; -}; - -/** - * struct usb_data_stream - generic object of an USB stream - * @buf_num: number of buffer allocated. - * @buf_size: size of each buffer in buf_list. - * @buf_list: array containing all allocate buffers for streaming. - * @dma_addr: list of dma_addr_t for each buffer in buf_list. - * - * @urbs_initialized: number of URBs initialized. - * @urbs_submitted: number of URBs submitted. - */ -#define MAX_NO_URBS_FOR_DATA_STREAM 10 -struct usb_data_stream { - struct usb_device *udev; - struct usb_data_stream_properties props; - -#define USB_STATE_INIT 0x00 -#define USB_STATE_URB_BUF 0x01 - int state; - - void (*complete) (struct usb_data_stream *, u8 *, size_t); - - struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; - int buf_num; - unsigned long buf_size; - u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; - dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; - - int urbs_initialized; - int urbs_submitted; - - void *user_priv; -}; - -/** - * struct dvb_usb_adapter - a DVB adapter on a USB device - * @id: index of this adapter (starting with 0). - * - * @feedcount: number of reqested feeds (used for streaming-activation) - * @pid_filtering: is hardware pid_filtering used or not. - * - * @pll_addr: I2C address of the tuner for programming - * @pll_init: array containing the initialization buffer - * @pll_desc: pointer to the appropriate struct dvb_pll_desc - * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board - * - * @dvb_adap: device's dvb_adapter. - * @dmxdev: device's dmxdev. - * @demux: device's software demuxer. - * @dvb_net: device's dvb_net interfaces. - * @dvb_frontend: device's frontend. - * @max_feed_count: how many feeds can be handled simultaneously by this - * device - * - * @fe_init: rerouted frontend-init (wakeup) function. - * @fe_sleep: rerouted frontend-sleep function. - * - * @stream: the usb data stream. - */ -struct dvb_usb_adapter { - struct dvb_usb_device *dev; - struct dvb_usb_adapter_properties props; - -#define DVB_USB_ADAP_STATE_INIT 0x000 -#define DVB_USB_ADAP_STATE_DVB 0x001 - int state; - - u8 id; - - int feedcount; - int pid_filtering; - - /* dvb */ - struct dvb_adapter dvb_adap; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvb_net; - struct dvb_frontend *fe; - int max_feed_count; - - int (*fe_init) (struct dvb_frontend *); - int (*fe_sleep) (struct dvb_frontend *); - - struct usb_data_stream stream; - - void *priv; -}; - -/** - * struct dvb_usb_device - object of a DVB USB device - * @props: copy of the struct dvb_usb_properties this device belongs to. - * @desc: pointer to the device's struct dvb_usb_device_description. - * @state: initialization and runtime state of the device. - * - * @powered: indicated whether the device is power or not. - * Powered is in/decremented for each call to modify the state. - * @udev: pointer to the device's struct usb_device. - * - * @usb_mutex: semaphore of USB control messages (reading needs two messages) - * @i2c_mutex: semaphore for i2c-transfers - * - * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB - * - * @rc_dev: rc device for the remote control (rc-core mode) - * @input_dev: input device for the remote control (legacy mode) - * @rc_query_work: struct work_struct frequent rc queries - * @last_event: last triggered event - * @last_state: last state (no, pressed, repeat) - * @owner: owner of the dvb_adapter - * @priv: private data of the actual driver (allocate by dvb-usb, size defined - * in size_of_priv of dvb_usb_properties). - */ -struct dvb_usb_device { - struct dvb_usb_device_properties props; - struct dvb_usb_device_description *desc; - - struct usb_device *udev; - -#define DVB_USB_STATE_INIT 0x000 -#define DVB_USB_STATE_I2C 0x001 -#define DVB_USB_STATE_DVB 0x002 -#define DVB_USB_STATE_REMOTE 0x004 - int state; - - int powered; - - /* locking */ - struct mutex usb_mutex; - - /* i2c */ - struct mutex i2c_mutex; - struct i2c_adapter i2c_adap; - - int num_adapters_initialized; - struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; - - /* remote control */ - struct rc_dev *rc_dev; - struct input_dev *input_dev; - char rc_phys[64]; - struct delayed_work rc_query_work; - u32 last_event; - int last_state; - - struct module *owner; - - void *priv; -}; - -extern int dvb_usb_device_init(struct usb_interface *, - struct dvb_usb_device_properties *, - struct module *, struct dvb_usb_device **, - short *adapter_nums); -extern void dvb_usb_device_exit(struct usb_interface *); - -/* the generic read/write method for device control */ -extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int); -extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); - -/* commonly used remote control parsing */ -extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); - -/* commonly used firmware download types and function */ -struct hexline { - u8 len; - u32 addr; - u8 type; - u8 data[255]; - u8 chk; -}; -extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type); -extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos); - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -/* dvb-usb-i2c.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for (de-)initializing an I2C adapter. - */ -#include "dvb-usb-common.h" - -int dvb_usb_i2c_init(struct dvb_usb_device *d) -{ - int ret = 0; - - if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER)) - return 0; - - if (d->props.i2c_algo == NULL) { - err("no i2c algorithm specified"); - return -EINVAL; - } - - strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); - d->i2c_adap.algo = d->props.i2c_algo; - d->i2c_adap.algo_data = NULL; - d->i2c_adap.dev.parent = &d->udev->dev; - - i2c_set_adapdata(&d->i2c_adap, d); - - if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0) - err("could not add i2c adapter"); - - d->state |= DVB_USB_STATE_I2C; - - return ret; -} - -int dvb_usb_i2c_exit(struct dvb_usb_device *d) -{ - if (d->state & DVB_USB_STATE_I2C) - i2c_del_adapter(&d->i2c_adap); - d->state &= ~DVB_USB_STATE_I2C; - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,322 +0,0 @@ -/* dvb-usb-ids.h is part of the DVB USB library. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see - * dvb-usb-init.c for copyright information. - * - * a header file containing define's for the USB device supported by the - * various drivers. - */ -#ifndef _DVB_USB_IDS_H_ -#define _DVB_USB_IDS_H_ - -/* Vendor IDs */ -#define USB_VID_ADSTECH 0x06e1 -#define USB_VID_AFATECH 0x15a4 -#define USB_VID_ALCOR_MICRO 0x058f -#define USB_VID_ALINK 0x05e3 -#define USB_VID_AMT 0x1c73 -#define USB_VID_ANCHOR 0x0547 -#define USB_VID_ANSONIC 0x10b9 -#define USB_VID_ANUBIS_ELECTRONIC 0x10fd -#define USB_VID_ASUS 0x0b05 -#define USB_VID_AVERMEDIA 0x07ca -#define USB_VID_COMPRO 0x185b -#define USB_VID_COMPRO_UNK 0x145f -#define USB_VID_CONEXANT 0x0572 -#define USB_VID_CYPRESS 0x04b4 -#define USB_VID_DIBCOM 0x10b8 -#define USB_VID_DPOSH 0x1498 -#define USB_VID_DVICO 0x0fe9 -#define USB_VID_E3C 0x18b4 -#define USB_VID_ELGATO 0x0fd9 -#define USB_VID_EMPIA 0xeb1a -#define USB_VID_GENPIX 0x09c0 -#define USB_VID_GRANDTEC 0x5032 -#define USB_VID_GTEK 0x1f4d -#define USB_VID_HANFTEK 0x15f4 -#define USB_VID_HAUPPAUGE 0x2040 -#define USB_VID_HYPER_PALTEK 0x1025 -#define USB_VID_INTEL 0x8086 -#define USB_VID_KWORLD 0xeb2a -#define USB_VID_KWORLD_2 0x1b80 -#define USB_VID_KYE 0x0458 -#define USB_VID_LEADTEK 0x0413 -#define USB_VID_LITEON 0x04ca -#define USB_VID_MEDION 0x1660 -#define USB_VID_MIGLIA 0x18f3 -#define USB_VID_MSI 0x0db0 -#define USB_VID_MSI_2 0x1462 -#define USB_VID_OPERA1 0x695c -#define USB_VID_PINNACLE 0x2304 -#define USB_VID_PCTV 0x2013 -#define USB_VID_PIXELVIEW 0x1554 -#define USB_VID_TECHNOTREND 0x0b48 -#define USB_VID_TERRATEC 0x0ccd -#define USB_VID_TELESTAR 0x10b9 -#define USB_VID_VISIONPLUS 0x13d3 -#define USB_VID_SONY 0x1415 -#define USB_VID_TWINHAN 0x1822 -#define USB_VID_ULTIMA_ELECTRONIC 0x05d8 -#define USB_VID_UNIWILL 0x1584 -#define USB_VID_WIDEVIEW 0x14aa -#define USB_VID_GIGABYTE 0x1044 -#define USB_VID_YUAN 0x1164 -#define USB_VID_XTENSIONS 0x1ae7 -#define USB_VID_HUMAX_COEX 0x10b9 -#define USB_VID_774 0x7a69 -#define USB_VID_EVOLUTEPC 0x1e59 -#define USB_VID_AZUREWAVE 0x13d3 -#define USB_VID_TECHNISAT 0x14f7 - -/* Product IDs */ -#define USB_PID_ADSTECH_USB2_COLD 0xa333 -#define USB_PID_ADSTECH_USB2_WARM 0xa334 -#define USB_PID_AFATECH_AF9005 0x9020 -#define USB_PID_AFATECH_AF9015_9015 0x9015 -#define USB_PID_AFATECH_AF9015_9016 0x9016 -#define USB_PID_TREKSTOR_DVBT 0x901b -#define USB_VID_ALINK_DTU 0xf170 -#define USB_PID_ANSONIC_DVBT_USB 0x6000 -#define USB_PID_ANYSEE 0x861f -#define USB_PID_AZUREWAVE_AD_TU700 0x3237 -#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 -#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 -#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 -#define USB_PID_AVERMEDIA_DVBT_USB2_WARM 0xa801 -#define USB_PID_COMPRO_DVBU2000_COLD 0xd000 -#define USB_PID_COMPRO_DVBU2000_WARM 0xd001 -#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c -#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d -#define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 -#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 -#define USB_PID_CONCEPTRONIC_CTVDIGRCU 0xe397 -#define USB_PID_CONEXANT_D680_DMB 0x86d6 -#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 -#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 -#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 -#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9 -#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6 -#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 -#define USB_PID_DIBCOM_STK7700P 0x1e14 -#define USB_PID_DIBCOM_STK7700P_PC 0x1e78 -#define USB_PID_DIBCOM_STK7700D 0x1ef0 -#define USB_PID_DIBCOM_STK7700_U7000 0x7001 -#define USB_PID_DIBCOM_STK7070P 0x1ebc -#define USB_PID_DIBCOM_STK7070PD 0x1ebe -#define USB_PID_DIBCOM_STK807XP 0x1f90 -#define USB_PID_DIBCOM_STK807XPVR 0x1f98 -#define USB_PID_DIBCOM_STK8096GP 0x1fa0 -#define USB_PID_DIBCOM_NIM8096MD 0x1fa8 -#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 -#define USB_PID_DIBCOM_STK7770P 0x1e80 -#define USB_PID_DIBCOM_NIM7090 0x1bb2 -#define USB_PID_DIBCOM_TFE7090PVR 0x1bb4 -#define USB_PID_DIBCOM_NIM9090M 0x2383 -#define USB_PID_DIBCOM_NIM9090MD 0x2384 -#define USB_PID_DPOSH_M9206_COLD 0x9206 -#define USB_PID_DPOSH_M9206_WARM 0xa090 -#define USB_PID_E3C_EC168 0x1689 -#define USB_PID_E3C_EC168_2 0xfffa -#define USB_PID_E3C_EC168_3 0xfffb -#define USB_PID_E3C_EC168_4 0x1001 -#define USB_PID_E3C_EC168_5 0x1002 -#define USB_PID_UNIWILL_STK7700P 0x6003 -#define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 -#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 -#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 -#define USB_PID_INTEL_CE9500 0x9500 -#define USB_PID_KWORLD_399U 0xe399 -#define USB_PID_KWORLD_399U_2 0xe400 -#define USB_PID_KWORLD_395U 0xe396 -#define USB_PID_KWORLD_395U_2 0xe39b -#define USB_PID_KWORLD_395U_3 0xe395 -#define USB_PID_KWORLD_395U_4 0xe39a -#define USB_PID_KWORLD_MC810 0xc810 -#define USB_PID_KWORLD_PC160_2T 0xc160 -#define USB_PID_KWORLD_PC160_T 0xc161 -#define USB_PID_KWORLD_UB383_T 0xe383 -#define USB_PID_KWORLD_VSTREAM_COLD 0x17de -#define USB_PID_KWORLD_VSTREAM_WARM 0x17df -#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 -#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 -#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097 -#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099 -#define USB_PID_TWINHAN_VP7041_COLD 0x3201 -#define USB_PID_TWINHAN_VP7041_WARM 0x3202 -#define USB_PID_TWINHAN_VP7020_COLD 0x3203 -#define USB_PID_TWINHAN_VP7020_WARM 0x3204 -#define USB_PID_TWINHAN_VP7045_COLD 0x3205 -#define USB_PID_TWINHAN_VP7045_WARM 0x3206 -#define USB_PID_TWINHAN_VP7021_COLD 0x3207 -#define USB_PID_TWINHAN_VP7021_WARM 0x3208 -#define USB_PID_TINYTWIN 0x3226 -#define USB_PID_TINYTWIN_2 0xe402 -#define USB_PID_TINYTWIN_3 0x9016 -#define USB_PID_DNTV_TINYUSB2_COLD 0x3223 -#define USB_PID_DNTV_TINYUSB2_WARM 0x3224 -#define USB_PID_ULTIMA_TVBOX_COLD 0x8105 -#define USB_PID_ULTIMA_TVBOX_WARM 0x8106 -#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107 -#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108 -#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235 -#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109 -#define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a -#define USB_PID_ARTEC_T14_COLD 0x810b -#define USB_PID_ARTEC_T14_WARM 0x810c -#define USB_PID_ARTEC_T14BR 0x810f -#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 -#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 -#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e -#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f -#define USB_PID_HANFTEK_UMT_010_COLD 0x0001 -#define USB_PID_HANFTEK_UMT_010_WARM 0x0015 -#define USB_PID_DTT200U_COLD 0x0201 -#define USB_PID_DTT200U_WARM 0x0301 -#define USB_PID_WT220U_ZAP250_COLD 0x0220 -#define USB_PID_WT220U_COLD 0x0222 -#define USB_PID_WT220U_WARM 0x0221 -#define USB_PID_WT220U_FC_COLD 0x0225 -#define USB_PID_WT220U_FC_WARM 0x0226 -#define USB_PID_WT220U_ZL0353_COLD 0x022a -#define USB_PID_WT220U_ZL0353_WARM 0x022b -#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 -#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 -#define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941 -#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 -#define USB_PID_HAUPPAUGE_NOVA_T_500_3 0x8400 -#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 -#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 -#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 -#define USB_PID_HAUPPAUGE_MYTV_T 0x7080 -#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 -#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200 -#define USB_PID_HAUPPAUGE_TIGER_ATSC 0xb200 -#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210 0xb210 -#define USB_PID_AVERMEDIA_EXPRESS 0xb568 -#define USB_PID_AVERMEDIA_VOLAR 0xa807 -#define USB_PID_AVERMEDIA_VOLAR_2 0xb808 -#define USB_PID_AVERMEDIA_VOLAR_A868R 0xa868 -#define USB_PID_AVERMEDIA_MCE_USB_M038 0x1228 -#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039 -#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039 -#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039 -#define USB_PID_AVERMEDIA_VOLAR_X 0xa815 -#define USB_PID_AVERMEDIA_VOLAR_X_2 0x8150 -#define USB_PID_AVERMEDIA_A309 0xa309 -#define USB_PID_AVERMEDIA_A310 0xa310 -#define USB_PID_AVERMEDIA_A850 0x850a -#define USB_PID_AVERMEDIA_A850T 0x850b -#define USB_PID_AVERMEDIA_A805 0xa805 -#define USB_PID_AVERMEDIA_A815M 0x815a -#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 -#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d -#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a -#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 -#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 -#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060 -#define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 -#define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 -#define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab -#define USB_PID_TERRATEC_T3 0x10a0 -#define USB_PID_TERRATEC_T5 0x10a1 -#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e -#define USB_PID_PINNACLE_PCTV2000E 0x022c -#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 -#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 -#define USB_PID_PINNACLE_PCTV71E 0x022b -#define USB_PID_PINNACLE_PCTV72E 0x0236 -#define USB_PID_PINNACLE_PCTV73E 0x0237 -#define USB_PID_PINNACLE_PCTV310E 0x3211 -#define USB_PID_PINNACLE_PCTV801E 0x023a -#define USB_PID_PINNACLE_PCTV801E_SE 0x023b -#define USB_PID_PINNACLE_PCTV73A 0x0243 -#define USB_PID_PINNACLE_PCTV73ESE 0x0245 -#define USB_PID_PINNACLE_PCTV74E 0x0246 -#define USB_PID_PINNACLE_PCTV282E 0x0248 -#define USB_PID_PIXELVIEW_SBTVD 0x5010 -#define USB_PID_PCTV_200E 0x020e -#define USB_PID_PCTV_400E 0x020f -#define USB_PID_PCTV_450E 0x0222 -#define USB_PID_NEBULA_DIGITV 0x0201 -#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 -#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 -#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM 0xd501 -#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD 0xdb00 -#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM 0xdb01 -#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD 0xdb10 -#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM 0xdb11 -#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD 0xdb50 -#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51 -#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 -#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 -#define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 -#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2 0xdb98 -#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 -#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 -#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 -#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 -#define USB_PID_MEDION_MD95700 0x0932 -#define USB_PID_MSI_MEGASKY580 0x5580 -#define USB_PID_MSI_MEGASKY580_55801 0x5581 -#define USB_PID_KYE_DVB_T_COLD 0x701e -#define USB_PID_KYE_DVB_T_WARM 0x701f -#define USB_PID_LITEON_DVB_T_COLD 0xf000 -#define USB_PID_LITEON_DVB_T_WARM 0xf001 -#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 -#define USB_PID_DIGIVOX_MINI_SL_WARM 0xe361 -#define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6 -#define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7 -#define USB_PID_WINFAST_DTV2000DS 0x6a04 -#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 -#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 -#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 -#define USB_PID_WINFAST_DTV_DONGLE_H 0x60f6 -#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01 -#define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029 -#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 -#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 -#define USB_PID_GENPIX_8PSK_REV_2 0x0202 -#define USB_PID_GENPIX_SKYWALKER_1 0x0203 -#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204 -#define USB_PID_GENPIX_SKYWALKER_2 0x0206 -#define USB_PID_SIGMATEK_DVB_110 0x6610 -#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 -#define USB_PID_MSI_DIGIVOX_DUO 0x8801 -#define USB_PID_OPERA1_COLD 0x2830 -#define USB_PID_OPERA1_WARM 0x3829 -#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 -#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 -#define USB_PID_GIGABYTE_U7000 0x7001 -#define USB_PID_GIGABYTE_U8000 0x7002 -#define USB_PID_ASUS_U3000 0x171f -#define USB_PID_ASUS_U3000H 0x1736 -#define USB_PID_ASUS_U3100 0x173f -#define USB_PID_YUAN_EC372S 0x1edc -#define USB_PID_YUAN_STK7700PH 0x1f08 -#define USB_PID_YUAN_PD378S 0x2edc -#define USB_PID_YUAN_MC770 0x0871 -#define USB_PID_YUAN_STK7700D 0x1efc -#define USB_PID_YUAN_STK7700D_2 0x1e8c -#define USB_PID_DW2102 0x2102 -#define USB_PID_XTENSIONS_XD_380 0x0381 -#define USB_PID_TELESTAR_STARSTICK_2 0x8000 -#define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807 -#define USB_PID_SONY_PLAYTV 0x0003 -#define USB_PID_MYGICA_D689 0xd811 -#define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 -#define USB_PID_ELGATO_EYETV_DTT 0x0021 -#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 -#define USB_PID_ELGATO_EYETV_SAT 0x002a -#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000 -#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001 -#define USB_PID_FRIIO_WHITE 0x0001 -#define USB_PID_TVWAY_PLUS 0x0002 -#define USB_PID_SVEON_STV20 0xe39d -#define USB_PID_AZUREWAVE_AZ6027 0x3275 -#define USB_PID_TERRATEC_DVBS2CI_V1 0x10a4 -#define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac -#define USB_PID_TECHNISAT_USB2_HDCI_V1 0x0001 -#define USB_PID_TECHNISAT_USB2_HDCI_V2 0x0002 -#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2 0x0004 -#define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500 -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,288 +0,0 @@ -/* - * DVB USB library - provides a generic interface for a DVB USB device driver. - * - * dvb-usb-init.c - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dvb-usb-common.h" - -/* debug */ -int dvb_usb_debug; -module_param_named(debug, dvb_usb_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS); - -int dvb_usb_disable_rc_polling; -module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); -MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); - -static int dvb_usb_force_pid_filter_usage; -module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); -MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); - -static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) -{ - struct dvb_usb_adapter *adap; - int ret, n; - - for (n = 0; n < d->props.num_adapters; n++) { - adap = &d->adapter[n]; - adap->dev = d; - adap->id = n; - - memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties)); - - /* speed - when running at FULL speed we need a HW PID filter */ - if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); - return -ENODEV; - } - - if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) || - (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - info("will use the device's hardware PID filter (table count: %d).", adap->props.pid_filter_count); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props.pid_filter_count; - } else { - info("will pass the complete MPEG2 transport stream to the software demuxer."); - adap->pid_filtering = 0; - adap->max_feed_count = 255; - } - - if (!adap->pid_filtering && - dvb_usb_force_pid_filter_usage && - adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) { - info("pid filter enabled by module option."); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props.pid_filter_count; - } - - if (adap->props.size_of_priv > 0) { - adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL); - if (adap->priv == NULL) { - err("no memory for priv for adapter %d.", n); - return -ENOMEM; - } - } - - if ((ret = dvb_usb_adapter_stream_init(adap)) || - (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || - (ret = dvb_usb_adapter_frontend_init(adap))) { - return ret; - } - - d->num_adapters_initialized++; - d->state |= DVB_USB_STATE_DVB; - } - - /* - * when reloading the driver w/o replugging the device - * sometimes a timeout occures, this helps - */ - if (d->props.generic_bulk_ctrl_endpoint != 0) { - usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - } - - return 0; -} - -static int dvb_usb_adapter_exit(struct dvb_usb_device *d) -{ - int n; - - for (n = 0; n < d->num_adapters_initialized; n++) { - dvb_usb_adapter_frontend_exit(&d->adapter[n]); - dvb_usb_adapter_dvb_exit(&d->adapter[n]); - dvb_usb_adapter_stream_exit(&d->adapter[n]); - kfree(d->adapter[n].priv); - } - d->num_adapters_initialized = 0; - d->state &= ~DVB_USB_STATE_DVB; - return 0; -} - - -/* general initialization functions */ -static int dvb_usb_exit(struct dvb_usb_device *d) -{ - deb_info("state before exiting everything: %x\n", d->state); - dvb_usb_remote_exit(d); - dvb_usb_adapter_exit(d); - dvb_usb_i2c_exit(d); - deb_info("state should be zero now: %x\n", d->state); - d->state = DVB_USB_STATE_INIT; - kfree(d->priv); - kfree(d); - return 0; -} - -static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) -{ - int ret = 0; - - mutex_init(&d->usb_mutex); - mutex_init(&d->i2c_mutex); - - d->state = DVB_USB_STATE_INIT; - - if (d->props.size_of_priv > 0) { - d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); - if (d->priv == NULL) { - err("no memory for priv in 'struct dvb_usb_device'"); - return -ENOMEM; - } - } - - /* check the capabilities and set appropriate variables */ - dvb_usb_device_power_ctrl(d, 1); - - if ((ret = dvb_usb_i2c_init(d)) || - (ret = dvb_usb_adapter_init(d, adapter_nums))) { - dvb_usb_exit(d); - return ret; - } - - if ((ret = dvb_usb_remote_init(d))) - err("could not initialize remote control."); - - dvb_usb_device_power_ctrl(d, 0); - - return 0; -} - -/* determine the name and the state of the just found USB device */ -static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold) -{ - int i, j; - struct dvb_usb_device_description *desc = NULL; - - *cold = -1; - - for (i = 0; i < props->num_device_descs; i++) { - - for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) { - deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct); - if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && - props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { - *cold = 1; - desc = &props->devices[i]; - break; - } - } - - if (desc != NULL) - break; - - for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) { - deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct); - if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && - props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { - *cold = 0; - desc = &props->devices[i]; - break; - } - } - } - - if (desc != NULL && props->identify_state != NULL) - props->identify_state(udev, props, &desc, cold); - - return desc; -} - -int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - if (onoff) - d->powered++; - else - d->powered--; - - if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ - deb_info("power control: %d\n", onoff); - if (d->props.power_ctrl) - return d->props.power_ctrl(d, onoff); - } - return 0; -} - -/* - * USB - */ -int dvb_usb_device_init(struct usb_interface *intf, - struct dvb_usb_device_properties *props, - struct module *owner, struct dvb_usb_device **du, - short *adapter_nums) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct dvb_usb_device *d = NULL; - struct dvb_usb_device_description *desc = NULL; - - int ret = -ENOMEM, cold = 0; - - if (du != NULL) - *du = NULL; - - if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { - deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); - return -ENODEV; - } - - if (cold) { - info("found a '%s' in cold state, will try to load a firmware", desc->name); - ret = dvb_usb_download_firmware(udev, props); - if (!props->no_reconnect || ret != 0) - return ret; - } - - info("found a '%s' in warm state.", desc->name); - d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); - if (d == NULL) { - err("no memory for 'struct dvb_usb_device'"); - return -ENOMEM; - } - - d->udev = udev; - memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); - d->desc = desc; - d->owner = owner; - - usb_set_intfdata(intf, d); - - if (du != NULL) - *du = d; - - ret = dvb_usb_init(d, adapter_nums); - - if (ret == 0) - info("%s successfully initialized and connected.", desc->name); - else - info("%s error while loading driver (%d)", desc->name, ret); - return ret; -} -EXPORT_SYMBOL(dvb_usb_device_init); - -void dvb_usb_device_exit(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name = "generic DVB-USB module"; - - usb_set_intfdata(intf, NULL); - if (d != NULL && d->desc != NULL) { - name = d->desc->name; - dvb_usb_exit(d); - } - info("%s successfully deinitialized and disconnected.", name); - -} -EXPORT_SYMBOL(dvb_usb_device_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,364 +0,0 @@ -/* dvb-usb-remote.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for initializing the input-device and for handling remote-control-queries. - */ -#include "dvb-usb-common.h" -#include - -static int legacy_dvb_usb_getkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) -{ - struct dvb_usb_device *d = input_get_drvdata(dev); - - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - int i; - - /* See if we can match the raw key code. */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (keymap[i].scancode == scancode) { - *keycode = keymap[i].keycode; - return 0; - } - - /* - * If is there extra space, returns KEY_RESERVED, - * otherwise, input core won't let legacy_dvb_usb_setkeycode - * to work - */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (keymap[i].keycode == KEY_RESERVED || - keymap[i].keycode == KEY_UNKNOWN) { - *keycode = KEY_RESERVED; - return 0; - } - - return -EINVAL; -} - -static int legacy_dvb_usb_setkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode) -{ - struct dvb_usb_device *d = input_get_drvdata(dev); - - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - int i; - - /* Search if it is replacing an existing keycode */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (keymap[i].scancode == scancode) { - keymap[i].keycode = keycode; - return 0; - } - - /* Search if is there a clean entry. If so, use it */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (keymap[i].keycode == KEY_RESERVED || - keymap[i].keycode == KEY_UNKNOWN) { - keymap[i].scancode = scancode; - keymap[i].keycode = keycode; - return 0; - } - - /* - * FIXME: Currently, it is not possible to increase the size of - * scancode table. For it to happen, one possibility - * would be to allocate a table with key_map_size + 1, - * copying data, appending the new key on it, and freeing - * the old one - or maybe just allocating some spare space - */ - - return -EINVAL; -} - -/* Remote-control poll function - called every dib->rc_query_interval ms to see - * whether the remote control has received anything. - * - * TODO: Fix the repeat rate of the input device. - */ -static void legacy_dvb_usb_read_remote_control(struct work_struct *work) -{ - struct dvb_usb_device *d = - container_of(work, struct dvb_usb_device, rc_query_work.work); - u32 event; - int state; - - /* TODO: need a lock here. We can simply skip checking for the remote control - if we're busy. */ - - /* when the parameter has been set to 1 via sysfs while the driver was running */ - if (dvb_usb_disable_rc_polling) - return; - - if (d->props.rc.legacy.rc_query(d,&event,&state)) { - err("error while querying for an remote control event."); - goto schedule; - } - - - switch (state) { - case REMOTE_NO_KEY_PRESSED: - break; - case REMOTE_KEY_PRESSED: - deb_rc("key pressed\n"); - d->last_event = event; - case REMOTE_KEY_REPEAT: - deb_rc("key repeated\n"); - input_event(d->input_dev, EV_KEY, event, 1); - input_sync(d->input_dev); - input_event(d->input_dev, EV_KEY, d->last_event, 0); - input_sync(d->input_dev); - break; - default: - break; - } - -/* improved repeat handling ??? - switch (state) { - case REMOTE_NO_KEY_PRESSED: - deb_rc("NO KEY PRESSED\n"); - if (d->last_state != REMOTE_NO_KEY_PRESSED) { - deb_rc("releasing event %d\n",d->last_event); - input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); - input_sync(d->rc_input_dev); - } - d->last_state = REMOTE_NO_KEY_PRESSED; - d->last_event = 0; - break; - case REMOTE_KEY_PRESSED: - deb_rc("KEY PRESSED\n"); - deb_rc("pressing event %d\n",event); - - input_event(d->rc_input_dev, EV_KEY, event, 1); - input_sync(d->rc_input_dev); - - d->last_event = event; - d->last_state = REMOTE_KEY_PRESSED; - break; - case REMOTE_KEY_REPEAT: - deb_rc("KEY_REPEAT\n"); - if (d->last_state != REMOTE_NO_KEY_PRESSED) { - deb_rc("repeating event %d\n",d->last_event); - input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); - input_sync(d->rc_input_dev); - d->last_state = REMOTE_KEY_REPEAT; - } - default: - break; - } -*/ - -schedule: - schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval)); -} - -static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) -{ - int i, err, rc_interval; - struct input_dev *input_dev; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - input_dev->evbit[0] = BIT_MASK(EV_KEY); - input_dev->name = "IR-receiver inside an USB DVB receiver"; - input_dev->phys = d->rc_phys; - usb_to_input_id(d->udev, &input_dev->id); - input_dev->dev.parent = &d->udev->dev; - d->input_dev = input_dev; - d->rc_dev = NULL; - - input_dev->getkeycode = legacy_dvb_usb_getkeycode; - input_dev->setkeycode = legacy_dvb_usb_setkeycode; - - /* set the bits for the keys */ - deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size); - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - deb_rc("setting bit for event %d item %d\n", - d->props.rc.legacy.rc_map_table[i].keycode, i); - set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit); - } - - /* setting these two values to non-zero, we have to manage key repeats */ - input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval; - input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150; - - input_set_drvdata(input_dev, d); - - err = input_register_device(input_dev); - if (err) - input_free_device(input_dev); - - rc_interval = d->props.rc.legacy.rc_interval; - - INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control); - - info("schedule remote query interval to %d msecs.", rc_interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(rc_interval)); - - d->state |= DVB_USB_STATE_REMOTE; - - return err; -} - -/* Remote-control poll function - called every dib->rc_query_interval ms to see - * whether the remote control has received anything. - * - * TODO: Fix the repeat rate of the input device. - */ -static void dvb_usb_read_remote_control(struct work_struct *work) -{ - struct dvb_usb_device *d = - container_of(work, struct dvb_usb_device, rc_query_work.work); - int err; - - /* TODO: need a lock here. We can simply skip checking for the remote control - if we're busy. */ - - /* when the parameter has been set to 1 via sysfs while the - * driver was running, or when bulk mode is enabled after IR init - */ - if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode) - return; - - err = d->props.rc.core.rc_query(d); - if (err) - err("error %d while querying for an remote control event.", err); - - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->props.rc.core.rc_interval)); -} - -static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) -{ - int err, rc_interval; - struct rc_dev *dev; - - dev = rc_allocate_device(); - if (!dev) - return -ENOMEM; - - dev->driver_name = d->props.rc.core.module_name; - dev->map_name = d->props.rc.core.rc_codes; - dev->change_protocol = d->props.rc.core.change_protocol; - dev->allowed_protos = d->props.rc.core.allowed_protos; - dev->driver_type = d->props.rc.core.driver_type; - usb_to_input_id(d->udev, &dev->input_id); - dev->input_name = "IR-receiver inside an USB DVB receiver"; - dev->input_phys = d->rc_phys; - dev->dev.parent = &d->udev->dev; - dev->priv = d; - - err = rc_register_device(dev); - if (err < 0) { - rc_free_device(dev); - return err; - } - - d->input_dev = NULL; - d->rc_dev = dev; - - if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode) - return 0; - - /* Polling mode - initialize a work queue for handling it */ - INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); - - rc_interval = d->props.rc.core.rc_interval; - - info("schedule remote query interval to %d msecs.", rc_interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(rc_interval)); - - return 0; -} - -int dvb_usb_remote_init(struct dvb_usb_device *d) -{ - int err; - - if (dvb_usb_disable_rc_polling) - return 0; - - if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query) - d->props.rc.mode = DVB_RC_LEGACY; - else if (d->props.rc.core.rc_codes) - d->props.rc.mode = DVB_RC_CORE; - else - return 0; - - usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - - /* Start the remote-control polling. */ - if (d->props.rc.legacy.rc_interval < 40) - d->props.rc.legacy.rc_interval = 100; /* default */ - - if (d->props.rc.mode == DVB_RC_LEGACY) - err = legacy_dvb_usb_remote_init(d); - else - err = rc_core_dvb_usb_remote_init(d); - if (err) - return err; - - d->state |= DVB_USB_STATE_REMOTE; - - return 0; -} - -int dvb_usb_remote_exit(struct dvb_usb_device *d) -{ - if (d->state & DVB_USB_STATE_REMOTE) { - cancel_delayed_work_sync(&d->rc_query_work); - if (d->props.rc.mode == DVB_RC_LEGACY) - input_unregister_device(d->input_dev); - else - rc_unregister_device(d->rc_dev); - } - d->state &= ~DVB_USB_STATE_REMOTE; - return 0; -} - -#define DVB_USB_RC_NEC_EMPTY 0x00 -#define DVB_USB_RC_NEC_KEY_PRESSED 0x01 -#define DVB_USB_RC_NEC_KEY_REPEATED 0x02 -int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, - u8 keybuf[5], u32 *event, int *state) -{ - int i; - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - switch (keybuf[0]) { - case DVB_USB_RC_NEC_EMPTY: - break; - case DVB_USB_RC_NEC_KEY_PRESSED: - if ((u8) ~keybuf[1] != keybuf[2] || - (u8) ~keybuf[3] != keybuf[4]) { - deb_err("remote control checksum failed.\n"); - break; - } - /* See if we can match the raw key code. */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (rc5_custom(&keymap[i]) == keybuf[1] && - rc5_data(&keymap[i]) == keybuf[3]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - return 0; - } - deb_err("key mapping failed - no appropriate key found in keymapping\n"); - break; - case DVB_USB_RC_NEC_KEY_REPEATED: - *state = REMOTE_KEY_REPEAT; - break; - default: - deb_err("unknown type of remote status: %d\n",keybuf[0]); - break; - } - return 0; -} -EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/* dvb-usb-urb.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file keeps functions for initializing and handling the - * USB and URB stuff. - */ -#include "dvb-usb-common.h" - -int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, - u16 rlen, int delay_ms) -{ - int actlen,ret = -ENOMEM; - - if (!d || wbuf == NULL || wlen == 0) - return -EINVAL; - - if (d->props.generic_bulk_ctrl_endpoint == 0) { - err("endpoint for generic control not specified."); - return -EINVAL; - } - - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) - return ret; - - deb_xfer(">>> "); - debug_dump(wbuf,wlen,deb_xfer); - - ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, - 2000); - - if (ret) - err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); - else - ret = actlen != wlen ? -1 : 0; - - /* an answer is expected, and no error before */ - if (!ret && rbuf && rlen) { - if (delay_ms) - msleep(delay_ms); - - ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint_response ? - d->props.generic_bulk_ctrl_endpoint_response : - d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, - 2000); - - if (ret) - err("recv bulk message failed: %d",ret); - else { - deb_xfer("<<< "); - debug_dump(rbuf,actlen,deb_xfer); - } - } - - mutex_unlock(&d->usb_mutex); - return ret; -} -EXPORT_SYMBOL(dvb_usb_generic_rw); - -int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) -{ - return dvb_usb_generic_rw(d,buf,len,NULL,0,0); -} -EXPORT_SYMBOL(dvb_usb_generic_write); - -static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter(&adap->demux, buffer, length); -} - -static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter_204(&adap->demux, buffer, length); -} - -int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) -{ - adap->stream.udev = adap->dev->udev; - if (adap->props.caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) - adap->stream.complete = dvb_usb_data_complete_204; - else - adap->stream.complete = dvb_usb_data_complete; - adap->stream.user_priv = adap; - return usb_urb_init(&adap->stream, &adap->props.stream); -} - -int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) -{ - return usb_urb_exit(&adap->stream); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dw2102.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dw2102.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dw2102.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dw2102.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1933 +0,0 @@ -/* DVB USB framework compliant Linux driver for the - * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, - * TeVii S600, S630, S650, S660, S480, - * Prof 1100, 7500, - * Geniatech SU3000 Cards - * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dw2102.h" -#include "si21xx.h" -#include "stv0299.h" -#include "z0194a.h" -#include "stv0288.h" -#include "stb6000.h" -#include "eds1547.h" -#include "cx24116.h" -#include "tda1002x.h" -#include "mt312.h" -#include "zl10039.h" -#include "ds3000.h" -#include "stv0900.h" -#include "stv6110.h" -#include "stb6100.h" -#include "stb6100_proc.h" - -#ifndef USB_PID_DW2102 -#define USB_PID_DW2102 0x2102 -#endif - -#ifndef USB_PID_DW2104 -#define USB_PID_DW2104 0x2104 -#endif - -#ifndef USB_PID_DW3101 -#define USB_PID_DW3101 0x3101 -#endif - -#ifndef USB_PID_CINERGY_S -#define USB_PID_CINERGY_S 0x0064 -#endif - -#ifndef USB_PID_TEVII_S630 -#define USB_PID_TEVII_S630 0xd630 -#endif - -#ifndef USB_PID_TEVII_S650 -#define USB_PID_TEVII_S650 0xd650 -#endif - -#ifndef USB_PID_TEVII_S660 -#define USB_PID_TEVII_S660 0xd660 -#endif - -#ifndef USB_PID_TEVII_S480_1 -#define USB_PID_TEVII_S480_1 0xd481 -#endif - -#ifndef USB_PID_TEVII_S480_2 -#define USB_PID_TEVII_S480_2 0xd482 -#endif - -#ifndef USB_PID_PROF_1100 -#define USB_PID_PROF_1100 0xb012 -#endif - -#define DW210X_READ_MSG 0 -#define DW210X_WRITE_MSG 1 - -#define REG_1F_SYMBOLRATE_BYTE0 0x1f -#define REG_20_SYMBOLRATE_BYTE1 0x20 -#define REG_21_SYMBOLRATE_BYTE2 0x21 -/* on my own*/ -#define DW2102_VOLTAGE_CTRL (0x1800) -#define SU3000_STREAM_CTRL (0x1900) -#define DW2102_RC_QUERY (0x1a00) -#define DW2102_LED_CTRL (0x1b00) - -#define err_str "did not find the firmware file. (%s) " \ - "Please see linux/Documentation/dvb/ for more details " \ - "on firmware-problems." - -struct rc_map_dvb_usb_table_table { - struct rc_map_table *rc_keys; - int rc_keys_size; -}; - -struct su3000_state { - u8 initialized; -}; - -struct s6x0_state { - int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v); -}; - -/* debug */ -static int dvb_usb_dw2102_debug; -module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." - DVB_USB_DEBUG_STATUS); - -/* keymaps */ -static int ir_keymap; -module_param_named(keymap, ir_keymap, int, 0644); -MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..." - " 256=none"); - -/* demod probe */ -static int demod_probe = 1; -module_param_named(demod, demod_probe, int, 0644); -MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 " - "4=stv0903+stb6100(or-able))."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, - u16 index, u8 * data, u16 len, int flags) -{ - int ret; - u8 u8buf[len]; - - unsigned int pipe = (flags == DW210X_READ_MSG) ? - usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); - u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; - - if (flags == DW210X_WRITE_MSG) - memcpy(u8buf, data, len); - ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, - value, index , u8buf, len, 2000); - - if (flags == DW210X_READ_MSG) - memcpy(data, u8buf, len); - return ret; -} - -/* I2C */ -static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0, ret = 0; - u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; - u16 value; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 2: - /* read stv0299 register */ - value = msg[0].buf[0];/* register */ - for (i = 0; i < msg[1].len; i++) { - ret = dw210x_op_rw(d->udev, 0xb5, value + i, 0, - buf6, 2, DW210X_READ_MSG); - msg[1].buf[i] = buf6[0]; - } - break; - case 1: - switch (msg[0].addr) { - case 0x68: - /* write to stv0299 register */ - buf6[0] = 0x2a; - buf6[1] = msg[0].buf[0]; - buf6[2] = msg[0].buf[1]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 3, DW210X_WRITE_MSG); - break; - case 0x60: - if (msg[0].flags == 0) { - /* write to tuner pll */ - buf6[0] = 0x2c; - buf6[1] = 5; - buf6[2] = 0xc0; - buf6[3] = msg[0].buf[0]; - buf6[4] = msg[0].buf[1]; - buf6[5] = msg[0].buf[2]; - buf6[6] = msg[0].buf[3]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 7, DW210X_WRITE_MSG); - } else { - /* read from tuner */ - ret = dw210x_op_rw(d->udev, 0xb5, 0, 0, - buf6, 1, DW210X_READ_MSG); - msg[0].buf[0] = buf6[0]; - } - break; - case (DW2102_RC_QUERY): - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, - buf6, 2, DW210X_READ_MSG); - msg[0].buf[0] = buf6[0]; - msg[0].buf[1] = buf6[1]; - break; - case (DW2102_VOLTAGE_CTRL): - buf6[0] = 0x30; - buf6[1] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 2, DW210X_WRITE_MSG); - break; - } - - break; - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, - struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0; - u8 buf6[] = {0, 0, 0, 0, 0, 0, 0}; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 2: - /* read si2109 register by number */ - buf6[0] = msg[0].addr << 1; - buf6[1] = msg[0].len; - buf6[2] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - buf6, msg[0].len + 2, DW210X_WRITE_MSG); - /* read si2109 register */ - ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, - buf6, msg[1].len + 2, DW210X_READ_MSG); - memcpy(msg[1].buf, buf6 + 2, msg[1].len); - - break; - case 1: - switch (msg[0].addr) { - case 0x68: - /* write to si2109 register */ - buf6[0] = msg[0].addr << 1; - buf6[1] = msg[0].len; - memcpy(buf6 + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, - msg[0].len + 2, DW210X_WRITE_MSG); - break; - case(DW2102_RC_QUERY): - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, - buf6, 2, DW210X_READ_MSG); - msg[0].buf[0] = buf6[0]; - msg[0].buf[1] = buf6[1]; - break; - case(DW2102_VOLTAGE_CTRL): - buf6[0] = 0x30; - buf6[1] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, - buf6, 2, DW210X_WRITE_MSG); - break; - } - break; - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 2: { - /* read */ - /* first write first register number */ - u8 ibuf[msg[1].len + 2], obuf[3]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - obuf[2] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - /* second read registers */ - ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0, - ibuf, msg[1].len + 2, DW210X_READ_MSG); - memcpy(msg[1].buf, ibuf + 2, msg[1].len); - - break; - } - case 1: - switch (msg[0].addr) { - case 0x68: { - /* write to register */ - u8 obuf[msg[0].len + 2]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - break; - } - case 0x61: { - /* write to tuner */ - u8 obuf[msg[0].len + 2]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - break; - } - case(DW2102_RC_QUERY): { - u8 ibuf[2]; - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW210X_READ_MSG); - memcpy(msg[0].buf, ibuf , 2); - break; - } - case(DW2102_VOLTAGE_CTRL): { - u8 obuf[2]; - obuf[0] = 0x30; - obuf[1] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - break; - } - } - - break; - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0; - int len, i, j; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (j = 0; j < num; j++) { - switch (msg[j].addr) { - case(DW2102_RC_QUERY): { - u8 ibuf[2]; - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf , 2); - break; - } - case(DW2102_VOLTAGE_CTRL): { - u8 obuf[2]; - obuf[0] = 0x30; - obuf[1] = msg[j].buf[0]; - ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - break; - } - /*case 0x55: cx24116 - case 0x6a: stv0903 - case 0x68: ds3000, stv0903 - case 0x60: ts2020, stv6110, stb6100 */ - default: { - if (msg[j].flags == I2C_M_RD) { - /* read registers */ - u8 ibuf[msg[j].len + 2]; - ret = dw210x_op_rw(d->udev, 0xc3, - (msg[j].addr << 1) + 1, 0, - ibuf, msg[j].len + 2, - DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf + 2, msg[j].len); - mdelay(10); - } else if (((msg[j].buf[0] == 0xb0) && - (msg[j].addr == 0x68)) || - ((msg[j].buf[0] == 0xf7) && - (msg[j].addr == 0x55))) { - /* write firmware */ - u8 obuf[19]; - obuf[0] = msg[j].addr << 1; - obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len); - obuf[2] = msg[j].buf[0]; - len = msg[j].len - 1; - i = 1; - do { - memcpy(obuf + 3, msg[j].buf + i, - (len > 16 ? 16 : len)); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, (len > 16 ? 16 : len) + 3, - DW210X_WRITE_MSG); - i += 16; - len -= 16; - } while (len > 0); - } else { - /* write registers */ - u8 obuf[msg[j].len + 2]; - obuf[0] = msg[j].addr << 1; - obuf[1] = msg[j].len; - memcpy(obuf + 2, msg[j].buf, msg[j].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[j].len + 2, - DW210X_WRITE_MSG); - } - break; - } - } - - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int ret = 0, i; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 2: { - /* read */ - /* first write first register number */ - u8 ibuf[msg[1].len + 2], obuf[3]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - obuf[2] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - /* second read registers */ - ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, - ibuf, msg[1].len + 2, DW210X_READ_MSG); - memcpy(msg[1].buf, ibuf + 2, msg[1].len); - - break; - } - case 1: - switch (msg[0].addr) { - case 0x60: - case 0x0c: { - /* write to register */ - u8 obuf[msg[0].len + 2]; - obuf[0] = msg[0].addr << 1; - obuf[1] = msg[0].len; - memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - break; - } - case(DW2102_RC_QUERY): { - u8 ibuf[2]; - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW210X_READ_MSG); - memcpy(msg[0].buf, ibuf , 2); - break; - } - } - - break; - } - - for (i = 0; i < num; i++) { - deb_xfer("%02x:%02x: %s ", i, msg[i].addr, - msg[i].flags == 0 ? ">>>" : "<<<"); - debug_dump(msg[i].buf, msg[i].len, deb_xfer); - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct usb_device *udev; - int ret = 0; - int len, i, j; - - if (!d) - return -ENODEV; - udev = d->udev; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (j = 0; j < num; j++) { - switch (msg[j].addr) { - case (DW2102_RC_QUERY): { - u8 ibuf[5]; - ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 5, DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf + 3, 2); - break; - } - case (DW2102_VOLTAGE_CTRL): { - u8 obuf[2]; - - obuf[0] = 1; - obuf[1] = msg[j].buf[1];/* off-on */ - ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - obuf[0] = 3; - obuf[1] = msg[j].buf[0];/* 13v-18v */ - ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - break; - } - case (DW2102_LED_CTRL): { - u8 obuf[2]; - - obuf[0] = 5; - obuf[1] = msg[j].buf[0]; - ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, - obuf, 2, DW210X_WRITE_MSG); - break; - } - /*case 0x55: cx24116 - case 0x6a: stv0903 - case 0x68: ds3000, stv0903 - case 0x60: ts2020, stv6110, stb6100 - case 0xa0: eeprom */ - default: { - if (msg[j].flags == I2C_M_RD) { - /* read registers */ - u8 ibuf[msg[j].len]; - ret = dw210x_op_rw(d->udev, 0x91, 0, 0, - ibuf, msg[j].len, - DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf, msg[j].len); - break; - } else if ((msg[j].buf[0] == 0xb0) && - (msg[j].addr == 0x68)) { - /* write firmware */ - u8 obuf[19]; - obuf[0] = (msg[j].len > 16 ? - 18 : msg[j].len + 1); - obuf[1] = msg[j].addr << 1; - obuf[2] = msg[j].buf[0]; - len = msg[j].len - 1; - i = 1; - do { - memcpy(obuf + 3, msg[j].buf + i, - (len > 16 ? 16 : len)); - ret = dw210x_op_rw(d->udev, 0x80, 0, 0, - obuf, (len > 16 ? 16 : len) + 3, - DW210X_WRITE_MSG); - i += 16; - len -= 16; - } while (len > 0); - } else if (j < (num - 1)) { - /* write register addr before read */ - u8 obuf[msg[j].len + 2]; - obuf[0] = msg[j + 1].len; - obuf[1] = (msg[j].addr << 1); - memcpy(obuf + 2, msg[j].buf, msg[j].len); - ret = dw210x_op_rw(d->udev, - udev->descriptor.idProduct == - 0x7500 ? 0x92 : 0x90, 0, 0, - obuf, msg[j].len + 2, - DW210X_WRITE_MSG); - break; - } else { - /* write registers */ - u8 obuf[msg[j].len + 2]; - obuf[0] = msg[j].len + 1; - obuf[1] = (msg[j].addr << 1); - memcpy(obuf + 2, msg[j].buf, msg[j].len); - ret = dw210x_op_rw(d->udev, 0x80, 0, 0, - obuf, msg[j].len + 2, - DW210X_WRITE_MSG); - break; - } - break; - } - } - } - - mutex_unlock(&d->i2c_mutex); - return num; -} - -static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - u8 obuf[0x40], ibuf[0x40]; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - switch (num) { - case 1: - switch (msg[0].addr) { - case SU3000_STREAM_CTRL: - obuf[0] = msg[0].buf[0] + 0x36; - obuf[1] = 3; - obuf[2] = 0; - if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0) - err("i2c transfer failed."); - break; - case DW2102_RC_QUERY: - obuf[0] = 0x10; - if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0) - err("i2c transfer failed."); - msg[0].buf[1] = ibuf[0]; - msg[0].buf[0] = ibuf[1]; - break; - default: - /* always i2c write*/ - obuf[0] = 0x08; - obuf[1] = msg[0].addr; - obuf[2] = msg[0].len; - - memcpy(&obuf[3], msg[0].buf, msg[0].len); - - if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3, - ibuf, 1, 0) < 0) - err("i2c transfer failed."); - - } - break; - case 2: - /* always i2c read */ - obuf[0] = 0x09; - obuf[1] = msg[0].len; - obuf[2] = msg[1].len; - obuf[3] = msg[0].addr; - memcpy(&obuf[4], msg[0].buf, msg[0].len); - - if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4, - ibuf, msg[1].len + 1, 0) < 0) - err("i2c transfer failed."); - - memcpy(msg[1].buf, &ibuf[1], msg[1].len); - break; - default: - warn("more than 2 i2c messages at a time is not handled yet."); - break; - } - mutex_unlock(&d->i2c_mutex); - return num; -} - -static u32 dw210x_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm dw2102_i2c_algo = { - .master_xfer = dw2102_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm dw2102_serit_i2c_algo = { - .master_xfer = dw2102_serit_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm dw2102_earda_i2c_algo = { - .master_xfer = dw2102_earda_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm dw2104_i2c_algo = { - .master_xfer = dw2104_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm dw3101_i2c_algo = { - .master_xfer = dw3101_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm s6x0_i2c_algo = { - .master_xfer = s6x0_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static struct i2c_algorithm su3000_i2c_algo = { - .master_xfer = su3000_i2c_transfer, - .functionality = dw210x_i2c_func, -}; - -static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - int i; - u8 ibuf[] = {0, 0}; - u8 eeprom[256], eepromline[16]; - - for (i = 0; i < 256; i++) { - if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) { - err("read eeprom failed."); - return -1; - } else { - eepromline[i%16] = ibuf[0]; - eeprom[i] = ibuf[0]; - } - if ((i % 16) == 15) { - deb_xfer("%02x: ", i - 15); - debug_dump(eepromline, 16, deb_xfer); - } - } - - memcpy(mac, eeprom + 8, 6); - return 0; -}; - -static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - int i, ret; - u8 ibuf[] = { 0 }, obuf[] = { 0 }; - u8 eeprom[256], eepromline[16]; - struct i2c_msg msg[] = { - { - .addr = 0xa0 >> 1, - .flags = 0, - .buf = obuf, - .len = 1, - }, { - .addr = 0xa0 >> 1, - .flags = I2C_M_RD, - .buf = ibuf, - .len = 1, - } - }; - - for (i = 0; i < 256; i++) { - obuf[0] = i; - ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2); - if (ret != 2) { - err("read eeprom failed."); - return -1; - } else { - eepromline[i % 16] = ibuf[0]; - eeprom[i] = ibuf[0]; - } - - if ((i % 16) == 15) { - deb_xfer("%02x: ", i - 15); - debug_dump(eepromline, 16, deb_xfer); - } - } - - memcpy(mac, eeprom + 16, 6); - return 0; -}; - -static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - static u8 command_start[] = {0x00}; - static u8 command_stop[] = {0x01}; - struct i2c_msg msg = { - .addr = SU3000_STREAM_CTRL, - .flags = 0, - .buf = onoff ? command_start : command_stop, - .len = 1 - }; - - i2c_transfer(&adap->dev->i2c_adap, &msg, 1); - - return 0; -} - -static int su3000_power_ctrl(struct dvb_usb_device *d, int i) -{ - struct su3000_state *state = (struct su3000_state *)d->priv; - u8 obuf[] = {0xde, 0}; - - info("%s: %d, initialized %d\n", __func__, i, state->initialized); - - if (i && !state->initialized) { - state->initialized = 1; - /* reset board */ - dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0); - } - - return 0; -} - -static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - int i; - u8 obuf[] = { 0x1f, 0xf0 }; - u8 ibuf[] = { 0 }; - struct i2c_msg msg[] = { - { - .addr = 0x51, - .flags = 0, - .buf = obuf, - .len = 2, - }, { - .addr = 0x51, - .flags = I2C_M_RD, - .buf = ibuf, - .len = 1, - - } - }; - - for (i = 0; i < 6; i++) { - obuf[1] = 0xf0 + i; - if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) - break; - else - mac[i] = ibuf[0]; - - debug_dump(mac, 6, printk); - } - - return 0; -} - -static int su3000_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - info("%s\n", __func__); - - *cold = 0; - return 0; -} - -static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - static u8 command_13v[] = {0x00, 0x01}; - static u8 command_18v[] = {0x01, 0x01}; - static u8 command_off[] = {0x00, 0x00}; - struct i2c_msg msg = { - .addr = DW2102_VOLTAGE_CTRL, - .flags = 0, - .buf = command_off, - .len = 2, - }; - - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); - if (voltage == SEC_VOLTAGE_18) - msg.buf = command_18v; - else if (voltage == SEC_VOLTAGE_13) - msg.buf = command_13v; - - i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); - - return 0; -} - -static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct dvb_usb_adapter *d = - (struct dvb_usb_adapter *)(fe->dvb->priv); - struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; - - dw210x_set_voltage(fe, voltage); - if (st->old_set_voltage) - st->old_set_voltage(fe, voltage); - - return 0; -} - -static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) -{ - static u8 led_off[] = { 0 }; - static u8 led_on[] = { 1 }; - struct i2c_msg msg = { - .addr = DW2102_LED_CTRL, - .flags = 0, - .buf = led_off, - .len = 1 - }; - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); - - if (offon) - msg.buf = led_on; - i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); -} - -static struct stv0299_config sharp_z0194a_config = { - .demod_address = 0x68, - .inittab = sharp_z0194a_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a_set_symbol_rate, -}; - -static struct cx24116_config dw2104_config = { - .demod_address = 0x55, - .mpg_clk_pos_pol = 0x01, -}; - -static struct si21xx_config serit_sp1511lhb_config = { - .demod_address = 0x68, - .min_delay_ms = 100, - -}; - -static struct tda10023_config dw3101_tda10023_config = { - .demod_address = 0x0c, - .invert = 1, -}; - -static struct mt312_config zl313_config = { - .demod_address = 0x0e, -}; - -static struct ds3000_config dw2104_ds3000_config = { - .demod_address = 0x68, -}; - -static struct stv0900_config dw2104a_stv0900_config = { - .demod_address = 0x6a, - .demod_mode = 0, - .xtal = 27000000, - .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ - .diseqc_mode = 2,/* 2/3 PWM */ - .tun1_maddress = 0,/* 0x60 */ - .tun1_adc = 0,/* 2 Vpp */ - .path1_mode = 3, -}; - -static struct stb6100_config dw2104a_stb6100_config = { - .tuner_address = 0x60, - .refclock = 27000000, -}; - -static struct stv0900_config dw2104_stv0900_config = { - .demod_address = 0x68, - .demod_mode = 0, - .xtal = 8000000, - .clkmode = 3, - .diseqc_mode = 2, - .tun1_maddress = 0, - .tun1_adc = 1,/* 1 Vpp */ - .path1_mode = 3, -}; - -static struct stv6110_config dw2104_stv6110_config = { - .i2c_address = 0x60, - .mclk = 16000000, - .clk_div = 1, -}; - -static struct stv0900_config prof_7500_stv0900_config = { - .demod_address = 0x6a, - .demod_mode = 0, - .xtal = 27000000, - .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ - .diseqc_mode = 2,/* 2/3 PWM */ - .tun1_maddress = 0,/* 0x60 */ - .tun1_adc = 0,/* 2 Vpp */ - .path1_mode = 3, - .tun1_type = 3, - .set_lock_led = dw210x_led_ctrl, -}; - -static struct ds3000_config su3000_ds3000_config = { - .demod_address = 0x68, - .ci_mode = 1, -}; - -static int dw2104_frontend_attach(struct dvb_usb_adapter *d) -{ - struct dvb_tuner_ops *tuner_ops = NULL; - - if (demod_probe & 4) { - d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, - &d->dev->i2c_adap, 0); - if (d->fe != NULL) { - if (dvb_attach(stb6100_attach, d->fe, - &dw2104a_stb6100_config, - &d->dev->i2c_adap)) { - tuner_ops = &d->fe->ops.tuner_ops; - tuner_ops->set_frequency = stb6100_set_freq; - tuner_ops->get_frequency = stb6100_get_freq; - tuner_ops->set_bandwidth = stb6100_set_bandw; - tuner_ops->get_bandwidth = stb6100_get_bandw; - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached STV0900+STB6100!\n"); - return 0; - } - } - } - - if (demod_probe & 2) { - d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, - &d->dev->i2c_adap, 0); - if (d->fe != NULL) { - if (dvb_attach(stv6110_attach, d->fe, - &dw2104_stv6110_config, - &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached STV0900+STV6110A!\n"); - return 0; - } - } - } - - if (demod_probe & 1) { - d->fe = dvb_attach(cx24116_attach, &dw2104_config, - &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached cx24116!\n"); - return 0; - } - } - - d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, - &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached DS3000!\n"); - return 0; - } - - return -EIO; -} - -static struct dvb_usb_device_properties dw2102_properties; -static struct dvb_usb_device_properties dw2104_properties; -static struct dvb_usb_device_properties s6x0_properties; - -static int dw2102_frontend_attach(struct dvb_usb_adapter *d) -{ - if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { - /*dw2102_properties.adapter->tuner_attach = NULL;*/ - d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, - &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached si21xx!\n"); - return 0; - } - } - - if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { - d->fe = dvb_attach(stv0288_attach, &earda_config, - &d->dev->i2c_adap); - if (d->fe != NULL) { - if (dvb_attach(stb6000_attach, d->fe, 0x61, - &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached stv0288!\n"); - return 0; - } - } - } - - if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { - /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ - d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, - &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached stv0299!\n"); - return 0; - } - } - return -EIO; -} - -static int dw3101_frontend_attach(struct dvb_usb_adapter *d) -{ - d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, - &d->dev->i2c_adap, 0x48); - if (d->fe != NULL) { - info("Attached tda10023!\n"); - return 0; - } - return -EIO; -} - -static int zl100313_frontend_attach(struct dvb_usb_adapter *d) -{ - d->fe = dvb_attach(mt312_attach, &zl313_config, - &d->dev->i2c_adap); - if (d->fe != NULL) { - if (dvb_attach(zl10039_attach, d->fe, 0x60, - &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached zl100313+zl10039!\n"); - return 0; - } - } - - return -EIO; -} - -static int stv0288_frontend_attach(struct dvb_usb_adapter *d) -{ - u8 obuf[] = {7, 1}; - - d->fe = dvb_attach(stv0288_attach, &earda_config, - &d->dev->i2c_adap); - - if (d->fe == NULL) - return -EIO; - - if (NULL == dvb_attach(stb6000_attach, d->fe, 0x61, &d->dev->i2c_adap)) - return -EIO; - - d->fe->ops.set_voltage = dw210x_set_voltage; - - dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); - - info("Attached stv0288+stb6000!\n"); - - return 0; - -} - -static int ds3000_frontend_attach(struct dvb_usb_adapter *d) -{ - struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; - u8 obuf[] = {7, 1}; - - d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, - &d->dev->i2c_adap); - - if (d->fe == NULL) - return -EIO; - - st->old_set_voltage = d->fe->ops.set_voltage; - d->fe->ops.set_voltage = s660_set_voltage; - - dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); - - info("Attached ds3000+ds2020!\n"); - - return 0; -} - -static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) -{ - u8 obuf[] = {7, 1}; - - d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, - &d->dev->i2c_adap, 0); - if (d->fe == NULL) - return -EIO; - - d->fe->ops.set_voltage = dw210x_set_voltage; - - dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); - - info("Attached STV0900+STB6100A!\n"); - - return 0; -} - -static int su3000_frontend_attach(struct dvb_usb_adapter *d) -{ - u8 obuf[3] = { 0xe, 0x80, 0 }; - u8 ibuf[] = { 0 }; - - if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) - err("command 0x0e transfer failed."); - - obuf[0] = 0xe; - obuf[1] = 0x83; - obuf[2] = 0; - - if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) - err("command 0x0e transfer failed."); - - obuf[0] = 0xe; - obuf[1] = 0x83; - obuf[2] = 1; - - if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) - err("command 0x0e transfer failed."); - - obuf[0] = 0x51; - - if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) - err("command 0x51 transfer failed."); - - d->fe = dvb_attach(ds3000_attach, &su3000_ds3000_config, - &d->dev->i2c_adap); - if (d->fe == NULL) - return -EIO; - - info("Attached DS3000!\n"); - - return 0; -} - -static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe, 0x60, - &adap->dev->i2c_adap, DVB_PLL_OPERA1); - return 0; -} - -static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe, 0x60, - &adap->dev->i2c_adap, DVB_PLL_TUA6034); - - return 0; -} - -static struct rc_map_table rc_map_dw210x_table[] = { - { 0xf80a, KEY_POWER2 }, /*power*/ - { 0xf80c, KEY_MUTE }, /*mute*/ - { 0xf811, KEY_1 }, - { 0xf812, KEY_2 }, - { 0xf813, KEY_3 }, - { 0xf814, KEY_4 }, - { 0xf815, KEY_5 }, - { 0xf816, KEY_6 }, - { 0xf817, KEY_7 }, - { 0xf818, KEY_8 }, - { 0xf819, KEY_9 }, - { 0xf810, KEY_0 }, - { 0xf81c, KEY_CHANNELUP }, /*ch+*/ - { 0xf80f, KEY_CHANNELDOWN }, /*ch-*/ - { 0xf81a, KEY_VOLUMEUP }, /*vol+*/ - { 0xf80e, KEY_VOLUMEDOWN }, /*vol-*/ - { 0xf804, KEY_RECORD }, /*rec*/ - { 0xf809, KEY_FAVORITES }, /*fav*/ - { 0xf808, KEY_REWIND }, /*rewind*/ - { 0xf807, KEY_FASTFORWARD }, /*fast*/ - { 0xf80b, KEY_PAUSE }, /*pause*/ - { 0xf802, KEY_ESC }, /*cancel*/ - { 0xf803, KEY_TAB }, /*tab*/ - { 0xf800, KEY_UP }, /*up*/ - { 0xf81f, KEY_OK }, /*ok*/ - { 0xf801, KEY_DOWN }, /*down*/ - { 0xf805, KEY_CAMERA }, /*cap*/ - { 0xf806, KEY_STOP }, /*stop*/ - { 0xf840, KEY_ZOOM }, /*full*/ - { 0xf81e, KEY_TV }, /*tvmode*/ - { 0xf81b, KEY_LAST }, /*recall*/ -}; - -static struct rc_map_table rc_map_tevii_table[] = { - { 0xf80a, KEY_POWER }, - { 0xf80c, KEY_MUTE }, - { 0xf811, KEY_1 }, - { 0xf812, KEY_2 }, - { 0xf813, KEY_3 }, - { 0xf814, KEY_4 }, - { 0xf815, KEY_5 }, - { 0xf816, KEY_6 }, - { 0xf817, KEY_7 }, - { 0xf818, KEY_8 }, - { 0xf819, KEY_9 }, - { 0xf810, KEY_0 }, - { 0xf81c, KEY_MENU }, - { 0xf80f, KEY_VOLUMEDOWN }, - { 0xf81a, KEY_LAST }, - { 0xf80e, KEY_OPEN }, - { 0xf804, KEY_RECORD }, - { 0xf809, KEY_VOLUMEUP }, - { 0xf808, KEY_CHANNELUP }, - { 0xf807, KEY_PVR }, - { 0xf80b, KEY_TIME }, - { 0xf802, KEY_RIGHT }, - { 0xf803, KEY_LEFT }, - { 0xf800, KEY_UP }, - { 0xf81f, KEY_OK }, - { 0xf801, KEY_DOWN }, - { 0xf805, KEY_TUNER }, - { 0xf806, KEY_CHANNELDOWN }, - { 0xf840, KEY_PLAYPAUSE }, - { 0xf81e, KEY_REWIND }, - { 0xf81b, KEY_FAVORITES }, - { 0xf81d, KEY_BACK }, - { 0xf84d, KEY_FASTFORWARD }, - { 0xf844, KEY_EPG }, - { 0xf84c, KEY_INFO }, - { 0xf841, KEY_AB }, - { 0xf843, KEY_AUDIO }, - { 0xf845, KEY_SUBTITLE }, - { 0xf84a, KEY_LIST }, - { 0xf846, KEY_F1 }, - { 0xf847, KEY_F2 }, - { 0xf85e, KEY_F3 }, - { 0xf85c, KEY_F4 }, - { 0xf852, KEY_F5 }, - { 0xf85a, KEY_F6 }, - { 0xf856, KEY_MODE }, - { 0xf858, KEY_SWITCHVIDEOMODE }, -}; - -static struct rc_map_table rc_map_tbs_table[] = { - { 0xf884, KEY_POWER }, - { 0xf894, KEY_MUTE }, - { 0xf887, KEY_1 }, - { 0xf886, KEY_2 }, - { 0xf885, KEY_3 }, - { 0xf88b, KEY_4 }, - { 0xf88a, KEY_5 }, - { 0xf889, KEY_6 }, - { 0xf88f, KEY_7 }, - { 0xf88e, KEY_8 }, - { 0xf88d, KEY_9 }, - { 0xf892, KEY_0 }, - { 0xf896, KEY_CHANNELUP }, - { 0xf891, KEY_CHANNELDOWN }, - { 0xf893, KEY_VOLUMEUP }, - { 0xf88c, KEY_VOLUMEDOWN }, - { 0xf883, KEY_RECORD }, - { 0xf898, KEY_PAUSE }, - { 0xf899, KEY_OK }, - { 0xf89a, KEY_SHUFFLE }, - { 0xf881, KEY_UP }, - { 0xf890, KEY_LEFT }, - { 0xf882, KEY_RIGHT }, - { 0xf888, KEY_DOWN }, - { 0xf895, KEY_FAVORITES }, - { 0xf897, KEY_SUBTITLE }, - { 0xf89d, KEY_ZOOM }, - { 0xf89f, KEY_EXIT }, - { 0xf89e, KEY_MENU }, - { 0xf89c, KEY_EPG }, - { 0xf880, KEY_PREVIOUS }, - { 0xf89b, KEY_MODE } -}; - -static struct rc_map_table rc_map_su3000_table[] = { - { 0x25, KEY_POWER }, /* right-bottom Red */ - { 0x0a, KEY_MUTE }, /* -/-- */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x00, KEY_0 }, - { 0x20, KEY_UP }, /* CH+ */ - { 0x21, KEY_DOWN }, /* CH+ */ - { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ - { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */ - { 0x1f, KEY_RECORD }, - { 0x17, KEY_PLAY }, - { 0x16, KEY_PAUSE }, - { 0x0b, KEY_STOP }, - { 0x27, KEY_FASTFORWARD },/* >> */ - { 0x26, KEY_REWIND }, /* << */ - { 0x0d, KEY_OK }, /* Mute */ - { 0x11, KEY_LEFT }, /* VOL- */ - { 0x10, KEY_RIGHT }, /* VOL+ */ - { 0x29, KEY_BACK }, /* button under 9 */ - { 0x2c, KEY_MENU }, /* TTX */ - { 0x2b, KEY_EPG }, /* EPG */ - { 0x1e, KEY_RED }, /* OSD */ - { 0x0e, KEY_GREEN }, /* Window */ - { 0x2d, KEY_YELLOW }, /* button under << */ - { 0x0f, KEY_BLUE }, /* bottom yellow button */ - { 0x14, KEY_AUDIO }, /* Snapshot */ - { 0x38, KEY_TV }, /* TV/Radio */ - { 0x0c, KEY_ESC } /* upper Red buttton */ -}; - -static struct rc_map_dvb_usb_table_table keys_tables[] = { - { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) }, - { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) }, - { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) }, - { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) }, -}; - -static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - int keymap_size = d->props.rc.legacy.rc_map_size; - u8 key[2]; - struct i2c_msg msg = { - .addr = DW2102_RC_QUERY, - .flags = I2C_M_RD, - .buf = key, - .len = 2 - }; - int i; - /* override keymap */ - if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) { - keymap = keys_tables[ir_keymap - 1].rc_keys ; - keymap_size = keys_tables[ir_keymap - 1].rc_keys_size; - } else if (ir_keymap > ARRAY_SIZE(keys_tables)) - return 0; /* none */ - - *state = REMOTE_NO_KEY_PRESSED; - if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { - for (i = 0; i < keymap_size ; i++) { - if (rc5_data(&keymap[i]) == msg.buf[0]) { - *state = REMOTE_KEY_PRESSED; - *event = keymap[i].keycode; - break; - } - - } - - if ((*state) == REMOTE_KEY_PRESSED) - deb_rc("%s: found rc key: %x, %x, event: %x\n", - __func__, key[0], key[1], (*event)); - else if (key[0] != 0xff) - deb_rc("%s: unknown rc key: %x, %x\n", - __func__, key[0], key[1]); - - } - - return 0; -} - -static struct usb_device_id dw2102_table[] = { - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, - {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, - {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, - {USB_DEVICE(0x3034, 0x7500)}, - {USB_DEVICE(0x1f4d, 0x3000)}, - {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, - {USB_DEVICE(0x1f4d, 0x3100)}, - { } -}; - -MODULE_DEVICE_TABLE(usb, dw2102_table); - -static int dw2102_load_firmware(struct usb_device *dev, - const struct firmware *frmwr) -{ - u8 *b, *p; - int ret = 0, i; - u8 reset; - u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; - const struct firmware *fw; - const char *fw_2101 = "dvb-usb-dw2101.fw"; - - switch (dev->descriptor.idProduct) { - case 0x2101: - ret = request_firmware(&fw, fw_2101, &dev->dev); - if (ret != 0) { - err(err_str, fw_2101); - return ret; - } - break; - default: - fw = frmwr; - break; - } - info("start downloading DW210X firmware"); - p = kmalloc(fw->size, GFP_KERNEL); - reset = 1; - /*stop the CPU*/ - dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG); - dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG); - - if (p != NULL) { - memcpy(p, fw->data, fw->size); - for (i = 0; i < fw->size; i += 0x40) { - b = (u8 *) p + i; - if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40, - DW210X_WRITE_MSG) != 0x40) { - err("error while transferring firmware"); - ret = -EINVAL; - break; - } - } - /* restart the CPU */ - reset = 0; - if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, - DW210X_WRITE_MSG) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, - DW210X_WRITE_MSG) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - /* init registers */ - switch (dev->descriptor.idProduct) { - case USB_PID_TEVII_S650: - dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table; - dw2104_properties.rc.legacy.rc_map_size = - ARRAY_SIZE(rc_map_tevii_table); - case USB_PID_DW2104: - reset = 1; - dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, - DW210X_WRITE_MSG); - /* break omitted intentionally */ - case USB_PID_DW3101: - reset = 0; - dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, - DW210X_WRITE_MSG); - break; - case USB_PID_CINERGY_S: - case USB_PID_DW2102: - dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, - DW210X_WRITE_MSG); - dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, - DW210X_READ_MSG); - /* check STV0299 frontend */ - dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, - DW210X_READ_MSG); - if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) { - dw2102_properties.i2c_algo = &dw2102_i2c_algo; - dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach; - break; - } else { - /* check STV0288 frontend */ - reset16[0] = 0xd0; - reset16[1] = 1; - reset16[2] = 0; - dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3, - DW210X_WRITE_MSG); - dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3, - DW210X_READ_MSG); - if (reset16[2] == 0x11) { - dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; - break; - } - } - case 0x2101: - dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, - DW210X_READ_MSG); - dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, - DW210X_READ_MSG); - dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, - DW210X_READ_MSG); - dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, - DW210X_READ_MSG); - break; - } - - msleep(100); - kfree(p); - } - return ret; -} - -static struct dvb_usb_device_properties dw2102_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-dw2102.fw", - .no_reconnect = 1, - - .i2c_algo = &dw2102_serit_i2c_algo, - - .rc.legacy = { - .rc_map_table = rc_map_dw210x_table, - .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x81, - /* parameter for the MPEG2-data transfer */ - .num_adapters = 1, - .download_firmware = dw2102_load_firmware, - .read_mac_address = dw210x_read_mac_address, - .adapter = { - { - .frontend_attach = dw2102_frontend_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .num_device_descs = 3, - .devices = { - {"DVBWorld DVB-S 2102 USB2.0", - {&dw2102_table[0], NULL}, - {NULL}, - }, - {"DVBWorld DVB-S 2101 USB2.0", - {&dw2102_table[1], NULL}, - {NULL}, - }, - {"TerraTec Cinergy S USB", - {&dw2102_table[4], NULL}, - {NULL}, - }, - } -}; - -static struct dvb_usb_device_properties dw2104_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-dw2104.fw", - .no_reconnect = 1, - - .i2c_algo = &dw2104_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_dw210x_table, - .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x81, - /* parameter for the MPEG2-data transfer */ - .num_adapters = 1, - .download_firmware = dw2102_load_firmware, - .read_mac_address = dw210x_read_mac_address, - .adapter = { - { - .frontend_attach = dw2104_frontend_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .num_device_descs = 2, - .devices = { - { "DVBWorld DW2104 USB2.0", - {&dw2102_table[2], NULL}, - {NULL}, - }, - { "TeVii S650 USB2.0", - {&dw2102_table[3], NULL}, - {NULL}, - }, - } -}; - -static struct dvb_usb_device_properties dw3101_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-dw3101.fw", - .no_reconnect = 1, - - .i2c_algo = &dw3101_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_dw210x_table, - .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x81, - /* parameter for the MPEG2-data transfer */ - .num_adapters = 1, - .download_firmware = dw2102_load_firmware, - .read_mac_address = dw210x_read_mac_address, - .adapter = { - { - .frontend_attach = dw3101_frontend_attach, - .tuner_attach = dw3101_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .num_device_descs = 1, - .devices = { - { "DVBWorld DVB-C 3101 USB2.0", - {&dw2102_table[5], NULL}, - {NULL}, - }, - } -}; - -static struct dvb_usb_device_properties s6x0_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .size_of_priv = sizeof(struct s6x0_state), - .firmware = "dvb-usb-s630.fw", - .no_reconnect = 1, - - .i2c_algo = &s6x0_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_tevii_table, - .rc_map_size = ARRAY_SIZE(rc_map_tevii_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .generic_bulk_ctrl_endpoint = 0x81, - .num_adapters = 1, - .download_firmware = dw2102_load_firmware, - .read_mac_address = s6x0_read_mac_address, - .adapter = { - { - .frontend_attach = zl100313_frontend_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .num_device_descs = 1, - .devices = { - {"TeVii S630 USB", - {&dw2102_table[6], NULL}, - {NULL}, - }, - } -}; - -struct dvb_usb_device_properties *p1100; -static struct dvb_usb_device_description d1100 = { - "Prof 1100 USB ", - {&dw2102_table[7], NULL}, - {NULL}, -}; - -struct dvb_usb_device_properties *s660; -static struct dvb_usb_device_description d660 = { - "TeVii S660 USB", - {&dw2102_table[8], NULL}, - {NULL}, -}; - -static struct dvb_usb_device_description d480_1 = { - "TeVii S480.1 USB", - {&dw2102_table[12], NULL}, - {NULL}, -}; - -static struct dvb_usb_device_description d480_2 = { - "TeVii S480.2 USB", - {&dw2102_table[13], NULL}, - {NULL}, -}; - -struct dvb_usb_device_properties *p7500; -static struct dvb_usb_device_description d7500 = { - "Prof 7500 USB DVB-S2", - {&dw2102_table[9], NULL}, - {NULL}, -}; - -static struct dvb_usb_device_properties su3000_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .size_of_priv = sizeof(struct su3000_state), - .power_ctrl = su3000_power_ctrl, - .num_adapters = 1, - .identify_state = su3000_identify_state, - .i2c_algo = &su3000_i2c_algo, - - .rc.legacy = { - .rc_map_table = rc_map_su3000_table, - .rc_map_size = ARRAY_SIZE(rc_map_su3000_table), - .rc_interval = 150, - .rc_query = dw2102_rc_query, - }, - - .read_mac_address = su3000_read_mac_address, - - .generic_bulk_ctrl_endpoint = 0x01, - - .adapter = { - { - .streaming_ctrl = su3000_streaming_ctrl, - .frontend_attach = su3000_frontend_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - } - } - }, - .num_device_descs = 3, - .devices = { - { "SU3000HD DVB-S USB2.0", - { &dw2102_table[10], NULL }, - { NULL }, - }, - { "Terratec Cinergy S2 USB HD", - { &dw2102_table[11], NULL }, - { NULL }, - }, - { "X3M TV SPC1400HD PCI", - { &dw2102_table[14], NULL }, - { NULL }, - }, - } -}; - -static int dw2102_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - p1100 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!p1100) - return -ENOMEM; - /* copy default structure */ - memcpy(p1100, &s6x0_properties, - sizeof(struct dvb_usb_device_properties)); - /* fill only different fields */ - p1100->firmware = "dvb-usb-p1100.fw"; - p1100->devices[0] = d1100; - p1100->rc.legacy.rc_map_table = rc_map_tbs_table; - p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); - p1100->adapter->frontend_attach = stv0288_frontend_attach; - - s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!s660) { - kfree(p1100); - return -ENOMEM; - } - memcpy(s660, &s6x0_properties, - sizeof(struct dvb_usb_device_properties)); - s660->firmware = "dvb-usb-s660.fw"; - s660->num_device_descs = 3; - s660->devices[0] = d660; - s660->devices[1] = d480_1; - s660->devices[2] = d480_2; - s660->adapter->frontend_attach = ds3000_frontend_attach; - - p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!p7500) { - kfree(p1100); - kfree(s660); - return -ENOMEM; - } - memcpy(p7500, &s6x0_properties, - sizeof(struct dvb_usb_device_properties)); - p7500->firmware = "dvb-usb-p7500.fw"; - p7500->devices[0] = d7500; - p7500->rc.legacy.rc_map_table = rc_map_tbs_table; - p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); - p7500->adapter->frontend_attach = prof_7500_frontend_attach; - - if (0 == dvb_usb_device_init(intf, &dw2102_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dw2104_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dw3101_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &s6x0_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, p1100, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, s660, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, p7500, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &su3000_properties, - THIS_MODULE, NULL, adapter_nr)) - return 0; - - return -ENODEV; -} - -static struct usb_driver dw2102_driver = { - .name = "dw2102", - .probe = dw2102_probe, - .disconnect = dvb_usb_device_exit, - .id_table = dw2102_table, -}; - -static int __init dw2102_module_init(void) -{ - int ret = usb_register(&dw2102_driver); - if (ret) - err("usb_register failed. Error number %d", ret); - - return ret; -} - -static void __exit dw2102_module_exit(void) -{ - usb_deregister(&dw2102_driver); -} - -module_init(dw2102_module_init); -module_exit(dw2102_module_exit); - -MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); -MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," - " DVB-C 3101 USB2.0," - " TeVii S600, S630, S650, S660, S480," - " Prof 1100, 7500 USB2.0," - " Geniatech SU3000 devices"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dw2102.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dw2102.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dw2102.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/dw2102.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -#ifndef _DW2102_H_ -#define _DW2102_H_ - -#define DVB_USB_LOG_PREFIX "dw2102" -#include "dvb-usb.h" - -#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) -#define deb_rc(args...) dprintk(dvb_usb_dw2102_debug, 0x04, args) -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ec168.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ec168.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ec168.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ec168.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,440 +0,0 @@ -/* - * E3C EC168 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "ec168.h" -#include "ec100.h" -#include "mxl5005s.h" - -/* debug */ -static int dvb_usb_ec168_debug; -module_param_named(debug, dvb_usb_ec168_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static struct ec100_config ec168_ec100_config; - -static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req) -{ - int ret; - unsigned int pipe; - u8 request, requesttype; - u8 buf[req->size]; - - switch (req->cmd) { - case DOWNLOAD_FIRMWARE: - case GPIO: - case WRITE_I2C: - case STREAMING_CTRL: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - request = req->cmd; - break; - case READ_I2C: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - request = req->cmd; - break; - case GET_CONFIG: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - request = CONFIG; - break; - case SET_CONFIG: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - request = CONFIG; - break; - case WRITE_DEMOD: - requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); - request = DEMOD_RW; - break; - case READ_DEMOD: - requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); - request = DEMOD_RW; - break; - default: - err("unknown command:%02x", req->cmd); - ret = -EPERM; - goto error; - } - - if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { - /* write */ - memcpy(buf, req->data, req->size); - pipe = usb_sndctrlpipe(udev, 0); - } else { - /* read */ - pipe = usb_rcvctrlpipe(udev, 0); - } - - msleep(1); /* avoid I2C errors */ - - ret = usb_control_msg(udev, pipe, request, requesttype, req->value, - req->index, buf, sizeof(buf), EC168_USB_TIMEOUT); - - ec168_debug_dump(request, requesttype, req->value, req->index, buf, - req->size, deb_xfer); - - if (ret < 0) - goto error; - else - ret = 0; - - /* read request, copy returned data to return buf */ - if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) - memcpy(req->data, buf, req->size); - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) -{ - return ec168_rw_udev(d->udev, req); -} - -/* I2C */ -static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct ec168_req req; - int i = 0; - int ret; - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - while (i < num) { - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].addr == ec168_ec100_config.demod_address) { - req.cmd = READ_DEMOD; - req.value = 0; - req.index = 0xff00 + msg[i].buf[0]; /* reg */ - req.size = msg[i+1].len; /* bytes to read */ - req.data = &msg[i+1].buf[0]; - ret = ec168_ctrl_msg(d, &req); - i += 2; - } else { - err("I2C read not implemented"); - ret = -ENOSYS; - i += 2; - } - } else { - if (msg[i].addr == ec168_ec100_config.demod_address) { - req.cmd = WRITE_DEMOD; - req.value = msg[i].buf[1]; /* val */ - req.index = 0xff00 + msg[i].buf[0]; /* reg */ - req.size = 0; - req.data = NULL; - ret = ec168_ctrl_msg(d, &req); - i += 1; - } else { - req.cmd = WRITE_I2C; - req.value = msg[i].buf[0]; /* val */ - req.index = 0x0100 + msg[i].addr; /* I2C addr */ - req.size = msg[i].len-1; - req.data = &msg[i].buf[1]; - ret = ec168_ctrl_msg(d, &req); - i += 1; - } - } - if (ret) - goto error; - - } - ret = i; - -error: - mutex_unlock(&d->i2c_mutex); - return i; -} - - -static u32 ec168_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm ec168_i2c_algo = { - .master_xfer = ec168_i2c_xfer, - .functionality = ec168_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct ec100_config ec168_ec100_config = { - .demod_address = 0xff, /* not real address, demod is integrated */ -}; - -static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) -{ - deb_info("%s:\n", __func__); - adap->fe = dvb_attach(ec100_attach, &ec168_ec100_config, - &adap->dev->i2c_adap); - if (adap->fe == NULL) - return -ENODEV; - - return 0; -} - -static struct mxl5005s_config ec168_mxl5003s_config = { - .i2c_address = 0xc6, - .if_freq = IF_FREQ_4570000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_OFF, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .AgcMasterByte = 0x00, -}; - -static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) -{ - deb_info("%s:\n", __func__); - return dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap, - &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; -} - -static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL}; - deb_info("%s: onoff:%d\n", __func__, onoff); - if (onoff) - req.index = 0x0102; - return ec168_ctrl_msg(adap->dev, &req); -} - -static int ec168_download_firmware(struct usb_device *udev, - const struct firmware *fw) -{ - int i, len, packets, remainder, ret; - u16 addr = 0x0000; /* firmware start address */ - struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; - deb_info("%s:\n", __func__); - - #define FW_PACKET_MAX_DATA 2048 - packets = fw->size / FW_PACKET_MAX_DATA; - remainder = fw->size % FW_PACKET_MAX_DATA; - len = FW_PACKET_MAX_DATA; - for (i = 0; i <= packets; i++) { - if (i == packets) /* set size of the last packet */ - len = remainder; - - req.size = len; - req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); - req.index = addr; - addr += FW_PACKET_MAX_DATA; - - ret = ec168_rw_udev(udev, &req); - if (ret) { - err("firmware download failed:%d packet:%d", ret, i); - goto error; - } - } - req.size = 0; - - /* set "warm"? */ - req.cmd = SET_CONFIG; - req.value = 0; - req.index = 0x0001; - ret = ec168_rw_udev(udev, &req); - if (ret) - goto error; - - /* really needed - no idea what does */ - req.cmd = GPIO; - req.value = 0; - req.index = 0x0206; - ret = ec168_rw_udev(udev, &req); - if (ret) - goto error; - - /* activate tuner I2C? */ - req.cmd = WRITE_I2C; - req.value = 0; - req.index = 0x00c6; - ret = ec168_rw_udev(udev, &req); - if (ret) - goto error; - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -static int ec168_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold) -{ - int ret; - u8 reply; - struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; - deb_info("%s:\n", __func__); - - ret = ec168_rw_udev(udev, &req); - if (ret) - goto error; - - deb_info("%s: reply:%02x\n", __func__, reply); - - if (reply == 0x01) - *cold = 0; - else - *cold = 1; - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties ec168_properties; - -static int ec168_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret; - deb_info("%s: interface:%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - ret = dvb_usb_device_init(intf, &ec168_properties, THIS_MODULE, NULL, - adapter_nr); - if (ret) - goto error; - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -#define E3C_EC168_1689 0 -#define E3C_EC168_FFFA 1 -#define E3C_EC168_FFFB 2 -#define E3C_EC168_1001 3 -#define E3C_EC168_1002 4 - -static struct usb_device_id ec168_id[] = { - [E3C_EC168_1689] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168)}, - [E3C_EC168_FFFA] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2)}, - [E3C_EC168_FFFB] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3)}, - [E3C_EC168_1001] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4)}, - [E3C_EC168_1002] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5)}, - {} /* terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, ec168_id); - -static struct dvb_usb_device_properties ec168_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = ec168_download_firmware, - .firmware = "dvb-usb-ec168.fw", - .no_reconnect = 1, - - .size_of_priv = 0, - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = ec168_streaming_ctrl, - .frontend_attach = ec168_ec100_frontend_attach, - .tuner_attach = ec168_mxl5003s_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = (32*512), - } - } - }, - } - }, - - .identify_state = ec168_identify_state, - - .i2c_algo = &ec168_i2c_algo, - - .num_device_descs = 1, - .devices = { - { - .name = "E3C EC168 DVB-T USB2.0 reference design", - .cold_ids = { - &ec168_id[E3C_EC168_1689], - &ec168_id[E3C_EC168_FFFA], - &ec168_id[E3C_EC168_FFFB], - &ec168_id[E3C_EC168_1001], - &ec168_id[E3C_EC168_1002], - NULL}, - .warm_ids = {NULL}, - }, - } -}; - -static struct usb_driver ec168_driver = { - .name = "dvb_usb_ec168", - .probe = ec168_probe, - .disconnect = dvb_usb_device_exit, - .id_table = ec168_id, -}; - -/* module stuff */ -static int __init ec168_module_init(void) -{ - int ret; - deb_info("%s:\n", __func__); - ret = usb_register(&ec168_driver); - if (ret) - err("module init failed:%d", ret); - - return ret; -} - -static void __exit ec168_module_exit(void) -{ - deb_info("%s:\n", __func__); - /* deregister this driver from the USB subsystem */ - usb_deregister(&ec168_driver); -} - -module_init(ec168_module_init); -module_exit(ec168_module_exit); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("E3C EC168 DVB-T USB2.0 driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ec168.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ec168.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ec168.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ec168.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* - * E3C EC168 DVB USB driver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef EC168_H -#define EC168_H - -#define DVB_USB_LOG_PREFIX "ec168" -#include "dvb-usb.h" - -#define deb_info(args...) dprintk(dvb_usb_ec168_debug, 0x01, args) -#define deb_rc(args...) dprintk(dvb_usb_ec168_debug, 0x02, args) -#define deb_xfer(args...) dprintk(dvb_usb_ec168_debug, 0x04, args) -#define deb_reg(args...) dprintk(dvb_usb_ec168_debug, 0x08, args) -#define deb_i2c(args...) dprintk(dvb_usb_ec168_debug, 0x10, args) -#define deb_fw(args...) dprintk(dvb_usb_ec168_debug, 0x20, args) - -#define ec168_debug_dump(r, t, v, i, b, l, func) { \ - int loop_; \ - func("%02x %02x %02x %02x %02x %02x %02x %02x", \ - t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \ - if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ - func(" >>> "); \ - else \ - func(" <<< "); \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ -} - -#define EC168_USB_TIMEOUT 1000 - -struct ec168_req { - u8 cmd; /* [1] */ - u16 value; /* [2|3] */ - u16 index; /* [4|5] */ - u16 size; /* [6|7] */ - u8 *data; -}; - -enum ec168_cmd { - DOWNLOAD_FIRMWARE = 0x00, - CONFIG = 0x01, - DEMOD_RW = 0x03, - GPIO = 0x04, - STREAMING_CTRL = 0x10, - READ_I2C = 0x20, - WRITE_I2C = 0x21, - HID_DOWNLOAD = 0x30, - GET_CONFIG, - SET_CONFIG, - READ_DEMOD, - WRITE_DEMOD, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,524 +0,0 @@ -/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. - * - * Copyright (C) 2009 Akihiro Tsukada - * - * This module is based off the the gl861 and vp702x modules. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "friio.h" - -/* debug */ -int dvb_usb_friio_debug; -module_param_named(debug, dvb_usb_friio_debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))." - DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -/** - * Indirect I2C access to the PLL via FE. - * whole I2C protocol data to the PLL is sent via the FE's I2C register. - * This is done by a control msg to the FE with the I2C data accompanied, and - * a specific USB request number is assigned for that purpose. - * - * this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE). - * TODO: refoctored, smarter i2c functions. - */ -static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u16 index = wbuf[0]; /* must be JDVBT90502_2ND_I2C_REG(=0xFE) */ - u16 value = addr << (8 + 1); - int wo = (rbuf == NULL || rlen == 0); /* write only */ - u8 req, type; - - deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n", - wbuf[1], wbuf[0], wlen - 1); - - if (wo && wlen >= 2) { - req = GL861_REQ_I2C_DATA_CTRL_WRITE; - type = GL861_WRITE; - udelay(20); - return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - req, type, value, index, - &wbuf[1], wlen - 1, 2000); - } - - deb_xfer("not supported ctrl-msg, aborting."); - return -EINVAL; -} - -/* normal I2C access (without extra data arguments). - * write to the register wbuf[0] at I2C address addr with the value wbuf[1], - * or read from the register wbuf[0]. - * register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3 - */ -static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u16 index; - u16 value = addr << (8 + 1); - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - u8 req, type; - unsigned int pipe; - - /* special case for the indirect I2C access to the PLL via FE, */ - if (addr == friio_fe_config.demod_address && - wbuf[0] == JDVBT90502_2ND_I2C_REG) - return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen); - - if (wo) { - req = GL861_REQ_I2C_WRITE; - type = GL861_WRITE; - pipe = usb_sndctrlpipe(d->udev, 0); - } else { /* rw */ - req = GL861_REQ_I2C_READ; - type = GL861_READ; - pipe = usb_rcvctrlpipe(d->udev, 0); - } - - switch (wlen) { - case 1: - index = wbuf[0]; - break; - case 2: - index = wbuf[0]; - value = value + wbuf[1]; - break; - case 3: - /* special case for 16bit register-address */ - index = (wbuf[2] << 8) | wbuf[0]; - value = value + wbuf[1]; - break; - default: - deb_xfer("wlen = %x, aborting.", wlen); - return -EINVAL; - } - msleep(1); - return usb_control_msg(d->udev, pipe, req, type, - value, index, rbuf, rlen, 2000); -} - -/* I2C */ -static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { - if (gl861_i2c_msg(d, msg[i].addr, - msg[i].buf, msg[i].len, - msg[i + 1].buf, msg[i + 1].len) < 0) - break; - i++; - } else - if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, NULL, 0) < 0) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 gl861_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - - -static int friio_ext_ctl(struct dvb_usb_adapter *adap, - u32 sat_color, int lnb_on) -{ - int i; - int ret; - struct i2c_msg msg; - u8 buf[2]; - u32 mask; - u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0; - - msg.addr = 0x00; - msg.flags = 0; - msg.len = 2; - msg.buf = buf; - - buf[0] = 0x00; - - /* send 2bit header (&B10) */ - buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE; - ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); - buf[1] |= FRIIO_CTL_CLK; - ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); - - buf[1] = lnb | FRIIO_CTL_STROBE; - ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); - buf[1] |= FRIIO_CTL_CLK; - ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); - - /* send 32bit(satur, R, G, B) data in serial */ - mask = 1 << 31; - for (i = 0; i < 32; i++) { - buf[1] = lnb | FRIIO_CTL_STROBE; - if (sat_color & mask) - buf[1] |= FRIIO_CTL_LED; - ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); - buf[1] |= FRIIO_CTL_CLK; - ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); - mask >>= 1; - } - - /* set the strobe off */ - buf[1] = lnb; - ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); - buf[1] |= FRIIO_CTL_CLK; - ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); - - return (ret == 70); -} - - -static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); - -/* TODO: move these init cmds to the FE's init routine? */ -static u8 streaming_init_cmds[][2] = { - {0x33, 0x08}, - {0x37, 0x40}, - {0x3A, 0x1F}, - {0x3B, 0xFF}, - {0x3C, 0x1F}, - {0x3D, 0xFF}, - {0x38, 0x00}, - {0x35, 0x00}, - {0x39, 0x00}, - {0x36, 0x00}, -}; -static int cmdlen = sizeof(streaming_init_cmds) / 2; - -/* - * Command sequence in this init function is a replay - * of the captured USB commands from the Windows proprietary driver. - */ -static int friio_initialize(struct dvb_usb_device *d) -{ - int ret; - int i; - int retry = 0; - u8 rbuf[2]; - u8 wbuf[3]; - - deb_info("%s called.\n", __func__); - - /* use gl861_i2c_msg instead of gl861_i2c_xfer(), */ - /* because the i2c device is not set up yet. */ - wbuf[0] = 0x11; - wbuf[1] = 0x02; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); - if (ret < 0) - goto error; - msleep(2); - - wbuf[0] = 0x11; - wbuf[1] = 0x00; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); - if (ret < 0) - goto error; - msleep(1); - - /* following msgs should be in the FE's init code? */ - /* cmd sequence to identify the device type? (friio black/white) */ - wbuf[0] = 0x03; - wbuf[1] = 0x80; - /* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */ - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE, - 0x1200, 0x0100, wbuf, 2, 2000); - if (ret < 0) - goto error; - - msleep(2); - wbuf[0] = 0x00; - wbuf[2] = 0x01; /* reg.0x0100 */ - wbuf[1] = 0x00; - ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2); - /* my Friio White returns 0xffff. */ - if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff) - goto error; - - msleep(2); - wbuf[0] = 0x03; - wbuf[1] = 0x80; - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE, - 0x9000, 0x0100, wbuf, 2, 2000); - if (ret < 0) - goto error; - - msleep(2); - wbuf[0] = 0x00; - wbuf[2] = 0x01; /* reg.0x0100 */ - wbuf[1] = 0x00; - ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2); - /* my Friio White returns 0xffff again. */ - if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff) - goto error; - - msleep(1); - -restart: - /* ============ start DEMOD init cmds ================== */ - /* read PLL status to clear the POR bit */ - wbuf[0] = JDVBT90502_2ND_I2C_REG; - wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1; /* +1 for reading */ - ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0); - if (ret < 0) - goto error; - - msleep(5); - /* note: DEMODULATOR has 16bit register-address. */ - wbuf[0] = 0x00; - wbuf[2] = 0x01; /* reg addr: 0x0100 */ - wbuf[1] = 0x00; /* val: not used */ - ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1); - if (ret < 0) - goto error; -/* - msleep(1); - wbuf[0] = 0x80; - wbuf[1] = 0x00; - ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1); - if (ret < 0) - goto error; - */ - if (rbuf[0] & 0x80) { /* still in PowerOnReset state? */ - if (++retry > 3) { - deb_info("failed to get the correct" - " FE demod status:0x%02x\n", rbuf[0]); - goto error; - } - msleep(100); - goto restart; - } - - /* TODO: check return value in rbuf */ - /* =========== end DEMOD init cmds ===================== */ - msleep(1); - - wbuf[0] = 0x30; - wbuf[1] = 0x04; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); - if (ret < 0) - goto error; - - msleep(2); - /* following 2 cmds unnecessary? */ - wbuf[0] = 0x00; - wbuf[1] = 0x01; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); - if (ret < 0) - goto error; - - wbuf[0] = 0x06; - wbuf[1] = 0x0F; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); - if (ret < 0) - goto error; - - /* some streaming ctl cmds (maybe) */ - msleep(10); - for (i = 0; i < cmdlen; i++) { - ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2, - NULL, 0); - if (ret < 0) - goto error; - msleep(1); - } - msleep(20); - - /* change the LED color etc. */ - ret = friio_streaming_ctrl(&d->adapter[0], 0); - if (ret < 0) - goto error; - - return 0; - -error: - deb_info("%s:ret == %d\n", __func__, ret); - return -EIO; -} - -/* Callbacks for DVB USB */ - -static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - - deb_info("%s called.(%d)\n", __func__, onoff); - - /* set the LED color and saturation (and LNB on) */ - if (onoff) - ret = friio_ext_ctl(adap, 0x6400ff64, 1); - else - ret = friio_ext_ctl(adap, 0x96ff00ff, 1); - - if (ret != 1) { - deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret); - return -EREMOTEIO; - } - return 0; -} - -static int friio_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (friio_initialize(adap->dev) < 0) - return -EIO; - - adap->fe = jdvbt90502_attach(adap->dev); - if (adap->fe == NULL) - return -EIO; - - return 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties friio_properties; - -static int friio_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d; - struct usb_host_interface *alt; - int ret; - - if (intf->num_altsetting < GL861_ALTSETTING_COUNT) - return -ENODEV; - - alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING); - if (alt == NULL) { - deb_rc("not alt found!\n"); - return -ENODEV; - } - ret = usb_set_interface(interface_to_usbdev(intf), - alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - if (ret != 0) { - deb_rc("failed to set alt-setting!\n"); - return ret; - } - - ret = dvb_usb_device_init(intf, &friio_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) - friio_streaming_ctrl(&d->adapter[0], 1); - - return ret; -} - - -struct jdvbt90502_config friio_fe_config = { - .demod_address = FRIIO_DEMOD_ADDR, - .pll_address = FRIIO_PLL_ADDR, -}; - -static struct i2c_algorithm gl861_i2c_algo = { - .master_xfer = gl861_i2c_xfer, - .functionality = gl861_i2c_func, -}; - -static struct usb_device_id friio_table[] = { - { USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, friio_table); - - -static struct dvb_usb_device_properties friio_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = 0, - - .num_adapters = 1, - .adapter = { - /* caps:0 => no pid filter, 188B TS packet */ - /* GL861 has a HW pid filter, but no info available. */ - { - .caps = 0, - - .frontend_attach = friio_frontend_attach, - .streaming_ctrl = friio_streaming_ctrl, - - .stream = { - .type = USB_BULK, - /* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */ - .count = 8, - .endpoint = 0x01, - .u = { - /* GL861 has 6KB buf inside */ - .bulk = { - .buffersize = 16384, - } - } - }, - } - }, - .i2c_algo = &gl861_i2c_algo, - - .num_device_descs = 1, - .devices = { - { - .name = "774 Friio ISDB-T USB2.0", - .cold_ids = { NULL }, - .warm_ids = { &friio_table[0], NULL }, - }, - } -}; - -static struct usb_driver friio_driver = { - .name = "dvb_usb_friio", - .probe = friio_probe, - .disconnect = dvb_usb_device_exit, - .id_table = friio_table, -}; - - -/* module stuff */ -static int __init friio_module_init(void) -{ - int ret; - - ret = usb_register(&friio_driver); - if (ret) - err("usb_register failed. Error number %d", ret); - - return ret; -} - - -static void __exit friio_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&friio_driver); -} - -module_init(friio_module_init); -module_exit(friio_module_exit); - -MODULE_AUTHOR("Akihiro Tsukada "); -MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio-fe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio-fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,474 +0,0 @@ -/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. - * - * Copyright (C) 2009 Akihiro Tsukada - * - * This module is based off the the gl861 and vp702x modules. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include -#include -#include - -#include "friio.h" - -struct jdvbt90502_state { - struct i2c_adapter *i2c; - struct dvb_frontend frontend; - struct jdvbt90502_config config; -}; - -/* NOTE: TC90502 has 16bit register-address? */ -/* register 0x0100 is used for reading PLL status, so reg is u16 here */ -static int jdvbt90502_reg_read(struct jdvbt90502_state *state, - const u16 reg, u8 *buf, const size_t count) -{ - int ret; - u8 wbuf[3]; - struct i2c_msg msg[2]; - - wbuf[0] = reg & 0xFF; - wbuf[1] = 0; - wbuf[2] = reg >> 8; - - msg[0].addr = state->config.demod_address; - msg[0].flags = 0; - msg[0].buf = wbuf; - msg[0].len = sizeof(wbuf); - - msg[1].addr = msg[0].addr; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - msg[1].len = count; - - ret = i2c_transfer(state->i2c, msg, 2); - if (ret != 2) { - deb_fe(" reg read failed.\n"); - return -EREMOTEIO; - } - return 0; -} - -/* currently 16bit register-address is not used, so reg is u8 here */ -static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state, - const u8 reg, const u8 val) -{ - struct i2c_msg msg; - u8 wbuf[2]; - - wbuf[0] = reg; - wbuf[1] = val; - - msg.addr = state->config.demod_address; - msg.flags = 0; - msg.buf = wbuf; - msg.len = sizeof(wbuf); - - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - deb_fe(" reg write failed."); - return -EREMOTEIO; - } - return 0; -} - -static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len) -{ - struct jdvbt90502_state *state = fe->demodulator_priv; - int err, i; - for (i = 0; i < len - 1; i++) { - err = jdvbt90502_single_reg_write(state, - buf[0] + i, buf[i + 1]); - if (err) - return err; - } - - return 0; -} - -/* read pll status byte via the demodulator's I2C register */ -/* note: Win box reads it by 8B block at the I2C addr 0x30 from reg:0x80 */ -static int jdvbt90502_pll_read(struct jdvbt90502_state *state, u8 *result) -{ - int ret; - - /* +1 for reading */ - u8 pll_addr_byte = (state->config.pll_address << 1) + 1; - - *result = 0; - - ret = jdvbt90502_single_reg_write(state, JDVBT90502_2ND_I2C_REG, - pll_addr_byte); - if (ret) - goto error; - - ret = jdvbt90502_reg_read(state, 0x0100, result, 1); - if (ret) - goto error; - - deb_fe("PLL read val:%02x\n", *result); - return 0; - -error: - deb_fe("%s:ret == %d\n", __func__, ret); - return -EREMOTEIO; -} - - -/* set pll frequency via the demodulator's I2C register */ -static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq) -{ - int ret; - int retry; - u8 res1; - u8 res2[9]; - - u8 pll_freq_cmd[PLL_CMD_LEN]; - u8 pll_agc_cmd[PLL_CMD_LEN]; - struct i2c_msg msg[2]; - u32 f; - - deb_fe("%s: freq=%d, step=%d\n", __func__, freq, - state->frontend.ops.info.frequency_stepsize); - /* freq -> oscilator frequency conversion. */ - /* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */ - f = freq / state->frontend.ops.info.frequency_stepsize; - /* add 399[1/7 MHZ] = 57MHz for the IF */ - f += 399; - /* add center frequency shift if necessary */ - if (f % 7 == 0) - f++; - pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */ - pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1; - pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F; - pll_freq_cmd[DIVIDER_BYTE2] = f & 0xFF; - pll_freq_cmd[CONTROL_BYTE] = 0xB2; /* ref.divider:28, 4MHz/28=1/7MHz */ - pll_freq_cmd[BANDSWITCH_BYTE] = 0x08; /* UHF band */ - - msg[0].addr = state->config.demod_address; - msg[0].flags = 0; - msg[0].buf = pll_freq_cmd; - msg[0].len = sizeof(pll_freq_cmd); - - ret = i2c_transfer(state->i2c, &msg[0], 1); - if (ret != 1) - goto error; - - udelay(50); - - pll_agc_cmd[DEMOD_REDIRECT_REG] = pll_freq_cmd[DEMOD_REDIRECT_REG]; - pll_agc_cmd[ADDRESS_BYTE] = pll_freq_cmd[ADDRESS_BYTE]; - pll_agc_cmd[DIVIDER_BYTE1] = pll_freq_cmd[DIVIDER_BYTE1]; - pll_agc_cmd[DIVIDER_BYTE2] = pll_freq_cmd[DIVIDER_BYTE2]; - pll_agc_cmd[CONTROL_BYTE] = 0x9A; /* AGC_CTRL instead of BANDSWITCH */ - pll_agc_cmd[AGC_CTRL_BYTE] = 0x50; - /* AGC Time Constant 2s, AGC take-over point:103dBuV(lowest) */ - - msg[1].addr = msg[0].addr; - msg[1].flags = 0; - msg[1].buf = pll_agc_cmd; - msg[1].len = sizeof(pll_agc_cmd); - - ret = i2c_transfer(state->i2c, &msg[1], 1); - if (ret != 1) - goto error; - - /* I don't know what these cmds are for, */ - /* but the USB log on a windows box contains them */ - ret = jdvbt90502_single_reg_write(state, 0x01, 0x40); - ret |= jdvbt90502_single_reg_write(state, 0x01, 0x00); - if (ret) - goto error; - udelay(100); - - /* wait for the demod to be ready? */ -#define RETRY_COUNT 5 - for (retry = 0; retry < RETRY_COUNT; retry++) { - ret = jdvbt90502_reg_read(state, 0x0096, &res1, 1); - if (ret) - goto error; - /* if (res1 != 0x00) goto error; */ - ret = jdvbt90502_reg_read(state, 0x00B0, res2, sizeof(res2)); - if (ret) - goto error; - if (res2[0] >= 0xA7) - break; - msleep(100); - } - if (retry >= RETRY_COUNT) { - deb_fe("%s: FE does not get ready after freq setting.\n", - __func__); - return -EREMOTEIO; - } - - return 0; -error: - deb_fe("%s:ret == %d\n", __func__, ret); - return -EREMOTEIO; -} - -static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state) -{ - u8 result; - int ret; - - *state = FE_HAS_SIGNAL; - - ret = jdvbt90502_pll_read(fe->demodulator_priv, &result); - if (ret) { - deb_fe("%s:ret == %d\n", __func__, ret); - return -EREMOTEIO; - } - - *state = FE_HAS_SIGNAL - | FE_HAS_CARRIER - | FE_HAS_VITERBI - | FE_HAS_SYNC; - - if (result & PLL_STATUS_LOCKED) - *state |= FE_HAS_LOCK; - - return 0; -} - -static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - int ret; - u8 rbuf[37]; - - *strength = 0; - - /* status register (incl. signal strength) : 0x89 */ - /* TODO: read just the necessary registers [0x8B..0x8D]? */ - ret = jdvbt90502_reg_read(fe->demodulator_priv, 0x0089, - rbuf, sizeof(rbuf)); - - if (ret) { - deb_fe("%s:ret == %d\n", __func__, ret); - return -EREMOTEIO; - } - - /* signal_strength: rbuf[2-4] (24bit BE), use lower 16bit for now. */ - *strength = (rbuf[3] << 8) + rbuf[4]; - if (rbuf[2]) - *strength = 0xffff; - - return 0; -} - - -/* filter out un-supported properties to notify users */ -static int jdvbt90502_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - int r = 0; - - switch (tvp->cmd) { - case DTV_DELIVERY_SYSTEM: - if (tvp->u.data != SYS_ISDBT) - r = -EINVAL; - break; - case DTV_CLEAR: - case DTV_TUNE: - case DTV_FREQUENCY: - break; - default: - r = -EINVAL; - } - return r; -} - -static int jdvbt90502_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - p->inversion = INVERSION_AUTO; - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - p->u.ofdm.code_rate_HP = FEC_AUTO; - p->u.ofdm.code_rate_LP = FEC_AUTO; - p->u.ofdm.constellation = QAM_64; - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; - return 0; -} - -static int jdvbt90502_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - /** - * NOTE: ignore all the parameters except frequency. - * others should be fixed to the proper value for ISDB-T, - * but don't check here. - */ - - struct jdvbt90502_state *state = fe->demodulator_priv; - int ret; - - deb_fe("%s: Freq:%d\n", __func__, p->frequency); - - /* for recovery from DTV_CLEAN */ - fe->dtv_property_cache.delivery_system = SYS_ISDBT; - - ret = jdvbt90502_pll_set_freq(state, p->frequency); - if (ret) { - deb_fe("%s:ret == %d\n", __func__, ret); - return -EREMOTEIO; - } - - return 0; -} - - -/** - * (reg, val) commad list to initialize this module. - * captured on a Windows box. - */ -static u8 init_code[][2] = { - {0x01, 0x40}, - {0x04, 0x38}, - {0x05, 0x40}, - {0x07, 0x40}, - {0x0F, 0x4F}, - {0x11, 0x21}, - {0x12, 0x0B}, - {0x13, 0x2F}, - {0x14, 0x31}, - {0x16, 0x02}, - {0x21, 0xC4}, - {0x22, 0x20}, - {0x2C, 0x79}, - {0x2D, 0x34}, - {0x2F, 0x00}, - {0x30, 0x28}, - {0x31, 0x31}, - {0x32, 0xDF}, - {0x38, 0x01}, - {0x39, 0x78}, - {0x3B, 0x33}, - {0x3C, 0x33}, - {0x48, 0x90}, - {0x51, 0x68}, - {0x5E, 0x38}, - {0x71, 0x00}, - {0x72, 0x08}, - {0x77, 0x00}, - {0xC0, 0x21}, - {0xC1, 0x10}, - {0xE4, 0x1A}, - {0xEA, 0x1F}, - {0x77, 0x00}, - {0x71, 0x00}, - {0x71, 0x00}, - {0x76, 0x0C}, -}; - -static const int init_code_len = sizeof(init_code) / sizeof(u8[2]); - -static int jdvbt90502_init(struct dvb_frontend *fe) -{ - int i = -1; - int ret; - struct i2c_msg msg; - - struct jdvbt90502_state *state = fe->demodulator_priv; - - deb_fe("%s called.\n", __func__); - - msg.addr = state->config.demod_address; - msg.flags = 0; - msg.len = 2; - for (i = 0; i < init_code_len; i++) { - msg.buf = init_code[i]; - ret = i2c_transfer(state->i2c, &msg, 1); - if (ret != 1) - goto error; - } - fe->dtv_property_cache.delivery_system = SYS_ISDBT; - msleep(100); - - return 0; - -error: - deb_fe("%s: init_code[%d] failed. ret==%d\n", __func__, i, ret); - return -EREMOTEIO; -} - - -static void jdvbt90502_release(struct dvb_frontend *fe) -{ - struct jdvbt90502_state *state = fe->demodulator_priv; - kfree(state); -} - - -static struct dvb_frontend_ops jdvbt90502_ops; - -struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d) -{ - struct jdvbt90502_state *state = NULL; - - deb_info("%s called.\n", __func__); - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct jdvbt90502_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->i2c = &d->i2c_adap; - memcpy(&state->config, &friio_fe_config, sizeof(friio_fe_config)); - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &jdvbt90502_ops, - sizeof(jdvbt90502_ops)); - state->frontend.demodulator_priv = state; - - if (jdvbt90502_init(&state->frontend) < 0) - goto error; - - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops jdvbt90502_ops = { - - .info = { - .name = "Comtech JDVBT90502 ISDB-T", - .type = FE_OFDM, - .frequency_min = 473000000, /* UHF 13ch, center */ - .frequency_max = 767142857, /* UHF 62ch, center */ - .frequency_stepsize = JDVBT90502_PLL_CLK / - JDVBT90502_PLL_DIVIDER, - .frequency_tolerance = 0, - - /* NOTE: this driver ignores all parameters but frequency. */ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = jdvbt90502_release, - - .init = jdvbt90502_init, - .write = _jdvbt90502_write, - - .set_property = jdvbt90502_set_property, - - .set_frontend = jdvbt90502_set_frontend, - .get_frontend = jdvbt90502_get_frontend, - - .read_status = jdvbt90502_read_status, - .read_signal_strength = jdvbt90502_read_signal_strength, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/friio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. - * - * Copyright (C) 2009 Akihiro Tsukada - * - * This module is based off the the gl861 and vp702x modules. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_FRIIO_H_ -#define _DVB_USB_FRIIO_H_ - -/** - * Friio Components - * USB hub: AU4254 - * USB controller(+ TS dmx & streaming): GL861 - * Frontend: comtech JDVBT-90502 - * (tuner PLL: tua6034, I2C addr:(0xC0 >> 1)) - * (OFDM demodulator: TC90502, I2C addr:(0x30 >> 1)) - * LED x3 (+LNB) controll: PIC 16F676 - * EEPROM: 24C08 - * - * (USB smart card reader: AU9522) - * - */ - -#define DVB_USB_LOG_PREFIX "friio" -#include "dvb-usb.h" - -extern int dvb_usb_friio_debug; -#define deb_info(args...) dprintk(dvb_usb_friio_debug, 0x01, args) -#define deb_xfer(args...) dprintk(dvb_usb_friio_debug, 0x02, args) -#define deb_rc(args...) dprintk(dvb_usb_friio_debug, 0x04, args) -#define deb_fe(args...) dprintk(dvb_usb_friio_debug, 0x08, args) - -/* Vendor requests */ -#define GL861_WRITE 0x40 -#define GL861_READ 0xc0 - -/* command bytes */ -#define GL861_REQ_I2C_WRITE 0x01 -#define GL861_REQ_I2C_READ 0x02 -/* For control msg with data argument */ -/* Used for accessing the PLL on the secondary I2C bus of FE via GL861 */ -#define GL861_REQ_I2C_DATA_CTRL_WRITE 0x03 - -#define GL861_ALTSETTING_COUNT 2 -#define FRIIO_BULK_ALTSETTING 0 -#define FRIIO_ISOC_ALTSETTING 1 - -/* LED & LNB control via PIC. */ -/* basically, it's serial control with clock and strobe. */ -/* write the below 4bit control data to the reg 0x00 at the I2C addr 0x00 */ -/* when controlling the LEDs, 32bit(saturation, R, G, B) is sent on the bit3*/ -#define FRIIO_CTL_LNB (1 << 0) -#define FRIIO_CTL_STROBE (1 << 1) -#define FRIIO_CTL_CLK (1 << 2) -#define FRIIO_CTL_LED (1 << 3) - -/* Front End related */ - -#define FRIIO_DEMOD_ADDR (0x30 >> 1) -#define FRIIO_PLL_ADDR (0xC0 >> 1) - -#define JDVBT90502_PLL_CLK 4000000 -#define JDVBT90502_PLL_DIVIDER 28 - -#define JDVBT90502_2ND_I2C_REG 0xFE - -/* byte index for pll i2c command data structure*/ -/* see datasheet for tua6034 */ -#define DEMOD_REDIRECT_REG 0 -#define ADDRESS_BYTE 1 -#define DIVIDER_BYTE1 2 -#define DIVIDER_BYTE2 3 -#define CONTROL_BYTE 4 -#define BANDSWITCH_BYTE 5 -#define AGC_CTRL_BYTE 5 -#define PLL_CMD_LEN 6 - -/* bit masks for PLL STATUS response */ -#define PLL_STATUS_POR_MODE 0x80 /* 1: Power on Reset (test) Mode */ -#define PLL_STATUS_LOCKED 0x40 /* 1: locked */ -#define PLL_STATUS_AGC_ACTIVE 0x08 /* 1:active */ -#define PLL_STATUS_TESTMODE 0x07 /* digital output level (5 level) */ - /* 0.15Vcc step 0x00: < 0.15Vcc, ..., 0x04: >= 0.6Vcc (<= 1Vcc) */ - - -struct jdvbt90502_config { - u8 demod_address; /* i2c addr for demodulator IC */ - u8 pll_address; /* PLL addr on the secondary i2c*/ -}; -extern struct jdvbt90502_config friio_fe_config; - -extern struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gl861.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gl861.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gl861.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gl861.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,232 +0,0 @@ -/* DVB USB compliant linux driver for GL861 USB2.0 devices. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "gl861.h" - -#include "zl10353.h" -#include "qt1010.h" - -/* debug */ -static int dvb_usb_gl861_debug; -module_param_named(debug, dvb_usb_gl861_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." - DVB_USB_DEBUG_STATUS); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u16 index; - u16 value = addr << (8 + 1); - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - u8 req, type; - - if (wo) { - req = GL861_REQ_I2C_WRITE; - type = GL861_WRITE; - } else { /* rw */ - req = GL861_REQ_I2C_READ; - type = GL861_READ; - } - - switch (wlen) { - case 1: - index = wbuf[0]; - break; - case 2: - index = wbuf[0]; - value = value + wbuf[1]; - break; - default: - warn("wlen = %x, aborting.", wlen); - return -EINVAL; - } - - msleep(1); /* avoid I2C errors */ - - return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type, - value, index, rbuf, rlen, 2000); -} - -/* I2C */ -static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, msg[i+1].buf, msg[i+1].len) < 0) - break; - i++; - } else - if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, NULL, 0) < 0) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 gl861_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm gl861_i2c_algo = { - .master_xfer = gl861_i2c_xfer, - .functionality = gl861_i2c_func, -}; - -/* Callbacks for DVB USB */ -static struct zl10353_config gl861_zl10353_config = { - .demod_address = 0x0f, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static int gl861_frontend_attach(struct dvb_usb_adapter *adap) -{ - - adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config, - &adap->dev->i2c_adap); - if (adap->fe == NULL) - return -EIO; - - return 0; -} - -static struct qt1010_config gl861_qt1010_config = { - .i2c_address = 0x62 -}; - -static int gl861_tuner_attach(struct dvb_usb_adapter *adap) -{ - return dvb_attach(qt1010_attach, - adap->fe, &adap->dev->i2c_adap, - &gl861_qt1010_config) == NULL ? -ENODEV : 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties gl861_properties; - -static int gl861_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d; - struct usb_host_interface *alt; - int ret; - - if (intf->num_altsetting < 2) - return -ENODEV; - - ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d, - adapter_nr); - if (ret == 0) { - alt = usb_altnum_to_altsetting(intf, 0); - - if (alt == NULL) { - deb_rc("not alt found!\n"); - return -ENODEV; - } - - ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - } - - return ret; -} - -static struct usb_device_id gl861_table [] = { - { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) }, - { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, gl861_table); - -static struct dvb_usb_device_properties gl861_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = 0, - - .num_adapters = 1, - .adapter = {{ - - .frontend_attach = gl861_frontend_attach, - .tuner_attach = gl861_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - } }, - .i2c_algo = &gl861_i2c_algo, - - .num_device_descs = 2, - .devices = { - { - .name = "MSI Mega Sky 55801 DVB-T USB2.0", - .cold_ids = { NULL }, - .warm_ids = { &gl861_table[0], NULL }, - }, - { - .name = "A-LINK DTU DVB-T USB2.0", - .cold_ids = { NULL }, - .warm_ids = { &gl861_table[1], NULL }, - }, - } -}; - -static struct usb_driver gl861_driver = { - .name = "dvb_usb_gl861", - .probe = gl861_probe, - .disconnect = dvb_usb_device_exit, - .id_table = gl861_table, -}; - -/* module stuff */ -static int __init gl861_module_init(void) -{ - int ret; - - ret = usb_register(&gl861_driver); - if (ret) - err("usb_register failed. Error number %d", ret); - - return ret; -} - -static void __exit gl861_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&gl861_driver); -} - -module_init(gl861_module_init); -module_exit(gl861_module_exit); - -MODULE_AUTHOR("Carl Lundqvist "); -MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gl861.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gl861.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gl861.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gl861.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -#ifndef _DVB_USB_GL861_H_ -#define _DVB_USB_GL861_H_ - -#define DVB_USB_LOG_PREFIX "gl861" -#include "dvb-usb.h" - -#define deb_rc(args...) dprintk(dvb_usb_gl861_debug, 0x01, args) - -#define GL861_WRITE 0x40 -#define GL861_READ 0xc0 - -#define GL861_REQ_I2C_WRITE 0x01 -#define GL861_REQ_I2C_READ 0x02 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,343 +0,0 @@ -/* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module - * - * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) - * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) - * - * Thanks to GENPIX for the sample code used to implement this module. - * - * This module is based off the vp7045 and vp702x modules - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "gp8psk.h" - -/* debug */ -static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; -int dvb_usb_gp8psk_debug; -module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers) -{ - return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6)); -} - -static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers) -{ - return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1)); -} - -static void gp8psk_info(struct dvb_usb_device *d) -{ - u8 fpga_vers, fw_vers[6]; - - if (!gp8psk_get_fw_version(d, fw_vers)) - info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i", - fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers), - 2000 + fw_vers[5], fw_vers[4], fw_vers[3]); - else - info("failed to get FW version"); - - if (!gp8psk_get_fpga_version(d, &fpga_vers)) - info("FPGA Version = %i", fpga_vers); - else - info("failed to get FPGA version"); -} - -int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) -{ - int ret = 0,try = 0; - - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) - return ret; - - while (ret >= 0 && ret != blen && try < 3) { - ret = usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev,0), - req, - USB_TYPE_VENDOR | USB_DIR_IN, - value,index,b,blen, - 2000); - deb_info("reading number %d (ret: %d)\n",try,ret); - try++; - } - - if (ret < 0 || ret != blen) { - warn("usb in %d operation failed.", req); - ret = -EIO; - } else - ret = 0; - - deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); - debug_dump(b,blen,deb_xfer); - - mutex_unlock(&d->usb_mutex); - - return ret; -} - -int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - int ret; - - deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); - debug_dump(b,blen,deb_xfer); - - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) - return ret; - - if (usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev,0), - req, - USB_TYPE_VENDOR | USB_DIR_OUT, - value,index,b,blen, - 2000) != blen) { - warn("usb out operation failed."); - ret = -EIO; - } else - ret = 0; - mutex_unlock(&d->usb_mutex); - - return ret; -} - -static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) -{ - int ret; - const struct firmware *fw = NULL; - const u8 *ptr; - u8 *buf; - if ((ret = request_firmware(&fw, bcm4500_firmware, - &d->udev->dev)) != 0) { - err("did not find the bcm4500 firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", - bcm4500_firmware,ret); - return ret; - } - - ret = -EINVAL; - - if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) - goto out_rel_fw; - - info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); - - ptr = fw->data; - buf = kmalloc(64, GFP_KERNEL | GFP_DMA); - if (!buf) { - ret = -ENOMEM; - goto out_rel_fw; - } - - while (ptr[0] != 0xff) { - u16 buflen = ptr[0] + 4; - if (ptr + buflen >= fw->data + fw->size) { - err("failed to load bcm4500 firmware."); - goto out_free; - } - memcpy(buf, ptr, buflen); - if (dvb_usb_generic_write(d, buf, buflen)) { - err("failed to load bcm4500 firmware."); - goto out_free; - } - ptr += buflen; - } - - ret = 0; - -out_free: - kfree(buf); -out_rel_fw: - release_firmware(fw); - - return ret; -} - -static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 status, buf; - int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); - - if (onoff) { - gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); - if (! (status & bm8pskStarted)) { /* started */ - if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) - gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0); - if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) - return -EINVAL; - gp8psk_info(d); - } - - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */ - if(gp8psk_load_bcm4500fw(d)) - return -EINVAL; - - if (! (status & bmIntersilOn)) /* LNB Power */ - if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, - &buf, 1)) - return -EINVAL; - - /* Set DVB mode to 1 */ - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) - return -EINVAL; - /* Abort possible TS (if previous tune crashed) */ - if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0)) - return -EINVAL; - } else { - /* Turn off LNB power */ - if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) - return -EINVAL; - /* Turn off 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) - return -EINVAL; - if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) - gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0); - } - return 0; -} - -int gp8psk_bcm4500_reload(struct dvb_usb_device *d) -{ - u8 buf; - int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); - /* Turn off 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) - return -EINVAL; - /* Turn On 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) - return -EINVAL; - /* load BCM4500 firmware */ - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (gp8psk_load_bcm4500fw(d)) - return -EINVAL; - return 0; -} - -static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0); -} - -static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) -{ - adap->fe = gp8psk_fe_attach(adap->dev); - return 0; -} - -static struct dvb_usb_device_properties gp8psk_properties; - -static int gp8psk_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret; - struct usb_device *udev = interface_to_usbdev(intf); - ret = dvb_usb_device_init(intf, &gp8psk_properties, - THIS_MODULE, NULL, adapter_nr); - if (ret == 0) { - info("found Genpix USB device pID = %x (hex)", - le16_to_cpu(udev->descriptor.idProduct)); - } - return ret; -} - -static struct usb_device_id gp8psk_usb_table [] = { - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) }, -/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */ - { 0 }, -}; -MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); - -static struct dvb_usb_device_properties gp8psk_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-gp8psk-01.fw", - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = gp8psk_streaming_ctrl, - .frontend_attach = gp8psk_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - } - }, - .power_ctrl = gp8psk_power_ctrl, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 4, - .devices = { - { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", - .cold_ids = { &gp8psk_usb_table[0], NULL }, - .warm_ids = { &gp8psk_usb_table[1], NULL }, - }, - { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", - .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[2], NULL }, - }, - { .name = "Genpix SkyWalker-1 DVB-S receiver", - .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[3], NULL }, - }, - { .name = "Genpix SkyWalker-2 DVB-S receiver", - .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[4], NULL }, - }, - { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver gp8psk_usb_driver = { - .name = "dvb_usb_gp8psk", - .probe = gp8psk_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = gp8psk_usb_table, -}; - -/* module stuff */ -static int __init gp8psk_usb_module_init(void) -{ - int result; - if ((result = usb_register(&gp8psk_usb_driver))) { - err("usb_register failed. (%d)",result); - return result; - } - - return 0; -} - -static void __exit gp8psk_usb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&gp8psk_usb_driver); -} - -module_init(gp8psk_usb_module_init); -module_exit(gp8psk_usb_module_exit); - -MODULE_AUTHOR("Alan Nisota "); -MODULE_DESCRIPTION("Driver for Genpix DVB-S"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,378 +0,0 @@ -/* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module - * - * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) - * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) - * - * Thanks to GENPIX for the sample code used to implement this module. - * - * This module is based off the vp7045 and vp702x modules - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "gp8psk.h" - -struct gp8psk_fe_state { - struct dvb_frontend fe; - struct dvb_usb_device *d; - u8 lock; - u16 snr; - unsigned long next_status_check; - unsigned long status_check_interval; -}; - -static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 status; - gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1); - return status & bmDCtuned; -} - -static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode) -{ - struct gp8psk_fe_state *state = fe->demodulator_priv; - return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0); -} - -static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) -{ - u8 buf[6]; - if (time_after(jiffies,st->next_status_check)) { - gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); - gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); - st->snr = (buf[1]) << 8 | buf[0]; - st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; - } - return 0; -} - -static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - gp8psk_fe_update_status(st); - - if (st->lock) - *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; - else - *status = 0; - - if (*status & FE_HAS_LOCK) - st->status_check_interval = 1000; - else - st->status_check_interval = 100; - return 0; -} - -/* not supported by this Frontend */ -static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber) -{ - (void) fe; - *ber = 0; - return 0; -} - -/* not supported by this Frontend */ -static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) -{ - (void) fe; - *unc = 0; - return 0; -} - -static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - gp8psk_fe_update_status(st); - /* snr is reported in dBu*256 */ - *snr = st->snr; - return 0; -} - -static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - gp8psk_fe_update_status(st); - /* snr is reported in dBu*256 */ - /* snr / 38.4 ~= 100% strength */ - /* snr * 17 returns 100% strength as 65535 */ - if (st->snr > 0xf00) - *strength = 0xffff; - else - *strength = (st->snr << 4) + st->snr; /* snr*17 */ - return 0; -} - -static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 800; - return 0; -} - -static int gp8psk_fe_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - deb_fe("%s(..)\n", __func__); - return 0; -} - -static int gp8psk_fe_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - deb_fe("%s(..)\n", __func__); - return 0; -} - - -static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct gp8psk_fe_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u8 cmd[10]; - u32 freq = fep->frequency * 1000; - int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct); - - deb_fe("%s()\n", __func__); - - cmd[4] = freq & 0xff; - cmd[5] = (freq >> 8) & 0xff; - cmd[6] = (freq >> 16) & 0xff; - cmd[7] = (freq >> 24) & 0xff; - - switch (c->delivery_system) { - case SYS_DVBS: - /* Allow QPSK and 8PSK (even for DVB-S) */ - if (c->modulation != QPSK && c->modulation != PSK_8) { - deb_fe("%s: unsupported modulation selected (%d)\n", - __func__, c->modulation); - return -EOPNOTSUPP; - } - c->fec_inner = FEC_AUTO; - break; - case SYS_DVBS2: - deb_fe("%s: DVB-S2 delivery system selected\n", __func__); - break; - - default: - deb_fe("%s: unsupported delivery system selected (%d)\n", - __func__, c->delivery_system); - return -EOPNOTSUPP; - } - - cmd[0] = c->symbol_rate & 0xff; - cmd[1] = (c->symbol_rate >> 8) & 0xff; - cmd[2] = (c->symbol_rate >> 16) & 0xff; - cmd[3] = (c->symbol_rate >> 24) & 0xff; - switch (c->modulation) { - case QPSK: - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (gp8psk_tuned_to_DCII(fe)) - gp8psk_bcm4500_reload(state->d); - switch (c->fec_inner) { - case FEC_1_2: - cmd[9] = 0; break; - case FEC_2_3: - cmd[9] = 1; break; - case FEC_3_4: - cmd[9] = 2; break; - case FEC_5_6: - cmd[9] = 3; break; - case FEC_7_8: - cmd[9] = 4; break; - case FEC_AUTO: - cmd[9] = 5; break; - default: - cmd[9] = 5; break; - } - cmd[8] = ADV_MOD_DVB_QPSK; - break; - case PSK_8: /* PSK_8 is for compatibility with DN */ - cmd[8] = ADV_MOD_TURBO_8PSK; - switch (c->fec_inner) { - case FEC_2_3: - cmd[9] = 0; break; - case FEC_3_4: - cmd[9] = 1; break; - case FEC_3_5: - cmd[9] = 2; break; - case FEC_5_6: - cmd[9] = 3; break; - case FEC_8_9: - cmd[9] = 4; break; - default: - cmd[9] = 0; break; - } - break; - case QAM_16: /* QAM_16 is for compatibility with DN */ - cmd[8] = ADV_MOD_TURBO_16QAM; - cmd[9] = 0; - break; - default: /* Unknown modulation */ - deb_fe("%s: unsupported modulation selected (%d)\n", - __func__, c->modulation); - return -EOPNOTSUPP; - } - - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - gp8psk_set_tuner_mode(fe, 0); - gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10); - - state->lock = 0; - state->next_status_check = jiffies; - state->status_check_interval = 200; - - return 0; -} - -static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - - deb_fe("%s\n",__func__); - - if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0, - m->msg, m->msg_len)) { - return -EINVAL; - } - return 0; -} - -static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe, - fe_sec_mini_cmd_t burst) -{ - struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 cmd; - - deb_fe("%s\n",__func__); - - /* These commands are certainly wrong */ - cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01; - - if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0, - &cmd, 0)) { - return -EINVAL; - } - return 0; -} - -static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct gp8psk_fe_state* state = fe->demodulator_priv; - - if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE, - (tone == SEC_TONE_ON), 0, NULL, 0)) { - return -EINVAL; - } - return 0; -} - -static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct gp8psk_fe_state* state = fe->demodulator_priv; - - if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, - voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { - return -EINVAL; - } - return 0; -} - -static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) -{ - struct gp8psk_fe_state* state = fe->demodulator_priv; - return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); -} - -static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) -{ - struct gp8psk_fe_state* state = fe->demodulator_priv; - u8 cmd = sw_cmd & 0x7f; - - if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0, - NULL, 0)) { - return -EINVAL; - } - if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), - 0, NULL, 0)) { - return -EINVAL; - } - - return 0; -} - -static void gp8psk_fe_release(struct dvb_frontend* fe) -{ - struct gp8psk_fe_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops gp8psk_fe_ops; - -struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d) -{ - struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL); - if (s == NULL) - goto error; - - s->d = d; - memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops)); - s->fe.demodulator_priv = s; - - goto success; -error: - return NULL; -success: - return &s->fe; -} - - -static struct dvb_frontend_ops gp8psk_fe_ops = { - .info = { - .name = "Genpix DVB-S", - .type = FE_QPSK, - .frequency_min = 800000, - .frequency_max = 2250000, - .frequency_stepsize = 100, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, /* ppm */ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - /* - * FE_CAN_QAM_16 is for compatibility - * (Myth incorrectly detects Turbo-QPSK as plain QAM-16) - */ - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC - }, - - .release = gp8psk_fe_release, - - .init = NULL, - .sleep = NULL, - - .set_property = gp8psk_fe_set_property, - .get_property = gp8psk_fe_get_property, - .set_frontend = gp8psk_fe_set_frontend, - - .get_tune_settings = gp8psk_fe_get_tune_settings, - - .read_status = gp8psk_fe_read_status, - .read_ber = gp8psk_fe_read_ber, - .read_signal_strength = gp8psk_fe_read_signal_strength, - .read_snr = gp8psk_fe_read_snr, - .read_ucblocks = gp8psk_fe_read_unc_blocks, - - .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg, - .diseqc_send_burst = gp8psk_fe_send_diseqc_burst, - .set_tone = gp8psk_fe_set_tone, - .set_voltage = gp8psk_fe_set_voltage, - .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, - .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/gp8psk.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -/* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module - * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) - * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) - * - * Thanks to GENPIX for the sample code used to implement this module. - * - * This module is based off the vp7045 and vp702x modules - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_GP8PSK_H_ -#define _DVB_USB_GP8PSK_H_ - -#define DVB_USB_LOG_PREFIX "gp8psk" -#include "dvb-usb.h" - -extern int dvb_usb_gp8psk_debug; -#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args) -#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args) - -/* Twinhan Vendor requests */ -#define TH_COMMAND_IN 0xC0 -#define TH_COMMAND_OUT 0xC1 - -/* gp8psk commands */ - -#define GET_8PSK_CONFIG 0x80 /* in */ -#define SET_8PSK_CONFIG 0x81 -#define I2C_WRITE 0x83 -#define I2C_READ 0x84 -#define ARM_TRANSFER 0x85 -#define TUNE_8PSK 0x86 -#define GET_SIGNAL_STRENGTH 0x87 /* in */ -#define LOAD_BCM4500 0x88 -#define BOOT_8PSK 0x89 /* in */ -#define START_INTERSIL 0x8A /* in */ -#define SET_LNB_VOLTAGE 0x8B -#define SET_22KHZ_TONE 0x8C -#define SEND_DISEQC_COMMAND 0x8D -#define SET_DVB_MODE 0x8E -#define SET_DN_SWITCH 0x8F -#define GET_SIGNAL_LOCK 0x90 /* in */ -#define GET_FW_VERS 0x92 -#define GET_SERIAL_NUMBER 0x93 /* in */ -#define USE_EXTRA_VOLT 0x94 -#define GET_FPGA_VERS 0x95 -#define CW3K_INIT 0x9d - -/* PSK_configuration bits */ -#define bm8pskStarted 0x01 -#define bm8pskFW_Loaded 0x02 -#define bmIntersilOn 0x04 -#define bmDVBmode 0x08 -#define bm22kHz 0x10 -#define bmSEL18V 0x20 -#define bmDCtuned 0x40 -#define bmArmed 0x80 - -/* Satellite modulation modes */ -#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ -#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */ -#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */ -#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */ - -#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */ -#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */ -#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */ -#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */ -#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */ -#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */ - -#define GET_USB_SPEED 0x07 - #define USB_SPEED_LOW 0 - #define USB_SPEED_FULL 1 - #define USB_SPEED_HIGH 2 - -#define RESET_FX2 0x13 - -#define FW_VERSION_READ 0x0B -#define VENDOR_STRING_READ 0x0C -#define PRODUCT_STRING_READ 0x0D -#define FW_BCD_VERSION_READ 0x14 - -/* firmware revision id's */ -#define GP8PSK_FW_REV1 0x020604 -#define GP8PSK_FW_REV2 0x020704 -#define GP8PSK_FW_VERS(_fw_vers) ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0]) - -extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); -extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen); -extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,368 +0,0 @@ -config DVB_USB - tristate "Support for various USB DVB devices" - depends on DVB_CORE && USB && I2C && RC_CORE - help - By enabling this you will be able to choose the various supported - USB1.1 and USB2.0 DVB devices. - - Almost every USB device needs a firmware, please look into - . - - For a complete list of supported USB devices see the LinuxTV DVB Wiki: - - - Say Y if you own a USB DVB device. - -config DVB_USB_DEBUG - bool "Enable extended debug support for all DVB-USB devices" - depends on DVB_USB - help - Say Y if you want to enable debugging. See modinfo dvb-usb (and the - appropriate drivers) for debug levels. - -config DVB_USB_A800 - tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" - depends on DVB_USB - select DVB_DIB3000MC - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. - -config DVB_USB_DIBUSB_MB - tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_DIB3000MB - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - help - Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by - DiBcom () equipped with a DiB3000M-B demodulator. - - For an up-to-date list of devices supported by this driver, have a look - on the Linux-DVB Wiki at www.linuxtv.org. - - Say Y if you own such a device and want to use it. You should build it as - a module. - -config DVB_USB_DIBUSB_MB_FAULTY - bool "Support faulty USB IDs" - depends on DVB_USB_DIBUSB_MB - help - Support for faulty USB IDs due to an invalid EEPROM on some Artec devices. - -config DVB_USB_DIBUSB_MC - tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" - depends on DVB_USB - select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - help - Support for USB2.0 DVB-T receivers based on reference designs made by - DiBcom () equipped with a DiB3000M-C/P demodulator. - - For an up-to-date list of devices supported by this driver, have a look - on the Linux-DVB Wiki at www.linuxtv.org. - - Say Y if you own such a device and want to use it. You should build it as - a module. - -config DVB_USB_DIB0700 - tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)" - depends on DVB_USB - select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select DVB_DIB7000M if !DVB_FE_CUSTOMISE - select DVB_DIB8000 if !DVB_FE_CUSTOMISE - select DVB_DIB3000MC if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select DVB_LGDT3305 if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - help - Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The - USB bridge is also present in devices having the DiB7700 DVB-T-USB - silicon. This chip can be found in devices offered by Hauppauge, - Avermedia and other big and small companies. - - For an up-to-date list of devices supported by this driver, have a look - on the LinuxTV Wiki at www.linuxtv.org. - - Say Y if you own such a device and want to use it. You should build it as - a module. - -config DVB_USB_UMT_010 - tristate "HanfTek UMT-010 DVB-T USB2.0 support" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - help - Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. - -config DVB_USB_CXUSB - tristate "Conexant USB2.0 hybrid reference design support" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_CX22702 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE - select DVB_ATBM8830 if !DVB_FE_CUSTOMISE - select DVB_LGS8GXX if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Conexant USB2.0 hybrid reference design. - Currently, only DVB and ATSC modes are supported, analog mode - shall be added in the future. Devices that require this module: - - Medion MD95700 hybrid USB2.0 device. - DViCO FusionHDTV (Bluebird) USB2.0 devices - -config DVB_USB_M920X - tristate "Uli m920x DVB-T USB2.0 support" - depends on DVB_USB - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. - Currently, only devices with a product id of - "DTV USB MINI" (in cold state) are supported. - Firmware required. - -config DVB_USB_GL861 - tristate "Genesys Logic GL861 USB2.0 support" - depends on DVB_USB - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 - receiver with USB ID 0db0:5581. - -config DVB_USB_AU6610 - tristate "Alcor Micro AU6610 USB2.0 support" - depends on DVB_USB - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. - -config DVB_USB_DIGITV - tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_NXT6000 if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - help - Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. - -config DVB_USB_VP7045 - tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support" - depends on DVB_USB - help - Say Y here to support the - - TwinhanDTV Alpha (stick) (VP-7045), - TwinhanDTV MagicBox II (VP-7046), - DigitalNow TinyUSB 2 DVB-t, - DigitalRise USB 2.0 Ter (Beetle) and - TYPHOON DVB-T USB DRIVE - - DVB-T USB2.0 receivers. - -config DVB_USB_VP702X - tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support" - depends on DVB_USB - help - Say Y here to support the - - TwinhanDTV StarBox, - DigitalRise USB Starbox and - TYPHOON DVB-S USB 2.0 BOX - - DVB-S USB2.0 receivers. - -config DVB_USB_GP8PSK - tristate "GENPIX 8PSK->USB module support" - depends on DVB_USB - help - Say Y here to support the - GENPIX 8psk module - - DVB-S USB2.0 receivers. - -config DVB_USB_NOVA_T_USB2 - tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" - depends on DVB_USB - select DVB_DIB3000MC - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. - -config DVB_USB_TTUSB2 - tristate "Pinnacle 400e DVB-S USB2.0 support" - depends on DVB_USB - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - help - Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The - firmware protocol used by this module is similar to the one used by the - old ttusb-driver - that's why the module is called dvb-usb-ttusb2. - -config DVB_USB_DTT200U - tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" - depends on DVB_USB - help - Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. - - The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). - - The WT-220U and its clones are pen-sized. - -config DVB_USB_OPERA1 - tristate "Opera1 DVB-S USB2.0 receiver" - depends on DVB_USB - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_PLL if !DVB_FE_CUSTOMISE - help - Say Y here to support the Opera DVB-S USB2.0 receiver. - -config DVB_USB_AF9005 - tristate "Afatech AF9005 DVB-T USB1.1 support" - depends on DVB_USB && EXPERIMENTAL - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver - and the TerraTec Cinergy T USB XE (Rev.1) - -config DVB_USB_AF9005_REMOTE - tristate "Afatech AF9005 default remote control support" - depends on DVB_USB_AF9005 - help - Say Y here to support the default remote control decoding for the - Afatech AF9005 based receiver. - -config DVB_USB_DW2102 - tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_SI21XX if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_MT312 if !DVB_FE_CUSTOMISE - select DVB_ZL10039 if !DVB_FE_CUSTOMISE - select DVB_DS3000 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select DVB_STV6110 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE - help - Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0 - receivers. - -config DVB_USB_CINERGY_T2 - tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" - depends on DVB_USB - help - Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers - - Say Y if you own such a device and want to use it. - -config DVB_USB_ANYSEE - tristate "Anysee DVB-T/C USB2.0 support" - depends on DVB_USB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - help - Say Y here to support the Anysee E30, Anysee E30 Plus or - Anysee E30 C Plus DVB USB2.0 receiver. - -config DVB_USB_DTV5100 - tristate "AME DTV-5100 USB2.0 DVB-T support" - depends on DVB_USB - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. - -config DVB_USB_AF9015 - tristate "Afatech AF9015 DVB-T USB2.0 support" - depends on DVB_USB - select DVB_AF9013 - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver - -config DVB_USB_CE6230 - tristate "Intel CE6230 DVB-T USB2.0 support" - depends on DVB_USB && EXPERIMENTAL - select DVB_ZL10353 - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver - -config DVB_USB_FRIIO - tristate "Friio ISDB-T USB2.0 Receiver support" - depends on DVB_USB - help - Say Y here to support the Japanese DTV receiver Friio. - -config DVB_USB_EC168 - tristate "E3C EC168 DVB-T USB2.0 support" - depends on DVB_USB && EXPERIMENTAL - select DVB_EC100 - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. - -config DVB_USB_AZ6027 - tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" - depends on DVB_USB - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - help - Say Y here to support the AZ6027 device - -config DVB_USB_LME2510 - tristate "LME DM04/QQBOX DVB-S USB2.0 support" - depends on DVB_USB - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_IX2505V if !DVB_FE_CUSTOMISE - help - Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . - -config DVB_USB_TECHNISAT_USB2 - tristate "Technisat DVB-S/S2 USB2.0 support" - depends on DVB_USB - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - help - Say Y here to support the Technisat USB2 DVB-S/S2 device diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/lmedm04.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/lmedm04.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/lmedm04.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/lmedm04.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1223 +0,0 @@ -/* DVB USB compliant linux driver for - * - * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 - * LME2510C + LG TDQY-P001F - * LME2510C + BS2F7HZ0194 - * LME2510 + LG TDQY-P001F - * LME2510 + BS2F7HZ0194 - * - * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) - * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) - * - * MV001F (LME2510+LGTDQY-P001F) - * LG TDQY - P001F =(TDA8263 + TDA10086H) - * - * MVB0001F (LME2510C+LGTDQT-P001F) - * - * MV0194 (LME2510+SHARP:BS2F7HZ0194) - * SHARP:BS2F7HZ0194 = (STV0299+IX2410) - * - * MVB0194 (LME2510C+SHARP0194) - * - * For firmware see Documentation/dvb/lmedm04.txt - * - * I2C addresses: - * 0xd0 - STV0288 - Demodulator - * 0xc0 - Sharp IX2505V - Tuner - * -- - * 0x1c - TDA10086 - Demodulator - * 0xc0 - TDA8263 - Tuner - * -- - * 0xd0 - STV0299 - Demodulator - * 0xc0 - IX2410 - Tuner - * - * - * VID = 3344 PID LME2510=1122 LME2510C=1120 - * - * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com) - * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2, as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * see Documentation/dvb/README.dvb-usb for more information - * - * Known Issues : - * LME2510: Non Intel USB chipsets fail to maintain High Speed on - * Boot or Hot Plug. - * - * QQbox suffers from noise on LNB voltage. - * - * LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system - * with other tuners. After a cold reset streaming will not start. - * - * PID functions have been removed from this driver version due to - * problems with different firmware and application versions. - */ -#define DVB_USB_LOG_PREFIX "LME2510(C)" -#include -#include -#include - -#include "dvb-usb.h" -#include "lmedm04.h" -#include "tda826x.h" -#include "tda10086.h" -#include "stv0288.h" -#include "ix2505v.h" -#include "stv0299.h" -#include "dvb-pll.h" -#include "z0194a.h" - - - -/* debug */ -static int dvb_usb_lme2510_debug; -#define l_dprintk(var, level, args...) do { \ - if ((var >= level)) \ - printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \ -} while (0) - -#define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args) -#define debug_data_snipet(level, name, p) \ - deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ - *p, *(p+1), *(p+2), *(p+3), *(p+4), \ - *(p+5), *(p+6), *(p+7)); - - -module_param_named(debug, dvb_usb_lme2510_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." - DVB_USB_DEBUG_STATUS); - -static int dvb_usb_lme2510_firmware; -module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644); -MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG"); - - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define TUNER_DEFAULT 0x0 -#define TUNER_LG 0x1 -#define TUNER_S7395 0x2 -#define TUNER_S0194 0x3 - -struct lme2510_state { - u8 id; - u8 tuner_config; - u8 signal_lock; - u8 signal_level; - u8 signal_sn; - u8 time_key; - u8 i2c_talk_onoff; - u8 i2c_gate; - u8 i2c_tuner_gate_w; - u8 i2c_tuner_gate_r; - u8 i2c_tuner_addr; - u8 stream_on; - void *buffer; - struct urb *lme_urb; - void *usb_buffer; - -}; - -static int lme2510_bulk_write(struct usb_device *dev, - u8 *snd, int len, u8 pipe) -{ - int ret, actual_l; - - ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), - snd, len , &actual_l, 100); - return ret; -} - -static int lme2510_bulk_read(struct usb_device *dev, - u8 *rev, int len, u8 pipe) -{ - int ret, actual_l; - - ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), - rev, len , &actual_l, 200); - return ret; -} - -static int lme2510_usb_talk(struct dvb_usb_device *d, - u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - struct lme2510_state *st = d->priv; - u8 *buff; - int ret = 0; - - if (st->usb_buffer == NULL) { - st->usb_buffer = kmalloc(512, GFP_KERNEL); - if (st->usb_buffer == NULL) { - info("MEM Error no memory"); - return -ENOMEM; - } - } - buff = st->usb_buffer; - - /* the read/write capped at 512 */ - memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen); - - ret = mutex_lock_interruptible(&d->usb_mutex); - - if (ret < 0) - return -EAGAIN; - - ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01)); - - ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); - - msleep(10); - - ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01)); - - ret |= lme2510_bulk_read(d->udev, buff, (rlen > 512) ? - 512 : rlen , 0x01); - - if (rlen > 0) - memcpy(rbuf, buff, rlen); - - mutex_unlock(&d->usb_mutex); - - return (ret < 0) ? -ENODEV : 0; -} - -static int lme2510_stream_restart(struct dvb_usb_device *d) -{ - static u8 stream_on[] = LME_ST_ON_W; - int ret; - u8 rbuff[10]; - /*Restart Stream Command*/ - ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), - rbuff, sizeof(rbuff)); - return ret; -} -static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u32 keypress) -{ - struct dvb_usb_device *d = adap->dev; - - deb_info(1, "INT Key Keypress =%04x", keypress); - - if (keypress > 0) - rc_keydown(d->rc_dev, keypress, 0); - - return 0; -} - -static void lme2510_int_response(struct urb *lme_urb) -{ - struct dvb_usb_adapter *adap = lme_urb->context; - struct lme2510_state *st = adap->dev->priv; - static u8 *ibuf, *rbuf; - int i = 0, offset; - - switch (lme_urb->status) { - case 0: - case -ETIMEDOUT: - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - return; - default: - info("Error %x", lme_urb->status); - break; - } - - rbuf = (u8 *) lme_urb->transfer_buffer; - - offset = ((lme_urb->actual_length/8) > 4) - ? 4 : (lme_urb->actual_length/8) ; - - for (i = 0; i < offset; ++i) { - ibuf = (u8 *)&rbuf[i*8]; - deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x", - offset, i, ibuf[0], ibuf[1]); - - switch (ibuf[0]) { - case 0xaa: - debug_data_snipet(1, "INT Remote data snipet in", ibuf); - lme2510_remote_keypress(adap, - (u32)(ibuf[2] << 24) + (ibuf[3] << 16) + - (ibuf[4] << 8) + ibuf[5]); - break; - case 0xbb: - switch (st->tuner_config) { - case TUNER_LG: - if (ibuf[2] > 0) - st->signal_lock = ibuf[2]; - st->signal_level = ibuf[4]; - st->signal_sn = ibuf[3]; - st->time_key = ibuf[7]; - break; - case TUNER_S7395: - case TUNER_S0194: - /* Tweak for earlier firmware*/ - if (ibuf[1] == 0x03) { - if (ibuf[2] > 1) - st->signal_lock = ibuf[2]; - st->signal_level = ibuf[3]; - st->signal_sn = ibuf[4]; - } else { - st->signal_level = ibuf[4]; - st->signal_sn = ibuf[5]; - st->signal_lock = - (st->signal_lock & 0xf7) + - ((ibuf[2] & 0x01) << 0x03); - } - break; - default: - break; - } - debug_data_snipet(5, "INT Remote data snipet in", ibuf); - break; - case 0xcc: - debug_data_snipet(1, "INT Control data snipet", ibuf); - break; - default: - debug_data_snipet(1, "INT Unknown data snipet", ibuf); - break; - } - } - usb_submit_urb(lme_urb, GFP_ATOMIC); -} - -static int lme2510_int_read(struct dvb_usb_adapter *adap) -{ - struct lme2510_state *lme_int = adap->dev->priv; - - lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC); - - if (lme_int->lme_urb == NULL) - return -ENOMEM; - - lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 5000, GFP_ATOMIC, - &lme_int->lme_urb->transfer_dma); - - if (lme_int->buffer == NULL) - return -ENOMEM; - - usb_fill_int_urb(lme_int->lme_urb, - adap->dev->udev, - usb_rcvintpipe(adap->dev->udev, 0xa), - lme_int->buffer, - 4096, - lme2510_int_response, - adap, - 11); - - lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC); - info("INT Interupt Service Started"); - - return 0; -} - -static int lme2510_return_status(struct usb_device *dev) -{ - int ret = 0; - u8 data[10] = {0}; - - ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200); - info("Firmware Status: %x (%x)", ret , data[2]); - - return (ret < 0) ? -ENODEV : data[2]; -} - -static int lme2510_msg(struct dvb_usb_device *d, - u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - int ret = 0; - struct lme2510_state *st = d->priv; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - if (st->i2c_talk_onoff == 1) { - - ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - - switch (st->tuner_config) { - case TUNER_LG: - if (wbuf[2] == 0x1c) { - if (wbuf[3] == 0x0e) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x10)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - msleep(80); - } - } - break; - case TUNER_S7395: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x24) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5)) - msleep(5); - } - break; - case TUNER_S0194: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x1b) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - } - break; - default: - break; - } - } else { - switch (st->tuner_config) { - case TUNER_LG: - switch (wbuf[3]) { - case 0x0e: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x43: - rbuf[0] = 0x55; - rbuf[1] = st->signal_level; - break; - case 0x1c: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S7395: - switch (wbuf[3]) { - case 0x10: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x2d: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x2e: - case 0x26: - case 0x27: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S0194: - switch (wbuf[3]) { - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x1b: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x19: - case 0x25: - case 0x1e: - case 0x1d: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - default: - break; - } - - deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)", - wbuf[3], rbuf[1]); - - } - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - - -static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct lme2510_state *st = d->priv; - static u8 obuf[64], ibuf[512]; - int i, read, read_o; - u16 len; - u8 gate = st->i2c_gate; - - if (gate == 0) - gate = 5; - - if (num > 2) - warn("more than 2 i2c messages" - "at a time is not handled yet. TODO."); - - for (i = 0; i < num; i++) { - read_o = 1 & (msg[i].flags & I2C_M_RD); - read = i+1 < num && (msg[i+1].flags & I2C_M_RD); - read |= read_o; - gate = (msg[i].addr == st->i2c_tuner_addr) - ? (read) ? st->i2c_tuner_gate_r - : st->i2c_tuner_gate_w - : st->i2c_gate; - obuf[0] = gate | (read << 7); - - if (gate == 5) - obuf[1] = (read) ? 2 : msg[i].len + 1; - else - obuf[1] = msg[i].len + read + 1; - - obuf[2] = msg[i].addr; - if (read) { - if (read_o) - len = 3; - else { - memcpy(&obuf[3], msg[i].buf, msg[i].len); - obuf[msg[i].len+3] = msg[i+1].len; - len = msg[i].len+4; - } - } else { - memcpy(&obuf[3], msg[i].buf, msg[i].len); - len = msg[i].len+3; - } - - if (lme2510_msg(d, obuf, len, ibuf, 512) < 0) { - deb_info(1, "i2c transfer failed."); - return -EAGAIN; - } - - if (read) { - if (read_o) - memcpy(msg[i].buf, &ibuf[1], msg[i].len); - else { - memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); - i++; - } - } - } - return i; -} - -static u32 lme2510_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm lme2510_i2c_algo = { - .master_xfer = lme2510_i2c_xfer, - .functionality = lme2510_i2c_func, -}; - -/* Callbacks for DVB USB */ -static int lme2510_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - *cold = 0; - return 0; -} - -static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct lme2510_state *st = adap->dev->priv; - static u8 clear_reg_3[] = LME_CLEAR_PID; - static u8 rbuf[1]; - int ret = 0, rlen = sizeof(rbuf); - - deb_info(1, "STM (%02x)", onoff); - - /* Streaming is started by FE_HAS_LOCK */ - if (onoff == 1) - st->stream_on = 1; - else { - deb_info(1, "STM Steam Off"); - /* mutex is here only to avoid collision with I2C */ - ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); - - ret |= lme2510_usb_talk(adap->dev, clear_reg_3, - sizeof(clear_reg_3), rbuf, rlen); - st->stream_on = 0; - st->i2c_talk_onoff = 1; - - mutex_unlock(&adap->dev->i2c_mutex); - } - - return (ret < 0) ? -ENODEV : 0; -} - -static int lme2510_int_service(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap->dev; - struct rc_dev *rc; - int ret; - - info("STA Configuring Remote"); - - rc = rc_allocate_device(); - if (!rc) - return -ENOMEM; - - usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - - rc->input_name = "LME2510 Remote Control"; - rc->input_phys = d->rc_phys; - rc->map_name = RC_MAP_LME2510; - rc->driver_name = "LME 2510"; - usb_to_input_id(d->udev, &rc->input_id); - - ret = rc_register_device(rc); - if (ret) { - rc_free_device(rc); - return ret; - } - d->rc_dev = rc; - - /* Start the Interupt */ - ret = lme2510_int_read(adap); - if (ret < 0) { - rc_unregister_device(rc); - info("INT Unable to start Interupt Service"); - return -ENODEV; - } - - return 0; -} - -static u8 check_sum(u8 *p, u8 len) -{ - u8 sum = 0; - while (len--) - sum += *p++; - return sum; -} - -static int lme2510_download_firmware(struct usb_device *dev, - const struct firmware *fw) -{ - int ret = 0; - u8 data[512] = {0}; - u16 j, wlen, len_in, start, end; - u8 packet_size, dlen, i; - u8 *fw_data; - - packet_size = 0x31; - len_in = 1; - - - info("FRM Starting Firmware Download"); - - for (i = 1; i < 3; i++) { - start = (i == 1) ? 0 : 512; - end = (i == 1) ? 512 : fw->size; - for (j = start; j < end; j += (packet_size+1)) { - fw_data = (u8 *)(fw->data + j); - if ((end - j) > packet_size) { - data[0] = i; - dlen = packet_size; - } else { - data[0] = i | 0x80; - dlen = (u8)(end - j)-1; - } - data[1] = dlen; - memcpy(&data[2], fw_data, dlen+1); - wlen = (u8) dlen + 4; - data[wlen-1] = check_sum(fw_data, dlen+1); - deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3], - data[dlen+2], data[dlen+3]); - ret |= lme2510_bulk_write(dev, data, wlen, 1); - ret |= lme2510_bulk_read(dev, data, len_in , 1); - ret |= (data[0] == 0x88) ? 0 : -1; - } - } - - usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000); - - - data[0] = 0x8a; - len_in = 1; - msleep(2000); - ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Resetting*/ - ret |= lme2510_bulk_read(dev, data, len_in, 1); - msleep(400); - - if (ret < 0) - info("FRM Firmware Download Failed (%04x)" , ret); - else - info("FRM Firmware Download Completed - Resetting Device"); - - - return (ret < 0) ? -ENODEV : 0; -} - -static void lme_coldreset(struct usb_device *dev) -{ - int ret = 0, len_in; - u8 data[512] = {0}; - - data[0] = 0x0a; - len_in = 1; - info("FRM Firmware Cold Reset"); - ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/ - ret |= lme2510_bulk_read(dev, data, len_in, 1); - - return; -} - -static int lme_firmware_switch(struct usb_device *udev, int cold) -{ - const struct firmware *fw = NULL; - const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw"; - const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw"; - const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw"; - const char fw_lg[] = "dvb-usb-lme2510-lg.fw"; - const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw"; - const char *fw_lme; - int ret, cold_fw; - - cold = (cold > 0) ? (cold & 1) : 0; - - cold_fw = !cold; - - if (udev->descriptor.idProduct == 0x1122) { - switch (dvb_usb_lme2510_firmware) { - default: - dvb_usb_lme2510_firmware = TUNER_S0194; - case TUNER_S0194: - fw_lme = fw_s0194; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) { - cold = 0;/*lme2510-s0194 cannot cold reset*/ - break; - } - dvb_usb_lme2510_firmware = TUNER_LG; - case TUNER_LG: - fw_lme = fw_lg; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - info("FRM No Firmware Found - please install"); - dvb_usb_lme2510_firmware = TUNER_DEFAULT; - cold = 0; - cold_fw = 0; - break; - } - } else { - switch (dvb_usb_lme2510_firmware) { - default: - dvb_usb_lme2510_firmware = TUNER_S7395; - case TUNER_S7395: - fw_lme = fw_c_s7395; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - dvb_usb_lme2510_firmware = TUNER_LG; - case TUNER_LG: - fw_lme = fw_c_lg; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - dvb_usb_lme2510_firmware = TUNER_S0194; - case TUNER_S0194: - fw_lme = fw_c_s0194; - ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) - break; - info("FRM No Firmware Found - please install"); - dvb_usb_lme2510_firmware = TUNER_DEFAULT; - cold = 0; - cold_fw = 0; - break; - } - } - - if (cold_fw) { - info("FRM Loading %s file", fw_lme); - ret = lme2510_download_firmware(udev, fw); - } - - if (cold) { - info("FRM Changing to %s firmware", fw_lme); - lme_coldreset(udev); - return -ENODEV; - } - - release_firmware(fw); - - return ret; -} - -static int lme2510_kill_urb(struct usb_data_stream *stream) -{ - int i; - - for (i = 0; i < stream->urbs_submitted; i++) { - deb_info(3, "killing URB no. %d.", i); - /* stop the URB */ - usb_kill_urb(stream->urb_list[i]); - } - stream->urbs_submitted = 0; - - return 0; -} - -static struct tda10086_config tda10086_config = { - .demod_address = 0x1c, - .invert = 0, - .diseqc_tone = 1, - .xtal_freq = TDA10086_XTAL_16M, -}; - -static struct stv0288_config lme_config = { - .demod_address = 0xd0, - .min_delay_ms = 15, - .inittab = s7395_inittab, -}; - -static struct ix2505v_config lme_tuner = { - .tuner_address = 0xc0, - .min_delay_ms = 100, - .tuner_gain = 0x0, - .tuner_chargepump = 0x3, -}; - -static struct stv0299_config sharp_z0194_config = { - .demod_address = 0xd0, - .inittab = sharp_z0194a_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a_set_symbol_rate, -}; - -static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - static u8 voltage_low[] = LME_VOLTAGE_L; - static u8 voltage_high[] = LME_VOLTAGE_H; - static u8 rbuf[1]; - int ret = 0, len = 3, rlen = 1; - - if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) - return -EAGAIN; - - switch (voltage) { - case SEC_VOLTAGE_18: - ret |= lme2510_usb_talk(adap->dev, - voltage_high, len, rbuf, rlen); - break; - - case SEC_VOLTAGE_OFF: - case SEC_VOLTAGE_13: - default: - ret |= lme2510_usb_talk(adap->dev, - voltage_low, len, rbuf, rlen); - break; - } - - mutex_unlock(&adap->dev->i2c_mutex); - - return (ret < 0) ? -ENODEV : 0; -} - -static int lme_name(struct dvb_usb_adapter *adap) -{ - struct lme2510_state *st = adap->dev->priv; - const char *desc = adap->dev->desc->name; - char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", - " SHARP:BS2F7HZ0194"}; - char *name = adap->fe->ops.info.name; - - strlcpy(name, desc, 128); - strlcat(name, fe_name[st->tuner_config], 128); - - return 0; -} - -static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct lme2510_state *st = adap->dev->priv; - - int ret = 0; - - st->i2c_talk_onoff = 1; - - st->i2c_gate = 4; - adap->fe = dvb_attach(tda10086_attach, &tda10086_config, - &adap->dev->i2c_adap); - - if (adap->fe) { - info("TUN Found Frontend TDA10086"); - st->i2c_tuner_gate_w = 4; - st->i2c_tuner_gate_r = 4; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_LG; - if (dvb_usb_lme2510_firmware != TUNER_LG) { - dvb_usb_lme2510_firmware = TUNER_LG; - ret = lme_firmware_switch(adap->dev->udev, 1); - } - goto end; - } - - st->i2c_gate = 4; - adap->fe = dvb_attach(stv0299_attach, &sharp_z0194_config, - &adap->dev->i2c_adap); - if (adap->fe) { - info("FE Found Stv0299"); - st->i2c_tuner_gate_w = 4; - st->i2c_tuner_gate_r = 5; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_S0194; - if (dvb_usb_lme2510_firmware != TUNER_S0194) { - dvb_usb_lme2510_firmware = TUNER_S0194; - ret = lme_firmware_switch(adap->dev->udev, 1); - } - goto end; - } - - st->i2c_gate = 5; - adap->fe = dvb_attach(stv0288_attach, &lme_config, - &adap->dev->i2c_adap); - if (adap->fe) { - info("FE Found Stv0288"); - st->i2c_tuner_gate_w = 4; - st->i2c_tuner_gate_r = 5; - st->i2c_tuner_addr = 0xc0; - st->tuner_config = TUNER_S7395; - if (dvb_usb_lme2510_firmware != TUNER_S7395) { - dvb_usb_lme2510_firmware = TUNER_S7395; - ret = lme_firmware_switch(adap->dev->udev, 1); - } - } else { - info("DM04 Not Supported"); - return -ENODEV; - } - - -end: if (ret) { - kfree(adap->fe); - adap->fe = NULL; - return -ENODEV; - } - - adap->fe->ops.set_voltage = dm04_lme2510_set_voltage; - ret = lme_name(adap); - return ret; -} - -static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) -{ - struct lme2510_state *st = adap->dev->priv; - char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"}; - int ret = 0; - - switch (st->tuner_config) { - case TUNER_LG: - if (dvb_attach(tda826x_attach, adap->fe, 0xc0, - &adap->dev->i2c_adap, 1)) - ret = st->tuner_config; - break; - case TUNER_S7395: - if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner, - &adap->dev->i2c_adap)) - ret = st->tuner_config; - break; - case TUNER_S0194: - if (dvb_attach(dvb_pll_attach , adap->fe, 0xc0, - &adap->dev->i2c_adap, DVB_PLL_OPERA1)) - ret = st->tuner_config; - break; - default: - break; - } - - if (ret) - info("TUN Found %s tuner", tun_msg[ret]); - else { - info("TUN No tuner found --- reseting device"); - lme_coldreset(adap->dev->udev); - return -ENODEV; - } - - /* Start the Interupt & Remote*/ - ret = lme2510_int_service(adap); - - return ret; -} - -static int lme2510_powerup(struct dvb_usb_device *d, int onoff) -{ - struct lme2510_state *st = d->priv; - static u8 lnb_on[] = LNB_ON; - static u8 lnb_off[] = LNB_OFF; - static u8 rbuf[1]; - int ret, len = 3, rlen = 1; - - ret = mutex_lock_interruptible(&d->i2c_mutex); - - if (onoff) - ret |= lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); - else - ret |= lme2510_usb_talk(d, lnb_off, len, rbuf, rlen); - - st->i2c_talk_onoff = 1; - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties lme2510_properties; -static struct dvb_usb_device_properties lme2510c_properties; - -static int lme2510_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - int ret = 0; - - usb_reset_configuration(udev); - - usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1); - - if (udev->speed != USB_SPEED_HIGH) { - ret = usb_reset_device(udev); - info("DEV Failed to connect in HIGH SPEED mode"); - return -ENODEV; - } - - if (lme2510_return_status(udev) == 0x44) { - lme_firmware_switch(udev, 0); - return -ENODEV; - } - - if (0 == dvb_usb_device_init(intf, &lme2510_properties, - THIS_MODULE, NULL, adapter_nr)) { - info("DEV registering device driver"); - return 0; - } - if (0 == dvb_usb_device_init(intf, &lme2510c_properties, - THIS_MODULE, NULL, adapter_nr)) { - info("DEV registering device driver"); - return 0; - } - - info("DEV lme2510 Error"); - return -ENODEV; - -} - -static struct usb_device_id lme2510_table[] = { - { USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */ - { USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */ - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, lme2510_table); - -static struct dvb_usb_device_properties lme2510_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .size_of_priv = sizeof(struct lme2510_state), - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = lme2510_streaming_ctrl, - .frontend_attach = dm04_lme2510_frontend_attach, - .tuner_attach = dm04_lme2510_tuner, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - - } - } - } - } - }, - .power_ctrl = lme2510_powerup, - .identify_state = lme2510_identify_state, - .i2c_algo = &lme2510_i2c_algo, - .generic_bulk_ctrl_endpoint = 0, - .num_device_descs = 1, - .devices = { - { "DM04_LME2510_DVB-S", - { &lme2510_table[0], NULL }, - }, - - } -}; - -static struct dvb_usb_device_properties lme2510c_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .size_of_priv = sizeof(struct lme2510_state), - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = lme2510_streaming_ctrl, - .frontend_attach = dm04_lme2510_frontend_attach, - .tuner_attach = dm04_lme2510_tuner, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x8, - .u = { - .bulk = { - .buffersize = 4096, - - } - } - } - } - }, - .power_ctrl = lme2510_powerup, - .identify_state = lme2510_identify_state, - .i2c_algo = &lme2510_i2c_algo, - .generic_bulk_ctrl_endpoint = 0, - .num_device_descs = 1, - .devices = { - { "DM04_LME2510C_DVB-S", - { &lme2510_table[1], NULL }, - }, - } -}; - -void *lme2510_exit_int(struct dvb_usb_device *d) -{ - struct lme2510_state *st = d->priv; - struct dvb_usb_adapter *adap = &d->adapter[0]; - void *buffer = NULL; - - if (adap != NULL) { - lme2510_kill_urb(&adap->stream); - adap->feedcount = 0; - } - - if (st->lme_urb != NULL) { - st->i2c_talk_onoff = 1; - st->signal_lock = 0; - st->signal_level = 0; - st->signal_sn = 0; - buffer = st->usb_buffer; - usb_kill_urb(st->lme_urb); - usb_free_coherent(d->udev, 5000, st->buffer, - st->lme_urb->transfer_dma); - info("Interupt Service Stopped"); - rc_unregister_device(d->rc_dev); - info("Remote Stopped"); - } - return buffer; -} - -void lme2510_exit(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - void *usb_buffer; - - if (d != NULL) { - usb_buffer = lme2510_exit_int(d); - dvb_usb_device_exit(intf); - kfree(usb_buffer); - } -} - -static struct usb_driver lme2510_driver = { - .name = "LME2510C_DVB-S", - .probe = lme2510_probe, - .disconnect = lme2510_exit, - .id_table = lme2510_table, -}; - -/* module stuff */ -static int __init lme2510_module_init(void) -{ - int result = usb_register(&lme2510_driver); - if (result) { - err("usb_register failed. Error number %d", result); - return result; - } - - return 0; -} - -static void __exit lme2510_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&lme2510_driver); -} - -module_init(lme2510_module_init); -module_exit(lme2510_module_exit); - -MODULE_AUTHOR("Malcolm Priestley "); -MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/lmedm04.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/lmedm04.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/lmedm04.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/lmedm04.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,173 +0,0 @@ -/* DVB USB compliant linux driver for - * - * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 - * LME2510C + LG TDQY-P001F - * LME2510 + LG TDQY-P001F - * - * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) - * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) - * - * MVB001F (LME2510+LGTDQT-P001F) - * LG TDQY - P001F =(TDA8263 + TDA10086H) - * - * MVB0001F (LME2510C+LGTDQT-P001F) - * - * 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, version 2. - * * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_LME2510_H_ -#define _DVB_USB_LME2510_H_ - -/* Streamer & PID - * - * Note: These commands do not actually stop the streaming - * but form some kind of packet filtering/stream count - * or tuning related functions. - * 06 XX - * offset 1 = 00 Enable Streaming - * - * - * PID - * 03 XX XX ----> reg number ---> setting....20 XX - * offset 1 = length - * offset 2 = start of data - * end byte -1 = 20 - * end byte = clear pid always a0, other wise 9c, 9a ?? - * -*/ -#define LME_ST_ON_W {0x06, 0x00} -#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} - -/* LNB Voltage - * 07 XX XX - * offset 1 = 01 - * offset 2 = 00=Voltage low 01=Voltage high - * - * LNB Power - * 03 01 XX - * offset 2 = 00=ON 01=OFF - */ - -#define LME_VOLTAGE_L {0x07, 0x01, 0x00} -#define LME_VOLTAGE_H {0x07, 0x01, 0x01} -#define LNB_ON {0x3a, 0x01, 0x00} -#define LNB_OFF {0x3a, 0x01, 0x01} - -/* Initial stv0288 settings for 7395 Frontend */ -static u8 s7395_inittab[] = { - 0x01, 0x15, - 0x02, 0x20, - 0x03, 0xa0, - 0x04, 0xa0, - 0x05, 0x12, - 0x06, 0x00, - 0x09, 0x00, - 0x0a, 0x04, - 0x0b, 0x00, - 0x0c, 0x00, - 0x0d, 0x00, - 0x0e, 0xc1, - 0x0f, 0x54, - 0x11, 0x7a, - 0x12, 0x03, - 0x13, 0x48, - 0x14, 0x84, - 0x15, 0xc5, - 0x16, 0xb8, - 0x17, 0x9c, - 0x18, 0x00, - 0x19, 0xa6, - 0x1a, 0x88, - 0x1b, 0x8f, - 0x1c, 0xf0, - 0x20, 0x0b, - 0x21, 0x54, - 0x22, 0xff, - 0x23, 0x01, - 0x28, 0x46, - 0x29, 0x66, - 0x2a, 0x90, - 0x2b, 0xfa, - 0x2c, 0xd9, - 0x30, 0x0, - 0x31, 0x1e, - 0x32, 0x14, - 0x33, 0x0f, - 0x34, 0x09, - 0x35, 0x0c, - 0x36, 0x05, - 0x37, 0x2f, - 0x38, 0x16, - 0x39, 0xbd, - 0x3a, 0x0, - 0x3b, 0x13, - 0x3c, 0x11, - 0x3d, 0x30, - 0x40, 0x63, - 0x41, 0x04, - 0x42, 0x60, - 0x43, 0x00, - 0x44, 0x00, - 0x45, 0x00, - 0x46, 0x00, - 0x47, 0x00, - 0x4a, 0x00, - 0x50, 0x12, - 0x51, 0x36, - 0x52, 0x21, - 0x53, 0x94, - 0x54, 0xb2, - 0x55, 0x29, - 0x56, 0x64, - 0x57, 0x2b, - 0x58, 0x54, - 0x59, 0x86, - 0x5a, 0x00, - 0x5b, 0x9b, - 0x5c, 0x08, - 0x5d, 0x7f, - 0x5e, 0xff, - 0x5f, 0x8d, - 0x70, 0x0, - 0x71, 0x0, - 0x72, 0x0, - 0x74, 0x0, - 0x75, 0x0, - 0x76, 0x0, - 0x81, 0x0, - 0x82, 0x3f, - 0x83, 0x3f, - 0x84, 0x0, - 0x85, 0x0, - 0x88, 0x0, - 0x89, 0x0, - 0x8a, 0x0, - 0x8b, 0x0, - 0x8c, 0x0, - 0x90, 0x0, - 0x91, 0x0, - 0x92, 0x0, - 0x93, 0x0, - 0x94, 0x1c, - 0x97, 0x0, - 0xa0, 0x48, - 0xa1, 0x0, - 0xb0, 0xb8, - 0xb1, 0x3a, - 0xb2, 0x10, - 0xb3, 0x82, - 0xb4, 0x80, - 0xb5, 0x82, - 0xb6, 0x82, - 0xb7, 0x82, - 0xb8, 0x20, - 0xb9, 0x0, - 0xf0, 0x0, - 0xf1, 0x0, - 0xf2, 0xc0, - 0xff, 0xff, -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/m920x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/m920x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/m920x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/m920x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1081 +0,0 @@ -/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver - * - * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ - -#include "m920x.h" - -#include "mt352.h" -#include "mt352_priv.h" -#include "qt1010.h" -#include "tda1004x.h" -#include "tda827x.h" - -#include -#include "tuner-simple.h" -#include - -/* debug */ -static int dvb_usb_m920x_debug; -module_param_named(debug,dvb_usb_m920x_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid); - -static inline int m920x_read(struct usb_device *udev, u8 request, u16 value, - u16 index, void *data, int size) -{ - int ret; - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - request, USB_TYPE_VENDOR | USB_DIR_IN, - value, index, data, size, 2000); - if (ret < 0) { - printk(KERN_INFO "m920x_read = error: %d\n", ret); - return ret; - } - - if (ret != size) { - deb("m920x_read = no data\n"); - return -EIO; - } - - return 0; -} - -static inline int m920x_write(struct usb_device *udev, u8 request, - u16 value, u16 index) -{ - int ret; - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - request, USB_TYPE_VENDOR | USB_DIR_OUT, - value, index, NULL, 0, 2000); - - return ret; -} - -static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) -{ - int ret = 0, i, epi, flags = 0; - int adap_enabled[M9206_MAX_ADAPTERS] = { 0 }; - - /* Remote controller init. */ - if (d->props.rc.legacy.rc_query) { - deb("Initialising remote control\n"); - while (rc_seq->address) { - if ((ret = m920x_write(d->udev, M9206_CORE, - rc_seq->data, - rc_seq->address)) != 0) { - deb("Initialising remote control failed\n"); - return ret; - } - - rc_seq++; - } - - deb("Initialising remote control success\n"); - } - - for (i = 0; i < d->props.num_adapters; i++) - flags |= d->adapter[i].props.caps; - - /* Some devices(Dposh) might crash if we attempt touch at all. */ - if (flags & DVB_USB_ADAP_HAS_PID_FILTER) { - for (i = 0; i < d->props.num_adapters; i++) { - epi = d->adapter[i].props.stream.endpoint - 0x81; - - if (epi < 0 || epi >= M9206_MAX_ADAPTERS) { - printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n"); - return -EINVAL; - } - - adap_enabled[epi] = 1; - } - - for (i = 0; i < M9206_MAX_ADAPTERS; i++) { - if (adap_enabled[i]) - continue; - - if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0) - return ret; - - if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0) - return ret; - } - } - - return ret; -} - -static int m920x_init_ep(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_interface *alt; - - if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) { - deb("No alt found!\n"); - return -ENODEV; - } - - return usb_set_interface(udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); -} - -static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - struct m920x_state *m = d->priv; - int i, ret = 0; - u8 rc_state[2]; - - if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0) - goto unlock; - - if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0) - goto unlock; - - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) { - *event = d->props.rc.legacy.rc_map_table[i].keycode; - - switch(rc_state[0]) { - case 0x80: - *state = REMOTE_NO_KEY_PRESSED; - goto unlock; - - case 0x88: /* framing error or "invalid code" */ - case 0x99: - case 0xc0: - case 0xd8: - *state = REMOTE_NO_KEY_PRESSED; - m->rep_count = 0; - goto unlock; - - case 0x93: - case 0x92: - case 0x83: /* pinnacle PCTV310e */ - case 0x82: - m->rep_count = 0; - *state = REMOTE_KEY_PRESSED; - goto unlock; - - case 0x91: - case 0x81: /* pinnacle PCTV310e */ - /* prevent immediate auto-repeat */ - if (++m->rep_count > 2) - *state = REMOTE_KEY_REPEAT; - else - *state = REMOTE_NO_KEY_PRESSED; - goto unlock; - - default: - deb("Unexpected rc state %02x\n", rc_state[0]); - *state = REMOTE_NO_KEY_PRESSED; - goto unlock; - } - } - - if (rc_state[1] != 0) - deb("Unknown rc key %02x\n", rc_state[1]); - - *state = REMOTE_NO_KEY_PRESSED; - - unlock: - - return ret; -} - -/* I2C */ -static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i, j; - int ret = 0; - - if (!num) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - if (msg[i].flags & (I2C_M_NO_RD_ACK | I2C_M_IGNORE_NAK | I2C_M_TEN) || msg[i].len == 0) { - /* For a 0 byte message, I think sending the address - * to index 0x80|0x40 would be the correct thing to - * do. However, zero byte messages are only used for - * probing, and since we don't know how to get the - * slave's ack, we can't probe. */ - ret = -ENOTSUPP; - goto unlock; - } - /* Send START & address/RW bit */ - if (!(msg[i].flags & I2C_M_NOSTART)) { - if ((ret = m920x_write(d->udev, M9206_I2C, - (msg[i].addr << 1) | - (msg[i].flags & I2C_M_RD ? 0x01 : 0), 0x80)) != 0) - goto unlock; - /* Should check for ack here, if we knew how. */ - } - if (msg[i].flags & I2C_M_RD) { - for (j = 0; j < msg[i].len; j++) { - /* Last byte of transaction? - * Send STOP, otherwise send ACK. */ - int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x01; - - if ((ret = m920x_read(d->udev, M9206_I2C, 0x0, - 0x20 | stop, - &msg[i].buf[j], 1)) != 0) - goto unlock; - } - } else { - for (j = 0; j < msg[i].len; j++) { - /* Last byte of transaction? Then send STOP. */ - int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x00; - - if ((ret = m920x_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0) - goto unlock; - /* Should check for ack here too. */ - } - } - } - ret = num; - - unlock: - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static u32 m920x_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm m920x_i2c_algo = { - .master_xfer = m920x_i2c_xfer, - .functionality = m920x_i2c_func, -}; - -/* pid filter */ -static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid) -{ - int ret = 0; - - if (pid >= 0x8000) - return -EINVAL; - - pid |= 0x8000; - - if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0) - return ret; - - if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0) - return ret; - - return ret; -} - -static int m920x_update_filters(struct dvb_usb_adapter *adap) -{ - struct m920x_state *m = adap->dev->priv; - int enabled = m->filtering_enabled[adap->id]; - int i, ret = 0, filter = 0; - int ep = adap->props.stream.endpoint; - - for (i = 0; i < M9206_MAX_FILTERS; i++) - if (m->filters[adap->id][i] == 8192) - enabled = 0; - - /* Disable all filters */ - if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0) - return ret; - - for (i = 0; i < M9206_MAX_FILTERS; i++) - if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0) - return ret; - - /* Set */ - if (enabled) { - for (i = 0; i < M9206_MAX_FILTERS; i++) { - if (m->filters[adap->id][i] == 0) - continue; - - if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0) - return ret; - - filter++; - } - } - - return ret; -} - -static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct m920x_state *m = adap->dev->priv; - - m->filtering_enabled[adap->id] = onoff ? 1 : 0; - - return m920x_update_filters(adap); -} - -static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) -{ - struct m920x_state *m = adap->dev->priv; - - m->filters[adap->id][index] = onoff ? pid : 0; - - return m920x_update_filters(adap); -} - -static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw) -{ - u16 value, index, size; - u8 read[4], *buff; - int i, pass, ret = 0; - - buff = kmalloc(65536, GFP_KERNEL); - if (buff == NULL) - return -ENOMEM; - - if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) - goto done; - deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]); - - if ((ret = m920x_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0) - goto done; - deb("%x\n", read[0]); - - for (pass = 0; pass < 2; pass++) { - for (i = 0; i + (sizeof(u16) * 3) < fw->size;) { - value = get_unaligned_le16(fw->data + i); - i += sizeof(u16); - - index = get_unaligned_le16(fw->data + i); - i += sizeof(u16); - - size = get_unaligned_le16(fw->data + i); - i += sizeof(u16); - - if (pass == 1) { - /* Will stall if using fw->data ... */ - memcpy(buff, fw->data + i, size); - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), - M9206_FW, - USB_TYPE_VENDOR | USB_DIR_OUT, - value, index, buff, size, 20); - if (ret != size) { - deb("error while uploading fw!\n"); - ret = -EIO; - goto done; - } - msleep(3); - } - i += size; - } - if (i != fw->size) { - deb("bad firmware file!\n"); - ret = -EINVAL; - goto done; - } - } - - msleep(36); - - /* m920x will disconnect itself from the bus after this. */ - (void) m920x_write(udev, M9206_CORE, 0x01, M9206_FW_GO); - deb("firmware uploaded!\n"); - - done: - kfree(buff); - - return ret; -} - -/* Callbacks for DVB USB */ -static int m920x_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - struct usb_host_interface *alt; - - alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1); - *cold = (alt == NULL) ? 1 : 0; - - return 0; -} - -/* demod configurations */ -static int m920x_mt352_demod_init(struct dvb_frontend *fe) -{ - int ret; - u8 config[] = { CONFIG, 0x3d }; - u8 clock[] = { CLOCK_CTL, 0x30 }; - u8 reset[] = { RESET, 0x80 }; - u8 adc_ctl[] = { ADC_CTL_1, 0x40 }; - u8 agc[] = { AGC_TARGET, 0x1c, 0x20 }; - u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 }; - u8 unk1[] = { 0x93, 0x1a }; - u8 unk2[] = { 0xb5, 0x7a }; - - deb("Demod init!\n"); - - if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0) - return ret; - if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0) - return ret; - if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0) - return ret; - if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0) - return ret; - if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0) - return ret; - if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0) - return ret; - if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0) - return ret; - if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0) - return ret; - - return 0; -} - -static struct mt352_config m920x_mt352_config = { - .demod_address = 0x0f, - .no_tuner = 1, - .demod_init = m920x_mt352_demod_init, -}; - -static struct tda1004x_config m920x_tda10046_08_config = { - .demod_address = 0x08, - .invert = 0, - .invert_oclk = 0, - .ts_mode = TDA10046_TS_SERIAL, - .xtal_freq = TDA10046_XTAL_16M, - .if_freq = TDA10046_FREQ_045, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GPTRI, - .request_firmware = NULL, -}; - -static struct tda1004x_config m920x_tda10046_0b_config = { - .demod_address = 0x0b, - .invert = 0, - .invert_oclk = 0, - .ts_mode = TDA10046_TS_SERIAL, - .xtal_freq = TDA10046_XTAL_16M, - .if_freq = TDA10046_FREQ_045, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GPTRI, - .request_firmware = NULL, /* uses firmware EEPROM */ -}; - -/* tuner configurations */ -static struct qt1010_config m920x_qt1010_config = { - .i2c_address = 0x62 -}; - -/* Callbacks for DVB USB */ -static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - if ((adap->fe = dvb_attach(mt352_attach, - &m920x_mt352_config, - &adap->dev->i2c_adap)) == NULL) - return -EIO; - - return 0; -} - -static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - if ((adap->fe = dvb_attach(tda10046_attach, - &m920x_tda10046_08_config, - &adap->dev->i2c_adap)) == NULL) - return -EIO; - - return 0; -} - -static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - if ((adap->fe = dvb_attach(tda10046_attach, - &m920x_tda10046_0b_config, - &adap->dev->i2c_adap)) == NULL) - return -EIO; - - return 0; -} - -static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) - return -ENODEV; - - return 0; -} - -static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL) - return -ENODEV; - - return 0; -} - -static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) -{ - deb("%s\n",__func__); - - if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) - return -ENODEV; - - return 0; -} - -static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(simple_tuner_attach, adap->fe, - &adap->dev->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3); - return 0; -} - -/* device-specific initialization */ -static struct m920x_inits megasky_rc_init [] = { - { M9206_RC_INIT2, 0xa8 }, - { M9206_RC_INIT1, 0x51 }, - { } /* terminating entry */ -}; - -static struct m920x_inits tvwalkertwin_rc_init [] = { - { M9206_RC_INIT2, 0x00 }, - { M9206_RC_INIT1, 0xef }, - { 0xff28, 0x00 }, - { 0xff23, 0x00 }, - { 0xff21, 0x30 }, - { } /* terminating entry */ -}; - -static struct m920x_inits pinnacle310e_init[] = { - /* without these the tuner don't work */ - { 0xff20, 0x9b }, - { 0xff22, 0x70 }, - - /* rc settings */ - { 0xff50, 0x80 }, - { M9206_RC_INIT1, 0x00 }, - { M9206_RC_INIT2, 0xff }, - { } /* terminating entry */ -}; - -/* ir keymaps */ -static struct rc_map_table rc_map_megasky_table[] = { - { 0x0012, KEY_POWER }, - { 0x001e, KEY_CYCLEWINDOWS }, /* min/max */ - { 0x0002, KEY_CHANNELUP }, - { 0x0005, KEY_CHANNELDOWN }, - { 0x0003, KEY_VOLUMEUP }, - { 0x0006, KEY_VOLUMEDOWN }, - { 0x0004, KEY_MUTE }, - { 0x0007, KEY_OK }, /* TS */ - { 0x0008, KEY_STOP }, - { 0x0009, KEY_MENU }, /* swap */ - { 0x000a, KEY_REWIND }, - { 0x001b, KEY_PAUSE }, - { 0x001f, KEY_FASTFORWARD }, - { 0x000c, KEY_RECORD }, - { 0x000d, KEY_CAMERA }, /* screenshot */ - { 0x000e, KEY_COFFEE }, /* "MTS" */ -}; - -static struct rc_map_table rc_map_tvwalkertwin_table[] = { - { 0x0001, KEY_ZOOM }, /* Full Screen */ - { 0x0002, KEY_CAMERA }, /* snapshot */ - { 0x0003, KEY_MUTE }, - { 0x0004, KEY_REWIND }, - { 0x0005, KEY_PLAYPAUSE }, /* Play/Pause */ - { 0x0006, KEY_FASTFORWARD }, - { 0x0007, KEY_RECORD }, - { 0x0008, KEY_STOP }, - { 0x0009, KEY_TIME }, /* Timeshift */ - { 0x000c, KEY_COFFEE }, /* Recall */ - { 0x000e, KEY_CHANNELUP }, - { 0x0012, KEY_POWER }, - { 0x0015, KEY_MENU }, /* source */ - { 0x0018, KEY_CYCLEWINDOWS }, /* TWIN PIP */ - { 0x001a, KEY_CHANNELDOWN }, - { 0x001b, KEY_VOLUMEDOWN }, - { 0x001e, KEY_VOLUMEUP }, -}; - -static struct rc_map_table rc_map_pinnacle310e_table[] = { - { 0x16, KEY_POWER }, - { 0x17, KEY_FAVORITES }, - { 0x0f, KEY_TEXT }, - { 0x48, KEY_MEDIA }, /* preview */ - { 0x1c, KEY_EPG }, - { 0x04, KEY_LIST }, /* record list */ - { 0x03, KEY_1 }, - { 0x01, KEY_2 }, - { 0x06, KEY_3 }, - { 0x09, KEY_4 }, - { 0x1d, KEY_5 }, - { 0x1f, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x19, KEY_8 }, - { 0x1b, KEY_9 }, - { 0x15, KEY_0 }, - { 0x0c, KEY_CANCEL }, - { 0x4a, KEY_CLEAR }, - { 0x13, KEY_BACK }, - { 0x00, KEY_TAB }, - { 0x4b, KEY_UP }, - { 0x4e, KEY_LEFT }, - { 0x52, KEY_RIGHT }, - { 0x51, KEY_DOWN }, - { 0x4f, KEY_ENTER }, /* could also be KEY_OK */ - { 0x1e, KEY_VOLUMEUP }, - { 0x0a, KEY_VOLUMEDOWN }, - { 0x05, KEY_CHANNELUP }, - { 0x02, KEY_CHANNELDOWN }, - { 0x11, KEY_RECORD }, - { 0x14, KEY_PLAY }, - { 0x4c, KEY_PAUSE }, - { 0x1a, KEY_STOP }, - { 0x40, KEY_REWIND }, - { 0x12, KEY_FASTFORWARD }, - { 0x41, KEY_PREVIOUSSONG }, /* Replay */ - { 0x42, KEY_NEXTSONG }, /* Skip */ - { 0x54, KEY_CAMERA }, /* Capture */ -/* { 0x50, KEY_SAP }, */ /* Sap */ - { 0x47, KEY_CYCLEWINDOWS }, /* Pip */ - { 0x4d, KEY_SCREEN }, /* FullScreen */ - { 0x08, KEY_SUBTITLE }, - { 0x0e, KEY_MUTE }, -/* { 0x49, KEY_LR }, */ /* L/R */ - { 0x07, KEY_SLEEP }, /* Hibernate */ - { 0x08, KEY_MEDIA }, /* A/V */ - { 0x0e, KEY_MENU }, /* Recall */ - { 0x45, KEY_ZOOMIN }, - { 0x46, KEY_ZOOMOUT }, - { 0x18, KEY_TV }, /* Red */ - { 0x53, KEY_VCR }, /* Green */ - { 0x5e, KEY_SAT }, /* Yellow */ - { 0x5f, KEY_PLAYER }, /* Blue */ -}; - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties megasky_properties; -static struct dvb_usb_device_properties digivox_mini_ii_properties; -static struct dvb_usb_device_properties tvwalkertwin_properties; -static struct dvb_usb_device_properties dposh_properties; -static struct dvb_usb_device_properties pinnacle_pctv310e_properties; - -static int m920x_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d = NULL; - int ret; - struct m920x_inits *rc_init_seq = NULL; - int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber; - - deb("Probing for m920x device at interface %d\n", bInterfaceNumber); - - if (bInterfaceNumber == 0) { - /* Single-tuner device, or first interface on - * multi-tuner device - */ - - ret = dvb_usb_device_init(intf, &megasky_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - rc_init_seq = megasky_rc_init; - goto found; - } - - ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - /* No remote control, so no rc_init_seq */ - goto found; - } - - /* This configures both tuners on the TV Walker Twin */ - ret = dvb_usb_device_init(intf, &tvwalkertwin_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - rc_init_seq = tvwalkertwin_rc_init; - goto found; - } - - ret = dvb_usb_device_init(intf, &dposh_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - /* Remote controller not supported yet. */ - goto found; - } - - ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties, - THIS_MODULE, &d, adapter_nr); - if (ret == 0) { - rc_init_seq = pinnacle310e_init; - goto found; - } - - return ret; - } else { - /* Another interface on a multi-tuner device */ - - /* The LifeView TV Walker Twin gets here, but struct - * tvwalkertwin_properties already configured both - * tuners, so there is nothing for us to do here - */ - } - - found: - if ((ret = m920x_init_ep(intf)) < 0) - return ret; - - if (d && (ret = m920x_init(d, rc_init_seq)) != 0) - return ret; - - return ret; -} - -static struct usb_device_id m920x_table [] = { - { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_MSI_DIGI_VOX_MINI_II) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) }, - { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) }, - { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, m920x_table); - -static struct dvb_usb_device_properties megasky_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-megasky-02.fw", - .download_firmware = m920x_firmware_download, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_megasky_table, - .rc_map_size = ARRAY_SIZE(rc_map_megasky_table), - .rc_query = m920x_rc_query, - }, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 1, - .adapter = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_mt352_frontend_attach, - .tuner_attach = m920x_qt1010_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - }}, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { "MSI Mega Sky 580 DVB-T USB2.0", - { &m920x_table[0], NULL }, - { NULL }, - } - } -}; - -static struct dvb_usb_device_properties digivox_mini_ii_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-digivox-02.fw", - .download_firmware = m920x_firmware_download, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 1, - .adapter = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_tda10046_08_frontend_attach, - .tuner_attach = m920x_tda8275_60_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 0x4000, - } - } - }, - }}, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { "MSI DIGI VOX mini II DVB-T USB2.0", - { &m920x_table[1], NULL }, - { NULL }, - }, - } -}; - -/* LifeView TV Walker Twin support by Nick Andrew - * - * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A - * TDA10046 #0 is located at i2c address 0x08 - * TDA10046 #1 is located at i2c address 0x0b - * TDA8275A #0 is located at i2c address 0x60 - * TDA8275A #1 is located at i2c address 0x61 - */ -static struct dvb_usb_device_properties tvwalkertwin_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-tvwalkert.fw", - .download_firmware = m920x_firmware_download, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_tvwalkertwin_table, - .rc_map_size = ARRAY_SIZE(rc_map_tvwalkertwin_table), - .rc_query = m920x_rc_query, - }, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 2, - .adapter = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_tda10046_08_frontend_attach, - .tuner_attach = m920x_tda8275_60_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 512, - } - } - }},{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_tda10046_0b_frontend_attach, - .tuner_attach = m920x_tda8275_61_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - }}, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { .name = "LifeView TV Walker Twin DVB-T USB2.0", - .cold_ids = { &m920x_table[2], NULL }, - .warm_ids = { &m920x_table[3], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties dposh_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-dposh-01.fw", - .download_firmware = m920x_firmware_download, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 1, - .adapter = {{ - /* Hardware pid filters don't work with this device/firmware */ - - .frontend_attach = m920x_mt352_frontend_attach, - .tuner_attach = m920x_qt1010_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - }}, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { .name = "Dposh DVB-T USB2.0", - .cold_ids = { &m920x_table[4], NULL }, - .warm_ids = { &m920x_table[5], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties pinnacle_pctv310e_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = NULL, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_pinnacle310e_table, - .rc_map_size = ARRAY_SIZE(rc_map_pinnacle310e_table), - .rc_query = m920x_rc_query, - }, - - .size_of_priv = sizeof(struct m920x_state), - - .identify_state = m920x_identify_state, - .num_adapters = 1, - .adapter = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - - .pid_filter_count = 8, - .pid_filter = m920x_pid_filter, - .pid_filter_ctrl = m920x_pid_filter_ctrl, - - .frontend_attach = m920x_mt352_frontend_attach, - .tuner_attach = m920x_fmd1216me_tuner_attach, - - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x84, - .u = { - .isoc = { - .framesperurb = 128, - .framesize = 564, - .interval = 1, - } - } - }, - } }, - .i2c_algo = &m920x_i2c_algo, - - .num_device_descs = 1, - .devices = { - { "Pinnacle PCTV 310e", - { &m920x_table[6], NULL }, - { NULL }, - } - } -}; - -static struct usb_driver m920x_driver = { - .name = "dvb_usb_m920x", - .probe = m920x_probe, - .disconnect = dvb_usb_device_exit, - .id_table = m920x_table, -}; - -/* module stuff */ -static int __init m920x_module_init(void) -{ - int ret; - - if ((ret = usb_register(&m920x_driver))) { - err("usb_register failed. Error number %d", ret); - return ret; - } - - return 0; -} - -static void __exit m920x_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&m920x_driver); -} - -module_init (m920x_module_init); -module_exit (m920x_module_exit); - -MODULE_AUTHOR("Aapo Tahkola "); -MODULE_DESCRIPTION("DVB Driver for ULI M920x"); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/m920x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/m920x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/m920x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/m920x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -#ifndef _DVB_USB_M920X_H_ -#define _DVB_USB_M920X_H_ - -#define DVB_USB_LOG_PREFIX "m920x" -#include "dvb-usb.h" - -#define deb(args...) dprintk(dvb_usb_m920x_debug,0x01,args) - -#define M9206_CORE 0x22 -#define M9206_RC_STATE 0xff51 -#define M9206_RC_KEY 0xff52 -#define M9206_RC_INIT1 0xff54 -#define M9206_RC_INIT2 0xff55 -#define M9206_FW_GO 0xff69 - -#define M9206_I2C 0x23 -#define M9206_FILTER 0x25 -#define M9206_FW 0x30 - -#define M9206_MAX_FILTERS 8 -#define M9206_MAX_ADAPTERS 4 - -/* -sequences found in logs: -[index value] -0x80 write addr -(0x00 out byte)* -0x40 out byte - -0x80 write addr -(0x00 out byte)* -0x80 read addr -(0x21 in byte)* -0x60 in byte - -this sequence works: -0x80 read addr -(0x21 in byte)* -0x60 in byte - -Guess at API of the I2C function: -I2C operation is done one byte at a time with USB control messages. The -index the messages is sent to is made up of a set of flags that control -the I2C bus state: -0x80: Send START condition. After a START condition, one would normally - always send the 7-bit slave I2C address as the 7 MSB, followed by - the read/write bit as the LSB. -0x40: Send STOP condition. This should be set on the last byte of an - I2C transaction. -0x20: Read a byte from the slave. As opposed to writing a byte to the - slave. The slave will normally not produce any data unless you - set the R/W bit to 1 when sending the slave's address after the - START condition. -0x01: Respond with ACK, as opposed to a NACK. For a multi-byte read, - the master should send an ACK, that is pull SDA low during the 9th - clock cycle, after every byte but the last. This flags only makes - sense when bit 0x20 is set, indicating a read. - -What any other bits might mean, or how to get the slave's ACK/NACK -response to a write, is unknown. -*/ - -struct m920x_state { - u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS]; - int filtering_enabled[M9206_MAX_ADAPTERS]; - int rep_count; -}; - -/* Initialisation data for the m920x - */ - -struct m920x_inits { - u16 address; - u8 data; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o -obj-$(CONFIG_DVB_USB) += dvb-usb.o - -dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o -obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o - -dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o -obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o - -dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o -obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o - -dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o -obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o - -dvb-usb-dibusb-common-objs = dibusb-common.o - -dvb-usb-a800-objs = a800.o -obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o - -dvb-usb-dibusb-mb-objs = dibusb-mb.o -obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o - -dvb-usb-dibusb-mc-objs = dibusb-mc.o -obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o - -dvb-usb-nova-t-usb2-objs = nova-t-usb2.o -obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o - -dvb-usb-umt-010-objs = umt-010.o -obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o - -dvb-usb-m920x-objs = m920x.o -obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o - -dvb-usb-gl861-objs = gl861.o -obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o - -dvb-usb-au6610-objs = au6610.o -obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o - -dvb-usb-digitv-objs = digitv.o -obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o - -dvb-usb-cxusb-objs = cxusb.o -obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o - -dvb-usb-ttusb2-objs = ttusb2.o -obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o - -dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o -obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o - -dvb-usb-opera-objs = opera1.o -obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o - - -dvb-usb-af9005-objs = af9005.o af9005-fe.o -obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o - -dvb-usb-af9005-remote-objs = af9005-remote.o -obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o - -dvb-usb-anysee-objs = anysee.o -obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o - -dvb-usb-dw2102-objs = dw2102.o -obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o - -dvb-usb-dtv5100-objs = dtv5100.o -obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o - -dvb-usb-af9015-objs = af9015.o -obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o - -dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o -obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o - -dvb-usb-ce6230-objs = ce6230.o -obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o - -dvb-usb-friio-objs = friio.o friio-fe.o -obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o - -dvb-usb-ec168-objs = ec168.o -obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o - -dvb-usb-az6027-objs = az6027.o -obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o - -dvb-usb-lmedm04-objs = lmedm04.o -obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o - -dvb-usb-technisat-usb2-objs = technisat-usb2.o -obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -# due to tuner-xc3028 -EXTRA_CFLAGS += -Idrivers/media/common/tuners - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/nova-t-usb2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/nova-t-usb2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/nova-t-usb2.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/nova-t-usb2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,249 +0,0 @@ -/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2 - * DVB-T receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_rc(args...) dprintk(debug,0x01,args) -#define deb_ee(args...) dprintk(debug,0x02,args) - -/* Hauppauge NOVA-T USB2 keys */ -static struct rc_map_table rc_map_haupp_table[] = { - { 0x1e00, KEY_0 }, - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, - { 0x1e0a, KEY_KPASTERISK }, - { 0x1e0b, KEY_RED }, - { 0x1e0c, KEY_RADIO }, - { 0x1e0d, KEY_MENU }, - { 0x1e0e, KEY_GRAVE }, /* # */ - { 0x1e0f, KEY_MUTE }, - { 0x1e10, KEY_VOLUMEUP }, - { 0x1e11, KEY_VOLUMEDOWN }, - { 0x1e12, KEY_CHANNEL }, - { 0x1e14, KEY_UP }, - { 0x1e15, KEY_DOWN }, - { 0x1e16, KEY_LEFT }, - { 0x1e17, KEY_RIGHT }, - { 0x1e18, KEY_VIDEO }, - { 0x1e19, KEY_AUDIO }, - { 0x1e1a, KEY_MEDIA }, - { 0x1e1b, KEY_EPG }, - { 0x1e1c, KEY_TV }, - { 0x1e1e, KEY_NEXT }, - { 0x1e1f, KEY_BACK }, - { 0x1e20, KEY_CHANNELUP }, - { 0x1e21, KEY_CHANNELDOWN }, - { 0x1e24, KEY_LAST }, /* Skip backwards */ - { 0x1e25, KEY_OK }, - { 0x1e29, KEY_BLUE}, - { 0x1e2e, KEY_GREEN }, - { 0x1e30, KEY_PAUSE }, - { 0x1e32, KEY_REWIND }, - { 0x1e34, KEY_FASTFORWARD }, - { 0x1e35, KEY_PLAY }, - { 0x1e36, KEY_STOP }, - { 0x1e37, KEY_RECORD }, - { 0x1e38, KEY_YELLOW }, - { 0x1e3b, KEY_GOTO }, - { 0x1e3d, KEY_POWER }, -}; - -/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key - * is delivered. No workaround yet, maybe a new firmware. - */ -static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom; - u16 raw; - int i; - struct dibusb_device_state *st = d->priv; - - dvb_usb_generic_rw(d,cmd,2,key,5,0); - - *state = REMOTE_NO_KEY_PRESSED; - switch (key[0]) { - case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED: - raw = ((key[1] << 8) | key[2]) >> 3; - toggle = !!(raw & 0x800); - data = raw & 0x3f; - custom = (raw >> 6) & 0x1f; - - deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle); - - for (i = 0; i < ARRAY_SIZE(rc_map_haupp_table); i++) { - if (rc5_data(&rc_map_haupp_table[i]) == data && - rc5_custom(&rc_map_haupp_table[i]) == custom) { - - deb_rc("c: %x, d: %x\n", rc5_data(&rc_map_haupp_table[i]), - rc5_custom(&rc_map_haupp_table[i])); - - *event = rc_map_haupp_table[i].keycode; - *state = REMOTE_KEY_PRESSED; - if (st->old_toggle == toggle) { - if (st->last_repeat_count++ < 2) - *state = REMOTE_NO_KEY_PRESSED; - } else { - st->last_repeat_count = 0; - st->old_toggle = toggle; - } - break; - } - } - - break; - case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY: - default: - break; - } - - return 0; -} - -static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) -{ - int i; - u8 b; - - mac[0] = 0x00; - mac[1] = 0x0d; - mac[2] = 0xfe; - - /* this is a complete guess, but works for my box */ - for (i = 136; i < 139; i++) { - dibusb_read_eeprom_byte(d,i, &b); - - mac[5 - (i - 136)] = b; - } - - return 0; -} - -/* USB Driver stuff */ -static struct dvb_usb_device_properties nova_t_properties; - -static int nova_t_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &nova_t_properties, - THIS_MODULE, NULL, adapter_nr); -} - -/* do not change the order of the ID table */ -static struct usb_device_id nova_t_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, nova_t_table); - -static struct dvb_usb_device_properties nova_t_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-nova-t-usb2-02.fw", - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, - .frontend_attach = dibusb_dib3000mc_frontend_attach, - .tuner_attach = dibusb_dib3000mc_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .size_of_priv = sizeof(struct dibusb_device_state), - - .power_ctrl = dibusb2_0_power_ctrl, - .read_mac_address = nova_t_read_mac_address, - - .rc.legacy = { - .rc_interval = 100, - .rc_map_table = rc_map_haupp_table, - .rc_map_size = ARRAY_SIZE(rc_map_haupp_table), - .rc_query = nova_t_rc_query, - }, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Hauppauge WinTV-NOVA-T usb2", - { &nova_t_table[0], NULL }, - { &nova_t_table[1], NULL }, - }, - { NULL }, - } -}; - -static struct usb_driver nova_t_driver = { - .name = "dvb_usb_nova_t_usb2", - .probe = nova_t_probe, - .disconnect = dvb_usb_device_exit, - .id_table = nova_t_table, -}; - -/* module stuff */ -static int __init nova_t_module_init(void) -{ - int result; - if ((result = usb_register(&nova_t_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit nova_t_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&nova_t_driver); -} - -module_init (nova_t_module_init); -module_exit (nova_t_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/opera1.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/opera1.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/opera1.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/opera1.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,585 +0,0 @@ -/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card -* -* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org) -* Copyright (C) 2006 Marco Gittler (g.marco@freenet.de) -* -* 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, version 2. -* -* see Documentation/dvb/README.dvb-usb for more information -*/ - -#define DVB_USB_LOG_PREFIX "opera" - -#include "dvb-usb.h" -#include "stv0299.h" - -#define OPERA_READ_MSG 0 -#define OPERA_WRITE_MSG 1 -#define OPERA_I2C_TUNER 0xd1 - -#define READ_FX2_REG_REQ 0xba -#define READ_MAC_ADDR 0x08 -#define OPERA_WRITE_FX2 0xbb -#define OPERA_TUNER_REQ 0xb1 -#define REG_1F_SYMBOLRATE_BYTE0 0x1f -#define REG_20_SYMBOLRATE_BYTE1 0x20 -#define REG_21_SYMBOLRATE_BYTE2 0x21 - -#define ADDR_B600_VOLTAGE_13V (0x02) -#define ADDR_B601_VOLTAGE_18V (0x03) -#define ADDR_B1A6_STREAM_CTRL (0x04) -#define ADDR_B880_READ_REMOTE (0x05) - -struct opera1_state { - u32 last_key_pressed; -}; -struct rc_map_opera_table { - u32 keycode; - u32 event; -}; - -static int dvb_usb_opera1_debug; -module_param_named(debug, dvb_usb_opera1_debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." - DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - - -static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value, - u8 * data, u16 len, int flags) -{ - int ret; - u8 r; - u8 u8buf[len]; - - unsigned int pipe = (flags == OPERA_READ_MSG) ? - usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0); - u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; - - if (flags == OPERA_WRITE_MSG) - memcpy(u8buf, data, len); - ret = - usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, - value, 0x0, u8buf, len, 2000); - - if (request == OPERA_TUNER_REQ) { - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR, - 0x01, 0x0, &r, 1, 2000)<1 || r!=0x08) - return 0; - } - if (flags == OPERA_READ_MSG) - memcpy(data, u8buf, len); - return ret; -} - -/* I2C */ - -static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr, - u8 * buf, u16 len) -{ - int ret = 0; - u8 request; - u16 value; - - if (!dev) { - info("no usb_device"); - return -EINVAL; - } - if (mutex_lock_interruptible(&dev->usb_mutex) < 0) - return -EAGAIN; - - switch (addr>>1){ - case ADDR_B600_VOLTAGE_13V: - request=0xb6; - value=0x00; - break; - case ADDR_B601_VOLTAGE_18V: - request=0xb6; - value=0x01; - break; - case ADDR_B1A6_STREAM_CTRL: - request=0xb1; - value=0xa6; - break; - case ADDR_B880_READ_REMOTE: - request=0xb8; - value=0x80; - break; - default: - request=0xb1; - value=addr; - } - ret = opera1_xilinx_rw(dev->udev, request, - value, buf, len, - addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG); - - mutex_unlock(&dev->usb_mutex); - return ret; -} - -static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0, tmp = 0; - - if (!d) - return -ENODEV; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - if ((tmp = opera1_usb_i2c_msgxfer(d, - (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), - msg[i].buf, - msg[i].len - )) != msg[i].len) { - break; - } - if (dvb_usb_opera1_debug & 0x10) - info("sending i2c mesage %d %d", tmp, msg[i].len); - } - mutex_unlock(&d->i2c_mutex); - return num; -} - -static u32 opera1_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm opera1_i2c_algo = { - .master_xfer = opera1_i2c_xfer, - .functionality = opera1_i2c_func, -}; - -static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - static u8 command_13v[1]={0x00}; - static u8 command_18v[1]={0x01}; - struct i2c_msg msg[] = { - {.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1}, - }; - struct dvb_usb_adapter *udev_adap = - (struct dvb_usb_adapter *)(fe->dvb->priv); - if (voltage == SEC_VOLTAGE_18) { - msg[0].addr = ADDR_B601_VOLTAGE_18V; - msg[0].buf = command_18v; - } - i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1); - return 0; -} - -static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, - u32 ratio) -{ - stv0299_writereg(fe, 0x13, 0x98); - stv0299_writereg(fe, 0x14, 0x95); - stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff); - stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff); - stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0); - return 0; - -} -static u8 opera1_inittab[] = { - 0x00, 0xa1, - 0x01, 0x15, - 0x02, 0x00, - 0x03, 0x00, - 0x04, 0x7d, - 0x05, 0x05, - 0x06, 0x02, - 0x07, 0x00, - 0x0b, 0x00, - 0x0c, 0x01, - 0x0d, 0x81, - 0x0e, 0x44, - 0x0f, 0x19, - 0x10, 0x3f, - 0x11, 0x84, - 0x12, 0xda, - 0x13, 0x98, - 0x14, 0x95, - 0x15, 0xc9, - 0x16, 0xeb, - 0x17, 0x00, - 0x18, 0x19, - 0x19, 0x8b, - 0x1a, 0x00, - 0x1b, 0x82, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - REG_1F_SYMBOLRATE_BYTE0, 0x06, - REG_20_SYMBOLRATE_BYTE1, 0x50, - REG_21_SYMBOLRATE_BYTE2, 0x10, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x37, - 0x25, 0xbc, - 0x26, 0x00, - 0x27, 0x00, - 0x28, 0x00, - 0x29, 0x1e, - 0x2a, 0x14, - 0x2b, 0x1f, - 0x2c, 0x09, - 0x2d, 0x0a, - 0x2e, 0x00, - 0x2f, 0x00, - 0x30, 0x00, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x13, - 0xff, 0xff, -}; - -static struct stv0299_config opera1_stv0299_config = { - .demod_address = 0xd0>>1, - .min_delay_ms = 100, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_0, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .inittab = opera1_inittab, - .set_symbol_rate = opera1_stv0299_set_symbol_rate, -}; - -static int opera1_frontend_attach(struct dvb_usb_adapter *d) -{ - if ((d->fe = - dvb_attach(stv0299_attach, &opera1_stv0299_config, - &d->dev->i2c_adap)) != NULL) { - d->fe->ops.set_voltage = opera1_set_voltage; - return 0; - } - info("not attached stv0299"); - return -EIO; -} - -static int opera1_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach( - dvb_pll_attach, adap->fe, 0xc0>>1, - &adap->dev->i2c_adap, DVB_PLL_OPERA1 - ); - return 0; -} - -static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 val = onoff ? 0x01 : 0x00; - - if (dvb_usb_opera1_debug) - info("power %s", onoff ? "on" : "off"); - return opera1_xilinx_rw(d->udev, 0xb7, val, - &val, 1, OPERA_WRITE_MSG); -} - -static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - static u8 buf_start[2] = { 0xff, 0x03 }; - static u8 buf_stop[2] = { 0xff, 0x00 }; - struct i2c_msg start_tuner[] = { - {.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2}, - }; - if (dvb_usb_opera1_debug) - info("streaming %s", onoff ? "on" : "off"); - i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1); - return 0; -} - -static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - u8 b_pid[3]; - struct i2c_msg msg[] = { - {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, - }; - if (dvb_usb_opera1_debug) - info("pidfilter index: %d pid: %d %s", index, pid, - onoff ? "on" : "off"); - b_pid[0] = (2 * index) + 4; - b_pid[1] = onoff ? (pid & 0xff) : (0x00); - b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00); - i2c_transfer(&adap->dev->i2c_adap, msg, 1); - return 0; -} - -static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) -{ - int u = 0x04; - u8 b_pid[3]; - struct i2c_msg msg[] = { - {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, - }; - if (dvb_usb_opera1_debug) - info("%s hw-pidfilter", onoff ? "enable" : "disable"); - for (; u < 0x7e; u += 2) { - b_pid[0] = u; - b_pid[1] = 0; - b_pid[2] = 0x80; - i2c_transfer(&adap->dev->i2c_adap, msg, 1); - } - return 0; -} - -static struct rc_map_table rc_map_opera1_table[] = { - {0x5fa0, KEY_1}, - {0x51af, KEY_2}, - {0x5da2, KEY_3}, - {0x41be, KEY_4}, - {0x0bf5, KEY_5}, - {0x43bd, KEY_6}, - {0x47b8, KEY_7}, - {0x49b6, KEY_8}, - {0x05fa, KEY_9}, - {0x45ba, KEY_0}, - {0x09f6, KEY_CHANNELUP}, /*chanup */ - {0x1be5, KEY_CHANNELDOWN}, /*chandown */ - {0x5da3, KEY_VOLUMEDOWN}, /*voldown */ - {0x5fa1, KEY_VOLUMEUP}, /*volup */ - {0x07f8, KEY_SPACE}, /*tab */ - {0x1fe1, KEY_OK}, /*play ok */ - {0x1be4, KEY_ZOOM}, /*zoom */ - {0x59a6, KEY_MUTE}, /*mute */ - {0x5ba5, KEY_RADIO}, /*tv/f */ - {0x19e7, KEY_RECORD}, /*rec */ - {0x01fe, KEY_STOP}, /*Stop */ - {0x03fd, KEY_PAUSE}, /*pause */ - {0x03fc, KEY_SCREEN}, /*<- -> */ - {0x07f9, KEY_CAMERA}, /*capture */ - {0x47b9, KEY_ESC}, /*exit */ - {0x43bc, KEY_POWER2}, /*power */ -}; - -static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state) -{ - struct opera1_state *opst = dev->priv; - u8 rcbuffer[32]; - const u16 startmarker1 = 0x10ed; - const u16 startmarker2 = 0x11ec; - struct i2c_msg read_remote[] = { - {.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32}, - }; - int i = 0; - u32 send_key = 0; - - if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) { - for (i = 0; i < 32; i++) { - if (rcbuffer[i]) - send_key |= 1; - if (i < 31) - send_key = send_key << 1; - } - if (send_key & 0x8000) - send_key = (send_key << 1) | (send_key >> 15 & 0x01); - - if (send_key == 0xffff && opst->last_key_pressed != 0) { - *state = REMOTE_KEY_REPEAT; - *event = opst->last_key_pressed; - return 0; - } - for (; send_key != 0;) { - if (send_key >> 16 == startmarker2) { - break; - } else if (send_key >> 16 == startmarker1) { - send_key = - (send_key & 0xfffeffff) | (startmarker1 << 16); - break; - } else - send_key >>= 1; - } - - if (send_key == 0) - return 0; - - send_key = (send_key & 0xffff) | 0x0100; - - for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) { - if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) { - *state = REMOTE_KEY_PRESSED; - *event = rc_map_opera1_table[i].keycode; - opst->last_key_pressed = - rc_map_opera1_table[i].keycode; - break; - } - opst->last_key_pressed = 0; - } - } else - *state = REMOTE_NO_KEY_PRESSED; - return 0; -} - -static struct usb_device_id opera1_table[] = { - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)}, - {USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, opera1_table); - -static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -{ - u8 command[] = { READ_MAC_ADDR }; - opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG); - opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG); - return 0; -} -static int opera1_xilinx_load_firmware(struct usb_device *dev, - const char *filename) -{ - const struct firmware *fw = NULL; - u8 *b, *p; - int ret = 0, i,fpgasize=40; - u8 testval; - info("start downloading fpga firmware %s",filename); - - if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems.", - filename); - return ret; - } else { - p = kmalloc(fw->size, GFP_KERNEL); - opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG); - if (p != NULL && testval != 0x67) { - - u8 reset = 0, fpga_command = 0; - memcpy(p, fw->data, fw->size); - /* clear fpga ? */ - opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1, - OPERA_WRITE_MSG); - for (i = 0; i < fw->size;) { - if ( (fw->size - i) size-i; - } - b = (u8 *) p + i; - if (opera1_xilinx_rw - (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize, - OPERA_WRITE_MSG) != fpgasize - ) { - err("error while transferring firmware"); - ret = -EINVAL; - break; - } - i = i + fpgasize; - } - /* restart the CPU */ - if (ret || opera1_xilinx_rw - (dev, 0xa0, 0xe600, &reset, 1, - OPERA_WRITE_MSG) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - } - } - kfree(p); - release_firmware(fw); - return ret; -} - -static struct dvb_usb_device_properties opera1_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-opera-01.fw", - .size_of_priv = sizeof(struct opera1_state), - - .power_ctrl = opera1_power_ctrl, - .i2c_algo = &opera1_i2c_algo, - - .rc.legacy = { - .rc_map_table = rc_map_opera1_table, - .rc_map_size = ARRAY_SIZE(rc_map_opera1_table), - .rc_interval = 200, - .rc_query = opera1_rc_query, - }, - .read_mac_address = opera1_read_mac_address, - .generic_bulk_ctrl_endpoint = 0x00, - /* parameter for the MPEG2-data transfer */ - .num_adapters = 1, - .adapter = { - { - .frontend_attach = opera1_frontend_attach, - .streaming_ctrl = opera1_streaming_ctrl, - .tuner_attach = opera1_tuner_attach, - .caps = - DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter = opera1_pid_filter, - .pid_filter_ctrl = opera1_pid_filter_control, - .pid_filter_count = 252, - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .num_device_descs = 1, - .devices = { - {"Opera1 DVB-S USB2.0", - {&opera1_table[0], NULL}, - {&opera1_table[1], NULL}, - }, - } -}; - -static int opera1_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - - if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM && - udev->descriptor.idVendor == USB_VID_OPERA1 && - opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0 - ) { - return -EINVAL; - } - - if (0 != dvb_usb_device_init(intf, &opera1_properties, - THIS_MODULE, NULL, adapter_nr)) - return -EINVAL; - return 0; -} - -static struct usb_driver opera1_driver = { - .name = "opera1", - .probe = opera1_probe, - .disconnect = dvb_usb_device_exit, - .id_table = opera1_table, -}; - -static int __init opera1_module_init(void) -{ - int result = 0; - if ((result = usb_register(&opera1_driver))) { - err("usb_register failed. Error number %d", result); - } - return result; -} - -static void __exit opera1_module_exit(void) -{ - usb_deregister(&opera1_driver); -} - -module_init(opera1_module_init); -module_exit(opera1_module_exit); - -MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org"); -MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de"); -MODULE_DESCRIPTION("Driver for Opera1 DVB-S device"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/technisat-usb2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/technisat-usb2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/technisat-usb2.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/technisat-usb2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,806 +0,0 @@ -/* - * Linux driver for Technisat DVB-S/S2 USB 2.0 device - * - * Copyright (C) 2010 Patrick Boettcher, - * Kernel Labs Inc. PO Box 745, St James, NY 11780 - * - * Development was sponsored by Technisat Digital UK Limited, whose - * registered office is Witan Gate House 500 - 600 Witan Gate West, - * Milton Keynes, MK9 1SH - * - * 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, or (at your option) any later version. - * - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND - * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR - * FITNESS FOR A PARTICULAR PURPOSE. NEITHER THE COPYRIGHT HOLDER - * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL, - * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR - * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the - * GNU General Public License for more details. - */ - -#define DVB_USB_LOG_PREFIX "technisat-usb2" -#include "dvb-usb.h" - -#include "stv6110x.h" -#include "stv090x.h" - -/* module parameters */ -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, - "set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \ - DVB_USB_DEBUG_STATUS); - -/* disables all LED control command and - * also does not start the signal polling thread */ -static int disable_led_control; -module_param(disable_led_control, int, 0444); -MODULE_PARM_DESC(disable_led_control, - "disable LED control of the device " - "(default: 0 - LED control is active)."); - -/* device private data */ -struct technisat_usb2_state { - struct dvb_usb_device *dev; - struct delayed_work green_led_work; - u8 power_state; - - u16 last_scan_code; -}; - -/* debug print helpers */ -#define deb_info(args...) dprintk(debug, 0x01, args) -#define deb_eeprom(args...) dprintk(debug, 0x02, args) -#define deb_i2c(args...) dprintk(debug, 0x04, args) -#define deb_rc(args...) dprintk(debug, 0x08, args) - -/* vendor requests */ -#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3 -#define SET_FRONT_END_RESET_VENDOR_REQUEST 0xB4 -#define GET_VERSION_INFO_VENDOR_REQUEST 0xB5 -#define SET_GREEN_LED_VENDOR_REQUEST 0xB6 -#define SET_RED_LED_VENDOR_REQUEST 0xB7 -#define GET_IR_DATA_VENDOR_REQUEST 0xB8 -#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST 0xB9 -#define SET_USB_REENUMERATION 0xBA - -/* i2c-access methods */ -#define I2C_SPEED_100KHZ_BIT 0x40 - -#define I2C_STATUS_NAK 7 -#define I2C_STATUS_OK 8 - -static int technisat_usb2_i2c_access(struct usb_device *udev, - u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) -{ - u8 b[64]; - int ret, actual_length; - - deb_i2c("i2c-access: %02x, tx: ", device_addr); - debug_dump(tx, txlen, deb_i2c); - deb_i2c(" "); - - if (txlen > 62) { - err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)", - device_addr); - txlen = 62; - } - if (rxlen > 62) { - err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)", - device_addr); - txlen = 62; - } - - b[0] = I2C_SPEED_100KHZ_BIT; - b[1] = device_addr << 1; - - if (rx != NULL) { - b[0] |= rxlen; - b[1] |= 1; - } - - memcpy(&b[2], tx, txlen); - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x01), - b, 2 + txlen, - NULL, 1000); - - if (ret < 0) { - err("i2c-error: out failed %02x = %d", device_addr, ret); - return -ENODEV; - } - - ret = usb_bulk_msg(udev, - usb_rcvbulkpipe(udev, 0x01), - b, 64, &actual_length, 1000); - if (ret < 0) { - err("i2c-error: in failed %02x = %d", device_addr, ret); - return -ENODEV; - } - - if (b[0] != I2C_STATUS_OK) { - err("i2c-error: %02x = %d", device_addr, b[0]); - /* handle tuner-i2c-nak */ - if (!(b[0] == I2C_STATUS_NAK && - device_addr == 0x60 - /* && device_is_technisat_usb2 */)) - return -ENODEV; - } - - deb_i2c("status: %d, ", b[0]); - - if (rx != NULL) { - memcpy(rx, &b[2], rxlen); - - deb_i2c("rx (%d): ", rxlen); - debug_dump(rx, rxlen, deb_i2c); - } - - deb_i2c("\n"); - - return 0; -} - -static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, - int num) -{ - int ret = 0, i; - struct dvb_usb_device *d = i2c_get_adapdata(adap); - - /* Ensure nobody else hits the i2c bus while we're sending our - sequence of messages, (such as the remote control thread) */ - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - if (i+1 < num && msg[i+1].flags & I2C_M_RD) { - ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr, - msg[i].buf, msg[i].len, - msg[i+1].buf, msg[i+1].len); - if (ret != 0) - break; - i++; - } else { - ret = technisat_usb2_i2c_access(d->udev, msg[i].addr, - msg[i].buf, msg[i].len, - NULL, 0); - if (ret != 0) - break; - } - } - - if (ret == 0) - ret = i; - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm technisat_usb2_i2c_algo = { - .master_xfer = technisat_usb2_i2c_xfer, - .functionality = technisat_usb2_i2c_func, -}; - -#if 0 -static void technisat_usb2_frontend_reset(struct usb_device *udev) -{ - usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - SET_FRONT_END_RESET_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - 10, 0, - NULL, 0, 500); -} -#endif - -/* LED control */ -enum technisat_usb2_led_state { - LED_OFF, - LED_BLINK, - LED_ON, - LED_UNDEFINED -}; - -static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state) -{ - int ret; - - u8 led[8] = { - red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, - 0 - }; - - if (disable_led_control && state != LED_OFF) - return 0; - - switch (state) { - case LED_ON: - led[1] = 0x82; - break; - case LED_BLINK: - led[1] = 0x82; - if (red) { - led[2] = 0x02; - led[3] = 10; - led[4] = 10; - } else { - led[2] = 0xff; - led[3] = 50; - led[4] = 50; - } - led[5] = 1; - break; - - default: - case LED_OFF: - led[1] = 0x80; - break; - } - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - 0, 0, - led, sizeof(led), 500); - - mutex_unlock(&d->i2c_mutex); - return ret; -} - -static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green) -{ - int ret; - u8 b = 0; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - SET_LED_TIMER_DIVIDER_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - (red << 8) | green, 0, - &b, 1, 500); - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static void technisat_usb2_green_led_control(struct work_struct *work) -{ - struct technisat_usb2_state *state = - container_of(work, struct technisat_usb2_state, green_led_work.work); - struct dvb_frontend *fe = state->dev->adapter[0].fe; - - if (state->power_state == 0) - goto schedule; - - if (fe != NULL) { - enum fe_status status; - - if (fe->ops.read_status(fe, &status) != 0) - goto schedule; - - if (status & FE_HAS_LOCK) { - u32 ber; - - if (fe->ops.read_ber(fe, &ber) != 0) - goto schedule; - - if (ber > 1000) - technisat_usb2_set_led(state->dev, 0, LED_BLINK); - else - technisat_usb2_set_led(state->dev, 0, LED_ON); - } else - technisat_usb2_set_led(state->dev, 0, LED_OFF); - } - -schedule: - schedule_delayed_work(&state->green_led_work, - msecs_to_jiffies(500)); -} - -/* method to find out whether the firmware has to be downloaded or not */ -static int technisat_usb2_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold) -{ - int ret; - u8 version[3]; - - /* first select the interface */ - if (usb_set_interface(udev, 0, 1) != 0) - err("could not set alternate setting to 0"); - else - info("set alternate setting"); - - *cold = 0; /* by default do not download a firmware - just in case something is wrong */ - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - GET_VERSION_INFO_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_IN, - 0, 0, - version, sizeof(version), 500); - - if (ret < 0) - *cold = 1; - else { - info("firmware version: %d.%d", version[1], version[2]); - *cold = 0; - } - - return 0; -} - -/* power control */ -static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level) -{ - struct technisat_usb2_state *state = d->priv; - - state->power_state = level; - - if (disable_led_control) - return 0; - - /* green led is turned off in any case - will be turned on when tuning */ - technisat_usb2_set_led(d, 0, LED_OFF); - /* red led is turned on all the time */ - technisat_usb2_set_led(d, 1, LED_ON); - return 0; -} - -/* mac address reading - from the eeprom */ -#if 0 -static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d) -{ - u8 reg; - u8 b[16]; - int i, j; - - /* full EEPROM dump */ - for (j = 0; j < 256 * 4; j += 16) { - reg = j; - if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, ®, 1, b, 16) != 0) - break; - - deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg); - for (i = 0; i < 16; i++) - deb_eeprom("%02x ", b[i]); - deb_eeprom("\n"); - } -} -#endif - -static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length) -{ - u8 lrc = 0; - while (--length) - lrc ^= *b++; - return lrc; -} - -static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d, - u16 offset, u8 *b, u16 length, u8 tries) -{ - u8 bo = offset & 0xff; - struct i2c_msg msg[] = { - { - .addr = 0x50 | ((offset >> 8) & 0x3), - .buf = &bo, - .len = 1 - }, { - .addr = 0x50 | ((offset >> 8) & 0x3), - .flags = I2C_M_RD, - .buf = b, - .len = length - } - }; - - while (tries--) { - int status; - - if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) - break; - - status = - technisat_usb2_calc_lrc(b, length - 1) == b[length - 1]; - - if (status) - return 0; - } - - return -EREMOTEIO; -} - -#define EEPROM_MAC_START 0x3f8 -#define EEPROM_MAC_TOTAL 8 -static int technisat_usb2_read_mac_address(struct dvb_usb_device *d, - u8 mac[]) -{ - u8 buf[EEPROM_MAC_TOTAL]; - - if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START, - buf, EEPROM_MAC_TOTAL, 4) != 0) - return -ENODEV; - - memcpy(mac, buf, 6); - return 0; -} - -/* frontend attach */ -static int technisat_usb2_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - int i; - u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */ - - gpio[2] = 1; /* high - voltage ? */ - - switch (voltage) { - case SEC_VOLTAGE_13: - gpio[0] = 1; - break; - case SEC_VOLTAGE_18: - gpio[0] = 1; - gpio[1] = 1; - break; - default: - case SEC_VOLTAGE_OFF: - break; - } - - for (i = 0; i < 3; i++) - if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0) - return -EREMOTEIO; - return 0; -} - -static struct stv090x_config technisat_usb2_stv090x_config = { - .device = STV0903, - .demod_mode = STV090x_SINGLE, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 8000000, - .address = 0x68, - - .ts1_mode = STV090x_TSMODE_DVBCI, - .ts1_clk = 13400000, - .ts1_tei = 1, - - .repeater_level = STV090x_RPTLEVEL_64, - - .tuner_bbgain = 6, -}; - -static struct stv6110x_config technisat_usb2_stv6110x_config = { - .addr = 0x60, - .refclk = 16000000, - .clk_div = 2, -}; - -static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) -{ - struct usb_device *udev = a->dev->udev; - int ret; - - a->fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, - &a->dev->i2c_adap, STV090x_DEMODULATOR_0); - - if (a->fe) { - struct stv6110x_devctl *ctl; - - ctl = dvb_attach(stv6110x_attach, - a->fe, - &technisat_usb2_stv6110x_config, - &a->dev->i2c_adap); - - if (ctl) { - technisat_usb2_stv090x_config.tuner_init = ctl->tuner_init; - technisat_usb2_stv090x_config.tuner_sleep = ctl->tuner_sleep; - technisat_usb2_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; - technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; - technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; - technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; - technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; - technisat_usb2_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; - technisat_usb2_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; - technisat_usb2_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; - technisat_usb2_stv090x_config.tuner_get_status = ctl->tuner_get_status; - - /* call the init function once to initialize - tuner's clock output divider and demod's - master clock */ - if (a->fe->ops.init) - a->fe->ops.init(a->fe); - - if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0) - return -EAGAIN; - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - 0, 0, - NULL, 0, 500); - mutex_unlock(&a->dev->i2c_mutex); - - if (ret != 0) - err("could not set IF_CLK to external"); - - a->fe->ops.set_voltage = technisat_usb2_set_voltage; - - /* if everything was successful assign a nice name to the frontend */ - strlcpy(a->fe->ops.info.name, a->dev->desc->name, - sizeof(a->fe->ops.info.name)); - } else { - dvb_frontend_detach(a->fe); - a->fe = NULL; - } - } - - technisat_usb2_set_led_timer(a->dev, 1, 1); - - return a->fe == NULL ? -ENODEV : 0; -} - -/* Remote control */ - -/* the device is giving providing raw IR-signals to the host mapping - * it only to one remote control is just the default implementation - */ -#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889 -#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US) - -#define FIRMWARE_CLOCK_TICK 83333 -#define FIRMWARE_CLOCK_DIVISOR 256 - -#define IR_PERCENT_TOLERANCE 15 - -#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) -#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR) - -#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) -#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR) - -#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) -#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) - -#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) -#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) - -static int technisat_usb2_get_ir(struct dvb_usb_device *d) -{ - u8 buf[62], *b; - int ret; - struct ir_raw_event ev; - - buf[0] = GET_IR_DATA_VENDOR_REQUEST; - buf[1] = 0x08; - buf[2] = 0x8f; - buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT; - buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - GET_IR_DATA_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_OUT, - 0, 0, - buf, 5, 500); - if (ret < 0) - goto unlock; - - buf[1] = 0; - buf[2] = 0; - ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - GET_IR_DATA_VENDOR_REQUEST, - USB_TYPE_VENDOR | USB_DIR_IN, - 0x8080, 0, - buf, sizeof(buf), 500); - -unlock: - mutex_unlock(&d->i2c_mutex); - - if (ret < 0) - return ret; - - if (ret == 1) - return 0; /* no key pressed */ - - /* decoding */ - b = buf+1; - -#if 0 - deb_rc("RC: %d ", ret); - debug_dump(b, ret, deb_rc); -#endif - - ev.pulse = 0; - while (1) { - ev.pulse = !ev.pulse; - ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000; - ir_raw_event_store(d->rc_dev, &ev); - - b++; - if (*b == 0xff) { - ev.pulse = 0; - ev.duration = 888888*2; - ir_raw_event_store(d->rc_dev, &ev); - break; - } - } - - ir_raw_event_handle(d->rc_dev); - - return 1; -} - -static int technisat_usb2_rc_query(struct dvb_usb_device *d) -{ - int ret = technisat_usb2_get_ir(d); - - if (ret < 0) - return ret; - - if (ret == 0) - return 0; - - if (!disable_led_control) - technisat_usb2_set_led(d, 1, LED_BLINK); - - return 0; -} - -/* DVB-USB and USB stuff follows */ -static struct usb_device_id technisat_usb2_id_table[] = { - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) }, - { 0 } /* Terminating entry */ -}; - -/* device description */ -static struct dvb_usb_device_properties technisat_usb2_devices = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .identify_state = technisat_usb2_identify_state, - .firmware = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw", - - .size_of_priv = sizeof(struct technisat_usb2_state), - - .i2c_algo = &technisat_usb2_i2c_algo, - - .power_ctrl = technisat_usb2_power_ctrl, - .read_mac_address = technisat_usb2_read_mac_address, - - .num_adapters = 1, - .adapter = { - { - .frontend_attach = technisat_usb2_frontend_attach, - - .stream = { - .type = USB_ISOC, - .count = 8, - .endpoint = 0x2, - .u = { - .isoc = { - .framesperurb = 32, - .framesize = 2048, - .interval = 3, - } - } - }, - - .size_of_priv = 0, - }, - }, - - .num_device_descs = 1, - .devices = { - { "Technisat SkyStar USB HD (DVB-S/S2)", - { &technisat_usb2_id_table[0], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = 100, - .rc_codes = RC_MAP_TECHNISAT_USB2, - .module_name = "technisat-usb2", - .rc_query = technisat_usb2_rc_query, - .allowed_protos = RC_TYPE_ALL, - .driver_type = RC_DRIVER_IR_RAW, - } -}; - -static int technisat_usb2_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *dev; - - if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE, - &dev, adapter_nr) != 0) - return -ENODEV; - - if (dev) { - struct technisat_usb2_state *state = dev->priv; - state->dev = dev; - - if (!disable_led_control) { - INIT_DELAYED_WORK(&state->green_led_work, - technisat_usb2_green_led_control); - schedule_delayed_work(&state->green_led_work, - msecs_to_jiffies(500)); - } - } - - return 0; -} - -static void technisat_usb2_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *dev = usb_get_intfdata(intf); - - /* work and stuff was only created when the device is is hot-state */ - if (dev != NULL) { - struct technisat_usb2_state *state = dev->priv; - if (state != NULL) { - cancel_delayed_work_sync(&state->green_led_work); - flush_scheduled_work(); - } - } - - dvb_usb_device_exit(intf); -} - -static struct usb_driver technisat_usb2_driver = { - .name = "dvb_usb_technisat_usb2", - .probe = technisat_usb2_probe, - .disconnect = technisat_usb2_disconnect, - .id_table = technisat_usb2_id_table, -}; - -/* module stuff */ -static int __init technisat_usb2_module_init(void) -{ - int result = usb_register(&technisat_usb2_driver); - if (result) { - err("usb_register failed. Code %d", result); - return result; - } - - return 0; -} - -static void __exit technisat_usb2_module_exit(void) -{ - usb_deregister(&technisat_usb2_driver); -} - -module_init(technisat_usb2_module_init); -module_exit(technisat_usb2_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ttusb2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ttusb2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ttusb2.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ttusb2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,452 +0,0 @@ -/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones - * (e.g. Pinnacle 400e DVB-S USB2.0). - * - * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes. - * - * TDA8263 + TDA10086 - * - * I2C addresses: - * 0x08 - LNBP21PD - LNB power supply - * 0x0e - TDA10086 - Demodulator - * 0x50 - FX2 eeprom - * 0x60 - TDA8263 - Tuner - * 0x78 ??? - * - * Copyright (c) 2002 Holger Waechtler - * Copyright (c) 2003 Felix Domke - * Copyright (C) 2005-6 Patrick Boettcher - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#define DVB_USB_LOG_PREFIX "ttusb2" -#include "dvb-usb.h" - -#include "ttusb2.h" - -#include "tda826x.h" -#include "tda10086.h" -#include "tda1002x.h" -#include "tda827x.h" -#include "lnbp21.h" - -/* debug */ -static int dvb_usb_ttusb2_debug; -#define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) -module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct ttusb2_state { - u8 id; - u16 last_rc_key; -}; - -static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, - u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - struct ttusb2_state *st = d->priv; - u8 s[wlen+4],r[64] = { 0 }; - int ret = 0; - - memset(s,0,wlen+4); - - s[0] = 0xaa; - s[1] = ++st->id; - s[2] = cmd; - s[3] = wlen; - memcpy(&s[4],wbuf,wlen); - - ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0); - - if (ret != 0 || - r[0] != 0x55 || - r[1] != s[1] || - r[2] != cmd || - (rlen > 0 && r[3] != rlen)) { - warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); - return -EIO; - } - - if (rlen > 0) - memcpy(rbuf, &r[4], rlen); - - return 0; -} - -static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - static u8 obuf[60], ibuf[60]; - int i,read; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - if (num > 2) - warn("more than 2 i2c messages at a time is not handled yet. TODO."); - - for (i = 0; i < num; i++) { - read = i+1 < num && (msg[i+1].flags & I2C_M_RD); - - obuf[0] = (msg[i].addr << 1) | read; - obuf[1] = msg[i].len; - - /* read request */ - if (read) - obuf[2] = msg[i+1].len; - else - obuf[2] = 0; - - memcpy(&obuf[3],msg[i].buf,msg[i].len); - - if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) { - err("i2c transfer failed."); - break; - } - - if (read) { - memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len); - i++; - } - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm ttusb2_i2c_algo = { - .master_xfer = ttusb2_i2c_xfer, - .functionality = ttusb2_i2c_func, -}; - -/* command to poll IR receiver (copied from pctv452e.c) */ -#define CMD_GET_IR_CODE 0x1b - -/* IR */ -static int tt3650_rc_query(struct dvb_usb_device *d) -{ - int ret; - u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */ - struct ttusb2_state *st = d->priv; - ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx)); - if (ret != 0) - return ret; - - if (rx[8] & 0x01) { - /* got a "press" event */ - st->last_rc_key = (rx[3] << 8) | rx[2]; - deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]); - rc_keydown(d->rc_dev, st->last_rc_key, 0); - } else if (st->last_rc_key) { - rc_keyup(d->rc_dev); - st->last_rc_key = 0; - } - - return 0; -} - - -/* Callbacks for DVB USB */ -static int ttusb2_identify_state (struct usb_device *udev, struct - dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, - int *cold) -{ - *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; - return 0; -} - -static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b = onoff; - ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0); - return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0); -} - - -static struct tda10086_config tda10086_config = { - .demod_address = 0x0e, - .invert = 0, - .diseqc_tone = 1, - .xtal_freq = TDA10086_XTAL_16M, -}; - -static struct tda10023_config tda10023_config = { - .demod_address = 0x0c, - .invert = 0, - .xtal = 16000000, - .pll_m = 11, - .pll_p = 3, - .pll_n = 1, - .deltaf = 0xa511, -}; - -static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev,0,3) < 0) - err("set interface to alts=3 failed"); - - if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { - deb_info("TDA10086 attach failed\n"); - return -ENODEV; - } - - return 0; -} - -static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 3) < 0) - err("set interface to alts=3 failed"); - if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { - deb_info("TDA10023 attach failed\n"); - return -ENODEV; - } - return 0; -} - -static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) -{ - if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) { - printk(KERN_ERR "%s: No tda827x found!\n", __func__); - return -ENODEV; - } - return 0; -} - -static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) -{ - if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { - deb_info("TDA8263 attach failed\n"); - return -ENODEV; - } - - if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) { - deb_info("LNBP21 attach failed\n"); - return -ENODEV; - } - return 0; -} - -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties ttusb2_properties; -static struct dvb_usb_device_properties ttusb2_properties_s2400; -static struct dvb_usb_device_properties ttusb2_properties_ct3650; - -static int ttusb2_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &ttusb2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650, - THIS_MODULE, NULL, adapter_nr)) - return 0; - return -ENODEV; -} - -static struct usb_device_id ttusb2_table [] = { - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, - { USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_S2400) }, - { USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_CT3650) }, - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, ttusb2_table); - -static struct dvb_usb_device_properties ttusb2_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-pctv-400e-01.fw", - - .size_of_priv = sizeof(struct ttusb2_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, - - .frontend_attach = ttusb2_frontend_tda10086_attach, - .tuner_attach = ttusb2_tuner_tda826x_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x02, - .u = { - .isoc = { - .framesperurb = 4, - .framesize = 940, - .interval = 1, - } - } - } - } - }, - - .power_ctrl = ttusb2_power_ctrl, - .identify_state = ttusb2_identify_state, - - .i2c_algo = &ttusb2_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 2, - .devices = { - { "Pinnacle 400e DVB-S USB2.0", - { &ttusb2_table[0], NULL }, - { NULL }, - }, - { "Pinnacle 450e DVB-S USB2.0", - { &ttusb2_table[1], NULL }, - { NULL }, - }, - } -}; - -static struct dvb_usb_device_properties ttusb2_properties_s2400 = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-tt-s2400-01.fw", - - .size_of_priv = sizeof(struct ttusb2_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = NULL, - - .frontend_attach = ttusb2_frontend_tda10086_attach, - .tuner_attach = ttusb2_tuner_tda826x_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x02, - .u = { - .isoc = { - .framesperurb = 4, - .framesize = 940, - .interval = 1, - } - } - } - } - }, - - .power_ctrl = ttusb2_power_ctrl, - .identify_state = ttusb2_identify_state, - - .i2c_algo = &ttusb2_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Technotrend TT-connect S-2400", - { &ttusb2_table[2], NULL }, - { NULL }, - }, - } -}; - -static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct ttusb2_state), - - .rc.core = { - .rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */ - .rc_codes = RC_MAP_TT_1500, - .rc_query = tt3650_rc_query, - .allowed_protos = RC_TYPE_UNKNOWN, - }, - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = NULL, - - .frontend_attach = ttusb2_frontend_tda10023_attach, - .tuner_attach = ttusb2_tuner_tda827x_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x02, - .u = { - .isoc = { - .framesperurb = 4, - .framesize = 940, - .interval = 1, - } - } - } - }, - }, - - .power_ctrl = ttusb2_power_ctrl, - .identify_state = ttusb2_identify_state, - - .i2c_algo = &ttusb2_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Technotrend TT-connect CT-3650", - .warm_ids = { &ttusb2_table[3], NULL }, - }, - } -}; - -static struct usb_driver ttusb2_driver = { - .name = "dvb_usb_ttusb2", - .probe = ttusb2_probe, - .disconnect = dvb_usb_device_exit, - .id_table = ttusb2_table, -}; - -/* module stuff */ -static int __init ttusb2_module_init(void) -{ - int result; - if ((result = usb_register(&ttusb2_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit ttusb2_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&ttusb2_driver); -} - -module_init (ttusb2_module_init); -module_exit (ttusb2_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ttusb2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ttusb2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ttusb2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/ttusb2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones - * (e.g. Pinnacle 400e DVB-S USB2.0). - * - * Copyright (c) 2002 Holger Waechtler - * Copyright (c) 2003 Felix Domke - * Copyright (C) 2005-6 Patrick Boettcher - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_TTUSB2_H_ -#define _DVB_USB_TTUSB2_H_ - -/* TTUSB protocol - * - * always to messages (out/in) - * out message: - * 0xaa - * - * in message (complete block is always 0x40 bytes long) - * 0x55 - * - * id is incremented for each transaction - */ - -#define CMD_DSP_DOWNLOAD 0x13 -/* out data: [28] - * last block must be empty */ - -#define CMD_DSP_BOOT 0x14 -/* out data: nothing */ - -#define CMD_POWER 0x15 -/* out data: */ - -#define CMD_LNB 0x16 -/* out data: <18V=0,13V=1> */ - -#define CMD_GET_VERSION 0x17 -/* in data: [5] */ - -#define CMD_DISEQC 0x18 -/* out data: [cmdlen] */ - -#define CMD_PID_ENABLE 0x22 -/* out data: */ - -#define CMD_PID_DISABLE 0x23 -/* out data: */ - -#define CMD_FILTER_ENABLE 0x24 -/* out data: [12] [12] */ - -#define CMD_FILTER_DISABLE 0x25 -/* out data: */ - -#define CMD_GET_DSP_VERSION 0x26 -/* in data: [28] */ - -#define CMD_I2C_XFER 0x31 -/* out data: [sndlen] - * in data: [rcvlen] */ - -#define CMD_I2C_BITRATE 0x32 -/* out data: */ - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/umt-010.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/umt-010.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/umt-010.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/umt-010.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,167 +0,0 @@ -/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0 - * DVB-T receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -#include "mt352.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int umt_mt352_demod_init(struct dvb_frontend *fe) -{ - static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d }; - static u8 mt352_reset[] = { 0x50, 0x80 }; - static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 }; - static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 }; - - static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff }; - static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff }; - static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 }; - static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 }; - static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f }; - - static u8 mt352_acq_ctl[] = { 0x53, 0x50 }; - static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio)); - - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - - mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1)); - mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2)); - mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3)); - mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4)); - mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5)); - - mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl)); - mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1)); - - return 0; -} - -static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct mt352_config umt_config; - - memset(&umt_config,0,sizeof(struct mt352_config)); - umt_config.demod_init = umt_mt352_demod_init; - umt_config.demod_address = 0xf; - - adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); - - return 0; -} - -static int umt_tuner_attach (struct dvb_usb_adapter *adap) -{ - dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034); - return 0; -} - -/* USB Driver stuff */ -static struct dvb_usb_device_properties umt_properties; - -static int umt_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - if (0 == dvb_usb_device_init(intf, &umt_properties, - THIS_MODULE, NULL, adapter_nr)) - return 0; - return -EINVAL; -} - -/* do not change the order of the ID table */ -static struct usb_device_id umt_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE (usb, umt_table); - -static struct dvb_usb_device_properties umt_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-umt-010-02.fw", - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .frontend_attach = umt_mt352_frontend_attach, - .tuner_attach = umt_tuner_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = MAX_NO_URBS_FOR_DATA_STREAM, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - - .size_of_priv = sizeof(struct dibusb_state), - } - }, - .power_ctrl = dibusb_power_ctrl, - - .i2c_algo = &dibusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .num_device_descs = 1, - .devices = { - { "Hanftek UMT-010 DVB-T USB2.0", - { &umt_table[0], NULL }, - { &umt_table[1], NULL }, - }, - } -}; - -static struct usb_driver umt_driver = { - .name = "dvb_usb_umt_010", - .probe = umt_probe, - .disconnect = dvb_usb_device_exit, - .id_table = umt_table, -}; - -/* module stuff */ -static int __init umt_module_init(void) -{ - int result; - if ((result = usb_register(&umt_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit umt_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&umt_driver); -} - -module_init (umt_module_init); -module_exit (umt_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/usb-urb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/usb-urb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/usb-urb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/usb-urb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,254 +0,0 @@ -/* usb-urb.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file keeps functions for initializing and handling the - * BULK and ISOC USB data transfers in a generic way. - * Can be used for DVB-only and also, that's the plan, for - * Hybrid USB devices (analog and DVB). - */ -#include "dvb-usb-common.h" - -/* URB stuff for streaming */ -static void usb_urb_complete(struct urb *urb) -{ - struct usb_data_stream *stream = urb->context; - int ptype = usb_pipetype(urb->pipe); - int i; - u8 *b; - - deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n", - ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", - urb->status,urb->actual_length,urb->transfer_buffer_length, - urb->number_of_packets,urb->error_count); - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - deb_ts("urb completition error %d.\n", urb->status); - break; - } - - b = (u8 *) urb->transfer_buffer; - switch (ptype) { - case PIPE_ISOCHRONOUS: - for (i = 0; i < urb->number_of_packets; i++) { - - if (urb->iso_frame_desc[i].status != 0) - deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); - else if (urb->iso_frame_desc[i].actual_length > 0) - stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); - - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - debug_dump(b,20,deb_uxfer); - break; - case PIPE_BULK: - if (urb->actual_length > 0) - stream->complete(stream, b, urb->actual_length); - break; - default: - err("unknown endpoint type in completition handler."); - return; - } - usb_submit_urb(urb,GFP_ATOMIC); -} - -int usb_urb_kill(struct usb_data_stream *stream) -{ - int i; - for (i = 0; i < stream->urbs_submitted; i++) { - deb_ts("killing URB no. %d.\n",i); - - /* stop the URB */ - usb_kill_urb(stream->urb_list[i]); - } - stream->urbs_submitted = 0; - return 0; -} - -int usb_urb_submit(struct usb_data_stream *stream) -{ - int i,ret; - for (i = 0; i < stream->urbs_initialized; i++) { - deb_ts("submitting URB no. %d\n",i); - if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) { - err("could not submit URB no. %d - get them all back",i); - usb_urb_kill(stream); - return ret; - } - stream->urbs_submitted++; - } - return 0; -} - -static int usb_free_stream_buffers(struct usb_data_stream *stream) -{ - if (stream->state & USB_STATE_URB_BUF) { - while (stream->buf_num) { - stream->buf_num--; - deb_mem("freeing buffer %d\n",stream->buf_num); - usb_free_coherent(stream->udev, stream->buf_size, - stream->buf_list[stream->buf_num], - stream->dma_addr[stream->buf_num]); - } - } - - stream->state &= ~USB_STATE_URB_BUF; - - return 0; -} - -static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size) -{ - stream->buf_num = 0; - stream->buf_size = size; - - deb_mem("all in all I will use %lu bytes for streaming\n",num*size); - - for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { - deb_mem("allocating buffer %d\n",stream->buf_num); - if (( stream->buf_list[stream->buf_num] = - usb_alloc_coherent(stream->udev, size, GFP_ATOMIC, - &stream->dma_addr[stream->buf_num]) ) == NULL) { - deb_mem("not enough memory for urb-buffer allocation.\n"); - usb_free_stream_buffers(stream); - return -ENOMEM; - } - deb_mem("buffer %d: %p (dma: %Lu)\n", - stream->buf_num, -stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); - memset(stream->buf_list[stream->buf_num],0,size); - stream->state |= USB_STATE_URB_BUF; - } - deb_mem("allocation successful\n"); - - return 0; -} - -static int usb_bulk_urb_init(struct usb_data_stream *stream) -{ - int i, j; - - if ((i = usb_allocate_stream_buffers(stream,stream->props.count, - stream->props.u.bulk.buffersize)) < 0) - return i; - - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); - if (!stream->urb_list[i]) { - deb_mem("not enough memory for urb_alloc_urb!.\n"); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[i]); - return -ENOMEM; - } - usb_fill_bulk_urb( stream->urb_list[i], stream->udev, - usb_rcvbulkpipe(stream->udev,stream->props.endpoint), - stream->buf_list[i], - stream->props.u.bulk.buffersize, - usb_urb_complete, stream); - - stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; - stream->urbs_initialized++; - } - return 0; -} - -static int usb_isoc_urb_init(struct usb_data_stream *stream) -{ - int i,j; - - if ((i = usb_allocate_stream_buffers(stream,stream->props.count, - stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0) - return i; - - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - struct urb *urb; - int frame_offset = 0; - - stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC); - if (!stream->urb_list[i]) { - deb_mem("not enough memory for urb_alloc_urb!\n"); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[i]); - return -ENOMEM; - } - - urb = stream->urb_list[i]; - - urb->dev = stream->udev; - urb->context = stream; - urb->complete = usb_urb_complete; - urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = stream->props.u.isoc.interval; - urb->number_of_packets = stream->props.u.isoc.framesperurb; - urb->transfer_buffer_length = stream->buf_size; - urb->transfer_buffer = stream->buf_list[i]; - urb->transfer_dma = stream->dma_addr[i]; - - for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize; - frame_offset += stream->props.u.isoc.framesize; - } - - stream->urbs_initialized++; - } - return 0; -} - -int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) -{ - if (stream == NULL || props == NULL) - return -EINVAL; - - memcpy(&stream->props, props, sizeof(*props)); - - usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint)); - - if (stream->complete == NULL) { - err("there is no data callback - this doesn't make sense."); - return -EINVAL; - } - - switch (stream->props.type) { - case USB_BULK: - return usb_bulk_urb_init(stream); - case USB_ISOC: - return usb_isoc_urb_init(stream); - default: - err("unknown URB-type for data transfer."); - return -EINVAL; - } -} - -int usb_urb_exit(struct usb_data_stream *stream) -{ - int i; - - usb_urb_kill(stream); - - for (i = 0; i < stream->urbs_initialized; i++) { - if (stream->urb_list[i] != NULL) { - deb_mem("freeing URB no. %d.\n",i); - /* free the URBs */ - usb_free_urb(stream->urb_list[i]); - } - } - stream->urbs_initialized = 0; - - usb_free_stream_buffers(stream); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,338 +0,0 @@ -/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S - * receiver. - * - * Copyright (C) 2005 Ralph Metzler - * Metzler Brothers Systementwicklung GbR - * - * Copyright (C) 2005 Patrick Boettcher - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "vp702x.h" - -/* debug */ -int dvb_usb_vp702x_debug; -module_param_named(debug,dvb_usb_vp702x_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct vp702x_state { - int pid_filter_count; - int pid_filter_can_bypass; - u8 pid_filter_state; -}; - -struct vp702x_device_state { - u8 power_state; -}; - -/* check for mutex FIXME */ -int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) -{ - int ret = -1; - - ret = usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev,0), - req, - USB_TYPE_VENDOR | USB_DIR_IN, - value,index,b,blen, - 2000); - - if (ret < 0) { - warn("usb in operation failed. (%d)", ret); - ret = -EIO; - } else - ret = 0; - - - deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); - debug_dump(b,blen,deb_xfer); - - return ret; -} - -static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) -{ - int ret; - deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); - debug_dump(b,blen,deb_xfer); - - if ((ret = usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev,0), - req, - USB_TYPE_VENDOR | USB_DIR_OUT, - value,index,b,blen, - 2000)) != blen) { - warn("usb out operation failed. (%d)",ret); - return -EIO; - } else - return 0; -} - -int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec) -{ - int ret; - - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) - return ret; - - ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen); - msleep(msec); - ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen); - - mutex_unlock(&d->usb_mutex); - - return ret; -} - -static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, - int olen, u8 *i, int ilen, int msec) -{ - u8 bout[olen+2]; - u8 bin[ilen+1]; - int ret = 0; - - bout[0] = 0x00; - bout[1] = cmd; - memcpy(&bout[2],o,olen); - - ret = vp702x_usb_inout_op(d, bout, olen+2, bin, ilen+1,msec); - - if (ret == 0) - memcpy(i,&bin[1],ilen); - - return ret; -} - -static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass) -{ - u8 buf[16] = { 0 }; - return vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, 0, buf, 16); -} - -static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state) -{ - u8 buf[16] = { 0 }; - return vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, 0, buf, 16); -} - -static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff) -{ - struct vp702x_state *st = adap->priv; - u8 buf[16] = { 0 }; - - if (onoff) - st->pid_filter_state |= (1 << id); - else { - st->pid_filter_state &= ~(1 << id); - pid = 0xffff; - } - - id = 0x10 + id*2; - - vp702x_set_pld_state(adap, st->pid_filter_state); - vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16); - vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16); - return 0; -} - - -static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap) -{ - struct vp702x_state *st = adap->priv; - int i; - u8 b[10] = { 0 }; - - st->pid_filter_count = 8; - st->pid_filter_can_bypass = 1; - st->pid_filter_state = 0x00; - - vp702x_set_pld_mode(adap, 1); // bypass - - for (i = 0; i < st->pid_filter_count; i++) - vp702x_set_pid(adap, 0xffff, i, 1); - - vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10); - vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10); - vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10); - - //vp702x_set_pld_mode(d, 0); // filter - return 0; -} - -static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - return 0; -} - -/* keys for the enclosed remote control */ -static struct rc_map_table rc_map_vp702x_table[] = { - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, -}; - -/* remote control stuff (does not work with my box) */ -static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key[10]; - int i; - -/* remove the following return to enabled remote querying */ - return 0; - - vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10); - - deb_rc("remote query key: %x %d\n",key[1],key[1]); - - if (key[1] == 0x44) { - *state = REMOTE_NO_KEY_PRESSED; - return 0; - } - - for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++) - if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) { - *state = REMOTE_KEY_PRESSED; - *event = rc_map_vp702x_table[i].keycode; - break; - } - return 0; -} - - -static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) -{ - u8 i; - for (i = 6; i < 12; i++) - vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &mac[i - 6], 1); - return 0; -} - -static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 buf[10] = { 0 }; - - vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); - - if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, buf, 10, 10)) - return -EIO; - - buf[9] = '\0'; - info("system string: %s",&buf[1]); - - vp702x_init_pid_filter(adap); - - adap->fe = vp702x_fe_attach(adap->dev); - vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); - - return 0; -} - -static struct dvb_usb_device_properties vp702x_properties; - -static int vp702x_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &vp702x_properties, - THIS_MODULE, NULL, adapter_nr); -} - -static struct usb_device_id vp702x_usb_table [] = { - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) }, -// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) }, -// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) }, - { 0 }, -}; -MODULE_DEVICE_TABLE(usb, vp702x_usb_table); - -static struct dvb_usb_device_properties vp702x_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-vp702x-02.fw", - .no_reconnect = 1, - - .size_of_priv = sizeof(struct vp702x_device_state), - - .num_adapters = 1, - .adapter = { - { - .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS, - - .streaming_ctrl = vp702x_streaming_ctrl, - .frontend_attach = vp702x_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .size_of_priv = sizeof(struct vp702x_state), - } - }, - .read_mac_address = vp702x_read_mac_addr, - - .rc.legacy = { - .rc_map_table = rc_map_vp702x_table, - .rc_map_size = ARRAY_SIZE(rc_map_vp702x_table), - .rc_interval = 400, - .rc_query = vp702x_rc_query, - }, - - .num_device_descs = 1, - .devices = { - { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)", - .cold_ids = { &vp702x_usb_table[0], NULL }, - .warm_ids = { NULL }, - }, -/* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)", - .cold_ids = { &vp702x_usb_table[2], NULL }, - .warm_ids = { &vp702x_usb_table[3], NULL }, - }, -*/ { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver vp702x_usb_driver = { - .name = "dvb_usb_vp702x", - .probe = vp702x_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = vp702x_usb_table, -}; - -/* module stuff */ -static int __init vp702x_usb_module_init(void) -{ - int result; - if ((result = usb_register(&vp702x_usb_driver))) { - err("usb_register failed. (%d)",result); - return result; - } - - return 0; -} - -static void __exit vp702x_usb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&vp702x_usb_driver); -} - -module_init(vp702x_usb_module_init); -module_exit(vp702x_usb_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x-fe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x-fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,349 +0,0 @@ -/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0 - * DVB-S receiver. - * - * Copyright (C) 2005 Ralph Metzler - * Metzler Brothers Systementwicklung GbR - * - * Copyright (C) 2005 Patrick Boettcher - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * This file can be removed soon, after the DST-driver is rewritten to provice - * the frontend-controlling separately. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - * - */ -#include "vp702x.h" - -struct vp702x_fe_state { - struct dvb_frontend fe; - struct dvb_usb_device *d; - - struct dvb_frontend_ops ops; - - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone_mode; - - u8 lnb_buf[8]; - - u8 lock; - u8 sig; - u8 snr; - - unsigned long next_status_check; - unsigned long status_check_interval; -}; - -static int vp702x_fe_refresh_state(struct vp702x_fe_state *st) -{ - u8 buf[10]; - if (time_after(jiffies,st->next_status_check)) { - vp702x_usb_in_op(st->d,READ_STATUS,0,0,buf,10); - - st->lock = buf[4]; - vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x11,0,&st->snr,1); - vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x15,0,&st->sig,1); - - st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; - } - return 0; -} - -static u8 vp702x_chksum(u8 *buf,int f, int count) -{ - u8 s = 0; - int i; - for (i = f; i < f+count; i++) - s += buf[i]; - return ~s+1; -} - -static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - deb_fe("%s\n",__func__); - - if (st->lock == 0) - *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; - else - *status = 0; - - if (*status & FE_HAS_LOCK) - st->status_check_interval = 1000; - else - st->status_check_interval = 250; - return 0; -} - -/* not supported by this Frontend */ -static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - *ber = 0; - return 0; -} - -/* not supported by this Frontend */ -static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - *unc = 0; - return 0; -} - -static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - - *strength = (st->sig << 8) | st->sig; - return 0; -} - -static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - u8 _snr; - struct vp702x_fe_state *st = fe->demodulator_priv; - vp702x_fe_refresh_state(st); - - _snr = (st->snr & 0x1f) * 0xff / 0x1f; - *snr = (_snr << 8) | _snr; - return 0; -} - -static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - deb_fe("%s\n",__func__); - tune->min_delay_ms = 2000; - return 0; -} - -static int vp702x_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - u32 freq = fep->frequency/1000; - /*CalFrequency*/ -/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */ - u64 sr; - u8 cmd[8] = { 0 },ibuf[10]; - - cmd[0] = (freq >> 8) & 0x7f; - cmd[1] = freq & 0xff; - cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ - - sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20; - do_div(sr,88000); - cmd[3] = (sr >> 12) & 0xff; - cmd[4] = (sr >> 4) & 0xff; - cmd[5] = (sr << 4) & 0xf0; - - deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", - fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, - (unsigned long) sr, (unsigned long) sr); - -/* if (fep->inversion == INVERSION_ON) - cmd[6] |= 0x80; */ - - if (st->voltage == SEC_VOLTAGE_18) - cmd[6] |= 0x40; - -/* if (fep->u.qpsk.symbol_rate > 8000000) - cmd[6] |= 0x20; - - if (fep->frequency < 1531000) - cmd[6] |= 0x04; - - if (st->tone_mode == SEC_TONE_ON) - cmd[6] |= 0x01;*/ - - cmd[7] = vp702x_chksum(cmd,0,7); - - st->status_check_interval = 250; - st->next_status_check = jiffies; - - vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); - - if (ibuf[2] == 0 && ibuf[3] == 0) - deb_fe("tuning failed.\n"); - else - deb_fe("tuning succeeded.\n"); - - return 0; -} - -static int vp702x_fe_init(struct dvb_frontend *fe) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - deb_fe("%s\n",__func__); - vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); - return 0; -} - -static int vp702x_fe_sleep(struct dvb_frontend *fe) -{ - deb_fe("%s\n",__func__); - return 0; -} - -static int vp702x_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - deb_fe("%s\n",__func__); - return 0; -} - -static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - u8 cmd[8],ibuf[10]; - memset(cmd,0,8); - - deb_fe("%s\n",__func__); - - if (m->msg_len > 4) - return -EINVAL; - - cmd[1] = SET_DISEQC_CMD; - cmd[2] = m->msg_len; - memcpy(&cmd[3], m->msg, m->msg_len); - cmd[7] = vp702x_chksum(cmd,0,7); - - vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); - - if (ibuf[2] == 0 && ibuf[3] == 0) - deb_fe("diseqc cmd failed.\n"); - else - deb_fe("diseqc cmd succeeded.\n"); - - return 0; -} - -static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) -{ - deb_fe("%s\n",__func__); - return 0; -} - -static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - u8 ibuf[10]; - deb_fe("%s\n",__func__); - - st->tone_mode = tone; - - if (tone == SEC_TONE_ON) - st->lnb_buf[2] = 0x02; - else - st->lnb_buf[2] = 0x00; - - st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7); - - vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100); - if (ibuf[2] == 0 && ibuf[3] == 0) - deb_fe("set_tone cmd failed.\n"); - else - deb_fe("set_tone cmd succeeded.\n"); - - return 0; -} - -static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t - voltage) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - u8 ibuf[10]; - deb_fe("%s\n",__func__); - - st->voltage = voltage; - - if (voltage != SEC_VOLTAGE_OFF) - st->lnb_buf[4] = 0x01; - else - st->lnb_buf[4] = 0x00; - - st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7); - - vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100); - if (ibuf[2] == 0 && ibuf[3] == 0) - deb_fe("set_voltage cmd failed.\n"); - else - deb_fe("set_voltage cmd succeeded.\n"); - - return 0; -} - -static void vp702x_fe_release(struct dvb_frontend* fe) -{ - struct vp702x_fe_state *st = fe->demodulator_priv; - kfree(st); -} - -static struct dvb_frontend_ops vp702x_fe_ops; - -struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) -{ - struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL); - if (s == NULL) - goto error; - - s->d = d; - - memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops)); - s->fe.demodulator_priv = s; - - s->lnb_buf[1] = SET_LNB_POWER; - s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */ - - return &s->fe; -error: - return NULL; -} - - -static struct dvb_frontend_ops vp702x_fe_ops = { - .info = { - .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1000, /* kHz for QPSK frontends */ - .frequency_tolerance = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, /* ppm */ - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_QPSK | - FE_CAN_FEC_AUTO - }, - .release = vp702x_fe_release, - - .init = vp702x_fe_init, - .sleep = vp702x_fe_sleep, - - .set_frontend = vp702x_fe_set_frontend, - .get_frontend = vp702x_fe_get_frontend, - .get_tune_settings = vp702x_fe_get_tune_settings, - - .read_status = vp702x_fe_read_status, - .read_ber = vp702x_fe_read_ber, - .read_signal_strength = vp702x_fe_read_signal_strength, - .read_snr = vp702x_fe_read_snr, - .read_ucblocks = vp702x_fe_read_unc_blocks, - - .diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg, - .diseqc_send_burst = vp702x_fe_send_diseqc_burst, - .set_tone = vp702x_fe_set_tone, - .set_voltage = vp702x_fe_set_voltage, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp702x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -#ifndef _DVB_USB_VP7021_H_ -#define _DVB_USB_VP7021_H_ - -#define DVB_USB_LOG_PREFIX "vp702x" -#include "dvb-usb.h" - -extern int dvb_usb_vp702x_debug; -#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_vp702x_debug,0x04,args) -#define deb_fe(args...) dprintk(dvb_usb_vp702x_debug,0x08,args) - -/* commands are read and written with USB control messages */ - -/* consecutive read/write operation */ -#define REQUEST_OUT 0xB2 -#define REQUEST_IN 0xB3 - -/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0 - * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer - * the returning buffer looks as follows - * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */ - -#define GET_TUNER_STATUS 0x05 -/* additional in buffer: - * 0 1 2 3 4 5 6 7 8 - * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */ - -#define GET_SYSTEM_STRING 0x06 -/* additional in buffer: - * 0 1 2 3 4 5 6 7 8 - * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */ - -#define SET_DISEQC_CMD 0x08 -/* additional out buffer: - * 0 1 2 3 4 - * len X1 X2 X3 X4 - * additional in buffer: - * 0 1 2 - * N/A 0 0 b[1] == b[2] == 0 -> success, failure otherwise */ - -#define SET_LNB_POWER 0x09 -/* additional out buffer: - * 0 1 2 - * 0x00 0xff 1 = on, 0 = off - * additional in buffer: - * 0 1 2 - * N/A 0 0 b[1] == b[2] == 0 -> success failure otherwise */ - -#define GET_MAC_ADDRESS 0x0A -/* #define GET_MAC_ADDRESS 0x0B */ -/* additional in buffer: - * 0 1 2 3 4 5 6 7 8 - * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */ - -#define SET_PID_FILTER 0x11 -/* additional in buffer: - * 0 1 ... 14 15 16 - * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */ - -/* request: 0xB2; i: 0; v: 0; - * b[0] != 0 -> tune and lock a channel - * 0 1 2 3 4 5 6 7 - * freq0 freq1 divstep srate0 srate1 srate2 flag chksum - */ - -/* one direction requests */ -#define READ_REMOTE_REQ 0xB4 -/* IN i: 0; v: 0; b[0] == request, b[1] == key */ - -#define READ_PID_NUMBER_REQ 0xB5 -/* IN i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */ - -#define WRITE_EEPROM_REQ 0xB6 -/* OUT i: offset; v: value to write; no extra buffer */ - -#define READ_EEPROM_REQ 0xB7 -/* IN i: bufferlen; v: offset; buffer with bufferlen bytes */ - -#define READ_STATUS 0xB8 -/* IN i: 0; v: 0; bufferlen 10 */ - -#define READ_TUNER_REG_REQ 0xB9 -/* IN i: 0; v: register; b[0] = value */ - -#define READ_FX2_REG_REQ 0xBA -/* IN i: offset; v: 0; b[0] = value */ - -#define WRITE_FX2_REG_REQ 0xBB -/* OUT i: offset; v: value to write; 1 byte extra buffer */ - -#define SET_TUNER_POWER_REQ 0xBC -/* IN i: 0 = power off, 1 = power on */ - -#define WRITE_TUNER_REG_REQ 0xBD -/* IN i: register, v: value to write, no extra buffer */ - -#define RESET_TUNER 0xBE -/* IN i: 0, v: 0, no extra buffer */ - -extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); - -extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); -extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,314 +0,0 @@ -/* DVB USB compliant Linux driver for the - * - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver - * - DigitalNow TinyUSB2 DVB-t receiver - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "vp7045.h" - -/* debug */ -static int dvb_usb_vp7045_debug; -module_param_named(debug,dvb_usb_vp7045_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) - -int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec) -{ - int ret = 0; - u8 inbuf[12] = { 0 }, outbuf[20] = { 0 }; - - outbuf[0] = cmd; - - if (outlen > 19) - outlen = 19; - - if (inlen > 11) - inlen = 11; - - if (out != NULL && outlen > 0) - memcpy(&outbuf[1], out, outlen); - - deb_xfer("out buffer: "); - debug_dump(outbuf,outlen+1,deb_xfer); - - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) - return ret; - - if (usb_control_msg(d->udev, - usb_sndctrlpipe(d->udev,0), - TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, - outbuf, 20, 2000) != 20) { - err("USB control message 'out' went wrong."); - ret = -EIO; - goto unlock; - } - - msleep(msec); - - if (usb_control_msg(d->udev, - usb_rcvctrlpipe(d->udev,0), - TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - inbuf, 12, 2000) != 12) { - err("USB control message 'in' went wrong."); - ret = -EIO; - goto unlock; - } - - deb_xfer("in buffer: "); - debug_dump(inbuf,12,deb_xfer); - - if (in != NULL && inlen > 0) - memcpy(in,&inbuf[1],inlen); - -unlock: - mutex_unlock(&d->usb_mutex); - - return ret; -} - -u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg) -{ - u8 obuf[2] = { 0 },v; - obuf[1] = reg; - - vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30); - - return v; -} - -static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 v = onoff; - return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150); -} - -/* remote control stuff */ - -/* The keymapping struct. Somehow this should be loaded to the driver, but - * currently it is hardcoded. */ -static struct rc_map_table rc_map_vp7045_table[] = { - { 0x0016, KEY_POWER }, - { 0x0010, KEY_MUTE }, - { 0x0003, KEY_1 }, - { 0x0001, KEY_2 }, - { 0x0006, KEY_3 }, - { 0x0009, KEY_4 }, - { 0x001d, KEY_5 }, - { 0x001f, KEY_6 }, - { 0x000d, KEY_7 }, - { 0x0019, KEY_8 }, - { 0x001b, KEY_9 }, - { 0x0015, KEY_0 }, - { 0x0005, KEY_CHANNELUP }, - { 0x0002, KEY_CHANNELDOWN }, - { 0x001e, KEY_VOLUMEUP }, - { 0x000a, KEY_VOLUMEDOWN }, - { 0x0011, KEY_RECORD }, - { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */ - { 0x0014, KEY_PLAY }, - { 0x001a, KEY_STOP }, - { 0x0040, KEY_REWIND }, - { 0x0012, KEY_FASTFORWARD }, - { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */ - { 0x004c, KEY_PAUSE }, - { 0x004d, KEY_SCREEN }, /* Full screen mode. */ - { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ - { 0x000c, KEY_CANCEL }, /* Cancel */ - { 0x001c, KEY_EPG }, /* EPG */ - { 0x0000, KEY_TAB }, /* Tab */ - { 0x0048, KEY_INFO }, /* Preview */ - { 0x0004, KEY_LIST }, /* RecordList */ - { 0x000f, KEY_TEXT }, /* Teletext */ - { 0x0041, KEY_PREVIOUSSONG }, - { 0x0042, KEY_NEXTSONG }, - { 0x004b, KEY_UP }, - { 0x0051, KEY_DOWN }, - { 0x004e, KEY_LEFT }, - { 0x0052, KEY_RIGHT }, - { 0x004f, KEY_ENTER }, - { 0x0013, KEY_CANCEL }, - { 0x004a, KEY_CLEAR }, - { 0x0054, KEY_PRINT }, /* Capture */ - { 0x0043, KEY_SUBTITLE }, /* Subtitle/CC */ - { 0x0008, KEY_VIDEO }, /* A/V */ - { 0x0007, KEY_SLEEP }, /* Hibernate */ - { 0x0045, KEY_ZOOM }, /* Zoom+ */ - { 0x0018, KEY_RED}, - { 0x0053, KEY_GREEN}, - { 0x005e, KEY_YELLOW}, - { 0x005f, KEY_BLUE} -}; - -static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key; - int i; - vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20); - - deb_rc("remote query key: %x %d\n",key,key); - - if (key == 0x44) { - *state = REMOTE_NO_KEY_PRESSED; - return 0; - } - - for (i = 0; i < ARRAY_SIZE(rc_map_vp7045_table); i++) - if (rc5_data(&rc_map_vp7045_table[i]) == key) { - *state = REMOTE_KEY_PRESSED; - *event = rc_map_vp7045_table[i].keycode; - break; - } - return 0; -} - -static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset) -{ - int i = 0; - u8 v,br[2]; - for (i=0; i < len; i++) { - v = offset + i; - vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5); - buf[i] = br[1]; - } - deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i); - debug_dump(buf,i,deb_info); - return 0; -} - -static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) -{ - return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR); -} - -static int vp7045_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 buf[255] = { 0 }; - - vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0); - buf[10] = '\0'; - deb_info("firmware says: %s ",buf); - - vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0); - buf[10] = '\0'; - deb_info("%s ",buf); - - vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0); - buf[10] = '\0'; - deb_info("v%s\n",buf); - -/* Dump the EEPROM */ -/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */ - - adap->fe = vp7045_fe_attach(adap->dev); - - return 0; -} - -static struct dvb_usb_device_properties vp7045_properties; - -static int vp7045_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return dvb_usb_device_init(intf, &vp7045_properties, - THIS_MODULE, NULL, adapter_nr); -} - -static struct usb_device_id vp7045_usb_table [] = { - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) }, - { 0 }, -}; -MODULE_DEVICE_TABLE(usb, vp7045_usb_table); - -static struct dvb_usb_device_properties vp7045_properties = { - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-vp7045-01.fw", - - .num_adapters = 1, - .adapter = { - { - .frontend_attach = vp7045_frontend_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } - }, - .power_ctrl = vp7045_power_ctrl, - .read_mac_address = vp7045_read_mac_addr, - - .rc.legacy = { - .rc_interval = 400, - .rc_map_table = rc_map_vp7045_table, - .rc_map_size = ARRAY_SIZE(rc_map_vp7045_table), - .rc_query = vp7045_rc_query, - }, - - .num_device_descs = 2, - .devices = { - { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)", - .cold_ids = { &vp7045_usb_table[0], NULL }, - .warm_ids = { &vp7045_usb_table[1], NULL }, - }, - { .name = "DigitalNow TinyUSB 2 DVB-t Receiver", - .cold_ids = { &vp7045_usb_table[2], NULL }, - .warm_ids = { &vp7045_usb_table[3], NULL }, - }, - { NULL }, - } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver vp7045_usb_driver = { - .name = "dvb_usb_vp7045", - .probe = vp7045_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = vp7045_usb_table, -}; - -/* module stuff */ -static int __init vp7045_usb_module_init(void) -{ - int result; - if ((result = usb_register(&vp7045_usb_driver))) { - err("usb_register failed. (%d)",result); - return result; - } - - return 0; -} - -static void __exit vp7045_usb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&vp7045_usb_driver); -} - -module_init(vp7045_usb_module_init); -module_exit(vp7045_usb_module_exit); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045-fe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045-fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,192 +0,0 @@ -/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0 - * DVB-T receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - * - */ -#include "vp7045.h" - -/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT - * - * Programming is hidden inside the firmware, so set_frontend is very easy. - * Even though there is a Firmware command that one can use to access the demod - * via its registers. This is used for status information. - */ - -struct vp7045_fe_state { - struct dvb_frontend fe; - struct dvb_usb_device *d; -}; - -static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - u8 s0 = vp7045_read_reg(state->d,0x00), - s1 = vp7045_read_reg(state->d,0x01), - s3 = vp7045_read_reg(state->d,0x03); - - *status = 0; - if (s0 & (1 << 4)) - *status |= FE_HAS_CARRIER; - if (s0 & (1 << 1)) - *status |= FE_HAS_VITERBI; - if (s0 & (1 << 5)) - *status |= FE_HAS_LOCK; - if (s1 & (1 << 1)) - *status |= FE_HAS_SYNC; - if (s3 & (1 << 6)) - *status |= FE_HAS_SIGNAL; - - if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != - (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) - *status &= ~FE_HAS_LOCK; - - return 0; -} - -static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - *ber = (vp7045_read_reg(state->d, 0x0D) << 16) | - (vp7045_read_reg(state->d, 0x0E) << 8) | - vp7045_read_reg(state->d, 0x0F); - return 0; -} - -static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - *unc = (vp7045_read_reg(state->d, 0x10) << 8) | - vp7045_read_reg(state->d, 0x11); - return 0; -} - -static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) | - vp7045_read_reg(state->d, 0x15); - - *strength = ~signal; - return 0; -} - -static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - u8 _snr = vp7045_read_reg(state->d, 0x09); - *snr = (_snr << 8) | _snr; - return 0; -} - -static int vp7045_fe_init(struct dvb_frontend* fe) -{ - return 0; -} - -static int vp7045_fe_sleep(struct dvb_frontend* fe) -{ - return 0; -} - -static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 800; - return 0; -} - -static int vp7045_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - u8 buf[5]; - u32 freq = fep->frequency / 1000; - - buf[0] = (freq >> 16) & 0xff; - buf[1] = (freq >> 8) & 0xff; - buf[2] = freq & 0xff; - buf[3] = 0; - - switch (fep->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: buf[4] = 8; break; - case BANDWIDTH_7_MHZ: buf[4] = 7; break; - case BANDWIDTH_6_MHZ: buf[4] = 6; break; - case BANDWIDTH_AUTO: return -EOPNOTSUPP; - default: - return -EINVAL; - } - - vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200); - return 0; -} - -static int vp7045_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - return 0; -} - -static void vp7045_fe_release(struct dvb_frontend* fe) -{ - struct vp7045_fe_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops vp7045_fe_ops; - -struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d) -{ - struct vp7045_fe_state *s = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL); - if (s == NULL) - goto error; - - s->d = d; - memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops)); - s->fe.demodulator_priv = s; - - return &s->fe; -error: - return NULL; -} - - -static struct dvb_frontend_ops vp7045_fe_ops = { - .info = { - .name = "Twinhan VP7045/46 USB DVB-T", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 1000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = vp7045_fe_release, - - .init = vp7045_fe_init, - .sleep = vp7045_fe_sleep, - - .set_frontend = vp7045_fe_set_frontend, - .get_frontend = vp7045_fe_get_frontend, - .get_tune_settings = vp7045_fe_get_tune_settings, - - .read_status = vp7045_fe_read_status, - .read_ber = vp7045_fe_read_ber, - .read_signal_strength = vp7045_fe_read_signal_strength, - .read_snr = vp7045_fe_read_snr, - .read_ucblocks = vp7045_fe_read_unc_blocks, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/dvb-usb/vp7045.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII - * USB2.0 DVB-T receiver. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * Thanks to Twinhan who kindly provided hardware and information. - * - * 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, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#ifndef _DVB_USB_VP7045_H_ -#define _DVB_USB_VP7045_H_ - -#define DVB_USB_LOG_PREFIX "vp7045" -#include "dvb-usb.h" - -/* vp7045 commands */ - -/* Twinhan Vendor requests */ -#define TH_COMMAND_IN 0xC0 -#define TH_COMMAND_OUT 0xC1 - -/* command bytes */ -#define TUNER_REG_READ 0x03 -#define TUNER_REG_WRITE 0x04 - -#define RC_VAL_READ 0x05 - #define RC_NO_KEY 0x44 - -#define SET_TUNER_POWER 0x06 -#define CHECK_TUNER_POWER 0x12 - #define Tuner_Power_ON 1 - #define Tuner_Power_OFF 0 - -#define GET_USB_SPEED 0x07 - #define USB_SPEED_LOW 0 - #define USB_SPEED_FULL 1 - #define USB_SPEED_HIGH 2 - -#define LOCK_TUNER_COMMAND 0x09 - -#define TUNER_SIGNAL_READ 0x0A - -/* FX2 eeprom */ -#define SET_EE_VALUE 0x10 -#define GET_EE_VALUE 0x11 - #define FX2_ID_ADDR 0x00 - #define VID_MSB_ADDR 0x02 - #define VID_LSB_ADDR 0x01 - #define PID_MSB_ADDR 0x04 - #define PID_LSB_ADDR 0x03 - #define MAC_0_ADDR 0x07 - #define MAC_1_ADDR 0x08 - #define MAC_2_ADDR 0x09 - #define MAC_3_ADDR 0x0a - #define MAC_4_ADDR 0x0b - #define MAC_5_ADDR 0x0c - -#define RESET_FX2 0x13 - -#define FW_VERSION_READ 0x0B -#define VENDOR_STRING_READ 0x0C -#define PRODUCT_STRING_READ 0x0D -#define FW_BCD_VERSION_READ 0x14 - -extern struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d); -extern int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen,int msec); -extern u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-avc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-avc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-avc.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-avc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1470 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Ben Backx - * Copyright (C) 2008 Henrik Kurelid - * - * 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, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "firedtv.h" - -#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL - -#define AVC_CTYPE_CONTROL 0x0 -#define AVC_CTYPE_STATUS 0x1 -#define AVC_CTYPE_NOTIFY 0x3 - -#define AVC_RESPONSE_ACCEPTED 0x9 -#define AVC_RESPONSE_STABLE 0xc -#define AVC_RESPONSE_CHANGED 0xd -#define AVC_RESPONSE_INTERIM 0xf - -#define AVC_SUBUNIT_TYPE_TUNER (0x05 << 3) -#define AVC_SUBUNIT_TYPE_UNIT (0x1f << 3) - -#define AVC_OPCODE_VENDOR 0x00 -#define AVC_OPCODE_READ_DESCRIPTOR 0x09 -#define AVC_OPCODE_DSIT 0xc8 -#define AVC_OPCODE_DSD 0xcb - -#define DESCRIPTOR_TUNER_STATUS 0x80 -#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00 - -#define SFE_VENDOR_DE_COMPANYID_0 0x00 /* OUI of Digital Everywhere */ -#define SFE_VENDOR_DE_COMPANYID_1 0x12 -#define SFE_VENDOR_DE_COMPANYID_2 0x87 - -#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0a -#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52 -#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 /* for DVB-S */ - -#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00 -#define SFE_VENDOR_OPCODE_HOST2CA 0x56 -#define SFE_VENDOR_OPCODE_CA2HOST 0x57 -#define SFE_VENDOR_OPCODE_CISTATUS 0x59 -#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 /* for DVB-S2 */ - -#define SFE_VENDOR_TAG_CA_RESET 0x00 -#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01 -#define SFE_VENDOR_TAG_CA_PMT 0x02 -#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04 -#define SFE_VENDOR_TAG_CA_MMI 0x05 -#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07 - -#define EN50221_LIST_MANAGEMENT_ONLY 0x03 -#define EN50221_TAG_APP_INFO 0x9f8021 -#define EN50221_TAG_CA_INFO 0x9f8031 - -struct avc_command_frame { - u8 ctype; - u8 subunit; - u8 opcode; - u8 operand[509]; -}; - -struct avc_response_frame { - u8 response; - u8 subunit; - u8 opcode; - u8 operand[509]; -}; - -#define LAST_OPERAND (509 - 1) - -static inline void clear_operands(struct avc_command_frame *c, int from, int to) -{ - memset(&c->operand[from], 0, to - from + 1); -} - -static void pad_operands(struct avc_command_frame *c, int from) -{ - int to = ALIGN(from, 4); - - if (from <= to && to <= LAST_OPERAND) - clear_operands(c, from, to); -} - -#define AVC_DEBUG_READ_DESCRIPTOR 0x0001 -#define AVC_DEBUG_DSIT 0x0002 -#define AVC_DEBUG_DSD 0x0004 -#define AVC_DEBUG_REGISTER_REMOTE_CONTROL 0x0008 -#define AVC_DEBUG_LNB_CONTROL 0x0010 -#define AVC_DEBUG_TUNE_QPSK 0x0020 -#define AVC_DEBUG_TUNE_QPSK2 0x0040 -#define AVC_DEBUG_HOST2CA 0x0080 -#define AVC_DEBUG_CA2HOST 0x0100 -#define AVC_DEBUG_APPLICATION_PMT 0x4000 -#define AVC_DEBUG_FCP_PAYLOADS 0x8000 - -static int avc_debug; -module_param_named(debug, avc_debug, int, 0644); -MODULE_PARM_DESC(debug, "Verbose logging (none = 0" - ", FCP subactions" - ": READ DESCRIPTOR = " __stringify(AVC_DEBUG_READ_DESCRIPTOR) - ", DSIT = " __stringify(AVC_DEBUG_DSIT) - ", REGISTER_REMOTE_CONTROL = " __stringify(AVC_DEBUG_REGISTER_REMOTE_CONTROL) - ", LNB CONTROL = " __stringify(AVC_DEBUG_LNB_CONTROL) - ", TUNE QPSK = " __stringify(AVC_DEBUG_TUNE_QPSK) - ", TUNE QPSK2 = " __stringify(AVC_DEBUG_TUNE_QPSK2) - ", HOST2CA = " __stringify(AVC_DEBUG_HOST2CA) - ", CA2HOST = " __stringify(AVC_DEBUG_CA2HOST) - "; Application sent PMT = " __stringify(AVC_DEBUG_APPLICATION_PMT) - ", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS) - ", or a combination, or all = -1)"); - -/* - * This is a workaround since there is no vendor specific command to retrieve - * ca_info using AVC. If this parameter is not used, ca_system_id will be - * filled with application_manufacturer from ca_app_info. - * Digital Everywhere have said that adding ca_info is on their TODO list. - */ -static unsigned int num_fake_ca_system_ids; -static int fake_ca_system_ids[4] = { -1, -1, -1, -1 }; -module_param_array(fake_ca_system_ids, int, &num_fake_ca_system_ids, 0644); -MODULE_PARM_DESC(fake_ca_system_ids, "If your CAM application manufacturer " - "does not have the same ca_system_id as your CAS, you can " - "override what ca_system_ids are presented to the " - "application by setting this field to an array of ids."); - -static const char *debug_fcp_ctype(unsigned int ctype) -{ - static const char *ctypes[] = { - [0x0] = "CONTROL", [0x1] = "STATUS", - [0x2] = "SPECIFIC INQUIRY", [0x3] = "NOTIFY", - [0x4] = "GENERAL INQUIRY", [0x8] = "NOT IMPLEMENTED", - [0x9] = "ACCEPTED", [0xa] = "REJECTED", - [0xb] = "IN TRANSITION", [0xc] = "IMPLEMENTED/STABLE", - [0xd] = "CHANGED", [0xf] = "INTERIM", - }; - const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL; - - return ret ? ret : "?"; -} - -static const char *debug_fcp_opcode(unsigned int opcode, - const u8 *data, int length) -{ - switch (opcode) { - case AVC_OPCODE_VENDOR: - break; - case AVC_OPCODE_READ_DESCRIPTOR: - return avc_debug & AVC_DEBUG_READ_DESCRIPTOR ? - "ReadDescriptor" : NULL; - case AVC_OPCODE_DSIT: - return avc_debug & AVC_DEBUG_DSIT ? - "DirectSelectInfo.Type" : NULL; - case AVC_OPCODE_DSD: - return avc_debug & AVC_DEBUG_DSD ? "DirectSelectData" : NULL; - default: - return "Unknown"; - } - - if (length < 7 || - data[3] != SFE_VENDOR_DE_COMPANYID_0 || - data[4] != SFE_VENDOR_DE_COMPANYID_1 || - data[5] != SFE_VENDOR_DE_COMPANYID_2) - return "Vendor/Unknown"; - - switch (data[6]) { - case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL: - return avc_debug & AVC_DEBUG_REGISTER_REMOTE_CONTROL ? - "RegisterRC" : NULL; - case SFE_VENDOR_OPCODE_LNB_CONTROL: - return avc_debug & AVC_DEBUG_LNB_CONTROL ? "LNBControl" : NULL; - case SFE_VENDOR_OPCODE_TUNE_QPSK: - return avc_debug & AVC_DEBUG_TUNE_QPSK ? "TuneQPSK" : NULL; - case SFE_VENDOR_OPCODE_TUNE_QPSK2: - return avc_debug & AVC_DEBUG_TUNE_QPSK2 ? "TuneQPSK2" : NULL; - case SFE_VENDOR_OPCODE_HOST2CA: - return avc_debug & AVC_DEBUG_HOST2CA ? "Host2CA" : NULL; - case SFE_VENDOR_OPCODE_CA2HOST: - return avc_debug & AVC_DEBUG_CA2HOST ? "CA2Host" : NULL; - } - return "Vendor/Unknown"; -} - -static void debug_fcp(const u8 *data, int length) -{ - unsigned int subunit_type, subunit_id, opcode; - const char *op, *prefix; - - prefix = data[0] > 7 ? "FCP <- " : "FCP -> "; - subunit_type = data[1] >> 3; - subunit_id = data[1] & 7; - opcode = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2]; - op = debug_fcp_opcode(opcode, data, length); - - if (op) { - printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n", - prefix, subunit_type, subunit_id, length, - debug_fcp_ctype(data[0]), op); - if (avc_debug & AVC_DEBUG_FCP_PAYLOADS) - print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE, - 16, 1, data, length, false); - } -} - -static void debug_pmt(char *msg, int length) -{ - printk(KERN_INFO "APP PMT -> l=%d\n", length); - print_hex_dump(KERN_INFO, "APP PMT -> ", DUMP_PREFIX_NONE, - 16, 1, msg, length, false); -} - -static int avc_write(struct firedtv *fdtv) -{ - int err, retry; - - fdtv->avc_reply_received = false; - - for (retry = 0; retry < 6; retry++) { - if (unlikely(avc_debug)) - debug_fcp(fdtv->avc_data, fdtv->avc_data_length); - - err = fdtv_write(fdtv, FCP_COMMAND_REGISTER, - fdtv->avc_data, fdtv->avc_data_length); - if (err) { - dev_err(fdtv->device, "FCP command write failed\n"); - - return err; - } - - /* - * AV/C specs say that answers should be sent within 150 ms. - * Time out after 200 ms. - */ - if (wait_event_timeout(fdtv->avc_wait, - fdtv->avc_reply_received, - msecs_to_jiffies(200)) != 0) - return 0; - } - dev_err(fdtv->device, "FCP response timed out\n"); - - return -ETIMEDOUT; -} - -static bool is_register_rc(struct avc_response_frame *r) -{ - return r->opcode == AVC_OPCODE_VENDOR && - r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && - r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && - r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && - r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; -} - -int avc_recv(struct firedtv *fdtv, void *data, size_t length) -{ - struct avc_response_frame *r = data; - - if (unlikely(avc_debug)) - debug_fcp(data, length); - - if (length >= 8 && is_register_rc(r)) { - switch (r->response) { - case AVC_RESPONSE_CHANGED: - fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]); - schedule_work(&fdtv->remote_ctrl_work); - break; - case AVC_RESPONSE_INTERIM: - if (is_register_rc((void *)fdtv->avc_data)) - goto wake; - break; - default: - dev_info(fdtv->device, - "remote control result = %d\n", r->response); - } - return 0; - } - - if (fdtv->avc_reply_received) { - dev_err(fdtv->device, "out-of-order AVC response, ignored\n"); - return -EIO; - } - - memcpy(fdtv->avc_data, data, length); - fdtv->avc_data_length = length; -wake: - fdtv->avc_reply_received = true; - wake_up(&fdtv->avc_wait); - - return 0; -} - -static int add_pid_filter(struct firedtv *fdtv, u8 *operand) -{ - int i, n, pos = 1; - - for (i = 0, n = 0; i < 16; i++) { - if (test_bit(i, &fdtv->channel_active)) { - operand[pos++] = 0x13; /* flowfunction relay */ - operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */ - operand[pos++] = (fdtv->channel_pid[i] >> 8) & 0x1f; - operand[pos++] = fdtv->channel_pid[i] & 0xff; - operand[pos++] = 0x00; /* tableID */ - operand[pos++] = 0x00; /* filter_length */ - n++; - } - } - operand[0] = n; - - return pos; -} - -/* - * tuning command for setting the relative LNB frequency - * (not supported by the AVC standard) - */ -static int avc_tuner_tuneqpsk(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - if (fdtv->type == FIREDTV_DVB_S2) - c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK2; - else - c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; - - c->operand[4] = (params->frequency >> 24) & 0xff; - c->operand[5] = (params->frequency >> 16) & 0xff; - c->operand[6] = (params->frequency >> 8) & 0xff; - c->operand[7] = params->frequency & 0xff; - - c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; - c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; - - switch (params->u.qpsk.fec_inner) { - case FEC_1_2: c->operand[10] = 0x1; break; - case FEC_2_3: c->operand[10] = 0x2; break; - case FEC_3_4: c->operand[10] = 0x3; break; - case FEC_5_6: c->operand[10] = 0x4; break; - case FEC_7_8: c->operand[10] = 0x5; break; - case FEC_4_5: - case FEC_8_9: - case FEC_AUTO: - default: c->operand[10] = 0x0; - } - - if (fdtv->voltage == 0xff) - c->operand[11] = 0xff; - else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */ - c->operand[11] = 0; - else - c->operand[11] = 1; - - if (fdtv->tone == 0xff) - c->operand[12] = 0xff; - else if (fdtv->tone == SEC_TONE_ON) /* band */ - c->operand[12] = 1; - else - c->operand[12] = 0; - - if (fdtv->type == FIREDTV_DVB_S2) { - if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) { - switch (fdtv->fe.dtv_property_cache.modulation) { - case QAM_16: c->operand[13] = 0x1; break; - case QPSK: c->operand[13] = 0x2; break; - case PSK_8: c->operand[13] = 0x3; break; - default: c->operand[13] = 0x2; break; - } - switch (fdtv->fe.dtv_property_cache.rolloff) { - case ROLLOFF_AUTO: c->operand[14] = 0x2; break; - case ROLLOFF_35: c->operand[14] = 0x2; break; - case ROLLOFF_20: c->operand[14] = 0x0; break; - case ROLLOFF_25: c->operand[14] = 0x1; break; - /* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */ - } - switch (fdtv->fe.dtv_property_cache.pilot) { - case PILOT_AUTO: c->operand[15] = 0x0; break; - case PILOT_OFF: c->operand[15] = 0x0; break; - case PILOT_ON: c->operand[15] = 0x1; break; - } - } else { - c->operand[13] = 0x1; /* auto modulation */ - c->operand[14] = 0xff; /* disable rolloff */ - c->operand[15] = 0xff; /* disable pilot */ - } - return 16; - } else { - return 13; - } -} - -static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - - c->opcode = AVC_OPCODE_DSD; - - c->operand[0] = 0; /* source plug */ - c->operand[1] = 0xd2; /* subfunction replace */ - c->operand[2] = 0x20; /* system id = DVB */ - c->operand[3] = 0x00; /* antenna number */ - c->operand[4] = 0x11; /* system_specific_multiplex selection_length */ - - /* multiplex_valid_flags, high byte */ - c->operand[5] = 0 << 7 /* reserved */ - | 0 << 6 /* Polarisation */ - | 0 << 5 /* Orbital_Pos */ - | 1 << 4 /* Frequency */ - | 1 << 3 /* Symbol_Rate */ - | 0 << 2 /* FEC_outer */ - | (params->u.qam.fec_inner != FEC_AUTO ? 1 << 1 : 0) - | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0); - - /* multiplex_valid_flags, low byte */ - c->operand[6] = 0 << 7 /* NetworkID */ - | 0 << 0 /* reserved */ ; - - c->operand[7] = 0x00; - c->operand[8] = 0x00; - c->operand[9] = 0x00; - c->operand[10] = 0x00; - - c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); - c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff; - c->operand[13] = (params->frequency / 4000) & 0xff; - c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; - c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; - c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; - c->operand[17] = 0x00; - - switch (params->u.qpsk.fec_inner) { - case FEC_1_2: c->operand[18] = 0x1; break; - case FEC_2_3: c->operand[18] = 0x2; break; - case FEC_3_4: c->operand[18] = 0x3; break; - case FEC_5_6: c->operand[18] = 0x4; break; - case FEC_7_8: c->operand[18] = 0x5; break; - case FEC_8_9: c->operand[18] = 0x6; break; - case FEC_4_5: c->operand[18] = 0x8; break; - case FEC_AUTO: - default: c->operand[18] = 0x0; - } - - switch (params->u.qam.modulation) { - case QAM_16: c->operand[19] = 0x08; break; - case QAM_32: c->operand[19] = 0x10; break; - case QAM_64: c->operand[19] = 0x18; break; - case QAM_128: c->operand[19] = 0x20; break; - case QAM_256: c->operand[19] = 0x28; break; - case QAM_AUTO: - default: c->operand[19] = 0x00; - } - - c->operand[20] = 0x00; - c->operand[21] = 0x00; - - return 22 + add_pid_filter(fdtv, &c->operand[22]); -} - -static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) -{ - struct dvb_ofdm_parameters *ofdm = ¶ms->u.ofdm; - struct avc_command_frame *c = (void *)fdtv->avc_data; - - c->opcode = AVC_OPCODE_DSD; - - c->operand[0] = 0; /* source plug */ - c->operand[1] = 0xd2; /* subfunction replace */ - c->operand[2] = 0x20; /* system id = DVB */ - c->operand[3] = 0x00; /* antenna number */ - c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */ - - /* multiplex_valid_flags, high byte */ - c->operand[5] = - 0 << 7 /* reserved */ - | 1 << 6 /* CenterFrequency */ - | (ofdm->bandwidth != BANDWIDTH_AUTO ? 1 << 5 : 0) - | (ofdm->constellation != QAM_AUTO ? 1 << 4 : 0) - | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0) - | (ofdm->code_rate_HP != FEC_AUTO ? 1 << 2 : 0) - | (ofdm->code_rate_LP != FEC_AUTO ? 1 << 1 : 0) - | (ofdm->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0); - - /* multiplex_valid_flags, low byte */ - c->operand[6] = - 0 << 7 /* NetworkID */ - | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0) - | 0 << 5 /* OtherFrequencyFlag */ - | 0 << 0 /* reserved */ ; - - c->operand[7] = 0x0; - c->operand[8] = (params->frequency / 10) >> 24; - c->operand[9] = ((params->frequency / 10) >> 16) & 0xff; - c->operand[10] = ((params->frequency / 10) >> 8) & 0xff; - c->operand[11] = (params->frequency / 10) & 0xff; - - switch (ofdm->bandwidth) { - case BANDWIDTH_7_MHZ: c->operand[12] = 0x20; break; - case BANDWIDTH_8_MHZ: - case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ - case BANDWIDTH_AUTO: - default: c->operand[12] = 0x00; - } - - switch (ofdm->constellation) { - case QAM_16: c->operand[13] = 1 << 6; break; - case QAM_64: c->operand[13] = 2 << 6; break; - case QPSK: - default: c->operand[13] = 0x00; - } - - switch (ofdm->hierarchy_information) { - case HIERARCHY_1: c->operand[13] |= 1 << 3; break; - case HIERARCHY_2: c->operand[13] |= 2 << 3; break; - case HIERARCHY_4: c->operand[13] |= 3 << 3; break; - case HIERARCHY_AUTO: - case HIERARCHY_NONE: - default: break; - } - - switch (ofdm->code_rate_HP) { - case FEC_2_3: c->operand[13] |= 1; break; - case FEC_3_4: c->operand[13] |= 2; break; - case FEC_5_6: c->operand[13] |= 3; break; - case FEC_7_8: c->operand[13] |= 4; break; - case FEC_1_2: - default: break; - } - - switch (ofdm->code_rate_LP) { - case FEC_2_3: c->operand[14] = 1 << 5; break; - case FEC_3_4: c->operand[14] = 2 << 5; break; - case FEC_5_6: c->operand[14] = 3 << 5; break; - case FEC_7_8: c->operand[14] = 4 << 5; break; - case FEC_1_2: - default: c->operand[14] = 0x00; break; - } - - switch (ofdm->guard_interval) { - case GUARD_INTERVAL_1_16: c->operand[14] |= 1 << 3; break; - case GUARD_INTERVAL_1_8: c->operand[14] |= 2 << 3; break; - case GUARD_INTERVAL_1_4: c->operand[14] |= 3 << 3; break; - case GUARD_INTERVAL_1_32: - case GUARD_INTERVAL_AUTO: - default: break; - } - - switch (ofdm->transmission_mode) { - case TRANSMISSION_MODE_8K: c->operand[14] |= 1 << 1; break; - case TRANSMISSION_MODE_2K: - case TRANSMISSION_MODE_AUTO: - default: break; - } - - c->operand[15] = 0x00; /* network_ID[0] */ - c->operand[16] = 0x00; /* network_ID[1] */ - - return 17 + add_pid_filter(fdtv, &c->operand[17]); -} - -int avc_tuner_dsd(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - int pos, ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_CONTROL; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - - switch (fdtv->type) { - case FIREDTV_DVB_S: - case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break; - case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break; - case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break; - default: - BUG(); - } - pad_operands(c, pos); - - fdtv->avc_data_length = ALIGN(3 + pos, 4); - ret = avc_write(fdtv); -#if 0 - /* - * FIXME: - * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller. - * Check for AVC_RESPONSE_ACCEPTED here instead? - */ - if (status) - *status = r->operand[2]; -#endif - mutex_unlock(&fdtv->avc_mutex); - - if (ret == 0) - msleep(500); - - return ret; -} - -int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - int ret, pos, k; - - if (pidc > 16 && pidc != 0xff) - return -EINVAL; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_CONTROL; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_DSD; - - c->operand[0] = 0; /* source plug */ - c->operand[1] = 0xd2; /* subfunction replace */ - c->operand[2] = 0x20; /* system id = DVB */ - c->operand[3] = 0x00; /* antenna number */ - c->operand[4] = 0x00; /* system_specific_multiplex selection_length */ - c->operand[5] = pidc; /* Nr_of_dsd_sel_specs */ - - pos = 6; - if (pidc != 0xff) - for (k = 0; k < pidc; k++) { - c->operand[pos++] = 0x13; /* flowfunction relay */ - c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */ - c->operand[pos++] = (pid[k] >> 8) & 0x1f; - c->operand[pos++] = pid[k] & 0xff; - c->operand[pos++] = 0x00; /* tableID */ - c->operand[pos++] = 0x00; /* filter_length */ - } - pad_operands(c, pos); - - fdtv->avc_data_length = ALIGN(3 + pos, 4); - ret = avc_write(fdtv); - - /* FIXME: check response code? */ - - mutex_unlock(&fdtv->avc_mutex); - - if (ret == 0) - msleep(50); - - return ret; -} - -int avc_tuner_get_ts(struct firedtv *fdtv) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - int ret, sl; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_CONTROL; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_DSIT; - - sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11; - - c->operand[0] = 0; /* source plug */ - c->operand[1] = 0xd2; /* subfunction replace */ - c->operand[2] = 0xff; /* status */ - c->operand[3] = 0x20; /* system id = DVB */ - c->operand[4] = 0x00; /* antenna number */ - c->operand[5] = 0x0; /* system_specific_search_flags */ - c->operand[6] = sl; /* system_specific_multiplex selection_length */ - /* - * operand[7]: valid_flags[0] - * operand[8]: valid_flags[1] - * operand[7 + sl]: nr_of_dsit_sel_specs (always 0) - */ - clear_operands(c, 7, 24); - - fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28; - ret = avc_write(fdtv); - - /* FIXME: check response code? */ - - mutex_unlock(&fdtv->avc_mutex); - - if (ret == 0) - msleep(250); - - return ret; -} - -int avc_identify_subunit(struct firedtv *fdtv) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - struct avc_response_frame *r = (void *)fdtv->avc_data; - int ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_CONTROL; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_READ_DESCRIPTOR; - - c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER; - c->operand[1] = 0xff; - c->operand[2] = 0x00; - c->operand[3] = 0x00; /* length highbyte */ - c->operand[4] = 0x08; /* length lowbyte */ - c->operand[5] = 0x00; /* offset highbyte */ - c->operand[6] = 0x0d; /* offset lowbyte */ - clear_operands(c, 7, 8); /* padding */ - - fdtv->avc_data_length = 12; - ret = avc_write(fdtv); - if (ret < 0) - goto out; - - if ((r->response != AVC_RESPONSE_STABLE && - r->response != AVC_RESPONSE_ACCEPTED) || - (r->operand[3] << 8) + r->operand[4] != 8) { - dev_err(fdtv->device, "cannot read subunit identifier\n"); - ret = -EINVAL; - } -out: - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -#define SIZEOF_ANTENNA_INPUT_INFO 22 - -int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - struct avc_response_frame *r = (void *)fdtv->avc_data; - int length, ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_CONTROL; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_READ_DESCRIPTOR; - - c->operand[0] = DESCRIPTOR_TUNER_STATUS; - c->operand[1] = 0xff; /* read_result_status */ - /* - * operand[2]: reserved - * operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8 - * operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff - */ - clear_operands(c, 2, 31); - - fdtv->avc_data_length = 12; - ret = avc_write(fdtv); - if (ret < 0) - goto out; - - if (r->response != AVC_RESPONSE_STABLE && - r->response != AVC_RESPONSE_ACCEPTED) { - dev_err(fdtv->device, "cannot read tuner status\n"); - ret = -EINVAL; - goto out; - } - - length = r->operand[9]; - if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) { - dev_err(fdtv->device, "got invalid tuner status\n"); - ret = -EINVAL; - goto out; - } - - stat->active_system = r->operand[10]; - stat->searching = r->operand[11] >> 7 & 1; - stat->moving = r->operand[11] >> 6 & 1; - stat->no_rf = r->operand[11] >> 5 & 1; - stat->input = r->operand[12] >> 7 & 1; - stat->selected_antenna = r->operand[12] & 0x7f; - stat->ber = r->operand[13] << 24 | - r->operand[14] << 16 | - r->operand[15] << 8 | - r->operand[16]; - stat->signal_strength = r->operand[17]; - stat->raster_frequency = r->operand[18] >> 6 & 2; - stat->rf_frequency = (r->operand[18] & 0x3f) << 16 | - r->operand[19] << 8 | - r->operand[20]; - stat->man_dep_info_length = r->operand[21]; - stat->front_end_error = r->operand[22] >> 4 & 1; - stat->antenna_error = r->operand[22] >> 3 & 1; - stat->front_end_power_status = r->operand[22] >> 1 & 1; - stat->power_supply = r->operand[22] & 1; - stat->carrier_noise_ratio = r->operand[23] << 8 | - r->operand[24]; - stat->power_supply_voltage = r->operand[27]; - stat->antenna_voltage = r->operand[28]; - stat->firewire_bus_voltage = r->operand[29]; - stat->ca_mmi = r->operand[30] & 1; - stat->ca_pmt_reply = r->operand[31] >> 7 & 1; - stat->ca_date_time_request = r->operand[31] >> 6 & 1; - stat->ca_application_info = r->operand[31] >> 5 & 1; - stat->ca_module_present_status = r->operand[31] >> 4 & 1; - stat->ca_dvb_flag = r->operand[31] >> 3 & 1; - stat->ca_error_flag = r->operand[31] >> 2 & 1; - stat->ca_initialization_status = r->operand[31] >> 1 & 1; -out: - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, - char conttone, char nrdiseq, - struct dvb_diseqc_master_cmd *diseqcmd) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - struct avc_response_frame *r = (void *)fdtv->avc_data; - int pos, j, k, ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_CONTROL; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL; - c->operand[4] = voltage; - c->operand[5] = nrdiseq; - - pos = 6; - for (j = 0; j < nrdiseq; j++) { - c->operand[pos++] = diseqcmd[j].msg_len; - - for (k = 0; k < diseqcmd[j].msg_len; k++) - c->operand[pos++] = diseqcmd[j].msg[k]; - } - c->operand[pos++] = burst; - c->operand[pos++] = conttone; - pad_operands(c, pos); - - fdtv->avc_data_length = ALIGN(3 + pos, 4); - ret = avc_write(fdtv); - if (ret < 0) - goto out; - - if (r->response != AVC_RESPONSE_ACCEPTED) { - dev_err(fdtv->device, "LNB control failed\n"); - ret = -EINVAL; - } -out: - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -int avc_register_remote_control(struct firedtv *fdtv) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - int ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_NOTIFY; - c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7; - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; - c->operand[4] = 0; /* padding */ - - fdtv->avc_data_length = 8; - ret = avc_write(fdtv); - - /* FIXME: check response code? */ - - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -void avc_remote_ctrl_work(struct work_struct *work) -{ - struct firedtv *fdtv = - container_of(work, struct firedtv, remote_ctrl_work); - - /* Should it be rescheduled in failure cases? */ - avc_register_remote_control(fdtv); -} - -#if 0 /* FIXME: unused */ -int avc_tuner_host2ca(struct firedtv *fdtv) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - int ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_CONTROL; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; - c->operand[4] = 0; /* slot */ - c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ - clear_operands(c, 6, 8); - - fdtv->avc_data_length = 12; - ret = avc_write(fdtv); - - /* FIXME: check response code? */ - - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} -#endif - -static int get_ca_object_pos(struct avc_response_frame *r) -{ - int length = 1; - - /* Check length of length field */ - if (r->operand[7] & 0x80) - length = (r->operand[7] & 0x7f) + 1; - return length + 7; -} - -static int get_ca_object_length(struct avc_response_frame *r) -{ -#if 0 /* FIXME: unused */ - int size = 0; - int i; - - if (r->operand[7] & 0x80) - for (i = 0; i < (r->operand[7] & 0x7f); i++) { - size <<= 8; - size += r->operand[8 + i]; - } -#endif - return r->operand[7]; -} - -int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - struct avc_response_frame *r = (void *)fdtv->avc_data; - int pos, ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_STATUS; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; - c->operand[4] = 0; /* slot */ - c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ - clear_operands(c, 6, LAST_OPERAND); - - fdtv->avc_data_length = 12; - ret = avc_write(fdtv); - if (ret < 0) - goto out; - - /* FIXME: check response code and validate response data */ - - pos = get_ca_object_pos(r); - app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff; - app_info[1] = (EN50221_TAG_APP_INFO >> 8) & 0xff; - app_info[2] = (EN50221_TAG_APP_INFO >> 0) & 0xff; - app_info[3] = 6 + r->operand[pos + 4]; - app_info[4] = 0x01; - memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]); - *len = app_info[3] + 4; -out: - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - struct avc_response_frame *r = (void *)fdtv->avc_data; - int i, pos, ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_STATUS; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; - c->operand[4] = 0; /* slot */ - c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ - clear_operands(c, 6, LAST_OPERAND); - - fdtv->avc_data_length = 12; - ret = avc_write(fdtv); - if (ret < 0) - goto out; - - /* FIXME: check response code and validate response data */ - - pos = get_ca_object_pos(r); - app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff; - app_info[1] = (EN50221_TAG_CA_INFO >> 8) & 0xff; - app_info[2] = (EN50221_TAG_CA_INFO >> 0) & 0xff; - if (num_fake_ca_system_ids == 0) { - app_info[3] = 2; - app_info[4] = r->operand[pos + 0]; - app_info[5] = r->operand[pos + 1]; - } else { - app_info[3] = num_fake_ca_system_ids * 2; - for (i = 0; i < num_fake_ca_system_ids; i++) { - app_info[4 + i * 2] = - (fake_ca_system_ids[i] >> 8) & 0xff; - app_info[5 + i * 2] = fake_ca_system_ids[i] & 0xff; - } - } - *len = app_info[3] + 4; -out: - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -int avc_ca_reset(struct firedtv *fdtv) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - int ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_CONTROL; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; - c->operand[4] = 0; /* slot */ - c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */ - c->operand[6] = 0; /* more/last */ - c->operand[7] = 1; /* length */ - c->operand[8] = 0; /* force hardware reset */ - - fdtv->avc_data_length = 12; - ret = avc_write(fdtv); - - /* FIXME: check response code? */ - - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - struct avc_response_frame *r = (void *)fdtv->avc_data; - int list_management; - int program_info_length; - int pmt_cmd_id; - int read_pos; - int write_pos; - int es_info_length; - int crc32_csum; - int ret; - - if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT)) - debug_pmt(msg, length); - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_CONTROL; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_VENDOR; - - if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) { - dev_info(fdtv->device, "forcing list_management to ONLY\n"); - msg[0] = EN50221_LIST_MANAGEMENT_ONLY; - } - /* We take the cmd_id from the programme level only! */ - list_management = msg[0]; - program_info_length = ((msg[4] & 0x0f) << 8) + msg[5]; - if (program_info_length > 0) - program_info_length--; /* Remove pmt_cmd_id */ - pmt_cmd_id = msg[6]; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; - c->operand[4] = 0; /* slot */ - c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */ - c->operand[6] = 0; /* more/last */ - /* Use three bytes for length field in case length > 127 */ - c->operand[10] = list_management; - c->operand[11] = 0x01; /* pmt_cmd=OK_descramble */ - - /* TS program map table */ - - c->operand[12] = 0x02; /* Table id=2 */ - c->operand[13] = 0x80; /* Section syntax + length */ - - c->operand[15] = msg[1]; /* Program number */ - c->operand[16] = msg[2]; - c->operand[17] = msg[3]; /* Version number and current/next */ - c->operand[18] = 0x00; /* Section number=0 */ - c->operand[19] = 0x00; /* Last section number=0 */ - c->operand[20] = 0x1f; /* PCR_PID=1FFF */ - c->operand[21] = 0xff; - c->operand[22] = (program_info_length >> 8); /* Program info length */ - c->operand[23] = (program_info_length & 0xff); - - /* CA descriptors at programme level */ - read_pos = 6; - write_pos = 24; - if (program_info_length > 0) { - pmt_cmd_id = msg[read_pos++]; - if (pmt_cmd_id != 1 && pmt_cmd_id != 4) - dev_err(fdtv->device, - "invalid pmt_cmd_id %d\n", pmt_cmd_id); - - memcpy(&c->operand[write_pos], &msg[read_pos], - program_info_length); - read_pos += program_info_length; - write_pos += program_info_length; - } - while (read_pos < length) { - c->operand[write_pos++] = msg[read_pos++]; - c->operand[write_pos++] = msg[read_pos++]; - c->operand[write_pos++] = msg[read_pos++]; - es_info_length = - ((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1]; - read_pos += 2; - if (es_info_length > 0) - es_info_length--; /* Remove pmt_cmd_id */ - c->operand[write_pos++] = es_info_length >> 8; - c->operand[write_pos++] = es_info_length & 0xff; - if (es_info_length > 0) { - pmt_cmd_id = msg[read_pos++]; - if (pmt_cmd_id != 1 && pmt_cmd_id != 4) - dev_err(fdtv->device, "invalid pmt_cmd_id %d " - "at stream level\n", pmt_cmd_id); - - memcpy(&c->operand[write_pos], &msg[read_pos], - es_info_length); - read_pos += es_info_length; - write_pos += es_info_length; - } - } - write_pos += 4; /* CRC */ - - c->operand[7] = 0x82; - c->operand[8] = (write_pos - 10) >> 8; - c->operand[9] = (write_pos - 10) & 0xff; - c->operand[14] = write_pos - 15; - - crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1); - c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff; - c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff; - c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff; - c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff; - pad_operands(c, write_pos); - - fdtv->avc_data_length = ALIGN(3 + write_pos, 4); - ret = avc_write(fdtv); - if (ret < 0) - goto out; - - if (r->response != AVC_RESPONSE_ACCEPTED) { - dev_err(fdtv->device, - "CA PMT failed with response 0x%x\n", r->response); - ret = -EFAULT; - } -out: - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -int avc_ca_get_time_date(struct firedtv *fdtv, int *interval) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - struct avc_response_frame *r = (void *)fdtv->avc_data; - int ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_STATUS; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; - c->operand[4] = 0; /* slot */ - c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */ - clear_operands(c, 6, LAST_OPERAND); - - fdtv->avc_data_length = 12; - ret = avc_write(fdtv); - if (ret < 0) - goto out; - - /* FIXME: check response code and validate response data */ - - *interval = r->operand[get_ca_object_pos(r)]; -out: - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -int avc_ca_enter_menu(struct firedtv *fdtv) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - int ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_STATUS; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; - c->operand[4] = 0; /* slot */ - c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; - clear_operands(c, 6, 8); - - fdtv->avc_data_length = 12; - ret = avc_write(fdtv); - - /* FIXME: check response code? */ - - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len) -{ - struct avc_command_frame *c = (void *)fdtv->avc_data; - struct avc_response_frame *r = (void *)fdtv->avc_data; - int ret; - - mutex_lock(&fdtv->avc_mutex); - - c->ctype = AVC_CTYPE_STATUS; - c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; - c->opcode = AVC_OPCODE_VENDOR; - - c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; - c->operand[4] = 0; /* slot */ - c->operand[5] = SFE_VENDOR_TAG_CA_MMI; - clear_operands(c, 6, LAST_OPERAND); - - fdtv->avc_data_length = 12; - ret = avc_write(fdtv); - if (ret < 0) - goto out; - - /* FIXME: check response code and validate response data */ - - *len = get_ca_object_length(r); - memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len); -out: - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL - -static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data) -{ - int ret; - - mutex_lock(&fdtv->avc_mutex); - - ret = fdtv_read(fdtv, addr, data); - if (ret < 0) - dev_err(fdtv->device, "CMP: read I/O error\n"); - - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[]) -{ - int ret; - - mutex_lock(&fdtv->avc_mutex); - - /* data[] is stack-allocated and should not be DMA-mapped. */ - memcpy(fdtv->avc_data, data, 8); - - ret = fdtv_lock(fdtv, addr, fdtv->avc_data); - if (ret < 0) - dev_err(fdtv->device, "CMP: lock I/O error\n"); - else - memcpy(data, fdtv->avc_data, 8); - - mutex_unlock(&fdtv->avc_mutex); - - return ret; -} - -static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift) -{ - return (be32_to_cpu(opcr) >> shift) & mask; -} - -static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift) -{ - *opcr &= ~cpu_to_be32(mask << shift); - *opcr |= cpu_to_be32((value & mask) << shift); -} - -#define get_opcr_online(v) get_opcr((v), 0x1, 31) -#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24) -#define get_opcr_channel(v) get_opcr((v), 0x3f, 16) - -#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24) -#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16) -#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14) -#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10) - -int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel) -{ - __be32 old_opcr, opcr[2]; - u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); - int attempts = 0; - int ret; - - ret = cmp_read(fdtv, opcr_address, opcr); - if (ret < 0) - return ret; - -repeat: - if (!get_opcr_online(*opcr)) { - dev_err(fdtv->device, "CMP: output offline\n"); - return -EBUSY; - } - - old_opcr = *opcr; - - if (get_opcr_p2p_connections(*opcr)) { - if (get_opcr_channel(*opcr) != channel) { - dev_err(fdtv->device, "CMP: cannot change channel\n"); - return -EBUSY; - } - dev_info(fdtv->device, "CMP: overlaying connection\n"); - - /* We don't allocate isochronous resources. */ - } else { - set_opcr_channel(opcr, channel); - set_opcr_data_rate(opcr, 2); /* S400 */ - - /* FIXME: this is for the worst case - optimize */ - set_opcr_overhead_id(opcr, 0); - - /* FIXME: allocate isochronous channel and bandwidth at IRM */ - } - - set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1); - - opcr[1] = *opcr; - opcr[0] = old_opcr; - - ret = cmp_lock(fdtv, opcr_address, opcr); - if (ret < 0) - return ret; - - if (old_opcr != *opcr) { - /* - * FIXME: if old_opcr.P2P_Connections > 0, - * deallocate isochronous channel and bandwidth at IRM - */ - - if (++attempts < 6) /* arbitrary limit */ - goto repeat; - return -EBUSY; - } - - return 0; -} - -void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel) -{ - __be32 old_opcr, opcr[2]; - u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); - int attempts = 0; - - if (cmp_read(fdtv, opcr_address, opcr) < 0) - return; - -repeat: - if (!get_opcr_online(*opcr) || !get_opcr_p2p_connections(*opcr) || - get_opcr_channel(*opcr) != channel) { - dev_err(fdtv->device, "CMP: no connection to break\n"); - return; - } - - old_opcr = *opcr; - set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) - 1); - - opcr[1] = *opcr; - opcr[0] = old_opcr; - - if (cmp_lock(fdtv, opcr_address, opcr) < 0) - return; - - if (old_opcr != *opcr) { - /* - * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last - * owner, deallocate isochronous channel and bandwidth at IRM - * if (...) - * fdtv->backend->dealloc_resources(fdtv, channel, bw); - */ - - if (++attempts < 6) /* arbitrary limit */ - goto repeat; - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-ci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-ci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-ci.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-ci.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,260 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include - -#include "firedtv.h" - -#define EN50221_TAG_APP_INFO_ENQUIRY 0x9f8020 -#define EN50221_TAG_CA_INFO_ENQUIRY 0x9f8030 -#define EN50221_TAG_CA_PMT 0x9f8032 -#define EN50221_TAG_ENTER_MENU 0x9f8022 - -static int fdtv_ca_ready(struct firedtv_tuner_status *stat) -{ - return stat->ca_initialization_status == 1 && - stat->ca_error_flag == 0 && - stat->ca_dvb_flag == 1 && - stat->ca_module_present_status == 1; -} - -static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat) -{ - int flags = 0; - - if (stat->ca_module_present_status == 1) - flags |= CA_CI_MODULE_PRESENT; - if (stat->ca_initialization_status == 1 && - stat->ca_error_flag == 0 && - stat->ca_dvb_flag == 1) - flags |= CA_CI_MODULE_READY; - return flags; -} - -static int fdtv_ca_reset(struct firedtv *fdtv) -{ - return avc_ca_reset(fdtv) ? -EFAULT : 0; -} - -static int fdtv_ca_get_caps(void *arg) -{ - struct ca_caps *cap = arg; - - cap->slot_num = 1; - cap->slot_type = CA_CI; - cap->descr_num = 1; - cap->descr_type = CA_ECD; - return 0; -} - -static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg) -{ - struct firedtv_tuner_status stat; - struct ca_slot_info *slot = arg; - - if (avc_tuner_status(fdtv, &stat)) - return -EFAULT; - - if (slot->num != 0) - return -EFAULT; - - slot->type = CA_CI; - slot->flags = fdtv_get_ca_flags(&stat); - return 0; -} - -static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg) -{ - struct ca_msg *reply = arg; - - return avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; -} - -static int fdtv_ca_info(struct firedtv *fdtv, void *arg) -{ - struct ca_msg *reply = arg; - - return avc_ca_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; -} - -static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg) -{ - struct ca_msg *reply = arg; - - return avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; -} - -static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg) -{ - struct firedtv_tuner_status stat; - int err; - - switch (fdtv->ca_last_command) { - case EN50221_TAG_APP_INFO_ENQUIRY: - err = fdtv_ca_app_info(fdtv, arg); - break; - case EN50221_TAG_CA_INFO_ENQUIRY: - err = fdtv_ca_info(fdtv, arg); - break; - default: - if (avc_tuner_status(fdtv, &stat)) - err = -EFAULT; - else if (stat.ca_mmi == 1) - err = fdtv_ca_get_mmi(fdtv, arg); - else { - dev_info(fdtv->device, "unhandled CA message 0x%08x\n", - fdtv->ca_last_command); - err = -EFAULT; - } - } - fdtv->ca_last_command = 0; - return err; -} - -static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg) -{ - struct ca_msg *msg = arg; - int data_pos; - int data_length; - int i; - - data_pos = 4; - if (msg->msg[3] & 0x80) { - data_length = 0; - for (i = 0; i < (msg->msg[3] & 0x7f); i++) - data_length = (data_length << 8) + msg->msg[data_pos++]; - } else { - data_length = msg->msg[3]; - } - - return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? -EFAULT : 0; -} - -static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg) -{ - struct ca_msg *msg = arg; - int err; - - /* Do we need a semaphore for this? */ - fdtv->ca_last_command = - (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2]; - switch (fdtv->ca_last_command) { - case EN50221_TAG_CA_PMT: - err = fdtv_ca_pmt(fdtv, arg); - break; - case EN50221_TAG_APP_INFO_ENQUIRY: - /* handled in ca_get_msg */ - err = 0; - break; - case EN50221_TAG_CA_INFO_ENQUIRY: - /* handled in ca_get_msg */ - err = 0; - break; - case EN50221_TAG_ENTER_MENU: - err = avc_ca_enter_menu(fdtv); - break; - default: - dev_err(fdtv->device, "unhandled CA message 0x%08x\n", - fdtv->ca_last_command); - err = -EFAULT; - } - return err; -} - -static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg) -{ - struct dvb_device *dvbdev = file->private_data; - struct firedtv *fdtv = dvbdev->priv; - struct firedtv_tuner_status stat; - int err; - - switch (cmd) { - case CA_RESET: - err = fdtv_ca_reset(fdtv); - break; - case CA_GET_CAP: - err = fdtv_ca_get_caps(arg); - break; - case CA_GET_SLOT_INFO: - err = fdtv_ca_get_slot_info(fdtv, arg); - break; - case CA_GET_MSG: - err = fdtv_ca_get_msg(fdtv, arg); - break; - case CA_SEND_MSG: - err = fdtv_ca_send_msg(fdtv, arg); - break; - default: - dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd); - err = -EOPNOTSUPP; - } - - /* FIXME Is this necessary? */ - avc_tuner_status(fdtv, &stat); - - return err; -} - -static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait) -{ - return POLLIN; -} - -static const struct file_operations fdtv_ca_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = dvb_generic_ioctl, - .open = dvb_generic_open, - .release = dvb_generic_release, - .poll = fdtv_ca_io_poll, - .llseek = noop_llseek, -}; - -static struct dvb_device fdtv_ca = { - .users = 1, - .readers = 1, - .writers = 1, - .fops = &fdtv_ca_fops, - .kernel_ioctl = fdtv_ca_ioctl, -}; - -int fdtv_ca_register(struct firedtv *fdtv) -{ - struct firedtv_tuner_status stat; - int err; - - if (avc_tuner_status(fdtv, &stat)) - return -EINVAL; - - if (!fdtv_ca_ready(&stat)) - return -EFAULT; - - err = dvb_register_device(&fdtv->adapter, &fdtv->cadev, - &fdtv_ca, fdtv, DVB_DEVICE_CA); - - if (stat.ca_application_info == 0) - dev_err(fdtv->device, "CaApplicationInfo is not set\n"); - if (stat.ca_date_time_request == 1) - avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval); - - return err; -} - -void fdtv_ca_release(struct firedtv *fdtv) -{ - if (fdtv->cadev) - dvb_unregister_device(fdtv->cadev); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-dvb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "firedtv.h" - -static int alloc_channel(struct firedtv *fdtv) -{ - int i; - - for (i = 0; i < 16; i++) - if (!__test_and_set_bit(i, &fdtv->channel_active)) - break; - return i; -} - -static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[]) -{ - int i, n; - - for (i = 0, n = 0; i < 16; i++) - if (test_bit(i, &fdtv->channel_active)) - pid[n++] = fdtv->channel_pid[i]; - *pidc = n; -} - -static inline void dealloc_channel(struct firedtv *fdtv, int i) -{ - __clear_bit(i, &fdtv->channel_active); -} - -int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct firedtv *fdtv = dvbdmxfeed->demux->priv; - int pidc, c, ret; - u16 pids[16]; - - switch (dvbdmxfeed->type) { - case DMX_TYPE_TS: - case DMX_TYPE_SEC: - break; - default: - dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n", - dvbdmxfeed->type); - return -EINVAL; - } - - if (mutex_lock_interruptible(&fdtv->demux_mutex)) - return -EINTR; - - if (dvbdmxfeed->type == DMX_TYPE_TS) { - switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - case DMX_TS_PES_AUDIO: - case DMX_TS_PES_TELETEXT: - case DMX_TS_PES_PCR: - case DMX_TS_PES_OTHER: - c = alloc_channel(fdtv); - break; - default: - dev_err(fdtv->device, - "can't start dmx feed: invalid pes type %u\n", - dvbdmxfeed->pes_type); - ret = -EINVAL; - goto out; - } - } else { - c = alloc_channel(fdtv); - } - - if (c > 15) { - dev_err(fdtv->device, "can't start dmx feed: busy\n"); - ret = -EBUSY; - goto out; - } - - dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c; - fdtv->channel_pid[c] = dvbdmxfeed->pid; - collect_channels(fdtv, &pidc, pids); - - if (dvbdmxfeed->pid == 8192) { - ret = avc_tuner_get_ts(fdtv); - if (ret) { - dealloc_channel(fdtv, c); - dev_err(fdtv->device, "can't get TS\n"); - goto out; - } - } else { - ret = avc_tuner_set_pids(fdtv, pidc, pids); - if (ret) { - dealloc_channel(fdtv, c); - dev_err(fdtv->device, "can't set PIDs\n"); - goto out; - } - } -out: - mutex_unlock(&fdtv->demux_mutex); - - return ret; -} - -int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *demux = dvbdmxfeed->demux; - struct firedtv *fdtv = demux->priv; - int pidc, c, ret; - u16 pids[16]; - - if (dvbdmxfeed->type == DMX_TYPE_TS && - !((dvbdmxfeed->ts_type & TS_PACKET) && - (demux->dmx.frontend->source != DMX_MEMORY_FE))) { - - if (dvbdmxfeed->ts_type & TS_DECODER) { - if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || - !demux->pesfilter[dvbdmxfeed->pes_type]) - return -EINVAL; - - demux->pids[dvbdmxfeed->pes_type] |= 0x8000; - demux->pesfilter[dvbdmxfeed->pes_type] = NULL; - } - - if (!(dvbdmxfeed->ts_type & TS_DECODER && - dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) - return 0; - } - - if (mutex_lock_interruptible(&fdtv->demux_mutex)) - return -EINTR; - - c = (unsigned long)dvbdmxfeed->priv; - dealloc_channel(fdtv, c); - collect_channels(fdtv, &pidc, pids); - - ret = avc_tuner_set_pids(fdtv, pidc, pids); - - mutex_unlock(&fdtv->demux_mutex); - - return ret; -} - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -int fdtv_dvb_register(struct firedtv *fdtv, const char *name) -{ - int err; - - err = dvb_register_adapter(&fdtv->adapter, name, - THIS_MODULE, fdtv->device, adapter_nr); - if (err < 0) - goto fail_log; - - /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/ - fdtv->demux.dmx.capabilities = 0; - - fdtv->demux.priv = fdtv; - fdtv->demux.filternum = 16; - fdtv->demux.feednum = 16; - fdtv->demux.start_feed = fdtv_start_feed; - fdtv->demux.stop_feed = fdtv_stop_feed; - fdtv->demux.write_to_decoder = NULL; - - err = dvb_dmx_init(&fdtv->demux); - if (err) - goto fail_unreg_adapter; - - fdtv->dmxdev.filternum = 16; - fdtv->dmxdev.demux = &fdtv->demux.dmx; - fdtv->dmxdev.capabilities = 0; - - err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter); - if (err) - goto fail_dmx_release; - - fdtv->frontend.source = DMX_FRONTEND_0; - - err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend); - if (err) - goto fail_dmxdev_release; - - err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx, - &fdtv->frontend); - if (err) - goto fail_rem_frontend; - - dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); - - fdtv_frontend_init(fdtv, name); - err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe); - if (err) - goto fail_net_release; - - err = fdtv_ca_register(fdtv); - if (err) - dev_info(fdtv->device, - "Conditional Access Module not enabled\n"); - return 0; - -fail_net_release: - dvb_net_release(&fdtv->dvbnet); - fdtv->demux.dmx.close(&fdtv->demux.dmx); -fail_rem_frontend: - fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); -fail_dmxdev_release: - dvb_dmxdev_release(&fdtv->dmxdev); -fail_dmx_release: - dvb_dmx_release(&fdtv->demux); -fail_unreg_adapter: - dvb_unregister_adapter(&fdtv->adapter); -fail_log: - dev_err(fdtv->device, "DVB initialization failed\n"); - return err; -} - -void fdtv_dvb_unregister(struct firedtv *fdtv) -{ - fdtv_ca_release(fdtv); - dvb_unregister_frontend(&fdtv->fe); - dvb_net_release(&fdtv->dvbnet); - fdtv->demux.dmx.close(&fdtv->demux.dmx); - fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); - dvb_dmxdev_release(&fdtv->dmxdev); - dvb_dmx_release(&fdtv->demux); - dvb_unregister_adapter(&fdtv->adapter); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-fe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,273 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include - -#include - -#include "firedtv.h" - -static int fdtv_dvb_init(struct dvb_frontend *fe) -{ - struct firedtv *fdtv = fe->sec_priv; - int err; - - /* FIXME - allocate free channel at IRM */ - fdtv->isochannel = fdtv->adapter.num; - - err = cmp_establish_pp_connection(fdtv, fdtv->subunit, - fdtv->isochannel); - if (err) { - dev_err(fdtv->device, - "could not establish point to point connection\n"); - return err; - } - - return fdtv_start_iso(fdtv); -} - -static int fdtv_sleep(struct dvb_frontend *fe) -{ - struct firedtv *fdtv = fe->sec_priv; - - fdtv_stop_iso(fdtv); - cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel); - fdtv->isochannel = -1; - return 0; -} - -#define LNBCONTROL_DONTCARE 0xff - -static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *cmd) -{ - struct firedtv *fdtv = fe->sec_priv; - - return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, - LNBCONTROL_DONTCARE, 1, cmd); -} - -static int fdtv_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t minicmd) -{ - return 0; -} - -static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct firedtv *fdtv = fe->sec_priv; - - fdtv->tone = tone; - return 0; -} - -static int fdtv_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct firedtv *fdtv = fe->sec_priv; - - fdtv->voltage = voltage; - return 0; -} - -static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct firedtv *fdtv = fe->sec_priv; - struct firedtv_tuner_status stat; - - if (avc_tuner_status(fdtv, &stat)) - return -EINVAL; - - if (stat.no_rf) - *status = 0; - else - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_CARRIER | FE_HAS_LOCK; - return 0; -} - -static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct firedtv *fdtv = fe->sec_priv; - struct firedtv_tuner_status stat; - - if (avc_tuner_status(fdtv, &stat)) - return -EINVAL; - - *ber = stat.ber; - return 0; -} - -static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct firedtv *fdtv = fe->sec_priv; - struct firedtv_tuner_status stat; - - if (avc_tuner_status(fdtv, &stat)) - return -EINVAL; - - *strength = stat.signal_strength << 8; - return 0; -} - -static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct firedtv *fdtv = fe->sec_priv; - struct firedtv_tuner_status stat; - - if (avc_tuner_status(fdtv, &stat)) - return -EINVAL; - - /* C/N[dB] = -10 * log10(snr / 65535) */ - *snr = stat.carrier_noise_ratio * 257; - return 0; -} - -static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - return -EOPNOTSUPP; -} - -static int fdtv_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct firedtv *fdtv = fe->sec_priv; - - return avc_tuner_dsd(fdtv, params); -} - -static int fdtv_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - return -EOPNOTSUPP; -} - -static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp) -{ - return 0; -} - -static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp) -{ - return 0; -} - -void fdtv_frontend_init(struct firedtv *fdtv, const char *name) -{ - struct dvb_frontend_ops *ops = &fdtv->fe.ops; - struct dvb_frontend_info *fi = &ops->info; - - ops->init = fdtv_dvb_init; - ops->sleep = fdtv_sleep; - - ops->set_frontend = fdtv_set_frontend; - ops->get_frontend = fdtv_get_frontend; - - ops->get_property = fdtv_get_property; - ops->set_property = fdtv_set_property; - - ops->read_status = fdtv_read_status; - ops->read_ber = fdtv_read_ber; - ops->read_signal_strength = fdtv_read_signal_strength; - ops->read_snr = fdtv_read_snr; - ops->read_ucblocks = fdtv_read_uncorrected_blocks; - - ops->diseqc_send_master_cmd = fdtv_diseqc_send_master_cmd; - ops->diseqc_send_burst = fdtv_diseqc_send_burst; - ops->set_tone = fdtv_set_tone; - ops->set_voltage = fdtv_set_voltage; - - switch (fdtv->type) { - case FIREDTV_DVB_S: - fi->type = FE_QPSK; - - fi->frequency_min = 950000; - fi->frequency_max = 2150000; - fi->frequency_stepsize = 125; - fi->symbol_rate_min = 1000000; - fi->symbol_rate_max = 40000000; - - fi->caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | - FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK; - break; - - case FIREDTV_DVB_S2: - fi->type = FE_QPSK; - - fi->frequency_min = 950000; - fi->frequency_max = 2150000; - fi->frequency_stepsize = 125; - fi->symbol_rate_min = 1000000; - fi->symbol_rate_max = 40000000; - - fi->caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | - FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | - FE_CAN_2G_MODULATION; - break; - - case FIREDTV_DVB_C: - fi->type = FE_QAM; - - fi->frequency_min = 47000000; - fi->frequency_max = 866000000; - fi->frequency_stepsize = 62500; - fi->symbol_rate_min = 870000; - fi->symbol_rate_max = 6900000; - - fi->caps = FE_CAN_INVERSION_AUTO | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO; - break; - - case FIREDTV_DVB_T: - fi->type = FE_OFDM; - - fi->frequency_min = 49000000; - fi->frequency_max = 861000000; - fi->frequency_stepsize = 62500; - - fi->caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_2_3 | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO; - break; - - default: - dev_err(fdtv->device, "no frontend for model type %d\n", - fdtv->type); - } - strcpy(fi->name, name); - - fdtv->fe.dvb = &fdtv->adapter; - fdtv->fe.sec_priv = fdtv; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-fw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-fw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-fw.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-fw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,429 +0,0 @@ -/* - * FireDTV driver -- firewire I/O backend - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "firedtv.h" - -static LIST_HEAD(node_list); -static DEFINE_SPINLOCK(node_list_lock); - -static inline struct fw_device *device_of(struct firedtv *fdtv) -{ - return fw_device(fdtv->device->parent); -} - -static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len, - int tcode) -{ - struct fw_device *device = device_of(fdtv); - int rcode, generation = device->generation; - - smp_rmb(); /* node_id vs. generation */ - - rcode = fw_run_transaction(device->card, tcode, device->node_id, - generation, device->max_speed, addr, data, len); - - return rcode != RCODE_COMPLETE ? -EIO : 0; -} - -int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data) -{ - return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP); -} - -int fdtv_read(struct firedtv *fdtv, u64 addr, void *data) -{ - return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST); -} - -int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) -{ - return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST); -} - -#define ISO_HEADER_SIZE 4 -#define CIP_HEADER_SIZE 8 -#define MPEG2_TS_HEADER_SIZE 4 -#define MPEG2_TS_SOURCE_PACKET_SIZE (4 + 188) - -#define MAX_PACKET_SIZE 1024 /* 776, rounded up to 2^n */ -#define PACKETS_PER_PAGE (PAGE_SIZE / MAX_PACKET_SIZE) -#define N_PACKETS 64 /* buffer size */ -#define N_PAGES DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE) -#define IRQ_INTERVAL 16 - -struct fdtv_ir_context { - struct fw_iso_context *context; - struct fw_iso_buffer buffer; - int interrupt_packet; - int current_packet; - char *pages[N_PAGES]; -}; - -static int queue_iso(struct fdtv_ir_context *ctx, int index) -{ - struct fw_iso_packet p; - - p.payload_length = MAX_PACKET_SIZE; - p.interrupt = !(++ctx->interrupt_packet & (IRQ_INTERVAL - 1)); - p.skip = 0; - p.header_length = ISO_HEADER_SIZE; - - return fw_iso_context_queue(ctx->context, &p, &ctx->buffer, - index * MAX_PACKET_SIZE); -} - -static void handle_iso(struct fw_iso_context *context, u32 cycle, - size_t header_length, void *header, void *data) -{ - struct firedtv *fdtv = data; - struct fdtv_ir_context *ctx = fdtv->ir_context; - __be32 *h, *h_end; - int length, err, i = ctx->current_packet; - char *p, *p_end; - - for (h = header, h_end = h + header_length / 4; h < h_end; h++) { - length = be32_to_cpup(h) >> 16; - if (unlikely(length > MAX_PACKET_SIZE)) { - dev_err(fdtv->device, "length = %d\n", length); - length = MAX_PACKET_SIZE; - } - - p = ctx->pages[i / PACKETS_PER_PAGE] - + (i % PACKETS_PER_PAGE) * MAX_PACKET_SIZE; - p_end = p + length; - - for (p += CIP_HEADER_SIZE + MPEG2_TS_HEADER_SIZE; p < p_end; - p += MPEG2_TS_SOURCE_PACKET_SIZE) - dvb_dmx_swfilter_packets(&fdtv->demux, p, 1); - - err = queue_iso(ctx, i); - if (unlikely(err)) - dev_err(fdtv->device, "requeue failed\n"); - - i = (i + 1) & (N_PACKETS - 1); - } - ctx->current_packet = i; -} - -int fdtv_start_iso(struct firedtv *fdtv) -{ - struct fdtv_ir_context *ctx; - struct fw_device *device = device_of(fdtv); - int i, err; - - ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->context = fw_iso_context_create(device->card, - FW_ISO_CONTEXT_RECEIVE, fdtv->isochannel, - device->max_speed, ISO_HEADER_SIZE, handle_iso, fdtv); - if (IS_ERR(ctx->context)) { - err = PTR_ERR(ctx->context); - goto fail_free; - } - - err = fw_iso_buffer_init(&ctx->buffer, device->card, - N_PAGES, DMA_FROM_DEVICE); - if (err) - goto fail_context_destroy; - - ctx->interrupt_packet = 0; - ctx->current_packet = 0; - - for (i = 0; i < N_PAGES; i++) - ctx->pages[i] = page_address(ctx->buffer.pages[i]); - - for (i = 0; i < N_PACKETS; i++) { - err = queue_iso(ctx, i); - if (err) - goto fail; - } - - err = fw_iso_context_start(ctx->context, -1, 0, - FW_ISO_CONTEXT_MATCH_ALL_TAGS); - if (err) - goto fail; - - fdtv->ir_context = ctx; - - return 0; -fail: - fw_iso_buffer_destroy(&ctx->buffer, device->card); -fail_context_destroy: - fw_iso_context_destroy(ctx->context); -fail_free: - kfree(ctx); - - return err; -} - -void fdtv_stop_iso(struct firedtv *fdtv) -{ - struct fdtv_ir_context *ctx = fdtv->ir_context; - - fw_iso_context_stop(ctx->context); - fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card); - fw_iso_context_destroy(ctx->context); - kfree(ctx); -} - -static void handle_fcp(struct fw_card *card, struct fw_request *request, - int tcode, int destination, int source, int generation, - unsigned long long offset, void *payload, size_t length, - void *callback_data) -{ - struct firedtv *f, *fdtv = NULL; - struct fw_device *device; - unsigned long flags; - int su; - - if (length < 2 || (((u8 *)payload)[0] & 0xf0) != 0) - return; - - su = ((u8 *)payload)[1] & 0x7; - - spin_lock_irqsave(&node_list_lock, flags); - list_for_each_entry(f, &node_list, list) { - device = device_of(f); - if (device->generation != generation) - continue; - - smp_rmb(); /* node_id vs. generation */ - - if (device->card == card && - device->node_id == source && - (f->subunit == su || (f->subunit == 0 && su == 0x7))) { - fdtv = f; - break; - } - } - spin_unlock_irqrestore(&node_list_lock, flags); - - if (fdtv) - avc_recv(fdtv, payload, length); -} - -static struct fw_address_handler fcp_handler = { - .length = CSR_FCP_END - CSR_FCP_RESPONSE, - .address_callback = handle_fcp, -}; - -static const struct fw_address_region fcp_region = { - .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE, - .end = CSR_REGISTER_BASE + CSR_FCP_END, -}; - -static const char * const model_names[] = { - [FIREDTV_UNKNOWN] = "unknown type", - [FIREDTV_DVB_S] = "FireDTV S/CI", - [FIREDTV_DVB_C] = "FireDTV C/CI", - [FIREDTV_DVB_T] = "FireDTV T/CI", - [FIREDTV_DVB_S2] = "FireDTV S2 ", -}; - -/* Adjust the template string if models with longer names appear. */ -#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????") - -static int node_probe(struct device *dev) -{ - struct firedtv *fdtv; - char name[MAX_MODEL_NAME_LEN]; - int name_len, i, err; - - fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); - if (!fdtv) - return -ENOMEM; - - dev_set_drvdata(dev, fdtv); - fdtv->device = dev; - fdtv->isochannel = -1; - fdtv->voltage = 0xff; - fdtv->tone = 0xff; - - mutex_init(&fdtv->avc_mutex); - init_waitqueue_head(&fdtv->avc_wait); - mutex_init(&fdtv->demux_mutex); - INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); - - name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL, - name, sizeof(name)); - for (i = ARRAY_SIZE(model_names); --i; ) - if (strlen(model_names[i]) <= name_len && - strncmp(name, model_names[i], name_len) == 0) - break; - fdtv->type = i; - - err = fdtv_register_rc(fdtv, dev); - if (err) - goto fail_free; - - spin_lock_irq(&node_list_lock); - list_add_tail(&fdtv->list, &node_list); - spin_unlock_irq(&node_list_lock); - - err = avc_identify_subunit(fdtv); - if (err) - goto fail; - - err = fdtv_dvb_register(fdtv, model_names[fdtv->type]); - if (err) - goto fail; - - avc_register_remote_control(fdtv); - - return 0; -fail: - spin_lock_irq(&node_list_lock); - list_del(&fdtv->list); - spin_unlock_irq(&node_list_lock); - fdtv_unregister_rc(fdtv); -fail_free: - kfree(fdtv); - - return err; -} - -static int node_remove(struct device *dev) -{ - struct firedtv *fdtv = dev_get_drvdata(dev); - - fdtv_dvb_unregister(fdtv); - - spin_lock_irq(&node_list_lock); - list_del(&fdtv->list); - spin_unlock_irq(&node_list_lock); - - fdtv_unregister_rc(fdtv); - - kfree(fdtv); - return 0; -} - -static void node_update(struct fw_unit *unit) -{ - struct firedtv *fdtv = dev_get_drvdata(&unit->device); - - if (fdtv->isochannel >= 0) - cmp_establish_pp_connection(fdtv, fdtv->subunit, - fdtv->isochannel); -} - -#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ - IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION) - -#define DIGITAL_EVERYWHERE_OUI 0x001287 -#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d -#define AVC_SW_VERSION_ENTRY 0x010001 - -static const struct ieee1394_device_id fdtv_id_table[] = { - { - /* FloppyDTV S/CI and FloppyDTV S2 */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000024, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FloppyDTV T/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000025, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FloppyDTV C/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000026, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FireDTV S/CI and FloppyDTV S2 */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000034, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FireDTV T/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000035, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FireDTV C/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000036, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, {} -}; -MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); - -static struct fw_driver fdtv_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "firedtv", - .bus = &fw_bus_type, - .probe = node_probe, - .remove = node_remove, - }, - .update = node_update, - .id_table = fdtv_id_table, -}; - -static int __init fdtv_init(void) -{ - int ret; - - ret = fw_core_add_address_handler(&fcp_handler, &fcp_region); - if (ret < 0) - return ret; - - ret = driver_register(&fdtv_driver.driver); - if (ret < 0) - fw_core_remove_address_handler(&fcp_handler); - - return ret; -} - -static void __exit fdtv_exit(void) -{ - driver_unregister(&fdtv_driver.driver); - fw_core_remove_address_handler(&fcp_handler); -} - -module_init(fdtv_init); -module_exit(fdtv_exit); - -MODULE_AUTHOR("Andreas Monitzer "); -MODULE_AUTHOR("Ben Backx "); -MODULE_DESCRIPTION("FireDTV DVB Driver"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,168 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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, or (at your option) any later version. - */ - -#ifndef _FIREDTV_H -#define _FIREDTV_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -struct firedtv_tuner_status { - unsigned active_system:8; - unsigned searching:1; - unsigned moving:1; - unsigned no_rf:1; - unsigned input:1; - unsigned selected_antenna:7; - unsigned ber:32; - unsigned signal_strength:8; - unsigned raster_frequency:2; - unsigned rf_frequency:22; - unsigned man_dep_info_length:8; - unsigned front_end_error:1; - unsigned antenna_error:1; - unsigned front_end_power_status:1; - unsigned power_supply:1; - unsigned carrier_noise_ratio:16; - unsigned power_supply_voltage:8; - unsigned antenna_voltage:8; - unsigned firewire_bus_voltage:8; - unsigned ca_mmi:1; - unsigned ca_pmt_reply:1; - unsigned ca_date_time_request:1; - unsigned ca_application_info:1; - unsigned ca_module_present_status:1; - unsigned ca_dvb_flag:1; - unsigned ca_error_flag:1; - unsigned ca_initialization_status:1; -}; - -enum model_type { - FIREDTV_UNKNOWN = 0, - FIREDTV_DVB_S = 1, - FIREDTV_DVB_C = 2, - FIREDTV_DVB_T = 3, - FIREDTV_DVB_S2 = 4, -}; - -struct device; -struct input_dev; -struct fdtv_ir_context; - -struct firedtv { - struct device *device; - struct list_head list; - - struct dvb_adapter adapter; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dmx_frontend frontend; - struct dvb_net dvbnet; - struct dvb_frontend fe; - - struct dvb_device *cadev; - int ca_last_command; - int ca_time_interval; - - struct mutex avc_mutex; - wait_queue_head_t avc_wait; - bool avc_reply_received; - struct work_struct remote_ctrl_work; - struct input_dev *remote_ctrl_dev; - - enum model_type type; - char subunit; - char isochannel; - struct fdtv_ir_context *ir_context; - - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; - - struct mutex demux_mutex; - unsigned long channel_active; - u16 channel_pid[16]; - - int avc_data_length; - u8 avc_data[512]; -}; - -/* firedtv-avc.c */ -int avc_recv(struct firedtv *fdtv, void *data, size_t length); -int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat); -struct dvb_frontend_parameters; -int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params); -int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]); -int avc_tuner_get_ts(struct firedtv *fdtv); -int avc_identify_subunit(struct firedtv *fdtv); -struct dvb_diseqc_master_cmd; -int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, - char conttone, char nrdiseq, - struct dvb_diseqc_master_cmd *diseqcmd); -void avc_remote_ctrl_work(struct work_struct *work); -int avc_register_remote_control(struct firedtv *fdtv); -int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len); -int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len); -int avc_ca_reset(struct firedtv *fdtv); -int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length); -int avc_ca_get_time_date(struct firedtv *fdtv, int *interval); -int avc_ca_enter_menu(struct firedtv *fdtv); -int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len); -int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel); -void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel); - -/* firedtv-ci.c */ -int fdtv_ca_register(struct firedtv *fdtv); -void fdtv_ca_release(struct firedtv *fdtv); - -/* firedtv-dvb.c */ -int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed); -int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed); -int fdtv_dvb_register(struct firedtv *fdtv, const char *name); -void fdtv_dvb_unregister(struct firedtv *fdtv); - -/* firedtv-fe.c */ -void fdtv_frontend_init(struct firedtv *fdtv, const char *name); - -/* firedtv-fw.c */ -int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data); -int fdtv_read(struct firedtv *fdtv, u64 addr, void *data); -int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len); -int fdtv_start_iso(struct firedtv *fdtv); -void fdtv_stop_iso(struct firedtv *fdtv); - -/* firedtv-rc.c */ -#ifdef CONFIG_DVB_FIREDTV_INPUT -int fdtv_register_rc(struct firedtv *fdtv, struct device *dev); -void fdtv_unregister_rc(struct firedtv *fdtv); -void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code); -#else -static inline int fdtv_register_rc(struct firedtv *fdtv, - struct device *dev) { return 0; } -static inline void fdtv_unregister_rc(struct firedtv *fdtv) {} -static inline void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) {} -#endif - -#endif /* _FIREDTV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-rc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-rc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-rc.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/firedtv-rc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,196 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * - * 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, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "firedtv.h" - -/* fixed table with older keycodes, geared towards MythTV */ -static const u16 oldtable[] = { - - /* code from device: 0x4501...0x451f */ - - KEY_ESC, - KEY_F9, - KEY_1, - KEY_2, - KEY_3, - KEY_4, - KEY_5, - KEY_6, - KEY_7, - KEY_8, - KEY_9, - KEY_I, - KEY_0, - KEY_ENTER, - KEY_RED, - KEY_UP, - KEY_GREEN, - KEY_F10, - KEY_SPACE, - KEY_F11, - KEY_YELLOW, - KEY_DOWN, - KEY_BLUE, - KEY_Z, - KEY_P, - KEY_PAGEDOWN, - KEY_LEFT, - KEY_W, - KEY_RIGHT, - KEY_P, - KEY_M, - - /* code from device: 0x4540...0x4542 */ - - KEY_R, - KEY_V, - KEY_C, -}; - -/* user-modifiable table for a remote as sold in 2008 */ -static const u16 keytable[] = { - - /* code from device: 0x0300...0x031f */ - - [0x00] = KEY_POWER, - [0x01] = KEY_SLEEP, - [0x02] = KEY_STOP, - [0x03] = KEY_OK, - [0x04] = KEY_RIGHT, - [0x05] = KEY_1, - [0x06] = KEY_2, - [0x07] = KEY_3, - [0x08] = KEY_LEFT, - [0x09] = KEY_4, - [0x0a] = KEY_5, - [0x0b] = KEY_6, - [0x0c] = KEY_UP, - [0x0d] = KEY_7, - [0x0e] = KEY_8, - [0x0f] = KEY_9, - [0x10] = KEY_DOWN, - [0x11] = KEY_TITLE, /* "OSD" - fixme */ - [0x12] = KEY_0, - [0x13] = KEY_F20, /* "16:9" - fixme */ - [0x14] = KEY_SCREEN, /* "FULL" - fixme */ - [0x15] = KEY_MUTE, - [0x16] = KEY_SUBTITLE, - [0x17] = KEY_RECORD, - [0x18] = KEY_TEXT, - [0x19] = KEY_AUDIO, - [0x1a] = KEY_RED, - [0x1b] = KEY_PREVIOUS, - [0x1c] = KEY_REWIND, - [0x1d] = KEY_PLAYPAUSE, - [0x1e] = KEY_NEXT, - [0x1f] = KEY_VOLUMEUP, - - /* code from device: 0x0340...0x0354 */ - - [0x20] = KEY_CHANNELUP, - [0x21] = KEY_F21, /* "4:3" - fixme */ - [0x22] = KEY_TV, - [0x23] = KEY_DVD, - [0x24] = KEY_VCR, - [0x25] = KEY_AUX, - [0x26] = KEY_GREEN, - [0x27] = KEY_YELLOW, - [0x28] = KEY_BLUE, - [0x29] = KEY_CHANNEL, /* "CH.LIST" */ - [0x2a] = KEY_VENDOR, /* "CI" - fixme */ - [0x2b] = KEY_VOLUMEDOWN, - [0x2c] = KEY_CHANNELDOWN, - [0x2d] = KEY_LAST, - [0x2e] = KEY_INFO, - [0x2f] = KEY_FORWARD, - [0x30] = KEY_LIST, - [0x31] = KEY_FAVORITES, - [0x32] = KEY_MENU, - [0x33] = KEY_EPG, - [0x34] = KEY_EXIT, -}; - -int fdtv_register_rc(struct firedtv *fdtv, struct device *dev) -{ - struct input_dev *idev; - int i, err; - - idev = input_allocate_device(); - if (!idev) - return -ENOMEM; - - fdtv->remote_ctrl_dev = idev; - idev->name = "FireDTV remote control"; - idev->dev.parent = dev; - idev->evbit[0] = BIT_MASK(EV_KEY); - idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL); - if (!idev->keycode) { - err = -ENOMEM; - goto fail; - } - idev->keycodesize = sizeof(keytable[0]); - idev->keycodemax = ARRAY_SIZE(keytable); - - for (i = 0; i < ARRAY_SIZE(keytable); i++) - set_bit(keytable[i], idev->keybit); - - err = input_register_device(idev); - if (err) - goto fail_free_keymap; - - return 0; - -fail_free_keymap: - kfree(idev->keycode); -fail: - input_free_device(idev); - return err; -} - -void fdtv_unregister_rc(struct firedtv *fdtv) -{ - cancel_work_sync(&fdtv->remote_ctrl_work); - kfree(fdtv->remote_ctrl_dev->keycode); - input_unregister_device(fdtv->remote_ctrl_dev); -} - -void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) -{ - struct input_dev *idev = fdtv->remote_ctrl_dev; - u16 *keycode = idev->keycode; - - if (code >= 0x0300 && code <= 0x031f) - code = keycode[code - 0x0300]; - else if (code >= 0x0340 && code <= 0x0354) - code = keycode[code - 0x0320]; - else if (code >= 0x4501 && code <= 0x451f) - code = oldtable[code - 0x4501]; - else if (code >= 0x4540 && code <= 0x4542) - code = oldtable[code - 0x4521]; - else { - printk(KERN_DEBUG "firedtv: invalid key code 0x%04x " - "from remote control\n", code); - return; - } - - input_report_key(idev, code, 1); - input_sync(idev); - input_report_key(idev, code, 0); - input_sync(idev); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -config DVB_FIREDTV - tristate "FireDTV and FloppyDTV" - depends on DVB_CORE && FIREWIRE - help - Support for DVB receivers from Digital Everywhere - which are connected via IEEE 1394 (FireWire). - - These devices don't have an MPEG decoder built in, - so you need an external software decoder to watch TV. - - To compile this driver as a module, say M here: - the module will be called firedtv. - -if DVB_FIREDTV - -config DVB_FIREDTV_INPUT - def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m) - -endif # DVB_FIREDTV diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/firewire/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -obj-$(CONFIG_DVB_FIREDTV) += firedtv.o - -firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o -firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o - -ccflags-y += -Idrivers/media/dvb/dvb-core diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1572 +0,0 @@ -/* - * Afatech AF9013 demodulator driver - * - * Copyright (C) 2007 Antti Palosaari - * - * Thanks to Afatech who kindly provided information. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "af9013_priv.h" -#include "af9013.h" - -int af9013_debug; - -struct af9013_state { - struct i2c_adapter *i2c; - struct dvb_frontend frontend; - - struct af9013_config config; - - /* tuner/demod RF and IF AGC limits used for signal strength calc */ - u8 signal_strength_en, rf_50, rf_80, if_50, if_80; - u16 signal_strength; - u32 ber; - u32 ucblocks; - u16 snr; - u32 frequency; - unsigned long next_statistics_check; -}; - -static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; - -static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg, - u8 *val, u8 len) -{ - u8 buf[3+len]; - struct i2c_msg msg = { - .addr = state->config.demod_address, - .flags = 0, - .len = sizeof(buf), - .buf = buf }; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - buf[2] = mbox; - memcpy(&buf[3], val, len); - - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - warn("I2C write failed reg:%04x len:%d", reg, len); - return -EREMOTEIO; - } - return 0; -} - -static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val, - u8 len) -{ - u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7); - return af9013_write_regs(state, mbox, reg, val, len); -} - -static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val, - u8 len) -{ - u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7); - return af9013_write_regs(state, mbox, reg, val, len); -} - -/* write single register */ -static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val) -{ - return af9013_write_ofdm_regs(state, reg, &val, 1); -} - -/* read single register */ -static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val) -{ - u8 obuf[3] = { reg >> 8, reg & 0xff, 0 }; - u8 ibuf[1]; - struct i2c_msg msg[2] = { - { - .addr = state->config.demod_address, - .flags = 0, - .len = sizeof(obuf), - .buf = obuf - }, { - .addr = state->config.demod_address, - .flags = I2C_M_RD, - .len = sizeof(ibuf), - .buf = ibuf - } - }; - - if (i2c_transfer(state->i2c, msg, 2) != 2) { - warn("I2C read failed reg:%04x", reg); - return -EREMOTEIO; - } - *val = ibuf[0]; - return 0; -} - -static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos, - u8 len, u8 val) -{ - int ret; - u8 tmp, mask; - - ret = af9013_read_reg(state, reg, &tmp); - if (ret) - return ret; - - mask = regmask[len - 1] << pos; - tmp = (tmp & ~mask) | ((val << pos) & mask); - - return af9013_write_reg(state, reg, tmp); -} - -static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos, - u8 len, u8 *val) -{ - int ret; - u8 tmp; - - ret = af9013_read_reg(state, reg, &tmp); - if (ret) - return ret; - *val = (tmp >> pos) & regmask[len - 1]; - return 0; -} - -static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) -{ - int ret; - u8 pos; - u16 addr; - deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval); - -/* GPIO0 & GPIO1 0xd735 - GPIO2 & GPIO3 0xd736 */ - - switch (gpio) { - case 0: - case 1: - addr = 0xd735; - break; - case 2: - case 3: - addr = 0xd736; - break; - - default: - err("invalid gpio:%d\n", gpio); - ret = -EINVAL; - goto error; - }; - - switch (gpio) { - case 0: - case 2: - pos = 0; - break; - case 1: - case 3: - default: - pos = 4; - break; - }; - - ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval); - -error: - return ret; -} - -static u32 af913_div(u32 a, u32 b, u32 x) -{ - u32 r = 0, c = 0, i; - deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x); - - if (a > b) { - c = a / b; - a = a - c * b; - } - - for (i = 0; i < x; i++) { - if (a >= b) { - r += 1; - a -= b; - } - a <<= 1; - r <<= 1; - } - r = (c << (u32)x) + r; - - deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r); - return r; -} - -static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw) -{ - int ret, i, j, found; - deb_info("%s: adc_clock:%d bw:%d\n", __func__, - state->config.adc_clock, bw); - - /* lookup coeff from table */ - for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) { - if (coeff_table[i].adc_clock == state->config.adc_clock && - coeff_table[i].bw == bw) { - found = 1; - break; - } - } - - if (!found) { - err("invalid bw or clock"); - ret = -EINVAL; - goto error; - } - - deb_info("%s: coeff: ", __func__); - debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info); - - /* program */ - for (j = 0; j < sizeof(coeff_table[i].val); j++) { - ret = af9013_write_reg(state, 0xae00 + j, - coeff_table[i].val[j]); - if (ret) - break; - } - -error: - return ret; -} - -static int af9013_set_adc_ctrl(struct af9013_state *state) -{ - int ret; - u8 buf[3], tmp, i; - u32 adc_cw; - - deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock); - - /* adc frequency type */ - switch (state->config.adc_clock) { - case 28800: /* 28.800 MHz */ - tmp = 0; - break; - case 20480: /* 20.480 MHz */ - tmp = 1; - break; - case 28000: /* 28.000 MHz */ - tmp = 2; - break; - case 25000: /* 25.000 MHz */ - tmp = 3; - break; - default: - err("invalid xtal"); - return -EINVAL; - } - - adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul); - - buf[0] = (u8) ((adc_cw & 0x000000ff)); - buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8); - buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16); - - deb_info("%s: adc_cw:", __func__); - debug_dump(buf, sizeof(buf), deb_info); - - /* program */ - for (i = 0; i < sizeof(buf); i++) { - ret = af9013_write_reg(state, 0xd180 + i, buf[i]); - if (ret) - goto error; - } - ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp); -error: - return ret; -} - -static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw) -{ - int ret; - u16 addr; - u8 buf[3], i, j; - u32 adc_freq, freq_cw; - s8 bfs_spec_inv; - int if_sample_freq; - - for (j = 0; j < 3; j++) { - if (j == 0) { - addr = 0xd140; /* fcw normal */ - bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; - } else if (j == 1) { - addr = 0x9be7; /* fcw dummy ram */ - bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; - } else { - addr = 0x9bea; /* fcw inverted */ - bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1; - } - - adc_freq = state->config.adc_clock * 1000; - if_sample_freq = state->config.tuner_if * 1000; - - /* TDA18271 uses different sampling freq for every bw */ - if (state->config.tuner == AF9013_TUNER_TDA18271) { - switch (bw) { - case BANDWIDTH_6_MHZ: - if_sample_freq = 3300000; /* 3.3 MHz */ - break; - case BANDWIDTH_7_MHZ: - if_sample_freq = 3500000; /* 3.5 MHz */ - break; - case BANDWIDTH_8_MHZ: - default: - if_sample_freq = 4000000; /* 4.0 MHz */ - break; - } - } else if (state->config.tuner == AF9013_TUNER_TDA18218) { - switch (bw) { - case BANDWIDTH_6_MHZ: - if_sample_freq = 3000000; /* 3 MHz */ - break; - case BANDWIDTH_7_MHZ: - if_sample_freq = 3500000; /* 3.5 MHz */ - break; - case BANDWIDTH_8_MHZ: - default: - if_sample_freq = 4000000; /* 4 MHz */ - break; - } - } - - while (if_sample_freq > (adc_freq / 2)) - if_sample_freq = if_sample_freq - adc_freq; - - if (if_sample_freq >= 0) - bfs_spec_inv = bfs_spec_inv * (-1); - else - if_sample_freq = if_sample_freq * (-1); - - freq_cw = af913_div(if_sample_freq, adc_freq, 23ul); - - if (bfs_spec_inv == -1) - freq_cw = 0x00800000 - freq_cw; - - buf[0] = (u8) ((freq_cw & 0x000000ff)); - buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8); - buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16); - - - deb_info("%s: freq_cw:", __func__); - debug_dump(buf, sizeof(buf), deb_info); - - /* program */ - for (i = 0; i < sizeof(buf); i++) { - ret = af9013_write_reg(state, addr++, buf[i]); - if (ret) - goto error; - } - } -error: - return ret; -} - -static int af9013_set_ofdm_params(struct af9013_state *state, - struct dvb_ofdm_parameters *params, u8 *auto_mode) -{ - int ret; - u8 i, buf[3] = {0, 0, 0}; - *auto_mode = 0; /* set if parameters are requested to auto set */ - - /* Try auto-detect transmission parameters in case of AUTO requested or - garbage parameters given by application for compatibility. - MPlayer seems to provide garbage parameters currently. */ - - switch (params->transmission_mode) { - case TRANSMISSION_MODE_AUTO: - *auto_mode = 1; - case TRANSMISSION_MODE_2K: - break; - case TRANSMISSION_MODE_8K: - buf[0] |= (1 << 0); - break; - default: - deb_info("%s: invalid transmission_mode\n", __func__); - *auto_mode = 1; - } - - switch (params->guard_interval) { - case GUARD_INTERVAL_AUTO: - *auto_mode = 1; - case GUARD_INTERVAL_1_32: - break; - case GUARD_INTERVAL_1_16: - buf[0] |= (1 << 2); - break; - case GUARD_INTERVAL_1_8: - buf[0] |= (2 << 2); - break; - case GUARD_INTERVAL_1_4: - buf[0] |= (3 << 2); - break; - default: - deb_info("%s: invalid guard_interval\n", __func__); - *auto_mode = 1; - } - - switch (params->hierarchy_information) { - case HIERARCHY_AUTO: - *auto_mode = 1; - case HIERARCHY_NONE: - break; - case HIERARCHY_1: - buf[0] |= (1 << 4); - break; - case HIERARCHY_2: - buf[0] |= (2 << 4); - break; - case HIERARCHY_4: - buf[0] |= (3 << 4); - break; - default: - deb_info("%s: invalid hierarchy_information\n", __func__); - *auto_mode = 1; - }; - - switch (params->constellation) { - case QAM_AUTO: - *auto_mode = 1; - case QPSK: - break; - case QAM_16: - buf[1] |= (1 << 6); - break; - case QAM_64: - buf[1] |= (2 << 6); - break; - default: - deb_info("%s: invalid constellation\n", __func__); - *auto_mode = 1; - } - - /* Use HP. How and which case we can switch to LP? */ - buf[1] |= (1 << 4); - - switch (params->code_rate_HP) { - case FEC_AUTO: - *auto_mode = 1; - case FEC_1_2: - break; - case FEC_2_3: - buf[2] |= (1 << 0); - break; - case FEC_3_4: - buf[2] |= (2 << 0); - break; - case FEC_5_6: - buf[2] |= (3 << 0); - break; - case FEC_7_8: - buf[2] |= (4 << 0); - break; - default: - deb_info("%s: invalid code_rate_HP\n", __func__); - *auto_mode = 1; - } - - switch (params->code_rate_LP) { - case FEC_AUTO: - /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO - by dvb_frontend.c for compatibility */ - if (params->hierarchy_information != HIERARCHY_NONE) - *auto_mode = 1; - case FEC_1_2: - break; - case FEC_2_3: - buf[2] |= (1 << 3); - break; - case FEC_3_4: - buf[2] |= (2 << 3); - break; - case FEC_5_6: - buf[2] |= (3 << 3); - break; - case FEC_7_8: - buf[2] |= (4 << 3); - break; - case FEC_NONE: - if (params->hierarchy_information == HIERARCHY_AUTO) - break; - default: - deb_info("%s: invalid code_rate_LP\n", __func__); - *auto_mode = 1; - } - - switch (params->bandwidth) { - case BANDWIDTH_6_MHZ: - break; - case BANDWIDTH_7_MHZ: - buf[1] |= (1 << 2); - break; - case BANDWIDTH_8_MHZ: - buf[1] |= (2 << 2); - break; - default: - deb_info("%s: invalid bandwidth\n", __func__); - buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */ - } - - /* program */ - for (i = 0; i < sizeof(buf); i++) { - ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]); - if (ret) - break; - } - - return ret; -} - -static int af9013_reset(struct af9013_state *state, u8 sleep) -{ - int ret; - u8 tmp, i; - deb_info("%s\n", __func__); - - /* enable OFDM reset */ - ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1); - if (ret) - goto error; - - /* start reset mechanism */ - ret = af9013_write_reg(state, 0xaeff, 1); - if (ret) - goto error; - - /* reset is done when bit 1 is set */ - for (i = 0; i < 150; i++) { - ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp); - if (ret) - goto error; - if (tmp) - break; /* reset done */ - msleep(10); - } - if (!tmp) - return -ETIMEDOUT; - - /* don't clear reset when going to sleep */ - if (!sleep) { - /* clear OFDM reset */ - ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); - if (ret) - goto error; - - /* disable OFDM reset */ - ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); - } -error: - return ret; -} - -static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) -{ - int ret; - deb_info("%s: onoff:%d\n", __func__, onoff); - - if (onoff) { - /* power on */ - ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0); - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); - } else { - /* power off */ - ret = af9013_reset(state, 1); - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1); - } -error: - return ret; -} - -static int af9013_lock_led(struct af9013_state *state, u8 onoff) -{ - deb_info("%s: onoff:%d\n", __func__, onoff); - - return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff); -} - -static int af9013_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - u8 auto_mode; /* auto set TPS */ - - deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, - params->u.ofdm.bandwidth); - - state->frequency = params->frequency; - - /* program tuner */ - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); - - /* program CFOE coefficients */ - ret = af9013_set_coeff(state, params->u.ofdm.bandwidth); - if (ret) - goto error; - - /* program frequency control */ - ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth); - if (ret) - goto error; - - /* clear TPS lock flag (inverted flag) */ - ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1); - if (ret) - goto error; - - /* clear MPEG2 lock flag */ - ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0); - if (ret) - goto error; - - /* empty channel function */ - ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0); - if (ret) - goto error; - - /* empty DVB-T channel function */ - ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0); - if (ret) - goto error; - - /* program TPS and bandwidth, check if auto mode needed */ - ret = af9013_set_ofdm_params(state, ¶ms->u.ofdm, &auto_mode); - if (ret) - goto error; - - if (auto_mode) { - /* clear easy mode flag */ - ret = af9013_write_reg(state, 0xaefd, 0); - deb_info("%s: auto TPS\n", __func__); - } else { - /* set easy mode flag */ - ret = af9013_write_reg(state, 0xaefd, 1); - if (ret) - goto error; - ret = af9013_write_reg(state, 0xaefe, 0); - deb_info("%s: manual TPS\n", __func__); - } - if (ret) - goto error; - - /* everything is set, lets try to receive channel - OFSM GO! */ - ret = af9013_write_reg(state, 0xffff, 0); - if (ret) - goto error; - -error: - return ret; -} - -static int af9013_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - u8 i, buf[3]; - deb_info("%s\n", __func__); - - /* read TPS registers */ - for (i = 0; i < 3; i++) { - ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]); - if (ret) - goto error; - } - - switch ((buf[1] >> 6) & 3) { - case 0: - p->u.ofdm.constellation = QPSK; - break; - case 1: - p->u.ofdm.constellation = QAM_16; - break; - case 2: - p->u.ofdm.constellation = QAM_64; - break; - } - - switch ((buf[0] >> 0) & 3) { - case 0: - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - break; - case 1: - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - } - - switch ((buf[0] >> 2) & 3) { - case 0: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; - break; - } - - switch ((buf[0] >> 4) & 7) { - case 0: - p->u.ofdm.hierarchy_information = HIERARCHY_NONE; - break; - case 1: - p->u.ofdm.hierarchy_information = HIERARCHY_1; - break; - case 2: - p->u.ofdm.hierarchy_information = HIERARCHY_2; - break; - case 3: - p->u.ofdm.hierarchy_information = HIERARCHY_4; - break; - } - - switch ((buf[2] >> 0) & 7) { - case 0: - p->u.ofdm.code_rate_HP = FEC_1_2; - break; - case 1: - p->u.ofdm.code_rate_HP = FEC_2_3; - break; - case 2: - p->u.ofdm.code_rate_HP = FEC_3_4; - break; - case 3: - p->u.ofdm.code_rate_HP = FEC_5_6; - break; - case 4: - p->u.ofdm.code_rate_HP = FEC_7_8; - break; - } - - switch ((buf[2] >> 3) & 7) { - case 0: - p->u.ofdm.code_rate_LP = FEC_1_2; - break; - case 1: - p->u.ofdm.code_rate_LP = FEC_2_3; - break; - case 2: - p->u.ofdm.code_rate_LP = FEC_3_4; - break; - case 3: - p->u.ofdm.code_rate_LP = FEC_5_6; - break; - case 4: - p->u.ofdm.code_rate_LP = FEC_7_8; - break; - } - - switch ((buf[1] >> 2) & 3) { - case 0: - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - break; - case 1: - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - break; - case 2: - p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - break; - } - - p->inversion = INVERSION_AUTO; - p->frequency = state->frequency; - -error: - return ret; -} - -static int af9013_update_ber_unc(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - u8 buf[3], i; - u32 error_bit_count = 0; - u32 total_bit_count = 0; - u32 abort_packet_count = 0; - - state->ber = 0; - - /* check if error bit count is ready */ - ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]); - if (ret) - goto error; - if (!buf[0]) - goto exit; - - /* get RSD packet abort count */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0xd38a + i, &buf[i]); - if (ret) - goto error; - } - abort_packet_count = (buf[1] << 8) + buf[0]; - - /* get error bit count */ - for (i = 0; i < 3; i++) { - ret = af9013_read_reg(state, 0xd387 + i, &buf[i]); - if (ret) - goto error; - } - error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0]; - error_bit_count = error_bit_count - abort_packet_count * 8 * 8; - - /* get used RSD counting period (10000 RSD packets used) */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0xd385 + i, &buf[i]); - if (ret) - goto error; - } - total_bit_count = (buf[1] << 8) + buf[0]; - total_bit_count = total_bit_count - abort_packet_count; - total_bit_count = total_bit_count * 204 * 8; - - if (total_bit_count) - state->ber = error_bit_count * 1000000000 / total_bit_count; - - state->ucblocks += abort_packet_count; - - deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__, - error_bit_count, total_bit_count, abort_packet_count); - - /* set BER counting range */ - ret = af9013_write_reg(state, 0xd385, 10000 & 0xff); - if (ret) - goto error; - ret = af9013_write_reg(state, 0xd386, 10000 >> 8); - if (ret) - goto error; - /* reset and start BER counter */ - ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1); - if (ret) - goto error; - -exit: -error: - return ret; -} - -static int af9013_update_snr(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - u8 buf[3], i, len; - u32 quant = 0; - struct snr_table *uninitialized_var(snr_table); - - /* check if quantizer ready (for snr) */ - ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]); - if (ret) - goto error; - if (buf[0]) { - /* quantizer ready - read it */ - for (i = 0; i < 3; i++) { - ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]); - if (ret) - goto error; - } - quant = (buf[2] << 16) + (buf[1] << 8) + buf[0]; - - /* read current constellation */ - ret = af9013_read_reg(state, 0xd3c1, &buf[0]); - if (ret) - goto error; - - switch ((buf[0] >> 6) & 3) { - case 0: - len = ARRAY_SIZE(qpsk_snr_table); - snr_table = qpsk_snr_table; - break; - case 1: - len = ARRAY_SIZE(qam16_snr_table); - snr_table = qam16_snr_table; - break; - case 2: - len = ARRAY_SIZE(qam64_snr_table); - snr_table = qam64_snr_table; - break; - default: - len = 0; - break; - } - - if (len) { - for (i = 0; i < len; i++) { - if (quant < snr_table[i].val) { - state->snr = snr_table[i].snr * 10; - break; - } - } - } - - /* set quantizer super frame count */ - ret = af9013_write_reg(state, 0xd2e2, 1); - if (ret) - goto error; - - /* check quantizer availability */ - for (i = 0; i < 10; i++) { - msleep(10); - ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1, - &buf[0]); - if (ret) - goto error; - if (!buf[0]) - break; - } - - /* reset quantizer */ - ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1); - if (ret) - goto error; - } - -error: - return ret; -} - -static int af9013_update_signal_strength(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret = 0; - u8 rf_gain, if_gain; - int signal_strength; - - deb_info("%s\n", __func__); - - if (state->signal_strength_en) { - ret = af9013_read_reg(state, 0xd07c, &rf_gain); - if (ret) - goto error; - ret = af9013_read_reg(state, 0xd07d, &if_gain); - if (ret) - goto error; - signal_strength = (0xffff / \ - (9 * (state->rf_50 + state->if_50) - \ - 11 * (state->rf_80 + state->if_80))) * \ - (10 * (rf_gain + if_gain) - \ - 11 * (state->rf_80 + state->if_80)); - if (signal_strength < 0) - signal_strength = 0; - else if (signal_strength > 0xffff) - signal_strength = 0xffff; - - state->signal_strength = signal_strength; - } else { - state->signal_strength = 0; - } - -error: - return ret; -} - -static int af9013_update_statistics(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - - if (time_before(jiffies, state->next_statistics_check)) - return 0; - - /* set minimum statistic update interval */ - state->next_statistics_check = jiffies + msecs_to_jiffies(1200); - - ret = af9013_update_signal_strength(fe); - if (ret) - goto error; - ret = af9013_update_snr(fe); - if (ret) - goto error; - ret = af9013_update_ber_unc(fe); - if (ret) - goto error; - -error: - return ret; -} - -static int af9013_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *fesettings) -{ - fesettings->min_delay_ms = 800; - fesettings->step_size = 0; - fesettings->max_drift = 0; - - return 0; -} - -static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret = 0; - u8 tmp; - *status = 0; - - /* MPEG2 lock */ - ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_LOCK; - - if (!*status) { - /* TPS lock */ - ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI; - } - - if (!*status) { - /* CFO lock */ - ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; - } - - if (!*status) { - /* SFOE lock */ - ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; - } - - if (!*status) { - /* AGC lock */ - ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL; - } - - ret = af9013_update_statistics(fe); - -error: - return ret; -} - - -static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); - *ber = state->ber; - return ret; -} - -static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); - *strength = state->signal_strength; - return ret; -} - -static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); - *snr = state->snr; - return ret; -} - -static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); - *ucblocks = state->ucblocks; - return ret; -} - -static int af9013_sleep(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - deb_info("%s\n", __func__); - - ret = af9013_lock_led(state, 0); - if (ret) - goto error; - - ret = af9013_power_ctrl(state, 0); -error: - return ret; -} - -static int af9013_init(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret, i, len; - u8 tmp0, tmp1; - struct regdesc *init; - deb_info("%s\n", __func__); - - /* reset OFDM */ - ret = af9013_reset(state, 0); - if (ret) - goto error; - - /* power on */ - ret = af9013_power_ctrl(state, 1); - if (ret) - goto error; - - /* enable ADC */ - ret = af9013_write_reg(state, 0xd73a, 0xa4); - if (ret) - goto error; - - /* write API version to firmware */ - for (i = 0; i < sizeof(state->config.api_version); i++) { - ret = af9013_write_reg(state, 0x9bf2 + i, - state->config.api_version[i]); - if (ret) - goto error; - } - - /* program ADC control */ - ret = af9013_set_adc_ctrl(state); - if (ret) - goto error; - - /* set I2C master clock */ - ret = af9013_write_reg(state, 0xd416, 0x14); - if (ret) - goto error; - - /* set 16 embx */ - ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1); - if (ret) - goto error; - - /* set no trigger */ - ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0); - if (ret) - goto error; - - /* set read-update bit for constellation */ - ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1); - if (ret) - goto error; - - /* enable FEC monitor */ - ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1); - if (ret) - goto error; - - /* load OFSM settings */ - deb_info("%s: load ofsm settings\n", __func__); - len = ARRAY_SIZE(ofsm_init); - init = ofsm_init; - for (i = 0; i < len; i++) { - ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, - init[i].len, init[i].val); - if (ret) - goto error; - } - - /* load tuner specific settings */ - deb_info("%s: load tuner specific settings\n", __func__); - switch (state->config.tuner) { - case AF9013_TUNER_MXL5003D: - len = ARRAY_SIZE(tuner_init_mxl5003d); - init = tuner_init_mxl5003d; - break; - case AF9013_TUNER_MXL5005D: - case AF9013_TUNER_MXL5005R: - case AF9013_TUNER_MXL5007T: - len = ARRAY_SIZE(tuner_init_mxl5005); - init = tuner_init_mxl5005; - break; - case AF9013_TUNER_ENV77H11D5: - len = ARRAY_SIZE(tuner_init_env77h11d5); - init = tuner_init_env77h11d5; - break; - case AF9013_TUNER_MT2060: - len = ARRAY_SIZE(tuner_init_mt2060); - init = tuner_init_mt2060; - break; - case AF9013_TUNER_MC44S803: - len = ARRAY_SIZE(tuner_init_mc44s803); - init = tuner_init_mc44s803; - break; - case AF9013_TUNER_QT1010: - case AF9013_TUNER_QT1010A: - len = ARRAY_SIZE(tuner_init_qt1010); - init = tuner_init_qt1010; - break; - case AF9013_TUNER_MT2060_2: - len = ARRAY_SIZE(tuner_init_mt2060_2); - init = tuner_init_mt2060_2; - break; - case AF9013_TUNER_TDA18271: - case AF9013_TUNER_TDA18218: - len = ARRAY_SIZE(tuner_init_tda18271); - init = tuner_init_tda18271; - break; - case AF9013_TUNER_UNKNOWN: - default: - len = ARRAY_SIZE(tuner_init_unknown); - init = tuner_init_unknown; - break; - } - - for (i = 0; i < len; i++) { - ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, - init[i].len, init[i].val); - if (ret) - goto error; - } - - /* set TS mode */ - deb_info("%s: setting ts mode\n", __func__); - tmp0 = 0; /* parallel mode */ - tmp1 = 0; /* serial mode */ - switch (state->config.output_mode) { - case AF9013_OUTPUT_MODE_PARALLEL: - tmp0 = 1; - break; - case AF9013_OUTPUT_MODE_SERIAL: - tmp1 = 1; - break; - case AF9013_OUTPUT_MODE_USB: - /* usb mode for AF9015 */ - default: - break; - } - ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */ - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */ - if (ret) - goto error; - - /* enable lock led */ - ret = af9013_lock_led(state, 1); - if (ret) - goto error; - - /* read values needed for signal strength calculation */ - ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, - &state->signal_strength_en); - if (ret) - goto error; - - if (state->signal_strength_en) { - ret = af9013_read_reg(state, 0x9bbd, &state->rf_50); - if (ret) - goto error; - ret = af9013_read_reg(state, 0x9bd0, &state->rf_80); - if (ret) - goto error; - ret = af9013_read_reg(state, 0x9be2, &state->if_50); - if (ret) - goto error; - ret = af9013_read_reg(state, 0x9be4, &state->if_80); - if (ret) - goto error; - } - -error: - return ret; -} - -static struct dvb_frontend_ops af9013_ops; - -static int af9013_download_firmware(struct af9013_state *state) -{ - int i, len, remaining, ret; - const struct firmware *fw; - u16 checksum = 0; - u8 val; - u8 fw_params[4]; - u8 *fw_file = AF9013_DEFAULT_FIRMWARE; - - msleep(100); - /* check whether firmware is already running */ - ret = af9013_read_reg(state, 0x98be, &val); - if (ret) - goto error; - else - deb_info("%s: firmware status:%02x\n", __func__, val); - - if (val == 0x0c) /* fw is running, no need for download */ - goto exit; - - info("found a '%s' in cold state, will try to load a firmware", - af9013_ops.info.name); - - /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_file, state->i2c->dev.parent); - if (ret) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details" \ - " on firmware-problems. (%d)", - fw_file, ret); - goto error; - } - - info("downloading firmware from file '%s'", fw_file); - - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; - - fw_params[0] = checksum >> 8; - fw_params[1] = checksum & 0xff; - fw_params[2] = fw->size >> 8; - fw_params[3] = fw->size & 0xff; - - /* write fw checksum & size */ - ret = af9013_write_ofsm_regs(state, 0x50fc, - fw_params, sizeof(fw_params)); - if (ret) - goto error_release; - - #define FW_ADDR 0x5100 /* firmware start address */ - #define LEN_MAX 16 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - - ret = af9013_write_ofsm_regs(state, - FW_ADDR + fw->size - remaining, - (u8 *) &fw->data[fw->size - remaining], len); - if (ret) { - err("firmware download failed:%d", ret); - goto error_release; - } - } - - /* request boot firmware */ - ret = af9013_write_reg(state, 0xe205, 1); - if (ret) - goto error_release; - - for (i = 0; i < 15; i++) { - msleep(100); - - /* check firmware status */ - ret = af9013_read_reg(state, 0x98be, &val); - if (ret) - goto error_release; - - deb_info("%s: firmware status:%02x\n", __func__, val); - - if (val == 0x0c || val == 0x04) /* success or fail */ - break; - } - - if (val == 0x04) { - err("firmware did not run"); - ret = -1; - } else if (val != 0x0c) { - err("firmware boot timeout"); - ret = -1; - } - -error_release: - release_firmware(fw); -error: -exit: - if (!ret) - info("found a '%s' in warm state.", af9013_ops.info.name); - return ret; -} - -static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - int ret; - struct af9013_state *state = fe->demodulator_priv; - deb_info("%s: enable:%d\n", __func__, enable); - - if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) - ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable); - else - ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable); - - return ret; -} - -static void af9013_release(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops af9013_ops; - -struct dvb_frontend *af9013_attach(const struct af9013_config *config, - struct i2c_adapter *i2c) -{ - int ret; - struct af9013_state *state = NULL; - u8 buf[4], i; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->i2c = i2c; - memcpy(&state->config, config, sizeof(struct af9013_config)); - - /* download firmware */ - if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) { - ret = af9013_download_firmware(state); - if (ret) - goto error; - } - - /* firmware version */ - for (i = 0; i < 4; i++) { - ret = af9013_read_reg(state, 0x5103 + i, &buf[i]); - if (ret) - goto error; - } - info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]); - - /* chip version */ - ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]); - if (ret) - goto error; - - /* ROM version */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0x116b + i, &buf[i]); - if (ret) - goto error; - } - deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__, - buf[2], buf[0], buf[1]); - - /* settings for mp2if */ - if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) { - /* AF9015 split PSB to 1.5k + 0.5k */ - ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1); - } else { - /* AF9013 change the output bit to data7 */ - ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1); - if (ret) - goto error; - /* AF9013 set mpeg to full speed */ - ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1); - } - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1); - if (ret) - goto error; - - /* set GPIOs */ - for (i = 0; i < sizeof(state->config.gpio); i++) { - ret = af9013_set_gpio(state, i, state->config.gpio[i]); - if (ret) - goto error; - } - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &af9013_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - return &state->frontend; -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(af9013_attach); - -static struct dvb_frontend_ops af9013_ops = { - .info = { - .name = "Afatech AF9013 DVB-T", - .type = FE_OFDM, - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 250000, - .frequency_tolerance = 0, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | - FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | - FE_CAN_RECOVER | - FE_CAN_MUTE_TS - }, - - .release = af9013_release, - .init = af9013_init, - .sleep = af9013_sleep, - .i2c_gate_ctrl = af9013_i2c_gate_ctrl, - - .set_frontend = af9013_set_frontend, - .get_frontend = af9013_get_frontend, - - .get_tune_settings = af9013_get_tune_settings, - - .read_status = af9013_read_status, - .read_ber = af9013_read_ber, - .read_signal_strength = af9013_read_signal_strength, - .read_snr = af9013_read_snr, - .read_ucblocks = af9013_read_ucblocks, -}; - -module_param_named(debug, af9013_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -/* - * Afatech AF9013 demodulator driver - * - * Copyright (C) 2007 Antti Palosaari - * - * Thanks to Afatech who kindly provided information. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _AF9013_H_ -#define _AF9013_H_ - -#include - -enum af9013_ts_mode { - AF9013_OUTPUT_MODE_PARALLEL, - AF9013_OUTPUT_MODE_SERIAL, - AF9013_OUTPUT_MODE_USB, /* only for AF9015 */ -}; - -enum af9013_tuner { - AF9013_TUNER_MXL5003D = 3, /* MaxLinear */ - AF9013_TUNER_MXL5005D = 13, /* MaxLinear */ - AF9013_TUNER_MXL5005R = 30, /* MaxLinear */ - AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */ - AF9013_TUNER_MT2060 = 130, /* Microtune */ - AF9013_TUNER_MC44S803 = 133, /* Freescale */ - AF9013_TUNER_QT1010 = 134, /* Quantek */ - AF9013_TUNER_UNKNOWN = 140, /* for can tuners ? */ - AF9013_TUNER_MT2060_2 = 147, /* Microtune */ - AF9013_TUNER_TDA18271 = 156, /* NXP */ - AF9013_TUNER_QT1010A = 162, /* Quantek */ - AF9013_TUNER_MXL5007T = 177, /* MaxLinear */ - AF9013_TUNER_TDA18218 = 179, /* NXP */ -}; - -/* AF9013/5 GPIOs (mostly guessed) - demod#1-gpio#0 - set demod#2 i2c-addr for dual devices - demod#1-gpio#1 - xtal setting (?) - demod#1-gpio#3 - tuner#1 - demod#2-gpio#0 - tuner#2 - demod#2-gpio#1 - xtal setting (?) -*/ -#define AF9013_GPIO_ON (1 << 0) -#define AF9013_GPIO_EN (1 << 1) -#define AF9013_GPIO_O (1 << 2) -#define AF9013_GPIO_I (1 << 3) - -#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN) -#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) - -#define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN) -#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) - -struct af9013_config { - /* demodulator's I2C address */ - u8 demod_address; - - /* frequencies in kHz */ - u32 adc_clock; - - /* tuner ID */ - u8 tuner; - - /* tuner IF */ - u16 tuner_if; - - /* TS data output mode */ - u8 output_mode:2; - - /* RF spectrum inversion */ - u8 rf_spec_inv:1; - - /* API version */ - u8 api_version[4]; - - /* GPIOs */ - u8 gpio[4]; -}; - - -#if defined(CONFIG_DVB_AF9013) || \ - (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE)) -extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *af9013_attach( -const struct af9013_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_AF9013 */ - -#endif /* _AF9013_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/af9013_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,923 +0,0 @@ -/* - * Afatech AF9013 demodulator driver - * - * Copyright (C) 2007 Antti Palosaari - * - * Thanks to Afatech who kindly provided information. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _AF9013_PRIV_ -#define _AF9013_PRIV_ - -#define LOG_PREFIX "af9013" -extern int af9013_debug; - -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) - -#define debug_dump(b, l, func) {\ - int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ -} - -#define deb_info(args...) dprintk(af9013_debug, 0x01, args) - -#undef err -#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -#undef info -#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef warn -#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) - -#define AF9013_DEFAULT_FIRMWARE "dvb-fe-af9013.fw" - -struct regdesc { - u16 addr; - u8 pos:4; - u8 len:4; - u8 val; -}; - -struct snr_table { - u32 val; - u8 snr; -}; - -struct coeff { - u32 adc_clock; - fe_bandwidth_t bw; - u8 val[24]; -}; - -/* pre-calculated coeff lookup table */ -static struct coeff coeff_table[] = { - /* 28.800 MHz */ - { 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14, - 0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a, - 0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } }, - { 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71, - 0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38, - 0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } }, - { 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf, - 0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7, - 0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } }, - /* 20.480 MHz */ - { 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24, - 0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92, - 0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } }, - { 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40, - 0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00, - 0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } }, - { 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b, - 0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d, - 0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } }, - /* 28.000 MHz */ - { 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39, - 0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f, - 0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } }, - { 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92, - 0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49, - 0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } }, - { 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb, - 0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63, - 0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } }, - /* 25.000 MHz */ - { 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9, - 0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e, - 0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } }, - { 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e, - 0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7, - 0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } }, - { 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63, - 0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f, - 0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } }, -}; - -/* QPSK SNR lookup table */ -static struct snr_table qpsk_snr_table[] = { - { 0x0b4771, 0 }, - { 0x0c1aed, 1 }, - { 0x0d0d27, 2 }, - { 0x0e4d19, 3 }, - { 0x0e5da8, 4 }, - { 0x107097, 5 }, - { 0x116975, 6 }, - { 0x1252d9, 7 }, - { 0x131fa4, 8 }, - { 0x13d5e1, 9 }, - { 0x148e53, 10 }, - { 0x15358b, 11 }, - { 0x15dd29, 12 }, - { 0x168112, 13 }, - { 0x170b61, 14 }, - { 0xffffff, 15 }, -}; - -/* QAM16 SNR lookup table */ -static struct snr_table qam16_snr_table[] = { - { 0x05eb62, 5 }, - { 0x05fecf, 6 }, - { 0x060b80, 7 }, - { 0x062501, 8 }, - { 0x064865, 9 }, - { 0x069604, 10 }, - { 0x06f356, 11 }, - { 0x07706a, 12 }, - { 0x0804d3, 13 }, - { 0x089d1a, 14 }, - { 0x093e3d, 15 }, - { 0x09e35d, 16 }, - { 0x0a7c3c, 17 }, - { 0x0afaf8, 18 }, - { 0x0b719d, 19 }, - { 0xffffff, 20 }, -}; - -/* QAM64 SNR lookup table */ -static struct snr_table qam64_snr_table[] = { - { 0x03109b, 12 }, - { 0x0310d4, 13 }, - { 0x031920, 14 }, - { 0x0322d0, 15 }, - { 0x0339fc, 16 }, - { 0x0364a1, 17 }, - { 0x038bcc, 18 }, - { 0x03c7d3, 19 }, - { 0x0408cc, 20 }, - { 0x043bed, 21 }, - { 0x048061, 22 }, - { 0x04be95, 23 }, - { 0x04fa7d, 24 }, - { 0x052405, 25 }, - { 0x05570d, 26 }, - { 0xffffff, 27 }, -}; - -static struct regdesc ofsm_init[] = { - { 0xd73a, 0, 8, 0xa1 }, - { 0xd73b, 0, 8, 0x1f }, - { 0xd73c, 4, 4, 0x0a }, - { 0xd732, 3, 1, 0x00 }, - { 0xd731, 4, 2, 0x03 }, - { 0xd73d, 7, 1, 0x01 }, - { 0xd740, 0, 1, 0x00 }, - { 0xd740, 1, 1, 0x00 }, - { 0xd740, 2, 1, 0x00 }, - { 0xd740, 3, 1, 0x01 }, - { 0xd3c1, 4, 1, 0x01 }, - { 0x9124, 0, 8, 0x58 }, - { 0x9125, 0, 2, 0x02 }, - { 0xd3a2, 0, 8, 0x00 }, - { 0xd3a3, 0, 8, 0x04 }, - { 0xd305, 0, 8, 0x32 }, - { 0xd306, 0, 8, 0x10 }, - { 0xd304, 0, 8, 0x04 }, - { 0x9112, 0, 1, 0x01 }, - { 0x911d, 0, 1, 0x01 }, - { 0x911a, 0, 1, 0x01 }, - { 0x911b, 0, 1, 0x01 }, - { 0x9bce, 0, 4, 0x02 }, - { 0x9116, 0, 1, 0x01 }, - { 0x9122, 0, 8, 0xd0 }, - { 0xd2e0, 0, 8, 0xd0 }, - { 0xd2e9, 0, 4, 0x0d }, - { 0xd38c, 0, 8, 0xfc }, - { 0xd38d, 0, 8, 0x00 }, - { 0xd38e, 0, 8, 0x7e }, - { 0xd38f, 0, 8, 0x00 }, - { 0xd390, 0, 8, 0x2f }, - { 0xd145, 4, 1, 0x01 }, - { 0xd1a9, 4, 1, 0x01 }, - { 0xd158, 5, 3, 0x01 }, - { 0xd159, 0, 6, 0x06 }, - { 0xd167, 0, 8, 0x00 }, - { 0xd168, 0, 4, 0x07 }, - { 0xd1c3, 5, 3, 0x00 }, - { 0xd1c4, 0, 6, 0x00 }, - { 0xd1c5, 0, 7, 0x10 }, - { 0xd1c6, 0, 3, 0x02 }, - { 0xd080, 2, 5, 0x03 }, - { 0xd081, 4, 4, 0x09 }, - { 0xd098, 4, 4, 0x0f }, - { 0xd098, 0, 4, 0x03 }, - { 0xdbc0, 4, 1, 0x01 }, - { 0xdbc7, 0, 8, 0x08 }, - { 0xdbc8, 4, 4, 0x00 }, - { 0xdbc9, 0, 5, 0x01 }, - { 0xd280, 0, 8, 0xe0 }, - { 0xd281, 0, 8, 0xff }, - { 0xd282, 0, 8, 0xff }, - { 0xd283, 0, 8, 0xc3 }, - { 0xd284, 0, 8, 0xff }, - { 0xd285, 0, 4, 0x01 }, - { 0xd0f0, 0, 7, 0x1a }, - { 0xd0f1, 4, 1, 0x01 }, - { 0xd0f2, 0, 8, 0x0c }, - { 0xd101, 5, 3, 0x06 }, - { 0xd103, 0, 4, 0x08 }, - { 0xd0f8, 0, 7, 0x20 }, - { 0xd111, 5, 1, 0x00 }, - { 0xd111, 6, 1, 0x00 }, - { 0x910b, 0, 8, 0x0a }, - { 0x9115, 0, 8, 0x02 }, - { 0x910c, 0, 8, 0x02 }, - { 0x910d, 0, 8, 0x08 }, - { 0x910e, 0, 8, 0x0a }, - { 0x9bf6, 0, 8, 0x06 }, - { 0x9bf8, 0, 8, 0x02 }, - { 0x9bf7, 0, 8, 0x05 }, - { 0x9bf9, 0, 8, 0x0f }, - { 0x9bfc, 0, 8, 0x13 }, - { 0x9bd3, 0, 8, 0xff }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, -}; - -/* Panasonic ENV77H11D5 tuner init - AF9013_TUNER_ENV77H11D5 = 129 */ -static struct regdesc tuner_init_env77h11d5[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x03 }, - { 0x9bbe, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0xd015, 0, 8, 0x50 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0xdf }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x44 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0xeb }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xf4 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bba, 0, 8, 0xf9 }, - { 0x9bc3, 0, 8, 0xdf }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0xeb }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bc9, 0, 8, 0x52 }, - { 0xd011, 0, 8, 0x3c }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xf7 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x0b }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x4d }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, -}; - -/* Microtune MT2060 tuner init - AF9013_TUNER_MT2060 = 130 */ -static struct regdesc tuner_init_mt2060[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x07 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0x9bbe, 0, 1, 0x00 }, - { 0x9bcc, 0, 1, 0x00 }, - { 0x9bb9, 0, 8, 0x75 }, - { 0x9bcd, 0, 8, 0x24 }, - { 0x9bff, 0, 8, 0x30 }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x32 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x36 }, - { 0xd00d, 0, 2, 0x03 }, - { 0xd00a, 0, 8, 0x35 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x07 }, - { 0x9bc8, 0, 8, 0x90 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x36 }, - { 0x9bc6, 0, 8, 0x03 }, - { 0x9bba, 0, 8, 0xc9 }, - { 0x9bc9, 0, 8, 0x79 }, - { 0xd011, 0, 8, 0x10 }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0x45 }, - { 0xd014, 0, 2, 0x03 }, - { 0xd040, 0, 8, 0x98 }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0xcf }, - { 0xd043, 0, 2, 0x03 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0xcc }, - { 0x9be4, 0, 8, 0xa0 }, - { 0x9bbd, 0, 8, 0x8e }, - { 0x9be2, 0, 8, 0x4d }, - { 0x9bee, 0, 1, 0x01 }, -}; - -/* Microtune MT2060 tuner init - AF9013_TUNER_MT2060_2 = 147 */ -static struct regdesc tuner_init_mt2060_2[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x06 }, - { 0x9bbe, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x32 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x36 }, - { 0xd00d, 0, 2, 0x03 }, - { 0xd00a, 0, 8, 0x35 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x07 }, - { 0x9bc8, 0, 8, 0x90 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x36 }, - { 0x9bc6, 0, 8, 0x03 }, - { 0x9bba, 0, 8, 0xc9 }, - { 0x9bc9, 0, 8, 0x79 }, - { 0xd011, 0, 8, 0x10 }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0x45 }, - { 0xd014, 0, 2, 0x03 }, - { 0xd040, 0, 8, 0x98 }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0xcf }, - { 0xd043, 0, 2, 0x03 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 8, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x96 }, - { 0xd054, 0, 8, 0x46 }, - { 0xd045, 7, 1, 0x00 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, -}; - -/* MaxLinear MXL5003 tuner init - AF9013_TUNER_MXL5003D = 3 */ -static struct regdesc tuner_init_mxl5003d[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x09 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0x9bfc, 0, 8, 0x0f }, - { 0x9bf6, 0, 8, 0x01 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0xd015, 0, 8, 0x33 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x40 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x6c }, - { 0xd007, 0, 2, 0x00 }, - { 0xd00c, 0, 8, 0x3d }, - { 0xd00d, 0, 2, 0x00 }, - { 0xd00a, 0, 8, 0x45 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x07 }, - { 0x9bc8, 0, 8, 0x52 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x3d }, - { 0x9bc6, 0, 8, 0x00 }, - { 0x9bba, 0, 8, 0xa2 }, - { 0x9bc9, 0, 8, 0xa0 }, - { 0xd011, 0, 8, 0x56 }, - { 0xd012, 0, 2, 0x00 }, - { 0xd013, 0, 8, 0x50 }, - { 0xd014, 0, 2, 0x00 }, - { 0xd040, 0, 8, 0x56 }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0x50 }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 8, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, -}; - -/* MaxLinear MXL5005S & MXL5007T tuner init - AF9013_TUNER_MXL5005D = 13 - AF9013_TUNER_MXL5005R = 30 - AF9013_TUNER_MXL5007T = 177 */ -static struct regdesc tuner_init_mxl5005[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x07 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x28 }, - { 0x9bff, 0, 8, 0x24 }, - { 0xd015, 0, 8, 0x40 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x40 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x73 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0xfa }, - { 0xd00d, 0, 2, 0x01 }, - { 0xd00a, 0, 8, 0xff }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x23 }, - { 0x9bc8, 0, 8, 0x55 }, - { 0x9bc3, 0, 8, 0x01 }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0xfa }, - { 0x9bc6, 0, 8, 0x01 }, - { 0x9bba, 0, 8, 0xff }, - { 0x9bc9, 0, 8, 0xff }, - { 0x9bd3, 0, 8, 0x95 }, - { 0xd011, 0, 8, 0x70 }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xfb }, - { 0xd014, 0, 2, 0x01 }, - { 0xd040, 0, 8, 0x70 }, - { 0xd041, 0, 2, 0x01 }, - { 0xd042, 0, 8, 0xfb }, - { 0xd043, 0, 2, 0x01 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0x93 }, - { 0x9be4, 0, 8, 0xfe }, - { 0x9bbd, 0, 8, 0x63 }, - { 0x9be2, 0, 8, 0xfe }, - { 0x9bee, 0, 1, 0x01 }, -}; - -/* Quantek QT1010 tuner init - AF9013_TUNER_QT1010 = 134 - AF9013_TUNER_QT1010A = 162 */ -static struct regdesc tuner_init_qt1010[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x09 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x28 }, - { 0x9bff, 0, 8, 0x20 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x99 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x0f }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0x50 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x00 }, - { 0x9bc8, 0, 8, 0x00 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x0f }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bba, 0, 8, 0xc5 }, - { 0x9bc9, 0, 8, 0xff }, - { 0xd011, 0, 8, 0x58 }, - { 0xd012, 0, 2, 0x02 }, - { 0xd013, 0, 8, 0x89 }, - { 0xd014, 0, 2, 0x01 }, - { 0xd040, 0, 8, 0x58 }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x89 }, - { 0xd043, 0, 2, 0x01 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0xcd }, - { 0x9be4, 0, 8, 0xbb }, - { 0x9bbd, 0, 8, 0x93 }, - { 0x9be2, 0, 8, 0x80 }, - { 0x9bee, 0, 1, 0x01 }, -}; - -/* Freescale MC44S803 tuner init - AF9013_TUNER_MC44S803 = 133 */ -static struct regdesc tuner_init_mc44s803[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x06 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0x9bf6, 0, 8, 0x01 }, - { 0x9bf8, 0, 8, 0x02 }, - { 0x9bf9, 0, 8, 0x02 }, - { 0x9bfc, 0, 8, 0x1f }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x24 }, - { 0x9bff, 0, 8, 0x24 }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x01 }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x7b }, - { 0xd007, 0, 2, 0x00 }, - { 0xd00c, 0, 8, 0x7c }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xfe }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x08 }, - { 0x9bc8, 0, 8, 0x9a }, - { 0x9bc3, 0, 8, 0x01 }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x7c }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bba, 0, 8, 0xfc }, - { 0x9bc9, 0, 8, 0xaa }, - { 0xd011, 0, 8, 0x6b }, - { 0xd012, 0, 2, 0x00 }, - { 0xd013, 0, 8, 0x88 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x6b }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0x7c }, - { 0xd043, 0, 2, 0x02 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0x9e }, - { 0x9be4, 0, 8, 0xff }, - { 0x9bbd, 0, 8, 0x9e }, - { 0x9be2, 0, 8, 0x25 }, - { 0x9bee, 0, 1, 0x01 }, - { 0xd73b, 3, 1, 0x00 }, -}; - -/* unknown, probably for tin can tuner, tuner init - AF9013_TUNER_UNKNOWN = 140 */ -static struct regdesc tuner_init_unknown[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x02 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x00 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x18 }, - { 0x9bff, 0, 8, 0x2c }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0xdf }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x44 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x00 }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xf6 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bba, 0, 8, 0xf9 }, - { 0x9bc8, 0, 8, 0xaa }, - { 0x9bc3, 0, 8, 0xdf }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x00 }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bc9, 0, 8, 0xf0 }, - { 0xd011, 0, 8, 0x3c }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xf7 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x0b }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x4d }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, -}; - -/* NXP TDA18271 & TDA18218 tuner init - AF9013_TUNER_TDA18271 = 156 - AF9013_TUNER_TDA18218 = 179 */ -static struct regdesc tuner_init_tda18271[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x04 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x00 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x18 }, - { 0x9bff, 0, 8, 0x2c }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0xdf }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x44 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x00 }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xf6 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bba, 0, 8, 0xf9 }, - { 0x9bc8, 0, 8, 0xaa }, - { 0x9bc3, 0, 8, 0xdf }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x00 }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bc9, 0, 8, 0xf0 }, - { 0xd011, 0, 8, 0x3c }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xf7 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x0b }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x4d }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0xa8 }, - { 0x9be4, 0, 8, 0x7f }, - { 0x9bbd, 0, 8, 0xa8 }, - { 0x9be2, 0, 8, 0x20 }, - { 0x9bee, 0, 1, 0x01 }, -}; - -#endif /* _AF9013_PRIV_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,509 +0,0 @@ -/* - * Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator - * ATBM8830, ATBM8831 - * - * Copyright (C) 2009 David T.L. Wong - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "dvb_frontend.h" - -#include "atbm8830.h" -#include "atbm8830_priv.h" - -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "atbm8830: " args); \ - } while (0) - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data) -{ - int ret = 0; - u8 dev_addr; - u8 buf1[] = { reg >> 8, reg & 0xFF }; - u8 buf2[] = { data }; - struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 }; - struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 }; - - dev_addr = priv->config->demod_address; - msg1.addr = dev_addr; - msg2.addr = dev_addr; - - if (debug >= 2) - dprintk("%s: reg=0x%04X, data=0x%02X\n", __func__, reg, data); - - ret = i2c_transfer(priv->i2c, &msg1, 1); - if (ret != 1) - return -EIO; - - ret = i2c_transfer(priv->i2c, &msg2, 1); - return (ret != 1) ? -EIO : 0; -} - -static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data) -{ - int ret; - u8 dev_addr; - - u8 buf1[] = { reg >> 8, reg & 0xFF }; - u8 buf2[] = { 0 }; - struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 }; - struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 }; - - dev_addr = priv->config->demod_address; - msg1.addr = dev_addr; - msg2.addr = dev_addr; - - ret = i2c_transfer(priv->i2c, &msg1, 1); - if (ret != 1) { - dprintk("%s: error reg=0x%04x, ret=%i\n", __func__, reg, ret); - return -EIO; - } - - ret = i2c_transfer(priv->i2c, &msg2, 1); - if (ret != 1) - return -EIO; - - *p_data = buf2[0]; - if (debug >= 2) - dprintk("%s: reg=0x%04X, data=0x%02X\n", - __func__, reg, buf2[0]); - - return 0; -} - -/* Lock register latch so that multi-register read is atomic */ -static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock) -{ - return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0); -} - -static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/) -{ - u32 val; - u64 t; - - /* 0x100000 * freq / 30.4MHz */ - t = (u64)0x100000 * freq; - do_div(t, 30400); - val = t; - - atbm8830_write_reg(priv, REG_OSC_CLK, val); - atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8); - atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16); - - return 0; -} - -static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/) -{ - - u32 fs = priv->config->osc_clk_freq; - u64 t; - u32 val; - u8 dat; - - if (freq != 0) { - /* 2 * PI * (freq - fs) / fs * (2 ^ 22) */ - t = (u64) 2 * 31416 * (freq - fs); - t <<= 22; - do_div(t, fs); - do_div(t, 1000); - val = t; - - atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1); - atbm8830_write_reg(priv, REG_IF_FREQ, val); - atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8); - atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16); - - atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat); - dat &= 0xFC; - atbm8830_write_reg(priv, REG_ADC_CONFIG, dat); - } else { - /* Zero IF */ - atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0); - - atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat); - dat &= 0xFC; - dat |= 0x02; - atbm8830_write_reg(priv, REG_ADC_CONFIG, dat); - - if (priv->config->zif_swap_iq) - atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03); - else - atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01); - } - - return 0; -} - -static int is_locked(struct atbm_state *priv, u8 *locked) -{ - u8 status; - - atbm8830_read_reg(priv, REG_LOCK_STATUS, &status); - - if (locked != NULL) - *locked = (status == 1); - return 0; -} - -static int set_agc_config(struct atbm_state *priv, - u8 min, u8 max, u8 hold_loop) -{ - /* no effect if both min and max are zero */ - if (!min && !max) - return 0; - - atbm8830_write_reg(priv, REG_AGC_MIN, min); - atbm8830_write_reg(priv, REG_AGC_MAX, max); - atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop); - - return 0; -} - -static int set_static_channel_mode(struct atbm_state *priv) -{ - int i; - - for (i = 0; i < 5; i++) - atbm8830_write_reg(priv, 0x099B + i, 0x08); - - atbm8830_write_reg(priv, 0x095B, 0x7F); - atbm8830_write_reg(priv, 0x09CB, 0x01); - atbm8830_write_reg(priv, 0x09CC, 0x7F); - atbm8830_write_reg(priv, 0x09CD, 0x7F); - atbm8830_write_reg(priv, 0x0E01, 0x20); - - /* For single carrier */ - atbm8830_write_reg(priv, 0x0B03, 0x0A); - atbm8830_write_reg(priv, 0x0935, 0x10); - atbm8830_write_reg(priv, 0x0936, 0x08); - atbm8830_write_reg(priv, 0x093E, 0x08); - atbm8830_write_reg(priv, 0x096E, 0x06); - - /* frame_count_max0 */ - atbm8830_write_reg(priv, 0x0B09, 0x00); - /* frame_count_max1 */ - atbm8830_write_reg(priv, 0x0B0A, 0x08); - - return 0; -} - -static int set_ts_config(struct atbm_state *priv) -{ - const struct atbm8830_config *cfg = priv->config; - - /*Set parallel/serial ts mode*/ - atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0); - atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0); - /*Set ts sampling edge*/ - atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE, - cfg->ts_sampling_edge ? 1 : 0); - /*Set ts clock freerun*/ - atbm8830_write_reg(priv, REG_TS_CLK_FREERUN, - cfg->ts_clk_gated ? 0 : 1); - - return 0; -} - -static int atbm8830_init(struct dvb_frontend *fe) -{ - struct atbm_state *priv = fe->demodulator_priv; - const struct atbm8830_config *cfg = priv->config; - - /*Set oscillator frequency*/ - set_osc_freq(priv, cfg->osc_clk_freq); - - /*Set IF frequency*/ - set_if_freq(priv, cfg->if_freq); - - /*Set AGC Config*/ - set_agc_config(priv, cfg->agc_min, cfg->agc_max, - cfg->agc_hold_loop); - - /*Set static channel mode*/ - set_static_channel_mode(priv); - - set_ts_config(priv); - /*Turn off DSP reset*/ - atbm8830_write_reg(priv, 0x000A, 0); - - /*SW version test*/ - atbm8830_write_reg(priv, 0x020C, 11); - - /* Run */ - atbm8830_write_reg(priv, REG_DEMOD_RUN, 1); - - return 0; -} - - -static void atbm8830_release(struct dvb_frontend *fe) -{ - struct atbm_state *state = fe->demodulator_priv; - dprintk("%s\n", __func__); - - kfree(state); -} - -static int atbm8830_set_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) -{ - struct atbm_state *priv = fe->demodulator_priv; - int i; - u8 locked = 0; - dprintk("%s\n", __func__); - - /* set frequency */ - if (fe->ops.tuner_ops.set_params) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, fe_params); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* start auto lock */ - for (i = 0; i < 10; i++) { - mdelay(100); - dprintk("Try %d\n", i); - is_locked(priv, &locked); - if (locked != 0) { - dprintk("ATBM8830 locked!\n"); - break; - } - } - - return 0; -} - -static int atbm8830_get_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) -{ - dprintk("%s\n", __func__); - - /* TODO: get real readings from device */ - /* inversion status */ - fe_params->inversion = INVERSION_OFF; - - /* bandwidth */ - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - - fe_params->u.ofdm.code_rate_HP = FEC_AUTO; - fe_params->u.ofdm.code_rate_LP = FEC_AUTO; - - fe_params->u.ofdm.constellation = QAM_AUTO; - - /* transmission mode */ - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - - /* guard interval */ - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - - /* hierarchy */ - fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; - - return 0; -} - -static int atbm8830_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *fesettings) -{ - fesettings->min_delay_ms = 0; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status) -{ - struct atbm_state *priv = fe->demodulator_priv; - u8 locked = 0; - u8 agc_locked = 0; - - dprintk("%s\n", __func__); - *fe_status = 0; - - is_locked(priv, &locked); - if (locked) { - *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - } - dprintk("%s: fe_status=0x%x\n", __func__, *fe_status); - - atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked); - dprintk("AGC Lock: %d\n", agc_locked); - - return 0; -} - -static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct atbm_state *priv = fe->demodulator_priv; - u32 frame_err; - u8 t; - - dprintk("%s\n", __func__); - - atbm8830_reglatch_lock(priv, 1); - - atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t); - frame_err = t & 0x7F; - frame_err <<= 8; - atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t); - frame_err |= t; - - atbm8830_reglatch_lock(priv, 0); - - *ber = frame_err * 100 / 32767; - - dprintk("%s: ber=0x%x\n", __func__, *ber); - return 0; -} - -static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal) -{ - struct atbm_state *priv = fe->demodulator_priv; - u32 pwm; - u8 t; - - dprintk("%s\n", __func__); - atbm8830_reglatch_lock(priv, 1); - - atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t); - pwm = t & 0x03; - pwm <<= 8; - atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t); - pwm |= t; - - atbm8830_reglatch_lock(priv, 0); - - dprintk("AGC PWM = 0x%02X\n", pwm); - pwm = 0x400 - pwm; - - *signal = pwm * 0x10000 / 0x400; - - return 0; -} - -static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - dprintk("%s\n", __func__); - *snr = 0; - return 0; -} - -static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - dprintk("%s\n", __func__); - *ucblocks = 0; - return 0; -} - -static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct atbm_state *priv = fe->demodulator_priv; - - return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0); -} - -static struct dvb_frontend_ops atbm8830_ops = { - .info = { - .name = "AltoBeam ATBM8830/8831 DMB-TH", - .type = FE_OFDM, - .frequency_min = 474000000, - .frequency_max = 858000000, - .frequency_stepsize = 10000, - .caps = - FE_CAN_FEC_AUTO | - FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO - }, - - .release = atbm8830_release, - - .init = atbm8830_init, - .sleep = NULL, - .write = NULL, - .i2c_gate_ctrl = atbm8830_i2c_gate_ctrl, - - .set_frontend = atbm8830_set_fe, - .get_frontend = atbm8830_get_fe, - .get_tune_settings = atbm8830_get_tune_settings, - - .read_status = atbm8830_read_status, - .read_ber = atbm8830_read_ber, - .read_signal_strength = atbm8830_read_signal_strength, - .read_snr = atbm8830_read_snr, - .read_ucblocks = atbm8830_read_ucblocks, -}; - -struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, - struct i2c_adapter *i2c) -{ - struct atbm_state *priv = NULL; - u8 data = 0; - - dprintk("%s()\n", __func__); - - if (config == NULL || i2c == NULL) - return NULL; - - priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL); - if (priv == NULL) - goto error_out; - - priv->config = config; - priv->i2c = i2c; - - /* check if the demod is there */ - if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) { - dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n", - __func__, priv->config->demod_address); - goto error_out; - } - dprintk("atbm8830 chip id: 0x%02X\n", data); - - memcpy(&priv->frontend.ops, &atbm8830_ops, - sizeof(struct dvb_frontend_ops)); - priv->frontend.demodulator_priv = priv; - - atbm8830_init(&priv->frontend); - - atbm8830_i2c_gate_ctrl(&priv->frontend, 1); - - return &priv->frontend; - -error_out: - dprintk("%s() error_out\n", __func__); - kfree(priv); - return NULL; - -} -EXPORT_SYMBOL(atbm8830_attach); - -MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver"); -MODULE_AUTHOR("David T. L. Wong "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/* - * Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator - * ATBM8830, ATBM8831 - * - * Copyright (C) 2009 David T.L. Wong - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ATBM8830_H__ -#define __ATBM8830_H__ - -#include -#include - -#define ATBM8830_PROD_8830 0 -#define ATBM8830_PROD_8831 1 - -struct atbm8830_config { - - /* product type */ - u8 prod; - - /* the demodulator's i2c address */ - u8 demod_address; - - /* parallel or serial transport stream */ - u8 serial_ts; - - /* transport stream clock output only when receving valid stream */ - u8 ts_clk_gated; - - /* Decoder sample TS data at rising edge of clock */ - u8 ts_sampling_edge; - - /* Oscillator clock frequency */ - u32 osc_clk_freq; /* in kHz */ - - /* IF frequency */ - u32 if_freq; /* in kHz */ - - /* Swap I/Q for zero IF */ - u8 zif_swap_iq; - - /* Tuner AGC settings */ - u8 agc_min; - u8 agc_max; - u8 agc_hold_loop; -}; - -#if defined(CONFIG_DVB_ATBM8830) || \ - (defined(CONFIG_DVB_ATBM8830_MODULE) && defined(MODULE)) -extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, - struct i2c_adapter *i2c); -#else -static inline -struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, - struct i2c_adapter *i2c) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_ATBM8830 */ - -#endif /* __ATBM8830_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/atbm8830_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/* - * Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator - * ATBM8830, ATBM8831 - * - * Copyright (C) 2009 David T.L. Wong - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ATBM8830_PRIV_H -#define __ATBM8830_PRIV_H - -struct atbm_state { - struct i2c_adapter *i2c; - /* configuration settings */ - const struct atbm8830_config *config; - struct dvb_frontend frontend; -}; - -#define REG_CHIP_ID 0x0000 -#define REG_TUNER_BASEBAND 0x0001 -#define REG_DEMOD_RUN 0x0004 -#define REG_DSP_RESET 0x0005 -#define REG_RAM_RESET 0x0006 -#define REG_ADC_RESET 0x0007 -#define REG_TSPORT_RESET 0x0008 -#define REG_BLKERR_POL 0x000C -#define REG_I2C_GATE 0x0103 -#define REG_TS_SAMPLE_EDGE 0x0301 -#define REG_TS_PKT_LEN_204 0x0302 -#define REG_TS_PKT_LEN_AUTO 0x0303 -#define REG_TS_SERIAL 0x0305 -#define REG_TS_CLK_FREERUN 0x0306 -#define REG_TS_VALID_MODE 0x0307 -#define REG_TS_CLK_MODE 0x030B /* 1 for serial, 0 for parallel */ - -#define REG_TS_ERRBIT_USE 0x030C -#define REG_LOCK_STATUS 0x030D -#define REG_ADC_CONFIG 0x0602 -#define REG_CARRIER_OFFSET 0x0827 /* 0x0827-0x0829 little endian */ -#define REG_DETECTED_PN_MODE 0x082D -#define REG_READ_LATCH 0x084D -#define REG_IF_FREQ 0x0A00 /* 0x0A00-0x0A02 little endian */ -#define REG_OSC_CLK 0x0A03 /* 0x0A03-0x0A05 little endian */ -#define REG_BYPASS_CCI 0x0A06 -#define REG_ANALOG_LUMA_DETECTED 0x0A25 -#define REG_ANALOG_AUDIO_DETECTED 0x0A26 -#define REG_ANALOG_CHROMA_DETECTED 0x0A39 -#define REG_FRAME_ERR_CNT 0x0B04 -#define REG_USE_EXT_ADC 0x0C00 -#define REG_SWAP_I_Q 0x0C01 -#define REG_TPS_MANUAL 0x0D01 -#define REG_TPS_CONFIG 0x0D02 -#define REG_BYPASS_DEINTERLEAVER 0x0E00 -#define REG_AGC_TARGET 0x1003 /* 0x1003-0x1005 little endian */ -#define REG_AGC_MIN 0x1020 -#define REG_AGC_MAX 0x1023 -#define REG_AGC_LOCK 0x1027 -#define REG_AGC_PWM_VAL 0x1028 /* 0x1028-0x1029 little endian */ -#define REG_AGC_HOLD_LOOP 0x1031 - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_decoder.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_decoder.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,853 +0,0 @@ -/* - * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder - * - * Copyright (C) 2009 Devin Heitmueller - * Copyright (C) 2005-2008 Auvitek International, Ltd. - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/* Developer notes: - * - * VBI support is not yet working - * Enough is implemented here for CVBS and S-Video inputs, but the actual - * analog demodulator code isn't implemented (not needed for xc5000 since it - * has its own demodulator and outputs CVBS) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "au8522.h" -#include "au8522_priv.h" - -MODULE_AUTHOR("Devin Heitmueller"); -MODULE_LICENSE("GPL"); - -static int au8522_analog_debug; - - -module_param_named(analog_debug, au8522_analog_debug, int, 0644); - -MODULE_PARM_DESC(analog_debug, - "Analog debugging messages [0=Off (default) 1=On]"); - -struct au8522_register_config { - u16 reg_name; - u8 reg_val[8]; -}; - - -/* Video Decoder Filter Coefficients - The values are as follows from left to right - 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13" -*/ -static const struct au8522_register_config filter_coef[] = { - {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} }, - {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} }, - {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} }, - {AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} }, - {AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} }, - {AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} }, - {AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} }, - {AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} }, - {AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} }, - {AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} }, - {AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} }, - {AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} }, - {AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} }, - {AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} }, - {AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} }, - {AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} }, - {AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} }, - {AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} }, - {AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} }, - {AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} }, - {AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} }, - {AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} }, - {AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} }, - {AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} }, - {AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} }, - {AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} }, - {AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} }, - {AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} }, - {AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} }, - {AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} }, - -}; -#define NUM_FILTER_COEF (sizeof(filter_coef)\ - / sizeof(struct au8522_register_config)) - - -/* Registers 0x060b through 0x0652 are the LP Filter coefficients - The values are as follows from left to right - 0="SIF" 1="ATVRF/ATVRF13" - Note: the "ATVRF/ATVRF13" mode has never been tested -*/ -static const struct au8522_register_config lpfilter_coef[] = { - {0x060b, {0x21, 0x0b} }, - {0x060c, {0xad, 0xad} }, - {0x060d, {0x70, 0xf0} }, - {0x060e, {0xea, 0xe9} }, - {0x060f, {0xdd, 0xdd} }, - {0x0610, {0x08, 0x64} }, - {0x0611, {0x60, 0x60} }, - {0x0612, {0xf8, 0xb2} }, - {0x0613, {0x01, 0x02} }, - {0x0614, {0xe4, 0xb4} }, - {0x0615, {0x19, 0x02} }, - {0x0616, {0xae, 0x2e} }, - {0x0617, {0xee, 0xc5} }, - {0x0618, {0x56, 0x56} }, - {0x0619, {0x30, 0x58} }, - {0x061a, {0xf9, 0xf8} }, - {0x061b, {0x24, 0x64} }, - {0x061c, {0x07, 0x07} }, - {0x061d, {0x30, 0x30} }, - {0x061e, {0xa9, 0xed} }, - {0x061f, {0x09, 0x0b} }, - {0x0620, {0x42, 0xc2} }, - {0x0621, {0x1d, 0x2a} }, - {0x0622, {0xd6, 0x56} }, - {0x0623, {0x95, 0x8b} }, - {0x0624, {0x2b, 0x2b} }, - {0x0625, {0x30, 0x24} }, - {0x0626, {0x3e, 0x3e} }, - {0x0627, {0x62, 0xe2} }, - {0x0628, {0xe9, 0xf5} }, - {0x0629, {0x99, 0x19} }, - {0x062a, {0xd4, 0x11} }, - {0x062b, {0x03, 0x04} }, - {0x062c, {0xb5, 0x85} }, - {0x062d, {0x1e, 0x20} }, - {0x062e, {0x2a, 0xea} }, - {0x062f, {0xd7, 0xd2} }, - {0x0630, {0x15, 0x15} }, - {0x0631, {0xa3, 0xa9} }, - {0x0632, {0x1f, 0x1f} }, - {0x0633, {0xf9, 0xd1} }, - {0x0634, {0xc0, 0xc3} }, - {0x0635, {0x4d, 0x8d} }, - {0x0636, {0x21, 0x31} }, - {0x0637, {0x83, 0x83} }, - {0x0638, {0x08, 0x8c} }, - {0x0639, {0x19, 0x19} }, - {0x063a, {0x45, 0xa5} }, - {0x063b, {0xef, 0xec} }, - {0x063c, {0x8a, 0x8a} }, - {0x063d, {0xf4, 0xf6} }, - {0x063e, {0x8f, 0x8f} }, - {0x063f, {0x44, 0x0c} }, - {0x0640, {0xef, 0xf0} }, - {0x0641, {0x66, 0x66} }, - {0x0642, {0xcc, 0xd2} }, - {0x0643, {0x41, 0x41} }, - {0x0644, {0x63, 0x93} }, - {0x0645, {0x8e, 0x8e} }, - {0x0646, {0xa2, 0x42} }, - {0x0647, {0x7b, 0x7b} }, - {0x0648, {0x04, 0x04} }, - {0x0649, {0x00, 0x00} }, - {0x064a, {0x40, 0x40} }, - {0x064b, {0x8c, 0x98} }, - {0x064c, {0x00, 0x00} }, - {0x064d, {0x63, 0xc3} }, - {0x064e, {0x04, 0x04} }, - {0x064f, {0x20, 0x20} }, - {0x0650, {0x00, 0x00} }, - {0x0651, {0x40, 0x40} }, - {0x0652, {0x01, 0x01} }, -}; -#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\ - / sizeof(struct au8522_register_config)) - -static inline struct au8522_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct au8522_state, sd); -} - -static void setup_vbi(struct au8522_state *state, int aud_input) -{ - int i; - - /* These are set to zero regardless of what mode we're in */ - au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_L_REG018H, 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H, 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH, 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH, 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_THRESH1_REG01CH, 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH, 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH, 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H, 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H, - 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H, - 0x00); - au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H, - 0x00); - - /* Setup the VBI registers */ - for (i = 0x30; i < 0x60; i++) - au8522_writereg(state, i, 0x40); - - /* For some reason, every register is 0x40 except register 0x44 - (confirmed via the HVR-950q USB capture) */ - au8522_writereg(state, 0x44, 0x60); - - /* Enable VBI (we always do this regardless of whether the user is - viewing closed caption info) */ - au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, - AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON); - -} - -static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode) -{ - int i; - int filter_coef_type; - - /* Provide reasonable defaults for picture tuning values */ - au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07); - au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed); - state->brightness = 0xed - 128; - au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79); - state->contrast = 0x79; - au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80); - au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80); - state->saturation = 0x80; - au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00); - au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00); - state->hue = 0x00; - - /* Other decoder registers */ - au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00); - - if (input_mode == 0x23) { - /* S-Video input mapping */ - au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04); - } else { - /* All other modes (CVBS/ATVRF etc.) */ - au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00); - } - - au8522_writereg(state, AU8522_TVDEC_PGA_REG012H, - AU8522_TVDEC_PGA_REG012H_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H, - AU8522_TVDEC_COMB_MODE_REG015H_CVBS); - au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H, - AU8522_TVDED_DBG_MODE_REG060H_CVBS); - au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H, - AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13); - au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H, - AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13); - au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H, - AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS); - au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H, - AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H, - AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H, - AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H, - AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H, - AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H, - AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH, - AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH, - AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS); - if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 || - input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) { - au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH, - AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO); - au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH, - AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO); - } else { - au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH, - AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH, - AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS); - } - au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH, - AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS); - au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH, - AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H, - AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS); - au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS); - au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS); - au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H, - AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS); - au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS); - au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS); - au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H, - AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS); - au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H, - AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS); - au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H, - AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS); - au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH, - AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS); - au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH, - AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS); - au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H, - AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS); - au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H, - AU8522_TOREGAAGC_REG0E5H_CVBS); - au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS); - - setup_vbi(state, 0); - - if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 || - input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) { - /* Despite what the table says, for the HVR-950q we still need - to be in CVBS mode for the S-Video input (reason unknown). */ - /* filter_coef_type = 3; */ - filter_coef_type = 5; - } else { - filter_coef_type = 5; - } - - /* Load the Video Decoder Filter Coefficients */ - for (i = 0; i < NUM_FILTER_COEF; i++) { - au8522_writereg(state, filter_coef[i].reg_name, - filter_coef[i].reg_val[filter_coef_type]); - } - - /* It's not clear what these registers are for, but they are always - set to the same value regardless of what mode we're in */ - au8522_writereg(state, AU8522_REG42EH, 0x87); - au8522_writereg(state, AU8522_REG42FH, 0xa2); - au8522_writereg(state, AU8522_REG430H, 0xbf); - au8522_writereg(state, AU8522_REG431H, 0xcb); - au8522_writereg(state, AU8522_REG432H, 0xa1); - au8522_writereg(state, AU8522_REG433H, 0x41); - au8522_writereg(state, AU8522_REG434H, 0x88); - au8522_writereg(state, AU8522_REG435H, 0xc2); - au8522_writereg(state, AU8522_REG436H, 0x3c); -} - -static void au8522_setup_cvbs_mode(struct au8522_state *state) -{ - /* here we're going to try the pre-programmed route */ - au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H, - AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS); - - /* PGA in automatic mode */ - au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00); - - /* Enable clamping control */ - au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00); - - au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, - AU8522_INPUT_CONTROL_REG081H_CVBS_CH1); - - setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1); - - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, - AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); -} - -static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state) -{ - /* here we're going to try the pre-programmed route */ - au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H, - AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS); - - /* It's not clear why we have to have the PGA in automatic mode while - enabling clamp control, but it's what Windows does */ - au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00); - - /* Enable clamping control */ - au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e); - - /* Disable automatic PGA (since the CVBS is coming from the tuner) */ - au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10); - - /* Set input mode to CVBS on channel 4 with SIF audio input enabled */ - au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, - AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF); - - setup_decoder_defaults(state, - AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF); - - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, - AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); -} - -static void au8522_setup_svideo_mode(struct au8522_state *state) -{ - au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H, - AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO); - - /* Set input to Y on Channe1, C on Channel 3 */ - au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, - AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13); - - /* PGA in automatic mode */ - au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00); - - /* Enable clamping control */ - au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00); - - setup_decoder_defaults(state, - AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13); - - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, - AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); -} - -/* ----------------------------------------------------------------------- */ - -static void disable_audio_input(struct au8522_state *state) -{ - au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00); - au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00); - au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00); - - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04); - au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02); - - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, - AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO); -} - -/* 0=disable, 1=SIF */ -static void set_audio_input(struct au8522_state *state, int aud_input) -{ - int i; - - /* Note that this function needs to be used in conjunction with setting - the input routing via register 0x81 */ - - if (aud_input == AU8522_AUDIO_NONE) { - disable_audio_input(state); - return; - } - - if (aud_input != AU8522_AUDIO_SIF) { - /* The caller asked for a mode we don't currently support */ - printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n", - aud_input); - return; - } - - /* Load the Audio Decoder Filter Coefficients */ - for (i = 0; i < NUM_LPFILTER_COEF; i++) { - au8522_writereg(state, lpfilter_coef[i].reg_name, - lpfilter_coef[i].reg_val[0]); - } - - /* Setup audio */ - au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00); - au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00); - au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00); - au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80); - au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84); - msleep(150); - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00); - msleep(1); - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d); - msleep(50); - au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F); - au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F); - au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff); - msleep(80); - au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F); - au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F); - au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO); - au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82); - msleep(70); - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09); - au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03); - au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2); -} - -/* ----------------------------------------------------------------------- */ - -static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct au8522_state *state = to_state(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - state->brightness = ctrl->value; - au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, - ctrl->value - 128); - break; - case V4L2_CID_CONTRAST: - state->contrast = ctrl->value; - au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, - ctrl->value); - break; - case V4L2_CID_SATURATION: - state->saturation = ctrl->value; - au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, - ctrl->value); - au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, - ctrl->value); - break; - case V4L2_CID_HUE: - state->hue = ctrl->value; - au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, - ctrl->value >> 8); - au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, - ctrl->value & 0xFF); - break; - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_MUTE: - /* Not yet implemented */ - default: - return -EINVAL; - } - - return 0; -} - -static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct au8522_state *state = to_state(sd); - - /* Note that we are using values cached in the state structure instead - of reading the registers due to issues with i2c reads not working - properly/consistently yet on the HVR-950q */ - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = state->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = state->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = state->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = state->hue; - break; - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_MUTE: - /* Not yet supported */ - default: - return -EINVAL; - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int au8522_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct au8522_state *state = to_state(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->val = au8522_readreg(state, reg->reg & 0xffff); - return 0; -} - -static int au8522_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct au8522_state *state = to_state(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - au8522_writereg(state, reg->reg, reg->val & 0xff); - return 0; -} -#endif - -static int au8522_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct au8522_state *state = to_state(sd); - - if (enable) { - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, - 0x01); - msleep(1); - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, - AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); - } else { - /* This does not completely power down the device - (it only reduces it from around 140ma to 80ma) */ - au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, - 1 << 5); - } - return 0; -} - -static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, - AU8522_TVDEC_CONTRAST_REG00BH_CVBS); - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0); - default: - break; - } - - qc->type = 0; - return -EINVAL; -} - -static int au8522_reset(struct v4l2_subdev *sd, u32 val) -{ - struct au8522_state *state = to_state(sd); - - state->operational_mode = AU8522_ANALOG_MODE; - - /* Clear out any state associated with the digital side of the - chip, so that when it gets powered back up it won't think - that it is already tuned */ - state->current_frequency = 0; - - au8522_writereg(state, 0xa4, 1 << 5); - - return 0; -} - -static int au8522_s_video_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct au8522_state *state = to_state(sd); - - au8522_reset(sd, 0); - - /* Jam open the i2c gate to the tuner. We do this here to handle the - case where the user went into digital mode (causing the gate to be - closed), and then came back to analog mode */ - au8522_writereg(state, 0x106, 1); - - if (input == AU8522_COMPOSITE_CH1) { - au8522_setup_cvbs_mode(state); - } else if (input == AU8522_SVIDEO_CH13) { - au8522_setup_svideo_mode(state); - } else if (input == AU8522_COMPOSITE_CH4_SIF) { - au8522_setup_cvbs_tuner_mode(state); - } else { - printk(KERN_ERR "au8522 mode not currently supported\n"); - return -EINVAL; - } - return 0; -} - -static int au8522_s_audio_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct au8522_state *state = to_state(sd); - set_audio_input(state, input); - return 0; -} - -static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - int val = 0; - struct au8522_state *state = to_state(sd); - u8 lock_status; - - /* Interrogate the decoder to see if we are getting a real signal */ - lock_status = au8522_readreg(state, 0x00); - if (lock_status == 0xa2) - vt->signal = 0x01; - else - vt->signal = 0x00; - - vt->capability |= - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - - val = V4L2_TUNER_SUB_MONO; - vt->rxsubchans = val; - vt->audmode = V4L2_TUNER_MODE_STEREO; - return 0; -} - -static int au8522_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct au8522_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev); -} - -static int au8522_log_status(struct v4l2_subdev *sd) -{ - /* FIXME: Add some status info here */ - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops au8522_core_ops = { - .log_status = au8522_log_status, - .g_chip_ident = au8522_g_chip_ident, - .g_ctrl = au8522_g_ctrl, - .s_ctrl = au8522_s_ctrl, - .queryctrl = au8522_queryctrl, - .reset = au8522_reset, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = au8522_g_register, - .s_register = au8522_s_register, -#endif -}; - -static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = { - .g_tuner = au8522_g_tuner, -}; - -static const struct v4l2_subdev_audio_ops au8522_audio_ops = { - .s_routing = au8522_s_audio_routing, -}; - -static const struct v4l2_subdev_video_ops au8522_video_ops = { - .s_routing = au8522_s_video_routing, - .s_stream = au8522_s_stream, -}; - -static const struct v4l2_subdev_ops au8522_ops = { - .core = &au8522_core_ops, - .tuner = &au8522_tuner_ops, - .audio = &au8522_audio_ops, - .video = &au8522_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int au8522_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct au8522_state *state; - struct v4l2_subdev *sd; - int instance; - struct au8522_config *demod_config; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - return -EIO; - } - - /* allocate memory for the internal state */ - instance = au8522_get_state(&state, client->adapter, client->addr); - switch (instance) { - case 0: - printk(KERN_ERR "au8522_decoder allocation failed\n"); - return -EIO; - case 1: - /* new demod instance */ - printk(KERN_INFO "au8522_decoder creating new instance...\n"); - break; - default: - /* existing demod instance */ - printk(KERN_INFO "au8522_decoder attach existing instance.\n"); - break; - } - - demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL); - if (demod_config == NULL) { - if (instance == 1) - kfree(state); - return -ENOMEM; - } - demod_config->demod_address = 0x8e >> 1; - - state->config = demod_config; - state->i2c = client->adapter; - - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &au8522_ops); - - state->c = client; - state->vid_input = AU8522_COMPOSITE_CH1; - state->aud_input = AU8522_AUDIO_NONE; - state->id = 8522; - state->rev = 0; - - /* Jam open the i2c gate to the tuner */ - au8522_writereg(state, 0x106, 1); - - return 0; -} - -static int au8522_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - v4l2_device_unregister_subdev(sd); - au8522_release_state(to_state(sd)); - return 0; -} - -static const struct i2c_device_id au8522_id[] = { - {"au8522", 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, au8522_id); - -static struct i2c_driver au8522_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "au8522", - }, - .probe = au8522_probe, - .remove = au8522_remove, - .id_table = au8522_id, -}; - -static __init int init_au8522(void) -{ - return i2c_add_driver(&au8522_driver); -} - -static __exit void exit_au8522(void) -{ - i2c_del_driver(&au8522_driver); -} - -module_init(init_au8522); -module_exit(exit_au8522); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_dig.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_dig.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_dig.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_dig.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1013 +0,0 @@ -/* - Auvitek AU8522 QAM/8VSB demodulator driver - - Copyright (C) 2008 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "au8522.h" -#include "au8522_priv.h" - -static int debug; - -/* Despite the name "hybrid_tuner", the framework works just as well for - hybrid demodulators as well... */ -static LIST_HEAD(hybrid_tuner_instance_list); -static DEFINE_MUTEX(au8522_list_mutex); - -#define dprintk(arg...)\ - do { if (debug)\ - printk(arg);\ - } while (0) - -/* 16 bit registers, 8 bit values */ -int au8522_writereg(struct au8522_state *state, u16 reg, u8 data) -{ - int ret; - u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data }; - - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = 0, .buf = buf, .len = 3 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " - "ret == %i)\n", __func__, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -u8 au8522_readreg(struct au8522_state *state, u16 reg) -{ - int ret; - u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff }; - u8 b1[] = { 0 }; - - struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, - .buf = b0, .len = 2 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, - .buf = b1, .len = 1 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - printk(KERN_ERR "%s: readreg error (ret == %i)\n", - __func__, ret); - return b1[0]; -} - -static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct au8522_state *state = fe->demodulator_priv; - - dprintk("%s(%d)\n", __func__, enable); - - if (state->operational_mode == AU8522_ANALOG_MODE) { - /* We're being asked to manage the gate even though we're - not in digital mode. This can occur if we get switched - over to analog mode before the dvb_frontend kernel thread - has completely shutdown */ - return 0; - } - - if (enable) - return au8522_writereg(state, 0x106, 1); - else - return au8522_writereg(state, 0x106, 0); -} - -struct mse2snr_tab { - u16 val; - u16 data; -}; - -/* VSB SNR lookup table */ -static struct mse2snr_tab vsb_mse2snr_tab[] = { - { 0, 270 }, - { 2, 250 }, - { 3, 240 }, - { 5, 230 }, - { 7, 220 }, - { 9, 210 }, - { 12, 200 }, - { 13, 195 }, - { 15, 190 }, - { 17, 185 }, - { 19, 180 }, - { 21, 175 }, - { 24, 170 }, - { 27, 165 }, - { 31, 160 }, - { 32, 158 }, - { 33, 156 }, - { 36, 152 }, - { 37, 150 }, - { 39, 148 }, - { 40, 146 }, - { 41, 144 }, - { 43, 142 }, - { 44, 140 }, - { 48, 135 }, - { 50, 130 }, - { 43, 142 }, - { 53, 125 }, - { 56, 120 }, - { 256, 115 }, -}; - -/* QAM64 SNR lookup table */ -static struct mse2snr_tab qam64_mse2snr_tab[] = { - { 15, 0 }, - { 16, 290 }, - { 17, 288 }, - { 18, 286 }, - { 19, 284 }, - { 20, 282 }, - { 21, 281 }, - { 22, 279 }, - { 23, 277 }, - { 24, 275 }, - { 25, 273 }, - { 26, 271 }, - { 27, 269 }, - { 28, 268 }, - { 29, 266 }, - { 30, 264 }, - { 31, 262 }, - { 32, 260 }, - { 33, 259 }, - { 34, 258 }, - { 35, 256 }, - { 36, 255 }, - { 37, 254 }, - { 38, 252 }, - { 39, 251 }, - { 40, 250 }, - { 41, 249 }, - { 42, 248 }, - { 43, 246 }, - { 44, 245 }, - { 45, 244 }, - { 46, 242 }, - { 47, 241 }, - { 48, 240 }, - { 50, 239 }, - { 51, 238 }, - { 53, 237 }, - { 54, 236 }, - { 56, 235 }, - { 57, 234 }, - { 59, 233 }, - { 60, 232 }, - { 62, 231 }, - { 63, 230 }, - { 65, 229 }, - { 67, 228 }, - { 68, 227 }, - { 70, 226 }, - { 71, 225 }, - { 73, 224 }, - { 74, 223 }, - { 76, 222 }, - { 78, 221 }, - { 80, 220 }, - { 82, 219 }, - { 85, 218 }, - { 88, 217 }, - { 90, 216 }, - { 92, 215 }, - { 93, 214 }, - { 94, 212 }, - { 95, 211 }, - { 97, 210 }, - { 99, 209 }, - { 101, 208 }, - { 102, 207 }, - { 104, 206 }, - { 107, 205 }, - { 111, 204 }, - { 114, 203 }, - { 118, 202 }, - { 122, 201 }, - { 125, 200 }, - { 128, 199 }, - { 130, 198 }, - { 132, 197 }, - { 256, 190 }, -}; - -/* QAM256 SNR lookup table */ -static struct mse2snr_tab qam256_mse2snr_tab[] = { - { 16, 0 }, - { 17, 400 }, - { 18, 398 }, - { 19, 396 }, - { 20, 394 }, - { 21, 392 }, - { 22, 390 }, - { 23, 388 }, - { 24, 386 }, - { 25, 384 }, - { 26, 382 }, - { 27, 380 }, - { 28, 379 }, - { 29, 378 }, - { 30, 377 }, - { 31, 376 }, - { 32, 375 }, - { 33, 374 }, - { 34, 373 }, - { 35, 372 }, - { 36, 371 }, - { 37, 370 }, - { 38, 362 }, - { 39, 354 }, - { 40, 346 }, - { 41, 338 }, - { 42, 330 }, - { 43, 328 }, - { 44, 326 }, - { 45, 324 }, - { 46, 322 }, - { 47, 320 }, - { 48, 319 }, - { 49, 318 }, - { 50, 317 }, - { 51, 316 }, - { 52, 315 }, - { 53, 314 }, - { 54, 313 }, - { 55, 312 }, - { 56, 311 }, - { 57, 310 }, - { 58, 308 }, - { 59, 306 }, - { 60, 304 }, - { 61, 302 }, - { 62, 300 }, - { 63, 298 }, - { 65, 295 }, - { 68, 294 }, - { 70, 293 }, - { 73, 292 }, - { 76, 291 }, - { 78, 290 }, - { 79, 289 }, - { 81, 288 }, - { 82, 287 }, - { 83, 286 }, - { 84, 285 }, - { 85, 284 }, - { 86, 283 }, - { 88, 282 }, - { 89, 281 }, - { 256, 280 }, -}; - -static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse, - u16 *snr) -{ - int i, ret = -EINVAL; - dprintk("%s()\n", __func__); - - for (i = 0; i < sz; i++) { - if (mse < tab[i].val) { - *snr = tab[i].data; - ret = 0; - break; - } - } - dprintk("%s() snr=%d\n", __func__, *snr); - return ret; -} - -static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq) -{ - struct au8522_state *state = fe->demodulator_priv; - u8 r0b5, r0b6, r0b7; - char *ifmhz; - - switch (if_freq) { - case AU8522_IF_3_25MHZ: - ifmhz = "3.25"; - r0b5 = 0x00; - r0b6 = 0x3d; - r0b7 = 0xa0; - break; - case AU8522_IF_4MHZ: - ifmhz = "4.00"; - r0b5 = 0x00; - r0b6 = 0x4b; - r0b7 = 0xd9; - break; - case AU8522_IF_6MHZ: - ifmhz = "6.00"; - r0b5 = 0xfb; - r0b6 = 0x8e; - r0b7 = 0x39; - break; - default: - dprintk("%s() IF Frequency not supported\n", __func__); - return -EINVAL; - } - dprintk("%s() %s MHz\n", __func__, ifmhz); - au8522_writereg(state, 0x80b5, r0b5); - au8522_writereg(state, 0x80b6, r0b6); - au8522_writereg(state, 0x80b7, r0b7); - - return 0; -} - -/* VSB Modulation table */ -static struct { - u16 reg; - u16 data; -} VSB_mod_tab[] = { - { 0x8090, 0x84 }, - { 0x4092, 0x11 }, - { 0x2005, 0x00 }, - { 0x8091, 0x80 }, - { 0x80a3, 0x0c }, - { 0x80a4, 0xe8 }, - { 0x8081, 0xc4 }, - { 0x80a5, 0x40 }, - { 0x80a7, 0x40 }, - { 0x80a6, 0x67 }, - { 0x8262, 0x20 }, - { 0x821c, 0x30 }, - { 0x80d8, 0x1a }, - { 0x8227, 0xa0 }, - { 0x8121, 0xff }, - { 0x80a8, 0xf0 }, - { 0x80a9, 0x05 }, - { 0x80aa, 0x77 }, - { 0x80ab, 0xf0 }, - { 0x80ac, 0x05 }, - { 0x80ad, 0x77 }, - { 0x80ae, 0x41 }, - { 0x80af, 0x66 }, - { 0x821b, 0xcc }, - { 0x821d, 0x80 }, - { 0x80a4, 0xe8 }, - { 0x8231, 0x13 }, -}; - -/* QAM64 Modulation table */ -static struct { - u16 reg; - u16 data; -} QAM64_mod_tab[] = { - { 0x00a3, 0x09 }, - { 0x00a4, 0x00 }, - { 0x0081, 0xc4 }, - { 0x00a5, 0x40 }, - { 0x00aa, 0x77 }, - { 0x00ad, 0x77 }, - { 0x00a6, 0x67 }, - { 0x0262, 0x20 }, - { 0x021c, 0x30 }, - { 0x00b8, 0x3e }, - { 0x00b9, 0xf0 }, - { 0x00ba, 0x01 }, - { 0x00bb, 0x18 }, - { 0x00bc, 0x50 }, - { 0x00bd, 0x00 }, - { 0x00be, 0xea }, - { 0x00bf, 0xef }, - { 0x00c0, 0xfc }, - { 0x00c1, 0xbd }, - { 0x00c2, 0x1f }, - { 0x00c3, 0xfc }, - { 0x00c4, 0xdd }, - { 0x00c5, 0xaf }, - { 0x00c6, 0x00 }, - { 0x00c7, 0x38 }, - { 0x00c8, 0x30 }, - { 0x00c9, 0x05 }, - { 0x00ca, 0x4a }, - { 0x00cb, 0xd0 }, - { 0x00cc, 0x01 }, - { 0x00cd, 0xd9 }, - { 0x00ce, 0x6f }, - { 0x00cf, 0xf9 }, - { 0x00d0, 0x70 }, - { 0x00d1, 0xdf }, - { 0x00d2, 0xf7 }, - { 0x00d3, 0xc2 }, - { 0x00d4, 0xdf }, - { 0x00d5, 0x02 }, - { 0x00d6, 0x9a }, - { 0x00d7, 0xd0 }, - { 0x0250, 0x0d }, - { 0x0251, 0xcd }, - { 0x0252, 0xe0 }, - { 0x0253, 0x05 }, - { 0x0254, 0xa7 }, - { 0x0255, 0xff }, - { 0x0256, 0xed }, - { 0x0257, 0x5b }, - { 0x0258, 0xae }, - { 0x0259, 0xe6 }, - { 0x025a, 0x3d }, - { 0x025b, 0x0f }, - { 0x025c, 0x0d }, - { 0x025d, 0xea }, - { 0x025e, 0xf2 }, - { 0x025f, 0x51 }, - { 0x0260, 0xf5 }, - { 0x0261, 0x06 }, - { 0x021a, 0x00 }, - { 0x0546, 0x40 }, - { 0x0210, 0xc7 }, - { 0x0211, 0xaa }, - { 0x0212, 0xab }, - { 0x0213, 0x02 }, - { 0x0502, 0x00 }, - { 0x0121, 0x04 }, - { 0x0122, 0x04 }, - { 0x052e, 0x10 }, - { 0x00a4, 0xca }, - { 0x00a7, 0x40 }, - { 0x0526, 0x01 }, -}; - -/* QAM256 Modulation table */ -static struct { - u16 reg; - u16 data; -} QAM256_mod_tab[] = { - { 0x80a3, 0x09 }, - { 0x80a4, 0x00 }, - { 0x8081, 0xc4 }, - { 0x80a5, 0x40 }, - { 0x80aa, 0x77 }, - { 0x80ad, 0x77 }, - { 0x80a6, 0x67 }, - { 0x8262, 0x20 }, - { 0x821c, 0x30 }, - { 0x80b8, 0x3e }, - { 0x80b9, 0xf0 }, - { 0x80ba, 0x01 }, - { 0x80bb, 0x18 }, - { 0x80bc, 0x50 }, - { 0x80bd, 0x00 }, - { 0x80be, 0xea }, - { 0x80bf, 0xef }, - { 0x80c0, 0xfc }, - { 0x80c1, 0xbd }, - { 0x80c2, 0x1f }, - { 0x80c3, 0xfc }, - { 0x80c4, 0xdd }, - { 0x80c5, 0xaf }, - { 0x80c6, 0x00 }, - { 0x80c7, 0x38 }, - { 0x80c8, 0x30 }, - { 0x80c9, 0x05 }, - { 0x80ca, 0x4a }, - { 0x80cb, 0xd0 }, - { 0x80cc, 0x01 }, - { 0x80cd, 0xd9 }, - { 0x80ce, 0x6f }, - { 0x80cf, 0xf9 }, - { 0x80d0, 0x70 }, - { 0x80d1, 0xdf }, - { 0x80d2, 0xf7 }, - { 0x80d3, 0xc2 }, - { 0x80d4, 0xdf }, - { 0x80d5, 0x02 }, - { 0x80d6, 0x9a }, - { 0x80d7, 0xd0 }, - { 0x8250, 0x0d }, - { 0x8251, 0xcd }, - { 0x8252, 0xe0 }, - { 0x8253, 0x05 }, - { 0x8254, 0xa7 }, - { 0x8255, 0xff }, - { 0x8256, 0xed }, - { 0x8257, 0x5b }, - { 0x8258, 0xae }, - { 0x8259, 0xe6 }, - { 0x825a, 0x3d }, - { 0x825b, 0x0f }, - { 0x825c, 0x0d }, - { 0x825d, 0xea }, - { 0x825e, 0xf2 }, - { 0x825f, 0x51 }, - { 0x8260, 0xf5 }, - { 0x8261, 0x06 }, - { 0x821a, 0x00 }, - { 0x8546, 0x40 }, - { 0x8210, 0x26 }, - { 0x8211, 0xf6 }, - { 0x8212, 0x84 }, - { 0x8213, 0x02 }, - { 0x8502, 0x01 }, - { 0x8121, 0x04 }, - { 0x8122, 0x04 }, - { 0x852e, 0x10 }, - { 0x80a4, 0xca }, - { 0x80a7, 0x40 }, - { 0x8526, 0x01 }, -}; - -static int au8522_enable_modulation(struct dvb_frontend *fe, - fe_modulation_t m) -{ - struct au8522_state *state = fe->demodulator_priv; - int i; - - dprintk("%s(0x%08x)\n", __func__, m); - - switch (m) { - case VSB_8: - dprintk("%s() VSB_8\n", __func__); - for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++) - au8522_writereg(state, - VSB_mod_tab[i].reg, - VSB_mod_tab[i].data); - au8522_set_if(fe, state->config->vsb_if); - break; - case QAM_64: - dprintk("%s() QAM 64\n", __func__); - for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++) - au8522_writereg(state, - QAM64_mod_tab[i].reg, - QAM64_mod_tab[i].data); - au8522_set_if(fe, state->config->qam_if); - break; - case QAM_256: - dprintk("%s() QAM 256\n", __func__); - for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++) - au8522_writereg(state, - QAM256_mod_tab[i].reg, - QAM256_mod_tab[i].data); - au8522_set_if(fe, state->config->qam_if); - break; - default: - dprintk("%s() Invalid modulation\n", __func__); - return -EINVAL; - } - - state->current_modulation = m; - - return 0; -} - -/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int au8522_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct au8522_state *state = fe->demodulator_priv; - int ret = -EINVAL; - - dprintk("%s(frequency=%d)\n", __func__, p->frequency); - - if ((state->current_frequency == p->frequency) && - (state->current_modulation == p->u.vsb.modulation)) - return 0; - - au8522_enable_modulation(fe, p->u.vsb.modulation); - - /* Allow the demod to settle */ - msleep(100); - - if (fe->ops.tuner_ops.set_params) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - if (ret < 0) - return ret; - - state->current_frequency = p->frequency; - - return 0; -} - -/* Reset the demod hardware and reset all of the configuration registers - to a default state. */ -int au8522_init(struct dvb_frontend *fe) -{ - struct au8522_state *state = fe->demodulator_priv; - dprintk("%s()\n", __func__); - - state->operational_mode = AU8522_DIGITAL_MODE; - - /* Clear out any state associated with the digital side of the - chip, so that when it gets powered back up it won't think - that it is already tuned */ - state->current_frequency = 0; - - au8522_writereg(state, 0xa4, 1 << 5); - - au8522_i2c_gate_ctrl(fe, 1); - - return 0; -} - -static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) -{ - struct au8522_led_config *led_config = state->config->led_cfg; - u8 val; - - /* bail out if we cant control an LED */ - if (!led_config || !led_config->gpio_output || - !led_config->gpio_output_enable || !led_config->gpio_output_disable) - return 0; - - val = au8522_readreg(state, 0x4000 | - (led_config->gpio_output & ~0xc000)); - if (onoff) { - /* enable GPIO output */ - val &= ~((led_config->gpio_output_enable >> 8) & 0xff); - val |= (led_config->gpio_output_enable & 0xff); - } else { - /* disable GPIO output */ - val &= ~((led_config->gpio_output_disable >> 8) & 0xff); - val |= (led_config->gpio_output_disable & 0xff); - } - return au8522_writereg(state, 0x8000 | - (led_config->gpio_output & ~0xc000), val); -} - -/* led = 0 | off - * led = 1 | signal ok - * led = 2 | signal strong - * led < 0 | only light led if leds are currently off - */ -static int au8522_led_ctrl(struct au8522_state *state, int led) -{ - struct au8522_led_config *led_config = state->config->led_cfg; - int i, ret = 0; - - /* bail out if we cant control an LED */ - if (!led_config || !led_config->gpio_leds || - !led_config->num_led_states || !led_config->led_states) - return 0; - - if (led < 0) { - /* if LED is already lit, then leave it as-is */ - if (state->led_state) - return 0; - else - led *= -1; - } - - /* toggle LED if changing state */ - if (state->led_state != led) { - u8 val; - - dprintk("%s: %d\n", __func__, led); - - au8522_led_gpio_enable(state, 1); - - val = au8522_readreg(state, 0x4000 | - (led_config->gpio_leds & ~0xc000)); - - /* start with all leds off */ - for (i = 0; i < led_config->num_led_states; i++) - val &= ~led_config->led_states[i]; - - /* set selected LED state */ - if (led < led_config->num_led_states) - val |= led_config->led_states[led]; - else if (led_config->num_led_states) - val |= - led_config->led_states[led_config->num_led_states - 1]; - - ret = au8522_writereg(state, 0x8000 | - (led_config->gpio_leds & ~0xc000), val); - if (ret < 0) - return ret; - - state->led_state = led; - - if (led == 0) - au8522_led_gpio_enable(state, 0); - } - - return 0; -} - -int au8522_sleep(struct dvb_frontend *fe) -{ - struct au8522_state *state = fe->demodulator_priv; - dprintk("%s()\n", __func__); - - /* Only power down if the digital side is currently using the chip */ - if (state->operational_mode == AU8522_ANALOG_MODE) { - /* We're not in one of the expected power modes, which means - that the DVB thread is probably telling us to go to sleep - even though the analog frontend has already started using - the chip. So ignore the request */ - return 0; - } - - /* turn off led */ - au8522_led_ctrl(state, 0); - - /* Power down the chip */ - au8522_writereg(state, 0xa4, 1 << 5); - - state->current_frequency = 0; - - return 0; -} - -static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct au8522_state *state = fe->demodulator_priv; - u8 reg; - u32 tuner_status = 0; - - *status = 0; - - if (state->current_modulation == VSB_8) { - dprintk("%s() Checking VSB_8\n", __func__); - reg = au8522_readreg(state, 0x4088); - if ((reg & 0x03) == 0x03) - *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; - } else { - dprintk("%s() Checking QAM\n", __func__); - reg = au8522_readreg(state, 0x4541); - if (reg & 0x80) - *status |= FE_HAS_VITERBI; - if (reg & 0x20) - *status |= FE_HAS_LOCK | FE_HAS_SYNC; - } - - switch (state->config->status_mode) { - case AU8522_DEMODLOCKING: - dprintk("%s() DEMODLOCKING\n", __func__); - if (*status & FE_HAS_VITERBI) - *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; - break; - case AU8522_TUNERLOCKING: - /* Get the tuner status */ - dprintk("%s() TUNERLOCKING\n", __func__); - if (fe->ops.tuner_ops.get_status) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - fe->ops.tuner_ops.get_status(fe, &tuner_status); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - if (tuner_status) - *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; - break; - } - state->fe_status = *status; - - if (*status & FE_HAS_LOCK) - /* turn on LED, if it isn't on already */ - au8522_led_ctrl(state, -1); - else - /* turn off LED */ - au8522_led_ctrl(state, 0); - - dprintk("%s() status 0x%08x\n", __func__, *status); - - return 0; -} - -static int au8522_led_status(struct au8522_state *state, const u16 *snr) -{ - struct au8522_led_config *led_config = state->config->led_cfg; - int led; - u16 strong; - - /* bail out if we cant control an LED */ - if (!led_config) - return 0; - - if (0 == (state->fe_status & FE_HAS_LOCK)) - return au8522_led_ctrl(state, 0); - else if (state->current_modulation == QAM_256) - strong = led_config->qam256_strong; - else if (state->current_modulation == QAM_64) - strong = led_config->qam64_strong; - else /* (state->current_modulation == VSB_8) */ - strong = led_config->vsb8_strong; - - if (*snr >= strong) - led = 2; - else - led = 1; - - if ((state->led_state) && - (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10)) - /* snr didn't change enough to bother - * changing the color of the led */ - return 0; - - return au8522_led_ctrl(state, led); -} - -static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct au8522_state *state = fe->demodulator_priv; - int ret = -EINVAL; - - dprintk("%s()\n", __func__); - - if (state->current_modulation == QAM_256) - ret = au8522_mse2snr_lookup(qam256_mse2snr_tab, - ARRAY_SIZE(qam256_mse2snr_tab), - au8522_readreg(state, 0x4522), - snr); - else if (state->current_modulation == QAM_64) - ret = au8522_mse2snr_lookup(qam64_mse2snr_tab, - ARRAY_SIZE(qam64_mse2snr_tab), - au8522_readreg(state, 0x4522), - snr); - else /* VSB_8 */ - ret = au8522_mse2snr_lookup(vsb_mse2snr_tab, - ARRAY_SIZE(vsb_mse2snr_tab), - au8522_readreg(state, 0x4311), - snr); - - if (state->config->led_cfg) - au8522_led_status(state, snr); - - return ret; -} - -static int au8522_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - return au8522_read_snr(fe, signal_strength); -} - -static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct au8522_state *state = fe->demodulator_priv; - - if (state->current_modulation == VSB_8) - *ucblocks = au8522_readreg(state, 0x4087); - else - *ucblocks = au8522_readreg(state, 0x4543); - - return 0; -} - -static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - return au8522_read_ucblocks(fe, ber); -} - -static int au8522_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct au8522_state *state = fe->demodulator_priv; - - p->frequency = state->current_frequency; - p->u.vsb.modulation = state->current_modulation; - - return 0; -} - -static int au8522_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static struct dvb_frontend_ops au8522_ops; - -int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, - u8 client_address) -{ - int ret; - - mutex_lock(&au8522_list_mutex); - ret = hybrid_tuner_request_state(struct au8522_state, (*state), - hybrid_tuner_instance_list, - i2c, client_address, "au8522"); - mutex_unlock(&au8522_list_mutex); - - return ret; -} - -void au8522_release_state(struct au8522_state *state) -{ - mutex_lock(&au8522_list_mutex); - if (state != NULL) - hybrid_tuner_release_state(state); - mutex_unlock(&au8522_list_mutex); -} - - -static void au8522_release(struct dvb_frontend *fe) -{ - struct au8522_state *state = fe->demodulator_priv; - au8522_release_state(state); -} - -struct dvb_frontend *au8522_attach(const struct au8522_config *config, - struct i2c_adapter *i2c) -{ - struct au8522_state *state = NULL; - int instance; - - /* allocate memory for the internal state */ - instance = au8522_get_state(&state, i2c, config->demod_address); - switch (instance) { - case 0: - dprintk("%s state allocation failed\n", __func__); - break; - case 1: - /* new demod instance */ - dprintk("%s using new instance\n", __func__); - break; - default: - /* existing demod instance */ - dprintk("%s using existing instance\n", __func__); - break; - } - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->operational_mode = AU8522_DIGITAL_MODE; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &au8522_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - if (au8522_init(&state->frontend) != 0) { - printk(KERN_ERR "%s: Failed to initialize correctly\n", - __func__); - goto error; - } - - /* Note: Leaving the I2C gate open here. */ - au8522_i2c_gate_ctrl(&state->frontend, 1); - - return &state->frontend; - -error: - au8522_release_state(state); - return NULL; -} -EXPORT_SYMBOL(au8522_attach); - -static struct dvb_frontend_ops au8522_ops = { - - .info = { - .name = "Auvitek AU8522 QAM/8VSB Frontend", - .type = FE_ATSC, - .frequency_min = 54000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - - .init = au8522_init, - .sleep = au8522_sleep, - .i2c_gate_ctrl = au8522_i2c_gate_ctrl, - .set_frontend = au8522_set_frontend, - .get_frontend = au8522_get_frontend, - .get_tune_settings = au8522_get_tune_settings, - .read_status = au8522_read_status, - .read_ber = au8522_read_ber, - .read_signal_strength = au8522_read_signal_strength, - .read_snr = au8522_read_snr, - .read_ucblocks = au8522_read_ucblocks, - .release = au8522_release, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable verbose debug messages"); - -MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver"); -MODULE_AUTHOR("Steven Toth"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -/* - Auvitek AU8522 QAM/8VSB demodulator driver - - Copyright (C) 2008 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __AU8522_H__ -#define __AU8522_H__ - -#include - -enum au8522_if_freq { - AU8522_IF_6MHZ = 0, - AU8522_IF_4MHZ, - AU8522_IF_3_25MHZ, -}; - -struct au8522_led_config { - u16 vsb8_strong; - u16 qam64_strong; - u16 qam256_strong; - - u16 gpio_output; - /* unset hi bits, set low bits */ - u16 gpio_output_enable; - u16 gpio_output_disable; - - u16 gpio_leds; - u8 *led_states; - unsigned int num_led_states; -}; - -struct au8522_config { - /* the demodulator's i2c address */ - u8 demod_address; - - /* Return lock status based on tuner lock, or demod lock */ -#define AU8522_TUNERLOCKING 0 -#define AU8522_DEMODLOCKING 1 - u8 status_mode; - - struct au8522_led_config *led_cfg; - - enum au8522_if_freq vsb_if; - enum au8522_if_freq qam_if; -}; - -#if defined(CONFIG_DVB_AU8522) || \ - (defined(CONFIG_DVB_AU8522_MODULE) && defined(MODULE)) -extern struct dvb_frontend *au8522_attach(const struct au8522_config *config, - struct i2c_adapter *i2c); -#else -static inline -struct dvb_frontend *au8522_attach(const struct au8522_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_AU8522 */ - -/* Other modes may need to be added later */ -enum au8522_video_input { - AU8522_COMPOSITE_CH1 = 1, - AU8522_COMPOSITE_CH2, - AU8522_COMPOSITE_CH3, - AU8522_COMPOSITE_CH4, - AU8522_COMPOSITE_CH4_SIF, - AU8522_SVIDEO_CH13, - AU8522_SVIDEO_CH24, -}; - -enum au8522_audio_input { - AU8522_AUDIO_NONE, - AU8522_AUDIO_SIF, -}; - -#endif /* __AU8522_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/au8522_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,421 +0,0 @@ -/* - Auvitek AU8522 QAM/8VSB demodulator driver - - Copyright (C) 2008 Steven Toth - Copyright (C) 2008 Devin Heitmueller - Copyright (C) 2005-2008 Auvitek International, Ltd. - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "au8522.h" -#include "tuner-i2c.h" - -#define AU8522_ANALOG_MODE 0 -#define AU8522_DIGITAL_MODE 1 - -struct au8522_state { - struct i2c_client *c; - struct i2c_adapter *i2c; - - u8 operational_mode; - - /* Used for sharing of the state between analog and digital mode */ - struct tuner_i2c_props i2c_props; - struct list_head hybrid_tuner_instance_list; - - /* configuration settings */ - const struct au8522_config *config; - - struct dvb_frontend frontend; - - u32 current_frequency; - fe_modulation_t current_modulation; - - u32 fe_status; - unsigned int led_state; - - /* Analog settings */ - struct v4l2_subdev sd; - v4l2_std_id std; - int vid_input; - int aud_input; - u32 id; - u32 rev; - u8 brightness; - u8 contrast; - u8 saturation; - s16 hue; -}; - -/* These are routines shared by both the VSB/QAM demodulator and the analog - decoder */ -int au8522_writereg(struct au8522_state *state, u16 reg, u8 data); -u8 au8522_readreg(struct au8522_state *state, u16 reg); -int au8522_init(struct dvb_frontend *fe); -int au8522_sleep(struct dvb_frontend *fe); - -int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, - u8 client_address); -void au8522_release_state(struct au8522_state *state); - -/* REGISTERS */ -#define AU8522_INPUT_CONTROL_REG081H 0x081 -#define AU8522_PGA_CONTROL_REG082H 0x082 -#define AU8522_CLAMPING_CONTROL_REG083H 0x083 - -#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H 0x0A3 -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H 0x0A4 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H 0x0A5 -#define AU8522_AGC_CONTROL_RANGE_REG0A6H 0x0A6 -#define AU8522_SYSTEM_GAIN_CONTROL_REG0A7H 0x0A7 -#define AU8522_TUNER_AGC_RF_STOP_REG0A8H 0x0A8 -#define AU8522_TUNER_AGC_RF_START_REG0A9H 0x0A9 -#define AU8522_TUNER_RF_AGC_DEFAULT_REG0AAH 0x0AA -#define AU8522_TUNER_AGC_IF_STOP_REG0ABH 0x0AB -#define AU8522_TUNER_AGC_IF_START_REG0ACH 0x0AC -#define AU8522_TUNER_AGC_IF_DEFAULT_REG0ADH 0x0AD -#define AU8522_TUNER_AGC_STEP_REG0AEH 0x0AE -#define AU8522_TUNER_GAIN_STEP_REG0AFH 0x0AF - -/* Receiver registers */ -#define AU8522_FRMREGTHRD1_REG0B0H 0x0B0 -#define AU8522_FRMREGAGC1H_REG0B1H 0x0B1 -#define AU8522_FRMREGSHIFT1_REG0B2H 0x0B2 -#define AU8522_TOREGAGC1_REG0B3H 0x0B3 -#define AU8522_TOREGASHIFT1_REG0B4H 0x0B4 -#define AU8522_FRMREGBBH_REG0B5H 0x0B5 -#define AU8522_FRMREGBBM_REG0B6H 0x0B6 -#define AU8522_FRMREGBBL_REG0B7H 0x0B7 -/* 0xB8 TO 0xD7 are the filter coefficients */ -#define AU8522_FRMREGTHRD2_REG0D8H 0x0D8 -#define AU8522_FRMREGAGC2H_REG0D9H 0x0D9 -#define AU8522_TOREGAGC2_REG0DAH 0x0DA -#define AU8522_TOREGSHIFT2_REG0DBH 0x0DB -#define AU8522_FRMREGPILOTH_REG0DCH 0x0DC -#define AU8522_FRMREGPILOTM_REG0DDH 0x0DD -#define AU8522_FRMREGPILOTL_REG0DEH 0x0DE -#define AU8522_TOREGFREQ_REG0DFH 0x0DF - -#define AU8522_RX_PGA_RFOUT_REG0EBH 0x0EB -#define AU8522_RX_PGA_IFOUT_REG0ECH 0x0EC -#define AU8522_RX_PGA_PGAOUT_REG0EDH 0x0ED - -#define AU8522_CHIP_MODE_REG0FEH 0x0FE - -/* I2C bus control registers */ -#define AU8522_I2C_CONTROL_REG0_REG090H 0x090 -#define AU8522_I2C_CONTROL_REG1_REG091H 0x091 -#define AU8522_I2C_STATUS_REG092H 0x092 -#define AU8522_I2C_WR_DATA0_REG093H 0x093 -#define AU8522_I2C_WR_DATA1_REG094H 0x094 -#define AU8522_I2C_WR_DATA2_REG095H 0x095 -#define AU8522_I2C_WR_DATA3_REG096H 0x096 -#define AU8522_I2C_WR_DATA4_REG097H 0x097 -#define AU8522_I2C_WR_DATA5_REG098H 0x098 -#define AU8522_I2C_WR_DATA6_REG099H 0x099 -#define AU8522_I2C_WR_DATA7_REG09AH 0x09A -#define AU8522_I2C_RD_DATA0_REG09BH 0x09B -#define AU8522_I2C_RD_DATA1_REG09CH 0x09C -#define AU8522_I2C_RD_DATA2_REG09DH 0x09D -#define AU8522_I2C_RD_DATA3_REG09EH 0x09E -#define AU8522_I2C_RD_DATA4_REG09FH 0x09F -#define AU8522_I2C_RD_DATA5_REG0A0H 0x0A0 -#define AU8522_I2C_RD_DATA6_REG0A1H 0x0A1 -#define AU8522_I2C_RD_DATA7_REG0A2H 0x0A2 - -#define AU8522_ENA_USB_REG101H 0x101 - -#define AU8522_I2S_CTRL_0_REG110H 0x110 -#define AU8522_I2S_CTRL_1_REG111H 0x111 -#define AU8522_I2S_CTRL_2_REG112H 0x112 - -#define AU8522_FRMREGFFECONTROL_REG121H 0x121 -#define AU8522_FRMREGDFECONTROL_REG122H 0x122 - -#define AU8522_CARRFREQOFFSET0_REG201H 0x201 -#define AU8522_CARRFREQOFFSET1_REG202H 0x202 - -#define AU8522_DECIMATION_GAIN_REG21AH 0x21A -#define AU8522_FRMREGIFSLP_REG21BH 0x21B -#define AU8522_FRMREGTHRDL2_REG21CH 0x21C -#define AU8522_FRMREGSTEP3DB_REG21DH 0x21D -#define AU8522_DAGC_GAIN_ADJUSTMENT_REG21EH 0x21E -#define AU8522_FRMREGPLLMODE_REG21FH 0x21F -#define AU8522_FRMREGCSTHRD_REG220H 0x220 -#define AU8522_FRMREGCRLOCKDMAX_REG221H 0x221 -#define AU8522_FRMREGCRPERIODMASK_REG222H 0x222 -#define AU8522_FRMREGCRLOCK0THH_REG223H 0x223 -#define AU8522_FRMREGCRLOCK1THH_REG224H 0x224 -#define AU8522_FRMREGCRLOCK0THL_REG225H 0x225 -#define AU8522_FRMREGCRLOCK1THL_REG226H 0x226 -#define AU_FRMREGPLLACQPHASESCL_REG227H 0x227 -#define AU8522_FRMREGFREQFBCTRL_REG228H 0x228 - -/* Analog TV Decoder */ -#define AU8522_TVDEC_STATUS_REG000H 0x000 -#define AU8522_TVDEC_INT_STATUS_REG001H 0x001 -#define AU8522_TVDEC_MACROVISION_STATUS_REG002H 0x002 -#define AU8522_TVDEC_SHARPNESSREG009H 0x009 -#define AU8522_TVDEC_BRIGHTNESS_REG00AH 0x00A -#define AU8522_TVDEC_CONTRAST_REG00BH 0x00B -#define AU8522_TVDEC_SATURATION_CB_REG00CH 0x00C -#define AU8522_TVDEC_SATURATION_CR_REG00DH 0x00D -#define AU8522_TVDEC_HUE_H_REG00EH 0x00E -#define AU8522_TVDEC_HUE_L_REG00FH 0x00F -#define AU8522_TVDEC_INT_MASK_REG010H 0x010 -#define AU8522_VIDEO_MODE_REG011H 0x011 -#define AU8522_TVDEC_PGA_REG012H 0x012 -#define AU8522_TVDEC_COMB_MODE_REG015H 0x015 -#define AU8522_REG016H 0x016 -#define AU8522_TVDED_DBG_MODE_REG060H 0x060 -#define AU8522_TVDEC_FORMAT_CTRL1_REG061H 0x061 -#define AU8522_TVDEC_FORMAT_CTRL2_REG062H 0x062 -#define AU8522_TVDEC_VCR_DET_LLIM_REG063H 0x063 -#define AU8522_TVDEC_VCR_DET_HLIM_REG064H 0x064 -#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H 0x065 -#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H 0x066 -#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H 0x067 -#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H 0x068 -#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H 0x069 -#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH 0x06A -#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH 0x06B -#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH 0x06C -#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH 0x06D -#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH 0x06E -#define AU8522_TVDEC_UV_SEP_THR_REG06FH 0x06F -#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H 0x070 -#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H 0x073 -#define AU8522_TVDEC_DCAGC_CTRL_REG077H 0x077 -#define AU8522_TVDEC_PIC_START_ADJ_REG078H 0x078 -#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H 0x079 -#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH 0x07A -#define AU8522_TVDEC_INTRP_CTRL_REG07BH 0x07B -#define AU8522_TVDEC_PLL_STATUS_REG07EH 0x07E -#define AU8522_TVDEC_FSC_FREQ_REG07FH 0x07F - -#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H 0x0E4 -#define AU8522_TOREGAAGC_REG0E5H 0x0E5 - -#define AU8522_TVDEC_CHROMA_AGC_REG401H 0x401 -#define AU8522_TVDEC_CHROMA_SFT_REG402H 0x402 -#define AU8522_FILTER_COEF_R410 0x410 -#define AU8522_FILTER_COEF_R411 0x411 -#define AU8522_FILTER_COEF_R412 0x412 -#define AU8522_FILTER_COEF_R413 0x413 -#define AU8522_FILTER_COEF_R414 0x414 -#define AU8522_FILTER_COEF_R415 0x415 -#define AU8522_FILTER_COEF_R416 0x416 -#define AU8522_FILTER_COEF_R417 0x417 -#define AU8522_FILTER_COEF_R418 0x418 -#define AU8522_FILTER_COEF_R419 0x419 -#define AU8522_FILTER_COEF_R41A 0x41A -#define AU8522_FILTER_COEF_R41B 0x41B -#define AU8522_FILTER_COEF_R41C 0x41C -#define AU8522_FILTER_COEF_R41D 0x41D -#define AU8522_FILTER_COEF_R41E 0x41E -#define AU8522_FILTER_COEF_R41F 0x41F -#define AU8522_FILTER_COEF_R420 0x420 -#define AU8522_FILTER_COEF_R421 0x421 -#define AU8522_FILTER_COEF_R422 0x422 -#define AU8522_FILTER_COEF_R423 0x423 -#define AU8522_FILTER_COEF_R424 0x424 -#define AU8522_FILTER_COEF_R425 0x425 -#define AU8522_FILTER_COEF_R426 0x426 -#define AU8522_FILTER_COEF_R427 0x427 -#define AU8522_FILTER_COEF_R428 0x428 -#define AU8522_FILTER_COEF_R429 0x429 -#define AU8522_FILTER_COEF_R42A 0x42A -#define AU8522_FILTER_COEF_R42B 0x42B -#define AU8522_FILTER_COEF_R42C 0x42C -#define AU8522_FILTER_COEF_R42D 0x42D - -/* VBI Control Registers */ -#define AU8522_TVDEC_VBI_RX_FIFO_CONTAIN_REG004H 0x004 -#define AU8522_TVDEC_VBI_TX_FIFO_CONTAIN_REG005H 0x005 -#define AU8522_TVDEC_VBI_RX_FIFO_READ_REG006H 0x006 -#define AU8522_TVDEC_VBI_FIFO_STATUS_REG007H 0x007 -#define AU8522_TVDEC_VBI_CTRL_H_REG017H 0x017 -#define AU8522_TVDEC_VBI_CTRL_L_REG018H 0x018 -#define AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H 0x019 -#define AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH 0x01A -#define AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH 0x01B -#define AU8522_TVDEC_VBI_USER_THRESH1_REG01CH 0x01C -#define AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH 0x01E -#define AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH 0x01F -#define AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H 0x020 -#define AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H 0x021 -#define AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H 0x022 -#define AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H 0x023 - -#define AU8522_REG071H 0x071 -#define AU8522_REG072H 0x072 -#define AU8522_REG074H 0x074 -#define AU8522_REG075H 0x075 - -/* Digital Demodulator Registers */ -#define AU8522_FRAME_COUNT0_REG084H 0x084 -#define AU8522_RS_STATUS_G0_REG085H 0x085 -#define AU8522_RS_STATUS_B0_REG086H 0x086 -#define AU8522_RS_STATUS_E_REG087H 0x087 -#define AU8522_DEMODULATION_STATUS_REG088H 0x088 -#define AU8522_TOREGTRESTATUS_REG0E6H 0x0E6 -#define AU8522_TSPORT_CONTROL_REG10BH 0x10B -#define AU8522_TSTHES_REG10CH 0x10C -#define AU8522_FRMREGDFEKEEP_REG301H 0x301 -#define AU8522_DFE_AVERAGE_REG302H 0x302 -#define AU8522_FRMREGEQLERRWIN_REG303H 0x303 -#define AU8522_FRMREGFFEKEEP_REG304H 0x304 -#define AU8522_FRMREGDFECONTROL1_REG305H 0x305 -#define AU8522_FRMREGEQLERRLOW_REG306H 0x306 - -#define AU8522_REG42EH 0x42E -#define AU8522_REG42FH 0x42F -#define AU8522_REG430H 0x430 -#define AU8522_REG431H 0x431 -#define AU8522_REG432H 0x432 -#define AU8522_REG433H 0x433 -#define AU8522_REG434H 0x434 -#define AU8522_REG435H 0x435 -#define AU8522_REG436H 0x436 - -/* GPIO Registers */ -#define AU8522_GPIO_CONTROL_REG0E0H 0x0E0 -#define AU8522_GPIO_STATUS_REG0E1H 0x0E1 -#define AU8522_GPIO_DATA_REG0E2H 0x0E2 - -/* Audio Control Registers */ -#define AU8522_AUDIOAGC_REG0EEH 0x0EE -#define AU8522_AUDIO_STATUS_REG0F0H 0x0F0 -#define AU8522_AUDIO_MODE_REG0F1H 0x0F1 -#define AU8522_AUDIO_VOLUME_L_REG0F2H 0x0F2 -#define AU8522_AUDIO_VOLUME_R_REG0F3H 0x0F3 -#define AU8522_AUDIO_VOLUME_REG0F4H 0x0F4 -#define AU8522_FRMREGAUPHASE_REG0F7H 0x0F7 -#define AU8522_REG0F9H 0x0F9 - -#define AU8522_AUDIOAGC2_REG605H 0x605 -#define AU8522_AUDIOFREQ_REG606H 0x606 - - -/**************************************************************/ - -#define AU8522_INPUT_CONTROL_REG081H_ATSC 0xC4 -#define AU8522_INPUT_CONTROL_REG081H_ATVRF 0xC4 -#define AU8522_INPUT_CONTROL_REG081H_ATVRF13 0xC4 -#define AU8522_INPUT_CONTROL_REG081H_J83B64 0xC4 -#define AU8522_INPUT_CONTROL_REG081H_J83B256 0xC4 -#define AU8522_INPUT_CONTROL_REG081H_CVBS 0x20 -#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH1 0xA2 -#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH2 0xA0 -#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH3 0x69 -#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4 0x68 -#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF 0x28 -/* CH1 AS Y,CH3 AS C */ -#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 0x23 -/* CH2 AS Y,CH4 AS C */ -#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24 0x20 -#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATSC 0x0C -#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B64 0x09 -#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B256 0x09 -#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS 0x12 -#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF 0x1A -#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF13 0x1A -#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO 0x02 - -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CLEAR 0x00 -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO 0x9C -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS 0x9D -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATSC 0xE8 -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B256 0xCA -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B64 0xCA -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF 0xDD -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF13 0xDD -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_PAL 0xDD -#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_FM 0xDD - -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATSC 0x80 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B256 0x80 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B64 0x80 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_ATSC 0x40 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B256 0x40 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B64 0x40 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_CLEAR 0x00 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF 0x01 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF13 0x01 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_SVIDEO 0x04 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_CVBS 0x01 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PWM 0x03 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_IIS 0x09 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PAL 0x01 -#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_FM 0x01 - -/* STILL NEED TO BE REFACTORED @@@@@@@@@@@@@@ */ -#define AU8522_TVDEC_CONTRAST_REG00BH_CVBS 0x79 -#define AU8522_TVDEC_SATURATION_CB_REG00CH_CVBS 0x80 -#define AU8522_TVDEC_SATURATION_CR_REG00DH_CVBS 0x80 -#define AU8522_TVDEC_HUE_H_REG00EH_CVBS 0x00 -#define AU8522_TVDEC_HUE_L_REG00FH_CVBS 0x00 -#define AU8522_TVDEC_PGA_REG012H_CVBS 0x0F -#define AU8522_TVDEC_COMB_MODE_REG015H_CVBS 0x00 -#define AU8522_REG016H_CVBS 0x00 -#define AU8522_TVDED_DBG_MODE_REG060H_CVBS 0x00 -#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS 0x0B -#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13 0x03 -#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13 0x00 -#define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS 0x19 -#define AU8522_REG0F9H_AUDIO 0x20 -#define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS 0xA7 -#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS 0x0A -#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS 0x32 -#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS 0x19 -#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS 0x23 -#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS 0x41 -#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS 0x0A -#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS 0x32 -#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS 0x34 -#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO 0x2a -#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS 0x05 -#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO 0x15 -#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS 0x6E -#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS 0x0F -#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS 0x80 -#define AU8522_REG071H_CVBS 0x18 -#define AU8522_REG072H_CVBS 0x30 -#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS 0xF0 -#define AU8522_REG074H_CVBS 0x80 -#define AU8522_REG075H_CVBS 0xF0 -#define AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS 0xFB -#define AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS 0x04 -#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS 0x00 -#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS 0x00 -#define AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS 0xEE -#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS 0xFE -#define AU8522_TOREGAAGC_REG0E5H_CVBS 0x00 -#define AU8522_TVDEC_VBI6A_REG035H_CVBS 0x40 - -/* Enables Closed captioning */ -#define AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON 0x21 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,854 +0,0 @@ -/* - * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) - * - * Copyright (C) 2001-5, B2C2 inc. - * - * GPL/Linux driver written by Patrick Boettcher - * - * This driver is "hard-coded" to be used with the 1st generation of - * Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming - * (Panasonic CT10S) is located here, which is actually wrong. Unless there is - * another device with a BCM3510, this is no problem. - * - * The driver works also with QAM64 DVB-C, but had an unreasonable high - * UNC. (Tested with the Air2PC ATSC 1st generation) - * - * You'll need a firmware for this driver in order to get it running. It is - * called "dvb-fe-bcm3510-01.fw". - * - * 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, or (at your option) - * any later version. - * - * 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., 675 Mass - * Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "bcm3510.h" -#include "bcm3510_priv.h" - -struct bcm3510_state { - - struct i2c_adapter* i2c; - const struct bcm3510_config* config; - struct dvb_frontend frontend; - - /* demodulator private data */ - struct mutex hab_mutex; - u8 firmware_loaded:1; - - unsigned long next_status_check; - unsigned long status_check_interval; - struct bcm3510_hab_cmd_status1 status1; - struct bcm3510_hab_cmd_status2 status2; -}; - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able))."); - -#define dprintk(level,x...) if (level & debug) printk(x) -#define dbufout(b,l,m) {\ - int i; \ - for (i = 0; i < l; i++) \ - m("%02x ",b[i]); \ -} -#define deb_info(args...) dprintk(0x01,args) -#define deb_i2c(args...) dprintk(0x02,args) -#define deb_hab(args...) dprintk(0x04,args) - -/* transfer functions */ -static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len) -{ - u8 b[256]; - int err; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 }; - - b[0] = reg; - memcpy(&b[1],buf,len); - - deb_i2c("i2c wr %02x: ",reg); - dbufout(buf,len,deb_i2c); - deb_i2c("\n"); - - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - - deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n", - __func__, state->config->demod_address, reg, err); - return -EREMOTEIO; - } - - return 0; -} - -static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len) -{ - struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } - }; - int err; - - memset(buf,0,len); - - if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { - deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n", - __func__, state->config->demod_address, reg, err); - return -EREMOTEIO; - } - deb_i2c("i2c rd %02x: ",reg); - dbufout(buf,len,deb_i2c); - deb_i2c("\n"); - - return 0; -} - -static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v) -{ - return bcm3510_writebytes(state,reg,&v.raw,1); -} - -static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v) -{ - return bcm3510_readbytes(state,reg,&v->raw,1); -} - -/* Host Access Buffer transfers */ -static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len) -{ - bcm3510_register_value v; - int ret,i; - - v.HABADR_a6.HABADR = 0; - if ((ret = bcm3510_writeB(st,0xa6,v)) < 0) - return ret; - - for (i = 0; i < len; i++) { - if ((ret = bcm3510_readB(st,0xa7,&v)) < 0) - return ret; - buf[i] = v.HABDATA_a7; - } - return 0; -} - -static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len) -{ - bcm3510_register_value v,hab; - int ret,i; - unsigned long t; - -/* Check if any previous HAB request still needs to be serviced by the - * Aquisition Processor before sending new request */ - if ((ret = bcm3510_readB(st,0xa8,&v)) < 0) - return ret; - if (v.HABSTAT_a8.HABR) { - deb_info("HAB is running already - clearing it.\n"); - v.HABSTAT_a8.HABR = 0; - bcm3510_writeB(st,0xa8,v); -// return -EBUSY; - } - -/* Send the start HAB Address (automatically incremented after write of - * HABDATA) and write the HAB Data */ - hab.HABADR_a6.HABADR = 0; - if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0) - return ret; - - for (i = 0; i < len; i++) { - hab.HABDATA_a7 = buf[i]; - if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0) - return ret; - } - -/* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to - * be written) */ - v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1; - if ((ret = bcm3510_writeB(st,0xa8,v)) < 0) - return ret; - -/* Polling method: Wait until the AP finishes processing the HAB request */ - t = jiffies + 1*HZ; - while (time_before(jiffies, t)) { - deb_info("waiting for HAB to complete\n"); - msleep(10); - if ((ret = bcm3510_readB(st,0xa8,&v)) < 0) - return ret; - - if (!v.HABSTAT_a8.HABR) - return 0; - } - - deb_info("send_request execution timed out.\n"); - return -ETIMEDOUT; -} - -static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen) -{ - u8 ob[olen+2],ib[ilen+2]; - int ret = 0; - - ob[0] = cmd; - ob[1] = msgid; - memcpy(&ob[2],obuf,olen); - - deb_hab("hab snd: "); - dbufout(ob,olen+2,deb_hab); - deb_hab("\n"); - - if (mutex_lock_interruptible(&st->hab_mutex) < 0) - return -EAGAIN; - - if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 || - (ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0) - goto error; - - deb_hab("hab get: "); - dbufout(ib,ilen+2,deb_hab); - deb_hab("\n"); - - memcpy(ibuf,&ib[2],ilen); -error: - mutex_unlock(&st->hab_mutex); - return ret; -} - -#if 0 -/* not needed, we use a semaphore to prevent HAB races */ -static int bcm3510_is_ap_ready(struct bcm3510_state *st) -{ - bcm3510_register_value ap,hab; - int ret; - - if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 || - (ret = bcm3510_readB(st,0xa2,&ap) < 0)) - return ret; - - if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) { - deb_info("AP is busy\n"); - return -EBUSY; - } - - return 0; -} -#endif - -static int bcm3510_bert_reset(struct bcm3510_state *st) -{ - bcm3510_register_value b; - int ret; - - if ((ret = bcm3510_readB(st,0xfa,&b)) < 0) - return ret; - - b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); - b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b); - b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); - b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b); - - /* clear residual bit counter TODO */ - return 0; -} - -static int bcm3510_refresh_state(struct bcm3510_state *st) -{ - if (time_after(jiffies,st->next_status_check)) { - bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1)); - bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2)); - st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; - } - return 0; -} - -static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct bcm3510_state* st = fe->demodulator_priv; - bcm3510_refresh_state(st); - - *status = 0; - if (st->status1.STATUS1.RECEIVER_LOCK) - *status |= FE_HAS_LOCK | FE_HAS_SYNC; - - if (st->status1.STATUS1.FEC_LOCK) - *status |= FE_HAS_VITERBI; - - if (st->status1.STATUS1.OUT_PLL_LOCK) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; - - if (*status & FE_HAS_LOCK) - st->status_check_interval = 1500; - else /* more frequently checks if no lock has been achieved yet */ - st->status_check_interval = 500; - - deb_info("real_status: %02x\n",*status); - return 0; -} - -static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct bcm3510_state* st = fe->demodulator_priv; - bcm3510_refresh_state(st); - - *ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2; - return 0; -} - -static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc) -{ - struct bcm3510_state* st = fe->demodulator_priv; - bcm3510_refresh_state(st); - *unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1; - return 0; -} - -static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct bcm3510_state* st = fe->demodulator_priv; - s32 t; - - bcm3510_refresh_state(st); - t = st->status2.SIGNAL; - - if (t > 190) - t = 190; - if (t < 90) - t = 90; - - t -= 90; - t = t * 0xff / 100; - /* normalize if necessary */ - *strength = (t << 8) | t; - return 0; -} - -static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct bcm3510_state* st = fe->demodulator_priv; - bcm3510_refresh_state(st); - - *snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8); - return 0; -} - -/* tuner frontend programming */ -static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a) -{ - struct bcm3510_hab_cmd_tune c; - memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune)); - -/* I2C Mode disabled, set 16 control / Data pairs */ - c.length = 0x10; - c.clock_width = 0; -/* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to - * logic high (as Configuration) */ - c.misc = 0x10; -/* Set duration of the initial state of TUNCTL = 3.34 micro Sec */ - c.TUNCTL_state = 0x40; - -/* PRESCALER DEVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */ - c.ctl_dat[0].ctrl.size = BITS_8; - c.ctl_dat[0].data = 0x80 | bc; - -/* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */ - c.ctl_dat[1].ctrl.size = BITS_8; - c.ctl_dat[1].data = 4; - -/* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */ - c.ctl_dat[2].ctrl.size = BITS_3; - c.ctl_dat[2].data = 0x20; - -/* control CS0 pin, pulse byte ? */ - c.ctl_dat[3].ctrl.size = BITS_3; - c.ctl_dat[3].ctrl.clk_off = 1; - c.ctl_dat[3].ctrl.cs0 = 1; - c.ctl_dat[3].data = 0x40; - -/* PGM_S18 to PGM_S11 */ - c.ctl_dat[4].ctrl.size = BITS_8; - c.ctl_dat[4].data = n >> 3; - -/* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */ - c.ctl_dat[5].ctrl.size = BITS_8; - c.ctl_dat[5].data = ((n & 0x7) << 5) | (a >> 2); - -/* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */ - c.ctl_dat[6].ctrl.size = BITS_3; - c.ctl_dat[6].data = (a << 6) & 0xdf; - -/* control CS0 pin, pulse byte ? */ - c.ctl_dat[7].ctrl.size = BITS_3; - c.ctl_dat[7].ctrl.clk_off = 1; - c.ctl_dat[7].ctrl.cs0 = 1; - c.ctl_dat[7].data = 0x40; - -/* PRESCALER DEVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */ - c.ctl_dat[8].ctrl.size = BITS_8; - c.ctl_dat[8].data = 0x80; - -/* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */ - c.ctl_dat[9].ctrl.size = BITS_8; - c.ctl_dat[9].data = 0x10; - -/* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */ - c.ctl_dat[10].ctrl.size = BITS_3; - c.ctl_dat[10].data = 0x20; - -/* pulse byte */ - c.ctl_dat[11].ctrl.size = BITS_3; - c.ctl_dat[11].ctrl.clk_off = 1; - c.ctl_dat[11].ctrl.cs1 = 1; - c.ctl_dat[11].data = 0x40; - -/* PGM_S18 to PGM_S11 */ - c.ctl_dat[12].ctrl.size = BITS_8; - c.ctl_dat[12].data = 0x2a; - -/* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */ - c.ctl_dat[13].ctrl.size = BITS_8; - c.ctl_dat[13].data = 0x8e; - -/* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */ - c.ctl_dat[14].ctrl.size = BITS_3; - c.ctl_dat[14].data = 0; - -/* Pulse Byte */ - c.ctl_dat[15].ctrl.size = BITS_3; - c.ctl_dat[15].ctrl.clk_off = 1; - c.ctl_dat[15].ctrl.cs1 = 1; - c.ctl_dat[15].data = 0x40; - - return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0); -} - -static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq) -{ - u8 bc,a; - u16 n; - s32 YIntercept,Tfvco1; - - freq /= 1000; - - deb_info("%dkHz:",freq); - /* set Band Switch */ - if (freq <= 168000) - bc = 0x1c; - else if (freq <= 378000) - bc = 0x2c; - else - bc = 0x30; - - if (freq >= 470000) { - freq -= 470001; - YIntercept = 18805; - } else if (freq >= 90000) { - freq -= 90001; - YIntercept = 15005; - } else if (freq >= 76000){ - freq -= 76001; - YIntercept = 14865; - } else { - freq -= 54001; - YIntercept = 14645; - } - - Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10; - - n = Tfvco1 >> 6; - a = Tfvco1 & 0x3f; - - deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a); - if (n >= 16 && n <= 2047) - return bcm3510_tuner_cmd(st,bc,n,a); - - return -EINVAL; -} - -static int bcm3510_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) -{ - struct bcm3510_state* st = fe->demodulator_priv; - struct bcm3510_hab_cmd_ext_acquire cmd; - struct bcm3510_hab_cmd_bert_control bert; - int ret; - - memset(&cmd,0,sizeof(cmd)); - switch (p->u.vsb.modulation) { - case QAM_256: - cmd.ACQUIRE0.MODE = 0x1; - cmd.ACQUIRE1.SYM_RATE = 0x1; - cmd.ACQUIRE1.IF_FREQ = 0x1; - break; - case QAM_64: - cmd.ACQUIRE0.MODE = 0x2; - cmd.ACQUIRE1.SYM_RATE = 0x2; - cmd.ACQUIRE1.IF_FREQ = 0x1; - break; -/* case QAM_256: - cmd.ACQUIRE0.MODE = 0x3; - break; - case QAM_128: - cmd.ACQUIRE0.MODE = 0x4; - break; - case QAM_64: - cmd.ACQUIRE0.MODE = 0x5; - break; - case QAM_32: - cmd.ACQUIRE0.MODE = 0x6; - break; - case QAM_16: - cmd.ACQUIRE0.MODE = 0x7; - break;*/ - case VSB_8: - cmd.ACQUIRE0.MODE = 0x8; - cmd.ACQUIRE1.SYM_RATE = 0x0; - cmd.ACQUIRE1.IF_FREQ = 0x0; - break; - case VSB_16: - cmd.ACQUIRE0.MODE = 0x9; - cmd.ACQUIRE1.SYM_RATE = 0x0; - cmd.ACQUIRE1.IF_FREQ = 0x0; - default: - return -EINVAL; - }; - cmd.ACQUIRE0.OFFSET = 0; - cmd.ACQUIRE0.NTSCSWEEP = 1; - cmd.ACQUIRE0.FA = 1; - cmd.ACQUIRE0.BW = 0; - -/* if (enableOffset) { - cmd.IF_OFFSET0 = xx; - cmd.IF_OFFSET1 = xx; - - cmd.SYM_OFFSET0 = xx; - cmd.SYM_OFFSET1 = xx; - if (enableNtscSweep) { - cmd.NTSC_OFFSET0; - cmd.NTSC_OFFSET1; - } - } */ - bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0); - -/* doing it with different MSGIDs, data book and source differs */ - bert.BE = 0; - bert.unused = 0; - bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0); - bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0); - - bcm3510_bert_reset(st); - - if ((ret = bcm3510_set_freq(st,p->frequency)) < 0) - return ret; - - memset(&st->status1,0,sizeof(st->status1)); - memset(&st->status2,0,sizeof(st->status2)); - st->status_check_interval = 500; - -/* Give the AP some time */ - msleep(200); - - return 0; -} - -static int bcm3510_sleep(struct dvb_frontend* fe) -{ - return 0; -} - -static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s) -{ - s->min_delay_ms = 1000; - s->step_size = 0; - s->max_drift = 0; - return 0; -} - -static void bcm3510_release(struct dvb_frontend* fe) -{ - struct bcm3510_state* state = fe->demodulator_priv; - kfree(state); -} - -/* firmware download: - * firmware file is build up like this: - * 16bit addr, 16bit length, 8byte of length - */ -#define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw" - -static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, const u8 *b, - u16 len) -{ - int ret = 0,i; - bcm3510_register_value vH, vL,vD; - - vH.MADRH_a9 = addr >> 8; - vL.MADRL_aa = addr; - if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret; - if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret; - - for (i = 0; i < len; i++) { - vD.MDATA_ab = b[i]; - if ((ret = bcm3510_writeB(st,0xab,vD)) < 0) - return ret; - } - - return 0; -} - -static int bcm3510_download_firmware(struct dvb_frontend* fe) -{ - struct bcm3510_state* st = fe->demodulator_priv; - const struct firmware *fw; - u16 addr,len; - const u8 *b; - int ret,i; - - deb_info("requesting firmware\n"); - if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) { - err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); - return ret; - } - deb_info("got firmware: %zd\n",fw->size); - - b = fw->data; - for (i = 0; i < fw->size;) { - addr = le16_to_cpu( *( (u16 *)&b[i] ) ); - len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); - deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size); - if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { - err("firmware download failed: %d\n",ret); - return ret; - } - i += 4 + len; - } - release_firmware(fw); - deb_info("firmware download successfully completed\n"); - return 0; -} - -static int bcm3510_check_firmware_version(struct bcm3510_state *st) -{ - struct bcm3510_hab_cmd_get_version_info ver; - bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver)); - - deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n", - ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version); - - if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION && - ver.config_version == BCM3510_DEF_CONFIG_VERSION && - ver.demod_version == BCM3510_DEF_DEMOD_VERSION) - return 0; - - deb_info("version check failed\n"); - return -ENODEV; -} - -/* (un)resetting the AP */ -static int bcm3510_reset(struct bcm3510_state *st) -{ - int ret; - unsigned long t; - bcm3510_register_value v; - - bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1; - if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) - return ret; - - t = jiffies + 3*HZ; - while (time_before(jiffies, t)) { - msleep(10); - if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) - return ret; - - if (v.APSTAT1_a2.RESET) - return 0; - } - deb_info("reset timed out\n"); - return -ETIMEDOUT; -} - -static int bcm3510_clear_reset(struct bcm3510_state *st) -{ - bcm3510_register_value v; - int ret; - unsigned long t; - - v.raw = 0; - if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) - return ret; - - t = jiffies + 3*HZ; - while (time_before(jiffies, t)) { - msleep(10); - if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) - return ret; - - /* verify that reset is cleared */ - if (!v.APSTAT1_a2.RESET) - return 0; - } - deb_info("reset clear timed out\n"); - return -ETIMEDOUT; -} - -static int bcm3510_init_cold(struct bcm3510_state *st) -{ - int ret; - bcm3510_register_value v; - - /* read Acquisation Processor status register and check it is not in RUN mode */ - if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) - return ret; - if (v.APSTAT1_a2.RUN) { - deb_info("AP is already running - firmware already loaded.\n"); - return 0; - } - - deb_info("reset?\n"); - if ((ret = bcm3510_reset(st)) < 0) - return ret; - - deb_info("tristate?\n"); - /* tri-state */ - v.TSTCTL_2e.CTL = 0; - if ((ret = bcm3510_writeB(st,0x2e,v)) < 0) - return ret; - - deb_info("firmware?\n"); - if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 || - (ret = bcm3510_clear_reset(st)) < 0) - return ret; - - /* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */ - - return 0; -} - -static int bcm3510_init(struct dvb_frontend* fe) -{ - struct bcm3510_state* st = fe->demodulator_priv; - bcm3510_register_value j; - struct bcm3510_hab_cmd_set_agc c; - int ret; - - if ((ret = bcm3510_readB(st,0xca,&j)) < 0) - return ret; - - deb_info("JDEC: %02x\n",j.raw); - - switch (j.JDEC_ca.JDEC) { - case JDEC_WAIT_AT_RAM: - deb_info("attempting to download firmware\n"); - if ((ret = bcm3510_init_cold(st)) < 0) - return ret; - case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */ - deb_info("firmware is loaded\n"); - bcm3510_check_firmware_version(st); - break; - default: - return -ENODEV; - } - - memset(&c,0,1); - c.SEL = 1; - bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0); - - return 0; -} - - -static struct dvb_frontend_ops bcm3510_ops; - -struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config, - struct i2c_adapter *i2c) -{ - struct bcm3510_state* state = NULL; - int ret; - bcm3510_register_value v; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct bcm3510_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - - state->config = config; - state->i2c = i2c; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - mutex_init(&state->hab_mutex); - - if ((ret = bcm3510_readB(state,0xe0,&v)) < 0) - goto error; - - deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER); - - if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */ - (v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0)) /* warm */ - goto error; - - info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER); - - bcm3510_reset(state); - - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(bcm3510_attach); - -static struct dvb_frontend_ops bcm3510_ops = { - - .info = { - .name = "Broadcom BCM3510 VSB/QAM frontend", - .type = FE_ATSC, - .frequency_min = 54000000, - .frequency_max = 803000000, - /* stepsize is just a guess */ - .frequency_stepsize = 0, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_8VSB | FE_CAN_16VSB | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 - }, - - .release = bcm3510_release, - - .init = bcm3510_init, - .sleep = bcm3510_sleep, - - .set_frontend = bcm3510_set_frontend, - .get_tune_settings = bcm3510_get_tune_settings, - - .read_status = bcm3510_read_status, - .read_ber = bcm3510_read_ber, - .read_signal_strength = bcm3510_read_signal_strength, - .read_snr = bcm3510_read_snr, - .read_ucblocks = bcm3510_read_unc, -}; - -MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver"); -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) - * - * Copyright (C) 2001-5, B2C2 inc. - * - * GPL/Linux driver written by Patrick Boettcher - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef BCM3510_H -#define BCM3510_H - -#include -#include - -struct bcm3510_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* request firmware for device */ - int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); -}; - -#if defined(CONFIG_DVB_BCM3510) || (defined(CONFIG_DVB_BCM3510_MODULE) && defined(MODULE)) -extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_BCM3510 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bcm3510_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,460 +0,0 @@ -/* - * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) - * - * Copyright (C) 2001-5, B2C2 inc. - * - * GPL/Linux driver written by Patrick Boettcher - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef __BCM3510_PRIV_H__ -#define __BCM3510_PRIV_H__ - -#define PACKED __attribute__((packed)) - -#undef err -#define err(format, arg...) printk(KERN_ERR "bcm3510: " format "\n" , ## arg) -#undef info -#define info(format, arg...) printk(KERN_INFO "bcm3510: " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) printk(KERN_WARNING "bcm3510: " format "\n" , ## arg) - - -#define PANASONIC_FIRST_IF_BASE_IN_KHz 1407500 -#define BCM3510_SYMBOL_RATE 5381000 - -typedef union { - u8 raw; - - struct { - u8 CTL :8; - } TSTCTL_2e; - - u8 LDCERC_4e; - u8 LDUERC_4f; - u8 LD_BER0_65; - u8 LD_BER1_66; - u8 LD_BER2_67; - u8 LD_BER3_68; - - struct { - u8 RESET :1; - u8 IDLE :1; - u8 STOP :1; - u8 HIRQ0 :1; - u8 HIRQ1 :1; - u8 na0 :1; - u8 HABAV :1; - u8 na1 :1; - } HCTL1_a0; - - struct { - u8 na0 :1; - u8 IDLMSK :1; - u8 STMSK :1; - u8 I0MSK :1; - u8 I1MSK :1; - u8 na1 :1; - u8 HABMSK :1; - u8 na2 :1; - } HCTLMSK_a1; - - struct { - u8 RESET :1; - u8 IDLE :1; - u8 STOP :1; - u8 RUN :1; - u8 HABAV :1; - u8 MEMAV :1; - u8 ALDONE :1; - u8 REIRQ :1; - } APSTAT1_a2; - - struct { - u8 RSTMSK :1; - u8 IMSK :1; - u8 SMSK :1; - u8 RMSK :1; - u8 HABMSK :1; - u8 MAVMSK :1; - u8 ALDMSK :1; - u8 REMSK :1; - } APMSK1_a3; - - u8 APSTAT2_a4; - u8 APMSK2_a5; - - struct { - u8 HABADR :7; - u8 na :1; - } HABADR_a6; - - u8 HABDATA_a7; - - struct { - u8 HABR :1; - u8 LDHABR :1; - u8 APMSK :1; - u8 HMSK :1; - u8 LDMSK :1; - u8 na :3; - } HABSTAT_a8; - - u8 MADRH_a9; - u8 MADRL_aa; - u8 MDATA_ab; - - struct { -#define JDEC_WAIT_AT_RAM 0x7 -#define JDEC_EEPROM_LOAD_WAIT 0x4 - u8 JDEC :3; - u8 na :5; - } JDEC_ca; - - struct { - u8 REV :4; - u8 LAYER :4; - } REVID_e0; - - struct { - u8 unk0 :1; - u8 CNTCTL :1; - u8 BITCNT :1; - u8 unk1 :1; - u8 RESYNC :1; - u8 unk2 :3; - } BERCTL_fa; - - struct { - u8 CSEL0 :1; - u8 CLKED0 :1; - u8 CSEL1 :1; - u8 CLKED1 :1; - u8 CLKLEV :1; - u8 SPIVAR :1; - u8 na :2; - } TUNSET_fc; - - struct { - u8 CLK :1; - u8 DATA :1; - u8 CS0 :1; - u8 CS1 :1; - u8 AGCSEL :1; - u8 na0 :1; - u8 TUNSEL :1; - u8 na1 :1; - } TUNCTL_fd; - - u8 TUNSEL0_fe; - u8 TUNSEL1_ff; - -} bcm3510_register_value; - -/* HAB commands */ - -/* version */ -#define CMD_GET_VERSION_INFO 0x3D -#define MSGID_GET_VERSION_INFO 0x15 -struct bcm3510_hab_cmd_get_version_info { - u8 microcode_version; - u8 script_version; - u8 config_version; - u8 demod_version; -} PACKED; - -#define BCM3510_DEF_MICROCODE_VERSION 0x0E -#define BCM3510_DEF_SCRIPT_VERSION 0x06 -#define BCM3510_DEF_CONFIG_VERSION 0x01 -#define BCM3510_DEF_DEMOD_VERSION 0xB1 - -/* acquire */ -#define CMD_ACQUIRE 0x38 - -#define MSGID_EXT_TUNER_ACQUIRE 0x0A -struct bcm3510_hab_cmd_ext_acquire { - struct { - u8 MODE :4; - u8 BW :1; - u8 FA :1; - u8 NTSCSWEEP :1; - u8 OFFSET :1; - } PACKED ACQUIRE0; /* control_byte */ - - struct { - u8 IF_FREQ :3; - u8 zero0 :1; - u8 SYM_RATE :3; - u8 zero1 :1; - } PACKED ACQUIRE1; /* sym_if */ - - u8 IF_OFFSET0; /* IF_Offset_10hz */ - u8 IF_OFFSET1; - u8 SYM_OFFSET0; /* SymbolRateOffset */ - u8 SYM_OFFSET1; - u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */ - u8 NTSC_OFFSET1; -} PACKED; - -#define MSGID_INT_TUNER_ACQUIRE 0x0B -struct bcm3510_hab_cmd_int_acquire { - struct { - u8 MODE :4; - u8 BW :1; - u8 FA :1; - u8 NTSCSWEEP :1; - u8 OFFSET :1; - } PACKED ACQUIRE0; /* control_byte */ - - struct { - u8 IF_FREQ :3; - u8 zero0 :1; - u8 SYM_RATE :3; - u8 zero1 :1; - } PACKED ACQUIRE1; /* sym_if */ - - u8 TUNER_FREQ0; - u8 TUNER_FREQ1; - u8 TUNER_FREQ2; - u8 TUNER_FREQ3; - u8 IF_OFFSET0; /* IF_Offset_10hz */ - u8 IF_OFFSET1; - u8 SYM_OFFSET0; /* SymbolRateOffset */ - u8 SYM_OFFSET1; - u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */ - u8 NTSC_OFFSET1; -} PACKED; - -/* modes */ -#define BCM3510_QAM16 = 0x01 -#define BCM3510_QAM32 = 0x02 -#define BCM3510_QAM64 = 0x03 -#define BCM3510_QAM128 = 0x04 -#define BCM3510_QAM256 = 0x05 -#define BCM3510_8VSB = 0x0B -#define BCM3510_16VSB = 0x0D - -/* IF_FREQS */ -#define BCM3510_IF_TERRESTRIAL 0x0 -#define BCM3510_IF_CABLE 0x1 -#define BCM3510_IF_USE_CMD 0x7 - -/* SYM_RATE */ -#define BCM3510_SR_8VSB 0x0 /* 5381119 s/sec */ -#define BCM3510_SR_256QAM 0x1 /* 5360537 s/sec */ -#define BCM3510_SR_16QAM 0x2 /* 5056971 s/sec */ -#define BCM3510_SR_MISC 0x3 /* 5000000 s/sec */ -#define BCM3510_SR_USE_CMD 0x7 - -/* special symbol rate */ -#define CMD_SET_VALUE_NOT_LISTED 0x2d -#define MSGID_SET_SYMBOL_RATE_NOT_LISTED 0x0c -struct bcm3510_hab_cmd_set_sr_not_listed { - u8 HOST_SYM_RATE0; - u8 HOST_SYM_RATE1; - u8 HOST_SYM_RATE2; - u8 HOST_SYM_RATE3; -} PACKED; - -/* special IF */ -#define MSGID_SET_IF_FREQ_NOT_LISTED 0x0d -struct bcm3510_hab_cmd_set_if_freq_not_listed { - u8 HOST_IF_FREQ0; - u8 HOST_IF_FREQ1; - u8 HOST_IF_FREQ2; - u8 HOST_IF_FREQ3; -} PACKED; - -/* auto reacquire */ -#define CMD_AUTO_PARAM 0x2a -#define MSGID_AUTO_REACQUIRE 0x0e -struct bcm3510_hab_cmd_auto_reacquire { - u8 ACQ :1; /* on/off*/ - u8 unused :7; -} PACKED; - -#define MSGID_SET_RF_AGC_SEL 0x12 -struct bcm3510_hab_cmd_set_agc { - u8 LVL :1; - u8 unused :6; - u8 SEL :1; -} PACKED; - -#define MSGID_SET_AUTO_INVERSION 0x14 -struct bcm3510_hab_cmd_auto_inversion { - u8 AI :1; - u8 unused :7; -} PACKED; - - -/* bert control */ -#define CMD_STATE_CONTROL 0x12 -#define MSGID_BERT_CONTROL 0x0e -#define MSGID_BERT_SET 0xfa -struct bcm3510_hab_cmd_bert_control { - u8 BE :1; - u8 unused :7; -} PACKED; - -#define MSGID_TRI_STATE 0x2e -struct bcm3510_hab_cmd_tri_state { - u8 RE :1; /* a/d ram port pins */ - u8 PE :1; /* baud clock pin */ - u8 AC :1; /* a/d clock pin */ - u8 BE :1; /* baud clock pin */ - u8 unused :4; -} PACKED; - - -/* tune */ -#define CMD_TUNE 0x38 -#define MSGID_TUNE 0x16 -struct bcm3510_hab_cmd_tune_ctrl_data_pair { - struct { -#define BITS_8 0x07 -#define BITS_7 0x06 -#define BITS_6 0x05 -#define BITS_5 0x04 -#define BITS_4 0x03 -#define BITS_3 0x02 -#define BITS_2 0x01 -#define BITS_1 0x00 - u8 size :3; - u8 unk :2; - u8 clk_off :1; - u8 cs0 :1; - u8 cs1 :1; - - } PACKED ctrl; - - u8 data; -} PACKED; - -struct bcm3510_hab_cmd_tune { - u8 length; - u8 clock_width; - u8 misc; - u8 TUNCTL_state; - - struct bcm3510_hab_cmd_tune_ctrl_data_pair ctl_dat[16]; -} PACKED; - -#define CMD_STATUS 0x38 -#define MSGID_STATUS1 0x08 -struct bcm3510_hab_cmd_status1 { - struct { - u8 EQ_MODE :4; - u8 reserved :2; - u8 QRE :1; /* if QSE and the spectrum is inversed */ - u8 QSE :1; /* automatic spectral inversion */ - } PACKED STATUS0; - - struct { - u8 RECEIVER_LOCK :1; - u8 FEC_LOCK :1; - u8 OUT_PLL_LOCK :1; - u8 reserved :5; - } PACKED STATUS1; - - struct { - u8 reserved :2; - u8 BW :1; - u8 NTE :1; /* NTSC filter sweep enabled */ - u8 AQI :1; /* currently acquiring */ - u8 FA :1; /* fast acquisition */ - u8 ARI :1; /* auto reacquire */ - u8 TI :1; /* programming the tuner */ - } PACKED STATUS2; - u8 STATUS3; - u8 SNR_EST0; - u8 SNR_EST1; - u8 TUNER_FREQ0; - u8 TUNER_FREQ1; - u8 TUNER_FREQ2; - u8 TUNER_FREQ3; - u8 SYM_RATE0; - u8 SYM_RATE1; - u8 SYM_RATE2; - u8 SYM_RATE3; - u8 SYM_OFFSET0; - u8 SYM_OFFSET1; - u8 SYM_ERROR0; - u8 SYM_ERROR1; - u8 IF_FREQ0; - u8 IF_FREQ1; - u8 IF_FREQ2; - u8 IF_FREQ3; - u8 IF_OFFSET0; - u8 IF_OFFSET1; - u8 IF_ERROR0; - u8 IF_ERROR1; - u8 NTSC_FILTER0; - u8 NTSC_FILTER1; - u8 NTSC_FILTER2; - u8 NTSC_FILTER3; - u8 NTSC_OFFSET0; - u8 NTSC_OFFSET1; - u8 NTSC_ERROR0; - u8 NTSC_ERROR1; - u8 INT_AGC_LEVEL0; - u8 INT_AGC_LEVEL1; - u8 EXT_AGC_LEVEL0; - u8 EXT_AGC_LEVEL1; -} PACKED; - -#define MSGID_STATUS2 0x14 -struct bcm3510_hab_cmd_status2 { - struct { - u8 EQ_MODE :4; - u8 reserved :2; - u8 QRE :1; - u8 QSR :1; - } PACKED STATUS0; - struct { - u8 RL :1; - u8 FL :1; - u8 OL :1; - u8 reserved :5; - } PACKED STATUS1; - u8 SYMBOL_RATE0; - u8 SYMBOL_RATE1; - u8 SYMBOL_RATE2; - u8 SYMBOL_RATE3; - u8 LDCERC0; - u8 LDCERC1; - u8 LDCERC2; - u8 LDCERC3; - u8 LDUERC0; - u8 LDUERC1; - u8 LDUERC2; - u8 LDUERC3; - u8 LDBER0; - u8 LDBER1; - u8 LDBER2; - u8 LDBER3; - struct { - u8 MODE_TYPE :4; /* acquire mode 0 */ - u8 reservd :4; - } MODE_TYPE; - u8 SNR_EST0; - u8 SNR_EST1; - u8 SIGNAL; -} PACKED; - -#define CMD_SET_RF_BW_NOT_LISTED 0x3f -#define MSGID_SET_RF_BW_NOT_LISTED 0x11 -/* TODO */ - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bsbe1.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bsbe1.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bsbe1.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bsbe1.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/* - * bsbe1.h - ALPS BSBE1 tuner support - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org - */ - -#ifndef BSBE1_H -#define BSBE1_H - -static u8 alps_bsbe1_inittab[] = { - 0x01, 0x15, /* XTAL = 4MHz, VCO = 352 MHz */ - 0x02, 0x30, /* MCLK = 88 MHz */ - 0x03, 0x00, /* ACR output 0 */ - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x05, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x00, /* DAC output 0 */ - 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1/OP0 normal, val = 1 (LNB power on) */ - 0x0d, 0x82, /* DC offset compensation = on, beta_agc1 = 2 */ - 0x0f, 0x92, /* AGC1R */ - 0x10, 0x34, /* AGC2O */ - 0x11, 0x84, /* TLSR */ - 0x12, 0xb9, /* CFD */ - 0x15, 0xc9, /* lock detector threshold */ - 0x28, 0x00, /* out imp: normal, type: parallel, FEC mode: QPSK */ - 0x33, 0xfc, /* RS control */ - 0x34, 0x93, /* count viterbi bit errors per 2E18 bytes */ - 0xff, 0xff -}; - - -static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } - else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } - else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } - else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } - else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } - else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio ) & 0xf0); - - return 0; -} - -static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) -{ - int ret; - u8 data[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - struct i2c_adapter *i2c = fe->tuner_priv; - - if ((params->frequency < 950000) || (params->frequency > 2150000)) - return -EINVAL; - - div = params->frequency / 1000; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1; - data[3] = 0xe0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = i2c_transfer(i2c, &msg, 1); - return (ret != 1) ? -EIO : 0; -} - -static struct stv0299_config alps_bsbe1_config = { - .demod_address = 0x68, - .inittab = alps_bsbe1_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .min_delay_ms = 100, - .set_symbol_rate = alps_bsbe1_set_symbol_rate, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bsru6.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bsru6.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bsru6.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/bsru6.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,142 +0,0 @@ -/* - * bsru6.h - ALPS BSRU6 tuner support (moved from budget-ci.c) - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org - */ - -#ifndef BSRU6_H -#define BSRU6_H - -static u8 alps_bsru6_inittab[] = { - 0x01, 0x15, - 0x02, 0x00, - 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - 0x10, 0x3f, // AGC2 0x3d - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, // lock detector threshold - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 - 0x29, 0x1e, // 1/2 threshold - 0x2a, 0x14, // 2/3 threshold - 0x2b, 0x0f, // 3/4 threshold - 0x2c, 0x09, // 5/6 threshold - 0x2d, 0x05, // 7/8 threshold - 0x2e, 0x01, - 0x31, 0x1f, // test all FECs - 0x32, 0x19, // viterbi and synchro search - 0x33, 0xfc, // rs control - 0x34, 0x93, // error control - 0x0f, 0x52, - 0xff, 0xff -}; - -static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { - aclk = 0xb7; - bclk = 0x47; - } else if (srate < 3000000) { - aclk = 0xb7; - bclk = 0x4b; - } else if (srate < 7000000) { - aclk = 0xb7; - bclk = 0x4f; - } else if (srate < 14000000) { - aclk = 0xb7; - bclk = 0x53; - } else if (srate < 30000000) { - aclk = 0xb6; - bclk = 0x53; - } else if (srate < 45000000) { - aclk = 0xb4; - bclk = 0x51; - } - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, ratio & 0xf0); - - return 0; -} - -static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - struct i2c_adapter *i2c = fe->tuner_priv; - - if ((params->frequency < 950000) || (params->frequency > 2150000)) - return -EINVAL; - - div = (params->frequency + (125 - 1)) / 125; // round correctly - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; - buf[3] = 0xC4; - - if (params->frequency > 1530000) - buf[3] = 0xc0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(i2c, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct stv0299_config alps_bsru6_config = { - .demod_address = 0x68, - .inittab = alps_bsru6_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = alps_bsru6_set_symbol_rate, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22700.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22700.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22700.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22700.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,440 +0,0 @@ -/* - Conexant cx22700 DVB OFDM demodulator driver - - Copyright (C) 2001-2002 Convergence Integrated Media GmbH - Holger Waechtler - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "cx22700.h" - - -struct cx22700_state { - - struct i2c_adapter* i2c; - - const struct cx22700_config* config; - - struct dvb_frontend frontend; -}; - - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "cx22700: " args); \ - } while (0) - -static u8 init_tab [] = { - 0x04, 0x10, - 0x05, 0x09, - 0x06, 0x00, - 0x08, 0x04, - 0x09, 0x00, - 0x0a, 0x01, - 0x15, 0x40, - 0x16, 0x10, - 0x17, 0x87, - 0x18, 0x17, - 0x1a, 0x10, - 0x25, 0x04, - 0x2e, 0x00, - 0x39, 0x00, - 0x3a, 0x04, - 0x45, 0x08, - 0x46, 0x02, - 0x47, 0x05, -}; - - -static int cx22700_writereg (struct cx22700_state* state, u8 reg, u8 data) -{ - int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - - dprintk ("%s\n", __func__); - - ret = i2c_transfer (state->i2c, &msg, 1); - - if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", - __func__, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -static int cx22700_readreg (struct cx22700_state* state, u8 reg) -{ - int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - dprintk ("%s\n", __func__); - - ret = i2c_transfer (state->i2c, msg, 2); - - if (ret != 2) return -EIO; - - return b1[0]; -} - -static int cx22700_set_inversion (struct cx22700_state* state, int inversion) -{ - u8 val; - - dprintk ("%s\n", __func__); - - switch (inversion) { - case INVERSION_AUTO: - return -EOPNOTSUPP; - case INVERSION_ON: - val = cx22700_readreg (state, 0x09); - return cx22700_writereg (state, 0x09, val | 0x01); - case INVERSION_OFF: - val = cx22700_readreg (state, 0x09); - return cx22700_writereg (state, 0x09, val & 0xfe); - default: - return -EINVAL; - } -} - -static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p) -{ - static const u8 qam_tab [4] = { 0, 1, 0, 2 }; - static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 }; - u8 val; - - dprintk ("%s\n", __func__); - - if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8) - return -EINVAL; - - if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8) - return -EINVAL; - - if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5) - return -EINVAL; - - if (p->guard_interval < GUARD_INTERVAL_1_32 || - p->guard_interval > GUARD_INTERVAL_1_4) - return -EINVAL; - - if (p->transmission_mode != TRANSMISSION_MODE_2K && - p->transmission_mode != TRANSMISSION_MODE_8K) - return -EINVAL; - - if (p->constellation != QPSK && - p->constellation != QAM_16 && - p->constellation != QAM_64) - return -EINVAL; - - if (p->hierarchy_information < HIERARCHY_NONE || - p->hierarchy_information > HIERARCHY_4) - return -EINVAL; - - if (p->bandwidth < BANDWIDTH_8_MHZ || p->bandwidth > BANDWIDTH_6_MHZ) - return -EINVAL; - - if (p->bandwidth == BANDWIDTH_7_MHZ) - cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10)); - else - cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10)); - - val = qam_tab[p->constellation - QPSK]; - val |= p->hierarchy_information - HIERARCHY_NONE; - - cx22700_writereg (state, 0x04, val); - - val = fec_tab[p->code_rate_HP - FEC_1_2] << 3; - val |= fec_tab[p->code_rate_LP - FEC_1_2]; - - cx22700_writereg (state, 0x05, val); - - val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2; - val |= p->transmission_mode - TRANSMISSION_MODE_2K; - - cx22700_writereg (state, 0x06, val); - - cx22700_writereg (state, 0x08, 0x04 | 0x02); /* use user tps parameters */ - cx22700_writereg (state, 0x08, 0x04); /* restart aquisition */ - - return 0; -} - -static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p) -{ - static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 }; - static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4, - FEC_5_6, FEC_7_8 }; - u8 val; - - dprintk ("%s\n", __func__); - - if (!(cx22700_readreg(state, 0x07) & 0x20)) /* tps valid? */ - return -EAGAIN; - - val = cx22700_readreg (state, 0x01); - - if ((val & 0x7) > 4) - p->hierarchy_information = HIERARCHY_AUTO; - else - p->hierarchy_information = HIERARCHY_NONE + (val & 0x7); - - if (((val >> 3) & 0x3) > 2) - p->constellation = QAM_AUTO; - else - p->constellation = qam_tab[(val >> 3) & 0x3]; - - val = cx22700_readreg (state, 0x02); - - if (((val >> 3) & 0x07) > 4) - p->code_rate_HP = FEC_AUTO; - else - p->code_rate_HP = fec_tab[(val >> 3) & 0x07]; - - if ((val & 0x07) > 4) - p->code_rate_LP = FEC_AUTO; - else - p->code_rate_LP = fec_tab[val & 0x07]; - - val = cx22700_readreg (state, 0x03); - - p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3); - p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1); - - return 0; -} - -static int cx22700_init (struct dvb_frontend* fe) - -{ struct cx22700_state* state = fe->demodulator_priv; - int i; - - dprintk("cx22700_init: init chip\n"); - - cx22700_writereg (state, 0x00, 0x02); /* soft reset */ - cx22700_writereg (state, 0x00, 0x00); - - msleep(10); - - for (i=0; idemodulator_priv; - - u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) - | (cx22700_readreg (state, 0x0e) << 1); - u8 sync = cx22700_readreg (state, 0x07); - - *status = 0; - - if (rs_ber < 0xff00) - *status |= FE_HAS_SIGNAL; - - if (sync & 0x20) - *status |= FE_HAS_CARRIER; - - if (sync & 0x10) - *status |= FE_HAS_VITERBI; - - if (sync & 0x10) - *status |= FE_HAS_SYNC; - - if (*status == 0x0f) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct cx22700_state* state = fe->demodulator_priv; - - *ber = cx22700_readreg (state, 0x0c) & 0x7f; - cx22700_writereg (state, 0x0c, 0x00); - - return 0; -} - -static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) -{ - struct cx22700_state* state = fe->demodulator_priv; - - u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) - | (cx22700_readreg (state, 0x0e) << 1); - *signal_strength = ~rs_ber; - - return 0; -} - -static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct cx22700_state* state = fe->demodulator_priv; - - u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) - | (cx22700_readreg (state, 0x0e) << 1); - *snr = ~rs_ber; - - return 0; -} - -static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct cx22700_state* state = fe->demodulator_priv; - - *ucblocks = cx22700_readreg (state, 0x0f); - cx22700_writereg (state, 0x0f, 0x00); - - return 0; -} - -static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct cx22700_state* state = fe->demodulator_priv; - - cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/ - cx22700_writereg (state, 0x00, 0x00); - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - cx22700_set_inversion (state, p->inversion); - cx22700_set_tps (state, &p->u.ofdm); - cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */ - cx22700_writereg (state, 0x00, 0x01); /* restart acquire */ - - return 0; -} - -static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct cx22700_state* state = fe->demodulator_priv; - u8 reg09 = cx22700_readreg (state, 0x09); - - p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22700_get_tps (state, &p->u.ofdm); -} - -static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct cx22700_state* state = fe->demodulator_priv; - - if (enable) { - return cx22700_writereg(state, 0x0a, 0x00); - } else { - return cx22700_writereg(state, 0x0a, 0x01); - } -} - -static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) -{ - fesettings->min_delay_ms = 150; - fesettings->step_size = 166667; - fesettings->max_drift = 166667*2; - return 0; -} - -static void cx22700_release(struct dvb_frontend* fe) -{ - struct cx22700_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops cx22700_ops; - -struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, - struct i2c_adapter* i2c) -{ - struct cx22700_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct cx22700_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* check if the demod is there */ - if (cx22700_readreg(state, 0x07) < 0) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops cx22700_ops = { - - .info = { - .name = "Conexant CX22700 DVB-T", - .type = FE_OFDM, - .frequency_min = 470000000, - .frequency_max = 860000000, - .frequency_stepsize = 166667, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_RECOVER - }, - - .release = cx22700_release, - - .init = cx22700_init, - .i2c_gate_ctrl = cx22700_i2c_gate_ctrl, - - .set_frontend = cx22700_set_frontend, - .get_frontend = cx22700_get_frontend, - .get_tune_settings = cx22700_get_tune_settings, - - .read_status = cx22700_read_status, - .read_ber = cx22700_read_ber, - .read_signal_strength = cx22700_read_signal_strength, - .read_snr = cx22700_read_snr, - .read_ucblocks = cx22700_read_ucblocks, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver"); -MODULE_AUTHOR("Holger Waechtler"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(cx22700_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22700.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22700.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22700.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22700.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - Conexant CX22700 DVB OFDM demodulator driver - - Copyright (C) 2001-2002 Convergence Integrated Media GmbH - Holger Waechtler - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef CX22700_H -#define CX22700_H - -#include - -struct cx22700_config -{ - /* the demodulator's i2c address */ - u8 demod_address; -}; - -#if defined(CONFIG_DVB_CX22700) || (defined(CONFIG_DVB_CX22700_MODULE) && defined(MODULE)) -extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_CX22700 - -#endif // CX22700_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22702.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22702.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22702.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22702.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,638 +0,0 @@ -/* - Conexant 22702 DVB OFDM demodulator driver - - based on: - Alps TDMB7 DVB OFDM demodulator driver - - Copyright (C) 2001-2002 Convergence Integrated Media GmbH - Holger Waechtler - - Copyright (C) 2004 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "cx22702.h" - -struct cx22702_state { - - struct i2c_adapter *i2c; - - /* configuration settings */ - const struct cx22702_config *config; - - struct dvb_frontend frontend; - - /* previous uncorrected block counter */ - u8 prevUCBlocks; -}; - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable verbose debug messages"); - -#define dprintk if (debug) printk - -/* Register values to initialise the demod */ -static const u8 init_tab[] = { - 0x00, 0x00, /* Stop aquisition */ - 0x0B, 0x06, - 0x09, 0x01, - 0x0D, 0x41, - 0x16, 0x32, - 0x20, 0x0A, - 0x21, 0x17, - 0x24, 0x3e, - 0x26, 0xff, - 0x27, 0x10, - 0x28, 0x00, - 0x29, 0x00, - 0x2a, 0x10, - 0x2b, 0x00, - 0x2c, 0x10, - 0x2d, 0x00, - 0x48, 0xd4, - 0x49, 0x56, - 0x6b, 0x1e, - 0xc8, 0x02, - 0xf9, 0x00, - 0xfa, 0x00, - 0xfb, 0x00, - 0xfc, 0x00, - 0xfd, 0x00, -}; - -static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data) -{ - int ret; - u8 buf[] = { reg, data }; - struct i2c_msg msg = { - .addr = state->config->demod_address, .flags = 0, - .buf = buf, .len = 2 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (unlikely(ret != 1)) { - printk(KERN_ERR - "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", - __func__, reg, data, ret); - return -1; - } - - return 0; -} - -static u8 cx22702_readreg(struct cx22702_state *state, u8 reg) -{ - int ret; - u8 data; - - struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, - .buf = ®, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, - .buf = &data, .len = 1 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (unlikely(ret != 2)) { - printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n", - __func__, reg, ret); - return 0; - } - - return data; -} - -static int cx22702_set_inversion(struct cx22702_state *state, int inversion) -{ - u8 val; - - val = cx22702_readreg(state, 0x0C); - switch (inversion) { - case INVERSION_AUTO: - return -EOPNOTSUPP; - case INVERSION_ON: - val |= 0x01; - break; - case INVERSION_OFF: - val &= 0xfe; - break; - default: - return -EINVAL; - } - return cx22702_writereg(state, 0x0C, val); -} - -/* Retrieve the demod settings */ -static int cx22702_get_tps(struct cx22702_state *state, - struct dvb_ofdm_parameters *p) -{ - u8 val; - - /* Make sure the TPS regs are valid */ - if (!(cx22702_readreg(state, 0x0A) & 0x20)) - return -EAGAIN; - - val = cx22702_readreg(state, 0x01); - switch ((val & 0x18) >> 3) { - case 0: - p->constellation = QPSK; - break; - case 1: - p->constellation = QAM_16; - break; - case 2: - p->constellation = QAM_64; - break; - } - switch (val & 0x07) { - case 0: - p->hierarchy_information = HIERARCHY_NONE; - break; - case 1: - p->hierarchy_information = HIERARCHY_1; - break; - case 2: - p->hierarchy_information = HIERARCHY_2; - break; - case 3: - p->hierarchy_information = HIERARCHY_4; - break; - } - - - val = cx22702_readreg(state, 0x02); - switch ((val & 0x38) >> 3) { - case 0: - p->code_rate_HP = FEC_1_2; - break; - case 1: - p->code_rate_HP = FEC_2_3; - break; - case 2: - p->code_rate_HP = FEC_3_4; - break; - case 3: - p->code_rate_HP = FEC_5_6; - break; - case 4: - p->code_rate_HP = FEC_7_8; - break; - } - switch (val & 0x07) { - case 0: - p->code_rate_LP = FEC_1_2; - break; - case 1: - p->code_rate_LP = FEC_2_3; - break; - case 2: - p->code_rate_LP = FEC_3_4; - break; - case 3: - p->code_rate_LP = FEC_5_6; - break; - case 4: - p->code_rate_LP = FEC_7_8; - break; - } - - val = cx22702_readreg(state, 0x03); - switch ((val & 0x0c) >> 2) { - case 0: - p->guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - p->guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - p->guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - p->guard_interval = GUARD_INTERVAL_1_4; - break; - } - switch (val & 0x03) { - case 0: - p->transmission_mode = TRANSMISSION_MODE_2K; - break; - case 1: - p->transmission_mode = TRANSMISSION_MODE_8K; - break; - } - - return 0; -} - -static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct cx22702_state *state = fe->demodulator_priv; - u8 val; - - dprintk("%s(%d)\n", __func__, enable); - val = cx22702_readreg(state, 0x0D); - if (enable) - val &= 0xfe; - else - val |= 0x01; - return cx22702_writereg(state, 0x0D, val); -} - -/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int cx22702_set_tps(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - u8 val; - struct cx22702_state *state = fe->demodulator_priv; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* set inversion */ - cx22702_set_inversion(state, p->inversion); - - /* set bandwidth */ - val = cx22702_readreg(state, 0x0C) & 0xcf; - switch (p->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - val |= 0x20; - break; - case BANDWIDTH_7_MHZ: - val |= 0x10; - break; - case BANDWIDTH_8_MHZ: - break; - default: - dprintk("%s: invalid bandwidth\n", __func__); - return -EINVAL; - } - cx22702_writereg(state, 0x0C, val); - - p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */ - - /* use auto configuration? */ - if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) || - (p->u.ofdm.constellation == QAM_AUTO) || - (p->u.ofdm.code_rate_HP == FEC_AUTO) || - (p->u.ofdm.code_rate_LP == FEC_AUTO) || - (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) || - (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) { - - /* TPS Source - use hardware driven values */ - cx22702_writereg(state, 0x06, 0x10); - cx22702_writereg(state, 0x07, 0x9); - cx22702_writereg(state, 0x08, 0xC1); - cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) - & 0xfc); - cx22702_writereg(state, 0x0C, - (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); - cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */ - dprintk("%s: Autodetecting\n", __func__); - return 0; - } - - /* manually programmed values */ - switch (p->u.ofdm.constellation) { /* mask 0x18 */ - case QPSK: - val = 0x00; - break; - case QAM_16: - val = 0x08; - break; - case QAM_64: - val = 0x10; - break; - default: - dprintk("%s: invalid constellation\n", __func__); - return -EINVAL; - } - switch (p->u.ofdm.hierarchy_information) { /* mask 0x07 */ - case HIERARCHY_NONE: - break; - case HIERARCHY_1: - val |= 0x01; - break; - case HIERARCHY_2: - val |= 0x02; - break; - case HIERARCHY_4: - val |= 0x03; - break; - default: - dprintk("%s: invalid hierarchy\n", __func__); - return -EINVAL; - } - cx22702_writereg(state, 0x06, val); - - switch (p->u.ofdm.code_rate_HP) { /* mask 0x38 */ - case FEC_NONE: - case FEC_1_2: - val = 0x00; - break; - case FEC_2_3: - val = 0x08; - break; - case FEC_3_4: - val = 0x10; - break; - case FEC_5_6: - val = 0x18; - break; - case FEC_7_8: - val = 0x20; - break; - default: - dprintk("%s: invalid code_rate_HP\n", __func__); - return -EINVAL; - } - switch (p->u.ofdm.code_rate_LP) { /* mask 0x07 */ - case FEC_NONE: - case FEC_1_2: - break; - case FEC_2_3: - val |= 0x01; - break; - case FEC_3_4: - val |= 0x02; - break; - case FEC_5_6: - val |= 0x03; - break; - case FEC_7_8: - val |= 0x04; - break; - default: - dprintk("%s: invalid code_rate_LP\n", __func__); - return -EINVAL; - } - cx22702_writereg(state, 0x07, val); - - switch (p->u.ofdm.guard_interval) { /* mask 0x0c */ - case GUARD_INTERVAL_1_32: - val = 0x00; - break; - case GUARD_INTERVAL_1_16: - val = 0x04; - break; - case GUARD_INTERVAL_1_8: - val = 0x08; - break; - case GUARD_INTERVAL_1_4: - val = 0x0c; - break; - default: - dprintk("%s: invalid guard_interval\n", __func__); - return -EINVAL; - } - switch (p->u.ofdm.transmission_mode) { /* mask 0x03 */ - case TRANSMISSION_MODE_2K: - break; - case TRANSMISSION_MODE_8K: - val |= 0x1; - break; - default: - dprintk("%s: invalid transmission_mode\n", __func__); - return -EINVAL; - } - cx22702_writereg(state, 0x08, val); - cx22702_writereg(state, 0x0B, - (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02); - cx22702_writereg(state, 0x0C, - (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); - - /* Begin channel aquisition */ - cx22702_writereg(state, 0x00, 0x01); - - return 0; -} - -/* Reset the demod hardware and reset all of the configuration registers - to a default state. */ -static int cx22702_init(struct dvb_frontend *fe) -{ - int i; - struct cx22702_state *state = fe->demodulator_priv; - - cx22702_writereg(state, 0x00, 0x02); - - msleep(10); - - for (i = 0; i < ARRAY_SIZE(init_tab); i += 2) - cx22702_writereg(state, init_tab[i], init_tab[i + 1]); - - cx22702_writereg(state, 0xf8, (state->config->output_mode << 1) - & 0x02); - - cx22702_i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct cx22702_state *state = fe->demodulator_priv; - u8 reg0A; - u8 reg23; - - *status = 0; - - reg0A = cx22702_readreg(state, 0x0A); - reg23 = cx22702_readreg(state, 0x23); - - dprintk("%s: status demod=0x%02x agc=0x%02x\n" - , __func__, reg0A, reg23); - - if (reg0A & 0x10) { - *status |= FE_HAS_LOCK; - *status |= FE_HAS_VITERBI; - *status |= FE_HAS_SYNC; - } - - if (reg0A & 0x20) - *status |= FE_HAS_CARRIER; - - if (reg23 < 0xf0) - *status |= FE_HAS_SIGNAL; - - return 0; -} - -static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct cx22702_state *state = fe->demodulator_priv; - - if (cx22702_readreg(state, 0xE4) & 0x02) { - /* Realtime statistics */ - *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 - | (cx22702_readreg(state, 0xDF) & 0x7F); - } else { - /* Averagtine statistics */ - *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 - | cx22702_readreg(state, 0xDF); - } - - return 0; -} - -static int cx22702_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - struct cx22702_state *state = fe->demodulator_priv; - - u16 rs_ber; - rs_ber = cx22702_readreg(state, 0x23); - *signal_strength = (rs_ber << 8) | rs_ber; - - return 0; -} - -static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct cx22702_state *state = fe->demodulator_priv; - - u16 rs_ber; - if (cx22702_readreg(state, 0xE4) & 0x02) { - /* Realtime statistics */ - rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 - | (cx22702_readreg(state, 0xDF) & 0x7F); - } else { - /* Averagine statistics */ - rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8 - | cx22702_readreg(state, 0xDF); - } - *snr = ~rs_ber; - - return 0; -} - -static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct cx22702_state *state = fe->demodulator_priv; - - u8 _ucblocks; - - /* RS Uncorrectable Packet Count then reset */ - _ucblocks = cx22702_readreg(state, 0xE3); - if (state->prevUCBlocks < _ucblocks) - *ucblocks = (_ucblocks - state->prevUCBlocks); - else - *ucblocks = state->prevUCBlocks - _ucblocks; - state->prevUCBlocks = _ucblocks; - - return 0; -} - -static int cx22702_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct cx22702_state *state = fe->demodulator_priv; - - u8 reg0C = cx22702_readreg(state, 0x0C); - - p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22702_get_tps(state, &p->u.ofdm); -} - -static int cx22702_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void cx22702_release(struct dvb_frontend *fe) -{ - struct cx22702_state *state = fe->demodulator_priv; - kfree(state); -} - -static const struct dvb_frontend_ops cx22702_ops; - -struct dvb_frontend *cx22702_attach(const struct cx22702_config *config, - struct i2c_adapter *i2c) -{ - struct cx22702_state *state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* check if the demod is there */ - if (cx22702_readreg(state, 0x1f) != 0x3) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &cx22702_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(cx22702_attach); - -static const struct dvb_frontend_ops cx22702_ops = { - - .info = { - .name = "Conexant CX22702 DVB-T", - .type = FE_OFDM, - .frequency_min = 177000000, - .frequency_max = 858000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER - }, - - .release = cx22702_release, - - .init = cx22702_init, - .i2c_gate_ctrl = cx22702_i2c_gate_ctrl, - - .set_frontend = cx22702_set_tps, - .get_frontend = cx22702_get_frontend, - .get_tune_settings = cx22702_get_tune_settings, - - .read_status = cx22702_read_status, - .read_ber = cx22702_read_ber, - .read_signal_strength = cx22702_read_signal_strength, - .read_snr = cx22702_read_snr, - .read_ucblocks = cx22702_read_ucblocks, -}; - -MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver"); -MODULE_AUTHOR("Steven Toth"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22702.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22702.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22702.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx22702.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* - Conexant 22702 DVB OFDM demodulator driver - - based on: - Alps TDMB7 DVB OFDM demodulator driver - - Copyright (C) 2001-2002 Convergence Integrated Media GmbH - Holger Waechtler - - Copyright (C) 2004 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef CX22702_H -#define CX22702_H - -#include - -struct cx22702_config { - /* the demodulator's i2c address */ - u8 demod_address; - - /* serial/parallel output */ -#define CX22702_PARALLEL_OUTPUT 0 -#define CX22702_SERIAL_OUTPUT 1 - u8 output_mode; -}; - -#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) \ - && defined(MODULE)) -extern struct dvb_frontend *cx22702_attach( - const struct cx22702_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *cx22702_attach( - const struct cx22702_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24110.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24110.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24110.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24110.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,667 +0,0 @@ -/* - cx24110 - Single Chip Satellite Channel Receiver driver module - - Copyright (C) 2002 Peter Hettkamp based on - work - Copyright (C) 1999 Convergence Integrated Media GmbH - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "cx24110.h" - - -struct cx24110_state { - - struct i2c_adapter* i2c; - - const struct cx24110_config* config; - - struct dvb_frontend frontend; - - u32 lastber; - u32 lastbler; - u32 lastesn0; -}; - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "cx24110: " args); \ - } while (0) - -static struct {u8 reg; u8 data;} cx24110_regdata[]= - /* Comments beginning with @ denote this value should - be the default */ - {{0x09,0x01}, /* SoftResetAll */ - {0x09,0x00}, /* release reset */ - {0x01,0xe8}, /* MSB of code rate 27.5MS/s */ - {0x02,0x17}, /* middle byte " */ - {0x03,0x29}, /* LSB " */ - {0x05,0x03}, /* @ DVB mode, standard code rate 3/4 */ - {0x06,0xa5}, /* @ PLL 60MHz */ - {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */ - {0x0a,0x00}, /* @ partial chip disables, do not set */ - {0x0b,0x01}, /* set output clock in gapped mode, start signal low - active for first byte */ - {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */ - {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */ - {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1 - to avoid starting the BER counter. Reset the - CRC test bit. Finite counting selected */ - {0x15,0xff}, /* @ size of the limited time window for RS BER - estimation. It is *256 RS blocks, this - gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */ - {0x16,0x00}, /* @ enable all RS output ports */ - {0x17,0x04}, /* @ time window allowed for the RS to sync */ - {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned - for automatically */ - /* leave the current code rate and normalization - registers as they are after reset... */ - {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting - only once */ - {0x23,0x18}, /* @ size of the limited time window for Viterbi BER - estimation. It is *65536 channel bits, i.e. - approx. 38ms at 27.5MS/s, rate 3/4 */ - {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */ - /* leave front-end AGC parameters at default values */ - /* leave decimation AGC parameters at default values */ - {0x35,0x40}, /* disable all interrupts. They are not connected anyway */ - {0x36,0xff}, /* clear all interrupt pending flags */ - {0x37,0x00}, /* @ fully enable AutoAcqq state machine */ - {0x38,0x07}, /* @ enable fade recovery, but not autostart AutoAcq */ - /* leave the equalizer parameters on their default values */ - /* leave the final AGC parameters on their default values */ - {0x41,0x00}, /* @ MSB of front-end derotator frequency */ - {0x42,0x00}, /* @ middle bytes " */ - {0x43,0x00}, /* @ LSB " */ - /* leave the carrier tracking loop parameters on default */ - /* leave the bit timing loop parameters at default */ - {0x56,0x4d}, /* set the filtune voltage to 2.7V, as recommended by */ - /* the cx24108 data sheet for symbol rates above 15MS/s */ - {0x57,0x00}, /* @ Filter sigma delta enabled, positive */ - {0x61,0x95}, /* GPIO pins 1-4 have special function */ - {0x62,0x05}, /* GPIO pin 5 has special function, pin 6 is GPIO */ - {0x63,0x00}, /* All GPIO pins use CMOS output characteristics */ - {0x64,0x20}, /* GPIO 6 is input, all others are outputs */ - {0x6d,0x30}, /* tuner auto mode clock freq 62kHz */ - {0x70,0x15}, /* use auto mode, tuner word is 21 bits long */ - {0x73,0x00}, /* @ disable several demod bypasses */ - {0x74,0x00}, /* @ " */ - {0x75,0x00} /* @ " */ - /* the remaining registers are for SEC */ - }; - - -static int cx24110_writereg (struct cx24110_state* state, int reg, int data) -{ - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - int err; - - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - dprintk ("%s: writereg error (err == %i, reg == 0x%02x," - " data == 0x%02x)\n", __func__, err, reg, data); - return -EREMOTEIO; - } - - return 0; -} - -static int cx24110_readreg (struct cx24110_state* state, u8 reg) -{ - int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) return ret; - - return b1[0]; -} - -static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inversion_t inversion) -{ -/* fixme (low): error handling */ - - switch (inversion) { - case INVERSION_OFF: - cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1); - /* AcqSpectrInvDis on. No idea why someone should want this */ - cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7); - /* Initial value 0 at start of acq */ - cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef); - /* current value 0 */ - /* The cx24110 manual tells us this reg is read-only. - But what the heck... set it ayways */ - break; - case INVERSION_ON: - cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1); - /* AcqSpectrInvDis on. No idea why someone should want this */ - cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08); - /* Initial value 1 at start of acq */ - cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10); - /* current value 1 */ - break; - case INVERSION_AUTO: - cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe); - /* AcqSpectrInvDis off. Leave initial & current states as is */ - break; - default: - return -EINVAL; - } - - return 0; -} - -static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec) -{ -/* fixme (low): error handling */ - - static const int rate[]={-1,1,2,3,5,7,-1}; - static const int g1[]={-1,0x01,0x02,0x05,0x15,0x45,-1}; - static const int g2[]={-1,0x01,0x03,0x06,0x1a,0x7a,-1}; - - /* Well, the AutoAcq engine of the cx24106 and 24110 automatically - searches all enabled viterbi rates, and can handle non-standard - rates as well. */ - - if (fec>FEC_AUTO) - fec=FEC_AUTO; - - if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */ - cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf); - /* clear AcqVitDis bit */ - cx24110_writereg(state,0x18,0xae); - /* allow all DVB standard code rates */ - cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3); - /* set nominal Viterbi rate 3/4 */ - cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3); - /* set current Viterbi rate 3/4 */ - cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06); - /* set the puncture registers for code rate 3/4 */ - return 0; - } else { - cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20); - /* set AcqVitDis bit */ - if(rate[fec]>0) { - cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]); - /* set nominal Viterbi rate */ - cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]); - /* set current Viterbi rate */ - cx24110_writereg(state,0x1a,g1[fec]); - cx24110_writereg(state,0x1b,g2[fec]); - /* not sure if this is the right way: I always used AutoAcq mode */ - } else - return -EOPNOTSUPP; -/* fixme (low): which is the correct return code? */ - }; - return 0; -} - -static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state) -{ - int i; - - i=cx24110_readreg(state,0x22)&0x0f; - if(!(i&0x08)) { - return FEC_1_2 + i - 1; - } else { -/* fixme (low): a special code rate has been selected. In theory, we need to - return a denominator value, a numerator value, and a pair of puncture - maps to correctly describe this mode. But this should never happen in - practice, because it cannot be set by cx24110_get_fec. */ - return FEC_NONE; - } -} - -static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate) -{ -/* fixme (low): add error handling */ - u32 ratio; - u32 tmp, fclk, BDRI; - - static const u32 bands[]={5000000UL,15000000UL,90999000UL/2}; - int i; - - dprintk("cx24110 debug: entering %s(%d)\n",__func__,srate); - if (srate>90999000UL/2) - srate=90999000UL/2; - if (srate<500000) - srate=500000; - - for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++) - ; - /* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz, - and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult, - R06[3:0] PLLphaseDetGain */ - tmp=cx24110_readreg(state,0x07)&0xfc; - if(srate<90999000UL/4) { /* sample rate 45MHz*/ - cx24110_writereg(state,0x07,tmp); - cx24110_writereg(state,0x06,0x78); - fclk=90999000UL/2; - } else if(srate<60666000UL/2) { /* sample rate 60MHz */ - cx24110_writereg(state,0x07,tmp|0x1); - cx24110_writereg(state,0x06,0xa5); - fclk=60666000UL; - } else if(srate<80888000UL/2) { /* sample rate 80MHz */ - cx24110_writereg(state,0x07,tmp|0x2); - cx24110_writereg(state,0x06,0x87); - fclk=80888000UL; - } else { /* sample rate 90MHz */ - cx24110_writereg(state,0x07,tmp|0x3); - cx24110_writereg(state,0x06,0x78); - fclk=90999000UL; - }; - dprintk("cx24110 debug: fclk %d Hz\n",fclk); - /* we need to divide two integers with approx. 27 bits in 32 bit - arithmetic giving a 25 bit result */ - /* the maximum dividend is 90999000/2, 0x02b6446c, this number is - also the most complex divisor. Hence, the dividend has, - assuming 32bit unsigned arithmetic, 6 clear bits on top, the - divisor 2 unused bits at the bottom. Also, the quotient is - always less than 1/2. Borrowed from VES1893.c, of course */ - - tmp=srate<<6; - BDRI=fclk>>2; - ratio=(tmp/BDRI); - - tmp=(tmp%BDRI)<<8; - ratio=(ratio<<8)+(tmp/BDRI); - - tmp=(tmp%BDRI)<<8; - ratio=(ratio<<8)+(tmp/BDRI); - - tmp=(tmp%BDRI)<<1; - ratio=(ratio<<1)+(tmp/BDRI); - - dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]); - dprintk("fclk = %d\n", fclk); - dprintk("ratio= %08x\n", ratio); - - cx24110_writereg(state, 0x1, (ratio>>16)&0xff); - cx24110_writereg(state, 0x2, (ratio>>8)&0xff); - cx24110_writereg(state, 0x3, (ratio)&0xff); - - return 0; - -} - -static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len) -{ - struct cx24110_state *state = fe->demodulator_priv; - - if (len != 3) - return -EINVAL; - -/* tuner data is 21 bits long, must be left-aligned in data */ -/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */ -/* FIXME (low): add error handling, avoid infinite loops if HW fails... */ - - cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */ - cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */ - - /* if the auto tuner writer is still busy, clear it out */ - while (cx24110_readreg(state,0x6d)&0x80) - cx24110_writereg(state,0x72,0); - - /* write the topmost 8 bits */ - cx24110_writereg(state,0x72,buf[0]); - - /* wait for the send to be completed */ - while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) - ; - - /* send another 8 bytes */ - cx24110_writereg(state,0x72,buf[1]); - while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) - ; - - /* and the topmost 5 bits of this byte */ - cx24110_writereg(state,0x72,buf[2]); - while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) - ; - - /* now strobe the enable line once */ - cx24110_writereg(state,0x6d,0x32); - cx24110_writereg(state,0x6d,0x30); - - return 0; -} - -static int cx24110_initfe(struct dvb_frontend* fe) -{ - struct cx24110_state *state = fe->demodulator_priv; -/* fixme (low): error handling */ - int i; - - dprintk("%s: init chip\n", __func__); - - for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) { - cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data); - }; - - return 0; -} - -static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct cx24110_state *state = fe->demodulator_priv; - - switch (voltage) { - case SEC_VOLTAGE_13: - return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0); - case SEC_VOLTAGE_18: - return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40); - default: - return -EINVAL; - }; -} - -static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) -{ - int rv, bit; - struct cx24110_state *state = fe->demodulator_priv; - unsigned long timeout; - - if (burst == SEC_MINI_A) - bit = 0x00; - else if (burst == SEC_MINI_B) - bit = 0x08; - else - return -EINVAL; - - rv = cx24110_readreg(state, 0x77); - if (!(rv & 0x04)) - cx24110_writereg(state, 0x77, rv | 0x04); - - rv = cx24110_readreg(state, 0x76); - cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit)); - timeout = jiffies + msecs_to_jiffies(100); - while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40)) - ; /* wait for LNB ready */ - - return 0; -} - -static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *cmd) -{ - int i, rv; - struct cx24110_state *state = fe->demodulator_priv; - unsigned long timeout; - - if (cmd->msg_len < 3 || cmd->msg_len > 6) - return -EINVAL; /* not implemented */ - - for (i = 0; i < cmd->msg_len; i++) - cx24110_writereg(state, 0x79 + i, cmd->msg[i]); - - rv = cx24110_readreg(state, 0x77); - if (rv & 0x04) { - cx24110_writereg(state, 0x77, rv & ~0x04); - msleep(30); /* reportedly fixes switching problems */ - } - - rv = cx24110_readreg(state, 0x76); - - cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); - timeout = jiffies + msecs_to_jiffies(100); - while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40)) - ; /* wait for LNB ready */ - - return 0; -} - -static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct cx24110_state *state = fe->demodulator_priv; - - int sync = cx24110_readreg (state, 0x55); - - *status = 0; - - if (sync & 0x10) - *status |= FE_HAS_SIGNAL; - - if (sync & 0x08) - *status |= FE_HAS_CARRIER; - - sync = cx24110_readreg (state, 0x08); - - if (sync & 0x40) - *status |= FE_HAS_VITERBI; - - if (sync & 0x20) - *status |= FE_HAS_SYNC; - - if ((sync & 0x60) == 0x60) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct cx24110_state *state = fe->demodulator_priv; - - /* fixme (maybe): value range is 16 bit. Scale? */ - if(cx24110_readreg(state,0x24)&0x10) { - /* the Viterbi error counter has finished one counting window */ - cx24110_writereg(state,0x24,0x04); /* select the ber reg */ - state->lastber=cx24110_readreg(state,0x25)| - (cx24110_readreg(state,0x26)<<8); - cx24110_writereg(state,0x24,0x04); /* start new count window */ - cx24110_writereg(state,0x24,0x14); - } - *ber = state->lastber; - - return 0; -} - -static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) -{ - struct cx24110_state *state = fe->demodulator_priv; - -/* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */ - u8 signal = cx24110_readreg (state, 0x27)+128; - *signal_strength = (signal << 8) | signal; - - return 0; -} - -static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct cx24110_state *state = fe->demodulator_priv; - - /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */ - if(cx24110_readreg(state,0x6a)&0x80) { - /* the Es/N0 error counter has finished one counting window */ - state->lastesn0=cx24110_readreg(state,0x69)| - (cx24110_readreg(state,0x68)<<8); - cx24110_writereg(state,0x6a,0x84); /* start new count window */ - } - *snr = state->lastesn0; - - return 0; -} - -static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct cx24110_state *state = fe->demodulator_priv; - u32 lastbyer; - - if(cx24110_readreg(state,0x10)&0x40) { - /* the RS error counter has finished one counting window */ - cx24110_writereg(state,0x10,0x60); /* select the byer reg */ - lastbyer=cx24110_readreg(state,0x12)| - (cx24110_readreg(state,0x13)<<8)| - (cx24110_readreg(state,0x14)<<16); - cx24110_writereg(state,0x10,0x70); /* select the bler reg */ - state->lastbler=cx24110_readreg(state,0x12)| - (cx24110_readreg(state,0x13)<<8)| - (cx24110_readreg(state,0x14)<<16); - cx24110_writereg(state,0x10,0x20); /* start new count window */ - } - *ucblocks = state->lastbler; - - return 0; -} - -static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct cx24110_state *state = fe->demodulator_priv; - - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - cx24110_set_inversion (state, p->inversion); - cx24110_set_fec (state, p->u.qpsk.fec_inner); - cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate); - cx24110_writereg(state,0x04,0x05); /* start aquisition */ - - return 0; -} - -static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct cx24110_state *state = fe->demodulator_priv; - s32 afc; unsigned sclk; - -/* cannot read back tuner settings (freq). Need to have some private storage */ - - sclk = cx24110_readreg (state, 0x07) & 0x03; -/* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz. - * Need 64 bit arithmetic. Is thiss possible in the kernel? */ - if (sclk==0) sclk=90999000L/2L; - else if (sclk==1) sclk=60666000L; - else if (sclk==2) sclk=80888000L; - else sclk=90999000L; - sclk>>=8; - afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+ - ((sclk*cx24110_readreg (state, 0x45))>>8)+ - ((sclk*cx24110_readreg (state, 0x46))>>16); - - p->frequency += afc; - p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ? - INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = cx24110_get_fec (state); - - return 0; -} - -static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct cx24110_state *state = fe->demodulator_priv; - - return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0)); -} - -static void cx24110_release(struct dvb_frontend* fe) -{ - struct cx24110_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops cx24110_ops; - -struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, - struct i2c_adapter* i2c) -{ - struct cx24110_state* state = NULL; - int ret; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct cx24110_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->lastber = 0; - state->lastbler = 0; - state->lastesn0 = 0; - - /* check if the demod is there */ - ret = cx24110_readreg(state, 0x00); - if ((ret != 0x5a) && (ret != 0x69)) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops cx24110_ops = { - - .info = { - .name = "Conexant CX24110 DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1011, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_RECOVER - }, - - .release = cx24110_release, - - .init = cx24110_initfe, - .write = _cx24110_pll_write, - .set_frontend = cx24110_set_frontend, - .get_frontend = cx24110_get_frontend, - .read_status = cx24110_read_status, - .read_ber = cx24110_read_ber, - .read_signal_strength = cx24110_read_signal_strength, - .read_snr = cx24110_read_snr, - .read_ucblocks = cx24110_read_ucblocks, - - .diseqc_send_master_cmd = cx24110_send_diseqc_msg, - .set_tone = cx24110_set_tone, - .set_voltage = cx24110_set_voltage, - .diseqc_send_burst = cx24110_diseqc_send_burst, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver"); -MODULE_AUTHOR("Peter Hettkamp"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(cx24110_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24110.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24110.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24110.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24110.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* - cx24110 - Single Chip Satellite Channel Receiver driver module - - Copyright (C) 2002 Peter Hettkamp based on - work - Copyright (C) 1999 Convergence Integrated Media GmbH - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef CX24110_H -#define CX24110_H - -#include - -struct cx24110_config -{ - /* the demodulator's i2c address */ - u8 demod_address; -}; - -static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) -{ - u8 buf[] = { - (u8)((val >> 24) & 0xff), - (u8)((val >> 16) & 0xff), - (u8)((val >> 8) & 0xff) - }; - - if (fe->ops.write) - return fe->ops.write(fe, buf, 3); - return 0; -} - -#if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) -extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_CX24110 - -#endif // CX24110_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24113.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24113.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24113.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24113.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,620 +0,0 @@ -/* - * Driver for Conexant CX24113/CX24128 Tuner (Satellite) - * - * Copyright (C) 2007-8 Patrick Boettcher - * - * Developed for BBTI / Technisat - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "cx24113.h" - -static int debug; - -#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0) -#define err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0) - -#define dprintk(args...) \ - do { \ - if (debug) { \ - printk(KERN_DEBUG "CX24113: %s: ", __func__); \ - printk(args); \ - } \ - } while (0) - -struct cx24113_state { - struct i2c_adapter *i2c; - const struct cx24113_config *config; - -#define REV_CX24113 0x23 - u8 rev; - u8 ver; - - u8 icp_mode:1; - -#define ICP_LEVEL1 0 -#define ICP_LEVEL2 1 -#define ICP_LEVEL3 2 -#define ICP_LEVEL4 3 - u8 icp_man:2; - u8 icp_auto_low:2; - u8 icp_auto_mlow:2; - u8 icp_auto_mhi:2; - u8 icp_auto_hi:2; - u8 icp_dig; - -#define LNA_MIN_GAIN 0 -#define LNA_MID_GAIN 1 -#define LNA_MAX_GAIN 2 - u8 lna_gain:2; - - u8 acp_on:1; - - u8 vco_mode:2; - u8 vco_shift:1; -#define VCOBANDSEL_6 0x80 -#define VCOBANDSEL_5 0x01 -#define VCOBANDSEL_4 0x02 -#define VCOBANDSEL_3 0x04 -#define VCOBANDSEL_2 0x08 -#define VCOBANDSEL_1 0x10 - u8 vco_band; - -#define VCODIV4 4 -#define VCODIV2 2 - u8 vcodiv; - - u8 bs_delay:4; - u16 bs_freqcnt:13; - u16 bs_rdiv; - u8 prescaler_mode:1; - - u8 rfvga_bias_ctrl; - - s16 tuner_gain_thres; - u8 gain_level; - - u32 frequency; - - u8 refdiv; - - u8 Fwindow_enabled; -}; - -static int cx24113_writereg(struct cx24113_state *state, int reg, int data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->i2c_addr, - .flags = 0, .buf = buf, .len = 2 }; - int err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) { - printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x," - " data == 0x%02x)\n", __func__, err, reg, data); - return err; - } - - return 0; -} - -static int cx24113_readreg(struct cx24113_state *state, u8 reg) -{ - int ret; - u8 b; - struct i2c_msg msg[] = { - { .addr = state->config->i2c_addr, - .flags = 0, .buf = ®, .len = 1 }, - { .addr = state->config->i2c_addr, - .flags = I2C_M_RD, .buf = &b, .len = 1 } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n", - __func__, reg, ret); - return ret; - } - - return b; -} - -static void cx24113_set_parameters(struct cx24113_state *state) -{ - u8 r; - - r = cx24113_readreg(state, 0x10) & 0x82; - r |= state->icp_mode; - r |= state->icp_man << 4; - r |= state->icp_dig << 2; - r |= state->prescaler_mode << 5; - cx24113_writereg(state, 0x10, r); - - r = (state->icp_auto_low << 0) | (state->icp_auto_mlow << 2) - | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6); - cx24113_writereg(state, 0x11, r); - - if (state->rev == REV_CX24113) { - r = cx24113_readreg(state, 0x20) & 0xec; - r |= state->lna_gain; - r |= state->rfvga_bias_ctrl << 4; - cx24113_writereg(state, 0x20, r); - } - - r = cx24113_readreg(state, 0x12) & 0x03; - r |= state->acp_on << 2; - r |= state->bs_delay << 4; - cx24113_writereg(state, 0x12, r); - - r = cx24113_readreg(state, 0x18) & 0x40; - r |= state->vco_shift; - if (state->vco_band == VCOBANDSEL_6) - r |= (1 << 7); - else - r |= (state->vco_band << 1); - cx24113_writereg(state, 0x18, r); - - r = cx24113_readreg(state, 0x14) & 0x20; - r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f); - cx24113_writereg(state, 0x14, r); - cx24113_writereg(state, 0x15, (state->bs_freqcnt & 0xff)); - - cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff); - r = (cx24113_readreg(state, 0x17) & 0x0f) | - ((state->bs_rdiv & 0x0f) << 4); - cx24113_writereg(state, 0x17, r); -} - -#define VGA_0 0x00 -#define VGA_1 0x04 -#define VGA_2 0x02 -#define VGA_3 0x06 -#define VGA_4 0x01 -#define VGA_5 0x05 -#define VGA_6 0x03 -#define VGA_7 0x07 - -#define RFVGA_0 0x00 -#define RFVGA_1 0x01 -#define RFVGA_2 0x02 -#define RFVGA_3 0x03 - -static int cx24113_set_gain_settings(struct cx24113_state *state, - s16 power_estimation) -{ - u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0, - vga = cx24113_readreg(state, 0x1f) & 0x3f, - rfvga = cx24113_readreg(state, 0x20) & 0xf3; - u8 gain_level = power_estimation >= state->tuner_gain_thres; - - dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n", - power_estimation, state->tuner_gain_thres, - state->gain_level, gain_level); - - if (gain_level == state->gain_level) - return 0; /* nothing to be done */ - - ampout |= 0xf; - - if (gain_level) { - rfvga |= RFVGA_0 << 2; - vga |= (VGA_7 << 3) | VGA_7; - } else { - rfvga |= RFVGA_2 << 2; - vga |= (VGA_6 << 3) | VGA_2; - } - state->gain_level = gain_level; - - cx24113_writereg(state, 0x1d, ampout); - cx24113_writereg(state, 0x1f, vga); - cx24113_writereg(state, 0x20, rfvga); - - return 1; /* did something */ -} - -static int cx24113_set_Fref(struct cx24113_state *state, u8 high) -{ - u8 xtal = cx24113_readreg(state, 0x02); - if (state->rev == 0x43 && state->vcodiv == VCODIV4) - high = 1; - - xtal &= ~0x2; - if (high) - xtal |= high << 1; - return cx24113_writereg(state, 0x02, xtal); -} - -static int cx24113_enable(struct cx24113_state *state, u8 enable) -{ - u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable; - if (state->rev == REV_CX24113) - r21 |= (1 << 1); - return cx24113_writereg(state, 0x21, r21); -} - -static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz) -{ - u8 r; - - if (bandwidth_khz <= 19000) - r = 0x03 << 6; - else if (bandwidth_khz <= 25000) - r = 0x02 << 6; - else - r = 0x01 << 6; - - dprintk("bandwidth to be set: %d\n", bandwidth_khz); - bandwidth_khz *= 10; - bandwidth_khz -= 10000; - bandwidth_khz /= 1000; - bandwidth_khz += 5; - bandwidth_khz /= 10; - - dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz); - - r |= bandwidth_khz & 0x3f; - - return cx24113_writereg(state, 0x1e, r); -} - -static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on) -{ - u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7); - return cx24113_writereg(state, 0x10, r); -} - -static int cx24113_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct cx24113_state *state = fe->tuner_priv; - u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1; - if (r) - *status |= TUNER_STATUS_LOCKED; - dprintk("PLL locked: %d\n", r); - return 0; -} - -static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv) -{ - if (state->rev == 0x43 && state->vcodiv == VCODIV4) - refdiv = 2; - return state->refdiv = refdiv; -} - -static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f) -{ - s32 N; - s64 F; - u64 dividend; - u8 R, r; - u8 vcodiv; - u8 factor; - s32 freq_hz = state->frequency * 1000; - - if (state->config->xtal_khz < 20000) - factor = 1; - else - factor = 2; - - if (state->rev == REV_CX24113) { - if (state->frequency >= 1100000) - vcodiv = VCODIV2; - else - vcodiv = VCODIV4; - } else { - if (state->frequency >= 1165000) - vcodiv = VCODIV2; - else - vcodiv = VCODIV4; - } - state->vcodiv = vcodiv; - - dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv); - R = 0; - do { - R = cx24113_set_ref_div(state, R + 1); - - /* calculate tuner PLL settings: */ - N = (freq_hz / 100 * vcodiv) * R; - N /= (state->config->xtal_khz) * factor * 2; - N += 5; /* For round up. */ - N /= 10; - N -= 32; - } while (N < 6 && R < 3); - - if (N < 6) { - err("strange frequency: N < 6\n"); - return; - } - F = freq_hz; - F *= (u64) (R * vcodiv * 262144); - dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R); - /* do_div needs an u64 as first argument */ - dividend = F; - do_div(dividend, state->config->xtal_khz * 1000 * factor * 2); - F = dividend; - dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R); - F -= (N + 32) * 262144; - - dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R); - - if (state->Fwindow_enabled) { - if (F > (262144 / 2 - 1638)) - F = 262144 / 2 - 1638; - if (F < (-262144 / 2 + 1638)) - F = -262144 / 2 + 1638; - if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) { - F = 0; - r = cx24113_readreg(state, 0x10); - cx24113_writereg(state, 0x10, r | (1 << 6)); - } - } - dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R); - - *n = (u16) N; - *f = (s32) F; -} - - -static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r) -{ - u8 reg; - cx24113_writereg(state, 0x19, (n >> 1) & 0xff); - - reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f); - cx24113_writereg(state, 0x1a, reg); - - cx24113_writereg(state, 0x1b, (f >> 3) & 0xff); - - reg = cx24113_readreg(state, 0x1c) & 0x1f; - cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5)); - - cx24113_set_Fref(state, r - 1); -} - -static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency) -{ - u8 r = 1; /* or 2 */ - u16 n = 6; - s32 f = 0; - - r = cx24113_readreg(state, 0x14); - cx24113_writereg(state, 0x14, r & 0x3f); - - r = cx24113_readreg(state, 0x10); - cx24113_writereg(state, 0x10, r & 0xbf); - - state->frequency = frequency; - - dprintk("tuning to frequency: %d\n", frequency); - - cx24113_calc_pll_nf(state, &n, &f); - cx24113_set_nfr(state, n, f, state->refdiv); - - r = cx24113_readreg(state, 0x18) & 0xbf; - if (state->vcodiv != VCODIV2) - r |= 1 << 6; - cx24113_writereg(state, 0x18, r); - - /* The need for this sleep is not clear. But helps in some cases */ - msleep(5); - - r = cx24113_readreg(state, 0x1c) & 0xef; - cx24113_writereg(state, 0x1c, r | (1 << 4)); - return 0; -} - -static int cx24113_init(struct dvb_frontend *fe) -{ - struct cx24113_state *state = fe->tuner_priv; - int ret; - - state->tuner_gain_thres = -50; - state->gain_level = 255; /* to force a gain-setting initialization */ - state->icp_mode = 0; - - if (state->config->xtal_khz < 11000) { - state->icp_auto_hi = ICP_LEVEL4; - state->icp_auto_mhi = ICP_LEVEL4; - state->icp_auto_mlow = ICP_LEVEL3; - state->icp_auto_low = ICP_LEVEL3; - } else { - state->icp_auto_hi = ICP_LEVEL4; - state->icp_auto_mhi = ICP_LEVEL4; - state->icp_auto_mlow = ICP_LEVEL3; - state->icp_auto_low = ICP_LEVEL2; - } - - state->icp_dig = ICP_LEVEL3; - state->icp_man = ICP_LEVEL1; - state->acp_on = 1; - state->vco_mode = 0; - state->vco_shift = 0; - state->vco_band = VCOBANDSEL_1; - state->bs_delay = 8; - state->bs_freqcnt = 0x0fff; - state->bs_rdiv = 0x0fff; - state->prescaler_mode = 0; - state->lna_gain = LNA_MAX_GAIN; - state->rfvga_bias_ctrl = 1; - state->Fwindow_enabled = 1; - - cx24113_set_Fref(state, 0); - cx24113_enable(state, 0x3d); - cx24113_set_parameters(state); - - cx24113_set_gain_settings(state, -30); - - cx24113_set_bandwidth(state, 18025); - cx24113_set_clk_inversion(state, 1); - - if (state->config->xtal_khz >= 40000) - ret = cx24113_writereg(state, 0x02, - (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2)); - else - ret = cx24113_writereg(state, 0x02, - (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2)); - - return ret; -} - -static int cx24113_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct cx24113_state *state = fe->tuner_priv; - /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */ - u32 roll_off = 675; - u32 bw; - - bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000; - bw += (10000000/100) + 5; - bw /= 10; - bw += 1000; - cx24113_set_bandwidth(state, bw); - - cx24113_set_frequency(state, p->frequency); - msleep(5); - return cx24113_get_status(fe, &bw); -} - -static s8 cx24113_agc_table[2][10] = { - {-54, -41, -35, -30, -25, -21, -16, -10, -6, -2}, - {-39, -35, -30, -25, -19, -15, -11, -5, 1, 9}, -}; - -void cx24113_agc_callback(struct dvb_frontend *fe) -{ - struct cx24113_state *state = fe->tuner_priv; - s16 s, i; - if (!fe->ops.read_signal_strength) - return; - - do { - /* this only works with the current CX24123 implementation */ - fe->ops.read_signal_strength(fe, (u16 *) &s); - s >>= 8; - dprintk("signal strength: %d\n", s); - for (i = 0; i < sizeof(cx24113_agc_table[0]); i++) - if (cx24113_agc_table[state->gain_level][i] > s) - break; - s = -25 - i*5; - } while (cx24113_set_gain_settings(state, s)); -} -EXPORT_SYMBOL(cx24113_agc_callback); - -static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct cx24113_state *state = fe->tuner_priv; - *frequency = state->frequency; - return 0; -} - -static int cx24113_release(struct dvb_frontend *fe) -{ - struct cx24113_state *state = fe->tuner_priv; - dprintk("\n"); - fe->tuner_priv = NULL; - kfree(state); - return 0; -} - -static const struct dvb_tuner_ops cx24113_tuner_ops = { - .info = { - .name = "Conexant CX24113", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_step = 125, - }, - - .release = cx24113_release, - - .init = cx24113_init, - .sleep = NULL, - - .set_params = cx24113_set_params, - .get_frequency = cx24113_get_frequency, - .get_bandwidth = NULL, - .get_status = cx24113_get_status, -}; - -struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, - const struct cx24113_config *config, struct i2c_adapter *i2c) -{ - /* allocate memory for the internal state */ - struct cx24113_state *state = - kzalloc(sizeof(struct cx24113_state), GFP_KERNEL); - int rc; - if (state == NULL) { - err("Unable to kzalloc\n"); - goto error; - } - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - info("trying to detect myself\n"); - - /* making a dummy read, because of some expected troubles - * after power on */ - cx24113_readreg(state, 0x00); - - rc = cx24113_readreg(state, 0x00); - if (rc < 0) { - info("CX24113 not found.\n"); - goto error; - } - state->rev = rc; - - switch (rc) { - case 0x43: - info("detected CX24113 variant\n"); - break; - case REV_CX24113: - info("successfully detected\n"); - break; - default: - err("unsupported device id: %x\n", state->rev); - goto error; - } - state->ver = cx24113_readreg(state, 0x01); - info("version: %x\n", state->ver); - - /* create dvb_frontend */ - memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops, - sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = state; - return fe; - -error: - kfree(state); - - return NULL; -} -EXPORT_SYMBOL(cx24113_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware"); -MODULE_LICENSE("GPL"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24113.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24113.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24113.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24113.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/* - * Driver for Conexant CX24113/CX24128 Tuner (Satelite) - * - * Copyright (C) 2007-8 Patrick Boettcher - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef CX24113_H -#define CX24113_H - -struct dvb_frontend; - -struct cx24113_config { - u8 i2c_addr; /* 0x14 or 0x54 */ - - u32 xtal_khz; -}; - -#if defined(CONFIG_DVB_TUNER_CX24113) || \ - (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) -extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *, - const struct cx24113_config *config, struct i2c_adapter *i2c); - -extern void cx24113_agc_callback(struct dvb_frontend *fe); -#else -static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, - const struct cx24113_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline void cx24113_agc_callback(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -} -#endif - -#endif /* CX24113_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24116.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24116.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24116.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24116.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1509 +0,0 @@ -/* - Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver - - Copyright (C) 2006-2008 Steven Toth - Copyright (C) 2006-2007 Georg Acher - Copyright (C) 2007-2008 Darron Broad - March 2007 - Fixed some bugs. - Added diseqc support. - Added corrected signal strength support. - August 2007 - Sync with legacy version. - Some clean ups. - Copyright (C) 2008 Igor Liplianin - September, 9th 2008 - Fixed locking on high symbol rates (>30000). - Implement MPEG initialization parameter. - January, 17th 2009 - Fill set_voltage with actually control voltage code. - Correct set tone to not affect voltage. - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "cx24116.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); - -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_INFO "cx24116: " args); \ - } while (0) - -#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw" -#define CX24116_SEARCH_RANGE_KHZ 5000 - -/* known registers */ -#define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */ -#define CX24116_REG_EXECUTE (0x1f) /* execute command */ -#define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */ -#define CX24116_REG_RESET (0x20) /* reset status > 0 */ -#define CX24116_REG_SIGNAL (0x9e) /* signal low */ -#define CX24116_REG_SSTATUS (0x9d) /* signal high / status */ -#define CX24116_REG_QUALITY8 (0xa3) -#define CX24116_REG_QSTATUS (0xbc) -#define CX24116_REG_QUALITY0 (0xd5) -#define CX24116_REG_BER0 (0xc9) -#define CX24116_REG_BER8 (0xc8) -#define CX24116_REG_BER16 (0xc7) -#define CX24116_REG_BER24 (0xc6) -#define CX24116_REG_UCB0 (0xcb) -#define CX24116_REG_UCB8 (0xca) -#define CX24116_REG_CLKDIV (0xf3) -#define CX24116_REG_RATEDIV (0xf9) - -/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */ -#define CX24116_REG_FECSTATUS (0x9c) - -/* FECSTATUS bits */ -/* mask to determine configured fec (not tuned) or actual fec (tuned) */ -#define CX24116_FEC_FECMASK (0x1f) - -/* Select DVB-S demodulator, else DVB-S2 */ -#define CX24116_FEC_DVBS (0x20) -#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */ - -/* Pilot mode requested when tuning else always reset when tuned */ -#define CX24116_FEC_PILOT (0x80) - -/* arg buffer size */ -#define CX24116_ARGLEN (0x1e) - -/* rolloff */ -#define CX24116_ROLLOFF_020 (0x00) -#define CX24116_ROLLOFF_025 (0x01) -#define CX24116_ROLLOFF_035 (0x02) - -/* pilot bit */ -#define CX24116_PILOT_OFF (0x00) -#define CX24116_PILOT_ON (0x40) - -/* signal status */ -#define CX24116_HAS_SIGNAL (0x01) -#define CX24116_HAS_CARRIER (0x02) -#define CX24116_HAS_VITERBI (0x04) -#define CX24116_HAS_SYNCLOCK (0x08) -#define CX24116_HAS_UNKNOWN1 (0x10) -#define CX24116_HAS_UNKNOWN2 (0x20) -#define CX24116_STATUS_MASK (0x0f) -#define CX24116_SIGNAL_MASK (0xc0) - -#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */ -#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */ -#define CX24116_DISEQC_MESGCACHE (2) /* message cached */ - -/* arg offset for DiSEqC */ -#define CX24116_DISEQC_BURST (1) -#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */ -#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */ -#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */ -#define CX24116_DISEQC_MSGLEN (5) -#define CX24116_DISEQC_MSGOFS (6) - -/* DiSEqC burst */ -#define CX24116_DISEQC_MINI_A (0) -#define CX24116_DISEQC_MINI_B (1) - -/* DiSEqC tone burst */ -static int toneburst = 1; -module_param(toneburst, int, 0644); -MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\ - "2=MESSAGE CACHE (default:1)"); - -/* SNR measurements */ -static int esno_snr; -module_param(esno_snr, int, 0644); -MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, "\ - "1=ESNO(db * 10) (default:0)"); - -enum cmds { - CMD_SET_VCO = 0x10, - CMD_TUNEREQUEST = 0x11, - CMD_MPEGCONFIG = 0x13, - CMD_TUNERINIT = 0x14, - CMD_BANDWIDTH = 0x15, - CMD_GETAGC = 0x19, - CMD_LNBCONFIG = 0x20, - CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */ - CMD_LNBDCLEVEL = 0x22, - CMD_SET_TONE = 0x23, - CMD_UPDFWVERS = 0x35, - CMD_TUNERSLEEP = 0x36, - CMD_AGCCONTROL = 0x3b, /* Unknown */ -}; - -/* The Demod/Tuner can't easily provide these, we cache them */ -struct cx24116_tuning { - u32 frequency; - u32 symbol_rate; - fe_spectral_inversion_t inversion; - fe_code_rate_t fec; - - fe_delivery_system_t delsys; - fe_modulation_t modulation; - fe_pilot_t pilot; - fe_rolloff_t rolloff; - - /* Demod values */ - u8 fec_val; - u8 fec_mask; - u8 inversion_val; - u8 pilot_val; - u8 rolloff_val; -}; - -/* Basic commands that are sent to the firmware */ -struct cx24116_cmd { - u8 len; - u8 args[CX24116_ARGLEN]; -}; - -struct cx24116_state { - struct i2c_adapter *i2c; - const struct cx24116_config *config; - - struct dvb_frontend frontend; - - struct cx24116_tuning dcur; - struct cx24116_tuning dnxt; - - u8 skip_fw_load; - u8 burst; - struct cx24116_cmd dsec_cmd; -}; - -static int cx24116_writereg(struct cx24116_state *state, int reg, int data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = 0, .buf = buf, .len = 2 }; - int err; - - if (debug > 1) - printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n", - __func__, reg, data); - - err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) { - printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," - " value == 0x%02x)\n", __func__, err, reg, data); - return -EREMOTEIO; - } - - return 0; -} - -/* Bulk byte writes to a single I2C address, for 32k firmware load */ -static int cx24116_writeregN(struct cx24116_state *state, int reg, - const u8 *data, u16 len) -{ - int ret = -EREMOTEIO; - struct i2c_msg msg; - u8 *buf; - - buf = kmalloc(len + 1, GFP_KERNEL); - if (buf == NULL) { - printk("Unable to kmalloc\n"); - ret = -ENOMEM; - goto error; - } - - *(buf) = reg; - memcpy(buf + 1, data, len); - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.buf = buf; - msg.len = len + 1; - - if (debug > 1) - printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n", - __func__, reg, len); - - ret = i2c_transfer(state->i2c, &msg, 1); - if (ret != 1) { - printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n", - __func__, ret, reg); - ret = -EREMOTEIO; - } - -error: - kfree(buf); - - return ret; -} - -static int cx24116_readreg(struct cx24116_state *state, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, - .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, - .buf = b1, .len = 1 } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - printk(KERN_ERR "%s: reg=0x%x (error=%d)\n", - __func__, reg, ret); - return ret; - } - - if (debug > 1) - printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n", - reg, b1[0]); - - return b1[0]; -} - -static int cx24116_set_inversion(struct cx24116_state *state, - fe_spectral_inversion_t inversion) -{ - dprintk("%s(%d)\n", __func__, inversion); - - switch (inversion) { - case INVERSION_OFF: - state->dnxt.inversion_val = 0x00; - break; - case INVERSION_ON: - state->dnxt.inversion_val = 0x04; - break; - case INVERSION_AUTO: - state->dnxt.inversion_val = 0x0C; - break; - default: - return -EINVAL; - } - - state->dnxt.inversion = inversion; - - return 0; -} - -/* - * modfec (modulation and FEC) - * =========================== - * - * MOD FEC mask/val standard - * ---- -------- ----------- -------- - * QPSK FEC_1_2 0x02 0x02+X DVB-S - * QPSK FEC_2_3 0x04 0x02+X DVB-S - * QPSK FEC_3_4 0x08 0x02+X DVB-S - * QPSK FEC_4_5 0x10 0x02+X DVB-S (?) - * QPSK FEC_5_6 0x20 0x02+X DVB-S - * QPSK FEC_6_7 0x40 0x02+X DVB-S - * QPSK FEC_7_8 0x80 0x02+X DVB-S - * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?) - * QPSK AUTO 0xff 0x02+X DVB-S - * - * For DVB-S high byte probably represents FEC - * and low byte selects the modulator. The high - * byte is search range mask. Bit 5 may turn - * on DVB-S and remaining bits represent some - * kind of calibration (how/what i do not know). - * - * Eg.(2/3) szap "Zone Horror" - * - * mask/val = 0x04, 0x20 - * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK - * - * mask/val = 0x04, 0x30 - * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK - * - * After tuning FECSTATUS contains actual FEC - * in use numbered 1 through to 8 for 1/2 .. 2/3 etc - * - * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only) - * - * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2 - * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2 - * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2 - * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2 - * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2 - * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2 - * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2 - * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2 - * - * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2 - * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2 - * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2 - * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2 - * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2 - * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2 - * - * For DVB-S2 low bytes selects both modulator - * and FEC. High byte is meaningless here. To - * set pilot, bit 6 (0x40) is set. When inspecting - * FECSTATUS bit 7 (0x80) represents the pilot - * selection whilst not tuned. When tuned, actual FEC - * in use is found in FECSTATUS as per above. Pilot - * value is reset. - */ - -/* A table of modulation, fec and configuration bytes for the demod. - * Not all S2 mmodulation schemes are support and not all rates with - * a scheme are support. Especially, no auto detect when in S2 mode. - */ -static struct cx24116_modfec { - fe_delivery_system_t delivery_system; - fe_modulation_t modulation; - fe_code_rate_t fec; - u8 mask; /* In DVBS mode this is used to autodetect */ - u8 val; /* Passed to the firmware to indicate mode selection */ -} CX24116_MODFEC_MODES[] = { - /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ - - /*mod fec mask val */ - { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 }, - { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ - { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ - { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ - { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ - { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ - { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ - { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ - { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ - { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 }, - /* NBC-QPSK */ - { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 }, - { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 }, - { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 }, - { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 }, - { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 }, - { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 }, - { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a }, - { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b }, - /* 8PSK */ - { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c }, - { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d }, - { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e }, - { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f }, - { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 }, - { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 }, - /* - * `val' can be found in the FECSTATUS register when tuning. - * FECSTATUS will give the actual FEC in use if tuning was successful. - */ -}; - -static int cx24116_lookup_fecmod(struct cx24116_state *state, - fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f) -{ - int i, ret = -EOPNOTSUPP; - - dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f); - - for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) { - if ((d == CX24116_MODFEC_MODES[i].delivery_system) && - (m == CX24116_MODFEC_MODES[i].modulation) && - (f == CX24116_MODFEC_MODES[i].fec)) { - ret = i; - break; - } - } - - return ret; -} - -static int cx24116_set_fec(struct cx24116_state *state, - fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec) -{ - int ret = 0; - - dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec); - - ret = cx24116_lookup_fecmod(state, delsys, mod, fec); - - if (ret < 0) - return ret; - - state->dnxt.fec = fec; - state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val; - state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask; - dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__, - state->dnxt.fec_mask, state->dnxt.fec_val); - - return 0; -} - -static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate) -{ - dprintk("%s(%d)\n", __func__, rate); - - /* check if symbol rate is within limits */ - if ((rate > state->frontend.ops.info.symbol_rate_max) || - (rate < state->frontend.ops.info.symbol_rate_min)) { - dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate); - return -EOPNOTSUPP; - } - - state->dnxt.symbol_rate = rate; - dprintk("%s() symbol_rate = %d\n", __func__, rate); - - return 0; -} - -static int cx24116_load_firmware(struct dvb_frontend *fe, - const struct firmware *fw); - -static int cx24116_firmware_ondemand(struct dvb_frontend *fe) -{ - struct cx24116_state *state = fe->demodulator_priv; - const struct firmware *fw; - int ret = 0; - - dprintk("%s()\n", __func__); - - if (cx24116_readreg(state, 0x20) > 0) { - - if (state->skip_fw_load) - return 0; - - /* Load firmware */ - /* request the firmware, this will block until loaded */ - printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", - __func__, CX24116_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, - state->i2c->dev.parent); - printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", - __func__); - if (ret) { - printk(KERN_ERR "%s: No firmware uploaded " - "(timeout or file not found?)\n", __func__); - return ret; - } - - /* Make sure we don't recurse back through here - * during loading */ - state->skip_fw_load = 1; - - ret = cx24116_load_firmware(fe, fw); - if (ret) - printk(KERN_ERR "%s: Writing firmware to device failed\n", - __func__); - - release_firmware(fw); - - printk(KERN_INFO "%s: Firmware upload %s\n", __func__, - ret == 0 ? "complete" : "failed"); - - /* Ensure firmware is always loaded if required */ - state->skip_fw_load = 0; - } - - return ret; -} - -/* Take a basic firmware command structure, format it - * and forward it for processing - */ -static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd) -{ - struct cx24116_state *state = fe->demodulator_priv; - int i, ret; - - dprintk("%s()\n", __func__); - - /* Load the firmware if required */ - ret = cx24116_firmware_ondemand(fe); - if (ret != 0) { - printk(KERN_ERR "%s(): Unable initialise the firmware\n", - __func__); - return ret; - } - - /* Write the command */ - for (i = 0; i < cmd->len ; i++) { - dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]); - cx24116_writereg(state, i, cmd->args[i]); - } - - /* Start execution and wait for cmd to terminate */ - cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01); - while (cx24116_readreg(state, CX24116_REG_EXECUTE)) { - msleep(10); - if (i++ > 64) { - /* Avoid looping forever if the firmware does - not respond */ - printk(KERN_WARNING "%s() Firmware not responding\n", - __func__); - return -EREMOTEIO; - } - } - return 0; -} - -static int cx24116_load_firmware(struct dvb_frontend *fe, - const struct firmware *fw) -{ - struct cx24116_state *state = fe->demodulator_priv; - struct cx24116_cmd cmd; - int i, ret; - unsigned char vers[4]; - - dprintk("%s\n", __func__); - dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n", - fw->size, - fw->data[0], - fw->data[1], - fw->data[fw->size-2], - fw->data[fw->size-1]); - - /* Toggle 88x SRST pin to reset demod */ - if (state->config->reset_device) - state->config->reset_device(fe); - - /* Begin the firmware load process */ - /* Prepare the demod, load the firmware, cleanup after load */ - - /* Init PLL */ - cx24116_writereg(state, 0xE5, 0x00); - cx24116_writereg(state, 0xF1, 0x08); - cx24116_writereg(state, 0xF2, 0x13); - - /* Start PLL */ - cx24116_writereg(state, 0xe0, 0x03); - cx24116_writereg(state, 0xe0, 0x00); - - /* Unknown */ - cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); - cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); - - /* Unknown */ - cx24116_writereg(state, 0xF0, 0x03); - cx24116_writereg(state, 0xF4, 0x81); - cx24116_writereg(state, 0xF5, 0x00); - cx24116_writereg(state, 0xF6, 0x00); - - /* write the entire firmware as one transaction */ - cx24116_writeregN(state, 0xF7, fw->data, fw->size); - - cx24116_writereg(state, 0xF4, 0x10); - cx24116_writereg(state, 0xF0, 0x00); - cx24116_writereg(state, 0xF8, 0x06); - - /* Firmware CMD 10: VCO config */ - cmd.args[0x00] = CMD_SET_VCO; - cmd.args[0x01] = 0x05; - cmd.args[0x02] = 0xdc; - cmd.args[0x03] = 0xda; - cmd.args[0x04] = 0xae; - cmd.args[0x05] = 0xaa; - cmd.args[0x06] = 0x04; - cmd.args[0x07] = 0x9d; - cmd.args[0x08] = 0xfc; - cmd.args[0x09] = 0x06; - cmd.len = 0x0a; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00); - - /* Firmware CMD 14: Tuner config */ - cmd.args[0x00] = CMD_TUNERINIT; - cmd.args[0x01] = 0x00; - cmd.args[0x02] = 0x00; - cmd.len = 0x03; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - cx24116_writereg(state, 0xe5, 0x00); - - /* Firmware CMD 13: MPEG config */ - cmd.args[0x00] = CMD_MPEGCONFIG; - cmd.args[0x01] = 0x01; - cmd.args[0x02] = 0x75; - cmd.args[0x03] = 0x00; - if (state->config->mpg_clk_pos_pol) - cmd.args[0x04] = state->config->mpg_clk_pos_pol; - else - cmd.args[0x04] = 0x02; - cmd.args[0x05] = 0x00; - cmd.len = 0x06; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - /* Firmware CMD 35: Get firmware version */ - cmd.args[0x00] = CMD_UPDFWVERS; - cmd.len = 0x02; - for (i = 0; i < 4; i++) { - cmd.args[0x01] = i; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX); - } - printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__, - vers[0], vers[1], vers[2], vers[3]); - - return 0; -} - -static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct cx24116_state *state = fe->demodulator_priv; - - int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) & - CX24116_STATUS_MASK; - - dprintk("%s: status = 0x%02x\n", __func__, lock); - - *status = 0; - - if (lock & CX24116_HAS_SIGNAL) - *status |= FE_HAS_SIGNAL; - if (lock & CX24116_HAS_CARRIER) - *status |= FE_HAS_CARRIER; - if (lock & CX24116_HAS_VITERBI) - *status |= FE_HAS_VITERBI; - if (lock & CX24116_HAS_SYNCLOCK) - *status |= FE_HAS_SYNC | FE_HAS_LOCK; - - return 0; -} - -static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct cx24116_state *state = fe->demodulator_priv; - - dprintk("%s()\n", __func__); - - *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) | - (cx24116_readreg(state, CX24116_REG_BER16) << 16) | - (cx24116_readreg(state, CX24116_REG_BER8) << 8) | - cx24116_readreg(state, CX24116_REG_BER0); - - return 0; -} - -/* TODO Determine function and scale appropriately */ -static int cx24116_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - struct cx24116_state *state = fe->demodulator_priv; - struct cx24116_cmd cmd; - int ret; - u16 sig_reading; - - dprintk("%s()\n", __func__); - - /* Firmware CMD 19: Get AGC */ - cmd.args[0x00] = CMD_GETAGC; - cmd.len = 0x01; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - sig_reading = - (cx24116_readreg(state, - CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) | - (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6); - *signal_strength = 0 - sig_reading; - - dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", - __func__, sig_reading, *signal_strength); - - return 0; -} - -/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ -static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr) -{ - struct cx24116_state *state = fe->demodulator_priv; - u8 snr_reading; - static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ - 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667, - 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667, - 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667, - 0x18000 }; - - dprintk("%s()\n", __func__); - - snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); - - if (snr_reading >= 0xa0 /* 100% */) - *snr = 0xffff; - else - *snr = snr_tab[(snr_reading & 0xf0) >> 4] + - (snr_tab[(snr_reading & 0x0f)] >> 4); - - dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, - snr_reading, *snr); - - return 0; -} - -/* The reelbox patches show the value in the registers represents - * ESNO, from 0->30db (values 0->300). We provide this value by - * default. - */ -static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr) -{ - struct cx24116_state *state = fe->demodulator_priv; - - dprintk("%s()\n", __func__); - - *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 | - cx24116_readreg(state, CX24116_REG_QUALITY0); - - dprintk("%s: raw 0x%04x\n", __func__, *snr); - - return 0; -} - -static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - if (esno_snr == 1) - return cx24116_read_snr_esno(fe, snr); - else - return cx24116_read_snr_pct(fe, snr); -} - -static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct cx24116_state *state = fe->demodulator_priv; - - dprintk("%s()\n", __func__); - - *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) | - cx24116_readreg(state, CX24116_REG_UCB0); - - return 0; -} - -/* Overwrite the current tuning params, we are about to tune */ -static void cx24116_clone_params(struct dvb_frontend *fe) -{ - struct cx24116_state *state = fe->demodulator_priv; - memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur)); -} - -/* Wait for LNB */ -static int cx24116_wait_for_lnb(struct dvb_frontend *fe) -{ - struct cx24116_state *state = fe->demodulator_priv; - int i; - - dprintk("%s() qstatus = 0x%02x\n", __func__, - cx24116_readreg(state, CX24116_REG_QSTATUS)); - - /* Wait for up to 300 ms */ - for (i = 0; i < 30 ; i++) { - if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20) - return 0; - msleep(10); - } - - dprintk("%s(): LNB not ready\n", __func__); - - return -ETIMEDOUT; /* -EBUSY ? */ -} - -static int cx24116_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct cx24116_cmd cmd; - int ret; - - dprintk("%s: %s\n", __func__, - voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : - voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); - - /* Wait for LNB ready */ - ret = cx24116_wait_for_lnb(fe); - if (ret != 0) - return ret; - - /* Wait for voltage/min repeat delay */ - msleep(100); - - cmd.args[0x00] = CMD_LNBDCLEVEL; - cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00); - cmd.len = 0x02; - - /* Min delay time before DiSEqC send */ - msleep(15); - - return cx24116_cmd_execute(fe, &cmd); -} - -static int cx24116_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t tone) -{ - struct cx24116_cmd cmd; - int ret; - - dprintk("%s(%d)\n", __func__, tone); - if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { - printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone); - return -EINVAL; - } - - /* Wait for LNB ready */ - ret = cx24116_wait_for_lnb(fe); - if (ret != 0) - return ret; - - /* Min delay time after DiSEqC send */ - msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ - - /* Now we set the tone */ - cmd.args[0x00] = CMD_SET_TONE; - cmd.args[0x01] = 0x00; - cmd.args[0x02] = 0x00; - - switch (tone) { - case SEC_TONE_ON: - dprintk("%s: setting tone on\n", __func__); - cmd.args[0x03] = 0x01; - break; - case SEC_TONE_OFF: - dprintk("%s: setting tone off\n", __func__); - cmd.args[0x03] = 0x00; - break; - } - cmd.len = 0x04; - - /* Min delay time before DiSEqC send */ - msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ - - return cx24116_cmd_execute(fe, &cmd); -} - -/* Initialise DiSEqC */ -static int cx24116_diseqc_init(struct dvb_frontend *fe) -{ - struct cx24116_state *state = fe->demodulator_priv; - struct cx24116_cmd cmd; - int ret; - - /* Firmware CMD 20: LNB/DiSEqC config */ - cmd.args[0x00] = CMD_LNBCONFIG; - cmd.args[0x01] = 0x00; - cmd.args[0x02] = 0x10; - cmd.args[0x03] = 0x00; - cmd.args[0x04] = 0x8f; - cmd.args[0x05] = 0x28; - cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01; - cmd.args[0x07] = 0x01; - cmd.len = 0x08; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - /* Prepare a DiSEqC command */ - state->dsec_cmd.args[0x00] = CMD_LNBSEND; - - /* DiSEqC burst */ - state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; - - /* Unknown */ - state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; - state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; - /* Continuation flag? */ - state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; - - /* DiSEqC message length */ - state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; - - /* Command length */ - state->dsec_cmd.len = CX24116_DISEQC_MSGOFS; - - return 0; -} - -/* Send DiSEqC message with derived burst (hack) || previous burst */ -static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *d) -{ - struct cx24116_state *state = fe->demodulator_priv; - int i, ret; - - /* Dump DiSEqC message */ - if (debug) { - printk(KERN_INFO "cx24116: %s(", __func__); - for (i = 0 ; i < d->msg_len ;) { - printk(KERN_INFO "0x%02x", d->msg[i]); - if (++i < d->msg_len) - printk(KERN_INFO ", "); - } - printk(") toneburst=%d\n", toneburst); - } - - /* Validate length */ - if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) - return -EINVAL; - - /* DiSEqC message */ - for (i = 0; i < d->msg_len; i++) - state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; - - /* DiSEqC message length */ - state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; - - /* Command length */ - state->dsec_cmd.len = CX24116_DISEQC_MSGOFS + - state->dsec_cmd.args[CX24116_DISEQC_MSGLEN]; - - /* DiSEqC toneburst */ - if (toneburst == CX24116_DISEQC_MESGCACHE) - /* Message is cached */ - return 0; - - else if (toneburst == CX24116_DISEQC_TONEOFF) - /* Message is sent without burst */ - state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0; - - else if (toneburst == CX24116_DISEQC_TONECACHE) { - /* - * Message is sent with derived else cached burst - * - * WRITE PORT GROUP COMMAND 38 - * - * 0/A/A: E0 10 38 F0..F3 - * 1/B/B: E0 10 38 F4..F7 - * 2/C/A: E0 10 38 F8..FB - * 3/D/B: E0 10 38 FC..FF - * - * databyte[3]= 8421:8421 - * ABCD:WXYZ - * CLR :SET - * - * WX= PORT SELECT 0..3 (X=TONEBURST) - * Y = VOLTAGE (0=13V, 1=18V) - * Z = BAND (0=LOW, 1=HIGH(22K)) - */ - if (d->msg_len >= 4 && d->msg[2] == 0x38) - state->dsec_cmd.args[CX24116_DISEQC_BURST] = - ((d->msg[3] & 4) >> 2); - if (debug) - dprintk("%s burst=%d\n", __func__, - state->dsec_cmd.args[CX24116_DISEQC_BURST]); - } - - /* Wait for LNB ready */ - ret = cx24116_wait_for_lnb(fe); - if (ret != 0) - return ret; - - /* Wait for voltage/min repeat delay */ - msleep(100); - - /* Command */ - ret = cx24116_cmd_execute(fe, &state->dsec_cmd); - if (ret != 0) - return ret; - /* - * Wait for send - * - * Eutelsat spec: - * >15ms delay + (XXX determine if FW does this, see set_tone) - * 13.5ms per byte + - * >15ms delay + - * 12.5ms burst + - * >15ms delay (XXX determine if FW does this, see set_tone) - */ - msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + - ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60)); - - return 0; -} - -/* Send DiSEqC burst */ -static int cx24116_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) -{ - struct cx24116_state *state = fe->demodulator_priv; - int ret; - - dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst); - - /* DiSEqC burst */ - if (burst == SEC_MINI_A) - state->dsec_cmd.args[CX24116_DISEQC_BURST] = - CX24116_DISEQC_MINI_A; - else if (burst == SEC_MINI_B) - state->dsec_cmd.args[CX24116_DISEQC_BURST] = - CX24116_DISEQC_MINI_B; - else - return -EINVAL; - - /* DiSEqC toneburst */ - if (toneburst != CX24116_DISEQC_MESGCACHE) - /* Burst is cached */ - return 0; - - /* Burst is to be sent with cached message */ - - /* Wait for LNB ready */ - ret = cx24116_wait_for_lnb(fe); - if (ret != 0) - return ret; - - /* Wait for voltage/min repeat delay */ - msleep(100); - - /* Command */ - ret = cx24116_cmd_execute(fe, &state->dsec_cmd); - if (ret != 0) - return ret; - - /* - * Wait for send - * - * Eutelsat spec: - * >15ms delay + (XXX determine if FW does this, see set_tone) - * 13.5ms per byte + - * >15ms delay + - * 12.5ms burst + - * >15ms delay (XXX determine if FW does this, see set_tone) - */ - msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60); - - return 0; -} - -static void cx24116_release(struct dvb_frontend *fe) -{ - struct cx24116_state *state = fe->demodulator_priv; - dprintk("%s\n", __func__); - kfree(state); -} - -static struct dvb_frontend_ops cx24116_ops; - -struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, - struct i2c_adapter *i2c) -{ - struct cx24116_state *state = NULL; - int ret; - - dprintk("%s\n", __func__); - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL); - if (state == NULL) - goto error1; - - state->config = config; - state->i2c = i2c; - - /* check if the demod is present */ - ret = (cx24116_readreg(state, 0xFF) << 8) | - cx24116_readreg(state, 0xFE); - if (ret != 0x0501) { - printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n"); - goto error2; - } - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &cx24116_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error2: kfree(state); -error1: return NULL; -} -EXPORT_SYMBOL(cx24116_attach); - -/* - * Initialise or wake up device - * - * Power config will reset and load initial firmware if required - */ -static int cx24116_initfe(struct dvb_frontend *fe) -{ - struct cx24116_state *state = fe->demodulator_priv; - struct cx24116_cmd cmd; - int ret; - - dprintk("%s()\n", __func__); - - /* Power on */ - cx24116_writereg(state, 0xe0, 0); - cx24116_writereg(state, 0xe1, 0); - cx24116_writereg(state, 0xea, 0); - - /* Firmware CMD 36: Power config */ - cmd.args[0x00] = CMD_TUNERSLEEP; - cmd.args[0x01] = 0; - cmd.len = 0x02; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - ret = cx24116_diseqc_init(fe); - if (ret != 0) - return ret; - - /* HVR-4000 needs this */ - return cx24116_set_voltage(fe, SEC_VOLTAGE_13); -} - -/* - * Put device to sleep - */ -static int cx24116_sleep(struct dvb_frontend *fe) -{ - struct cx24116_state *state = fe->demodulator_priv; - struct cx24116_cmd cmd; - int ret; - - dprintk("%s()\n", __func__); - - /* Firmware CMD 36: Power config */ - cmd.args[0x00] = CMD_TUNERSLEEP; - cmd.args[0x01] = 1; - cmd.len = 0x02; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - /* Power off (Shutdown clocks) */ - cx24116_writereg(state, 0xea, 0xff); - cx24116_writereg(state, 0xe1, 1); - cx24116_writereg(state, 0xe0, 1); - - return 0; -} - -static int cx24116_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int cx24116_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -/* dvb-core told us to tune, the tv property cache will be complete, - * it's safe for is to pull values and use them for tuning purposes. - */ -static int cx24116_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct cx24116_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct cx24116_cmd cmd; - fe_status_t tunerstat; - int i, status, ret, retune = 1; - - dprintk("%s()\n", __func__); - - switch (c->delivery_system) { - case SYS_DVBS: - dprintk("%s: DVB-S delivery system selected\n", __func__); - - /* Only QPSK is supported for DVB-S */ - if (c->modulation != QPSK) { - dprintk("%s: unsupported modulation selected (%d)\n", - __func__, c->modulation); - return -EOPNOTSUPP; - } - - /* Pilot doesn't exist in DVB-S, turn bit off */ - state->dnxt.pilot_val = CX24116_PILOT_OFF; - - /* DVB-S only supports 0.35 */ - if (c->rolloff != ROLLOFF_35) { - dprintk("%s: unsupported rolloff selected (%d)\n", - __func__, c->rolloff); - return -EOPNOTSUPP; - } - state->dnxt.rolloff_val = CX24116_ROLLOFF_035; - break; - - case SYS_DVBS2: - dprintk("%s: DVB-S2 delivery system selected\n", __func__); - - /* - * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, - * but not hardware auto detection - */ - if (c->modulation != PSK_8 && c->modulation != QPSK) { - dprintk("%s: unsupported modulation selected (%d)\n", - __func__, c->modulation); - return -EOPNOTSUPP; - } - - switch (c->pilot) { - case PILOT_AUTO: /* Not supported but emulated */ - state->dnxt.pilot_val = (c->modulation == QPSK) - ? CX24116_PILOT_OFF : CX24116_PILOT_ON; - retune++; - break; - case PILOT_OFF: - state->dnxt.pilot_val = CX24116_PILOT_OFF; - break; - case PILOT_ON: - state->dnxt.pilot_val = CX24116_PILOT_ON; - break; - default: - dprintk("%s: unsupported pilot mode selected (%d)\n", - __func__, c->pilot); - return -EOPNOTSUPP; - } - - switch (c->rolloff) { - case ROLLOFF_20: - state->dnxt.rolloff_val = CX24116_ROLLOFF_020; - break; - case ROLLOFF_25: - state->dnxt.rolloff_val = CX24116_ROLLOFF_025; - break; - case ROLLOFF_35: - state->dnxt.rolloff_val = CX24116_ROLLOFF_035; - break; - case ROLLOFF_AUTO: /* Rolloff must be explicit */ - default: - dprintk("%s: unsupported rolloff selected (%d)\n", - __func__, c->rolloff); - return -EOPNOTSUPP; - } - break; - - default: - dprintk("%s: unsupported delivery system selected (%d)\n", - __func__, c->delivery_system); - return -EOPNOTSUPP; - } - state->dnxt.delsys = c->delivery_system; - state->dnxt.modulation = c->modulation; - state->dnxt.frequency = c->frequency; - state->dnxt.pilot = c->pilot; - state->dnxt.rolloff = c->rolloff; - - ret = cx24116_set_inversion(state, c->inversion); - if (ret != 0) - return ret; - - /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ - ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner); - if (ret != 0) - return ret; - - ret = cx24116_set_symbolrate(state, c->symbol_rate); - if (ret != 0) - return ret; - - /* discard the 'current' tuning parameters and prepare to tune */ - cx24116_clone_params(fe); - - dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys); - dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation); - dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); - dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__, - state->dcur.pilot, state->dcur.pilot_val); - dprintk("%s: retune = %d\n", __func__, retune); - dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__, - state->dcur.rolloff, state->dcur.rolloff_val); - dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); - dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, - state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); - dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__, - state->dcur.inversion, state->dcur.inversion_val); - - /* This is also done in advise/acquire on HVR4000 but not on LITE */ - if (state->config->set_ts_params) - state->config->set_ts_params(fe, 0); - - /* Set/Reset B/W */ - cmd.args[0x00] = CMD_BANDWIDTH; - cmd.args[0x01] = 0x01; - cmd.len = 0x02; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - /* Prepare a tune request */ - cmd.args[0x00] = CMD_TUNEREQUEST; - - /* Frequency */ - cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16; - cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8; - cmd.args[0x03] = (state->dcur.frequency & 0x0000ff); - - /* Symbol Rate */ - cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8; - cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff); - - /* Automatic Inversion */ - cmd.args[0x06] = state->dcur.inversion_val; - - /* Modulation / FEC / Pilot */ - cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val; - - cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; - cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; - cmd.args[0x0a] = 0x00; - cmd.args[0x0b] = 0x00; - cmd.args[0x0c] = state->dcur.rolloff_val; - cmd.args[0x0d] = state->dcur.fec_mask; - - if (state->dcur.symbol_rate > 30000000) { - cmd.args[0x0e] = 0x04; - cmd.args[0x0f] = 0x00; - cmd.args[0x10] = 0x01; - cmd.args[0x11] = 0x77; - cmd.args[0x12] = 0x36; - cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44); - cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01); - } else { - cmd.args[0x0e] = 0x06; - cmd.args[0x0f] = 0x00; - cmd.args[0x10] = 0x00; - cmd.args[0x11] = 0xFA; - cmd.args[0x12] = 0x24; - cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); - cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); - } - - cmd.len = 0x13; - - /* We need to support pilot and non-pilot tuning in the - * driver automatically. This is a workaround for because - * the demod does not support autodetect. - */ - do { - /* Reset status register */ - status = cx24116_readreg(state, CX24116_REG_SSTATUS) - & CX24116_SIGNAL_MASK; - cx24116_writereg(state, CX24116_REG_SSTATUS, status); - - /* Tune */ - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - break; - - /* - * Wait for up to 500 ms before retrying - * - * If we are able to tune then generally it occurs within 100ms. - * If it takes longer, try a different toneburst setting. - */ - for (i = 0; i < 50 ; i++) { - cx24116_read_status(fe, &tunerstat); - status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC); - if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) { - dprintk("%s: Tuned\n", __func__); - goto tuned; - } - msleep(10); - } - - dprintk("%s: Not tuned\n", __func__); - - /* Toggle pilot bit when in auto-pilot */ - if (state->dcur.pilot == PILOT_AUTO) - cmd.args[0x07] ^= CX24116_PILOT_ON; - } while (--retune); - -tuned: /* Set/Reset B/W */ - cmd.args[0x00] = CMD_BANDWIDTH; - cmd.args[0x01] = 0x00; - cmd.len = 0x02; - ret = cx24116_cmd_execute(fe, &cmd); - if (ret != 0) - return ret; - - return ret; -} - -static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, - unsigned int mode_flags, unsigned int *delay, fe_status_t *status) -{ - *delay = HZ / 5; - if (params) { - int ret = cx24116_set_frontend(fe, params); - if (ret) - return ret; - } - return cx24116_read_status(fe, status); -} - -static int cx24116_get_algo(struct dvb_frontend *fe) -{ - return DVBFE_ALGO_HW; -} - -static struct dvb_frontend_ops cx24116_ops = { - - .info = { - .name = "Conexant CX24116/CX24118", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1011, /* kHz for QPSK frontends */ - .frequency_tolerance = 5000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_2G_MODULATION | - FE_CAN_QPSK | FE_CAN_RECOVER - }, - - .release = cx24116_release, - - .init = cx24116_initfe, - .sleep = cx24116_sleep, - .read_status = cx24116_read_status, - .read_ber = cx24116_read_ber, - .read_signal_strength = cx24116_read_signal_strength, - .read_snr = cx24116_read_snr, - .read_ucblocks = cx24116_read_ucblocks, - .set_tone = cx24116_set_tone, - .set_voltage = cx24116_set_voltage, - .diseqc_send_master_cmd = cx24116_send_diseqc_msg, - .diseqc_send_burst = cx24116_diseqc_send_burst, - .get_frontend_algo = cx24116_get_algo, - .tune = cx24116_tune, - - .set_property = cx24116_set_property, - .get_property = cx24116_get_property, - .set_frontend = cx24116_set_frontend, -}; - -MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); -MODULE_AUTHOR("Steven Toth"); -MODULE_LICENSE("GPL"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24116.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24116.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24116.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24116.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/* - Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver - - Copyright (C) 2006 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef CX24116_H -#define CX24116_H - -#include - -struct cx24116_config { - /* the demodulator's i2c address */ - u8 demod_address; - - /* Need to set device param for start_dma */ - int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); - - /* Need to reset device during firmware loading */ - int (*reset_device)(struct dvb_frontend *fe); - - /* Need to set MPEG parameters */ - u8 mpg_clk_pos_pol:0x02; -}; - -#if defined(CONFIG_DVB_CX24116) || \ - (defined(CONFIG_DVB_CX24116_MODULE) && defined(MODULE)) -extern struct dvb_frontend *cx24116_attach( - const struct cx24116_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *cx24116_attach( - const struct cx24116_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* CX24116_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24123.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24123.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24123.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24123.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1167 +0,0 @@ -/* - * Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver - * - * Copyright (C) 2005 Steven Toth - * - * Support for KWorld DVB-S 100 by Vadim Catana - * - * Support for CX24123/CX24113-NIM by Patrick Boettcher - * - * 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, or (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "cx24123.h" - -#define XTAL 10111000 - -static int force_band; -module_param(force_band, int, 0644); -MODULE_PARM_DESC(force_band, "Force a specific band select "\ - "(1-9, default:off)."); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); - -#define info(args...) do { printk(KERN_INFO "CX24123: " args); } while (0) -#define err(args...) do { printk(KERN_ERR "CX24123: " args); } while (0) - -#define dprintk(args...) \ - do { \ - if (debug) { \ - printk(KERN_DEBUG "CX24123: %s: ", __func__); \ - printk(args); \ - } \ - } while (0) - -struct cx24123_state { - struct i2c_adapter *i2c; - const struct cx24123_config *config; - - struct dvb_frontend frontend; - - /* Some PLL specifics for tuning */ - u32 VCAarg; - u32 VGAarg; - u32 bandselectarg; - u32 pllarg; - u32 FILTune; - - struct i2c_adapter tuner_i2c_adapter; - - u8 demod_rev; - - /* The Demod/Tuner can't easily provide these, we cache them */ - u32 currentfreq; - u32 currentsymbolrate; -}; - -/* Various tuner defaults need to be established for a given symbol rate Sps */ -static struct cx24123_AGC_val { - u32 symbolrate_low; - u32 symbolrate_high; - u32 VCAprogdata; - u32 VGAprogdata; - u32 FILTune; -} cx24123_AGC_vals[] = -{ - { - .symbolrate_low = 1000000, - .symbolrate_high = 4999999, - /* the specs recommend other values for VGA offsets, - but tests show they are wrong */ - .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0, - .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x07, - .FILTune = 0x27f /* 0.41 V */ - }, - { - .symbolrate_low = 5000000, - .symbolrate_high = 14999999, - .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0, - .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x1f, - .FILTune = 0x317 /* 0.90 V */ - }, - { - .symbolrate_low = 15000000, - .symbolrate_high = 45000000, - .VGAprogdata = (1 << 19) | (0x100 << 9) | 0x180, - .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x3f, - .FILTune = 0x145 /* 2.70 V */ - }, -}; - -/* - * Various tuner defaults need to be established for a given frequency kHz. - * fixme: The bounds on the bands do not match the doc in real life. - * fixme: Some of them have been moved, other might need adjustment. - */ -static struct cx24123_bandselect_val { - u32 freq_low; - u32 freq_high; - u32 VCOdivider; - u32 progdata; -} cx24123_bandselect_vals[] = -{ - /* band 1 */ - { - .freq_low = 950000, - .freq_high = 1074999, - .VCOdivider = 4, - .progdata = (0 << 19) | (0 << 9) | 0x40, - }, - - /* band 2 */ - { - .freq_low = 1075000, - .freq_high = 1177999, - .VCOdivider = 4, - .progdata = (0 << 19) | (0 << 9) | 0x80, - }, - - /* band 3 */ - { - .freq_low = 1178000, - .freq_high = 1295999, - .VCOdivider = 2, - .progdata = (0 << 19) | (1 << 9) | 0x01, - }, - - /* band 4 */ - { - .freq_low = 1296000, - .freq_high = 1431999, - .VCOdivider = 2, - .progdata = (0 << 19) | (1 << 9) | 0x02, - }, - - /* band 5 */ - { - .freq_low = 1432000, - .freq_high = 1575999, - .VCOdivider = 2, - .progdata = (0 << 19) | (1 << 9) | 0x04, - }, - - /* band 6 */ - { - .freq_low = 1576000, - .freq_high = 1717999, - .VCOdivider = 2, - .progdata = (0 << 19) | (1 << 9) | 0x08, - }, - - /* band 7 */ - { - .freq_low = 1718000, - .freq_high = 1855999, - .VCOdivider = 2, - .progdata = (0 << 19) | (1 << 9) | 0x10, - }, - - /* band 8 */ - { - .freq_low = 1856000, - .freq_high = 2035999, - .VCOdivider = 2, - .progdata = (0 << 19) | (1 << 9) | 0x20, - }, - - /* band 9 */ - { - .freq_low = 2036000, - .freq_high = 2150000, - .VCOdivider = 2, - .progdata = (0 << 19) | (1 << 9) | 0x40, - }, -}; - -static struct { - u8 reg; - u8 data; -} cx24123_regdata[] = -{ - {0x00, 0x03}, /* Reset system */ - {0x00, 0x00}, /* Clear reset */ - {0x03, 0x07}, /* QPSK, DVB, Auto Acquisition (default) */ - {0x04, 0x10}, /* MPEG */ - {0x05, 0x04}, /* MPEG */ - {0x06, 0x31}, /* MPEG (default) */ - {0x0b, 0x00}, /* Freq search start point (default) */ - {0x0c, 0x00}, /* Demodulator sample gain (default) */ - {0x0d, 0x7f}, /* Force driver to shift until the maximum (+-10 MHz) */ - {0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */ - {0x0f, 0xfe}, /* FEC search mask (all supported codes) */ - {0x10, 0x01}, /* Default search inversion, no repeat (default) */ - {0x16, 0x00}, /* Enable reading of frequency */ - {0x17, 0x01}, /* Enable EsNO Ready Counter */ - {0x1c, 0x80}, /* Enable error counter */ - {0x20, 0x00}, /* Tuner burst clock rate = 500KHz */ - {0x21, 0x15}, /* Tuner burst mode, word length = 0x15 */ - {0x28, 0x00}, /* Enable FILTERV with positive pol., DiSEqC 2.x off */ - {0x29, 0x00}, /* DiSEqC LNB_DC off */ - {0x2a, 0xb0}, /* DiSEqC Parameters (default) */ - {0x2b, 0x73}, /* DiSEqC Tone Frequency (default) */ - {0x2c, 0x00}, /* DiSEqC Message (0x2c - 0x31) */ - {0x2d, 0x00}, - {0x2e, 0x00}, - {0x2f, 0x00}, - {0x30, 0x00}, - {0x31, 0x00}, - {0x32, 0x8c}, /* DiSEqC Parameters (default) */ - {0x33, 0x00}, /* Interrupts off (0x33 - 0x34) */ - {0x34, 0x00}, - {0x35, 0x03}, /* DiSEqC Tone Amplitude (default) */ - {0x36, 0x02}, /* DiSEqC Parameters (default) */ - {0x37, 0x3a}, /* DiSEqC Parameters (default) */ - {0x3a, 0x00}, /* Enable AGC accumulator (for signal strength) */ - {0x44, 0x00}, /* Constellation (default) */ - {0x45, 0x00}, /* Symbol count (default) */ - {0x46, 0x0d}, /* Symbol rate estimator on (default) */ - {0x56, 0xc1}, /* Error Counter = Viterbi BER */ - {0x57, 0xff}, /* Error Counter Window (default) */ - {0x5c, 0x20}, /* Acquisition AFC Expiration window (default is 0x10) */ - {0x67, 0x83}, /* Non-DCII symbol clock */ -}; - -static int cx24123_i2c_writereg(struct cx24123_state *state, - u8 i2c_addr, int reg, int data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { - .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2 - }; - int err; - - /* printk(KERN_DEBUG "wr(%02x): %02x %02x\n", i2c_addr, reg, data); */ - - err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) { - printk("%s: writereg error(err == %i, reg == 0x%02x," - " data == 0x%02x)\n", __func__, err, reg, data); - return err; - } - - return 0; -} - -static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg) -{ - int ret; - u8 b = 0; - struct i2c_msg msg[] = { - { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 }, - { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &b, .len = 1 } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - err("%s: reg=0x%x (error=%d)\n", __func__, reg, ret); - return ret; - } - - /* printk(KERN_DEBUG "rd(%02x): %02x %02x\n", i2c_addr, reg, b); */ - - return b; -} - -#define cx24123_readreg(state, reg) \ - cx24123_i2c_readreg(state, state->config->demod_address, reg) -#define cx24123_writereg(state, reg, val) \ - cx24123_i2c_writereg(state, state->config->demod_address, reg, val) - -static int cx24123_set_inversion(struct cx24123_state *state, - fe_spectral_inversion_t inversion) -{ - u8 nom_reg = cx24123_readreg(state, 0x0e); - u8 auto_reg = cx24123_readreg(state, 0x10); - - switch (inversion) { - case INVERSION_OFF: - dprintk("inversion off\n"); - cx24123_writereg(state, 0x0e, nom_reg & ~0x80); - cx24123_writereg(state, 0x10, auto_reg | 0x80); - break; - case INVERSION_ON: - dprintk("inversion on\n"); - cx24123_writereg(state, 0x0e, nom_reg | 0x80); - cx24123_writereg(state, 0x10, auto_reg | 0x80); - break; - case INVERSION_AUTO: - dprintk("inversion auto\n"); - cx24123_writereg(state, 0x10, auto_reg & ~0x80); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int cx24123_get_inversion(struct cx24123_state *state, - fe_spectral_inversion_t *inversion) -{ - u8 val; - - val = cx24123_readreg(state, 0x1b) >> 7; - - if (val == 0) { - dprintk("read inversion off\n"); - *inversion = INVERSION_OFF; - } else { - dprintk("read inversion on\n"); - *inversion = INVERSION_ON; - } - - return 0; -} - -static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec) -{ - u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07; - - if ((fec < FEC_NONE) || (fec > FEC_AUTO)) - fec = FEC_AUTO; - - /* Set the soft decision threshold */ - if (fec == FEC_1_2) - cx24123_writereg(state, 0x43, - cx24123_readreg(state, 0x43) | 0x01); - else - cx24123_writereg(state, 0x43, - cx24123_readreg(state, 0x43) & ~0x01); - - switch (fec) { - case FEC_1_2: - dprintk("set FEC to 1/2\n"); - cx24123_writereg(state, 0x0e, nom_reg | 0x01); - cx24123_writereg(state, 0x0f, 0x02); - break; - case FEC_2_3: - dprintk("set FEC to 2/3\n"); - cx24123_writereg(state, 0x0e, nom_reg | 0x02); - cx24123_writereg(state, 0x0f, 0x04); - break; - case FEC_3_4: - dprintk("set FEC to 3/4\n"); - cx24123_writereg(state, 0x0e, nom_reg | 0x03); - cx24123_writereg(state, 0x0f, 0x08); - break; - case FEC_4_5: - dprintk("set FEC to 4/5\n"); - cx24123_writereg(state, 0x0e, nom_reg | 0x04); - cx24123_writereg(state, 0x0f, 0x10); - break; - case FEC_5_6: - dprintk("set FEC to 5/6\n"); - cx24123_writereg(state, 0x0e, nom_reg | 0x05); - cx24123_writereg(state, 0x0f, 0x20); - break; - case FEC_6_7: - dprintk("set FEC to 6/7\n"); - cx24123_writereg(state, 0x0e, nom_reg | 0x06); - cx24123_writereg(state, 0x0f, 0x40); - break; - case FEC_7_8: - dprintk("set FEC to 7/8\n"); - cx24123_writereg(state, 0x0e, nom_reg | 0x07); - cx24123_writereg(state, 0x0f, 0x80); - break; - case FEC_AUTO: - dprintk("set FEC to auto\n"); - cx24123_writereg(state, 0x0f, 0xfe); - break; - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static int cx24123_get_fec(struct cx24123_state *state, fe_code_rate_t *fec) -{ - int ret; - - ret = cx24123_readreg(state, 0x1b); - if (ret < 0) - return ret; - ret = ret & 0x07; - - switch (ret) { - case 1: - *fec = FEC_1_2; - break; - case 2: - *fec = FEC_2_3; - break; - case 3: - *fec = FEC_3_4; - break; - case 4: - *fec = FEC_4_5; - break; - case 5: - *fec = FEC_5_6; - break; - case 6: - *fec = FEC_6_7; - break; - case 7: - *fec = FEC_7_8; - break; - default: - /* this can happen when there's no lock */ - *fec = FEC_NONE; - } - - return 0; -} - -/* Approximation of closest integer of log2(a/b). It actually gives the - lowest integer i such that 2^i >= round(a/b) */ -static u32 cx24123_int_log2(u32 a, u32 b) -{ - u32 exp, nearest = 0; - u32 div = a / b; - if (a % b >= b / 2) - ++div; - if (div < (1 << 31)) { - for (exp = 1; div > exp; nearest++) - exp += exp; - } - return nearest; -} - -static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate) -{ - u32 tmp, sample_rate, ratio, sample_gain; - u8 pll_mult; - - /* check if symbol rate is within limits */ - if ((srate > state->frontend.ops.info.symbol_rate_max) || - (srate < state->frontend.ops.info.symbol_rate_min)) - return -EOPNOTSUPP; - - /* choose the sampling rate high enough for the required operation, - while optimizing the power consumed by the demodulator */ - if (srate < (XTAL*2)/2) - pll_mult = 2; - else if (srate < (XTAL*3)/2) - pll_mult = 3; - else if (srate < (XTAL*4)/2) - pll_mult = 4; - else if (srate < (XTAL*5)/2) - pll_mult = 5; - else if (srate < (XTAL*6)/2) - pll_mult = 6; - else if (srate < (XTAL*7)/2) - pll_mult = 7; - else if (srate < (XTAL*8)/2) - pll_mult = 8; - else - pll_mult = 9; - - - sample_rate = pll_mult * XTAL; - - /* - SYSSymbolRate[21:0] = (srate << 23) / sample_rate - - We have to use 32 bit unsigned arithmetic without precision loss. - The maximum srate is 45000000 or 0x02AEA540. This number has - only 6 clear bits on top, hence we can shift it left only 6 bits - at a time. Borrowed from cx24110.c - */ - - tmp = srate << 6; - ratio = tmp / sample_rate; - - tmp = (tmp % sample_rate) << 6; - ratio = (ratio << 6) + (tmp / sample_rate); - - tmp = (tmp % sample_rate) << 6; - ratio = (ratio << 6) + (tmp / sample_rate); - - tmp = (tmp % sample_rate) << 5; - ratio = (ratio << 5) + (tmp / sample_rate); - - - cx24123_writereg(state, 0x01, pll_mult * 6); - - cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f); - cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff); - cx24123_writereg(state, 0x0a, ratio & 0xff); - - /* also set the demodulator sample gain */ - sample_gain = cx24123_int_log2(sample_rate, srate); - tmp = cx24123_readreg(state, 0x0c) & ~0xe0; - cx24123_writereg(state, 0x0c, tmp | sample_gain << 5); - - dprintk("srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n", - srate, ratio, sample_rate, sample_gain); - - return 0; -} - -/* - * Based on the required frequency and symbolrate, the tuner AGC has - * to be configured and the correct band selected. - * Calculate those values. - */ -static int cx24123_pll_calculate(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct cx24123_state *state = fe->demodulator_priv; - u32 ndiv = 0, adiv = 0, vco_div = 0; - int i = 0; - int pump = 2; - int band = 0; - int num_bands = ARRAY_SIZE(cx24123_bandselect_vals); - struct cx24123_bandselect_val *bsv = NULL; - struct cx24123_AGC_val *agcv = NULL; - - /* Defaults for low freq, low rate */ - state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; - state->VGAarg = cx24123_AGC_vals[0].VGAprogdata; - state->bandselectarg = cx24123_bandselect_vals[0].progdata; - vco_div = cx24123_bandselect_vals[0].VCOdivider; - - /* For the given symbol rate, determine the VCA, VGA and - * FILTUNE programming bits */ - for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) { - agcv = &cx24123_AGC_vals[i]; - if ((agcv->symbolrate_low <= p->u.qpsk.symbol_rate) && - (agcv->symbolrate_high >= p->u.qpsk.symbol_rate)) { - state->VCAarg = agcv->VCAprogdata; - state->VGAarg = agcv->VGAprogdata; - state->FILTune = agcv->FILTune; - } - } - - /* determine the band to use */ - if (force_band < 1 || force_band > num_bands) { - for (i = 0; i < num_bands; i++) { - bsv = &cx24123_bandselect_vals[i]; - if ((bsv->freq_low <= p->frequency) && - (bsv->freq_high >= p->frequency)) - band = i; - } - } else - band = force_band - 1; - - state->bandselectarg = cx24123_bandselect_vals[band].progdata; - vco_div = cx24123_bandselect_vals[band].VCOdivider; - - /* determine the charge pump current */ - if (p->frequency < (cx24123_bandselect_vals[band].freq_low + - cx24123_bandselect_vals[band].freq_high) / 2) - pump = 0x01; - else - pump = 0x02; - - /* Determine the N/A dividers for the requested lband freq (in kHz). */ - /* Note: the reference divider R=10, frequency is in KHz, - * XTAL is in Hz */ - ndiv = (((p->frequency * vco_div * 10) / - (2 * XTAL / 1000)) / 32) & 0x1ff; - adiv = (((p->frequency * vco_div * 10) / - (2 * XTAL / 1000)) % 32) & 0x1f; - - if (adiv == 0 && ndiv > 0) - ndiv--; - - /* control bits 11, refdiv 11, charge pump polarity 1, - * charge pump current, ndiv, adiv */ - state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | - (pump << 14) | (ndiv << 5) | adiv; - - return 0; -} - -/* - * Tuner data is 21 bits long, must be left-aligned in data. - * Tuner cx24109 is written through a dedicated 3wire interface - * on the demod chip. - */ -static int cx24123_pll_writereg(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p, u32 data) -{ - struct cx24123_state *state = fe->demodulator_priv; - unsigned long timeout; - - dprintk("pll writereg called, data=0x%08x\n", data); - - /* align the 21 bytes into to bit23 boundary */ - data = data << 3; - - /* Reset the demod pll word length to 0x15 bits */ - cx24123_writereg(state, 0x21, 0x15); - - /* write the msb 8 bits, wait for the send to be completed */ - timeout = jiffies + msecs_to_jiffies(40); - cx24123_writereg(state, 0x22, (data >> 16) & 0xff); - while ((cx24123_readreg(state, 0x20) & 0x40) == 0) { - if (time_after(jiffies, timeout)) { - err("%s: demodulator is not responding, "\ - "possibly hung, aborting.\n", __func__); - return -EREMOTEIO; - } - msleep(10); - } - - /* send another 8 bytes, wait for the send to be completed */ - timeout = jiffies + msecs_to_jiffies(40); - cx24123_writereg(state, 0x22, (data >> 8) & 0xff); - while ((cx24123_readreg(state, 0x20) & 0x40) == 0) { - if (time_after(jiffies, timeout)) { - err("%s: demodulator is not responding, "\ - "possibly hung, aborting.\n", __func__); - return -EREMOTEIO; - } - msleep(10); - } - - /* send the lower 5 bits of this byte, padded with 3 LBB, - * wait for the send to be completed */ - timeout = jiffies + msecs_to_jiffies(40); - cx24123_writereg(state, 0x22, (data) & 0xff); - while ((cx24123_readreg(state, 0x20) & 0x80)) { - if (time_after(jiffies, timeout)) { - err("%s: demodulator is not responding," \ - "possibly hung, aborting.\n", __func__); - return -EREMOTEIO; - } - msleep(10); - } - - /* Trigger the demod to configure the tuner */ - cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2); - cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd); - - return 0; -} - -static int cx24123_pll_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct cx24123_state *state = fe->demodulator_priv; - u8 val; - - dprintk("frequency=%i\n", p->frequency); - - if (cx24123_pll_calculate(fe, p) != 0) { - err("%s: cx24123_pll_calcutate failed\n", __func__); - return -EINVAL; - } - - /* Write the new VCO/VGA */ - cx24123_pll_writereg(fe, p, state->VCAarg); - cx24123_pll_writereg(fe, p, state->VGAarg); - - /* Write the new bandselect and pll args */ - cx24123_pll_writereg(fe, p, state->bandselectarg); - cx24123_pll_writereg(fe, p, state->pllarg); - - /* set the FILTUNE voltage */ - val = cx24123_readreg(state, 0x28) & ~0x3; - cx24123_writereg(state, 0x27, state->FILTune >> 2); - cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3)); - - dprintk("pll tune VCA=%d, band=%d, pll=%d\n", state->VCAarg, - state->bandselectarg, state->pllarg); - - return 0; -} - - -/* - * 0x23: - * [7:7] = BTI enabled - * [6:6] = I2C repeater enabled - * [5:5] = I2C repeater start - * [0:0] = BTI start - */ - -/* mode == 1 -> i2c-repeater, 0 -> bti */ -static int cx24123_repeater_mode(struct cx24123_state *state, u8 mode, u8 start) -{ - u8 r = cx24123_readreg(state, 0x23) & 0x1e; - if (mode) - r |= (1 << 6) | (start << 5); - else - r |= (1 << 7) | (start); - return cx24123_writereg(state, 0x23, r); -} - -static int cx24123_initfe(struct dvb_frontend *fe) -{ - struct cx24123_state *state = fe->demodulator_priv; - int i; - - dprintk("init frontend\n"); - - /* Configure the demod to a good set of defaults */ - for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++) - cx24123_writereg(state, cx24123_regdata[i].reg, - cx24123_regdata[i].data); - - /* Set the LNB polarity */ - if (state->config->lnb_polarity) - cx24123_writereg(state, 0x32, - cx24123_readreg(state, 0x32) | 0x02); - - if (state->config->dont_use_pll) - cx24123_repeater_mode(state, 1, 0); - - return 0; -} - -static int cx24123_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct cx24123_state *state = fe->demodulator_priv; - u8 val; - - val = cx24123_readreg(state, 0x29) & ~0x40; - - switch (voltage) { - case SEC_VOLTAGE_13: - dprintk("setting voltage 13V\n"); - return cx24123_writereg(state, 0x29, val & 0x7f); - case SEC_VOLTAGE_18: - dprintk("setting voltage 18V\n"); - return cx24123_writereg(state, 0x29, val | 0x80); - case SEC_VOLTAGE_OFF: - /* already handled in cx88-dvb */ - return 0; - default: - return -EINVAL; - }; - - return 0; -} - -/* wait for diseqc queue to become ready (or timeout) */ -static void cx24123_wait_for_diseqc(struct cx24123_state *state) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(200); - while (!(cx24123_readreg(state, 0x29) & 0x40)) { - if (time_after(jiffies, timeout)) { - err("%s: diseqc queue not ready, " \ - "command may be lost.\n", __func__); - break; - } - msleep(10); - } -} - -static int cx24123_send_diseqc_msg(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *cmd) -{ - struct cx24123_state *state = fe->demodulator_priv; - int i, val, tone; - - dprintk("\n"); - - /* stop continuous tone if enabled */ - tone = cx24123_readreg(state, 0x29); - if (tone & 0x10) - cx24123_writereg(state, 0x29, tone & ~0x50); - - /* wait for diseqc queue ready */ - cx24123_wait_for_diseqc(state); - - /* select tone mode */ - cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb); - - for (i = 0; i < cmd->msg_len; i++) - cx24123_writereg(state, 0x2C + i, cmd->msg[i]); - - val = cx24123_readreg(state, 0x29); - cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) | - ((cmd->msg_len-3) & 3)); - - /* wait for diseqc message to finish sending */ - cx24123_wait_for_diseqc(state); - - /* restart continuous tone if enabled */ - if (tone & 0x10) - cx24123_writereg(state, 0x29, tone & ~0x40); - - return 0; -} - -static int cx24123_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) -{ - struct cx24123_state *state = fe->demodulator_priv; - int val, tone; - - dprintk("\n"); - - /* stop continuous tone if enabled */ - tone = cx24123_readreg(state, 0x29); - if (tone & 0x10) - cx24123_writereg(state, 0x29, tone & ~0x50); - - /* wait for diseqc queue ready */ - cx24123_wait_for_diseqc(state); - - /* select tone mode */ - cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4); - msleep(30); - val = cx24123_readreg(state, 0x29); - if (burst == SEC_MINI_A) - cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00)); - else if (burst == SEC_MINI_B) - cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x08)); - else - return -EINVAL; - - cx24123_wait_for_diseqc(state); - cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb); - - /* restart continuous tone if enabled */ - if (tone & 0x10) - cx24123_writereg(state, 0x29, tone & ~0x40); - - return 0; -} - -static int cx24123_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct cx24123_state *state = fe->demodulator_priv; - int sync = cx24123_readreg(state, 0x14); - - *status = 0; - if (state->config->dont_use_pll) { - u32 tun_status = 0; - if (fe->ops.tuner_ops.get_status) - fe->ops.tuner_ops.get_status(fe, &tun_status); - if (tun_status & TUNER_STATUS_LOCKED) - *status |= FE_HAS_SIGNAL; - } else { - int lock = cx24123_readreg(state, 0x20); - if (lock & 0x01) - *status |= FE_HAS_SIGNAL; - } - - if (sync & 0x02) - *status |= FE_HAS_CARRIER; /* Phase locked */ - if (sync & 0x04) - *status |= FE_HAS_VITERBI; - - /* Reed-Solomon Status */ - if (sync & 0x08) - *status |= FE_HAS_SYNC; - if (sync & 0x80) - *status |= FE_HAS_LOCK; /*Full Sync */ - - return 0; -} - -/* - * Configured to return the measurement of errors in blocks, - * because no UCBLOCKS value is available, so this value doubles up - * to satisfy both measurements. - */ -static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct cx24123_state *state = fe->demodulator_priv; - - /* The true bit error rate is this value divided by - the window size (set as 256 * 255) */ - *ber = ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) | - (cx24123_readreg(state, 0x1d) << 8 | - cx24123_readreg(state, 0x1e)); - - dprintk("BER = %d\n", *ber); - - return 0; -} - -static int cx24123_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - struct cx24123_state *state = fe->demodulator_priv; - - /* larger = better */ - *signal_strength = cx24123_readreg(state, 0x3b) << 8; - - dprintk("Signal strength = %d\n", *signal_strength); - - return 0; -} - -static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct cx24123_state *state = fe->demodulator_priv; - - /* Inverted raw Es/N0 count, totally bogus but better than the - BER threshold. */ - *snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) | - (u16)cx24123_readreg(state, 0x19)); - - dprintk("read S/N index = %d\n", *snr); - - return 0; -} - -static int cx24123_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct cx24123_state *state = fe->demodulator_priv; - - dprintk("\n"); - - if (state->config->set_ts_params) - state->config->set_ts_params(fe, 0); - - state->currentfreq = p->frequency; - state->currentsymbolrate = p->u.qpsk.symbol_rate; - - cx24123_set_inversion(state, p->inversion); - cx24123_set_fec(state, p->u.qpsk.fec_inner); - cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate); - - if (!state->config->dont_use_pll) - cx24123_pll_tune(fe, p); - else if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, p); - else - err("it seems I don't have a tuner..."); - - /* Enable automatic aquisition and reset cycle */ - cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07)); - cx24123_writereg(state, 0x00, 0x10); - cx24123_writereg(state, 0x00, 0); - - if (state->config->agc_callback) - state->config->agc_callback(fe); - - return 0; -} - -static int cx24123_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct cx24123_state *state = fe->demodulator_priv; - - dprintk("\n"); - - if (cx24123_get_inversion(state, &p->inversion) != 0) { - err("%s: Failed to get inversion status\n", __func__); - return -EREMOTEIO; - } - if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) { - err("%s: Failed to get fec status\n", __func__); - return -EREMOTEIO; - } - p->frequency = state->currentfreq; - p->u.qpsk.symbol_rate = state->currentsymbolrate; - - return 0; -} - -static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct cx24123_state *state = fe->demodulator_priv; - u8 val; - - /* wait for diseqc queue ready */ - cx24123_wait_for_diseqc(state); - - val = cx24123_readreg(state, 0x29) & ~0x40; - - switch (tone) { - case SEC_TONE_ON: - dprintk("setting tone on\n"); - return cx24123_writereg(state, 0x29, val | 0x10); - case SEC_TONE_OFF: - dprintk("setting tone off\n"); - return cx24123_writereg(state, 0x29, val & 0xef); - default: - err("CASE reached default with tone=%d\n", tone); - return -EINVAL; - } - - return 0; -} - -static int cx24123_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, - unsigned int mode_flags, - unsigned int *delay, - fe_status_t *status) -{ - int retval = 0; - - if (params != NULL) - retval = cx24123_set_frontend(fe, params); - - if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) - cx24123_read_status(fe, status); - *delay = HZ/10; - - return retval; -} - -static int cx24123_get_algo(struct dvb_frontend *fe) -{ - return 1; /* FE_ALGO_HW */ -} - -static void cx24123_release(struct dvb_frontend *fe) -{ - struct cx24123_state *state = fe->demodulator_priv; - dprintk("\n"); - i2c_del_adapter(&state->tuner_i2c_adapter); - kfree(state); -} - -static int cx24123_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msg[], int num) -{ - struct cx24123_state *state = i2c_get_adapdata(i2c_adap); - /* this repeater closes after the first stop */ - cx24123_repeater_mode(state, 1, 1); - return i2c_transfer(state->i2c, msg, num); -} - -static u32 cx24123_tuner_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm cx24123_tuner_i2c_algo = { - .master_xfer = cx24123_tuner_i2c_tuner_xfer, - .functionality = cx24123_tuner_i2c_func, -}; - -struct i2c_adapter * - cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe) -{ - struct cx24123_state *state = fe->demodulator_priv; - return &state->tuner_i2c_adapter; -} -EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter); - -static struct dvb_frontend_ops cx24123_ops; - -struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, - struct i2c_adapter *i2c) -{ - /* allocate memory for the internal state */ - struct cx24123_state *state = - kzalloc(sizeof(struct cx24123_state), GFP_KERNEL); - - dprintk("\n"); - if (state == NULL) { - err("Unable to kzalloc\n"); - goto error; - } - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* check if the demod is there */ - state->demod_rev = cx24123_readreg(state, 0x00); - switch (state->demod_rev) { - case 0xe1: - info("detected CX24123C\n"); - break; - case 0xd1: - info("detected CX24123\n"); - break; - default: - err("wrong demod revision: %x\n", state->demod_rev); - goto error; - } - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &cx24123_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - /* create tuner i2c adapter */ - if (config->dont_use_pll) - cx24123_repeater_mode(state, 1, 0); - - strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus", - sizeof(state->tuner_i2c_adapter.name)); - state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo; - state->tuner_i2c_adapter.algo_data = NULL; - i2c_set_adapdata(&state->tuner_i2c_adapter, state); - if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) { - err("tuner i2c bus could not be initialized\n"); - goto error; - } - - return &state->frontend; - -error: - kfree(state); - - return NULL; -} -EXPORT_SYMBOL(cx24123_attach); - -static struct dvb_frontend_ops cx24123_ops = { - - .info = { - .name = "Conexant CX24123/CX24109", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1011, /* kHz for QPSK frontends */ - .frequency_tolerance = 5000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_RECOVER - }, - - .release = cx24123_release, - - .init = cx24123_initfe, - .set_frontend = cx24123_set_frontend, - .get_frontend = cx24123_get_frontend, - .read_status = cx24123_read_status, - .read_ber = cx24123_read_ber, - .read_signal_strength = cx24123_read_signal_strength, - .read_snr = cx24123_read_snr, - .diseqc_send_master_cmd = cx24123_send_diseqc_msg, - .diseqc_send_burst = cx24123_diseqc_send_burst, - .set_tone = cx24123_set_tone, - .set_voltage = cx24123_set_voltage, - .tune = cx24123_tune, - .get_frontend_algo = cx24123_get_algo, -}; - -MODULE_DESCRIPTION("DVB Frontend module for Conexant " \ - "CX24123/CX24109/CX24113 hardware"); -MODULE_AUTHOR("Steven Toth"); -MODULE_LICENSE("GPL"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24123.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24123.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24123.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/cx24123.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* - Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver - - Copyright (C) 2005 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef CX24123_H -#define CX24123_H - -#include - -struct cx24123_config { - /* the demodulator's i2c address */ - u8 demod_address; - - /* Need to set device param for start_dma */ - int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); - - /* 0 = LNB voltage normal, 1 = LNB voltage inverted */ - int lnb_polarity; - - /* this device has another tuner */ - u8 dont_use_pll; - void (*agc_callback) (struct dvb_frontend *); -}; - -#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) \ - && defined(MODULE)) -extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, - struct i2c_adapter *i2c); -extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *); -#else -static inline struct dvb_frontend *cx24123_attach( - const struct cx24123_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static struct i2c_adapter * - cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* CX24123_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0070.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0070.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0070.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0070.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,737 +0,0 @@ -/* - * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. - * - * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) - * - * 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, or (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * This code is more or less generated from another driver, please - * excuse some codingstyle oddities. - * - */ - -#include -#include -#include - -#include "dvb_frontend.h" - -#include "dib0070.h" -#include "dibx000_common.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); - -#define dprintk(args...) do { \ - if (debug) { \ - printk(KERN_DEBUG "DiB0070: "); \ - printk(args); \ - printk("\n"); \ - } \ -} while (0) - -#define DIB0070_P1D 0x00 -#define DIB0070_P1F 0x01 -#define DIB0070_P1G 0x03 -#define DIB0070S_P1A 0x02 - -struct dib0070_state { - struct i2c_adapter *i2c; - struct dvb_frontend *fe; - const struct dib0070_config *cfg; - u16 wbd_ff_offset; - u8 revision; - - enum frontend_tune_state tune_state; - u32 current_rf; - - /* for the captrim binary search */ - s8 step; - u16 adc_diff; - - s8 captrim; - s8 fcaptrim; - u16 lo4; - - const struct dib0070_tuning *current_tune_table_index; - const struct dib0070_lna_match *lna_match; - - u8 wbd_gain_current; - u16 wbd_offset_3_3[2]; -}; - -static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) -{ - u8 b[2]; - struct i2c_msg msg[2] = { - { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, - }; - if (i2c_transfer(state->i2c, msg, 2) != 2) { - printk(KERN_WARNING "DiB0070 I2C read failed\n"); - return 0; - } - return (b[0] << 8) | b[1]; -} - -static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) -{ - u8 b[3] = { reg, val >> 8, val & 0xff }; - struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "DiB0070 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -#define HARD_RESET(state) do { \ - state->cfg->sleep(state->fe, 0); \ - if (state->cfg->reset) { \ - state->cfg->reset(state->fe,1); msleep(10); \ - state->cfg->reset(state->fe,0); msleep(10); \ - } \ -} while (0) - -static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) -{ - struct dib0070_state *state = fe->tuner_priv; - u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; - - if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000) - tmp |= (0 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000) - tmp |= (1 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000) - tmp |= (2 << 14); - else - tmp |= (3 << 14); - - dib0070_write_reg(state, 0x02, tmp); - - /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ - if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { - u16 value = dib0070_read_reg(state, 0x17); - - dib0070_write_reg(state, 0x17, value & 0xfffc); - tmp = dib0070_read_reg(state, 0x01) & 0x01ff; - dib0070_write_reg(state, 0x01, tmp | (60 << 9)); - - dib0070_write_reg(state, 0x17, value); - } - return 0; -} - -static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state) -{ - int8_t step_sign; - u16 adc; - int ret = 0; - - if (*tune_state == CT_TUNER_STEP_0) { - - dib0070_write_reg(state, 0x0f, 0xed10); - dib0070_write_reg(state, 0x17, 0x0034); - - dib0070_write_reg(state, 0x18, 0x0032); - state->step = state->captrim = state->fcaptrim = 64; - state->adc_diff = 3000; - ret = 20; - - *tune_state = CT_TUNER_STEP_1; - } else if (*tune_state == CT_TUNER_STEP_1) { - state->step /= 2; - dib0070_write_reg(state, 0x14, state->lo4 | state->captrim); - ret = 15; - - *tune_state = CT_TUNER_STEP_2; - } else if (*tune_state == CT_TUNER_STEP_2) { - - adc = dib0070_read_reg(state, 0x19); - - dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024); - - if (adc >= 400) { - adc -= 400; - step_sign = -1; - } else { - adc = 400 - adc; - step_sign = 1; - } - - if (adc < state->adc_diff) { - dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff); - state->adc_diff = adc; - state->fcaptrim = state->captrim; - - - - } - state->captrim += (step_sign * state->step); - - if (state->step >= 1) - *tune_state = CT_TUNER_STEP_1; - else - *tune_state = CT_TUNER_STEP_3; - - } else if (*tune_state == CT_TUNER_STEP_3) { - dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim); - dib0070_write_reg(state, 0x18, 0x07ff); - *tune_state = CT_TUNER_STEP_4; - } - - return ret; -} - -static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) -{ - struct dib0070_state *state = fe->tuner_priv; - u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); - dprintk("CTRL_LO5: 0x%x", lo5); - return dib0070_write_reg(state, 0x15, lo5); -} - -void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) -{ - struct dib0070_state *state = fe->tuner_priv; - - if (open) { - dib0070_write_reg(state, 0x1b, 0xff00); - dib0070_write_reg(state, 0x1a, 0x0000); - } else { - dib0070_write_reg(state, 0x1b, 0x4112); - if (state->cfg->vga_filter != 0) { - dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); - dprintk("vga filter register is set to %x", state->cfg->vga_filter); - } else - dib0070_write_reg(state, 0x1a, 0x0009); - } -} - -EXPORT_SYMBOL(dib0070_ctrl_agc_filter); -struct dib0070_tuning { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 switch_trim; - u8 vco_band; - u8 hfdiv; - u8 vco_multi; - u8 presc; - u8 wbdmux; - u16 tuner_enable; -}; - -struct dib0070_lna_match { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 lna_band; -}; - -static const struct dib0070_tuning dib0070s_tuning_table[] = { - { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */ - { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 }, - { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 }, - { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */ - { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, - { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, - { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */ -}; - -static const struct dib0070_tuning dib0070_tuning_table[] = { - { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */ - { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */ - { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 }, - { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 }, - { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */ - { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 }, - { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 }, - { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */ -}; - -static const struct dib0070_lna_match dib0070_lna_flip_chip[] = { - { 180000, 0 }, /* VHF */ - { 188000, 1 }, - { 196400, 2 }, - { 250000, 3 }, - { 550000, 0 }, /* UHF */ - { 590000, 1 }, - { 666000, 3 }, - { 864000, 5 }, - { 1500000, 0 }, /* LBAND or everything higher than UHF */ - { 1600000, 1 }, - { 2000000, 3 }, - { 0xffffffff, 7 }, -}; - -static const struct dib0070_lna_match dib0070_lna[] = { - { 180000, 0 }, /* VHF */ - { 188000, 1 }, - { 196400, 2 }, - { 250000, 3 }, - { 550000, 2 }, /* UHF */ - { 650000, 3 }, - { 750000, 5 }, - { 850000, 6 }, - { 864000, 7 }, - { 1500000, 0 }, /* LBAND or everything higher than UHF */ - { 1600000, 1 }, - { 2000000, 3 }, - { 0xffffffff, 7 }, -}; - -#define LPF 100 -static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) -{ - struct dib0070_state *state = fe->tuner_priv; - - const struct dib0070_tuning *tune; - const struct dib0070_lna_match *lna_match; - - enum frontend_tune_state *tune_state = &state->tune_state; - int ret = 10; /* 1ms is the default delay most of the time */ - - u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000); - u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); - -#ifdef CONFIG_SYS_ISDBT - if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) - if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) - && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) - || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2))) - || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) - freq += 850; -#endif - if (state->current_rf != freq) { - - switch (state->revision) { - case DIB0070S_P1A: - tune = dib0070s_tuning_table; - lna_match = dib0070_lna; - break; - default: - tune = dib0070_tuning_table; - if (state->cfg->flip_chip) - lna_match = dib0070_lna_flip_chip; - else - lna_match = dib0070_lna; - break; - } - while (freq > tune->max_freq) /* find the right one */ - tune++; - while (freq > lna_match->max_freq) /* find the right one */ - lna_match++; - - state->current_tune_table_index = tune; - state->lna_match = lna_match; - } - - if (*tune_state == CT_TUNER_START) { - dprintk("Tuning for Band: %hd (%d kHz)", band, freq); - if (state->current_rf != freq) { - u8 REFDIV; - u32 FBDiv, Rest, FREF, VCOF_kHz; - u8 Den; - - state->current_rf = freq; - state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); - - - dib0070_write_reg(state, 0x17, 0x30); - - - VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; - - switch (band) { - case BAND_VHF: - REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); - break; - case BAND_FM: - REFDIV = (u8) ((state->cfg->clock_khz) / 1000); - break; - default: - REFDIV = (u8) (state->cfg->clock_khz / 10000); - break; - } - FREF = state->cfg->clock_khz / REFDIV; - - - - switch (state->revision) { - case DIB0070S_P1A: - FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); - Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; - break; - - case DIB0070_P1G: - case DIB0070_P1F: - default: - FBDiv = (freq / (FREF / 2)); - Rest = 2 * freq - FBDiv * FREF; - break; - } - - if (Rest < LPF) - Rest = 0; - else if (Rest < 2 * LPF) - Rest = 2 * LPF; - else if (Rest > (FREF - LPF)) { - Rest = 0; - FBDiv += 1; - } else if (Rest > (FREF - 2 * LPF)) - Rest = FREF - 2 * LPF; - Rest = (Rest * 6528) / (FREF / 10); - - Den = 1; - if (Rest > 0) { - state->lo4 |= (1 << 14) | (1 << 12); - Den = 255; - } - - - dib0070_write_reg(state, 0x11, (u16)FBDiv); - dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); - dib0070_write_reg(state, 0x13, (u16) Rest); - - if (state->revision == DIB0070S_P1A) { - - if (band == BAND_SBAND) { - dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); - dib0070_write_reg(state, 0x1d, 0xFFFF); - } else - dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); - } - - dib0070_write_reg(state, 0x20, - 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); - - dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); - dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); - dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); - dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); - dprintk("VCO = %hd", state->current_tune_table_index->vco_band); - dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); - - *tune_state = CT_TUNER_STEP_0; - } else { /* we are already tuned to this frequency - the configuration is correct */ - ret = 50; /* wakeup time */ - *tune_state = CT_TUNER_STEP_5; - } - } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { - - ret = dib0070_captrim(state, tune_state); - - } else if (*tune_state == CT_TUNER_STEP_4) { - const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; - if (tmp != NULL) { - while (freq/1000 > tmp->freq) /* find the right one */ - tmp++; - dib0070_write_reg(state, 0x0f, - (0 << 15) | (1 << 14) | (3 << 12) - | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) - | (state->current_tune_table_index->wbdmux << 0)); - state->wbd_gain_current = tmp->wbd_gain_val; - } else { - dib0070_write_reg(state, 0x0f, - (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index-> - wbdmux << 0)); - state->wbd_gain_current = 6; - } - - dib0070_write_reg(state, 0x06, 0x3fff); - dib0070_write_reg(state, 0x07, - (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0)); - dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); - dib0070_write_reg(state, 0x0d, 0x0d80); - - - dib0070_write_reg(state, 0x18, 0x07ff); - dib0070_write_reg(state, 0x17, 0x0033); - - - *tune_state = CT_TUNER_STEP_5; - } else if (*tune_state == CT_TUNER_STEP_5) { - dib0070_set_bandwidth(fe, ch); - *tune_state = CT_TUNER_STOP; - } else { - ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ - } - return ret; -} - - -static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - struct dib0070_state *state = fe->tuner_priv; - uint32_t ret; - - state->tune_state = CT_TUNER_START; - - do { - ret = dib0070_tune_digital(fe, p); - if (ret != FE_CALLBACK_TIME_NEVER) - msleep(ret/10); - else - break; - } while (state->tune_state != CT_TUNER_STOP); - - return 0; -} - -static int dib0070_wakeup(struct dvb_frontend *fe) -{ - struct dib0070_state *state = fe->tuner_priv; - if (state->cfg->sleep) - state->cfg->sleep(fe, 0); - return 0; -} - -static int dib0070_sleep(struct dvb_frontend *fe) -{ - struct dib0070_state *state = fe->tuner_priv; - if (state->cfg->sleep) - state->cfg->sleep(fe, 1); - return 0; -} - -u8 dib0070_get_rf_output(struct dvb_frontend *fe) -{ - struct dib0070_state *state = fe->tuner_priv; - return (dib0070_read_reg(state, 0x07) >> 11) & 0x3; -} -EXPORT_SYMBOL(dib0070_get_rf_output); - -int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no) -{ - struct dib0070_state *state = fe->tuner_priv; - u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff; - if (no > 3) - no = 3; - if (no < 1) - no = 1; - return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11)); -} -EXPORT_SYMBOL(dib0070_set_rf_output); - -static const u16 dib0070_p1f_defaults[] = - -{ - 7, 0x02, - 0x0008, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0002, - 0x0100, - - 3, 0x0d, - 0x0d80, - 0x0001, - 0x0000, - - 4, 0x11, - 0x0000, - 0x0103, - 0x0000, - 0x0000, - - 3, 0x16, - 0x0004 | 0x0040, - 0x0030, - 0x07ff, - - 6, 0x1b, - 0x4112, - 0xff00, - 0xc07f, - 0x0000, - 0x0180, - 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, - - 0, -}; - -static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain) -{ - u16 tuner_en = dib0070_read_reg(state, 0x20); - u16 offset; - - dib0070_write_reg(state, 0x18, 0x07ff); - dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); - dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); - msleep(9); - offset = dib0070_read_reg(state, 0x19); - dib0070_write_reg(state, 0x20, tuner_en); - return offset; -} - -static void dib0070_wbd_offset_calibration(struct dib0070_state *state) -{ - u8 gain; - for (gain = 6; gain < 8; gain++) { - state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); - dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]); - } -} - -u16 dib0070_wbd_offset(struct dvb_frontend *fe) -{ - struct dib0070_state *state = fe->tuner_priv; - const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; - u32 freq = fe->dtv_property_cache.frequency/1000; - - if (tmp != NULL) { - while (freq/1000 > tmp->freq) /* find the right one */ - tmp++; - state->wbd_gain_current = tmp->wbd_gain_val; - } else - state->wbd_gain_current = 6; - - return state->wbd_offset_3_3[state->wbd_gain_current - 6]; -} -EXPORT_SYMBOL(dib0070_wbd_offset); - -#define pgm_read_word(w) (*w) -static int dib0070_reset(struct dvb_frontend *fe) -{ - struct dib0070_state *state = fe->tuner_priv; - u16 l, r, *n; - - HARD_RESET(state); - - -#ifndef FORCE_SBAND_TUNER - if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) - state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; - else -#else -#warning forcing SBAND -#endif - state->revision = DIB0070S_P1A; - - /* P1F or not */ - dprintk("Revision: %x", state->revision); - - if (state->revision == DIB0070_P1D) { - dprintk("Error: this driver is not to be used meant for P1D or earlier"); - return -EINVAL; - } - - n = (u16 *) dib0070_p1f_defaults; - l = pgm_read_word(n++); - while (l) { - r = pgm_read_word(n++); - do { - dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); - r++; - } while (--l); - l = pgm_read_word(n++); - } - - if (state->cfg->force_crystal_mode != 0) - r = state->cfg->force_crystal_mode; - else if (state->cfg->clock_khz >= 24000) - r = 1; - else - r = 2; - - - r |= state->cfg->osc_buffer_state << 3; - - dib0070_write_reg(state, 0x10, r); - dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5)); - - if (state->cfg->invert_iq) { - r = dib0070_read_reg(state, 0x02) & 0xffdf; - dib0070_write_reg(state, 0x02, r | (1 << 5)); - } - - if (state->revision == DIB0070S_P1A) - dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); - else - dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter); - - dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); - - dib0070_wbd_offset_calibration(state); - - return 0; -} - -static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct dib0070_state *state = fe->tuner_priv; - - *frequency = 1000 * state->current_rf; - return 0; -} - -static int dib0070_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops dib0070_ops = { - .info = { - .name = "DiBcom DiB0070", - .frequency_min = 45000000, - .frequency_max = 860000000, - .frequency_step = 1000, - }, - .release = dib0070_release, - - .init = dib0070_wakeup, - .sleep = dib0070_sleep, - .set_params = dib0070_tune, - - .get_frequency = dib0070_get_frequency, -// .get_bandwidth = dib0070_get_bandwidth -}; - -struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) -{ - struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->cfg = cfg; - state->i2c = i2c; - state->fe = fe; - fe->tuner_priv = state; - - if (dib0070_reset(fe) != 0) - goto free_mem; - - printk(KERN_INFO "DiB0070: successfully identified\n"); - memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = state; - return fe; - -free_mem: - kfree(state); - fe->tuner_priv = NULL; - return NULL; -} -EXPORT_SYMBOL(dib0070_attach); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0070.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0070.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0070.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0070.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/* - * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. - * - * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) - * - * 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, version 2. - */ -#ifndef DIB0070_H -#define DIB0070_H - -struct dvb_frontend; -struct i2c_adapter; - -#define DEFAULT_DIB0070_I2C_ADDRESS 0x60 - -struct dib0070_wbd_gain_cfg { - u16 freq; - u16 wbd_gain_val; -}; - -struct dib0070_config { - u8 i2c_address; - - /* tuner pins controlled externally */ - int (*reset) (struct dvb_frontend *, int); - int (*sleep) (struct dvb_frontend *, int); - - /* offset in kHz */ - int freq_offset_khz_uhf; - int freq_offset_khz_vhf; - - u8 osc_buffer_state; /* 0= normal, 1= tri-state */ - u32 clock_khz; - u8 clock_pad_drive; /* (Drive + 1) * 2mA */ - - u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */ - - u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */ - - u8 flip_chip; - u8 enable_third_order_filter; - u8 charge_pump; - - const struct dib0070_wbd_gain_cfg *wbd_gain; - - u8 vga_filter; -}; - -#if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE)) -extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); -extern u16 dib0070_wbd_offset(struct dvb_frontend *); -extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open); -extern u8 dib0070_get_rf_output(struct dvb_frontend *fe); -extern int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no); -#else -static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} - -static inline void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0090.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0090.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0090.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0090.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2456 +0,0 @@ -/* - * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. - * - * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) - * - * 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, or (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * This code is more or less generated from another driver, please - * excuse some codingstyle oddities. - * - */ - -#include -#include -#include - -#include "dvb_frontend.h" - -#include "dib0090.h" -#include "dibx000_common.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); - -#define dprintk(args...) do { \ - if (debug) { \ - printk(KERN_DEBUG "DiB0090: "); \ - printk(args); \ - printk("\n"); \ - } \ -} while (0) - -#define CONFIG_SYS_DVBT -#define CONFIG_SYS_ISDBT -#define CONFIG_BAND_CBAND -#define CONFIG_BAND_VHF -#define CONFIG_BAND_UHF -#define CONFIG_DIB0090_USE_PWM_AGC - -#define EN_LNA0 0x8000 -#define EN_LNA1 0x4000 -#define EN_LNA2 0x2000 -#define EN_LNA3 0x1000 -#define EN_MIX0 0x0800 -#define EN_MIX1 0x0400 -#define EN_MIX2 0x0200 -#define EN_MIX3 0x0100 -#define EN_IQADC 0x0040 -#define EN_PLL 0x0020 -#define EN_TX 0x0010 -#define EN_BB 0x0008 -#define EN_LO 0x0004 -#define EN_BIAS 0x0001 - -#define EN_IQANA 0x0002 -#define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */ -#define EN_CRYSTAL 0x0002 - -#define EN_UHF 0x22E9 -#define EN_VHF 0x44E9 -#define EN_LBD 0x11E9 -#define EN_SBD 0x44E9 -#define EN_CAB 0x88E9 - -/* Calibration defines */ -#define DC_CAL 0x1 -#define WBD_CAL 0x2 -#define TEMP_CAL 0x4 -#define CAPTRIM_CAL 0x8 - -#define KROSUS_PLL_LOCKED 0x800 -#define KROSUS 0x2 - -/* Use those defines to identify SOC version */ -#define SOC 0x02 -#define SOC_7090_P1G_11R1 0x82 -#define SOC_7090_P1G_21R1 0x8a -#define SOC_8090_P1G_11R1 0x86 -#define SOC_8090_P1G_21R1 0x8e - -/* else use thos ones to check */ -#define P1A_B 0x0 -#define P1C 0x1 -#define P1D_E_F 0x3 -#define P1G 0x7 -#define P1G_21R2 0xf - -#define MP001 0x1 /* Single 9090/8096 */ -#define MP005 0x4 /* Single Sband */ -#define MP008 0x6 /* Dual diversity VHF-UHF-LBAND */ -#define MP009 0x7 /* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */ - -#define pgm_read_word(w) (*w) - -struct dc_calibration; - -struct dib0090_tuning { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 switch_trim; - u8 lna_tune; - u16 lna_bias; - u16 v2i; - u16 mix; - u16 load; - u16 tuner_enable; -}; - -struct dib0090_pll { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 vco_band; - u8 hfdiv_code; - u8 hfdiv; - u8 topresc; -}; - -struct dib0090_identity { - u8 version; - u8 product; - u8 p1g; - u8 in_soc; -}; - -struct dib0090_state { - struct i2c_adapter *i2c; - struct dvb_frontend *fe; - const struct dib0090_config *config; - - u8 current_band; - enum frontend_tune_state tune_state; - u32 current_rf; - - u16 wbd_offset; - s16 wbd_target; /* in dB */ - - s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */ - s16 current_gain; /* keeps the currently programmed gain */ - u8 agc_step; /* new binary search */ - - u16 gain[2]; /* for channel monitoring */ - - const u16 *rf_ramp; - const u16 *bb_ramp; - - /* for the software AGC ramps */ - u16 bb_1_def; - u16 rf_lt_def; - u16 gain_reg[4]; - - /* for the captrim/dc-offset search */ - s8 step; - s16 adc_diff; - s16 min_adc_diff; - - s8 captrim; - s8 fcaptrim; - - const struct dc_calibration *dc; - u16 bb6, bb7; - - const struct dib0090_tuning *current_tune_table_index; - const struct dib0090_pll *current_pll_table_index; - - u8 tuner_is_tuned; - u8 agc_freeze; - - struct dib0090_identity identity; - - u32 rf_request; - u8 current_standard; - - u8 calibrate; - u32 rest; - u16 bias; - s16 temperature; - - u8 wbd_calibration_gain; - const struct dib0090_wbd_slope *current_wbd_table; - u16 wbdmux; -}; - -struct dib0090_fw_state { - struct i2c_adapter *i2c; - struct dvb_frontend *fe; - struct dib0090_identity identity; - const struct dib0090_config *config; -}; - -static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) -{ - u8 b[2]; - struct i2c_msg msg[2] = { - {.addr = state->config->i2c_address, .flags = 0, .buf = ®, .len = 1}, - {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2}, - }; - if (i2c_transfer(state->i2c, msg, 2) != 2) { - printk(KERN_WARNING "DiB0090 I2C read failed\n"); - return 0; - } - return (b[0] << 8) | b[1]; -} - -static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) -{ - u8 b[3] = { reg & 0xff, val >> 8, val & 0xff }; - struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 }; - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "DiB0090 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) -{ - u8 b[2]; - struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 }; - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "DiB0090 I2C read failed\n"); - return 0; - } - return (b[0] << 8) | b[1]; -} - -static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) -{ - u8 b[2] = { val >> 8, val & 0xff }; - struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 }; - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "DiB0090 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -#define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0) -#define ADC_TARGET -220 -#define GAIN_ALPHA 5 -#define WBD_ALPHA 6 -#define LPF 100 -static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c) -{ - do { - dib0090_write_reg(state, r++, *b++); - } while (--c); -} - -static int dib0090_identify(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - u16 v; - struct dib0090_identity *identity = &state->identity; - - v = dib0090_read_reg(state, 0x1a); - - identity->p1g = 0; - identity->in_soc = 0; - - dprintk("Tuner identification (Version = 0x%04x)", v); - - /* without PLL lock info */ - v &= ~KROSUS_PLL_LOCKED; - - identity->version = v & 0xff; - identity->product = (v >> 8) & 0xf; - - if (identity->product != KROSUS) - goto identification_error; - - if ((identity->version & 0x3) == SOC) { - identity->in_soc = 1; - switch (identity->version) { - case SOC_8090_P1G_11R1: - dprintk("SOC 8090 P1-G11R1 Has been detected"); - identity->p1g = 1; - break; - case SOC_8090_P1G_21R1: - dprintk("SOC 8090 P1-G21R1 Has been detected"); - identity->p1g = 1; - break; - case SOC_7090_P1G_11R1: - dprintk("SOC 7090 P1-G11R1 Has been detected"); - identity->p1g = 1; - break; - case SOC_7090_P1G_21R1: - dprintk("SOC 7090 P1-G21R1 Has been detected"); - identity->p1g = 1; - break; - default: - goto identification_error; - } - } else { - switch ((identity->version >> 5) & 0x7) { - case MP001: - dprintk("MP001 : 9090/8096"); - break; - case MP005: - dprintk("MP005 : Single Sband"); - break; - case MP008: - dprintk("MP008 : diversity VHF-UHF-LBAND"); - break; - case MP009: - dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND"); - break; - default: - goto identification_error; - } - - switch (identity->version & 0x1f) { - case P1G_21R2: - dprintk("P1G_21R2 detected"); - identity->p1g = 1; - break; - case P1G: - dprintk("P1G detected"); - identity->p1g = 1; - break; - case P1D_E_F: - dprintk("P1D/E/F detected"); - break; - case P1C: - dprintk("P1C detected"); - break; - case P1A_B: - dprintk("P1-A/B detected: driver is deactivated - not available"); - goto identification_error; - break; - default: - goto identification_error; - } - } - - return 0; - -identification_error: - return -EIO; -} - -static int dib0090_fw_identify(struct dvb_frontend *fe) -{ - struct dib0090_fw_state *state = fe->tuner_priv; - struct dib0090_identity *identity = &state->identity; - - u16 v = dib0090_fw_read_reg(state, 0x1a); - identity->p1g = 0; - identity->in_soc = 0; - - dprintk("FE: Tuner identification (Version = 0x%04x)", v); - - /* without PLL lock info */ - v &= ~KROSUS_PLL_LOCKED; - - identity->version = v & 0xff; - identity->product = (v >> 8) & 0xf; - - if (identity->product != KROSUS) - goto identification_error; - - if ((identity->version & 0x3) == SOC) { - identity->in_soc = 1; - switch (identity->version) { - case SOC_8090_P1G_11R1: - dprintk("SOC 8090 P1-G11R1 Has been detected"); - identity->p1g = 1; - break; - case SOC_8090_P1G_21R1: - dprintk("SOC 8090 P1-G21R1 Has been detected"); - identity->p1g = 1; - break; - case SOC_7090_P1G_11R1: - dprintk("SOC 7090 P1-G11R1 Has been detected"); - identity->p1g = 1; - break; - case SOC_7090_P1G_21R1: - dprintk("SOC 7090 P1-G21R1 Has been detected"); - identity->p1g = 1; - break; - default: - goto identification_error; - } - } else { - switch ((identity->version >> 5) & 0x7) { - case MP001: - dprintk("MP001 : 9090/8096"); - break; - case MP005: - dprintk("MP005 : Single Sband"); - break; - case MP008: - dprintk("MP008 : diversity VHF-UHF-LBAND"); - break; - case MP009: - dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND"); - break; - default: - goto identification_error; - } - - switch (identity->version & 0x1f) { - case P1G_21R2: - dprintk("P1G_21R2 detected"); - identity->p1g = 1; - break; - case P1G: - dprintk("P1G detected"); - identity->p1g = 1; - break; - case P1D_E_F: - dprintk("P1D/E/F detected"); - break; - case P1C: - dprintk("P1C detected"); - break; - case P1A_B: - dprintk("P1-A/B detected: driver is deactivated - not available"); - goto identification_error; - break; - default: - goto identification_error; - } - } - - return 0; - -identification_error: - return -EIO;; -} - -static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) -{ - struct dib0090_state *state = fe->tuner_priv; - u16 PllCfg, i, v; - - HARD_RESET(state); - - dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL); - dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ - - if (!cfg->in_soc) { - /* adcClkOutRatio=8->7, release reset */ - dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); - if (cfg->clkoutdrive != 0) - dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) - | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); - else - dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) - | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); - } - - /* Read Pll current config * */ - PllCfg = dib0090_read_reg(state, 0x21); - - /** Reconfigure PLL if current setting is different from default setting **/ - if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc) - && !cfg->io.pll_bypass) { - - /* Set Bypass mode */ - PllCfg |= (1 << 15); - dib0090_write_reg(state, 0x21, PllCfg); - - /* Set Reset Pll */ - PllCfg &= ~(1 << 13); - dib0090_write_reg(state, 0x21, PllCfg); - - /*** Set new Pll configuration in bypass and reset state ***/ - PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv); - dib0090_write_reg(state, 0x21, PllCfg); - - /* Remove Reset Pll */ - PllCfg |= (1 << 13); - dib0090_write_reg(state, 0x21, PllCfg); - - /*** Wait for PLL lock ***/ - i = 100; - do { - v = !!(dib0090_read_reg(state, 0x1a) & 0x800); - if (v) - break; - } while (--i); - - if (i == 0) { - dprintk("Pll: Unable to lock Pll"); - return; - } - - /* Finally Remove Bypass mode */ - PllCfg &= ~(1 << 15); - dib0090_write_reg(state, 0x21, PllCfg); - } - - if (cfg->io.pll_bypass) { - PllCfg |= (cfg->io.pll_bypass << 15); - dib0090_write_reg(state, 0x21, PllCfg); - } -} - -static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) -{ - struct dib0090_fw_state *state = fe->tuner_priv; - u16 PllCfg; - u16 v; - int i; - - dprintk("fw reset digital"); - HARD_RESET(state); - - dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL); - dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ - - dib0090_fw_write_reg(state, 0x20, - ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv); - - v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0); - if (cfg->clkoutdrive != 0) - v |= cfg->clkoutdrive << 5; - else - v |= 7 << 5; - - v |= 2 << 10; - dib0090_fw_write_reg(state, 0x23, v); - - /* Read Pll current config * */ - PllCfg = dib0090_fw_read_reg(state, 0x21); - - /** Reconfigure PLL if current setting is different from default setting **/ - if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) { - - /* Set Bypass mode */ - PllCfg |= (1 << 15); - dib0090_fw_write_reg(state, 0x21, PllCfg); - - /* Set Reset Pll */ - PllCfg &= ~(1 << 13); - dib0090_fw_write_reg(state, 0x21, PllCfg); - - /*** Set new Pll configuration in bypass and reset state ***/ - PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv); - dib0090_fw_write_reg(state, 0x21, PllCfg); - - /* Remove Reset Pll */ - PllCfg |= (1 << 13); - dib0090_fw_write_reg(state, 0x21, PllCfg); - - /*** Wait for PLL lock ***/ - i = 100; - do { - v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800); - if (v) - break; - } while (--i); - - if (i == 0) { - dprintk("Pll: Unable to lock Pll"); - return -EIO; - } - - /* Finally Remove Bypass mode */ - PllCfg &= ~(1 << 15); - dib0090_fw_write_reg(state, 0x21, PllCfg); - } - - if (cfg->io.pll_bypass) { - PllCfg |= (cfg->io.pll_bypass << 15); - dib0090_fw_write_reg(state, 0x21, PllCfg); - } - - return dib0090_fw_identify(fe); -} - -static int dib0090_wakeup(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - if (state->config->sleep) - state->config->sleep(fe, 0); - - /* enable dataTX in case we have been restarted in the wrong moment */ - dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); - return 0; -} - -static int dib0090_sleep(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - if (state->config->sleep) - state->config->sleep(fe, 1); - return 0; -} - -void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) -{ - struct dib0090_state *state = fe->tuner_priv; - if (fast) - dib0090_write_reg(state, 0x04, 0); - else - dib0090_write_reg(state, 0x04, 1); -} - -EXPORT_SYMBOL(dib0090_dcc_freq); - -static const u16 bb_ramp_pwm_normal_socs[] = { - 550, /* max BB gain in 10th of dB */ - (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */ - 440, - (4 << 9) | 0, /* BB_RAMP3 = 26dB */ - (0 << 9) | 208, /* BB_RAMP4 */ - (4 << 9) | 208, /* BB_RAMP5 = 29dB */ - (0 << 9) | 440, /* BB_RAMP6 */ -}; - -static const u16 rf_ramp_pwm_cband_7090[] = { - 280, /* max RF gain in 10th of dB */ - 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ - 504, /* ramp_max = maximum X used on the ramp */ - (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */ - (0 << 10) | 504, /* RF_RAMP6, LNA 1 */ - (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */ - (0 << 10) | 364, /* RF_RAMP8, LNA 2 */ - (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */ - (0 << 10) | 228, /* GAIN_4_2, LNA 3 */ - (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ - (0 << 10) | 109, /* RF_RAMP4, LNA 4 */ -}; - -static const u16 rf_ramp_pwm_cband_8090[] = { - 345, /* max RF gain in 10th of dB */ - 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ - 1000, /* ramp_max = maximum X used on the ramp */ - (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */ - (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */ - (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */ - (0 << 10) | 772, /* RF_RAMP6, LNA 2 */ - (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */ - (0 << 10) | 496, /* RF_RAMP8, LNA 3 */ - (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */ - (0 << 10) | 200, /* GAIN_4_2, LNA 4 */ -}; - -static const u16 rf_ramp_pwm_uhf_7090[] = { - 407, /* max RF gain in 10th of dB */ - 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ - 529, /* ramp_max = maximum X used on the ramp */ - (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ - (0 << 10) | 176, /* RF_RAMP4, LNA 1 */ - (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */ - (0 << 10) | 529, /* RF_RAMP6, LNA 2 */ - (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */ - (0 << 10) | 400, /* RF_RAMP8, LNA 3 */ - (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */ - (0 << 10) | 316, /* GAIN_4_2, LNA 4 */ -}; - -static const u16 rf_ramp_pwm_uhf_8090[] = { - 388, /* max RF gain in 10th of dB */ - 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ - 1008, /* ramp_max = maximum X used on the ramp */ - (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ - (0 << 10) | 369, /* RF_RAMP4, LNA 1 */ - (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */ - (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */ - (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */ - (0 << 10) | 809, /* RF_RAMP8, LNA 3 */ - (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */ - (0 << 10) | 659, /* GAIN_4_2, LNA 4 */ -}; - -static const u16 rf_ramp_pwm_cband[] = { - 0, /* max RF gain in 10th of dB */ - 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ - 0, /* ramp_max = maximum X used on the ramp */ - (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */ - (0 << 10) | 0, /* 0x2d, LNA 1 */ - (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */ - (0 << 10) | 0, /* 0x2f, LNA 2 */ - (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */ - (0 << 10) | 0, /* 0x31, LNA 3 */ - (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ - (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ -}; - -static const u16 rf_ramp_vhf[] = { - 412, /* max RF gain in 10th of dB */ - 132, 307, 127, /* LNA1, 13.2dB */ - 105, 412, 255, /* LNA2, 10.5dB */ - 50, 50, 127, /* LNA3, 5dB */ - 125, 175, 127, /* LNA4, 12.5dB */ - 0, 0, 127, /* CBAND, 0dB */ -}; - -static const u16 rf_ramp_uhf[] = { - 412, /* max RF gain in 10th of dB */ - 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */ - 105, 412, 255, /* LNA2 : 10.5 dB */ - 50, 50, 127, /* LNA3 : 5.0 dB */ - 125, 175, 127, /* LNA4 : 12.5 dB */ - 0, 0, 127, /* CBAND : 0.0 dB */ -}; - -static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */ -{ - 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */ - 84, 314, 127, /* LNA1 */ - 80, 230, 255, /* LNA2 */ - 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */ - 70, 70, 127, /* LNA4 */ - 0, 0, 127, /* CBAND */ -}; - -static const u16 rf_ramp_cband[] = { - 332, /* max RF gain in 10th of dB */ - 132, 252, 127, /* LNA1, dB */ - 80, 332, 255, /* LNA2, dB */ - 0, 0, 127, /* LNA3, dB */ - 0, 0, 127, /* LNA4, dB */ - 120, 120, 127, /* LT1 CBAND */ -}; - -static const u16 rf_ramp_pwm_vhf[] = { - 404, /* max RF gain in 10th of dB */ - 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ - 1011, /* ramp_max = maximum X used on the ramp */ - (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ - (0 << 10) | 756, /* 0x2d, LNA 1 */ - (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ - (0 << 10) | 1011, /* 0x2f, LNA 2 */ - (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */ - (0 << 10) | 417, /* 0x31, LNA 3 */ - (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */ - (0 << 10) | 290, /* GAIN_4_2, LNA 4 */ -}; - -static const u16 rf_ramp_pwm_uhf[] = { - 404, /* max RF gain in 10th of dB */ - 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ - 1011, /* ramp_max = maximum X used on the ramp */ - (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ - (0 << 10) | 756, /* 0x2d, LNA 1 */ - (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ - (0 << 10) | 1011, /* 0x2f, LNA 2 */ - (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */ - (0 << 10) | 127, /* 0x31, LNA 3 */ - (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */ - (0 << 10) | 417, /* GAIN_4_2, LNA 4 */ -}; - -static const u16 bb_ramp_boost[] = { - 550, /* max BB gain in 10th of dB */ - 260, 260, 26, /* BB1, 26dB */ - 290, 550, 29, /* BB2, 29dB */ -}; - -static const u16 bb_ramp_pwm_normal[] = { - 500, /* max RF gain in 10th of dB */ - 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */ - 400, - (2 << 9) | 0, /* 0x35 = 21dB */ - (0 << 9) | 168, /* 0x36 */ - (2 << 9) | 168, /* 0x37 = 29dB */ - (0 << 9) | 400, /* 0x38 */ -}; - -struct slope { - s16 range; - s16 slope; -}; -static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val) -{ - u8 i; - u16 rest; - u16 ret = 0; - for (i = 0; i < num; i++) { - if (val > slopes[i].range) - rest = slopes[i].range; - else - rest = val; - ret += (rest * slopes[i].slope) / slopes[i].range; - val -= rest; - } - return ret; -} - -static const struct slope dib0090_wbd_slopes[3] = { - {66, 120}, /* -64,-52: offset - 65 */ - {600, 170}, /* -52,-35: 65 - 665 */ - {170, 250}, /* -45,-10: 665 - 835 */ -}; - -static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd) -{ - wbd &= 0x3ff; - if (wbd < state->wbd_offset) - wbd = 0; - else - wbd -= state->wbd_offset; - /* -64dB is the floor */ - return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd); -} - -static void dib0090_wbd_target(struct dib0090_state *state, u32 rf) -{ - u16 offset = 250; - - /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */ - - if (state->current_band == BAND_VHF) - offset = 650; -#ifndef FIRMWARE_FIREFLY - if (state->current_band == BAND_VHF) - offset = state->config->wbd_vhf_offset; - if (state->current_band == BAND_CBAND) - offset = state->config->wbd_cband_offset; -#endif - - state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset); - dprintk("wbd-target: %d dB", (u32) state->wbd_target); -} - -static const int gain_reg_addr[4] = { - 0x08, 0x0a, 0x0f, 0x01 -}; - -static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force) -{ - u16 rf, bb, ref; - u16 i, v, gain_reg[4] = { 0 }, gain; - const u16 *g; - - if (top_delta < -511) - top_delta = -511; - if (top_delta > 511) - top_delta = 511; - - if (force) { - top_delta *= (1 << WBD_ALPHA); - gain_delta *= (1 << GAIN_ALPHA); - } - - if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */ - state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; - else - state->rf_gain_limit += top_delta; - - if (state->rf_gain_limit < 0) /*underflow */ - state->rf_gain_limit = 0; - - /* use gain as a temporary variable and correct current_gain */ - gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA; - if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */ - state->current_gain = gain; - else - state->current_gain += gain_delta; - /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */ - if (state->current_gain < 0) - state->current_gain = 0; - - /* now split total gain to rf and bb gain */ - gain = state->current_gain >> GAIN_ALPHA; - - /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */ - if (gain > (state->rf_gain_limit >> WBD_ALPHA)) { - rf = state->rf_gain_limit >> WBD_ALPHA; - bb = gain - rf; - if (bb > state->bb_ramp[0]) - bb = state->bb_ramp[0]; - } else { /* high signal level -> all gains put on RF */ - rf = gain; - bb = 0; - } - - state->gain[0] = rf; - state->gain[1] = bb; - - /* software ramp */ - /* Start with RF gains */ - g = state->rf_ramp + 1; /* point on RF LNA1 max gain */ - ref = rf; - for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */ - if (g[0] == 0 || ref < (g[1] - g[0])) /* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */ - v = 0; /* force the gain to write for the current amp to be null */ - else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */ - v = g[2]; /* force this amp to be full gain */ - else /* compute the value to set to this amp because we are somewhere in his range */ - v = ((ref - (g[1] - g[0])) * g[2]) / g[0]; - - if (i == 0) /* LNA 1 reg mapping */ - gain_reg[0] = v; - else if (i == 1) /* LNA 2 reg mapping */ - gain_reg[0] |= v << 7; - else if (i == 2) /* LNA 3 reg mapping */ - gain_reg[1] = v; - else if (i == 3) /* LNA 4 reg mapping */ - gain_reg[1] |= v << 7; - else if (i == 4) /* CBAND LNA reg mapping */ - gain_reg[2] = v | state->rf_lt_def; - else if (i == 5) /* BB gain 1 reg mapping */ - gain_reg[3] = v << 3; - else if (i == 6) /* BB gain 2 reg mapping */ - gain_reg[3] |= v << 8; - - g += 3; /* go to next gain bloc */ - - /* When RF is finished, start with BB */ - if (i == 4) { - g = state->bb_ramp + 1; /* point on BB gain 1 max gain */ - ref = bb; - } - } - gain_reg[3] |= state->bb_1_def; - gain_reg[3] |= ((bb % 10) * 100) / 125; - -#ifdef DEBUG_AGC - dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb, - gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]); -#endif - - /* Write the amplifier regs */ - for (i = 0; i < 4; i++) { - v = gain_reg[i]; - if (force || state->gain_reg[i] != v) { - state->gain_reg[i] = v; - dib0090_write_reg(state, gain_reg_addr[i], v); - } - } -} - -static void dib0090_set_boost(struct dib0090_state *state, int onoff) -{ - state->bb_1_def &= 0xdfff; - state->bb_1_def |= onoff << 13; -} - -static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg) -{ - state->rf_ramp = cfg; -} - -static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg) -{ - state->rf_ramp = cfg; - - dib0090_write_reg(state, 0x2a, 0xffff); - - dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a)); - - dib0090_write_regs(state, 0x2c, cfg + 3, 6); - dib0090_write_regs(state, 0x3e, cfg + 9, 2); -} - -static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg) -{ - state->bb_ramp = cfg; - dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ -} - -static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg) -{ - state->bb_ramp = cfg; - - dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ - - dib0090_write_reg(state, 0x33, 0xffff); - dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33)); - dib0090_write_regs(state, 0x35, cfg + 3, 4); -} - -void dib0090_pwm_gain_reset(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - /* reset the AGC */ - - if (state->config->use_pwm_agc) { -#ifdef CONFIG_BAND_SBAND - if (state->current_band == BAND_SBAND) { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost); - } else -#endif -#ifdef CONFIG_BAND_CBAND - if (state->current_band == BAND_CBAND) { - if (state->identity.in_soc) { - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); - if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090); - else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090); - } else { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); - } - } else -#endif -#ifdef CONFIG_BAND_VHF - if (state->current_band == BAND_VHF) { - if (state->identity.in_soc) { - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); - } else { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); - } - } else -#endif - { - if (state->identity.in_soc) { - if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090); - else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); - } else { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); - } - } - - if (state->rf_ramp[0] != 0) - dib0090_write_reg(state, 0x32, (3 << 11)); - else - dib0090_write_reg(state, 0x32, (0 << 11)); - - dib0090_write_reg(state, 0x04, 0x01); - dib0090_write_reg(state, 0x39, (1 << 10)); - } -} - -EXPORT_SYMBOL(dib0090_pwm_gain_reset); - -static u32 dib0090_get_slow_adc_val(struct dib0090_state *state) -{ - u16 adc_val = dib0090_read_reg(state, 0x1d); - if (state->identity.in_soc) - adc_val >>= 2; - return adc_val; -} - -int dib0090_gain_control(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - enum frontend_tune_state *tune_state = &state->tune_state; - int ret = 10; - - u16 wbd_val = 0; - u8 apply_gain_immediatly = 1; - s16 wbd_error = 0, adc_error = 0; - - if (*tune_state == CT_AGC_START) { - state->agc_freeze = 0; - dib0090_write_reg(state, 0x04, 0x0); - -#ifdef CONFIG_BAND_SBAND - if (state->current_band == BAND_SBAND) { - dib0090_set_rframp(state, rf_ramp_sband); - dib0090_set_bbramp(state, bb_ramp_boost); - } else -#endif -#ifdef CONFIG_BAND_VHF - if (state->current_band == BAND_VHF && !state->identity.p1g) { - dib0090_set_rframp(state, rf_ramp_vhf); - dib0090_set_bbramp(state, bb_ramp_boost); - } else -#endif -#ifdef CONFIG_BAND_CBAND - if (state->current_band == BAND_CBAND && !state->identity.p1g) { - dib0090_set_rframp(state, rf_ramp_cband); - dib0090_set_bbramp(state, bb_ramp_boost); - } else -#endif - if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) { - dib0090_set_rframp(state, rf_ramp_cband_broadmatching); - dib0090_set_bbramp(state, bb_ramp_boost); - } else { - dib0090_set_rframp(state, rf_ramp_uhf); - dib0090_set_bbramp(state, bb_ramp_boost); - } - - dib0090_write_reg(state, 0x32, 0); - dib0090_write_reg(state, 0x39, 0); - - dib0090_wbd_target(state, state->current_rf); - - state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; - state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA; - - *tune_state = CT_AGC_STEP_0; - } else if (!state->agc_freeze) { - s16 wbd = 0, i, cnt; - - int adc; - wbd_val = dib0090_get_slow_adc_val(state); - - if (*tune_state == CT_AGC_STEP_0) - cnt = 5; - else - cnt = 1; - - for (i = 0; i < cnt; i++) { - wbd_val = dib0090_get_slow_adc_val(state); - wbd += dib0090_wbd_to_db(state, wbd_val); - } - wbd /= cnt; - wbd_error = state->wbd_target - wbd; - - if (*tune_state == CT_AGC_STEP_0) { - if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) { -#ifdef CONFIG_BAND_CBAND - /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */ - u8 ltg2 = (state->rf_lt_def >> 10) & 0x7; - if (state->current_band == BAND_CBAND && ltg2) { - ltg2 >>= 1; - state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */ - } -#endif - } else { - state->agc_step = 0; - *tune_state = CT_AGC_STEP_1; - } - } else { - /* calc the adc power */ - adc = state->config->get_adc_power(fe); - adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */ - - adc_error = (s16) (((s32) ADC_TARGET) - adc); -#ifdef CONFIG_STANDARD_DAB - if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) - adc_error -= 10; -#endif -#ifdef CONFIG_STANDARD_DVBT - if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT && - (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16)) - adc_error += 60; -#endif -#ifdef CONFIG_SYS_ISDBT - if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count > - 0) - && - ((state->fe->dtv_property_cache.layer[0].modulation == - QAM_64) - || (state->fe->dtv_property_cache. - layer[0].modulation == QAM_16))) - || - ((state->fe->dtv_property_cache.layer[1].segment_count > - 0) - && - ((state->fe->dtv_property_cache.layer[1].modulation == - QAM_64) - || (state->fe->dtv_property_cache. - layer[1].modulation == QAM_16))) - || - ((state->fe->dtv_property_cache.layer[2].segment_count > - 0) - && - ((state->fe->dtv_property_cache.layer[2].modulation == - QAM_64) - || (state->fe->dtv_property_cache. - layer[2].modulation == QAM_16))) - ) - ) - adc_error += 60; -#endif - - if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */ - if (ABS(adc_error) < 50 || state->agc_step++ > 5) { - -#ifdef CONFIG_STANDARD_DAB - if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) { - dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */ - dib0090_write_reg(state, 0x04, 0x0); - } else -#endif - { - dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32)); - dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */ - } - - *tune_state = CT_AGC_STOP; - } - } else { - /* everything higher than or equal to CT_AGC_STOP means tracking */ - ret = 100; /* 10ms interval */ - apply_gain_immediatly = 0; - } - } -#ifdef DEBUG_AGC - dprintk - ("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm", - (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, - (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA)); -#endif - } - - /* apply gain */ - if (!state->agc_freeze) - dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly); - return ret; -} - -EXPORT_SYMBOL(dib0090_gain_control); - -void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) -{ - struct dib0090_state *state = fe->tuner_priv; - if (rf) - *rf = state->gain[0]; - if (bb) - *bb = state->gain[1]; - if (rf_gain_limit) - *rf_gain_limit = state->rf_gain_limit; - if (rflt) - *rflt = (state->rf_lt_def >> 10) & 0x7; -} - -EXPORT_SYMBOL(dib0090_get_current_gain); - -u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000; - s32 current_temp = state->temperature; - s32 wbd_thot, wbd_tcold; - const struct dib0090_wbd_slope *wbd = state->current_wbd_table; - - while (f_MHz > wbd->max_freq) - wbd++; - - dprintk("using wbd-table-entry with max freq %d", wbd->max_freq); - - if (current_temp < 0) - current_temp = 0; - if (current_temp > 128) - current_temp = 128; - - state->wbdmux &= ~(7 << 13); - if (wbd->wbd_gain != 0) - state->wbdmux |= (wbd->wbd_gain << 13); - else - state->wbdmux |= (4 << 13); - - dib0090_write_reg(state, 0x10, state->wbdmux); - - wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6); - wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6); - - wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7; - - state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold); - dprintk("wbd-target: %d dB", (u32) state->wbd_target); - dprintk("wbd offset applied is %d", wbd_tcold); - - return state->wbd_offset + wbd_tcold; -} - -EXPORT_SYMBOL(dib0090_get_wbd_offset); - -static const u16 dib0090_defaults[] = { - - 25, 0x01, - 0x0000, - 0x99a0, - 0x6008, - 0x0000, - 0x8bcb, - 0x0000, - 0x0405, - 0x0000, - 0x0000, - 0x0000, - 0xb802, - 0x0300, - 0x2d12, - 0xbac0, - 0x7c00, - 0xdbb9, - 0x0954, - 0x0743, - 0x8000, - 0x0001, - 0x0040, - 0x0100, - 0x0000, - 0xe910, - 0x149e, - - 1, 0x1c, - 0xff2d, - - 1, 0x39, - 0x0000, - - 2, 0x1e, - 0x07FF, - 0x0007, - - 1, 0x24, - EN_UHF | EN_CRYSTAL, - - 2, 0x3c, - 0x3ff, - 0x111, - 0 -}; - -static const u16 dib0090_p1g_additionnal_defaults[] = { - 1, 0x05, - 0xabcd, - - 1, 0x11, - 0x00b4, - - 1, 0x1c, - 0xfffd, - - 1, 0x40, - 0x108, - 0 -}; - -static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n) -{ - u16 l, r; - - l = pgm_read_word(n++); - while (l) { - r = pgm_read_word(n++); - do { - dib0090_write_reg(state, r, pgm_read_word(n++)); - r++; - } while (--l); - l = pgm_read_word(n++); - } -} - -#define CAP_VALUE_MIN (u8) 9 -#define CAP_VALUE_MAX (u8) 40 -#define HR_MIN (u8) 25 -#define HR_MAX (u8) 40 -#define POLY_MIN (u8) 0 -#define POLY_MAX (u8) 8 - -void dib0090_set_EFUSE(struct dib0090_state *state) -{ - u8 c, h, n; - u16 e2, e4; - u16 cal; - - e2 = dib0090_read_reg(state, 0x26); - e4 = dib0090_read_reg(state, 0x28); - - if ((state->identity.version == P1D_E_F) || - (state->identity.version == P1G) || (e2 == 0xffff)) { - - dib0090_write_reg(state, 0x22, 0x10); - cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff; - - if ((cal < 670) || (cal == 1023)) - cal = 850; - n = 165 - ((cal * 10)>>6) ; - e2 = e4 = (3<<12) | (34<<6) | (n); - } - - if (e2 != e4) - e2 &= e4; /* Remove the redundancy */ - - if (e2 != 0xffff) { - c = e2 & 0x3f; - n = (e2 >> 12) & 0xf; - h = (e2 >> 6) & 0x3f; - - if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN)) - c = 32; - if ((h >= HR_MAX) || (h <= HR_MIN)) - h = 34; - if ((n >= POLY_MAX) || (n <= POLY_MIN)) - n = 3; - - dib0090_write_reg(state, 0x13, (h << 10)) ; - e2 = (n<<11) | ((h>>2)<<6) | (c); - dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */ - } -} - -static int dib0090_reset(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - - dib0090_reset_digital(fe, state->config); - if (dib0090_identify(fe) < 0) - return -EIO; - -#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT - if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */ - return 0; -#endif - - if (!state->identity.in_soc) { - if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2) - dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL)); - else - dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL)); - } - - dib0090_set_default_config(state, dib0090_defaults); - - if (state->identity.in_soc) - dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */ - - if (state->identity.p1g) - dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults); - - /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/ - if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc)) - dib0090_set_EFUSE(state); - - /* Congigure in function of the crystal */ - if (state->config->io.clock_khz >= 24000) - dib0090_write_reg(state, 0x14, 1); - else - dib0090_write_reg(state, 0x14, 2); - dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1); - - state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL; /* enable iq-offset-calibration and wbd-calibration when tuning next time */ - - return 0; -} - -#define steps(u) (((u) > 15) ? ((u)-16) : (u)) -#define INTERN_WAIT 10 -static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state) -{ - int ret = INTERN_WAIT * 10; - - switch (*tune_state) { - case CT_TUNER_STEP_2: - /* Turns to positive */ - dib0090_write_reg(state, 0x1f, 0x7); - *tune_state = CT_TUNER_STEP_3; - break; - - case CT_TUNER_STEP_3: - state->adc_diff = dib0090_read_reg(state, 0x1d); - - /* Turns to negative */ - dib0090_write_reg(state, 0x1f, 0x4); - *tune_state = CT_TUNER_STEP_4; - break; - - case CT_TUNER_STEP_4: - state->adc_diff -= dib0090_read_reg(state, 0x1d); - *tune_state = CT_TUNER_STEP_5; - ret = 0; - break; - - default: - break; - } - - return ret; -} - -struct dc_calibration { - u8 addr; - u8 offset; - u8 pga:1; - u16 bb1; - u8 i:1; -}; - -static const struct dc_calibration dc_table[] = { - /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ - {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1}, - {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0}, - /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ - {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1}, - {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0}, - {0}, -}; - -static const struct dc_calibration dc_p1g_table[] = { - /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ - /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */ - {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1}, - {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0}, - /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ - {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1}, - {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0}, - {0}, -}; - -static void dib0090_set_trim(struct dib0090_state *state) -{ - u16 *val; - - if (state->dc->addr == 0x07) - val = &state->bb7; - else - val = &state->bb6; - - *val &= ~(0x1f << state->dc->offset); - *val |= state->step << state->dc->offset; - - dib0090_write_reg(state, state->dc->addr, *val); -} - -static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) -{ - int ret = 0; - u16 reg; - - switch (*tune_state) { - case CT_TUNER_START: - dprintk("Start DC offset calibration"); - - /* force vcm2 = 0.8V */ - state->bb6 = 0; - state->bb7 = 0x040d; - - /* the LNA AND LO are off */ - reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */ - dib0090_write_reg(state, 0x24, reg); - - state->wbdmux = dib0090_read_reg(state, 0x10); - dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3); - dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); - - state->dc = dc_table; - - if (state->identity.p1g) - state->dc = dc_p1g_table; - *tune_state = CT_TUNER_STEP_0; - - /* fall through */ - - case CT_TUNER_STEP_0: - dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q"); - dib0090_write_reg(state, 0x01, state->dc->bb1); - dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7)); - - state->step = 0; - state->min_adc_diff = 1023; - *tune_state = CT_TUNER_STEP_1; - ret = 50; - break; - - case CT_TUNER_STEP_1: - dib0090_set_trim(state); - *tune_state = CT_TUNER_STEP_2; - break; - - case CT_TUNER_STEP_2: - case CT_TUNER_STEP_3: - case CT_TUNER_STEP_4: - ret = dib0090_get_offset(state, tune_state); - break; - - case CT_TUNER_STEP_5: /* found an offset */ - dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step); - if (state->step == 0 && state->adc_diff < 0) { - state->min_adc_diff = -1023; - dprintk("Change of sign of the minimum adc diff"); - } - - dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step); - - /* first turn for this frequency */ - if (state->step == 0) { - if (state->dc->pga && state->adc_diff < 0) - state->step = 0x10; - if (state->dc->pga == 0 && state->adc_diff > 0) - state->step = 0x10; - } - - /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */ - if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) { - /* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */ - state->step++; - state->min_adc_diff = state->adc_diff; - *tune_state = CT_TUNER_STEP_1; - } else { - /* the minimum was what we have seen in the step before */ - if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) { - dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff); - state->step--; - } - - dib0090_set_trim(state); - dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step); - - state->dc++; - if (state->dc->addr == 0) /* done */ - *tune_state = CT_TUNER_STEP_6; - else - *tune_state = CT_TUNER_STEP_0; - - } - break; - - case CT_TUNER_STEP_6: - dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); - dib0090_write_reg(state, 0x1f, 0x7); - *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ - state->calibrate &= ~DC_CAL; - default: - break; - } - return ret; -} - -static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) -{ - u8 wbd_gain; - const struct dib0090_wbd_slope *wbd = state->current_wbd_table; - - switch (*tune_state) { - case CT_TUNER_START: - while (state->current_rf / 1000 > wbd->max_freq) - wbd++; - if (wbd->wbd_gain != 0) - wbd_gain = wbd->wbd_gain; - else { - wbd_gain = 4; -#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND) - if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) - wbd_gain = 2; -#endif - } - - if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */ - *tune_state = CT_TUNER_START; - state->calibrate &= ~WBD_CAL; - return 0; - } - - dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3)); - - dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1))); - *tune_state = CT_TUNER_STEP_0; - state->wbd_calibration_gain = wbd_gain; - return 90; /* wait for the WBDMUX to switch and for the ADC to sample */ - - case CT_TUNER_STEP_0: - state->wbd_offset = dib0090_get_slow_adc_val(state); - dprintk("WBD calibration offset = %d", state->wbd_offset); - *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ - state->calibrate &= ~WBD_CAL; - break; - - default: - break; - } - return 0; -} - -static void dib0090_set_bandwidth(struct dib0090_state *state) -{ - u16 tmp; - - if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000) - tmp = (3 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000) - tmp = (2 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000) - tmp = (1 << 14); - else - tmp = (0 << 14); - - state->bb_1_def &= 0x3fff; - state->bb_1_def |= tmp; - - dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */ - - dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */ - dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */ - if (state->identity.in_soc) { - dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */ - } else { - dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */ - dib0090_write_reg(state, 0x05, 0xabcd); /* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */ - } -} - -static const struct dib0090_pll dib0090_pll_table[] = { -#ifdef CONFIG_BAND_CBAND - {56000, 0, 9, 48, 6}, - {70000, 1, 9, 48, 6}, - {87000, 0, 8, 32, 4}, - {105000, 1, 8, 32, 4}, - {115000, 0, 7, 24, 6}, - {140000, 1, 7, 24, 6}, - {170000, 0, 6, 16, 4}, -#endif -#ifdef CONFIG_BAND_VHF - {200000, 1, 6, 16, 4}, - {230000, 0, 5, 12, 6}, - {280000, 1, 5, 12, 6}, - {340000, 0, 4, 8, 4}, - {380000, 1, 4, 8, 4}, - {450000, 0, 3, 6, 6}, -#endif -#ifdef CONFIG_BAND_UHF - {580000, 1, 3, 6, 6}, - {700000, 0, 2, 4, 4}, - {860000, 1, 2, 4, 4}, -#endif -#ifdef CONFIG_BAND_LBAND - {1800000, 1, 0, 2, 4}, -#endif -#ifdef CONFIG_BAND_SBAND - {2900000, 0, 14, 1, 4}, -#endif -}; - -static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = { - -#ifdef CONFIG_BAND_CBAND - {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, - {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, - {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, -#endif -#ifdef CONFIG_BAND_UHF - {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, -#endif -#ifdef CONFIG_BAND_LBAND - {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, - {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, - {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, -#endif -#ifdef CONFIG_BAND_SBAND - {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, - {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, -#endif -}; - -static const struct dib0090_tuning dib0090_tuning_table[] = { - -#ifdef CONFIG_BAND_CBAND - {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, -#endif -#ifdef CONFIG_BAND_VHF - {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, - {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, - {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, -#endif -#ifdef CONFIG_BAND_UHF - {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, -#endif -#ifdef CONFIG_BAND_LBAND - {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, - {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, - {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, -#endif -#ifdef CONFIG_BAND_SBAND - {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, - {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, -#endif -}; - -static const struct dib0090_tuning dib0090_p1g_tuning_table[] = { -#ifdef CONFIG_BAND_CBAND - {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB}, -#endif -#ifdef CONFIG_BAND_VHF - {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, - {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, - {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, -#endif -#ifdef CONFIG_BAND_UHF - {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, -#endif -#ifdef CONFIG_BAND_LBAND - {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, - {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, - {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, -#endif -#ifdef CONFIG_BAND_SBAND - {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, - {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, -#endif -}; - -static const struct dib0090_pll dib0090_p1g_pll_table[] = { -#ifdef CONFIG_BAND_CBAND - {57000, 0, 11, 48, 6}, - {70000, 1, 11, 48, 6}, - {86000, 0, 10, 32, 4}, - {105000, 1, 10, 32, 4}, - {115000, 0, 9, 24, 6}, - {140000, 1, 9, 24, 6}, - {170000, 0, 8, 16, 4}, -#endif -#ifdef CONFIG_BAND_VHF - {200000, 1, 8, 16, 4}, - {230000, 0, 7, 12, 6}, - {280000, 1, 7, 12, 6}, - {340000, 0, 6, 8, 4}, - {380000, 1, 6, 8, 4}, - {455000, 0, 5, 6, 6}, -#endif -#ifdef CONFIG_BAND_UHF - {580000, 1, 5, 6, 6}, - {680000, 0, 4, 4, 4}, - {860000, 1, 4, 4, 4}, -#endif -#ifdef CONFIG_BAND_LBAND - {1800000, 1, 2, 2, 4}, -#endif -#ifdef CONFIG_BAND_SBAND - {2900000, 0, 1, 1, 6}, -#endif -}; - -static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = { -#ifdef CONFIG_BAND_CBAND - {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, - {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, - {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, -#endif -#ifdef CONFIG_BAND_UHF - {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, - {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, -#endif -#ifdef CONFIG_BAND_LBAND - {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, - {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, - {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, -#endif -#ifdef CONFIG_BAND_SBAND - {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, - {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, -#endif -}; - -static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = { -#ifdef CONFIG_BAND_CBAND - {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, - {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, - {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, - {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, -#endif -}; - -static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state) -{ - int ret = 0; - u16 lo4 = 0xe900; - - s16 adc_target; - u16 adc; - s8 step_sign; - u8 force_soft_search = 0; - - if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) - force_soft_search = 1; - - if (*tune_state == CT_TUNER_START) { - dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO"); - dib0090_write_reg(state, 0x10, 0x2B1); - dib0090_write_reg(state, 0x1e, 0x0032); - - if (!state->tuner_is_tuned) { - /* prepare a complete captrim */ - if (!state->identity.p1g || force_soft_search) - state->step = state->captrim = state->fcaptrim = 64; - - state->current_rf = state->rf_request; - } else { /* we are already tuned to this frequency - the configuration is correct */ - if (!state->identity.p1g || force_soft_search) { - /* do a minimal captrim even if the frequency has not changed */ - state->step = 4; - state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f; - } - } - state->adc_diff = 3000; - *tune_state = CT_TUNER_STEP_0; - - } else if (*tune_state == CT_TUNER_STEP_0) { - if (state->identity.p1g && !force_soft_search) { - u8 ratio = 31; - - dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1); - dib0090_read_reg(state, 0x40); - ret = 50; - } else { - state->step /= 2; - dib0090_write_reg(state, 0x18, lo4 | state->captrim); - - if (state->identity.in_soc) - ret = 25; - } - *tune_state = CT_TUNER_STEP_1; - - } else if (*tune_state == CT_TUNER_STEP_1) { - if (state->identity.p1g && !force_soft_search) { - dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0); - dib0090_read_reg(state, 0x40); - - state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F; - dprintk("***Final Captrim= 0x%x", state->fcaptrim); - *tune_state = CT_TUNER_STEP_3; - - } else { - /* MERGE for all krosus before P1G */ - adc = dib0090_get_slow_adc_val(state); - dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024); - - if (state->rest == 0 || state->identity.in_soc) { /* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */ - adc_target = 200; - } else - adc_target = 400; - - if (adc >= adc_target) { - adc -= adc_target; - step_sign = -1; - } else { - adc = adc_target - adc; - step_sign = 1; - } - - if (adc < state->adc_diff) { - dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff); - state->adc_diff = adc; - state->fcaptrim = state->captrim; - } - - state->captrim += step_sign * state->step; - if (state->step >= 1) - *tune_state = CT_TUNER_STEP_0; - else - *tune_state = CT_TUNER_STEP_2; - - ret = 25; - } - } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */ - /*write the final cptrim config */ - dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim); - - *tune_state = CT_TUNER_STEP_3; - - } else if (*tune_state == CT_TUNER_STEP_3) { - state->calibrate &= ~CAPTRIM_CAL; - *tune_state = CT_TUNER_STEP_0; - } - - return ret; -} - -static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state) -{ - int ret = 15; - s16 val; - - switch (*tune_state) { - case CT_TUNER_START: - state->wbdmux = dib0090_read_reg(state, 0x10); - dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3)); - - state->bias = dib0090_read_reg(state, 0x13); - dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8)); - - *tune_state = CT_TUNER_STEP_0; - /* wait for the WBDMUX to switch and for the ADC to sample */ - break; - - case CT_TUNER_STEP_0: - state->adc_diff = dib0090_get_slow_adc_val(state); - dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8)); - *tune_state = CT_TUNER_STEP_1; - break; - - case CT_TUNER_STEP_1: - val = dib0090_get_slow_adc_val(state); - state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55; - - dprintk("temperature: %d C", state->temperature - 30); - - *tune_state = CT_TUNER_STEP_2; - break; - - case CT_TUNER_STEP_2: - dib0090_write_reg(state, 0x13, state->bias); - dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */ - - *tune_state = CT_TUNER_START; - state->calibrate &= ~TEMP_CAL; - if (state->config->analog_output == 0) - dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); - - break; - - default: - ret = 0; - break; - } - return ret; -} - -#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ -static int dib0090_tune(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - const struct dib0090_tuning *tune = state->current_tune_table_index; - const struct dib0090_pll *pll = state->current_pll_table_index; - enum frontend_tune_state *tune_state = &state->tune_state; - - u16 lo5, lo6, Den, tmp; - u32 FBDiv, Rest, FREF, VCOF_kHz = 0; - int ret = 10; /* 1ms is the default delay most of the time */ - u8 c, i; - - /************************* VCO ***************************/ - /* Default values for FG */ - /* from these are needed : */ - /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */ - - /* in any case we first need to do a calibration if needed */ - if (*tune_state == CT_TUNER_START) { - /* deactivate DataTX before some calibrations */ - if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL)) - dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); - else - /* Activate DataTX in case a calibration has been done before */ - if (state->config->analog_output == 0) - dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); - } - - if (state->calibrate & DC_CAL) - return dib0090_dc_offset_calibration(state, tune_state); - else if (state->calibrate & WBD_CAL) { - if (state->current_rf == 0) - state->current_rf = state->fe->dtv_property_cache.frequency / 1000; - return dib0090_wbd_calibration(state, tune_state); - } else if (state->calibrate & TEMP_CAL) - return dib0090_get_temperature(state, tune_state); - else if (state->calibrate & CAPTRIM_CAL) - return dib0090_captrim_search(state, tune_state); - - if (*tune_state == CT_TUNER_START) { - /* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */ - if (state->config->use_pwm_agc && state->identity.in_soc) { - tmp = dib0090_read_reg(state, 0x39); - if ((tmp >> 10) & 0x1) - dib0090_write_reg(state, 0x39, tmp & ~(1 << 10)); - } - - state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000); - state->rf_request = - state->fe->dtv_property_cache.frequency / 1000 + (state->current_band == - BAND_UHF ? state->config->freq_offset_khz_uhf : state->config-> - freq_offset_khz_vhf); - - /* in ISDB-T 1seg we shift tuning frequency */ - if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1 - && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) { - const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if; - u8 found_offset = 0; - u32 margin_khz = 100; - - if (LUT_offset != NULL) { - while (LUT_offset->RF_freq != 0xffff) { - if (((state->rf_request > (LUT_offset->RF_freq - margin_khz)) - && (state->rf_request < (LUT_offset->RF_freq + margin_khz))) - && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) { - state->rf_request += LUT_offset->offset_khz; - found_offset = 1; - break; - } - LUT_offset++; - } - } - - if (found_offset == 0) - state->rf_request += 400; - } - if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) { - state->tuner_is_tuned = 0; - state->current_rf = 0; - state->current_standard = 0; - - tune = dib0090_tuning_table; - if (state->identity.p1g) - tune = dib0090_p1g_tuning_table; - - tmp = (state->identity.version >> 5) & 0x7; - - if (state->identity.in_soc) { - if (state->config->force_cband_input) { /* Use the CBAND input for all band */ - if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF - || state->current_band & BAND_UHF) { - state->current_band = BAND_CBAND; - tune = dib0090_tuning_table_cband_7090; - } - } else { /* Use the CBAND input for all band under UHF */ - if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) { - state->current_band = BAND_CBAND; - tune = dib0090_tuning_table_cband_7090; - } - } - } else - if (tmp == 0x4 || tmp == 0x7) { - /* CBAND tuner version for VHF */ - if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) { - state->current_band = BAND_CBAND; /* Force CBAND */ - - tune = dib0090_tuning_table_fm_vhf_on_cband; - if (state->identity.p1g) - tune = dib0090_p1g_tuning_table_fm_vhf_on_cband; - } - } - - pll = dib0090_pll_table; - if (state->identity.p1g) - pll = dib0090_p1g_pll_table; - - /* Look for the interval */ - while (state->rf_request > tune->max_freq) - tune++; - while (state->rf_request > pll->max_freq) - pll++; - - state->current_tune_table_index = tune; - state->current_pll_table_index = pll; - - dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim)); - - VCOF_kHz = (pll->hfdiv * state->rf_request) * 2; - - FREF = state->config->io.clock_khz; - if (state->config->fref_clock_ratio != 0) - FREF /= state->config->fref_clock_ratio; - - FBDiv = (VCOF_kHz / pll->topresc / FREF); - Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; - - if (Rest < LPF) - Rest = 0; - else if (Rest < 2 * LPF) - Rest = 2 * LPF; - else if (Rest > (FREF - LPF)) { - Rest = 0; - FBDiv += 1; - } else if (Rest > (FREF - 2 * LPF)) - Rest = FREF - 2 * LPF; - Rest = (Rest * 6528) / (FREF / 10); - state->rest = Rest; - - /* external loop filter, otherwise: - * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4; - * lo6 = 0x0e34 */ - - if (Rest == 0) { - if (pll->vco_band) - lo5 = 0x049f; - else - lo5 = 0x041f; - } else { - if (pll->vco_band) - lo5 = 0x049e; - else if (state->config->analog_output) - lo5 = 0x041d; - else - lo5 = 0x041c; - } - - if (state->identity.p1g) { /* Bias is done automatically in P1G */ - if (state->identity.in_soc) { - if (state->identity.version == SOC_8090_P1G_11R1) - lo5 = 0x46f; - else - lo5 = 0x42f; - } else - lo5 = 0x42c; - } - - lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */ - - if (!state->config->io.pll_int_loop_filt) { - if (state->identity.in_soc) - lo6 = 0xff98; - else if (state->identity.p1g || (Rest == 0)) - lo6 = 0xfff8; - else - lo6 = 0xff28; - } else - lo6 = (state->config->io.pll_int_loop_filt << 3); - - Den = 1; - - if (Rest > 0) { - if (state->config->analog_output) - lo6 |= (1 << 2) | 2; - else { - if (state->identity.in_soc) - lo6 |= (1 << 2) | 2; - else - lo6 |= (1 << 2) | 2; - } - Den = 255; - } - dib0090_write_reg(state, 0x15, (u16) FBDiv); - if (state->config->fref_clock_ratio != 0) - dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio); - else - dib0090_write_reg(state, 0x16, (Den << 8) | 1); - dib0090_write_reg(state, 0x17, (u16) Rest); - dib0090_write_reg(state, 0x19, lo5); - dib0090_write_reg(state, 0x1c, lo6); - - lo6 = tune->tuner_enable; - if (state->config->analog_output) - lo6 = (lo6 & 0xff9f) | 0x2; - - dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL); - - } - - state->current_rf = state->rf_request; - state->current_standard = state->fe->dtv_property_cache.delivery_system; - - ret = 20; - state->calibrate = CAPTRIM_CAL; /* captrim serach now */ - } - - else if (*tune_state == CT_TUNER_STEP_0) { /* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */ - const struct dib0090_wbd_slope *wbd = state->current_wbd_table; - - while (state->current_rf / 1000 > wbd->max_freq) - wbd++; - - dib0090_write_reg(state, 0x1e, 0x07ff); - dprintk("Final Captrim: %d", (u32) state->fcaptrim); - dprintk("HFDIV code: %d", (u32) pll->hfdiv_code); - dprintk("VCO = %d", (u32) pll->vco_band); - dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request); - dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz); - dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); - dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8), - (u32) dib0090_read_reg(state, 0x1c) & 0x3); - -#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ - c = 4; - i = 3; - - if (wbd->wbd_gain != 0) - c = wbd->wbd_gain; - - state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1)); - dib0090_write_reg(state, 0x10, state->wbdmux); - - if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) { - dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune); - dib0090_write_reg(state, 0x09, tune->lna_bias); - dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim)); - } else - dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias); - - dib0090_write_reg(state, 0x0c, tune->v2i); - dib0090_write_reg(state, 0x0d, tune->mix); - dib0090_write_reg(state, 0x0e, tune->load); - *tune_state = CT_TUNER_STEP_1; - - } else if (*tune_state == CT_TUNER_STEP_1) { - /* initialize the lt gain register */ - state->rf_lt_def = 0x7c00; - - dib0090_set_bandwidth(state); - state->tuner_is_tuned = 1; - - state->calibrate |= WBD_CAL; - state->calibrate |= TEMP_CAL; - *tune_state = CT_TUNER_STOP; - } else - ret = FE_CALLBACK_TIME_NEVER; - return ret; -} - -static int dib0090_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - - return state->tune_state; -} - -EXPORT_SYMBOL(dib0090_get_tune_state); - -int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) -{ - struct dib0090_state *state = fe->tuner_priv; - - state->tune_state = tune_state; - return 0; -} - -EXPORT_SYMBOL(dib0090_set_tune_state); - -static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) -{ - struct dib0090_state *state = fe->tuner_priv; - - *frequency = 1000 * state->current_rf; - return 0; -} - -static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - struct dib0090_state *state = fe->tuner_priv; - u32 ret; - - state->tune_state = CT_TUNER_START; - - do { - ret = dib0090_tune(fe); - if (ret != FE_CALLBACK_TIME_NEVER) - msleep(ret / 10); - else - break; - } while (state->tune_state != CT_TUNER_STOP); - - return 0; -} - -static const struct dvb_tuner_ops dib0090_ops = { - .info = { - .name = "DiBcom DiB0090", - .frequency_min = 45000000, - .frequency_max = 860000000, - .frequency_step = 1000, - }, - .release = dib0090_release, - - .init = dib0090_wakeup, - .sleep = dib0090_sleep, - .set_params = dib0090_set_params, - .get_frequency = dib0090_get_frequency, -}; - -static const struct dvb_tuner_ops dib0090_fw_ops = { - .info = { - .name = "DiBcom DiB0090", - .frequency_min = 45000000, - .frequency_max = 860000000, - .frequency_step = 1000, - }, - .release = dib0090_release, - - .init = NULL, - .sleep = NULL, - .set_params = NULL, - .get_frequency = NULL, -}; - -static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = { - {470, 0, 250, 0, 100, 4}, - {860, 51, 866, 21, 375, 4}, - {1700, 0, 800, 0, 850, 4}, - {2900, 0, 250, 0, 100, 6}, - {0xFFFF, 0, 0, 0, 0, 0}, -}; - -struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) -{ - struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL); - if (st == NULL) - return NULL; - - st->config = config; - st->i2c = i2c; - st->fe = fe; - fe->tuner_priv = st; - - if (config->wbd == NULL) - st->current_wbd_table = dib0090_wbd_table_default; - else - st->current_wbd_table = config->wbd; - - if (dib0090_reset(fe) != 0) - goto free_mem; - - printk(KERN_INFO "DiB0090: successfully identified\n"); - memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops)); - - return fe; - free_mem: - kfree(st); - fe->tuner_priv = NULL; - return NULL; -} - -EXPORT_SYMBOL(dib0090_register); - -struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) -{ - struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL); - if (st == NULL) - return NULL; - - st->config = config; - st->i2c = i2c; - st->fe = fe; - fe->tuner_priv = st; - - if (dib0090_fw_reset_digital(fe, st->config) != 0) - goto free_mem; - - dprintk("DiB0090 FW: successfully identified"); - memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops)); - - return fe; -free_mem: - kfree(st); - fe->tuner_priv = NULL; - return NULL; -} -EXPORT_SYMBOL(dib0090_fw_register); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_AUTHOR("Olivier Grenie "); -MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0090.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0090.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0090.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib0090.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,139 +0,0 @@ -/* - * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. - * - * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) - * - * 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, version 2. - */ -#ifndef DIB0090_H -#define DIB0090_H - -struct dvb_frontend; -struct i2c_adapter; - -#define DEFAULT_DIB0090_I2C_ADDRESS 0x60 - -struct dib0090_io_config { - u32 clock_khz; - - u8 pll_bypass:1; - u8 pll_range:1; - u8 pll_prediv:6; - u8 pll_loopdiv:6; - - u8 adc_clock_ratio; /* valid is 8, 7 ,6 */ - u16 pll_int_loop_filt; -}; - -struct dib0090_wbd_slope { - u16 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u16 slope_cold; - u16 offset_cold; - u16 slope_hot; - u16 offset_hot; - u8 wbd_gain; -}; - -struct dib0090_low_if_offset_table { - int std; - u32 RF_freq; - s32 offset_khz; -}; - -struct dib0090_config { - struct dib0090_io_config io; - int (*reset) (struct dvb_frontend *, int); - int (*sleep) (struct dvb_frontend *, int); - - /* offset in kHz */ - int freq_offset_khz_uhf; - int freq_offset_khz_vhf; - - int (*get_adc_power) (struct dvb_frontend *); - - u8 clkouttobamse:1; /* activate or deactivate clock output */ - u8 analog_output; - - u8 i2c_address; - /* add drives and other things if necessary */ - u16 wbd_vhf_offset; - u16 wbd_cband_offset; - u8 use_pwm_agc; - u8 clkoutdrive; - - u8 ls_cfg_pad_drv; - u8 data_tx_drv; - - u8 in_soc; - const struct dib0090_low_if_offset_table *low_if; - u8 fref_clock_ratio; - u16 force_cband_input; - struct dib0090_wbd_slope *wbd; -}; - -#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE)) -extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); -extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); -extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); -extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe); -extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner); -extern int dib0090_gain_control(struct dvb_frontend *fe); -extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe); -extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); -extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt); -#else -static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -} - -static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -} - -static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} - -static inline int dib0090_gain_control(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return CT_DONE; -} - -static inline int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - * public header file of the frontend drivers for mobile DVB-T demodulators - * DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/) - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * based on GPL code from DibCom, which has - * - * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) - * - * 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, version 2. - * - * Acknowledgements - * - * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver - * sources, on which this driver (and the dvb-dibusb) are based. - * - * see Documentation/dvb/README.dibusb for more information - * - */ - -#ifndef DIB3000_H -#define DIB3000_H - -#include - -struct dib3000_config -{ - /* the demodulator's i2c address */ - u8 demod_address; -}; - -struct dib_fe_xfer_ops -{ - /* pid and transfer handling is done in the demodulator */ - int (*pid_parse)(struct dvb_frontend *fe, int onoff); - int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff); - int (*pid_ctrl)(struct dvb_frontend *fe, int index, int pid, int onoff); - int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl); -}; - -#if defined(CONFIG_DVB_DIB3000MB) || (defined(CONFIG_DVB_DIB3000MB_MODULE) && defined(MODULE)) -extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, - struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops); -#else -static inline struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, - struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_DIB3000MB - -#endif // DIB3000_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,834 +0,0 @@ -/* - * Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B - * DiBcom (http://www.dibcom.fr/) - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * based on GPL code from DibCom, which has - * - * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) - * - * 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, version 2. - * - * Acknowledgements - * - * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver - * sources, on which this driver (and the dvb-dibusb) are based. - * - * see Documentation/dvb/README.dibusb for more information - * - */ - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "dib3000.h" -#include "dib3000mb_priv.h" - -/* Version information */ -#define DRIVER_VERSION "0.1" -#define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator" -#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able))."); - -#define deb_info(args...) dprintk(0x01,args) -#define deb_i2c(args...) dprintk(0x02,args) -#define deb_srch(args...) dprintk(0x04,args) -#define deb_info(args...) dprintk(0x01,args) -#define deb_xfer(args...) dprintk(0x02,args) -#define deb_setf(args...) dprintk(0x04,args) -#define deb_getf(args...) dprintk(0x08,args) - -static int dib3000_read_reg(struct dib3000_state *state, u16 reg) -{ - u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff }; - u8 rb[2]; - struct i2c_msg msg[] = { - { .addr = state->config.demod_address, .flags = 0, .buf = wb, .len = 2 }, - { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 }, - }; - - if (i2c_transfer(state->i2c, msg, 2) != 2) - deb_i2c("i2c read error\n"); - - deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg, - (rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]); - - return (rb[0] << 8) | rb[1]; -} - -static int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val) -{ - u8 b[] = { - (reg >> 8) & 0xff, reg & 0xff, - (val >> 8) & 0xff, val & 0xff, - }; - struct i2c_msg msg[] = { - { .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 } - }; - deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val); - - return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0; -} - -static int dib3000_search_status(u16 irq,u16 lock) -{ - if (irq & 0x02) { - if (lock & 0x01) { - deb_srch("auto search succeeded\n"); - return 1; // auto search succeeded - } else { - deb_srch("auto search not successful\n"); - return 0; // auto search failed - } - } else if (irq & 0x01) { - deb_srch("auto search failed\n"); - return 0; // auto search failed - } - return -1; // try again -} - -/* for auto search */ -static u16 dib3000_seq[2][2][2] = /* fft,gua, inv */ - { /* fft */ - { /* gua */ - { 0, 1 }, /* 0 0 { 0,1 } */ - { 3, 9 }, /* 0 1 { 0,1 } */ - }, - { - { 2, 5 }, /* 1 0 { 0,1 } */ - { 6, 11 }, /* 1 1 { 0,1 } */ - } - }; - -static int dib3000mb_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep); - -static int dib3000mb_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep, int tuner) -{ - struct dib3000_state* state = fe->demodulator_priv; - struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; - fe_code_rate_t fe_cr = FEC_NONE; - int search_state, seq; - - if (tuner && fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fep); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - - deb_setf("bandwidth: "); - switch (ofdm->bandwidth) { - case BANDWIDTH_8_MHZ: - deb_setf("8 MHz\n"); - wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]); - wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz); - break; - case BANDWIDTH_7_MHZ: - deb_setf("7 MHz\n"); - wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]); - wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz); - break; - case BANDWIDTH_6_MHZ: - deb_setf("6 MHz\n"); - wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]); - wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz); - break; - case BANDWIDTH_AUTO: - return -EOPNOTSUPP; - default: - err("unknown bandwidth value."); - return -EINVAL; - } - } - wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4); - - deb_setf("transmission mode: "); - switch (ofdm->transmission_mode) { - case TRANSMISSION_MODE_2K: - deb_setf("2k\n"); - wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K); - break; - case TRANSMISSION_MODE_8K: - deb_setf("8k\n"); - wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_8K); - break; - case TRANSMISSION_MODE_AUTO: - deb_setf("auto\n"); - break; - default: - return -EINVAL; - } - - deb_setf("guard: "); - switch (ofdm->guard_interval) { - case GUARD_INTERVAL_1_32: - deb_setf("1_32\n"); - wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32); - break; - case GUARD_INTERVAL_1_16: - deb_setf("1_16\n"); - wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_16); - break; - case GUARD_INTERVAL_1_8: - deb_setf("1_8\n"); - wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_8); - break; - case GUARD_INTERVAL_1_4: - deb_setf("1_4\n"); - wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_4); - break; - case GUARD_INTERVAL_AUTO: - deb_setf("auto\n"); - break; - default: - return -EINVAL; - } - - deb_setf("inversion: "); - switch (fep->inversion) { - case INVERSION_OFF: - deb_setf("off\n"); - wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF); - break; - case INVERSION_AUTO: - deb_setf("auto "); - break; - case INVERSION_ON: - deb_setf("on\n"); - wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_ON); - break; - default: - return -EINVAL; - } - - deb_setf("constellation: "); - switch (ofdm->constellation) { - case QPSK: - deb_setf("qpsk\n"); - wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK); - break; - case QAM_16: - deb_setf("qam16\n"); - wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_16QAM); - break; - case QAM_64: - deb_setf("qam64\n"); - wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_64QAM); - break; - case QAM_AUTO: - break; - default: - return -EINVAL; - } - deb_setf("hierarchy: "); - switch (ofdm->hierarchy_information) { - case HIERARCHY_NONE: - deb_setf("none "); - /* fall through */ - case HIERARCHY_1: - deb_setf("alpha=1\n"); - wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1); - break; - case HIERARCHY_2: - deb_setf("alpha=2\n"); - wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_2); - break; - case HIERARCHY_4: - deb_setf("alpha=4\n"); - wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_4); - break; - case HIERARCHY_AUTO: - deb_setf("alpha=auto\n"); - break; - default: - return -EINVAL; - } - - deb_setf("hierarchy: "); - if (ofdm->hierarchy_information == HIERARCHY_NONE) { - deb_setf("none\n"); - wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF); - wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP); - fe_cr = ofdm->code_rate_HP; - } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { - deb_setf("on\n"); - wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON); - wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP); - fe_cr = ofdm->code_rate_LP; - } - deb_setf("fec: "); - switch (fe_cr) { - case FEC_1_2: - deb_setf("1_2\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_1_2); - break; - case FEC_2_3: - deb_setf("2_3\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_2_3); - break; - case FEC_3_4: - deb_setf("3_4\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_3_4); - break; - case FEC_5_6: - deb_setf("5_6\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_5_6); - break; - case FEC_7_8: - deb_setf("7_8\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_7_8); - break; - case FEC_NONE: - deb_setf("none "); - break; - case FEC_AUTO: - deb_setf("auto\n"); - break; - default: - return -EINVAL; - } - - seq = dib3000_seq - [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO] - [ofdm->guard_interval == GUARD_INTERVAL_AUTO] - [fep->inversion == INVERSION_AUTO]; - - deb_setf("seq? %d\n", seq); - - wr(DIB3000MB_REG_SEQ, seq); - - wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE); - - if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) { - if (ofdm->guard_interval == GUARD_INTERVAL_1_8) { - wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8); - } else { - wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT); - } - - wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_2K); - } else { - wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_DEFAULT); - } - - wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_OFF); - wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF); - wr(DIB3000MB_REG_MOBILE_MODE, DIB3000MB_MOBILE_MODE_OFF); - - wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_high); - - wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_ACTIVATE); - - wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC + DIB3000MB_RESTART_CTRL); - wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF); - - /* wait for AGC lock */ - msleep(70); - - wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low); - - /* something has to be auto searched */ - if (ofdm->constellation == QAM_AUTO || - ofdm->hierarchy_information == HIERARCHY_AUTO || - fe_cr == FEC_AUTO || - fep->inversion == INVERSION_AUTO) { - int as_count=0; - - deb_setf("autosearch enabled.\n"); - - wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT); - - wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AUTO_SEARCH); - wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF); - - while ((search_state = - dib3000_search_status( - rd(DIB3000MB_REG_AS_IRQ_PENDING), - rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100) - msleep(1); - - deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count); - - if (search_state == 1) { - struct dvb_frontend_parameters feps; - if (dib3000mb_get_frontend(fe, &feps) == 0) { - deb_setf("reading tuning data from frontend succeeded.\n"); - return dib3000mb_set_frontend(fe, &feps, 0); - } - } - - } else { - wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_CTRL); - wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF); - } - - return 0; -} - -static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) -{ - struct dib3000_state* state = fe->demodulator_priv; - - deb_info("dib3000mb is getting up.\n"); - wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_UP); - - wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC); - - wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE); - wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE_RST); - - wr(DIB3000MB_REG_CLOCK, DIB3000MB_CLOCK_DEFAULT); - - wr(DIB3000MB_REG_ELECT_OUT_MODE, DIB3000MB_ELECT_OUT_MODE_ON); - - wr(DIB3000MB_REG_DDS_FREQ_MSB, DIB3000MB_DDS_FREQ_MSB); - wr(DIB3000MB_REG_DDS_FREQ_LSB, DIB3000MB_DDS_FREQ_LSB); - - wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]); - - wr_foreach(dib3000mb_reg_impulse_noise, - dib3000mb_impulse_noise_values[DIB3000MB_IMPNOISE_OFF]); - - wr_foreach(dib3000mb_reg_agc_gain, dib3000mb_default_agc_gain); - - wr(DIB3000MB_REG_PHASE_NOISE, DIB3000MB_PHASE_NOISE_DEFAULT); - - wr_foreach(dib3000mb_reg_phase_noise, dib3000mb_default_noise_phase); - - wr_foreach(dib3000mb_reg_lock_duration, dib3000mb_default_lock_duration); - - wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low); - - wr(DIB3000MB_REG_LOCK0_MASK, DIB3000MB_LOCK0_DEFAULT); - wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4); - wr(DIB3000MB_REG_LOCK2_MASK, DIB3000MB_LOCK2_DEFAULT); - wr(DIB3000MB_REG_SEQ, dib3000_seq[1][1][1]); - - wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz); - - wr(DIB3000MB_REG_UNK_68, DIB3000MB_UNK_68); - wr(DIB3000MB_REG_UNK_69, DIB3000MB_UNK_69); - wr(DIB3000MB_REG_UNK_71, DIB3000MB_UNK_71); - wr(DIB3000MB_REG_UNK_77, DIB3000MB_UNK_77); - wr(DIB3000MB_REG_UNK_78, DIB3000MB_UNK_78); - wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT); - wr(DIB3000MB_REG_UNK_92, DIB3000MB_UNK_92); - wr(DIB3000MB_REG_UNK_96, DIB3000MB_UNK_96); - wr(DIB3000MB_REG_UNK_97, DIB3000MB_UNK_97); - wr(DIB3000MB_REG_UNK_106, DIB3000MB_UNK_106); - wr(DIB3000MB_REG_UNK_107, DIB3000MB_UNK_107); - wr(DIB3000MB_REG_UNK_108, DIB3000MB_UNK_108); - wr(DIB3000MB_REG_UNK_122, DIB3000MB_UNK_122); - wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF); - wr(DIB3000MB_REG_BERLEN, DIB3000MB_BERLEN_DEFAULT); - - wr_foreach(dib3000mb_reg_filter_coeffs, dib3000mb_filter_coeffs); - - wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_ON); - wr(DIB3000MB_REG_MULTI_DEMOD_MSB, DIB3000MB_MULTI_DEMOD_MSB); - wr(DIB3000MB_REG_MULTI_DEMOD_LSB, DIB3000MB_MULTI_DEMOD_LSB); - - wr(DIB3000MB_REG_OUTPUT_MODE, DIB3000MB_OUTPUT_MODE_SLAVE); - - wr(DIB3000MB_REG_FIFO_142, DIB3000MB_FIFO_142); - wr(DIB3000MB_REG_MPEG2_OUT_MODE, DIB3000MB_MPEG2_OUT_MODE_188); - wr(DIB3000MB_REG_PID_PARSE, DIB3000MB_PID_PARSE_ACTIVATE); - wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT); - wr(DIB3000MB_REG_FIFO_146, DIB3000MB_FIFO_146); - wr(DIB3000MB_REG_FIFO_147, DIB3000MB_FIFO_147); - - wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF); - - return 0; -} - -static int dib3000mb_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct dib3000_state* state = fe->demodulator_priv; - struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; - fe_code_rate_t *cr; - u16 tps_val; - int inv_test1,inv_test2; - u32 dds_val, threshold = 0x800000; - - if (!rd(DIB3000MB_REG_TPS_LOCK)) - return 0; - - dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB); - deb_getf("DDS_VAL: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_VALUE_MSB), rd(DIB3000MB_REG_DDS_VALUE_LSB)); - if (dds_val < threshold) - inv_test1 = 0; - else if (dds_val == threshold) - inv_test1 = 1; - else - inv_test1 = 2; - - dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB); - deb_getf("DDS_FREQ: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_FREQ_MSB), rd(DIB3000MB_REG_DDS_FREQ_LSB)); - if (dds_val < threshold) - inv_test2 = 0; - else if (dds_val == threshold) - inv_test2 = 1; - else - inv_test2 = 2; - - fep->inversion = - ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) || - ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ? - INVERSION_ON : INVERSION_OFF; - - deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); - - switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) { - case DIB3000_CONSTELLATION_QPSK: - deb_getf("QPSK "); - ofdm->constellation = QPSK; - break; - case DIB3000_CONSTELLATION_16QAM: - deb_getf("QAM16 "); - ofdm->constellation = QAM_16; - break; - case DIB3000_CONSTELLATION_64QAM: - deb_getf("QAM64 "); - ofdm->constellation = QAM_64; - break; - default: - err("Unexpected constellation returned by TPS (%d)", tps_val); - break; - } - deb_getf("TPS: %d\n", tps_val); - - if (rd(DIB3000MB_REG_TPS_HRCH)) { - deb_getf("HRCH ON\n"); - cr = &ofdm->code_rate_LP; - ofdm->code_rate_HP = FEC_NONE; - switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) { - case DIB3000_ALPHA_0: - deb_getf("HIERARCHY_NONE "); - ofdm->hierarchy_information = HIERARCHY_NONE; - break; - case DIB3000_ALPHA_1: - deb_getf("HIERARCHY_1 "); - ofdm->hierarchy_information = HIERARCHY_1; - break; - case DIB3000_ALPHA_2: - deb_getf("HIERARCHY_2 "); - ofdm->hierarchy_information = HIERARCHY_2; - break; - case DIB3000_ALPHA_4: - deb_getf("HIERARCHY_4 "); - ofdm->hierarchy_information = HIERARCHY_4; - break; - default: - err("Unexpected ALPHA value returned by TPS (%d)", tps_val); - break; - } - deb_getf("TPS: %d\n", tps_val); - - tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP); - } else { - deb_getf("HRCH OFF\n"); - cr = &ofdm->code_rate_HP; - ofdm->code_rate_LP = FEC_NONE; - ofdm->hierarchy_information = HIERARCHY_NONE; - - tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP); - } - - switch (tps_val) { - case DIB3000_FEC_1_2: - deb_getf("FEC_1_2 "); - *cr = FEC_1_2; - break; - case DIB3000_FEC_2_3: - deb_getf("FEC_2_3 "); - *cr = FEC_2_3; - break; - case DIB3000_FEC_3_4: - deb_getf("FEC_3_4 "); - *cr = FEC_3_4; - break; - case DIB3000_FEC_5_6: - deb_getf("FEC_5_6 "); - *cr = FEC_4_5; - break; - case DIB3000_FEC_7_8: - deb_getf("FEC_7_8 "); - *cr = FEC_7_8; - break; - default: - err("Unexpected FEC returned by TPS (%d)", tps_val); - break; - } - deb_getf("TPS: %d\n",tps_val); - - switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) { - case DIB3000_GUARD_TIME_1_32: - deb_getf("GUARD_INTERVAL_1_32 "); - ofdm->guard_interval = GUARD_INTERVAL_1_32; - break; - case DIB3000_GUARD_TIME_1_16: - deb_getf("GUARD_INTERVAL_1_16 "); - ofdm->guard_interval = GUARD_INTERVAL_1_16; - break; - case DIB3000_GUARD_TIME_1_8: - deb_getf("GUARD_INTERVAL_1_8 "); - ofdm->guard_interval = GUARD_INTERVAL_1_8; - break; - case DIB3000_GUARD_TIME_1_4: - deb_getf("GUARD_INTERVAL_1_4 "); - ofdm->guard_interval = GUARD_INTERVAL_1_4; - break; - default: - err("Unexpected Guard Time returned by TPS (%d)", tps_val); - break; - } - deb_getf("TPS: %d\n", tps_val); - - switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) { - case DIB3000_TRANSMISSION_MODE_2K: - deb_getf("TRANSMISSION_MODE_2K "); - ofdm->transmission_mode = TRANSMISSION_MODE_2K; - break; - case DIB3000_TRANSMISSION_MODE_8K: - deb_getf("TRANSMISSION_MODE_8K "); - ofdm->transmission_mode = TRANSMISSION_MODE_8K; - break; - default: - err("unexpected transmission mode return by TPS (%d)", tps_val); - break; - } - deb_getf("TPS: %d\n", tps_val); - - return 0; -} - -static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat) -{ - struct dib3000_state* state = fe->demodulator_priv; - - *stat = 0; - - if (rd(DIB3000MB_REG_AGC_LOCK)) - *stat |= FE_HAS_SIGNAL; - if (rd(DIB3000MB_REG_CARRIER_LOCK)) - *stat |= FE_HAS_CARRIER; - if (rd(DIB3000MB_REG_VIT_LCK)) - *stat |= FE_HAS_VITERBI; - if (rd(DIB3000MB_REG_TS_SYNC_LOCK)) - *stat |= (FE_HAS_SYNC | FE_HAS_LOCK); - - deb_getf("actual status is %2x\n",*stat); - - deb_getf("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n", - rd(DIB3000MB_REG_TPS_LOCK), - rd(DIB3000MB_REG_TPS_QAM), - rd(DIB3000MB_REG_TPS_HRCH), - rd(DIB3000MB_REG_TPS_VIT_ALPHA), - rd(DIB3000MB_REG_TPS_CODE_RATE_HP), - rd(DIB3000MB_REG_TPS_CODE_RATE_LP), - rd(DIB3000MB_REG_TPS_GUARD_TIME), - rd(DIB3000MB_REG_TPS_FFT), - rd(DIB3000MB_REG_TPS_CELL_ID)); - - //*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - return 0; -} - -static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber) -{ - struct dib3000_state* state = fe->demodulator_priv; - - *ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB)); - return 0; -} - -/* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */ -static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength) -{ - struct dib3000_state* state = fe->demodulator_priv; - - *strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170; - return 0; -} - -static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - struct dib3000_state* state = fe->demodulator_priv; - short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER); - int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) | - rd(DIB3000MB_REG_NOISE_POWER_LSB); - *snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1); - return 0; -} - -static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) -{ - struct dib3000_state* state = fe->demodulator_priv; - - *unc = rd(DIB3000MB_REG_PACKET_ERROR_RATE); - return 0; -} - -static int dib3000mb_sleep(struct dvb_frontend* fe) -{ - struct dib3000_state* state = fe->demodulator_priv; - deb_info("dib3000mb is going to bed.\n"); - wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_DOWN); - return 0; -} - -static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 800; - return 0; -} - -static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe) -{ - return dib3000mb_fe_init(fe, 0); -} - -static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) -{ - return dib3000mb_set_frontend(fe, fep, 1); -} - -static void dib3000mb_release(struct dvb_frontend* fe) -{ - struct dib3000_state *state = fe->demodulator_priv; - kfree(state); -} - -/* pid filter and transfer stuff */ -static int dib3000mb_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff) -{ - struct dib3000_state *state = fe->demodulator_priv; - pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0); - wr(index+DIB3000MB_REG_FIRST_PID,pid); - return 0; -} - -static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff) -{ - struct dib3000_state *state = fe->demodulator_priv; - - deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling"); - if (onoff) { - wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_ACTIVATE); - } else { - wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT); - } - return 0; -} - -static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff) -{ - struct dib3000_state *state = fe->demodulator_priv; - deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling"); - wr(DIB3000MB_REG_PID_PARSE,onoff); - return 0; -} - -static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr) -{ - struct dib3000_state *state = fe->demodulator_priv; - if (onoff) { - wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); - } else { - wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr)); - } - return 0; -} - -static struct dvb_frontend_ops dib3000mb_ops; - -struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, - struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) -{ - struct dib3000_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->i2c = i2c; - memcpy(&state->config,config,sizeof(struct dib3000_config)); - - /* check for the correct demod */ - if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) - goto error; - - if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - /* set the xfer operations */ - xfer_ops->pid_parse = dib3000mb_pid_parse; - xfer_ops->fifo_ctrl = dib3000mb_fifo_control; - xfer_ops->pid_ctrl = dib3000mb_pid_control; - xfer_ops->tuner_pass_ctrl = dib3000mb_tuner_pass_ctrl; - - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops dib3000mb_ops = { - - .info = { - .name = "DiBcom 3000M-B DVB-T", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = dib3000mb_release, - - .init = dib3000mb_fe_init_nonmobile, - .sleep = dib3000mb_sleep, - - .set_frontend = dib3000mb_set_frontend_and_tuner, - .get_frontend = dib3000mb_get_frontend, - .get_tune_settings = dib3000mb_fe_get_tune_settings, - - .read_status = dib3000mb_read_status, - .read_ber = dib3000mb_read_ber, - .read_signal_strength = dib3000mb_read_signal_strength, - .read_snr = dib3000mb_read_snr, - .read_ucblocks = dib3000mb_read_unc_blocks, -}; - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(dib3000mb_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mb_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mb_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mb_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mb_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,556 +0,0 @@ -/* - * dib3000mb_priv.h - * - * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) - * - * 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, version 2. - * - * for more information see dib3000mb.c . - */ - -#ifndef __DIB3000MB_PRIV_H_INCLUDED__ -#define __DIB3000MB_PRIV_H_INCLUDED__ - -/* info and err, taken from usb.h, if there is anything available like by default. */ -#define err(format, arg...) printk(KERN_ERR "dib3000: " format "\n" , ## arg) -#define info(format, arg...) printk(KERN_INFO "dib3000: " format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg) - -/* handy shortcuts */ -#define rd(reg) dib3000_read_reg(state,reg) - -#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \ - { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; } - -#define wr_foreach(a,v) { int i; \ - if (sizeof(a) != sizeof(v)) \ - err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\ - for (i=0; i < sizeof(a)/sizeof(u16); i++) \ - wr(a[i],v[i]); \ - } - -#define set_or(reg,val) wr(reg,rd(reg) | val) - -#define set_and(reg,val) wr(reg,rd(reg) & val) - -/* debug */ - -#define dprintk(level,args...) \ - do { if ((debug & level)) { printk(args); } } while (0) - -/* mask for enabling a specific pid for the pid_filter */ -#define DIB3000_ACTIVATE_PID_FILTERING (0x2000) - -/* common values for tuning */ -#define DIB3000_ALPHA_0 ( 0) -#define DIB3000_ALPHA_1 ( 1) -#define DIB3000_ALPHA_2 ( 2) -#define DIB3000_ALPHA_4 ( 4) - -#define DIB3000_CONSTELLATION_QPSK ( 0) -#define DIB3000_CONSTELLATION_16QAM ( 1) -#define DIB3000_CONSTELLATION_64QAM ( 2) - -#define DIB3000_GUARD_TIME_1_32 ( 0) -#define DIB3000_GUARD_TIME_1_16 ( 1) -#define DIB3000_GUARD_TIME_1_8 ( 2) -#define DIB3000_GUARD_TIME_1_4 ( 3) - -#define DIB3000_TRANSMISSION_MODE_2K ( 0) -#define DIB3000_TRANSMISSION_MODE_8K ( 1) - -#define DIB3000_SELECT_LP ( 0) -#define DIB3000_SELECT_HP ( 1) - -#define DIB3000_FEC_1_2 ( 1) -#define DIB3000_FEC_2_3 ( 2) -#define DIB3000_FEC_3_4 ( 3) -#define DIB3000_FEC_5_6 ( 5) -#define DIB3000_FEC_7_8 ( 7) - -#define DIB3000_HRCH_OFF ( 0) -#define DIB3000_HRCH_ON ( 1) - -#define DIB3000_DDS_INVERSION_OFF ( 0) -#define DIB3000_DDS_INVERSION_ON ( 1) - -#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a << 8)) -#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 8) | (1 << 7))) - -#define DIB3000_REG_MANUFACTOR_ID ( 1025) -#define DIB3000_I2C_ID_DIBCOM (0x01b3) - -#define DIB3000_REG_DEVICE_ID ( 1026) -#define DIB3000MB_DEVICE_ID (0x3000) -#define DIB3000MC_DEVICE_ID (0x3001) -#define DIB3000P_DEVICE_ID (0x3002) - -/* frontend state */ -struct dib3000_state { - struct i2c_adapter* i2c; - -/* configuration settings */ - struct dib3000_config config; - - struct dvb_frontend frontend; - int timing_offset; - int timing_offset_comp_done; - - fe_bandwidth_t last_tuned_bw; - u32 last_tuned_freq; -}; - -/* register addresses and some of their default values */ - -/* restart subsystems */ -#define DIB3000MB_REG_RESTART ( 0) - -#define DIB3000MB_RESTART_OFF ( 0) -#define DIB3000MB_RESTART_AUTO_SEARCH (1 << 1) -#define DIB3000MB_RESTART_CTRL (1 << 2) -#define DIB3000MB_RESTART_AGC (1 << 3) - -/* FFT size */ -#define DIB3000MB_REG_FFT ( 1) - -/* Guard time */ -#define DIB3000MB_REG_GUARD_TIME ( 2) - -/* QAM */ -#define DIB3000MB_REG_QAM ( 3) - -/* Alpha coefficient high priority Viterbi algorithm */ -#define DIB3000MB_REG_VIT_ALPHA ( 4) - -/* spectrum inversion */ -#define DIB3000MB_REG_DDS_INV ( 5) - -/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */ -#define DIB3000MB_REG_DDS_FREQ_MSB ( 6) -#define DIB3000MB_REG_DDS_FREQ_LSB ( 7) -#define DIB3000MB_DDS_FREQ_MSB ( 178) -#define DIB3000MB_DDS_FREQ_LSB ( 8990) - -/* timing frequency (carrier spacing) */ -static u16 dib3000mb_reg_timing_freq[] = { 8,9 }; -static u16 dib3000mb_timing_freq[][2] = { - { 126 , 48873 }, /* 6 MHz */ - { 147 , 57019 }, /* 7 MHz */ - { 168 , 65164 }, /* 8 MHz */ -}; - -/* impulse noise parameter */ -/* 36 ??? */ - -static u16 dib3000mb_reg_impulse_noise[] = { 10,11,12,15,36 }; - -enum dib3000mb_impulse_noise_type { - DIB3000MB_IMPNOISE_OFF, - DIB3000MB_IMPNOISE_MOBILE, - DIB3000MB_IMPNOISE_FIXED, - DIB3000MB_IMPNOISE_DEFAULT -}; - -static u16 dib3000mb_impulse_noise_values[][5] = { - { 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */ - { 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */ - { 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */ - { 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */ -}; - -/* - * Dual Automatic-Gain-Control - * - gains RF in tuner (AGC1) - * - gains IF after filtering (AGC2) - */ - -/* also from 16 to 18 */ -static u16 dib3000mb_reg_agc_gain[] = { - 19,20,21,22,23,24,25,26,27,28,29,30,31,32 -}; - -static u16 dib3000mb_default_agc_gain[] = - { 0x0001, 52429, 623, 128, 166, 195, 61, /* RF ??? */ - 0x0001, 53766, 38011, 0, 90, 33, 23 }; /* IF ??? */ - -/* phase noise */ -/* 36 is set when setting the impulse noise */ -static u16 dib3000mb_reg_phase_noise[] = { 33,34,35,37,38 }; - -static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 }; - -/* lock duration */ -static u16 dib3000mb_reg_lock_duration[] = { 39,40 }; -static u16 dib3000mb_default_lock_duration[] = { 135, 135 }; - -/* AGC loop bandwidth */ -static u16 dib3000mb_reg_agc_bandwidth[] = { 43,44,45,46,47,48,49,50 }; - -static u16 dib3000mb_agc_bandwidth_low[] = - { 2088, 10, 2088, 10, 3448, 5, 3448, 5 }; -static u16 dib3000mb_agc_bandwidth_high[] = - { 2349, 5, 2349, 5, 2586, 2, 2586, 2 }; - -/* - * lock0 definition (coff_lock) - */ -#define DIB3000MB_REG_LOCK0_MASK ( 51) -#define DIB3000MB_LOCK0_DEFAULT ( 4) - -/* - * lock1 definition (cpil_lock) - * for auto search - * which values hide behind the lock masks - */ -#define DIB3000MB_REG_LOCK1_MASK ( 52) -#define DIB3000MB_LOCK1_SEARCH_4 (0x0004) -#define DIB3000MB_LOCK1_SEARCH_2048 (0x0800) -#define DIB3000MB_LOCK1_DEFAULT (0x0001) - -/* - * lock2 definition (fec_lock) */ -#define DIB3000MB_REG_LOCK2_MASK ( 53) -#define DIB3000MB_LOCK2_DEFAULT (0x0080) - -/* - * SEQ ? what was that again ... :) - * changes when, inversion, guard time and fft is - * either automatically detected or not - */ -#define DIB3000MB_REG_SEQ ( 54) - -/* bandwidth */ -static u16 dib3000mb_reg_bandwidth[] = { 55,56,57,58,59,60,61,62,63,64,65,66,67 }; -static u16 dib3000mb_bandwidth_6mhz[] = - { 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 }; - -static u16 dib3000mb_bandwidth_7mhz[] = - { 0, 28, 64421, 96, 39973, 483, 3255, 0, 1000, 0, 1010, 1, 45264 }; - -static u16 dib3000mb_bandwidth_8mhz[] = - { 0, 25, 23600, 84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 }; - -#define DIB3000MB_REG_UNK_68 ( 68) -#define DIB3000MB_UNK_68 ( 0) - -#define DIB3000MB_REG_UNK_69 ( 69) -#define DIB3000MB_UNK_69 ( 0) - -#define DIB3000MB_REG_UNK_71 ( 71) -#define DIB3000MB_UNK_71 ( 0) - -#define DIB3000MB_REG_UNK_77 ( 77) -#define DIB3000MB_UNK_77 ( 6) - -#define DIB3000MB_REG_UNK_78 ( 78) -#define DIB3000MB_UNK_78 (0x0080) - -/* isi */ -#define DIB3000MB_REG_ISI ( 79) -#define DIB3000MB_ISI_ACTIVATE ( 0) -#define DIB3000MB_ISI_INHIBIT ( 1) - -/* sync impovement */ -#define DIB3000MB_REG_SYNC_IMPROVEMENT ( 84) -#define DIB3000MB_SYNC_IMPROVE_2K_1_8 ( 3) -#define DIB3000MB_SYNC_IMPROVE_DEFAULT ( 0) - -/* phase noise compensation inhibition */ -#define DIB3000MB_REG_PHASE_NOISE ( 87) -#define DIB3000MB_PHASE_NOISE_DEFAULT ( 0) - -#define DIB3000MB_REG_UNK_92 ( 92) -#define DIB3000MB_UNK_92 (0x0080) - -#define DIB3000MB_REG_UNK_96 ( 96) -#define DIB3000MB_UNK_96 (0x0010) - -#define DIB3000MB_REG_UNK_97 ( 97) -#define DIB3000MB_UNK_97 (0x0009) - -/* mobile mode ??? */ -#define DIB3000MB_REG_MOBILE_MODE ( 101) -#define DIB3000MB_MOBILE_MODE_ON ( 1) -#define DIB3000MB_MOBILE_MODE_OFF ( 0) - -#define DIB3000MB_REG_UNK_106 ( 106) -#define DIB3000MB_UNK_106 (0x0080) - -#define DIB3000MB_REG_UNK_107 ( 107) -#define DIB3000MB_UNK_107 (0x0080) - -#define DIB3000MB_REG_UNK_108 ( 108) -#define DIB3000MB_UNK_108 (0x0080) - -/* fft */ -#define DIB3000MB_REG_UNK_121 ( 121) -#define DIB3000MB_UNK_121_2K ( 7) -#define DIB3000MB_UNK_121_DEFAULT ( 5) - -#define DIB3000MB_REG_UNK_122 ( 122) -#define DIB3000MB_UNK_122 ( 2867) - -/* QAM for mobile mode */ -#define DIB3000MB_REG_MOBILE_MODE_QAM ( 126) -#define DIB3000MB_MOBILE_MODE_QAM_64 ( 3) -#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16 ( 1) -#define DIB3000MB_MOBILE_MODE_QAM_OFF ( 0) - -/* - * data diversity when having more than one chip on-board - * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY - */ -#define DIB3000MB_REG_DATA_IN_DIVERSITY ( 127) -#define DIB3000MB_DATA_DIVERSITY_IN_OFF ( 0) -#define DIB3000MB_DATA_DIVERSITY_IN_ON ( 2) - -/* vit hrch */ -#define DIB3000MB_REG_VIT_HRCH ( 128) - -/* vit code rate */ -#define DIB3000MB_REG_VIT_CODE_RATE ( 129) - -/* vit select hp */ -#define DIB3000MB_REG_VIT_HP ( 130) - -/* time frame for Bit-Error-Rate calculation */ -#define DIB3000MB_REG_BERLEN ( 135) -#define DIB3000MB_BERLEN_LONG ( 0) -#define DIB3000MB_BERLEN_DEFAULT ( 1) -#define DIB3000MB_BERLEN_MEDIUM ( 2) -#define DIB3000MB_BERLEN_SHORT ( 3) - -/* 142 - 152 FIFO parameters - * which is what ? - */ - -#define DIB3000MB_REG_FIFO_142 ( 142) -#define DIB3000MB_FIFO_142 ( 0) - -/* MPEG2 TS output mode */ -#define DIB3000MB_REG_MPEG2_OUT_MODE ( 143) -#define DIB3000MB_MPEG2_OUT_MODE_204 ( 0) -#define DIB3000MB_MPEG2_OUT_MODE_188 ( 1) - -#define DIB3000MB_REG_PID_PARSE ( 144) -#define DIB3000MB_PID_PARSE_INHIBIT ( 0) -#define DIB3000MB_PID_PARSE_ACTIVATE ( 1) - -#define DIB3000MB_REG_FIFO ( 145) -#define DIB3000MB_FIFO_INHIBIT ( 1) -#define DIB3000MB_FIFO_ACTIVATE ( 0) - -#define DIB3000MB_REG_FIFO_146 ( 146) -#define DIB3000MB_FIFO_146 ( 3) - -#define DIB3000MB_REG_FIFO_147 ( 147) -#define DIB3000MB_FIFO_147 (0x0100) - -/* - * pidfilter - * it is not a hardware pidfilter but a filter which drops all pids - * except the ones set. Necessary because of the limited USB1.1 bandwidth. - * regs 153-168 - */ - -#define DIB3000MB_REG_FIRST_PID ( 153) -#define DIB3000MB_NUM_PIDS ( 16) - -/* - * output mode - * USB devices have to use 'slave'-mode - * see also DIB3000MB_REG_ELECT_OUT_MODE - */ -#define DIB3000MB_REG_OUTPUT_MODE ( 169) -#define DIB3000MB_OUTPUT_MODE_GATED_CLK ( 0) -#define DIB3000MB_OUTPUT_MODE_CONT_CLK ( 1) -#define DIB3000MB_OUTPUT_MODE_SERIAL ( 2) -#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY ( 5) -#define DIB3000MB_OUTPUT_MODE_SLAVE ( 6) - -/* irq event mask */ -#define DIB3000MB_REG_IRQ_EVENT_MASK ( 170) -#define DIB3000MB_IRQ_EVENT_MASK ( 0) - -/* filter coefficients */ -static u16 dib3000mb_reg_filter_coeffs[] = { - 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, - 188, 189, 190, 191, 192, 194 -}; - -static u16 dib3000mb_filter_coeffs[] = { - 226, 160, 29, - 979, 998, 19, - 22, 1019, 1006, - 1022, 12, 6, - 1017, 1017, 3, - 6, 1019, - 1021, 2, 3, - 1, 0, -}; - -/* - * mobile algorithm (when you are moving with your device) - * but not faster than 90 km/h - */ -#define DIB3000MB_REG_MOBILE_ALGO ( 195) -#define DIB3000MB_MOBILE_ALGO_ON ( 0) -#define DIB3000MB_MOBILE_ALGO_OFF ( 1) - -/* multiple demodulators algorithm */ -#define DIB3000MB_REG_MULTI_DEMOD_MSB ( 206) -#define DIB3000MB_REG_MULTI_DEMOD_LSB ( 207) - -/* terminator, no more demods */ -#define DIB3000MB_MULTI_DEMOD_MSB ( 32767) -#define DIB3000MB_MULTI_DEMOD_LSB ( 4095) - -/* bring the device into a known */ -#define DIB3000MB_REG_RESET_DEVICE ( 1024) -#define DIB3000MB_RESET_DEVICE (0x812c) -#define DIB3000MB_RESET_DEVICE_RST ( 0) - -/* hardware clock configuration */ -#define DIB3000MB_REG_CLOCK ( 1027) -#define DIB3000MB_CLOCK_DEFAULT (0x9000) -#define DIB3000MB_CLOCK_DIVERSITY (0x92b0) - -/* power down config */ -#define DIB3000MB_REG_POWER_CONTROL ( 1028) -#define DIB3000MB_POWER_DOWN ( 1) -#define DIB3000MB_POWER_UP ( 0) - -/* electrical output mode */ -#define DIB3000MB_REG_ELECT_OUT_MODE ( 1029) -#define DIB3000MB_ELECT_OUT_MODE_OFF ( 0) -#define DIB3000MB_ELECT_OUT_MODE_ON ( 1) - -/* set the tuner i2c address */ -#define DIB3000MB_REG_TUNER ( 1089) - -/* monitoring registers (read only) */ - -/* agc loop locked (size: 1) */ -#define DIB3000MB_REG_AGC_LOCK ( 324) - -/* agc power (size: 16) */ -#define DIB3000MB_REG_AGC_POWER ( 325) - -/* agc1 value (16) */ -#define DIB3000MB_REG_AGC1_VALUE ( 326) - -/* agc2 value (16) */ -#define DIB3000MB_REG_AGC2_VALUE ( 327) - -/* total RF power (16), can be used for signal strength */ -#define DIB3000MB_REG_RF_POWER ( 328) - -/* dds_frequency with offset (24) */ -#define DIB3000MB_REG_DDS_VALUE_MSB ( 339) -#define DIB3000MB_REG_DDS_VALUE_LSB ( 340) - -/* timing offset signed (24) */ -#define DIB3000MB_REG_TIMING_OFFSET_MSB ( 341) -#define DIB3000MB_REG_TIMING_OFFSET_LSB ( 342) - -/* fft start position (13) */ -#define DIB3000MB_REG_FFT_WINDOW_POS ( 353) - -/* carriers locked (1) */ -#define DIB3000MB_REG_CARRIER_LOCK ( 355) - -/* noise power (24) */ -#define DIB3000MB_REG_NOISE_POWER_MSB ( 372) -#define DIB3000MB_REG_NOISE_POWER_LSB ( 373) - -#define DIB3000MB_REG_MOBILE_NOISE_MSB ( 374) -#define DIB3000MB_REG_MOBILE_NOISE_LSB ( 375) - -/* - * signal power (16), this and the above can be - * used to calculate the signal/noise - ratio - */ -#define DIB3000MB_REG_SIGNAL_POWER ( 380) - -/* mer (24) */ -#define DIB3000MB_REG_MER_MSB ( 381) -#define DIB3000MB_REG_MER_LSB ( 382) - -/* - * Transmission Parameter Signalling (TPS) - * the following registers can be used to get TPS-information. - * The values are according to the DVB-T standard. - */ - -/* TPS locked (1) */ -#define DIB3000MB_REG_TPS_LOCK ( 394) - -/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */ -#define DIB3000MB_REG_TPS_QAM ( 398) - -/* hierarchy from TPS (1) */ -#define DIB3000MB_REG_TPS_HRCH ( 399) - -/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */ -#define DIB3000MB_REG_TPS_VIT_ALPHA ( 400) - -/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */ -#define DIB3000MB_REG_TPS_CODE_RATE_HP ( 401) - -/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */ -#define DIB3000MB_REG_TPS_CODE_RATE_LP ( 402) - -/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */ -#define DIB3000MB_REG_TPS_GUARD_TIME ( 403) - -/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */ -#define DIB3000MB_REG_TPS_FFT ( 404) - -/* cell id from TPS (16) */ -#define DIB3000MB_REG_TPS_CELL_ID ( 406) - -/* TPS (68) */ -#define DIB3000MB_REG_TPS_1 ( 408) -#define DIB3000MB_REG_TPS_2 ( 409) -#define DIB3000MB_REG_TPS_3 ( 410) -#define DIB3000MB_REG_TPS_4 ( 411) -#define DIB3000MB_REG_TPS_5 ( 412) - -/* bit error rate (before RS correction) (21) */ -#define DIB3000MB_REG_BER_MSB ( 414) -#define DIB3000MB_REG_BER_LSB ( 415) - -/* packet error rate (uncorrected TS packets) (16) */ -#define DIB3000MB_REG_PACKET_ERROR_RATE ( 417) - -/* uncorrected packet count (16) */ -#define DIB3000MB_REG_UNC ( 420) - -/* viterbi locked (1) */ -#define DIB3000MB_REG_VIT_LCK ( 421) - -/* viterbi inidcator (16) */ -#define DIB3000MB_REG_VIT_INDICATOR ( 422) - -/* transport stream sync lock (1) */ -#define DIB3000MB_REG_TS_SYNC_LOCK ( 423) - -/* transport stream RS lock (1) */ -#define DIB3000MB_REG_TS_RS_LOCK ( 424) - -/* lock mask 0 value (1) */ -#define DIB3000MB_REG_LOCK0_VALUE ( 425) - -/* lock mask 1 value (1) */ -#define DIB3000MB_REG_LOCK1_VALUE ( 426) - -/* lock mask 2 value (1) */ -#define DIB3000MB_REG_LOCK2_VALUE ( 427) - -/* interrupt pending for auto search */ -#define DIB3000MB_REG_AS_IRQ_PENDING ( 434) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mc.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,934 +0,0 @@ -/* - * Driver for DiBcom DiB3000MC/P-demodulator. - * - * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/) - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * This code is partially based on the previous dib3000mc.c . - * - * 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, version 2. - */ - -#include -#include -#include - -#include "dvb_frontend.h" - -#include "dib3000mc.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); - -static int buggy_sfn_workaround; -module_param(buggy_sfn_workaround, int, 0644); -MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); - -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) - -struct dib3000mc_state { - struct dvb_frontend demod; - struct dib3000mc_config *cfg; - - u8 i2c_addr; - struct i2c_adapter *i2c_adap; - - struct dibx000_i2c_master i2c_master; - - u32 timf; - - fe_bandwidth_t current_bandwidth; - - u16 dev_id; - - u8 sfn_workaround_active :1; -}; - -static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg) -{ - u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff }; - u8 rb[2]; - struct i2c_msg msg[2] = { - { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 }, - { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 }, - }; - - if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); - - return (rb[0] << 8) | rb[1]; -} - -static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val) -{ - u8 b[4] = { - (reg >> 8) & 0xff, reg & 0xff, - (val >> 8) & 0xff, val & 0xff, - }; - struct i2c_msg msg = { - .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 - }; - return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; -} - -static int dib3000mc_identify(struct dib3000mc_state *state) -{ - u16 value; - if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) { - dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value); - return -EREMOTEIO; - } - - value = dib3000mc_read_word(state, 1026); - if (value != 0x3001 && value != 0x3002) { - dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value); - return -EREMOTEIO; - } - state->dev_id = value; - - dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id); - - return 0; -} - -static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset) -{ - u32 timf; - - if (state->timf == 0) { - timf = 1384402; // default value for 8MHz - if (update_offset) - msleep(200); // first time we do an update - } else - timf = state->timf; - - timf *= (bw / 1000); - - if (update_offset) { - s16 tim_offs = dib3000mc_read_word(state, 416); - - if (tim_offs & 0x2000) - tim_offs -= 0x4000; - - if (nfft == TRANSMISSION_MODE_2K) - tim_offs *= 4; - - timf += tim_offs; - state->timf = timf / (bw / 1000); - } - - dprintk("timf: %d\n", timf); - - dib3000mc_write_word(state, 23, (u16) (timf >> 16)); - dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff); - - return 0; -} - -static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state) -{ - u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb; - if (state->cfg->pwm3_inversion) { - reg_51 = (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0); - reg_52 |= (1 << 2); - } else { - reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0); - reg_52 |= (1 << 8); - } - dib3000mc_write_word(state, 51, reg_51); - dib3000mc_write_word(state, 52, reg_52); - - if (state->cfg->use_pwm3) - dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0)); - else - dib3000mc_write_word(state, 245, 0); - - dib3000mc_write_word(state, 1040, 0x3); - return 0; -} - -static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode) -{ - int ret = 0; - u16 fifo_threshold = 1792; - u16 outreg = 0; - u16 outmode = 0; - u16 elecout = 1; - u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */ - - dprintk("-I- Setting output mode for demod %p to %d\n", - &state->demod, mode); - - switch (mode) { - case OUTMODE_HIGH_Z: // disable - elecout = 0; - break; - case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock - outmode = 0; - break; - case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock - outmode = 1; - break; - case OUTMODE_MPEG2_SERIAL: // STBs with serial input - outmode = 2; - break; - case OUTMODE_MPEG2_FIFO: // e.g. USB feeding - elecout = 3; - /*ADDR @ 206 : - P_smo_error_discard [1;6:6] = 0 - P_smo_rs_discard [1;5:5] = 0 - P_smo_pid_parse [1;4:4] = 0 - P_smo_fifo_flush [1;3:3] = 0 - P_smo_mode [2;2:1] = 11 - P_smo_ovf_prot [1;0:0] = 0 - */ - smo_reg |= 3 << 1; - fifo_threshold = 512; - outmode = 5; - break; - case OUTMODE_DIVERSITY: - outmode = 4; - elecout = 1; - break; - default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); - outmode = 0; - break; - } - - if ((state->cfg->output_mpeg2_in_188_bytes)) - smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1 - - outreg = dib3000mc_read_word(state, 244) & 0x07FF; - outreg |= (outmode << 11); - ret |= dib3000mc_write_word(state, 244, outreg); - ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/ - ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */ - ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */ - return ret; -} - -static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw) -{ - u16 bw_cfg[6] = { 0 }; - u16 imp_bw_cfg[3] = { 0 }; - u16 reg; - -/* settings here are for 27.7MHz */ - switch (bw) { - case 8000: - bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20; - imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7; - break; - - case 7000: - bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7; - imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0; - break; - - case 6000: - bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5; - imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089; - break; - - case 5000: - bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500; - imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072; - break; - - default: return -EINVAL; - } - - for (reg = 6; reg < 12; reg++) - dib3000mc_write_word(state, reg, bw_cfg[reg - 6]); - dib3000mc_write_word(state, 12, 0x0000); - dib3000mc_write_word(state, 13, 0x03e8); - dib3000mc_write_word(state, 14, 0x0000); - dib3000mc_write_word(state, 15, 0x03f2); - dib3000mc_write_word(state, 16, 0x0001); - dib3000mc_write_word(state, 17, 0xb0d0); - // P_sec_len - dib3000mc_write_word(state, 18, 0x0393); - dib3000mc_write_word(state, 19, 0x8700); - - for (reg = 55; reg < 58; reg++) - dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]); - - // Timing configuration - dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0); - - return 0; -} - -static u16 impulse_noise_val[29] = - -{ - 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3, - 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2, - 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd -}; - -static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft) -{ - u16 i; - for (i = 58; i < 87; i++) - dib3000mc_write_word(state, i, impulse_noise_val[i-58]); - - if (nfft == TRANSMISSION_MODE_8K) { - dib3000mc_write_word(state, 58, 0x3b); - dib3000mc_write_word(state, 84, 0x00); - dib3000mc_write_word(state, 85, 0x8200); - } - - dib3000mc_write_word(state, 34, 0x1294); - dib3000mc_write_word(state, 35, 0x1ff8); - if (mode == 1) - dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10)); -} - -static int dib3000mc_init(struct dvb_frontend *demod) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - struct dibx000_agc_config *agc = state->cfg->agc; - - // Restart Configuration - dib3000mc_write_word(state, 1027, 0x8000); - dib3000mc_write_word(state, 1027, 0x0000); - - // power up the demod + mobility configuration - dib3000mc_write_word(state, 140, 0x0000); - dib3000mc_write_word(state, 1031, 0); - - if (state->cfg->mobile_mode) { - dib3000mc_write_word(state, 139, 0x0000); - dib3000mc_write_word(state, 141, 0x0000); - dib3000mc_write_word(state, 175, 0x0002); - dib3000mc_write_word(state, 1032, 0x0000); - } else { - dib3000mc_write_word(state, 139, 0x0001); - dib3000mc_write_word(state, 141, 0x0000); - dib3000mc_write_word(state, 175, 0x0000); - dib3000mc_write_word(state, 1032, 0x012C); - } - dib3000mc_write_word(state, 1033, 0x0000); - - // P_clk_cfg - dib3000mc_write_word(state, 1037, 0x3130); - - // other configurations - - // P_ctrl_sfreq - dib3000mc_write_word(state, 33, (5 << 0)); - dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0)); - - // Phase noise control - // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange - dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0)); - - if (state->cfg->phase_noise_mode == 0) - dib3000mc_write_word(state, 111, 0x00); - else - dib3000mc_write_word(state, 111, 0x02); - - // P_agc_global - dib3000mc_write_word(state, 50, 0x8000); - - // agc setup misc - dib3000mc_setup_pwm_state(state); - - // P_agc_counter_lock - dib3000mc_write_word(state, 53, 0x87); - // P_agc_counter_unlock - dib3000mc_write_word(state, 54, 0x87); - - /* agc */ - dib3000mc_write_word(state, 36, state->cfg->max_time); - dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0)); - dib3000mc_write_word(state, 38, state->cfg->pwm3_value); - dib3000mc_write_word(state, 39, state->cfg->ln_adc_level); - - // set_agc_loop_Bw - dib3000mc_write_word(state, 40, 0x0179); - dib3000mc_write_word(state, 41, 0x03f0); - - dib3000mc_write_word(state, 42, agc->agc1_max); - dib3000mc_write_word(state, 43, agc->agc1_min); - dib3000mc_write_word(state, 44, agc->agc2_max); - dib3000mc_write_word(state, 45, agc->agc2_min); - dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2); - dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - -// Begin: TimeOut registers - // P_pha3_thres - dib3000mc_write_word(state, 110, 3277); - // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80 - dib3000mc_write_word(state, 26, 0x6680); - // lock_mask0 - dib3000mc_write_word(state, 1, 4); - // lock_mask1 - dib3000mc_write_word(state, 2, 4); - // lock_mask2 - dib3000mc_write_word(state, 3, 0x1000); - // P_search_maxtrial=1 - dib3000mc_write_word(state, 5, 1); - - dib3000mc_set_bandwidth(state, 8000); - - // div_lock_mask - dib3000mc_write_word(state, 4, 0x814); - - dib3000mc_write_word(state, 21, (1 << 9) | 0x164); - dib3000mc_write_word(state, 22, 0x463d); - - // Spurious rm cfg - // P_cspu_regul, P_cspu_win_cut - dib3000mc_write_word(state, 120, 0x200f); - // P_adp_selec_monit - dib3000mc_write_word(state, 134, 0); - - // Fec cfg - dib3000mc_write_word(state, 195, 0x10); - - // diversity register: P_dvsy_sync_wait.. - dib3000mc_write_word(state, 180, 0x2FF0); - - // Impulse noise configuration - dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K); - - // output mode set-up - dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); - - /* close the i2c-gate */ - dib3000mc_write_word(state, 769, (1 << 7) ); - - return 0; -} - -static int dib3000mc_sleep(struct dvb_frontend *demod) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - - dib3000mc_write_word(state, 1031, 0xFFFF); - dib3000mc_write_word(state, 1032, 0xFFFF); - dib3000mc_write_word(state, 1033, 0xFFF0); - - return 0; -} - -static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) -{ - u16 cfg[4] = { 0 },reg; - switch (qam) { - case QPSK: - cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0; - break; - case QAM_16: - cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0; - break; - case QAM_64: - cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8; - break; - } - for (reg = 129; reg < 133; reg++) - dib3000mc_write_word(state, reg, cfg[reg - 129]); -} - -static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) -{ - u16 value; - dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); - -// if (boost) -// dib3000mc_write_word(state, 100, (11 << 6) + 6); -// else - dib3000mc_write_word(state, 100, (16 << 6) + 9); - - dib3000mc_write_word(state, 1027, 0x0800); - dib3000mc_write_word(state, 1027, 0x0000); - - //Default cfg isi offset adp - dib3000mc_write_word(state, 26, 0x6680); - dib3000mc_write_word(state, 29, 0x1273); - dib3000mc_write_word(state, 33, 5); - dib3000mc_set_adp_cfg(state, QAM_16); - dib3000mc_write_word(state, 133, 15564); - - dib3000mc_write_word(state, 12 , 0x0); - dib3000mc_write_word(state, 13 , 0x3e8); - dib3000mc_write_word(state, 14 , 0x0); - dib3000mc_write_word(state, 15 , 0x3f2); - - dib3000mc_write_word(state, 93,0); - dib3000mc_write_word(state, 94,0); - dib3000mc_write_word(state, 95,0); - dib3000mc_write_word(state, 96,0); - dib3000mc_write_word(state, 97,0); - dib3000mc_write_word(state, 98,0); - - dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); - - value = 0; - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: value |= (0 << 7); break; - default: - case TRANSMISSION_MODE_8K: value |= (1 << 7); break; - } - switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_32: value |= (0 << 5); break; - case GUARD_INTERVAL_1_16: value |= (1 << 5); break; - case GUARD_INTERVAL_1_4: value |= (3 << 5); break; - default: - case GUARD_INTERVAL_1_8: value |= (2 << 5); break; - } - switch (ch->u.ofdm.constellation) { - case QPSK: value |= (0 << 3); break; - case QAM_16: value |= (1 << 3); break; - default: - case QAM_64: value |= (2 << 3); break; - } - switch (HIERARCHY_1) { - case HIERARCHY_2: value |= 2; break; - case HIERARCHY_4: value |= 4; break; - default: - case HIERARCHY_1: value |= 1; break; - } - dib3000mc_write_word(state, 0, value); - dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); - - value = 0; - if (ch->u.ofdm.hierarchy_information == 1) - value |= (1 << 4); - if (1 == 1) - value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { - case FEC_2_3: value |= (2 << 1); break; - case FEC_3_4: value |= (3 << 1); break; - case FEC_5_6: value |= (5 << 1); break; - case FEC_7_8: value |= (7 << 1); break; - default: - case FEC_1_2: value |= (1 << 1); break; - } - dib3000mc_write_word(state, 181, value); - - // diversity synchro delay add 50% SFN margin - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_8K: value = 256; break; - case TRANSMISSION_MODE_2K: - default: value = 64; break; - } - switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_16: value *= 2; break; - case GUARD_INTERVAL_1_8: value *= 4; break; - case GUARD_INTERVAL_1_4: value *= 8; break; - default: - case GUARD_INTERVAL_1_32: value *= 1; break; - } - value <<= 4; - value |= dib3000mc_read_word(state, 180) & 0x000f; - dib3000mc_write_word(state, 180, value); - - // restart demod - value = dib3000mc_read_word(state, 0); - dib3000mc_write_word(state, 0, value | (1 << 9)); - dib3000mc_write_word(state, 0, value); - - msleep(30); - - dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); -} - -static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - u16 reg; -// u32 val; - struct dvb_frontend_parameters schan; - - schan = *chan; - - /* TODO what is that ? */ - - /* a channel for autosearch */ - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_2_3; - schan.u.ofdm.hierarchy_information = 0; - - dib3000mc_set_channel_cfg(state, &schan, 11); - - reg = dib3000mc_read_word(state, 0); - dib3000mc_write_word(state, 0, reg | (1 << 8)); - dib3000mc_read_word(state, 511); - dib3000mc_write_word(state, 0, reg); - - return 0; -} - -static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - u16 irq_pending = dib3000mc_read_word(state, 511); - - if (irq_pending & 0x1) // failed - return 1; - - if (irq_pending & 0x2) // succeeded - return 2; - - return 0; // still pending -} - -static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - - // ** configure demod ** - dib3000mc_set_channel_cfg(state, ch, 0); - - // activates isi - if (state->sfn_workaround_active) { - dprintk("SFN workaround is active\n"); - dib3000mc_write_word(state, 29, 0x1273); - dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift - } else { - dib3000mc_write_word(state, 29, 0x1073); - dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift - } - - dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); - if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { - dib3000mc_write_word(state, 26, 38528); - dib3000mc_write_word(state, 33, 8); - } else { - dib3000mc_write_word(state, 26, 30336); - dib3000mc_write_word(state, 33, 6); - } - - if (dib3000mc_read_word(state, 509) & 0x80) - dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); - - return 0; -} - -struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating) -{ - struct dib3000mc_state *st = demod->demodulator_priv; - return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating); -} - -EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master); - -static int dib3000mc_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - u16 tps = dib3000mc_read_word(state,458); - - fep->inversion = INVERSION_AUTO; - - fep->u.ofdm.bandwidth = state->current_bandwidth; - - switch ((tps >> 8) & 0x1) { - case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; - } - - switch (tps & 0x3) { - case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; - case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; - case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; - case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; - } - - switch ((tps >> 13) & 0x3) { - case 0: fep->u.ofdm.constellation = QPSK; break; - case 1: fep->u.ofdm.constellation = QAM_16; break; - case 2: - default: fep->u.ofdm.constellation = QAM_64; break; - } - - /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ - /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */ - - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; - switch ((tps >> 5) & 0x7) { - case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; - case 7: - default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; - - } - - switch ((tps >> 2) & 0x7) { - case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; - case 7: - default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; - } - - return 0; -} - -static int dib3000mc_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - int ret; - - dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); - - state->current_bandwidth = fep->u.ofdm.bandwidth; - dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); - - /* maybe the parameter has been changed */ - state->sfn_workaround_active = buggy_sfn_workaround; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fep); - msleep(100); - } - - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || - fep->u.ofdm.constellation == QAM_AUTO || - fep->u.ofdm.code_rate_HP == FEC_AUTO) { - int i = 1000, found; - - dib3000mc_autosearch_start(fe, fep); - do { - msleep(1); - found = dib3000mc_autosearch_is_irq(fe); - } while (found == 0 && i--); - - dprintk("autosearch returns: %d\n",found); - if (found == 0 || found == 1) - return 0; // no channel found - - dib3000mc_get_frontend(fe, fep); - } - - ret = dib3000mc_tune(fe, fep); - - /* make this a config parameter */ - dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return ret; -} - -static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - u16 lock = dib3000mc_read_word(state, 509); - - *stat = 0; - - if (lock & 0x8000) - *stat |= FE_HAS_SIGNAL; - if (lock & 0x3000) - *stat |= FE_HAS_CARRIER; - if (lock & 0x0100) - *stat |= FE_HAS_VITERBI; - if (lock & 0x0010) - *stat |= FE_HAS_SYNC; - if (lock & 0x0008) - *stat |= FE_HAS_LOCK; - - return 0; -} - -static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501); - return 0; -} - -static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - *unc = dib3000mc_read_word(state, 508); - return 0; -} - -static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - u16 val = dib3000mc_read_word(state, 392); - *strength = 65535 - val; - return 0; -} - -static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - *snr = 0x0000; - return 0; -} - -static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void dib3000mc_release(struct dvb_frontend *fe) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - dibx000_exit_i2c_master(&state->i2c_master); - kfree(state); -} - -int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0); - return 0; -} -EXPORT_SYMBOL(dib3000mc_pid_control); - -int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4); - tmp |= (onoff << 4); - return dib3000mc_write_word(state, 206, tmp); -} -EXPORT_SYMBOL(dib3000mc_pid_parse); - -void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - state->cfg = cfg; -} -EXPORT_SYMBOL(dib3000mc_set_config); - -int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]) -{ - struct dib3000mc_state *dmcst; - int k; - u8 new_addr; - - static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26}; - - dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL); - if (dmcst == NULL) - return -ENOMEM; - - dmcst->i2c_adap = i2c; - - for (k = no_of_demods-1; k >= 0; k--) { - dmcst->cfg = &cfg[k]; - - /* designated i2c address */ - new_addr = DIB3000MC_I2C_ADDRESS[k]; - dmcst->i2c_addr = new_addr; - if (dib3000mc_identify(dmcst) != 0) { - dmcst->i2c_addr = default_addr; - if (dib3000mc_identify(dmcst) != 0) { - dprintk("-E- DiB3000P/MC #%d: not identified\n", k); - kfree(dmcst); - return -ENODEV; - } - } - - dib3000mc_set_output_mode(dmcst, OUTMODE_MPEG2_PAR_CONT_CLK); - - // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0) - dib3000mc_write_word(dmcst, 1024, (new_addr << 3) | 0x1); - dmcst->i2c_addr = new_addr; - } - - for (k = 0; k < no_of_demods; k++) { - dmcst->cfg = &cfg[k]; - dmcst->i2c_addr = DIB3000MC_I2C_ADDRESS[k]; - - dib3000mc_write_word(dmcst, 1024, dmcst->i2c_addr << 3); - - /* turn off data output */ - dib3000mc_set_output_mode(dmcst, OUTMODE_HIGH_Z); - } - - kfree(dmcst); - return 0; -} -EXPORT_SYMBOL(dib3000mc_i2c_enumeration); - -static struct dvb_frontend_ops dib3000mc_ops; - -struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg) -{ - struct dvb_frontend *demod; - struct dib3000mc_state *st; - st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL); - if (st == NULL) - return NULL; - - st->cfg = cfg; - st->i2c_adap = i2c_adap; - st->i2c_addr = i2c_addr; - - demod = &st->demod; - demod->demodulator_priv = st; - memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); - - if (dib3000mc_identify(st) != 0) - goto error; - - dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr); - - dib3000mc_write_word(st, 1037, 0x3130); - - return demod; - -error: - kfree(st); - return NULL; -} -EXPORT_SYMBOL(dib3000mc_attach); - -static struct dvb_frontend_ops dib3000mc_ops = { - .info = { - .name = "DiBcom 3000MC/P", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = dib3000mc_release, - - .init = dib3000mc_init, - .sleep = dib3000mc_sleep, - - .set_frontend = dib3000mc_set_frontend, - .get_tune_settings = dib3000mc_fe_get_tune_settings, - .get_frontend = dib3000mc_get_frontend, - - .read_status = dib3000mc_read_status, - .read_ber = dib3000mc_read_ber, - .read_signal_strength = dib3000mc_read_signal_strength, - .read_snr = dib3000mc_read_snr, - .read_ucblocks = dib3000mc_read_unc_blocks, -}; - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib3000mc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* - * Driver for DiBcom DiB3000MC/P-demodulator. - * - * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/) - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher\@desy.de) - * - * This code is partially based on the previous dib3000mc.c . - * - * 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, version 2. - */ -#ifndef DIB3000MC_H -#define DIB3000MC_H - -#include "dibx000_common.h" - -struct dib3000mc_config { - struct dibx000_agc_config *agc; - - u8 phase_noise_mode; - u8 impulse_noise_mode; - - u8 pwm3_inversion; - u8 use_pwm3; - u16 pwm3_value; - - u16 max_time; - u16 ln_adc_level; - - u8 agc_command1 :1; - u8 agc_command2 :1; - - u8 mobile_mode; - - u8 output_mpeg2_in_188_bytes; -}; - -#define DEFAULT_DIB3000MC_I2C_ADDRESS 16 -#define DEFAULT_DIB3000P_I2C_ADDRESS 24 - -#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && \ - defined(MODULE)) -extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, - u8 i2c_addr, - struct dib3000mc_config *cfg); -extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, - int no_of_demods, u8 default_addr, - struct dib3000mc_config cfg[]); -extern -struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, - int gating); -#else -static inline -struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, - struct dib3000mc_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline -int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, - int no_of_demods, u8 default_addr, - struct dib3000mc_config cfg[]) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline -struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, - int gating) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_DIB3000MC - -extern int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff); -extern int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff); - -extern void dib3000mc_set_config(struct dvb_frontend *, struct dib3000mc_config *); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000m.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000m.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000m.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000m.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1429 +0,0 @@ -/* - * Linux-DVB Driver for DiBcom's DiB7000M and - * first generation DiB7000P-demodulator-family. - * - * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) - * - * 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, version 2. - */ -#include -#include -#include - -#include "dvb_frontend.h" - -#include "dib7000m.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); - -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0) - -struct dib7000m_state { - struct dvb_frontend demod; - struct dib7000m_config cfg; - - u8 i2c_addr; - struct i2c_adapter *i2c_adap; - - struct dibx000_i2c_master i2c_master; - -/* offset is 1 in case of the 7000MC */ - u8 reg_offs; - - u16 wbd_ref; - - u8 current_band; - fe_bandwidth_t current_bandwidth; - struct dibx000_agc_config *current_agc; - u32 timf; - u32 timf_default; - u32 internal_clk; - - u8 div_force_off : 1; - u8 div_state : 1; - u16 div_sync_wait; - - u16 revision; - - u8 agc_state; -}; - -enum dib7000m_power_mode { - DIB7000M_POWER_ALL = 0, - - DIB7000M_POWER_NO, - DIB7000M_POWER_INTERF_ANALOG_AGC, - DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD, - DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD, - DIB7000M_POWER_INTERFACE_ONLY, -}; - -static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) -{ - u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff }; - u8 rb[2]; - struct i2c_msg msg[2] = { - { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 }, - { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 }, - }; - - if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d",reg); - - return (rb[0] << 8) | rb[1]; -} - -static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) -{ - u8 b[4] = { - (reg >> 8) & 0xff, reg & 0xff, - (val >> 8) & 0xff, val & 0xff, - }; - struct i2c_msg msg = { - .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 - }; - return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; -} -static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) -{ - u16 l = 0, r, *n; - n = buf; - l = *n++; - while (l) { - r = *n++; - - if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC - r++; - - do { - dib7000m_write_word(state, r, *n++); - r++; - } while (--l); - l = *n++; - } -} - -static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) -{ - int ret = 0; - u16 outreg, fifo_threshold, smo_mode, - sram = 0x0005; /* by default SRAM output is disabled */ - - outreg = 0; - fifo_threshold = 1792; - smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1); - - dprintk( "setting output mode for demod %p to %d", &state->demod, mode); - - switch (mode) { - case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock - outreg = (1 << 10); /* 0x0400 */ - break; - case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock - outreg = (1 << 10) | (1 << 6); /* 0x0440 */ - break; - case OUTMODE_MPEG2_SERIAL: // STBs with serial input - outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ - break; - case OUTMODE_DIVERSITY: - if (state->cfg.hostbus_diversity) - outreg = (1 << 10) | (4 << 6); /* 0x0500 */ - else - sram |= 0x0c00; - break; - case OUTMODE_MPEG2_FIFO: // e.g. USB feeding - smo_mode |= (3 << 1); - fifo_threshold = 512; - outreg = (1 << 10) | (5 << 6); - break; - case OUTMODE_HIGH_Z: // disable - outreg = 0; - break; - default: - dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); - break; - } - - if (state->cfg.output_mpeg2_in_188_bytes) - smo_mode |= (1 << 5) ; - - ret |= dib7000m_write_word(state, 294 + state->reg_offs, smo_mode); - ret |= dib7000m_write_word(state, 295 + state->reg_offs, fifo_threshold); /* synchronous fread */ - ret |= dib7000m_write_word(state, 1795, outreg); - ret |= dib7000m_write_word(state, 1805, sram); - - if (state->revision == 0x4003) { - u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd; - if (mode == OUTMODE_DIVERSITY) - clk_cfg1 |= (1 << 1); // P_O_CLK_en - dib7000m_write_word(state, 909, clk_cfg1); - } - return ret; -} - -static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) -{ - /* by default everything is going to be powered off */ - u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff; - u8 offset = 0; - - /* now, depending on the requested mode, we power on */ - switch (mode) { - /* power up everything in the demod */ - case DIB7000M_POWER_ALL: - reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000; - break; - - /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */ - case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */ - reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)); - break; - - case DIB7000M_POWER_INTERF_ANALOG_AGC: - reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10)); - reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2)); - reg_906 &= ~((1 << 0)); - break; - - case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD: - reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000; - break; - - case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD: - reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000; - break; - case DIB7000M_POWER_NO: - break; - } - - /* always power down unused parts */ - if (!state->cfg.mobile_mode) - reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); - - /* P_sdio_select_clk = 0 on MC and after*/ - if (state->revision != 0x4000) - reg_906 <<= 1; - - if (state->revision == 0x4003) - offset = 1; - - dib7000m_write_word(state, 903 + offset, reg_903); - dib7000m_write_word(state, 904 + offset, reg_904); - dib7000m_write_word(state, 905 + offset, reg_905); - dib7000m_write_word(state, 906 + offset, reg_906); -} - -static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no) -{ - int ret = 0; - u16 reg_913 = dib7000m_read_word(state, 913), - reg_914 = dib7000m_read_word(state, 914); - - switch (no) { - case DIBX000_SLOW_ADC_ON: - reg_914 |= (1 << 1) | (1 << 0); - ret |= dib7000m_write_word(state, 914, reg_914); - reg_914 &= ~(1 << 1); - break; - - case DIBX000_SLOW_ADC_OFF: - reg_914 |= (1 << 1) | (1 << 0); - break; - - case DIBX000_ADC_ON: - if (state->revision == 0x4000) { // workaround for PA/MA - // power-up ADC - dib7000m_write_word(state, 913, 0); - dib7000m_write_word(state, 914, reg_914 & 0x3); - // power-down bandgag - dib7000m_write_word(state, 913, (1 << 15)); - dib7000m_write_word(state, 914, reg_914 & 0x3); - } - - reg_913 &= 0x0fff; - reg_914 &= 0x0003; - break; - - case DIBX000_ADC_OFF: // leave the VBG voltage on - reg_913 |= (1 << 14) | (1 << 13) | (1 << 12); - reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); - break; - - case DIBX000_VBG_ENABLE: - reg_913 &= ~(1 << 15); - break; - - case DIBX000_VBG_DISABLE: - reg_913 |= (1 << 15); - break; - - default: - break; - } - -// dprintk( "913: %x, 914: %x", reg_913, reg_914); - ret |= dib7000m_write_word(state, 913, reg_913); - ret |= dib7000m_write_word(state, 914, reg_914); - - return ret; -} - -static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) -{ - u32 timf; - - // store the current bandwidth for later use - state->current_bandwidth = bw; - - if (state->timf == 0) { - dprintk( "using default timf"); - timf = state->timf_default; - } else { - dprintk( "using updated timf"); - timf = state->timf; - } - - timf = timf * (bw / 50) / 160; - - dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); - dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff)); - - return 0; -} - -static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) -{ - struct dib7000m_state *state = demod->demodulator_priv; - - if (state->div_force_off) { - dprintk( "diversity combination deactivated - forced by COFDM parameters"); - onoff = 0; - } - state->div_state = (u8)onoff; - - if (onoff) { - dib7000m_write_word(state, 263 + state->reg_offs, 6); - dib7000m_write_word(state, 264 + state->reg_offs, 6); - dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); - } else { - dib7000m_write_word(state, 263 + state->reg_offs, 1); - dib7000m_write_word(state, 264 + state->reg_offs, 0); - dib7000m_write_word(state, 266 + state->reg_offs, 0); - } - - return 0; -} - -static int dib7000m_sad_calib(struct dib7000m_state *state) -{ - -/* internal */ -// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth - dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); - dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 - - /* do the calibration */ - dib7000m_write_word(state, 929, (1 << 0)); - dib7000m_write_word(state, 929, (0 << 0)); - - msleep(1); - - return 0; -} - -static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw) -{ - dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); - dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff)); - dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); - dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff)); - - dib7000m_write_word(state, 928, bw->sad_cfg); -} - -static void dib7000m_reset_pll(struct dib7000m_state *state) -{ - const struct dibx000_bandwidth_config *bw = state->cfg.bw; - u16 reg_907,reg_910; - - /* default */ - reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) | - (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | - (bw->enable_refdiv << 1) | (0 << 0); - reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset; - - // for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value) - // this is only working only for 30 MHz crystals - if (!state->cfg.quartz_direct) { - reg_910 |= (1 << 5); // forcing the predivider to 1 - - // if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2) - if(state->cfg.input_clk_is_div_2) - reg_907 |= (16 << 9); - else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary - reg_907 |= (8 << 9); - } else { - reg_907 |= (bw->pll_ratio & 0x3f) << 9; - reg_910 |= (bw->pll_prediv << 5); - } - - dib7000m_write_word(state, 910, reg_910); // pll cfg - dib7000m_write_word(state, 907, reg_907); // clk cfg0 - dib7000m_write_word(state, 908, 0x0006); // clk_cfg1 - - dib7000m_reset_pll_common(state, bw); -} - -static void dib7000mc_reset_pll(struct dib7000m_state *state) -{ - const struct dibx000_bandwidth_config *bw = state->cfg.bw; - u16 clk_cfg1; - - // clk_cfg0 - dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0)); - - // clk_cfg1 - //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) | - clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) | - (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) | - (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0); - dib7000m_write_word(state, 908, clk_cfg1); - clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3); - dib7000m_write_word(state, 908, clk_cfg1); - - // smpl_cfg - dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7)); - - dib7000m_reset_pll_common(state, bw); -} - -static int dib7000m_reset_gpio(struct dib7000m_state *st) -{ - /* reset the GPIOs */ - dib7000m_write_word(st, 773, st->cfg.gpio_dir); - dib7000m_write_word(st, 774, st->cfg.gpio_val); - - /* TODO 782 is P_gpio_od */ - - dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos); - - dib7000m_write_word(st, 780, st->cfg.pwm_freq_div); - return 0; -} - -static u16 dib7000m_defaults_common[] = - -{ - // auto search configuration - 3, 2, - 0x0004, - 0x1000, - 0x0814, - - 12, 6, - 0x001b, - 0x7740, - 0x005b, - 0x8d80, - 0x01c9, - 0xc380, - 0x0000, - 0x0080, - 0x0000, - 0x0090, - 0x0001, - 0xd4c0, - - 1, 26, - 0x6680, // P_corm_thres Lock algorithms configuration - - 1, 170, - 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on - - 8, 173, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - - 1, 182, - 8192, // P_fft_nb_to_cut - - 2, 195, - 0x0ccd, // P_pha3_thres - 0, // P_cti_use_cpe, P_cti_use_prog - - 1, 205, - 0x200f, // P_cspu_regul, P_cspu_win_cut - - 5, 214, - 0x023d, // P_adp_regul_cnt - 0x00a4, // P_adp_noise_cnt - 0x00a4, // P_adp_regul_ext - 0x7ff0, // P_adp_noise_ext - 0x3ccc, // P_adp_fil - - 1, 226, - 0, // P_2d_byp_ti_num - - 1, 255, - 0x800, // P_equal_thres_wgn - - 1, 263, - 0x0001, - - 1, 281, - 0x0010, // P_fec_* - - 1, 294, - 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - - 0 -}; - -static u16 dib7000m_defaults[] = - -{ - /* set ADC level to -16 */ - 11, 76, - (1 << 13) - 825 - 117, - (1 << 13) - 837 - 117, - (1 << 13) - 811 - 117, - (1 << 13) - 766 - 117, - (1 << 13) - 737 - 117, - (1 << 13) - 693 - 117, - (1 << 13) - 648 - 117, - (1 << 13) - 619 - 117, - (1 << 13) - 575 - 117, - (1 << 13) - 531 - 117, - (1 << 13) - 501 - 117, - - // Tuner IO bank: max drive (14mA) - 1, 912, - 0x2c8a, - - 1, 1817, - 1, - - 0, -}; - -static int dib7000m_demod_reset(struct dib7000m_state *state) -{ - dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); - - /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ - dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE); - - /* restart all parts */ - dib7000m_write_word(state, 898, 0xffff); - dib7000m_write_word(state, 899, 0xffff); - dib7000m_write_word(state, 900, 0xff0f); - dib7000m_write_word(state, 901, 0xfffc); - - dib7000m_write_word(state, 898, 0); - dib7000m_write_word(state, 899, 0); - dib7000m_write_word(state, 900, 0); - dib7000m_write_word(state, 901, 0); - - if (state->revision == 0x4000) - dib7000m_reset_pll(state); - else - dib7000mc_reset_pll(state); - - if (dib7000m_reset_gpio(state) != 0) - dprintk( "GPIO reset was not successful."); - - if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk( "OUTPUT_MODE could not be reset."); - - /* unforce divstr regardless whether i2c enumeration was done or not */ - dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) ); - - dib7000m_set_bandwidth(state, 8000); - - dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON); - dib7000m_sad_calib(state); - dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF); - - if (state->cfg.dvbt_mode) - dib7000m_write_word(state, 1796, 0x0); // select DVB-T output - - if (state->cfg.mobile_mode) - dib7000m_write_word(state, 261 + state->reg_offs, 2); - else - dib7000m_write_word(state, 224 + state->reg_offs, 1); - - // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - dib7000m_write_word(state, 36, 0x0755); - else - dib7000m_write_word(state, 36, 0x1f55); - - // P_divclksel=3 P_divbitsel=1 - if (state->revision == 0x4000) - dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); - else - dib7000m_write_word(state, 909, (3 << 4) | 1); - - dib7000m_write_tab(state, dib7000m_defaults_common); - dib7000m_write_tab(state, dib7000m_defaults); - - dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY); - - state->internal_clk = state->cfg.bw->internal; - - return 0; -} - -static void dib7000m_restart_agc(struct dib7000m_state *state) -{ - // P_restart_iqc & P_restart_agc - dib7000m_write_word(state, 898, 0x0c00); - dib7000m_write_word(state, 898, 0x0000); -} - -static int dib7000m_agc_soft_split(struct dib7000m_state *state) -{ - u16 agc,split_offset; - - if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) - return 0; - - // n_agc_global - agc = dib7000m_read_word(state, 390); - - if (agc > state->current_agc->split.min_thres) - split_offset = state->current_agc->split.min; - else if (agc < state->current_agc->split.max_thres) - split_offset = state->current_agc->split.max; - else - split_offset = state->current_agc->split.max * - (agc - state->current_agc->split.min_thres) / - (state->current_agc->split.max_thres - state->current_agc->split.min_thres); - - dprintk( "AGC split_offset: %d",split_offset); - - // P_agc_force_split and P_agc_split_offset - return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset); -} - -static int dib7000m_update_lna(struct dib7000m_state *state) -{ - u16 dyn_gain; - - if (state->cfg.update_lna) { - // read dyn_gain here (because it is demod-dependent and not fe) - dyn_gain = dib7000m_read_word(state, 390); - - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed - dib7000m_restart_agc(state); - return 1; - } - } - return 0; -} - -static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) -{ - struct dibx000_agc_config *agc = NULL; - int i; - if (state->current_band == band && state->current_agc != NULL) - return 0; - state->current_band = band; - - for (i = 0; i < state->cfg.agc_config_count; i++) - if (state->cfg.agc[i].band_caps & band) { - agc = &state->cfg.agc[i]; - break; - } - - if (agc == NULL) { - dprintk( "no valid AGC configuration found for band 0x%02x",band); - return -EINVAL; - } - - state->current_agc = agc; - - /* AGC */ - dib7000m_write_word(state, 72 , agc->setup); - dib7000m_write_word(state, 73 , agc->inv_gain); - dib7000m_write_word(state, 74 , agc->time_stabiliz); - dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock); - - // Demod AGC loop configuration - dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp); - dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp); - - dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", - state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); - - /* AGC continued */ - if (state->wbd_ref != 0) - dib7000m_write_word(state, 102, state->wbd_ref); - else // use default - dib7000m_write_word(state, 102, agc->wbd_ref); - - dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) ); - dib7000m_write_word(state, 104, agc->agc1_max); - dib7000m_write_word(state, 105, agc->agc1_min); - dib7000m_write_word(state, 106, agc->agc2_max); - dib7000m_write_word(state, 107, agc->agc2_min); - dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 ); - dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - - if (state->revision > 0x4000) { // settings for the MC - dib7000m_write_word(state, 71, agc->agc1_pt3); -// dprintk( "929: %x %d %d", -// (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel); - dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); - } else { - // wrong default values - u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 }; - for (i = 0; i < 9; i++) - dib7000m_write_word(state, 88 + i, b[i]); - } - return 0; -} - -static void dib7000m_update_timf(struct dib7000m_state *state) -{ - u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437); - state->timf = timf * 160 / (state->current_bandwidth / 50); - dib7000m_write_word(state, 23, (u16) (timf >> 16)); - dib7000m_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); -} - -static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) -{ - struct dib7000m_state *state = demod->demodulator_priv; - u16 cfg_72 = dib7000m_read_word(state, 72); - int ret = -1; - u8 *agc_state = &state->agc_state; - u8 agc_split; - - switch (state->agc_state) { - case 0: - // set power-up level: interf+analog+AGC - dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); - dib7000m_set_adc_state(state, DIBX000_ADC_ON); - - if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) - return -1; - - ret = 7; /* ADC power up */ - (*agc_state)++; - break; - - case 1: - /* AGC initialization */ - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000m_write_word(state, 75, 32768); - if (!state->current_agc->perform_agc_softsplit) { - /* we are using the wbd - so slow AGC startup */ - dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */ - (*agc_state)++; - ret = 5; - } else { - /* default AGC startup */ - (*agc_state) = 4; - /* wait AGC rough lock time */ - ret = 7; - } - - dib7000m_restart_agc(state); - break; - - case 2: /* fast split search path after 5sec */ - dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */ - dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */ - (*agc_state)++; - ret = 14; - break; - - case 3: /* split search ended */ - agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */ - dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ - - dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ - dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ - - dib7000m_restart_agc(state); - - dprintk( "SPLIT %p: %hd", demod, agc_split); - - (*agc_state)++; - ret = 5; - break; - - case 4: /* LNA startup */ - /* wait AGC accurate lock time */ - ret = 7; - - if (dib7000m_update_lna(state)) - // wait only AGC rough lock time - ret = 5; - else - (*agc_state)++; - break; - - case 5: - dib7000m_agc_soft_split(state); - - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); - - (*agc_state)++; - break; - - default: - break; - } - return ret; -} - -static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq) -{ - u16 value, est[4]; - - dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - - /* nfft, guard, qam, alpha */ - value = 0; - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: value |= (0 << 7); break; - case TRANSMISSION_MODE_4K: value |= (2 << 7); break; - default: - case TRANSMISSION_MODE_8K: value |= (1 << 7); break; - } - switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_32: value |= (0 << 5); break; - case GUARD_INTERVAL_1_16: value |= (1 << 5); break; - case GUARD_INTERVAL_1_4: value |= (3 << 5); break; - default: - case GUARD_INTERVAL_1_8: value |= (2 << 5); break; - } - switch (ch->u.ofdm.constellation) { - case QPSK: value |= (0 << 3); break; - case QAM_16: value |= (1 << 3); break; - default: - case QAM_64: value |= (2 << 3); break; - } - switch (HIERARCHY_1) { - case HIERARCHY_2: value |= 2; break; - case HIERARCHY_4: value |= 4; break; - default: - case HIERARCHY_1: value |= 1; break; - } - dib7000m_write_word(state, 0, value); - dib7000m_write_word(state, 5, (seq << 4)); - - /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ - value = 0; - if (1 != 0) - value |= (1 << 6); - if (ch->u.ofdm.hierarchy_information == 1) - value |= (1 << 4); - if (1 == 1) - value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { - case FEC_2_3: value |= (2 << 1); break; - case FEC_3_4: value |= (3 << 1); break; - case FEC_5_6: value |= (5 << 1); break; - case FEC_7_8: value |= (7 << 1); break; - default: - case FEC_1_2: value |= (1 << 1); break; - } - dib7000m_write_word(state, 267 + state->reg_offs, value); - - /* offset loop parameters */ - - /* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */ - dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80); - - /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ - dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3)); - - /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */ - dib7000m_write_word(state, 32, (0 << 4) | 0x3); - - /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */ - dib7000m_write_word(state, 33, (0 << 4) | 0x5); - - /* P_dvsy_sync_wait */ - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_8K: value = 256; break; - case TRANSMISSION_MODE_4K: value = 128; break; - case TRANSMISSION_MODE_2K: - default: value = 64; break; - } - switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_16: value *= 2; break; - case GUARD_INTERVAL_1_8: value *= 4; break; - case GUARD_INTERVAL_1_4: value *= 8; break; - default: - case GUARD_INTERVAL_1_32: value *= 1; break; - } - state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO - - /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */ - /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (1 == 1 || state->revision > 0x4000) - state->div_force_off = 0; - else - state->div_force_off = 1; - dib7000m_set_diversity_in(&state->demod, state->div_state); - - /* channel estimation fine configuration */ - switch (ch->u.ofdm.constellation) { - case QAM_64: - est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ - est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ - est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ - break; - case QAM_16: - est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ - est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ - est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ - break; - default: - est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ - est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ - est[2] = 0x0333; /* P_adp_regul_ext 0.1 */ - est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ - break; - } - for (value = 0; value < 4; value++) - dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]); - - // set power-up level: autosearch - dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); -} - -static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) -{ - struct dib7000m_state *state = demod->demodulator_priv; - struct dvb_frontend_parameters schan; - int ret = 0; - u32 value, factor; - - schan = *ch; - - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_3_4; - schan.u.ofdm.hierarchy_information = 0; - - dib7000m_set_channel(state, &schan, 7); - - factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); - if (factor >= 5000) - factor = 1; - else - factor = 6; - - // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->internal_clk * factor; - ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time - ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->internal_clk * factor; - ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time - ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->internal_clk * factor; - ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time - ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time - - // start search - value = dib7000m_read_word(state, 0); - ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9))); - - /* clear n_irq_pending */ - if (state->revision == 0x4000) - dib7000m_write_word(state, 1793, 0); - else - dib7000m_read_word(state, 537); - - ret |= dib7000m_write_word(state, 0, (u16) value); - - return ret; -} - -static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg) -{ - u16 irq_pending = dib7000m_read_word(state, reg); - - if (irq_pending & 0x1) { // failed - dprintk( "autosearch failed"); - return 1; - } - - if (irq_pending & 0x2) { // succeeded - dprintk( "autosearch succeeded"); - return 2; - } - return 0; // still pending -} - -static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) -{ - struct dib7000m_state *state = demod->demodulator_priv; - if (state->revision == 0x4000) - return dib7000m_autosearch_irq(state, 1793); - else - return dib7000m_autosearch_irq(state, 537); -} - -static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) -{ - struct dib7000m_state *state = demod->demodulator_priv; - int ret = 0; - u16 value; - - // we are already tuned - just resuming from suspend - if (ch != NULL) - dib7000m_set_channel(state, ch, 0); - else - return -EINVAL; - - // restart demod - ret |= dib7000m_write_word(state, 898, 0x4000); - ret |= dib7000m_write_word(state, 898, 0x0000); - msleep(45); - - dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); - /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ - ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); - - // never achieved a lock before - wait for timfreq to update - if (state->timf == 0) - msleep(200); - - //dump_reg(state); - /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ - value = (6 << 8) | 0x80; - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: value |= (7 << 12); break; - case TRANSMISSION_MODE_4K: value |= (8 << 12); break; - default: - case TRANSMISSION_MODE_8K: value |= (9 << 12); break; - } - ret |= dib7000m_write_word(state, 26, value); - - /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ - value = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: value |= 0x6; break; - case TRANSMISSION_MODE_4K: value |= 0x7; break; - default: - case TRANSMISSION_MODE_8K: value |= 0x8; break; - } - ret |= dib7000m_write_word(state, 32, value); - - /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ - value = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: value |= 0x6; break; - case TRANSMISSION_MODE_4K: value |= 0x7; break; - default: - case TRANSMISSION_MODE_8K: value |= 0x8; break; - } - ret |= dib7000m_write_word(state, 33, value); - - // we achieved a lock - it's time to update the timf freq - if ((dib7000m_read_word(state, 535) >> 6) & 0x1) - dib7000m_update_timf(state); - - dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - return ret; -} - -static int dib7000m_wakeup(struct dvb_frontend *demod) -{ - struct dib7000m_state *state = demod->demodulator_priv; - - dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); - - if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) - dprintk( "could not start Slow ADC"); - - return 0; -} - -static int dib7000m_sleep(struct dvb_frontend *demod) -{ - struct dib7000m_state *st = demod->demodulator_priv; - dib7000m_set_output_mode(st, OUTMODE_HIGH_Z); - dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY); - return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | - dib7000m_set_adc_state(st, DIBX000_ADC_OFF); -} - -static int dib7000m_identify(struct dib7000m_state *state) -{ - u16 value; - - if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { - dprintk( "wrong Vendor ID (0x%x)",value); - return -EREMOTEIO; - } - - state->revision = dib7000m_read_word(state, 897); - if (state->revision != 0x4000 && - state->revision != 0x4001 && - state->revision != 0x4002 && - state->revision != 0x4003) { - dprintk( "wrong Device ID (0x%x)",value); - return -EREMOTEIO; - } - - /* protect this driver to be used with 7000PC */ - if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { - dprintk( "this driver does not work with DiB7000PC"); - return -EREMOTEIO; - } - - switch (state->revision) { - case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break; - case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break; - case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break; - case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break; - } - - return 0; -} - - -static int dib7000m_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct dib7000m_state *state = fe->demodulator_priv; - u16 tps = dib7000m_read_word(state,480); - - fep->inversion = INVERSION_AUTO; - - fep->u.ofdm.bandwidth = state->current_bandwidth; - - switch ((tps >> 8) & 0x3) { - case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; - /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ - } - - switch (tps & 0x3) { - case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; - case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; - case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; - case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; - } - - switch ((tps >> 14) & 0x3) { - case 0: fep->u.ofdm.constellation = QPSK; break; - case 1: fep->u.ofdm.constellation = QAM_16; break; - case 2: - default: fep->u.ofdm.constellation = QAM_64; break; - } - - /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ - /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ - - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; - switch ((tps >> 5) & 0x7) { - case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; - case 7: - default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; - - } - - switch ((tps >> 2) & 0x7) { - case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; - case 7: - default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; - } - - /* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */ - - return 0; -} - -static int dib7000m_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct dib7000m_state *state = fe->demodulator_priv; - int time, ret; - - dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); - - state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); - - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, fep); - - /* start up the AGC */ - state->agc_state = 0; - do { - time = dib7000m_agc_startup(fe, fep); - if (time != -1) - msleep(time); - } while (time != -1); - - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || - fep->u.ofdm.constellation == QAM_AUTO || - fep->u.ofdm.code_rate_HP == FEC_AUTO) { - int i = 800, found; - - dib7000m_autosearch_start(fe, fep); - do { - msleep(1); - found = dib7000m_autosearch_is_irq(fe); - } while (found == 0 && i--); - - dprintk("autosearch returns: %d",found); - if (found == 0 || found == 1) - return 0; // no channel found - - dib7000m_get_frontend(fe, fep); - } - - ret = dib7000m_tune(fe, fep); - - /* make this a config parameter */ - dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return ret; -} - -static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) -{ - struct dib7000m_state *state = fe->demodulator_priv; - u16 lock = dib7000m_read_word(state, 535); - - *stat = 0; - - if (lock & 0x8000) - *stat |= FE_HAS_SIGNAL; - if (lock & 0x3000) - *stat |= FE_HAS_CARRIER; - if (lock & 0x0100) - *stat |= FE_HAS_VITERBI; - if (lock & 0x0010) - *stat |= FE_HAS_SYNC; - if (lock & 0x0008) - *stat |= FE_HAS_LOCK; - - return 0; -} - -static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct dib7000m_state *state = fe->demodulator_priv; - *ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527); - return 0; -} - -static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) -{ - struct dib7000m_state *state = fe->demodulator_priv; - *unc = dib7000m_read_word(state, 534); - return 0; -} - -static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct dib7000m_state *state = fe->demodulator_priv; - u16 val = dib7000m_read_word(state, 390); - *strength = 65535 - val; - return 0; -} - -static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - *snr = 0x0000; - return 0; -} - -static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void dib7000m_release(struct dvb_frontend *demod) -{ - struct dib7000m_state *st = demod->demodulator_priv; - dibx000_exit_i2c_master(&st->i2c_master); - kfree(st); -} - -struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating) -{ - struct dib7000m_state *st = demod->demodulator_priv; - return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); -} -EXPORT_SYMBOL(dib7000m_get_i2c_master); - -int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) -{ - struct dib7000m_state *state = fe->demodulator_priv; - u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef; - val |= (onoff & 0x1) << 4; - dprintk("PID filter enabled %d", onoff); - return dib7000m_write_word(state, 294 + state->reg_offs, val); -} -EXPORT_SYMBOL(dib7000m_pid_filter_ctrl); - -int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) -{ - struct dib7000m_state *state = fe->demodulator_priv; - dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); - return dib7000m_write_word(state, 300 + state->reg_offs + id, - onoff ? (1 << 13) | pid : 0); -} -EXPORT_SYMBOL(dib7000m_pid_filter); - -#if 0 -/* used with some prototype boards */ -int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, - u8 default_addr, struct dib7000m_config cfg[]) -{ - struct dib7000m_state st = { .i2c_adap = i2c }; - int k = 0; - u8 new_addr = 0; - - for (k = no_of_demods-1; k >= 0; k--) { - st.cfg = cfg[k]; - - /* designated i2c address */ - new_addr = (0x40 + k) << 1; - st.i2c_addr = new_addr; - if (dib7000m_identify(&st) != 0) { - st.i2c_addr = default_addr; - if (dib7000m_identify(&st) != 0) { - dprintk("DiB7000M #%d: not identified", k); - return -EIO; - } - } - - /* start diversity to pull_down div_str - just for i2c-enumeration */ - dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY); - - dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output - - /* set new i2c address and force divstart */ - dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); - - dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); - } - - for (k = 0; k < no_of_demods; k++) { - st.cfg = cfg[k]; - st.i2c_addr = (0x40 + k) << 1; - - // unforce divstr - dib7000m_write_word(&st,1794, st.i2c_addr << 2); - - /* deactivate div - it was just for i2c-enumeration */ - dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z); - } - - return 0; -} -EXPORT_SYMBOL(dib7000m_i2c_enumeration); -#endif - -static struct dvb_frontend_ops dib7000m_ops; -struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg) -{ - struct dvb_frontend *demod; - struct dib7000m_state *st; - st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL); - if (st == NULL) - return NULL; - - memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config)); - st->i2c_adap = i2c_adap; - st->i2c_addr = i2c_addr; - - demod = &st->demod; - demod->demodulator_priv = st; - memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); - - st->timf_default = cfg->bw->timf; - - if (dib7000m_identify(st) != 0) - goto error; - - if (st->revision == 0x4000) - dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr); - else - dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr); - - dib7000m_demod_reset(st); - - return demod; - -error: - kfree(st); - return NULL; -} -EXPORT_SYMBOL(dib7000m_attach); - -static struct dvb_frontend_ops dib7000m_ops = { - .info = { - .name = "DiBcom 7000MA/MB/PA/PB/MC", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = dib7000m_release, - - .init = dib7000m_wakeup, - .sleep = dib7000m_sleep, - - .set_frontend = dib7000m_set_frontend, - .get_tune_settings = dib7000m_fe_get_tune_settings, - .get_frontend = dib7000m_get_frontend, - - .read_status = dib7000m_read_status, - .read_ber = dib7000m_read_ber, - .read_signal_strength = dib7000m_read_signal_strength, - .read_snr = dib7000m_read_snr, - .read_ucblocks = dib7000m_read_unc_blocks, -}; - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000m.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000m.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000m.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000m.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -#ifndef DIB7000M_H -#define DIB7000M_H - -#include "dibx000_common.h" - -struct dib7000m_config { - u8 dvbt_mode; - u8 output_mpeg2_in_188_bytes; - u8 hostbus_diversity; - u8 tuner_is_baseband; - u8 mobile_mode; - int (*update_lna) (struct dvb_frontend *, u16 agc_global); - - u8 agc_config_count; - struct dibx000_agc_config *agc; - - struct dibx000_bandwidth_config *bw; - -#define DIB7000M_GPIO_DEFAULT_DIRECTIONS 0xffff - u16 gpio_dir; -#define DIB7000M_GPIO_DEFAULT_VALUES 0x0000 - u16 gpio_val; -#define DIB7000M_GPIO_PWM_POS0(v) ((v & 0xf) << 12) -#define DIB7000M_GPIO_PWM_POS1(v) ((v & 0xf) << 8 ) -#define DIB7000M_GPIO_PWM_POS2(v) ((v & 0xf) << 4 ) -#define DIB7000M_GPIO_PWM_POS3(v) (v & 0xf) -#define DIB7000M_GPIO_DEFAULT_PWM_POS 0xffff - u16 gpio_pwm_pos; - - u16 pwm_freq_div; - - u8 quartz_direct; - - u8 input_clk_is_div_2; - - int (*agc_control) (struct dvb_frontend *, u8 before); -}; - -#define DEFAULT_DIB7000M_I2C_ADDRESS 18 - -#if defined(CONFIG_DVB_DIB7000M) || (defined(CONFIG_DVB_DIB7000M_MODULE) && \ - defined(MODULE)) -extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap, - u8 i2c_addr, - struct dib7000m_config *cfg); -extern struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *, - enum dibx000_i2c_interface, - int); -extern int dib7000m_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); -extern int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); -#else -static inline -struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap, - u8 i2c_addr, struct dib7000m_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline -struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *demod, - enum dibx000_i2c_interface intf, - int gating) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static inline int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, - u16 pid, u8 onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, - uint8_t onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} -#endif - -/* TODO -extern INT dib7000m_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); -extern INT dib7000m_enable_vbg_voltage(struct dibDemod *demod); -extern void dib7000m_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff); -extern USHORT dib7000m_get_current_agc_global(struct dibDemod *demod); -*/ - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000p.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000p.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000p.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000p.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2365 +0,0 @@ -/* - * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). - * - * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) - * - * 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, version 2. - */ -#include -#include -#include - -#include "dvb_math.h" -#include "dvb_frontend.h" - -#include "dib7000p.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); - -static int buggy_sfn_workaround; -module_param(buggy_sfn_workaround, int, 0644); -MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); - -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) - -struct i2c_device { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; -}; - -struct dib7000p_state { - struct dvb_frontend demod; - struct dib7000p_config cfg; - - u8 i2c_addr; - struct i2c_adapter *i2c_adap; - - struct dibx000_i2c_master i2c_master; - - u16 wbd_ref; - - u8 current_band; - u32 current_bandwidth; - struct dibx000_agc_config *current_agc; - u32 timf; - - u8 div_force_off:1; - u8 div_state:1; - u16 div_sync_wait; - - u8 agc_state; - - u16 gpio_dir; - u16 gpio_val; - - u8 sfn_workaround_active:1; - -#define SOC7090 0x7090 - u16 version; - - u16 tuner_enable; - struct i2c_adapter dib7090_tuner_adap; -}; - -enum dib7000p_power_mode { - DIB7000P_POWER_ALL = 0, - DIB7000P_POWER_ANALOG_ADC, - DIB7000P_POWER_INTERFACE_ONLY, -}; - -static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode); -static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); - -static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) -{ - u8 wb[2] = { reg >> 8, reg & 0xff }; - u8 rb[2]; - struct i2c_msg msg[2] = { - {.addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2}, - {.addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2}, - }; - - if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d", reg); - - return (rb[0] << 8) | rb[1]; -} - -static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) -{ - u8 b[4] = { - (reg >> 8) & 0xff, reg & 0xff, - (val >> 8) & 0xff, val & 0xff, - }; - struct i2c_msg msg = { - .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 - }; - return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; -} - -static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf) -{ - u16 l = 0, r, *n; - n = buf; - l = *n++; - while (l) { - r = *n++; - - do { - dib7000p_write_word(state, r, *n++); - r++; - } while (--l); - l = *n++; - } -} - -static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) -{ - int ret = 0; - u16 outreg, fifo_threshold, smo_mode; - - outreg = 0; - fifo_threshold = 1792; - smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); - - dprintk("setting output mode for demod %p to %d", &state->demod, mode); - - switch (mode) { - case OUTMODE_MPEG2_PAR_GATED_CLK: - outreg = (1 << 10); /* 0x0400 */ - break; - case OUTMODE_MPEG2_PAR_CONT_CLK: - outreg = (1 << 10) | (1 << 6); /* 0x0440 */ - break; - case OUTMODE_MPEG2_SERIAL: - outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */ - break; - case OUTMODE_DIVERSITY: - if (state->cfg.hostbus_diversity) - outreg = (1 << 10) | (4 << 6); /* 0x0500 */ - else - outreg = (1 << 11); - break; - case OUTMODE_MPEG2_FIFO: - smo_mode |= (3 << 1); - fifo_threshold = 512; - outreg = (1 << 10) | (5 << 6); - break; - case OUTMODE_ANALOG_ADC: - outreg = (1 << 10) | (3 << 6); - break; - case OUTMODE_HIGH_Z: - outreg = 0; - break; - default: - dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod); - break; - } - - if (state->cfg.output_mpeg2_in_188_bytes) - smo_mode |= (1 << 5); - - ret |= dib7000p_write_word(state, 235, smo_mode); - ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ - if (state->version != SOC7090) - ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */ - - return ret; -} - -static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) -{ - struct dib7000p_state *state = demod->demodulator_priv; - - if (state->div_force_off) { - dprintk("diversity combination deactivated - forced by COFDM parameters"); - onoff = 0; - dib7000p_write_word(state, 207, 0); - } else - dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); - - state->div_state = (u8) onoff; - - if (onoff) { - dib7000p_write_word(state, 204, 6); - dib7000p_write_word(state, 205, 16); - /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - } else { - dib7000p_write_word(state, 204, 1); - dib7000p_write_word(state, 205, 0); - } - - return 0; -} - -static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode) -{ - /* by default everything is powered off */ - u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff); - - /* now, depending on the requested mode, we power on */ - switch (mode) { - /* power up everything in the demod */ - case DIB7000P_POWER_ALL: - reg_774 = 0x0000; - reg_775 = 0x0000; - reg_776 = 0x0; - reg_899 = 0x0; - if (state->version == SOC7090) - reg_1280 &= 0x001f; - else - reg_1280 &= 0x01ff; - break; - - case DIB7000P_POWER_ANALOG_ADC: - /* dem, cfg, iqc, sad, agc */ - reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); - /* nud */ - reg_776 &= ~((1 << 0)); - /* Dout */ - if (state->version != SOC7090) - reg_1280 &= ~((1 << 11)); - reg_1280 &= ~(1 << 6); - /* fall through wanted to enable the interfaces */ - - /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ - case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ - if (state->version == SOC7090) - reg_1280 &= ~((1 << 7) | (1 << 5)); - else - reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); - break; - -/* TODO following stuff is just converted from the dib7000-driver - check when is used what */ - } - - dib7000p_write_word(state, 774, reg_774); - dib7000p_write_word(state, 775, reg_775); - dib7000p_write_word(state, 776, reg_776); - dib7000p_write_word(state, 899, reg_899); - dib7000p_write_word(state, 1280, reg_1280); - - return 0; -} - -static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no) -{ - u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909); - u16 reg; - - switch (no) { - case DIBX000_SLOW_ADC_ON: - if (state->version == SOC7090) { - reg = dib7000p_read_word(state, 1925); - - dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */ - - reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */ - msleep(200); - dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */ - - reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12)); - dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */ - } else { - reg_909 |= (1 << 1) | (1 << 0); - dib7000p_write_word(state, 909, reg_909); - reg_909 &= ~(1 << 1); - } - break; - - case DIBX000_SLOW_ADC_OFF: - if (state->version == SOC7090) { - reg = dib7000p_read_word(state, 1925); - dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */ - } else - reg_909 |= (1 << 1) | (1 << 0); - break; - - case DIBX000_ADC_ON: - reg_908 &= 0x0fff; - reg_909 &= 0x0003; - break; - - case DIBX000_ADC_OFF: - reg_908 |= (1 << 14) | (1 << 13) | (1 << 12); - reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); - break; - - case DIBX000_VBG_ENABLE: - reg_908 &= ~(1 << 15); - break; - - case DIBX000_VBG_DISABLE: - reg_908 |= (1 << 15); - break; - - default: - break; - } - -// dprintk( "908: %x, 909: %x\n", reg_908, reg_909); - - reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4; - reg_908 |= (state->cfg.enable_current_mirror & 1) << 7; - - dib7000p_write_word(state, 908, reg_908); - dib7000p_write_word(state, 909, reg_909); -} - -static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) -{ - u32 timf; - - // store the current bandwidth for later use - state->current_bandwidth = bw; - - if (state->timf == 0) { - dprintk("using default timf"); - timf = state->cfg.bw->timf; - } else { - dprintk("using updated timf"); - timf = state->timf; - } - - timf = timf * (bw / 50) / 160; - - dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); - dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff)); - - return 0; -} - -static int dib7000p_sad_calib(struct dib7000p_state *state) -{ -/* internal */ - dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); - - if (state->version == SOC7090) - dib7000p_write_word(state, 74, 2048); - else - dib7000p_write_word(state, 74, 776); - - /* do the calibration */ - dib7000p_write_word(state, 73, (1 << 0)); - dib7000p_write_word(state, 73, (0 << 0)); - - msleep(1); - - return 0; -} - -int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) -{ - struct dib7000p_state *state = demod->demodulator_priv; - if (value > 4095) - value = 4095; - state->wbd_ref = value; - return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value); -} -EXPORT_SYMBOL(dib7000p_set_wbd_ref); - -static void dib7000p_reset_pll(struct dib7000p_state *state) -{ - struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; - u16 clk_cfg0; - - if (state->version == SOC7090) { - dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv)); - - while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) - ; - - dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15)); - } else { - /* force PLL bypass */ - clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | - (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); - - dib7000p_write_word(state, 900, clk_cfg0); - - /* P_pll_cfg */ - dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); - clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); - dib7000p_write_word(state, 900, clk_cfg0); - } - - dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); - dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff)); - dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff)); - dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff)); - - dib7000p_write_word(state, 72, bw->sad_cfg); -} - -static u32 dib7000p_get_internal_freq(struct dib7000p_state *state) -{ - u32 internal = (u32) dib7000p_read_word(state, 18) << 16; - internal |= (u32) dib7000p_read_word(state, 19); - internal /= 1000; - - return internal; -} - -int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw) -{ - struct dib7000p_state *state = fe->demodulator_priv; - u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856); - u8 loopdiv, prediv; - u32 internal, xtal; - - /* get back old values */ - prediv = reg_1856 & 0x3f; - loopdiv = (reg_1856 >> 6) & 0x3f; - - if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) { - dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio); - reg_1856 &= 0xf000; - reg_1857 = dib7000p_read_word(state, 1857); - dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15)); - - dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f)); - - /* write new system clk into P_sec_len */ - internal = dib7000p_get_internal_freq(state); - xtal = (internal / loopdiv) * prediv; - internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */ - dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff)); - dib7000p_write_word(state, 19, (u16) (internal & 0xffff)); - - dib7000p_write_word(state, 1857, reg_1857 | (1 << 15)); - - while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) - dprintk("Waiting for PLL to lock"); - - return 0; - } - return -EIO; -} -EXPORT_SYMBOL(dib7000p_update_pll); - -static int dib7000p_reset_gpio(struct dib7000p_state *st) -{ - /* reset the GPIOs */ - dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos); - - dib7000p_write_word(st, 1029, st->gpio_dir); - dib7000p_write_word(st, 1030, st->gpio_val); - - /* TODO 1031 is P_gpio_od */ - - dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos); - - dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div); - return 0; -} - -static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val) -{ - st->gpio_dir = dib7000p_read_word(st, 1029); - st->gpio_dir &= ~(1 << num); /* reset the direction bit */ - st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ - dib7000p_write_word(st, 1029, st->gpio_dir); - - st->gpio_val = dib7000p_read_word(st, 1030); - st->gpio_val &= ~(1 << num); /* reset the direction bit */ - st->gpio_val |= (val & 0x01) << num; /* set the new value */ - dib7000p_write_word(st, 1030, st->gpio_val); - - return 0; -} - -int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val) -{ - struct dib7000p_state *state = demod->demodulator_priv; - return dib7000p_cfg_gpio(state, num, dir, val); -} -EXPORT_SYMBOL(dib7000p_set_gpio); - -static u16 dib7000p_defaults[] = { - // auto search configuration - 3, 2, - 0x0004, - 0x1000, - 0x0814, /* Equal Lock */ - - 12, 6, - 0x001b, - 0x7740, - 0x005b, - 0x8d80, - 0x01c9, - 0xc380, - 0x0000, - 0x0080, - 0x0000, - 0x0090, - 0x0001, - 0xd4c0, - - 1, 26, - 0x6680, - - /* set ADC level to -16 */ - 11, 79, - (1 << 13) - 825 - 117, - (1 << 13) - 837 - 117, - (1 << 13) - 811 - 117, - (1 << 13) - 766 - 117, - (1 << 13) - 737 - 117, - (1 << 13) - 693 - 117, - (1 << 13) - 648 - 117, - (1 << 13) - 619 - 117, - (1 << 13) - 575 - 117, - (1 << 13) - 531 - 117, - (1 << 13) - 501 - 117, - - 1, 142, - 0x0410, - - /* disable power smoothing */ - 8, 145, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - - 1, 154, - 1 << 13, - - 1, 168, - 0x0ccd, - - 1, 183, - 0x200f, - - 1, 212, - 0x169, - - 5, 187, - 0x023d, - 0x00a4, - 0x00a4, - 0x7ff0, - 0x3ccc, - - 1, 198, - 0x800, - - 1, 222, - 0x0010, - - 1, 235, - 0x0062, - - 2, 901, - 0x0006, - (3 << 10) | (1 << 6), - - 1, 905, - 0x2c8e, - - 0, -}; - -static int dib7000p_demod_reset(struct dib7000p_state *state) -{ - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); - - if (state->version == SOC7090) - dibx000_reset_i2c_master(&state->i2c_master); - - dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE); - - /* restart all parts */ - dib7000p_write_word(state, 770, 0xffff); - dib7000p_write_word(state, 771, 0xffff); - dib7000p_write_word(state, 772, 0x001f); - dib7000p_write_word(state, 898, 0x0003); - dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3))); - - dib7000p_write_word(state, 770, 0); - dib7000p_write_word(state, 771, 0); - dib7000p_write_word(state, 772, 0); - dib7000p_write_word(state, 898, 0); - dib7000p_write_word(state, 1280, 0); - - /* default */ - dib7000p_reset_pll(state); - - if (dib7000p_reset_gpio(state) != 0) - dprintk("GPIO reset was not successful."); - - if (state->version == SOC7090) { - dib7000p_write_word(state, 899, 0); - - /* impulse noise */ - dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */ - dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */ - dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */ - dib7000p_write_word(state, 273, (1<<6) | 30); - } - if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("OUTPUT_MODE could not be reset."); - - dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); - dib7000p_sad_calib(state); - dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF); - - /* unforce divstr regardless whether i2c enumeration was done or not */ - dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1)); - - dib7000p_set_bandwidth(state, 8000); - - if (state->version == SOC7090) { - dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */ - } else { - if (state->cfg.tuner_is_baseband) - dib7000p_write_word(state, 36, 0x0755); - else - dib7000p_write_word(state, 36, 0x1f55); - } - - dib7000p_write_tab(state, dib7000p_defaults); - - dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); - - return 0; -} - -static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) -{ - u16 tmp = 0; - tmp = dib7000p_read_word(state, 903); - dib7000p_write_word(state, 903, (tmp | 0x1)); - tmp = dib7000p_read_word(state, 900); - dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); -} - -static void dib7000p_restart_agc(struct dib7000p_state *state) -{ - // P_restart_iqc & P_restart_agc - dib7000p_write_word(state, 770, (1 << 11) | (1 << 9)); - dib7000p_write_word(state, 770, 0x0000); -} - -static int dib7000p_update_lna(struct dib7000p_state *state) -{ - u16 dyn_gain; - - if (state->cfg.update_lna) { - dyn_gain = dib7000p_read_word(state, 394); - if (state->cfg.update_lna(&state->demod, dyn_gain)) { - dib7000p_restart_agc(state); - return 1; - } - } - - return 0; -} - -static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) -{ - struct dibx000_agc_config *agc = NULL; - int i; - if (state->current_band == band && state->current_agc != NULL) - return 0; - state->current_band = band; - - for (i = 0; i < state->cfg.agc_config_count; i++) - if (state->cfg.agc[i].band_caps & band) { - agc = &state->cfg.agc[i]; - break; - } - - if (agc == NULL) { - dprintk("no valid AGC configuration found for band 0x%02x", band); - return -EINVAL; - } - - state->current_agc = agc; - - /* AGC */ - dib7000p_write_word(state, 75, agc->setup); - dib7000p_write_word(state, 76, agc->inv_gain); - dib7000p_write_word(state, 77, agc->time_stabiliz); - dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); - - // Demod AGC loop configuration - dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); - dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); - - /* AGC continued */ - dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", - state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); - - if (state->wbd_ref != 0) - dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); - else - dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); - - dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); - - dib7000p_write_word(state, 107, agc->agc1_max); - dib7000p_write_word(state, 108, agc->agc1_min); - dib7000p_write_word(state, 109, agc->agc2_max); - dib7000p_write_word(state, 110, agc->agc2_min); - dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); - dib7000p_write_word(state, 112, agc->agc1_pt3); - dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - return 0; -} - -static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz) -{ - u32 internal = dib7000p_get_internal_freq(state); - s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */ - u32 abs_offset_khz = ABS(offset_khz); - u32 dds = state->cfg.bw->ifreq & 0x1ffffff; - u8 invert = !!(state->cfg.bw->ifreq & (1 << 25)); - - dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert); - - if (offset_khz < 0) - unit_khz_dds_val *= -1; - - /* IF tuner */ - if (invert) - dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */ - else - dds += (abs_offset_khz * unit_khz_dds_val); - - if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */ - dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9))); - dib7000p_write_word(state, 22, (u16) (dds & 0xffff)); - } -} - -static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) -{ - struct dib7000p_state *state = demod->demodulator_priv; - int ret = -1; - u8 *agc_state = &state->agc_state; - u8 agc_split; - u16 reg; - u32 upd_demod_gain_period = 0x1000; - - switch (state->agc_state) { - case 0: - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); - if (state->version == SOC7090) { - reg = dib7000p_read_word(state, 0x79b) & 0xff00; - dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */ - dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF)); - - /* enable adc i & q */ - reg = dib7000p_read_word(state, 0x780); - dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7))); - } else { - dib7000p_set_adc_state(state, DIBX000_ADC_ON); - dib7000p_pll_clk_cfg(state); - } - - if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0) - return -1; - - dib7000p_set_dds(state, 0); - ret = 7; - (*agc_state)++; - break; - - case 1: - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000p_write_word(state, 78, 32768); - if (!state->current_agc->perform_agc_softsplit) { - /* we are using the wbd - so slow AGC startup */ - /* force 0 split on WBD and restart AGC */ - dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); - (*agc_state)++; - ret = 5; - } else { - /* default AGC startup */ - (*agc_state) = 4; - /* wait AGC rough lock time */ - ret = 7; - } - - dib7000p_restart_agc(state); - break; - - case 2: /* fast split search path after 5sec */ - dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ - dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ - (*agc_state)++; - ret = 14; - break; - - case 3: /* split search ended */ - agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */ - dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ - - dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ - dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ - - dib7000p_restart_agc(state); - - dprintk("SPLIT %p: %hd", demod, agc_split); - - (*agc_state)++; - ret = 5; - break; - - case 4: /* LNA startup */ - ret = 7; - - if (dib7000p_update_lna(state)) - ret = 5; - else - (*agc_state)++; - break; - - case 5: - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); - (*agc_state)++; - break; - default: - break; - } - return ret; -} - -static void dib7000p_update_timf(struct dib7000p_state *state) -{ - u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); - state->timf = timf * 160 / (state->current_bandwidth / 50); - dib7000p_write_word(state, 23, (u16) (timf >> 16)); - dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf); - -} - -u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) -{ - struct dib7000p_state *state = fe->demodulator_priv; - switch (op) { - case DEMOD_TIMF_SET: - state->timf = timf; - break; - case DEMOD_TIMF_UPDATE: - dib7000p_update_timf(state); - break; - case DEMOD_TIMF_GET: - break; - } - dib7000p_set_bandwidth(state, state->current_bandwidth); - return state->timf; -} -EXPORT_SYMBOL(dib7000p_ctrl_timf); - -static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) -{ - u16 value, est[4]; - - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - - /* nfft, guard, qam, alpha */ - value = 0; - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: - value |= (0 << 7); - break; - case TRANSMISSION_MODE_4K: - value |= (2 << 7); - break; - default: - case TRANSMISSION_MODE_8K: - value |= (1 << 7); - break; - } - switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_32: - value |= (0 << 5); - break; - case GUARD_INTERVAL_1_16: - value |= (1 << 5); - break; - case GUARD_INTERVAL_1_4: - value |= (3 << 5); - break; - default: - case GUARD_INTERVAL_1_8: - value |= (2 << 5); - break; - } - switch (ch->u.ofdm.constellation) { - case QPSK: - value |= (0 << 3); - break; - case QAM_16: - value |= (1 << 3); - break; - default: - case QAM_64: - value |= (2 << 3); - break; - } - switch (HIERARCHY_1) { - case HIERARCHY_2: - value |= 2; - break; - case HIERARCHY_4: - value |= 4; - break; - default: - case HIERARCHY_1: - value |= 1; - break; - } - dib7000p_write_word(state, 0, value); - dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ - - /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ - value = 0; - if (1 != 0) - value |= (1 << 6); - if (ch->u.ofdm.hierarchy_information == 1) - value |= (1 << 4); - if (1 == 1) - value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { - case FEC_2_3: - value |= (2 << 1); - break; - case FEC_3_4: - value |= (3 << 1); - break; - case FEC_5_6: - value |= (5 << 1); - break; - case FEC_7_8: - value |= (7 << 1); - break; - default: - case FEC_1_2: - value |= (1 << 1); - break; - } - dib7000p_write_word(state, 208, value); - - /* offset loop parameters */ - dib7000p_write_word(state, 26, 0x6680); - dib7000p_write_word(state, 32, 0x0003); - dib7000p_write_word(state, 29, 0x1273); - dib7000p_write_word(state, 33, 0x0005); - - /* P_dvsy_sync_wait */ - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_8K: - value = 256; - break; - case TRANSMISSION_MODE_4K: - value = 128; - break; - case TRANSMISSION_MODE_2K: - default: - value = 64; - break; - } - switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_16: - value *= 2; - break; - case GUARD_INTERVAL_1_8: - value *= 4; - break; - case GUARD_INTERVAL_1_4: - value *= 8; - break; - default: - case GUARD_INTERVAL_1_32: - value *= 1; - break; - } - if (state->cfg.diversity_delay == 0) - state->div_sync_wait = (value * 3) / 2 + 48; - else - state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; - - /* deactive the possibility of diversity reception if extended interleaver */ - state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; - dib7000p_set_diversity_in(&state->demod, state->div_state); - - /* channel estimation fine configuration */ - switch (ch->u.ofdm.constellation) { - case QAM_64: - est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ - est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ - est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ - break; - case QAM_16: - est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ - est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ - est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ - break; - default: - est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ - est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ - est[2] = 0x0333; /* P_adp_regul_ext 0.1 */ - est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ - break; - } - for (value = 0; value < 4; value++) - dib7000p_write_word(state, 187 + value, est[value]); -} - -static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) -{ - struct dib7000p_state *state = demod->demodulator_priv; - struct dvb_frontend_parameters schan; - u32 value, factor; - u32 internal = dib7000p_get_internal_freq(state); - - schan = *ch; - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_3_4; - schan.u.ofdm.hierarchy_information = 0; - - dib7000p_set_channel(state, &schan, 7); - - factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); - if (factor >= 5000) - factor = 1; - else - factor = 6; - - value = 30 * internal * factor; - dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); - dib7000p_write_word(state, 7, (u16) (value & 0xffff)); - value = 100 * internal * factor; - dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); - dib7000p_write_word(state, 9, (u16) (value & 0xffff)); - value = 500 * internal * factor; - dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); - dib7000p_write_word(state, 11, (u16) (value & 0xffff)); - - value = dib7000p_read_word(state, 0); - dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); - dib7000p_read_word(state, 1284); - dib7000p_write_word(state, 0, (u16) value); - - return 0; -} - -static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) -{ - struct dib7000p_state *state = demod->demodulator_priv; - u16 irq_pending = dib7000p_read_word(state, 1284); - - if (irq_pending & 0x1) - return 1; - - if (irq_pending & 0x2) - return 2; - - return 0; -} - -static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) -{ - static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 }; - static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, - 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, - 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, - 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, - 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, - 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, - 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, - 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, - 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, - 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, - 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, - 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, - 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, - 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, - 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255 - }; - - u32 xtal = state->cfg.bw->xtal_hz / 1000; - int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz; - int k; - int coef_re[8], coef_im[8]; - int bw_khz = bw; - u32 pha; - - dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); - - if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2) - return; - - bw_khz /= 100; - - dib7000p_write_word(state, 142, 0x0610); - - for (k = 0; k < 8; k++) { - pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff; - - if (pha == 0) { - coef_re[k] = 256; - coef_im[k] = 0; - } else if (pha < 256) { - coef_re[k] = sine[256 - (pha & 0xff)]; - coef_im[k] = sine[pha & 0xff]; - } else if (pha == 256) { - coef_re[k] = 0; - coef_im[k] = 256; - } else if (pha < 512) { - coef_re[k] = -sine[pha & 0xff]; - coef_im[k] = sine[256 - (pha & 0xff)]; - } else if (pha == 512) { - coef_re[k] = -256; - coef_im[k] = 0; - } else if (pha < 768) { - coef_re[k] = -sine[256 - (pha & 0xff)]; - coef_im[k] = -sine[pha & 0xff]; - } else if (pha == 768) { - coef_re[k] = 0; - coef_im[k] = -256; - } else { - coef_re[k] = sine[pha & 0xff]; - coef_im[k] = -sine[256 - (pha & 0xff)]; - } - - coef_re[k] *= notch[k]; - coef_re[k] += (1 << 14); - if (coef_re[k] >= (1 << 24)) - coef_re[k] = (1 << 24) - 1; - coef_re[k] /= (1 << 15); - - coef_im[k] *= notch[k]; - coef_im[k] += (1 << 14); - if (coef_im[k] >= (1 << 24)) - coef_im[k] = (1 << 24) - 1; - coef_im[k] /= (1 << 15); - - dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); - - dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); - dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); - dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); - } - dib7000p_write_word(state, 143, 0); -} - -static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) -{ - struct dib7000p_state *state = demod->demodulator_priv; - u16 tmp = 0; - - if (ch != NULL) - dib7000p_set_channel(state, ch, 0); - else - return -EINVAL; - - // restart demod - dib7000p_write_word(state, 770, 0x4000); - dib7000p_write_word(state, 770, 0x0000); - msleep(45); - - /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ - tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3); - if (state->sfn_workaround_active) { - dprintk("SFN workaround is active"); - tmp |= (1 << 9); - dib7000p_write_word(state, 166, 0x4000); - } else { - dib7000p_write_word(state, 166, 0x0000); - } - dib7000p_write_word(state, 29, tmp); - - // never achieved a lock with that bandwidth so far - wait for osc-freq to update - if (state->timf == 0) - msleep(200); - - /* offset loop parameters */ - - /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ - tmp = (6 << 8) | 0x80; - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: - tmp |= (2 << 12); - break; - case TRANSMISSION_MODE_4K: - tmp |= (3 << 12); - break; - default: - case TRANSMISSION_MODE_8K: - tmp |= (4 << 12); - break; - } - dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ - - /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ - tmp = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: - tmp |= 0x6; - break; - case TRANSMISSION_MODE_4K: - tmp |= 0x7; - break; - default: - case TRANSMISSION_MODE_8K: - tmp |= 0x8; - break; - } - dib7000p_write_word(state, 32, tmp); - - /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ - tmp = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: - tmp |= 0x6; - break; - case TRANSMISSION_MODE_4K: - tmp |= 0x7; - break; - default: - case TRANSMISSION_MODE_8K: - tmp |= 0x8; - break; - } - dib7000p_write_word(state, 33, tmp); - - tmp = dib7000p_read_word(state, 509); - if (!((tmp >> 6) & 0x1)) { - /* restart the fec */ - tmp = dib7000p_read_word(state, 771); - dib7000p_write_word(state, 771, tmp | (1 << 1)); - dib7000p_write_word(state, 771, tmp); - msleep(40); - tmp = dib7000p_read_word(state, 509); - } - // we achieved a lock - it's time to update the osc freq - if ((tmp >> 6) & 0x1) { - dib7000p_update_timf(state); - /* P_timf_alpha += 2 */ - tmp = dib7000p_read_word(state, 26); - dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12)); - } - - if (state->cfg.spur_protect) - dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - return 0; -} - -static int dib7000p_wakeup(struct dvb_frontend *demod) -{ - struct dib7000p_state *state = demod->demodulator_priv; - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); - dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); - if (state->version == SOC7090) - dib7000p_sad_calib(state); - return 0; -} - -static int dib7000p_sleep(struct dvb_frontend *demod) -{ - struct dib7000p_state *state = demod->demodulator_priv; - if (state->version == SOC7090) - return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); - return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); -} - -static int dib7000p_identify(struct dib7000p_state *st) -{ - u16 value; - dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); - - if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { - dprintk("wrong Vendor ID (read=0x%x)", value); - return -EREMOTEIO; - } - - if ((value = dib7000p_read_word(st, 769)) != 0x4000) { - dprintk("wrong Device ID (%x)", value); - return -EREMOTEIO; - } - - return 0; -} - -static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dib7000p_state *state = fe->demodulator_priv; - u16 tps = dib7000p_read_word(state, 463); - - fep->inversion = INVERSION_AUTO; - - fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth); - - switch ((tps >> 8) & 0x3) { - case 0: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - break; - case 1: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - break; - /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ - } - - switch (tps & 0x3) { - case 0: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; - break; - } - - switch ((tps >> 14) & 0x3) { - case 0: - fep->u.ofdm.constellation = QPSK; - break; - case 1: - fep->u.ofdm.constellation = QAM_16; - break; - case 2: - default: - fep->u.ofdm.constellation = QAM_64; - break; - } - - /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ - /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ - - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; - switch ((tps >> 5) & 0x7) { - case 1: - fep->u.ofdm.code_rate_HP = FEC_1_2; - break; - case 2: - fep->u.ofdm.code_rate_HP = FEC_2_3; - break; - case 3: - fep->u.ofdm.code_rate_HP = FEC_3_4; - break; - case 5: - fep->u.ofdm.code_rate_HP = FEC_5_6; - break; - case 7: - default: - fep->u.ofdm.code_rate_HP = FEC_7_8; - break; - - } - - switch ((tps >> 2) & 0x7) { - case 1: - fep->u.ofdm.code_rate_LP = FEC_1_2; - break; - case 2: - fep->u.ofdm.code_rate_LP = FEC_2_3; - break; - case 3: - fep->u.ofdm.code_rate_LP = FEC_3_4; - break; - case 5: - fep->u.ofdm.code_rate_LP = FEC_5_6; - break; - case 7: - default: - fep->u.ofdm.code_rate_LP = FEC_7_8; - break; - } - - /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */ - - return 0; -} - -static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dib7000p_state *state = fe->demodulator_priv; - int time, ret; - - if (state->version == SOC7090) { - dib7090_set_diversity_in(fe, 0); - dib7090_set_output_mode(fe, OUTMODE_HIGH_Z); - } else - dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); - - /* maybe the parameter has been changed */ - state->sfn_workaround_active = buggy_sfn_workaround; - - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, fep); - - /* start up the AGC */ - state->agc_state = 0; - do { - time = dib7000p_agc_startup(fe, fep); - if (time != -1) - msleep(time); - } while (time != -1); - - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { - int i = 800, found; - - dib7000p_autosearch_start(fe, fep); - do { - msleep(1); - found = dib7000p_autosearch_is_irq(fe); - } while (found == 0 && i--); - - dprintk("autosearch returns: %d", found); - if (found == 0 || found == 1) - return 0; - - dib7000p_get_frontend(fe, fep); - } - - ret = dib7000p_tune(fe, fep); - - /* make this a config parameter */ - if (state->version == SOC7090) - dib7090_set_output_mode(fe, state->cfg.output_mode); - else - dib7000p_set_output_mode(state, state->cfg.output_mode); - - return ret; -} - -static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat) -{ - struct dib7000p_state *state = fe->demodulator_priv; - u16 lock = dib7000p_read_word(state, 509); - - *stat = 0; - - if (lock & 0x8000) - *stat |= FE_HAS_SIGNAL; - if (lock & 0x3000) - *stat |= FE_HAS_CARRIER; - if (lock & 0x0100) - *stat |= FE_HAS_VITERBI; - if (lock & 0x0010) - *stat |= FE_HAS_SYNC; - if ((lock & 0x0038) == 0x38) - *stat |= FE_HAS_LOCK; - - return 0; -} - -static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber) -{ - struct dib7000p_state *state = fe->demodulator_priv; - *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501); - return 0; -} - -static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) -{ - struct dib7000p_state *state = fe->demodulator_priv; - *unc = dib7000p_read_word(state, 506); - return 0; -} - -static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength) -{ - struct dib7000p_state *state = fe->demodulator_priv; - u16 val = dib7000p_read_word(state, 394); - *strength = 65535 - val; - return 0; -} - -static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr) -{ - struct dib7000p_state *state = fe->demodulator_priv; - u16 val; - s32 signal_mant, signal_exp, noise_mant, noise_exp; - u32 result = 0; - - val = dib7000p_read_word(state, 479); - noise_mant = (val >> 4) & 0xff; - noise_exp = ((val & 0xf) << 2); - val = dib7000p_read_word(state, 480); - noise_exp += ((val >> 14) & 0x3); - if ((noise_exp & 0x20) != 0) - noise_exp -= 0x40; - - signal_mant = (val >> 6) & 0xFF; - signal_exp = (val & 0x3F); - if ((signal_exp & 0x20) != 0) - signal_exp -= 0x40; - - if (signal_mant != 0) - result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant); - else - result = intlog10(2) * 10 * signal_exp - 100; - - if (noise_mant != 0) - result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant); - else - result -= intlog10(2) * 10 * noise_exp - 100; - - *snr = result / ((1 << 24) / 10); - return 0; -} - -static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void dib7000p_release(struct dvb_frontend *demod) -{ - struct dib7000p_state *st = demod->demodulator_priv; - dibx000_exit_i2c_master(&st->i2c_master); - i2c_del_adapter(&st->dib7090_tuner_adap); - kfree(st); -} - -int dib7000pc_detection(struct i2c_adapter *i2c_adap) -{ - u8 tx[2], rx[2]; - struct i2c_msg msg[2] = { - {.addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2}, - {.addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2}, - }; - - tx[0] = 0x03; - tx[1] = 0x00; - - if (i2c_transfer(i2c_adap, msg, 2) == 2) - if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected"); - return 1; - } - - msg[0].addr = msg[1].addr = 0x40; - - if (i2c_transfer(i2c_adap, msg, 2) == 2) - if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected"); - return 1; - } - - dprintk("-D- DiB7000PC not detected"); - return 0; -} -EXPORT_SYMBOL(dib7000pc_detection); - -struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating) -{ - struct dib7000p_state *st = demod->demodulator_priv; - return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); -} -EXPORT_SYMBOL(dib7000p_get_i2c_master); - -int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) -{ - struct dib7000p_state *state = fe->demodulator_priv; - u16 val = dib7000p_read_word(state, 235) & 0xffef; - val |= (onoff & 0x1) << 4; - dprintk("PID filter enabled %d", onoff); - return dib7000p_write_word(state, 235, val); -} -EXPORT_SYMBOL(dib7000p_pid_filter_ctrl); - -int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) -{ - struct dib7000p_state *state = fe->demodulator_priv; - dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); - return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0); -} -EXPORT_SYMBOL(dib7000p_pid_filter); - -int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]) -{ - struct dib7000p_state *dpst; - int k = 0; - u8 new_addr = 0; - - dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL); - if (!dpst) - return -ENOMEM; - - dpst->i2c_adap = i2c; - - for (k = no_of_demods - 1; k >= 0; k--) { - dpst->cfg = cfg[k]; - - /* designated i2c address */ - if (cfg[k].default_i2c_addr != 0) - new_addr = cfg[k].default_i2c_addr + (k << 1); - else - new_addr = (0x40 + k) << 1; - dpst->i2c_addr = new_addr; - dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ - if (dib7000p_identify(dpst) != 0) { - dpst->i2c_addr = default_addr; - dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ - if (dib7000p_identify(dpst) != 0) { - dprintk("DiB7000P #%d: not identified\n", k); - kfree(dpst); - return -EIO; - } - } - - /* start diversity to pull_down div_str - just for i2c-enumeration */ - dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY); - - /* set new i2c address and force divstart */ - dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2); - - dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); - } - - for (k = 0; k < no_of_demods; k++) { - dpst->cfg = cfg[k]; - if (cfg[k].default_i2c_addr != 0) - dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1; - else - dpst->i2c_addr = (0x40 + k) << 1; - - // unforce divstr - dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2); - - /* deactivate div - it was just for i2c-enumeration */ - dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z); - } - - kfree(dpst); - return 0; -} -EXPORT_SYMBOL(dib7000p_i2c_enumeration); - -static const s32 lut_1000ln_mant[] = { - 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600 -}; - -static s32 dib7000p_get_adc_power(struct dvb_frontend *fe) -{ - struct dib7000p_state *state = fe->demodulator_priv; - u32 tmp_val = 0, exp = 0, mant = 0; - s32 pow_i; - u16 buf[2]; - u8 ix = 0; - - buf[0] = dib7000p_read_word(state, 0x184); - buf[1] = dib7000p_read_word(state, 0x185); - pow_i = (buf[0] << 16) | buf[1]; - dprintk("raw pow_i = %d", pow_i); - - tmp_val = pow_i; - while (tmp_val >>= 1) - exp++; - - mant = (pow_i * 1000 / (1 << exp)); - dprintk(" mant = %d exp = %d", mant / 1000, exp); - - ix = (u8) ((mant - 1000) / 100); /* index of the LUT */ - dprintk(" ix = %d", ix); - - pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908); - pow_i = (pow_i << 8) / 1000; - dprintk(" pow_i = %d", pow_i); - - return pow_i; -} - -static int map_addr_to_serpar_number(struct i2c_msg *msg) -{ - if ((msg->buf[0] <= 15)) - msg->buf[0] -= 1; - else if (msg->buf[0] == 17) - msg->buf[0] = 15; - else if (msg->buf[0] == 16) - msg->buf[0] = 17; - else if (msg->buf[0] == 19) - msg->buf[0] = 16; - else if (msg->buf[0] >= 21 && msg->buf[0] <= 25) - msg->buf[0] -= 3; - else if (msg->buf[0] == 28) - msg->buf[0] = 23; - else - return -EINVAL; - return 0; -} - -static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) -{ - struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); - u8 n_overflow = 1; - u16 i = 1000; - u16 serpar_num = msg[0].buf[0]; - - while (n_overflow == 1 && i) { - n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; - i--; - if (i == 0) - dprintk("Tuner ITF: write busy (overflow)"); - } - dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); - dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); - - return num; -} - -static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) -{ - struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); - u8 n_overflow = 1, n_empty = 1; - u16 i = 1000; - u16 serpar_num = msg[0].buf[0]; - u16 read_word; - - while (n_overflow == 1 && i) { - n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; - i--; - if (i == 0) - dprintk("TunerITF: read busy (overflow)"); - } - dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f)); - - i = 1000; - while (n_empty == 1 && i) { - n_empty = dib7000p_read_word(state, 1984) & 0x1; - i--; - if (i == 0) - dprintk("TunerITF: read busy (empty)"); - } - read_word = dib7000p_read_word(state, 1987); - msg[1].buf[0] = (read_word >> 8) & 0xff; - msg[1].buf[1] = (read_word) & 0xff; - - return num; -} - -static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) -{ - if (map_addr_to_serpar_number(&msg[0]) == 0) { /* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */ - if (num == 1) { /* write */ - return w7090p_tuner_write_serpar(i2c_adap, msg, 1); - } else { /* read */ - return w7090p_tuner_read_serpar(i2c_adap, msg, 2); - } - } - return num; -} - -int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address) -{ - struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); - u16 word; - - if (num == 1) { /* write */ - dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); - } else { - word = dib7000p_read_word(state, apb_address); - msg[1].buf[0] = (word >> 8) & 0xff; - msg[1].buf[1] = (word) & 0xff; - } - - return num; -} - -static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) -{ - struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); - - u16 apb_address = 0, word; - int i = 0; - switch (msg[0].buf[0]) { - case 0x12: - apb_address = 1920; - break; - case 0x14: - apb_address = 1921; - break; - case 0x24: - apb_address = 1922; - break; - case 0x1a: - apb_address = 1923; - break; - case 0x22: - apb_address = 1924; - break; - case 0x33: - apb_address = 1926; - break; - case 0x34: - apb_address = 1927; - break; - case 0x35: - apb_address = 1928; - break; - case 0x36: - apb_address = 1929; - break; - case 0x37: - apb_address = 1930; - break; - case 0x38: - apb_address = 1931; - break; - case 0x39: - apb_address = 1932; - break; - case 0x2a: - apb_address = 1935; - break; - case 0x2b: - apb_address = 1936; - break; - case 0x2c: - apb_address = 1937; - break; - case 0x2d: - apb_address = 1938; - break; - case 0x2e: - apb_address = 1939; - break; - case 0x2f: - apb_address = 1940; - break; - case 0x30: - apb_address = 1941; - break; - case 0x31: - apb_address = 1942; - break; - case 0x32: - apb_address = 1943; - break; - case 0x3e: - apb_address = 1944; - break; - case 0x3f: - apb_address = 1945; - break; - case 0x40: - apb_address = 1948; - break; - case 0x25: - apb_address = 914; - break; - case 0x26: - apb_address = 915; - break; - case 0x27: - apb_address = 916; - break; - case 0x28: - apb_address = 917; - break; - case 0x1d: - i = ((dib7000p_read_word(state, 72) >> 12) & 0x3); - word = dib7000p_read_word(state, 384 + i); - msg[1].buf[0] = (word >> 8) & 0xff; - msg[1].buf[1] = (word) & 0xff; - return num; - case 0x1f: - if (num == 1) { /* write */ - word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]); - word &= 0x3; - word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12); - dib7000p_write_word(state, 72, word); /* Set the proper input */ - return num; - } - } - - if (apb_address != 0) /* R/W acces via APB */ - return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address); - else /* R/W access via SERPAR */ - return w7090p_tuner_rw_serpar(i2c_adap, msg, num); - - return 0; -} - -static u32 dib7000p_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm dib7090_tuner_xfer_algo = { - .master_xfer = dib7090_tuner_xfer, - .functionality = dib7000p_i2c_func, -}; - -struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe) -{ - struct dib7000p_state *st = fe->demodulator_priv; - return &st->dib7090_tuner_adap; -} -EXPORT_SYMBOL(dib7090_get_i2c_tuner); - -static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive) -{ - u16 reg; - - /* drive host bus 2, 3, 4 */ - reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); - reg |= (drive << 12) | (drive << 6) | drive; - dib7000p_write_word(state, 1798, reg); - - /* drive host bus 5,6 */ - reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8)); - reg |= (drive << 8) | (drive << 2); - dib7000p_write_word(state, 1799, reg); - - /* drive host bus 7, 8, 9 */ - reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); - reg |= (drive << 12) | (drive << 6) | drive; - dib7000p_write_word(state, 1800, reg); - - /* drive host bus 10, 11 */ - reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8)); - reg |= (drive << 8) | (drive << 2); - dib7000p_write_word(state, 1801, reg); - - /* drive host bus 12, 13, 14 */ - reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); - reg |= (drive << 12) | (drive << 6) | drive; - dib7000p_write_word(state, 1802, reg); - - return 0; -} - -static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize) -{ - u32 quantif = 3; - u32 nom = (insertExtSynchro * P_Kin + syncSize); - u32 denom = P_Kout; - u32 syncFreq = ((nom << quantif) / denom); - - if ((syncFreq & ((1 << quantif) - 1)) != 0) - syncFreq = (syncFreq >> quantif) + 1; - else - syncFreq = (syncFreq >> quantif); - - if (syncFreq != 0) - syncFreq = syncFreq - 1; - - return syncFreq; -} - -static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize) -{ - u8 index_buf; - u16 rx_copy_buf[22]; - - dprintk("Configure DibStream Tx"); - for (index_buf = 0; index_buf < 22; index_buf++) - rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf); - - dib7000p_write_word(state, 1615, 1); - dib7000p_write_word(state, 1603, P_Kin); - dib7000p_write_word(state, 1605, P_Kout); - dib7000p_write_word(state, 1606, insertExtSynchro); - dib7000p_write_word(state, 1608, synchroMode); - dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff); - dib7000p_write_word(state, 1610, syncWord & 0xffff); - dib7000p_write_word(state, 1612, syncSize); - dib7000p_write_word(state, 1615, 0); - - for (index_buf = 0; index_buf < 22; index_buf++) - dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]); - - return 0; -} - -static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize, - u32 dataOutRate) -{ - u32 syncFreq; - - dprintk("Configure DibStream Rx"); - if ((P_Kin != 0) && (P_Kout != 0)) { - syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize); - dib7000p_write_word(state, 1542, syncFreq); - } - dib7000p_write_word(state, 1554, 1); - dib7000p_write_word(state, 1536, P_Kin); - dib7000p_write_word(state, 1537, P_Kout); - dib7000p_write_word(state, 1539, synchroMode); - dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff); - dib7000p_write_word(state, 1541, syncWord & 0xffff); - dib7000p_write_word(state, 1543, syncSize); - dib7000p_write_word(state, 1544, dataOutRate); - dib7000p_write_word(state, 1554, 0); - - return 0; -} - -static int dib7090_enDivOnHostBus(struct dib7000p_state *state) -{ - u16 reg; - - dprintk("Enable Diversity on host bus"); - reg = (1 << 8) | (1 << 5); - dib7000p_write_word(state, 1288, reg); - - return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); -} - -static int dib7090_enAdcOnHostBus(struct dib7000p_state *state) -{ - u16 reg; - - dprintk("Enable ADC on host bus"); - reg = (1 << 7) | (1 << 5); - dib7000p_write_word(state, 1288, reg); - - return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); -} - -static int dib7090_enMpegOnHostBus(struct dib7000p_state *state) -{ - u16 reg; - - dprintk("Enable Mpeg on host bus"); - reg = (1 << 9) | (1 << 5); - dib7000p_write_word(state, 1288, reg); - - return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); -} - -static int dib7090_enMpegInput(struct dib7000p_state *state) -{ - dprintk("Enable Mpeg input"); - return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ -} - -static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) -{ - u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1); - - dprintk("Enable Mpeg mux"); - dib7000p_write_word(state, 1287, reg); - - reg &= ~(1 << 7); - dib7000p_write_word(state, 1287, reg); - - reg = (1 << 4); - dib7000p_write_word(state, 1288, reg); - - return 0; -} - -static int dib7090_disableMpegMux(struct dib7000p_state *state) -{ - u16 reg; - - dprintk("Disable Mpeg mux"); - dib7000p_write_word(state, 1288, 0); - - reg = dib7000p_read_word(state, 1287); - reg &= ~(1 << 7); - dib7000p_write_word(state, 1287, reg); - - return 0; -} - -static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode) -{ - struct dib7000p_state *state = fe->demodulator_priv; - - switch (mode) { - case INPUT_MODE_DIVERSITY: - dprintk("Enable diversity INPUT"); - dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); - break; - case INPUT_MODE_MPEG: - dprintk("Enable Mpeg INPUT"); - dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ - break; - case INPUT_MODE_OFF: - default: - dprintk("Disable INPUT"); - dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0); - break; - } - return 0; -} - -static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) -{ - switch (onoff) { - case 0: /* only use the internal way - not the diversity input */ - dib7090_set_input_mode(fe, INPUT_MODE_MPEG); - break; - case 1: /* both ways */ - case 2: /* only the diversity input */ - dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY); - break; - } - - return 0; -} - -static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) -{ - struct dib7000p_state *state = fe->demodulator_priv; - - u16 outreg, smo_mode, fifo_threshold; - u8 prefer_mpeg_mux_use = 1; - int ret = 0; - - dib7090_host_bus_drive(state, 1); - - fifo_threshold = 1792; - smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); - outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1)); - - switch (mode) { - case OUTMODE_HIGH_Z: - outreg = 0; - break; - - case OUTMODE_MPEG2_SERIAL: - if (prefer_mpeg_mux_use) { - dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux"); - dib7090_enMpegOnHostBus(state); - dib7090_enMpegInput(state); - if (state->cfg.enMpegOutput == 1) - dib7090_enMpegMux(state, 3, 1, 1); - - } else { /* Use Smooth block */ - dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (2 << 6) | (0 << 1); - } - break; - - case OUTMODE_MPEG2_PAR_GATED_CLK: - if (prefer_mpeg_mux_use) { - dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); - dib7090_enMpegOnHostBus(state); - dib7090_enMpegInput(state); - if (state->cfg.enMpegOutput == 1) - dib7090_enMpegMux(state, 2, 0, 0); - } else { /* Use Smooth block */ - dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (0 << 6); - } - break; - - case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ - dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (1 << 6); - break; - - case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */ - dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (5 << 6); - smo_mode |= (3 << 1); - fifo_threshold = 512; - break; - - case OUTMODE_DIVERSITY: - dprintk("Sip 7090P setting output mode MODE_DIVERSITY"); - dib7090_disableMpegMux(state); - dib7090_enDivOnHostBus(state); - break; - - case OUTMODE_ANALOG_ADC: - dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC"); - dib7090_enAdcOnHostBus(state); - break; - } - - if (state->cfg.output_mpeg2_in_188_bytes) - smo_mode |= (1 << 5); - - ret |= dib7000p_write_word(state, 235, smo_mode); - ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ - ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */ - - return ret; -} - -int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - struct dib7000p_state *state = fe->demodulator_priv; - u16 en_cur_state; - - dprintk("sleep dib7090: %d", onoff); - - en_cur_state = dib7000p_read_word(state, 1922); - - if (en_cur_state > 0xff) - state->tuner_enable = en_cur_state; - - if (onoff) - en_cur_state &= 0x00ff; - else { - if (state->tuner_enable != 0) - en_cur_state = state->tuner_enable; - } - - dib7000p_write_word(state, 1922, en_cur_state); - - return 0; -} -EXPORT_SYMBOL(dib7090_tuner_sleep); - -int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) -{ - dprintk("AGC restart callback: %d", restart); - return 0; -} -EXPORT_SYMBOL(dib7090_agc_restart); - -int dib7090_get_adc_power(struct dvb_frontend *fe) -{ - return dib7000p_get_adc_power(fe); -} -EXPORT_SYMBOL(dib7090_get_adc_power); - -int dib7090_slave_reset(struct dvb_frontend *fe) -{ - struct dib7000p_state *state = fe->demodulator_priv; - u16 reg; - - reg = dib7000p_read_word(state, 1794); - dib7000p_write_word(state, 1794, reg | (4 << 12)); - - dib7000p_write_word(state, 1032, 0xffff); - return 0; -} -EXPORT_SYMBOL(dib7090_slave_reset); - -static struct dvb_frontend_ops dib7000p_ops; -struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) -{ - struct dvb_frontend *demod; - struct dib7000p_state *st; - st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL); - if (st == NULL) - return NULL; - - memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config)); - st->i2c_adap = i2c_adap; - st->i2c_addr = i2c_addr; - st->gpio_val = cfg->gpio_val; - st->gpio_dir = cfg->gpio_dir; - - /* Ensure the output mode remains at the previous default if it's - * not specifically set by the caller. - */ - if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) - st->cfg.output_mode = OUTMODE_MPEG2_FIFO; - - demod = &st->demod; - demod->demodulator_priv = st; - memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops)); - - dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */ - - if (dib7000p_identify(st) != 0) - goto error; - - st->version = dib7000p_read_word(st, 897); - - /* FIXME: make sure the dev.parent field is initialized, or else - request_firmware() will hit an OOPS (this should be moved somewhere - more common) */ - - dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); - - /* init 7090 tuner adapter */ - strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name)); - st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo; - st->dib7090_tuner_adap.algo_data = NULL; - st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent; - i2c_set_adapdata(&st->dib7090_tuner_adap, st); - i2c_add_adapter(&st->dib7090_tuner_adap); - - dib7000p_demod_reset(st); - - if (st->version == SOC7090) { - dib7090_set_output_mode(demod, st->cfg.output_mode); - dib7090_set_diversity_in(demod, 0); - } - - return demod; - -error: - kfree(st); - return NULL; -} -EXPORT_SYMBOL(dib7000p_attach); - -static struct dvb_frontend_ops dib7000p_ops = { - .info = { - .name = "DiBcom 7000PC", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, - }, - - .release = dib7000p_release, - - .init = dib7000p_wakeup, - .sleep = dib7000p_sleep, - - .set_frontend = dib7000p_set_frontend, - .get_tune_settings = dib7000p_fe_get_tune_settings, - .get_frontend = dib7000p_get_frontend, - - .read_status = dib7000p_read_status, - .read_ber = dib7000p_read_ber, - .read_signal_strength = dib7000p_read_signal_strength, - .read_snr = dib7000p_read_snr, - .read_ucblocks = dib7000p_read_unc_blocks, -}; - -MODULE_AUTHOR("Olivier Grenie "); -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000p.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000p.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000p.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib7000p.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +0,0 @@ -#ifndef DIB7000P_H -#define DIB7000P_H - -#include "dibx000_common.h" - -struct dib7000p_config { - u8 output_mpeg2_in_188_bytes; - u8 hostbus_diversity; - u8 tuner_is_baseband; - int (*update_lna) (struct dvb_frontend *, u16 agc_global); - - u8 agc_config_count; - struct dibx000_agc_config *agc; - struct dibx000_bandwidth_config *bw; - -#define DIB7000P_GPIO_DEFAULT_DIRECTIONS 0xffff - u16 gpio_dir; -#define DIB7000P_GPIO_DEFAULT_VALUES 0x0000 - u16 gpio_val; -#define DIB7000P_GPIO_PWM_POS0(v) ((v & 0xf) << 12) -#define DIB7000P_GPIO_PWM_POS1(v) ((v & 0xf) << 8 ) -#define DIB7000P_GPIO_PWM_POS2(v) ((v & 0xf) << 4 ) -#define DIB7000P_GPIO_PWM_POS3(v) (v & 0xf) -#define DIB7000P_GPIO_DEFAULT_PWM_POS 0xffff - u16 gpio_pwm_pos; - - u16 pwm_freq_div; - - u8 quartz_direct; - - u8 spur_protect; - - int (*agc_control) (struct dvb_frontend *, u8 before); - - u8 output_mode; - u8 disable_sample_and_hold:1; - - u8 enable_current_mirror:1; - u16 diversity_delay; - - u8 default_i2c_addr; - u8 enMpegOutput:1; -}; - -#define DEFAULT_DIB7000P_I2C_ADDRESS 18 - -#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \ - defined(MODULE)) -extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); -extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); -extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); -extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); -extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); -extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); -extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); -extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw); -extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf); -extern int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart); -extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff); -extern int dib7090_get_adc_power(struct dvb_frontend *fe); -extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe); -extern int dib7090_slave_reset(struct dvb_frontend *fe); -#else -static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} - -static inline int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib7090_get_adc_power(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int dib7090_slave_reset(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib8000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib8000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib8000.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib8000.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2557 +0,0 @@ -/* - * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T). - * - * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/) - * - * 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, version 2. - */ -#include -#include -#include -#include "dvb_math.h" - -#include "dvb_frontend.h" - -#include "dib8000.h" - -#define LAYER_ALL -1 -#define LAYER_A 1 -#define LAYER_B 2 -#define LAYER_C 3 - -#define FE_CALLBACK_TIME_NEVER 0xffffffff -#define MAX_NUMBER_OF_FRONTENDS 6 - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); - -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) - -#define FE_STATUS_TUNE_FAILED 0 - -struct i2c_device { - struct i2c_adapter *adap; - u8 addr; -}; - -struct dib8000_state { - struct dib8000_config cfg; - - struct i2c_device i2c; - - struct dibx000_i2c_master i2c_master; - - u16 wbd_ref; - - u8 current_band; - u32 current_bandwidth; - struct dibx000_agc_config *current_agc; - u32 timf; - u32 timf_default; - - u8 div_force_off:1; - u8 div_state:1; - u16 div_sync_wait; - - u8 agc_state; - u8 differential_constellation; - u8 diversity_onoff; - - s16 ber_monitored_layer; - u16 gpio_dir; - u16 gpio_val; - - u16 revision; - u8 isdbt_cfg_loaded; - enum frontend_tune_state tune_state; - u32 status; - - struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; -}; - -enum dib8000_power_mode { - DIB8000M_POWER_ALL = 0, - DIB8000M_POWER_INTERFACE_ONLY, -}; - -static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) -{ - u8 wb[2] = { reg >> 8, reg & 0xff }; - u8 rb[2]; - struct i2c_msg msg[2] = { - {.addr = i2c->addr >> 1,.flags = 0,.buf = wb,.len = 2}, - {.addr = i2c->addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2}, - }; - - if (i2c_transfer(i2c->adap, msg, 2) != 2) - dprintk("i2c read error on %d", reg); - - return (rb[0] << 8) | rb[1]; -} - -static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) -{ - return dib8000_i2c_read16(&state->i2c, reg); -} - -static u32 dib8000_read32(struct dib8000_state *state, u16 reg) -{ - u16 rw[2]; - - rw[0] = dib8000_read_word(state, reg + 0); - rw[1] = dib8000_read_word(state, reg + 1); - - return ((rw[0] << 16) | (rw[1])); -} - -static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) -{ - u8 b[4] = { - (reg >> 8) & 0xff, reg & 0xff, - (val >> 8) & 0xff, val & 0xff, - }; - struct i2c_msg msg = { - .addr = i2c->addr >> 1,.flags = 0,.buf = b,.len = 4 - }; - return i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; -} - -static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) -{ - return dib8000_i2c_write16(&state->i2c, reg, val); -} - -static const s16 coeff_2k_sb_1seg_dqpsk[8] = { - (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, - (920 << 5) | 0x09 -}; - -static const s16 coeff_2k_sb_1seg[8] = { - (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f -}; - -static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { - (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, - (-931 << 5) | 0x0f -}; - -static const s16 coeff_2k_sb_3seg_0dqpsk[8] = { - (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, - (982 << 5) | 0x0c -}; - -static const s16 coeff_2k_sb_3seg_1dqpsk[8] = { - (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, - (-720 << 5) | 0x0d -}; - -static const s16 coeff_2k_sb_3seg[8] = { - (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, - (-610 << 5) | 0x0a -}; - -static const s16 coeff_4k_sb_1seg_dqpsk[8] = { - (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, - (-922 << 5) | 0x0d -}; - -static const s16 coeff_4k_sb_1seg[8] = { - (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, - (-655 << 5) | 0x0a -}; - -static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { - (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, - (-958 << 5) | 0x13 -}; - -static const s16 coeff_4k_sb_3seg_0dqpsk[8] = { - (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, - (-568 << 5) | 0x0f -}; - -static const s16 coeff_4k_sb_3seg_1dqpsk[8] = { - (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, - (-848 << 5) | 0x13 -}; - -static const s16 coeff_4k_sb_3seg[8] = { - (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, - (-869 << 5) | 0x13 -}; - -static const s16 coeff_8k_sb_1seg_dqpsk[8] = { - (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, - (-598 << 5) | 0x10 -}; - -static const s16 coeff_8k_sb_1seg[8] = { - (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, - (585 << 5) | 0x0f -}; - -static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { - (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, - (0 << 5) | 0x14 -}; - -static const s16 coeff_8k_sb_3seg_0dqpsk[8] = { - (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, - (-877 << 5) | 0x15 -}; - -static const s16 coeff_8k_sb_3seg_1dqpsk[8] = { - (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, - (-921 << 5) | 0x14 -}; - -static const s16 coeff_8k_sb_3seg[8] = { - (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, - (690 << 5) | 0x14 -}; - -static const s16 ana_fe_coeff_3seg[24] = { - 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017 -}; - -static const s16 ana_fe_coeff_1seg[24] = { - 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003 -}; - -static const s16 ana_fe_coeff_13seg[24] = { - 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1 -}; - -static u16 fft_to_mode(struct dib8000_state *state) -{ - u16 mode; - switch (state->fe[0]->dtv_property_cache.transmission_mode) { - case TRANSMISSION_MODE_2K: - mode = 1; - break; - case TRANSMISSION_MODE_4K: - mode = 2; - break; - default: - case TRANSMISSION_MODE_AUTO: - case TRANSMISSION_MODE_8K: - mode = 3; - break; - } - return mode; -} - -static void dib8000_set_acquisition_mode(struct dib8000_state *state) -{ - u16 nud = dib8000_read_word(state, 298); - nud |= (1 << 3) | (1 << 0); - dprintk("acquisition mode activated"); - dib8000_write_word(state, 298, nud); -} -static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) -{ - struct dib8000_state *state = fe->demodulator_priv; - - u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */ - - outreg = 0; - fifo_threshold = 1792; - smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); - - dprintk("-I- Setting output mode for demod %p to %d", - &state->fe[0], mode); - - switch (mode) { - case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock - outreg = (1 << 10); /* 0x0400 */ - break; - case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock - outreg = (1 << 10) | (1 << 6); /* 0x0440 */ - break; - case OUTMODE_MPEG2_SERIAL: // STBs with serial input - outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ - break; - case OUTMODE_DIVERSITY: - if (state->cfg.hostbus_diversity) { - outreg = (1 << 10) | (4 << 6); /* 0x0500 */ - sram &= 0xfdff; - } else - sram |= 0x0c00; - break; - case OUTMODE_MPEG2_FIFO: // e.g. USB feeding - smo_mode |= (3 << 1); - fifo_threshold = 512; - outreg = (1 << 10) | (5 << 6); - break; - case OUTMODE_HIGH_Z: // disable - outreg = 0; - break; - - case OUTMODE_ANALOG_ADC: - outreg = (1 << 10) | (3 << 6); - dib8000_set_acquisition_mode(state); - break; - - default: - dprintk("Unhandled output_mode passed to be set for demod %p", - &state->fe[0]); - return -EINVAL; - } - - if (state->cfg.output_mpeg2_in_188_bytes) - smo_mode |= (1 << 5); - - dib8000_write_word(state, 299, smo_mode); - dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */ - dib8000_write_word(state, 1286, outreg); - dib8000_write_word(state, 1291, sram); - - return 0; -} - -static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff) -{ - struct dib8000_state *state = fe->demodulator_priv; - u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0; - - if (!state->differential_constellation) { - dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1 - dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2 - } else { - dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0 - dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0 - } - state->diversity_onoff = onoff; - - switch (onoff) { - case 0: /* only use the internal way - not the diversity input */ - dib8000_write_word(state, 270, 1); - dib8000_write_word(state, 271, 0); - break; - case 1: /* both ways */ - dib8000_write_word(state, 270, 6); - dib8000_write_word(state, 271, 6); - break; - case 2: /* only the diversity input */ - dib8000_write_word(state, 270, 0); - dib8000_write_word(state, 271, 1); - break; - } - return 0; -} - -static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode) -{ - /* by default everything is going to be powered off */ - u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, - reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, - reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; - - /* now, depending on the requested mode, we power on */ - switch (mode) { - /* power up everything in the demod */ - case DIB8000M_POWER_ALL: - reg_774 = 0x0000; - reg_775 = 0x0000; - reg_776 = 0x0000; - reg_900 &= 0xfffc; - reg_1280 &= 0x00ff; - break; - case DIB8000M_POWER_INTERFACE_ONLY: - reg_1280 &= 0x00ff; - break; - } - - dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280); - dib8000_write_word(state, 774, reg_774); - dib8000_write_word(state, 775, reg_775); - dib8000_write_word(state, 776, reg_776); - dib8000_write_word(state, 900, reg_900); - dib8000_write_word(state, 1280, reg_1280); -} - -static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no) -{ - int ret = 0; - u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908); - - switch (no) { - case DIBX000_SLOW_ADC_ON: - reg_908 |= (1 << 1) | (1 << 0); - ret |= dib8000_write_word(state, 908, reg_908); - reg_908 &= ~(1 << 1); - break; - - case DIBX000_SLOW_ADC_OFF: - reg_908 |= (1 << 1) | (1 << 0); - break; - - case DIBX000_ADC_ON: - reg_907 &= 0x0fff; - reg_908 &= 0x0003; - break; - - case DIBX000_ADC_OFF: // leave the VBG voltage on - reg_907 |= (1 << 14) | (1 << 13) | (1 << 12); - reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); - break; - - case DIBX000_VBG_ENABLE: - reg_907 &= ~(1 << 15); - break; - - case DIBX000_VBG_DISABLE: - reg_907 |= (1 << 15); - break; - - default: - break; - } - - ret |= dib8000_write_word(state, 907, reg_907); - ret |= dib8000_write_word(state, 908, reg_908); - - return ret; -} - -static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) -{ - struct dib8000_state *state = fe->demodulator_priv; - u32 timf; - - if (bw == 0) - bw = 6000; - - if (state->timf == 0) { - dprintk("using default timf"); - timf = state->timf_default; - } else { - dprintk("using updated timf"); - timf = state->timf; - } - - dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff)); - dib8000_write_word(state, 30, (u16) ((timf) & 0xffff)); - - return 0; -} - -static int dib8000_sad_calib(struct dib8000_state *state) -{ -/* internal */ - dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); - dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096 - - /* do the calibration */ - dib8000_write_word(state, 923, (1 << 0)); - dib8000_write_word(state, 923, (0 << 0)); - - msleep(1); - return 0; -} - -int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) -{ - struct dib8000_state *state = fe->demodulator_priv; - if (value > 4095) - value = 4095; - state->wbd_ref = value; - return dib8000_write_word(state, 106, value); -} - -EXPORT_SYMBOL(dib8000_set_wbd_ref); -static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) -{ - dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25); - dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */ - dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff)); - dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff)); - dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff)); - dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003)); - - dib8000_write_word(state, 922, bw->sad_cfg); -} - -static void dib8000_reset_pll(struct dib8000_state *state) -{ - const struct dibx000_bandwidth_config *pll = state->cfg.pll; - u16 clk_cfg1; - - // clk_cfg0 - dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); - - // clk_cfg1 - clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | - (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | - (pll->pll_range << 1) | (pll->pll_reset << 0); - - dib8000_write_word(state, 902, clk_cfg1); - clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); - dib8000_write_word(state, 902, clk_cfg1); - - dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */ - - /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ - if (state->cfg.pll->ADClkSrc == 0) - dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | - (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); - else if (state->cfg.refclksel != 0) - dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | - ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | - (pll->ADClkSrc << 7) | (0 << 1)); - else - dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); - - dib8000_reset_pll_common(state, pll); -} - -static int dib8000_reset_gpio(struct dib8000_state *st) -{ - /* reset the GPIOs */ - dib8000_write_word(st, 1029, st->cfg.gpio_dir); - dib8000_write_word(st, 1030, st->cfg.gpio_val); - - /* TODO 782 is P_gpio_od */ - - dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos); - - dib8000_write_word(st, 1037, st->cfg.pwm_freq_div); - return 0; -} - -static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val) -{ - st->cfg.gpio_dir = dib8000_read_word(st, 1029); - st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */ - st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */ - dib8000_write_word(st, 1029, st->cfg.gpio_dir); - - st->cfg.gpio_val = dib8000_read_word(st, 1030); - st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */ - st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */ - dib8000_write_word(st, 1030, st->cfg.gpio_val); - - dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val); - - return 0; -} - -int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) -{ - struct dib8000_state *state = fe->demodulator_priv; - return dib8000_cfg_gpio(state, num, dir, val); -} - -EXPORT_SYMBOL(dib8000_set_gpio); -static const u16 dib8000_defaults[] = { - /* auto search configuration - lock0 by default waiting - * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */ - 3, 7, - 0x0004, - 0x0400, - 0x0814, - - 12, 11, - 0x001b, - 0x7740, - 0x005b, - 0x8d80, - 0x01c9, - 0xc380, - 0x0000, - 0x0080, - 0x0000, - 0x0090, - 0x0001, - 0xd4c0, - - /*1, 32, - 0x6680 // P_corm_thres Lock algorithms configuration */ - - 11, 80, /* set ADC level to -16 */ - (1 << 13) - 825 - 117, - (1 << 13) - 837 - 117, - (1 << 13) - 811 - 117, - (1 << 13) - 766 - 117, - (1 << 13) - 737 - 117, - (1 << 13) - 693 - 117, - (1 << 13) - 648 - 117, - (1 << 13) - 619 - 117, - (1 << 13) - 575 - 117, - (1 << 13) - 531 - 117, - (1 << 13) - 501 - 117, - - 4, 108, - 0, - 0, - 0, - 0, - - 1, 175, - 0x0410, - 1, 179, - 8192, // P_fft_nb_to_cut - - 6, 181, - 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800 - 0x2800, - 0x2800, - 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800 - 0x2800, - 0x2800, - - 2, 193, - 0x0666, // P_pha3_thres - 0x0000, // P_cti_use_cpe, P_cti_use_prog - - 2, 205, - 0x200f, // P_cspu_regul, P_cspu_win_cut - 0x000f, // P_des_shift_work - - 5, 215, - 0x023d, // P_adp_regul_cnt - 0x00a4, // P_adp_noise_cnt - 0x00a4, // P_adp_regul_ext - 0x7ff0, // P_adp_noise_ext - 0x3ccc, // P_adp_fil - - 1, 230, - 0x0000, // P_2d_byp_ti_num - - 1, 263, - 0x800, //P_equal_thres_wgn - - 1, 268, - (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode - - 1, 270, - 0x0001, // P_div_lock0_wait - 1, 285, - 0x0020, //p_fec_ - 1, 299, - 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */ - - 1, 338, - (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1 - (1 << 10) | - (0 << 9) | /* P_ctrl_pre_freq_inh=0 */ - (3 << 5) | /* P_ctrl_pre_freq_step=3 */ - (1 << 0), /* P_pre_freq_win_len=1 */ - - 1, 903, - (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW) - - 0, -}; - -static u16 dib8000_identify(struct i2c_device *client) -{ - u16 value; - - //because of glitches sometimes - value = dib8000_i2c_read16(client, 896); - - if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) { - dprintk("wrong Vendor ID (read=0x%x)", value); - return 0; - } - - value = dib8000_i2c_read16(client, 897); - if (value != 0x8000 && value != 0x8001 && value != 0x8002) { - dprintk("wrong Device ID (%x)", value); - return 0; - } - - switch (value) { - case 0x8000: - dprintk("found DiB8000A"); - break; - case 0x8001: - dprintk("found DiB8000B"); - break; - case 0x8002: - dprintk("found DiB8000C"); - break; - } - return value; -} - -static int dib8000_reset(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - - dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */ - - if ((state->revision = dib8000_identify(&state->i2c)) == 0) - return -EINVAL; - - if (state->revision == 0x8000) - dprintk("error : dib8000 MA not supported"); - - dibx000_reset_i2c_master(&state->i2c_master); - - dib8000_set_power_mode(state, DIB8000M_POWER_ALL); - - /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ - dib8000_set_adc_state(state, DIBX000_VBG_ENABLE); - - /* restart all parts */ - dib8000_write_word(state, 770, 0xffff); - dib8000_write_word(state, 771, 0xffff); - dib8000_write_word(state, 772, 0xfffc); - dib8000_write_word(state, 898, 0x000c); // sad - dib8000_write_word(state, 1280, 0x004d); - dib8000_write_word(state, 1281, 0x000c); - - dib8000_write_word(state, 770, 0x0000); - dib8000_write_word(state, 771, 0x0000); - dib8000_write_word(state, 772, 0x0000); - dib8000_write_word(state, 898, 0x0004); // sad - dib8000_write_word(state, 1280, 0x0000); - dib8000_write_word(state, 1281, 0x0000); - - /* drives */ - if (state->cfg.drives) - dib8000_write_word(state, 906, state->cfg.drives); - else { - dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); - dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust - } - - dib8000_reset_pll(state); - - if (dib8000_reset_gpio(state) != 0) - dprintk("GPIO reset was not successful."); - - if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0) - dprintk("OUTPUT_MODE could not be resetted."); - - state->current_agc = NULL; - - // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... - /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */ - if (state->cfg.pll->ifreq == 0) - dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */ - else - dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */ - - { - u16 l = 0, r; - const u16 *n; - n = dib8000_defaults; - l = *n++; - while (l) { - r = *n++; - do { - dib8000_write_word(state, r, *n++); - r++; - } while (--l); - l = *n++; - } - } - state->isdbt_cfg_loaded = 0; - - //div_cfg override for special configs - if (state->cfg.div_cfg != 0) - dib8000_write_word(state, 903, state->cfg.div_cfg); - - /* unforce divstr regardless whether i2c enumeration was done or not */ - dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1)); - - dib8000_set_bandwidth(fe, 6000); - - dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); - dib8000_sad_calib(state); - dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); - - dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); - - return 0; -} - -static void dib8000_restart_agc(struct dib8000_state *state) -{ - // P_restart_iqc & P_restart_agc - dib8000_write_word(state, 770, 0x0a00); - dib8000_write_word(state, 770, 0x0000); -} - -static int dib8000_update_lna(struct dib8000_state *state) -{ - u16 dyn_gain; - - if (state->cfg.update_lna) { - // read dyn_gain here (because it is demod-dependent and not tuner) - dyn_gain = dib8000_read_word(state, 390); - - if (state->cfg.update_lna(state->fe[0], dyn_gain)) { - dib8000_restart_agc(state); - return 1; - } - } - return 0; -} - -static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) -{ - struct dibx000_agc_config *agc = NULL; - int i; - if (state->current_band == band && state->current_agc != NULL) - return 0; - state->current_band = band; - - for (i = 0; i < state->cfg.agc_config_count; i++) - if (state->cfg.agc[i].band_caps & band) { - agc = &state->cfg.agc[i]; - break; - } - - if (agc == NULL) { - dprintk("no valid AGC configuration found for band 0x%02x", band); - return -EINVAL; - } - - state->current_agc = agc; - - /* AGC */ - dib8000_write_word(state, 76, agc->setup); - dib8000_write_word(state, 77, agc->inv_gain); - dib8000_write_word(state, 78, agc->time_stabiliz); - dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock); - - // Demod AGC loop configuration - dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp); - dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp); - - dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", - state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); - - /* AGC continued */ - if (state->wbd_ref != 0) - dib8000_write_word(state, 106, state->wbd_ref); - else // use default - dib8000_write_word(state, 106, agc->wbd_ref); - dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); - dib8000_write_word(state, 108, agc->agc1_max); - dib8000_write_word(state, 109, agc->agc1_min); - dib8000_write_word(state, 110, agc->agc2_max); - dib8000_write_word(state, 111, agc->agc2_min); - dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2); - dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - - dib8000_write_word(state, 75, agc->agc1_pt3); - dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */ - - return 0; -} - -void dib8000_pwm_agc_reset(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - dib8000_set_adc_state(state, DIBX000_ADC_ON); - dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))); -} -EXPORT_SYMBOL(dib8000_pwm_agc_reset); - -static int dib8000_agc_soft_split(struct dib8000_state *state) -{ - u16 agc, split_offset; - - if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) - return FE_CALLBACK_TIME_NEVER; - - // n_agc_global - agc = dib8000_read_word(state, 390); - - if (agc > state->current_agc->split.min_thres) - split_offset = state->current_agc->split.min; - else if (agc < state->current_agc->split.max_thres) - split_offset = state->current_agc->split.max; - else - split_offset = state->current_agc->split.max * - (agc - state->current_agc->split.min_thres) / - (state->current_agc->split.max_thres - state->current_agc->split.min_thres); - - dprintk("AGC split_offset: %d", split_offset); - - // P_agc_force_split and P_agc_split_offset - dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset); - return 5000; -} - -static int dib8000_agc_startup(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - enum frontend_tune_state *tune_state = &state->tune_state; - - int ret = 0; - - switch (*tune_state) { - case CT_AGC_START: - // set power-up level: interf+analog+AGC - - dib8000_set_adc_state(state, DIBX000_ADC_ON); - - if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) { - *tune_state = CT_AGC_STOP; - state->status = FE_STATUS_TUNE_FAILED; - break; - } - - ret = 70; - *tune_state = CT_AGC_STEP_0; - break; - - case CT_AGC_STEP_0: - //AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(fe, 1); - - dib8000_restart_agc(state); - - // wait AGC rough lock time - ret = 50; - *tune_state = CT_AGC_STEP_1; - break; - - case CT_AGC_STEP_1: - // wait AGC accurate lock time - ret = 70; - - if (dib8000_update_lna(state)) - // wait only AGC rough lock time - ret = 50; - else - *tune_state = CT_AGC_STEP_2; - break; - - case CT_AGC_STEP_2: - dib8000_agc_soft_split(state); - - if (state->cfg.agc_control) - state->cfg.agc_control(fe, 0); - - *tune_state = CT_AGC_STOP; - break; - default: - ret = dib8000_agc_soft_split(state); - break; - } - return ret; - -} - -static const s32 lut_1000ln_mant[] = -{ - 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 -}; - -s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) -{ - struct dib8000_state *state = fe->demodulator_priv; - u32 ix = 0, tmp_val = 0, exp = 0, mant = 0; - s32 val; - - val = dib8000_read32(state, 384); - if (mode) { - tmp_val = val; - while (tmp_val >>= 1) - exp++; - mant = (val * 1000 / (1<timf = dib8000_read32(state, 435); - - dib8000_write_word(state, 29, (u16) (timf >> 16)); - dib8000_write_word(state, 30, (u16) (timf & 0xffff)); - dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); -} - -static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching) -{ - u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0; - u8 guard, crate, constellation, timeI; - u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; - u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled - const s16 *ncoeff = NULL, *ana_fe; - u16 tmcc_pow = 0; - u16 coff_pow = 0x2800; - u16 init_prbs = 0xfff; - u16 ana_gain = 0; - u16 adc_target_16dB[11] = { - (1 << 13) - 825 - 117, - (1 << 13) - 837 - 117, - (1 << 13) - 811 - 117, - (1 << 13) - 766 - 117, - (1 << 13) - 737 - 117, - (1 << 13) - 693 - 117, - (1 << 13) - 648 - 117, - (1 << 13) - 619 - 117, - (1 << 13) - 575 - 117, - (1 << 13) - 531 - 117, - (1 << 13) - 501 - 117 - }; - - if (state->ber_monitored_layer != LAYER_ALL) - dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer); - else - dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); - - i = dib8000_read_word(state, 26) & 1; // P_dds_invspec - dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i); - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { - //compute new dds_freq for the seg and adjust prbs - int seg_offset = - state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx - - (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) - - (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2); - int clk = state->cfg.pll->internal; - u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26) - int dds_offset = seg_offset * segtodds; - int new_dds, sub_channel; - if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - dds_offset -= (int)(segtodds / 2); - - if (state->cfg.pll->ifreq == 0) { - if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) { - dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); - new_dds = dds_offset; - } else - new_dds = dds_offset; - - // We shift tuning frequency if the wanted segment is : - // - the segment of center frequency with an odd total number of segments - // - the segment to the left of center frequency with an even total number of segments - // - the segment to the right of center frequency with an even total number of segments - if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT) - && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) - && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) - && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == - ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) - || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2))) - || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == - ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) - )) { - new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26) - } - } else { - if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) - new_dds = state->cfg.pll->ifreq - dds_offset; - else - new_dds = state->cfg.pll->ifreq + dds_offset; - } - dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff)); - dib8000_write_word(state, 28, (u16) (new_dds & 0xffff)); - if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) - sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3; - else - sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3; - sub_channel -= 6; - - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K - || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) { - dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1 - dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1 - } else { - dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0 - dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0 - } - - switch (state->fe[0]->dtv_property_cache.transmission_mode) { - case TRANSMISSION_MODE_2K: - switch (sub_channel) { - case -6: - init_prbs = 0x0; - break; // 41, 0, 1 - case -5: - init_prbs = 0x423; - break; // 02~04 - case -4: - init_prbs = 0x9; - break; // 05~07 - case -3: - init_prbs = 0x5C7; - break; // 08~10 - case -2: - init_prbs = 0x7A6; - break; // 11~13 - case -1: - init_prbs = 0x3D8; - break; // 14~16 - case 0: - init_prbs = 0x527; - break; // 17~19 - case 1: - init_prbs = 0x7FF; - break; // 20~22 - case 2: - init_prbs = 0x79B; - break; // 23~25 - case 3: - init_prbs = 0x3D6; - break; // 26~28 - case 4: - init_prbs = 0x3A2; - break; // 29~31 - case 5: - init_prbs = 0x53B; - break; // 32~34 - case 6: - init_prbs = 0x2F4; - break; // 35~37 - default: - case 7: - init_prbs = 0x213; - break; // 38~40 - } - break; - - case TRANSMISSION_MODE_4K: - switch (sub_channel) { - case -6: - init_prbs = 0x0; - break; // 41, 0, 1 - case -5: - init_prbs = 0x208; - break; // 02~04 - case -4: - init_prbs = 0xC3; - break; // 05~07 - case -3: - init_prbs = 0x7B9; - break; // 08~10 - case -2: - init_prbs = 0x423; - break; // 11~13 - case -1: - init_prbs = 0x5C7; - break; // 14~16 - case 0: - init_prbs = 0x3D8; - break; // 17~19 - case 1: - init_prbs = 0x7FF; - break; // 20~22 - case 2: - init_prbs = 0x3D6; - break; // 23~25 - case 3: - init_prbs = 0x53B; - break; // 26~28 - case 4: - init_prbs = 0x213; - break; // 29~31 - case 5: - init_prbs = 0x29; - break; // 32~34 - case 6: - init_prbs = 0xD0; - break; // 35~37 - default: - case 7: - init_prbs = 0x48E; - break; // 38~40 - } - break; - - default: - case TRANSMISSION_MODE_8K: - switch (sub_channel) { - case -6: - init_prbs = 0x0; - break; // 41, 0, 1 - case -5: - init_prbs = 0x740; - break; // 02~04 - case -4: - init_prbs = 0x069; - break; // 05~07 - case -3: - init_prbs = 0x7DD; - break; // 08~10 - case -2: - init_prbs = 0x208; - break; // 11~13 - case -1: - init_prbs = 0x7B9; - break; // 14~16 - case 0: - init_prbs = 0x5C7; - break; // 17~19 - case 1: - init_prbs = 0x7FF; - break; // 20~22 - case 2: - init_prbs = 0x53B; - break; // 23~25 - case 3: - init_prbs = 0x29; - break; // 26~28 - case 4: - init_prbs = 0x48E; - break; // 29~31 - case 5: - init_prbs = 0x4C4; - break; // 32~34 - case 6: - init_prbs = 0x367; - break; // 33~37 - default: - case 7: - init_prbs = 0x684; - break; // 38~40 - } - break; - } - } else { - dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff)); - dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff)); - dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003)); - } - /*P_mode == ?? */ - dib8000_write_word(state, 10, (seq << 4)); - // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000); - - switch (state->fe[0]->dtv_property_cache.guard_interval) { - case GUARD_INTERVAL_1_32: - guard = 0; - break; - case GUARD_INTERVAL_1_16: - guard = 1; - break; - case GUARD_INTERVAL_1_8: - guard = 2; - break; - case GUARD_INTERVAL_1_4: - default: - guard = 3; - break; - } - - dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1 - - max_constellation = DQPSK; - for (i = 0; i < 3; i++) { - switch (state->fe[0]->dtv_property_cache.layer[i].modulation) { - case DQPSK: - constellation = 0; - break; - case QPSK: - constellation = 1; - break; - case QAM_16: - constellation = 2; - break; - case QAM_64: - default: - constellation = 3; - break; - } - - switch (state->fe[0]->dtv_property_cache.layer[i].fec) { - case FEC_1_2: - crate = 1; - break; - case FEC_2_3: - crate = 2; - break; - case FEC_3_4: - crate = 3; - break; - case FEC_5_6: - crate = 5; - break; - case FEC_7_8: - default: - crate = 7; - break; - } - - if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) && - ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) || - (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)) - ) - timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving; - else - timeI = 0; - dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) | - (crate << 3) | timeI); - if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) { - switch (max_constellation) { - case DQPSK: - case QPSK: - if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 || - state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64) - max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation; - break; - case QAM_16: - if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64) - max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation; - break; - } - } - } - - mode = fft_to_mode(state); - - //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/ - - dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | - ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache. - isdbt_sb_mode & 1) << 4)); - - dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval); - - /* signal optimization parameter */ - - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) { - seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0]; - for (i = 1; i < 3; i++) - nbseg_diff += - (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; - for (i = 0; i < nbseg_diff; i++) - seg_diff_mask |= 1 << permu_seg[i + 1]; - } else { - for (i = 0; i < 3; i++) - nbseg_diff += - (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; - for (i = 0; i < nbseg_diff; i++) - seg_diff_mask |= 1 << permu_seg[i]; - } - dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask); - - state->differential_constellation = (seg_diff_mask != 0); - dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) - seg_mask13 = 0x00E0; - else // 1-segment - seg_mask13 = 0x0040; - } else - seg_mask13 = 0x1fff; - - // WRITE: Mode & Diff mask - dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask); - - if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode)) - dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); - else - dib8000_write_word(state, 268, (2 << 9) | 39); //init value - - // ---- SMALL ---- - // P_small_seg_diff - dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352 - - dib8000_write_word(state, 353, seg_mask13); // ADDR 353 - -/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */ - - // ---- SMALL ---- - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - switch (state->fe[0]->dtv_property_cache.transmission_mode) { - case TRANSMISSION_MODE_2K: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) - ncoeff = coeff_2k_sb_1seg_dqpsk; - else // QPSK or QAM - ncoeff = coeff_2k_sb_1seg; - } else { // 3-segments - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) - ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; - else // QPSK or QAM on external segments - ncoeff = coeff_2k_sb_3seg_0dqpsk; - } else { // QPSK or QAM on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) - ncoeff = coeff_2k_sb_3seg_1dqpsk; - else // QPSK or QAM on external segments - ncoeff = coeff_2k_sb_3seg; - } - } - break; - - case TRANSMISSION_MODE_4K: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) - ncoeff = coeff_4k_sb_1seg_dqpsk; - else // QPSK or QAM - ncoeff = coeff_4k_sb_1seg; - } else { // 3-segments - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { - ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; - } else { // QPSK or QAM on external segments - ncoeff = coeff_4k_sb_3seg_0dqpsk; - } - } else { // QPSK or QAM on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { - ncoeff = coeff_4k_sb_3seg_1dqpsk; - } else // QPSK or QAM on external segments - ncoeff = coeff_4k_sb_3seg; - } - } - break; - - case TRANSMISSION_MODE_AUTO: - case TRANSMISSION_MODE_8K: - default: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) - ncoeff = coeff_8k_sb_1seg_dqpsk; - else // QPSK or QAM - ncoeff = coeff_8k_sb_1seg; - } else { // 3-segments - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { - ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; - } else { // QPSK or QAM on external segments - ncoeff = coeff_8k_sb_3seg_0dqpsk; - } - } else { // QPSK or QAM on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { - ncoeff = coeff_8k_sb_3seg_1dqpsk; - } else // QPSK or QAM on external segments - ncoeff = coeff_8k_sb_3seg; - } - } - break; - } - for (i = 0; i < 8; i++) - dib8000_write_word(state, 343 + i, ncoeff[i]); - } - - // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 - dib8000_write_word(state, 351, - (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5); - - // ---- COFF ---- - // Carloff, the most robust - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - - // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64 - // P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 - dib8000_write_word(state, 187, - (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2) - | 0x3); - -/* // P_small_coef_ext_enable = 1 */ -/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */ - - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { - - // P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1) - if (mode == 3) - dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14)); - else - dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14)); - // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, - // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 - dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4); - // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 - dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); - // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 - dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); - - // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k - dib8000_write_word(state, 181, 300); - dib8000_write_word(state, 182, 150); - dib8000_write_word(state, 183, 80); - dib8000_write_word(state, 184, 300); - dib8000_write_word(state, 185, 150); - dib8000_write_word(state, 186, 80); - } else { // Sound Broadcasting mode 3 seg - // P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15 - /* if (mode == 3) */ - /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */ - /* else */ - /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */ - dib8000_write_word(state, 180, 0x1fcf | (1 << 14)); - - // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, - // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 - dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4); - // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 - dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); - //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 - dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); - - // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k - dib8000_write_word(state, 181, 350); - dib8000_write_word(state, 182, 300); - dib8000_write_word(state, 183, 250); - dib8000_write_word(state, 184, 350); - dib8000_write_word(state, 185, 300); - dib8000_write_word(state, 186, 250); - } - - } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments - dib8000_write_word(state, 180, (16 << 6) | 9); - dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2); - coff_pow = 0x2800; - for (i = 0; i < 6; i++) - dib8000_write_word(state, 181 + i, coff_pow); - - // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1, - // P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 - dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1); - - // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 - dib8000_write_word(state, 340, (8 << 6) | (6 << 0)); - // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 - dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); - } - // ---- FFT ---- - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) - dib8000_write_word(state, 178, 64); // P_fft_powrange=64 - else - dib8000_write_word(state, 178, 32); // P_fft_powrange=32 - - /* make the cpil_coff_lock more robust but slower p_coff_winlen - * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) - */ - /* if ( ( nbseg_diff>0)&&(nbseg_diff<13)) - dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */ - - dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */ - dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */ - dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */ - if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0)) - dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */ - else - dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */ - dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */ - //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */ - if (!autosearching) - dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */ - else - dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. - dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000); - - dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */ - - /* offset loop parameters */ - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) - /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ - dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40); - - else // Sound Broadcasting mode 3 seg - /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ - dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60); - } else - // TODO in 13 seg, timf_alpha can always be the same or not ? - /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */ - dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80); - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) - /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */ - dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode)); - - else // Sound Broadcasting mode 3 seg - /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */ - dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode)); - } else - /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */ - dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode)); - - /* P_dvsy_sync_wait - reuse mode */ - switch (state->fe[0]->dtv_property_cache.transmission_mode) { - case TRANSMISSION_MODE_8K: - mode = 256; - break; - case TRANSMISSION_MODE_4K: - mode = 128; - break; - default: - case TRANSMISSION_MODE_2K: - mode = 64; - break; - } - if (state->cfg.diversity_delay == 0) - mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo - else - mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo - mode <<= 4; - dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode); - - /* channel estimation fine configuration */ - switch (max_constellation) { - case QAM_64: - ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB - coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ - coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ - coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ - //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1 - break; - case QAM_16: - ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB - coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ - coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ - coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ - //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16))) - break; - default: - ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level - coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ - coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ - coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */ - coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ - break; - } - for (mode = 0; mode < 4; mode++) - dib8000_write_word(state, 215 + mode, coeff[mode]); - - // update ana_gain depending on max constellation - dib8000_write_word(state, 116, ana_gain); - // update ADC target depending on ana_gain - if (ana_gain) { // set -16dB ADC target for ana_gain=-1 - for (i = 0; i < 10; i++) - dib8000_write_word(state, 80 + i, adc_target_16dB[i]); - } else { // set -22dB ADC target for ana_gain=0 - for (i = 0; i < 10; i++) - dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355); - } - - // ---- ANA_FE ---- - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) - ana_fe = ana_fe_coeff_3seg; - else // 1-segment - ana_fe = ana_fe_coeff_1seg; - } else - ana_fe = ana_fe_coeff_13seg; - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0) - for (mode = 0; mode < 24; mode++) - dib8000_write_word(state, 117 + mode, ana_fe[mode]); - - // ---- CHAN_BLK ---- - for (i = 0; i < 13; i++) { - if ((((~seg_diff_mask) >> i) & 1) == 1) { - P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0)); - P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0)); - } - } - dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge - dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge - // "P_cspu_left_edge" not used => do not care - // "P_cspu_right_edge" not used => do not care - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1 - dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0 - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 - && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) { - //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0 - dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15 - } - } else if (state->isdbt_cfg_loaded == 0) { - dib8000_write_word(state, 228, 0); // default value - dib8000_write_word(state, 265, 31); // default value - dib8000_write_word(state, 205, 0x200f); // init value - } - // ---- TMCC ---- - for (i = 0; i < 3; i++) - tmcc_pow += - (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count); - // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); - // Threshold is set at 1/4 of max power. - tmcc_pow *= (1 << (9 - 2)); - - dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k - dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k - dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k - //dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); - // ---- PHA3 ---- - - if (state->isdbt_cfg_loaded == 0) - dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */ - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) - state->isdbt_cfg_loaded = 0; - else - state->isdbt_cfg_loaded = 1; - -} - -static int dib8000_autosearch_start(struct dvb_frontend *fe) -{ - u8 factor; - u32 value; - struct dib8000_state *state = fe->demodulator_priv; - - int slist = 0; - - state->fe[0]->dtv_property_cache.inversion = 0; - if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode) - state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; - state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64; - state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3; - state->fe[0]->dtv_property_cache.layer[0].interleaving = 0; - - //choose the right list, in sb, always do everything - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; - slist = 7; - dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); - } else { - if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) { - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { - slist = 7; - dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 to have autosearch start ok with mode2 - } else - slist = 3; - } else { - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { - slist = 2; - dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 - } else - slist = 0; - } - - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; - if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; - - dprintk("using list for autosearch : %d", slist); - dib8000_set_channel(state, (unsigned char)slist, 1); - //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 - - factor = 1; - - //set lock_mask values - dib8000_write_word(state, 6, 0x4); - dib8000_write_word(state, 7, 0x8); - dib8000_write_word(state, 8, 0x1000); - - //set lock_mask wait time values - value = 50 * state->cfg.pll->internal * factor; - dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time - dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.pll->internal * factor; - dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time - dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time - value = 1000 * state->cfg.pll->internal * factor; - dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time - dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time - - value = dib8000_read_word(state, 0); - dib8000_write_word(state, 0, (u16) ((1 << 15) | value)); - dib8000_read_word(state, 1284); // reset the INT. n_irq_pending - dib8000_write_word(state, 0, (u16) value); - - } - - return 0; -} - -static int dib8000_autosearch_irq(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - u16 irq_pending = dib8000_read_word(state, 1284); - - if (irq_pending & 0x1) { // failed - dprintk("dib8000_autosearch_irq failed"); - return 1; - } - - if (irq_pending & 0x2) { // succeeded - dprintk("dib8000_autosearch_irq succeeded"); - return 2; - } - - return 0; // still pending -} - -static int dib8000_tune(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - int ret = 0; - u16 value, mode = fft_to_mode(state); - - // we are already tuned - just resuming from suspend - if (state == NULL) - return -EINVAL; - - dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000); - dib8000_set_channel(state, 0, 0); - - // restart demod - ret |= dib8000_write_word(state, 770, 0x4000); - ret |= dib8000_write_word(state, 770, 0x0000); - msleep(45); - - /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */ - /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */ - - // never achieved a lock before - wait for timfreq to update - if (state->timf == 0) { - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) - msleep(300); - else // Sound Broadcasting mode 3 seg - msleep(500); - } else // 13 seg - msleep(200); - } - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { - - /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */ - dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40); - //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80); - - /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */ - ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5)); - - } else { // Sound Broadcasting mode 3 seg - - /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */ - dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60); - - ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5)); - } - - } else { // 13 seg - /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */ - dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80); - - ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5)); - - } - - // we achieved a coff_cpil_lock - it's time to update the timf - if ((dib8000_read_word(state, 568) >> 11) & 0x1) - dib8000_update_timf(state); - - //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start - dib8000_write_word(state, 6, 0x200); - - if (state->revision == 0x8002) { - value = dib8000_read_word(state, 903); - dib8000_write_word(state, 903, value & ~(1 << 3)); - msleep(1); - dib8000_write_word(state, 903, value | (1 << 3)); - } - - return ret; -} - -static int dib8000_wakeup(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - u8 index_frontend; - int ret; - - dib8000_set_power_mode(state, DIB8000M_POWER_ALL); - dib8000_set_adc_state(state, DIBX000_ADC_ON); - if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) - dprintk("could not start Slow ADC"); - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]); - if (ret < 0) - return ret; - } - - return 0; -} - -static int dib8000_sleep(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - u8 index_frontend; - int ret; - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); - if (ret < 0) - return ret; - } - - dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); - dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); - return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); -} - -enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - return state->tune_state; -} -EXPORT_SYMBOL(dib8000_get_tune_state); - -int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) -{ - struct dib8000_state *state = fe->demodulator_priv; - state->tune_state = tune_state; - return 0; -} -EXPORT_SYMBOL(dib8000_set_tune_state); - -static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dib8000_state *state = fe->demodulator_priv; - u16 i, val = 0; - fe_status_t stat; - u8 index_frontend, sub_index_frontend; - - fe->dtv_property_cache.bandwidth_hz = 6000000; - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); - if (stat&FE_HAS_SYNC) { - dprintk("TMCC lock on the slave%i", index_frontend); - /* synchronize the cache with the other frontends */ - state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); - for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { - if (sub_index_frontend != index_frontend) { - state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; - state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; - state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; - state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; - state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; - for (i = 0; i < 3; i++) { - state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count; - state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; - state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; - state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; - } - } - } - return 0; - } - } - - fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1; - - val = dib8000_read_word(state, 570); - fe->dtv_property_cache.inversion = (val & 0x40) >> 6; - switch ((val & 0x30) >> 4) { - case 1: - fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; - break; - case 3: - default: - fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; - break; - } - - switch (val & 0x3) { - case 0: - fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; - dprintk("dib8000_get_frontend GI = 1/32 "); - break; - case 1: - fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; - dprintk("dib8000_get_frontend GI = 1/16 "); - break; - case 2: - dprintk("dib8000_get_frontend GI = 1/8 "); - fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - dprintk("dib8000_get_frontend GI = 1/4 "); - fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; - break; - } - - val = dib8000_read_word(state, 505); - fe->dtv_property_cache.isdbt_partial_reception = val & 1; - dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception); - - for (i = 0; i < 3; i++) { - val = dib8000_read_word(state, 493 + i); - fe->dtv_property_cache.layer[i].segment_count = val & 0x0F; - dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count); - - val = dib8000_read_word(state, 499 + i); - fe->dtv_property_cache.layer[i].interleaving = val & 0x3; - dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving); - - val = dib8000_read_word(state, 481 + i); - switch (val & 0x7) { - case 1: - fe->dtv_property_cache.layer[i].fec = FEC_1_2; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i); - break; - case 2: - fe->dtv_property_cache.layer[i].fec = FEC_2_3; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i); - break; - case 3: - fe->dtv_property_cache.layer[i].fec = FEC_3_4; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i); - break; - case 5: - fe->dtv_property_cache.layer[i].fec = FEC_5_6; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i); - break; - default: - fe->dtv_property_cache.layer[i].fec = FEC_7_8; - dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i); - break; - } - - val = dib8000_read_word(state, 487 + i); - switch (val & 0x3) { - case 0: - dprintk("dib8000_get_frontend : Layer %d DQPSK ", i); - fe->dtv_property_cache.layer[i].modulation = DQPSK; - break; - case 1: - fe->dtv_property_cache.layer[i].modulation = QPSK; - dprintk("dib8000_get_frontend : Layer %d QPSK ", i); - break; - case 2: - fe->dtv_property_cache.layer[i].modulation = QAM_16; - dprintk("dib8000_get_frontend : Layer %d QAM16 ", i); - break; - case 3: - default: - dprintk("dib8000_get_frontend : Layer %d QAM64 ", i); - fe->dtv_property_cache.layer[i].modulation = QAM_64; - break; - } - } - - /* synchronize the cache with the other frontends */ - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode; - state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; - state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; - state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval; - state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception; - for (i = 0; i < 3; i++) { - state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count; - state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving; - state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec; - state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation; - } - } - return 0; -} - -static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dib8000_state *state = fe->demodulator_priv; - u8 nbr_pending, exit_condition, index_frontend; - s8 index_frontend_success = -1; - int time, ret; - int time_slave = FE_CALLBACK_TIME_NEVER; - - if (state->fe[0]->dtv_property_cache.frequency == 0) { - dprintk("dib8000: must at least specify frequency "); - return 0; - } - - if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { - dprintk("dib8000: no bandwidth specified, set to default "); - state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000; - } - - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - /* synchronization of the cache */ - state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; - memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); - - dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); - if (state->fe[index_frontend]->ops.tuner_ops.set_params) - state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep); - - dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START); - } - - /* start up the AGC */ - do { - time = dib8000_agc_startup(state->fe[0]); - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - time_slave = dib8000_agc_startup(state->fe[index_frontend]); - if (time == FE_CALLBACK_TIME_NEVER) - time = time_slave; - else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time)) - time = time_slave; - } - if (time != FE_CALLBACK_TIME_NEVER) - msleep(time / 10); - else - break; - exit_condition = 1; - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) { - exit_condition = 0; - break; - } - } - } while (exit_condition == 0); - - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); - - if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) || - (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) || - (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) || - (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) || - (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) && - (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) && - (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) && - ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) || - (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) || - (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) && - (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) && - (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) && - ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) || - (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) || - (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) && - (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) && - (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) && - ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) || - (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) || - (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) || - ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) && - ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) || - ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && - ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) { - int i = 80000; - u8 found = 0; - u8 tune_failed = 0; - - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000); - dib8000_autosearch_start(state->fe[index_frontend]); - } - - do { - msleep(20); - nbr_pending = 0; - exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - if (((tune_failed >> index_frontend) & 0x1) == 0) { - found = dib8000_autosearch_irq(state->fe[index_frontend]); - switch (found) { - case 0: /* tune pending */ - nbr_pending++; - break; - case 2: - dprintk("autosearch succeed on the frontend%i", index_frontend); - exit_condition = 2; - index_frontend_success = index_frontend; - break; - default: - dprintk("unhandled autosearch result"); - case 1: - dprintk("autosearch failed for the frontend%i", index_frontend); - break; - } - } - } - - /* if all tune are done and no success, exit: tune failed */ - if ((nbr_pending == 0) && (exit_condition == 0)) - exit_condition = 1; - } while ((exit_condition == 0) && i--); - - if (exit_condition == 1) { /* tune failed */ - dprintk("tune failed"); - return 0; - } - - dprintk("tune success on frontend%i", index_frontend_success); - - dib8000_get_frontend(fe, fep); - } - - for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - ret = dib8000_tune(state->fe[index_frontend]); - - /* set output mode and diversity input */ - dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); - dib8000_set_diversity_in(state->fe[index_frontend-1], 1); - } - - /* turn off the diversity of the last chip */ - dib8000_set_diversity_in(state->fe[index_frontend-1], 0); - - return ret; -} - -static u16 dib8000_read_lock(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - - return dib8000_read_word(state, 568); -} - -static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) -{ - struct dib8000_state *state = fe->demodulator_priv; - u16 lock_slave = 0, lock = dib8000_read_word(state, 568); - u8 index_frontend; - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - lock_slave |= dib8000_read_lock(state->fe[index_frontend]); - - *stat = 0; - - if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1)) - *stat |= FE_HAS_SIGNAL; - - if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */ - *stat |= FE_HAS_CARRIER; - - if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */ - *stat |= FE_HAS_SYNC; - - if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */ - *stat |= FE_HAS_LOCK; - - if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) { - lock = dib8000_read_word(state, 554); /* Viterbi Layer A */ - if (lock & 0x01) - *stat |= FE_HAS_VITERBI; - - lock = dib8000_read_word(state, 555); /* Viterbi Layer B */ - if (lock & 0x01) - *stat |= FE_HAS_VITERBI; - - lock = dib8000_read_word(state, 556); /* Viterbi Layer C */ - if (lock & 0x01) - *stat |= FE_HAS_VITERBI; - } - - return 0; -} - -static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber) -{ - struct dib8000_state *state = fe->demodulator_priv; - *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments - return 0; -} - -static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) -{ - struct dib8000_state *state = fe->demodulator_priv; - *unc = dib8000_read_word(state, 565); // packet error on 13 seg - return 0; -} - -static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) -{ - struct dib8000_state *state = fe->demodulator_priv; - u8 index_frontend; - u16 val; - - *strength = 0; - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); - if (val > 65535 - *strength) - *strength = 65535; - else - *strength += val; - } - - val = 65535 - dib8000_read_word(state, 390); - if (val > 65535 - *strength) - *strength = 65535; - else - *strength += val; - return 0; -} - -static u32 dib8000_get_snr(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - u32 n, s, exp; - u16 val; - - val = dib8000_read_word(state, 542); - n = (val >> 6) & 0xff; - exp = (val & 0x3f); - if ((exp & 0x20) != 0) - exp -= 0x40; - n <<= exp+16; - - val = dib8000_read_word(state, 543); - s = (val >> 6) & 0xff; - exp = (val & 0x3f); - if ((exp & 0x20) != 0) - exp -= 0x40; - s <<= exp+16; - - if (n > 0) { - u32 t = (s/n) << 16; - return t + ((s << 16) - n*t) / n; - } - return 0xffffffff; -} - -static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) -{ - struct dib8000_state *state = fe->demodulator_priv; - u8 index_frontend; - u32 snr_master; - - snr_master = dib8000_get_snr(fe); - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - snr_master += dib8000_get_snr(state->fe[index_frontend]); - - if (snr_master != 0) { - snr_master = 10*intlog10(snr_master>>16); - *snr = snr_master / ((1 << 24) / 10); - } - else - *snr = 0; - - return 0; -} - -int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) -{ - struct dib8000_state *state = fe->demodulator_priv; - u8 index_frontend = 1; - - while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) - index_frontend++; - if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { - dprintk("set slave fe %p to index %i", fe_slave, index_frontend); - state->fe[index_frontend] = fe_slave; - return 0; - } - - dprintk("too many slave frontend"); - return -ENOMEM; -} -EXPORT_SYMBOL(dib8000_set_slave_frontend); - -int dib8000_remove_slave_frontend(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - u8 index_frontend = 1; - - while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) - index_frontend++; - if (index_frontend != 1) { - dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1); - state->fe[index_frontend] = NULL; - return 0; - } - - dprintk("no frontend to be removed"); - return -ENODEV; -} -EXPORT_SYMBOL(dib8000_remove_slave_frontend); - -struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) -{ - struct dib8000_state *state = fe->demodulator_priv; - - if (slave_index >= MAX_NUMBER_OF_FRONTENDS) - return NULL; - return state->fe[slave_index]; -} -EXPORT_SYMBOL(dib8000_get_slave_frontend); - - -int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) -{ - int k = 0; - u8 new_addr = 0; - struct i2c_device client = {.adap = host }; - - for (k = no_of_demods - 1; k >= 0; k--) { - /* designated i2c address */ - new_addr = first_addr + (k << 1); - - client.addr = new_addr; - dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ - if (dib8000_identify(&client) == 0) { - dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ - client.addr = default_addr; - if (dib8000_identify(&client) == 0) { - dprintk("#%d: not identified", k); - return -EINVAL; - } - } - - /* start diversity to pull_down div_str - just for i2c-enumeration */ - dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6)); - - /* set new i2c address and force divstart */ - dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2); - client.addr = new_addr; - dib8000_identify(&client); - - dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); - } - - for (k = 0; k < no_of_demods; k++) { - new_addr = first_addr | (k << 1); - client.addr = new_addr; - - // unforce divstr - dib8000_i2c_write16(&client, 1285, new_addr << 2); - - /* deactivate div - it was just for i2c-enumeration */ - dib8000_i2c_write16(&client, 1286, 0); - } - - return 0; -} - -EXPORT_SYMBOL(dib8000_i2c_enumeration); -static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - tune->step_size = 0; - tune->max_drift = 0; - return 0; -} - -static void dib8000_release(struct dvb_frontend *fe) -{ - struct dib8000_state *st = fe->demodulator_priv; - u8 index_frontend; - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) - dvb_frontend_detach(st->fe[index_frontend]); - - dibx000_exit_i2c_master(&st->i2c_master); - kfree(st->fe[0]); - kfree(st); -} - -struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) -{ - struct dib8000_state *st = fe->demodulator_priv; - return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); -} - -EXPORT_SYMBOL(dib8000_get_i2c_master); - -int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) -{ - struct dib8000_state *st = fe->demodulator_priv; - u16 val = dib8000_read_word(st, 299) & 0xffef; - val |= (onoff & 0x1) << 4; - - dprintk("pid filter enabled %d", onoff); - return dib8000_write_word(st, 299, val); -} -EXPORT_SYMBOL(dib8000_pid_filter_ctrl); - -int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) -{ - struct dib8000_state *st = fe->demodulator_priv; - dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); - return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); -} -EXPORT_SYMBOL(dib8000_pid_filter); - -static const struct dvb_frontend_ops dib8000_ops = { - .info = { - .name = "DiBcom 8000 ISDB-T", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, - }, - - .release = dib8000_release, - - .init = dib8000_wakeup, - .sleep = dib8000_sleep, - - .set_frontend = dib8000_set_frontend, - .get_tune_settings = dib8000_fe_get_tune_settings, - .get_frontend = dib8000_get_frontend, - - .read_status = dib8000_read_status, - .read_ber = dib8000_read_ber, - .read_signal_strength = dib8000_read_signal_strength, - .read_snr = dib8000_read_snr, - .read_ucblocks = dib8000_read_unc_blocks, -}; - -struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) -{ - struct dvb_frontend *fe; - struct dib8000_state *state; - - dprintk("dib8000_attach"); - - state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL); - if (state == NULL) - return NULL; - fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); - if (fe == NULL) - goto error; - - memcpy(&state->cfg, cfg, sizeof(struct dib8000_config)); - state->i2c.adap = i2c_adap; - state->i2c.addr = i2c_addr; - state->gpio_val = cfg->gpio_val; - state->gpio_dir = cfg->gpio_dir; - - /* Ensure the output mode remains at the previous default if it's - * not specifically set by the caller. - */ - if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) - state->cfg.output_mode = OUTMODE_MPEG2_FIFO; - - state->fe[0] = fe; - fe->demodulator_priv = state; - memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops)); - - state->timf_default = cfg->pll->timf; - - if (dib8000_identify(&state->i2c) == 0) - goto error; - - dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); - - dib8000_reset(fe); - - dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */ - - return fe; - - error: - kfree(state); - return NULL; -} - -EXPORT_SYMBOL(dib8000_attach); - -MODULE_AUTHOR("Olivier Grenie "); -MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib8000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib8000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib8000.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib8000.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -#ifndef DIB8000_H -#define DIB8000_H - -#include "dibx000_common.h" - -struct dib8000_config { - u8 output_mpeg2_in_188_bytes; - u8 hostbus_diversity; - u8 tuner_is_baseband; - int (*update_lna) (struct dvb_frontend *, u16 agc_global); - - u8 agc_config_count; - struct dibx000_agc_config *agc; - struct dibx000_bandwidth_config *pll; - -#define DIB8000_GPIO_DEFAULT_DIRECTIONS 0xffff - u16 gpio_dir; -#define DIB8000_GPIO_DEFAULT_VALUES 0x0000 - u16 gpio_val; -#define DIB8000_GPIO_PWM_POS0(v) ((v & 0xf) << 12) -#define DIB8000_GPIO_PWM_POS1(v) ((v & 0xf) << 8 ) -#define DIB8000_GPIO_PWM_POS2(v) ((v & 0xf) << 4 ) -#define DIB8000_GPIO_PWM_POS3(v) (v & 0xf) -#define DIB8000_GPIO_DEFAULT_PWM_POS 0xffff - u16 gpio_pwm_pos; - u16 pwm_freq_div; - - void (*agc_control) (struct dvb_frontend *, u8 before); - - u16 drives; - u16 diversity_delay; - u8 div_cfg; - u8 output_mode; - u8 refclksel; -}; - -#define DEFAULT_DIB8000_I2C_ADDRESS 18 - -#if defined(CONFIG_DVB_DIB8000) || (defined(CONFIG_DVB_DIB8000_MODULE) && defined(MODULE)) -extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg); -extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); - -extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); - -extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); -extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); -extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff); -extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); -extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); -extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe); -extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe); -extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode); -extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); -extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe); -extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); -#else -static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} -static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} -static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return CT_SHUTDOWN; -} -static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -} -static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} -static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -int dib8000_remove_slave_frontend(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib9000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib9000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib9000.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib9000.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2351 +0,0 @@ -/* - * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family. - * - * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/) - * - * 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, version 2. - */ -#include -#include -#include - -#include "dvb_math.h" -#include "dvb_frontend.h" - -#include "dib9000.h" -#include "dibx000_common.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); - -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB9000: "); printk(args); printk("\n"); } } while (0) -#define MAX_NUMBER_OF_FRONTENDS 6 - -struct i2c_device { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; -}; - -/* lock */ -#define DIB_LOCK struct mutex -#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0) -#define DibReleaseLock(lock) mutex_unlock(lock) -#define DibInitLock(lock) mutex_init(lock) -#define DibFreeLock(lock) - -struct dib9000_state { - struct i2c_device i2c; - - struct dibx000_i2c_master i2c_master; - struct i2c_adapter tuner_adap; - struct i2c_adapter component_bus; - - u16 revision; - u8 reg_offs; - - enum frontend_tune_state tune_state; - u32 status; - struct dvb_frontend_parametersContext channel_status; - - u8 fe_id; - -#define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff - u16 gpio_dir; -#define DIB9000_GPIO_DEFAULT_VALUES 0x0000 - u16 gpio_val; -#define DIB9000_GPIO_DEFAULT_PWM_POS 0xffff - u16 gpio_pwm_pos; - - union { /* common for all chips */ - struct { - u8 mobile_mode:1; - } host; - - struct { - struct dib9000_fe_memory_map { - u16 addr; - u16 size; - } fe_mm[18]; - u8 memcmd; - - DIB_LOCK mbx_if_lock; /* to protect read/write operations */ - DIB_LOCK mbx_lock; /* to protect the whole mailbox handling */ - - DIB_LOCK mem_lock; /* to protect the memory accesses */ - DIB_LOCK mem_mbx_lock; /* to protect the memory-based mailbox */ - -#define MBX_MAX_WORDS (256 - 200 - 2) -#define DIB9000_MSG_CACHE_SIZE 2 - u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS]; - u8 fw_is_running; - } risc; - } platform; - - union { /* common for all platforms */ - struct { - struct dib9000_config cfg; - } d9; - } chip; - - struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; - u16 component_bus_speed; -}; - -u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 -}; - -enum dib9000_power_mode { - DIB9000_POWER_ALL = 0, - - DIB9000_POWER_NO, - DIB9000_POWER_INTERF_ANALOG_AGC, - DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD, - DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD, - DIB9000_POWER_INTERFACE_ONLY, -}; - -enum dib9000_out_messages { - OUT_MSG_HBM_ACK, - OUT_MSG_HOST_BUF_FAIL, - OUT_MSG_REQ_VERSION, - OUT_MSG_BRIDGE_I2C_W, - OUT_MSG_BRIDGE_I2C_R, - OUT_MSG_BRIDGE_APB_W, - OUT_MSG_BRIDGE_APB_R, - OUT_MSG_SCAN_CHANNEL, - OUT_MSG_MONIT_DEMOD, - OUT_MSG_CONF_GPIO, - OUT_MSG_DEBUG_HELP, - OUT_MSG_SUBBAND_SEL, - OUT_MSG_ENABLE_TIME_SLICE, - OUT_MSG_FE_FW_DL, - OUT_MSG_FE_CHANNEL_SEARCH, - OUT_MSG_FE_CHANNEL_TUNE, - OUT_MSG_FE_SLEEP, - OUT_MSG_FE_SYNC, - OUT_MSG_CTL_MONIT, - - OUT_MSG_CONF_SVC, - OUT_MSG_SET_HBM, - OUT_MSG_INIT_DEMOD, - OUT_MSG_ENABLE_DIVERSITY, - OUT_MSG_SET_OUTPUT_MODE, - OUT_MSG_SET_PRIORITARY_CHANNEL, - OUT_MSG_ACK_FRG, - OUT_MSG_INIT_PMU, -}; - -enum dib9000_in_messages { - IN_MSG_DATA, - IN_MSG_FRAME_INFO, - IN_MSG_CTL_MONIT, - IN_MSG_ACK_FREE_ITEM, - IN_MSG_DEBUG_BUF, - IN_MSG_MPE_MONITOR, - IN_MSG_RAWTS_MONITOR, - IN_MSG_END_BRIDGE_I2C_RW, - IN_MSG_END_BRIDGE_APB_RW, - IN_MSG_VERSION, - IN_MSG_END_OF_SCAN, - IN_MSG_MONIT_DEMOD, - IN_MSG_ERROR, - IN_MSG_FE_FW_DL_DONE, - IN_MSG_EVENT, - IN_MSG_ACK_CHANGE_SVC, - IN_MSG_HBM_PROF, -}; - -/* memory_access requests */ -#define FE_MM_W_CHANNEL 0 -#define FE_MM_W_FE_INFO 1 -#define FE_MM_RW_SYNC 2 - -#define FE_SYNC_CHANNEL 1 -#define FE_SYNC_W_GENERIC_MONIT 2 -#define FE_SYNC_COMPONENT_ACCESS 3 - -#define FE_MM_R_CHANNEL_SEARCH_STATE 3 -#define FE_MM_R_CHANNEL_UNION_CONTEXT 4 -#define FE_MM_R_FE_INFO 5 -#define FE_MM_R_FE_MONITOR 6 - -#define FE_MM_W_CHANNEL_HEAD 7 -#define FE_MM_W_CHANNEL_UNION 8 -#define FE_MM_W_CHANNEL_CONTEXT 9 -#define FE_MM_R_CHANNEL_UNION 10 -#define FE_MM_R_CHANNEL_CONTEXT 11 -#define FE_MM_R_CHANNEL_TUNE_STATE 12 - -#define FE_MM_R_GENERIC_MONITORING_SIZE 13 -#define FE_MM_W_GENERIC_MONITORING 14 -#define FE_MM_R_GENERIC_MONITORING 15 - -#define FE_MM_W_COMPONENT_ACCESS 16 -#define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17 -static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len); -static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len); - -static u16 to_fw_output_mode(u16 mode) -{ - switch (mode) { - case OUTMODE_HIGH_Z: - return 0; - case OUTMODE_MPEG2_PAR_GATED_CLK: - return 4; - case OUTMODE_MPEG2_PAR_CONT_CLK: - return 8; - case OUTMODE_MPEG2_SERIAL: - return 16; - case OUTMODE_DIVERSITY: - return 128; - case OUTMODE_MPEG2_FIFO: - return 2; - case OUTMODE_ANALOG_ADC: - return 1; - default: - return 0; - } -} - -static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32 len, u16 attribute) -{ - u32 chunk_size = 126; - u32 l; - int ret; - u8 wb[2] = { reg >> 8, reg & 0xff }; - struct i2c_msg msg[2] = { - {.addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2}, - {.addr = state->i2c.i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = len}, - }; - - if (state->platform.risc.fw_is_running && (reg < 1024)) - return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len); - - if (attribute & DATA_BUS_ACCESS_MODE_8BIT) - wb[0] |= (1 << 5); - if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) - wb[0] |= (1 << 4); - - do { - l = len < chunk_size ? len : chunk_size; - msg[1].len = l; - msg[1].buf = b; - ret = i2c_transfer(state->i2c.i2c_adap, msg, 2) != 2 ? -EREMOTEIO : 0; - if (ret != 0) { - dprintk("i2c read error on %d", reg); - return -EREMOTEIO; - } - - b += l; - len -= l; - - if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) - reg += l / 2; - } while ((ret == 0) && len); - - return 0; -} - -static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg) -{ - u8 b[2]; - u8 wb[2] = { reg >> 8, reg & 0xff }; - struct i2c_msg msg[2] = { - {.addr = i2c->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2}, - {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = 2}, - }; - - if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) { - dprintk("read register %x error", reg); - return 0; - } - - return (b[0] << 8) | b[1]; -} - -static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg) -{ - u8 b[2]; - if (dib9000_read16_attr(state, reg, b, 2, 0) != 0) - return 0; - return (b[0] << 8 | b[1]); -} - -static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute) -{ - u8 b[2]; - if (dib9000_read16_attr(state, reg, b, 2, attribute) != 0) - return 0; - return (b[0] << 8 | b[1]); -} - -#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) - -static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute) -{ - u8 b[255]; - u32 chunk_size = 126; - u32 l; - int ret; - - struct i2c_msg msg = { - .addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = b, .len = len + 2 - }; - - if (state->platform.risc.fw_is_running && (reg < 1024)) { - if (dib9000_risc_apb_access_write - (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0) - return -EINVAL; - return 0; - } - - b[0] = (reg >> 8) & 0xff; - b[1] = (reg) & 0xff; - - if (attribute & DATA_BUS_ACCESS_MODE_8BIT) - b[0] |= (1 << 5); - if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) - b[0] |= (1 << 4); - - do { - l = len < chunk_size ? len : chunk_size; - msg.len = l + 2; - memcpy(&b[2], buf, l); - - ret = i2c_transfer(state->i2c.i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; - - buf += l; - len -= l; - - if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) - reg += l / 2; - } while ((ret == 0) && len); - - return ret; -} - -static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) -{ - u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff }; - struct i2c_msg msg = { - .addr = i2c->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 - }; - - return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; -} - -static inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val) -{ - u8 b[2] = { val >> 8, val & 0xff }; - return dib9000_write16_attr(state, reg, b, 2, 0); -} - -static inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute) -{ - u8 b[2] = { val >> 8, val & 0xff }; - return dib9000_write16_attr(state, reg, b, 2, attribute); -} - -#define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0) -#define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) -#define dib9000_write16_noinc_attr(state, reg, buf, len, attribute) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | (attribute)) - -#define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0) -#define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0) - -#define MAC_IRQ (1 << 1) -#define IRQ_POL_MSK (1 << 4) - -#define dib9000_risc_mem_read_chunks(state, b, len) dib9000_read16_attr(state, 1063, b, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) -#define dib9000_risc_mem_write_chunks(state, buf, len) dib9000_write16_attr(state, 1063, buf, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) - -static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading) -{ - u8 b[14] = { 0 }; - -/* dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */ -/* b[0] = 0 << 7; */ - b[1] = 1; - -/* b[2] = 0; */ -/* b[3] = 0; */ - b[4] = (u8) (addr >> 8); - b[5] = (u8) (addr & 0xff); - -/* b[10] = 0; */ -/* b[11] = 0; */ - b[12] = (u8) (addr >> 8); - b[13] = (u8) (addr & 0xff); - - addr += len; -/* b[6] = 0; */ -/* b[7] = 0; */ - b[8] = (u8) (addr >> 8); - b[9] = (u8) (addr & 0xff); - - dib9000_write(state, 1056, b, 14); - if (reading) - dib9000_write_word(state, 1056, (1 << 15) | 1); - state->platform.risc.memcmd = -1; /* if it was called directly reset it - to force a future setup-call to set it */ -} - -static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd) -{ - struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f]; - /* decide whether we need to "refresh" the memory controller */ - if (state->platform.risc.memcmd == cmd && /* same command */ - !(cmd & 0x80 && m->size < 67)) /* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */ - return; - dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80); - state->platform.risc.memcmd = cmd; -} - -static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len) -{ - if (!state->platform.risc.fw_is_running) - return -EIO; - - DibAcquireLock(&state->platform.risc.mem_lock); - dib9000_risc_mem_setup(state, cmd | 0x80); - dib9000_risc_mem_read_chunks(state, b, len); - DibReleaseLock(&state->platform.risc.mem_lock); - return 0; -} - -static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b) -{ - struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd]; - if (!state->platform.risc.fw_is_running) - return -EIO; - - DibAcquireLock(&state->platform.risc.mem_lock); - dib9000_risc_mem_setup(state, cmd); - dib9000_risc_mem_write_chunks(state, b, m->size); - DibReleaseLock(&state->platform.risc.mem_lock); - return 0; -} - -static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len) -{ - u16 offs; - - if (risc_id == 1) - offs = 16; - else - offs = 0; - - /* config crtl reg */ - dib9000_write_word(state, 1024 + offs, 0x000f); - dib9000_write_word(state, 1025 + offs, 0); - dib9000_write_word(state, 1031 + offs, key); - - dprintk("going to download %dB of microcode", len); - if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) { - dprintk("error while downloading microcode for RISC %c", 'A' + risc_id); - return -EIO; - } - - dprintk("Microcode for RISC %c loaded", 'A' + risc_id); - - return 0; -} - -static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id) -{ - u16 mbox_offs; - u16 reset_reg; - u16 tries = 1000; - - if (risc_id == 1) - mbox_offs = 16; - else - mbox_offs = 0; - - /* Reset mailbox */ - dib9000_write_word(state, 1027 + mbox_offs, 0x8000); - - /* Read reset status */ - do { - reset_reg = dib9000_read_word(state, 1027 + mbox_offs); - msleep(100); - } while ((reset_reg & 0x8000) && --tries); - - if (reset_reg & 0x8000) { - dprintk("MBX: init ERROR, no response from RISC %c", 'A' + risc_id); - return -EIO; - } - dprintk("MBX: initialized"); - return 0; -} - -#define MAX_MAILBOX_TRY 100 -static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr) -{ - u8 *d, b[2]; - u16 tmp; - u16 size; - u32 i; - int ret = 0; - - if (!state->platform.risc.fw_is_running) - return -EINVAL; - - DibAcquireLock(&state->platform.risc.mbx_if_lock); - tmp = MAX_MAILBOX_TRY; - do { - size = dib9000_read_word_attr(state, 1043, attr) & 0xff; - if ((size + len + 1) > MBX_MAX_WORDS && --tmp) { - dprintk("MBX: RISC mbx full, retrying"); - msleep(100); - } else - break; - } while (1); - - /*dprintk( "MBX: size: %d", size); */ - - if (tmp == 0) { - ret = -EINVAL; - goto out; - } -#ifdef DUMP_MSG - dprintk("--> %02x %d ", id, len + 1); - for (i = 0; i < len; i++) - dprintk("%04x ", data[i]); - dprintk("\n"); -#endif - - /* byte-order conversion - works on big (where it is not necessary) or little endian */ - d = (u8 *) data; - for (i = 0; i < len; i++) { - tmp = data[i]; - *d++ = tmp >> 8; - *d++ = tmp & 0xff; - } - - /* write msg */ - b[0] = id; - b[1] = len + 1; - if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) { - ret = -EIO; - goto out; - } - - /* update register nb_mes_in_RX */ - ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr); - -out: - DibReleaseLock(&state->platform.risc.mbx_if_lock); - - return ret; -} - -static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr) -{ -#ifdef DUMP_MSG - u16 *d = data; -#endif - - u16 tmp, i; - u8 size; - u8 mc_base; - - if (!state->platform.risc.fw_is_running) - return 0; - - DibAcquireLock(&state->platform.risc.mbx_if_lock); - if (risc_id == 1) - mc_base = 16; - else - mc_base = 0; - - /* Length and type in the first word */ - *data = dib9000_read_word_attr(state, 1029 + mc_base, attr); - - size = *data & 0xff; - if (size <= MBX_MAX_WORDS) { - data++; - size--; /* Initial word already read */ - - dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr); - - /* to word conversion */ - for (i = 0; i < size; i++) { - tmp = *data; - *data = (tmp >> 8) | (tmp << 8); - data++; - } - -#ifdef DUMP_MSG - dprintk("<-- "); - for (i = 0; i < size + 1; i++) - dprintk("%04x ", d[i]); - dprintk("\n"); -#endif - } else { - dprintk("MBX: message is too big for message cache (%d), flushing message", size); - size--; /* Initial word already read */ - while (size--) - dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr); - } - /* Update register nb_mes_in_TX */ - dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr); - - DibReleaseLock(&state->platform.risc.mbx_if_lock); - - return size + 1; -} - -static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size) -{ - u32 ts = data[1] << 16 | data[0]; - char *b = (char *)&data[2]; - - b[2 * (size - 2) - 1] = '\0'; /* Bullet proof the buffer */ - if (*b == '~') { - b++; - dprintk(b); - } else - dprintk("RISC%d: %d.%04d %s", state->fe_id, ts / 10000, ts % 10000, *b ? b : ""); - return 1; -} - -static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr) -{ - int i; - u8 size; - u16 *block; - /* find a free slot */ - for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { - block = state->platform.risc.message_cache[i]; - if (*block == 0) { - size = dib9000_mbx_read(state, block, 1, attr); - -/* dprintk( "MBX: fetched %04x message to cache", *block); */ - - switch (*block >> 8) { - case IN_MSG_DEBUG_BUF: - dib9000_risc_debug_buf(state, block + 1, size); /* debug-messages are going to be printed right away */ - *block = 0; /* free the block */ - break; -#if 0 - case IN_MSG_DATA: /* FE-TRACE */ - dib9000_risc_data_process(state, block + 1, size); - *block = 0; - break; -#endif - default: - break; - } - - return 1; - } - } - dprintk("MBX: no free cache-slot found for new message..."); - return -1; -} - -static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr) -{ - if (risc_id == 0) - return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f; /* 5 bit field */ - else - return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f; /* 7 bit field */ -} - -static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) -{ - int ret = 0; - u16 tmp; - - if (!state->platform.risc.fw_is_running) - return -1; - - DibAcquireLock(&state->platform.risc.mbx_lock); - - if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ - ret = dib9000_mbx_fetch_to_cache(state, attr); - - tmp = dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ -/* if (tmp) */ -/* dprintk( "cleared IRQ: %x", tmp); */ - DibReleaseLock(&state->platform.risc.mbx_lock); - - return ret; -} - -static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr) -{ - u8 i; - u16 *block; - u16 timeout = 30; - - *msg = 0; - do { - /* dib9000_mbx_get_from_cache(); */ - for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { - block = state->platform.risc.message_cache[i]; - if ((*block >> 8) == id) { - *size = (*block & 0xff) - 1; - memcpy(msg, block + 1, (*size) * 2); - *block = 0; /* free the block */ - i = 0; /* signal that we found a message */ - break; - } - } - - if (i == 0) - break; - - if (dib9000_mbx_process(state, attr) == -1) /* try to fetch one message - if any */ - return -1; - - } while (--timeout); - - if (timeout == 0) { - dprintk("waiting for message %d timed out", id); - return -1; - } - - return i == 0; -} - -static int dib9000_risc_check_version(struct dib9000_state *state) -{ - u8 r[4]; - u8 size; - u16 fw_version = 0; - - if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0) - return -EIO; - - if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0) - return -EIO; - - fw_version = (r[0] << 8) | r[1]; - dprintk("RISC: ver: %d.%02d (IC: %d)", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]); - - if ((fw_version >> 10) != 7) - return -EINVAL; - - switch (fw_version & 0x3ff) { - case 11: - case 12: - case 14: - case 15: - case 16: - case 17: - break; - default: - dprintk("RISC: invalid firmware version"); - return -EINVAL; - } - - dprintk("RISC: valid firmware version"); - return 0; -} - -static int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB) -{ - /* Reconfig pool mac ram */ - dib9000_write_word(state, 1225, 0x02); /* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */ - dib9000_write_word(state, 1226, 0x05); - - /* Toggles IP crypto to Host APB interface. */ - dib9000_write_word(state, 1542, 1); - - /* Set jump and no jump in the dma box */ - dib9000_write_word(state, 1074, 0); - dib9000_write_word(state, 1075, 0); - - /* Set MAC as APB Master. */ - dib9000_write_word(state, 1237, 0); - - /* Reset the RISCs */ - if (codeA != NULL) - dib9000_write_word(state, 1024, 2); - else - dib9000_write_word(state, 1024, 15); - if (codeB != NULL) - dib9000_write_word(state, 1040, 2); - - if (codeA != NULL) - dib9000_firmware_download(state, 0, 0x1234, codeA, lenA); - if (codeB != NULL) - dib9000_firmware_download(state, 1, 0x1234, codeB, lenB); - - /* Run the RISCs */ - if (codeA != NULL) - dib9000_write_word(state, 1024, 0); - if (codeB != NULL) - dib9000_write_word(state, 1040, 0); - - if (codeA != NULL) - if (dib9000_mbx_host_init(state, 0) != 0) - return -EIO; - if (codeB != NULL) - if (dib9000_mbx_host_init(state, 1) != 0) - return -EIO; - - msleep(100); - state->platform.risc.fw_is_running = 1; - - if (dib9000_risc_check_version(state) != 0) - return -EINVAL; - - state->platform.risc.memcmd = 0xff; - return 0; -} - -static u16 dib9000_identify(struct i2c_device *client) -{ - u16 value; - - value = dib9000_i2c_read16(client, 896); - if (value != 0x01b3) { - dprintk("wrong Vendor ID (0x%x)", value); - return 0; - } - - value = dib9000_i2c_read16(client, 897); - if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) { - dprintk("wrong Device ID (0x%x)", value); - return 0; - } - - /* protect this driver to be used with 7000PC */ - if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) { - dprintk("this driver does not work with DiB7000PC"); - return 0; - } - - switch (value) { - case 0x4000: - dprintk("found DiB7000MA/PA/MB/PB"); - break; - case 0x4001: - dprintk("found DiB7000HC"); - break; - case 0x4002: - dprintk("found DiB7000MC"); - break; - case 0x4003: - dprintk("found DiB9000A"); - break; - case 0x4004: - dprintk("found DiB9000H"); - break; - case 0x4005: - dprintk("found DiB9000M"); - break; - } - - return value; -} - -static void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode) -{ - /* by default everything is going to be powered off */ - u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906; - u8 offset; - - if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005) - offset = 1; - else - offset = 0; - - reg_906 = dib9000_read_word(state, 906 + offset) | 0x3; /* keep settings for RISC */ - - /* now, depending on the requested mode, we power on */ - switch (mode) { - /* power up everything in the demod */ - case DIB9000_POWER_ALL: - reg_903 = 0x0000; - reg_904 = 0x0000; - reg_905 = 0x0000; - reg_906 = 0x0000; - break; - - /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */ - case DIB9000_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */ - reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)); - break; - - case DIB9000_POWER_INTERF_ANALOG_AGC: - reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10)); - reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2)); - reg_906 &= ~((1 << 0)); - break; - - case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD: - reg_903 = 0x0000; - reg_904 = 0x801f; - reg_905 = 0x0000; - reg_906 &= ~((1 << 0)); - break; - - case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD: - reg_903 = 0x0000; - reg_904 = 0x8000; - reg_905 = 0x010b; - reg_906 &= ~((1 << 0)); - break; - default: - case DIB9000_POWER_NO: - break; - } - - /* always power down unused parts */ - if (!state->platform.host.mobile_mode) - reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); - - /* P_sdio_select_clk = 0 on MC and after */ - if (state->revision != 0x4000) - reg_906 <<= 1; - - dib9000_write_word(state, 903 + offset, reg_903); - dib9000_write_word(state, 904 + offset, reg_904); - dib9000_write_word(state, 905 + offset, reg_905); - dib9000_write_word(state, 906 + offset, reg_906); -} - -static int dib9000_fw_reset(struct dvb_frontend *fe) -{ - struct dib9000_state *state = fe->demodulator_priv; - - dib9000_write_word(state, 1817, 0x0003); - - dib9000_write_word(state, 1227, 1); - dib9000_write_word(state, 1227, 0); - - switch ((state->revision = dib9000_identify(&state->i2c))) { - case 0x4003: - case 0x4004: - case 0x4005: - state->reg_offs = 1; - break; - default: - return -EINVAL; - } - - /* reset the i2c-master to use the host interface */ - dibx000_reset_i2c_master(&state->i2c_master); - - dib9000_set_power_mode(state, DIB9000_POWER_ALL); - - /* unforce divstr regardless whether i2c enumeration was done or not */ - dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1)); - dib9000_write_word(state, 1796, 0); - dib9000_write_word(state, 1805, 0x805); - - /* restart all parts */ - dib9000_write_word(state, 898, 0xffff); - dib9000_write_word(state, 899, 0xffff); - dib9000_write_word(state, 900, 0x0001); - dib9000_write_word(state, 901, 0xff19); - dib9000_write_word(state, 902, 0x003c); - - dib9000_write_word(state, 898, 0); - dib9000_write_word(state, 899, 0); - dib9000_write_word(state, 900, 0); - dib9000_write_word(state, 901, 0); - dib9000_write_word(state, 902, 0); - - dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives); - - dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY); - - return 0; -} - -static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len) -{ - u16 mb[10]; - u8 i, s; - - if (address >= 1024 || !state->platform.risc.fw_is_running) - return -EINVAL; - - /* dprintk( "APB access thru rd fw %d %x", address, attribute); */ - - mb[0] = (u16) address; - mb[1] = len / 2; - dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute); - switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) { - case 1: - s--; - for (i = 0; i < s; i++) { - b[i * 2] = (mb[i + 1] >> 8) & 0xff; - b[i * 2 + 1] = (mb[i + 1]) & 0xff; - } - return 0; - default: - return -EIO; - } - return -EIO; -} - -static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len) -{ - u16 mb[10]; - u8 s, i; - - if (address >= 1024 || !state->platform.risc.fw_is_running) - return -EINVAL; - - /* dprintk( "APB access thru wr fw %d %x", address, attribute); */ - - mb[0] = (unsigned short)address; - for (i = 0; i < len && i < 20; i += 2) - mb[1 + (i / 2)] = (b[i] << 8 | b[i + 1]); - - dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, 1 + len / 2, attribute); - return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL; -} - -static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i) -{ - u8 index_loop = 10; - - if (!state->platform.risc.fw_is_running) - return 0; - dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i); - do { - dib9000_risc_mem_read(state, FE_MM_RW_SYNC, &i, 1); - } while (i && index_loop--); - - if (index_loop > 0) - return 0; - return -EIO; -} - -static int dib9000_fw_init(struct dib9000_state *state) -{ - struct dibGPIOFunction *f; - u16 b[40] = { 0 }; - u8 i; - u8 size; - - if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0) - return -EIO; - - /* initialize the firmware */ - for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) { - f = &state->chip.d9.cfg.gpio_function[i]; - if (f->mask) { - switch (f->function) { - case BOARD_GPIO_FUNCTION_COMPONENT_ON: - b[0] = (u16) f->mask; - b[1] = (u16) f->direction; - b[2] = (u16) f->value; - break; - case BOARD_GPIO_FUNCTION_COMPONENT_OFF: - b[3] = (u16) f->mask; - b[4] = (u16) f->direction; - b[5] = (u16) f->value; - break; - } - } - } - if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0) - return -EIO; - - /* subband */ - b[0] = state->chip.d9.cfg.subband.size; /* type == 0 -> GPIO - PWM not yet supported */ - for (i = 0; i < state->chip.d9.cfg.subband.size; i++) { - b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz; - b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask; - b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction; - b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value; - } - b[1 + i * 4] = 0; /* fe_id */ - if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0) - return -EIO; - - /* 0 - id, 1 - no_of_frontends */ - b[0] = (0 << 8) | 1; - /* 0 = i2c-address demod, 0 = tuner */ - b[1] = (0 << 8) | (0); - b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff); - b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff); - b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff); - b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff); - b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff); - b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff); - b[29] = state->chip.d9.cfg.if_drives; - if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0) - return -EIO; - - if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0) - return -EIO; - - if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0) - return -EIO; - - if (size > ARRAY_SIZE(b)) { - dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size, - (int)ARRAY_SIZE(b)); - return -EINVAL; - } - - for (i = 0; i < size; i += 2) { - state->platform.risc.fe_mm[i / 2].addr = b[i + 0]; - state->platform.risc.fe_mm[i / 2].size = b[i + 1]; - } - - return 0; -} - -static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_frontend_parameters *ch) -{ - u8 b[9]; - u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000; - if (state->fe_id % 2) - freq += 101; - - b[0] = (u8) ((freq >> 0) & 0xff); - b[1] = (u8) ((freq >> 8) & 0xff); - b[2] = (u8) ((freq >> 16) & 0xff); - b[3] = (u8) ((freq >> 24) & 0xff); - b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff); - b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff); - b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff); - b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff); - b[8] = 0x80; /* do not wait for CELL ID when doing autosearch */ - if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT) - b[8] |= 1; - dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b); -} - -static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) -{ - struct dib9000_state *state = fe->demodulator_priv; - struct dibDVBTChannel { - s8 spectrum_inversion; - - s8 nfft; - s8 guard; - s8 constellation; - - s8 hrch; - s8 alpha; - s8 code_rate_hp; - s8 code_rate_lp; - s8 select_hp; - - s8 intlv_native; - }; - struct dibDVBTChannel ch; - int ret = 0; - - DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - goto error; - ret = -EIO; - } - - dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) &ch, sizeof(struct dibDVBTChannel)); - - switch (ch.spectrum_inversion & 0x7) { - case 1: - state->fe[0]->dtv_property_cache.inversion = INVERSION_ON; - break; - case 0: - state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF; - break; - default: - case -1: - state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO; - break; - } - switch (ch.nfft) { - case 0: - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; - break; - case 2: - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K; - break; - case 1: - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; - break; - default: - case -1: - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; - break; - } - switch (ch.guard) { - case 0: - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; - break; - default: - case -1: - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; - break; - } - switch (ch.constellation) { - case 2: - state->fe[0]->dtv_property_cache.modulation = QAM_64; - break; - case 1: - state->fe[0]->dtv_property_cache.modulation = QAM_16; - break; - case 0: - state->fe[0]->dtv_property_cache.modulation = QPSK; - break; - default: - case -1: - state->fe[0]->dtv_property_cache.modulation = QAM_AUTO; - break; - } - switch (ch.hrch) { - case 0: - state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE; - break; - case 1: - state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1; - break; - default: - case -1: - state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO; - break; - } - switch (ch.code_rate_hp) { - case 1: - state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2; - break; - case 2: - state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3; - break; - case 3: - state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4; - break; - case 5: - state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6; - break; - case 7: - state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8; - break; - default: - case -1: - state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO; - break; - } - switch (ch.code_rate_lp) { - case 1: - state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2; - break; - case 2: - state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3; - break; - case 3: - state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4; - break; - case 5: - state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6; - break; - case 7: - state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8; - break; - default: - case -1: - state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO; - break; - } - -error: - DibReleaseLock(&state->platform.risc.mem_mbx_lock); - return ret; -} - -static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) -{ - struct dib9000_state *state = fe->demodulator_priv; - struct dibDVBTChannel { - s8 spectrum_inversion; - - s8 nfft; - s8 guard; - s8 constellation; - - s8 hrch; - s8 alpha; - s8 code_rate_hp; - s8 code_rate_lp; - s8 select_hp; - - s8 intlv_native; - }; - struct dibDVBTChannel ch; - - switch (state->fe[0]->dtv_property_cache.inversion) { - case INVERSION_ON: - ch.spectrum_inversion = 1; - break; - case INVERSION_OFF: - ch.spectrum_inversion = 0; - break; - default: - case INVERSION_AUTO: - ch.spectrum_inversion = -1; - break; - } - switch (state->fe[0]->dtv_property_cache.transmission_mode) { - case TRANSMISSION_MODE_2K: - ch.nfft = 0; - break; - case TRANSMISSION_MODE_4K: - ch.nfft = 2; - break; - case TRANSMISSION_MODE_8K: - ch.nfft = 1; - break; - default: - case TRANSMISSION_MODE_AUTO: - ch.nfft = 1; - break; - } - switch (state->fe[0]->dtv_property_cache.guard_interval) { - case GUARD_INTERVAL_1_32: - ch.guard = 0; - break; - case GUARD_INTERVAL_1_16: - ch.guard = 1; - break; - case GUARD_INTERVAL_1_8: - ch.guard = 2; - break; - case GUARD_INTERVAL_1_4: - ch.guard = 3; - break; - default: - case GUARD_INTERVAL_AUTO: - ch.guard = -1; - break; - } - switch (state->fe[0]->dtv_property_cache.modulation) { - case QAM_64: - ch.constellation = 2; - break; - case QAM_16: - ch.constellation = 1; - break; - case QPSK: - ch.constellation = 0; - break; - default: - case QAM_AUTO: - ch.constellation = -1; - break; - } - switch (state->fe[0]->dtv_property_cache.hierarchy) { - case HIERARCHY_NONE: - ch.hrch = 0; - break; - case HIERARCHY_1: - case HIERARCHY_2: - case HIERARCHY_4: - ch.hrch = 1; - break; - default: - case HIERARCHY_AUTO: - ch.hrch = -1; - break; - } - ch.alpha = 1; - switch (state->fe[0]->dtv_property_cache.code_rate_HP) { - case FEC_1_2: - ch.code_rate_hp = 1; - break; - case FEC_2_3: - ch.code_rate_hp = 2; - break; - case FEC_3_4: - ch.code_rate_hp = 3; - break; - case FEC_5_6: - ch.code_rate_hp = 5; - break; - case FEC_7_8: - ch.code_rate_hp = 7; - break; - default: - case FEC_AUTO: - ch.code_rate_hp = -1; - break; - } - switch (state->fe[0]->dtv_property_cache.code_rate_LP) { - case FEC_1_2: - ch.code_rate_lp = 1; - break; - case FEC_2_3: - ch.code_rate_lp = 2; - break; - case FEC_3_4: - ch.code_rate_lp = 3; - break; - case FEC_5_6: - ch.code_rate_lp = 5; - break; - case FEC_7_8: - ch.code_rate_lp = 7; - break; - default: - case FEC_AUTO: - ch.code_rate_lp = -1; - break; - } - ch.select_hp = 1; - ch.intlv_native = 1; - - dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch); - - return 0; -} - -static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) -{ - struct dib9000_state *state = fe->demodulator_priv; - int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN; - s8 i; - - switch (state->tune_state) { - case CT_DEMOD_START: - dib9000_fw_set_channel_head(state, ch); - - /* write the channel context - a channel is initialized to 0, so it is OK */ - dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info); - dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info); - - if (search) - dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0); - else { - dib9000_fw_set_channel_union(fe, ch); - dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0); - } - state->tune_state = CT_DEMOD_STEP_1; - break; - case CT_DEMOD_STEP_1: - if (search) - dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) &i, 1); - else - dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) &i, 1); - switch (i) { /* something happened */ - case 0: - break; - case -2: /* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */ - if (search) - state->status = FE_STATUS_DEMOD_SUCCESS; - else { - state->tune_state = CT_DEMOD_STOP; - state->status = FE_STATUS_LOCKED; - } - break; - default: - state->status = FE_STATUS_TUNE_FAILED; - state->tune_state = CT_DEMOD_STOP; - break; - } - break; - default: - ret = FE_CALLBACK_TIME_NEVER; - break; - } - - return ret; -} - -static int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff) -{ - struct dib9000_state *state = fe->demodulator_priv; - u16 mode = (u16) onoff; - return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1); -} - -static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode) -{ - struct dib9000_state *state = fe->demodulator_priv; - u16 outreg, smo_mode; - - dprintk("setting output mode for demod %p to %d", fe, mode); - - switch (mode) { - case OUTMODE_MPEG2_PAR_GATED_CLK: - outreg = (1 << 10); /* 0x0400 */ - break; - case OUTMODE_MPEG2_PAR_CONT_CLK: - outreg = (1 << 10) | (1 << 6); /* 0x0440 */ - break; - case OUTMODE_MPEG2_SERIAL: - outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ - break; - case OUTMODE_DIVERSITY: - outreg = (1 << 10) | (4 << 6); /* 0x0500 */ - break; - case OUTMODE_MPEG2_FIFO: - outreg = (1 << 10) | (5 << 6); - break; - case OUTMODE_HIGH_Z: - outreg = 0; - break; - default: - dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]); - return -EINVAL; - } - - dib9000_write_word(state, 1795, outreg); - - switch (mode) { - case OUTMODE_MPEG2_PAR_GATED_CLK: - case OUTMODE_MPEG2_PAR_CONT_CLK: - case OUTMODE_MPEG2_SERIAL: - case OUTMODE_MPEG2_FIFO: - smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1); - if (state->chip.d9.cfg.output_mpeg2_in_188_bytes) - smo_mode |= (1 << 5); - dib9000_write_word(state, 295, smo_mode); - break; - } - - outreg = to_fw_output_mode(mode); - return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1); -} - -static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) -{ - struct dib9000_state *state = i2c_get_adapdata(i2c_adap); - u16 i, len, t, index_msg; - - for (index_msg = 0; index_msg < num; index_msg++) { - if (msg[index_msg].flags & I2C_M_RD) { /* read */ - len = msg[index_msg].len; - if (len > 16) - len = 16; - - if (dib9000_read_word(state, 790) != 0) - dprintk("TunerITF: read busy"); - - dib9000_write_word(state, 784, (u16) (msg[index_msg].addr)); - dib9000_write_word(state, 787, (len / 2) - 1); - dib9000_write_word(state, 786, 1); /* start read */ - - i = 1000; - while (dib9000_read_word(state, 790) != (len / 2) && i) - i--; - - if (i == 0) - dprintk("TunerITF: read failed"); - - for (i = 0; i < len; i += 2) { - t = dib9000_read_word(state, 785); - msg[index_msg].buf[i] = (t >> 8) & 0xff; - msg[index_msg].buf[i + 1] = (t) & 0xff; - } - if (dib9000_read_word(state, 790) != 0) - dprintk("TunerITF: read more data than expected"); - } else { - i = 1000; - while (dib9000_read_word(state, 789) && i) - i--; - if (i == 0) - dprintk("TunerITF: write busy"); - - len = msg[index_msg].len; - if (len > 16) - len = 16; - - for (i = 0; i < len; i += 2) - dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]); - dib9000_write_word(state, 784, (u16) msg[index_msg].addr); - dib9000_write_word(state, 787, (len / 2) - 1); - dib9000_write_word(state, 786, 0); /* start write */ - - i = 1000; - while (dib9000_read_word(state, 791) > 0 && i) - i--; - if (i == 0) - dprintk("TunerITF: write failed"); - } - } - return num; -} - -int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed) -{ - struct dib9000_state *state = fe->demodulator_priv; - - state->component_bus_speed = speed; - return 0; -} -EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed); - -static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) -{ - struct dib9000_state *state = i2c_get_adapdata(i2c_adap); - u8 type = 0; /* I2C */ - u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4; - u16 scl = state->component_bus_speed; /* SCL frequency */ - struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER]; - u8 p[13] = { 0 }; - - p[0] = type; - p[1] = port; - p[2] = msg[0].addr << 1; - - p[3] = (u8) scl & 0xff; /* scl */ - p[4] = (u8) (scl >> 8); - - p[7] = 0; - p[8] = 0; - - p[9] = (u8) (msg[0].len); - p[10] = (u8) (msg[0].len >> 8); - if ((num > 1) && (msg[1].flags & I2C_M_RD)) { - p[11] = (u8) (msg[1].len); - p[12] = (u8) (msg[1].len >> 8); - } else { - p[11] = 0; - p[12] = 0; - } - - DibAcquireLock(&state->platform.risc.mem_mbx_lock); - - dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p); - - { /* write-part */ - dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0); - dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len); - } - - /* do the transaction */ - if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); - return 0; - } - - /* read back any possible result */ - if ((num > 1) && (msg[1].flags & I2C_M_RD)) - dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len); - - DibReleaseLock(&state->platform.risc.mem_mbx_lock); - - return num; -} - -static u32 dib9000_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm dib9000_tuner_algo = { - .master_xfer = dib9000_tuner_xfer, - .functionality = dib9000_i2c_func, -}; - -static struct i2c_algorithm dib9000_component_bus_algo = { - .master_xfer = dib9000_fw_component_bus_xfer, - .functionality = dib9000_i2c_func, -}; - -struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe) -{ - struct dib9000_state *st = fe->demodulator_priv; - return &st->tuner_adap; -} -EXPORT_SYMBOL(dib9000_get_tuner_interface); - -struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) -{ - struct dib9000_state *st = fe->demodulator_priv; - return &st->component_bus; -} -EXPORT_SYMBOL(dib9000_get_component_bus_interface); - -struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) -{ - struct dib9000_state *st = fe->demodulator_priv; - return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); -} -EXPORT_SYMBOL(dib9000_get_i2c_master); - -int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) -{ - struct dib9000_state *st = fe->demodulator_priv; - - st->i2c.i2c_adap = i2c; - return 0; -} -EXPORT_SYMBOL(dib9000_set_i2c_adapter); - -static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val) -{ - st->gpio_dir = dib9000_read_word(st, 773); - st->gpio_dir &= ~(1 << num); /* reset the direction bit */ - st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ - dib9000_write_word(st, 773, st->gpio_dir); - - st->gpio_val = dib9000_read_word(st, 774); - st->gpio_val &= ~(1 << num); /* reset the direction bit */ - st->gpio_val |= (val & 0x01) << num; /* set the new value */ - dib9000_write_word(st, 774, st->gpio_val); - - dprintk("gpio dir: %04x: gpio val: %04x", st->gpio_dir, st->gpio_val); - - return 0; -} - -int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) -{ - struct dib9000_state *state = fe->demodulator_priv; - return dib9000_cfg_gpio(state, num, dir, val); -} -EXPORT_SYMBOL(dib9000_set_gpio); - -int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) -{ - struct dib9000_state *state = fe->demodulator_priv; - u16 val = dib9000_read_word(state, 294 + 1) & 0xffef; - val |= (onoff & 0x1) << 4; - - dprintk("PID filter enabled %d", onoff); - return dib9000_write_word(state, 294 + 1, val); -} -EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl); - -int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) -{ - struct dib9000_state *state = fe->demodulator_priv; - dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); - return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); -} -EXPORT_SYMBOL(dib9000_fw_pid_filter); - -int dib9000_firmware_post_pll_init(struct dvb_frontend *fe) -{ - struct dib9000_state *state = fe->demodulator_priv; - return dib9000_fw_init(state); -} -EXPORT_SYMBOL(dib9000_firmware_post_pll_init); - -static void dib9000_release(struct dvb_frontend *demod) -{ - struct dib9000_state *st = demod->demodulator_priv; - u8 index_frontend; - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) - dvb_frontend_detach(st->fe[index_frontend]); - - DibFreeLock(&state->platform.risc.mbx_if_lock); - DibFreeLock(&state->platform.risc.mbx_lock); - DibFreeLock(&state->platform.risc.mem_lock); - DibFreeLock(&state->platform.risc.mem_mbx_lock); - dibx000_exit_i2c_master(&st->i2c_master); - - i2c_del_adapter(&st->tuner_adap); - i2c_del_adapter(&st->component_bus); - kfree(st->fe[0]); - kfree(st); -} - -static int dib9000_wakeup(struct dvb_frontend *fe) -{ - return 0; -} - -static int dib9000_sleep(struct dvb_frontend *fe) -{ - struct dib9000_state *state = fe->demodulator_priv; - u8 index_frontend; - int ret; - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); - if (ret < 0) - return ret; - } - return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); -} - -static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dib9000_state *state = fe->demodulator_priv; - u8 index_frontend, sub_index_frontend; - fe_status_t stat; - int ret; - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); - if (stat & FE_HAS_SYNC) { - dprintk("TPS lock on the slave%i", index_frontend); - - /* synchronize the cache with the other frontends */ - state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); - for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); - sub_index_frontend++) { - if (sub_index_frontend != index_frontend) { - state->fe[sub_index_frontend]->dtv_property_cache.modulation = - state->fe[index_frontend]->dtv_property_cache.modulation; - state->fe[sub_index_frontend]->dtv_property_cache.inversion = - state->fe[index_frontend]->dtv_property_cache.inversion; - state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = - state->fe[index_frontend]->dtv_property_cache.transmission_mode; - state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = - state->fe[index_frontend]->dtv_property_cache.guard_interval; - state->fe[sub_index_frontend]->dtv_property_cache.hierarchy = - state->fe[index_frontend]->dtv_property_cache.hierarchy; - state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP = - state->fe[index_frontend]->dtv_property_cache.code_rate_HP; - state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP = - state->fe[index_frontend]->dtv_property_cache.code_rate_LP; - state->fe[sub_index_frontend]->dtv_property_cache.rolloff = - state->fe[index_frontend]->dtv_property_cache.rolloff; - } - } - return 0; - } - } - - /* get the channel from master chip */ - ret = dib9000_fw_get_channel(fe, fep); - if (ret != 0) - return ret; - - /* synchronize the cache with the other frontends */ - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; - state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; - state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval; - state->fe[index_frontend]->dtv_property_cache.modulation = fe->dtv_property_cache.modulation; - state->fe[index_frontend]->dtv_property_cache.hierarchy = fe->dtv_property_cache.hierarchy; - state->fe[index_frontend]->dtv_property_cache.code_rate_HP = fe->dtv_property_cache.code_rate_HP; - state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP; - state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff; - } - - return 0; -} - -static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) -{ - struct dib9000_state *state = fe->demodulator_priv; - state->tune_state = tune_state; - if (tune_state == CT_DEMOD_START) - state->status = FE_STATUS_TUNE_PENDING; - - return 0; -} - -static u32 dib9000_get_status(struct dvb_frontend *fe) -{ - struct dib9000_state *state = fe->demodulator_priv; - return state->status; -} - -static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status) -{ - struct dib9000_state *state = fe->demodulator_priv; - - memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext)); - return 0; -} - -static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dib9000_state *state = fe->demodulator_priv; - int sleep_time, sleep_time_slave; - u32 frontend_status; - u8 nbr_pending, exit_condition, index_frontend, index_frontend_success; - struct dvb_frontend_parametersContext channel_status; - - /* check that the correct parameters are set */ - if (state->fe[0]->dtv_property_cache.frequency == 0) { - dprintk("dib9000: must specify frequency "); - return 0; - } - - if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { - dprintk("dib9000: must specify bandwidth "); - return 0; - } - fe->dtv_property_cache.delivery_system = SYS_DVBT; - - /* set the master status */ - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { - /* no channel specified, autosearch the channel */ - state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN; - } else - state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; - - /* set mode and status for the different frontends */ - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - dib9000_fw_set_diversity_in(state->fe[index_frontend], 1); - - /* synchronization of the cache */ - memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); - - state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT; - dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); - - dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status); - dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); - } - - /* actual tune */ - exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ - index_frontend_success = 0; - do { - sleep_time = dib9000_fw_tune(state->fe[0], NULL); - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); - if (sleep_time == FE_CALLBACK_TIME_NEVER) - sleep_time = sleep_time_slave; - else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) - sleep_time = sleep_time_slave; - } - if (sleep_time != FE_CALLBACK_TIME_NEVER) - msleep(sleep_time / 10); - else - break; - - nbr_pending = 0; - exit_condition = 0; - index_frontend_success = 0; - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - frontend_status = -dib9000_get_status(state->fe[index_frontend]); - if (frontend_status > -FE_STATUS_TUNE_PENDING) { - exit_condition = 2; /* tune success */ - index_frontend_success = index_frontend; - break; - } - if (frontend_status == -FE_STATUS_TUNE_PENDING) - nbr_pending++; /* some frontends are still tuning */ - } - if ((exit_condition != 2) && (nbr_pending == 0)) - exit_condition = 1; /* if all tune are done and no success, exit: tune failed */ - - } while (exit_condition == 0); - - /* check the tune result */ - if (exit_condition == 1) { /* tune failed */ - dprintk("tune failed"); - return 0; - } - - dprintk("tune success on frontend%i", index_frontend_success); - - /* synchronize all the channel cache */ - dib9000_get_frontend(state->fe[0], fep); - - /* retune the other frontends with the found channel */ - channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - /* only retune the frontends which was not tuned success */ - if (index_frontend != index_frontend_success) { - dib9000_set_channel_status(state->fe[index_frontend], &channel_status); - dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); - } - } - do { - sleep_time = FE_CALLBACK_TIME_NEVER; - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - if (index_frontend != index_frontend_success) { - sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); - if (sleep_time == FE_CALLBACK_TIME_NEVER) - sleep_time = sleep_time_slave; - else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) - sleep_time = sleep_time_slave; - } - } - if (sleep_time != FE_CALLBACK_TIME_NEVER) - msleep(sleep_time / 10); - else - break; - - nbr_pending = 0; - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - if (index_frontend != index_frontend_success) { - frontend_status = -dib9000_get_status(state->fe[index_frontend]); - if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING)) - nbr_pending++; /* some frontends are still tuning */ - } - } - } while (nbr_pending != 0); - - /* set the output mode */ - dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode); - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); - - /* turn off the diversity for the last frontend */ - dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); - - return 0; -} - -static u16 dib9000_read_lock(struct dvb_frontend *fe) -{ - struct dib9000_state *state = fe->demodulator_priv; - - return dib9000_read_word(state, 535); -} - -static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) -{ - struct dib9000_state *state = fe->demodulator_priv; - u8 index_frontend; - u16 lock = 0, lock_slave = 0; - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - lock_slave |= dib9000_read_lock(state->fe[index_frontend]); - - lock = dib9000_read_word(state, 535); - - *stat = 0; - - if ((lock & 0x8000) || (lock_slave & 0x8000)) - *stat |= FE_HAS_SIGNAL; - if ((lock & 0x3000) || (lock_slave & 0x3000)) - *stat |= FE_HAS_CARRIER; - if ((lock & 0x0100) || (lock_slave & 0x0100)) - *stat |= FE_HAS_VITERBI; - if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38)) - *stat |= FE_HAS_SYNC; - if ((lock & 0x0008) || (lock_slave & 0x0008)) - *stat |= FE_HAS_LOCK; - - return 0; -} - -static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) -{ - struct dib9000_state *state = fe->demodulator_priv; - u16 c[16]; - - DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; - dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); - - *ber = c[10] << 16 | c[11]; - return 0; -} - -static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) -{ - struct dib9000_state *state = fe->demodulator_priv; - u8 index_frontend; - u16 c[16]; - u16 val; - - *strength = 0; - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); - if (val > 65535 - *strength) - *strength = 65535; - else - *strength += val; - } - - DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; - dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); - - val = 65535 - c[4]; - if (val > 65535 - *strength) - *strength = 65535; - else - *strength += val; - return 0; -} - -static u32 dib9000_get_snr(struct dvb_frontend *fe) -{ - struct dib9000_state *state = fe->demodulator_priv; - u16 c[16]; - u32 n, s, exp; - u16 val; - - DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; - dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); - - val = c[7]; - n = (val >> 4) & 0xff; - exp = ((val & 0xf) << 2); - val = c[8]; - exp += ((val >> 14) & 0x3); - if ((exp & 0x20) != 0) - exp -= 0x40; - n <<= exp + 16; - - s = (val >> 6) & 0xFF; - exp = (val & 0x3F); - if ((exp & 0x20) != 0) - exp -= 0x40; - s <<= exp + 16; - - if (n > 0) { - u32 t = (s / n) << 16; - return t + ((s << 16) - n * t) / n; - } - return 0xffffffff; -} - -static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) -{ - struct dib9000_state *state = fe->demodulator_priv; - u8 index_frontend; - u32 snr_master; - - snr_master = dib9000_get_snr(fe); - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - snr_master += dib9000_get_snr(state->fe[index_frontend]); - - if ((snr_master >> 16) != 0) { - snr_master = 10 * intlog10(snr_master >> 16); - *snr = snr_master / ((1 << 24) / 10); - } else - *snr = 0; - - return 0; -} - -static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) -{ - struct dib9000_state *state = fe->demodulator_priv; - u16 c[16]; - - DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; - dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); - - *unc = c[12]; - return 0; -} - -int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr) -{ - int k = 0; - u8 new_addr = 0; - struct i2c_device client = {.i2c_adap = i2c }; - - client.i2c_addr = default_addr + 16; - dib9000_i2c_write16(&client, 1796, 0x0); - - for (k = no_of_demods - 1; k >= 0; k--) { - /* designated i2c address */ - new_addr = first_addr + (k << 1); - client.i2c_addr = default_addr; - - dib9000_i2c_write16(&client, 1817, 3); - dib9000_i2c_write16(&client, 1796, 0); - dib9000_i2c_write16(&client, 1227, 1); - dib9000_i2c_write16(&client, 1227, 0); - - client.i2c_addr = new_addr; - dib9000_i2c_write16(&client, 1817, 3); - dib9000_i2c_write16(&client, 1796, 0); - dib9000_i2c_write16(&client, 1227, 1); - dib9000_i2c_write16(&client, 1227, 0); - - if (dib9000_identify(&client) == 0) { - client.i2c_addr = default_addr; - if (dib9000_identify(&client) == 0) { - dprintk("DiB9000 #%d: not identified", k); - return -EIO; - } - } - - dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6)); - dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2); - - dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); - } - - for (k = 0; k < no_of_demods; k++) { - new_addr = first_addr | (k << 1); - client.i2c_addr = new_addr; - - dib9000_i2c_write16(&client, 1794, (new_addr << 2)); - dib9000_i2c_write16(&client, 1795, 0); - } - - return 0; -} -EXPORT_SYMBOL(dib9000_i2c_enumeration); - -int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) -{ - struct dib9000_state *state = fe->demodulator_priv; - u8 index_frontend = 1; - - while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) - index_frontend++; - if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { - dprintk("set slave fe %p to index %i", fe_slave, index_frontend); - state->fe[index_frontend] = fe_slave; - return 0; - } - - dprintk("too many slave frontend"); - return -ENOMEM; -} -EXPORT_SYMBOL(dib9000_set_slave_frontend); - -int dib9000_remove_slave_frontend(struct dvb_frontend *fe) -{ - struct dib9000_state *state = fe->demodulator_priv; - u8 index_frontend = 1; - - while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) - index_frontend++; - if (index_frontend != 1) { - dprintk("remove slave fe %p (index %i)", state->fe[index_frontend - 1], index_frontend - 1); - state->fe[index_frontend] = NULL; - return 0; - } - - dprintk("no frontend to be removed"); - return -ENODEV; -} -EXPORT_SYMBOL(dib9000_remove_slave_frontend); - -struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) -{ - struct dib9000_state *state = fe->demodulator_priv; - - if (slave_index >= MAX_NUMBER_OF_FRONTENDS) - return NULL; - return state->fe[slave_index]; -} -EXPORT_SYMBOL(dib9000_get_slave_frontend); - -static struct dvb_frontend_ops dib9000_ops; -struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg) -{ - struct dvb_frontend *fe; - struct dib9000_state *st; - st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL); - if (st == NULL) - return NULL; - fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); - if (fe == NULL) - return NULL; - - memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config)); - st->i2c.i2c_adap = i2c_adap; - st->i2c.i2c_addr = i2c_addr; - - st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS; - st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES; - st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS; - - DibInitLock(&st->platform.risc.mbx_if_lock); - DibInitLock(&st->platform.risc.mbx_lock); - DibInitLock(&st->platform.risc.mem_lock); - DibInitLock(&st->platform.risc.mem_mbx_lock); - - st->fe[0] = fe; - fe->demodulator_priv = st; - memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops)); - - /* Ensure the output mode remains at the previous default if it's - * not specifically set by the caller. - */ - if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) - st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO; - - if (dib9000_identify(&st->i2c) == 0) - goto error; - - dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr); - - st->tuner_adap.dev.parent = i2c_adap->dev.parent; - strncpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", sizeof(st->tuner_adap.name)); - st->tuner_adap.algo = &dib9000_tuner_algo; - st->tuner_adap.algo_data = NULL; - i2c_set_adapdata(&st->tuner_adap, st); - if (i2c_add_adapter(&st->tuner_adap) < 0) - goto error; - - st->component_bus.dev.parent = i2c_adap->dev.parent; - strncpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", sizeof(st->component_bus.name)); - st->component_bus.algo = &dib9000_component_bus_algo; - st->component_bus.algo_data = NULL; - st->component_bus_speed = 340; - i2c_set_adapdata(&st->component_bus, st); - if (i2c_add_adapter(&st->component_bus) < 0) - goto component_bus_add_error; - - dib9000_fw_reset(fe); - - return fe; - -component_bus_add_error: - i2c_del_adapter(&st->tuner_adap); -error: - kfree(st); - return NULL; -} -EXPORT_SYMBOL(dib9000_attach); - -static struct dvb_frontend_ops dib9000_ops = { - .info = { - .name = "DiBcom 9000", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, - }, - - .release = dib9000_release, - - .init = dib9000_wakeup, - .sleep = dib9000_sleep, - - .set_frontend = dib9000_set_frontend, - .get_tune_settings = dib9000_fe_get_tune_settings, - .get_frontend = dib9000_get_frontend, - - .read_status = dib9000_read_status, - .read_ber = dib9000_read_ber, - .read_signal_strength = dib9000_read_signal_strength, - .read_snr = dib9000_read_snr, - .read_ucblocks = dib9000_read_unc_blocks, -}; - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_AUTHOR("Olivier Grenie "); -MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib9000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib9000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib9000.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dib9000.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -#ifndef DIB9000_H -#define DIB9000_H - -#include "dibx000_common.h" - -struct dib9000_config { - u8 dvbt_mode; - u8 output_mpeg2_in_188_bytes; - u8 hostbus_diversity; - struct dibx000_bandwidth_config *bw; - - u16 if_drives; - - u32 timing_frequency; - u32 xtal_clock_khz; - u32 vcxo_timer; - u32 demod_clock_khz; - - const u8 *microcode_B_fe_buffer; - u32 microcode_B_fe_size; - - struct dibGPIOFunction gpio_function[2]; - struct dibSubbandSelection subband; - - u8 output_mode; -}; - -#define DEFAULT_DIB9000_I2C_ADDRESS 18 - -#if defined(CONFIG_DVB_DIB9000) || (defined(CONFIG_DVB_DIB9000_MODULE) && defined(MODULE)) -extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg); -extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); -extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe); -extern struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating); -extern int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val); -extern int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); -extern int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff); -extern int dib9000_firmware_post_pll_init(struct dvb_frontend *fe); -extern int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); -extern int dib9000_remove_slave_frontend(struct dvb_frontend *fe); -extern struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); -extern struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe); -extern int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c); -extern int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed); -#else -static inline struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib9000_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib9000_firmware_post_pll_init(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -int dib9000_remove_slave_frontend(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dibx000_common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dibx000_common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dibx000_common.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dibx000_common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,441 +0,0 @@ -#include - -#include "dibx000_common.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); - -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0) - -static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) -{ - u8 b[4] = { - (reg >> 8) & 0xff, reg & 0xff, - (val >> 8) & 0xff, val & 0xff, - }; - struct i2c_msg msg = { - .addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4 - }; - - return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; -} - -static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) -{ - u8 wb[2] = { reg >> 8, reg & 0xff }; - u8 rb[2]; - struct i2c_msg msg[2] = { - {.addr = mst->i2c_addr, .flags = 0, .buf = wb, .len = 2}, - {.addr = mst->i2c_addr, .flags = I2C_M_RD, .buf = rb, .len = 2}, - }; - - if (i2c_transfer(mst->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d", reg); - - return (rb[0] << 8) | rb[1]; -} - -static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) -{ - int i = 100; - u16 status; - - while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0) - ; - - /* i2c timed out */ - if (i == 0) - return -EREMOTEIO; - - /* no acknowledge */ - if ((status & 0x0080) == 0) - return -EREMOTEIO; - - return 0; -} - -static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop) -{ - u16 data; - u16 da; - u16 i; - u16 txlen = msg->len, len; - const u8 *b = msg->buf; - - while (txlen) { - dibx000_read_word(mst, mst->base_reg + 2); - - len = txlen > 8 ? 8 : txlen; - for (i = 0; i < len; i += 2) { - data = *b++ << 8; - if (i+1 < len) - data |= *b++; - dibx000_write_word(mst, mst->base_reg, data); - } - da = (((u8) (msg->addr)) << 9) | - (1 << 8) | - (1 << 7) | - (0 << 6) | - (0 << 5) | - ((len & 0x7) << 2) | - (0 << 1) | - (0 << 0); - - if (txlen == msg->len) - da |= 1 << 5; /* start */ - - if (txlen-len == 0 && stop) - da |= 1 << 6; /* stop */ - - dibx000_write_word(mst, mst->base_reg+1, da); - - if (dibx000_is_i2c_done(mst) != 0) - return -EREMOTEIO; - txlen -= len; - } - - return 0; -} - -static int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg) -{ - u16 da; - u8 *b = msg->buf; - u16 rxlen = msg->len, len; - - while (rxlen) { - len = rxlen > 8 ? 8 : rxlen; - da = (((u8) (msg->addr)) << 9) | - (1 << 8) | - (1 << 7) | - (0 << 6) | - (0 << 5) | - ((len & 0x7) << 2) | - (1 << 1) | - (0 << 0); - - if (rxlen == msg->len) - da |= 1 << 5; /* start */ - - if (rxlen-len == 0) - da |= 1 << 6; /* stop */ - dibx000_write_word(mst, mst->base_reg+1, da); - - if (dibx000_is_i2c_done(mst) != 0) - return -EREMOTEIO; - - rxlen -= len; - - while (len) { - da = dibx000_read_word(mst, mst->base_reg); - *b++ = (da >> 8) & 0xff; - len--; - if (len >= 1) { - *b++ = da & 0xff; - len--; - } - } - } - - return 0; -} - -int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed) -{ - struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); - - if (mst->device_rev < DIB7000MC && speed < 235) - speed = 235; - return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed)); - -} -EXPORT_SYMBOL(dibx000_i2c_set_speed); - -static u32 dibx000_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, - enum dibx000_i2c_interface intf) -{ - if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { - dprintk("selecting interface: %d", intf); - mst->selected_interface = intf; - return dibx000_write_word(mst, mst->base_reg + 4, intf); - } - return 0; -} - -static int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) -{ - struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); - int msg_index; - int ret = 0; - - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2); - for (msg_index = 0; msg_index < num; msg_index++) { - if (msg[msg_index].flags & I2C_M_RD) { - ret = dibx000_master_i2c_read(mst, &msg[msg_index]); - if (ret != 0) - return 0; - } else { - ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1); - if (ret != 0) - return 0; - } - } - - return num; -} - -static int dibx000_i2c_master_xfer_gpio34(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) -{ - struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); - int msg_index; - int ret = 0; - - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_3_4); - for (msg_index = 0; msg_index < num; msg_index++) { - if (msg[msg_index].flags & I2C_M_RD) { - ret = dibx000_master_i2c_read(mst, &msg[msg_index]); - if (ret != 0) - return 0; - } else { - ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1); - if (ret != 0) - return 0; - } - } - - return num; -} - -static struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = { - .master_xfer = dibx000_i2c_master_xfer_gpio12, - .functionality = dibx000_i2c_func, -}; - -static struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = { - .master_xfer = dibx000_i2c_master_xfer_gpio34, - .functionality = dibx000_i2c_func, -}; - -static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], - u8 addr, int onoff) -{ - u16 val; - - - if (onoff) - val = addr << 8; // bit 7 = use master or not, if 0, the gate is open - else - val = 1 << 7; - - if (mst->device_rev > DIB7000) - val <<= 1; - - tx[0] = (((mst->base_reg + 1) >> 8) & 0xff); - tx[1] = ((mst->base_reg + 1) & 0xff); - tx[2] = val >> 8; - tx[3] = val & 0xff; - - return 0; -} - -static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msg[], int num) -{ - struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); - struct i2c_msg m[2 + num]; - u8 tx_open[4], tx_close[4]; - - memset(m, 0, sizeof(struct i2c_msg) * (2 + num)); - - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); - - dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1); - m[0].addr = mst->i2c_addr; - m[0].buf = tx_open; - m[0].len = 4; - - memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); - - dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0); - m[num + 1].addr = mst->i2c_addr; - m[num + 1].buf = tx_close; - m[num + 1].len = 4; - - return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO; -} - -static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = { - .master_xfer = dibx000_i2c_gated_gpio67_xfer, - .functionality = dibx000_i2c_func, -}; - -static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msg[], int num) -{ - struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); - struct i2c_msg m[2 + num]; - u8 tx_open[4], tx_close[4]; - - memset(m, 0, sizeof(struct i2c_msg) * (2 + num)); - - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); - - dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1); - m[0].addr = mst->i2c_addr; - m[0].buf = tx_open; - m[0].len = 4; - - memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); - - dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0); - m[num + 1].addr = mst->i2c_addr; - m[num + 1].buf = tx_close; - m[num + 1].len = 4; - - return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO; -} - -static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { - .master_xfer = dibx000_i2c_gated_tuner_xfer, - .functionality = dibx000_i2c_func, -}; - -struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, - enum dibx000_i2c_interface intf, - int gating) -{ - struct i2c_adapter *i2c = NULL; - - switch (intf) { - case DIBX000_I2C_INTERFACE_TUNER: - if (gating) - i2c = &mst->gated_tuner_i2c_adap; - break; - case DIBX000_I2C_INTERFACE_GPIO_1_2: - if (!gating) - i2c = &mst->master_i2c_adap_gpio12; - break; - case DIBX000_I2C_INTERFACE_GPIO_3_4: - if (!gating) - i2c = &mst->master_i2c_adap_gpio34; - break; - case DIBX000_I2C_INTERFACE_GPIO_6_7: - if (gating) - i2c = &mst->master_i2c_adap_gpio67; - break; - default: - printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n"); - break; - } - - return i2c; -} - -EXPORT_SYMBOL(dibx000_get_i2c_adapter); - -void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst) -{ - /* initialize the i2c-master by closing the gate */ - u8 tx[4]; - struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 }; - - dibx000_i2c_gate_ctrl(mst, tx, 0, 0); - i2c_transfer(mst->i2c_adap, &m, 1); - mst->selected_interface = 0xff; // the first time force a select of the I2C - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); -} - -EXPORT_SYMBOL(dibx000_reset_i2c_master); - -static int i2c_adapter_init(struct i2c_adapter *i2c_adap, - struct i2c_algorithm *algo, const char *name, - struct dibx000_i2c_master *mst) -{ - strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); - i2c_adap->algo = algo; - i2c_adap->algo_data = NULL; - i2c_set_adapdata(i2c_adap, mst); - if (i2c_add_adapter(i2c_adap) < 0) - return -ENODEV; - return 0; -} - -int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, - struct i2c_adapter *i2c_adap, u8 i2c_addr) -{ - u8 tx[4]; - struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 }; - - mst->device_rev = device_rev; - mst->i2c_adap = i2c_adap; - mst->i2c_addr = i2c_addr >> 1; - - if (device_rev == DIB7000P || device_rev == DIB8000) - mst->base_reg = 1024; - else - mst->base_reg = 768; - - mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent; - if (i2c_adapter_init - (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, - "DiBX000 tuner I2C bus", mst) != 0) - printk(KERN_ERR - "DiBX000: could not initialize the tuner i2c_adapter\n"); - - mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent; - if (i2c_adapter_init - (&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo, - "DiBX000 master GPIO12 I2C bus", mst) != 0) - printk(KERN_ERR - "DiBX000: could not initialize the master i2c_adapter\n"); - - mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent; - if (i2c_adapter_init - (&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo, - "DiBX000 master GPIO34 I2C bus", mst) != 0) - printk(KERN_ERR - "DiBX000: could not initialize the master i2c_adapter\n"); - - mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent; - if (i2c_adapter_init - (&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo, - "DiBX000 master GPIO67 I2C bus", mst) != 0) - printk(KERN_ERR - "DiBX000: could not initialize the master i2c_adapter\n"); - - /* initialize the i2c-master by closing the gate */ - dibx000_i2c_gate_ctrl(mst, tx, 0, 0); - - return i2c_transfer(i2c_adap, &m, 1) == 1; -} - -EXPORT_SYMBOL(dibx000_init_i2c_master); - -void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) -{ - i2c_del_adapter(&mst->gated_tuner_i2c_adap); - i2c_del_adapter(&mst->master_i2c_adap_gpio12); - i2c_del_adapter(&mst->master_i2c_adap_gpio34); - i2c_del_adapter(&mst->master_i2c_adap_gpio67); -} -EXPORT_SYMBOL(dibx000_exit_i2c_master); - - -u32 systime(void) -{ - struct timespec t; - - t = current_kernel_time(); - return (t.tv_sec * 10000) + (t.tv_nsec / 100000); -} -EXPORT_SYMBOL(systime); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Common function the DiBcom demodulator family"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dibx000_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dibx000_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dibx000_common.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dibx000_common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,273 +0,0 @@ -#ifndef DIBX000_COMMON_H -#define DIBX000_COMMON_H - -enum dibx000_i2c_interface { - DIBX000_I2C_INTERFACE_TUNER = 0, - DIBX000_I2C_INTERFACE_GPIO_1_2 = 1, - DIBX000_I2C_INTERFACE_GPIO_3_4 = 2, - DIBX000_I2C_INTERFACE_GPIO_6_7 = 3 -}; - -struct dibx000_i2c_master { -#define DIB3000MC 1 -#define DIB7000 2 -#define DIB7000P 11 -#define DIB7000MC 12 -#define DIB8000 13 - u16 device_rev; - - enum dibx000_i2c_interface selected_interface; - -/* struct i2c_adapter tuner_i2c_adap; */ - struct i2c_adapter gated_tuner_i2c_adap; - struct i2c_adapter master_i2c_adap_gpio12; - struct i2c_adapter master_i2c_adap_gpio34; - struct i2c_adapter master_i2c_adap_gpio67; - - struct i2c_adapter *i2c_adap; - u8 i2c_addr; - - u16 base_reg; -}; - -extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, - u16 device_rev, struct i2c_adapter *i2c_adap, - u8 i2c_addr); -extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master - *mst, - enum dibx000_i2c_interface - intf, int gating); -extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); -extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst); -extern int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed); - -extern u32 systime(void); - -#define BAND_LBAND 0x01 -#define BAND_UHF 0x02 -#define BAND_VHF 0x04 -#define BAND_SBAND 0x08 -#define BAND_FM 0x10 -#define BAND_CBAND 0x20 - -#define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \ - (freq_kHz) <= 115000 ? BAND_FM : \ - (freq_kHz) <= 250000 ? BAND_VHF : \ - (freq_kHz) <= 863000 ? BAND_UHF : \ - (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND ) - -struct dibx000_agc_config { - /* defines the capabilities of this AGC-setting - using the BAND_-defines */ - u8 band_caps; - - u16 setup; - - u16 inv_gain; - u16 time_stabiliz; - - u8 alpha_level; - u16 thlock; - - u8 wbd_inv; - u16 wbd_ref; - u8 wbd_sel; - u8 wbd_alpha; - - u16 agc1_max; - u16 agc1_min; - u16 agc2_max; - u16 agc2_min; - - u8 agc1_pt1; - u8 agc1_pt2; - u8 agc1_pt3; - - u8 agc1_slope1; - u8 agc1_slope2; - - u8 agc2_pt1; - u8 agc2_pt2; - - u8 agc2_slope1; - u8 agc2_slope2; - - u8 alpha_mant; - u8 alpha_exp; - - u8 beta_mant; - u8 beta_exp; - - u8 perform_agc_softsplit; - - struct { - u16 min; - u16 max; - u16 min_thres; - u16 max_thres; - } split; -}; - -struct dibx000_bandwidth_config { - u32 internal; - u32 sampling; - - u8 pll_prediv; - u8 pll_ratio; - u8 pll_range; - u8 pll_reset; - u8 pll_bypass; - - u8 enable_refdiv; - u8 bypclk_div; - u8 IO_CLK_en_core; - u8 ADClkSrc; - u8 modulo; - - u16 sad_cfg; - - u32 ifreq; - u32 timf; - - u32 xtal_hz; -}; - -enum dibx000_adc_states { - DIBX000_SLOW_ADC_ON = 0, - DIBX000_SLOW_ADC_OFF, - DIBX000_ADC_ON, - DIBX000_ADC_OFF, - DIBX000_VBG_ENABLE, - DIBX000_VBG_DISABLE, -}; - -#define BANDWIDTH_TO_KHZ(v) ((v) == BANDWIDTH_8_MHZ ? 8000 : \ - (v) == BANDWIDTH_7_MHZ ? 7000 : \ - (v) == BANDWIDTH_6_MHZ ? 6000 : 8000) - -#define BANDWIDTH_TO_INDEX(v) ( \ - (v) == 8000 ? BANDWIDTH_8_MHZ : \ - (v) == 7000 ? BANDWIDTH_7_MHZ : \ - (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ ) - -/* Chip output mode. */ -#define OUTMODE_HIGH_Z 0 -#define OUTMODE_MPEG2_PAR_GATED_CLK 1 -#define OUTMODE_MPEG2_PAR_CONT_CLK 2 -#define OUTMODE_MPEG2_SERIAL 7 -#define OUTMODE_DIVERSITY 4 -#define OUTMODE_MPEG2_FIFO 5 -#define OUTMODE_ANALOG_ADC 6 - -#define INPUT_MODE_OFF 0x11 -#define INPUT_MODE_DIVERSITY 0x12 -#define INPUT_MODE_MPEG 0x13 - -enum frontend_tune_state { - CT_TUNER_START = 10, - CT_TUNER_STEP_0, - CT_TUNER_STEP_1, - CT_TUNER_STEP_2, - CT_TUNER_STEP_3, - CT_TUNER_STEP_4, - CT_TUNER_STEP_5, - CT_TUNER_STEP_6, - CT_TUNER_STEP_7, - CT_TUNER_STOP, - - CT_AGC_START = 20, - CT_AGC_STEP_0, - CT_AGC_STEP_1, - CT_AGC_STEP_2, - CT_AGC_STEP_3, - CT_AGC_STEP_4, - CT_AGC_STOP, - - CT_DEMOD_START = 30, - CT_DEMOD_STEP_1, - CT_DEMOD_STEP_2, - CT_DEMOD_STEP_3, - CT_DEMOD_STEP_4, - CT_DEMOD_STEP_5, - CT_DEMOD_STEP_6, - CT_DEMOD_STEP_7, - CT_DEMOD_STEP_8, - CT_DEMOD_STEP_9, - CT_DEMOD_STEP_10, - CT_DEMOD_SEARCH_NEXT = 41, - CT_DEMOD_STEP_LOCKED, - CT_DEMOD_STOP, - - CT_DONE = 100, - CT_SHUTDOWN, - -}; - -struct dvb_frontend_parametersContext { -#define CHANNEL_STATUS_PARAMETERS_UNKNOWN 0x01 -#define CHANNEL_STATUS_PARAMETERS_SET 0x02 - u8 status; - u32 tune_time_estimation[2]; - s32 tps_available; - u16 tps[9]; -}; - -#define FE_STATUS_TUNE_FAILED 0 -#define FE_STATUS_TUNE_TIMED_OUT -1 -#define FE_STATUS_TUNE_TIME_TOO_SHORT -2 -#define FE_STATUS_TUNE_PENDING -3 -#define FE_STATUS_STD_SUCCESS -4 -#define FE_STATUS_FFT_SUCCESS -5 -#define FE_STATUS_DEMOD_SUCCESS -6 -#define FE_STATUS_LOCKED -7 -#define FE_STATUS_DATA_LOCKED -8 - -#define FE_CALLBACK_TIME_NEVER 0xffffffff - -#define ABS(x) ((x < 0) ? (-x) : (x)) - -#define DATA_BUS_ACCESS_MODE_8BIT 0x01 -#define DATA_BUS_ACCESS_MODE_16BIT 0x02 -#define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10 - -struct dibGPIOFunction { -#define BOARD_GPIO_COMPONENT_BUS_ADAPTER 1 -#define BOARD_GPIO_COMPONENT_DEMOD 2 - u8 component; - -#define BOARD_GPIO_FUNCTION_BOARD_ON 1 -#define BOARD_GPIO_FUNCTION_BOARD_OFF 2 -#define BOARD_GPIO_FUNCTION_COMPONENT_ON 3 -#define BOARD_GPIO_FUNCTION_COMPONENT_OFF 4 -#define BOARD_GPIO_FUNCTION_SUBBAND_PWM 5 -#define BOARD_GPIO_FUNCTION_SUBBAND_GPIO 6 - u8 function; - -/* mask, direction and value are used specify which GPIO to change GPIO0 - * is LSB and possible GPIO31 is MSB. The same bit-position as in the - * mask is used for the direction and the value. Direction == 1 is OUT, - * 0 == IN. For direction "OUT" value is either 1 or 0, for direction IN - * value has no meaning. - * - * In case of BOARD_GPIO_FUNCTION_PWM mask is giving the GPIO to be - * used to do the PWM. Direction gives the PWModulator to be used. - * Value gives the PWM value in device-dependent scale. - */ - u32 mask; - u32 direction; - u32 value; -}; - -#define MAX_NB_SUBBANDS 8 -struct dibSubbandSelection { - u8 size; /* Actual number of subbands. */ - struct { - u16 f_mhz; - struct dibGPIOFunction gpio; - } subband[MAX_NB_SUBBANDS]; -}; - -#define DEMOD_TIMF_SET 0x00 -#define DEMOD_TIMF_GET 0x01 -#define DEMOD_TIMF_UPDATE 0x02 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1511 +0,0 @@ -/* - * Driver for Micronas drx397xD demodulator - * - * Copyright (C) 2007 Henk Vergonet - * - * 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, or - * (at your option) any later version. - * - * 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, see . - */ - -#define DEBUG /* uncomment if you want debugging output */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "drx397xD.h" - -static const char mod_name[] = "drx397xD"; - -#define MAX_CLOCK_DRIFT 200 /* maximal 200 PPM allowed */ - -#define F_SET_0D0h 1 -#define F_SET_0D4h 2 - -enum fw_ix { -#define _FW_ENTRY(a, b, c) b -#include "drx397xD_fw.h" -}; - -/* chip specifics */ -struct drx397xD_state { - struct i2c_adapter *i2c; - struct dvb_frontend frontend; - struct drx397xD_config config; - enum fw_ix chip_rev; - int flags; - u32 bandwidth_parm; /* internal bandwidth conversions */ - u32 f_osc; /* w90: actual osc frequency [Hz] */ -}; - -/* Firmware */ -static const char *blob_name[] = { -#define _BLOB_ENTRY(a, b) a -#include "drx397xD_fw.h" -}; - -enum blob_ix { -#define _BLOB_ENTRY(a, b) b -#include "drx397xD_fw.h" -}; - -static struct { - const char *name; - const struct firmware *file; - rwlock_t lock; - int refcnt; - const u8 *data[ARRAY_SIZE(blob_name)]; -} fw[] = { -#define _FW_ENTRY(a, b, c) { \ - .name = a, \ - .file = NULL, \ - .lock = __RW_LOCK_UNLOCKED(fw[c].lock), \ - .refcnt = 0, \ - .data = { } } -#include "drx397xD_fw.h" -}; - -/* use only with writer lock acquired */ -static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix) -{ - memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); - if (fw[ix].file) - release_firmware(fw[ix].file); -} - -static void drx_release_fw(struct drx397xD_state *s) -{ - enum fw_ix ix = s->chip_rev; - - pr_debug("%s\n", __func__); - - write_lock(&fw[ix].lock); - if (fw[ix].refcnt) { - fw[ix].refcnt--; - if (fw[ix].refcnt == 0) - _drx_release_fw(s, ix); - } - write_unlock(&fw[ix].lock); -} - -static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix) -{ - const u8 *data; - size_t size, len; - int i = 0, j, rc = -EINVAL; - - pr_debug("%s\n", __func__); - - if (ix < 0 || ix >= ARRAY_SIZE(fw)) - return -EINVAL; - s->chip_rev = ix; - - write_lock(&fw[ix].lock); - if (fw[ix].file) { - rc = 0; - goto exit_ok; - } - memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); - - rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent); - if (rc != 0) { - printk(KERN_ERR "%s: Firmware \"%s\" not available\n", - mod_name, fw[ix].name); - goto exit_err; - } - - if (!fw[ix].file->data || fw[ix].file->size < 10) - goto exit_corrupt; - - data = fw[ix].file->data; - size = fw[ix].file->size; - - if (data[i++] != 2) /* check firmware version */ - goto exit_corrupt; - - do { - switch (data[i++]) { - case 0x00: /* bytecode */ - if (i >= size) - break; - i += data[i]; - case 0x01: /* reset */ - case 0x02: /* sleep */ - i++; - break; - case 0xfe: /* name */ - len = strnlen(&data[i], size - i); - if (i + len + 1 >= size) - goto exit_corrupt; - if (data[i + len + 1] != 0) - goto exit_corrupt; - for (j = 0; j < ARRAY_SIZE(blob_name); j++) { - if (strcmp(blob_name[j], &data[i]) == 0) { - fw[ix].data[j] = &data[i + len + 1]; - pr_debug("Loading %s\n", blob_name[j]); - } - } - i += len + 1; - break; - case 0xff: /* file terminator */ - if (i == size) { - rc = 0; - goto exit_ok; - } - default: - goto exit_corrupt; - } - } while (i < size); - -exit_corrupt: - printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name); -exit_err: - _drx_release_fw(s, ix); - fw[ix].refcnt--; -exit_ok: - fw[ix].refcnt++; - write_unlock(&fw[ix].lock); - - return rc; -} - -/* i2c bus IO */ -static int write_fw(struct drx397xD_state *s, enum blob_ix ix) -{ - const u8 *data; - int len, rc = 0, i = 0; - struct i2c_msg msg = { - .addr = s->config.demod_address, - .flags = 0 - }; - - if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { - pr_debug("%s drx_fw_ix_t out of range\n", __func__); - return -EINVAL; - } - pr_debug("%s %s\n", __func__, blob_name[ix]); - - read_lock(&fw[s->chip_rev].lock); - data = fw[s->chip_rev].data[ix]; - if (!data) { - rc = -EINVAL; - goto exit_rc; - } - - for (;;) { - switch (data[i++]) { - case 0: /* bytecode */ - len = data[i++]; - msg.len = len; - msg.buf = (__u8 *) &data[i]; - if (i2c_transfer(s->i2c, &msg, 1) != 1) { - rc = -EIO; - goto exit_rc; - } - i += len; - break; - case 1: /* reset */ - case 2: /* sleep */ - i++; - break; - default: - goto exit_rc; - } - } -exit_rc: - read_unlock(&fw[s->chip_rev].lock); - - return rc; -} - -/* Function is not endian safe, use the RD16 wrapper below */ -static int _read16(struct drx397xD_state *s, __le32 i2c_adr) -{ - int rc; - u8 a[4]; - __le16 v; - struct i2c_msg msg[2] = { - { - .addr = s->config.demod_address, - .flags = 0, - .buf = a, - .len = sizeof(a) - }, { - .addr = s->config.demod_address, - .flags = I2C_M_RD, - .buf = (u8 *)&v, - .len = sizeof(v) - } - }; - - *(__le32 *) a = i2c_adr; - - rc = i2c_transfer(s->i2c, msg, 2); - if (rc != 2) - return -EIO; - - return le16_to_cpu(v); -} - -/* Function is not endian safe, use the WR16.. wrappers below */ -static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val) -{ - u8 a[6]; - int rc; - struct i2c_msg msg = { - .addr = s->config.demod_address, - .flags = 0, - .buf = a, - .len = sizeof(a) - }; - - *(__le32 *)a = i2c_adr; - *(__le16 *)&a[4] = val; - - rc = i2c_transfer(s->i2c, &msg, 1); - if (rc != 1) - return -EIO; - - return 0; -} - -#define WR16(ss, adr, val) \ - _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val)) -#define WR16_E0(ss, adr, val) \ - _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val)) -#define RD16(ss, adr) \ - _read16(ss, I2C_ADR_C0(adr)) - -#define EXIT_RC(cmd) \ - if ((rc = (cmd)) < 0) \ - goto exit_rc - -/* Tuner callback */ -static int PLL_Set(struct drx397xD_state *s, - struct dvb_frontend_parameters *fep, int *df_tuner) -{ - struct dvb_frontend *fe = &s->frontend; - u32 f_tuner, f = fep->frequency; - int rc; - - pr_debug("%s\n", __func__); - - if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || - (f < s->frontend.ops.tuner_ops.info.frequency_min)) - return -EINVAL; - - *df_tuner = 0; - if (!s->frontend.ops.tuner_ops.set_params || - !s->frontend.ops.tuner_ops.get_frequency) - return -ENOSYS; - - rc = s->frontend.ops.tuner_ops.set_params(fe, fep); - if (rc < 0) - return rc; - - rc = s->frontend.ops.tuner_ops.get_frequency(fe, &f_tuner); - if (rc < 0) - return rc; - - *df_tuner = f_tuner - f; - pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f, - f_tuner); - - return 0; -} - -/* Demodulator helper functions */ -static int SC_WaitForReady(struct drx397xD_state *s) -{ - int cnt = 1000; - int rc; - - pr_debug("%s\n", __func__); - - while (cnt--) { - rc = RD16(s, 0x820043); - if (rc == 0) - return 0; - } - - return -1; -} - -static int SC_SendCommand(struct drx397xD_state *s, int cmd) -{ - int rc; - - pr_debug("%s\n", __func__); - - WR16(s, 0x820043, cmd); - SC_WaitForReady(s); - rc = RD16(s, 0x820042); - if ((rc & 0xffff) == 0xffff) - return -1; - - return 0; -} - -static int HI_Command(struct drx397xD_state *s, u16 cmd) -{ - int rc, cnt = 1000; - - pr_debug("%s\n", __func__); - - rc = WR16(s, 0x420032, cmd); - if (rc < 0) - return rc; - - do { - rc = RD16(s, 0x420032); - if (rc == 0) { - rc = RD16(s, 0x420031); - return rc; - } - if (rc < 0) - return rc; - } while (--cnt); - - return rc; -} - -static int HI_CfgCommand(struct drx397xD_state *s) -{ - - pr_debug("%s\n", __func__); - - WR16(s, 0x420033, 0x3973); - WR16(s, 0x420034, s->config.w50); /* code 4, log 4 */ - WR16(s, 0x420035, s->config.w52); /* code 15, log 9 */ - WR16(s, 0x420036, s->config.demod_address << 1); - WR16(s, 0x420037, s->config.w56); /* code (set_i2c ?? initX 1 ), log 1 */ - /* WR16(s, 0x420033, 0x3973); */ - if ((s->config.w56 & 8) == 0) - return HI_Command(s, 3); - - return WR16(s, 0x420032, 0x3); -} - -static const u8 fastIncrDecLUT_15273[] = { - 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, - 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f -}; - -static const u8 slowIncrDecLUT_15272[] = { - 3, 4, 4, 5, 6 -}; - -static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) -{ - u16 w06 = agc->w06; - u16 w08 = agc->w08; - u16 w0A = agc->w0A; - u16 w0C = agc->w0C; - int quot, rem, i, rc = -EINVAL; - - pr_debug("%s\n", __func__); - - if (agc->w04 > 0x3ff) - goto exit_rc; - - if (agc->d00 == 1) { - EXIT_RC(RD16(s, 0x0c20010)); - rc &= ~0x10; - EXIT_RC(WR16(s, 0x0c20010, rc)); - return WR16(s, 0x0c20030, agc->w04 & 0x7ff); - } - - if (agc->d00 != 0) - goto exit_rc; - if (w0A < w08) - goto exit_rc; - if (w0A > 0x3ff) - goto exit_rc; - if (w0C > 0x3ff) - goto exit_rc; - if (w06 > 0x3ff) - goto exit_rc; - - EXIT_RC(RD16(s, 0x0c20010)); - rc |= 0x10; - EXIT_RC(WR16(s, 0x0c20010, rc)); - - EXIT_RC(WR16(s, 0x0c20025, (w06 >> 1) & 0x1ff)); - EXIT_RC(WR16(s, 0x0c20031, (w0A - w08) >> 1)); - EXIT_RC(WR16(s, 0x0c20032, ((w0A + w08) >> 1) - 0x1ff)); - - quot = w0C / 113; - rem = w0C % 113; - if (quot <= 8) { - quot = 8 - quot; - } else { - quot = 0; - rem += 113; - } - - EXIT_RC(WR16(s, 0x0c20024, quot)); - - i = fastIncrDecLUT_15273[rem / 8]; - EXIT_RC(WR16(s, 0x0c2002d, i)); - EXIT_RC(WR16(s, 0x0c2002e, i)); - - i = slowIncrDecLUT_15272[rem / 28]; - EXIT_RC(WR16(s, 0x0c2002b, i)); - rc = WR16(s, 0x0c2002c, i); -exit_rc: - return rc; -} - -static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) -{ - u16 w04 = agc->w04; - u16 w06 = agc->w06; - int rc = -1; - - pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06); - - if (w04 > 0x3ff) - goto exit_rc; - - switch (agc->d00) { - case 1: - if (w04 == 0x3ff) - w04 = 0x400; - - EXIT_RC(WR16(s, 0x0c20036, w04)); - s->config.w9C &= ~2; - EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); - EXIT_RC(RD16(s, 0x0c20010)); - rc &= 0xbfdf; - EXIT_RC(WR16(s, 0x0c20010, rc)); - EXIT_RC(RD16(s, 0x0c20013)); - rc &= ~2; - break; - case 0: - /* loc_8000659 */ - s->config.w9C &= ~2; - EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); - EXIT_RC(RD16(s, 0x0c20010)); - rc &= 0xbfdf; - rc |= 0x4000; - EXIT_RC(WR16(s, 0x0c20010, rc)); - EXIT_RC(WR16(s, 0x0c20051, (w06 >> 4) & 0x3f)); - EXIT_RC(RD16(s, 0x0c20013)); - rc &= ~2; - break; - default: - s->config.w9C |= 2; - EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); - EXIT_RC(RD16(s, 0x0c20010)); - rc &= 0xbfdf; - EXIT_RC(WR16(s, 0x0c20010, rc)); - - EXIT_RC(WR16(s, 0x0c20036, 0)); - - EXIT_RC(RD16(s, 0x0c20013)); - rc |= 2; - } - rc = WR16(s, 0x0c20013, rc); - -exit_rc: - return rc; -} - -static int GetLockStatus(struct drx397xD_state *s, int *lockstat) -{ - int rc; - - *lockstat = 0; - - rc = RD16(s, 0x082004b); - if (rc < 0) - return rc; - - if (s->config.d60 != 2) - return 0; - - if ((rc & 7) == 7) - *lockstat |= 1; - if ((rc & 3) == 3) - *lockstat |= 2; - if (rc & 1) - *lockstat |= 4; - return 0; -} - -static int CorrectSysClockDeviation(struct drx397xD_state *s) -{ - int rc = -EINVAL; - int lockstat; - u32 clk, clk_limit; - - pr_debug("%s\n", __func__); - - if (s->config.d5C == 0) { - EXIT_RC(WR16(s, 0x08200e8, 0x010)); - EXIT_RC(WR16(s, 0x08200e9, 0x113)); - s->config.d5C = 1; - return rc; - } - if (s->config.d5C != 1) - goto exit_rc; - - rc = RD16(s, 0x0820048); - - rc = GetLockStatus(s, &lockstat); - if (rc < 0) - goto exit_rc; - if ((lockstat & 1) == 0) - goto exit_rc; - - EXIT_RC(WR16(s, 0x0420033, 0x200)); - EXIT_RC(WR16(s, 0x0420034, 0xc5)); - EXIT_RC(WR16(s, 0x0420035, 0x10)); - EXIT_RC(WR16(s, 0x0420036, 0x1)); - EXIT_RC(WR16(s, 0x0420037, 0xa)); - EXIT_RC(HI_Command(s, 6)); - EXIT_RC(RD16(s, 0x0420040)); - clk = rc; - EXIT_RC(RD16(s, 0x0420041)); - clk |= rc << 16; - - if (clk <= 0x26ffff) - goto exit_rc; - if (clk > 0x610000) - goto exit_rc; - - if (!s->bandwidth_parm) - return -EINVAL; - - /* round & convert to Hz */ - clk = ((u64) (clk + 0x800000) * s->bandwidth_parm + (1 << 20)) >> 21; - clk_limit = s->config.f_osc * MAX_CLOCK_DRIFT / 1000; - - if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { - s->f_osc = clk; - pr_debug("%s: osc %d %d [Hz]\n", __func__, - s->config.f_osc * 1000, clk - s->config.f_osc * 1000); - } - rc = WR16(s, 0x08200e8, 0); - -exit_rc: - return rc; -} - -static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) -{ - int rc, si, bp; - - pr_debug("%s\n", __func__); - - si = s->config.wA0; - if (s->config.w98 == 0) { - si |= 1; - bp = 0; - } else { - si &= ~1; - bp = 0x200; - } - if (s->config.w9A == 0) - si |= 0x80; - else - si &= ~0x80; - - EXIT_RC(WR16(s, 0x2150045, 0)); - EXIT_RC(WR16(s, 0x2150010, si)); - EXIT_RC(WR16(s, 0x2150011, bp)); - rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0)); - -exit_rc: - return rc; -} - -static int drx_tune(struct drx397xD_state *s, - struct dvb_frontend_parameters *fep) -{ - u16 v22 = 0; - u16 v1C = 0; - u16 v1A = 0; - u16 v18 = 0; - u32 edi = 0, ebx = 0, ebp = 0, edx = 0; - u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0; - - int rc, df_tuner = 0; - int a, b, c, d; - pr_debug("%s %d\n", __func__, s->config.d60); - - if (s->config.d60 != 2) - goto set_tuner; - rc = CorrectSysClockDeviation(s); - if (rc < 0) - goto set_tuner; - - s->config.d60 = 1; - rc = ConfigureMPEGOutput(s, 0); - if (rc < 0) - goto set_tuner; -set_tuner: - - rc = PLL_Set(s, fep, &df_tuner); - if (rc < 0) { - printk(KERN_ERR "Error in pll_set\n"); - goto exit_rc; - } - msleep(200); - - a = rc = RD16(s, 0x2150016); - if (rc < 0) - goto exit_rc; - b = rc = RD16(s, 0x2150010); - if (rc < 0) - goto exit_rc; - c = rc = RD16(s, 0x2150034); - if (rc < 0) - goto exit_rc; - d = rc = RD16(s, 0x2150035); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x2150014, c); - rc = WR16(s, 0x2150015, d); - rc = WR16(s, 0x2150010, 0); - rc = WR16(s, 0x2150000, 2); - rc = WR16(s, 0x2150036, 0x0fff); - rc = WR16(s, 0x2150016, a); - - rc = WR16(s, 0x2150010, 2); - rc = WR16(s, 0x2150007, 0); - rc = WR16(s, 0x2150000, 1); - rc = WR16(s, 0x2110000, 0); - rc = WR16(s, 0x0800000, 0); - rc = WR16(s, 0x2800000, 0); - rc = WR16(s, 0x2110010, 0x664); - - rc = write_fw(s, DRXD_ResetECRAM); - rc = WR16(s, 0x2110000, 1); - - rc = write_fw(s, DRXD_InitSC); - if (rc < 0) - goto exit_rc; - - rc = SetCfgIfAgc(s, &s->config.ifagc); - if (rc < 0) - goto exit_rc; - - rc = SetCfgRfAgc(s, &s->config.rfagc); - if (rc < 0) - goto exit_rc; - - if (fep->u.ofdm.transmission_mode != TRANSMISSION_MODE_2K) - v22 = 1; - switch (fep->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_8K: - edi = 1; - if (s->chip_rev == DRXD_FW_B1) - break; - - rc = WR16(s, 0x2010010, 0); - if (rc < 0) - break; - v1C = 0x63; - v1A = 0x53; - v18 = 0x43; - break; - default: - edi = 0; - if (s->chip_rev == DRXD_FW_B1) - break; - - rc = WR16(s, 0x2010010, 1); - if (rc < 0) - break; - - v1C = 0x61; - v1A = 0x47; - v18 = 0x41; - } - - switch (fep->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_4: - edi |= 0x0c; - break; - case GUARD_INTERVAL_1_8: - edi |= 0x08; - break; - case GUARD_INTERVAL_1_16: - edi |= 0x04; - break; - case GUARD_INTERVAL_1_32: - break; - default: - v22 |= 2; - } - - ebx = 0; - ebp = 0; - v20 = 0; - v1E = 0; - v16 = 0; - v14 = 0; - v12 = 0; - v10 = 0; - v0E = 0; - - switch (fep->u.ofdm.hierarchy_information) { - case HIERARCHY_1: - edi |= 0x40; - if (s->chip_rev == DRXD_FW_B1) - break; - rc = WR16(s, 0x1c10047, 1); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x2010012, 1); - if (rc < 0) - goto exit_rc; - ebx = 0x19f; - ebp = 0x1fb; - v20 = 0x0c0; - v1E = 0x195; - v16 = 0x1d6; - v14 = 0x1ef; - v12 = 4; - v10 = 5; - v0E = 5; - break; - case HIERARCHY_2: - edi |= 0x80; - if (s->chip_rev == DRXD_FW_B1) - break; - rc = WR16(s, 0x1c10047, 2); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x2010012, 2); - if (rc < 0) - goto exit_rc; - ebx = 0x08f; - ebp = 0x12f; - v20 = 0x0c0; - v1E = 0x11e; - v16 = 0x1d6; - v14 = 0x15e; - v12 = 4; - v10 = 5; - v0E = 5; - break; - case HIERARCHY_4: - edi |= 0xc0; - if (s->chip_rev == DRXD_FW_B1) - break; - rc = WR16(s, 0x1c10047, 3); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x2010012, 3); - if (rc < 0) - goto exit_rc; - ebx = 0x14d; - ebp = 0x197; - v20 = 0x0c0; - v1E = 0x1ce; - v16 = 0x1d6; - v14 = 0x11a; - v12 = 4; - v10 = 6; - v0E = 5; - break; - default: - v22 |= 8; - if (s->chip_rev == DRXD_FW_B1) - break; - rc = WR16(s, 0x1c10047, 0); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x2010012, 0); - if (rc < 0) - goto exit_rc; - /* QPSK QAM16 QAM64 */ - ebx = 0x19f; /* 62 */ - ebp = 0x1fb; /* 15 */ - v20 = 0x16a; /* 62 */ - v1E = 0x195; /* 62 */ - v16 = 0x1bb; /* 15 */ - v14 = 0x1ef; /* 15 */ - v12 = 5; /* 16 */ - v10 = 5; /* 16 */ - v0E = 5; /* 16 */ - } - - switch (fep->u.ofdm.constellation) { - default: - v22 |= 4; - case QPSK: - if (s->chip_rev == DRXD_FW_B1) - break; - - rc = WR16(s, 0x1c10046, 0); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x2010011, 0); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x201001a, 0x10); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x201001b, 0); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x201001c, 0); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c10062, v20); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c1002a, v1C); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c10015, v16); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c10016, v12); - if (rc < 0) - goto exit_rc; - break; - case QAM_16: - edi |= 0x10; - if (s->chip_rev == DRXD_FW_B1) - break; - - rc = WR16(s, 0x1c10046, 1); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x2010011, 1); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x201001a, 0x10); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x201001b, 4); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x201001c, 0); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c10062, v1E); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c1002a, v1A); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c10015, v14); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c10016, v10); - if (rc < 0) - goto exit_rc; - break; - case QAM_64: - edi |= 0x20; - rc = WR16(s, 0x1c10046, 2); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x2010011, 2); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x201001a, 0x20); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x201001b, 8); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x201001c, 2); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c10062, ebx); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c1002a, v18); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c10015, ebp); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x1c10016, v0E); - if (rc < 0) - goto exit_rc; - break; - } - - if (s->config.s20d24 == 1) { - rc = WR16(s, 0x2010013, 0); - } else { - rc = WR16(s, 0x2010013, 1); - edi |= 0x1000; - } - - switch (fep->u.ofdm.code_rate_HP) { - default: - v22 |= 0x10; - case FEC_1_2: - if (s->chip_rev == DRXD_FW_B1) - break; - rc = WR16(s, 0x2090011, 0); - break; - case FEC_2_3: - edi |= 0x200; - if (s->chip_rev == DRXD_FW_B1) - break; - rc = WR16(s, 0x2090011, 1); - break; - case FEC_3_4: - edi |= 0x400; - if (s->chip_rev == DRXD_FW_B1) - break; - rc = WR16(s, 0x2090011, 2); - break; - case FEC_5_6: /* 5 */ - edi |= 0x600; - if (s->chip_rev == DRXD_FW_B1) - break; - rc = WR16(s, 0x2090011, 3); - break; - case FEC_7_8: /* 7 */ - edi |= 0x800; - if (s->chip_rev == DRXD_FW_B1) - break; - rc = WR16(s, 0x2090011, 4); - break; - }; - if (rc < 0) - goto exit_rc; - - switch (fep->u.ofdm.bandwidth) { - default: - rc = -EINVAL; - goto exit_rc; - case BANDWIDTH_8_MHZ: /* 0 */ - case BANDWIDTH_AUTO: - rc = WR16(s, 0x0c2003f, 0x32); - s->bandwidth_parm = ebx = 0x8b8249; - edx = 0; - break; - case BANDWIDTH_7_MHZ: - rc = WR16(s, 0x0c2003f, 0x3b); - s->bandwidth_parm = ebx = 0x7a1200; - edx = 0x4807; - break; - case BANDWIDTH_6_MHZ: - rc = WR16(s, 0x0c2003f, 0x47); - s->bandwidth_parm = ebx = 0x68a1b6; - edx = 0x0f07; - break; - }; - - if (rc < 0) - goto exit_rc; - - rc = WR16(s, 0x08200ec, edx); - if (rc < 0) - goto exit_rc; - - rc = RD16(s, 0x0820050); - if (rc < 0) - goto exit_rc; - rc = WR16(s, 0x0820050, rc); - - { - /* Configure bandwidth specific factor */ - ebx = div64_u64(((u64) (s->f_osc) << 21) + (ebx >> 1), - (u64)ebx) - 0x800000; - EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff)); - EXIT_RC(WR16(s, 0x0c50011, ebx >> 16)); - - /* drx397xD oscillator calibration */ - ebx = div64_u64(((u64) (s->config.f_if + df_tuner) << 28) + - (s->f_osc >> 1), (u64)s->f_osc); - } - ebx &= 0xfffffff; - if (fep->inversion == INVERSION_ON) - ebx = 0x10000000 - ebx; - - EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff)); - EXIT_RC(WR16(s, 0x0c30011, ebx >> 16)); - - EXIT_RC(WR16(s, 0x0800000, 1)); - EXIT_RC(RD16(s, 0x0800000)); - - - EXIT_RC(SC_WaitForReady(s)); - EXIT_RC(WR16(s, 0x0820042, 0)); - EXIT_RC(WR16(s, 0x0820041, v22)); - EXIT_RC(WR16(s, 0x0820040, edi)); - EXIT_RC(SC_SendCommand(s, 3)); - - rc = RD16(s, 0x0800000); - - SC_WaitForReady(s); - WR16(s, 0x0820042, 0); - WR16(s, 0x0820041, 1); - WR16(s, 0x0820040, 1); - SC_SendCommand(s, 1); - - - rc = WR16(s, 0x2150000, 2); - rc = WR16(s, 0x2150016, a); - rc = WR16(s, 0x2150010, 4); - rc = WR16(s, 0x2150036, 0); - rc = WR16(s, 0x2150000, 1); - s->config.d60 = 2; - -exit_rc: - return rc; -} - -/******************************************************************************* - * DVB interface - ******************************************************************************/ - -static int drx397x_init(struct dvb_frontend *fe) -{ - struct drx397xD_state *s = fe->demodulator_priv; - int rc; - - pr_debug("%s\n", __func__); - - s->config.rfagc.d00 = 2; /* 0x7c */ - s->config.rfagc.w04 = 0; - s->config.rfagc.w06 = 0x3ff; - - s->config.ifagc.d00 = 0; /* 0x68 */ - s->config.ifagc.w04 = 0; - s->config.ifagc.w06 = 140; - s->config.ifagc.w08 = 0; - s->config.ifagc.w0A = 0x3ff; - s->config.ifagc.w0C = 0x388; - - /* for signal strenght calculations */ - s->config.ss76 = 820; - s->config.ss78 = 2200; - s->config.ss7A = 150; - - /* HI_CfgCommand */ - s->config.w50 = 4; - s->config.w52 = 9; - - s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ - s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ - s->config.w92 = 12000; - - s->config.w9C = 0x000e; - s->config.w9E = 0x0000; - - /* ConfigureMPEGOutput params */ - s->config.wA0 = 4; - s->config.w98 = 1; - s->config.w9A = 1; - - /* get chip revision */ - rc = RD16(s, 0x2410019); - if (rc < 0) - return -ENODEV; - - if (rc == 0) { - printk(KERN_INFO "%s: chip revision A2\n", mod_name); - rc = drx_load_fw(s, DRXD_FW_A2); - } else { - - rc = (rc >> 12) - 3; - switch (rc) { - case 1: - s->flags |= F_SET_0D4h; - case 0: - case 4: - s->flags |= F_SET_0D0h; - break; - case 2: - case 5: - break; - case 3: - s->flags |= F_SET_0D4h; - break; - default: - return -ENODEV; - }; - printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc); - rc = drx_load_fw(s, DRXD_FW_B1); - } - if (rc < 0) - goto error; - - rc = WR16(s, 0x0420033, 0x3973); - if (rc < 0) - goto error; - - rc = HI_Command(s, 2); - - msleep(1); - - if (s->chip_rev == DRXD_FW_A2) { - rc = WR16(s, 0x043012d, 0x47F); - if (rc < 0) - goto error; - } - rc = WR16_E0(s, 0x0400000, 0); - if (rc < 0) - goto error; - - if (s->config.w92 > 20000 || s->config.w92 % 4000) { - printk(KERN_ERR "%s: invalid osc frequency\n", mod_name); - rc = -1; - goto error; - } - - rc = WR16(s, 0x2410010, 1); - if (rc < 0) - goto error; - rc = WR16(s, 0x2410011, 0x15); - if (rc < 0) - goto error; - rc = WR16(s, 0x2410012, s->config.w92 / 4000); - if (rc < 0) - goto error; -#ifdef ORIG_FW - rc = WR16(s, 0x2410015, 2); - if (rc < 0) - goto error; -#endif - rc = WR16(s, 0x2410017, 0x3973); - if (rc < 0) - goto error; - - s->f_osc = s->config.f_osc * 1000; /* initial estimator */ - - s->config.w56 = 1; - - rc = HI_CfgCommand(s); - if (rc < 0) - goto error; - - rc = write_fw(s, DRXD_InitAtomicRead); - if (rc < 0) - goto error; - - if (s->chip_rev == DRXD_FW_A2) { - rc = WR16(s, 0x2150013, 0); - if (rc < 0) - goto error; - } - - rc = WR16_E0(s, 0x0400002, 0); - if (rc < 0) - goto error; - rc = WR16(s, 0x0400002, 0); - if (rc < 0) - goto error; - - if (s->chip_rev == DRXD_FW_A2) { - rc = write_fw(s, DRXD_ResetCEFR); - if (rc < 0) - goto error; - } - rc = write_fw(s, DRXD_microcode); - if (rc < 0) - goto error; - - s->config.w9C = 0x0e; - if (s->flags & F_SET_0D0h) { - s->config.w9C = 0; - rc = RD16(s, 0x0c20010); - if (rc < 0) - goto write_DRXD_InitFE_1; - - rc &= ~0x1000; - rc = WR16(s, 0x0c20010, rc); - if (rc < 0) - goto write_DRXD_InitFE_1; - - rc = RD16(s, 0x0c20011); - if (rc < 0) - goto write_DRXD_InitFE_1; - - rc &= ~0x8; - rc = WR16(s, 0x0c20011, rc); - if (rc < 0) - goto write_DRXD_InitFE_1; - - rc = WR16(s, 0x0c20012, 1); - } - -write_DRXD_InitFE_1: - - rc = write_fw(s, DRXD_InitFE_1); - if (rc < 0) - goto error; - - rc = 1; - if (s->chip_rev == DRXD_FW_B1) { - if (s->flags & F_SET_0D0h) - rc = 0; - } else { - if (s->flags & F_SET_0D0h) - rc = 4; - } - - rc = WR16(s, 0x0C20012, rc); - if (rc < 0) - goto error; - - rc = WR16(s, 0x0C20013, s->config.w9E); - if (rc < 0) - goto error; - rc = WR16(s, 0x0C20015, s->config.w9C); - if (rc < 0) - goto error; - - rc = write_fw(s, DRXD_InitFE_2); - if (rc < 0) - goto error; - rc = write_fw(s, DRXD_InitFT); - if (rc < 0) - goto error; - rc = write_fw(s, DRXD_InitCP); - if (rc < 0) - goto error; - rc = write_fw(s, DRXD_InitCE); - if (rc < 0) - goto error; - rc = write_fw(s, DRXD_InitEQ); - if (rc < 0) - goto error; - rc = write_fw(s, DRXD_InitEC); - if (rc < 0) - goto error; - rc = write_fw(s, DRXD_InitSC); - if (rc < 0) - goto error; - - rc = SetCfgIfAgc(s, &s->config.ifagc); - if (rc < 0) - goto error; - - rc = SetCfgRfAgc(s, &s->config.rfagc); - if (rc < 0) - goto error; - - rc = ConfigureMPEGOutput(s, 1); - rc = WR16(s, 0x08201fe, 0x0017); - rc = WR16(s, 0x08201ff, 0x0101); - - s->config.d5C = 0; - s->config.d60 = 1; - s->config.d48 = 1; - -error: - return rc; -} - -static int drx397x_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - return 0; -} - -static int drx397x_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct drx397xD_state *s = fe->demodulator_priv; - - s->config.s20d24 = 1; - - return drx_tune(s, params); -} - -static int drx397x_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings - *fe_tune_settings) -{ - fe_tune_settings->min_delay_ms = 10000; - fe_tune_settings->step_size = 0; - fe_tune_settings->max_drift = 0; - - return 0; -} - -static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct drx397xD_state *s = fe->demodulator_priv; - int lockstat; - - GetLockStatus(s, &lockstat); - - *status = 0; - if (lockstat & 2) { - CorrectSysClockDeviation(s); - ConfigureMPEGOutput(s, 1); - *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; - } - if (lockstat & 4) - *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; - - return 0; -} - -static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber) -{ - *ber = 0; - - return 0; -} - -static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - *snr = 0; - - return 0; -} - -static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct drx397xD_state *s = fe->demodulator_priv; - int rc; - - if (s->config.ifagc.d00 == 2) { - *strength = 0xffff; - return 0; - } - rc = RD16(s, 0x0c20035); - if (rc < 0) { - *strength = 0; - return 0; - } - rc &= 0x3ff; - /* Signal strength is calculated using the following formula: - * - * a = 2200 * 150 / (2200 + 150); - * a = a * 3300 / (a + 820); - * b = 2200 * 3300 / (2200 + 820); - * c = (((b-a) * rc) >> 10 + a) << 4; - * strength = ~c & 0xffff; - * - * The following does the same but with less rounding errors: - */ - *strength = ~(7720 + (rc * 30744 >> 10)); - - return 0; -} - -static int drx397x_read_ucblocks(struct dvb_frontend *fe, - unsigned int *ucblocks) -{ - *ucblocks = 0; - - return 0; -} - -static int drx397x_sleep(struct dvb_frontend *fe) -{ - return 0; -} - -static void drx397x_release(struct dvb_frontend *fe) -{ - struct drx397xD_state *s = fe->demodulator_priv; - printk(KERN_INFO "%s: release demodulator\n", mod_name); - if (s) { - drx_release_fw(s); - kfree(s); - } - -} - -static struct dvb_frontend_ops drx397x_ops = { - - .info = { - .name = "Micronas DRX397xD DVB-T Frontend", - .type = FE_OFDM, - .frequency_min = 47125000, - .frequency_max = 855250000, - .frequency_stepsize = 166667, - .frequency_tolerance = 0, - .caps = /* 0x0C01B2EAE */ - FE_CAN_FEC_1_2 | /* = 0x2, */ - FE_CAN_FEC_2_3 | /* = 0x4, */ - FE_CAN_FEC_3_4 | /* = 0x8, */ - FE_CAN_FEC_5_6 | /* = 0x20, */ - FE_CAN_FEC_7_8 | /* = 0x80, */ - FE_CAN_FEC_AUTO | /* = 0x200, */ - FE_CAN_QPSK | /* = 0x400, */ - FE_CAN_QAM_16 | /* = 0x800, */ - FE_CAN_QAM_64 | /* = 0x2000, */ - FE_CAN_QAM_AUTO | /* = 0x10000, */ - FE_CAN_TRANSMISSION_MODE_AUTO | /* = 0x20000, */ - FE_CAN_GUARD_INTERVAL_AUTO | /* = 0x80000, */ - FE_CAN_HIERARCHY_AUTO | /* = 0x100000, */ - FE_CAN_RECOVER | /* = 0x40000000, */ - FE_CAN_MUTE_TS /* = 0x80000000 */ - }, - - .release = drx397x_release, - .init = drx397x_init, - .sleep = drx397x_sleep, - - .set_frontend = drx397x_set_frontend, - .get_tune_settings = drx397x_get_tune_settings, - .get_frontend = drx397x_get_frontend, - - .read_status = drx397x_read_status, - .read_snr = drx397x_read_snr, - .read_signal_strength = drx397x_read_signal_strength, - .read_ber = drx397x_read_ber, - .read_ucblocks = drx397x_read_ucblocks, -}; - -struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, - struct i2c_adapter *i2c) -{ - struct drx397xD_state *state; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); - if (!state) - goto error; - - /* setup the state */ - state->i2c = i2c; - memcpy(&state->config, config, sizeof(struct drx397xD_config)); - - /* check if the demod is there */ - if (RD16(state, 0x2410019) < 0) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &drx397x_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - return &state->frontend; -error: - kfree(state); - - return NULL; -} -EXPORT_SYMBOL(drx397xD_attach); - -MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend"); -MODULE_AUTHOR("Henk Vergonet"); -MODULE_LICENSE("GPL"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD_fw.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD_fw.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD_fw.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD_fw.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - * Firmware definitions for Micronas drx397xD - * - * Copyright (C) 2007 Henk Vergonet - * - * 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, or - * (at your option) any later version. - * - * 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, see . - */ - -#ifdef _FW_ENTRY - _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0, DRXD_FW_A2 ), - _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1, DRXD_FW_B1 ), -#undef _FW_ENTRY -#endif /* _FW_ENTRY */ - -#ifdef _BLOB_ENTRY - _BLOB_ENTRY("InitAtomicRead", DRXD_InitAtomicRead = 0 ), - _BLOB_ENTRY("InitCE", DRXD_InitCE ), - _BLOB_ENTRY("InitCP", DRXD_InitCP ), - _BLOB_ENTRY("InitEC", DRXD_InitEC ), - _BLOB_ENTRY("InitEQ", DRXD_InitEQ ), - _BLOB_ENTRY("InitFE_1", DRXD_InitFE_1 ), - _BLOB_ENTRY("InitFE_2", DRXD_InitFE_2 ), - _BLOB_ENTRY("InitFT", DRXD_InitFT ), - _BLOB_ENTRY("InitSC", DRXD_InitSC ), - _BLOB_ENTRY("ResetCEFR", DRXD_ResetCEFR ), - _BLOB_ENTRY("ResetECRAM", DRXD_ResetECRAM ), - _BLOB_ENTRY("microcode", DRXD_microcode ), -#undef _BLOB_ENTRY -#endif /* _BLOB_ENTRY */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/drx397xD.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,130 +0,0 @@ -/* - * Driver for Micronas DVB-T drx397xD demodulator - * - * Copyright (C) 2007 Henk vergonet - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef _DRX397XD_H_INCLUDED -#define _DRX397XD_H_INCLUDED - -#include - -#define DRX_F_STEPSIZE 166667 -#define DRX_F_OFFSET 36000000 - -#define I2C_ADR_C0(x) \ -( cpu_to_le32( \ - (u32)( \ - (((u32)(x) & (u32)0x000000ffUL) ) | \ - (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ - (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \ - ( (u32)0x00c00000UL) \ - )) \ -) - -#define I2C_ADR_E0(x) \ -( cpu_to_le32( \ - (u32)( \ - (((u32)(x) & (u32)0x000000ffUL) ) | \ - (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ - (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \ - ( (u32)0x00e00000UL) \ - )) \ -) - -struct drx397xD_CfgRfAgc /* 0x7c */ -{ - int d00; /* 2 */ - u16 w04; - u16 w06; -}; - -struct drx397xD_CfgIfAgc /* 0x68 */ -{ - int d00; /* 0 */ - u16 w04; /* 0 */ - u16 w06; - u16 w08; - u16 w0A; - u16 w0C; -}; - -struct drx397xD_s20 { - int d04; - u32 d18; - u32 d1C; - u32 d20; - u32 d14; - u32 d24; - u32 d0C; - u32 d08; -}; - -struct drx397xD_config -{ - /* demodulator's I2C address */ - u8 demod_address; /* 0x0f */ - - struct drx397xD_CfgIfAgc ifagc; /* 0x68 */ - struct drx397xD_CfgRfAgc rfagc; /* 0x7c */ - u32 s20d24; - - /* HI_CfgCommand parameters */ - u16 w50, w52, /* w54, */ w56; - - int d5C; - int d60; - int d48; - int d28; - - u32 f_if; /* d14: intermediate frequency [Hz] */ - /* 36000000 on Cinergy 2400i DT */ - /* 42800000 on Pinnacle Hybrid PRO 330e */ - - u16 f_osc; /* s66: 48000 oscillator frequency [kHz] */ - - u16 w92; /* 20000 */ - - u16 wA0; - u16 w98; - u16 w9A; - - u16 w9C; /* 0xe0 */ - u16 w9E; /* 0x00 */ - - /* used for signal strength calculations in - drx397x_read_signal_strength - */ - u16 ss78; // 2200 - u16 ss7A; // 150 - u16 ss76; // 820 -}; - -#if defined(CONFIG_DVB_DRX397XD) || (defined(CONFIG_DVB_DRX397XD_MODULE) && defined(MODULE)) -extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_DRX397XD */ - -#endif /* _DRX397XD_H_INCLUDED */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ds3000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ds3000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ds3000.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ds3000.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1327 +0,0 @@ -/* - Montage Technology DS3000/TS2020 - DVBS/S2 Demodulator/Tuner driver - Copyright (C) 2009 Konstantin Dimitrov - - Copyright (C) 2009 TurboSight.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "ds3000.h" - -static int debug; - -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(args); \ - } while (0) - -/* as of March 2009 current DS3000 firmware version is 1.78 */ -/* DS3000 FW v1.78 MD5: a32d17910c4f370073f9346e71d34b80 */ -#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw" - -#define DS3000_SAMPLE_RATE 96000 /* in kHz */ -#define DS3000_XTAL_FREQ 27000 /* in kHz */ - -/* Register values to initialise the demod in DVB-S mode */ -static u8 ds3000_dvbs_init_tab[] = { - 0x23, 0x05, - 0x08, 0x03, - 0x0c, 0x00, - 0x21, 0x54, - 0x25, 0x82, - 0x27, 0x31, - 0x30, 0x08, - 0x31, 0x40, - 0x32, 0x32, - 0x33, 0x35, - 0x35, 0xff, - 0x3a, 0x00, - 0x37, 0x10, - 0x38, 0x10, - 0x39, 0x02, - 0x42, 0x60, - 0x4a, 0x40, - 0x4b, 0x04, - 0x4d, 0x91, - 0x5d, 0xc8, - 0x50, 0x77, - 0x51, 0x77, - 0x52, 0x36, - 0x53, 0x36, - 0x56, 0x01, - 0x63, 0x43, - 0x64, 0x30, - 0x65, 0x40, - 0x68, 0x26, - 0x69, 0x4c, - 0x70, 0x20, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0x40, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0x60, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0x80, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0xa0, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0x1f, - 0x76, 0x00, - 0x77, 0xd1, - 0x78, 0x0c, - 0x79, 0x80, - 0x7f, 0x04, - 0x7c, 0x00, - 0x80, 0x86, - 0x81, 0xa6, - 0x85, 0x04, - 0xcd, 0xf4, - 0x90, 0x33, - 0xa0, 0x44, - 0xc0, 0x18, - 0xc3, 0x10, - 0xc4, 0x08, - 0xc5, 0x80, - 0xc6, 0x80, - 0xc7, 0x0a, - 0xc8, 0x1a, - 0xc9, 0x80, - 0xfe, 0x92, - 0xe0, 0xf8, - 0xe6, 0x8b, - 0xd0, 0x40, - 0xf8, 0x20, - 0xfa, 0x0f, - 0xfd, 0x20, - 0xad, 0x20, - 0xae, 0x07, - 0xb8, 0x00, -}; - -/* Register values to initialise the demod in DVB-S2 mode */ -static u8 ds3000_dvbs2_init_tab[] = { - 0x23, 0x0f, - 0x08, 0x07, - 0x0c, 0x00, - 0x21, 0x54, - 0x25, 0x82, - 0x27, 0x31, - 0x30, 0x08, - 0x31, 0x32, - 0x32, 0x32, - 0x33, 0x35, - 0x35, 0xff, - 0x3a, 0x00, - 0x37, 0x10, - 0x38, 0x10, - 0x39, 0x02, - 0x42, 0x60, - 0x4a, 0x80, - 0x4b, 0x04, - 0x4d, 0x81, - 0x5d, 0x88, - 0x50, 0x36, - 0x51, 0x36, - 0x52, 0x36, - 0x53, 0x36, - 0x63, 0x60, - 0x64, 0x10, - 0x65, 0x10, - 0x68, 0x04, - 0x69, 0x29, - 0x70, 0x20, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0x40, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0x60, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0x80, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0xa0, - 0x71, 0x70, - 0x72, 0x04, - 0x73, 0x00, - 0x70, 0x1f, - 0xa0, 0x44, - 0xc0, 0x08, - 0xc1, 0x10, - 0xc2, 0x08, - 0xc3, 0x10, - 0xc4, 0x08, - 0xc5, 0xf0, - 0xc6, 0xf0, - 0xc7, 0x0a, - 0xc8, 0x1a, - 0xc9, 0x80, - 0xca, 0x23, - 0xcb, 0x24, - 0xce, 0x74, - 0x90, 0x03, - 0x76, 0x80, - 0x77, 0x42, - 0x78, 0x0a, - 0x79, 0x80, - 0xad, 0x40, - 0xae, 0x07, - 0x7f, 0xd4, - 0x7c, 0x00, - 0x80, 0xa8, - 0x81, 0xda, - 0x7c, 0x01, - 0x80, 0xda, - 0x81, 0xec, - 0x7c, 0x02, - 0x80, 0xca, - 0x81, 0xeb, - 0x7c, 0x03, - 0x80, 0xba, - 0x81, 0xdb, - 0x85, 0x08, - 0x86, 0x00, - 0x87, 0x02, - 0x89, 0x80, - 0x8b, 0x44, - 0x8c, 0xaa, - 0x8a, 0x10, - 0xba, 0x00, - 0xf5, 0x04, - 0xfe, 0x44, - 0xd2, 0x32, - 0xb8, 0x00, -}; - -struct ds3000_state { - struct i2c_adapter *i2c; - const struct ds3000_config *config; - struct dvb_frontend frontend; - u8 skip_fw_load; - /* previous uncorrected block counter for DVB-S2 */ - u16 prevUCBS2; -}; - -static int ds3000_writereg(struct ds3000_state *state, int reg, int data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = 0, .buf = buf, .len = 2 }; - int err; - - dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data); - - err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) { - printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," - " value == 0x%02x)\n", __func__, err, reg, data); - return -EREMOTEIO; - } - - return 0; -} - -static int ds3000_tuner_writereg(struct ds3000_state *state, int reg, int data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr = 0x60, - .flags = 0, .buf = buf, .len = 2 }; - int err; - - dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data); - - ds3000_writereg(state, 0x03, 0x11); - err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) { - printk("%s: writereg error(err == %i, reg == 0x%02x," - " value == 0x%02x)\n", __func__, err, reg, data); - return -EREMOTEIO; - } - - return 0; -} - -/* I2C write for 8k firmware load */ -static int ds3000_writeFW(struct ds3000_state *state, int reg, - const u8 *data, u16 len) -{ - int i, ret = -EREMOTEIO; - struct i2c_msg msg; - u8 *buf; - - buf = kmalloc(33, GFP_KERNEL); - if (buf == NULL) { - printk(KERN_ERR "Unable to kmalloc\n"); - ret = -ENOMEM; - goto error; - } - - *(buf) = reg; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.buf = buf; - msg.len = 33; - - for (i = 0; i < len; i += 32) { - memcpy(buf + 1, data + i, 32); - - dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len); - - ret = i2c_transfer(state->i2c, &msg, 1); - if (ret != 1) { - printk(KERN_ERR "%s: write error(err == %i, " - "reg == 0x%02x\n", __func__, ret, reg); - ret = -EREMOTEIO; - } - } - -error: - kfree(buf); - - return ret; -} - -static int ds3000_readreg(struct ds3000_state *state, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { - .addr = state->config->demod_address, - .flags = 0, - .buf = b0, - .len = 1 - }, { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = b1, - .len = 1 - } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret); - return ret; - } - - dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]); - - return b1[0]; -} - -static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { - .addr = 0x60, - .flags = 0, - .buf = b0, - .len = 1 - }, { - .addr = 0x60, - .flags = I2C_M_RD, - .buf = b1, - .len = 1 - } - }; - - ds3000_writereg(state, 0x03, 0x12); - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret); - return ret; - } - - dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]); - - return b1[0]; -} - -static int ds3000_load_firmware(struct dvb_frontend *fe, - const struct firmware *fw); - -static int ds3000_firmware_ondemand(struct dvb_frontend *fe) -{ - struct ds3000_state *state = fe->demodulator_priv; - const struct firmware *fw; - int ret = 0; - - dprintk("%s()\n", __func__); - - if (ds3000_readreg(state, 0xb2) <= 0) - return ret; - - if (state->skip_fw_load) - return 0; - /* Load firmware */ - /* request the firmware, this will block until someone uploads it */ - printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, - DS3000_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE, - state->i2c->dev.parent); - printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__); - if (ret) { - printk(KERN_ERR "%s: No firmware uploaded (timeout or file not " - "found?)\n", __func__); - return ret; - } - - /* Make sure we don't recurse back through here during loading */ - state->skip_fw_load = 1; - - ret = ds3000_load_firmware(fe, fw); - if (ret) - printk("%s: Writing firmware to device failed\n", __func__); - - release_firmware(fw); - - dprintk("%s: Firmware upload %s\n", __func__, - ret == 0 ? "complete" : "failed"); - - /* Ensure firmware is always loaded if required */ - state->skip_fw_load = 0; - - return ret; -} - -static int ds3000_load_firmware(struct dvb_frontend *fe, - const struct firmware *fw) -{ - struct ds3000_state *state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n", - fw->size, - fw->data[0], - fw->data[1], - fw->data[fw->size - 2], - fw->data[fw->size - 1]); - - /* Begin the firmware load process */ - ds3000_writereg(state, 0xb2, 0x01); - /* write the entire firmware */ - ds3000_writeFW(state, 0xb0, fw->data, fw->size); - ds3000_writereg(state, 0xb2, 0x00); - - return 0; -} - -static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct ds3000_state *state = fe->demodulator_priv; - u8 data; - - dprintk("%s(%d)\n", __func__, voltage); - - data = ds3000_readreg(state, 0xa2); - data |= 0x03; /* bit0 V/H, bit1 off/on */ - - switch (voltage) { - case SEC_VOLTAGE_18: - data &= ~0x03; - break; - case SEC_VOLTAGE_13: - data &= ~0x03; - data |= 0x01; - break; - case SEC_VOLTAGE_OFF: - break; - } - - ds3000_writereg(state, 0xa2, data); - - return 0; -} - -static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status) -{ - struct ds3000_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int lock; - - *status = 0; - - switch (c->delivery_system) { - case SYS_DVBS: - lock = ds3000_readreg(state, 0xd1); - if ((lock & 0x07) == 0x07) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - - break; - case SYS_DVBS2: - lock = ds3000_readreg(state, 0x0d); - if ((lock & 0x8f) == 0x8f) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - - break; - default: - return 1; - } - - dprintk("%s: status = 0x%02x\n", __func__, lock); - - return 0; -} - -/* read DS3000 BER value */ -static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber) -{ - struct ds3000_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u8 data; - u32 ber_reading, lpdc_frames; - - dprintk("%s()\n", __func__); - - switch (c->delivery_system) { - case SYS_DVBS: - /* set the number of bytes checked during - BER estimation */ - ds3000_writereg(state, 0xf9, 0x04); - /* read BER estimation status */ - data = ds3000_readreg(state, 0xf8); - /* check if BER estimation is ready */ - if ((data & 0x10) == 0) { - /* this is the number of error bits, - to calculate the bit error rate - divide to 8388608 */ - *ber = (ds3000_readreg(state, 0xf7) << 8) | - ds3000_readreg(state, 0xf6); - /* start counting error bits */ - /* need to be set twice - otherwise it fails sometimes */ - data |= 0x10; - ds3000_writereg(state, 0xf8, data); - ds3000_writereg(state, 0xf8, data); - } else - /* used to indicate that BER estimation - is not ready, i.e. BER is unknown */ - *ber = 0xffffffff; - break; - case SYS_DVBS2: - /* read the number of LPDC decoded frames */ - lpdc_frames = (ds3000_readreg(state, 0xd7) << 16) | - (ds3000_readreg(state, 0xd6) << 8) | - ds3000_readreg(state, 0xd5); - /* read the number of packets with bad CRC */ - ber_reading = (ds3000_readreg(state, 0xf8) << 8) | - ds3000_readreg(state, 0xf7); - if (lpdc_frames > 750) { - /* clear LPDC frame counters */ - ds3000_writereg(state, 0xd1, 0x01); - /* clear bad packets counter */ - ds3000_writereg(state, 0xf9, 0x01); - /* enable bad packets counter */ - ds3000_writereg(state, 0xf9, 0x00); - /* enable LPDC frame counters */ - ds3000_writereg(state, 0xd1, 0x00); - *ber = ber_reading; - } else - /* used to indicate that BER estimation is not ready, - i.e. BER is unknown */ - *ber = 0xffffffff; - break; - default: - return 1; - } - - return 0; -} - -/* read TS2020 signal strength */ -static int ds3000_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - struct ds3000_state *state = fe->demodulator_priv; - u16 sig_reading, sig_strength; - u8 rfgain, bbgain; - - dprintk("%s()\n", __func__); - - rfgain = ds3000_tuner_readreg(state, 0x3d) & 0x1f; - bbgain = ds3000_tuner_readreg(state, 0x21) & 0x1f; - - if (rfgain > 15) - rfgain = 15; - if (bbgain > 13) - bbgain = 13; - - sig_reading = rfgain * 2 + bbgain * 3; - - sig_strength = 40 + (64 - sig_reading) * 50 / 64 ; - - /* cook the value to be suitable for szap-s2 human readable output */ - *signal_strength = sig_strength * 1000; - - dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, - sig_reading, *signal_strength); - - return 0; -} - -/* calculate DS3000 snr value in dB */ -static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct ds3000_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u8 snr_reading, snr_value; - u32 dvbs2_signal_reading, dvbs2_noise_reading, tmp; - static const u16 dvbs_snr_tab[] = { /* 20 x Table (rounded up) */ - 0x0000, 0x1b13, 0x2aea, 0x3627, 0x3ede, 0x45fe, 0x4c03, - 0x513a, 0x55d4, 0x59f2, 0x5dab, 0x6111, 0x6431, 0x6717, - 0x69c9, 0x6c4e, 0x6eac, 0x70e8, 0x7304, 0x7505 - }; - static const u16 dvbs2_snr_tab[] = { /* 80 x Table (rounded up) */ - 0x0000, 0x0bc2, 0x12a3, 0x1785, 0x1b4e, 0x1e65, 0x2103, - 0x2347, 0x2546, 0x2710, 0x28ae, 0x2a28, 0x2b83, 0x2cc5, - 0x2df1, 0x2f09, 0x3010, 0x3109, 0x31f4, 0x32d2, 0x33a6, - 0x3470, 0x3531, 0x35ea, 0x369b, 0x3746, 0x37ea, 0x3888, - 0x3920, 0x39b3, 0x3a42, 0x3acc, 0x3b51, 0x3bd3, 0x3c51, - 0x3ccb, 0x3d42, 0x3db6, 0x3e27, 0x3e95, 0x3f00, 0x3f68, - 0x3fcf, 0x4033, 0x4094, 0x40f4, 0x4151, 0x41ac, 0x4206, - 0x425e, 0x42b4, 0x4308, 0x435b, 0x43ac, 0x43fc, 0x444a, - 0x4497, 0x44e2, 0x452d, 0x4576, 0x45bd, 0x4604, 0x4649, - 0x468e, 0x46d1, 0x4713, 0x4755, 0x4795, 0x47d4, 0x4813, - 0x4851, 0x488d, 0x48c9, 0x4904, 0x493f, 0x4978, 0x49b1, - 0x49e9, 0x4a20, 0x4a57 - }; - - dprintk("%s()\n", __func__); - - switch (c->delivery_system) { - case SYS_DVBS: - snr_reading = ds3000_readreg(state, 0xff); - snr_reading /= 8; - if (snr_reading == 0) - *snr = 0x0000; - else { - if (snr_reading > 20) - snr_reading = 20; - snr_value = dvbs_snr_tab[snr_reading - 1] * 10 / 23026; - /* cook the value to be suitable for szap-s2 - human readable output */ - *snr = snr_value * 8 * 655; - } - dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, - snr_reading, *snr); - break; - case SYS_DVBS2: - dvbs2_noise_reading = (ds3000_readreg(state, 0x8c) & 0x3f) + - (ds3000_readreg(state, 0x8d) << 4); - dvbs2_signal_reading = ds3000_readreg(state, 0x8e); - tmp = dvbs2_signal_reading * dvbs2_signal_reading >> 1; - if (tmp == 0) { - *snr = 0x0000; - return 0; - } - if (dvbs2_noise_reading == 0) { - snr_value = 0x0013; - /* cook the value to be suitable for szap-s2 - human readable output */ - *snr = 0xffff; - return 0; - } - if (tmp > dvbs2_noise_reading) { - snr_reading = tmp / dvbs2_noise_reading; - if (snr_reading > 80) - snr_reading = 80; - snr_value = dvbs2_snr_tab[snr_reading - 1] / 1000; - /* cook the value to be suitable for szap-s2 - human readable output */ - *snr = snr_value * 5 * 655; - } else { - snr_reading = dvbs2_noise_reading / tmp; - if (snr_reading > 80) - snr_reading = 80; - *snr = -(dvbs2_snr_tab[snr_reading] / 1000); - } - dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, - snr_reading, *snr); - break; - default: - return 1; - } - - return 0; -} - -/* read DS3000 uncorrected blocks */ -static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct ds3000_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u8 data; - u16 _ucblocks; - - dprintk("%s()\n", __func__); - - switch (c->delivery_system) { - case SYS_DVBS: - *ucblocks = (ds3000_readreg(state, 0xf5) << 8) | - ds3000_readreg(state, 0xf4); - data = ds3000_readreg(state, 0xf8); - /* clear packet counters */ - data &= ~0x20; - ds3000_writereg(state, 0xf8, data); - /* enable packet counters */ - data |= 0x20; - ds3000_writereg(state, 0xf8, data); - break; - case SYS_DVBS2: - _ucblocks = (ds3000_readreg(state, 0xe2) << 8) | - ds3000_readreg(state, 0xe1); - if (_ucblocks > state->prevUCBS2) - *ucblocks = _ucblocks - state->prevUCBS2; - else - *ucblocks = state->prevUCBS2 - _ucblocks; - state->prevUCBS2 = _ucblocks; - break; - default: - return 1; - } - - return 0; -} - -static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct ds3000_state *state = fe->demodulator_priv; - u8 data; - - dprintk("%s(%d)\n", __func__, tone); - if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { - printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone); - return -EINVAL; - } - - data = ds3000_readreg(state, 0xa2); - data &= ~0xc0; - ds3000_writereg(state, 0xa2, data); - - switch (tone) { - case SEC_TONE_ON: - dprintk("%s: setting tone on\n", __func__); - data = ds3000_readreg(state, 0xa1); - data &= ~0x43; - data |= 0x04; - ds3000_writereg(state, 0xa1, data); - break; - case SEC_TONE_OFF: - dprintk("%s: setting tone off\n", __func__); - data = ds3000_readreg(state, 0xa2); - data |= 0x80; - ds3000_writereg(state, 0xa2, data); - break; - } - - return 0; -} - -static int ds3000_send_diseqc_msg(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *d) -{ - struct ds3000_state *state = fe->demodulator_priv; - int i; - u8 data; - - /* Dump DiSEqC message */ - dprintk("%s(", __func__); - for (i = 0 ; i < d->msg_len;) { - dprintk("0x%02x", d->msg[i]); - if (++i < d->msg_len) - dprintk(", "); - } - - /* enable DiSEqC message send pin */ - data = ds3000_readreg(state, 0xa2); - data &= ~0xc0; - ds3000_writereg(state, 0xa2, data); - - /* DiSEqC message */ - for (i = 0; i < d->msg_len; i++) - ds3000_writereg(state, 0xa3 + i, d->msg[i]); - - data = ds3000_readreg(state, 0xa1); - /* clear DiSEqC message length and status, - enable DiSEqC message send */ - data &= ~0xf8; - /* set DiSEqC mode, modulation active during 33 pulses, - set DiSEqC message length */ - data |= ((d->msg_len - 1) << 3) | 0x07; - ds3000_writereg(state, 0xa1, data); - - /* wait up to 150ms for DiSEqC transmission to complete */ - for (i = 0; i < 15; i++) { - data = ds3000_readreg(state, 0xa1); - if ((data & 0x40) == 0) - break; - msleep(10); - } - - /* DiSEqC timeout after 150ms */ - if (i == 15) { - data = ds3000_readreg(state, 0xa1); - data &= ~0x80; - data |= 0x40; - ds3000_writereg(state, 0xa1, data); - - data = ds3000_readreg(state, 0xa2); - data &= ~0xc0; - data |= 0x80; - ds3000_writereg(state, 0xa2, data); - - return 1; - } - - data = ds3000_readreg(state, 0xa2); - data &= ~0xc0; - data |= 0x80; - ds3000_writereg(state, 0xa2, data); - - return 0; -} - -/* Send DiSEqC burst */ -static int ds3000_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) -{ - struct ds3000_state *state = fe->demodulator_priv; - int i; - u8 data; - - dprintk("%s()\n", __func__); - - data = ds3000_readreg(state, 0xa2); - data &= ~0xc0; - ds3000_writereg(state, 0xa2, data); - - /* DiSEqC burst */ - if (burst == SEC_MINI_A) - /* Unmodulated tone burst */ - ds3000_writereg(state, 0xa1, 0x02); - else if (burst == SEC_MINI_B) - /* Modulated tone burst */ - ds3000_writereg(state, 0xa1, 0x01); - else - return -EINVAL; - - msleep(13); - for (i = 0; i < 5; i++) { - data = ds3000_readreg(state, 0xa1); - if ((data & 0x40) == 0) - break; - msleep(1); - } - - if (i == 5) { - data = ds3000_readreg(state, 0xa1); - data &= ~0x80; - data |= 0x40; - ds3000_writereg(state, 0xa1, data); - - data = ds3000_readreg(state, 0xa2); - data &= ~0xc0; - data |= 0x80; - ds3000_writereg(state, 0xa2, data); - - return 1; - } - - data = ds3000_readreg(state, 0xa2); - data &= ~0xc0; - data |= 0x80; - ds3000_writereg(state, 0xa2, data); - - return 0; -} - -static void ds3000_release(struct dvb_frontend *fe) -{ - struct ds3000_state *state = fe->demodulator_priv; - dprintk("%s\n", __func__); - kfree(state); -} - -static struct dvb_frontend_ops ds3000_ops; - -struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, - struct i2c_adapter *i2c) -{ - struct ds3000_state *state = NULL; - int ret; - - dprintk("%s\n", __func__); - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL); - if (state == NULL) { - printk(KERN_ERR "Unable to kmalloc\n"); - goto error2; - } - - state->config = config; - state->i2c = i2c; - state->prevUCBS2 = 0; - - /* check if the demod is present */ - ret = ds3000_readreg(state, 0x00) & 0xfe; - if (ret != 0xe0) { - printk(KERN_ERR "Invalid probe, probably not a DS3000\n"); - goto error3; - } - - printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n", - ds3000_readreg(state, 0x02), - ds3000_readreg(state, 0x01)); - - memcpy(&state->frontend.ops, &ds3000_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error3: - kfree(state); -error2: - return NULL; -} -EXPORT_SYMBOL(ds3000_attach); - -static int ds3000_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int ds3000_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int ds3000_set_carrier_offset(struct dvb_frontend *fe, - s32 carrier_offset_khz) -{ - struct ds3000_state *state = fe->demodulator_priv; - s32 tmp; - - tmp = carrier_offset_khz; - tmp *= 65536; - tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE); - - if (tmp < 0) - tmp += 65536; - - ds3000_writereg(state, 0x5f, tmp >> 8); - ds3000_writereg(state, 0x5e, tmp & 0xff); - - return 0; -} - -static int ds3000_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct ds3000_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - int i; - fe_status_t status; - u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4; - s32 offset_khz; - u16 value, ndiv; - u32 f3db; - - dprintk("%s() ", __func__); - - if (state->config->set_ts_params) - state->config->set_ts_params(fe, 0); - /* Tune */ - /* unknown */ - ds3000_tuner_writereg(state, 0x07, 0x02); - ds3000_tuner_writereg(state, 0x10, 0x00); - ds3000_tuner_writereg(state, 0x60, 0x79); - ds3000_tuner_writereg(state, 0x08, 0x01); - ds3000_tuner_writereg(state, 0x00, 0x01); - div4 = 0; - - /* calculate and set freq divider */ - if (p->frequency < 1146000) { - ds3000_tuner_writereg(state, 0x10, 0x11); - div4 = 1; - ndiv = ((p->frequency * (6 + 8) * 4) + - (DS3000_XTAL_FREQ / 2)) / - DS3000_XTAL_FREQ - 1024; - } else { - ds3000_tuner_writereg(state, 0x10, 0x01); - ndiv = ((p->frequency * (6 + 8) * 2) + - (DS3000_XTAL_FREQ / 2)) / - DS3000_XTAL_FREQ - 1024; - } - - ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8); - ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff); - - /* set pll */ - ds3000_tuner_writereg(state, 0x03, 0x06); - ds3000_tuner_writereg(state, 0x51, 0x0f); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x10); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(5); - - /* unknown */ - ds3000_tuner_writereg(state, 0x51, 0x17); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x08); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(5); - - value = ds3000_tuner_readreg(state, 0x3d); - value &= 0x0f; - if ((value > 4) && (value < 15)) { - value -= 3; - if (value < 4) - value = 4; - value = ((value << 3) | 0x01) & 0x79; - } - - ds3000_tuner_writereg(state, 0x60, value); - ds3000_tuner_writereg(state, 0x51, 0x17); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x08); - ds3000_tuner_writereg(state, 0x50, 0x00); - - /* set low-pass filter period */ - ds3000_tuner_writereg(state, 0x04, 0x2e); - ds3000_tuner_writereg(state, 0x51, 0x1b); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x04); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(5); - - f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000; - if ((c->symbol_rate / 1000) < 5000) - f3db += 3000; - if (f3db < 7000) - f3db = 7000; - if (f3db > 40000) - f3db = 40000; - - /* set low-pass filter baseband */ - value = ds3000_tuner_readreg(state, 0x26); - mlpf = 0x2e * 207 / ((value << 1) + 151); - mlpf_max = mlpf * 135 / 100; - mlpf_min = mlpf * 78 / 100; - if (mlpf_max > 63) - mlpf_max = 63; - - /* rounded to the closest integer */ - nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2)) - / (2766 * DS3000_XTAL_FREQ); - if (nlpf > 23) - nlpf = 23; - if (nlpf < 1) - nlpf = 1; - - /* rounded to the closest integer */ - mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) + - (1000 * f3db / 2)) / (1000 * f3db); - - if (mlpf_new < mlpf_min) { - nlpf++; - mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) + - (1000 * f3db / 2)) / (1000 * f3db); - } - - if (mlpf_new > mlpf_max) - mlpf_new = mlpf_max; - - ds3000_tuner_writereg(state, 0x04, mlpf_new); - ds3000_tuner_writereg(state, 0x06, nlpf); - ds3000_tuner_writereg(state, 0x51, 0x1b); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x04); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(5); - - /* unknown */ - ds3000_tuner_writereg(state, 0x51, 0x1e); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x01); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(60); - - offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ - / (6 + 8) / (div4 + 1) / 2 - p->frequency; - - /* ds3000 global reset */ - ds3000_writereg(state, 0x07, 0x80); - ds3000_writereg(state, 0x07, 0x00); - /* ds3000 build-in uC reset */ - ds3000_writereg(state, 0xb2, 0x01); - /* ds3000 software reset */ - ds3000_writereg(state, 0x00, 0x01); - - switch (c->delivery_system) { - case SYS_DVBS: - /* initialise the demod in DVB-S mode */ - for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2) - ds3000_writereg(state, - ds3000_dvbs_init_tab[i], - ds3000_dvbs_init_tab[i + 1]); - value = ds3000_readreg(state, 0xfe); - value &= 0xc0; - value |= 0x1b; - ds3000_writereg(state, 0xfe, value); - break; - case SYS_DVBS2: - /* initialise the demod in DVB-S2 mode */ - for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2) - ds3000_writereg(state, - ds3000_dvbs2_init_tab[i], - ds3000_dvbs2_init_tab[i + 1]); - ds3000_writereg(state, 0xfe, 0x98); - break; - default: - return 1; - } - - /* enable 27MHz clock output */ - ds3000_writereg(state, 0x29, 0x80); - /* enable ac coupling */ - ds3000_writereg(state, 0x25, 0x8a); - - /* enhance symbol rate performance */ - if ((c->symbol_rate / 1000) <= 5000) { - value = 29777 / (c->symbol_rate / 1000) + 1; - if (value % 2 != 0) - value++; - ds3000_writereg(state, 0xc3, 0x0d); - ds3000_writereg(state, 0xc8, value); - ds3000_writereg(state, 0xc4, 0x10); - ds3000_writereg(state, 0xc7, 0x0e); - } else if ((c->symbol_rate / 1000) <= 10000) { - value = 92166 / (c->symbol_rate / 1000) + 1; - if (value % 2 != 0) - value++; - ds3000_writereg(state, 0xc3, 0x07); - ds3000_writereg(state, 0xc8, value); - ds3000_writereg(state, 0xc4, 0x09); - ds3000_writereg(state, 0xc7, 0x12); - } else if ((c->symbol_rate / 1000) <= 20000) { - value = 64516 / (c->symbol_rate / 1000) + 1; - ds3000_writereg(state, 0xc3, value); - ds3000_writereg(state, 0xc8, 0x0e); - ds3000_writereg(state, 0xc4, 0x07); - ds3000_writereg(state, 0xc7, 0x18); - } else { - value = 129032 / (c->symbol_rate / 1000) + 1; - ds3000_writereg(state, 0xc3, value); - ds3000_writereg(state, 0xc8, 0x0a); - ds3000_writereg(state, 0xc4, 0x05); - ds3000_writereg(state, 0xc7, 0x24); - } - - /* normalized symbol rate rounded to the closest integer */ - value = (((c->symbol_rate / 1000) << 16) + - (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE; - ds3000_writereg(state, 0x61, value & 0x00ff); - ds3000_writereg(state, 0x62, (value & 0xff00) >> 8); - - /* co-channel interference cancellation disabled */ - ds3000_writereg(state, 0x56, 0x00); - - /* equalizer disabled */ - ds3000_writereg(state, 0x76, 0x00); - - /*ds3000_writereg(state, 0x08, 0x03); - ds3000_writereg(state, 0xfd, 0x22); - ds3000_writereg(state, 0x08, 0x07); - ds3000_writereg(state, 0xfd, 0x42); - ds3000_writereg(state, 0x08, 0x07);*/ - - if (state->config->ci_mode) { - switch (c->delivery_system) { - case SYS_DVBS: - default: - ds3000_writereg(state, 0xfd, 0x80); - break; - case SYS_DVBS2: - ds3000_writereg(state, 0xfd, 0x01); - break; - } - } - - /* ds3000 out of software reset */ - ds3000_writereg(state, 0x00, 0x00); - /* start ds3000 build-in uC */ - ds3000_writereg(state, 0xb2, 0x00); - - ds3000_set_carrier_offset(fe, offset_khz); - - for (i = 0; i < 30 ; i++) { - ds3000_read_status(fe, &status); - if (status && FE_HAS_LOCK) - break; - - msleep(10); - } - - return 0; -} - -static int ds3000_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p, - unsigned int mode_flags, - unsigned int *delay, - fe_status_t *status) -{ - if (p) { - int ret = ds3000_set_frontend(fe, p); - if (ret) - return ret; - } - - *delay = HZ / 5; - - return ds3000_read_status(fe, status); -} - -static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe) -{ - dprintk("%s()\n", __func__); - return DVBFE_ALGO_HW; -} - -/* - * Initialise or wake up device - * - * Power config will reset and load initial firmware if required - */ -static int ds3000_initfe(struct dvb_frontend *fe) -{ - struct ds3000_state *state = fe->demodulator_priv; - int ret; - - dprintk("%s()\n", __func__); - /* hard reset */ - ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08)); - msleep(1); - - /* TS2020 init */ - ds3000_tuner_writereg(state, 0x42, 0x73); - ds3000_tuner_writereg(state, 0x05, 0x01); - ds3000_tuner_writereg(state, 0x62, 0xf5); - /* Load the firmware if required */ - ret = ds3000_firmware_ondemand(fe); - if (ret != 0) { - printk(KERN_ERR "%s: Unable initialize firmware\n", __func__); - return ret; - } - - return 0; -} - -/* Put device to sleep */ -static int ds3000_sleep(struct dvb_frontend *fe) -{ - dprintk("%s()\n", __func__); - return 0; -} - -static struct dvb_frontend_ops ds3000_ops = { - - .info = { - .name = "Montage Technology DS3000/TS2020", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1011, /* kHz for QPSK frontends */ - .frequency_tolerance = 5000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_2G_MODULATION | - FE_CAN_QPSK | FE_CAN_RECOVER - }, - - .release = ds3000_release, - - .init = ds3000_initfe, - .sleep = ds3000_sleep, - .read_status = ds3000_read_status, - .read_ber = ds3000_read_ber, - .read_signal_strength = ds3000_read_signal_strength, - .read_snr = ds3000_read_snr, - .read_ucblocks = ds3000_read_ucblocks, - .set_voltage = ds3000_set_voltage, - .set_tone = ds3000_set_tone, - .diseqc_send_master_cmd = ds3000_send_diseqc_msg, - .diseqc_send_burst = ds3000_diseqc_send_burst, - .get_frontend_algo = ds3000_get_algo, - - .set_property = ds3000_set_property, - .get_property = ds3000_get_property, - .set_frontend = ds3000_set_frontend, - .tune = ds3000_tune, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); - -MODULE_DESCRIPTION("DVB Frontend module for Montage Technology " - "DS3000/TS2020 hardware"); -MODULE_AUTHOR("Konstantin Dimitrov"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ds3000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ds3000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ds3000.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ds3000.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - Montage Technology DS3000/TS2020 - DVBS/S2 Satellite demod/tuner driver - Copyright (C) 2009 Konstantin Dimitrov - - Copyright (C) 2009 TurboSight.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef DS3000_H -#define DS3000_H - -#include - -struct ds3000_config { - /* the demodulator's i2c address */ - u8 demod_address; - u8 ci_mode; - /* Set device param to start dma */ - int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); -}; - -#if defined(CONFIG_DVB_DS3000) || \ - (defined(CONFIG_DVB_DS3000_MODULE) && defined(MODULE)) -extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, - struct i2c_adapter *i2c); -#else -static inline -struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_DS3000 */ -#endif /* DS3000_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,276 +0,0 @@ -/* - * Driver for Dummy Frontend - * - * Written by Emard - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvb_dummy_fe.h" - - -struct dvb_dummy_fe_state { - struct dvb_frontend frontend; -}; - - -static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - *status = FE_HAS_SIGNAL - | FE_HAS_CARRIER - | FE_HAS_VITERBI - | FE_HAS_SYNC - | FE_HAS_LOCK; - - return 0; -} - -static int dvb_dummy_fe_read_ber(struct dvb_frontend* fe, u32* ber) -{ - *ber = 0; - return 0; -} - -static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - *strength = 0; - return 0; -} - -static int dvb_dummy_fe_read_snr(struct dvb_frontend* fe, u16* snr) -{ - *snr = 0; - return 0; -} - -static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - *ucblocks = 0; - return 0; -} - -static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - return 0; -} - -static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - return 0; -} - -static int dvb_dummy_fe_sleep(struct dvb_frontend* fe) -{ - return 0; -} - -static int dvb_dummy_fe_init(struct dvb_frontend* fe) -{ - return 0; -} - -static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - return 0; -} - -static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - return 0; -} - -static void dvb_dummy_fe_release(struct dvb_frontend* fe) -{ - struct dvb_dummy_fe_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops; - -struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) -{ - struct dvb_dummy_fe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; - -struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) -{ - struct dvb_dummy_fe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; - -struct dvb_frontend *dvb_dummy_fe_qam_attach(void) -{ - struct dvb_dummy_fe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { - - .info = { - .name = "Dummy DVB-T", - .type = FE_OFDM, - .frequency_min = 0, - .frequency_max = 863250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = dvb_dummy_fe_release, - - .init = dvb_dummy_fe_init, - .sleep = dvb_dummy_fe_sleep, - - .set_frontend = dvb_dummy_fe_set_frontend, - .get_frontend = dvb_dummy_fe_get_frontend, - - .read_status = dvb_dummy_fe_read_status, - .read_ber = dvb_dummy_fe_read_ber, - .read_signal_strength = dvb_dummy_fe_read_signal_strength, - .read_snr = dvb_dummy_fe_read_snr, - .read_ucblocks = dvb_dummy_fe_read_ucblocks, -}; - -static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { - - .info = { - .name = "Dummy DVB-C", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, - .symbol_rate_min = (57840000/2)/64, /* SACLK/64 == (XIN/2)/64 */ - .symbol_rate_max = (57840000/2)/4, /* SACLK/4 */ - .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO - }, - - .release = dvb_dummy_fe_release, - - .init = dvb_dummy_fe_init, - .sleep = dvb_dummy_fe_sleep, - - .set_frontend = dvb_dummy_fe_set_frontend, - .get_frontend = dvb_dummy_fe_get_frontend, - - .read_status = dvb_dummy_fe_read_status, - .read_ber = dvb_dummy_fe_read_ber, - .read_signal_strength = dvb_dummy_fe_read_signal_strength, - .read_snr = dvb_dummy_fe_read_snr, - .read_ucblocks = dvb_dummy_fe_read_ucblocks, -}; - -static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { - - .info = { - .name = "Dummy DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 250, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK - }, - - .release = dvb_dummy_fe_release, - - .init = dvb_dummy_fe_init, - .sleep = dvb_dummy_fe_sleep, - - .set_frontend = dvb_dummy_fe_set_frontend, - .get_frontend = dvb_dummy_fe_get_frontend, - - .read_status = dvb_dummy_fe_read_status, - .read_ber = dvb_dummy_fe_read_ber, - .read_signal_strength = dvb_dummy_fe_read_signal_strength, - .read_snr = dvb_dummy_fe_read_snr, - .read_ucblocks = dvb_dummy_fe_read_ucblocks, - - .set_voltage = dvb_dummy_fe_set_voltage, - .set_tone = dvb_dummy_fe_set_tone, -}; - -MODULE_DESCRIPTION("DVB DUMMY Frontend"); -MODULE_AUTHOR("Emard"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach); -EXPORT_SYMBOL(dvb_dummy_fe_qam_attach); -EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - * Driver for Dummy Frontend - * - * Written by Emard - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef DVB_DUMMY_FE_H -#define DVB_DUMMY_FE_H - -#include -#include "dvb_frontend.h" - -#if defined(CONFIG_DVB_DUMMY_FE) || (defined(CONFIG_DVB_DUMMY_FE_MODULE) && \ -defined(MODULE)) -extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void); -extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void); -extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void); -#else -static inline struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static inline struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static inline struct dvb_frontend *dvb_dummy_fe_qam_attach(void) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_DUMMY_FE */ - -#endif // DVB_DUMMY_FE_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb-pll.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb-pll.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb-pll.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb-pll.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,795 +0,0 @@ -/* - * descriptions + helper functions for simple dvb plls. - * - * (c) 2004 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "dvb-pll.h" - -struct dvb_pll_priv { - /* pll number */ - int nr; - - /* i2c details */ - int pll_i2c_address; - struct i2c_adapter *i2c; - - /* the PLL descriptor */ - struct dvb_pll_desc *pll_desc; - - /* cached frequency/bandwidth */ - u32 frequency; - u32 bandwidth; -}; - -#define DVB_PLL_MAX 64 - -static unsigned int dvb_pll_devcount; - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static unsigned int id[DVB_PLL_MAX] = - { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED }; -module_param_array(id, int, NULL, 0644); -MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)"); - -/* ----------------------------------------------------------- */ - -struct dvb_pll_desc { - char *name; - u32 min; - u32 max; - u32 iffreq; - void (*set)(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params); - u8 *initdata; - u8 *initdata2; - u8 *sleepdata; - int count; - struct { - u32 limit; - u32 stepsize; - u8 config; - u8 cb; - } entries[12]; -}; - -/* ----------------------------------------------------------- */ -/* descriptions */ - -static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { - .name = "Thomson dtt7579", - .min = 177000000, - .max = 858000000, - .iffreq= 36166667, - .sleepdata = (u8[]){ 2, 0xb4, 0x03 }, - .count = 4, - .entries = { - { 443250000, 166667, 0xb4, 0x02 }, - { 542000000, 166667, 0xb4, 0x08 }, - { 771000000, 166667, 0xbc, 0x08 }, - { 999999999, 166667, 0xf4, 0x08 }, - }, -}; - -static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) -{ - if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth) - buf[3] |= 0x10; -} - -static struct dvb_pll_desc dvb_pll_thomson_dtt759x = { - .name = "Thomson dtt759x", - .min = 177000000, - .max = 896000000, - .set = thomson_dtt759x_bw, - .iffreq= 36166667, - .sleepdata = (u8[]){ 2, 0x84, 0x03 }, - .count = 5, - .entries = { - { 264000000, 166667, 0xb4, 0x02 }, - { 470000000, 166667, 0xbc, 0x02 }, - { 735000000, 166667, 0xbc, 0x08 }, - { 835000000, 166667, 0xf4, 0x08 }, - { 999999999, 166667, 0xfc, 0x08 }, - }, -}; - -static struct dvb_pll_desc dvb_pll_lg_z201 = { - .name = "LG z201", - .min = 174000000, - .max = 862000000, - .iffreq= 36166667, - .sleepdata = (u8[]){ 2, 0xbc, 0x03 }, - .count = 5, - .entries = { - { 157500000, 166667, 0xbc, 0x01 }, - { 443250000, 166667, 0xbc, 0x02 }, - { 542000000, 166667, 0xbc, 0x04 }, - { 830000000, 166667, 0xf4, 0x04 }, - { 999999999, 166667, 0xfc, 0x04 }, - }, -}; - -static struct dvb_pll_desc dvb_pll_unknown_1 = { - .name = "unknown 1", /* used by dntv live dvb-t */ - .min = 174000000, - .max = 862000000, - .iffreq= 36166667, - .count = 9, - .entries = { - { 150000000, 166667, 0xb4, 0x01 }, - { 173000000, 166667, 0xbc, 0x01 }, - { 250000000, 166667, 0xb4, 0x02 }, - { 400000000, 166667, 0xbc, 0x02 }, - { 420000000, 166667, 0xf4, 0x02 }, - { 470000000, 166667, 0xfc, 0x02 }, - { 600000000, 166667, 0xbc, 0x08 }, - { 730000000, 166667, 0xf4, 0x08 }, - { 999999999, 166667, 0xfc, 0x08 }, - }, -}; - -/* Infineon TUA6010XS - * used in Thomson Cable Tuner - */ -static struct dvb_pll_desc dvb_pll_tua6010xs = { - .name = "Infineon TUA6010XS", - .min = 44250000, - .max = 858000000, - .iffreq= 36125000, - .count = 3, - .entries = { - { 115750000, 62500, 0x8e, 0x03 }, - { 403250000, 62500, 0x8e, 0x06 }, - { 999999999, 62500, 0x8e, 0x85 }, - }, -}; - -/* Panasonic env57h1xd5 (some Philips PLL ?) */ -static struct dvb_pll_desc dvb_pll_env57h1xd5 = { - .name = "Panasonic ENV57H1XD5", - .min = 44250000, - .max = 858000000, - .iffreq= 36125000, - .count = 4, - .entries = { - { 153000000, 166667, 0xc2, 0x41 }, - { 470000000, 166667, 0xc2, 0x42 }, - { 526000000, 166667, 0xc2, 0x84 }, - { 999999999, 166667, 0xc2, 0xa4 }, - }, -}; - -/* Philips TDA6650/TDA6651 - * used in Panasonic ENV77H11D5 - */ -static void tda665x_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) -{ - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) - buf[3] |= 0x08; -} - -static struct dvb_pll_desc dvb_pll_tda665x = { - .name = "Philips TDA6650/TDA6651", - .min = 44250000, - .max = 858000000, - .set = tda665x_bw, - .iffreq= 36166667, - .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab }, - .count = 12, - .entries = { - { 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ }, - { 123834000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, - { 161000000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, - { 163834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, - { 253834000, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ }, - { 383834000, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ }, - { 443834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, - { 444000000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, - { 583834000, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ }, - { 793834000, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ }, - { 444834000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, - { 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, - } -}; - -/* Infineon TUA6034 - * used in LG TDTP E102P - */ -static void tua6034_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) -{ - if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth) - buf[3] |= 0x08; -} - -static struct dvb_pll_desc dvb_pll_tua6034 = { - .name = "Infineon TUA6034", - .min = 44250000, - .max = 858000000, - .iffreq= 36166667, - .count = 3, - .set = tua6034_bw, - .entries = { - { 174500000, 62500, 0xce, 0x01 }, - { 230000000, 62500, 0xce, 0x02 }, - { 999999999, 62500, 0xce, 0x04 }, - }, -}; - -/* ALPS TDED4 - * used in Nebula-Cards and USB boxes - */ -static void tded4_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) -{ - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) - buf[3] |= 0x04; -} - -static struct dvb_pll_desc dvb_pll_tded4 = { - .name = "ALPS TDED4", - .min = 47000000, - .max = 863000000, - .iffreq= 36166667, - .set = tded4_bw, - .count = 4, - .entries = { - { 153000000, 166667, 0x85, 0x01 }, - { 470000000, 166667, 0x85, 0x02 }, - { 823000000, 166667, 0x85, 0x08 }, - { 999999999, 166667, 0x85, 0x88 }, - } -}; - -/* ALPS TDHU2 - * used in AverTVHD MCE A180 - */ -static struct dvb_pll_desc dvb_pll_tdhu2 = { - .name = "ALPS TDHU2", - .min = 54000000, - .max = 864000000, - .iffreq= 44000000, - .count = 4, - .entries = { - { 162000000, 62500, 0x85, 0x01 }, - { 426000000, 62500, 0x85, 0x02 }, - { 782000000, 62500, 0x85, 0x08 }, - { 999999999, 62500, 0x85, 0x88 }, - } -}; - -/* Samsung TBMV30111IN / TBMV30712IN1 - * used in Air2PC ATSC - 2nd generation (nxt2002) - */ -static struct dvb_pll_desc dvb_pll_samsung_tbmv = { - .name = "Samsung TBMV30111IN / TBMV30712IN1", - .min = 54000000, - .max = 860000000, - .iffreq= 44000000, - .count = 6, - .entries = { - { 172000000, 166667, 0xb4, 0x01 }, - { 214000000, 166667, 0xb4, 0x02 }, - { 467000000, 166667, 0xbc, 0x02 }, - { 721000000, 166667, 0xbc, 0x08 }, - { 841000000, 166667, 0xf4, 0x08 }, - { 999999999, 166667, 0xfc, 0x02 }, - } -}; - -/* - * Philips SD1878 Tuner. - */ -static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { - .name = "Philips SD1878", - .min = 950000, - .max = 2150000, - .iffreq= 249, /* zero-IF, offset 249 is to round up */ - .count = 4, - .entries = { - { 1250000, 500, 0xc4, 0x00}, - { 1450000, 500, 0xc4, 0x40}, - { 2050000, 500, 0xc4, 0x80}, - { 2150000, 500, 0xc4, 0xc0}, - }, -}; - -static void opera1_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000; - struct i2c_msg msg = { - .addr = priv->pll_i2c_address, - .flags = 0, - .buf = buf, - .len = 4 - }; - int result; - u8 lpf; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - result = i2c_transfer(priv->i2c, &msg, 1); - if (result != 1) - printk(KERN_ERR "%s: i2c_transfer failed:%d", - __func__, result); - - if (b_w <= 10000) - lpf = 0xc; - else if (b_w <= 12000) - lpf = 0x2; - else if (b_w <= 14000) - lpf = 0xa; - else if (b_w <= 16000) - lpf = 0x6; - else if (b_w <= 18000) - lpf = 0xe; - else if (b_w <= 20000) - lpf = 0x1; - else if (b_w <= 22000) - lpf = 0x9; - else if (b_w <= 24000) - lpf = 0x5; - else if (b_w <= 26000) - lpf = 0xd; - else if (b_w <= 28000) - lpf = 0x3; - else - lpf = 0xb; - buf[2] ^= 0x1c; /* Flip bits 3-5 */ - /* Set lpf */ - buf[2] |= ((lpf >> 2) & 0x3) << 3; - buf[3] |= (lpf & 0x3) << 2; - - return; -} - -static struct dvb_pll_desc dvb_pll_opera1 = { - .name = "Opera Tuner", - .min = 900000, - .max = 2250000, - .initdata = (u8[]){ 4, 0x08, 0xe5, 0xe1, 0x00 }, - .initdata2 = (u8[]){ 4, 0x08, 0xe5, 0xe5, 0x00 }, - .iffreq= 0, - .set = opera1_bw, - .count = 8, - .entries = { - { 1064000, 500, 0xf9, 0xc2 }, - { 1169000, 500, 0xf9, 0xe2 }, - { 1299000, 500, 0xf9, 0x20 }, - { 1444000, 500, 0xf9, 0x40 }, - { 1606000, 500, 0xf9, 0x60 }, - { 1777000, 500, 0xf9, 0x80 }, - { 1941000, 500, 0xf9, 0xa0 }, - { 2250000, 500, 0xf9, 0xc0 }, - } -}; - -static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { - .addr = priv->pll_i2c_address, - .flags = 0, - .buf = buf, - .len = 4 - }; - int result; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - result = i2c_transfer(priv->i2c, &msg, 1); - if (result != 1) - printk(KERN_ERR "%s: i2c_transfer failed:%d", - __func__, result); - - buf[2] = 0x9e; - buf[3] = 0x90; - - return; -} - -/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */ -static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = { - .name = "Samsung DTOS403IH102A", - .min = 44250000, - .max = 858000000, - .iffreq = 36125000, - .count = 8, - .set = samsung_dtos403ih102a_set, - .entries = { - { 135000000, 62500, 0xbe, 0x01 }, - { 177000000, 62500, 0xf6, 0x01 }, - { 370000000, 62500, 0xbe, 0x02 }, - { 450000000, 62500, 0xf6, 0x02 }, - { 466000000, 62500, 0xfe, 0x02 }, - { 538000000, 62500, 0xbe, 0x08 }, - { 826000000, 62500, 0xf6, 0x08 }, - { 999999999, 62500, 0xfe, 0x08 }, - } -}; - -/* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */ -static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = { - .name = "Samsung TDTC9251DH0", - .min = 48000000, - .max = 863000000, - .iffreq = 36166667, - .count = 3, - .entries = { - { 157500000, 166667, 0xcc, 0x09 }, - { 443000000, 166667, 0xcc, 0x0a }, - { 863000000, 166667, 0xcc, 0x08 }, - } -}; - -/* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */ -static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = { - .name = "Samsung TBDU18132", - .min = 950000, - .max = 2150000, /* guesses */ - .iffreq = 0, - .count = 2, - .entries = { - { 1550000, 125, 0x84, 0x82 }, - { 4095937, 125, 0x84, 0x80 }, - } - /* TSA5059 PLL has a 17 bit divisor rather than the 15 bits supported - * by this driver. The two extra bits are 0x60 in the third byte. 15 - * bits is enough for over 4 GHz, which is enough to cover the range - * of this tuner. We could use the additional divisor bits by adding - * more entries, e.g. - { 0x0ffff * 125 + 125/2, 125, 0x84 | 0x20, }, - { 0x17fff * 125 + 125/2, 125, 0x84 | 0x40, }, - { 0x1ffff * 125 + 125/2, 125, 0x84 | 0x60, }, */ -}; - -/* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */ -static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = { - .name = "Samsung TBMU24112", - .min = 950000, - .max = 2150000, /* guesses */ - .iffreq = 0, - .count = 2, - .entries = { - { 1500000, 125, 0x84, 0x18 }, - { 9999999, 125, 0x84, 0x08 }, - } -}; - -/* Alps TDEE4 DVB-C NIM, used on Cablestar 2 */ -/* byte 4 : 1 * * AGD R3 R2 R1 R0 - * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1 - * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 - * Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5 - * 47 - 153 0 * 0 0 0 0 0 1 0x01 - * 153 - 430 0 * 0 0 0 0 1 0 0x02 - * 430 - 822 0 * 0 0 1 0 0 0 0x08 - * 822 - 862 1 * 0 0 1 0 0 0 0x88 */ -static struct dvb_pll_desc dvb_pll_alps_tdee4 = { - .name = "ALPS TDEE4", - .min = 47000000, - .max = 862000000, - .iffreq = 36125000, - .count = 4, - .entries = { - { 153000000, 62500, 0x95, 0x01 }, - { 430000000, 62500, 0x95, 0x02 }, - { 822000000, 62500, 0x95, 0x08 }, - { 999999999, 62500, 0x95, 0x88 }, - } -}; - -/* ----------------------------------------------------------- */ - -static struct dvb_pll_desc *pll_list[] = { - [DVB_PLL_UNDEFINED] = NULL, - [DVB_PLL_THOMSON_DTT7579] = &dvb_pll_thomson_dtt7579, - [DVB_PLL_THOMSON_DTT759X] = &dvb_pll_thomson_dtt759x, - [DVB_PLL_LG_Z201] = &dvb_pll_lg_z201, - [DVB_PLL_UNKNOWN_1] = &dvb_pll_unknown_1, - [DVB_PLL_TUA6010XS] = &dvb_pll_tua6010xs, - [DVB_PLL_ENV57H1XD5] = &dvb_pll_env57h1xd5, - [DVB_PLL_TUA6034] = &dvb_pll_tua6034, - [DVB_PLL_TDA665X] = &dvb_pll_tda665x, - [DVB_PLL_TDED4] = &dvb_pll_tded4, - [DVB_PLL_TDEE4] = &dvb_pll_alps_tdee4, - [DVB_PLL_TDHU2] = &dvb_pll_tdhu2, - [DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv, - [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261, - [DVB_PLL_OPERA1] = &dvb_pll_opera1, - [DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a, - [DVB_PLL_SAMSUNG_TDTC9251DH0] = &dvb_pll_samsung_tdtc9251dh0, - [DVB_PLL_SAMSUNG_TBDU18132] = &dvb_pll_samsung_tbdu18132, - [DVB_PLL_SAMSUNG_TBMU24112] = &dvb_pll_samsung_tbmu24112, -}; - -/* ----------------------------------------------------------- */ -/* code */ - -static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - struct dvb_pll_desc *desc = priv->pll_desc; - u32 div; - int i; - - if (params->frequency != 0 && (params->frequency < desc->min || - params->frequency > desc->max)) - return -EINVAL; - - for (i = 0; i < desc->count; i++) { - if (params->frequency > desc->entries[i].limit) - continue; - break; - } - - if (debug) - printk("pll: %s: freq=%d | i=%d/%d\n", desc->name, - params->frequency, i, desc->count); - if (i == desc->count) - return -EINVAL; - - div = (params->frequency + desc->iffreq + - desc->entries[i].stepsize/2) / desc->entries[i].stepsize; - buf[0] = div >> 8; - buf[1] = div & 0xff; - buf[2] = desc->entries[i].config; - buf[3] = desc->entries[i].cb; - - if (desc->set) - desc->set(fe, buf, params); - - if (debug) - printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", - desc->name, div, buf[0], buf[1], buf[2], buf[3]); - - // calculate the frequency we set it to - return (div * desc->entries[i].stepsize) - desc->iffreq; -} - -static int dvb_pll_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int dvb_pll_sleep(struct dvb_frontend *fe) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - - if (priv->i2c == NULL) - return -EINVAL; - - if (priv->pll_desc->sleepdata) { - struct i2c_msg msg = { .flags = 0, - .addr = priv->pll_i2c_address, - .buf = priv->pll_desc->sleepdata + 1, - .len = priv->pll_desc->sleepdata[0] }; - - int result; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { - return result; - } - return 0; - } - /* Shouldn't be called when initdata is NULL, maybe BUG()? */ - return -EINVAL; -} - -static int dvb_pll_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - u8 buf[4]; - struct i2c_msg msg = - { .addr = priv->pll_i2c_address, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - int result; - u32 frequency = 0; - - if (priv->i2c == NULL) - return -EINVAL; - - if ((result = dvb_pll_configure(fe, buf, params)) < 0) - return result; - else - frequency = result; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { - return result; - } - - priv->frequency = frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - - return 0; -} - -static int dvb_pll_calc_regs(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, - u8 *buf, int buf_len) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - int result; - u32 frequency = 0; - - if (buf_len < 5) - return -EINVAL; - - if ((result = dvb_pll_configure(fe, buf+1, params)) < 0) - return result; - else - frequency = result; - - buf[0] = priv->pll_i2c_address; - - priv->frequency = frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - - return 5; -} - -static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static int dvb_pll_init(struct dvb_frontend *fe) -{ - struct dvb_pll_priv *priv = fe->tuner_priv; - - if (priv->i2c == NULL) - return -EINVAL; - - if (priv->pll_desc->initdata) { - struct i2c_msg msg = { .flags = 0, - .addr = priv->pll_i2c_address, - .buf = priv->pll_desc->initdata + 1, - .len = priv->pll_desc->initdata[0] }; - - int result; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - result = i2c_transfer(priv->i2c, &msg, 1); - if (result != 1) - return result; - if (priv->pll_desc->initdata2) { - msg.buf = priv->pll_desc->initdata2 + 1; - msg.len = priv->pll_desc->initdata2[0]; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - result = i2c_transfer(priv->i2c, &msg, 1); - if (result != 1) - return result; - } - return 0; - } - /* Shouldn't be called when initdata is NULL, maybe BUG()? */ - return -EINVAL; -} - -static struct dvb_tuner_ops dvb_pll_tuner_ops = { - .release = dvb_pll_release, - .sleep = dvb_pll_sleep, - .init = dvb_pll_init, - .set_params = dvb_pll_set_params, - .calc_regs = dvb_pll_calc_regs, - .get_frequency = dvb_pll_get_frequency, - .get_bandwidth = dvb_pll_get_bandwidth, -}; - -struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, - struct i2c_adapter *i2c, - unsigned int pll_desc_id) -{ - u8 b1 [] = { 0 }; - struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, - .buf = b1, .len = 1 }; - struct dvb_pll_priv *priv = NULL; - int ret; - struct dvb_pll_desc *desc; - - if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) && - (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list))) - pll_desc_id = id[dvb_pll_devcount]; - - BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list)); - - desc = pll_list[pll_desc_id]; - - if (i2c != NULL) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = i2c_transfer (i2c, &msg, 1); - if (ret != 1) - return NULL; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->pll_i2c_address = pll_addr; - priv->i2c = i2c; - priv->pll_desc = desc; - priv->nr = dvb_pll_devcount++; - - memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - strncpy(fe->ops.tuner_ops.info.name, desc->name, - sizeof(fe->ops.tuner_ops.info.name)); - fe->ops.tuner_ops.info.frequency_min = desc->min; - fe->ops.tuner_ops.info.frequency_max = desc->max; - if (!desc->initdata) - fe->ops.tuner_ops.init = NULL; - if (!desc->sleepdata) - fe->ops.tuner_ops.sleep = NULL; - - fe->tuner_priv = priv; - - if ((debug) || (id[priv->nr] == pll_desc_id)) { - printk("dvb-pll[%d]", priv->nr); - if (i2c != NULL) - printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); - printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, - id[priv->nr] == pll_desc_id ? - "insmod option" : "autodetected"); - } - - return fe; -} -EXPORT_SYMBOL(dvb_pll_attach); - -MODULE_DESCRIPTION("dvb pll library"); -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb-pll.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb-pll.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb-pll.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/dvb-pll.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - * descriptions + helper functions for simple dvb plls. - */ - -#ifndef __DVB_PLL_H__ -#define __DVB_PLL_H__ - -#include -#include "dvb_frontend.h" - -#define DVB_PLL_UNDEFINED 0 -#define DVB_PLL_THOMSON_DTT7579 1 -#define DVB_PLL_THOMSON_DTT759X 2 -#define DVB_PLL_LG_Z201 3 -#define DVB_PLL_UNKNOWN_1 4 -#define DVB_PLL_TUA6010XS 5 -#define DVB_PLL_ENV57H1XD5 6 -#define DVB_PLL_TUA6034 7 -#define DVB_PLL_TDA665X 8 -#define DVB_PLL_TDED4 9 -#define DVB_PLL_TDHU2 10 -#define DVB_PLL_SAMSUNG_TBMV 11 -#define DVB_PLL_PHILIPS_SD1878_TDA8261 12 -#define DVB_PLL_OPERA1 13 -#define DVB_PLL_SAMSUNG_DTOS403IH102A 14 -#define DVB_PLL_SAMSUNG_TDTC9251DH0 15 -#define DVB_PLL_SAMSUNG_TBDU18132 16 -#define DVB_PLL_SAMSUNG_TBMU24112 17 -#define DVB_PLL_TDEE4 18 - -/** - * Attach a dvb-pll to the supplied frontend structure. - * - * @param fe Frontend to attach to. - * @param pll_addr i2c address of the PLL (if used). - * @param i2c i2c adapter to use (set to NULL if not used). - * @param pll_desc_id dvb_pll_desc to use. - * @return Frontend pointer on success, NULL on failure - */ -#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE)) -extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, - int pll_addr, - struct i2c_adapter *i2c, - unsigned int pll_desc_id); -#else -static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, - int pll_addr, - struct i2c_adapter *i2c, - unsigned int pll_desc_id) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,335 +0,0 @@ -/* - * E3C EC100 demodulator driver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "dvb_frontend.h" -#include "ec100_priv.h" -#include "ec100.h" - -int ec100_debug; -module_param_named(debug, ec100_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -struct ec100_state { - struct i2c_adapter *i2c; - struct dvb_frontend frontend; - struct ec100_config config; - - u16 ber; -}; - -/* write single register */ -static int ec100_write_reg(struct ec100_state *state, u8 reg, u8 val) -{ - u8 buf[2] = {reg, val}; - struct i2c_msg msg = { - .addr = state->config.demod_address, - .flags = 0, - .len = 2, - .buf = buf}; - - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - warn("I2C write failed reg:%02x", reg); - return -EREMOTEIO; - } - return 0; -} - -/* read single register */ -static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val) -{ - struct i2c_msg msg[2] = { - { - .addr = state->config.demod_address, - .flags = 0, - .len = 1, - .buf = ® - }, { - .addr = state->config.demod_address, - .flags = I2C_M_RD, - .len = 1, - .buf = val - } - }; - - if (i2c_transfer(state->i2c, msg, 2) != 2) { - warn("I2C read failed reg:%02x", reg); - return -EREMOTEIO; - } - return 0; -} - -static int ec100_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct ec100_state *state = fe->demodulator_priv; - int ret; - u8 tmp, tmp2; - - deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, - params->u.ofdm.bandwidth); - - /* program tuner */ - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); - - ret = ec100_write_reg(state, 0x04, 0x06); - if (ret) - goto error; - ret = ec100_write_reg(state, 0x67, 0x58); - if (ret) - goto error; - ret = ec100_write_reg(state, 0x05, 0x18); - if (ret) - goto error; - - /* reg/bw | 6 | 7 | 8 - -------+------+------+------ - A 0x1b | 0xa1 | 0xe7 | 0x2c - A 0x1c | 0x55 | 0x63 | 0x72 - -------+------+------+------ - B 0x1b | 0xb7 | 0x00 | 0x49 - B 0x1c | 0x55 | 0x64 | 0x72 */ - - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - tmp = 0xb7; - tmp2 = 0x55; - break; - case BANDWIDTH_7_MHZ: - tmp = 0x00; - tmp2 = 0x64; - break; - case BANDWIDTH_8_MHZ: - default: - tmp = 0x49; - tmp2 = 0x72; - } - - ret = ec100_write_reg(state, 0x1b, tmp); - if (ret) - goto error; - ret = ec100_write_reg(state, 0x1c, tmp2); - if (ret) - goto error; - - ret = ec100_write_reg(state, 0x0c, 0xbb); /* if freq */ - if (ret) - goto error; - ret = ec100_write_reg(state, 0x0d, 0x31); /* if freq */ - if (ret) - goto error; - - ret = ec100_write_reg(state, 0x08, 0x24); - if (ret) - goto error; - - ret = ec100_write_reg(state, 0x00, 0x00); /* go */ - if (ret) - goto error; - ret = ec100_write_reg(state, 0x00, 0x20); /* go */ - if (ret) - goto error; - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -static int ec100_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *fesettings) -{ - fesettings->min_delay_ms = 300; - fesettings->step_size = 0; - fesettings->max_drift = 0; - - return 0; -} - -static int ec100_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct ec100_state *state = fe->demodulator_priv; - int ret; - u8 tmp; - *status = 0; - - ret = ec100_read_reg(state, 0x42, &tmp); - if (ret) - goto error; - - if (tmp & 0x80) { - /* bit7 set - have lock */ - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_LOCK; - } else { - ret = ec100_read_reg(state, 0x01, &tmp); - if (ret) - goto error; - - if (tmp & 0x10) { - /* bit4 set - have signal */ - *status |= FE_HAS_SIGNAL; - if (!(tmp & 0x01)) { - /* bit0 clear - have ~valid signal */ - *status |= FE_HAS_CARRIER | FE_HAS_VITERBI; - } - } - } - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -static int ec100_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct ec100_state *state = fe->demodulator_priv; - int ret; - u8 tmp, tmp2; - u16 ber2; - - *ber = 0; - - ret = ec100_read_reg(state, 0x65, &tmp); - if (ret) - goto error; - ret = ec100_read_reg(state, 0x66, &tmp2); - if (ret) - goto error; - - ber2 = (tmp2 << 8) | tmp; - - /* if counter overflow or clear */ - if (ber2 < state->ber) - *ber = ber2; - else - *ber = ber2 - state->ber; - - state->ber = ber2; - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -static int ec100_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct ec100_state *state = fe->demodulator_priv; - int ret; - u8 tmp; - - ret = ec100_read_reg(state, 0x24, &tmp); - if (ret) { - *strength = 0; - goto error; - } - - *strength = ((tmp << 8) | tmp); - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -static int ec100_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - *snr = 0; - return 0; -} - -static int ec100_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - *ucblocks = 0; - return 0; -} - -static void ec100_release(struct dvb_frontend *fe) -{ - struct ec100_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops ec100_ops; - -struct dvb_frontend *ec100_attach(const struct ec100_config *config, - struct i2c_adapter *i2c) -{ - int ret; - struct ec100_state *state = NULL; - u8 tmp; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct ec100_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->i2c = i2c; - memcpy(&state->config, config, sizeof(struct ec100_config)); - - /* check if the demod is there */ - ret = ec100_read_reg(state, 0x33, &tmp); - if (ret || tmp != 0x0b) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &ec100_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - return &state->frontend; -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(ec100_attach); - -static struct dvb_frontend_ops ec100_ops = { - .info = { - .name = "E3C EC100 DVB-T", - .type = FE_OFDM, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | - FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | - FE_CAN_MUTE_TS - }, - - .release = ec100_release, - .set_frontend = ec100_set_frontend, - .get_tune_settings = ec100_get_tune_settings, - .read_status = ec100_read_status, - .read_ber = ec100_read_ber, - .read_signal_strength = ec100_read_signal_strength, - .read_snr = ec100_read_snr, - .read_ucblocks = ec100_read_ucblocks, -}; - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("E3C EC100 DVB-T demodulator driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * E3C EC100 demodulator driver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef EC100_H -#define EC100_H - -#include - -struct ec100_config { - /* demodulator's I2C address */ - u8 demod_address; -}; - - -#if defined(CONFIG_DVB_EC100) || \ - (defined(CONFIG_DVB_EC100_MODULE) && defined(MODULE)) -extern struct dvb_frontend *ec100_attach(const struct ec100_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *ec100_attach( - const struct ec100_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* EC100_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ec100_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - * E3C EC100 demodulator driver - * - * Copyright (C) 2009 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef EC100_PRIV -#define EC100_PRIV - -#define LOG_PREFIX "ec100" - -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) - -#define deb_info(args...) dprintk(ec100_debug, 0x01, args) - -#undef err -#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -#undef info -#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef warn -#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) - -#endif /* EC100_PRIV */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/eds1547.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/eds1547.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/eds1547.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/eds1547.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -/* eds1547.h Earda EDS-1547 tuner support -* -* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) -* -* 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, version 2. -* -* see Documentation/dvb/README.dvb-usb for more information -*/ - -#ifndef EDS1547 -#define EDS1547 - -static u8 stv0288_earda_inittab[] = { - 0x01, 0x57, - 0x02, 0x20, - 0x03, 0x8e, - 0x04, 0x8e, - 0x05, 0x12, - 0x06, 0x00, - 0x07, 0x00, - 0x09, 0x00, - 0x0a, 0x04, - 0x0b, 0x00, - 0x0c, 0x00, - 0x0d, 0x00, - 0x0e, 0xd4, - 0x0f, 0x30, - 0x11, 0x44, - 0x12, 0x03, - 0x13, 0x48, - 0x14, 0x84, - 0x15, 0x45, - 0x16, 0xb7, - 0x17, 0x9c, - 0x18, 0x00, - 0x19, 0xa6, - 0x1a, 0x88, - 0x1b, 0x8f, - 0x1c, 0xf0, - 0x20, 0x0b, - 0x21, 0x54, - 0x22, 0x00, - 0x23, 0x00, - 0x2b, 0xff, - 0x2c, 0xf7, - 0x30, 0x00, - 0x31, 0x1e, - 0x32, 0x14, - 0x33, 0x0f, - 0x34, 0x09, - 0x35, 0x0c, - 0x36, 0x05, - 0x37, 0x2f, - 0x38, 0x16, - 0x39, 0xbd, - 0x3a, 0x00, - 0x3b, 0x13, - 0x3c, 0x11, - 0x3d, 0x30, - 0x40, 0x63, - 0x41, 0x04, - 0x42, 0x60, - 0x43, 0x00, - 0x44, 0x00, - 0x45, 0x00, - 0x46, 0x00, - 0x47, 0x00, - 0x4a, 0x00, - 0x50, 0x10, - 0x51, 0x36, - 0x52, 0x09, - 0x53, 0x94, - 0x54, 0x62, - 0x55, 0x29, - 0x56, 0x64, - 0x57, 0x2b, - 0x58, 0x54, - 0x59, 0x86, - 0x5a, 0x00, - 0x5b, 0x9b, - 0x5c, 0x08, - 0x5d, 0x7f, - 0x5e, 0x00, - 0x5f, 0xff, - 0x70, 0x00, - 0x71, 0x00, - 0x72, 0x00, - 0x74, 0x00, - 0x75, 0x00, - 0x76, 0x00, - 0x81, 0x00, - 0x82, 0x3f, - 0x83, 0x3f, - 0x84, 0x00, - 0x85, 0x00, - 0x88, 0x00, - 0x89, 0x00, - 0x8a, 0x00, - 0x8b, 0x00, - 0x8c, 0x00, - 0x90, 0x00, - 0x91, 0x00, - 0x92, 0x00, - 0x93, 0x00, - 0x94, 0x1c, - 0x97, 0x00, - 0xa0, 0x48, - 0xa1, 0x00, - 0xb0, 0xb8, - 0xb1, 0x3a, - 0xb2, 0x10, - 0xb3, 0x82, - 0xb4, 0x80, - 0xb5, 0x82, - 0xb6, 0x82, - 0xb7, 0x82, - 0xb8, 0x20, - 0xb9, 0x00, - 0xf0, 0x00, - 0xf1, 0x00, - 0xf2, 0xc0, - 0xff,0xff, -}; - -static struct stv0288_config earda_config = { - .demod_address = 0x68, - .min_delay_ms = 100, - .inittab = stv0288_earda_inittab, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6405.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6405.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6405.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6405.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,164 +0,0 @@ -/* - * isl6405.c - driver for dual lnb supply and control ic ISL6405 - * - * Copyright (C) 2008 Hartmut Hackmann - * Copyright (C) 2006 Oliver Endriss - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org - */ -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "isl6405.h" - -struct isl6405 { - u8 config; - u8 override_or; - u8 override_and; - struct i2c_adapter *i2c; - u8 i2c_addr; -}; - -static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv; - struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0, - .buf = &isl6405->config, - .len = sizeof(isl6405->config) }; - - if (isl6405->override_or & 0x80) { - isl6405->config &= ~(ISL6405_VSEL2 | ISL6405_EN2); - switch (voltage) { - case SEC_VOLTAGE_OFF: - break; - case SEC_VOLTAGE_13: - isl6405->config |= ISL6405_EN2; - break; - case SEC_VOLTAGE_18: - isl6405->config |= (ISL6405_EN2 | ISL6405_VSEL2); - break; - default: - return -EINVAL; - } - } else { - isl6405->config &= ~(ISL6405_VSEL1 | ISL6405_EN1); - switch (voltage) { - case SEC_VOLTAGE_OFF: - break; - case SEC_VOLTAGE_13: - isl6405->config |= ISL6405_EN1; - break; - case SEC_VOLTAGE_18: - isl6405->config |= (ISL6405_EN1 | ISL6405_VSEL1); - break; - default: - return -EINVAL; - }; - } - isl6405->config |= isl6405->override_or; - isl6405->config &= isl6405->override_and; - - return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO; -} - -static int isl6405_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) -{ - struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv; - struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0, - .buf = &isl6405->config, - .len = sizeof(isl6405->config) }; - - if (isl6405->override_or & 0x80) { - if (arg) - isl6405->config |= ISL6405_LLC2; - else - isl6405->config &= ~ISL6405_LLC2; - } else { - if (arg) - isl6405->config |= ISL6405_LLC1; - else - isl6405->config &= ~ISL6405_LLC1; - } - isl6405->config |= isl6405->override_or; - isl6405->config &= isl6405->override_and; - - return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO; -} - -static void isl6405_release(struct dvb_frontend *fe) -{ - /* power off */ - isl6405_set_voltage(fe, SEC_VOLTAGE_OFF); - - /* free */ - kfree(fe->sec_priv); - fe->sec_priv = NULL; -} - -struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, - u8 i2c_addr, u8 override_set, u8 override_clear) -{ - struct isl6405 *isl6405 = kmalloc(sizeof(struct isl6405), GFP_KERNEL); - if (!isl6405) - return NULL; - - /* default configuration */ - if (override_set & 0x80) - isl6405->config = ISL6405_ISEL2; - else - isl6405->config = ISL6405_ISEL1; - isl6405->i2c = i2c; - isl6405->i2c_addr = i2c_addr; - fe->sec_priv = isl6405; - - /* bits which should be forced to '1' */ - isl6405->override_or = override_set; - - /* bits which should be forced to '0' */ - isl6405->override_and = ~override_clear; - - /* detect if it is present or not */ - if (isl6405_set_voltage(fe, SEC_VOLTAGE_OFF)) { - kfree(isl6405); - fe->sec_priv = NULL; - return NULL; - } - - /* install release callback */ - fe->ops.release_sec = isl6405_release; - - /* override frontend ops */ - fe->ops.set_voltage = isl6405_set_voltage; - fe->ops.enable_high_lnb_voltage = isl6405_enable_high_lnb_voltage; - - return fe; -} -EXPORT_SYMBOL(isl6405_attach); - -MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405"); -MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6405.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6405.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6405.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6405.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -/* - * isl6405.h - driver for dual lnb supply and control ic ISL6405 - * - * Copyright (C) 2008 Hartmut Hackmann - * Copyright (C) 2006 Oliver Endriss - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org - */ - -#ifndef _ISL6405_H -#define _ISL6405_H - -#include - -/* system register bits */ - -/* this bit selects register (control) 1 or 2 - note that the bit maps are different */ - -#define ISL6405_SR 0x80 - -/* SR = 0 */ -#define ISL6405_OLF1 0x01 -#define ISL6405_EN1 0x02 -#define ISL6405_VSEL1 0x04 -#define ISL6405_LLC1 0x08 -#define ISL6405_ENT1 0x10 -#define ISL6405_ISEL1 0x20 -#define ISL6405_DCL 0x40 - -/* SR = 1 */ -#define ISL6405_OLF2 0x01 -#define ISL6405_OTF 0x02 -#define ISL6405_EN2 0x04 -#define ISL6405_VSEL2 0x08 -#define ISL6405_LLC2 0x10 -#define ISL6405_ENT2 0x20 -#define ISL6405_ISEL2 0x40 - -#if defined(CONFIG_DVB_ISL6405) || (defined(CONFIG_DVB_ISL6405_MODULE) && defined(MODULE)) -/* override_set and override_clear control which system register bits (above) - * to always set & clear - */ -extern struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, - u8 i2c_addr, u8 override_set, u8 override_clear); -#else -static inline struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 i2c_addr, - u8 override_set, u8 override_clear) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_ISL6405 */ - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6421.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6421.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6421.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6421.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/* - * isl6421.h - driver for lnb supply and control ic ISL6421 - * - * Copyright (C) 2006 Andrew de Quincey - * Copyright (C) 2006 Oliver Endriss - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org - */ -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "isl6421.h" - -struct isl6421 { - u8 config; - u8 override_or; - u8 override_and; - struct i2c_adapter *i2c; - u8 i2c_addr; -}; - -static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; - struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, - .buf = &isl6421->config, - .len = sizeof(isl6421->config) }; - - isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1); - - switch(voltage) { - case SEC_VOLTAGE_OFF: - break; - case SEC_VOLTAGE_13: - isl6421->config |= ISL6421_EN1; - break; - case SEC_VOLTAGE_18: - isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1); - break; - default: - return -EINVAL; - }; - - isl6421->config |= isl6421->override_or; - isl6421->config &= isl6421->override_and; - - return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; -} - -static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) -{ - struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; - struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, - .buf = &isl6421->config, - .len = sizeof(isl6421->config) }; - - if (arg) - isl6421->config |= ISL6421_LLC1; - else - isl6421->config &= ~ISL6421_LLC1; - - isl6421->config |= isl6421->override_or; - isl6421->config &= isl6421->override_and; - - return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; -} - -static void isl6421_release(struct dvb_frontend *fe) -{ - /* power off */ - isl6421_set_voltage(fe, SEC_VOLTAGE_OFF); - - /* free */ - kfree(fe->sec_priv); - fe->sec_priv = NULL; -} - -struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, - u8 override_set, u8 override_clear) -{ - struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL); - if (!isl6421) - return NULL; - - /* default configuration */ - isl6421->config = ISL6421_ISEL1; - isl6421->i2c = i2c; - isl6421->i2c_addr = i2c_addr; - fe->sec_priv = isl6421; - - /* bits which should be forced to '1' */ - isl6421->override_or = override_set; - - /* bits which should be forced to '0' */ - isl6421->override_and = ~override_clear; - - /* detect if it is present or not */ - if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) { - kfree(isl6421); - fe->sec_priv = NULL; - return NULL; - } - - /* install release callback */ - fe->ops.release_sec = isl6421_release; - - /* override frontend ops */ - fe->ops.set_voltage = isl6421_set_voltage; - fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage; - - return fe; -} -EXPORT_SYMBOL(isl6421_attach); - -MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421"); -MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6421.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6421.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6421.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6421.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/* - * isl6421.h - driver for lnb supply and control ic ISL6421 - * - * Copyright (C) 2006 Andrew de Quincey - * Copyright (C) 2006 Oliver Endriss - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org - */ - -#ifndef _ISL6421_H -#define _ISL6421_H - -#include - -/* system register bits */ -#define ISL6421_OLF1 0x01 -#define ISL6421_EN1 0x02 -#define ISL6421_VSEL1 0x04 -#define ISL6421_LLC1 0x08 -#define ISL6421_ENT1 0x10 -#define ISL6421_ISEL1 0x20 -#define ISL6421_DCL 0x40 - -#if defined(CONFIG_DVB_ISL6421) || (defined(CONFIG_DVB_ISL6421_MODULE) && defined(MODULE)) -/* override_set and override_clear control which system register bits (above) to always set & clear */ -extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, - u8 override_set, u8 override_clear); -#else -static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, - u8 override_set, u8 override_clear) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_ISL6421 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6423.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6423.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6423.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6423.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,308 +0,0 @@ -/* - Intersil ISL6423 SEC and LNB Power supply controller - - Copyright (C) Manu Abraham - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "isl6423.h" - -static unsigned int verbose; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "Set Verbosity level"); - -#define FE_ERROR 0 -#define FE_NOTICE 1 -#define FE_INFO 2 -#define FE_DEBUG 3 -#define FE_DEBUGREG 4 - -#define dprintk(__y, __z, format, arg...) do { \ - if (__z) { \ - if ((verbose > FE_ERROR) && (verbose > __y)) \ - printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ - else if ((verbose > FE_NOTICE) && (verbose > __y)) \ - printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ - else if ((verbose > FE_INFO) && (verbose > __y)) \ - printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ - else if ((verbose > FE_DEBUG) && (verbose > __y)) \ - printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ - } else { \ - if (verbose > __y) \ - printk(format, ##arg); \ - } \ -} while (0) - -struct isl6423_dev { - const struct isl6423_config *config; - struct i2c_adapter *i2c; - - u8 reg_3; - u8 reg_4; - - unsigned int verbose; -}; - -static int isl6423_write(struct isl6423_dev *isl6423, u8 reg) -{ - struct i2c_adapter *i2c = isl6423->i2c; - u8 addr = isl6423->config->addr; - int err = 0; - - struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = ®, .len = 1 }; - - dprintk(FE_DEBUG, 1, "write reg %02X", reg); - err = i2c_transfer(i2c, &msg, 1); - if (err < 0) - goto exit; - return 0; - -exit: - dprintk(FE_ERROR, 1, "I/O error <%d>", err); - return err; -} - -static int isl6423_set_modulation(struct dvb_frontend *fe) -{ - struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; - const struct isl6423_config *config = isl6423->config; - int err = 0; - u8 reg_2 = 0; - - reg_2 = 0x01 << 5; - - if (config->mod_extern) - reg_2 |= (1 << 3); - else - reg_2 |= (1 << 4); - - err = isl6423_write(isl6423, reg_2); - if (err < 0) - goto exit; - return 0; - -exit: - dprintk(FE_ERROR, 1, "I/O error <%d>", err); - return err; -} - -static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg) -{ - struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; - u8 reg_3 = isl6423->reg_3; - u8 reg_4 = isl6423->reg_4; - int err = 0; - - if (arg) { - /* EN = 1, VSPEN = 1, VBOT = 1 */ - reg_4 |= (1 << 4); - reg_4 |= 0x1; - reg_3 |= (1 << 3); - } else { - /* EN = 1, VSPEN = 1, VBOT = 0 */ - reg_4 |= (1 << 4); - reg_4 &= ~0x1; - reg_3 |= (1 << 3); - } - err = isl6423_write(isl6423, reg_3); - if (err < 0) - goto exit; - - err = isl6423_write(isl6423, reg_4); - if (err < 0) - goto exit; - - isl6423->reg_3 = reg_3; - isl6423->reg_4 = reg_4; - - return 0; -exit: - dprintk(FE_ERROR, 1, "I/O error <%d>", err); - return err; -} - - -static int isl6423_set_voltage(struct dvb_frontend *fe, - enum fe_sec_voltage voltage) -{ - struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; - u8 reg_3 = isl6423->reg_3; - u8 reg_4 = isl6423->reg_4; - int err = 0; - - switch (voltage) { - case SEC_VOLTAGE_OFF: - /* EN = 0 */ - reg_4 &= ~(1 << 4); - break; - - case SEC_VOLTAGE_13: - /* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */ - reg_4 |= (1 << 4); - reg_4 &= ~0x3; - reg_3 |= (1 << 3); - break; - - case SEC_VOLTAGE_18: - /* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */ - reg_4 |= (1 << 4); - reg_4 |= 0x2; - reg_4 &= ~0x1; - reg_3 |= (1 << 3); - break; - - default: - break; - } - err = isl6423_write(isl6423, reg_3); - if (err < 0) - goto exit; - - err = isl6423_write(isl6423, reg_4); - if (err < 0) - goto exit; - - isl6423->reg_3 = reg_3; - isl6423->reg_4 = reg_4; - - return 0; -exit: - dprintk(FE_ERROR, 1, "I/O error <%d>", err); - return err; -} - -static int isl6423_set_current(struct dvb_frontend *fe) -{ - struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; - u8 reg_3 = isl6423->reg_3; - const struct isl6423_config *config = isl6423->config; - int err = 0; - - switch (config->current_max) { - case SEC_CURRENT_275m: - /* 275mA */ - /* ISELH = 0, ISELL = 0 */ - reg_3 &= ~0x3; - break; - - case SEC_CURRENT_515m: - /* 515mA */ - /* ISELH = 0, ISELL = 1 */ - reg_3 &= ~0x2; - reg_3 |= 0x1; - break; - - case SEC_CURRENT_635m: - /* 635mA */ - /* ISELH = 1, ISELL = 0 */ - reg_3 &= ~0x1; - reg_3 |= 0x2; - break; - - case SEC_CURRENT_800m: - /* 800mA */ - /* ISELH = 1, ISELL = 1 */ - reg_3 |= 0x3; - break; - } - - err = isl6423_write(isl6423, reg_3); - if (err < 0) - goto exit; - - switch (config->curlim) { - case SEC_CURRENT_LIM_ON: - /* DCL = 0 */ - reg_3 &= ~0x10; - break; - - case SEC_CURRENT_LIM_OFF: - /* DCL = 1 */ - reg_3 |= 0x10; - break; - } - - err = isl6423_write(isl6423, reg_3); - if (err < 0) - goto exit; - - isl6423->reg_3 = reg_3; - - return 0; -exit: - dprintk(FE_ERROR, 1, "I/O error <%d>", err); - return err; -} - -static void isl6423_release(struct dvb_frontend *fe) -{ - isl6423_set_voltage(fe, SEC_VOLTAGE_OFF); - - kfree(fe->sec_priv); - fe->sec_priv = NULL; -} - -struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct isl6423_config *config) -{ - struct isl6423_dev *isl6423; - - isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL); - if (!isl6423) - return NULL; - - isl6423->config = config; - isl6423->i2c = i2c; - fe->sec_priv = isl6423; - - /* SR3H = 0, SR3M = 1, SR3L = 0 */ - isl6423->reg_3 = 0x02 << 5; - /* SR4H = 0, SR4M = 1, SR4L = 1 */ - isl6423->reg_4 = 0x03 << 5; - - if (isl6423_set_current(fe)) - goto exit; - - if (isl6423_set_modulation(fe)) - goto exit; - - fe->ops.release_sec = isl6423_release; - fe->ops.set_voltage = isl6423_set_voltage; - fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost; - isl6423->verbose = verbose; - - return fe; - -exit: - kfree(isl6423); - fe->sec_priv = NULL; - return NULL; -} -EXPORT_SYMBOL(isl6423_attach); - -MODULE_DESCRIPTION("ISL6423 SEC"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6423.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6423.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6423.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/isl6423.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* - Intersil ISL6423 SEC and LNB Power supply controller - - Copyright (C) Manu Abraham - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __ISL_6423_H -#define __ISL_6423_H - -#include - -enum isl6423_current { - SEC_CURRENT_275m = 0, - SEC_CURRENT_515m, - SEC_CURRENT_635m, - SEC_CURRENT_800m, -}; - -enum isl6423_curlim { - SEC_CURRENT_LIM_ON = 1, - SEC_CURRENT_LIM_OFF -}; - -struct isl6423_config { - enum isl6423_current current_max; - enum isl6423_curlim curlim; - u8 addr; - u8 mod_extern; -}; - -#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE)) - - -extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct isl6423_config *config); - -#else -static inline struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - const struct isl6423_config *config) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -#endif /* CONFIG_DVB_ISL6423 */ - -#endif /* __ISL_6423_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,401 +0,0 @@ -/* - * Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite" - * - * Copyright (c) 2007-8 Patrick Boettcher - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "itd1000.h" -#include "itd1000_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define deb(args...) do { \ - if (debug) { \ - printk(KERN_DEBUG "ITD1000: " args);\ - printk("\n"); \ - } \ -} while (0) - -#define warn(args...) do { \ - printk(KERN_WARNING "ITD1000: " args); \ - printk("\n"); \ -} while (0) - -#define info(args...) do { \ - printk(KERN_INFO "ITD1000: " args); \ - printk("\n"); \ -} while (0) - -/* don't write more than one byte with flexcop behind */ -static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 len) -{ - u8 buf[1+len]; - struct i2c_msg msg = { - .addr = state->cfg->i2c_address, .flags = 0, .buf = buf, .len = len+1 - }; - buf[0] = reg; - memcpy(&buf[1], v, len); - - /* deb("wr %02x: %02x", reg, v[0]); */ - - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "itd1000 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; -} - -static int itd1000_read_reg(struct itd1000_state *state, u8 reg) -{ - u8 val; - struct i2c_msg msg[2] = { - { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = &val, .len = 1 }, - }; - - /* ugly flexcop workaround */ - itd1000_write_regs(state, (reg - 1) & 0xff, &state->shadow[(reg - 1) & 0xff], 1); - - if (i2c_transfer(state->i2c, msg, 2) != 2) { - warn("itd1000 I2C read failed"); - return -EREMOTEIO; - } - return val; -} - -static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v) -{ - int ret = itd1000_write_regs(state, r, &v, 1); - state->shadow[r] = v; - return ret; -} - - -static struct { - u32 symbol_rate; - u8 pgaext : 4; /* PLLFH */ - u8 bbgvmin : 4; /* BBGVMIN */ -} itd1000_lpf_pga[] = { - { 0, 0x8, 0x3 }, - { 5200000, 0x8, 0x3 }, - { 12200000, 0x4, 0x3 }, - { 15400000, 0x2, 0x3 }, - { 19800000, 0x2, 0x3 }, - { 21500000, 0x2, 0x3 }, - { 24500000, 0x2, 0x3 }, - { 28400000, 0x2, 0x3 }, - { 33400000, 0x2, 0x3 }, - { 34400000, 0x1, 0x4 }, - { 34400000, 0x1, 0x4 }, - { 38400000, 0x1, 0x4 }, - { 38400000, 0x1, 0x4 }, - { 40400000, 0x1, 0x4 }, - { 45400000, 0x1, 0x4 }, -}; - -static void itd1000_set_lpf_bw(struct itd1000_state *state, u32 symbol_rate) -{ - u8 i; - u8 con1 = itd1000_read_reg(state, CON1) & 0xfd; - u8 pllfh = itd1000_read_reg(state, PLLFH) & 0x0f; - u8 bbgvmin = itd1000_read_reg(state, BBGVMIN) & 0xf0; - u8 bw = itd1000_read_reg(state, BW) & 0xf0; - - deb("symbol_rate = %d", symbol_rate); - - /* not sure what is that ? - starting to download the table */ - itd1000_write_reg(state, CON1, con1 | (1 << 1)); - - for (i = 0; i < ARRAY_SIZE(itd1000_lpf_pga); i++) - if (symbol_rate < itd1000_lpf_pga[i].symbol_rate) { - deb("symrate: index: %d pgaext: %x, bbgvmin: %x", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin); - itd1000_write_reg(state, PLLFH, pllfh | (itd1000_lpf_pga[i].pgaext << 4)); - itd1000_write_reg(state, BBGVMIN, bbgvmin | (itd1000_lpf_pga[i].bbgvmin)); - itd1000_write_reg(state, BW, bw | (i & 0x0f)); - break; - } - - itd1000_write_reg(state, CON1, con1 | (0 << 1)); -} - -static struct { - u8 vcorg; - u32 fmax_rg; -} itd1000_vcorg[] = { - { 1, 920000 }, - { 2, 971000 }, - { 3, 1031000 }, - { 4, 1091000 }, - { 5, 1171000 }, - { 6, 1281000 }, - { 7, 1381000 }, - { 8, 500000 }, /* this is intentional. */ - { 9, 1451000 }, - { 10, 1531000 }, - { 11, 1631000 }, - { 12, 1741000 }, - { 13, 1891000 }, - { 14, 2071000 }, - { 15, 2250000 }, -}; - -static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz) -{ - u8 i; - u8 gvbb_i2c = itd1000_read_reg(state, GVBB_I2C) & 0xbf; - u8 vco_chp1_i2c = itd1000_read_reg(state, VCO_CHP1_I2C) & 0x0f; - u8 adcout; - - /* reserved bit again (reset ?) */ - itd1000_write_reg(state, GVBB_I2C, gvbb_i2c | (1 << 6)); - - for (i = 0; i < ARRAY_SIZE(itd1000_vcorg); i++) { - if (freq_khz < itd1000_vcorg[i].fmax_rg) { - itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | (itd1000_vcorg[i].vcorg << 4)); - msleep(1); - - adcout = itd1000_read_reg(state, PLLLOCK) & 0x0f; - - deb("VCO: %dkHz: %d -> ADCOUT: %d %02x", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c); - - if (adcout > 13) { - if (!(itd1000_vcorg[i].vcorg == 7 || itd1000_vcorg[i].vcorg == 15)) - itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg + 1) << 4)); - } else if (adcout < 2) { - if (!(itd1000_vcorg[i].vcorg == 1 || itd1000_vcorg[i].vcorg == 9)) - itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg - 1) << 4)); - } - break; - } - } -} - -static const struct { - u32 freq; - u8 values[10]; /* RFTR, RFST1 - RFST9 */ -} itd1000_fre_values[] = { - { 1075000, { 0x59, 0x1d, 0x1c, 0x17, 0x16, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, - { 1250000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, - { 1450000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, - { 1650000, { 0x69, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, - { 1750000, { 0x69, 0x1e, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, - { 1850000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } }, - { 1900000, { 0x69, 0x1d, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } }, - { 1950000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0d, 0x0b, 0x0a } }, - { 2050000, { 0x69, 0x1e, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0b, 0x0a } }, - { 2150000, { 0x69, 0x1d, 0x1c, 0x17, 0x15, 0x14, 0x13, 0x0f, 0x0e, 0x0b } } -}; - - -#define FREF 16 - -static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz) -{ - int i, j; - u32 plln, pllf; - u64 tmp; - - plln = (freq_khz * 1000) / 2 / FREF; - - /* Compute the factional part times 1000 */ - tmp = plln % 1000000; - plln /= 1000000; - - tmp *= 1048576; - do_div(tmp, 1000000); - pllf = (u32) tmp; - - state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF; - deb("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d", freq_khz, state->frequency, pllf, plln); - - itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */; - itd1000_write_reg(state, PLLNL, plln & 0xff); - itd1000_write_reg(state, PLLFH, (itd1000_read_reg(state, PLLFH) & 0xf0) | ((pllf >> 16) & 0x0f)); - itd1000_write_reg(state, PLLFM, (pllf >> 8) & 0xff); - itd1000_write_reg(state, PLLFL, (pllf >> 0) & 0xff); - - for (i = 0; i < ARRAY_SIZE(itd1000_fre_values); i++) { - if (freq_khz <= itd1000_fre_values[i].freq) { - deb("fre_values: %d", i); - itd1000_write_reg(state, RFTR, itd1000_fre_values[i].values[0]); - for (j = 0; j < 9; j++) - itd1000_write_reg(state, RFST1+j, itd1000_fre_values[i].values[j+1]); - break; - } - } - - itd1000_set_vco(state, freq_khz); -} - -static int itd1000_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - struct itd1000_state *state = fe->tuner_priv; - u8 pllcon1; - - itd1000_set_lo(state, p->frequency); - itd1000_set_lpf_bw(state, p->u.qpsk.symbol_rate); - - pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f; - itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7)); - itd1000_write_reg(state, PLLCON1, pllcon1); - - return 0; -} - -static int itd1000_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct itd1000_state *state = fe->tuner_priv; - *frequency = state->frequency; - return 0; -} - -static int itd1000_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - return 0; -} - -static u8 itd1000_init_tab[][2] = { - { PLLCON1, 0x65 }, /* Register does not change */ - { PLLNH, 0x80 }, /* Bits [7:6] do not change */ - { RESERVED_0X6D, 0x3b }, - { VCO_CHP2_I2C, 0x12 }, - { 0x72, 0xf9 }, /* No such regsister defined */ - { RESERVED_0X73, 0xff }, - { RESERVED_0X74, 0xb2 }, - { RESERVED_0X75, 0xc7 }, - { EXTGVBBRF, 0xf0 }, - { DIVAGCCK, 0x80 }, - { BBTR, 0xa0 }, - { RESERVED_0X7E, 0x4f }, - { 0x82, 0x88 }, /* No such regsister defined */ - { 0x83, 0x80 }, /* No such regsister defined */ - { 0x84, 0x80 }, /* No such regsister defined */ - { RESERVED_0X85, 0x74 }, - { RESERVED_0X86, 0xff }, - { RESERVED_0X88, 0x02 }, - { RESERVED_0X89, 0x16 }, - { RFST0, 0x1f }, - { RESERVED_0X94, 0x66 }, - { RESERVED_0X95, 0x66 }, - { RESERVED_0X96, 0x77 }, - { RESERVED_0X97, 0x99 }, - { RESERVED_0X98, 0xff }, - { RESERVED_0X99, 0xfc }, - { RESERVED_0X9A, 0xba }, - { RESERVED_0X9B, 0xaa }, -}; - -static u8 itd1000_reinit_tab[][2] = { - { VCO_CHP1_I2C, 0x8a }, - { BW, 0x87 }, - { GVBB_I2C, 0x03 }, - { BBGVMIN, 0x03 }, - { CON1, 0x2e }, -}; - - -static int itd1000_init(struct dvb_frontend *fe) -{ - struct itd1000_state *state = fe->tuner_priv; - int i; - - for (i = 0; i < ARRAY_SIZE(itd1000_init_tab); i++) - itd1000_write_reg(state, itd1000_init_tab[i][0], itd1000_init_tab[i][1]); - - for (i = 0; i < ARRAY_SIZE(itd1000_reinit_tab); i++) - itd1000_write_reg(state, itd1000_reinit_tab[i][0], itd1000_reinit_tab[i][1]); - - return 0; -} - -static int itd1000_sleep(struct dvb_frontend *fe) -{ - return 0; -} - -static int itd1000_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops itd1000_tuner_ops = { - .info = { - .name = "Integrant ITD1000", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_step = 125, /* kHz for QPSK frontends */ - }, - - .release = itd1000_release, - - .init = itd1000_init, - .sleep = itd1000_sleep, - - .set_params = itd1000_set_parameters, - .get_frequency = itd1000_get_frequency, - .get_bandwidth = itd1000_get_bandwidth -}; - - -struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg) -{ - struct itd1000_state *state = NULL; - u8 i = 0; - - state = kzalloc(sizeof(struct itd1000_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->cfg = cfg; - state->i2c = i2c; - - i = itd1000_read_reg(state, 0); - if (i != 0) { - kfree(state); - return NULL; - } - info("successfully identified (ID: %d)", i); - - memset(state->shadow, 0xff, sizeof(state->shadow)); - for (i = 0x65; i < 0x9c; i++) - state->shadow[i] = itd1000_read_reg(state, i); - - memcpy(&fe->ops.tuner_ops, &itd1000_tuner_ops, sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = state; - - return fe; -} -EXPORT_SYMBOL(itd1000_attach); - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Integrant ITD1000 driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite" - * - * Copyright (c) 2007 Patrick Boettcher - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef ITD1000_H -#define ITD1000_H - -struct dvb_frontend; -struct i2c_adapter; - -struct itd1000_config { - u8 i2c_address; -}; - -#if defined(CONFIG_DVB_TUNER_ITD1000) || (defined(CONFIG_DVB_TUNER_ITD1000_MODULE) && defined(MODULE)) -extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg); -#else -static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/itd1000_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -/* - * Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite" - * - * Copyright (c) 2007 Patrick Boettcher - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef ITD1000_PRIV_H -#define ITD1000_PRIV_H - -struct itd1000_state { - struct itd1000_config *cfg; - struct i2c_adapter *i2c; - - u32 frequency; /* contains the value resulting from the LO-setting */ - - /* ugly workaround for flexcop's incapable i2c-controller - * FIXME, if possible - */ - u8 shadow[256]; -}; - -enum itd1000_register { - VCO_CHP1 = 0x65, - VCO_CHP2, - PLLCON1, - PLLNH, - PLLNL, - PLLFH, - PLLFM, - PLLFL, - RESERVED_0X6D, - PLLLOCK, - VCO_CHP2_I2C, - VCO_CHP1_I2C, - BW, - RESERVED_0X73 = 0x73, - RESERVED_0X74, - RESERVED_0X75, - GVBB, - GVRF, - GVBB_I2C, - EXTGVBBRF, - DIVAGCCK, - BBTR, - RFTR, - BBGVMIN, - RESERVED_0X7E, - RESERVED_0X85 = 0x85, - RESERVED_0X86, - CON1, - RESERVED_0X88, - RESERVED_0X89, - RFST0, - RFST1, - RFST2, - RFST3, - RFST4, - RFST5, - RFST6, - RFST7, - RFST8, - RFST9, - RESERVED_0X94, - RESERVED_0X95, - RESERVED_0X96, - RESERVED_0X97, - RESERVED_0X98, - RESERVED_0X99, - RESERVED_0X9A, - RESERVED_0X9B, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ix2505v.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ix2505v.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ix2505v.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ix2505v.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,323 +0,0 @@ -/** - * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner - * - * Copyright (C) 2010 Malcolm Priestley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2, as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include - -#include "ix2505v.h" - -static int ix2505v_debug; -#define dprintk(level, args...) do { \ - if (ix2505v_debug & level) \ - printk(KERN_DEBUG "ix2505v: " args); \ -} while (0) - -#define deb_info(args...) dprintk(0x01, args) -#define deb_i2c(args...) dprintk(0x02, args) - -struct ix2505v_state { - struct i2c_adapter *i2c; - const struct ix2505v_config *config; - u32 frequency; -}; - -/** - * Data read format of the Sharp IX2505V B0017 - * - * byte1: 1 | 1 | 0 | 0 | 0 | MA1 | MA0 | 1 - * byte2: POR | FL | RD2 | RD1 | RD0 | X | X | X - * - * byte1 = address - * byte2; - * POR = Power on Reset (VCC H=<2.2v L=>2.2v) - * FL = Phase Lock (H=lock L=unlock) - * RD0-2 = Reserved internal operations - * - * Only POR can be used to check the tuner is present - * - * Caution: after byte2 the I2C reverts to write mode continuing to read - * may corrupt tuning data. - * - */ - -static int ix2505v_read_status_reg(struct ix2505v_state *state) -{ - u8 addr = state->config->tuner_address; - u8 b2[] = {0}; - int ret; - - struct i2c_msg msg[1] = { - { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } - }; - - ret = i2c_transfer(state->i2c, msg, 1); - deb_i2c("Read %s ", __func__); - - return (ret == 1) ? (int) b2[0] : -1; -} - -static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count) -{ - struct i2c_msg msg[1] = { - { .addr = state->config->tuner_address, .flags = 0, - .buf = buf, .len = count }, - }; - - int ret; - - ret = i2c_transfer(state->i2c, msg, 1); - - if (ret != 1) { - deb_i2c("%s: i2c error, ret=%d\n", __func__, ret); - return -EIO; - } - - return 0; -} - -static int ix2505v_release(struct dvb_frontend *fe) -{ - struct ix2505v_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - - return 0; -} - -/** - * Data write format of the Sharp IX2505V B0017 - * - * byte1: 1 | 1 | 0 | 0 | 0 | 0(MA1)| 0(MA0)| 0 - * byte2: 0 | BG1 | BG2 | N8 | N7 | N6 | N5 | N4 - * byte3: N3 | N2 | N1 | A5 | A4 | A3 | A2 | A1 - * byte4: 1 | 1(C1) | 1(C0) | PD5 | PD4 | TM | 0(RTS)| 1(REF) - * byte5: BA2 | BA1 | BA0 | PSC | PD3 |PD2/TS2|DIV/TS1|PD0/TS0 - * - * byte1 = address - * - * Write order - * 1) byte1 -> byte2 -> byte3 -> byte4 -> byte5 - * 2) byte1 -> byte4 -> byte5 -> byte2 -> byte3 - * 3) byte1 -> byte2 -> byte3 -> byte4 - * 4) byte1 -> byte4 -> byte5 -> byte2 - * 5) byte1 -> byte2 -> byte3 - * 6) byte1 -> byte4 -> byte5 - * 7) byte1 -> byte2 - * 8) byte1 -> byte4 - * - * Recommended Setup - * 1 -> 8 -> 6 - */ - -static int ix2505v_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct ix2505v_state *state = fe->tuner_priv; - u32 frequency = params->frequency; - u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000; - u32 div_factor, N , A, x; - int ret = 0, len; - u8 gain, cc, ref, psc, local_osc, lpf; - u8 data[4] = {0}; - - if ((frequency < fe->ops.info.frequency_min) - || (frequency > fe->ops.info.frequency_max)) - return -EINVAL; - - if (state->config->tuner_gain) - gain = (state->config->tuner_gain < 4) - ? state->config->tuner_gain : 0; - else - gain = 0x0; - - if (state->config->tuner_chargepump) - cc = state->config->tuner_chargepump; - else - cc = 0x3; - - ref = 8; /* REF =1 */ - psc = 32; /* PSC = 0 */ - - div_factor = (frequency * ref) / 40; /* local osc = 4Mhz */ - x = div_factor / psc; - N = x/100; - A = ((x - (N * 100)) * psc) / 100; - - data[0] = ((gain & 0x3) << 5) | (N >> 3); - data[1] = (N << 5) | (A & 0x1f); - data[2] = 0x81 | ((cc & 0x3) << 5) ; /*PD5,PD4 & TM = 0|C1,C0|REF=1*/ - - deb_info("Frq=%d x=%d N=%d A=%d\n", frequency, x, N, A); - - if (frequency <= 1065000) - local_osc = (6 << 5) | 2; - else if (frequency <= 1170000) - local_osc = (7 << 5) | 2; - else if (frequency <= 1300000) - local_osc = (1 << 5); - else if (frequency <= 1445000) - local_osc = (2 << 5); - else if (frequency <= 1607000) - local_osc = (3 << 5); - else if (frequency <= 1778000) - local_osc = (4 << 5); - else if (frequency <= 1942000) - local_osc = (5 << 5); - else /*frequency up to 2150000*/ - local_osc = (6 << 5); - - data[3] = local_osc; /* all other bits set 0 */ - - if (b_w <= 10000) - lpf = 0xc; - else if (b_w <= 12000) - lpf = 0x2; - else if (b_w <= 14000) - lpf = 0xa; - else if (b_w <= 16000) - lpf = 0x6; - else if (b_w <= 18000) - lpf = 0xe; - else if (b_w <= 20000) - lpf = 0x1; - else if (b_w <= 22000) - lpf = 0x9; - else if (b_w <= 24000) - lpf = 0x5; - else if (b_w <= 26000) - lpf = 0xd; - else if (b_w <= 28000) - lpf = 0x3; - else - lpf = 0xb; - - deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf); - deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - len = sizeof(data); - - ret |= ix2505v_write(state, data, len); - - data[2] |= 0x4; /* set TM = 1 other bits same */ - - len = 1; - ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */ - - msleep(10); - - data[2] |= ((lpf >> 2) & 0x3) << 3; /* lpf */ - data[3] |= (lpf & 0x3) << 2; - - deb_info("Data 2=[%x%x]\n", data[2], data[3]); - - len = 2; - ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */ - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (state->config->min_delay_ms) - msleep(state->config->min_delay_ms); - - state->frequency = frequency; - - return ret; -} - -static int ix2505v_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct ix2505v_state *state = fe->tuner_priv; - - *frequency = state->frequency; - - return 0; -} - -static struct dvb_tuner_ops ix2505v_tuner_ops = { - .info = { - .name = "Sharp IX2505V (B0017)", - .frequency_min = 950000, - .frequency_max = 2175000 - }, - .release = ix2505v_release, - .set_params = ix2505v_set_params, - .get_frequency = ix2505v_get_frequency, -}; - -struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, - const struct ix2505v_config *config, - struct i2c_adapter *i2c) -{ - struct ix2505v_state *state = NULL; - int ret; - - if (NULL == config) { - deb_i2c("%s: no config ", __func__); - goto error; - } - - state = kzalloc(sizeof(struct ix2505v_state), GFP_KERNEL); - if (NULL == state) - return NULL; - - state->config = config; - state->i2c = i2c; - - if (state->config->tuner_write_only) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = ix2505v_read_status_reg(state); - - if (ret & 0x80) { - deb_i2c("%s: No IX2505V found\n", __func__); - goto error; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - fe->tuner_priv = state; - - memcpy(&fe->ops.tuner_ops, &ix2505v_tuner_ops, - sizeof(struct dvb_tuner_ops)); - deb_i2c("%s: initialization (%s addr=0x%02x) ok\n", - __func__, fe->ops.tuner_ops.info.name, config->tuner_address); - - return fe; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(ix2505v_attach); - -module_param_named(debug, ix2505v_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("DVB IX2505V tuner driver"); -MODULE_AUTHOR("Malcolm Priestley"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ix2505v.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ix2505v.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ix2505v.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ix2505v.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -/** - * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner - * - * Copyright (C) 2010 Malcolm Priestley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2, as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef DVB_IX2505V_H -#define DVB_IX2505V_H - -#include -#include "dvb_frontend.h" - -/** - * Attach a ix2505v tuner to the supplied frontend structure. - * - * @param fe Frontend to attach to. - * @param config ix2505v_config structure - * @return FE pointer on success, NULL on failure. - */ - -struct ix2505v_config { - u8 tuner_address; - - /*Baseband AMP gain control 0/1=0dB(default) 2=-2bB 3=-4dB */ - u8 tuner_gain; - - /*Charge pump output +/- 0=120 1=260 2=555 3=1200(default) */ - u8 tuner_chargepump; - - /* delay after tune */ - int min_delay_ms; - - /* disables reads*/ - u8 tuner_write_only; - -}; - -#if defined(CONFIG_DVB_IX2505V) || \ - (defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE)) -extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, - const struct ix2505v_config *config, struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, - const struct ix2505v_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* DVB_IX2505V_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,643 +0,0 @@ -config DVB_FE_CUSTOMISE - bool "Customise the frontend modules to build" - depends on DVB_CORE - default y if EXPERT - help - This allows the user to select/deselect frontend drivers for their - hardware from the build. - - Use this option with care as deselecting frontends which are in fact - necessary will result in DVB devices which cannot be tuned due to lack - of driver support. - - If unsure say N. - -menu "Customise DVB Frontends" - visible if DVB_FE_CUSTOMISE - -comment "Multistandard (satellite) frontends" - depends on DVB_CORE - -config DVB_STB0899 - tristate "STB0899 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want - to support this demodulator based frontends - -config DVB_STB6100 - tristate "STB6100 based tuners" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A Silicon tuner from ST used in conjunction with the STB0899 - demodulator. Say Y when you want to support this tuner. - -config DVB_STV090x - tristate "STV0900/STV0903(A/B) based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators. - Say Y when you want to support these frontends. - -config DVB_STV6110x - tristate "STV6110/(A) based tuners" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A Silicon tuner that supports DVB-S and DVB-S2 modes - -comment "DVB-S (satellite) frontends" - depends on DVB_CORE - -config DVB_CX24110 - tristate "Conexant CX24110 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_CX24123 - tristate "Conexant CX24123 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_MT312 - tristate "Zarlink VP310/MT312/ZL10313 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_ZL10036 - tristate "Zarlink ZL10036 silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_ZL10039 - tristate "Zarlink ZL10039 silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_S5H1420 - tristate "Samsung S5H1420 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_STV0288 - tristate "ST STV0288 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_STB6000 - tristate "ST STB6000 silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S silicon tuner module. Say Y when you want to support this tuner. - -config DVB_STV0299 - tristate "ST STV0299 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_STV6110 - tristate "ST STV6110 silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S silicon tuner module. Say Y when you want to support this tuner. - -config DVB_STV0900 - tristate "ST STV0900 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S/S2 demodulator. Say Y when you want to support this frontend. - -config DVB_TDA8083 - tristate "Philips TDA8083 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_TDA10086 - tristate "Philips TDA10086 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_TDA8261 - tristate "Philips TDA8261 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_VES1X93 - tristate "VLSI VES1893 or VES1993 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_TUNER_ITD1000 - tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_TUNER_CX24113 - tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - - -config DVB_TDA826X - tristate "Philips TDA826X silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TUA6100 - tristate "Infineon TUA6100 PLL" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S PLL chip. - -config DVB_CX24116 - tristate "Conexant CX24116 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S/S2 tuner module. Say Y when you want to support this frontend. - -config DVB_SI21XX - tristate "Silicon Labs SI21XX based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_DS3000 - tristate "Montage Tehnology DS3000 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S/S2 tuner module. Say Y when you want to support this frontend. - -config DVB_MB86A16 - tristate "Fujitsu MB86A16 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S/DSS Direct Conversion reveiver. - Say Y when you want to support this frontend. - -comment "DVB-T (terrestrial) frontends" - depends on DVB_CORE - -config DVB_SP8870 - tristate "Spase sp8870 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - - This driver needs external firmware. Please use the command - "/Documentation/dvb/get_dvb_firmware sp8870" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_SP887X - tristate "Spase sp887x based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - - This driver needs external firmware. Please use the command - "/Documentation/dvb/get_dvb_firmware sp887x" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_CX22700 - tristate "Conexant CX22700 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_CX22702 - tristate "Conexant cx22702 demodulator (OFDM)" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_S5H1432 - tristate "Samsung s5h1432 demodulator (OFDM)" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_DRX397XD - tristate "Micronas DRX3975D/DRX3977D based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - - TODO: - This driver needs external firmware. Please use the command - "/Documentation/dvb/get_dvb_firmware drx397xD" to - download/extract them, and then copy them to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_L64781 - tristate "LSI L64781" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_TDA1004X - tristate "Philips TDA10045H/TDA10046H based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware tda10045", - "/Documentation/dvb/get_dvb_firmware tda10046" to - download/extract them, and then copy them to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_NXT6000 - tristate "NxtWave Communications NXT6000 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_MT352 - tristate "Zarlink MT352 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_ZL10353 - tristate "Zarlink ZL10353 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_DIB3000MB - tristate "DiBcom 3000M-B" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_DIB3000MC - tristate "DiBcom 3000P/M-C" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_DIB7000M - tristate "DiBcom 7000MA/MB/PA/PB/MC" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_DIB7000P - tristate "DiBcom 7000PC" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_DIB9000 - tristate "DiBcom 9000" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_TDA10048 - tristate "Philips TDA10048HN based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_AF9013 - tristate "Afatech AF9013 demodulator" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - Say Y when you want to support this frontend. - -config DVB_EC100 - tristate "E3C EC100" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - Say Y when you want to support this frontend. - -config DVB_STV0367 - tristate "ST STV0367 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T/C tuner module. Say Y when you want to support this frontend. - -comment "DVB-C (cable) frontends" - depends on DVB_CORE - -config DVB_VES1820 - tristate "VLSI VES1820 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-C tuner module. Say Y when you want to support this frontend. - -config DVB_TDA10021 - tristate "Philips TDA10021 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-C tuner module. Say Y when you want to support this frontend. - -config DVB_TDA10023 - tristate "Philips TDA10023 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-C tuner module. Say Y when you want to support this frontend. - -config DVB_STV0297 - tristate "ST STV0297 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-C tuner module. Say Y when you want to support this frontend. - -comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends" - depends on DVB_CORE - -config DVB_NXT200X - tristate "NxtWave Communications NXT2002/NXT2004 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware nxt2002" and - "/Documentation/dvb/get_dvb_firmware nxt2004" to - download/extract them, and then copy them to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_OR51211 - tristate "Oren OR51211 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An ATSC 8VSB tuner module. Say Y when you want to support this frontend. - - This driver needs external firmware. Please use the command - "/Documentation/dvb/get_dvb_firmware or51211" to - download it, and then copy it to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_OR51132 - tristate "Oren OR51132 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or - "/Documentation/dvb/get_dvb_firmware or51132_qam" to - download firmwares for 8VSB and QAM64/256, respectively. Copy them to - /usr/lib/hotplug/firmware or /lib/firmware (depending on - configuration of firmware hotplug). - -config DVB_BCM3510 - tristate "Broadcom BCM3510" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to - support this frontend. - -config DVB_LGDT330X - tristate "LG Electronics LGDT3302/LGDT3303 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - -config DVB_LGDT3305 - tristate "LG Electronics LGDT3304 and LGDT3305 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - -config DVB_S5H1409 - tristate "Samsung S5H1409 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - -config DVB_AU8522 - tristate "Auvitek AU8522 based" - depends on DVB_CORE && I2C && VIDEO_V4L2 - default m if DVB_FE_CUSTOMISE - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - -config DVB_S5H1411 - tristate "Samsung S5H1411 based" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - -comment "ISDB-T (terrestrial) frontends" - depends on DVB_CORE - -config DVB_S921 - tristate "Sharp S921 frontend" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module. - Say Y when you want to support this frontend. - -config DVB_DIB8000 - tristate "DiBcom 8000MB/MC" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator. - Say Y when you want to support this frontend. - -config DVB_MB86A20S - tristate "Fujitsu mb86a20s" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator. - Say Y when you want to support this frontend. - -comment "Digital terrestrial only tuners/PLL" - depends on DVB_CORE - -config DVB_PLL - tristate "Generic I2C PLL based tuners" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - This module drives a number of tuners based on PLL chips with a - common I2C interface. Say Y when you want to support these tuners. - -config DVB_TUNER_DIB0070 - tristate "DiBcom DiB0070 silicon base-band tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon baseband tuner DiB0070 from DiBcom. - This device is only used inside a SiP called together with a - demodulator for now. - -config DVB_TUNER_DIB0090 - tristate "DiBcom DiB0090 silicon base-band tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon baseband tuner DiB0090 from DiBcom. - This device is only used inside a SiP called together with a - demodulator for now. - -comment "SEC control devices for DVB-S" - depends on DVB_CORE - -config DVB_LNBP21 - tristate "LNBP21/LNBH24 SEC controllers" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An SEC control chips. - -config DVB_ISL6405 - tristate "ISL6405 SEC controller" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An SEC control chip. - -config DVB_ISL6421 - tristate "ISL6421 SEC controller" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - An SEC control chip. - -config DVB_ISL6423 - tristate "ISL6423 SEC controller" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A SEC controller chip from Intersil - -config DVB_LGS8GL5 - tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DMB-TH tuner module. Say Y when you want to support this frontend. - -config DVB_LGS8GXX - tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator" - depends on DVB_CORE && I2C - select FW_LOADER - default m if DVB_FE_CUSTOMISE - help - A DMB-TH tuner module. Say Y when you want to support this frontend. - -config DVB_ATBM8830 - tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DMB-TH tuner module. Say Y when you want to support this frontend. - -config DVB_TDA665x - tristate "TDA665x tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - Support for tuner modules based on Philips TDA6650/TDA6651 chips. - Say Y when you want to support this chip. - - Currently supported tuners: - * Panasonic ENV57H12D5 (ET-50DT) - -config DVB_IX2505V - tristate "Sharp IX2505V silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -comment "Tools to develop new frontends" - -config DVB_DUMMY_FE - tristate "Dummy frontend driver" - default n -endmenu diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/l64781.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/l64781.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/l64781.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/l64781.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,602 +0,0 @@ -/* - driver for LSI L64781 COFDM demodulator - - Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH - Marko Kohtala - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "l64781.h" - - -struct l64781_state { - struct i2c_adapter* i2c; - const struct l64781_config* config; - struct dvb_frontend frontend; - - /* private demodulator data */ - unsigned int first:1; -}; - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "l64781: " args); \ - } while (0) - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - - -static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data) -{ - int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - - if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) - dprintk ("%s: write_reg error (reg == %02x) = %02x!\n", - __func__, reg, ret); - - return (ret != 1) ? -1 : 0; -} - -static int l64781_readreg (struct l64781_state* state, u8 reg) -{ - int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) return ret; - - return b1[0]; -} - -static void apply_tps (struct l64781_state* state) -{ - l64781_writereg (state, 0x2a, 0x00); - l64781_writereg (state, 0x2a, 0x01); - - /* This here is a little bit questionable because it enables - the automatic update of TPS registers. I think we'd need to - handle the IRQ from FE to update some other registers as - well, or at least implement some magic to tuning to correct - to the TPS received from transmission. */ - l64781_writereg (state, 0x2a, 0x02); -} - - -static void reset_afc (struct l64781_state* state) -{ - /* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for - timing offset */ - l64781_writereg (state, 0x07, 0x9e); /* stall AFC */ - l64781_writereg (state, 0x08, 0); /* AFC INIT FREQ */ - l64781_writereg (state, 0x09, 0); - l64781_writereg (state, 0x0a, 0); - l64781_writereg (state, 0x07, 0x8e); - l64781_writereg (state, 0x0e, 0); /* AGC gain to zero in beginning */ - l64781_writereg (state, 0x11, 0x80); /* stall TIM */ - l64781_writereg (state, 0x10, 0); /* TIM_OFFSET_LSB */ - l64781_writereg (state, 0x12, 0); - l64781_writereg (state, 0x13, 0); - l64781_writereg (state, 0x11, 0x00); -} - -static int reset_and_configure (struct l64781_state* state) -{ - u8 buf [] = { 0x06 }; - struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 }; - // NOTE: this is correct in writing to address 0x00 - - return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV; -} - -static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param) -{ - struct l64781_state* state = fe->demodulator_priv; - /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */ - static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 }; - /* QPSK, QAM_16, QAM_64 */ - static const u8 qam_tab [] = { 2, 4, 0, 6 }; - static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */ - static const u8 guard_tab [] = { 1, 2, 4, 8 }; - /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */ - static const u32 ppm = 8000; - struct dvb_ofdm_parameters *p = ¶m->u.ofdm; - u32 ddfs_offset_fixed; -/* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */ -/* bw_tab[p->bandWidth]<<10)/15625; */ - u32 init_freq; - u32 spi_bias; - u8 val0x04; - u8 val0x05; - u8 val0x06; - int bw = p->bandwidth - BANDWIDTH_8_MHZ; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - if (param->inversion != INVERSION_ON && - param->inversion != INVERSION_OFF) - return -EINVAL; - - if (bw < 0 || bw > 2) - return -EINVAL; - - if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 && - p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 && - p->code_rate_HP != FEC_7_8) - return -EINVAL; - - if (p->hierarchy_information != HIERARCHY_NONE && - (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 && - p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 && - p->code_rate_LP != FEC_7_8)) - return -EINVAL; - - if (p->constellation != QPSK && p->constellation != QAM_16 && - p->constellation != QAM_64) - return -EINVAL; - - if (p->transmission_mode != TRANSMISSION_MODE_2K && - p->transmission_mode != TRANSMISSION_MODE_8K) - return -EINVAL; - - if (p->guard_interval < GUARD_INTERVAL_1_32 || - p->guard_interval > GUARD_INTERVAL_1_4) - return -EINVAL; - - if (p->hierarchy_information < HIERARCHY_NONE || - p->hierarchy_information > HIERARCHY_4) - return -EINVAL; - - ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000; - - /* This works up to 20000 ppm, it overflows if too large ppm! */ - init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) / - bw_tab[p->bandwidth] & 0xFFFFFF); - - /* SPI bias calculation is slightly modified to fit in 32bit */ - /* will work for high ppm only... */ - spi_bias = 378 * (1 << 10); - spi_bias *= 16; - spi_bias *= bw_tab[p->bandwidth]; - spi_bias *= qam_tab[p->constellation]; - spi_bias /= p->code_rate_HP + 1; - spi_bias /= (guard_tab[p->guard_interval] + 32); - spi_bias *= 1000; - spi_bias /= 1000 + ppm/1000; - spi_bias *= p->code_rate_HP; - - val0x04 = (p->transmission_mode << 2) | p->guard_interval; - val0x05 = fec_tab[p->code_rate_HP]; - - if (p->hierarchy_information != HIERARCHY_NONE) - val0x05 |= (p->code_rate_LP - FEC_1_2) << 3; - - val0x06 = (p->hierarchy_information << 2) | p->constellation; - - l64781_writereg (state, 0x04, val0x04); - l64781_writereg (state, 0x05, val0x05); - l64781_writereg (state, 0x06, val0x06); - - reset_afc (state); - - /* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */ - l64781_writereg (state, 0x15, - p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3); - l64781_writereg (state, 0x16, init_freq & 0xff); - l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff); - l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff); - - l64781_writereg (state, 0x1b, spi_bias & 0xff); - l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff); - l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) | - (param->inversion == INVERSION_ON ? 0x80 : 0x00)); - - l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff); - l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f); - - l64781_readreg (state, 0x00); /* clear interrupt registers... */ - l64781_readreg (state, 0x01); /* dto. */ - - apply_tps (state); - - return 0; -} - -static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param) -{ - struct l64781_state* state = fe->demodulator_priv; - int tmp; - - - tmp = l64781_readreg(state, 0x04); - switch(tmp & 3) { - case 0: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; - break; - } - switch((tmp >> 2) & 3) { - case 0: - param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - break; - case 1: - param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - break; - default: - printk("Unexpected value for transmission_mode\n"); - } - - - - tmp = l64781_readreg(state, 0x05); - switch(tmp & 7) { - case 0: - param->u.ofdm.code_rate_HP = FEC_1_2; - break; - case 1: - param->u.ofdm.code_rate_HP = FEC_2_3; - break; - case 2: - param->u.ofdm.code_rate_HP = FEC_3_4; - break; - case 3: - param->u.ofdm.code_rate_HP = FEC_5_6; - break; - case 4: - param->u.ofdm.code_rate_HP = FEC_7_8; - break; - default: - printk("Unexpected value for code_rate_HP\n"); - } - switch((tmp >> 3) & 7) { - case 0: - param->u.ofdm.code_rate_LP = FEC_1_2; - break; - case 1: - param->u.ofdm.code_rate_LP = FEC_2_3; - break; - case 2: - param->u.ofdm.code_rate_LP = FEC_3_4; - break; - case 3: - param->u.ofdm.code_rate_LP = FEC_5_6; - break; - case 4: - param->u.ofdm.code_rate_LP = FEC_7_8; - break; - default: - printk("Unexpected value for code_rate_LP\n"); - } - - - tmp = l64781_readreg(state, 0x06); - switch(tmp & 3) { - case 0: - param->u.ofdm.constellation = QPSK; - break; - case 1: - param->u.ofdm.constellation = QAM_16; - break; - case 2: - param->u.ofdm.constellation = QAM_64; - break; - default: - printk("Unexpected value for constellation\n"); - } - switch((tmp >> 2) & 7) { - case 0: - param->u.ofdm.hierarchy_information = HIERARCHY_NONE; - break; - case 1: - param->u.ofdm.hierarchy_information = HIERARCHY_1; - break; - case 2: - param->u.ofdm.hierarchy_information = HIERARCHY_2; - break; - case 3: - param->u.ofdm.hierarchy_information = HIERARCHY_4; - break; - default: - printk("Unexpected value for hierarchy\n"); - } - - - tmp = l64781_readreg (state, 0x1d); - param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; - - tmp = (int) (l64781_readreg (state, 0x08) | - (l64781_readreg (state, 0x09) << 8) | - (l64781_readreg (state, 0x0a) << 16)); - param->frequency += tmp; - - return 0; -} - -static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct l64781_state* state = fe->demodulator_priv; - int sync = l64781_readreg (state, 0x32); - int gain = l64781_readreg (state, 0x0e); - - l64781_readreg (state, 0x00); /* clear interrupt registers... */ - l64781_readreg (state, 0x01); /* dto. */ - - *status = 0; - - if (gain > 5) - *status |= FE_HAS_SIGNAL; - - if (sync & 0x02) /* VCXO locked, this criteria should be ok */ - *status |= FE_HAS_CARRIER; - - if (sync & 0x20) - *status |= FE_HAS_VITERBI; - - if (sync & 0x40) - *status |= FE_HAS_SYNC; - - if (sync == 0x7f) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int l64781_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct l64781_state* state = fe->demodulator_priv; - - /* XXX FIXME: set up counting period (reg 0x26...0x28) - */ - *ber = l64781_readreg (state, 0x39) - | (l64781_readreg (state, 0x3a) << 8); - - return 0; -} - -static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) -{ - struct l64781_state* state = fe->demodulator_priv; - - u8 gain = l64781_readreg (state, 0x0e); - *signal_strength = (gain << 8) | gain; - - return 0; -} - -static int l64781_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct l64781_state* state = fe->demodulator_priv; - - u8 avg_quality = 0xff - l64781_readreg (state, 0x33); - *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/ - - return 0; -} - -static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct l64781_state* state = fe->demodulator_priv; - - *ucblocks = l64781_readreg (state, 0x37) - | (l64781_readreg (state, 0x38) << 8); - - return 0; -} - -static int l64781_sleep(struct dvb_frontend* fe) -{ - struct l64781_state* state = fe->demodulator_priv; - - /* Power down */ - return l64781_writereg (state, 0x3e, 0x5a); -} - -static int l64781_init(struct dvb_frontend* fe) -{ - struct l64781_state* state = fe->demodulator_priv; - - reset_and_configure (state); - - /* Power up */ - l64781_writereg (state, 0x3e, 0xa5); - - /* Reset hard */ - l64781_writereg (state, 0x2a, 0x04); - l64781_writereg (state, 0x2a, 0x00); - - /* Set tuner specific things */ - /* AFC_POL, set also in reset_afc */ - l64781_writereg (state, 0x07, 0x8e); - - /* Use internal ADC */ - l64781_writereg (state, 0x0b, 0x81); - - /* AGC loop gain, and polarity is positive */ - l64781_writereg (state, 0x0c, 0x84); - - /* Internal ADC outputs two's complement */ - l64781_writereg (state, 0x0d, 0x8c); - - /* With ppm=8000, it seems the DTR_SENSITIVITY will result in - value of 2 with all possible bandwidths and guard - intervals, which is the initial value anyway. */ - /*l64781_writereg (state, 0x19, 0x92);*/ - - /* Everything is two's complement, soft bit and CSI_OUT too */ - l64781_writereg (state, 0x1e, 0x09); - - /* delay a bit after first init attempt */ - if (state->first) { - state->first = 0; - msleep(200); - } - - return 0; -} - -static int l64781_get_tune_settings(struct dvb_frontend* fe, - struct dvb_frontend_tune_settings* fesettings) -{ - fesettings->min_delay_ms = 4000; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static void l64781_release(struct dvb_frontend* fe) -{ - struct l64781_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops l64781_ops; - -struct dvb_frontend* l64781_attach(const struct l64781_config* config, - struct i2c_adapter* i2c) -{ - struct l64781_state* state = NULL; - int reg0x3e = -1; - u8 b0 [] = { 0x1a }; - u8 b1 [] = { 0x00 }; - struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct l64781_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->first = 1; - - /** - * the L64781 won't show up before we send the reset_and_configure() - * broadcast. If nothing responds there is no L64781 on the bus... - */ - if (reset_and_configure(state) < 0) { - dprintk("No response to reset and configure broadcast...\n"); - goto error; - } - - /* The chip always responds to reads */ - if (i2c_transfer(state->i2c, msg, 2) != 2) { - dprintk("No response to read on I2C bus\n"); - goto error; - } - - /* Save current register contents for bailout */ - reg0x3e = l64781_readreg(state, 0x3e); - - /* Reading the POWER_DOWN register always returns 0 */ - if (reg0x3e != 0) { - dprintk("Device doesn't look like L64781\n"); - goto error; - } - - /* Turn the chip off */ - l64781_writereg (state, 0x3e, 0x5a); - - /* Responds to all reads with 0 */ - if (l64781_readreg(state, 0x1a) != 0) { - dprintk("Read 1 returned unexpcted value\n"); - goto error; - } - - /* Turn the chip on */ - l64781_writereg (state, 0x3e, 0xa5); - - /* Responds with register default value */ - if (l64781_readreg(state, 0x1a) != 0xa1) { - dprintk("Read 2 returned unexpcted value\n"); - goto error; - } - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - if (reg0x3e >= 0) - l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */ - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops l64781_ops = { - - .info = { - .name = "LSI L64781 DVB-T", - .type = FE_OFDM, - /* .frequency_min = ???,*/ - /* .frequency_max = ???,*/ - .frequency_stepsize = 166666, - /* .frequency_tolerance = ???,*/ - /* .symbol_rate_tolerance = ???,*/ - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_MUTE_TS - }, - - .release = l64781_release, - - .init = l64781_init, - .sleep = l64781_sleep, - - .set_frontend = apply_frontend_param, - .get_frontend = get_frontend, - .get_tune_settings = l64781_get_tune_settings, - - .read_status = l64781_read_status, - .read_ber = l64781_read_ber, - .read_signal_strength = l64781_read_signal_strength, - .read_snr = l64781_read_snr, - .read_ucblocks = l64781_read_ucblocks, -}; - -MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver"); -MODULE_AUTHOR("Holger Waechtler, Marko Kohtala"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(l64781_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/l64781.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/l64781.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/l64781.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/l64781.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - driver for LSI L64781 COFDM demodulator - - Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH - Marko Kohtala - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef L64781_H -#define L64781_H - -#include - -struct l64781_config -{ - /* the demodulator's i2c address */ - u8 demod_address; -}; - -#if defined(CONFIG_DVB_L64781) || (defined(CONFIG_DVB_L64781_MODULE) && defined(MODULE)) -extern struct dvb_frontend* l64781_attach(const struct l64781_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* l64781_attach(const struct l64781_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_L64781 - -#endif // L64781_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt3305.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt3305.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt3305.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt3305.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1221 +0,0 @@ -/* - * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM - * - * Copyright (C) 2008, 2009, 2010 Michael Krufky - * - * LGDT3304 support by Jarod Wilson - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include "dvb_math.h" -#include "lgdt3305.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); - -#define DBG_INFO 1 -#define DBG_REG 2 - -#define lg_printk(kern, fmt, arg...) \ - printk(kern "%s: " fmt, __func__, ##arg) - -#define lg_info(fmt, arg...) printk(KERN_INFO "lgdt3305: " fmt, ##arg) -#define lg_warn(fmt, arg...) lg_printk(KERN_WARNING, fmt, ##arg) -#define lg_err(fmt, arg...) lg_printk(KERN_ERR, fmt, ##arg) -#define lg_dbg(fmt, arg...) if (debug & DBG_INFO) \ - lg_printk(KERN_DEBUG, fmt, ##arg) -#define lg_reg(fmt, arg...) if (debug & DBG_REG) \ - lg_printk(KERN_DEBUG, fmt, ##arg) - -#define lg_fail(ret) \ -({ \ - int __ret; \ - __ret = (ret < 0); \ - if (__ret) \ - lg_err("error %d on line %d\n", ret, __LINE__); \ - __ret; \ -}) - -struct lgdt3305_state { - struct i2c_adapter *i2c_adap; - const struct lgdt3305_config *cfg; - - struct dvb_frontend frontend; - - fe_modulation_t current_modulation; - u32 current_frequency; - u32 snr; -}; - -/* ------------------------------------------------------------------------ */ - -/* FIXME: verify & document the LGDT3304 registers */ - -#define LGDT3305_GEN_CTRL_1 0x0000 -#define LGDT3305_GEN_CTRL_2 0x0001 -#define LGDT3305_GEN_CTRL_3 0x0002 -#define LGDT3305_GEN_STATUS 0x0003 -#define LGDT3305_GEN_CONTROL 0x0007 -#define LGDT3305_GEN_CTRL_4 0x000a -#define LGDT3305_DGTL_AGC_REF_1 0x0012 -#define LGDT3305_DGTL_AGC_REF_2 0x0013 -#define LGDT3305_CR_CTR_FREQ_1 0x0106 -#define LGDT3305_CR_CTR_FREQ_2 0x0107 -#define LGDT3305_CR_CTR_FREQ_3 0x0108 -#define LGDT3305_CR_CTR_FREQ_4 0x0109 -#define LGDT3305_CR_MSE_1 0x011b -#define LGDT3305_CR_MSE_2 0x011c -#define LGDT3305_CR_LOCK_STATUS 0x011d -#define LGDT3305_CR_CTRL_7 0x0126 -#define LGDT3305_AGC_POWER_REF_1 0x0300 -#define LGDT3305_AGC_POWER_REF_2 0x0301 -#define LGDT3305_AGC_DELAY_PT_1 0x0302 -#define LGDT3305_AGC_DELAY_PT_2 0x0303 -#define LGDT3305_RFAGC_LOOP_FLTR_BW_1 0x0306 -#define LGDT3305_RFAGC_LOOP_FLTR_BW_2 0x0307 -#define LGDT3305_IFBW_1 0x0308 -#define LGDT3305_IFBW_2 0x0309 -#define LGDT3305_AGC_CTRL_1 0x030c -#define LGDT3305_AGC_CTRL_4 0x0314 -#define LGDT3305_EQ_MSE_1 0x0413 -#define LGDT3305_EQ_MSE_2 0x0414 -#define LGDT3305_EQ_MSE_3 0x0415 -#define LGDT3305_PT_MSE_1 0x0417 -#define LGDT3305_PT_MSE_2 0x0418 -#define LGDT3305_PT_MSE_3 0x0419 -#define LGDT3305_FEC_BLOCK_CTRL 0x0504 -#define LGDT3305_FEC_LOCK_STATUS 0x050a -#define LGDT3305_FEC_PKT_ERR_1 0x050c -#define LGDT3305_FEC_PKT_ERR_2 0x050d -#define LGDT3305_TP_CTRL_1 0x050e -#define LGDT3305_BERT_PERIOD 0x0801 -#define LGDT3305_BERT_ERROR_COUNT_1 0x080a -#define LGDT3305_BERT_ERROR_COUNT_2 0x080b -#define LGDT3305_BERT_ERROR_COUNT_3 0x080c -#define LGDT3305_BERT_ERROR_COUNT_4 0x080d - -static int lgdt3305_write_reg(struct lgdt3305_state *state, u16 reg, u8 val) -{ - int ret; - u8 buf[] = { reg >> 8, reg & 0xff, val }; - struct i2c_msg msg = { - .addr = state->cfg->i2c_addr, .flags = 0, - .buf = buf, .len = 3, - }; - - lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val); - - ret = i2c_transfer(state->i2c_adap, &msg, 1); - - if (ret != 1) { - lg_err("error (addr %02x %02x <- %02x, err = %i)\n", - msg.buf[0], msg.buf[1], msg.buf[2], ret); - if (ret < 0) - return ret; - else - return -EREMOTEIO; - } - return 0; -} - -static int lgdt3305_read_reg(struct lgdt3305_state *state, u16 reg, u8 *val) -{ - int ret; - u8 reg_buf[] = { reg >> 8, reg & 0xff }; - struct i2c_msg msg[] = { - { .addr = state->cfg->i2c_addr, - .flags = 0, .buf = reg_buf, .len = 2 }, - { .addr = state->cfg->i2c_addr, - .flags = I2C_M_RD, .buf = val, .len = 1 }, - }; - - lg_reg("reg: 0x%04x\n", reg); - - ret = i2c_transfer(state->i2c_adap, msg, 2); - - if (ret != 2) { - lg_err("error (addr %02x reg %04x error (ret == %i)\n", - state->cfg->i2c_addr, reg, ret); - if (ret < 0) - return ret; - else - return -EREMOTEIO; - } - return 0; -} - -#define read_reg(state, reg) \ -({ \ - u8 __val; \ - int ret = lgdt3305_read_reg(state, reg, &__val); \ - if (lg_fail(ret)) \ - __val = 0; \ - __val; \ -}) - -static int lgdt3305_set_reg_bit(struct lgdt3305_state *state, - u16 reg, int bit, int onoff) -{ - u8 val; - int ret; - - lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff); - - ret = lgdt3305_read_reg(state, reg, &val); - if (lg_fail(ret)) - goto fail; - - val &= ~(1 << bit); - val |= (onoff & 1) << bit; - - ret = lgdt3305_write_reg(state, reg, val); -fail: - return ret; -} - -struct lgdt3305_reg { - u16 reg; - u8 val; -}; - -static int lgdt3305_write_regs(struct lgdt3305_state *state, - struct lgdt3305_reg *regs, int len) -{ - int i, ret; - - lg_reg("writing %d registers...\n", len); - - for (i = 0; i < len - 1; i++) { - ret = lgdt3305_write_reg(state, regs[i].reg, regs[i].val); - if (lg_fail(ret)) - return ret; - } - return 0; -} - -/* ------------------------------------------------------------------------ */ - -static int lgdt3305_soft_reset(struct lgdt3305_state *state) -{ - int ret; - - lg_dbg("\n"); - - ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 0); - if (lg_fail(ret)) - goto fail; - - msleep(20); - ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 1); -fail: - return ret; -} - -static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state, - enum lgdt3305_mpeg_mode mode) -{ - lg_dbg("(%d)\n", mode); - return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode); -} - -static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state, - enum lgdt3305_tp_clock_edge edge, - enum lgdt3305_tp_valid_polarity valid) -{ - u8 val; - int ret; - - lg_dbg("edge = %d, valid = %d\n", edge, valid); - - ret = lgdt3305_read_reg(state, LGDT3305_TP_CTRL_1, &val); - if (lg_fail(ret)) - goto fail; - - val &= ~0x09; - - if (edge) - val |= 0x08; - if (valid) - val |= 0x01; - - ret = lgdt3305_write_reg(state, LGDT3305_TP_CTRL_1, val); - if (lg_fail(ret)) - goto fail; - - ret = lgdt3305_soft_reset(state); -fail: - return ret; -} - -static int lgdt3305_set_modulation(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) -{ - u8 opermode; - int ret; - - lg_dbg("\n"); - - ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_1, &opermode); - if (lg_fail(ret)) - goto fail; - - opermode &= ~0x03; - - switch (param->u.vsb.modulation) { - case VSB_8: - opermode |= 0x03; - break; - case QAM_64: - opermode |= 0x00; - break; - case QAM_256: - opermode |= 0x01; - break; - default: - return -EINVAL; - } - ret = lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_1, opermode); -fail: - return ret; -} - -static int lgdt3305_set_filter_extension(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) -{ - int val; - - switch (param->u.vsb.modulation) { - case VSB_8: - val = 0; - break; - case QAM_64: - case QAM_256: - val = 1; - break; - default: - return -EINVAL; - } - lg_dbg("val = %d\n", val); - - return lgdt3305_set_reg_bit(state, 0x043f, 2, val); -} - -/* ------------------------------------------------------------------------ */ - -static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) -{ - u16 agc_ref; - - switch (param->u.vsb.modulation) { - case VSB_8: - agc_ref = 0x32c4; - break; - case QAM_64: - agc_ref = 0x2a00; - break; - case QAM_256: - agc_ref = 0x2a80; - break; - default: - return -EINVAL; - } - - lg_dbg("agc ref: 0x%04x\n", agc_ref); - - lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_1, agc_ref >> 8); - lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_2, agc_ref & 0xff); - - return 0; -} - -static int lgdt3305_rfagc_loop(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) -{ - u16 ifbw, rfbw, agcdelay; - - switch (param->u.vsb.modulation) { - case VSB_8: - agcdelay = 0x04c0; - rfbw = 0x8000; - ifbw = 0x8000; - break; - case QAM_64: - case QAM_256: - agcdelay = 0x046b; - rfbw = 0x8889; - /* FIXME: investigate optimal ifbw & rfbw values for the - * DT3304 and re-write this switch..case block */ - if (state->cfg->demod_chip == LGDT3304) - ifbw = 0x6666; - else /* (state->cfg->demod_chip == LGDT3305) */ - ifbw = 0x8888; - break; - default: - return -EINVAL; - } - - if (state->cfg->rf_agc_loop) { - lg_dbg("agcdelay: 0x%04x, rfbw: 0x%04x\n", agcdelay, rfbw); - - /* rf agc loop filter bandwidth */ - lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_1, - agcdelay >> 8); - lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_2, - agcdelay & 0xff); - - lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_1, - rfbw >> 8); - lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_2, - rfbw & 0xff); - } else { - lg_dbg("ifbw: 0x%04x\n", ifbw); - - /* if agc loop filter bandwidth */ - lgdt3305_write_reg(state, LGDT3305_IFBW_1, ifbw >> 8); - lgdt3305_write_reg(state, LGDT3305_IFBW_2, ifbw & 0xff); - } - - return 0; -} - -static int lgdt3305_agc_setup(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) -{ - int lockdten, acqen; - - switch (param->u.vsb.modulation) { - case VSB_8: - lockdten = 0; - acqen = 0; - break; - case QAM_64: - case QAM_256: - lockdten = 1; - acqen = 1; - break; - default: - return -EINVAL; - } - - lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen); - - /* control agc function */ - switch (state->cfg->demod_chip) { - case LGDT3304: - lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1); - lgdt3305_set_reg_bit(state, 0x030e, 2, acqen); - break; - case LGDT3305: - lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1); - lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen); - break; - default: - return -EINVAL; - } - - return lgdt3305_rfagc_loop(state, param); -} - -static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) -{ - u16 usref = 0; - - switch (param->u.vsb.modulation) { - case VSB_8: - if (state->cfg->usref_8vsb) - usref = state->cfg->usref_8vsb; - break; - case QAM_64: - if (state->cfg->usref_qam64) - usref = state->cfg->usref_qam64; - break; - case QAM_256: - if (state->cfg->usref_qam256) - usref = state->cfg->usref_qam256; - break; - default: - return -EINVAL; - } - - if (usref) { - lg_dbg("set manual mode: 0x%04x\n", usref); - - lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 3, 1); - - lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_1, - 0xff & (usref >> 8)); - lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_2, - 0xff & (usref >> 0)); - } - return 0; -} - -/* ------------------------------------------------------------------------ */ - -static int lgdt3305_spectral_inversion(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param, - int inversion) -{ - int ret; - - lg_dbg("(%d)\n", inversion); - - switch (param->u.vsb.modulation) { - case VSB_8: - ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7, - inversion ? 0xf9 : 0x79); - break; - case QAM_64: - case QAM_256: - ret = lgdt3305_write_reg(state, LGDT3305_FEC_BLOCK_CTRL, - inversion ? 0xfd : 0xff); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int lgdt3305_set_if(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) -{ - u16 if_freq_khz; - u8 nco1, nco2, nco3, nco4; - u64 nco; - - switch (param->u.vsb.modulation) { - case VSB_8: - if_freq_khz = state->cfg->vsb_if_khz; - break; - case QAM_64: - case QAM_256: - if_freq_khz = state->cfg->qam_if_khz; - break; - default: - return -EINVAL; - } - - nco = if_freq_khz / 10; - - switch (param->u.vsb.modulation) { - case VSB_8: - nco <<= 24; - do_div(nco, 625); - break; - case QAM_64: - case QAM_256: - nco <<= 28; - do_div(nco, 625); - break; - default: - return -EINVAL; - } - - nco1 = (nco >> 24) & 0x3f; - nco1 |= 0x40; - nco2 = (nco >> 16) & 0xff; - nco3 = (nco >> 8) & 0xff; - nco4 = nco & 0xff; - - lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, nco1); - lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, nco2); - lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, nco3); - lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, nco4); - - lg_dbg("%d KHz -> [%02x%02x%02x%02x]\n", - if_freq_khz, nco1, nco2, nco3, nco4); - - return 0; -} - -/* ------------------------------------------------------------------------ */ - -static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - - if (state->cfg->deny_i2c_rptr) - return 0; - - lg_dbg("(%d)\n", enable); - - return lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_2, 5, - enable ? 0 : 1); -} - -static int lgdt3305_sleep(struct dvb_frontend *fe) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - u8 gen_ctrl_3, gen_ctrl_4; - - lg_dbg("\n"); - - gen_ctrl_3 = read_reg(state, LGDT3305_GEN_CTRL_3); - gen_ctrl_4 = read_reg(state, LGDT3305_GEN_CTRL_4); - - /* hold in software reset while sleeping */ - gen_ctrl_3 &= ~0x01; - /* tristate the IF-AGC pin */ - gen_ctrl_3 |= 0x02; - /* tristate the RF-AGC pin */ - gen_ctrl_3 |= 0x04; - - /* disable vsb/qam module */ - gen_ctrl_4 &= ~0x01; - /* disable adc module */ - gen_ctrl_4 &= ~0x02; - - lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_3, gen_ctrl_3); - lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_4, gen_ctrl_4); - - return 0; -} - -static int lgdt3305_init(struct dvb_frontend *fe) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - int ret; - - static struct lgdt3305_reg lgdt3304_init_data[] = { - { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, }, - { .reg = 0x000d, .val = 0x02, }, - { .reg = 0x000e, .val = 0x02, }, - { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, }, - { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, }, - { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, }, - { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, }, - { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, }, - { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, }, - { .reg = LGDT3305_CR_CTRL_7, .val = 0xf9, }, - { .reg = 0x0112, .val = 0x17, }, - { .reg = 0x0113, .val = 0x15, }, - { .reg = 0x0114, .val = 0x18, }, - { .reg = 0x0115, .val = 0xff, }, - { .reg = 0x0116, .val = 0x3c, }, - { .reg = 0x0214, .val = 0x67, }, - { .reg = 0x0424, .val = 0x8d, }, - { .reg = 0x0427, .val = 0x12, }, - { .reg = 0x0428, .val = 0x4f, }, - { .reg = LGDT3305_IFBW_1, .val = 0x80, }, - { .reg = LGDT3305_IFBW_2, .val = 0x00, }, - { .reg = 0x030a, .val = 0x08, }, - { .reg = 0x030b, .val = 0x9b, }, - { .reg = 0x030d, .val = 0x00, }, - { .reg = 0x030e, .val = 0x1c, }, - { .reg = 0x0314, .val = 0xe1, }, - { .reg = 0x000d, .val = 0x82, }, - { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, }, - { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, }, - }; - - static struct lgdt3305_reg lgdt3305_init_data[] = { - { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, }, - { .reg = LGDT3305_GEN_CTRL_2, .val = 0xb0, }, - { .reg = LGDT3305_GEN_CTRL_3, .val = 0x01, }, - { .reg = LGDT3305_GEN_CONTROL, .val = 0x6f, }, - { .reg = LGDT3305_GEN_CTRL_4, .val = 0x03, }, - { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, }, - { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, }, - { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, }, - { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, }, - { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, }, - { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, }, - { .reg = LGDT3305_CR_CTRL_7, .val = 0x79, }, - { .reg = LGDT3305_AGC_POWER_REF_1, .val = 0x32, }, - { .reg = LGDT3305_AGC_POWER_REF_2, .val = 0xc4, }, - { .reg = LGDT3305_AGC_DELAY_PT_1, .val = 0x0d, }, - { .reg = LGDT3305_AGC_DELAY_PT_2, .val = 0x30, }, - { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, }, - { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, }, - { .reg = LGDT3305_IFBW_1, .val = 0x80, }, - { .reg = LGDT3305_IFBW_2, .val = 0x00, }, - { .reg = LGDT3305_AGC_CTRL_1, .val = 0x30, }, - { .reg = LGDT3305_AGC_CTRL_4, .val = 0x61, }, - { .reg = LGDT3305_FEC_BLOCK_CTRL, .val = 0xff, }, - { .reg = LGDT3305_TP_CTRL_1, .val = 0x1b, }, - }; - - lg_dbg("\n"); - - switch (state->cfg->demod_chip) { - case LGDT3304: - ret = lgdt3305_write_regs(state, lgdt3304_init_data, - ARRAY_SIZE(lgdt3304_init_data)); - break; - case LGDT3305: - ret = lgdt3305_write_regs(state, lgdt3305_init_data, - ARRAY_SIZE(lgdt3305_init_data)); - break; - default: - ret = -EINVAL; - } - if (lg_fail(ret)) - goto fail; - - ret = lgdt3305_soft_reset(state); -fail: - return ret; -} - -static int lgdt3304_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - int ret; - - lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); - - if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - if (lg_fail(ret)) - goto fail; - state->current_frequency = param->frequency; - } - - ret = lgdt3305_set_modulation(state, param); - if (lg_fail(ret)) - goto fail; - - ret = lgdt3305_passband_digital_agc(state, param); - if (lg_fail(ret)) - goto fail; - - ret = lgdt3305_agc_setup(state, param); - if (lg_fail(ret)) - goto fail; - - /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */ - switch (param->u.vsb.modulation) { - case VSB_8: - lgdt3305_write_reg(state, 0x030d, 0x00); - lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f); - lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c); - lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac); - lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba); - break; - case QAM_64: - case QAM_256: - lgdt3305_write_reg(state, 0x030d, 0x14); - ret = lgdt3305_set_if(state, param); - if (lg_fail(ret)) - goto fail; - break; - default: - return -EINVAL; - } - - - ret = lgdt3305_spectral_inversion(state, param, - state->cfg->spectral_inversion - ? 1 : 0); - if (lg_fail(ret)) - goto fail; - - state->current_modulation = param->u.vsb.modulation; - - ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); - if (lg_fail(ret)) - goto fail; - - /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */ - ret = lgdt3305_mpeg_mode_polarity(state, - state->cfg->tpclk_edge, - state->cfg->tpvalid_polarity); -fail: - return ret; -} - -static int lgdt3305_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - int ret; - - lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); - - if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - if (lg_fail(ret)) - goto fail; - state->current_frequency = param->frequency; - } - - ret = lgdt3305_set_modulation(state, param); - if (lg_fail(ret)) - goto fail; - - ret = lgdt3305_passband_digital_agc(state, param); - if (lg_fail(ret)) - goto fail; - ret = lgdt3305_set_agc_power_ref(state, param); - if (lg_fail(ret)) - goto fail; - ret = lgdt3305_agc_setup(state, param); - if (lg_fail(ret)) - goto fail; - - /* low if */ - ret = lgdt3305_write_reg(state, LGDT3305_GEN_CONTROL, 0x2f); - if (lg_fail(ret)) - goto fail; - ret = lgdt3305_set_reg_bit(state, LGDT3305_CR_CTR_FREQ_1, 6, 1); - if (lg_fail(ret)) - goto fail; - - ret = lgdt3305_set_if(state, param); - if (lg_fail(ret)) - goto fail; - ret = lgdt3305_spectral_inversion(state, param, - state->cfg->spectral_inversion - ? 1 : 0); - if (lg_fail(ret)) - goto fail; - - ret = lgdt3305_set_filter_extension(state, param); - if (lg_fail(ret)) - goto fail; - - state->current_modulation = param->u.vsb.modulation; - - ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); - if (lg_fail(ret)) - goto fail; - - /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */ - ret = lgdt3305_mpeg_mode_polarity(state, - state->cfg->tpclk_edge, - state->cfg->tpvalid_polarity); -fail: - return ret; -} - -static int lgdt3305_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - - lg_dbg("\n"); - - param->u.vsb.modulation = state->current_modulation; - param->frequency = state->current_frequency; - return 0; -} - -/* ------------------------------------------------------------------------ */ - -static int lgdt3305_read_cr_lock_status(struct lgdt3305_state *state, - int *locked) -{ - u8 val; - int ret; - char *cr_lock_state = ""; - - *locked = 0; - - ret = lgdt3305_read_reg(state, LGDT3305_CR_LOCK_STATUS, &val); - if (lg_fail(ret)) - goto fail; - - switch (state->current_modulation) { - case QAM_256: - case QAM_64: - if (val & (1 << 1)) - *locked = 1; - - switch (val & 0x07) { - case 0: - cr_lock_state = "QAM UNLOCK"; - break; - case 4: - cr_lock_state = "QAM 1stLock"; - break; - case 6: - cr_lock_state = "QAM 2ndLock"; - break; - case 7: - cr_lock_state = "QAM FinalLock"; - break; - default: - cr_lock_state = "CLOCKQAM-INVALID!"; - break; - } - break; - case VSB_8: - if (val & (1 << 7)) { - *locked = 1; - cr_lock_state = "CLOCKVSB"; - } - break; - default: - ret = -EINVAL; - } - lg_dbg("(%d) %s\n", *locked, cr_lock_state); -fail: - return ret; -} - -static int lgdt3305_read_fec_lock_status(struct lgdt3305_state *state, - int *locked) -{ - u8 val; - int ret, mpeg_lock, fec_lock, viterbi_lock; - - *locked = 0; - - switch (state->current_modulation) { - case QAM_256: - case QAM_64: - ret = lgdt3305_read_reg(state, - LGDT3305_FEC_LOCK_STATUS, &val); - if (lg_fail(ret)) - goto fail; - - mpeg_lock = (val & (1 << 0)) ? 1 : 0; - fec_lock = (val & (1 << 2)) ? 1 : 0; - viterbi_lock = (val & (1 << 3)) ? 1 : 0; - - *locked = mpeg_lock && fec_lock && viterbi_lock; - - lg_dbg("(%d) %s%s%s\n", *locked, - mpeg_lock ? "mpeg lock " : "", - fec_lock ? "fec lock " : "", - viterbi_lock ? "viterbi lock" : ""); - break; - case VSB_8: - default: - ret = -EINVAL; - } -fail: - return ret; -} - -static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - u8 val; - int ret, signal, inlock, nofecerr, snrgood, - cr_lock, fec_lock, sync_lock; - - *status = 0; - - ret = lgdt3305_read_reg(state, LGDT3305_GEN_STATUS, &val); - if (lg_fail(ret)) - goto fail; - - signal = (val & (1 << 4)) ? 1 : 0; - inlock = (val & (1 << 3)) ? 0 : 1; - sync_lock = (val & (1 << 2)) ? 1 : 0; - nofecerr = (val & (1 << 1)) ? 1 : 0; - snrgood = (val & (1 << 0)) ? 1 : 0; - - lg_dbg("%s%s%s%s%s\n", - signal ? "SIGNALEXIST " : "", - inlock ? "INLOCK " : "", - sync_lock ? "SYNCLOCK " : "", - nofecerr ? "NOFECERR " : "", - snrgood ? "SNRGOOD " : ""); - - ret = lgdt3305_read_cr_lock_status(state, &cr_lock); - if (lg_fail(ret)) - goto fail; - - if (signal) - *status |= FE_HAS_SIGNAL; - if (cr_lock) - *status |= FE_HAS_CARRIER; - if (nofecerr) - *status |= FE_HAS_VITERBI; - if (sync_lock) - *status |= FE_HAS_SYNC; - - switch (state->current_modulation) { - case QAM_256: - case QAM_64: - /* signal bit is unreliable on the DT3304 in QAM mode */ - if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock)) - *status |= FE_HAS_SIGNAL; - - ret = lgdt3305_read_fec_lock_status(state, &fec_lock); - if (lg_fail(ret)) - goto fail; - - if (fec_lock) - *status |= FE_HAS_LOCK; - break; - case VSB_8: - if (inlock) - *status |= FE_HAS_LOCK; - break; - default: - ret = -EINVAL; - } -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -/* borrowed from lgdt330x.c */ -static u32 calculate_snr(u32 mse, u32 c) -{ - if (mse == 0) /* no signal */ - return 0; - - mse = intlog10(mse); - if (mse > c) { - /* Negative SNR, which is possible, but realisticly the - demod will lose lock before the signal gets this bad. The - API only allows for unsigned values, so just return 0 */ - return 0; - } - return 10*(c - mse); -} - -static int lgdt3305_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - u32 noise; /* noise value */ - u32 c; /* per-modulation SNR calculation constant */ - - switch (state->current_modulation) { - case VSB_8: -#ifdef USE_PTMSE - /* Use Phase Tracker Mean-Square Error Register */ - /* SNR for ranges from -13.11 to +44.08 */ - noise = ((read_reg(state, LGDT3305_PT_MSE_1) & 0x07) << 16) | - (read_reg(state, LGDT3305_PT_MSE_2) << 8) | - (read_reg(state, LGDT3305_PT_MSE_3) & 0xff); - c = 73957994; /* log10(25*32^2)*2^24 */ -#else - /* Use Equalizer Mean-Square Error Register */ - /* SNR for ranges from -16.12 to +44.08 */ - noise = ((read_reg(state, LGDT3305_EQ_MSE_1) & 0x0f) << 16) | - (read_reg(state, LGDT3305_EQ_MSE_2) << 8) | - (read_reg(state, LGDT3305_EQ_MSE_3) & 0xff); - c = 73957994; /* log10(25*32^2)*2^24 */ -#endif - break; - case QAM_64: - case QAM_256: - noise = (read_reg(state, LGDT3305_CR_MSE_1) << 8) | - (read_reg(state, LGDT3305_CR_MSE_2) & 0xff); - - c = (state->current_modulation == QAM_64) ? - 97939837 : 98026066; - /* log10(688128)*2^24 and log10(696320)*2^24 */ - break; - default: - return -EINVAL; - } - state->snr = calculate_snr(noise, c); - /* report SNR in dB * 10 */ - *snr = (state->snr / ((1 << 24) / 10)); - lg_dbg("noise = 0x%08x, snr = %d.%02d dB\n", noise, - state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); - - return 0; -} - -static int lgdt3305_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - /* borrowed from lgdt330x.c - * - * Calculate strength from SNR up to 35dB - * Even though the SNR can go higher than 35dB, - * there is some comfort factor in having a range of - * strong signals that can show at 100% - */ - struct lgdt3305_state *state = fe->demodulator_priv; - u16 snr; - int ret; - - *strength = 0; - - ret = fe->ops.read_snr(fe, &snr); - if (lg_fail(ret)) - goto fail; - /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ - /* scale the range 0 - 35*2^24 into 0 - 65535 */ - if (state->snr >= 8960 * 0x10000) - *strength = 0xffff; - else - *strength = state->snr / 8960; -fail: - return ret; -} - -/* ------------------------------------------------------------------------ */ - -static int lgdt3305_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - *ber = 0; - return 0; -} - -static int lgdt3305_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - - *ucblocks = - (read_reg(state, LGDT3305_FEC_PKT_ERR_1) << 8) | - (read_reg(state, LGDT3305_FEC_PKT_ERR_2) & 0xff); - - return 0; -} - -static int lgdt3305_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings - *fe_tune_settings) -{ - fe_tune_settings->min_delay_ms = 500; - lg_dbg("\n"); - return 0; -} - -static void lgdt3305_release(struct dvb_frontend *fe) -{ - struct lgdt3305_state *state = fe->demodulator_priv; - lg_dbg("\n"); - kfree(state); -} - -static struct dvb_frontend_ops lgdt3304_ops; -static struct dvb_frontend_ops lgdt3305_ops; - -struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, - struct i2c_adapter *i2c_adap) -{ - struct lgdt3305_state *state = NULL; - int ret; - u8 val; - - lg_dbg("(%d-%04x)\n", - i2c_adap ? i2c_adapter_id(i2c_adap) : 0, - config ? config->i2c_addr : 0); - - state = kzalloc(sizeof(struct lgdt3305_state), GFP_KERNEL); - if (state == NULL) - goto fail; - - state->cfg = config; - state->i2c_adap = i2c_adap; - - switch (config->demod_chip) { - case LGDT3304: - memcpy(&state->frontend.ops, &lgdt3304_ops, - sizeof(struct dvb_frontend_ops)); - break; - case LGDT3305: - memcpy(&state->frontend.ops, &lgdt3305_ops, - sizeof(struct dvb_frontend_ops)); - break; - default: - goto fail; - } - state->frontend.demodulator_priv = state; - - /* verify that we're talking to a lg dt3304/5 */ - ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val); - if ((lg_fail(ret)) | (val == 0)) - goto fail; - ret = lgdt3305_write_reg(state, 0x0808, 0x80); - if (lg_fail(ret)) - goto fail; - ret = lgdt3305_read_reg(state, 0x0808, &val); - if ((lg_fail(ret)) | (val != 0x80)) - goto fail; - ret = lgdt3305_write_reg(state, 0x0808, 0x00); - if (lg_fail(ret)) - goto fail; - - state->current_frequency = -1; - state->current_modulation = -1; - - return &state->frontend; -fail: - lg_warn("unable to detect %s hardware\n", - config->demod_chip ? "LGDT3304" : "LGDT3305"); - kfree(state); - return NULL; -} -EXPORT_SYMBOL(lgdt3305_attach); - -static struct dvb_frontend_ops lgdt3304_ops = { - .info = { - .name = "LG Electronics LGDT3304 VSB/QAM Frontend", - .type = FE_ATSC, - .frequency_min = 54000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl, - .init = lgdt3305_init, - .set_frontend = lgdt3304_set_parameters, - .get_frontend = lgdt3305_get_frontend, - .get_tune_settings = lgdt3305_get_tune_settings, - .read_status = lgdt3305_read_status, - .read_ber = lgdt3305_read_ber, - .read_signal_strength = lgdt3305_read_signal_strength, - .read_snr = lgdt3305_read_snr, - .read_ucblocks = lgdt3305_read_ucblocks, - .release = lgdt3305_release, -}; - -static struct dvb_frontend_ops lgdt3305_ops = { - .info = { - .name = "LG Electronics LGDT3305 VSB/QAM Frontend", - .type = FE_ATSC, - .frequency_min = 54000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl, - .init = lgdt3305_init, - .sleep = lgdt3305_sleep, - .set_frontend = lgdt3305_set_parameters, - .get_frontend = lgdt3305_get_frontend, - .get_tune_settings = lgdt3305_get_tune_settings, - .read_status = lgdt3305_read_status, - .read_ber = lgdt3305_read_ber, - .read_signal_strength = lgdt3305_read_signal_strength, - .read_snr = lgdt3305_read_snr, - .read_ucblocks = lgdt3305_read_ucblocks, - .release = lgdt3305_release, -}; - -MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt3305.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt3305.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt3305.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt3305.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -/* - * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM - * - * Copyright (C) 2008, 2009, 2010 Michael Krufky - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _LGDT3305_H_ -#define _LGDT3305_H_ - -#include -#include "dvb_frontend.h" - - -enum lgdt3305_mpeg_mode { - LGDT3305_MPEG_PARALLEL = 0, - LGDT3305_MPEG_SERIAL = 1, -}; - -enum lgdt3305_tp_clock_edge { - LGDT3305_TPCLK_RISING_EDGE = 0, - LGDT3305_TPCLK_FALLING_EDGE = 1, -}; - -enum lgdt3305_tp_valid_polarity { - LGDT3305_TP_VALID_LOW = 0, - LGDT3305_TP_VALID_HIGH = 1, -}; - -enum lgdt_demod_chip_type { - LGDT3305 = 0, - LGDT3304 = 1, -}; - -struct lgdt3305_config { - u8 i2c_addr; - - /* user defined IF frequency in KHz */ - u16 qam_if_khz; - u16 vsb_if_khz; - - /* AGC Power reference - defaults are used if left unset */ - u16 usref_8vsb; /* default: 0x32c4 */ - u16 usref_qam64; /* default: 0x5400 */ - u16 usref_qam256; /* default: 0x2a80 */ - - /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */ - unsigned int deny_i2c_rptr:1; - - /* spectral inversion - 0:disabled 1:enabled */ - unsigned int spectral_inversion:1; - - /* use RF AGC loop - 0:disabled 1:enabled */ - unsigned int rf_agc_loop:1; - - enum lgdt3305_mpeg_mode mpeg_mode; - enum lgdt3305_tp_clock_edge tpclk_edge; - enum lgdt3305_tp_valid_polarity tpvalid_polarity; - enum lgdt_demod_chip_type demod_chip; -}; - -#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \ - defined(MODULE)) -extern -struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, - struct i2c_adapter *i2c_adap); -#else -static inline -struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, - struct i2c_adapter *i2c_adap) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_LGDT3305 */ - -#endif /* _LGDT3305_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,820 +0,0 @@ -/* - * Support for LGDT3302 and LGDT3303 - VSB/QAM - * - * Copyright (C) 2005 Wilson Michaels - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* - * NOTES ABOUT THIS DRIVER - * - * This Linux driver supports: - * DViCO FusionHDTV 3 Gold-Q - * DViCO FusionHDTV 3 Gold-T - * DViCO FusionHDTV 5 Gold - * DViCO FusionHDTV 5 Lite - * DViCO FusionHDTV 5 USB Gold - * Air2PC/AirStar 2 ATSC 3rd generation (HD5000) - * pcHDTV HD5500 - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvb_math.h" -#include "lgdt330x_priv.h" -#include "lgdt330x.h" - -/* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */ -/* #define USE_EQMSE */ - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off)."); -#define dprintk(args...) \ -do { \ -if (debug) printk(KERN_DEBUG "lgdt330x: " args); \ -} while (0) - -struct lgdt330x_state -{ - struct i2c_adapter* i2c; - - /* Configuration settings */ - const struct lgdt330x_config* config; - - struct dvb_frontend frontend; - - /* Demodulator private data */ - fe_modulation_t current_modulation; - u32 snr; /* Result of last SNR calculation */ - - /* Tuner private data */ - u32 current_frequency; -}; - -static int i2c_write_demod_bytes (struct lgdt330x_state* state, - u8 *buf, /* data bytes to send */ - int len /* number of bytes to send */ ) -{ - struct i2c_msg msg = - { .addr = state->config->demod_address, - .flags = 0, - .buf = buf, - .len = 2 }; - int i; - int err; - - for (i=0; ii2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __func__, msg.buf[0], msg.buf[1], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - msg.buf += 2; - } - return 0; -} - -/* - * This routine writes the register (reg) to the demod bus - * then reads the data returned for (len) bytes. - */ - -static u8 i2c_read_demod_bytes (struct lgdt330x_state* state, - enum I2C_REG reg, u8* buf, int len) -{ - u8 wr [] = { reg }; - struct i2c_msg msg [] = { - { .addr = state->config->demod_address, - .flags = 0, .buf = wr, .len = 1 }, - { .addr = state->config->demod_address, - .flags = I2C_M_RD, .buf = buf, .len = len }, - }; - int ret; - ret = i2c_transfer(state->i2c, msg, 2); - if (ret != 2) { - printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret); - } else { - ret = 0; - } - return ret; -} - -/* Software reset */ -static int lgdt3302_SwReset(struct lgdt330x_state* state) -{ - u8 ret; - u8 reset[] = { - IRQ_MASK, - 0x00 /* bit 6 is active low software reset - * bits 5-0 are 1 to mask interrupts */ - }; - - ret = i2c_write_demod_bytes(state, - reset, sizeof(reset)); - if (ret == 0) { - - /* force reset high (inactive) and unmask interrupts */ - reset[1] = 0x7f; - ret = i2c_write_demod_bytes(state, - reset, sizeof(reset)); - } - return ret; -} - -static int lgdt3303_SwReset(struct lgdt330x_state* state) -{ - u8 ret; - u8 reset[] = { - 0x02, - 0x00 /* bit 0 is active low software reset */ - }; - - ret = i2c_write_demod_bytes(state, - reset, sizeof(reset)); - if (ret == 0) { - - /* force reset high (inactive) */ - reset[1] = 0x01; - ret = i2c_write_demod_bytes(state, - reset, sizeof(reset)); - } - return ret; -} - -static int lgdt330x_SwReset(struct lgdt330x_state* state) -{ - switch (state->config->demod_chip) { - case LGDT3302: - return lgdt3302_SwReset(state); - case LGDT3303: - return lgdt3303_SwReset(state); - default: - return -ENODEV; - } -} - -static int lgdt330x_init(struct dvb_frontend* fe) -{ - /* Hardware reset is done using gpio[0] of cx23880x chip. - * I'd like to do it here, but don't know how to find chip address. - * cx88-cards.c arranges for the reset bit to be inactive (high). - * Maybe there needs to be a callable function in cx88-core or - * the caller of this function needs to do it. */ - - /* - * Array of byte pairs - * to initialize each different chip - */ - static u8 lgdt3302_init_data[] = { - /* Use 50MHz parameter values from spec sheet since xtal is 50 */ - /* Change the value of NCOCTFV[25:0] of carrier - recovery center frequency register */ - VSB_CARRIER_FREQ0, 0x00, - VSB_CARRIER_FREQ1, 0x87, - VSB_CARRIER_FREQ2, 0x8e, - VSB_CARRIER_FREQ3, 0x01, - /* Change the TPCLK pin polarity - data is valid on falling clock */ - DEMUX_CONTROL, 0xfb, - /* Change the value of IFBW[11:0] of - AGC IF/RF loop filter bandwidth register */ - AGC_RF_BANDWIDTH0, 0x40, - AGC_RF_BANDWIDTH1, 0x93, - AGC_RF_BANDWIDTH2, 0x00, - /* Change the value of bit 6, 'nINAGCBY' and - 'NSSEL[1:0] of ACG function control register 2 */ - AGC_FUNC_CTRL2, 0xc6, - /* Change the value of bit 6 'RFFIX' - of AGC function control register 3 */ - AGC_FUNC_CTRL3, 0x40, - /* Set the value of 'INLVTHD' register 0x2a/0x2c - to 0x7fe */ - AGC_DELAY0, 0x07, - AGC_DELAY2, 0xfe, - /* Change the value of IAGCBW[15:8] - of inner AGC loop filter bandwidth */ - AGC_LOOP_BANDWIDTH0, 0x08, - AGC_LOOP_BANDWIDTH1, 0x9a - }; - - static u8 lgdt3303_init_data[] = { - 0x4c, 0x14 - }; - - static u8 flip_1_lgdt3303_init_data[] = { - 0x4c, 0x14, - 0x87, 0xf3 - }; - - static u8 flip_2_lgdt3303_init_data[] = { - 0x4c, 0x14, - 0x87, 0xda - }; - - struct lgdt330x_state* state = fe->demodulator_priv; - char *chip_name; - int err; - - switch (state->config->demod_chip) { - case LGDT3302: - chip_name = "LGDT3302"; - err = i2c_write_demod_bytes(state, lgdt3302_init_data, - sizeof(lgdt3302_init_data)); - break; - case LGDT3303: - chip_name = "LGDT3303"; - switch (state->config->clock_polarity_flip) { - case 2: - err = i2c_write_demod_bytes(state, - flip_2_lgdt3303_init_data, - sizeof(flip_2_lgdt3303_init_data)); - break; - case 1: - err = i2c_write_demod_bytes(state, - flip_1_lgdt3303_init_data, - sizeof(flip_1_lgdt3303_init_data)); - break; - case 0: - default: - err = i2c_write_demod_bytes(state, lgdt3303_init_data, - sizeof(lgdt3303_init_data)); - } - break; - default: - chip_name = "undefined"; - printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n"); - err = -ENODEV; - } - dprintk("%s entered as %s\n", __func__, chip_name); - if (err < 0) - return err; - return lgdt330x_SwReset(state); -} - -static int lgdt330x_read_ber(struct dvb_frontend* fe, u32* ber) -{ - *ber = 0; /* Not supplied by the demod chips */ - return 0; -} - -static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct lgdt330x_state* state = fe->demodulator_priv; - int err; - u8 buf[2]; - - switch (state->config->demod_chip) { - case LGDT3302: - err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, - buf, sizeof(buf)); - break; - case LGDT3303: - err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1, - buf, sizeof(buf)); - break; - default: - printk(KERN_WARNING - "Only LGDT3302 and LGDT3303 are supported chips.\n"); - err = -ENODEV; - } - - *ucblocks = (buf[0] << 8) | buf[1]; - return 0; -} - -static int lgdt330x_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) -{ - /* - * Array of byte pairs - * to initialize 8VSB for lgdt3303 chip 50 MHz IF - */ - static u8 lgdt3303_8vsb_44_data[] = { - 0x04, 0x00, - 0x0d, 0x40, - 0x0e, 0x87, - 0x0f, 0x8e, - 0x10, 0x01, - 0x47, 0x8b }; - - /* - * Array of byte pairs - * to initialize QAM for lgdt3303 chip - */ - static u8 lgdt3303_qam_data[] = { - 0x04, 0x00, - 0x0d, 0x00, - 0x0e, 0x00, - 0x0f, 0x00, - 0x10, 0x00, - 0x51, 0x63, - 0x47, 0x66, - 0x48, 0x66, - 0x4d, 0x1a, - 0x49, 0x08, - 0x4a, 0x9b }; - - struct lgdt330x_state* state = fe->demodulator_priv; - - static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; - - int err; - /* Change only if we are actually changing the modulation */ - if (state->current_modulation != param->u.vsb.modulation) { - switch(param->u.vsb.modulation) { - case VSB_8: - dprintk("%s: VSB_8 MODE\n", __func__); - - /* Select VSB mode */ - top_ctrl_cfg[1] = 0x03; - - /* Select ANT connector if supported by card */ - if (state->config->pll_rf_set) - state->config->pll_rf_set(fe, 1); - - if (state->config->demod_chip == LGDT3303) { - err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data, - sizeof(lgdt3303_8vsb_44_data)); - } - break; - - case QAM_64: - dprintk("%s: QAM_64 MODE\n", __func__); - - /* Select QAM_64 mode */ - top_ctrl_cfg[1] = 0x00; - - /* Select CABLE connector if supported by card */ - if (state->config->pll_rf_set) - state->config->pll_rf_set(fe, 0); - - if (state->config->demod_chip == LGDT3303) { - err = i2c_write_demod_bytes(state, lgdt3303_qam_data, - sizeof(lgdt3303_qam_data)); - } - break; - - case QAM_256: - dprintk("%s: QAM_256 MODE\n", __func__); - - /* Select QAM_256 mode */ - top_ctrl_cfg[1] = 0x01; - - /* Select CABLE connector if supported by card */ - if (state->config->pll_rf_set) - state->config->pll_rf_set(fe, 0); - - if (state->config->demod_chip == LGDT3303) { - err = i2c_write_demod_bytes(state, lgdt3303_qam_data, - sizeof(lgdt3303_qam_data)); - } - break; - default: - printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, param->u.vsb.modulation); - return -1; - } - /* - * select serial or parallel MPEG harware interface - * Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303 - * Parallel: 0x00 - */ - top_ctrl_cfg[1] |= state->config->serial_mpeg; - - /* Select the requested mode */ - i2c_write_demod_bytes(state, top_ctrl_cfg, - sizeof(top_ctrl_cfg)); - if (state->config->set_ts_params) - state->config->set_ts_params(fe, 0); - state->current_modulation = param->u.vsb.modulation; - } - - /* Tune to the specified frequency */ - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* Keep track of the new frequency */ - /* FIXME this is the wrong way to do this... */ - /* The tuner is shared with the video4linux analog API */ - state->current_frequency = param->frequency; - - lgdt330x_SwReset(state); - return 0; -} - -static int lgdt330x_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters* param) -{ - struct lgdt330x_state *state = fe->demodulator_priv; - param->frequency = state->current_frequency; - return 0; -} - -static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct lgdt330x_state* state = fe->demodulator_priv; - u8 buf[3]; - - *status = 0; /* Reset status result */ - - /* AGC status register */ - i2c_read_demod_bytes(state, AGC_STATUS, buf, 1); - dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]); - if ((buf[0] & 0x0c) == 0x8){ - /* Test signal does not exist flag */ - /* as well as the AGC lock flag. */ - *status |= FE_HAS_SIGNAL; - } - - /* - * You must set the Mask bits to 1 in the IRQ_MASK in order - * to see that status bit in the IRQ_STATUS register. - * This is done in SwReset(); - */ - /* signal status */ - i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf)); - dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __func__, buf[0], buf[1], buf[2]); - - - /* sync status */ - if ((buf[2] & 0x03) == 0x01) { - *status |= FE_HAS_SYNC; - } - - /* FEC error status */ - if ((buf[2] & 0x0c) == 0x08) { - *status |= FE_HAS_LOCK; - *status |= FE_HAS_VITERBI; - } - - /* Carrier Recovery Lock Status Register */ - i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); - dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]); - switch (state->current_modulation) { - case QAM_256: - case QAM_64: - /* Need to understand why there are 3 lock levels here */ - if ((buf[0] & 0x07) == 0x07) - *status |= FE_HAS_CARRIER; - break; - case VSB_8: - if ((buf[0] & 0x80) == 0x80) - *status |= FE_HAS_CARRIER; - break; - default: - printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__); - } - - return 0; -} - -static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct lgdt330x_state* state = fe->demodulator_priv; - int err; - u8 buf[3]; - - *status = 0; /* Reset status result */ - - /* lgdt3303 AGC status register */ - err = i2c_read_demod_bytes(state, 0x58, buf, 1); - if (err < 0) - return err; - - dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]); - if ((buf[0] & 0x21) == 0x01){ - /* Test input signal does not exist flag */ - /* as well as the AGC lock flag. */ - *status |= FE_HAS_SIGNAL; - } - - /* Carrier Recovery Lock Status Register */ - i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); - dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]); - switch (state->current_modulation) { - case QAM_256: - case QAM_64: - /* Need to understand why there are 3 lock levels here */ - if ((buf[0] & 0x07) == 0x07) - *status |= FE_HAS_CARRIER; - else - break; - i2c_read_demod_bytes(state, 0x8a, buf, 1); - if ((buf[0] & 0x04) == 0x04) - *status |= FE_HAS_SYNC; - if ((buf[0] & 0x01) == 0x01) - *status |= FE_HAS_LOCK; - if ((buf[0] & 0x08) == 0x08) - *status |= FE_HAS_VITERBI; - break; - case VSB_8: - if ((buf[0] & 0x80) == 0x80) - *status |= FE_HAS_CARRIER; - else - break; - i2c_read_demod_bytes(state, 0x38, buf, 1); - if ((buf[0] & 0x02) == 0x00) - *status |= FE_HAS_SYNC; - if ((buf[0] & 0x01) == 0x01) { - *status |= FE_HAS_LOCK; - *status |= FE_HAS_VITERBI; - } - break; - default: - printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__); - } - return 0; -} - -/* Calculate SNR estimation (scaled by 2^24) - - 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM - equations from LGDT3303 datasheet. VSB is the same between the '02 - and '03, so maybe QAM is too? Perhaps someone with a newer datasheet - that has QAM information could verify? - - For 8-VSB: (two ways, take your pick) - LGDT3302: - SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE) - LGDT3303: - SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE) - LGDT3302 & LGDT3303: - SNR_PT = 10 * log10(25 * 32^2 / PT_MSE) (we use this one) - For 64-QAM: - SNR = 10 * log10( 688128 / MSEQAM) - For 256-QAM: - SNR = 10 * log10( 696320 / MSEQAM) - - We re-write the snr equation as: - SNR * 2^24 = 10*(c - intlog10(MSE)) - Where for 256-QAM, c = log10(696320) * 2^24, and so on. */ - -static u32 calculate_snr(u32 mse, u32 c) -{ - if (mse == 0) /* No signal */ - return 0; - - mse = intlog10(mse); - if (mse > c) { - /* Negative SNR, which is possible, but realisticly the - demod will lose lock before the signal gets this bad. The - API only allows for unsigned values, so just return 0 */ - return 0; - } - return 10*(c - mse); -} - -static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; - u8 buf[5]; /* read data buffer */ - u32 noise; /* noise value */ - u32 c; /* per-modulation SNR calculation constant */ - - switch(state->current_modulation) { - case VSB_8: - i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5); -#ifdef USE_EQMSE - /* Use Equalizer Mean-Square Error Register */ - /* SNR for ranges from -15.61 to +41.58 */ - noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; - c = 69765745; /* log10(25*24^2)*2^24 */ -#else - /* Use Phase Tracker Mean-Square Error Register */ - /* SNR for ranges from -13.11 to +44.08 */ - noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; - c = 73957994; /* log10(25*32^2)*2^24 */ -#endif - break; - case QAM_64: - case QAM_256: - i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); - noise = ((buf[0] & 3) << 8) | buf[1]; - c = state->current_modulation == QAM_64 ? 97939837 : 98026066; - /* log10(688128)*2^24 and log10(696320)*2^24 */ - break; - default: - printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n", - __func__); - return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ - } - - state->snr = calculate_snr(noise, c); - *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ - - dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, - state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); - - return 0; -} - -static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; - u8 buf[5]; /* read data buffer */ - u32 noise; /* noise value */ - u32 c; /* per-modulation SNR calculation constant */ - - switch(state->current_modulation) { - case VSB_8: - i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5); -#ifdef USE_EQMSE - /* Use Equalizer Mean-Square Error Register */ - /* SNR for ranges from -16.12 to +44.08 */ - noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2]; - c = 73957994; /* log10(25*32^2)*2^24 */ -#else - /* Use Phase Tracker Mean-Square Error Register */ - /* SNR for ranges from -13.11 to +44.08 */ - noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; - c = 73957994; /* log10(25*32^2)*2^24 */ -#endif - break; - case QAM_64: - case QAM_256: - i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); - noise = (buf[0] << 8) | buf[1]; - c = state->current_modulation == QAM_64 ? 97939837 : 98026066; - /* log10(688128)*2^24 and log10(696320)*2^24 */ - break; - default: - printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n", - __func__); - return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ - } - - state->snr = calculate_snr(noise, c); - *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ - - dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, - state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); - - return 0; -} - -static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - /* Calculate Strength from SNR up to 35dB */ - /* Even though the SNR can go higher than 35dB, there is some comfort */ - /* factor in having a range of strong signals that can show at 100% */ - struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; - u16 snr; - int ret; - - ret = fe->ops.read_snr(fe, &snr); - if (ret != 0) - return ret; - /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ - /* scale the range 0 - 35*2^24 into 0 - 65535 */ - if (state->snr >= 8960 * 0x10000) - *strength = 0xffff; - else - *strength = state->snr / 8960; - - return 0; -} - -static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) -{ - /* I have no idea about this - it may not be needed */ - fe_tune_settings->min_delay_ms = 500; - fe_tune_settings->step_size = 0; - fe_tune_settings->max_drift = 0; - return 0; -} - -static void lgdt330x_release(struct dvb_frontend* fe) -{ - struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops lgdt3302_ops; -static struct dvb_frontend_ops lgdt3303_ops; - -struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, - struct i2c_adapter* i2c) -{ - struct lgdt330x_state* state = NULL; - u8 buf[1]; - - /* Allocate memory for the internal state */ - state = kzalloc(sizeof(struct lgdt330x_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* Setup the state */ - state->config = config; - state->i2c = i2c; - - /* Create dvb_frontend */ - switch (config->demod_chip) { - case LGDT3302: - memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); - break; - case LGDT3303: - memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops)); - break; - default: - goto error; - } - state->frontend.demodulator_priv = state; - - /* Verify communication with demod chip */ - if (i2c_read_demod_bytes(state, 2, buf, 1)) - goto error; - - state->current_frequency = -1; - state->current_modulation = -1; - - return &state->frontend; - -error: - kfree(state); - dprintk("%s: ERROR\n",__func__); - return NULL; -} - -static struct dvb_frontend_ops lgdt3302_ops = { - .info = { - .name= "LG Electronics LGDT3302 VSB/QAM Frontend", - .type = FE_ATSC, - .frequency_min= 54000000, - .frequency_max= 858000000, - .frequency_stepsize= 62500, - .symbol_rate_min = 5056941, /* QAM 64 */ - .symbol_rate_max = 10762000, /* VSB 8 */ - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - .init = lgdt330x_init, - .set_frontend = lgdt330x_set_parameters, - .get_frontend = lgdt330x_get_frontend, - .get_tune_settings = lgdt330x_get_tune_settings, - .read_status = lgdt3302_read_status, - .read_ber = lgdt330x_read_ber, - .read_signal_strength = lgdt330x_read_signal_strength, - .read_snr = lgdt3302_read_snr, - .read_ucblocks = lgdt330x_read_ucblocks, - .release = lgdt330x_release, -}; - -static struct dvb_frontend_ops lgdt3303_ops = { - .info = { - .name= "LG Electronics LGDT3303 VSB/QAM Frontend", - .type = FE_ATSC, - .frequency_min= 54000000, - .frequency_max= 858000000, - .frequency_stepsize= 62500, - .symbol_rate_min = 5056941, /* QAM 64 */ - .symbol_rate_max = 10762000, /* VSB 8 */ - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - .init = lgdt330x_init, - .set_frontend = lgdt330x_set_parameters, - .get_frontend = lgdt330x_get_frontend, - .get_tune_settings = lgdt330x_get_tune_settings, - .read_status = lgdt3303_read_status, - .read_ber = lgdt330x_read_ber, - .read_signal_strength = lgdt330x_read_signal_strength, - .read_snr = lgdt3303_read_snr, - .read_ucblocks = lgdt330x_read_ucblocks, - .release = lgdt330x_release, -}; - -MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); -MODULE_AUTHOR("Wilson Michaels"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(lgdt330x_attach); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* - * Support for LGDT3302 and LGDT3303 - VSB/QAM - * - * Copyright (C) 2005 Wilson Michaels - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef LGDT330X_H -#define LGDT330X_H - -#include - -typedef enum lg_chip_t { - UNDEFINED, - LGDT3302, - LGDT3303 -}lg_chip_type; - -struct lgdt330x_config -{ - /* The demodulator's i2c address */ - u8 demod_address; - - /* LG demodulator chip LGDT3302 or LGDT3303 */ - lg_chip_type demod_chip; - - /* MPEG hardware interface - 0:parallel 1:serial */ - int serial_mpeg; - - /* PLL interface */ - int (*pll_rf_set) (struct dvb_frontend* fe, int index); - - /* Need to set device param for start_dma */ - int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); - - /* Flip the polarity of the mpeg data transfer clock using alternate init data - * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled */ - int clock_polarity_flip; -}; - -#if defined(CONFIG_DVB_LGDT330X) || (defined(CONFIG_DVB_LGDT330X_MODULE) && defined(MODULE)) -extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_LGDT330X - -#endif /* LGDT330X_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgdt330x_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/* - * Support for LGDT3302 and LGDT3303 - VSB/QAM - * - * Copyright (C) 2005 Wilson Michaels - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _LGDT330X_PRIV_ -#define _LGDT330X_PRIV_ - -/* i2c control register addresses */ -enum I2C_REG { - TOP_CONTROL= 0x00, - IRQ_MASK= 0x01, - IRQ_STATUS= 0x02, - VSB_CARRIER_FREQ0= 0x16, - VSB_CARRIER_FREQ1= 0x17, - VSB_CARRIER_FREQ2= 0x18, - VSB_CARRIER_FREQ3= 0x19, - CARRIER_MSEQAM1= 0x1a, - CARRIER_MSEQAM2= 0x1b, - CARRIER_LOCK= 0x1c, - TIMING_RECOVERY= 0x1d, - AGC_DELAY0= 0x2a, - AGC_DELAY1= 0x2b, - AGC_DELAY2= 0x2c, - AGC_RF_BANDWIDTH0= 0x2d, - AGC_RF_BANDWIDTH1= 0x2e, - AGC_RF_BANDWIDTH2= 0x2f, - AGC_LOOP_BANDWIDTH0= 0x30, - AGC_LOOP_BANDWIDTH1= 0x31, - AGC_FUNC_CTRL1= 0x32, - AGC_FUNC_CTRL2= 0x33, - AGC_FUNC_CTRL3= 0x34, - AGC_RFIF_ACC0= 0x39, - AGC_RFIF_ACC1= 0x3a, - AGC_RFIF_ACC2= 0x3b, - AGC_STATUS= 0x3f, - SYNC_STATUS_VSB= 0x43, - DEMUX_CONTROL= 0x66, - LGDT3302_EQPH_ERR0= 0x47, - LGDT3302_EQ_ERR1= 0x48, - LGDT3302_EQ_ERR2= 0x49, - LGDT3302_PH_ERR1= 0x4a, - LGDT3302_PH_ERR2= 0x4b, - LGDT3302_PACKET_ERR_COUNTER1= 0x6a, - LGDT3302_PACKET_ERR_COUNTER2= 0x6b, - LGDT3303_EQPH_ERR0= 0x6e, - LGDT3303_EQ_ERR1= 0x6f, - LGDT3303_EQ_ERR2= 0x70, - LGDT3303_PH_ERR1= 0x71, - LGDT3303_PH_ERR2= 0x72, - LGDT3303_PACKET_ERR_COUNTER1= 0x8b, - LGDT3303_PACKET_ERR_COUNTER2= 0x8c, -}; - -#endif /* _LGDT330X_PRIV_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gl5.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gl5.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gl5.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gl5.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,454 +0,0 @@ -/* - Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver - - Copyright (C) 2008 Sirius International (Hong Kong) Limited - Timothy Lee - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "lgs8gl5.h" - - -#define REG_RESET 0x02 -#define REG_RESET_OFF 0x01 -#define REG_03 0x03 -#define REG_04 0x04 -#define REG_07 0x07 -#define REG_09 0x09 -#define REG_0A 0x0a -#define REG_0B 0x0b -#define REG_0C 0x0c -#define REG_37 0x37 -#define REG_STRENGTH 0x4b -#define REG_STRENGTH_MASK 0x7f -#define REG_STRENGTH_CARRIER 0x80 -#define REG_INVERSION 0x7c -#define REG_INVERSION_ON 0x80 -#define REG_7D 0x7d -#define REG_7E 0x7e -#define REG_A2 0xa2 -#define REG_STATUS 0xa4 -#define REG_STATUS_SYNC 0x04 -#define REG_STATUS_LOCK 0x01 - - -struct lgs8gl5_state { - struct i2c_adapter *i2c; - const struct lgs8gl5_config *config; - struct dvb_frontend frontend; -}; - - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "lgs8gl5: " args); \ - } while (0) - - -/* Writes into demod's register */ -static int -lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) -{ - int ret; - u8 buf[] = {reg, data}; - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf, - .len = 2 - }; - - ret = i2c_transfer(state->i2c, &msg, 1); - if (ret != 1) - dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n", - __func__, reg, data, ret); - return (ret != 1) ? -1 : 0; -} - - -/* Reads from demod's register */ -static int -lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) -{ - int ret; - u8 b0[] = {reg}; - u8 b1[] = {0}; - struct i2c_msg msg[2] = { - { - .addr = state->config->demod_address, - .flags = 0, - .buf = b0, - .len = 1 - }, - { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = b1, - .len = 1 - } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - if (ret != 2) - return -EIO; - - return b1[0]; -} - - -static int -lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) -{ - lgs8gl5_read_reg(state, reg); - lgs8gl5_write_reg(state, reg, data); - return 0; -} - - -/* Writes into alternate device's register */ -/* TODO: Find out what that device is for! */ -static int -lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) -{ - int ret; - u8 b0[] = {reg}; - u8 b1[] = {0}; - u8 b2[] = {reg, data}; - struct i2c_msg msg[3] = { - { - .addr = state->config->demod_address + 2, - .flags = 0, - .buf = b0, - .len = 1 - }, - { - .addr = state->config->demod_address + 2, - .flags = I2C_M_RD, - .buf = b1, - .len = 1 - }, - { - .addr = state->config->demod_address + 2, - .flags = 0, - .buf = b2, - .len = 2 - }, - }; - - ret = i2c_transfer(state->i2c, msg, 3); - return (ret != 3) ? -1 : 0; -} - - -static void -lgs8gl5_soft_reset(struct lgs8gl5_state *state) -{ - u8 val; - - dprintk("%s\n", __func__); - - val = lgs8gl5_read_reg(state, REG_RESET); - lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF); - lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF); - msleep(5); -} - - -/* Starts demodulation */ -static void -lgs8gl5_start_demod(struct lgs8gl5_state *state) -{ - u8 val; - int n; - - dprintk("%s\n", __func__); - - lgs8gl5_update_alt_reg(state, 0xc2, 0x28); - lgs8gl5_soft_reset(state); - lgs8gl5_update_reg(state, REG_07, 0x10); - lgs8gl5_update_reg(state, REG_07, 0x10); - lgs8gl5_write_reg(state, REG_09, 0x0e); - lgs8gl5_write_reg(state, REG_0A, 0xe5); - lgs8gl5_write_reg(state, REG_0B, 0x35); - lgs8gl5_write_reg(state, REG_0C, 0x30); - - lgs8gl5_update_reg(state, REG_03, 0x00); - lgs8gl5_update_reg(state, REG_7E, 0x01); - lgs8gl5_update_alt_reg(state, 0xc5, 0x00); - lgs8gl5_update_reg(state, REG_04, 0x02); - lgs8gl5_update_reg(state, REG_37, 0x01); - lgs8gl5_soft_reset(state); - - /* Wait for carrier */ - for (n = 0; n < 10; n++) { - val = lgs8gl5_read_reg(state, REG_STRENGTH); - dprintk("Wait for carrier[%d] 0x%02X\n", n, val); - if (val & REG_STRENGTH_CARRIER) - break; - msleep(4); - } - if (!(val & REG_STRENGTH_CARRIER)) - return; - - /* Wait for lock */ - for (n = 0; n < 20; n++) { - val = lgs8gl5_read_reg(state, REG_STATUS); - dprintk("Wait for lock[%d] 0x%02X\n", n, val); - if (val & REG_STATUS_LOCK) - break; - msleep(12); - } - if (!(val & REG_STATUS_LOCK)) - return; - - lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2)); - lgs8gl5_soft_reset(state); -} - - -static int -lgs8gl5_init(struct dvb_frontend *fe) -{ - struct lgs8gl5_state *state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - lgs8gl5_update_alt_reg(state, 0xc2, 0x28); - lgs8gl5_soft_reset(state); - lgs8gl5_update_reg(state, REG_07, 0x10); - lgs8gl5_update_reg(state, REG_07, 0x10); - lgs8gl5_write_reg(state, REG_09, 0x0e); - lgs8gl5_write_reg(state, REG_0A, 0xe5); - lgs8gl5_write_reg(state, REG_0B, 0x35); - lgs8gl5_write_reg(state, REG_0C, 0x30); - - return 0; -} - - -static int -lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct lgs8gl5_state *state = fe->demodulator_priv; - u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); - u8 flags = lgs8gl5_read_reg(state, REG_STATUS); - - *status = 0; - - if ((level & REG_STRENGTH_MASK) > 0) - *status |= FE_HAS_SIGNAL; - if (level & REG_STRENGTH_CARRIER) - *status |= FE_HAS_CARRIER; - if (flags & REG_STATUS_SYNC) - *status |= FE_HAS_SYNC; - if (flags & REG_STATUS_LOCK) - *status |= FE_HAS_LOCK; - - return 0; -} - - -static int -lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - *ber = 0; - - return 0; -} - - -static int -lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) -{ - struct lgs8gl5_state *state = fe->demodulator_priv; - u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); - *signal_strength = (level & REG_STRENGTH_MASK) << 8; - - return 0; -} - - -static int -lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct lgs8gl5_state *state = fe->demodulator_priv; - u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); - *snr = (level & REG_STRENGTH_MASK) << 8; - - return 0; -} - - -static int -lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - *ucblocks = 0; - - return 0; -} - - -static int -lgs8gl5_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct lgs8gl5_state *state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ) - return -EINVAL; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* lgs8gl5_set_inversion(state, p->inversion); */ - - lgs8gl5_start_demod(state); - - return 0; -} - - -static int -lgs8gl5_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct lgs8gl5_state *state = fe->demodulator_priv; - u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); - struct dvb_ofdm_parameters *o = &p->u.ofdm; - - p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; - - o->code_rate_HP = FEC_1_2; - o->code_rate_LP = FEC_7_8; - o->guard_interval = GUARD_INTERVAL_1_32; - o->transmission_mode = TRANSMISSION_MODE_2K; - o->constellation = QAM_64; - o->hierarchy_information = HIERARCHY_NONE; - o->bandwidth = BANDWIDTH_8_MHZ; - - return 0; -} - - -static int -lgs8gl5_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *fesettings) -{ - fesettings->min_delay_ms = 240; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - - -static void -lgs8gl5_release(struct dvb_frontend *fe) -{ - struct lgs8gl5_state *state = fe->demodulator_priv; - kfree(state); -} - - -static struct dvb_frontend_ops lgs8gl5_ops; - - -struct dvb_frontend* -lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c) -{ - struct lgs8gl5_state *state = NULL; - - dprintk("%s\n", __func__); - - /* Allocate memory for the internal state */ - state = kzalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* Setup the state */ - state->config = config; - state->i2c = i2c; - - /* Check if the demod is there */ - if (lgs8gl5_read_reg(state, REG_RESET) < 0) - goto error; - - /* Create dvb_frontend */ - memcpy(&state->frontend.ops, &lgs8gl5_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(lgs8gl5_attach); - - -static struct dvb_frontend_ops lgs8gl5_ops = { - .info = { - .name = "Legend Silicon LGS-8GL5 DMB-TH", - .type = FE_OFDM, - .frequency_min = 474000000, - .frequency_max = 858000000, - .frequency_stepsize = 10000, - .frequency_tolerance = 0, - .caps = FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | - FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_BANDWIDTH_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | - FE_CAN_RECOVER - }, - - .release = lgs8gl5_release, - - .init = lgs8gl5_init, - - .set_frontend = lgs8gl5_set_frontend, - .get_frontend = lgs8gl5_get_frontend, - .get_tune_settings = lgs8gl5_get_tune_settings, - - .read_status = lgs8gl5_read_status, - .read_ber = lgs8gl5_read_ber, - .read_signal_strength = lgs8gl5_read_signal_strength, - .read_snr = lgs8gl5_read_snr, - .read_ucblocks = lgs8gl5_read_ucblocks, -}; - - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver"); -MODULE_AUTHOR("Timothy Lee"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gl5.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gl5.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gl5.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gl5.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/* - Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver - - Copyright (C) 2008 Sirius International (Hong Kong) Limited - Timothy Lee - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef LGS8GL5_H -#define LGS8GL5_H - -#include - -struct lgs8gl5_config { - /* the demodulator's i2c address */ - u8 demod_address; -}; - -#if defined(CONFIG_DVB_LGS8GL5) || \ - (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE)) -extern struct dvb_frontend *lgs8gl5_attach( - const struct lgs8gl5_config *config, struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *lgs8gl5_attach( - const struct lgs8gl5_config *config, struct i2c_adapter *i2c) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_LGS8GL5 */ - -#endif /* LGS8GL5_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1073 +0,0 @@ -/* - * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator - * LGS8913, LGS8GL5, LGS8G75 - * experimental support LGS8G42, LGS8G52 - * - * Copyright (C) 2007-2009 David T.L. Wong - * Copyright (C) 2008 Sirius International (Hong Kong) Limited - * Timothy Lee (for initial work on LGS8GL5) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include - -#include "dvb_frontend.h" - -#include "lgs8gxx.h" -#include "lgs8gxx_priv.h" - -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "lgs8gxx: " args); \ - } while (0) - -static int debug; -static int fake_signal_str = 1; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -module_param(fake_signal_str, int, 0644); -MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913." -"Signal strength calculation is slow.(default:on)."); - -/* LGS8GXX internal helper functions */ - -static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data) -{ - int ret; - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; - - msg.addr = priv->config->demod_address; - if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0) - msg.addr += 0x02; - - if (debug >= 2) - dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data); - - ret = i2c_transfer(priv->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", - __func__, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data) -{ - int ret; - u8 dev_addr; - - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { .flags = 0, .buf = b0, .len = 1 }, - { .flags = I2C_M_RD, .buf = b1, .len = 1 }, - }; - - dev_addr = priv->config->demod_address; - if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0) - dev_addr += 0x02; - msg[1].addr = msg[0].addr = dev_addr; - - ret = i2c_transfer(priv->i2c, msg, 2); - if (ret != 2) { - dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret); - return -1; - } - - *p_data = b1[0]; - if (debug >= 2) - dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, b1[0]); - return 0; -} - -static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv) -{ - lgs8gxx_write_reg(priv, 0x02, 0x00); - msleep(1); - lgs8gxx_write_reg(priv, 0x02, 0x01); - msleep(100); - - return 0; -} - -static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask, - u8 val, u8 delay, u8 tries) -{ - u8 t; - int i; - - for (i = 0; i < tries; i++) { - lgs8gxx_read_reg(priv, reg, &t); - - if ((t & mask) == val) - return 0; - msleep(delay); - } - - return 1; -} - -static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv) -{ - const struct lgs8gxx_config *config = priv->config; - u8 if_conf; - - if_conf = 0x10; /* AGC output on, RF_AGC output off; */ - - if_conf |= - ((config->ext_adc) ? 0x80 : 0x00) | - ((config->if_neg_center) ? 0x04 : 0x00) | - ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */ - ((config->adc_signed) ? 0x02 : 0x00) | - ((config->if_neg_edge) ? 0x01 : 0x00); - - if (config->ext_adc && - (config->prod == LGS8GXX_PROD_LGS8G52)) { - lgs8gxx_write_reg(priv, 0xBA, 0x40); - } - - lgs8gxx_write_reg(priv, 0x07, if_conf); - - return 0; -} - -static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/) -{ - u64 val; - u32 v32; - u32 if_clk; - - if_clk = priv->config->if_clk_freq; - - val = freq; - if (freq != 0) { - val <<= 32; - if (if_clk != 0) - do_div(val, if_clk); - v32 = val & 0xFFFFFFFF; - dprintk("Set IF Freq to %dkHz\n", freq); - } else { - v32 = 0; - dprintk("Set IF Freq to baseband\n"); - } - dprintk("AFC_INIT_FREQ = 0x%08X\n", v32); - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32)); - lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8)); - lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16)); - lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24)); - } else { - lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32)); - lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8)); - lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16)); - lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24)); - } - - return 0; -} - -static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv) -{ - u64 val; - u32 v32 = 0; - u8 reg_addr, t; - int i; - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) - reg_addr = 0x23; - else - reg_addr = 0x48; - - for (i = 0; i < 4; i++) { - lgs8gxx_read_reg(priv, reg_addr, &t); - v32 <<= 8; - v32 |= t; - reg_addr--; - } - - val = v32; - val *= priv->config->if_clk_freq; - val >>= 32; - dprintk("AFC = %u kHz\n", (u32)val); - return 0; -} - -static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv) -{ - u8 t; - u8 prod = priv->config->prod; - - if (prod == LGS8GXX_PROD_LGS8913) - lgs8gxx_write_reg(priv, 0xC6, 0x01); - - if (prod == LGS8GXX_PROD_LGS8G75) { - lgs8gxx_read_reg(priv, 0x0C, &t); - t &= (~0x04); - lgs8gxx_write_reg(priv, 0x0C, t | 0x80); - lgs8gxx_write_reg(priv, 0x39, 0x00); - lgs8gxx_write_reg(priv, 0x3D, 0x04); - } else if (prod == LGS8GXX_PROD_LGS8913 || - prod == LGS8GXX_PROD_LGS8GL5 || - prod == LGS8GXX_PROD_LGS8G42 || - prod == LGS8GXX_PROD_LGS8G52 || - prod == LGS8GXX_PROD_LGS8G54) { - lgs8gxx_read_reg(priv, 0x7E, &t); - lgs8gxx_write_reg(priv, 0x7E, t | 0x01); - - /* clear FEC self reset */ - lgs8gxx_read_reg(priv, 0xC5, &t); - lgs8gxx_write_reg(priv, 0xC5, t & 0xE0); - } - - if (prod == LGS8GXX_PROD_LGS8913) { - /* FEC auto detect */ - lgs8gxx_write_reg(priv, 0xC1, 0x03); - - lgs8gxx_read_reg(priv, 0x7C, &t); - t = (t & 0x8C) | 0x03; - lgs8gxx_write_reg(priv, 0x7C, t); - - /* BER test mode */ - lgs8gxx_read_reg(priv, 0xC3, &t); - t = (t & 0xEF) | 0x10; - lgs8gxx_write_reg(priv, 0xC3, t); - } - - if (priv->config->prod == LGS8GXX_PROD_LGS8G52) - lgs8gxx_write_reg(priv, 0xD9, 0x40); - - return 0; -} - -static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv) -{ - int ret = 0; - u8 t; - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - u8 t2; - lgs8gxx_read_reg(priv, 0x0C, &t); - t &= (~0x80); - lgs8gxx_write_reg(priv, 0x0C, t); - - lgs8gxx_read_reg(priv, 0x0C, &t); - lgs8gxx_read_reg(priv, 0x19, &t2); - - if (((t&0x03) == 0x01) && (t2&0x01)) { - lgs8gxx_write_reg(priv, 0x6E, 0x05); - lgs8gxx_write_reg(priv, 0x39, 0x02); - lgs8gxx_write_reg(priv, 0x39, 0x03); - lgs8gxx_write_reg(priv, 0x3D, 0x05); - lgs8gxx_write_reg(priv, 0x3E, 0x28); - lgs8gxx_write_reg(priv, 0x53, 0x80); - } else { - lgs8gxx_write_reg(priv, 0x6E, 0x3F); - lgs8gxx_write_reg(priv, 0x39, 0x00); - lgs8gxx_write_reg(priv, 0x3D, 0x04); - } - - lgs8gxx_soft_reset(priv); - return 0; - } - - /* turn off auto-detect; manual settings */ - lgs8gxx_write_reg(priv, 0x7E, 0); - if (priv->config->prod == LGS8GXX_PROD_LGS8913) - lgs8gxx_write_reg(priv, 0xC1, 0); - - ret = lgs8gxx_read_reg(priv, 0xC5, &t); - t = (t & 0xE0) | 0x06; - lgs8gxx_write_reg(priv, 0xC5, t); - - lgs8gxx_soft_reset(priv); - - return 0; -} - -static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked) -{ - int ret = 0; - u8 t; - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) - ret = lgs8gxx_read_reg(priv, 0x13, &t); - else - ret = lgs8gxx_read_reg(priv, 0x4B, &t); - if (ret != 0) - return ret; - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) - *locked = ((t & 0x80) == 0x80) ? 1 : 0; - else - *locked = ((t & 0xC0) == 0xC0) ? 1 : 0; - return 0; -} - -/* Wait for Code Acquisition Lock */ -static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked) -{ - int ret = 0; - u8 reg, mask, val; - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - reg = 0x13; - mask = 0x80; - val = 0x80; - } else { - reg = 0x4B; - mask = 0xC0; - val = 0xC0; - } - - ret = wait_reg_mask(priv, reg, mask, val, 50, 40); - *locked = (ret == 0) ? 1 : 0; - - return 0; -} - -static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv, - u8 *finished) -{ - int ret = 0; - u8 reg, mask, val; - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - reg = 0x1f; - mask = 0xC0; - val = 0x80; - } else { - reg = 0xA4; - mask = 0x03; - val = 0x01; - } - - ret = wait_reg_mask(priv, reg, mask, val, 10, 20); - *finished = (ret == 0) ? 1 : 0; - - return 0; -} - -static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn, - u8 *locked) -{ - int err = 0; - u8 ad_fini = 0; - u8 t1, t2; - - if (gi == GI_945) - dprintk("try GI 945\n"); - else if (gi == GI_595) - dprintk("try GI 595\n"); - else if (gi == GI_420) - dprintk("try GI 420\n"); - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - lgs8gxx_read_reg(priv, 0x0C, &t1); - lgs8gxx_read_reg(priv, 0x18, &t2); - t1 &= ~(GI_MASK); - t1 |= gi; - t2 &= 0xFE; - t2 |= cpn ? 0x01 : 0x00; - lgs8gxx_write_reg(priv, 0x0C, t1); - lgs8gxx_write_reg(priv, 0x18, t2); - } else { - lgs8gxx_write_reg(priv, 0x04, gi); - } - lgs8gxx_soft_reset(priv); - err = lgs8gxx_wait_ca_lock(priv, locked); - if (err || !(*locked)) - return err; - err = lgs8gxx_is_autodetect_finished(priv, &ad_fini); - if (err != 0) - return err; - if (ad_fini) { - dprintk("auto detect finished\n"); - } else - *locked = 0; - - return 0; -} - -static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv, - u8 *detected_param, u8 *gi) -{ - int i, j; - int err = 0; - u8 locked = 0, tmp_gi; - - dprintk("%s\n", __func__); - - lgs8gxx_set_mode_auto(priv); - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - lgs8gxx_write_reg(priv, 0x67, 0xAA); - lgs8gxx_write_reg(priv, 0x6E, 0x3F); - } else { - /* Guard Interval */ - lgs8gxx_write_reg(priv, 0x03, 00); - } - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - tmp_gi = GI_945; - err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked); - if (err) - goto out; - if (locked) - goto locked; - } - for (j = 0; j < 2; j++) { - tmp_gi = GI_420; - err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked); - if (err) - goto out; - if (locked) - goto locked; - } - tmp_gi = GI_595; - err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked); - if (err) - goto out; - if (locked) - goto locked; - } - -locked: - if ((err == 0) && (locked == 1)) { - u8 t; - - if (priv->config->prod != LGS8GXX_PROD_LGS8G75) { - lgs8gxx_read_reg(priv, 0xA2, &t); - *detected_param = t; - } else { - lgs8gxx_read_reg(priv, 0x1F, &t); - *detected_param = t & 0x3F; - } - - if (tmp_gi == GI_945) - dprintk("GI 945 locked\n"); - else if (tmp_gi == GI_595) - dprintk("GI 595 locked\n"); - else if (tmp_gi == GI_420) - dprintk("GI 420 locked\n"); - *gi = tmp_gi; - } - if (!locked) - err = -1; - -out: - return err; -} - -static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv) -{ - s8 err; - u8 gi = 0x2; - u8 detected_param = 0; - - err = lgs8gxx_auto_detect(priv, &detected_param, &gi); - - if (err != 0) { - dprintk("lgs8gxx_auto_detect failed\n"); - } else - dprintk("detected param = 0x%02X\n", detected_param); - - /* Apply detected parameters */ - if (priv->config->prod == LGS8GXX_PROD_LGS8913) { - u8 inter_leave_len = detected_param & TIM_MASK ; - /* Fix 8913 time interleaver detection bug */ - inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40; - detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK; - detected_param |= inter_leave_len; - } - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - u8 t; - lgs8gxx_read_reg(priv, 0x19, &t); - t &= 0x81; - t |= detected_param << 1; - lgs8gxx_write_reg(priv, 0x19, t); - } else { - lgs8gxx_write_reg(priv, 0x7D, detected_param); - if (priv->config->prod == LGS8GXX_PROD_LGS8913) - lgs8gxx_write_reg(priv, 0xC0, detected_param); - } - /* lgs8gxx_soft_reset(priv); */ - - /* Enter manual mode */ - lgs8gxx_set_mode_manual(priv); - - switch (gi) { - case GI_945: - priv->curr_gi = 945; break; - case GI_595: - priv->curr_gi = 595; break; - case GI_420: - priv->curr_gi = 420; break; - default: - priv->curr_gi = 945; break; - } -} - -static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv, - u8 serial, u8 clk_pol, u8 clk_gated) -{ - int ret = 0; - u8 t, reg_addr; - - reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2; - ret = lgs8gxx_read_reg(priv, reg_addr, &t); - if (ret != 0) - return ret; - - t &= 0xF8; - t |= serial ? TS_SERIAL : TS_PARALLEL; - t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL; - t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN; - - ret = lgs8gxx_write_reg(priv, reg_addr, t); - if (ret != 0) - return ret; - - return 0; -} - -/* A/D input peak-to-peak voltage range */ -static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv, - u8 sel) -{ - u8 r26 = 0x73, r27 = 0x90; - - if (priv->config->prod != LGS8GXX_PROD_LGS8G75) - return 0; - - r26 |= (sel & 0x01) << 7; - r27 |= (sel & 0x02) >> 1; - lgs8gxx_write_reg(priv, 0x26, r26); - lgs8gxx_write_reg(priv, 0x27, r27); - - return 0; -} - -/* LGS8913 demod frontend functions */ - -static int lgs8913_init(struct lgs8gxx_state *priv) -{ - u8 t; - - /* LGS8913 specific */ - lgs8gxx_write_reg(priv, 0xc1, 0x3); - - lgs8gxx_read_reg(priv, 0x7c, &t); - lgs8gxx_write_reg(priv, 0x7c, (t&0x8c) | 0x3); - - /* LGS8913 specific */ - lgs8gxx_read_reg(priv, 0xc3, &t); - lgs8gxx_write_reg(priv, 0xc3, t&0x10); - - - return 0; -} - -static int lgs8g75_init_data(struct lgs8gxx_state *priv) -{ - const struct firmware *fw; - int rc; - int i; - - rc = request_firmware(&fw, "lgs8g75.fw", &priv->i2c->dev); - if (rc) - return rc; - - lgs8gxx_write_reg(priv, 0xC6, 0x40); - - lgs8gxx_write_reg(priv, 0x3D, 0x04); - lgs8gxx_write_reg(priv, 0x39, 0x00); - - lgs8gxx_write_reg(priv, 0x3A, 0x00); - lgs8gxx_write_reg(priv, 0x38, 0x00); - lgs8gxx_write_reg(priv, 0x3B, 0x00); - lgs8gxx_write_reg(priv, 0x38, 0x00); - - for (i = 0; i < fw->size; i++) { - lgs8gxx_write_reg(priv, 0x38, 0x00); - lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff)); - lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8)); - lgs8gxx_write_reg(priv, 0x3C, fw->data[i]); - } - - lgs8gxx_write_reg(priv, 0x38, 0x00); - - release_firmware(fw); - return 0; -} - -static int lgs8gxx_init(struct dvb_frontend *fe) -{ - struct lgs8gxx_state *priv = - (struct lgs8gxx_state *)fe->demodulator_priv; - const struct lgs8gxx_config *config = priv->config; - u8 data = 0; - s8 err; - dprintk("%s\n", __func__); - - lgs8gxx_read_reg(priv, 0, &data); - dprintk("reg 0 = 0x%02X\n", data); - - if (config->prod == LGS8GXX_PROD_LGS8G75) - lgs8g75_set_adc_vpp(priv, config->adc_vpp); - - /* Setup MPEG output format */ - err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts, - config->ts_clk_pol, - config->ts_clk_gated); - if (err != 0) - return -EIO; - - if (config->prod == LGS8GXX_PROD_LGS8913) - lgs8913_init(priv); - lgs8gxx_set_if_freq(priv, priv->config->if_freq); - lgs8gxx_set_ad_mode(priv); - - return 0; -} - -static void lgs8gxx_release(struct dvb_frontend *fe) -{ - struct lgs8gxx_state *state = fe->demodulator_priv; - dprintk("%s\n", __func__); - - kfree(state); -} - - -static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len) -{ - struct lgs8gxx_state *priv = fe->demodulator_priv; - - if (len != 2) - return -EINVAL; - - return lgs8gxx_write_reg(priv, buf[0], buf[1]); -} - -static int lgs8gxx_set_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) -{ - struct lgs8gxx_state *priv = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - /* set frequency */ - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* start auto lock */ - lgs8gxx_auto_lock(priv); - - msleep(10); - - return 0; -} - -static int lgs8gxx_get_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) -{ - dprintk("%s\n", __func__); - - /* TODO: get real readings from device */ - /* inversion status */ - fe_params->inversion = INVERSION_OFF; - - /* bandwidth */ - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - - fe_params->u.ofdm.code_rate_HP = FEC_AUTO; - fe_params->u.ofdm.code_rate_LP = FEC_AUTO; - - fe_params->u.ofdm.constellation = QAM_AUTO; - - /* transmission mode */ - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - - /* guard interval */ - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - - /* hierarchy */ - fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; - - return 0; -} - -static -int lgs8gxx_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *fesettings) -{ - /* FIXME: copy from tda1004x.c */ - fesettings->min_delay_ms = 800; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status) -{ - struct lgs8gxx_state *priv = fe->demodulator_priv; - s8 ret; - u8 t, locked = 0; - - dprintk("%s\n", __func__); - *fe_status = 0; - - lgs8gxx_get_afc_phase(priv); - lgs8gxx_is_locked(priv, &locked); - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - if (locked) - *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - return 0; - } - - ret = lgs8gxx_read_reg(priv, 0x4B, &t); - if (ret != 0) - return -EIO; - - dprintk("Reg 0x4B: 0x%02X\n", t); - - *fe_status = 0; - if (priv->config->prod == LGS8GXX_PROD_LGS8913) { - if ((t & 0x40) == 0x40) - *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; - if ((t & 0x80) == 0x80) - *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - } else { - if ((t & 0x80) == 0x80) - *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - } - - /* success */ - dprintk("%s: fe_status=0x%x\n", __func__, *fe_status); - return 0; -} - -static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal) -{ - u16 v; - u8 agc_lvl[2], cat; - - dprintk("%s()\n", __func__); - lgs8gxx_read_reg(priv, 0x3F, &agc_lvl[0]); - lgs8gxx_read_reg(priv, 0x3E, &agc_lvl[1]); - - v = agc_lvl[0]; - v <<= 8; - v |= agc_lvl[1]; - - dprintk("agc_lvl: 0x%04X\n", v); - - if (v < 0x100) - cat = 0; - else if (v < 0x190) - cat = 5; - else if (v < 0x2A8) - cat = 4; - else if (v < 0x381) - cat = 3; - else if (v < 0x400) - cat = 2; - else if (v == 0x400) - cat = 1; - else - cat = 0; - - *signal = cat * 65535 / 5; - - return 0; -} - -static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal) -{ - u8 t; s8 ret; - s16 max_strength = 0; - u8 str; - u16 i, gi = priv->curr_gi; - - dprintk("%s\n", __func__); - - ret = lgs8gxx_read_reg(priv, 0x4B, &t); - if (ret != 0) - return -EIO; - - if (fake_signal_str) { - if ((t & 0xC0) == 0xC0) { - dprintk("Fake signal strength\n"); - *signal = 0x7FFF; - } else - *signal = 0; - return 0; - } - - dprintk("gi = %d\n", gi); - for (i = 0; i < gi; i++) { - - if ((i & 0xFF) == 0) - lgs8gxx_write_reg(priv, 0x84, 0x03 & (i >> 8)); - lgs8gxx_write_reg(priv, 0x83, i & 0xFF); - - lgs8gxx_read_reg(priv, 0x94, &str); - if (max_strength < str) - max_strength = str; - } - - *signal = max_strength; - dprintk("%s: signal=0x%02X\n", __func__, *signal); - - lgs8gxx_read_reg(priv, 0x95, &t); - dprintk("%s: AVG Noise=0x%02X\n", __func__, t); - - return 0; -} - -static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal) -{ - u8 t; - s16 v = 0; - - dprintk("%s\n", __func__); - - lgs8gxx_read_reg(priv, 0xB1, &t); - v |= t; - v <<= 8; - lgs8gxx_read_reg(priv, 0xB0, &t); - v |= t; - - *signal = v; - dprintk("%s: signal=0x%02X\n", __func__, *signal); - - return 0; -} - -static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal) -{ - struct lgs8gxx_state *priv = fe->demodulator_priv; - - if (priv->config->prod == LGS8GXX_PROD_LGS8913) - return lgs8913_read_signal_strength(priv, signal); - else if (priv->config->prod == LGS8GXX_PROD_LGS8G75) - return lgs8g75_read_signal_strength(priv, signal); - else - return lgs8gxx_read_signal_agc(priv, signal); -} - -static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct lgs8gxx_state *priv = fe->demodulator_priv; - u8 t; - *snr = 0; - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) - lgs8gxx_read_reg(priv, 0x34, &t); - else - lgs8gxx_read_reg(priv, 0x95, &t); - dprintk("AVG Noise=0x%02X\n", t); - *snr = 256 - t; - *snr <<= 8; - dprintk("snr=0x%x\n", *snr); - - return 0; -} - -static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - *ucblocks = 0; - dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks); - return 0; -} - -static void packet_counter_start(struct lgs8gxx_state *priv) -{ - u8 orig, t; - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - lgs8gxx_read_reg(priv, 0x30, &orig); - orig &= 0xE7; - t = orig | 0x10; - lgs8gxx_write_reg(priv, 0x30, t); - t = orig | 0x18; - lgs8gxx_write_reg(priv, 0x30, t); - t = orig | 0x10; - lgs8gxx_write_reg(priv, 0x30, t); - } else { - lgs8gxx_write_reg(priv, 0xC6, 0x01); - lgs8gxx_write_reg(priv, 0xC6, 0x41); - lgs8gxx_write_reg(priv, 0xC6, 0x01); - } -} - -static void packet_counter_stop(struct lgs8gxx_state *priv) -{ - u8 t; - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - lgs8gxx_read_reg(priv, 0x30, &t); - t &= 0xE7; - lgs8gxx_write_reg(priv, 0x30, t); - } else { - lgs8gxx_write_reg(priv, 0xC6, 0x81); - } -} - -static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct lgs8gxx_state *priv = fe->demodulator_priv; - u8 reg_err, reg_total, t; - u32 total_cnt = 0, err_cnt = 0; - int i; - - dprintk("%s\n", __func__); - - packet_counter_start(priv); - msleep(200); - packet_counter_stop(priv); - - if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { - reg_total = 0x28; reg_err = 0x2C; - } else { - reg_total = 0xD0; reg_err = 0xD4; - } - - for (i = 0; i < 4; i++) { - total_cnt <<= 8; - lgs8gxx_read_reg(priv, reg_total+3-i, &t); - total_cnt |= t; - } - for (i = 0; i < 4; i++) { - err_cnt <<= 8; - lgs8gxx_read_reg(priv, reg_err+3-i, &t); - err_cnt |= t; - } - dprintk("error=%d total=%d\n", err_cnt, total_cnt); - - if (total_cnt == 0) - *ber = 0; - else - *ber = err_cnt * 100 / total_cnt; - - dprintk("%s: ber=0x%x\n", __func__, *ber); - return 0; -} - -static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct lgs8gxx_state *priv = fe->demodulator_priv; - - if (priv->config->tuner_address == 0) - return 0; - if (enable) { - u8 v = 0x80 | priv->config->tuner_address; - return lgs8gxx_write_reg(priv, 0x01, v); - } - return lgs8gxx_write_reg(priv, 0x01, 0); -} - -static struct dvb_frontend_ops lgs8gxx_ops = { - .info = { - .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH", - .type = FE_OFDM, - .frequency_min = 474000000, - .frequency_max = 858000000, - .frequency_stepsize = 10000, - .caps = - FE_CAN_FEC_AUTO | - FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO - }, - - .release = lgs8gxx_release, - - .init = lgs8gxx_init, - .write = lgs8gxx_write, - .i2c_gate_ctrl = lgs8gxx_i2c_gate_ctrl, - - .set_frontend = lgs8gxx_set_fe, - .get_frontend = lgs8gxx_get_fe, - .get_tune_settings = lgs8gxx_get_tune_settings, - - .read_status = lgs8gxx_read_status, - .read_ber = lgs8gxx_read_ber, - .read_signal_strength = lgs8gxx_read_signal_strength, - .read_snr = lgs8gxx_read_snr, - .read_ucblocks = lgs8gxx_read_ucblocks, -}; - -struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, - struct i2c_adapter *i2c) -{ - struct lgs8gxx_state *priv = NULL; - u8 data = 0; - - dprintk("%s()\n", __func__); - - if (config == NULL || i2c == NULL) - return NULL; - - priv = kzalloc(sizeof(struct lgs8gxx_state), GFP_KERNEL); - if (priv == NULL) - goto error_out; - - priv->config = config; - priv->i2c = i2c; - - /* check if the demod is there */ - if (lgs8gxx_read_reg(priv, 0, &data) != 0) { - dprintk("%s lgs8gxx not found at i2c addr 0x%02X\n", - __func__, priv->config->demod_address); - goto error_out; - } - - lgs8gxx_read_reg(priv, 1, &data); - - memcpy(&priv->frontend.ops, &lgs8gxx_ops, - sizeof(struct dvb_frontend_ops)); - priv->frontend.demodulator_priv = priv; - - if (config->prod == LGS8GXX_PROD_LGS8G75) - lgs8g75_init_data(priv); - - return &priv->frontend; - -error_out: - dprintk("%s() error_out\n", __func__); - kfree(priv); - return NULL; - -} -EXPORT_SYMBOL(lgs8gxx_attach); - -MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver"); -MODULE_AUTHOR("David T. L. Wong "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* - * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator - * LGS8913, LGS8GL5, LGS8G75 - * experimental support LGS8G42, LGS8G52 - * - * Copyright (C) 2007-2009 David T.L. Wong - * Copyright (C) 2008 Sirius International (Hong Kong) Limited - * Timothy Lee (for initial work on LGS8GL5) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef __LGS8GXX_H__ -#define __LGS8GXX_H__ - -#include -#include - -#define LGS8GXX_PROD_LGS8913 0 -#define LGS8GXX_PROD_LGS8GL5 1 -#define LGS8GXX_PROD_LGS8G42 3 -#define LGS8GXX_PROD_LGS8G52 4 -#define LGS8GXX_PROD_LGS8G54 5 -#define LGS8GXX_PROD_LGS8G75 6 - -struct lgs8gxx_config { - - /* product type */ - u8 prod; - - /* the demodulator's i2c address */ - u8 demod_address; - - /* parallel or serial transport stream */ - u8 serial_ts; - - /* transport stream polarity*/ - u8 ts_clk_pol; - - /* transport stream clock gated by ts_valid */ - u8 ts_clk_gated; - - /* A/D Clock frequency */ - u32 if_clk_freq; /* in kHz */ - - /* IF frequency */ - u32 if_freq; /* in kHz */ - - /*Use External ADC*/ - u8 ext_adc; - - /*External ADC output two's complement*/ - u8 adc_signed; - - /*Sample IF data at falling edge of IF_CLK*/ - u8 if_neg_edge; - - /*IF use Negative center frequency*/ - u8 if_neg_center; - - /*8G75 internal ADC input range selection*/ - /*0: 0.8Vpp, 1: 1.0Vpp, 2: 1.6Vpp, 3: 2.0Vpp*/ - u8 adc_vpp; - - /* slave address and configuration of the tuner */ - u8 tuner_address; -}; - -#if defined(CONFIG_DVB_LGS8GXX) || \ - (defined(CONFIG_DVB_LGS8GXX_MODULE) && defined(MODULE)) -extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, - struct i2c_adapter *i2c); -#else -static inline -struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, - struct i2c_adapter *i2c) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_LGS8GXX */ - -#endif /* __LGS8GXX_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/* - * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator - * LGS8913, LGS8GL5, LGS8G75 - * experimental support LGS8G42, LGS8G52 - * - * Copyright (C) 2007-2009 David T.L. Wong - * Copyright (C) 2008 Sirius International (Hong Kong) Limited - * Timothy Lee (for initial work on LGS8GL5) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef LGS8913_PRIV_H -#define LGS8913_PRIV_H - -struct lgs8gxx_state { - struct i2c_adapter *i2c; - /* configuration settings */ - const struct lgs8gxx_config *config; - struct dvb_frontend frontend; - u16 curr_gi; /* current guard interval */ -}; - -#define SC_MASK 0x1C /* Sub-Carrier Modulation Mask */ -#define SC_QAM64 0x10 /* 64QAM modulation */ -#define SC_QAM32 0x0C /* 32QAM modulation */ -#define SC_QAM16 0x08 /* 16QAM modulation */ -#define SC_QAM4NR 0x04 /* 4QAM-NR modulation */ -#define SC_QAM4 0x00 /* 4QAM modulation */ - -#define LGS_FEC_MASK 0x03 /* FEC Rate Mask */ -#define LGS_FEC_0_4 0x00 /* FEC Rate 0.4 */ -#define LGS_FEC_0_6 0x01 /* FEC Rate 0.6 */ -#define LGS_FEC_0_8 0x02 /* FEC Rate 0.8 */ - -#define TIM_MASK 0x20 /* Time Interleave Length Mask */ -#define TIM_LONG 0x20 /* Time Interleave Length = 720 */ -#define TIM_MIDDLE 0x00 /* Time Interleave Length = 240 */ - -#define CF_MASK 0x80 /* Control Frame Mask */ -#define CF_EN 0x80 /* Control Frame On */ - -#define GI_MASK 0x03 /* Guard Interval Mask */ -#define GI_420 0x00 /* 1/9 Guard Interval */ -#define GI_595 0x01 /* */ -#define GI_945 0x02 /* 1/4 Guard Interval */ - - -#define TS_PARALLEL 0x00 /* Parallel TS Output a.k.a. SPI */ -#define TS_SERIAL 0x01 /* Serial TS Output a.k.a. SSI */ -#define TS_CLK_NORMAL 0x00 /* MPEG Clock Normal */ -#define TS_CLK_INVERTED 0x02 /* MPEG Clock Inverted */ -#define TS_CLK_GATED 0x00 /* MPEG clock gated */ -#define TS_CLK_FREERUN 0x04 /* MPEG clock free running*/ - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbh24.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbh24.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbh24.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbh24.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/* - * lnbh24.h - driver for lnb supply and control ic lnbh24 - * - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _LNBH24_H -#define _LNBH24_H - -/* system register bits */ -#define LNBH24_OLF 0x01 -#define LNBH24_OTF 0x02 -#define LNBH24_EN 0x04 -#define LNBH24_VSEL 0x08 -#define LNBH24_LLC 0x10 -#define LNBH24_TEN 0x20 -#define LNBH24_TTX 0x40 -#define LNBH24_PCL 0x80 - -#include - -#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \ - && defined(MODULE)) -/* override_set and override_clear control which - system register bits (above) to always set & clear */ -extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 override_set, - u8 override_clear, u8 i2c_addr); -#else -static inline struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 override_set, - u8 override_clear, u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbp21.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbp21.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbp21.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbp21.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,188 +0,0 @@ -/* - * lnbp21.c - driver for lnb supply and control ic lnbp21 - * - * Copyright (C) 2006, 2009 Oliver Endriss - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org - */ -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "lnbp21.h" -#include "lnbh24.h" - -struct lnbp21 { - u8 config; - u8 override_or; - u8 override_and; - struct i2c_adapter *i2c; - u8 i2c_addr; -}; - -static int lnbp21_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; - struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, - .buf = &lnbp21->config, - .len = sizeof(lnbp21->config) }; - - lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN); - - switch(voltage) { - case SEC_VOLTAGE_OFF: - break; - case SEC_VOLTAGE_13: - lnbp21->config |= LNBP21_EN; - break; - case SEC_VOLTAGE_18: - lnbp21->config |= (LNBP21_EN | LNBP21_VSEL); - break; - default: - return -EINVAL; - }; - - lnbp21->config |= lnbp21->override_or; - lnbp21->config &= lnbp21->override_and; - - return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; -} - -static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) -{ - struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; - struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, - .buf = &lnbp21->config, - .len = sizeof(lnbp21->config) }; - - if (arg) - lnbp21->config |= LNBP21_LLC; - else - lnbp21->config &= ~LNBP21_LLC; - - lnbp21->config |= lnbp21->override_or; - lnbp21->config &= lnbp21->override_and; - - return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; -} - -static int lnbp21_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t tone) -{ - struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; - struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, - .buf = &lnbp21->config, - .len = sizeof(lnbp21->config) }; - - switch (tone) { - case SEC_TONE_OFF: - lnbp21->config &= ~LNBP21_TEN; - break; - case SEC_TONE_ON: - lnbp21->config |= LNBP21_TEN; - break; - default: - return -EINVAL; - }; - - lnbp21->config |= lnbp21->override_or; - lnbp21->config &= lnbp21->override_and; - - return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; -} - -static void lnbp21_release(struct dvb_frontend *fe) -{ - /* LNBP power off */ - lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF); - - /* free data */ - kfree(fe->sec_priv); - fe->sec_priv = NULL; -} - -static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 override_set, - u8 override_clear, u8 i2c_addr, u8 config) -{ - struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL); - if (!lnbp21) - return NULL; - - /* default configuration */ - lnbp21->config = config; - lnbp21->i2c = i2c; - lnbp21->i2c_addr = i2c_addr; - fe->sec_priv = lnbp21; - - /* bits which should be forced to '1' */ - lnbp21->override_or = override_set; - - /* bits which should be forced to '0' */ - lnbp21->override_and = ~override_clear; - - /* detect if it is present or not */ - if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) { - kfree(lnbp21); - return NULL; - } - - /* install release callback */ - fe->ops.release_sec = lnbp21_release; - - /* override frontend ops */ - fe->ops.set_voltage = lnbp21_set_voltage; - fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; - if (!(override_clear & LNBH24_TEN)) /*22kHz logic controlled by demod*/ - fe->ops.set_tone = lnbp21_set_tone; - printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr); - - return fe; -} - -struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 override_set, - u8 override_clear, u8 i2c_addr) -{ - return lnbx2x_attach(fe, i2c, override_set, override_clear, - i2c_addr, LNBH24_TTX); -} -EXPORT_SYMBOL(lnbh24_attach); - -struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 override_set, - u8 override_clear) -{ - return lnbx2x_attach(fe, i2c, override_set, override_clear, - 0x08, LNBP21_ISEL); -} -EXPORT_SYMBOL(lnbp21_attach); - -MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24"); -MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbp21.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbp21.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbp21.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/lnbp21.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/* - * lnbp21.h - driver for lnb supply and control ic lnbp21 - * - * Copyright (C) 2006 Oliver Endriss - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org - */ - -#ifndef _LNBP21_H -#define _LNBP21_H - -/* system register bits */ -/* [RO] 0=OK; 1=over current limit flag */ -#define LNBP21_OLF 0x01 -/* [RO] 0=OK; 1=over temperature flag (150 C) */ -#define LNBP21_OTF 0x02 -/* [RW] 0=disable LNB power, enable loopthrough - 1=enable LNB power, disable loopthrough */ -#define LNBP21_EN 0x04 -/* [RW] 0=low voltage (13/14V, vert pol) - 1=high voltage (18/19V,horiz pol) */ -#define LNBP21_VSEL 0x08 -/* [RW] increase LNB voltage by 1V: - 0=13/18V; 1=14/19V */ -#define LNBP21_LLC 0x10 -/* [RW] 0=tone controlled by DSQIN pin - 1=tone enable, disable DSQIN */ -#define LNBP21_TEN 0x20 -/* [RW] current limit select: - 0:Iout=500-650mA Isc=300mA - 1:Iout=400-550mA Isc=200mA */ -#define LNBP21_ISEL 0x40 -/* [RW] short-circuit protect: - 0=pulsed (dynamic) curr limiting - 1=static curr limiting */ -#define LNBP21_PCL 0x80 - -#include - -#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \ - && defined(MODULE)) -/* override_set and override_clear control which - system register bits (above) to always set & clear */ -extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 override_set, - u8 override_clear); -#else -static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, u8 override_set, - u8 override_clear) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -# -# Makefile for the kernel DVB frontend device drivers. -# - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners/ - -stb0899-objs = stb0899_drv.o stb0899_algo.o -stv0900-objs = stv0900_core.o stv0900_sw.o -au8522-objs = au8522_dig.o au8522_decoder.o - -obj-$(CONFIG_DVB_PLL) += dvb-pll.o -obj-$(CONFIG_DVB_STV0299) += stv0299.o -obj-$(CONFIG_DVB_STB0899) += stb0899.o -obj-$(CONFIG_DVB_STB6100) += stb6100.o -obj-$(CONFIG_DVB_SP8870) += sp8870.o -obj-$(CONFIG_DVB_CX22700) += cx22700.o -obj-$(CONFIG_DVB_S5H1432) += s5h1432.o -obj-$(CONFIG_DVB_CX24110) += cx24110.o -obj-$(CONFIG_DVB_TDA8083) += tda8083.o -obj-$(CONFIG_DVB_L64781) += l64781.o -obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o -obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o -obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o -obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o -obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o -obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o -obj-$(CONFIG_DVB_MT312) += mt312.o -obj-$(CONFIG_DVB_VES1820) += ves1820.o -obj-$(CONFIG_DVB_VES1X93) += ves1x93.o -obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o -obj-$(CONFIG_DVB_SP887X) += sp887x.o -obj-$(CONFIG_DVB_NXT6000) += nxt6000.o -obj-$(CONFIG_DVB_MT352) += mt352.o -obj-$(CONFIG_DVB_ZL10036) += zl10036.o -obj-$(CONFIG_DVB_ZL10039) += zl10039.o -obj-$(CONFIG_DVB_ZL10353) += zl10353.o -obj-$(CONFIG_DVB_CX22702) += cx22702.o -obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o -obj-$(CONFIG_DVB_TDA10021) += tda10021.o -obj-$(CONFIG_DVB_TDA10023) += tda10023.o -obj-$(CONFIG_DVB_STV0297) += stv0297.o -obj-$(CONFIG_DVB_NXT200X) += nxt200x.o -obj-$(CONFIG_DVB_OR51211) += or51211.o -obj-$(CONFIG_DVB_OR51132) += or51132.o -obj-$(CONFIG_DVB_BCM3510) += bcm3510.o -obj-$(CONFIG_DVB_S5H1420) += s5h1420.o -obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o -obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o -obj-$(CONFIG_DVB_CX24123) += cx24123.o -obj-$(CONFIG_DVB_LNBP21) += lnbp21.o -obj-$(CONFIG_DVB_ISL6405) += isl6405.o -obj-$(CONFIG_DVB_ISL6421) += isl6421.o -obj-$(CONFIG_DVB_TDA10086) += tda10086.o -obj-$(CONFIG_DVB_TDA826X) += tda826x.o -obj-$(CONFIG_DVB_TDA8261) += tda8261.o -obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o -obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o -obj-$(CONFIG_DVB_TUA6100) += tua6100.o -obj-$(CONFIG_DVB_S5H1409) += s5h1409.o -obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o -obj-$(CONFIG_DVB_AU8522) += au8522.o -obj-$(CONFIG_DVB_TDA10048) += tda10048.o -obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o -obj-$(CONFIG_DVB_S5H1411) += s5h1411.o -obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o -obj-$(CONFIG_DVB_TDA665x) += tda665x.o -obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o -obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o -obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o -obj-$(CONFIG_DVB_AF9013) += af9013.o -obj-$(CONFIG_DVB_CX24116) += cx24116.o -obj-$(CONFIG_DVB_SI21XX) += si21xx.o -obj-$(CONFIG_DVB_STV0288) += stv0288.o -obj-$(CONFIG_DVB_STB6000) += stb6000.o -obj-$(CONFIG_DVB_S921) += s921.o -obj-$(CONFIG_DVB_STV6110) += stv6110.o -obj-$(CONFIG_DVB_STV0900) += stv0900.o -obj-$(CONFIG_DVB_STV090x) += stv090x.o -obj-$(CONFIG_DVB_STV6110x) += stv6110x.o -obj-$(CONFIG_DVB_ISL6423) += isl6423.o -obj-$(CONFIG_DVB_EC100) += ec100.o -obj-$(CONFIG_DVB_DS3000) += ds3000.o -obj-$(CONFIG_DVB_MB86A16) += mb86a16.o -obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o -obj-$(CONFIG_DVB_IX2505V) += ix2505v.o -obj-$(CONFIG_DVB_STV0367) += stv0367.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1878 +0,0 @@ -/* - Fujitsu MB86A16 DVB-S/DSS DC Receiver driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "mb86a16.h" -#include "mb86a16_priv.h" - -unsigned int verbose = 5; -module_param(verbose, int, 0644); - -#define ABS(x) ((x) < 0 ? (-x) : (x)) - -struct mb86a16_state { - struct i2c_adapter *i2c_adap; - const struct mb86a16_config *config; - struct dvb_frontend frontend; - - /* tuning parameters */ - int frequency; - int srate; - - /* Internal stuff */ - int master_clk; - int deci; - int csel; - int rsel; -}; - -#define MB86A16_ERROR 0 -#define MB86A16_NOTICE 1 -#define MB86A16_INFO 2 -#define MB86A16_DEBUG 3 - -#define dprintk(x, y, z, format, arg...) do { \ - if (z) { \ - if ((x > MB86A16_ERROR) && (x > y)) \ - printk(KERN_ERR "%s: " format "\n", __func__, ##arg); \ - else if ((x > MB86A16_NOTICE) && (x > y)) \ - printk(KERN_NOTICE "%s: " format "\n", __func__, ##arg); \ - else if ((x > MB86A16_INFO) && (x > y)) \ - printk(KERN_INFO "%s: " format "\n", __func__, ##arg); \ - else if ((x > MB86A16_DEBUG) && (x > y)) \ - printk(KERN_DEBUG "%s: " format "\n", __func__, ##arg); \ - } else { \ - if (x > y) \ - printk(format, ##arg); \ - } \ -} while (0) - -#define TRACE_IN dprintk(verbose, MB86A16_DEBUG, 1, "-->()") -#define TRACE_OUT dprintk(verbose, MB86A16_DEBUG, 1, "()-->") - -static int mb86a16_write(struct mb86a16_state *state, u8 reg, u8 val) -{ - int ret; - u8 buf[] = { reg, val }; - - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf, - .len = 2 - }; - - dprintk(verbose, MB86A16_DEBUG, 1, - "writing to [0x%02x],Reg[0x%02x],Data[0x%02x]", - state->config->demod_address, buf[0], buf[1]); - - ret = i2c_transfer(state->i2c_adap, &msg, 1); - - return (ret != 1) ? -EREMOTEIO : 0; -} - -static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - - struct i2c_msg msg[] = { - { - .addr = state->config->demod_address, - .flags = 0, - .buf = b0, - .len = 1 - }, { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = b1, - .len = 1 - } - }; - ret = i2c_transfer(state->i2c_adap, msg, 2); - if (ret != 2) { - dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)", - reg, ret); - - return -EREMOTEIO; - } - *val = b1[0]; - - return ret; -} - -static int CNTM_set(struct mb86a16_state *state, - unsigned char timint1, - unsigned char timint2, - unsigned char cnext) -{ - unsigned char val; - - val = (timint1 << 4) | (timint2 << 2) | cnext; - if (mb86a16_write(state, MB86A16_CNTMR, val) < 0) - goto err; - - return 0; - -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int smrt_set(struct mb86a16_state *state, int rate) -{ - int tmp ; - int m ; - unsigned char STOFS0, STOFS1; - - m = 1 << state->deci; - tmp = (8192 * state->master_clk - 2 * m * rate * 8192 + state->master_clk / 2) / state->master_clk; - - STOFS0 = tmp & 0x0ff; - STOFS1 = (tmp & 0xf00) >> 8; - - if (mb86a16_write(state, MB86A16_SRATE1, (state->deci << 2) | - (state->csel << 1) | - state->rsel) < 0) - goto err; - if (mb86a16_write(state, MB86A16_SRATE2, STOFS0) < 0) - goto err; - if (mb86a16_write(state, MB86A16_SRATE3, STOFS1) < 0) - goto err; - - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -1; -} - -static int srst(struct mb86a16_state *state) -{ - if (mb86a16_write(state, MB86A16_RESET, 0x04) < 0) - goto err; - - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - -} - -static int afcex_data_set(struct mb86a16_state *state, - unsigned char AFCEX_L, - unsigned char AFCEX_H) -{ - if (mb86a16_write(state, MB86A16_AFCEXL, AFCEX_L) < 0) - goto err; - if (mb86a16_write(state, MB86A16_AFCEXH, AFCEX_H) < 0) - goto err; - - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - - return -1; -} - -static int afcofs_data_set(struct mb86a16_state *state, - unsigned char AFCEX_L, - unsigned char AFCEX_H) -{ - if (mb86a16_write(state, 0x58, AFCEX_L) < 0) - goto err; - if (mb86a16_write(state, 0x59, AFCEX_H) < 0) - goto err; - - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int stlp_set(struct mb86a16_state *state, - unsigned char STRAS, - unsigned char STRBS) -{ - if (mb86a16_write(state, MB86A16_STRFILTCOEF1, (STRBS << 3) | (STRAS)) < 0) - goto err; - - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int Vi_set(struct mb86a16_state *state, unsigned char ETH, unsigned char VIA) -{ - if (mb86a16_write(state, MB86A16_VISET2, 0x04) < 0) - goto err; - if (mb86a16_write(state, MB86A16_VISET3, 0xf5) < 0) - goto err; - - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int initial_set(struct mb86a16_state *state) -{ - if (stlp_set(state, 5, 7)) - goto err; - - udelay(100); - if (afcex_data_set(state, 0, 0)) - goto err; - - udelay(100); - if (afcofs_data_set(state, 0, 0)) - goto err; - - udelay(100); - if (mb86a16_write(state, MB86A16_CRLFILTCOEF1, 0x16) < 0) - goto err; - if (mb86a16_write(state, 0x2f, 0x21) < 0) - goto err; - if (mb86a16_write(state, MB86A16_VIMAG, 0x38) < 0) - goto err; - if (mb86a16_write(state, MB86A16_FAGCS1, 0x00) < 0) - goto err; - if (mb86a16_write(state, MB86A16_FAGCS2, 0x1c) < 0) - goto err; - if (mb86a16_write(state, MB86A16_FAGCS3, 0x20) < 0) - goto err; - if (mb86a16_write(state, MB86A16_FAGCS4, 0x1e) < 0) - goto err; - if (mb86a16_write(state, MB86A16_FAGCS5, 0x23) < 0) - goto err; - if (mb86a16_write(state, 0x54, 0xff) < 0) - goto err; - if (mb86a16_write(state, MB86A16_TSOUT, 0x00) < 0) - goto err; - - return 0; - -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int S01T_set(struct mb86a16_state *state, - unsigned char s1t, - unsigned s0t) -{ - if (mb86a16_write(state, 0x33, (s1t << 3) | s0t) < 0) - goto err; - - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - - -static int EN_set(struct mb86a16_state *state, - int cren, - int afcen) -{ - unsigned char val; - - val = 0x7a | (cren << 7) | (afcen << 2); - if (mb86a16_write(state, 0x49, val) < 0) - goto err; - - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int AFCEXEN_set(struct mb86a16_state *state, - int afcexen, - int smrt) -{ - unsigned char AFCA ; - - if (smrt > 18875) - AFCA = 4; - else if (smrt > 9375) - AFCA = 3; - else if (smrt > 2250) - AFCA = 2; - else - AFCA = 1; - - if (mb86a16_write(state, 0x2a, 0x02 | (afcexen << 5) | (AFCA << 2)) < 0) - goto err; - - return 0; - -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int DAGC_data_set(struct mb86a16_state *state, - unsigned char DAGCA, - unsigned char DAGCW) -{ - if (mb86a16_write(state, 0x2d, (DAGCA << 3) | DAGCW) < 0) - goto err; - - return 0; - -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static void smrt_info_get(struct mb86a16_state *state, int rate) -{ - if (rate >= 37501) { - state->deci = 0; state->csel = 0; state->rsel = 0; - } else if (rate >= 30001) { - state->deci = 0; state->csel = 0; state->rsel = 1; - } else if (rate >= 26251) { - state->deci = 0; state->csel = 1; state->rsel = 0; - } else if (rate >= 22501) { - state->deci = 0; state->csel = 1; state->rsel = 1; - } else if (rate >= 18751) { - state->deci = 1; state->csel = 0; state->rsel = 0; - } else if (rate >= 15001) { - state->deci = 1; state->csel = 0; state->rsel = 1; - } else if (rate >= 13126) { - state->deci = 1; state->csel = 1; state->rsel = 0; - } else if (rate >= 11251) { - state->deci = 1; state->csel = 1; state->rsel = 1; - } else if (rate >= 9376) { - state->deci = 2; state->csel = 0; state->rsel = 0; - } else if (rate >= 7501) { - state->deci = 2; state->csel = 0; state->rsel = 1; - } else if (rate >= 6563) { - state->deci = 2; state->csel = 1; state->rsel = 0; - } else if (rate >= 5626) { - state->deci = 2; state->csel = 1; state->rsel = 1; - } else if (rate >= 4688) { - state->deci = 3; state->csel = 0; state->rsel = 0; - } else if (rate >= 3751) { - state->deci = 3; state->csel = 0; state->rsel = 1; - } else if (rate >= 3282) { - state->deci = 3; state->csel = 1; state->rsel = 0; - } else if (rate >= 2814) { - state->deci = 3; state->csel = 1; state->rsel = 1; - } else if (rate >= 2344) { - state->deci = 4; state->csel = 0; state->rsel = 0; - } else if (rate >= 1876) { - state->deci = 4; state->csel = 0; state->rsel = 1; - } else if (rate >= 1641) { - state->deci = 4; state->csel = 1; state->rsel = 0; - } else if (rate >= 1407) { - state->deci = 4; state->csel = 1; state->rsel = 1; - } else if (rate >= 1172) { - state->deci = 5; state->csel = 0; state->rsel = 0; - } else if (rate >= 939) { - state->deci = 5; state->csel = 0; state->rsel = 1; - } else if (rate >= 821) { - state->deci = 5; state->csel = 1; state->rsel = 0; - } else { - state->deci = 5; state->csel = 1; state->rsel = 1; - } - - if (state->csel == 0) - state->master_clk = 92000; - else - state->master_clk = 61333; - -} - -static int signal_det(struct mb86a16_state *state, - int smrt, - unsigned char *SIG) -{ - - int ret ; - int smrtd ; - int wait_sym ; - - u32 wait_t; - unsigned char S[3] ; - int i ; - - if (*SIG > 45) { - if (CNTM_set(state, 2, 1, 2) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); - return -1; - } - wait_sym = 40000; - } else { - if (CNTM_set(state, 3, 1, 2) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); - return -1; - } - wait_sym = 80000; - } - for (i = 0; i < 3; i++) { - if (i == 0) - smrtd = smrt * 98 / 100; - else if (i == 1) - smrtd = smrt; - else - smrtd = smrt * 102 / 100; - smrt_info_get(state, smrtd); - smrt_set(state, smrtd); - srst(state); - wait_t = (wait_sym + 99 * smrtd / 100) / smrtd; - if (wait_t == 0) - wait_t = 1; - msleep_interruptible(10); - if (mb86a16_read(state, 0x37, &(S[i])) != 2) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - } - if ((S[1] > S[0] * 112 / 100) && - (S[1] > S[2] * 112 / 100)) { - - ret = 1; - } else { - ret = 0; - } - *SIG = S[1]; - - if (CNTM_set(state, 0, 1, 2) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); - return -1; - } - - return ret; -} - -static int rf_val_set(struct mb86a16_state *state, - int f, - int smrt, - unsigned char R) -{ - unsigned char C, F, B; - int M; - unsigned char rf_val[5]; - int ack = -1; - - if (smrt > 37750) - C = 1; - else if (smrt > 18875) - C = 2; - else if (smrt > 5500) - C = 3; - else - C = 4; - - if (smrt > 30500) - F = 3; - else if (smrt > 9375) - F = 1; - else if (smrt > 4625) - F = 0; - else - F = 2; - - if (f < 1060) - B = 0; - else if (f < 1175) - B = 1; - else if (f < 1305) - B = 2; - else if (f < 1435) - B = 3; - else if (f < 1570) - B = 4; - else if (f < 1715) - B = 5; - else if (f < 1845) - B = 6; - else if (f < 1980) - B = 7; - else if (f < 2080) - B = 8; - else - B = 9; - - M = f * (1 << R) / 2; - - rf_val[0] = 0x01 | (C << 3) | (F << 1); - rf_val[1] = (R << 5) | ((M & 0x1f000) >> 12); - rf_val[2] = (M & 0x00ff0) >> 4; - rf_val[3] = ((M & 0x0000f) << 4) | B; - - /* Frequency Set */ - if (mb86a16_write(state, 0x21, rf_val[0]) < 0) - ack = 0; - if (mb86a16_write(state, 0x22, rf_val[1]) < 0) - ack = 0; - if (mb86a16_write(state, 0x23, rf_val[2]) < 0) - ack = 0; - if (mb86a16_write(state, 0x24, rf_val[3]) < 0) - ack = 0; - if (mb86a16_write(state, 0x25, 0x01) < 0) - ack = 0; - if (ack == 0) { - dprintk(verbose, MB86A16_ERROR, 1, "RF Setup - I2C transfer error"); - return -EREMOTEIO; - } - - return 0; -} - -static int afcerr_chk(struct mb86a16_state *state) -{ - unsigned char AFCM_L, AFCM_H ; - int AFCM ; - int afcm, afcerr ; - - if (mb86a16_read(state, 0x0e, &AFCM_L) != 2) - goto err; - if (mb86a16_read(state, 0x0f, &AFCM_H) != 2) - goto err; - - AFCM = (AFCM_H << 8) + AFCM_L; - - if (AFCM > 2048) - afcm = AFCM - 4096; - else - afcm = AFCM; - afcerr = afcm * state->master_clk / 8192; - - return afcerr; - -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int dagcm_val_get(struct mb86a16_state *state) -{ - int DAGCM; - unsigned char DAGCM_H, DAGCM_L; - - if (mb86a16_read(state, 0x45, &DAGCM_L) != 2) - goto err; - if (mb86a16_read(state, 0x46, &DAGCM_H) != 2) - goto err; - - DAGCM = (DAGCM_H << 8) + DAGCM_L; - - return DAGCM; - -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - u8 stat, stat2; - struct mb86a16_state *state = fe->demodulator_priv; - - *status = 0; - - if (mb86a16_read(state, MB86A16_SIG1, &stat) != 2) - goto err; - if (mb86a16_read(state, MB86A16_SIG2, &stat2) != 2) - goto err; - if ((stat > 25) && (stat2 > 25)) - *status |= FE_HAS_SIGNAL; - if ((stat > 45) && (stat2 > 45)) - *status |= FE_HAS_CARRIER; - - if (mb86a16_read(state, MB86A16_STATUS, &stat) != 2) - goto err; - - if (stat & 0x01) - *status |= FE_HAS_SYNC; - if (stat & 0x01) - *status |= FE_HAS_VITERBI; - - if (mb86a16_read(state, MB86A16_FRAMESYNC, &stat) != 2) - goto err; - - if ((stat & 0x0f) && (*status & FE_HAS_VITERBI)) - *status |= FE_HAS_LOCK; - - return 0; - -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int sync_chk(struct mb86a16_state *state, - unsigned char *VIRM) -{ - unsigned char val; - int sync; - - if (mb86a16_read(state, 0x0d, &val) != 2) - goto err; - - dprintk(verbose, MB86A16_INFO, 1, "Status = %02x,", val); - sync = val & 0x01; - *VIRM = (val & 0x1c) >> 2; - - return sync; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - -} - -static int freqerr_chk(struct mb86a16_state *state, - int fTP, - int smrt, - int unit) -{ - unsigned char CRM, AFCML, AFCMH; - unsigned char temp1, temp2, temp3; - int crm, afcm, AFCM; - int crrerr, afcerr; /* kHz */ - int frqerr; /* MHz */ - int afcen, afcexen = 0; - int R, M, fOSC, fOSC_OFS; - - if (mb86a16_read(state, 0x43, &CRM) != 2) - goto err; - - if (CRM > 127) - crm = CRM - 256; - else - crm = CRM; - - crrerr = smrt * crm / 256; - if (mb86a16_read(state, 0x49, &temp1) != 2) - goto err; - - afcen = (temp1 & 0x04) >> 2; - if (afcen == 0) { - if (mb86a16_read(state, 0x2a, &temp1) != 2) - goto err; - afcexen = (temp1 & 0x20) >> 5; - } - - if (afcen == 1) { - if (mb86a16_read(state, 0x0e, &AFCML) != 2) - goto err; - if (mb86a16_read(state, 0x0f, &AFCMH) != 2) - goto err; - } else if (afcexen == 1) { - if (mb86a16_read(state, 0x2b, &AFCML) != 2) - goto err; - if (mb86a16_read(state, 0x2c, &AFCMH) != 2) - goto err; - } - if ((afcen == 1) || (afcexen == 1)) { - smrt_info_get(state, smrt); - AFCM = ((AFCMH & 0x01) << 8) + AFCML; - if (AFCM > 255) - afcm = AFCM - 512; - else - afcm = AFCM; - - afcerr = afcm * state->master_clk / 8192; - } else - afcerr = 0; - - if (mb86a16_read(state, 0x22, &temp1) != 2) - goto err; - if (mb86a16_read(state, 0x23, &temp2) != 2) - goto err; - if (mb86a16_read(state, 0x24, &temp3) != 2) - goto err; - - R = (temp1 & 0xe0) >> 5; - M = ((temp1 & 0x1f) << 12) + (temp2 << 4) + (temp3 >> 4); - if (R == 0) - fOSC = 2 * M; - else - fOSC = M; - - fOSC_OFS = fOSC - fTP; - - if (unit == 0) { /* MHz */ - if (crrerr + afcerr + fOSC_OFS * 1000 >= 0) - frqerr = (crrerr + afcerr + fOSC_OFS * 1000 + 500) / 1000; - else - frqerr = (crrerr + afcerr + fOSC_OFS * 1000 - 500) / 1000; - } else { /* kHz */ - frqerr = crrerr + afcerr + fOSC_OFS * 1000; - } - - return frqerr; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static unsigned char vco_dev_get(struct mb86a16_state *state, int smrt) -{ - unsigned char R; - - if (smrt > 9375) - R = 0; - else - R = 1; - - return R; -} - -static void swp_info_get(struct mb86a16_state *state, - int fOSC_start, - int smrt, - int v, int R, - int swp_ofs, - int *fOSC, - int *afcex_freq, - unsigned char *AFCEX_L, - unsigned char *AFCEX_H) -{ - int AFCEX ; - int crnt_swp_freq ; - - crnt_swp_freq = fOSC_start * 1000 + v * swp_ofs; - - if (R == 0) - *fOSC = (crnt_swp_freq + 1000) / 2000 * 2; - else - *fOSC = (crnt_swp_freq + 500) / 1000; - - if (*fOSC >= crnt_swp_freq) - *afcex_freq = *fOSC * 1000 - crnt_swp_freq; - else - *afcex_freq = crnt_swp_freq - *fOSC * 1000; - - AFCEX = *afcex_freq * 8192 / state->master_clk; - *AFCEX_L = AFCEX & 0x00ff; - *AFCEX_H = (AFCEX & 0x0f00) >> 8; -} - - -static int swp_freq_calcuation(struct mb86a16_state *state, int i, int v, int *V, int vmax, int vmin, - int SIGMIN, int fOSC, int afcex_freq, int swp_ofs, unsigned char *SIG1) -{ - int swp_freq ; - - if ((i % 2 == 1) && (v <= vmax)) { - /* positive v (case 1) */ - if ((v - 1 == vmin) && - (*(V + 30 + v) >= 0) && - (*(V + 30 + v - 1) >= 0) && - (*(V + 30 + v - 1) > *(V + 30 + v)) && - (*(V + 30 + v - 1) > SIGMIN)) { - - swp_freq = fOSC * 1000 + afcex_freq - swp_ofs; - *SIG1 = *(V + 30 + v - 1); - } else if ((v == vmax) && - (*(V + 30 + v) >= 0) && - (*(V + 30 + v - 1) >= 0) && - (*(V + 30 + v) > *(V + 30 + v - 1)) && - (*(V + 30 + v) > SIGMIN)) { - /* (case 2) */ - swp_freq = fOSC * 1000 + afcex_freq; - *SIG1 = *(V + 30 + v); - } else if ((*(V + 30 + v) > 0) && - (*(V + 30 + v - 1) > 0) && - (*(V + 30 + v - 2) > 0) && - (*(V + 30 + v - 3) > 0) && - (*(V + 30 + v - 1) > *(V + 30 + v)) && - (*(V + 30 + v - 2) > *(V + 30 + v - 3)) && - ((*(V + 30 + v - 1) > SIGMIN) || - (*(V + 30 + v - 2) > SIGMIN))) { - /* (case 3) */ - if (*(V + 30 + v - 1) >= *(V + 30 + v - 2)) { - swp_freq = fOSC * 1000 + afcex_freq - swp_ofs; - *SIG1 = *(V + 30 + v - 1); - } else { - swp_freq = fOSC * 1000 + afcex_freq - swp_ofs * 2; - *SIG1 = *(V + 30 + v - 2); - } - } else if ((v == vmax) && - (*(V + 30 + v) >= 0) && - (*(V + 30 + v - 1) >= 0) && - (*(V + 30 + v - 2) >= 0) && - (*(V + 30 + v) > *(V + 30 + v - 2)) && - (*(V + 30 + v - 1) > *(V + 30 + v - 2)) && - ((*(V + 30 + v) > SIGMIN) || - (*(V + 30 + v - 1) > SIGMIN))) { - /* (case 4) */ - if (*(V + 30 + v) >= *(V + 30 + v - 1)) { - swp_freq = fOSC * 1000 + afcex_freq; - *SIG1 = *(V + 30 + v); - } else { - swp_freq = fOSC * 1000 + afcex_freq - swp_ofs; - *SIG1 = *(V + 30 + v - 1); - } - } else { - swp_freq = -1 ; - } - } else if ((i % 2 == 0) && (v >= vmin)) { - /* Negative v (case 1) */ - if ((*(V + 30 + v) > 0) && - (*(V + 30 + v + 1) > 0) && - (*(V + 30 + v + 2) > 0) && - (*(V + 30 + v + 1) > *(V + 30 + v)) && - (*(V + 30 + v + 1) > *(V + 30 + v + 2)) && - (*(V + 30 + v + 1) > SIGMIN)) { - - swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; - *SIG1 = *(V + 30 + v + 1); - } else if ((v + 1 == vmax) && - (*(V + 30 + v) >= 0) && - (*(V + 30 + v + 1) >= 0) && - (*(V + 30 + v + 1) > *(V + 30 + v)) && - (*(V + 30 + v + 1) > SIGMIN)) { - /* (case 2) */ - swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; - *SIG1 = *(V + 30 + v); - } else if ((v == vmin) && - (*(V + 30 + v) > 0) && - (*(V + 30 + v + 1) > 0) && - (*(V + 30 + v + 2) > 0) && - (*(V + 30 + v) > *(V + 30 + v + 1)) && - (*(V + 30 + v) > *(V + 30 + v + 2)) && - (*(V + 30 + v) > SIGMIN)) { - /* (case 3) */ - swp_freq = fOSC * 1000 + afcex_freq; - *SIG1 = *(V + 30 + v); - } else if ((*(V + 30 + v) >= 0) && - (*(V + 30 + v + 1) >= 0) && - (*(V + 30 + v + 2) >= 0) && - (*(V + 30 + v + 3) >= 0) && - (*(V + 30 + v + 1) > *(V + 30 + v)) && - (*(V + 30 + v + 2) > *(V + 30 + v + 3)) && - ((*(V + 30 + v + 1) > SIGMIN) || - (*(V + 30 + v + 2) > SIGMIN))) { - /* (case 4) */ - if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) { - swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; - *SIG1 = *(V + 30 + v + 1); - } else { - swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2; - *SIG1 = *(V + 30 + v + 2); - } - } else if ((*(V + 30 + v) >= 0) && - (*(V + 30 + v + 1) >= 0) && - (*(V + 30 + v + 2) >= 0) && - (*(V + 30 + v + 3) >= 0) && - (*(V + 30 + v) > *(V + 30 + v + 2)) && - (*(V + 30 + v + 1) > *(V + 30 + v + 2)) && - (*(V + 30 + v) > *(V + 30 + v + 3)) && - (*(V + 30 + v + 1) > *(V + 30 + v + 3)) && - ((*(V + 30 + v) > SIGMIN) || - (*(V + 30 + v + 1) > SIGMIN))) { - /* (case 5) */ - if (*(V + 30 + v) >= *(V + 30 + v + 1)) { - swp_freq = fOSC * 1000 + afcex_freq; - *SIG1 = *(V + 30 + v); - } else { - swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; - *SIG1 = *(V + 30 + v + 1); - } - } else if ((v + 2 == vmin) && - (*(V + 30 + v) >= 0) && - (*(V + 30 + v + 1) >= 0) && - (*(V + 30 + v + 2) >= 0) && - (*(V + 30 + v + 1) > *(V + 30 + v)) && - (*(V + 30 + v + 2) > *(V + 30 + v)) && - ((*(V + 30 + v + 1) > SIGMIN) || - (*(V + 30 + v + 2) > SIGMIN))) { - /* (case 6) */ - if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) { - swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; - *SIG1 = *(V + 30 + v + 1); - } else { - swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2; - *SIG1 = *(V + 30 + v + 2); - } - } else if ((vmax == 0) && (vmin == 0) && (*(V + 30 + v) > SIGMIN)) { - swp_freq = fOSC * 1000; - *SIG1 = *(V + 30 + v); - } else - swp_freq = -1; - } else - swp_freq = -1; - - return swp_freq; -} - -static void swp_info_get2(struct mb86a16_state *state, - int smrt, - int R, - int swp_freq, - int *afcex_freq, - int *fOSC, - unsigned char *AFCEX_L, - unsigned char *AFCEX_H) -{ - int AFCEX ; - - if (R == 0) - *fOSC = (swp_freq + 1000) / 2000 * 2; - else - *fOSC = (swp_freq + 500) / 1000; - - if (*fOSC >= swp_freq) - *afcex_freq = *fOSC * 1000 - swp_freq; - else - *afcex_freq = swp_freq - *fOSC * 1000; - - AFCEX = *afcex_freq * 8192 / state->master_clk; - *AFCEX_L = AFCEX & 0x00ff; - *AFCEX_H = (AFCEX & 0x0f00) >> 8; -} - -static void afcex_info_get(struct mb86a16_state *state, - int afcex_freq, - unsigned char *AFCEX_L, - unsigned char *AFCEX_H) -{ - int AFCEX ; - - AFCEX = afcex_freq * 8192 / state->master_clk; - *AFCEX_L = AFCEX & 0x00ff; - *AFCEX_H = (AFCEX & 0x0f00) >> 8; -} - -static int SEQ_set(struct mb86a16_state *state, unsigned char loop) -{ - /* SLOCK0 = 0 */ - if (mb86a16_write(state, 0x32, 0x02 | (loop << 2)) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - - return 0; -} - -static int iq_vt_set(struct mb86a16_state *state, unsigned char IQINV) -{ - /* Viterbi Rate, IQ Settings */ - if (mb86a16_write(state, 0x06, 0xdf | (IQINV << 5)) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - - return 0; -} - -static int FEC_srst(struct mb86a16_state *state) -{ - if (mb86a16_write(state, MB86A16_RESET, 0x02) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - - return 0; -} - -static int S2T_set(struct mb86a16_state *state, unsigned char S2T) -{ - if (mb86a16_write(state, 0x34, 0x70 | S2T) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - - return 0; -} - -static int S45T_set(struct mb86a16_state *state, unsigned char S4T, unsigned char S5T) -{ - if (mb86a16_write(state, 0x35, 0x00 | (S5T << 4) | S4T) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - - return 0; -} - - -static int mb86a16_set_fe(struct mb86a16_state *state) -{ - u8 agcval, cnmval; - - int i, j; - int fOSC = 0; - int fOSC_start = 0; - int wait_t; - int fcp; - int swp_ofs; - int V[60]; - u8 SIG1MIN; - - unsigned char CREN, AFCEN, AFCEXEN; - unsigned char SIG1; - unsigned char TIMINT1, TIMINT2, TIMEXT; - unsigned char S0T, S1T; - unsigned char S2T; -/* unsigned char S2T, S3T; */ - unsigned char S4T, S5T; - unsigned char AFCEX_L, AFCEX_H; - unsigned char R; - unsigned char VIRM; - unsigned char ETH, VIA; - unsigned char junk; - - int loop; - int ftemp; - int v, vmax, vmin; - int vmax_his, vmin_his; - int swp_freq, prev_swp_freq[20]; - int prev_freq_num; - int signal_dupl; - int afcex_freq; - int signal; - int afcerr; - int temp_freq, delta_freq; - int dagcm[4]; - int smrt_d; -/* int freq_err; */ - int n; - int ret = -1; - int sync; - - dprintk(verbose, MB86A16_INFO, 1, "freq=%d Mhz, symbrt=%d Ksps", state->frequency, state->srate); - - fcp = 3000; - swp_ofs = state->srate / 4; - - for (i = 0; i < 60; i++) - V[i] = -1; - - for (i = 0; i < 20; i++) - prev_swp_freq[i] = 0; - - SIG1MIN = 25; - - for (n = 0; ((n < 3) && (ret == -1)); n++) { - SEQ_set(state, 0); - iq_vt_set(state, 0); - - CREN = 0; - AFCEN = 0; - AFCEXEN = 1; - TIMINT1 = 0; - TIMINT2 = 1; - TIMEXT = 2; - S1T = 0; - S0T = 0; - - if (initial_set(state) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "initial set failed"); - return -1; - } - if (DAGC_data_set(state, 3, 2) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error"); - return -1; - } - if (EN_set(state, CREN, AFCEN) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "EN set error"); - return -1; /* (0, 0) */ - } - if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); - return -1; /* (1, smrt) = (1, symbolrate) */ - } - if (CNTM_set(state, TIMINT1, TIMINT2, TIMEXT) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "CNTM set error"); - return -1; /* (0, 1, 2) */ - } - if (S01T_set(state, S1T, S0T) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "S01T set error"); - return -1; /* (0, 0) */ - } - smrt_info_get(state, state->srate); - if (smrt_set(state, state->srate) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "smrt info get error"); - return -1; - } - - R = vco_dev_get(state, state->srate); - if (R == 1) - fOSC_start = state->frequency; - - else if (R == 0) { - if (state->frequency % 2 == 0) { - fOSC_start = state->frequency; - } else { - fOSC_start = state->frequency + 1; - if (fOSC_start > 2150) - fOSC_start = state->frequency - 1; - } - } - loop = 1; - ftemp = fOSC_start * 1000; - vmax = 0 ; - while (loop == 1) { - ftemp = ftemp + swp_ofs; - vmax++; - - /* Upper bound */ - if (ftemp > 2150000) { - loop = 0; - vmax--; - } else { - if ((ftemp == 2150000) || - (ftemp - state->frequency * 1000 >= fcp + state->srate / 4)) - loop = 0; - } - } - - loop = 1; - ftemp = fOSC_start * 1000; - vmin = 0 ; - while (loop == 1) { - ftemp = ftemp - swp_ofs; - vmin--; - - /* Lower bound */ - if (ftemp < 950000) { - loop = 0; - vmin++; - } else { - if ((ftemp == 950000) || - (state->frequency * 1000 - ftemp >= fcp + state->srate / 4)) - loop = 0; - } - } - - wait_t = (8000 + state->srate / 2) / state->srate; - if (wait_t == 0) - wait_t = 1; - - i = 0; - j = 0; - prev_freq_num = 0; - loop = 1; - signal = 0; - vmax_his = 0; - vmin_his = 0; - v = 0; - - while (loop == 1) { - swp_info_get(state, fOSC_start, state->srate, - v, R, swp_ofs, &fOSC, - &afcex_freq, &AFCEX_L, &AFCEX_H); - - udelay(100); - if (rf_val_set(state, fOSC, state->srate, R) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); - return -1; - } - udelay(100); - if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); - return -1; - } - if (srst(state) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "srst error"); - return -1; - } - msleep_interruptible(wait_t); - - if (mb86a16_read(state, 0x37, &SIG1) != 2) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -1; - } - V[30 + v] = SIG1 ; - swp_freq = swp_freq_calcuation(state, i, v, V, vmax, vmin, - SIG1MIN, fOSC, afcex_freq, - swp_ofs, &SIG1); /* changed */ - - signal_dupl = 0; - for (j = 0; j < prev_freq_num; j++) { - if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) { - signal_dupl = 1; - dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j); - } - } - if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) { - dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate); - prev_swp_freq[prev_freq_num] = swp_freq; - prev_freq_num++; - swp_info_get2(state, state->srate, R, swp_freq, - &afcex_freq, &fOSC, - &AFCEX_L, &AFCEX_H); - - if (rf_val_set(state, fOSC, state->srate, R) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); - return -1; - } - if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); - return -1; - } - signal = signal_det(state, state->srate, &SIG1); - if (signal == 1) { - dprintk(verbose, MB86A16_ERROR, 1, "***** Signal Found *****"); - loop = 0; - } else { - dprintk(verbose, MB86A16_ERROR, 1, "!!!!! No signal !!!!!, try again..."); - smrt_info_get(state, state->srate); - if (smrt_set(state, state->srate) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); - return -1; - } - } - } - if (v > vmax) - vmax_his = 1 ; - if (v < vmin) - vmin_his = 1 ; - i++; - - if ((i % 2 == 1) && (vmax_his == 1)) - i++; - if ((i % 2 == 0) && (vmin_his == 1)) - i++; - - if (i % 2 == 1) - v = (i + 1) / 2; - else - v = -i / 2; - - if ((vmax_his == 1) && (vmin_his == 1)) - loop = 0 ; - } - - if (signal == 1) { - dprintk(verbose, MB86A16_INFO, 1, " Start Freq Error Check"); - S1T = 7 ; - S0T = 1 ; - CREN = 0 ; - AFCEN = 1 ; - AFCEXEN = 0 ; - - if (S01T_set(state, S1T, S0T) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "S01T set error"); - return -1; - } - smrt_info_get(state, state->srate); - if (smrt_set(state, state->srate) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); - return -1; - } - if (EN_set(state, CREN, AFCEN) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "EN set error"); - return -1; - } - if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); - return -1; - } - afcex_info_get(state, afcex_freq, &AFCEX_L, &AFCEX_H); - if (afcofs_data_set(state, AFCEX_L, AFCEX_H) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "AFCOFS data set error"); - return -1; - } - if (srst(state) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "srst error"); - return -1; - } - /* delay 4~200 */ - wait_t = 200000 / state->master_clk + 200000 / state->srate; - msleep(wait_t); - afcerr = afcerr_chk(state); - if (afcerr == -1) - return -1; - - swp_freq = fOSC * 1000 + afcerr ; - AFCEXEN = 1 ; - if (state->srate >= 1500) - smrt_d = state->srate / 3; - else - smrt_d = state->srate / 2; - smrt_info_get(state, smrt_d); - if (smrt_set(state, smrt_d) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); - return -1; - } - if (AFCEXEN_set(state, AFCEXEN, smrt_d) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); - return -1; - } - R = vco_dev_get(state, smrt_d); - if (DAGC_data_set(state, 2, 0) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error"); - return -1; - } - for (i = 0; i < 3; i++) { - temp_freq = swp_freq + (i - 1) * state->srate / 8; - swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); - if (rf_val_set(state, fOSC, smrt_d, R) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); - return -1; - } - if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); - return -1; - } - wait_t = 200000 / state->master_clk + 40000 / smrt_d; - msleep(wait_t); - dagcm[i] = dagcm_val_get(state); - } - if ((dagcm[0] > dagcm[1]) && - (dagcm[0] > dagcm[2]) && - (dagcm[0] - dagcm[1] > 2 * (dagcm[2] - dagcm[1]))) { - - temp_freq = swp_freq - 2 * state->srate / 8; - swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); - if (rf_val_set(state, fOSC, smrt_d, R) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); - return -1; - } - if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "afcex data set"); - return -1; - } - wait_t = 200000 / state->master_clk + 40000 / smrt_d; - msleep(wait_t); - dagcm[3] = dagcm_val_get(state); - if (dagcm[3] > dagcm[1]) - delta_freq = (dagcm[2] - dagcm[0] + dagcm[1] - dagcm[3]) * state->srate / 300; - else - delta_freq = 0; - } else if ((dagcm[2] > dagcm[1]) && - (dagcm[2] > dagcm[0]) && - (dagcm[2] - dagcm[1] > 2 * (dagcm[0] - dagcm[1]))) { - - temp_freq = swp_freq + 2 * state->srate / 8; - swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); - if (rf_val_set(state, fOSC, smrt_d, R) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "rf val set"); - return -1; - } - if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "afcex data set"); - return -1; - } - wait_t = 200000 / state->master_clk + 40000 / smrt_d; - msleep(wait_t); - dagcm[3] = dagcm_val_get(state); - if (dagcm[3] > dagcm[1]) - delta_freq = (dagcm[2] - dagcm[0] + dagcm[3] - dagcm[1]) * state->srate / 300; - else - delta_freq = 0 ; - - } else { - delta_freq = 0 ; - } - dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq); - swp_freq += delta_freq; - dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq); - if (ABS(state->frequency * 1000 - swp_freq) > 3800) { - dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !"); - } else { - - S1T = 0; - S0T = 3; - CREN = 1; - AFCEN = 0; - AFCEXEN = 1; - - if (S01T_set(state, S1T, S0T) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "S01T set error"); - return -1; - } - if (DAGC_data_set(state, 0, 0) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error"); - return -1; - } - R = vco_dev_get(state, state->srate); - smrt_info_get(state, state->srate); - if (smrt_set(state, state->srate) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); - return -1; - } - if (EN_set(state, CREN, AFCEN) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "EN set error"); - return -1; - } - if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); - return -1; - } - swp_info_get2(state, state->srate, R, swp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); - if (rf_val_set(state, fOSC, state->srate, R) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); - return -1; - } - if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); - return -1; - } - if (srst(state) < 0) { - dprintk(verbose, MB86A16_ERROR, 1, "srst error"); - return -1; - } - wait_t = 7 + (10000 + state->srate / 2) / state->srate; - if (wait_t == 0) - wait_t = 1; - msleep_interruptible(wait_t); - if (mb86a16_read(state, 0x37, &SIG1) != 2) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - - if (SIG1 > 110) { - S2T = 4; S4T = 1; S5T = 6; ETH = 4; VIA = 6; - wait_t = 7 + (917504 + state->srate / 2) / state->srate; - } else if (SIG1 > 105) { - S2T = 4; S4T = 2; S5T = 8; ETH = 7; VIA = 2; - wait_t = 7 + (1048576 + state->srate / 2) / state->srate; - } else if (SIG1 > 85) { - S2T = 5; S4T = 2; S5T = 8; ETH = 7; VIA = 2; - wait_t = 7 + (1310720 + state->srate / 2) / state->srate; - } else if (SIG1 > 65) { - S2T = 6; S4T = 2; S5T = 8; ETH = 7; VIA = 2; - wait_t = 7 + (1572864 + state->srate / 2) / state->srate; - } else { - S2T = 7; S4T = 2; S5T = 8; ETH = 7; VIA = 2; - wait_t = 7 + (2097152 + state->srate / 2) / state->srate; - } - wait_t *= 2; /* FOS */ - S2T_set(state, S2T); - S45T_set(state, S4T, S5T); - Vi_set(state, ETH, VIA); - srst(state); - msleep_interruptible(wait_t); - sync = sync_chk(state, &VIRM); - dprintk(verbose, MB86A16_INFO, 1, "-------- Viterbi=[%d] SYNC=[%d] ---------", VIRM, sync); - if (VIRM) { - if (VIRM == 4) { - /* 5/6 */ - if (SIG1 > 110) - wait_t = (786432 + state->srate / 2) / state->srate; - else - wait_t = (1572864 + state->srate / 2) / state->srate; - if (state->srate < 5000) - /* FIXME ! , should be a long wait ! */ - msleep_interruptible(wait_t); - else - msleep_interruptible(wait_t); - - if (sync_chk(state, &junk) == 0) { - iq_vt_set(state, 1); - FEC_srst(state); - } - } - /* 1/2, 2/3, 3/4, 7/8 */ - if (SIG1 > 110) - wait_t = (786432 + state->srate / 2) / state->srate; - else - wait_t = (1572864 + state->srate / 2) / state->srate; - msleep_interruptible(wait_t); - SEQ_set(state, 1); - } else { - dprintk(verbose, MB86A16_INFO, 1, "NO -- SYNC"); - SEQ_set(state, 1); - ret = -1; - } - } - } else { - dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL"); - ret = -1; - } - - sync = sync_chk(state, &junk); - if (sync) { - dprintk(verbose, MB86A16_INFO, 1, "******* SYNC *******"); - freqerr_chk(state, state->frequency, state->srate, 1); - ret = 0; - break; - } - } - - mb86a16_read(state, 0x15, &agcval); - mb86a16_read(state, 0x26, &cnmval); - dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval); - - return ret; -} - -static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *cmd) -{ - struct mb86a16_state *state = fe->demodulator_priv; - int i; - u8 regs; - - if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0) - goto err; - if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0) - goto err; - if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0) - goto err; - - regs = 0x18; - - if (cmd->msg_len > 5 || cmd->msg_len < 4) - return -EINVAL; - - for (i = 0; i < cmd->msg_len; i++) { - if (mb86a16_write(state, regs, cmd->msg[i]) < 0) - goto err; - - regs++; - } - i += 0x90; - - msleep_interruptible(10); - - if (mb86a16_write(state, MB86A16_DCC1, i) < 0) - goto err; - if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) - goto err; - - return 0; - -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) -{ - struct mb86a16_state *state = fe->demodulator_priv; - - switch (burst) { - case SEC_MINI_A: - if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA | - MB86A16_DCC1_TBEN | - MB86A16_DCC1_TBO) < 0) - goto err; - if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) - goto err; - break; - case SEC_MINI_B: - if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA | - MB86A16_DCC1_TBEN) < 0) - goto err; - if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) - goto err; - break; - } - - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct mb86a16_state *state = fe->demodulator_priv; - - switch (tone) { - case SEC_TONE_ON: - if (mb86a16_write(state, MB86A16_TONEOUT2, 0x00) < 0) - goto err; - if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA | - MB86A16_DCC1_CTOE) < 0) - - goto err; - if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) - goto err; - break; - case SEC_TONE_OFF: - if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0) - goto err; - if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0) - goto err; - if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0) - goto err; - break; - default: - return -EINVAL; - } - return 0; - -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct mb86a16_state *state = fe->demodulator_priv; - - state->frequency = p->frequency / 1000; - state->srate = p->u.qpsk.symbol_rate / 1000; - - if (!mb86a16_set_fe(state)) { - dprintk(verbose, MB86A16_ERROR, 1, "Succesfully acquired LOCK"); - return DVBFE_ALGO_SEARCH_SUCCESS; - } - - dprintk(verbose, MB86A16_ERROR, 1, "Lock acquisition failed!"); - return DVBFE_ALGO_SEARCH_FAILED; -} - -static void mb86a16_release(struct dvb_frontend *fe) -{ - struct mb86a16_state *state = fe->demodulator_priv; - kfree(state); -} - -static int mb86a16_init(struct dvb_frontend *fe) -{ - return 0; -} - -static int mb86a16_sleep(struct dvb_frontend *fe) -{ - return 0; -} - -static int mb86a16_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - u8 ber_mon, ber_tab, ber_lsb, ber_mid, ber_msb, ber_tim, ber_rst; - u32 timer; - - struct mb86a16_state *state = fe->demodulator_priv; - - *ber = 0; - if (mb86a16_read(state, MB86A16_BERMON, &ber_mon) != 2) - goto err; - if (mb86a16_read(state, MB86A16_BERTAB, &ber_tab) != 2) - goto err; - if (mb86a16_read(state, MB86A16_BERLSB, &ber_lsb) != 2) - goto err; - if (mb86a16_read(state, MB86A16_BERMID, &ber_mid) != 2) - goto err; - if (mb86a16_read(state, MB86A16_BERMSB, &ber_msb) != 2) - goto err; - /* BER monitor invalid when BER_EN = 0 */ - if (ber_mon & 0x04) { - /* coarse, fast calculation */ - *ber = ber_tab & 0x1f; - dprintk(verbose, MB86A16_DEBUG, 1, "BER coarse=[0x%02x]", *ber); - if (ber_mon & 0x01) { - /* - * BER_SEL = 1, The monitored BER is the estimated - * value with a Reed-Solomon decoder error amount at - * the deinterleaver output. - * monitored BER is expressed as a 20 bit output in total - */ - ber_rst = ber_mon >> 3; - *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb; - if (ber_rst == 0) - timer = 12500000; - if (ber_rst == 1) - timer = 25000000; - if (ber_rst == 2) - timer = 50000000; - if (ber_rst == 3) - timer = 100000000; - - *ber /= timer; - dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber); - } else { - /* - * BER_SEL = 0, The monitored BER is the estimated - * value with a Viterbi decoder error amount at the - * QPSK demodulator output. - * monitored BER is expressed as a 24 bit output in total - */ - ber_tim = ber_mon >> 1; - *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb; - if (ber_tim == 0) - timer = 16; - if (ber_tim == 1) - timer = 24; - - *ber /= 2 ^ timer; - dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber); - } - } - return 0; -err: - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; -} - -static int mb86a16_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - u8 agcm = 0; - struct mb86a16_state *state = fe->demodulator_priv; - - *strength = 0; - if (mb86a16_read(state, MB86A16_AGCM, &agcm) != 2) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - - *strength = ((0xff - agcm) * 100) / 256; - dprintk(verbose, MB86A16_DEBUG, 1, "Signal strength=[%d %%]", (u8) *strength); - *strength = (0xffff - 0xff) + agcm; - - return 0; -} - -struct cnr { - u8 cn_reg; - u8 cn_val; -}; - -static const struct cnr cnr_tab[] = { - { 35, 2 }, - { 40, 3 }, - { 50, 4 }, - { 60, 5 }, - { 70, 6 }, - { 80, 7 }, - { 92, 8 }, - { 103, 9 }, - { 115, 10 }, - { 138, 12 }, - { 162, 15 }, - { 180, 18 }, - { 185, 19 }, - { 189, 20 }, - { 195, 22 }, - { 199, 24 }, - { 201, 25 }, - { 202, 26 }, - { 203, 27 }, - { 205, 28 }, - { 208, 30 } -}; - -static int mb86a16_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct mb86a16_state *state = fe->demodulator_priv; - int i = 0; - int low_tide = 2, high_tide = 30, q_level; - u8 cn; - - *snr = 0; - if (mb86a16_read(state, 0x26, &cn) != 2) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - - for (i = 0; i < ARRAY_SIZE(cnr_tab); i++) { - if (cn < cnr_tab[i].cn_reg) { - *snr = cnr_tab[i].cn_val; - break; - } - } - q_level = (*snr * 100) / (high_tide - low_tide); - dprintk(verbose, MB86A16_ERROR, 1, "SNR (Quality) = [%d dB], Level=%d %%", *snr, q_level); - *snr = (0xffff - 0xff) + *snr; - - return 0; -} - -static int mb86a16_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - u8 dist; - struct mb86a16_state *state = fe->demodulator_priv; - - if (mb86a16_read(state, MB86A16_DISTMON, &dist) != 2) { - dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; - } - *ucblocks = dist; - - return 0; -} - -static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe) -{ - return DVBFE_ALGO_CUSTOM; -} - -static struct dvb_frontend_ops mb86a16_ops = { - .info = { - .name = "Fujitsu MB86A16 DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 3000, - .frequency_tolerance = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | FE_CAN_QPSK | - FE_CAN_FEC_AUTO - }, - .release = mb86a16_release, - - .get_frontend_algo = mb86a16_frontend_algo, - .search = mb86a16_search, - .init = mb86a16_init, - .sleep = mb86a16_sleep, - .read_status = mb86a16_read_status, - - .read_ber = mb86a16_read_ber, - .read_signal_strength = mb86a16_read_signal_strength, - .read_snr = mb86a16_read_snr, - .read_ucblocks = mb86a16_read_ucblocks, - - .diseqc_send_master_cmd = mb86a16_send_diseqc_msg, - .diseqc_send_burst = mb86a16_send_diseqc_burst, - .set_tone = mb86a16_set_tone, -}; - -struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, - struct i2c_adapter *i2c_adap) -{ - u8 dev_id = 0; - struct mb86a16_state *state = NULL; - - state = kmalloc(sizeof(struct mb86a16_state), GFP_KERNEL); - if (state == NULL) - goto error; - - state->config = config; - state->i2c_adap = i2c_adap; - - mb86a16_read(state, 0x7f, &dev_id); - if (dev_id != 0xfe) - goto error; - - memcpy(&state->frontend.ops, &mb86a16_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - state->frontend.ops.set_voltage = state->config->set_voltage; - - return &state->frontend; -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(mb86a16_attach); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Manu Abraham"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - Fujitsu MB86A16 DVB-S/DSS DC Receiver driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MB86A16_H -#define __MB86A16_H - -#include -#include "dvb_frontend.h" - - -struct mb86a16_config { - u8 demod_address; - - int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); -}; - - - -#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE)) - -extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, - struct i2c_adapter *i2c_adap); - -#else - -static inline struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, - struct i2c_adapter *i2c_adap) -{ - printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); - return NULL; -} - -#endif /* CONFIG_DVB_MB86A16 */ - -#endif /* __MB86A16_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a16_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,151 +0,0 @@ -/* - Fujitsu MB86A16 DVB-S/DSS DC Receiver driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MB86A16_PRIV_H -#define __MB86A16_PRIV_H - -#define MB86A16_TSOUT 0x00 -#define MB86A16_TSOUT_HIZSEL (0x01 << 5) -#define MB86A16_TSOUT_HIZCNTI (0x01 << 4) -#define MB86A16_TSOUT_MODE (0x01 << 3) -#define MB86A16_TSOUT_ORDER (0x01 << 2) -#define MB86A16_TSOUT_ERROR (0x01 << 1) -#define Mb86A16_TSOUT_EDGE (0x01 << 0) - -#define MB86A16_FEC 0x01 -#define MB86A16_FEC_FSYNC (0x01 << 5) -#define MB86A16_FEC_PCKB8 (0x01 << 4) -#define MB86A16_FEC_DVDS (0x01 << 3) -#define MB86A16_FEC_EREN (0x01 << 2) -#define Mb86A16_FEC_RSEN (0x01 << 1) -#define MB86A16_FEC_DIEN (0x01 << 0) - -#define MB86A16_AGC 0x02 -#define MB86A16_AGC_AGMD (0x01 << 6) -#define MB86A16_AGC_AGCW (0x0f << 2) -#define MB86A16_AGC_AGCP (0x01 << 1) -#define MB86A16_AGC_AGCR (0x01 << 0) - -#define MB86A16_SRATE1 0x03 -#define MB86A16_SRATE1_DECI (0x07 << 2) -#define MB86A16_SRATE1_CSEL (0x01 << 1) -#define MB86A16_SRATE1_RSEL (0x01 << 0) - -#define MB86A16_SRATE2 0x04 -#define MB86A16_SRATE2_STOFSL (0xff << 0) - -#define MB86A16_SRATE3 0x05 -#define MB86A16_SRATE2_STOFSH (0xff << 0) - -#define MB86A16_VITERBI 0x06 -#define MB86A16_FRAMESYNC 0x07 -#define MB86A16_CRLFILTCOEF1 0x08 -#define MB86A16_CRLFILTCOEF2 0x09 -#define MB86A16_STRFILTCOEF1 0x0a -#define MB86A16_STRFILTCOEF2 0x0b -#define MB86A16_RESET 0x0c -#define MB86A16_STATUS 0x0d -#define MB86A16_AFCML 0x0e -#define MB86A16_AFCMH 0x0f -#define MB86A16_BERMON 0x10 -#define MB86A16_BERTAB 0x11 -#define MB86A16_BERLSB 0x12 -#define MB86A16_BERMID 0x13 -#define MB86A16_BERMSB 0x14 -#define MB86A16_AGCM 0x15 - -#define MB86A16_DCC1 0x16 -#define MB86A16_DCC1_DISTA (0x01 << 7) -#define MB86A16_DCC1_PRTY (0x01 << 6) -#define MB86A16_DCC1_CTOE (0x01 << 5) -#define MB86A16_DCC1_TBEN (0x01 << 4) -#define MB86A16_DCC1_TBO (0x01 << 3) -#define MB86A16_DCC1_NUM (0x07 << 0) - -#define MB86A16_DCC2 0x17 -#define MB86A16_DCC2_DCBST (0x01 << 0) - -#define MB86A16_DCC3 0x18 -#define MB86A16_DCC3_CODE0 (0xff << 0) - -#define MB86A16_DCC4 0x19 -#define MB86A16_DCC4_CODE1 (0xff << 0) - -#define MB86A16_DCC5 0x1a -#define MB86A16_DCC5_CODE2 (0xff << 0) - -#define MB86A16_DCC6 0x1b -#define MB86A16_DCC6_CODE3 (0xff << 0) - -#define MB86A16_DCC7 0x1c -#define MB86A16_DCC7_CODE4 (0xff << 0) - -#define MB86A16_DCC8 0x1d -#define MB86A16_DCC8_CODE5 (0xff << 0) - -#define MB86A16_DCCOUT 0x1e -#define MB86A16_DCCOUT_DISEN (0x01 << 0) - -#define MB86A16_TONEOUT1 0x1f -#define MB86A16_TONE_TDIVL (0xff << 0) - -#define MB86A16_TONEOUT2 0x20 -#define MB86A16_TONE_TMD (0x03 << 2) -#define MB86A16_TONE_TDIVH (0x03 << 0) - -#define MB86A16_FREQ1 0x21 -#define MB86A16_FREQ2 0x22 -#define MB86A16_FREQ3 0x23 -#define MB86A16_FREQ4 0x24 -#define MB86A16_FREQSET 0x25 -#define MB86A16_CNM 0x26 -#define MB86A16_PORT0 0x27 -#define MB86A16_PORT1 0x28 -#define MB86A16_DRCFILT 0x29 -#define MB86A16_AFC 0x2a -#define MB86A16_AFCEXL 0x2b -#define MB86A16_AFCEXH 0x2c -#define MB86A16_DAGC 0x2d -#define MB86A16_SEQMODE 0x32 -#define MB86A16_S0S1T 0x33 -#define MB86A16_S2S3T 0x34 -#define MB86A16_S4S5T 0x35 -#define MB86A16_CNTMR 0x36 -#define MB86A16_SIG1 0x37 -#define MB86A16_SIG2 0x38 -#define MB86A16_VIMAG 0x39 -#define MB86A16_VISET1 0x3a -#define MB86A16_VISET2 0x3b -#define MB86A16_VISET3 0x3c -#define MB86A16_FAGCS1 0x3d -#define MB86A16_FAGCS2 0x3e -#define MB86A16_FAGCS3 0x3f -#define MB86A16_FAGCS4 0x40 -#define MB86A16_FAGCS5 0x41 -#define MB86A16_FAGCS6 0x42 -#define MB86A16_CRM 0x43 -#define MB86A16_STRM 0x44 -#define MB86A16_DAGCML 0x45 -#define MB86A16_DAGCMH 0x46 -#define MB86A16_QPSKTST 0x49 -#define MB86A16_DISTMON 0x52 -#define MB86A16_VERSION 0x7f - -#endif /* __MB86A16_PRIV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a20s.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a20s.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a20s.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a20s.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,639 +0,0 @@ -/* - * Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver - * - * Copyright (C) 2010 Mauro Carvalho Chehab - * Copyright (C) 2009-2010 Douglas Landgraf - * - * FIXME: Need to port to DVB v5.2 API - * - * 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 version 2. - * - * 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. - */ - -#include -#include - -#include "dvb_frontend.h" -#include "mb86a20s.h" - -static int debug = 1; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); - -#define rc(args...) do { \ - printk(KERN_ERR "mb86a20s: " args); \ -} while (0) - -#define dprintk(args...) \ - do { \ - if (debug) { \ - printk(KERN_DEBUG "mb86a20s: %s: ", __func__); \ - printk(args); \ - } \ - } while (0) - -struct mb86a20s_state { - struct i2c_adapter *i2c; - const struct mb86a20s_config *config; - - struct dvb_frontend frontend; - - bool need_init; -}; - -struct regdata { - u8 reg; - u8 data; -}; - -/* - * Initialization sequence: Use whatevere default values that PV SBTVD - * does on its initialisation, obtained via USB snoop - */ -static struct regdata mb86a20s_init[] = { - { 0x70, 0x0f }, - { 0x70, 0xff }, - { 0x08, 0x01 }, - { 0x09, 0x3e }, - { 0x50, 0xd1 }, - { 0x51, 0x22 }, - { 0x39, 0x01 }, - { 0x71, 0x00 }, - { 0x28, 0x2a }, - { 0x29, 0x00 }, - { 0x2a, 0xff }, - { 0x2b, 0x80 }, - { 0x28, 0x20 }, - { 0x29, 0x33 }, - { 0x2a, 0xdf }, - { 0x2b, 0xa9 }, - { 0x3b, 0x21 }, - { 0x3c, 0x3a }, - { 0x01, 0x0d }, - { 0x04, 0x08 }, - { 0x05, 0x05 }, - { 0x04, 0x0e }, - { 0x05, 0x00 }, - { 0x04, 0x0f }, - { 0x05, 0x14 }, - { 0x04, 0x0b }, - { 0x05, 0x8c }, - { 0x04, 0x00 }, - { 0x05, 0x00 }, - { 0x04, 0x01 }, - { 0x05, 0x07 }, - { 0x04, 0x02 }, - { 0x05, 0x0f }, - { 0x04, 0x03 }, - { 0x05, 0xa0 }, - { 0x04, 0x09 }, - { 0x05, 0x00 }, - { 0x04, 0x0a }, - { 0x05, 0xff }, - { 0x04, 0x27 }, - { 0x05, 0x64 }, - { 0x04, 0x28 }, - { 0x05, 0x00 }, - { 0x04, 0x1e }, - { 0x05, 0xff }, - { 0x04, 0x29 }, - { 0x05, 0x0a }, - { 0x04, 0x32 }, - { 0x05, 0x0a }, - { 0x04, 0x14 }, - { 0x05, 0x02 }, - { 0x04, 0x04 }, - { 0x05, 0x00 }, - { 0x04, 0x05 }, - { 0x05, 0x22 }, - { 0x04, 0x06 }, - { 0x05, 0x0e }, - { 0x04, 0x07 }, - { 0x05, 0xd8 }, - { 0x04, 0x12 }, - { 0x05, 0x00 }, - { 0x04, 0x13 }, - { 0x05, 0xff }, - { 0x52, 0x01 }, - { 0x50, 0xa7 }, - { 0x51, 0x00 }, - { 0x50, 0xa8 }, - { 0x51, 0xff }, - { 0x50, 0xa9 }, - { 0x51, 0xff }, - { 0x50, 0xaa }, - { 0x51, 0x00 }, - { 0x50, 0xab }, - { 0x51, 0xff }, - { 0x50, 0xac }, - { 0x51, 0xff }, - { 0x50, 0xad }, - { 0x51, 0x00 }, - { 0x50, 0xae }, - { 0x51, 0xff }, - { 0x50, 0xaf }, - { 0x51, 0xff }, - { 0x5e, 0x07 }, - { 0x50, 0xdc }, - { 0x51, 0x01 }, - { 0x50, 0xdd }, - { 0x51, 0xf4 }, - { 0x50, 0xde }, - { 0x51, 0x01 }, - { 0x50, 0xdf }, - { 0x51, 0xf4 }, - { 0x50, 0xe0 }, - { 0x51, 0x01 }, - { 0x50, 0xe1 }, - { 0x51, 0xf4 }, - { 0x50, 0xb0 }, - { 0x51, 0x07 }, - { 0x50, 0xb2 }, - { 0x51, 0xff }, - { 0x50, 0xb3 }, - { 0x51, 0xff }, - { 0x50, 0xb4 }, - { 0x51, 0xff }, - { 0x50, 0xb5 }, - { 0x51, 0xff }, - { 0x50, 0xb6 }, - { 0x51, 0xff }, - { 0x50, 0xb7 }, - { 0x51, 0xff }, - { 0x50, 0x50 }, - { 0x51, 0x02 }, - { 0x50, 0x51 }, - { 0x51, 0x04 }, - { 0x45, 0x04 }, - { 0x48, 0x04 }, - { 0x50, 0xd5 }, - { 0x51, 0x01 }, /* Serial */ - { 0x50, 0xd6 }, - { 0x51, 0x1f }, - { 0x50, 0xd2 }, - { 0x51, 0x03 }, - { 0x50, 0xd7 }, - { 0x51, 0x3f }, - { 0x1c, 0x01 }, - { 0x28, 0x06 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x03 }, - { 0x28, 0x07 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x0d }, - { 0x28, 0x08 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x02 }, - { 0x28, 0x09 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x01 }, - { 0x28, 0x0a }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x21 }, - { 0x28, 0x0b }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x29 }, - { 0x28, 0x0c }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x16 }, - { 0x28, 0x0d }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x31 }, - { 0x28, 0x0e }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x0e }, - { 0x28, 0x0f }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x4e }, - { 0x28, 0x10 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x46 }, - { 0x28, 0x11 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x0f }, - { 0x28, 0x12 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x56 }, - { 0x28, 0x13 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x35 }, - { 0x28, 0x14 }, - { 0x29, 0x00 }, - { 0x2a, 0x01 }, - { 0x2b, 0xbe }, - { 0x28, 0x15 }, - { 0x29, 0x00 }, - { 0x2a, 0x01 }, - { 0x2b, 0x84 }, - { 0x28, 0x16 }, - { 0x29, 0x00 }, - { 0x2a, 0x03 }, - { 0x2b, 0xee }, - { 0x28, 0x17 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x98 }, - { 0x28, 0x18 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x9f }, - { 0x28, 0x19 }, - { 0x29, 0x00 }, - { 0x2a, 0x07 }, - { 0x2b, 0xb2 }, - { 0x28, 0x1a }, - { 0x29, 0x00 }, - { 0x2a, 0x06 }, - { 0x2b, 0xc2 }, - { 0x28, 0x1b }, - { 0x29, 0x00 }, - { 0x2a, 0x07 }, - { 0x2b, 0x4a }, - { 0x28, 0x1c }, - { 0x29, 0x00 }, - { 0x2a, 0x01 }, - { 0x2b, 0xbc }, - { 0x28, 0x1d }, - { 0x29, 0x00 }, - { 0x2a, 0x04 }, - { 0x2b, 0xba }, - { 0x28, 0x1e }, - { 0x29, 0x00 }, - { 0x2a, 0x06 }, - { 0x2b, 0x14 }, - { 0x50, 0x1e }, - { 0x51, 0x5d }, - { 0x50, 0x22 }, - { 0x51, 0x00 }, - { 0x50, 0x23 }, - { 0x51, 0xc8 }, - { 0x50, 0x24 }, - { 0x51, 0x00 }, - { 0x50, 0x25 }, - { 0x51, 0xf0 }, - { 0x50, 0x26 }, - { 0x51, 0x00 }, - { 0x50, 0x27 }, - { 0x51, 0xc3 }, - { 0x50, 0x39 }, - { 0x51, 0x02 }, - { 0x50, 0xd5 }, - { 0x51, 0x01 }, - { 0xd0, 0x00 }, -}; - -static struct regdata mb86a20s_reset_reception[] = { - { 0x70, 0xf0 }, - { 0x70, 0xff }, - { 0x08, 0x01 }, - { 0x08, 0x00 }, -}; - -static int mb86a20s_i2c_writereg(struct mb86a20s_state *state, - u8 i2c_addr, int reg, int data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { - .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2 - }; - int rc; - - rc = i2c_transfer(state->i2c, &msg, 1); - if (rc != 1) { - printk("%s: writereg error (rc == %i, reg == 0x%02x," - " data == 0x%02x)\n", __func__, rc, reg, data); - return rc; - } - - return 0; -} - -static int mb86a20s_i2c_writeregdata(struct mb86a20s_state *state, - u8 i2c_addr, struct regdata *rd, int size) -{ - int i, rc; - - for (i = 0; i < size; i++) { - rc = mb86a20s_i2c_writereg(state, i2c_addr, rd[i].reg, - rd[i].data); - if (rc < 0) - return rc; - } - return 0; -} - -static int mb86a20s_i2c_readreg(struct mb86a20s_state *state, - u8 i2c_addr, u8 reg) -{ - u8 val; - int rc; - struct i2c_msg msg[] = { - { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 }, - { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 } - }; - - rc = i2c_transfer(state->i2c, msg, 2); - - if (rc != 2) { - rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc); - return rc; - } - - return val; -} - -#define mb86a20s_readreg(state, reg) \ - mb86a20s_i2c_readreg(state, state->config->demod_address, reg) -#define mb86a20s_writereg(state, reg, val) \ - mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val) -#define mb86a20s_writeregdata(state, regdata) \ - mb86a20s_i2c_writeregdata(state, state->config->demod_address, \ - regdata, ARRAY_SIZE(regdata)) - -static int mb86a20s_initfe(struct dvb_frontend *fe) -{ - struct mb86a20s_state *state = fe->demodulator_priv; - int rc; - u8 regD5 = 1; - - dprintk("\n"); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - /* Initialize the frontend */ - rc = mb86a20s_writeregdata(state, mb86a20s_init); - if (rc < 0) - goto err; - - if (!state->config->is_serial) { - regD5 &= ~1; - - rc = mb86a20s_writereg(state, 0x50, 0xd5); - if (rc < 0) - goto err; - rc = mb86a20s_writereg(state, 0x51, regD5); - if (rc < 0) - goto err; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - -err: - if (rc < 0) { - state->need_init = true; - printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n"); - } else { - state->need_init = false; - dprintk("Initialization succeded.\n"); - } - return rc; -} - -static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct mb86a20s_state *state = fe->demodulator_priv; - unsigned rf_max, rf_min, rf; - u8 val; - - dprintk("\n"); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - /* Does a binary search to get RF strength */ - rf_max = 0xfff; - rf_min = 0; - do { - rf = (rf_max + rf_min) / 2; - mb86a20s_writereg(state, 0x04, 0x1f); - mb86a20s_writereg(state, 0x05, rf >> 8); - mb86a20s_writereg(state, 0x04, 0x20); - mb86a20s_writereg(state, 0x04, rf); - - val = mb86a20s_readreg(state, 0x02); - if (val & 0x08) - rf_min = (rf_max + rf_min) / 2; - else - rf_max = (rf_max + rf_min) / 2; - if (rf_max - rf_min < 4) { - *strength = (((rf_max + rf_min) / 2) * 65535) / 4095; - break; - } - } while (1); - - dprintk("signal strength = %d\n", *strength); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - return 0; -} - -static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct mb86a20s_state *state = fe->demodulator_priv; - u8 val; - - dprintk("\n"); - *status = 0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - val = mb86a20s_readreg(state, 0x0a) & 0xf; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (val >= 2) - *status |= FE_HAS_SIGNAL; - - if (val >= 4) - *status |= FE_HAS_CARRIER; - - if (val >= 5) - *status |= FE_HAS_VITERBI; - - if (val >= 7) - *status |= FE_HAS_SYNC; - - if (val >= 8) /* Maybe 9? */ - *status |= FE_HAS_LOCK; - - dprintk("val = %d, status = 0x%02x\n", val, *status); - - return 0; -} - -static int mb86a20s_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct mb86a20s_state *state = fe->demodulator_priv; - int rc; - - dprintk("\n"); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - dprintk("Calling tuner set parameters\n"); - fe->ops.tuner_ops.set_params(fe, p); - - /* - * Make it more reliable: if, for some reason, the initial - * device initialization doesn't happen, initialize it when - * a SBTVD parameters are adjusted. - * - * Unfortunately, due to a hard to track bug at tda829x/tda18271, - * the agc callback logic is not called during DVB attach time, - * causing mb86a20s to not be initialized with Kworld SBTVD. - * So, this hack is needed, in order to make Kworld SBTVD to work. - */ - if (state->need_init) - mb86a20s_initfe(fe); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - return rc; -} - -static int mb86a20s_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - - /* FIXME: For now, it does nothing */ - - fe->dtv_property_cache.bandwidth_hz = 6000000; - fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; - fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; - fe->dtv_property_cache.isdbt_partial_reception = 0; - - return 0; -} - -static int mb86a20s_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, - unsigned int mode_flags, - unsigned int *delay, - fe_status_t *status) -{ - int rc = 0; - - dprintk("\n"); - - if (params != NULL) - rc = mb86a20s_set_frontend(fe, params); - - if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) - mb86a20s_read_status(fe, status); - - return rc; -} - -static void mb86a20s_release(struct dvb_frontend *fe) -{ - struct mb86a20s_state *state = fe->demodulator_priv; - - dprintk("\n"); - - kfree(state); -} - -static struct dvb_frontend_ops mb86a20s_ops; - -struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, - struct i2c_adapter *i2c) -{ - u8 rev; - - /* allocate memory for the internal state */ - struct mb86a20s_state *state = - kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL); - - dprintk("\n"); - if (state == NULL) { - rc("Unable to kzalloc\n"); - goto error; - } - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &mb86a20s_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - /* Check if it is a mb86a20s frontend */ - rev = mb86a20s_readreg(state, 0); - - if (rev == 0x13) { - printk(KERN_INFO "Detected a Fujitsu mb86a20s frontend\n"); - } else { - printk(KERN_ERR "Frontend revision %d is unknown - aborting.\n", - rev); - goto error; - } - - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(mb86a20s_attach); - -static struct dvb_frontend_ops mb86a20s_ops = { - /* Use dib8000 values per default */ - .info = { - .name = "Fujitsu mb86A20s", - .type = FE_OFDM, - .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_QAM_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, - /* Actually, those values depend on the used tuner */ - .frequency_min = 45000000, - .frequency_max = 864000000, - .frequency_stepsize = 62500, - }, - - .release = mb86a20s_release, - - .init = mb86a20s_initfe, - .set_frontend = mb86a20s_set_frontend, - .get_frontend = mb86a20s_get_frontend, - .read_status = mb86a20s_read_status, - .read_signal_strength = mb86a20s_read_signal_strength, - .tune = mb86a20s_tune, -}; - -MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a20s.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a20s.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a20s.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mb86a20s.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * Fujitsu mb86a20s driver - * - * Copyright (C) 2010 Mauro Carvalho Chehab - * - * 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 version 2. - * - * 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. - */ - -#ifndef MB86A20S_H -#define MB86A20S_H - -#include - -/** - * struct mb86a20s_config - Define the per-device attributes of the frontend - * - * @demod_address: the demodulator's i2c address - */ - -struct mb86a20s_config { - u8 demod_address; - bool is_serial; -}; - -#if defined(CONFIG_DVB_MB86A20S) || (defined(CONFIG_DVB_MB86A20S_MODULE) \ - && defined(MODULE)) -extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, - struct i2c_adapter *i2c); -extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *); -#else -static inline struct dvb_frontend *mb86a20s_attach( - const struct mb86a20s_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static struct i2c_adapter * - mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* MB86A20S */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,840 +0,0 @@ -/* - Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder - - Copyright (C) 2003 Andreas Oberritter - Copyright (C) 2008 Matthias Schwarzott - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - References: - http://products.zarlink.com/product_profiles/MT312.htm - http://products.zarlink.com/product_profiles/SL1935.htm -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "mt312_priv.h" -#include "mt312.h" - - -struct mt312_state { - struct i2c_adapter *i2c; - /* configuration settings */ - const struct mt312_config *config; - struct dvb_frontend frontend; - - u8 id; - unsigned long xtal; - u8 freq_mult; -}; - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "mt312: " args); \ - } while (0) - -#define MT312_PLL_CLK 10000000UL /* 10 MHz */ -#define MT312_PLL_CLK_10_111 10111000UL /* 10.111 MHz */ - -static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, - u8 *buf, const size_t count) -{ - int ret; - struct i2c_msg msg[2]; - u8 regbuf[1] = { reg }; - - msg[0].addr = state->config->demod_address; - msg[0].flags = 0; - msg[0].buf = regbuf; - msg[0].len = 1; - msg[1].addr = state->config->demod_address; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - msg[1].len = count; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret); - return -EREMOTEIO; - } - - if (debug) { - int i; - dprintk("R(%d):", reg & 0x7f); - for (i = 0; i < count; i++) - printk(KERN_CONT " %02x", buf[i]); - printk("\n"); - } - - return 0; -} - -static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, - const u8 *src, const size_t count) -{ - int ret; - u8 buf[count + 1]; - struct i2c_msg msg; - - if (debug) { - int i; - dprintk("W(%d):", reg & 0x7f); - for (i = 0; i < count; i++) - printk(KERN_CONT " %02x", src[i]); - printk("\n"); - } - - buf[0] = reg; - memcpy(&buf[1], src, count); - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.buf = buf; - msg.len = count + 1; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) { - dprintk("%s: ret == %d\n", __func__, ret); - return -EREMOTEIO; - } - - return 0; -} - -static inline int mt312_readreg(struct mt312_state *state, - const enum mt312_reg_addr reg, u8 *val) -{ - return mt312_read(state, reg, val, 1); -} - -static inline int mt312_writereg(struct mt312_state *state, - const enum mt312_reg_addr reg, const u8 val) -{ - return mt312_write(state, reg, &val, 1); -} - -static inline u32 mt312_div(u32 a, u32 b) -{ - return (a + (b / 2)) / b; -} - -static int mt312_reset(struct mt312_state *state, const u8 full) -{ - return mt312_writereg(state, RESET, full ? 0x80 : 0x40); -} - -static int mt312_get_inversion(struct mt312_state *state, - fe_spectral_inversion_t *i) -{ - int ret; - u8 vit_mode; - - ret = mt312_readreg(state, VIT_MODE, &vit_mode); - if (ret < 0) - return ret; - - if (vit_mode & 0x80) /* auto inversion was used */ - *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF; - - return 0; -} - -static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) -{ - int ret; - u8 sym_rate_h; - u8 dec_ratio; - u16 sym_rat_op; - u16 monitor; - u8 buf[2]; - - ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h); - if (ret < 0) - return ret; - - if (sym_rate_h & 0x80) { - /* symbol rate search was used */ - ret = mt312_writereg(state, MON_CTRL, 0x03); - if (ret < 0) - return ret; - - ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); - if (ret < 0) - return ret; - - monitor = (buf[0] << 8) | buf[1]; - - dprintk("sr(auto) = %u\n", - mt312_div(monitor * 15625, 4)); - } else { - ret = mt312_writereg(state, MON_CTRL, 0x05); - if (ret < 0) - return ret; - - ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); - if (ret < 0) - return ret; - - dec_ratio = ((buf[0] >> 5) & 0x07) * 32; - - ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf)); - if (ret < 0) - return ret; - - sym_rat_op = (buf[0] << 8) | buf[1]; - - dprintk("sym_rat_op=%d dec_ratio=%d\n", - sym_rat_op, dec_ratio); - dprintk("*sr(manual) = %lu\n", - (((state->xtal * 8192) / (sym_rat_op + 8192)) * - 2) - dec_ratio); - } - - return 0; -} - -static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr) -{ - const fe_code_rate_t fec_tab[8] = - { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8, - FEC_AUTO, FEC_AUTO }; - - int ret; - u8 fec_status; - - ret = mt312_readreg(state, FEC_STATUS, &fec_status); - if (ret < 0) - return ret; - - *cr = fec_tab[(fec_status >> 4) & 0x07]; - - return 0; -} - -static int mt312_initfe(struct dvb_frontend *fe) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - u8 buf[2]; - - /* wake up */ - ret = mt312_writereg(state, CONFIG, - (state->freq_mult == 6 ? 0x88 : 0x8c)); - if (ret < 0) - return ret; - - /* wait at least 150 usec */ - udelay(150); - - /* full reset */ - ret = mt312_reset(state, 1); - if (ret < 0) - return ret; - -/* Per datasheet, write correct values. 09/28/03 ACCJr. - * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */ - { - u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02, - 0x01, 0x00, 0x00, 0x00 }; - - ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def)); - if (ret < 0) - return ret; - } - - switch (state->id) { - case ID_ZL10313: - /* enable ADC */ - ret = mt312_writereg(state, GPP_CTRL, 0x80); - if (ret < 0) - return ret; - - /* configure ZL10313 for optimal ADC performance */ - buf[0] = 0x80; - buf[1] = 0xB0; - ret = mt312_write(state, HW_CTRL, buf, 2); - if (ret < 0) - return ret; - - /* enable MPEG output and ADCs */ - ret = mt312_writereg(state, HW_CTRL, 0x00); - if (ret < 0) - return ret; - - ret = mt312_writereg(state, MPEG_CTRL, 0x00); - if (ret < 0) - return ret; - - break; - } - - /* SYS_CLK */ - buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000); - - /* DISEQC_RATIO */ - buf[1] = mt312_div(state->xtal, 22000 * 4); - - ret = mt312_write(state, SYS_CLK, buf, sizeof(buf)); - if (ret < 0) - return ret; - - ret = mt312_writereg(state, SNR_THS_HIGH, 0x32); - if (ret < 0) - return ret; - - /* different MOCLK polarity */ - switch (state->id) { - case ID_ZL10313: - buf[0] = 0x33; - break; - default: - buf[0] = 0x53; - break; - } - - ret = mt312_writereg(state, OP_CTRL, buf[0]); - if (ret < 0) - return ret; - - /* TS_SW_LIM */ - buf[0] = 0x8c; - buf[1] = 0x98; - - ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf)); - if (ret < 0) - return ret; - - ret = mt312_writereg(state, CS_SW_LIM, 0x69); - if (ret < 0) - return ret; - - return 0; -} - -static int mt312_send_master_cmd(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *c) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - u8 diseqc_mode; - - if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) - return -EINVAL; - - ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); - if (ret < 0) - return ret; - - ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len); - if (ret < 0) - return ret; - - ret = mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) - | 0x04); - if (ret < 0) - return ret; - - /* is there a better way to wait for message to be transmitted */ - msleep(100); - - /* set DISEQC_MODE[2:0] to zero if a return message is expected */ - if (c->msg[0] & 0x02) { - ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40)); - if (ret < 0) - return ret; - } - - return 0; -} - -static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c) -{ - struct mt312_state *state = fe->demodulator_priv; - const u8 mini_tab[2] = { 0x02, 0x03 }; - - int ret; - u8 diseqc_mode; - - if (c > SEC_MINI_B) - return -EINVAL; - - ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); - if (ret < 0) - return ret; - - ret = mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | mini_tab[c]); - if (ret < 0) - return ret; - - return 0; -} - -static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t) -{ - struct mt312_state *state = fe->demodulator_priv; - const u8 tone_tab[2] = { 0x01, 0x00 }; - - int ret; - u8 diseqc_mode; - - if (t > SEC_TONE_OFF) - return -EINVAL; - - ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); - if (ret < 0) - return ret; - - ret = mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | tone_tab[t]); - if (ret < 0) - return ret; - - return 0; -} - -static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v) -{ - struct mt312_state *state = fe->demodulator_priv; - const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; - u8 val; - - if (v > SEC_VOLTAGE_OFF) - return -EINVAL; - - val = volt_tab[v]; - if (state->config->voltage_inverted) - val ^= 0x40; - - return mt312_writereg(state, DISEQC_MODE, val); -} - -static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - u8 status[3]; - - *s = 0; - - ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status)); - if (ret < 0) - return ret; - - dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x," - " FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); - - if (status[0] & 0xc0) - *s |= FE_HAS_SIGNAL; /* signal noise ratio */ - if (status[0] & 0x04) - *s |= FE_HAS_CARRIER; /* qpsk carrier lock */ - if (status[2] & 0x02) - *s |= FE_HAS_VITERBI; /* viterbi lock */ - if (status[2] & 0x04) - *s |= FE_HAS_SYNC; /* byte align lock */ - if (status[0] & 0x01) - *s |= FE_HAS_LOCK; /* qpsk lock */ - - return 0; -} - -static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - u8 buf[3]; - - ret = mt312_read(state, RS_BERCNT_H, buf, 3); - if (ret < 0) - return ret; - - *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64; - - return 0; -} - -static int mt312_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - u8 buf[3]; - u16 agc; - s16 err_db; - - ret = mt312_read(state, AGC_H, buf, sizeof(buf)); - if (ret < 0) - return ret; - - agc = (buf[0] << 6) | (buf[1] >> 2); - err_db = (s16) (((buf[1] & 0x03) << 14) | buf[2] << 6) >> 6; - - *signal_strength = agc; - - dprintk("agc=%08x err_db=%hd\n", agc, err_db); - - return 0; -} - -static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - u8 buf[2]; - - ret = mt312_read(state, M_SNR_H, buf, sizeof(buf)); - if (ret < 0) - return ret; - - *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1); - - return 0; -} - -static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - u8 buf[2]; - - ret = mt312_read(state, RS_UBC_H, buf, sizeof(buf)); - if (ret < 0) - return ret; - - *ubc = (buf[0] << 8) | buf[1]; - - return 0; -} - -static int mt312_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - u8 buf[5], config_val; - u16 sr; - - const u8 fec_tab[10] = - { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f }; - const u8 inv_tab[3] = { 0x00, 0x40, 0x80 }; - - dprintk("%s: Freq %d\n", __func__, p->frequency); - - if ((p->frequency < fe->ops.info.frequency_min) - || (p->frequency > fe->ops.info.frequency_max)) - return -EINVAL; - - if ((p->inversion < INVERSION_OFF) - || (p->inversion > INVERSION_ON)) - return -EINVAL; - - if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) - || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) - return -EINVAL; - - if ((p->u.qpsk.fec_inner < FEC_NONE) - || (p->u.qpsk.fec_inner > FEC_AUTO)) - return -EINVAL; - - if ((p->u.qpsk.fec_inner == FEC_4_5) - || (p->u.qpsk.fec_inner == FEC_8_9)) - return -EINVAL; - - switch (state->id) { - case ID_VP310: - /* For now we will do this only for the VP310. - * It should be better for the mt312 as well, - * but tuning will be slower. ACCJr 09/29/03 - */ - ret = mt312_readreg(state, CONFIG, &config_val); - if (ret < 0) - return ret; - if (p->u.qpsk.symbol_rate >= 30000000) { - /* Note that 30MS/s should use 90MHz */ - if (state->freq_mult == 6) { - /* We are running 60MHz */ - state->freq_mult = 9; - ret = mt312_initfe(fe); - if (ret < 0) - return ret; - } - } else { - if (state->freq_mult == 9) { - /* We are running 90MHz */ - state->freq_mult = 6; - ret = mt312_initfe(fe); - if (ret < 0) - return ret; - } - } - break; - - case ID_MT312: - case ID_ZL10313: - break; - - default: - return -EINVAL; - } - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* sr = (u16)(sr * 256.0 / 1000000.0) */ - sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625); - - /* SYM_RATE */ - buf[0] = (sr >> 8) & 0x3f; - buf[1] = (sr >> 0) & 0xff; - - /* VIT_MODE */ - buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner]; - - /* QPSK_CTRL */ - buf[3] = 0x40; /* swap I and Q before QPSK demodulation */ - - if (p->u.qpsk.symbol_rate < 10000000) - buf[3] |= 0x04; /* use afc mode */ - - /* GO */ - buf[4] = 0x01; - - ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf)); - if (ret < 0) - return ret; - - mt312_reset(state, 0); - - return 0; -} - -static int mt312_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - - ret = mt312_get_inversion(state, &p->inversion); - if (ret < 0) - return ret; - - ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate); - if (ret < 0) - return ret; - - ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner); - if (ret < 0) - return ret; - - return 0; -} - -static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct mt312_state *state = fe->demodulator_priv; - - u8 val = 0x00; - int ret; - - switch (state->id) { - case ID_ZL10313: - ret = mt312_readreg(state, GPP_CTRL, &val); - if (ret < 0) - goto error; - - /* preserve this bit to not accidently shutdown ADC */ - val &= 0x80; - break; - } - - if (enable) - val |= 0x40; - else - val &= ~0x40; - - ret = mt312_writereg(state, GPP_CTRL, val); - -error: - return ret; -} - -static int mt312_sleep(struct dvb_frontend *fe) -{ - struct mt312_state *state = fe->demodulator_priv; - int ret; - u8 config; - - /* reset all registers to defaults */ - ret = mt312_reset(state, 1); - if (ret < 0) - return ret; - - if (state->id == ID_ZL10313) { - /* reset ADC */ - ret = mt312_writereg(state, GPP_CTRL, 0x00); - if (ret < 0) - return ret; - - /* full shutdown of ADCs, mpeg bus tristated */ - ret = mt312_writereg(state, HW_CTRL, 0x0d); - if (ret < 0) - return ret; - } - - ret = mt312_readreg(state, CONFIG, &config); - if (ret < 0) - return ret; - - /* enter standby */ - ret = mt312_writereg(state, CONFIG, config & 0x7f); - if (ret < 0) - return ret; - - return 0; -} - -static int mt312_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *fesettings) -{ - fesettings->min_delay_ms = 50; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static void mt312_release(struct dvb_frontend *fe) -{ - struct mt312_state *state = fe->demodulator_priv; - kfree(state); -} - -#define MT312_SYS_CLK 90000000UL /* 90 MHz */ -static struct dvb_frontend_ops mt312_ops = { - - .info = { - .name = "Zarlink ???? DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - /* FIXME: adjust freq to real used xtal */ - .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, - .symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */ - .symbol_rate_max = MT312_SYS_CLK / 2, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS | - FE_CAN_RECOVER - }, - - .release = mt312_release, - - .init = mt312_initfe, - .sleep = mt312_sleep, - .i2c_gate_ctrl = mt312_i2c_gate_ctrl, - - .set_frontend = mt312_set_frontend, - .get_frontend = mt312_get_frontend, - .get_tune_settings = mt312_get_tune_settings, - - .read_status = mt312_read_status, - .read_ber = mt312_read_ber, - .read_signal_strength = mt312_read_signal_strength, - .read_snr = mt312_read_snr, - .read_ucblocks = mt312_read_ucblocks, - - .diseqc_send_master_cmd = mt312_send_master_cmd, - .diseqc_send_burst = mt312_send_burst, - .set_tone = mt312_set_tone, - .set_voltage = mt312_set_voltage, -}; - -struct dvb_frontend *mt312_attach(const struct mt312_config *config, - struct i2c_adapter *i2c) -{ - struct mt312_state *state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct mt312_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* check if the demod is there */ - if (mt312_readreg(state, ID, &state->id) < 0) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &mt312_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - switch (state->id) { - case ID_VP310: - strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S"); - state->xtal = MT312_PLL_CLK; - state->freq_mult = 9; - break; - case ID_MT312: - strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S"); - state->xtal = MT312_PLL_CLK; - state->freq_mult = 6; - break; - case ID_ZL10313: - strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S"); - state->xtal = MT312_PLL_CLK_10_111; - state->freq_mult = 9; - break; - default: - printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313" - " are supported chips.\n"); - goto error; - } - - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(mt312_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver"); -MODULE_AUTHOR("Andreas Oberritter "); -MODULE_AUTHOR("Matthias Schwarzott "); -MODULE_LICENSE("GPL"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - Driver for Zarlink MT312 Satellite Channel Decoder - - Copyright (C) 2003 Andreas Oberritter - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - References: - http://products.zarlink.com/product_profiles/MT312.htm - http://products.zarlink.com/product_profiles/SL1935.htm -*/ - -#ifndef MT312_H -#define MT312_H - -#include - -struct mt312_config { - /* the demodulator's i2c address */ - u8 demod_address; - - /* inverted voltage setting */ - unsigned int voltage_inverted:1; -}; - -#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE)) -struct dvb_frontend *mt312_attach(const struct mt312_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *mt312_attach( - const struct mt312_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_MT312 */ - -#endif /* MT312_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt312_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -/* - Driver for Zarlink MT312 QPSK Frontend - - Copyright (C) 2003 Andreas Oberritter - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef _DVB_FRONTENDS_MT312_PRIV -#define _DVB_FRONTENDS_MT312_PRIV - -enum mt312_reg_addr { - QPSK_INT_H = 0, - QPSK_INT_M = 1, - QPSK_INT_L = 2, - FEC_INT = 3, - QPSK_STAT_H = 4, - QPSK_STAT_L = 5, - FEC_STATUS = 6, - LNB_FREQ_H = 7, - LNB_FREQ_L = 8, - M_SNR_H = 9, - M_SNR_L = 10, - VIT_ERRCNT_H = 11, - VIT_ERRCNT_M = 12, - VIT_ERRCNT_L = 13, - RS_BERCNT_H = 14, - RS_BERCNT_M = 15, - RS_BERCNT_L = 16, - RS_UBC_H = 17, - RS_UBC_L = 18, - SIG_LEVEL = 19, - GPP_CTRL = 20, - RESET = 21, - DISEQC_MODE = 22, - SYM_RATE_H = 23, - SYM_RATE_L = 24, - VIT_MODE = 25, - QPSK_CTRL = 26, - GO = 27, - IE_QPSK_H = 28, - IE_QPSK_M = 29, - IE_QPSK_L = 30, - IE_FEC = 31, - QPSK_STAT_EN = 32, - FEC_STAT_EN = 33, - SYS_CLK = 34, - DISEQC_RATIO = 35, - DISEQC_INSTR = 36, - FR_LIM = 37, - FR_OFF = 38, - AGC_CTRL = 39, - AGC_INIT = 40, - AGC_REF = 41, - AGC_MAX = 42, - AGC_MIN = 43, - AGC_LK_TH = 44, - TS_AGC_LK_TH = 45, - AGC_PWR_SET = 46, - QPSK_MISC = 47, - SNR_THS_LOW = 48, - SNR_THS_HIGH = 49, - TS_SW_RATE = 50, - TS_SW_LIM_L = 51, - TS_SW_LIM_H = 52, - CS_SW_RATE_1 = 53, - CS_SW_RATE_2 = 54, - CS_SW_RATE_3 = 55, - CS_SW_RATE_4 = 56, - CS_SW_LIM = 57, - TS_LPK = 58, - TS_LPK_M = 59, - TS_LPK_L = 60, - CS_KPROP_H = 61, - CS_KPROP_L = 62, - CS_KINT_H = 63, - CS_KINT_L = 64, - QPSK_SCALE = 65, - TLD_OUTCLK_TH = 66, - TLD_INCLK_TH = 67, - FLD_TH = 68, - PLD_OUTLK3 = 69, - PLD_OUTLK2 = 70, - PLD_OUTLK1 = 71, - PLD_OUTLK0 = 72, - PLD_INLK3 = 73, - PLD_INLK2 = 74, - PLD_INLK1 = 75, - PLD_INLK0 = 76, - PLD_ACC_TIME = 77, - SWEEP_PAR = 78, - STARTUP_TIME = 79, - LOSSLOCK_TH = 80, - FEC_LOCK_TM = 81, - LOSSLOCK_TM = 82, - VIT_ERRPER_H = 83, - VIT_ERRPER_M = 84, - VIT_ERRPER_L = 85, - HW_CTRL = 84, /* ZL10313 only */ - MPEG_CTRL = 85, /* ZL10313 only */ - VIT_SETUP = 86, - VIT_REF0 = 87, - VIT_REF1 = 88, - VIT_REF2 = 89, - VIT_REF3 = 90, - VIT_REF4 = 91, - VIT_REF5 = 92, - VIT_REF6 = 93, - VIT_MAXERR = 94, - BA_SETUPT = 95, - OP_CTRL = 96, - FEC_SETUP = 97, - PROG_SYNC = 98, - AFC_SEAR_TH = 99, - CSACC_DIF_TH = 100, - QPSK_LK_CT = 101, - QPSK_ST_CT = 102, - MON_CTRL = 103, - QPSK_RESET = 104, - QPSK_TST_CT = 105, - QPSK_TST_ST = 106, - TEST_R = 107, - AGC_H = 108, - AGC_M = 109, - AGC_L = 110, - FREQ_ERR1_H = 111, - FREQ_ERR1_M = 112, - FREQ_ERR1_L = 113, - FREQ_ERR2_H = 114, - FREQ_ERR2_L = 115, - SYM_RAT_OP_H = 116, - SYM_RAT_OP_L = 117, - DESEQC2_INT = 118, - DISEQC2_STAT = 119, - DISEQC2_FIFO = 120, - DISEQC2_CTRL1 = 121, - DISEQC2_CTRL2 = 122, - MONITOR_H = 123, - MONITOR_L = 124, - TEST_MODE = 125, - ID = 126, - CONFIG = 127 -}; - -enum mt312_model_id { - ID_VP310 = 1, - ID_MT312 = 3, - ID_ZL10313 = 5, -}; - -#endif /* DVB_FRONTENDS_MT312_PRIV */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,613 +0,0 @@ -/* - * Driver for Zarlink DVB-T MT352 demodulator - * - * Written by Holger Waechtler - * and Daniel Mack - * - * AVerMedia AVerTV DVB-T 771 support by - * Wolfram Joost - * - * Support for Samsung TDTC9251DH01C(M) tuner - * Copyright (C) 2004 Antonio Mancuso - * Amauri Celani - * - * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by - * Christopher Pascoe - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "mt352_priv.h" -#include "mt352.h" - -struct mt352_state { - struct i2c_adapter* i2c; - struct dvb_frontend frontend; - - /* configuration settings */ - struct mt352_config config; -}; - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "mt352: " args); \ - } while (0) - -static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val) -{ - struct mt352_state* state = fe->demodulator_priv; - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0, - .buf = buf, .len = 2 }; - int err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) { - printk("mt352_write() to reg %x failed (err = %d)!\n", reg, err); - return err; - } - return 0; -} - -static int _mt352_write(struct dvb_frontend* fe, const u8 ibuf[], int ilen) -{ - int err,i; - for (i=0; i < ilen-1; i++) - if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1]))) - return err; - - return 0; -} - -static int mt352_read_register(struct mt352_state* state, u8 reg) -{ - int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config.demod_address, - .flags = 0, - .buf = b0, .len = 1 }, - { .addr = state->config.demod_address, - .flags = I2C_M_RD, - .buf = b1, .len = 1 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - printk("%s: readreg error (reg=%d, ret==%i)\n", - __func__, reg, ret); - return ret; - } - - return b1[0]; -} - -static int mt352_sleep(struct dvb_frontend* fe) -{ - static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 }; - - _mt352_write(fe, mt352_softdown, sizeof(mt352_softdown)); - return 0; -} - -static void mt352_calc_nominal_rate(struct mt352_state* state, - enum fe_bandwidth bandwidth, - unsigned char *buf) -{ - u32 adc_clock = 20480; /* 20.340 MHz */ - u32 bw,value; - - switch (bandwidth) { - case BANDWIDTH_6_MHZ: - bw = 6; - break; - case BANDWIDTH_7_MHZ: - bw = 7; - break; - case BANDWIDTH_8_MHZ: - default: - bw = 8; - break; - } - if (state->config.adc_clock) - adc_clock = state->config.adc_clock; - - value = 64 * bw * (1<<16) / (7 * 8); - value = value * 1000 / adc_clock; - dprintk("%s: bw %d, adc_clock %d => 0x%x\n", - __func__, bw, adc_clock, value); - buf[0] = msb(value); - buf[1] = lsb(value); -} - -static void mt352_calc_input_freq(struct mt352_state* state, - unsigned char *buf) -{ - int adc_clock = 20480; /* 20.480000 MHz */ - int if2 = 36167; /* 36.166667 MHz */ - int ife,value; - - if (state->config.adc_clock) - adc_clock = state->config.adc_clock; - if (state->config.if2) - if2 = state->config.if2; - - if (adc_clock >= if2 * 2) - ife = if2; - else { - ife = adc_clock - (if2 % adc_clock); - if (ife > adc_clock / 2) - ife = adc_clock - ife; - } - value = -16374 * ife / adc_clock; - dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", - __func__, if2, ife, adc_clock, value, value & 0x3fff); - buf[0] = msb(value); - buf[1] = lsb(value); -} - -static int mt352_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) -{ - struct mt352_state* state = fe->demodulator_priv; - unsigned char buf[13]; - static unsigned char tuner_go[] = { 0x5d, 0x01 }; - static unsigned char fsm_go[] = { 0x5e, 0x01 }; - unsigned int tps = 0; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - - switch (op->code_rate_HP) { - case FEC_2_3: - tps |= (1 << 7); - break; - case FEC_3_4: - tps |= (2 << 7); - break; - case FEC_5_6: - tps |= (3 << 7); - break; - case FEC_7_8: - tps |= (4 << 7); - break; - case FEC_1_2: - case FEC_AUTO: - break; - default: - return -EINVAL; - } - - switch (op->code_rate_LP) { - case FEC_2_3: - tps |= (1 << 4); - break; - case FEC_3_4: - tps |= (2 << 4); - break; - case FEC_5_6: - tps |= (3 << 4); - break; - case FEC_7_8: - tps |= (4 << 4); - break; - case FEC_1_2: - case FEC_AUTO: - break; - case FEC_NONE: - if (op->hierarchy_information == HIERARCHY_AUTO || - op->hierarchy_information == HIERARCHY_NONE) - break; - default: - return -EINVAL; - } - - switch (op->constellation) { - case QPSK: - break; - case QAM_AUTO: - case QAM_16: - tps |= (1 << 13); - break; - case QAM_64: - tps |= (2 << 13); - break; - default: - return -EINVAL; - } - - switch (op->transmission_mode) { - case TRANSMISSION_MODE_2K: - case TRANSMISSION_MODE_AUTO: - break; - case TRANSMISSION_MODE_8K: - tps |= (1 << 0); - break; - default: - return -EINVAL; - } - - switch (op->guard_interval) { - case GUARD_INTERVAL_1_32: - case GUARD_INTERVAL_AUTO: - break; - case GUARD_INTERVAL_1_16: - tps |= (1 << 2); - break; - case GUARD_INTERVAL_1_8: - tps |= (2 << 2); - break; - case GUARD_INTERVAL_1_4: - tps |= (3 << 2); - break; - default: - return -EINVAL; - } - - switch (op->hierarchy_information) { - case HIERARCHY_AUTO: - case HIERARCHY_NONE: - break; - case HIERARCHY_1: - tps |= (1 << 10); - break; - case HIERARCHY_2: - tps |= (2 << 10); - break; - case HIERARCHY_4: - tps |= (3 << 10); - break; - default: - return -EINVAL; - } - - - buf[0] = TPS_GIVEN_1; /* TPS_GIVEN_1 and following registers */ - - buf[1] = msb(tps); /* TPS_GIVEN_(1|0) */ - buf[2] = lsb(tps); - - buf[3] = 0x50; // old -// buf[3] = 0xf4; // pinnacle - - mt352_calc_nominal_rate(state, op->bandwidth, buf+4); - mt352_calc_input_freq(state, buf+6); - - if (state->config.no_tuner) { - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - _mt352_write(fe, buf, 8); - _mt352_write(fe, fsm_go, 2); - } else { - if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5); - buf[8] <<= 1; - _mt352_write(fe, buf, sizeof(buf)); - _mt352_write(fe, tuner_go, 2); - } - } - - return 0; -} - -static int mt352_get_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) -{ - struct mt352_state* state = fe->demodulator_priv; - u16 tps; - u16 div; - u8 trl; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - static const u8 tps_fec_to_api[8] = - { - FEC_1_2, - FEC_2_3, - FEC_3_4, - FEC_5_6, - FEC_7_8, - FEC_AUTO, - FEC_AUTO, - FEC_AUTO - }; - - if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 ) - return -EINVAL; - - /* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because - * the mt352 sometimes works with the wrong parameters - */ - tps = (mt352_read_register(state, TPS_RECEIVED_1) << 8) | mt352_read_register(state, TPS_RECEIVED_0); - div = (mt352_read_register(state, CHAN_START_1) << 8) | mt352_read_register(state, CHAN_START_0); - trl = mt352_read_register(state, TRL_NOMINAL_RATE_1); - - op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; - op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; - - switch ( (tps >> 13) & 3) - { - case 0: - op->constellation = QPSK; - break; - case 1: - op->constellation = QAM_16; - break; - case 2: - op->constellation = QAM_64; - break; - default: - op->constellation = QAM_AUTO; - break; - } - - op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K; - - switch ( (tps >> 2) & 3) - { - case 0: - op->guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - op->guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - op->guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - op->guard_interval = GUARD_INTERVAL_1_4; - break; - default: - op->guard_interval = GUARD_INTERVAL_AUTO; - break; - } - - switch ( (tps >> 10) & 7) - { - case 0: - op->hierarchy_information = HIERARCHY_NONE; - break; - case 1: - op->hierarchy_information = HIERARCHY_1; - break; - case 2: - op->hierarchy_information = HIERARCHY_2; - break; - case 3: - op->hierarchy_information = HIERARCHY_4; - break; - default: - op->hierarchy_information = HIERARCHY_AUTO; - break; - } - - param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000; - - if (trl == 0x72) - op->bandwidth = BANDWIDTH_8_MHZ; - else if (trl == 0x64) - op->bandwidth = BANDWIDTH_7_MHZ; - else - op->bandwidth = BANDWIDTH_6_MHZ; - - - if (mt352_read_register(state, STATUS_2) & 0x02) - param->inversion = INVERSION_OFF; - else - param->inversion = INVERSION_ON; - - return 0; -} - -static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct mt352_state* state = fe->demodulator_priv; - int s0, s1, s3; - - /* FIXME: - * - * The MT352 design manual from Zarlink states (page 46-47): - * - * Notes about the TUNER_GO register: - * - * If the Read_Tuner_Byte (bit-1) is activated, then the tuner status - * byte is copied from the tuner to the STATUS_3 register and - * completion of the read operation is indicated by bit-5 of the - * INTERRUPT_3 register. - */ - - if ((s0 = mt352_read_register(state, STATUS_0)) < 0) - return -EREMOTEIO; - if ((s1 = mt352_read_register(state, STATUS_1)) < 0) - return -EREMOTEIO; - if ((s3 = mt352_read_register(state, STATUS_3)) < 0) - return -EREMOTEIO; - - *status = 0; - if (s0 & (1 << 4)) - *status |= FE_HAS_CARRIER; - if (s0 & (1 << 1)) - *status |= FE_HAS_VITERBI; - if (s0 & (1 << 5)) - *status |= FE_HAS_LOCK; - if (s1 & (1 << 1)) - *status |= FE_HAS_SYNC; - if (s3 & (1 << 6)) - *status |= FE_HAS_SIGNAL; - - if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != - (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) - *status &= ~FE_HAS_LOCK; - - return 0; -} - -static int mt352_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct mt352_state* state = fe->demodulator_priv; - - *ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) | - (mt352_read_register (state, RS_ERR_CNT_1) << 8) | - (mt352_read_register (state, RS_ERR_CNT_0)); - - return 0; -} - -static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct mt352_state* state = fe->demodulator_priv; - - /* align the 12 bit AGC gain with the most significant bits */ - u16 signal = ((mt352_read_register(state, AGC_GAIN_1) & 0x0f) << 12) | - (mt352_read_register(state, AGC_GAIN_0) << 4); - - /* inverse of gain is signal strength */ - *strength = ~signal; - return 0; -} - -static int mt352_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct mt352_state* state = fe->demodulator_priv; - - u8 _snr = mt352_read_register (state, SNR); - *snr = (_snr << 8) | _snr; - - return 0; -} - -static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct mt352_state* state = fe->demodulator_priv; - - *ucblocks = (mt352_read_register (state, RS_UBC_1) << 8) | - (mt352_read_register (state, RS_UBC_0)); - - return 0; -} - -static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) -{ - fe_tune_settings->min_delay_ms = 800; - fe_tune_settings->step_size = 0; - fe_tune_settings->max_drift = 0; - - return 0; -} - -static int mt352_init(struct dvb_frontend* fe) -{ - struct mt352_state* state = fe->demodulator_priv; - - static u8 mt352_reset_attach [] = { RESET, 0xC0 }; - - dprintk("%s: hello\n",__func__); - - if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 || - (mt352_read_register(state, CONFIG) & 0x20) == 0) { - - /* Do a "hard" reset */ - _mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach)); - return state->config.demod_init(fe); - } - - return 0; -} - -static void mt352_release(struct dvb_frontend* fe) -{ - struct mt352_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops mt352_ops; - -struct dvb_frontend* mt352_attach(const struct mt352_config* config, - struct i2c_adapter* i2c) -{ - struct mt352_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct mt352_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->i2c = i2c; - memcpy(&state->config,config,sizeof(struct mt352_config)); - - /* check if the demod is there */ - if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops mt352_ops = { - - .info = { - .name = "Zarlink MT352 DVB-T", - .type = FE_OFDM, - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .frequency_tolerance = 0, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | - FE_CAN_MUTE_TS - }, - - .release = mt352_release, - - .init = mt352_init, - .sleep = mt352_sleep, - .write = _mt352_write, - - .set_frontend = mt352_set_parameters, - .get_frontend = mt352_get_parameters, - .get_tune_settings = mt352_get_tune_settings, - - .read_status = mt352_read_status, - .read_ber = mt352_read_ber, - .read_signal_strength = mt352_read_signal_strength, - .read_snr = mt352_read_snr, - .read_ucblocks = mt352_read_ucblocks, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Zarlink MT352 DVB-T Demodulator driver"); -MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(mt352_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* - * Driver for Zarlink DVB-T MT352 demodulator - * - * Written by Holger Waechtler - * and Daniel Mack - * - * AVerMedia AVerTV DVB-T 771 support by - * Wolfram Joost - * - * Support for Samsung TDTC9251DH01C(M) tuner - * Copyright (C) 2004 Antonio Mancuso - * Amauri Celani - * - * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by - * Christopher Pascoe - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef MT352_H -#define MT352_H - -#include - -struct mt352_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* frequencies in kHz */ - int adc_clock; // default: 20480 - int if2; // default: 36166 - - /* set if no pll is connected to the secondary i2c bus */ - int no_tuner; - - /* Initialise the demodulator and PLL. Cannot be NULL */ - int (*demod_init)(struct dvb_frontend* fe); -}; - -#if defined(CONFIG_DVB_MT352) || (defined(CONFIG_DVB_MT352_MODULE) && defined(MODULE)) -extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* mt352_attach(const struct mt352_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_MT352 - -static inline int mt352_write(struct dvb_frontend *fe, const u8 buf[], int len) { - int r = 0; - if (fe->ops.write) - r = fe->ops.write(fe, buf, len); - return r; -} - -#endif // MT352_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/mt352_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -/* - * Driver for Zarlink DVB-T MT352 demodulator - * - * Written by Holger Waechtler - * and Daniel Mack - * - * AVerMedia AVerTV DVB-T 771 support by - * Wolfram Joost - * - * Support for Samsung TDTC9251DH01C(M) tuner - * Copyright (C) 2004 Antonio Mancuso - * Amauri Celani - * - * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by - * Christopher Pascoe - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef _MT352_PRIV_ -#define _MT352_PRIV_ - -#define ID_MT352 0x13 - -#define msb(x) (((x) >> 8) & 0xff) -#define lsb(x) ((x) & 0xff) - -enum mt352_reg_addr { - STATUS_0 = 0x00, - STATUS_1 = 0x01, - STATUS_2 = 0x02, - STATUS_3 = 0x03, - STATUS_4 = 0x04, - INTERRUPT_0 = 0x05, - INTERRUPT_1 = 0x06, - INTERRUPT_2 = 0x07, - INTERRUPT_3 = 0x08, - SNR = 0x09, - VIT_ERR_CNT_2 = 0x0A, - VIT_ERR_CNT_1 = 0x0B, - VIT_ERR_CNT_0 = 0x0C, - RS_ERR_CNT_2 = 0x0D, - RS_ERR_CNT_1 = 0x0E, - RS_ERR_CNT_0 = 0x0F, - RS_UBC_1 = 0x10, - RS_UBC_0 = 0x11, - AGC_GAIN_3 = 0x12, - AGC_GAIN_2 = 0x13, - AGC_GAIN_1 = 0x14, - AGC_GAIN_0 = 0x15, - FREQ_OFFSET_2 = 0x17, - FREQ_OFFSET_1 = 0x18, - FREQ_OFFSET_0 = 0x19, - TIMING_OFFSET_1 = 0x1A, - TIMING_OFFSET_0 = 0x1B, - CHAN_FREQ_1 = 0x1C, - CHAN_FREQ_0 = 0x1D, - TPS_RECEIVED_1 = 0x1E, - TPS_RECEIVED_0 = 0x1F, - TPS_CURRENT_1 = 0x20, - TPS_CURRENT_0 = 0x21, - TPS_CELL_ID_1 = 0x22, - TPS_CELL_ID_0 = 0x23, - TPS_MISC_DATA_2 = 0x24, - TPS_MISC_DATA_1 = 0x25, - TPS_MISC_DATA_0 = 0x26, - RESET = 0x50, - TPS_GIVEN_1 = 0x51, - TPS_GIVEN_0 = 0x52, - ACQ_CTL = 0x53, - TRL_NOMINAL_RATE_1 = 0x54, - TRL_NOMINAL_RATE_0 = 0x55, - INPUT_FREQ_1 = 0x56, - INPUT_FREQ_0 = 0x57, - TUNER_ADDR = 0x58, - CHAN_START_1 = 0x59, - CHAN_START_0 = 0x5A, - CONT_1 = 0x5B, - CONT_0 = 0x5C, - TUNER_GO = 0x5D, - STATUS_EN_0 = 0x5F, - STATUS_EN_1 = 0x60, - INTERRUPT_EN_0 = 0x61, - INTERRUPT_EN_1 = 0x62, - INTERRUPT_EN_2 = 0x63, - INTERRUPT_EN_3 = 0x64, - AGC_TARGET = 0x67, - AGC_CTL = 0x68, - CAPT_RANGE = 0x75, - SNR_SELECT_1 = 0x79, - SNR_SELECT_0 = 0x7A, - RS_ERR_PER_1 = 0x7C, - RS_ERR_PER_0 = 0x7D, - CHIP_ID = 0x7F, - CHAN_STOP_1 = 0x80, - CHAN_STOP_0 = 0x81, - CHAN_STEP_1 = 0x82, - CHAN_STEP_0 = 0x83, - FEC_LOCK_TIME = 0x85, - OFDM_LOCK_TIME = 0x86, - ACQ_DELAY = 0x87, - SCAN_CTL = 0x88, - CLOCK_CTL = 0x89, - CONFIG = 0x8A, - MCLK_RATIO = 0x8B, - GPP_CTL = 0x8C, - ADC_CTL_1 = 0x8E, - ADC_CTL_0 = 0x8F -}; - -/* here we assume 1/6MHz == 166.66kHz stepsize */ -#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - -#endif /* _MT352_PRIV_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt200x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt200x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt200x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt200x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1241 +0,0 @@ -/* - * Support for NXT2002 and NXT2004 - VSB/QAM - * - * Copyright (C) 2005 Kirk Lapray - * Copyright (C) 2006 Michael Krufky - * based on nxt2002 by Taylor Jacob - * and nxt2004 by Jean-Francois Thibert - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * -*/ - -/* - * NOTES ABOUT THIS DRIVER - * - * This Linux driver supports: - * B2C2/BBTI Technisat Air2PC - ATSC (NXT2002) - * AverTVHD MCE A180 (NXT2004) - * ATI HDTV Wonder (NXT2004) - * - * This driver needs external firmware. Please use the command - * "/Documentation/dvb/get_dvb_firmware nxt2002" or - * "/Documentation/dvb/get_dvb_firmware nxt2004" to - * download/extract the appropriate firmware, and then copy it to - * /usr/lib/hotplug/firmware/ or /lib/firmware/ - * (depending on configuration of firmware hotplug). - */ -#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" -#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw" -#define CRC_CCIT_MASK 0x1021 - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "nxt200x.h" - -struct nxt200x_state { - - struct i2c_adapter* i2c; - const struct nxt200x_config* config; - struct dvb_frontend frontend; - - /* demodulator private data */ - nxt_chip_type demod_chip; - u8 initialised:1; -}; - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "nxt200x: " args); \ - } while (0) - -static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len) -{ - int err; - struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len }; - - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n", - __func__, addr, err); - return -EREMOTEIO; - } - return 0; -} - -static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len) -{ - int err; - struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; - - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n", - __func__, addr, err); - return -EREMOTEIO; - } - return 0; -} - -static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, - const u8 *buf, u8 len) -{ - u8 buf2 [len+1]; - int err; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 }; - - buf2[0] = reg; - memcpy(&buf2[1], buf, len); - - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n", - __func__, state->config->demod_address, err); - return -EREMOTEIO; - } - return 0; -} - -static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len) -{ - u8 reg2 [] = { reg }; - - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } }; - - int err; - - if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { - printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n", - __func__, state->config->demod_address, err); - return -EREMOTEIO; - } - return 0; -} - -static u16 nxt200x_crc(u16 crc, u8 c) -{ - u8 i; - u16 input = (u16) c & 0xFF; - - input<<=8; - for(i=0; i<8; i++) { - if((crc^input) & 0x8000) - crc=(crc<<1)^CRC_CCIT_MASK; - else - crc<<=1; - input<<=1; - } - return crc; -} - -static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) -{ - u8 attr, len2, buf; - dprintk("%s\n", __func__); - - /* set mutli register register */ - nxt200x_writebytes(state, 0x35, ®, 1); - - /* send the actual data */ - nxt200x_writebytes(state, 0x36, data, len); - - switch (state->demod_chip) { - case NXT2002: - len2 = len; - buf = 0x02; - break; - case NXT2004: - /* probably not right, but gives correct values */ - attr = 0x02; - if (reg & 0x80) { - attr = attr << 1; - if (reg & 0x04) - attr = attr >> 1; - } - /* set write bit */ - len2 = ((attr << 4) | 0x10) | len; - buf = 0x80; - break; - default: - return -EINVAL; - break; - } - - /* set multi register length */ - nxt200x_writebytes(state, 0x34, &len2, 1); - - /* toggle the multireg write bit */ - nxt200x_writebytes(state, 0x21, &buf, 1); - - nxt200x_readbytes(state, 0x21, &buf, 1); - - switch (state->demod_chip) { - case NXT2002: - if ((buf & 0x02) == 0) - return 0; - break; - case NXT2004: - if (buf == 0) - return 0; - break; - default: - return -EINVAL; - break; - } - - printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg); - - return 0; -} - -static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) -{ - int i; - u8 buf, len2, attr; - dprintk("%s\n", __func__); - - /* set mutli register register */ - nxt200x_writebytes(state, 0x35, ®, 1); - - switch (state->demod_chip) { - case NXT2002: - /* set multi register length */ - len2 = len & 0x80; - nxt200x_writebytes(state, 0x34, &len2, 1); - - /* read the actual data */ - nxt200x_readbytes(state, reg, data, len); - return 0; - break; - case NXT2004: - /* probably not right, but gives correct values */ - attr = 0x02; - if (reg & 0x80) { - attr = attr << 1; - if (reg & 0x04) - attr = attr >> 1; - } - - /* set multi register length */ - len2 = (attr << 4) | len; - nxt200x_writebytes(state, 0x34, &len2, 1); - - /* toggle the multireg bit*/ - buf = 0x80; - nxt200x_writebytes(state, 0x21, &buf, 1); - - /* read the actual data */ - for(i = 0; i < len; i++) { - nxt200x_readbytes(state, 0x36 + i, &data[i], 1); - } - return 0; - break; - default: - return -EINVAL; - break; - } -} - -static void nxt200x_microcontroller_stop (struct nxt200x_state* state) -{ - u8 buf, stopval, counter = 0; - dprintk("%s\n", __func__); - - /* set correct stop value */ - switch (state->demod_chip) { - case NXT2002: - stopval = 0x40; - break; - case NXT2004: - stopval = 0x10; - break; - default: - stopval = 0; - break; - } - - buf = 0x80; - nxt200x_writebytes(state, 0x22, &buf, 1); - - while (counter < 20) { - nxt200x_readbytes(state, 0x31, &buf, 1); - if (buf & stopval) - return; - msleep(10); - counter++; - } - - printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n"); - return; -} - -static void nxt200x_microcontroller_start (struct nxt200x_state* state) -{ - u8 buf; - dprintk("%s\n", __func__); - - buf = 0x00; - nxt200x_writebytes(state, 0x22, &buf, 1); -} - -static void nxt2004_microcontroller_init (struct nxt200x_state* state) -{ - u8 buf[9]; - u8 counter = 0; - dprintk("%s\n", __func__); - - buf[0] = 0x00; - nxt200x_writebytes(state, 0x2b, buf, 1); - buf[0] = 0x70; - nxt200x_writebytes(state, 0x34, buf, 1); - buf[0] = 0x04; - nxt200x_writebytes(state, 0x35, buf, 1); - buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89; - buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0; - nxt200x_writebytes(state, 0x36, buf, 9); - buf[0] = 0x80; - nxt200x_writebytes(state, 0x21, buf, 1); - - while (counter < 20) { - nxt200x_readbytes(state, 0x21, buf, 1); - if (buf[0] == 0) - return; - msleep(10); - counter++; - } - - printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n"); - - return; -} - -static int nxt200x_writetuner (struct nxt200x_state* state, u8* data) -{ - u8 buf, count = 0; - - dprintk("%s\n", __func__); - - dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]); - - /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip. - * direct write is required for Philips TUV1236D and ALPS TDHU2 */ - switch (state->demod_chip) { - case NXT2004: - if (i2c_writebytes(state, data[0], data+1, 4)) - printk(KERN_WARNING "nxt200x: error writing to tuner\n"); - /* wait until we have a lock */ - while (count < 20) { - i2c_readbytes(state, data[0], &buf, 1); - if (buf & 0x40) - return 0; - msleep(100); - count++; - } - printk("nxt2004: timeout waiting for tuner lock\n"); - break; - case NXT2002: - /* set the i2c transfer speed to the tuner */ - buf = 0x03; - nxt200x_writebytes(state, 0x20, &buf, 1); - - /* setup to transfer 4 bytes via i2c */ - buf = 0x04; - nxt200x_writebytes(state, 0x34, &buf, 1); - - /* write actual tuner bytes */ - nxt200x_writebytes(state, 0x36, data+1, 4); - - /* set tuner i2c address */ - buf = data[0] << 1; - nxt200x_writebytes(state, 0x35, &buf, 1); - - /* write UC Opmode to begin transfer */ - buf = 0x80; - nxt200x_writebytes(state, 0x21, &buf, 1); - - while (count < 20) { - nxt200x_readbytes(state, 0x21, &buf, 1); - if ((buf & 0x80)== 0x00) - return 0; - msleep(100); - count++; - } - printk("nxt2002: timeout error writing tuner\n"); - break; - default: - return -EINVAL; - break; - } - return 0; -} - -static void nxt200x_agc_reset(struct nxt200x_state* state) -{ - u8 buf; - dprintk("%s\n", __func__); - - switch (state->demod_chip) { - case NXT2002: - buf = 0x08; - nxt200x_writebytes(state, 0x08, &buf, 1); - buf = 0x00; - nxt200x_writebytes(state, 0x08, &buf, 1); - break; - case NXT2004: - nxt200x_readreg_multibyte(state, 0x08, &buf, 1); - buf = 0x08; - nxt200x_writereg_multibyte(state, 0x08, &buf, 1); - buf = 0x00; - nxt200x_writereg_multibyte(state, 0x08, &buf, 1); - break; - default: - break; - } - return; -} - -static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) -{ - - struct nxt200x_state* state = fe->demodulator_priv; - u8 buf[3], written = 0, chunkpos = 0; - u16 rambase, position, crc = 0; - - dprintk("%s\n", __func__); - dprintk("Firmware is %zu bytes\n", fw->size); - - /* Get the RAM base for this nxt2002 */ - nxt200x_readbytes(state, 0x10, buf, 1); - - if (buf[0] & 0x10) - rambase = 0x1000; - else - rambase = 0x0000; - - dprintk("rambase on this nxt2002 is %04X\n", rambase); - - /* Hold the micro in reset while loading firmware */ - buf[0] = 0x80; - nxt200x_writebytes(state, 0x2B, buf, 1); - - for (position = 0; position < fw->size; position++) { - if (written == 0) { - crc = 0; - chunkpos = 0x28; - buf[0] = ((rambase + position) >> 8); - buf[1] = (rambase + position) & 0xFF; - buf[2] = 0x81; - /* write starting address */ - nxt200x_writebytes(state, 0x29, buf, 3); - } - written++; - chunkpos++; - - if ((written % 4) == 0) - nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4); - - crc = nxt200x_crc(crc, fw->data[position]); - - if ((written == 255) || (position+1 == fw->size)) { - /* write remaining bytes of firmware */ - nxt200x_writebytes(state, chunkpos+4-(written %4), - &fw->data[position-(written %4) + 1], - written %4); - buf[0] = crc << 8; - buf[1] = crc & 0xFF; - - /* write crc */ - nxt200x_writebytes(state, 0x2C, buf, 2); - - /* do a read to stop things */ - nxt200x_readbytes(state, 0x2A, buf, 1); - - /* set transfer mode to complete */ - buf[0] = 0x80; - nxt200x_writebytes(state, 0x2B, buf, 1); - - written = 0; - } - } - - return 0; -}; - -static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) -{ - - struct nxt200x_state* state = fe->demodulator_priv; - u8 buf[3]; - u16 rambase, position, crc=0; - - dprintk("%s\n", __func__); - dprintk("Firmware is %zu bytes\n", fw->size); - - /* set rambase */ - rambase = 0x1000; - - /* hold the micro in reset while loading firmware */ - buf[0] = 0x80; - nxt200x_writebytes(state, 0x2B, buf,1); - - /* calculate firmware CRC */ - for (position = 0; position < fw->size; position++) { - crc = nxt200x_crc(crc, fw->data[position]); - } - - buf[0] = rambase >> 8; - buf[1] = rambase & 0xFF; - buf[2] = 0x81; - /* write starting address */ - nxt200x_writebytes(state,0x29,buf,3); - - for (position = 0; position < fw->size;) { - nxt200x_writebytes(state, 0x2C, &fw->data[position], - fw->size-position > 255 ? 255 : fw->size-position); - position += (fw->size-position > 255 ? 255 : fw->size-position); - } - buf[0] = crc >> 8; - buf[1] = crc & 0xFF; - - dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]); - - /* write crc */ - nxt200x_writebytes(state, 0x2C, buf,2); - - /* do a read to stop things */ - nxt200x_readbytes(state, 0x2C, buf, 1); - - /* set transfer mode to complete */ - buf[0] = 0x80; - nxt200x_writebytes(state, 0x2B, buf,1); - - return 0; -}; - -static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) -{ - struct nxt200x_state* state = fe->demodulator_priv; - u8 buf[5]; - - /* stop the micro first */ - nxt200x_microcontroller_stop(state); - - if (state->demod_chip == NXT2004) { - /* make sure demod is set to digital */ - buf[0] = 0x04; - nxt200x_writebytes(state, 0x14, buf, 1); - buf[0] = 0x00; - nxt200x_writebytes(state, 0x17, buf, 1); - } - - /* set additional params */ - switch (p->u.vsb.modulation) { - case QAM_64: - case QAM_256: - /* Set punctured clock for QAM */ - /* This is just a guess since I am unable to test it */ - if (state->config->set_ts_params) - state->config->set_ts_params(fe, 1); - break; - case VSB_8: - /* Set non-punctured clock for VSB */ - if (state->config->set_ts_params) - state->config->set_ts_params(fe, 0); - break; - default: - return -EINVAL; - break; - } - - if (fe->ops.tuner_ops.calc_regs) { - /* get tuning information */ - fe->ops.tuner_ops.calc_regs(fe, p, buf, 5); - - /* write frequency information */ - nxt200x_writetuner(state, buf); - } - - /* reset the agc now that tuning has been completed */ - nxt200x_agc_reset(state); - - /* set target power level */ - switch (p->u.vsb.modulation) { - case QAM_64: - case QAM_256: - buf[0] = 0x74; - break; - case VSB_8: - buf[0] = 0x70; - break; - default: - return -EINVAL; - break; - } - nxt200x_writebytes(state, 0x42, buf, 1); - - /* configure sdm */ - switch (state->demod_chip) { - case NXT2002: - buf[0] = 0x87; - break; - case NXT2004: - buf[0] = 0x07; - break; - default: - return -EINVAL; - break; - } - nxt200x_writebytes(state, 0x57, buf, 1); - - /* write sdm1 input */ - buf[0] = 0x10; - buf[1] = 0x00; - switch (state->demod_chip) { - case NXT2002: - nxt200x_writereg_multibyte(state, 0x58, buf, 2); - break; - case NXT2004: - nxt200x_writebytes(state, 0x58, buf, 2); - break; - default: - return -EINVAL; - break; - } - - /* write sdmx input */ - switch (p->u.vsb.modulation) { - case QAM_64: - buf[0] = 0x68; - break; - case QAM_256: - buf[0] = 0x64; - break; - case VSB_8: - buf[0] = 0x60; - break; - default: - return -EINVAL; - break; - } - buf[1] = 0x00; - switch (state->demod_chip) { - case NXT2002: - nxt200x_writereg_multibyte(state, 0x5C, buf, 2); - break; - case NXT2004: - nxt200x_writebytes(state, 0x5C, buf, 2); - break; - default: - return -EINVAL; - break; - } - - /* write adc power lpf fc */ - buf[0] = 0x05; - nxt200x_writebytes(state, 0x43, buf, 1); - - if (state->demod_chip == NXT2004) { - /* write ??? */ - buf[0] = 0x00; - buf[1] = 0x00; - nxt200x_writebytes(state, 0x46, buf, 2); - } - - /* write accumulator2 input */ - buf[0] = 0x80; - buf[1] = 0x00; - switch (state->demod_chip) { - case NXT2002: - nxt200x_writereg_multibyte(state, 0x4B, buf, 2); - break; - case NXT2004: - nxt200x_writebytes(state, 0x4B, buf, 2); - break; - default: - return -EINVAL; - break; - } - - /* write kg1 */ - buf[0] = 0x00; - nxt200x_writebytes(state, 0x4D, buf, 1); - - /* write sdm12 lpf fc */ - buf[0] = 0x44; - nxt200x_writebytes(state, 0x55, buf, 1); - - /* write agc control reg */ - buf[0] = 0x04; - nxt200x_writebytes(state, 0x41, buf, 1); - - if (state->demod_chip == NXT2004) { - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x24; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - - /* soft reset? */ - nxt200x_readreg_multibyte(state, 0x08, buf, 1); - buf[0] = 0x10; - nxt200x_writereg_multibyte(state, 0x08, buf, 1); - nxt200x_readreg_multibyte(state, 0x08, buf, 1); - buf[0] = 0x00; - nxt200x_writereg_multibyte(state, 0x08, buf, 1); - - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x04; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x00; - nxt200x_writereg_multibyte(state, 0x81, buf, 1); - buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; - nxt200x_writereg_multibyte(state, 0x82, buf, 3); - nxt200x_readreg_multibyte(state, 0x88, buf, 1); - buf[0] = 0x11; - nxt200x_writereg_multibyte(state, 0x88, buf, 1); - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x44; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - } - - /* write agc ucgp0 */ - switch (p->u.vsb.modulation) { - case QAM_64: - buf[0] = 0x02; - break; - case QAM_256: - buf[0] = 0x03; - break; - case VSB_8: - buf[0] = 0x00; - break; - default: - return -EINVAL; - break; - } - nxt200x_writebytes(state, 0x30, buf, 1); - - /* write agc control reg */ - buf[0] = 0x00; - nxt200x_writebytes(state, 0x41, buf, 1); - - /* write accumulator2 input */ - buf[0] = 0x80; - buf[1] = 0x00; - switch (state->demod_chip) { - case NXT2002: - nxt200x_writereg_multibyte(state, 0x49, buf, 2); - nxt200x_writereg_multibyte(state, 0x4B, buf, 2); - break; - case NXT2004: - nxt200x_writebytes(state, 0x49, buf, 2); - nxt200x_writebytes(state, 0x4B, buf, 2); - break; - default: - return -EINVAL; - break; - } - - /* write agc control reg */ - buf[0] = 0x04; - nxt200x_writebytes(state, 0x41, buf, 1); - - nxt200x_microcontroller_start(state); - - if (state->demod_chip == NXT2004) { - nxt2004_microcontroller_init(state); - - /* ???? */ - buf[0] = 0xF0; - buf[1] = 0x00; - nxt200x_writebytes(state, 0x5C, buf, 2); - } - - /* adjacent channel detection should be done here, but I don't - have any stations with this need so I cannot test it */ - - return 0; -} - -static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct nxt200x_state* state = fe->demodulator_priv; - u8 lock; - nxt200x_readbytes(state, 0x31, &lock, 1); - - *status = 0; - if (lock & 0x20) { - *status |= FE_HAS_SIGNAL; - *status |= FE_HAS_CARRIER; - *status |= FE_HAS_VITERBI; - *status |= FE_HAS_SYNC; - *status |= FE_HAS_LOCK; - } - return 0; -} - -static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct nxt200x_state* state = fe->demodulator_priv; - u8 b[3]; - - nxt200x_readreg_multibyte(state, 0xE6, b, 3); - - *ber = ((b[0] << 8) + b[1]) * 8; - - return 0; -} - -static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct nxt200x_state* state = fe->demodulator_priv; - u8 b[2]; - u16 temp = 0; - - /* setup to read cluster variance */ - b[0] = 0x00; - nxt200x_writebytes(state, 0xA1, b, 1); - - /* get multreg val */ - nxt200x_readreg_multibyte(state, 0xA6, b, 2); - - temp = (b[0] << 8) | b[1]; - *strength = ((0x7FFF - temp) & 0x0FFF) * 16; - - return 0; -} - -static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr) -{ - - struct nxt200x_state* state = fe->demodulator_priv; - u8 b[2]; - u16 temp = 0, temp2; - u32 snrdb = 0; - - /* setup to read cluster variance */ - b[0] = 0x00; - nxt200x_writebytes(state, 0xA1, b, 1); - - /* get multreg val from 0xA6 */ - nxt200x_readreg_multibyte(state, 0xA6, b, 2); - - temp = (b[0] << 8) | b[1]; - temp2 = 0x7FFF - temp; - - /* snr will be in db */ - if (temp2 > 0x7F00) - snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) ); - else if (temp2 > 0x7EC0) - snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) ); - else if (temp2 > 0x7C00) - snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) ); - else - snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) ); - - /* the value reported back from the frontend will be FFFF=32db 0000=0db */ - *snr = snrdb * (0xFFFF/32000); - - return 0; -} - -static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct nxt200x_state* state = fe->demodulator_priv; - u8 b[3]; - - nxt200x_readreg_multibyte(state, 0xE6, b, 3); - *ucblocks = b[2]; - - return 0; -} - -static int nxt200x_sleep(struct dvb_frontend* fe) -{ - return 0; -} - -static int nxt2002_init(struct dvb_frontend* fe) -{ - struct nxt200x_state* state = fe->demodulator_priv; - const struct firmware *fw; - int ret; - u8 buf[2]; - - /* request the firmware, this will block until someone uploads it */ - printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, - state->i2c->dev.parent); - printk("nxt2002: Waiting for firmware upload(2)...\n"); - if (ret) { - printk("nxt2002: No firmware uploaded (timeout or file not found?)\n"); - return ret; - } - - ret = nxt2002_load_firmware(fe, fw); - release_firmware(fw); - if (ret) { - printk("nxt2002: Writing firmware to device failed\n"); - return ret; - } - printk("nxt2002: Firmware upload complete\n"); - - /* Put the micro into reset */ - nxt200x_microcontroller_stop(state); - - /* ensure transfer is complete */ - buf[0]=0x00; - nxt200x_writebytes(state, 0x2B, buf, 1); - - /* Put the micro into reset for real this time */ - nxt200x_microcontroller_stop(state); - - /* soft reset everything (agc,frontend,eq,fec)*/ - buf[0] = 0x0F; - nxt200x_writebytes(state, 0x08, buf, 1); - buf[0] = 0x00; - nxt200x_writebytes(state, 0x08, buf, 1); - - /* write agc sdm configure */ - buf[0] = 0xF1; - nxt200x_writebytes(state, 0x57, buf, 1); - - /* write mod output format */ - buf[0] = 0x20; - nxt200x_writebytes(state, 0x09, buf, 1); - - /* write fec mpeg mode */ - buf[0] = 0x7E; - buf[1] = 0x00; - nxt200x_writebytes(state, 0xE9, buf, 2); - - /* write mux selection */ - buf[0] = 0x00; - nxt200x_writebytes(state, 0xCC, buf, 1); - - return 0; -} - -static int nxt2004_init(struct dvb_frontend* fe) -{ - struct nxt200x_state* state = fe->demodulator_priv; - const struct firmware *fw; - int ret; - u8 buf[3]; - - /* ??? */ - buf[0]=0x00; - nxt200x_writebytes(state, 0x1E, buf, 1); - - /* request the firmware, this will block until someone uploads it */ - printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, - state->i2c->dev.parent); - printk("nxt2004: Waiting for firmware upload(2)...\n"); - if (ret) { - printk("nxt2004: No firmware uploaded (timeout or file not found?)\n"); - return ret; - } - - ret = nxt2004_load_firmware(fe, fw); - release_firmware(fw); - if (ret) { - printk("nxt2004: Writing firmware to device failed\n"); - return ret; - } - printk("nxt2004: Firmware upload complete\n"); - - /* ensure transfer is complete */ - buf[0] = 0x01; - nxt200x_writebytes(state, 0x19, buf, 1); - - nxt2004_microcontroller_init(state); - nxt200x_microcontroller_stop(state); - nxt200x_microcontroller_stop(state); - nxt2004_microcontroller_init(state); - nxt200x_microcontroller_stop(state); - - /* soft reset everything (agc,frontend,eq,fec)*/ - buf[0] = 0xFF; - nxt200x_writereg_multibyte(state, 0x08, buf, 1); - buf[0] = 0x00; - nxt200x_writereg_multibyte(state, 0x08, buf, 1); - - /* write agc sdm configure */ - buf[0] = 0xD7; - nxt200x_writebytes(state, 0x57, buf, 1); - - /* ???*/ - buf[0] = 0x07; - buf[1] = 0xfe; - nxt200x_writebytes(state, 0x35, buf, 2); - buf[0] = 0x12; - nxt200x_writebytes(state, 0x34, buf, 1); - buf[0] = 0x80; - nxt200x_writebytes(state, 0x21, buf, 1); - - /* ???*/ - buf[0] = 0x21; - nxt200x_writebytes(state, 0x0A, buf, 1); - - /* ???*/ - buf[0] = 0x01; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - - /* write fec mpeg mode */ - buf[0] = 0x7E; - buf[1] = 0x00; - nxt200x_writebytes(state, 0xE9, buf, 2); - - /* write mux selection */ - buf[0] = 0x00; - nxt200x_writebytes(state, 0xCC, buf, 1); - - /* ???*/ - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x00; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - - /* soft reset? */ - nxt200x_readreg_multibyte(state, 0x08, buf, 1); - buf[0] = 0x10; - nxt200x_writereg_multibyte(state, 0x08, buf, 1); - nxt200x_readreg_multibyte(state, 0x08, buf, 1); - buf[0] = 0x00; - nxt200x_writereg_multibyte(state, 0x08, buf, 1); - - /* ???*/ - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x01; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x70; - nxt200x_writereg_multibyte(state, 0x81, buf, 1); - buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66; - nxt200x_writereg_multibyte(state, 0x82, buf, 3); - - nxt200x_readreg_multibyte(state, 0x88, buf, 1); - buf[0] = 0x11; - nxt200x_writereg_multibyte(state, 0x88, buf, 1); - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x40; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - - nxt200x_readbytes(state, 0x10, buf, 1); - buf[0] = 0x10; - nxt200x_writebytes(state, 0x10, buf, 1); - nxt200x_readbytes(state, 0x0A, buf, 1); - buf[0] = 0x21; - nxt200x_writebytes(state, 0x0A, buf, 1); - - nxt2004_microcontroller_init(state); - - buf[0] = 0x21; - nxt200x_writebytes(state, 0x0A, buf, 1); - buf[0] = 0x7E; - nxt200x_writebytes(state, 0xE9, buf, 1); - buf[0] = 0x00; - nxt200x_writebytes(state, 0xEA, buf, 1); - - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x00; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x00; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - - /* soft reset? */ - nxt200x_readreg_multibyte(state, 0x08, buf, 1); - buf[0] = 0x10; - nxt200x_writereg_multibyte(state, 0x08, buf, 1); - nxt200x_readreg_multibyte(state, 0x08, buf, 1); - buf[0] = 0x00; - nxt200x_writereg_multibyte(state, 0x08, buf, 1); - - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x04; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x00; - nxt200x_writereg_multibyte(state, 0x81, buf, 1); - buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; - nxt200x_writereg_multibyte(state, 0x82, buf, 3); - - nxt200x_readreg_multibyte(state, 0x88, buf, 1); - buf[0] = 0x11; - nxt200x_writereg_multibyte(state, 0x88, buf, 1); - - nxt200x_readreg_multibyte(state, 0x80, buf, 1); - buf[0] = 0x44; - nxt200x_writereg_multibyte(state, 0x80, buf, 1); - - /* initialize tuner */ - nxt200x_readbytes(state, 0x10, buf, 1); - buf[0] = 0x12; - nxt200x_writebytes(state, 0x10, buf, 1); - buf[0] = 0x04; - nxt200x_writebytes(state, 0x13, buf, 1); - buf[0] = 0x00; - nxt200x_writebytes(state, 0x16, buf, 1); - buf[0] = 0x04; - nxt200x_writebytes(state, 0x14, buf, 1); - buf[0] = 0x00; - nxt200x_writebytes(state, 0x14, buf, 1); - nxt200x_writebytes(state, 0x17, buf, 1); - nxt200x_writebytes(state, 0x14, buf, 1); - nxt200x_writebytes(state, 0x17, buf, 1); - - return 0; -} - -static int nxt200x_init(struct dvb_frontend* fe) -{ - struct nxt200x_state* state = fe->demodulator_priv; - int ret = 0; - - if (!state->initialised) { - switch (state->demod_chip) { - case NXT2002: - ret = nxt2002_init(fe); - break; - case NXT2004: - ret = nxt2004_init(fe); - break; - default: - return -EINVAL; - break; - } - state->initialised = 1; - } - return ret; -} - -static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) -{ - fesettings->min_delay_ms = 500; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static void nxt200x_release(struct dvb_frontend* fe) -{ - struct nxt200x_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops nxt200x_ops; - -struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, - struct i2c_adapter* i2c) -{ - struct nxt200x_state* state = NULL; - u8 buf [] = {0,0,0,0,0}; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct nxt200x_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->initialised = 0; - - /* read card id */ - nxt200x_readbytes(state, 0x00, buf, 5); - dprintk("NXT info: %02X %02X %02X %02X %02X\n", - buf[0], buf[1], buf[2], buf[3], buf[4]); - - /* set demod chip */ - switch (buf[0]) { - case 0x04: - state->demod_chip = NXT2002; - printk("nxt200x: NXT2002 Detected\n"); - break; - case 0x05: - state->demod_chip = NXT2004; - printk("nxt200x: NXT2004 Detected\n"); - break; - default: - goto error; - } - - /* make sure demod chip is supported */ - switch (state->demod_chip) { - case NXT2002: - if (buf[0] != 0x04) goto error; /* device id */ - if (buf[1] != 0x02) goto error; /* fab id */ - if (buf[2] != 0x11) goto error; /* month */ - if (buf[3] != 0x20) goto error; /* year msb */ - if (buf[4] != 0x00) goto error; /* year lsb */ - break; - case NXT2004: - if (buf[0] != 0x05) goto error; /* device id */ - break; - default: - goto error; - } - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - printk("Unknown/Unsupported NXT chip: %02X %02X %02X %02X %02X\n", - buf[0], buf[1], buf[2], buf[3], buf[4]); - return NULL; -} - -static struct dvb_frontend_ops nxt200x_ops = { - - .info = { - .name = "Nextwave NXT200X VSB/QAM frontend", - .type = FE_ATSC, - .frequency_min = 54000000, - .frequency_max = 860000000, - .frequency_stepsize = 166666, /* stepsize is just a guess */ - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256 - }, - - .release = nxt200x_release, - - .init = nxt200x_init, - .sleep = nxt200x_sleep, - - .set_frontend = nxt200x_setup_frontend_parameters, - .get_tune_settings = nxt200x_get_tune_settings, - - .read_status = nxt200x_read_status, - .read_ber = nxt200x_read_ber, - .read_signal_strength = nxt200x_read_signal_strength, - .read_snr = nxt200x_read_snr, - .read_ucblocks = nxt200x_read_ucblocks, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); -MODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(nxt200x_attach); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt200x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt200x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt200x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt200x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* - * Support for NXT2002 and NXT2004 - VSB/QAM - * - * Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com) - * based on nxt2002 by Taylor Jacob - * and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * -*/ - -#ifndef NXT200X_H -#define NXT200X_H - -#include -#include - -typedef enum nxt_chip_t { - NXTUNDEFINED, - NXT2002, - NXT2004 -}nxt_chip_type; - -struct nxt200x_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* need to set device param for start_dma */ - int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); -}; - -#if defined(CONFIG_DVB_NXT200X) || (defined(CONFIG_DVB_NXT200X_MODULE) && defined(MODULE)) -extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_NXT200X - -#endif /* NXT200X_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,610 +0,0 @@ -/* - NxtWave Communications - NXT6000 demodulator driver - - Copyright (C) 2002-2003 Florian Schirmer - Copyright (C) 2003 Paul Andreassen - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "nxt6000_priv.h" -#include "nxt6000.h" - - - -struct nxt6000_state { - struct i2c_adapter* i2c; - /* configuration settings */ - const struct nxt6000_config* config; - struct dvb_frontend frontend; -}; - -static int debug; -#define dprintk if (debug) printk - -static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 }; - int ret; - - if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) - dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret); - - return (ret != 1) ? -EFAULT : 0; -} - -static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msgs[] = { - {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, - {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} - }; - - ret = i2c_transfer(state->i2c, msgs, 2); - - if (ret != 2) - dprintk("nxt6000: nxt6000_read error (reg: 0x%02X, ret: %d)\n", reg, ret); - - return b1[0]; -} - -static void nxt6000_reset(struct nxt6000_state* state) -{ - u8 val; - - val = nxt6000_readreg(state, OFDM_COR_CTL); - - nxt6000_writereg(state, OFDM_COR_CTL, val & ~COREACT); - nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT); -} - -static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth) -{ - u16 nominal_rate; - int result; - - switch (bandwidth) { - - case BANDWIDTH_6_MHZ: - nominal_rate = 0x55B7; - break; - - case BANDWIDTH_7_MHZ: - nominal_rate = 0x6400; - break; - - case BANDWIDTH_8_MHZ: - nominal_rate = 0x7249; - break; - - default: - return -EINVAL; - } - - if ((result = nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0) - return result; - - return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF); -} - -static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval) -{ - switch (guard_interval) { - - case GUARD_INTERVAL_1_32: - return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); - - case GUARD_INTERVAL_1_16: - return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); - - case GUARD_INTERVAL_AUTO: - case GUARD_INTERVAL_1_8: - return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); - - case GUARD_INTERVAL_1_4: - return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); - - default: - return -EINVAL; - } -} - -static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion) -{ - switch (inversion) { - - case INVERSION_OFF: - return nxt6000_writereg(state, OFDM_ITB_CTL, 0x00); - - case INVERSION_ON: - return nxt6000_writereg(state, OFDM_ITB_CTL, ITBINV); - - default: - return -EINVAL; - - } -} - -static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmit_mode_t transmission_mode) -{ - int result; - - switch (transmission_mode) { - - case TRANSMISSION_MODE_2K: - if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0) - return result; - - return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04)); - - case TRANSMISSION_MODE_8K: - case TRANSMISSION_MODE_AUTO: - if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0) - return result; - - return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04)); - - default: - return -EINVAL; - - } -} - -static void nxt6000_setup(struct dvb_frontend* fe) -{ - struct nxt6000_state* state = fe->demodulator_priv; - - nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM); - nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01); - nxt6000_writereg(state, VIT_BERTIME_2, 0x00); // BER Timer = 0x000200 * 256 = 131072 bits - nxt6000_writereg(state, VIT_BERTIME_1, 0x02); // - nxt6000_writereg(state, VIT_BERTIME_0, 0x00); // - nxt6000_writereg(state, VIT_COR_INTEN, 0x98); // Enable BER interrupts - nxt6000_writereg(state, VIT_COR_CTL, 0x82); // Enable BER measurement - nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC | 0x02 ); - nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F)); - nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02); - nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW); - nxt6000_writereg(state, OFDM_ITB_FREQ_1, 0x06); - nxt6000_writereg(state, OFDM_ITB_FREQ_2, 0x31); - nxt6000_writereg(state, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04); - nxt6000_writereg(state, CAS_FREQ, 0xBB); /* CHECKME */ - nxt6000_writereg(state, OFDM_SYR_CTL, 1 << 2); - nxt6000_writereg(state, OFDM_PPM_CTL_1, PPM256); - nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, 0x49); - nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, 0x72); - nxt6000_writereg(state, ANALOG_CONTROL_0, 1 << 5); - nxt6000_writereg(state, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2); - nxt6000_writereg(state, DIAG_CONFIG, TB_SET); - - if (state->config->clock_inversion) - nxt6000_writereg(state, SUB_DIAG_MODE_SEL, CLKINVERSION); - else - nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0); - - nxt6000_writereg(state, TS_FORMAT, 0); -} - -static void nxt6000_dump_status(struct nxt6000_state *state) -{ - u8 val; - -/* - printk("RS_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, RS_COR_STAT)); - printk("VIT_SYNC_STATUS: 0x%02X\n", nxt6000_readreg(fe, VIT_SYNC_STATUS)); - printk("OFDM_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_COR_STAT)); - printk("OFDM_SYR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_SYR_STAT)); - printk("OFDM_TPS_RCVD_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_1)); - printk("OFDM_TPS_RCVD_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_2)); - printk("OFDM_TPS_RCVD_3: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_3)); - printk("OFDM_TPS_RCVD_4: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_4)); - printk("OFDM_TPS_RESERVED_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_1)); - printk("OFDM_TPS_RESERVED_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_2)); -*/ - printk("NXT6000 status:"); - - val = nxt6000_readreg(state, RS_COR_STAT); - - printk(" DATA DESCR LOCK: %d,", val & 0x01); - printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01); - - val = nxt6000_readreg(state, VIT_SYNC_STATUS); - - printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01); - - switch ((val >> 4) & 0x07) { - - case 0x00: - printk(" VITERBI CODERATE: 1/2,"); - break; - - case 0x01: - printk(" VITERBI CODERATE: 2/3,"); - break; - - case 0x02: - printk(" VITERBI CODERATE: 3/4,"); - break; - - case 0x03: - printk(" VITERBI CODERATE: 5/6,"); - break; - - case 0x04: - printk(" VITERBI CODERATE: 7/8,"); - break; - - default: - printk(" VITERBI CODERATE: Reserved,"); - - } - - val = nxt6000_readreg(state, OFDM_COR_STAT); - - printk(" CHCTrack: %d,", (val >> 7) & 0x01); - printk(" TPSLock: %d,", (val >> 6) & 0x01); - printk(" SYRLock: %d,", (val >> 5) & 0x01); - printk(" AGCLock: %d,", (val >> 4) & 0x01); - - switch (val & 0x0F) { - - case 0x00: - printk(" CoreState: IDLE,"); - break; - - case 0x02: - printk(" CoreState: WAIT_AGC,"); - break; - - case 0x03: - printk(" CoreState: WAIT_SYR,"); - break; - - case 0x04: - printk(" CoreState: WAIT_PPM,"); - break; - - case 0x01: - printk(" CoreState: WAIT_TRL,"); - break; - - case 0x05: - printk(" CoreState: WAIT_TPS,"); - break; - - case 0x06: - printk(" CoreState: MONITOR_TPS,"); - break; - - default: - printk(" CoreState: Reserved,"); - - } - - val = nxt6000_readreg(state, OFDM_SYR_STAT); - - printk(" SYRLock: %d,", (val >> 4) & 0x01); - printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K"); - - switch ((val >> 4) & 0x03) { - - case 0x00: - printk(" SYRGuard: 1/32,"); - break; - - case 0x01: - printk(" SYRGuard: 1/16,"); - break; - - case 0x02: - printk(" SYRGuard: 1/8,"); - break; - - case 0x03: - printk(" SYRGuard: 1/4,"); - break; - } - - val = nxt6000_readreg(state, OFDM_TPS_RCVD_3); - - switch ((val >> 4) & 0x07) { - - case 0x00: - printk(" TPSLP: 1/2,"); - break; - - case 0x01: - printk(" TPSLP: 2/3,"); - break; - - case 0x02: - printk(" TPSLP: 3/4,"); - break; - - case 0x03: - printk(" TPSLP: 5/6,"); - break; - - case 0x04: - printk(" TPSLP: 7/8,"); - break; - - default: - printk(" TPSLP: Reserved,"); - - } - - switch (val & 0x07) { - - case 0x00: - printk(" TPSHP: 1/2,"); - break; - - case 0x01: - printk(" TPSHP: 2/3,"); - break; - - case 0x02: - printk(" TPSHP: 3/4,"); - break; - - case 0x03: - printk(" TPSHP: 5/6,"); - break; - - case 0x04: - printk(" TPSHP: 7/8,"); - break; - - default: - printk(" TPSHP: Reserved,"); - - } - - val = nxt6000_readreg(state, OFDM_TPS_RCVD_4); - - printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K"); - - switch ((val >> 4) & 0x03) { - - case 0x00: - printk(" TPSGuard: 1/32,"); - break; - - case 0x01: - printk(" TPSGuard: 1/16,"); - break; - - case 0x02: - printk(" TPSGuard: 1/8,"); - break; - - case 0x03: - printk(" TPSGuard: 1/4,"); - break; - - } - - /* Strange magic required to gain access to RF_AGC_STATUS */ - nxt6000_readreg(state, RF_AGC_VAL_1); - val = nxt6000_readreg(state, RF_AGC_STATUS); - val = nxt6000_readreg(state, RF_AGC_STATUS); - - printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01); - printk("\n"); -} - -static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - u8 core_status; - struct nxt6000_state* state = fe->demodulator_priv; - - *status = 0; - - core_status = nxt6000_readreg(state, OFDM_COR_STAT); - - if (core_status & AGCLOCKED) - *status |= FE_HAS_SIGNAL; - - if (nxt6000_readreg(state, OFDM_SYR_STAT) & GI14_SYR_LOCK) - *status |= FE_HAS_CARRIER; - - if (nxt6000_readreg(state, VIT_SYNC_STATUS) & VITINSYNC) - *status |= FE_HAS_VITERBI; - - if (nxt6000_readreg(state, RS_COR_STAT) & RSCORESTATUS) - *status |= FE_HAS_SYNC; - - if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))) - *status |= FE_HAS_LOCK; - - if (debug) - nxt6000_dump_status(state); - - return 0; -} - -static int nxt6000_init(struct dvb_frontend* fe) -{ - struct nxt6000_state* state = fe->demodulator_priv; - - nxt6000_reset(state); - nxt6000_setup(fe); - - return 0; -} - -static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) -{ - struct nxt6000_state* state = fe->demodulator_priv; - int result; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0) - return result; - if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0) - return result; - if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0) - return result; - if ((result = nxt6000_set_inversion(state, param->inversion)) < 0) - return result; - - msleep(500); - return 0; -} - -static void nxt6000_release(struct dvb_frontend* fe) -{ - struct nxt6000_state* state = fe->demodulator_priv; - kfree(state); -} - -static int nxt6000_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct nxt6000_state* state = fe->demodulator_priv; - - *snr = nxt6000_readreg( state, OFDM_CHC_SNR) / 8; - - return 0; -} - -static int nxt6000_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct nxt6000_state* state = fe->demodulator_priv; - - nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18 ); - - *ber = (nxt6000_readreg( state, VIT_BER_1 ) << 8 ) | - nxt6000_readreg( state, VIT_BER_0 ); - - nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18); // Clear BER Done interrupts - - return 0; -} - -static int nxt6000_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) -{ - struct nxt6000_state* state = fe->demodulator_priv; - - *signal_strength = (short) (511 - - (nxt6000_readreg(state, AGC_GAIN_1) + - ((nxt6000_readreg(state, AGC_GAIN_2) & 0x03) << 8))); - - return 0; -} - -static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 500; - return 0; -} - -static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct nxt6000_state* state = fe->demodulator_priv; - - if (enable) { - return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); - } else { - return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); - } -} - -static struct dvb_frontend_ops nxt6000_ops; - -struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, - struct i2c_adapter* i2c) -{ - struct nxt6000_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct nxt6000_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* check if the demod is there */ - if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops nxt6000_ops = { - - .info = { - .name = "NxtWave NXT6000 DVB-T", - .type = FE_OFDM, - .frequency_min = 0, - .frequency_max = 863250000, - .frequency_stepsize = 62500, - /*.frequency_tolerance = *//* FIXME: 12% of SR */ - .symbol_rate_min = 0, /* FIXME */ - .symbol_rate_max = 9360000, /* FIXME */ - .symbol_rate_tolerance = 4000, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = nxt6000_release, - - .init = nxt6000_init, - .i2c_gate_ctrl = nxt6000_i2c_gate_ctrl, - - .get_tune_settings = nxt6000_fe_get_tune_settings, - - .set_frontend = nxt6000_set_frontend, - - .read_status = nxt6000_read_status, - .read_ber = nxt6000_read_ber, - .read_signal_strength = nxt6000_read_signal_strength, - .read_snr = nxt6000_read_snr, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("NxtWave NXT6000 DVB-T demodulator driver"); -MODULE_AUTHOR("Florian Schirmer"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(nxt6000_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - NxtWave Communications - NXT6000 demodulator driver - - Copyright (C) 2002-2003 Florian Schirmer - Copyright (C) 2003 Paul Andreassen - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef NXT6000_H -#define NXT6000_H - -#include - -struct nxt6000_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* should clock inversion be used? */ - u8 clock_inversion:1; -}; - -#if defined(CONFIG_DVB_NXT6000) || (defined(CONFIG_DVB_NXT6000_MODULE) && defined(MODULE)) -extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_NXT6000 - -#endif // NXT6000_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/nxt6000_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,286 +0,0 @@ -/* - * Public Include File for DRV6000 users - * (ie. NxtWave Communications - NXT6000 demodulator driver) - * - * Copyright (C) 2001 NxtWave Communications, Inc. - * - */ - -/* Nxt6000 Register Addresses and Bit Masks */ - -/* Maximum Register Number */ -#define MAXNXT6000REG (0x9A) - -/* 0x1B A_VIT_BER_0 aka 0x3A */ -#define A_VIT_BER_0 (0x1B) - -/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */ -#define A_VIT_BER_TIMER_0 (0x1D) - -/* 0x21 RS_COR_STAT */ -#define RS_COR_STAT (0x21) -#define RSCORESTATUS (0x03) - -/* 0x22 RS_COR_INTEN */ -#define RS_COR_INTEN (0x22) - -/* 0x23 RS_COR_INSTAT */ -#define RS_COR_INSTAT (0x23) -#define INSTAT_ERROR (0x04) -#define LOCK_LOSS_BITS (0x03) - -/* 0x24 RS_COR_SYNC_PARAM */ -#define RS_COR_SYNC_PARAM (0x24) -#define SYNC_PARAM (0x03) - -/* 0x25 BER_CTRL */ -#define BER_CTRL (0x25) -#define BER_ENABLE (0x02) -#define BER_RESET (0x01) - -/* 0x26 BER_PAY */ -#define BER_PAY (0x26) - -/* 0x27 BER_PKT_L */ -#define BER_PKT_L (0x27) -#define BER_PKTOVERFLOW (0x80) - -/* 0x30 VIT_COR_CTL */ -#define VIT_COR_CTL (0x30) -#define BER_CONTROL (0x02) -#define VIT_COR_MASK (0x82) -#define VIT_COR_RESYNC (0x80) - - -/* 0x32 VIT_SYNC_STATUS */ -#define VIT_SYNC_STATUS (0x32) -#define VITINSYNC (0x80) - -/* 0x33 VIT_COR_INTEN */ -#define VIT_COR_INTEN (0x33) -#define GLOBAL_ENABLE (0x80) - -/* 0x34 VIT_COR_INTSTAT */ -#define VIT_COR_INTSTAT (0x34) -#define BER_DONE (0x08) -#define BER_OVERFLOW (0x10) - -/* 0x38 VIT_BERTIME_2 */ -#define VIT_BERTIME_2 (0x38) - -/* 0x39 VIT_BERTIME_1 */ -#define VIT_BERTIME_1 (0x39) - -/* 0x3A VIT_BERTIME_0 */ -#define VIT_BERTIME_0 (0x3a) - - /* 0x38 OFDM_BERTimer *//* Use the alias registers */ -#define A_VIT_BER_TIMER_0 (0x1D) - - /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */ -#define A_VIT_BER_0 (0x1B) - -/* 0x3B VIT_BER_1 */ -#define VIT_BER_1 (0x3b) - -/* 0x3C VIT_BER_0 */ -#define VIT_BER_0 (0x3c) - -/* 0x40 OFDM_COR_CTL */ -#define OFDM_COR_CTL (0x40) -#define COREACT (0x20) -#define HOLDSM (0x10) -#define WAIT_AGC (0x02) -#define WAIT_SYR (0x03) - -/* 0x41 OFDM_COR_STAT */ -#define OFDM_COR_STAT (0x41) -#define COR_STATUS (0x0F) -#define MONITOR_TPS (0x06) -#define TPSLOCKED (0x40) -#define AGCLOCKED (0x10) - -/* 0x42 OFDM_COR_INTEN */ -#define OFDM_COR_INTEN (0x42) -#define TPSRCVBAD (0x04) -#define TPSRCVCHANGED (0x02) -#define TPSRCVUPDATE (0x01) - -/* 0x43 OFDM_COR_INSTAT */ -#define OFDM_COR_INSTAT (0x43) - -/* 0x44 OFDM_COR_MODEGUARD */ -#define OFDM_COR_MODEGUARD (0x44) -#define FORCEMODE (0x08) -#define FORCEMODE8K (0x04) - -/* 0x45 OFDM_AGC_CTL */ -#define OFDM_AGC_CTL (0x45) -#define INITIAL_AGC_BW (0x08) -#define AGCNEG (0x02) -#define AGCLAST (0x10) - -/* 0x48 OFDM_AGC_TARGET */ -#define OFDM_AGC_TARGET (0x48) -#define OFDM_AGC_TARGET_DEFAULT (0x28) -#define OFDM_AGC_TARGET_IMPULSE (0x38) - -/* 0x49 OFDM_AGC_GAIN_1 */ -#define OFDM_AGC_GAIN_1 (0x49) - -/* 0x4B OFDM_ITB_CTL */ -#define OFDM_ITB_CTL (0x4B) -#define ITBINV (0x01) - -/* 0x49 AGC_GAIN_1 */ -#define AGC_GAIN_1 (0x49) - -/* 0x4A AGC_GAIN_2 */ -#define AGC_GAIN_2 (0x4A) - -/* 0x4C OFDM_ITB_FREQ_1 */ -#define OFDM_ITB_FREQ_1 (0x4C) - -/* 0x4D OFDM_ITB_FREQ_2 */ -#define OFDM_ITB_FREQ_2 (0x4D) - -/* 0x4E OFDM_CAS_CTL */ -#define OFDM_CAS_CTL (0x4E) -#define ACSDIS (0x40) -#define CCSEN (0x80) - -/* 0x4F CAS_FREQ */ -#define CAS_FREQ (0x4F) - -/* 0x51 OFDM_SYR_CTL */ -#define OFDM_SYR_CTL (0x51) -#define SIXTH_ENABLE (0x80) -#define SYR_TRACKING_DISABLE (0x01) - -/* 0x52 OFDM_SYR_STAT */ -#define OFDM_SYR_STAT (0x52) -#define GI14_2K_SYR_LOCK (0x13) -#define GI14_8K_SYR_LOCK (0x17) -#define GI14_SYR_LOCK (0x10) - -/* 0x55 OFDM_SYR_OFFSET_1 */ -#define OFDM_SYR_OFFSET_1 (0x55) - -/* 0x56 OFDM_SYR_OFFSET_2 */ -#define OFDM_SYR_OFFSET_2 (0x56) - -/* 0x58 OFDM_SCR_CTL */ -#define OFDM_SCR_CTL (0x58) -#define SYR_ADJ_DECAY_MASK (0x70) -#define SYR_ADJ_DECAY (0x30) - -/* 0x59 OFDM_PPM_CTL_1 */ -#define OFDM_PPM_CTL_1 (0x59) -#define PPMMAX_MASK (0x30) -#define PPM256 (0x30) - -/* 0x5B OFDM_TRL_NOMINALRATE_1 */ -#define OFDM_TRL_NOMINALRATE_1 (0x5B) - -/* 0x5C OFDM_TRL_NOMINALRATE_2 */ -#define OFDM_TRL_NOMINALRATE_2 (0x5C) - -/* 0x5D OFDM_TRL_TIME_1 */ -#define OFDM_TRL_TIME_1 (0x5D) - -/* 0x60 OFDM_CRL_FREQ_1 */ -#define OFDM_CRL_FREQ_1 (0x60) - -/* 0x63 OFDM_CHC_CTL_1 */ -#define OFDM_CHC_CTL_1 (0x63) -#define MANMEAN1 (0xF0); -#define CHCFIR (0x01) - -/* 0x64 OFDM_CHC_SNR */ -#define OFDM_CHC_SNR (0x64) - -/* 0x65 OFDM_BDI_CTL */ -#define OFDM_BDI_CTL (0x65) -#define LP_SELECT (0x02) - -/* 0x67 OFDM_TPS_RCVD_1 */ -#define OFDM_TPS_RCVD_1 (0x67) -#define TPSFRAME (0x03) - -/* 0x68 OFDM_TPS_RCVD_2 */ -#define OFDM_TPS_RCVD_2 (0x68) - -/* 0x69 OFDM_TPS_RCVD_3 */ -#define OFDM_TPS_RCVD_3 (0x69) - -/* 0x6A OFDM_TPS_RCVD_4 */ -#define OFDM_TPS_RCVD_4 (0x6A) - -/* 0x6B OFDM_TPS_RESERVED_1 */ -#define OFDM_TPS_RESERVED_1 (0x6B) - -/* 0x6C OFDM_TPS_RESERVED_2 */ -#define OFDM_TPS_RESERVED_2 (0x6C) - -/* 0x73 OFDM_MSC_REV */ -#define OFDM_MSC_REV (0x73) - -/* 0x76 OFDM_SNR_CARRIER_2 */ -#define OFDM_SNR_CARRIER_2 (0x76) -#define MEAN_MASK (0x80) -#define MEANBIT (0x80) - -/* 0x80 ANALOG_CONTROL_0 */ -#define ANALOG_CONTROL_0 (0x80) -#define POWER_DOWN_ADC (0x40) - -/* 0x81 ENABLE_TUNER_IIC */ -#define ENABLE_TUNER_IIC (0x81) -#define ENABLE_TUNER_BIT (0x01) - -/* 0x82 EN_DMD_RACQ */ -#define EN_DMD_RACQ (0x82) -#define EN_DMD_RACQ_REG_VAL (0x81) -#define EN_DMD_RACQ_REG_VAL_14 (0x01) - -/* 0x84 SNR_COMMAND */ -#define SNR_COMMAND (0x84) -#define SNRStat (0x80) - -/* 0x85 SNRCARRIERNUMBER_LSB */ -#define SNRCARRIERNUMBER_LSB (0x85) - -/* 0x87 SNRMINTHRESHOLD_LSB */ -#define SNRMINTHRESHOLD_LSB (0x87) - -/* 0x89 SNR_PER_CARRIER_LSB */ -#define SNR_PER_CARRIER_LSB (0x89) - -/* 0x8B SNRBELOWTHRESHOLD_LSB */ -#define SNRBELOWTHRESHOLD_LSB (0x8B) - -/* 0x91 RF_AGC_VAL_1 */ -#define RF_AGC_VAL_1 (0x91) - -/* 0x92 RF_AGC_STATUS */ -#define RF_AGC_STATUS (0x92) - -/* 0x98 DIAG_CONFIG */ -#define DIAG_CONFIG (0x98) -#define DIAG_MASK (0x70) -#define TB_SET (0x10) -#define TRAN_SELECT (0x07) -#define SERIAL_SELECT (0x01) - -/* 0x99 SUB_DIAG_MODE_SEL */ -#define SUB_DIAG_MODE_SEL (0x99) -#define CLKINVERSION (0x01) - -/* 0x9A TS_FORMAT */ -#define TS_FORMAT (0x9A) -#define ERROR_SENSE (0x08) -#define VALID_SENSE (0x04) -#define SYNC_SENSE (0x02) -#define GATED_CLOCK (0x01) - -#define NXT6000ASICDEVICE (0x0b) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51132.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51132.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51132.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51132.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,625 +0,0 @@ -/* - * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM - * - * - * Copyright (C) 2007 Trent Piepho - * - * Copyright (C) 2005 Kirk Lapray - * - * Based on code from Jack Kelliher (kelliher@xmission.com) - * Copyright (C) 2002 & pcHDTV, inc. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * -*/ - -/* - * This driver needs two external firmware files. Please copy - * "dvb-fe-or51132-vsb.fw" and "dvb-fe-or51132-qam.fw" to - * /usr/lib/hotplug/firmware/ or /lib/firmware/ - * (depending on configuration of firmware hotplug). - */ -#define OR51132_VSB_FIRMWARE "dvb-fe-or51132-vsb.fw" -#define OR51132_QAM_FIRMWARE "dvb-fe-or51132-qam.fw" - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_math.h" -#include "dvb_frontend.h" -#include "or51132.h" - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "or51132: " args); \ - } while (0) - - -struct or51132_state -{ - struct i2c_adapter* i2c; - - /* Configuration settings */ - const struct or51132_config* config; - - struct dvb_frontend frontend; - - /* Demodulator private data */ - fe_modulation_t current_modulation; - u32 snr; /* Result of last SNR calculation */ - - /* Tuner private data */ - u32 current_frequency; -}; - - -/* Write buffer to demod */ -static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len) -{ - int err; - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = 0, .buf = (u8*)buf, .len = len }; - - /* msleep(20); */ /* doesn't appear to be necessary */ - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n", - msg.addr, msg.len, err); - return -EREMOTEIO; - } - return 0; -} - -/* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00); - Less code and more efficient that loading a buffer on the stack with - the bytes to send and then calling or51132_writebuf() on that. */ -#define or51132_writebytes(state, data...) \ - ({ static const u8 _data[] = {data}; \ - or51132_writebuf(state, _data, sizeof(_data)); }) - -/* Read data from demod into buffer. Returns 0 on success. */ -static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len) -{ - int err; - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = I2C_M_RD, .buf = buf, .len = len }; - - /* msleep(20); */ /* doesn't appear to be necessary */ - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n", - msg.addr, msg.len, err); - return -EREMOTEIO; - } - return 0; -} - -/* Reads a 16-bit demod register. Returns <0 on error. */ -static int or51132_readreg(struct or51132_state *state, u8 reg) -{ - u8 buf[2] = { 0x04, reg }; - struct i2c_msg msg[2] = { - {.addr = state->config->demod_address, .flags = 0, - .buf = buf, .len = 2 }, - {.addr = state->config->demod_address, .flags = I2C_M_RD, - .buf = buf, .len = 2 }}; - int err; - - if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) { - printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n", - reg, err); - return -EREMOTEIO; - } - return buf[0] | (buf[1] << 8); -} - -static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) -{ - struct or51132_state* state = fe->demodulator_priv; - static const u8 run_buf[] = {0x7F,0x01}; - u8 rec_buf[8]; - u32 firmwareAsize, firmwareBsize; - int i,ret; - - dprintk("Firmware is %Zd bytes\n",fw->size); - - /* Get size of firmware A and B */ - firmwareAsize = le32_to_cpu(*((__le32*)fw->data)); - dprintk("FirmwareA is %i bytes\n",firmwareAsize); - firmwareBsize = le32_to_cpu(*((__le32*)(fw->data+4))); - dprintk("FirmwareB is %i bytes\n",firmwareBsize); - - /* Upload firmware */ - if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) { - printk(KERN_WARNING "or51132: load_firmware error 1\n"); - return ret; - } - if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize], - firmwareBsize))) { - printk(KERN_WARNING "or51132: load_firmware error 2\n"); - return ret; - } - - if ((ret = or51132_writebuf(state, run_buf, 2))) { - printk(KERN_WARNING "or51132: load_firmware error 3\n"); - return ret; - } - if ((ret = or51132_writebuf(state, run_buf, 2))) { - printk(KERN_WARNING "or51132: load_firmware error 4\n"); - return ret; - } - - /* 50ms for operation to begin */ - msleep(50); - - /* Read back ucode version to besure we loaded correctly and are really up and running */ - /* Get uCode version */ - if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) { - printk(KERN_WARNING "or51132: load_firmware error a\n"); - return ret; - } - if ((ret = or51132_writebytes(state, 0x04, 0x17))) { - printk(KERN_WARNING "or51132: load_firmware error b\n"); - return ret; - } - if ((ret = or51132_writebytes(state, 0x00, 0x00))) { - printk(KERN_WARNING "or51132: load_firmware error c\n"); - return ret; - } - for (i=0;i<4;i++) { - /* Once upon a time, this command might have had something - to do with getting the firmware version, but it's - not used anymore: - {0x04,0x00,0x30,0x00,i+1} */ - /* Read 8 bytes, two bytes at a time */ - if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) { - printk(KERN_WARNING - "or51132: load_firmware error d - %d\n",i); - return ret; - } - } - - printk(KERN_WARNING - "or51132: Version: %02X%02X%02X%02X-%02X%02X%02X%02X (%02X%01X-%01X-%02X%01X-%01X)\n", - rec_buf[1],rec_buf[0],rec_buf[3],rec_buf[2], - rec_buf[5],rec_buf[4],rec_buf[7],rec_buf[6], - rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f, - rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f); - - if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) { - printk(KERN_WARNING "or51132: load_firmware error e\n"); - return ret; - } - return 0; -}; - -static int or51132_init(struct dvb_frontend* fe) -{ - return 0; -} - -static int or51132_read_ber(struct dvb_frontend* fe, u32* ber) -{ - *ber = 0; - return 0; -} - -static int or51132_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - *ucblocks = 0; - return 0; -} - -static int or51132_sleep(struct dvb_frontend* fe) -{ - return 0; -} - -static int or51132_setmode(struct dvb_frontend* fe) -{ - struct or51132_state* state = fe->demodulator_priv; - u8 cmd_buf1[3] = {0x04, 0x01, 0x5f}; - u8 cmd_buf2[3] = {0x1c, 0x00, 0 }; - - dprintk("setmode %d\n",(int)state->current_modulation); - - switch (state->current_modulation) { - case VSB_8: - /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */ - cmd_buf1[2] = 0x50; - /* REC MODE inv IF spectrum, Normal */ - cmd_buf2[1] = 0x03; - /* Channel MODE ATSC/VSB8 */ - cmd_buf2[2] = 0x06; - break; - /* All QAM modes are: - Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high - REC MODE Normal Carrier Lock */ - case QAM_AUTO: - /* Channel MODE Auto QAM64/256 */ - cmd_buf2[2] = 0x4f; - break; - case QAM_256: - /* Channel MODE QAM256 */ - cmd_buf2[2] = 0x45; - break; - case QAM_64: - /* Channel MODE QAM64 */ - cmd_buf2[2] = 0x43; - break; - default: - printk(KERN_WARNING - "or51132: setmode: Modulation set to unsupported value (%d)\n", - state->current_modulation); - return -EINVAL; - } - - /* Set Receiver 1 register */ - if (or51132_writebuf(state, cmd_buf1, 3)) { - printk(KERN_WARNING "or51132: set_mode error 1\n"); - return -EREMOTEIO; - } - dprintk("set #1 to %02x\n", cmd_buf1[2]); - - /* Set operation mode in Receiver 6 register */ - if (or51132_writebuf(state, cmd_buf2, 3)) { - printk(KERN_WARNING "or51132: set_mode error 2\n"); - return -EREMOTEIO; - } - dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]); - - return 0; -} - -/* Some modulations use the same firmware. This classifies modulations - by the firmware they use. */ -#define MOD_FWCLASS_UNKNOWN 0 -#define MOD_FWCLASS_VSB 1 -#define MOD_FWCLASS_QAM 2 -static int modulation_fw_class(fe_modulation_t modulation) -{ - switch(modulation) { - case VSB_8: - return MOD_FWCLASS_VSB; - case QAM_AUTO: - case QAM_64: - case QAM_256: - return MOD_FWCLASS_QAM; - default: - return MOD_FWCLASS_UNKNOWN; - } -} - -static int or51132_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) -{ - int ret; - struct or51132_state* state = fe->demodulator_priv; - const struct firmware *fw; - const char *fwname; - int clock_mode; - - /* Upload new firmware only if we need a different one */ - if (modulation_fw_class(state->current_modulation) != - modulation_fw_class(param->u.vsb.modulation)) { - switch(modulation_fw_class(param->u.vsb.modulation)) { - case MOD_FWCLASS_VSB: - dprintk("set_parameters VSB MODE\n"); - fwname = OR51132_VSB_FIRMWARE; - - /* Set non-punctured clock for VSB */ - clock_mode = 0; - break; - case MOD_FWCLASS_QAM: - dprintk("set_parameters QAM MODE\n"); - fwname = OR51132_QAM_FIRMWARE; - - /* Set punctured clock for QAM */ - clock_mode = 1; - break; - default: - printk("or51132: Modulation type(%d) UNSUPPORTED\n", - param->u.vsb.modulation); - return -1; - } - printk("or51132: Waiting for firmware upload(%s)...\n", - fwname); - ret = request_firmware(&fw, fwname, state->i2c->dev.parent); - if (ret) { - printk(KERN_WARNING "or51132: No firmware up" - "loaded(timeout or file not found?)\n"); - return ret; - } - ret = or51132_load_firmware(fe, fw); - release_firmware(fw); - if (ret) { - printk(KERN_WARNING "or51132: Writing firmware to " - "device failed!\n"); - return ret; - } - printk("or51132: Firmware upload complete.\n"); - state->config->set_ts_params(fe, clock_mode); - } - /* Change only if we are actually changing the modulation */ - if (state->current_modulation != param->u.vsb.modulation) { - state->current_modulation = param->u.vsb.modulation; - or51132_setmode(fe); - } - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* Set to current mode */ - or51132_setmode(fe); - - /* Update current frequency */ - state->current_frequency = param->frequency; - return 0; -} - -static int or51132_get_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) -{ - struct or51132_state* state = fe->demodulator_priv; - int status; - int retry = 1; - -start: - /* Receiver Status */ - if ((status = or51132_readreg(state, 0x00)) < 0) { - printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n"); - return -EREMOTEIO; - } - switch(status&0xff) { - case 0x06: param->u.vsb.modulation = VSB_8; break; - case 0x43: param->u.vsb.modulation = QAM_64; break; - case 0x45: param->u.vsb.modulation = QAM_256; break; - default: - if (retry--) goto start; - printk(KERN_WARNING "or51132: unknown status 0x%02x\n", - status&0xff); - return -EREMOTEIO; - } - - /* FIXME: Read frequency from frontend, take AFC into account */ - param->frequency = state->current_frequency; - - /* FIXME: How to read inversion setting? Receiver 6 register? */ - param->inversion = INVERSION_AUTO; - - return 0; -} - -static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct or51132_state* state = fe->demodulator_priv; - int reg; - - /* Receiver Status */ - if ((reg = or51132_readreg(state, 0x00)) < 0) { - printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg); - *status = 0; - return -EREMOTEIO; - } - dprintk("%s: read_status %04x\n", __func__, reg); - - if (reg & 0x0100) /* Receiver Lock */ - *status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI| - FE_HAS_SYNC|FE_HAS_LOCK; - else - *status = 0; - return 0; -} - -/* Calculate SNR estimation (scaled by 2^24) - - 8-VSB SNR and QAM equations from Oren datasheets - - For 8-VSB: - SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) - K - - Where K = 0 if NTSC rejection filter is OFF; and - K = 3 if NTSC rejection filter is ON - - For QAM64: - SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) - - For QAM256: - SNR[dB] = 10 * log10(907832426.314266 / MSE^2 ) - - We re-write the snr equation as: - SNR * 2^24 = 10*(c - 2*intlog10(MSE)) - Where for QAM256, c = log10(907832426.314266) * 2^24 - and for 8-VSB and QAM64, c = log10(897152044.8282) * 2^24 */ - -static u32 calculate_snr(u32 mse, u32 c) -{ - if (mse == 0) /* No signal */ - return 0; - - mse = 2*intlog10(mse); - if (mse > c) { - /* Negative SNR, which is possible, but realisticly the - demod will lose lock before the signal gets this bad. The - API only allows for unsigned values, so just return 0 */ - return 0; - } - return 10*(c - mse); -} - -static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct or51132_state* state = fe->demodulator_priv; - int noise, reg; - u32 c, usK = 0; - int retry = 1; - -start: - /* SNR after Equalizer */ - noise = or51132_readreg(state, 0x02); - if (noise < 0) { - printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n"); - return -EREMOTEIO; - } - dprintk("read_snr noise (%d)\n", noise); - - /* Read status, contains modulation type for QAM_AUTO and - NTSC filter for VSB */ - reg = or51132_readreg(state, 0x00); - if (reg < 0) { - printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n"); - return -EREMOTEIO; - } - - switch (reg&0xff) { - case 0x06: - if (reg & 0x1000) usK = 3 << 24; - /* Fall through to QAM64 case */ - case 0x43: - c = 150204167; - break; - case 0x45: - c = 150290396; - break; - default: - printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff); - if (retry--) goto start; - return -EREMOTEIO; - } - dprintk("%s: modulation %02x, NTSC rej O%s\n", __func__, - reg&0xff, reg&0x1000?"n":"ff"); - - /* Calculate SNR using noise, c, and NTSC rejection correction */ - state->snr = calculate_snr(noise, c) - usK; - *snr = (state->snr) >> 16; - - dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, - state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); - - return 0; -} - -static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - /* Calculate Strength from SNR up to 35dB */ - /* Even though the SNR can go higher than 35dB, there is some comfort */ - /* factor in having a range of strong signals that can show at 100% */ - struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; - u16 snr; - int ret; - - ret = fe->ops.read_snr(fe, &snr); - if (ret != 0) - return ret; - /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ - /* scale the range 0 - 35*2^24 into 0 - 65535 */ - if (state->snr >= 8960 * 0x10000) - *strength = 0xffff; - else - *strength = state->snr / 8960; - - return 0; -} - -static int or51132_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) -{ - fe_tune_settings->min_delay_ms = 500; - fe_tune_settings->step_size = 0; - fe_tune_settings->max_drift = 0; - - return 0; -} - -static void or51132_release(struct dvb_frontend* fe) -{ - struct or51132_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops or51132_ops; - -struct dvb_frontend* or51132_attach(const struct or51132_config* config, - struct i2c_adapter* i2c) -{ - struct or51132_state* state = NULL; - - /* Allocate memory for the internal state */ - state = kzalloc(sizeof(struct or51132_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - /* Setup the state */ - state->config = config; - state->i2c = i2c; - state->current_frequency = -1; - state->current_modulation = -1; - - /* Create dvb_frontend */ - memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; -} - -static struct dvb_frontend_ops or51132_ops = { - - .info = { - .name = "Oren OR51132 VSB/QAM Frontend", - .type = FE_ATSC, - .frequency_min = 44000000, - .frequency_max = 958000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | - FE_CAN_8VSB - }, - - .release = or51132_release, - - .init = or51132_init, - .sleep = or51132_sleep, - - .set_frontend = or51132_set_parameters, - .get_frontend = or51132_get_parameters, - .get_tune_settings = or51132_get_tune_settings, - - .read_status = or51132_read_status, - .read_ber = or51132_read_ber, - .read_signal_strength = or51132_read_signal_strength, - .read_snr = or51132_read_snr, - .read_ucblocks = or51132_read_ucblocks, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver"); -MODULE_AUTHOR("Kirk Lapray"); -MODULE_AUTHOR("Trent Piepho"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(or51132_attach); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51132.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51132.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51132.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51132.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/* - * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM - * - * Copyright (C) 2005 Kirk Lapray - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * -*/ - -#ifndef OR51132_H -#define OR51132_H - -#include -#include - -struct or51132_config -{ - /* The demodulator's i2c address */ - u8 demod_address; - - /* Need to set device param for start_dma */ - int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); -}; - -#if defined(CONFIG_DVB_OR51132) || (defined(CONFIG_DVB_OR51132_MODULE) && defined(MODULE)) -extern struct dvb_frontend* or51132_attach(const struct or51132_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* or51132_attach(const struct or51132_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_OR51132 - -#endif // OR51132_H - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51211.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51211.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51211.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51211.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,582 +0,0 @@ -/* - * Support for OR51211 (pcHDTV HD-2000) - VSB - * - * Copyright (C) 2005 Kirk Lapray - * - * Based on code from Jack Kelliher (kelliher@xmission.com) - * Copyright (C) 2002 & pcHDTV, inc. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * -*/ - -/* - * This driver needs external firmware. Please use the command - * "/Documentation/dvb/get_dvb_firmware or51211" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware - * or /lib/firmware (depending on configuration of firmware hotplug). - */ -#define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw" - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_math.h" -#include "dvb_frontend.h" -#include "or51211.h" - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "or51211: " args); \ - } while (0) - -static u8 run_buf[] = {0x7f,0x01}; -static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC - -struct or51211_state { - - struct i2c_adapter* i2c; - - /* Configuration settings */ - const struct or51211_config* config; - - struct dvb_frontend frontend; - struct bt878* bt; - - /* Demodulator private data */ - u8 initialized:1; - u32 snr; /* Result of last SNR claculation */ - - /* Tuner private data */ - u32 current_frequency; -}; - -static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf, - int len) -{ - int err; - struct i2c_msg msg; - msg.addr = reg; - msg.flags = 0; - msg.len = len; - msg.buf = (u8 *)buf; - - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "or51211: i2c_writebytes error " - "(addr %02x, err == %i)\n", reg, err); - return -EREMOTEIO; - } - - return 0; -} - -static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len) -{ - int err; - struct i2c_msg msg; - msg.addr = reg; - msg.flags = I2C_M_RD; - msg.len = len; - msg.buf = buf; - - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "or51211: i2c_readbytes error " - "(addr %02x, err == %i)\n", reg, err); - return -EREMOTEIO; - } - - return 0; -} - -static int or51211_load_firmware (struct dvb_frontend* fe, - const struct firmware *fw) -{ - struct or51211_state* state = fe->demodulator_priv; - u8 tudata[585]; - int i; - - dprintk("Firmware is %zd bytes\n",fw->size); - - /* Get eprom data */ - tudata[0] = 17; - if (i2c_writebytes(state,0x50,tudata,1)) { - printk(KERN_WARNING "or51211:load_firmware error eprom addr\n"); - return -1; - } - if (i2c_readbytes(state,0x50,&tudata[145],192)) { - printk(KERN_WARNING "or51211: load_firmware error eprom\n"); - return -1; - } - - /* Create firmware buffer */ - for (i = 0; i < 145; i++) - tudata[i] = fw->data[i]; - - for (i = 0; i < 248; i++) - tudata[i+337] = fw->data[145+i]; - - state->config->reset(fe); - - if (i2c_writebytes(state,state->config->demod_address,tudata,585)) { - printk(KERN_WARNING "or51211: load_firmware error 1\n"); - return -1; - } - msleep(1); - - if (i2c_writebytes(state,state->config->demod_address, - &fw->data[393],8125)) { - printk(KERN_WARNING "or51211: load_firmware error 2\n"); - return -1; - } - msleep(1); - - if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { - printk(KERN_WARNING "or51211: load_firmware error 3\n"); - return -1; - } - - /* Wait at least 5 msec */ - msleep(10); - if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { - printk(KERN_WARNING "or51211: load_firmware error 4\n"); - return -1; - } - msleep(10); - - printk("or51211: Done.\n"); - return 0; -}; - -static int or51211_setmode(struct dvb_frontend* fe, int mode) -{ - struct or51211_state* state = fe->demodulator_priv; - u8 rec_buf[14]; - - state->config->setmode(fe, mode); - - if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { - printk(KERN_WARNING "or51211: setmode error 1\n"); - return -1; - } - - /* Wait at least 5 msec */ - msleep(10); - if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { - printk(KERN_WARNING "or51211: setmode error 2\n"); - return -1; - } - - msleep(10); - - /* Set operation mode in Receiver 1 register; - * type 1: - * data 0x50h Automatic sets receiver channel conditions - * Automatic NTSC rejection filter - * Enable MPEG serial data output - * MPEG2tr - * High tuner phase noise - * normal +/-150kHz Carrier acquisition range - */ - if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) { - printk(KERN_WARNING "or51211: setmode error 3\n"); - return -1; - } - - rec_buf[0] = 0x04; - rec_buf[1] = 0x00; - rec_buf[2] = 0x03; - rec_buf[3] = 0x00; - msleep(20); - if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) { - printk(KERN_WARNING "or51211: setmode error 5\n"); - } - msleep(3); - if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) { - printk(KERN_WARNING "or51211: setmode error 6"); - return -1; - } - dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]); - - return 0; -} - -static int or51211_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) -{ - struct or51211_state* state = fe->demodulator_priv; - - /* Change only if we are actually changing the channel */ - if (state->current_frequency != param->frequency) { - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* Set to ATSC mode */ - or51211_setmode(fe,0); - - /* Update current frequency */ - state->current_frequency = param->frequency; - } - return 0; -} - -static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct or51211_state* state = fe->demodulator_priv; - unsigned char rec_buf[2]; - unsigned char snd_buf[] = {0x04,0x00,0x03,0x00}; - *status = 0; - - /* Receiver Status */ - if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { - printk(KERN_WARNING "or51132: read_status write error\n"); - return -1; - } - msleep(3); - if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { - printk(KERN_WARNING "or51132: read_status read error\n"); - return -1; - } - dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]); - - if (rec_buf[0] & 0x01) { /* Receiver Lock */ - *status |= FE_HAS_SIGNAL; - *status |= FE_HAS_CARRIER; - *status |= FE_HAS_VITERBI; - *status |= FE_HAS_SYNC; - *status |= FE_HAS_LOCK; - } - return 0; -} - -/* Calculate SNR estimation (scaled by 2^24) - - 8-VSB SNR equation from Oren datasheets - - For 8-VSB: - SNR[dB] = 10 * log10(219037.9454 / MSE^2 ) - - We re-write the snr equation as: - SNR * 2^24 = 10*(c - 2*intlog10(MSE)) - Where for 8-VSB, c = log10(219037.9454) * 2^24 */ - -static u32 calculate_snr(u32 mse, u32 c) -{ - if (mse == 0) /* No signal */ - return 0; - - mse = 2*intlog10(mse); - if (mse > c) { - /* Negative SNR, which is possible, but realisticly the - demod will lose lock before the signal gets this bad. The - API only allows for unsigned values, so just return 0 */ - return 0; - } - return 10*(c - mse); -} - -static int or51211_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct or51211_state* state = fe->demodulator_priv; - u8 rec_buf[2]; - u8 snd_buf[3]; - - /* SNR after Equalizer */ - snd_buf[0] = 0x04; - snd_buf[1] = 0x00; - snd_buf[2] = 0x04; - - if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { - printk(KERN_WARNING "%s: error writing snr reg\n", - __func__); - return -1; - } - if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { - printk(KERN_WARNING "%s: read_status read error\n", - __func__); - return -1; - } - - state->snr = calculate_snr(rec_buf[0], 89599047); - *snr = (state->snr) >> 16; - - dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __func__, rec_buf[0], - state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); - - return 0; -} - -static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - /* Calculate Strength from SNR up to 35dB */ - /* Even though the SNR can go higher than 35dB, there is some comfort */ - /* factor in having a range of strong signals that can show at 100% */ - struct or51211_state* state = (struct or51211_state*)fe->demodulator_priv; - u16 snr; - int ret; - - ret = fe->ops.read_snr(fe, &snr); - if (ret != 0) - return ret; - /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ - /* scale the range 0 - 35*2^24 into 0 - 65535 */ - if (state->snr >= 8960 * 0x10000) - *strength = 0xffff; - else - *strength = state->snr / 8960; - - return 0; -} - -static int or51211_read_ber(struct dvb_frontend* fe, u32* ber) -{ - *ber = -ENOSYS; - return 0; -} - -static int or51211_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - *ucblocks = -ENOSYS; - return 0; -} - -static int or51211_sleep(struct dvb_frontend* fe) -{ - return 0; -} - -static int or51211_init(struct dvb_frontend* fe) -{ - struct or51211_state* state = fe->demodulator_priv; - const struct or51211_config* config = state->config; - const struct firmware* fw; - unsigned char get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00}; - unsigned char rec_buf[14]; - int ret,i; - - if (!state->initialized) { - /* Request the firmware, this will block until it uploads */ - printk(KERN_INFO "or51211: Waiting for firmware upload " - "(%s)...\n", OR51211_DEFAULT_FIRMWARE); - ret = config->request_firmware(fe, &fw, - OR51211_DEFAULT_FIRMWARE); - printk(KERN_INFO "or51211:Got Hotplug firmware\n"); - if (ret) { - printk(KERN_WARNING "or51211: No firmware uploaded " - "(timeout or file not found?)\n"); - return ret; - } - - ret = or51211_load_firmware(fe, fw); - release_firmware(fw); - if (ret) { - printk(KERN_WARNING "or51211: Writing firmware to " - "device failed!\n"); - return ret; - } - printk(KERN_INFO "or51211: Firmware upload complete.\n"); - - /* Set operation mode in Receiver 1 register; - * type 1: - * data 0x50h Automatic sets receiver channel conditions - * Automatic NTSC rejection filter - * Enable MPEG serial data output - * MPEG2tr - * High tuner phase noise - * normal +/-150kHz Carrier acquisition range - */ - if (i2c_writebytes(state,state->config->demod_address, - cmd_buf,3)) { - printk(KERN_WARNING "or51211: Load DVR Error 5\n"); - return -1; - } - - /* Read back ucode version to besure we loaded correctly */ - /* and are really up and running */ - rec_buf[0] = 0x04; - rec_buf[1] = 0x00; - rec_buf[2] = 0x03; - rec_buf[3] = 0x00; - msleep(30); - if (i2c_writebytes(state,state->config->demod_address, - rec_buf,3)) { - printk(KERN_WARNING "or51211: Load DVR Error A\n"); - return -1; - } - msleep(3); - if (i2c_readbytes(state,state->config->demod_address, - &rec_buf[10],2)) { - printk(KERN_WARNING "or51211: Load DVR Error B\n"); - return -1; - } - - rec_buf[0] = 0x04; - rec_buf[1] = 0x00; - rec_buf[2] = 0x01; - rec_buf[3] = 0x00; - msleep(20); - if (i2c_writebytes(state,state->config->demod_address, - rec_buf,3)) { - printk(KERN_WARNING "or51211: Load DVR Error C\n"); - return -1; - } - msleep(3); - if (i2c_readbytes(state,state->config->demod_address, - &rec_buf[12],2)) { - printk(KERN_WARNING "or51211: Load DVR Error D\n"); - return -1; - } - - for (i = 0; i < 8; i++) - rec_buf[i]=0xed; - - for (i = 0; i < 5; i++) { - msleep(30); - get_ver_buf[4] = i+1; - if (i2c_writebytes(state,state->config->demod_address, - get_ver_buf,5)) { - printk(KERN_WARNING "or51211:Load DVR Error 6" - " - %d\n",i); - return -1; - } - msleep(3); - - if (i2c_readbytes(state,state->config->demod_address, - &rec_buf[i*2],2)) { - printk(KERN_WARNING "or51211:Load DVR Error 7" - " - %d\n",i); - return -1; - } - /* If we didn't receive the right index, try again */ - if ((int)rec_buf[i*2+1]!=i+1){ - i--; - } - } - dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n", - rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3], - rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7], - rec_buf[8], rec_buf[9]); - - printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x" - " Status %02x\n", - rec_buf[2], rec_buf[4],rec_buf[6], - rec_buf[12],rec_buf[10]); - - rec_buf[0] = 0x04; - rec_buf[1] = 0x00; - rec_buf[2] = 0x03; - rec_buf[3] = 0x00; - msleep(20); - if (i2c_writebytes(state,state->config->demod_address, - rec_buf,3)) { - printk(KERN_WARNING "or51211: Load DVR Error 8\n"); - return -1; - } - msleep(20); - if (i2c_readbytes(state,state->config->demod_address, - &rec_buf[8],2)) { - printk(KERN_WARNING "or51211: Load DVR Error 9\n"); - return -1; - } - state->initialized = 1; - } - - return 0; -} - -static int or51211_get_tune_settings(struct dvb_frontend* fe, - struct dvb_frontend_tune_settings* fesettings) -{ - fesettings->min_delay_ms = 500; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static void or51211_release(struct dvb_frontend* fe) -{ - struct or51211_state* state = fe->demodulator_priv; - state->config->sleep(fe); - kfree(state); -} - -static struct dvb_frontend_ops or51211_ops; - -struct dvb_frontend* or51211_attach(const struct or51211_config* config, - struct i2c_adapter* i2c) -{ - struct or51211_state* state = NULL; - - /* Allocate memory for the internal state */ - state = kzalloc(sizeof(struct or51211_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - /* Setup the state */ - state->config = config; - state->i2c = i2c; - state->initialized = 0; - state->current_frequency = 0; - - /* Create dvb_frontend */ - memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; -} - -static struct dvb_frontend_ops or51211_ops = { - - .info = { - .name = "Oren OR51211 VSB Frontend", - .type = FE_ATSC, - .frequency_min = 44000000, - .frequency_max = 958000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_8VSB - }, - - .release = or51211_release, - - .init = or51211_init, - .sleep = or51211_sleep, - - .set_frontend = or51211_set_parameters, - .get_tune_settings = or51211_get_tune_settings, - - .read_status = or51211_read_status, - .read_ber = or51211_read_ber, - .read_signal_strength = or51211_read_signal_strength, - .read_snr = or51211_read_snr, - .read_ucblocks = or51211_read_ucblocks, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver"); -MODULE_AUTHOR("Kirk Lapray"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(or51211_attach); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51211.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51211.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51211.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/or51211.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/* - * Support for OR51211 (pcHDTV HD-2000) - VSB - * - * Copyright (C) 2005 Kirk Lapray - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * -*/ - -#ifndef OR51211_H -#define OR51211_H - -#include -#include - -struct or51211_config -{ - /* The demodulator's i2c address */ - u8 demod_address; - - /* Request firmware for device */ - int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); - void (*setmode)(struct dvb_frontend * fe, int mode); - void (*reset)(struct dvb_frontend * fe); - void (*sleep)(struct dvb_frontend * fe); -}; - -#if defined(CONFIG_DVB_OR51211) || (defined(CONFIG_DVB_OR51211_MODULE) && defined(MODULE)) -extern struct dvb_frontend* or51211_attach(const struct or51211_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* or51211_attach(const struct or51211_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_OR51211 - -#endif // OR51211_H - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1409.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1409.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1409.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1409.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1001 +0,0 @@ -/* - Samsung S5H1409 VSB/QAM demodulator driver - - Copyright (C) 2006 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "s5h1409.h" - -struct s5h1409_state { - - struct i2c_adapter *i2c; - - /* configuration settings */ - const struct s5h1409_config *config; - - struct dvb_frontend frontend; - - /* previous uncorrected block counter */ - fe_modulation_t current_modulation; - - u32 current_frequency; - int if_freq; - - u32 is_qam_locked; - - /* QAM tuning state goes through the following state transitions */ -#define QAM_STATE_UNTUNED 0 -#define QAM_STATE_TUNING_STARTED 1 -#define QAM_STATE_INTERLEAVE_SET 2 -#define QAM_STATE_QAM_OPTIMIZED_L1 3 -#define QAM_STATE_QAM_OPTIMIZED_L2 4 -#define QAM_STATE_QAM_OPTIMIZED_L3 5 - u8 qam_state; -}; - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable verbose debug messages"); - -#define dprintk if (debug) printk - -/* Register values to initialise the demod, this will set VSB by default */ -static struct init_tab { - u8 reg; - u16 data; -} init_tab[] = { - { 0x00, 0x0071, }, - { 0x01, 0x3213, }, - { 0x09, 0x0025, }, - { 0x1c, 0x001d, }, - { 0x1f, 0x002d, }, - { 0x20, 0x001d, }, - { 0x22, 0x0022, }, - { 0x23, 0x0020, }, - { 0x29, 0x110f, }, - { 0x2a, 0x10b4, }, - { 0x2b, 0x10ae, }, - { 0x2c, 0x0031, }, - { 0x31, 0x010d, }, - { 0x32, 0x0100, }, - { 0x44, 0x0510, }, - { 0x54, 0x0104, }, - { 0x58, 0x2222, }, - { 0x59, 0x1162, }, - { 0x5a, 0x3211, }, - { 0x5d, 0x0370, }, - { 0x5e, 0x0296, }, - { 0x61, 0x0010, }, - { 0x63, 0x4a00, }, - { 0x65, 0x0800, }, - { 0x71, 0x0003, }, - { 0x72, 0x0470, }, - { 0x81, 0x0002, }, - { 0x82, 0x0600, }, - { 0x86, 0x0002, }, - { 0x8a, 0x2c38, }, - { 0x8b, 0x2a37, }, - { 0x92, 0x302f, }, - { 0x93, 0x3332, }, - { 0x96, 0x000c, }, - { 0x99, 0x0101, }, - { 0x9c, 0x2e37, }, - { 0x9d, 0x2c37, }, - { 0x9e, 0x2c37, }, - { 0xab, 0x0100, }, - { 0xac, 0x1003, }, - { 0xad, 0x103f, }, - { 0xe2, 0x0100, }, - { 0xe3, 0x1000, }, - { 0x28, 0x1010, }, - { 0xb1, 0x000e, }, -}; - -/* VSB SNR lookup table */ -static struct vsb_snr_tab { - u16 val; - u16 data; -} vsb_snr_tab[] = { - { 924, 300, }, - { 923, 300, }, - { 918, 295, }, - { 915, 290, }, - { 911, 285, }, - { 906, 280, }, - { 901, 275, }, - { 896, 270, }, - { 891, 265, }, - { 885, 260, }, - { 879, 255, }, - { 873, 250, }, - { 864, 245, }, - { 858, 240, }, - { 850, 235, }, - { 841, 230, }, - { 832, 225, }, - { 823, 220, }, - { 812, 215, }, - { 802, 210, }, - { 788, 205, }, - { 778, 200, }, - { 767, 195, }, - { 753, 190, }, - { 740, 185, }, - { 725, 180, }, - { 707, 175, }, - { 689, 170, }, - { 671, 165, }, - { 656, 160, }, - { 637, 155, }, - { 616, 150, }, - { 542, 145, }, - { 519, 140, }, - { 507, 135, }, - { 497, 130, }, - { 492, 125, }, - { 474, 120, }, - { 300, 111, }, - { 0, 0, }, -}; - -/* QAM64 SNR lookup table */ -static struct qam64_snr_tab { - u16 val; - u16 data; -} qam64_snr_tab[] = { - { 1, 0, }, - { 12, 300, }, - { 15, 290, }, - { 18, 280, }, - { 22, 270, }, - { 23, 268, }, - { 24, 266, }, - { 25, 264, }, - { 27, 262, }, - { 28, 260, }, - { 29, 258, }, - { 30, 256, }, - { 32, 254, }, - { 33, 252, }, - { 34, 250, }, - { 35, 249, }, - { 36, 248, }, - { 37, 247, }, - { 38, 246, }, - { 39, 245, }, - { 40, 244, }, - { 41, 243, }, - { 42, 241, }, - { 43, 240, }, - { 44, 239, }, - { 45, 238, }, - { 46, 237, }, - { 47, 236, }, - { 48, 235, }, - { 49, 234, }, - { 50, 233, }, - { 51, 232, }, - { 52, 231, }, - { 53, 230, }, - { 55, 229, }, - { 56, 228, }, - { 57, 227, }, - { 58, 226, }, - { 59, 225, }, - { 60, 224, }, - { 62, 223, }, - { 63, 222, }, - { 65, 221, }, - { 66, 220, }, - { 68, 219, }, - { 69, 218, }, - { 70, 217, }, - { 72, 216, }, - { 73, 215, }, - { 75, 214, }, - { 76, 213, }, - { 78, 212, }, - { 80, 211, }, - { 81, 210, }, - { 83, 209, }, - { 84, 208, }, - { 85, 207, }, - { 87, 206, }, - { 89, 205, }, - { 91, 204, }, - { 93, 203, }, - { 95, 202, }, - { 96, 201, }, - { 104, 200, }, - { 255, 0, }, -}; - -/* QAM256 SNR lookup table */ -static struct qam256_snr_tab { - u16 val; - u16 data; -} qam256_snr_tab[] = { - { 1, 0, }, - { 12, 400, }, - { 13, 390, }, - { 15, 380, }, - { 17, 360, }, - { 19, 350, }, - { 22, 348, }, - { 23, 346, }, - { 24, 344, }, - { 25, 342, }, - { 26, 340, }, - { 27, 336, }, - { 28, 334, }, - { 29, 332, }, - { 30, 330, }, - { 31, 328, }, - { 32, 326, }, - { 33, 325, }, - { 34, 322, }, - { 35, 320, }, - { 37, 318, }, - { 39, 316, }, - { 40, 314, }, - { 41, 312, }, - { 42, 310, }, - { 43, 308, }, - { 46, 306, }, - { 47, 304, }, - { 49, 302, }, - { 51, 300, }, - { 53, 298, }, - { 54, 297, }, - { 55, 296, }, - { 56, 295, }, - { 57, 294, }, - { 59, 293, }, - { 60, 292, }, - { 61, 291, }, - { 63, 290, }, - { 64, 289, }, - { 65, 288, }, - { 66, 287, }, - { 68, 286, }, - { 69, 285, }, - { 71, 284, }, - { 72, 283, }, - { 74, 282, }, - { 75, 281, }, - { 76, 280, }, - { 77, 279, }, - { 78, 278, }, - { 81, 277, }, - { 83, 276, }, - { 84, 275, }, - { 86, 274, }, - { 87, 273, }, - { 89, 272, }, - { 90, 271, }, - { 92, 270, }, - { 93, 269, }, - { 95, 268, }, - { 96, 267, }, - { 98, 266, }, - { 100, 265, }, - { 102, 264, }, - { 104, 263, }, - { 105, 262, }, - { 106, 261, }, - { 110, 260, }, - { 255, 0, }, -}; - -/* 8 bit registers, 16 bit values */ -static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data) -{ - int ret; - u8 buf[] = { reg, data >> 8, data & 0xff }; - - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = 0, .buf = buf, .len = 3 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, " - "ret == %i)\n", __func__, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0, 0 }; - - struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, - .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, - .buf = b1, .len = 2 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - printk("%s: readreg error (ret == %i)\n", __func__, ret); - return (b1[0] << 8) | b1[1]; -} - -static int s5h1409_softreset(struct dvb_frontend *fe) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - dprintk("%s()\n", __func__); - - s5h1409_writereg(state, 0xf5, 0); - s5h1409_writereg(state, 0xf5, 1); - state->is_qam_locked = 0; - state->qam_state = QAM_STATE_UNTUNED; - return 0; -} - -#define S5H1409_VSB_IF_FREQ 5380 -#define S5H1409_QAM_IF_FREQ (state->config->qam_if) - -static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - dprintk("%s(%d KHz)\n", __func__, KHz); - - switch (KHz) { - case 4000: - s5h1409_writereg(state, 0x87, 0x014b); - s5h1409_writereg(state, 0x88, 0x0cb5); - s5h1409_writereg(state, 0x89, 0x03e2); - break; - case 5380: - case 44000: - default: - s5h1409_writereg(state, 0x87, 0x01be); - s5h1409_writereg(state, 0x88, 0x0436); - s5h1409_writereg(state, 0x89, 0x054d); - break; - } - state->if_freq = KHz; - - return 0; -} - -static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - dprintk("%s(%d)\n", __func__, inverted); - - if (inverted == 1) - return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ - else - return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ -} - -static int s5h1409_enable_modulation(struct dvb_frontend *fe, - fe_modulation_t m) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - dprintk("%s(0x%08x)\n", __func__, m); - - switch (m) { - case VSB_8: - dprintk("%s() VSB_8\n", __func__); - if (state->if_freq != S5H1409_VSB_IF_FREQ) - s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ); - s5h1409_writereg(state, 0xf4, 0); - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk("%s() QAM_AUTO (64/256)\n", __func__); - if (state->if_freq != S5H1409_QAM_IF_FREQ) - s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ); - s5h1409_writereg(state, 0xf4, 1); - s5h1409_writereg(state, 0x85, 0x110); - break; - default: - dprintk("%s() Invalid modulation\n", __func__); - return -EINVAL; - } - - state->current_modulation = m; - s5h1409_softreset(fe); - - return 0; -} - -static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - dprintk("%s(%d)\n", __func__, enable); - - if (enable) - return s5h1409_writereg(state, 0xf3, 1); - else - return s5h1409_writereg(state, 0xf3, 0); -} - -static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - dprintk("%s(%d)\n", __func__, enable); - - if (enable) - return s5h1409_writereg(state, 0xe3, - s5h1409_readreg(state, 0xe3) | 0x1100); - else - return s5h1409_writereg(state, 0xe3, - s5h1409_readreg(state, 0xe3) & 0xfeff); -} - -static int s5h1409_sleep(struct dvb_frontend *fe, int enable) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - dprintk("%s(%d)\n", __func__, enable); - - return s5h1409_writereg(state, 0xf2, enable); -} - -static int s5h1409_register_reset(struct dvb_frontend *fe) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - dprintk("%s()\n", __func__); - - return s5h1409_writereg(state, 0xfa, 0); -} - -static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe) -{ - struct s5h1409_state *state = fe->demodulator_priv; - u16 reg; - - if (state->qam_state < QAM_STATE_INTERLEAVE_SET) { - /* We should not perform amhum optimization until - the interleave mode has been configured */ - return; - } - - if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) { - /* We've already reached the maximum optimization level, so - dont bother banging on the status registers */ - return; - } - - /* QAM EQ lock check */ - reg = s5h1409_readreg(state, 0xf0); - - if ((reg >> 13) & 0x1) { - reg &= 0xff; - - s5h1409_writereg(state, 0x96, 0x000c); - if (reg < 0x68) { - if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L3) { - dprintk("%s() setting QAM state to OPT_L3\n", - __func__); - s5h1409_writereg(state, 0x93, 0x3130); - s5h1409_writereg(state, 0x9e, 0x2836); - state->qam_state = QAM_STATE_QAM_OPTIMIZED_L3; - } - } else { - if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L2) { - dprintk("%s() setting QAM state to OPT_L2\n", - __func__); - s5h1409_writereg(state, 0x93, 0x3332); - s5h1409_writereg(state, 0x9e, 0x2c37); - state->qam_state = QAM_STATE_QAM_OPTIMIZED_L2; - } - } - - } else { - if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L1) { - dprintk("%s() setting QAM state to OPT_L1\n", __func__); - s5h1409_writereg(state, 0x96, 0x0008); - s5h1409_writereg(state, 0x93, 0x3332); - s5h1409_writereg(state, 0x9e, 0x2c37); - state->qam_state = QAM_STATE_QAM_OPTIMIZED_L1; - } - } -} - -static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe) -{ - struct s5h1409_state *state = fe->demodulator_priv; - u16 reg; - - if (state->is_qam_locked) - return; - - /* QAM EQ lock check */ - reg = s5h1409_readreg(state, 0xf0); - - if ((reg >> 13) & 0x1) { - - state->is_qam_locked = 1; - reg &= 0xff; - - s5h1409_writereg(state, 0x96, 0x00c); - if ((reg < 0x38) || (reg > 0x68)) { - s5h1409_writereg(state, 0x93, 0x3332); - s5h1409_writereg(state, 0x9e, 0x2c37); - } else { - s5h1409_writereg(state, 0x93, 0x3130); - s5h1409_writereg(state, 0x9e, 0x2836); - } - - } else { - s5h1409_writereg(state, 0x96, 0x0008); - s5h1409_writereg(state, 0x93, 0x3332); - s5h1409_writereg(state, 0x9e, 0x2c37); - } -} - -static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) -{ - struct s5h1409_state *state = fe->demodulator_priv; - u16 reg, reg1, reg2; - - if (state->qam_state >= QAM_STATE_INTERLEAVE_SET) { - /* We've done the optimization already */ - return; - } - - reg = s5h1409_readreg(state, 0xf1); - - /* Master lock */ - if ((reg >> 15) & 0x1) { - if (state->qam_state == QAM_STATE_UNTUNED || - state->qam_state == QAM_STATE_TUNING_STARTED) { - dprintk("%s() setting QAM state to INTERLEAVE_SET\n", - __func__); - reg1 = s5h1409_readreg(state, 0xb2); - reg2 = s5h1409_readreg(state, 0xad); - - s5h1409_writereg(state, 0x96, 0x0020); - s5h1409_writereg(state, 0xad, - (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff))); - state->qam_state = QAM_STATE_INTERLEAVE_SET; - } - } else { - if (state->qam_state == QAM_STATE_UNTUNED) { - dprintk("%s() setting QAM state to TUNING_STARTED\n", - __func__); - s5h1409_writereg(state, 0x96, 0x08); - s5h1409_writereg(state, 0xab, - s5h1409_readreg(state, 0xab) | 0x1001); - state->qam_state = QAM_STATE_TUNING_STARTED; - } - } -} - -static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe) -{ - struct s5h1409_state *state = fe->demodulator_priv; - u16 reg, reg1, reg2; - - reg = s5h1409_readreg(state, 0xf1); - - /* Master lock */ - if ((reg >> 15) & 0x1) { - if (state->qam_state != 2) { - state->qam_state = 2; - reg1 = s5h1409_readreg(state, 0xb2); - reg2 = s5h1409_readreg(state, 0xad); - - s5h1409_writereg(state, 0x96, 0x20); - s5h1409_writereg(state, 0xad, - (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff))); - s5h1409_writereg(state, 0xab, - s5h1409_readreg(state, 0xab) & 0xeffe); - } - } else { - if (state->qam_state != 1) { - state->qam_state = 1; - s5h1409_writereg(state, 0x96, 0x08); - s5h1409_writereg(state, 0xab, - s5h1409_readreg(state, 0xab) | 0x1001); - } - } -} - -/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1409_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - dprintk("%s(frequency=%d)\n", __func__, p->frequency); - - s5h1409_softreset(fe); - - state->current_frequency = p->frequency; - - s5h1409_enable_modulation(fe, p->u.vsb.modulation); - - if (fe->ops.tuner_ops.set_params) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* Issue a reset to the demod so it knows to resync against the - newly tuned frequency */ - s5h1409_softreset(fe); - - /* Optimize the demod for QAM */ - if (state->current_modulation != VSB_8) { - /* This almost certainly applies to all boards, but for now - only do it for the HVR-1600. Once the other boards are - tested, the "legacy" versions can just go away */ - if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) { - s5h1409_set_qam_interleave_mode(fe); - s5h1409_set_qam_amhum_mode(fe); - } else { - s5h1409_set_qam_amhum_mode_legacy(fe); - s5h1409_set_qam_interleave_mode_legacy(fe); - } - } - - return 0; -} - -static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) -{ - struct s5h1409_state *state = fe->demodulator_priv; - u16 val; - - dprintk("%s(%d)\n", __func__, mode); - - val = s5h1409_readreg(state, 0xac) & 0xcfff; - switch (mode) { - case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: - val |= 0x0000; - break; - case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: - dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); - val |= 0x1000; - break; - case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: - val |= 0x2000; - break; - case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: - val |= 0x3000; - break; - default: - return -EINVAL; - } - - /* Configure MPEG Signal Timing charactistics */ - return s5h1409_writereg(state, 0xac, val); -} - -/* Reset the demod hardware and reset all of the configuration registers - to a default state. */ -static int s5h1409_init(struct dvb_frontend *fe) -{ - int i; - - struct s5h1409_state *state = fe->demodulator_priv; - dprintk("%s()\n", __func__); - - s5h1409_sleep(fe, 0); - s5h1409_register_reset(fe); - - for (i = 0; i < ARRAY_SIZE(init_tab); i++) - s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data); - - /* The datasheet says that after initialisation, VSB is default */ - state->current_modulation = VSB_8; - - /* Optimize for the HVR-1600 if appropriate. Note that some of these - may get folded into the generic case after testing with other - devices */ - if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) { - /* VSB AGC REF */ - s5h1409_writereg(state, 0x09, 0x0050); - - /* Unknown but Windows driver does it... */ - s5h1409_writereg(state, 0x21, 0x0001); - s5h1409_writereg(state, 0x50, 0x030e); - - /* QAM AGC REF */ - s5h1409_writereg(state, 0x82, 0x0800); - } - - if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) - s5h1409_writereg(state, 0xab, - s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ - else - s5h1409_writereg(state, 0xab, - s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */ - - s5h1409_set_spectralinversion(fe, state->config->inversion); - s5h1409_set_if_freq(fe, state->if_freq); - s5h1409_set_gpio(fe, state->config->gpio); - s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing); - s5h1409_softreset(fe); - - /* Note: Leaving the I2C gate closed. */ - s5h1409_i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct s5h1409_state *state = fe->demodulator_priv; - u16 reg; - u32 tuner_status = 0; - - *status = 0; - - /* Optimize the demod for QAM */ - if (state->current_modulation != VSB_8) { - /* This almost certainly applies to all boards, but for now - only do it for the HVR-1600. Once the other boards are - tested, the "legacy" versions can just go away */ - if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) { - s5h1409_set_qam_interleave_mode(fe); - s5h1409_set_qam_amhum_mode(fe); - } - } - - /* Get the demodulator status */ - reg = s5h1409_readreg(state, 0xf1); - if (reg & 0x1000) - *status |= FE_HAS_VITERBI; - if (reg & 0x8000) - *status |= FE_HAS_LOCK | FE_HAS_SYNC; - - switch (state->config->status_mode) { - case S5H1409_DEMODLOCKING: - if (*status & FE_HAS_VITERBI) - *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; - break; - case S5H1409_TUNERLOCKING: - /* Get the tuner status */ - if (fe->ops.tuner_ops.get_status) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - fe->ops.tuner_ops.get_status(fe, &tuner_status); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - if (tuner_status) - *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; - break; - } - - dprintk("%s() status 0x%08x\n", __func__, *status); - - return 0; -} - -static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) -{ - int i, ret = -EINVAL; - dprintk("%s()\n", __func__); - - for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) { - if (v < qam256_snr_tab[i].val) { - *snr = qam256_snr_tab[i].data; - ret = 0; - break; - } - } - return ret; -} - -static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) -{ - int i, ret = -EINVAL; - dprintk("%s()\n", __func__); - - for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) { - if (v < qam64_snr_tab[i].val) { - *snr = qam64_snr_tab[i].data; - ret = 0; - break; - } - } - return ret; -} - -static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) -{ - int i, ret = -EINVAL; - dprintk("%s()\n", __func__); - - for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) { - if (v > vsb_snr_tab[i].val) { - *snr = vsb_snr_tab[i].data; - ret = 0; - break; - } - } - dprintk("%s() snr=%d\n", __func__, *snr); - return ret; -} - -static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct s5h1409_state *state = fe->demodulator_priv; - u16 reg; - dprintk("%s()\n", __func__); - - switch (state->current_modulation) { - case QAM_64: - reg = s5h1409_readreg(state, 0xf0) & 0xff; - return s5h1409_qam64_lookup_snr(fe, snr, reg); - case QAM_256: - reg = s5h1409_readreg(state, 0xf0) & 0xff; - return s5h1409_qam256_lookup_snr(fe, snr, reg); - case VSB_8: - reg = s5h1409_readreg(state, 0xf1) & 0x3ff; - return s5h1409_vsb_lookup_snr(fe, snr, reg); - default: - break; - } - - return -EINVAL; -} - -static int s5h1409_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - return s5h1409_read_snr(fe, signal_strength); -} - -static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - *ucblocks = s5h1409_readreg(state, 0xb5); - - return 0; -} - -static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - return s5h1409_read_ucblocks(fe, ber); -} - -static int s5h1409_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct s5h1409_state *state = fe->demodulator_priv; - - p->frequency = state->current_frequency; - p->u.vsb.modulation = state->current_modulation; - - return 0; -} - -static int s5h1409_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void s5h1409_release(struct dvb_frontend *fe) -{ - struct s5h1409_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops s5h1409_ops; - -struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, - struct i2c_adapter *i2c) -{ - struct s5h1409_state *state = NULL; - u16 reg; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct s5h1409_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->current_modulation = 0; - state->if_freq = S5H1409_VSB_IF_FREQ; - - /* check if the demod exists */ - reg = s5h1409_readreg(state, 0x04); - if ((reg != 0x0066) && (reg != 0x007f)) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &s5h1409_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - if (s5h1409_init(&state->frontend) != 0) { - printk(KERN_ERR "%s: Failed to initialize correctly\n", - __func__); - goto error; - } - - /* Note: Leaving the I2C gate open here. */ - s5h1409_i2c_gate_ctrl(&state->frontend, 1); - - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(s5h1409_attach); - -static struct dvb_frontend_ops s5h1409_ops = { - - .info = { - .name = "Samsung S5H1409 QAM/8VSB Frontend", - .type = FE_ATSC, - .frequency_min = 54000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - - .init = s5h1409_init, - .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl, - .set_frontend = s5h1409_set_frontend, - .get_frontend = s5h1409_get_frontend, - .get_tune_settings = s5h1409_get_tune_settings, - .read_status = s5h1409_read_status, - .read_ber = s5h1409_read_ber, - .read_signal_strength = s5h1409_read_signal_strength, - .read_snr = s5h1409_read_snr, - .read_ucblocks = s5h1409_read_ucblocks, - .release = s5h1409_release, -}; - -MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); -MODULE_AUTHOR("Steven Toth"); -MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * c-basic-offset: 8 - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1409.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1409.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1409.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1409.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -/* - Samsung S5H1409 VSB/QAM demodulator driver - - Copyright (C) 2006 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __S5H1409_H__ -#define __S5H1409_H__ - -#include - -struct s5h1409_config { - /* the demodulator's i2c address */ - u8 demod_address; - - /* serial/parallel output */ -#define S5H1409_PARALLEL_OUTPUT 0 -#define S5H1409_SERIAL_OUTPUT 1 - u8 output_mode; - - /* GPIO Setting */ -#define S5H1409_GPIO_OFF 0 -#define S5H1409_GPIO_ON 1 - u8 gpio; - - /* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */ - u16 qam_if; - - /* Spectral Inversion */ -#define S5H1409_INVERSION_OFF 0 -#define S5H1409_INVERSION_ON 1 - u8 inversion; - - /* Return lock status based on tuner lock, or demod lock */ -#define S5H1409_TUNERLOCKING 0 -#define S5H1409_DEMODLOCKING 1 - u8 status_mode; - - /* MPEG signal timing */ -#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 - u16 mpeg_timing; - - /* HVR-1600 optimizations (to better work with MXL5005s) - Note: some of these are likely to be folded into the generic driver - after being regression tested with other boards */ -#define S5H1409_HVR1600_NOOPTIMIZE 0 -#define S5H1409_HVR1600_OPTIMIZE 1 - u8 hvr1600_opt; -}; - -#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \ - && defined(MODULE)) -extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *s5h1409_attach( - const struct s5h1409_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_S5H1409 */ - -#endif /* __S5H1409_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1411.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1411.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1411.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1411.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,923 +0,0 @@ -/* - Samsung S5H1411 VSB/QAM demodulator driver - - Copyright (C) 2008 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "s5h1411.h" - -struct s5h1411_state { - - struct i2c_adapter *i2c; - - /* configuration settings */ - const struct s5h1411_config *config; - - struct dvb_frontend frontend; - - fe_modulation_t current_modulation; - unsigned int first_tune:1; - - u32 current_frequency; - int if_freq; - - u8 inversion; -}; - -static int debug; - -#define dprintk(arg...) do { \ - if (debug) \ - printk(arg); \ - } while (0) - -/* Register values to initialise the demod, defaults to VSB */ -static struct init_tab { - u8 addr; - u8 reg; - u16 data; -} init_tab[] = { - { S5H1411_I2C_TOP_ADDR, 0x00, 0x0071, }, - { S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, }, - { S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, }, - { S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, }, - { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342c, }, - { S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, }, - { S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, }, - { S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, }, - { S5H1411_I2C_TOP_ADDR, 0x27, 0x0f04, }, - { S5H1411_I2C_TOP_ADDR, 0x28, 0x070f, }, - { S5H1411_I2C_TOP_ADDR, 0x29, 0x2820, }, - { S5H1411_I2C_TOP_ADDR, 0x2a, 0x102e, }, - { S5H1411_I2C_TOP_ADDR, 0x2b, 0x0220, }, - { S5H1411_I2C_TOP_ADDR, 0x2e, 0x0d0e, }, - { S5H1411_I2C_TOP_ADDR, 0x2f, 0x1013, }, - { S5H1411_I2C_TOP_ADDR, 0x31, 0x171b, }, - { S5H1411_I2C_TOP_ADDR, 0x32, 0x0e0f, }, - { S5H1411_I2C_TOP_ADDR, 0x33, 0x0f10, }, - { S5H1411_I2C_TOP_ADDR, 0x34, 0x170e, }, - { S5H1411_I2C_TOP_ADDR, 0x35, 0x4b10, }, - { S5H1411_I2C_TOP_ADDR, 0x36, 0x0f17, }, - { S5H1411_I2C_TOP_ADDR, 0x3c, 0x1577, }, - { S5H1411_I2C_TOP_ADDR, 0x3d, 0x081a, }, - { S5H1411_I2C_TOP_ADDR, 0x3e, 0x77ee, }, - { S5H1411_I2C_TOP_ADDR, 0x40, 0x1e09, }, - { S5H1411_I2C_TOP_ADDR, 0x41, 0x0f0c, }, - { S5H1411_I2C_TOP_ADDR, 0x42, 0x1f10, }, - { S5H1411_I2C_TOP_ADDR, 0x4d, 0x0509, }, - { S5H1411_I2C_TOP_ADDR, 0x4e, 0x0a00, }, - { S5H1411_I2C_TOP_ADDR, 0x50, 0x0000, }, - { S5H1411_I2C_TOP_ADDR, 0x5b, 0x0000, }, - { S5H1411_I2C_TOP_ADDR, 0x5c, 0x0008, }, - { S5H1411_I2C_TOP_ADDR, 0x57, 0x1101, }, - { S5H1411_I2C_TOP_ADDR, 0x65, 0x007c, }, - { S5H1411_I2C_TOP_ADDR, 0x68, 0x0512, }, - { S5H1411_I2C_TOP_ADDR, 0x69, 0x0258, }, - { S5H1411_I2C_TOP_ADDR, 0x70, 0x0004, }, - { S5H1411_I2C_TOP_ADDR, 0x71, 0x0007, }, - { S5H1411_I2C_TOP_ADDR, 0x76, 0x00a9, }, - { S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, }, - { S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, }, - { S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, }, - { S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, }, - { S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, }, - { S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, }, - { S5H1411_I2C_TOP_ADDR, 0xb8, 0x003f, }, - { S5H1411_I2C_TOP_ADDR, 0xb9, 0x2700, }, - { S5H1411_I2C_TOP_ADDR, 0xba, 0xfac8, }, - { S5H1411_I2C_TOP_ADDR, 0xbe, 0x1003, }, - { S5H1411_I2C_TOP_ADDR, 0xbf, 0x103f, }, - { S5H1411_I2C_TOP_ADDR, 0xce, 0x2000, }, - { S5H1411_I2C_TOP_ADDR, 0xcf, 0x0800, }, - { S5H1411_I2C_TOP_ADDR, 0xd0, 0x0800, }, - { S5H1411_I2C_TOP_ADDR, 0xd1, 0x0400, }, - { S5H1411_I2C_TOP_ADDR, 0xd2, 0x0800, }, - { S5H1411_I2C_TOP_ADDR, 0xd3, 0x2000, }, - { S5H1411_I2C_TOP_ADDR, 0xd4, 0x3000, }, - { S5H1411_I2C_TOP_ADDR, 0xdb, 0x4a9b, }, - { S5H1411_I2C_TOP_ADDR, 0xdc, 0x1000, }, - { S5H1411_I2C_TOP_ADDR, 0xde, 0x0001, }, - { S5H1411_I2C_TOP_ADDR, 0xdf, 0x0000, }, - { S5H1411_I2C_TOP_ADDR, 0xe3, 0x0301, }, - { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0000, }, - { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0001, }, - { S5H1411_I2C_QAM_ADDR, 0x08, 0x0600, }, - { S5H1411_I2C_QAM_ADDR, 0x18, 0x4201, }, - { S5H1411_I2C_QAM_ADDR, 0x1e, 0x6476, }, - { S5H1411_I2C_QAM_ADDR, 0x21, 0x0830, }, - { S5H1411_I2C_QAM_ADDR, 0x0c, 0x5679, }, - { S5H1411_I2C_QAM_ADDR, 0x0d, 0x579b, }, - { S5H1411_I2C_QAM_ADDR, 0x24, 0x0102, }, - { S5H1411_I2C_QAM_ADDR, 0x31, 0x7488, }, - { S5H1411_I2C_QAM_ADDR, 0x32, 0x0a08, }, - { S5H1411_I2C_QAM_ADDR, 0x3d, 0x8689, }, - { S5H1411_I2C_QAM_ADDR, 0x49, 0x0048, }, - { S5H1411_I2C_QAM_ADDR, 0x57, 0x2012, }, - { S5H1411_I2C_QAM_ADDR, 0x5d, 0x7676, }, - { S5H1411_I2C_QAM_ADDR, 0x04, 0x0400, }, - { S5H1411_I2C_QAM_ADDR, 0x58, 0x00c0, }, - { S5H1411_I2C_QAM_ADDR, 0x5b, 0x0100, }, -}; - -/* VSB SNR lookup table */ -static struct vsb_snr_tab { - u16 val; - u16 data; -} vsb_snr_tab[] = { - { 0x39f, 300, }, - { 0x39b, 295, }, - { 0x397, 290, }, - { 0x394, 285, }, - { 0x38f, 280, }, - { 0x38b, 275, }, - { 0x387, 270, }, - { 0x382, 265, }, - { 0x37d, 260, }, - { 0x377, 255, }, - { 0x370, 250, }, - { 0x36a, 245, }, - { 0x364, 240, }, - { 0x35b, 235, }, - { 0x353, 230, }, - { 0x349, 225, }, - { 0x340, 320, }, - { 0x337, 215, }, - { 0x327, 210, }, - { 0x31b, 205, }, - { 0x310, 200, }, - { 0x302, 195, }, - { 0x2f3, 190, }, - { 0x2e4, 185, }, - { 0x2d7, 180, }, - { 0x2cd, 175, }, - { 0x2bb, 170, }, - { 0x2a9, 165, }, - { 0x29e, 160, }, - { 0x284, 155, }, - { 0x27a, 150, }, - { 0x260, 145, }, - { 0x23a, 140, }, - { 0x224, 135, }, - { 0x213, 130, }, - { 0x204, 125, }, - { 0x1fe, 120, }, - { 0, 0, }, -}; - -/* QAM64 SNR lookup table */ -static struct qam64_snr_tab { - u16 val; - u16 data; -} qam64_snr_tab[] = { - { 0x0001, 0, }, - { 0x0af0, 300, }, - { 0x0d80, 290, }, - { 0x10a0, 280, }, - { 0x14b5, 270, }, - { 0x1590, 268, }, - { 0x1680, 266, }, - { 0x17b0, 264, }, - { 0x18c0, 262, }, - { 0x19b0, 260, }, - { 0x1ad0, 258, }, - { 0x1d00, 256, }, - { 0x1da0, 254, }, - { 0x1ef0, 252, }, - { 0x2050, 250, }, - { 0x20f0, 249, }, - { 0x21d0, 248, }, - { 0x22b0, 247, }, - { 0x23a0, 246, }, - { 0x2470, 245, }, - { 0x24f0, 244, }, - { 0x25a0, 243, }, - { 0x26c0, 242, }, - { 0x27b0, 241, }, - { 0x28d0, 240, }, - { 0x29b0, 239, }, - { 0x2ad0, 238, }, - { 0x2ba0, 237, }, - { 0x2c80, 236, }, - { 0x2d20, 235, }, - { 0x2e00, 234, }, - { 0x2f10, 233, }, - { 0x3050, 232, }, - { 0x3190, 231, }, - { 0x3300, 230, }, - { 0x3340, 229, }, - { 0x3200, 228, }, - { 0x3550, 227, }, - { 0x3610, 226, }, - { 0x3600, 225, }, - { 0x3700, 224, }, - { 0x3800, 223, }, - { 0x3920, 222, }, - { 0x3a20, 221, }, - { 0x3b30, 220, }, - { 0x3d00, 219, }, - { 0x3e00, 218, }, - { 0x4000, 217, }, - { 0x4100, 216, }, - { 0x4300, 215, }, - { 0x4400, 214, }, - { 0x4600, 213, }, - { 0x4700, 212, }, - { 0x4800, 211, }, - { 0x4a00, 210, }, - { 0x4b00, 209, }, - { 0x4d00, 208, }, - { 0x4f00, 207, }, - { 0x5050, 206, }, - { 0x5200, 205, }, - { 0x53c0, 204, }, - { 0x5450, 203, }, - { 0x5650, 202, }, - { 0x5820, 201, }, - { 0x6000, 200, }, - { 0xffff, 0, }, -}; - -/* QAM256 SNR lookup table */ -static struct qam256_snr_tab { - u16 val; - u16 data; -} qam256_snr_tab[] = { - { 0x0001, 0, }, - { 0x0970, 400, }, - { 0x0a90, 390, }, - { 0x0b90, 380, }, - { 0x0d90, 370, }, - { 0x0ff0, 360, }, - { 0x1240, 350, }, - { 0x1345, 348, }, - { 0x13c0, 346, }, - { 0x14c0, 344, }, - { 0x1500, 342, }, - { 0x1610, 340, }, - { 0x1700, 338, }, - { 0x1800, 336, }, - { 0x18b0, 334, }, - { 0x1900, 332, }, - { 0x1ab0, 330, }, - { 0x1bc0, 328, }, - { 0x1cb0, 326, }, - { 0x1db0, 324, }, - { 0x1eb0, 322, }, - { 0x2030, 320, }, - { 0x2200, 318, }, - { 0x2280, 316, }, - { 0x2410, 314, }, - { 0x25b0, 312, }, - { 0x27a0, 310, }, - { 0x2840, 308, }, - { 0x29d0, 306, }, - { 0x2b10, 304, }, - { 0x2d30, 302, }, - { 0x2f20, 300, }, - { 0x30c0, 298, }, - { 0x3260, 297, }, - { 0x32c0, 296, }, - { 0x3300, 295, }, - { 0x33b0, 294, }, - { 0x34b0, 293, }, - { 0x35a0, 292, }, - { 0x3650, 291, }, - { 0x3800, 290, }, - { 0x3900, 289, }, - { 0x3a50, 288, }, - { 0x3b30, 287, }, - { 0x3cb0, 286, }, - { 0x3e20, 285, }, - { 0x3fa0, 284, }, - { 0x40a0, 283, }, - { 0x41c0, 282, }, - { 0x42f0, 281, }, - { 0x44a0, 280, }, - { 0x4600, 279, }, - { 0x47b0, 278, }, - { 0x4900, 277, }, - { 0x4a00, 276, }, - { 0x4ba0, 275, }, - { 0x4d00, 274, }, - { 0x4f00, 273, }, - { 0x5000, 272, }, - { 0x51f0, 272, }, - { 0x53a0, 270, }, - { 0x5520, 269, }, - { 0x5700, 268, }, - { 0x5800, 267, }, - { 0x5a00, 266, }, - { 0x5c00, 265, }, - { 0x5d00, 264, }, - { 0x5f00, 263, }, - { 0x6000, 262, }, - { 0x6200, 261, }, - { 0x6400, 260, }, - { 0xffff, 0, }, -}; - -/* 8 bit registers, 16 bit values */ -static int s5h1411_writereg(struct s5h1411_state *state, - u8 addr, u8 reg, u16 data) -{ - int ret; - u8 buf[] = { reg, data >> 8, data & 0xff }; - - struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, " - "ret == %i)\n", __func__, addr, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0, 0 }; - - struct i2c_msg msg[] = { - { .addr = addr, .flags = 0, .buf = b0, .len = 1 }, - { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - printk(KERN_ERR "%s: readreg error (ret == %i)\n", - __func__, ret); - return (b1[0] << 8) | b1[1]; -} - -static int s5h1411_softreset(struct dvb_frontend *fe) -{ - struct s5h1411_state *state = fe->demodulator_priv; - - dprintk("%s()\n", __func__); - - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 0); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 1); - return 0; -} - -static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz) -{ - struct s5h1411_state *state = fe->demodulator_priv; - - dprintk("%s(%d KHz)\n", __func__, KHz); - - switch (KHz) { - case 3250: - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d5); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342); - s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9); - break; - case 3500: - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1225); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x1e96); - s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1225); - break; - case 4000: - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x14bc); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0xb53e); - s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x14bd); - break; - default: - dprintk("%s(%d KHz) Invalid, defaulting to 5380\n", - __func__, KHz); - /* no break, need to continue */ - case 5380: - case 44000: - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x3655); - s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1be4); - break; - } - - state->if_freq = KHz; - - return 0; -} - -static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode) -{ - struct s5h1411_state *state = fe->demodulator_priv; - u16 val; - - dprintk("%s(%d)\n", __func__, mode); - - val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff; - switch (mode) { - case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: - val |= 0x0000; - break; - case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: - dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); - val |= 0x1000; - break; - case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: - val |= 0x2000; - break; - case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: - val |= 0x3000; - break; - default: - return -EINVAL; - } - - /* Configure MPEG Signal Timing charactistics */ - return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbe, val); -} - -static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion) -{ - struct s5h1411_state *state = fe->demodulator_priv; - u16 val; - - dprintk("%s(%d)\n", __func__, inversion); - val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x24) & ~0x1000; - - if (inversion == 1) - val |= 0x1000; /* Inverted */ - - state->inversion = inversion; - return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val); -} - -static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial) -{ - struct s5h1411_state *state = fe->demodulator_priv; - u16 val; - - dprintk("%s(%d)\n", __func__, serial); - val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100; - - if (serial == 1) - val |= 0x100; - - return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val); -} - -static int s5h1411_enable_modulation(struct dvb_frontend *fe, - fe_modulation_t m) -{ - struct s5h1411_state *state = fe->demodulator_priv; - - dprintk("%s(0x%08x)\n", __func__, m); - - if ((state->first_tune == 0) && (m == state->current_modulation)) { - dprintk("%s() Already at desired modulation. Skipping...\n", - __func__); - return 0; - } - - switch (m) { - case VSB_8: - dprintk("%s() VSB_8\n", __func__); - s5h1411_set_if_freq(fe, state->config->vsb_if); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x71); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x00); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0xf1); - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk("%s() QAM_AUTO (64/256)\n", __func__); - s5h1411_set_if_freq(fe, state->config->qam_if); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x0001); - s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x16, 0x1101); - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0x00f0); - break; - default: - dprintk("%s() Invalid modulation\n", __func__); - return -EINVAL; - } - - state->current_modulation = m; - state->first_tune = 0; - s5h1411_softreset(fe); - - return 0; -} - -static int s5h1411_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct s5h1411_state *state = fe->demodulator_priv; - - dprintk("%s(%d)\n", __func__, enable); - - if (enable) - return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1); - else - return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 0); -} - -static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable) -{ - struct s5h1411_state *state = fe->demodulator_priv; - u16 val; - - dprintk("%s(%d)\n", __func__, enable); - - val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xe0) & ~0x02; - - if (enable) - return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, - val | 0x02); - else - return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val); -} - -static int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable) -{ - struct s5h1411_state *state = fe->demodulator_priv; - - dprintk("%s(%d)\n", __func__, enable); - - if (enable) - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 1); - else { - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 0); - s5h1411_softreset(fe); - } - - return 0; -} - -static int s5h1411_sleep(struct dvb_frontend *fe) -{ - return s5h1411_set_powerstate(fe, 1); -} - -static int s5h1411_register_reset(struct dvb_frontend *fe) -{ - struct s5h1411_state *state = fe->demodulator_priv; - - dprintk("%s()\n", __func__); - - return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf3, 0); -} - -/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1411_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct s5h1411_state *state = fe->demodulator_priv; - - dprintk("%s(frequency=%d)\n", __func__, p->frequency); - - s5h1411_softreset(fe); - - state->current_frequency = p->frequency; - - s5h1411_enable_modulation(fe, p->u.vsb.modulation); - - if (fe->ops.tuner_ops.set_params) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - fe->ops.tuner_ops.set_params(fe, p); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* Issue a reset to the demod so it knows to resync against the - newly tuned frequency */ - s5h1411_softreset(fe); - - return 0; -} - -/* Reset the demod hardware and reset all of the configuration registers - to a default state. */ -static int s5h1411_init(struct dvb_frontend *fe) -{ - struct s5h1411_state *state = fe->demodulator_priv; - int i; - - dprintk("%s()\n", __func__); - - s5h1411_set_powerstate(fe, 0); - s5h1411_register_reset(fe); - - for (i = 0; i < ARRAY_SIZE(init_tab); i++) - s5h1411_writereg(state, init_tab[i].addr, - init_tab[i].reg, - init_tab[i].data); - - /* The datasheet says that after initialisation, VSB is default */ - state->current_modulation = VSB_8; - - /* Although the datasheet says it's in VSB, empirical evidence - shows problems getting lock on the first tuning request. Make - sure we call enable_modulation the first time around */ - state->first_tune = 1; - - if (state->config->output_mode == S5H1411_SERIAL_OUTPUT) - /* Serial */ - s5h1411_set_serialmode(fe, 1); - else - /* Parallel */ - s5h1411_set_serialmode(fe, 0); - - s5h1411_set_spectralinversion(fe, state->config->inversion); - s5h1411_set_if_freq(fe, state->config->vsb_if); - s5h1411_set_gpio(fe, state->config->gpio); - s5h1411_set_mpeg_timing(fe, state->config->mpeg_timing); - s5h1411_softreset(fe); - - /* Note: Leaving the I2C gate closed. */ - s5h1411_i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct s5h1411_state *state = fe->demodulator_priv; - u16 reg; - u32 tuner_status = 0; - - *status = 0; - - /* Register F2 bit 15 = Master Lock, removed */ - - switch (state->current_modulation) { - case QAM_64: - case QAM_256: - reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0); - if (reg & 0x10) /* QAM FEC Lock */ - *status |= FE_HAS_SYNC | FE_HAS_LOCK; - if (reg & 0x100) /* QAM EQ Lock */ - *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; - - break; - case VSB_8: - reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2); - if (reg & 0x1000) /* FEC Lock */ - *status |= FE_HAS_SYNC | FE_HAS_LOCK; - if (reg & 0x2000) /* EQ Lock */ - *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; - - reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x53); - if (reg & 0x1) /* AFC Lock */ - *status |= FE_HAS_SIGNAL; - - break; - default: - return -EINVAL; - } - - switch (state->config->status_mode) { - case S5H1411_DEMODLOCKING: - if (*status & FE_HAS_VITERBI) - *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; - break; - case S5H1411_TUNERLOCKING: - /* Get the tuner status */ - if (fe->ops.tuner_ops.get_status) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - fe->ops.tuner_ops.get_status(fe, &tuner_status); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - if (tuner_status) - *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; - break; - } - - dprintk("%s() status 0x%08x\n", __func__, *status); - - return 0; -} - -static int s5h1411_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) -{ - int i, ret = -EINVAL; - dprintk("%s()\n", __func__); - - for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) { - if (v < qam256_snr_tab[i].val) { - *snr = qam256_snr_tab[i].data; - ret = 0; - break; - } - } - return ret; -} - -static int s5h1411_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) -{ - int i, ret = -EINVAL; - dprintk("%s()\n", __func__); - - for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) { - if (v < qam64_snr_tab[i].val) { - *snr = qam64_snr_tab[i].data; - ret = 0; - break; - } - } - return ret; -} - -static int s5h1411_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) -{ - int i, ret = -EINVAL; - dprintk("%s()\n", __func__); - - for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) { - if (v > vsb_snr_tab[i].val) { - *snr = vsb_snr_tab[i].data; - ret = 0; - break; - } - } - dprintk("%s() snr=%d\n", __func__, *snr); - return ret; -} - -static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct s5h1411_state *state = fe->demodulator_priv; - u16 reg; - dprintk("%s()\n", __func__); - - switch (state->current_modulation) { - case QAM_64: - reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1); - return s5h1411_qam64_lookup_snr(fe, snr, reg); - case QAM_256: - reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1); - return s5h1411_qam256_lookup_snr(fe, snr, reg); - case VSB_8: - reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, - 0xf2) & 0x3ff; - return s5h1411_vsb_lookup_snr(fe, snr, reg); - default: - break; - } - - return -EINVAL; -} - -static int s5h1411_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - return s5h1411_read_snr(fe, signal_strength); -} - -static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct s5h1411_state *state = fe->demodulator_priv; - - *ucblocks = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xc9); - - return 0; -} - -static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - return s5h1411_read_ucblocks(fe, ber); -} - -static int s5h1411_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct s5h1411_state *state = fe->demodulator_priv; - - p->frequency = state->current_frequency; - p->u.vsb.modulation = state->current_modulation; - - return 0; -} - -static int s5h1411_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void s5h1411_release(struct dvb_frontend *fe) -{ - struct s5h1411_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops s5h1411_ops; - -struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, - struct i2c_adapter *i2c) -{ - struct s5h1411_state *state = NULL; - u16 reg; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct s5h1411_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->current_modulation = VSB_8; - state->inversion = state->config->inversion; - - /* check if the demod exists */ - reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x05); - if (reg != 0x0066) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &s5h1411_ops, - sizeof(struct dvb_frontend_ops)); - - state->frontend.demodulator_priv = state; - - if (s5h1411_init(&state->frontend) != 0) { - printk(KERN_ERR "%s: Failed to initialize correctly\n", - __func__); - goto error; - } - - /* Note: Leaving the I2C gate open here. */ - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1); - - /* Put the device into low-power mode until first use */ - s5h1411_set_powerstate(&state->frontend, 1); - - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(s5h1411_attach); - -static struct dvb_frontend_ops s5h1411_ops = { - - .info = { - .name = "Samsung S5H1411 QAM/8VSB Frontend", - .type = FE_ATSC, - .frequency_min = 54000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - - .init = s5h1411_init, - .sleep = s5h1411_sleep, - .i2c_gate_ctrl = s5h1411_i2c_gate_ctrl, - .set_frontend = s5h1411_set_frontend, - .get_frontend = s5h1411_get_frontend, - .get_tune_settings = s5h1411_get_tune_settings, - .read_status = s5h1411_read_status, - .read_ber = s5h1411_read_ber, - .read_signal_strength = s5h1411_read_signal_strength, - .read_snr = s5h1411_read_snr, - .read_ucblocks = s5h1411_read_ucblocks, - .release = s5h1411_release, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable verbose debug messages"); - -MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver"); -MODULE_AUTHOR("Steven Toth"); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1411.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1411.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1411.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1411.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -/* - Samsung S5H1411 VSB/QAM demodulator driver - - Copyright (C) 2008 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __S5H1411_H__ -#define __S5H1411_H__ - -#include - -#define S5H1411_I2C_TOP_ADDR (0x32 >> 1) -#define S5H1411_I2C_QAM_ADDR (0x34 >> 1) - -struct s5h1411_config { - - /* serial/parallel output */ -#define S5H1411_PARALLEL_OUTPUT 0 -#define S5H1411_SERIAL_OUTPUT 1 - u8 output_mode; - - /* GPIO Setting */ -#define S5H1411_GPIO_OFF 0 -#define S5H1411_GPIO_ON 1 - u8 gpio; - - /* MPEG signal timing */ -#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 - u16 mpeg_timing; - - /* IF Freq for QAM and VSB in KHz */ -#define S5H1411_IF_3250 3250 -#define S5H1411_IF_3500 3500 -#define S5H1411_IF_4000 4000 -#define S5H1411_IF_5380 5380 -#define S5H1411_IF_44000 44000 -#define S5H1411_VSB_IF_DEFAULT S5H1411_IF_44000 -#define S5H1411_QAM_IF_DEFAULT S5H1411_IF_44000 - u16 qam_if; - u16 vsb_if; - - /* Spectral Inversion */ -#define S5H1411_INVERSION_OFF 0 -#define S5H1411_INVERSION_ON 1 - u8 inversion; - - /* Return lock status based on tuner lock, or demod lock */ -#define S5H1411_TUNERLOCKING 0 -#define S5H1411_DEMODLOCKING 1 - u8 status_mode; -}; - -#if defined(CONFIG_DVB_S5H1411) || \ - (defined(CONFIG_DVB_S5H1411_MODULE) && defined(MODULE)) -extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *s5h1411_attach( - const struct s5h1411_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_S5H1411 */ - -#endif /* __S5H1411_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,981 +0,0 @@ -/* - * Driver for - * Samsung S5H1420 and - * PnpNetwork PN1010 QPSK Demodulator - * - * Copyright (C) 2005 Andrew de Quincey - * Copyright (C) 2005-8 Patrick Boettcher - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -#include "dvb_frontend.h" -#include "s5h1420.h" -#include "s5h1420_priv.h" - -#define TONE_FREQ 22000 - -struct s5h1420_state { - struct i2c_adapter* i2c; - const struct s5h1420_config* config; - - struct dvb_frontend frontend; - struct i2c_adapter tuner_i2c_adapter; - - u8 CON_1_val; - - u8 postlocked:1; - u32 fclk; - u32 tunedfreq; - fe_code_rate_t fec_inner; - u32 symbol_rate; - - /* FIXME: ugly workaround for flexcop's incapable i2c-controller - * it does not support repeated-start, workaround: write addr-1 - * and then read - */ - u8 shadow[256]; -}; - -static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); -static int s5h1420_get_tune_settings(struct dvb_frontend* fe, - struct dvb_frontend_tune_settings* fesettings); - - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debugging"); - -#define dprintk(x...) do { \ - if (debug) \ - printk(KERN_DEBUG "S5H1420: " x); \ -} while (0) - -static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg) -{ - int ret; - u8 b[2]; - struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 2 }, - { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = 1 }, - }; - - b[0] = (reg - 1) & 0xff; - b[1] = state->shadow[(reg - 1) & 0xff]; - - if (state->config->repeated_start_workaround) { - ret = i2c_transfer(state->i2c, msg, 3); - if (ret != 3) - return ret; - } else { - ret = i2c_transfer(state->i2c, &msg[1], 1); - if (ret != 1) - return ret; - ret = i2c_transfer(state->i2c, &msg[2], 1); - if (ret != 1) - return ret; - } - - /* dprintk("rd(%02x): %02x %02x\n", state->config->demod_address, reg, b[0]); */ - - return b[0]; -} - -static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - int err; - - /* dprintk("wr(%02x): %02x %02x\n", state->config->demod_address, reg, data); */ - err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) { - dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data); - return -EREMOTEIO; - } - state->shadow[reg] = data; - - return 0; -} - -static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct s5h1420_state* state = fe->demodulator_priv; - - dprintk("enter %s\n", __func__); - - switch(voltage) { - case SEC_VOLTAGE_13: - s5h1420_writereg(state, 0x3c, - (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02); - break; - - case SEC_VOLTAGE_18: - s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03); - break; - - case SEC_VOLTAGE_OFF: - s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd); - break; - } - - dprintk("leave %s\n", __func__); - return 0; -} - -static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct s5h1420_state* state = fe->demodulator_priv; - - dprintk("enter %s\n", __func__); - switch(tone) { - case SEC_TONE_ON: - s5h1420_writereg(state, 0x3b, - (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08); - break; - - case SEC_TONE_OFF: - s5h1420_writereg(state, 0x3b, - (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); - break; - } - dprintk("leave %s\n", __func__); - - return 0; -} - -static int s5h1420_send_master_cmd (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd* cmd) -{ - struct s5h1420_state* state = fe->demodulator_priv; - u8 val; - int i; - unsigned long timeout; - int result = 0; - - dprintk("enter %s\n", __func__); - if (cmd->msg_len > 8) - return -EINVAL; - - /* setup for DISEQC */ - val = s5h1420_readreg(state, 0x3b); - s5h1420_writereg(state, 0x3b, 0x02); - msleep(15); - - /* write the DISEQC command bytes */ - for(i=0; i< cmd->msg_len; i++) { - s5h1420_writereg(state, 0x3d + i, cmd->msg[i]); - } - - /* kick off transmission */ - s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | - ((cmd->msg_len-1) << 4) | 0x08); - - /* wait for transmission to complete */ - timeout = jiffies + ((100*HZ) / 1000); - while(time_before(jiffies, timeout)) { - if (!(s5h1420_readreg(state, 0x3b) & 0x08)) - break; - - msleep(5); - } - if (time_after(jiffies, timeout)) - result = -ETIMEDOUT; - - /* restore original settings */ - s5h1420_writereg(state, 0x3b, val); - msleep(15); - dprintk("leave %s\n", __func__); - return result; -} - -static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, - struct dvb_diseqc_slave_reply* reply) -{ - struct s5h1420_state* state = fe->demodulator_priv; - u8 val; - int i; - int length; - unsigned long timeout; - int result = 0; - - /* setup for DISEQC recieve */ - val = s5h1420_readreg(state, 0x3b); - s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */ - msleep(15); - - /* wait for reception to complete */ - timeout = jiffies + ((reply->timeout*HZ) / 1000); - while(time_before(jiffies, timeout)) { - if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */ - break; - - msleep(5); - } - if (time_after(jiffies, timeout)) { - result = -ETIMEDOUT; - goto exit; - } - - /* check error flag - FIXME: not sure what this does - docs do not describe - * beyond "error flag for diseqc receive data :( */ - if (s5h1420_readreg(state, 0x49)) { - result = -EIO; - goto exit; - } - - /* check length */ - length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4; - if (length > sizeof(reply->msg)) { - result = -EOVERFLOW; - goto exit; - } - reply->msg_len = length; - - /* extract data */ - for(i=0; i< length; i++) { - reply->msg[i] = s5h1420_readreg(state, 0x3d + i); - } - -exit: - /* restore original settings */ - s5h1420_writereg(state, 0x3b, val); - msleep(15); - return result; -} - -static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct s5h1420_state* state = fe->demodulator_priv; - u8 val; - int result = 0; - unsigned long timeout; - - /* setup for tone burst */ - val = s5h1420_readreg(state, 0x3b); - s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01); - - /* set value for B position if requested */ - if (minicmd == SEC_MINI_B) { - s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04); - } - msleep(15); - - /* start transmission */ - s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08); - - /* wait for transmission to complete */ - timeout = jiffies + ((100*HZ) / 1000); - while(time_before(jiffies, timeout)) { - if (!(s5h1420_readreg(state, 0x3b) & 0x08)) - break; - - msleep(5); - } - if (time_after(jiffies, timeout)) - result = -ETIMEDOUT; - - /* restore original settings */ - s5h1420_writereg(state, 0x3b, val); - msleep(15); - return result; -} - -static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state) -{ - u8 val; - fe_status_t status = 0; - - val = s5h1420_readreg(state, 0x14); - if (val & 0x02) - status |= FE_HAS_SIGNAL; - if (val & 0x01) - status |= FE_HAS_CARRIER; - val = s5h1420_readreg(state, 0x36); - if (val & 0x01) - status |= FE_HAS_VITERBI; - if (val & 0x20) - status |= FE_HAS_SYNC; - if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC)) - status |= FE_HAS_LOCK; - - return status; -} - -static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct s5h1420_state* state = fe->demodulator_priv; - u8 val; - - dprintk("enter %s\n", __func__); - - if (status == NULL) - return -EINVAL; - - /* determine lock state */ - *status = s5h1420_get_status_bits(state); - - /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert - the inversion, wait a bit and check again */ - if (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI)) { - val = s5h1420_readreg(state, Vit10); - if ((val & 0x07) == 0x03) { - if (val & 0x08) - s5h1420_writereg(state, Vit09, 0x13); - else - s5h1420_writereg(state, Vit09, 0x1b); - - /* wait a bit then update lock status */ - mdelay(200); - *status = s5h1420_get_status_bits(state); - } - } - - /* perform post lock setup */ - if ((*status & FE_HAS_LOCK) && !state->postlocked) { - - /* calculate the data rate */ - u32 tmp = s5h1420_getsymbolrate(state); - switch (s5h1420_readreg(state, Vit10) & 0x07) { - case 0: tmp = (tmp * 2 * 1) / 2; break; - case 1: tmp = (tmp * 2 * 2) / 3; break; - case 2: tmp = (tmp * 2 * 3) / 4; break; - case 3: tmp = (tmp * 2 * 5) / 6; break; - case 4: tmp = (tmp * 2 * 6) / 7; break; - case 5: tmp = (tmp * 2 * 7) / 8; break; - } - - if (tmp == 0) { - printk(KERN_ERR "s5h1420: avoided division by 0\n"); - tmp = 1; - } - tmp = state->fclk / tmp; - - - /* set the MPEG_CLK_INTL for the calculated data rate */ - if (tmp < 2) - val = 0x00; - else if (tmp < 5) - val = 0x01; - else if (tmp < 9) - val = 0x02; - else if (tmp < 13) - val = 0x03; - else if (tmp < 17) - val = 0x04; - else if (tmp < 25) - val = 0x05; - else if (tmp < 33) - val = 0x06; - else - val = 0x07; - dprintk("for MPEG_CLK_INTL %d %x\n", tmp, val); - - s5h1420_writereg(state, FEC01, 0x18); - s5h1420_writereg(state, FEC01, 0x10); - s5h1420_writereg(state, FEC01, val); - - /* Enable "MPEG_Out" */ - val = s5h1420_readreg(state, Mpeg02); - s5h1420_writereg(state, Mpeg02, val | (1 << 6)); - - /* kicker disable */ - val = s5h1420_readreg(state, QPSK01) & 0x7f; - s5h1420_writereg(state, QPSK01, val); - - /* DC freeze TODO it was never activated by default or it can stay activated */ - - if (s5h1420_getsymbolrate(state) >= 20000000) { - s5h1420_writereg(state, Loop04, 0x8a); - s5h1420_writereg(state, Loop05, 0x6a); - } else { - s5h1420_writereg(state, Loop04, 0x58); - s5h1420_writereg(state, Loop05, 0x27); - } - - /* post-lock processing has been done! */ - state->postlocked = 1; - } - - dprintk("leave %s\n", __func__); - - return 0; -} - -static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct s5h1420_state* state = fe->demodulator_priv; - - s5h1420_writereg(state, 0x46, 0x1d); - mdelay(25); - - *ber = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); - - return 0; -} - -static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct s5h1420_state* state = fe->demodulator_priv; - - u8 val = s5h1420_readreg(state, 0x15); - - *strength = (u16) ((val << 8) | val); - - return 0; -} - -static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct s5h1420_state* state = fe->demodulator_priv; - - s5h1420_writereg(state, 0x46, 0x1f); - mdelay(25); - - *ucblocks = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); - - return 0; -} - -static void s5h1420_reset(struct s5h1420_state* state) -{ - dprintk("%s\n", __func__); - s5h1420_writereg (state, 0x01, 0x08); - s5h1420_writereg (state, 0x01, 0x00); - udelay(10); -} - -static void s5h1420_setsymbolrate(struct s5h1420_state* state, - struct dvb_frontend_parameters *p) -{ - u8 v; - u64 val; - - dprintk("enter %s\n", __func__); - - val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24); - if (p->u.qpsk.symbol_rate < 29000000) - val *= 2; - do_div(val, (state->fclk / 1000)); - - dprintk("symbol rate register: %06llx\n", (unsigned long long)val); - - v = s5h1420_readreg(state, Loop01); - s5h1420_writereg(state, Loop01, v & 0x7f); - s5h1420_writereg(state, Tnco01, val >> 16); - s5h1420_writereg(state, Tnco02, val >> 8); - s5h1420_writereg(state, Tnco03, val & 0xff); - s5h1420_writereg(state, Loop01, v | 0x80); - dprintk("leave %s\n", __func__); -} - -static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) -{ - return state->symbol_rate; -} - -static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset) -{ - int val; - u8 v; - - dprintk("enter %s\n", __func__); - - /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so - * divide fclk by 1000000 to get the correct value. */ - val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000)); - - dprintk("phase rotator/freqoffset: %d %06x\n", freqoffset, val); - - v = s5h1420_readreg(state, Loop01); - s5h1420_writereg(state, Loop01, v & 0xbf); - s5h1420_writereg(state, Pnco01, val >> 16); - s5h1420_writereg(state, Pnco02, val >> 8); - s5h1420_writereg(state, Pnco03, val & 0xff); - s5h1420_writereg(state, Loop01, v | 0x40); - dprintk("leave %s\n", __func__); -} - -static int s5h1420_getfreqoffset(struct s5h1420_state* state) -{ - int val; - - s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08); - val = s5h1420_readreg(state, 0x0e) << 16; - val |= s5h1420_readreg(state, 0x0f) << 8; - val |= s5h1420_readreg(state, 0x10); - s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); - - if (val & 0x800000) - val |= 0xff000000; - - /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so - * divide fclk by 1000000 to get the correct value. */ - val = (((-val) * (state->fclk/1000000)) / (1<<24)); - - return val; -} - -static void s5h1420_setfec_inversion(struct s5h1420_state* state, - struct dvb_frontend_parameters *p) -{ - u8 inversion = 0; - u8 vit08, vit09; - - dprintk("enter %s\n", __func__); - - if (p->inversion == INVERSION_OFF) - inversion = state->config->invert ? 0x08 : 0; - else if (p->inversion == INVERSION_ON) - inversion = state->config->invert ? 0 : 0x08; - - if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { - vit08 = 0x3f; - vit09 = 0; - } else { - switch(p->u.qpsk.fec_inner) { - case FEC_1_2: - vit08 = 0x01; vit09 = 0x10; - break; - - case FEC_2_3: - vit08 = 0x02; vit09 = 0x11; - break; - - case FEC_3_4: - vit08 = 0x04; vit09 = 0x12; - break; - - case FEC_5_6: - vit08 = 0x08; vit09 = 0x13; - break; - - case FEC_6_7: - vit08 = 0x10; vit09 = 0x14; - break; - - case FEC_7_8: - vit08 = 0x20; vit09 = 0x15; - break; - - default: - return; - } - } - vit09 |= inversion; - dprintk("fec: %02x %02x\n", vit08, vit09); - s5h1420_writereg(state, Vit08, vit08); - s5h1420_writereg(state, Vit09, vit09); - dprintk("leave %s\n", __func__); -} - -static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) -{ - switch(s5h1420_readreg(state, 0x32) & 0x07) { - case 0: - return FEC_1_2; - - case 1: - return FEC_2_3; - - case 2: - return FEC_3_4; - - case 3: - return FEC_5_6; - - case 4: - return FEC_6_7; - - case 5: - return FEC_7_8; - } - - return FEC_NONE; -} - -static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) -{ - if (s5h1420_readreg(state, 0x32) & 0x08) - return INVERSION_ON; - - return INVERSION_OFF; -} - -static int s5h1420_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) -{ - struct s5h1420_state* state = fe->demodulator_priv; - int frequency_delta; - struct dvb_frontend_tune_settings fesettings; - uint8_t clock_settting; - - dprintk("enter %s\n", __func__); - - /* check if we should do a fast-tune */ - memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); - s5h1420_get_tune_settings(fe, &fesettings); - frequency_delta = p->frequency - state->tunedfreq; - if ((frequency_delta > -fesettings.max_drift) && - (frequency_delta < fesettings.max_drift) && - (frequency_delta != 0) && - (state->fec_inner == p->u.qpsk.fec_inner) && - (state->symbol_rate == p->u.qpsk.symbol_rate)) { - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - if (fe->ops.tuner_ops.get_frequency) { - u32 tmp; - fe->ops.tuner_ops.get_frequency(fe, &tmp); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - s5h1420_setfreqoffset(state, p->frequency - tmp); - } else { - s5h1420_setfreqoffset(state, 0); - } - dprintk("simple tune\n"); - return 0; - } - dprintk("tuning demod\n"); - - /* first of all, software reset */ - s5h1420_reset(state); - - /* set s5h1420 fclk PLL according to desired symbol rate */ - if (p->u.qpsk.symbol_rate > 33000000) - state->fclk = 80000000; - else if (p->u.qpsk.symbol_rate > 28500000) - state->fclk = 59000000; - else if (p->u.qpsk.symbol_rate > 25000000) - state->fclk = 86000000; - else if (p->u.qpsk.symbol_rate > 1900000) - state->fclk = 88000000; - else - state->fclk = 44000000; - - /* Clock */ - switch (state->fclk) { - default: - case 88000000: - clock_settting = 80; - break; - case 86000000: - clock_settting = 78; - break; - case 80000000: - clock_settting = 72; - break; - case 59000000: - clock_settting = 51; - break; - case 44000000: - clock_settting = 36; - break; - } - dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); - s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8); - s5h1420_writereg(state, PLL02, 0x40); - s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); - - /* TODO DC offset removal, config parameter ? */ - if (p->u.qpsk.symbol_rate > 29000000) - s5h1420_writereg(state, QPSK01, 0xae | 0x10); - else - s5h1420_writereg(state, QPSK01, 0xac | 0x10); - - /* set misc registers */ - s5h1420_writereg(state, CON_1, 0x00); - s5h1420_writereg(state, QPSK02, 0x00); - s5h1420_writereg(state, Pre01, 0xb0); - - s5h1420_writereg(state, Loop01, 0xF0); - s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */ - s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */ - if (p->u.qpsk.symbol_rate > 20000000) - s5h1420_writereg(state, Loop04, 0x79); - else - s5h1420_writereg(state, Loop04, 0x58); - s5h1420_writereg(state, Loop05, 0x6b); - - if (p->u.qpsk.symbol_rate >= 8000000) - s5h1420_writereg(state, Post01, (0 << 6) | 0x10); - else if (p->u.qpsk.symbol_rate >= 4000000) - s5h1420_writereg(state, Post01, (1 << 6) | 0x10); - else - s5h1420_writereg(state, Post01, (3 << 6) | 0x10); - - s5h1420_writereg(state, Monitor12, 0x00); /* unfreeze DC compensation */ - - s5h1420_writereg(state, Sync01, 0x33); - s5h1420_writereg(state, Mpeg01, state->config->cdclk_polarity); - s5h1420_writereg(state, Mpeg02, 0x3d); /* Parallel output more, disabled -> enabled later */ - s5h1420_writereg(state, Err01, 0x03); /* 0x1d for s5h1420 */ - - s5h1420_writereg(state, Vit06, 0x6e); /* 0x8e for s5h1420 */ - s5h1420_writereg(state, DiS03, 0x00); - s5h1420_writereg(state, Rf01, 0x61); /* Tuner i2c address - for the gate controller */ - - /* set tuner PLL */ - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - s5h1420_setfreqoffset(state, 0); - } - - /* set the reset of the parameters */ - s5h1420_setsymbolrate(state, p); - s5h1420_setfec_inversion(state, p); - - /* start QPSK */ - s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1); - - state->fec_inner = p->u.qpsk.fec_inner; - state->symbol_rate = p->u.qpsk.symbol_rate; - state->postlocked = 0; - state->tunedfreq = p->frequency; - - dprintk("leave %s\n", __func__); - return 0; -} - -static int s5h1420_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) -{ - struct s5h1420_state* state = fe->demodulator_priv; - - p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state); - p->inversion = s5h1420_getinversion(state); - p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state); - p->u.qpsk.fec_inner = s5h1420_getfec(state); - - return 0; -} - -static int s5h1420_get_tune_settings(struct dvb_frontend* fe, - struct dvb_frontend_tune_settings* fesettings) -{ - if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { - fesettings->min_delay_ms = 50; - fesettings->step_size = 2000; - fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { - fesettings->min_delay_ms = 100; - fesettings->step_size = 1500; - fesettings->max_drift = 9000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { - fesettings->min_delay_ms = 100; - fesettings->step_size = 1000; - fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { - fesettings->min_delay_ms = 100; - fesettings->step_size = 500; - fesettings->max_drift = 7000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { - fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); - fesettings->max_drift = 14 * fesettings->step_size; - } else { - fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); - fesettings->max_drift = 18 * fesettings->step_size; - } - - return 0; -} - -static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct s5h1420_state* state = fe->demodulator_priv; - - if (enable) - return s5h1420_writereg(state, 0x02, state->CON_1_val | 1); - else - return s5h1420_writereg(state, 0x02, state->CON_1_val & 0xfe); -} - -static int s5h1420_init (struct dvb_frontend* fe) -{ - struct s5h1420_state* state = fe->demodulator_priv; - - /* disable power down and do reset */ - state->CON_1_val = state->config->serial_mpeg << 4; - s5h1420_writereg(state, 0x02, state->CON_1_val); - msleep(10); - s5h1420_reset(state); - - return 0; -} - -static int s5h1420_sleep(struct dvb_frontend* fe) -{ - struct s5h1420_state* state = fe->demodulator_priv; - state->CON_1_val = 0x12; - return s5h1420_writereg(state, 0x02, state->CON_1_val); -} - -static void s5h1420_release(struct dvb_frontend* fe) -{ - struct s5h1420_state* state = fe->demodulator_priv; - i2c_del_adapter(&state->tuner_i2c_adapter); - kfree(state); -} - -static u32 s5h1420_tuner_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) -{ - struct s5h1420_state *state = i2c_get_adapdata(i2c_adap); - struct i2c_msg m[1 + num]; - u8 tx_open[2] = { CON_1, state->CON_1_val | 1 }; /* repeater stops once there was a stop condition */ - - memset(m, 0, sizeof(struct i2c_msg) * (1 + num)); - - m[0].addr = state->config->demod_address; - m[0].buf = tx_open; - m[0].len = 2; - - memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); - - return i2c_transfer(state->i2c, m, 1+num) == 1 + num ? num : -EIO; -} - -static struct i2c_algorithm s5h1420_tuner_i2c_algo = { - .master_xfer = s5h1420_tuner_i2c_tuner_xfer, - .functionality = s5h1420_tuner_i2c_func, -}; - -struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe) -{ - struct s5h1420_state *state = fe->demodulator_priv; - return &state->tuner_i2c_adapter; -} -EXPORT_SYMBOL(s5h1420_get_tuner_i2c_adapter); - -static struct dvb_frontend_ops s5h1420_ops; - -struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, - struct i2c_adapter *i2c) -{ - /* allocate memory for the internal state */ - struct s5h1420_state *state = kzalloc(sizeof(struct s5h1420_state), GFP_KERNEL); - u8 i; - - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->postlocked = 0; - state->fclk = 88000000; - state->tunedfreq = 0; - state->fec_inner = FEC_NONE; - state->symbol_rate = 0; - - /* check if the demod is there + identify it */ - i = s5h1420_readreg(state, ID01); - if (i != 0x03) - goto error; - - memset(state->shadow, 0xff, sizeof(state->shadow)); - - for (i = 0; i < 0x50; i++) - state->shadow[i] = s5h1420_readreg(state, i); - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - /* create tuner i2c adapter */ - strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", - sizeof(state->tuner_i2c_adapter.name)); - state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo; - state->tuner_i2c_adapter.algo_data = NULL; - i2c_set_adapdata(&state->tuner_i2c_adapter, state); - if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) { - printk(KERN_ERR "S5H1420/PN1010: tuner i2c bus could not be initialized\n"); - goto error; - } - - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(s5h1420_attach); - -static struct dvb_frontend_ops s5h1420_ops = { - - .info = { - .name = "Samsung S5H1420/PnpNetwork PN1010 DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - /* .symbol_rate_tolerance = ???,*/ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK - }, - - .release = s5h1420_release, - - .init = s5h1420_init, - .sleep = s5h1420_sleep, - .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl, - - .set_frontend = s5h1420_set_frontend, - .get_frontend = s5h1420_get_frontend, - .get_tune_settings = s5h1420_get_tune_settings, - - .read_status = s5h1420_read_status, - .read_ber = s5h1420_read_ber, - .read_signal_strength = s5h1420_read_signal_strength, - .read_ucblocks = s5h1420_read_ucblocks, - - .diseqc_send_master_cmd = s5h1420_send_master_cmd, - .diseqc_recv_slave_reply = s5h1420_recv_slave_reply, - .diseqc_send_burst = s5h1420_send_burst, - .set_tone = s5h1420_set_tone, - .set_voltage = s5h1420_set_voltage, -}; - -MODULE_DESCRIPTION("Samsung S5H1420/PnpNetwork PN1010 DVB-S Demodulator driver"); -MODULE_AUTHOR("Andrew de Quincey, Patrick Boettcher"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* - * Driver for - * Samsung S5H1420 and - * PnpNetwork PN1010 QPSK Demodulator - * - * Copyright (C) 2005 Andrew de Quincey - * Copyright (C) 2005-8 Patrick Boettcher - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef S5H1420_H -#define S5H1420_H - -#include - -struct s5h1420_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* does the inversion require inversion? */ - u8 invert:1; - - u8 repeated_start_workaround:1; - u8 cdclk_polarity:1; /* 1 == falling edge, 0 == raising edge */ - - u8 serial_mpeg:1; -}; - -#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE)) -extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, - struct i2c_adapter *i2c); -extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe); -#else -static inline struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe) -{ - return NULL; -} -#endif // CONFIG_DVB_S5H1420 - -#endif // S5H1420_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1420_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/* - * Driver for - * Samsung S5H1420 and - * PnpNetwork PN1010 QPSK Demodulator - * - * Copyright (C) 2005 Andrew de Quincey - * Copyright (C) 2005 Patrick Boettcher - * - * 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, or (at your option) - * any later version. - * - * 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., 675 Mass - * Ave, Cambridge, MA 02139, USA. - */ -#ifndef S5H1420_PRIV -#define S5H1420_PRIV - -#include - -enum s5h1420_register { - ID01 = 0x00, - CON_0 = 0x01, - CON_1 = 0x02, - PLL01 = 0x03, - PLL02 = 0x04, - QPSK01 = 0x05, - QPSK02 = 0x06, - Pre01 = 0x07, - Post01 = 0x08, - Loop01 = 0x09, - Loop02 = 0x0a, - Loop03 = 0x0b, - Loop04 = 0x0c, - Loop05 = 0x0d, - Pnco01 = 0x0e, - Pnco02 = 0x0f, - Pnco03 = 0x10, - Tnco01 = 0x11, - Tnco02 = 0x12, - Tnco03 = 0x13, - Monitor01 = 0x14, - Monitor02 = 0x15, - Monitor03 = 0x16, - Monitor04 = 0x17, - Monitor05 = 0x18, - Monitor06 = 0x19, - Monitor07 = 0x1a, - Monitor12 = 0x1f, - - FEC01 = 0x22, - Soft01 = 0x23, - Soft02 = 0x24, - Soft03 = 0x25, - Soft04 = 0x26, - Soft05 = 0x27, - Soft06 = 0x28, - Vit01 = 0x29, - Vit02 = 0x2a, - Vit03 = 0x2b, - Vit04 = 0x2c, - Vit05 = 0x2d, - Vit06 = 0x2e, - Vit07 = 0x2f, - Vit08 = 0x30, - Vit09 = 0x31, - Vit10 = 0x32, - Vit11 = 0x33, - Vit12 = 0x34, - Sync01 = 0x35, - Sync02 = 0x36, - Rs01 = 0x37, - Mpeg01 = 0x38, - Mpeg02 = 0x39, - DiS01 = 0x3a, - DiS02 = 0x3b, - DiS03 = 0x3c, - DiS04 = 0x3d, - DiS05 = 0x3e, - DiS06 = 0x3f, - DiS07 = 0x40, - DiS08 = 0x41, - DiS09 = 0x42, - DiS10 = 0x43, - DiS11 = 0x44, - Rf01 = 0x45, - Err01 = 0x46, - Err02 = 0x47, - Err03 = 0x48, - Err04 = 0x49, -}; - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1432.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1432.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1432.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1432.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,415 +0,0 @@ -/* - * Samsung s5h1432 DVB-T demodulator driver - * - * Copyright (C) 2009 Bill Liu - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "s5h1432.h" - -struct s5h1432_state { - - struct i2c_adapter *i2c; - - /* configuration settings */ - const struct s5h1432_config *config; - - struct dvb_frontend frontend; - - fe_modulation_t current_modulation; - unsigned int first_tune:1; - - u32 current_frequency; - int if_freq; - - u8 inversion; -}; - -static int debug; - -#define dprintk(arg...) do { \ - if (debug) \ - printk(arg); \ - } while (0) - -static int s5h1432_writereg(struct s5h1432_state *state, - u8 addr, u8 reg, u8 data) -{ - int ret; - u8 buf[] = { reg, data }; - - struct i2c_msg msg = {.addr = addr, .flags = 0, .buf = buf, .len = 2 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, " - "ret == %i)\n", __func__, addr, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -static u8 s5h1432_readreg(struct s5h1432_state *state, u8 addr, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - - struct i2c_msg msg[] = { - {.addr = addr, .flags = 0, .buf = b0, .len = 1}, - {.addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1} - }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - printk(KERN_ERR "%s: readreg error (ret == %i)\n", - __func__, ret); - return b1[0]; -} - -static int s5h1432_sleep(struct dvb_frontend *fe) -{ - return 0; -} - -static int s5h1432_set_channel_bandwidth(struct dvb_frontend *fe, - u32 bandwidth) -{ - struct s5h1432_state *state = fe->demodulator_priv; - - u8 reg = 0; - - /* Register [0x2E] bit 3:2 : 8MHz = 0; 7MHz = 1; 6MHz = 2 */ - reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x2E); - reg &= ~(0x0C); - switch (bandwidth) { - case 6: - reg |= 0x08; - break; - case 7: - reg |= 0x04; - break; - case 8: - reg |= 0x00; - break; - default: - return 0; - } - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2E, reg); - return 1; -} - -static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz) -{ - struct s5h1432_state *state = fe->demodulator_priv; - - switch (ifFreqHz) { - case TAIWAN_HI_IF_FREQ_44_MHZ: - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x15); - break; - case EUROPE_HI_IF_FREQ_36_MHZ: - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x40); - break; - case IF_FREQ_6_MHZ: - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xe0); - break; - case IF_FREQ_3point3_MHZ: - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE); - break; - case IF_FREQ_3point5_MHZ: - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xED); - break; - case IF_FREQ_4_MHZ: - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0xAA); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0xAA); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEA); - break; - default: - { - u32 value = 0; - value = (u32) (((48000 - (ifFreqHz / 1000)) * 512 * - (u32) 32768) / (48 * 1000)); - printk(KERN_INFO - "Default IFFreq %d :reg value = 0x%x\n", - ifFreqHz, value); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, - (u8) value & 0xFF); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, - (u8) (value >> 8) & 0xFF); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, - (u8) (value >> 16) & 0xFF); - break; - } - - } - - return 1; -} - -/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1432_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - u32 dvb_bandwidth = 8; - struct s5h1432_state *state = fe->demodulator_priv; - - if (p->frequency == state->current_frequency) { - /*current_frequency = p->frequency; */ - /*state->current_frequency = p->frequency; */ - } else { - fe->ops.tuner_ops.set_params(fe, p); - msleep(300); - s5h1432_set_channel_bandwidth(fe, dvb_bandwidth); - switch (p->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - dvb_bandwidth = 6; - s5h1432_set_IF(fe, IF_FREQ_4_MHZ); - break; - case BANDWIDTH_7_MHZ: - dvb_bandwidth = 7; - s5h1432_set_IF(fe, IF_FREQ_4_MHZ); - break; - case BANDWIDTH_8_MHZ: - dvb_bandwidth = 8; - s5h1432_set_IF(fe, IF_FREQ_4_MHZ); - break; - default: - return 0; - } - /*fe->ops.tuner_ops.set_params(fe, p); */ -/*Soft Reset chip*/ - msleep(30); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); - msleep(30); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b); - - s5h1432_set_channel_bandwidth(fe, dvb_bandwidth); - switch (p->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - dvb_bandwidth = 6; - s5h1432_set_IF(fe, IF_FREQ_4_MHZ); - break; - case BANDWIDTH_7_MHZ: - dvb_bandwidth = 7; - s5h1432_set_IF(fe, IF_FREQ_4_MHZ); - break; - case BANDWIDTH_8_MHZ: - dvb_bandwidth = 8; - s5h1432_set_IF(fe, IF_FREQ_4_MHZ); - break; - default: - return 0; - } - /*fe->ops.tuner_ops.set_params(fe,p); */ - /*Soft Reset chip*/ - msleep(30); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); - msleep(30); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b); - - } - - state->current_frequency = p->frequency; - - return 0; -} - -static int s5h1432_init(struct dvb_frontend *fe) -{ - struct s5h1432_state *state = fe->demodulator_priv; - - u8 reg = 0; - state->current_frequency = 0; - printk(KERN_INFO " s5h1432_init().\n"); - - /*Set VSB mode as default, this also does a soft reset */ - /*Initialize registers */ - - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x04, 0xa8); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x05, 0x01); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x07, 0x70); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x19, 0x80); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1b, 0x9D); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1c, 0x30); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1d, 0x20); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x1B); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2e, 0x40); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, 0x84); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x50, 0x5a); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x5a, 0xd3); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x68, 0x50); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xb8, 0x3c); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xc4, 0x10); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xcc, 0x9c); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xDA, 0x00); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe1, 0x94); - /* s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf4, 0xa1); */ - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf9, 0x00); - - /*For NXP tuner*/ - - /*Set 3.3MHz as default IF frequency */ - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE); - /* Set reg 0x1E to get the full dynamic range */ - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x31); - - /* Mode setting in demod */ - reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x42); - reg |= 0x80; - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, reg); - /* Serial mode */ - - /* Soft Reset chip */ - - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); - msleep(30); - s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b); - - - return 0; -} - -static int s5h1432_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - return 0; -} - -static int s5h1432_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - return 0; -} - -static int s5h1432_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - return 0; -} - -static int s5h1432_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - - return 0; -} - -static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - return 0; -} - -static int s5h1432_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - return 0; -} - -static int s5h1432_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - return 0; -} - -static void s5h1432_release(struct dvb_frontend *fe) -{ - struct s5h1432_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops s5h1432_ops; - -struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, - struct i2c_adapter *i2c) -{ - struct s5h1432_state *state = NULL; - - printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n"); - /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->current_modulation = QAM_16; - state->inversion = state->config->inversion; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &s5h1432_ops, - sizeof(struct dvb_frontend_ops)); - - state->frontend.demodulator_priv = state; - - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(s5h1432_attach); - -static struct dvb_frontend_ops s5h1432_ops = { - - .info = { - .name = "Samsung s5h1432 DVB-T Frontend", - .type = FE_OFDM, - .frequency_min = 177000000, - .frequency_max = 858000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER}, - - .init = s5h1432_init, - .sleep = s5h1432_sleep, - .set_frontend = s5h1432_set_frontend, - .get_frontend = s5h1432_get_frontend, - .get_tune_settings = s5h1432_get_tune_settings, - .read_status = s5h1432_read_status, - .read_ber = s5h1432_read_ber, - .read_signal_strength = s5h1432_read_signal_strength, - .read_snr = s5h1432_read_snr, - .read_ucblocks = s5h1432_read_ucblocks, - .release = s5h1432_release, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable verbose debug messages"); - -MODULE_DESCRIPTION("Samsung s5h1432 DVB-T Demodulator driver"); -MODULE_AUTHOR("Bill Liu"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1432.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1432.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1432.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s5h1432.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -/* - * Samsung s5h1432 VSB/QAM demodulator driver - * - * Copyright (C) 2009 Bill Liu - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef __S5H1432_H__ -#define __S5H1432_H__ - -#include - -#define S5H1432_I2C_TOP_ADDR (0x02 >> 1) - -#define TAIWAN_HI_IF_FREQ_44_MHZ 44000000 -#define EUROPE_HI_IF_FREQ_36_MHZ 36000000 -#define IF_FREQ_6_MHZ 6000000 -#define IF_FREQ_3point3_MHZ 3300000 -#define IF_FREQ_3point5_MHZ 3500000 -#define IF_FREQ_4_MHZ 4000000 - -struct s5h1432_config { - - /* serial/parallel output */ -#define S5H1432_PARALLEL_OUTPUT 0 -#define S5H1432_SERIAL_OUTPUT 1 - u8 output_mode; - - /* GPIO Setting */ -#define S5H1432_GPIO_OFF 0 -#define S5H1432_GPIO_ON 1 - u8 gpio; - - /* MPEG signal timing */ -#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 - u16 mpeg_timing; - - /* IF Freq for QAM and VSB in KHz */ -#define S5H1432_IF_3250 3250 -#define S5H1432_IF_3500 3500 -#define S5H1432_IF_4000 4000 -#define S5H1432_IF_5380 5380 -#define S5H1432_IF_44000 44000 -#define S5H1432_VSB_IF_DEFAULT s5h1432_IF_44000 -#define S5H1432_QAM_IF_DEFAULT s5h1432_IF_44000 - u16 qam_if; - u16 vsb_if; - - /* Spectral Inversion */ -#define S5H1432_INVERSION_OFF 0 -#define S5H1432_INVERSION_ON 1 - u8 inversion; - - /* Return lock status based on tuner lock, or demod lock */ -#define S5H1432_TUNERLOCKING 0 -#define S5H1432_DEMODLOCKING 1 - u8 status_mode; -}; - -#if defined(CONFIG_DVB_S5H1432) || \ - (defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE)) -extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *s5h1432_attach(const struct s5h1432_config - *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_s5h1432 */ - -#endif /* __s5h1432_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s921.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s921.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s921.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s921.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,548 +0,0 @@ -/* - * Sharp VA3A5JZ921 One Seg Broadcast Module driver - * This device is labeled as just S. 921 at the top of the frontend can - * - * Copyright (C) 2009-2010 Mauro Carvalho Chehab - * Copyright (C) 2009-2010 Douglas Landgraf - * - * Developed for Leadership SBTVD 1seg device sold in Brazil - * - * Frontend module based on cx24123 driver, getting some info from - * the old s921 driver. - * - * FIXME: Need to port to DVB v5.2 API - * - * 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 version 2. - * - * 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. - */ - -#include -#include - -#include "dvb_frontend.h" -#include "s921.h" - -static int debug = 1; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); - -#define rc(args...) do { \ - printk(KERN_ERR "s921: " args); \ -} while (0) - -#define dprintk(args...) \ - do { \ - if (debug) { \ - printk(KERN_DEBUG "s921: %s: ", __func__); \ - printk(args); \ - } \ - } while (0) - -struct s921_state { - struct i2c_adapter *i2c; - const struct s921_config *config; - - struct dvb_frontend frontend; - - /* The Demod can't easily provide these, we cache them */ - u32 currentfreq; -}; - -/* - * Various tuner defaults need to be established for a given frequency kHz. - * fixme: The bounds on the bands do not match the doc in real life. - * fixme: Some of them have been moved, other might need adjustment. - */ -static struct s921_bandselect_val { - u32 freq_low; - u8 band_reg; -} s921_bandselect[] = { - { 0, 0x7b }, - { 485140000, 0x5b }, - { 515140000, 0x3b }, - { 545140000, 0x1b }, - { 599140000, 0xfb }, - { 623140000, 0xdb }, - { 659140000, 0xbb }, - { 713140000, 0x9b }, -}; - -struct regdata { - u8 reg; - u8 data; -}; - -static struct regdata s921_init[] = { - { 0x01, 0x80 }, /* Probably, a reset sequence */ - { 0x01, 0x40 }, - { 0x01, 0x80 }, - { 0x01, 0x40 }, - - { 0x02, 0x00 }, - { 0x03, 0x40 }, - { 0x04, 0x01 }, - { 0x05, 0x00 }, - { 0x06, 0x00 }, - { 0x07, 0x00 }, - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x5a }, - { 0x0c, 0x00 }, - { 0x0d, 0x00 }, - { 0x0f, 0x00 }, - { 0x13, 0x1b }, - { 0x14, 0x80 }, - { 0x15, 0x40 }, - { 0x17, 0x70 }, - { 0x18, 0x01 }, - { 0x19, 0x12 }, - { 0x1a, 0x01 }, - { 0x1b, 0x12 }, - { 0x1c, 0xa0 }, - { 0x1d, 0x00 }, - { 0x1e, 0x0a }, - { 0x1f, 0x08 }, - { 0x20, 0x40 }, - { 0x21, 0xff }, - { 0x22, 0x4c }, - { 0x23, 0x4e }, - { 0x24, 0x4c }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x27, 0xf4 }, - { 0x28, 0x60 }, - { 0x29, 0x88 }, - { 0x2a, 0x40 }, - { 0x2b, 0x40 }, - { 0x2c, 0xff }, - { 0x2d, 0x00 }, - { 0x2e, 0xff }, - { 0x2f, 0x00 }, - { 0x30, 0x20 }, - { 0x31, 0x06 }, - { 0x32, 0x0c }, - { 0x34, 0x0f }, - { 0x37, 0xfe }, - { 0x38, 0x00 }, - { 0x39, 0x63 }, - { 0x3a, 0x10 }, - { 0x3b, 0x10 }, - { 0x47, 0x00 }, - { 0x49, 0xe5 }, - { 0x4b, 0x00 }, - { 0x50, 0xc0 }, - { 0x52, 0x20 }, - { 0x54, 0x5a }, - { 0x55, 0x5b }, - { 0x56, 0x40 }, - { 0x57, 0x70 }, - { 0x5c, 0x50 }, - { 0x5d, 0x00 }, - { 0x62, 0x17 }, - { 0x63, 0x2f }, - { 0x64, 0x6f }, - { 0x68, 0x00 }, - { 0x69, 0x89 }, - { 0x6a, 0x00 }, - { 0x6b, 0x00 }, - { 0x6c, 0x00 }, - { 0x6d, 0x00 }, - { 0x6e, 0x00 }, - { 0x70, 0x10 }, - { 0x71, 0x00 }, - { 0x75, 0x00 }, - { 0x76, 0x30 }, - { 0x77, 0x01 }, - { 0xaf, 0x00 }, - { 0xb0, 0xa0 }, - { 0xb2, 0x3d }, - { 0xb3, 0x25 }, - { 0xb4, 0x8b }, - { 0xb5, 0x4b }, - { 0xb6, 0x3f }, - { 0xb7, 0xff }, - { 0xb8, 0xff }, - { 0xb9, 0xfc }, - { 0xba, 0x00 }, - { 0xbb, 0x00 }, - { 0xbc, 0x00 }, - { 0xd0, 0x30 }, - { 0xe4, 0x84 }, - { 0xf0, 0x48 }, - { 0xf1, 0x19 }, - { 0xf2, 0x5a }, - { 0xf3, 0x8e }, - { 0xf4, 0x2d }, - { 0xf5, 0x07 }, - { 0xf6, 0x5a }, - { 0xf7, 0xba }, - { 0xf8, 0xd7 }, -}; - -static struct regdata s921_prefreq[] = { - { 0x47, 0x60 }, - { 0x68, 0x00 }, - { 0x69, 0x89 }, - { 0xf0, 0x48 }, - { 0xf1, 0x19 }, -}; - -static struct regdata s921_postfreq[] = { - { 0xf5, 0xae }, - { 0xf6, 0xb7 }, - { 0xf7, 0xba }, - { 0xf8, 0xd7 }, - { 0x68, 0x0a }, - { 0x69, 0x09 }, -}; - -static int s921_i2c_writereg(struct s921_state *state, - u8 i2c_addr, int reg, int data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { - .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2 - }; - int rc; - - rc = i2c_transfer(state->i2c, &msg, 1); - if (rc != 1) { - printk("%s: writereg rcor(rc == %i, reg == 0x%02x," - " data == 0x%02x)\n", __func__, rc, reg, data); - return rc; - } - - return 0; -} - -static int s921_i2c_writeregdata(struct s921_state *state, u8 i2c_addr, - struct regdata *rd, int size) -{ - int i, rc; - - for (i = 0; i < size; i++) { - rc = s921_i2c_writereg(state, i2c_addr, rd[i].reg, rd[i].data); - if (rc < 0) - return rc; - } - return 0; -} - -static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg) -{ - u8 val; - int rc; - struct i2c_msg msg[] = { - { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 }, - { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 } - }; - - rc = i2c_transfer(state->i2c, msg, 2); - - if (rc != 2) { - rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc); - return rc; - } - - return val; -} - -#define s921_readreg(state, reg) \ - s921_i2c_readreg(state, state->config->demod_address, reg) -#define s921_writereg(state, reg, val) \ - s921_i2c_writereg(state, state->config->demod_address, reg, val) -#define s921_writeregdata(state, regdata) \ - s921_i2c_writeregdata(state, state->config->demod_address, \ - regdata, ARRAY_SIZE(regdata)) - -static int s921_pll_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct s921_state *state = fe->demodulator_priv; - int band, rc, i; - unsigned long f_offset; - u8 f_switch; - u64 offset; - - dprintk("frequency=%i\n", p->frequency); - - for (band = 0; band < ARRAY_SIZE(s921_bandselect); band++) - if (p->frequency < s921_bandselect[band].freq_low) - break; - band--; - - if (band < 0) { - rc("%s: frequency out of range\n", __func__); - return -EINVAL; - } - - f_switch = s921_bandselect[band].band_reg; - - offset = ((u64)p->frequency) * 258; - do_div(offset, 6000000); - f_offset = ((unsigned long)offset) + 2321; - - rc = s921_writeregdata(state, s921_prefreq); - if (rc < 0) - return rc; - - rc = s921_writereg(state, 0xf2, (f_offset >> 8) & 0xff); - if (rc < 0) - return rc; - - rc = s921_writereg(state, 0xf3, f_offset & 0xff); - if (rc < 0) - return rc; - - rc = s921_writereg(state, 0xf4, f_switch); - if (rc < 0) - return rc; - - rc = s921_writeregdata(state, s921_postfreq); - if (rc < 0) - return rc; - - for (i = 0 ; i < 6; i++) { - rc = s921_readreg(state, 0x80); - dprintk("status 0x80: %02x\n", rc); - } - rc = s921_writereg(state, 0x01, 0x40); - if (rc < 0) - return rc; - - rc = s921_readreg(state, 0x01); - dprintk("status 0x01: %02x\n", rc); - - rc = s921_readreg(state, 0x80); - dprintk("status 0x80: %02x\n", rc); - - rc = s921_readreg(state, 0x80); - dprintk("status 0x80: %02x\n", rc); - - rc = s921_readreg(state, 0x32); - dprintk("status 0x32: %02x\n", rc); - - dprintk("pll tune band=%d, pll=%d\n", f_switch, (int)f_offset); - - return 0; -} - -static int s921_initfe(struct dvb_frontend *fe) -{ - struct s921_state *state = fe->demodulator_priv; - int rc; - - dprintk("\n"); - - rc = s921_writeregdata(state, s921_init); - if (rc < 0) - return rc; - - return 0; -} - -static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct s921_state *state = fe->demodulator_priv; - int regstatus, rc; - - *status = 0; - - rc = s921_readreg(state, 0x81); - if (rc < 0) - return rc; - - regstatus = rc << 8; - - rc = s921_readreg(state, 0x82); - if (rc < 0) - return rc; - - regstatus |= rc; - - dprintk("status = %04x\n", regstatus); - - /* Full Sync - We don't know what each bit means on regs 0x81/0x82 */ - if ((regstatus & 0xff) == 0x40) { - *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_LOCK; - } else if (regstatus & 0x40) { - /* This is close to Full Sync, but not enough to get useful info */ - *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_VITERBI | - FE_HAS_SYNC; - } - - return 0; -} - -static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - fe_status_t status; - struct s921_state *state = fe->demodulator_priv; - int rc; - - /* FIXME: Use the proper register for it... 0x80? */ - rc = s921_read_status(fe, &status); - if (rc < 0) - return rc; - - *strength = (status & FE_HAS_LOCK) ? 0xffff : 0; - - dprintk("strength = 0x%04x\n", *strength); - - rc = s921_readreg(state, 0x01); - dprintk("status 0x01: %02x\n", rc); - - rc = s921_readreg(state, 0x80); - dprintk("status 0x80: %02x\n", rc); - - rc = s921_readreg(state, 0x32); - dprintk("status 0x32: %02x\n", rc); - - return 0; -} - -static int s921_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct s921_state *state = fe->demodulator_priv; - int rc; - - dprintk("\n"); - - /* FIXME: We don't know how to use non-auto mode */ - - rc = s921_pll_tune(fe, p); - if (rc < 0) - return rc; - - state->currentfreq = p->frequency; - - return 0; -} - -static int s921_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct s921_state *state = fe->demodulator_priv; - - /* FIXME: Probably it is possible to get it from regs f1 and f2 */ - p->frequency = state->currentfreq; - - return 0; -} - -static int s921_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, - unsigned int mode_flags, - unsigned int *delay, - fe_status_t *status) -{ - int rc = 0; - - dprintk("\n"); - - if (params != NULL) - rc = s921_set_frontend(fe, params); - - if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) - s921_read_status(fe, status); - - return rc; -} - -static int s921_get_algo(struct dvb_frontend *fe) -{ - return 1; /* FE_ALGO_HW */ -} - -static void s921_release(struct dvb_frontend *fe) -{ - struct s921_state *state = fe->demodulator_priv; - - dprintk("\n"); - kfree(state); -} - -static struct dvb_frontend_ops s921_ops; - -struct dvb_frontend *s921_attach(const struct s921_config *config, - struct i2c_adapter *i2c) -{ - /* allocate memory for the internal state */ - struct s921_state *state = - kzalloc(sizeof(struct s921_state), GFP_KERNEL); - - dprintk("\n"); - if (state == NULL) { - rc("Unable to kzalloc\n"); - goto rcor; - } - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &s921_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - return &state->frontend; - -rcor: - kfree(state); - - return NULL; -} -EXPORT_SYMBOL(s921_attach); - -static struct dvb_frontend_ops s921_ops = { - /* Use dib8000 values per default */ - .info = { - .name = "Sharp S921", - .type = FE_OFDM, - .frequency_min = 470000000, - /* - * Max should be 770MHz instead, according with Sharp docs, - * but Leadership doc says it works up to 806 MHz. This is - * required to get channel 69, used in Brazil - */ - .frequency_max = 806000000, - .frequency_tolerance = 0, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = s921_release, - - .init = s921_initfe, - .set_frontend = s921_set_frontend, - .get_frontend = s921_get_frontend, - .read_status = s921_read_status, - .read_signal_strength = s921_read_signal_strength, - .tune = s921_tune, - .get_frontend_algo = s921_get_algo, -}; - -MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_AUTHOR("Douglas Landgraf "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s921.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s921.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s921.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/s921.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * Sharp s921 driver - * - * Copyright (C) 2009 Mauro Carvalho Chehab - * Copyright (C) 2009 Douglas Landgraf - * - * 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 version 2. - * - * 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. - */ - -#ifndef S921_H -#define S921_H - -#include - -struct s921_config { - /* the demodulator's i2c address */ - u8 demod_address; -}; - -#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) \ - && defined(MODULE)) -extern struct dvb_frontend *s921_attach(const struct s921_config *config, - struct i2c_adapter *i2c); -extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *); -#else -static inline struct dvb_frontend *s921_attach( - const struct s921_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static struct i2c_adapter * - s921_get_tuner_i2c_adapter(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* S921_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/si21xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/si21xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/si21xx.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/si21xx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,967 +0,0 @@ -/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator -* -* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) -* -* 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, or -* (at your option) any later version. -* -*/ -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "si21xx.h" - -#define REVISION_REG 0x00 -#define SYSTEM_MODE_REG 0x01 -#define TS_CTRL_REG_1 0x02 -#define TS_CTRL_REG_2 0x03 -#define PIN_CTRL_REG_1 0x04 -#define PIN_CTRL_REG_2 0x05 -#define LOCK_STATUS_REG_1 0x0f -#define LOCK_STATUS_REG_2 0x10 -#define ACQ_STATUS_REG 0x11 -#define ACQ_CTRL_REG_1 0x13 -#define ACQ_CTRL_REG_2 0x14 -#define PLL_DIVISOR_REG 0x15 -#define COARSE_TUNE_REG 0x16 -#define FINE_TUNE_REG_L 0x17 -#define FINE_TUNE_REG_H 0x18 - -#define ANALOG_AGC_POWER_LEVEL_REG 0x28 -#define CFO_ESTIMATOR_CTRL_REG_1 0x29 -#define CFO_ESTIMATOR_CTRL_REG_2 0x2a -#define CFO_ESTIMATOR_CTRL_REG_3 0x2b - -#define SYM_RATE_ESTIMATE_REG_L 0x31 -#define SYM_RATE_ESTIMATE_REG_M 0x32 -#define SYM_RATE_ESTIMATE_REG_H 0x33 - -#define CFO_ESTIMATOR_OFFSET_REG_L 0x36 -#define CFO_ESTIMATOR_OFFSET_REG_H 0x37 -#define CFO_ERROR_REG_L 0x38 -#define CFO_ERROR_REG_H 0x39 -#define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a - -#define SYM_RATE_REG_L 0x3f -#define SYM_RATE_REG_M 0x40 -#define SYM_RATE_REG_H 0x41 -#define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42 -#define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43 - -#define C_N_ESTIMATOR_CTRL_REG 0x7c -#define C_N_ESTIMATOR_THRSHLD_REG 0x7d -#define C_N_ESTIMATOR_LEVEL_REG_L 0x7e -#define C_N_ESTIMATOR_LEVEL_REG_H 0x7f - -#define BLIND_SCAN_CTRL_REG 0x80 - -#define LSA_CTRL_REG_1 0x8D -#define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f -#define ONE_DB_BNDWDTH_THRSHLD_REG 0x90 -#define TWO_DB_BNDWDTH_THRSHLD_REG 0x91 -#define THREE_DB_BNDWDTH_THRSHLD_REG 0x92 -#define INBAND_POWER_THRSHLD_REG 0x93 -#define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94 - -#define VIT_SRCH_CTRL_REG_1 0xa0 -#define VIT_SRCH_CTRL_REG_2 0xa1 -#define VIT_SRCH_CTRL_REG_3 0xa2 -#define VIT_SRCH_STATUS_REG 0xa3 -#define VITERBI_BER_COUNT_REG_L 0xab -#define REED_SOLOMON_CTRL_REG 0xb0 -#define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1 -#define PRBS_CTRL_REG 0xb5 - -#define LNB_CTRL_REG_1 0xc0 -#define LNB_CTRL_REG_2 0xc1 -#define LNB_CTRL_REG_3 0xc2 -#define LNB_CTRL_REG_4 0xc3 -#define LNB_CTRL_STATUS_REG 0xc4 -#define LNB_FIFO_REGS_0 0xc5 -#define LNB_FIFO_REGS_1 0xc6 -#define LNB_FIFO_REGS_2 0xc7 -#define LNB_FIFO_REGS_3 0xc8 -#define LNB_FIFO_REGS_4 0xc9 -#define LNB_FIFO_REGS_5 0xca -#define LNB_SUPPLY_CTRL_REG_1 0xcb -#define LNB_SUPPLY_CTRL_REG_2 0xcc -#define LNB_SUPPLY_CTRL_REG_3 0xcd -#define LNB_SUPPLY_CTRL_REG_4 0xce -#define LNB_SUPPLY_STATUS_REG 0xcf - -#define FAIL -1 -#define PASS 0 - -#define ALLOWABLE_FS_COUNT 10 -#define STATUS_BER 0 -#define STATUS_UCBLOCKS 1 - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "si21xx: " args); \ - } while (0) - -enum { - ACTIVE_HIGH, - ACTIVE_LOW -}; -enum { - BYTE_WIDE, - BIT_WIDE -}; -enum { - CLK_GAPPED_MODE, - CLK_CONTINUOUS_MODE -}; -enum { - RISING_EDGE, - FALLING_EDGE -}; -enum { - MSB_FIRST, - LSB_FIRST -}; -enum { - SERIAL, - PARALLEL -}; - -struct si21xx_state { - struct i2c_adapter *i2c; - const struct si21xx_config *config; - struct dvb_frontend frontend; - u8 initialised:1; - int errmode; - int fs; /*Sampling rate of the ADC in MHz*/ -}; - -/* register default initialization */ -static u8 serit_sp1511lhb_inittab[] = { - 0x01, 0x28, /* set i2c_inc_disable */ - 0x20, 0x03, - 0x27, 0x20, - 0xe0, 0x45, - 0xe1, 0x08, - 0xfe, 0x01, - 0x01, 0x28, - 0x89, 0x09, - 0x04, 0x80, - 0x05, 0x01, - 0x06, 0x00, - 0x20, 0x03, - 0x24, 0x88, - 0x29, 0x09, - 0x2a, 0x0f, - 0x2c, 0x10, - 0x2d, 0x19, - 0x2e, 0x08, - 0x2f, 0x10, - 0x30, 0x19, - 0x34, 0x20, - 0x35, 0x03, - 0x45, 0x02, - 0x46, 0x45, - 0x47, 0xd0, - 0x48, 0x00, - 0x49, 0x40, - 0x4a, 0x03, - 0x4c, 0xfd, - 0x4f, 0x2e, - 0x50, 0x2e, - 0x51, 0x10, - 0x52, 0x10, - 0x56, 0x92, - 0x59, 0x00, - 0x5a, 0x2d, - 0x5b, 0x33, - 0x5c, 0x1f, - 0x5f, 0x76, - 0x62, 0xc0, - 0x63, 0xc0, - 0x64, 0xf3, - 0x65, 0xf3, - 0x79, 0x40, - 0x6a, 0x40, - 0x6b, 0x0a, - 0x6c, 0x80, - 0x6d, 0x27, - 0x71, 0x06, - 0x75, 0x60, - 0x78, 0x00, - 0x79, 0xb5, - 0x7c, 0x05, - 0x7d, 0x1a, - 0x87, 0x55, - 0x88, 0x72, - 0x8f, 0x08, - 0x90, 0xe0, - 0x94, 0x40, - 0xa0, 0x3f, - 0xa1, 0xc0, - 0xa4, 0xcc, - 0xa5, 0x66, - 0xa6, 0x66, - 0xa7, 0x7b, - 0xa8, 0x7b, - 0xa9, 0x7b, - 0xaa, 0x9a, - 0xed, 0x04, - 0xad, 0x00, - 0xae, 0x03, - 0xcc, 0xab, - 0x01, 0x08, - 0xff, 0xff -}; - -/* low level read/writes */ -static int si21_writeregs(struct si21xx_state *state, u8 reg1, - u8 *data, int len) -{ - int ret; - u8 buf[60];/* = { reg1, data };*/ - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf, - .len = len + 1 - }; - - msg.buf[0] = reg1; - memcpy(msg.buf + 1, data, len); - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, " - "ret == %i)\n", __func__, reg1, data[0], ret); - - return (ret != 1) ? -EREMOTEIO : 0; -} - -static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data) -{ - int ret; - u8 buf[] = { reg, data }; - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf, - .len = 2 - }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, " - "ret == %i)\n", __func__, reg, data, ret); - - return (ret != 1) ? -EREMOTEIO : 0; -} - -static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len) -{ - struct si21xx_state *state = fe->demodulator_priv; - - if (len != 2) - return -EINVAL; - - return si21_writereg(state, buf[0], buf[1]); -} - -static u8 si21_readreg(struct si21xx_state *state, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { - .addr = state->config->demod_address, - .flags = 0, - .buf = b0, - .len = 1 - }, { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = b1, - .len = 1 - } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", - __func__, reg, ret); - - return b1[0]; -} - -static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len) -{ - int ret; - struct i2c_msg msg[] = { - { - .addr = state->config->demod_address, - .flags = 0, - .buf = ®1, - .len = 1 - }, { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = b, - .len = len - } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - dprintk("%s: readreg error (ret == %i)\n", __func__, ret); - - return ret == 2 ? 0 : -1; -} - -static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) -{ - unsigned long start = jiffies; - - dprintk("%s\n", __func__); - - while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) { - if (jiffies - start > timeout) { - dprintk("%s: timeout!!\n", __func__); - return -ETIMEDOUT; - } - msleep(10); - }; - - return 0; -} - -static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate) -{ - struct si21xx_state *state = fe->demodulator_priv; - u32 sym_rate, data_rate; - int i; - u8 sym_rate_bytes[3]; - - dprintk("%s : srate = %i\n", __func__ , srate); - - if ((srate < 1000000) || (srate > 45000000)) - return -EINVAL; - - data_rate = srate; - sym_rate = 0; - - for (i = 0; i < 4; ++i) { - sym_rate /= 100; - sym_rate = sym_rate + ((data_rate % 100) * 0x800000) / - state->fs; - data_rate /= 100; - } - for (i = 0; i < 3; ++i) - sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff); - - si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03); - - return 0; -} - -static int si21xx_send_diseqc_msg(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *m) -{ - struct si21xx_state *state = fe->demodulator_priv; - u8 lnb_status; - u8 LNB_CTRL_1; - int status; - - dprintk("%s\n", __func__); - - status = PASS; - LNB_CTRL_1 = 0; - - status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01); - status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01); - - /*fill the FIFO*/ - status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len); - - LNB_CTRL_1 = (lnb_status & 0x70); - LNB_CTRL_1 |= m->msg_len; - - LNB_CTRL_1 |= 0x80; /* begin LNB signaling */ - - status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01); - - return status; -} - -static int si21xx_send_diseqc_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) -{ - struct si21xx_state *state = fe->demodulator_priv; - u8 val; - - dprintk("%s\n", __func__); - - if (si21xx_wait_diseqc_idle(state, 100) < 0) - return -ETIMEDOUT; - - val = (0x80 | si21_readreg(state, 0xc1)); - if (si21_writereg(state, LNB_CTRL_REG_1, - burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10))) - return -EREMOTEIO; - - if (si21xx_wait_diseqc_idle(state, 100) < 0) - return -ETIMEDOUT; - - if (si21_writereg(state, LNB_CTRL_REG_1, val)) - return -EREMOTEIO; - - return 0; -} -/* 30.06.2008 */ -static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct si21xx_state *state = fe->demodulator_priv; - u8 val; - - dprintk("%s\n", __func__); - val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); - - switch (tone) { - case SEC_TONE_ON: - return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20); - - case SEC_TONE_OFF: - return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20)); - - default: - return -EINVAL; - } -} - -static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) -{ - struct si21xx_state *state = fe->demodulator_priv; - - u8 val; - dprintk("%s: %s\n", __func__, - volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : - volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); - - - val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); - - switch (volt) { - case SEC_VOLTAGE_18: - return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40); - break; - case SEC_VOLTAGE_13: - return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40)); - break; - default: - return -EINVAL; - }; -} - -static int si21xx_init(struct dvb_frontend *fe) -{ - struct si21xx_state *state = fe->demodulator_priv; - int i; - int status = 0; - u8 reg1; - u8 val; - u8 reg2[2]; - - dprintk("%s\n", __func__); - - for (i = 0; ; i += 2) { - reg1 = serit_sp1511lhb_inittab[i]; - val = serit_sp1511lhb_inittab[i+1]; - if (reg1 == 0xff && val == 0xff) - break; - si21_writeregs(state, reg1, &val, 1); - } - - /*DVB QPSK SYSTEM MODE REG*/ - reg1 = 0x08; - si21_writeregs(state, SYSTEM_MODE_REG, ®1, 0x01); - - /*transport stream config*/ - /* - mode = PARALLEL; - sdata_form = LSB_FIRST; - clk_edge = FALLING_EDGE; - clk_mode = CLK_GAPPED_MODE; - strt_len = BYTE_WIDE; - sync_pol = ACTIVE_HIGH; - val_pol = ACTIVE_HIGH; - err_pol = ACTIVE_HIGH; - sclk_rate = 0x00; - parity = 0x00 ; - data_delay = 0x00; - clk_delay = 0x00; - pclk_smooth = 0x00; - */ - reg2[0] = - PARALLEL + (LSB_FIRST << 1) - + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3) - + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5) - + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7); - - reg2[1] = 0; - /* sclk_rate + (parity << 2) - + (data_delay << 3) + (clk_delay << 4) - + (pclk_smooth << 5); - */ - status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02); - if (status != 0) - dprintk(" %s : TS Set Error\n", __func__); - - return 0; - -} - -static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct si21xx_state *state = fe->demodulator_priv; - u8 regs_read[2]; - u8 reg_read; - u8 i; - u8 lock; - u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG); - - si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02); - reg_read = 0; - - for (i = 0; i < 7; ++i) - reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i); - - lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80)); - - dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock); - *status = 0; - - if (signal > 10) - *status |= FE_HAS_SIGNAL; - - if (lock & 0x2) - *status |= FE_HAS_CARRIER; - - if (lock & 0x20) - *status |= FE_HAS_VITERBI; - - if (lock & 0x40) - *status |= FE_HAS_SYNC; - - if ((lock & 0x7b) == 0x7b) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct si21xx_state *state = fe->demodulator_priv; - - /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG, - (u8*)agclevel, 0x01);*/ - - u16 signal = (3 * si21_readreg(state, 0x27) * - si21_readreg(state, 0x28)); - - dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__, - si21_readreg(state, 0x27), - si21_readreg(state, 0x28), (int) signal); - - signal <<= 4; - *strength = signal; - - return 0; -} - -static int si21_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct si21xx_state *state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - if (state->errmode != STATUS_BER) - return 0; - - *ber = (si21_readreg(state, 0x1d) << 8) | - si21_readreg(state, 0x1e); - - return 0; -} - -static int si21_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct si21xx_state *state = fe->demodulator_priv; - - s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) | - si21_readreg(state, 0x25)); - xsnr = 3 * (xsnr - 0xa100); - *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; - - dprintk("%s\n", __func__); - - return 0; -} - -static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct si21xx_state *state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - if (state->errmode != STATUS_UCBLOCKS) - *ucblocks = 0; - else - *ucblocks = (si21_readreg(state, 0x1d) << 8) | - si21_readreg(state, 0x1e); - - return 0; -} - -/* initiates a channel acquisition sequence - using the specified symbol rate and code rate */ -static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, - fe_code_rate_t crate) -{ - - struct si21xx_state *state = fe->demodulator_priv; - u8 coderates[] = { - 0x0, 0x01, 0x02, 0x04, 0x00, - 0x8, 0x10, 0x20, 0x00, 0x3f - }; - - u8 coderate_ptr; - int status; - u8 start_acq = 0x80; - u8 reg, regs[3]; - - dprintk("%s\n", __func__); - - status = PASS; - coderate_ptr = coderates[crate]; - - si21xx_set_symbolrate(fe, symbrate); - - /* write code rates to use in the Viterbi search */ - status |= si21_writeregs(state, - VIT_SRCH_CTRL_REG_1, - &coderate_ptr, 0x01); - - /* clear acq_start bit */ - status |= si21_readregs(state, ACQ_CTRL_REG_2, ®, 0x01); - reg &= ~start_acq; - status |= si21_writeregs(state, ACQ_CTRL_REG_2, ®, 0x01); - - /* use new Carrier Frequency Offset Estimator (QuickLock) */ - regs[0] = 0xCB; - regs[1] = 0x40; - regs[2] = 0xCB; - - status |= si21_writeregs(state, - TWO_DB_BNDWDTH_THRSHLD_REG, - ®s[0], 0x03); - reg = 0x56; - status |= si21_writeregs(state, - LSA_CTRL_REG_1, ®, 1); - reg = 0x05; - status |= si21_writeregs(state, - BLIND_SCAN_CTRL_REG, ®, 1); - /* start automatic acq */ - status |= si21_writeregs(state, - ACQ_CTRL_REG_2, &start_acq, 0x01); - - return status; -} - -static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int si21xx_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *dfp) -{ - struct si21xx_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - /* freq Channel carrier frequency in KHz (i.e. 1550000 KHz) - datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/ - - /* in MHz */ - unsigned char coarse_tune_freq; - int fine_tune_freq; - unsigned char sample_rate = 0; - /* boolean */ - bool inband_interferer_ind; - - /* INTERMEDIATE VALUES */ - int icoarse_tune_freq; /* MHz */ - int ifine_tune_freq; /* MHz */ - unsigned int band_high; - unsigned int band_low; - unsigned int x1; - unsigned int x2; - int i; - bool inband_interferer_div2[ALLOWABLE_FS_COUNT]; - bool inband_interferer_div4[ALLOWABLE_FS_COUNT]; - int status; - - /* allowable sample rates for ADC in MHz */ - int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195, - 196, 204, 205, 206, 207 - }; - /* in MHz */ - int if_limit_high; - int if_limit_low; - int lnb_lo; - int lnb_uncertanity; - - int rf_freq; - int data_rate; - unsigned char regs[4]; - - dprintk("%s : FE_SET_FRONTEND\n", __func__); - - if (c->delivery_system != SYS_DVBS) { - dprintk("%s: unsupported delivery system selected (%d)\n", - __func__, c->delivery_system); - return -EOPNOTSUPP; - } - - for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) - inband_interferer_div2[i] = inband_interferer_div4[i] = false; - - if_limit_high = -700000; - if_limit_low = -100000; - /* in MHz */ - lnb_lo = 0; - lnb_uncertanity = 0; - - rf_freq = 10 * c->frequency ; - data_rate = c->symbol_rate / 100; - - status = PASS; - - band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200) - + (data_rate * 135)) / 200; - - band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200) - + (data_rate * 135)) / 200; - - - icoarse_tune_freq = 100000 * - (((rf_freq - lnb_lo) - - (if_limit_low + if_limit_high) / 2) - / 100000); - - ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ; - - for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { - x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * - (afs[i] * 2500) + afs[i] * 2500; - - x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * - (afs[i] * 2500); - - if (((band_low < x1) && (x1 < band_high)) || - ((band_low < x2) && (x2 < band_high))) - inband_interferer_div4[i] = true; - - } - - for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { - x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * - (afs[i] * 5000) + afs[i] * 5000; - - x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * - (afs[i] * 5000); - - if (((band_low < x1) && (x1 < band_high)) || - ((band_low < x2) && (x2 < band_high))) - inband_interferer_div2[i] = true; - } - - inband_interferer_ind = true; - for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { - if (inband_interferer_div2[i] || inband_interferer_div4[i]) { - inband_interferer_ind = false; - break; - } - } - - if (inband_interferer_ind) { - for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { - if (!inband_interferer_div2[i]) { - sample_rate = (u8) afs[i]; - break; - } - } - } else { - for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { - if ((inband_interferer_div2[i] || - !inband_interferer_div4[i])) { - sample_rate = (u8) afs[i]; - break; - } - } - - } - - if (sample_rate > 207 || sample_rate < 192) - sample_rate = 200; - - fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) / - ((sample_rate) * 1000)); - - coarse_tune_freq = (u8)(icoarse_tune_freq / 100000); - - regs[0] = sample_rate; - regs[1] = coarse_tune_freq; - regs[2] = fine_tune_freq & 0xFF; - regs[3] = fine_tune_freq >> 8 & 0xFF; - - status |= si21_writeregs(state, PLL_DIVISOR_REG, ®s[0], 0x04); - - state->fs = sample_rate;/*ADC MHz*/ - si21xx_setacquire(fe, c->symbol_rate, c->fec_inner); - - return 0; -} - -static int si21xx_sleep(struct dvb_frontend *fe) -{ - struct si21xx_state *state = fe->demodulator_priv; - u8 regdata; - - dprintk("%s\n", __func__); - - si21_readregs(state, SYSTEM_MODE_REG, ®data, 0x01); - regdata |= 1 << 6; - si21_writeregs(state, SYSTEM_MODE_REG, ®data, 0x01); - state->initialised = 0; - - return 0; -} - -static void si21xx_release(struct dvb_frontend *fe) -{ - struct si21xx_state *state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - kfree(state); -} - -static struct dvb_frontend_ops si21xx_ops = { - - .info = { - .name = "SL SI21XX DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, /* kHz for QPSK frontends */ - .frequency_tolerance = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, /* ppm */ - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_QPSK | - FE_CAN_FEC_AUTO - }, - - .release = si21xx_release, - .init = si21xx_init, - .sleep = si21xx_sleep, - .write = si21_write, - .read_status = si21_read_status, - .read_ber = si21_read_ber, - .read_signal_strength = si21_read_signal_strength, - .read_snr = si21_read_snr, - .read_ucblocks = si21_read_ucblocks, - .diseqc_send_master_cmd = si21xx_send_diseqc_msg, - .diseqc_send_burst = si21xx_send_diseqc_burst, - .set_tone = si21xx_set_tone, - .set_voltage = si21xx_set_voltage, - - .set_property = si21xx_set_property, - .get_property = si21xx_get_property, - .set_frontend = si21xx_set_frontend, -}; - -struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, - struct i2c_adapter *i2c) -{ - struct si21xx_state *state = NULL; - int id; - - dprintk("%s\n", __func__); - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->initialised = 0; - state->errmode = STATUS_BER; - - /* check if the demod is there */ - id = si21_readreg(state, SYSTEM_MODE_REG); - si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */ - msleep(200); - id = si21_readreg(state, 0x00); - - /* register 0x00 contains: - 0x34 for SI2107 - 0x24 for SI2108 - 0x14 for SI2109 - 0x04 for SI2110 - */ - if (id != 0x04 && id != 0x14) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &si21xx_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(si21xx_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver"); -MODULE_AUTHOR("Igor M. Liplianin"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/si21xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/si21xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/si21xx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/si21xx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -#ifndef SI21XX_H -#define SI21XX_H - -#include -#include "dvb_frontend.h" - -struct si21xx_config { - /* the demodulator's i2c address */ - u8 demod_address; - - /* minimum delay before retuning */ - int min_delay_ms; -}; - -#if defined(CONFIG_DVB_SI21XX) || \ - (defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE)) -extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *si21xx_attach( - const struct si21xx_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val) -{ - int r = 0; - u8 buf[] = {reg, val}; - if (fe->ops.write) - r = fe->ops.write(fe, buf, 2); - return r; -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp8870.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp8870.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp8870.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp8870.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,619 +0,0 @@ -/* - Driver for Spase SP8870 demodulator - - Copyright (C) 1999 Juergen Peitz - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* - * This driver needs external firmware. Please use the command - * "/Documentation/dvb/get_dvb_firmware alps_tdlb7" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware - * or /lib/firmware (depending on configuration of firmware hotplug). - */ -#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw" - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "sp8870.h" - - -struct sp8870_state { - - struct i2c_adapter* i2c; - - const struct sp8870_config* config; - - struct dvb_frontend frontend; - - /* demodulator private data */ - u8 initialised:1; -}; - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "sp8870: " args); \ - } while (0) - -/* firmware size for sp8870 */ -#define SP8870_FIRMWARE_SIZE 16382 - -/* starting point for firmware in file 'Sc_main.mc' */ -#define SP8870_FIRMWARE_OFFSET 0x0A - -static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data) -{ - u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 }; - int err; - - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data); - return -EREMOTEIO; - } - - return 0; -} - -static int sp8870_readreg (struct sp8870_state* state, u16 reg) -{ - int ret; - u8 b0 [] = { reg >> 8 , reg & 0xff }; - u8 b1 [] = { 0, 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; - - ret = i2c_transfer (state->i2c, msg, 2); - - if (ret != 2) { - dprintk("%s: readreg error (ret == %i)\n", __func__, ret); - return -1; - } - - return (b1[0] << 8 | b1[1]); -} - -static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw) -{ - struct i2c_msg msg; - const char *fw_buf = fw->data; - int fw_pos; - u8 tx_buf[255]; - int tx_len; - int err = 0; - - dprintk ("%s: ...\n", __func__); - - if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET) - return -EINVAL; - - // system controller stop - sp8870_writereg(state, 0x0F00, 0x0000); - - // instruction RAM register hiword - sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF)); - - // instruction RAM MWR - sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16)); - - // do firmware upload - fw_pos = SP8870_FIRMWARE_OFFSET; - while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){ - tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos; - // write register 0xCF0A - tx_buf[0] = 0xCF; - tx_buf[1] = 0x0A; - memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len); - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.buf = tx_buf; - msg.len = tx_len + 2; - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - printk("%s: firmware upload failed!\n", __func__); - printk ("%s: i2c error (err == %i)\n", __func__, err); - return err; - } - fw_pos += tx_len; - } - - dprintk ("%s: done!\n", __func__); - return 0; -}; - -static void sp8870_microcontroller_stop (struct sp8870_state* state) -{ - sp8870_writereg(state, 0x0F08, 0x000); - sp8870_writereg(state, 0x0F09, 0x000); - - // microcontroller STOP - sp8870_writereg(state, 0x0F00, 0x000); -} - -static void sp8870_microcontroller_start (struct sp8870_state* state) -{ - sp8870_writereg(state, 0x0F08, 0x000); - sp8870_writereg(state, 0x0F09, 0x000); - - // microcontroller START - sp8870_writereg(state, 0x0F00, 0x001); - // not documented but if we don't read 0x0D01 out here - // we don't get a correct data valid signal - sp8870_readreg(state, 0x0D01); -} - -static int sp8870_read_data_valid_signal(struct sp8870_state* state) -{ - return (sp8870_readreg(state, 0x0D02) > 0); -} - -static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) -{ - int known_parameters = 1; - - *reg0xc05 = 0x000; - - switch (p->u.ofdm.constellation) { - case QPSK: - break; - case QAM_16: - *reg0xc05 |= (1 << 10); - break; - case QAM_64: - *reg0xc05 |= (2 << 10); - break; - case QAM_AUTO: - known_parameters = 0; - break; - default: - return -EINVAL; - }; - - switch (p->u.ofdm.hierarchy_information) { - case HIERARCHY_NONE: - break; - case HIERARCHY_1: - *reg0xc05 |= (1 << 7); - break; - case HIERARCHY_2: - *reg0xc05 |= (2 << 7); - break; - case HIERARCHY_4: - *reg0xc05 |= (3 << 7); - break; - case HIERARCHY_AUTO: - known_parameters = 0; - break; - default: - return -EINVAL; - }; - - switch (p->u.ofdm.code_rate_HP) { - case FEC_1_2: - break; - case FEC_2_3: - *reg0xc05 |= (1 << 3); - break; - case FEC_3_4: - *reg0xc05 |= (2 << 3); - break; - case FEC_5_6: - *reg0xc05 |= (3 << 3); - break; - case FEC_7_8: - *reg0xc05 |= (4 << 3); - break; - case FEC_AUTO: - known_parameters = 0; - break; - default: - return -EINVAL; - }; - - if (known_parameters) - *reg0xc05 |= (2 << 1); /* use specified parameters */ - else - *reg0xc05 |= (1 << 1); /* enable autoprobing */ - - return 0; -} - -static int sp8870_wake_up(struct sp8870_state* state) -{ - // enable TS output and interface pins - return sp8870_writereg(state, 0xC18, 0x00D); -} - -static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) -{ - struct sp8870_state* state = fe->demodulator_priv; - int err; - u16 reg0xc05; - - if ((err = configure_reg0xc05(p, ®0xc05))) - return err; - - // system controller stop - sp8870_microcontroller_stop(state); - - // set tuner parameters - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - // sample rate correction bit [23..17] - sp8870_writereg(state, 0x0319, 0x000A); - - // sample rate correction bit [16..0] - sp8870_writereg(state, 0x031A, 0x0AAB); - - // integer carrier offset - sp8870_writereg(state, 0x0309, 0x0400); - - // fractional carrier offset - sp8870_writereg(state, 0x030A, 0x0000); - - // filter for 6/7/8 Mhz channel - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) - sp8870_writereg(state, 0x0311, 0x0002); - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) - sp8870_writereg(state, 0x0311, 0x0001); - else - sp8870_writereg(state, 0x0311, 0x0000); - - // scan order: 2k first = 0x0000, 8k first = 0x0001 - if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) - sp8870_writereg(state, 0x0338, 0x0000); - else - sp8870_writereg(state, 0x0338, 0x0001); - - sp8870_writereg(state, 0xc05, reg0xc05); - - // read status reg in order to clear pending irqs - sp8870_readreg(state, 0x200); - - // system controller start - sp8870_microcontroller_start(state); - - return 0; -} - -static int sp8870_init (struct dvb_frontend* fe) -{ - struct sp8870_state* state = fe->demodulator_priv; - const struct firmware *fw = NULL; - - sp8870_wake_up(state); - if (state->initialised) return 0; - state->initialised = 1; - - dprintk ("%s\n", __func__); - - - /* request the firmware, this will block until someone uploads it */ - printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE); - if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) { - printk("sp8870: no firmware upload (timeout or file not found?)\n"); - return -EIO; - } - - if (sp8870_firmware_upload(state, fw)) { - printk("sp8870: writing firmware to device failed\n"); - release_firmware(fw); - return -EIO; - } - release_firmware(fw); - printk("sp8870: firmware upload complete\n"); - - /* enable TS output and interface pins */ - sp8870_writereg(state, 0xc18, 0x00d); - - // system controller stop - sp8870_microcontroller_stop(state); - - // ADC mode - sp8870_writereg(state, 0x0301, 0x0003); - - // Reed Solomon parity bytes passed to output - sp8870_writereg(state, 0x0C13, 0x0001); - - // MPEG clock is suppressed if no valid data - sp8870_writereg(state, 0x0C14, 0x0001); - - /* bit 0x010: enable data valid signal */ - sp8870_writereg(state, 0x0D00, 0x010); - sp8870_writereg(state, 0x0D01, 0x000); - - return 0; -} - -static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status) -{ - struct sp8870_state* state = fe->demodulator_priv; - int status; - int signal; - - *fe_status = 0; - - status = sp8870_readreg (state, 0x0200); - if (status < 0) - return -EIO; - - signal = sp8870_readreg (state, 0x0303); - if (signal < 0) - return -EIO; - - if (signal > 0x0F) - *fe_status |= FE_HAS_SIGNAL; - if (status & 0x08) - *fe_status |= FE_HAS_SYNC; - if (status & 0x04) - *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI; - - return 0; -} - -static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber) -{ - struct sp8870_state* state = fe->demodulator_priv; - int ret; - u32 tmp; - - *ber = 0; - - ret = sp8870_readreg(state, 0xC08); - if (ret < 0) - return -EIO; - - tmp = ret & 0x3F; - - ret = sp8870_readreg(state, 0xC07); - if (ret < 0) - return -EIO; - - tmp = ret << 6; - - if (tmp >= 0x3FFF0) - tmp = ~0; - - *ber = tmp; - - return 0; -} - -static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal) -{ - struct sp8870_state* state = fe->demodulator_priv; - int ret; - u16 tmp; - - *signal = 0; - - ret = sp8870_readreg (state, 0x306); - if (ret < 0) - return -EIO; - - tmp = ret << 8; - - ret = sp8870_readreg (state, 0x303); - if (ret < 0) - return -EIO; - - tmp |= ret; - - if (tmp) - *signal = 0xFFFF - tmp; - - return 0; -} - -static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks) -{ - struct sp8870_state* state = fe->demodulator_priv; - int ret; - - *ublocks = 0; - - ret = sp8870_readreg(state, 0xC0C); - if (ret < 0) - return -EIO; - - if (ret == 0xFFFF) - ret = ~0; - - *ublocks = ret; - - return 0; -} - -/* number of trials to recover from lockup */ -#define MAXTRIALS 5 -/* maximum checks for data valid signal */ -#define MAXCHECKS 100 - -/* only for debugging: counter for detected lockups */ -static int lockups; -/* only for debugging: counter for channel switches */ -static int switches; - -static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct sp8870_state* state = fe->demodulator_priv; - - /* - The firmware of the sp8870 sometimes locks up after setting frontend parameters. - We try to detect this by checking the data valid signal. - If it is not set after MAXCHECKS we try to recover the lockup by setting - the frontend parameters again. - */ - - int err = 0; - int valid = 0; - int trials = 0; - int check_count = 0; - - dprintk("%s: frequency = %i\n", __func__, p->frequency); - - for (trials = 1; trials <= MAXTRIALS; trials++) { - - if ((err = sp8870_set_frontend_parameters(fe, p))) - return err; - - for (check_count = 0; check_count < MAXCHECKS; check_count++) { -// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0); - valid = sp8870_read_data_valid_signal(state); - if (valid) { - dprintk("%s: delay = %i usec\n", - __func__, check_count * 10); - break; - } - udelay(10); - } - if (valid) - break; - } - - if (!valid) { - printk("%s: firmware crash!!!!!!\n", __func__); - return -EIO; - } - - if (debug) { - if (valid) { - if (trials > 1) { - printk("%s: firmware lockup!!!\n", __func__); - printk("%s: recovered after %i trial(s))\n", __func__, trials - 1); - lockups++; - } - } - switches++; - printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups); - } - - return 0; -} - -static int sp8870_sleep(struct dvb_frontend* fe) -{ - struct sp8870_state* state = fe->demodulator_priv; - - // tristate TS output and disable interface pins - return sp8870_writereg(state, 0xC18, 0x000); -} - -static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) -{ - fesettings->min_delay_ms = 350; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct sp8870_state* state = fe->demodulator_priv; - - if (enable) { - return sp8870_writereg(state, 0x206, 0x001); - } else { - return sp8870_writereg(state, 0x206, 0x000); - } -} - -static void sp8870_release(struct dvb_frontend* fe) -{ - struct sp8870_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops sp8870_ops; - -struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, - struct i2c_adapter* i2c) -{ - struct sp8870_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->initialised = 0; - - /* check if the demod is there */ - if (sp8870_readreg(state, 0x0200) < 0) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops sp8870_ops = { - - .info = { - .name = "Spase SP8870 DVB-T", - .type = FE_OFDM, - .frequency_min = 470000000, - .frequency_max = 860000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | - FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER - }, - - .release = sp8870_release, - - .init = sp8870_init, - .sleep = sp8870_sleep, - .i2c_gate_ctrl = sp8870_i2c_gate_ctrl, - - .set_frontend = sp8870_set_frontend, - .get_tune_settings = sp8870_get_tune_settings, - - .read_status = sp8870_read_status, - .read_ber = sp8870_read_ber, - .read_signal_strength = sp8870_read_signal_strength, - .read_ucblocks = sp8870_read_uncorrected_blocks, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver"); -MODULE_AUTHOR("Juergen Peitz"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(sp8870_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp8870.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp8870.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp8870.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp8870.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - Driver for Spase SP8870 demodulator - - Copyright (C) 1999 Juergen Peitz - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef SP8870_H -#define SP8870_H - -#include -#include - -struct sp8870_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* request firmware for device */ - int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); -}; - -#if defined(CONFIG_DVB_SP8870) || (defined(CONFIG_DVB_SP8870_MODULE) && defined(MODULE)) -extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_SP8870 - -#endif // SP8870_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp887x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp887x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp887x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp887x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,617 +0,0 @@ -/* - Driver for the Spase sp887x demodulator -*/ - -/* - * This driver needs external firmware. Please use the command - * "/Documentation/dvb/get_dvb_firmware sp887x" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware - * or /lib/firmware (depending on configuration of firmware hotplug). - */ -#define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw" - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "sp887x.h" - - -struct sp887x_state { - struct i2c_adapter* i2c; - const struct sp887x_config* config; - struct dvb_frontend frontend; - - /* demodulator private data */ - u8 initialised:1; -}; - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "sp887x: " args); \ - } while (0) - -static int i2c_writebytes (struct sp887x_state* state, u8 *buf, u8 len) -{ - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = len }; - int err; - - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - printk ("%s: i2c write error (addr %02x, err == %i)\n", - __func__, state->config->demod_address, err); - return -EREMOTEIO; - } - - return 0; -} - -static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data) -{ - u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 4 }; - int ret; - - if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) { - /** - * in case of soft reset we ignore ACK errors... - */ - if (!(reg == 0xf1a && data == 0x000 && - (ret == -EREMOTEIO || ret == -EFAULT))) - { - printk("%s: writereg error " - "(reg %03x, data %03x, ret == %i)\n", - __func__, reg & 0xffff, data & 0xffff, ret); - return ret; - } - } - - return 0; -} - -static int sp887x_readreg (struct sp887x_state* state, u16 reg) -{ - u8 b0 [] = { reg >> 8 , reg & 0xff }; - u8 b1 [2]; - int ret; - struct i2c_msg msg[] = {{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 }}; - - if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { - printk("%s: readreg error (ret == %i)\n", __func__, ret); - return -1; - } - - return (((b1[0] << 8) | b1[1]) & 0xfff); -} - -static void sp887x_microcontroller_stop (struct sp887x_state* state) -{ - dprintk("%s\n", __func__); - sp887x_writereg(state, 0xf08, 0x000); - sp887x_writereg(state, 0xf09, 0x000); - - /* microcontroller STOP */ - sp887x_writereg(state, 0xf00, 0x000); -} - -static void sp887x_microcontroller_start (struct sp887x_state* state) -{ - dprintk("%s\n", __func__); - sp887x_writereg(state, 0xf08, 0x000); - sp887x_writereg(state, 0xf09, 0x000); - - /* microcontroller START */ - sp887x_writereg(state, 0xf00, 0x001); -} - -static void sp887x_setup_agc (struct sp887x_state* state) -{ - /* setup AGC parameters */ - dprintk("%s\n", __func__); - sp887x_writereg(state, 0x33c, 0x054); - sp887x_writereg(state, 0x33b, 0x04c); - sp887x_writereg(state, 0x328, 0x000); - sp887x_writereg(state, 0x327, 0x005); - sp887x_writereg(state, 0x326, 0x001); - sp887x_writereg(state, 0x325, 0x001); - sp887x_writereg(state, 0x324, 0x001); - sp887x_writereg(state, 0x318, 0x050); - sp887x_writereg(state, 0x317, 0x3fe); - sp887x_writereg(state, 0x316, 0x001); - sp887x_writereg(state, 0x313, 0x005); - sp887x_writereg(state, 0x312, 0x002); - sp887x_writereg(state, 0x306, 0x000); - sp887x_writereg(state, 0x303, 0x000); -} - -#define BLOCKSIZE 30 -#define FW_SIZE 0x4000 -/** - * load firmware and setup MPEG interface... - */ -static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw) -{ - struct sp887x_state* state = fe->demodulator_priv; - u8 buf [BLOCKSIZE+2]; - int i; - int fw_size = fw->size; - const unsigned char *mem = fw->data; - - dprintk("%s\n", __func__); - - /* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */ - if (fw_size < FW_SIZE+10) - return -ENODEV; - - mem = fw->data + 10; - - /* soft reset */ - sp887x_writereg(state, 0xf1a, 0x000); - - sp887x_microcontroller_stop (state); - - printk ("%s: firmware upload... ", __func__); - - /* setup write pointer to -1 (end of memory) */ - /* bit 0x8000 in address is set to enable 13bit mode */ - sp887x_writereg(state, 0x8f08, 0x1fff); - - /* dummy write (wrap around to start of memory) */ - sp887x_writereg(state, 0x8f0a, 0x0000); - - for (i = 0; i < FW_SIZE; i += BLOCKSIZE) { - int c = BLOCKSIZE; - int err; - - if (i+c > FW_SIZE) - c = FW_SIZE - i; - - /* bit 0x8000 in address is set to enable 13bit mode */ - /* bit 0x4000 enables multibyte read/write transfers */ - /* write register is 0xf0a */ - buf[0] = 0xcf; - buf[1] = 0x0a; - - memcpy(&buf[2], mem + i, c); - - if ((err = i2c_writebytes (state, buf, c+2)) < 0) { - printk ("failed.\n"); - printk ("%s: i2c error (err == %i)\n", __func__, err); - return err; - } - } - - /* don't write RS bytes between packets */ - sp887x_writereg(state, 0xc13, 0x001); - - /* suppress clock if (!data_valid) */ - sp887x_writereg(state, 0xc14, 0x000); - - /* setup MPEG interface... */ - sp887x_writereg(state, 0xc1a, 0x872); - sp887x_writereg(state, 0xc1b, 0x001); - sp887x_writereg(state, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */ - sp887x_writereg(state, 0xc1a, 0x871); - - /* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */ - sp887x_writereg(state, 0x301, 0x002); - - sp887x_setup_agc(state); - - /* bit 0x010: enable data valid signal */ - sp887x_writereg(state, 0xd00, 0x010); - sp887x_writereg(state, 0x0d1, 0x000); - return 0; -}; - -static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) -{ - int known_parameters = 1; - - *reg0xc05 = 0x000; - - switch (p->u.ofdm.constellation) { - case QPSK: - break; - case QAM_16: - *reg0xc05 |= (1 << 10); - break; - case QAM_64: - *reg0xc05 |= (2 << 10); - break; - case QAM_AUTO: - known_parameters = 0; - break; - default: - return -EINVAL; - }; - - switch (p->u.ofdm.hierarchy_information) { - case HIERARCHY_NONE: - break; - case HIERARCHY_1: - *reg0xc05 |= (1 << 7); - break; - case HIERARCHY_2: - *reg0xc05 |= (2 << 7); - break; - case HIERARCHY_4: - *reg0xc05 |= (3 << 7); - break; - case HIERARCHY_AUTO: - known_parameters = 0; - break; - default: - return -EINVAL; - }; - - switch (p->u.ofdm.code_rate_HP) { - case FEC_1_2: - break; - case FEC_2_3: - *reg0xc05 |= (1 << 3); - break; - case FEC_3_4: - *reg0xc05 |= (2 << 3); - break; - case FEC_5_6: - *reg0xc05 |= (3 << 3); - break; - case FEC_7_8: - *reg0xc05 |= (4 << 3); - break; - case FEC_AUTO: - known_parameters = 0; - break; - default: - return -EINVAL; - }; - - if (known_parameters) - *reg0xc05 |= (2 << 1); /* use specified parameters */ - else - *reg0xc05 |= (1 << 1); /* enable autoprobing */ - - return 0; -} - -/** - * estimates division of two 24bit numbers, - * derived from the ves1820/stv0299 driver code - */ -static void divide (int n, int d, int *quotient_i, int *quotient_f) -{ - unsigned int q, r; - - r = (n % d) << 8; - q = (r / d); - - if (quotient_i) - *quotient_i = q; - - if (quotient_f) { - r = (r % d) << 8; - q = (q << 8) | (r / d); - r = (r % d) << 8; - *quotient_f = (q << 8) | (r / d); - } -} - -static void sp887x_correct_offsets (struct sp887x_state* state, - struct dvb_frontend_parameters *p, - int actual_freq) -{ - static const u32 srate_correction [] = { 1879617, 4544878, 8098561 }; - int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; - int freq_offset = actual_freq - p->frequency; - int sysclock = 61003; //[kHz] - int ifreq = 36000000; - int freq; - int frequency_shift; - - if (p->inversion == INVERSION_ON) - freq = ifreq - freq_offset; - else - freq = ifreq + freq_offset; - - divide(freq / 333, sysclock, NULL, &frequency_shift); - - if (p->inversion == INVERSION_ON) - frequency_shift = -frequency_shift; - - /* sample rate correction */ - sp887x_writereg(state, 0x319, srate_correction[bw_index] >> 12); - sp887x_writereg(state, 0x31a, srate_correction[bw_index] & 0xfff); - - /* carrier offset correction */ - sp887x_writereg(state, 0x309, frequency_shift >> 12); - sp887x_writereg(state, 0x30a, frequency_shift & 0xfff); -} - -static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) -{ - struct sp887x_state* state = fe->demodulator_priv; - unsigned actual_freq; - int err; - u16 val, reg0xc05; - - if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && - p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ && - p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ) - return -EINVAL; - - if ((err = configure_reg0xc05(p, ®0xc05))) - return err; - - sp887x_microcontroller_stop(state); - - /* setup the PLL */ - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - if (fe->ops.tuner_ops.get_frequency) { - fe->ops.tuner_ops.get_frequency(fe, &actual_freq); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } else { - actual_freq = p->frequency; - } - - /* read status reg in order to clear u.ofdm.bandwidth == BANDWIDTH_6_MHZ) - val = 2; - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) - val = 1; - else - val = 0; - - sp887x_writereg(state, 0x311, val); - - /* scan order: 2k first = 0, 8k first = 1 */ - if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) - sp887x_writereg(state, 0x338, 0x000); - else - sp887x_writereg(state, 0x338, 0x001); - - sp887x_writereg(state, 0xc05, reg0xc05); - - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) - val = 2 << 3; - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) - val = 3 << 3; - else - val = 0 << 3; - - /* enable OFDM and SAW bits as lock indicators in sync register 0xf17, - * optimize algorithm for given bandwidth... - */ - sp887x_writereg(state, 0xf14, 0x160 | val); - sp887x_writereg(state, 0xf15, 0x000); - - sp887x_microcontroller_start(state); - return 0; -} - -static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct sp887x_state* state = fe->demodulator_priv; - u16 snr12 = sp887x_readreg(state, 0xf16); - u16 sync0x200 = sp887x_readreg(state, 0x200); - u16 sync0xf17 = sp887x_readreg(state, 0xf17); - - *status = 0; - - if (snr12 > 0x00f) - *status |= FE_HAS_SIGNAL; - - //if (sync0x200 & 0x004) - // *status |= FE_HAS_SYNC | FE_HAS_CARRIER; - - //if (sync0x200 & 0x008) - // *status |= FE_HAS_VITERBI; - - if ((sync0xf17 & 0x00f) == 0x002) { - *status |= FE_HAS_LOCK; - *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER; - } - - if (sync0x200 & 0x001) { /* tuner adjustment requested...*/ - int steps = (sync0x200 >> 4) & 0x00f; - if (steps & 0x008) - steps = -steps; - dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n", - steps); - } - - return 0; -} - -static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct sp887x_state* state = fe->demodulator_priv; - - *ber = (sp887x_readreg(state, 0xc08) & 0x3f) | - (sp887x_readreg(state, 0xc07) << 6); - sp887x_writereg(state, 0xc08, 0x000); - sp887x_writereg(state, 0xc07, 0x000); - if (*ber >= 0x3fff0) - *ber = ~0; - - return 0; -} - -static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct sp887x_state* state = fe->demodulator_priv; - - u16 snr12 = sp887x_readreg(state, 0xf16); - u32 signal = 3 * (snr12 << 4); - *strength = (signal < 0xffff) ? signal : 0xffff; - - return 0; -} - -static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct sp887x_state* state = fe->demodulator_priv; - - u16 snr12 = sp887x_readreg(state, 0xf16); - *snr = (snr12 << 4) | (snr12 >> 8); - - return 0; -} - -static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct sp887x_state* state = fe->demodulator_priv; - - *ucblocks = sp887x_readreg(state, 0xc0c); - if (*ucblocks == 0xfff) - *ucblocks = ~0; - - return 0; -} - -static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct sp887x_state* state = fe->demodulator_priv; - - if (enable) { - return sp887x_writereg(state, 0x206, 0x001); - } else { - return sp887x_writereg(state, 0x206, 0x000); - } -} - -static int sp887x_sleep(struct dvb_frontend* fe) -{ - struct sp887x_state* state = fe->demodulator_priv; - - /* tristate TS output and disable interface pins */ - sp887x_writereg(state, 0xc18, 0x000); - - return 0; -} - -static int sp887x_init(struct dvb_frontend* fe) -{ - struct sp887x_state* state = fe->demodulator_priv; - const struct firmware *fw = NULL; - int ret; - - if (!state->initialised) { - /* request the firmware, this will block until someone uploads it */ - printk("sp887x: waiting for firmware upload (%s)...\n", SP887X_DEFAULT_FIRMWARE); - ret = state->config->request_firmware(fe, &fw, SP887X_DEFAULT_FIRMWARE); - if (ret) { - printk("sp887x: no firmware upload (timeout or file not found?)\n"); - return ret; - } - - ret = sp887x_initial_setup(fe, fw); - release_firmware(fw); - if (ret) { - printk("sp887x: writing firmware to device failed\n"); - return ret; - } - printk("sp887x: firmware upload complete\n"); - state->initialised = 1; - } - - /* enable TS output and interface pins */ - sp887x_writereg(state, 0xc18, 0x00d); - - return 0; -} - -static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) -{ - fesettings->min_delay_ms = 350; - fesettings->step_size = 166666*2; - fesettings->max_drift = (166666*2)+1; - return 0; -} - -static void sp887x_release(struct dvb_frontend* fe) -{ - struct sp887x_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops sp887x_ops; - -struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, - struct i2c_adapter* i2c) -{ - struct sp887x_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct sp887x_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->initialised = 0; - - /* check if the demod is there */ - if (sp887x_readreg(state, 0x0200) < 0) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops sp887x_ops = { - - .info = { - .name = "Spase SP887x DVB-T", - .type = FE_OFDM, - .frequency_min = 50500000, - .frequency_max = 858000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_RECOVER - }, - - .release = sp887x_release, - - .init = sp887x_init, - .sleep = sp887x_sleep, - .i2c_gate_ctrl = sp887x_i2c_gate_ctrl, - - .set_frontend = sp887x_setup_frontend_parameters, - .get_tune_settings = sp887x_get_tune_settings, - - .read_status = sp887x_read_status, - .read_ber = sp887x_read_ber, - .read_signal_strength = sp887x_read_signal_strength, - .read_snr = sp887x_read_snr, - .read_ucblocks = sp887x_read_ucblocks, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(sp887x_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp887x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp887x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp887x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/sp887x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/* - Driver for the Spase sp887x demodulator -*/ - -#ifndef SP887X_H -#define SP887X_H - -#include -#include - -struct sp887x_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* request firmware for device */ - int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); -}; - -#if defined(CONFIG_DVB_SP887X) || (defined(CONFIG_DVB_SP887X_MODULE) && defined(MODULE)) -extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_SP887X - -#endif // SP887X_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_algo.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_algo.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_algo.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_algo.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1522 +0,0 @@ -/* - STB0899 Multistandard Frontend driver - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "stb0899_drv.h" -#include "stb0899_priv.h" -#include "stb0899_reg.h" - -inline u32 stb0899_do_div(u64 n, u32 d) -{ - /* wrap do_div() for ease of use */ - - do_div(n, d); - return n; -} - -#if 0 -/* These functions are currently unused */ -/* - * stb0899_calc_srate - * Compute symbol rate - */ -static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr) -{ - u64 tmp; - - /* srate = (SFR * master_clk) >> 20 */ - - /* sfr is of size 20 bit, stored with an offset of 4 bit */ - tmp = (((u32)sfr[0]) << 16) | (((u32)sfr[1]) << 8) | sfr[2]; - tmp &= ~0xf; - tmp *= master_clk; - tmp >>= 24; - - return tmp; -} - -/* - * stb0899_get_srate - * Get the current symbol rate - */ -static u32 stb0899_get_srate(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - u8 sfr[3]; - - stb0899_read_regs(state, STB0899_SFRH, sfr, 3); - - return stb0899_calc_srate(internal->master_clk, sfr); -} -#endif - -/* - * stb0899_set_srate - * Set symbol frequency - * MasterClock: master clock frequency (hz) - * SymbolRate: symbol rate (bauds) - * return symbol frequency - */ -static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 srate) -{ - u32 tmp; - u8 sfr[3]; - - dprintk(state->verbose, FE_DEBUG, 1, "-->"); - /* - * in order to have the maximum precision, the symbol rate entered into - * the chip is computed as the closest value of the "true value". - * In this purpose, the symbol rate value is rounded (1 is added on the bit - * below the LSB ) - * - * srate = (SFR * master_clk) >> 20 - * <=> - * SFR = srate << 20 / master_clk - * - * rounded: - * SFR = (srate << 21 + master_clk) / (2 * master_clk) - * - * stored as 20 bit number with an offset of 4 bit: - * sfr = SFR << 4; - */ - - tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk); - tmp <<= 4; - - sfr[0] = tmp >> 16; - sfr[1] = tmp >> 8; - sfr[2] = tmp; - - stb0899_write_regs(state, STB0899_SFRH, sfr, 3); - - return srate; -} - -/* - * stb0899_calc_derot_time - * Compute the amount of time needed by the derotator to lock - * SymbolRate: Symbol rate - * return: derotator time constant (ms) - */ -static long stb0899_calc_derot_time(long srate) -{ - if (srate > 0) - return (100000 / (srate / 1000)); - else - return 0; -} - -/* - * stb0899_carr_width - * Compute the width of the carrier - * return: width of carrier (kHz or Mhz) - */ -long stb0899_carr_width(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - - return (internal->srate + (internal->srate * internal->rolloff) / 100); -} - -/* - * stb0899_first_subrange - * Compute the first subrange of the search - */ -static void stb0899_first_subrange(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_params *params = &state->params; - struct stb0899_config *config = state->config; - - int range = 0; - u32 bandwidth = 0; - - if (config->tuner_get_bandwidth) { - stb0899_i2c_gate_ctrl(&state->frontend, 1); - config->tuner_get_bandwidth(&state->frontend, &bandwidth); - stb0899_i2c_gate_ctrl(&state->frontend, 0); - range = bandwidth - stb0899_carr_width(state) / 2; - } - - if (range > 0) - internal->sub_range = min(internal->srch_range, range); - else - internal->sub_range = 0; - - internal->freq = params->freq; - internal->tuner_offst = 0L; - internal->sub_dir = 1; -} - -/* - * stb0899_check_tmg - * check for timing lock - * internal.Ttiming: time to wait for loop lock - */ -static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - int lock; - u8 reg; - s8 timing; - - msleep(internal->t_derot); - - stb0899_write_reg(state, STB0899_RTF, 0xf2); - reg = stb0899_read_reg(state, STB0899_TLIR); - lock = STB0899_GETFIELD(TLIR_TMG_LOCK_IND, reg); - timing = stb0899_read_reg(state, STB0899_RTF); - - if (lock >= 42) { - if ((lock > 48) && (abs(timing) >= 110)) { - internal->status = ANALOGCARRIER; - dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !"); - } else { - internal->status = TIMINGOK; - dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK !"); - } - } else { - internal->status = NOTIMING; - dprintk(state->verbose, FE_DEBUG, 1, "-->NO TIMING !"); - } - return internal->status; -} - -/* - * stb0899_search_tmg - * perform a fs/2 zig-zag to find timing - */ -static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_params *params = &state->params; - - short int derot_step, derot_freq = 0, derot_limit, next_loop = 3; - int index = 0; - u8 cfr[2]; - - internal->status = NOTIMING; - - /* timing loop computation & symbol rate optimisation */ - derot_limit = (internal->sub_range / 2L) / internal->mclk; - derot_step = (params->srate / 2L) / internal->mclk; - - while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) { - index++; - derot_freq += index * internal->direction * derot_step; /* next derot zig zag position */ - - if (abs(derot_freq) > derot_limit) - next_loop--; - - if (next_loop) { - STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); - STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); - stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ - } - internal->direction = -internal->direction; /* Change zigzag direction */ - } - - if (internal->status == TIMINGOK) { - stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ - internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); - dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq); - } - - return internal->status; -} - -/* - * stb0899_check_carrier - * Check for carrier found - */ -static enum stb0899_status stb0899_check_carrier(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - u8 reg; - - msleep(internal->t_derot); /* wait for derotator ok */ - - reg = stb0899_read_reg(state, STB0899_CFD); - STB0899_SETFIELD_VAL(CFD_ON, reg, 1); - stb0899_write_reg(state, STB0899_CFD, reg); - - reg = stb0899_read_reg(state, STB0899_DSTATUS); - dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg); - if (STB0899_GETFIELD(CARRIER_FOUND, reg)) { - internal->status = CARRIEROK; - dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !"); - } else { - internal->status = NOCARRIER; - dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !"); - } - - return internal->status; -} - -/* - * stb0899_search_carrier - * Search for a QPSK carrier with the derotator - */ -static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - - short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3; - int index = 0; - u8 cfr[2]; - u8 reg; - - internal->status = NOCARRIER; - derot_limit = (internal->sub_range / 2L) / internal->mclk; - derot_freq = internal->derot_freq; - - reg = stb0899_read_reg(state, STB0899_CFD); - STB0899_SETFIELD_VAL(CFD_ON, reg, 1); - stb0899_write_reg(state, STB0899_CFD, reg); - - do { - dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk); - if (stb0899_check_carrier(state) == NOCARRIER) { - index++; - last_derot_freq = derot_freq; - derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */ - - if(abs(derot_freq) > derot_limit) - next_loop--; - - if (next_loop) { - reg = stb0899_read_reg(state, STB0899_CFD); - STB0899_SETFIELD_VAL(CFD_ON, reg, 1); - stb0899_write_reg(state, STB0899_CFD, reg); - - STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); - STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); - stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ - } - } - - internal->direction = -internal->direction; /* Change zigzag direction */ - } while ((internal->status != CARRIEROK) && next_loop); - - if (internal->status == CARRIEROK) { - stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ - internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); - dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq); - } else { - internal->derot_freq = last_derot_freq; - } - - return internal->status; -} - -/* - * stb0899_check_data - * Check for data found - */ -static enum stb0899_status stb0899_check_data(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_params *params = &state->params; - - int lock = 0, index = 0, dataTime = 500, loop; - u8 reg; - - internal->status = NODATA; - - /* RESET FEC */ - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESACS, reg, 1); - stb0899_write_reg(state, STB0899_TSTRES, reg); - msleep(1); - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESACS, reg, 0); - stb0899_write_reg(state, STB0899_TSTRES, reg); - - if (params->srate <= 2000000) - dataTime = 2000; - else if (params->srate <= 5000000) - dataTime = 1500; - else if (params->srate <= 15000000) - dataTime = 1000; - else - dataTime = 500; - - stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop */ - while (1) { - /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP */ - reg = stb0899_read_reg(state, STB0899_VSTATUS); - lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg); - loop = STB0899_GETFIELD(VSTATUS_END_LOOPVIT, reg); - - if (lock || loop || (index > dataTime)) - break; - index++; - } - - if (lock) { /* DATA LOCK indicator */ - internal->status = DATAOK; - dprintk(state->verbose, FE_DEBUG, 1, "-----------------> DATA OK !"); - } - - return internal->status; -} - -/* - * stb0899_search_data - * Search for a QPSK carrier with the derotator - */ -static enum stb0899_status stb0899_search_data(struct stb0899_state *state) -{ - short int derot_freq, derot_step, derot_limit, next_loop = 3; - u8 cfr[2]; - u8 reg; - int index = 1; - - struct stb0899_internal *internal = &state->internal; - struct stb0899_params *params = &state->params; - - derot_step = (params->srate / 4L) / internal->mclk; - derot_limit = (internal->sub_range / 2L) / internal->mclk; - derot_freq = internal->derot_freq; - - do { - if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) { - - derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */ - if (abs(derot_freq) > derot_limit) - next_loop--; - - if (next_loop) { - dprintk(state->verbose, FE_DEBUG, 1, "Derot freq=%d, mclk=%d", derot_freq, internal->mclk); - reg = stb0899_read_reg(state, STB0899_CFD); - STB0899_SETFIELD_VAL(CFD_ON, reg, 1); - stb0899_write_reg(state, STB0899_CFD, reg); - - STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); - STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); - stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ - - stb0899_check_carrier(state); - index++; - } - } - internal->direction = -internal->direction; /* change zig zag direction */ - } while ((internal->status != DATAOK) && next_loop); - - if (internal->status == DATAOK) { - stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ - internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); - dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq); - } - - return internal->status; -} - -/* - * stb0899_check_range - * check if the found frequency is in the correct range - */ -static enum stb0899_status stb0899_check_range(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_params *params = &state->params; - - int range_offst, tp_freq; - - range_offst = internal->srch_range / 2000; - tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000; - - if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) { - internal->status = RANGEOK; - dprintk(state->verbose, FE_DEBUG, 1, "----> RANGEOK !"); - } else { - internal->status = OUTOFRANGE; - dprintk(state->verbose, FE_DEBUG, 1, "----> OUT OF RANGE !"); - } - - return internal->status; -} - -/* - * NextSubRange - * Compute the next subrange of the search - */ -static void next_sub_range(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_params *params = &state->params; - - long old_sub_range; - - if (internal->sub_dir > 0) { - old_sub_range = internal->sub_range; - internal->sub_range = min((internal->srch_range / 2) - - (internal->tuner_offst + internal->sub_range / 2), - internal->sub_range); - - if (internal->sub_range < 0) - internal->sub_range = 0; - - internal->tuner_offst += (old_sub_range + internal->sub_range) / 2; - } - - internal->freq = params->freq + (internal->sub_dir * internal->tuner_offst) / 1000; - internal->sub_dir = -internal->sub_dir; -} - -/* - * stb0899_dvbs_algo - * Search for a signal, timing, carrier and data for a - * given frequency in a given range - */ -enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state) -{ - struct stb0899_params *params = &state->params; - struct stb0899_internal *internal = &state->internal; - struct stb0899_config *config = state->config; - - u8 bclc, reg; - u8 cfr[2]; - u8 eq_const[10]; - s32 clnI = 3; - u32 bandwidth = 0; - - /* BETA values rated @ 99MHz */ - s32 betaTab[5][4] = { - /* 5 10 20 30MBps */ - { 37, 34, 32, 31 }, /* QPSK 1/2 */ - { 37, 35, 33, 31 }, /* QPSK 2/3 */ - { 37, 35, 33, 31 }, /* QPSK 3/4 */ - { 37, 36, 33, 32 }, /* QPSK 5/6 */ - { 37, 36, 33, 32 } /* QPSK 7/8 */ - }; - - internal->direction = 1; - - stb0899_set_srate(state, internal->master_clk, params->srate); - /* Carrier loop optimization versus symbol rate for acquisition*/ - if (params->srate <= 5000000) { - stb0899_write_reg(state, STB0899_ACLC, 0x89); - bclc = stb0899_read_reg(state, STB0899_BCLC); - STB0899_SETFIELD_VAL(BETA, bclc, 0x1c); - stb0899_write_reg(state, STB0899_BCLC, bclc); - clnI = 0; - } else if (params->srate <= 15000000) { - stb0899_write_reg(state, STB0899_ACLC, 0xc9); - bclc = stb0899_read_reg(state, STB0899_BCLC); - STB0899_SETFIELD_VAL(BETA, bclc, 0x22); - stb0899_write_reg(state, STB0899_BCLC, bclc); - clnI = 1; - } else if(params->srate <= 25000000) { - stb0899_write_reg(state, STB0899_ACLC, 0x89); - bclc = stb0899_read_reg(state, STB0899_BCLC); - STB0899_SETFIELD_VAL(BETA, bclc, 0x27); - stb0899_write_reg(state, STB0899_BCLC, bclc); - clnI = 2; - } else { - stb0899_write_reg(state, STB0899_ACLC, 0xc8); - bclc = stb0899_read_reg(state, STB0899_BCLC); - STB0899_SETFIELD_VAL(BETA, bclc, 0x29); - stb0899_write_reg(state, STB0899_BCLC, bclc); - clnI = 3; - } - - dprintk(state->verbose, FE_DEBUG, 1, "Set the timing loop to acquisition"); - /* Set the timing loop to acquisition */ - stb0899_write_reg(state, STB0899_RTC, 0x46); - stb0899_write_reg(state, STB0899_CFD, 0xee); - - /* !! WARNING !! - * Do not read any status variables while acquisition, - * If any needed, read before the acquisition starts - * querying status while acquiring causes the - * acquisition to go bad and hence no locks. - */ - dprintk(state->verbose, FE_DEBUG, 1, "Derot Percent=%d Srate=%d mclk=%d", - internal->derot_percent, params->srate, internal->mclk); - - /* Initial calculations */ - internal->derot_step = internal->derot_percent * (params->srate / 1000L) / internal->mclk; /* DerotStep/1000 * Fsymbol */ - internal->t_derot = stb0899_calc_derot_time(params->srate); - internal->t_data = 500; - - dprintk(state->verbose, FE_DEBUG, 1, "RESET stream merger"); - /* RESET Stream merger */ - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESRS, reg, 1); - stb0899_write_reg(state, STB0899_TSTRES, reg); - - /* - * Set KDIVIDER to an intermediate value between - * 1/2 and 7/8 for acquisition - */ - reg = stb0899_read_reg(state, STB0899_DEMAPVIT); - STB0899_SETFIELD_VAL(DEMAPVIT_KDIVIDER, reg, 60); - stb0899_write_reg(state, STB0899_DEMAPVIT, reg); - - stb0899_write_reg(state, STB0899_EQON, 0x01); /* Equalizer OFF while acquiring */ - stb0899_write_reg(state, STB0899_VITSYNC, 0x19); - - stb0899_first_subrange(state); - do { - /* Initialisations */ - cfr[0] = cfr[1] = 0; - stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* RESET derotator frequency */ - - stb0899_write_reg(state, STB0899_RTF, 0); - reg = stb0899_read_reg(state, STB0899_CFD); - STB0899_SETFIELD_VAL(CFD_ON, reg, 1); - stb0899_write_reg(state, STB0899_CFD, reg); - - internal->derot_freq = 0; - internal->status = NOAGC1; - - /* enable tuner I/O */ - stb0899_i2c_gate_ctrl(&state->frontend, 1); - - /* Move tuner to frequency */ - dprintk(state->verbose, FE_DEBUG, 1, "Tuner set frequency"); - if (state->config->tuner_set_frequency) - state->config->tuner_set_frequency(&state->frontend, internal->freq); - - if (state->config->tuner_get_frequency) - state->config->tuner_get_frequency(&state->frontend, &internal->freq); - - msleep(internal->t_agc1 + internal->t_agc2 + internal->t_derot); /* AGC1, AGC2 and timing loop */ - dprintk(state->verbose, FE_DEBUG, 1, "current derot freq=%d", internal->derot_freq); - internal->status = AGC1OK; - - /* There is signal in the band */ - if (config->tuner_get_bandwidth) - config->tuner_get_bandwidth(&state->frontend, &bandwidth); - - /* disable tuner I/O */ - stb0899_i2c_gate_ctrl(&state->frontend, 0); - - if (params->srate <= bandwidth / 2) - stb0899_search_tmg(state); /* For low rates (SCPC) */ - else - stb0899_check_tmg(state); /* For high rates (MCPC) */ - - if (internal->status == TIMINGOK) { - dprintk(state->verbose, FE_DEBUG, 1, - "TIMING OK ! Derot freq=%d, mclk=%d", - internal->derot_freq, internal->mclk); - - if (stb0899_search_carrier(state) == CARRIEROK) { /* Search for carrier */ - dprintk(state->verbose, FE_DEBUG, 1, - "CARRIER OK ! Derot freq=%d, mclk=%d", - internal->derot_freq, internal->mclk); - - if (stb0899_search_data(state) == DATAOK) { /* Check for data */ - dprintk(state->verbose, FE_DEBUG, 1, - "DATA OK ! Derot freq=%d, mclk=%d", - internal->derot_freq, internal->mclk); - - if (stb0899_check_range(state) == RANGEOK) { - dprintk(state->verbose, FE_DEBUG, 1, - "RANGE OK ! derot freq=%d, mclk=%d", - internal->derot_freq, internal->mclk); - - internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000); - reg = stb0899_read_reg(state, STB0899_PLPARM); - internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg); - dprintk(state->verbose, FE_DEBUG, 1, - "freq=%d, internal resultant freq=%d", - params->freq, internal->freq); - - dprintk(state->verbose, FE_DEBUG, 1, - "internal puncture rate=%d", - internal->fecrate); - } - } - } - } - if (internal->status != RANGEOK) - next_sub_range(state); - - } while (internal->sub_range && internal->status != RANGEOK); - - /* Set the timing loop to tracking */ - stb0899_write_reg(state, STB0899_RTC, 0x33); - stb0899_write_reg(state, STB0899_CFD, 0xf7); - /* if locked and range ok, set Kdiv */ - if (internal->status == RANGEOK) { - dprintk(state->verbose, FE_DEBUG, 1, "Locked & Range OK !"); - stb0899_write_reg(state, STB0899_EQON, 0x41); /* Equalizer OFF while acquiring */ - stb0899_write_reg(state, STB0899_VITSYNC, 0x39); /* SN to b'11 for acquisition */ - - /* - * Carrier loop optimization versus - * symbol Rate/Puncture Rate for Tracking - */ - reg = stb0899_read_reg(state, STB0899_BCLC); - switch (internal->fecrate) { - case STB0899_FEC_1_2: /* 13 */ - stb0899_write_reg(state, STB0899_DEMAPVIT, 0x1a); - STB0899_SETFIELD_VAL(BETA, reg, betaTab[0][clnI]); - stb0899_write_reg(state, STB0899_BCLC, reg); - break; - case STB0899_FEC_2_3: /* 18 */ - stb0899_write_reg(state, STB0899_DEMAPVIT, 44); - STB0899_SETFIELD_VAL(BETA, reg, betaTab[1][clnI]); - stb0899_write_reg(state, STB0899_BCLC, reg); - break; - case STB0899_FEC_3_4: /* 21 */ - stb0899_write_reg(state, STB0899_DEMAPVIT, 60); - STB0899_SETFIELD_VAL(BETA, reg, betaTab[2][clnI]); - stb0899_write_reg(state, STB0899_BCLC, reg); - break; - case STB0899_FEC_5_6: /* 24 */ - stb0899_write_reg(state, STB0899_DEMAPVIT, 75); - STB0899_SETFIELD_VAL(BETA, reg, betaTab[3][clnI]); - stb0899_write_reg(state, STB0899_BCLC, reg); - break; - case STB0899_FEC_6_7: /* 25 */ - stb0899_write_reg(state, STB0899_DEMAPVIT, 88); - stb0899_write_reg(state, STB0899_ACLC, 0x88); - stb0899_write_reg(state, STB0899_BCLC, 0x9a); - break; - case STB0899_FEC_7_8: /* 26 */ - stb0899_write_reg(state, STB0899_DEMAPVIT, 94); - STB0899_SETFIELD_VAL(BETA, reg, betaTab[4][clnI]); - stb0899_write_reg(state, STB0899_BCLC, reg); - break; - default: - dprintk(state->verbose, FE_DEBUG, 1, "Unsupported Puncture Rate"); - break; - } - /* release stream merger RESET */ - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESRS, reg, 0); - stb0899_write_reg(state, STB0899_TSTRES, reg); - - /* disable carrier detector */ - reg = stb0899_read_reg(state, STB0899_CFD); - STB0899_SETFIELD_VAL(CFD_ON, reg, 0); - stb0899_write_reg(state, STB0899_CFD, reg); - - stb0899_read_regs(state, STB0899_EQUAI1, eq_const, 10); - } - - return internal->status; -} - -/* - * stb0899_dvbs2_config_uwp - * Configure UWP state machine - */ -static void stb0899_dvbs2_config_uwp(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_config *config = state->config; - u32 uwp1, uwp2, uwp3, reg; - - uwp1 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1); - uwp2 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL2); - uwp3 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL3); - - STB0899_SETFIELD_VAL(UWP_ESN0_AVE, uwp1, config->esno_ave); - STB0899_SETFIELD_VAL(UWP_ESN0_QUANT, uwp1, config->esno_quant); - STB0899_SETFIELD_VAL(UWP_TH_SOF, uwp1, config->uwp_threshold_sof); - - STB0899_SETFIELD_VAL(FE_COARSE_TRK, uwp2, internal->av_frame_coarse); - STB0899_SETFIELD_VAL(FE_FINE_TRK, uwp2, internal->av_frame_fine); - STB0899_SETFIELD_VAL(UWP_MISS_TH, uwp2, config->miss_threshold); - - STB0899_SETFIELD_VAL(UWP_TH_ACQ, uwp3, config->uwp_threshold_acq); - STB0899_SETFIELD_VAL(UWP_TH_TRACK, uwp3, config->uwp_threshold_track); - - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL1, STB0899_OFF0_UWP_CNTRL1, uwp1); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL2, STB0899_OFF0_UWP_CNTRL2, uwp2); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL3, STB0899_OFF0_UWP_CNTRL3, uwp3); - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, SOF_SRCH_TO); - STB0899_SETFIELD_VAL(SOF_SEARCH_TIMEOUT, reg, config->sof_search_timeout); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_SOF_SRCH_TO, STB0899_OFF0_SOF_SRCH_TO, reg); -} - -/* - * stb0899_dvbs2_config_csm_auto - * Set CSM to AUTO mode - */ -static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state) -{ - u32 reg; - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); - STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, reg, 1); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg); -} - -static long Log2Int(int number) -{ - int i; - - i = 0; - while ((1 << i) <= abs(number)) - i++; - - if (number == 0) - i = 1; - - return i - 1; -} - -/* - * stb0899_dvbs2_calc_srate - * compute BTR_NOM_FREQ for the symbol rate - */ -static u32 stb0899_dvbs2_calc_srate(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_config *config = state->config; - - u32 dec_ratio, dec_rate, decim, remain, intval, btr_nom_freq; - u32 master_clk, srate; - - dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); - dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; - dec_rate = Log2Int(dec_ratio); - decim = 1 << dec_rate; - master_clk = internal->master_clk / 1000; - srate = internal->srate / 1000; - - if (decim <= 4) { - intval = (decim * (1 << (config->btr_nco_bits - 1))) / master_clk; - remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk; - } else { - intval = (1 << (config->btr_nco_bits - 1)) / (master_clk / 100) * decim / 100; - remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk; - } - btr_nom_freq = (intval * srate) + ((remain * srate) / master_clk); - - return btr_nom_freq; -} - -/* - * stb0899_dvbs2_calc_dev - * compute the correction to be applied to symbol rate - */ -static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - u32 dec_ratio, correction, master_clk, srate; - - dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); - dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; - - master_clk = internal->master_clk / 1000; /* for integer Caculation*/ - srate = internal->srate / 1000; /* for integer Caculation*/ - correction = (512 * master_clk) / (2 * dec_ratio * srate); - - return correction; -} - -/* - * stb0899_dvbs2_set_srate - * Set DVBS2 symbol rate - */ -static void stb0899_dvbs2_set_srate(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - - u32 dec_ratio, dec_rate, win_sel, decim, f_sym, btr_nom_freq; - u32 correction, freq_adj, band_lim, decim_cntrl, reg; - u8 anti_alias; - - /*set decimation to 1*/ - dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); - dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; - dec_rate = Log2Int(dec_ratio); - - win_sel = 0; - if (dec_rate >= 5) - win_sel = dec_rate - 4; - - decim = (1 << dec_rate); - /* (FSamp/Fsymbol *100) for integer Caculation */ - f_sym = internal->master_clk / ((decim * internal->srate) / 1000); - - if (f_sym <= 2250) /* don't band limit signal going into btr block*/ - band_lim = 1; - else - band_lim = 0; /* band limit signal going into btr block*/ - - decim_cntrl = ((win_sel << 3) & 0x18) + ((band_lim << 5) & 0x20) + (dec_rate & 0x7); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DECIM_CNTRL, STB0899_OFF0_DECIM_CNTRL, decim_cntrl); - - if (f_sym <= 3450) - anti_alias = 0; - else if (f_sym <= 4250) - anti_alias = 1; - else - anti_alias = 2; - - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ANTI_ALIAS_SEL, STB0899_OFF0_ANTI_ALIAS_SEL, anti_alias); - btr_nom_freq = stb0899_dvbs2_calc_srate(state); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_NOM_FREQ, STB0899_OFF0_BTR_NOM_FREQ, btr_nom_freq); - - correction = stb0899_dvbs2_calc_dev(state); - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL); - STB0899_SETFIELD_VAL(BTR_FREQ_CORR, reg, correction); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg); - - /* scale UWP+CSM frequency to sample rate*/ - freq_adj = internal->srate / (internal->master_clk / 4096); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_FREQ_ADJ_SCALE, STB0899_OFF0_FREQ_ADJ_SCALE, freq_adj); -} - -/* - * stb0899_dvbs2_set_btr_loopbw - * set bit timing loop bandwidth as a percentage of the symbol rate - */ -static void stb0899_dvbs2_set_btr_loopbw(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_config *config = state->config; - - u32 sym_peak = 23, zeta = 707, loopbw_percent = 60; - s32 dec_ratio, dec_rate, k_btr1_rshft, k_btr1, k_btr0_rshft; - s32 k_btr0, k_btr2_rshft, k_direct_shift, k_indirect_shift; - u32 decim, K, wn, k_direct, k_indirect; - u32 reg; - - dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); - dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; - dec_rate = Log2Int(dec_ratio); - decim = (1 << dec_rate); - - sym_peak *= 576000; - K = (1 << config->btr_nco_bits) / (internal->master_clk / 1000); - K *= (internal->srate / 1000000) * decim; /*k=k 10^-8*/ - - if (K != 0) { - K = sym_peak / K; - wn = (4 * zeta * zeta) + 1000000; - wn = (2 * (loopbw_percent * 1000) * 40 * zeta) /wn; /*wn =wn 10^-8*/ - - k_indirect = (wn * wn) / K; - k_indirect = k_indirect; /*kindirect = kindirect 10^-6*/ - k_direct = (2 * wn * zeta) / K; /*kDirect = kDirect 10^-2*/ - k_direct *= 100; - - k_direct_shift = Log2Int(k_direct) - Log2Int(10000) - 2; - k_btr1_rshft = (-1 * k_direct_shift) + config->btr_gain_shift_offset; - k_btr1 = k_direct / (1 << k_direct_shift); - k_btr1 /= 10000; - - k_indirect_shift = Log2Int(k_indirect + 15) - 20 /*- 2*/; - k_btr0_rshft = (-1 * k_indirect_shift) + config->btr_gain_shift_offset; - k_btr0 = k_indirect * (1 << (-k_indirect_shift)); - k_btr0 /= 1000000; - - k_btr2_rshft = 0; - if (k_btr0_rshft > 15) { - k_btr2_rshft = k_btr0_rshft - 15; - k_btr0_rshft = 15; - } - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_LOOP_GAIN); - STB0899_SETFIELD_VAL(KBTR0_RSHFT, reg, k_btr0_rshft); - STB0899_SETFIELD_VAL(KBTR0, reg, k_btr0); - STB0899_SETFIELD_VAL(KBTR1_RSHFT, reg, k_btr1_rshft); - STB0899_SETFIELD_VAL(KBTR1, reg, k_btr1); - STB0899_SETFIELD_VAL(KBTR2_RSHFT, reg, k_btr2_rshft); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, reg); - } else - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, 0xc4c4f); -} - -/* - * stb0899_dvbs2_set_carr_freq - * set nominal frequency for carrier search - */ -static void stb0899_dvbs2_set_carr_freq(struct stb0899_state *state, s32 carr_freq, u32 master_clk) -{ - struct stb0899_config *config = state->config; - s32 crl_nom_freq; - u32 reg; - - crl_nom_freq = (1 << config->crl_nco_bits) / master_clk; - crl_nom_freq *= carr_freq; - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); - STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, crl_nom_freq); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); -} - -/* - * stb0899_dvbs2_init_calc - * Initialize DVBS2 UWP, CSM, carrier and timing loops - */ -static void stb0899_dvbs2_init_calc(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - s32 steps, step_size; - u32 range, reg; - - /* config uwp and csm */ - stb0899_dvbs2_config_uwp(state); - stb0899_dvbs2_config_csm_auto(state); - - /* initialize BTR */ - stb0899_dvbs2_set_srate(state); - stb0899_dvbs2_set_btr_loopbw(state); - - if (internal->srate / 1000000 >= 15) - step_size = (1 << 17) / 5; - else if (internal->srate / 1000000 >= 10) - step_size = (1 << 17) / 7; - else if (internal->srate / 1000000 >= 5) - step_size = (1 << 17) / 10; - else - step_size = (1 << 17) / 4; - - range = internal->srch_range / 1000000; - steps = (10 * range * (1 << 17)) / (step_size * (internal->srate / 1000000)); - steps = (steps + 6) / 10; - steps = (steps == 0) ? 1 : steps; - if (steps % 2 == 0) - stb0899_dvbs2_set_carr_freq(state, internal->center_freq - - (internal->step_size * (internal->srate / 20000000)), - (internal->master_clk) / 1000000); - else - stb0899_dvbs2_set_carr_freq(state, internal->center_freq, (internal->master_clk) / 1000000); - - /*Set Carrier Search params (zigzag, num steps and freq step size*/ - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, ACQ_CNTRL2); - STB0899_SETFIELD_VAL(ZIGZAG, reg, 1); - STB0899_SETFIELD_VAL(NUM_STEPS, reg, steps); - STB0899_SETFIELD_VAL(FREQ_STEPSIZE, reg, step_size); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQ_CNTRL2, STB0899_OFF0_ACQ_CNTRL2, reg); -} - -/* - * stb0899_dvbs2_btr_init - * initialize the timing loop - */ -static void stb0899_dvbs2_btr_init(struct stb0899_state *state) -{ - u32 reg; - - /* set enable BTR loopback */ - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL); - STB0899_SETFIELD_VAL(INTRP_PHS_SENSE, reg, 1); - STB0899_SETFIELD_VAL(BTR_ERR_ENA, reg, 1); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg); - - /* fix btr freq accum at 0 */ - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x10000000); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x00000000); - - /* fix btr freq accum at 0 */ - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x10000000); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x00000000); -} - -/* - * stb0899_dvbs2_reacquire - * trigger a DVB-S2 acquisition - */ -static void stb0899_dvbs2_reacquire(struct stb0899_state *state) -{ - u32 reg = 0; - - /* demod soft reset */ - STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 1); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg); - - /*Reset Timing Loop */ - stb0899_dvbs2_btr_init(state); - - /* reset Carrier loop */ - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, (1 << 30)); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, 0); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_LOOP_GAIN, STB0899_OFF0_CRL_LOOP_GAIN, 0); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, (1 << 30)); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, 0); - - /*release demod soft reset */ - reg = 0; - STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 0); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg); - - /* start acquisition process */ - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQUIRE_TRIG, STB0899_OFF0_ACQUIRE_TRIG, 1); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_LOCK_LOST, STB0899_OFF0_LOCK_LOST, 0); - - /* equalizer Init */ - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 1); - - /*Start equilizer */ - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 0); - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); - STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0); - STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 0); - STB0899_SETFIELD_VAL(EQ_DELAY, reg, 0x05); - STB0899_SETFIELD_VAL(EQ_ADAPT_MODE, reg, 0x01); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); - - /* RESET Packet delineator */ - stb0899_write_reg(state, STB0899_PDELCTRL, 0x4a); -} - -/* - * stb0899_dvbs2_get_dmd_status - * get DVB-S2 Demod LOCK status - */ -static enum stb0899_status stb0899_dvbs2_get_dmd_status(struct stb0899_state *state, int timeout) -{ - int time = -10, lock = 0, uwp, csm; - u32 reg; - - do { - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS); - dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg); - if (STB0899_GETFIELD(IF_AGC_LOCK, reg)) - dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !"); - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2); - dprintk(state->verbose, FE_DEBUG, 1, "----------->DMD STAT2=[0x%02x]", reg); - uwp = STB0899_GETFIELD(UWP_LOCK, reg); - csm = STB0899_GETFIELD(CSM_LOCK, reg); - if (uwp && csm) - lock = 1; - - time += 10; - msleep(10); - - } while ((!lock) && (time <= timeout)); - - if (lock) { - dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 LOCK !"); - return DVBS2_DEMOD_LOCK; - } else { - return DVBS2_DEMOD_NOLOCK; - } -} - -/* - * stb0899_dvbs2_get_data_lock - * get FEC status - */ -static int stb0899_dvbs2_get_data_lock(struct stb0899_state *state, int timeout) -{ - int time = 0, lock = 0; - u8 reg; - - while ((!lock) && (time < timeout)) { - reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1); - dprintk(state->verbose, FE_DEBUG, 1, "---------> CFGPDELSTATUS=[0x%02x]", reg); - lock = STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg); - time++; - } - - return lock; -} - -/* - * stb0899_dvbs2_get_fec_status - * get DVB-S2 FEC LOCK status - */ -static enum stb0899_status stb0899_dvbs2_get_fec_status(struct stb0899_state *state, int timeout) -{ - int time = 0, Locked; - - do { - Locked = stb0899_dvbs2_get_data_lock(state, 1); - time++; - msleep(1); - - } while ((!Locked) && (time < timeout)); - - if (Locked) { - dprintk(state->verbose, FE_DEBUG, 1, "---------->DVB-S2 FEC LOCK !"); - return DVBS2_FEC_LOCK; - } else { - return DVBS2_FEC_NOLOCK; - } -} - - -/* - * stb0899_dvbs2_init_csm - * set parameters for manual mode - */ -static void stb0899_dvbs2_init_csm(struct stb0899_state *state, int pilots, enum stb0899_modcod modcod) -{ - struct stb0899_internal *internal = &state->internal; - - s32 dvt_tbl = 1, two_pass = 0, agc_gain = 6, agc_shift = 0, loop_shift = 0, phs_diff_thr = 0x80; - s32 gamma_acq, gamma_rho_acq, gamma_trk, gamma_rho_trk, lock_count_thr; - u32 csm1, csm2, csm3, csm4; - - if (((internal->master_clk / internal->srate) <= 4) && (modcod <= 11) && (pilots == 1)) { - switch (modcod) { - case STB0899_QPSK_12: - gamma_acq = 25; - gamma_rho_acq = 2700; - gamma_trk = 12; - gamma_rho_trk = 180; - lock_count_thr = 8; - break; - case STB0899_QPSK_35: - gamma_acq = 38; - gamma_rho_acq = 7182; - gamma_trk = 14; - gamma_rho_trk = 308; - lock_count_thr = 8; - break; - case STB0899_QPSK_23: - gamma_acq = 42; - gamma_rho_acq = 9408; - gamma_trk = 17; - gamma_rho_trk = 476; - lock_count_thr = 8; - break; - case STB0899_QPSK_34: - gamma_acq = 53; - gamma_rho_acq = 16642; - gamma_trk = 19; - gamma_rho_trk = 646; - lock_count_thr = 8; - break; - case STB0899_QPSK_45: - gamma_acq = 53; - gamma_rho_acq = 17119; - gamma_trk = 22; - gamma_rho_trk = 880; - lock_count_thr = 8; - break; - case STB0899_QPSK_56: - gamma_acq = 55; - gamma_rho_acq = 19250; - gamma_trk = 23; - gamma_rho_trk = 989; - lock_count_thr = 8; - break; - case STB0899_QPSK_89: - gamma_acq = 60; - gamma_rho_acq = 24240; - gamma_trk = 24; - gamma_rho_trk = 1176; - lock_count_thr = 8; - break; - case STB0899_QPSK_910: - gamma_acq = 66; - gamma_rho_acq = 29634; - gamma_trk = 24; - gamma_rho_trk = 1176; - lock_count_thr = 8; - break; - default: - gamma_acq = 66; - gamma_rho_acq = 29634; - gamma_trk = 24; - gamma_rho_trk = 1176; - lock_count_thr = 8; - break; - } - - csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); - STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, csm1, 0); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); - - csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); - csm2 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL2); - csm3 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL3); - csm4 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL4); - - STB0899_SETFIELD_VAL(CSM_DVT_TABLE, csm1, dvt_tbl); - STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, two_pass); - STB0899_SETFIELD_VAL(CSM_AGC_GAIN, csm1, agc_gain); - STB0899_SETFIELD_VAL(CSM_AGC_SHIFT, csm1, agc_shift); - STB0899_SETFIELD_VAL(FE_LOOP_SHIFT, csm1, loop_shift); - STB0899_SETFIELD_VAL(CSM_GAMMA_ACQ, csm2, gamma_acq); - STB0899_SETFIELD_VAL(CSM_GAMMA_RHOACQ, csm2, gamma_rho_acq); - STB0899_SETFIELD_VAL(CSM_GAMMA_TRACK, csm3, gamma_trk); - STB0899_SETFIELD_VAL(CSM_GAMMA_RHOTRACK, csm3, gamma_rho_trk); - STB0899_SETFIELD_VAL(CSM_LOCKCOUNT_THRESH, csm4, lock_count_thr); - STB0899_SETFIELD_VAL(CSM_PHASEDIFF_THRESH, csm4, phs_diff_thr); - - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL2, STB0899_OFF0_CSM_CNTRL2, csm2); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL3, STB0899_OFF0_CSM_CNTRL3, csm3); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL4, STB0899_OFF0_CSM_CNTRL4, csm4); - } -} - -/* - * stb0899_dvbs2_get_srate - * get DVB-S2 Symbol Rate - */ -static u32 stb0899_dvbs2_get_srate(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_config *config = state->config; - - u32 bTrNomFreq, srate, decimRate, intval1, intval2, reg; - int div1, div2, rem1, rem2; - - div1 = config->btr_nco_bits / 2; - div2 = config->btr_nco_bits - div1 - 1; - - bTrNomFreq = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_NOM_FREQ); - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DECIM_CNTRL); - decimRate = STB0899_GETFIELD(DECIM_RATE, reg); - decimRate = (1 << decimRate); - - intval1 = internal->master_clk / (1 << div1); - intval2 = bTrNomFreq / (1 << div2); - - rem1 = internal->master_clk % (1 << div1); - rem2 = bTrNomFreq % (1 << div2); - /* only for integer calculation */ - srate = (intval1 * intval2) + ((intval1 * rem2) / (1 << div2)) + ((intval2 * rem1) / (1 << div1)); - srate /= decimRate; /*symbrate = (btrnomfreq_register_val*MasterClock)/2^(27+decim_rate_field) */ - - return srate; -} - -/* - * stb0899_dvbs2_algo - * Search for signal, timing, carrier and data for a given - * frequency in a given range - */ -enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - enum stb0899_modcod modcod; - - s32 offsetfreq, searchTime, FecLockTime, pilots, iqSpectrum; - int i = 0; - u32 reg, csm1; - - if (internal->srate <= 2000000) { - searchTime = 5000; /* 5000 ms max time to lock UWP and CSM, SYMB <= 2Mbs */ - FecLockTime = 350; /* 350 ms max time to lock FEC, SYMB <= 2Mbs */ - } else if (internal->srate <= 5000000) { - searchTime = 2500; /* 2500 ms max time to lock UWP and CSM, 2Mbs < SYMB <= 5Mbs */ - FecLockTime = 170; /* 170 ms max time to lock FEC, 2Mbs< SYMB <= 5Mbs */ - } else if (internal->srate <= 10000000) { - searchTime = 1500; /* 1500 ms max time to lock UWP and CSM, 5Mbs srate <= 15000000) { - searchTime = 500; /* 500 ms max time to lock UWP and CSM, 10Mbs srate <= 20000000) { - searchTime = 300; /* 300 ms max time to lock UWP and CSM, 15Mbs < SYMB <= 20Mbs */ - FecLockTime = 30; /* 50 ms max time to lock FEC, 15Mbs< SYMB <= 20Mbs */ - } else if (internal->srate <= 25000000) { - searchTime = 250; /* 250 ms max time to lock UWP and CSM, 20 Mbs < SYMB <= 25Mbs */ - FecLockTime = 25; /* 25 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs */ - } else { - searchTime = 150; /* 150 ms max time to lock UWP and CSM, SYMB > 25Mbs */ - FecLockTime = 20; /* 20 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs */ - } - - /* Maintain Stream Merger in reset during acquisition */ - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESRS, reg, 1); - stb0899_write_reg(state, STB0899_TSTRES, reg); - - /* enable tuner I/O */ - stb0899_i2c_gate_ctrl(&state->frontend, 1); - - /* Move tuner to frequency */ - if (state->config->tuner_set_frequency) - state->config->tuner_set_frequency(&state->frontend, internal->freq); - if (state->config->tuner_get_frequency) - state->config->tuner_get_frequency(&state->frontend, &internal->freq); - - /* disable tuner I/O */ - stb0899_i2c_gate_ctrl(&state->frontend, 0); - - /* Set IF AGC to acquisition */ - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); - STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg, 4); - STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 32); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2); - STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 0); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg); - - /* Initialisation */ - stb0899_dvbs2_init_calc(state); - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); - switch (internal->inversion) { - case IQ_SWAP_OFF: - STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 0); - break; - case IQ_SWAP_ON: - STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1); - break; - case IQ_SWAP_AUTO: /* use last successful search first */ - STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1); - break; - } - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg); - stb0899_dvbs2_reacquire(state); - - /* Wait for demod lock (UWP and CSM) */ - internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime); - - if (internal->status == DVBS2_DEMOD_LOCK) { - dprintk(state->verbose, FE_DEBUG, 1, "------------> DVB-S2 DEMOD LOCK !"); - i = 0; - /* Demod Locked, check FEC status */ - internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); - - /*If false lock (UWP and CSM Locked but no FEC) try 3 time max*/ - while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { - /* Read the frequency offset*/ - offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); - - /* Set the Nominal frequency to the found frequency offset for the next reacquire*/ - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); - STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); - stb0899_dvbs2_reacquire(state); - internal->status = stb0899_dvbs2_get_fec_status(state, searchTime); - i++; - } - } - - if (internal->status != DVBS2_FEC_LOCK) { - if (internal->inversion == IQ_SWAP_AUTO) { - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); - iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg); - /* IQ Spectrum Inversion */ - STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg); - /* start acquistion process */ - stb0899_dvbs2_reacquire(state); - - /* Wait for demod lock (UWP and CSM) */ - internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime); - if (internal->status == DVBS2_DEMOD_LOCK) { - i = 0; - /* Demod Locked, check FEC */ - internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); - /*try thrice for false locks, (UWP and CSM Locked but no FEC) */ - while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { - /* Read the frequency offset*/ - offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); - - /* Set the Nominal frequency to the found frequency offset for the next reacquire*/ - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); - STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); - - stb0899_dvbs2_reacquire(state); - internal->status = stb0899_dvbs2_get_fec_status(state, searchTime); - i++; - } - } -/* - if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED) - pParams->IQLocked = !iqSpectrum; -*/ - } - } - if (internal->status == DVBS2_FEC_LOCK) { - dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !"); - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); - modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2; - pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01; - - if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) && - (INRANGE(STB0899_QPSK_23, modcod, STB0899_QPSK_910)) && - (pilots == 1)) { - - stb0899_dvbs2_init_csm(state, pilots, modcod); - /* Wait for UWP,CSM and data LOCK 20ms max */ - internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); - - i = 0; - while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { - csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); - STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 1); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); - csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); - STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 0); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); - - internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); - i++; - } - } - - if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) && - (INRANGE(STB0899_QPSK_12, modcod, STB0899_QPSK_35)) && - (pilots == 1)) { - - /* Equalizer Disable update */ - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); - STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 1); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); - } - - /* slow down the Equalizer once locked */ - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); - STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0x02); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); - - /* Store signal parameters */ - offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); - - offsetfreq = offsetfreq / ((1 << 30) / 1000); - offsetfreq *= (internal->master_clk / 1000000); - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); - if (STB0899_GETFIELD(SPECTRUM_INVERT, reg)) - offsetfreq *= -1; - - internal->freq = internal->freq - offsetfreq; - internal->srate = stb0899_dvbs2_get_srate(state); - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); - internal->modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2; - internal->pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01; - internal->frame_length = (STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 1) & 0x01; - - /* Set IF AGC to tracking */ - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); - STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg, 3); - - /* if QPSK 1/2,QPSK 3/5 or QPSK 2/3 set IF AGC reference to 16 otherwise 32*/ - if (INRANGE(STB0899_QPSK_12, internal->modcod, STB0899_QPSK_23)) - STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 16); - - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2); - STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 7); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg); - } - - /* Release Stream Merger Reset */ - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESRS, reg, 0); - stb0899_write_reg(state, STB0899_TSTRES, reg); - - return internal->status; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_cfg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_cfg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_cfg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_cfg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,287 +0,0 @@ -/* - STB0899 Multistandard Frontend driver - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STB0899_CFG_H -#define __STB0899_CFG_H - -static const struct stb0899_s2_reg stb0899_s2_init_2[] = { - - { STB0899_OFF0_DMD_STATUS , STB0899_BASE_DMD_STATUS , 0x00000103 }, /* DMDSTATUS */ - { STB0899_OFF0_CRL_FREQ , STB0899_BASE_CRL_FREQ , 0x3ed1da56 }, /* CRLFREQ */ - { STB0899_OFF0_BTR_FREQ , STB0899_BASE_BTR_FREQ , 0x00004000 }, /* BTRFREQ */ - { STB0899_OFF0_IF_AGC_GAIN , STB0899_BASE_IF_AGC_GAIN , 0x00002ade }, /* IFAGCGAIN */ - { STB0899_OFF0_BB_AGC_GAIN , STB0899_BASE_BB_AGC_GAIN , 0x000001bc }, /* BBAGCGAIN */ - { STB0899_OFF0_DC_OFFSET , STB0899_BASE_DC_OFFSET , 0x00000200 }, /* DCOFFSET */ - { STB0899_OFF0_DMD_CNTRL , STB0899_BASE_DMD_CNTRL , 0x0000000f }, /* DMDCNTRL */ - - { STB0899_OFF0_IF_AGC_CNTRL , STB0899_BASE_IF_AGC_CNTRL , 0x03fb4a20 }, /* IFAGCCNTRL */ - { STB0899_OFF0_BB_AGC_CNTRL , STB0899_BASE_BB_AGC_CNTRL , 0x00200c97 }, /* BBAGCCNTRL */ - - { STB0899_OFF0_CRL_CNTRL , STB0899_BASE_CRL_CNTRL , 0x00000016 }, /* CRLCNTRL */ - { STB0899_OFF0_CRL_PHS_INIT , STB0899_BASE_CRL_PHS_INIT , 0x00000000 }, /* CRLPHSINIT */ - { STB0899_OFF0_CRL_FREQ_INIT , STB0899_BASE_CRL_FREQ_INIT , 0x00000000 }, /* CRLFREQINIT */ - { STB0899_OFF0_CRL_LOOP_GAIN , STB0899_BASE_CRL_LOOP_GAIN , 0x00000000 }, /* CRLLOOPGAIN */ - { STB0899_OFF0_CRL_NOM_FREQ , STB0899_BASE_CRL_NOM_FREQ , 0x3ed097b6 }, /* CRLNOMFREQ */ - { STB0899_OFF0_CRL_SWP_RATE , STB0899_BASE_CRL_SWP_RATE , 0x00000000 }, /* CRLSWPRATE */ - { STB0899_OFF0_CRL_MAX_SWP , STB0899_BASE_CRL_MAX_SWP , 0x00000000 }, /* CRLMAXSWP */ - { STB0899_OFF0_CRL_LK_CNTRL , STB0899_BASE_CRL_LK_CNTRL , 0x0f6cdc01 }, /* CRLLKCNTRL */ - { STB0899_OFF0_DECIM_CNTRL , STB0899_BASE_DECIM_CNTRL , 0x00000000 }, /* DECIMCNTRL */ - { STB0899_OFF0_BTR_CNTRL , STB0899_BASE_BTR_CNTRL , 0x00003993 }, /* BTRCNTRL */ - { STB0899_OFF0_BTR_LOOP_GAIN , STB0899_BASE_BTR_LOOP_GAIN , 0x000d3c6f }, /* BTRLOOPGAIN */ - { STB0899_OFF0_BTR_PHS_INIT , STB0899_BASE_BTR_PHS_INIT , 0x00000000 }, /* BTRPHSINIT */ - { STB0899_OFF0_BTR_FREQ_INIT , STB0899_BASE_BTR_FREQ_INIT , 0x00000000 }, /* BTRFREQINIT */ - { STB0899_OFF0_BTR_NOM_FREQ , STB0899_BASE_BTR_NOM_FREQ , 0x0238e38e }, /* BTRNOMFREQ */ - { STB0899_OFF0_BTR_LK_CNTRL , STB0899_BASE_BTR_LK_CNTRL , 0x00000000 }, /* BTRLKCNTRL */ - { STB0899_OFF0_DECN_CNTRL , STB0899_BASE_DECN_CNTRL , 0x00000000 }, /* DECNCNTRL */ - { STB0899_OFF0_TP_CNTRL , STB0899_BASE_TP_CNTRL , 0x00000000 }, /* TPCNTRL */ - { STB0899_OFF0_TP_BUF_STATUS , STB0899_BASE_TP_BUF_STATUS , 0x00000000 }, /* TPBUFSTATUS */ - { STB0899_OFF0_DC_ESTIM , STB0899_BASE_DC_ESTIM , 0x00000000 }, /* DCESTIM */ - { STB0899_OFF0_FLL_CNTRL , STB0899_BASE_FLL_CNTRL , 0x00000000 }, /* FLLCNTRL */ - { STB0899_OFF0_FLL_FREQ_WD , STB0899_BASE_FLL_FREQ_WD , 0x40070000 }, /* FLLFREQWD */ - { STB0899_OFF0_ANTI_ALIAS_SEL , STB0899_BASE_ANTI_ALIAS_SEL , 0x00000001 }, /* ANTIALIASSEL */ - { STB0899_OFF0_RRC_ALPHA , STB0899_BASE_RRC_ALPHA , 0x00000002 }, /* RRCALPHA */ - { STB0899_OFF0_DC_ADAPT_LSHFT , STB0899_BASE_DC_ADAPT_LSHFT , 0x00000000 }, /* DCADAPTISHFT */ - { STB0899_OFF0_IMB_OFFSET , STB0899_BASE_IMB_OFFSET , 0x0000fe01 }, /* IMBOFFSET */ - { STB0899_OFF0_IMB_ESTIMATE , STB0899_BASE_IMB_ESTIMATE , 0x00000000 }, /* IMBESTIMATE */ - { STB0899_OFF0_IMB_CNTRL , STB0899_BASE_IMB_CNTRL , 0x00000001 }, /* IMBCNTRL */ - { STB0899_OFF0_IF_AGC_CNTRL2 , STB0899_BASE_IF_AGC_CNTRL2 , 0x00005007 }, /* IFAGCCNTRL2 */ - { STB0899_OFF0_DMD_CNTRL2 , STB0899_BASE_DMD_CNTRL2 , 0x00000002 }, /* DMDCNTRL2 */ - { STB0899_OFF0_TP_BUFFER , STB0899_BASE_TP_BUFFER , 0x00000000 }, /* TPBUFFER */ - { STB0899_OFF0_TP_BUFFER1 , STB0899_BASE_TP_BUFFER1 , 0x00000000 }, /* TPBUFFER1 */ - { STB0899_OFF0_TP_BUFFER2 , STB0899_BASE_TP_BUFFER2 , 0x00000000 }, /* TPBUFFER2 */ - { STB0899_OFF0_TP_BUFFER3 , STB0899_BASE_TP_BUFFER3 , 0x00000000 }, /* TPBUFFER3 */ - { STB0899_OFF0_TP_BUFFER4 , STB0899_BASE_TP_BUFFER4 , 0x00000000 }, /* TPBUFFER4 */ - { STB0899_OFF0_TP_BUFFER5 , STB0899_BASE_TP_BUFFER5 , 0x00000000 }, /* TPBUFFER5 */ - { STB0899_OFF0_TP_BUFFER6 , STB0899_BASE_TP_BUFFER6 , 0x00000000 }, /* TPBUFFER6 */ - { STB0899_OFF0_TP_BUFFER7 , STB0899_BASE_TP_BUFFER7 , 0x00000000 }, /* TPBUFFER7 */ - { STB0899_OFF0_TP_BUFFER8 , STB0899_BASE_TP_BUFFER8 , 0x00000000 }, /* TPBUFFER8 */ - { STB0899_OFF0_TP_BUFFER9 , STB0899_BASE_TP_BUFFER9 , 0x00000000 }, /* TPBUFFER9 */ - { STB0899_OFF0_TP_BUFFER10 , STB0899_BASE_TP_BUFFER10 , 0x00000000 }, /* TPBUFFER10 */ - { STB0899_OFF0_TP_BUFFER11 , STB0899_BASE_TP_BUFFER11 , 0x00000000 }, /* TPBUFFER11 */ - { STB0899_OFF0_TP_BUFFER12 , STB0899_BASE_TP_BUFFER12 , 0x00000000 }, /* TPBUFFER12 */ - { STB0899_OFF0_TP_BUFFER13 , STB0899_BASE_TP_BUFFER13 , 0x00000000 }, /* TPBUFFER13 */ - { STB0899_OFF0_TP_BUFFER14 , STB0899_BASE_TP_BUFFER14 , 0x00000000 }, /* TPBUFFER14 */ - { STB0899_OFF0_TP_BUFFER15 , STB0899_BASE_TP_BUFFER15 , 0x00000000 }, /* TPBUFFER15 */ - { STB0899_OFF0_TP_BUFFER16 , STB0899_BASE_TP_BUFFER16 , 0x0000ff00 }, /* TPBUFFER16 */ - { STB0899_OFF0_TP_BUFFER17 , STB0899_BASE_TP_BUFFER17 , 0x00000100 }, /* TPBUFFER17 */ - { STB0899_OFF0_TP_BUFFER18 , STB0899_BASE_TP_BUFFER18 , 0x0000fe01 }, /* TPBUFFER18 */ - { STB0899_OFF0_TP_BUFFER19 , STB0899_BASE_TP_BUFFER19 , 0x000004fe }, /* TPBUFFER19 */ - { STB0899_OFF0_TP_BUFFER20 , STB0899_BASE_TP_BUFFER20 , 0x0000cfe7 }, /* TPBUFFER20 */ - { STB0899_OFF0_TP_BUFFER21 , STB0899_BASE_TP_BUFFER21 , 0x0000bec6 }, /* TPBUFFER21 */ - { STB0899_OFF0_TP_BUFFER22 , STB0899_BASE_TP_BUFFER22 , 0x0000c2bf }, /* TPBUFFER22 */ - { STB0899_OFF0_TP_BUFFER23 , STB0899_BASE_TP_BUFFER23 , 0x0000c1c1 }, /* TPBUFFER23 */ - { STB0899_OFF0_TP_BUFFER24 , STB0899_BASE_TP_BUFFER24 , 0x0000c1c1 }, /* TPBUFFER24 */ - { STB0899_OFF0_TP_BUFFER25 , STB0899_BASE_TP_BUFFER25 , 0x0000c1c1 }, /* TPBUFFER25 */ - { STB0899_OFF0_TP_BUFFER26 , STB0899_BASE_TP_BUFFER26 , 0x0000c1c1 }, /* TPBUFFER26 */ - { STB0899_OFF0_TP_BUFFER27 , STB0899_BASE_TP_BUFFER27 , 0x0000c1c0 }, /* TPBUFFER27 */ - { STB0899_OFF0_TP_BUFFER28 , STB0899_BASE_TP_BUFFER28 , 0x0000c0c0 }, /* TPBUFFER28 */ - { STB0899_OFF0_TP_BUFFER29 , STB0899_BASE_TP_BUFFER29 , 0x0000c1c1 }, /* TPBUFFER29 */ - { STB0899_OFF0_TP_BUFFER30 , STB0899_BASE_TP_BUFFER30 , 0x0000c1c1 }, /* TPBUFFER30 */ - { STB0899_OFF0_TP_BUFFER31 , STB0899_BASE_TP_BUFFER31 , 0x0000c0c1 }, /* TPBUFFER31 */ - { STB0899_OFF0_TP_BUFFER32 , STB0899_BASE_TP_BUFFER32 , 0x0000c0c1 }, /* TPBUFFER32 */ - { STB0899_OFF0_TP_BUFFER33 , STB0899_BASE_TP_BUFFER33 , 0x0000c1c1 }, /* TPBUFFER33 */ - { STB0899_OFF0_TP_BUFFER34 , STB0899_BASE_TP_BUFFER34 , 0x0000c1c1 }, /* TPBUFFER34 */ - { STB0899_OFF0_TP_BUFFER35 , STB0899_BASE_TP_BUFFER35 , 0x0000c0c1 }, /* TPBUFFER35 */ - { STB0899_OFF0_TP_BUFFER36 , STB0899_BASE_TP_BUFFER36 , 0x0000c1c1 }, /* TPBUFFER36 */ - { STB0899_OFF0_TP_BUFFER37 , STB0899_BASE_TP_BUFFER37 , 0x0000c0c1 }, /* TPBUFFER37 */ - { STB0899_OFF0_TP_BUFFER38 , STB0899_BASE_TP_BUFFER38 , 0x0000c1c1 }, /* TPBUFFER38 */ - { STB0899_OFF0_TP_BUFFER39 , STB0899_BASE_TP_BUFFER39 , 0x0000c0c0 }, /* TPBUFFER39 */ - { STB0899_OFF0_TP_BUFFER40 , STB0899_BASE_TP_BUFFER40 , 0x0000c1c0 }, /* TPBUFFER40 */ - { STB0899_OFF0_TP_BUFFER41 , STB0899_BASE_TP_BUFFER41 , 0x0000c1c1 }, /* TPBUFFER41 */ - { STB0899_OFF0_TP_BUFFER42 , STB0899_BASE_TP_BUFFER42 , 0x0000c0c0 }, /* TPBUFFER42 */ - { STB0899_OFF0_TP_BUFFER43 , STB0899_BASE_TP_BUFFER43 , 0x0000c1c0 }, /* TPBUFFER43 */ - { STB0899_OFF0_TP_BUFFER44 , STB0899_BASE_TP_BUFFER44 , 0x0000c0c1 }, /* TPBUFFER44 */ - { STB0899_OFF0_TP_BUFFER45 , STB0899_BASE_TP_BUFFER45 , 0x0000c1be }, /* TPBUFFER45 */ - { STB0899_OFF0_TP_BUFFER46 , STB0899_BASE_TP_BUFFER46 , 0x0000c1c9 }, /* TPBUFFER46 */ - { STB0899_OFF0_TP_BUFFER47 , STB0899_BASE_TP_BUFFER47 , 0x0000c0da }, /* TPBUFFER47 */ - { STB0899_OFF0_TP_BUFFER48 , STB0899_BASE_TP_BUFFER48 , 0x0000c0ba }, /* TPBUFFER48 */ - { STB0899_OFF0_TP_BUFFER49 , STB0899_BASE_TP_BUFFER49 , 0x0000c1c4 }, /* TPBUFFER49 */ - { STB0899_OFF0_TP_BUFFER50 , STB0899_BASE_TP_BUFFER50 , 0x0000c1bf }, /* TPBUFFER50 */ - { STB0899_OFF0_TP_BUFFER51 , STB0899_BASE_TP_BUFFER51 , 0x0000c0c1 }, /* TPBUFFER51 */ - { STB0899_OFF0_TP_BUFFER52 , STB0899_BASE_TP_BUFFER52 , 0x0000c1c0 }, /* TPBUFFER52 */ - { STB0899_OFF0_TP_BUFFER53 , STB0899_BASE_TP_BUFFER53 , 0x0000c0c1 }, /* TPBUFFER53 */ - { STB0899_OFF0_TP_BUFFER54 , STB0899_BASE_TP_BUFFER54 , 0x0000c1c1 }, /* TPBUFFER54 */ - { STB0899_OFF0_TP_BUFFER55 , STB0899_BASE_TP_BUFFER55 , 0x0000c1c1 }, /* TPBUFFER55 */ - { STB0899_OFF0_TP_BUFFER56 , STB0899_BASE_TP_BUFFER56 , 0x0000c1c1 }, /* TPBUFFER56 */ - { STB0899_OFF0_TP_BUFFER57 , STB0899_BASE_TP_BUFFER57 , 0x0000c1c1 }, /* TPBUFFER57 */ - { STB0899_OFF0_TP_BUFFER58 , STB0899_BASE_TP_BUFFER58 , 0x0000c1c1 }, /* TPBUFFER58 */ - { STB0899_OFF0_TP_BUFFER59 , STB0899_BASE_TP_BUFFER59 , 0x0000c1c1 }, /* TPBUFFER59 */ - { STB0899_OFF0_TP_BUFFER60 , STB0899_BASE_TP_BUFFER60 , 0x0000c1c1 }, /* TPBUFFER60 */ - { STB0899_OFF0_TP_BUFFER61 , STB0899_BASE_TP_BUFFER61 , 0x0000c1c1 }, /* TPBUFFER61 */ - { STB0899_OFF0_TP_BUFFER62 , STB0899_BASE_TP_BUFFER62 , 0x0000c1c1 }, /* TPBUFFER62 */ - { STB0899_OFF0_TP_BUFFER63 , STB0899_BASE_TP_BUFFER63 , 0x0000c1c0 }, /* TPBUFFER63 */ - { STB0899_OFF0_RESET_CNTRL , STB0899_BASE_RESET_CNTRL , 0x00000001 }, /* RESETCNTRL */ - { STB0899_OFF0_ACM_ENABLE , STB0899_BASE_ACM_ENABLE , 0x00005654 }, /* ACMENABLE */ - { STB0899_OFF0_DESCR_CNTRL , STB0899_BASE_DESCR_CNTRL , 0x00000000 }, /* DESCRCNTRL */ - { STB0899_OFF0_CSM_CNTRL1 , STB0899_BASE_CSM_CNTRL1 , 0x00020019 }, /* CSMCNTRL1 */ - { STB0899_OFF0_CSM_CNTRL2 , STB0899_BASE_CSM_CNTRL2 , 0x004b3237 }, /* CSMCNTRL2 */ - { STB0899_OFF0_CSM_CNTRL3 , STB0899_BASE_CSM_CNTRL3 , 0x0003dd17 }, /* CSMCNTRL3 */ - { STB0899_OFF0_CSM_CNTRL4 , STB0899_BASE_CSM_CNTRL4 , 0x00008008 }, /* CSMCNTRL4 */ - { STB0899_OFF0_UWP_CNTRL1 , STB0899_BASE_UWP_CNTRL1 , 0x002a3106 }, /* UWPCNTRL1 */ - { STB0899_OFF0_UWP_CNTRL2 , STB0899_BASE_UWP_CNTRL2 , 0x0006140a }, /* UWPCNTRL2 */ - { STB0899_OFF0_UWP_STAT1 , STB0899_BASE_UWP_STAT1 , 0x00008000 }, /* UWPSTAT1 */ - { STB0899_OFF0_UWP_STAT2 , STB0899_BASE_UWP_STAT2 , 0x00000000 }, /* UWPSTAT2 */ - { STB0899_OFF0_DMD_STAT2 , STB0899_BASE_DMD_STAT2 , 0x00000000 }, /* DMDSTAT2 */ - { STB0899_OFF0_FREQ_ADJ_SCALE , STB0899_BASE_FREQ_ADJ_SCALE , 0x00000471 }, /* FREQADJSCALE */ - { STB0899_OFF0_UWP_CNTRL3 , STB0899_BASE_UWP_CNTRL3 , 0x017b0465 }, /* UWPCNTRL3 */ - { STB0899_OFF0_SYM_CLK_SEL , STB0899_BASE_SYM_CLK_SEL , 0x00000002 }, /* SYMCLKSEL */ - { STB0899_OFF0_SOF_SRCH_TO , STB0899_BASE_SOF_SRCH_TO , 0x00196464 }, /* SOFSRCHTO */ - { STB0899_OFF0_ACQ_CNTRL1 , STB0899_BASE_ACQ_CNTRL1 , 0x00000603 }, /* ACQCNTRL1 */ - { STB0899_OFF0_ACQ_CNTRL2 , STB0899_BASE_ACQ_CNTRL2 , 0x02046666 }, /* ACQCNTRL2 */ - { STB0899_OFF0_ACQ_CNTRL3 , STB0899_BASE_ACQ_CNTRL3 , 0x10046583 }, /* ACQCNTRL3 */ - { STB0899_OFF0_FE_SETTLE , STB0899_BASE_FE_SETTLE , 0x00010404 }, /* FESETTLE */ - { STB0899_OFF0_AC_DWELL , STB0899_BASE_AC_DWELL , 0x0002aa8a }, /* ACDWELL */ - { STB0899_OFF0_ACQUIRE_TRIG , STB0899_BASE_ACQUIRE_TRIG , 0x00000000 }, /* ACQUIRETRIG */ - { STB0899_OFF0_LOCK_LOST , STB0899_BASE_LOCK_LOST , 0x00000001 }, /* LOCKLOST */ - { STB0899_OFF0_ACQ_STAT1 , STB0899_BASE_ACQ_STAT1 , 0x00000500 }, /* ACQSTAT1 */ - { STB0899_OFF0_ACQ_TIMEOUT , STB0899_BASE_ACQ_TIMEOUT , 0x0028a0a0 }, /* ACQTIMEOUT */ - { STB0899_OFF0_ACQ_TIME , STB0899_BASE_ACQ_TIME , 0x00000000 }, /* ACQTIME */ - { STB0899_OFF0_FINAL_AGC_CNTRL , STB0899_BASE_FINAL_AGC_CNTRL , 0x00800c17 }, /* FINALAGCCNTRL*/ - { STB0899_OFF0_FINAL_AGC_GAIN , STB0899_BASE_FINAL_AGC_GAIN , 0x00000000 }, /* FINALAGCCGAIN*/ - { STB0899_OFF0_EQUALIZER_INIT , STB0899_BASE_EQUALIZER_INIT , 0x00000000 }, /* EQUILIZERINIT*/ - { STB0899_OFF0_EQ_CNTRL , STB0899_BASE_EQ_CNTRL , 0x00054802 }, /* EQCNTL */ - { STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF0 */ - { STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF1 */ - { STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF2 */ - { STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF3 */ - { STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF4 */ - { STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 }, /* EQIINITCOEFF5 */ - { STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF6 */ - { STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF7 */ - { STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF8 */ - { STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF9 */ - { STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF10*/ - { STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF0 */ - { STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF1 */ - { STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF2 */ - { STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF3 */ - { STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF4 */ - { STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF5 */ - { STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF6 */ - { STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF7 */ - { STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF8 */ - { STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF9 */ - { STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF10*/ - { STB0899_OFF0_EQ_I_OUT_COEFF_0 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT0 */ - { STB0899_OFF1_EQ_I_OUT_COEFF_1 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT1 */ - { STB0899_OFF2_EQ_I_OUT_COEFF_2 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT2 */ - { STB0899_OFF3_EQ_I_OUT_COEFF_3 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT3 */ - { STB0899_OFF4_EQ_I_OUT_COEFF_4 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT4 */ - { STB0899_OFF5_EQ_I_OUT_COEFF_5 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT5 */ - { STB0899_OFF6_EQ_I_OUT_COEFF_6 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT6 */ - { STB0899_OFF7_EQ_I_OUT_COEFF_7 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT7 */ - { STB0899_OFF8_EQ_I_OUT_COEFF_8 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT8 */ - { STB0899_OFF9_EQ_I_OUT_COEFF_9 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT9 */ - { STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT10*/ - { STB0899_OFF0_EQ_Q_OUT_COEFF_0 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT0 */ - { STB0899_OFF1_EQ_Q_OUT_COEFF_1 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT1 */ - { STB0899_OFF2_EQ_Q_OUT_COEFF_2 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT2 */ - { STB0899_OFF3_EQ_Q_OUT_COEFF_3 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT3 */ - { STB0899_OFF4_EQ_Q_OUT_COEFF_4 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT4 */ - { STB0899_OFF5_EQ_Q_OUT_COEFF_5 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT5 */ - { STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT6 */ - { STB0899_OFF7_EQ_Q_OUT_COEFF_7 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT7 */ - { STB0899_OFF8_EQ_Q_OUT_COEFF_8 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT8 */ - { STB0899_OFF9_EQ_Q_OUT_COEFF_9 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT9 */ - { STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT10*/ - { 0xffff , 0xffffffff , 0xffffffff }, -}; -static const struct stb0899_s2_reg stb0899_s2_init_4[] = { - { STB0899_OFF0_BLOCK_LNGTH , STB0899_BASE_BLOCK_LNGTH , 0x00000008 }, /* BLOCKLNGTH */ - { STB0899_OFF0_ROW_STR , STB0899_BASE_ROW_STR , 0x000000b4 }, /* ROWSTR */ - { STB0899_OFF0_BN_END_ADDR , STB0899_BASE_BN_END_ADDR , 0x000004b5 }, /* BNANDADDR */ - { STB0899_OFF0_CN_END_ADDR , STB0899_BASE_CN_END_ADDR , 0x00000b4b }, /* CNANDADDR */ - { STB0899_OFF0_INFO_LENGTH , STB0899_BASE_INFO_LENGTH , 0x00000078 }, /* INFOLENGTH */ - { STB0899_OFF0_BOT_ADDR , STB0899_BASE_BOT_ADDR , 0x000001e0 }, /* BOT_ADDR */ - { STB0899_OFF0_BCH_BLK_LN , STB0899_BASE_BCH_BLK_LN , 0x0000a8c0 }, /* BCHBLKLN */ - { STB0899_OFF0_BCH_T , STB0899_BASE_BCH_T , 0x0000000c }, /* BCHT */ - { STB0899_OFF0_CNFG_MODE , STB0899_BASE_CNFG_MODE , 0x00000001 }, /* CNFGMODE */ - { STB0899_OFF0_LDPC_STAT , STB0899_BASE_LDPC_STAT , 0x0000000d }, /* LDPCSTAT */ - { STB0899_OFF0_ITER_SCALE , STB0899_BASE_ITER_SCALE , 0x00000040 }, /* ITERSCALE */ - { STB0899_OFF0_INPUT_MODE , STB0899_BASE_INPUT_MODE , 0x00000000 }, /* INPUTMODE */ - { STB0899_OFF0_LDPCDECRST , STB0899_BASE_LDPCDECRST , 0x00000000 }, /* LDPCDECRST */ - { STB0899_OFF0_CLK_PER_BYTE_RW , STB0899_BASE_CLK_PER_BYTE_RW , 0x00000008 }, /* CLKPERBYTE */ - { STB0899_OFF0_BCH_ERRORS , STB0899_BASE_BCH_ERRORS , 0x00000000 }, /* BCHERRORS */ - { STB0899_OFF0_LDPC_ERRORS , STB0899_BASE_LDPC_ERRORS , 0x00000000 }, /* LDPCERRORS */ - { STB0899_OFF0_BCH_MODE , STB0899_BASE_BCH_MODE , 0x00000000 }, /* BCHMODE */ - { STB0899_OFF0_ERR_ACC_PER , STB0899_BASE_ERR_ACC_PER , 0x00000008 }, /* ERRACCPER */ - { STB0899_OFF0_BCH_ERR_ACC , STB0899_BASE_BCH_ERR_ACC , 0x00000000 }, /* BCHERRACC */ - { STB0899_OFF0_FEC_TP_SEL , STB0899_BASE_FEC_TP_SEL , 0x00000000 }, /* FECTPSEL */ - { 0xffff , 0xffffffff , 0xffffffff }, -}; - -static const struct stb0899_s1_reg stb0899_s1_init_5[] = { - { STB0899_TSTCK , 0x00 }, - { STB0899_TSTRES , 0x00 }, - { STB0899_TSTOUT , 0x00 }, - { STB0899_TSTIN , 0x00 }, - { STB0899_TSTSYS , 0x00 }, - { STB0899_TSTCHIP , 0x00 }, - { STB0899_TSTFREE , 0x00 }, - { STB0899_TSTI2C , 0x00 }, - { STB0899_BITSPEEDM , 0x00 }, - { STB0899_BITSPEEDL , 0x00 }, - { STB0899_TBUSBIT , 0x00 }, - { STB0899_TSTDIS , 0x00 }, - { STB0899_TSTDISRX , 0x00 }, - { STB0899_TSTJETON , 0x00 }, - { STB0899_TSTDCADJ , 0x00 }, - { STB0899_TSTAGC1 , 0x00 }, - { STB0899_TSTAGC1N , 0x00 }, - { STB0899_TSTPOLYPH , 0x00 }, - { STB0899_TSTR , 0x00 }, - { STB0899_TSTAGC2 , 0x00 }, - { STB0899_TSTCTL1 , 0x00 }, - { STB0899_TSTCTL2 , 0x00 }, - { STB0899_TSTCTL3 , 0x00 }, - { STB0899_TSTDEMAP , 0x00 }, - { STB0899_TSTDEMAP2 , 0x00 }, - { STB0899_TSTDEMMON , 0x00 }, - { STB0899_TSTRATE , 0x00 }, - { STB0899_TSTSELOUT , 0x00 }, - { STB0899_TSYNC , 0x00 }, - { STB0899_TSTERR , 0x00 }, - { STB0899_TSTRAM1 , 0x00 }, - { STB0899_TSTVSELOUT , 0x00 }, - { STB0899_TSTFORCEIN , 0x00 }, - { STB0899_TSTRS1 , 0x00 }, - { STB0899_TSTRS2 , 0x00 }, - { STB0899_TSTRS3 , 0x00 }, - { STB0899_GHOSTREG , 0x81 }, - { 0xffff , 0xff }, -}; - -#define STB0899_DVBS2_ESNO_AVE 3 -#define STB0899_DVBS2_ESNO_QUANT 32 -#define STB0899_DVBS2_AVFRAMES_COARSE 10 -#define STB0899_DVBS2_AVFRAMES_FINE 20 -#define STB0899_DVBS2_MISS_THRESHOLD 6 -#define STB0899_DVBS2_UWP_THRESHOLD_ACQ 1125 -#define STB0899_DVBS2_UWP_THRESHOLD_TRACK 758 -#define STB0899_DVBS2_UWP_THRESHOLD_SOF 1350 -#define STB0899_DVBS2_SOF_SEARCH_TIMEOUT 1664100 - -#define STB0899_DVBS2_BTR_NCO_BITS 28 -#define STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET 15 -#define STB0899_DVBS2_CRL_NCO_BITS 30 -#define STB0899_DVBS2_LDPC_MAX_ITER 70 - -#endif //__STB0899_CFG_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_drv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_drv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_drv.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_drv.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1686 +0,0 @@ -/* - STB0899 Multistandard Frontend driver - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include - -#include -#include "dvb_frontend.h" - -#include "stb0899_drv.h" -#include "stb0899_priv.h" -#include "stb0899_reg.h" - -static unsigned int verbose = 0;//1; -module_param(verbose, int, 0644); - -/* C/N in dB/10, NIRM/NIRL */ -static const struct stb0899_tab stb0899_cn_tab[] = { - { 200, 2600 }, - { 190, 2700 }, - { 180, 2860 }, - { 170, 3020 }, - { 160, 3210 }, - { 150, 3440 }, - { 140, 3710 }, - { 130, 4010 }, - { 120, 4360 }, - { 110, 4740 }, - { 100, 5190 }, - { 90, 5670 }, - { 80, 6200 }, - { 70, 6770 }, - { 60, 7360 }, - { 50, 7970 }, - { 40, 8250 }, - { 30, 9000 }, - { 20, 9450 }, - { 15, 9600 }, -}; - -/* DVB-S AGCIQ_VALUE vs. signal level in dBm/10. - * As measured, connected to a modulator. - * -8.0 to -50.0 dBm directly connected, - * -52.0 to -74.8 with extra attenuation. - * Cut-off to AGCIQ_VALUE = 0x80 below -74.8dBm. - * Crude linear extrapolation below -84.8dBm and above -8.0dBm. - */ -static const struct stb0899_tab stb0899_dvbsrf_tab[] = { - { -950, -128 }, - { -748, -94 }, - { -745, -92 }, - { -735, -90 }, - { -720, -87 }, - { -670, -77 }, - { -640, -70 }, - { -610, -62 }, - { -600, -60 }, - { -590, -56 }, - { -560, -41 }, - { -540, -25 }, - { -530, -17 }, - { -520, -11 }, - { -500, 1 }, - { -490, 6 }, - { -480, 10 }, - { -440, 22 }, - { -420, 27 }, - { -400, 31 }, - { -380, 34 }, - { -340, 40 }, - { -320, 43 }, - { -280, 48 }, - { -250, 52 }, - { -230, 55 }, - { -180, 61 }, - { -140, 66 }, - { -90, 73 }, - { -80, 74 }, - { 500, 127 } -}; - -/* DVB-S2 IF_AGC_GAIN vs. signal level in dBm/10. - * As measured, connected to a modulator. - * -8.0 to -50.1 dBm directly connected, - * -53.0 to -76.6 with extra attenuation. - * Cut-off to IF_AGC_GAIN = 0x3fff below -76.6dBm. - * Crude linear extrapolation below -76.6dBm and above -8.0dBm. - */ -static const struct stb0899_tab stb0899_dvbs2rf_tab[] = { - { 700, 0 }, - { -80, 3217 }, - { -150, 3893 }, - { -190, 4217 }, - { -240, 4621 }, - { -280, 4945 }, - { -320, 5273 }, - { -350, 5545 }, - { -370, 5741 }, - { -410, 6147 }, - { -450, 6671 }, - { -490, 7413 }, - { -501, 7665 }, - { -530, 8767 }, - { -560, 10219 }, - { -580, 10939 }, - { -590, 11518 }, - { -600, 11723 }, - { -650, 12659 }, - { -690, 13219 }, - { -730, 13645 }, - { -750, 13909 }, - { -766, 14153 }, - { -999, 16383 } -}; - -/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/ -static struct stb0899_tab stb0899_quant_tab[] = { - { 0, 0 }, - { 0, 100 }, - { 600, 200 }, - { 950, 299 }, - { 1200, 398 }, - { 1400, 501 }, - { 1560, 603 }, - { 1690, 700 }, - { 1810, 804 }, - { 1910, 902 }, - { 2000, 1000 }, - { 2080, 1096 }, - { 2160, 1202 }, - { 2230, 1303 }, - { 2350, 1496 }, - { 2410, 1603 }, - { 2460, 1698 }, - { 2510, 1799 }, - { 2600, 1995 }, - { 2650, 2113 }, - { 2690, 2213 }, - { 2720, 2291 }, - { 2760, 2399 }, - { 2800, 2512 }, - { 2860, 2692 }, - { 2930, 2917 }, - { 2960, 3020 }, - { 3010, 3199 }, - { 3040, 3311 }, - { 3060, 3388 }, - { 3120, 3631 }, - { 3190, 3936 }, - { 3400, 5012 }, - { 3610, 6383 }, - { 3800, 7943 }, - { 4210, 12735 }, - { 4500, 17783 }, - { 4690, 22131 }, - { 4810, 25410 } -}; - -/* DVB-S2 Es/N0 estimate in dB/100 vs read value */ -static struct stb0899_tab stb0899_est_tab[] = { - { 0, 0 }, - { 0, 1 }, - { 301, 2 }, - { 1204, 16 }, - { 1806, 64 }, - { 2408, 256 }, - { 2709, 512 }, - { 3010, 1023 }, - { 3311, 2046 }, - { 3612, 4093 }, - { 3823, 6653 }, - { 3913, 8185 }, - { 4010, 10233 }, - { 4107, 12794 }, - { 4214, 16368 }, - { 4266, 18450 }, - { 4311, 20464 }, - { 4353, 22542 }, - { 4391, 24604 }, - { 4425, 26607 }, - { 4457, 28642 }, - { 4487, 30690 }, - { 4515, 32734 }, - { 4612, 40926 }, - { 4692, 49204 }, - { 4816, 65464 }, - { 4913, 81846 }, - { 4993, 98401 }, - { 5060, 114815 }, - { 5118, 131220 }, - { 5200, 158489 }, - { 5300, 199526 }, - { 5400, 251189 }, - { 5500, 316228 }, - { 5600, 398107 }, - { 5720, 524807 }, - { 5721, 526017 }, -}; - -static int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg) -{ - int ret; - - u8 b0[] = { reg >> 8, reg & 0xff }; - u8 buf; - - struct i2c_msg msg[] = { - { - .addr = state->config->demod_address, - .flags = 0, - .buf = b0, - .len = 2 - },{ - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = &buf, - .len = 1 - } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - if (ret != 2) { - if (ret != -ERESTARTSYS) - dprintk(state->verbose, FE_ERROR, 1, - "Read error, Reg=[0x%02x], Status=%d", - reg, ret); - - return ret < 0 ? ret : -EREMOTEIO; - } - if (unlikely(*state->verbose >= FE_DEBUGREG)) - dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%02x], data=%02x", - reg, buf); - - return (unsigned int)buf; -} - -int stb0899_read_reg(struct stb0899_state *state, unsigned int reg) -{ - int result; - - result = _stb0899_read_reg(state, reg); - /* - * Bug ID 9: - * access to 0xf2xx/0xf6xx - * must be followed by read from 0xf2ff/0xf6ff. - */ - if ((reg != 0xf2ff) && (reg != 0xf6ff) && - (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) - _stb0899_read_reg(state, (reg | 0x00ff)); - - return result; -} - -u32 _stb0899_read_s2reg(struct stb0899_state *state, - u32 stb0899_i2cdev, - u32 stb0899_base_addr, - u16 stb0899_reg_offset) -{ - int status; - u32 data; - u8 buf[7] = { 0 }; - u16 tmpaddr; - - u8 buf_0[] = { - GETBYTE(stb0899_i2cdev, BYTE1), /* 0xf3 S2 Base Address (MSB) */ - GETBYTE(stb0899_i2cdev, BYTE0), /* 0xfc S2 Base Address (LSB) */ - GETBYTE(stb0899_base_addr, BYTE0), /* 0x00 Base Address (LSB) */ - GETBYTE(stb0899_base_addr, BYTE1), /* 0x04 Base Address (LSB) */ - GETBYTE(stb0899_base_addr, BYTE2), /* 0x00 Base Address (MSB) */ - GETBYTE(stb0899_base_addr, BYTE3), /* 0x00 Base Address (MSB) */ - }; - u8 buf_1[] = { - 0x00, /* 0xf3 Reg Offset */ - 0x00, /* 0x44 Reg Offset */ - }; - - struct i2c_msg msg_0 = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf_0, - .len = 6 - }; - - struct i2c_msg msg_1 = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf_1, - .len = 2 - }; - - struct i2c_msg msg_r = { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = buf, - .len = 4 - }; - - tmpaddr = stb0899_reg_offset & 0xff00; - if (!(stb0899_reg_offset & 0x8)) - tmpaddr = stb0899_reg_offset | 0x20; - - buf_1[0] = GETBYTE(tmpaddr, BYTE1); - buf_1[1] = GETBYTE(tmpaddr, BYTE0); - - status = i2c_transfer(state->i2c, &msg_0, 1); - if (status < 1) { - if (status != -ERESTARTSYS) - printk(KERN_ERR "%s ERR(1), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", - __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); - - goto err; - } - - /* Dummy */ - status = i2c_transfer(state->i2c, &msg_1, 1); - if (status < 1) - goto err; - - status = i2c_transfer(state->i2c, &msg_r, 1); - if (status < 1) - goto err; - - buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1); - buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0); - - /* Actual */ - status = i2c_transfer(state->i2c, &msg_1, 1); - if (status < 1) { - if (status != -ERESTARTSYS) - printk(KERN_ERR "%s ERR(2), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", - __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); - goto err; - } - - status = i2c_transfer(state->i2c, &msg_r, 1); - if (status < 1) { - if (status != -ERESTARTSYS) - printk(KERN_ERR "%s ERR(3), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", - __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); - return status < 0 ? status : -EREMOTEIO; - } - - data = MAKEWORD32(buf[3], buf[2], buf[1], buf[0]); - if (unlikely(*state->verbose >= FE_DEBUGREG)) - printk(KERN_DEBUG "%s Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n", - __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, data); - - return data; - -err: - return status < 0 ? status : -EREMOTEIO; -} - -int stb0899_write_s2reg(struct stb0899_state *state, - u32 stb0899_i2cdev, - u32 stb0899_base_addr, - u16 stb0899_reg_offset, - u32 stb0899_data) -{ - int status; - - /* Base Address Setup */ - u8 buf_0[] = { - GETBYTE(stb0899_i2cdev, BYTE1), /* 0xf3 S2 Base Address (MSB) */ - GETBYTE(stb0899_i2cdev, BYTE0), /* 0xfc S2 Base Address (LSB) */ - GETBYTE(stb0899_base_addr, BYTE0), /* 0x00 Base Address (LSB) */ - GETBYTE(stb0899_base_addr, BYTE1), /* 0x04 Base Address (LSB) */ - GETBYTE(stb0899_base_addr, BYTE2), /* 0x00 Base Address (MSB) */ - GETBYTE(stb0899_base_addr, BYTE3), /* 0x00 Base Address (MSB) */ - }; - u8 buf_1[] = { - 0x00, /* 0xf3 Reg Offset */ - 0x00, /* 0x44 Reg Offset */ - 0x00, /* data */ - 0x00, /* data */ - 0x00, /* data */ - 0x00, /* data */ - }; - - struct i2c_msg msg_0 = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf_0, - .len = 6 - }; - - struct i2c_msg msg_1 = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf_1, - .len = 6 - }; - - buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1); - buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0); - buf_1[2] = GETBYTE(stb0899_data, BYTE0); - buf_1[3] = GETBYTE(stb0899_data, BYTE1); - buf_1[4] = GETBYTE(stb0899_data, BYTE2); - buf_1[5] = GETBYTE(stb0899_data, BYTE3); - - if (unlikely(*state->verbose >= FE_DEBUGREG)) - printk(KERN_DEBUG "%s Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n", - __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data); - - status = i2c_transfer(state->i2c, &msg_0, 1); - if (unlikely(status < 1)) { - if (status != -ERESTARTSYS) - printk(KERN_ERR "%s ERR (1), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n", - __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status); - goto err; - } - status = i2c_transfer(state->i2c, &msg_1, 1); - if (unlikely(status < 1)) { - if (status != -ERESTARTSYS) - printk(KERN_ERR "%s ERR (2), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n", - __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status); - - return status < 0 ? status : -EREMOTEIO; - } - - return 0; - -err: - return status < 0 ? status : -EREMOTEIO; -} - -int stb0899_read_regs(struct stb0899_state *state, unsigned int reg, u8 *buf, u32 count) -{ - int status; - - u8 b0[] = { reg >> 8, reg & 0xff }; - - struct i2c_msg msg[] = { - { - .addr = state->config->demod_address, - .flags = 0, - .buf = b0, - .len = 2 - },{ - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = buf, - .len = count - } - }; - - status = i2c_transfer(state->i2c, msg, 2); - if (status != 2) { - if (status != -ERESTARTSYS) - printk(KERN_ERR "%s Read error, Reg=[0x%04x], Count=%u, Status=%d\n", - __func__, reg, count, status); - goto err; - } - /* - * Bug ID 9: - * access to 0xf2xx/0xf6xx - * must be followed by read from 0xf2ff/0xf6ff. - */ - if ((reg != 0xf2ff) && (reg != 0xf6ff) && - (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) - _stb0899_read_reg(state, (reg | 0x00ff)); - - if (unlikely(*state->verbose >= FE_DEBUGREG)) { - int i; - - printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); - for (i = 0; i < count; i++) { - printk(" %02x", buf[i]); - } - printk("\n"); - } - - return 0; -err: - return status < 0 ? status : -EREMOTEIO; -} - -int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, u32 count) -{ - int ret; - u8 buf[2 + count]; - struct i2c_msg i2c_msg = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf, - .len = 2 + count - }; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - memcpy(&buf[2], data, count); - - if (unlikely(*state->verbose >= FE_DEBUGREG)) { - int i; - - printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); - for (i = 0; i < count; i++) - printk(" %02x", data[i]); - printk("\n"); - } - ret = i2c_transfer(state->i2c, &i2c_msg, 1); - - /* - * Bug ID 9: - * access to 0xf2xx/0xf6xx - * must be followed by read from 0xf2ff/0xf6ff. - */ - if ((((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) - stb0899_read_reg(state, (reg | 0x00ff)); - - if (ret != 1) { - if (ret != -ERESTARTSYS) - dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d", - reg, data[0], count, ret); - return ret < 0 ? ret : -EREMOTEIO; - } - - return 0; -} - -int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data) -{ - return stb0899_write_regs(state, reg, &data, 1); -} - -/* - * stb0899_get_mclk - * Get STB0899 master clock frequency - * ExtClk: external clock frequency (Hz) - */ -static u32 stb0899_get_mclk(struct stb0899_state *state) -{ - u32 mclk = 0, div = 0; - - div = stb0899_read_reg(state, STB0899_NCOARSE); - mclk = (div + 1) * state->config->xtal_freq / 6; - dprintk(state->verbose, FE_DEBUG, 1, "div=%d, mclk=%d", div, mclk); - - return mclk; -} - -/* - * stb0899_set_mclk - * Set STB0899 master Clock frequency - * Mclk: demodulator master clock - * ExtClk: external clock frequency (Hz) - */ -static void stb0899_set_mclk(struct stb0899_state *state, u32 Mclk) -{ - struct stb0899_internal *internal = &state->internal; - u8 mdiv = 0; - - dprintk(state->verbose, FE_DEBUG, 1, "state->config=%p", state->config); - mdiv = ((6 * Mclk) / state->config->xtal_freq) - 1; - dprintk(state->verbose, FE_DEBUG, 1, "mdiv=%d", mdiv); - - stb0899_write_reg(state, STB0899_NCOARSE, mdiv); - internal->master_clk = stb0899_get_mclk(state); - - dprintk(state->verbose, FE_DEBUG, 1, "MasterCLOCK=%d", internal->master_clk); -} - -static int stb0899_postproc(struct stb0899_state *state, u8 ctl, int enable) -{ - struct stb0899_config *config = state->config; - const struct stb0899_postproc *postproc = config->postproc; - - /* post process event */ - if (postproc) { - if (enable) { - if (postproc[ctl].level == STB0899_GPIOPULLUP) - stb0899_write_reg(state, postproc[ctl].gpio, 0x02); - else - stb0899_write_reg(state, postproc[ctl].gpio, 0x82); - } else { - if (postproc[ctl].level == STB0899_GPIOPULLUP) - stb0899_write_reg(state, postproc[ctl].gpio, 0x82); - else - stb0899_write_reg(state, postproc[ctl].gpio, 0x02); - } - } - return 0; -} - -static void stb0899_release(struct dvb_frontend *fe) -{ - struct stb0899_state *state = fe->demodulator_priv; - - dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend"); - /* post process event */ - stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0); - kfree(state); -} - -/* - * stb0899_get_alpha - * return: rolloff - */ -static int stb0899_get_alpha(struct stb0899_state *state) -{ - u8 mode_coeff; - - mode_coeff = stb0899_read_reg(state, STB0899_DEMOD); - - if (STB0899_GETFIELD(MODECOEFF, mode_coeff) == 1) - return 20; - else - return 35; -} - -/* - * stb0899_init_calc - */ -static void stb0899_init_calc(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - int master_clk; - u8 agc[2]; - u8 agc1cn; - u32 reg; - - /* Read registers (in burst mode) */ - agc1cn = stb0899_read_reg(state, STB0899_AGC1CN); - stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O */ - - /* Initial calculations */ - master_clk = stb0899_get_mclk(state); - internal->t_agc1 = 0; - internal->t_agc2 = 0; - internal->master_clk = master_clk; - internal->mclk = master_clk / 65536L; - internal->rolloff = stb0899_get_alpha(state); - - /* DVBS2 Initial calculations */ - /* Set AGC value to the middle */ - internal->agc_gain = 8154; - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); - STB0899_SETFIELD_VAL(IF_GAIN_INIT, reg, internal->agc_gain); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, RRC_ALPHA); - internal->rrc_alpha = STB0899_GETFIELD(RRC_ALPHA, reg); - - internal->center_freq = 0; - internal->av_frame_coarse = 10; - internal->av_frame_fine = 20; - internal->step_size = 2; -/* - if ((pParams->SpectralInv == FE_IQ_NORMAL) || (pParams->SpectralInv == FE_IQ_AUTO)) - pParams->IQLocked = 0; - else - pParams->IQLocked = 1; -*/ -} - -static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeout) -{ - u8 reg = 0; - unsigned long start = jiffies; - - while (1) { - reg = stb0899_read_reg(state, STB0899_DISSTATUS); - if (!STB0899_GETFIELD(FIFOFULL, reg)) - break; - if ((jiffies - start) > timeout) { - dprintk(state->verbose, FE_ERROR, 1, "timed out !!"); - return -ETIMEDOUT; - } - } - - return 0; -} - -static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) -{ - struct stb0899_state *state = fe->demodulator_priv; - u8 reg, i; - - if (cmd->msg_len > 8) - return -EINVAL; - - /* enable FIFO precharge */ - reg = stb0899_read_reg(state, STB0899_DISCNTRL1); - STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 1); - stb0899_write_reg(state, STB0899_DISCNTRL1, reg); - for (i = 0; i < cmd->msg_len; i++) { - /* wait for FIFO empty */ - if (stb0899_wait_diseqc_fifo_empty(state, 10) < 0) - return -ETIMEDOUT; - - stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]); - } - reg = stb0899_read_reg(state, STB0899_DISCNTRL1); - STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0); - stb0899_write_reg(state, STB0899_DISCNTRL1, reg); - msleep(100); - return 0; -} - -static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout) -{ - u8 reg = 0; - unsigned long start = jiffies; - - while (!STB0899_GETFIELD(RXEND, reg)) { - reg = stb0899_read_reg(state, STB0899_DISRX_ST0); - if (jiffies - start > timeout) { - dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); - return -ETIMEDOUT; - } - msleep(10); - } - - return 0; -} - -static int stb0899_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply) -{ - struct stb0899_state *state = fe->demodulator_priv; - u8 reg, length = 0, i; - int result; - - if (stb0899_wait_diseqc_rxidle(state, 100) < 0) - return -ETIMEDOUT; - - reg = stb0899_read_reg(state, STB0899_DISRX_ST0); - if (STB0899_GETFIELD(RXEND, reg)) { - - reg = stb0899_read_reg(state, STB0899_DISRX_ST1); - length = STB0899_GETFIELD(FIFOBYTENBR, reg); - - if (length > sizeof (reply->msg)) { - result = -EOVERFLOW; - goto exit; - } - reply->msg_len = length; - - /* extract data */ - for (i = 0; i < length; i++) - reply->msg[i] = stb0899_read_reg(state, STB0899_DISFIFO); - } - - return 0; -exit: - - return result; -} - -static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout) -{ - u8 reg = 0; - unsigned long start = jiffies; - - while (!STB0899_GETFIELD(TXIDLE, reg)) { - reg = stb0899_read_reg(state, STB0899_DISSTATUS); - if (jiffies - start > timeout) { - dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); - return -ETIMEDOUT; - } - msleep(10); - } - return 0; -} - -static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) -{ - struct stb0899_state *state = fe->demodulator_priv; - u8 reg, old_state; - - /* wait for diseqc idle */ - if (stb0899_wait_diseqc_txidle(state, 100) < 0) - return -ETIMEDOUT; - - reg = stb0899_read_reg(state, STB0899_DISCNTRL1); - old_state = reg; - /* set to burst mode */ - STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x03); - STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x01); - stb0899_write_reg(state, STB0899_DISCNTRL1, reg); - switch (burst) { - case SEC_MINI_A: - /* unmodulated */ - stb0899_write_reg(state, STB0899_DISFIFO, 0x00); - break; - case SEC_MINI_B: - /* modulated */ - stb0899_write_reg(state, STB0899_DISFIFO, 0xff); - break; - } - reg = stb0899_read_reg(state, STB0899_DISCNTRL1); - STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x00); - stb0899_write_reg(state, STB0899_DISCNTRL1, reg); - /* wait for diseqc idle */ - if (stb0899_wait_diseqc_txidle(state, 100) < 0) - return -ETIMEDOUT; - - /* restore state */ - stb0899_write_reg(state, STB0899_DISCNTRL1, old_state); - - return 0; -} - -static int stb0899_diseqc_init(struct stb0899_state *state) -{ - struct dvb_diseqc_master_cmd tx_data; -/* - struct dvb_diseqc_slave_reply rx_data; -*/ - u8 f22_tx, f22_rx, reg; - - u32 mclk, tx_freq = 22000;/* count = 0, i; */ - tx_data.msg[0] = 0xe2; - tx_data.msg_len = 3; - reg = stb0899_read_reg(state, STB0899_DISCNTRL2); - STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0); - stb0899_write_reg(state, STB0899_DISCNTRL2, reg); - - /* disable Tx spy */ - reg = stb0899_read_reg(state, STB0899_DISCNTRL1); - STB0899_SETFIELD_VAL(DISEQCRESET, reg, 1); - stb0899_write_reg(state, STB0899_DISCNTRL1, reg); - - reg = stb0899_read_reg(state, STB0899_DISCNTRL1); - STB0899_SETFIELD_VAL(DISEQCRESET, reg, 0); - stb0899_write_reg(state, STB0899_DISCNTRL1, reg); - - mclk = stb0899_get_mclk(state); - f22_tx = mclk / (tx_freq * 32); - stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq */ - state->rx_freq = 20000; - f22_rx = mclk / (state->rx_freq * 32); - - return 0; -} - -static int stb0899_sleep(struct dvb_frontend *fe) -{ - struct stb0899_state *state = fe->demodulator_priv; -/* - u8 reg; -*/ - dprintk(state->verbose, FE_DEBUG, 1, "Going to Sleep .. (Really tired .. :-))"); - /* post process event */ - stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0); - - return 0; -} - -static int stb0899_wakeup(struct dvb_frontend *fe) -{ - int rc; - struct stb0899_state *state = fe->demodulator_priv; - - if ((rc = stb0899_write_reg(state, STB0899_SYNTCTRL, STB0899_SELOSCI))) - return rc; - /* Activate all clocks; DVB-S2 registers are inaccessible otherwise. */ - if ((rc = stb0899_write_reg(state, STB0899_STOPCLK1, 0x00))) - return rc; - if ((rc = stb0899_write_reg(state, STB0899_STOPCLK2, 0x00))) - return rc; - - /* post process event */ - stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 1); - - return 0; -} - -static int stb0899_init(struct dvb_frontend *fe) -{ - int i; - struct stb0899_state *state = fe->demodulator_priv; - struct stb0899_config *config = state->config; - - dprintk(state->verbose, FE_DEBUG, 1, "Initializing STB0899 ... "); - - /* init device */ - dprintk(state->verbose, FE_DEBUG, 1, "init device"); - for (i = 0; config->init_dev[i].address != 0xffff; i++) - stb0899_write_reg(state, config->init_dev[i].address, config->init_dev[i].data); - - dprintk(state->verbose, FE_DEBUG, 1, "init S2 demod"); - /* init S2 demod */ - for (i = 0; config->init_s2_demod[i].offset != 0xffff; i++) - stb0899_write_s2reg(state, STB0899_S2DEMOD, - config->init_s2_demod[i].base_address, - config->init_s2_demod[i].offset, - config->init_s2_demod[i].data); - - dprintk(state->verbose, FE_DEBUG, 1, "init S1 demod"); - /* init S1 demod */ - for (i = 0; config->init_s1_demod[i].address != 0xffff; i++) - stb0899_write_reg(state, config->init_s1_demod[i].address, config->init_s1_demod[i].data); - - dprintk(state->verbose, FE_DEBUG, 1, "init S2 FEC"); - /* init S2 fec */ - for (i = 0; config->init_s2_fec[i].offset != 0xffff; i++) - stb0899_write_s2reg(state, STB0899_S2FEC, - config->init_s2_fec[i].base_address, - config->init_s2_fec[i].offset, - config->init_s2_fec[i].data); - - dprintk(state->verbose, FE_DEBUG, 1, "init TST"); - /* init test */ - for (i = 0; config->init_tst[i].address != 0xffff; i++) - stb0899_write_reg(state, config->init_tst[i].address, config->init_tst[i].data); - - stb0899_init_calc(state); - stb0899_diseqc_init(state); - - return 0; -} - -static int stb0899_table_lookup(const struct stb0899_tab *tab, int max, int val) -{ - int res = 0; - int min = 0, med; - - if (val < tab[min].read) - res = tab[min].real; - else if (val >= tab[max].read) - res = tab[max].real; - else { - while ((max - min) > 1) { - med = (max + min) / 2; - if (val >= tab[min].read && val < tab[med].read) - max = med; - else - min = med; - } - res = ((val - tab[min].read) * - (tab[max].real - tab[min].real) / - (tab[max].read - tab[min].read)) + - tab[min].real; - } - - return res; -} - -static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct stb0899_state *state = fe->demodulator_priv; - struct stb0899_internal *internal = &state->internal; - - int val; - u32 reg; - switch (state->delsys) { - case SYS_DVBS: - case SYS_DSS: - if (internal->lock) { - reg = stb0899_read_reg(state, STB0899_VSTATUS); - if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { - - reg = stb0899_read_reg(state, STB0899_AGCIQIN); - val = (s32)(s8)STB0899_GETFIELD(AGCIQVALUE, reg); - - *strength = stb0899_table_lookup(stb0899_dvbsrf_tab, ARRAY_SIZE(stb0899_dvbsrf_tab) - 1, val); - *strength += 750; - dprintk(state->verbose, FE_DEBUG, 1, "AGCIQVALUE = 0x%02x, C = %d * 0.1 dBm", - val & 0xff, *strength); - } - } - break; - case SYS_DVBS2: - if (internal->lock) { - reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN); - val = STB0899_GETFIELD(IF_AGC_GAIN, reg); - - *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val); - *strength += 750; - dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm", - val & 0x3fff, *strength); - } - break; - default: - dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); - return -EINVAL; - } - - return 0; -} - -static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct stb0899_state *state = fe->demodulator_priv; - struct stb0899_internal *internal = &state->internal; - - unsigned int val, quant, quantn = -1, est, estn = -1; - u8 buf[2]; - u32 reg; - - reg = stb0899_read_reg(state, STB0899_VSTATUS); - switch (state->delsys) { - case SYS_DVBS: - case SYS_DSS: - if (internal->lock) { - if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { - - stb0899_read_regs(state, STB0899_NIRM, buf, 2); - val = MAKEWORD16(buf[0], buf[1]); - - *snr = stb0899_table_lookup(stb0899_cn_tab, ARRAY_SIZE(stb0899_cn_tab) - 1, val); - dprintk(state->verbose, FE_DEBUG, 1, "NIR = 0x%02x%02x = %u, C/N = %d * 0.1 dBm\n", - buf[0], buf[1], val, *snr); - } - } - break; - case SYS_DVBS2: - if (internal->lock) { - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1); - quant = STB0899_GETFIELD(UWP_ESN0_QUANT, reg); - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); - est = STB0899_GETFIELD(ESN0_EST, reg); - if (est == 1) - val = 301; /* C/N = 30.1 dB */ - else if (est == 2) - val = 270; /* C/N = 27.0 dB */ - else { - /* quantn = 100 * log(quant^2) */ - quantn = stb0899_table_lookup(stb0899_quant_tab, ARRAY_SIZE(stb0899_quant_tab) - 1, quant * 100); - /* estn = 100 * log(est) */ - estn = stb0899_table_lookup(stb0899_est_tab, ARRAY_SIZE(stb0899_est_tab) - 1, est); - /* snr(dBm/10) = -10*(log(est)-log(quant^2)) => snr(dBm/10) = (100*log(quant^2)-100*log(est))/10 */ - val = (quantn - estn) / 10; - } - *snr = val; - dprintk(state->verbose, FE_DEBUG, 1, "Es/N0 quant = %d (%d) estimate = %u (%d), C/N = %d * 0.1 dBm", - quant, quantn, est, estn, val); - } - break; - default: - dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); - return -EINVAL; - } - - return 0; -} - -static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status) -{ - struct stb0899_state *state = fe->demodulator_priv; - struct stb0899_internal *internal = &state->internal; - u8 reg; - *status = 0; - - switch (state->delsys) { - case SYS_DVBS: - case SYS_DSS: - dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S/DSS"); - if (internal->lock) { - reg = stb0899_read_reg(state, STB0899_VSTATUS); - if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { - dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK"); - *status |= FE_HAS_CARRIER | FE_HAS_LOCK; - - reg = stb0899_read_reg(state, STB0899_PLPARM); - if (STB0899_GETFIELD(VITCURPUN, reg)) { - dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_VITERBI | FE_HAS_SYNC"); - *status |= FE_HAS_VITERBI | FE_HAS_SYNC; - /* post process event */ - stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1); - } - } - } - break; - case SYS_DVBS2: - dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S2"); - if (internal->lock) { - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2); - if (STB0899_GETFIELD(UWP_LOCK, reg) && STB0899_GETFIELD(CSM_LOCK, reg)) { - *status |= FE_HAS_CARRIER; - dprintk(state->verbose, FE_DEBUG, 1, - "UWP & CSM Lock ! ---> DVB-S2 FE_HAS_CARRIER"); - - reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1); - if (STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg)) { - *status |= FE_HAS_LOCK; - dprintk(state->verbose, FE_DEBUG, 1, - "Packet Delineator Locked ! -----> DVB-S2 FE_HAS_LOCK"); - - } - if (STB0899_GETFIELD(CONTINUOUS_STREAM, reg)) { - *status |= FE_HAS_VITERBI; - dprintk(state->verbose, FE_DEBUG, 1, - "Packet Delineator found VITERBI ! -----> DVB-S2 FE_HAS_VITERBI"); - } - if (STB0899_GETFIELD(ACCEPTED_STREAM, reg)) { - *status |= FE_HAS_SYNC; - dprintk(state->verbose, FE_DEBUG, 1, - "Packet Delineator found SYNC ! -----> DVB-S2 FE_HAS_SYNC"); - /* post process event */ - stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1); - } - } - } - break; - default: - dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); - return -EINVAL; - } - return 0; -} - -/* - * stb0899_get_error - * viterbi error for DVB-S/DSS - * packet error for DVB-S2 - * Bit Error Rate or Packet Error Rate * 10 ^ 7 - */ -static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct stb0899_state *state = fe->demodulator_priv; - struct stb0899_internal *internal = &state->internal; - - u8 lsb, msb; - u32 i; - - *ber = 0; - - switch (state->delsys) { - case SYS_DVBS: - case SYS_DSS: - if (internal->lock) { - /* average 5 BER values */ - for (i = 0; i < 5; i++) { - msleep(100); - lsb = stb0899_read_reg(state, STB0899_ECNT1L); - msb = stb0899_read_reg(state, STB0899_ECNT1M); - *ber += MAKEWORD16(msb, lsb); - } - *ber /= 5; - /* Viterbi Check */ - if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) { - /* Error Rate */ - *ber *= 9766; - /* ber = ber * 10 ^ 7 */ - *ber /= (-1 + (1 << (2 * STB0899_GETFIELD(NOE, internal->err_ctrl)))); - *ber /= 8; - } - } - break; - case SYS_DVBS2: - if (internal->lock) { - /* Average 5 PER values */ - for (i = 0; i < 5; i++) { - msleep(100); - lsb = stb0899_read_reg(state, STB0899_ECNT1L); - msb = stb0899_read_reg(state, STB0899_ECNT1M); - *ber += MAKEWORD16(msb, lsb); - } - /* ber = ber * 10 ^ 7 */ - *ber *= 10000000; - *ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl)))); - } - break; - default: - dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); - return -EINVAL; - } - - return 0; -} - -static int stb0899_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct stb0899_state *state = fe->demodulator_priv; - - switch (voltage) { - case SEC_VOLTAGE_13: - stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82); - stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02); - stb0899_write_reg(state, STB0899_GPIO02CFG, 0x00); - break; - case SEC_VOLTAGE_18: - stb0899_write_reg(state, STB0899_GPIO00CFG, 0x02); - stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02); - stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82); - break; - case SEC_VOLTAGE_OFF: - stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82); - stb0899_write_reg(state, STB0899_GPIO01CFG, 0x82); - stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int stb0899_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct stb0899_state *state = fe->demodulator_priv; - struct stb0899_internal *internal = &state->internal; - - u8 div, reg; - - /* wait for diseqc idle */ - if (stb0899_wait_diseqc_txidle(state, 100) < 0) - return -ETIMEDOUT; - - switch (tone) { - case SEC_TONE_ON: - div = (internal->master_clk / 100) / 5632; - div = (div + 5) / 10; - stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x66); - reg = stb0899_read_reg(state, STB0899_ACRPRESC); - STB0899_SETFIELD_VAL(ACRPRESC, reg, 0x03); - stb0899_write_reg(state, STB0899_ACRPRESC, reg); - stb0899_write_reg(state, STB0899_ACRDIV1, div); - break; - case SEC_TONE_OFF: - stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x20); - break; - default: - return -EINVAL; - } - return 0; -} - -int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - int i2c_stat; - struct stb0899_state *state = fe->demodulator_priv; - - i2c_stat = stb0899_read_reg(state, STB0899_I2CRPT); - if (i2c_stat < 0) - goto err; - - if (enable) { - dprintk(state->verbose, FE_DEBUG, 1, "Enabling I2C Repeater ..."); - i2c_stat |= STB0899_I2CTON; - if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0) - goto err; - } else { - dprintk(state->verbose, FE_DEBUG, 1, "Disabling I2C Repeater ..."); - i2c_stat &= ~STB0899_I2CTON; - if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0) - goto err; - } - return 0; -err: - dprintk(state->verbose, FE_ERROR, 1, "I2C Repeater control failed"); - return -EREMOTEIO; -} - - -static inline void CONVERT32(u32 x, char *str) -{ - *str++ = (x >> 24) & 0xff; - *str++ = (x >> 16) & 0xff; - *str++ = (x >> 8) & 0xff; - *str++ = (x >> 0) & 0xff; - *str = '\0'; -} - -int stb0899_get_dev_id(struct stb0899_state *state) -{ - u8 chip_id, release; - u16 id; - u32 demod_ver = 0, fec_ver = 0; - char demod_str[5] = { 0 }; - char fec_str[5] = { 0 }; - - id = stb0899_read_reg(state, STB0899_DEV_ID); - dprintk(state->verbose, FE_DEBUG, 1, "ID reg=[0x%02x]", id); - chip_id = STB0899_GETFIELD(CHIP_ID, id); - release = STB0899_GETFIELD(CHIP_REL, id); - - dprintk(state->verbose, FE_ERROR, 1, "Device ID=[%d], Release=[%d]", - chip_id, release); - - CONVERT32(STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CORE_ID), (char *)&demod_str); - - demod_ver = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_VERSION_ID); - dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver); - CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str); - fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG); - if (! (chip_id > 0)) { - dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899"); - - return -ENODEV; - } - dprintk(state->verbose, FE_ERROR, 1, "FEC Core ID=[%s], Version=[%d]", (char*) &fec_str, fec_ver); - - return 0; -} - -static void stb0899_set_delivery(struct stb0899_state *state) -{ - u8 reg; - u8 stop_clk[2]; - - stop_clk[0] = stb0899_read_reg(state, STB0899_STOPCLK1); - stop_clk[1] = stb0899_read_reg(state, STB0899_STOPCLK2); - - switch (state->delsys) { - case SYS_DVBS: - dprintk(state->verbose, FE_DEBUG, 1, "Delivery System -- DVB-S"); - /* FECM/Viterbi ON */ - reg = stb0899_read_reg(state, STB0899_FECM); - STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0); - STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1); - stb0899_write_reg(state, STB0899_FECM, reg); - - stb0899_write_reg(state, STB0899_RSULC, 0xb1); - stb0899_write_reg(state, STB0899_TSULC, 0x40); - stb0899_write_reg(state, STB0899_RSLLC, 0x42); - stb0899_write_reg(state, STB0899_TSLPL, 0x12); - - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESLDPC, reg, 1); - stb0899_write_reg(state, STB0899_TSTRES, reg); - - STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); - STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1); - STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1); - - STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1); - STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1); - - STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 1); - STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); - - STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1); - break; - case SYS_DVBS2: - /* FECM/Viterbi OFF */ - reg = stb0899_read_reg(state, STB0899_FECM); - STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0); - STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 0); - stb0899_write_reg(state, STB0899_FECM, reg); - - stb0899_write_reg(state, STB0899_RSULC, 0xb1); - stb0899_write_reg(state, STB0899_TSULC, 0x42); - stb0899_write_reg(state, STB0899_RSLLC, 0x40); - stb0899_write_reg(state, STB0899_TSLPL, 0x02); - - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESLDPC, reg, 0); - stb0899_write_reg(state, STB0899_TSTRES, reg); - - STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); - STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 0); - STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 0); - - STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 0); - STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 0); - - STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 0); - STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); - - STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 0); - break; - case SYS_DSS: - /* FECM/Viterbi ON */ - reg = stb0899_read_reg(state, STB0899_FECM); - STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 1); - STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1); - stb0899_write_reg(state, STB0899_FECM, reg); - - stb0899_write_reg(state, STB0899_RSULC, 0xa1); - stb0899_write_reg(state, STB0899_TSULC, 0x61); - stb0899_write_reg(state, STB0899_RSLLC, 0x42); - - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESLDPC, reg, 1); - stb0899_write_reg(state, STB0899_TSTRES, reg); - - STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); - STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1); - STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1); - - STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1); - STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1); - - STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); - - STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1); - break; - default: - dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system"); - break; - } - STB0899_SETFIELD_VAL(STOP_CKADCI108, stop_clk[0], 0); - stb0899_write_regs(state, STB0899_STOPCLK1, stop_clk, 2); -} - -/* - * stb0899_set_iterations - * set the LDPC iteration scale function - */ -static void stb0899_set_iterations(struct stb0899_state *state) -{ - struct stb0899_internal *internal = &state->internal; - struct stb0899_config *config = state->config; - - s32 iter_scale; - u32 reg; - - iter_scale = 17 * (internal->master_clk / 1000); - iter_scale += 410000; - iter_scale /= (internal->srate / 1000000); - iter_scale /= 1000; - - if (iter_scale > config->ldpc_max_iter) - iter_scale = config->ldpc_max_iter; - - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, MAX_ITER); - STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg); -} - -static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - struct stb0899_state *state = fe->demodulator_priv; - struct stb0899_params *i_params = &state->params; - struct stb0899_internal *internal = &state->internal; - struct stb0899_config *config = state->config; - struct dtv_frontend_properties *props = &fe->dtv_property_cache; - - u32 SearchRange, gain; - - i_params->freq = p->frequency; - i_params->srate = p->u.qpsk.symbol_rate; - state->delsys = props->delivery_system; - dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys); - - SearchRange = 10000000; - dprintk(state->verbose, FE_DEBUG, 1, "Frequency=%d, Srate=%d", i_params->freq, i_params->srate); - /* checking Search Range is meaningless for a fixed 3 Mhz */ - if (INRANGE(i_params->srate, 1000000, 45000000)) { - dprintk(state->verbose, FE_DEBUG, 1, "Parameters IN RANGE"); - stb0899_set_delivery(state); - - if (state->config->tuner_set_rfsiggain) { - if (internal->srate > 15000000) - gain = 8; /* 15Mb < srate < 45Mb, gain = 8dB */ - else if (internal->srate > 5000000) - gain = 12; /* 5Mb < srate < 15Mb, gain = 12dB */ - else - gain = 14; /* 1Mb < srate < 5Mb, gain = 14db */ - state->config->tuner_set_rfsiggain(fe, gain); - } - - if (i_params->srate <= 5000000) - stb0899_set_mclk(state, config->lo_clk); - else - stb0899_set_mclk(state, config->hi_clk); - - switch (state->delsys) { - case SYS_DVBS: - case SYS_DSS: - dprintk(state->verbose, FE_DEBUG, 1, "DVB-S delivery system"); - internal->freq = i_params->freq; - internal->srate = i_params->srate; - /* - * search = user search range + - * 500Khz + - * 2 * Tuner_step_size + - * 10% of the symbol rate - */ - internal->srch_range = SearchRange + 1500000 + (i_params->srate / 5); - internal->derot_percent = 30; - - /* What to do for tuners having no bandwidth setup ? */ - /* enable tuner I/O */ - stb0899_i2c_gate_ctrl(&state->frontend, 1); - - if (state->config->tuner_set_bandwidth) - state->config->tuner_set_bandwidth(fe, (13 * (stb0899_carr_width(state) + SearchRange)) / 10); - if (state->config->tuner_get_bandwidth) - state->config->tuner_get_bandwidth(fe, &internal->tuner_bw); - - /* disable tuner I/O */ - stb0899_i2c_gate_ctrl(&state->frontend, 0); - - /* Set DVB-S1 AGC */ - stb0899_write_reg(state, STB0899_AGCRFCFG, 0x11); - - /* Run the search algorithm */ - dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S search algo .."); - if (stb0899_dvbs_algo(state) == RANGEOK) { - internal->lock = 1; - dprintk(state->verbose, FE_DEBUG, 1, - "-------------------------------------> DVB-S LOCK !"); - -// stb0899_write_reg(state, STB0899_ERRCTRL1, 0x3d); /* Viterbi Errors */ -// internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS); -// internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1); -// dprintk(state->verbose, FE_DEBUG, 1, "VSTATUS=0x%02x", internal->v_status); -// dprintk(state->verbose, FE_DEBUG, 1, "ERR_CTRL=0x%02x", internal->err_ctrl); - - return DVBFE_ALGO_SEARCH_SUCCESS; - } else { - internal->lock = 0; - - return DVBFE_ALGO_SEARCH_FAILED; - } - break; - case SYS_DVBS2: - internal->freq = i_params->freq; - internal->srate = i_params->srate; - internal->srch_range = SearchRange; - - /* enable tuner I/O */ - stb0899_i2c_gate_ctrl(&state->frontend, 1); - - if (state->config->tuner_set_bandwidth) - state->config->tuner_set_bandwidth(fe, (stb0899_carr_width(state) + SearchRange)); - if (state->config->tuner_get_bandwidth) - state->config->tuner_get_bandwidth(fe, &internal->tuner_bw); - - /* disable tuner I/O */ - stb0899_i2c_gate_ctrl(&state->frontend, 0); - -// pParams->SpectralInv = pSearch->IQ_Inversion; - - /* Set DVB-S2 AGC */ - stb0899_write_reg(state, STB0899_AGCRFCFG, 0x1c); - - /* Set IterScale =f(MCLK,SYMB) */ - stb0899_set_iterations(state); - - /* Run the search algorithm */ - dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S2 search algo .."); - if (stb0899_dvbs2_algo(state) == DVBS2_FEC_LOCK) { - internal->lock = 1; - dprintk(state->verbose, FE_DEBUG, 1, - "-------------------------------------> DVB-S2 LOCK !"); - -// stb0899_write_reg(state, STB0899_ERRCTRL1, 0xb6); /* Packet Errors */ -// internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS); -// internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1); - - return DVBFE_ALGO_SEARCH_SUCCESS; - } else { - internal->lock = 0; - - return DVBFE_ALGO_SEARCH_FAILED; - } - break; - default: - dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system"); - return DVBFE_ALGO_SEARCH_INVALID; - } - } - - return DVBFE_ALGO_SEARCH_ERROR; -} -/* - * stb0899_track - * periodically check the signal level against a specified - * threshold level and perform derotator centering. - * called once we have a lock from a successful search - * event. - * - * Will be called periodically called to maintain the - * lock. - * - * Will be used to get parameters as well as info from - * the decoded baseband header - * - * Once a new lock has established, the internal state - * frequency (internal->freq) is updated - */ -static int stb0899_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - return 0; -} - -static int stb0899_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - struct stb0899_state *state = fe->demodulator_priv; - struct stb0899_internal *internal = &state->internal; - - dprintk(state->verbose, FE_DEBUG, 1, "Get params"); - p->u.qpsk.symbol_rate = internal->srate; - - return 0; -} - -static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe) -{ - return DVBFE_ALGO_CUSTOM; -} - -static struct dvb_frontend_ops stb0899_ops = { - - .info = { - .name = "STB0899 Multistandard", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 0, - .frequency_tolerance = 0, - .symbol_rate_min = 5000000, - .symbol_rate_max = 45000000, - - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_AUTO | - FE_CAN_2G_MODULATION | - FE_CAN_QPSK - }, - - .release = stb0899_release, - .init = stb0899_init, - .sleep = stb0899_sleep, -// .wakeup = stb0899_wakeup, - - .i2c_gate_ctrl = stb0899_i2c_gate_ctrl, - - .get_frontend_algo = stb0899_frontend_algo, - .search = stb0899_search, - .track = stb0899_track, - .get_frontend = stb0899_get_frontend, - - - .read_status = stb0899_read_status, - .read_snr = stb0899_read_snr, - .read_signal_strength = stb0899_read_signal_strength, - .read_ber = stb0899_read_ber, - - .set_voltage = stb0899_set_voltage, - .set_tone = stb0899_set_tone, - - .diseqc_send_master_cmd = stb0899_send_diseqc_msg, - .diseqc_recv_slave_reply = stb0899_recv_slave_reply, - .diseqc_send_burst = stb0899_send_diseqc_burst, -}; - -struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c) -{ - struct stb0899_state *state = NULL; - enum stb0899_inversion inversion; - - state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL); - if (state == NULL) - goto error; - - inversion = config->inversion; - state->verbose = &verbose; - state->config = config; - state->i2c = i2c; - state->frontend.ops = stb0899_ops; - state->frontend.demodulator_priv = state; - state->internal.inversion = inversion; - - stb0899_wakeup(&state->frontend); - if (stb0899_get_dev_id(state) == -ENODEV) { - printk("%s: Exiting .. !\n", __func__); - goto error; - } - - printk("%s: Attaching STB0899 \n", __func__); - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(stb0899_attach); -MODULE_PARM_DESC(verbose, "Set Verbosity level"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_DESCRIPTION("STB0899 Multi-Std frontend"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_drv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_drv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_drv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_drv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -/* - STB0899 Multistandard Frontend driver - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STB0899_DRV_H -#define __STB0899_DRV_H - -#include -#include - -#include "dvb_frontend.h" - -#define STB0899_TSMODE_SERIAL 1 -#define STB0899_CLKPOL_FALLING 2 -#define STB0899_CLKNULL_PARITY 3 -#define STB0899_SYNC_FORCED 4 -#define STB0899_FECMODE_DSS 5 - -struct stb0899_s1_reg { - u16 address; - u8 data; -}; - -struct stb0899_s2_reg { - u16 offset; - u32 base_address; - u32 data; -}; - -enum stb0899_inversion { - IQ_SWAP_OFF = 0, - IQ_SWAP_ON, - IQ_SWAP_AUTO -}; - -#define STB0899_GPIO00 0xf140 -#define STB0899_GPIO01 0xf141 -#define STB0899_GPIO02 0xf142 -#define STB0899_GPIO03 0xf143 -#define STB0899_GPIO04 0xf144 -#define STB0899_GPIO05 0xf145 -#define STB0899_GPIO06 0xf146 -#define STB0899_GPIO07 0xf147 -#define STB0899_GPIO08 0xf148 -#define STB0899_GPIO09 0xf149 -#define STB0899_GPIO10 0xf14a -#define STB0899_GPIO11 0xf14b -#define STB0899_GPIO12 0xf14c -#define STB0899_GPIO13 0xf14d -#define STB0899_GPIO14 0xf14e -#define STB0899_GPIO15 0xf14f -#define STB0899_GPIO16 0xf150 -#define STB0899_GPIO17 0xf151 -#define STB0899_GPIO18 0xf152 -#define STB0899_GPIO19 0xf153 -#define STB0899_GPIO20 0xf154 - -#define STB0899_GPIOPULLUP 0x01 /* Output device is connected to Vdd */ -#define STB0899_GPIOPULLDN 0x00 /* Output device is connected to Vss */ - -#define STB0899_POSTPROC_GPIO_POWER 0x00 -#define STB0899_POSTPROC_GPIO_LOCK 0x01 - -/* - * Post process output configuration control - * 1. POWER ON/OFF (index 0) - * 2. FE_HAS_LOCK/LOCK_LOSS (index 1) - * - * @gpio = one of the above listed GPIO's - * @level = output state: pulled up or low - */ -struct stb0899_postproc { - u16 gpio; - u8 level; -}; - -struct stb0899_config { - const struct stb0899_s1_reg *init_dev; - const struct stb0899_s2_reg *init_s2_demod; - const struct stb0899_s1_reg *init_s1_demod; - const struct stb0899_s2_reg *init_s2_fec; - const struct stb0899_s1_reg *init_tst; - - const struct stb0899_postproc *postproc; - - enum stb0899_inversion inversion; - - u32 xtal_freq; - - u8 demod_address; - u8 ts_output_mode; - u8 block_sync_mode; - u8 ts_pfbit_toggle; - - u8 clock_polarity; - u8 data_clk_parity; - u8 fec_mode; - u8 data_output_ctl; - u8 data_fifo_mode; - u8 out_rate_comp; - u8 i2c_repeater; -// int inversion; - int lo_clk; - int hi_clk; - - u32 esno_ave; - u32 esno_quant; - u32 avframes_coarse; - u32 avframes_fine; - u32 miss_threshold; - u32 uwp_threshold_acq; - u32 uwp_threshold_track; - u32 uwp_threshold_sof; - u32 sof_search_timeout; - - u32 btr_nco_bits; - u32 btr_gain_shift_offset; - u32 crl_nco_bits; - u32 ldpc_max_iter; - - int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency); - int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency); - int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); - int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); - int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain); -}; - -#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE)) - -extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config, - struct i2c_adapter *i2c); - -#else - -static inline struct dvb_frontend *stb0899_attach(struct stb0899_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); - return NULL; -} - -#endif //CONFIG_DVB_STB0899 - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,263 +0,0 @@ -/* - STB0899 Multistandard Frontend driver - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STB0899_PRIV_H -#define __STB0899_PRIV_H - -#include "dvb_frontend.h" -#include "stb0899_drv.h" - -#define FE_ERROR 0 -#define FE_NOTICE 1 -#define FE_INFO 2 -#define FE_DEBUG 3 -#define FE_DEBUGREG 4 - -#define dprintk(x, y, z, format, arg...) do { \ - if (z) { \ - if ((*x > FE_ERROR) && (*x > y)) \ - printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ - else if ((*x > FE_NOTICE) && (*x > y)) \ - printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ - else if ((*x > FE_INFO) && (*x > y)) \ - printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ - else if ((*x > FE_DEBUG) && (*x > y)) \ - printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ - } else { \ - if (*x > y) \ - printk(format, ##arg); \ - } \ -} while(0) - -#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \ - ((y <= val) && (val <= x)) ? 1 : 0) - -#define BYTE0 0 -#define BYTE1 8 -#define BYTE2 16 -#define BYTE3 24 - -#define GETBYTE(x, y) (((x) >> (y)) & 0xff) -#define MAKEWORD32(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) -#define MAKEWORD16(a, b) (((a) << 8) | (b)) - -#define LSB(x) ((x & 0xff)) -#define MSB(y) ((y >> 8) & 0xff) - - -#define STB0899_GETFIELD(bitf, val) ((val >> STB0899_OFFST_##bitf) & ((1 << STB0899_WIDTH_##bitf) - 1)) - - -#define STB0899_SETFIELD(mask, val, width, offset) (mask & (~(((1 << width) - 1) << \ - offset))) | ((val & \ - ((1 << width) - 1)) << offset) - -#define STB0899_SETFIELD_VAL(bitf, mask, val) (mask = (mask & (~(((1 << STB0899_WIDTH_##bitf) - 1) <<\ - STB0899_OFFST_##bitf))) | \ - (val << STB0899_OFFST_##bitf)) - - -enum stb0899_status { - NOAGC1 = 0, - AGC1OK, - NOTIMING, - ANALOGCARRIER, - TIMINGOK, - NOAGC2, - AGC2OK, - NOCARRIER, - CARRIEROK, - NODATA, - FALSELOCK, - DATAOK, - OUTOFRANGE, - RANGEOK, - DVBS2_DEMOD_LOCK, - DVBS2_DEMOD_NOLOCK, - DVBS2_FEC_LOCK, - DVBS2_FEC_NOLOCK -}; - -enum stb0899_modcod { - STB0899_DUMMY_PLF, - STB0899_QPSK_14, - STB0899_QPSK_13, - STB0899_QPSK_25, - STB0899_QPSK_12, - STB0899_QPSK_35, - STB0899_QPSK_23, - STB0899_QPSK_34, - STB0899_QPSK_45, - STB0899_QPSK_56, - STB0899_QPSK_89, - STB0899_QPSK_910, - STB0899_8PSK_35, - STB0899_8PSK_23, - STB0899_8PSK_34, - STB0899_8PSK_56, - STB0899_8PSK_89, - STB0899_8PSK_910, - STB0899_16APSK_23, - STB0899_16APSK_34, - STB0899_16APSK_45, - STB0899_16APSK_56, - STB0899_16APSK_89, - STB0899_16APSK_910, - STB0899_32APSK_34, - STB0899_32APSK_45, - STB0899_32APSK_56, - STB0899_32APSK_89, - STB0899_32APSK_910 -}; - -enum stb0899_frame { - STB0899_LONG_FRAME, - STB0899_SHORT_FRAME -}; - -enum stb0899_alpha { - RRC_20, - RRC_25, - RRC_35 -}; - -struct stb0899_tab { - s32 real; - s32 read; -}; - -enum stb0899_fec { - STB0899_FEC_1_2 = 13, - STB0899_FEC_2_3 = 18, - STB0899_FEC_3_4 = 21, - STB0899_FEC_5_6 = 24, - STB0899_FEC_6_7 = 25, - STB0899_FEC_7_8 = 26 -}; - -struct stb0899_params { - u32 freq; /* Frequency */ - u32 srate; /* Symbol rate */ - enum fe_code_rate fecrate; -}; - -struct stb0899_internal { - u32 master_clk; - u32 freq; /* Demod internal Frequency */ - u32 srate; /* Demod internal Symbol rate */ - enum stb0899_fec fecrate; /* Demod internal FEC rate */ - s32 srch_range; /* Demod internal Search Range */ - s32 sub_range; /* Demod current sub range (Hz) */ - s32 tuner_step; /* Tuner step (Hz) */ - s32 tuner_offst; /* Relative offset to carrier (Hz) */ - u32 tuner_bw; /* Current bandwidth of the tuner (Hz) */ - - s32 mclk; /* Masterclock Divider factor (binary) */ - s32 rolloff; /* Current RollOff of the filter (x100) */ - - s16 derot_freq; /* Current derotator frequency (Hz) */ - s16 derot_percent; - - s16 direction; /* Current derotator search direction */ - s16 derot_step; /* Derotator step (binary value) */ - s16 t_derot; /* Derotator time constant (ms) */ - s16 t_data; /* Data recovery time constant (ms) */ - s16 sub_dir; /* Direction of the next sub range */ - - s16 t_agc1; /* Agc1 time constant (ms) */ - s16 t_agc2; /* Agc2 time constant (ms) */ - - u32 lock; /* Demod internal lock state */ - enum stb0899_status status; /* Demod internal status */ - - /* DVB-S2 */ - s32 agc_gain; /* RF AGC Gain */ - s32 center_freq; /* Nominal carrier frequency */ - s32 av_frame_coarse; /* Coarse carrier freq search frames */ - s32 av_frame_fine; /* Fine carrier freq search frames */ - - s16 step_size; /* Carrier frequency search step size */ - - enum stb0899_alpha rrc_alpha; - enum stb0899_inversion inversion; - enum stb0899_modcod modcod; - u8 pilots; /* Pilots found */ - - enum stb0899_frame frame_length; - u8 v_status; /* VSTATUS */ - u8 err_ctrl; /* ERRCTRLn */ -}; - -struct stb0899_state { - struct i2c_adapter *i2c; - struct stb0899_config *config; - struct dvb_frontend frontend; - - u32 *verbose; /* Cached module verbosity level */ - - struct stb0899_internal internal; /* Device internal parameters */ - - /* cached params from API */ - enum fe_delivery_system delsys; - struct stb0899_params params; - - u32 rx_freq; /* DiSEqC 2.0 receiver freq */ - struct mutex search_lock; -}; -/* stb0899.c */ -extern int stb0899_read_reg(struct stb0899_state *state, - unsigned int reg); - -extern u32 _stb0899_read_s2reg(struct stb0899_state *state, - u32 stb0899_i2cdev, - u32 stb0899_base_addr, - u16 stb0899_reg_offset); - -extern int stb0899_read_regs(struct stb0899_state *state, - unsigned int reg, u8 *buf, - u32 count); - -extern int stb0899_write_regs(struct stb0899_state *state, - unsigned int reg, u8 *data, - u32 count); - -extern int stb0899_write_reg(struct stb0899_state *state, - unsigned int reg, - u8 data); - -extern int stb0899_write_s2reg(struct stb0899_state *state, - u32 stb0899_i2cdev, - u32 stb0899_base_addr, - u16 stb0899_reg_offset, - u32 stb0899_data); - -extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable); - - -#define STB0899_READ_S2REG(DEVICE, REG) (_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG)) -//#define STB0899_WRITE_S2REG(DEVICE, REG, DATA) (_stb0899_write_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG, DATA)) - -/* stb0899_algo.c */ -extern enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state); -extern enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state); -extern long stb0899_carr_width(struct stb0899_state *state); - -#endif //__STB0899_PRIV_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb0899_reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,2027 +0,0 @@ -/* - STB0899 Multistandard Frontend driver - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STB0899_REG_H -#define __STB0899_REG_H - -/* S1 */ -#define STB0899_DEV_ID 0xf000 -#define STB0899_CHIP_ID (0x0f << 4) -#define STB0899_OFFST_CHIP_ID 4 -#define STB0899_WIDTH_CHIP_ID 4 -#define STB0899_CHIP_REL (0x0f << 0) -#define STB0899_OFFST_CHIP_REL 0 -#define STB0899_WIDTH_CHIP_REL 4 - -#define STB0899_DEMOD 0xf40e -#define STB0899_MODECOEFF (0x01 << 0) -#define STB0899_OFFST_MODECOEFF 0 -#define STB0899_WIDTH_MODECOEFF 1 - -#define STB0899_RCOMPC 0xf410 -#define STB0899_AGC1CN 0xf412 -#define STB0899_AGC1REF 0xf413 -#define STB0899_RTC 0xf417 -#define STB0899_TMGCFG 0xf418 -#define STB0899_AGC2REF 0xf419 -#define STB0899_TLSR 0xf41a - -#define STB0899_CFD 0xf41b -#define STB0899_CFD_ON (0x01 << 7) -#define STB0899_OFFST_CFD_ON 7 -#define STB0899_WIDTH_CFD_ON 1 - -#define STB0899_ACLC 0xf41c - -#define STB0899_BCLC 0xf41d -#define STB0899_OFFST_ALGO 6 -#define STB0899_WIDTH_ALGO_QPSK2 2 -#define STB0899_ALGO_QPSK2 (2 << 6) -#define STB0899_ALGO_QPSK1 (1 << 6) -#define STB0899_ALGO_BPSK (0 << 6) -#define STB0899_OFFST_BETA 0 -#define STB0899_WIDTH_BETA 6 - -#define STB0899_EQON 0xf41e -#define STB0899_LDT 0xf41f -#define STB0899_LDT2 0xf420 -#define STB0899_EQUALREF 0xf425 -#define STB0899_TMGRAMP 0xf426 -#define STB0899_TMGTHD 0xf427 -#define STB0899_IDCCOMP 0xf428 -#define STB0899_QDCCOMP 0xf429 -#define STB0899_POWERI 0xf42a -#define STB0899_POWERQ 0xf42b -#define STB0899_RCOMP 0xf42c - -#define STB0899_AGCIQIN 0xf42e -#define STB0899_AGCIQVALUE (0xff << 0) -#define STB0899_OFFST_AGCIQVALUE 0 -#define STB0899_WIDTH_AGCIQVALUE 8 - -#define STB0899_AGC2I1 0xf436 -#define STB0899_AGC2I2 0xf437 - -#define STB0899_TLIR 0xf438 -#define STB0899_TLIR_TMG_LOCK_IND (0xff << 0) -#define STB0899_OFFST_TLIR_TMG_LOCK_IND 0 -#define STB0899_WIDTH_TLIR_TMG_LOCK_IND 8 - -#define STB0899_RTF 0xf439 -#define STB0899_RTF_TIMING_LOOP_FREQ (0xff << 0) -#define STB0899_OFFST_RTF_TIMING_LOOP_FREQ 0 -#define STB0899_WIDTH_RTF_TIMING_LOOP_FREQ 8 - -#define STB0899_DSTATUS 0xf43a -#define STB0899_CARRIER_FOUND (0x01 << 7) -#define STB0899_OFFST_CARRIER_FOUND 7 -#define STB0899_WIDTH_CARRIER_FOUND 1 -#define STB0899_TMG_LOCK (0x01 << 6) -#define STB0899_OFFST_TMG_LOCK 6 -#define STB0899_WIDTH_TMG_LOCK 1 -#define STB0899_DEMOD_LOCK (0x01 << 5) -#define STB0899_OFFST_DEMOD_LOCK 5 -#define STB0899_WIDTH_DEMOD_LOCK 1 -#define STB0899_TMG_AUTO (0x01 << 4) -#define STB0899_OFFST_TMG_AUTO 4 -#define STB0899_WIDTH_TMG_AUTO 1 -#define STB0899_END_MAIN (0x01 << 3) -#define STB0899_OFFST_END_MAIN 3 -#define STB0899_WIDTH_END_MAIN 1 - -#define STB0899_LDI 0xf43b -#define STB0899_OFFST_LDI 0 -#define STB0899_WIDTH_LDI 8 - -#define STB0899_CFRM 0xf43e -#define STB0899_OFFST_CFRM 0 -#define STB0899_WIDTH_CFRM 8 - -#define STB0899_CFRL 0xf43f -#define STB0899_OFFST_CFRL 0 -#define STB0899_WIDTH_CFRL 8 - -#define STB0899_NIRM 0xf440 -#define STB0899_OFFST_NIRM 0 -#define STB0899_WIDTH_NIRM 8 - -#define STB0899_NIRL 0xf441 -#define STB0899_OFFST_NIRL 0 -#define STB0899_WIDTH_NIRL 8 - -#define STB0899_ISYMB 0xf444 -#define STB0899_QSYMB 0xf445 - -#define STB0899_SFRH 0xf446 -#define STB0899_OFFST_SFRH 0 -#define STB0899_WIDTH_SFRH 8 - -#define STB0899_SFRM 0xf447 -#define STB0899_OFFST_SFRM 0 -#define STB0899_WIDTH_SFRM 8 - -#define STB0899_SFRL 0xf448 -#define STB0899_OFFST_SFRL 4 -#define STB0899_WIDTH_SFRL 4 - -#define STB0899_SFRUPH 0xf44c -#define STB0899_SFRUPM 0xf44d -#define STB0899_SFRUPL 0xf44e - -#define STB0899_EQUAI1 0xf4e0 -#define STB0899_EQUAQ1 0xf4e1 -#define STB0899_EQUAI2 0xf4e2 -#define STB0899_EQUAQ2 0xf4e3 -#define STB0899_EQUAI3 0xf4e4 -#define STB0899_EQUAQ3 0xf4e5 -#define STB0899_EQUAI4 0xf4e6 -#define STB0899_EQUAQ4 0xf4e7 -#define STB0899_EQUAI5 0xf4e8 -#define STB0899_EQUAQ5 0xf4e9 - -#define STB0899_DSTATUS2 0xf50c -#define STB0899_DS2_TMG_AUTOSRCH (0x01 << 7) -#define STB8999_OFFST_DS2_TMG_AUTOSRCH 7 -#define STB0899_WIDTH_DS2_TMG_AUTOSRCH 1 -#define STB0899_DS2_END_MAINLOOP (0x01 << 6) -#define STB0899_OFFST_DS2_END_MAINLOOP 6 -#define STB0899_WIDTH_DS2_END_MAINLOOP 1 -#define STB0899_DS2_CFSYNC (0x01 << 5) -#define STB0899_OFFST_DS2_CFSYNC 5 -#define STB0899_WIDTH_DS2_CFSYNC 1 -#define STB0899_DS2_TMGLOCK (0x01 << 4) -#define STB0899_OFFST_DS2_TMGLOCK 4 -#define STB0899_WIDTH_DS2_TMGLOCK 1 -#define STB0899_DS2_DEMODWAIT (0x01 << 3) -#define STB0899_OFFST_DS2_DEMODWAIT 3 -#define STB0899_WIDTH_DS2_DEMODWAIT 1 -#define STB0899_DS2_FECON (0x01 << 1) -#define STB0899_OFFST_DS2_FECON 1 -#define STB0899_WIDTH_DS2_FECON 1 - -/* S1 FEC */ -#define STB0899_VSTATUS 0xf50d -#define STB0899_VSTATUS_VITERBI_ON (0x01 << 7) -#define STB0899_OFFST_VSTATUS_VITERBI_ON 7 -#define STB0899_WIDTH_VSTATUS_VITERBI_ON 1 -#define STB0899_VSTATUS_END_LOOPVIT (0x01 << 6) -#define STB0899_OFFST_VSTATUS_END_LOOPVIT 6 -#define STB0899_WIDTH_VSTATUS_END_LOOPVIT 1 -#define STB0899_VSTATUS_PRFVIT (0x01 << 4) -#define STB0899_OFFST_VSTATUS_PRFVIT 4 -#define STB0899_WIDTH_VSTATUS_PRFVIT 1 -#define STB0899_VSTATUS_LOCKEDVIT (0x01 << 3) -#define STB0899_OFFST_VSTATUS_LOCKEDVIT 3 -#define STB0899_WIDTH_VSTATUS_LOCKEDVIT 1 - -#define STB0899_VERROR 0xf50f - -#define STB0899_IQSWAP 0xf523 -#define STB0899_SYM (0x01 << 3) -#define STB0899_OFFST_SYM 3 -#define STB0899_WIDTH_SYM 1 - -#define STB0899_FECAUTO1 0xf530 -#define STB0899_DSSSRCH (0x01 << 3) -#define STB0899_OFFST_DSSSRCH 3 -#define STB0899_WIDTH_DSSSRCH 1 -#define STB0899_SYMSRCH (0x01 << 2) -#define STB0899_OFFST_SYMSRCH 2 -#define STB0899_WIDTH_SYMSRCH 1 -#define STB0899_QPSKSRCH (0x01 << 1) -#define STB0899_OFFST_QPSKSRCH 1 -#define STB0899_WIDTH_QPSKSRCH 1 -#define STB0899_BPSKSRCH (0x01 << 0) -#define STB0899_OFFST_BPSKSRCH 0 -#define STB0899_WIDTH_BPSKSRCH 1 - -#define STB0899_FECM 0xf533 -#define STB0899_FECM_NOT_DVB (0x01 << 7) -#define STB0899_OFFST_FECM_NOT_DVB 7 -#define STB0899_WIDTH_FECM_NOT_DVB 1 -#define STB0899_FECM_RSVD1 (0x07 << 4) -#define STB0899_OFFST_FECM_RSVD1 4 -#define STB0899_WIDTH_FECM_RSVD1 3 -#define STB0899_FECM_VITERBI_ON (0x01 << 3) -#define STB0899_OFFST_FECM_VITERBI_ON 3 -#define STB0899_WIDTH_FECM_VITERBI_ON 1 -#define STB0899_FECM_RSVD0 (0x01 << 2) -#define STB0899_OFFST_FECM_RSVD0 2 -#define STB0899_WIDTH_FECM_RSVD0 1 -#define STB0899_FECM_SYNCDIS (0x01 << 1) -#define STB0899_OFFST_FECM_SYNCDIS 1 -#define STB0899_WIDTH_FECM_SYNCDIS 1 -#define STB0899_FECM_SYMI (0x01 << 0) -#define STB0899_OFFST_FECM_SYMI 0 -#define STB0899_WIDTH_FECM_SYMI 1 - -#define STB0899_VTH12 0xf534 -#define STB0899_VTH23 0xf535 -#define STB0899_VTH34 0xf536 -#define STB0899_VTH56 0xf537 -#define STB0899_VTH67 0xf538 -#define STB0899_VTH78 0xf539 - -#define STB0899_PRVIT 0xf53c -#define STB0899_PR_7_8 (0x01 << 5) -#define STB0899_OFFST_PR_7_8 5 -#define STB0899_WIDTH_PR_7_8 1 -#define STB0899_PR_6_7 (0x01 << 4) -#define STB0899_OFFST_PR_6_7 4 -#define STB0899_WIDTH_PR_6_7 1 -#define STB0899_PR_5_6 (0x01 << 3) -#define STB0899_OFFST_PR_5_6 3 -#define STB0899_WIDTH_PR_5_6 1 -#define STB0899_PR_3_4 (0x01 << 2) -#define STB0899_OFFST_PR_3_4 2 -#define STB0899_WIDTH_PR_3_4 1 -#define STB0899_PR_2_3 (0x01 << 1) -#define STB0899_OFFST_PR_2_3 1 -#define STB0899_WIDTH_PR_2_3 1 -#define STB0899_PR_1_2 (0x01 << 0) -#define STB0899_OFFST_PR_1_2 0 -#define STB0899_WIDTH_PR_1_2 1 - -#define STB0899_VITSYNC 0xf53d -#define STB0899_AM (0x01 << 7) -#define STB0899_OFFST_AM 7 -#define STB0899_WIDTH_AM 1 -#define STB0899_FREEZE (0x01 << 6) -#define STB0899_OFFST_FREEZE 6 -#define STB0899_WIDTH_FREEZE 1 -#define STB0899_SN_65536 (0x03 << 4) -#define STB0899_OFFST_SN_65536 4 -#define STB0899_WIDTH_SN_65536 2 -#define STB0899_SN_16384 (0x01 << 5) -#define STB0899_OFFST_SN_16384 5 -#define STB0899_WIDTH_SN_16384 1 -#define STB0899_SN_4096 (0x01 << 4) -#define STB0899_OFFST_SN_4096 4 -#define STB0899_WIDTH_SN_4096 1 -#define STB0899_SN_1024 (0x00 << 4) -#define STB0899_OFFST_SN_1024 4 -#define STB0899_WIDTH_SN_1024 0 -#define STB0899_TO_128 (0x03 << 2) -#define STB0899_OFFST_TO_128 2 -#define STB0899_WIDTH_TO_128 2 -#define STB0899_TO_64 (0x01 << 3) -#define STB0899_OFFST_TO_64 3 -#define STB0899_WIDTH_TO_64 1 -#define STB0899_TO_32 (0x01 << 2) -#define STB0899_OFFST_TO_32 2 -#define STB0899_WIDTH_TO_32 1 -#define STB0899_TO_16 (0x00 << 2) -#define STB0899_OFFST_TO_16 2 -#define STB0899_WIDTH_TO_16 0 -#define STB0899_HYST_128 (0x03 << 1) -#define STB0899_OFFST_HYST_128 1 -#define STB0899_WIDTH_HYST_128 2 -#define STB0899_HYST_64 (0x01 << 1) -#define STB0899_OFFST_HYST_64 1 -#define STB0899_WIDTH_HYST_64 1 -#define STB0899_HYST_32 (0x01 << 0) -#define STB0899_OFFST_HYST_32 0 -#define STB0899_WIDTH_HYST_32 1 -#define STB0899_HYST_16 (0x00 << 0) -#define STB0899_OFFST_HYST_16 0 -#define STB0899_WIDTH_HYST_16 0 - -#define STB0899_RSULC 0xf548 -#define STB0899_ULDIL_ON (0x01 << 7) -#define STB0899_OFFST_ULDIL_ON 7 -#define STB0899_WIDTH_ULDIL_ON 1 -#define STB0899_ULAUTO_ON (0x01 << 6) -#define STB0899_OFFST_ULAUTO_ON 6 -#define STB0899_WIDTH_ULAUTO_ON 1 -#define STB0899_ULRS_ON (0x01 << 5) -#define STB0899_OFFST_ULRS_ON 5 -#define STB0899_WIDTH_ULRS_ON 1 -#define STB0899_ULDESCRAM_ON (0x01 << 4) -#define STB0899_OFFST_ULDESCRAM_ON 4 -#define STB0899_WIDTH_ULDESCRAM_ON 1 -#define STB0899_UL_DISABLE (0x01 << 2) -#define STB0899_OFFST_UL_DISABLE 2 -#define STB0899_WIDTH_UL_DISABLE 1 -#define STB0899_NOFTHRESHOLD (0x01 << 0) -#define STB0899_OFFST_NOFTHRESHOLD 0 -#define STB0899_WIDTH_NOFTHRESHOLD 1 - -#define STB0899_RSLLC 0xf54a -#define STB0899_DEMAPVIT 0xf583 -#define STB0899_DEMAPVIT_RSVD (0x01 << 7) -#define STB0899_OFFST_DEMAPVIT_RSVD 7 -#define STB0899_WIDTH_DEMAPVIT_RSVD 1 -#define STB0899_DEMAPVIT_KDIVIDER (0x7f << 0) -#define STB0899_OFFST_DEMAPVIT_KDIVIDER 0 -#define STB0899_WIDTH_DEMAPVIT_KDIVIDER 7 - -#define STB0899_PLPARM 0xf58c -#define STB0899_VITMAPPING (0x07 << 5) -#define STB0899_OFFST_VITMAPPING 5 -#define STB0899_WIDTH_VITMAPPING 3 -#define STB0899_VITMAPPING_BPSK (0x01 << 5) -#define STB0899_OFFST_VITMAPPING_BPSK 5 -#define STB0899_WIDTH_VITMAPPING_BPSK 1 -#define STB0899_VITMAPPING_QPSK (0x00 << 5) -#define STB0899_OFFST_VITMAPPING_QPSK 5 -#define STB0899_WIDTH_VITMAPPING_QPSK 0 -#define STB0899_VITCURPUN (0x1f << 0) -#define STB0899_OFFST_VITCURPUN 0 -#define STB0899_WIDTH_VITCURPUN 5 -#define STB0899_VITCURPUN_1_2 (0x0d << 0) -#define STB0899_VITCURPUN_2_3 (0x12 << 0) -#define STB0899_VITCURPUN_3_4 (0x15 << 0) -#define STB0899_VITCURPUN_5_6 (0x18 << 0) -#define STB0899_VITCURPUN_6_7 (0x19 << 0) -#define STB0899_VITCURPUN_7_8 (0x1a << 0) - -/* S2 DEMOD */ -#define STB0899_OFF0_DMD_STATUS 0xf300 -#define STB0899_BASE_DMD_STATUS 0x00000000 -#define STB0899_IF_AGC_LOCK (0x01 << 8) -#define STB0899_OFFST_IF_AGC_LOCK 0 -#define STB0899_WIDTH_IF_AGC_LOCK 1 - -#define STB0899_OFF0_CRL_FREQ 0xf304 -#define STB0899_BASE_CRL_FREQ 0x00000000 -#define STB0899_CARR_FREQ (0x3fffffff << 0) -#define STB0899_OFFST_CARR_FREQ 0 -#define STB0899_WIDTH_CARR_FREQ 30 - -#define STB0899_OFF0_BTR_FREQ 0xf308 -#define STB0899_BASE_BTR_FREQ 0x00000000 -#define STB0899_BTR_FREQ (0xfffffff << 0) -#define STB0899_OFFST_BTR_FREQ 0 -#define STB0899_WIDTH_BTR_FREQ 28 - -#define STB0899_OFF0_IF_AGC_GAIN 0xf30c -#define STB0899_BASE_IF_AGC_GAIN 0x00000000 -#define STB0899_IF_AGC_GAIN (0x3fff < 0) -#define STB0899_OFFST_IF_AGC_GAIN 0 -#define STB0899_WIDTH_IF_AGC_GAIN 14 - -#define STB0899_OFF0_BB_AGC_GAIN 0xf310 -#define STB0899_BASE_BB_AGC_GAIN 0x00000000 -#define STB0899_BB_AGC_GAIN (0x3fff < 0) -#define STB0899_OFFST_BB_AGC_GAIN 0 -#define STB0899_WIDTH_BB_AGC_GAIN 14 - -#define STB0899_OFF0_DC_OFFSET 0xf314 -#define STB0899_BASE_DC_OFFSET 0x00000000 -#define STB0899_I (0xff < 8) -#define STB0899_OFFST_I 8 -#define STB0899_WIDTH_I 8 -#define STB0899_Q (0xff < 0) -#define STB0899_OFFST_Q 8 -#define STB0899_WIDTH_Q 8 - -#define STB0899_OFF0_DMD_CNTRL 0xf31c -#define STB0899_BASE_DMD_CNTRL 0x00000000 -#define STB0899_ADC0_PINS1IN (0x01 << 6) -#define STB0899_OFFST_ADC0_PINS1IN 6 -#define STB0899_WIDTH_ADC0_PINS1IN 1 -#define STB0899_IN2COMP1_OFFBIN0 (0x01 << 3) -#define STB0899_OFFST_IN2COMP1_OFFBIN0 3 -#define STB0899_WIDTH_IN2COMP1_OFFBIN0 1 -#define STB0899_DC_COMP (0x01 << 2) -#define STB0899_OFFST_DC_COMP 2 -#define STB0899_WIDTH_DC_COMP 1 -#define STB0899_MODMODE (0x03 << 0) -#define STB0899_OFFST_MODMODE 0 -#define STB0899_WIDTH_MODMODE 2 - -#define STB0899_OFF0_IF_AGC_CNTRL 0xf320 -#define STB0899_BASE_IF_AGC_CNTRL 0x00000000 -#define STB0899_IF_GAIN_INIT (0x3fff << 13) -#define STB0899_OFFST_IF_GAIN_INIT 13 -#define STB0899_WIDTH_IF_GAIN_INIT 14 -#define STB0899_IF_GAIN_SENSE (0x01 << 12) -#define STB0899_OFFST_IF_GAIN_SENSE 12 -#define STB0899_WIDTH_IF_GAIN_SENSE 1 -#define STB0899_IF_LOOP_GAIN (0x0f << 8) -#define STB0899_OFFST_IF_LOOP_GAIN 8 -#define STB0899_WIDTH_IF_LOOP_GAIN 4 -#define STB0899_IF_LD_GAIN_INIT (0x01 << 7) -#define STB0899_OFFST_IF_LD_GAIN_INIT 7 -#define STB0899_WIDTH_IF_LD_GAIN_INIT 1 -#define STB0899_IF_AGC_REF (0x7f << 0) -#define STB0899_OFFST_IF_AGC_REF 0 -#define STB0899_WIDTH_IF_AGC_REF 7 - -#define STB0899_OFF0_BB_AGC_CNTRL 0xf324 -#define STB0899_BASE_BB_AGC_CNTRL 0x00000000 -#define STB0899_BB_GAIN_INIT (0x3fff << 12) -#define STB0899_OFFST_BB_GAIN_INIT 12 -#define STB0899_WIDTH_BB_GAIN_INIT 14 -#define STB0899_BB_LOOP_GAIN (0x0f << 8) -#define STB0899_OFFST_BB_LOOP_GAIN 8 -#define STB0899_WIDTH_BB_LOOP_GAIN 4 -#define STB0899_BB_LD_GAIN_INIT (0x01 << 7) -#define STB0899_OFFST_BB_LD_GAIN_INIT 7 -#define STB0899_WIDTH_BB_LD_GAIN_INIT 1 -#define STB0899_BB_AGC_REF (0x7f << 0) -#define STB0899_OFFST_BB_AGC_REF 0 -#define STB0899_WIDTH_BB_AGC_REF 7 - -#define STB0899_OFF0_CRL_CNTRL 0xf328 -#define STB0899_BASE_CRL_CNTRL 0x00000000 -#define STB0899_CRL_LOCK_CLEAR (0x01 << 5) -#define STB0899_OFFST_CRL_LOCK_CLEAR 5 -#define STB0899_WIDTH_CRL_LOCK_CLEAR 1 -#define STB0899_CRL_SWPR_CLEAR (0x01 << 4) -#define STB0899_OFFST_CRL_SWPR_CLEAR 4 -#define STB0899_WIDTH_CRL_SWPR_CLEAR 1 -#define STB0899_CRL_SWP_ENA (0x01 << 3) -#define STB0899_OFFST_CRL_SWP_ENA 3 -#define STB0899_WIDTH_CRL_SWP_ENA 1 -#define STB0899_CRL_DET_SEL (0x01 << 2) -#define STB0899_OFFST_CRL_DET_SEL 2 -#define STB0899_WIDTH_CRL_DET_SEL 1 -#define STB0899_CRL_SENSE (0x01 << 1) -#define STB0899_OFFST_CRL_SENSE 1 -#define STB0899_WIDTH_CRL_SENSE 1 -#define STB0899_CRL_PHSERR_CLEAR (0x01 << 0) -#define STB0899_OFFST_CRL_PHSERR_CLEAR 0 -#define STB0899_WIDTH_CRL_PHSERR_CLEAR 1 - -#define STB0899_OFF0_CRL_PHS_INIT 0xf32c -#define STB0899_BASE_CRL_PHS_INIT 0x00000000 -#define STB0899_CRL_PHS_INIT_31 (0x1 << 30) -#define STB0899_OFFST_CRL_PHS_INIT_31 30 -#define STB0899_WIDTH_CRL_PHS_INIT_31 1 -#define STB0899_CRL_LD_INIT_PHASE (0x1 << 24) -#define STB0899_OFFST_CRL_LD_INIT_PHASE 24 -#define STB0899_WIDTH_CRL_LD_INIT_PHASE 1 -#define STB0899_CRL_INIT_PHASE (0xffffff << 0) -#define STB0899_OFFST_CRL_INIT_PHASE 0 -#define STB0899_WIDTH_CRL_INIT_PHASE 24 - -#define STB0899_OFF0_CRL_FREQ_INIT 0xf330 -#define STB0899_BASE_CRL_FREQ_INIT 0x00000000 -#define STB0899_CRL_FREQ_INIT_31 (0x1 << 30) -#define STB0899_OFFST_CRL_FREQ_INIT_31 30 -#define STB0899_WIDTH_CRL_FREQ_INIT_31 1 -#define STB0899_CRL_LD_FREQ_INIT (0x1 << 24) -#define STB0899_OFFST_CRL_LD_FREQ_INIT 24 -#define STB0899_WIDTH_CRL_LD_FREQ_INIT 1 -#define STB0899_CRL_FREQ_INIT (0xffffff << 0) -#define STB0899_OFFST_CRL_FREQ_INIT 0 -#define STB0899_WIDTH_CRL_FREQ_INIT 24 - -#define STB0899_OFF0_CRL_LOOP_GAIN 0xf334 -#define STB0899_BASE_CRL_LOOP_GAIN 0x00000000 -#define STB0899_KCRL2_RSHFT (0xf << 16) -#define STB0899_OFFST_KCRL2_RSHFT 16 -#define STB0899_WIDTH_KCRL2_RSHFT 4 -#define STB0899_KCRL1 (0xf << 12) -#define STB0899_OFFST_KCRL1 12 -#define STB0899_WIDTH_KCRL1 4 -#define STB0899_KCRL1_RSHFT (0xf << 8) -#define STB0899_OFFST_KCRL1_RSHFT 8 -#define STB0899_WIDTH_KCRL1_RSHFT 4 -#define STB0899_KCRL0 (0xf << 4) -#define STB0899_OFFST_KCRL0 4 -#define STB0899_WIDTH_KCRL0 4 -#define STB0899_KCRL0_RSHFT (0xf << 0) -#define STB0899_OFFST_KCRL0_RSHFT 0 -#define STB0899_WIDTH_KCRL0_RSHFT 4 - -#define STB0899_OFF0_CRL_NOM_FREQ 0xf338 -#define STB0899_BASE_CRL_NOM_FREQ 0x00000000 -#define STB0899_CRL_NOM_FREQ (0x3fffffff << 0) -#define STB0899_OFFST_CRL_NOM_FREQ 0 -#define STB0899_WIDTH_CRL_NOM_FREQ 30 - -#define STB0899_OFF0_CRL_SWP_RATE 0xf33c -#define STB0899_BASE_CRL_SWP_RATE 0x00000000 -#define STB0899_CRL_SWP_RATE (0x3fffffff << 0) -#define STB0899_OFFST_CRL_SWP_RATE 0 -#define STB0899_WIDTH_CRL_SWP_RATE 30 - -#define STB0899_OFF0_CRL_MAX_SWP 0xf340 -#define STB0899_BASE_CRL_MAX_SWP 0x00000000 -#define STB0899_CRL_MAX_SWP (0x3fffffff << 0) -#define STB0899_OFFST_CRL_MAX_SWP 0 -#define STB0899_WIDTH_CRL_MAX_SWP 30 - -#define STB0899_OFF0_CRL_LK_CNTRL 0xf344 -#define STB0899_BASE_CRL_LK_CNTRL 0x00000000 - -#define STB0899_OFF0_DECIM_CNTRL 0xf348 -#define STB0899_BASE_DECIM_CNTRL 0x00000000 -#define STB0899_BAND_LIMIT_B (0x01 << 5) -#define STB0899_OFFST_BAND_LIMIT_B 5 -#define STB0899_WIDTH_BAND_LIMIT_B 1 -#define STB0899_WIN_SEL (0x03 << 3) -#define STB0899_OFFST_WIN_SEL 3 -#define STB0899_WIDTH_WIN_SEL 2 -#define STB0899_DECIM_RATE (0x07 << 0) -#define STB0899_OFFST_DECIM_RATE 0 -#define STB0899_WIDTH_DECIM_RATE 3 - -#define STB0899_OFF0_BTR_CNTRL 0xf34c -#define STB0899_BASE_BTR_CNTRL 0x00000000 -#define STB0899_BTR_FREQ_CORR (0x7ff << 4) -#define STB0899_OFFST_BTR_FREQ_CORR 4 -#define STB0899_WIDTH_BTR_FREQ_CORR 11 -#define STB0899_BTR_CLR_LOCK (0x01 << 3) -#define STB0899_OFFST_BTR_CLR_LOCK 3 -#define STB0899_WIDTH_BTR_CLR_LOCK 1 -#define STB0899_BTR_SENSE (0x01 << 2) -#define STB0899_OFFST_BTR_SENSE 2 -#define STB0899_WIDTH_BTR_SENSE 1 -#define STB0899_BTR_ERR_ENA (0x01 << 1) -#define STB0899_OFFST_BTR_ERR_ENA 1 -#define STB0899_WIDTH_BTR_ERR_ENA 1 -#define STB0899_INTRP_PHS_SENSE (0x01 << 0) -#define STB0899_OFFST_INTRP_PHS_SENSE 0 -#define STB0899_WIDTH_INTRP_PHS_SENSE 1 - -#define STB0899_OFF0_BTR_LOOP_GAIN 0xf350 -#define STB0899_BASE_BTR_LOOP_GAIN 0x00000000 -#define STB0899_KBTR2_RSHFT (0x0f << 16) -#define STB0899_OFFST_KBTR2_RSHFT 16 -#define STB0899_WIDTH_KBTR2_RSHFT 4 -#define STB0899_KBTR1 (0x0f << 12) -#define STB0899_OFFST_KBTR1 12 -#define STB0899_WIDTH_KBTR1 4 -#define STB0899_KBTR1_RSHFT (0x0f << 8) -#define STB0899_OFFST_KBTR1_RSHFT 8 -#define STB0899_WIDTH_KBTR1_RSHFT 4 -#define STB0899_KBTR0 (0x0f << 4) -#define STB0899_OFFST_KBTR0 4 -#define STB0899_WIDTH_KBTR0 4 -#define STB0899_KBTR0_RSHFT (0x0f << 0) -#define STB0899_OFFST_KBTR0_RSHFT 0 -#define STB0899_WIDTH_KBTR0_RSHFT 4 - -#define STB0899_OFF0_BTR_PHS_INIT 0xf354 -#define STB0899_BASE_BTR_PHS_INIT 0x00000000 -#define STB0899_BTR_LD_PHASE_INIT (0x01 << 28) -#define STB0899_OFFST_BTR_LD_PHASE_INIT 28 -#define STB0899_WIDTH_BTR_LD_PHASE_INIT 1 -#define STB0899_BTR_INIT_PHASE (0xfffffff << 0) -#define STB0899_OFFST_BTR_INIT_PHASE 0 -#define STB0899_WIDTH_BTR_INIT_PHASE 28 - -#define STB0899_OFF0_BTR_FREQ_INIT 0xf358 -#define STB0899_BASE_BTR_FREQ_INIT 0x00000000 -#define STB0899_BTR_LD_FREQ_INIT (1 << 28) -#define STB0899_OFFST_BTR_LD_FREQ_INIT 28 -#define STB0899_WIDTH_BTR_LD_FREQ_INIT 1 -#define STB0899_BTR_FREQ_INIT (0xfffffff << 0) -#define STB0899_OFFST_BTR_FREQ_INIT 0 -#define STB0899_WIDTH_BTR_FREQ_INIT 28 - -#define STB0899_OFF0_BTR_NOM_FREQ 0xf35c -#define STB0899_BASE_BTR_NOM_FREQ 0x00000000 -#define STB0899_BTR_NOM_FREQ (0xfffffff << 0) -#define STB0899_OFFST_BTR_NOM_FREQ 0 -#define STB0899_WIDTH_BTR_NOM_FREQ 28 - -#define STB0899_OFF0_BTR_LK_CNTRL 0xf360 -#define STB0899_BASE_BTR_LK_CNTRL 0x00000000 -#define STB0899_BTR_MIN_ENERGY (0x0f << 24) -#define STB0899_OFFST_BTR_MIN_ENERGY 24 -#define STB0899_WIDTH_BTR_MIN_ENERGY 4 -#define STB0899_BTR_LOCK_TH_LO (0xff << 16) -#define STB0899_OFFST_BTR_LOCK_TH_LO 16 -#define STB0899_WIDTH_BTR_LOCK_TH_LO 8 -#define STB0899_BTR_LOCK_TH_HI (0xff << 8) -#define STB0899_OFFST_BTR_LOCK_TH_HI 8 -#define STB0899_WIDTH_BTR_LOCK_TH_HI 8 -#define STB0899_BTR_LOCK_GAIN (0x03 << 6) -#define STB0899_OFFST_BTR_LOCK_GAIN 6 -#define STB0899_WIDTH_BTR_LOCK_GAIN 2 -#define STB0899_BTR_LOCK_LEAK (0x3f << 0) -#define STB0899_OFFST_BTR_LOCK_LEAK 0 -#define STB0899_WIDTH_BTR_LOCK_LEAK 6 - -#define STB0899_OFF0_DECN_CNTRL 0xf364 -#define STB0899_BASE_DECN_CNTRL 0x00000000 - -#define STB0899_OFF0_TP_CNTRL 0xf368 -#define STB0899_BASE_TP_CNTRL 0x00000000 - -#define STB0899_OFF0_TP_BUF_STATUS 0xf36c -#define STB0899_BASE_TP_BUF_STATUS 0x00000000 -#define STB0899_TP_BUFFER_FULL (1 << 0) - -#define STB0899_OFF0_DC_ESTIM 0xf37c -#define STB0899_BASE_DC_ESTIM 0x0000 -#define STB0899_I_DC_ESTIMATE (0xff << 8) -#define STB0899_OFFST_I_DC_ESTIMATE 8 -#define STB0899_WIDTH_I_DC_ESTIMATE 8 -#define STB0899_Q_DC_ESTIMATE (0xff << 0) -#define STB0899_OFFST_Q_DC_ESTIMATE 0 -#define STB0899_WIDTH_Q_DC_ESTIMATE 8 - -#define STB0899_OFF0_FLL_CNTRL 0xf310 -#define STB0899_BASE_FLL_CNTRL 0x00000020 -#define STB0899_CRL_FLL_ACC (0x01 << 4) -#define STB0899_OFFST_CRL_FLL_ACC 4 -#define STB0899_WIDTH_CRL_FLL_ACC 1 -#define STB0899_FLL_AVG_PERIOD (0x0f << 0) -#define STB0899_OFFST_FLL_AVG_PERIOD 0 -#define STB0899_WIDTH_FLL_AVG_PERIOD 4 - -#define STB0899_OFF0_FLL_FREQ_WD 0xf314 -#define STB0899_BASE_FLL_FREQ_WD 0x00000020 -#define STB0899_FLL_FREQ_WD (0xffffffff << 0) -#define STB0899_OFFST_FLL_FREQ_WD 0 -#define STB0899_WIDTH_FLL_FREQ_WD 32 - -#define STB0899_OFF0_ANTI_ALIAS_SEL 0xf358 -#define STB0899_BASE_ANTI_ALIAS_SEL 0x00000020 -#define STB0899_ANTI_ALIAS_SELB (0x03 << 0) -#define STB0899_OFFST_ANTI_ALIAS_SELB 0 -#define STB0899_WIDTH_ANTI_ALIAS_SELB 2 - -#define STB0899_OFF0_RRC_ALPHA 0xf35c -#define STB0899_BASE_RRC_ALPHA 0x00000020 -#define STB0899_RRC_ALPHA (0x03 << 0) -#define STB0899_OFFST_RRC_ALPHA 0 -#define STB0899_WIDTH_RRC_ALPHA 2 - -#define STB0899_OFF0_DC_ADAPT_LSHFT 0xf360 -#define STB0899_BASE_DC_ADAPT_LSHFT 0x00000020 -#define STB0899_DC_ADAPT_LSHFT (0x077 << 0) -#define STB0899_OFFST_DC_ADAPT_LSHFT 0 -#define STB0899_WIDTH_DC_ADAPT_LSHFT 3 - -#define STB0899_OFF0_IMB_OFFSET 0xf364 -#define STB0899_BASE_IMB_OFFSET 0x00000020 -#define STB0899_PHS_IMB_COMP (0xff << 8) -#define STB0899_OFFST_PHS_IMB_COMP 8 -#define STB0899_WIDTH_PHS_IMB_COMP 8 -#define STB0899_AMPL_IMB_COMP (0xff << 0) -#define STB0899_OFFST_AMPL_IMB_COMP 0 -#define STB0899_WIDTH_AMPL_IMB_COMP 8 - -#define STB0899_OFF0_IMB_ESTIMATE 0xf368 -#define STB0899_BASE_IMB_ESTIMATE 0x00000020 -#define STB0899_PHS_IMB_ESTIMATE (0xff << 8) -#define STB0899_OFFST_PHS_IMB_ESTIMATE 8 -#define STB0899_WIDTH_PHS_IMB_ESTIMATE 8 -#define STB0899_AMPL_IMB_ESTIMATE (0xff << 0) -#define STB0899_OFFST_AMPL_IMB_ESTIMATE 0 -#define STB0899_WIDTH_AMPL_IMB_ESTIMATE 8 - -#define STB0899_OFF0_IMB_CNTRL 0xf36c -#define STB0899_BASE_IMB_CNTRL 0x00000020 -#define STB0899_PHS_ADAPT_LSHFT (0x07 << 4) -#define STB0899_OFFST_PHS_ADAPT_LSHFT 4 -#define STB0899_WIDTH_PHS_ADAPT_LSHFT 3 -#define STB0899_AMPL_ADAPT_LSHFT (0x07 << 1) -#define STB0899_OFFST_AMPL_ADAPT_LSHFT 1 -#define STB0899_WIDTH_AMPL_ADAPT_LSHFT 3 -#define STB0899_IMB_COMP (0x01 << 0) -#define STB0899_OFFST_IMB_COMP 0 -#define STB0899_WIDTH_IMB_COMP 1 - -#define STB0899_OFF0_IF_AGC_CNTRL2 0xf374 -#define STB0899_BASE_IF_AGC_CNTRL2 0x00000020 -#define STB0899_IF_AGC_LOCK_TH (0xff << 11) -#define STB0899_OFFST_IF_AGC_LOCK_TH 11 -#define STB0899_WIDTH_IF_AGC_LOCK_TH 8 -#define STB0899_IF_AGC_SD_DIV (0xff << 3) -#define STB0899_OFFST_IF_AGC_SD_DIV 3 -#define STB0899_WIDTH_IF_AGC_SD_DIV 8 -#define STB0899_IF_AGC_DUMP_PER (0x07 << 0) -#define STB0899_OFFST_IF_AGC_DUMP_PER 0 -#define STB0899_WIDTH_IF_AGC_DUMP_PER 3 - -#define STB0899_OFF0_DMD_CNTRL2 0xf378 -#define STB0899_BASE_DMD_CNTRL2 0x00000020 -#define STB0899_SPECTRUM_INVERT (0x01 << 2) -#define STB0899_OFFST_SPECTRUM_INVERT 2 -#define STB0899_WIDTH_SPECTRUM_INVERT 1 -#define STB0899_AGC_MODE (0x01 << 1) -#define STB0899_OFFST_AGC_MODE 1 -#define STB0899_WIDTH_AGC_MODE 1 -#define STB0899_CRL_FREQ_ADJ (0x01 << 0) -#define STB0899_OFFST_CRL_FREQ_ADJ 0 -#define STB0899_WIDTH_CRL_FREQ_ADJ 1 - -#define STB0899_OFF0_TP_BUFFER 0xf300 -#define STB0899_BASE_TP_BUFFER 0x00000040 -#define STB0899_TP_BUFFER_IN (0xffff << 0) -#define STB0899_OFFST_TP_BUFFER_IN 0 -#define STB0899_WIDTH_TP_BUFFER_IN 16 - -#define STB0899_OFF0_TP_BUFFER1 0xf304 -#define STB0899_BASE_TP_BUFFER1 0x00000040 -#define STB0899_OFF0_TP_BUFFER2 0xf308 -#define STB0899_BASE_TP_BUFFER2 0x00000040 -#define STB0899_OFF0_TP_BUFFER3 0xf30c -#define STB0899_BASE_TP_BUFFER3 0x00000040 -#define STB0899_OFF0_TP_BUFFER4 0xf310 -#define STB0899_BASE_TP_BUFFER4 0x00000040 -#define STB0899_OFF0_TP_BUFFER5 0xf314 -#define STB0899_BASE_TP_BUFFER5 0x00000040 -#define STB0899_OFF0_TP_BUFFER6 0xf318 -#define STB0899_BASE_TP_BUFFER6 0x00000040 -#define STB0899_OFF0_TP_BUFFER7 0xf31c -#define STB0899_BASE_TP_BUFFER7 0x00000040 -#define STB0899_OFF0_TP_BUFFER8 0xf320 -#define STB0899_BASE_TP_BUFFER8 0x00000040 -#define STB0899_OFF0_TP_BUFFER9 0xf324 -#define STB0899_BASE_TP_BUFFER9 0x00000040 -#define STB0899_OFF0_TP_BUFFER10 0xf328 -#define STB0899_BASE_TP_BUFFER10 0x00000040 -#define STB0899_OFF0_TP_BUFFER11 0xf32c -#define STB0899_BASE_TP_BUFFER11 0x00000040 -#define STB0899_OFF0_TP_BUFFER12 0xf330 -#define STB0899_BASE_TP_BUFFER12 0x00000040 -#define STB0899_OFF0_TP_BUFFER13 0xf334 -#define STB0899_BASE_TP_BUFFER13 0x00000040 -#define STB0899_OFF0_TP_BUFFER14 0xf338 -#define STB0899_BASE_TP_BUFFER14 0x00000040 -#define STB0899_OFF0_TP_BUFFER15 0xf33c -#define STB0899_BASE_TP_BUFFER15 0x00000040 -#define STB0899_OFF0_TP_BUFFER16 0xf340 -#define STB0899_BASE_TP_BUFFER16 0x00000040 -#define STB0899_OFF0_TP_BUFFER17 0xf344 -#define STB0899_BASE_TP_BUFFER17 0x00000040 -#define STB0899_OFF0_TP_BUFFER18 0xf348 -#define STB0899_BASE_TP_BUFFER18 0x00000040 -#define STB0899_OFF0_TP_BUFFER19 0xf34c -#define STB0899_BASE_TP_BUFFER19 0x00000040 -#define STB0899_OFF0_TP_BUFFER20 0xf350 -#define STB0899_BASE_TP_BUFFER20 0x00000040 -#define STB0899_OFF0_TP_BUFFER21 0xf354 -#define STB0899_BASE_TP_BUFFER21 0x00000040 -#define STB0899_OFF0_TP_BUFFER22 0xf358 -#define STB0899_BASE_TP_BUFFER22 0x00000040 -#define STB0899_OFF0_TP_BUFFER23 0xf35c -#define STB0899_BASE_TP_BUFFER23 0x00000040 -#define STB0899_OFF0_TP_BUFFER24 0xf360 -#define STB0899_BASE_TP_BUFFER24 0x00000040 -#define STB0899_OFF0_TP_BUFFER25 0xf364 -#define STB0899_BASE_TP_BUFFER25 0x00000040 -#define STB0899_OFF0_TP_BUFFER26 0xf368 -#define STB0899_BASE_TP_BUFFER26 0x00000040 -#define STB0899_OFF0_TP_BUFFER27 0xf36c -#define STB0899_BASE_TP_BUFFER27 0x00000040 -#define STB0899_OFF0_TP_BUFFER28 0xf370 -#define STB0899_BASE_TP_BUFFER28 0x00000040 -#define STB0899_OFF0_TP_BUFFER29 0xf374 -#define STB0899_BASE_TP_BUFFER29 0x00000040 -#define STB0899_OFF0_TP_BUFFER30 0xf378 -#define STB0899_BASE_TP_BUFFER30 0x00000040 -#define STB0899_OFF0_TP_BUFFER31 0xf37c -#define STB0899_BASE_TP_BUFFER31 0x00000040 -#define STB0899_OFF0_TP_BUFFER32 0xf300 -#define STB0899_BASE_TP_BUFFER32 0x00000060 -#define STB0899_OFF0_TP_BUFFER33 0xf304 -#define STB0899_BASE_TP_BUFFER33 0x00000060 -#define STB0899_OFF0_TP_BUFFER34 0xf308 -#define STB0899_BASE_TP_BUFFER34 0x00000060 -#define STB0899_OFF0_TP_BUFFER35 0xf30c -#define STB0899_BASE_TP_BUFFER35 0x00000060 -#define STB0899_OFF0_TP_BUFFER36 0xf310 -#define STB0899_BASE_TP_BUFFER36 0x00000060 -#define STB0899_OFF0_TP_BUFFER37 0xf314 -#define STB0899_BASE_TP_BUFFER37 0x00000060 -#define STB0899_OFF0_TP_BUFFER38 0xf318 -#define STB0899_BASE_TP_BUFFER38 0x00000060 -#define STB0899_OFF0_TP_BUFFER39 0xf31c -#define STB0899_BASE_TP_BUFFER39 0x00000060 -#define STB0899_OFF0_TP_BUFFER40 0xf320 -#define STB0899_BASE_TP_BUFFER40 0x00000060 -#define STB0899_OFF0_TP_BUFFER41 0xf324 -#define STB0899_BASE_TP_BUFFER41 0x00000060 -#define STB0899_OFF0_TP_BUFFER42 0xf328 -#define STB0899_BASE_TP_BUFFER42 0x00000060 -#define STB0899_OFF0_TP_BUFFER43 0xf32c -#define STB0899_BASE_TP_BUFFER43 0x00000060 -#define STB0899_OFF0_TP_BUFFER44 0xf330 -#define STB0899_BASE_TP_BUFFER44 0x00000060 -#define STB0899_OFF0_TP_BUFFER45 0xf334 -#define STB0899_BASE_TP_BUFFER45 0x00000060 -#define STB0899_OFF0_TP_BUFFER46 0xf338 -#define STB0899_BASE_TP_BUFFER46 0x00000060 -#define STB0899_OFF0_TP_BUFFER47 0xf33c -#define STB0899_BASE_TP_BUFFER47 0x00000060 -#define STB0899_OFF0_TP_BUFFER48 0xf340 -#define STB0899_BASE_TP_BUFFER48 0x00000060 -#define STB0899_OFF0_TP_BUFFER49 0xf344 -#define STB0899_BASE_TP_BUFFER49 0x00000060 -#define STB0899_OFF0_TP_BUFFER50 0xf348 -#define STB0899_BASE_TP_BUFFER50 0x00000060 -#define STB0899_OFF0_TP_BUFFER51 0xf34c -#define STB0899_BASE_TP_BUFFER51 0x00000060 -#define STB0899_OFF0_TP_BUFFER52 0xf350 -#define STB0899_BASE_TP_BUFFER52 0x00000060 -#define STB0899_OFF0_TP_BUFFER53 0xf354 -#define STB0899_BASE_TP_BUFFER53 0x00000060 -#define STB0899_OFF0_TP_BUFFER54 0xf358 -#define STB0899_BASE_TP_BUFFER54 0x00000060 -#define STB0899_OFF0_TP_BUFFER55 0xf35c -#define STB0899_BASE_TP_BUFFER55 0x00000060 -#define STB0899_OFF0_TP_BUFFER56 0xf360 -#define STB0899_BASE_TP_BUFFER56 0x00000060 -#define STB0899_OFF0_TP_BUFFER57 0xf364 -#define STB0899_BASE_TP_BUFFER57 0x00000060 -#define STB0899_OFF0_TP_BUFFER58 0xf368 -#define STB0899_BASE_TP_BUFFER58 0x00000060 -#define STB0899_OFF0_TP_BUFFER59 0xf36c -#define STB0899_BASE_TP_BUFFER59 0x00000060 -#define STB0899_OFF0_TP_BUFFER60 0xf370 -#define STB0899_BASE_TP_BUFFER60 0x00000060 -#define STB0899_OFF0_TP_BUFFER61 0xf374 -#define STB0899_BASE_TP_BUFFER61 0x00000060 -#define STB0899_OFF0_TP_BUFFER62 0xf378 -#define STB0899_BASE_TP_BUFFER62 0x00000060 -#define STB0899_OFF0_TP_BUFFER63 0xf37c -#define STB0899_BASE_TP_BUFFER63 0x00000060 - -#define STB0899_OFF0_RESET_CNTRL 0xf300 -#define STB0899_BASE_RESET_CNTRL 0x00000400 -#define STB0899_DVBS2_RESET (0x01 << 0) -#define STB0899_OFFST_DVBS2_RESET 0 -#define STB0899_WIDTH_DVBS2_RESET 1 - -#define STB0899_OFF0_ACM_ENABLE 0xf304 -#define STB0899_BASE_ACM_ENABLE 0x00000400 -#define STB0899_ACM_ENABLE 1 - -#define STB0899_OFF0_DESCR_CNTRL 0xf30c -#define STB0899_BASE_DESCR_CNTRL 0x00000400 -#define STB0899_OFFST_DESCR_CNTRL 0 -#define STB0899_WIDTH_DESCR_CNTRL 16 - -#define STB0899_OFF0_UWP_CNTRL1 0xf320 -#define STB0899_BASE_UWP_CNTRL1 0x00000400 -#define STB0899_UWP_TH_SOF (0x7fff << 11) -#define STB0899_OFFST_UWP_TH_SOF 11 -#define STB0899_WIDTH_UWP_TH_SOF 15 -#define STB0899_UWP_ESN0_QUANT (0xff << 3) -#define STB0899_OFFST_UWP_ESN0_QUANT 3 -#define STB0899_WIDTH_UWP_ESN0_QUANT 8 -#define STB0899_UWP_ESN0_AVE (0x03 << 1) -#define STB0899_OFFST_UWP_ESN0_AVE 1 -#define STB0899_WIDTH_UWP_ESN0_AVE 2 -#define STB0899_UWP_START (0x01 << 0) -#define STB0899_OFFST_UWP_START 0 -#define STB0899_WIDTH_UWP_START 1 - -#define STB0899_OFF0_UWP_CNTRL2 0xf324 -#define STB0899_BASE_UWP_CNTRL2 0x00000400 -#define STB0899_UWP_MISS_TH (0xff << 16) -#define STB0899_OFFST_UWP_MISS_TH 16 -#define STB0899_WIDTH_UWP_MISS_TH 8 -#define STB0899_FE_FINE_TRK (0xff << 8) -#define STB0899_OFFST_FE_FINE_TRK 8 -#define STB0899_WIDTH_FE_FINE_TRK 8 -#define STB0899_FE_COARSE_TRK (0xff << 0) -#define STB0899_OFFST_FE_COARSE_TRK 0 -#define STB0899_WIDTH_FE_COARSE_TRK 8 - -#define STB0899_OFF0_UWP_STAT1 0xf328 -#define STB0899_BASE_UWP_STAT1 0x00000400 -#define STB0899_UWP_STATE (0x03ff << 15) -#define STB0899_OFFST_UWP_STATE 15 -#define STB0899_WIDTH_UWP_STATE 10 -#define STB0899_UW_MAX_PEAK (0x7fff << 0) -#define STB0899_OFFST_UW_MAX_PEAK 0 -#define STB0899_WIDTH_UW_MAX_PEAK 15 - -#define STB0899_OFF0_UWP_STAT2 0xf32c -#define STB0899_BASE_UWP_STAT2 0x00000400 -#define STB0899_ESNO_EST (0x07ffff << 7) -#define STB0899_OFFST_ESN0_EST 7 -#define STB0899_WIDTH_ESN0_EST 19 -#define STB0899_UWP_DECODE_MOD (0x7f << 0) -#define STB0899_OFFST_UWP_DECODE_MOD 0 -#define STB0899_WIDTH_UWP_DECODE_MOD 7 - -#define STB0899_OFF0_DMD_CORE_ID 0xf334 -#define STB0899_BASE_DMD_CORE_ID 0x00000400 -#define STB0899_CORE_ID (0xffffffff << 0) -#define STB0899_OFFST_CORE_ID 0 -#define STB0899_WIDTH_CORE_ID 32 - -#define STB0899_OFF0_DMD_VERSION_ID 0xf33c -#define STB0899_BASE_DMD_VERSION_ID 0x00000400 -#define STB0899_VERSION_ID (0xff << 0) -#define STB0899_OFFST_VERSION_ID 0 -#define STB0899_WIDTH_VERSION_ID 8 - -#define STB0899_OFF0_DMD_STAT2 0xf340 -#define STB0899_BASE_DMD_STAT2 0x00000400 -#define STB0899_CSM_LOCK (0x01 << 1) -#define STB0899_OFFST_CSM_LOCK 1 -#define STB0899_WIDTH_CSM_LOCK 1 -#define STB0899_UWP_LOCK (0x01 << 0) -#define STB0899_OFFST_UWP_LOCK 0 -#define STB0899_WIDTH_UWP_LOCK 1 - -#define STB0899_OFF0_FREQ_ADJ_SCALE 0xf344 -#define STB0899_BASE_FREQ_ADJ_SCALE 0x00000400 -#define STB0899_FREQ_ADJ_SCALE (0x0fff << 0) -#define STB0899_OFFST_FREQ_ADJ_SCALE 0 -#define STB0899_WIDTH_FREQ_ADJ_SCALE 12 - -#define STB0899_OFF0_UWP_CNTRL3 0xf34c -#define STB0899_BASE_UWP_CNTRL3 0x00000400 -#define STB0899_UWP_TH_TRACK (0x7fff << 15) -#define STB0899_OFFST_UWP_TH_TRACK 15 -#define STB0899_WIDTH_UWP_TH_TRACK 15 -#define STB0899_UWP_TH_ACQ (0x7fff << 0) -#define STB0899_OFFST_UWP_TH_ACQ 0 -#define STB0899_WIDTH_UWP_TH_ACQ 15 - -#define STB0899_OFF0_SYM_CLK_SEL 0xf350 -#define STB0899_BASE_SYM_CLK_SEL 0x00000400 -#define STB0899_SYM_CLK_SEL (0x03 << 0) -#define STB0899_OFFST_SYM_CLK_SEL 0 -#define STB0899_WIDTH_SYM_CLK_SEL 2 - -#define STB0899_OFF0_SOF_SRCH_TO 0xf354 -#define STB0899_BASE_SOF_SRCH_TO 0x00000400 -#define STB0899_SOF_SEARCH_TIMEOUT (0x3fffff << 0) -#define STB0899_OFFST_SOF_SEARCH_TIMEOUT 0 -#define STB0899_WIDTH_SOF_SEARCH_TIMEOUT 22 - -#define STB0899_OFF0_ACQ_CNTRL1 0xf358 -#define STB0899_BASE_ACQ_CNTRL1 0x00000400 -#define STB0899_FE_FINE_ACQ (0xff << 8) -#define STB0899_OFFST_FE_FINE_ACQ 8 -#define STB0899_WIDTH_FE_FINE_ACQ 8 -#define STB0899_FE_COARSE_ACQ (0xff << 0) -#define STB0899_OFFST_FE_COARSE_ACQ 0 -#define STB0899_WIDTH_FE_COARSE_ACQ 8 - -#define STB0899_OFF0_ACQ_CNTRL2 0xf35c -#define STB0899_BASE_ACQ_CNTRL2 0x00000400 -#define STB0899_ZIGZAG (0x01 << 25) -#define STB0899_OFFST_ZIGZAG 25 -#define STB0899_WIDTH_ZIGZAG 1 -#define STB0899_NUM_STEPS (0xff << 17) -#define STB0899_OFFST_NUM_STEPS 17 -#define STB0899_WIDTH_NUM_STEPS 8 -#define STB0899_FREQ_STEPSIZE (0x1ffff << 0) -#define STB0899_OFFST_FREQ_STEPSIZE 0 -#define STB0899_WIDTH_FREQ_STEPSIZE 17 - -#define STB0899_OFF0_ACQ_CNTRL3 0xf360 -#define STB0899_BASE_ACQ_CNTRL3 0x00000400 -#define STB0899_THRESHOLD_SCL (0x3f << 23) -#define STB0899_OFFST_THRESHOLD_SCL 23 -#define STB0899_WIDTH_THRESHOLD_SCL 6 -#define STB0899_UWP_TH_SRCH (0x7fff << 8) -#define STB0899_OFFST_UWP_TH_SRCH 8 -#define STB0899_WIDTH_UWP_TH_SRCH 15 -#define STB0899_AUTO_REACQUIRE (0x01 << 7) -#define STB0899_OFFST_AUTO_REACQUIRE 7 -#define STB0899_WIDTH_AUTO_REACQUIRE 1 -#define STB0899_TRACK_LOCK_SEL (0x01 << 6) -#define STB0899_OFFST_TRACK_LOCK_SEL 6 -#define STB0899_WIDTH_TRACK_LOCK_SEL 1 -#define STB0899_ACQ_SEARCH_MODE (0x03 << 4) -#define STB0899_OFFST_ACQ_SEARCH_MODE 4 -#define STB0899_WIDTH_ACQ_SEARCH_MODE 2 -#define STB0899_CONFIRM_FRAMES (0x0f << 0) -#define STB0899_OFFST_CONFIRM_FRAMES 0 -#define STB0899_WIDTH_CONFIRM_FRAMES 4 - -#define STB0899_OFF0_FE_SETTLE 0xf364 -#define STB0899_BASE_FE_SETTLE 0x00000400 -#define STB0899_SETTLING_TIME (0x3fffff << 0) -#define STB0899_OFFST_SETTLING_TIME 0 -#define STB0899_WIDTH_SETTLING_TIME 22 - -#define STB0899_OFF0_AC_DWELL 0xf368 -#define STB0899_BASE_AC_DWELL 0x00000400 -#define STB0899_DWELL_TIME (0x3fffff << 0) -#define STB0899_OFFST_DWELL_TIME 0 -#define STB0899_WIDTH_DWELL_TIME 22 - -#define STB0899_OFF0_ACQUIRE_TRIG 0xf36c -#define STB0899_BASE_ACQUIRE_TRIG 0x00000400 -#define STB0899_ACQUIRE (0x01 << 0) -#define STB0899_OFFST_ACQUIRE 0 -#define STB0899_WIDTH_ACQUIRE 1 - -#define STB0899_OFF0_LOCK_LOST 0xf370 -#define STB0899_BASE_LOCK_LOST 0x00000400 -#define STB0899_LOCK_LOST (0x01 << 0) -#define STB0899_OFFST_LOCK_LOST 0 -#define STB0899_WIDTH_LOCK_LOST 1 - -#define STB0899_OFF0_ACQ_STAT1 0xf374 -#define STB0899_BASE_ACQ_STAT1 0x00000400 -#define STB0899_STEP_FREQ (0x1fffff << 11) -#define STB0899_OFFST_STEP_FREQ 11 -#define STB0899_WIDTH_STEP_FREQ 21 -#define STB0899_ACQ_STATE (0x07 << 8) -#define STB0899_OFFST_ACQ_STATE 8 -#define STB0899_WIDTH_ACQ_STATE 3 -#define STB0899_UW_DETECT_COUNT (0xff << 0) -#define STB0899_OFFST_UW_DETECT_COUNT 0 -#define STB0899_WIDTH_UW_DETECT_COUNT 8 - -#define STB0899_OFF0_ACQ_TIMEOUT 0xf378 -#define STB0899_BASE_ACQ_TIMEOUT 0x00000400 -#define STB0899_ACQ_TIMEOUT (0x3fffff << 0) -#define STB0899_OFFST_ACQ_TIMEOUT 0 -#define STB0899_WIDTH_ACQ_TIMEOUT 22 - -#define STB0899_OFF0_ACQ_TIME 0xf37c -#define STB0899_BASE_ACQ_TIME 0x00000400 -#define STB0899_ACQ_TIME_SYM (0xffffff << 0) -#define STB0899_OFFST_ACQ_TIME_SYM 0 -#define STB0899_WIDTH_ACQ_TIME_SYM 24 - -#define STB0899_OFF0_FINAL_AGC_CNTRL 0xf308 -#define STB0899_BASE_FINAL_AGC_CNTRL 0x00000440 -#define STB0899_FINAL_GAIN_INIT (0x3fff << 12) -#define STB0899_OFFST_FINAL_GAIN_INIT 12 -#define STB0899_WIDTH_FINAL_GAIN_INIT 14 -#define STB0899_FINAL_LOOP_GAIN (0x0f << 8) -#define STB0899_OFFST_FINAL_LOOP_GAIN 8 -#define STB0899_WIDTH_FINAL_LOOP_GAIN 4 -#define STB0899_FINAL_LD_GAIN_INIT (0x01 << 7) -#define STB0899_OFFST_FINAL_LD_GAIN_INIT 7 -#define STB0899_WIDTH_FINAL_LD_GAIN_INIT 1 -#define STB0899_FINAL_AGC_REF (0x7f << 0) -#define STB0899_OFFST_FINAL_AGC_REF 0 -#define STB0899_WIDTH_FINAL_AGC_REF 7 - -#define STB0899_OFF0_FINAL_AGC_GAIN 0xf30c -#define STB0899_BASE_FINAL_AGC_GAIN 0x00000440 -#define STB0899_FINAL_AGC_GAIN (0x3fff << 0) -#define STB0899_OFFST_FINAL_AGC_GAIN 0 -#define STB0899_WIDTH_FINAL_AGC_GAIN 14 - -#define STB0899_OFF0_EQUALIZER_INIT 0xf310 -#define STB0899_BASE_EQUALIZER_INIT 0x00000440 -#define STB0899_EQ_SRST (0x01 << 1) -#define STB0899_OFFST_EQ_SRST 1 -#define STB0899_WIDTH_EQ_SRST 1 -#define STB0899_EQ_INIT (0x01 << 0) -#define STB0899_OFFST_EQ_INIT 0 -#define STB0899_WIDTH_EQ_INIT 1 - -#define STB0899_OFF0_EQ_CNTRL 0xf314 -#define STB0899_BASE_EQ_CNTRL 0x00000440 -#define STB0899_EQ_ADAPT_MODE (0x01 << 18) -#define STB0899_OFFST_EQ_ADAPT_MODE 18 -#define STB0899_WIDTH_EQ_ADAPT_MODE 1 -#define STB0899_EQ_DELAY (0x0f << 14) -#define STB0899_OFFST_EQ_DELAY 14 -#define STB0899_WIDTH_EQ_DELAY 4 -#define STB0899_EQ_QUANT_LEVEL (0xff << 6) -#define STB0899_OFFST_EQ_QUANT_LEVEL 6 -#define STB0899_WIDTH_EQ_QUANT_LEVEL 8 -#define STB0899_EQ_DISABLE_UPDATE (0x01 << 5) -#define STB0899_OFFST_EQ_DISABLE_UPDATE 5 -#define STB0899_WIDTH_EQ_DISABLE_UPDATE 1 -#define STB0899_EQ_BYPASS (0x01 << 4) -#define STB0899_OFFST_EQ_BYPASS 4 -#define STB0899_WIDTH_EQ_BYPASS 1 -#define STB0899_EQ_SHIFT (0x0f << 0) -#define STB0899_OFFST_EQ_SHIFT 0 -#define STB0899_WIDTH_EQ_SHIFT 4 - -#define STB0899_OFF0_EQ_I_INIT_COEFF_0 0xf320 -#define STB0899_OFF1_EQ_I_INIT_COEFF_1 0xf324 -#define STB0899_OFF2_EQ_I_INIT_COEFF_2 0xf328 -#define STB0899_OFF3_EQ_I_INIT_COEFF_3 0xf32c -#define STB0899_OFF4_EQ_I_INIT_COEFF_4 0xf330 -#define STB0899_OFF5_EQ_I_INIT_COEFF_5 0xf334 -#define STB0899_OFF6_EQ_I_INIT_COEFF_6 0xf338 -#define STB0899_OFF7_EQ_I_INIT_COEFF_7 0xf33c -#define STB0899_OFF8_EQ_I_INIT_COEFF_8 0xf340 -#define STB0899_OFF9_EQ_I_INIT_COEFF_9 0xf344 -#define STB0899_OFFa_EQ_I_INIT_COEFF_10 0xf348 -#define STB0899_BASE_EQ_I_INIT_COEFF_N 0x00000440 -#define STB0899_EQ_I_INIT_COEFF_N (0x0fff << 0) -#define STB0899_OFFST_EQ_I_INIT_COEFF_N 0 -#define STB0899_WIDTH_EQ_I_INIT_COEFF_N 12 - -#define STB0899_OFF0_EQ_Q_INIT_COEFF_0 0xf350 -#define STB0899_OFF1_EQ_Q_INIT_COEFF_1 0xf354 -#define STB0899_OFF2_EQ_Q_INIT_COEFF_2 0xf358 -#define STB0899_OFF3_EQ_Q_INIT_COEFF_3 0xf35c -#define STB0899_OFF4_EQ_Q_INIT_COEFF_4 0xf360 -#define STB0899_OFF5_EQ_Q_INIT_COEFF_5 0xf364 -#define STB0899_OFF6_EQ_Q_INIT_COEFF_6 0xf368 -#define STB0899_OFF7_EQ_Q_INIT_COEFF_7 0xf36c -#define STB0899_OFF8_EQ_Q_INIT_COEFF_8 0xf370 -#define STB0899_OFF9_EQ_Q_INIT_COEFF_9 0xf374 -#define STB0899_OFFa_EQ_Q_INIT_COEFF_10 0xf378 -#define STB0899_BASE_EQ_Q_INIT_COEFF_N 0x00000440 -#define STB0899_EQ_Q_INIT_COEFF_N (0x0fff << 0) -#define STB0899_OFFST_EQ_Q_INIT_COEFF_N 0 -#define STB0899_WIDTH_EQ_Q_INIT_COEFF_N 12 - -#define STB0899_OFF0_EQ_I_OUT_COEFF_0 0xf300 -#define STB0899_OFF1_EQ_I_OUT_COEFF_1 0xf304 -#define STB0899_OFF2_EQ_I_OUT_COEFF_2 0xf308 -#define STB0899_OFF3_EQ_I_OUT_COEFF_3 0xf30c -#define STB0899_OFF4_EQ_I_OUT_COEFF_4 0xf310 -#define STB0899_OFF5_EQ_I_OUT_COEFF_5 0xf314 -#define STB0899_OFF6_EQ_I_OUT_COEFF_6 0xf318 -#define STB0899_OFF7_EQ_I_OUT_COEFF_7 0xf31c -#define STB0899_OFF8_EQ_I_OUT_COEFF_8 0xf320 -#define STB0899_OFF9_EQ_I_OUT_COEFF_9 0xf324 -#define STB0899_OFFa_EQ_I_OUT_COEFF_10 0xf328 -#define STB0899_BASE_EQ_I_OUT_COEFF_N 0x00000460 -#define STB0899_EQ_I_OUT_COEFF_N (0x0fff << 0) -#define STB0899_OFFST_EQ_I_OUT_COEFF_N 0 -#define STB0899_WIDTH_EQ_I_OUT_COEFF_N 12 - -#define STB0899_OFF0_EQ_Q_OUT_COEFF_0 0xf330 -#define STB0899_OFF1_EQ_Q_OUT_COEFF_1 0xf334 -#define STB0899_OFF2_EQ_Q_OUT_COEFF_2 0xf338 -#define STB0899_OFF3_EQ_Q_OUT_COEFF_3 0xf33c -#define STB0899_OFF4_EQ_Q_OUT_COEFF_4 0xf340 -#define STB0899_OFF5_EQ_Q_OUT_COEFF_5 0xf344 -#define STB0899_OFF6_EQ_Q_OUT_COEFF_6 0xf348 -#define STB0899_OFF7_EQ_Q_OUT_COEFF_7 0xf34c -#define STB0899_OFF8_EQ_Q_OUT_COEFF_8 0xf350 -#define STB0899_OFF9_EQ_Q_OUT_COEFF_9 0xf354 -#define STB0899_OFFa_EQ_Q_OUT_COEFF_10 0xf358 -#define STB0899_BASE_EQ_Q_OUT_COEFF_N 0x00000460 -#define STB0899_EQ_Q_OUT_COEFF_N (0x0fff << 0) -#define STB0899_OFFST_EQ_Q_OUT_COEFF_N 0 -#define STB0899_WIDTH_EQ_Q_OUT_COEFF_N 12 - -/* S2 FEC */ -#define STB0899_OFF0_BLOCK_LNGTH 0xfa04 -#define STB0899_BASE_BLOCK_LNGTH 0x00000000 -#define STB0899_BLOCK_LENGTH (0xff << 0) -#define STB0899_OFFST_BLOCK_LENGTH 0 -#define STB0899_WIDTH_BLOCK_LENGTH 8 - -#define STB0899_OFF0_ROW_STR 0xfa08 -#define STB0899_BASE_ROW_STR 0x00000000 -#define STB0899_ROW_STRIDE (0xff << 0) -#define STB0899_OFFST_ROW_STRIDE 0 -#define STB0899_WIDTH_ROW_STRIDE 8 - -#define STB0899_OFF0_MAX_ITER 0xfa0c -#define STB0899_BASE_MAX_ITER 0x00000000 -#define STB0899_MAX_ITERATIONS (0xff << 0) -#define STB0899_OFFST_MAX_ITERATIONS 0 -#define STB0899_WIDTH_MAX_ITERATIONS 8 - -#define STB0899_OFF0_BN_END_ADDR 0xfa10 -#define STB0899_BASE_BN_END_ADDR 0x00000000 -#define STB0899_BN_END_ADDR (0x0fff << 0) -#define STB0899_OFFST_BN_END_ADDR 0 -#define STB0899_WIDTH_BN_END_ADDR 12 - -#define STB0899_OFF0_CN_END_ADDR 0xfa14 -#define STB0899_BASE_CN_END_ADDR 0x00000000 -#define STB0899_CN_END_ADDR (0x0fff << 0) -#define STB0899_OFFST_CN_END_ADDR 0 -#define STB0899_WIDTH_CN_END_ADDR 12 - -#define STB0899_OFF0_INFO_LENGTH 0xfa1c -#define STB0899_BASE_INFO_LENGTH 0x00000000 -#define STB0899_INFO_LENGTH (0xff << 0) -#define STB0899_OFFST_INFO_LENGTH 0 -#define STB0899_WIDTH_INFO_LENGTH 8 - -#define STB0899_OFF0_BOT_ADDR 0xfa20 -#define STB0899_BASE_BOT_ADDR 0x00000000 -#define STB0899_BOTTOM_BASE_ADDR (0x03ff << 0) -#define STB0899_OFFST_BOTTOM_BASE_ADDR 0 -#define STB0899_WIDTH_BOTTOM_BASE_ADDR 10 - -#define STB0899_OFF0_BCH_BLK_LN 0xfa24 -#define STB0899_BASE_BCH_BLK_LN 0x00000000 -#define STB0899_BCH_BLOCK_LENGTH (0xffff << 0) -#define STB0899_OFFST_BCH_BLOCK_LENGTH 0 -#define STB0899_WIDTH_BCH_BLOCK_LENGTH 16 - -#define STB0899_OFF0_BCH_T 0xfa28 -#define STB0899_BASE_BCH_T 0x00000000 -#define STB0899_BCH_T (0x0f << 0) -#define STB0899_OFFST_BCH_T 0 -#define STB0899_WIDTH_BCH_T 4 - -#define STB0899_OFF0_CNFG_MODE 0xfa00 -#define STB0899_BASE_CNFG_MODE 0x00000800 -#define STB0899_MODCOD (0x1f << 2) -#define STB0899_OFFST_MODCOD 2 -#define STB0899_WIDTH_MODCOD 5 -#define STB0899_MODCOD_SEL (0x01 << 1) -#define STB0899_OFFST_MODCOD_SEL 1 -#define STB0899_WIDTH_MODCOD_SEL 1 -#define STB0899_CONFIG_MODE (0x01 << 0) -#define STB0899_OFFST_CONFIG_MODE 0 -#define STB0899_WIDTH_CONFIG_MODE 1 - -#define STB0899_OFF0_LDPC_STAT 0xfa04 -#define STB0899_BASE_LDPC_STAT 0x00000800 -#define STB0899_ITERATION (0xff << 3) -#define STB0899_OFFST_ITERATION 3 -#define STB0899_WIDTH_ITERATION 8 -#define STB0899_LDPC_DEC_STATE (0x07 << 0) -#define STB0899_OFFST_LDPC_DEC_STATE 0 -#define STB0899_WIDTH_LDPC_DEC_STATE 3 - -#define STB0899_OFF0_ITER_SCALE 0xfa08 -#define STB0899_BASE_ITER_SCALE 0x00000800 -#define STB0899_ITERATION_SCALE (0xff << 0) -#define STB0899_OFFST_ITERATION_SCALE 0 -#define STB0899_WIDTH_ITERATION_SCALE 8 - -#define STB0899_OFF0_INPUT_MODE 0xfa0c -#define STB0899_BASE_INPUT_MODE 0x00000800 -#define STB0899_SD_BLOCK1_STREAM0 (0x01 << 0) -#define STB0899_OFFST_SD_BLOCK1_STREAM0 0 -#define STB0899_WIDTH_SD_BLOCK1_STREAM0 1 - -#define STB0899_OFF0_LDPCDECRST 0xfa10 -#define STB0899_BASE_LDPCDECRST 0x00000800 -#define STB0899_LDPC_DEC_RST (0x01 << 0) -#define STB0899_OFFST_LDPC_DEC_RST 0 -#define STB0899_WIDTH_LDPC_DEC_RST 1 - -#define STB0899_OFF0_CLK_PER_BYTE_RW 0xfa14 -#define STB0899_BASE_CLK_PER_BYTE_RW 0x00000800 -#define STB0899_CLKS_PER_BYTE (0x0f << 0) -#define STB0899_OFFST_CLKS_PER_BYTE 0 -#define STB0899_WIDTH_CLKS_PER_BYTE 5 - -#define STB0899_OFF0_BCH_ERRORS 0xfa18 -#define STB0899_BASE_BCH_ERRORS 0x00000800 -#define STB0899_BCH_ERRORS (0x0f << 0) -#define STB0899_OFFST_BCH_ERRORS 0 -#define STB0899_WIDTH_BCH_ERRORS 4 - -#define STB0899_OFF0_LDPC_ERRORS 0xfa1c -#define STB0899_BASE_LDPC_ERRORS 0x00000800 -#define STB0899_LDPC_ERRORS (0xffff << 0) -#define STB0899_OFFST_LDPC_ERRORS 0 -#define STB0899_WIDTH_LDPC_ERRORS 16 - -#define STB0899_OFF0_BCH_MODE 0xfa20 -#define STB0899_BASE_BCH_MODE 0x00000800 -#define STB0899_BCH_CORRECT_N (0x01 << 1) -#define STB0899_OFFST_BCH_CORRECT_N 1 -#define STB0899_WIDTH_BCH_CORRECT_N 1 -#define STB0899_FULL_BYPASS (0x01 << 0) -#define STB0899_OFFST_FULL_BYPASS 0 -#define STB0899_WIDTH_FULL_BYPASS 1 - -#define STB0899_OFF0_ERR_ACC_PER 0xfa24 -#define STB0899_BASE_ERR_ACC_PER 0x00000800 -#define STB0899_BCH_ERR_ACC_PERIOD (0x0f << 0) -#define STB0899_OFFST_BCH_ERR_ACC_PERIOD 0 -#define STB0899_WIDTH_BCH_ERR_ACC_PERIOD 4 - -#define STB0899_OFF0_BCH_ERR_ACC 0xfa28 -#define STB0899_BASE_BCH_ERR_ACC 0x00000800 -#define STB0899_BCH_ERR_ACCUM (0xff << 0) -#define STB0899_OFFST_BCH_ERR_ACCUM 0 -#define STB0899_WIDTH_BCH_ERR_ACCUM 8 - -#define STB0899_OFF0_FEC_CORE_ID_REG 0xfa2c -#define STB0899_BASE_FEC_CORE_ID_REG 0x00000800 -#define STB0899_FEC_CORE_ID (0xffffffff << 0) -#define STB0899_OFFST_FEC_CORE_ID 0 -#define STB0899_WIDTH_FEC_CORE_ID 32 - -#define STB0899_OFF0_FEC_VER_ID_REG 0xfa34 -#define STB0899_BASE_FEC_VER_ID_REG 0x00000800 -#define STB0899_FEC_VER_ID (0xff << 0) -#define STB0899_OFFST_FEC_VER_ID 0 -#define STB0899_WIDTH_FEC_VER_ID 8 - -#define STB0899_OFF0_FEC_TP_SEL 0xfa38 -#define STB0899_BASE_FEC_TP_SEL 0x00000800 - -#define STB0899_OFF0_CSM_CNTRL1 0xf310 -#define STB0899_BASE_CSM_CNTRL1 0x00000400 -#define STB0899_CSM_FORCE_FREQLOCK (0x01 << 19) -#define STB0899_OFFST_CSM_FORCE_FREQLOCK 19 -#define STB0899_WIDTH_CSM_FORCE_FREQLOCK 1 -#define STB0899_CSM_FREQ_LOCKSTATE (0x01 << 18) -#define STB0899_OFFST_CSM_FREQ_LOCKSTATE 18 -#define STB0899_WIDTH_CSM_FREQ_LOCKSTATE 1 -#define STB0899_CSM_AUTO_PARAM (0x01 << 17) -#define STB0899_OFFST_CSM_AUTO_PARAM 17 -#define STB0899_WIDTH_CSM_AUTO_PARAM 1 -#define STB0899_FE_LOOP_SHIFT (0x07 << 14) -#define STB0899_OFFST_FE_LOOP_SHIFT 14 -#define STB0899_WIDTH_FE_LOOP_SHIFT 3 -#define STB0899_CSM_AGC_SHIFT (0x07 << 11) -#define STB0899_OFFST_CSM_AGC_SHIFT 11 -#define STB0899_WIDTH_CSM_AGC_SHIFT 3 -#define STB0899_CSM_AGC_GAIN (0x1ff << 2) -#define STB0899_OFFST_CSM_AGC_GAIN 2 -#define STB0899_WIDTH_CSM_AGC_GAIN 9 -#define STB0899_CSM_TWO_PASS (0x01 << 1) -#define STB0899_OFFST_CSM_TWO_PASS 1 -#define STB0899_WIDTH_CSM_TWO_PASS 1 -#define STB0899_CSM_DVT_TABLE (0x01 << 0) -#define STB0899_OFFST_CSM_DVT_TABLE 0 -#define STB0899_WIDTH_CSM_DVT_TABLE 1 - -#define STB0899_OFF0_CSM_CNTRL2 0xf314 -#define STB0899_BASE_CSM_CNTRL2 0x00000400 -#define STB0899_CSM_GAMMA_RHO_ACQ (0x1ff << 9) -#define STB0899_OFFST_CSM_GAMMA_RHOACQ 9 -#define STB0899_WIDTH_CSM_GAMMA_RHOACQ 9 -#define STB0899_CSM_GAMMA_ACQ (0x1ff << 0) -#define STB0899_OFFST_CSM_GAMMA_ACQ 0 -#define STB0899_WIDTH_CSM_GAMMA_ACQ 9 - -#define STB0899_OFF0_CSM_CNTRL3 0xf318 -#define STB0899_BASE_CSM_CNTRL3 0x00000400 -#define STB0899_CSM_GAMMA_RHO_TRACK (0x1ff << 9) -#define STB0899_OFFST_CSM_GAMMA_RHOTRACK 9 -#define STB0899_WIDTH_CSM_GAMMA_RHOTRACK 9 -#define STB0899_CSM_GAMMA_TRACK (0x1ff << 0) -#define STB0899_OFFST_CSM_GAMMA_TRACK 0 -#define STB0899_WIDTH_CSM_GAMMA_TRACK 9 - -#define STB0899_OFF0_CSM_CNTRL4 0xf31c -#define STB0899_BASE_CSM_CNTRL4 0x00000400 -#define STB0899_CSM_PHASEDIFF_THRESH (0x0f << 8) -#define STB0899_OFFST_CSM_PHASEDIFF_THRESH 8 -#define STB0899_WIDTH_CSM_PHASEDIFF_THRESH 4 -#define STB0899_CSM_LOCKCOUNT_THRESH (0xff << 0) -#define STB0899_OFFST_CSM_LOCKCOUNT_THRESH 0 -#define STB0899_WIDTH_CSM_LOCKCOUNT_THRESH 8 - -/* Check on chapter 8 page 42 */ -#define STB0899_ERRCTRL1 0xf574 -#define STB0899_ERRCTRL2 0xf575 -#define STB0899_ERRCTRL3 0xf576 -#define STB0899_ERR_SRC_S1 (0x1f << 3) -#define STB0899_OFFST_ERR_SRC_S1 3 -#define STB0899_WIDTH_ERR_SRC_S1 5 -#define STB0899_ERR_SRC_S2 (0x0f << 0) -#define STB0899_OFFST_ERR_SRC_S2 0 -#define STB0899_WIDTH_ERR_SRC_S2 4 -#define STB0899_NOE (0x07 << 0) -#define STB0899_OFFST_NOE 0 -#define STB0899_WIDTH_NOE 3 - -#define STB0899_ECNT1M 0xf524 -#define STB0899_ECNT1L 0xf525 -#define STB0899_ECNT2M 0xf526 -#define STB0899_ECNT2L 0xf527 -#define STB0899_ECNT3M 0xf528 -#define STB0899_ECNT3L 0xf529 - -#define STB0899_DMONMSK1 0xf57b -#define STB0899_DMONMSK1_WAIT_1STEP (1 << 7) -#define STB0899_DMONMSK1_FREE_14 (1 << 6) -#define STB0899_DMONMSK1_AVRGVIT_CALC (1 << 5) -#define STB0899_DMONMSK1_FREE_12 (1 << 4) -#define STB0899_DMONMSK1_FREE_11 (1 << 3) -#define STB0899_DMONMSK1_B0DIV_CALC (1 << 2) -#define STB0899_DMONMSK1_KDIVB1_CALC (1 << 1) -#define STB0899_DMONMSK1_KDIVB2_CALC (1 << 0) - -#define STB0899_DMONMSK0 0xf57c -#define STB0899_DMONMSK0_SMOTTH_CALC (1 << 7) -#define STB0899_DMONMSK0_FREE_6 (1 << 6) -#define STB0899_DMONMSK0_SIGPOWER_CALC (1 << 5) -#define STB0899_DMONMSK0_QSEUIL_CALC (1 << 4) -#define STB0899_DMONMSK0_FREE_3 (1 << 3) -#define STB0899_DMONMSK0_FREE_2 (1 << 2) -#define STB0899_DMONMSK0_KVDIVB1_CALC (1 << 1) -#define STB0899_DMONMSK0_KVDIVB2_CALC (1 << 0) - -#define STB0899_TSULC 0xf549 -#define STB0899_ULNOSYNCBYTES (0x01 << 7) -#define STB0899_OFFST_ULNOSYNCBYTES 7 -#define STB0899_WIDTH_ULNOSYNCBYTES 1 -#define STB0899_ULPARITY_ON (0x01 << 6) -#define STB0899_OFFST_ULPARITY_ON 6 -#define STB0899_WIDTH_ULPARITY_ON 1 -#define STB0899_ULSYNCOUTRS (0x01 << 5) -#define STB0899_OFFST_ULSYNCOUTRS 5 -#define STB0899_WIDTH_ULSYNCOUTRS 1 -#define STB0899_ULDSS_PACKETS (0x01 << 0) -#define STB0899_OFFST_ULDSS_PACKETS 0 -#define STB0899_WIDTH_ULDSS_PACKETS 1 - -#define STB0899_TSLPL 0xf54b -#define STB0899_LLDVBS2_MODE (0x01 << 4) -#define STB0899_OFFST_LLDVBS2_MODE 4 -#define STB0899_WIDTH_LLDVBS2_MODE 1 -#define STB0899_LLISSYI_ON (0x01 << 3) -#define STB0899_OFFST_LLISSYI_ON 3 -#define STB0899_WIDTH_LLISSYI_ON 1 -#define STB0899_LLNPD_ON (0x01 << 2) -#define STB0899_OFFST_LLNPD_ON 2 -#define STB0899_WIDTH_LLNPD_ON 1 -#define STB0899_LLCRC8_ON (0x01 << 1) -#define STB0899_OFFST_LLCRC8_ON 1 -#define STB0899_WIDTH_LLCRC8_ON 1 - -#define STB0899_TSCFGH 0xf54c -#define STB0899_OUTRS_PS (0x01 << 6) -#define STB0899_OFFST_OUTRS_PS 6 -#define STB0899_WIDTH_OUTRS_PS 1 -#define STB0899_SYNCBYTE (0x01 << 5) -#define STB0899_OFFST_SYNCBYTE 5 -#define STB0899_WIDTH_SYNCBYTE 1 -#define STB0899_PFBIT (0x01 << 4) -#define STB0899_OFFST_PFBIT 4 -#define STB0899_WIDTH_PFBIT 1 -#define STB0899_ERR_BIT (0x01 << 3) -#define STB0899_OFFST_ERR_BIT 3 -#define STB0899_WIDTH_ERR_BIT 1 -#define STB0899_MPEG (0x01 << 2) -#define STB0899_OFFST_MPEG 2 -#define STB0899_WIDTH_MPEG 1 -#define STB0899_CLK_POL (0x01 << 1) -#define STB0899_OFFST_CLK_POL 1 -#define STB0899_WIDTH_CLK_POL 1 -#define STB0899_FORCE0 (0x01 << 0) -#define STB0899_OFFST_FORCE0 0 -#define STB0899_WIDTH_FORCE0 1 - -#define STB0899_TSCFGM 0xf54d -#define STB0899_LLPRIORITY (0x01 << 3) -#define STB0899_OFFST_LLPRIORIY 3 -#define STB0899_WIDTH_LLPRIORITY 1 -#define STB0899_EN188 (0x01 << 2) -#define STB0899_OFFST_EN188 2 -#define STB0899_WIDTH_EN188 1 - -#define STB0899_TSCFGL 0xf54e -#define STB0899_DEL_ERRPCK (0x01 << 7) -#define STB0899_OFFST_DEL_ERRPCK 7 -#define STB0899_WIDTH_DEL_ERRPCK 1 -#define STB0899_ERRFLAGSTD (0x01 << 5) -#define STB0899_OFFST_ERRFLAGSTD 5 -#define STB0899_WIDTH_ERRFLAGSTD 1 -#define STB0899_MPEGERR (0x01 << 4) -#define STB0899_OFFST_MPEGERR 4 -#define STB0899_WIDTH_MPEGERR 1 -#define STB0899_BCH_CHK (0x01 << 3) -#define STB0899_OFFST_BCH_CHK 5 -#define STB0899_WIDTH_BCH_CHK 1 -#define STB0899_CRC8CHK (0x01 << 2) -#define STB0899_OFFST_CRC8CHK 2 -#define STB0899_WIDTH_CRC8CHK 1 -#define STB0899_SPEC_INFO (0x01 << 1) -#define STB0899_OFFST_SPEC_INFO 1 -#define STB0899_WIDTH_SPEC_INFO 1 -#define STB0899_LOW_PRIO_CLK (0x01 << 0) -#define STB0899_OFFST_LOW_PRIO_CLK 0 -#define STB0899_WIDTH_LOW_PRIO_CLK 1 -#define STB0899_ERROR_NORM (0x00 << 0) -#define STB0899_OFFST_ERROR_NORM 0 -#define STB0899_WIDTH_ERROR_NORM 0 - -#define STB0899_TSOUT 0xf54f -#define STB0899_RSSYNCDEL 0xf550 -#define STB0899_TSINHDELH 0xf551 -#define STB0899_TSINHDELM 0xf552 -#define STB0899_TSINHDELL 0xf553 -#define STB0899_TSLLSTKM 0xf55a -#define STB0899_TSLLSTKL 0xf55b -#define STB0899_TSULSTKM 0xf55c -#define STB0899_TSULSTKL 0xf55d -#define STB0899_TSSTATUS 0xf561 - -#define STB0899_PDELCTRL 0xf600 -#define STB0899_INVERT_RES (0x01 << 7) -#define STB0899_OFFST_INVERT_RES 7 -#define STB0899_WIDTH_INVERT_RES 1 -#define STB0899_FORCE_ACCEPTED (0x01 << 6) -#define STB0899_OFFST_FORCE_ACCEPTED 6 -#define STB0899_WIDTH_FORCE_ACCEPTED 1 -#define STB0899_FILTER_EN (0x01 << 5) -#define STB0899_OFFST_FILTER_EN 5 -#define STB0899_WIDTH_FILTER_EN 1 -#define STB0899_LOCKFALL_THRESH (0x01 << 4) -#define STB0899_OFFST_LOCKFALL_THRESH 4 -#define STB0899_WIDTH_LOCKFALL_THRESH 1 -#define STB0899_HYST_EN (0x01 << 3) -#define STB0899_OFFST_HYST_EN 3 -#define STB0899_WIDTH_HYST_EN 1 -#define STB0899_HYST_SWRST (0x01 << 2) -#define STB0899_OFFST_HYST_SWRST 2 -#define STB0899_WIDTH_HYST_SWRST 1 -#define STB0899_ALGO_EN (0x01 << 1) -#define STB0899_OFFST_ALGO_EN 1 -#define STB0899_WIDTH_ALGO_EN 1 -#define STB0899_ALGO_SWRST (0x01 << 0) -#define STB0899_OFFST_ALGO_SWRST 0 -#define STB0899_WIDTH_ALGO_SWRST 1 - -#define STB0899_PDELCTRL2 0xf601 -#define STB0899_BBHCTRL1 0xf602 -#define STB0899_BBHCTRL2 0xf603 -#define STB0899_HYSTTHRESH 0xf604 - -#define STB0899_MATCSTM 0xf605 -#define STB0899_MATCSTL 0xf606 -#define STB0899_UPLCSTM 0xf607 -#define STB0899_UPLCSTL 0xf608 -#define STB0899_DFLCSTM 0xf609 -#define STB0899_DFLCSTL 0xf60a -#define STB0899_SYNCCST 0xf60b -#define STB0899_SYNCDCSTM 0xf60c -#define STB0899_SYNCDCSTL 0xf60d -#define STB0899_ISI_ENTRY 0xf60e -#define STB0899_ISI_BIT_EN 0xf60f -#define STB0899_MATSTRM 0xf610 -#define STB0899_MATSTRL 0xf611 -#define STB0899_UPLSTRM 0xf612 -#define STB0899_UPLSTRL 0xf613 -#define STB0899_DFLSTRM 0xf614 -#define STB0899_DFLSTRL 0xf615 -#define STB0899_SYNCSTR 0xf616 -#define STB0899_SYNCDSTRM 0xf617 -#define STB0899_SYNCDSTRL 0xf618 - -#define STB0899_CFGPDELSTATUS1 0xf619 -#define STB0899_BADDFL (0x01 << 6) -#define STB0899_OFFST_BADDFL 6 -#define STB0899_WIDTH_BADDFL 1 -#define STB0899_CONTINUOUS_STREAM (0x01 << 5) -#define STB0899_OFFST_CONTINUOUS_STREAM 5 -#define STB0899_WIDTH_CONTINUOUS_STREAM 1 -#define STB0899_ACCEPTED_STREAM (0x01 << 4) -#define STB0899_OFFST_ACCEPTED_STREAM 4 -#define STB0899_WIDTH_ACCEPTED_STREAM 1 -#define STB0899_BCH_ERRFLAG (0x01 << 3) -#define STB0899_OFFST_BCH_ERRFLAG 3 -#define STB0899_WIDTH_BCH_ERRFLAG 1 -#define STB0899_CRCRES (0x01 << 2) -#define STB0899_OFFST_CRCRES 2 -#define STB0899_WIDTH_CRCRES 1 -#define STB0899_CFGPDELSTATUS_LOCK (0x01 << 1) -#define STB0899_OFFST_CFGPDELSTATUS_LOCK 1 -#define STB0899_WIDTH_CFGPDELSTATUS_LOCK 1 -#define STB0899_1STLOCK (0x01 << 0) -#define STB0899_OFFST_1STLOCK 0 -#define STB0899_WIDTH_1STLOCK 1 - -#define STB0899_CFGPDELSTATUS2 0xf61a -#define STB0899_BBFERRORM 0xf61b -#define STB0899_BBFERRORL 0xf61c -#define STB0899_UPKTERRORM 0xf61d -#define STB0899_UPKTERRORL 0xf61e - -#define STB0899_TSTCK 0xff10 - -#define STB0899_TSTRES 0xff11 -#define STB0899_FRESLDPC (0x01 << 7) -#define STB0899_OFFST_FRESLDPC 7 -#define STB0899_WIDTH_FRESLDPC 1 -#define STB0899_FRESRS (0x01 << 6) -#define STB0899_OFFST_FRESRS 6 -#define STB0899_WIDTH_FRESRS 1 -#define STB0899_FRESVIT (0x01 << 5) -#define STB0899_OFFST_FRESVIT 5 -#define STB0899_WIDTH_FRESVIT 1 -#define STB0899_FRESMAS1_2 (0x01 << 4) -#define STB0899_OFFST_FRESMAS1_2 4 -#define STB0899_WIDTH_FRESMAS1_2 1 -#define STB0899_FRESACS (0x01 << 3) -#define STB0899_OFFST_FRESACS 3 -#define STB0899_WIDTH_FRESACS 1 -#define STB0899_FRESSYM (0x01 << 2) -#define STB0899_OFFST_FRESSYM 2 -#define STB0899_WIDTH_FRESSYM 1 -#define STB0899_FRESMAS (0x01 << 1) -#define STB0899_OFFST_FRESMAS 1 -#define STB0899_WIDTH_FRESMAS 1 -#define STB0899_FRESINT (0x01 << 0) -#define STB0899_OFFST_FRESINIT 0 -#define STB0899_WIDTH_FRESINIT 1 - -#define STB0899_TSTOUT 0xff12 -#define STB0899_EN_SIGNATURE (0x01 << 7) -#define STB0899_OFFST_EN_SIGNATURE 7 -#define STB0899_WIDTH_EN_SIGNATURE 1 -#define STB0899_BCLK_CLK (0x01 << 6) -#define STB0899_OFFST_BCLK_CLK 6 -#define STB0899_WIDTH_BCLK_CLK 1 -#define STB0899_SGNL_OUT (0x01 << 5) -#define STB0899_OFFST_SGNL_OUT 5 -#define STB0899_WIDTH_SGNL_OUT 1 -#define STB0899_TS (0x01 << 4) -#define STB0899_OFFST_TS 4 -#define STB0899_WIDTH_TS 1 -#define STB0899_CTEST (0x01 << 0) -#define STB0899_OFFST_CTEST 0 -#define STB0899_WIDTH_CTEST 1 - -#define STB0899_TSTIN 0xff13 -#define STB0899_TEST_IN (0x01 << 7) -#define STB0899_OFFST_TEST_IN 7 -#define STB0899_WIDTH_TEST_IN 1 -#define STB0899_EN_ADC (0x01 << 6) -#define STB0899_OFFST_EN_ADC 6 -#define STB0899_WIDTH_ENADC 1 -#define STB0899_SGN_ADC (0x01 << 5) -#define STB0899_OFFST_SGN_ADC 5 -#define STB0899_WIDTH_SGN_ADC 1 -#define STB0899_BCLK_IN (0x01 << 4) -#define STB0899_OFFST_BCLK_IN 4 -#define STB0899_WIDTH_BCLK_IN 1 -#define STB0899_JETONIN_MODE (0x01 << 3) -#define STB0899_OFFST_JETONIN_MODE 3 -#define STB0899_WIDTH_JETONIN_MODE 1 -#define STB0899_BCLK_VALUE (0x01 << 2) -#define STB0899_OFFST_BCLK_VALUE 2 -#define STB0899_WIDTH_BCLK_VALUE 1 -#define STB0899_SGNRST_T12 (0x01 << 1) -#define STB0899_OFFST_SGNRST_T12 1 -#define STB0899_WIDTH_SGNRST_T12 1 -#define STB0899_LOWSP_ENAX (0x01 << 0) -#define STB0899_OFFST_LOWSP_ENAX 0 -#define STB0899_WIDTH_LOWSP_ENAX 1 - -#define STB0899_TSTSYS 0xff14 -#define STB0899_TSTCHIP 0xff15 -#define STB0899_TSTFREE 0xff16 -#define STB0899_TSTI2C 0xff17 -#define STB0899_BITSPEEDM 0xff1c -#define STB0899_BITSPEEDL 0xff1d -#define STB0899_TBUSBIT 0xff1e -#define STB0899_TSTDIS 0xff24 -#define STB0899_TSTDISRX 0xff25 -#define STB0899_TSTJETON 0xff28 -#define STB0899_TSTDCADJ 0xff40 -#define STB0899_TSTAGC1 0xff41 -#define STB0899_TSTAGC1N 0xff42 -#define STB0899_TSTPOLYPH 0xff48 -#define STB0899_TSTR 0xff49 -#define STB0899_TSTAGC2 0xff4a -#define STB0899_TSTCTL1 0xff4b -#define STB0899_TSTCTL2 0xff4c -#define STB0899_TSTCTL3 0xff4d -#define STB0899_TSTDEMAP 0xff50 -#define STB0899_TSTDEMAP2 0xff51 -#define STB0899_TSTDEMMON 0xff52 -#define STB0899_TSTRATE 0xff53 -#define STB0899_TSTSELOUT 0xff54 -#define STB0899_TSYNC 0xff55 -#define STB0899_TSTERR 0xff56 -#define STB0899_TSTRAM1 0xff58 -#define STB0899_TSTVSELOUT 0xff59 -#define STB0899_TSTFORCEIN 0xff5a -#define STB0899_TSTRS1 0xff5c -#define STB0899_TSTRS2 0xff5d -#define STB0899_TSTRS3 0xff53 - -#define STB0899_INTBUFSTATUS 0xf200 -#define STB0899_INTBUFCTRL 0xf201 -#define STB0899_PCKLENUL 0xf55e -#define STB0899_PCKLENLL 0xf55f -#define STB0899_RSPCKLEN 0xf560 - -/* 2 registers */ -#define STB0899_SYNCDCST 0xf60c - -/* DiSEqC */ -#define STB0899_DISCNTRL1 0xf0a0 -#define STB0899_TIMOFF (0x01 << 7) -#define STB0899_OFFST_TIMOFF 7 -#define STB0899_WIDTH_TIMOFF 1 -#define STB0899_DISEQCRESET (0x01 << 6) -#define STB0899_OFFST_DISEQCRESET 6 -#define STB0899_WIDTH_DISEQCRESET 1 -#define STB0899_TIMCMD (0x03 << 4) -#define STB0899_OFFST_TIMCMD 4 -#define STB0899_WIDTH_TIMCMD 2 -#define STB0899_DISPRECHARGE (0x01 << 2) -#define STB0899_OFFST_DISPRECHARGE 2 -#define STB0899_WIDTH_DISPRECHARGE 1 -#define STB0899_DISEQCMODE (0x03 << 0) -#define STB0899_OFFST_DISEQCMODE 0 -#define STB0899_WIDTH_DISEQCMODE 2 - -#define STB0899_DISCNTRL2 0xf0a1 -#define STB0899_RECEIVER_ON (0x01 << 7) -#define STB0899_OFFST_RECEIVER_ON 7 -#define STB0899_WIDTH_RECEIVER_ON 1 -#define STB0899_IGNO_SHORT_22K (0x01 << 6) -#define STB0899_OFFST_IGNO_SHORT_22K 6 -#define STB0899_WIDTH_IGNO_SHORT_22K 1 -#define STB0899_ONECHIP_TRX (0x01 << 5) -#define STB0899_OFFST_ONECHIP_TRX 5 -#define STB0899_WIDTH_ONECHIP_TRX 1 -#define STB0899_EXT_ENVELOP (0x01 << 4) -#define STB0899_OFFST_EXT_ENVELOP 4 -#define STB0899_WIDTH_EXT_ENVELOP 1 -#define STB0899_PIN_SELECT (0x03 << 2) -#define STB0899_OFFST_PIN_SELCT 2 -#define STB0899_WIDTH_PIN_SELCT 2 -#define STB0899_IRQ_RXEND (0x01 << 1) -#define STB0899_OFFST_IRQ_RXEND 1 -#define STB0899_WIDTH_IRQ_RXEND 1 -#define STB0899_IRQ_4NBYTES (0x01 << 0) -#define STB0899_OFFST_IRQ_4NBYTES 0 -#define STB0899_WIDTH_IRQ_4NBYTES 1 - -#define STB0899_DISRX_ST0 0xf0a4 -#define STB0899_RXEND (0x01 << 7) -#define STB0899_OFFST_RXEND 7 -#define STB0899_WIDTH_RXEND 1 -#define STB0899_RXACTIVE (0x01 << 6) -#define STB0899_OFFST_RXACTIVE 6 -#define STB0899_WIDTH_RXACTIVE 1 -#define STB0899_SHORT22K (0x01 << 5) -#define STB0899_OFFST_SHORT22K 5 -#define STB0899_WIDTH_SHORT22K 1 -#define STB0899_CONTTONE (0x01 << 4) -#define STB0899_OFFST_CONTTONE 4 -#define STB0899_WIDTH_CONTONE 1 -#define STB0899_4BFIFOREDY (0x01 << 3) -#define STB0899_OFFST_4BFIFOREDY 3 -#define STB0899_WIDTH_4BFIFOREDY 1 -#define STB0899_FIFOEMPTY (0x01 << 2) -#define STB0899_OFFST_FIFOEMPTY 2 -#define STB0899_WIDTH_FIFOEMPTY 1 -#define STB0899_ABORTTRX (0x01 << 0) -#define STB0899_OFFST_ABORTTRX 0 -#define STB0899_WIDTH_ABORTTRX 1 - -#define STB0899_DISRX_ST1 0xf0a5 -#define STB0899_RXFAIL (0x01 << 7) -#define STB0899_OFFST_RXFAIL 7 -#define STB0899_WIDTH_RXFAIL 1 -#define STB0899_FIFOPFAIL (0x01 << 6) -#define STB0899_OFFST_FIFOPFAIL 6 -#define STB0899_WIDTH_FIFOPFAIL 1 -#define STB0899_RXNONBYTES (0x01 << 5) -#define STB0899_OFFST_RXNONBYTES 5 -#define STB0899_WIDTH_RXNONBYTES 1 -#define STB0899_FIFOOVF (0x01 << 4) -#define STB0899_OFFST_FIFOOVF 4 -#define STB0899_WIDTH_FIFOOVF 1 -#define STB0899_FIFOBYTENBR (0x0f << 0) -#define STB0899_OFFST_FIFOBYTENBR 0 -#define STB0899_WIDTH_FIFOBYTENBR 4 - -#define STB0899_DISPARITY 0xf0a6 - -#define STB0899_DISFIFO 0xf0a7 - -#define STB0899_DISSTATUS 0xf0a8 -#define STB0899_FIFOFULL (0x01 << 6) -#define STB0899_OFFST_FIFOFULL 6 -#define STB0899_WIDTH_FIFOFULL 1 -#define STB0899_TXIDLE (0x01 << 5) -#define STB0899_OFFST_TXIDLE 5 -#define STB0899_WIDTH_TXIDLE 1 -#define STB0899_GAPBURST (0x01 << 4) -#define STB0899_OFFST_GAPBURST 4 -#define STB0899_WIDTH_GAPBURST 1 -#define STB0899_TXFIFOBYTES (0x0f << 0) -#define STB0899_OFFST_TXFIFOBYTES 0 -#define STB0899_WIDTH_TXFIFOBYTES 4 -#define STB0899_DISF22 0xf0a9 - -#define STB0899_DISF22RX 0xf0aa - -/* General Purpose */ -#define STB0899_SYSREG 0xf101 -#define STB0899_ACRPRESC 0xf110 -#define STB0899_OFFST_RSVD2 7 -#define STB0899_WIDTH_RSVD2 1 -#define STB0899_OFFST_ACRPRESC 4 -#define STB0899_WIDTH_ACRPRESC 3 -#define STB0899_OFFST_RSVD1 3 -#define STB0899_WIDTH_RSVD1 1 -#define STB0899_OFFST_ACRPRESC2 0 -#define STB0899_WIDTH_ACRPRESC2 3 - -#define STB0899_ACRDIV1 0xf111 -#define STB0899_ACRDIV2 0xf112 -#define STB0899_DACR1 0xf113 -#define STB0899_DACR2 0xf114 -#define STB0899_OUTCFG 0xf11c -#define STB0899_MODECFG 0xf11d -#define STB0899_NCOARSE 0xf1b3 - -#define STB0899_SYNTCTRL 0xf1b6 -#define STB0899_STANDBY (0x01 << 7) -#define STB0899_OFFST_STANDBY 7 -#define STB0899_WIDTH_STANDBY 1 -#define STB0899_BYPASSPLL (0x01 << 6) -#define STB0899_OFFST_BYPASSPLL 6 -#define STB0899_WIDTH_BYPASSPLL 1 -#define STB0899_SEL1XRATIO (0x01 << 5) -#define STB0899_OFFST_SEL1XRATIO 5 -#define STB0899_WIDTH_SEL1XRATIO 1 -#define STB0899_SELOSCI (0x01 << 1) -#define STB0899_OFFST_SELOSCI 1 -#define STB0899_WIDTH_SELOSCI 1 - -#define STB0899_FILTCTRL 0xf1b7 -#define STB0899_SYSCTRL 0xf1b8 - -#define STB0899_STOPCLK1 0xf1c2 -#define STB0899_STOP_CKINTBUF108 (0x01 << 7) -#define STB0899_OFFST_STOP_CKINTBUF108 7 -#define STB0899_WIDTH_STOP_CKINTBUF108 1 -#define STB0899_STOP_CKINTBUF216 (0x01 << 6) -#define STB0899_OFFST_STOP_CKINTBUF216 6 -#define STB0899_WIDTH_STOP_CKINTBUF216 1 -#define STB0899_STOP_CHK8PSK (0x01 << 5) -#define STB0899_OFFST_STOP_CHK8PSK 5 -#define STB0899_WIDTH_STOP_CHK8PSK 1 -#define STB0899_STOP_CKFEC108 (0x01 << 4) -#define STB0899_OFFST_STOP_CKFEC108 4 -#define STB0899_WIDTH_STOP_CKFEC108 1 -#define STB0899_STOP_CKFEC216 (0x01 << 3) -#define STB0899_OFFST_STOP_CKFEC216 3 -#define STB0899_WIDTH_STOP_CKFEC216 1 -#define STB0899_STOP_CKCORE216 (0x01 << 2) -#define STB0899_OFFST_STOP_CKCORE216 2 -#define STB0899_WIDTH_STOP_CKCORE216 1 -#define STB0899_STOP_CKADCI108 (0x01 << 1) -#define STB0899_OFFST_STOP_CKADCI108 1 -#define STB0899_WIDTH_STOP_CKADCI108 1 -#define STB0899_STOP_INVCKADCI108 (0x01 << 0) -#define STB0899_OFFST_STOP_INVCKADCI108 0 -#define STB0899_WIDTH_STOP_INVCKADCI108 1 - -#define STB0899_STOPCLK2 0xf1c3 -#define STB0899_STOP_CKS2DMD108 (0x01 << 2) -#define STB0899_OFFST_STOP_CKS2DMD108 2 -#define STB0899_WIDTH_STOP_CKS2DMD108 1 -#define STB0899_STOP_CKPKDLIN108 (0x01 << 1) -#define STB0899_OFFST_STOP_CKPKDLIN108 1 -#define STB0899_WIDTH_STOP_CKPKDLIN108 1 -#define STB0899_STOP_CKPKDLIN216 (0x01 << 0) -#define STB0899_OFFST_STOP_CKPKDLIN216 0 -#define STB0899_WIDTH_STOP_CKPKDLIN216 1 - -#define STB0899_TSTTNR1 0xf1e0 -#define STB0899_BYPASS_ADC (0x01 << 7) -#define STB0899_OFFST_BYPASS_ADC 7 -#define STB0899_WIDTH_BYPASS_ADC 1 -#define STB0899_INVADCICKOUT (0x01 << 6) -#define STB0899_OFFST_INVADCICKOUT 6 -#define STB0899_WIDTH_INVADCICKOUT 1 -#define STB0899_ADCTEST_VOLTAGE (0x03 << 4) -#define STB0899_OFFST_ADCTEST_VOLTAGE 4 -#define STB0899_WIDTH_ADCTEST_VOLTAGE 1 -#define STB0899_ADC_RESET (0x01 << 3) -#define STB0899_OFFST_ADC_RESET 3 -#define STB0899_WIDTH_ADC_RESET 1 -#define STB0899_TSTTNR1_2 (0x01 << 2) -#define STB0899_OFFST_TSTTNR1_2 2 -#define STB0899_WIDTH_TSTTNR1_2 1 -#define STB0899_ADCPON (0x01 << 1) -#define STB0899_OFFST_ADCPON 1 -#define STB0899_WIDTH_ADCPON 1 -#define STB0899_ADCIN_MODE (0x01 << 0) -#define STB0899_OFFST_ADCIN_MODE 0 -#define STB0899_WIDTH_ADCIN_MODE 1 - -#define STB0899_TSTTNR2 0xf1e1 -#define STB0899_TSTTNR2_7 (0x01 << 7) -#define STB0899_OFFST_TSTTNR2_7 7 -#define STB0899_WIDTH_TSTTNR2_7 1 -#define STB0899_NOT_DISRX_WIRED (0x01 << 6) -#define STB0899_OFFST_NOT_DISRX_WIRED 6 -#define STB0899_WIDTH_NOT_DISRX_WIRED 1 -#define STB0899_DISEQC_DCURRENT (0x01 << 5) -#define STB0899_OFFST_DISEQC_DCURRENT 5 -#define STB0899_WIDTH_DISEQC_DCURRENT 1 -#define STB0899_DISEQC_ZCURRENT (0x01 << 4) -#define STB0899_OFFST_DISEQC_ZCURRENT 4 -#define STB0899_WIDTH_DISEQC_ZCURRENT 1 -#define STB0899_DISEQC_SINC_SOURCE (0x03 << 2) -#define STB0899_OFFST_DISEQC_SINC_SOURCE 2 -#define STB0899_WIDTH_DISEQC_SINC_SOURCE 2 -#define STB0899_SELIQSRC (0x03 << 0) -#define STB0899_OFFST_SELIQSRC 0 -#define STB0899_WIDTH_SELIQSRC 2 - -#define STB0899_TSTTNR3 0xf1e2 - -#define STB0899_I2CCFG 0xf129 -#define STB0899_I2CCFGRSVD (0x0f << 4) -#define STB0899_OFFST_I2CCFGRSVD 4 -#define STB0899_WIDTH_I2CCFGRSVD 4 -#define STB0899_I2CFASTMODE (0x01 << 3) -#define STB0899_OFFST_I2CFASTMODE 3 -#define STB0899_WIDTH_I2CFASTMODE 1 -#define STB0899_STATUSWR (0x01 << 2) -#define STB0899_OFFST_STATUSWR 2 -#define STB0899_WIDTH_STATUSWR 1 -#define STB0899_I2CADDRINC (0x03 << 0) -#define STB0899_OFFST_I2CADDRINC 0 -#define STB0899_WIDTH_I2CADDRINC 2 - -#define STB0899_I2CRPT 0xf12a -#define STB0899_I2CTON (0x01 << 7) -#define STB0899_OFFST_I2CTON 7 -#define STB0899_WIDTH_I2CTON 1 -#define STB0899_ENARPTLEVEL (0x01 << 6) -#define STB0899_OFFST_ENARPTLEVEL 6 -#define STB0899_WIDTH_ENARPTLEVEL 2 -#define STB0899_SCLTDELAY (0x01 << 3) -#define STB0899_OFFST_SCLTDELAY 3 -#define STB0899_WIDTH_SCLTDELAY 1 -#define STB0899_STOPENA (0x01 << 2) -#define STB0899_OFFST_STOPENA 2 -#define STB0899_WIDTH_STOPENA 1 -#define STB0899_STOPSDAT2SDA (0x01 << 1) -#define STB0899_OFFST_STOPSDAT2SDA 1 -#define STB0899_WIDTH_STOPSDAT2SDA 1 - -#define STB0899_IOPVALUE8 0xf136 -#define STB0899_IOPVALUE7 0xf137 -#define STB0899_IOPVALUE6 0xf138 -#define STB0899_IOPVALUE5 0xf139 -#define STB0899_IOPVALUE4 0xf13a -#define STB0899_IOPVALUE3 0xf13b -#define STB0899_IOPVALUE2 0xf13c -#define STB0899_IOPVALUE1 0xf13d -#define STB0899_IOPVALUE0 0xf13e - -#define STB0899_GPIO00CFG 0xf140 - -#define STB0899_GPIO01CFG 0xf141 -#define STB0899_GPIO02CFG 0xf142 -#define STB0899_GPIO03CFG 0xf143 -#define STB0899_GPIO04CFG 0xf144 -#define STB0899_GPIO05CFG 0xf145 -#define STB0899_GPIO06CFG 0xf146 -#define STB0899_GPIO07CFG 0xf147 -#define STB0899_GPIO08CFG 0xf148 -#define STB0899_GPIO09CFG 0xf149 -#define STB0899_GPIO10CFG 0xf14a -#define STB0899_GPIO11CFG 0xf14b -#define STB0899_GPIO12CFG 0xf14c -#define STB0899_GPIO13CFG 0xf14d -#define STB0899_GPIO14CFG 0xf14e -#define STB0899_GPIO15CFG 0xf14f -#define STB0899_GPIO16CFG 0xf150 -#define STB0899_GPIO17CFG 0xf151 -#define STB0899_GPIO18CFG 0xf152 -#define STB0899_GPIO19CFG 0xf153 -#define STB0899_GPIO20CFG 0xf154 - -#define STB0899_SDATCFG 0xf155 -#define STB0899_SCLTCFG 0xf156 -#define STB0899_AGCRFCFG 0xf157 -#define STB0899_GPIO22 0xf158 /* AGCBB2CFG */ -#define STB0899_GPIO21 0xf159 /* AGCBB1CFG */ -#define STB0899_DIRCLKCFG 0xf15a -#define STB0899_CLKOUT27CFG 0xf15b -#define STB0899_STDBYCFG 0xf15c -#define STB0899_CS0CFG 0xf15d -#define STB0899_CS1CFG 0xf15e -#define STB0899_DISEQCOCFG 0xf15f - -#define STB0899_GPIO32CFG 0xf160 -#define STB0899_GPIO33CFG 0xf161 -#define STB0899_GPIO34CFG 0xf162 -#define STB0899_GPIO35CFG 0xf163 -#define STB0899_GPIO36CFG 0xf164 -#define STB0899_GPIO37CFG 0xf165 -#define STB0899_GPIO38CFG 0xf166 -#define STB0899_GPIO39CFG 0xf167 - -#define STB0899_IRQSTATUS_3 0xf120 -#define STB0899_IRQSTATUS_2 0xf121 -#define STB0899_IRQSTATUS_1 0xf122 -#define STB0899_IRQSTATUS_0 0xf123 - -#define STB0899_IRQMSK_3 0xf124 -#define STB0899_IRQMSK_2 0xf125 -#define STB0899_IRQMSK_1 0xf126 -#define STB0899_IRQMSK_0 0xf127 - -#define STB0899_IRQCFG 0xf128 - -#define STB0899_GHOSTREG 0xf000 - -#define STB0899_S2DEMOD 0xf3fc -#define STB0899_S2FEC 0xfafc - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6000.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6000.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,256 +0,0 @@ - /* - Driver for ST STB6000 DVBS Silicon tuner - - Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#include -#include -#include -#include - -#include "stb6000.h" - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "stb6000: " args); \ - } while (0) - -struct stb6000_priv { - /* i2c details */ - int i2c_address; - struct i2c_adapter *i2c; - u32 frequency; -}; - -static int stb6000_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int stb6000_sleep(struct dvb_frontend *fe) -{ - struct stb6000_priv *priv = fe->tuner_priv; - int ret; - u8 buf[] = { 10, 0 }; - struct i2c_msg msg = { - .addr = priv->i2c_address, - .flags = 0, - .buf = buf, - .len = 2 - }; - - dprintk("%s:\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = i2c_transfer(priv->i2c, &msg, 1); - if (ret != 1) - dprintk("%s: i2c error\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return (ret == 1) ? 0 : ret; -} - -static int stb6000_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct stb6000_priv *priv = fe->tuner_priv; - unsigned int n, m; - int ret; - u32 freq_mhz; - int bandwidth; - u8 buf[12]; - struct i2c_msg msg = { - .addr = priv->i2c_address, - .flags = 0, - .buf = buf, - .len = 12 - }; - - dprintk("%s:\n", __func__); - - freq_mhz = params->frequency / 1000; - bandwidth = params->u.qpsk.symbol_rate / 1000000; - - if (bandwidth > 31) - bandwidth = 31; - - if ((freq_mhz > 949) && (freq_mhz < 2151)) { - buf[0] = 0x01; - buf[1] = 0xac; - if (freq_mhz < 1950) - buf[1] = 0xaa; - if (freq_mhz < 1800) - buf[1] = 0xa8; - if (freq_mhz < 1650) - buf[1] = 0xa6; - if (freq_mhz < 1530) - buf[1] = 0xa5; - if (freq_mhz < 1470) - buf[1] = 0xa4; - if (freq_mhz < 1370) - buf[1] = 0xa2; - if (freq_mhz < 1300) - buf[1] = 0xa1; - if (freq_mhz < 1200) - buf[1] = 0xa0; - if (freq_mhz < 1075) - buf[1] = 0xbc; - if (freq_mhz < 1000) - buf[1] = 0xba; - if (freq_mhz < 1075) { - n = freq_mhz / 8; /* vco=lo*4 */ - m = 2; - } else { - n = freq_mhz / 16; /* vco=lo*2 */ - m = 1; - } - buf[2] = n >> 1; - buf[3] = (unsigned char)(((n & 1) << 7) | - (m * freq_mhz - n * 16) | 0x60); - buf[4] = 0x04; - buf[5] = 0x0e; - - buf[6] = (unsigned char)(bandwidth); - - buf[7] = 0xd8; - buf[8] = 0xd0; - buf[9] = 0x50; - buf[10] = 0xeb; - buf[11] = 0x4f; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = i2c_transfer(priv->i2c, &msg, 1); - if (ret != 1) - dprintk("%s: i2c error\n", __func__); - - udelay(10); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - buf[0] = 0x07; - buf[1] = 0xdf; - buf[2] = 0xd0; - buf[3] = 0x50; - buf[4] = 0xfb; - msg.len = 5; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = i2c_transfer(priv->i2c, &msg, 1); - if (ret != 1) - dprintk("%s: i2c error\n", __func__); - - udelay(10); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - priv->frequency = freq_mhz * 1000; - - return (ret == 1) ? 0 : ret; - } - return -1; -} - -static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct stb6000_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static struct dvb_tuner_ops stb6000_tuner_ops = { - .info = { - .name = "ST STB6000", - .frequency_min = 950000, - .frequency_max = 2150000 - }, - .release = stb6000_release, - .sleep = stb6000_sleep, - .set_params = stb6000_set_params, - .get_frequency = stb6000_get_frequency, -}; - -struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, - struct i2c_adapter *i2c) -{ - struct stb6000_priv *priv = NULL; - u8 b0[] = { 0 }; - u8 b1[] = { 0, 0 }; - struct i2c_msg msg[2] = { - { - .addr = addr, - .flags = 0, - .buf = b0, - .len = 0 - }, { - .addr = addr, - .flags = I2C_M_RD, - .buf = b1, - .len = 2 - } - }; - int ret; - - dprintk("%s:\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - /* is some i2c device here ? */ - ret = i2c_transfer(i2c, msg, 2); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (ret != 2) - return NULL; - - priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c_address = addr; - priv->i2c = i2c; - - memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - - return fe; -} -EXPORT_SYMBOL(stb6000_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("DVB STB6000 driver"); -MODULE_AUTHOR("Igor M. Liplianin "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6000.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6000.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ - /* - Driver for ST stb6000 DVBS Silicon tuner - - Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef __DVB_STB6000_H__ -#define __DVB_STB6000_H__ - -#include -#include "dvb_frontend.h" - -/** - * Attach a stb6000 tuner to the supplied frontend structure. - * - * @param fe Frontend to attach to. - * @param addr i2c address of the tuner. - * @param i2c i2c adapter to use. - * @return FE pointer on success, NULL on failure. - */ -#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \ - && defined(MODULE)) -extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, - int addr, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_STB6000 */ - -#endif /* __DVB_STB6000_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,612 +0,0 @@ -/* - STB6100 Silicon Tuner - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "stb6100.h" - -static unsigned int verbose; -module_param(verbose, int, 0644); - - -#define FE_ERROR 0 -#define FE_NOTICE 1 -#define FE_INFO 2 -#define FE_DEBUG 3 - -#define dprintk(x, y, z, format, arg...) do { \ - if (z) { \ - if ((x > FE_ERROR) && (x > y)) \ - printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ - else if ((x > FE_NOTICE) && (x > y)) \ - printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ - else if ((x > FE_INFO) && (x > y)) \ - printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ - else if ((x > FE_DEBUG) && (x > y)) \ - printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ - } else { \ - if (x > y) \ - printk(format, ##arg); \ - } \ -} while (0) - -struct stb6100_lkup { - u32 val_low; - u32 val_high; - u8 reg; -}; - -static int stb6100_release(struct dvb_frontend *fe); - -static const struct stb6100_lkup lkup[] = { - { 0, 950000, 0x0a }, - { 950000, 1000000, 0x0a }, - { 1000000, 1075000, 0x0c }, - { 1075000, 1200000, 0x00 }, - { 1200000, 1300000, 0x01 }, - { 1300000, 1370000, 0x02 }, - { 1370000, 1470000, 0x04 }, - { 1470000, 1530000, 0x05 }, - { 1530000, 1650000, 0x06 }, - { 1650000, 1800000, 0x08 }, - { 1800000, 1950000, 0x0a }, - { 1950000, 2150000, 0x0c }, - { 2150000, 9999999, 0x0c }, - { 0, 0, 0x00 } -}; - -/* Register names for easy debugging. */ -static const char *stb6100_regnames[] = { - [STB6100_LD] = "LD", - [STB6100_VCO] = "VCO", - [STB6100_NI] = "NI", - [STB6100_NF_LSB] = "NF", - [STB6100_K] = "K", - [STB6100_G] = "G", - [STB6100_F] = "F", - [STB6100_DLB] = "DLB", - [STB6100_TEST1] = "TEST1", - [STB6100_FCCK] = "FCCK", - [STB6100_LPEN] = "LPEN", - [STB6100_TEST3] = "TEST3", -}; - -/* Template for normalisation, i.e. setting unused or undocumented - * bits as required according to the documentation. - */ -struct stb6100_regmask { - u8 mask; - u8 set; -}; - -static const struct stb6100_regmask stb6100_template[] = { - [STB6100_LD] = { 0xff, 0x00 }, - [STB6100_VCO] = { 0xff, 0x00 }, - [STB6100_NI] = { 0xff, 0x00 }, - [STB6100_NF_LSB] = { 0xff, 0x00 }, - [STB6100_K] = { 0xc7, 0x38 }, - [STB6100_G] = { 0xef, 0x10 }, - [STB6100_F] = { 0x1f, 0xc0 }, - [STB6100_DLB] = { 0x38, 0xc4 }, - [STB6100_TEST1] = { 0x00, 0x8f }, - [STB6100_FCCK] = { 0x40, 0x0d }, - [STB6100_LPEN] = { 0xf0, 0x0b }, - [STB6100_TEST3] = { 0x00, 0xde }, -}; - -/* - * Currently unused. Some boards might need it in the future - */ -static inline void stb6100_normalise_regs(u8 regs[]) -{ - int i; - - for (i = 0; i < STB6100_NUMREGS; i++) - regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set; -} - -static int stb6100_read_regs(struct stb6100_state *state, u8 regs[]) -{ - int rc; - struct i2c_msg msg = { - .addr = state->config->tuner_address, - .flags = I2C_M_RD, - .buf = regs, - .len = STB6100_NUMREGS - }; - - rc = i2c_transfer(state->i2c, &msg, 1); - if (unlikely(rc != 1)) { - dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]", - state->config->tuner_address, rc); - - return -EREMOTEIO; - } - if (unlikely(verbose > FE_DEBUG)) { - int i; - - dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address); - for (i = 0; i < STB6100_NUMREGS; i++) - dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[i], regs[i]); - } - return 0; -} - -static int stb6100_read_reg(struct stb6100_state *state, u8 reg) -{ - u8 regs[STB6100_NUMREGS]; - int rc; - - struct i2c_msg msg = { - .addr = state->config->tuner_address + reg, - .flags = I2C_M_RD, - .buf = regs, - .len = 1 - }; - - rc = i2c_transfer(state->i2c, &msg, 1); - - if (unlikely(reg >= STB6100_NUMREGS)) { - dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); - return -EINVAL; - } - if (unlikely(verbose > FE_DEBUG)) { - dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address); - dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[reg], regs[0]); - } - - return (unsigned int)regs[0]; -} - -static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len) -{ - int rc; - u8 cmdbuf[len + 1]; - struct i2c_msg msg = { - .addr = state->config->tuner_address, - .flags = 0, - .buf = cmdbuf, - .len = len + 1 - }; - - if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) { - dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d", - start, len); - return -EINVAL; - } - memcpy(&cmdbuf[1], buf, len); - cmdbuf[0] = start; - - if (unlikely(verbose > FE_DEBUG)) { - int i; - - dprintk(verbose, FE_DEBUG, 1, " Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len); - for (i = 0; i < len; i++) - dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[start + i], buf[i]); - } - rc = i2c_transfer(state->i2c, &msg, 1); - if (unlikely(rc != 1)) { - dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]", - (unsigned int)state->config->tuner_address, start, len, rc); - return -EREMOTEIO; - } - return 0; -} - -static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data) -{ - if (unlikely(reg >= STB6100_NUMREGS)) { - dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); - return -EREMOTEIO; - } - data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set; - return stb6100_write_reg_range(state, &data, reg, 1); -} - - -static int stb6100_get_status(struct dvb_frontend *fe, u32 *status) -{ - int rc; - struct stb6100_state *state = fe->tuner_priv; - - rc = stb6100_read_reg(state, STB6100_LD); - if (rc < 0) { - dprintk(verbose, FE_ERROR, 1, "%s failed", __func__); - return rc; - } - return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0; -} - -static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - int rc; - u8 f; - struct stb6100_state *state = fe->tuner_priv; - - rc = stb6100_read_reg(state, STB6100_F); - if (rc < 0) - return rc; - f = rc & STB6100_F_F; - - state->status.bandwidth = (f + 5) * 2000; /* x2 for ZIF */ - - *bandwidth = state->bandwidth = state->status.bandwidth * 1000; - dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth); - return 0; -} - -static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) -{ - u32 tmp; - int rc; - struct stb6100_state *state = fe->tuner_priv; - - dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth); - - bandwidth /= 2; /* ZIF */ - - if (bandwidth >= 36000000) /* F[4:0] BW/2 max =31+5=36 mhz for F=31 */ - tmp = 31; - else if (bandwidth <= 5000000) /* bw/2 min = 5Mhz for F=0 */ - tmp = 0; - else /* if 5 < bw/2 < 36 */ - tmp = (bandwidth + 500000) / 1000000 - 5; - - /* Turn on LPF bandwidth setting clock control, - * set bandwidth, wait 10ms, turn off. - */ - rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK); - if (rc < 0) - return rc; - rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp); - if (rc < 0) - return rc; - - msleep(5); /* This is dangerous as another (related) thread may start */ - - rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d); - if (rc < 0) - return rc; - - msleep(10); /* This is dangerous as another (related) thread may start */ - - return 0; -} - -static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - int rc; - u32 nint, nfrac, fvco; - int psd2, odiv; - struct stb6100_state *state = fe->tuner_priv; - u8 regs[STB6100_NUMREGS]; - - rc = stb6100_read_regs(state, regs); - if (rc < 0) - return rc; - - odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT; - psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT; - nint = regs[STB6100_NI]; - nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB]; - fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2); - *frequency = state->frequency = fvco >> (odiv + 1); - - dprintk(verbose, FE_DEBUG, 1, - "frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u", - state->frequency, odiv, psd2, state->reference, fvco, nint, nfrac); - return 0; -} - - -static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) -{ - int rc; - const struct stb6100_lkup *ptr; - struct stb6100_state *state = fe->tuner_priv; - struct dvb_frontend_parameters p; - - u32 srate = 0, fvco, nint, nfrac; - u8 regs[STB6100_NUMREGS]; - u8 g, psd2, odiv; - - dprintk(verbose, FE_DEBUG, 1, "Version 2010-8-14 13:51"); - - if (fe->ops.get_frontend) { - dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters"); - fe->ops.get_frontend(fe, &p); - } - srate = p.u.qpsk.symbol_rate; - - /* Set up tuner cleanly, LPF calibration on */ - rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK); - if (rc < 0) - return rc; /* allow LPF calibration */ - - /* PLL Loop disabled, bias on, VCO on, synth on */ - regs[STB6100_LPEN] = 0xeb; - rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]); - if (rc < 0) - return rc; - - /* Program the registers with their data values */ - - /* VCO divide ratio (LO divide ratio, VCO prescaler enable). */ - if (frequency <= 1075000) - odiv = 1; - else - odiv = 0; - - /* VCO enabled, seach clock off as per LL3.7, 3.4.1 */ - regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT); - - /* OSM */ - for (ptr = lkup; - (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high); - ptr++); - - if (ptr->val_high == 0) { - printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency); - return -EINVAL; - } - regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg; - rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); - if (rc < 0) - return rc; - - if ((frequency > 1075000) && (frequency <= 1325000)) - psd2 = 0; - else - psd2 = 1; - /* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */ - fvco = frequency << (1 + odiv); - /* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */ - nint = fvco / (state->reference << psd2); - /* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */ - nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2)) - << (9 - psd2), state->reference); - - /* NI */ - regs[STB6100_NI] = nint; - rc = stb6100_write_reg(state, STB6100_NI, regs[STB6100_NI]); - if (rc < 0) - return rc; - - /* NF */ - regs[STB6100_NF_LSB] = nfrac; - rc = stb6100_write_reg(state, STB6100_NF_LSB, regs[STB6100_NF_LSB]); - if (rc < 0) - return rc; - - /* K */ - regs[STB6100_K] = (0x38 & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT); - regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB); - rc = stb6100_write_reg(state, STB6100_K, regs[STB6100_K]); - if (rc < 0) - return rc; - - /* G Baseband gain. */ - if (srate >= 15000000) - g = 9; /* +4 dB */ - else if (srate >= 5000000) - g = 11; /* +8 dB */ - else - g = 14; /* +14 dB */ - - regs[STB6100_G] = (0x10 & ~STB6100_G_G) | g; - regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */ - regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */ - rc = stb6100_write_reg(state, STB6100_G, regs[STB6100_G]); - if (rc < 0) - return rc; - - /* F we don't write as it is set up in BW set */ - - /* DLB set DC servo loop BW to 160Hz (LLA 3.8 / 2.1) */ - regs[STB6100_DLB] = 0xcc; - rc = stb6100_write_reg(state, STB6100_DLB, regs[STB6100_DLB]); - if (rc < 0) - return rc; - - dprintk(verbose, FE_DEBUG, 1, - "frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u", - frequency, srate, (unsigned int)g, (unsigned int)odiv, - (unsigned int)psd2, state->reference, - ptr->reg, fvco, nint, nfrac); - - /* Set up the test registers */ - regs[STB6100_TEST1] = 0x8f; - rc = stb6100_write_reg(state, STB6100_TEST1, regs[STB6100_TEST1]); - if (rc < 0) - return rc; - regs[STB6100_TEST3] = 0xde; - rc = stb6100_write_reg(state, STB6100_TEST3, regs[STB6100_TEST3]); - if (rc < 0) - return rc; - - /* Bring up tuner according to LLA 3.7 3.4.1, step 2 */ - regs[STB6100_LPEN] = 0xfb; /* PLL Loop enabled, bias on, VCO on, synth on */ - rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]); - if (rc < 0) - return rc; - - msleep(2); - - /* Bring up tuner according to LLA 3.7 3.4.1, step 3 */ - regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */ - rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); - if (rc < 0) - return rc; - - msleep(10); /* This is dangerous as another (related) thread may start */ /* wait for LO to lock */ - - regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */ - regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */ - rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); - if (rc < 0) - return rc; - - rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d); - if (rc < 0) - return rc; /* Stop LPF calibration */ - - msleep(10); /* This is dangerous as another (related) thread may start */ - /* wait for stabilisation, (should not be necessary) */ - return 0; -} - -static int stb6100_sleep(struct dvb_frontend *fe) -{ - /* TODO: power down */ - return 0; -} - -static int stb6100_init(struct dvb_frontend *fe) -{ - struct stb6100_state *state = fe->tuner_priv; - struct tuner_state *status = &state->status; - - status->tunerstep = 125000; - status->ifreq = 0; - status->refclock = 27000000; /* Hz */ - status->iqsense = 1; - status->bandwidth = 36000; /* kHz */ - state->bandwidth = status->bandwidth * 1000; /* Hz */ - state->reference = status->refclock / 1000; /* kHz */ - - /* Set default bandwidth. Modified, PN 13-May-10 */ - return 0; -} - -static int stb6100_get_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *state) -{ - switch (param) { - case DVBFE_TUNER_FREQUENCY: - stb6100_get_frequency(fe, &state->frequency); - break; - case DVBFE_TUNER_TUNERSTEP: - break; - case DVBFE_TUNER_IFFREQ: - break; - case DVBFE_TUNER_BANDWIDTH: - stb6100_get_bandwidth(fe, &state->bandwidth); - break; - case DVBFE_TUNER_REFCLOCK: - break; - default: - break; - } - - return 0; -} - -static int stb6100_set_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *state) -{ - struct stb6100_state *tstate = fe->tuner_priv; - - switch (param) { - case DVBFE_TUNER_FREQUENCY: - stb6100_set_frequency(fe, state->frequency); - tstate->frequency = state->frequency; - break; - case DVBFE_TUNER_TUNERSTEP: - break; - case DVBFE_TUNER_IFFREQ: - break; - case DVBFE_TUNER_BANDWIDTH: - stb6100_set_bandwidth(fe, state->bandwidth); - tstate->bandwidth = state->bandwidth; - break; - case DVBFE_TUNER_REFCLOCK: - break; - default: - break; - } - - return 0; -} - -static struct dvb_tuner_ops stb6100_ops = { - .info = { - .name = "STB6100 Silicon Tuner", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_step = 0, - }, - - .init = stb6100_init, - .sleep = stb6100_sleep, - .get_status = stb6100_get_status, - .get_state = stb6100_get_state, - .set_state = stb6100_set_state, - .release = stb6100_release -}; - -struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, - const struct stb6100_config *config, - struct i2c_adapter *i2c) -{ - struct stb6100_state *state = NULL; - - state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL); - if (state == NULL) - goto error; - - state->config = config; - state->i2c = i2c; - state->frontend = fe; - state->reference = config->refclock / 1000; /* kHz */ - fe->tuner_priv = state; - fe->ops.tuner_ops = stb6100_ops; - - printk("%s: Attaching STB6100 \n", __func__); - return fe; - -error: - kfree(state); - return NULL; -} - -static int stb6100_release(struct dvb_frontend *fe) -{ - struct stb6100_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - - return 0; -} - -EXPORT_SYMBOL(stb6100_attach); -MODULE_PARM_DESC(verbose, "Set Verbosity level"); - -MODULE_AUTHOR("Manu Abraham"); -MODULE_DESCRIPTION("STB6100 Silicon tuner"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100_cfg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100_cfg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100_cfg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100_cfg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -/* - STB6100 Silicon Tuner - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - struct tuner_state t_state; - int err = 0; - - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->get_state) { - if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { - printk("%s: Invalid parameter\n", __func__); - return err; - } - *frequency = t_state.frequency; - } - return 0; -} - -static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - struct tuner_state t_state; - int err = 0; - - t_state.frequency = frequency; - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->set_state) { - if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { - printk("%s: Invalid parameter\n", __func__); - return err; - } - } - return 0; -} - -static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct dvb_frontend_ops *frontend_ops = &fe->ops; - struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state t_state; - int err = 0; - - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->get_state) { - if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { - printk("%s: Invalid parameter\n", __func__); - return err; - } - *bandwidth = t_state.bandwidth; - } - return 0; -} - -static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - struct tuner_state t_state; - int err = 0; - - t_state.bandwidth = bandwidth; - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->set_state) { - if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { - printk("%s: Invalid parameter\n", __func__); - return err; - } - } - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/* - STB6100 Silicon Tuner - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STB_6100_REG_H -#define __STB_6100_REG_H - -#include -#include "dvb_frontend.h" - -#define STB6100_LD 0x00 -#define STB6100_LD_LOCK (1 << 0) - -#define STB6100_VCO 0x01 -#define STB6100_VCO_OSCH (0x01 << 7) -#define STB6100_VCO_OSCH_SHIFT 7 -#define STB6100_VCO_OCK (0x03 << 5) -#define STB6100_VCO_OCK_SHIFT 5 -#define STB6100_VCO_ODIV (0x01 << 4) -#define STB6100_VCO_ODIV_SHIFT 4 -#define STB6100_VCO_OSM (0x0f << 0) - -#define STB6100_NI 0x02 -#define STB6100_NF_LSB 0x03 - -#define STB6100_K 0x04 -#define STB6100_K_PSD2 (0x01 << 2) -#define STB6100_K_PSD2_SHIFT 2 -#define STB6100_K_NF_MSB (0x03 << 0) - -#define STB6100_G 0x05 -#define STB6100_G_G (0x0f << 0) -#define STB6100_G_GCT (0x07 << 5) - -#define STB6100_F 0x06 -#define STB6100_F_F (0x1f << 0) - -#define STB6100_DLB 0x07 - -#define STB6100_TEST1 0x08 - -#define STB6100_FCCK 0x09 -#define STB6100_FCCK_FCCK (0x01 << 6) - -#define STB6100_LPEN 0x0a -#define STB6100_LPEN_LPEN (0x01 << 4) -#define STB6100_LPEN_SYNP (0x01 << 5) -#define STB6100_LPEN_OSCP (0x01 << 6) -#define STB6100_LPEN_BEN (0x01 << 7) - -#define STB6100_TEST3 0x0b - -#define STB6100_NUMREGS 0x0c - - -#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \ - ((y <= val) && (val <= x)) ? 1 : 0) - -#define CHKRANGE(val, x, y) (((val >= x) && (val < y)) ? 1 : 0) - -struct stb6100_config { - u8 tuner_address; - u32 refclock; -}; - -struct stb6100_state { - struct i2c_adapter *i2c; - - const struct stb6100_config *config; - struct dvb_tuner_ops ops; - struct dvb_frontend *frontend; - struct tuner_state status; - - u32 frequency; - u32 srate; - u32 bandwidth; - u32 reference; -}; - -#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE)) - -extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, - const struct stb6100_config *config, - struct i2c_adapter *i2c); - -#else - -static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, - const struct stb6100_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); - return NULL; -} - -#endif //CONFIG_DVB_STB6100 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100_proc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100_proc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100_proc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stb6100_proc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,138 +0,0 @@ -/* - STB6100 Silicon Tuner wrapper - Copyright (C)2009 Igor M. Liplianin (liplianin@me.by) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - struct tuner_state state; - int err = 0; - - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->get_state) { - if (frontend_ops->i2c_gate_ctrl) - frontend_ops->i2c_gate_ctrl(fe, 1); - - err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &state); - if (err < 0) { - printk(KERN_ERR "%s: Invalid parameter\n", __func__); - return err; - } - - if (frontend_ops->i2c_gate_ctrl) - frontend_ops->i2c_gate_ctrl(fe, 0); - - *frequency = state.frequency; - } - - return 0; -} - -static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - struct tuner_state state; - int err = 0; - - state.frequency = frequency; - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->set_state) { - if (frontend_ops->i2c_gate_ctrl) - frontend_ops->i2c_gate_ctrl(fe, 1); - - err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &state); - if (err < 0) { - printk(KERN_ERR "%s: Invalid parameter\n", __func__); - return err; - } - - if (frontend_ops->i2c_gate_ctrl) - frontend_ops->i2c_gate_ctrl(fe, 0); - - } - - return 0; -} - -static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - struct tuner_state state; - int err = 0; - - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->get_state) { - if (frontend_ops->i2c_gate_ctrl) - frontend_ops->i2c_gate_ctrl(fe, 1); - - err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &state); - if (err < 0) { - printk(KERN_ERR "%s: Invalid parameter\n", __func__); - return err; - } - - if (frontend_ops->i2c_gate_ctrl) - frontend_ops->i2c_gate_ctrl(fe, 0); - - *bandwidth = state.bandwidth; - } - - return 0; -} - -static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - struct tuner_state state; - int err = 0; - - state.bandwidth = bandwidth; - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->set_state) { - if (frontend_ops->i2c_gate_ctrl) - frontend_ops->i2c_gate_ctrl(fe, 1); - - err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &state); - if (err < 0) { - printk(KERN_ERR "%s: Invalid parameter\n", __func__); - return err; - } - - if (frontend_ops->i2c_gate_ctrl) - frontend_ops->i2c_gate_ctrl(fe, 0); - - } - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0288.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0288.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0288.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0288.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,624 +0,0 @@ -/* - Driver for ST STV0288 demodulator - Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de - for Reel Multimedia - Copyright (C) 2008 TurboSight.com, Bob Liu - Copyright (C) 2008 Igor M. Liplianin - Removed stb6000 specific tuner code and revised some - procedures. - 2010-09-01 Josef Pavlik - Fixed diseqc_msg, diseqc_burst and set_tone problems - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "stv0288.h" - -struct stv0288_state { - struct i2c_adapter *i2c; - const struct stv0288_config *config; - struct dvb_frontend frontend; - - u8 initialised:1; - u32 tuner_frequency; - u32 symbol_rate; - fe_code_rate_t fec_inner; - int errmode; -}; - -#define STATUS_BER 0 -#define STATUS_UCBLOCKS 1 - -static int debug; -static int debug_legacy_dish_switch; -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "stv0288: " args); \ - } while (0) - - -static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data) -{ - int ret; - u8 buf[] = { reg, data }; - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf, - .len = 2 - }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " - "ret == %i)\n", __func__, reg, data, ret); - - return (ret != 1) ? -EREMOTEIO : 0; -} - -static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len) -{ - struct stv0288_state *state = fe->demodulator_priv; - - if (len != 2) - return -EINVAL; - - return stv0288_writeregI(state, buf[0], buf[1]); -} - -static u8 stv0288_readreg(struct stv0288_state *state, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { - .addr = state->config->demod_address, - .flags = 0, - .buf = b0, - .len = 1 - }, { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = b1, - .len = 1 - } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", - __func__, reg, ret); - - return b1[0]; -} - -static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate) -{ - struct stv0288_state *state = fe->demodulator_priv; - unsigned int temp; - unsigned char b[3]; - - if ((srate < 1000000) || (srate > 45000000)) - return -EINVAL; - - temp = (unsigned int)srate / 1000; - - temp = temp * 32768; - temp = temp / 25; - temp = temp / 125; - b[0] = (unsigned char)((temp >> 12) & 0xff); - b[1] = (unsigned char)((temp >> 4) & 0xff); - b[2] = (unsigned char)((temp << 4) & 0xf0); - stv0288_writeregI(state, 0x28, 0x80); /* SFRH */ - stv0288_writeregI(state, 0x29, 0); /* SFRM */ - stv0288_writeregI(state, 0x2a, 0); /* SFRL */ - - stv0288_writeregI(state, 0x28, b[0]); - stv0288_writeregI(state, 0x29, b[1]); - stv0288_writeregI(state, 0x2a, b[2]); - dprintk("stv0288: stv0288_set_symbolrate\n"); - - return 0; -} - -static int stv0288_send_diseqc_msg(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *m) -{ - struct stv0288_state *state = fe->demodulator_priv; - - int i; - - dprintk("%s\n", __func__); - - stv0288_writeregI(state, 0x09, 0); - msleep(30); - stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */ - - for (i = 0; i < m->msg_len; i++) { - if (stv0288_writeregI(state, 0x06, m->msg[i])) - return -EREMOTEIO; - } - msleep(m->msg_len*12); - return 0; -} - -static int stv0288_send_diseqc_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t burst) -{ - struct stv0288_state *state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */ - return -EREMOTEIO; - - if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff)) - return -EREMOTEIO; - - msleep(15); - if (stv0288_writeregI(state, 0x05, 0x12)) - return -EREMOTEIO; - - return 0; -} - -static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct stv0288_state *state = fe->demodulator_priv; - - switch (tone) { - case SEC_TONE_ON: - if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */ - return -EREMOTEIO; - break; - - case SEC_TONE_OFF: - if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/ - return -EREMOTEIO; - break; - - default: - return -EINVAL; - } - return 0; -} - -static u8 stv0288_inittab[] = { - 0x01, 0x15, - 0x02, 0x20, - 0x09, 0x0, - 0x0a, 0x4, - 0x0b, 0x0, - 0x0c, 0x0, - 0x0d, 0x0, - 0x0e, 0xd4, - 0x0f, 0x30, - 0x11, 0x80, - 0x12, 0x03, - 0x13, 0x48, - 0x14, 0x84, - 0x15, 0x45, - 0x16, 0xb7, - 0x17, 0x9c, - 0x18, 0x0, - 0x19, 0xa6, - 0x1a, 0x88, - 0x1b, 0x8f, - 0x1c, 0xf0, - 0x20, 0x0b, - 0x21, 0x54, - 0x22, 0x0, - 0x23, 0x0, - 0x2b, 0xff, - 0x2c, 0xf7, - 0x30, 0x0, - 0x31, 0x1e, - 0x32, 0x14, - 0x33, 0x0f, - 0x34, 0x09, - 0x35, 0x0c, - 0x36, 0x05, - 0x37, 0x2f, - 0x38, 0x16, - 0x39, 0xbe, - 0x3a, 0x0, - 0x3b, 0x13, - 0x3c, 0x11, - 0x3d, 0x30, - 0x40, 0x63, - 0x41, 0x04, - 0x42, 0x60, - 0x43, 0x00, - 0x44, 0x00, - 0x45, 0x00, - 0x46, 0x00, - 0x47, 0x00, - 0x4a, 0x00, - 0x50, 0x10, - 0x51, 0x38, - 0x52, 0x21, - 0x58, 0x54, - 0x59, 0x86, - 0x5a, 0x0, - 0x5b, 0x9b, - 0x5c, 0x08, - 0x5d, 0x7f, - 0x5e, 0x0, - 0x5f, 0xff, - 0x70, 0x0, - 0x71, 0x0, - 0x72, 0x0, - 0x74, 0x0, - 0x75, 0x0, - 0x76, 0x0, - 0x81, 0x0, - 0x82, 0x3f, - 0x83, 0x3f, - 0x84, 0x0, - 0x85, 0x0, - 0x88, 0x0, - 0x89, 0x0, - 0x8a, 0x0, - 0x8b, 0x0, - 0x8c, 0x0, - 0x90, 0x0, - 0x91, 0x0, - 0x92, 0x0, - 0x93, 0x0, - 0x94, 0x1c, - 0x97, 0x0, - 0xa0, 0x48, - 0xa1, 0x0, - 0xb0, 0xb8, - 0xb1, 0x3a, - 0xb2, 0x10, - 0xb3, 0x82, - 0xb4, 0x80, - 0xb5, 0x82, - 0xb6, 0x82, - 0xb7, 0x82, - 0xb8, 0x20, - 0xb9, 0x0, - 0xf0, 0x0, - 0xf1, 0x0, - 0xf2, 0xc0, - 0x51, 0x36, - 0x52, 0x09, - 0x53, 0x94, - 0x54, 0x62, - 0x55, 0x29, - 0x56, 0x64, - 0x57, 0x2b, - 0xff, 0xff, -}; - -static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) -{ - dprintk("%s: %s\n", __func__, - volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : - volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); - - return 0; -} - -static int stv0288_init(struct dvb_frontend *fe) -{ - struct stv0288_state *state = fe->demodulator_priv; - int i; - u8 reg; - u8 val; - - dprintk("stv0288: init chip\n"); - stv0288_writeregI(state, 0x41, 0x04); - msleep(50); - - /* we have default inittab */ - if (state->config->inittab == NULL) { - for (i = 0; !(stv0288_inittab[i] == 0xff && - stv0288_inittab[i + 1] == 0xff); i += 2) - stv0288_writeregI(state, stv0288_inittab[i], - stv0288_inittab[i + 1]); - } else { - for (i = 0; ; i += 2) { - reg = state->config->inittab[i]; - val = state->config->inittab[i+1]; - if (reg == 0xff && val == 0xff) - break; - stv0288_writeregI(state, reg, val); - } - } - return 0; -} - -static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct stv0288_state *state = fe->demodulator_priv; - - u8 sync = stv0288_readreg(state, 0x24); - if (sync == 255) - sync = 0; - - dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); - - *status = 0; - if (sync & 0x80) - *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; - if (sync & 0x10) - *status |= FE_HAS_VITERBI; - if (sync & 0x08) { - *status |= FE_HAS_LOCK; - dprintk("stv0288 has locked\n"); - } - - return 0; -} - -static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct stv0288_state *state = fe->demodulator_priv; - - if (state->errmode != STATUS_BER) - return 0; - *ber = (stv0288_readreg(state, 0x26) << 8) | - stv0288_readreg(state, 0x27); - dprintk("stv0288_read_ber %d\n", *ber); - - return 0; -} - - -static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct stv0288_state *state = fe->demodulator_priv; - - s32 signal = 0xffff - ((stv0288_readreg(state, 0x10) << 8)); - - - signal = signal * 5 / 4; - *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; - dprintk("stv0288_read_signal_strength %d\n", *strength); - - return 0; -} -static int stv0288_sleep(struct dvb_frontend *fe) -{ - struct stv0288_state *state = fe->demodulator_priv; - - stv0288_writeregI(state, 0x41, 0x84); - state->initialised = 0; - - return 0; -} -static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct stv0288_state *state = fe->demodulator_priv; - - s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8) - | stv0288_readreg(state, 0x2e)); - xsnr = 3 * (xsnr - 0xa100); - *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; - dprintk("stv0288_read_snr %d\n", *snr); - - return 0; -} - -static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct stv0288_state *state = fe->demodulator_priv; - - if (state->errmode != STATUS_BER) - return 0; - *ucblocks = (stv0288_readreg(state, 0x26) << 8) | - stv0288_readreg(state, 0x27); - dprintk("stv0288_read_ber %d\n", *ucblocks); - - return 0; -} - -static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int stv0288_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *dfp) -{ - struct stv0288_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - char tm; - unsigned char tda[3]; - - dprintk("%s : FE_SET_FRONTEND\n", __func__); - - if (c->delivery_system != SYS_DVBS) { - dprintk("%s: unsupported delivery " - "system selected (%d)\n", - __func__, c->delivery_system); - return -EOPNOTSUPP; - } - - if (state->config->set_ts_params) - state->config->set_ts_params(fe, 0); - - /* only frequency & symbol_rate are used for tuner*/ - dfp->frequency = c->frequency; - dfp->u.qpsk.symbol_rate = c->symbol_rate; - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, dfp); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - udelay(10); - stv0288_set_symbolrate(fe, c->symbol_rate); - /* Carrier lock control register */ - stv0288_writeregI(state, 0x15, 0xc5); - - tda[0] = 0x2b; /* CFRM */ - tda[2] = 0x0; /* CFRL */ - for (tm = -6; tm < 7;) { - /* Viterbi status */ - if (stv0288_readreg(state, 0x24) & 0x8) - break; - - tda[2] += 40; - if (tda[2] < 40) - tm++; - tda[1] = (unsigned char)tm; - stv0288_writeregI(state, 0x2b, tda[1]); - stv0288_writeregI(state, 0x2c, tda[2]); - udelay(30); - } - - state->tuner_frequency = c->frequency; - state->fec_inner = FEC_AUTO; - state->symbol_rate = c->symbol_rate; - - return 0; -} - -static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct stv0288_state *state = fe->demodulator_priv; - - if (enable) - stv0288_writeregI(state, 0x01, 0xb5); - else - stv0288_writeregI(state, 0x01, 0x35); - - udelay(1); - - return 0; -} - -static void stv0288_release(struct dvb_frontend *fe) -{ - struct stv0288_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops stv0288_ops = { - - .info = { - .name = "ST STV0288 DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1000, /* kHz for QPSK frontends */ - .frequency_tolerance = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, /* ppm */ - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_QPSK | - FE_CAN_FEC_AUTO - }, - - .release = stv0288_release, - .init = stv0288_init, - .sleep = stv0288_sleep, - .write = stv0288_write, - .i2c_gate_ctrl = stv0288_i2c_gate_ctrl, - .read_status = stv0288_read_status, - .read_ber = stv0288_read_ber, - .read_signal_strength = stv0288_read_signal_strength, - .read_snr = stv0288_read_snr, - .read_ucblocks = stv0288_read_ucblocks, - .diseqc_send_master_cmd = stv0288_send_diseqc_msg, - .diseqc_send_burst = stv0288_send_diseqc_burst, - .set_tone = stv0288_set_tone, - .set_voltage = stv0288_set_voltage, - - .set_property = stv0288_set_property, - .get_property = stv0288_get_property, - .set_frontend = stv0288_set_frontend, -}; - -struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, - struct i2c_adapter *i2c) -{ - struct stv0288_state *state = NULL; - int id; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct stv0288_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->initialised = 0; - state->tuner_frequency = 0; - state->symbol_rate = 0; - state->fec_inner = 0; - state->errmode = STATUS_BER; - - stv0288_writeregI(state, 0x41, 0x04); - msleep(200); - id = stv0288_readreg(state, 0x00); - dprintk("stv0288 id %x\n", id); - - /* register 0x00 contains 0x11 for STV0288 */ - if (id != 0x11) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &stv0288_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - - return NULL; -} -EXPORT_SYMBOL(stv0288_attach); - -module_param(debug_legacy_dish_switch, int, 0444); -MODULE_PARM_DESC(debug_legacy_dish_switch, - "Enable timing analysis for Dish Network legacy switches"); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver"); -MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin"); -MODULE_LICENSE("GPL"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0288.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0288.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0288.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0288.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -/* - Driver for ST STV0288 demodulator - - Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de - for Reel Multimedia - Copyright (C) 2008 TurboSight.com, - Copyright (C) 2008 Igor M. Liplianin - Removed stb6000 specific tuner code and revised some - procedures. - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef STV0288_H -#define STV0288_H - -#include -#include "dvb_frontend.h" - -struct stv0288_config { - /* the demodulator's i2c address */ - u8 demod_address; - - u8* inittab; - - /* minimum delay before retuning */ - int min_delay_ms; - - int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); -}; - -#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \ - defined(MODULE)) -extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_STV0288 */ - -static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val) -{ - int r = 0; - u8 buf[] = { reg, val }; - if (fe->ops.write) - r = fe->ops.write(fe, buf, 2); - return r; -} - -#endif /* STV0288_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0297.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0297.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0297.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0297.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,723 +0,0 @@ -/* - Driver for STV0297 demodulator - - Copyright (C) 2004 Andrew de Quincey - Copyright (C) 2003-2004 Dennis Noermann - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "stv0297.h" - -struct stv0297_state { - struct i2c_adapter *i2c; - const struct stv0297_config *config; - struct dvb_frontend frontend; - - unsigned long last_ber; - unsigned long base_freq; -}; - -#if 1 -#define dprintk(x...) printk(x) -#else -#define dprintk(x...) -#endif - -#define STV0297_CLOCK_KHZ 28900 - - -static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data) -{ - int ret; - u8 buf[] = { reg, data }; - struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " - "ret == %i)\n", __func__, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -static int stv0297_readreg(struct stv0297_state *state, u8 reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, - {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} - }; - - // this device needs a STOP between the register and data - if (state->config->stop_during_read) { - if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); - return -1; - } - if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); - return -1; - } - } else { - if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); - return -1; - } - } - - return b1[0]; -} - -static int stv0297_writereg_mask(struct stv0297_state *state, u8 reg, u8 mask, u8 data) -{ - int val; - - val = stv0297_readreg(state, reg); - val &= ~mask; - val |= (data & mask); - stv0297_writereg(state, reg, val); - - return 0; -} - -static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len) -{ - int ret; - struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = - ®1,.len = 1}, - {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len} - }; - - // this device needs a STOP between the register and data - if (state->config->stop_during_read) { - if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); - return -1; - } - if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); - return -1; - } - } else { - if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); - return -1; - } - } - - return 0; -} - -static u32 stv0297_get_symbolrate(struct stv0297_state *state) -{ - u64 tmp; - - tmp = stv0297_readreg(state, 0x55); - tmp |= stv0297_readreg(state, 0x56) << 8; - tmp |= stv0297_readreg(state, 0x57) << 16; - tmp |= stv0297_readreg(state, 0x58) << 24; - - tmp *= STV0297_CLOCK_KHZ; - tmp >>= 32; - - return (u32) tmp; -} - -static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate) -{ - long tmp; - - tmp = 131072L * srate; /* 131072 = 2^17 */ - tmp = tmp / (STV0297_CLOCK_KHZ / 4); /* 1/4 = 2^-2 */ - tmp = tmp * 8192L; /* 8192 = 2^13 */ - - stv0297_writereg(state, 0x55, (unsigned char) (tmp & 0xFF)); - stv0297_writereg(state, 0x56, (unsigned char) (tmp >> 8)); - stv0297_writereg(state, 0x57, (unsigned char) (tmp >> 16)); - stv0297_writereg(state, 0x58, (unsigned char) (tmp >> 24)); -} - -static void stv0297_set_sweeprate(struct stv0297_state *state, short fshift, long symrate) -{ - long tmp; - - tmp = (long) fshift *262144L; /* 262144 = 2*18 */ - tmp /= symrate; - tmp *= 1024; /* 1024 = 2*10 */ - - // adjust - if (tmp >= 0) { - tmp += 500000; - } else { - tmp -= 500000; - } - tmp /= 1000000; - - stv0297_writereg(state, 0x60, tmp & 0xFF); - stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0); -} - -static void stv0297_set_carrieroffset(struct stv0297_state *state, long offset) -{ - long tmp; - - /* symrate is hardcoded to 10000 */ - tmp = offset * 26844L; /* (2**28)/10000 */ - if (tmp < 0) - tmp += 0x10000000; - tmp &= 0x0FFFFFFF; - - stv0297_writereg(state, 0x66, (unsigned char) (tmp & 0xFF)); - stv0297_writereg(state, 0x67, (unsigned char) (tmp >> 8)); - stv0297_writereg(state, 0x68, (unsigned char) (tmp >> 16)); - stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f); -} - -/* -static long stv0297_get_carrieroffset(struct stv0297_state *state) -{ - s64 tmp; - - stv0297_writereg(state, 0x6B, 0x00); - - tmp = stv0297_readreg(state, 0x66); - tmp |= (stv0297_readreg(state, 0x67) << 8); - tmp |= (stv0297_readreg(state, 0x68) << 16); - tmp |= (stv0297_readreg(state, 0x69) & 0x0F) << 24; - - tmp *= stv0297_get_symbolrate(state); - tmp >>= 28; - - return (s32) tmp; -} -*/ - -static void stv0297_set_initialdemodfreq(struct stv0297_state *state, long freq) -{ - s32 tmp; - - if (freq > 10000) - freq -= STV0297_CLOCK_KHZ; - - tmp = (STV0297_CLOCK_KHZ * 1000) / (1 << 16); - tmp = (freq * 1000) / tmp; - if (tmp > 0xffff) - tmp = 0xffff; - - stv0297_writereg_mask(state, 0x25, 0x80, 0x80); - stv0297_writereg(state, 0x21, tmp >> 8); - stv0297_writereg(state, 0x20, tmp); -} - -static int stv0297_set_qam(struct stv0297_state *state, fe_modulation_t modulation) -{ - int val = 0; - - switch (modulation) { - case QAM_16: - val = 0; - break; - - case QAM_32: - val = 1; - break; - - case QAM_64: - val = 4; - break; - - case QAM_128: - val = 2; - break; - - case QAM_256: - val = 3; - break; - - default: - return -EINVAL; - } - - stv0297_writereg_mask(state, 0x00, 0x70, val << 4); - - return 0; -} - -static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_inversion_t inversion) -{ - int val = 0; - - switch (inversion) { - case INVERSION_OFF: - val = 0; - break; - - case INVERSION_ON: - val = 1; - break; - - default: - return -EINVAL; - } - - stv0297_writereg_mask(state, 0x83, 0x08, val << 3); - - return 0; -} - -static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct stv0297_state *state = fe->demodulator_priv; - - if (enable) { - stv0297_writereg(state, 0x87, 0x78); - stv0297_writereg(state, 0x86, 0xc8); - } - - return 0; -} - -static int stv0297_init(struct dvb_frontend *fe) -{ - struct stv0297_state *state = fe->demodulator_priv; - int i; - - /* load init table */ - for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2) - stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]); - msleep(200); - - state->last_ber = 0; - - return 0; -} - -static int stv0297_sleep(struct dvb_frontend *fe) -{ - struct stv0297_state *state = fe->demodulator_priv; - - stv0297_writereg_mask(state, 0x80, 1, 1); - - return 0; -} - -static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status) -{ - struct stv0297_state *state = fe->demodulator_priv; - - u8 sync = stv0297_readreg(state, 0xDF); - - *status = 0; - if (sync & 0x80) - *status |= - FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; - return 0; -} - -static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber) -{ - struct stv0297_state *state = fe->demodulator_priv; - u8 BER[3]; - - stv0297_readregs(state, 0xA0, BER, 3); - if (!(BER[0] & 0x80)) { - state->last_ber = BER[2] << 8 | BER[1]; - stv0297_writereg_mask(state, 0xA0, 0x80, 0x80); - } - - *ber = state->last_ber; - - return 0; -} - - -static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength) -{ - struct stv0297_state *state = fe->demodulator_priv; - u8 STRENGTH[3]; - u16 tmp; - - stv0297_readregs(state, 0x41, STRENGTH, 3); - tmp = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0]; - if (STRENGTH[2] & 0x20) { - if (tmp < 0x200) - tmp = 0; - else - tmp = tmp - 0x200; - } else { - if (tmp > 0x1ff) - tmp = 0; - else - tmp = 0x1ff - tmp; - } - *strength = (tmp << 7) | (tmp >> 2); - return 0; -} - -static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr) -{ - struct stv0297_state *state = fe->demodulator_priv; - u8 SNR[2]; - - stv0297_readregs(state, 0x07, SNR, 2); - *snr = SNR[1] << 8 | SNR[0]; - - return 0; -} - -static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) -{ - struct stv0297_state *state = fe->demodulator_priv; - - stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */ - - *ucblocks = (stv0297_readreg(state, 0xD5) << 8) - | stv0297_readreg(state, 0xD4); - - stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */ - stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */ - - return 0; -} - -static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - struct stv0297_state *state = fe->demodulator_priv; - int u_threshold; - int initial_u; - int blind_u; - int delay; - int sweeprate; - int carrieroffset; - unsigned long starttime; - unsigned long timeout; - fe_spectral_inversion_t inversion; - - switch (p->u.qam.modulation) { - case QAM_16: - case QAM_32: - case QAM_64: - delay = 100; - sweeprate = 1000; - break; - - case QAM_128: - case QAM_256: - delay = 200; - sweeprate = 500; - break; - - default: - return -EINVAL; - } - - // determine inversion dependant parameters - inversion = p->inversion; - if (state->config->invert) - inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; - carrieroffset = -330; - switch (inversion) { - case INVERSION_OFF: - break; - - case INVERSION_ON: - sweeprate = -sweeprate; - carrieroffset = -carrieroffset; - break; - - default: - return -EINVAL; - } - - stv0297_init(fe); - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* clear software interrupts */ - stv0297_writereg(state, 0x82, 0x0); - - /* set initial demodulation frequency */ - stv0297_set_initialdemodfreq(state, 7250); - - /* setup AGC */ - stv0297_writereg_mask(state, 0x43, 0x10, 0x00); - stv0297_writereg(state, 0x41, 0x00); - stv0297_writereg_mask(state, 0x42, 0x03, 0x01); - stv0297_writereg_mask(state, 0x36, 0x60, 0x00); - stv0297_writereg_mask(state, 0x36, 0x18, 0x00); - stv0297_writereg_mask(state, 0x71, 0x80, 0x80); - stv0297_writereg(state, 0x72, 0x00); - stv0297_writereg(state, 0x73, 0x00); - stv0297_writereg_mask(state, 0x74, 0x0F, 0x00); - stv0297_writereg_mask(state, 0x43, 0x08, 0x00); - stv0297_writereg_mask(state, 0x71, 0x80, 0x00); - - /* setup STL */ - stv0297_writereg_mask(state, 0x5a, 0x20, 0x20); - stv0297_writereg_mask(state, 0x5b, 0x02, 0x02); - stv0297_writereg_mask(state, 0x5b, 0x02, 0x00); - stv0297_writereg_mask(state, 0x5b, 0x01, 0x00); - stv0297_writereg_mask(state, 0x5a, 0x40, 0x40); - - /* disable frequency sweep */ - stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); - - /* reset deinterleaver */ - stv0297_writereg_mask(state, 0x81, 0x01, 0x01); - stv0297_writereg_mask(state, 0x81, 0x01, 0x00); - - /* ??? */ - stv0297_writereg_mask(state, 0x83, 0x20, 0x20); - stv0297_writereg_mask(state, 0x83, 0x20, 0x00); - - /* reset equaliser */ - u_threshold = stv0297_readreg(state, 0x00) & 0xf; - initial_u = stv0297_readreg(state, 0x01) >> 4; - blind_u = stv0297_readreg(state, 0x01) & 0xf; - stv0297_writereg_mask(state, 0x84, 0x01, 0x01); - stv0297_writereg_mask(state, 0x84, 0x01, 0x00); - stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold); - stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4); - stv0297_writereg_mask(state, 0x01, 0x0f, blind_u); - - /* data comes from internal A/D */ - stv0297_writereg_mask(state, 0x87, 0x80, 0x00); - - /* clear phase registers */ - stv0297_writereg(state, 0x63, 0x00); - stv0297_writereg(state, 0x64, 0x00); - stv0297_writereg(state, 0x65, 0x00); - stv0297_writereg(state, 0x66, 0x00); - stv0297_writereg(state, 0x67, 0x00); - stv0297_writereg(state, 0x68, 0x00); - stv0297_writereg_mask(state, 0x69, 0x0f, 0x00); - - /* set parameters */ - stv0297_set_qam(state, p->u.qam.modulation); - stv0297_set_symbolrate(state, p->u.qam.symbol_rate / 1000); - stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000); - stv0297_set_carrieroffset(state, carrieroffset); - stv0297_set_inversion(state, inversion); - - /* kick off lock */ - /* Disable corner detection for higher QAMs */ - if (p->u.qam.modulation == QAM_128 || - p->u.qam.modulation == QAM_256) - stv0297_writereg_mask(state, 0x88, 0x08, 0x00); - else - stv0297_writereg_mask(state, 0x88, 0x08, 0x08); - - stv0297_writereg_mask(state, 0x5a, 0x20, 0x00); - stv0297_writereg_mask(state, 0x6a, 0x01, 0x01); - stv0297_writereg_mask(state, 0x43, 0x40, 0x40); - stv0297_writereg_mask(state, 0x5b, 0x30, 0x00); - stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c); - stv0297_writereg_mask(state, 0x03, 0x03, 0x03); - stv0297_writereg_mask(state, 0x43, 0x10, 0x10); - - /* wait for WGAGC lock */ - starttime = jiffies; - timeout = jiffies + msecs_to_jiffies(2000); - while (time_before(jiffies, timeout)) { - msleep(10); - if (stv0297_readreg(state, 0x43) & 0x08) - break; - } - if (time_after(jiffies, timeout)) { - goto timeout; - } - msleep(20); - - /* wait for equaliser partial convergence */ - timeout = jiffies + msecs_to_jiffies(500); - while (time_before(jiffies, timeout)) { - msleep(10); - - if (stv0297_readreg(state, 0x82) & 0x04) { - break; - } - } - if (time_after(jiffies, timeout)) { - goto timeout; - } - - /* wait for equaliser full convergence */ - timeout = jiffies + msecs_to_jiffies(delay); - while (time_before(jiffies, timeout)) { - msleep(10); - - if (stv0297_readreg(state, 0x82) & 0x08) { - break; - } - } - if (time_after(jiffies, timeout)) { - goto timeout; - } - - /* disable sweep */ - stv0297_writereg_mask(state, 0x6a, 1, 0); - stv0297_writereg_mask(state, 0x88, 8, 0); - - /* wait for main lock */ - timeout = jiffies + msecs_to_jiffies(20); - while (time_before(jiffies, timeout)) { - msleep(10); - - if (stv0297_readreg(state, 0xDF) & 0x80) { - break; - } - } - if (time_after(jiffies, timeout)) { - goto timeout; - } - msleep(100); - - /* is it still locked after that delay? */ - if (!(stv0297_readreg(state, 0xDF) & 0x80)) { - goto timeout; - } - - /* success!! */ - stv0297_writereg_mask(state, 0x5a, 0x40, 0x00); - state->base_freq = p->frequency; - return 0; - -timeout: - stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); - return 0; -} - -static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - struct stv0297_state *state = fe->demodulator_priv; - int reg_00, reg_83; - - reg_00 = stv0297_readreg(state, 0x00); - reg_83 = stv0297_readreg(state, 0x83); - - p->frequency = state->base_freq; - p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; - if (state->config->invert) - p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; - p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000; - p->u.qam.fec_inner = FEC_NONE; - - switch ((reg_00 >> 4) & 0x7) { - case 0: - p->u.qam.modulation = QAM_16; - break; - case 1: - p->u.qam.modulation = QAM_32; - break; - case 2: - p->u.qam.modulation = QAM_128; - break; - case 3: - p->u.qam.modulation = QAM_256; - break; - case 4: - p->u.qam.modulation = QAM_64; - break; - } - - return 0; -} - -static void stv0297_release(struct dvb_frontend *fe) -{ - struct stv0297_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops stv0297_ops; - -struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, - struct i2c_adapter *i2c) -{ - struct stv0297_state *state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct stv0297_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->last_ber = 0; - state->base_freq = 0; - - /* check if the demod is there */ - if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops stv0297_ops = { - - .info = { - .name = "ST STV0297 DVB-C", - .type = FE_QAM, - .frequency_min = 47000000, - .frequency_max = 862000000, - .frequency_stepsize = 62500, - .symbol_rate_min = 870000, - .symbol_rate_max = 11700000, - .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO}, - - .release = stv0297_release, - - .init = stv0297_init, - .sleep = stv0297_sleep, - .i2c_gate_ctrl = stv0297_i2c_gate_ctrl, - - .set_frontend = stv0297_set_frontend, - .get_frontend = stv0297_get_frontend, - - .read_status = stv0297_read_status, - .read_ber = stv0297_read_ber, - .read_signal_strength = stv0297_read_signal_strength, - .read_snr = stv0297_read_snr, - .read_ucblocks = stv0297_read_ucblocks, -}; - -MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver"); -MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(stv0297_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0297.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0297.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0297.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0297.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/* - Driver for STV0297 demodulator - - Copyright (C) 2003-2004 Dennis Noermann - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef STV0297_H -#define STV0297_H - -#include -#include "dvb_frontend.h" - -struct stv0297_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* inittab - array of pairs of values. - * First of each pair is the register, second is the value. - * List should be terminated with an 0xff, 0xff pair. - */ - u8* inittab; - - /* does the "inversion" need inverted? */ - u8 invert:1; - - /* set to 1 if the device requires an i2c STOP during reading */ - u8 stop_during_read:1; -}; - -#if defined(CONFIG_DVB_STV0297) || (defined(CONFIG_DVB_STV0297_MODULE) && defined(MODULE)) -extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_STV0297 - -#endif // STV0297_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0299.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0299.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0299.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0299.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,754 +0,0 @@ -/* - Driver for ST STV0299 demodulator - - Copyright (C) 2001-2002 Convergence Integrated Media GmbH - , - , - - - - Philips SU1278/SH - - Copyright (C) 2002 by Peter Schildmann - - - LG TDQF-S001F - - Copyright (C) 2002 Felix Domke - & Andreas Oberritter - - - Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B - - Copyright (C) 2003 Vadim Catana : - - Support for Philips SU1278 on Technotrend hardware - - Copyright (C) 2004 Andrew de Quincey - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "stv0299.h" - -struct stv0299_state { - struct i2c_adapter* i2c; - const struct stv0299_config* config; - struct dvb_frontend frontend; - - u8 initialised:1; - u32 tuner_frequency; - u32 symbol_rate; - fe_code_rate_t fec_inner; - int errmode; - u32 ucblocks; -}; - -#define STATUS_BER 0 -#define STATUS_UCBLOCKS 1 - -static int debug; -static int debug_legacy_dish_switch; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "stv0299: " args); \ - } while (0) - - -static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) -{ - int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - - ret = i2c_transfer (state->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " - "ret == %i)\n", __func__, reg, data, ret); - - return (ret != 1) ? -EREMOTEIO : 0; -} - -static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len) -{ - struct stv0299_state* state = fe->demodulator_priv; - - if (len != 2) - return -EINVAL; - - return stv0299_writeregI(state, buf[0], buf[1]); -} - -static u8 stv0299_readreg (struct stv0299_state* state, u8 reg) -{ - int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - ret = i2c_transfer (state->i2c, msg, 2); - - if (ret != 2) - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", - __func__, reg, ret); - - return b1[0]; -} - -static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len) -{ - int ret; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; - - ret = i2c_transfer (state->i2c, msg, 2); - - if (ret != 2) - dprintk("%s: readreg error (ret == %i)\n", __func__, ret); - - return ret == 2 ? 0 : ret; -} - -static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) -{ - dprintk ("%s\n", __func__); - - switch (fec) { - case FEC_AUTO: - { - return stv0299_writeregI (state, 0x31, 0x1f); - } - case FEC_1_2: - { - return stv0299_writeregI (state, 0x31, 0x01); - } - case FEC_2_3: - { - return stv0299_writeregI (state, 0x31, 0x02); - } - case FEC_3_4: - { - return stv0299_writeregI (state, 0x31, 0x04); - } - case FEC_5_6: - { - return stv0299_writeregI (state, 0x31, 0x08); - } - case FEC_7_8: - { - return stv0299_writeregI (state, 0x31, 0x10); - } - default: - { - return -EINVAL; - } - } -} - -static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state) -{ - static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6, - FEC_7_8, FEC_1_2 }; - u8 index; - - dprintk ("%s\n", __func__); - - index = stv0299_readreg (state, 0x1b); - index &= 0x7; - - if (index > 4) - return FEC_AUTO; - - return fec_tab [index]; -} - -static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) -{ - unsigned long start = jiffies; - - dprintk ("%s\n", __func__); - - while (stv0299_readreg(state, 0x0a) & 1) { - if (jiffies - start > timeout) { - dprintk ("%s: timeout!!\n", __func__); - return -ETIMEDOUT; - } - msleep(10); - }; - - return 0; -} - -static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) -{ - unsigned long start = jiffies; - - dprintk ("%s\n", __func__); - - while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) { - if (jiffies - start > timeout) { - dprintk ("%s: timeout!!\n", __func__); - return -ETIMEDOUT; - } - msleep(10); - }; - - return 0; -} - -static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate) -{ - struct stv0299_state* state = fe->demodulator_priv; - u64 big = srate; - u32 ratio; - - // check rate is within limits - if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; - - // calculate value to program - big = big << 20; - big += (state->config->mclk-1); // round correctly - do_div(big, state->config->mclk); - ratio = big << 4; - - return state->config->set_symbol_rate(fe, srate, ratio); -} - -static int stv0299_get_symbolrate (struct stv0299_state* state) -{ - u32 Mclk = state->config->mclk / 4096L; - u32 srate; - s32 offset; - u8 sfr[3]; - s8 rtf; - - dprintk ("%s\n", __func__); - - stv0299_readregs (state, 0x1f, sfr, 3); - stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1); - - srate = (sfr[0] << 8) | sfr[1]; - srate *= Mclk; - srate /= 16; - srate += (sfr[2] >> 4) * Mclk / 256; - offset = (s32) rtf * (srate / 4096L); - offset /= 128; - - dprintk ("%s : srate = %i\n", __func__, srate); - dprintk ("%s : ofset = %i\n", __func__, offset); - - srate += offset; - - srate += 1000; - srate /= 2000; - srate *= 2000; - - return srate; -} - -static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) -{ - struct stv0299_state* state = fe->demodulator_priv; - u8 val; - int i; - - dprintk ("%s\n", __func__); - - if (stv0299_wait_diseqc_idle (state, 100) < 0) - return -ETIMEDOUT; - - val = stv0299_readreg (state, 0x08); - - if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ - return -EREMOTEIO; - - for (i=0; imsg_len; i++) { - if (stv0299_wait_diseqc_fifo (state, 100) < 0) - return -ETIMEDOUT; - - if (stv0299_writeregI (state, 0x09, m->msg[i])) - return -EREMOTEIO; - } - - if (stv0299_wait_diseqc_idle (state, 100) < 0) - return -ETIMEDOUT; - - return 0; -} - -static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) -{ - struct stv0299_state* state = fe->demodulator_priv; - u8 val; - - dprintk ("%s\n", __func__); - - if (stv0299_wait_diseqc_idle (state, 100) < 0) - return -ETIMEDOUT; - - val = stv0299_readreg (state, 0x08); - - if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ - return -EREMOTEIO; - - if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) - return -EREMOTEIO; - - if (stv0299_wait_diseqc_idle (state, 100) < 0) - return -ETIMEDOUT; - - if (stv0299_writeregI (state, 0x08, val)) - return -EREMOTEIO; - - return 0; -} - -static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct stv0299_state* state = fe->demodulator_priv; - u8 val; - - if (stv0299_wait_diseqc_idle (state, 100) < 0) - return -ETIMEDOUT; - - val = stv0299_readreg (state, 0x08); - - switch (tone) { - case SEC_TONE_ON: - return stv0299_writeregI (state, 0x08, val | 0x3); - - case SEC_TONE_OFF: - return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02); - - default: - return -EINVAL; - } -} - -static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct stv0299_state* state = fe->demodulator_priv; - u8 reg0x08; - u8 reg0x0c; - - dprintk("%s: %s\n", __func__, - voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : - voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); - - reg0x08 = stv0299_readreg (state, 0x08); - reg0x0c = stv0299_readreg (state, 0x0c); - - /** - * H/V switching over OP0, OP1 and OP2 are LNB power enable bits - */ - reg0x0c &= 0x0f; - reg0x08 = (reg0x08 & 0x3f) | (state->config->lock_output << 6); - - switch (voltage) { - case SEC_VOLTAGE_13: - if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) - reg0x0c |= 0x10; /* OP1 off, OP0 on */ - else - reg0x0c |= 0x40; /* OP1 on, OP0 off */ - break; - case SEC_VOLTAGE_18: - reg0x0c |= 0x50; /* OP1 on, OP0 on */ - break; - case SEC_VOLTAGE_OFF: - /* LNB power off! */ - reg0x08 = 0x00; - reg0x0c = 0x00; - break; - default: - return -EINVAL; - }; - - if (state->config->op0_off) - reg0x0c &= ~0x10; - - stv0299_writeregI(state, 0x08, reg0x08); - return stv0299_writeregI(state, 0x0c, reg0x0c); -} - -static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd) -{ - struct stv0299_state* state = fe->demodulator_priv; - u8 reg0x08; - u8 reg0x0c; - u8 lv_mask = 0x40; - u8 last = 1; - int i; - struct timeval nexttime; - struct timeval tv[10]; - - reg0x08 = stv0299_readreg (state, 0x08); - reg0x0c = stv0299_readreg (state, 0x0c); - reg0x0c &= 0x0f; - stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); - if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) - lv_mask = 0x10; - - cmd = cmd << 1; - if (debug_legacy_dish_switch) - printk ("%s switch command: 0x%04lx\n",__func__, cmd); - - do_gettimeofday (&nexttime); - if (debug_legacy_dish_switch) - memcpy (&tv[0], &nexttime, sizeof (struct timeval)); - stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ - - dvb_frontend_sleep_until(&nexttime, 32000); - - for (i=0; i<9; i++) { - if (debug_legacy_dish_switch) - do_gettimeofday (&tv[i+1]); - if((cmd & 0x01) != last) { - /* set voltage to (last ? 13V : 18V) */ - stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50)); - last = (last) ? 0 : 1; - } - - cmd = cmd >> 1; - - if (i != 8) - dvb_frontend_sleep_until(&nexttime, 8000); - } - if (debug_legacy_dish_switch) { - printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", - __func__, fe->dvb->num); - for (i = 1; i < 10; i++) - printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); - } - - return 0; -} - -static int stv0299_init (struct dvb_frontend* fe) -{ - struct stv0299_state* state = fe->demodulator_priv; - int i; - u8 reg; - u8 val; - - dprintk("stv0299: init chip\n"); - - for (i = 0; ; i += 2) { - reg = state->config->inittab[i]; - val = state->config->inittab[i+1]; - if (reg == 0xff && val == 0xff) - break; - if (reg == 0x0c && state->config->op0_off) - val &= ~0x10; - stv0299_writeregI(state, reg, val); - } - - return 0; -} - -static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct stv0299_state* state = fe->demodulator_priv; - - u8 signal = 0xff - stv0299_readreg (state, 0x18); - u8 sync = stv0299_readreg (state, 0x1b); - - dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); - *status = 0; - - if (signal > 10) - *status |= FE_HAS_SIGNAL; - - if (sync & 0x80) - *status |= FE_HAS_CARRIER; - - if (sync & 0x10) - *status |= FE_HAS_VITERBI; - - if (sync & 0x08) - *status |= FE_HAS_SYNC; - - if ((sync & 0x98) == 0x98) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct stv0299_state* state = fe->demodulator_priv; - - if (state->errmode != STATUS_BER) - return -ENOSYS; - - *ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8); - - return 0; -} - -static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct stv0299_state* state = fe->demodulator_priv; - - s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8) - | stv0299_readreg (state, 0x19)); - - dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __func__, - stv0299_readreg (state, 0x18), - stv0299_readreg (state, 0x19), (int) signal); - - signal = signal * 5 / 4; - *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; - - return 0; -} - -static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct stv0299_state* state = fe->demodulator_priv; - - s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8) - | stv0299_readreg (state, 0x25)); - xsnr = 3 * (xsnr - 0xa100); - *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; - - return 0; -} - -static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct stv0299_state* state = fe->demodulator_priv; - - if (state->errmode != STATUS_UCBLOCKS) - return -ENOSYS; - - state->ucblocks += stv0299_readreg(state, 0x1e); - state->ucblocks += (stv0299_readreg(state, 0x1d) << 8); - *ucblocks = state->ucblocks; - - return 0; -} - -static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) -{ - struct stv0299_state* state = fe->demodulator_priv; - int invval = 0; - - dprintk ("%s : FE_SET_FRONTEND\n", __func__); - if (state->config->set_ts_params) - state->config->set_ts_params(fe, 0); - - // set the inversion - if (p->inversion == INVERSION_OFF) invval = 0; - else if (p->inversion == INVERSION_ON) invval = 1; - else { - printk("stv0299 does not support auto-inversion\n"); - return -EINVAL; - } - if (state->config->invert) invval = (~invval) & 1; - stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - stv0299_set_FEC (state, p->u.qpsk.fec_inner); - stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); - stv0299_writeregI(state, 0x22, 0x00); - stv0299_writeregI(state, 0x23, 0x00); - - state->tuner_frequency = p->frequency; - state->fec_inner = p->u.qpsk.fec_inner; - state->symbol_rate = p->u.qpsk.symbol_rate; - - return 0; -} - -static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) -{ - struct stv0299_state* state = fe->demodulator_priv; - s32 derot_freq; - int invval; - - derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8) - | stv0299_readreg (state, 0x23)); - - derot_freq *= (state->config->mclk >> 16); - derot_freq += 500; - derot_freq /= 1000; - - p->frequency += derot_freq; - - invval = stv0299_readreg (state, 0x0c) & 1; - if (state->config->invert) invval = (~invval) & 1; - p->inversion = invval ? INVERSION_ON : INVERSION_OFF; - - p->u.qpsk.fec_inner = stv0299_get_fec (state); - p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state); - - return 0; -} - -static int stv0299_sleep(struct dvb_frontend* fe) -{ - struct stv0299_state* state = fe->demodulator_priv; - - stv0299_writeregI(state, 0x02, 0x80); - state->initialised = 0; - - return 0; -} - -static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct stv0299_state* state = fe->demodulator_priv; - - if (enable) { - stv0299_writeregI(state, 0x05, 0xb5); - } else { - stv0299_writeregI(state, 0x05, 0x35); - } - udelay(1); - return 0; -} - -static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) -{ - struct stv0299_state* state = fe->demodulator_priv; - - fesettings->min_delay_ms = state->config->min_delay_ms; - if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000; - fesettings->max_drift = 5000; - } else { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; - fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; - } - return 0; -} - -static void stv0299_release(struct dvb_frontend* fe) -{ - struct stv0299_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops stv0299_ops; - -struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, - struct i2c_adapter* i2c) -{ - struct stv0299_state* state = NULL; - int id; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct stv0299_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->initialised = 0; - state->tuner_frequency = 0; - state->symbol_rate = 0; - state->fec_inner = 0; - state->errmode = STATUS_BER; - - /* check if the demod is there */ - stv0299_writeregI(state, 0x02, 0x34); /* standby off */ - msleep(200); - id = stv0299_readreg(state, 0x00); - - /* register 0x00 contains 0xa1 for STV0299 and STV0299B */ - /* register 0x00 might contain 0x80 when returning from standby */ - if (id != 0xa1 && id != 0x80) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops stv0299_ops = { - - .info = { - .name = "ST STV0299 DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, /* kHz for QPSK frontends */ - .frequency_tolerance = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, /* ppm */ - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_QPSK | - FE_CAN_FEC_AUTO - }, - - .release = stv0299_release, - - .init = stv0299_init, - .sleep = stv0299_sleep, - .write = stv0299_write, - .i2c_gate_ctrl = stv0299_i2c_gate_ctrl, - - .set_frontend = stv0299_set_frontend, - .get_frontend = stv0299_get_frontend, - .get_tune_settings = stv0299_get_tune_settings, - - .read_status = stv0299_read_status, - .read_ber = stv0299_read_ber, - .read_signal_strength = stv0299_read_signal_strength, - .read_snr = stv0299_read_snr, - .read_ucblocks = stv0299_read_ucblocks, - - .diseqc_send_master_cmd = stv0299_send_diseqc_msg, - .diseqc_send_burst = stv0299_send_diseqc_burst, - .set_tone = stv0299_set_tone, - .set_voltage = stv0299_set_voltage, - .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd, -}; - -module_param(debug_legacy_dish_switch, int, 0444); -MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches"); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver"); -MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, " - "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(stv0299_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0299.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0299.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0299.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0299.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -/* - Driver for ST STV0299 demodulator - - Copyright (C) 2001-2002 Convergence Integrated Media GmbH - , - , - - - - Philips SU1278/SH - - Copyright (C) 2002 by Peter Schildmann - - - LG TDQF-S001F - - Copyright (C) 2002 Felix Domke - & Andreas Oberritter - - - Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B - - Copyright (C) 2003 Vadim Catana : - - Support for Philips SU1278 on Technotrend hardware - - Copyright (C) 2004 Andrew de Quincey - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef STV0299_H -#define STV0299_H - -#include -#include "dvb_frontend.h" - -#define STV0299_LOCKOUTPUT_0 0 -#define STV0299_LOCKOUTPUT_1 1 -#define STV0299_LOCKOUTPUT_CF 2 -#define STV0299_LOCKOUTPUT_LK 3 - -#define STV0299_VOLT13_OP0 0 -#define STV0299_VOLT13_OP1 1 - -struct stv0299_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* inittab - array of pairs of values. - * First of each pair is the register, second is the value. - * List should be terminated with an 0xff, 0xff pair. - */ - const u8* inittab; - - /* master clock to use */ - u32 mclk; - - /* does the inversion require inversion? */ - u8 invert:1; - - /* Skip reinitialisation? */ - u8 skip_reinit:1; - - /* LOCK OUTPUT setting */ - u8 lock_output:2; - - /* Is 13v controlled by OP0 or OP1? */ - u8 volt13_op0_op1:1; - - /* Turn-off OP0? */ - u8 op0_off:1; - - /* minimum delay before retuning */ - int min_delay_ms; - - /* Set the symbol rate */ - int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio); - - /* Set device param to start dma */ - int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); -}; - -#if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE)) -extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_STV0299 - -static inline int stv0299_writereg(struct dvb_frontend *fe, u8 reg, u8 val) { - int r = 0; - u8 buf[] = {reg, val}; - if (fe->ops.write) - r = fe->ops.write(fe, buf, 2); - return r; -} - -#endif // STV0299_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3459 +0,0 @@ -/* - * stv0367.c - * - * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. - * - * Copyright (C) ST Microelectronics. - * Copyright (C) 2010,2011 NetUP Inc. - * Copyright (C) 2010,2011 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "stv0367.h" -#include "stv0367_regs.h" -#include "stv0367_priv.h" - -static int stvdebug; -module_param_named(debug, stvdebug, int, 0644); - -static int i2cdebug; -module_param_named(i2c_debug, i2cdebug, int, 0644); - -#define dprintk(args...) \ - do { \ - if (stvdebug) \ - printk(KERN_DEBUG args); \ - } while (0) - /* DVB-C */ - -struct stv0367cab_state { - enum stv0367_cab_signal_type state; - u32 mclk; - u32 adc_clk; - s32 search_range; - s32 derot_offset; - /* results */ - int locked; /* channel found */ - u32 freq_khz; /* found frequency (in kHz) */ - u32 symbol_rate; /* found symbol rate (in Bds) */ - enum stv0367cab_mod modulation; /* modulation */ - fe_spectral_inversion_t spect_inv; /* Spectrum Inversion */ -}; - -struct stv0367ter_state { - /* DVB-T */ - enum stv0367_ter_signal_type state; - enum stv0367_ter_if_iq_mode if_iq_mode; - enum stv0367_ter_mode mode;/* mode 2K or 8K */ - fe_guard_interval_t guard; - enum stv0367_ter_hierarchy hierarchy; - u32 frequency; - fe_spectral_inversion_t sense; /* current search spectrum */ - u8 force; /* force mode/guard */ - u8 bw; /* channel width 6, 7 or 8 in MHz */ - u8 pBW; /* channel width used during previous lock */ - u32 pBER; - u32 pPER; - u32 ucblocks; - s8 echo_pos; /* echo position */ - u8 first_lock; - u8 unlock_counter; - u32 agc_val; -}; - -struct stv0367_state { - struct dvb_frontend fe; - struct i2c_adapter *i2c; - /* config settings */ - const struct stv0367_config *config; - u8 chip_id; - /* DVB-C */ - struct stv0367cab_state *cab_state; - /* DVB-T */ - struct stv0367ter_state *ter_state; -}; - -struct st_register { - u16 addr; - u8 value; -}; - -/* values for STV4100 XTAL=30M int clk=53.125M*/ -static struct st_register def0367ter[STV0367TER_NBREGS] = { - {R367TER_ID, 0x60}, - {R367TER_I2CRPT, 0xa0}, - /* {R367TER_I2CRPT, 0x22},*/ - {R367TER_TOPCTRL, 0x00},/* for xc5000; was 0x02 */ - {R367TER_IOCFG0, 0x40}, - {R367TER_DAC0R, 0x00}, - {R367TER_IOCFG1, 0x00}, - {R367TER_DAC1R, 0x00}, - {R367TER_IOCFG2, 0x62}, - {R367TER_SDFR, 0x00}, - {R367TER_STATUS, 0xf8}, - {R367TER_AUX_CLK, 0x0a}, - {R367TER_FREESYS1, 0x00}, - {R367TER_FREESYS2, 0x00}, - {R367TER_FREESYS3, 0x00}, - {R367TER_GPIO_CFG, 0x55}, - {R367TER_GPIO_CMD, 0x00}, - {R367TER_AGC2MAX, 0xff}, - {R367TER_AGC2MIN, 0x00}, - {R367TER_AGC1MAX, 0xff}, - {R367TER_AGC1MIN, 0x00}, - {R367TER_AGCR, 0xbc}, - {R367TER_AGC2TH, 0x00}, - {R367TER_AGC12C, 0x00}, - {R367TER_AGCCTRL1, 0x85}, - {R367TER_AGCCTRL2, 0x1f}, - {R367TER_AGC1VAL1, 0x00}, - {R367TER_AGC1VAL2, 0x00}, - {R367TER_AGC2VAL1, 0x6f}, - {R367TER_AGC2VAL2, 0x05}, - {R367TER_AGC2PGA, 0x00}, - {R367TER_OVF_RATE1, 0x00}, - {R367TER_OVF_RATE2, 0x00}, - {R367TER_GAIN_SRC1, 0xaa},/* for xc5000; was 0x2b */ - {R367TER_GAIN_SRC2, 0xd6},/* for xc5000; was 0x04 */ - {R367TER_INC_DEROT1, 0x55}, - {R367TER_INC_DEROT2, 0x55}, - {R367TER_PPM_CPAMP_DIR, 0x2c}, - {R367TER_PPM_CPAMP_INV, 0x00}, - {R367TER_FREESTFE_1, 0x00}, - {R367TER_FREESTFE_2, 0x1c}, - {R367TER_DCOFFSET, 0x00}, - {R367TER_EN_PROCESS, 0x05}, - {R367TER_SDI_SMOOTHER, 0x80}, - {R367TER_FE_LOOP_OPEN, 0x1c}, - {R367TER_FREQOFF1, 0x00}, - {R367TER_FREQOFF2, 0x00}, - {R367TER_FREQOFF3, 0x00}, - {R367TER_TIMOFF1, 0x00}, - {R367TER_TIMOFF2, 0x00}, - {R367TER_EPQ, 0x02}, - {R367TER_EPQAUTO, 0x01}, - {R367TER_SYR_UPDATE, 0xf5}, - {R367TER_CHPFREE, 0x00}, - {R367TER_PPM_STATE_MAC, 0x23}, - {R367TER_INR_THRESHOLD, 0xff}, - {R367TER_EPQ_TPS_ID_CELL, 0xf9}, - {R367TER_EPQ_CFG, 0x00}, - {R367TER_EPQ_STATUS, 0x01}, - {R367TER_AUTORELOCK, 0x81}, - {R367TER_BER_THR_VMSB, 0x00}, - {R367TER_BER_THR_MSB, 0x00}, - {R367TER_BER_THR_LSB, 0x00}, - {R367TER_CCD, 0x83}, - {R367TER_SPECTR_CFG, 0x00}, - {R367TER_CHC_DUMMY, 0x18}, - {R367TER_INC_CTL, 0x88}, - {R367TER_INCTHRES_COR1, 0xb4}, - {R367TER_INCTHRES_COR2, 0x96}, - {R367TER_INCTHRES_DET1, 0x0e}, - {R367TER_INCTHRES_DET2, 0x11}, - {R367TER_IIR_CELLNB, 0x8d}, - {R367TER_IIRCX_COEFF1_MSB, 0x00}, - {R367TER_IIRCX_COEFF1_LSB, 0x00}, - {R367TER_IIRCX_COEFF2_MSB, 0x09}, - {R367TER_IIRCX_COEFF2_LSB, 0x18}, - {R367TER_IIRCX_COEFF3_MSB, 0x14}, - {R367TER_IIRCX_COEFF3_LSB, 0x9c}, - {R367TER_IIRCX_COEFF4_MSB, 0x00}, - {R367TER_IIRCX_COEFF4_LSB, 0x00}, - {R367TER_IIRCX_COEFF5_MSB, 0x36}, - {R367TER_IIRCX_COEFF5_LSB, 0x42}, - {R367TER_FEPATH_CFG, 0x00}, - {R367TER_PMC1_FUNC, 0x65}, - {R367TER_PMC1_FOR, 0x00}, - {R367TER_PMC2_FUNC, 0x00}, - {R367TER_STATUS_ERR_DA, 0xe0}, - {R367TER_DIG_AGC_R, 0xfe}, - {R367TER_COMAGC_TARMSB, 0x0b}, - {R367TER_COM_AGC_TAR_ENMODE, 0x41}, - {R367TER_COM_AGC_CFG, 0x3e}, - {R367TER_COM_AGC_GAIN1, 0x39}, - {R367TER_AUT_AGC_TARGETMSB, 0x0b}, - {R367TER_LOCK_DET_MSB, 0x01}, - {R367TER_AGCTAR_LOCK_LSBS, 0x40}, - {R367TER_AUT_GAIN_EN, 0xf4}, - {R367TER_AUT_CFG, 0xf0}, - {R367TER_LOCKN, 0x23}, - {R367TER_INT_X_3, 0x00}, - {R367TER_INT_X_2, 0x03}, - {R367TER_INT_X_1, 0x8d}, - {R367TER_INT_X_0, 0xa0}, - {R367TER_MIN_ERRX_MSB, 0x00}, - {R367TER_COR_CTL, 0x23}, - {R367TER_COR_STAT, 0xf6}, - {R367TER_COR_INTEN, 0x00}, - {R367TER_COR_INTSTAT, 0x3f}, - {R367TER_COR_MODEGUARD, 0x03}, - {R367TER_AGC_CTL, 0x08}, - {R367TER_AGC_MANUAL1, 0x00}, - {R367TER_AGC_MANUAL2, 0x00}, - {R367TER_AGC_TARG, 0x16}, - {R367TER_AGC_GAIN1, 0x53}, - {R367TER_AGC_GAIN2, 0x1d}, - {R367TER_RESERVED_1, 0x00}, - {R367TER_RESERVED_2, 0x00}, - {R367TER_RESERVED_3, 0x00}, - {R367TER_CAS_CTL, 0x44}, - {R367TER_CAS_FREQ, 0xb3}, - {R367TER_CAS_DAGCGAIN, 0x12}, - {R367TER_SYR_CTL, 0x04}, - {R367TER_SYR_STAT, 0x10}, - {R367TER_SYR_NCO1, 0x00}, - {R367TER_SYR_NCO2, 0x00}, - {R367TER_SYR_OFFSET1, 0x00}, - {R367TER_SYR_OFFSET2, 0x00}, - {R367TER_FFT_CTL, 0x00}, - {R367TER_SCR_CTL, 0x70}, - {R367TER_PPM_CTL1, 0xf8}, - {R367TER_TRL_CTL, 0x14},/* for xc5000; was 0xac */ - {R367TER_TRL_NOMRATE1, 0xae},/* for xc5000; was 0x1e */ - {R367TER_TRL_NOMRATE2, 0x56},/* for xc5000; was 0x58 */ - {R367TER_TRL_TIME1, 0x1d}, - {R367TER_TRL_TIME2, 0xfc}, - {R367TER_CRL_CTL, 0x24}, - {R367TER_CRL_FREQ1, 0xad}, - {R367TER_CRL_FREQ2, 0x9d}, - {R367TER_CRL_FREQ3, 0xff}, - {R367TER_CHC_CTL, 0x01}, - {R367TER_CHC_SNR, 0xf0}, - {R367TER_BDI_CTL, 0x00}, - {R367TER_DMP_CTL, 0x00}, - {R367TER_TPS_RCVD1, 0x30}, - {R367TER_TPS_RCVD2, 0x02}, - {R367TER_TPS_RCVD3, 0x01}, - {R367TER_TPS_RCVD4, 0x00}, - {R367TER_TPS_ID_CELL1, 0x00}, - {R367TER_TPS_ID_CELL2, 0x00}, - {R367TER_TPS_RCVD5_SET1, 0x02}, - {R367TER_TPS_SET2, 0x02}, - {R367TER_TPS_SET3, 0x01}, - {R367TER_TPS_CTL, 0x00}, - {R367TER_CTL_FFTOSNUM, 0x34}, - {R367TER_TESTSELECT, 0x09}, - {R367TER_MSC_REV, 0x0a}, - {R367TER_PIR_CTL, 0x00}, - {R367TER_SNR_CARRIER1, 0xa1}, - {R367TER_SNR_CARRIER2, 0x9a}, - {R367TER_PPM_CPAMP, 0x2c}, - {R367TER_TSM_AP0, 0x00}, - {R367TER_TSM_AP1, 0x00}, - {R367TER_TSM_AP2 , 0x00}, - {R367TER_TSM_AP3, 0x00}, - {R367TER_TSM_AP4, 0x00}, - {R367TER_TSM_AP5, 0x00}, - {R367TER_TSM_AP6, 0x00}, - {R367TER_TSM_AP7, 0x00}, - {R367TER_TSTRES, 0x00}, - {R367TER_ANACTRL, 0x0D},/* PLL stoped, restart at init!!! */ - {R367TER_TSTBUS, 0x00}, - {R367TER_TSTRATE, 0x00}, - {R367TER_CONSTMODE, 0x01}, - {R367TER_CONSTCARR1, 0x00}, - {R367TER_CONSTCARR2, 0x00}, - {R367TER_ICONSTEL, 0x0a}, - {R367TER_QCONSTEL, 0x15}, - {R367TER_TSTBISTRES0, 0x00}, - {R367TER_TSTBISTRES1, 0x00}, - {R367TER_TSTBISTRES2, 0x28}, - {R367TER_TSTBISTRES3, 0x00}, - {R367TER_RF_AGC1, 0xff}, - {R367TER_RF_AGC2, 0x83}, - {R367TER_ANADIGCTRL, 0x19}, - {R367TER_PLLMDIV, 0x01},/* for xc5000; was 0x0c */ - {R367TER_PLLNDIV, 0x06},/* for xc5000; was 0x55 */ - {R367TER_PLLSETUP, 0x18}, - {R367TER_DUAL_AD12, 0x0C},/* for xc5000 AGC voltage 1.6V */ - {R367TER_TSTBIST, 0x00}, - {R367TER_PAD_COMP_CTRL, 0x00}, - {R367TER_PAD_COMP_WR, 0x00}, - {R367TER_PAD_COMP_RD, 0xe0}, - {R367TER_SYR_TARGET_FFTADJT_MSB, 0x00}, - {R367TER_SYR_TARGET_FFTADJT_LSB, 0x00}, - {R367TER_SYR_TARGET_CHCADJT_MSB, 0x00}, - {R367TER_SYR_TARGET_CHCADJT_LSB, 0x00}, - {R367TER_SYR_FLAG, 0x00}, - {R367TER_CRL_TARGET1, 0x00}, - {R367TER_CRL_TARGET2, 0x00}, - {R367TER_CRL_TARGET3, 0x00}, - {R367TER_CRL_TARGET4, 0x00}, - {R367TER_CRL_FLAG, 0x00}, - {R367TER_TRL_TARGET1, 0x00}, - {R367TER_TRL_TARGET2, 0x00}, - {R367TER_TRL_CHC, 0x00}, - {R367TER_CHC_SNR_TARG, 0x00}, - {R367TER_TOP_TRACK, 0x00}, - {R367TER_TRACKER_FREE1, 0x00}, - {R367TER_ERROR_CRL1, 0x00}, - {R367TER_ERROR_CRL2, 0x00}, - {R367TER_ERROR_CRL3, 0x00}, - {R367TER_ERROR_CRL4, 0x00}, - {R367TER_DEC_NCO1, 0x2c}, - {R367TER_DEC_NCO2, 0x0f}, - {R367TER_DEC_NCO3, 0x20}, - {R367TER_SNR, 0xf1}, - {R367TER_SYR_FFTADJ1, 0x00}, - {R367TER_SYR_FFTADJ2, 0x00}, - {R367TER_SYR_CHCADJ1, 0x00}, - {R367TER_SYR_CHCADJ2, 0x00}, - {R367TER_SYR_OFF, 0x00}, - {R367TER_PPM_OFFSET1, 0x00}, - {R367TER_PPM_OFFSET2, 0x03}, - {R367TER_TRACKER_FREE2, 0x00}, - {R367TER_DEBG_LT10, 0x00}, - {R367TER_DEBG_LT11, 0x00}, - {R367TER_DEBG_LT12, 0x00}, - {R367TER_DEBG_LT13, 0x00}, - {R367TER_DEBG_LT14, 0x00}, - {R367TER_DEBG_LT15, 0x00}, - {R367TER_DEBG_LT16, 0x00}, - {R367TER_DEBG_LT17, 0x00}, - {R367TER_DEBG_LT18, 0x00}, - {R367TER_DEBG_LT19, 0x00}, - {R367TER_DEBG_LT1A, 0x00}, - {R367TER_DEBG_LT1B, 0x00}, - {R367TER_DEBG_LT1C, 0x00}, - {R367TER_DEBG_LT1D, 0x00}, - {R367TER_DEBG_LT1E, 0x00}, - {R367TER_DEBG_LT1F, 0x00}, - {R367TER_RCCFGH, 0x00}, - {R367TER_RCCFGM, 0x00}, - {R367TER_RCCFGL, 0x00}, - {R367TER_RCINSDELH, 0x00}, - {R367TER_RCINSDELM, 0x00}, - {R367TER_RCINSDELL, 0x00}, - {R367TER_RCSTATUS, 0x00}, - {R367TER_RCSPEED, 0x6f}, - {R367TER_RCDEBUGM, 0xe7}, - {R367TER_RCDEBUGL, 0x9b}, - {R367TER_RCOBSCFG, 0x00}, - {R367TER_RCOBSM, 0x00}, - {R367TER_RCOBSL, 0x00}, - {R367TER_RCFECSPY, 0x00}, - {R367TER_RCFSPYCFG, 0x00}, - {R367TER_RCFSPYDATA, 0x00}, - {R367TER_RCFSPYOUT, 0x00}, - {R367TER_RCFSTATUS, 0x00}, - {R367TER_RCFGOODPACK, 0x00}, - {R367TER_RCFPACKCNT, 0x00}, - {R367TER_RCFSPYMISC, 0x00}, - {R367TER_RCFBERCPT4, 0x00}, - {R367TER_RCFBERCPT3, 0x00}, - {R367TER_RCFBERCPT2, 0x00}, - {R367TER_RCFBERCPT1, 0x00}, - {R367TER_RCFBERCPT0, 0x00}, - {R367TER_RCFBERERR2, 0x00}, - {R367TER_RCFBERERR1, 0x00}, - {R367TER_RCFBERERR0, 0x00}, - {R367TER_RCFSTATESM, 0x00}, - {R367TER_RCFSTATESL, 0x00}, - {R367TER_RCFSPYBER, 0x00}, - {R367TER_RCFSPYDISTM, 0x00}, - {R367TER_RCFSPYDISTL, 0x00}, - {R367TER_RCFSPYOBS7, 0x00}, - {R367TER_RCFSPYOBS6, 0x00}, - {R367TER_RCFSPYOBS5, 0x00}, - {R367TER_RCFSPYOBS4, 0x00}, - {R367TER_RCFSPYOBS3, 0x00}, - {R367TER_RCFSPYOBS2, 0x00}, - {R367TER_RCFSPYOBS1, 0x00}, - {R367TER_RCFSPYOBS0, 0x00}, - {R367TER_TSGENERAL, 0x00}, - {R367TER_RC1SPEED, 0x6f}, - {R367TER_TSGSTATUS, 0x18}, - {R367TER_FECM, 0x01}, - {R367TER_VTH12, 0xff}, - {R367TER_VTH23, 0xa1}, - {R367TER_VTH34, 0x64}, - {R367TER_VTH56, 0x40}, - {R367TER_VTH67, 0x00}, - {R367TER_VTH78, 0x2c}, - {R367TER_VITCURPUN, 0x12}, - {R367TER_VERROR, 0x01}, - {R367TER_PRVIT, 0x3f}, - {R367TER_VAVSRVIT, 0x00}, - {R367TER_VSTATUSVIT, 0xbd}, - {R367TER_VTHINUSE, 0xa1}, - {R367TER_KDIV12, 0x20}, - {R367TER_KDIV23, 0x40}, - {R367TER_KDIV34, 0x20}, - {R367TER_KDIV56, 0x30}, - {R367TER_KDIV67, 0x00}, - {R367TER_KDIV78, 0x30}, - {R367TER_SIGPOWER, 0x54}, - {R367TER_DEMAPVIT, 0x40}, - {R367TER_VITSCALE, 0x00}, - {R367TER_FFEC1PRG, 0x00}, - {R367TER_FVITCURPUN, 0x12}, - {R367TER_FVERROR, 0x01}, - {R367TER_FVSTATUSVIT, 0xbd}, - {R367TER_DEBUG_LT1, 0x00}, - {R367TER_DEBUG_LT2, 0x00}, - {R367TER_DEBUG_LT3, 0x00}, - {R367TER_TSTSFMET, 0x00}, - {R367TER_SELOUT, 0x00}, - {R367TER_TSYNC, 0x00}, - {R367TER_TSTERR, 0x00}, - {R367TER_TSFSYNC, 0x00}, - {R367TER_TSTSFERR, 0x00}, - {R367TER_TSTTSSF1, 0x01}, - {R367TER_TSTTSSF2, 0x1f}, - {R367TER_TSTTSSF3, 0x00}, - {R367TER_TSTTS1, 0x00}, - {R367TER_TSTTS2, 0x1f}, - {R367TER_TSTTS3, 0x01}, - {R367TER_TSTTS4, 0x00}, - {R367TER_TSTTSRC, 0x00}, - {R367TER_TSTTSRS, 0x00}, - {R367TER_TSSTATEM, 0xb0}, - {R367TER_TSSTATEL, 0x40}, - {R367TER_TSCFGH, 0xC0}, - {R367TER_TSCFGM, 0xc0},/* for xc5000; was 0x00 */ - {R367TER_TSCFGL, 0x20}, - {R367TER_TSSYNC, 0x00}, - {R367TER_TSINSDELH, 0x00}, - {R367TER_TSINSDELM, 0x00}, - {R367TER_TSINSDELL, 0x00}, - {R367TER_TSDIVN, 0x03}, - {R367TER_TSDIVPM, 0x00}, - {R367TER_TSDIVPL, 0x00}, - {R367TER_TSDIVQM, 0x00}, - {R367TER_TSDIVQL, 0x00}, - {R367TER_TSDILSTKM, 0x00}, - {R367TER_TSDILSTKL, 0x00}, - {R367TER_TSSPEED, 0x40},/* for xc5000; was 0x6f */ - {R367TER_TSSTATUS, 0x81}, - {R367TER_TSSTATUS2, 0x6a}, - {R367TER_TSBITRATEM, 0x0f}, - {R367TER_TSBITRATEL, 0xc6}, - {R367TER_TSPACKLENM, 0x00}, - {R367TER_TSPACKLENL, 0xfc}, - {R367TER_TSBLOCLENM, 0x0a}, - {R367TER_TSBLOCLENL, 0x80}, - {R367TER_TSDLYH, 0x90}, - {R367TER_TSDLYM, 0x68}, - {R367TER_TSDLYL, 0x01}, - {R367TER_TSNPDAV, 0x00}, - {R367TER_TSBUFSTATH, 0x00}, - {R367TER_TSBUFSTATM, 0x00}, - {R367TER_TSBUFSTATL, 0x00}, - {R367TER_TSDEBUGM, 0xcf}, - {R367TER_TSDEBUGL, 0x1e}, - {R367TER_TSDLYSETH, 0x00}, - {R367TER_TSDLYSETM, 0x68}, - {R367TER_TSDLYSETL, 0x00}, - {R367TER_TSOBSCFG, 0x00}, - {R367TER_TSOBSM, 0x47}, - {R367TER_TSOBSL, 0x1f}, - {R367TER_ERRCTRL1, 0x95}, - {R367TER_ERRCNT1H, 0x80}, - {R367TER_ERRCNT1M, 0x00}, - {R367TER_ERRCNT1L, 0x00}, - {R367TER_ERRCTRL2, 0x95}, - {R367TER_ERRCNT2H, 0x00}, - {R367TER_ERRCNT2M, 0x00}, - {R367TER_ERRCNT2L, 0x00}, - {R367TER_FECSPY, 0x88}, - {R367TER_FSPYCFG, 0x2c}, - {R367TER_FSPYDATA, 0x3a}, - {R367TER_FSPYOUT, 0x06}, - {R367TER_FSTATUS, 0x61}, - {R367TER_FGOODPACK, 0xff}, - {R367TER_FPACKCNT, 0xff}, - {R367TER_FSPYMISC, 0x66}, - {R367TER_FBERCPT4, 0x00}, - {R367TER_FBERCPT3, 0x00}, - {R367TER_FBERCPT2, 0x36}, - {R367TER_FBERCPT1, 0x36}, - {R367TER_FBERCPT0, 0x14}, - {R367TER_FBERERR2, 0x00}, - {R367TER_FBERERR1, 0x03}, - {R367TER_FBERERR0, 0x28}, - {R367TER_FSTATESM, 0x00}, - {R367TER_FSTATESL, 0x02}, - {R367TER_FSPYBER, 0x00}, - {R367TER_FSPYDISTM, 0x01}, - {R367TER_FSPYDISTL, 0x9f}, - {R367TER_FSPYOBS7, 0xc9}, - {R367TER_FSPYOBS6, 0x99}, - {R367TER_FSPYOBS5, 0x08}, - {R367TER_FSPYOBS4, 0xec}, - {R367TER_FSPYOBS3, 0x01}, - {R367TER_FSPYOBS2, 0x0f}, - {R367TER_FSPYOBS1, 0xf5}, - {R367TER_FSPYOBS0, 0x08}, - {R367TER_SFDEMAP, 0x40}, - {R367TER_SFERROR, 0x00}, - {R367TER_SFAVSR, 0x30}, - {R367TER_SFECSTATUS, 0xcc}, - {R367TER_SFKDIV12, 0x20}, - {R367TER_SFKDIV23, 0x40}, - {R367TER_SFKDIV34, 0x20}, - {R367TER_SFKDIV56, 0x20}, - {R367TER_SFKDIV67, 0x00}, - {R367TER_SFKDIV78, 0x20}, - {R367TER_SFDILSTKM, 0x00}, - {R367TER_SFDILSTKL, 0x00}, - {R367TER_SFSTATUS, 0xb5}, - {R367TER_SFDLYH, 0x90}, - {R367TER_SFDLYM, 0x60}, - {R367TER_SFDLYL, 0x01}, - {R367TER_SFDLYSETH, 0xc0}, - {R367TER_SFDLYSETM, 0x60}, - {R367TER_SFDLYSETL, 0x00}, - {R367TER_SFOBSCFG, 0x00}, - {R367TER_SFOBSM, 0x47}, - {R367TER_SFOBSL, 0x05}, - {R367TER_SFECINFO, 0x40}, - {R367TER_SFERRCTRL, 0x74}, - {R367TER_SFERRCNTH, 0x80}, - {R367TER_SFERRCNTM , 0x00}, - {R367TER_SFERRCNTL, 0x00}, - {R367TER_SYMBRATEM, 0x2f}, - {R367TER_SYMBRATEL, 0x50}, - {R367TER_SYMBSTATUS, 0x7f}, - {R367TER_SYMBCFG, 0x00}, - {R367TER_SYMBFIFOM, 0xf4}, - {R367TER_SYMBFIFOL, 0x0d}, - {R367TER_SYMBOFFSM, 0xf0}, - {R367TER_SYMBOFFSL, 0x2d}, - {R367TER_DEBUG_LT4, 0x00}, - {R367TER_DEBUG_LT5, 0x00}, - {R367TER_DEBUG_LT6, 0x00}, - {R367TER_DEBUG_LT7, 0x00}, - {R367TER_DEBUG_LT8, 0x00}, - {R367TER_DEBUG_LT9, 0x00}, -}; - -#define RF_LOOKUP_TABLE_SIZE 31 -#define RF_LOOKUP_TABLE2_SIZE 16 -/* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/ -s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = { - {/*AGC1*/ - 48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 80, 83, 85, 88, - }, {/*RF(dbm)*/ - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, - 49, 50, 52, 53, 54, 55, 56, - } -}; -/* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/ -s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = { - {/*AGC2*/ - 28, 29, 31, 32, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, - }, {/*RF(dbm)*/ - 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, - } -}; - -static struct st_register def0367cab[STV0367CAB_NBREGS] = { - {R367CAB_ID, 0x60}, - {R367CAB_I2CRPT, 0xa0}, - /*{R367CAB_I2CRPT, 0x22},*/ - {R367CAB_TOPCTRL, 0x10}, - {R367CAB_IOCFG0, 0x80}, - {R367CAB_DAC0R, 0x00}, - {R367CAB_IOCFG1, 0x00}, - {R367CAB_DAC1R, 0x00}, - {R367CAB_IOCFG2, 0x00}, - {R367CAB_SDFR, 0x00}, - {R367CAB_AUX_CLK, 0x00}, - {R367CAB_FREESYS1, 0x00}, - {R367CAB_FREESYS2, 0x00}, - {R367CAB_FREESYS3, 0x00}, - {R367CAB_GPIO_CFG, 0x55}, - {R367CAB_GPIO_CMD, 0x01}, - {R367CAB_TSTRES, 0x00}, - {R367CAB_ANACTRL, 0x0d},/* was 0x00 need to check - I.M.L.*/ - {R367CAB_TSTBUS, 0x00}, - {R367CAB_RF_AGC1, 0xea}, - {R367CAB_RF_AGC2, 0x82}, - {R367CAB_ANADIGCTRL, 0x0b}, - {R367CAB_PLLMDIV, 0x01}, - {R367CAB_PLLNDIV, 0x08}, - {R367CAB_PLLSETUP, 0x18}, - {R367CAB_DUAL_AD12, 0x0C}, /* for xc5000 AGC voltage 1.6V */ - {R367CAB_TSTBIST, 0x00}, - {R367CAB_CTRL_1, 0x00}, - {R367CAB_CTRL_2, 0x03}, - {R367CAB_IT_STATUS1, 0x2b}, - {R367CAB_IT_STATUS2, 0x08}, - {R367CAB_IT_EN1, 0x00}, - {R367CAB_IT_EN2, 0x00}, - {R367CAB_CTRL_STATUS, 0x04}, - {R367CAB_TEST_CTL, 0x00}, - {R367CAB_AGC_CTL, 0x73}, - {R367CAB_AGC_IF_CFG, 0x50}, - {R367CAB_AGC_RF_CFG, 0x00}, - {R367CAB_AGC_PWM_CFG, 0x03}, - {R367CAB_AGC_PWR_REF_L, 0x5a}, - {R367CAB_AGC_PWR_REF_H, 0x00}, - {R367CAB_AGC_RF_TH_L, 0xff}, - {R367CAB_AGC_RF_TH_H, 0x07}, - {R367CAB_AGC_IF_LTH_L, 0x00}, - {R367CAB_AGC_IF_LTH_H, 0x08}, - {R367CAB_AGC_IF_HTH_L, 0xff}, - {R367CAB_AGC_IF_HTH_H, 0x07}, - {R367CAB_AGC_PWR_RD_L, 0xa0}, - {R367CAB_AGC_PWR_RD_M, 0xe9}, - {R367CAB_AGC_PWR_RD_H, 0x03}, - {R367CAB_AGC_PWM_IFCMD_L, 0xe4}, - {R367CAB_AGC_PWM_IFCMD_H, 0x00}, - {R367CAB_AGC_PWM_RFCMD_L, 0xff}, - {R367CAB_AGC_PWM_RFCMD_H, 0x07}, - {R367CAB_IQDEM_CFG, 0x01}, - {R367CAB_MIX_NCO_LL, 0x22}, - {R367CAB_MIX_NCO_HL, 0x96}, - {R367CAB_MIX_NCO_HH, 0x55}, - {R367CAB_SRC_NCO_LL, 0xff}, - {R367CAB_SRC_NCO_LH, 0x0c}, - {R367CAB_SRC_NCO_HL, 0xf5}, - {R367CAB_SRC_NCO_HH, 0x20}, - {R367CAB_IQDEM_GAIN_SRC_L, 0x06}, - {R367CAB_IQDEM_GAIN_SRC_H, 0x01}, - {R367CAB_IQDEM_DCRM_CFG_LL, 0xfe}, - {R367CAB_IQDEM_DCRM_CFG_LH, 0xff}, - {R367CAB_IQDEM_DCRM_CFG_HL, 0x0f}, - {R367CAB_IQDEM_DCRM_CFG_HH, 0x00}, - {R367CAB_IQDEM_ADJ_COEFF0, 0x34}, - {R367CAB_IQDEM_ADJ_COEFF1, 0xae}, - {R367CAB_IQDEM_ADJ_COEFF2, 0x46}, - {R367CAB_IQDEM_ADJ_COEFF3, 0x77}, - {R367CAB_IQDEM_ADJ_COEFF4, 0x96}, - {R367CAB_IQDEM_ADJ_COEFF5, 0x69}, - {R367CAB_IQDEM_ADJ_COEFF6, 0xc7}, - {R367CAB_IQDEM_ADJ_COEFF7, 0x01}, - {R367CAB_IQDEM_ADJ_EN, 0x04}, - {R367CAB_IQDEM_ADJ_AGC_REF, 0x94}, - {R367CAB_ALLPASSFILT1, 0xc9}, - {R367CAB_ALLPASSFILT2, 0x2d}, - {R367CAB_ALLPASSFILT3, 0xa3}, - {R367CAB_ALLPASSFILT4, 0xfb}, - {R367CAB_ALLPASSFILT5, 0xf6}, - {R367CAB_ALLPASSFILT6, 0x45}, - {R367CAB_ALLPASSFILT7, 0x6f}, - {R367CAB_ALLPASSFILT8, 0x7e}, - {R367CAB_ALLPASSFILT9, 0x05}, - {R367CAB_ALLPASSFILT10, 0x0a}, - {R367CAB_ALLPASSFILT11, 0x51}, - {R367CAB_TRL_AGC_CFG, 0x20}, - {R367CAB_TRL_LPF_CFG, 0x28}, - {R367CAB_TRL_LPF_ACQ_GAIN, 0x44}, - {R367CAB_TRL_LPF_TRK_GAIN, 0x22}, - {R367CAB_TRL_LPF_OUT_GAIN, 0x03}, - {R367CAB_TRL_LOCKDET_LTH, 0x04}, - {R367CAB_TRL_LOCKDET_HTH, 0x11}, - {R367CAB_TRL_LOCKDET_TRGVAL, 0x20}, - {R367CAB_IQ_QAM, 0x01}, - {R367CAB_FSM_STATE, 0xa0}, - {R367CAB_FSM_CTL, 0x08}, - {R367CAB_FSM_STS, 0x0c}, - {R367CAB_FSM_SNR0_HTH, 0x00}, - {R367CAB_FSM_SNR1_HTH, 0x00}, - {R367CAB_FSM_SNR2_HTH, 0x23},/* 0x00 */ - {R367CAB_FSM_SNR0_LTH, 0x00}, - {R367CAB_FSM_SNR1_LTH, 0x00}, - {R367CAB_FSM_EQA1_HTH, 0x00}, - {R367CAB_FSM_TEMPO, 0x32}, - {R367CAB_FSM_CONFIG, 0x03}, - {R367CAB_EQU_I_TESTTAP_L, 0x11}, - {R367CAB_EQU_I_TESTTAP_M, 0x00}, - {R367CAB_EQU_I_TESTTAP_H, 0x00}, - {R367CAB_EQU_TESTAP_CFG, 0x00}, - {R367CAB_EQU_Q_TESTTAP_L, 0xff}, - {R367CAB_EQU_Q_TESTTAP_M, 0x00}, - {R367CAB_EQU_Q_TESTTAP_H, 0x00}, - {R367CAB_EQU_TAP_CTRL, 0x00}, - {R367CAB_EQU_CTR_CRL_CONTROL_L, 0x11}, - {R367CAB_EQU_CTR_CRL_CONTROL_H, 0x05}, - {R367CAB_EQU_CTR_HIPOW_L, 0x00}, - {R367CAB_EQU_CTR_HIPOW_H, 0x00}, - {R367CAB_EQU_I_EQU_LO, 0xef}, - {R367CAB_EQU_I_EQU_HI, 0x00}, - {R367CAB_EQU_Q_EQU_LO, 0xee}, - {R367CAB_EQU_Q_EQU_HI, 0x00}, - {R367CAB_EQU_MAPPER, 0xc5}, - {R367CAB_EQU_SWEEP_RATE, 0x80}, - {R367CAB_EQU_SNR_LO, 0x64}, - {R367CAB_EQU_SNR_HI, 0x03}, - {R367CAB_EQU_GAMMA_LO, 0x00}, - {R367CAB_EQU_GAMMA_HI, 0x00}, - {R367CAB_EQU_ERR_GAIN, 0x36}, - {R367CAB_EQU_RADIUS, 0xaa}, - {R367CAB_EQU_FFE_MAINTAP, 0x00}, - {R367CAB_EQU_FFE_LEAKAGE, 0x63}, - {R367CAB_EQU_FFE_MAINTAP_POS, 0xdf}, - {R367CAB_EQU_GAIN_WIDE, 0x88}, - {R367CAB_EQU_GAIN_NARROW, 0x41}, - {R367CAB_EQU_CTR_LPF_GAIN, 0xd1}, - {R367CAB_EQU_CRL_LPF_GAIN, 0xa7}, - {R367CAB_EQU_GLOBAL_GAIN, 0x06}, - {R367CAB_EQU_CRL_LD_SEN, 0x85}, - {R367CAB_EQU_CRL_LD_VAL, 0xe2}, - {R367CAB_EQU_CRL_TFR, 0x20}, - {R367CAB_EQU_CRL_BISTH_LO, 0x00}, - {R367CAB_EQU_CRL_BISTH_HI, 0x00}, - {R367CAB_EQU_SWEEP_RANGE_LO, 0x00}, - {R367CAB_EQU_SWEEP_RANGE_HI, 0x00}, - {R367CAB_EQU_CRL_LIMITER, 0x40}, - {R367CAB_EQU_MODULUS_MAP, 0x90}, - {R367CAB_EQU_PNT_GAIN, 0xa7}, - {R367CAB_FEC_AC_CTR_0, 0x16}, - {R367CAB_FEC_AC_CTR_1, 0x0b}, - {R367CAB_FEC_AC_CTR_2, 0x88}, - {R367CAB_FEC_AC_CTR_3, 0x02}, - {R367CAB_FEC_STATUS, 0x12}, - {R367CAB_RS_COUNTER_0, 0x7d}, - {R367CAB_RS_COUNTER_1, 0xd0}, - {R367CAB_RS_COUNTER_2, 0x19}, - {R367CAB_RS_COUNTER_3, 0x0b}, - {R367CAB_RS_COUNTER_4, 0xa3}, - {R367CAB_RS_COUNTER_5, 0x00}, - {R367CAB_BERT_0, 0x01}, - {R367CAB_BERT_1, 0x25}, - {R367CAB_BERT_2, 0x41}, - {R367CAB_BERT_3, 0x39}, - {R367CAB_OUTFORMAT_0, 0xc2}, - {R367CAB_OUTFORMAT_1, 0x22}, - {R367CAB_SMOOTHER_2, 0x28}, - {R367CAB_TSMF_CTRL_0, 0x01}, - {R367CAB_TSMF_CTRL_1, 0xc6}, - {R367CAB_TSMF_CTRL_3, 0x43}, - {R367CAB_TS_ON_ID_0, 0x00}, - {R367CAB_TS_ON_ID_1, 0x00}, - {R367CAB_TS_ON_ID_2, 0x00}, - {R367CAB_TS_ON_ID_3, 0x00}, - {R367CAB_RE_STATUS_0, 0x00}, - {R367CAB_RE_STATUS_1, 0x00}, - {R367CAB_RE_STATUS_2, 0x00}, - {R367CAB_RE_STATUS_3, 0x00}, - {R367CAB_TS_STATUS_0, 0x00}, - {R367CAB_TS_STATUS_1, 0x00}, - {R367CAB_TS_STATUS_2, 0xa0}, - {R367CAB_TS_STATUS_3, 0x00}, - {R367CAB_T_O_ID_0, 0x00}, - {R367CAB_T_O_ID_1, 0x00}, - {R367CAB_T_O_ID_2, 0x00}, - {R367CAB_T_O_ID_3, 0x00}, -}; - -static -int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len) -{ - u8 buf[len + 2]; - struct i2c_msg msg = { - .addr = state->config->demod_address, - .flags = 0, - .buf = buf, - .len = len + 2 - }; - int ret; - - buf[0] = MSB(reg); - buf[1] = LSB(reg); - memcpy(buf + 2, data, len); - - if (i2cdebug) - printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, buf[2]); - - ret = i2c_transfer(state->i2c, &msg, 1); - if (ret != 1) - printk(KERN_ERR "%s: i2c write error!\n", __func__); - - return (ret != 1) ? -EREMOTEIO : 0; -} - -static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data) -{ - return stv0367_writeregs(state, reg, &data, 1); -} - -static u8 stv0367_readreg(struct stv0367_state *state, u16 reg) -{ - u8 b0[] = { 0, 0 }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { - .addr = state->config->demod_address, - .flags = 0, - .buf = b0, - .len = 2 - }, { - .addr = state->config->demod_address, - .flags = I2C_M_RD, - .buf = b1, - .len = 1 - } - }; - int ret; - - b0[0] = MSB(reg); - b0[1] = LSB(reg); - - ret = i2c_transfer(state->i2c, msg, 2); - if (ret != 2) - printk(KERN_ERR "%s: i2c read error\n", __func__); - - if (i2cdebug) - printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, b1[0]); - - return b1[0]; -} - -static void extract_mask_pos(u32 label, u8 *mask, u8 *pos) -{ - u8 position = 0, i = 0; - - (*mask) = label & 0xff; - - while ((position == 0) && (i < 8)) { - position = ((*mask) >> i) & 0x01; - i++; - } - - (*pos) = (i - 1); -} - -static void stv0367_writebits(struct stv0367_state *state, u32 label, u8 val) -{ - u8 reg, mask, pos; - - reg = stv0367_readreg(state, (label >> 16) & 0xffff); - extract_mask_pos(label, &mask, &pos); - - val = mask & (val << pos); - - reg = (reg & (~mask)) | val; - stv0367_writereg(state, (label >> 16) & 0xffff, reg); - -} - -static void stv0367_setbits(u8 *reg, u32 label, u8 val) -{ - u8 mask, pos; - - extract_mask_pos(label, &mask, &pos); - - val = mask & (val << pos); - - (*reg) = ((*reg) & (~mask)) | val; -} - -static u8 stv0367_readbits(struct stv0367_state *state, u32 label) -{ - u8 val = 0xff; - u8 mask, pos; - - extract_mask_pos(label, &mask, &pos); - - val = stv0367_readreg(state, label >> 16); - val = (val & mask) >> pos; - - return val; -} - -u8 stv0367_getbits(u8 reg, u32 label) -{ - u8 mask, pos; - - extract_mask_pos(label, &mask, &pos); - - return (reg & mask) >> pos; -} - -static int stv0367ter_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct stv0367_state *state = fe->demodulator_priv; - u8 tmp = stv0367_readreg(state, R367TER_I2CRPT); - - dprintk("%s:\n", __func__); - - if (enable) { - stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 0); - stv0367_setbits(&tmp, F367TER_I2CT_ON, 1); - } else { - stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 1); - stv0367_setbits(&tmp, F367TER_I2CT_ON, 0); - } - - stv0367_writereg(state, R367TER_I2CRPT, tmp); - - return 0; -} - -static u32 stv0367_get_tuner_freq(struct dvb_frontend *fe) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - u32 freq = 0; - int err = 0; - - dprintk("%s:\n", __func__); - - - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->get_frequency) { - err = tuner_ops->get_frequency(fe, &freq); - if (err < 0) { - printk(KERN_ERR "%s: Invalid parameter\n", __func__); - return err; - } - - dprintk("%s: frequency=%d\n", __func__, freq); - - } else - return -1; - - return freq; -} - -static u16 CellsCoeffs_8MHz_367cofdm[3][6][5] = { - { - {0x10EF, 0xE205, 0x10EF, 0xCE49, 0x6DA7}, /* CELL 1 COEFFS 27M*/ - {0x2151, 0xc557, 0x2151, 0xc705, 0x6f93}, /* CELL 2 COEFFS */ - {0x2503, 0xc000, 0x2503, 0xc375, 0x7194}, /* CELL 3 COEFFS */ - {0x20E9, 0xca94, 0x20e9, 0xc153, 0x7194}, /* CELL 4 COEFFS */ - {0x06EF, 0xF852, 0x06EF, 0xC057, 0x7207}, /* CELL 5 COEFFS */ - {0x0000, 0x0ECC, 0x0ECC, 0x0000, 0x3647} /* CELL 6 COEFFS */ - }, { - {0x10A0, 0xE2AF, 0x10A1, 0xCE76, 0x6D6D}, /* CELL 1 COEFFS 25M*/ - {0x20DC, 0xC676, 0x20D9, 0xC80A, 0x6F29}, - {0x2532, 0xC000, 0x251D, 0xC391, 0x706F}, - {0x1F7A, 0xCD2B, 0x2032, 0xC15E, 0x711F}, - {0x0698, 0xFA5E, 0x0568, 0xC059, 0x7193}, - {0x0000, 0x0918, 0x149C, 0x0000, 0x3642} /* CELL 6 COEFFS */ - }, { - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */ - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000} - } -}; - -static u16 CellsCoeffs_7MHz_367cofdm[3][6][5] = { - { - {0x12CA, 0xDDAF, 0x12CA, 0xCCEB, 0x6FB1}, /* CELL 1 COEFFS 27M*/ - {0x2329, 0xC000, 0x2329, 0xC6B0, 0x725F}, /* CELL 2 COEFFS */ - {0x2394, 0xC000, 0x2394, 0xC2C7, 0x7410}, /* CELL 3 COEFFS */ - {0x251C, 0xC000, 0x251C, 0xC103, 0x74D9}, /* CELL 4 COEFFS */ - {0x0804, 0xF546, 0x0804, 0xC040, 0x7544}, /* CELL 5 COEFFS */ - {0x0000, 0x0CD9, 0x0CD9, 0x0000, 0x370A} /* CELL 6 COEFFS */ - }, { - {0x1285, 0xDE47, 0x1285, 0xCD17, 0x6F76}, /*25M*/ - {0x234C, 0xC000, 0x2348, 0xC6DA, 0x7206}, - {0x23B4, 0xC000, 0x23AC, 0xC2DB, 0x73B3}, - {0x253D, 0xC000, 0x25B6, 0xC10B, 0x747F}, - {0x0721, 0xF79C, 0x065F, 0xC041, 0x74EB}, - {0x0000, 0x08FA, 0x1162, 0x0000, 0x36FF} - }, { - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */ - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000} - } -}; - -static u16 CellsCoeffs_6MHz_367cofdm[3][6][5] = { - { - {0x1699, 0xD5B8, 0x1699, 0xCBC3, 0x713B}, /* CELL 1 COEFFS 27M*/ - {0x2245, 0xC000, 0x2245, 0xC568, 0x74D5}, /* CELL 2 COEFFS */ - {0x227F, 0xC000, 0x227F, 0xC1FC, 0x76C6}, /* CELL 3 COEFFS */ - {0x235E, 0xC000, 0x235E, 0xC0A7, 0x778A}, /* CELL 4 COEFFS */ - {0x0ECB, 0xEA0B, 0x0ECB, 0xC027, 0x77DD}, /* CELL 5 COEFFS */ - {0x0000, 0x0B68, 0x0B68, 0x0000, 0xC89A}, /* CELL 6 COEFFS */ - }, { - {0x1655, 0xD64E, 0x1658, 0xCBEF, 0x70FE}, /*25M*/ - {0x225E, 0xC000, 0x2256, 0xC589, 0x7489}, - {0x2293, 0xC000, 0x2295, 0xC209, 0x767E}, - {0x2377, 0xC000, 0x23AA, 0xC0AB, 0x7746}, - {0x0DC7, 0xEBC8, 0x0D07, 0xC027, 0x7799}, - {0x0000, 0x0888, 0x0E9C, 0x0000, 0x3757} - - }, { - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */ - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - {0x0000, 0x0000, 0x0000, 0x0000, 0x0000} - } -}; - -static u32 stv0367ter_get_mclk(struct stv0367_state *state, u32 ExtClk_Hz) -{ - u32 mclk_Hz = 0; /* master clock frequency (Hz) */ - u32 m, n, p; - - dprintk("%s:\n", __func__); - - if (stv0367_readbits(state, F367TER_BYPASS_PLLXN) == 0) { - n = (u32)stv0367_readbits(state, F367TER_PLL_NDIV); - if (n == 0) - n = n + 1; - - m = (u32)stv0367_readbits(state, F367TER_PLL_MDIV); - if (m == 0) - m = m + 1; - - p = (u32)stv0367_readbits(state, F367TER_PLL_PDIV); - if (p > 5) - p = 5; - - mclk_Hz = ((ExtClk_Hz / 2) * n) / (m * (1 << p)); - - dprintk("N=%d M=%d P=%d mclk_Hz=%d ExtClk_Hz=%d\n", - n, m, p, mclk_Hz, ExtClk_Hz); - } else - mclk_Hz = ExtClk_Hz; - - dprintk("%s: mclk_Hz=%d\n", __func__, mclk_Hz); - - return mclk_Hz; -} - -static int stv0367ter_filt_coeff_init(struct stv0367_state *state, - u16 CellsCoeffs[3][6][5], u32 DemodXtal) -{ - int i, j, k, freq; - - dprintk("%s:\n", __func__); - - freq = stv0367ter_get_mclk(state, DemodXtal); - - if (freq == 53125000) - k = 1; /* equivalent to Xtal 25M on 362*/ - else if (freq == 54000000) - k = 0; /* equivalent to Xtal 27M on 362*/ - else if (freq == 52500000) - k = 2; /* equivalent to Xtal 30M on 362*/ - else - return 0; - - for (i = 1; i <= 6; i++) { - stv0367_writebits(state, F367TER_IIR_CELL_NB, i - 1); - - for (j = 1; j <= 5; j++) { - stv0367_writereg(state, - (R367TER_IIRCX_COEFF1_MSB + 2 * (j - 1)), - MSB(CellsCoeffs[k][i-1][j-1])); - stv0367_writereg(state, - (R367TER_IIRCX_COEFF1_LSB + 2 * (j - 1)), - LSB(CellsCoeffs[k][i-1][j-1])); - } - } - - return 1; - -} - -static void stv0367ter_agc_iir_lock_detect_set(struct stv0367_state *state) -{ - dprintk("%s:\n", __func__); - - stv0367_writebits(state, F367TER_LOCK_DETECT_LSB, 0x00); - - /* Lock detect 1 */ - stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x00); - stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06); - stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04); - - /* Lock detect 2 */ - stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x01); - stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06); - stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04); - - /* Lock detect 3 */ - stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x02); - stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01); - stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00); - - /* Lock detect 4 */ - stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x03); - stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01); - stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00); - -} - -static int stv0367_iir_filt_init(struct stv0367_state *state, u8 Bandwidth, - u32 DemodXtalValue) -{ - dprintk("%s:\n", __func__); - - stv0367_writebits(state, F367TER_NRST_IIR, 0); - - switch (Bandwidth) { - case 6: - if (!stv0367ter_filt_coeff_init(state, - CellsCoeffs_6MHz_367cofdm, - DemodXtalValue)) - return 0; - break; - case 7: - if (!stv0367ter_filt_coeff_init(state, - CellsCoeffs_7MHz_367cofdm, - DemodXtalValue)) - return 0; - break; - case 8: - if (!stv0367ter_filt_coeff_init(state, - CellsCoeffs_8MHz_367cofdm, - DemodXtalValue)) - return 0; - break; - default: - return 0; - } - - stv0367_writebits(state, F367TER_NRST_IIR, 1); - - return 1; -} - -static void stv0367ter_agc_iir_rst(struct stv0367_state *state) -{ - - u8 com_n; - - dprintk("%s:\n", __func__); - - com_n = stv0367_readbits(state, F367TER_COM_N); - - stv0367_writebits(state, F367TER_COM_N, 0x07); - - stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x00); - stv0367_writebits(state, F367TER_COM_AGC_ON, 0x00); - - stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x01); - stv0367_writebits(state, F367TER_COM_AGC_ON, 0x01); - - stv0367_writebits(state, F367TER_COM_N, com_n); - -} - -static int stv0367ter_duration(s32 mode, int tempo1, int tempo2, int tempo3) -{ - int local_tempo = 0; - switch (mode) { - case 0: - local_tempo = tempo1; - break; - case 1: - local_tempo = tempo2; - break ; - - case 2: - local_tempo = tempo3; - break; - - default: - break; - } - /* msleep(local_tempo); */ - return local_tempo; -} - -static enum -stv0367_ter_signal_type stv0367ter_check_syr(struct stv0367_state *state) -{ - int wd = 100; - unsigned short int SYR_var; - s32 SYRStatus; - - dprintk("%s:\n", __func__); - - SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK); - - while ((!SYR_var) && (wd > 0)) { - usleep_range(2000, 3000); - wd -= 2; - SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK); - } - - if (!SYR_var) - SYRStatus = FE_TER_NOSYMBOL; - else - SYRStatus = FE_TER_SYMBOLOK; - - dprintk("stv0367ter_check_syr SYRStatus %s\n", - SYR_var == 0 ? "No Symbol" : "OK"); - - return SYRStatus; -} - -static enum -stv0367_ter_signal_type stv0367ter_check_cpamp(struct stv0367_state *state, - s32 FFTmode) -{ - - s32 CPAMPvalue = 0, CPAMPStatus, CPAMPMin; - int wd = 0; - - dprintk("%s:\n", __func__); - - switch (FFTmode) { - case 0: /*2k mode*/ - CPAMPMin = 20; - wd = 10; - break; - case 1: /*8k mode*/ - CPAMPMin = 80; - wd = 55; - break; - case 2: /*4k mode*/ - CPAMPMin = 40; - wd = 30; - break; - default: - CPAMPMin = 0xffff; /*drives to NOCPAMP */ - break; - } - - dprintk("%s: CPAMPMin=%d wd=%d\n", __func__, CPAMPMin, wd); - - CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT); - while ((CPAMPvalue < CPAMPMin) && (wd > 0)) { - usleep_range(1000, 2000); - wd -= 1; - CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT); - /*dprintk("CPAMPvalue= %d at wd=%d\n",CPAMPvalue,wd); */ - } - dprintk("******last CPAMPvalue= %d at wd=%d\n", CPAMPvalue, wd); - if (CPAMPvalue < CPAMPMin) { - CPAMPStatus = FE_TER_NOCPAMP; - printk(KERN_ERR "CPAMP failed\n"); - } else { - printk(KERN_ERR "CPAMP OK !\n"); - CPAMPStatus = FE_TER_CPAMPOK; - } - - return CPAMPStatus; -} - -enum -stv0367_ter_signal_type stv0367ter_lock_algo(struct stv0367_state *state) -{ - enum stv0367_ter_signal_type ret_flag; - short int wd, tempo; - u8 try, u_var1 = 0, u_var2 = 0, u_var3 = 0, u_var4 = 0, mode, guard; - u8 tmp, tmp2; - - dprintk("%s:\n", __func__); - - if (state == NULL) - return FE_TER_SWNOK; - - try = 0; - do { - ret_flag = FE_TER_LOCKOK; - - stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); - - if (state->config->if_iq_mode != 0) - stv0367_writebits(state, F367TER_COM_N, 0x07); - - stv0367_writebits(state, F367TER_GUARD, 3);/* suggest 2k 1/4 */ - stv0367_writebits(state, F367TER_MODE, 0); - stv0367_writebits(state, F367TER_SYR_TR_DIS, 0); - usleep_range(5000, 10000); - - stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); - - - if (stv0367ter_check_syr(state) == FE_TER_NOSYMBOL) - return FE_TER_NOSYMBOL; - else { /* - if chip locked on wrong mode first try, - it must lock correctly second try */ - mode = stv0367_readbits(state, F367TER_SYR_MODE); - if (stv0367ter_check_cpamp(state, mode) == - FE_TER_NOCPAMP) { - if (try == 0) - ret_flag = FE_TER_NOCPAMP; - - } - } - - try++; - } while ((try < 10) && (ret_flag != FE_TER_LOCKOK)); - - tmp = stv0367_readreg(state, R367TER_SYR_STAT); - tmp2 = stv0367_readreg(state, R367TER_STATUS); - dprintk("state=%p\n", state); - dprintk("LOCK OK! mode=%d SYR_STAT=0x%x R367TER_STATUS=0x%x\n", - mode, tmp, tmp2); - - tmp = stv0367_readreg(state, R367TER_PRVIT); - tmp2 = stv0367_readreg(state, R367TER_I2CRPT); - dprintk("PRVIT=0x%x I2CRPT=0x%x\n", tmp, tmp2); - - tmp = stv0367_readreg(state, R367TER_GAIN_SRC1); - dprintk("GAIN_SRC1=0x%x\n", tmp); - - if ((mode != 0) && (mode != 1) && (mode != 2)) - return FE_TER_SWNOK; - - /*guard=stv0367_readbits(state,F367TER_SYR_GUARD); */ - - /*supress EPQ auto for SYR_GARD 1/16 or 1/32 - and set channel predictor in automatic */ -#if 0 - switch (guard) { - - case 0: - case 1: - stv0367_writebits(state, F367TER_AUTO_LE_EN, 0); - stv0367_writereg(state, R367TER_CHC_CTL, 0x01); - break; - case 2: - case 3: - stv0367_writebits(state, F367TER_AUTO_LE_EN, 1); - stv0367_writereg(state, R367TER_CHC_CTL, 0x11); - break; - - default: - return FE_TER_SWNOK; - } -#endif - - /*reset fec an reedsolo FOR 367 only*/ - stv0367_writebits(state, F367TER_RST_SFEC, 1); - stv0367_writebits(state, F367TER_RST_REEDSOLO, 1); - usleep_range(1000, 2000); - stv0367_writebits(state, F367TER_RST_SFEC, 0); - stv0367_writebits(state, F367TER_RST_REEDSOLO, 0); - - u_var1 = stv0367_readbits(state, F367TER_LK); - u_var2 = stv0367_readbits(state, F367TER_PRF); - u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK); - /* u_var4=stv0367_readbits(state,F367TER_TSFIFO_LINEOK); */ - - wd = stv0367ter_duration(mode, 125, 500, 250); - tempo = stv0367ter_duration(mode, 4, 16, 8); - - /*while ( ((!u_var1)||(!u_var2)||(!u_var3)||(!u_var4)) && (wd>=0)) */ - while (((!u_var1) || (!u_var2) || (!u_var3)) && (wd >= 0)) { - usleep_range(1000 * tempo, 1000 * (tempo + 1)); - wd -= tempo; - u_var1 = stv0367_readbits(state, F367TER_LK); - u_var2 = stv0367_readbits(state, F367TER_PRF); - u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK); - /*u_var4=stv0367_readbits(state, F367TER_TSFIFO_LINEOK); */ - } - - if (!u_var1) - return FE_TER_NOLOCK; - - - if (!u_var2) - return FE_TER_NOPRFOUND; - - if (!u_var3) - return FE_TER_NOTPS; - - guard = stv0367_readbits(state, F367TER_SYR_GUARD); - stv0367_writereg(state, R367TER_CHC_CTL, 0x11); - switch (guard) { - case 0: - case 1: - stv0367_writebits(state, F367TER_AUTO_LE_EN, 0); - /*stv0367_writereg(state,R367TER_CHC_CTL, 0x1);*/ - stv0367_writebits(state, F367TER_SYR_FILTER, 0); - break; - case 2: - case 3: - stv0367_writebits(state, F367TER_AUTO_LE_EN, 1); - /*stv0367_writereg(state,R367TER_CHC_CTL, 0x11);*/ - stv0367_writebits(state, F367TER_SYR_FILTER, 1); - break; - - default: - return FE_TER_SWNOK; - } - - /* apply Sfec workaround if 8K 64QAM CR!=1/2*/ - if ((stv0367_readbits(state, F367TER_TPS_CONST) == 2) && - (mode == 1) && - (stv0367_readbits(state, F367TER_TPS_HPCODE) != 0)) { - stv0367_writereg(state, R367TER_SFDLYSETH, 0xc0); - stv0367_writereg(state, R367TER_SFDLYSETM, 0x60); - stv0367_writereg(state, R367TER_SFDLYSETL, 0x0); - } else - stv0367_writereg(state, R367TER_SFDLYSETH, 0x0); - - wd = stv0367ter_duration(mode, 125, 500, 250); - u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK); - - while ((!u_var4) && (wd >= 0)) { - usleep_range(1000 * tempo, 1000 * (tempo + 1)); - wd -= tempo; - u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK); - } - - if (!u_var4) - return FE_TER_NOLOCK; - - /* for 367 leave COM_N at 0x7 for IQ_mode*/ - /*if(ter_state->if_iq_mode!=FE_TER_NORMAL_IF_TUNER) { - tempo=0; - while ((stv0367_readbits(state,F367TER_COM_USEGAINTRK)!=1) && - (stv0367_readbits(state,F367TER_COM_AGCLOCK)!=1)&&(tempo<100)) { - ChipWaitOrAbort(state,1); - tempo+=1; - } - - stv0367_writebits(state,F367TER_COM_N,0x17); - } */ - - stv0367_writebits(state, F367TER_SYR_TR_DIS, 1); - - dprintk("FE_TER_LOCKOK !!!\n"); - - return FE_TER_LOCKOK; - -} - -static void stv0367ter_set_ts_mode(struct stv0367_state *state, - enum stv0367_ts_mode PathTS) -{ - - dprintk("%s:\n", __func__); - - if (state == NULL) - return; - - stv0367_writebits(state, F367TER_TS_DIS, 0); - switch (PathTS) { - default: - /*for removing warning :default we can assume in parallel mode*/ - case STV0367_PARALLEL_PUNCT_CLOCK: - stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 0); - stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 0); - break; - case STV0367_SERIAL_PUNCT_CLOCK: - stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 1); - stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 1); - break; - } -} - -static void stv0367ter_set_clk_pol(struct stv0367_state *state, - enum stv0367_clk_pol clock) -{ - - dprintk("%s:\n", __func__); - - if (state == NULL) - return; - - switch (clock) { - case STV0367_RISINGEDGE_CLOCK: - stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 1); - break; - case STV0367_FALLINGEDGE_CLOCK: - stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0); - break; - /*case FE_TER_CLOCK_POLARITY_DEFAULT:*/ - default: - stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0); - break; - } -} - -#if 0 -static void stv0367ter_core_sw(struct stv0367_state *state) -{ - - dprintk("%s:\n", __func__); - - stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); - stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); - msleep(350); -} -#endif -static int stv0367ter_standby(struct dvb_frontend *fe, u8 standby_on) -{ - struct stv0367_state *state = fe->demodulator_priv; - - dprintk("%s:\n", __func__); - - if (standby_on) { - stv0367_writebits(state, F367TER_STDBY, 1); - stv0367_writebits(state, F367TER_STDBY_FEC, 1); - stv0367_writebits(state, F367TER_STDBY_CORE, 1); - } else { - stv0367_writebits(state, F367TER_STDBY, 0); - stv0367_writebits(state, F367TER_STDBY_FEC, 0); - stv0367_writebits(state, F367TER_STDBY_CORE, 0); - } - - return 0; -} - -static int stv0367ter_sleep(struct dvb_frontend *fe) -{ - return stv0367ter_standby(fe, 1); -} - -int stv0367ter_init(struct dvb_frontend *fe) -{ - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367ter_state *ter_state = state->ter_state; - int i; - - dprintk("%s:\n", __func__); - - ter_state->pBER = 0; - - for (i = 0; i < STV0367TER_NBREGS; i++) - stv0367_writereg(state, def0367ter[i].addr, - def0367ter[i].value); - - switch (state->config->xtal) { - /*set internal freq to 53.125MHz */ - case 25000000: - stv0367_writereg(state, R367TER_PLLMDIV, 0xa); - stv0367_writereg(state, R367TER_PLLNDIV, 0x55); - stv0367_writereg(state, R367TER_PLLSETUP, 0x18); - break; - default: - case 27000000: - dprintk("FE_STV0367TER_SetCLKgen for 27Mhz\n"); - stv0367_writereg(state, R367TER_PLLMDIV, 0x1); - stv0367_writereg(state, R367TER_PLLNDIV, 0x8); - stv0367_writereg(state, R367TER_PLLSETUP, 0x18); - break; - case 30000000: - stv0367_writereg(state, R367TER_PLLMDIV, 0xc); - stv0367_writereg(state, R367TER_PLLNDIV, 0x55); - stv0367_writereg(state, R367TER_PLLSETUP, 0x18); - break; - } - - stv0367_writereg(state, R367TER_I2CRPT, 0xa0); - stv0367_writereg(state, R367TER_ANACTRL, 0x00); - - /*Set TS1 and TS2 to serial or parallel mode */ - stv0367ter_set_ts_mode(state, state->config->ts_mode); - stv0367ter_set_clk_pol(state, state->config->clk_pol); - - state->chip_id = stv0367_readreg(state, R367TER_ID); - ter_state->first_lock = 0; - ter_state->unlock_counter = 2; - - return 0; -} - -static int stv0367ter_algo(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367ter_state *ter_state = state->ter_state; - int offset = 0, tempo = 0; - u8 u_var; - u8 /*constell,*/ counter, tps_rcvd[2]; - s8 step; - s32 timing_offset = 0; - u32 trl_nomrate = 0, InternalFreq = 0, temp = 0; - - dprintk("%s:\n", __func__); - - ter_state->frequency = param->frequency; - ter_state->force = FE_TER_FORCENONE - + stv0367_readbits(state, F367TER_FORCE) * 2; - ter_state->if_iq_mode = state->config->if_iq_mode; - switch (state->config->if_iq_mode) { - case FE_TER_NORMAL_IF_TUNER: /* Normal IF mode */ - dprintk("ALGO: FE_TER_NORMAL_IF_TUNER selected\n"); - stv0367_writebits(state, F367TER_TUNER_BB, 0); - stv0367_writebits(state, F367TER_LONGPATH_IF, 0); - stv0367_writebits(state, F367TER_DEMUX_SWAP, 0); - break; - case FE_TER_LONGPATH_IF_TUNER: /* Long IF mode */ - dprintk("ALGO: FE_TER_LONGPATH_IF_TUNER selected\n"); - stv0367_writebits(state, F367TER_TUNER_BB, 0); - stv0367_writebits(state, F367TER_LONGPATH_IF, 1); - stv0367_writebits(state, F367TER_DEMUX_SWAP, 1); - break; - case FE_TER_IQ_TUNER: /* IQ mode */ - dprintk("ALGO: FE_TER_IQ_TUNER selected\n"); - stv0367_writebits(state, F367TER_TUNER_BB, 1); - stv0367_writebits(state, F367TER_PPM_INVSEL, 0); - break; - default: - printk(KERN_ERR "ALGO: wrong TUNER type selected\n"); - return -EINVAL; - } - - usleep_range(5000, 7000); - - switch (param->inversion) { - case INVERSION_AUTO: - default: - dprintk("%s: inversion AUTO\n", __func__); - if (ter_state->if_iq_mode == FE_TER_IQ_TUNER) - stv0367_writebits(state, F367TER_IQ_INVERT, - ter_state->sense); - else - stv0367_writebits(state, F367TER_INV_SPECTR, - ter_state->sense); - - break; - case INVERSION_ON: - case INVERSION_OFF: - if (ter_state->if_iq_mode == FE_TER_IQ_TUNER) - stv0367_writebits(state, F367TER_IQ_INVERT, - param->inversion); - else - stv0367_writebits(state, F367TER_INV_SPECTR, - param->inversion); - - break; - } - - if ((ter_state->if_iq_mode != FE_TER_NORMAL_IF_TUNER) && - (ter_state->pBW != ter_state->bw)) { - stv0367ter_agc_iir_lock_detect_set(state); - - /*set fine agc target to 180 for LPIF or IQ mode*/ - /* set Q_AGCTarget */ - stv0367_writebits(state, F367TER_SEL_IQNTAR, 1); - stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB); - /*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */ - - /* set Q_AGCTarget */ - stv0367_writebits(state, F367TER_SEL_IQNTAR, 0); - stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB); - /*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */ - - if (!stv0367_iir_filt_init(state, ter_state->bw, - state->config->xtal)) - return -EINVAL; - /*set IIR filter once for 6,7 or 8MHz BW*/ - ter_state->pBW = ter_state->bw; - - stv0367ter_agc_iir_rst(state); - } - - if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO) - stv0367_writebits(state, F367TER_BDI_LPSEL, 0x01); - else - stv0367_writebits(state, F367TER_BDI_LPSEL, 0x00); - - InternalFreq = stv0367ter_get_mclk(state, state->config->xtal) / 1000; - temp = (int) - ((((ter_state->bw * 64 * (1 << 15) * 100) - / (InternalFreq)) * 10) / 7); - - stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB, temp % 2); - temp = temp / 2; - stv0367_writebits(state, F367TER_TRL_NOMRATE_HI, temp / 256); - stv0367_writebits(state, F367TER_TRL_NOMRATE_LO, temp % 256); - - temp = stv0367_readbits(state, F367TER_TRL_NOMRATE_HI) * 512 + - stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2 + - stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB); - temp = (int)(((1 << 17) * ter_state->bw * 1000) / (7 * (InternalFreq))); - stv0367_writebits(state, F367TER_GAIN_SRC_HI, temp / 256); - stv0367_writebits(state, F367TER_GAIN_SRC_LO, temp % 256); - temp = stv0367_readbits(state, F367TER_GAIN_SRC_HI) * 256 + - stv0367_readbits(state, F367TER_GAIN_SRC_LO); - - temp = (int) - ((InternalFreq - state->config->if_khz) * (1 << 16) - / (InternalFreq)); - - dprintk("DEROT temp=0x%x\n", temp); - stv0367_writebits(state, F367TER_INC_DEROT_HI, temp / 256); - stv0367_writebits(state, F367TER_INC_DEROT_LO, temp % 256); - - ter_state->echo_pos = 0; - ter_state->ucblocks = 0; /* liplianin */ - ter_state->pBER = 0; /* liplianin */ - stv0367_writebits(state, F367TER_LONG_ECHO, ter_state->echo_pos); - - if (stv0367ter_lock_algo(state) != FE_TER_LOCKOK) - return 0; - - ter_state->state = FE_TER_LOCKOK; - /* update results */ - tps_rcvd[0] = stv0367_readreg(state, R367TER_TPS_RCVD2); - tps_rcvd[1] = stv0367_readreg(state, R367TER_TPS_RCVD3); - - ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE); - ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD); - - ter_state->first_lock = 1; /* we know sense now :) */ - - ter_state->agc_val = - (stv0367_readbits(state, F367TER_AGC1_VAL_LO) << 16) + - (stv0367_readbits(state, F367TER_AGC1_VAL_HI) << 24) + - stv0367_readbits(state, F367TER_AGC2_VAL_LO) + - (stv0367_readbits(state, F367TER_AGC2_VAL_HI) << 8); - - /* Carrier offset calculation */ - stv0367_writebits(state, F367TER_FREEZE, 1); - offset = (stv0367_readbits(state, F367TER_CRL_FOFFSET_VHI) << 16) ; - offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_HI) << 8); - offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_LO)); - stv0367_writebits(state, F367TER_FREEZE, 0); - if (offset > 8388607) - offset -= 16777216; - - offset = offset * 2 / 16384; - - if (ter_state->mode == FE_TER_MODE_2K) - offset = (offset * 4464) / 1000;/*** 1 FFT BIN=4.464khz***/ - else if (ter_state->mode == FE_TER_MODE_4K) - offset = (offset * 223) / 100;/*** 1 FFT BIN=2.23khz***/ - else if (ter_state->mode == FE_TER_MODE_8K) - offset = (offset * 111) / 100;/*** 1 FFT BIN=1.1khz***/ - - if (stv0367_readbits(state, F367TER_PPM_INVSEL) == 1) { - if ((stv0367_readbits(state, F367TER_INV_SPECTR) == - (stv0367_readbits(state, - F367TER_STATUS_INV_SPECRUM) == 1))) - offset = offset * -1; - } - - if (ter_state->bw == 6) - offset = (offset * 6) / 8; - else if (ter_state->bw == 7) - offset = (offset * 7) / 8; - - ter_state->frequency += offset; - - tempo = 10; /* exit even if timing_offset stays null */ - while ((timing_offset == 0) && (tempo > 0)) { - usleep_range(10000, 20000); /*was 20ms */ - /* fine tuning of timing offset if required */ - timing_offset = stv0367_readbits(state, F367TER_TRL_TOFFSET_LO) - + 256 * stv0367_readbits(state, - F367TER_TRL_TOFFSET_HI); - if (timing_offset >= 32768) - timing_offset -= 65536; - trl_nomrate = (512 * stv0367_readbits(state, - F367TER_TRL_NOMRATE_HI) - + stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2 - + stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB)); - - timing_offset = ((signed)(1000000 / trl_nomrate) * - timing_offset) / 2048; - tempo--; - } - - if (timing_offset <= 0) { - timing_offset = (timing_offset - 11) / 22; - step = -1; - } else { - timing_offset = (timing_offset + 11) / 22; - step = 1; - } - - for (counter = 0; counter < abs(timing_offset); counter++) { - trl_nomrate += step; - stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB, - trl_nomrate % 2); - stv0367_writebits(state, F367TER_TRL_NOMRATE_LO, - trl_nomrate / 2); - usleep_range(1000, 2000); - } - - usleep_range(5000, 6000); - /* unlocks could happen in case of trl centring big step, - then a core off/on restarts demod */ - u_var = stv0367_readbits(state, F367TER_LK); - - if (!u_var) { - stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); - msleep(20); - stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); - } - - return 0; -} - -static int stv0367ter_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367ter_state *ter_state = state->ter_state; - - /*u8 trials[2]; */ - s8 num_trials, index; - u8 SenseTrials[] = { INVERSION_ON, INVERSION_OFF }; - - stv0367ter_init(fe); - - if (fe->ops.tuner_ops.set_params) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - switch (op->transmission_mode) { - default: - case TRANSMISSION_MODE_AUTO: - case TRANSMISSION_MODE_2K: - ter_state->mode = FE_TER_MODE_2K; - break; -/* case TRANSMISSION_MODE_4K: - pLook.mode = FE_TER_MODE_4K; - break;*/ - case TRANSMISSION_MODE_8K: - ter_state->mode = FE_TER_MODE_8K; - break; - } - - switch (op->guard_interval) { - default: - case GUARD_INTERVAL_1_32: - case GUARD_INTERVAL_1_16: - case GUARD_INTERVAL_1_8: - case GUARD_INTERVAL_1_4: - ter_state->guard = op->guard_interval; - break; - case GUARD_INTERVAL_AUTO: - ter_state->guard = GUARD_INTERVAL_1_32; - break; - } - - switch (op->bandwidth) { - case BANDWIDTH_6_MHZ: - ter_state->bw = FE_TER_CHAN_BW_6M; - break; - case BANDWIDTH_7_MHZ: - ter_state->bw = FE_TER_CHAN_BW_7M; - break; - case BANDWIDTH_8_MHZ: - default: - ter_state->bw = FE_TER_CHAN_BW_8M; - } - - ter_state->hierarchy = FE_TER_HIER_NONE; - - switch (param->inversion) { - case INVERSION_OFF: - case INVERSION_ON: - num_trials = 1; - break; - default: - num_trials = 2; - if (ter_state->first_lock) - num_trials = 1; - break; - } - - ter_state->state = FE_TER_NOLOCK; - index = 0; - - while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) { - if (!ter_state->first_lock) { - if (param->inversion == INVERSION_AUTO) - ter_state->sense = SenseTrials[index]; - - } - stv0367ter_algo(fe,/* &pLook, result,*/ param); - - if ((ter_state->state == FE_TER_LOCKOK) && - (param->inversion == INVERSION_AUTO) && - (index == 1)) { - /* invert spectrum sense */ - SenseTrials[index] = SenseTrials[0]; - SenseTrials[(index + 1) % 2] = (SenseTrials[1] + 1) % 2; - } - - index++; - } - - return 0; -} - -static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367ter_state *ter_state = state->ter_state; - u32 errs = 0; - - /*wait for counting completion*/ - if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0) { - errs = - ((u32)stv0367_readbits(state, F367TER_ERR_CNT1) - * (1 << 16)) - + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI) - * (1 << 8)) - + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO)); - ter_state->ucblocks = errs; - } - - (*ucblocks) = ter_state->ucblocks; - - return 0; -} - -static int stv0367ter_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367ter_state *ter_state = state->ter_state; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - int error = 0; - enum stv0367_ter_mode mode; - int constell = 0,/* snr = 0,*/ Data = 0; - - param->frequency = stv0367_get_tuner_freq(fe); - if ((int)param->frequency < 0) - param->frequency = c->frequency; - - constell = stv0367_readbits(state, F367TER_TPS_CONST); - if (constell == 0) - op->constellation = QPSK; - else if (constell == 1) - op->constellation = QAM_16; - else - op->constellation = QAM_64; - - param->inversion = stv0367_readbits(state, F367TER_INV_SPECTR); - - /* Get the Hierarchical mode */ - Data = stv0367_readbits(state, F367TER_TPS_HIERMODE); - - switch (Data) { - case 0: - op->hierarchy_information = HIERARCHY_NONE; - break; - case 1: - op->hierarchy_information = HIERARCHY_1; - break; - case 2: - op->hierarchy_information = HIERARCHY_2; - break; - case 3: - op->hierarchy_information = HIERARCHY_4; - break; - default: - op->hierarchy_information = HIERARCHY_AUTO; - break; /* error */ - } - - /* Get the FEC Rate */ - if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO) - Data = stv0367_readbits(state, F367TER_TPS_LPCODE); - else - Data = stv0367_readbits(state, F367TER_TPS_HPCODE); - - switch (Data) { - case 0: - op->code_rate_HP = FEC_1_2; - break; - case 1: - op->code_rate_HP = FEC_2_3; - break; - case 2: - op->code_rate_HP = FEC_3_4; - break; - case 3: - op->code_rate_HP = FEC_5_6; - break; - case 4: - op->code_rate_HP = FEC_7_8; - break; - default: - op->code_rate_HP = FEC_AUTO; - break; /* error */ - } - - mode = stv0367_readbits(state, F367TER_SYR_MODE); - - switch (mode) { - case FE_TER_MODE_2K: - op->transmission_mode = TRANSMISSION_MODE_2K; - break; -/* case FE_TER_MODE_4K: - op->transmission_mode = TRANSMISSION_MODE_4K; - break;*/ - case FE_TER_MODE_8K: - op->transmission_mode = TRANSMISSION_MODE_8K; - break; - default: - op->transmission_mode = TRANSMISSION_MODE_AUTO; - } - - op->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD); - - return error; -} - -static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct stv0367_state *state = fe->demodulator_priv; - u32 snru32 = 0; - int cpt = 0; - u8 cut = stv0367_readbits(state, F367TER_IDENTIFICATIONREG); - - while (cpt < 10) { - usleep_range(2000, 3000); - if (cut == 0x50) /*cut 1.0 cut 1.1*/ - snru32 += stv0367_readbits(state, F367TER_CHCSNR) / 4; - else /*cu2.0*/ - snru32 += 125 * stv0367_readbits(state, F367TER_CHCSNR); - - cpt++; - } - - snru32 /= 10;/*average on 10 values*/ - - *snr = snru32 / 1000; - - return 0; -} - -#if 0 -static int stv0367ter_status(struct dvb_frontend *fe) -{ - - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367ter_state *ter_state = state->ter_state; - int locked = FALSE; - - locked = (stv0367_readbits(state, F367TER_LK)); - if (!locked) - ter_state->unlock_counter += 1; - else - ter_state->unlock_counter = 0; - - if (ter_state->unlock_counter > 2) { - if (!stv0367_readbits(state, F367TER_TPS_LOCK) || - (!stv0367_readbits(state, F367TER_LK))) { - stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); - usleep_range(2000, 3000); - stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); - msleep(350); - locked = (stv0367_readbits(state, F367TER_TPS_LOCK)) && - (stv0367_readbits(state, F367TER_LK)); - } - - } - - return locked; -} -#endif -static int stv0367ter_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct stv0367_state *state = fe->demodulator_priv; - - dprintk("%s:\n", __func__); - - *status = 0; - - if (stv0367_readbits(state, F367TER_LK)) { - *status |= FE_HAS_LOCK; - dprintk("%s: stv0367 has locked\n", __func__); - } - - return 0; -} - -static int stv0367ter_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367ter_state *ter_state = state->ter_state; - u32 Errors = 0, tber = 0, temporary = 0; - int abc = 0, def = 0; - - - /*wait for counting completion*/ - if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0) - Errors = ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT) - * (1 << 16)) - + ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT_HI) - * (1 << 8)) - + ((u32)stv0367_readbits(state, - F367TER_SFEC_ERR_CNT_LO)); - /*measurement not completed, load previous value*/ - else { - tber = ter_state->pBER; - return 0; - } - - abc = stv0367_readbits(state, F367TER_SFEC_ERR_SOURCE); - def = stv0367_readbits(state, F367TER_SFEC_NUM_EVENT); - - if (Errors == 0) { - tber = 0; - } else if (abc == 0x7) { - if (Errors <= 4) { - temporary = (Errors * 1000000000) / (8 * (1 << 14)); - temporary = temporary; - } else if (Errors <= 42) { - temporary = (Errors * 100000000) / (8 * (1 << 14)); - temporary = temporary * 10; - } else if (Errors <= 429) { - temporary = (Errors * 10000000) / (8 * (1 << 14)); - temporary = temporary * 100; - } else if (Errors <= 4294) { - temporary = (Errors * 1000000) / (8 * (1 << 14)); - temporary = temporary * 1000; - } else if (Errors <= 42949) { - temporary = (Errors * 100000) / (8 * (1 << 14)); - temporary = temporary * 10000; - } else if (Errors <= 429496) { - temporary = (Errors * 10000) / (8 * (1 << 14)); - temporary = temporary * 100000; - } else { /*if (Errors<4294967) 2^22 max error*/ - temporary = (Errors * 1000) / (8 * (1 << 14)); - temporary = temporary * 100000; /* still to *10 */ - } - - /* Byte error*/ - if (def == 2) - /*tber=Errors/(8*(1 <<14));*/ - tber = temporary; - else if (def == 3) - /*tber=Errors/(8*(1 <<16));*/ - tber = temporary / 4; - else if (def == 4) - /*tber=Errors/(8*(1 <<18));*/ - tber = temporary / 16; - else if (def == 5) - /*tber=Errors/(8*(1 <<20));*/ - tber = temporary / 64; - else if (def == 6) - /*tber=Errors/(8*(1 <<22));*/ - tber = temporary / 256; - else - /* should not pass here*/ - tber = 0; - - if ((Errors < 4294967) && (Errors > 429496)) - tber *= 10; - - } - - /* save actual value */ - ter_state->pBER = tber; - - (*ber) = tber; - - return 0; -} -#if 0 -static u32 stv0367ter_get_per(struct stv0367_state *state) -{ - struct stv0367ter_state *ter_state = state->ter_state; - u32 Errors = 0, Per = 0, temporary = 0; - int abc = 0, def = 0, cpt = 0; - - while (((stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 1) && - (cpt < 400)) || ((Errors == 0) && (cpt < 400))) { - usleep_range(1000, 2000); - Errors = ((u32)stv0367_readbits(state, F367TER_ERR_CNT1) - * (1 << 16)) - + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI) - * (1 << 8)) - + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO)); - cpt++; - } - abc = stv0367_readbits(state, F367TER_ERR_SRC1); - def = stv0367_readbits(state, F367TER_NUM_EVT1); - - if (Errors == 0) - Per = 0; - else if (abc == 0x9) { - if (Errors <= 4) { - temporary = (Errors * 1000000000) / (8 * (1 << 8)); - temporary = temporary; - } else if (Errors <= 42) { - temporary = (Errors * 100000000) / (8 * (1 << 8)); - temporary = temporary * 10; - } else if (Errors <= 429) { - temporary = (Errors * 10000000) / (8 * (1 << 8)); - temporary = temporary * 100; - } else if (Errors <= 4294) { - temporary = (Errors * 1000000) / (8 * (1 << 8)); - temporary = temporary * 1000; - } else if (Errors <= 42949) { - temporary = (Errors * 100000) / (8 * (1 << 8)); - temporary = temporary * 10000; - } else { /*if(Errors<=429496) 2^16 errors max*/ - temporary = (Errors * 10000) / (8 * (1 << 8)); - temporary = temporary * 100000; - } - - /* pkt error*/ - if (def == 2) - /*Per=Errors/(1 << 8);*/ - Per = temporary; - else if (def == 3) - /*Per=Errors/(1 << 10);*/ - Per = temporary / 4; - else if (def == 4) - /*Per=Errors/(1 << 12);*/ - Per = temporary / 16; - else if (def == 5) - /*Per=Errors/(1 << 14);*/ - Per = temporary / 64; - else if (def == 6) - /*Per=Errors/(1 << 16);*/ - Per = temporary / 256; - else - Per = 0; - - } - /* save actual value */ - ter_state->pPER = Per; - - return Per; -} -#endif -static int stv0367_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings - *fe_tune_settings) -{ - fe_tune_settings->min_delay_ms = 1000; - fe_tune_settings->step_size = 0; - fe_tune_settings->max_drift = 0; - - return 0; -} - -static void stv0367_release(struct dvb_frontend *fe) -{ - struct stv0367_state *state = fe->demodulator_priv; - - kfree(state->ter_state); - kfree(state->cab_state); - kfree(state); -} - -static struct dvb_frontend_ops stv0367ter_ops = { - .info = { - .name = "ST STV0367 DVB-T", - .type = FE_OFDM, - .frequency_min = 47000000, - .frequency_max = 862000000, - .frequency_stepsize = 15625, - .frequency_tolerance = 0, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | - FE_CAN_INVERSION_AUTO | - FE_CAN_MUTE_TS - }, - .release = stv0367_release, - .init = stv0367ter_init, - .sleep = stv0367ter_sleep, - .i2c_gate_ctrl = stv0367ter_gate_ctrl, - .set_frontend = stv0367ter_set_frontend, - .get_frontend = stv0367ter_get_frontend, - .get_tune_settings = stv0367_get_tune_settings, - .read_status = stv0367ter_read_status, - .read_ber = stv0367ter_read_ber,/* too slow */ -/* .read_signal_strength = stv0367_read_signal_strength,*/ - .read_snr = stv0367ter_read_snr, - .read_ucblocks = stv0367ter_read_ucblocks, -}; - -struct dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, - struct i2c_adapter *i2c) -{ - struct stv0367_state *state = NULL; - struct stv0367ter_state *ter_state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL); - if (state == NULL) - goto error; - ter_state = kzalloc(sizeof(struct stv0367ter_state), GFP_KERNEL); - if (ter_state == NULL) - goto error; - - /* setup the state */ - state->i2c = i2c; - state->config = config; - state->ter_state = ter_state; - state->fe.ops = stv0367ter_ops; - state->fe.demodulator_priv = state; - state->chip_id = stv0367_readreg(state, 0xf000); - - dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id); - - /* check if the demod is there */ - if ((state->chip_id != 0x50) && (state->chip_id != 0x60)) - goto error; - - return &state->fe; - -error: - kfree(ter_state); - kfree(state); - return NULL; -} -EXPORT_SYMBOL(stv0367ter_attach); - -static int stv0367cab_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct stv0367_state *state = fe->demodulator_priv; - - dprintk("%s:\n", __func__); - - stv0367_writebits(state, F367CAB_I2CT_ON, (enable > 0) ? 1 : 0); - - return 0; -} - -static u32 stv0367cab_get_mclk(struct dvb_frontend *fe, u32 ExtClk_Hz) -{ - struct stv0367_state *state = fe->demodulator_priv; - u32 mclk_Hz = 0;/* master clock frequency (Hz) */ - u32 M, N, P; - - - if (stv0367_readbits(state, F367CAB_BYPASS_PLLXN) == 0) { - N = (u32)stv0367_readbits(state, F367CAB_PLL_NDIV); - if (N == 0) - N = N + 1; - - M = (u32)stv0367_readbits(state, F367CAB_PLL_MDIV); - if (M == 0) - M = M + 1; - - P = (u32)stv0367_readbits(state, F367CAB_PLL_PDIV); - - if (P > 5) - P = 5; - - mclk_Hz = ((ExtClk_Hz / 2) * N) / (M * (1 << P)); - dprintk("stv0367cab_get_mclk BYPASS_PLLXN mclk_Hz=%d\n", - mclk_Hz); - } else - mclk_Hz = ExtClk_Hz; - - dprintk("stv0367cab_get_mclk final mclk_Hz=%d\n", mclk_Hz); - - return mclk_Hz; -} - -static u32 stv0367cab_get_adc_freq(struct dvb_frontend *fe, u32 ExtClk_Hz) -{ - u32 ADCClk_Hz = ExtClk_Hz; - - ADCClk_Hz = stv0367cab_get_mclk(fe, ExtClk_Hz); - - return ADCClk_Hz; -} - -enum stv0367cab_mod stv0367cab_SetQamSize(struct stv0367_state *state, - u32 SymbolRate, - enum stv0367cab_mod QAMSize) -{ - /* Set QAM size */ - stv0367_writebits(state, F367CAB_QAM_MODE, QAMSize); - - /* Set Registers settings specific to the QAM size */ - switch (QAMSize) { - case FE_CAB_MOD_QAM4: - stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); - break; - case FE_CAB_MOD_QAM16: - stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x64); - stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); - stv0367_writereg(state, R367CAB_FSM_STATE, 0x90); - stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); - stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); - stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95); - stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40); - stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x8a); - break; - case FE_CAB_MOD_QAM32: - stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); - stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x6e); - stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0); - stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); - stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xb7); - stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x9d); - stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f); - stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7); - break; - case FE_CAB_MOD_QAM64: - stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x82); - stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a); - if (SymbolRate > 45000000) { - stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0); - stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); - stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa5); - } else if (SymbolRate > 25000000) { - stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0); - stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); - stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6); - } else { - stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0); - stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1); - stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); - } - stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95); - stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40); - stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x99); - break; - case FE_CAB_MOD_QAM128: - stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); - stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x76); - stv0367_writereg(state, R367CAB_FSM_STATE, 0x90); - stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xb1); - if (SymbolRate > 45000000) - stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); - else if (SymbolRate > 25000000) - stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6); - else - stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0x97); - - stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x8e); - stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f); - stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7); - break; - case FE_CAB_MOD_QAM256: - stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x94); - stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a); - stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0); - if (SymbolRate > 45000000) - stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); - else if (SymbolRate > 25000000) - stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); - else - stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1); - - stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); - stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x85); - stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40); - stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7); - break; - case FE_CAB_MOD_QAM512: - stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); - break; - case FE_CAB_MOD_QAM1024: - stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); - break; - default: - break; - } - - return QAMSize; -} - -static u32 stv0367cab_set_derot_freq(struct stv0367_state *state, - u32 adc_hz, s32 derot_hz) -{ - u32 sampled_if = 0; - u32 adc_khz; - - adc_khz = adc_hz / 1000; - - dprintk("%s: adc_hz=%d derot_hz=%d\n", __func__, adc_hz, derot_hz); - - if (adc_khz != 0) { - if (derot_hz < 1000000) - derot_hz = adc_hz / 4; /* ZIF operation */ - if (derot_hz > adc_hz) - derot_hz = derot_hz - adc_hz; - sampled_if = (u32)derot_hz / 1000; - sampled_if *= 32768; - sampled_if /= adc_khz; - sampled_if *= 256; - } - - if (sampled_if > 8388607) - sampled_if = 8388607; - - dprintk("%s: sampled_if=0x%x\n", __func__, sampled_if); - - stv0367_writereg(state, R367CAB_MIX_NCO_LL, sampled_if); - stv0367_writereg(state, R367CAB_MIX_NCO_HL, (sampled_if >> 8)); - stv0367_writebits(state, F367CAB_MIX_NCO_INC_HH, (sampled_if >> 16)); - - return derot_hz; -} - -static u32 stv0367cab_get_derot_freq(struct stv0367_state *state, u32 adc_hz) -{ - u32 sampled_if; - - sampled_if = stv0367_readbits(state, F367CAB_MIX_NCO_INC_LL) + - (stv0367_readbits(state, F367CAB_MIX_NCO_INC_HL) << 8) + - (stv0367_readbits(state, F367CAB_MIX_NCO_INC_HH) << 16); - - sampled_if /= 256; - sampled_if *= (adc_hz / 1000); - sampled_if += 1; - sampled_if /= 32768; - - return sampled_if; -} - -static u32 stv0367cab_set_srate(struct stv0367_state *state, u32 adc_hz, - u32 mclk_hz, u32 SymbolRate, - enum stv0367cab_mod QAMSize) -{ - u32 QamSizeCorr = 0; - u32 u32_tmp = 0, u32_tmp1 = 0; - u32 adp_khz; - - dprintk("%s:\n", __func__); - - /* Set Correction factor of SRC gain */ - switch (QAMSize) { - case FE_CAB_MOD_QAM4: - QamSizeCorr = 1110; - break; - case FE_CAB_MOD_QAM16: - QamSizeCorr = 1032; - break; - case FE_CAB_MOD_QAM32: - QamSizeCorr = 954; - break; - case FE_CAB_MOD_QAM64: - QamSizeCorr = 983; - break; - case FE_CAB_MOD_QAM128: - QamSizeCorr = 957; - break; - case FE_CAB_MOD_QAM256: - QamSizeCorr = 948; - break; - case FE_CAB_MOD_QAM512: - QamSizeCorr = 0; - break; - case FE_CAB_MOD_QAM1024: - QamSizeCorr = 944; - break; - default: - break; - } - - /* Transfer ratio calculation */ - if (adc_hz != 0) { - u32_tmp = 256 * SymbolRate; - u32_tmp = u32_tmp / adc_hz; - } - stv0367_writereg(state, R367CAB_EQU_CRL_TFR, (u8)u32_tmp); - - /* Symbol rate and SRC gain calculation */ - adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */ - if (adp_khz != 0) { - u32_tmp = SymbolRate; - u32_tmp1 = SymbolRate; - - if (u32_tmp < 2097152) { /* 2097152 = 2^21 */ - /* Symbol rate calculation */ - u32_tmp *= 2048; /* 2048 = 2^11 */ - u32_tmp = u32_tmp / adp_khz; - u32_tmp = u32_tmp * 16384; /* 16384 = 2^14 */ - u32_tmp /= 125 ; /* 125 = 1000/2^3 */ - u32_tmp = u32_tmp * 8; /* 8 = 2^3 */ - - /* SRC Gain Calculation */ - u32_tmp1 *= 2048; /* *2*2^10 */ - u32_tmp1 /= 439; /* *2/878 */ - u32_tmp1 *= 256; /* *2^8 */ - u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */ - u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ - u32_tmp1 = u32_tmp1 / 10000000; - - } else if (u32_tmp < 4194304) { /* 4194304 = 2**22 */ - /* Symbol rate calculation */ - u32_tmp *= 1024 ; /* 1024 = 2**10 */ - u32_tmp = u32_tmp / adp_khz; - u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */ - u32_tmp /= 125 ; /* 125 = 1000/2**3 */ - u32_tmp = u32_tmp * 16; /* 16 = 2**4 */ - - /* SRC Gain Calculation */ - u32_tmp1 *= 1024; /* *2*2^9 */ - u32_tmp1 /= 439; /* *2/878 */ - u32_tmp1 *= 256; /* *2^8 */ - u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz)*/ - u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ - u32_tmp1 = u32_tmp1 / 5000000; - } else if (u32_tmp < 8388607) { /* 8388607 = 2**23 */ - /* Symbol rate calculation */ - u32_tmp *= 512 ; /* 512 = 2**9 */ - u32_tmp = u32_tmp / adp_khz; - u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */ - u32_tmp /= 125 ; /* 125 = 1000/2**3 */ - u32_tmp = u32_tmp * 32; /* 32 = 2**5 */ - - /* SRC Gain Calculation */ - u32_tmp1 *= 512; /* *2*2^8 */ - u32_tmp1 /= 439; /* *2/878 */ - u32_tmp1 *= 256; /* *2^8 */ - u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */ - u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ - u32_tmp1 = u32_tmp1 / 2500000; - } else { - /* Symbol rate calculation */ - u32_tmp *= 256 ; /* 256 = 2**8 */ - u32_tmp = u32_tmp / adp_khz; - u32_tmp = u32_tmp * 16384; /* 16384 = 2**13 */ - u32_tmp /= 125 ; /* 125 = 1000/2**3 */ - u32_tmp = u32_tmp * 64; /* 64 = 2**6 */ - - /* SRC Gain Calculation */ - u32_tmp1 *= 256; /* 2*2^7 */ - u32_tmp1 /= 439; /* *2/878 */ - u32_tmp1 *= 256; /* *2^8 */ - u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */ - u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ - u32_tmp1 = u32_tmp1 / 1250000; - } - } -#if 0 - /* Filters' coefficients are calculated and written - into registers only if the filters are enabled */ - if (stv0367_readbits(state, F367CAB_ADJ_EN)) { - stv0367cab_SetIirAdjacentcoefficient(state, mclk_hz, - SymbolRate); - /* AllPass filter must be enabled - when the adjacents filter is used */ - stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 1); - stv0367cab_SetAllPasscoefficient(state, mclk_hz, SymbolRate); - } else - /* AllPass filter must be disabled - when the adjacents filter is not used */ -#endif - stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0); - - stv0367_writereg(state, R367CAB_SRC_NCO_LL, u32_tmp); - stv0367_writereg(state, R367CAB_SRC_NCO_LH, (u32_tmp >> 8)); - stv0367_writereg(state, R367CAB_SRC_NCO_HL, (u32_tmp >> 16)); - stv0367_writereg(state, R367CAB_SRC_NCO_HH, (u32_tmp >> 24)); - - stv0367_writereg(state, R367CAB_IQDEM_GAIN_SRC_L, u32_tmp1 & 0x00ff); - stv0367_writebits(state, F367CAB_GAIN_SRC_HI, (u32_tmp1 >> 8) & 0x00ff); - - return SymbolRate ; -} - -static u32 stv0367cab_GetSymbolRate(struct stv0367_state *state, u32 mclk_hz) -{ - u32 regsym; - u32 adp_khz; - - regsym = stv0367_readreg(state, R367CAB_SRC_NCO_LL) + - (stv0367_readreg(state, R367CAB_SRC_NCO_LH) << 8) + - (stv0367_readreg(state, R367CAB_SRC_NCO_HL) << 16) + - (stv0367_readreg(state, R367CAB_SRC_NCO_HH) << 24); - - adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */ - - if (regsym < 134217728) { /* 134217728L = 2**27*/ - regsym = regsym * 32; /* 32 = 2**5 */ - regsym = regsym / 32768; /* 32768L = 2**15 */ - regsym = adp_khz * regsym; /* AdpClk in kHz */ - regsym = regsym / 128; /* 128 = 2**7 */ - regsym *= 125 ; /* 125 = 1000/2**3 */ - regsym /= 2048 ; /* 2048 = 2**11 */ - } else if (regsym < 268435456) { /* 268435456L = 2**28 */ - regsym = regsym * 16; /* 16 = 2**4 */ - regsym = regsym / 32768; /* 32768L = 2**15 */ - regsym = adp_khz * regsym; /* AdpClk in kHz */ - regsym = regsym / 128; /* 128 = 2**7 */ - regsym *= 125 ; /* 125 = 1000/2**3*/ - regsym /= 1024 ; /* 256 = 2**10*/ - } else if (regsym < 536870912) { /* 536870912L = 2**29*/ - regsym = regsym * 8; /* 8 = 2**3 */ - regsym = regsym / 32768; /* 32768L = 2**15 */ - regsym = adp_khz * regsym; /* AdpClk in kHz */ - regsym = regsym / 128; /* 128 = 2**7 */ - regsym *= 125 ; /* 125 = 1000/2**3 */ - regsym /= 512 ; /* 128 = 2**9 */ - } else { - regsym = regsym * 4; /* 4 = 2**2 */ - regsym = regsym / 32768; /* 32768L = 2**15 */ - regsym = adp_khz * regsym; /* AdpClk in kHz */ - regsym = regsym / 128; /* 128 = 2**7 */ - regsym *= 125 ; /* 125 = 1000/2**3 */ - regsym /= 256 ; /* 64 = 2**8 */ - } - - return regsym; -} - -static int stv0367cab_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct stv0367_state *state = fe->demodulator_priv; - - dprintk("%s:\n", __func__); - - *status = 0; - - if (stv0367_readbits(state, F367CAB_QAMFEC_LOCK)) { - *status |= FE_HAS_LOCK; - dprintk("%s: stv0367 has locked\n", __func__); - } - - return 0; -} - -static int stv0367cab_standby(struct dvb_frontend *fe, u8 standby_on) -{ - struct stv0367_state *state = fe->demodulator_priv; - - dprintk("%s:\n", __func__); - - if (standby_on) { - stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x03); - stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x01); - stv0367_writebits(state, F367CAB_STDBY, 1); - stv0367_writebits(state, F367CAB_STDBY_CORE, 1); - stv0367_writebits(state, F367CAB_EN_BUFFER_I, 0); - stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 0); - stv0367_writebits(state, F367CAB_POFFQ, 1); - stv0367_writebits(state, F367CAB_POFFI, 1); - } else { - stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x00); - stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x00); - stv0367_writebits(state, F367CAB_STDBY, 0); - stv0367_writebits(state, F367CAB_STDBY_CORE, 0); - stv0367_writebits(state, F367CAB_EN_BUFFER_I, 1); - stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 1); - stv0367_writebits(state, F367CAB_POFFQ, 0); - stv0367_writebits(state, F367CAB_POFFI, 0); - } - - return 0; -} - -static int stv0367cab_sleep(struct dvb_frontend *fe) -{ - return stv0367cab_standby(fe, 1); -} - -int stv0367cab_init(struct dvb_frontend *fe) -{ - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367cab_state *cab_state = state->cab_state; - int i; - - dprintk("%s:\n", __func__); - - for (i = 0; i < STV0367CAB_NBREGS; i++) - stv0367_writereg(state, def0367cab[i].addr, - def0367cab[i].value); - - switch (state->config->ts_mode) { - case STV0367_DVBCI_CLOCK: - dprintk("Setting TSMode = STV0367_DVBCI_CLOCK\n"); - stv0367_writebits(state, F367CAB_OUTFORMAT, 0x03); - break; - case STV0367_SERIAL_PUNCT_CLOCK: - case STV0367_SERIAL_CONT_CLOCK: - stv0367_writebits(state, F367CAB_OUTFORMAT, 0x01); - break; - case STV0367_PARALLEL_PUNCT_CLOCK: - case STV0367_OUTPUTMODE_DEFAULT: - stv0367_writebits(state, F367CAB_OUTFORMAT, 0x00); - break; - } - - switch (state->config->clk_pol) { - case STV0367_RISINGEDGE_CLOCK: - stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x00); - break; - case STV0367_FALLINGEDGE_CLOCK: - case STV0367_CLOCKPOLARITY_DEFAULT: - stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x01); - break; - } - - stv0367_writebits(state, F367CAB_SYNC_STRIP, 0x00); - - stv0367_writebits(state, F367CAB_CT_NBST, 0x01); - - stv0367_writebits(state, F367CAB_TS_SWAP, 0x01); - - stv0367_writebits(state, F367CAB_FIFO_BYPASS, 0x00); - - stv0367_writereg(state, R367CAB_ANACTRL, 0x00);/*PLL enabled and used */ - - cab_state->mclk = stv0367cab_get_mclk(fe, state->config->xtal); - cab_state->adc_clk = stv0367cab_get_adc_freq(fe, state->config->xtal); - - return 0; -} -static -enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, - struct dvb_frontend_parameters *param) -{ - struct dvb_qam_parameters *op = ¶m->u.qam; - struct stv0367cab_state *cab_state = state->cab_state; - enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC; - u32 QAMFEC_Lock, QAM_Lock, u32_tmp, - LockTime, TRLTimeOut, AGCTimeOut, CRLSymbols, - CRLTimeOut, EQLTimeOut, DemodTimeOut, FECTimeOut; - u8 TrackAGCAccum; - s32 tmp; - - dprintk("%s:\n", __func__); - - /* Timeouts calculation */ - /* A max lock time of 25 ms is allowed for delayed AGC */ - AGCTimeOut = 25; - /* 100000 symbols needed by the TRL as a maximum value */ - TRLTimeOut = 100000000 / op->symbol_rate; - /* CRLSymbols is the needed number of symbols to achieve a lock - within [-4%, +4%] of the symbol rate. - CRL timeout is calculated - for a lock within [-search_range, +search_range]. - EQL timeout can be changed depending on - the micro-reflections we want to handle. - A characterization must be performed - with these echoes to get new timeout values. - */ - switch (op->modulation) { - case QAM_16: - CRLSymbols = 150000; - EQLTimeOut = 100; - break; - case QAM_32: - CRLSymbols = 250000; - EQLTimeOut = 100; - break; - case QAM_64: - CRLSymbols = 200000; - EQLTimeOut = 100; - break; - case QAM_128: - CRLSymbols = 250000; - EQLTimeOut = 100; - break; - case QAM_256: - CRLSymbols = 250000; - EQLTimeOut = 100; - break; - default: - CRLSymbols = 200000; - EQLTimeOut = 100; - break; - } -#if 0 - if (pIntParams->search_range < 0) { - CRLTimeOut = (25 * CRLSymbols * - (-pIntParams->search_range / 1000)) / - (pIntParams->symbol_rate / 1000); - } else -#endif - CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) / - (op->symbol_rate / 1000); - - CRLTimeOut = (1000 * CRLTimeOut) / op->symbol_rate; - /* Timeouts below 50ms are coerced */ - if (CRLTimeOut < 50) - CRLTimeOut = 50; - /* A maximum of 100 TS packets is needed to get FEC lock even in case - the spectrum inversion needs to be changed. - This is equal to 20 ms in case of the lowest symbol rate of 0.87Msps - */ - FECTimeOut = 20; - DemodTimeOut = AGCTimeOut + TRLTimeOut + CRLTimeOut + EQLTimeOut; - - dprintk("%s: DemodTimeOut=%d\n", __func__, DemodTimeOut); - - /* Reset the TRL to ensure nothing starts until the - AGC is stable which ensures a better lock time - */ - stv0367_writereg(state, R367CAB_CTRL_1, 0x04); - /* Set AGC accumulation time to minimum and lock threshold to maximum - in order to speed up the AGC lock */ - TrackAGCAccum = stv0367_readbits(state, F367CAB_AGC_ACCUMRSTSEL); - stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, 0x0); - /* Modulus Mapper is disabled */ - stv0367_writebits(state, F367CAB_MODULUSMAP_EN, 0); - /* Disable the sweep function */ - stv0367_writebits(state, F367CAB_SWEEP_EN, 0); - /* The sweep function is never used, Sweep rate must be set to 0 */ - /* Set the derotator frequency in Hz */ - stv0367cab_set_derot_freq(state, cab_state->adc_clk, - (1000 * (s32)state->config->if_khz + cab_state->derot_offset)); - /* Disable the Allpass Filter when the symbol rate is out of range */ - if ((op->symbol_rate > 10800000) | (op->symbol_rate < 1800000)) { - stv0367_writebits(state, F367CAB_ADJ_EN, 0); - stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0); - } -#if 0 - /* Check if the tuner is locked */ - tuner_lock = stv0367cab_tuner_get_status(fe); - if (tuner_lock == 0) - return FE_367CAB_NOTUNER; -#endif - /* Relase the TRL to start demodulator acquisition */ - /* Wait for QAM lock */ - LockTime = 0; - stv0367_writereg(state, R367CAB_CTRL_1, 0x00); - do { - QAM_Lock = stv0367_readbits(state, F367CAB_FSM_STATUS); - if ((LockTime >= (DemodTimeOut - EQLTimeOut)) && - (QAM_Lock == 0x04)) - /* - * We don't wait longer, the frequency/phase offset - * must be too big - */ - LockTime = DemodTimeOut; - else if ((LockTime >= (AGCTimeOut + TRLTimeOut)) && - (QAM_Lock == 0x02)) - /* - * We don't wait longer, either there is no signal or - * it is not the right symbol rate or it is an analog - * carrier - */ - { - LockTime = DemodTimeOut; - u32_tmp = stv0367_readbits(state, - F367CAB_AGC_PWR_WORD_LO) + - (stv0367_readbits(state, - F367CAB_AGC_PWR_WORD_ME) << 8) + - (stv0367_readbits(state, - F367CAB_AGC_PWR_WORD_HI) << 16); - if (u32_tmp >= 131072) - u32_tmp = 262144 - u32_tmp; - u32_tmp = u32_tmp / (1 << (11 - stv0367_readbits(state, - F367CAB_AGC_IF_BWSEL))); - - if (u32_tmp < stv0367_readbits(state, - F367CAB_AGC_PWRREF_LO) + - 256 * stv0367_readbits(state, - F367CAB_AGC_PWRREF_HI) - 10) - QAM_Lock = 0x0f; - } else { - usleep_range(10000, 20000); - LockTime += 10; - } - dprintk("QAM_Lock=0x%x LockTime=%d\n", QAM_Lock, LockTime); - tmp = stv0367_readreg(state, R367CAB_IT_STATUS1); - - dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp); - - } while (((QAM_Lock != 0x0c) && (QAM_Lock != 0x0b)) && - (LockTime < DemodTimeOut)); - - dprintk("QAM_Lock=0x%x\n", QAM_Lock); - - tmp = stv0367_readreg(state, R367CAB_IT_STATUS1); - dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp); - tmp = stv0367_readreg(state, R367CAB_IT_STATUS2); - dprintk("R367CAB_IT_STATUS2=0x%x\n", tmp); - - tmp = stv0367cab_get_derot_freq(state, cab_state->adc_clk); - dprintk("stv0367cab_get_derot_freq=0x%x\n", tmp); - - if ((QAM_Lock == 0x0c) || (QAM_Lock == 0x0b)) { - /* Wait for FEC lock */ - LockTime = 0; - do { - usleep_range(5000, 7000); - LockTime += 5; - QAMFEC_Lock = stv0367_readbits(state, - F367CAB_QAMFEC_LOCK); - } while (!QAMFEC_Lock && (LockTime < FECTimeOut)); - } else - QAMFEC_Lock = 0; - - if (QAMFEC_Lock) { - signalType = FE_CAB_DATAOK; - cab_state->modulation = op->modulation; - cab_state->spect_inv = stv0367_readbits(state, - F367CAB_QUAD_INV); -#if 0 -/* not clear for me */ - if (state->config->if_khz != 0) { - if (state->config->if_khz > cab_state->adc_clk / 1000) { - cab_state->freq_khz = - FE_Cab_TunerGetFrequency(pIntParams->hTuner) - - stv0367cab_get_derot_freq(state, cab_state->adc_clk) - - cab_state->adc_clk / 1000 + state->config->if_khz; - } else { - cab_state->freq_khz = - FE_Cab_TunerGetFrequency(pIntParams->hTuner) - - stv0367cab_get_derot_freq(state, cab_state->adc_clk) - + state->config->if_khz; - } - } else { - cab_state->freq_khz = - FE_Cab_TunerGetFrequency(pIntParams->hTuner) + - stv0367cab_get_derot_freq(state, - cab_state->adc_clk) - - cab_state->adc_clk / 4000; - } -#endif - cab_state->symbol_rate = stv0367cab_GetSymbolRate(state, - cab_state->mclk); - cab_state->locked = 1; - - /* stv0367_setbits(state, F367CAB_AGC_ACCUMRSTSEL,7);*/ - } else { - switch (QAM_Lock) { - case 1: - signalType = FE_CAB_NOAGC; - break; - case 2: - signalType = FE_CAB_NOTIMING; - break; - case 3: - signalType = FE_CAB_TIMINGOK; - break; - case 4: - signalType = FE_CAB_NOCARRIER; - break; - case 5: - signalType = FE_CAB_CARRIEROK; - break; - case 7: - signalType = FE_CAB_NOBLIND; - break; - case 8: - signalType = FE_CAB_BLINDOK; - break; - case 10: - signalType = FE_CAB_NODEMOD; - break; - case 11: - signalType = FE_CAB_DEMODOK; - break; - case 12: - signalType = FE_CAB_DEMODOK; - break; - case 13: - signalType = FE_CAB_NODEMOD; - break; - case 14: - signalType = FE_CAB_NOBLIND; - break; - case 15: - signalType = FE_CAB_NOSIGNAL; - break; - default: - break; - } - - } - - /* Set the AGC control values to tracking values */ - stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, TrackAGCAccum); - return signalType; -} - -static int stv0367cab_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367cab_state *cab_state = state->cab_state; - struct dvb_qam_parameters *op = ¶m->u.qam; - enum stv0367cab_mod QAMSize = 0; - - dprintk("%s: freq = %d, srate = %d\n", __func__, - param->frequency, op->symbol_rate); - - cab_state->derot_offset = 0; - - switch (op->modulation) { - case QAM_16: - QAMSize = FE_CAB_MOD_QAM16; - break; - case QAM_32: - QAMSize = FE_CAB_MOD_QAM32; - break; - case QAM_64: - QAMSize = FE_CAB_MOD_QAM64; - break; - case QAM_128: - QAMSize = FE_CAB_MOD_QAM128; - break; - case QAM_256: - QAMSize = FE_CAB_MOD_QAM256; - break; - default: - break; - } - - stv0367cab_init(fe); - - /* Tuner Frequency Setting */ - if (fe->ops.tuner_ops.set_params) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - stv0367cab_SetQamSize( - state, - op->symbol_rate, - QAMSize); - - stv0367cab_set_srate(state, - cab_state->adc_clk, - cab_state->mclk, - op->symbol_rate, - QAMSize); - /* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */ - cab_state->state = stv0367cab_algo(state, param); - return 0; -} - -static int stv0367cab_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct stv0367_state *state = fe->demodulator_priv; - struct stv0367cab_state *cab_state = state->cab_state; - struct dvb_qam_parameters *op = ¶m->u.qam; - - enum stv0367cab_mod QAMSize; - - dprintk("%s:\n", __func__); - - op->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk); - - QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); - switch (QAMSize) { - case FE_CAB_MOD_QAM16: - op->modulation = QAM_16; - break; - case FE_CAB_MOD_QAM32: - op->modulation = QAM_32; - break; - case FE_CAB_MOD_QAM64: - op->modulation = QAM_64; - break; - case FE_CAB_MOD_QAM128: - op->modulation = QAM_128; - break; - case QAM_256: - op->modulation = QAM_256; - break; - default: - break; - } - - param->frequency = stv0367_get_tuner_freq(fe); - - dprintk("%s: tuner frequency = %d\n", __func__, param->frequency); - - if (state->config->if_khz == 0) { - param->frequency += - (stv0367cab_get_derot_freq(state, cab_state->adc_clk) - - cab_state->adc_clk / 4000); - return 0; - } - - if (state->config->if_khz > cab_state->adc_clk / 1000) - param->frequency += (state->config->if_khz - - stv0367cab_get_derot_freq(state, cab_state->adc_clk) - - cab_state->adc_clk / 1000); - else - param->frequency += (state->config->if_khz - - stv0367cab_get_derot_freq(state, cab_state->adc_clk)); - - return 0; -} - -#if 0 -void stv0367cab_GetErrorCount(state, enum stv0367cab_mod QAMSize, - u32 symbol_rate, FE_367qam_Monitor *Monitor_results) -{ - stv0367cab_OptimiseNByteAndGetBER(state, QAMSize, symbol_rate, Monitor_results); - stv0367cab_GetPacketsCount(state, Monitor_results); - - return; -} - -static int stv0367cab_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct stv0367_state *state = fe->demodulator_priv; - - return 0; -} -#endif -static s32 stv0367cab_get_rf_lvl(struct stv0367_state *state) -{ - s32 rfLevel = 0; - s32 RfAgcPwm = 0, IfAgcPwm = 0; - u8 i; - - stv0367_writebits(state, F367CAB_STDBY_ADCGP, 0x0); - - RfAgcPwm = - (stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_LO) & 0x03) + - (stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_HI) << 2); - RfAgcPwm = 100 * RfAgcPwm / 1023; - - IfAgcPwm = - stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_LO) + - (stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_HI) << 8); - if (IfAgcPwm >= 2048) - IfAgcPwm -= 2048; - else - IfAgcPwm += 2048; - - IfAgcPwm = 100 * IfAgcPwm / 4095; - - /* For DTT75467 on NIM */ - if (RfAgcPwm < 90 && IfAgcPwm < 28) { - for (i = 0; i < RF_LOOKUP_TABLE_SIZE; i++) { - if (RfAgcPwm <= stv0367cab_RF_LookUp1[0][i]) { - rfLevel = (-1) * stv0367cab_RF_LookUp1[1][i]; - break; - } - } - if (i == RF_LOOKUP_TABLE_SIZE) - rfLevel = -56; - } else { /*if IF AGC>10*/ - for (i = 0; i < RF_LOOKUP_TABLE2_SIZE; i++) { - if (IfAgcPwm <= stv0367cab_RF_LookUp2[0][i]) { - rfLevel = (-1) * stv0367cab_RF_LookUp2[1][i]; - break; - } - } - if (i == RF_LOOKUP_TABLE2_SIZE) - rfLevel = -72; - } - return rfLevel; -} - -static int stv0367cab_read_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct stv0367_state *state = fe->demodulator_priv; - - s32 signal = stv0367cab_get_rf_lvl(state); - - dprintk("%s: signal=%d dBm\n", __func__, signal); - - if (signal <= -72) - *strength = 65535; - else - *strength = (22 + signal) * (-1311); - - dprintk("%s: strength=%d\n", __func__, (*strength)); - - return 0; -} - -static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct stv0367_state *state = fe->demodulator_priv; - u32 noisepercentage; - enum stv0367cab_mod QAMSize; - u32 regval = 0, temp = 0; - int power, i; - - QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); - switch (QAMSize) { - case FE_CAB_MOD_QAM4: - power = 21904; - break; - case FE_CAB_MOD_QAM16: - power = 20480; - break; - case FE_CAB_MOD_QAM32: - power = 23040; - break; - case FE_CAB_MOD_QAM64: - power = 21504; - break; - case FE_CAB_MOD_QAM128: - power = 23616; - break; - case FE_CAB_MOD_QAM256: - power = 21760; - break; - case FE_CAB_MOD_QAM512: - power = 1; - break; - case FE_CAB_MOD_QAM1024: - power = 21280; - break; - default: - power = 1; - break; - } - - for (i = 0; i < 10; i++) { - regval += (stv0367_readbits(state, F367CAB_SNR_LO) - + 256 * stv0367_readbits(state, F367CAB_SNR_HI)); - } - - regval /= 10; /*for average over 10 times in for loop above*/ - if (regval != 0) { - temp = power - * (1 << (3 + stv0367_readbits(state, F367CAB_SNR_PER))); - temp /= regval; - } - - /* table values, not needed to calculate logarithms */ - if (temp >= 5012) - noisepercentage = 100; - else if (temp >= 3981) - noisepercentage = 93; - else if (temp >= 3162) - noisepercentage = 86; - else if (temp >= 2512) - noisepercentage = 79; - else if (temp >= 1995) - noisepercentage = 72; - else if (temp >= 1585) - noisepercentage = 65; - else if (temp >= 1259) - noisepercentage = 58; - else if (temp >= 1000) - noisepercentage = 50; - else if (temp >= 794) - noisepercentage = 43; - else if (temp >= 501) - noisepercentage = 36; - else if (temp >= 316) - noisepercentage = 29; - else if (temp >= 200) - noisepercentage = 22; - else if (temp >= 158) - noisepercentage = 14; - else if (temp >= 126) - noisepercentage = 7; - else - noisepercentage = 0; - - dprintk("%s: noisepercentage=%d\n", __func__, noisepercentage); - - *snr = (noisepercentage * 65535) / 100; - - return 0; -} - -static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct stv0367_state *state = fe->demodulator_priv; - int corrected, tscount; - - *ucblocks = (stv0367_readreg(state, R367CAB_RS_COUNTER_5) << 8) - | stv0367_readreg(state, R367CAB_RS_COUNTER_4); - corrected = (stv0367_readreg(state, R367CAB_RS_COUNTER_3) << 8) - | stv0367_readreg(state, R367CAB_RS_COUNTER_2); - tscount = (stv0367_readreg(state, R367CAB_RS_COUNTER_2) << 8) - | stv0367_readreg(state, R367CAB_RS_COUNTER_1); - - dprintk("%s: uncorrected blocks=%d corrected blocks=%d tscount=%d\n", - __func__, *ucblocks, corrected, tscount); - - return 0; -}; - -static struct dvb_frontend_ops stv0367cab_ops = { - .info = { - .name = "ST STV0367 DVB-C", - .type = FE_QAM, - .frequency_min = 47000000, - .frequency_max = 862000000, - .frequency_stepsize = 62500, - .symbol_rate_min = 870000, - .symbol_rate_max = 11700000, - .caps = 0x400 |/* FE_CAN_QAM_4 */ - FE_CAN_QAM_16 | FE_CAN_QAM_32 | - FE_CAN_QAM_64 | FE_CAN_QAM_128 | - FE_CAN_QAM_256 | FE_CAN_FEC_AUTO - }, - .release = stv0367_release, - .init = stv0367cab_init, - .sleep = stv0367cab_sleep, - .i2c_gate_ctrl = stv0367cab_gate_ctrl, - .set_frontend = stv0367cab_set_frontend, - .get_frontend = stv0367cab_get_frontend, - .read_status = stv0367cab_read_status, -/* .read_ber = stv0367cab_read_ber, */ - .read_signal_strength = stv0367cab_read_strength, - .read_snr = stv0367cab_read_snr, - .read_ucblocks = stv0367cab_read_ucblcks, - .get_tune_settings = stv0367_get_tune_settings, -}; - -struct dvb_frontend *stv0367cab_attach(const struct stv0367_config *config, - struct i2c_adapter *i2c) -{ - struct stv0367_state *state = NULL; - struct stv0367cab_state *cab_state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL); - if (state == NULL) - goto error; - cab_state = kzalloc(sizeof(struct stv0367cab_state), GFP_KERNEL); - if (cab_state == NULL) - goto error; - - /* setup the state */ - state->i2c = i2c; - state->config = config; - cab_state->search_range = 280000; - state->cab_state = cab_state; - state->fe.ops = stv0367cab_ops; - state->fe.demodulator_priv = state; - state->chip_id = stv0367_readreg(state, 0xf000); - - dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id); - - /* check if the demod is there */ - if ((state->chip_id != 0x50) && (state->chip_id != 0x60)) - goto error; - - return &state->fe; - -error: - kfree(cab_state); - kfree(state); - return NULL; -} -EXPORT_SYMBOL(stv0367cab_attach); - -MODULE_PARM_DESC(debug, "Set debug"); -MODULE_PARM_DESC(i2c_debug, "Set i2c debug"); - -MODULE_AUTHOR("Igor M. Liplianin"); -MODULE_DESCRIPTION("ST STV0367 DVB-C/T demodulator driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/* - * stv0367.h - * - * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. - * - * Copyright (C) ST Microelectronics. - * Copyright (C) 2010,2011 NetUP Inc. - * Copyright (C) 2010,2011 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef STV0367_H -#define STV0367_H - -#include -#include "dvb_frontend.h" - -struct stv0367_config { - u8 demod_address; - u32 xtal; - u32 if_khz;/*4500*/ - int if_iq_mode; - int ts_mode; - int clk_pol; -}; - -#if defined(CONFIG_DVB_STV0367) || (defined(CONFIG_DVB_STV0367_MODULE) \ - && defined(MODULE)) -extern struct -dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, - struct i2c_adapter *i2c); -extern struct -dvb_frontend *stv0367cab_attach(const struct stv0367_config *config, - struct i2c_adapter *i2c); -#else -static inline struct -dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static inline struct -dvb_frontend *stv0367cab_attach(const struct stv0367_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -/* - * stv0367_priv.h - * - * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. - * - * Copyright (C) ST Microelectronics. - * Copyright (C) 2010,2011 NetUP Inc. - * Copyright (C) 2010,2011 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* Common driver error constants */ - -#ifndef STV0367_PRIV_H -#define STV0367_PRIV_H - -#ifndef TRUE - #define TRUE (1 == 1) -#endif -#ifndef FALSE - #define FALSE (!TRUE) -#endif - -#ifndef NULL -#define NULL 0 -#endif - -/* MACRO definitions */ -#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X)) -#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) -#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) -#define INRANGE(X, Y, Z) \ - ((((X) <= (Y)) && ((Y) <= (Z))) || \ - (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0) - -#ifndef MAKEWORD -#define MAKEWORD(X, Y) (((X) << 8) + (Y)) -#endif - -#define LSB(X) (((X) & 0xff)) -#define MSB(Y) (((Y) >> 8) & 0xff) -#define MMSB(Y)(((Y) >> 16) & 0xff) - -enum stv0367_ter_signal_type { - FE_TER_NOAGC = 0, - FE_TER_AGCOK = 5, - FE_TER_NOTPS = 6, - FE_TER_TPSOK = 7, - FE_TER_NOSYMBOL = 8, - FE_TER_BAD_CPQ = 9, - FE_TER_PRFOUNDOK = 10, - FE_TER_NOPRFOUND = 11, - FE_TER_LOCKOK = 12, - FE_TER_NOLOCK = 13, - FE_TER_SYMBOLOK = 15, - FE_TER_CPAMPOK = 16, - FE_TER_NOCPAMP = 17, - FE_TER_SWNOK = 18 -}; - -enum stv0367_ts_mode { - STV0367_OUTPUTMODE_DEFAULT, - STV0367_SERIAL_PUNCT_CLOCK, - STV0367_SERIAL_CONT_CLOCK, - STV0367_PARALLEL_PUNCT_CLOCK, - STV0367_DVBCI_CLOCK -}; - -enum stv0367_clk_pol { - STV0367_CLOCKPOLARITY_DEFAULT, - STV0367_RISINGEDGE_CLOCK, - STV0367_FALLINGEDGE_CLOCK -}; - -enum stv0367_ter_bw { - FE_TER_CHAN_BW_6M = 6, - FE_TER_CHAN_BW_7M = 7, - FE_TER_CHAN_BW_8M = 8 -}; - -#if 0 -enum FE_TER_Rate_TPS { - FE_TER_TPS_1_2 = 0, - FE_TER_TPS_2_3 = 1, - FE_TER_TPS_3_4 = 2, - FE_TER_TPS_5_6 = 3, - FE_TER_TPS_7_8 = 4 -}; -#endif - -enum stv0367_ter_mode { - FE_TER_MODE_2K, - FE_TER_MODE_8K, - FE_TER_MODE_4K -}; -#if 0 -enum FE_TER_Hierarchy_Alpha { - FE_TER_HIER_ALPHA_NONE, /* Regular modulation */ - FE_TER_HIER_ALPHA_1, /* Hierarchical modulation a = 1*/ - FE_TER_HIER_ALPHA_2, /* Hierarchical modulation a = 2*/ - FE_TER_HIER_ALPHA_4 /* Hierarchical modulation a = 4*/ -}; -#endif -enum stv0367_ter_hierarchy { - FE_TER_HIER_NONE, /*Hierarchy None*/ - FE_TER_HIER_LOW_PRIO, /*Hierarchy : Low Priority*/ - FE_TER_HIER_HIGH_PRIO, /*Hierarchy : High Priority*/ - FE_TER_HIER_PRIO_ANY /*Hierarchy :Any*/ -}; - -#if 0 -enum fe_stv0367_ter_spec { - FE_TER_INVERSION_NONE = 0, - FE_TER_INVERSION = 1, - FE_TER_INVERSION_AUTO = 2, - FE_TER_INVERSION_UNK = 4 -}; -#endif - -enum stv0367_ter_if_iq_mode { - FE_TER_NORMAL_IF_TUNER = 0, - FE_TER_LONGPATH_IF_TUNER = 1, - FE_TER_IQ_TUNER = 2 - -}; - -#if 0 -enum FE_TER_FECRate { - FE_TER_FEC_NONE = 0x00, /* no FEC rate specified */ - FE_TER_FEC_ALL = 0xFF, /* Logical OR of all FECs */ - FE_TER_FEC_1_2 = 1, - FE_TER_FEC_2_3 = (1 << 1), - FE_TER_FEC_3_4 = (1 << 2), - FE_TER_FEC_4_5 = (1 << 3), - FE_TER_FEC_5_6 = (1 << 4), - FE_TER_FEC_6_7 = (1 << 5), - FE_TER_FEC_7_8 = (1 << 6), - FE_TER_FEC_8_9 = (1 << 7) -}; - -enum FE_TER_Rate { - FE_TER_FE_1_2 = 0, - FE_TER_FE_2_3 = 1, - FE_TER_FE_3_4 = 2, - FE_TER_FE_5_6 = 3, - FE_TER_FE_6_7 = 4, - FE_TER_FE_7_8 = 5 -}; -#endif - -enum stv0367_ter_force { - FE_TER_FORCENONE = 0, - FE_TER_FORCE_M_G = 1 -}; - -enum stv0367cab_mod { - FE_CAB_MOD_QAM4, - FE_CAB_MOD_QAM16, - FE_CAB_MOD_QAM32, - FE_CAB_MOD_QAM64, - FE_CAB_MOD_QAM128, - FE_CAB_MOD_QAM256, - FE_CAB_MOD_QAM512, - FE_CAB_MOD_QAM1024 -}; -#if 0 -enum { - FE_CAB_FEC_A = 1, /* J83 Annex A */ - FE_CAB_FEC_B = (1 << 1),/* J83 Annex B */ - FE_CAB_FEC_C = (1 << 2) /* J83 Annex C */ -} FE_CAB_FECType_t; -#endif -struct stv0367_cab_signal_info { - int locked; - u32 frequency; /* kHz */ - u32 symbol_rate; /* Mbds */ - enum stv0367cab_mod modulation; - fe_spectral_inversion_t spect_inv; - s32 Power_dBmx10; /* Power of the RF signal (dBm x 10) */ - u32 CN_dBx10; /* Carrier to noise ratio (dB x 10) */ - u32 BER; /* Bit error rate (x 10000000) */ -}; - -enum stv0367_cab_signal_type { - FE_CAB_NOTUNER, - FE_CAB_NOAGC, - FE_CAB_NOSIGNAL, - FE_CAB_NOTIMING, - FE_CAB_TIMINGOK, - FE_CAB_NOCARRIER, - FE_CAB_CARRIEROK, - FE_CAB_NOBLIND, - FE_CAB_BLINDOK, - FE_CAB_NODEMOD, - FE_CAB_DEMODOK, - FE_CAB_DATAOK -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367_regs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0367_regs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,3614 +0,0 @@ -/* - * stv0367_regs.h - * - * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. - * - * Copyright (C) ST Microelectronics. - * Copyright (C) 2010,2011 NetUP Inc. - * Copyright (C) 2010,2011 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef STV0367_REGS_H -#define STV0367_REGS_H - -/* ID */ -#define R367TER_ID 0xf000 -#define F367TER_IDENTIFICATIONREG 0xf00000ff - -/* I2CRPT */ -#define R367TER_I2CRPT 0xf001 -#define F367TER_I2CT_ON 0xf0010080 -#define F367TER_ENARPT_LEVEL 0xf0010070 -#define F367TER_SCLT_DELAY 0xf0010008 -#define F367TER_SCLT_NOD 0xf0010004 -#define F367TER_STOP_ENABLE 0xf0010002 -#define F367TER_SDAT_NOD 0xf0010001 - -/* TOPCTRL */ -#define R367TER_TOPCTRL 0xf002 -#define F367TER_STDBY 0xf0020080 -#define F367TER_STDBY_FEC 0xf0020040 -#define F367TER_STDBY_CORE 0xf0020020 -#define F367TER_QAM_COFDM 0xf0020010 -#define F367TER_TS_DIS 0xf0020008 -#define F367TER_DIR_CLK_216 0xf0020004 -#define F367TER_TUNER_BB 0xf0020002 -#define F367TER_DVBT_H 0xf0020001 - -/* IOCFG0 */ -#define R367TER_IOCFG0 0xf003 -#define F367TER_OP0_SD 0xf0030080 -#define F367TER_OP0_VAL 0xf0030040 -#define F367TER_OP0_OD 0xf0030020 -#define F367TER_OP0_INV 0xf0030010 -#define F367TER_OP0_DACVALUE_HI 0xf003000f - -/* DAc0R */ -#define R367TER_DAC0R 0xf004 -#define F367TER_OP0_DACVALUE_LO 0xf00400ff - -/* IOCFG1 */ -#define R367TER_IOCFG1 0xf005 -#define F367TER_IP0 0xf0050040 -#define F367TER_OP1_OD 0xf0050020 -#define F367TER_OP1_INV 0xf0050010 -#define F367TER_OP1_DACVALUE_HI 0xf005000f - -/* DAC1R */ -#define R367TER_DAC1R 0xf006 -#define F367TER_OP1_DACVALUE_LO 0xf00600ff - -/* IOCFG2 */ -#define R367TER_IOCFG2 0xf007 -#define F367TER_OP2_LOCK_CONF 0xf00700e0 -#define F367TER_OP2_OD 0xf0070010 -#define F367TER_OP2_VAL 0xf0070008 -#define F367TER_OP1_LOCK_CONF 0xf0070007 - -/* SDFR */ -#define R367TER_SDFR 0xf008 -#define F367TER_OP0_FREQ 0xf00800f0 -#define F367TER_OP1_FREQ 0xf008000f - -/* STATUS */ -#define R367TER_STATUS 0xf009 -#define F367TER_TPS_LOCK 0xf0090080 -#define F367TER_SYR_LOCK 0xf0090040 -#define F367TER_AGC_LOCK 0xf0090020 -#define F367TER_PRF 0xf0090010 -#define F367TER_LK 0xf0090008 -#define F367TER_PR 0xf0090007 - -/* AUX_CLK */ -#define R367TER_AUX_CLK 0xf00a -#define F367TER_AUXFEC_CTL 0xf00a00c0 -#define F367TER_DIS_CKX4 0xf00a0020 -#define F367TER_CKSEL 0xf00a0018 -#define F367TER_CKDIV_PROG 0xf00a0006 -#define F367TER_AUXCLK_ENA 0xf00a0001 - -/* FREESYS1 */ -#define R367TER_FREESYS1 0xf00b -#define F367TER_FREE_SYS1 0xf00b00ff - -/* FREESYS2 */ -#define R367TER_FREESYS2 0xf00c -#define F367TER_FREE_SYS2 0xf00c00ff - -/* FREESYS3 */ -#define R367TER_FREESYS3 0xf00d -#define F367TER_FREE_SYS3 0xf00d00ff - -/* GPIO_CFG */ -#define R367TER_GPIO_CFG 0xf00e -#define F367TER_GPIO7_NOD 0xf00e0080 -#define F367TER_GPIO7_CFG 0xf00e0040 -#define F367TER_GPIO6_NOD 0xf00e0020 -#define F367TER_GPIO6_CFG 0xf00e0010 -#define F367TER_GPIO5_NOD 0xf00e0008 -#define F367TER_GPIO5_CFG 0xf00e0004 -#define F367TER_GPIO4_NOD 0xf00e0002 -#define F367TER_GPIO4_CFG 0xf00e0001 - -/* GPIO_CMD */ -#define R367TER_GPIO_CMD 0xf00f -#define F367TER_GPIO7_VAL 0xf00f0008 -#define F367TER_GPIO6_VAL 0xf00f0004 -#define F367TER_GPIO5_VAL 0xf00f0002 -#define F367TER_GPIO4_VAL 0xf00f0001 - -/* AGC2MAX */ -#define R367TER_AGC2MAX 0xf010 -#define F367TER_AGC2_MAX 0xf01000ff - -/* AGC2MIN */ -#define R367TER_AGC2MIN 0xf011 -#define F367TER_AGC2_MIN 0xf01100ff - -/* AGC1MAX */ -#define R367TER_AGC1MAX 0xf012 -#define F367TER_AGC1_MAX 0xf01200ff - -/* AGC1MIN */ -#define R367TER_AGC1MIN 0xf013 -#define F367TER_AGC1_MIN 0xf01300ff - -/* AGCR */ -#define R367TER_AGCR 0xf014 -#define F367TER_RATIO_A 0xf01400e0 -#define F367TER_RATIO_B 0xf0140018 -#define F367TER_RATIO_C 0xf0140007 - -/* AGC2TH */ -#define R367TER_AGC2TH 0xf015 -#define F367TER_AGC2_THRES 0xf01500ff - -/* AGC12c */ -#define R367TER_AGC12C 0xf016 -#define F367TER_AGC1_IV 0xf0160080 -#define F367TER_AGC1_OD 0xf0160040 -#define F367TER_AGC1_LOAD 0xf0160020 -#define F367TER_AGC2_IV 0xf0160010 -#define F367TER_AGC2_OD 0xf0160008 -#define F367TER_AGC2_LOAD 0xf0160004 -#define F367TER_AGC12_MODE 0xf0160003 - -/* AGCCTRL1 */ -#define R367TER_AGCCTRL1 0xf017 -#define F367TER_DAGC_ON 0xf0170080 -#define F367TER_INVERT_AGC12 0xf0170040 -#define F367TER_AGC1_MODE 0xf0170008 -#define F367TER_AGC2_MODE 0xf0170007 - -/* AGCCTRL2 */ -#define R367TER_AGCCTRL2 0xf018 -#define F367TER_FRZ2_CTRL 0xf0180060 -#define F367TER_FRZ1_CTRL 0xf0180018 -#define F367TER_TIME_CST 0xf0180007 - -/* AGC1VAL1 */ -#define R367TER_AGC1VAL1 0xf019 -#define F367TER_AGC1_VAL_LO 0xf01900ff - -/* AGC1VAL2 */ -#define R367TER_AGC1VAL2 0xf01a -#define F367TER_AGC1_VAL_HI 0xf01a000f - -/* AGC2VAL1 */ -#define R367TER_AGC2VAL1 0xf01b -#define F367TER_AGC2_VAL_LO 0xf01b00ff - -/* AGC2VAL2 */ -#define R367TER_AGC2VAL2 0xf01c -#define F367TER_AGC2_VAL_HI 0xf01c000f - -/* AGC2PGA */ -#define R367TER_AGC2PGA 0xf01d -#define F367TER_AGC2_PGA 0xf01d00ff - -/* OVF_RATE1 */ -#define R367TER_OVF_RATE1 0xf01e -#define F367TER_OVF_RATE_HI 0xf01e000f - -/* OVF_RATE2 */ -#define R367TER_OVF_RATE2 0xf01f -#define F367TER_OVF_RATE_LO 0xf01f00ff - -/* GAIN_SRC1 */ -#define R367TER_GAIN_SRC1 0xf020 -#define F367TER_INV_SPECTR 0xf0200080 -#define F367TER_IQ_INVERT 0xf0200040 -#define F367TER_INR_BYPASS 0xf0200020 -#define F367TER_STATUS_INV_SPECRUM 0xf0200010 -#define F367TER_GAIN_SRC_HI 0xf020000f - -/* GAIN_SRC2 */ -#define R367TER_GAIN_SRC2 0xf021 -#define F367TER_GAIN_SRC_LO 0xf02100ff - -/* INC_DEROT1 */ -#define R367TER_INC_DEROT1 0xf022 -#define F367TER_INC_DEROT_HI 0xf02200ff - -/* INC_DEROT2 */ -#define R367TER_INC_DEROT2 0xf023 -#define F367TER_INC_DEROT_LO 0xf02300ff - -/* PPM_CPAMP_DIR */ -#define R367TER_PPM_CPAMP_DIR 0xf024 -#define F367TER_PPM_CPAMP_DIRECT 0xf02400ff - -/* PPM_CPAMP_INV */ -#define R367TER_PPM_CPAMP_INV 0xf025 -#define F367TER_PPM_CPAMP_INVER 0xf02500ff - -/* FREESTFE_1 */ -#define R367TER_FREESTFE_1 0xf026 -#define F367TER_SYMBOL_NUMBER_INC 0xf02600c0 -#define F367TER_SEL_LSB 0xf0260004 -#define F367TER_AVERAGE_ON 0xf0260002 -#define F367TER_DC_ADJ 0xf0260001 - -/* FREESTFE_2 */ -#define R367TER_FREESTFE_2 0xf027 -#define F367TER_SEL_SRCOUT 0xf02700c0 -#define F367TER_SEL_SYRTHR 0xf027001f - -/* DCOFFSET */ -#define R367TER_DCOFFSET 0xf028 -#define F367TER_SELECT_I_Q 0xf0280080 -#define F367TER_DC_OFFSET 0xf028007f - -/* EN_PROCESS */ -#define R367TER_EN_PROCESS 0xf029 -#define F367TER_FREE 0xf02900f0 -#define F367TER_ENAB_MANUAL 0xf0290001 - -/* SDI_SMOOTHER */ -#define R367TER_SDI_SMOOTHER 0xf02a -#define F367TER_DIS_SMOOTH 0xf02a0080 -#define F367TER_SDI_INC_SMOOTHER 0xf02a007f - -/* FE_LOOP_OPEN */ -#define R367TER_FE_LOOP_OPEN 0xf02b -#define F367TER_TRL_LOOP_OP 0xf02b0002 -#define F367TER_CRL_LOOP_OP 0xf02b0001 - -/* FREQOFF1 */ -#define R367TER_FREQOFF1 0xf02c -#define F367TER_FREQ_OFFSET_LOOP_OPEN_VHI 0xf02c00ff - -/* FREQOFF2 */ -#define R367TER_FREQOFF2 0xf02d -#define F367TER_FREQ_OFFSET_LOOP_OPEN_HI 0xf02d00ff - -/* FREQOFF3 */ -#define R367TER_FREQOFF3 0xf02e -#define F367TER_FREQ_OFFSET_LOOP_OPEN_LO 0xf02e00ff - -/* TIMOFF1 */ -#define R367TER_TIMOFF1 0xf02f -#define F367TER_TIM_OFFSET_LOOP_OPEN_HI 0xf02f00ff - -/* TIMOFF2 */ -#define R367TER_TIMOFF2 0xf030 -#define F367TER_TIM_OFFSET_LOOP_OPEN_LO 0xf03000ff - -/* EPQ */ -#define R367TER_EPQ 0xf031 -#define F367TER_EPQ1 0xf03100ff - -/* EPQAUTO */ -#define R367TER_EPQAUTO 0xf032 -#define F367TER_EPQ2 0xf03200ff - -/* SYR_UPDATE */ -#define R367TER_SYR_UPDATE 0xf033 -#define F367TER_SYR_PROTV 0xf0330080 -#define F367TER_SYR_PROTV_GAIN 0xf0330060 -#define F367TER_SYR_FILTER 0xf0330010 -#define F367TER_SYR_TRACK_THRES 0xf033000c - -/* CHPFREE */ -#define R367TER_CHPFREE 0xf034 -#define F367TER_CHP_FREE 0xf03400ff - -/* PPM_STATE_MAC */ -#define R367TER_PPM_STATE_MAC 0xf035 -#define F367TER_PPM_STATE_MACHINE_DECODER 0xf035003f - -/* INR_THRESHOLD */ -#define R367TER_INR_THRESHOLD 0xf036 -#define F367TER_INR_THRESH 0xf03600ff - -/* EPQ_TPS_ID_CELL */ -#define R367TER_EPQ_TPS_ID_CELL 0xf037 -#define F367TER_ENABLE_LGTH_TO_CF 0xf0370080 -#define F367TER_DIS_TPS_RSVD 0xf0370040 -#define F367TER_DIS_BCH 0xf0370020 -#define F367TER_DIS_ID_CEL 0xf0370010 -#define F367TER_TPS_ADJUST_SYM 0xf037000f - -/* EPQ_CFG */ -#define R367TER_EPQ_CFG 0xf038 -#define F367TER_EPQ_RANGE 0xf0380002 -#define F367TER_EPQ_SOFT 0xf0380001 - -/* EPQ_STATUS */ -#define R367TER_EPQ_STATUS 0xf039 -#define F367TER_SLOPE_INC 0xf03900fc -#define F367TER_TPS_FIELD 0xf0390003 - -/* AUTORELOCK */ -#define R367TER_AUTORELOCK 0xf03a -#define F367TER_BYPASS_BER_TEMPO 0xf03a0080 -#define F367TER_BER_TEMPO 0xf03a0070 -#define F367TER_BYPASS_COFDM_TEMPO 0xf03a0008 -#define F367TER_COFDM_TEMPO 0xf03a0007 - -/* BER_THR_VMSB */ -#define R367TER_BER_THR_VMSB 0xf03b -#define F367TER_BER_THRESHOLD_HI 0xf03b00ff - -/* BER_THR_MSB */ -#define R367TER_BER_THR_MSB 0xf03c -#define F367TER_BER_THRESHOLD_MID 0xf03c00ff - -/* BER_THR_LSB */ -#define R367TER_BER_THR_LSB 0xf03d -#define F367TER_BER_THRESHOLD_LO 0xf03d00ff - -/* CCD */ -#define R367TER_CCD 0xf03e -#define F367TER_CCD_DETECTED 0xf03e0080 -#define F367TER_CCD_RESET 0xf03e0040 -#define F367TER_CCD_THRESHOLD 0xf03e000f - -/* SPECTR_CFG */ -#define R367TER_SPECTR_CFG 0xf03f -#define F367TER_SPECT_CFG 0xf03f0003 - -/* CONSTMU_MSB */ -#define R367TER_CONSTMU_MSB 0xf040 -#define F367TER_CONSTMU_FREEZE 0xf0400080 -#define F367TER_CONSTNU_FORCE_EN 0xf0400040 -#define F367TER_CONST_MU_MSB 0xf040003f - -/* CONSTMU_LSB */ -#define R367TER_CONSTMU_LSB 0xf041 -#define F367TER_CONST_MU_LSB 0xf04100ff - -/* CONSTMU_MAX_MSB */ -#define R367TER_CONSTMU_MAX_MSB 0xf042 -#define F367TER_CONST_MU_MAX_MSB 0xf042003f - -/* CONSTMU_MAX_LSB */ -#define R367TER_CONSTMU_MAX_LSB 0xf043 -#define F367TER_CONST_MU_MAX_LSB 0xf04300ff - -/* ALPHANOISE */ -#define R367TER_ALPHANOISE 0xf044 -#define F367TER_USE_ALLFILTER 0xf0440080 -#define F367TER_INTER_ON 0xf0440040 -#define F367TER_ALPHA_NOISE 0xf044001f - -/* MAXGP_MSB */ -#define R367TER_MAXGP_MSB 0xf045 -#define F367TER_MUFILTER_LENGTH 0xf04500f0 -#define F367TER_MAX_GP_MSB 0xf045000f - -/* MAXGP_LSB */ -#define R367TER_MAXGP_LSB 0xf046 -#define F367TER_MAX_GP_LSB 0xf04600ff - -/* ALPHAMSB */ -#define R367TER_ALPHAMSB 0xf047 -#define F367TER_CHC_DATARATE 0xf04700c0 -#define F367TER_ALPHA_MSB 0xf047003f - -/* ALPHALSB */ -#define R367TER_ALPHALSB 0xf048 -#define F367TER_ALPHA_LSB 0xf04800ff - -/* PILOT_ACCU */ -#define R367TER_PILOT_ACCU 0xf049 -#define F367TER_USE_SCAT4ADDAPT 0xf0490080 -#define F367TER_PILOT_ACC 0xf049001f - -/* PILOTMU_ACCU */ -#define R367TER_PILOTMU_ACCU 0xf04a -#define F367TER_DISCARD_BAD_SP 0xf04a0080 -#define F367TER_DISCARD_BAD_CP 0xf04a0040 -#define F367TER_PILOT_MU_ACCU 0xf04a001f - -/* FILT_CHANNEL_EST */ -#define R367TER_FILT_CHANNEL_EST 0xf04b -#define F367TER_USE_FILT_PILOT 0xf04b0080 -#define F367TER_FILT_CHANNEL 0xf04b007f - -/* ALPHA_NOPISE_FREQ */ -#define R367TER_ALPHA_NOPISE_FREQ 0xf04c -#define F367TER_NOISE_FREQ_FILT 0xf04c0040 -#define F367TER_ALPHA_NOISE_FREQ 0xf04c003f - -/* RATIO_PILOT */ -#define R367TER_RATIO_PILOT 0xf04d -#define F367TER_RATIO_MEAN_SP 0xf04d00f0 -#define F367TER_RATIO_MEAN_CP 0xf04d000f - -/* CHC_CTL */ -#define R367TER_CHC_CTL 0xf04e -#define F367TER_TRACK_EN 0xf04e0080 -#define F367TER_NOISE_NORM_EN 0xf04e0040 -#define F367TER_FORCE_CHC_RESET 0xf04e0020 -#define F367TER_SHORT_TIME 0xf04e0010 -#define F367TER_FORCE_STATE_EN 0xf04e0008 -#define F367TER_FORCE_STATE 0xf04e0007 - -/* EPQ_ADJUST */ -#define R367TER_EPQ_ADJUST 0xf04f -#define F367TER_ADJUST_SCAT_IND 0xf04f00c0 -#define F367TER_ONE_SYMBOL 0xf04f0010 -#define F367TER_EPQ_DECAY 0xf04f000e -#define F367TER_HOLD_SLOPE 0xf04f0001 - -/* EPQ_THRES */ -#define R367TER_EPQ_THRES 0xf050 -#define F367TER_EPQ_THR 0xf05000ff - -/* OMEGA_CTL */ -#define R367TER_OMEGA_CTL 0xf051 -#define F367TER_OMEGA_RST 0xf0510080 -#define F367TER_FREEZE_OMEGA 0xf0510040 -#define F367TER_OMEGA_SEL 0xf051003f - -/* GP_CTL */ -#define R367TER_GP_CTL 0xf052 -#define F367TER_CHC_STATE 0xf05200e0 -#define F367TER_FREEZE_GP 0xf0520010 -#define F367TER_GP_SEL 0xf052000f - -/* MUMSB */ -#define R367TER_MUMSB 0xf053 -#define F367TER_MU_MSB 0xf053007f - -/* MULSB */ -#define R367TER_MULSB 0xf054 -#define F367TER_MU_LSB 0xf05400ff - -/* GPMSB */ -#define R367TER_GPMSB 0xf055 -#define F367TER_CSI_THRESHOLD 0xf05500e0 -#define F367TER_GP_MSB 0xf055000f - -/* GPLSB */ -#define R367TER_GPLSB 0xf056 -#define F367TER_GP_LSB 0xf05600ff - -/* OMEGAMSB */ -#define R367TER_OMEGAMSB 0xf057 -#define F367TER_OMEGA_MSB 0xf057007f - -/* OMEGALSB */ -#define R367TER_OMEGALSB 0xf058 -#define F367TER_OMEGA_LSB 0xf05800ff - -/* SCAT_NB */ -#define R367TER_SCAT_NB 0xf059 -#define F367TER_CHC_TEST 0xf05900f8 -#define F367TER_SCAT_NUMB 0xf0590003 - -/* CHC_DUMMY */ -#define R367TER_CHC_DUMMY 0xf05a -#define F367TER_CHC_DUM 0xf05a00ff - -/* INC_CTL */ -#define R367TER_INC_CTL 0xf05b -#define F367TER_INC_BYPASS 0xf05b0080 -#define F367TER_INC_NDEPTH 0xf05b000c -#define F367TER_INC_MADEPTH 0xf05b0003 - -/* INCTHRES_COR1 */ -#define R367TER_INCTHRES_COR1 0xf05c -#define F367TER_INC_THRES_COR1 0xf05c00ff - -/* INCTHRES_COR2 */ -#define R367TER_INCTHRES_COR2 0xf05d -#define F367TER_INC_THRES_COR2 0xf05d00ff - -/* INCTHRES_DET1 */ -#define R367TER_INCTHRES_DET1 0xf05e -#define F367TER_INC_THRES_DET1 0xf05e003f - -/* INCTHRES_DET2 */ -#define R367TER_INCTHRES_DET2 0xf05f -#define F367TER_INC_THRES_DET2 0xf05f003f - -/* IIR_CELLNB */ -#define R367TER_IIR_CELLNB 0xf060 -#define F367TER_NRST_IIR 0xf0600080 -#define F367TER_IIR_CELL_NB 0xf0600007 - -/* IIRCX_COEFF1_MSB */ -#define R367TER_IIRCX_COEFF1_MSB 0xf061 -#define F367TER_IIR_CX_COEFF1_MSB 0xf06100ff - -/* IIRCX_COEFF1_LSB */ -#define R367TER_IIRCX_COEFF1_LSB 0xf062 -#define F367TER_IIR_CX_COEFF1_LSB 0xf06200ff - -/* IIRCX_COEFF2_MSB */ -#define R367TER_IIRCX_COEFF2_MSB 0xf063 -#define F367TER_IIR_CX_COEFF2_MSB 0xf06300ff - -/* IIRCX_COEFF2_LSB */ -#define R367TER_IIRCX_COEFF2_LSB 0xf064 -#define F367TER_IIR_CX_COEFF2_LSB 0xf06400ff - -/* IIRCX_COEFF3_MSB */ -#define R367TER_IIRCX_COEFF3_MSB 0xf065 -#define F367TER_IIR_CX_COEFF3_MSB 0xf06500ff - -/* IIRCX_COEFF3_LSB */ -#define R367TER_IIRCX_COEFF3_LSB 0xf066 -#define F367TER_IIR_CX_COEFF3_LSB 0xf06600ff - -/* IIRCX_COEFF4_MSB */ -#define R367TER_IIRCX_COEFF4_MSB 0xf067 -#define F367TER_IIR_CX_COEFF4_MSB 0xf06700ff - -/* IIRCX_COEFF4_LSB */ -#define R367TER_IIRCX_COEFF4_LSB 0xf068 -#define F367TER_IIR_CX_COEFF4_LSB 0xf06800ff - -/* IIRCX_COEFF5_MSB */ -#define R367TER_IIRCX_COEFF5_MSB 0xf069 -#define F367TER_IIR_CX_COEFF5_MSB 0xf06900ff - -/* IIRCX_COEFF5_LSB */ -#define R367TER_IIRCX_COEFF5_LSB 0xf06a -#define F367TER_IIR_CX_COEFF5_LSB 0xf06a00ff - -/* FEPATH_CFG */ -#define R367TER_FEPATH_CFG 0xf06b -#define F367TER_DEMUX_SWAP 0xf06b0004 -#define F367TER_DIGAGC_SWAP 0xf06b0002 -#define F367TER_LONGPATH_IF 0xf06b0001 - -/* PMC1_FUNC */ -#define R367TER_PMC1_FUNC 0xf06c -#define F367TER_SOFT_RSTN 0xf06c0080 -#define F367TER_PMC1_AVERAGE_TIME 0xf06c0078 -#define F367TER_PMC1_WAIT_TIME 0xf06c0006 -#define F367TER_PMC1_2N_SEL 0xf06c0001 - -/* PMC1_FOR */ -#define R367TER_PMC1_FOR 0xf06d -#define F367TER_PMC1_FORCE 0xf06d0080 -#define F367TER_PMC1_FORCE_VALUE 0xf06d007c - -/* PMC2_FUNC */ -#define R367TER_PMC2_FUNC 0xf06e -#define F367TER_PMC2_SOFT_STN 0xf06e0080 -#define F367TER_PMC2_ACCU_TIME 0xf06e0070 -#define F367TER_PMC2_CMDP_MN 0xf06e0008 -#define F367TER_PMC2_SWAP 0xf06e0004 - -/* STATUS_ERR_DA */ -#define R367TER_STATUS_ERR_DA 0xf06f -#define F367TER_COM_USEGAINTRK 0xf06f0080 -#define F367TER_COM_AGCLOCK 0xf06f0040 -#define F367TER_AUT_AGCLOCK 0xf06f0020 -#define F367TER_MIN_ERR_X_LSB 0xf06f000f - -/* DIG_AGC_R */ -#define R367TER_DIG_AGC_R 0xf070 -#define F367TER_COM_SOFT_RSTN 0xf0700080 -#define F367TER_COM_AGC_ON 0xf0700040 -#define F367TER_COM_EARLY 0xf0700020 -#define F367TER_AUT_SOFT_RESETN 0xf0700010 -#define F367TER_AUT_AGC_ON 0xf0700008 -#define F367TER_AUT_EARLY 0xf0700004 -#define F367TER_AUT_ROT_EN 0xf0700002 -#define F367TER_LOCK_SOFT_RESETN 0xf0700001 - -/* COMAGC_TARMSB */ -#define R367TER_COMAGC_TARMSB 0xf071 -#define F367TER_COM_AGC_TARGET_MSB 0xf07100ff - -/* COM_AGC_TAR_ENMODE */ -#define R367TER_COM_AGC_TAR_ENMODE 0xf072 -#define F367TER_COM_AGC_TARGET_LSB 0xf07200f0 -#define F367TER_COM_ENMODE 0xf072000f - -/* COM_AGC_CFG */ -#define R367TER_COM_AGC_CFG 0xf073 -#define F367TER_COM_N 0xf07300f8 -#define F367TER_COM_STABMODE 0xf0730006 -#define F367TER_ERR_SEL 0xf0730001 - -/* COM_AGC_GAIN1 */ -#define R367TER_COM_AGC_GAIN1 0xf074 -#define F367TER_COM_GAIN1aCK 0xf07400f0 -#define F367TER_COM_GAIN1TRK 0xf074000f - -/* AUT_AGC_TARGETMSB */ -#define R367TER_AUT_AGC_TARGETMSB 0xf075 -#define F367TER_AUT_AGC_TARGET_MSB 0xf07500ff - -/* LOCK_DET_MSB */ -#define R367TER_LOCK_DET_MSB 0xf076 -#define F367TER_LOCK_DETECT_MSB 0xf07600ff - -/* AGCTAR_LOCK_LSBS */ -#define R367TER_AGCTAR_LOCK_LSBS 0xf077 -#define F367TER_AUT_AGC_TARGET_LSB 0xf07700f0 -#define F367TER_LOCK_DETECT_LSB 0xf077000f - -/* AUT_GAIN_EN */ -#define R367TER_AUT_GAIN_EN 0xf078 -#define F367TER_AUT_ENMODE 0xf07800f0 -#define F367TER_AUT_GAIN2 0xf078000f - -/* AUT_CFG */ -#define R367TER_AUT_CFG 0xf079 -#define F367TER_AUT_N 0xf07900f8 -#define F367TER_INT_CHOICE 0xf0790006 -#define F367TER_INT_LOAD 0xf0790001 - -/* LOCKN */ -#define R367TER_LOCKN 0xf07a -#define F367TER_LOCK_N 0xf07a00f8 -#define F367TER_SEL_IQNTAR 0xf07a0004 -#define F367TER_LOCK_DETECT_CHOICE 0xf07a0003 - -/* INT_X_3 */ -#define R367TER_INT_X_3 0xf07b -#define F367TER_INT_X3 0xf07b00ff - -/* INT_X_2 */ -#define R367TER_INT_X_2 0xf07c -#define F367TER_INT_X2 0xf07c00ff - -/* INT_X_1 */ -#define R367TER_INT_X_1 0xf07d -#define F367TER_INT_X1 0xf07d00ff - -/* INT_X_0 */ -#define R367TER_INT_X_0 0xf07e -#define F367TER_INT_X0 0xf07e00ff - -/* MIN_ERRX_MSB */ -#define R367TER_MIN_ERRX_MSB 0xf07f -#define F367TER_MIN_ERR_X_MSB 0xf07f00ff - -/* COR_CTL */ -#define R367TER_COR_CTL 0xf080 -#define F367TER_CORE_ACTIVE 0xf0800020 -#define F367TER_HOLD 0xf0800010 -#define F367TER_CORE_STATE_CTL 0xf080000f - -/* COR_STAT */ -#define R367TER_COR_STAT 0xf081 -#define F367TER_SCATT_LOCKED 0xf0810080 -#define F367TER_TPS_LOCKED 0xf0810040 -#define F367TER_SYR_LOCKED_COR 0xf0810020 -#define F367TER_AGC_LOCKED_STAT 0xf0810010 -#define F367TER_CORE_STATE_STAT 0xf081000f - -/* COR_INTEN */ -#define R367TER_COR_INTEN 0xf082 -#define F367TER_INTEN 0xf0820080 -#define F367TER_INTEN_SYR 0xf0820020 -#define F367TER_INTEN_FFT 0xf0820010 -#define F367TER_INTEN_AGC 0xf0820008 -#define F367TER_INTEN_TPS1 0xf0820004 -#define F367TER_INTEN_TPS2 0xf0820002 -#define F367TER_INTEN_TPS3 0xf0820001 - -/* COR_INTSTAT */ -#define R367TER_COR_INTSTAT 0xf083 -#define F367TER_INTSTAT_SYR 0xf0830020 -#define F367TER_INTSTAT_FFT 0xf0830010 -#define F367TER_INTSAT_AGC 0xf0830008 -#define F367TER_INTSTAT_TPS1 0xf0830004 -#define F367TER_INTSTAT_TPS2 0xf0830002 -#define F367TER_INTSTAT_TPS3 0xf0830001 - -/* COR_MODEGUARD */ -#define R367TER_COR_MODEGUARD 0xf084 -#define F367TER_FORCE 0xf0840010 -#define F367TER_MODE 0xf084000c -#define F367TER_GUARD 0xf0840003 - -/* AGC_CTL */ -#define R367TER_AGC_CTL 0xf085 -#define F367TER_AGC_TIMING_FACTOR 0xf08500e0 -#define F367TER_AGC_LAST 0xf0850010 -#define F367TER_AGC_GAIN 0xf085000c -#define F367TER_AGC_NEG 0xf0850002 -#define F367TER_AGC_SET 0xf0850001 - -/* AGC_MANUAL1 */ -#define R367TER_AGC_MANUAL1 0xf086 -#define F367TER_AGC_VAL_LO 0xf08600ff - -/* AGC_MANUAL2 */ -#define R367TER_AGC_MANUAL2 0xf087 -#define F367TER_AGC_VAL_HI 0xf087000f - -/* AGC_TARG */ -#define R367TER_AGC_TARG 0xf088 -#define F367TER_AGC_TARGET 0xf08800ff - -/* AGC_GAIN1 */ -#define R367TER_AGC_GAIN1 0xf089 -#define F367TER_AGC_GAIN_LO 0xf08900ff - -/* AGC_GAIN2 */ -#define R367TER_AGC_GAIN2 0xf08a -#define F367TER_AGC_LOCKED_GAIN2 0xf08a0010 -#define F367TER_AGC_GAIN_HI 0xf08a000f - -/* RESERVED_1 */ -#define R367TER_RESERVED_1 0xf08b -#define F367TER_RESERVED1 0xf08b00ff - -/* RESERVED_2 */ -#define R367TER_RESERVED_2 0xf08c -#define F367TER_RESERVED2 0xf08c00ff - -/* RESERVED_3 */ -#define R367TER_RESERVED_3 0xf08d -#define F367TER_RESERVED3 0xf08d00ff - -/* CAS_CTL */ -#define R367TER_CAS_CTL 0xf08e -#define F367TER_CCS_ENABLE 0xf08e0080 -#define F367TER_ACS_DISABLE 0xf08e0040 -#define F367TER_DAGC_DIS 0xf08e0020 -#define F367TER_DAGC_GAIN 0xf08e0018 -#define F367TER_CCSMU 0xf08e0007 - -/* CAS_FREQ */ -#define R367TER_CAS_FREQ 0xf08f -#define F367TER_CCS_FREQ 0xf08f00ff - -/* CAS_DAGCGAIN */ -#define R367TER_CAS_DAGCGAIN 0xf090 -#define F367TER_CAS_DAGC_GAIN 0xf09000ff - -/* SYR_CTL */ -#define R367TER_SYR_CTL 0xf091 -#define F367TER_SICTH_ENABLE 0xf0910080 -#define F367TER_LONG_ECHO 0xf0910078 -#define F367TER_AUTO_LE_EN 0xf0910004 -#define F367TER_SYR_BYPASS 0xf0910002 -#define F367TER_SYR_TR_DIS 0xf0910001 - -/* SYR_STAT */ -#define R367TER_SYR_STAT 0xf092 -#define F367TER_SYR_LOCKED_STAT 0xf0920010 -#define F367TER_SYR_MODE 0xf092000c -#define F367TER_SYR_GUARD 0xf0920003 - -/* SYR_NCO1 */ -#define R367TER_SYR_NCO1 0xf093 -#define F367TER_SYR_NCO_LO 0xf09300ff - -/* SYR_NCO2 */ -#define R367TER_SYR_NCO2 0xf094 -#define F367TER_SYR_NCO_HI 0xf094003f - -/* SYR_OFFSET1 */ -#define R367TER_SYR_OFFSET1 0xf095 -#define F367TER_SYR_OFFSET_LO 0xf09500ff - -/* SYR_OFFSET2 */ -#define R367TER_SYR_OFFSET2 0xf096 -#define F367TER_SYR_OFFSET_HI 0xf096003f - -/* FFT_CTL */ -#define R367TER_FFT_CTL 0xf097 -#define F367TER_SHIFT_FFT_TRIG 0xf0970018 -#define F367TER_FFT_TRIGGER 0xf0970004 -#define F367TER_FFT_MANUAL 0xf0970002 -#define F367TER_IFFT_MODE 0xf0970001 - -/* SCR_CTL */ -#define R367TER_SCR_CTL 0xf098 -#define F367TER_SYRADJDECAY 0xf0980070 -#define F367TER_SCR_CPEDIS 0xf0980002 -#define F367TER_SCR_DIS 0xf0980001 - -/* PPM_CTL1 */ -#define R367TER_PPM_CTL1 0xf099 -#define F367TER_PPM_MAXFREQ 0xf0990030 -#define F367TER_PPM_MAXTIM 0xf0990008 -#define F367TER_PPM_INVSEL 0xf0990004 -#define F367TER_PPM_SCATDIS 0xf0990002 -#define F367TER_PPM_BYP 0xf0990001 - -/* TRL_CTL */ -#define R367TER_TRL_CTL 0xf09a -#define F367TER_TRL_NOMRATE_LSB 0xf09a0080 -#define F367TER_TRL_GAIN_FACTOR 0xf09a0078 -#define F367TER_TRL_LOOPGAIN 0xf09a0007 - -/* TRL_NOMRATE1 */ -#define R367TER_TRL_NOMRATE1 0xf09b -#define F367TER_TRL_NOMRATE_LO 0xf09b00ff - -/* TRL_NOMRATE2 */ -#define R367TER_TRL_NOMRATE2 0xf09c -#define F367TER_TRL_NOMRATE_HI 0xf09c00ff - -/* TRL_TIME1 */ -#define R367TER_TRL_TIME1 0xf09d -#define F367TER_TRL_TOFFSET_LO 0xf09d00ff - -/* TRL_TIME2 */ -#define R367TER_TRL_TIME2 0xf09e -#define F367TER_TRL_TOFFSET_HI 0xf09e00ff - -/* CRL_CTL */ -#define R367TER_CRL_CTL 0xf09f -#define F367TER_CRL_DIS 0xf09f0080 -#define F367TER_CRL_GAIN_FACTOR 0xf09f0078 -#define F367TER_CRL_LOOPGAIN 0xf09f0007 - -/* CRL_FREQ1 */ -#define R367TER_CRL_FREQ1 0xf0a0 -#define F367TER_CRL_FOFFSET_LO 0xf0a000ff - -/* CRL_FREQ2 */ -#define R367TER_CRL_FREQ2 0xf0a1 -#define F367TER_CRL_FOFFSET_HI 0xf0a100ff - -/* CRL_FREQ3 */ -#define R367TER_CRL_FREQ3 0xf0a2 -#define F367TER_CRL_FOFFSET_VHI 0xf0a200ff - -/* TPS_SFRAME_CTL */ -#define R367TER_TPS_SFRAME_CTL 0xf0a3 -#define F367TER_TPS_SFRAME_SYNC 0xf0a30001 - -/* CHC_SNR */ -#define R367TER_CHC_SNR 0xf0a4 -#define F367TER_CHCSNR 0xf0a400ff - -/* BDI_CTL */ -#define R367TER_BDI_CTL 0xf0a5 -#define F367TER_BDI_LPSEL 0xf0a50002 -#define F367TER_BDI_SERIAL 0xf0a50001 - -/* DMP_CTL */ -#define R367TER_DMP_CTL 0xf0a6 -#define F367TER_DMP_SCALING_FACTOR 0xf0a6001e -#define F367TER_DMP_SDDIS 0xf0a60001 - -/* TPS_RCVD1 */ -#define R367TER_TPS_RCVD1 0xf0a7 -#define F367TER_TPS_CHANGE 0xf0a70040 -#define F367TER_BCH_OK 0xf0a70020 -#define F367TER_TPS_SYNC 0xf0a70010 -#define F367TER_TPS_FRAME 0xf0a70003 - -/* TPS_RCVD2 */ -#define R367TER_TPS_RCVD2 0xf0a8 -#define F367TER_TPS_HIERMODE 0xf0a80070 -#define F367TER_TPS_CONST 0xf0a80003 - -/* TPS_RCVD3 */ -#define R367TER_TPS_RCVD3 0xf0a9 -#define F367TER_TPS_LPCODE 0xf0a90070 -#define F367TER_TPS_HPCODE 0xf0a90007 - -/* TPS_RCVD4 */ -#define R367TER_TPS_RCVD4 0xf0aa -#define F367TER_TPS_GUARD 0xf0aa0030 -#define F367TER_TPS_MODE 0xf0aa0003 - -/* TPS_ID_CELL1 */ -#define R367TER_TPS_ID_CELL1 0xf0ab -#define F367TER_TPS_ID_CELL_LO 0xf0ab00ff - -/* TPS_ID_CELL2 */ -#define R367TER_TPS_ID_CELL2 0xf0ac -#define F367TER_TPS_ID_CELL_HI 0xf0ac00ff - -/* TPS_RCVD5_SET1 */ -#define R367TER_TPS_RCVD5_SET1 0xf0ad -#define F367TER_TPS_NA 0xf0ad00fC -#define F367TER_TPS_SETFRAME 0xf0ad0003 - -/* TPS_SET2 */ -#define R367TER_TPS_SET2 0xf0ae -#define F367TER_TPS_SETHIERMODE 0xf0ae0070 -#define F367TER_TPS_SETCONST 0xf0ae0003 - -/* TPS_SET3 */ -#define R367TER_TPS_SET3 0xf0af -#define F367TER_TPS_SETLPCODE 0xf0af0070 -#define F367TER_TPS_SETHPCODE 0xf0af0007 - -/* TPS_CTL */ -#define R367TER_TPS_CTL 0xf0b0 -#define F367TER_TPS_IMM 0xf0b00004 -#define F367TER_TPS_BCHDIS 0xf0b00002 -#define F367TER_TPS_UPDDIS 0xf0b00001 - -/* CTL_FFTOSNUM */ -#define R367TER_CTL_FFTOSNUM 0xf0b1 -#define F367TER_SYMBOL_NUMBER 0xf0b1007f - -/* TESTSELECT */ -#define R367TER_TESTSELECT 0xf0b2 -#define F367TER_TEST_SELECT 0xf0b2001f - -/* MSC_REV */ -#define R367TER_MSC_REV 0xf0b3 -#define F367TER_REV_NUMBER 0xf0b300ff - -/* PIR_CTL */ -#define R367TER_PIR_CTL 0xf0b4 -#define F367TER_FREEZE 0xf0b40001 - -/* SNR_CARRIER1 */ -#define R367TER_SNR_CARRIER1 0xf0b5 -#define F367TER_SNR_CARRIER_LO 0xf0b500ff - -/* SNR_CARRIER2 */ -#define R367TER_SNR_CARRIER2 0xf0b6 -#define F367TER_MEAN 0xf0b600c0 -#define F367TER_SNR_CARRIER_HI 0xf0b6001f - -/* PPM_CPAMP */ -#define R367TER_PPM_CPAMP 0xf0b7 -#define F367TER_PPM_CPC 0xf0b700ff - -/* TSM_AP0 */ -#define R367TER_TSM_AP0 0xf0b8 -#define F367TER_ADDRESS_BYTE_0 0xf0b800ff - -/* TSM_AP1 */ -#define R367TER_TSM_AP1 0xf0b9 -#define F367TER_ADDRESS_BYTE_1 0xf0b900ff - -/* TSM_AP2 */ -#define R367TER_TSM_AP2 0xf0bA -#define F367TER_DATA_BYTE_0 0xf0ba00ff - -/* TSM_AP3 */ -#define R367TER_TSM_AP3 0xf0bB -#define F367TER_DATA_BYTE_1 0xf0bb00ff - -/* TSM_AP4 */ -#define R367TER_TSM_AP4 0xf0bC -#define F367TER_DATA_BYTE_2 0xf0bc00ff - -/* TSM_AP5 */ -#define R367TER_TSM_AP5 0xf0bD -#define F367TER_DATA_BYTE_3 0xf0bd00ff - -/* TSM_AP6 */ -#define R367TER_TSM_AP6 0xf0bE -#define F367TER_TSM_AP_6 0xf0be00ff - -/* TSM_AP7 */ -#define R367TER_TSM_AP7 0xf0bF -#define F367TER_MEM_SELECT_BYTE 0xf0bf00ff - -/* TSTRES */ -#define R367TER_TSTRES 0xf0c0 -#define F367TER_FRES_DISPLAY 0xf0c00080 -#define F367TER_FRES_FIFO_AD 0xf0c00020 -#define F367TER_FRESRS 0xf0c00010 -#define F367TER_FRESACS 0xf0c00008 -#define F367TER_FRESFEC 0xf0c00004 -#define F367TER_FRES_PRIF 0xf0c00002 -#define F367TER_FRESCORE 0xf0c00001 - -/* ANACTRL */ -#define R367TER_ANACTRL 0xf0c1 -#define F367TER_BYPASS_XTAL 0xf0c10040 -#define F367TER_BYPASS_PLLXN 0xf0c1000c -#define F367TER_DIS_PAD_OSC 0xf0c10002 -#define F367TER_STDBY_PLLXN 0xf0c10001 - -/* TSTBUS */ -#define R367TER_TSTBUS 0xf0c2 -#define F367TER_TS_BYTE_CLK_INV 0xf0c20080 -#define F367TER_CFG_IP 0xf0c20070 -#define F367TER_CFG_TST 0xf0c2000f - -/* TSTRATE */ -#define R367TER_TSTRATE 0xf0c6 -#define F367TER_FORCEPHA 0xf0c60080 -#define F367TER_FNEWPHA 0xf0c60010 -#define F367TER_FROT90 0xf0c60008 -#define F367TER_FR 0xf0c60007 - -/* CONSTMODE */ -#define R367TER_CONSTMODE 0xf0cb -#define F367TER_TST_PRIF 0xf0cb00e0 -#define F367TER_CAR_TYPE 0xf0cb0018 -#define F367TER_CONST_MODE 0xf0cb0003 - -/* CONSTCARR1 */ -#define R367TER_CONSTCARR1 0xf0cc -#define F367TER_CONST_CARR_LO 0xf0cc00ff - -/* CONSTCARR2 */ -#define R367TER_CONSTCARR2 0xf0cd -#define F367TER_CONST_CARR_HI 0xf0cd001f - -/* ICONSTEL */ -#define R367TER_ICONSTEL 0xf0ce -#define F367TER_PICONSTEL 0xf0ce00ff - -/* QCONSTEL */ -#define R367TER_QCONSTEL 0xf0cf -#define F367TER_PQCONSTEL 0xf0cf00ff - -/* TSTBISTRES0 */ -#define R367TER_TSTBISTRES0 0xf0d0 -#define F367TER_BEND_PPM 0xf0d00080 -#define F367TER_BBAD_PPM 0xf0d00040 -#define F367TER_BEND_FFTW 0xf0d00020 -#define F367TER_BBAD_FFTW 0xf0d00010 -#define F367TER_BEND_FFT_BUF 0xf0d00008 -#define F367TER_BBAD_FFT_BUF 0xf0d00004 -#define F367TER_BEND_SYR 0xf0d00002 -#define F367TER_BBAD_SYR 0xf0d00001 - -/* TSTBISTRES1 */ -#define R367TER_TSTBISTRES1 0xf0d1 -#define F367TER_BEND_CHC_CP 0xf0d10080 -#define F367TER_BBAD_CHC_CP 0xf0d10040 -#define F367TER_BEND_CHCI 0xf0d10020 -#define F367TER_BBAD_CHCI 0xf0d10010 -#define F367TER_BEND_BDI 0xf0d10008 -#define F367TER_BBAD_BDI 0xf0d10004 -#define F367TER_BEND_SDI 0xf0d10002 -#define F367TER_BBAD_SDI 0xf0d10001 - -/* TSTBISTRES2 */ -#define R367TER_TSTBISTRES2 0xf0d2 -#define F367TER_BEND_CHC_INC 0xf0d20080 -#define F367TER_BBAD_CHC_INC 0xf0d20040 -#define F367TER_BEND_CHC_SPP 0xf0d20020 -#define F367TER_BBAD_CHC_SPP 0xf0d20010 -#define F367TER_BEND_CHC_CPP 0xf0d20008 -#define F367TER_BBAD_CHC_CPP 0xf0d20004 -#define F367TER_BEND_CHC_SP 0xf0d20002 -#define F367TER_BBAD_CHC_SP 0xf0d20001 - -/* TSTBISTRES3 */ -#define R367TER_TSTBISTRES3 0xf0d3 -#define F367TER_BEND_QAM 0xf0d30080 -#define F367TER_BBAD_QAM 0xf0d30040 -#define F367TER_BEND_SFEC_VIT 0xf0d30020 -#define F367TER_BBAD_SFEC_VIT 0xf0d30010 -#define F367TER_BEND_SFEC_DLINE 0xf0d30008 -#define F367TER_BBAD_SFEC_DLINE 0xf0d30004 -#define F367TER_BEND_SFEC_HW 0xf0d30002 -#define F367TER_BBAD_SFEC_HW 0xf0d30001 - -/* RF_AGC1 */ -#define R367TER_RF_AGC1 0xf0d4 -#define F367TER_RF_AGC1_LEVEL_HI 0xf0d400ff - -/* RF_AGC2 */ -#define R367TER_RF_AGC2 0xf0d5 -#define F367TER_REF_ADGP 0xf0d50080 -#define F367TER_STDBY_ADCGP 0xf0d50020 -#define F367TER_CHANNEL_SEL 0xf0d5001c -#define F367TER_RF_AGC1_LEVEL_LO 0xf0d50003 - -/* ANADIGCTRL */ -#define R367TER_ANADIGCTRL 0xf0d7 -#define F367TER_SEL_CLKDEM 0xf0d70020 -#define F367TER_EN_BUFFER_Q 0xf0d70010 -#define F367TER_EN_BUFFER_I 0xf0d70008 -#define F367TER_ADC_RIS_EGDE 0xf0d70004 -#define F367TER_SGN_ADC 0xf0d70002 -#define F367TER_SEL_AD12_SYNC 0xf0d70001 - -/* PLLMDIV */ -#define R367TER_PLLMDIV 0xf0d8 -#define F367TER_PLL_MDIV 0xf0d800ff - -/* PLLNDIV */ -#define R367TER_PLLNDIV 0xf0d9 -#define F367TER_PLL_NDIV 0xf0d900ff - -/* PLLSETUP */ -#define R367TER_PLLSETUP 0xf0dA -#define F367TER_PLL_PDIV 0xf0da0070 -#define F367TER_PLL_KDIV 0xf0da000f - -/* DUAL_AD12 */ -#define R367TER_DUAL_AD12 0xf0dB -#define F367TER_FS20M 0xf0db0020 -#define F367TER_FS50M 0xf0db0010 -#define F367TER_INMODe0 0xf0db0008 -#define F367TER_POFFQ 0xf0db0004 -#define F367TER_POFFI 0xf0db0002 -#define F367TER_INMODE1 0xf0db0001 - -/* TSTBIST */ -#define R367TER_TSTBIST 0xf0dC -#define F367TER_TST_BYP_CLK 0xf0dc0080 -#define F367TER_TST_GCLKENA_STD 0xf0dc0040 -#define F367TER_TST_GCLKENA 0xf0dc0020 -#define F367TER_TST_MEMBIST 0xf0dc001f - -/* PAD_COMP_CTRL */ -#define R367TER_PAD_COMP_CTRL 0xf0dD -#define F367TER_COMPTQ 0xf0dd0010 -#define F367TER_COMPEN 0xf0dd0008 -#define F367TER_FREEZE2 0xf0dd0004 -#define F367TER_SLEEP_INHBT 0xf0dd0002 -#define F367TER_CHIP_SLEEP 0xf0dd0001 - -/* PAD_COMP_WR */ -#define R367TER_PAD_COMP_WR 0xf0de -#define F367TER_WR_ASRC 0xf0de007f - -/* PAD_COMP_RD */ -#define R367TER_PAD_COMP_RD 0xf0df -#define F367TER_COMPOK 0xf0df0080 -#define F367TER_RD_ASRC 0xf0df007f - -/* SYR_TARGET_FFTADJT_MSB */ -#define R367TER_SYR_TARGET_FFTADJT_MSB 0xf100 -#define F367TER_SYR_START 0xf1000080 -#define F367TER_SYR_TARGET_FFTADJ_HI 0xf100000f - -/* SYR_TARGET_FFTADJT_LSB */ -#define R367TER_SYR_TARGET_FFTADJT_LSB 0xf101 -#define F367TER_SYR_TARGET_FFTADJ_LO 0xf10100ff - -/* SYR_TARGET_CHCADJT_MSB */ -#define R367TER_SYR_TARGET_CHCADJT_MSB 0xf102 -#define F367TER_SYR_TARGET_CHCADJ_HI 0xf102000f - -/* SYR_TARGET_CHCADJT_LSB */ -#define R367TER_SYR_TARGET_CHCADJT_LSB 0xf103 -#define F367TER_SYR_TARGET_CHCADJ_LO 0xf10300ff - -/* SYR_FLAG */ -#define R367TER_SYR_FLAG 0xf104 -#define F367TER_TRIG_FLG1 0xf1040080 -#define F367TER_TRIG_FLG0 0xf1040040 -#define F367TER_FFT_FLG1 0xf1040008 -#define F367TER_FFT_FLG0 0xf1040004 -#define F367TER_CHC_FLG1 0xf1040002 -#define F367TER_CHC_FLG0 0xf1040001 - -/* CRL_TARGET1 */ -#define R367TER_CRL_TARGET1 0xf105 -#define F367TER_CRL_START 0xf1050080 -#define F367TER_CRL_TARGET_VHI 0xf105000f - -/* CRL_TARGET2 */ -#define R367TER_CRL_TARGET2 0xf106 -#define F367TER_CRL_TARGET_HI 0xf10600ff - -/* CRL_TARGET3 */ -#define R367TER_CRL_TARGET3 0xf107 -#define F367TER_CRL_TARGET_LO 0xf10700ff - -/* CRL_TARGET4 */ -#define R367TER_CRL_TARGET4 0xf108 -#define F367TER_CRL_TARGET_VLO 0xf10800ff - -/* CRL_FLAG */ -#define R367TER_CRL_FLAG 0xf109 -#define F367TER_CRL_FLAG1 0xf1090002 -#define F367TER_CRL_FLAG0 0xf1090001 - -/* TRL_TARGET1 */ -#define R367TER_TRL_TARGET1 0xf10a -#define F367TER_TRL_TARGET_HI 0xf10a00ff - -/* TRL_TARGET2 */ -#define R367TER_TRL_TARGET2 0xf10b -#define F367TER_TRL_TARGET_LO 0xf10b00ff - -/* TRL_CHC */ -#define R367TER_TRL_CHC 0xf10c -#define F367TER_TRL_START 0xf10c0080 -#define F367TER_CHC_START 0xf10c0040 -#define F367TER_TRL_FLAG1 0xf10c0002 -#define F367TER_TRL_FLAG0 0xf10c0001 - -/* CHC_SNR_TARG */ -#define R367TER_CHC_SNR_TARG 0xf10d -#define F367TER_CHC_SNR_TARGET 0xf10d00ff - -/* TOP_TRACK */ -#define R367TER_TOP_TRACK 0xf10e -#define F367TER_TOP_START 0xf10e0080 -#define F367TER_FIRST_FLAG 0xf10e0070 -#define F367TER_TOP_FLAG1 0xf10e0008 -#define F367TER_TOP_FLAG0 0xf10e0004 -#define F367TER_CHC_FLAG1 0xf10e0002 -#define F367TER_CHC_FLAG0 0xf10e0001 - -/* TRACKER_FREE1 */ -#define R367TER_TRACKER_FREE1 0xf10f -#define F367TER_TRACKER_FREE_1 0xf10f00ff - -/* ERROR_CRL1 */ -#define R367TER_ERROR_CRL1 0xf110 -#define F367TER_ERROR_CRL_VHI 0xf11000ff - -/* ERROR_CRL2 */ -#define R367TER_ERROR_CRL2 0xf111 -#define F367TER_ERROR_CRL_HI 0xf11100ff - -/* ERROR_CRL3 */ -#define R367TER_ERROR_CRL3 0xf112 -#define F367TER_ERROR_CRL_LOI 0xf11200ff - -/* ERROR_CRL4 */ -#define R367TER_ERROR_CRL4 0xf113 -#define F367TER_ERROR_CRL_VLO 0xf11300ff - -/* DEC_NCO1 */ -#define R367TER_DEC_NCO1 0xf114 -#define F367TER_DEC_NCO_VHI 0xf11400ff - -/* DEC_NCO2 */ -#define R367TER_DEC_NCO2 0xf115 -#define F367TER_DEC_NCO_HI 0xf11500ff - -/* DEC_NCO3 */ -#define R367TER_DEC_NCO3 0xf116 -#define F367TER_DEC_NCO_LO 0xf11600ff - -/* SNR */ -#define R367TER_SNR 0xf117 -#define F367TER_SNRATIO 0xf11700ff - -/* SYR_FFTADJ1 */ -#define R367TER_SYR_FFTADJ1 0xf118 -#define F367TER_SYR_FFTADJ_HI 0xf11800ff - -/* SYR_FFTADJ2 */ -#define R367TER_SYR_FFTADJ2 0xf119 -#define F367TER_SYR_FFTADJ_LO 0xf11900ff - -/* SYR_CHCADJ1 */ -#define R367TER_SYR_CHCADJ1 0xf11a -#define F367TER_SYR_CHCADJ_HI 0xf11a00ff - -/* SYR_CHCADJ2 */ -#define R367TER_SYR_CHCADJ2 0xf11b -#define F367TER_SYR_CHCADJ_LO 0xf11b00ff - -/* SYR_OFF */ -#define R367TER_SYR_OFF 0xf11c -#define F367TER_SYR_OFFSET 0xf11c00ff - -/* PPM_OFFSET1 */ -#define R367TER_PPM_OFFSET1 0xf11d -#define F367TER_PPM_OFFSET_HI 0xf11d00ff - -/* PPM_OFFSET2 */ -#define R367TER_PPM_OFFSET2 0xf11e -#define F367TER_PPM_OFFSET_LO 0xf11e00ff - -/* TRACKER_FREE2 */ -#define R367TER_TRACKER_FREE2 0xf11f -#define F367TER_TRACKER_FREE_2 0xf11f00ff - -/* DEBG_LT10 */ -#define R367TER_DEBG_LT10 0xf120 -#define F367TER_DEBUG_LT10 0xf12000ff - -/* DEBG_LT11 */ -#define R367TER_DEBG_LT11 0xf121 -#define F367TER_DEBUG_LT11 0xf12100ff - -/* DEBG_LT12 */ -#define R367TER_DEBG_LT12 0xf122 -#define F367TER_DEBUG_LT12 0xf12200ff - -/* DEBG_LT13 */ -#define R367TER_DEBG_LT13 0xf123 -#define F367TER_DEBUG_LT13 0xf12300ff - -/* DEBG_LT14 */ -#define R367TER_DEBG_LT14 0xf124 -#define F367TER_DEBUG_LT14 0xf12400ff - -/* DEBG_LT15 */ -#define R367TER_DEBG_LT15 0xf125 -#define F367TER_DEBUG_LT15 0xf12500ff - -/* DEBG_LT16 */ -#define R367TER_DEBG_LT16 0xf126 -#define F367TER_DEBUG_LT16 0xf12600ff - -/* DEBG_LT17 */ -#define R367TER_DEBG_LT17 0xf127 -#define F367TER_DEBUG_LT17 0xf12700ff - -/* DEBG_LT18 */ -#define R367TER_DEBG_LT18 0xf128 -#define F367TER_DEBUG_LT18 0xf12800ff - -/* DEBG_LT19 */ -#define R367TER_DEBG_LT19 0xf129 -#define F367TER_DEBUG_LT19 0xf12900ff - -/* DEBG_LT1a */ -#define R367TER_DEBG_LT1A 0xf12a -#define F367TER_DEBUG_LT1A 0xf12a00ff - -/* DEBG_LT1b */ -#define R367TER_DEBG_LT1B 0xf12b -#define F367TER_DEBUG_LT1B 0xf12b00ff - -/* DEBG_LT1c */ -#define R367TER_DEBG_LT1C 0xf12c -#define F367TER_DEBUG_LT1C 0xf12c00ff - -/* DEBG_LT1D */ -#define R367TER_DEBG_LT1D 0xf12d -#define F367TER_DEBUG_LT1D 0xf12d00ff - -/* DEBG_LT1E */ -#define R367TER_DEBG_LT1E 0xf12e -#define F367TER_DEBUG_LT1E 0xf12e00ff - -/* DEBG_LT1F */ -#define R367TER_DEBG_LT1F 0xf12f -#define F367TER_DEBUG_LT1F 0xf12f00ff - -/* RCCFGH */ -#define R367TER_RCCFGH 0xf200 -#define F367TER_TSRCFIFO_DVBCI 0xf2000080 -#define F367TER_TSRCFIFO_SERIAL 0xf2000040 -#define F367TER_TSRCFIFO_DISABLE 0xf2000020 -#define F367TER_TSFIFO_2TORC 0xf2000010 -#define F367TER_TSRCFIFO_HSGNLOUT 0xf2000008 -#define F367TER_TSRCFIFO_ERRMODE 0xf2000006 -#define F367TER_RCCFGH_0 0xf2000001 - -/* RCCFGM */ -#define R367TER_RCCFGM 0xf201 -#define F367TER_TSRCFIFO_MANSPEED 0xf20100c0 -#define F367TER_TSRCFIFO_PERMDATA 0xf2010020 -#define F367TER_TSRCFIFO_NONEWSGNL 0xf2010010 -#define F367TER_RCBYTE_OVERSAMPLING 0xf201000e -#define F367TER_TSRCFIFO_INVDATA 0xf2010001 - -/* RCCFGL */ -#define R367TER_RCCFGL 0xf202 -#define F367TER_TSRCFIFO_BCLKDEL1cK 0xf20200c0 -#define F367TER_RCCFGL_5 0xf2020020 -#define F367TER_TSRCFIFO_DUTY50 0xf2020010 -#define F367TER_TSRCFIFO_NSGNL2dATA 0xf2020008 -#define F367TER_TSRCFIFO_DISSERMUX 0xf2020004 -#define F367TER_RCCFGL_1 0xf2020002 -#define F367TER_TSRCFIFO_STOPCKDIS 0xf2020001 - -/* RCINSDELH */ -#define R367TER_RCINSDELH 0xf203 -#define F367TER_TSRCDEL_SYNCBYTE 0xf2030080 -#define F367TER_TSRCDEL_XXHEADER 0xf2030040 -#define F367TER_TSRCDEL_BBHEADER 0xf2030020 -#define F367TER_TSRCDEL_DATAFIELD 0xf2030010 -#define F367TER_TSRCINSDEL_ISCR 0xf2030008 -#define F367TER_TSRCINSDEL_NPD 0xf2030004 -#define F367TER_TSRCINSDEL_RSPARITY 0xf2030002 -#define F367TER_TSRCINSDEL_CRC8 0xf2030001 - -/* RCINSDELM */ -#define R367TER_RCINSDELM 0xf204 -#define F367TER_TSRCINS_BBPADDING 0xf2040080 -#define F367TER_TSRCINS_BCHFEC 0xf2040040 -#define F367TER_TSRCINS_LDPCFEC 0xf2040020 -#define F367TER_TSRCINS_EMODCOD 0xf2040010 -#define F367TER_TSRCINS_TOKEN 0xf2040008 -#define F367TER_TSRCINS_XXXERR 0xf2040004 -#define F367TER_TSRCINS_MATYPE 0xf2040002 -#define F367TER_TSRCINS_UPL 0xf2040001 - -/* RCINSDELL */ -#define R367TER_RCINSDELL 0xf205 -#define F367TER_TSRCINS_DFL 0xf2050080 -#define F367TER_TSRCINS_SYNCD 0xf2050040 -#define F367TER_TSRCINS_BLOCLEN 0xf2050020 -#define F367TER_TSRCINS_SIGPCOUNT 0xf2050010 -#define F367TER_TSRCINS_FIFO 0xf2050008 -#define F367TER_TSRCINS_REALPACK 0xf2050004 -#define F367TER_TSRCINS_TSCONFIG 0xf2050002 -#define F367TER_TSRCINS_LATENCY 0xf2050001 - -/* RCSTATUS */ -#define R367TER_RCSTATUS 0xf206 -#define F367TER_TSRCFIFO_LINEOK 0xf2060080 -#define F367TER_TSRCFIFO_ERROR 0xf2060040 -#define F367TER_TSRCFIFO_DATA7 0xf2060020 -#define F367TER_RCSTATUS_4 0xf2060010 -#define F367TER_TSRCFIFO_DEMODSEL 0xf2060008 -#define F367TER_TSRC1FIFOSPEED_STORE 0xf2060004 -#define F367TER_RCSTATUS_1 0xf2060002 -#define F367TER_TSRCSERIAL_IMPOSSIBLE 0xf2060001 - -/* RCSPEED */ -#define R367TER_RCSPEED 0xf207 -#define F367TER_TSRCFIFO_OUTSPEED 0xf20700ff - -/* RCDEBUGM */ -#define R367TER_RCDEBUGM 0xf208 -#define F367TER_SD_UNSYNC 0xf2080080 -#define F367TER_ULFLOCK_DETECTM 0xf2080040 -#define F367TER_SUL_SELECTOS 0xf2080020 -#define F367TER_DILUL_NOSCRBLE 0xf2080010 -#define F367TER_NUL_SCRB 0xf2080008 -#define F367TER_UL_SCRB 0xf2080004 -#define F367TER_SCRAULBAD 0xf2080002 -#define F367TER_SCRAUL_UNSYNC 0xf2080001 - -/* RCDEBUGL */ -#define R367TER_RCDEBUGL 0xf209 -#define F367TER_RS_ERR 0xf2090080 -#define F367TER_LLFLOCK_DETECTM 0xf2090040 -#define F367TER_NOT_SUL_SELECTOS 0xf2090020 -#define F367TER_DILLL_NOSCRBLE 0xf2090010 -#define F367TER_NLL_SCRB 0xf2090008 -#define F367TER_LL_SCRB 0xf2090004 -#define F367TER_SCRALLBAD 0xf2090002 -#define F367TER_SCRALL_UNSYNC 0xf2090001 - -/* RCOBSCFG */ -#define R367TER_RCOBSCFG 0xf20a -#define F367TER_TSRCFIFO_OBSCFG 0xf20a00ff - -/* RCOBSM */ -#define R367TER_RCOBSM 0xf20b -#define F367TER_TSRCFIFO_OBSDATA_HI 0xf20b00ff - -/* RCOBSL */ -#define R367TER_RCOBSL 0xf20c -#define F367TER_TSRCFIFO_OBSDATA_LO 0xf20c00ff - -/* RCFECSPY */ -#define R367TER_RCFECSPY 0xf210 -#define F367TER_SPYRC_ENABLE 0xf2100080 -#define F367TER_RCNO_SYNCBYTE 0xf2100040 -#define F367TER_RCSERIAL_MODE 0xf2100020 -#define F367TER_RCUNUSUAL_PACKET 0xf2100010 -#define F367TER_BERRCMETER_DATAMODE 0xf210000c -#define F367TER_BERRCMETER_LMODE 0xf2100002 -#define F367TER_BERRCMETER_RESET 0xf2100001 - -/* RCFSPYCFG */ -#define R367TER_RCFSPYCFG 0xf211 -#define F367TER_FECSPYRC_INPUT 0xf21100c0 -#define F367TER_RCRST_ON_ERROR 0xf2110020 -#define F367TER_RCONE_SHOT 0xf2110010 -#define F367TER_RCI2C_MODE 0xf211000c -#define F367TER_SPYRC_HSTERESIS 0xf2110003 - -/* RCFSPYDATA */ -#define R367TER_RCFSPYDATA 0xf212 -#define F367TER_SPYRC_STUFFING 0xf2120080 -#define F367TER_RCNOERR_PKTJITTER 0xf2120040 -#define F367TER_SPYRC_CNULLPKT 0xf2120020 -#define F367TER_SPYRC_OUTDATA_MODE 0xf212001f - -/* RCFSPYOUT */ -#define R367TER_RCFSPYOUT 0xf213 -#define F367TER_FSPYRC_DIRECT 0xf2130080 -#define F367TER_RCFSPYOUT_6 0xf2130040 -#define F367TER_SPYRC_OUTDATA_BUS 0xf2130038 -#define F367TER_RCSTUFF_MODE 0xf2130007 - -/* RCFSTATUS */ -#define R367TER_RCFSTATUS 0xf214 -#define F367TER_SPYRC_ENDSIM 0xf2140080 -#define F367TER_RCVALID_SIM 0xf2140040 -#define F367TER_RCFOUND_SIGNAL 0xf2140020 -#define F367TER_RCDSS_SYNCBYTE 0xf2140010 -#define F367TER_RCRESULT_STATE 0xf214000f - -/* RCFGOODPACK */ -#define R367TER_RCFGOODPACK 0xf215 -#define F367TER_RCGOOD_PACKET 0xf21500ff - -/* RCFPACKCNT */ -#define R367TER_RCFPACKCNT 0xf216 -#define F367TER_RCPACKET_COUNTER 0xf21600ff - -/* RCFSPYMISC */ -#define R367TER_RCFSPYMISC 0xf217 -#define F367TER_RCLABEL_COUNTER 0xf21700ff - -/* RCFBERCPT4 */ -#define R367TER_RCFBERCPT4 0xf218 -#define F367TER_FBERRCMETER_CPT_MMMMSB 0xf21800ff - -/* RCFBERCPT3 */ -#define R367TER_RCFBERCPT3 0xf219 -#define F367TER_FBERRCMETER_CPT_MMMSB 0xf21900ff - -/* RCFBERCPT2 */ -#define R367TER_RCFBERCPT2 0xf21a -#define F367TER_FBERRCMETER_CPT_MMSB 0xf21a00ff - -/* RCFBERCPT1 */ -#define R367TER_RCFBERCPT1 0xf21b -#define F367TER_FBERRCMETER_CPT_MSB 0xf21b00ff - -/* RCFBERCPT0 */ -#define R367TER_RCFBERCPT0 0xf21c -#define F367TER_FBERRCMETER_CPT_LSB 0xf21c00ff - -/* RCFBERERR2 */ -#define R367TER_RCFBERERR2 0xf21d -#define F367TER_FBERRCMETER_ERR_HI 0xf21d00ff - -/* RCFBERERR1 */ -#define R367TER_RCFBERERR1 0xf21e -#define F367TER_FBERRCMETER_ERR 0xf21e00ff - -/* RCFBERERR0 */ -#define R367TER_RCFBERERR0 0xf21f -#define F367TER_FBERRCMETER_ERR_LO 0xf21f00ff - -/* RCFSTATESM */ -#define R367TER_RCFSTATESM 0xf220 -#define F367TER_RCRSTATE_F 0xf2200080 -#define F367TER_RCRSTATE_E 0xf2200040 -#define F367TER_RCRSTATE_D 0xf2200020 -#define F367TER_RCRSTATE_C 0xf2200010 -#define F367TER_RCRSTATE_B 0xf2200008 -#define F367TER_RCRSTATE_A 0xf2200004 -#define F367TER_RCRSTATE_9 0xf2200002 -#define F367TER_RCRSTATE_8 0xf2200001 - -/* RCFSTATESL */ -#define R367TER_RCFSTATESL 0xf221 -#define F367TER_RCRSTATE_7 0xf2210080 -#define F367TER_RCRSTATE_6 0xf2210040 -#define F367TER_RCRSTATE_5 0xf2210020 -#define F367TER_RCRSTATE_4 0xf2210010 -#define F367TER_RCRSTATE_3 0xf2210008 -#define F367TER_RCRSTATE_2 0xf2210004 -#define F367TER_RCRSTATE_1 0xf2210002 -#define F367TER_RCRSTATE_0 0xf2210001 - -/* RCFSPYBER */ -#define R367TER_RCFSPYBER 0xf222 -#define F367TER_RCFSPYBER_7 0xf2220080 -#define F367TER_SPYRCOBS_XORREAD 0xf2220040 -#define F367TER_FSPYRCBER_OBSMODE 0xf2220020 -#define F367TER_FSPYRCBER_SYNCBYT 0xf2220010 -#define F367TER_FSPYRCBER_UNSYNC 0xf2220008 -#define F367TER_FSPYRCBER_CTIME 0xf2220007 - -/* RCFSPYDISTM */ -#define R367TER_RCFSPYDISTM 0xf223 -#define F367TER_RCPKTTIME_DISTANCE_HI 0xf22300ff - -/* RCFSPYDISTL */ -#define R367TER_RCFSPYDISTL 0xf224 -#define F367TER_RCPKTTIME_DISTANCE_LO 0xf22400ff - -/* RCFSPYOBS7 */ -#define R367TER_RCFSPYOBS7 0xf228 -#define F367TER_RCSPYOBS_SPYFAIL 0xf2280080 -#define F367TER_RCSPYOBS_SPYFAIL1 0xf2280040 -#define F367TER_RCSPYOBS_ERROR 0xf2280020 -#define F367TER_RCSPYOBS_STROUT 0xf2280010 -#define F367TER_RCSPYOBS_RESULTSTATE1 0xf228000f - -/* RCFSPYOBS6 */ -#define R367TER_RCFSPYOBS6 0xf229 -#define F367TER_RCSPYOBS_RESULTSTATe0 0xf22900f0 -#define F367TER_RCSPYOBS_RESULTSTATEM1 0xf229000f - -/* RCFSPYOBS5 */ -#define R367TER_RCFSPYOBS5 0xf22a -#define F367TER_RCSPYOBS_BYTEOFPACKET1 0xf22a00ff - -/* RCFSPYOBS4 */ -#define R367TER_RCFSPYOBS4 0xf22b -#define F367TER_RCSPYOBS_BYTEVALUE1 0xf22b00ff - -/* RCFSPYOBS3 */ -#define R367TER_RCFSPYOBS3 0xf22c -#define F367TER_RCSPYOBS_DATA1 0xf22c00ff - -/* RCFSPYOBS2 */ -#define R367TER_RCFSPYOBS2 0xf22d -#define F367TER_RCSPYOBS_DATa0 0xf22d00ff - -/* RCFSPYOBS1 */ -#define R367TER_RCFSPYOBS1 0xf22e -#define F367TER_RCSPYOBS_DATAM1 0xf22e00ff - -/* RCFSPYOBS0 */ -#define R367TER_RCFSPYOBS0 0xf22f -#define F367TER_RCSPYOBS_DATAM2 0xf22f00ff - -/* TSGENERAL */ -#define R367TER_TSGENERAL 0xf230 -#define F367TER_TSGENERAL_7 0xf2300080 -#define F367TER_TSGENERAL_6 0xf2300040 -#define F367TER_TSFIFO_BCLK1aLL 0xf2300020 -#define F367TER_TSGENERAL_4 0xf2300010 -#define F367TER_MUXSTREAM_OUTMODE 0xf2300008 -#define F367TER_TSFIFO_PERMPARAL 0xf2300006 -#define F367TER_RST_REEDSOLO 0xf2300001 - -/* RC1SPEED */ -#define R367TER_RC1SPEED 0xf231 -#define F367TER_TSRCFIFO1_OUTSPEED 0xf23100ff - -/* TSGSTATUS */ -#define R367TER_TSGSTATUS 0xf232 -#define F367TER_TSGSTATUS_7 0xf2320080 -#define F367TER_TSGSTATUS_6 0xf2320040 -#define F367TER_RSMEM_FULL 0xf2320020 -#define F367TER_RS_MULTCALC 0xf2320010 -#define F367TER_RSIN_OVERTIME 0xf2320008 -#define F367TER_TSFIFO3_DEMODSEL 0xf2320004 -#define F367TER_TSFIFO2_DEMODSEL 0xf2320002 -#define F367TER_TSFIFO1_DEMODSEL 0xf2320001 - - -/* FECM */ -#define R367TER_FECM 0xf233 -#define F367TER_DSS_DVB 0xf2330080 -#define F367TER_DEMOD_BYPASS 0xf2330040 -#define F367TER_CMP_SLOWMODE 0xf2330020 -#define F367TER_DSS_SRCH 0xf2330010 -#define F367TER_FECM_3 0xf2330008 -#define F367TER_DIFF_MODEVIT 0xf2330004 -#define F367TER_SYNCVIT 0xf2330002 -#define F367TER_I2CSYM 0xf2330001 - -/* VTH12 */ -#define R367TER_VTH12 0xf234 -#define F367TER_VTH_12 0xf23400ff - -/* VTH23 */ -#define R367TER_VTH23 0xf235 -#define F367TER_VTH_23 0xf23500ff - -/* VTH34 */ -#define R367TER_VTH34 0xf236 -#define F367TER_VTH_34 0xf23600ff - -/* VTH56 */ -#define R367TER_VTH56 0xf237 -#define F367TER_VTH_56 0xf23700ff - -/* VTH67 */ -#define R367TER_VTH67 0xf238 -#define F367TER_VTH_67 0xf23800ff - -/* VTH78 */ -#define R367TER_VTH78 0xf239 -#define F367TER_VTH_78 0xf23900ff - -/* VITCURPUN */ -#define R367TER_VITCURPUN 0xf23a -#define F367TER_VIT_MAPPING 0xf23a00e0 -#define F367TER_VIT_CURPUN 0xf23a001f - -/* VERROR */ -#define R367TER_VERROR 0xf23b -#define F367TER_REGERR_VIT 0xf23b00ff - -/* PRVIT */ -#define R367TER_PRVIT 0xf23c -#define F367TER_PRVIT_7 0xf23c0080 -#define F367TER_DIS_VTHLOCK 0xf23c0040 -#define F367TER_E7_8VIT 0xf23c0020 -#define F367TER_E6_7VIT 0xf23c0010 -#define F367TER_E5_6VIT 0xf23c0008 -#define F367TER_E3_4VIT 0xf23c0004 -#define F367TER_E2_3VIT 0xf23c0002 -#define F367TER_E1_2VIT 0xf23c0001 - -/* VAVSRVIT */ -#define R367TER_VAVSRVIT 0xf23d -#define F367TER_AMVIT 0xf23d0080 -#define F367TER_FROZENVIT 0xf23d0040 -#define F367TER_SNVIT 0xf23d0030 -#define F367TER_TOVVIT 0xf23d000c -#define F367TER_HYPVIT 0xf23d0003 - -/* VSTATUSVIT */ -#define R367TER_VSTATUSVIT 0xf23e -#define F367TER_VITERBI_ON 0xf23e0080 -#define F367TER_END_LOOPVIT 0xf23e0040 -#define F367TER_VITERBI_DEPRF 0xf23e0020 -#define F367TER_PRFVIT 0xf23e0010 -#define F367TER_LOCKEDVIT 0xf23e0008 -#define F367TER_VITERBI_DELOCK 0xf23e0004 -#define F367TER_VIT_DEMODSEL 0xf23e0002 -#define F367TER_VITERBI_COMPOUT 0xf23e0001 - -/* VTHINUSE */ -#define R367TER_VTHINUSE 0xf23f -#define F367TER_VIT_INUSE 0xf23f00ff - -/* KDIV12 */ -#define R367TER_KDIV12 0xf240 -#define F367TER_KDIV12_MANUAL 0xf2400080 -#define F367TER_K_DIVIDER_12 0xf240007f - -/* KDIV23 */ -#define R367TER_KDIV23 0xf241 -#define F367TER_KDIV23_MANUAL 0xf2410080 -#define F367TER_K_DIVIDER_23 0xf241007f - -/* KDIV34 */ -#define R367TER_KDIV34 0xf242 -#define F367TER_KDIV34_MANUAL 0xf2420080 -#define F367TER_K_DIVIDER_34 0xf242007f - -/* KDIV56 */ -#define R367TER_KDIV56 0xf243 -#define F367TER_KDIV56_MANUAL 0xf2430080 -#define F367TER_K_DIVIDER_56 0xf243007f - -/* KDIV67 */ -#define R367TER_KDIV67 0xf244 -#define F367TER_KDIV67_MANUAL 0xf2440080 -#define F367TER_K_DIVIDER_67 0xf244007f - -/* KDIV78 */ -#define R367TER_KDIV78 0xf245 -#define F367TER_KDIV78_MANUAL 0xf2450080 -#define F367TER_K_DIVIDER_78 0xf245007f - -/* SIGPOWER */ -#define R367TER_SIGPOWER 0xf246 -#define F367TER_SIGPOWER_MANUAL 0xf2460080 -#define F367TER_SIG_POWER 0xf246007f - -/* DEMAPVIT */ -#define R367TER_DEMAPVIT 0xf247 -#define F367TER_DEMAPVIT_7 0xf2470080 -#define F367TER_K_DIVIDER_VIT 0xf247007f - -/* VITSCALE */ -#define R367TER_VITSCALE 0xf248 -#define F367TER_NVTH_NOSRANGE 0xf2480080 -#define F367TER_VERROR_MAXMODE 0xf2480040 -#define F367TER_KDIV_MODE 0xf2480030 -#define F367TER_NSLOWSN_LOCKED 0xf2480008 -#define F367TER_DELOCK_PRFLOSS 0xf2480004 -#define F367TER_DIS_RSFLOCK 0xf2480002 -#define F367TER_VITSCALE_0 0xf2480001 - -/* FFEC1PRG */ -#define R367TER_FFEC1PRG 0xf249 -#define F367TER_FDSS_DVB 0xf2490080 -#define F367TER_FDSS_SRCH 0xf2490040 -#define F367TER_FFECPROG_5 0xf2490020 -#define F367TER_FFECPROG_4 0xf2490010 -#define F367TER_FFECPROG_3 0xf2490008 -#define F367TER_FFECPROG_2 0xf2490004 -#define F367TER_FTS1_DISABLE 0xf2490002 -#define F367TER_FTS2_DISABLE 0xf2490001 - -/* FVITCURPUN */ -#define R367TER_FVITCURPUN 0xf24a -#define F367TER_FVIT_MAPPING 0xf24a00e0 -#define F367TER_FVIT_CURPUN 0xf24a001f - -/* FVERROR */ -#define R367TER_FVERROR 0xf24b -#define F367TER_FREGERR_VIT 0xf24b00ff - -/* FVSTATUSVIT */ -#define R367TER_FVSTATUSVIT 0xf24c -#define F367TER_FVITERBI_ON 0xf24c0080 -#define F367TER_F1END_LOOPVIT 0xf24c0040 -#define F367TER_FVITERBI_DEPRF 0xf24c0020 -#define F367TER_FPRFVIT 0xf24c0010 -#define F367TER_FLOCKEDVIT 0xf24c0008 -#define F367TER_FVITERBI_DELOCK 0xf24c0004 -#define F367TER_FVIT_DEMODSEL 0xf24c0002 -#define F367TER_FVITERBI_COMPOUT 0xf24c0001 - -/* DEBUG_LT1 */ -#define R367TER_DEBUG_LT1 0xf24d -#define F367TER_DBG_LT1 0xf24d00ff - -/* DEBUG_LT2 */ -#define R367TER_DEBUG_LT2 0xf24e -#define F367TER_DBG_LT2 0xf24e00ff - -/* DEBUG_LT3 */ -#define R367TER_DEBUG_LT3 0xf24f -#define F367TER_DBG_LT3 0xf24f00ff - -/* TSTSFMET */ -#define R367TER_TSTSFMET 0xf250 -#define F367TER_TSTSFEC_METRIQUES 0xf25000ff - -/* SELOUT */ -#define R367TER_SELOUT 0xf252 -#define F367TER_EN_SYNC 0xf2520080 -#define F367TER_EN_TBUSDEMAP 0xf2520040 -#define F367TER_SELOUT_5 0xf2520020 -#define F367TER_SELOUT_4 0xf2520010 -#define F367TER_TSTSYNCHRO_MODE 0xf2520002 - -/* TSYNC */ -#define R367TER_TSYNC 0xf253 -#define F367TER_CURPUN_INCMODE 0xf2530080 -#define F367TER_CERR_TSTMODE 0xf2530040 -#define F367TER_SHIFTSOF_MODE 0xf2530030 -#define F367TER_SLOWPHA_MODE 0xf2530008 -#define F367TER_PXX_BYPALL 0xf2530004 -#define F367TER_FROTA45_FIRST 0xf2530002 -#define F367TER_TST_BCHERROR 0xf2530001 - -/* TSTERR */ -#define R367TER_TSTERR 0xf254 -#define F367TER_TST_LONGPKT 0xf2540080 -#define F367TER_TST_ISSYION 0xf2540040 -#define F367TER_TST_NPDON 0xf2540020 -#define F367TER_TSTERR_4 0xf2540010 -#define F367TER_TRACEBACK_MODE 0xf2540008 -#define F367TER_TST_RSPARITY 0xf2540004 -#define F367TER_METRIQUE_MODE 0xf2540003 - -/* TSFSYNC */ -#define R367TER_TSFSYNC 0xf255 -#define F367TER_EN_SFECSYNC 0xf2550080 -#define F367TER_EN_SFECDEMAP 0xf2550040 -#define F367TER_SFCERR_TSTMODE 0xf2550020 -#define F367TER_SFECPXX_BYPALL 0xf2550010 -#define F367TER_SFECTSTSYNCHRO_MODE 0xf255000f - -/* TSTSFERR */ -#define R367TER_TSTSFERR 0xf256 -#define F367TER_TSTSTERR_7 0xf2560080 -#define F367TER_TSTSTERR_6 0xf2560040 -#define F367TER_TSTSTERR_5 0xf2560020 -#define F367TER_TSTSTERR_4 0xf2560010 -#define F367TER_SFECTRACEBACK_MODE 0xf2560008 -#define F367TER_SFEC_NCONVPROG 0xf2560004 -#define F367TER_SFECMETRIQUE_MODE 0xf2560003 - -/* TSTTSSF1 */ -#define R367TER_TSTTSSF1 0xf258 -#define F367TER_TSTERSSF 0xf2580080 -#define F367TER_TSTTSSFEN 0xf2580040 -#define F367TER_SFEC_OUTMODE 0xf2580030 -#define F367TER_XLSF_NOFTHRESHOLD 0xf2580008 -#define F367TER_TSTTSSF_STACKSEL 0xf2580007 - -/* TSTTSSF2 */ -#define R367TER_TSTTSSF2 0xf259 -#define F367TER_DILSF_DBBHEADER 0xf2590080 -#define F367TER_TSTTSSF_DISBUG 0xf2590040 -#define F367TER_TSTTSSF_NOBADSTART 0xf2590020 -#define F367TER_TSTTSSF_SELECT 0xf259001f - -/* TSTTSSF3 */ -#define R367TER_TSTTSSF3 0xf25a -#define F367TER_TSTTSSF3_7 0xf25a0080 -#define F367TER_TSTTSSF3_6 0xf25a0040 -#define F367TER_TSTTSSF3_5 0xf25a0020 -#define F367TER_TSTTSSF3_4 0xf25a0010 -#define F367TER_TSTTSSF3_3 0xf25a0008 -#define F367TER_TSTTSSF3_2 0xf25a0004 -#define F367TER_TSTTSSF3_1 0xf25a0002 -#define F367TER_DISSF_CLKENABLE 0xf25a0001 - -/* TSTTS1 */ -#define R367TER_TSTTS1 0xf25c -#define F367TER_TSTERS 0xf25c0080 -#define F367TER_TSFIFO_DSSSYNCB 0xf25c0040 -#define F367TER_TSTTS_FSPYBEFRS 0xf25c0020 -#define F367TER_NFORCE_SYNCBYTE 0xf25c0010 -#define F367TER_XL_NOFTHRESHOLD 0xf25c0008 -#define F367TER_TSTTS_FRFORCEPKT 0xf25c0004 -#define F367TER_DESCR_NOTAUTO 0xf25c0002 -#define F367TER_TSTTSEN 0xf25c0001 - -/* TSTTS2 */ -#define R367TER_TSTTS2 0xf25d -#define F367TER_DIL_DBBHEADER 0xf25d0080 -#define F367TER_TSTTS_NOBADXXX 0xf25d0040 -#define F367TER_TSFIFO_DELSPEEDUP 0xf25d0020 -#define F367TER_TSTTS_SELECT 0xf25d001f - -/* TSTTS3 */ -#define R367TER_TSTTS3 0xf25e -#define F367TER_TSTTS_NOPKTGAIN 0xf25e0080 -#define F367TER_TSTTS_NOPKTENE 0xf25e0040 -#define F367TER_TSTTS_ISOLATION 0xf25e0020 -#define F367TER_TSTTS_DISBUG 0xf25e0010 -#define F367TER_TSTTS_NOBADSTART 0xf25e0008 -#define F367TER_TSTTS_STACKSEL 0xf25e0007 - -/* TSTTS4 */ -#define R367TER_TSTTS4 0xf25f -#define F367TER_TSTTS4_7 0xf25f0080 -#define F367TER_TSTTS4_6 0xf25f0040 -#define F367TER_TSTTS4_5 0xf25f0020 -#define F367TER_TSTTS_DISDSTATE 0xf25f0010 -#define F367TER_TSTTS_FASTNOSYNC 0xf25f0008 -#define F367TER_EXT_FECSPYIN 0xf25f0004 -#define F367TER_TSTTS_NODPZERO 0xf25f0002 -#define F367TER_TSTTS_NODIV3 0xf25f0001 - -/* TSTTSRC */ -#define R367TER_TSTTSRC 0xf26c -#define F367TER_TSTTSRC_7 0xf26c0080 -#define F367TER_TSRCFIFO_DSSSYNCB 0xf26c0040 -#define F367TER_TSRCFIFO_DPUNACTIVE 0xf26c0020 -#define F367TER_TSRCFIFO_DELSPEEDUP 0xf26c0010 -#define F367TER_TSTTSRC_NODIV3 0xf26c0008 -#define F367TER_TSTTSRC_FRFORCEPKT 0xf26c0004 -#define F367TER_SAT25_SDDORIGINE 0xf26c0002 -#define F367TER_TSTTSRC_INACTIVE 0xf26c0001 - -/* TSTTSRS */ -#define R367TER_TSTTSRS 0xf26d -#define F367TER_TSTTSRS_7 0xf26d0080 -#define F367TER_TSTTSRS_6 0xf26d0040 -#define F367TER_TSTTSRS_5 0xf26d0020 -#define F367TER_TSTTSRS_4 0xf26d0010 -#define F367TER_TSTTSRS_3 0xf26d0008 -#define F367TER_TSTTSRS_2 0xf26d0004 -#define F367TER_TSTRS_DISRS2 0xf26d0002 -#define F367TER_TSTRS_DISRS1 0xf26d0001 - -/* TSSTATEM */ -#define R367TER_TSSTATEM 0xf270 -#define F367TER_TSDIL_ON 0xf2700080 -#define F367TER_TSSKIPRS_ON 0xf2700040 -#define F367TER_TSRS_ON 0xf2700020 -#define F367TER_TSDESCRAMB_ON 0xf2700010 -#define F367TER_TSFRAME_MODE 0xf2700008 -#define F367TER_TS_DISABLE 0xf2700004 -#define F367TER_TSACM_MODE 0xf2700002 -#define F367TER_TSOUT_NOSYNC 0xf2700001 - -/* TSSTATEL */ -#define R367TER_TSSTATEL 0xf271 -#define F367TER_TSNOSYNCBYTE 0xf2710080 -#define F367TER_TSPARITY_ON 0xf2710040 -#define F367TER_TSSYNCOUTRS_ON 0xf2710020 -#define F367TER_TSDVBS2_MODE 0xf2710010 -#define F367TER_TSISSYI_ON 0xf2710008 -#define F367TER_TSNPD_ON 0xf2710004 -#define F367TER_TSCRC8_ON 0xf2710002 -#define F367TER_TSDSS_PACKET 0xf2710001 - -/* TSCFGH */ -#define R367TER_TSCFGH 0xf272 -#define F367TER_TSFIFO_DVBCI 0xf2720080 -#define F367TER_TSFIFO_SERIAL 0xf2720040 -#define F367TER_TSFIFO_TEIUPDATE 0xf2720020 -#define F367TER_TSFIFO_DUTY50 0xf2720010 -#define F367TER_TSFIFO_HSGNLOUT 0xf2720008 -#define F367TER_TSFIFO_ERRMODE 0xf2720006 -#define F367TER_RST_HWARE 0xf2720001 - -/* TSCFGM */ -#define R367TER_TSCFGM 0xf273 -#define F367TER_TSFIFO_MANSPEED 0xf27300c0 -#define F367TER_TSFIFO_PERMDATA 0xf2730020 -#define F367TER_TSFIFO_NONEWSGNL 0xf2730010 -#define F367TER_TSFIFO_BITSPEED 0xf2730008 -#define F367TER_NPD_SPECDVBS2 0xf2730004 -#define F367TER_TSFIFO_STOPCKDIS 0xf2730002 -#define F367TER_TSFIFO_INVDATA 0xf2730001 - -/* TSCFGL */ -#define R367TER_TSCFGL 0xf274 -#define F367TER_TSFIFO_BCLKDEL1cK 0xf27400c0 -#define F367TER_BCHERROR_MODE 0xf2740030 -#define F367TER_TSFIFO_NSGNL2dATA 0xf2740008 -#define F367TER_TSFIFO_EMBINDVB 0xf2740004 -#define F367TER_TSFIFO_DPUNACT 0xf2740002 -#define F367TER_TSFIFO_NPDOFF 0xf2740001 - -/* TSSYNC */ -#define R367TER_TSSYNC 0xf275 -#define F367TER_TSFIFO_PERMUTE 0xf2750080 -#define F367TER_TSFIFO_FISCR3B 0xf2750060 -#define F367TER_TSFIFO_SYNCMODE 0xf2750018 -#define F367TER_TSFIFO_SYNCSEL 0xf2750007 - -/* TSINSDELH */ -#define R367TER_TSINSDELH 0xf276 -#define F367TER_TSDEL_SYNCBYTE 0xf2760080 -#define F367TER_TSDEL_XXHEADER 0xf2760040 -#define F367TER_TSDEL_BBHEADER 0xf2760020 -#define F367TER_TSDEL_DATAFIELD 0xf2760010 -#define F367TER_TSINSDEL_ISCR 0xf2760008 -#define F367TER_TSINSDEL_NPD 0xf2760004 -#define F367TER_TSINSDEL_RSPARITY 0xf2760002 -#define F367TER_TSINSDEL_CRC8 0xf2760001 - -/* TSINSDELM */ -#define R367TER_TSINSDELM 0xf277 -#define F367TER_TSINS_BBPADDING 0xf2770080 -#define F367TER_TSINS_BCHFEC 0xf2770040 -#define F367TER_TSINS_LDPCFEC 0xf2770020 -#define F367TER_TSINS_EMODCOD 0xf2770010 -#define F367TER_TSINS_TOKEN 0xf2770008 -#define F367TER_TSINS_XXXERR 0xf2770004 -#define F367TER_TSINS_MATYPE 0xf2770002 -#define F367TER_TSINS_UPL 0xf2770001 - -/* TSINSDELL */ -#define R367TER_TSINSDELL 0xf278 -#define F367TER_TSINS_DFL 0xf2780080 -#define F367TER_TSINS_SYNCD 0xf2780040 -#define F367TER_TSINS_BLOCLEN 0xf2780020 -#define F367TER_TSINS_SIGPCOUNT 0xf2780010 -#define F367TER_TSINS_FIFO 0xf2780008 -#define F367TER_TSINS_REALPACK 0xf2780004 -#define F367TER_TSINS_TSCONFIG 0xf2780002 -#define F367TER_TSINS_LATENCY 0xf2780001 - -/* TSDIVN */ -#define R367TER_TSDIVN 0xf279 -#define F367TER_TSFIFO_LOWSPEED 0xf2790080 -#define F367TER_BYTE_OVERSAMPLING 0xf2790070 -#define F367TER_TSMANUAL_PACKETNBR 0xf279000f - -/* TSDIVPM */ -#define R367TER_TSDIVPM 0xf27a -#define F367TER_TSMANUAL_P_HI 0xf27a00ff - -/* TSDIVPL */ -#define R367TER_TSDIVPL 0xf27b -#define F367TER_TSMANUAL_P_LO 0xf27b00ff - -/* TSDIVQM */ -#define R367TER_TSDIVQM 0xf27c -#define F367TER_TSMANUAL_Q_HI 0xf27c00ff - -/* TSDIVQL */ -#define R367TER_TSDIVQL 0xf27d -#define F367TER_TSMANUAL_Q_LO 0xf27d00ff - -/* TSDILSTKM */ -#define R367TER_TSDILSTKM 0xf27e -#define F367TER_TSFIFO_DILSTK_HI 0xf27e00ff - -/* TSDILSTKL */ -#define R367TER_TSDILSTKL 0xf27f -#define F367TER_TSFIFO_DILSTK_LO 0xf27f00ff - -/* TSSPEED */ -#define R367TER_TSSPEED 0xf280 -#define F367TER_TSFIFO_OUTSPEED 0xf28000ff - -/* TSSTATUS */ -#define R367TER_TSSTATUS 0xf281 -#define F367TER_TSFIFO_LINEOK 0xf2810080 -#define F367TER_TSFIFO_ERROR 0xf2810040 -#define F367TER_TSFIFO_DATA7 0xf2810020 -#define F367TER_TSFIFO_NOSYNC 0xf2810010 -#define F367TER_ISCR_INITIALIZED 0xf2810008 -#define F367TER_ISCR_UPDATED 0xf2810004 -#define F367TER_SOFFIFO_UNREGUL 0xf2810002 -#define F367TER_DIL_READY 0xf2810001 - -/* TSSTATUS2 */ -#define R367TER_TSSTATUS2 0xf282 -#define F367TER_TSFIFO_DEMODSEL 0xf2820080 -#define F367TER_TSFIFOSPEED_STORE 0xf2820040 -#define F367TER_DILXX_RESET 0xf2820020 -#define F367TER_TSSERIAL_IMPOSSIBLE 0xf2820010 -#define F367TER_TSFIFO_UNDERSPEED 0xf2820008 -#define F367TER_BITSPEED_EVENT 0xf2820004 -#define F367TER_UL_SCRAMBDETECT 0xf2820002 -#define F367TER_ULDTV67_FALSELOCK 0xf2820001 - -/* TSBITRATEM */ -#define R367TER_TSBITRATEM 0xf283 -#define F367TER_TSFIFO_BITRATE_HI 0xf28300ff - -/* TSBITRATEL */ -#define R367TER_TSBITRATEL 0xf284 -#define F367TER_TSFIFO_BITRATE_LO 0xf28400ff - -/* TSPACKLENM */ -#define R367TER_TSPACKLENM 0xf285 -#define F367TER_TSFIFO_PACKCPT 0xf28500e0 -#define F367TER_DIL_RPLEN_HI 0xf285001f - -/* TSPACKLENL */ -#define R367TER_TSPACKLENL 0xf286 -#define F367TER_DIL_RPLEN_LO 0xf28600ff - -/* TSBLOCLENM */ -#define R367TER_TSBLOCLENM 0xf287 -#define F367TER_TSFIFO_PFLEN_HI 0xf28700ff - -/* TSBLOCLENL */ -#define R367TER_TSBLOCLENL 0xf288 -#define F367TER_TSFIFO_PFLEN_LO 0xf28800ff - -/* TSDLYH */ -#define R367TER_TSDLYH 0xf289 -#define F367TER_SOFFIFO_TSTIMEVALID 0xf2890080 -#define F367TER_SOFFIFO_SPEEDUP 0xf2890040 -#define F367TER_SOFFIFO_STOP 0xf2890020 -#define F367TER_SOFFIFO_REGULATED 0xf2890010 -#define F367TER_SOFFIFO_REALSBOFF_HI 0xf289000f - -/* TSDLYM */ -#define R367TER_TSDLYM 0xf28a -#define F367TER_SOFFIFO_REALSBOFF_MED 0xf28a00ff - -/* TSDLYL */ -#define R367TER_TSDLYL 0xf28b -#define F367TER_SOFFIFO_REALSBOFF_LO 0xf28b00ff - -/* TSNPDAV */ -#define R367TER_TSNPDAV 0xf28c -#define F367TER_TSNPD_AVERAGE 0xf28c00ff - -/* TSBUFSTATH */ -#define R367TER_TSBUFSTATH 0xf28d -#define F367TER_TSISCR_3BYTES 0xf28d0080 -#define F367TER_TSISCR_NEWDATA 0xf28d0040 -#define F367TER_TSISCR_BUFSTAT_HI 0xf28d003f - -/* TSBUFSTATM */ -#define R367TER_TSBUFSTATM 0xf28e -#define F367TER_TSISCR_BUFSTAT_MED 0xf28e00ff - -/* TSBUFSTATL */ -#define R367TER_TSBUFSTATL 0xf28f -#define F367TER_TSISCR_BUFSTAT_LO 0xf28f00ff - -/* TSDEBUGM */ -#define R367TER_TSDEBUGM 0xf290 -#define F367TER_TSFIFO_ILLPACKET 0xf2900080 -#define F367TER_DIL_NOSYNC 0xf2900040 -#define F367TER_DIL_ISCR 0xf2900020 -#define F367TER_DILOUT_BSYNCB 0xf2900010 -#define F367TER_TSFIFO_EMPTYPKT 0xf2900008 -#define F367TER_TSFIFO_EMPTYRD 0xf2900004 -#define F367TER_SOFFIFO_STOPM 0xf2900002 -#define F367TER_SOFFIFO_SPEEDUPM 0xf2900001 - -/* TSDEBUGL */ -#define R367TER_TSDEBUGL 0xf291 -#define F367TER_TSFIFO_PACKLENFAIL 0xf2910080 -#define F367TER_TSFIFO_SYNCBFAIL 0xf2910040 -#define F367TER_TSFIFO_VITLIBRE 0xf2910020 -#define F367TER_TSFIFO_BOOSTSPEEDM 0xf2910010 -#define F367TER_TSFIFO_UNDERSPEEDM 0xf2910008 -#define F367TER_TSFIFO_ERROR_EVNT 0xf2910004 -#define F367TER_TSFIFO_FULL 0xf2910002 -#define F367TER_TSFIFO_OVERFLOWM 0xf2910001 - -/* TSDLYSETH */ -#define R367TER_TSDLYSETH 0xf292 -#define F367TER_SOFFIFO_OFFSET 0xf29200e0 -#define F367TER_SOFFIFO_SYMBOFFSET_HI 0xf292001f - -/* TSDLYSETM */ -#define R367TER_TSDLYSETM 0xf293 -#define F367TER_SOFFIFO_SYMBOFFSET_MED 0xf29300ff - -/* TSDLYSETL */ -#define R367TER_TSDLYSETL 0xf294 -#define F367TER_SOFFIFO_SYMBOFFSET_LO 0xf29400ff - -/* TSOBSCFG */ -#define R367TER_TSOBSCFG 0xf295 -#define F367TER_TSFIFO_OBSCFG 0xf29500ff - -/* TSOBSM */ -#define R367TER_TSOBSM 0xf296 -#define F367TER_TSFIFO_OBSDATA_HI 0xf29600ff - -/* TSOBSL */ -#define R367TER_TSOBSL 0xf297 -#define F367TER_TSFIFO_OBSDATA_LO 0xf29700ff - -/* ERRCTRL1 */ -#define R367TER_ERRCTRL1 0xf298 -#define F367TER_ERR_SRC1 0xf29800f0 -#define F367TER_ERRCTRL1_3 0xf2980008 -#define F367TER_NUM_EVT1 0xf2980007 - -/* ERRCNT1H */ -#define R367TER_ERRCNT1H 0xf299 -#define F367TER_ERRCNT1_OLDVALUE 0xf2990080 -#define F367TER_ERR_CNT1 0xf299007f - -/* ERRCNT1M */ -#define R367TER_ERRCNT1M 0xf29a -#define F367TER_ERR_CNT1_HI 0xf29a00ff - -/* ERRCNT1L */ -#define R367TER_ERRCNT1L 0xf29b -#define F367TER_ERR_CNT1_LO 0xf29b00ff - -/* ERRCTRL2 */ -#define R367TER_ERRCTRL2 0xf29c -#define F367TER_ERR_SRC2 0xf29c00f0 -#define F367TER_ERRCTRL2_3 0xf29c0008 -#define F367TER_NUM_EVT2 0xf29c0007 - -/* ERRCNT2H */ -#define R367TER_ERRCNT2H 0xf29d -#define F367TER_ERRCNT2_OLDVALUE 0xf29d0080 -#define F367TER_ERR_CNT2_HI 0xf29d007f - -/* ERRCNT2M */ -#define R367TER_ERRCNT2M 0xf29e -#define F367TER_ERR_CNT2_MED 0xf29e00ff - -/* ERRCNT2L */ -#define R367TER_ERRCNT2L 0xf29f -#define F367TER_ERR_CNT2_LO 0xf29f00ff - -/* FECSPY */ -#define R367TER_FECSPY 0xf2a0 -#define F367TER_SPY_ENABLE 0xf2a00080 -#define F367TER_NO_SYNCBYTE 0xf2a00040 -#define F367TER_SERIAL_MODE 0xf2a00020 -#define F367TER_UNUSUAL_PACKET 0xf2a00010 -#define F367TER_BERMETER_DATAMODE 0xf2a0000c -#define F367TER_BERMETER_LMODE 0xf2a00002 -#define F367TER_BERMETER_RESET 0xf2a00001 - -/* FSPYCFG */ -#define R367TER_FSPYCFG 0xf2a1 -#define F367TER_FECSPY_INPUT 0xf2a100c0 -#define F367TER_RST_ON_ERROR 0xf2a10020 -#define F367TER_ONE_SHOT 0xf2a10010 -#define F367TER_I2C_MOD 0xf2a1000c -#define F367TER_SPY_HYSTERESIS 0xf2a10003 - -/* FSPYDATA */ -#define R367TER_FSPYDATA 0xf2a2 -#define F367TER_SPY_STUFFING 0xf2a20080 -#define F367TER_NOERROR_PKTJITTER 0xf2a20040 -#define F367TER_SPY_CNULLPKT 0xf2a20020 -#define F367TER_SPY_OUTDATA_MODE 0xf2a2001f - -/* FSPYOUT */ -#define R367TER_FSPYOUT 0xf2a3 -#define F367TER_FSPY_DIRECT 0xf2a30080 -#define F367TER_FSPYOUT_6 0xf2a30040 -#define F367TER_SPY_OUTDATA_BUS 0xf2a30038 -#define F367TER_STUFF_MODE 0xf2a30007 - -/* FSTATUS */ -#define R367TER_FSTATUS 0xf2a4 -#define F367TER_SPY_ENDSIM 0xf2a40080 -#define F367TER_VALID_SIM 0xf2a40040 -#define F367TER_FOUND_SIGNAL 0xf2a40020 -#define F367TER_DSS_SYNCBYTE 0xf2a40010 -#define F367TER_RESULT_STATE 0xf2a4000f - -/* FGOODPACK */ -#define R367TER_FGOODPACK 0xf2a5 -#define F367TER_FGOOD_PACKET 0xf2a500ff - -/* FPACKCNT */ -#define R367TER_FPACKCNT 0xf2a6 -#define F367TER_FPACKET_COUNTER 0xf2a600ff - -/* FSPYMISC */ -#define R367TER_FSPYMISC 0xf2a7 -#define F367TER_FLABEL_COUNTER 0xf2a700ff - -/* FBERCPT4 */ -#define R367TER_FBERCPT4 0xf2a8 -#define F367TER_FBERMETER_CPT5 0xf2a800ff - -/* FBERCPT3 */ -#define R367TER_FBERCPT3 0xf2a9 -#define F367TER_FBERMETER_CPT4 0xf2a900ff - -/* FBERCPT2 */ -#define R367TER_FBERCPT2 0xf2aa -#define F367TER_FBERMETER_CPT3 0xf2aa00ff - -/* FBERCPT1 */ -#define R367TER_FBERCPT1 0xf2ab -#define F367TER_FBERMETER_CPT2 0xf2ab00ff - -/* FBERCPT0 */ -#define R367TER_FBERCPT0 0xf2ac -#define F367TER_FBERMETER_CPT1 0xf2ac00ff - -/* FBERERR2 */ -#define R367TER_FBERERR2 0xf2ad -#define F367TER_FBERMETER_ERR_HI 0xf2ad00ff - -/* FBERERR1 */ -#define R367TER_FBERERR1 0xf2ae -#define F367TER_FBERMETER_ERR_MED 0xf2ae00ff - -/* FBERERR0 */ -#define R367TER_FBERERR0 0xf2af -#define F367TER_FBERMETER_ERR_LO 0xf2af00ff - -/* FSTATESM */ -#define R367TER_FSTATESM 0xf2b0 -#define F367TER_RSTATE_F 0xf2b00080 -#define F367TER_RSTATE_E 0xf2b00040 -#define F367TER_RSTATE_D 0xf2b00020 -#define F367TER_RSTATE_C 0xf2b00010 -#define F367TER_RSTATE_B 0xf2b00008 -#define F367TER_RSTATE_A 0xf2b00004 -#define F367TER_RSTATE_9 0xf2b00002 -#define F367TER_RSTATE_8 0xf2b00001 - -/* FSTATESL */ -#define R367TER_FSTATESL 0xf2b1 -#define F367TER_RSTATE_7 0xf2b10080 -#define F367TER_RSTATE_6 0xf2b10040 -#define F367TER_RSTATE_5 0xf2b10020 -#define F367TER_RSTATE_4 0xf2b10010 -#define F367TER_RSTATE_3 0xf2b10008 -#define F367TER_RSTATE_2 0xf2b10004 -#define F367TER_RSTATE_1 0xf2b10002 -#define F367TER_RSTATE_0 0xf2b10001 - -/* FSPYBER */ -#define R367TER_FSPYBER 0xf2b2 -#define F367TER_FSPYBER_7 0xf2b20080 -#define F367TER_FSPYOBS_XORREAD 0xf2b20040 -#define F367TER_FSPYBER_OBSMODE 0xf2b20020 -#define F367TER_FSPYBER_SYNCBYTE 0xf2b20010 -#define F367TER_FSPYBER_UNSYNC 0xf2b20008 -#define F367TER_FSPYBER_CTIME 0xf2b20007 - -/* FSPYDISTM */ -#define R367TER_FSPYDISTM 0xf2b3 -#define F367TER_PKTTIME_DISTANCE_HI 0xf2b300ff - -/* FSPYDISTL */ -#define R367TER_FSPYDISTL 0xf2b4 -#define F367TER_PKTTIME_DISTANCE_LO 0xf2b400ff - -/* FSPYOBS7 */ -#define R367TER_FSPYOBS7 0xf2b8 -#define F367TER_FSPYOBS_SPYFAIL 0xf2b80080 -#define F367TER_FSPYOBS_SPYFAIL1 0xf2b80040 -#define F367TER_FSPYOBS_ERROR 0xf2b80020 -#define F367TER_FSPYOBS_STROUT 0xf2b80010 -#define F367TER_FSPYOBS_RESULTSTATE1 0xf2b8000f - -/* FSPYOBS6 */ -#define R367TER_FSPYOBS6 0xf2b9 -#define F367TER_FSPYOBS_RESULTSTATe0 0xf2b900f0 -#define F367TER_FSPYOBS_RESULTSTATEM1 0xf2b9000f - -/* FSPYOBS5 */ -#define R367TER_FSPYOBS5 0xf2ba -#define F367TER_FSPYOBS_BYTEOFPACKET1 0xf2ba00ff - -/* FSPYOBS4 */ -#define R367TER_FSPYOBS4 0xf2bb -#define F367TER_FSPYOBS_BYTEVALUE1 0xf2bb00ff - -/* FSPYOBS3 */ -#define R367TER_FSPYOBS3 0xf2bc -#define F367TER_FSPYOBS_DATA1 0xf2bc00ff - -/* FSPYOBS2 */ -#define R367TER_FSPYOBS2 0xf2bd -#define F367TER_FSPYOBS_DATa0 0xf2bd00ff - -/* FSPYOBS1 */ -#define R367TER_FSPYOBS1 0xf2be -#define F367TER_FSPYOBS_DATAM1 0xf2be00ff - -/* FSPYOBS0 */ -#define R367TER_FSPYOBS0 0xf2bf -#define F367TER_FSPYOBS_DATAM2 0xf2bf00ff - -/* SFDEMAP */ -#define R367TER_SFDEMAP 0xf2c0 -#define F367TER_SFDEMAP_7 0xf2c00080 -#define F367TER_SFEC_K_DIVIDER_VIT 0xf2c0007f - -/* SFERROR */ -#define R367TER_SFERROR 0xf2c1 -#define F367TER_SFEC_REGERR_VIT 0xf2c100ff - -/* SFAVSR */ -#define R367TER_SFAVSR 0xf2c2 -#define F367TER_SFEC_SUMERRORS 0xf2c20080 -#define F367TER_SERROR_MAXMODE 0xf2c20040 -#define F367TER_SN_SFEC 0xf2c20030 -#define F367TER_KDIV_MODE_SFEC 0xf2c2000c -#define F367TER_SFAVSR_1 0xf2c20002 -#define F367TER_SFAVSR_0 0xf2c20001 - -/* SFECSTATUS */ -#define R367TER_SFECSTATUS 0xf2c3 -#define F367TER_SFEC_ON 0xf2c30080 -#define F367TER_SFSTATUS_6 0xf2c30040 -#define F367TER_SFSTATUS_5 0xf2c30020 -#define F367TER_SFSTATUS_4 0xf2c30010 -#define F367TER_LOCKEDSFEC 0xf2c30008 -#define F367TER_SFEC_DELOCK 0xf2c30004 -#define F367TER_SFEC_DEMODSEL1 0xf2c30002 -#define F367TER_SFEC_OVFON 0xf2c30001 - -/* SFKDIV12 */ -#define R367TER_SFKDIV12 0xf2c4 -#define F367TER_SFECKDIV12_MAN 0xf2c40080 -#define F367TER_SFEC_K_DIVIDER_12 0xf2c4007f - -/* SFKDIV23 */ -#define R367TER_SFKDIV23 0xf2c5 -#define F367TER_SFECKDIV23_MAN 0xf2c50080 -#define F367TER_SFEC_K_DIVIDER_23 0xf2c5007f - -/* SFKDIV34 */ -#define R367TER_SFKDIV34 0xf2c6 -#define F367TER_SFECKDIV34_MAN 0xf2c60080 -#define F367TER_SFEC_K_DIVIDER_34 0xf2c6007f - -/* SFKDIV56 */ -#define R367TER_SFKDIV56 0xf2c7 -#define F367TER_SFECKDIV56_MAN 0xf2c70080 -#define F367TER_SFEC_K_DIVIDER_56 0xf2c7007f - -/* SFKDIV67 */ -#define R367TER_SFKDIV67 0xf2c8 -#define F367TER_SFECKDIV67_MAN 0xf2c80080 -#define F367TER_SFEC_K_DIVIDER_67 0xf2c8007f - -/* SFKDIV78 */ -#define R367TER_SFKDIV78 0xf2c9 -#define F367TER_SFECKDIV78_MAN 0xf2c90080 -#define F367TER_SFEC_K_DIVIDER_78 0xf2c9007f - -/* SFDILSTKM */ -#define R367TER_SFDILSTKM 0xf2ca -#define F367TER_SFEC_PACKCPT 0xf2ca00e0 -#define F367TER_SFEC_DILSTK_HI 0xf2ca001f - -/* SFDILSTKL */ -#define R367TER_SFDILSTKL 0xf2cb -#define F367TER_SFEC_DILSTK_LO 0xf2cb00ff - -/* SFSTATUS */ -#define R367TER_SFSTATUS 0xf2cc -#define F367TER_SFEC_LINEOK 0xf2cc0080 -#define F367TER_SFEC_ERROR 0xf2cc0040 -#define F367TER_SFEC_DATA7 0xf2cc0020 -#define F367TER_SFEC_OVERFLOW 0xf2cc0010 -#define F367TER_SFEC_DEMODSEL2 0xf2cc0008 -#define F367TER_SFEC_NOSYNC 0xf2cc0004 -#define F367TER_SFEC_UNREGULA 0xf2cc0002 -#define F367TER_SFEC_READY 0xf2cc0001 - -/* SFDLYH */ -#define R367TER_SFDLYH 0xf2cd -#define F367TER_SFEC_TSTIMEVALID 0xf2cd0080 -#define F367TER_SFEC_SPEEDUP 0xf2cd0040 -#define F367TER_SFEC_STOP 0xf2cd0020 -#define F367TER_SFEC_REGULATED 0xf2cd0010 -#define F367TER_SFEC_REALSYMBOFFSET 0xf2cd000f - -/* SFDLYM */ -#define R367TER_SFDLYM 0xf2ce -#define F367TER_SFEC_REALSYMBOFFSET_HI 0xf2ce00ff - -/* SFDLYL */ -#define R367TER_SFDLYL 0xf2cf -#define F367TER_SFEC_REALSYMBOFFSET_LO 0xf2cf00ff - -/* SFDLYSETH */ -#define R367TER_SFDLYSETH 0xf2d0 -#define F367TER_SFEC_OFFSET 0xf2d000e0 -#define F367TER_SFECDLYSETH_4 0xf2d00010 -#define F367TER_RST_SFEC 0xf2d00008 -#define F367TER_SFECDLYSETH_2 0xf2d00004 -#define F367TER_SFEC_DISABLE 0xf2d00002 -#define F367TER_SFEC_UNREGUL 0xf2d00001 - -/* SFDLYSETM */ -#define R367TER_SFDLYSETM 0xf2d1 -#define F367TER_SFECDLYSETM_7 0xf2d10080 -#define F367TER_SFEC_SYMBOFFSET_HI 0xf2d1007f - -/* SFDLYSETL */ -#define R367TER_SFDLYSETL 0xf2d2 -#define F367TER_SFEC_SYMBOFFSET_LO 0xf2d200ff - -/* SFOBSCFG */ -#define R367TER_SFOBSCFG 0xf2d3 -#define F367TER_SFEC_OBSCFG 0xf2d300ff - -/* SFOBSM */ -#define R367TER_SFOBSM 0xf2d4 -#define F367TER_SFEC_OBSDATA_HI 0xf2d400ff - -/* SFOBSL */ -#define R367TER_SFOBSL 0xf2d5 -#define F367TER_SFEC_OBSDATA_LO 0xf2d500ff - -/* SFECINFO */ -#define R367TER_SFECINFO 0xf2d6 -#define F367TER_SFECINFO_7 0xf2d60080 -#define F367TER_SFEC_SYNCDLSB 0xf2d60070 -#define F367TER_SFCE_S1cPHASE 0xf2d6000f - -/* SFERRCTRL */ -#define R367TER_SFERRCTRL 0xf2d8 -#define F367TER_SFEC_ERR_SOURCE 0xf2d800f0 -#define F367TER_SFERRCTRL_3 0xf2d80008 -#define F367TER_SFEC_NUM_EVENT 0xf2d80007 - -/* SFERRCNTH */ -#define R367TER_SFERRCNTH 0xf2d9 -#define F367TER_SFERRC_OLDVALUE 0xf2d90080 -#define F367TER_SFEC_ERR_CNT 0xf2d9007f - -/* SFERRCNTM */ -#define R367TER_SFERRCNTM 0xf2da -#define F367TER_SFEC_ERR_CNT_HI 0xf2da00ff - -/* SFERRCNTL */ -#define R367TER_SFERRCNTL 0xf2db -#define F367TER_SFEC_ERR_CNT_LO 0xf2db00ff - -/* SYMBRATEM */ -#define R367TER_SYMBRATEM 0xf2e0 -#define F367TER_DEFGEN_SYMBRATE_HI 0xf2e000ff - -/* SYMBRATEL */ -#define R367TER_SYMBRATEL 0xf2e1 -#define F367TER_DEFGEN_SYMBRATE_LO 0xf2e100ff - -/* SYMBSTATUS */ -#define R367TER_SYMBSTATUS 0xf2e2 -#define F367TER_SYMBDLINE2_OFF 0xf2e20080 -#define F367TER_SDDL_REINIT1 0xf2e20040 -#define F367TER_SDD_REINIT1 0xf2e20020 -#define F367TER_TOKENID_ERROR 0xf2e20010 -#define F367TER_SYMBRATE_OVERFLOW 0xf2e20008 -#define F367TER_SYMBRATE_UNDERFLOW 0xf2e20004 -#define F367TER_TOKENID_RSTEVENT 0xf2e20002 -#define F367TER_TOKENID_RESET1 0xf2e20001 - -/* SYMBCFG */ -#define R367TER_SYMBCFG 0xf2e3 -#define F367TER_SYMBCFG_7 0xf2e30080 -#define F367TER_SYMBCFG_6 0xf2e30040 -#define F367TER_SYMBCFG_5 0xf2e30020 -#define F367TER_SYMBCFG_4 0xf2e30010 -#define F367TER_SYMRATE_FSPEED 0xf2e3000c -#define F367TER_SYMRATE_SSPEED 0xf2e30003 - -/* SYMBFIFOM */ -#define R367TER_SYMBFIFOM 0xf2e4 -#define F367TER_SYMBFIFOM_7 0xf2e40080 -#define F367TER_SYMBFIFOM_6 0xf2e40040 -#define F367TER_DEFGEN_SYMFIFO_HI 0xf2e4003f - -/* SYMBFIFOL */ -#define R367TER_SYMBFIFOL 0xf2e5 -#define F367TER_DEFGEN_SYMFIFO_LO 0xf2e500ff - -/* SYMBOFFSM */ -#define R367TER_SYMBOFFSM 0xf2e6 -#define F367TER_TOKENID_RESET2 0xf2e60080 -#define F367TER_SDDL_REINIT2 0xf2e60040 -#define F367TER_SDD_REINIT2 0xf2e60020 -#define F367TER_SYMBOFFSM_4 0xf2e60010 -#define F367TER_SYMBOFFSM_3 0xf2e60008 -#define F367TER_DEFGEN_SYMBOFFSET_HI 0xf2e60007 - -/* SYMBOFFSL */ -#define R367TER_SYMBOFFSL 0xf2e7 -#define F367TER_DEFGEN_SYMBOFFSET_LO 0xf2e700ff - -/* DEBUG_LT4 */ -#define R367TER_DEBUG_LT4 0xf400 -#define F367TER_F_DEBUG_LT4 0xf40000ff - -/* DEBUG_LT5 */ -#define R367TER_DEBUG_LT5 0xf401 -#define F367TER_F_DEBUG_LT5 0xf40100ff - -/* DEBUG_LT6 */ -#define R367TER_DEBUG_LT6 0xf402 -#define F367TER_F_DEBUG_LT6 0xf40200ff - -/* DEBUG_LT7 */ -#define R367TER_DEBUG_LT7 0xf403 -#define F367TER_F_DEBUG_LT7 0xf40300ff - -/* DEBUG_LT8 */ -#define R367TER_DEBUG_LT8 0xf404 -#define F367TER_F_DEBUG_LT8 0xf40400ff - -/* DEBUG_LT9 */ -#define R367TER_DEBUG_LT9 0xf405 -#define F367TER_F_DEBUG_LT9 0xf40500ff - -#define STV0367TER_NBREGS 445 - -/* ID */ -#define R367CAB_ID 0xf000 -#define F367CAB_IDENTIFICATIONREGISTER 0xf00000ff - -/* I2CRPT */ -#define R367CAB_I2CRPT 0xf001 -#define F367CAB_I2CT_ON 0xf0010080 -#define F367CAB_ENARPT_LEVEL 0xf0010070 -#define F367CAB_SCLT_DELAY 0xf0010008 -#define F367CAB_SCLT_NOD 0xf0010004 -#define F367CAB_STOP_ENABLE 0xf0010002 -#define F367CAB_SDAT_NOD 0xf0010001 - -/* TOPCTRL */ -#define R367CAB_TOPCTRL 0xf002 -#define F367CAB_STDBY 0xf0020080 -#define F367CAB_STDBY_CORE 0xf0020020 -#define F367CAB_QAM_COFDM 0xf0020010 -#define F367CAB_TS_DIS 0xf0020008 -#define F367CAB_DIR_CLK_216 0xf0020004 - -/* IOCFG0 */ -#define R367CAB_IOCFG0 0xf003 -#define F367CAB_OP0_SD 0xf0030080 -#define F367CAB_OP0_VAL 0xf0030040 -#define F367CAB_OP0_OD 0xf0030020 -#define F367CAB_OP0_INV 0xf0030010 -#define F367CAB_OP0_DACVALUE_HI 0xf003000f - -/* DAc0R */ -#define R367CAB_DAC0R 0xf004 -#define F367CAB_OP0_DACVALUE_LO 0xf00400ff - -/* IOCFG1 */ -#define R367CAB_IOCFG1 0xf005 -#define F367CAB_IP0 0xf0050040 -#define F367CAB_OP1_OD 0xf0050020 -#define F367CAB_OP1_INV 0xf0050010 -#define F367CAB_OP1_DACVALUE_HI 0xf005000f - -/* DAC1R */ -#define R367CAB_DAC1R 0xf006 -#define F367CAB_OP1_DACVALUE_LO 0xf00600ff - -/* IOCFG2 */ -#define R367CAB_IOCFG2 0xf007 -#define F367CAB_OP2_LOCK_CONF 0xf00700e0 -#define F367CAB_OP2_OD 0xf0070010 -#define F367CAB_OP2_VAL 0xf0070008 -#define F367CAB_OP1_LOCK_CONF 0xf0070007 - -/* SDFR */ -#define R367CAB_SDFR 0xf008 -#define F367CAB_OP0_FREQ 0xf00800f0 -#define F367CAB_OP1_FREQ 0xf008000f - -/* AUX_CLK */ -#define R367CAB_AUX_CLK 0xf00a -#define F367CAB_AUXFEC_CTL 0xf00a00c0 -#define F367CAB_DIS_CKX4 0xf00a0020 -#define F367CAB_CKSEL 0xf00a0018 -#define F367CAB_CKDIV_PROG 0xf00a0006 -#define F367CAB_AUXCLK_ENA 0xf00a0001 - -/* FREESYS1 */ -#define R367CAB_FREESYS1 0xf00b -#define F367CAB_FREESYS_1 0xf00b00ff - -/* FREESYS2 */ -#define R367CAB_FREESYS2 0xf00c -#define F367CAB_FREESYS_2 0xf00c00ff - -/* FREESYS3 */ -#define R367CAB_FREESYS3 0xf00d -#define F367CAB_FREESYS_3 0xf00d00ff - -/* GPIO_CFG */ -#define R367CAB_GPIO_CFG 0xf00e -#define F367CAB_GPIO7_OD 0xf00e0080 -#define F367CAB_GPIO7_CFG 0xf00e0040 -#define F367CAB_GPIO6_OD 0xf00e0020 -#define F367CAB_GPIO6_CFG 0xf00e0010 -#define F367CAB_GPIO5_OD 0xf00e0008 -#define F367CAB_GPIO5_CFG 0xf00e0004 -#define F367CAB_GPIO4_OD 0xf00e0002 -#define F367CAB_GPIO4_CFG 0xf00e0001 - -/* GPIO_CMD */ -#define R367CAB_GPIO_CMD 0xf00f -#define F367CAB_GPIO7_VAL 0xf00f0008 -#define F367CAB_GPIO6_VAL 0xf00f0004 -#define F367CAB_GPIO5_VAL 0xf00f0002 -#define F367CAB_GPIO4_VAL 0xf00f0001 - -/* TSTRES */ -#define R367CAB_TSTRES 0xf0c0 -#define F367CAB_FRES_DISPLAY 0xf0c00080 -#define F367CAB_FRES_FIFO_AD 0xf0c00020 -#define F367CAB_FRESRS 0xf0c00010 -#define F367CAB_FRESACS 0xf0c00008 -#define F367CAB_FRESFEC 0xf0c00004 -#define F367CAB_FRES_PRIF 0xf0c00002 -#define F367CAB_FRESCORE 0xf0c00001 - -/* ANACTRL */ -#define R367CAB_ANACTRL 0xf0c1 -#define F367CAB_BYPASS_XTAL 0xf0c10040 -#define F367CAB_BYPASS_PLLXN 0xf0c1000c -#define F367CAB_DIS_PAD_OSC 0xf0c10002 -#define F367CAB_STDBY_PLLXN 0xf0c10001 - -/* TSTBUS */ -#define R367CAB_TSTBUS 0xf0c2 -#define F367CAB_TS_BYTE_CLK_INV 0xf0c20080 -#define F367CAB_CFG_IP 0xf0c20070 -#define F367CAB_CFG_TST 0xf0c2000f - -/* RF_AGC1 */ -#define R367CAB_RF_AGC1 0xf0d4 -#define F367CAB_RF_AGC1_LEVEL_HI 0xf0d400ff - -/* RF_AGC2 */ -#define R367CAB_RF_AGC2 0xf0d5 -#define F367CAB_REF_ADGP 0xf0d50080 -#define F367CAB_STDBY_ADCGP 0xf0d50020 -#define F367CAB_RF_AGC1_LEVEL_LO 0xf0d50003 - -/* ANADIGCTRL */ -#define R367CAB_ANADIGCTRL 0xf0d7 -#define F367CAB_SEL_CLKDEM 0xf0d70020 -#define F367CAB_EN_BUFFER_Q 0xf0d70010 -#define F367CAB_EN_BUFFER_I 0xf0d70008 -#define F367CAB_ADC_RIS_EGDE 0xf0d70004 -#define F367CAB_SGN_ADC 0xf0d70002 -#define F367CAB_SEL_AD12_SYNC 0xf0d70001 - -/* PLLMDIV */ -#define R367CAB_PLLMDIV 0xf0d8 -#define F367CAB_PLL_MDIV 0xf0d800ff - -/* PLLNDIV */ -#define R367CAB_PLLNDIV 0xf0d9 -#define F367CAB_PLL_NDIV 0xf0d900ff - -/* PLLSETUP */ -#define R367CAB_PLLSETUP 0xf0da -#define F367CAB_PLL_PDIV 0xf0da0070 -#define F367CAB_PLL_KDIV 0xf0da000f - -/* DUAL_AD12 */ -#define R367CAB_DUAL_AD12 0xf0db -#define F367CAB_FS20M 0xf0db0020 -#define F367CAB_FS50M 0xf0db0010 -#define F367CAB_INMODe0 0xf0db0008 -#define F367CAB_POFFQ 0xf0db0004 -#define F367CAB_POFFI 0xf0db0002 -#define F367CAB_INMODE1 0xf0db0001 - -/* TSTBIST */ -#define R367CAB_TSTBIST 0xf0dc -#define F367CAB_TST_BYP_CLK 0xf0dc0080 -#define F367CAB_TST_GCLKENA_STD 0xf0dc0040 -#define F367CAB_TST_GCLKENA 0xf0dc0020 -#define F367CAB_TST_MEMBIST 0xf0dc001f - -/* CTRL_1 */ -#define R367CAB_CTRL_1 0xf402 -#define F367CAB_SOFT_RST 0xf4020080 -#define F367CAB_EQU_RST 0xf4020008 -#define F367CAB_CRL_RST 0xf4020004 -#define F367CAB_TRL_RST 0xf4020002 -#define F367CAB_AGC_RST 0xf4020001 - -/* CTRL_2 */ -#define R367CAB_CTRL_2 0xf403 -#define F367CAB_DEINT_RST 0xf4030008 -#define F367CAB_RS_RST 0xf4030004 - -/* IT_STATUS1 */ -#define R367CAB_IT_STATUS1 0xf408 -#define F367CAB_SWEEP_OUT 0xf4080080 -#define F367CAB_FSM_CRL 0xf4080040 -#define F367CAB_CRL_LOCK 0xf4080020 -#define F367CAB_MFSM 0xf4080010 -#define F367CAB_TRL_LOCK 0xf4080008 -#define F367CAB_TRL_AGC_LIMIT 0xf4080004 -#define F367CAB_ADJ_AGC_LOCK 0xf4080002 -#define F367CAB_AGC_QAM_LOCK 0xf4080001 - -/* IT_STATUS2 */ -#define R367CAB_IT_STATUS2 0xf409 -#define F367CAB_TSMF_CNT 0xf4090080 -#define F367CAB_TSMF_EOF 0xf4090040 -#define F367CAB_TSMF_RDY 0xf4090020 -#define F367CAB_FEC_NOCORR 0xf4090010 -#define F367CAB_SYNCSTATE 0xf4090008 -#define F367CAB_DEINT_LOCK 0xf4090004 -#define F367CAB_FADDING_FRZ 0xf4090002 -#define F367CAB_TAPMON_ALARM 0xf4090001 - -/* IT_EN1 */ -#define R367CAB_IT_EN1 0xf40a -#define F367CAB_SWEEP_OUTE 0xf40a0080 -#define F367CAB_FSM_CRLE 0xf40a0040 -#define F367CAB_CRL_LOCKE 0xf40a0020 -#define F367CAB_MFSME 0xf40a0010 -#define F367CAB_TRL_LOCKE 0xf40a0008 -#define F367CAB_TRL_AGC_LIMITE 0xf40a0004 -#define F367CAB_ADJ_AGC_LOCKE 0xf40a0002 -#define F367CAB_AGC_LOCKE 0xf40a0001 - -/* IT_EN2 */ -#define R367CAB_IT_EN2 0xf40b -#define F367CAB_TSMF_CNTE 0xf40b0080 -#define F367CAB_TSMF_EOFE 0xf40b0040 -#define F367CAB_TSMF_RDYE 0xf40b0020 -#define F367CAB_FEC_NOCORRE 0xf40b0010 -#define F367CAB_SYNCSTATEE 0xf40b0008 -#define F367CAB_DEINT_LOCKE 0xf40b0004 -#define F367CAB_FADDING_FRZE 0xf40b0002 -#define F367CAB_TAPMON_ALARME 0xf40b0001 - -/* CTRL_STATUS */ -#define R367CAB_CTRL_STATUS 0xf40c -#define F367CAB_QAMFEC_LOCK 0xf40c0004 -#define F367CAB_TSMF_LOCK 0xf40c0002 -#define F367CAB_TSMF_ERROR 0xf40c0001 - -/* TEST_CTL */ -#define R367CAB_TEST_CTL 0xf40f -#define F367CAB_TST_BLK_SEL 0xf40f0060 -#define F367CAB_TST_BUS_SEL 0xf40f001f - -/* AGC_CTL */ -#define R367CAB_AGC_CTL 0xf410 -#define F367CAB_AGC_LCK_TH 0xf41000f0 -#define F367CAB_AGC_ACCUMRSTSEL 0xf4100007 - -/* AGC_IF_CFG */ -#define R367CAB_AGC_IF_CFG 0xf411 -#define F367CAB_AGC_IF_BWSEL 0xf41100f0 -#define F367CAB_AGC_IF_FREEZE 0xf4110002 - -/* AGC_RF_CFG */ -#define R367CAB_AGC_RF_CFG 0xf412 -#define F367CAB_AGC_RF_BWSEL 0xf4120070 -#define F367CAB_AGC_RF_FREEZE 0xf4120002 - -/* AGC_PWM_CFG */ -#define R367CAB_AGC_PWM_CFG 0xf413 -#define F367CAB_AGC_RF_PWM_TST 0xf4130080 -#define F367CAB_AGC_RF_PWM_INV 0xf4130040 -#define F367CAB_AGC_IF_PWM_TST 0xf4130008 -#define F367CAB_AGC_IF_PWM_INV 0xf4130004 -#define F367CAB_AGC_PWM_CLKDIV 0xf4130003 - -/* AGC_PWR_REF_L */ -#define R367CAB_AGC_PWR_REF_L 0xf414 -#define F367CAB_AGC_PWRREF_LO 0xf41400ff - -/* AGC_PWR_REF_H */ -#define R367CAB_AGC_PWR_REF_H 0xf415 -#define F367CAB_AGC_PWRREF_HI 0xf4150003 - -/* AGC_RF_TH_L */ -#define R367CAB_AGC_RF_TH_L 0xf416 -#define F367CAB_AGC_RF_TH_LO 0xf41600ff - -/* AGC_RF_TH_H */ -#define R367CAB_AGC_RF_TH_H 0xf417 -#define F367CAB_AGC_RF_TH_HI 0xf417000f - -/* AGC_IF_LTH_L */ -#define R367CAB_AGC_IF_LTH_L 0xf418 -#define F367CAB_AGC_IF_THLO_LO 0xf41800ff - -/* AGC_IF_LTH_H */ -#define R367CAB_AGC_IF_LTH_H 0xf419 -#define F367CAB_AGC_IF_THLO_HI 0xf419000f - -/* AGC_IF_HTH_L */ -#define R367CAB_AGC_IF_HTH_L 0xf41a -#define F367CAB_AGC_IF_THHI_LO 0xf41a00ff - -/* AGC_IF_HTH_H */ -#define R367CAB_AGC_IF_HTH_H 0xf41b -#define F367CAB_AGC_IF_THHI_HI 0xf41b000f - -/* AGC_PWR_RD_L */ -#define R367CAB_AGC_PWR_RD_L 0xf41c -#define F367CAB_AGC_PWR_WORD_LO 0xf41c00ff - -/* AGC_PWR_RD_M */ -#define R367CAB_AGC_PWR_RD_M 0xf41d -#define F367CAB_AGC_PWR_WORD_ME 0xf41d00ff - -/* AGC_PWR_RD_H */ -#define R367CAB_AGC_PWR_RD_H 0xf41e -#define F367CAB_AGC_PWR_WORD_HI 0xf41e0003 - -/* AGC_PWM_IFCMD_L */ -#define R367CAB_AGC_PWM_IFCMD_L 0xf420 -#define F367CAB_AGC_IF_PWMCMD_LO 0xf42000ff - -/* AGC_PWM_IFCMD_H */ -#define R367CAB_AGC_PWM_IFCMD_H 0xf421 -#define F367CAB_AGC_IF_PWMCMD_HI 0xf421000f - -/* AGC_PWM_RFCMD_L */ -#define R367CAB_AGC_PWM_RFCMD_L 0xf422 -#define F367CAB_AGC_RF_PWMCMD_LO 0xf42200ff - -/* AGC_PWM_RFCMD_H */ -#define R367CAB_AGC_PWM_RFCMD_H 0xf423 -#define F367CAB_AGC_RF_PWMCMD_HI 0xf423000f - -/* IQDEM_CFG */ -#define R367CAB_IQDEM_CFG 0xf424 -#define F367CAB_IQDEM_CLK_SEL 0xf4240004 -#define F367CAB_IQDEM_INVIQ 0xf4240002 -#define F367CAB_IQDEM_A2dTYPE 0xf4240001 - -/* MIX_NCO_LL */ -#define R367CAB_MIX_NCO_LL 0xf425 -#define F367CAB_MIX_NCO_INC_LL 0xf42500ff - -/* MIX_NCO_HL */ -#define R367CAB_MIX_NCO_HL 0xf426 -#define F367CAB_MIX_NCO_INC_HL 0xf42600ff - -/* MIX_NCO_HH */ -#define R367CAB_MIX_NCO_HH 0xf427 -#define F367CAB_MIX_NCO_INVCNST 0xf4270080 -#define F367CAB_MIX_NCO_INC_HH 0xf427007f - -/* SRC_NCO_LL */ -#define R367CAB_SRC_NCO_LL 0xf428 -#define F367CAB_SRC_NCO_INC_LL 0xf42800ff - -/* SRC_NCO_LH */ -#define R367CAB_SRC_NCO_LH 0xf429 -#define F367CAB_SRC_NCO_INC_LH 0xf42900ff - -/* SRC_NCO_HL */ -#define R367CAB_SRC_NCO_HL 0xf42a -#define F367CAB_SRC_NCO_INC_HL 0xf42a00ff - -/* SRC_NCO_HH */ -#define R367CAB_SRC_NCO_HH 0xf42b -#define F367CAB_SRC_NCO_INC_HH 0xf42b007f - -/* IQDEM_GAIN_SRC_L */ -#define R367CAB_IQDEM_GAIN_SRC_L 0xf42c -#define F367CAB_GAIN_SRC_LO 0xf42c00ff - -/* IQDEM_GAIN_SRC_H */ -#define R367CAB_IQDEM_GAIN_SRC_H 0xf42d -#define F367CAB_GAIN_SRC_HI 0xf42d0003 - -/* IQDEM_DCRM_CFG_LL */ -#define R367CAB_IQDEM_DCRM_CFG_LL 0xf430 -#define F367CAB_DCRM0_DCIN_L 0xf43000ff - -/* IQDEM_DCRM_CFG_LH */ -#define R367CAB_IQDEM_DCRM_CFG_LH 0xf431 -#define F367CAB_DCRM1_I_DCIN_L 0xf43100fc -#define F367CAB_DCRM0_DCIN_H 0xf4310003 - -/* IQDEM_DCRM_CFG_HL */ -#define R367CAB_IQDEM_DCRM_CFG_HL 0xf432 -#define F367CAB_DCRM1_Q_DCIN_L 0xf43200f0 -#define F367CAB_DCRM1_I_DCIN_H 0xf432000f - -/* IQDEM_DCRM_CFG_HH */ -#define R367CAB_IQDEM_DCRM_CFG_HH 0xf433 -#define F367CAB_DCRM1_FRZ 0xf4330080 -#define F367CAB_DCRM0_FRZ 0xf4330040 -#define F367CAB_DCRM1_Q_DCIN_H 0xf433003f - -/* IQDEM_ADJ_COEFf0 */ -#define R367CAB_IQDEM_ADJ_COEFF0 0xf434 -#define F367CAB_ADJIIR_COEFF10_L 0xf43400ff - -/* IQDEM_ADJ_COEFF1 */ -#define R367CAB_IQDEM_ADJ_COEFF1 0xf435 -#define F367CAB_ADJIIR_COEFF11_L 0xf43500fc -#define F367CAB_ADJIIR_COEFF10_H 0xf4350003 - -/* IQDEM_ADJ_COEFF2 */ -#define R367CAB_IQDEM_ADJ_COEFF2 0xf436 -#define F367CAB_ADJIIR_COEFF12_L 0xf43600f0 -#define F367CAB_ADJIIR_COEFF11_H 0xf436000f - -/* IQDEM_ADJ_COEFF3 */ -#define R367CAB_IQDEM_ADJ_COEFF3 0xf437 -#define F367CAB_ADJIIR_COEFF20_L 0xf43700c0 -#define F367CAB_ADJIIR_COEFF12_H 0xf437003f - -/* IQDEM_ADJ_COEFF4 */ -#define R367CAB_IQDEM_ADJ_COEFF4 0xf438 -#define F367CAB_ADJIIR_COEFF20_H 0xf43800ff - -/* IQDEM_ADJ_COEFF5 */ -#define R367CAB_IQDEM_ADJ_COEFF5 0xf439 -#define F367CAB_ADJIIR_COEFF21_L 0xf43900ff - -/* IQDEM_ADJ_COEFF6 */ -#define R367CAB_IQDEM_ADJ_COEFF6 0xf43a -#define F367CAB_ADJIIR_COEFF22_L 0xf43a00fc -#define F367CAB_ADJIIR_COEFF21_H 0xf43a0003 - -/* IQDEM_ADJ_COEFF7 */ -#define R367CAB_IQDEM_ADJ_COEFF7 0xf43b -#define F367CAB_ADJIIR_COEFF22_H 0xf43b000f - -/* IQDEM_ADJ_EN */ -#define R367CAB_IQDEM_ADJ_EN 0xf43c -#define F367CAB_ALLPASSFILT_EN 0xf43c0008 -#define F367CAB_ADJ_AGC_EN 0xf43c0004 -#define F367CAB_ADJ_COEFF_FRZ 0xf43c0002 -#define F367CAB_ADJ_EN 0xf43c0001 - -/* IQDEM_ADJ_AGC_REF */ -#define R367CAB_IQDEM_ADJ_AGC_REF 0xf43d -#define F367CAB_ADJ_AGC_REF 0xf43d00ff - -/* ALLPASSFILT1 */ -#define R367CAB_ALLPASSFILT1 0xf440 -#define F367CAB_ALLPASSFILT_COEFF1_LO 0xf44000ff - -/* ALLPASSFILT2 */ -#define R367CAB_ALLPASSFILT2 0xf441 -#define F367CAB_ALLPASSFILT_COEFF1_ME 0xf44100ff - -/* ALLPASSFILT3 */ -#define R367CAB_ALLPASSFILT3 0xf442 -#define F367CAB_ALLPASSFILT_COEFF2_LO 0xf44200c0 -#define F367CAB_ALLPASSFILT_COEFF1_HI 0xf442003f - -/* ALLPASSFILT4 */ -#define R367CAB_ALLPASSFILT4 0xf443 -#define F367CAB_ALLPASSFILT_COEFF2_MEL 0xf44300ff - -/* ALLPASSFILT5 */ -#define R367CAB_ALLPASSFILT5 0xf444 -#define F367CAB_ALLPASSFILT_COEFF2_MEH 0xf44400ff - -/* ALLPASSFILT6 */ -#define R367CAB_ALLPASSFILT6 0xf445 -#define F367CAB_ALLPASSFILT_COEFF3_LO 0xf44500f0 -#define F367CAB_ALLPASSFILT_COEFF2_HI 0xf445000f - -/* ALLPASSFILT7 */ -#define R367CAB_ALLPASSFILT7 0xf446 -#define F367CAB_ALLPASSFILT_COEFF3_MEL 0xf44600ff - -/* ALLPASSFILT8 */ -#define R367CAB_ALLPASSFILT8 0xf447 -#define F367CAB_ALLPASSFILT_COEFF3_MEH 0xf44700ff - -/* ALLPASSFILT9 */ -#define R367CAB_ALLPASSFILT9 0xf448 -#define F367CAB_ALLPASSFILT_COEFF4_LO 0xf44800fc -#define F367CAB_ALLPASSFILT_COEFF3_HI 0xf4480003 - -/* ALLPASSFILT10 */ -#define R367CAB_ALLPASSFILT10 0xf449 -#define F367CAB_ALLPASSFILT_COEFF4_ME 0xf44900ff - -/* ALLPASSFILT11 */ -#define R367CAB_ALLPASSFILT11 0xf44a -#define F367CAB_ALLPASSFILT_COEFF4_HI 0xf44a00ff - -/* TRL_AGC_CFG */ -#define R367CAB_TRL_AGC_CFG 0xf450 -#define F367CAB_TRL_AGC_FREEZE 0xf4500080 -#define F367CAB_TRL_AGC_REF 0xf450007f - -/* TRL_LPF_CFG */ -#define R367CAB_TRL_LPF_CFG 0xf454 -#define F367CAB_NYQPOINT_INV 0xf4540040 -#define F367CAB_TRL_SHIFT 0xf4540030 -#define F367CAB_NYQ_COEFF_SEL 0xf454000c -#define F367CAB_TRL_LPF_FREEZE 0xf4540002 -#define F367CAB_TRL_LPF_CRT 0xf4540001 - -/* TRL_LPF_ACQ_GAIN */ -#define R367CAB_TRL_LPF_ACQ_GAIN 0xf455 -#define F367CAB_TRL_GDIR_ACQ 0xf4550070 -#define F367CAB_TRL_GINT_ACQ 0xf4550007 - -/* TRL_LPF_TRK_GAIN */ -#define R367CAB_TRL_LPF_TRK_GAIN 0xf456 -#define F367CAB_TRL_GDIR_TRK 0xf4560070 -#define F367CAB_TRL_GINT_TRK 0xf4560007 - -/* TRL_LPF_OUT_GAIN */ -#define R367CAB_TRL_LPF_OUT_GAIN 0xf457 -#define F367CAB_TRL_GAIN_OUT 0xf4570007 - -/* TRL_LOCKDET_LTH */ -#define R367CAB_TRL_LOCKDET_LTH 0xf458 -#define F367CAB_TRL_LCK_THLO 0xf4580007 - -/* TRL_LOCKDET_HTH */ -#define R367CAB_TRL_LOCKDET_HTH 0xf459 -#define F367CAB_TRL_LCK_THHI 0xf45900ff - -/* TRL_LOCKDET_TRGVAL */ -#define R367CAB_TRL_LOCKDET_TRGVAL 0xf45a -#define F367CAB_TRL_LCK_TRG 0xf45a00ff - -/* IQ_QAM */ -#define R367CAB_IQ_QAM 0xf45c -#define F367CAB_IQ_INPUT 0xf45c0008 -#define F367CAB_DETECT_MODE 0xf45c0007 - -/* FSM_STATE */ -#define R367CAB_FSM_STATE 0xf460 -#define F367CAB_CRL_DFE 0xf4600080 -#define F367CAB_DFE_START 0xf4600040 -#define F367CAB_CTRLG_START 0xf4600030 -#define F367CAB_FSM_FORCESTATE 0xf460000f - -/* FSM_CTL */ -#define R367CAB_FSM_CTL 0xf461 -#define F367CAB_FEC2_EN 0xf4610040 -#define F367CAB_SIT_EN 0xf4610020 -#define F367CAB_TRL_AHEAD 0xf4610010 -#define F367CAB_TRL2_EN 0xf4610008 -#define F367CAB_FSM_EQA1_EN 0xf4610004 -#define F367CAB_FSM_BKP_DIS 0xf4610002 -#define F367CAB_FSM_FORCE_EN 0xf4610001 - -/* FSM_STS */ -#define R367CAB_FSM_STS 0xf462 -#define F367CAB_FSM_STATUS 0xf462000f - -/* FSM_SNR0_HTH */ -#define R367CAB_FSM_SNR0_HTH 0xf463 -#define F367CAB_SNR0_HTH 0xf46300ff - -/* FSM_SNR1_HTH */ -#define R367CAB_FSM_SNR1_HTH 0xf464 -#define F367CAB_SNR1_HTH 0xf46400ff - -/* FSM_SNR2_HTH */ -#define R367CAB_FSM_SNR2_HTH 0xf465 -#define F367CAB_SNR2_HTH 0xf46500ff - -/* FSM_SNR0_LTH */ -#define R367CAB_FSM_SNR0_LTH 0xf466 -#define F367CAB_SNR0_LTH 0xf46600ff - -/* FSM_SNR1_LTH */ -#define R367CAB_FSM_SNR1_LTH 0xf467 -#define F367CAB_SNR1_LTH 0xf46700ff - -/* FSM_EQA1_HTH */ -#define R367CAB_FSM_EQA1_HTH 0xf468 -#define F367CAB_SNR3_HTH_LO 0xf46800f0 -#define F367CAB_EQA1_HTH 0xf468000f - -/* FSM_TEMPO */ -#define R367CAB_FSM_TEMPO 0xf469 -#define F367CAB_SIT 0xf46900c0 -#define F367CAB_WST 0xf4690038 -#define F367CAB_ELT 0xf4690006 -#define F367CAB_SNR3_HTH_HI 0xf4690001 - -/* FSM_CONFIG */ -#define R367CAB_FSM_CONFIG 0xf46a -#define F367CAB_FEC2_DFEOFF 0xf46a0004 -#define F367CAB_PRIT_STATE 0xf46a0002 -#define F367CAB_MODMAP_STATE 0xf46a0001 - -/* EQU_I_TESTTAP_L */ -#define R367CAB_EQU_I_TESTTAP_L 0xf474 -#define F367CAB_I_TEST_TAP_L 0xf47400ff - -/* EQU_I_TESTTAP_M */ -#define R367CAB_EQU_I_TESTTAP_M 0xf475 -#define F367CAB_I_TEST_TAP_M 0xf47500ff - -/* EQU_I_TESTTAP_H */ -#define R367CAB_EQU_I_TESTTAP_H 0xf476 -#define F367CAB_I_TEST_TAP_H 0xf476001f - -/* EQU_TESTAP_CFG */ -#define R367CAB_EQU_TESTAP_CFG 0xf477 -#define F367CAB_TEST_FFE_DFE_SEL 0xf4770040 -#define F367CAB_TEST_TAP_SELECT 0xf477003f - -/* EQU_Q_TESTTAP_L */ -#define R367CAB_EQU_Q_TESTTAP_L 0xf478 -#define F367CAB_Q_TEST_TAP_L 0xf47800ff - -/* EQU_Q_TESTTAP_M */ -#define R367CAB_EQU_Q_TESTTAP_M 0xf479 -#define F367CAB_Q_TEST_TAP_M 0xf47900ff - -/* EQU_Q_TESTTAP_H */ -#define R367CAB_EQU_Q_TESTTAP_H 0xf47a -#define F367CAB_Q_TEST_TAP_H 0xf47a001f - -/* EQU_TAP_CTRL */ -#define R367CAB_EQU_TAP_CTRL 0xf47b -#define F367CAB_MTAP_FRZ 0xf47b0010 -#define F367CAB_PRE_FREEZE 0xf47b0008 -#define F367CAB_DFE_TAPMON_EN 0xf47b0004 -#define F367CAB_FFE_TAPMON_EN 0xf47b0002 -#define F367CAB_MTAP_ONLY 0xf47b0001 - -/* EQU_CTR_CRL_CONTROL_L */ -#define R367CAB_EQU_CTR_CRL_CONTROL_L 0xf47c -#define F367CAB_EQU_CTR_CRL_CONTROL_LO 0xf47c00ff - -/* EQU_CTR_CRL_CONTROL_H */ -#define R367CAB_EQU_CTR_CRL_CONTROL_H 0xf47d -#define F367CAB_EQU_CTR_CRL_CONTROL_HI 0xf47d00ff - -/* EQU_CTR_HIPOW_L */ -#define R367CAB_EQU_CTR_HIPOW_L 0xf47e -#define F367CAB_CTR_HIPOW_L 0xf47e00ff - -/* EQU_CTR_HIPOW_H */ -#define R367CAB_EQU_CTR_HIPOW_H 0xf47f -#define F367CAB_CTR_HIPOW_H 0xf47f00ff - -/* EQU_I_EQU_LO */ -#define R367CAB_EQU_I_EQU_LO 0xf480 -#define F367CAB_EQU_I_EQU_L 0xf48000ff - -/* EQU_I_EQU_HI */ -#define R367CAB_EQU_I_EQU_HI 0xf481 -#define F367CAB_EQU_I_EQU_H 0xf4810003 - -/* EQU_Q_EQU_LO */ -#define R367CAB_EQU_Q_EQU_LO 0xf482 -#define F367CAB_EQU_Q_EQU_L 0xf48200ff - -/* EQU_Q_EQU_HI */ -#define R367CAB_EQU_Q_EQU_HI 0xf483 -#define F367CAB_EQU_Q_EQU_H 0xf4830003 - -/* EQU_MAPPER */ -#define R367CAB_EQU_MAPPER 0xf484 -#define F367CAB_QUAD_AUTO 0xf4840080 -#define F367CAB_QUAD_INV 0xf4840040 -#define F367CAB_QAM_MODE 0xf4840007 - -/* EQU_SWEEP_RATE */ -#define R367CAB_EQU_SWEEP_RATE 0xf485 -#define F367CAB_SNR_PER 0xf48500c0 -#define F367CAB_SWEEP_RATE 0xf485003f - -/* EQU_SNR_LO */ -#define R367CAB_EQU_SNR_LO 0xf486 -#define F367CAB_SNR_LO 0xf48600ff - -/* EQU_SNR_HI */ -#define R367CAB_EQU_SNR_HI 0xf487 -#define F367CAB_SNR_HI 0xf48700ff - -/* EQU_GAMMA_LO */ -#define R367CAB_EQU_GAMMA_LO 0xf488 -#define F367CAB_GAMMA_LO 0xf48800ff - -/* EQU_GAMMA_HI */ -#define R367CAB_EQU_GAMMA_HI 0xf489 -#define F367CAB_GAMMA_ME 0xf48900ff - -/* EQU_ERR_GAIN */ -#define R367CAB_EQU_ERR_GAIN 0xf48a -#define F367CAB_EQA1MU 0xf48a0070 -#define F367CAB_CRL2MU 0xf48a000e -#define F367CAB_GAMMA_HI 0xf48a0001 - -/* EQU_RADIUS */ -#define R367CAB_EQU_RADIUS 0xf48b -#define F367CAB_RADIUS 0xf48b00ff - -/* EQU_FFE_MAINTAP */ -#define R367CAB_EQU_FFE_MAINTAP 0xf48c -#define F367CAB_FFE_MAINTAP_INIT 0xf48c00ff - -/* EQU_FFE_LEAKAGE */ -#define R367CAB_EQU_FFE_LEAKAGE 0xf48e -#define F367CAB_LEAK_PER 0xf48e00f0 -#define F367CAB_EQU_OUTSEL 0xf48e0002 -#define F367CAB_PNT2dFE 0xf48e0001 - -/* EQU_FFE_MAINTAP_POS */ -#define R367CAB_EQU_FFE_MAINTAP_POS 0xf48f -#define F367CAB_FFE_LEAK_EN 0xf48f0080 -#define F367CAB_DFE_LEAK_EN 0xf48f0040 -#define F367CAB_FFE_MAINTAP_POS 0xf48f003f - -/* EQU_GAIN_WIDE */ -#define R367CAB_EQU_GAIN_WIDE 0xf490 -#define F367CAB_DFE_GAIN_WIDE 0xf49000f0 -#define F367CAB_FFE_GAIN_WIDE 0xf490000f - -/* EQU_GAIN_NARROW */ -#define R367CAB_EQU_GAIN_NARROW 0xf491 -#define F367CAB_DFE_GAIN_NARROW 0xf49100f0 -#define F367CAB_FFE_GAIN_NARROW 0xf491000f - -/* EQU_CTR_LPF_GAIN */ -#define R367CAB_EQU_CTR_LPF_GAIN 0xf492 -#define F367CAB_CTR_GTO 0xf4920080 -#define F367CAB_CTR_GDIR 0xf4920070 -#define F367CAB_SWEEP_EN 0xf4920008 -#define F367CAB_CTR_GINT 0xf4920007 - -/* EQU_CRL_LPF_GAIN */ -#define R367CAB_EQU_CRL_LPF_GAIN 0xf493 -#define F367CAB_CRL_GTO 0xf4930080 -#define F367CAB_CRL_GDIR 0xf4930070 -#define F367CAB_SWEEP_DIR 0xf4930008 -#define F367CAB_CRL_GINT 0xf4930007 - -/* EQU_GLOBAL_GAIN */ -#define R367CAB_EQU_GLOBAL_GAIN 0xf494 -#define F367CAB_CRL_GAIN 0xf49400f8 -#define F367CAB_CTR_INC_GAIN 0xf4940004 -#define F367CAB_CTR_FRAC 0xf4940003 - -/* EQU_CRL_LD_SEN */ -#define R367CAB_EQU_CRL_LD_SEN 0xf495 -#define F367CAB_CTR_BADPOINT_EN 0xf4950080 -#define F367CAB_CTR_GAIN 0xf4950070 -#define F367CAB_LIMANEN 0xf4950008 -#define F367CAB_CRL_LD_SEN 0xf4950007 - -/* EQU_CRL_LD_VAL */ -#define R367CAB_EQU_CRL_LD_VAL 0xf496 -#define F367CAB_CRL_BISTH_LIMIT 0xf4960080 -#define F367CAB_CARE_EN 0xf4960040 -#define F367CAB_CRL_LD_PER 0xf4960030 -#define F367CAB_CRL_LD_WST 0xf496000c -#define F367CAB_CRL_LD_TFS 0xf4960003 - -/* EQU_CRL_TFR */ -#define R367CAB_EQU_CRL_TFR 0xf497 -#define F367CAB_CRL_LD_TFR 0xf49700ff - -/* EQU_CRL_BISTH_LO */ -#define R367CAB_EQU_CRL_BISTH_LO 0xf498 -#define F367CAB_CRL_BISTH_LO 0xf49800ff - -/* EQU_CRL_BISTH_HI */ -#define R367CAB_EQU_CRL_BISTH_HI 0xf499 -#define F367CAB_CRL_BISTH_HI 0xf49900ff - -/* EQU_SWEEP_RANGE_LO */ -#define R367CAB_EQU_SWEEP_RANGE_LO 0xf49a -#define F367CAB_SWEEP_RANGE_LO 0xf49a00ff - -/* EQU_SWEEP_RANGE_HI */ -#define R367CAB_EQU_SWEEP_RANGE_HI 0xf49b -#define F367CAB_SWEEP_RANGE_HI 0xf49b00ff - -/* EQU_CRL_LIMITER */ -#define R367CAB_EQU_CRL_LIMITER 0xf49c -#define F367CAB_BISECTOR_EN 0xf49c0080 -#define F367CAB_PHEST128_EN 0xf49c0040 -#define F367CAB_CRL_LIM 0xf49c003f - -/* EQU_MODULUS_MAP */ -#define R367CAB_EQU_MODULUS_MAP 0xf49d -#define F367CAB_PNT_DEPTH 0xf49d00e0 -#define F367CAB_MODULUS_CMP 0xf49d001f - -/* EQU_PNT_GAIN */ -#define R367CAB_EQU_PNT_GAIN 0xf49e -#define F367CAB_PNT_EN 0xf49e0080 -#define F367CAB_MODULUSMAP_EN 0xf49e0040 -#define F367CAB_PNT_GAIN 0xf49e003f - -/* FEC_AC_CTR_0 */ -#define R367CAB_FEC_AC_CTR_0 0xf4a8 -#define F367CAB_BE_BYPASS 0xf4a80020 -#define F367CAB_REFRESH47 0xf4a80010 -#define F367CAB_CT_NBST 0xf4a80008 -#define F367CAB_TEI_ENA 0xf4a80004 -#define F367CAB_DS_ENA 0xf4a80002 -#define F367CAB_TSMF_EN 0xf4a80001 - -/* FEC_AC_CTR_1 */ -#define R367CAB_FEC_AC_CTR_1 0xf4a9 -#define F367CAB_DEINT_DEPTH 0xf4a900ff - -/* FEC_AC_CTR_2 */ -#define R367CAB_FEC_AC_CTR_2 0xf4aa -#define F367CAB_DEINT_M 0xf4aa00f8 -#define F367CAB_DIS_UNLOCK 0xf4aa0004 -#define F367CAB_DESCR_MODE 0xf4aa0003 - -/* FEC_AC_CTR_3 */ -#define R367CAB_FEC_AC_CTR_3 0xf4ab -#define F367CAB_DI_UNLOCK 0xf4ab0080 -#define F367CAB_DI_FREEZE 0xf4ab0040 -#define F367CAB_MISMATCH 0xf4ab0030 -#define F367CAB_ACQ_MODE 0xf4ab000c -#define F367CAB_TRK_MODE 0xf4ab0003 - -/* FEC_STATUS */ -#define R367CAB_FEC_STATUS 0xf4ac -#define F367CAB_DEINT_SMCNTR 0xf4ac00e0 -#define F367CAB_DEINT_SYNCSTATE 0xf4ac0018 -#define F367CAB_DEINT_SYNLOST 0xf4ac0004 -#define F367CAB_DESCR_SYNCSTATE 0xf4ac0002 - -/* RS_COUNTER_0 */ -#define R367CAB_RS_COUNTER_0 0xf4ae -#define F367CAB_BK_CT_L 0xf4ae00ff - -/* RS_COUNTER_1 */ -#define R367CAB_RS_COUNTER_1 0xf4af -#define F367CAB_BK_CT_H 0xf4af00ff - -/* RS_COUNTER_2 */ -#define R367CAB_RS_COUNTER_2 0xf4b0 -#define F367CAB_CORR_CT_L 0xf4b000ff - -/* RS_COUNTER_3 */ -#define R367CAB_RS_COUNTER_3 0xf4b1 -#define F367CAB_CORR_CT_H 0xf4b100ff - -/* RS_COUNTER_4 */ -#define R367CAB_RS_COUNTER_4 0xf4b2 -#define F367CAB_UNCORR_CT_L 0xf4b200ff - -/* RS_COUNTER_5 */ -#define R367CAB_RS_COUNTER_5 0xf4b3 -#define F367CAB_UNCORR_CT_H 0xf4b300ff - -/* BERT_0 */ -#define R367CAB_BERT_0 0xf4b4 -#define F367CAB_RS_NOCORR 0xf4b40004 -#define F367CAB_CT_HOLD 0xf4b40002 -#define F367CAB_CT_CLEAR 0xf4b40001 - -/* BERT_1 */ -#define R367CAB_BERT_1 0xf4b5 -#define F367CAB_BERT_ON 0xf4b50020 -#define F367CAB_BERT_ERR_SRC 0xf4b50010 -#define F367CAB_BERT_ERR_MODE 0xf4b50008 -#define F367CAB_BERT_NBYTE 0xf4b50007 - -/* BERT_2 */ -#define R367CAB_BERT_2 0xf4b6 -#define F367CAB_BERT_ERRCOUNT_L 0xf4b600ff - -/* BERT_3 */ -#define R367CAB_BERT_3 0xf4b7 -#define F367CAB_BERT_ERRCOUNT_H 0xf4b700ff - -/* OUTFORMAT_0 */ -#define R367CAB_OUTFORMAT_0 0xf4b8 -#define F367CAB_CLK_POLARITY 0xf4b80080 -#define F367CAB_FEC_TYPE 0xf4b80040 -#define F367CAB_SYNC_STRIP 0xf4b80008 -#define F367CAB_TS_SWAP 0xf4b80004 -#define F367CAB_OUTFORMAT 0xf4b80003 - -/* OUTFORMAT_1 */ -#define R367CAB_OUTFORMAT_1 0xf4b9 -#define F367CAB_CI_DIVRANGE 0xf4b900ff - -/* SMOOTHER_2 */ -#define R367CAB_SMOOTHER_2 0xf4be -#define F367CAB_FIFO_BYPASS 0xf4be0020 - -/* TSMF_CTRL_0 */ -#define R367CAB_TSMF_CTRL_0 0xf4c0 -#define F367CAB_TS_NUMBER 0xf4c0001e -#define F367CAB_SEL_MODE 0xf4c00001 - -/* TSMF_CTRL_1 */ -#define R367CAB_TSMF_CTRL_1 0xf4c1 -#define F367CAB_CHECK_ERROR_BIT 0xf4c10080 -#define F367CAB_CHCK_F_SYNC 0xf4c10040 -#define F367CAB_H_MODE 0xf4c10008 -#define F367CAB_D_V_MODE 0xf4c10004 -#define F367CAB_MODE 0xf4c10003 - -/* TSMF_CTRL_3 */ -#define R367CAB_TSMF_CTRL_3 0xf4c3 -#define F367CAB_SYNC_IN_COUNT 0xf4c300f0 -#define F367CAB_SYNC_OUT_COUNT 0xf4c3000f - -/* TS_ON_ID_0 */ -#define R367CAB_TS_ON_ID_0 0xf4c4 -#define F367CAB_TS_ID_L 0xf4c400ff - -/* TS_ON_ID_1 */ -#define R367CAB_TS_ON_ID_1 0xf4c5 -#define F367CAB_TS_ID_H 0xf4c500ff - -/* TS_ON_ID_2 */ -#define R367CAB_TS_ON_ID_2 0xf4c6 -#define F367CAB_ON_ID_L 0xf4c600ff - -/* TS_ON_ID_3 */ -#define R367CAB_TS_ON_ID_3 0xf4c7 -#define F367CAB_ON_ID_H 0xf4c700ff - -/* RE_STATUS_0 */ -#define R367CAB_RE_STATUS_0 0xf4c8 -#define F367CAB_RECEIVE_STATUS_L 0xf4c800ff - -/* RE_STATUS_1 */ -#define R367CAB_RE_STATUS_1 0xf4c9 -#define F367CAB_RECEIVE_STATUS_LH 0xf4c900ff - -/* RE_STATUS_2 */ -#define R367CAB_RE_STATUS_2 0xf4ca -#define F367CAB_RECEIVE_STATUS_HL 0xf4ca00ff - -/* RE_STATUS_3 */ -#define R367CAB_RE_STATUS_3 0xf4cb -#define F367CAB_RECEIVE_STATUS_HH 0xf4cb003f - -/* TS_STATUS_0 */ -#define R367CAB_TS_STATUS_0 0xf4cc -#define F367CAB_TS_STATUS_L 0xf4cc00ff - -/* TS_STATUS_1 */ -#define R367CAB_TS_STATUS_1 0xf4cd -#define F367CAB_TS_STATUS_H 0xf4cd007f - -/* TS_STATUS_2 */ -#define R367CAB_TS_STATUS_2 0xf4ce -#define F367CAB_ERROR 0xf4ce0080 -#define F367CAB_EMERGENCY 0xf4ce0040 -#define F367CAB_CRE_TS 0xf4ce0030 -#define F367CAB_VER 0xf4ce000e -#define F367CAB_M_LOCK 0xf4ce0001 - -/* TS_STATUS_3 */ -#define R367CAB_TS_STATUS_3 0xf4cf -#define F367CAB_UPDATE_READY 0xf4cf0080 -#define F367CAB_END_FRAME_HEADER 0xf4cf0040 -#define F367CAB_CONTCNT 0xf4cf0020 -#define F367CAB_TS_IDENTIFIER_SEL 0xf4cf000f - -/* T_O_ID_0 */ -#define R367CAB_T_O_ID_0 0xf4d0 -#define F367CAB_ON_ID_I_L 0xf4d000ff - -/* T_O_ID_1 */ -#define R367CAB_T_O_ID_1 0xf4d1 -#define F367CAB_ON_ID_I_H 0xf4d100ff - -/* T_O_ID_2 */ -#define R367CAB_T_O_ID_2 0xf4d2 -#define F367CAB_TS_ID_I_L 0xf4d200ff - -/* T_O_ID_3 */ -#define R367CAB_T_O_ID_3 0xf4d3 -#define F367CAB_TS_ID_I_H 0xf4d300ff - -#define STV0367CAB_NBREGS 187 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1986 +0,0 @@ -/* - * stv0900_core.c - * - * Driver for ST STV0900 satellite demodulator IC. - * - * Copyright (C) ST Microelectronics. - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "stv0900.h" -#include "stv0900_reg.h" -#include "stv0900_priv.h" -#include "stv0900_init.h" - -int stvdebug = 1; -module_param_named(debug, stvdebug, int, 0644); - -/* internal params node */ -struct stv0900_inode { - /* pointer for internal params, one for each pair of demods */ - struct stv0900_internal *internal; - struct stv0900_inode *next_inode; -}; - -/* first internal params */ -static struct stv0900_inode *stv0900_first_inode; - -/* find chip by i2c adapter and i2c address */ -static struct stv0900_inode *find_inode(struct i2c_adapter *i2c_adap, - u8 i2c_addr) -{ - struct stv0900_inode *temp_chip = stv0900_first_inode; - - if (temp_chip != NULL) { - /* - Search of the last stv0900 chip or - find it by i2c adapter and i2c address */ - while ((temp_chip != NULL) && - ((temp_chip->internal->i2c_adap != i2c_adap) || - (temp_chip->internal->i2c_addr != i2c_addr))) - - temp_chip = temp_chip->next_inode; - - } - - return temp_chip; -} - -/* deallocating chip */ -static void remove_inode(struct stv0900_internal *internal) -{ - struct stv0900_inode *prev_node = stv0900_first_inode; - struct stv0900_inode *del_node = find_inode(internal->i2c_adap, - internal->i2c_addr); - - if (del_node != NULL) { - if (del_node == stv0900_first_inode) { - stv0900_first_inode = del_node->next_inode; - } else { - while (prev_node->next_inode != del_node) - prev_node = prev_node->next_inode; - - if (del_node->next_inode == NULL) - prev_node->next_inode = NULL; - else - prev_node->next_inode = - prev_node->next_inode->next_inode; - } - - kfree(del_node); - } -} - -/* allocating new chip */ -static struct stv0900_inode *append_internal(struct stv0900_internal *internal) -{ - struct stv0900_inode *new_node = stv0900_first_inode; - - if (new_node == NULL) { - new_node = kmalloc(sizeof(struct stv0900_inode), GFP_KERNEL); - stv0900_first_inode = new_node; - } else { - while (new_node->next_inode != NULL) - new_node = new_node->next_inode; - - new_node->next_inode = kmalloc(sizeof(struct stv0900_inode), - GFP_KERNEL); - if (new_node->next_inode != NULL) - new_node = new_node->next_inode; - else - new_node = NULL; - } - - if (new_node != NULL) { - new_node->internal = internal; - new_node->next_inode = NULL; - } - - return new_node; -} - -s32 ge2comp(s32 a, s32 width) -{ - if (width == 32) - return a; - else - return (a >= (1 << (width - 1))) ? (a - (1 << width)) : a; -} - -void stv0900_write_reg(struct stv0900_internal *intp, u16 reg_addr, - u8 reg_data) -{ - u8 data[3]; - int ret; - struct i2c_msg i2cmsg = { - .addr = intp->i2c_addr, - .flags = 0, - .len = 3, - .buf = data, - }; - - data[0] = MSB(reg_addr); - data[1] = LSB(reg_addr); - data[2] = reg_data; - - ret = i2c_transfer(intp->i2c_adap, &i2cmsg, 1); - if (ret != 1) - dprintk("%s: i2c error %d\n", __func__, ret); -} - -u8 stv0900_read_reg(struct stv0900_internal *intp, u16 reg) -{ - int ret; - u8 b0[] = { MSB(reg), LSB(reg) }; - u8 buf = 0; - struct i2c_msg msg[] = { - { - .addr = intp->i2c_addr, - .flags = 0, - .buf = b0, - .len = 2, - }, { - .addr = intp->i2c_addr, - .flags = I2C_M_RD, - .buf = &buf, - .len = 1, - }, - }; - - ret = i2c_transfer(intp->i2c_adap, msg, 2); - if (ret != 2) - dprintk("%s: i2c error %d, reg[0x%02x]\n", - __func__, ret, reg); - - return buf; -} - -static void extract_mask_pos(u32 label, u8 *mask, u8 *pos) -{ - u8 position = 0, i = 0; - - (*mask) = label & 0xff; - - while ((position == 0) && (i < 8)) { - position = ((*mask) >> i) & 0x01; - i++; - } - - (*pos) = (i - 1); -} - -void stv0900_write_bits(struct stv0900_internal *intp, u32 label, u8 val) -{ - u8 reg, mask, pos; - - reg = stv0900_read_reg(intp, (label >> 16) & 0xffff); - extract_mask_pos(label, &mask, &pos); - - val = mask & (val << pos); - - reg = (reg & (~mask)) | val; - stv0900_write_reg(intp, (label >> 16) & 0xffff, reg); - -} - -u8 stv0900_get_bits(struct stv0900_internal *intp, u32 label) -{ - u8 val = 0xff; - u8 mask, pos; - - extract_mask_pos(label, &mask, &pos); - - val = stv0900_read_reg(intp, label >> 16); - val = (val & mask) >> pos; - - return val; -} - -static enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp) -{ - s32 i; - - if (intp == NULL) - return STV0900_INVALID_HANDLE; - - intp->chip_id = stv0900_read_reg(intp, R0900_MID); - - if (intp->errs != STV0900_NO_ERROR) - return intp->errs; - - /*Startup sequence*/ - stv0900_write_reg(intp, R0900_P1_DMDISTATE, 0x5c); - stv0900_write_reg(intp, R0900_P2_DMDISTATE, 0x5c); - msleep(3); - stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x6c); - stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x6f); - stv0900_write_reg(intp, R0900_P1_I2CRPT, 0x20); - stv0900_write_reg(intp, R0900_P2_I2CRPT, 0x20); - stv0900_write_reg(intp, R0900_NCOARSE, 0x13); - msleep(3); - stv0900_write_reg(intp, R0900_I2CCFG, 0x08); - - switch (intp->clkmode) { - case 0: - case 2: - stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 - | intp->clkmode); - break; - default: - /* preserve SELOSCI bit */ - i = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL); - stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | i); - break; - } - - msleep(3); - for (i = 0; i < 181; i++) - stv0900_write_reg(intp, STV0900_InitVal[i][0], - STV0900_InitVal[i][1]); - - if (stv0900_read_reg(intp, R0900_MID) >= 0x20) { - stv0900_write_reg(intp, R0900_TSGENERAL, 0x0c); - for (i = 0; i < 32; i++) - stv0900_write_reg(intp, STV0900_Cut20_AddOnVal[i][0], - STV0900_Cut20_AddOnVal[i][1]); - } - - stv0900_write_reg(intp, R0900_P1_FSPYCFG, 0x6c); - stv0900_write_reg(intp, R0900_P2_FSPYCFG, 0x6c); - - stv0900_write_reg(intp, R0900_P1_PDELCTRL2, 0x01); - stv0900_write_reg(intp, R0900_P2_PDELCTRL2, 0x21); - - stv0900_write_reg(intp, R0900_P1_PDELCTRL3, 0x20); - stv0900_write_reg(intp, R0900_P2_PDELCTRL3, 0x20); - - stv0900_write_reg(intp, R0900_TSTRES0, 0x80); - stv0900_write_reg(intp, R0900_TSTRES0, 0x00); - - return STV0900_NO_ERROR; -} - -static u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk) -{ - u32 mclk = 90000000, div = 0, ad_div = 0; - - div = stv0900_get_bits(intp, F0900_M_DIV); - ad_div = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6); - - mclk = (div + 1) * ext_clk / ad_div; - - dprintk("%s: Calculated Mclk = %d\n", __func__, mclk); - - return mclk; -} - -static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk) -{ - u32 m_div, clk_sel; - - dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk, - intp->quartz); - - if (intp == NULL) - return STV0900_INVALID_HANDLE; - - if (intp->errs) - return STV0900_I2C_ERROR; - - clk_sel = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6); - m_div = ((clk_sel * mclk) / intp->quartz) - 1; - stv0900_write_bits(intp, F0900_M_DIV, m_div); - intp->mclk = stv0900_get_mclk_freq(intp, - intp->quartz); - - /*Set the DiseqC frequency to 22KHz */ - /* - Formula: - DiseqC_TX_Freq= MasterClock/(32*F22TX_Reg) - DiseqC_RX_Freq= MasterClock/(32*F22RX_Reg) - */ - m_div = intp->mclk / 704000; - stv0900_write_reg(intp, R0900_P1_F22TX, m_div); - stv0900_write_reg(intp, R0900_P1_F22RX, m_div); - - stv0900_write_reg(intp, R0900_P2_F22TX, m_div); - stv0900_write_reg(intp, R0900_P2_F22RX, m_div); - - if ((intp->errs)) - return STV0900_I2C_ERROR; - - return STV0900_NO_ERROR; -} - -static u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr, - enum fe_stv0900_demod_num demod) -{ - u32 lsb, msb, hsb, err_val; - - switch (cntr) { - case 0: - default: - hsb = stv0900_get_bits(intp, ERR_CNT12); - msb = stv0900_get_bits(intp, ERR_CNT11); - lsb = stv0900_get_bits(intp, ERR_CNT10); - break; - case 1: - hsb = stv0900_get_bits(intp, ERR_CNT22); - msb = stv0900_get_bits(intp, ERR_CNT21); - lsb = stv0900_get_bits(intp, ERR_CNT20); - break; - } - - err_val = (hsb << 16) + (msb << 8) + (lsb); - - return err_val; -} - -static int stv0900_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - - stv0900_write_bits(intp, I2CT_ON, enable); - - return 0; -} - -static void stv0900_set_ts_parallel_serial(struct stv0900_internal *intp, - enum fe_stv0900_clock_type path1_ts, - enum fe_stv0900_clock_type path2_ts) -{ - - dprintk("%s\n", __func__); - - if (intp->chip_id >= 0x20) { - switch (path1_ts) { - case STV0900_PARALLEL_PUNCT_CLOCK: - case STV0900_DVBCI_CLOCK: - switch (path2_ts) { - case STV0900_SERIAL_PUNCT_CLOCK: - case STV0900_SERIAL_CONT_CLOCK: - default: - stv0900_write_reg(intp, R0900_TSGENERAL, - 0x00); - break; - case STV0900_PARALLEL_PUNCT_CLOCK: - case STV0900_DVBCI_CLOCK: - stv0900_write_reg(intp, R0900_TSGENERAL, - 0x06); - stv0900_write_bits(intp, - F0900_P1_TSFIFO_MANSPEED, 3); - stv0900_write_bits(intp, - F0900_P2_TSFIFO_MANSPEED, 0); - stv0900_write_reg(intp, - R0900_P1_TSSPEED, 0x14); - stv0900_write_reg(intp, - R0900_P2_TSSPEED, 0x28); - break; - } - break; - case STV0900_SERIAL_PUNCT_CLOCK: - case STV0900_SERIAL_CONT_CLOCK: - default: - switch (path2_ts) { - case STV0900_SERIAL_PUNCT_CLOCK: - case STV0900_SERIAL_CONT_CLOCK: - default: - stv0900_write_reg(intp, - R0900_TSGENERAL, 0x0C); - break; - case STV0900_PARALLEL_PUNCT_CLOCK: - case STV0900_DVBCI_CLOCK: - stv0900_write_reg(intp, - R0900_TSGENERAL, 0x0A); - dprintk("%s: 0x0a\n", __func__); - break; - } - break; - } - } else { - switch (path1_ts) { - case STV0900_PARALLEL_PUNCT_CLOCK: - case STV0900_DVBCI_CLOCK: - switch (path2_ts) { - case STV0900_SERIAL_PUNCT_CLOCK: - case STV0900_SERIAL_CONT_CLOCK: - default: - stv0900_write_reg(intp, R0900_TSGENERAL1X, - 0x10); - break; - case STV0900_PARALLEL_PUNCT_CLOCK: - case STV0900_DVBCI_CLOCK: - stv0900_write_reg(intp, R0900_TSGENERAL1X, - 0x16); - stv0900_write_bits(intp, - F0900_P1_TSFIFO_MANSPEED, 3); - stv0900_write_bits(intp, - F0900_P2_TSFIFO_MANSPEED, 0); - stv0900_write_reg(intp, R0900_P1_TSSPEED, - 0x14); - stv0900_write_reg(intp, R0900_P2_TSSPEED, - 0x28); - break; - } - - break; - case STV0900_SERIAL_PUNCT_CLOCK: - case STV0900_SERIAL_CONT_CLOCK: - default: - switch (path2_ts) { - case STV0900_SERIAL_PUNCT_CLOCK: - case STV0900_SERIAL_CONT_CLOCK: - default: - stv0900_write_reg(intp, R0900_TSGENERAL1X, - 0x14); - break; - case STV0900_PARALLEL_PUNCT_CLOCK: - case STV0900_DVBCI_CLOCK: - stv0900_write_reg(intp, R0900_TSGENERAL1X, - 0x12); - dprintk("%s: 0x12\n", __func__); - break; - } - - break; - } - } - - switch (path1_ts) { - case STV0900_PARALLEL_PUNCT_CLOCK: - stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00); - stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x00); - break; - case STV0900_DVBCI_CLOCK: - stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00); - stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x01); - break; - case STV0900_SERIAL_PUNCT_CLOCK: - stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01); - stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x00); - break; - case STV0900_SERIAL_CONT_CLOCK: - stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01); - stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x01); - break; - default: - break; - } - - switch (path2_ts) { - case STV0900_PARALLEL_PUNCT_CLOCK: - stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00); - stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x00); - break; - case STV0900_DVBCI_CLOCK: - stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00); - stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x01); - break; - case STV0900_SERIAL_PUNCT_CLOCK: - stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01); - stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x00); - break; - case STV0900_SERIAL_CONT_CLOCK: - stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01); - stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x01); - break; - default: - break; - } - - stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1); - stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0); - stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1); - stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0); -} - -void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency, - u32 bandwidth) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - - if (&fe->ops) - frontend_ops = &fe->ops; - - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - - if (tuner_ops->set_frequency) { - if ((tuner_ops->set_frequency(fe, frequency)) < 0) - dprintk("%s: Invalid parameter\n", __func__); - else - dprintk("%s: Frequency=%d\n", __func__, frequency); - - } - - if (tuner_ops->set_bandwidth) { - if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0) - dprintk("%s: Invalid parameter\n", __func__); - else - dprintk("%s: Bandwidth=%d\n", __func__, bandwidth); - - } -} - -void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - - if (&fe->ops) - frontend_ops = &fe->ops; - - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - - if (tuner_ops->set_bandwidth) { - if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0) - dprintk("%s: Invalid parameter\n", __func__); - else - dprintk("%s: Bandwidth=%d\n", __func__, bandwidth); - - } -} - -u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod) -{ - u32 freq, round; - /* Formulat : - Tuner_Frequency(MHz) = Regs / 64 - Tuner_granularity(MHz) = Regs / 2048 - real_Tuner_Frequency = Tuner_Frequency(MHz) - Tuner_granularity(MHz) - */ - freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) + - (stv0900_get_bits(intp, TUN_RFFREQ1) << 2) + - stv0900_get_bits(intp, TUN_RFFREQ0); - - freq = (freq * 1000) / 64; - - round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) + - stv0900_get_bits(intp, TUN_RFRESTE0); - - round = (round * 1000) / 2048; - - return freq + round; -} - -void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency, - u32 Bandwidth, int demod) -{ - u32 tunerFrequency; - /* Formulat: - Tuner_frequency_reg= Frequency(MHz)*64 - */ - tunerFrequency = (Frequency * 64) / 1000; - - stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10)); - stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff); - stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03)); - /* Low Pass Filter = BW /2 (MHz)*/ - stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000); - /* Tuner Write trig */ - stv0900_write_reg(intp, TNRLD, 1); -} - -static s32 stv0900_get_rf_level(struct stv0900_internal *intp, - const struct stv0900_table *lookup, - enum fe_stv0900_demod_num demod) -{ - s32 agc_gain = 0, - imin, - imax, - i, - rf_lvl = 0; - - dprintk("%s\n", __func__); - - if ((lookup == NULL) || (lookup->size <= 0)) - return 0; - - agc_gain = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1), - stv0900_get_bits(intp, AGCIQ_VALUE0)); - - imin = 0; - imax = lookup->size - 1; - if (INRANGE(lookup->table[imin].regval, agc_gain, - lookup->table[imax].regval)) { - while ((imax - imin) > 1) { - i = (imax + imin) >> 1; - - if (INRANGE(lookup->table[imin].regval, - agc_gain, - lookup->table[i].regval)) - imax = i; - else - imin = i; - } - - rf_lvl = (s32)agc_gain - lookup->table[imin].regval; - rf_lvl *= (lookup->table[imax].realval - - lookup->table[imin].realval); - rf_lvl /= (lookup->table[imax].regval - - lookup->table[imin].regval); - rf_lvl += lookup->table[imin].realval; - } else if (agc_gain > lookup->table[0].regval) - rf_lvl = 5; - else if (agc_gain < lookup->table[lookup->size-1].regval) - rf_lvl = -100; - - dprintk("%s: RFLevel = %d\n", __func__, rf_lvl); - - return rf_lvl; -} - -static int stv0900_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *internal = state->internal; - s32 rflevel = stv0900_get_rf_level(internal, &stv0900_rf, - state->demod); - - rflevel = (rflevel + 100) * (65535 / 70); - if (rflevel < 0) - rflevel = 0; - - if (rflevel > 65535) - rflevel = 65535; - - *strength = rflevel; - - return 0; -} - -static s32 stv0900_carr_get_quality(struct dvb_frontend *fe, - const struct stv0900_table *lookup) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - - s32 c_n = -100, - regval, - imin, - imax, - i, - noise_field1, - noise_field0; - - dprintk("%s\n", __func__); - - if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) { - noise_field1 = NOSPLHT_NORMED1; - noise_field0 = NOSPLHT_NORMED0; - } else { - noise_field1 = NOSDATAT_NORMED1; - noise_field0 = NOSDATAT_NORMED0; - } - - if (stv0900_get_bits(intp, LOCK_DEFINITIF)) { - if ((lookup != NULL) && lookup->size) { - regval = 0; - msleep(5); - for (i = 0; i < 16; i++) { - regval += MAKEWORD(stv0900_get_bits(intp, - noise_field1), - stv0900_get_bits(intp, - noise_field0)); - msleep(1); - } - - regval /= 16; - imin = 0; - imax = lookup->size - 1; - if (INRANGE(lookup->table[imin].regval, - regval, - lookup->table[imax].regval)) { - while ((imax - imin) > 1) { - i = (imax + imin) >> 1; - if (INRANGE(lookup->table[imin].regval, - regval, - lookup->table[i].regval)) - imax = i; - else - imin = i; - } - - c_n = ((regval - lookup->table[imin].regval) - * (lookup->table[imax].realval - - lookup->table[imin].realval) - / (lookup->table[imax].regval - - lookup->table[imin].regval)) - + lookup->table[imin].realval; - } else if (regval < lookup->table[imin].regval) - c_n = 1000; - } - } - - return c_n; -} - -static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - u8 err_val1, err_val0; - u32 header_err_val = 0; - - *ucblocks = 0x0; - if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) { - /* DVB-S2 delineator errors count */ - - /* retreiving number for errnous headers */ - err_val1 = stv0900_read_reg(intp, BBFCRCKO1); - err_val0 = stv0900_read_reg(intp, BBFCRCKO0); - header_err_val = (err_val1 << 8) | err_val0; - - /* retreiving number for errnous packets */ - err_val1 = stv0900_read_reg(intp, UPCRCKO1); - err_val0 = stv0900_read_reg(intp, UPCRCKO0); - *ucblocks = (err_val1 << 8) | err_val0; - *ucblocks += header_err_val; - } - - return 0; -} - -static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - s32 snrlcl = stv0900_carr_get_quality(fe, - (const struct stv0900_table *)&stv0900_s2_cn); - snrlcl = (snrlcl + 30) * 384; - if (snrlcl < 0) - snrlcl = 0; - - if (snrlcl > 65535) - snrlcl = 65535; - - *snr = snrlcl; - - return 0; -} - -static u32 stv0900_get_ber(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - u32 ber = 10000000, i; - s32 demod_state; - - demod_state = stv0900_get_bits(intp, HEADER_MODE); - - switch (demod_state) { - case STV0900_SEARCH: - case STV0900_PLH_DETECTED: - default: - ber = 10000000; - break; - case STV0900_DVBS_FOUND: - ber = 0; - for (i = 0; i < 5; i++) { - msleep(5); - ber += stv0900_get_err_count(intp, 0, demod); - } - - ber /= 5; - if (stv0900_get_bits(intp, PRFVIT)) { - ber *= 9766; - ber = ber >> 13; - } - - break; - case STV0900_DVBS2_FOUND: - ber = 0; - for (i = 0; i < 5; i++) { - msleep(5); - ber += stv0900_get_err_count(intp, 0, demod); - } - - ber /= 5; - if (stv0900_get_bits(intp, PKTDELIN_LOCK)) { - ber *= 9766; - ber = ber >> 13; - } - - break; - } - - return ber; -} - -static int stv0900_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *internal = state->internal; - - *ber = stv0900_get_ber(internal, state->demod); - - return 0; -} - -int stv0900_get_demod_lock(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod, s32 time_out) -{ - s32 timer = 0, - lock = 0; - - enum fe_stv0900_search_state dmd_state; - - while ((timer < time_out) && (lock == 0)) { - dmd_state = stv0900_get_bits(intp, HEADER_MODE); - dprintk("Demod State = %d\n", dmd_state); - switch (dmd_state) { - case STV0900_SEARCH: - case STV0900_PLH_DETECTED: - default: - lock = 0; - break; - case STV0900_DVBS2_FOUND: - case STV0900_DVBS_FOUND: - lock = stv0900_get_bits(intp, LOCK_DEFINITIF); - break; - } - - if (lock == 0) - msleep(10); - - timer += 10; - } - - if (lock) - dprintk("DEMOD LOCK OK\n"); - else - dprintk("DEMOD LOCK FAIL\n"); - - return lock; -} - -void stv0900_stop_all_s2_modcod(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - s32 regflist, - i; - - dprintk("%s\n", __func__); - - regflist = MODCODLST0; - - for (i = 0; i < 16; i++) - stv0900_write_reg(intp, regflist + i, 0xff); -} - -void stv0900_activate_s2_modcod(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - u32 matype, - mod_code, - fmod, - reg_index, - field_index; - - dprintk("%s\n", __func__); - - if (intp->chip_id <= 0x11) { - msleep(5); - - mod_code = stv0900_read_reg(intp, PLHMODCOD); - matype = mod_code & 0x3; - mod_code = (mod_code & 0x7f) >> 2; - - reg_index = MODCODLSTF - mod_code / 2; - field_index = mod_code % 2; - - switch (matype) { - case 0: - default: - fmod = 14; - break; - case 1: - fmod = 13; - break; - case 2: - fmod = 11; - break; - case 3: - fmod = 7; - break; - } - - if ((INRANGE(STV0900_QPSK_12, mod_code, STV0900_8PSK_910)) - && (matype <= 1)) { - if (field_index == 0) - stv0900_write_reg(intp, reg_index, - 0xf0 | fmod); - else - stv0900_write_reg(intp, reg_index, - (fmod << 4) | 0xf); - } - - } else if (intp->chip_id >= 0x12) { - for (reg_index = 0; reg_index < 7; reg_index++) - stv0900_write_reg(intp, MODCODLST0 + reg_index, 0xff); - - stv0900_write_reg(intp, MODCODLSTE, 0xff); - stv0900_write_reg(intp, MODCODLSTF, 0xcf); - for (reg_index = 0; reg_index < 8; reg_index++) - stv0900_write_reg(intp, MODCODLST7 + reg_index, 0xcc); - - - } -} - -void stv0900_activate_s2_modcod_single(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - u32 reg_index; - - dprintk("%s\n", __func__); - - stv0900_write_reg(intp, MODCODLST0, 0xff); - stv0900_write_reg(intp, MODCODLST1, 0xf0); - stv0900_write_reg(intp, MODCODLSTF, 0x0f); - for (reg_index = 0; reg_index < 13; reg_index++) - stv0900_write_reg(intp, MODCODLST2 + reg_index, 0); - -} - -static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe) -{ - return DVBFE_ALGO_CUSTOM; -} - -static int stb0900_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - - return 0; -} - -static int stb0900_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - - return 0; -} - -void stv0900_start_search(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - u32 freq; - s16 freq_s16 ; - - stv0900_write_bits(intp, DEMOD_MODE, 0x1f); - if (intp->chip_id == 0x10) - stv0900_write_reg(intp, CORRELEXP, 0xaa); - - if (intp->chip_id < 0x20) - stv0900_write_reg(intp, CARHDR, 0x55); - - if (intp->chip_id <= 0x20) { - if (intp->symbol_rate[0] <= 5000000) { - stv0900_write_reg(intp, CARCFG, 0x44); - stv0900_write_reg(intp, CFRUP1, 0x0f); - stv0900_write_reg(intp, CFRUP0, 0xff); - stv0900_write_reg(intp, CFRLOW1, 0xf0); - stv0900_write_reg(intp, CFRLOW0, 0x00); - stv0900_write_reg(intp, RTCS2, 0x68); - } else { - stv0900_write_reg(intp, CARCFG, 0xc4); - stv0900_write_reg(intp, RTCS2, 0x44); - } - - } else { /*cut 3.0 above*/ - if (intp->symbol_rate[demod] <= 5000000) - stv0900_write_reg(intp, RTCS2, 0x68); - else - stv0900_write_reg(intp, RTCS2, 0x44); - - stv0900_write_reg(intp, CARCFG, 0x46); - if (intp->srch_algo[demod] == STV0900_WARM_START) { - freq = 1000 << 16; - freq /= (intp->mclk / 1000); - freq_s16 = (s16)freq; - } else { - freq = (intp->srch_range[demod] / 2000); - if (intp->symbol_rate[demod] <= 5000000) - freq += 80; - else - freq += 600; - - freq = freq << 16; - freq /= (intp->mclk / 1000); - freq_s16 = (s16)freq; - } - - stv0900_write_bits(intp, CFR_UP1, MSB(freq_s16)); - stv0900_write_bits(intp, CFR_UP0, LSB(freq_s16)); - freq_s16 *= (-1); - stv0900_write_bits(intp, CFR_LOW1, MSB(freq_s16)); - stv0900_write_bits(intp, CFR_LOW0, LSB(freq_s16)); - } - - stv0900_write_reg(intp, CFRINIT1, 0); - stv0900_write_reg(intp, CFRINIT0, 0); - - if (intp->chip_id >= 0x20) { - stv0900_write_reg(intp, EQUALCFG, 0x41); - stv0900_write_reg(intp, FFECFG, 0x41); - - if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) || - (intp->srch_standard[demod] == STV0900_SEARCH_DSS) || - (intp->srch_standard[demod] == STV0900_AUTO_SEARCH)) { - stv0900_write_reg(intp, VITSCALE, - 0x82); - stv0900_write_reg(intp, VAVSRVIT, 0x0); - } - } - - stv0900_write_reg(intp, SFRSTEP, 0x00); - stv0900_write_reg(intp, TMGTHRISE, 0xe0); - stv0900_write_reg(intp, TMGTHFALL, 0xc0); - stv0900_write_bits(intp, SCAN_ENABLE, 0); - stv0900_write_bits(intp, CFR_AUTOSCAN, 0); - stv0900_write_bits(intp, S1S2_SEQUENTIAL, 0); - stv0900_write_reg(intp, RTC, 0x88); - if (intp->chip_id >= 0x20) { - if (intp->symbol_rate[demod] < 2000000) { - if (intp->chip_id <= 0x20) - stv0900_write_reg(intp, CARFREQ, 0x39); - else /*cut 3.0*/ - stv0900_write_reg(intp, CARFREQ, 0x89); - - stv0900_write_reg(intp, CARHDR, 0x40); - } else if (intp->symbol_rate[demod] < 10000000) { - stv0900_write_reg(intp, CARFREQ, 0x4c); - stv0900_write_reg(intp, CARHDR, 0x20); - } else { - stv0900_write_reg(intp, CARFREQ, 0x4b); - stv0900_write_reg(intp, CARHDR, 0x20); - } - - } else { - if (intp->symbol_rate[demod] < 10000000) - stv0900_write_reg(intp, CARFREQ, 0xef); - else - stv0900_write_reg(intp, CARFREQ, 0xed); - } - - switch (intp->srch_algo[demod]) { - case STV0900_WARM_START: - stv0900_write_reg(intp, DMDISTATE, 0x1f); - stv0900_write_reg(intp, DMDISTATE, 0x18); - break; - case STV0900_COLD_START: - stv0900_write_reg(intp, DMDISTATE, 0x1f); - stv0900_write_reg(intp, DMDISTATE, 0x15); - break; - default: - break; - } -} - -u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode, - s32 pilot, u8 chip_id) -{ - u8 aclc_value = 0x29; - s32 i; - const struct stv0900_car_loop_optim *cls2, *cllqs2, *cllas2; - - dprintk("%s\n", __func__); - - if (chip_id <= 0x12) { - cls2 = FE_STV0900_S2CarLoop; - cllqs2 = FE_STV0900_S2LowQPCarLoopCut30; - cllas2 = FE_STV0900_S2APSKCarLoopCut30; - } else if (chip_id == 0x20) { - cls2 = FE_STV0900_S2CarLoopCut20; - cllqs2 = FE_STV0900_S2LowQPCarLoopCut20; - cllas2 = FE_STV0900_S2APSKCarLoopCut20; - } else { - cls2 = FE_STV0900_S2CarLoopCut30; - cllqs2 = FE_STV0900_S2LowQPCarLoopCut30; - cllas2 = FE_STV0900_S2APSKCarLoopCut30; - } - - if (modcode < STV0900_QPSK_12) { - i = 0; - while ((i < 3) && (modcode != cllqs2[i].modcode)) - i++; - - if (i >= 3) - i = 2; - } else { - i = 0; - while ((i < 14) && (modcode != cls2[i].modcode)) - i++; - - if (i >= 14) { - i = 0; - while ((i < 11) && (modcode != cllas2[i].modcode)) - i++; - - if (i >= 11) - i = 10; - } - } - - if (modcode <= STV0900_QPSK_25) { - if (pilot) { - if (srate <= 3000000) - aclc_value = cllqs2[i].car_loop_pilots_on_2; - else if (srate <= 7000000) - aclc_value = cllqs2[i].car_loop_pilots_on_5; - else if (srate <= 15000000) - aclc_value = cllqs2[i].car_loop_pilots_on_10; - else if (srate <= 25000000) - aclc_value = cllqs2[i].car_loop_pilots_on_20; - else - aclc_value = cllqs2[i].car_loop_pilots_on_30; - } else { - if (srate <= 3000000) - aclc_value = cllqs2[i].car_loop_pilots_off_2; - else if (srate <= 7000000) - aclc_value = cllqs2[i].car_loop_pilots_off_5; - else if (srate <= 15000000) - aclc_value = cllqs2[i].car_loop_pilots_off_10; - else if (srate <= 25000000) - aclc_value = cllqs2[i].car_loop_pilots_off_20; - else - aclc_value = cllqs2[i].car_loop_pilots_off_30; - } - - } else if (modcode <= STV0900_8PSK_910) { - if (pilot) { - if (srate <= 3000000) - aclc_value = cls2[i].car_loop_pilots_on_2; - else if (srate <= 7000000) - aclc_value = cls2[i].car_loop_pilots_on_5; - else if (srate <= 15000000) - aclc_value = cls2[i].car_loop_pilots_on_10; - else if (srate <= 25000000) - aclc_value = cls2[i].car_loop_pilots_on_20; - else - aclc_value = cls2[i].car_loop_pilots_on_30; - } else { - if (srate <= 3000000) - aclc_value = cls2[i].car_loop_pilots_off_2; - else if (srate <= 7000000) - aclc_value = cls2[i].car_loop_pilots_off_5; - else if (srate <= 15000000) - aclc_value = cls2[i].car_loop_pilots_off_10; - else if (srate <= 25000000) - aclc_value = cls2[i].car_loop_pilots_off_20; - else - aclc_value = cls2[i].car_loop_pilots_off_30; - } - - } else { - if (srate <= 3000000) - aclc_value = cllas2[i].car_loop_pilots_on_2; - else if (srate <= 7000000) - aclc_value = cllas2[i].car_loop_pilots_on_5; - else if (srate <= 15000000) - aclc_value = cllas2[i].car_loop_pilots_on_10; - else if (srate <= 25000000) - aclc_value = cllas2[i].car_loop_pilots_on_20; - else - aclc_value = cllas2[i].car_loop_pilots_on_30; - } - - return aclc_value; -} - -u8 stv0900_get_optim_short_carr_loop(s32 srate, - enum fe_stv0900_modulation modulation, - u8 chip_id) -{ - const struct stv0900_short_frames_car_loop_optim *s2scl; - const struct stv0900_short_frames_car_loop_optim_vs_mod *s2sclc30; - s32 mod_index = 0; - u8 aclc_value = 0x0b; - - dprintk("%s\n", __func__); - - s2scl = FE_STV0900_S2ShortCarLoop; - s2sclc30 = FE_STV0900_S2ShortCarLoopCut30; - - switch (modulation) { - case STV0900_QPSK: - default: - mod_index = 0; - break; - case STV0900_8PSK: - mod_index = 1; - break; - case STV0900_16APSK: - mod_index = 2; - break; - case STV0900_32APSK: - mod_index = 3; - break; - } - - if (chip_id >= 0x30) { - if (srate <= 3000000) - aclc_value = s2sclc30[mod_index].car_loop_2; - else if (srate <= 7000000) - aclc_value = s2sclc30[mod_index].car_loop_5; - else if (srate <= 15000000) - aclc_value = s2sclc30[mod_index].car_loop_10; - else if (srate <= 25000000) - aclc_value = s2sclc30[mod_index].car_loop_20; - else - aclc_value = s2sclc30[mod_index].car_loop_30; - - } else if (chip_id >= 0x20) { - if (srate <= 3000000) - aclc_value = s2scl[mod_index].car_loop_cut20_2; - else if (srate <= 7000000) - aclc_value = s2scl[mod_index].car_loop_cut20_5; - else if (srate <= 15000000) - aclc_value = s2scl[mod_index].car_loop_cut20_10; - else if (srate <= 25000000) - aclc_value = s2scl[mod_index].car_loop_cut20_20; - else - aclc_value = s2scl[mod_index].car_loop_cut20_30; - - } else { - if (srate <= 3000000) - aclc_value = s2scl[mod_index].car_loop_cut12_2; - else if (srate <= 7000000) - aclc_value = s2scl[mod_index].car_loop_cut12_5; - else if (srate <= 15000000) - aclc_value = s2scl[mod_index].car_loop_cut12_10; - else if (srate <= 25000000) - aclc_value = s2scl[mod_index].car_loop_cut12_20; - else - aclc_value = s2scl[mod_index].car_loop_cut12_30; - - } - - return aclc_value; -} - -static -enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp, - enum fe_stv0900_demod_mode LDPC_Mode, - enum fe_stv0900_demod_num demod) -{ - enum fe_stv0900_error error = STV0900_NO_ERROR; - s32 reg_ind; - - dprintk("%s\n", __func__); - - switch (LDPC_Mode) { - case STV0900_DUAL: - default: - if ((intp->demod_mode != STV0900_DUAL) - || (stv0900_get_bits(intp, F0900_DDEMOD) != 1)) { - stv0900_write_reg(intp, R0900_GENCFG, 0x1d); - - intp->demod_mode = STV0900_DUAL; - - stv0900_write_bits(intp, F0900_FRESFEC, 1); - stv0900_write_bits(intp, F0900_FRESFEC, 0); - - for (reg_ind = 0; reg_ind < 7; reg_ind++) - stv0900_write_reg(intp, - R0900_P1_MODCODLST0 + reg_ind, - 0xff); - for (reg_ind = 0; reg_ind < 8; reg_ind++) - stv0900_write_reg(intp, - R0900_P1_MODCODLST7 + reg_ind, - 0xcc); - - stv0900_write_reg(intp, R0900_P1_MODCODLSTE, 0xff); - stv0900_write_reg(intp, R0900_P1_MODCODLSTF, 0xcf); - - for (reg_ind = 0; reg_ind < 7; reg_ind++) - stv0900_write_reg(intp, - R0900_P2_MODCODLST0 + reg_ind, - 0xff); - for (reg_ind = 0; reg_ind < 8; reg_ind++) - stv0900_write_reg(intp, - R0900_P2_MODCODLST7 + reg_ind, - 0xcc); - - stv0900_write_reg(intp, R0900_P2_MODCODLSTE, 0xff); - stv0900_write_reg(intp, R0900_P2_MODCODLSTF, 0xcf); - } - - break; - case STV0900_SINGLE: - if (demod == STV0900_DEMOD_2) { - stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_1); - stv0900_activate_s2_modcod_single(intp, - STV0900_DEMOD_2); - stv0900_write_reg(intp, R0900_GENCFG, 0x06); - } else { - stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_2); - stv0900_activate_s2_modcod_single(intp, - STV0900_DEMOD_1); - stv0900_write_reg(intp, R0900_GENCFG, 0x04); - } - - intp->demod_mode = STV0900_SINGLE; - - stv0900_write_bits(intp, F0900_FRESFEC, 1); - stv0900_write_bits(intp, F0900_FRESFEC, 0); - stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 1); - stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 0); - stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 1); - stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 0); - break; - } - - return error; -} - -static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, - struct stv0900_init_params *p_init) -{ - struct stv0900_state *state = fe->demodulator_priv; - enum fe_stv0900_error error = STV0900_NO_ERROR; - enum fe_stv0900_error demodError = STV0900_NO_ERROR; - struct stv0900_internal *intp = NULL; - int selosci, i; - - struct stv0900_inode *temp_int = find_inode(state->i2c_adap, - state->config->demod_address); - - dprintk("%s\n", __func__); - - if ((temp_int != NULL) && (p_init->demod_mode == STV0900_DUAL)) { - state->internal = temp_int->internal; - (state->internal->dmds_used)++; - dprintk("%s: Find Internal Structure!\n", __func__); - return STV0900_NO_ERROR; - } else { - state->internal = kmalloc(sizeof(struct stv0900_internal), - GFP_KERNEL); - if (state->internal == NULL) - return STV0900_INVALID_HANDLE; - temp_int = append_internal(state->internal); - if (temp_int == NULL) { - kfree(state->internal); - state->internal = NULL; - return STV0900_INVALID_HANDLE; - } - state->internal->dmds_used = 1; - state->internal->i2c_adap = state->i2c_adap; - state->internal->i2c_addr = state->config->demod_address; - state->internal->clkmode = state->config->clkmode; - state->internal->errs = STV0900_NO_ERROR; - dprintk("%s: Create New Internal Structure!\n", __func__); - } - - if (state->internal == NULL) { - error = STV0900_INVALID_HANDLE; - return error; - } - - demodError = stv0900_initialize(state->internal); - if (demodError == STV0900_NO_ERROR) { - error = STV0900_NO_ERROR; - } else { - if (demodError == STV0900_INVALID_HANDLE) - error = STV0900_INVALID_HANDLE; - else - error = STV0900_I2C_ERROR; - - return error; - } - - intp = state->internal; - - intp->demod_mode = p_init->demod_mode; - stv0900_st_dvbs2_single(intp, intp->demod_mode, STV0900_DEMOD_1); - intp->chip_id = stv0900_read_reg(intp, R0900_MID); - intp->rolloff = p_init->rolloff; - intp->quartz = p_init->dmd_ref_clk; - - stv0900_write_bits(intp, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff); - stv0900_write_bits(intp, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff); - - intp->ts_config = p_init->ts_config; - if (intp->ts_config == NULL) - stv0900_set_ts_parallel_serial(intp, - p_init->path1_ts_clock, - p_init->path2_ts_clock); - else { - for (i = 0; intp->ts_config[i].addr != 0xffff; i++) - stv0900_write_reg(intp, - intp->ts_config[i].addr, - intp->ts_config[i].val); - - stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1); - stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0); - stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1); - stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0); - } - - intp->tuner_type[0] = p_init->tuner1_type; - intp->tuner_type[1] = p_init->tuner2_type; - /* tuner init */ - switch (p_init->tuner1_type) { - case 3: /*FE_AUTO_STB6100:*/ - stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c); - stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86); - stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18); - stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */ - stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05); - stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17); - stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f); - stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0); - stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3); - break; - /* case FE_SW_TUNER: */ - default: - stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6); - break; - } - - stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress); - switch (p_init->tuner1_adc) { - case 1: - stv0900_write_reg(intp, R0900_TSTTNR1, 0x26); - break; - default: - break; - } - - stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */ - - /* tuner init */ - switch (p_init->tuner2_type) { - case 3: /*FE_AUTO_STB6100:*/ - stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c); - stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86); - stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18); - stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */ - stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05); - stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17); - stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f); - stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0); - stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3); - break; - /* case FE_SW_TUNER: */ - default: - stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6); - break; - } - - stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress); - switch (p_init->tuner2_adc) { - case 1: - stv0900_write_reg(intp, R0900_TSTTNR3, 0x26); - break; - default: - break; - } - - stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */ - - stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv); - stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv); - stv0900_set_mclk(intp, 135000000); - msleep(3); - - switch (intp->clkmode) { - case 0: - case 2: - stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | intp->clkmode); - break; - default: - selosci = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL); - stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | selosci); - break; - } - msleep(3); - - intp->mclk = stv0900_get_mclk_freq(intp, intp->quartz); - if (intp->errs) - error = STV0900_I2C_ERROR; - - return error; -} - -static int stv0900_status(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - enum fe_stv0900_search_state demod_state; - int locked = FALSE; - u8 tsbitrate0_val, tsbitrate1_val; - s32 bitrate; - - demod_state = stv0900_get_bits(intp, HEADER_MODE); - switch (demod_state) { - case STV0900_SEARCH: - case STV0900_PLH_DETECTED: - default: - locked = FALSE; - break; - case STV0900_DVBS2_FOUND: - locked = stv0900_get_bits(intp, LOCK_DEFINITIF) && - stv0900_get_bits(intp, PKTDELIN_LOCK) && - stv0900_get_bits(intp, TSFIFO_LINEOK); - break; - case STV0900_DVBS_FOUND: - locked = stv0900_get_bits(intp, LOCK_DEFINITIF) && - stv0900_get_bits(intp, LOCKEDVIT) && - stv0900_get_bits(intp, TSFIFO_LINEOK); - break; - } - - dprintk("%s: locked = %d\n", __func__, locked); - - if (stvdebug) { - /* Print TS bitrate */ - tsbitrate0_val = stv0900_read_reg(intp, TSBITRATE0); - tsbitrate1_val = stv0900_read_reg(intp, TSBITRATE1); - /* Formula Bit rate = Mclk * px_tsfifo_bitrate / 16384 */ - bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000) - * (tsbitrate1_val << 8 | tsbitrate0_val); - bitrate /= 16384; - dprintk("TS bitrate = %d Mbit/sec \n", bitrate); - }; - - return locked; -} - -static enum dvbfe_search stv0900_search(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - struct stv0900_search_params p_search; - struct stv0900_signal_info p_result = intp->result[demod]; - - enum fe_stv0900_error error = STV0900_NO_ERROR; - - dprintk("%s: ", __func__); - - if (!(INRANGE(100000, c->symbol_rate, 70000000))) - return DVBFE_ALGO_SEARCH_FAILED; - - if (state->config->set_ts_params) - state->config->set_ts_params(fe, 0); - - p_result.locked = FALSE; - p_search.path = demod; - p_search.frequency = c->frequency; - p_search.symbol_rate = c->symbol_rate; - p_search.search_range = 10000000; - p_search.fec = STV0900_FEC_UNKNOWN; - p_search.standard = STV0900_AUTO_SEARCH; - p_search.iq_inversion = STV0900_IQ_AUTO; - p_search.search_algo = STV0900_BLIND_SEARCH; - /* Speeds up DVB-S searching */ - if (c->delivery_system == SYS_DVBS) - p_search.standard = STV0900_SEARCH_DVBS1; - - intp->srch_standard[demod] = p_search.standard; - intp->symbol_rate[demod] = p_search.symbol_rate; - intp->srch_range[demod] = p_search.search_range; - intp->freq[demod] = p_search.frequency; - intp->srch_algo[demod] = p_search.search_algo; - intp->srch_iq_inv[demod] = p_search.iq_inversion; - intp->fec[demod] = p_search.fec; - if ((stv0900_algo(fe) == STV0900_RANGEOK) && - (intp->errs == STV0900_NO_ERROR)) { - p_result.locked = intp->result[demod].locked; - p_result.standard = intp->result[demod].standard; - p_result.frequency = intp->result[demod].frequency; - p_result.symbol_rate = intp->result[demod].symbol_rate; - p_result.fec = intp->result[demod].fec; - p_result.modcode = intp->result[demod].modcode; - p_result.pilot = intp->result[demod].pilot; - p_result.frame_len = intp->result[demod].frame_len; - p_result.spectrum = intp->result[demod].spectrum; - p_result.rolloff = intp->result[demod].rolloff; - p_result.modulation = intp->result[demod].modulation; - } else { - p_result.locked = FALSE; - switch (intp->err[demod]) { - case STV0900_I2C_ERROR: - error = STV0900_I2C_ERROR; - break; - case STV0900_NO_ERROR: - default: - error = STV0900_SEARCH_FAILED; - break; - } - } - - if ((p_result.locked == TRUE) && (error == STV0900_NO_ERROR)) { - dprintk("Search Success\n"); - return DVBFE_ALGO_SEARCH_SUCCESS; - } else { - dprintk("Search Fail\n"); - return DVBFE_ALGO_SEARCH_FAILED; - } - -} - -static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status) -{ - struct stv0900_state *state = fe->demodulator_priv; - - dprintk("%s: ", __func__); - - if ((stv0900_status(state->internal, state->demod)) == TRUE) { - dprintk("DEMOD LOCK OK\n"); - *status = FE_HAS_CARRIER - | FE_HAS_VITERBI - | FE_HAS_SYNC - | FE_HAS_LOCK; - if (state->config->set_lock_led) - state->config->set_lock_led(fe, 1); - } else { - *status = 0; - if (state->config->set_lock_led) - state->config->set_lock_led(fe, 0); - dprintk("DEMOD LOCK FAIL\n"); - } - - return 0; -} - -static int stv0900_track(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - return 0; -} - -static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts) -{ - - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - - if (stop_ts == TRUE) - stv0900_write_bits(intp, RST_HWARE, 1); - else - stv0900_write_bits(intp, RST_HWARE, 0); - - return 0; -} - -static int stv0900_diseqc_init(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - - stv0900_write_bits(intp, DISTX_MODE, state->config->diseqc_mode); - stv0900_write_bits(intp, DISEQC_RESET, 1); - stv0900_write_bits(intp, DISEQC_RESET, 0); - - return 0; -} - -static int stv0900_init(struct dvb_frontend *fe) -{ - dprintk("%s\n", __func__); - - stv0900_stop_ts(fe, 1); - stv0900_diseqc_init(fe); - - return 0; -} - -static int stv0900_diseqc_send(struct stv0900_internal *intp , u8 *data, - u32 NbData, enum fe_stv0900_demod_num demod) -{ - s32 i = 0; - - stv0900_write_bits(intp, DIS_PRECHARGE, 1); - while (i < NbData) { - while (stv0900_get_bits(intp, FIFO_FULL)) - ;/* checkpatch complains */ - stv0900_write_reg(intp, DISTXDATA, data[i]); - i++; - } - - stv0900_write_bits(intp, DIS_PRECHARGE, 0); - i = 0; - while ((stv0900_get_bits(intp, TX_IDLE) != 1) && (i < 10)) { - msleep(10); - i++; - } - - return 0; -} - -static int stv0900_send_master_cmd(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *cmd) -{ - struct stv0900_state *state = fe->demodulator_priv; - - return stv0900_diseqc_send(state->internal, - cmd->msg, - cmd->msg_len, - state->demod); -} - -static int stv0900_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - u8 data; - - - switch (burst) { - case SEC_MINI_A: - stv0900_write_bits(intp, DISTX_MODE, 3);/* Unmodulated */ - data = 0x00; - stv0900_diseqc_send(intp, &data, 1, state->demod); - break; - case SEC_MINI_B: - stv0900_write_bits(intp, DISTX_MODE, 2);/* Modulated */ - data = 0xff; - stv0900_diseqc_send(intp, &data, 1, state->demod); - break; - } - - return 0; -} - -static int stv0900_recv_slave_reply(struct dvb_frontend *fe, - struct dvb_diseqc_slave_reply *reply) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - s32 i = 0; - - reply->msg_len = 0; - - while ((stv0900_get_bits(intp, RX_END) != 1) && (i < 10)) { - msleep(10); - i++; - } - - if (stv0900_get_bits(intp, RX_END)) { - reply->msg_len = stv0900_get_bits(intp, FIFO_BYTENBR); - - for (i = 0; i < reply->msg_len; i++) - reply->msg[i] = stv0900_read_reg(intp, DISRXDATA); - } - - return 0; -} - -static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t toneoff) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - - dprintk("%s: %s\n", __func__, ((toneoff == 0) ? "On" : "Off")); - - switch (toneoff) { - case SEC_TONE_ON: - /*Set the DiseqC mode to 22Khz _continues_ tone*/ - stv0900_write_bits(intp, DISTX_MODE, 0); - stv0900_write_bits(intp, DISEQC_RESET, 1); - /*release DiseqC reset to enable the 22KHz tone*/ - stv0900_write_bits(intp, DISEQC_RESET, 0); - break; - case SEC_TONE_OFF: - /*return diseqc mode to config->diseqc_mode. - Usually it's without _continues_ tone */ - stv0900_write_bits(intp, DISTX_MODE, - state->config->diseqc_mode); - /*maintain the DiseqC reset to disable the 22KHz tone*/ - stv0900_write_bits(intp, DISEQC_RESET, 1); - stv0900_write_bits(intp, DISEQC_RESET, 0); - break; - default: - return -EINVAL; - } - - return 0; -} - -static void stv0900_release(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - if (state->config->set_lock_led) - state->config->set_lock_led(fe, 0); - - if ((--(state->internal->dmds_used)) <= 0) { - - dprintk("%s: Actually removing\n", __func__); - - remove_inode(state->internal); - kfree(state->internal); - } - - kfree(state); -} - -static int stv0900_sleep(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - if (state->config->set_lock_led) - state->config->set_lock_led(fe, 0); - - return 0; -} - -static int stv0900_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - struct stv0900_signal_info p_result = intp->result[demod]; - - p->frequency = p_result.locked ? p_result.frequency : 0; - p->u.qpsk.symbol_rate = p_result.locked ? p_result.symbol_rate : 0; - return 0; -} - -static struct dvb_frontend_ops stv0900_ops = { - - .info = { - .name = "STV0900 frontend", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, - .frequency_tolerance = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | FE_CAN_QPSK | - FE_CAN_2G_MODULATION | - FE_CAN_FEC_AUTO - }, - .release = stv0900_release, - .init = stv0900_init, - .get_frontend = stv0900_get_frontend, - .sleep = stv0900_sleep, - .get_frontend_algo = stv0900_frontend_algo, - .i2c_gate_ctrl = stv0900_i2c_gate_ctrl, - .diseqc_send_master_cmd = stv0900_send_master_cmd, - .diseqc_send_burst = stv0900_send_burst, - .diseqc_recv_slave_reply = stv0900_recv_slave_reply, - .set_tone = stv0900_set_tone, - .set_property = stb0900_set_property, - .get_property = stb0900_get_property, - .search = stv0900_search, - .track = stv0900_track, - .read_status = stv0900_read_status, - .read_ber = stv0900_read_ber, - .read_signal_strength = stv0900_read_signal_strength, - .read_snr = stv0900_read_snr, - .read_ucblocks = stv0900_read_ucblocks, -}; - -struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, - struct i2c_adapter *i2c, - int demod) -{ - struct stv0900_state *state = NULL; - struct stv0900_init_params init_params; - enum fe_stv0900_error err_stv0900; - - state = kzalloc(sizeof(struct stv0900_state), GFP_KERNEL); - if (state == NULL) - goto error; - - state->demod = demod; - state->config = config; - state->i2c_adap = i2c; - - memcpy(&state->frontend.ops, &stv0900_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - switch (demod) { - case 0: - case 1: - init_params.dmd_ref_clk = config->xtal; - init_params.demod_mode = config->demod_mode; - init_params.rolloff = STV0900_35; - init_params.path1_ts_clock = config->path1_mode; - init_params.tun1_maddress = config->tun1_maddress; - init_params.tun1_iq_inv = STV0900_IQ_NORMAL; - init_params.tuner1_adc = config->tun1_adc; - init_params.tuner1_type = config->tun1_type; - init_params.path2_ts_clock = config->path2_mode; - init_params.ts_config = config->ts_config_regs; - init_params.tun2_maddress = config->tun2_maddress; - init_params.tuner2_adc = config->tun2_adc; - init_params.tuner2_type = config->tun2_type; - init_params.tun2_iq_inv = STV0900_IQ_SWAPPED; - - err_stv0900 = stv0900_init_internal(&state->frontend, - &init_params); - - if (err_stv0900) - goto error; - - break; - default: - goto error; - break; - } - - dprintk("%s: Attaching STV0900 demodulator(%d) \n", __func__, demod); - return &state->frontend; - -error: - dprintk("%s: Failed to attach STV0900 demodulator(%d) \n", - __func__, demod); - kfree(state); - return NULL; -} -EXPORT_SYMBOL(stv0900_attach); - -MODULE_PARM_DESC(debug, "Set debug"); - -MODULE_AUTHOR("Igor M. Liplianin"); -MODULE_DESCRIPTION("ST STV0900 frontend"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -/* - * stv0900.h - * - * Driver for ST STV0900 satellite demodulator IC. - * - * Copyright (C) ST Microelectronics. - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef STV0900_H -#define STV0900_H - -#include -#include "dvb_frontend.h" - -struct stv0900_reg { - u16 addr; - u8 val; -}; - -struct stv0900_config { - u8 demod_address; - u8 demod_mode; - u32 xtal; - u8 clkmode;/* 0 for CLKI, 2 for XTALI */ - - u8 diseqc_mode; - - u8 path1_mode; - u8 path2_mode; - struct stv0900_reg *ts_config_regs; - u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */ - u8 tun2_maddress; - u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */ - u8 tun2_adc; - u8 tun1_type;/* for now 3 for stb6100 auto, else - software */ - u8 tun2_type; - /* Set device param to start dma */ - int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); - /* Hook for Lock LED */ - void (*set_lock_led)(struct dvb_frontend *fe, int offon); -}; - -#if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \ - && defined(MODULE)) -extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, - struct i2c_adapter *i2c, int demod); -#else -static inline struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, - struct i2c_adapter *i2c, int demod) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_init.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_init.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_init.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_init.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,584 +0,0 @@ -/* - * stv0900_init.h - * - * Driver for ST STV0900 satellite demodulator IC. - * - * Copyright (C) ST Microelectronics. - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef STV0900_INIT_H -#define STV0900_INIT_H - -#include "stv0900_priv.h" - -/* DVBS2 C/N Look-Up table */ -static const struct stv0900_table stv0900_s2_cn = { - 55, - { - { -30, 13348 }, /*C/N=-3dB*/ - { -20, 12640 }, /*C/N=-2dB*/ - { -10, 11883 }, /*C/N=-1dB*/ - { 0, 11101 }, /*C/N=-0dB*/ - { 5, 10718 }, /*C/N=0.5dB*/ - { 10, 10339 }, /*C/N=1.0dB*/ - { 15, 9947 }, /*C/N=1.5dB*/ - { 20, 9552 }, /*C/N=2.0dB*/ - { 25, 9183 }, /*C/N=2.5dB*/ - { 30, 8799 }, /*C/N=3.0dB*/ - { 35, 8422 }, /*C/N=3.5dB*/ - { 40, 8062 }, /*C/N=4.0dB*/ - { 45, 7707 }, /*C/N=4.5dB*/ - { 50, 7353 }, /*C/N=5.0dB*/ - { 55, 7025 }, /*C/N=5.5dB*/ - { 60, 6684 }, /*C/N=6.0dB*/ - { 65, 6331 }, /*C/N=6.5dB*/ - { 70, 6036 }, /*C/N=7.0dB*/ - { 75, 5727 }, /*C/N=7.5dB*/ - { 80, 5437 }, /*C/N=8.0dB*/ - { 85, 5164 }, /*C/N=8.5dB*/ - { 90, 4902 }, /*C/N=9.0dB*/ - { 95, 4653 }, /*C/N=9.5dB*/ - { 100, 4408 }, /*C/N=10.0dB*/ - { 105, 4187 }, /*C/N=10.5dB*/ - { 110, 3961 }, /*C/N=11.0dB*/ - { 115, 3751 }, /*C/N=11.5dB*/ - { 120, 3558 }, /*C/N=12.0dB*/ - { 125, 3368 }, /*C/N=12.5dB*/ - { 130, 3191 }, /*C/N=13.0dB*/ - { 135, 3017 }, /*C/N=13.5dB*/ - { 140, 2862 }, /*C/N=14.0dB*/ - { 145, 2710 }, /*C/N=14.5dB*/ - { 150, 2565 }, /*C/N=15.0dB*/ - { 160, 2300 }, /*C/N=16.0dB*/ - { 170, 2058 }, /*C/N=17.0dB*/ - { 180, 1849 }, /*C/N=18.0dB*/ - { 190, 1663 }, /*C/N=19.0dB*/ - { 200, 1495 }, /*C/N=20.0dB*/ - { 210, 1349 }, /*C/N=21.0dB*/ - { 220, 1222 }, /*C/N=22.0dB*/ - { 230, 1110 }, /*C/N=23.0dB*/ - { 240, 1011 }, /*C/N=24.0dB*/ - { 250, 925 }, /*C/N=25.0dB*/ - { 260, 853 }, /*C/N=26.0dB*/ - { 270, 789 }, /*C/N=27.0dB*/ - { 280, 734 }, /*C/N=28.0dB*/ - { 290, 690 }, /*C/N=29.0dB*/ - { 300, 650 }, /*C/N=30.0dB*/ - { 310, 619 }, /*C/N=31.0dB*/ - { 320, 593 }, /*C/N=32.0dB*/ - { 330, 571 }, /*C/N=33.0dB*/ - { 400, 498 }, /*C/N=40.0dB*/ - { 450, 484 }, /*C/N=45.0dB*/ - { 500, 481 } /*C/N=50.0dB*/ - } -}; - -/* RF level C/N Look-Up table */ -static const struct stv0900_table stv0900_rf = { - 14, - { - { -5, 0xCAA1 }, /*-5dBm*/ - { -10, 0xC229 }, /*-10dBm*/ - { -15, 0xBB08 }, /*-15dBm*/ - { -20, 0xB4BC }, /*-20dBm*/ - { -25, 0xAD5A }, /*-25dBm*/ - { -30, 0xA298 }, /*-30dBm*/ - { -35, 0x98A8 }, /*-35dBm*/ - { -40, 0x8389 }, /*-40dBm*/ - { -45, 0x59BE }, /*-45dBm*/ - { -50, 0x3A14 }, /*-50dBm*/ - { -55, 0x2D11 }, /*-55dBm*/ - { -60, 0x210D }, /*-60dBm*/ - { -65, 0xA14F }, /*-65dBm*/ - { -70, 0x7AA } /*-70dBm*/ - } -}; - -struct stv0900_car_loop_optim { - enum fe_stv0900_modcode modcode; - u8 car_loop_pilots_on_2; - u8 car_loop_pilots_off_2; - u8 car_loop_pilots_on_5; - u8 car_loop_pilots_off_5; - u8 car_loop_pilots_on_10; - u8 car_loop_pilots_off_10; - u8 car_loop_pilots_on_20; - u8 car_loop_pilots_off_20; - u8 car_loop_pilots_on_30; - u8 car_loop_pilots_off_30; - -}; - -struct stv0900_short_frames_car_loop_optim { - enum fe_stv0900_modulation modulation; - u8 car_loop_cut12_2; /* Cut 1.2, SR<=3msps */ - u8 car_loop_cut20_2; /* Cut 2.0, SR<3msps */ - u8 car_loop_cut12_5; /* Cut 1.2, 3 - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef STV0900_PRIV_H -#define STV0900_PRIV_H - -#include - -#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X)) -#define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \ - || (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0) - -#ifndef MAKEWORD -#define MAKEWORD(X, Y) (((X) << 8) + (Y)) -#endif - -#define LSB(X) (((X) & 0xFF)) -#define MSB(Y) (((Y) >> 8) & 0xFF) - -#ifndef TRUE -#define TRUE (1 == 1) -#endif -#ifndef FALSE -#define FALSE (!TRUE) -#endif - -#define dprintk(args...) \ - do { \ - if (stvdebug) \ - printk(KERN_DEBUG args); \ - } while (0) - -#define STV0900_MAXLOOKUPSIZE 500 -#define STV0900_BLIND_SEARCH_AGC2_TH 700 -#define STV0900_BLIND_SEARCH_AGC2_TH_CUT30 1400 -#define IQPOWER_THRESHOLD 30 - -/* One point of the lookup table */ -struct stv000_lookpoint { - s32 realval;/* real value */ - s32 regval;/* binary value */ -}; - -/* Lookup table definition */ -struct stv0900_table{ - s32 size;/* Size of the lookup table */ - struct stv000_lookpoint table[STV0900_MAXLOOKUPSIZE];/* Lookup table */ -}; - -enum fe_stv0900_error { - STV0900_NO_ERROR = 0, - STV0900_INVALID_HANDLE, - STV0900_BAD_PARAMETER, - STV0900_I2C_ERROR, - STV0900_SEARCH_FAILED, -}; - -enum fe_stv0900_clock_type { - STV0900_USE_REGISTERS_DEFAULT, - STV0900_SERIAL_PUNCT_CLOCK,/*Serial punctured clock */ - STV0900_SERIAL_CONT_CLOCK,/*Serial continues clock */ - STV0900_PARALLEL_PUNCT_CLOCK,/*Parallel punctured clock */ - STV0900_DVBCI_CLOCK/*Parallel continues clock : DVBCI */ -}; - -enum fe_stv0900_search_state { - STV0900_SEARCH = 0, - STV0900_PLH_DETECTED, - STV0900_DVBS2_FOUND, - STV0900_DVBS_FOUND - -}; - -enum fe_stv0900_ldpc_state { - STV0900_PATH1_OFF_PATH2_OFF = 0, - STV0900_PATH1_ON_PATH2_OFF = 1, - STV0900_PATH1_OFF_PATH2_ON = 2, - STV0900_PATH1_ON_PATH2_ON = 3 -}; - -enum fe_stv0900_signal_type { - STV0900_NOAGC1 = 0, - STV0900_AGC1OK, - STV0900_NOTIMING, - STV0900_ANALOGCARRIER, - STV0900_TIMINGOK, - STV0900_NOAGC2, - STV0900_AGC2OK, - STV0900_NOCARRIER, - STV0900_CARRIEROK, - STV0900_NODATA, - STV0900_DATAOK, - STV0900_OUTOFRANGE, - STV0900_RANGEOK -}; - -enum fe_stv0900_demod_num { - STV0900_DEMOD_1, - STV0900_DEMOD_2 -}; - -enum fe_stv0900_tracking_standard { - STV0900_DVBS1_STANDARD,/* Found Standard*/ - STV0900_DVBS2_STANDARD, - STV0900_DSS_STANDARD, - STV0900_TURBOCODE_STANDARD, - STV0900_UNKNOWN_STANDARD -}; - -enum fe_stv0900_search_standard { - STV0900_AUTO_SEARCH, - STV0900_SEARCH_DVBS1,/* Search Standard*/ - STV0900_SEARCH_DVBS2, - STV0900_SEARCH_DSS, - STV0900_SEARCH_TURBOCODE -}; - -enum fe_stv0900_search_algo { - STV0900_BLIND_SEARCH,/* offset freq and SR are Unknown */ - STV0900_COLD_START,/* only the SR is known */ - STV0900_WARM_START/* offset freq and SR are known */ -}; - -enum fe_stv0900_modulation { - STV0900_QPSK, - STV0900_8PSK, - STV0900_16APSK, - STV0900_32APSK, - STV0900_UNKNOWN -}; - -enum fe_stv0900_modcode { - STV0900_DUMMY_PLF, - STV0900_QPSK_14, - STV0900_QPSK_13, - STV0900_QPSK_25, - STV0900_QPSK_12, - STV0900_QPSK_35, - STV0900_QPSK_23, - STV0900_QPSK_34, - STV0900_QPSK_45, - STV0900_QPSK_56, - STV0900_QPSK_89, - STV0900_QPSK_910, - STV0900_8PSK_35, - STV0900_8PSK_23, - STV0900_8PSK_34, - STV0900_8PSK_56, - STV0900_8PSK_89, - STV0900_8PSK_910, - STV0900_16APSK_23, - STV0900_16APSK_34, - STV0900_16APSK_45, - STV0900_16APSK_56, - STV0900_16APSK_89, - STV0900_16APSK_910, - STV0900_32APSK_34, - STV0900_32APSK_45, - STV0900_32APSK_56, - STV0900_32APSK_89, - STV0900_32APSK_910, - STV0900_MODCODE_UNKNOWN -}; - -enum fe_stv0900_fec {/*DVBS1, DSS and turbo code puncture rate*/ - STV0900_FEC_1_2 = 0, - STV0900_FEC_2_3, - STV0900_FEC_3_4, - STV0900_FEC_4_5,/*for turbo code only*/ - STV0900_FEC_5_6, - STV0900_FEC_6_7,/*for DSS only */ - STV0900_FEC_7_8, - STV0900_FEC_8_9,/*for turbo code only*/ - STV0900_FEC_UNKNOWN -}; - -enum fe_stv0900_frame_length { - STV0900_LONG_FRAME, - STV0900_SHORT_FRAME -}; - -enum fe_stv0900_pilot { - STV0900_PILOTS_OFF, - STV0900_PILOTS_ON -}; - -enum fe_stv0900_rolloff { - STV0900_35, - STV0900_25, - STV0900_20 -}; - -enum fe_stv0900_search_iq { - STV0900_IQ_AUTO, - STV0900_IQ_AUTO_NORMAL_FIRST, - STV0900_IQ_FORCE_NORMAL, - STV0900_IQ_FORCE_SWAPPED -}; - -enum stv0900_iq_inversion { - STV0900_IQ_NORMAL, - STV0900_IQ_SWAPPED -}; - -enum fe_stv0900_diseqc_mode { - STV0900_22KHZ_Continues = 0, - STV0900_DISEQC_2_3_PWM = 2, - STV0900_DISEQC_3_3_PWM = 3, - STV0900_DISEQC_2_3_ENVELOP = 4, - STV0900_DISEQC_3_3_ENVELOP = 5 -}; - -enum fe_stv0900_demod_mode { - STV0900_SINGLE = 0, - STV0900_DUAL -}; - -struct stv0900_init_params{ - u32 dmd_ref_clk;/* Refrence,Input clock for the demod in Hz */ - - /* Demodulator Type (single demod or dual demod) */ - enum fe_stv0900_demod_mode demod_mode; - enum fe_stv0900_rolloff rolloff; - enum fe_stv0900_clock_type path1_ts_clock; - - u8 tun1_maddress; - int tuner1_adc; - int tuner1_type; - - /* IQ from the tuner1 to the demod */ - enum stv0900_iq_inversion tun1_iq_inv; - enum fe_stv0900_clock_type path2_ts_clock; - - u8 tun2_maddress; - int tuner2_adc; - int tuner2_type; - - /* IQ from the tuner2 to the demod */ - enum stv0900_iq_inversion tun2_iq_inv; - struct stv0900_reg *ts_config; -}; - -struct stv0900_search_params { - enum fe_stv0900_demod_num path;/* Path Used demod1 or 2 */ - - u32 frequency;/* Transponder frequency (in KHz) */ - u32 symbol_rate;/* Transponder symbol rate (in bds)*/ - u32 search_range;/* Range of the search (in Hz) */ - - enum fe_stv0900_search_standard standard; - enum fe_stv0900_modulation modulation; - enum fe_stv0900_fec fec; - enum fe_stv0900_modcode modcode; - enum fe_stv0900_search_iq iq_inversion; - enum fe_stv0900_search_algo search_algo; - -}; - -struct stv0900_signal_info { - int locked;/* Transponder locked */ - u32 frequency;/* Transponder frequency (in KHz) */ - u32 symbol_rate;/* Transponder symbol rate (in Mbds) */ - - enum fe_stv0900_tracking_standard standard; - enum fe_stv0900_fec fec; - enum fe_stv0900_modcode modcode; - enum fe_stv0900_modulation modulation; - enum fe_stv0900_pilot pilot; - enum fe_stv0900_frame_length frame_len; - enum stv0900_iq_inversion spectrum; - enum fe_stv0900_rolloff rolloff; - - s32 Power;/* Power of the RF signal (dBm) */ - s32 C_N;/* Carrier to noise ratio (dB x10)*/ - u32 BER;/* Bit error rate (x10^7) */ - -}; - -struct stv0900_internal{ - s32 quartz; - s32 mclk; - /* manual RollOff for DVBS1/DSS only */ - enum fe_stv0900_rolloff rolloff; - /* Demodulator use for single demod or for dual demod) */ - enum fe_stv0900_demod_mode demod_mode; - - /*Demods */ - s32 freq[2]; - s32 bw[2]; - s32 symbol_rate[2]; - s32 srch_range[2]; - /* for software/auto tuner */ - int tuner_type[2]; - - /* algorithm for search Blind, Cold or Warm*/ - enum fe_stv0900_search_algo srch_algo[2]; - /* search standard: Auto, DVBS1/DSS only or DVBS2 only*/ - enum fe_stv0900_search_standard srch_standard[2]; - /* inversion search : auto, auto norma first, normal or inverted */ - enum fe_stv0900_search_iq srch_iq_inv[2]; - enum fe_stv0900_modcode modcode[2]; - enum fe_stv0900_modulation modulation[2]; - enum fe_stv0900_fec fec[2]; - - struct stv0900_signal_info result[2]; - enum fe_stv0900_error err[2]; - - - struct i2c_adapter *i2c_adap; - u8 i2c_addr; - u8 clkmode;/* 0 for CLKI, 2 for XTALI */ - u8 chip_id; - struct stv0900_reg *ts_config; - enum fe_stv0900_error errs; - int dmds_used; -}; - -/* state for each demod */ -struct stv0900_state { - /* pointer for internal params, one for each pair of demods */ - struct stv0900_internal *internal; - struct i2c_adapter *i2c_adap; - const struct stv0900_config *config; - struct dvb_frontend frontend; - int demod; -}; - -extern int stvdebug; - -extern s32 ge2comp(s32 a, s32 width); - -extern void stv0900_write_reg(struct stv0900_internal *i_params, - u16 reg_addr, u8 reg_data); - -extern u8 stv0900_read_reg(struct stv0900_internal *i_params, - u16 reg_addr); - -extern void stv0900_write_bits(struct stv0900_internal *i_params, - u32 label, u8 val); - -extern u8 stv0900_get_bits(struct stv0900_internal *i_params, - u32 label); - -extern int stv0900_get_demod_lock(struct stv0900_internal *i_params, - enum fe_stv0900_demod_num demod, s32 time_out); -extern int stv0900_check_signal_presence(struct stv0900_internal *i_params, - enum fe_stv0900_demod_num demod); - -extern enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe); - -extern void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency, - u32 bandwidth); -extern void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth); - -extern void stv0900_start_search(struct stv0900_internal *i_params, - enum fe_stv0900_demod_num demod); - -extern u8 stv0900_get_optim_carr_loop(s32 srate, - enum fe_stv0900_modcode modcode, - s32 pilot, u8 chip_id); - -extern u8 stv0900_get_optim_short_carr_loop(s32 srate, - enum fe_stv0900_modulation modulation, - u8 chip_id); - -extern void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params, - enum fe_stv0900_demod_num demod); - -extern void stv0900_activate_s2_modcod(struct stv0900_internal *i_params, - enum fe_stv0900_demod_num demod); - -extern void stv0900_activate_s2_modcod_single(struct stv0900_internal *i_params, - enum fe_stv0900_demod_num demod); - -extern enum -fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe, - enum fe_stv0900_demod_num demod); - -extern u32 -stv0900_get_freq_auto(struct stv0900_internal *intp, int demod); - -extern void -stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency, - u32 Bandwidth, int demod); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,3981 +0,0 @@ -/* - * stv0900_reg.h - * - * Driver for ST STV0900 satellite demodulator IC. - * - * Copyright (C) ST Microelectronics. - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef STV0900_REG_H -#define STV0900_REG_H - -extern s32 shiftx(s32 x, int demod, s32 shift); - -#define REGx(x) shiftx(x, demod, 0x200) -#define FLDx(x) shiftx(x, demod, 0x2000000) - -/*MID*/ -#define R0900_MID 0xf100 -#define F0900_MCHIP_IDENT 0xf10000f0 -#define F0900_MRELEASE 0xf100000f - -/*DACR1*/ -#define R0900_DACR1 0xf113 -#define F0900_DAC_MODE 0xf11300e0 -#define F0900_DAC_VALUE1 0xf113000f - -/*DACR2*/ -#define R0900_DACR2 0xf114 -#define F0900_DAC_VALUE0 0xf11400ff - -/*OUTCFG*/ -#define R0900_OUTCFG 0xf11c -#define F0900_OUTSERRS1_HZ 0xf11c0040 -#define F0900_OUTSERRS2_HZ 0xf11c0020 -#define F0900_OUTSERRS3_HZ 0xf11c0010 -#define F0900_OUTPARRS3_HZ 0xf11c0008 - -/*IRQSTATUS3*/ -#define R0900_IRQSTATUS3 0xf120 -#define F0900_SPLL_LOCK 0xf1200020 -#define F0900_SSTREAM_LCK_3 0xf1200010 -#define F0900_SSTREAM_LCK_2 0xf1200008 -#define F0900_SSTREAM_LCK_1 0xf1200004 -#define F0900_SDVBS1_PRF_2 0xf1200002 -#define F0900_SDVBS1_PRF_1 0xf1200001 - -/*IRQSTATUS2*/ -#define R0900_IRQSTATUS2 0xf121 -#define F0900_SSPY_ENDSIM_3 0xf1210080 -#define F0900_SSPY_ENDSIM_2 0xf1210040 -#define F0900_SSPY_ENDSIM_1 0xf1210020 -#define F0900_SPKTDEL_ERROR_2 0xf1210010 -#define F0900_SPKTDEL_LOCKB_2 0xf1210008 -#define F0900_SPKTDEL_LOCK_2 0xf1210004 -#define F0900_SPKTDEL_ERROR_1 0xf1210002 -#define F0900_SPKTDEL_LOCKB_1 0xf1210001 - -/*IRQSTATUS1*/ -#define R0900_IRQSTATUS1 0xf122 -#define F0900_SPKTDEL_LOCK_1 0xf1220080 -#define F0900_SDEMOD_LOCKB_2 0xf1220004 -#define F0900_SDEMOD_LOCK_2 0xf1220002 -#define F0900_SDEMOD_IRQ_2 0xf1220001 - -/*IRQSTATUS0*/ -#define R0900_IRQSTATUS0 0xf123 -#define F0900_SDEMOD_LOCKB_1 0xf1230080 -#define F0900_SDEMOD_LOCK_1 0xf1230040 -#define F0900_SDEMOD_IRQ_1 0xf1230020 -#define F0900_SBCH_ERRFLAG 0xf1230010 -#define F0900_SDISEQC2RX_IRQ 0xf1230008 -#define F0900_SDISEQC2TX_IRQ 0xf1230004 -#define F0900_SDISEQC1RX_IRQ 0xf1230002 -#define F0900_SDISEQC1TX_IRQ 0xf1230001 - -/*IRQMASK3*/ -#define R0900_IRQMASK3 0xf124 -#define F0900_MPLL_LOCK 0xf1240020 -#define F0900_MSTREAM_LCK_3 0xf1240010 -#define F0900_MSTREAM_LCK_2 0xf1240008 -#define F0900_MSTREAM_LCK_1 0xf1240004 -#define F0900_MDVBS1_PRF_2 0xf1240002 -#define F0900_MDVBS1_PRF_1 0xf1240001 - -/*IRQMASK2*/ -#define R0900_IRQMASK2 0xf125 -#define F0900_MSPY_ENDSIM_3 0xf1250080 -#define F0900_MSPY_ENDSIM_2 0xf1250040 -#define F0900_MSPY_ENDSIM_1 0xf1250020 -#define F0900_MPKTDEL_ERROR_2 0xf1250010 -#define F0900_MPKTDEL_LOCKB_2 0xf1250008 -#define F0900_MPKTDEL_LOCK_2 0xf1250004 -#define F0900_MPKTDEL_ERROR_1 0xf1250002 -#define F0900_MPKTDEL_LOCKB_1 0xf1250001 - -/*IRQMASK1*/ -#define R0900_IRQMASK1 0xf126 -#define F0900_MPKTDEL_LOCK_1 0xf1260080 -#define F0900_MEXTPINB2 0xf1260040 -#define F0900_MEXTPIN2 0xf1260020 -#define F0900_MEXTPINB1 0xf1260010 -#define F0900_MEXTPIN1 0xf1260008 -#define F0900_MDEMOD_LOCKB_2 0xf1260004 -#define F0900_MDEMOD_LOCK_2 0xf1260002 -#define F0900_MDEMOD_IRQ_2 0xf1260001 - -/*IRQMASK0*/ -#define R0900_IRQMASK0 0xf127 -#define F0900_MDEMOD_LOCKB_1 0xf1270080 -#define F0900_MDEMOD_LOCK_1 0xf1270040 -#define F0900_MDEMOD_IRQ_1 0xf1270020 -#define F0900_MBCH_ERRFLAG 0xf1270010 -#define F0900_MDISEQC2RX_IRQ 0xf1270008 -#define F0900_MDISEQC2TX_IRQ 0xf1270004 -#define F0900_MDISEQC1RX_IRQ 0xf1270002 -#define F0900_MDISEQC1TX_IRQ 0xf1270001 - -/*I2CCFG*/ -#define R0900_I2CCFG 0xf129 -#define F0900_I2C_FASTMODE 0xf1290008 -#define F0900_I2CADDR_INC 0xf1290003 - -/*P1_I2CRPT*/ -#define R0900_P1_I2CRPT 0xf12a -#define I2CRPT shiftx(R0900_P1_I2CRPT, demod, -1) -#define F0900_P1_I2CT_ON 0xf12a0080 -#define I2CT_ON shiftx(F0900_P1_I2CT_ON, demod, -0x10000) -#define F0900_P1_ENARPT_LEVEL 0xf12a0070 -#define F0900_P1_SCLT_DELAY 0xf12a0008 -#define F0900_P1_STOP_ENABLE 0xf12a0004 -#define F0900_P1_STOP_SDAT2SDA 0xf12a0002 - -/*P2_I2CRPT*/ -#define R0900_P2_I2CRPT 0xf12b -#define F0900_P2_I2CT_ON 0xf12b0080 -#define F0900_P2_ENARPT_LEVEL 0xf12b0070 -#define F0900_P2_SCLT_DELAY 0xf12b0008 -#define F0900_P2_STOP_ENABLE 0xf12b0004 -#define F0900_P2_STOP_SDAT2SDA 0xf12b0002 - -/*IOPVALUE6*/ -#define R0900_IOPVALUE6 0xf138 -#define F0900_VSCL 0xf1380004 -#define F0900_VSDA 0xf1380002 -#define F0900_VDATA3_0 0xf1380001 - -/*IOPVALUE5*/ -#define R0900_IOPVALUE5 0xf139 -#define F0900_VDATA3_1 0xf1390080 -#define F0900_VDATA3_2 0xf1390040 -#define F0900_VDATA3_3 0xf1390020 -#define F0900_VDATA3_4 0xf1390010 -#define F0900_VDATA3_5 0xf1390008 -#define F0900_VDATA3_6 0xf1390004 -#define F0900_VDATA3_7 0xf1390002 -#define F0900_VCLKOUT3 0xf1390001 - -/*IOPVALUE4*/ -#define R0900_IOPVALUE4 0xf13a -#define F0900_VSTROUT3 0xf13a0080 -#define F0900_VDPN3 0xf13a0040 -#define F0900_VERROR3 0xf13a0020 -#define F0900_VDATA2_7 0xf13a0010 -#define F0900_VCLKOUT2 0xf13a0008 -#define F0900_VSTROUT2 0xf13a0004 -#define F0900_VDPN2 0xf13a0002 -#define F0900_VERROR2 0xf13a0001 - -/*IOPVALUE3*/ -#define R0900_IOPVALUE3 0xf13b -#define F0900_VDATA1_7 0xf13b0080 -#define F0900_VCLKOUT1 0xf13b0040 -#define F0900_VSTROUT1 0xf13b0020 -#define F0900_VDPN1 0xf13b0010 -#define F0900_VERROR1 0xf13b0008 -#define F0900_VCLKOUT27 0xf13b0004 -#define F0900_VDISEQCOUT2 0xf13b0002 -#define F0900_VSCLT2 0xf13b0001 - -/*IOPVALUE2*/ -#define R0900_IOPVALUE2 0xf13c -#define F0900_VSDAT2 0xf13c0080 -#define F0900_VAGCRF2 0xf13c0040 -#define F0900_VDISEQCOUT1 0xf13c0020 -#define F0900_VSCLT1 0xf13c0010 -#define F0900_VSDAT1 0xf13c0008 -#define F0900_VAGCRF1 0xf13c0004 -#define F0900_VDIRCLK 0xf13c0002 -#define F0900_VSTDBY 0xf13c0001 - -/*IOPVALUE1*/ -#define R0900_IOPVALUE1 0xf13d -#define F0900_VCS1 0xf13d0080 -#define F0900_VCS0 0xf13d0040 -#define F0900_VGPIO13 0xf13d0020 -#define F0900_VGPIO12 0xf13d0010 -#define F0900_VGPIO11 0xf13d0008 -#define F0900_VGPIO10 0xf13d0004 -#define F0900_VGPIO9 0xf13d0002 -#define F0900_VGPIO8 0xf13d0001 - -/*IOPVALUE0*/ -#define R0900_IOPVALUE0 0xf13e -#define F0900_VGPIO7 0xf13e0080 -#define F0900_VGPIO6 0xf13e0040 -#define F0900_VGPIO5 0xf13e0020 -#define F0900_VGPIO4 0xf13e0010 -#define F0900_VGPIO3 0xf13e0008 -#define F0900_VGPIO2 0xf13e0004 -#define F0900_VGPIO1 0xf13e0002 -#define F0900_VCLKI2 0xf13e0001 - -/*CLKI2CFG*/ -#define R0900_CLKI2CFG 0xf140 -#define F0900_CLKI2_OPD 0xf1400080 -#define F0900_CLKI2_CONFIG 0xf140007e -#define F0900_CLKI2_XOR 0xf1400001 - -/*GPIO1CFG*/ -#define R0900_GPIO1CFG 0xf141 -#define F0900_GPIO1_OPD 0xf1410080 -#define F0900_GPIO1_CONFIG 0xf141007e -#define F0900_GPIO1_XOR 0xf1410001 - -/*GPIO2CFG*/ -#define R0900_GPIO2CFG 0xf142 -#define F0900_GPIO2_OPD 0xf1420080 -#define F0900_GPIO2_CONFIG 0xf142007e -#define F0900_GPIO2_XOR 0xf1420001 - -/*GPIO3CFG*/ -#define R0900_GPIO3CFG 0xf143 -#define F0900_GPIO3_OPD 0xf1430080 -#define F0900_GPIO3_CONFIG 0xf143007e -#define F0900_GPIO3_XOR 0xf1430001 - -/*GPIO4CFG*/ -#define R0900_GPIO4CFG 0xf144 -#define F0900_GPIO4_OPD 0xf1440080 -#define F0900_GPIO4_CONFIG 0xf144007e -#define F0900_GPIO4_XOR 0xf1440001 - -/*GPIO5CFG*/ -#define R0900_GPIO5CFG 0xf145 -#define F0900_GPIO5_OPD 0xf1450080 -#define F0900_GPIO5_CONFIG 0xf145007e -#define F0900_GPIO5_XOR 0xf1450001 - -/*GPIO6CFG*/ -#define R0900_GPIO6CFG 0xf146 -#define F0900_GPIO6_OPD 0xf1460080 -#define F0900_GPIO6_CONFIG 0xf146007e -#define F0900_GPIO6_XOR 0xf1460001 - -/*GPIO7CFG*/ -#define R0900_GPIO7CFG 0xf147 -#define F0900_GPIO7_OPD 0xf1470080 -#define F0900_GPIO7_CONFIG 0xf147007e -#define F0900_GPIO7_XOR 0xf1470001 - -/*GPIO8CFG*/ -#define R0900_GPIO8CFG 0xf148 -#define F0900_GPIO8_OPD 0xf1480080 -#define F0900_GPIO8_CONFIG 0xf148007e -#define F0900_GPIO8_XOR 0xf1480001 - -/*GPIO9CFG*/ -#define R0900_GPIO9CFG 0xf149 -#define F0900_GPIO9_OPD 0xf1490080 -#define F0900_GPIO9_CONFIG 0xf149007e -#define F0900_GPIO9_XOR 0xf1490001 - -/*GPIO10CFG*/ -#define R0900_GPIO10CFG 0xf14a -#define F0900_GPIO10_OPD 0xf14a0080 -#define F0900_GPIO10_CONFIG 0xf14a007e -#define F0900_GPIO10_XOR 0xf14a0001 - -/*GPIO11CFG*/ -#define R0900_GPIO11CFG 0xf14b -#define F0900_GPIO11_OPD 0xf14b0080 -#define F0900_GPIO11_CONFIG 0xf14b007e -#define F0900_GPIO11_XOR 0xf14b0001 - -/*GPIO12CFG*/ -#define R0900_GPIO12CFG 0xf14c -#define F0900_GPIO12_OPD 0xf14c0080 -#define F0900_GPIO12_CONFIG 0xf14c007e -#define F0900_GPIO12_XOR 0xf14c0001 - -/*GPIO13CFG*/ -#define R0900_GPIO13CFG 0xf14d -#define F0900_GPIO13_OPD 0xf14d0080 -#define F0900_GPIO13_CONFIG 0xf14d007e -#define F0900_GPIO13_XOR 0xf14d0001 - -/*CS0CFG*/ -#define R0900_CS0CFG 0xf14e -#define F0900_CS0_OPD 0xf14e0080 -#define F0900_CS0_CONFIG 0xf14e007e -#define F0900_CS0_XOR 0xf14e0001 - -/*CS1CFG*/ -#define R0900_CS1CFG 0xf14f -#define F0900_CS1_OPD 0xf14f0080 -#define F0900_CS1_CONFIG 0xf14f007e -#define F0900_CS1_XOR 0xf14f0001 - -/*STDBYCFG*/ -#define R0900_STDBYCFG 0xf150 -#define F0900_STDBY_OPD 0xf1500080 -#define F0900_STDBY_CONFIG 0xf150007e -#define F0900_STBDY_XOR 0xf1500001 - -/*DIRCLKCFG*/ -#define R0900_DIRCLKCFG 0xf151 -#define F0900_DIRCLK_OPD 0xf1510080 -#define F0900_DIRCLK_CONFIG 0xf151007e -#define F0900_DIRCLK_XOR 0xf1510001 - -/*AGCRF1CFG*/ -#define R0900_AGCRF1CFG 0xf152 -#define F0900_AGCRF1_OPD 0xf1520080 -#define F0900_AGCRF1_CONFIG 0xf152007e -#define F0900_AGCRF1_XOR 0xf1520001 - -/*SDAT1CFG*/ -#define R0900_SDAT1CFG 0xf153 -#define F0900_SDAT1_OPD 0xf1530080 -#define F0900_SDAT1_CONFIG 0xf153007e -#define F0900_SDAT1_XOR 0xf1530001 - -/*SCLT1CFG*/ -#define R0900_SCLT1CFG 0xf154 -#define F0900_SCLT1_OPD 0xf1540080 -#define F0900_SCLT1_CONFIG 0xf154007e -#define F0900_SCLT1_XOR 0xf1540001 - -/*DISEQCO1CFG*/ -#define R0900_DISEQCO1CFG 0xf155 -#define F0900_DISEQCO1_OPD 0xf1550080 -#define F0900_DISEQCO1_CONFIG 0xf155007e -#define F0900_DISEQC1_XOR 0xf1550001 - -/*AGCRF2CFG*/ -#define R0900_AGCRF2CFG 0xf156 -#define F0900_AGCRF2_OPD 0xf1560080 -#define F0900_AGCRF2_CONFIG 0xf156007e -#define F0900_AGCRF2_XOR 0xf1560001 - -/*SDAT2CFG*/ -#define R0900_SDAT2CFG 0xf157 -#define F0900_SDAT2_OPD 0xf1570080 -#define F0900_SDAT2_CONFIG 0xf157007e -#define F0900_SDAT2_XOR 0xf1570001 - -/*SCLT2CFG*/ -#define R0900_SCLT2CFG 0xf158 -#define F0900_SCLT2_OPD 0xf1580080 -#define F0900_SCLT2_CONFIG 0xf158007e -#define F0900_SCLT2_XOR 0xf1580001 - -/*DISEQCO2CFG*/ -#define R0900_DISEQCO2CFG 0xf159 -#define F0900_DISEQCO2_OPD 0xf1590080 -#define F0900_DISEQCO2_CONFIG 0xf159007e -#define F0900_DISEQC2_XOR 0xf1590001 - -/*CLKOUT27CFG*/ -#define R0900_CLKOUT27CFG 0xf15a -#define F0900_CLKOUT27_OPD 0xf15a0080 -#define F0900_CLKOUT27_CONFIG 0xf15a007e -#define F0900_CLKOUT27_XOR 0xf15a0001 - -/*ERROR1CFG*/ -#define R0900_ERROR1CFG 0xf15b -#define F0900_ERROR1_OPD 0xf15b0080 -#define F0900_ERROR1_CONFIG 0xf15b007e -#define F0900_ERROR1_XOR 0xf15b0001 - -/*DPN1CFG*/ -#define R0900_DPN1CFG 0xf15c -#define F0900_DPN1_OPD 0xf15c0080 -#define F0900_DPN1_CONFIG 0xf15c007e -#define F0900_DPN1_XOR 0xf15c0001 - -/*STROUT1CFG*/ -#define R0900_STROUT1CFG 0xf15d -#define F0900_STROUT1_OPD 0xf15d0080 -#define F0900_STROUT1_CONFIG 0xf15d007e -#define F0900_STROUT1_XOR 0xf15d0001 - -/*CLKOUT1CFG*/ -#define R0900_CLKOUT1CFG 0xf15e -#define F0900_CLKOUT1_OPD 0xf15e0080 -#define F0900_CLKOUT1_CONFIG 0xf15e007e -#define F0900_CLKOUT1_XOR 0xf15e0001 - -/*DATA71CFG*/ -#define R0900_DATA71CFG 0xf15f -#define F0900_DATA71_OPD 0xf15f0080 -#define F0900_DATA71_CONFIG 0xf15f007e -#define F0900_DATA71_XOR 0xf15f0001 - -/*ERROR2CFG*/ -#define R0900_ERROR2CFG 0xf160 -#define F0900_ERROR2_OPD 0xf1600080 -#define F0900_ERROR2_CONFIG 0xf160007e -#define F0900_ERROR2_XOR 0xf1600001 - -/*DPN2CFG*/ -#define R0900_DPN2CFG 0xf161 -#define F0900_DPN2_OPD 0xf1610080 -#define F0900_DPN2_CONFIG 0xf161007e -#define F0900_DPN2_XOR 0xf1610001 - -/*STROUT2CFG*/ -#define R0900_STROUT2CFG 0xf162 -#define F0900_STROUT2_OPD 0xf1620080 -#define F0900_STROUT2_CONFIG 0xf162007e -#define F0900_STROUT2_XOR 0xf1620001 - -/*CLKOUT2CFG*/ -#define R0900_CLKOUT2CFG 0xf163 -#define F0900_CLKOUT2_OPD 0xf1630080 -#define F0900_CLKOUT2_CONFIG 0xf163007e -#define F0900_CLKOUT2_XOR 0xf1630001 - -/*DATA72CFG*/ -#define R0900_DATA72CFG 0xf164 -#define F0900_DATA72_OPD 0xf1640080 -#define F0900_DATA72_CONFIG 0xf164007e -#define F0900_DATA72_XOR 0xf1640001 - -/*ERROR3CFG*/ -#define R0900_ERROR3CFG 0xf165 -#define F0900_ERROR3_OPD 0xf1650080 -#define F0900_ERROR3_CONFIG 0xf165007e -#define F0900_ERROR3_XOR 0xf1650001 - -/*DPN3CFG*/ -#define R0900_DPN3CFG 0xf166 -#define F0900_DPN3_OPD 0xf1660080 -#define F0900_DPN3_CONFIG 0xf166007e -#define F0900_DPN3_XOR 0xf1660001 - -/*STROUT3CFG*/ -#define R0900_STROUT3CFG 0xf167 -#define F0900_STROUT3_OPD 0xf1670080 -#define F0900_STROUT3_CONFIG 0xf167007e -#define F0900_STROUT3_XOR 0xf1670001 - -/*CLKOUT3CFG*/ -#define R0900_CLKOUT3CFG 0xf168 -#define F0900_CLKOUT3_OPD 0xf1680080 -#define F0900_CLKOUT3_CONFIG 0xf168007e -#define F0900_CLKOUT3_XOR 0xf1680001 - -/*DATA73CFG*/ -#define R0900_DATA73CFG 0xf169 -#define F0900_DATA73_OPD 0xf1690080 -#define F0900_DATA73_CONFIG 0xf169007e -#define F0900_DATA73_XOR 0xf1690001 - -/*STRSTATUS1*/ -#define R0900_STRSTATUS1 0xf16a -#define F0900_STRSTATUS_SEL2 0xf16a00f0 -#define F0900_STRSTATUS_SEL1 0xf16a000f - -/*STRSTATUS2*/ -#define R0900_STRSTATUS2 0xf16b -#define F0900_STRSTATUS_SEL4 0xf16b00f0 -#define F0900_STRSTATUS_SEL3 0xf16b000f - -/*STRSTATUS3*/ -#define R0900_STRSTATUS3 0xf16c -#define F0900_STRSTATUS_SEL6 0xf16c00f0 -#define F0900_STRSTATUS_SEL5 0xf16c000f - -/*FSKTFC2*/ -#define R0900_FSKTFC2 0xf170 -#define F0900_FSKT_KMOD 0xf17000fc -#define F0900_FSKT_CAR2 0xf1700003 - -/*FSKTFC1*/ -#define R0900_FSKTFC1 0xf171 -#define F0900_FSKT_CAR1 0xf17100ff - -/*FSKTFC0*/ -#define R0900_FSKTFC0 0xf172 -#define F0900_FSKT_CAR0 0xf17200ff - -/*FSKTDELTAF1*/ -#define R0900_FSKTDELTAF1 0xf173 -#define F0900_FSKT_DELTAF1 0xf173000f - -/*FSKTDELTAF0*/ -#define R0900_FSKTDELTAF0 0xf174 -#define F0900_FSKT_DELTAF0 0xf17400ff - -/*FSKTCTRL*/ -#define R0900_FSKTCTRL 0xf175 -#define F0900_FSKT_EN_SGN 0xf1750040 -#define F0900_FSKT_MOD_SGN 0xf1750020 -#define F0900_FSKT_MOD_EN 0xf175001c -#define F0900_FSKT_DACMODE 0xf1750003 - -/*FSKRFC2*/ -#define R0900_FSKRFC2 0xf176 -#define F0900_FSKR_DETSGN 0xf1760040 -#define F0900_FSKR_OUTSGN 0xf1760020 -#define F0900_FSKR_KAGC 0xf176001c -#define F0900_FSKR_CAR2 0xf1760003 - -/*FSKRFC1*/ -#define R0900_FSKRFC1 0xf177 -#define F0900_FSKR_CAR1 0xf17700ff - -/*FSKRFC0*/ -#define R0900_FSKRFC0 0xf178 -#define F0900_FSKR_CAR0 0xf17800ff - -/*FSKRK1*/ -#define R0900_FSKRK1 0xf179 -#define F0900_FSKR_K1_EXP 0xf17900e0 -#define F0900_FSKR_K1_MANT 0xf179001f - -/*FSKRK2*/ -#define R0900_FSKRK2 0xf17a -#define F0900_FSKR_K2_EXP 0xf17a00e0 -#define F0900_FSKR_K2_MANT 0xf17a001f - -/*FSKRAGCR*/ -#define R0900_FSKRAGCR 0xf17b -#define F0900_FSKR_OUTCTL 0xf17b00c0 -#define F0900_FSKR_AGC_REF 0xf17b003f - -/*FSKRAGC*/ -#define R0900_FSKRAGC 0xf17c -#define F0900_FSKR_AGC_ACCU 0xf17c00ff - -/*FSKRALPHA*/ -#define R0900_FSKRALPHA 0xf17d -#define F0900_FSKR_ALPHA_EXP 0xf17d001c -#define F0900_FSKR_ALPHA_M 0xf17d0003 - -/*FSKRPLTH1*/ -#define R0900_FSKRPLTH1 0xf17e -#define F0900_FSKR_BETA 0xf17e00f0 -#define F0900_FSKR_PLL_TRESH1 0xf17e000f - -/*FSKRPLTH0*/ -#define R0900_FSKRPLTH0 0xf17f -#define F0900_FSKR_PLL_TRESH0 0xf17f00ff - -/*FSKRDF1*/ -#define R0900_FSKRDF1 0xf180 -#define F0900_FSKR_OUT 0xf1800080 -#define F0900_FSKR_DELTAF1 0xf180001f - -/*FSKRDF0*/ -#define R0900_FSKRDF0 0xf181 -#define F0900_FSKR_DELTAF0 0xf18100ff - -/*FSKRSTEPP*/ -#define R0900_FSKRSTEPP 0xf182 -#define F0900_FSKR_STEP_PLUS 0xf18200ff - -/*FSKRSTEPM*/ -#define R0900_FSKRSTEPM 0xf183 -#define F0900_FSKR_STEP_MINUS 0xf18300ff - -/*FSKRDET1*/ -#define R0900_FSKRDET1 0xf184 -#define F0900_FSKR_DETECT 0xf1840080 -#define F0900_FSKR_CARDET_ACCU1 0xf184000f - -/*FSKRDET0*/ -#define R0900_FSKRDET0 0xf185 -#define F0900_FSKR_CARDET_ACCU0 0xf18500ff - -/*FSKRDTH1*/ -#define R0900_FSKRDTH1 0xf186 -#define F0900_FSKR_CARLOSS_THRESH1 0xf18600f0 -#define F0900_FSKR_CARDET_THRESH1 0xf186000f - -/*FSKRDTH0*/ -#define R0900_FSKRDTH0 0xf187 -#define F0900_FSKR_CARDET_THRESH0 0xf18700ff - -/*FSKRLOSS*/ -#define R0900_FSKRLOSS 0xf188 -#define F0900_FSKR_CARLOSS_THRESH0 0xf18800ff - -/*P2_DISTXCTL*/ -#define R0900_P2_DISTXCTL 0xf190 -#define F0900_P2_TIM_OFF 0xf1900080 -#define F0900_P2_DISEQC_RESET 0xf1900040 -#define F0900_P2_TIM_CMD 0xf1900030 -#define F0900_P2_DIS_PRECHARGE 0xf1900008 -#define F0900_P2_DISTX_MODE 0xf1900007 - -/*P2_DISRXCTL*/ -#define R0900_P2_DISRXCTL 0xf191 -#define F0900_P2_RECEIVER_ON 0xf1910080 -#define F0900_P2_IGNO_SHORT22K 0xf1910040 -#define F0900_P2_ONECHIP_TRX 0xf1910020 -#define F0900_P2_EXT_ENVELOP 0xf1910010 -#define F0900_P2_PIN_SELECT0 0xf191000c -#define F0900_P2_IRQ_RXEND 0xf1910002 -#define F0900_P2_IRQ_4NBYTES 0xf1910001 - -/*P2_DISRX_ST0*/ -#define R0900_P2_DISRX_ST0 0xf194 -#define F0900_P2_RX_END 0xf1940080 -#define F0900_P2_RX_ACTIVE 0xf1940040 -#define F0900_P2_SHORT_22KHZ 0xf1940020 -#define F0900_P2_CONT_TONE 0xf1940010 -#define F0900_P2_FIFO_4BREADY 0xf1940008 -#define F0900_P2_FIFO_EMPTY 0xf1940004 -#define F0900_P2_ABORT_DISRX 0xf1940001 - -/*P2_DISRX_ST1*/ -#define R0900_P2_DISRX_ST1 0xf195 -#define F0900_P2_RX_FAIL 0xf1950080 -#define F0900_P2_FIFO_PARITYFAIL 0xf1950040 -#define F0900_P2_RX_NONBYTE 0xf1950020 -#define F0900_P2_FIFO_OVERFLOW 0xf1950010 -#define F0900_P2_FIFO_BYTENBR 0xf195000f - -/*P2_DISRXDATA*/ -#define R0900_P2_DISRXDATA 0xf196 -#define F0900_P2_DISRX_DATA 0xf19600ff - -/*P2_DISTXDATA*/ -#define R0900_P2_DISTXDATA 0xf197 -#define F0900_P2_DISEQC_FIFO 0xf19700ff - -/*P2_DISTXSTATUS*/ -#define R0900_P2_DISTXSTATUS 0xf198 -#define F0900_P2_TX_FAIL 0xf1980080 -#define F0900_P2_FIFO_FULL 0xf1980040 -#define F0900_P2_TX_IDLE 0xf1980020 -#define F0900_P2_GAP_BURST 0xf1980010 -#define F0900_P2_TXFIFO_BYTES 0xf198000f - -/*P2_F22TX*/ -#define R0900_P2_F22TX 0xf199 -#define F0900_P2_F22_REG 0xf19900ff - -/*P2_F22RX*/ -#define R0900_P2_F22RX 0xf19a -#define F0900_P2_F22RX_REG 0xf19a00ff - -/*P2_ACRPRESC*/ -#define R0900_P2_ACRPRESC 0xf19c -#define F0900_P2_ACR_PRESC 0xf19c0007 - -/*P2_ACRDIV*/ -#define R0900_P2_ACRDIV 0xf19d -#define F0900_P2_ACR_DIV 0xf19d00ff - -/*P1_DISTXCTL*/ -#define R0900_P1_DISTXCTL 0xf1a0 -#define DISTXCTL shiftx(R0900_P1_DISTXCTL, demod, 0x10) -#define F0900_P1_TIM_OFF 0xf1a00080 -#define F0900_P1_DISEQC_RESET 0xf1a00040 -#define DISEQC_RESET shiftx(F0900_P1_DISEQC_RESET, demod, 0x100000) -#define F0900_P1_TIM_CMD 0xf1a00030 -#define F0900_P1_DIS_PRECHARGE 0xf1a00008 -#define DIS_PRECHARGE shiftx(F0900_P1_DIS_PRECHARGE, demod, 0x100000) -#define F0900_P1_DISTX_MODE 0xf1a00007 -#define DISTX_MODE shiftx(F0900_P1_DISTX_MODE, demod, 0x100000) - -/*P1_DISRXCTL*/ -#define R0900_P1_DISRXCTL 0xf1a1 -#define DISRXCTL shiftx(R0900_P1_DISRXCTL, demod, 0x10) -#define F0900_P1_RECEIVER_ON 0xf1a10080 -#define F0900_P1_IGNO_SHORT22K 0xf1a10040 -#define F0900_P1_ONECHIP_TRX 0xf1a10020 -#define F0900_P1_EXT_ENVELOP 0xf1a10010 -#define F0900_P1_PIN_SELECT0 0xf1a1000c -#define F0900_P1_IRQ_RXEND 0xf1a10002 -#define F0900_P1_IRQ_4NBYTES 0xf1a10001 - -/*P1_DISRX_ST0*/ -#define R0900_P1_DISRX_ST0 0xf1a4 -#define DISRX_ST0 shiftx(R0900_P1_DISRX_ST0, demod, 0x10) -#define F0900_P1_RX_END 0xf1a40080 -#define RX_END shiftx(F0900_P1_RX_END, demod, 0x100000) -#define F0900_P1_RX_ACTIVE 0xf1a40040 -#define F0900_P1_SHORT_22KHZ 0xf1a40020 -#define F0900_P1_CONT_TONE 0xf1a40010 -#define F0900_P1_FIFO_4BREADY 0xf1a40008 -#define F0900_P1_FIFO_EMPTY 0xf1a40004 -#define F0900_P1_ABORT_DISRX 0xf1a40001 - -/*P1_DISRX_ST1*/ -#define R0900_P1_DISRX_ST1 0xf1a5 -#define DISRX_ST1 shiftx(R0900_P1_DISRX_ST1, demod, 0x10) -#define F0900_P1_RX_FAIL 0xf1a50080 -#define F0900_P1_FIFO_PARITYFAIL 0xf1a50040 -#define F0900_P1_RX_NONBYTE 0xf1a50020 -#define F0900_P1_FIFO_OVERFLOW 0xf1a50010 -#define F0900_P1_FIFO_BYTENBR 0xf1a5000f -#define FIFO_BYTENBR shiftx(F0900_P1_FIFO_BYTENBR, demod, 0x100000) - -/*P1_DISRXDATA*/ -#define R0900_P1_DISRXDATA 0xf1a6 -#define DISRXDATA shiftx(R0900_P1_DISRXDATA, demod, 0x10) -#define F0900_P1_DISRX_DATA 0xf1a600ff - -/*P1_DISTXDATA*/ -#define R0900_P1_DISTXDATA 0xf1a7 -#define DISTXDATA shiftx(R0900_P1_DISTXDATA, demod, 0x10) -#define F0900_P1_DISEQC_FIFO 0xf1a700ff - -/*P1_DISTXSTATUS*/ -#define R0900_P1_DISTXSTATUS 0xf1a8 -#define F0900_P1_TX_FAIL 0xf1a80080 -#define F0900_P1_FIFO_FULL 0xf1a80040 -#define FIFO_FULL shiftx(F0900_P1_FIFO_FULL, demod, 0x100000) -#define F0900_P1_TX_IDLE 0xf1a80020 -#define TX_IDLE shiftx(F0900_P1_TX_IDLE, demod, 0x100000) -#define F0900_P1_GAP_BURST 0xf1a80010 -#define F0900_P1_TXFIFO_BYTES 0xf1a8000f - -/*P1_F22TX*/ -#define R0900_P1_F22TX 0xf1a9 -#define F22TX shiftx(R0900_P1_F22TX, demod, 0x10) -#define F0900_P1_F22_REG 0xf1a900ff - -/*P1_F22RX*/ -#define R0900_P1_F22RX 0xf1aa -#define F22RX shiftx(R0900_P1_F22RX, demod, 0x10) -#define F0900_P1_F22RX_REG 0xf1aa00ff - -/*P1_ACRPRESC*/ -#define R0900_P1_ACRPRESC 0xf1ac -#define ACRPRESC shiftx(R0900_P1_ACRPRESC, demod, 0x10) -#define F0900_P1_ACR_PRESC 0xf1ac0007 - -/*P1_ACRDIV*/ -#define R0900_P1_ACRDIV 0xf1ad -#define ACRDIV shiftx(R0900_P1_ACRDIV, demod, 0x10) -#define F0900_P1_ACR_DIV 0xf1ad00ff - -/*NCOARSE*/ -#define R0900_NCOARSE 0xf1b3 -#define F0900_M_DIV 0xf1b300ff - -/*SYNTCTRL*/ -#define R0900_SYNTCTRL 0xf1b6 -#define F0900_STANDBY 0xf1b60080 -#define F0900_BYPASSPLLCORE 0xf1b60040 -#define F0900_SELX1RATIO 0xf1b60020 -#define F0900_STOP_PLL 0xf1b60008 -#define F0900_BYPASSPLLFSK 0xf1b60004 -#define F0900_SELOSCI 0xf1b60002 -#define F0900_BYPASSPLLADC 0xf1b60001 - -/*FILTCTRL*/ -#define R0900_FILTCTRL 0xf1b7 -#define F0900_INV_CLK135 0xf1b70080 -#define F0900_SEL_FSKCKDIV 0xf1b70004 -#define F0900_INV_CLKFSK 0xf1b70002 -#define F0900_BYPASS_APPLI 0xf1b70001 - -/*PLLSTAT*/ -#define R0900_PLLSTAT 0xf1b8 -#define F0900_PLLLOCK 0xf1b80001 - -/*STOPCLK1*/ -#define R0900_STOPCLK1 0xf1c2 -#define F0900_STOP_CLKPKDT2 0xf1c20040 -#define F0900_STOP_CLKPKDT1 0xf1c20020 -#define F0900_STOP_CLKFEC 0xf1c20010 -#define F0900_STOP_CLKADCI2 0xf1c20008 -#define F0900_INV_CLKADCI2 0xf1c20004 -#define F0900_STOP_CLKADCI1 0xf1c20002 -#define F0900_INV_CLKADCI1 0xf1c20001 - -/*STOPCLK2*/ -#define R0900_STOPCLK2 0xf1c3 -#define F0900_STOP_CLKSAMP2 0xf1c30010 -#define F0900_STOP_CLKSAMP1 0xf1c30008 -#define F0900_STOP_CLKVIT2 0xf1c30004 -#define F0900_STOP_CLKVIT1 0xf1c30002 -#define STOP_CLKVIT shiftx(F0900_STOP_CLKVIT1, demod, -2) -#define F0900_STOP_CLKTS 0xf1c30001 - -/*TSTTNR0*/ -#define R0900_TSTTNR0 0xf1df -#define F0900_SEL_FSK 0xf1df0080 -#define F0900_FSK_PON 0xf1df0004 - -/*TSTTNR1*/ -#define R0900_TSTTNR1 0xf1e0 -#define F0900_ADC1_PON 0xf1e00002 -#define F0900_ADC1_INMODE 0xf1e00001 - -/*TSTTNR2*/ -#define R0900_TSTTNR2 0xf1e1 -#define F0900_DISEQC1_PON 0xf1e10020 - -/*TSTTNR3*/ -#define R0900_TSTTNR3 0xf1e2 -#define F0900_ADC2_PON 0xf1e20002 -#define F0900_ADC2_INMODE 0xf1e20001 - -/*TSTTNR4*/ -#define R0900_TSTTNR4 0xf1e3 -#define F0900_DISEQC2_PON 0xf1e30020 - -/*P2_IQCONST*/ -#define R0900_P2_IQCONST 0xf200 -#define F0900_P2_CONSTEL_SELECT 0xf2000060 -#define F0900_P2_IQSYMB_SEL 0xf200001f - -/*P2_NOSCFG*/ -#define R0900_P2_NOSCFG 0xf201 -#define F0900_P2_DUMMYPL_NOSDATA 0xf2010020 -#define F0900_P2_NOSPLH_BETA 0xf2010018 -#define F0900_P2_NOSDATA_BETA 0xf2010007 - -/*P2_ISYMB*/ -#define R0900_P2_ISYMB 0xf202 -#define F0900_P2_I_SYMBOL 0xf20201ff - -/*P2_QSYMB*/ -#define R0900_P2_QSYMB 0xf203 -#define F0900_P2_Q_SYMBOL 0xf20301ff - -/*P2_AGC1CFG*/ -#define R0900_P2_AGC1CFG 0xf204 -#define F0900_P2_DC_FROZEN 0xf2040080 -#define F0900_P2_DC_CORRECT 0xf2040040 -#define F0900_P2_AMM_FROZEN 0xf2040020 -#define F0900_P2_AMM_CORRECT 0xf2040010 -#define F0900_P2_QUAD_FROZEN 0xf2040008 -#define F0900_P2_QUAD_CORRECT 0xf2040004 - -/*P2_AGC1CN*/ -#define R0900_P2_AGC1CN 0xf206 -#define F0900_P2_AGC1_LOCKED 0xf2060080 -#define F0900_P2_AGC1_MINPOWER 0xf2060010 -#define F0900_P2_AGCOUT_FAST 0xf2060008 -#define F0900_P2_AGCIQ_BETA 0xf2060007 - -/*P2_AGC1REF*/ -#define R0900_P2_AGC1REF 0xf207 -#define F0900_P2_AGCIQ_REF 0xf20700ff - -/*P2_IDCCOMP*/ -#define R0900_P2_IDCCOMP 0xf208 -#define F0900_P2_IAVERAGE_ADJ 0xf20801ff - -/*P2_QDCCOMP*/ -#define R0900_P2_QDCCOMP 0xf209 -#define F0900_P2_QAVERAGE_ADJ 0xf20901ff - -/*P2_POWERI*/ -#define R0900_P2_POWERI 0xf20a -#define F0900_P2_POWER_I 0xf20a00ff - -/*P2_POWERQ*/ -#define R0900_P2_POWERQ 0xf20b -#define F0900_P2_POWER_Q 0xf20b00ff - -/*P2_AGC1AMM*/ -#define R0900_P2_AGC1AMM 0xf20c -#define F0900_P2_AMM_VALUE 0xf20c00ff - -/*P2_AGC1QUAD*/ -#define R0900_P2_AGC1QUAD 0xf20d -#define F0900_P2_QUAD_VALUE 0xf20d01ff - -/*P2_AGCIQIN1*/ -#define R0900_P2_AGCIQIN1 0xf20e -#define F0900_P2_AGCIQ_VALUE1 0xf20e00ff - -/*P2_AGCIQIN0*/ -#define R0900_P2_AGCIQIN0 0xf20f -#define F0900_P2_AGCIQ_VALUE0 0xf20f00ff - -/*P2_DEMOD*/ -#define R0900_P2_DEMOD 0xf210 -#define F0900_P2_MANUALS2_ROLLOFF 0xf2100080 -#define F0900_P2_SPECINV_CONTROL 0xf2100030 -#define F0900_P2_FORCE_ENASAMP 0xf2100008 -#define F0900_P2_MANUALSX_ROLLOFF 0xf2100004 -#define F0900_P2_ROLLOFF_CONTROL 0xf2100003 - -/*P2_DMDMODCOD*/ -#define R0900_P2_DMDMODCOD 0xf211 -#define F0900_P2_MANUAL_MODCOD 0xf2110080 -#define F0900_P2_DEMOD_MODCOD 0xf211007c -#define F0900_P2_DEMOD_TYPE 0xf2110003 - -/*P2_DSTATUS*/ -#define R0900_P2_DSTATUS 0xf212 -#define F0900_P2_CAR_LOCK 0xf2120080 -#define F0900_P2_TMGLOCK_QUALITY 0xf2120060 -#define F0900_P2_LOCK_DEFINITIF 0xf2120008 -#define F0900_P2_OVADC_DETECT 0xf2120001 - -/*P2_DSTATUS2*/ -#define R0900_P2_DSTATUS2 0xf213 -#define F0900_P2_DEMOD_DELOCK 0xf2130080 -#define F0900_P2_AGC1_NOSIGNALACK 0xf2130008 -#define F0900_P2_AGC2_OVERFLOW 0xf2130004 -#define F0900_P2_CFR_OVERFLOW 0xf2130002 -#define F0900_P2_GAMMA_OVERUNDER 0xf2130001 - -/*P2_DMDCFGMD*/ -#define R0900_P2_DMDCFGMD 0xf214 -#define F0900_P2_DVBS2_ENABLE 0xf2140080 -#define F0900_P2_DVBS1_ENABLE 0xf2140040 -#define F0900_P2_SCAN_ENABLE 0xf2140010 -#define F0900_P2_CFR_AUTOSCAN 0xf2140008 -#define F0900_P2_TUN_RNG 0xf2140003 - -/*P2_DMDCFG2*/ -#define R0900_P2_DMDCFG2 0xf215 -#define F0900_P2_S1S2_SEQUENTIAL 0xf2150040 -#define F0900_P2_INFINITE_RELOCK 0xf2150010 - -/*P2_DMDISTATE*/ -#define R0900_P2_DMDISTATE 0xf216 -#define F0900_P2_I2C_DEMOD_MODE 0xf216001f - -/*P2_DMDT0M*/ -#define R0900_P2_DMDT0M 0xf217 -#define F0900_P2_DMDT0_MIN 0xf21700ff - -/*P2_DMDSTATE*/ -#define R0900_P2_DMDSTATE 0xf21b -#define F0900_P2_HEADER_MODE 0xf21b0060 - -/*P2_DMDFLYW*/ -#define R0900_P2_DMDFLYW 0xf21c -#define F0900_P2_I2C_IRQVAL 0xf21c00f0 -#define F0900_P2_FLYWHEEL_CPT 0xf21c000f - -/*P2_DSTATUS3*/ -#define R0900_P2_DSTATUS3 0xf21d -#define F0900_P2_DEMOD_CFGMODE 0xf21d0060 - -/*P2_DMDCFG3*/ -#define R0900_P2_DMDCFG3 0xf21e -#define F0900_P2_NOSTOP_FIFOFULL 0xf21e0008 - -/*P2_DMDCFG4*/ -#define R0900_P2_DMDCFG4 0xf21f -#define F0900_P2_TUNER_NRELAUNCH 0xf21f0008 - -/*P2_CORRELMANT*/ -#define R0900_P2_CORRELMANT 0xf220 -#define F0900_P2_CORREL_MANT 0xf22000ff - -/*P2_CORRELABS*/ -#define R0900_P2_CORRELABS 0xf221 -#define F0900_P2_CORREL_ABS 0xf22100ff - -/*P2_CORRELEXP*/ -#define R0900_P2_CORRELEXP 0xf222 -#define F0900_P2_CORREL_ABSEXP 0xf22200f0 -#define F0900_P2_CORREL_EXP 0xf222000f - -/*P2_PLHMODCOD*/ -#define R0900_P2_PLHMODCOD 0xf224 -#define F0900_P2_SPECINV_DEMOD 0xf2240080 -#define F0900_P2_PLH_MODCOD 0xf224007c -#define F0900_P2_PLH_TYPE 0xf2240003 - -/*P2_DMDREG*/ -#define R0900_P2_DMDREG 0xf225 -#define F0900_P2_DECIM_PLFRAMES 0xf2250001 - -/*P2_AGC2O*/ -#define R0900_P2_AGC2O 0xf22c -#define F0900_P2_AGC2_COEF 0xf22c0007 - -/*P2_AGC2REF*/ -#define R0900_P2_AGC2REF 0xf22d -#define F0900_P2_AGC2_REF 0xf22d00ff - -/*P2_AGC1ADJ*/ -#define R0900_P2_AGC1ADJ 0xf22e -#define F0900_P2_AGC1_ADJUSTED 0xf22e007f - -/*P2_AGC2I1*/ -#define R0900_P2_AGC2I1 0xf236 -#define F0900_P2_AGC2_INTEGRATOR1 0xf23600ff - -/*P2_AGC2I0*/ -#define R0900_P2_AGC2I0 0xf237 -#define F0900_P2_AGC2_INTEGRATOR0 0xf23700ff - -/*P2_CARCFG*/ -#define R0900_P2_CARCFG 0xf238 -#define F0900_P2_CFRUPLOW_AUTO 0xf2380080 -#define F0900_P2_CFRUPLOW_TEST 0xf2380040 -#define F0900_P2_ROTAON 0xf2380004 -#define F0900_P2_PH_DET_ALGO 0xf2380003 - -/*P2_ACLC*/ -#define R0900_P2_ACLC 0xf239 -#define F0900_P2_CAR_ALPHA_MANT 0xf2390030 -#define F0900_P2_CAR_ALPHA_EXP 0xf239000f - -/*P2_BCLC*/ -#define R0900_P2_BCLC 0xf23a -#define F0900_P2_CAR_BETA_MANT 0xf23a0030 -#define F0900_P2_CAR_BETA_EXP 0xf23a000f - -/*P2_CARFREQ*/ -#define R0900_P2_CARFREQ 0xf23d -#define F0900_P2_KC_COARSE_EXP 0xf23d00f0 -#define F0900_P2_BETA_FREQ 0xf23d000f - -/*P2_CARHDR*/ -#define R0900_P2_CARHDR 0xf23e -#define F0900_P2_K_FREQ_HDR 0xf23e00ff - -/*P2_LDT*/ -#define R0900_P2_LDT 0xf23f -#define F0900_P2_CARLOCK_THRES 0xf23f01ff - -/*P2_LDT2*/ -#define R0900_P2_LDT2 0xf240 -#define F0900_P2_CARLOCK_THRES2 0xf24001ff - -/*P2_CFRICFG*/ -#define R0900_P2_CFRICFG 0xf241 -#define F0900_P2_NEG_CFRSTEP 0xf2410001 - -/*P2_CFRUP1*/ -#define R0900_P2_CFRUP1 0xf242 -#define F0900_P2_CFR_UP1 0xf24201ff - -/*P2_CFRUP0*/ -#define R0900_P2_CFRUP0 0xf243 -#define F0900_P2_CFR_UP0 0xf24300ff - -/*P2_CFRLOW1*/ -#define R0900_P2_CFRLOW1 0xf246 -#define F0900_P2_CFR_LOW1 0xf24601ff - -/*P2_CFRLOW0*/ -#define R0900_P2_CFRLOW0 0xf247 -#define F0900_P2_CFR_LOW0 0xf24700ff - -/*P2_CFRINIT1*/ -#define R0900_P2_CFRINIT1 0xf248 -#define F0900_P2_CFR_INIT1 0xf24801ff - -/*P2_CFRINIT0*/ -#define R0900_P2_CFRINIT0 0xf249 -#define F0900_P2_CFR_INIT0 0xf24900ff - -/*P2_CFRINC1*/ -#define R0900_P2_CFRINC1 0xf24a -#define F0900_P2_MANUAL_CFRINC 0xf24a0080 -#define F0900_P2_CFR_INC1 0xf24a003f - -/*P2_CFRINC0*/ -#define R0900_P2_CFRINC0 0xf24b -#define F0900_P2_CFR_INC0 0xf24b00f8 - -/*P2_CFR2*/ -#define R0900_P2_CFR2 0xf24c -#define F0900_P2_CAR_FREQ2 0xf24c01ff - -/*P2_CFR1*/ -#define R0900_P2_CFR1 0xf24d -#define F0900_P2_CAR_FREQ1 0xf24d00ff - -/*P2_CFR0*/ -#define R0900_P2_CFR0 0xf24e -#define F0900_P2_CAR_FREQ0 0xf24e00ff - -/*P2_LDI*/ -#define R0900_P2_LDI 0xf24f -#define F0900_P2_LOCK_DET_INTEGR 0xf24f01ff - -/*P2_TMGCFG*/ -#define R0900_P2_TMGCFG 0xf250 -#define F0900_P2_TMGLOCK_BETA 0xf25000c0 -#define F0900_P2_DO_TIMING_CORR 0xf2500010 -#define F0900_P2_TMG_MINFREQ 0xf2500003 - -/*P2_RTC*/ -#define R0900_P2_RTC 0xf251 -#define F0900_P2_TMGALPHA_EXP 0xf25100f0 -#define F0900_P2_TMGBETA_EXP 0xf251000f - -/*P2_RTCS2*/ -#define R0900_P2_RTCS2 0xf252 -#define F0900_P2_TMGALPHAS2_EXP 0xf25200f0 -#define F0900_P2_TMGBETAS2_EXP 0xf252000f - -/*P2_TMGTHRISE*/ -#define R0900_P2_TMGTHRISE 0xf253 -#define F0900_P2_TMGLOCK_THRISE 0xf25300ff - -/*P2_TMGTHFALL*/ -#define R0900_P2_TMGTHFALL 0xf254 -#define F0900_P2_TMGLOCK_THFALL 0xf25400ff - -/*P2_SFRUPRATIO*/ -#define R0900_P2_SFRUPRATIO 0xf255 -#define F0900_P2_SFR_UPRATIO 0xf25500ff - -/*P2_SFRLOWRATIO*/ -#define R0900_P2_SFRLOWRATIO 0xf256 -#define F0900_P2_SFR_LOWRATIO 0xf25600ff - -/*P2_KREFTMG*/ -#define R0900_P2_KREFTMG 0xf258 -#define F0900_P2_KREF_TMG 0xf25800ff - -/*P2_SFRSTEP*/ -#define R0900_P2_SFRSTEP 0xf259 -#define F0900_P2_SFR_SCANSTEP 0xf25900f0 -#define F0900_P2_SFR_CENTERSTEP 0xf259000f - -/*P2_TMGCFG2*/ -#define R0900_P2_TMGCFG2 0xf25a -#define F0900_P2_SFRRATIO_FINE 0xf25a0001 - -/*P2_KREFTMG2*/ -#define R0900_P2_KREFTMG2 0xf25b -#define F0900_P2_KREF_TMG2 0xf25b00ff - -/*P2_SFRINIT1*/ -#define R0900_P2_SFRINIT1 0xf25e -#define F0900_P2_SFR_INIT1 0xf25e007f - -/*P2_SFRINIT0*/ -#define R0900_P2_SFRINIT0 0xf25f -#define F0900_P2_SFR_INIT0 0xf25f00ff - -/*P2_SFRUP1*/ -#define R0900_P2_SFRUP1 0xf260 -#define F0900_P2_AUTO_GUP 0xf2600080 -#define F0900_P2_SYMB_FREQ_UP1 0xf260007f - -/*P2_SFRUP0*/ -#define R0900_P2_SFRUP0 0xf261 -#define F0900_P2_SYMB_FREQ_UP0 0xf26100ff - -/*P2_SFRLOW1*/ -#define R0900_P2_SFRLOW1 0xf262 -#define F0900_P2_AUTO_GLOW 0xf2620080 -#define F0900_P2_SYMB_FREQ_LOW1 0xf262007f - -/*P2_SFRLOW0*/ -#define R0900_P2_SFRLOW0 0xf263 -#define F0900_P2_SYMB_FREQ_LOW0 0xf26300ff - -/*P2_SFR3*/ -#define R0900_P2_SFR3 0xf264 -#define F0900_P2_SYMB_FREQ3 0xf26400ff - -/*P2_SFR2*/ -#define R0900_P2_SFR2 0xf265 -#define F0900_P2_SYMB_FREQ2 0xf26500ff - -/*P2_SFR1*/ -#define R0900_P2_SFR1 0xf266 -#define F0900_P2_SYMB_FREQ1 0xf26600ff - -/*P2_SFR0*/ -#define R0900_P2_SFR0 0xf267 -#define F0900_P2_SYMB_FREQ0 0xf26700ff - -/*P2_TMGREG2*/ -#define R0900_P2_TMGREG2 0xf268 -#define F0900_P2_TMGREG2 0xf26800ff - -/*P2_TMGREG1*/ -#define R0900_P2_TMGREG1 0xf269 -#define F0900_P2_TMGREG1 0xf26900ff - -/*P2_TMGREG0*/ -#define R0900_P2_TMGREG0 0xf26a -#define F0900_P2_TMGREG0 0xf26a00ff - -/*P2_TMGLOCK1*/ -#define R0900_P2_TMGLOCK1 0xf26b -#define F0900_P2_TMGLOCK_LEVEL1 0xf26b01ff - -/*P2_TMGLOCK0*/ -#define R0900_P2_TMGLOCK0 0xf26c -#define F0900_P2_TMGLOCK_LEVEL0 0xf26c00ff - -/*P2_TMGOBS*/ -#define R0900_P2_TMGOBS 0xf26d -#define F0900_P2_ROLLOFF_STATUS 0xf26d00c0 - -/*P2_EQUALCFG*/ -#define R0900_P2_EQUALCFG 0xf26f -#define F0900_P2_EQUAL_ON 0xf26f0040 -#define F0900_P2_MU_EQUALDFE 0xf26f0007 - -/*P2_EQUAI1*/ -#define R0900_P2_EQUAI1 0xf270 -#define F0900_P2_EQUA_ACCI1 0xf27001ff - -/*P2_EQUAQ1*/ -#define R0900_P2_EQUAQ1 0xf271 -#define F0900_P2_EQUA_ACCQ1 0xf27101ff - -/*P2_EQUAI2*/ -#define R0900_P2_EQUAI2 0xf272 -#define F0900_P2_EQUA_ACCI2 0xf27201ff - -/*P2_EQUAQ2*/ -#define R0900_P2_EQUAQ2 0xf273 -#define F0900_P2_EQUA_ACCQ2 0xf27301ff - -/*P2_EQUAI3*/ -#define R0900_P2_EQUAI3 0xf274 -#define F0900_P2_EQUA_ACCI3 0xf27401ff - -/*P2_EQUAQ3*/ -#define R0900_P2_EQUAQ3 0xf275 -#define F0900_P2_EQUA_ACCQ3 0xf27501ff - -/*P2_EQUAI4*/ -#define R0900_P2_EQUAI4 0xf276 -#define F0900_P2_EQUA_ACCI4 0xf27601ff - -/*P2_EQUAQ4*/ -#define R0900_P2_EQUAQ4 0xf277 -#define F0900_P2_EQUA_ACCQ4 0xf27701ff - -/*P2_EQUAI5*/ -#define R0900_P2_EQUAI5 0xf278 -#define F0900_P2_EQUA_ACCI5 0xf27801ff - -/*P2_EQUAQ5*/ -#define R0900_P2_EQUAQ5 0xf279 -#define F0900_P2_EQUA_ACCQ5 0xf27901ff - -/*P2_EQUAI6*/ -#define R0900_P2_EQUAI6 0xf27a -#define F0900_P2_EQUA_ACCI6 0xf27a01ff - -/*P2_EQUAQ6*/ -#define R0900_P2_EQUAQ6 0xf27b -#define F0900_P2_EQUA_ACCQ6 0xf27b01ff - -/*P2_EQUAI7*/ -#define R0900_P2_EQUAI7 0xf27c -#define F0900_P2_EQUA_ACCI7 0xf27c01ff - -/*P2_EQUAQ7*/ -#define R0900_P2_EQUAQ7 0xf27d -#define F0900_P2_EQUA_ACCQ7 0xf27d01ff - -/*P2_EQUAI8*/ -#define R0900_P2_EQUAI8 0xf27e -#define F0900_P2_EQUA_ACCI8 0xf27e01ff - -/*P2_EQUAQ8*/ -#define R0900_P2_EQUAQ8 0xf27f -#define F0900_P2_EQUA_ACCQ8 0xf27f01ff - -/*P2_NNOSDATAT1*/ -#define R0900_P2_NNOSDATAT1 0xf280 -#define F0900_P2_NOSDATAT_NORMED1 0xf28000ff - -/*P2_NNOSDATAT0*/ -#define R0900_P2_NNOSDATAT0 0xf281 -#define F0900_P2_NOSDATAT_NORMED0 0xf28100ff - -/*P2_NNOSDATA1*/ -#define R0900_P2_NNOSDATA1 0xf282 -#define F0900_P2_NOSDATA_NORMED1 0xf28200ff - -/*P2_NNOSDATA0*/ -#define R0900_P2_NNOSDATA0 0xf283 -#define F0900_P2_NOSDATA_NORMED0 0xf28300ff - -/*P2_NNOSPLHT1*/ -#define R0900_P2_NNOSPLHT1 0xf284 -#define F0900_P2_NOSPLHT_NORMED1 0xf28400ff - -/*P2_NNOSPLHT0*/ -#define R0900_P2_NNOSPLHT0 0xf285 -#define F0900_P2_NOSPLHT_NORMED0 0xf28500ff - -/*P2_NNOSPLH1*/ -#define R0900_P2_NNOSPLH1 0xf286 -#define F0900_P2_NOSPLH_NORMED1 0xf28600ff - -/*P2_NNOSPLH0*/ -#define R0900_P2_NNOSPLH0 0xf287 -#define F0900_P2_NOSPLH_NORMED0 0xf28700ff - -/*P2_NOSDATAT1*/ -#define R0900_P2_NOSDATAT1 0xf288 -#define F0900_P2_NOSDATAT_UNNORMED1 0xf28800ff - -/*P2_NOSDATAT0*/ -#define R0900_P2_NOSDATAT0 0xf289 -#define F0900_P2_NOSDATAT_UNNORMED0 0xf28900ff - -/*P2_NOSDATA1*/ -#define R0900_P2_NOSDATA1 0xf28a -#define F0900_P2_NOSDATA_UNNORMED1 0xf28a00ff - -/*P2_NOSDATA0*/ -#define R0900_P2_NOSDATA0 0xf28b -#define F0900_P2_NOSDATA_UNNORMED0 0xf28b00ff - -/*P2_NOSPLHT1*/ -#define R0900_P2_NOSPLHT1 0xf28c -#define F0900_P2_NOSPLHT_UNNORMED1 0xf28c00ff - -/*P2_NOSPLHT0*/ -#define R0900_P2_NOSPLHT0 0xf28d -#define F0900_P2_NOSPLHT_UNNORMED0 0xf28d00ff - -/*P2_NOSPLH1*/ -#define R0900_P2_NOSPLH1 0xf28e -#define F0900_P2_NOSPLH_UNNORMED1 0xf28e00ff - -/*P2_NOSPLH0*/ -#define R0900_P2_NOSPLH0 0xf28f -#define F0900_P2_NOSPLH_UNNORMED0 0xf28f00ff - -/*P2_CAR2CFG*/ -#define R0900_P2_CAR2CFG 0xf290 -#define F0900_P2_CARRIER3_DISABLE 0xf2900040 -#define F0900_P2_ROTA2ON 0xf2900004 -#define F0900_P2_PH_DET_ALGO2 0xf2900003 - -/*P2_CFR2CFR1*/ -#define R0900_P2_CFR2CFR1 0xf291 -#define F0900_P2_CFR2TOCFR1_DVBS1 0xf29100c0 -#define F0900_P2_EN_S2CAR2CENTER 0xf2910020 -#define F0900_P2_DIS_BCHERRCFR2 0xf2910010 -#define F0900_P2_CFR2TOCFR1_BETA 0xf2910007 - -/*P2_CFR22*/ -#define R0900_P2_CFR22 0xf293 -#define F0900_P2_CAR2_FREQ2 0xf29301ff - -/*P2_CFR21*/ -#define R0900_P2_CFR21 0xf294 -#define F0900_P2_CAR2_FREQ1 0xf29400ff - -/*P2_CFR20*/ -#define R0900_P2_CFR20 0xf295 -#define F0900_P2_CAR2_FREQ0 0xf29500ff - -/*P2_ACLC2S2Q*/ -#define R0900_P2_ACLC2S2Q 0xf297 -#define F0900_P2_ENAB_SPSKSYMB 0xf2970080 -#define F0900_P2_CAR2S2_Q_ALPH_M 0xf2970030 -#define F0900_P2_CAR2S2_Q_ALPH_E 0xf297000f - -/*P2_ACLC2S28*/ -#define R0900_P2_ACLC2S28 0xf298 -#define F0900_P2_OLDI3Q_MODE 0xf2980080 -#define F0900_P2_CAR2S2_8_ALPH_M 0xf2980030 -#define F0900_P2_CAR2S2_8_ALPH_E 0xf298000f - -/*P2_ACLC2S216A*/ -#define R0900_P2_ACLC2S216A 0xf299 -#define F0900_P2_DIS_C3STOPA2 0xf2990080 -#define F0900_P2_CAR2S2_16ADERAT 0xf2990040 -#define F0900_P2_CAR2S2_16A_ALPH_M 0xf2990030 -#define F0900_P2_CAR2S2_16A_ALPH_E 0xf299000f - -/*P2_ACLC2S232A*/ -#define R0900_P2_ACLC2S232A 0xf29a -#define F0900_P2_CAR2S2_32ADERAT 0xf29a0040 -#define F0900_P2_CAR2S2_32A_ALPH_M 0xf29a0030 -#define F0900_P2_CAR2S2_32A_ALPH_E 0xf29a000f - -/*P2_BCLC2S2Q*/ -#define R0900_P2_BCLC2S2Q 0xf29c -#define F0900_P2_CAR2S2_Q_BETA_M 0xf29c0030 -#define F0900_P2_CAR2S2_Q_BETA_E 0xf29c000f - -/*P2_BCLC2S28*/ -#define R0900_P2_BCLC2S28 0xf29d -#define F0900_P2_CAR2S2_8_BETA_M 0xf29d0030 -#define F0900_P2_CAR2S2_8_BETA_E 0xf29d000f - -/*P2_BCLC2S216A*/ -#define R0900_P2_BCLC2S216A 0xf29e - -/*P2_BCLC2S232A*/ -#define R0900_P2_BCLC2S232A 0xf29f - -/*P2_PLROOT2*/ -#define R0900_P2_PLROOT2 0xf2ac -#define F0900_P2_PLSCRAMB_MODE 0xf2ac000c -#define F0900_P2_PLSCRAMB_ROOT2 0xf2ac0003 - -/*P2_PLROOT1*/ -#define R0900_P2_PLROOT1 0xf2ad -#define F0900_P2_PLSCRAMB_ROOT1 0xf2ad00ff - -/*P2_PLROOT0*/ -#define R0900_P2_PLROOT0 0xf2ae -#define F0900_P2_PLSCRAMB_ROOT0 0xf2ae00ff - -/*P2_MODCODLST0*/ -#define R0900_P2_MODCODLST0 0xf2b0 - -/*P2_MODCODLST1*/ -#define R0900_P2_MODCODLST1 0xf2b1 -#define F0900_P2_DIS_MODCOD29 0xf2b100f0 -#define F0900_P2_DIS_32PSK_9_10 0xf2b1000f - -/*P2_MODCODLST2*/ -#define R0900_P2_MODCODLST2 0xf2b2 -#define F0900_P2_DIS_32PSK_8_9 0xf2b200f0 -#define F0900_P2_DIS_32PSK_5_6 0xf2b2000f - -/*P2_MODCODLST3*/ -#define R0900_P2_MODCODLST3 0xf2b3 -#define F0900_P2_DIS_32PSK_4_5 0xf2b300f0 -#define F0900_P2_DIS_32PSK_3_4 0xf2b3000f - -/*P2_MODCODLST4*/ -#define R0900_P2_MODCODLST4 0xf2b4 -#define F0900_P2_DIS_16PSK_9_10 0xf2b400f0 -#define F0900_P2_DIS_16PSK_8_9 0xf2b4000f - -/*P2_MODCODLST5*/ -#define R0900_P2_MODCODLST5 0xf2b5 -#define F0900_P2_DIS_16PSK_5_6 0xf2b500f0 -#define F0900_P2_DIS_16PSK_4_5 0xf2b5000f - -/*P2_MODCODLST6*/ -#define R0900_P2_MODCODLST6 0xf2b6 -#define F0900_P2_DIS_16PSK_3_4 0xf2b600f0 -#define F0900_P2_DIS_16PSK_2_3 0xf2b6000f - -/*P2_MODCODLST7*/ -#define R0900_P2_MODCODLST7 0xf2b7 -#define F0900_P2_DIS_8P_9_10 0xf2b700f0 -#define F0900_P2_DIS_8P_8_9 0xf2b7000f - -/*P2_MODCODLST8*/ -#define R0900_P2_MODCODLST8 0xf2b8 -#define F0900_P2_DIS_8P_5_6 0xf2b800f0 -#define F0900_P2_DIS_8P_3_4 0xf2b8000f - -/*P2_MODCODLST9*/ -#define R0900_P2_MODCODLST9 0xf2b9 -#define F0900_P2_DIS_8P_2_3 0xf2b900f0 -#define F0900_P2_DIS_8P_3_5 0xf2b9000f - -/*P2_MODCODLSTA*/ -#define R0900_P2_MODCODLSTA 0xf2ba -#define F0900_P2_DIS_QP_9_10 0xf2ba00f0 -#define F0900_P2_DIS_QP_8_9 0xf2ba000f - -/*P2_MODCODLSTB*/ -#define R0900_P2_MODCODLSTB 0xf2bb -#define F0900_P2_DIS_QP_5_6 0xf2bb00f0 -#define F0900_P2_DIS_QP_4_5 0xf2bb000f - -/*P2_MODCODLSTC*/ -#define R0900_P2_MODCODLSTC 0xf2bc -#define F0900_P2_DIS_QP_3_4 0xf2bc00f0 -#define F0900_P2_DIS_QP_2_3 0xf2bc000f - -/*P2_MODCODLSTD*/ -#define R0900_P2_MODCODLSTD 0xf2bd -#define F0900_P2_DIS_QP_3_5 0xf2bd00f0 -#define F0900_P2_DIS_QP_1_2 0xf2bd000f - -/*P2_MODCODLSTE*/ -#define R0900_P2_MODCODLSTE 0xf2be -#define F0900_P2_DIS_QP_2_5 0xf2be00f0 -#define F0900_P2_DIS_QP_1_3 0xf2be000f - -/*P2_MODCODLSTF*/ -#define R0900_P2_MODCODLSTF 0xf2bf -#define F0900_P2_DIS_QP_1_4 0xf2bf00f0 - -/*P2_GAUSSR0*/ -#define R0900_P2_GAUSSR0 0xf2c0 -#define F0900_P2_EN_CCIMODE 0xf2c00080 -#define F0900_P2_R0_GAUSSIEN 0xf2c0007f - -/*P2_CCIR0*/ -#define R0900_P2_CCIR0 0xf2c1 -#define F0900_P2_CCIDETECT_PLHONLY 0xf2c10080 -#define F0900_P2_R0_CCI 0xf2c1007f - -/*P2_CCIQUANT*/ -#define R0900_P2_CCIQUANT 0xf2c2 -#define F0900_P2_CCI_BETA 0xf2c200e0 -#define F0900_P2_CCI_QUANT 0xf2c2001f - -/*P2_CCITHRES*/ -#define R0900_P2_CCITHRES 0xf2c3 -#define F0900_P2_CCI_THRESHOLD 0xf2c300ff - -/*P2_CCIACC*/ -#define R0900_P2_CCIACC 0xf2c4 -#define F0900_P2_CCI_VALUE 0xf2c400ff - -/*P2_DMDRESCFG*/ -#define R0900_P2_DMDRESCFG 0xf2c6 -#define F0900_P2_DMDRES_RESET 0xf2c60080 -#define F0900_P2_DMDRES_STRALL 0xf2c60008 -#define F0900_P2_DMDRES_NEWONLY 0xf2c60004 -#define F0900_P2_DMDRES_NOSTORE 0xf2c60002 - -/*P2_DMDRESADR*/ -#define R0900_P2_DMDRESADR 0xf2c7 -#define F0900_P2_DMDRES_VALIDCFR 0xf2c70040 -#define F0900_P2_DMDRES_MEMFULL 0xf2c70030 -#define F0900_P2_DMDRES_RESNBR 0xf2c7000f - -/*P2_DMDRESDATA7*/ -#define R0900_P2_DMDRESDATA7 0xf2c8 -#define F0900_P2_DMDRES_DATA7 0xf2c800ff - -/*P2_DMDRESDATA6*/ -#define R0900_P2_DMDRESDATA6 0xf2c9 -#define F0900_P2_DMDRES_DATA6 0xf2c900ff - -/*P2_DMDRESDATA5*/ -#define R0900_P2_DMDRESDATA5 0xf2ca -#define F0900_P2_DMDRES_DATA5 0xf2ca00ff - -/*P2_DMDRESDATA4*/ -#define R0900_P2_DMDRESDATA4 0xf2cb -#define F0900_P2_DMDRES_DATA4 0xf2cb00ff - -/*P2_DMDRESDATA3*/ -#define R0900_P2_DMDRESDATA3 0xf2cc -#define F0900_P2_DMDRES_DATA3 0xf2cc00ff - -/*P2_DMDRESDATA2*/ -#define R0900_P2_DMDRESDATA2 0xf2cd -#define F0900_P2_DMDRES_DATA2 0xf2cd00ff - -/*P2_DMDRESDATA1*/ -#define R0900_P2_DMDRESDATA1 0xf2ce -#define F0900_P2_DMDRES_DATA1 0xf2ce00ff - -/*P2_DMDRESDATA0*/ -#define R0900_P2_DMDRESDATA0 0xf2cf -#define F0900_P2_DMDRES_DATA0 0xf2cf00ff - -/*P2_FFEI1*/ -#define R0900_P2_FFEI1 0xf2d0 -#define F0900_P2_FFE_ACCI1 0xf2d001ff - -/*P2_FFEQ1*/ -#define R0900_P2_FFEQ1 0xf2d1 -#define F0900_P2_FFE_ACCQ1 0xf2d101ff - -/*P2_FFEI2*/ -#define R0900_P2_FFEI2 0xf2d2 -#define F0900_P2_FFE_ACCI2 0xf2d201ff - -/*P2_FFEQ2*/ -#define R0900_P2_FFEQ2 0xf2d3 -#define F0900_P2_FFE_ACCQ2 0xf2d301ff - -/*P2_FFEI3*/ -#define R0900_P2_FFEI3 0xf2d4 -#define F0900_P2_FFE_ACCI3 0xf2d401ff - -/*P2_FFEQ3*/ -#define R0900_P2_FFEQ3 0xf2d5 -#define F0900_P2_FFE_ACCQ3 0xf2d501ff - -/*P2_FFEI4*/ -#define R0900_P2_FFEI4 0xf2d6 -#define F0900_P2_FFE_ACCI4 0xf2d601ff - -/*P2_FFEQ4*/ -#define R0900_P2_FFEQ4 0xf2d7 -#define F0900_P2_FFE_ACCQ4 0xf2d701ff - -/*P2_FFECFG*/ -#define R0900_P2_FFECFG 0xf2d8 -#define F0900_P2_EQUALFFE_ON 0xf2d80040 -#define F0900_P2_MU_EQUALFFE 0xf2d80007 - -/*P2_TNRCFG*/ -#define R0900_P2_TNRCFG 0xf2e0 -#define F0900_P2_TUN_ACKFAIL 0xf2e00080 -#define F0900_P2_TUN_TYPE 0xf2e00070 -#define F0900_P2_TUN_SECSTOP 0xf2e00008 -#define F0900_P2_TUN_VCOSRCH 0xf2e00004 -#define F0900_P2_TUN_MADDRESS 0xf2e00003 - -/*P2_TNRCFG2*/ -#define R0900_P2_TNRCFG2 0xf2e1 -#define F0900_P2_TUN_IQSWAP 0xf2e10080 -#define F0900_P2_DIS_BWCALC 0xf2e10004 -#define F0900_P2_SHORT_WAITSTATES 0xf2e10002 - -/*P2_TNRXTAL*/ -#define R0900_P2_TNRXTAL 0xf2e4 -#define F0900_P2_TUN_XTALFREQ 0xf2e4001f - -/*P2_TNRSTEPS*/ -#define R0900_P2_TNRSTEPS 0xf2e7 -#define F0900_P2_TUNER_BW0P125 0xf2e70080 -#define F0900_P2_BWINC_OFFSET 0xf2e70170 -#define F0900_P2_SOFTSTEP_RNG 0xf2e70008 -#define F0900_P2_TUN_BWOFFSET 0xf2e70007 - -/*P2_TNRGAIN*/ -#define R0900_P2_TNRGAIN 0xf2e8 -#define F0900_P2_TUN_KDIVEN 0xf2e800c0 -#define F0900_P2_STB6X00_OCK 0xf2e80030 -#define F0900_P2_TUN_GAIN 0xf2e8000f - -/*P2_TNRRF1*/ -#define R0900_P2_TNRRF1 0xf2e9 -#define F0900_P2_TUN_RFFREQ2 0xf2e900ff - -/*P2_TNRRF0*/ -#define R0900_P2_TNRRF0 0xf2ea -#define F0900_P2_TUN_RFFREQ1 0xf2ea00ff - -/*P2_TNRBW*/ -#define R0900_P2_TNRBW 0xf2eb -#define F0900_P2_TUN_RFFREQ0 0xf2eb00c0 -#define F0900_P2_TUN_BW 0xf2eb003f - -/*P2_TNRADJ*/ -#define R0900_P2_TNRADJ 0xf2ec -#define F0900_P2_STB61X0_CALTIME 0xf2ec0040 - -/*P2_TNRCTL2*/ -#define R0900_P2_TNRCTL2 0xf2ed -#define F0900_P2_STB61X0_RCCKOFF 0xf2ed0080 -#define F0900_P2_STB61X0_ICP_SDOFF 0xf2ed0040 -#define F0900_P2_STB61X0_DCLOOPOFF 0xf2ed0020 -#define F0900_P2_STB61X0_REFOUTSEL 0xf2ed0010 -#define F0900_P2_STB61X0_CALOFF 0xf2ed0008 -#define F0900_P2_STB6XX0_LPT_BEN 0xf2ed0004 -#define F0900_P2_STB6XX0_RX_OSCP 0xf2ed0002 -#define F0900_P2_STB6XX0_SYN 0xf2ed0001 - -/*P2_TNRCFG3*/ -#define R0900_P2_TNRCFG3 0xf2ee -#define F0900_P2_TUN_PLLFREQ 0xf2ee001c -#define F0900_P2_TUN_I2CFREQ_MODE 0xf2ee0003 - -/*P2_TNRLAUNCH*/ -#define R0900_P2_TNRLAUNCH 0xf2f0 - -/*P2_TNRLD*/ -#define R0900_P2_TNRLD 0xf2f0 -#define F0900_P2_TUNLD_VCOING 0xf2f00080 -#define F0900_P2_TUN_REG1FAIL 0xf2f00040 -#define F0900_P2_TUN_REG2FAIL 0xf2f00020 -#define F0900_P2_TUN_REG3FAIL 0xf2f00010 -#define F0900_P2_TUN_REG4FAIL 0xf2f00008 -#define F0900_P2_TUN_REG5FAIL 0xf2f00004 -#define F0900_P2_TUN_BWING 0xf2f00002 -#define F0900_P2_TUN_LOCKED 0xf2f00001 - -/*P2_TNROBSL*/ -#define R0900_P2_TNROBSL 0xf2f6 -#define F0900_P2_TUN_I2CABORTED 0xf2f60080 -#define F0900_P2_TUN_LPEN 0xf2f60040 -#define F0900_P2_TUN_FCCK 0xf2f60020 -#define F0900_P2_TUN_I2CLOCKED 0xf2f60010 -#define F0900_P2_TUN_PROGDONE 0xf2f6000c -#define F0900_P2_TUN_RFRESTE1 0xf2f60003 - -/*P2_TNRRESTE*/ -#define R0900_P2_TNRRESTE 0xf2f7 -#define F0900_P2_TUN_RFRESTE0 0xf2f700ff - -/*P2_SMAPCOEF7*/ -#define R0900_P2_SMAPCOEF7 0xf300 -#define F0900_P2_DIS_QSCALE 0xf3000080 -#define F0900_P2_SMAPCOEF_Q_LLR12 0xf300017f - -/*P2_SMAPCOEF6*/ -#define R0900_P2_SMAPCOEF6 0xf301 -#define F0900_P2_ADJ_8PSKLLR1 0xf3010004 -#define F0900_P2_OLD_8PSKLLR1 0xf3010002 -#define F0900_P2_DIS_AB8PSK 0xf3010001 - -/*P2_SMAPCOEF5*/ -#define R0900_P2_SMAPCOEF5 0xf302 -#define F0900_P2_DIS_8SCALE 0xf3020080 -#define F0900_P2_SMAPCOEF_8P_LLR23 0xf302017f - -/*P2_NCO2MAX1*/ -#define R0900_P2_NCO2MAX1 0xf314 -#define F0900_P2_TETA2_MAXVABS1 0xf31400ff - -/*P2_NCO2MAX0*/ -#define R0900_P2_NCO2MAX0 0xf315 -#define F0900_P2_TETA2_MAXVABS0 0xf31500ff - -/*P2_NCO2FR1*/ -#define R0900_P2_NCO2FR1 0xf316 -#define F0900_P2_NCO2FINAL_ANGLE1 0xf31600ff - -/*P2_NCO2FR0*/ -#define R0900_P2_NCO2FR0 0xf317 -#define F0900_P2_NCO2FINAL_ANGLE0 0xf31700ff - -/*P2_CFR2AVRGE1*/ -#define R0900_P2_CFR2AVRGE1 0xf318 -#define F0900_P2_I2C_CFR2AVERAGE1 0xf31800ff - -/*P2_CFR2AVRGE0*/ -#define R0900_P2_CFR2AVRGE0 0xf319 -#define F0900_P2_I2C_CFR2AVERAGE0 0xf31900ff - -/*P2_DMDPLHSTAT*/ -#define R0900_P2_DMDPLHSTAT 0xf320 -#define F0900_P2_PLH_STATISTIC 0xf32000ff - -/*P2_LOCKTIME3*/ -#define R0900_P2_LOCKTIME3 0xf322 -#define F0900_P2_DEMOD_LOCKTIME3 0xf32200ff - -/*P2_LOCKTIME2*/ -#define R0900_P2_LOCKTIME2 0xf323 -#define F0900_P2_DEMOD_LOCKTIME2 0xf32300ff - -/*P2_LOCKTIME1*/ -#define R0900_P2_LOCKTIME1 0xf324 -#define F0900_P2_DEMOD_LOCKTIME1 0xf32400ff - -/*P2_LOCKTIME0*/ -#define R0900_P2_LOCKTIME0 0xf325 -#define F0900_P2_DEMOD_LOCKTIME0 0xf32500ff - -/*P2_VITSCALE*/ -#define R0900_P2_VITSCALE 0xf332 -#define F0900_P2_NVTH_NOSRANGE 0xf3320080 -#define F0900_P2_VERROR_MAXMODE 0xf3320040 -#define F0900_P2_NSLOWSN_LOCKED 0xf3320008 -#define F0900_P2_DIS_RSFLOCK 0xf3320002 - -/*P2_FECM*/ -#define R0900_P2_FECM 0xf333 -#define F0900_P2_DSS_DVB 0xf3330080 -#define F0900_P2_DSS_SRCH 0xf3330010 -#define F0900_P2_SYNCVIT 0xf3330002 -#define F0900_P2_IQINV 0xf3330001 - -/*P2_VTH12*/ -#define R0900_P2_VTH12 0xf334 -#define F0900_P2_VTH12 0xf33400ff - -/*P2_VTH23*/ -#define R0900_P2_VTH23 0xf335 -#define F0900_P2_VTH23 0xf33500ff - -/*P2_VTH34*/ -#define R0900_P2_VTH34 0xf336 -#define F0900_P2_VTH34 0xf33600ff - -/*P2_VTH56*/ -#define R0900_P2_VTH56 0xf337 -#define F0900_P2_VTH56 0xf33700ff - -/*P2_VTH67*/ -#define R0900_P2_VTH67 0xf338 -#define F0900_P2_VTH67 0xf33800ff - -/*P2_VTH78*/ -#define R0900_P2_VTH78 0xf339 -#define F0900_P2_VTH78 0xf33900ff - -/*P2_VITCURPUN*/ -#define R0900_P2_VITCURPUN 0xf33a -#define F0900_P2_VIT_CURPUN 0xf33a001f - -/*P2_VERROR*/ -#define R0900_P2_VERROR 0xf33b -#define F0900_P2_REGERR_VIT 0xf33b00ff - -/*P2_PRVIT*/ -#define R0900_P2_PRVIT 0xf33c -#define F0900_P2_DIS_VTHLOCK 0xf33c0040 -#define F0900_P2_E7_8VIT 0xf33c0020 -#define F0900_P2_E6_7VIT 0xf33c0010 -#define F0900_P2_E5_6VIT 0xf33c0008 -#define F0900_P2_E3_4VIT 0xf33c0004 -#define F0900_P2_E2_3VIT 0xf33c0002 -#define F0900_P2_E1_2VIT 0xf33c0001 - -/*P2_VAVSRVIT*/ -#define R0900_P2_VAVSRVIT 0xf33d -#define F0900_P2_AMVIT 0xf33d0080 -#define F0900_P2_FROZENVIT 0xf33d0040 -#define F0900_P2_SNVIT 0xf33d0030 -#define F0900_P2_TOVVIT 0xf33d000c -#define F0900_P2_HYPVIT 0xf33d0003 - -/*P2_VSTATUSVIT*/ -#define R0900_P2_VSTATUSVIT 0xf33e -#define F0900_P2_PRFVIT 0xf33e0010 -#define F0900_P2_LOCKEDVIT 0xf33e0008 - -/*P2_VTHINUSE*/ -#define R0900_P2_VTHINUSE 0xf33f -#define F0900_P2_VIT_INUSE 0xf33f00ff - -/*P2_KDIV12*/ -#define R0900_P2_KDIV12 0xf340 -#define F0900_P2_K_DIVIDER_12 0xf340007f - -/*P2_KDIV23*/ -#define R0900_P2_KDIV23 0xf341 -#define F0900_P2_K_DIVIDER_23 0xf341007f - -/*P2_KDIV34*/ -#define R0900_P2_KDIV34 0xf342 -#define F0900_P2_K_DIVIDER_34 0xf342007f - -/*P2_KDIV56*/ -#define R0900_P2_KDIV56 0xf343 -#define F0900_P2_K_DIVIDER_56 0xf343007f - -/*P2_KDIV67*/ -#define R0900_P2_KDIV67 0xf344 -#define F0900_P2_K_DIVIDER_67 0xf344007f - -/*P2_KDIV78*/ -#define R0900_P2_KDIV78 0xf345 -#define F0900_P2_K_DIVIDER_78 0xf345007f - -/*P2_PDELCTRL1*/ -#define R0900_P2_PDELCTRL1 0xf350 -#define F0900_P2_INV_MISMASK 0xf3500080 -#define F0900_P2_FILTER_EN 0xf3500020 -#define F0900_P2_EN_MIS00 0xf3500002 -#define F0900_P2_ALGOSWRST 0xf3500001 - -/*P2_PDELCTRL2*/ -#define R0900_P2_PDELCTRL2 0xf351 -#define F0900_P2_RESET_UPKO_COUNT 0xf3510040 -#define F0900_P2_FRAME_MODE 0xf3510002 -#define F0900_P2_NOBCHERRFLG_USE 0xf3510001 - -/*P2_HYSTTHRESH*/ -#define R0900_P2_HYSTTHRESH 0xf354 -#define F0900_P2_UNLCK_THRESH 0xf35400f0 -#define F0900_P2_DELIN_LCK_THRESH 0xf354000f - -/*P2_ISIENTRY*/ -#define R0900_P2_ISIENTRY 0xf35e -#define F0900_P2_ISI_ENTRY 0xf35e00ff - -/*P2_ISIBITENA*/ -#define R0900_P2_ISIBITENA 0xf35f -#define F0900_P2_ISI_BIT_EN 0xf35f00ff - -/*P2_MATSTR1*/ -#define R0900_P2_MATSTR1 0xf360 -#define F0900_P2_MATYPE_CURRENT1 0xf36000ff - -/*P2_MATSTR0*/ -#define R0900_P2_MATSTR0 0xf361 -#define F0900_P2_MATYPE_CURRENT0 0xf36100ff - -/*P2_UPLSTR1*/ -#define R0900_P2_UPLSTR1 0xf362 -#define F0900_P2_UPL_CURRENT1 0xf36200ff - -/*P2_UPLSTR0*/ -#define R0900_P2_UPLSTR0 0xf363 -#define F0900_P2_UPL_CURRENT0 0xf36300ff - -/*P2_DFLSTR1*/ -#define R0900_P2_DFLSTR1 0xf364 -#define F0900_P2_DFL_CURRENT1 0xf36400ff - -/*P2_DFLSTR0*/ -#define R0900_P2_DFLSTR0 0xf365 -#define F0900_P2_DFL_CURRENT0 0xf36500ff - -/*P2_SYNCSTR*/ -#define R0900_P2_SYNCSTR 0xf366 -#define F0900_P2_SYNC_CURRENT 0xf36600ff - -/*P2_SYNCDSTR1*/ -#define R0900_P2_SYNCDSTR1 0xf367 -#define F0900_P2_SYNCD_CURRENT1 0xf36700ff - -/*P2_SYNCDSTR0*/ -#define R0900_P2_SYNCDSTR0 0xf368 -#define F0900_P2_SYNCD_CURRENT0 0xf36800ff - -/*P2_PDELSTATUS1*/ -#define R0900_P2_PDELSTATUS1 0xf369 -#define F0900_P2_PKTDELIN_DELOCK 0xf3690080 -#define F0900_P2_SYNCDUPDFL_BADDFL 0xf3690040 -#define F0900_P2_CONTINUOUS_STREAM 0xf3690020 -#define F0900_P2_UNACCEPTED_STREAM 0xf3690010 -#define F0900_P2_BCH_ERROR_FLAG 0xf3690008 -#define F0900_P2_PKTDELIN_LOCK 0xf3690002 -#define F0900_P2_FIRST_LOCK 0xf3690001 - -/*P2_PDELSTATUS2*/ -#define R0900_P2_PDELSTATUS2 0xf36a -#define F0900_P2_FRAME_MODCOD 0xf36a007c -#define F0900_P2_FRAME_TYPE 0xf36a0003 - -/*P2_BBFCRCKO1*/ -#define R0900_P2_BBFCRCKO1 0xf36b -#define F0900_P2_BBHCRC_KOCNT1 0xf36b00ff - -/*P2_BBFCRCKO0*/ -#define R0900_P2_BBFCRCKO0 0xf36c -#define F0900_P2_BBHCRC_KOCNT0 0xf36c00ff - -/*P2_UPCRCKO1*/ -#define R0900_P2_UPCRCKO1 0xf36d -#define F0900_P2_PKTCRC_KOCNT1 0xf36d00ff - -/*P2_UPCRCKO0*/ -#define R0900_P2_UPCRCKO0 0xf36e -#define F0900_P2_PKTCRC_KOCNT0 0xf36e00ff - -/*P2_PDELCTRL3*/ -#define R0900_P2_PDELCTRL3 0xf36f -#define F0900_P2_PKTDEL_CONTFAIL 0xf36f0080 -#define F0900_P2_NOFIFO_BCHERR 0xf36f0020 - -/*P2_TSSTATEM*/ -#define R0900_P2_TSSTATEM 0xf370 -#define F0900_P2_TSDIL_ON 0xf3700080 -#define F0900_P2_TSRS_ON 0xf3700020 -#define F0900_P2_TSDESCRAMB_ON 0xf3700010 -#define F0900_P2_TSFRAME_MODE 0xf3700008 -#define F0900_P2_TS_DISABLE 0xf3700004 -#define F0900_P2_TSOUT_NOSYNC 0xf3700001 - -/*P2_TSCFGH*/ -#define R0900_P2_TSCFGH 0xf372 -#define F0900_P2_TSFIFO_DVBCI 0xf3720080 -#define F0900_P2_TSFIFO_SERIAL 0xf3720040 -#define F0900_P2_TSFIFO_TEIUPDATE 0xf3720020 -#define F0900_P2_TSFIFO_DUTY50 0xf3720010 -#define F0900_P2_TSFIFO_HSGNLOUT 0xf3720008 -#define F0900_P2_TSFIFO_ERRMODE 0xf3720006 -#define F0900_P2_RST_HWARE 0xf3720001 - -/*P2_TSCFGM*/ -#define R0900_P2_TSCFGM 0xf373 -#define F0900_P2_TSFIFO_MANSPEED 0xf37300c0 -#define F0900_P2_TSFIFO_PERMDATA 0xf3730020 -#define F0900_P2_TSFIFO_DPUNACT 0xf3730002 -#define F0900_P2_TSFIFO_INVDATA 0xf3730001 - -/*P2_TSCFGL*/ -#define R0900_P2_TSCFGL 0xf374 -#define F0900_P2_TSFIFO_BCLKDEL1CK 0xf37400c0 -#define F0900_P2_BCHERROR_MODE 0xf3740030 -#define F0900_P2_TSFIFO_NSGNL2DATA 0xf3740008 -#define F0900_P2_TSFIFO_EMBINDVB 0xf3740004 -#define F0900_P2_TSFIFO_BITSPEED 0xf3740003 - -/*P2_TSINSDELH*/ -#define R0900_P2_TSINSDELH 0xf376 -#define F0900_P2_TSDEL_SYNCBYTE 0xf3760080 -#define F0900_P2_TSDEL_XXHEADER 0xf3760040 -#define F0900_P2_TSDEL_BBHEADER 0xf3760020 -#define F0900_P2_TSDEL_DATAFIELD 0xf3760010 -#define F0900_P2_TSINSDEL_ISCR 0xf3760008 -#define F0900_P2_TSINSDEL_NPD 0xf3760004 -#define F0900_P2_TSINSDEL_RSPARITY 0xf3760002 -#define F0900_P2_TSINSDEL_CRC8 0xf3760001 - -/*P2_TSDIVN*/ -#define R0900_P2_TSDIVN 0xf379 -#define F0900_P2_TSFIFO_SPEEDMODE 0xf37900c0 - -/*P2_TSCFG4*/ -#define R0900_P2_TSCFG4 0xf37a -#define F0900_P2_TSFIFO_TSSPEEDMODE 0xf37a00c0 - -/*P2_TSSPEED*/ -#define R0900_P2_TSSPEED 0xf380 -#define F0900_P2_TSFIFO_OUTSPEED 0xf38000ff - -/*P2_TSSTATUS*/ -#define R0900_P2_TSSTATUS 0xf381 -#define F0900_P2_TSFIFO_LINEOK 0xf3810080 -#define F0900_P2_TSFIFO_ERROR 0xf3810040 -#define F0900_P2_DIL_READY 0xf3810001 - -/*P2_TSSTATUS2*/ -#define R0900_P2_TSSTATUS2 0xf382 -#define F0900_P2_TSFIFO_DEMODSEL 0xf3820080 -#define F0900_P2_TSFIFOSPEED_STORE 0xf3820040 -#define F0900_P2_DILXX_RESET 0xf3820020 -#define F0900_P2_TSSERIAL_IMPOS 0xf3820010 -#define F0900_P2_SCRAMBDETECT 0xf3820002 - -/*P2_TSBITRATE1*/ -#define R0900_P2_TSBITRATE1 0xf383 -#define F0900_P2_TSFIFO_BITRATE1 0xf38300ff - -/*P2_TSBITRATE0*/ -#define R0900_P2_TSBITRATE0 0xf384 -#define F0900_P2_TSFIFO_BITRATE0 0xf38400ff - -/*P2_ERRCTRL1*/ -#define R0900_P2_ERRCTRL1 0xf398 -#define F0900_P2_ERR_SOURCE1 0xf39800f0 -#define F0900_P2_NUM_EVENT1 0xf3980007 - -/*P2_ERRCNT12*/ -#define R0900_P2_ERRCNT12 0xf399 -#define F0900_P2_ERRCNT1_OLDVALUE 0xf3990080 -#define F0900_P2_ERR_CNT12 0xf399007f - -/*P2_ERRCNT11*/ -#define R0900_P2_ERRCNT11 0xf39a -#define F0900_P2_ERR_CNT11 0xf39a00ff - -/*P2_ERRCNT10*/ -#define R0900_P2_ERRCNT10 0xf39b -#define F0900_P2_ERR_CNT10 0xf39b00ff - -/*P2_ERRCTRL2*/ -#define R0900_P2_ERRCTRL2 0xf39c -#define F0900_P2_ERR_SOURCE2 0xf39c00f0 -#define F0900_P2_NUM_EVENT2 0xf39c0007 - -/*P2_ERRCNT22*/ -#define R0900_P2_ERRCNT22 0xf39d -#define F0900_P2_ERRCNT2_OLDVALUE 0xf39d0080 -#define F0900_P2_ERR_CNT22 0xf39d007f - -/*P2_ERRCNT21*/ -#define R0900_P2_ERRCNT21 0xf39e -#define F0900_P2_ERR_CNT21 0xf39e00ff - -/*P2_ERRCNT20*/ -#define R0900_P2_ERRCNT20 0xf39f -#define F0900_P2_ERR_CNT20 0xf39f00ff - -/*P2_FECSPY*/ -#define R0900_P2_FECSPY 0xf3a0 -#define F0900_P2_SPY_ENABLE 0xf3a00080 -#define F0900_P2_NO_SYNCBYTE 0xf3a00040 -#define F0900_P2_SERIAL_MODE 0xf3a00020 -#define F0900_P2_UNUSUAL_PACKET 0xf3a00010 -#define F0900_P2_BERMETER_DATAMODE 0xf3a00008 -#define F0900_P2_BERMETER_LMODE 0xf3a00002 -#define F0900_P2_BERMETER_RESET 0xf3a00001 - -/*P2_FSPYCFG*/ -#define R0900_P2_FSPYCFG 0xf3a1 -#define F0900_P2_FECSPY_INPUT 0xf3a100c0 -#define F0900_P2_RST_ON_ERROR 0xf3a10020 -#define F0900_P2_ONE_SHOT 0xf3a10010 -#define F0900_P2_I2C_MODE 0xf3a1000c -#define F0900_P2_SPY_HYSTERESIS 0xf3a10003 - -/*P2_FSPYDATA*/ -#define R0900_P2_FSPYDATA 0xf3a2 -#define F0900_P2_SPY_STUFFING 0xf3a20080 -#define F0900_P2_SPY_CNULLPKT 0xf3a20020 -#define F0900_P2_SPY_OUTDATA_MODE 0xf3a2001f - -/*P2_FSPYOUT*/ -#define R0900_P2_FSPYOUT 0xf3a3 -#define F0900_P2_FSPY_DIRECT 0xf3a30080 -#define F0900_P2_STUFF_MODE 0xf3a30007 - -/*P2_FSTATUS*/ -#define R0900_P2_FSTATUS 0xf3a4 -#define F0900_P2_SPY_ENDSIM 0xf3a40080 -#define F0900_P2_VALID_SIM 0xf3a40040 -#define F0900_P2_FOUND_SIGNAL 0xf3a40020 -#define F0900_P2_DSS_SYNCBYTE 0xf3a40010 -#define F0900_P2_RESULT_STATE 0xf3a4000f - -/*P2_FBERCPT4*/ -#define R0900_P2_FBERCPT4 0xf3a8 -#define F0900_P2_FBERMETER_CPT4 0xf3a800ff - -/*P2_FBERCPT3*/ -#define R0900_P2_FBERCPT3 0xf3a9 -#define F0900_P2_FBERMETER_CPT3 0xf3a900ff - -/*P2_FBERCPT2*/ -#define R0900_P2_FBERCPT2 0xf3aa -#define F0900_P2_FBERMETER_CPT2 0xf3aa00ff - -/*P2_FBERCPT1*/ -#define R0900_P2_FBERCPT1 0xf3ab -#define F0900_P2_FBERMETER_CPT1 0xf3ab00ff - -/*P2_FBERCPT0*/ -#define R0900_P2_FBERCPT0 0xf3ac -#define F0900_P2_FBERMETER_CPT0 0xf3ac00ff - -/*P2_FBERERR2*/ -#define R0900_P2_FBERERR2 0xf3ad -#define F0900_P2_FBERMETER_ERR2 0xf3ad00ff - -/*P2_FBERERR1*/ -#define R0900_P2_FBERERR1 0xf3ae -#define F0900_P2_FBERMETER_ERR1 0xf3ae00ff - -/*P2_FBERERR0*/ -#define R0900_P2_FBERERR0 0xf3af -#define F0900_P2_FBERMETER_ERR0 0xf3af00ff - -/*P2_FSPYBER*/ -#define R0900_P2_FSPYBER 0xf3b2 -#define F0900_P2_FSPYBER_SYNCBYTE 0xf3b20010 -#define F0900_P2_FSPYBER_UNSYNC 0xf3b20008 -#define F0900_P2_FSPYBER_CTIME 0xf3b20007 - -/*P1_IQCONST*/ -#define R0900_P1_IQCONST 0xf400 -#define IQCONST REGx(R0900_P1_IQCONST) -#define F0900_P1_CONSTEL_SELECT 0xf4000060 -#define F0900_P1_IQSYMB_SEL 0xf400001f - -/*P1_NOSCFG*/ -#define R0900_P1_NOSCFG 0xf401 -#define NOSCFG REGx(R0900_P1_NOSCFG) -#define F0900_P1_DUMMYPL_NOSDATA 0xf4010020 -#define F0900_P1_NOSPLH_BETA 0xf4010018 -#define F0900_P1_NOSDATA_BETA 0xf4010007 - -/*P1_ISYMB*/ -#define R0900_P1_ISYMB 0xf402 -#define ISYMB REGx(R0900_P1_ISYMB) -#define F0900_P1_I_SYMBOL 0xf40201ff - -/*P1_QSYMB*/ -#define R0900_P1_QSYMB 0xf403 -#define QSYMB REGx(R0900_P1_QSYMB) -#define F0900_P1_Q_SYMBOL 0xf40301ff - -/*P1_AGC1CFG*/ -#define R0900_P1_AGC1CFG 0xf404 -#define AGC1CFG REGx(R0900_P1_AGC1CFG) -#define F0900_P1_DC_FROZEN 0xf4040080 -#define F0900_P1_DC_CORRECT 0xf4040040 -#define F0900_P1_AMM_FROZEN 0xf4040020 -#define F0900_P1_AMM_CORRECT 0xf4040010 -#define F0900_P1_QUAD_FROZEN 0xf4040008 -#define F0900_P1_QUAD_CORRECT 0xf4040004 - -/*P1_AGC1CN*/ -#define R0900_P1_AGC1CN 0xf406 -#define AGC1CN REGx(R0900_P1_AGC1CN) -#define F0900_P1_AGC1_LOCKED 0xf4060080 -#define F0900_P1_AGC1_MINPOWER 0xf4060010 -#define F0900_P1_AGCOUT_FAST 0xf4060008 -#define F0900_P1_AGCIQ_BETA 0xf4060007 - -/*P1_AGC1REF*/ -#define R0900_P1_AGC1REF 0xf407 -#define AGC1REF REGx(R0900_P1_AGC1REF) -#define F0900_P1_AGCIQ_REF 0xf40700ff - -/*P1_IDCCOMP*/ -#define R0900_P1_IDCCOMP 0xf408 -#define IDCCOMP REGx(R0900_P1_IDCCOMP) -#define F0900_P1_IAVERAGE_ADJ 0xf40801ff - -/*P1_QDCCOMP*/ -#define R0900_P1_QDCCOMP 0xf409 -#define QDCCOMP REGx(R0900_P1_QDCCOMP) -#define F0900_P1_QAVERAGE_ADJ 0xf40901ff - -/*P1_POWERI*/ -#define R0900_P1_POWERI 0xf40a -#define POWERI REGx(R0900_P1_POWERI) -#define F0900_P1_POWER_I 0xf40a00ff -#define POWER_I FLDx(F0900_P1_POWER_I) - -/*P1_POWERQ*/ -#define R0900_P1_POWERQ 0xf40b -#define POWERQ REGx(R0900_P1_POWERQ) -#define F0900_P1_POWER_Q 0xf40b00ff -#define POWER_Q FLDx(F0900_P1_POWER_Q) - -/*P1_AGC1AMM*/ -#define R0900_P1_AGC1AMM 0xf40c -#define AGC1AMM REGx(R0900_P1_AGC1AMM) -#define F0900_P1_AMM_VALUE 0xf40c00ff - -/*P1_AGC1QUAD*/ -#define R0900_P1_AGC1QUAD 0xf40d -#define AGC1QUAD REGx(R0900_P1_AGC1QUAD) -#define F0900_P1_QUAD_VALUE 0xf40d01ff - -/*P1_AGCIQIN1*/ -#define R0900_P1_AGCIQIN1 0xf40e -#define AGCIQIN1 REGx(R0900_P1_AGCIQIN1) -#define F0900_P1_AGCIQ_VALUE1 0xf40e00ff -#define AGCIQ_VALUE1 FLDx(F0900_P1_AGCIQ_VALUE1) - -/*P1_AGCIQIN0*/ -#define R0900_P1_AGCIQIN0 0xf40f -#define AGCIQIN0 REGx(R0900_P1_AGCIQIN0) -#define F0900_P1_AGCIQ_VALUE0 0xf40f00ff -#define AGCIQ_VALUE0 FLDx(F0900_P1_AGCIQ_VALUE0) - -/*P1_DEMOD*/ -#define R0900_P1_DEMOD 0xf410 -#define DEMOD REGx(R0900_P1_DEMOD) -#define F0900_P1_MANUALS2_ROLLOFF 0xf4100080 -#define MANUALS2_ROLLOFF FLDx(F0900_P1_MANUALS2_ROLLOFF) - -#define F0900_P1_SPECINV_CONTROL 0xf4100030 -#define SPECINV_CONTROL FLDx(F0900_P1_SPECINV_CONTROL) -#define F0900_P1_FORCE_ENASAMP 0xf4100008 -#define F0900_P1_MANUALSX_ROLLOFF 0xf4100004 -#define MANUALSX_ROLLOFF FLDx(F0900_P1_MANUALSX_ROLLOFF) -#define F0900_P1_ROLLOFF_CONTROL 0xf4100003 -#define ROLLOFF_CONTROL FLDx(F0900_P1_ROLLOFF_CONTROL) - -/*P1_DMDMODCOD*/ -#define R0900_P1_DMDMODCOD 0xf411 -#define DMDMODCOD REGx(R0900_P1_DMDMODCOD) -#define F0900_P1_MANUAL_MODCOD 0xf4110080 -#define F0900_P1_DEMOD_MODCOD 0xf411007c -#define DEMOD_MODCOD FLDx(F0900_P1_DEMOD_MODCOD) -#define F0900_P1_DEMOD_TYPE 0xf4110003 -#define DEMOD_TYPE FLDx(F0900_P1_DEMOD_TYPE) - -/*P1_DSTATUS*/ -#define R0900_P1_DSTATUS 0xf412 -#define DSTATUS REGx(R0900_P1_DSTATUS) -#define F0900_P1_CAR_LOCK 0xf4120080 -#define F0900_P1_TMGLOCK_QUALITY 0xf4120060 -#define TMGLOCK_QUALITY FLDx(F0900_P1_TMGLOCK_QUALITY) -#define F0900_P1_LOCK_DEFINITIF 0xf4120008 -#define LOCK_DEFINITIF FLDx(F0900_P1_LOCK_DEFINITIF) -#define F0900_P1_OVADC_DETECT 0xf4120001 - -/*P1_DSTATUS2*/ -#define R0900_P1_DSTATUS2 0xf413 -#define DSTATUS2 REGx(R0900_P1_DSTATUS2) -#define F0900_P1_DEMOD_DELOCK 0xf4130080 -#define F0900_P1_AGC1_NOSIGNALACK 0xf4130008 -#define F0900_P1_AGC2_OVERFLOW 0xf4130004 -#define F0900_P1_CFR_OVERFLOW 0xf4130002 -#define F0900_P1_GAMMA_OVERUNDER 0xf4130001 - -/*P1_DMDCFGMD*/ -#define R0900_P1_DMDCFGMD 0xf414 -#define DMDCFGMD REGx(R0900_P1_DMDCFGMD) -#define F0900_P1_DVBS2_ENABLE 0xf4140080 -#define DVBS2_ENABLE FLDx(F0900_P1_DVBS2_ENABLE) -#define F0900_P1_DVBS1_ENABLE 0xf4140040 -#define DVBS1_ENABLE FLDx(F0900_P1_DVBS1_ENABLE) -#define F0900_P1_SCAN_ENABLE 0xf4140010 -#define SCAN_ENABLE FLDx(F0900_P1_SCAN_ENABLE) -#define F0900_P1_CFR_AUTOSCAN 0xf4140008 -#define CFR_AUTOSCAN FLDx(F0900_P1_CFR_AUTOSCAN) -#define F0900_P1_TUN_RNG 0xf4140003 - -/*P1_DMDCFG2*/ -#define R0900_P1_DMDCFG2 0xf415 -#define DMDCFG2 REGx(R0900_P1_DMDCFG2) -#define F0900_P1_S1S2_SEQUENTIAL 0xf4150040 -#define S1S2_SEQUENTIAL FLDx(F0900_P1_S1S2_SEQUENTIAL) -#define F0900_P1_INFINITE_RELOCK 0xf4150010 - -/*P1_DMDISTATE*/ -#define R0900_P1_DMDISTATE 0xf416 -#define DMDISTATE REGx(R0900_P1_DMDISTATE) -#define F0900_P1_I2C_DEMOD_MODE 0xf416001f -#define DEMOD_MODE FLDx(F0900_P1_I2C_DEMOD_MODE) - -/*P1_DMDT0M*/ -#define R0900_P1_DMDT0M 0xf417 -#define DMDT0M REGx(R0900_P1_DMDT0M) -#define F0900_P1_DMDT0_MIN 0xf41700ff - -/*P1_DMDSTATE*/ -#define R0900_P1_DMDSTATE 0xf41b -#define DMDSTATE REGx(R0900_P1_DMDSTATE) -#define F0900_P1_HEADER_MODE 0xf41b0060 -#define HEADER_MODE FLDx(F0900_P1_HEADER_MODE) - -/*P1_DMDFLYW*/ -#define R0900_P1_DMDFLYW 0xf41c -#define DMDFLYW REGx(R0900_P1_DMDFLYW) -#define F0900_P1_I2C_IRQVAL 0xf41c00f0 -#define F0900_P1_FLYWHEEL_CPT 0xf41c000f -#define FLYWHEEL_CPT FLDx(F0900_P1_FLYWHEEL_CPT) - -/*P1_DSTATUS3*/ -#define R0900_P1_DSTATUS3 0xf41d -#define DSTATUS3 REGx(R0900_P1_DSTATUS3) -#define F0900_P1_DEMOD_CFGMODE 0xf41d0060 - -/*P1_DMDCFG3*/ -#define R0900_P1_DMDCFG3 0xf41e -#define DMDCFG3 REGx(R0900_P1_DMDCFG3) -#define F0900_P1_NOSTOP_FIFOFULL 0xf41e0008 - -/*P1_DMDCFG4*/ -#define R0900_P1_DMDCFG4 0xf41f -#define DMDCFG4 REGx(R0900_P1_DMDCFG4) -#define F0900_P1_TUNER_NRELAUNCH 0xf41f0008 - -/*P1_CORRELMANT*/ -#define R0900_P1_CORRELMANT 0xf420 -#define CORRELMANT REGx(R0900_P1_CORRELMANT) -#define F0900_P1_CORREL_MANT 0xf42000ff - -/*P1_CORRELABS*/ -#define R0900_P1_CORRELABS 0xf421 -#define CORRELABS REGx(R0900_P1_CORRELABS) -#define F0900_P1_CORREL_ABS 0xf42100ff - -/*P1_CORRELEXP*/ -#define R0900_P1_CORRELEXP 0xf422 -#define CORRELEXP REGx(R0900_P1_CORRELEXP) -#define F0900_P1_CORREL_ABSEXP 0xf42200f0 -#define F0900_P1_CORREL_EXP 0xf422000f - -/*P1_PLHMODCOD*/ -#define R0900_P1_PLHMODCOD 0xf424 -#define PLHMODCOD REGx(R0900_P1_PLHMODCOD) -#define F0900_P1_SPECINV_DEMOD 0xf4240080 -#define SPECINV_DEMOD FLDx(F0900_P1_SPECINV_DEMOD) -#define F0900_P1_PLH_MODCOD 0xf424007c -#define F0900_P1_PLH_TYPE 0xf4240003 - -/*P1_DMDREG*/ -#define R0900_P1_DMDREG 0xf425 -#define DMDREG REGx(R0900_P1_DMDREG) -#define F0900_P1_DECIM_PLFRAMES 0xf4250001 - -/*P1_AGC2O*/ -#define R0900_P1_AGC2O 0xf42c -#define AGC2O REGx(R0900_P1_AGC2O) -#define F0900_P1_AGC2_COEF 0xf42c0007 - -/*P1_AGC2REF*/ -#define R0900_P1_AGC2REF 0xf42d -#define AGC2REF REGx(R0900_P1_AGC2REF) -#define F0900_P1_AGC2_REF 0xf42d00ff - -/*P1_AGC1ADJ*/ -#define R0900_P1_AGC1ADJ 0xf42e -#define AGC1ADJ REGx(R0900_P1_AGC1ADJ) -#define F0900_P1_AGC1_ADJUSTED 0xf42e007f - -/*P1_AGC2I1*/ -#define R0900_P1_AGC2I1 0xf436 -#define AGC2I1 REGx(R0900_P1_AGC2I1) -#define F0900_P1_AGC2_INTEGRATOR1 0xf43600ff - -/*P1_AGC2I0*/ -#define R0900_P1_AGC2I0 0xf437 -#define AGC2I0 REGx(R0900_P1_AGC2I0) -#define F0900_P1_AGC2_INTEGRATOR0 0xf43700ff - -/*P1_CARCFG*/ -#define R0900_P1_CARCFG 0xf438 -#define CARCFG REGx(R0900_P1_CARCFG) -#define F0900_P1_CFRUPLOW_AUTO 0xf4380080 -#define F0900_P1_CFRUPLOW_TEST 0xf4380040 -#define F0900_P1_ROTAON 0xf4380004 -#define F0900_P1_PH_DET_ALGO 0xf4380003 - -/*P1_ACLC*/ -#define R0900_P1_ACLC 0xf439 -#define ACLC REGx(R0900_P1_ACLC) -#define F0900_P1_CAR_ALPHA_MANT 0xf4390030 -#define F0900_P1_CAR_ALPHA_EXP 0xf439000f - -/*P1_BCLC*/ -#define R0900_P1_BCLC 0xf43a -#define BCLC REGx(R0900_P1_BCLC) -#define F0900_P1_CAR_BETA_MANT 0xf43a0030 -#define F0900_P1_CAR_BETA_EXP 0xf43a000f - -/*P1_CARFREQ*/ -#define R0900_P1_CARFREQ 0xf43d -#define CARFREQ REGx(R0900_P1_CARFREQ) -#define F0900_P1_KC_COARSE_EXP 0xf43d00f0 -#define F0900_P1_BETA_FREQ 0xf43d000f - -/*P1_CARHDR*/ -#define R0900_P1_CARHDR 0xf43e -#define CARHDR REGx(R0900_P1_CARHDR) -#define F0900_P1_K_FREQ_HDR 0xf43e00ff - -/*P1_LDT*/ -#define R0900_P1_LDT 0xf43f -#define LDT REGx(R0900_P1_LDT) -#define F0900_P1_CARLOCK_THRES 0xf43f01ff - -/*P1_LDT2*/ -#define R0900_P1_LDT2 0xf440 -#define LDT2 REGx(R0900_P1_LDT2) -#define F0900_P1_CARLOCK_THRES2 0xf44001ff - -/*P1_CFRICFG*/ -#define R0900_P1_CFRICFG 0xf441 -#define CFRICFG REGx(R0900_P1_CFRICFG) -#define F0900_P1_NEG_CFRSTEP 0xf4410001 - -/*P1_CFRUP1*/ -#define R0900_P1_CFRUP1 0xf442 -#define CFRUP1 REGx(R0900_P1_CFRUP1) -#define F0900_P1_CFR_UP1 0xf44201ff -#define CFR_UP1 FLDx(F0900_P1_CFR_UP1) - -/*P1_CFRUP0*/ -#define R0900_P1_CFRUP0 0xf443 -#define CFRUP0 REGx(R0900_P1_CFRUP0) -#define F0900_P1_CFR_UP0 0xf44300ff -#define CFR_UP0 FLDx(F0900_P1_CFR_UP0) - -/*P1_CFRLOW1*/ -#define R0900_P1_CFRLOW1 0xf446 -#define CFRLOW1 REGx(R0900_P1_CFRLOW1) -#define F0900_P1_CFR_LOW1 0xf44601ff -#define CFR_LOW1 FLDx(F0900_P1_CFR_LOW1) - -/*P1_CFRLOW0*/ -#define R0900_P1_CFRLOW0 0xf447 -#define CFRLOW0 REGx(R0900_P1_CFRLOW0) -#define F0900_P1_CFR_LOW0 0xf44700ff -#define CFR_LOW0 FLDx(F0900_P1_CFR_LOW0) - -/*P1_CFRINIT1*/ -#define R0900_P1_CFRINIT1 0xf448 -#define CFRINIT1 REGx(R0900_P1_CFRINIT1) -#define F0900_P1_CFR_INIT1 0xf44801ff -#define CFR_INIT1 FLDx(F0900_P1_CFR_INIT1) - -/*P1_CFRINIT0*/ -#define R0900_P1_CFRINIT0 0xf449 -#define CFRINIT0 REGx(R0900_P1_CFRINIT0) -#define F0900_P1_CFR_INIT0 0xf44900ff -#define CFR_INIT0 FLDx(F0900_P1_CFR_INIT0) - -/*P1_CFRINC1*/ -#define R0900_P1_CFRINC1 0xf44a -#define CFRINC1 REGx(R0900_P1_CFRINC1) -#define F0900_P1_MANUAL_CFRINC 0xf44a0080 -#define F0900_P1_CFR_INC1 0xf44a003f - -/*P1_CFRINC0*/ -#define R0900_P1_CFRINC0 0xf44b -#define CFRINC0 REGx(R0900_P1_CFRINC0) -#define F0900_P1_CFR_INC0 0xf44b00f8 - -/*P1_CFR2*/ -#define R0900_P1_CFR2 0xf44c -#define CFR2 REGx(R0900_P1_CFR2) -#define F0900_P1_CAR_FREQ2 0xf44c01ff -#define CAR_FREQ2 FLDx(F0900_P1_CAR_FREQ2) - -/*P1_CFR1*/ -#define R0900_P1_CFR1 0xf44d -#define CFR1 REGx(R0900_P1_CFR1) -#define F0900_P1_CAR_FREQ1 0xf44d00ff -#define CAR_FREQ1 FLDx(F0900_P1_CAR_FREQ1) - -/*P1_CFR0*/ -#define R0900_P1_CFR0 0xf44e -#define CFR0 REGx(R0900_P1_CFR0) -#define F0900_P1_CAR_FREQ0 0xf44e00ff -#define CAR_FREQ0 FLDx(F0900_P1_CAR_FREQ0) - -/*P1_LDI*/ -#define R0900_P1_LDI 0xf44f -#define LDI REGx(R0900_P1_LDI) -#define F0900_P1_LOCK_DET_INTEGR 0xf44f01ff - -/*P1_TMGCFG*/ -#define R0900_P1_TMGCFG 0xf450 -#define TMGCFG REGx(R0900_P1_TMGCFG) -#define F0900_P1_TMGLOCK_BETA 0xf45000c0 -#define F0900_P1_DO_TIMING_CORR 0xf4500010 -#define F0900_P1_TMG_MINFREQ 0xf4500003 - -/*P1_RTC*/ -#define R0900_P1_RTC 0xf451 -#define RTC REGx(R0900_P1_RTC) -#define F0900_P1_TMGALPHA_EXP 0xf45100f0 -#define F0900_P1_TMGBETA_EXP 0xf451000f - -/*P1_RTCS2*/ -#define R0900_P1_RTCS2 0xf452 -#define RTCS2 REGx(R0900_P1_RTCS2) -#define F0900_P1_TMGALPHAS2_EXP 0xf45200f0 -#define F0900_P1_TMGBETAS2_EXP 0xf452000f - -/*P1_TMGTHRISE*/ -#define R0900_P1_TMGTHRISE 0xf453 -#define TMGTHRISE REGx(R0900_P1_TMGTHRISE) -#define F0900_P1_TMGLOCK_THRISE 0xf45300ff - -/*P1_TMGTHFALL*/ -#define R0900_P1_TMGTHFALL 0xf454 -#define TMGTHFALL REGx(R0900_P1_TMGTHFALL) -#define F0900_P1_TMGLOCK_THFALL 0xf45400ff - -/*P1_SFRUPRATIO*/ -#define R0900_P1_SFRUPRATIO 0xf455 -#define SFRUPRATIO REGx(R0900_P1_SFRUPRATIO) -#define F0900_P1_SFR_UPRATIO 0xf45500ff - -/*P1_SFRLOWRATIO*/ -#define R0900_P1_SFRLOWRATIO 0xf456 -#define F0900_P1_SFR_LOWRATIO 0xf45600ff - -/*P1_KREFTMG*/ -#define R0900_P1_KREFTMG 0xf458 -#define KREFTMG REGx(R0900_P1_KREFTMG) -#define F0900_P1_KREF_TMG 0xf45800ff - -/*P1_SFRSTEP*/ -#define R0900_P1_SFRSTEP 0xf459 -#define SFRSTEP REGx(R0900_P1_SFRSTEP) -#define F0900_P1_SFR_SCANSTEP 0xf45900f0 -#define F0900_P1_SFR_CENTERSTEP 0xf459000f - -/*P1_TMGCFG2*/ -#define R0900_P1_TMGCFG2 0xf45a -#define TMGCFG2 REGx(R0900_P1_TMGCFG2) -#define F0900_P1_SFRRATIO_FINE 0xf45a0001 - -/*P1_KREFTMG2*/ -#define R0900_P1_KREFTMG2 0xf45b -#define KREFTMG2 REGx(R0900_P1_KREFTMG2) -#define F0900_P1_KREF_TMG2 0xf45b00ff - -/*P1_SFRINIT1*/ -#define R0900_P1_SFRINIT1 0xf45e -#define SFRINIT1 REGx(R0900_P1_SFRINIT1) -#define F0900_P1_SFR_INIT1 0xf45e007f - -/*P1_SFRINIT0*/ -#define R0900_P1_SFRINIT0 0xf45f -#define SFRINIT0 REGx(R0900_P1_SFRINIT0) -#define F0900_P1_SFR_INIT0 0xf45f00ff - -/*P1_SFRUP1*/ -#define R0900_P1_SFRUP1 0xf460 -#define SFRUP1 REGx(R0900_P1_SFRUP1) -#define F0900_P1_AUTO_GUP 0xf4600080 -#define AUTO_GUP FLDx(F0900_P1_AUTO_GUP) -#define F0900_P1_SYMB_FREQ_UP1 0xf460007f - -/*P1_SFRUP0*/ -#define R0900_P1_SFRUP0 0xf461 -#define SFRUP0 REGx(R0900_P1_SFRUP0) -#define F0900_P1_SYMB_FREQ_UP0 0xf46100ff - -/*P1_SFRLOW1*/ -#define R0900_P1_SFRLOW1 0xf462 -#define SFRLOW1 REGx(R0900_P1_SFRLOW1) -#define F0900_P1_AUTO_GLOW 0xf4620080 -#define AUTO_GLOW FLDx(F0900_P1_AUTO_GLOW) -#define F0900_P1_SYMB_FREQ_LOW1 0xf462007f - -/*P1_SFRLOW0*/ -#define R0900_P1_SFRLOW0 0xf463 -#define SFRLOW0 REGx(R0900_P1_SFRLOW0) -#define F0900_P1_SYMB_FREQ_LOW0 0xf46300ff - -/*P1_SFR3*/ -#define R0900_P1_SFR3 0xf464 -#define SFR3 REGx(R0900_P1_SFR3) -#define F0900_P1_SYMB_FREQ3 0xf46400ff -#define SYMB_FREQ3 FLDx(F0900_P1_SYMB_FREQ3) - -/*P1_SFR2*/ -#define R0900_P1_SFR2 0xf465 -#define SFR2 REGx(R0900_P1_SFR2) -#define F0900_P1_SYMB_FREQ2 0xf46500ff -#define SYMB_FREQ2 FLDx(F0900_P1_SYMB_FREQ2) - -/*P1_SFR1*/ -#define R0900_P1_SFR1 0xf466 -#define SFR1 REGx(R0900_P1_SFR1) -#define F0900_P1_SYMB_FREQ1 0xf46600ff -#define SYMB_FREQ1 FLDx(F0900_P1_SYMB_FREQ1) - -/*P1_SFR0*/ -#define R0900_P1_SFR0 0xf467 -#define SFR0 REGx(R0900_P1_SFR0) -#define F0900_P1_SYMB_FREQ0 0xf46700ff -#define SYMB_FREQ0 FLDx(F0900_P1_SYMB_FREQ0) - -/*P1_TMGREG2*/ -#define R0900_P1_TMGREG2 0xf468 -#define TMGREG2 REGx(R0900_P1_TMGREG2) -#define F0900_P1_TMGREG2 0xf46800ff - -/*P1_TMGREG1*/ -#define R0900_P1_TMGREG1 0xf469 -#define TMGREG1 REGx(R0900_P1_TMGREG1) -#define F0900_P1_TMGREG1 0xf46900ff - -/*P1_TMGREG0*/ -#define R0900_P1_TMGREG0 0xf46a -#define TMGREG0 REGx(R0900_P1_TMGREG0) -#define F0900_P1_TMGREG0 0xf46a00ff - -/*P1_TMGLOCK1*/ -#define R0900_P1_TMGLOCK1 0xf46b -#define TMGLOCK1 REGx(R0900_P1_TMGLOCK1) -#define F0900_P1_TMGLOCK_LEVEL1 0xf46b01ff - -/*P1_TMGLOCK0*/ -#define R0900_P1_TMGLOCK0 0xf46c -#define TMGLOCK0 REGx(R0900_P1_TMGLOCK0) -#define F0900_P1_TMGLOCK_LEVEL0 0xf46c00ff - -/*P1_TMGOBS*/ -#define R0900_P1_TMGOBS 0xf46d -#define TMGOBS REGx(R0900_P1_TMGOBS) -#define F0900_P1_ROLLOFF_STATUS 0xf46d00c0 -#define ROLLOFF_STATUS FLDx(F0900_P1_ROLLOFF_STATUS) - -/*P1_EQUALCFG*/ -#define R0900_P1_EQUALCFG 0xf46f -#define EQUALCFG REGx(R0900_P1_EQUALCFG) -#define F0900_P1_EQUAL_ON 0xf46f0040 -#define F0900_P1_MU_EQUALDFE 0xf46f0007 - -/*P1_EQUAI1*/ -#define R0900_P1_EQUAI1 0xf470 -#define EQUAI1 REGx(R0900_P1_EQUAI1) -#define F0900_P1_EQUA_ACCI1 0xf47001ff - -/*P1_EQUAQ1*/ -#define R0900_P1_EQUAQ1 0xf471 -#define EQUAQ1 REGx(R0900_P1_EQUAQ1) -#define F0900_P1_EQUA_ACCQ1 0xf47101ff - -/*P1_EQUAI2*/ -#define R0900_P1_EQUAI2 0xf472 -#define EQUAI2 REGx(R0900_P1_EQUAI2) -#define F0900_P1_EQUA_ACCI2 0xf47201ff - -/*P1_EQUAQ2*/ -#define R0900_P1_EQUAQ2 0xf473 -#define EQUAQ2 REGx(R0900_P1_EQUAQ2) -#define F0900_P1_EQUA_ACCQ2 0xf47301ff - -/*P1_EQUAI3*/ -#define R0900_P1_EQUAI3 0xf474 -#define EQUAI3 REGx(R0900_P1_EQUAI3) -#define F0900_P1_EQUA_ACCI3 0xf47401ff - -/*P1_EQUAQ3*/ -#define R0900_P1_EQUAQ3 0xf475 -#define EQUAQ3 REGx(R0900_P1_EQUAQ3) -#define F0900_P1_EQUA_ACCQ3 0xf47501ff - -/*P1_EQUAI4*/ -#define R0900_P1_EQUAI4 0xf476 -#define EQUAI4 REGx(R0900_P1_EQUAI4) -#define F0900_P1_EQUA_ACCI4 0xf47601ff - -/*P1_EQUAQ4*/ -#define R0900_P1_EQUAQ4 0xf477 -#define EQUAQ4 REGx(R0900_P1_EQUAQ4) -#define F0900_P1_EQUA_ACCQ4 0xf47701ff - -/*P1_EQUAI5*/ -#define R0900_P1_EQUAI5 0xf478 -#define EQUAI5 REGx(R0900_P1_EQUAI5) -#define F0900_P1_EQUA_ACCI5 0xf47801ff - -/*P1_EQUAQ5*/ -#define R0900_P1_EQUAQ5 0xf479 -#define EQUAQ5 REGx(R0900_P1_EQUAQ5) -#define F0900_P1_EQUA_ACCQ5 0xf47901ff - -/*P1_EQUAI6*/ -#define R0900_P1_EQUAI6 0xf47a -#define EQUAI6 REGx(R0900_P1_EQUAI6) -#define F0900_P1_EQUA_ACCI6 0xf47a01ff - -/*P1_EQUAQ6*/ -#define R0900_P1_EQUAQ6 0xf47b -#define EQUAQ6 REGx(R0900_P1_EQUAQ6) -#define F0900_P1_EQUA_ACCQ6 0xf47b01ff - -/*P1_EQUAI7*/ -#define R0900_P1_EQUAI7 0xf47c -#define EQUAI7 REGx(R0900_P1_EQUAI7) -#define F0900_P1_EQUA_ACCI7 0xf47c01ff - -/*P1_EQUAQ7*/ -#define R0900_P1_EQUAQ7 0xf47d -#define EQUAQ7 REGx(R0900_P1_EQUAQ7) -#define F0900_P1_EQUA_ACCQ7 0xf47d01ff - -/*P1_EQUAI8*/ -#define R0900_P1_EQUAI8 0xf47e -#define EQUAI8 REGx(R0900_P1_EQUAI8) -#define F0900_P1_EQUA_ACCI8 0xf47e01ff - -/*P1_EQUAQ8*/ -#define R0900_P1_EQUAQ8 0xf47f -#define EQUAQ8 REGx(R0900_P1_EQUAQ8) -#define F0900_P1_EQUA_ACCQ8 0xf47f01ff - -/*P1_NNOSDATAT1*/ -#define R0900_P1_NNOSDATAT1 0xf480 -#define NNOSDATAT1 REGx(R0900_P1_NNOSDATAT1) -#define F0900_P1_NOSDATAT_NORMED1 0xf48000ff -#define NOSDATAT_NORMED1 FLDx(F0900_P1_NOSDATAT_NORMED1) - -/*P1_NNOSDATAT0*/ -#define R0900_P1_NNOSDATAT0 0xf481 -#define NNOSDATAT0 REGx(R0900_P1_NNOSDATAT0) -#define F0900_P1_NOSDATAT_NORMED0 0xf48100ff -#define NOSDATAT_NORMED0 FLDx(F0900_P1_NOSDATAT_NORMED0) - -/*P1_NNOSDATA1*/ -#define R0900_P1_NNOSDATA1 0xf482 -#define NNOSDATA1 REGx(R0900_P1_NNOSDATA1) -#define F0900_P1_NOSDATA_NORMED1 0xf48200ff - -/*P1_NNOSDATA0*/ -#define R0900_P1_NNOSDATA0 0xf483 -#define NNOSDATA0 REGx(R0900_P1_NNOSDATA0) -#define F0900_P1_NOSDATA_NORMED0 0xf48300ff - -/*P1_NNOSPLHT1*/ -#define R0900_P1_NNOSPLHT1 0xf484 -#define NNOSPLHT1 REGx(R0900_P1_NNOSPLHT1) -#define F0900_P1_NOSPLHT_NORMED1 0xf48400ff -#define NOSPLHT_NORMED1 FLDx(F0900_P1_NOSPLHT_NORMED1) - -/*P1_NNOSPLHT0*/ -#define R0900_P1_NNOSPLHT0 0xf485 -#define NNOSPLHT0 REGx(R0900_P1_NNOSPLHT0) -#define F0900_P1_NOSPLHT_NORMED0 0xf48500ff -#define NOSPLHT_NORMED0 FLDx(F0900_P1_NOSPLHT_NORMED0) - -/*P1_NNOSPLH1*/ -#define R0900_P1_NNOSPLH1 0xf486 -#define NNOSPLH1 REGx(R0900_P1_NNOSPLH1) -#define F0900_P1_NOSPLH_NORMED1 0xf48600ff - -/*P1_NNOSPLH0*/ -#define R0900_P1_NNOSPLH0 0xf487 -#define NNOSPLH0 REGx(R0900_P1_NNOSPLH0) -#define F0900_P1_NOSPLH_NORMED0 0xf48700ff - -/*P1_NOSDATAT1*/ -#define R0900_P1_NOSDATAT1 0xf488 -#define NOSDATAT1 REGx(R0900_P1_NOSDATAT1) -#define F0900_P1_NOSDATAT_UNNORMED1 0xf48800ff - -/*P1_NOSDATAT0*/ -#define R0900_P1_NOSDATAT0 0xf489 -#define NOSDATAT0 REGx(R0900_P1_NOSDATAT0) -#define F0900_P1_NOSDATAT_UNNORMED0 0xf48900ff - -/*P1_NOSDATA1*/ -#define R0900_P1_NOSDATA1 0xf48a -#define NOSDATA1 REGx(R0900_P1_NOSDATA1) -#define F0900_P1_NOSDATA_UNNORMED1 0xf48a00ff - -/*P1_NOSDATA0*/ -#define R0900_P1_NOSDATA0 0xf48b -#define NOSDATA0 REGx(R0900_P1_NOSDATA0) -#define F0900_P1_NOSDATA_UNNORMED0 0xf48b00ff - -/*P1_NOSPLHT1*/ -#define R0900_P1_NOSPLHT1 0xf48c -#define NOSPLHT1 REGx(R0900_P1_NOSPLHT1) -#define F0900_P1_NOSPLHT_UNNORMED1 0xf48c00ff - -/*P1_NOSPLHT0*/ -#define R0900_P1_NOSPLHT0 0xf48d -#define NOSPLHT0 REGx(R0900_P1_NOSPLHT0) -#define F0900_P1_NOSPLHT_UNNORMED0 0xf48d00ff - -/*P1_NOSPLH1*/ -#define R0900_P1_NOSPLH1 0xf48e -#define NOSPLH1 REGx(R0900_P1_NOSPLH1) -#define F0900_P1_NOSPLH_UNNORMED1 0xf48e00ff - -/*P1_NOSPLH0*/ -#define R0900_P1_NOSPLH0 0xf48f -#define NOSPLH0 REGx(R0900_P1_NOSPLH0) -#define F0900_P1_NOSPLH_UNNORMED0 0xf48f00ff - -/*P1_CAR2CFG*/ -#define R0900_P1_CAR2CFG 0xf490 -#define CAR2CFG REGx(R0900_P1_CAR2CFG) -#define F0900_P1_CARRIER3_DISABLE 0xf4900040 -#define F0900_P1_ROTA2ON 0xf4900004 -#define F0900_P1_PH_DET_ALGO2 0xf4900003 - -/*P1_CFR2CFR1*/ -#define R0900_P1_CFR2CFR1 0xf491 -#define CFR2CFR1 REGx(R0900_P1_CFR2CFR1) -#define F0900_P1_CFR2TOCFR1_DVBS1 0xf49100c0 -#define F0900_P1_EN_S2CAR2CENTER 0xf4910020 -#define F0900_P1_DIS_BCHERRCFR2 0xf4910010 -#define F0900_P1_CFR2TOCFR1_BETA 0xf4910007 - -/*P1_CFR22*/ -#define R0900_P1_CFR22 0xf493 -#define CFR22 REGx(R0900_P1_CFR22) -#define F0900_P1_CAR2_FREQ2 0xf49301ff - -/*P1_CFR21*/ -#define R0900_P1_CFR21 0xf494 -#define CFR21 REGx(R0900_P1_CFR21) -#define F0900_P1_CAR2_FREQ1 0xf49400ff - -/*P1_CFR20*/ -#define R0900_P1_CFR20 0xf495 -#define CFR20 REGx(R0900_P1_CFR20) -#define F0900_P1_CAR2_FREQ0 0xf49500ff - -/*P1_ACLC2S2Q*/ -#define R0900_P1_ACLC2S2Q 0xf497 -#define ACLC2S2Q REGx(R0900_P1_ACLC2S2Q) -#define F0900_P1_ENAB_SPSKSYMB 0xf4970080 -#define F0900_P1_CAR2S2_Q_ALPH_M 0xf4970030 -#define F0900_P1_CAR2S2_Q_ALPH_E 0xf497000f - -/*P1_ACLC2S28*/ -#define R0900_P1_ACLC2S28 0xf498 -#define ACLC2S28 REGx(R0900_P1_ACLC2S28) -#define F0900_P1_OLDI3Q_MODE 0xf4980080 -#define F0900_P1_CAR2S2_8_ALPH_M 0xf4980030 -#define F0900_P1_CAR2S2_8_ALPH_E 0xf498000f - -/*P1_ACLC2S216A*/ -#define R0900_P1_ACLC2S216A 0xf499 -#define ACLC2S216A REGx(R0900_P1_ACLC2S216A) -#define F0900_P1_DIS_C3STOPA2 0xf4990080 -#define F0900_P1_CAR2S2_16ADERAT 0xf4990040 -#define F0900_P1_CAR2S2_16A_ALPH_M 0xf4990030 -#define F0900_P1_CAR2S2_16A_ALPH_E 0xf499000f - -/*P1_ACLC2S232A*/ -#define R0900_P1_ACLC2S232A 0xf49a -#define ACLC2S232A REGx(R0900_P1_ACLC2S232A) -#define F0900_P1_CAR2S2_32ADERAT 0xf49a0040 -#define F0900_P1_CAR2S2_32A_ALPH_M 0xf49a0030 -#define F0900_P1_CAR2S2_32A_ALPH_E 0xf49a000f - -/*P1_BCLC2S2Q*/ -#define R0900_P1_BCLC2S2Q 0xf49c -#define BCLC2S2Q REGx(R0900_P1_BCLC2S2Q) -#define F0900_P1_CAR2S2_Q_BETA_M 0xf49c0030 -#define F0900_P1_CAR2S2_Q_BETA_E 0xf49c000f - -/*P1_BCLC2S28*/ -#define R0900_P1_BCLC2S28 0xf49d -#define BCLC2S28 REGx(R0900_P1_BCLC2S28) -#define F0900_P1_CAR2S2_8_BETA_M 0xf49d0030 -#define F0900_P1_CAR2S2_8_BETA_E 0xf49d000f - -/*P1_BCLC2S216A*/ -#define R0900_P1_BCLC2S216A 0xf49e -#define BCLC2S216A REGx(R0900_P1_BCLC2S216A) - -/*P1_BCLC2S232A*/ -#define R0900_P1_BCLC2S232A 0xf49f -#define BCLC2S232A REGx(R0900_P1_BCLC2S232A) - -/*P1_PLROOT2*/ -#define R0900_P1_PLROOT2 0xf4ac -#define PLROOT2 REGx(R0900_P1_PLROOT2) -#define F0900_P1_PLSCRAMB_MODE 0xf4ac000c -#define F0900_P1_PLSCRAMB_ROOT2 0xf4ac0003 - -/*P1_PLROOT1*/ -#define R0900_P1_PLROOT1 0xf4ad -#define PLROOT1 REGx(R0900_P1_PLROOT1) -#define F0900_P1_PLSCRAMB_ROOT1 0xf4ad00ff - -/*P1_PLROOT0*/ -#define R0900_P1_PLROOT0 0xf4ae -#define PLROOT0 REGx(R0900_P1_PLROOT0) -#define F0900_P1_PLSCRAMB_ROOT0 0xf4ae00ff - -/*P1_MODCODLST0*/ -#define R0900_P1_MODCODLST0 0xf4b0 -#define MODCODLST0 REGx(R0900_P1_MODCODLST0) - -/*P1_MODCODLST1*/ -#define R0900_P1_MODCODLST1 0xf4b1 -#define MODCODLST1 REGx(R0900_P1_MODCODLST1) -#define F0900_P1_DIS_MODCOD29 0xf4b100f0 -#define F0900_P1_DIS_32PSK_9_10 0xf4b1000f - -/*P1_MODCODLST2*/ -#define R0900_P1_MODCODLST2 0xf4b2 -#define MODCODLST2 REGx(R0900_P1_MODCODLST2) -#define F0900_P1_DIS_32PSK_8_9 0xf4b200f0 -#define F0900_P1_DIS_32PSK_5_6 0xf4b2000f - -/*P1_MODCODLST3*/ -#define R0900_P1_MODCODLST3 0xf4b3 -#define MODCODLST3 REGx(R0900_P1_MODCODLST3) -#define F0900_P1_DIS_32PSK_4_5 0xf4b300f0 -#define F0900_P1_DIS_32PSK_3_4 0xf4b3000f - -/*P1_MODCODLST4*/ -#define R0900_P1_MODCODLST4 0xf4b4 -#define MODCODLST4 REGx(R0900_P1_MODCODLST4) -#define F0900_P1_DIS_16PSK_9_10 0xf4b400f0 -#define F0900_P1_DIS_16PSK_8_9 0xf4b4000f - -/*P1_MODCODLST5*/ -#define R0900_P1_MODCODLST5 0xf4b5 -#define MODCODLST5 REGx(R0900_P1_MODCODLST5) -#define F0900_P1_DIS_16PSK_5_6 0xf4b500f0 -#define F0900_P1_DIS_16PSK_4_5 0xf4b5000f - -/*P1_MODCODLST6*/ -#define R0900_P1_MODCODLST6 0xf4b6 -#define MODCODLST6 REGx(R0900_P1_MODCODLST6) -#define F0900_P1_DIS_16PSK_3_4 0xf4b600f0 -#define F0900_P1_DIS_16PSK_2_3 0xf4b6000f - -/*P1_MODCODLST7*/ -#define R0900_P1_MODCODLST7 0xf4b7 -#define MODCODLST7 REGx(R0900_P1_MODCODLST7) -#define F0900_P1_DIS_8P_9_10 0xf4b700f0 -#define F0900_P1_DIS_8P_8_9 0xf4b7000f - -/*P1_MODCODLST8*/ -#define R0900_P1_MODCODLST8 0xf4b8 -#define MODCODLST8 REGx(R0900_P1_MODCODLST8) -#define F0900_P1_DIS_8P_5_6 0xf4b800f0 -#define F0900_P1_DIS_8P_3_4 0xf4b8000f - -/*P1_MODCODLST9*/ -#define R0900_P1_MODCODLST9 0xf4b9 -#define MODCODLST9 REGx(R0900_P1_MODCODLST9) -#define F0900_P1_DIS_8P_2_3 0xf4b900f0 -#define F0900_P1_DIS_8P_3_5 0xf4b9000f - -/*P1_MODCODLSTA*/ -#define R0900_P1_MODCODLSTA 0xf4ba -#define MODCODLSTA REGx(R0900_P1_MODCODLSTA) -#define F0900_P1_DIS_QP_9_10 0xf4ba00f0 -#define F0900_P1_DIS_QP_8_9 0xf4ba000f - -/*P1_MODCODLSTB*/ -#define R0900_P1_MODCODLSTB 0xf4bb -#define MODCODLSTB REGx(R0900_P1_MODCODLSTB) -#define F0900_P1_DIS_QP_5_6 0xf4bb00f0 -#define F0900_P1_DIS_QP_4_5 0xf4bb000f - -/*P1_MODCODLSTC*/ -#define R0900_P1_MODCODLSTC 0xf4bc -#define MODCODLSTC REGx(R0900_P1_MODCODLSTC) -#define F0900_P1_DIS_QP_3_4 0xf4bc00f0 -#define F0900_P1_DIS_QP_2_3 0xf4bc000f - -/*P1_MODCODLSTD*/ -#define R0900_P1_MODCODLSTD 0xf4bd -#define MODCODLSTD REGx(R0900_P1_MODCODLSTD) -#define F0900_P1_DIS_QP_3_5 0xf4bd00f0 -#define F0900_P1_DIS_QP_1_2 0xf4bd000f - -/*P1_MODCODLSTE*/ -#define R0900_P1_MODCODLSTE 0xf4be -#define MODCODLSTE REGx(R0900_P1_MODCODLSTE) -#define F0900_P1_DIS_QP_2_5 0xf4be00f0 -#define F0900_P1_DIS_QP_1_3 0xf4be000f - -/*P1_MODCODLSTF*/ -#define R0900_P1_MODCODLSTF 0xf4bf -#define MODCODLSTF REGx(R0900_P1_MODCODLSTF) -#define F0900_P1_DIS_QP_1_4 0xf4bf00f0 - -/*P1_GAUSSR0*/ -#define R0900_P1_GAUSSR0 0xf4c0 -#define GAUSSR0 REGx(R0900_P1_GAUSSR0) -#define F0900_P1_EN_CCIMODE 0xf4c00080 -#define F0900_P1_R0_GAUSSIEN 0xf4c0007f - -/*P1_CCIR0*/ -#define R0900_P1_CCIR0 0xf4c1 -#define CCIR0 REGx(R0900_P1_CCIR0) -#define F0900_P1_CCIDETECT_PLHONLY 0xf4c10080 -#define F0900_P1_R0_CCI 0xf4c1007f - -/*P1_CCIQUANT*/ -#define R0900_P1_CCIQUANT 0xf4c2 -#define CCIQUANT REGx(R0900_P1_CCIQUANT) -#define F0900_P1_CCI_BETA 0xf4c200e0 -#define F0900_P1_CCI_QUANT 0xf4c2001f - -/*P1_CCITHRES*/ -#define R0900_P1_CCITHRES 0xf4c3 -#define CCITHRES REGx(R0900_P1_CCITHRES) -#define F0900_P1_CCI_THRESHOLD 0xf4c300ff - -/*P1_CCIACC*/ -#define R0900_P1_CCIACC 0xf4c4 -#define CCIACC REGx(R0900_P1_CCIACC) -#define F0900_P1_CCI_VALUE 0xf4c400ff - -/*P1_DMDRESCFG*/ -#define R0900_P1_DMDRESCFG 0xf4c6 -#define DMDRESCFG REGx(R0900_P1_DMDRESCFG) -#define F0900_P1_DMDRES_RESET 0xf4c60080 -#define F0900_P1_DMDRES_STRALL 0xf4c60008 -#define F0900_P1_DMDRES_NEWONLY 0xf4c60004 -#define F0900_P1_DMDRES_NOSTORE 0xf4c60002 - -/*P1_DMDRESADR*/ -#define R0900_P1_DMDRESADR 0xf4c7 -#define DMDRESADR REGx(R0900_P1_DMDRESADR) -#define F0900_P1_DMDRES_VALIDCFR 0xf4c70040 -#define F0900_P1_DMDRES_MEMFULL 0xf4c70030 -#define F0900_P1_DMDRES_RESNBR 0xf4c7000f - -/*P1_DMDRESDATA7*/ -#define R0900_P1_DMDRESDATA7 0xf4c8 -#define F0900_P1_DMDRES_DATA7 0xf4c800ff - -/*P1_DMDRESDATA6*/ -#define R0900_P1_DMDRESDATA6 0xf4c9 -#define F0900_P1_DMDRES_DATA6 0xf4c900ff - -/*P1_DMDRESDATA5*/ -#define R0900_P1_DMDRESDATA5 0xf4ca -#define F0900_P1_DMDRES_DATA5 0xf4ca00ff - -/*P1_DMDRESDATA4*/ -#define R0900_P1_DMDRESDATA4 0xf4cb -#define F0900_P1_DMDRES_DATA4 0xf4cb00ff - -/*P1_DMDRESDATA3*/ -#define R0900_P1_DMDRESDATA3 0xf4cc -#define F0900_P1_DMDRES_DATA3 0xf4cc00ff - -/*P1_DMDRESDATA2*/ -#define R0900_P1_DMDRESDATA2 0xf4cd -#define F0900_P1_DMDRES_DATA2 0xf4cd00ff - -/*P1_DMDRESDATA1*/ -#define R0900_P1_DMDRESDATA1 0xf4ce -#define F0900_P1_DMDRES_DATA1 0xf4ce00ff - -/*P1_DMDRESDATA0*/ -#define R0900_P1_DMDRESDATA0 0xf4cf -#define F0900_P1_DMDRES_DATA0 0xf4cf00ff - -/*P1_FFEI1*/ -#define R0900_P1_FFEI1 0xf4d0 -#define FFEI1 REGx(R0900_P1_FFEI1) -#define F0900_P1_FFE_ACCI1 0xf4d001ff - -/*P1_FFEQ1*/ -#define R0900_P1_FFEQ1 0xf4d1 -#define FFEQ1 REGx(R0900_P1_FFEQ1) -#define F0900_P1_FFE_ACCQ1 0xf4d101ff - -/*P1_FFEI2*/ -#define R0900_P1_FFEI2 0xf4d2 -#define FFEI2 REGx(R0900_P1_FFEI2) -#define F0900_P1_FFE_ACCI2 0xf4d201ff - -/*P1_FFEQ2*/ -#define R0900_P1_FFEQ2 0xf4d3 -#define FFEQ2 REGx(R0900_P1_FFEQ2) -#define F0900_P1_FFE_ACCQ2 0xf4d301ff - -/*P1_FFEI3*/ -#define R0900_P1_FFEI3 0xf4d4 -#define FFEI3 REGx(R0900_P1_FFEI3) -#define F0900_P1_FFE_ACCI3 0xf4d401ff - -/*P1_FFEQ3*/ -#define R0900_P1_FFEQ3 0xf4d5 -#define FFEQ3 REGx(R0900_P1_FFEQ3) -#define F0900_P1_FFE_ACCQ3 0xf4d501ff - -/*P1_FFEI4*/ -#define R0900_P1_FFEI4 0xf4d6 -#define FFEI4 REGx(R0900_P1_FFEI4) -#define F0900_P1_FFE_ACCI4 0xf4d601ff - -/*P1_FFEQ4*/ -#define R0900_P1_FFEQ4 0xf4d7 -#define FFEQ4 REGx(R0900_P1_FFEQ4) -#define F0900_P1_FFE_ACCQ4 0xf4d701ff - -/*P1_FFECFG*/ -#define R0900_P1_FFECFG 0xf4d8 -#define FFECFG REGx(R0900_P1_FFECFG) -#define F0900_P1_EQUALFFE_ON 0xf4d80040 -#define F0900_P1_MU_EQUALFFE 0xf4d80007 - -/*P1_TNRCFG*/ -#define R0900_P1_TNRCFG 0xf4e0 -#define TNRCFG REGx(R0900_P1_TNRCFG) -#define F0900_P1_TUN_ACKFAIL 0xf4e00080 -#define F0900_P1_TUN_TYPE 0xf4e00070 -#define F0900_P1_TUN_SECSTOP 0xf4e00008 -#define F0900_P1_TUN_VCOSRCH 0xf4e00004 -#define F0900_P1_TUN_MADDRESS 0xf4e00003 - -/*P1_TNRCFG2*/ -#define R0900_P1_TNRCFG2 0xf4e1 -#define TNRCFG2 REGx(R0900_P1_TNRCFG2) -#define F0900_P1_TUN_IQSWAP 0xf4e10080 -#define F0900_P1_DIS_BWCALC 0xf4e10004 -#define F0900_P1_SHORT_WAITSTATES 0xf4e10002 - -/*P1_TNRXTAL*/ -#define R0900_P1_TNRXTAL 0xf4e4 -#define TNRXTAL REGx(R0900_P1_TNRXTAL) -#define F0900_P1_TUN_XTALFREQ 0xf4e4001f - -/*P1_TNRSTEPS*/ -#define R0900_P1_TNRSTEPS 0xf4e7 -#define TNRSTEPS REGx(R0900_P1_TNRSTEPS) -#define F0900_P1_TUNER_BW0P125 0xf4e70080 -#define F0900_P1_BWINC_OFFSET 0xf4e70170 -#define F0900_P1_SOFTSTEP_RNG 0xf4e70008 -#define F0900_P1_TUN_BWOFFSET 0xf4e70007 - -/*P1_TNRGAIN*/ -#define R0900_P1_TNRGAIN 0xf4e8 -#define TNRGAIN REGx(R0900_P1_TNRGAIN) -#define F0900_P1_TUN_KDIVEN 0xf4e800c0 -#define F0900_P1_STB6X00_OCK 0xf4e80030 -#define F0900_P1_TUN_GAIN 0xf4e8000f - -/*P1_TNRRF1*/ -#define R0900_P1_TNRRF1 0xf4e9 -#define TNRRF1 REGx(R0900_P1_TNRRF1) -#define F0900_P1_TUN_RFFREQ2 0xf4e900ff -#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2) - -/*P1_TNRRF0*/ -#define R0900_P1_TNRRF0 0xf4ea -#define TNRRF0 REGx(R0900_P1_TNRRF0) -#define F0900_P1_TUN_RFFREQ1 0xf4ea00ff -#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1) - -/*P1_TNRBW*/ -#define R0900_P1_TNRBW 0xf4eb -#define TNRBW REGx(R0900_P1_TNRBW) -#define F0900_P1_TUN_RFFREQ0 0xf4eb00c0 -#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0) -#define F0900_P1_TUN_BW 0xf4eb003f -#define TUN_BW FLDx(F0900_P1_TUN_BW) - -/*P1_TNRADJ*/ -#define R0900_P1_TNRADJ 0xf4ec -#define TNRADJ REGx(R0900_P1_TNRADJ) -#define F0900_P1_STB61X0_CALTIME 0xf4ec0040 - -/*P1_TNRCTL2*/ -#define R0900_P1_TNRCTL2 0xf4ed -#define TNRCTL2 REGx(R0900_P1_TNRCTL2) -#define F0900_P1_STB61X0_RCCKOFF 0xf4ed0080 -#define F0900_P1_STB61X0_ICP_SDOFF 0xf4ed0040 -#define F0900_P1_STB61X0_DCLOOPOFF 0xf4ed0020 -#define F0900_P1_STB61X0_REFOUTSEL 0xf4ed0010 -#define F0900_P1_STB61X0_CALOFF 0xf4ed0008 -#define F0900_P1_STB6XX0_LPT_BEN 0xf4ed0004 -#define F0900_P1_STB6XX0_RX_OSCP 0xf4ed0002 -#define F0900_P1_STB6XX0_SYN 0xf4ed0001 - -/*P1_TNRCFG3*/ -#define R0900_P1_TNRCFG3 0xf4ee -#define TNRCFG3 REGx(R0900_P1_TNRCFG3) -#define F0900_P1_TUN_PLLFREQ 0xf4ee001c -#define F0900_P1_TUN_I2CFREQ_MODE 0xf4ee0003 - -/*P1_TNRLAUNCH*/ -#define R0900_P1_TNRLAUNCH 0xf4f0 -#define TNRLAUNCH REGx(R0900_P1_TNRLAUNCH) - -/*P1_TNRLD*/ -#define R0900_P1_TNRLD 0xf4f0 -#define TNRLD REGx(R0900_P1_TNRLD) -#define F0900_P1_TUNLD_VCOING 0xf4f00080 -#define F0900_P1_TUN_REG1FAIL 0xf4f00040 -#define F0900_P1_TUN_REG2FAIL 0xf4f00020 -#define F0900_P1_TUN_REG3FAIL 0xf4f00010 -#define F0900_P1_TUN_REG4FAIL 0xf4f00008 -#define F0900_P1_TUN_REG5FAIL 0xf4f00004 -#define F0900_P1_TUN_BWING 0xf4f00002 -#define F0900_P1_TUN_LOCKED 0xf4f00001 - -/*P1_TNROBSL*/ -#define R0900_P1_TNROBSL 0xf4f6 -#define TNROBSL REGx(R0900_P1_TNROBSL) -#define F0900_P1_TUN_I2CABORTED 0xf4f60080 -#define F0900_P1_TUN_LPEN 0xf4f60040 -#define F0900_P1_TUN_FCCK 0xf4f60020 -#define F0900_P1_TUN_I2CLOCKED 0xf4f60010 -#define F0900_P1_TUN_PROGDONE 0xf4f6000c -#define F0900_P1_TUN_RFRESTE1 0xf4f60003 -#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1) - -/*P1_TNRRESTE*/ -#define R0900_P1_TNRRESTE 0xf4f7 -#define TNRRESTE REGx(R0900_P1_TNRRESTE) -#define F0900_P1_TUN_RFRESTE0 0xf4f700ff -#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0) - -/*P1_SMAPCOEF7*/ -#define R0900_P1_SMAPCOEF7 0xf500 -#define SMAPCOEF7 REGx(R0900_P1_SMAPCOEF7) -#define F0900_P1_DIS_QSCALE 0xf5000080 -#define F0900_P1_SMAPCOEF_Q_LLR12 0xf500017f - -/*P1_SMAPCOEF6*/ -#define R0900_P1_SMAPCOEF6 0xf501 -#define SMAPCOEF6 REGx(R0900_P1_SMAPCOEF6) -#define F0900_P1_ADJ_8PSKLLR1 0xf5010004 -#define F0900_P1_OLD_8PSKLLR1 0xf5010002 -#define F0900_P1_DIS_AB8PSK 0xf5010001 - -/*P1_SMAPCOEF5*/ -#define R0900_P1_SMAPCOEF5 0xf502 -#define SMAPCOEF5 REGx(R0900_P1_SMAPCOEF5) -#define F0900_P1_DIS_8SCALE 0xf5020080 -#define F0900_P1_SMAPCOEF_8P_LLR23 0xf502017f - -/*P1_NCO2MAX1*/ -#define R0900_P1_NCO2MAX1 0xf514 -#define NCO2MAX1 REGx(R0900_P1_NCO2MAX1) -#define F0900_P1_TETA2_MAXVABS1 0xf51400ff - -/*P1_NCO2MAX0*/ -#define R0900_P1_NCO2MAX0 0xf515 -#define NCO2MAX0 REGx(R0900_P1_NCO2MAX0) -#define F0900_P1_TETA2_MAXVABS0 0xf51500ff - -/*P1_NCO2FR1*/ -#define R0900_P1_NCO2FR1 0xf516 -#define NCO2FR1 REGx(R0900_P1_NCO2FR1) -#define F0900_P1_NCO2FINAL_ANGLE1 0xf51600ff - -/*P1_NCO2FR0*/ -#define R0900_P1_NCO2FR0 0xf517 -#define NCO2FR0 REGx(R0900_P1_NCO2FR0) -#define F0900_P1_NCO2FINAL_ANGLE0 0xf51700ff - -/*P1_CFR2AVRGE1*/ -#define R0900_P1_CFR2AVRGE1 0xf518 -#define CFR2AVRGE1 REGx(R0900_P1_CFR2AVRGE1) -#define F0900_P1_I2C_CFR2AVERAGE1 0xf51800ff - -/*P1_CFR2AVRGE0*/ -#define R0900_P1_CFR2AVRGE0 0xf519 -#define CFR2AVRGE0 REGx(R0900_P1_CFR2AVRGE0) -#define F0900_P1_I2C_CFR2AVERAGE0 0xf51900ff - -/*P1_DMDPLHSTAT*/ -#define R0900_P1_DMDPLHSTAT 0xf520 -#define DMDPLHSTAT REGx(R0900_P1_DMDPLHSTAT) -#define F0900_P1_PLH_STATISTIC 0xf52000ff - -/*P1_LOCKTIME3*/ -#define R0900_P1_LOCKTIME3 0xf522 -#define LOCKTIME3 REGx(R0900_P1_LOCKTIME3) -#define F0900_P1_DEMOD_LOCKTIME3 0xf52200ff - -/*P1_LOCKTIME2*/ -#define R0900_P1_LOCKTIME2 0xf523 -#define LOCKTIME2 REGx(R0900_P1_LOCKTIME2) -#define F0900_P1_DEMOD_LOCKTIME2 0xf52300ff - -/*P1_LOCKTIME1*/ -#define R0900_P1_LOCKTIME1 0xf524 -#define LOCKTIME1 REGx(R0900_P1_LOCKTIME1) -#define F0900_P1_DEMOD_LOCKTIME1 0xf52400ff - -/*P1_LOCKTIME0*/ -#define R0900_P1_LOCKTIME0 0xf525 -#define LOCKTIME0 REGx(R0900_P1_LOCKTIME0) -#define F0900_P1_DEMOD_LOCKTIME0 0xf52500ff - -/*P1_VITSCALE*/ -#define R0900_P1_VITSCALE 0xf532 -#define VITSCALE REGx(R0900_P1_VITSCALE) -#define F0900_P1_NVTH_NOSRANGE 0xf5320080 -#define F0900_P1_VERROR_MAXMODE 0xf5320040 -#define F0900_P1_NSLOWSN_LOCKED 0xf5320008 -#define F0900_P1_DIS_RSFLOCK 0xf5320002 - -/*P1_FECM*/ -#define R0900_P1_FECM 0xf533 -#define FECM REGx(R0900_P1_FECM) -#define F0900_P1_DSS_DVB 0xf5330080 -#define DSS_DVB FLDx(F0900_P1_DSS_DVB) -#define F0900_P1_DSS_SRCH 0xf5330010 -#define F0900_P1_SYNCVIT 0xf5330002 -#define F0900_P1_IQINV 0xf5330001 -#define IQINV FLDx(F0900_P1_IQINV) - -/*P1_VTH12*/ -#define R0900_P1_VTH12 0xf534 -#define VTH12 REGx(R0900_P1_VTH12) -#define F0900_P1_VTH12 0xf53400ff - -/*P1_VTH23*/ -#define R0900_P1_VTH23 0xf535 -#define VTH23 REGx(R0900_P1_VTH23) -#define F0900_P1_VTH23 0xf53500ff - -/*P1_VTH34*/ -#define R0900_P1_VTH34 0xf536 -#define VTH34 REGx(R0900_P1_VTH34) -#define F0900_P1_VTH34 0xf53600ff - -/*P1_VTH56*/ -#define R0900_P1_VTH56 0xf537 -#define VTH56 REGx(R0900_P1_VTH56) -#define F0900_P1_VTH56 0xf53700ff - -/*P1_VTH67*/ -#define R0900_P1_VTH67 0xf538 -#define VTH67 REGx(R0900_P1_VTH67) -#define F0900_P1_VTH67 0xf53800ff - -/*P1_VTH78*/ -#define R0900_P1_VTH78 0xf539 -#define VTH78 REGx(R0900_P1_VTH78) -#define F0900_P1_VTH78 0xf53900ff - -/*P1_VITCURPUN*/ -#define R0900_P1_VITCURPUN 0xf53a -#define VITCURPUN REGx(R0900_P1_VITCURPUN) -#define F0900_P1_VIT_CURPUN 0xf53a001f -#define VIT_CURPUN FLDx(F0900_P1_VIT_CURPUN) - -/*P1_VERROR*/ -#define R0900_P1_VERROR 0xf53b -#define VERROR REGx(R0900_P1_VERROR) -#define F0900_P1_REGERR_VIT 0xf53b00ff - -/*P1_PRVIT*/ -#define R0900_P1_PRVIT 0xf53c -#define PRVIT REGx(R0900_P1_PRVIT) -#define F0900_P1_DIS_VTHLOCK 0xf53c0040 -#define F0900_P1_E7_8VIT 0xf53c0020 -#define F0900_P1_E6_7VIT 0xf53c0010 -#define F0900_P1_E5_6VIT 0xf53c0008 -#define F0900_P1_E3_4VIT 0xf53c0004 -#define F0900_P1_E2_3VIT 0xf53c0002 -#define F0900_P1_E1_2VIT 0xf53c0001 - -/*P1_VAVSRVIT*/ -#define R0900_P1_VAVSRVIT 0xf53d -#define VAVSRVIT REGx(R0900_P1_VAVSRVIT) -#define F0900_P1_AMVIT 0xf53d0080 -#define F0900_P1_FROZENVIT 0xf53d0040 -#define F0900_P1_SNVIT 0xf53d0030 -#define F0900_P1_TOVVIT 0xf53d000c -#define F0900_P1_HYPVIT 0xf53d0003 - -/*P1_VSTATUSVIT*/ -#define R0900_P1_VSTATUSVIT 0xf53e -#define VSTATUSVIT REGx(R0900_P1_VSTATUSVIT) -#define F0900_P1_PRFVIT 0xf53e0010 -#define PRFVIT FLDx(F0900_P1_PRFVIT) -#define F0900_P1_LOCKEDVIT 0xf53e0008 -#define LOCKEDVIT FLDx(F0900_P1_LOCKEDVIT) - -/*P1_VTHINUSE*/ -#define R0900_P1_VTHINUSE 0xf53f -#define VTHINUSE REGx(R0900_P1_VTHINUSE) -#define F0900_P1_VIT_INUSE 0xf53f00ff - -/*P1_KDIV12*/ -#define R0900_P1_KDIV12 0xf540 -#define KDIV12 REGx(R0900_P1_KDIV12) -#define F0900_P1_K_DIVIDER_12 0xf540007f - -/*P1_KDIV23*/ -#define R0900_P1_KDIV23 0xf541 -#define KDIV23 REGx(R0900_P1_KDIV23) -#define F0900_P1_K_DIVIDER_23 0xf541007f - -/*P1_KDIV34*/ -#define R0900_P1_KDIV34 0xf542 -#define KDIV34 REGx(R0900_P1_KDIV34) -#define F0900_P1_K_DIVIDER_34 0xf542007f - -/*P1_KDIV56*/ -#define R0900_P1_KDIV56 0xf543 -#define KDIV56 REGx(R0900_P1_KDIV56) -#define F0900_P1_K_DIVIDER_56 0xf543007f - -/*P1_KDIV67*/ -#define R0900_P1_KDIV67 0xf544 -#define KDIV67 REGx(R0900_P1_KDIV67) -#define F0900_P1_K_DIVIDER_67 0xf544007f - -/*P1_KDIV78*/ -#define R0900_P1_KDIV78 0xf545 -#define KDIV78 REGx(R0900_P1_KDIV78) -#define F0900_P1_K_DIVIDER_78 0xf545007f - -/*P1_PDELCTRL1*/ -#define R0900_P1_PDELCTRL1 0xf550 -#define PDELCTRL1 REGx(R0900_P1_PDELCTRL1) -#define F0900_P1_INV_MISMASK 0xf5500080 -#define F0900_P1_FILTER_EN 0xf5500020 -#define F0900_P1_EN_MIS00 0xf5500002 -#define F0900_P1_ALGOSWRST 0xf5500001 -#define ALGOSWRST FLDx(F0900_P1_ALGOSWRST) - -/*P1_PDELCTRL2*/ -#define R0900_P1_PDELCTRL2 0xf551 -#define PDELCTRL2 REGx(R0900_P1_PDELCTRL2) -#define F0900_P1_RESET_UPKO_COUNT 0xf5510040 -#define RESET_UPKO_COUNT FLDx(F0900_P1_RESET_UPKO_COUNT) -#define F0900_P1_FRAME_MODE 0xf5510002 -#define F0900_P1_NOBCHERRFLG_USE 0xf5510001 - -/*P1_HYSTTHRESH*/ -#define R0900_P1_HYSTTHRESH 0xf554 -#define HYSTTHRESH REGx(R0900_P1_HYSTTHRESH) -#define F0900_P1_UNLCK_THRESH 0xf55400f0 -#define F0900_P1_DELIN_LCK_THRESH 0xf554000f - -/*P1_ISIENTRY*/ -#define R0900_P1_ISIENTRY 0xf55e -#define ISIENTRY REGx(R0900_P1_ISIENTRY) -#define F0900_P1_ISI_ENTRY 0xf55e00ff - -/*P1_ISIBITENA*/ -#define R0900_P1_ISIBITENA 0xf55f -#define ISIBITENA REGx(R0900_P1_ISIBITENA) -#define F0900_P1_ISI_BIT_EN 0xf55f00ff - -/*P1_MATSTR1*/ -#define R0900_P1_MATSTR1 0xf560 -#define MATSTR1 REGx(R0900_P1_MATSTR1) -#define F0900_P1_MATYPE_CURRENT1 0xf56000ff - -/*P1_MATSTR0*/ -#define R0900_P1_MATSTR0 0xf561 -#define MATSTR0 REGx(R0900_P1_MATSTR0) -#define F0900_P1_MATYPE_CURRENT0 0xf56100ff - -/*P1_UPLSTR1*/ -#define R0900_P1_UPLSTR1 0xf562 -#define UPLSTR1 REGx(R0900_P1_UPLSTR1) -#define F0900_P1_UPL_CURRENT1 0xf56200ff - -/*P1_UPLSTR0*/ -#define R0900_P1_UPLSTR0 0xf563 -#define UPLSTR0 REGx(R0900_P1_UPLSTR0) -#define F0900_P1_UPL_CURRENT0 0xf56300ff - -/*P1_DFLSTR1*/ -#define R0900_P1_DFLSTR1 0xf564 -#define DFLSTR1 REGx(R0900_P1_DFLSTR1) -#define F0900_P1_DFL_CURRENT1 0xf56400ff - -/*P1_DFLSTR0*/ -#define R0900_P1_DFLSTR0 0xf565 -#define DFLSTR0 REGx(R0900_P1_DFLSTR0) -#define F0900_P1_DFL_CURRENT0 0xf56500ff - -/*P1_SYNCSTR*/ -#define R0900_P1_SYNCSTR 0xf566 -#define SYNCSTR REGx(R0900_P1_SYNCSTR) -#define F0900_P1_SYNC_CURRENT 0xf56600ff - -/*P1_SYNCDSTR1*/ -#define R0900_P1_SYNCDSTR1 0xf567 -#define SYNCDSTR1 REGx(R0900_P1_SYNCDSTR1) -#define F0900_P1_SYNCD_CURRENT1 0xf56700ff - -/*P1_SYNCDSTR0*/ -#define R0900_P1_SYNCDSTR0 0xf568 -#define SYNCDSTR0 REGx(R0900_P1_SYNCDSTR0) -#define F0900_P1_SYNCD_CURRENT0 0xf56800ff - -/*P1_PDELSTATUS1*/ -#define R0900_P1_PDELSTATUS1 0xf569 -#define F0900_P1_PKTDELIN_DELOCK 0xf5690080 -#define F0900_P1_SYNCDUPDFL_BADDFL 0xf5690040 -#define F0900_P1_CONTINUOUS_STREAM 0xf5690020 -#define F0900_P1_UNACCEPTED_STREAM 0xf5690010 -#define F0900_P1_BCH_ERROR_FLAG 0xf5690008 -#define F0900_P1_PKTDELIN_LOCK 0xf5690002 -#define PKTDELIN_LOCK FLDx(F0900_P1_PKTDELIN_LOCK) -#define F0900_P1_FIRST_LOCK 0xf5690001 - -/*P1_PDELSTATUS2*/ -#define R0900_P1_PDELSTATUS2 0xf56a -#define F0900_P1_FRAME_MODCOD 0xf56a007c -#define F0900_P1_FRAME_TYPE 0xf56a0003 - -/*P1_BBFCRCKO1*/ -#define R0900_P1_BBFCRCKO1 0xf56b -#define BBFCRCKO1 REGx(R0900_P1_BBFCRCKO1) -#define F0900_P1_BBHCRC_KOCNT1 0xf56b00ff - -/*P1_BBFCRCKO0*/ -#define R0900_P1_BBFCRCKO0 0xf56c -#define BBFCRCKO0 REGx(R0900_P1_BBFCRCKO0) -#define F0900_P1_BBHCRC_KOCNT0 0xf56c00ff - -/*P1_UPCRCKO1*/ -#define R0900_P1_UPCRCKO1 0xf56d -#define UPCRCKO1 REGx(R0900_P1_UPCRCKO1) -#define F0900_P1_PKTCRC_KOCNT1 0xf56d00ff - -/*P1_UPCRCKO0*/ -#define R0900_P1_UPCRCKO0 0xf56e -#define UPCRCKO0 REGx(R0900_P1_UPCRCKO0) -#define F0900_P1_PKTCRC_KOCNT0 0xf56e00ff - -/*P1_PDELCTRL3*/ -#define R0900_P1_PDELCTRL3 0xf56f -#define PDELCTRL3 REGx(R0900_P1_PDELCTRL3) -#define F0900_P1_PKTDEL_CONTFAIL 0xf56f0080 -#define F0900_P1_NOFIFO_BCHERR 0xf56f0020 - -/*P1_TSSTATEM*/ -#define R0900_P1_TSSTATEM 0xf570 -#define TSSTATEM REGx(R0900_P1_TSSTATEM) -#define F0900_P1_TSDIL_ON 0xf5700080 -#define F0900_P1_TSRS_ON 0xf5700020 -#define F0900_P1_TSDESCRAMB_ON 0xf5700010 -#define F0900_P1_TSFRAME_MODE 0xf5700008 -#define F0900_P1_TS_DISABLE 0xf5700004 -#define F0900_P1_TSOUT_NOSYNC 0xf5700001 - -/*P1_TSCFGH*/ -#define R0900_P1_TSCFGH 0xf572 -#define TSCFGH REGx(R0900_P1_TSCFGH) -#define F0900_P1_TSFIFO_DVBCI 0xf5720080 -#define F0900_P1_TSFIFO_SERIAL 0xf5720040 -#define F0900_P1_TSFIFO_TEIUPDATE 0xf5720020 -#define F0900_P1_TSFIFO_DUTY50 0xf5720010 -#define F0900_P1_TSFIFO_HSGNLOUT 0xf5720008 -#define F0900_P1_TSFIFO_ERRMODE 0xf5720006 -#define F0900_P1_RST_HWARE 0xf5720001 -#define RST_HWARE FLDx(F0900_P1_RST_HWARE) - -/*P1_TSCFGM*/ -#define R0900_P1_TSCFGM 0xf573 -#define TSCFGM REGx(R0900_P1_TSCFGM) -#define F0900_P1_TSFIFO_MANSPEED 0xf57300c0 -#define F0900_P1_TSFIFO_PERMDATA 0xf5730020 -#define F0900_P1_TSFIFO_DPUNACT 0xf5730002 -#define F0900_P1_TSFIFO_INVDATA 0xf5730001 - -/*P1_TSCFGL*/ -#define R0900_P1_TSCFGL 0xf574 -#define TSCFGL REGx(R0900_P1_TSCFGL) -#define F0900_P1_TSFIFO_BCLKDEL1CK 0xf57400c0 -#define F0900_P1_BCHERROR_MODE 0xf5740030 -#define F0900_P1_TSFIFO_NSGNL2DATA 0xf5740008 -#define F0900_P1_TSFIFO_EMBINDVB 0xf5740004 -#define F0900_P1_TSFIFO_BITSPEED 0xf5740003 - -/*P1_TSINSDELH*/ -#define R0900_P1_TSINSDELH 0xf576 -#define TSINSDELH REGx(R0900_P1_TSINSDELH) -#define F0900_P1_TSDEL_SYNCBYTE 0xf5760080 -#define F0900_P1_TSDEL_XXHEADER 0xf5760040 -#define F0900_P1_TSDEL_BBHEADER 0xf5760020 -#define F0900_P1_TSDEL_DATAFIELD 0xf5760010 -#define F0900_P1_TSINSDEL_ISCR 0xf5760008 -#define F0900_P1_TSINSDEL_NPD 0xf5760004 -#define F0900_P1_TSINSDEL_RSPARITY 0xf5760002 -#define F0900_P1_TSINSDEL_CRC8 0xf5760001 - -/*P1_TSDIVN*/ -#define R0900_P1_TSDIVN 0xf579 -#define TSDIVN REGx(R0900_P1_TSDIVN) -#define F0900_P1_TSFIFO_SPEEDMODE 0xf57900c0 - -/*P1_TSCFG4*/ -#define R0900_P1_TSCFG4 0xf57a -#define TSCFG4 REGx(R0900_P1_TSCFG4) -#define F0900_P1_TSFIFO_TSSPEEDMODE 0xf57a00c0 - -/*P1_TSSPEED*/ -#define R0900_P1_TSSPEED 0xf580 -#define TSSPEED REGx(R0900_P1_TSSPEED) -#define F0900_P1_TSFIFO_OUTSPEED 0xf58000ff - -/*P1_TSSTATUS*/ -#define R0900_P1_TSSTATUS 0xf581 -#define TSSTATUS REGx(R0900_P1_TSSTATUS) -#define F0900_P1_TSFIFO_LINEOK 0xf5810080 -#define TSFIFO_LINEOK FLDx(F0900_P1_TSFIFO_LINEOK) -#define F0900_P1_TSFIFO_ERROR 0xf5810040 -#define F0900_P1_DIL_READY 0xf5810001 - -/*P1_TSSTATUS2*/ -#define R0900_P1_TSSTATUS2 0xf582 -#define TSSTATUS2 REGx(R0900_P1_TSSTATUS2) -#define F0900_P1_TSFIFO_DEMODSEL 0xf5820080 -#define F0900_P1_TSFIFOSPEED_STORE 0xf5820040 -#define F0900_P1_DILXX_RESET 0xf5820020 -#define F0900_P1_TSSERIAL_IMPOS 0xf5820010 -#define F0900_P1_SCRAMBDETECT 0xf5820002 - -/*P1_TSBITRATE1*/ -#define R0900_P1_TSBITRATE1 0xf583 -#define TSBITRATE1 REGx(R0900_P1_TSBITRATE1) -#define F0900_P1_TSFIFO_BITRATE1 0xf58300ff - -/*P1_TSBITRATE0*/ -#define R0900_P1_TSBITRATE0 0xf584 -#define TSBITRATE0 REGx(R0900_P1_TSBITRATE0) -#define F0900_P1_TSFIFO_BITRATE0 0xf58400ff - -/*P1_ERRCTRL1*/ -#define R0900_P1_ERRCTRL1 0xf598 -#define ERRCTRL1 REGx(R0900_P1_ERRCTRL1) -#define F0900_P1_ERR_SOURCE1 0xf59800f0 -#define F0900_P1_NUM_EVENT1 0xf5980007 - -/*P1_ERRCNT12*/ -#define R0900_P1_ERRCNT12 0xf599 -#define ERRCNT12 REGx(R0900_P1_ERRCNT12) -#define F0900_P1_ERRCNT1_OLDVALUE 0xf5990080 -#define F0900_P1_ERR_CNT12 0xf599007f -#define ERR_CNT12 FLDx(F0900_P1_ERR_CNT12) - -/*P1_ERRCNT11*/ -#define R0900_P1_ERRCNT11 0xf59a -#define ERRCNT11 REGx(R0900_P1_ERRCNT11) -#define F0900_P1_ERR_CNT11 0xf59a00ff -#define ERR_CNT11 FLDx(F0900_P1_ERR_CNT11) - -/*P1_ERRCNT10*/ -#define R0900_P1_ERRCNT10 0xf59b -#define ERRCNT10 REGx(R0900_P1_ERRCNT10) -#define F0900_P1_ERR_CNT10 0xf59b00ff -#define ERR_CNT10 FLDx(F0900_P1_ERR_CNT10) - -/*P1_ERRCTRL2*/ -#define R0900_P1_ERRCTRL2 0xf59c -#define ERRCTRL2 REGx(R0900_P1_ERRCTRL2) -#define F0900_P1_ERR_SOURCE2 0xf59c00f0 -#define F0900_P1_NUM_EVENT2 0xf59c0007 - -/*P1_ERRCNT22*/ -#define R0900_P1_ERRCNT22 0xf59d -#define ERRCNT22 REGx(R0900_P1_ERRCNT22) -#define F0900_P1_ERRCNT2_OLDVALUE 0xf59d0080 -#define F0900_P1_ERR_CNT22 0xf59d007f -#define ERR_CNT22 FLDx(F0900_P1_ERR_CNT22) - -/*P1_ERRCNT21*/ -#define R0900_P1_ERRCNT21 0xf59e -#define ERRCNT21 REGx(R0900_P1_ERRCNT21) -#define F0900_P1_ERR_CNT21 0xf59e00ff -#define ERR_CNT21 FLDx(F0900_P1_ERR_CNT21) - -/*P1_ERRCNT20*/ -#define R0900_P1_ERRCNT20 0xf59f -#define ERRCNT20 REGx(R0900_P1_ERRCNT20) -#define F0900_P1_ERR_CNT20 0xf59f00ff -#define ERR_CNT20 FLDx(F0900_P1_ERR_CNT20) - -/*P1_FECSPY*/ -#define R0900_P1_FECSPY 0xf5a0 -#define FECSPY REGx(R0900_P1_FECSPY) -#define F0900_P1_SPY_ENABLE 0xf5a00080 -#define F0900_P1_NO_SYNCBYTE 0xf5a00040 -#define F0900_P1_SERIAL_MODE 0xf5a00020 -#define F0900_P1_UNUSUAL_PACKET 0xf5a00010 -#define F0900_P1_BERMETER_DATAMODE 0xf5a00008 -#define F0900_P1_BERMETER_LMODE 0xf5a00002 -#define F0900_P1_BERMETER_RESET 0xf5a00001 - -/*P1_FSPYCFG*/ -#define R0900_P1_FSPYCFG 0xf5a1 -#define FSPYCFG REGx(R0900_P1_FSPYCFG) -#define F0900_P1_FECSPY_INPUT 0xf5a100c0 -#define F0900_P1_RST_ON_ERROR 0xf5a10020 -#define F0900_P1_ONE_SHOT 0xf5a10010 -#define F0900_P1_I2C_MODE 0xf5a1000c -#define F0900_P1_SPY_HYSTERESIS 0xf5a10003 - -/*P1_FSPYDATA*/ -#define R0900_P1_FSPYDATA 0xf5a2 -#define FSPYDATA REGx(R0900_P1_FSPYDATA) -#define F0900_P1_SPY_STUFFING 0xf5a20080 -#define F0900_P1_SPY_CNULLPKT 0xf5a20020 -#define F0900_P1_SPY_OUTDATA_MODE 0xf5a2001f - -/*P1_FSPYOUT*/ -#define R0900_P1_FSPYOUT 0xf5a3 -#define FSPYOUT REGx(R0900_P1_FSPYOUT) -#define F0900_P1_FSPY_DIRECT 0xf5a30080 -#define F0900_P1_STUFF_MODE 0xf5a30007 - -/*P1_FSTATUS*/ -#define R0900_P1_FSTATUS 0xf5a4 -#define FSTATUS REGx(R0900_P1_FSTATUS) -#define F0900_P1_SPY_ENDSIM 0xf5a40080 -#define F0900_P1_VALID_SIM 0xf5a40040 -#define F0900_P1_FOUND_SIGNAL 0xf5a40020 -#define F0900_P1_DSS_SYNCBYTE 0xf5a40010 -#define F0900_P1_RESULT_STATE 0xf5a4000f - -/*P1_FBERCPT4*/ -#define R0900_P1_FBERCPT4 0xf5a8 -#define FBERCPT4 REGx(R0900_P1_FBERCPT4) -#define F0900_P1_FBERMETER_CPT4 0xf5a800ff - -/*P1_FBERCPT3*/ -#define R0900_P1_FBERCPT3 0xf5a9 -#define FBERCPT3 REGx(R0900_P1_FBERCPT3) -#define F0900_P1_FBERMETER_CPT3 0xf5a900ff - -/*P1_FBERCPT2*/ -#define R0900_P1_FBERCPT2 0xf5aa -#define FBERCPT2 REGx(R0900_P1_FBERCPT2) -#define F0900_P1_FBERMETER_CPT2 0xf5aa00ff - -/*P1_FBERCPT1*/ -#define R0900_P1_FBERCPT1 0xf5ab -#define FBERCPT1 REGx(R0900_P1_FBERCPT1) -#define F0900_P1_FBERMETER_CPT1 0xf5ab00ff - -/*P1_FBERCPT0*/ -#define R0900_P1_FBERCPT0 0xf5ac -#define FBERCPT0 REGx(R0900_P1_FBERCPT0) -#define F0900_P1_FBERMETER_CPT0 0xf5ac00ff - -/*P1_FBERERR2*/ -#define R0900_P1_FBERERR2 0xf5ad -#define FBERERR2 REGx(R0900_P1_FBERERR2) -#define F0900_P1_FBERMETER_ERR2 0xf5ad00ff - -/*P1_FBERERR1*/ -#define R0900_P1_FBERERR1 0xf5ae -#define FBERERR1 REGx(R0900_P1_FBERERR1) -#define F0900_P1_FBERMETER_ERR1 0xf5ae00ff - -/*P1_FBERERR0*/ -#define R0900_P1_FBERERR0 0xf5af -#define FBERERR0 REGx(R0900_P1_FBERERR0) -#define F0900_P1_FBERMETER_ERR0 0xf5af00ff - -/*P1_FSPYBER*/ -#define R0900_P1_FSPYBER 0xf5b2 -#define FSPYBER REGx(R0900_P1_FSPYBER) -#define F0900_P1_FSPYBER_SYNCBYTE 0xf5b20010 -#define F0900_P1_FSPYBER_UNSYNC 0xf5b20008 -#define F0900_P1_FSPYBER_CTIME 0xf5b20007 - -/*RCCFG2*/ -#define R0900_RCCFG2 0xf600 - -/*TSGENERAL*/ -#define R0900_TSGENERAL 0xf630 -#define F0900_TSFIFO_DISTS2PAR 0xf6300040 -#define F0900_MUXSTREAM_OUTMODE 0xf6300008 -#define F0900_TSFIFO_PERMPARAL 0xf6300006 - -/*TSGENERAL1X*/ -#define R0900_TSGENERAL1X 0xf670 - -/*NBITER_NF4*/ -#define R0900_NBITER_NF4 0xfa03 -#define F0900_NBITER_NF_QP_1_2 0xfa0300ff - -/*NBITER_NF5*/ -#define R0900_NBITER_NF5 0xfa04 -#define F0900_NBITER_NF_QP_3_5 0xfa0400ff - -/*NBITER_NF6*/ -#define R0900_NBITER_NF6 0xfa05 -#define F0900_NBITER_NF_QP_2_3 0xfa0500ff - -/*NBITER_NF7*/ -#define R0900_NBITER_NF7 0xfa06 -#define F0900_NBITER_NF_QP_3_4 0xfa0600ff - -/*NBITER_NF8*/ -#define R0900_NBITER_NF8 0xfa07 -#define F0900_NBITER_NF_QP_4_5 0xfa0700ff - -/*NBITER_NF9*/ -#define R0900_NBITER_NF9 0xfa08 -#define F0900_NBITER_NF_QP_5_6 0xfa0800ff - -/*NBITER_NF10*/ -#define R0900_NBITER_NF10 0xfa09 -#define F0900_NBITER_NF_QP_8_9 0xfa0900ff - -/*NBITER_NF11*/ -#define R0900_NBITER_NF11 0xfa0a -#define F0900_NBITER_NF_QP_9_10 0xfa0a00ff - -/*NBITER_NF12*/ -#define R0900_NBITER_NF12 0xfa0b -#define F0900_NBITER_NF_8P_3_5 0xfa0b00ff - -/*NBITER_NF13*/ -#define R0900_NBITER_NF13 0xfa0c -#define F0900_NBITER_NF_8P_2_3 0xfa0c00ff - -/*NBITER_NF14*/ -#define R0900_NBITER_NF14 0xfa0d -#define F0900_NBITER_NF_8P_3_4 0xfa0d00ff - -/*NBITER_NF15*/ -#define R0900_NBITER_NF15 0xfa0e -#define F0900_NBITER_NF_8P_5_6 0xfa0e00ff - -/*NBITER_NF16*/ -#define R0900_NBITER_NF16 0xfa0f -#define F0900_NBITER_NF_8P_8_9 0xfa0f00ff - -/*NBITER_NF17*/ -#define R0900_NBITER_NF17 0xfa10 -#define F0900_NBITER_NF_8P_9_10 0xfa1000ff - -/*NBITERNOERR*/ -#define R0900_NBITERNOERR 0xfa3f -#define F0900_NBITER_STOP_CRIT 0xfa3f000f - -/*GAINLLR_NF4*/ -#define R0900_GAINLLR_NF4 0xfa43 -#define F0900_GAINLLR_NF_QP_1_2 0xfa43007f - -/*GAINLLR_NF5*/ -#define R0900_GAINLLR_NF5 0xfa44 -#define F0900_GAINLLR_NF_QP_3_5 0xfa44007f - -/*GAINLLR_NF6*/ -#define R0900_GAINLLR_NF6 0xfa45 -#define F0900_GAINLLR_NF_QP_2_3 0xfa45007f - -/*GAINLLR_NF7*/ -#define R0900_GAINLLR_NF7 0xfa46 -#define F0900_GAINLLR_NF_QP_3_4 0xfa46007f - -/*GAINLLR_NF8*/ -#define R0900_GAINLLR_NF8 0xfa47 -#define F0900_GAINLLR_NF_QP_4_5 0xfa47007f - -/*GAINLLR_NF9*/ -#define R0900_GAINLLR_NF9 0xfa48 -#define F0900_GAINLLR_NF_QP_5_6 0xfa48007f - -/*GAINLLR_NF10*/ -#define R0900_GAINLLR_NF10 0xfa49 -#define F0900_GAINLLR_NF_QP_8_9 0xfa49007f - -/*GAINLLR_NF11*/ -#define R0900_GAINLLR_NF11 0xfa4a -#define F0900_GAINLLR_NF_QP_9_10 0xfa4a007f - -/*GAINLLR_NF12*/ -#define R0900_GAINLLR_NF12 0xfa4b -#define F0900_GAINLLR_NF_8P_3_5 0xfa4b007f - -/*GAINLLR_NF13*/ -#define R0900_GAINLLR_NF13 0xfa4c -#define F0900_GAINLLR_NF_8P_2_3 0xfa4c007f - -/*GAINLLR_NF14*/ -#define R0900_GAINLLR_NF14 0xfa4d -#define F0900_GAINLLR_NF_8P_3_4 0xfa4d007f - -/*GAINLLR_NF15*/ -#define R0900_GAINLLR_NF15 0xfa4e -#define F0900_GAINLLR_NF_8P_5_6 0xfa4e007f - -/*GAINLLR_NF16*/ -#define R0900_GAINLLR_NF16 0xfa4f -#define F0900_GAINLLR_NF_8P_8_9 0xfa4f007f - -/*GAINLLR_NF17*/ -#define R0900_GAINLLR_NF17 0xfa50 -#define F0900_GAINLLR_NF_8P_9_10 0xfa50007f - -/*CFGEXT*/ -#define R0900_CFGEXT 0xfa80 -#define F0900_STAGMODE 0xfa800080 -#define F0900_BYPBCH 0xfa800040 -#define F0900_BYPLDPC 0xfa800020 -#define F0900_LDPCMODE 0xfa800010 -#define F0900_INVLLRSIGN 0xfa800008 -#define F0900_SHORTMULT 0xfa800004 -#define F0900_EXTERNTX 0xfa800001 - -/*GENCFG*/ -#define R0900_GENCFG 0xfa86 -#define F0900_BROADCAST 0xfa860010 -#define F0900_PRIORITY 0xfa860002 -#define F0900_DDEMOD 0xfa860001 - -/*LDPCERR1*/ -#define R0900_LDPCERR1 0xfa96 -#define F0900_LDPC_ERRORS_COUNTER1 0xfa9600ff - -/*LDPCERR0*/ -#define R0900_LDPCERR0 0xfa97 -#define F0900_LDPC_ERRORS_COUNTER0 0xfa9700ff - -/*BCHERR*/ -#define R0900_BCHERR 0xfa98 -#define F0900_ERRORFLAG 0xfa980010 -#define F0900_BCH_ERRORS_COUNTER 0xfa98000f - -/*TSTRES0*/ -#define R0900_TSTRES0 0xff11 -#define F0900_FRESFEC 0xff110080 - -/*P2_TCTL4*/ -#define R0900_P2_TCTL4 0xff28 -#define F0900_P2_PN4_SELECT 0xff280020 - -/*P1_TCTL4*/ -#define R0900_P1_TCTL4 0xff48 -#define TCTL4 shiftx(R0900_P1_TCTL4, demod, 0x20) -#define F0900_P1_PN4_SELECT 0xff480020 - -/*P2_TSTDISRX*/ -#define R0900_P2_TSTDISRX 0xff65 -#define F0900_P2_PIN_SELECT1 0xff650008 - -/*P1_TSTDISRX*/ -#define R0900_P1_TSTDISRX 0xff67 -#define TSTDISRX shiftx(R0900_P1_TSTDISRX, demod, 2) -#define F0900_P1_PIN_SELECT1 0xff670008 -#define PIN_SELECT1 shiftx(F0900_P1_PIN_SELECT1, demod, 0x20000) - -#define STV0900_NBREGS 723 -#define STV0900_NBFIELDS 1420 - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_sw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_sw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_sw.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv0900_sw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2034 +0,0 @@ -/* - * stv0900_sw.c - * - * Driver for ST STV0900 satellite demodulator IC. - * - * Copyright (C) ST Microelectronics. - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "stv0900.h" -#include "stv0900_reg.h" -#include "stv0900_priv.h" - -s32 shiftx(s32 x, int demod, s32 shift) -{ - if (demod == 1) - return x - shift; - - return x; -} - -int stv0900_check_signal_presence(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - s32 carr_offset, - agc2_integr, - max_carrier; - - int no_signal = FALSE; - - carr_offset = (stv0900_read_reg(intp, CFR2) << 8) - | stv0900_read_reg(intp, CFR1); - carr_offset = ge2comp(carr_offset, 16); - agc2_integr = (stv0900_read_reg(intp, AGC2I1) << 8) - | stv0900_read_reg(intp, AGC2I0); - max_carrier = intp->srch_range[demod] / 1000; - - max_carrier += (max_carrier / 10); - max_carrier = 65536 * (max_carrier / 2); - max_carrier /= intp->mclk / 1000; - if (max_carrier > 0x4000) - max_carrier = 0x4000; - - if ((agc2_integr > 0x2000) - || (carr_offset > (2 * max_carrier)) - || (carr_offset < (-2 * max_carrier))) - no_signal = TRUE; - - return no_signal; -} - -static void stv0900_get_sw_loop_params(struct stv0900_internal *intp, - s32 *frequency_inc, s32 *sw_timeout, - s32 *steps, - enum fe_stv0900_demod_num demod) -{ - s32 timeout, freq_inc, max_steps, srate, max_carrier; - - enum fe_stv0900_search_standard standard; - - srate = intp->symbol_rate[demod]; - max_carrier = intp->srch_range[demod] / 1000; - max_carrier += max_carrier / 10; - standard = intp->srch_standard[demod]; - - max_carrier = 65536 * (max_carrier / 2); - max_carrier /= intp->mclk / 1000; - - if (max_carrier > 0x4000) - max_carrier = 0x4000; - - freq_inc = srate; - freq_inc /= intp->mclk >> 10; - freq_inc = freq_inc << 6; - - switch (standard) { - case STV0900_SEARCH_DVBS1: - case STV0900_SEARCH_DSS: - freq_inc *= 3; - timeout = 20; - break; - case STV0900_SEARCH_DVBS2: - freq_inc *= 4; - timeout = 25; - break; - case STV0900_AUTO_SEARCH: - default: - freq_inc *= 3; - timeout = 25; - break; - } - - freq_inc /= 100; - - if ((freq_inc > max_carrier) || (freq_inc < 0)) - freq_inc = max_carrier / 2; - - timeout *= 27500; - - if (srate > 0) - timeout /= srate / 1000; - - if ((timeout > 100) || (timeout < 0)) - timeout = 100; - - max_steps = (max_carrier / freq_inc) + 1; - - if ((max_steps > 100) || (max_steps < 0)) { - max_steps = 100; - freq_inc = max_carrier / max_steps; - } - - *frequency_inc = freq_inc; - *sw_timeout = timeout; - *steps = max_steps; - -} - -static int stv0900_search_carr_sw_loop(struct stv0900_internal *intp, - s32 FreqIncr, s32 Timeout, int zigzag, - s32 MaxStep, enum fe_stv0900_demod_num demod) -{ - int no_signal, - lock = FALSE; - s32 stepCpt, - freqOffset, - max_carrier; - - max_carrier = intp->srch_range[demod] / 1000; - max_carrier += (max_carrier / 10); - - max_carrier = 65536 * (max_carrier / 2); - max_carrier /= intp->mclk / 1000; - - if (max_carrier > 0x4000) - max_carrier = 0x4000; - - if (zigzag == TRUE) - freqOffset = 0; - else - freqOffset = -max_carrier + FreqIncr; - - stepCpt = 0; - - do { - stv0900_write_reg(intp, DMDISTATE, 0x1c); - stv0900_write_reg(intp, CFRINIT1, (freqOffset / 256) & 0xff); - stv0900_write_reg(intp, CFRINIT0, freqOffset & 0xff); - stv0900_write_reg(intp, DMDISTATE, 0x18); - stv0900_write_bits(intp, ALGOSWRST, 1); - - if (intp->chip_id == 0x12) { - stv0900_write_bits(intp, RST_HWARE, 1); - stv0900_write_bits(intp, RST_HWARE, 0); - } - - if (zigzag == TRUE) { - if (freqOffset >= 0) - freqOffset = -freqOffset - 2 * FreqIncr; - else - freqOffset = -freqOffset; - } else - freqOffset += + 2 * FreqIncr; - - stepCpt++; - lock = stv0900_get_demod_lock(intp, demod, Timeout); - no_signal = stv0900_check_signal_presence(intp, demod); - - } while ((lock == FALSE) - && (no_signal == FALSE) - && ((freqOffset - FreqIncr) < max_carrier) - && ((freqOffset + FreqIncr) > -max_carrier) - && (stepCpt < MaxStep)); - - stv0900_write_bits(intp, ALGOSWRST, 0); - - return lock; -} - -static int stv0900_sw_algo(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - int lock = FALSE, - no_signal, - zigzag; - s32 s2fw, - fqc_inc, - sft_stp_tout, - trial_cntr, - max_steps; - - stv0900_get_sw_loop_params(intp, &fqc_inc, &sft_stp_tout, - &max_steps, demod); - switch (intp->srch_standard[demod]) { - case STV0900_SEARCH_DVBS1: - case STV0900_SEARCH_DSS: - if (intp->chip_id >= 0x20) - stv0900_write_reg(intp, CARFREQ, 0x3b); - else - stv0900_write_reg(intp, CARFREQ, 0xef); - - stv0900_write_reg(intp, DMDCFGMD, 0x49); - zigzag = FALSE; - break; - case STV0900_SEARCH_DVBS2: - if (intp->chip_id >= 0x20) - stv0900_write_reg(intp, CORRELABS, 0x79); - else - stv0900_write_reg(intp, CORRELABS, 0x68); - - stv0900_write_reg(intp, DMDCFGMD, 0x89); - - zigzag = TRUE; - break; - case STV0900_AUTO_SEARCH: - default: - if (intp->chip_id >= 0x20) { - stv0900_write_reg(intp, CARFREQ, 0x3b); - stv0900_write_reg(intp, CORRELABS, 0x79); - } else { - stv0900_write_reg(intp, CARFREQ, 0xef); - stv0900_write_reg(intp, CORRELABS, 0x68); - } - - stv0900_write_reg(intp, DMDCFGMD, 0xc9); - zigzag = FALSE; - break; - } - - trial_cntr = 0; - do { - lock = stv0900_search_carr_sw_loop(intp, - fqc_inc, - sft_stp_tout, - zigzag, - max_steps, - demod); - no_signal = stv0900_check_signal_presence(intp, demod); - trial_cntr++; - if ((lock == TRUE) - || (no_signal == TRUE) - || (trial_cntr == 2)) { - - if (intp->chip_id >= 0x20) { - stv0900_write_reg(intp, CARFREQ, 0x49); - stv0900_write_reg(intp, CORRELABS, 0x9e); - } else { - stv0900_write_reg(intp, CARFREQ, 0xed); - stv0900_write_reg(intp, CORRELABS, 0x88); - } - - if ((stv0900_get_bits(intp, HEADER_MODE) == - STV0900_DVBS2_FOUND) && - (lock == TRUE)) { - msleep(sft_stp_tout); - s2fw = stv0900_get_bits(intp, FLYWHEEL_CPT); - - if (s2fw < 0xd) { - msleep(sft_stp_tout); - s2fw = stv0900_get_bits(intp, - FLYWHEEL_CPT); - } - - if (s2fw < 0xd) { - lock = FALSE; - - if (trial_cntr < 2) { - if (intp->chip_id >= 0x20) - stv0900_write_reg(intp, - CORRELABS, - 0x79); - else - stv0900_write_reg(intp, - CORRELABS, - 0x68); - - stv0900_write_reg(intp, - DMDCFGMD, - 0x89); - } - } - } - } - - } while ((lock == FALSE) - && (trial_cntr < 2) - && (no_signal == FALSE)); - - return lock; -} - -static u32 stv0900_get_symbol_rate(struct stv0900_internal *intp, - u32 mclk, - enum fe_stv0900_demod_num demod) -{ - s32 rem1, rem2, intval1, intval2, srate; - - srate = (stv0900_get_bits(intp, SYMB_FREQ3) << 24) + - (stv0900_get_bits(intp, SYMB_FREQ2) << 16) + - (stv0900_get_bits(intp, SYMB_FREQ1) << 8) + - (stv0900_get_bits(intp, SYMB_FREQ0)); - dprintk("lock: srate=%d r0=0x%x r1=0x%x r2=0x%x r3=0x%x \n", - srate, stv0900_get_bits(intp, SYMB_FREQ0), - stv0900_get_bits(intp, SYMB_FREQ1), - stv0900_get_bits(intp, SYMB_FREQ2), - stv0900_get_bits(intp, SYMB_FREQ3)); - - intval1 = (mclk) >> 16; - intval2 = (srate) >> 16; - - rem1 = (mclk) % 0x10000; - rem2 = (srate) % 0x10000; - srate = (intval1 * intval2) + - ((intval1 * rem2) >> 16) + - ((intval2 * rem1) >> 16); - - return srate; -} - -static void stv0900_set_symbol_rate(struct stv0900_internal *intp, - u32 mclk, u32 srate, - enum fe_stv0900_demod_num demod) -{ - u32 symb; - - dprintk("%s: Mclk %d, SR %d, Dmd %d\n", __func__, mclk, - srate, demod); - - if (srate > 60000000) { - symb = srate << 4; - symb /= (mclk >> 12); - } else if (srate > 6000000) { - symb = srate << 6; - symb /= (mclk >> 10); - } else { - symb = srate << 9; - symb /= (mclk >> 7); - } - - stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0x7f); - stv0900_write_reg(intp, SFRINIT1 + 1, (symb & 0xff)); -} - -static void stv0900_set_max_symbol_rate(struct stv0900_internal *intp, - u32 mclk, u32 srate, - enum fe_stv0900_demod_num demod) -{ - u32 symb; - - srate = 105 * (srate / 100); - - if (srate > 60000000) { - symb = srate << 4; - symb /= (mclk >> 12); - } else if (srate > 6000000) { - symb = srate << 6; - symb /= (mclk >> 10); - } else { - symb = srate << 9; - symb /= (mclk >> 7); - } - - if (symb < 0x7fff) { - stv0900_write_reg(intp, SFRUP1, (symb >> 8) & 0x7f); - stv0900_write_reg(intp, SFRUP1 + 1, (symb & 0xff)); - } else { - stv0900_write_reg(intp, SFRUP1, 0x7f); - stv0900_write_reg(intp, SFRUP1 + 1, 0xff); - } -} - -static void stv0900_set_min_symbol_rate(struct stv0900_internal *intp, - u32 mclk, u32 srate, - enum fe_stv0900_demod_num demod) -{ - u32 symb; - - srate = 95 * (srate / 100); - if (srate > 60000000) { - symb = srate << 4; - symb /= (mclk >> 12); - - } else if (srate > 6000000) { - symb = srate << 6; - symb /= (mclk >> 10); - - } else { - symb = srate << 9; - symb /= (mclk >> 7); - } - - stv0900_write_reg(intp, SFRLOW1, (symb >> 8) & 0xff); - stv0900_write_reg(intp, SFRLOW1 + 1, (symb & 0xff)); -} - -static s32 stv0900_get_timing_offst(struct stv0900_internal *intp, - u32 srate, - enum fe_stv0900_demod_num demod) -{ - s32 timingoffset; - - - timingoffset = (stv0900_read_reg(intp, TMGREG2) << 16) + - (stv0900_read_reg(intp, TMGREG2 + 1) << 8) + - (stv0900_read_reg(intp, TMGREG2 + 2)); - - timingoffset = ge2comp(timingoffset, 24); - - - if (timingoffset == 0) - timingoffset = 1; - - timingoffset = ((s32)srate * 10) / ((s32)0x1000000 / timingoffset); - timingoffset /= 320; - - return timingoffset; -} - -static void stv0900_set_dvbs2_rolloff(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - s32 rolloff; - - if (intp->chip_id == 0x10) { - stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1); - rolloff = stv0900_read_reg(intp, MATSTR1) & 0x03; - stv0900_write_bits(intp, ROLLOFF_CONTROL, rolloff); - } else if (intp->chip_id <= 0x20) - stv0900_write_bits(intp, MANUALSX_ROLLOFF, 0); - else /* cut 3.0 */ - stv0900_write_bits(intp, MANUALS2_ROLLOFF, 0); -} - -static u32 stv0900_carrier_width(u32 srate, enum fe_stv0900_rolloff ro) -{ - u32 rolloff; - - switch (ro) { - case STV0900_20: - rolloff = 20; - break; - case STV0900_25: - rolloff = 25; - break; - case STV0900_35: - default: - rolloff = 35; - break; - } - - return srate + (srate * rolloff) / 100; -} - -static int stv0900_check_timing_lock(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - int timingLock = FALSE; - s32 i, - timingcpt = 0; - u8 car_freq, - tmg_th_high, - tmg_th_low; - - car_freq = stv0900_read_reg(intp, CARFREQ); - tmg_th_high = stv0900_read_reg(intp, TMGTHRISE); - tmg_th_low = stv0900_read_reg(intp, TMGTHFALL); - stv0900_write_reg(intp, TMGTHRISE, 0x20); - stv0900_write_reg(intp, TMGTHFALL, 0x0); - stv0900_write_bits(intp, CFR_AUTOSCAN, 0); - stv0900_write_reg(intp, RTC, 0x80); - stv0900_write_reg(intp, RTCS2, 0x40); - stv0900_write_reg(intp, CARFREQ, 0x0); - stv0900_write_reg(intp, CFRINIT1, 0x0); - stv0900_write_reg(intp, CFRINIT0, 0x0); - stv0900_write_reg(intp, AGC2REF, 0x65); - stv0900_write_reg(intp, DMDISTATE, 0x18); - msleep(7); - - for (i = 0; i < 10; i++) { - if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2) - timingcpt++; - - msleep(1); - } - - if (timingcpt >= 3) - timingLock = TRUE; - - stv0900_write_reg(intp, AGC2REF, 0x38); - stv0900_write_reg(intp, RTC, 0x88); - stv0900_write_reg(intp, RTCS2, 0x68); - stv0900_write_reg(intp, CARFREQ, car_freq); - stv0900_write_reg(intp, TMGTHRISE, tmg_th_high); - stv0900_write_reg(intp, TMGTHFALL, tmg_th_low); - - return timingLock; -} - -static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe, - s32 demod_timeout) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - int lock = FALSE, - d = demod; - s32 srate, - search_range, - locktimeout, - currier_step, - nb_steps, - current_step, - direction, - tuner_freq, - timeout, - freq; - - srate = intp->symbol_rate[d]; - search_range = intp->srch_range[d]; - - if (srate >= 10000000) - locktimeout = demod_timeout / 3; - else - locktimeout = demod_timeout / 2; - - lock = stv0900_get_demod_lock(intp, d, locktimeout); - - if (lock != FALSE) - return lock; - - if (srate >= 10000000) { - if (stv0900_check_timing_lock(intp, d) == TRUE) { - stv0900_write_reg(intp, DMDISTATE, 0x1f); - stv0900_write_reg(intp, DMDISTATE, 0x15); - lock = stv0900_get_demod_lock(intp, d, demod_timeout); - } else - lock = FALSE; - - return lock; - } - - if (intp->chip_id <= 0x20) { - if (srate <= 1000000) - currier_step = 500; - else if (srate <= 4000000) - currier_step = 1000; - else if (srate <= 7000000) - currier_step = 2000; - else if (srate <= 10000000) - currier_step = 3000; - else - currier_step = 5000; - - if (srate >= 2000000) { - timeout = (demod_timeout / 3); - if (timeout > 1000) - timeout = 1000; - } else - timeout = (demod_timeout / 2); - } else { - /*cut 3.0 */ - currier_step = srate / 4000; - timeout = (demod_timeout * 3) / 4; - } - - nb_steps = ((search_range / 1000) / currier_step); - - if ((nb_steps % 2) != 0) - nb_steps += 1; - - if (nb_steps <= 0) - nb_steps = 2; - else if (nb_steps > 12) - nb_steps = 12; - - current_step = 1; - direction = 1; - - if (intp->chip_id <= 0x20) { - tuner_freq = intp->freq[d]; - intp->bw[d] = stv0900_carrier_width(intp->symbol_rate[d], - intp->rolloff) + intp->symbol_rate[d]; - } else - tuner_freq = 0; - - while ((current_step <= nb_steps) && (lock == FALSE)) { - if (direction > 0) - tuner_freq += (current_step * currier_step); - else - tuner_freq -= (current_step * currier_step); - - if (intp->chip_id <= 0x20) { - if (intp->tuner_type[d] == 3) - stv0900_set_tuner_auto(intp, tuner_freq, - intp->bw[d], demod); - else - stv0900_set_tuner(fe, tuner_freq, intp->bw[d]); - - stv0900_write_reg(intp, DMDISTATE, 0x1c); - stv0900_write_reg(intp, CFRINIT1, 0); - stv0900_write_reg(intp, CFRINIT0, 0); - stv0900_write_reg(intp, DMDISTATE, 0x1f); - stv0900_write_reg(intp, DMDISTATE, 0x15); - } else { - stv0900_write_reg(intp, DMDISTATE, 0x1c); - freq = (tuner_freq * 65536) / (intp->mclk / 1000); - stv0900_write_bits(intp, CFR_INIT1, MSB(freq)); - stv0900_write_bits(intp, CFR_INIT0, LSB(freq)); - stv0900_write_reg(intp, DMDISTATE, 0x1f); - stv0900_write_reg(intp, DMDISTATE, 0x05); - } - - lock = stv0900_get_demod_lock(intp, d, timeout); - direction *= -1; - current_step++; - } - - return lock; -} - -static void stv0900_get_lock_timeout(s32 *demod_timeout, s32 *fec_timeout, - s32 srate, - enum fe_stv0900_search_algo algo) -{ - switch (algo) { - case STV0900_BLIND_SEARCH: - if (srate <= 1500000) { - (*demod_timeout) = 1500; - (*fec_timeout) = 400; - } else if (srate <= 5000000) { - (*demod_timeout) = 1000; - (*fec_timeout) = 300; - } else { - (*demod_timeout) = 700; - (*fec_timeout) = 100; - } - - break; - case STV0900_COLD_START: - case STV0900_WARM_START: - default: - if (srate <= 1000000) { - (*demod_timeout) = 3000; - (*fec_timeout) = 1700; - } else if (srate <= 2000000) { - (*demod_timeout) = 2500; - (*fec_timeout) = 1100; - } else if (srate <= 5000000) { - (*demod_timeout) = 1000; - (*fec_timeout) = 550; - } else if (srate <= 10000000) { - (*demod_timeout) = 700; - (*fec_timeout) = 250; - } else if (srate <= 20000000) { - (*demod_timeout) = 400; - (*fec_timeout) = 130; - } else { - (*demod_timeout) = 300; - (*fec_timeout) = 100; - } - - break; - - } - - if (algo == STV0900_WARM_START) - (*demod_timeout) /= 2; -} - -static void stv0900_set_viterbi_tracq(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - - s32 vth_reg = VTH12; - - dprintk("%s\n", __func__); - - stv0900_write_reg(intp, vth_reg++, 0xd0); - stv0900_write_reg(intp, vth_reg++, 0x7d); - stv0900_write_reg(intp, vth_reg++, 0x53); - stv0900_write_reg(intp, vth_reg++, 0x2f); - stv0900_write_reg(intp, vth_reg++, 0x24); - stv0900_write_reg(intp, vth_reg++, 0x1f); -} - -static void stv0900_set_viterbi_standard(struct stv0900_internal *intp, - enum fe_stv0900_search_standard standard, - enum fe_stv0900_fec fec, - enum fe_stv0900_demod_num demod) -{ - dprintk("%s: ViterbiStandard = ", __func__); - - switch (standard) { - case STV0900_AUTO_SEARCH: - dprintk("Auto\n"); - stv0900_write_reg(intp, FECM, 0x10); - stv0900_write_reg(intp, PRVIT, 0x3f); - break; - case STV0900_SEARCH_DVBS1: - dprintk("DVBS1\n"); - stv0900_write_reg(intp, FECM, 0x00); - switch (fec) { - case STV0900_FEC_UNKNOWN: - default: - stv0900_write_reg(intp, PRVIT, 0x2f); - break; - case STV0900_FEC_1_2: - stv0900_write_reg(intp, PRVIT, 0x01); - break; - case STV0900_FEC_2_3: - stv0900_write_reg(intp, PRVIT, 0x02); - break; - case STV0900_FEC_3_4: - stv0900_write_reg(intp, PRVIT, 0x04); - break; - case STV0900_FEC_5_6: - stv0900_write_reg(intp, PRVIT, 0x08); - break; - case STV0900_FEC_7_8: - stv0900_write_reg(intp, PRVIT, 0x20); - break; - } - - break; - case STV0900_SEARCH_DSS: - dprintk("DSS\n"); - stv0900_write_reg(intp, FECM, 0x80); - switch (fec) { - case STV0900_FEC_UNKNOWN: - default: - stv0900_write_reg(intp, PRVIT, 0x13); - break; - case STV0900_FEC_1_2: - stv0900_write_reg(intp, PRVIT, 0x01); - break; - case STV0900_FEC_2_3: - stv0900_write_reg(intp, PRVIT, 0x02); - break; - case STV0900_FEC_6_7: - stv0900_write_reg(intp, PRVIT, 0x10); - break; - } - break; - default: - break; - } -} - -static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - enum fe_stv0900_fec prate; - s32 rate_fld = stv0900_get_bits(intp, VIT_CURPUN); - - switch (rate_fld) { - case 13: - prate = STV0900_FEC_1_2; - break; - case 18: - prate = STV0900_FEC_2_3; - break; - case 21: - prate = STV0900_FEC_3_4; - break; - case 24: - prate = STV0900_FEC_5_6; - break; - case 25: - prate = STV0900_FEC_6_7; - break; - case 26: - prate = STV0900_FEC_7_8; - break; - default: - prate = STV0900_FEC_UNKNOWN; - break; - } - - return prate; -} - -static void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod, - u32 srate) -{ - if (intp->chip_id >= 0x30) { - if (srate >= 15000000) { - stv0900_write_reg(intp, ACLC, 0x2b); - stv0900_write_reg(intp, BCLC, 0x1a); - } else if ((srate >= 7000000) && (15000000 > srate)) { - stv0900_write_reg(intp, ACLC, 0x0c); - stv0900_write_reg(intp, BCLC, 0x1b); - } else if (srate < 7000000) { - stv0900_write_reg(intp, ACLC, 0x2c); - stv0900_write_reg(intp, BCLC, 0x1c); - } - - } else { /*cut 2.0 and 1.x*/ - stv0900_write_reg(intp, ACLC, 0x1a); - stv0900_write_reg(intp, BCLC, 0x09); - } - -} - -static void stv0900_track_optimization(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - - s32 srate, - pilots, - aclc, - freq1, - freq0, - i = 0, - timed, - timef, - blind_tun_sw = 0, - modulation; - - enum fe_stv0900_rolloff rolloff; - enum fe_stv0900_modcode foundModcod; - - dprintk("%s\n", __func__); - - srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); - srate += stv0900_get_timing_offst(intp, srate, demod); - - switch (intp->result[demod].standard) { - case STV0900_DVBS1_STANDARD: - case STV0900_DSS_STANDARD: - dprintk("%s: found DVB-S or DSS\n", __func__); - if (intp->srch_standard[demod] == STV0900_AUTO_SEARCH) { - stv0900_write_bits(intp, DVBS1_ENABLE, 1); - stv0900_write_bits(intp, DVBS2_ENABLE, 0); - } - - stv0900_write_bits(intp, ROLLOFF_CONTROL, intp->rolloff); - stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1); - - if (intp->chip_id < 0x30) { - stv0900_write_reg(intp, ERRCTRL1, 0x75); - break; - } - - if (stv0900_get_vit_fec(intp, demod) == STV0900_FEC_1_2) { - stv0900_write_reg(intp, GAUSSR0, 0x98); - stv0900_write_reg(intp, CCIR0, 0x18); - } else { - stv0900_write_reg(intp, GAUSSR0, 0x18); - stv0900_write_reg(intp, CCIR0, 0x18); - } - - stv0900_write_reg(intp, ERRCTRL1, 0x75); - break; - case STV0900_DVBS2_STANDARD: - dprintk("%s: found DVB-S2\n", __func__); - stv0900_write_bits(intp, DVBS1_ENABLE, 0); - stv0900_write_bits(intp, DVBS2_ENABLE, 1); - stv0900_write_reg(intp, ACLC, 0); - stv0900_write_reg(intp, BCLC, 0); - if (intp->result[demod].frame_len == STV0900_LONG_FRAME) { - foundModcod = stv0900_get_bits(intp, DEMOD_MODCOD); - pilots = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01; - aclc = stv0900_get_optim_carr_loop(srate, - foundModcod, - pilots, - intp->chip_id); - if (foundModcod <= STV0900_QPSK_910) - stv0900_write_reg(intp, ACLC2S2Q, aclc); - else if (foundModcod <= STV0900_8PSK_910) { - stv0900_write_reg(intp, ACLC2S2Q, 0x2a); - stv0900_write_reg(intp, ACLC2S28, aclc); - } - - if ((intp->demod_mode == STV0900_SINGLE) && - (foundModcod > STV0900_8PSK_910)) { - if (foundModcod <= STV0900_16APSK_910) { - stv0900_write_reg(intp, ACLC2S2Q, 0x2a); - stv0900_write_reg(intp, ACLC2S216A, - aclc); - } else if (foundModcod <= STV0900_32APSK_910) { - stv0900_write_reg(intp, ACLC2S2Q, 0x2a); - stv0900_write_reg(intp, ACLC2S232A, - aclc); - } - } - - } else { - modulation = intp->result[demod].modulation; - aclc = stv0900_get_optim_short_carr_loop(srate, - modulation, intp->chip_id); - if (modulation == STV0900_QPSK) - stv0900_write_reg(intp, ACLC2S2Q, aclc); - else if (modulation == STV0900_8PSK) { - stv0900_write_reg(intp, ACLC2S2Q, 0x2a); - stv0900_write_reg(intp, ACLC2S28, aclc); - } else if (modulation == STV0900_16APSK) { - stv0900_write_reg(intp, ACLC2S2Q, 0x2a); - stv0900_write_reg(intp, ACLC2S216A, aclc); - } else if (modulation == STV0900_32APSK) { - stv0900_write_reg(intp, ACLC2S2Q, 0x2a); - stv0900_write_reg(intp, ACLC2S232A, aclc); - } - - } - - if (intp->chip_id <= 0x11) { - if (intp->demod_mode != STV0900_SINGLE) - stv0900_activate_s2_modcod(intp, demod); - - } - - stv0900_write_reg(intp, ERRCTRL1, 0x67); - break; - case STV0900_UNKNOWN_STANDARD: - default: - dprintk("%s: found unknown standard\n", __func__); - stv0900_write_bits(intp, DVBS1_ENABLE, 1); - stv0900_write_bits(intp, DVBS2_ENABLE, 1); - break; - } - - freq1 = stv0900_read_reg(intp, CFR2); - freq0 = stv0900_read_reg(intp, CFR1); - rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS); - if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) { - stv0900_write_reg(intp, SFRSTEP, 0x00); - stv0900_write_bits(intp, SCAN_ENABLE, 0); - stv0900_write_bits(intp, CFR_AUTOSCAN, 0); - stv0900_write_reg(intp, TMGCFG2, 0xc1); - stv0900_set_symbol_rate(intp, intp->mclk, srate, demod); - blind_tun_sw = 1; - if (intp->result[demod].standard != STV0900_DVBS2_STANDARD) - stv0900_set_dvbs1_track_car_loop(intp, demod, srate); - - } - - if (intp->chip_id >= 0x20) { - if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) || - (intp->srch_standard[demod] == - STV0900_SEARCH_DSS) || - (intp->srch_standard[demod] == - STV0900_AUTO_SEARCH)) { - stv0900_write_reg(intp, VAVSRVIT, 0x0a); - stv0900_write_reg(intp, VITSCALE, 0x0); - } - } - - if (intp->chip_id < 0x20) - stv0900_write_reg(intp, CARHDR, 0x08); - - if (intp->chip_id == 0x10) - stv0900_write_reg(intp, CORRELEXP, 0x0a); - - stv0900_write_reg(intp, AGC2REF, 0x38); - - if ((intp->chip_id >= 0x20) || - (blind_tun_sw == 1) || - (intp->symbol_rate[demod] < 10000000)) { - stv0900_write_reg(intp, CFRINIT1, freq1); - stv0900_write_reg(intp, CFRINIT0, freq0); - intp->bw[demod] = stv0900_carrier_width(srate, - intp->rolloff) + 10000000; - - if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) { - if (intp->srch_algo[demod] != STV0900_WARM_START) { - if (intp->tuner_type[demod] == 3) - stv0900_set_tuner_auto(intp, - intp->freq[demod], - intp->bw[demod], - demod); - else - stv0900_set_bandwidth(fe, - intp->bw[demod]); - } - } - - if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) || - (intp->symbol_rate[demod] < 10000000)) - msleep(50); - else - msleep(5); - - stv0900_get_lock_timeout(&timed, &timef, srate, - STV0900_WARM_START); - - if (stv0900_get_demod_lock(intp, demod, timed / 2) == FALSE) { - stv0900_write_reg(intp, DMDISTATE, 0x1f); - stv0900_write_reg(intp, CFRINIT1, freq1); - stv0900_write_reg(intp, CFRINIT0, freq0); - stv0900_write_reg(intp, DMDISTATE, 0x18); - i = 0; - while ((stv0900_get_demod_lock(intp, - demod, - timed / 2) == FALSE) && - (i <= 2)) { - stv0900_write_reg(intp, DMDISTATE, 0x1f); - stv0900_write_reg(intp, CFRINIT1, freq1); - stv0900_write_reg(intp, CFRINIT0, freq0); - stv0900_write_reg(intp, DMDISTATE, 0x18); - i++; - } - } - - } - - if (intp->chip_id >= 0x20) - stv0900_write_reg(intp, CARFREQ, 0x49); - - if ((intp->result[demod].standard == STV0900_DVBS1_STANDARD) || - (intp->result[demod].standard == STV0900_DSS_STANDARD)) - stv0900_set_viterbi_tracq(intp, demod); - -} - -static int stv0900_get_fec_lock(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod, s32 time_out) -{ - s32 timer = 0, lock = 0; - - enum fe_stv0900_search_state dmd_state; - - dprintk("%s\n", __func__); - - dmd_state = stv0900_get_bits(intp, HEADER_MODE); - - while ((timer < time_out) && (lock == 0)) { - switch (dmd_state) { - case STV0900_SEARCH: - case STV0900_PLH_DETECTED: - default: - lock = 0; - break; - case STV0900_DVBS2_FOUND: - lock = stv0900_get_bits(intp, PKTDELIN_LOCK); - break; - case STV0900_DVBS_FOUND: - lock = stv0900_get_bits(intp, LOCKEDVIT); - break; - } - - if (lock == 0) { - msleep(10); - timer += 10; - } - } - - if (lock) - dprintk("%s: DEMOD FEC LOCK OK\n", __func__); - else - dprintk("%s: DEMOD FEC LOCK FAIL\n", __func__); - - return lock; -} - -static int stv0900_wait_for_lock(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod, - s32 dmd_timeout, s32 fec_timeout) -{ - - s32 timer = 0, lock = 0; - - dprintk("%s\n", __func__); - - lock = stv0900_get_demod_lock(intp, demod, dmd_timeout); - - if (lock) - lock = lock && stv0900_get_fec_lock(intp, demod, fec_timeout); - - if (lock) { - lock = 0; - - dprintk("%s: Timer = %d, time_out = %d\n", - __func__, timer, fec_timeout); - - while ((timer < fec_timeout) && (lock == 0)) { - lock = stv0900_get_bits(intp, TSFIFO_LINEOK); - msleep(1); - timer++; - } - } - - if (lock) - dprintk("%s: DEMOD LOCK OK\n", __func__); - else - dprintk("%s: DEMOD LOCK FAIL\n", __func__); - - if (lock) - return TRUE; - else - return FALSE; -} - -enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe, - enum fe_stv0900_demod_num demod) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_tracking_standard fnd_standard; - - int hdr_mode = stv0900_get_bits(intp, HEADER_MODE); - - switch (hdr_mode) { - case 2: - fnd_standard = STV0900_DVBS2_STANDARD; - break; - case 3: - if (stv0900_get_bits(intp, DSS_DVB) == 1) - fnd_standard = STV0900_DSS_STANDARD; - else - fnd_standard = STV0900_DVBS1_STANDARD; - - break; - default: - fnd_standard = STV0900_UNKNOWN_STANDARD; - } - - dprintk("%s: standard %d\n", __func__, fnd_standard); - - return fnd_standard; -} - -static s32 stv0900_get_carr_freq(struct stv0900_internal *intp, u32 mclk, - enum fe_stv0900_demod_num demod) -{ - s32 derot, - rem1, - rem2, - intval1, - intval2; - - derot = (stv0900_get_bits(intp, CAR_FREQ2) << 16) + - (stv0900_get_bits(intp, CAR_FREQ1) << 8) + - (stv0900_get_bits(intp, CAR_FREQ0)); - - derot = ge2comp(derot, 24); - intval1 = mclk >> 12; - intval2 = derot >> 12; - rem1 = mclk % 0x1000; - rem2 = derot % 0x1000; - derot = (intval1 * intval2) + - ((intval1 * rem2) >> 12) + - ((intval2 * rem1) >> 12); - - return derot; -} - -static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - u32 freq = 0; - - if (&fe->ops) - frontend_ops = &fe->ops; - - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - - if (tuner_ops->get_frequency) { - if ((tuner_ops->get_frequency(fe, &freq)) < 0) - dprintk("%s: Invalid parameter\n", __func__); - else - dprintk("%s: Frequency=%d\n", __func__, freq); - - } - - return freq; -} - -static enum -fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - enum fe_stv0900_signal_type range = STV0900_OUTOFRANGE; - struct stv0900_signal_info *result = &intp->result[demod]; - s32 offsetFreq, - srate_offset; - int i = 0, - d = demod; - - u8 timing; - - msleep(5); - if (intp->srch_algo[d] == STV0900_BLIND_SEARCH) { - timing = stv0900_read_reg(intp, TMGREG2); - i = 0; - stv0900_write_reg(intp, SFRSTEP, 0x5c); - - while ((i <= 50) && (timing != 0) && (timing != 0xff)) { - timing = stv0900_read_reg(intp, TMGREG2); - msleep(5); - i += 5; - } - } - - result->standard = stv0900_get_standard(fe, d); - if (intp->tuner_type[demod] == 3) - result->frequency = stv0900_get_freq_auto(intp, d); - else - result->frequency = stv0900_get_tuner_freq(fe); - - offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000; - result->frequency += offsetFreq; - result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d); - srate_offset = stv0900_get_timing_offst(intp, result->symbol_rate, d); - result->symbol_rate += srate_offset; - result->fec = stv0900_get_vit_fec(intp, d); - result->modcode = stv0900_get_bits(intp, DEMOD_MODCOD); - result->pilot = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01; - result->frame_len = ((u32)stv0900_get_bits(intp, DEMOD_TYPE)) >> 1; - result->rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS); - - dprintk("%s: modcode=0x%x \n", __func__, result->modcode); - - switch (result->standard) { - case STV0900_DVBS2_STANDARD: - result->spectrum = stv0900_get_bits(intp, SPECINV_DEMOD); - if (result->modcode <= STV0900_QPSK_910) - result->modulation = STV0900_QPSK; - else if (result->modcode <= STV0900_8PSK_910) - result->modulation = STV0900_8PSK; - else if (result->modcode <= STV0900_16APSK_910) - result->modulation = STV0900_16APSK; - else if (result->modcode <= STV0900_32APSK_910) - result->modulation = STV0900_32APSK; - else - result->modulation = STV0900_UNKNOWN; - break; - case STV0900_DVBS1_STANDARD: - case STV0900_DSS_STANDARD: - result->spectrum = stv0900_get_bits(intp, IQINV); - result->modulation = STV0900_QPSK; - break; - default: - break; - } - - if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) || - (intp->symbol_rate[d] < 10000000)) { - offsetFreq = result->frequency - intp->freq[d]; - if (intp->tuner_type[demod] == 3) - intp->freq[d] = stv0900_get_freq_auto(intp, d); - else - intp->freq[d] = stv0900_get_tuner_freq(fe); - - if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) - range = STV0900_RANGEOK; - else if (ABS(offsetFreq) <= - (stv0900_carrier_width(result->symbol_rate, - result->rolloff) / 2000)) - range = STV0900_RANGEOK; - - } else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) - range = STV0900_RANGEOK; - - dprintk("%s: range %d\n", __func__, range); - - return range; -} - -static enum -fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - enum fe_stv0900_signal_type signal_type = STV0900_NODATA; - - s32 srate, - demod_timeout, - fec_timeout, - freq1, - freq0; - - intp->result[demod].locked = FALSE; - - if (stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) { - srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); - srate += stv0900_get_timing_offst(intp, srate, demod); - if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) - stv0900_set_symbol_rate(intp, intp->mclk, srate, demod); - - stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, - srate, STV0900_WARM_START); - freq1 = stv0900_read_reg(intp, CFR2); - freq0 = stv0900_read_reg(intp, CFR1); - stv0900_write_bits(intp, CFR_AUTOSCAN, 0); - stv0900_write_bits(intp, SPECINV_CONTROL, - STV0900_IQ_FORCE_SWAPPED); - stv0900_write_reg(intp, DMDISTATE, 0x1c); - stv0900_write_reg(intp, CFRINIT1, freq1); - stv0900_write_reg(intp, CFRINIT0, freq0); - stv0900_write_reg(intp, DMDISTATE, 0x18); - if (stv0900_wait_for_lock(intp, demod, - demod_timeout, fec_timeout) == TRUE) { - intp->result[demod].locked = TRUE; - signal_type = stv0900_get_signal_params(fe); - stv0900_track_optimization(fe); - } else { - stv0900_write_bits(intp, SPECINV_CONTROL, - STV0900_IQ_FORCE_NORMAL); - stv0900_write_reg(intp, DMDISTATE, 0x1c); - stv0900_write_reg(intp, CFRINIT1, freq1); - stv0900_write_reg(intp, CFRINIT0, freq0); - stv0900_write_reg(intp, DMDISTATE, 0x18); - if (stv0900_wait_for_lock(intp, demod, - demod_timeout, fec_timeout) == TRUE) { - intp->result[demod].locked = TRUE; - signal_type = stv0900_get_signal_params(fe); - stv0900_track_optimization(fe); - } - - } - - } else - intp->result[demod].locked = FALSE; - - return signal_type; -} - -static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - u32 minagc2level = 0xffff, - agc2level, - init_freq, freq_step; - - s32 i, j, nb_steps, direction; - - dprintk("%s\n", __func__); - - stv0900_write_reg(intp, AGC2REF, 0x38); - stv0900_write_bits(intp, SCAN_ENABLE, 0); - stv0900_write_bits(intp, CFR_AUTOSCAN, 0); - - stv0900_write_bits(intp, AUTO_GUP, 1); - stv0900_write_bits(intp, AUTO_GLOW, 1); - - stv0900_write_reg(intp, DMDT0M, 0x0); - - stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod); - nb_steps = -1 + (intp->srch_range[demod] / 1000000); - nb_steps /= 2; - nb_steps = (2 * nb_steps) + 1; - - if (nb_steps < 0) - nb_steps = 1; - - direction = 1; - - freq_step = (1000000 << 8) / (intp->mclk >> 8); - - init_freq = 0; - - for (i = 0; i < nb_steps; i++) { - if (direction > 0) - init_freq = init_freq + (freq_step * i); - else - init_freq = init_freq - (freq_step * i); - - direction *= -1; - stv0900_write_reg(intp, DMDISTATE, 0x5C); - stv0900_write_reg(intp, CFRINIT1, (init_freq >> 8) & 0xff); - stv0900_write_reg(intp, CFRINIT0, init_freq & 0xff); - stv0900_write_reg(intp, DMDISTATE, 0x58); - msleep(10); - agc2level = 0; - - for (j = 0; j < 10; j++) - agc2level += (stv0900_read_reg(intp, AGC2I1) << 8) - | stv0900_read_reg(intp, AGC2I0); - - agc2level /= 10; - - if (agc2level < minagc2level) - minagc2level = agc2level; - - } - - return (u16)minagc2level; -} - -static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - int timing_lck = FALSE; - s32 i, timingcpt = 0, - direction = 1, - nb_steps, - current_step = 0, - tuner_freq; - u32 agc2_th, - coarse_srate = 0, - agc2_integr = 0, - currier_step = 1200; - - if (intp->chip_id >= 0x30) - agc2_th = 0x2e00; - else - agc2_th = 0x1f00; - - stv0900_write_bits(intp, DEMOD_MODE, 0x1f); - stv0900_write_reg(intp, TMGCFG, 0x12); - stv0900_write_reg(intp, TMGTHRISE, 0xf0); - stv0900_write_reg(intp, TMGTHFALL, 0xe0); - stv0900_write_bits(intp, SCAN_ENABLE, 1); - stv0900_write_bits(intp, CFR_AUTOSCAN, 1); - stv0900_write_reg(intp, SFRUP1, 0x83); - stv0900_write_reg(intp, SFRUP0, 0xc0); - stv0900_write_reg(intp, SFRLOW1, 0x82); - stv0900_write_reg(intp, SFRLOW0, 0xa0); - stv0900_write_reg(intp, DMDT0M, 0x0); - stv0900_write_reg(intp, AGC2REF, 0x50); - - if (intp->chip_id >= 0x30) { - stv0900_write_reg(intp, CARFREQ, 0x99); - stv0900_write_reg(intp, SFRSTEP, 0x98); - } else if (intp->chip_id >= 0x20) { - stv0900_write_reg(intp, CARFREQ, 0x6a); - stv0900_write_reg(intp, SFRSTEP, 0x95); - } else { - stv0900_write_reg(intp, CARFREQ, 0xed); - stv0900_write_reg(intp, SFRSTEP, 0x73); - } - - if (intp->symbol_rate[demod] <= 2000000) - currier_step = 1000; - else if (intp->symbol_rate[demod] <= 5000000) - currier_step = 2000; - else if (intp->symbol_rate[demod] <= 12000000) - currier_step = 3000; - else - currier_step = 5000; - - nb_steps = -1 + ((intp->srch_range[demod] / 1000) / currier_step); - nb_steps /= 2; - nb_steps = (2 * nb_steps) + 1; - - if (nb_steps < 0) - nb_steps = 1; - else if (nb_steps > 10) { - nb_steps = 11; - currier_step = (intp->srch_range[demod] / 1000) / 10; - } - - current_step = 0; - direction = 1; - - tuner_freq = intp->freq[demod]; - - while ((timing_lck == FALSE) && (current_step < nb_steps)) { - stv0900_write_reg(intp, DMDISTATE, 0x5f); - stv0900_write_bits(intp, DEMOD_MODE, 0); - - msleep(50); - - for (i = 0; i < 10; i++) { - if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2) - timingcpt++; - - agc2_integr += (stv0900_read_reg(intp, AGC2I1) << 8) | - stv0900_read_reg(intp, AGC2I0); - } - - agc2_integr /= 10; - coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); - current_step++; - direction *= -1; - - dprintk("lock: I2C_DEMOD_MODE_FIELD =0. Search started." - " tuner freq=%d agc2=0x%x srate_coarse=%d tmg_cpt=%d\n", - tuner_freq, agc2_integr, coarse_srate, timingcpt); - - if ((timingcpt >= 5) && - (agc2_integr < agc2_th) && - (coarse_srate < 55000000) && - (coarse_srate > 850000)) - timing_lck = TRUE; - else if (current_step < nb_steps) { - if (direction > 0) - tuner_freq += (current_step * currier_step); - else - tuner_freq -= (current_step * currier_step); - - if (intp->tuner_type[demod] == 3) - stv0900_set_tuner_auto(intp, tuner_freq, - intp->bw[demod], demod); - else - stv0900_set_tuner(fe, tuner_freq, - intp->bw[demod]); - } - } - - if (timing_lck == FALSE) - coarse_srate = 0; - else - coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); - - return coarse_srate; -} - -static u32 stv0900_search_srate_fine(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - u32 coarse_srate, - coarse_freq, - symb, - symbmax, - symbmin, - symbcomp; - - coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); - - if (coarse_srate > 3000000) { - symbmax = 13 * (coarse_srate / 10); - symbmax = (symbmax / 1000) * 65536; - symbmax /= (intp->mclk / 1000); - - symbmin = 10 * (coarse_srate / 13); - symbmin = (symbmin / 1000)*65536; - symbmin /= (intp->mclk / 1000); - - symb = (coarse_srate / 1000) * 65536; - symb /= (intp->mclk / 1000); - } else { - symbmax = 13 * (coarse_srate / 10); - symbmax = (symbmax / 100) * 65536; - symbmax /= (intp->mclk / 100); - - symbmin = 10 * (coarse_srate / 14); - symbmin = (symbmin / 100) * 65536; - symbmin /= (intp->mclk / 100); - - symb = (coarse_srate / 100) * 65536; - symb /= (intp->mclk / 100); - } - - symbcomp = 13 * (coarse_srate / 10); - coarse_freq = (stv0900_read_reg(intp, CFR2) << 8) - | stv0900_read_reg(intp, CFR1); - - if (symbcomp < intp->symbol_rate[demod]) - coarse_srate = 0; - else { - stv0900_write_reg(intp, DMDISTATE, 0x1f); - stv0900_write_reg(intp, TMGCFG2, 0xc1); - stv0900_write_reg(intp, TMGTHRISE, 0x20); - stv0900_write_reg(intp, TMGTHFALL, 0x00); - stv0900_write_reg(intp, TMGCFG, 0xd2); - stv0900_write_bits(intp, CFR_AUTOSCAN, 0); - stv0900_write_reg(intp, AGC2REF, 0x38); - - if (intp->chip_id >= 0x30) - stv0900_write_reg(intp, CARFREQ, 0x79); - else if (intp->chip_id >= 0x20) - stv0900_write_reg(intp, CARFREQ, 0x49); - else - stv0900_write_reg(intp, CARFREQ, 0xed); - - stv0900_write_reg(intp, SFRUP1, (symbmax >> 8) & 0x7f); - stv0900_write_reg(intp, SFRUP0, (symbmax & 0xff)); - - stv0900_write_reg(intp, SFRLOW1, (symbmin >> 8) & 0x7f); - stv0900_write_reg(intp, SFRLOW0, (symbmin & 0xff)); - - stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0xff); - stv0900_write_reg(intp, SFRINIT0, (symb & 0xff)); - - stv0900_write_reg(intp, DMDT0M, 0x20); - stv0900_write_reg(intp, CFRINIT1, (coarse_freq >> 8) & 0xff); - stv0900_write_reg(intp, CFRINIT0, coarse_freq & 0xff); - stv0900_write_reg(intp, DMDISTATE, 0x15); - } - - return coarse_srate; -} - -static int stv0900_blind_search_algo(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - u8 k_ref_tmg, - k_ref_tmg_max, - k_ref_tmg_min; - u32 coarse_srate, - agc2_th; - int lock = FALSE, - coarse_fail = FALSE; - s32 demod_timeout = 500, - fec_timeout = 50, - fail_cpt, - i, - agc2_overflow; - u16 agc2_int; - u8 dstatus2; - - dprintk("%s\n", __func__); - - if (intp->chip_id < 0x20) { - k_ref_tmg_max = 233; - k_ref_tmg_min = 143; - } else { - k_ref_tmg_max = 110; - k_ref_tmg_min = 10; - } - - if (intp->chip_id <= 0x20) - agc2_th = STV0900_BLIND_SEARCH_AGC2_TH; - else - agc2_th = STV0900_BLIND_SEARCH_AGC2_TH_CUT30; - - agc2_int = stv0900_blind_check_agc2_min_level(intp, demod); - - dprintk("%s agc2_int=%d agc2_th=%d \n", __func__, agc2_int, agc2_th); - if (agc2_int > agc2_th) - return FALSE; - - if (intp->chip_id == 0x10) - stv0900_write_reg(intp, CORRELEXP, 0xaa); - - if (intp->chip_id < 0x20) - stv0900_write_reg(intp, CARHDR, 0x55); - else - stv0900_write_reg(intp, CARHDR, 0x20); - - if (intp->chip_id <= 0x20) - stv0900_write_reg(intp, CARCFG, 0xc4); - else - stv0900_write_reg(intp, CARCFG, 0x6); - - stv0900_write_reg(intp, RTCS2, 0x44); - - if (intp->chip_id >= 0x20) { - stv0900_write_reg(intp, EQUALCFG, 0x41); - stv0900_write_reg(intp, FFECFG, 0x41); - stv0900_write_reg(intp, VITSCALE, 0x82); - stv0900_write_reg(intp, VAVSRVIT, 0x0); - } - - k_ref_tmg = k_ref_tmg_max; - - do { - stv0900_write_reg(intp, KREFTMG, k_ref_tmg); - if (stv0900_search_srate_coarse(fe) != 0) { - coarse_srate = stv0900_search_srate_fine(fe); - - if (coarse_srate != 0) { - stv0900_get_lock_timeout(&demod_timeout, - &fec_timeout, - coarse_srate, - STV0900_BLIND_SEARCH); - lock = stv0900_get_demod_lock(intp, - demod, - demod_timeout); - } else - lock = FALSE; - } else { - fail_cpt = 0; - agc2_overflow = 0; - - for (i = 0; i < 10; i++) { - agc2_int = (stv0900_read_reg(intp, AGC2I1) << 8) - | stv0900_read_reg(intp, AGC2I0); - - if (agc2_int >= 0xff00) - agc2_overflow++; - - dstatus2 = stv0900_read_reg(intp, DSTATUS2); - - if (((dstatus2 & 0x1) == 0x1) && - ((dstatus2 >> 7) == 1)) - fail_cpt++; - } - - if ((fail_cpt > 7) || (agc2_overflow > 7)) - coarse_fail = TRUE; - - lock = FALSE; - } - k_ref_tmg -= 30; - } while ((k_ref_tmg >= k_ref_tmg_min) && - (lock == FALSE) && - (coarse_fail == FALSE)); - - return lock; -} - -static void stv0900_set_viterbi_acq(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - s32 vth_reg = VTH12; - - dprintk("%s\n", __func__); - - stv0900_write_reg(intp, vth_reg++, 0x96); - stv0900_write_reg(intp, vth_reg++, 0x64); - stv0900_write_reg(intp, vth_reg++, 0x36); - stv0900_write_reg(intp, vth_reg++, 0x23); - stv0900_write_reg(intp, vth_reg++, 0x1e); - stv0900_write_reg(intp, vth_reg++, 0x19); -} - -static void stv0900_set_search_standard(struct stv0900_internal *intp, - enum fe_stv0900_demod_num demod) -{ - - dprintk("%s\n", __func__); - - switch (intp->srch_standard[demod]) { - case STV0900_SEARCH_DVBS1: - dprintk("Search Standard = DVBS1\n"); - break; - case STV0900_SEARCH_DSS: - dprintk("Search Standard = DSS\n"); - case STV0900_SEARCH_DVBS2: - break; - dprintk("Search Standard = DVBS2\n"); - case STV0900_AUTO_SEARCH: - default: - dprintk("Search Standard = AUTO\n"); - break; - } - - switch (intp->srch_standard[demod]) { - case STV0900_SEARCH_DVBS1: - case STV0900_SEARCH_DSS: - stv0900_write_bits(intp, DVBS1_ENABLE, 1); - stv0900_write_bits(intp, DVBS2_ENABLE, 0); - stv0900_write_bits(intp, STOP_CLKVIT, 0); - stv0900_set_dvbs1_track_car_loop(intp, - demod, - intp->symbol_rate[demod]); - stv0900_write_reg(intp, CAR2CFG, 0x22); - - stv0900_set_viterbi_acq(intp, demod); - stv0900_set_viterbi_standard(intp, - intp->srch_standard[demod], - intp->fec[demod], demod); - - break; - case STV0900_SEARCH_DVBS2: - stv0900_write_bits(intp, DVBS1_ENABLE, 0); - stv0900_write_bits(intp, DVBS2_ENABLE, 1); - stv0900_write_bits(intp, STOP_CLKVIT, 1); - stv0900_write_reg(intp, ACLC, 0x1a); - stv0900_write_reg(intp, BCLC, 0x09); - if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/ - stv0900_write_reg(intp, CAR2CFG, 0x26); - else - stv0900_write_reg(intp, CAR2CFG, 0x66); - - if (intp->demod_mode != STV0900_SINGLE) { - if (intp->chip_id <= 0x11) - stv0900_stop_all_s2_modcod(intp, demod); - else - stv0900_activate_s2_modcod(intp, demod); - - } else - stv0900_activate_s2_modcod_single(intp, demod); - - stv0900_set_viterbi_tracq(intp, demod); - - break; - case STV0900_AUTO_SEARCH: - default: - stv0900_write_bits(intp, DVBS1_ENABLE, 1); - stv0900_write_bits(intp, DVBS2_ENABLE, 1); - stv0900_write_bits(intp, STOP_CLKVIT, 0); - stv0900_write_reg(intp, ACLC, 0x1a); - stv0900_write_reg(intp, BCLC, 0x09); - stv0900_set_dvbs1_track_car_loop(intp, - demod, - intp->symbol_rate[demod]); - if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/ - stv0900_write_reg(intp, CAR2CFG, 0x26); - else - stv0900_write_reg(intp, CAR2CFG, 0x66); - - if (intp->demod_mode != STV0900_SINGLE) { - if (intp->chip_id <= 0x11) - stv0900_stop_all_s2_modcod(intp, demod); - else - stv0900_activate_s2_modcod(intp, demod); - - } else - stv0900_activate_s2_modcod_single(intp, demod); - - stv0900_set_viterbi_tracq(intp, demod); - stv0900_set_viterbi_standard(intp, - intp->srch_standard[demod], - intp->fec[demod], demod); - - break; - } -} - -enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe) -{ - struct stv0900_state *state = fe->demodulator_priv; - struct stv0900_internal *intp = state->internal; - enum fe_stv0900_demod_num demod = state->demod; - - s32 demod_timeout = 500, fec_timeout = 50; - s32 aq_power, agc1_power, i; - - int lock = FALSE, low_sr = FALSE; - - enum fe_stv0900_signal_type signal_type = STV0900_NOCARRIER; - enum fe_stv0900_search_algo algo; - int no_signal = FALSE; - - dprintk("%s\n", __func__); - - algo = intp->srch_algo[demod]; - stv0900_write_bits(intp, RST_HWARE, 1); - stv0900_write_reg(intp, DMDISTATE, 0x5c); - if (intp->chip_id >= 0x20) { - if (intp->symbol_rate[demod] > 5000000) - stv0900_write_reg(intp, CORRELABS, 0x9e); - else - stv0900_write_reg(intp, CORRELABS, 0x82); - } else - stv0900_write_reg(intp, CORRELABS, 0x88); - - stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, - intp->symbol_rate[demod], - intp->srch_algo[demod]); - - if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) { - intp->bw[demod] = 2 * 36000000; - - stv0900_write_reg(intp, TMGCFG2, 0xc0); - stv0900_write_reg(intp, CORRELMANT, 0x70); - - stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod); - } else { - stv0900_write_reg(intp, DMDT0M, 0x20); - stv0900_write_reg(intp, TMGCFG, 0xd2); - - if (intp->symbol_rate[demod] < 2000000) - stv0900_write_reg(intp, CORRELMANT, 0x63); - else - stv0900_write_reg(intp, CORRELMANT, 0x70); - - stv0900_write_reg(intp, AGC2REF, 0x38); - - intp->bw[demod] = - stv0900_carrier_width(intp->symbol_rate[demod], - intp->rolloff); - if (intp->chip_id >= 0x20) { - stv0900_write_reg(intp, KREFTMG, 0x5a); - - if (intp->srch_algo[demod] == STV0900_COLD_START) { - intp->bw[demod] += 10000000; - intp->bw[demod] *= 15; - intp->bw[demod] /= 10; - } else if (intp->srch_algo[demod] == STV0900_WARM_START) - intp->bw[demod] += 10000000; - - } else { - stv0900_write_reg(intp, KREFTMG, 0xc1); - intp->bw[demod] += 10000000; - intp->bw[demod] *= 15; - intp->bw[demod] /= 10; - } - - stv0900_write_reg(intp, TMGCFG2, 0xc1); - - stv0900_set_symbol_rate(intp, intp->mclk, - intp->symbol_rate[demod], demod); - stv0900_set_max_symbol_rate(intp, intp->mclk, - intp->symbol_rate[demod], demod); - stv0900_set_min_symbol_rate(intp, intp->mclk, - intp->symbol_rate[demod], demod); - if (intp->symbol_rate[demod] >= 10000000) - low_sr = FALSE; - else - low_sr = TRUE; - - } - - if (intp->tuner_type[demod] == 3) - stv0900_set_tuner_auto(intp, intp->freq[demod], - intp->bw[demod], demod); - else - stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]); - - agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1), - stv0900_get_bits(intp, AGCIQ_VALUE0)); - - aq_power = 0; - - if (agc1_power == 0) { - for (i = 0; i < 5; i++) - aq_power += (stv0900_get_bits(intp, POWER_I) + - stv0900_get_bits(intp, POWER_Q)) / 2; - - aq_power /= 5; - } - - if ((agc1_power == 0) && (aq_power < IQPOWER_THRESHOLD)) { - intp->result[demod].locked = FALSE; - signal_type = STV0900_NOAGC1; - dprintk("%s: NO AGC1, POWERI, POWERQ\n", __func__); - } else { - stv0900_write_bits(intp, SPECINV_CONTROL, - intp->srch_iq_inv[demod]); - if (intp->chip_id <= 0x20) /*cut 2.0*/ - stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1); - else /*cut 3.0*/ - stv0900_write_bits(intp, MANUALS2_ROLLOFF, 1); - - stv0900_set_search_standard(intp, demod); - - if (intp->srch_algo[demod] != STV0900_BLIND_SEARCH) - stv0900_start_search(intp, demod); - } - - if (signal_type == STV0900_NOAGC1) - return signal_type; - - if (intp->chip_id == 0x12) { - stv0900_write_bits(intp, RST_HWARE, 0); - msleep(3); - stv0900_write_bits(intp, RST_HWARE, 1); - stv0900_write_bits(intp, RST_HWARE, 0); - } - - if (algo == STV0900_BLIND_SEARCH) - lock = stv0900_blind_search_algo(fe); - else if (algo == STV0900_COLD_START) - lock = stv0900_get_demod_cold_lock(fe, demod_timeout); - else if (algo == STV0900_WARM_START) - lock = stv0900_get_demod_lock(intp, demod, demod_timeout); - - if ((lock == FALSE) && (algo == STV0900_COLD_START)) { - if (low_sr == FALSE) { - if (stv0900_check_timing_lock(intp, demod) == TRUE) - lock = stv0900_sw_algo(intp, demod); - } - } - - if (lock == TRUE) - signal_type = stv0900_get_signal_params(fe); - - if ((lock == TRUE) && (signal_type == STV0900_RANGEOK)) { - stv0900_track_optimization(fe); - if (intp->chip_id <= 0x11) { - if ((stv0900_get_standard(fe, 0) == - STV0900_DVBS1_STANDARD) && - (stv0900_get_standard(fe, 1) == - STV0900_DVBS1_STANDARD)) { - msleep(20); - stv0900_write_bits(intp, RST_HWARE, 0); - } else { - stv0900_write_bits(intp, RST_HWARE, 0); - msleep(3); - stv0900_write_bits(intp, RST_HWARE, 1); - stv0900_write_bits(intp, RST_HWARE, 0); - } - - } else if (intp->chip_id >= 0x20) { - stv0900_write_bits(intp, RST_HWARE, 0); - msleep(3); - stv0900_write_bits(intp, RST_HWARE, 1); - stv0900_write_bits(intp, RST_HWARE, 0); - } - - if (stv0900_wait_for_lock(intp, demod, - fec_timeout, fec_timeout) == TRUE) { - lock = TRUE; - intp->result[demod].locked = TRUE; - if (intp->result[demod].standard == - STV0900_DVBS2_STANDARD) { - stv0900_set_dvbs2_rolloff(intp, demod); - stv0900_write_bits(intp, RESET_UPKO_COUNT, 1); - stv0900_write_bits(intp, RESET_UPKO_COUNT, 0); - stv0900_write_reg(intp, ERRCTRL1, 0x67); - } else { - stv0900_write_reg(intp, ERRCTRL1, 0x75); - } - - stv0900_write_reg(intp, FBERCPT4, 0); - stv0900_write_reg(intp, ERRCTRL2, 0xc1); - } else { - lock = FALSE; - signal_type = STV0900_NODATA; - no_signal = stv0900_check_signal_presence(intp, demod); - - intp->result[demod].locked = FALSE; - } - } - - if ((signal_type != STV0900_NODATA) || (no_signal != FALSE)) - return signal_type; - - if (intp->chip_id > 0x11) { - intp->result[demod].locked = FALSE; - return signal_type; - } - - if ((stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) && - (intp->srch_iq_inv[demod] <= STV0900_IQ_AUTO_NORMAL_FIRST)) - signal_type = stv0900_dvbs1_acq_workaround(fe); - - return signal_type; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,4831 +0,0 @@ -/* - STV0900/0903 Multistandard Broadcast Frontend driver - Copyright (C) Manu Abraham - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include - -#include -#include "dvb_frontend.h" - -#include "stv6110x.h" /* for demodulator internal modes */ - -#include "stv090x_reg.h" -#include "stv090x.h" -#include "stv090x_priv.h" - -static unsigned int verbose; -module_param(verbose, int, 0644); - -/* internal params node */ -struct stv090x_dev { - /* pointer for internal params, one for each pair of demods */ - struct stv090x_internal *internal; - struct stv090x_dev *next_dev; -}; - -/* first internal params */ -static struct stv090x_dev *stv090x_first_dev; - -/* find chip by i2c adapter and i2c address */ -static struct stv090x_dev *find_dev(struct i2c_adapter *i2c_adap, - u8 i2c_addr) -{ - struct stv090x_dev *temp_dev = stv090x_first_dev; - - /* - Search of the last stv0900 chip or - find it by i2c adapter and i2c address */ - while ((temp_dev != NULL) && - ((temp_dev->internal->i2c_adap != i2c_adap) || - (temp_dev->internal->i2c_addr != i2c_addr))) { - - temp_dev = temp_dev->next_dev; - } - - return temp_dev; -} - -/* deallocating chip */ -static void remove_dev(struct stv090x_internal *internal) -{ - struct stv090x_dev *prev_dev = stv090x_first_dev; - struct stv090x_dev *del_dev = find_dev(internal->i2c_adap, - internal->i2c_addr); - - if (del_dev != NULL) { - if (del_dev == stv090x_first_dev) { - stv090x_first_dev = del_dev->next_dev; - } else { - while (prev_dev->next_dev != del_dev) - prev_dev = prev_dev->next_dev; - - prev_dev->next_dev = del_dev->next_dev; - } - - kfree(del_dev); - } -} - -/* allocating new chip */ -static struct stv090x_dev *append_internal(struct stv090x_internal *internal) -{ - struct stv090x_dev *new_dev; - struct stv090x_dev *temp_dev; - - new_dev = kmalloc(sizeof(struct stv090x_dev), GFP_KERNEL); - if (new_dev != NULL) { - new_dev->internal = internal; - new_dev->next_dev = NULL; - - /* append to list */ - if (stv090x_first_dev == NULL) { - stv090x_first_dev = new_dev; - } else { - temp_dev = stv090x_first_dev; - while (temp_dev->next_dev != NULL) - temp_dev = temp_dev->next_dev; - - temp_dev->next_dev = new_dev; - } - } - - return new_dev; -} - - -/* DVBS1 and DSS C/N Lookup table */ -static const struct stv090x_tab stv090x_s1cn_tab[] = { - { 0, 8917 }, /* 0.0dB */ - { 5, 8801 }, /* 0.5dB */ - { 10, 8667 }, /* 1.0dB */ - { 15, 8522 }, /* 1.5dB */ - { 20, 8355 }, /* 2.0dB */ - { 25, 8175 }, /* 2.5dB */ - { 30, 7979 }, /* 3.0dB */ - { 35, 7763 }, /* 3.5dB */ - { 40, 7530 }, /* 4.0dB */ - { 45, 7282 }, /* 4.5dB */ - { 50, 7026 }, /* 5.0dB */ - { 55, 6781 }, /* 5.5dB */ - { 60, 6514 }, /* 6.0dB */ - { 65, 6241 }, /* 6.5dB */ - { 70, 5965 }, /* 7.0dB */ - { 75, 5690 }, /* 7.5dB */ - { 80, 5424 }, /* 8.0dB */ - { 85, 5161 }, /* 8.5dB */ - { 90, 4902 }, /* 9.0dB */ - { 95, 4654 }, /* 9.5dB */ - { 100, 4417 }, /* 10.0dB */ - { 105, 4186 }, /* 10.5dB */ - { 110, 3968 }, /* 11.0dB */ - { 115, 3757 }, /* 11.5dB */ - { 120, 3558 }, /* 12.0dB */ - { 125, 3366 }, /* 12.5dB */ - { 130, 3185 }, /* 13.0dB */ - { 135, 3012 }, /* 13.5dB */ - { 140, 2850 }, /* 14.0dB */ - { 145, 2698 }, /* 14.5dB */ - { 150, 2550 }, /* 15.0dB */ - { 160, 2283 }, /* 16.0dB */ - { 170, 2042 }, /* 17.0dB */ - { 180, 1827 }, /* 18.0dB */ - { 190, 1636 }, /* 19.0dB */ - { 200, 1466 }, /* 20.0dB */ - { 210, 1315 }, /* 21.0dB */ - { 220, 1181 }, /* 22.0dB */ - { 230, 1064 }, /* 23.0dB */ - { 240, 960 }, /* 24.0dB */ - { 250, 869 }, /* 25.0dB */ - { 260, 792 }, /* 26.0dB */ - { 270, 724 }, /* 27.0dB */ - { 280, 665 }, /* 28.0dB */ - { 290, 616 }, /* 29.0dB */ - { 300, 573 }, /* 30.0dB */ - { 310, 537 }, /* 31.0dB */ - { 320, 507 }, /* 32.0dB */ - { 330, 483 }, /* 33.0dB */ - { 400, 398 }, /* 40.0dB */ - { 450, 381 }, /* 45.0dB */ - { 500, 377 } /* 50.0dB */ -}; - -/* DVBS2 C/N Lookup table */ -static const struct stv090x_tab stv090x_s2cn_tab[] = { - { -30, 13348 }, /* -3.0dB */ - { -20, 12640 }, /* -2d.0B */ - { -10, 11883 }, /* -1.0dB */ - { 0, 11101 }, /* -0.0dB */ - { 5, 10718 }, /* 0.5dB */ - { 10, 10339 }, /* 1.0dB */ - { 15, 9947 }, /* 1.5dB */ - { 20, 9552 }, /* 2.0dB */ - { 25, 9183 }, /* 2.5dB */ - { 30, 8799 }, /* 3.0dB */ - { 35, 8422 }, /* 3.5dB */ - { 40, 8062 }, /* 4.0dB */ - { 45, 7707 }, /* 4.5dB */ - { 50, 7353 }, /* 5.0dB */ - { 55, 7025 }, /* 5.5dB */ - { 60, 6684 }, /* 6.0dB */ - { 65, 6331 }, /* 6.5dB */ - { 70, 6036 }, /* 7.0dB */ - { 75, 5727 }, /* 7.5dB */ - { 80, 5437 }, /* 8.0dB */ - { 85, 5164 }, /* 8.5dB */ - { 90, 4902 }, /* 9.0dB */ - { 95, 4653 }, /* 9.5dB */ - { 100, 4408 }, /* 10.0dB */ - { 105, 4187 }, /* 10.5dB */ - { 110, 3961 }, /* 11.0dB */ - { 115, 3751 }, /* 11.5dB */ - { 120, 3558 }, /* 12.0dB */ - { 125, 3368 }, /* 12.5dB */ - { 130, 3191 }, /* 13.0dB */ - { 135, 3017 }, /* 13.5dB */ - { 140, 2862 }, /* 14.0dB */ - { 145, 2710 }, /* 14.5dB */ - { 150, 2565 }, /* 15.0dB */ - { 160, 2300 }, /* 16.0dB */ - { 170, 2058 }, /* 17.0dB */ - { 180, 1849 }, /* 18.0dB */ - { 190, 1663 }, /* 19.0dB */ - { 200, 1495 }, /* 20.0dB */ - { 210, 1349 }, /* 21.0dB */ - { 220, 1222 }, /* 22.0dB */ - { 230, 1110 }, /* 23.0dB */ - { 240, 1011 }, /* 24.0dB */ - { 250, 925 }, /* 25.0dB */ - { 260, 853 }, /* 26.0dB */ - { 270, 789 }, /* 27.0dB */ - { 280, 734 }, /* 28.0dB */ - { 290, 690 }, /* 29.0dB */ - { 300, 650 }, /* 30.0dB */ - { 310, 619 }, /* 31.0dB */ - { 320, 593 }, /* 32.0dB */ - { 330, 571 }, /* 33.0dB */ - { 400, 498 }, /* 40.0dB */ - { 450, 484 }, /* 45.0dB */ - { 500, 481 } /* 50.0dB */ -}; - -/* RF level C/N lookup table */ -static const struct stv090x_tab stv090x_rf_tab[] = { - { -5, 0xcaa1 }, /* -5dBm */ - { -10, 0xc229 }, /* -10dBm */ - { -15, 0xbb08 }, /* -15dBm */ - { -20, 0xb4bc }, /* -20dBm */ - { -25, 0xad5a }, /* -25dBm */ - { -30, 0xa298 }, /* -30dBm */ - { -35, 0x98a8 }, /* -35dBm */ - { -40, 0x8389 }, /* -40dBm */ - { -45, 0x59be }, /* -45dBm */ - { -50, 0x3a14 }, /* -50dBm */ - { -55, 0x2d11 }, /* -55dBm */ - { -60, 0x210d }, /* -60dBm */ - { -65, 0xa14f }, /* -65dBm */ - { -70, 0x07aa } /* -70dBm */ -}; - - -static struct stv090x_reg stv0900_initval[] = { - - { STV090x_OUTCFG, 0x00 }, - { STV090x_MODECFG, 0xff }, - { STV090x_AGCRF1CFG, 0x11 }, - { STV090x_AGCRF2CFG, 0x13 }, - { STV090x_TSGENERAL1X, 0x14 }, - { STV090x_TSTTNR2, 0x21 }, - { STV090x_TSTTNR4, 0x21 }, - { STV090x_P2_DISTXCTL, 0x22 }, - { STV090x_P2_F22TX, 0xc0 }, - { STV090x_P2_F22RX, 0xc0 }, - { STV090x_P2_DISRXCTL, 0x00 }, - { STV090x_P2_DMDCFGMD, 0xF9 }, - { STV090x_P2_DEMOD, 0x08 }, - { STV090x_P2_DMDCFG3, 0xc4 }, - { STV090x_P2_CARFREQ, 0xed }, - { STV090x_P2_LDT, 0xd0 }, - { STV090x_P2_LDT2, 0xb8 }, - { STV090x_P2_TMGCFG, 0xd2 }, - { STV090x_P2_TMGTHRISE, 0x20 }, - { STV090x_P1_TMGCFG, 0xd2 }, - - { STV090x_P2_TMGTHFALL, 0x00 }, - { STV090x_P2_FECSPY, 0x88 }, - { STV090x_P2_FSPYDATA, 0x3a }, - { STV090x_P2_FBERCPT4, 0x00 }, - { STV090x_P2_FSPYBER, 0x10 }, - { STV090x_P2_ERRCTRL1, 0x35 }, - { STV090x_P2_ERRCTRL2, 0xc1 }, - { STV090x_P2_CFRICFG, 0xf8 }, - { STV090x_P2_NOSCFG, 0x1c }, - { STV090x_P2_DMDTOM, 0x20 }, - { STV090x_P2_CORRELMANT, 0x70 }, - { STV090x_P2_CORRELABS, 0x88 }, - { STV090x_P2_AGC2O, 0x5b }, - { STV090x_P2_AGC2REF, 0x38 }, - { STV090x_P2_CARCFG, 0xe4 }, - { STV090x_P2_ACLC, 0x1A }, - { STV090x_P2_BCLC, 0x09 }, - { STV090x_P2_CARHDR, 0x08 }, - { STV090x_P2_KREFTMG, 0xc1 }, - { STV090x_P2_SFRUPRATIO, 0xf0 }, - { STV090x_P2_SFRLOWRATIO, 0x70 }, - { STV090x_P2_SFRSTEP, 0x58 }, - { STV090x_P2_TMGCFG2, 0x01 }, - { STV090x_P2_CAR2CFG, 0x26 }, - { STV090x_P2_BCLC2S2Q, 0x86 }, - { STV090x_P2_BCLC2S28, 0x86 }, - { STV090x_P2_SMAPCOEF7, 0x77 }, - { STV090x_P2_SMAPCOEF6, 0x85 }, - { STV090x_P2_SMAPCOEF5, 0x77 }, - { STV090x_P2_TSCFGL, 0x20 }, - { STV090x_P2_DMDCFG2, 0x3b }, - { STV090x_P2_MODCODLST0, 0xff }, - { STV090x_P2_MODCODLST1, 0xff }, - { STV090x_P2_MODCODLST2, 0xff }, - { STV090x_P2_MODCODLST3, 0xff }, - { STV090x_P2_MODCODLST4, 0xff }, - { STV090x_P2_MODCODLST5, 0xff }, - { STV090x_P2_MODCODLST6, 0xff }, - { STV090x_P2_MODCODLST7, 0xcc }, - { STV090x_P2_MODCODLST8, 0xcc }, - { STV090x_P2_MODCODLST9, 0xcc }, - { STV090x_P2_MODCODLSTA, 0xcc }, - { STV090x_P2_MODCODLSTB, 0xcc }, - { STV090x_P2_MODCODLSTC, 0xcc }, - { STV090x_P2_MODCODLSTD, 0xcc }, - { STV090x_P2_MODCODLSTE, 0xcc }, - { STV090x_P2_MODCODLSTF, 0xcf }, - { STV090x_P1_DISTXCTL, 0x22 }, - { STV090x_P1_F22TX, 0xc0 }, - { STV090x_P1_F22RX, 0xc0 }, - { STV090x_P1_DISRXCTL, 0x00 }, - { STV090x_P1_DMDCFGMD, 0xf9 }, - { STV090x_P1_DEMOD, 0x08 }, - { STV090x_P1_DMDCFG3, 0xc4 }, - { STV090x_P1_DMDTOM, 0x20 }, - { STV090x_P1_CARFREQ, 0xed }, - { STV090x_P1_LDT, 0xd0 }, - { STV090x_P1_LDT2, 0xb8 }, - { STV090x_P1_TMGCFG, 0xd2 }, - { STV090x_P1_TMGTHRISE, 0x20 }, - { STV090x_P1_TMGTHFALL, 0x00 }, - { STV090x_P1_SFRUPRATIO, 0xf0 }, - { STV090x_P1_SFRLOWRATIO, 0x70 }, - { STV090x_P1_TSCFGL, 0x20 }, - { STV090x_P1_FECSPY, 0x88 }, - { STV090x_P1_FSPYDATA, 0x3a }, - { STV090x_P1_FBERCPT4, 0x00 }, - { STV090x_P1_FSPYBER, 0x10 }, - { STV090x_P1_ERRCTRL1, 0x35 }, - { STV090x_P1_ERRCTRL2, 0xc1 }, - { STV090x_P1_CFRICFG, 0xf8 }, - { STV090x_P1_NOSCFG, 0x1c }, - { STV090x_P1_CORRELMANT, 0x70 }, - { STV090x_P1_CORRELABS, 0x88 }, - { STV090x_P1_AGC2O, 0x5b }, - { STV090x_P1_AGC2REF, 0x38 }, - { STV090x_P1_CARCFG, 0xe4 }, - { STV090x_P1_ACLC, 0x1A }, - { STV090x_P1_BCLC, 0x09 }, - { STV090x_P1_CARHDR, 0x08 }, - { STV090x_P1_KREFTMG, 0xc1 }, - { STV090x_P1_SFRSTEP, 0x58 }, - { STV090x_P1_TMGCFG2, 0x01 }, - { STV090x_P1_CAR2CFG, 0x26 }, - { STV090x_P1_BCLC2S2Q, 0x86 }, - { STV090x_P1_BCLC2S28, 0x86 }, - { STV090x_P1_SMAPCOEF7, 0x77 }, - { STV090x_P1_SMAPCOEF6, 0x85 }, - { STV090x_P1_SMAPCOEF5, 0x77 }, - { STV090x_P1_DMDCFG2, 0x3b }, - { STV090x_P1_MODCODLST0, 0xff }, - { STV090x_P1_MODCODLST1, 0xff }, - { STV090x_P1_MODCODLST2, 0xff }, - { STV090x_P1_MODCODLST3, 0xff }, - { STV090x_P1_MODCODLST4, 0xff }, - { STV090x_P1_MODCODLST5, 0xff }, - { STV090x_P1_MODCODLST6, 0xff }, - { STV090x_P1_MODCODLST7, 0xcc }, - { STV090x_P1_MODCODLST8, 0xcc }, - { STV090x_P1_MODCODLST9, 0xcc }, - { STV090x_P1_MODCODLSTA, 0xcc }, - { STV090x_P1_MODCODLSTB, 0xcc }, - { STV090x_P1_MODCODLSTC, 0xcc }, - { STV090x_P1_MODCODLSTD, 0xcc }, - { STV090x_P1_MODCODLSTE, 0xcc }, - { STV090x_P1_MODCODLSTF, 0xcf }, - { STV090x_GENCFG, 0x1d }, - { STV090x_NBITER_NF4, 0x37 }, - { STV090x_NBITER_NF5, 0x29 }, - { STV090x_NBITER_NF6, 0x37 }, - { STV090x_NBITER_NF7, 0x33 }, - { STV090x_NBITER_NF8, 0x31 }, - { STV090x_NBITER_NF9, 0x2f }, - { STV090x_NBITER_NF10, 0x39 }, - { STV090x_NBITER_NF11, 0x3a }, - { STV090x_NBITER_NF12, 0x29 }, - { STV090x_NBITER_NF13, 0x37 }, - { STV090x_NBITER_NF14, 0x33 }, - { STV090x_NBITER_NF15, 0x2f }, - { STV090x_NBITER_NF16, 0x39 }, - { STV090x_NBITER_NF17, 0x3a }, - { STV090x_NBITERNOERR, 0x04 }, - { STV090x_GAINLLR_NF4, 0x0C }, - { STV090x_GAINLLR_NF5, 0x0F }, - { STV090x_GAINLLR_NF6, 0x11 }, - { STV090x_GAINLLR_NF7, 0x14 }, - { STV090x_GAINLLR_NF8, 0x17 }, - { STV090x_GAINLLR_NF9, 0x19 }, - { STV090x_GAINLLR_NF10, 0x20 }, - { STV090x_GAINLLR_NF11, 0x21 }, - { STV090x_GAINLLR_NF12, 0x0D }, - { STV090x_GAINLLR_NF13, 0x0F }, - { STV090x_GAINLLR_NF14, 0x13 }, - { STV090x_GAINLLR_NF15, 0x1A }, - { STV090x_GAINLLR_NF16, 0x1F }, - { STV090x_GAINLLR_NF17, 0x21 }, - { STV090x_RCCFGH, 0x20 }, - { STV090x_P1_FECM, 0x01 }, /* disable DSS modes */ - { STV090x_P2_FECM, 0x01 }, /* disable DSS modes */ - { STV090x_P1_PRVIT, 0x2F }, /* disable PR 6/7 */ - { STV090x_P2_PRVIT, 0x2F }, /* disable PR 6/7 */ -}; - -static struct stv090x_reg stv0903_initval[] = { - { STV090x_OUTCFG, 0x00 }, - { STV090x_AGCRF1CFG, 0x11 }, - { STV090x_STOPCLK1, 0x48 }, - { STV090x_STOPCLK2, 0x14 }, - { STV090x_TSTTNR1, 0x27 }, - { STV090x_TSTTNR2, 0x21 }, - { STV090x_P1_DISTXCTL, 0x22 }, - { STV090x_P1_F22TX, 0xc0 }, - { STV090x_P1_F22RX, 0xc0 }, - { STV090x_P1_DISRXCTL, 0x00 }, - { STV090x_P1_DMDCFGMD, 0xF9 }, - { STV090x_P1_DEMOD, 0x08 }, - { STV090x_P1_DMDCFG3, 0xc4 }, - { STV090x_P1_CARFREQ, 0xed }, - { STV090x_P1_TNRCFG2, 0x82 }, - { STV090x_P1_LDT, 0xd0 }, - { STV090x_P1_LDT2, 0xb8 }, - { STV090x_P1_TMGCFG, 0xd2 }, - { STV090x_P1_TMGTHRISE, 0x20 }, - { STV090x_P1_TMGTHFALL, 0x00 }, - { STV090x_P1_SFRUPRATIO, 0xf0 }, - { STV090x_P1_SFRLOWRATIO, 0x70 }, - { STV090x_P1_TSCFGL, 0x20 }, - { STV090x_P1_FECSPY, 0x88 }, - { STV090x_P1_FSPYDATA, 0x3a }, - { STV090x_P1_FBERCPT4, 0x00 }, - { STV090x_P1_FSPYBER, 0x10 }, - { STV090x_P1_ERRCTRL1, 0x35 }, - { STV090x_P1_ERRCTRL2, 0xc1 }, - { STV090x_P1_CFRICFG, 0xf8 }, - { STV090x_P1_NOSCFG, 0x1c }, - { STV090x_P1_DMDTOM, 0x20 }, - { STV090x_P1_CORRELMANT, 0x70 }, - { STV090x_P1_CORRELABS, 0x88 }, - { STV090x_P1_AGC2O, 0x5b }, - { STV090x_P1_AGC2REF, 0x38 }, - { STV090x_P1_CARCFG, 0xe4 }, - { STV090x_P1_ACLC, 0x1A }, - { STV090x_P1_BCLC, 0x09 }, - { STV090x_P1_CARHDR, 0x08 }, - { STV090x_P1_KREFTMG, 0xc1 }, - { STV090x_P1_SFRSTEP, 0x58 }, - { STV090x_P1_TMGCFG2, 0x01 }, - { STV090x_P1_CAR2CFG, 0x26 }, - { STV090x_P1_BCLC2S2Q, 0x86 }, - { STV090x_P1_BCLC2S28, 0x86 }, - { STV090x_P1_SMAPCOEF7, 0x77 }, - { STV090x_P1_SMAPCOEF6, 0x85 }, - { STV090x_P1_SMAPCOEF5, 0x77 }, - { STV090x_P1_DMDCFG2, 0x3b }, - { STV090x_P1_MODCODLST0, 0xff }, - { STV090x_P1_MODCODLST1, 0xff }, - { STV090x_P1_MODCODLST2, 0xff }, - { STV090x_P1_MODCODLST3, 0xff }, - { STV090x_P1_MODCODLST4, 0xff }, - { STV090x_P1_MODCODLST5, 0xff }, - { STV090x_P1_MODCODLST6, 0xff }, - { STV090x_P1_MODCODLST7, 0xcc }, - { STV090x_P1_MODCODLST8, 0xcc }, - { STV090x_P1_MODCODLST9, 0xcc }, - { STV090x_P1_MODCODLSTA, 0xcc }, - { STV090x_P1_MODCODLSTB, 0xcc }, - { STV090x_P1_MODCODLSTC, 0xcc }, - { STV090x_P1_MODCODLSTD, 0xcc }, - { STV090x_P1_MODCODLSTE, 0xcc }, - { STV090x_P1_MODCODLSTF, 0xcf }, - { STV090x_GENCFG, 0x1c }, - { STV090x_NBITER_NF4, 0x37 }, - { STV090x_NBITER_NF5, 0x29 }, - { STV090x_NBITER_NF6, 0x37 }, - { STV090x_NBITER_NF7, 0x33 }, - { STV090x_NBITER_NF8, 0x31 }, - { STV090x_NBITER_NF9, 0x2f }, - { STV090x_NBITER_NF10, 0x39 }, - { STV090x_NBITER_NF11, 0x3a }, - { STV090x_NBITER_NF12, 0x29 }, - { STV090x_NBITER_NF13, 0x37 }, - { STV090x_NBITER_NF14, 0x33 }, - { STV090x_NBITER_NF15, 0x2f }, - { STV090x_NBITER_NF16, 0x39 }, - { STV090x_NBITER_NF17, 0x3a }, - { STV090x_NBITERNOERR, 0x04 }, - { STV090x_GAINLLR_NF4, 0x0C }, - { STV090x_GAINLLR_NF5, 0x0F }, - { STV090x_GAINLLR_NF6, 0x11 }, - { STV090x_GAINLLR_NF7, 0x14 }, - { STV090x_GAINLLR_NF8, 0x17 }, - { STV090x_GAINLLR_NF9, 0x19 }, - { STV090x_GAINLLR_NF10, 0x20 }, - { STV090x_GAINLLR_NF11, 0x21 }, - { STV090x_GAINLLR_NF12, 0x0D }, - { STV090x_GAINLLR_NF13, 0x0F }, - { STV090x_GAINLLR_NF14, 0x13 }, - { STV090x_GAINLLR_NF15, 0x1A }, - { STV090x_GAINLLR_NF16, 0x1F }, - { STV090x_GAINLLR_NF17, 0x21 }, - { STV090x_RCCFGH, 0x20 }, - { STV090x_P1_FECM, 0x01 }, /*disable the DSS mode */ - { STV090x_P1_PRVIT, 0x2f } /*disable puncture rate 6/7*/ -}; - -static struct stv090x_reg stv0900_cut20_val[] = { - - { STV090x_P2_DMDCFG3, 0xe8 }, - { STV090x_P2_DMDCFG4, 0x10 }, - { STV090x_P2_CARFREQ, 0x38 }, - { STV090x_P2_CARHDR, 0x20 }, - { STV090x_P2_KREFTMG, 0x5a }, - { STV090x_P2_SMAPCOEF7, 0x06 }, - { STV090x_P2_SMAPCOEF6, 0x00 }, - { STV090x_P2_SMAPCOEF5, 0x04 }, - { STV090x_P2_NOSCFG, 0x0c }, - { STV090x_P1_DMDCFG3, 0xe8 }, - { STV090x_P1_DMDCFG4, 0x10 }, - { STV090x_P1_CARFREQ, 0x38 }, - { STV090x_P1_CARHDR, 0x20 }, - { STV090x_P1_KREFTMG, 0x5a }, - { STV090x_P1_SMAPCOEF7, 0x06 }, - { STV090x_P1_SMAPCOEF6, 0x00 }, - { STV090x_P1_SMAPCOEF5, 0x04 }, - { STV090x_P1_NOSCFG, 0x0c }, - { STV090x_GAINLLR_NF4, 0x21 }, - { STV090x_GAINLLR_NF5, 0x21 }, - { STV090x_GAINLLR_NF6, 0x20 }, - { STV090x_GAINLLR_NF7, 0x1F }, - { STV090x_GAINLLR_NF8, 0x1E }, - { STV090x_GAINLLR_NF9, 0x1E }, - { STV090x_GAINLLR_NF10, 0x1D }, - { STV090x_GAINLLR_NF11, 0x1B }, - { STV090x_GAINLLR_NF12, 0x20 }, - { STV090x_GAINLLR_NF13, 0x20 }, - { STV090x_GAINLLR_NF14, 0x20 }, - { STV090x_GAINLLR_NF15, 0x20 }, - { STV090x_GAINLLR_NF16, 0x20 }, - { STV090x_GAINLLR_NF17, 0x21 }, -}; - -static struct stv090x_reg stv0903_cut20_val[] = { - { STV090x_P1_DMDCFG3, 0xe8 }, - { STV090x_P1_DMDCFG4, 0x10 }, - { STV090x_P1_CARFREQ, 0x38 }, - { STV090x_P1_CARHDR, 0x20 }, - { STV090x_P1_KREFTMG, 0x5a }, - { STV090x_P1_SMAPCOEF7, 0x06 }, - { STV090x_P1_SMAPCOEF6, 0x00 }, - { STV090x_P1_SMAPCOEF5, 0x04 }, - { STV090x_P1_NOSCFG, 0x0c }, - { STV090x_GAINLLR_NF4, 0x21 }, - { STV090x_GAINLLR_NF5, 0x21 }, - { STV090x_GAINLLR_NF6, 0x20 }, - { STV090x_GAINLLR_NF7, 0x1F }, - { STV090x_GAINLLR_NF8, 0x1E }, - { STV090x_GAINLLR_NF9, 0x1E }, - { STV090x_GAINLLR_NF10, 0x1D }, - { STV090x_GAINLLR_NF11, 0x1B }, - { STV090x_GAINLLR_NF12, 0x20 }, - { STV090x_GAINLLR_NF13, 0x20 }, - { STV090x_GAINLLR_NF14, 0x20 }, - { STV090x_GAINLLR_NF15, 0x20 }, - { STV090x_GAINLLR_NF16, 0x20 }, - { STV090x_GAINLLR_NF17, 0x21 } -}; - -/* Cut 2.0 Long Frame Tracking CR loop */ -static struct stv090x_long_frame_crloop stv090x_s2_crl_cut20[] = { - /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ - { STV090x_QPSK_12, 0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x1e }, - { STV090x_QPSK_35, 0x2f, 0x3f, 0x2e, 0x2f, 0x3d, 0x0f, 0x0e, 0x2e, 0x3d, 0x0e }, - { STV090x_QPSK_23, 0x2f, 0x3f, 0x2e, 0x2f, 0x0e, 0x0f, 0x0e, 0x1e, 0x3d, 0x3d }, - { STV090x_QPSK_34, 0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, - { STV090x_QPSK_45, 0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, - { STV090x_QPSK_56, 0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, - { STV090x_QPSK_89, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, - { STV090x_QPSK_910, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, - { STV090x_8PSK_35, 0x3c, 0x3e, 0x1c, 0x2e, 0x0c, 0x1e, 0x2b, 0x2d, 0x1b, 0x1d }, - { STV090x_8PSK_23, 0x1d, 0x3e, 0x3c, 0x2e, 0x2c, 0x1e, 0x0c, 0x2d, 0x2b, 0x1d }, - { STV090x_8PSK_34, 0x0e, 0x3e, 0x3d, 0x2e, 0x0d, 0x1e, 0x2c, 0x2d, 0x0c, 0x1d }, - { STV090x_8PSK_56, 0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d }, - { STV090x_8PSK_89, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d }, - { STV090x_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d } -}; - -/* Cut 3.0 Long Frame Tracking CR loop */ -static struct stv090x_long_frame_crloop stv090x_s2_crl_cut30[] = { - /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ - { STV090x_QPSK_12, 0x3c, 0x2c, 0x0c, 0x2c, 0x1b, 0x2c, 0x1b, 0x1c, 0x0b, 0x3b }, - { STV090x_QPSK_35, 0x0d, 0x0d, 0x0c, 0x0d, 0x1b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b }, - { STV090x_QPSK_23, 0x1d, 0x0d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b }, - { STV090x_QPSK_34, 0x1d, 0x1d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b }, - { STV090x_QPSK_45, 0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, - { STV090x_QPSK_56, 0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, - { STV090x_QPSK_89, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, - { STV090x_QPSK_910, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, - { STV090x_8PSK_35, 0x39, 0x29, 0x39, 0x19, 0x19, 0x19, 0x19, 0x19, 0x09, 0x19 }, - { STV090x_8PSK_23, 0x2a, 0x39, 0x1a, 0x0a, 0x39, 0x0a, 0x29, 0x39, 0x29, 0x0a }, - { STV090x_8PSK_34, 0x2b, 0x3a, 0x1b, 0x1b, 0x3a, 0x1b, 0x1a, 0x0b, 0x1a, 0x3a }, - { STV090x_8PSK_56, 0x0c, 0x1b, 0x3b, 0x3b, 0x1b, 0x3b, 0x3a, 0x3b, 0x3a, 0x1b }, - { STV090x_8PSK_89, 0x0d, 0x3c, 0x2c, 0x2c, 0x2b, 0x0c, 0x0b, 0x3b, 0x0b, 0x1b }, - { STV090x_8PSK_910, 0x0d, 0x0d, 0x2c, 0x3c, 0x3b, 0x1c, 0x0b, 0x3b, 0x0b, 0x1b } -}; - -/* Cut 2.0 Long Frame Tracking CR Loop */ -static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut20[] = { - /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ - { STV090x_16APSK_23, 0x0c, 0x0c, 0x0c, 0x0c, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x0c }, - { STV090x_16APSK_34, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0c, 0x2d, 0x0c, 0x1d, 0x0c }, - { STV090x_16APSK_45, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c }, - { STV090x_16APSK_56, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c }, - { STV090x_16APSK_89, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c }, - { STV090x_16APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c }, - { STV090x_32APSK_34, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, - { STV090x_32APSK_45, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, - { STV090x_32APSK_56, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, - { STV090x_32APSK_89, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, - { STV090x_32APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c } -}; - -/* Cut 3.0 Long Frame Tracking CR Loop */ -static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut30[] = { - /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ - { STV090x_16APSK_23, 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x0a, 0x3a, 0x0a, 0x2a, 0x0a }, - { STV090x_16APSK_34, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x3b, 0x0a, 0x1b, 0x0a }, - { STV090x_16APSK_45, 0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a }, - { STV090x_16APSK_56, 0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a }, - { STV090x_16APSK_89, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a }, - { STV090x_16APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a }, - { STV090x_32APSK_34, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, - { STV090x_32APSK_45, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, - { STV090x_32APSK_56, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, - { STV090x_32APSK_89, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, - { STV090x_32APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } -}; - -static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut20[] = { - /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ - { STV090x_QPSK_14, 0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x2d, 0x1f, 0x3d, 0x3e }, - { STV090x_QPSK_13, 0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x3d, 0x0f, 0x3d, 0x2e }, - { STV090x_QPSK_25, 0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x2e } -}; - -static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut30[] = { - /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ - { STV090x_QPSK_14, 0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x2a, 0x1c, 0x3a, 0x3b }, - { STV090x_QPSK_13, 0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x3a, 0x0c, 0x3a, 0x2b }, - { STV090x_QPSK_25, 0x1c, 0x3c, 0x1b, 0x3c, 0x3a, 0x1c, 0x3a, 0x3b, 0x3a, 0x2b } -}; - -/* Cut 2.0 Short Frame Tracking CR Loop */ -static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut20[] = { - /* MODCOD 2M 5M 10M 20M 30M */ - { STV090x_QPSK, 0x2f, 0x2e, 0x0e, 0x0e, 0x3d }, - { STV090x_8PSK, 0x3e, 0x0e, 0x2d, 0x0d, 0x3c }, - { STV090x_16APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d }, - { STV090x_32APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d } -}; - -/* Cut 3.0 Short Frame Tracking CR Loop */ -static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut30[] = { - /* MODCOD 2M 5M 10M 20M 30M */ - { STV090x_QPSK, 0x2C, 0x2B, 0x0B, 0x0B, 0x3A }, - { STV090x_8PSK, 0x3B, 0x0B, 0x2A, 0x0A, 0x39 }, - { STV090x_16APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A }, - { STV090x_32APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A } -}; - -static inline s32 comp2(s32 __x, s32 __width) -{ - if (__width == 32) - return __x; - else - return (__x >= (1 << (__width - 1))) ? (__x - (1 << __width)) : __x; -} - -static int stv090x_read_reg(struct stv090x_state *state, unsigned int reg) -{ - const struct stv090x_config *config = state->config; - int ret; - - u8 b0[] = { reg >> 8, reg & 0xff }; - u8 buf; - - struct i2c_msg msg[] = { - { .addr = config->address, .flags = 0, .buf = b0, .len = 2 }, - { .addr = config->address, .flags = I2C_M_RD, .buf = &buf, .len = 1 } - }; - - ret = i2c_transfer(state->i2c, msg, 2); - if (ret != 2) { - if (ret != -ERESTARTSYS) - dprintk(FE_ERROR, 1, - "Read error, Reg=[0x%02x], Status=%d", - reg, ret); - - return ret < 0 ? ret : -EREMOTEIO; - } - if (unlikely(*state->verbose >= FE_DEBUGREG)) - dprintk(FE_ERROR, 1, "Reg=[0x%02x], data=%02x", - reg, buf); - - return (unsigned int) buf; -} - -static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 *data, u32 count) -{ - const struct stv090x_config *config = state->config; - int ret; - u8 buf[2 + count]; - struct i2c_msg i2c_msg = { .addr = config->address, .flags = 0, .buf = buf, .len = 2 + count }; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - memcpy(&buf[2], data, count); - - if (unlikely(*state->verbose >= FE_DEBUGREG)) { - int i; - - printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); - for (i = 0; i < count; i++) - printk(" %02x", data[i]); - printk("\n"); - } - - ret = i2c_transfer(state->i2c, &i2c_msg, 1); - if (ret != 1) { - if (ret != -ERESTARTSYS) - dprintk(FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d", - reg, data[0], count, ret); - return ret < 0 ? ret : -EREMOTEIO; - } - - return 0; -} - -static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data) -{ - return stv090x_write_regs(state, reg, &data, 1); -} - -static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) -{ - u32 reg; - - /* - * NOTE! A lock is used as a FSM to control the state in which - * access is serialized between two tuners on the same demod. - * This has nothing to do with a lock to protect a critical section - * which may in some other cases be confused with protecting I/O - * access to the demodulator gate. - * In case of any error, the lock is unlocked and exit within the - * relevant operations themselves. - */ - if (enable) { - if (state->config->tuner_i2c_lock) - state->config->tuner_i2c_lock(&state->frontend, 1); - else - mutex_lock(&state->internal->tuner_lock); - } - - reg = STV090x_READ_DEMOD(state, I2CRPT); - if (enable) { - dprintk(FE_DEBUG, 1, "Enable Gate"); - STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0) - goto err; - - } else { - dprintk(FE_DEBUG, 1, "Disable Gate"); - STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 0); - if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0) - goto err; - } - - if (!enable) { - if (state->config->tuner_i2c_lock) - state->config->tuner_i2c_lock(&state->frontend, 0); - else - mutex_unlock(&state->internal->tuner_lock); - } - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - if (state->config->tuner_i2c_lock) - state->config->tuner_i2c_lock(&state->frontend, 0); - else - mutex_unlock(&state->internal->tuner_lock); - return -1; -} - -static void stv090x_get_lock_tmg(struct stv090x_state *state) -{ - switch (state->algo) { - case STV090x_BLIND_SEARCH: - dprintk(FE_DEBUG, 1, "Blind Search"); - if (state->srate <= 1500000) { /*10Msps< SR <=15Msps*/ - state->DemodTimeout = 1500; - state->FecTimeout = 400; - } else if (state->srate <= 5000000) { /*10Msps< SR <=15Msps*/ - state->DemodTimeout = 1000; - state->FecTimeout = 300; - } else { /*SR >20Msps*/ - state->DemodTimeout = 700; - state->FecTimeout = 100; - } - break; - - case STV090x_COLD_SEARCH: - case STV090x_WARM_SEARCH: - default: - dprintk(FE_DEBUG, 1, "Normal Search"); - if (state->srate <= 1000000) { /*SR <=1Msps*/ - state->DemodTimeout = 4500; - state->FecTimeout = 1700; - } else if (state->srate <= 2000000) { /*1Msps < SR <= 2Msps */ - state->DemodTimeout = 2500; - state->FecTimeout = 1100; - } else if (state->srate <= 5000000) { /*2Msps < SR <= 5Msps */ - state->DemodTimeout = 1000; - state->FecTimeout = 550; - } else if (state->srate <= 10000000) { /*5Msps < SR <= 10Msps */ - state->DemodTimeout = 700; - state->FecTimeout = 250; - } else if (state->srate <= 20000000) { /*10Msps < SR <= 20Msps */ - state->DemodTimeout = 400; - state->FecTimeout = 130; - } else { /*SR >20Msps*/ - state->DemodTimeout = 300; - state->FecTimeout = 100; - } - break; - } - - if (state->algo == STV090x_WARM_SEARCH) - state->DemodTimeout /= 2; -} - -static int stv090x_set_srate(struct stv090x_state *state, u32 srate) -{ - u32 sym; - - if (srate > 60000000) { - sym = (srate << 4); /* SR * 2^16 / master_clk */ - sym /= (state->internal->mclk >> 12); - } else if (srate > 6000000) { - sym = (srate << 6); - sym /= (state->internal->mclk >> 10); - } else { - sym = (srate << 9); - sym /= (state->internal->mclk >> 7); - } - - if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */ - goto err; - if (STV090x_WRITE_DEMOD(state, SFRINIT0, (sym & 0xff)) < 0) /* LSB */ - goto err; - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate) -{ - u32 sym; - - srate = 105 * (srate / 100); - if (srate > 60000000) { - sym = (srate << 4); /* SR * 2^16 / master_clk */ - sym /= (state->internal->mclk >> 12); - } else if (srate > 6000000) { - sym = (srate << 6); - sym /= (state->internal->mclk >> 10); - } else { - sym = (srate << 9); - sym /= (state->internal->mclk >> 7); - } - - if (sym < 0x7fff) { - if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) /* MSB */ - goto err; - if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) /* LSB */ - goto err; - } else { - if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x7f) < 0) /* MSB */ - goto err; - if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xff) < 0) /* LSB */ - goto err; - } - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate) -{ - u32 sym; - - srate = 95 * (srate / 100); - if (srate > 60000000) { - sym = (srate << 4); /* SR * 2^16 / master_clk */ - sym /= (state->internal->mclk >> 12); - } else if (srate > 6000000) { - sym = (srate << 6); - sym /= (state->internal->mclk >> 10); - } else { - sym = (srate << 9); - sym /= (state->internal->mclk >> 7); - } - - if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0x7f)) < 0) /* MSB */ - goto err; - if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */ - goto err; - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static u32 stv090x_car_width(u32 srate, enum stv090x_rolloff rolloff) -{ - u32 ro; - - switch (rolloff) { - case STV090x_RO_20: - ro = 20; - break; - case STV090x_RO_25: - ro = 25; - break; - case STV090x_RO_35: - default: - ro = 35; - break; - } - - return srate + (srate * ro) / 100; -} - -static int stv090x_set_vit_thacq(struct stv090x_state *state) -{ - if (STV090x_WRITE_DEMOD(state, VTH12, 0x96) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH23, 0x64) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH34, 0x36) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH56, 0x23) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH67, 0x1e) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH78, 0x19) < 0) - goto err; - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_set_vit_thtracq(struct stv090x_state *state) -{ - if (STV090x_WRITE_DEMOD(state, VTH12, 0xd0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH23, 0x7d) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH34, 0x53) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH56, 0x2f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH67, 0x24) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VTH78, 0x1f) < 0) - goto err; - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_set_viterbi(struct stv090x_state *state) -{ - switch (state->search_mode) { - case STV090x_SEARCH_AUTO: - if (STV090x_WRITE_DEMOD(state, FECM, 0x10) < 0) /* DVB-S and DVB-S2 */ - goto err; - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x3f) < 0) /* all puncture rate */ - goto err; - break; - case STV090x_SEARCH_DVBS1: - if (STV090x_WRITE_DEMOD(state, FECM, 0x00) < 0) /* disable DSS */ - goto err; - switch (state->fec) { - case STV090x_PR12: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0) - goto err; - break; - - case STV090x_PR23: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0) - goto err; - break; - - case STV090x_PR34: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x04) < 0) - goto err; - break; - - case STV090x_PR56: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x08) < 0) - goto err; - break; - - case STV090x_PR78: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x20) < 0) - goto err; - break; - - default: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x2f) < 0) /* all */ - goto err; - break; - } - break; - case STV090x_SEARCH_DSS: - if (STV090x_WRITE_DEMOD(state, FECM, 0x80) < 0) - goto err; - switch (state->fec) { - case STV090x_PR12: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0) - goto err; - break; - - case STV090x_PR23: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0) - goto err; - break; - - case STV090x_PR67: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x10) < 0) - goto err; - break; - - default: - if (STV090x_WRITE_DEMOD(state, PRVIT, 0x13) < 0) /* 1/2, 2/3, 6/7 */ - goto err; - break; - } - break; - default: - break; - } - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_stop_modcod(struct stv090x_state *state) -{ - if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xff) < 0) - goto err; - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_activate_modcod(struct stv090x_state *state) -{ - if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xfc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0) - goto err; - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_activate_modcod_single(struct stv090x_state *state) -{ - - if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xf0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0x0f) < 0) - goto err; - - return 0; - -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable) -{ - u32 reg; - - switch (state->demod) { - case STV090x_DEMODULATOR_0: - mutex_lock(&state->internal->demod_lock); - reg = stv090x_read_reg(state, STV090x_STOPCLK2); - STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable); - if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) - goto err; - mutex_unlock(&state->internal->demod_lock); - break; - - case STV090x_DEMODULATOR_1: - mutex_lock(&state->internal->demod_lock); - reg = stv090x_read_reg(state, STV090x_STOPCLK2); - STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable); - if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) - goto err; - mutex_unlock(&state->internal->demod_lock); - break; - - default: - dprintk(FE_ERROR, 1, "Wrong demodulator!"); - break; - } - return 0; -err: - mutex_unlock(&state->internal->demod_lock); - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_dvbs_track_crl(struct stv090x_state *state) -{ - if (state->internal->dev_ver >= 0x30) { - /* Set ACLC BCLC optimised value vs SR */ - if (state->srate >= 15000000) { - if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, BCLC, 0x1a) < 0) - goto err; - } else if ((state->srate >= 7000000) && (15000000 > state->srate)) { - if (STV090x_WRITE_DEMOD(state, ACLC, 0x0c) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, BCLC, 0x1b) < 0) - goto err; - } else if (state->srate < 7000000) { - if (STV090x_WRITE_DEMOD(state, ACLC, 0x2c) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, BCLC, 0x1c) < 0) - goto err; - } - - } else { - /* Cut 2.0 */ - if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0) - goto err; - } - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_delivery_search(struct stv090x_state *state) -{ - u32 reg; - - switch (state->search_mode) { - case STV090x_SEARCH_DVBS1: - case STV090x_SEARCH_DSS: - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); - STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - - /* Activate Viterbi decoder in legacy search, - * do not use FRESVIT1, might impact VITERBI2 - */ - if (stv090x_vitclk_ctl(state, 0) < 0) - goto err; - - if (stv090x_dvbs_track_crl(state) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x22) < 0) /* disable DVB-S2 */ - goto err; - - if (stv090x_set_vit_thacq(state) < 0) - goto err; - if (stv090x_set_viterbi(state) < 0) - goto err; - break; - - case STV090x_SEARCH_DVBS2: - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0); - STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); - STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - - if (stv090x_vitclk_ctl(state, 1) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) /* stop DVB-S CR loop */ - goto err; - if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0) - goto err; - - if (state->internal->dev_ver <= 0x20) { - /* enable S2 carrier loop */ - if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0) - goto err; - } else { - /* > Cut 3: Stop carrier 3 */ - if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0) - goto err; - } - - if (state->demod_mode != STV090x_SINGLE) { - /* Cut 2: enable link during search */ - if (stv090x_activate_modcod(state) < 0) - goto err; - } else { - /* Single demodulator - * Authorize SHORT and LONG frames, - * QPSK, 8PSK, 16APSK and 32APSK - */ - if (stv090x_activate_modcod_single(state) < 0) - goto err; - } - - if (stv090x_set_vit_thtracq(state) < 0) - goto err; - break; - - case STV090x_SEARCH_AUTO: - default: - /* enable DVB-S2 and DVB-S2 in Auto MODE */ - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0); - STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); - STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - - if (stv090x_vitclk_ctl(state, 0) < 0) - goto err; - - if (stv090x_dvbs_track_crl(state) < 0) - goto err; - - if (state->internal->dev_ver <= 0x20) { - /* enable S2 carrier loop */ - if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0) - goto err; - } else { - /* > Cut 3: Stop carrier 3 */ - if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0) - goto err; - } - - if (state->demod_mode != STV090x_SINGLE) { - /* Cut 2: enable link during search */ - if (stv090x_activate_modcod(state) < 0) - goto err; - } else { - /* Single demodulator - * Authorize SHORT and LONG frames, - * QPSK, 8PSK, 16APSK and 32APSK - */ - if (stv090x_activate_modcod_single(state) < 0) - goto err; - } - - if (stv090x_set_vit_thacq(state) < 0) - goto err; - - if (stv090x_set_viterbi(state) < 0) - goto err; - break; - } - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_start_search(struct stv090x_state *state) -{ - u32 reg, freq_abs; - s16 freq; - - /* Reset demodulator */ - reg = STV090x_READ_DEMOD(state, DMDISTATE); - STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); - if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0) - goto err; - - if (state->internal->dev_ver <= 0x20) { - if (state->srate <= 5000000) { - if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRUP0, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRLOW0, 0x00) < 0) - goto err; - - /*enlarge the timing bandwith for Low SR*/ - if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) - goto err; - } else { - /* If the symbol rate is >5 Msps - Set The carrier search up and low to auto mode */ - if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0) - goto err; - /*reduce the timing bandwith for high SR*/ - if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0) - goto err; - } - } else { - /* >= Cut 3 */ - if (state->srate <= 5000000) { - /* enlarge the timing bandwith for Low SR */ - STV090x_WRITE_DEMOD(state, RTCS2, 0x68); - } else { - /* reduce timing bandwith for high SR */ - STV090x_WRITE_DEMOD(state, RTCS2, 0x44); - } - - /* Set CFR min and max to manual mode */ - STV090x_WRITE_DEMOD(state, CARCFG, 0x46); - - if (state->algo == STV090x_WARM_SEARCH) { - /* WARM Start - * CFR min = -1MHz, - * CFR max = +1MHz - */ - freq_abs = 1000 << 16; - freq_abs /= (state->internal->mclk / 1000); - freq = (s16) freq_abs; - } else { - /* COLD Start - * CFR min =- (SearchRange / 2 + 600KHz) - * CFR max = +(SearchRange / 2 + 600KHz) - * (600KHz for the tuner step size) - */ - freq_abs = (state->search_range / 2000) + 600; - freq_abs = freq_abs << 16; - freq_abs /= (state->internal->mclk / 1000); - freq = (s16) freq_abs; - } - - if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRUP0, LSB(freq)) < 0) - goto err; - - freq *= -1; - - if (STV090x_WRITE_DEMOD(state, CFRLOW1, MSB(freq)) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRLOW0, LSB(freq)) < 0) - goto err; - - } - - if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0) - goto err; - - if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0) - goto err; - - if ((state->search_mode == STV090x_SEARCH_DVBS1) || - (state->search_mode == STV090x_SEARCH_DSS) || - (state->search_mode == STV090x_SEARCH_AUTO)) { - - if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) - goto err; - } - } - - if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xe0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xc0) < 0) - goto err; - - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0); - STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - reg = STV090x_READ_DEMOD(state, DMDCFG2); - STV090x_SETFIELD_Px(reg, S1S2_SEQUENTIAL_FIELD, 0x0); - if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) - goto err; - - if (state->internal->dev_ver >= 0x20) { - /*Frequency offset detector setting*/ - if (state->srate < 2000000) { - if (state->internal->dev_ver <= 0x20) { - /* Cut 2 */ - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0) - goto err; - } else { - /* Cut 3 */ - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0) - goto err; - } - if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0) - goto err; - } else if (state->srate < 10000000) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0) - goto err; - } else { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0) - goto err; - } - } else { - if (state->srate < 10000000) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xef) < 0) - goto err; - } else { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xed) < 0) - goto err; - } - } - - switch (state->algo) { - case STV090x_WARM_SEARCH: - /* The symbol rate and the exact - * carrier Frequency are known - */ - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) - goto err; - break; - - case STV090x_COLD_SEARCH: - /* The symbol rate is known */ - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) - goto err; - break; - - default: - break; - } - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_get_agc2_min_level(struct stv090x_state *state) -{ - u32 agc2_min = 0xffff, agc2 = 0, freq_init, freq_step, reg; - s32 i, j, steps, dir; - - if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) - goto err; - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0); - STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) /* SR = 65 Msps Max */ - goto err; - if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) /* SR= 400 ksps Min */ - goto err; - if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) /* stop acq @ coarse carrier state */ - goto err; - if (stv090x_set_srate(state, 1000000) < 0) - goto err; - - steps = state->search_range / 1000000; - if (steps <= 0) - steps = 1; - - dir = 1; - freq_step = (1000000 * 256) / (state->internal->mclk / 256); - freq_init = 0; - - for (i = 0; i < steps; i++) { - if (dir > 0) - freq_init = freq_init + (freq_step * i); - else - freq_init = freq_init - (freq_step * i); - - dir *= -1; - - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */ - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_init >> 8) & 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_init & 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */ - goto err; - msleep(10); - - agc2 = 0; - for (j = 0; j < 10; j++) { - agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) | - STV090x_READ_DEMOD(state, AGC2I0); - } - agc2 /= 10; - if (agc2 < agc2_min) - agc2_min = agc2; - } - - return agc2_min; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static u32 stv090x_get_srate(struct stv090x_state *state, u32 clk) -{ - u8 r3, r2, r1, r0; - s32 srate, int_1, int_2, tmp_1, tmp_2; - - r3 = STV090x_READ_DEMOD(state, SFR3); - r2 = STV090x_READ_DEMOD(state, SFR2); - r1 = STV090x_READ_DEMOD(state, SFR1); - r0 = STV090x_READ_DEMOD(state, SFR0); - - srate = ((r3 << 24) | (r2 << 16) | (r1 << 8) | r0); - - int_1 = clk >> 16; - int_2 = srate >> 16; - - tmp_1 = clk % 0x10000; - tmp_2 = srate % 0x10000; - - srate = (int_1 * int_2) + - ((int_1 * tmp_2) >> 16) + - ((int_2 * tmp_1) >> 16); - - return srate; -} - -static u32 stv090x_srate_srch_coarse(struct stv090x_state *state) -{ - struct dvb_frontend *fe = &state->frontend; - - int tmg_lock = 0, i; - s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq; - u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg; - u32 agc2th; - - if (state->internal->dev_ver >= 0x30) - agc2th = 0x2e00; - else - agc2th = 0x1f00; - - reg = STV090x_READ_DEMOD(state, DMDISTATE); - STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */ - if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0) - goto err; - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1); - STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x50) < 0) - goto err; - - if (state->internal->dev_ver >= 0x30) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x98) < 0) - goto err; - - } else if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0) - goto err; - } - - if (state->srate <= 2000000) - car_step = 1000; - else if (state->srate <= 5000000) - car_step = 2000; - else if (state->srate <= 12000000) - car_step = 3000; - else - car_step = 5000; - - steps = -1 + ((state->search_range / 1000) / car_step); - steps /= 2; - steps = (2 * steps) + 1; - if (steps < 0) - steps = 1; - else if (steps > 10) { - steps = 11; - car_step = (state->search_range / 1000) / 10; - } - cur_step = 0; - dir = 1; - freq = state->frequency; - - while ((!tmg_lock) && (cur_step < steps)) { - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */ - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRINIT1, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRINIT0, 0x00) < 0) - goto err; - /* trigger acquisition */ - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x40) < 0) - goto err; - msleep(50); - for (i = 0; i < 10; i++) { - reg = STV090x_READ_DEMOD(state, DSTATUS); - if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2) - tmg_cpt++; - agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) | - STV090x_READ_DEMOD(state, AGC2I0); - } - agc2 /= 10; - srate_coarse = stv090x_get_srate(state, state->internal->mclk); - cur_step++; - dir *= -1; - if ((tmg_cpt >= 5) && (agc2 < agc2th) && - (srate_coarse < 50000000) && (srate_coarse > 850000)) - tmg_lock = 1; - else if (cur_step < steps) { - if (dir > 0) - freq += cur_step * car_step; - else - freq -= cur_step * car_step; - - /* Setup tuner */ - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (state->config->tuner_set_frequency) { - if (state->config->tuner_set_frequency(fe, freq) < 0) - goto err_gateoff; - } - - if (state->config->tuner_set_bandwidth) { - if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) - goto err_gateoff; - } - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - msleep(50); - - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (state->config->tuner_get_status) { - if (state->config->tuner_get_status(fe, ®) < 0) - goto err_gateoff; - } - - if (reg) - dprintk(FE_DEBUG, 1, "Tuner phase locked"); - else - dprintk(FE_DEBUG, 1, "Tuner unlocked"); - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - } - } - if (!tmg_lock) - srate_coarse = 0; - else - srate_coarse = stv090x_get_srate(state, state->internal->mclk); - - return srate_coarse; - -err_gateoff: - stv090x_i2c_gate_ctrl(state, 0); -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static u32 stv090x_srate_srch_fine(struct stv090x_state *state) -{ - u32 srate_coarse, freq_coarse, sym, reg; - - srate_coarse = stv090x_get_srate(state, state->internal->mclk); - freq_coarse = STV090x_READ_DEMOD(state, CFR2) << 8; - freq_coarse |= STV090x_READ_DEMOD(state, CFR1); - sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */ - - if (sym < state->srate) - srate_coarse = 0; - else { - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */ - goto err; - if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0) - goto err; - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) - goto err; - - if (state->internal->dev_ver >= 0x30) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0) - goto err; - } else if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0) - goto err; - } - - if (srate_coarse > 3000000) { - sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */ - sym = (sym / 1000) * 65536; - sym /= (state->internal->mclk / 1000); - if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) - goto err; - sym = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */ - sym = (sym / 1000) * 65536; - sym /= (state->internal->mclk / 1000); - if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0) - goto err; - sym = (srate_coarse / 1000) * 65536; - sym /= (state->internal->mclk / 1000); - if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0) - goto err; - } else { - sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */ - sym = (sym / 100) * 65536; - sym /= (state->internal->mclk / 100); - if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) - goto err; - sym = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */ - sym = (sym / 100) * 65536; - sym /= (state->internal->mclk / 100); - if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0) - goto err; - sym = (srate_coarse / 100) * 65536; - sym /= (state->internal->mclk / 100); - if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0) - goto err; - } - if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_coarse >> 8) & 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_coarse & 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) /* trigger acquisition */ - goto err; - } - - return srate_coarse; - -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout) -{ - s32 timer = 0, lock = 0; - u32 reg; - u8 stat; - - while ((timer < timeout) && (!lock)) { - reg = STV090x_READ_DEMOD(state, DMDSTATE); - stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); - - switch (stat) { - case 0: /* searching */ - case 1: /* first PLH detected */ - default: - dprintk(FE_DEBUG, 1, "Demodulator searching .."); - lock = 0; - break; - case 2: /* DVB-S2 mode */ - case 3: /* DVB-S1/legacy mode */ - reg = STV090x_READ_DEMOD(state, DSTATUS); - lock = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD); - break; - } - - if (!lock) - msleep(10); - else - dprintk(FE_DEBUG, 1, "Demodulator acquired LOCK"); - - timer += 10; - } - return lock; -} - -static int stv090x_blind_search(struct stv090x_state *state) -{ - u32 agc2, reg, srate_coarse; - s32 cpt_fail, agc2_ovflw, i; - u8 k_ref, k_max, k_min; - int coarse_fail = 0; - int lock; - - k_max = 110; - k_min = 10; - - agc2 = stv090x_get_agc2_min_level(state); - - if (agc2 > STV090x_SEARCH_AGC2_TH(state->internal->dev_ver)) { - lock = 0; - } else { - - if (state->internal->dev_ver <= 0x20) { - if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0) - goto err; - } else { - /* > Cut 3 */ - if (STV090x_WRITE_DEMOD(state, CARCFG, 0x06) < 0) - goto err; - } - - if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0) - goto err; - - if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) /* set viterbi hysteresis */ - goto err; - } - - k_ref = k_max; - do { - if (STV090x_WRITE_DEMOD(state, KREFTMG, k_ref) < 0) - goto err; - if (stv090x_srate_srch_coarse(state) != 0) { - srate_coarse = stv090x_srate_srch_fine(state); - if (srate_coarse != 0) { - stv090x_get_lock_tmg(state); - lock = stv090x_get_dmdlock(state, - state->DemodTimeout); - } else { - lock = 0; - } - } else { - cpt_fail = 0; - agc2_ovflw = 0; - for (i = 0; i < 10; i++) { - agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) | - STV090x_READ_DEMOD(state, AGC2I0); - if (agc2 >= 0xff00) - agc2_ovflw++; - reg = STV090x_READ_DEMOD(state, DSTATUS2); - if ((STV090x_GETFIELD_Px(reg, CFR_OVERFLOW_FIELD) == 0x01) && - (STV090x_GETFIELD_Px(reg, DEMOD_DELOCK_FIELD) == 0x01)) - - cpt_fail++; - } - if ((cpt_fail > 7) || (agc2_ovflw > 7)) - coarse_fail = 1; - - lock = 0; - } - k_ref -= 20; - } while ((k_ref >= k_min) && (!lock) && (!coarse_fail)); - } - - return lock; - -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_chk_tmg(struct stv090x_state *state) -{ - u32 reg; - s32 tmg_cpt = 0, i; - u8 freq, tmg_thh, tmg_thl; - int tmg_lock = 0; - - freq = STV090x_READ_DEMOD(state, CARFREQ); - tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE); - tmg_thl = STV090x_READ_DEMOD(state, TMGTHFALL); - if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0) - goto err; - - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); /* stop carrier offset search */ - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, RTC, 0x80) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, RTCS2, 0x40) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x00) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) /* set car ofset to 0 */ - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x65) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) /* trigger acquisition */ - goto err; - msleep(10); - - for (i = 0; i < 10; i++) { - reg = STV090x_READ_DEMOD(state, DSTATUS); - if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2) - tmg_cpt++; - msleep(1); - } - if (tmg_cpt >= 3) - tmg_lock = 1; - - if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) /* DVB-S1 timing */ - goto err; - if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) /* DVB-S2 timing */ - goto err; - - if (STV090x_WRITE_DEMOD(state, CARFREQ, freq) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGTHRISE, tmg_thh) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGTHFALL, tmg_thl) < 0) - goto err; - - return tmg_lock; - -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd) -{ - struct dvb_frontend *fe = &state->frontend; - - u32 reg; - s32 car_step, steps, cur_step, dir, freq, timeout_lock; - int lock = 0; - - if (state->srate >= 10000000) - timeout_lock = timeout_dmd / 3; - else - timeout_lock = timeout_dmd / 2; - - lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */ - if (!lock) { - if (state->srate >= 10000000) { - if (stv090x_chk_tmg(state)) { - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) - goto err; - lock = stv090x_get_dmdlock(state, timeout_dmd); - } else { - lock = 0; - } - } else { - if (state->srate <= 4000000) - car_step = 1000; - else if (state->srate <= 7000000) - car_step = 2000; - else if (state->srate <= 10000000) - car_step = 3000; - else - car_step = 5000; - - steps = (state->search_range / 1000) / car_step; - steps /= 2; - steps = 2 * (steps + 1); - if (steps < 0) - steps = 2; - else if (steps > 12) - steps = 12; - - cur_step = 1; - dir = 1; - - if (!lock) { - freq = state->frequency; - state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate; - while ((cur_step <= steps) && (!lock)) { - if (dir > 0) - freq += cur_step * car_step; - else - freq -= cur_step * car_step; - - /* Setup tuner */ - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (state->config->tuner_set_frequency) { - if (state->config->tuner_set_frequency(fe, freq) < 0) - goto err_gateoff; - } - - if (state->config->tuner_set_bandwidth) { - if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) - goto err_gateoff; - } - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - msleep(50); - - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (state->config->tuner_get_status) { - if (state->config->tuner_get_status(fe, ®) < 0) - goto err_gateoff; - } - - if (reg) - dprintk(FE_DEBUG, 1, "Tuner phase locked"); - else - dprintk(FE_DEBUG, 1, "Tuner unlocked"); - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c); - if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) - goto err; - lock = stv090x_get_dmdlock(state, (timeout_dmd / 3)); - - dir *= -1; - cur_step++; - } - } - } - } - - return lock; - -err_gateoff: - stv090x_i2c_gate_ctrl(state, 0); -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s32 *timeout_sw, s32 *steps) -{ - s32 timeout, inc, steps_max, srate, car_max; - - srate = state->srate; - car_max = state->search_range / 1000; - car_max += car_max / 10; - car_max = 65536 * (car_max / 2); - car_max /= (state->internal->mclk / 1000); - - if (car_max > 0x4000) - car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */ - - inc = srate; - inc /= state->internal->mclk / 1000; - inc *= 256; - inc *= 256; - inc /= 1000; - - switch (state->search_mode) { - case STV090x_SEARCH_DVBS1: - case STV090x_SEARCH_DSS: - inc *= 3; /* freq step = 3% of srate */ - timeout = 20; - break; - - case STV090x_SEARCH_DVBS2: - inc *= 4; - timeout = 25; - break; - - case STV090x_SEARCH_AUTO: - default: - inc *= 3; - timeout = 25; - break; - } - inc /= 100; - if ((inc > car_max) || (inc < 0)) - inc = car_max / 2; /* increment <= 1/8 Mclk */ - - timeout *= 27500; /* 27.5 Msps reference */ - if (srate > 0) - timeout /= (srate / 1000); - - if ((timeout > 100) || (timeout < 0)) - timeout = 100; - - steps_max = (car_max / inc) + 1; /* min steps = 3 */ - if ((steps_max > 100) || (steps_max < 0)) { - steps_max = 100; /* max steps <= 100 */ - inc = car_max / steps_max; - } - *freq_inc = inc; - *timeout_sw = timeout; - *steps = steps_max; - - return 0; -} - -static int stv090x_chk_signal(struct stv090x_state *state) -{ - s32 offst_car, agc2, car_max; - int no_signal; - - offst_car = STV090x_READ_DEMOD(state, CFR2) << 8; - offst_car |= STV090x_READ_DEMOD(state, CFR1); - offst_car = comp2(offst_car, 16); - - agc2 = STV090x_READ_DEMOD(state, AGC2I1) << 8; - agc2 |= STV090x_READ_DEMOD(state, AGC2I0); - car_max = state->search_range / 1000; - - car_max += (car_max / 10); /* 10% margin */ - car_max = (65536 * car_max / 2); - car_max /= state->internal->mclk / 1000; - - if (car_max > 0x4000) - car_max = 0x4000; - - if ((agc2 > 0x2000) || (offst_car > 2 * car_max) || (offst_car < -2 * car_max)) { - no_signal = 1; - dprintk(FE_DEBUG, 1, "No Signal"); - } else { - no_signal = 0; - dprintk(FE_DEBUG, 1, "Found Signal"); - } - - return no_signal; -} - -static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 timeout, int zigzag, s32 steps_max) -{ - int no_signal, lock = 0; - s32 cpt_step = 0, offst_freq, car_max; - u32 reg; - - car_max = state->search_range / 1000; - car_max += (car_max / 10); - car_max = (65536 * car_max / 2); - car_max /= (state->internal->mclk / 1000); - if (car_max > 0x4000) - car_max = 0x4000; - - if (zigzag) - offst_freq = 0; - else - offst_freq = -car_max + inc; - - do { - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT1, ((offst_freq / 256) & 0xff)) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, offst_freq & 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) - goto err; - - reg = STV090x_READ_DEMOD(state, PDELCTRL1); - STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x1); /* stop DVB-S2 packet delin */ - if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) - goto err; - - if (zigzag) { - if (offst_freq >= 0) - offst_freq = -offst_freq - 2 * inc; - else - offst_freq = -offst_freq; - } else { - offst_freq += 2 * inc; - } - - cpt_step++; - - lock = stv090x_get_dmdlock(state, timeout); - no_signal = stv090x_chk_signal(state); - - } while ((!lock) && - (!no_signal) && - ((offst_freq - inc) < car_max) && - ((offst_freq + inc) > -car_max) && - (cpt_step < steps_max)); - - reg = STV090x_READ_DEMOD(state, PDELCTRL1); - STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) - goto err; - - return lock; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_sw_algo(struct stv090x_state *state) -{ - int no_signal, zigzag, lock = 0; - u32 reg; - - s32 dvbs2_fly_wheel; - s32 inc, timeout_step, trials, steps_max; - - /* get params */ - stv090x_get_loop_params(state, &inc, &timeout_step, &steps_max); - - switch (state->search_mode) { - case STV090x_SEARCH_DVBS1: - case STV090x_SEARCH_DSS: - /* accelerate the frequency detector */ - if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0) - goto err; - } - - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x49) < 0) - goto err; - zigzag = 0; - break; - - case STV090x_SEARCH_DVBS2: - if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0) - goto err; - } - - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0) - goto err; - zigzag = 1; - break; - - case STV090x_SEARCH_AUTO: - default: - /* accelerate the frequency detector */ - if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0) - goto err; - } - - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0xc9) < 0) - goto err; - zigzag = 0; - break; - } - - trials = 0; - do { - lock = stv090x_search_car_loop(state, inc, timeout_step, zigzag, steps_max); - no_signal = stv090x_chk_signal(state); - trials++; - - /*run the SW search 2 times maximum*/ - if (lock || no_signal || (trials == 2)) { - /*Check if the demod is not losing lock in DVBS2*/ - if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) - goto err; - } - - reg = STV090x_READ_DEMOD(state, DMDSTATE); - if ((lock) && (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == STV090x_DVBS2)) { - /*Check if the demod is not losing lock in DVBS2*/ - msleep(timeout_step); - reg = STV090x_READ_DEMOD(state, DMDFLYW); - dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD); - if (dvbs2_fly_wheel < 0xd) { /*if correct frames is decrementing */ - msleep(timeout_step); - reg = STV090x_READ_DEMOD(state, DMDFLYW); - dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD); - } - if (dvbs2_fly_wheel < 0xd) { - /*FALSE lock, The demod is loosing lock */ - lock = 0; - if (trials < 2) { - if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0) - goto err; - } - - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0) - goto err; - } - } - } - } - } while ((!lock) && (trials < 2) && (!no_signal)); - - return lock; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static enum stv090x_delsys stv090x_get_std(struct stv090x_state *state) -{ - u32 reg; - enum stv090x_delsys delsys; - - reg = STV090x_READ_DEMOD(state, DMDSTATE); - if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 2) - delsys = STV090x_DVBS2; - else if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 3) { - reg = STV090x_READ_DEMOD(state, FECM); - if (STV090x_GETFIELD_Px(reg, DSS_DVB_FIELD) == 1) - delsys = STV090x_DSS; - else - delsys = STV090x_DVBS1; - } else { - delsys = STV090x_ERROR; - } - - return delsys; -} - -/* in Hz */ -static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk) -{ - s32 derot, int_1, int_2, tmp_1, tmp_2; - - derot = STV090x_READ_DEMOD(state, CFR2) << 16; - derot |= STV090x_READ_DEMOD(state, CFR1) << 8; - derot |= STV090x_READ_DEMOD(state, CFR0); - - derot = comp2(derot, 24); - int_1 = mclk >> 12; - int_2 = derot >> 12; - - /* carrier_frequency = MasterClock * Reg / 2^24 */ - tmp_1 = mclk % 0x1000; - tmp_2 = derot % 0x1000; - - derot = (int_1 * int_2) + - ((int_1 * tmp_2) >> 12) + - ((int_2 * tmp_1) >> 12); - - return derot; -} - -static int stv090x_get_viterbi(struct stv090x_state *state) -{ - u32 reg, rate; - - reg = STV090x_READ_DEMOD(state, VITCURPUN); - rate = STV090x_GETFIELD_Px(reg, VIT_CURPUN_FIELD); - - switch (rate) { - case 13: - state->fec = STV090x_PR12; - break; - - case 18: - state->fec = STV090x_PR23; - break; - - case 21: - state->fec = STV090x_PR34; - break; - - case 24: - state->fec = STV090x_PR56; - break; - - case 25: - state->fec = STV090x_PR67; - break; - - case 26: - state->fec = STV090x_PR78; - break; - - default: - state->fec = STV090x_PRERR; - break; - } - - return 0; -} - -static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *state) -{ - struct dvb_frontend *fe = &state->frontend; - - u8 tmg; - u32 reg; - s32 i = 0, offst_freq; - - msleep(5); - - if (state->algo == STV090x_BLIND_SEARCH) { - tmg = STV090x_READ_DEMOD(state, TMGREG2); - STV090x_WRITE_DEMOD(state, SFRSTEP, 0x5c); - while ((i <= 50) && (tmg != 0) && (tmg != 0xff)) { - tmg = STV090x_READ_DEMOD(state, TMGREG2); - msleep(5); - i += 5; - } - } - state->delsys = stv090x_get_std(state); - - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (state->config->tuner_get_frequency) { - if (state->config->tuner_get_frequency(fe, &state->frequency) < 0) - goto err_gateoff; - } - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - offst_freq = stv090x_get_car_freq(state, state->internal->mclk) / 1000; - state->frequency += offst_freq; - - if (stv090x_get_viterbi(state) < 0) - goto err; - - reg = STV090x_READ_DEMOD(state, DMDMODCOD); - state->modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD); - state->pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01; - state->frame_len = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) >> 1; - reg = STV090x_READ_DEMOD(state, TMGOBS); - state->rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD); - reg = STV090x_READ_DEMOD(state, FECM); - state->inversion = STV090x_GETFIELD_Px(reg, IQINV_FIELD); - - if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) { - - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (state->config->tuner_get_frequency) { - if (state->config->tuner_get_frequency(fe, &state->frequency) < 0) - goto err_gateoff; - } - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - if (abs(offst_freq) <= ((state->search_range / 2000) + 500)) - return STV090x_RANGEOK; - else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000)) - return STV090x_RANGEOK; - else - return STV090x_OUTOFRANGE; /* Out of Range */ - } else { - if (abs(offst_freq) <= ((state->search_range / 2000) + 500)) - return STV090x_RANGEOK; - else - return STV090x_OUTOFRANGE; - } - - return STV090x_OUTOFRANGE; - -err_gateoff: - stv090x_i2c_gate_ctrl(state, 0); -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static u32 stv090x_get_tmgoffst(struct stv090x_state *state, u32 srate) -{ - s32 offst_tmg; - - offst_tmg = STV090x_READ_DEMOD(state, TMGREG2) << 16; - offst_tmg |= STV090x_READ_DEMOD(state, TMGREG1) << 8; - offst_tmg |= STV090x_READ_DEMOD(state, TMGREG0); - - offst_tmg = comp2(offst_tmg, 24); /* 2's complement */ - if (!offst_tmg) - offst_tmg = 1; - - offst_tmg = ((s32) srate * 10) / ((s32) 0x1000000 / offst_tmg); - offst_tmg /= 320; - - return offst_tmg; -} - -static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_modcod modcod, s32 pilots) -{ - u8 aclc = 0x29; - s32 i; - struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low; - - if (state->internal->dev_ver == 0x20) { - car_loop = stv090x_s2_crl_cut20; - car_loop_qpsk_low = stv090x_s2_lowqpsk_crl_cut20; - car_loop_apsk_low = stv090x_s2_apsk_crl_cut20; - } else { - /* >= Cut 3 */ - car_loop = stv090x_s2_crl_cut30; - car_loop_qpsk_low = stv090x_s2_lowqpsk_crl_cut30; - car_loop_apsk_low = stv090x_s2_apsk_crl_cut30; - } - - if (modcod < STV090x_QPSK_12) { - i = 0; - while ((i < 3) && (modcod != car_loop_qpsk_low[i].modcod)) - i++; - - if (i >= 3) - i = 2; - - } else { - i = 0; - while ((i < 14) && (modcod != car_loop[i].modcod)) - i++; - - if (i >= 14) { - i = 0; - while ((i < 11) && (modcod != car_loop_apsk_low[i].modcod)) - i++; - - if (i >= 11) - i = 10; - } - } - - if (modcod <= STV090x_QPSK_25) { - if (pilots) { - if (state->srate <= 3000000) - aclc = car_loop_qpsk_low[i].crl_pilots_on_2; - else if (state->srate <= 7000000) - aclc = car_loop_qpsk_low[i].crl_pilots_on_5; - else if (state->srate <= 15000000) - aclc = car_loop_qpsk_low[i].crl_pilots_on_10; - else if (state->srate <= 25000000) - aclc = car_loop_qpsk_low[i].crl_pilots_on_20; - else - aclc = car_loop_qpsk_low[i].crl_pilots_on_30; - } else { - if (state->srate <= 3000000) - aclc = car_loop_qpsk_low[i].crl_pilots_off_2; - else if (state->srate <= 7000000) - aclc = car_loop_qpsk_low[i].crl_pilots_off_5; - else if (state->srate <= 15000000) - aclc = car_loop_qpsk_low[i].crl_pilots_off_10; - else if (state->srate <= 25000000) - aclc = car_loop_qpsk_low[i].crl_pilots_off_20; - else - aclc = car_loop_qpsk_low[i].crl_pilots_off_30; - } - - } else if (modcod <= STV090x_8PSK_910) { - if (pilots) { - if (state->srate <= 3000000) - aclc = car_loop[i].crl_pilots_on_2; - else if (state->srate <= 7000000) - aclc = car_loop[i].crl_pilots_on_5; - else if (state->srate <= 15000000) - aclc = car_loop[i].crl_pilots_on_10; - else if (state->srate <= 25000000) - aclc = car_loop[i].crl_pilots_on_20; - else - aclc = car_loop[i].crl_pilots_on_30; - } else { - if (state->srate <= 3000000) - aclc = car_loop[i].crl_pilots_off_2; - else if (state->srate <= 7000000) - aclc = car_loop[i].crl_pilots_off_5; - else if (state->srate <= 15000000) - aclc = car_loop[i].crl_pilots_off_10; - else if (state->srate <= 25000000) - aclc = car_loop[i].crl_pilots_off_20; - else - aclc = car_loop[i].crl_pilots_off_30; - } - } else { /* 16APSK and 32APSK */ - if (state->srate <= 3000000) - aclc = car_loop_apsk_low[i].crl_pilots_on_2; - else if (state->srate <= 7000000) - aclc = car_loop_apsk_low[i].crl_pilots_on_5; - else if (state->srate <= 15000000) - aclc = car_loop_apsk_low[i].crl_pilots_on_10; - else if (state->srate <= 25000000) - aclc = car_loop_apsk_low[i].crl_pilots_on_20; - else - aclc = car_loop_apsk_low[i].crl_pilots_on_30; - } - - return aclc; -} - -static u8 stv090x_optimize_carloop_short(struct stv090x_state *state) -{ - struct stv090x_short_frame_crloop *short_crl = NULL; - s32 index = 0; - u8 aclc = 0x0b; - - switch (state->modulation) { - case STV090x_QPSK: - default: - index = 0; - break; - case STV090x_8PSK: - index = 1; - break; - case STV090x_16APSK: - index = 2; - break; - case STV090x_32APSK: - index = 3; - break; - } - - if (state->internal->dev_ver >= 0x30) { - /* Cut 3.0 and up */ - short_crl = stv090x_s2_short_crl_cut30; - } else { - /* Cut 2.0 and up: we don't support cuts older than 2.0 */ - short_crl = stv090x_s2_short_crl_cut20; - } - - if (state->srate <= 3000000) - aclc = short_crl[index].crl_2; - else if (state->srate <= 7000000) - aclc = short_crl[index].crl_5; - else if (state->srate <= 15000000) - aclc = short_crl[index].crl_10; - else if (state->srate <= 25000000) - aclc = short_crl[index].crl_20; - else - aclc = short_crl[index].crl_30; - - return aclc; -} - -static int stv090x_optimize_track(struct stv090x_state *state) -{ - struct dvb_frontend *fe = &state->frontend; - - enum stv090x_rolloff rolloff; - enum stv090x_modcod modcod; - - s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0; - u32 reg; - - srate = stv090x_get_srate(state, state->internal->mclk); - srate += stv090x_get_tmgoffst(state, srate); - - switch (state->delsys) { - case STV090x_DVBS1: - case STV090x_DSS: - if (state->search_mode == STV090x_SEARCH_AUTO) { - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); - STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - } - reg = STV090x_READ_DEMOD(state, DEMOD); - STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff); - STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x01); - if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) - goto err; - - if (state->internal->dev_ver >= 0x30) { - if (stv090x_get_viterbi(state) < 0) - goto err; - - if (state->fec == STV090x_PR12) { - if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x98) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0) - goto err; - } else { - if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x18) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0) - goto err; - } - } - - if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0) - goto err; - break; - - case STV090x_DVBS2: - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0); - STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - if (state->internal->dev_ver >= 0x30) { - if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0) - goto err; - } - if (state->frame_len == STV090x_LONG_FRAME) { - reg = STV090x_READ_DEMOD(state, DMDMODCOD); - modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD); - pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01; - aclc = stv090x_optimize_carloop(state, modcod, pilots); - if (modcod <= STV090x_QPSK_910) { - STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc); - } else if (modcod <= STV090x_8PSK_910) { - if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0) - goto err; - } - if ((state->demod_mode == STV090x_SINGLE) && (modcod > STV090x_8PSK_910)) { - if (modcod <= STV090x_16APSK_910) { - if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0) - goto err; - } else { - if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0) - goto err; - } - } - } else { - /*Carrier loop setting for short frame*/ - aclc = stv090x_optimize_carloop_short(state); - if (state->modulation == STV090x_QPSK) { - if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc) < 0) - goto err; - } else if (state->modulation == STV090x_8PSK) { - if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0) - goto err; - } else if (state->modulation == STV090x_16APSK) { - if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0) - goto err; - } else if (state->modulation == STV090x_32APSK) { - if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0) - goto err; - } - } - - STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */ - break; - - case STV090x_ERROR: - default: - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); - STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - break; - } - - f_1 = STV090x_READ_DEMOD(state, CFR2); - f_0 = STV090x_READ_DEMOD(state, CFR1); - reg = STV090x_READ_DEMOD(state, TMGOBS); - rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD); - - if (state->algo == STV090x_BLIND_SEARCH) { - STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00); - reg = STV090x_READ_DEMOD(state, DMDCFGMD); - STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0x00); - STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); - if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) - goto err; - - if (stv090x_set_srate(state, srate) < 0) - goto err; - blind_tune = 1; - - if (stv090x_dvbs_track_crl(state) < 0) - goto err; - } - - if (state->internal->dev_ver >= 0x20) { - if ((state->search_mode == STV090x_SEARCH_DVBS1) || - (state->search_mode == STV090x_SEARCH_DSS) || - (state->search_mode == STV090x_SEARCH_AUTO)) { - - if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x0a) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x00) < 0) - goto err; - } - } - - if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) - goto err; - - /* AUTO tracking MODE */ - if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x80) < 0) - goto err; - /* AUTO tracking MODE */ - if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0) - goto err; - - if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1) || - (state->srate < 10000000)) { - /* update initial carrier freq with the found freq offset */ - if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0) - goto err; - state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000; - - if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1)) { - - if (state->algo != STV090x_WARM_SEARCH) { - - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (state->config->tuner_set_bandwidth) { - if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) - goto err_gateoff; - } - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - } - } - if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) - msleep(50); /* blind search: wait 50ms for SR stabilization */ - else - msleep(5); - - stv090x_get_lock_tmg(state); - - if (!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) { - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) - goto err; - - i = 0; - - while ((!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) && (i <= 2)) { - - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) - goto err; - i++; - } - } - - } - - if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0) - goto err; - } - - if ((state->delsys == STV090x_DVBS1) || (state->delsys == STV090x_DSS)) - stv090x_set_vit_thtracq(state); - - return 0; - -err_gateoff: - stv090x_i2c_gate_ctrl(state, 0); -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_get_feclock(struct stv090x_state *state, s32 timeout) -{ - s32 timer = 0, lock = 0, stat; - u32 reg; - - while ((timer < timeout) && (!lock)) { - reg = STV090x_READ_DEMOD(state, DMDSTATE); - stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); - - switch (stat) { - case 0: /* searching */ - case 1: /* first PLH detected */ - default: - lock = 0; - break; - - case 2: /* DVB-S2 mode */ - reg = STV090x_READ_DEMOD(state, PDELSTATUS1); - lock = STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD); - break; - - case 3: /* DVB-S1/legacy mode */ - reg = STV090x_READ_DEMOD(state, VSTATUSVIT); - lock = STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD); - break; - } - if (!lock) { - msleep(10); - timer += 10; - } - } - return lock; -} - -static int stv090x_get_lock(struct stv090x_state *state, s32 timeout_dmd, s32 timeout_fec) -{ - u32 reg; - s32 timer = 0; - int lock; - - lock = stv090x_get_dmdlock(state, timeout_dmd); - if (lock) - lock = stv090x_get_feclock(state, timeout_fec); - - if (lock) { - lock = 0; - - while ((timer < timeout_fec) && (!lock)) { - reg = STV090x_READ_DEMOD(state, TSSTATUS); - lock = STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD); - msleep(1); - timer++; - } - } - - return lock; -} - -static int stv090x_set_s2rolloff(struct stv090x_state *state) -{ - u32 reg; - - if (state->internal->dev_ver <= 0x20) { - /* rolloff to auto mode if DVBS2 */ - reg = STV090x_READ_DEMOD(state, DEMOD); - STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00); - if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) - goto err; - } else { - /* DVB-S2 rolloff to auto mode if DVBS2 */ - reg = STV090x_READ_DEMOD(state, DEMOD); - STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 0x00); - if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) - goto err; - } - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - - -static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state) -{ - struct dvb_frontend *fe = &state->frontend; - enum stv090x_signal_state signal_state = STV090x_NOCARRIER; - u32 reg; - s32 agc1_power, power_iq = 0, i; - int lock = 0, low_sr = 0, no_signal = 0; - - reg = STV090x_READ_DEMOD(state, TSCFGH); - STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */ - if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */ - goto err; - - if (state->internal->dev_ver >= 0x20) { - if (state->srate > 5000000) { - if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) - goto err; - } else { - if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x82) < 0) - goto err; - } - } - - stv090x_get_lock_tmg(state); - - if (state->algo == STV090x_BLIND_SEARCH) { - state->tuner_bw = 2 * 36000000; /* wide bw for unknown srate */ - if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) /* wider srate scan */ - goto err; - if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0) - goto err; - if (stv090x_set_srate(state, 1000000) < 0) /* inital srate = 1Msps */ - goto err; - } else { - /* known srate */ - if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0) - goto err; - - if (state->srate < 2000000) { - /* SR < 2MSPS */ - if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x63) < 0) - goto err; - } else { - /* SR >= 2Msps */ - if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0) - goto err; - } - - if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) - goto err; - - if (state->internal->dev_ver >= 0x20) { - if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0) - goto err; - if (state->algo == STV090x_COLD_SEARCH) - state->tuner_bw = (15 * (stv090x_car_width(state->srate, state->rolloff) + 10000000)) / 10; - else if (state->algo == STV090x_WARM_SEARCH) - state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + 10000000; - } - - /* if cold start or warm (Symbolrate is known) - * use a Narrow symbol rate scan range - */ - if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) /* narrow srate scan */ - goto err; - - if (stv090x_set_srate(state, state->srate) < 0) - goto err; - - if (stv090x_set_max_srate(state, state->internal->mclk, - state->srate) < 0) - goto err; - if (stv090x_set_min_srate(state, state->internal->mclk, - state->srate) < 0) - goto err; - - if (state->srate >= 10000000) - low_sr = 0; - else - low_sr = 1; - } - - /* Setup tuner */ - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (state->config->tuner_set_bbgain) { - reg = state->config->tuner_bbgain; - if (reg == 0) - reg = 10; /* default: 10dB */ - if (state->config->tuner_set_bbgain(fe, reg) < 0) - goto err_gateoff; - } - - if (state->config->tuner_set_frequency) { - if (state->config->tuner_set_frequency(fe, state->frequency) < 0) - goto err_gateoff; - } - - if (state->config->tuner_set_bandwidth) { - if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) - goto err_gateoff; - } - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - msleep(50); - - if (state->config->tuner_get_status) { - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - if (state->config->tuner_get_status(fe, ®) < 0) - goto err_gateoff; - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - if (reg) - dprintk(FE_DEBUG, 1, "Tuner phase locked"); - else { - dprintk(FE_DEBUG, 1, "Tuner unlocked"); - return STV090x_NOCARRIER; - } - } - - msleep(10); - agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1), - STV090x_READ_DEMOD(state, AGCIQIN0)); - - if (agc1_power == 0) { - /* If AGC1 integrator value is 0 - * then read POWERI, POWERQ - */ - for (i = 0; i < 5; i++) { - power_iq += (STV090x_READ_DEMOD(state, POWERI) + - STV090x_READ_DEMOD(state, POWERQ)) >> 1; - } - power_iq /= 5; - } - - if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) { - dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq); - lock = 0; - signal_state = STV090x_NOAGC1; - } else { - reg = STV090x_READ_DEMOD(state, DEMOD); - STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion); - - if (state->internal->dev_ver <= 0x20) { - /* rolloff to auto mode if DVBS2 */ - STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1); - } else { - /* DVB-S2 rolloff to auto mode if DVBS2 */ - STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 1); - } - if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) - goto err; - - if (stv090x_delivery_search(state) < 0) - goto err; - - if (state->algo != STV090x_BLIND_SEARCH) { - if (stv090x_start_search(state) < 0) - goto err; - } - } - - if (signal_state == STV090x_NOAGC1) - return signal_state; - - if (state->algo == STV090x_BLIND_SEARCH) - lock = stv090x_blind_search(state); - - else if (state->algo == STV090x_COLD_SEARCH) - lock = stv090x_get_coldlock(state, state->DemodTimeout); - - else if (state->algo == STV090x_WARM_SEARCH) - lock = stv090x_get_dmdlock(state, state->DemodTimeout); - - if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) { - if (!low_sr) { - if (stv090x_chk_tmg(state)) - lock = stv090x_sw_algo(state); - } - } - - if (lock) - signal_state = stv090x_get_sig_params(state); - - if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */ - stv090x_optimize_track(state); - - if (state->internal->dev_ver >= 0x20) { - /* >= Cut 2.0 :release TS reset after - * demod lock and optimized Tracking - */ - reg = STV090x_READ_DEMOD(state, TSCFGH); - STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */ - if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) - goto err; - - msleep(3); - - STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* merger reset */ - if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) - goto err; - - STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */ - if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) - goto err; - } - - lock = stv090x_get_lock(state, state->FecTimeout, - state->FecTimeout); - if (lock) { - if (state->delsys == STV090x_DVBS2) { - stv090x_set_s2rolloff(state); - - reg = STV090x_READ_DEMOD(state, PDELCTRL2); - STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 1); - if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0) - goto err; - /* Reset DVBS2 packet delinator error counter */ - reg = STV090x_READ_DEMOD(state, PDELCTRL2); - STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 0); - if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */ - goto err; - } else { - if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0) - goto err; - } - /* Reset the Total packet counter */ - if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0x00) < 0) - goto err; - /* Reset the packet Error counter2 */ - if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0) - goto err; - } else { - signal_state = STV090x_NODATA; - no_signal = stv090x_chk_signal(state); - } - } - return signal_state; - -err_gateoff: - stv090x_i2c_gate_ctrl(state, 0); -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - struct stv090x_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *props = &fe->dtv_property_cache; - - if (p->frequency == 0) - return DVBFE_ALGO_SEARCH_INVALID; - - state->delsys = props->delivery_system; - state->frequency = p->frequency; - state->srate = p->u.qpsk.symbol_rate; - state->search_mode = STV090x_SEARCH_AUTO; - state->algo = STV090x_COLD_SEARCH; - state->fec = STV090x_PRERR; - if (state->srate > 10000000) { - dprintk(FE_DEBUG, 1, "Search range: 10 MHz"); - state->search_range = 10000000; - } else { - dprintk(FE_DEBUG, 1, "Search range: 5 MHz"); - state->search_range = 5000000; - } - - if (stv090x_algo(state) == STV090x_RANGEOK) { - dprintk(FE_DEBUG, 1, "Search success!"); - return DVBFE_ALGO_SEARCH_SUCCESS; - } else { - dprintk(FE_DEBUG, 1, "Search failed!"); - return DVBFE_ALGO_SEARCH_FAILED; - } - - return DVBFE_ALGO_SEARCH_ERROR; -} - -static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status) -{ - struct stv090x_state *state = fe->demodulator_priv; - u32 reg; - u8 search_state; - - reg = STV090x_READ_DEMOD(state, DMDSTATE); - search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); - - switch (search_state) { - case 0: /* searching */ - case 1: /* first PLH detected */ - default: - dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)"); - *status = 0; - break; - - case 2: /* DVB-S2 mode */ - dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2"); - reg = STV090x_READ_DEMOD(state, DSTATUS); - if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) { - reg = STV090x_READ_DEMOD(state, PDELSTATUS1); - if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) { - reg = STV090x_READ_DEMOD(state, TSSTATUS); - if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) { - *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_LOCK; - } - } - } - break; - - case 3: /* DVB-S1/legacy mode */ - dprintk(FE_DEBUG, 1, "Delivery system: DVB-S"); - reg = STV090x_READ_DEMOD(state, DSTATUS); - if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) { - reg = STV090x_READ_DEMOD(state, VSTATUSVIT); - if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) { - reg = STV090x_READ_DEMOD(state, TSSTATUS); - if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) { - *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_LOCK; - } - } - } - break; - } - - return 0; -} - -static int stv090x_read_per(struct dvb_frontend *fe, u32 *per) -{ - struct stv090x_state *state = fe->demodulator_priv; - - s32 count_4, count_3, count_2, count_1, count_0, count; - u32 reg, h, m, l; - enum fe_status status; - - stv090x_read_status(fe, &status); - if (!(status & FE_HAS_LOCK)) { - *per = 1 << 23; /* Max PER */ - } else { - /* Counter 2 */ - reg = STV090x_READ_DEMOD(state, ERRCNT22); - h = STV090x_GETFIELD_Px(reg, ERR_CNT2_FIELD); - - reg = STV090x_READ_DEMOD(state, ERRCNT21); - m = STV090x_GETFIELD_Px(reg, ERR_CNT21_FIELD); - - reg = STV090x_READ_DEMOD(state, ERRCNT20); - l = STV090x_GETFIELD_Px(reg, ERR_CNT20_FIELD); - - *per = ((h << 16) | (m << 8) | l); - - count_4 = STV090x_READ_DEMOD(state, FBERCPT4); - count_3 = STV090x_READ_DEMOD(state, FBERCPT3); - count_2 = STV090x_READ_DEMOD(state, FBERCPT2); - count_1 = STV090x_READ_DEMOD(state, FBERCPT1); - count_0 = STV090x_READ_DEMOD(state, FBERCPT0); - - if ((!count_4) && (!count_3)) { - count = (count_2 & 0xff) << 16; - count |= (count_1 & 0xff) << 8; - count |= count_0 & 0xff; - } else { - count = 1 << 24; - } - if (count == 0) - *per = 1; - } - if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0) - goto err; - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val) -{ - int res = 0; - int min = 0, med; - - if ((val >= tab[min].read && val < tab[max].read) || - (val >= tab[max].read && val < tab[min].read)) { - while ((max - min) > 1) { - med = (max + min) / 2; - if ((val >= tab[min].read && val < tab[med].read) || - (val >= tab[med].read && val < tab[min].read)) - max = med; - else - min = med; - } - res = ((val - tab[min].read) * - (tab[max].real - tab[min].real) / - (tab[max].read - tab[min].read)) + - tab[min].real; - } else { - if (tab[min].read < tab[max].read) { - if (val < tab[min].read) - res = tab[min].real; - else if (val >= tab[max].read) - res = tab[max].real; - } else { - if (val >= tab[min].read) - res = tab[min].real; - else if (val < tab[max].read) - res = tab[max].real; - } - } - - return res; -} - -static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct stv090x_state *state = fe->demodulator_priv; - u32 reg; - s32 agc_0, agc_1, agc; - s32 str; - - reg = STV090x_READ_DEMOD(state, AGCIQIN1); - agc_1 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD); - reg = STV090x_READ_DEMOD(state, AGCIQIN0); - agc_0 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD); - agc = MAKEWORD16(agc_1, agc_0); - - str = stv090x_table_lookup(stv090x_rf_tab, - ARRAY_SIZE(stv090x_rf_tab) - 1, agc); - if (agc > stv090x_rf_tab[0].read) - str = 0; - else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read) - str = -100; - *strength = (str + 100) * 0xFFFF / 100; - - return 0; -} - -static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr) -{ - struct stv090x_state *state = fe->demodulator_priv; - u32 reg_0, reg_1, reg, i; - s32 val_0, val_1, val = 0; - u8 lock_f; - s32 div; - u32 last; - - switch (state->delsys) { - case STV090x_DVBS2: - reg = STV090x_READ_DEMOD(state, DSTATUS); - lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD); - if (lock_f) { - msleep(5); - for (i = 0; i < 16; i++) { - reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1); - val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD); - reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0); - val_0 = STV090x_GETFIELD_Px(reg_0, NOSPLHT_NORMED_FIELD); - val += MAKEWORD16(val_1, val_0); - msleep(1); - } - val /= 16; - last = ARRAY_SIZE(stv090x_s2cn_tab) - 1; - div = stv090x_s2cn_tab[0].read - - stv090x_s2cn_tab[last].read; - *cnr = 0xFFFF - ((val * 0xFFFF) / div); - } - break; - - case STV090x_DVBS1: - case STV090x_DSS: - reg = STV090x_READ_DEMOD(state, DSTATUS); - lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD); - if (lock_f) { - msleep(5); - for (i = 0; i < 16; i++) { - reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1); - val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD); - reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0); - val_0 = STV090x_GETFIELD_Px(reg_0, NOSDATAT_UNNORMED_FIELD); - val += MAKEWORD16(val_1, val_0); - msleep(1); - } - val /= 16; - last = ARRAY_SIZE(stv090x_s1cn_tab) - 1; - div = stv090x_s1cn_tab[0].read - - stv090x_s1cn_tab[last].read; - *cnr = 0xFFFF - ((val * 0xFFFF) / div); - } - break; - default: - break; - } - - return 0; -} - -static int stv090x_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct stv090x_state *state = fe->demodulator_priv; - u32 reg; - - reg = STV090x_READ_DEMOD(state, DISTXCTL); - switch (tone) { - case SEC_TONE_ON: - STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0); - STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - break; - - case SEC_TONE_OFF: - STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0); - STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - break; - default: - return -EINVAL; - } - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - - -static enum dvbfe_algo stv090x_frontend_algo(struct dvb_frontend *fe) -{ - return DVBFE_ALGO_CUSTOM; -} - -static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) -{ - struct stv090x_state *state = fe->demodulator_priv; - u32 reg, idle = 0, fifo_full = 1; - int i; - - reg = STV090x_READ_DEMOD(state, DISTXCTL); - - STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, - (state->config->diseqc_envelope_mode) ? 4 : 2); - STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - - STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - - for (i = 0; i < cmd->msg_len; i++) { - - while (fifo_full) { - reg = STV090x_READ_DEMOD(state, DISTXSTATUS); - fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD); - } - - if (STV090x_WRITE_DEMOD(state, DISTXDATA, cmd->msg[i]) < 0) - goto err; - } - reg = STV090x_READ_DEMOD(state, DISTXCTL); - STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - - i = 0; - - while ((!idle) && (i < 10)) { - reg = STV090x_READ_DEMOD(state, DISTXSTATUS); - idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD); - msleep(10); - i++; - } - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) -{ - struct stv090x_state *state = fe->demodulator_priv; - u32 reg, idle = 0, fifo_full = 1; - u8 mode, value; - int i; - - reg = STV090x_READ_DEMOD(state, DISTXCTL); - - if (burst == SEC_MINI_A) { - mode = (state->config->diseqc_envelope_mode) ? 5 : 3; - value = 0x00; - } else { - mode = (state->config->diseqc_envelope_mode) ? 4 : 2; - value = 0xFF; - } - - STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, mode); - STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - - STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - - while (fifo_full) { - reg = STV090x_READ_DEMOD(state, DISTXSTATUS); - fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD); - } - - if (STV090x_WRITE_DEMOD(state, DISTXDATA, value) < 0) - goto err; - - reg = STV090x_READ_DEMOD(state, DISTXCTL); - STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0); - if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) - goto err; - - i = 0; - - while ((!idle) && (i < 10)) { - reg = STV090x_READ_DEMOD(state, DISTXSTATUS); - idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD); - msleep(10); - i++; - } - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply) -{ - struct stv090x_state *state = fe->demodulator_priv; - u32 reg = 0, i = 0, rx_end = 0; - - while ((rx_end != 1) && (i < 10)) { - msleep(10); - i++; - reg = STV090x_READ_DEMOD(state, DISRX_ST0); - rx_end = STV090x_GETFIELD_Px(reg, RX_END_FIELD); - } - - if (rx_end) { - reply->msg_len = STV090x_GETFIELD_Px(reg, FIFO_BYTENBR_FIELD); - for (i = 0; i < reply->msg_len; i++) - reply->msg[i] = STV090x_READ_DEMOD(state, DISRXDATA); - } - - return 0; -} - -static int stv090x_sleep(struct dvb_frontend *fe) -{ - struct stv090x_state *state = fe->demodulator_priv; - u32 reg; - u8 full_standby = 0; - - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (state->config->tuner_sleep) { - if (state->config->tuner_sleep(fe) < 0) - goto err_gateoff; - } - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - dprintk(FE_DEBUG, 1, "Set %s(%d) to sleep", - state->device == STV0900 ? "STV0900" : "STV0903", - state->demod); - - mutex_lock(&state->internal->demod_lock); - - switch (state->demod) { - case STV090x_DEMODULATOR_0: - /* power off ADC 1 */ - reg = stv090x_read_reg(state, STV090x_TSTTNR1); - STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0); - if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) - goto err; - /* power off DiSEqC 1 */ - reg = stv090x_read_reg(state, STV090x_TSTTNR2); - STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 0); - if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0) - goto err; - - /* check whether path 2 is already sleeping, that is when - ADC2 is off */ - reg = stv090x_read_reg(state, STV090x_TSTTNR3); - if (STV090x_GETFIELD(reg, ADC2_PON_FIELD) == 0) - full_standby = 1; - - /* stop clocks */ - reg = stv090x_read_reg(state, STV090x_STOPCLK1); - /* packet delineator 1 clock */ - STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 1); - /* ADC 1 clock */ - STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 1); - /* FEC clock is shared between the two paths, only stop it - when full standby is possible */ - if (full_standby) - STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1); - if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) - goto err; - reg = stv090x_read_reg(state, STV090x_STOPCLK2); - /* sampling 1 clock */ - STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 1); - /* viterbi 1 clock */ - STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 1); - /* TS clock is shared between the two paths, only stop it - when full standby is possible */ - if (full_standby) - STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1); - if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) - goto err; - break; - - case STV090x_DEMODULATOR_1: - /* power off ADC 2 */ - reg = stv090x_read_reg(state, STV090x_TSTTNR3); - STV090x_SETFIELD(reg, ADC2_PON_FIELD, 0); - if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0) - goto err; - /* power off DiSEqC 2 */ - reg = stv090x_read_reg(state, STV090x_TSTTNR4); - STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 0); - if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0) - goto err; - - /* check whether path 1 is already sleeping, that is when - ADC1 is off */ - reg = stv090x_read_reg(state, STV090x_TSTTNR1); - if (STV090x_GETFIELD(reg, ADC1_PON_FIELD) == 0) - full_standby = 1; - - /* stop clocks */ - reg = stv090x_read_reg(state, STV090x_STOPCLK1); - /* packet delineator 2 clock */ - STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 1); - /* ADC 2 clock */ - STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 1); - /* FEC clock is shared between the two paths, only stop it - when full standby is possible */ - if (full_standby) - STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1); - if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) - goto err; - reg = stv090x_read_reg(state, STV090x_STOPCLK2); - /* sampling 2 clock */ - STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 1); - /* viterbi 2 clock */ - STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 1); - /* TS clock is shared between the two paths, only stop it - when full standby is possible */ - if (full_standby) - STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1); - if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) - goto err; - break; - - default: - dprintk(FE_ERROR, 1, "Wrong demodulator!"); - break; - } - - if (full_standby) { - /* general power off */ - reg = stv090x_read_reg(state, STV090x_SYNTCTRL); - STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01); - if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) - goto err; - } - - mutex_unlock(&state->internal->demod_lock); - return 0; - -err_gateoff: - stv090x_i2c_gate_ctrl(state, 0); -err: - mutex_unlock(&state->internal->demod_lock); - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_wakeup(struct dvb_frontend *fe) -{ - struct stv090x_state *state = fe->demodulator_priv; - u32 reg; - - dprintk(FE_DEBUG, 1, "Wake %s(%d) from standby", - state->device == STV0900 ? "STV0900" : "STV0903", - state->demod); - - mutex_lock(&state->internal->demod_lock); - - /* general power on */ - reg = stv090x_read_reg(state, STV090x_SYNTCTRL); - STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00); - if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) - goto err; - - switch (state->demod) { - case STV090x_DEMODULATOR_0: - /* power on ADC 1 */ - reg = stv090x_read_reg(state, STV090x_TSTTNR1); - STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1); - if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) - goto err; - /* power on DiSEqC 1 */ - reg = stv090x_read_reg(state, STV090x_TSTTNR2); - STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 1); - if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0) - goto err; - - /* activate clocks */ - reg = stv090x_read_reg(state, STV090x_STOPCLK1); - /* packet delineator 1 clock */ - STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 0); - /* ADC 1 clock */ - STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 0); - /* FEC clock */ - STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0); - if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) - goto err; - reg = stv090x_read_reg(state, STV090x_STOPCLK2); - /* sampling 1 clock */ - STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 0); - /* viterbi 1 clock */ - STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 0); - /* TS clock */ - STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0); - if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) - goto err; - break; - - case STV090x_DEMODULATOR_1: - /* power on ADC 2 */ - reg = stv090x_read_reg(state, STV090x_TSTTNR3); - STV090x_SETFIELD(reg, ADC2_PON_FIELD, 1); - if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0) - goto err; - /* power on DiSEqC 2 */ - reg = stv090x_read_reg(state, STV090x_TSTTNR4); - STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 1); - if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0) - goto err; - - /* activate clocks */ - reg = stv090x_read_reg(state, STV090x_STOPCLK1); - /* packet delineator 2 clock */ - STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 0); - /* ADC 2 clock */ - STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 0); - /* FEC clock */ - STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0); - if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) - goto err; - reg = stv090x_read_reg(state, STV090x_STOPCLK2); - /* sampling 2 clock */ - STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 0); - /* viterbi 2 clock */ - STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 0); - /* TS clock */ - STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0); - if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) - goto err; - break; - - default: - dprintk(FE_ERROR, 1, "Wrong demodulator!"); - break; - } - - mutex_unlock(&state->internal->demod_lock); - return 0; -err: - mutex_unlock(&state->internal->demod_lock); - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static void stv090x_release(struct dvb_frontend *fe) -{ - struct stv090x_state *state = fe->demodulator_priv; - - state->internal->num_used--; - if (state->internal->num_used <= 0) { - - dprintk(FE_ERROR, 1, "Actually removing"); - - remove_dev(state->internal); - kfree(state->internal); - } - - kfree(state); -} - -static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc_mode) -{ - u32 reg = 0; - - reg = stv090x_read_reg(state, STV090x_GENCFG); - - switch (ldpc_mode) { - case STV090x_DUAL: - default: - if ((state->demod_mode != STV090x_DUAL) || (STV090x_GETFIELD(reg, DDEMOD_FIELD) != 1)) { - /* set LDPC to dual mode */ - if (stv090x_write_reg(state, STV090x_GENCFG, 0x1d) < 0) - goto err; - - state->demod_mode = STV090x_DUAL; - - reg = stv090x_read_reg(state, STV090x_TSTRES0); - STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1); - if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) - goto err; - STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0); - if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0) - goto err; - - if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0) - goto err; - } - break; - - case STV090x_SINGLE: - if (stv090x_stop_modcod(state) < 0) - goto err; - if (stv090x_activate_modcod_single(state) < 0) - goto err; - - if (state->demod == STV090x_DEMODULATOR_1) { - if (stv090x_write_reg(state, STV090x_GENCFG, 0x06) < 0) /* path 2 */ - goto err; - } else { - if (stv090x_write_reg(state, STV090x_GENCFG, 0x04) < 0) /* path 1 */ - goto err; - } - - reg = stv090x_read_reg(state, STV090x_TSTRES0); - STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1); - if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) - goto err; - STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0); - if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) - goto err; - - reg = STV090x_READ_DEMOD(state, PDELCTRL1); - STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x01); - if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) - goto err; - STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x00); - if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) - goto err; - break; - } - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -/* return (Hz), clk in Hz*/ -static u32 stv090x_get_mclk(struct stv090x_state *state) -{ - const struct stv090x_config *config = state->config; - u32 div, reg; - u8 ratio; - - div = stv090x_read_reg(state, STV090x_NCOARSE); - reg = stv090x_read_reg(state, STV090x_SYNTCTRL); - ratio = STV090x_GETFIELD(reg, SELX1RATIO_FIELD) ? 4 : 6; - - return (div + 1) * config->xtal / ratio; /* kHz */ -} - -static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk) -{ - const struct stv090x_config *config = state->config; - u32 reg, div, clk_sel; - - reg = stv090x_read_reg(state, STV090x_SYNTCTRL); - clk_sel = ((STV090x_GETFIELD(reg, SELX1RATIO_FIELD) == 1) ? 4 : 6); - - div = ((clk_sel * mclk) / config->xtal) - 1; - - reg = stv090x_read_reg(state, STV090x_NCOARSE); - STV090x_SETFIELD(reg, M_DIV_FIELD, div); - if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0) - goto err; - - state->internal->mclk = stv090x_get_mclk(state); - - /*Set the DiseqC frequency to 22KHz */ - div = state->internal->mclk / 704000; - if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0) - goto err; - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_set_tspath(struct stv090x_state *state) -{ - u32 reg; - - if (state->internal->dev_ver >= 0x20) { - switch (state->config->ts1_mode) { - case STV090x_TSMODE_PARALLEL_PUNCTURED: - case STV090x_TSMODE_DVBCI: - switch (state->config->ts2_mode) { - case STV090x_TSMODE_SERIAL_PUNCTURED: - case STV090x_TSMODE_SERIAL_CONTINUOUS: - default: - stv090x_write_reg(state, STV090x_TSGENERAL, 0x00); - break; - - case STV090x_TSMODE_PARALLEL_PUNCTURED: - case STV090x_TSMODE_DVBCI: - if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x06) < 0) /* Mux'd stream mode */ - goto err; - reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); - STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); - if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) - goto err; - reg = stv090x_read_reg(state, STV090x_P2_TSCFGM); - STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); - if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0) - goto err; - break; - } - break; - - case STV090x_TSMODE_SERIAL_PUNCTURED: - case STV090x_TSMODE_SERIAL_CONTINUOUS: - default: - switch (state->config->ts2_mode) { - case STV090x_TSMODE_SERIAL_PUNCTURED: - case STV090x_TSMODE_SERIAL_CONTINUOUS: - default: - if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0) - goto err; - break; - - case STV090x_TSMODE_PARALLEL_PUNCTURED: - case STV090x_TSMODE_DVBCI: - if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0a) < 0) - goto err; - break; - } - break; - } - } else { - switch (state->config->ts1_mode) { - case STV090x_TSMODE_PARALLEL_PUNCTURED: - case STV090x_TSMODE_DVBCI: - switch (state->config->ts2_mode) { - case STV090x_TSMODE_SERIAL_PUNCTURED: - case STV090x_TSMODE_SERIAL_CONTINUOUS: - default: - stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10); - break; - - case STV090x_TSMODE_PARALLEL_PUNCTURED: - case STV090x_TSMODE_DVBCI: - stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x16); - reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); - STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); - if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) - goto err; - reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); - STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 0); - if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0) - goto err; - break; - } - break; - - case STV090x_TSMODE_SERIAL_PUNCTURED: - case STV090x_TSMODE_SERIAL_CONTINUOUS: - default: - switch (state->config->ts2_mode) { - case STV090x_TSMODE_SERIAL_PUNCTURED: - case STV090x_TSMODE_SERIAL_CONTINUOUS: - default: - stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14); - break; - - case STV090x_TSMODE_PARALLEL_PUNCTURED: - case STV090x_TSMODE_DVBCI: - stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x12); - break; - } - break; - } - } - - switch (state->config->ts1_mode) { - case STV090x_TSMODE_PARALLEL_PUNCTURED: - reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); - STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); - STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); - STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); - if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) - goto err; - break; - - case STV090x_TSMODE_DVBCI: - reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); - STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); - STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); - STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); - if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) - goto err; - break; - - case STV090x_TSMODE_SERIAL_PUNCTURED: - reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); - STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); - STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); - STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); - if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) - goto err; - break; - - case STV090x_TSMODE_SERIAL_CONTINUOUS: - reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); - STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); - STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); - STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); - if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) - goto err; - break; - - default: - break; - } - - switch (state->config->ts2_mode) { - case STV090x_TSMODE_PARALLEL_PUNCTURED: - reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); - STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); - STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); - STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); - if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) - goto err; - break; - - case STV090x_TSMODE_DVBCI: - reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); - STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); - STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); - STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); - if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) - goto err; - break; - - case STV090x_TSMODE_SERIAL_PUNCTURED: - reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); - STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); - STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); - STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); - if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) - goto err; - break; - - case STV090x_TSMODE_SERIAL_CONTINUOUS: - reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); - STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); - STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); - STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); - if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) - goto err; - break; - - default: - break; - } - - if (state->config->ts1_clk > 0) { - u32 speed; - - switch (state->config->ts1_mode) { - case STV090x_TSMODE_PARALLEL_PUNCTURED: - case STV090x_TSMODE_DVBCI: - default: - speed = state->internal->mclk / - (state->config->ts1_clk / 4); - if (speed < 0x08) - speed = 0x08; - if (speed > 0xFF) - speed = 0xFF; - break; - case STV090x_TSMODE_SERIAL_PUNCTURED: - case STV090x_TSMODE_SERIAL_CONTINUOUS: - speed = state->internal->mclk / - (state->config->ts1_clk / 32); - if (speed < 0x20) - speed = 0x20; - if (speed > 0xFF) - speed = 0xFF; - break; - } - reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); - STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); - if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_P1_TSSPEED, speed) < 0) - goto err; - } - - if (state->config->ts2_clk > 0) { - u32 speed; - - switch (state->config->ts2_mode) { - case STV090x_TSMODE_PARALLEL_PUNCTURED: - case STV090x_TSMODE_DVBCI: - default: - speed = state->internal->mclk / - (state->config->ts2_clk / 4); - if (speed < 0x08) - speed = 0x08; - if (speed > 0xFF) - speed = 0xFF; - break; - case STV090x_TSMODE_SERIAL_PUNCTURED: - case STV090x_TSMODE_SERIAL_CONTINUOUS: - speed = state->internal->mclk / - (state->config->ts2_clk / 32); - if (speed < 0x20) - speed = 0x20; - if (speed > 0xFF) - speed = 0xFF; - break; - } - reg = stv090x_read_reg(state, STV090x_P2_TSCFGM); - STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); - if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_P2_TSSPEED, speed) < 0) - goto err; - } - - reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); - STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01); - if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) - goto err; - STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00); - if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) - goto err; - - reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); - STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01); - if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) - goto err; - STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00); - if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) - goto err; - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_init(struct dvb_frontend *fe) -{ - struct stv090x_state *state = fe->demodulator_priv; - const struct stv090x_config *config = state->config; - u32 reg; - - if (state->internal->mclk == 0) { - /* call tuner init to configure the tuner's clock output - divider directly before setting up the master clock of - the stv090x. */ - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (config->tuner_init) { - if (config->tuner_init(fe) < 0) - goto err_gateoff; - } - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */ - msleep(5); - if (stv090x_write_reg(state, STV090x_SYNTCTRL, - 0x20 | config->clk_mode) < 0) - goto err; - stv090x_get_mclk(state); - } - - if (stv090x_wakeup(fe) < 0) { - dprintk(FE_ERROR, 1, "Error waking device"); - goto err; - } - - if (stv090x_ldpc_mode(state, state->demod_mode) < 0) - goto err; - - reg = STV090x_READ_DEMOD(state, TNRCFG2); - STV090x_SETFIELD_Px(reg, TUN_IQSWAP_FIELD, state->inversion); - if (STV090x_WRITE_DEMOD(state, TNRCFG2, reg) < 0) - goto err; - reg = STV090x_READ_DEMOD(state, DEMOD); - STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff); - if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) - goto err; - - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - - if (config->tuner_set_mode) { - if (config->tuner_set_mode(fe, TUNER_WAKE) < 0) - goto err_gateoff; - } - - if (config->tuner_init) { - if (config->tuner_init(fe) < 0) - goto err_gateoff; - } - - if (stv090x_i2c_gate_ctrl(state, 0) < 0) - goto err; - - if (stv090x_set_tspath(state) < 0) - goto err; - - return 0; - -err_gateoff: - stv090x_i2c_gate_ctrl(state, 0); -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -static int stv090x_setup(struct dvb_frontend *fe) -{ - struct stv090x_state *state = fe->demodulator_priv; - const struct stv090x_config *config = state->config; - const struct stv090x_reg *stv090x_initval = NULL; - const struct stv090x_reg *stv090x_cut20_val = NULL; - unsigned long t1_size = 0, t2_size = 0; - u32 reg = 0; - - int i; - - if (state->device == STV0900) { - dprintk(FE_DEBUG, 1, "Initializing STV0900"); - stv090x_initval = stv0900_initval; - t1_size = ARRAY_SIZE(stv0900_initval); - stv090x_cut20_val = stv0900_cut20_val; - t2_size = ARRAY_SIZE(stv0900_cut20_val); - } else if (state->device == STV0903) { - dprintk(FE_DEBUG, 1, "Initializing STV0903"); - stv090x_initval = stv0903_initval; - t1_size = ARRAY_SIZE(stv0903_initval); - stv090x_cut20_val = stv0903_cut20_val; - t2_size = ARRAY_SIZE(stv0903_cut20_val); - } - - /* STV090x init */ - - /* Stop Demod */ - if (stv090x_write_reg(state, STV090x_P1_DMDISTATE, 0x5c) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0) - goto err; - - msleep(5); - - /* Set No Tuner Mode */ - if (stv090x_write_reg(state, STV090x_P1_TNRCFG, 0x6c) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0) - goto err; - - /* I2C repeater OFF */ - STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level); - if (stv090x_write_reg(state, STV090x_P1_I2CRPT, reg) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0) - goto err; - - if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */ - goto err; - msleep(5); - if (stv090x_write_reg(state, STV090x_I2CCFG, 0x08) < 0) /* 1/41 oversampling */ - goto err; - if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0) /* enable PLL */ - goto err; - msleep(5); - - /* write initval */ - dprintk(FE_DEBUG, 1, "Setting up initial values"); - for (i = 0; i < t1_size; i++) { - if (stv090x_write_reg(state, stv090x_initval[i].addr, stv090x_initval[i].data) < 0) - goto err; - } - - state->internal->dev_ver = stv090x_read_reg(state, STV090x_MID); - if (state->internal->dev_ver >= 0x20) { - if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0) - goto err; - - /* write cut20_val*/ - dprintk(FE_DEBUG, 1, "Setting up Cut 2.0 initial values"); - for (i = 0; i < t2_size; i++) { - if (stv090x_write_reg(state, stv090x_cut20_val[i].addr, stv090x_cut20_val[i].data) < 0) - goto err; - } - - } else if (state->internal->dev_ver < 0x20) { - dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!", - state->internal->dev_ver); - - goto err; - } else if (state->internal->dev_ver > 0x30) { - /* we shouldn't bail out from here */ - dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!", - state->internal->dev_ver); - } - - /* ADC1 range */ - reg = stv090x_read_reg(state, STV090x_TSTTNR1); - STV090x_SETFIELD(reg, ADC1_INMODE_FIELD, - (config->adc1_range == STV090x_ADC_1Vpp) ? 0 : 1); - if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) - goto err; - - /* ADC2 range */ - reg = stv090x_read_reg(state, STV090x_TSTTNR3); - STV090x_SETFIELD(reg, ADC2_INMODE_FIELD, - (config->adc2_range == STV090x_ADC_1Vpp) ? 0 : 1); - if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0) - goto err; - - if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0) - goto err; - if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0) - goto err; - - return 0; -err: - dprintk(FE_ERROR, 1, "I/O error"); - return -1; -} - -int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, - u8 xor_value) -{ - struct stv090x_state *state = fe->demodulator_priv; - u8 reg = 0; - - STV090x_SETFIELD(reg, GPIOx_OPD_FIELD, dir); - STV090x_SETFIELD(reg, GPIOx_CONFIG_FIELD, value); - STV090x_SETFIELD(reg, GPIOx_XOR_FIELD, xor_value); - - return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg); -} -EXPORT_SYMBOL(stv090x_set_gpio); - -static struct dvb_frontend_ops stv090x_ops = { - - .info = { - .name = "STV090x Multistandard", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 0, - .frequency_tolerance = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | - FE_CAN_2G_MODULATION - }, - - .release = stv090x_release, - .init = stv090x_init, - - .sleep = stv090x_sleep, - .get_frontend_algo = stv090x_frontend_algo, - - .diseqc_send_master_cmd = stv090x_send_diseqc_msg, - .diseqc_send_burst = stv090x_send_diseqc_burst, - .diseqc_recv_slave_reply = stv090x_recv_slave_reply, - .set_tone = stv090x_set_tone, - - .search = stv090x_search, - .read_status = stv090x_read_status, - .read_ber = stv090x_read_per, - .read_signal_strength = stv090x_read_signal_strength, - .read_snr = stv090x_read_cnr -}; - - -struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, - struct i2c_adapter *i2c, - enum stv090x_demodulator demod) -{ - struct stv090x_state *state = NULL; - struct stv090x_dev *temp_int; - - state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL); - if (state == NULL) - goto error; - - state->verbose = &verbose; - state->config = config; - state->i2c = i2c; - state->frontend.ops = stv090x_ops; - state->frontend.demodulator_priv = state; - state->demod = demod; - state->demod_mode = config->demod_mode; /* Single or Dual mode */ - state->device = config->device; - state->rolloff = STV090x_RO_35; /* default */ - - temp_int = find_dev(state->i2c, - state->config->address); - - if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) { - state->internal = temp_int->internal; - state->internal->num_used++; - dprintk(FE_INFO, 1, "Found Internal Structure!"); - } else { - state->internal = kmalloc(sizeof(struct stv090x_internal), - GFP_KERNEL); - if (!state->internal) - goto error; - temp_int = append_internal(state->internal); - if (!temp_int) { - kfree(state->internal); - goto error; - } - state->internal->num_used = 1; - state->internal->mclk = 0; - state->internal->dev_ver = 0; - state->internal->i2c_adap = state->i2c; - state->internal->i2c_addr = state->config->address; - dprintk(FE_INFO, 1, "Create New Internal Structure!"); - - mutex_init(&state->internal->demod_lock); - mutex_init(&state->internal->tuner_lock); - - if (stv090x_setup(&state->frontend) < 0) { - dprintk(FE_ERROR, 1, "Error setting up device"); - goto err_remove; - } - } - - /* workaround for stuck DiSEqC output */ - if (config->diseqc_envelope_mode) - stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A); - - dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x", - state->device == STV0900 ? "STV0900" : "STV0903", - demod, - state->internal->dev_ver); - - return &state->frontend; - -err_remove: - remove_dev(state->internal); - kfree(state->internal); -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(stv090x_attach); -MODULE_PARM_DESC(verbose, "Set Verbosity level"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -/* - STV0900/0903 Multistandard Broadcast Frontend driver - Copyright (C) Manu Abraham - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STV090x_H -#define __STV090x_H - -enum stv090x_demodulator { - STV090x_DEMODULATOR_0 = 1, - STV090x_DEMODULATOR_1 -}; - -enum stv090x_device { - STV0903 = 0, - STV0900, -}; - -enum stv090x_mode { - STV090x_DUAL = 0, - STV090x_SINGLE -}; - -enum stv090x_tsmode { - STV090x_TSMODE_SERIAL_PUNCTURED = 1, - STV090x_TSMODE_SERIAL_CONTINUOUS, - STV090x_TSMODE_PARALLEL_PUNCTURED, - STV090x_TSMODE_DVBCI -}; - -enum stv090x_clkmode { - STV090x_CLK_INT = 0, /* Clk i/p = CLKI */ - STV090x_CLK_EXT = 2 /* Clk i/p = XTALI */ -}; - -enum stv090x_i2crpt { - STV090x_RPTLEVEL_256 = 0, - STV090x_RPTLEVEL_128 = 1, - STV090x_RPTLEVEL_64 = 2, - STV090x_RPTLEVEL_32 = 3, - STV090x_RPTLEVEL_16 = 4, - STV090x_RPTLEVEL_8 = 5, - STV090x_RPTLEVEL_4 = 6, - STV090x_RPTLEVEL_2 = 7, -}; - -enum stv090x_adc_range { - STV090x_ADC_2Vpp = 0, - STV090x_ADC_1Vpp = 1 -}; - -struct stv090x_config { - enum stv090x_device device; - enum stv090x_mode demod_mode; - enum stv090x_clkmode clk_mode; - - u32 xtal; /* default: 8000000 */ - u8 address; /* default: 0x68 */ - - u8 ts1_mode; - u8 ts2_mode; - u32 ts1_clk; - u32 ts2_clk; - - u8 ts1_tei : 1; - u8 ts2_tei : 1; - - enum stv090x_i2crpt repeater_level; - - u8 tuner_bbgain; /* default: 10db */ - enum stv090x_adc_range adc1_range; /* default: 2Vpp */ - enum stv090x_adc_range adc2_range; /* default: 2Vpp */ - - bool diseqc_envelope_mode; - - int (*tuner_init) (struct dvb_frontend *fe); - int (*tuner_sleep) (struct dvb_frontend *fe); - int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); - int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); - int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency); - int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth); - int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth); - int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain); - int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain); - int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk); - int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status); - void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock); -}; - -#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE)) - -extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, - struct i2c_adapter *i2c, - enum stv090x_demodulator demod); - -/* dir = 0 -> output, dir = 1 -> input/open-drain */ -extern int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, - u8 dir, u8 value, u8 xor_value); - -#else - -static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, - struct i2c_adapter *i2c, - enum stv090x_demodulator demod) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, - u8 opd, u8 value, u8 xor_value) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} -#endif /* CONFIG_DVB_STV090x */ - -#endif /* __STV090x_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,279 +0,0 @@ -/* - STV0900/0903 Multistandard Broadcast Frontend driver - Copyright (C) Manu Abraham - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STV090x_PRIV_H -#define __STV090x_PRIV_H - -#include "dvb_frontend.h" - -#define FE_ERROR 0 -#define FE_NOTICE 1 -#define FE_INFO 2 -#define FE_DEBUG 3 -#define FE_DEBUGREG 4 - -#define dprintk(__y, __z, format, arg...) do { \ - if (__z) { \ - if ((verbose > FE_ERROR) && (verbose > __y)) \ - printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ - else if ((verbose > FE_NOTICE) && (verbose > __y)) \ - printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ - else if ((verbose > FE_INFO) && (verbose > __y)) \ - printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ - else if ((verbose > FE_DEBUG) && (verbose > __y)) \ - printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ - } else { \ - if (verbose > __y) \ - printk(format, ##arg); \ - } \ -} while (0) - -#define STV090x_READ_DEMOD(__state, __reg) (( \ - (__state)->demod == STV090x_DEMODULATOR_1) ? \ - stv090x_read_reg(__state, STV090x_P2_##__reg) : \ - stv090x_read_reg(__state, STV090x_P1_##__reg)) - -#define STV090x_WRITE_DEMOD(__state, __reg, __data) (( \ - (__state)->demod == STV090x_DEMODULATOR_1) ? \ - stv090x_write_reg(__state, STV090x_P2_##__reg, __data) :\ - stv090x_write_reg(__state, STV090x_P1_##__reg, __data)) - -#define STV090x_ADDR_OFFST(__state, __x) (( \ - (__state->demod) == STV090x_DEMODULATOR_1) ? \ - STV090x_P1_##__x : \ - STV090x_P2_##__x) - - -#define STV090x_SETFIELD(mask, bitf, val) (mask = (mask & (~(((1 << STV090x_WIDTH_##bitf) - 1) <<\ - STV090x_OFFST_##bitf))) | \ - (val << STV090x_OFFST_##bitf)) - -#define STV090x_GETFIELD(val, bitf) ((val >> STV090x_OFFST_##bitf) & ((1 << STV090x_WIDTH_##bitf) - 1)) - - -#define STV090x_SETFIELD_Px(mask, bitf, val) (mask = (mask & (~(((1 << STV090x_WIDTH_Px_##bitf) - 1) <<\ - STV090x_OFFST_Px_##bitf))) | \ - (val << STV090x_OFFST_Px_##bitf)) - -#define STV090x_GETFIELD_Px(val, bitf) ((val >> STV090x_OFFST_Px_##bitf) & ((1 << STV090x_WIDTH_Px_##bitf) - 1)) - -#define MAKEWORD16(__a, __b) (((__a) << 8) | (__b)) - -#define MSB(__x) ((__x >> 8) & 0xff) -#define LSB(__x) (__x & 0xff) - - -#define STV090x_IQPOWER_THRESHOLD 30 -#define STV090x_SEARCH_AGC2_TH_CUT20 700 -#define STV090x_SEARCH_AGC2_TH_CUT30 1400 - -#define STV090x_SEARCH_AGC2_TH(__ver) \ - ((__ver <= 0x20) ? \ - STV090x_SEARCH_AGC2_TH_CUT20 : \ - STV090x_SEARCH_AGC2_TH_CUT30) - -enum stv090x_signal_state { - STV090x_NOAGC1, - STV090x_NOCARRIER, - STV090x_NODATA, - STV090x_DATAOK, - STV090x_RANGEOK, - STV090x_OUTOFRANGE -}; - -enum stv090x_fec { - STV090x_PR12 = 0, - STV090x_PR23, - STV090x_PR34, - STV090x_PR45, - STV090x_PR56, - STV090x_PR67, - STV090x_PR78, - STV090x_PR89, - STV090x_PR910, - STV090x_PRERR -}; - -enum stv090x_modulation { - STV090x_QPSK, - STV090x_8PSK, - STV090x_16APSK, - STV090x_32APSK, - STV090x_UNKNOWN -}; - -enum stv090x_frame { - STV090x_LONG_FRAME, - STV090x_SHORT_FRAME -}; - -enum stv090x_pilot { - STV090x_PILOTS_OFF, - STV090x_PILOTS_ON -}; - -enum stv090x_rolloff { - STV090x_RO_35, - STV090x_RO_25, - STV090x_RO_20 -}; - -enum stv090x_inversion { - STV090x_IQ_AUTO, - STV090x_IQ_NORMAL, - STV090x_IQ_SWAP -}; - -enum stv090x_modcod { - STV090x_DUMMY_PLF = 0, - STV090x_QPSK_14, - STV090x_QPSK_13, - STV090x_QPSK_25, - STV090x_QPSK_12, - STV090x_QPSK_35, - STV090x_QPSK_23, - STV090x_QPSK_34, - STV090x_QPSK_45, - STV090x_QPSK_56, - STV090x_QPSK_89, - STV090x_QPSK_910, - STV090x_8PSK_35, - STV090x_8PSK_23, - STV090x_8PSK_34, - STV090x_8PSK_56, - STV090x_8PSK_89, - STV090x_8PSK_910, - STV090x_16APSK_23, - STV090x_16APSK_34, - STV090x_16APSK_45, - STV090x_16APSK_56, - STV090x_16APSK_89, - STV090x_16APSK_910, - STV090x_32APSK_34, - STV090x_32APSK_45, - STV090x_32APSK_56, - STV090x_32APSK_89, - STV090x_32APSK_910, - STV090x_MODCODE_UNKNOWN -}; - -enum stv090x_search { - STV090x_SEARCH_DSS = 0, - STV090x_SEARCH_DVBS1, - STV090x_SEARCH_DVBS2, - STV090x_SEARCH_AUTO -}; - -enum stv090x_algo { - STV090x_BLIND_SEARCH, - STV090x_COLD_SEARCH, - STV090x_WARM_SEARCH -}; - -enum stv090x_delsys { - STV090x_ERROR = 0, - STV090x_DVBS1 = 1, - STV090x_DVBS2, - STV090x_DSS -}; - -struct stv090x_long_frame_crloop { - enum stv090x_modcod modcod; - - u8 crl_pilots_on_2; - u8 crl_pilots_off_2; - u8 crl_pilots_on_5; - u8 crl_pilots_off_5; - u8 crl_pilots_on_10; - u8 crl_pilots_off_10; - u8 crl_pilots_on_20; - u8 crl_pilots_off_20; - u8 crl_pilots_on_30; - u8 crl_pilots_off_30; -}; - -struct stv090x_short_frame_crloop { - enum stv090x_modulation modulation; - - u8 crl_2; /* SR < 3M */ - u8 crl_5; /* 3 < SR <= 7M */ - u8 crl_10; /* 7 < SR <= 15M */ - u8 crl_20; /* 10 < SR <= 25M */ - u8 crl_30; /* 10 < SR <= 45M */ -}; - -struct stv090x_reg { - u16 addr; - u8 data; -}; - -struct stv090x_tab { - s32 real; - s32 read; -}; - -struct stv090x_internal { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; - - struct mutex demod_lock; /* Lock access to shared register */ - struct mutex tuner_lock; /* Lock access to tuners */ - s32 mclk; /* Masterclock Divider factor */ - u32 dev_ver; - - int num_used; -}; - -struct stv090x_state { - enum stv090x_device device; - enum stv090x_demodulator demod; - enum stv090x_mode demod_mode; - struct stv090x_internal *internal; - - struct i2c_adapter *i2c; - const struct stv090x_config *config; - struct dvb_frontend frontend; - - u32 *verbose; /* Cached module verbosity */ - - enum stv090x_delsys delsys; - enum stv090x_fec fec; - enum stv090x_modulation modulation; - enum stv090x_modcod modcod; - enum stv090x_search search_mode; - enum stv090x_frame frame_len; - enum stv090x_pilot pilots; - enum stv090x_rolloff rolloff; - enum stv090x_inversion inversion; - enum stv090x_algo algo; - - u32 frequency; - u32 srate; - - s32 tuner_bw; - - s32 search_range; - - s32 DemodTimeout; - s32 FecTimeout; -}; - -#endif /* __STV090x_PRIV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x_reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv090x_reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,2371 +0,0 @@ -/* - STV0900/0903 Multistandard Broadcast Frontend driver - Copyright (C) Manu Abraham - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STV090x_REG_H -#define __STV090x_REG_H - -#define STV090x_MID 0xf100 -#define STV090x_OFFST_MCHIP_IDENT_FIELD 4 -#define STV090x_WIDTH_MCHIP_IDENT_FIELD 4 -#define STV090x_OFFST_MRELEASE_FIELD 0 -#define STV090x_WIDTH_MRELEASE_FIELD 4 - -#define STV090x_DACR1 0xf113 -#define STV090x_OFFST_DACR1_MODE_FIELD 5 -#define STV090x_WIDTH_DACR1_MODE_FIELD 3 -#define STV090x_OFFST_DACR1_VALUE_FIELD 0 -#define STV090x_WIDTH_DACR1_VALUE_FIELD 4 - -#define STV090x_DACR2 0xf114 -#define STV090x_OFFST_DACR2_VALUE_FIELD 0 -#define STV090x_WIDTH_DACR2_VALUE_FIELD 8 - -#define STV090x_OUTCFG 0xf11c -#define STV090x_OFFST_OUTSERRS1_HZ_FIELD 6 -#define STV090x_WIDTH_OUTSERRS1_HZ_FIELD 1 -#define STV090x_OFFST_OUTSERRS2_HZ_FIELD 5 -#define STV090x_WIDTH_OUTSERRS2_HZ_FIELD 1 -#define STV090x_OFFST_OUTSERRS3_HZ_FIELD 4 -#define STV090x_WIDTH_OUTSERRS3_HZ_FIELD 1 -#define STV090x_OFFST_OUTPARRS3_HZ_FIELD 3 -#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD 1 - -#define STV090x_MODECFG 0xf11d - -#define STV090x_IRQSTATUS3 0xf120 -#define STV090x_OFFST_SPLL_LOCK_FIELD 5 -#define STV090x_WIDTH_SPLL_LOCK_FIELD 1 -#define STV090x_OFFST_SSTREAM_LCK_3_FIELD 4 -#define STV090x_WIDTH_SSTREAM_LCK_3_FIELD 1 -#define STV090x_OFFST_SSTREAM_LCK_2_FIELD 3 -#define STV090x_WIDTH_SSTREAM_LCK_2_FIELD 1 -#define STV090x_OFFST_SSTREAM_LCK_1_FIELD 2 -#define STV090x_WIDTH_SSTREAM_LCK_1_FIELD 1 -#define STV090x_OFFST_SDVBS1_PRF_2_FIELD 1 -#define STV090x_WIDTH_SDVBS1_PRF_2_FIELD 1 -#define STV090x_OFFST_SDVBS1_PRF_1_FIELD 0 -#define STV090x_WIDTH_SDVBS1_PRF_1_FIELD 1 - -#define STV090x_IRQSTATUS2 0xf121 -#define STV090x_OFFST_SSPY_ENDSIM_3_FIELD 7 -#define STV090x_WIDTH_SSPY_ENDSIM_3_FIELD 1 -#define STV090x_OFFST_SSPY_ENDSIM_2_FIELD 6 -#define STV090x_WIDTH_SSPY_ENDSIM_2_FIELD 1 -#define STV090x_OFFST_SSPY_ENDSIM_1_FIELD 5 -#define STV090x_WIDTH_SSPY_ENDSIM_1_FIELD 1 -#define STV090x_OFFST_SPKTDEL_ERROR_2_FIELD 4 -#define STV090x_WIDTH_SPKTDEL_ERROR_2_FIELD 1 -#define STV090x_OFFST_SPKTDEL_LOCKB_2_FIELD 3 -#define STV090x_WIDTH_SPKTDEL_LOCKB_2_FIELD 1 -#define STV090x_OFFST_SPKTDEL_LOCK_2_FIELD 2 -#define STV090x_WIDTH_SPKTDEL_LOCK_2_FIELD 1 -#define STV090x_OFFST_SPKTDEL_ERROR_1_FIELD 1 -#define STV090x_WIDTH_SPKTDEL_ERROR_1_FIELD 1 -#define STV090x_OFFST_SPKTDEL_LOCKB_1_FIELD 0 -#define STV090x_WIDTH_SPKTDEL_LOCKB_1_FIELD 1 - -#define STV090x_IRQSTATUS1 0xf122 -#define STV090x_OFFST_SPKTDEL_LOCK_1_FIELD 7 -#define STV090x_WIDTH_SPKTDEL_LOCK_1_FIELD 1 -#define STV090x_OFFST_SDEMOD_LOCKB_2_FIELD 2 -#define STV090x_WIDTH_SDEMOD_LOCKB_2_FIELD 1 -#define STV090x_OFFST_SDEMOD_LOCK_2_FIELD 1 -#define STV090x_WIDTH_SDEMOD_LOCK_2_FIELD 1 -#define STV090x_OFFST_SDEMOD_IRQ_2_FIELD 0 -#define STV090x_WIDTH_SDEMOD_IRQ_2_FIELD 1 - -#define STV090x_IRQSTATUS0 0xf123 -#define STV090x_OFFST_SDEMOD_LOCKB_1_FIELD 7 -#define STV090x_WIDTH_SDEMOD_LOCKB_1_FIELD 1 -#define STV090x_OFFST_SDEMOD_LOCK_1_FIELD 6 -#define STV090x_WIDTH_SDEMOD_LOCK_1_FIELD 1 -#define STV090x_OFFST_SDEMOD_IRQ_1_FIELD 5 -#define STV090x_WIDTH_SDEMOD_IRQ_1_FIELD 1 -#define STV090x_OFFST_SBCH_ERRFLAG_FIELD 4 -#define STV090x_WIDTH_SBCH_ERRFLAG_FIELD 1 -#define STV090x_OFFST_SDISEQC2RX_IRQ_FIELD 3 -#define STV090x_WIDTH_SDISEQC2RX_IRQ_FIELD 1 -#define STV090x_OFFST_SDISEQC2TX_IRQ_FIELD 2 -#define STV090x_WIDTH_SDISEQC2TX_IRQ_FIELD 1 -#define STV090x_OFFST_SDISEQC1RX_IRQ_FIELD 1 -#define STV090x_WIDTH_SDISEQC1RX_IRQ_FIELD 1 -#define STV090x_OFFST_SDISEQC1TX_IRQ_FIELD 0 -#define STV090x_WIDTH_SDISEQC1TX_IRQ_FIELD 1 - -#define STV090x_IRQMASK3 0xf124 -#define STV090x_OFFST_MPLL_LOCK_FIELD 5 -#define STV090x_WIDTH_MPLL_LOCK_FIELD 1 -#define STV090x_OFFST_MSTREAM_LCK_3_FIELD 4 -#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD 1 -#define STV090x_OFFST_MSTREAM_LCK_2_FIELD 3 -#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD 1 -#define STV090x_OFFST_MSTREAM_LCK_1_FIELD 2 -#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD 1 -#define STV090x_OFFST_MDVBS1_PRF_2_FIELD 1 -#define STV090x_WIDTH_MDVBS1_PRF_2_FIELD 1 -#define STV090x_OFFST_MDVBS1_PRF_1_FIELD 0 -#define STV090x_WIDTH_MDVBS1_PRF_1_FIELD 1 - -#define STV090x_IRQMASK2 0xf125 -#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD 7 -#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD 1 -#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD 6 -#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD 1 -#define STV090x_OFFST_MSPY_ENDSIM_1_FIELD 5 -#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD 1 -#define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD 4 -#define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD 1 -#define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD 3 -#define STV090x_WIDTH_MPKTDEL_LOCKB_2_FIELD 1 -#define STV090x_OFFST_MPKTDEL_LOCK_2_FIELD 2 -#define STV090x_WIDTH_MPKTDEL_LOCK_2_FIELD 1 -#define STV090x_OFFST_MPKTDEL_ERROR_1_FIELD 1 -#define STV090x_WIDTH_MPKTDEL_ERROR_1_FIELD 1 -#define STV090x_OFFST_MPKTDEL_LOCKB_1_FIELD 0 -#define STV090x_WIDTH_MPKTDEL_LOCKB_1_FIELD 1 - -#define STV090x_IRQMASK1 0xf126 -#define STV090x_OFFST_MPKTDEL_LOCK_1_FIELD 7 -#define STV090x_WIDTH_MPKTDEL_LOCK_1_FIELD 1 -#define STV090x_OFFST_MEXTPINB2_FIELD 6 -#define STV090x_WIDTH_MEXTPINB2_FIELD 1 -#define STV090x_OFFST_MEXTPIN2_FIELD 5 -#define STV090x_WIDTH_MEXTPIN2_FIELD 1 -#define STV090x_OFFST_MEXTPINB1_FIELD 4 -#define STV090x_WIDTH_MEXTPINB1_FIELD 1 -#define STV090x_OFFST_MEXTPIN1_FIELD 3 -#define STV090x_WIDTH_MEXTPIN1_FIELD 1 -#define STV090x_OFFST_MDEMOD_LOCKB_2_FIELD 2 -#define STV090x_WIDTH_MDEMOD_LOCKB_2_FIELD 1 -#define STV090x_OFFST_MDEMOD_LOCK_2_FIELD 1 -#define STV090x_WIDTH_MDEMOD_LOCK_2_FIELD 1 -#define STV090x_OFFST_MDEMOD_IRQ_2_FIELD 0 -#define STV090x_WIDTH_MDEMOD_IRQ_2_FIELD 1 - -#define STV090x_IRQMASK0 0xf127 -#define STV090x_OFFST_MDEMOD_LOCKB_1_FIELD 7 -#define STV090x_WIDTH_MDEMOD_LOCKB_1_FIELD 1 -#define STV090x_OFFST_MDEMOD_LOCK_1_FIELD 6 -#define STV090x_WIDTH_MDEMOD_LOCK_1_FIELD 1 -#define STV090x_OFFST_MDEMOD_IRQ_1_FIELD 5 -#define STV090x_WIDTH_MDEMOD_IRQ_1_FIELD 1 -#define STV090x_OFFST_MBCH_ERRFLAG_FIELD 4 -#define STV090x_WIDTH_MBCH_ERRFLAG_FIELD 1 -#define STV090x_OFFST_MDISEQC2RX_IRQ_FIELD 3 -#define STV090x_WIDTH_MDISEQC2RX_IRQ_FIELD 1 -#define STV090x_OFFST_MDISEQC2TX_IRQ_FIELD 2 -#define STV090x_WIDTH_MDISEQC2TX_IRQ_FIELD 1 -#define STV090x_OFFST_MDISEQC1RX_IRQ_FIELD 1 -#define STV090x_WIDTH_MDISEQC1RX_IRQ_FIELD 1 -#define STV090x_OFFST_MDISEQC1TX_IRQ_FIELD 0 -#define STV090x_WIDTH_MDISEQC1TX_IRQ_FIELD 1 - -#define STV090x_I2CCFG 0xf129 -#define STV090x_OFFST_12C_FASTMODE_FIELD 3 -#define STV090x_WIDTH_12C_FASTMODE_FIELD 1 -#define STV090x_OFFST_12CADDR_INC_FIELD 0 -#define STV090x_WIDTH_12CADDR_INC_FIELD 2 - -#define STV090x_Px_I2CRPT(__x) (0xf12a + (__x - 1) * 0x1) -#define STV090x_P1_I2CRPT STV090x_Px_I2CRPT(1) -#define STV090x_P2_I2CRPT STV090x_Px_I2CRPT(2) -#define STV090x_OFFST_Px_I2CT_ON_FIELD 7 -#define STV090x_WIDTH_Px_I2CT_ON_FIELD 1 -#define STV090x_OFFST_Px_ENARPT_LEVEL_FIELD 4 -#define STV090x_WIDTH_Px_ENARPT_LEVEL_FIELD 3 -#define STV090x_OFFST_Px_SCLT_DELAY_FIELD 3 -#define STV090x_WIDTH_Px_SCLT_DELAY_FIELD 1 -#define STV090x_OFFST_Px_STOP_ENABLE_FIELD 2 -#define STV090x_WIDTH_Px_STOP_ENABLE_FIELD 1 -#define STV090x_OFFST_Px_STOP_SDAT2SDA_FIELD 1 -#define STV090x_WIDTH_Px_STOP_SDAT2SDA_FIELD 1 - -#define STV090x_CLKI2CFG 0xf140 -#define STV090x_OFFST_CLKI2_OPD_FIELD 7 -#define STV090x_WIDTH_CLKI2_OPD_FIELD 1 -#define STV090x_OFFST_CLKI2_CONFIG_FIELD 1 -#define STV090x_WIDTH_CLKI2_CONFIG_FIELD 6 -#define STV090x_OFFST_CLKI2_XOR_FIELD 0 -#define STV090x_WIDTH_CLKI2_XOR_FIELD 1 - -#define STV090x_GPIOxCFG(__x) (0xf141 + (__x - 1)) -#define STV090x_GPIO1CFG STV090x_GPIOxCFG(1) -#define STV090x_GPIO2CFG STV090x_GPIOxCFG(2) -#define STV090x_GPIO3CFG STV090x_GPIOxCFG(3) -#define STV090x_GPIO4CFG STV090x_GPIOxCFG(4) -#define STV090x_GPIO5CFG STV090x_GPIOxCFG(5) -#define STV090x_GPIO6CFG STV090x_GPIOxCFG(6) -#define STV090x_GPIO7CFG STV090x_GPIOxCFG(7) -#define STV090x_GPIO8CFG STV090x_GPIOxCFG(8) -#define STV090x_GPIO9CFG STV090x_GPIOxCFG(9) -#define STV090x_GPIO10CFG STV090x_GPIOxCFG(10) -#define STV090x_GPIO11CFG STV090x_GPIOxCFG(11) -#define STV090x_GPIO12CFG STV090x_GPIOxCFG(12) -#define STV090x_GPIO13CFG STV090x_GPIOxCFG(13) -#define STV090x_OFFST_GPIOx_OPD_FIELD 7 -#define STV090x_WIDTH_GPIOx_OPD_FIELD 1 -#define STV090x_OFFST_GPIOx_CONFIG_FIELD 1 -#define STV090x_WIDTH_GPIOx_CONFIG_FIELD 6 -#define STV090x_OFFST_GPIOx_XOR_FIELD 0 -#define STV090x_WIDTH_GPIOx_XOR_FIELD 1 - -#define STV090x_CSxCFG(__x) (0xf14e + __x * 0x1) -#define STV090x_CS0CFG STV090x_CSxCFG(0) -#define STV090x_CS1CFG STV090x_CSxCFG(1) -#define STV090x_OFFST_CSX_OPD_FIELD 7 -#define STV090x_WIDTH_CSX_OPD_FIELD 1 -#define STV090x_OFFST_CSX_CONFIG_FIELD 1 -#define STV090x_WIDTH_CSX_CONFIG_FIELD 6 -#define STV090x_OFFST_CSX_XOR_FIELD 0 -#define STV090x_WIDTH_CSX_XOR_FIELD 1 - - -#define STV090x_STDBYCFG 0xf150 -#define STV090x_OFFST_STDBY_OPD_FIELD 7 -#define STV090x_WIDTH_STDBY_OPD_FIELD 1 -#define STV090x_OFFST_STDBY_CONFIG_FIELD 1 -#define STV090x_WIDTH_STDBY_CONFIG_FIELD 6 -#define STV090x_OFFST_STDBY_XOR_FIELD 0 -#define STV090x_WIDTH_STDBY_XOR_FIELD 1 - -#define STV090x_DIRCLKCFG 0xf151 -#define STV090x_OFFST_DIRCLK_OPD_FIELD 7 -#define STV090x_WIDTH_DIRCLK_OPD_FIELD 1 -#define STV090x_OFFST_DIRCLK_CONFIG_FIELD 1 -#define STV090x_WIDTH_DIRCLK_CONFIG_FIELD 6 -#define STV090x_OFFST_DIRCLK_XOR_FIELD 0 -#define STV090x_WIDTH_DIRCLK_XOR_FIELD 1 - - -#define STV090x_AGCRFxCFG(__x) (0xf152 + (__x - 1) * 0x4) -#define STV090x_AGCRF1CFG STV090x_AGCRFxCFG(1) -#define STV090x_AGCRF2CFG STV090x_AGCRFxCFG(2) -#define STV090x_OFFST_AGCRFx_OPD_FIELD 7 -#define STV090x_WIDTH_AGCRFx_OPD_FIELD 1 -#define STV090x_OFFST_AGCRFx_CONFIG_FIELD 1 -#define STV090x_WIDTH_AGCRFx_CONFIG_FIELD 6 -#define STV090x_OFFST_AGCRFx_XOR_FIELD 0 -#define STV090x_WIDTH_AGCRFx_XOR_FIELD 1 - -#define STV090x_SDATxCFG(__x) (0xf153 + (__x - 1) * 0x4) -#define STV090x_SDAT1CFG STV090x_SDATxCFG(1) -#define STV090x_SDAT2CFG STV090x_SDATxCFG(2) -#define STV090x_OFFST_SDATx_OPD_FIELD 7 -#define STV090x_WIDTH_SDATx_OPD_FIELD 1 -#define STV090x_OFFST_SDATx_CONFIG_FIELD 1 -#define STV090x_WIDTH_SDATx_CONFIG_FIELD 6 -#define STV090x_OFFST_SDATx_XOR_FIELD 0 -#define STV090x_WIDTH_SDATx_XOR_FIELD 1 - -#define STV090x_SCLTxCFG(__x) (0xf154 + (__x - 1) * 0x4) -#define STV090x_SCLT1CFG STV090x_SCLTxCFG(1) -#define STV090x_SCLT2CFG STV090x_SCLTxCFG(2) -#define STV090x_OFFST_SCLTx_OPD_FIELD 7 -#define STV090x_WIDTH_SCLTx_OPD_FIELD 1 -#define STV090x_OFFST_SCLTx_CONFIG_FIELD 1 -#define STV090x_WIDTH_SCLTx_CONFIG_FIELD 6 -#define STV090x_OFFST_SCLTx_XOR_FIELD 0 -#define STV090x_WIDTH_SCLTx_XOR_FIELD 1 - -#define STV090x_DISEQCOxCFG(__x) (0xf155 + (__x - 1) * 0x4) -#define STV090x_DISEQCO1CFG STV090x_DISEQCOxCFG(1) -#define STV090x_DISEQCO2CFG STV090x_DISEQCOxCFG(2) -#define STV090x_OFFST_DISEQCOx_OPD_FIELD 7 -#define STV090x_WIDTH_DISEQCOx_OPD_FIELD 1 -#define STV090x_OFFST_DISEQCOx_CONFIG_FIELD 1 -#define STV090x_WIDTH_DISEQCOx_CONFIG_FIELD 6 -#define STV090x_OFFST_DISEQCOx_XOR_FIELD 0 -#define STV090x_WIDTH_DISEQCOx_XOR_FIELD 1 - -#define STV090x_CLKOUT27CFG 0xf15a -#define STV090x_OFFST_CLKOUT27_OPD_FIELD 7 -#define STV090x_WIDTH_CLKOUT27_OPD_FIELD 1 -#define STV090x_OFFST_CLKOUT27_CONFIG_FIELD 1 -#define STV090x_WIDTH_CLKOUT27_CONFIG_FIELD 6 -#define STV090x_OFFST_CLKOUT27_XOR_FIELD 0 -#define STV090x_WIDTH_CLKOUT27_XOR_FIELD 1 - -#define STV090x_ERRORxCFG(__x) (0xf15b + (__x - 1) * 0x5) -#define STV090x_ERROR1CFG STV090x_ERRORxCFG(1) -#define STV090x_ERROR2CFG STV090x_ERRORxCFG(2) -#define STV090x_ERROR3CFG STV090x_ERRORxCFG(3) -#define STV090x_OFFST_ERRORx_OPD_FIELD 7 -#define STV090x_WIDTH_ERRORx_OPD_FIELD 1 -#define STV090x_OFFST_ERRORx_CONFIG_FIELD 1 -#define STV090x_WIDTH_ERRORx_CONFIG_FIELD 6 -#define STV090x_OFFST_ERRORx_XOR_FIELD 0 -#define STV090x_WIDTH_ERRORx_XOR_FIELD 1 - -#define STV090x_DPNxCFG(__x) (0xf15c + (__x - 1) * 0x5) -#define STV090x_DPN1CFG STV090x_DPNxCFG(1) -#define STV090x_DPN2CFG STV090x_DPNxCFG(2) -#define STV090x_DPN3CFG STV090x_DPNxCFG(3) -#define STV090x_OFFST_DPNx_OPD_FIELD 7 -#define STV090x_WIDTH_DPNx_OPD_FIELD 1 -#define STV090x_OFFST_DPNx_CONFIG_FIELD 1 -#define STV090x_WIDTH_DPNx_CONFIG_FIELD 6 -#define STV090x_OFFST_DPNx_XOR_FIELD 0 -#define STV090x_WIDTH_DPNx_XOR_FIELD 1 - -#define STV090x_STROUTxCFG(__x) (0xf15d + (__x - 1) * 0x5) -#define STV090x_STROUT1CFG STV090x_STROUTxCFG(1) -#define STV090x_STROUT2CFG STV090x_STROUTxCFG(2) -#define STV090x_STROUT3CFG STV090x_STROUTxCFG(3) -#define STV090x_OFFST_STROUTx_OPD_FIELD 7 -#define STV090x_WIDTH_STROUTx_OPD_FIELD 1 -#define STV090x_OFFST_STROUTx_CONFIG_FIELD 1 -#define STV090x_WIDTH_STROUTx_CONFIG_FIELD 6 -#define STV090x_OFFST_STROUTx_XOR_FIELD 0 -#define STV090x_WIDTH_STROUTx_XOR_FIELD 1 - -#define STV090x_CLKOUTxCFG(__x) (0xf15e + (__x - 1) * 0x5) -#define STV090x_CLKOUT1CFG STV090x_CLKOUTxCFG(1) -#define STV090x_CLKOUT2CFG STV090x_CLKOUTxCFG(2) -#define STV090x_CLKOUT3CFG STV090x_CLKOUTxCFG(3) -#define STV090x_OFFST_CLKOUTx_OPD_FIELD 7 -#define STV090x_WIDTH_CLKOUTx_OPD_FIELD 1 -#define STV090x_OFFST_CLKOUTx_CONFIG_FIELD 1 -#define STV090x_WIDTH_CLKOUTx_CONFIG_FIELD 6 -#define STV090x_OFFST_CLKOUTx_XOR_FIELD 0 -#define STV090x_WIDTH_CLKOUTx_XOR_FIELD 1 - -#define STV090x_DATAxCFG(__x) (0xf15f + (__x - 71) * 0x5) -#define STV090x_DATA71CFG STV090x_DATAxCFG(71) -#define STV090x_DATA72CFG STV090x_DATAxCFG(72) -#define STV090x_DATA73CFG STV090x_DATAxCFG(73) -#define STV090x_OFFST_DATAx_OPD_FIELD 7 -#define STV090x_WIDTH_DATAx_OPD_FIELD 1 -#define STV090x_OFFST_DATAx_CONFIG_FIELD 1 -#define STV090x_WIDTH_DATAx_CONFIG_FIELD 6 -#define STV090x_OFFST_DATAx_XOR_FIELD 0 -#define STV090x_WIDTH_DATAx_XOR_FIELD 1 - -#define STV090x_NCOARSE 0xf1b3 -#define STV090x_OFFST_M_DIV_FIELD 0 -#define STV090x_WIDTH_M_DIV_FIELD 8 - -#define STV090x_SYNTCTRL 0xf1b6 -#define STV090x_OFFST_STANDBY_FIELD 7 -#define STV090x_WIDTH_STANDBY_FIELD 1 -#define STV090x_OFFST_BYPASSPLLCORE_FIELD 6 -#define STV090x_WIDTH_BYPASSPLLCORE_FIELD 1 -#define STV090x_OFFST_SELX1RATIO_FIELD 5 -#define STV090x_WIDTH_SELX1RATIO_FIELD 1 -#define STV090x_OFFST_STOP_PLL_FIELD 3 -#define STV090x_WIDTH_STOP_PLL_FIELD 1 -#define STV090x_OFFST_BYPASSPLLFSK_FIELD 2 -#define STV090x_WIDTH_BYPASSPLLFSK_FIELD 1 -#define STV090x_OFFST_SELOSCI_FIELD 1 -#define STV090x_WIDTH_SELOSCI_FIELD 1 -#define STV090x_OFFST_BYPASSPLLADC_FIELD 0 -#define STV090x_WIDTH_BYPASSPLLADC_FIELD 1 - -#define STV090x_FILTCTRL 0xf1b7 -#define STV090x_OFFST_INV_CLK135_FIELD 7 -#define STV090x_WIDTH_INV_CLK135_FIELD 1 -#define STV090x_OFFST_SEL_FSKCKDIV_FIELD 2 -#define STV090x_WIDTH_SEL_FSKCKDIV_FIELD 1 -#define STV090x_OFFST_INV_CLKFSK_FIELD 1 -#define STV090x_WIDTH_INV_CLKFSK_FIELD 1 -#define STV090x_OFFST_BYPASS_APPLI_FIELD 0 -#define STV090x_WIDTH_BYPASS_APPLI_FIELD 1 - -#define STV090x_PLLSTAT 0xf1b8 -#define STV090x_OFFST_PLLLOCK_FIELD 0 -#define STV090x_WIDTH_PLLLOCK_FIELD 1 - -#define STV090x_STOPCLK1 0xf1c2 -#define STV090x_OFFST_STOP_CLKPKDT2_FIELD 6 -#define STV090x_WIDTH_STOP_CLKPKDT2_FIELD 1 -#define STV090x_OFFST_STOP_CLKPKDT1_FIELD 5 -#define STV090x_WIDTH_STOP_CLKPKDT1_FIELD 1 -#define STV090x_OFFST_STOP_CLKFEC_FIELD 4 -#define STV090x_WIDTH_STOP_CLKFEC_FIELD 1 -#define STV090x_OFFST_STOP_CLKADCI2_FIELD 3 -#define STV090x_WIDTH_STOP_CLKADCI2_FIELD 1 -#define STV090x_OFFST_INV_CLKADCI2_FIELD 2 -#define STV090x_WIDTH_INV_CLKADCI2_FIELD 1 -#define STV090x_OFFST_STOP_CLKADCI1_FIELD 1 -#define STV090x_WIDTH_STOP_CLKADCI1_FIELD 1 -#define STV090x_OFFST_INV_CLKADCI1_FIELD 0 -#define STV090x_WIDTH_INV_CLKADCI1_FIELD 1 - -#define STV090x_STOPCLK2 0xf1c3 -#define STV090x_OFFST_STOP_CLKSAMP2_FIELD 4 -#define STV090x_WIDTH_STOP_CLKSAMP2_FIELD 1 -#define STV090x_OFFST_STOP_CLKSAMP1_FIELD 3 -#define STV090x_WIDTH_STOP_CLKSAMP1_FIELD 1 -#define STV090x_OFFST_STOP_CLKVIT2_FIELD 2 -#define STV090x_WIDTH_STOP_CLKVIT2_FIELD 1 -#define STV090x_OFFST_STOP_CLKVIT1_FIELD 1 -#define STV090x_WIDTH_STOP_CLKVIT1_FIELD 1 -#define STV090x_OFFST_STOP_CLKTS_FIELD 0 -#define STV090x_WIDTH_STOP_CLKTS_FIELD 1 - -#define STV090x_TSTTNR0 0xf1df -#define STV090x_OFFST_SEL_FSK_FIELD 7 -#define STV090x_WIDTH_SEL_FSK_FIELD 1 -#define STV090x_OFFST_FSK_PON_FIELD 2 -#define STV090x_WIDTH_FSK_PON_FIELD 1 - -#define STV090x_TSTTNR1 0xf1e0 -#define STV090x_OFFST_ADC1_PON_FIELD 1 -#define STV090x_WIDTH_ADC1_PON_FIELD 1 -#define STV090x_OFFST_ADC1_INMODE_FIELD 0 -#define STV090x_WIDTH_ADC1_INMODE_FIELD 1 - -#define STV090x_TSTTNR2 0xf1e1 -#define STV090x_OFFST_DISEQC1_PON_FIELD 5 -#define STV090x_WIDTH_DISEQC1_PON_FIELD 1 - -#define STV090x_TSTTNR3 0xf1e2 -#define STV090x_OFFST_ADC2_PON_FIELD 1 -#define STV090x_WIDTH_ADC2_PON_FIELD 1 -#define STV090x_OFFST_ADC2_INMODE_FIELD 0 -#define STV090x_WIDTH_ADC2_INMODE_FIELD 1 - -#define STV090x_TSTTNR4 0xf1e3 -#define STV090x_OFFST_DISEQC2_PON_FIELD 5 -#define STV090x_WIDTH_DISEQC2_PON_FIELD 1 - -#define STV090x_FSKTFC2 0xf170 -#define STV090x_OFFST_FSKT_KMOD_FIELD 2 -#define STV090x_WIDTH_FSKT_KMOD_FIELD 6 -#define STV090x_OFFST_FSKT_CAR_FIELD 0 -#define STV090x_WIDTH_FSKT_CAR_FIELD 2 - -#define STV090x_FSKTFC1 0xf171 -#define STV090x_OFFST_FSKTC1_CAR_FIELD 0 -#define STV090x_WIDTH_FSKTC1_CAR_FIELD 8 - -#define STV090x_FSKTFC0 0xf172 -#define STV090x_OFFST_FSKTC0_CAR_FIELD 0 -#define STV090x_WIDTH_FSKTC0_CAR_FIELD 8 - -#define STV090x_FSKTDELTAF1 0xf173 -#define STV090x_OFFST_FSKTF1_DELTAF_FIELD 0 -#define STV090x_WIDTH_FSKTF1_DELTAF_FIELD 4 - -#define STV090x_FSKTDELTAF0 0xf174 -#define STV090x_OFFST_FSKTF0_DELTAF_FIELD 0 -#define STV090x_WIDTH_FSKTF0_DELTAF_FIELD 8 - -#define STV090x_FSKTCTRL 0xf175 -#define STV090x_OFFST_FSKT_EN_SGN_FIELD 6 -#define STV090x_WIDTH_FSKT_EN_SGN_FIELD 1 -#define STV090x_OFFST_FSKT_MOD_SGN_FIELD 5 -#define STV090x_WIDTH_FSKT_MOD_SGN_FIELD 1 -#define STV090x_OFFST_FSKT_MOD_EN_FIELD 2 -#define STV090x_WIDTH_FSKT_MOD_EN_FIELD 3 -#define STV090x_OFFST_FSKT_DACMODE_FIELD 0 -#define STV090x_WIDTH_FSKT_DACMODE_FIELD 2 - -#define STV090x_FSKRFC2 0xf176 -#define STV090x_OFFST_FSKRC2_DETSGN_FIELD 6 -#define STV090x_WIDTH_FSKRC2_DETSGN_FIELD 1 -#define STV090x_OFFST_FSKRC2_OUTSGN_FIELD 5 -#define STV090x_WIDTH_FSKRC2_OUTSGN_FIELD 1 -#define STV090x_OFFST_FSKRC2_KAGC_FIELD 2 -#define STV090x_WIDTH_FSKRC2_KAGC_FIELD 3 -#define STV090x_OFFST_FSKRC2_CAR_FIELD 0 -#define STV090x_WIDTH_FSKRC2_CAR_FIELD 2 - -#define STV090x_FSKRFC1 0xf177 -#define STV090x_OFFST_FSKRC1_CAR_FIELD 0 -#define STV090x_WIDTH_FSKRC1_CAR_FIELD 8 - -#define STV090x_FSKRFC0 0xf178 -#define STV090x_OFFST_FSKRC0_CAR_FIELD 0 -#define STV090x_WIDTH_FSKRC0_CAR_FIELD 8 - -#define STV090x_FSKRK1 0xf179 -#define STV090x_OFFST_FSKR_K1_EXP_FIELD 5 -#define STV090x_WIDTH_FSKR_K1_EXP_FIELD 3 -#define STV090x_OFFST_FSKR_K1_MANT_FIELD 0 -#define STV090x_WIDTH_FSKR_K1_MANT_FIELD 5 - -#define STV090x_FSKRK2 0xf17a -#define STV090x_OFFST_FSKR_K2_EXP_FIELD 5 -#define STV090x_WIDTH_FSKR_K2_EXP_FIELD 3 -#define STV090x_OFFST_FSKR_K2_MANT_FIELD 0 -#define STV090x_WIDTH_FSKR_K2_MANT_FIELD 5 - -#define STV090x_FSKRAGCR 0xf17b -#define STV090x_OFFST_FSKR_OUTCTL_FIELD 6 -#define STV090x_WIDTH_FSKR_OUTCTL_FIELD 2 -#define STV090x_OFFST_FSKR_AGC_REF_FIELD 0 -#define STV090x_WIDTH_FSKR_AGC_REF_FIELD 6 - -#define STV090x_FSKRAGC 0xf17c -#define STV090x_OFFST_FSKR_AGC_ACCU_FIELD 0 -#define STV090x_WIDTH_FSKR_AGC_ACCU_FIELD 8 - -#define STV090x_FSKRALPHA 0xf17d -#define STV090x_OFFST_FSKR_ALPHA_EXP_FIELD 2 -#define STV090x_WIDTH_FSKR_ALPHA_EXP_FIELD 3 -#define STV090x_OFFST_FSKR_ALPHA_M_FIELD 0 -#define STV090x_WIDTH_FSKR_ALPHA_M_FIELD 2 - -#define STV090x_FSKRPLTH1 0xf17e -#define STV090x_OFFST_FSKR_BETA_FIELD 4 -#define STV090x_WIDTH_FSKR_BETA_FIELD 4 -#define STV090x_OFFST_FSKR_PLL_TRESH1_FIELD 0 -#define STV090x_WIDTH_FSKR_PLL_TRESH1_FIELD 4 - -#define STV090x_FSKRPLTH0 0xf17f -#define STV090x_OFFST_FSKR_PLL_TRESH0_FIELD 0 -#define STV090x_WIDTH_FSKR_PLL_TRESH0_FIELD 8 - -#define STV090x_FSKRDF1 0xf180 -#define STV090x_OFFST_FSKR_DELTAF1_FIELD 0 -#define STV090x_WIDTH_FSKR_DELTAF1_FIELD 5 - -#define STV090x_FSKRDF0 0xf181 -#define STV090x_OFFST_FSKR_DELTAF0_FIELD 0 -#define STV090x_WIDTH_FSKR_DELTAF0_FIELD 8 - -#define STV090x_FSKRSTEPP 0xf182 -#define STV090x_OFFST_FSKR_STEP_PLUS_FIELD 0 -#define STV090x_WIDTH_FSKR_STEP_PLUS_FIELD 8 - -#define STV090x_FSKRSTEPM 0xf183 -#define STV090x_OFFST_FSKR_STEP_MINUS_FIELD 0 -#define STV090x_WIDTH_FSKR_STEP_MINUS_FIELD 8 - -#define STV090x_FSKRDET1 0xf184 -#define STV090x_OFFST_FSKR_CARDET1_ACCU_FIELD 0 -#define STV090x_WIDTH_FSKR_CARDET1_ACCU_FIELD 4 - -#define STV090x_FSKRDET0 0xf185 -#define STV090x_OFFST_FSKR_CARDET0_ACCU_FIELD 0 -#define STV090x_WIDTH_FSKR_CARDET0_ACCU_FIELD 8 - -#define STV090x_FSKRDTH1 0xf186 -#define STV090x_OFFST_FSKR_CARLOSS_THRESH1_FIELD 4 -#define STV090x_WIDTH_FSKR_CARLOSS_THRESH1_FIELD 4 -#define STV090x_OFFST_FSKR_CARDET_THRESH1_FIELD 0 -#define STV090x_WIDTH_FSKR_CARDET_THRESH1_FIELD 4 - -#define STV090x_FSKRDTH0 0xf187 -#define STV090x_OFFST_FSKR_CARDET_THRESH0_FIELD 0 -#define STV090x_WIDTH_FSKR_CARDET_THRESH0_FIELD 8 - -#define STV090x_FSKRLOSS 0xf188 -#define STV090x_OFFST_FSKR_CARLOSS_THRESH_FIELD 0 -#define STV090x_WIDTH_FSKR_CARLOSS_THRESH_FIELD 8 - -#define STV090x_Px_DISTXCTL(__x) (0xF1A0 - (__x - 1) * 0x10) -#define STV090x_P1_DISTXCTL STV090x_Px_DISTXCTL(1) -#define STV090x_P2_DISTXCTL STV090x_Px_DISTXCTL(2) -#define STV090x_OFFST_Px_TIM_OFF_FIELD 7 -#define STV090x_WIDTH_Px_TIM_OFF_FIELD 1 -#define STV090x_OFFST_Px_DISEQC_RESET_FIELD 6 -#define STV090x_WIDTH_Px_DISEQC_RESET_FIELD 1 -#define STV090x_OFFST_Px_TIM_CMD_FIELD 4 -#define STV090x_WIDTH_Px_TIM_CMD_FIELD 2 -#define STV090x_OFFST_Px_DIS_PRECHARGE_FIELD 3 -#define STV090x_WIDTH_Px_DIS_PRECHARGE_FIELD 1 -#define STV090x_OFFST_Px_DISTX_MODE_FIELD 0 -#define STV090x_WIDTH_Px_DISTX_MODE_FIELD 3 - -#define STV090x_Px_DISRXCTL(__x) (0xf1a1 - (__x - 1) * 0x10) -#define STV090x_P1_DISRXCTL STV090x_Px_DISRXCTL(1) -#define STV090x_P2_DISRXCTL STV090x_Px_DISRXCTL(2) -#define STV090x_OFFST_Px_RECEIVER_ON_FIELD 7 -#define STV090x_WIDTH_Px_RECEIVER_ON_FIELD 1 -#define STV090x_OFFST_Px_IGNO_SHORT22K_FIELD 6 -#define STV090x_WIDTH_Px_IGNO_SHORT22K_FIELD 1 -#define STV090x_OFFST_Px_ONECHIP_TRX_FIELD 5 -#define STV090x_WIDTH_Px_ONECHIP_TRX_FIELD 1 -#define STV090x_OFFST_Px_EXT_ENVELOP_FIELD 4 -#define STV090x_WIDTH_Px_EXT_ENVELOP_FIELD 1 -#define STV090x_OFFST_Px_PIN_SELECT_FIELD 2 -#define STV090x_WIDTH_Px_PIN_SELECT_FIELD 2 -#define STV090x_OFFST_Px_IRQ_RXEND_FIELD 1 -#define STV090x_WIDTH_Px_IRQ_RXEND_FIELD 1 -#define STV090x_OFFST_Px_IRQ_4NBYTES_FIELD 0 -#define STV090x_WIDTH_Px_IRQ_4NBYTES_FIELD 1 - -#define STV090x_Px_DISRX_ST0(__x) (0xf1a4 - (__x - 1) * 0x10) -#define STV090x_P1_DISRX_ST0 STV090x_Px_DISRX_ST0(1) -#define STV090x_P2_DISRX_ST0 STV090x_Px_DISRX_ST0(2) -#define STV090x_OFFST_Px_RX_END_FIELD 7 -#define STV090x_WIDTH_Px_RX_END_FIELD 1 -#define STV090x_OFFST_Px_RX_ACTIVE_FIELD 6 -#define STV090x_WIDTH_Px_RX_ACTIVE_FIELD 1 -#define STV090x_OFFST_Px_SHORT_22KHZ_FIELD 5 -#define STV090x_WIDTH_Px_SHORT_22KHZ_FIELD 1 -#define STV090x_OFFST_Px_CONT_TONE_FIELD 4 -#define STV090x_WIDTH_Px_CONT_TONE_FIELD 1 -#define STV090x_OFFST_Px_FIFO_4BREADY_FIELD 3 -#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD 1 -#define STV090x_OFFST_Px_FIFO_EMPTY_FIELD 2 -#define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD 1 -#define STV090x_OFFST_Px_ABORT_DISRX_FIELD 0 -#define STV090x_WIDTH_Px_ABORT_DISRX_FIELD 1 - -#define STV090x_Px_DISRX_ST1(__x) (0xf1a5 - (__x - 1) * 0x10) -#define STV090x_P1_DISRX_ST1 STV090x_Px_DISRX_ST1(1) -#define STV090x_P2_DISRX_ST1 STV090x_Px_DISRX_ST1(2) -#define STV090x_OFFST_Px_RX_FAIL_FIELD 7 -#define STV090x_WIDTH_Px_RX_FAIL_FIELD 1 -#define STV090x_OFFST_Px_FIFO_PARITYFAIL_FIELD 6 -#define STV090x_WIDTH_Px_FIFO_PARITYFAIL_FIELD 1 -#define STV090x_OFFST_Px_RX_NONBYTE_FIELD 5 -#define STV090x_WIDTH_Px_RX_NONBYTE_FIELD 1 -#define STV090x_OFFST_Px_FIFO_OVERFLOW_FIELD 4 -#define STV090x_WIDTH_Px_FIFO_OVERFLOW_FIELD 1 -#define STV090x_OFFST_Px_FIFO_BYTENBR_FIELD 0 -#define STV090x_WIDTH_Px_FIFO_BYTENBR_FIELD 4 - -#define STV090x_Px_DISRXDATA(__x) (0xf1a6 - (__x - 1) * 0x10) -#define STV090x_P1_DISRXDATA STV090x_Px_DISRXDATA(1) -#define STV090x_P2_DISRXDATA STV090x_Px_DISRXDATA(2) -#define STV090x_OFFST_Px_DISRX_DATA_FIELD 0 -#define STV090x_WIDTH_Px_DISRX_DATA_FIELD 8 - -#define STV090x_Px_DISTXDATA(__x) (0xf1a7 - (__x - 1) * 0x10) -#define STV090x_P1_DISTXDATA STV090x_Px_DISTXDATA(1) -#define STV090x_P2_DISTXDATA STV090x_Px_DISTXDATA(2) -#define STV090x_OFFST_Px_DISEQC_FIFO_FIELD 0 -#define STV090x_WIDTH_Px_DISEQC_FIFO_FIELD 8 - -#define STV090x_Px_DISTXSTATUS(__x) (0xf1a8 - (__x - 1) * 0x10) -#define STV090x_P1_DISTXSTATUS STV090x_Px_DISTXSTATUS(1) -#define STV090x_P2_DISTXSTATUS STV090x_Px_DISTXSTATUS(2) -#define STV090x_OFFST_Px_TX_FAIL_FIELD 7 -#define STV090x_WIDTH_Px_TX_FAIL_FIELD 1 -#define STV090x_OFFST_Px_FIFO_FULL_FIELD 6 -#define STV090x_WIDTH_Px_FIFO_FULL_FIELD 1 -#define STV090x_OFFST_Px_TX_IDLE_FIELD 5 -#define STV090x_WIDTH_Px_TX_IDLE_FIELD 1 -#define STV090x_OFFST_Px_GAP_BURST_FIELD 4 -#define STV090x_WIDTH_Px_GAP_BURST_FIELD 1 -#define STV090x_OFFST_Px_TXFIFO_BYTES_FIELD 0 -#define STV090x_WIDTH_Px_TXFIFO_BYTES_FIELD 4 - -#define STV090x_Px_F22TX(__x) (0xf1a9 - (__x - 1) * 0x10) -#define STV090x_P1_F22TX STV090x_Px_F22TX(1) -#define STV090x_P2_F22TX STV090x_Px_F22TX(2) -#define STV090x_OFFST_Px_F22_REG_FIELD 0 -#define STV090x_WIDTH_Px_F22_REG_FIELD 8 - -#define STV090x_Px_F22RX(__x) (0xf1aa - (__x - 1) * 0x10) -#define STV090x_P1_F22RX STV090x_Px_F22RX(1) -#define STV090x_P2_F22RX STV090x_Px_F22RX(2) -#define STV090x_OFFST_Px_F22RX_REG_FIELD 0 -#define STV090x_WIDTH_Px_F22RX_REG_FIELD 8 - -#define STV090x_Px_ACRPRESC(__x) (0xf1ac - (__x - 1) * 0x10) -#define STV090x_P1_ACRPRESC STV090x_Px_ACRPRESC(1) -#define STV090x_P2_ACRPRESC STV090x_Px_ACRPRESC(2) -#define STV090x_OFFST_Px_ACR_PRESC_FIELD 0 -#define STV090x_WIDTH_Px_ACR_PRESC_FIELD 3 - -#define STV090x_Px_ACRDIV(__x) (0xf1ad - (__x - 1) * 0x10) -#define STV090x_P1_ACRDIV STV090x_Px_ACRDIV(1) -#define STV090x_P2_ACRDIV STV090x_Px_ACRDIV(2) -#define STV090x_OFFST_Px_ACR_DIV_FIELD 0 -#define STV090x_WIDTH_Px_ACR_DIV_FIELD 8 - -#define STV090x_Px_IQCONST(__x) (0xF400 - (__x - 1) * 0x200) -#define STV090x_P1_IQCONST STV090x_Px_IQCONST(1) -#define STV090x_P2_IQCONST STV090x_Px_IQCONST(2) -#define STV090x_OFFST_Px_CONSTEL_SELECT_FIELD 5 -#define STV090x_WIDTH_Px_CONSTEL_SELECT_FIELD 2 - -#define STV090x_Px_NOSCFG(__x) (0xF401 - (__x - 1) * 0x200) -#define STV090x_P1_NOSCFG STV090x_Px_NOSCFG(1) -#define STV090x_P2_NOSCFG STV090x_Px_NOSCFG(2) -#define STV090x_OFFST_Px_NOSPLH_BETA_FIELD 3 -#define STV090x_WIDTH_Px_NOSPLH_BETA_FIELD 2 -#define STV090x_OFFST_Px_NOSDATA_BETA_FIELD 0 -#define STV090x_WIDTH_Px_NOSDATA_BETA_FIELD 3 - -#define STV090x_Px_ISYMB(__x) (0xF402 - (__x - 1) * 0x200) -#define STV090x_P1_ISYMB STV090x_Px_ISYMB(1) -#define STV090x_P2_ISYMB STV090x_Px_ISYMB(2) -#define STV090x_OFFST_Px_I_SYMBOL_FIELD 0 -#define STV090x_WIDTH_Px_I_SYMBOL_FIELD 8 - -#define STV090x_Px_QSYMB(__x) (0xF403 - (__x - 1) * 0x200) -#define STV090x_P1_QSYMB STV090x_Px_QSYMB(1) -#define STV090x_P2_QSYMB STV090x_Px_QSYMB(2) -#define STV090x_OFFST_Px_Q_SYMBOL_FIELD 0 -#define STV090x_WIDTH_Px_Q_SYMBOL_FIELD 8 - -#define STV090x_Px_AGC1CFG(__x) (0xF404 - (__x - 1) * 0x200) -#define STV090x_P1_AGC1CFG STV090x_Px_AGC1CFG(1) -#define STV090x_P2_AGC1CFG STV090x_Px_AGC1CFG(2) -#define STV090x_OFFST_Px_DC_FROZEN_FIELD 7 -#define STV090x_WIDTH_Px_DC_FROZEN_FIELD 1 -#define STV090x_OFFST_Px_DC_CORRECT_FIELD 6 -#define STV090x_WIDTH_Px_DC_CORRECT_FIELD 1 -#define STV090x_OFFST_Px_AMM_FROZEN_FIELD 5 -#define STV090x_WIDTH_Px_AMM_FROZEN_FIELD 1 -#define STV090x_OFFST_Px_AMM_CORRECT_FIELD 4 -#define STV090x_WIDTH_Px_AMM_CORRECT_FIELD 1 -#define STV090x_OFFST_Px_QUAD_FROZEN_FIELD 3 -#define STV090x_WIDTH_Px_QUAD_FROZEN_FIELD 1 -#define STV090x_OFFST_Px_QUAD_CORRECT_FIELD 2 -#define STV090x_WIDTH_Px_QUAD_CORRECT_FIELD 1 - -#define STV090x_Px_AGC1CN(__x) (0xF406 - (__x - 1) * 0x200) -#define STV090x_P1_AGC1CN STV090x_Px_AGC1CN(1) -#define STV090x_P2_AGC1CN STV090x_Px_AGC1CN(2) -#define STV090x_WIDTH_Px_AGC1_LOCKED_FIELD 7 -#define STV090x_OFFST_Px_AGC1_LOCKED_FIELD 1 -#define STV090x_OFFST_Px_AGC1_MINPOWER_FIELD 4 -#define STV090x_WIDTH_Px_AGC1_MINPOWER_FIELD 1 -#define STV090x_OFFST_Px_AGCOUT_FAST_FIELD 3 -#define STV090x_WIDTH_Px_AGCOUT_FAST_FIELD 1 -#define STV090x_OFFST_Px_AGCIQ_BETA_FIELD 0 -#define STV090x_WIDTH_Px_AGCIQ_BETA_FIELD 3 - -#define STV090x_Px_AGC1REF(__x) (0xF407 - (__x - 1) * 0x200) -#define STV090x_P1_AGC1REF STV090x_Px_AGC1REF(1) -#define STV090x_P2_AGC1REF STV090x_Px_AGC1REF(2) -#define STV090x_OFFST_Px_AGCIQ_REF_FIELD 0 -#define STV090x_WIDTH_Px_AGCIQ_REF_FIELD 8 - -#define STV090x_Px_IDCCOMP(__x) (0xF408 - (__x - 1) * 0x200) -#define STV090x_P1_IDCCOMP STV090x_Px_IDCCOMP(1) -#define STV090x_P2_IDCCOMP STV090x_Px_IDCCOMP(2) -#define STV090x_OFFST_Px_IAVERAGE_ADJ_FIELD 0 -#define STV090x_WIDTH_Px_IAVERAGE_ADJ_FIELD 8 - -#define STV090x_Px_QDCCOMP(__x) (0xF409 - (__x - 1) * 0x200) -#define STV090x_P1_QDCCOMP STV090x_Px_QDCCOMP(1) -#define STV090x_P2_QDCCOMP STV090x_Px_QDCCOMP(2) -#define STV090x_OFFST_Px_QAVERAGE_ADJ_FIELD 0 -#define STV090x_WIDTH_Px_QAVERAGE_ADJ_FIELD 8 - -#define STV090x_Px_POWERI(__x) (0xF40A - (__x - 1) * 0x200) -#define STV090x_P1_POWERI STV090x_Px_POWERI(1) -#define STV090x_P2_POWERI STV090x_Px_POWERI(2) -#define STV090x_OFFST_Px_POWER_I_FIELD 0 -#define STV090x_WIDTH_Px_POWER_I_FIELD 8 - -#define STV090x_Px_POWERQ(__x) (0xF40B - (__x - 1) * 0x200) -#define STV090x_P1_POWERQ STV090x_Px_POWERQ(1) -#define STV090x_P2_POWERQ STV090x_Px_POWERQ(2) -#define STV090x_OFFST_Px_POWER_Q_FIELD 0 -#define STV090x_WIDTH_Px_POWER_Q_FIELD 8 - -#define STV090x_Px_AGC1AMM(__x) (0xF40C - (__x - 1) * 0x200) -#define STV090x_P1_AGC1AMM STV090x_Px_AGC1AMM(1) -#define STV090x_P2_AGC1AMM STV090x_Px_AGC1AMM(2) -#define STV090x_OFFST_Px_AMM_VALUE_FIELD 0 -#define STV090x_WIDTH_Px_AMM_VALUE_FIELD 8 - -#define STV090x_Px_AGC1QUAD(__x) (0xF40D - (__x - 1) * 0x200) -#define STV090x_P1_AGC1QUAD STV090x_Px_AGC1QUAD(1) -#define STV090x_P2_AGC1QUAD STV090x_Px_AGC1QUAD(2) -#define STV090x_OFFST_Px_QUAD_VALUE_FIELD 0 -#define STV090x_WIDTH_Px_QUAD_VALUE_FIELD 8 - -#define STV090x_Px_AGCIQINy(__x, __y) (0xF40F - (__x-1) * 0x200 - __y * 0x1) -#define STV090x_P1_AGCIQIN0 STV090x_Px_AGCIQINy(1, 0) -#define STV090x_P1_AGCIQIN1 STV090x_Px_AGCIQINy(1, 1) -#define STV090x_P2_AGCIQIN0 STV090x_Px_AGCIQINy(2, 0) -#define STV090x_P2_AGCIQIN1 STV090x_Px_AGCIQINy(2, 1) -#define STV090x_OFFST_Px_AGCIQ_VALUE_FIELD 0 -#define STV090x_WIDTH_Px_AGCIQ_VALUE_FIELD 8 - -#define STV090x_Px_DEMOD(__x) (0xF410 - (__x - 1) * 0x200) -#define STV090x_P1_DEMOD STV090x_Px_DEMOD(1) -#define STV090x_P2_DEMOD STV090x_Px_DEMOD(2) -#define STV090x_OFFST_Px_MANUAL_S2ROLLOFF_FIELD 7 -#define STV090x_WIDTH_Px_MANUAL_S2ROLLOFF_FIELD 1 -#define STV090x_OFFST_Px_DEMOD_STOP_FIELD 6 -#define STV090x_WIDTH_Px_DEMOD_STOP_FIELD 1 -#define STV090x_OFFST_Px_SPECINV_CONTROL_FIELD 4 -#define STV090x_WIDTH_Px_SPECINV_CONTROL_FIELD 2 -#define STV090x_OFFST_Px_FORCE_ENASAMP_FIELD 3 -#define STV090x_WIDTH_Px_FORCE_ENASAMP_FIELD 1 -#define STV090x_OFFST_Px_MANUAL_SXROLLOFF_FIELD 2 -#define STV090x_WIDTH_Px_MANUAL_SXROLLOFF_FIELD 1 -#define STV090x_OFFST_Px_ROLLOFF_CONTROL_FIELD 0 -#define STV090x_WIDTH_Px_ROLLOFF_CONTROL_FIELD 2 - -#define STV090x_Px_DMDMODCOD(__x) (0xF411 - (__x - 1) * 0x200) -#define STV090x_P1_DMDMODCOD STV090x_Px_DMDMODCOD(1) -#define STV090x_P2_DMDMODCOD STV090x_Px_DMDMODCOD(2) -#define STV090x_OFFST_Px_MANUAL_MODCOD_FIELD 7 -#define STV090x_WIDTH_Px_MANUAL_MODCOD_FIELD 1 -#define STV090x_OFFST_Px_DEMOD_MODCOD_FIELD 2 -#define STV090x_WIDTH_Px_DEMOD_MODCOD_FIELD 5 -#define STV090x_OFFST_Px_DEMOD_TYPE_FIELD 0 -#define STV090x_WIDTH_Px_DEMOD_TYPE_FIELD 2 - -#define STV090x_Px_DSTATUS(__x) (0xF412 - (__x - 1) * 0x200) -#define STV090x_P1_DSTATUS STV090x_Px_DSTATUS(1) -#define STV090x_P2_DSTATUS STV090x_Px_DSTATUS(2) -#define STV090x_OFFST_Px_CAR_LOCK_FIELD 7 -#define STV090x_WIDTH_Px_CAR_LOCK_FIELD 1 -#define STV090x_OFFST_Px_TMGLOCK_QUALITY_FIELD 5 -#define STV090x_WIDTH_Px_TMGLOCK_QUALITY_FIELD 2 -#define STV090x_OFFST_Px_LOCK_DEFINITIF_FIELD 3 -#define STV090x_WIDTH_Px_LOCK_DEFINITIF_FIELD 1 - -#define STV090x_Px_DSTATUS2(__x) (0xF413 - (__x - 1) * 0x200) -#define STV090x_P1_DSTATUS2 STV090x_Px_DSTATUS2(1) -#define STV090x_P2_DSTATUS2 STV090x_Px_DSTATUS2(2) -#define STV090x_OFFST_Px_DEMOD_DELOCK_FIELD 7 -#define STV090x_WIDTH_Px_DEMOD_DELOCK_FIELD 1 -#define STV090x_OFFST_Px_AGC1_NOSIGNALACK_FIELD 3 -#define STV090x_WIDTH_Px_AGC1_NOSIGNALACK_FIELD 1 -#define STV090x_OFFST_Px_AGC2_OVERFLOW_FIELD 2 -#define STV090x_WIDTH_Px_AGC2_OVERFLOW_FIELD 1 -#define STV090x_OFFST_Px_CFR_OVERFLOW_FIELD 1 -#define STV090x_WIDTH_Px_CFR_OVERFLOW_FIELD 1 -#define STV090x_OFFST_Px_GAMMA_OVERUNDER_FIELD 0 -#define STV090x_WIDTH_Px_GAMMA_OVERUNDER_FIELD 1 - -#define STV090x_Px_DMDCFGMD(__x) (0xF414 - (__x - 1) * 0x200) -#define STV090x_P1_DMDCFGMD STV090x_Px_DMDCFGMD(1) -#define STV090x_P2_DMDCFGMD STV090x_Px_DMDCFGMD(2) -#define STV090x_OFFST_Px_DVBS2_ENABLE_FIELD 7 -#define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD 1 -#define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD 6 -#define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD 1 -#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD 4 -#define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD 1 -#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD 3 -#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD 1 -#define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD 2 -#define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD 1 -#define STV090x_OFFST_Px_TUN_RNG_FIELD 0 -#define STV090x_WIDTH_Px_TUN_RNG_FIELD 2 - -#define STV090x_Px_DMDCFG2(__x) (0xF415 - (__x - 1) * 0x200) -#define STV090x_P1_DMDCFG2 STV090x_Px_DMDCFG2(1) -#define STV090x_P2_DMDCFG2 STV090x_Px_DMDCFG2(2) -#define STV090x_OFFST_Px_S1S2_SEQUENTIAL_FIELD 6 -#define STV090x_WIDTH_Px_S1S2_SEQUENTIAL_FIELD 1 - -#define STV090x_Px_DMDISTATE(__x) (0xF416 - (__x - 1) * 0x200) -#define STV090x_P1_DMDISTATE STV090x_Px_DMDISTATE(1) -#define STV090x_P2_DMDISTATE STV090x_Px_DMDISTATE(2) -#define STV090x_OFFST_Px_I2C_DEMOD_MODE_FIELD 0 -#define STV090x_WIDTH_Px_I2C_DEMOD_MODE_FIELD 5 - -#define STV090x_Px_DMDTOM(__x) (0xF417 - (__x - 1) * 0x200) /* check */ -#define STV090x_P1_DMDTOM STV090x_Px_DMDTOM(1) -#define STV090x_P2_DMDTOM STV090x_Px_DMDTOM(2) - -#define STV090x_Px_DMDSTATE(__x) (0xF41B - (__x - 1) * 0x200) -#define STV090x_P1_DMDSTATE STV090x_Px_DMDSTATE(1) -#define STV090x_P2_DMDSTATE STV090x_Px_DMDSTATE(2) -#define STV090x_OFFST_Px_HEADER_MODE_FIELD 5 -#define STV090x_WIDTH_Px_HEADER_MODE_FIELD 2 - -#define STV090x_Px_DMDFLYW(__x) (0xF41C - (__x - 1) * 0x200) -#define STV090x_P1_DMDFLYW STV090x_Px_DMDFLYW(1) -#define STV090x_P2_DMDFLYW STV090x_Px_DMDFLYW(2) -#define STV090x_OFFST_Px_I2C_IRQVAL_FIELD 4 -#define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD 4 -#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD 0 -#define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD 4 - -#define STV090x_Px_DSTATUS3(__x) (0xF41D - (__x - 1) * 0x200) -#define STV090x_P1_DSTATUS3 STV090x_Px_DSTATUS3(1) -#define STV090x_P2_DSTATUS3 STV090x_Px_DSTATUS3(2) -#define STV090x_OFFST_Px_DEMOD_CFGMODE_FIELD 5 -#define STV090x_WIDTH_Px_DEMOD_CFGMODE_FIELD 2 - -#define STV090x_Px_DMDCFG3(__x) (0xF41E - (__x - 1) * 0x200) -#define STV090x_P1_DMDCFG3 STV090x_Px_DMDCFG3(1) -#define STV090x_P2_DMDCFG3 STV090x_Px_DMDCFG3(2) -#define STV090x_OFFST_Px_NOSTOP_FIFOFULL_FIELD 3 -#define STV090x_WIDTH_Px_NOSTOP_FIFOFULL_FIELD 1 - -#define STV090x_Px_DMDCFG4(__x) (0xf41f - (__x - 1) * 0x200) -#define STV090x_P1_DMDCFG4 STV090x_Px_DMDCFG4(1) -#define STV090x_P2_DMDCFG4 STV090x_Px_DMDCFG4(2) - -#define STV090x_Px_CORRELMANT(__x) (0xF420 - (__x - 1) * 0x200) -#define STV090x_P1_CORRELMANT STV090x_Px_CORRELMANT(1) -#define STV090x_P2_CORRELMANT STV090x_Px_CORRELMANT(2) -#define STV090x_OFFST_Px_CORREL_MANT_FIELD 0 -#define STV090x_WIDTH_Px_CORREL_MANT_FIELD 8 - -#define STV090x_Px_CORRELABS(__x) (0xF421 - (__x - 1) * 0x200) -#define STV090x_P1_CORRELABS STV090x_Px_CORRELABS(1) -#define STV090x_P2_CORRELABS STV090x_Px_CORRELABS(2) -#define STV090x_OFFST_Px_CORREL_ABS_FIELD 0 -#define STV090x_WIDTH_Px_CORREL_ABS_FIELD 8 - -#define STV090x_Px_CORRELEXP(__x) (0xF422 - (__x - 1) * 0x200) -#define STV090x_P1_CORRELEXP STV090x_Px_CORRELEXP(1) -#define STV090x_P2_CORRELEXP STV090x_Px_CORRELEXP(2) -#define STV090x_OFFST_Px_CORREL_ABSEXP_FIELD 4 -#define STV090x_WIDTH_Px_CORREL_ABSEXP_FIELD 4 -#define STV090x_OFFST_Px_CORREL_EXP_FIELD 0 -#define STV090x_WIDTH_Px_CORREL_EXP_FIELD 4 - -#define STV090x_Px_PLHMODCOD(__x) (0xF424 - (__x - 1) * 0x200) -#define STV090x_P1_PLHMODCOD STV090x_Px_PLHMODCOD(1) -#define STV090x_P2_PLHMODCOD STV090x_Px_PLHMODCOD(2) -#define STV090x_OFFST_Px_SPECINV_DEMOD_FIELD 7 -#define STV090x_WIDTH_Px_SPECINV_DEMOD_FIELD 1 -#define STV090x_OFFST_Px_PLH_MODCOD_FIELD 2 -#define STV090x_WIDTH_Px_PLH_MODCOD_FIELD 5 -#define STV090x_OFFST_Px_PLH_TYPE_FIELD 0 -#define STV090x_WIDTH_Px_PLH_TYPE_FIELD 2 - -#define STV090x_Px_AGCK32(__x) (0xf42b - (__x - 1) * 0x200) -#define STV090x_P1_AGCK32 STV090x_Px_AGCK32(1) -#define STV090x_P2_AGCK32 STV090x_Px_AGCK32(2) - -#define STV090x_Px_AGC2O(__x) (0xF42C - (__x - 1) * 0x200) -#define STV090x_P1_AGC2O STV090x_Px_AGC2O(1) -#define STV090x_P2_AGC2O STV090x_Px_AGC2O(2) - -#define STV090x_Px_AGC2REF(__x) (0xF42D - (__x - 1) * 0x200) -#define STV090x_P1_AGC2REF STV090x_Px_AGC2REF(1) -#define STV090x_P2_AGC2REF STV090x_Px_AGC2REF(2) -#define STV090x_OFFST_Px_AGC2_REF_FIELD 0 -#define STV090x_WIDTH_Px_AGC2_REF_FIELD 8 - -#define STV090x_Px_AGC1ADJ(__x) (0xF42E - (__x - 1) * 0x200) -#define STV090x_P1_AGC1ADJ STV090x_Px_AGC1ADJ(1) -#define STV090x_P2_AGC1ADJ STV090x_Px_AGC1ADJ(2) -#define STV090x_OFFST_Px_AGC1_ADJUSTED_FIELD 0 -#define STV090x_WIDTH_Px_AGC1_ADJUSTED_FIELD 7 - -#define STV090x_Px_AGC2Iy(__x, __y) (0xF437 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_AGC2I0 STV090x_Px_AGC2Iy(1, 0) -#define STV090x_P1_AGC2I1 STV090x_Px_AGC2Iy(1, 1) -#define STV090x_P2_AGC2I0 STV090x_Px_AGC2Iy(2, 0) -#define STV090x_P2_AGC2I1 STV090x_Px_AGC2Iy(2, 1) -#define STV090x_OFFST_Px_AGC2_INTEGRATOR_FIELD 0 -#define STV090x_WIDTH_Px_AGC2_INTEGRATOR_FIELD 8 - -#define STV090x_Px_CARCFG(__x) (0xF438 - (__x - 1) * 0x200) -#define STV090x_P1_CARCFG STV090x_Px_CARCFG(1) -#define STV090x_P2_CARCFG STV090x_Px_CARCFG(2) -#define STV090x_OFFST_Px_EN_CAR2CENTER_FIELD 5 -#define STV090x_WIDTH_Px_EN_CAR2CENTER_FIELD 1 -#define STV090x_OFFST_Px_ROTATON_FIELD 2 -#define STV090x_WIDTH_Px_ROTATON_FIELD 1 -#define STV090x_OFFST_Px_PH_DET_ALGO_FIELD 0 -#define STV090x_WIDTH_Px_PH_DET_ALGO_FIELD 2 - -#define STV090x_Px_ACLC(__x) (0xF439 - (__x - 1) * 0x200) -#define STV090x_P1_ACLC STV090x_Px_ACLC(1) -#define STV090x_P2_ACLC STV090x_Px_ACLC(2) -#define STV090x_OFFST_Px_CAR_ALPHA_MANT_FIELD 4 -#define STV090x_WIDTH_Px_CAR_ALPHA_MANT_FIELD 2 -#define STV090x_OFFST_Px_CAR_ALPHA_EXP_FIELD 0 -#define STV090x_WIDTH_Px_CAR_ALPHA_EXP_FIELD 4 - -#define STV090x_Px_BCLC(__x) (0xF43A - (__x - 1) * 0x200) -#define STV090x_P1_BCLC STV090x_Px_BCLC(1) -#define STV090x_P2_BCLC STV090x_Px_BCLC(2) -#define STV090x_OFFST_Px_CAR_BETA_MANT_FIELD 4 -#define STV090x_WIDTH_Px_CAR_BETA_MANT_FIELD 2 -#define STV090x_OFFST_Px_CAR_BETA_EXP_FIELD 0 -#define STV090x_WIDTH_Px_CAR_BETA_EXP_FIELD 4 - -#define STV090x_Px_CARFREQ(__x) (0xF43D - (__x - 1) * 0x200) -#define STV090x_P1_CARFREQ STV090x_Px_CARFREQ(1) -#define STV090x_P2_CARFREQ STV090x_Px_CARFREQ(2) -#define STV090x_OFFST_Px_KC_COARSE_EXP_FIELD 4 -#define STV090x_WIDTH_Px_KC_COARSE_EXP_FIELD 4 -#define STV090x_OFFST_Px_BETA_FREQ_FIELD 0 -#define STV090x_WIDTH_Px_BETA_FREQ_FIELD 4 - -#define STV090x_Px_CARHDR(__x) (0xF43E - (__x - 1) * 0x200) -#define STV090x_P1_CARHDR STV090x_Px_CARHDR(1) -#define STV090x_P2_CARHDR STV090x_Px_CARHDR(2) -#define STV090x_OFFST_Px_FREQ_HDR_FIELD 0 -#define STV090x_WIDTH_Px_FREQ_HDR_FIELD 8 - -#define STV090x_Px_LDT(__x) (0xF43F - (__x - 1) * 0x200) -#define STV090x_P1_LDT STV090x_Px_LDT(1) -#define STV090x_P2_LDT STV090x_Px_LDT(2) -#define STV090x_OFFST_Px_CARLOCK_THRES_FIELD 0 -#define STV090x_WIDTH_Px_CARLOCK_THRES_FIELD 8 - -#define STV090x_Px_LDT2(__x) (0xF440 - (__x - 1) * 0x200) -#define STV090x_P1_LDT2 STV090x_Px_LDT2(1) -#define STV090x_P2_LDT2 STV090x_Px_LDT2(2) -#define STV090x_OFFST_Px_CARLOCK_THRES2_FIELD 0 -#define STV090x_WIDTH_Px_CARLOCK_THRES2_FIELD 8 - -#define STV090x_Px_CFRICFG(__x) (0xF441 - (__x - 1) * 0x200) -#define STV090x_P1_CFRICFG STV090x_Px_CFRICFG(1) -#define STV090x_P2_CFRICFG STV090x_Px_CFRICFG(2) -#define STV090x_OFFST_Px_NEG_CFRSTEP_FIELD 0 -#define STV090x_WIDTH_Px_NEG_CFRSTEP_FIELD 1 - -#define STV090x_Pn_CFRUPy(__x, __y) (0xF443 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_CFRUP0 STV090x_Pn_CFRUPy(1, 0) -#define STV090x_P1_CFRUP1 STV090x_Pn_CFRUPy(1, 1) -#define STV090x_P2_CFRUP0 STV090x_Pn_CFRUPy(2, 0) -#define STV090x_P2_CFRUP1 STV090x_Pn_CFRUPy(2, 1) -#define STV090x_OFFST_Px_CFR_UP_FIELD 0 -#define STV090x_WIDTH_Px_CFR_UP_FIELD 8 - -#define STV090x_Pn_CFRLOWy(__x, __y) (0xF447 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_CFRLOW0 STV090x_Pn_CFRLOWy(1, 0) -#define STV090x_P1_CFRLOW1 STV090x_Pn_CFRLOWy(1, 1) -#define STV090x_P2_CFRLOW0 STV090x_Pn_CFRLOWy(2, 0) -#define STV090x_P2_CFRLOW1 STV090x_Pn_CFRLOWy(2, 1) -#define STV090x_OFFST_Px_CFR_LOW_FIELD 0 -#define STV090x_WIDTH_Px_CFR_LOW_FIELD 8 - -#define STV090x_Pn_CFRINITy(__x, __y) (0xF449 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_CFRINIT0 STV090x_Pn_CFRINITy(1, 0) -#define STV090x_P1_CFRINIT1 STV090x_Pn_CFRINITy(1, 1) -#define STV090x_P2_CFRINIT0 STV090x_Pn_CFRINITy(2, 0) -#define STV090x_P2_CFRINIT1 STV090x_Pn_CFRINITy(2, 1) -#define STV090x_OFFST_Px_CFR_INIT_FIELD 0 -#define STV090x_WIDTH_Px_CFR_INIT_FIELD 8 - -#define STV090x_Px_CFRINC1(__x) (0xF44A - (__x - 1) * 0x200) -#define STV090x_P1_CFRINC1 STV090x_Px_CFRINC1(1) -#define STV090x_P2_CFRINC1 STV090x_Px_CFRINC1(2) -#define STV090x_OFFST_Px_CFR_INC1_FIELD 0 -#define STV090x_WIDTH_Px_CFR_INC1_FIELD 7 /* check */ - -#define STV090x_Px_CFRINC0(__x) (0xF44B - (__x - 1) * 0x200) -#define STV090x_P1_CFRINC0 STV090x_Px_CFRINC0(1) -#define STV090x_P2_CFRINC0 STV090x_Px_CFRINC0(2) -#define STV090x_OFFST_Px_CFR_INC0_FIELD 4 /* check */ -#define STV090x_WIDTH_Px_CFR_INC0_FIELD 4 - -#define STV090x_Pn_CFRy(__x, __y) (0xF44E - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_CFR0 STV090x_Pn_CFRy(1, 0) -#define STV090x_P1_CFR1 STV090x_Pn_CFRy(1, 1) -#define STV090x_P1_CFR2 STV090x_Pn_CFRy(1, 2) -#define STV090x_P2_CFR0 STV090x_Pn_CFRy(2, 0) -#define STV090x_P2_CFR1 STV090x_Pn_CFRy(2, 1) -#define STV090x_P2_CFR2 STV090x_Pn_CFRy(2, 2) -#define STV090x_OFFST_Px_CAR_FREQ_FIELD 0 -#define STV090x_WIDTH_Px_CAR_FREQ_FIELD 8 - -#define STV090x_Px_LDI(__x) (0xF44F - (__x - 1) * 0x200) -#define STV090x_P1_LDI STV090x_Px_LDI(1) -#define STV090x_P2_LDI STV090x_Px_LDI(2) -#define STV090x_OFFST_Px_LOCK_DET_INTEGR_FIELD 0 -#define STV090x_WIDTH_Px_LOCK_DET_INTEGR_FIELD 8 - -#define STV090x_Px_TMGCFG(__x) (0xF450 - (__x - 1) * 0x200) -#define STV090x_P1_TMGCFG STV090x_Px_TMGCFG(1) -#define STV090x_P2_TMGCFG STV090x_Px_TMGCFG(2) -#define STV090x_OFFST_Px_TMGLOCK_BETA_FIELD 6 -#define STV090x_WIDTH_Px_TMGLOCK_BETA_FIELD 2 -#define STV090x_OFFST_Px_DO_TIMING_FIELD 4 -#define STV090x_WIDTH_Px_DO_TIMING_FIELD 1 -#define STV090x_OFFST_Px_TMG_MINFREQ_FIELD 0 -#define STV090x_WIDTH_Px_TMG_MINFREQ_FIELD 2 - -#define STV090x_Px_RTC(__x) (0xF451 - (__x - 1) * 0x200) -#define STV090x_P1_RTC STV090x_Px_RTC(1) -#define STV090x_P2_RTC STV090x_Px_RTC(2) -#define STV090x_OFFST_Px_TMGALPHA_EXP_FIELD 4 -#define STV090x_WIDTH_Px_TMGALPHA_EXP_FIELD 4 -#define STV090x_OFFST_Px_TMGBETA_EXP_FIELD 0 -#define STV090x_WIDTH_Px_TMGBETA_EXP_FIELD 4 - -#define STV090x_Px_RTCS2(__x) (0xF452 - (__x - 1) * 0x200) -#define STV090x_P1_RTCS2 STV090x_Px_RTCS2(1) -#define STV090x_P2_RTCS2 STV090x_Px_RTCS2(2) -#define STV090x_OFFST_Px_TMGALPHAS2_EXP_FIELD 4 -#define STV090x_WIDTH_Px_TMGALPHAS2_EXP_FIELD 4 -#define STV090x_OFFST_Px_TMGBETAS2_EXP_FIELD 0 -#define STV090x_WIDTH_Px_TMGBETAS2_EXP_FIELD 4 - -#define STV090x_Px_TMGTHRISE(__x) (0xF453 - (__x - 1) * 0x200) -#define STV090x_P1_TMGTHRISE STV090x_Px_TMGTHRISE(1) -#define STV090x_P2_TMGTHRISE STV090x_Px_TMGTHRISE(2) -#define STV090x_OFFST_Px_TMGLOCK_THRISE_FIELD 0 -#define STV090x_WIDTH_Px_TMGLOCK_THRISE_FIELD 8 - -#define STV090x_Px_TMGTHFALL(__x) (0xF454 - (__x - 1) * 0x200) -#define STV090x_P1_TMGTHFALL STV090x_Px_TMGTHFALL(1) -#define STV090x_P2_TMGTHFALL STV090x_Px_TMGTHFALL(2) -#define STV090x_OFFST_Px_TMGLOCK_THFALL_FIELD 0 -#define STV090x_WIDTH_Px_TMGLOCK_THFALL_FIELD 8 - -#define STV090x_Px_SFRUPRATIO(__x) (0xF455 - (__x - 1) * 0x200) -#define STV090x_P1_SFRUPRATIO STV090x_Px_SFRUPRATIO(1) -#define STV090x_P2_SFRUPRATIO STV090x_Px_SFRUPRATIO(2) -#define STV090x_OFFST_Px_SFR_UPRATIO_FIELD 0 -#define STV090x_WIDTH_Px_SFR_UPRATIO_FIELD 8 - -#define STV090x_Px_SFRLOWRATIO(__x) (0xF456 - (__x - 1) * 0x200) -#define STV090x_P1_SFRLOWRATIO STV090x_Px_SFRLOWRATIO(1) -#define STV090x_P2_SFRLOWRATIO STV090x_Px_SFRLOWRATIO(2) -#define STV090x_OFFST_Px_SFR_LOWRATIO_FIELD 0 -#define STV090x_WIDTH_Px_SFR_LOWRATIO_FIELD 8 - -#define STV090x_Px_KREFTMG(__x) (0xF458 - (__x - 1) * 0x200) -#define STV090x_P1_KREFTMG STV090x_Px_KREFTMG(1) -#define STV090x_P2_KREFTMG STV090x_Px_KREFTMG(2) -#define STV090x_OFFST_Px_KREF_TMG_FIELD 0 -#define STV090x_WIDTH_Px_KREF_TMG_FIELD 8 - -#define STV090x_Px_SFRSTEP(__x) (0xF459 - (__x - 1) * 0x200) -#define STV090x_P1_SFRSTEP STV090x_Px_SFRSTEP(1) -#define STV090x_P2_SFRSTEP STV090x_Px_SFRSTEP(2) -#define STV090x_OFFST_Px_SFR_SCANSTEP_FIELD 4 -#define STV090x_WIDTH_Px_SFR_SCANSTEP_FIELD 4 -#define STV090x_OFFST_Px_SFR_CENTERSTEP_FIELD 0 -#define STV090x_WIDTH_Px_SFR_CENTERSTEP_FIELD 4 - -#define STV090x_Px_TMGCFG2(__x) (0xF45A - (__x - 1) * 0x200) -#define STV090x_P1_TMGCFG2 STV090x_Px_TMGCFG2(1) -#define STV090x_P2_TMGCFG2 STV090x_Px_TMGCFG2(2) -#define STV090x_OFFST_Px_SFRRATIO_FINE_FIELD 0 -#define STV090x_WIDTH_Px_SFRRATIO_FINE_FIELD 1 - -#define STV090x_Px_SFRINIT1(__x) (0xF45E - (__x - 1) * 0x200) -#define STV090x_P1_SFRINIT1 STV090x_Px_SFRINIT1(1) -#define STV090x_P2_SFRINIT1 STV090x_Px_SFRINIT1(2) -#define STV090x_OFFST_Px_SFR_INIT1_FIELD 0 -#define STV090x_WIDTH_Px_SFR_INIT1_FIELD 7 - -#define STV090x_Px_SFRINIT0(__x) (0xF45F - (__x - 1) * 0x200) -#define STV090x_P1_SFRINIT0 STV090x_Px_SFRINIT0(1) -#define STV090x_P2_SFRINIT0 STV090x_Px_SFRINIT0(2) -#define STV090x_OFFST_Px_SFR_INIT0_FIELD 0 -#define STV090x_WIDTH_Px_SFR_INIT0_FIELD 8 - -#define STV090x_Px_SFRUP1(__x) (0xF460 - (__x - 1) * 0x200) -#define STV090x_P1_SFRUP1 STV090x_Px_SFRUP1(1) -#define STV090x_P2_SFRUP1 STV090x_Px_SFRUP1(2) -#define STV090x_OFFST_Px_SYMB_FREQ_UP1_FIELD 0 -#define STV090x_WIDTH_Px_SYMB_FREQ_UP1_FIELD 7 - -#define STV090x_Px_SFRUP0(__x) (0xF461 - (__x - 1) * 0x200) -#define STV090x_P1_SFRUP0 STV090x_Px_SFRUP0(1) -#define STV090x_P2_SFRUP0 STV090x_Px_SFRUP0(2) -#define STV090x_OFFST_Px_SYMB_FREQ_UP0_FIELD 0 -#define STV090x_WIDTH_Px_SYMB_FREQ_UP0_FIELD 8 - -#define STV090x_Px_SFRLOW1(__x) (0xF462 - (__x - 1) * 0x200) -#define STV090x_P1_SFRLOW1 STV090x_Px_SFRLOW1(1) -#define STV090x_P2_SFRLOW1 STV090x_Px_SFRLOW1(2) -#define STV090x_OFFST_Px_SYMB_FREQ_LOW1_FIELD 0 -#define STV090x_WIDTH_Px_SYMB_FREQ_LOW1_FIELD 7 - -#define STV090x_Px_SFRLOW0(__x) (0xF463 - (__x - 1) * 0x200) -#define STV090x_P1_SFRLOW0 STV090x_Px_SFRLOW0(1) -#define STV090x_P2_SFRLOW0 STV090x_Px_SFRLOW0(2) -#define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD 0 -#define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD 8 - -#define STV090x_Px_SFRy(__x, __y) (0xF467 - (__x-1) * 0x200 - __y) -#define STV090x_P1_SFR0 STV090x_Px_SFRy(1, 0) -#define STV090x_P1_SFR1 STV090x_Px_SFRy(1, 1) -#define STV090x_P1_SFR2 STV090x_Px_SFRy(1, 2) -#define STV090x_P1_SFR3 STV090x_Px_SFRy(1, 3) -#define STV090x_P2_SFR0 STV090x_Px_SFRy(2, 0) -#define STV090x_P2_SFR1 STV090x_Px_SFRy(2, 1) -#define STV090x_P2_SFR2 STV090x_Px_SFRy(2, 2) -#define STV090x_P2_SFR3 STV090x_Px_SFRy(2, 3) -#define STV090x_OFFST_Px_SYMB_FREQ_FIELD 0 -#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD 8 - -#define STV090x_Px_TMGREG2(__x) (0xF468 - (__x - 1) * 0x200) -#define STV090x_P1_TMGREG2 STV090x_Px_TMGREG2(1) -#define STV090x_P2_TMGREG2 STV090x_Px_TMGREG2(2) -#define STV090x_OFFST_Px_TMGREG_FIELD 0 -#define STV090x_WIDTH_Px_TMGREG_FIELD 8 - -#define STV090x_Px_TMGREG1(__x) (0xF469 - (__x - 1) * 0x200) -#define STV090x_P1_TMGREG1 STV090x_Px_TMGREG1(1) -#define STV090x_P2_TMGREG1 STV090x_Px_TMGREG1(2) -#define STV090x_OFFST_Px_TMGREG_FIELD 0 -#define STV090x_WIDTH_Px_TMGREG_FIELD 8 - -#define STV090x_Px_TMGREG0(__x) (0xF46A - (__x - 1) * 0x200) -#define STV090x_P1_TMGREG0 STV090x_Px_TMGREG0(1) -#define STV090x_P2_TMGREG0 STV090x_Px_TMGREG0(2) -#define STV090x_OFFST_Px_TMGREG_FIELD 0 -#define STV090x_WIDTH_Px_TMGREG_FIELD 8 - -#define STV090x_Px_TMGLOCKy(__x, __y) (0xF46C - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_TMGLOCK0 STV090x_Px_TMGLOCKy(1, 0) -#define STV090x_P1_TMGLOCK1 STV090x_Px_TMGLOCKy(1, 1) -#define STV090x_P2_TMGLOCK0 STV090x_Px_TMGLOCKy(2, 0) -#define STV090x_P2_TMGLOCK1 STV090x_Px_TMGLOCKy(2, 1) -#define STV090x_OFFST_Px_TMGLOCK_LEVEL_FIELD 0 -#define STV090x_WIDTH_Px_TMGLOCK_LEVEL_FIELD 8 - -#define STV090x_Px_TMGOBS(__x) (0xF46D - (__x - 1) * 0x200) -#define STV090x_P1_TMGOBS STV090x_Px_TMGOBS(1) -#define STV090x_P2_TMGOBS STV090x_Px_TMGOBS(2) -#define STV090x_OFFST_Px_ROLLOFF_STATUS_FIELD 6 -#define STV090x_WIDTH_Px_ROLLOFF_STATUS_FIELD 2 - -#define STV090x_Px_EQUALCFG(__x) (0xF46F - (__x - 1) * 0x200) -#define STV090x_P1_EQUALCFG STV090x_Px_EQUALCFG(1) -#define STV090x_P2_EQUALCFG STV090x_Px_EQUALCFG(2) -#define STV090x_OFFST_Px_EQUAL_ON_FIELD 6 -#define STV090x_WIDTH_Px_EQUAL_ON_FIELD 1 -#define STV090x_OFFST_Px_MU_EQUALDFE_FIELD 0 -#define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD 3 - -#define STV090x_Px_EQUAIy(__x, __y) (0xf470 - (__x-1) * 0x200 + 2 * (__y-1)) -#define STV090x_P1_EQUAI1 STV090x_Px_EQUAIy(1, 1) -#define STV090x_P1_EQUAI2 STV090x_Px_EQUAIy(1, 2) -#define STV090x_P1_EQUAI3 STV090x_Px_EQUAIy(1, 3) -#define STV090x_P1_EQUAI4 STV090x_Px_EQUAIy(1, 4) -#define STV090x_P1_EQUAI5 STV090x_Px_EQUAIy(1, 5) -#define STV090x_P1_EQUAI6 STV090x_Px_EQUAIy(1, 6) -#define STV090x_P1_EQUAI7 STV090x_Px_EQUAIy(1, 7) -#define STV090x_P1_EQUAI8 STV090x_Px_EQUAIy(1, 8) - -#define STV090x_P2_EQUAI1 STV090x_Px_EQUAIy(2, 1) -#define STV090x_P2_EQUAI2 STV090x_Px_EQUAIy(2, 2) -#define STV090x_P2_EQUAI3 STV090x_Px_EQUAIy(2, 3) -#define STV090x_P2_EQUAI4 STV090x_Px_EQUAIy(2, 4) -#define STV090x_P2_EQUAI5 STV090x_Px_EQUAIy(2, 5) -#define STV090x_P2_EQUAI6 STV090x_Px_EQUAIy(2, 6) -#define STV090x_P2_EQUAI7 STV090x_Px_EQUAIy(2, 7) -#define STV090x_P2_EQUAI8 STV090x_Px_EQUAIy(2, 8) -#define STV090x_OFFST_Px_EQUA_ACCIy_FIELD 0 -#define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD 8 - -#define STV090x_Px_EQUAQy(__x, __y) (0xf471 - (__x-1) * 0x200 + 2 * (__y-1)) -#define STV090x_P1_EQUAQ1 STV090x_Px_EQUAQy(1, 1) -#define STV090x_P1_EQUAQ2 STV090x_Px_EQUAQy(1, 2) -#define STV090x_P1_EQUAQ3 STV090x_Px_EQUAQy(1, 3) -#define STV090x_P1_EQUAQ4 STV090x_Px_EQUAQy(1, 4) -#define STV090x_P1_EQUAQ5 STV090x_Px_EQUAQy(1, 5) -#define STV090x_P1_EQUAQ6 STV090x_Px_EQUAQy(1, 6) -#define STV090x_P1_EQUAQ7 STV090x_Px_EQUAQy(1, 7) -#define STV090x_P1_EQUAQ8 STV090x_Px_EQUAQy(1, 8) - -#define STV090x_P2_EQUAQ1 STV090x_Px_EQUAQy(2, 1) -#define STV090x_P2_EQUAQ2 STV090x_Px_EQUAQy(2, 2) -#define STV090x_P2_EQUAQ3 STV090x_Px_EQUAQy(2, 3) -#define STV090x_P2_EQUAQ4 STV090x_Px_EQUAQy(2, 4) -#define STV090x_P2_EQUAQ5 STV090x_Px_EQUAQy(2, 5) -#define STV090x_P2_EQUAQ6 STV090x_Px_EQUAQy(2, 6) -#define STV090x_P2_EQUAQ7 STV090x_Px_EQUAQy(2, 7) -#define STV090x_P2_EQUAQ8 STV090x_Px_EQUAQy(2, 8) -#define STV090x_OFFST_Px_EQUA_ACCQy_FIELD 0 -#define STV090x_WIDTH_Px_EQUA_ACCQy_FIELD 8 - -#define STV090x_Px_NNOSDATATy(__x, __y) (0xf481 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_NNOSDATAT0 STV090x_Px_NNOSDATATy(1, 0) -#define STV090x_P1_NNOSDATAT1 STV090x_Px_NNOSDATATy(1, 1) -#define STV090x_P2_NNOSDATAT0 STV090x_Px_NNOSDATATy(2, 0) -#define STV090x_P2_NNOSDATAT1 STV090x_Px_NNOSDATATy(2, 1) -#define STV090x_OFFST_Px_NOSDATAT_NORMED_FIELD 0 -#define STV090x_WIDTH_Px_NOSDATAT_NORMED_FIELD 8 - -#define STV090x_Px_NNOSDATAy(__x, __y) (0xf483 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_NNOSDATA0 STV090x_Px_NNOSDATAy(1, 0) -#define STV090x_P1_NNOSDATA1 STV090x_Px_NNOSDATAy(1, 1) -#define STV090x_P2_NNOSDATA0 STV090x_Px_NNOSDATAy(2, 0) -#define STV090x_P2_NNOSDATA1 STV090x_Px_NNOSDATAy(2, 1) -#define STV090x_OFFST_Px_NOSDATA_NORMED_FIELD 0 -#define STV090x_WIDTH_Px_NOSDATA_NORMED_FIELD 8 - -#define STV090x_Px_NNOSPLHTy(__x, __y) (0xf485 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_NNOSPLHT0 STV090x_Px_NNOSPLHTy(1, 0) -#define STV090x_P1_NNOSPLHT1 STV090x_Px_NNOSPLHTy(1, 1) -#define STV090x_P2_NNOSPLHT0 STV090x_Px_NNOSPLHTy(2, 0) -#define STV090x_P2_NNOSPLHT1 STV090x_Px_NNOSPLHTy(2, 1) -#define STV090x_OFFST_Px_NOSPLHT_NORMED_FIELD 0 -#define STV090x_WIDTH_Px_NOSPLHT_NORMED_FIELD 8 - -#define STV090x_Px_NNOSPLHy(__x, __y) (0xf487 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_NNOSPLH0 STV090x_Px_NNOSPLHy(1, 0) -#define STV090x_P1_NNOSPLH1 STV090x_Px_NNOSPLHy(1, 1) -#define STV090x_P2_NNOSPLH0 STV090x_Px_NNOSPLHy(2, 0) -#define STV090x_P2_NNOSPLH1 STV090x_Px_NNOSPLHy(2, 1) -#define STV090x_OFFST_Px_NOSPLH_NORMED_FIELD 0 -#define STV090x_WIDTH_Px_NOSPLH_NORMED_FIELD 8 - -#define STV090x_Px_NOSDATATy(__x, __y) (0xf489 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_NOSDATAT0 STV090x_Px_NOSDATATy(1, 0) -#define STV090x_P1_NOSDATAT1 STV090x_Px_NOSDATATy(1, 1) -#define STV090x_P2_NOSDATAT0 STV090x_Px_NOSDATATy(2, 0) -#define STV090x_P2_NOSDATAT1 STV090x_Px_NOSDATATy(2, 1) -#define STV090x_OFFST_Px_NOSDATAT_UNNORMED_FIELD 0 -#define STV090x_WIDTH_Px_NOSDATAT_UNNORMED_FIELD 8 - -#define STV090x_Px_NOSDATAy(__x, __y) (0xf48b - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_NOSDATA0 STV090x_Px_NOSDATAy(1, 0) -#define STV090x_P1_NOSDATA1 STV090x_Px_NOSDATAy(1, 1) -#define STV090x_P2_NOSDATA0 STV090x_Px_NOSDATAy(2, 0) -#define STV090x_P2_NOSDATA1 STV090x_Px_NOSDATAy(2, 1) -#define STV090x_OFFST_Px_NOSDATA_UNNORMED_FIELD 0 -#define STV090x_WIDTH_Px_NOSDATA_UNNORMED_FIELD 8 - -#define STV090x_Px_NOSPLHTy(__x, __y) (0xf48d - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_NOSPLHT0 STV090x_Px_NOSPLHTy(1, 0) -#define STV090x_P1_NOSPLHT1 STV090x_Px_NOSPLHTy(1, 1) -#define STV090x_P2_NOSPLHT0 STV090x_Px_NOSPLHTy(2, 0) -#define STV090x_P2_NOSPLHT1 STV090x_Px_NOSPLHTy(2, 1) -#define STV090x_OFFST_Px_NOSPLHT_UNNORMED_FIELD 0 -#define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD 8 - -#define STV090x_Px_NOSPLHy(__x, __y) (0xf48f - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_NOSPLH0 STV090x_Px_NOSPLHy(1, 0) -#define STV090x_P1_NOSPLH1 STV090x_Px_NOSPLHy(1, 1) -#define STV090x_P2_NOSPLH0 STV090x_Px_NOSPLHy(2, 0) -#define STV090x_P2_NOSPLH1 STV090x_Px_NOSPLHy(2, 1) -#define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD 0 -#define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD 8 - -#define STV090x_Px_CAR2CFG(__x) (0xf490 - (__x - 1) * 0x200) -#define STV090x_P1_CAR2CFG STV090x_Px_CAR2CFG(1) -#define STV090x_P2_CAR2CFG STV090x_Px_CAR2CFG(2) -#define STV090x_OFFST_Px_PN4_SELECT_FIELD 6 -#define STV090x_WIDTH_Px_PN4_SELECT_FIELD 1 -#define STV090x_OFFST_Px_CFR2_STOPDVBS1_FIELD 5 -#define STV090x_WIDTH_Px_CFR2_STOPDVBS1_FIELD 1 -#define STV090x_OFFST_Px_ROTA2ON_FIELD 2 -#define STV090x_WIDTH_Px_ROTA2ON_FIELD 1 -#define STV090x_OFFST_Px_PH_DET_ALGO2_FIELD 0 -#define STV090x_WIDTH_Px_PH_DET_ALGO2_FIELD 2 - -#define STV090x_Px_ACLC2(__x) (0xf491 - (__x - 1) * 0x200) -#define STV090x_P1_ACLC2 STV090x_Px_ACLC2(1) -#define STV090x_P2_ACLC2 STV090x_Px_ACLC2(2) -#define STV090x_OFFST_Px_CAR2_ALPHA_MANT_FIELD 4 -#define STV090x_WIDTH_Px_CAR2_ALPHA_MANT_FIELD 2 -#define STV090x_OFFST_Px_CAR2_ALPHA_EXP_FIELD 0 -#define STV090x_WIDTH_Px_CAR2_ALPHA_EXP_FIELD 4 - -#define STV090x_Px_BCLC2(__x) (0xf492 - (__x - 1) * 0x200) -#define STV090x_P1_BCLC2 STV090x_Px_BCLC2(1) -#define STV090x_P2_BCLC2 STV090x_Px_BCLC2(2) -#define STV090x_OFFST_Px_CAR2_BETA_MANT_FIELD 4 -#define STV090x_WIDTH_Px_CAR2_BETA_MANT_FIELD 2 -#define STV090x_OFFST_Px_CAR2_BETA_EXP_FIELD 0 -#define STV090x_WIDTH_Px_CAR2_BETA_EXP_FIELD 4 - -#define STV090x_Px_ACLC2S2Q(__x) (0xf497 - (__x - 1) * 0x200) -#define STV090x_P1_ACLC2S2Q STV090x_Px_ACLC2S2Q(1) -#define STV090x_P2_ACLC2S2Q STV090x_Px_ACLC2S2Q(2) -#define STV090x_OFFST_Px_ENAB_SPSKSYMB_FIELD 7 -#define STV090x_WIDTH_Px_ENAB_SPSKSYMB_FIELD 1 -#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_M_FIELD 4 -#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_M_FIELD 2 -#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_E_FIELD 0 -#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_E_FIELD 4 - -#define STV090x_Px_ACLC2S28(__x) (0xf498 - (__x - 1) * 0x200) -#define STV090x_P1_ACLC2S28 STV090x_Px_ACLC2S28(1) -#define STV090x_P2_ACLC2S28 STV090x_Px_ACLC2S28(2) -#define STV090x_OFFST_Px_CAR2S2_8_ALPH_M_FIELD 4 -#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_M_FIELD 2 -#define STV090x_OFFST_Px_CAR2S2_8_ALPH_E_FIELD 0 -#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_E_FIELD 4 - -#define STV090x_Px_ACLC2S216A(__x) (0xf499 - (__x - 1) * 0x200) -#define STV090x_P1_ACLC2S216A STV090x_Px_ACLC2S216A(1) -#define STV090x_P2_ACLC2S216A STV090x_Px_ACLC2S216A(2) -#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_M_FIELD 4 -#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_M_FIELD 2 -#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD 0 -#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD 4 - -#define STV090x_Px_ACLC2S232A(__x) (0xf49A - (__x - 1) * 0x200) -#define STV090x_P1_ACLC2S232A STV090x_Px_ACLC2S232A(1) -#define STV090x_P2_ACLC2S232A STV090x_Px_ACLC2S232A(2) -#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD 4 -#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_M_FIELD 2 -#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_E_FIELD 0 -#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_E_FIELD 4 - -#define STV090x_Px_BCLC2S2Q(__x) (0xf49c - (__x - 1) * 0x200) -#define STV090x_P1_BCLC2S2Q STV090x_Px_BCLC2S2Q(1) -#define STV090x_P2_BCLC2S2Q STV090x_Px_BCLC2S2Q(2) -#define STV090x_OFFST_Px_CAR2S2_Q_BETA_M_FIELD 4 -#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_M_FIELD 2 -#define STV090x_OFFST_Px_CAR2S2_Q_BETA_E_FIELD 0 -#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_E_FIELD 4 - -#define STV090x_Px_BCLC2S28(__x) (0xf49d - (__x - 1) * 0x200) -#define STV090x_P1_BCLC2S28 STV090x_Px_BCLC2S28(1) -#define STV090x_P2_BCLC2S28 STV090x_Px_BCLC2S28(2) -#define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD 4 -#define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD 2 -#define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD 0 -#define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD 4 - -#define STV090x_Px_BCLC2S216A(__x) (0xf49e - (__x - 1) * 0x200) -#define STV090x_P1_BCLC2S216A STV090x_Px_BCLC2S216A(1) -#define STV090x_P2_BCLC2S216A STV090x_Px_BCLC2S216A(2) -#define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD 4 -#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD 2 -#define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD 0 -#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD 4 - -#define STV090x_Px_BCLC2S232A(__x) (0xf49f - (__x - 1) * 0x200) -#define STV090x_P1_BCLC2S232A STV090x_Px_BCLC2S232A(1) -#define STV090x_P2_BCLC2S232A STV090x_Px_BCLC2S232A(2) -#define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD 4 -#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD 2 -#define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD 0 -#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_E_FIELD 4 - -#define STV090x_Px_PLROOT2(__x) (0xf4ac - (__x - 1) * 0x200) -#define STV090x_P1_PLROOT2 STV090x_Px_PLROOT2(1) -#define STV090x_P2_PLROOT2 STV090x_Px_PLROOT2(2) -#define STV090x_OFFST_Px_PLSCRAMB_MODE_FIELD 2 -#define STV090x_WIDTH_Px_PLSCRAMB_MODE_FIELD 2 -#define STV090x_OFFST_Px_PLSCRAMB_ROOT_FIELD 0 -#define STV090x_WIDTH_Px_PLSCRAMB_ROOT_FIELD 2 - -#define STV090x_Px_PLROOT1(__x) (0xf4ad - (__x - 1) * 0x200) -#define STV090x_P1_PLROOT1 STV090x_Px_PLROOT1(1) -#define STV090x_P2_PLROOT1 STV090x_Px_PLROOT1(2) -#define STV090x_OFFST_Px_PLSCRAMB_ROOT1_FIELD 0 -#define STV090x_WIDTH_Px_PLSCRAMB_ROOT1_FIELD 8 - -#define STV090x_Px_PLROOT0(__x) (0xf4ae - (__x - 1) * 0x200) -#define STV090x_P1_PLROOT0 STV090x_Px_PLROOT0(1) -#define STV090x_P2_PLROOT0 STV090x_Px_PLROOT0(2) -#define STV090x_OFFST_Px_PLSCRAMB_ROOT0_FIELD 0 -#define STV090x_WIDTH_Px_PLSCRAMB_ROOT0_FIELD 8 - -#define STV090x_Px_MODCODLST0(__x) (0xf4b0 - (__x - 1) * 0x200) /* check */ -#define STV090x_P1_MODCODLST0 STV090x_Px_MODCODLST0(1) -#define STV090x_P2_MODCODLST0 STV090x_Px_MODCODLST0(2) - -#define STV090x_Px_MODCODLST1(__x) (0xf4b1 - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLST1 STV090x_Px_MODCODLST1(1) -#define STV090x_P2_MODCODLST1 STV090x_Px_MODCODLST1(2) -#define STV090x_OFFST_Px_DIS_MODCOD29_FIELD 4 -#define STV090x_WIDTH_Px_DIS_MODCOD29_FIELD 4 -#define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD 0 -#define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD 4 - -#define STV090x_Px_MODCODLST2(__x) (0xf4b2 - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLST2 STV090x_Px_MODCODLST2(1) -#define STV090x_P2_MODCODLST2 STV090x_Px_MODCODLST2(2) -#define STV090x_OFFST_Px_DIS_32PSK_8_9_FIELD 4 -#define STV090x_WIDTH_Px_DIS_32PSK_8_9_FIELD 4 -#define STV090x_OFFST_Px_DIS_32PSK_5_6_FIELD 0 -#define STV090x_WIDTH_Px_DIS_32PSK_5_6_FIELD 4 - -#define STV090x_Px_MODCODLST3(__x) (0xf4b3 - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLST3 STV090x_Px_MODCODLST3(1) -#define STV090x_P2_MODCODLST3 STV090x_Px_MODCODLST3(2) -#define STV090x_OFFST_Px_DIS_32PSK_4_5_FIELD 4 -#define STV090x_WIDTH_Px_DIS_32PSK_4_5_FIELD 4 -#define STV090x_OFFST_Px_DIS_32PSK_3_4_FIELD 0 -#define STV090x_WIDTH_Px_DIS_32PSK_3_4_FIELD 4 - -#define STV090x_Px_MODCODLST4(__x) (0xf4b4 - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLST4 STV090x_Px_MODCODLST4(1) -#define STV090x_P2_MODCODLST4 STV090x_Px_MODCODLST4(2) -#define STV090x_OFFST_Px_DIS_16PSK_9_10_FIELD 4 -#define STV090x_WIDTH_Px_DIS_16PSK_9_10_FIELD 4 -#define STV090x_OFFST_Px_DIS_16PSK_8_9_FIELD 0 -#define STV090x_WIDTH_Px_DIS_16PSK_8_9_FIELD 4 - -#define STV090x_Px_MODCODLST5(__x) (0xf4b5 - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLST5 STV090x_Px_MODCODLST5(1) -#define STV090x_P2_MODCODLST5 STV090x_Px_MODCODLST5(2) -#define STV090x_OFFST_Px_DIS_16PSK_5_6_FIELD 4 -#define STV090x_WIDTH_Px_DIS_16PSK_5_6_FIELD 4 -#define STV090x_OFFST_Px_DIS_16PSK_4_5_FIELD 0 -#define STV090x_WIDTH_Px_DIS_16PSK_4_5_FIELD 4 - -#define STV090x_Px_MODCODLST6(__x) (0xf4b6 - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLST6 STV090x_Px_MODCODLST6(1) -#define STV090x_P2_MODCODLST6 STV090x_Px_MODCODLST6(2) -#define STV090x_OFFST_Px_DIS_16PSK_3_4_FIELD 4 -#define STV090x_WIDTH_Px_DIS_16PSK_3_4_FIELD 4 -#define STV090x_OFFST_Px_DIS_16PSK_2_3_FIELD 0 -#define STV090x_WIDTH_Px_DIS_16PSK_2_3_FIELD 4 - -#define STV090x_Px_MODCODLST7(__x) (0xf4b7 - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLST7 STV090x_Px_MODCODLST7(1) -#define STV090x_P2_MODCODLST7 STV090x_Px_MODCODLST7(2) -#define STV090x_OFFST_Px_DIS_8P_9_10_FIELD 4 -#define STV090x_WIDTH_Px_DIS_8P_9_10_FIELD 4 -#define STV090x_OFFST_Px_DIS_8P_8_9_FIELD 0 -#define STV090x_WIDTH_Px_DIS_8P_8_9_FIELD 4 - -#define STV090x_Px_MODCODLST8(__x) (0xf4b8 - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLST8 STV090x_Px_MODCODLST8(1) -#define STV090x_P2_MODCODLST8 STV090x_Px_MODCODLST8(2) -#define STV090x_OFFST_Px_DIS_8P_5_6_FIELD 4 -#define STV090x_WIDTH_Px_DIS_8P_5_6_FIELD 4 -#define STV090x_OFFST_Px_DIS_8P_3_4_FIELD 0 -#define STV090x_WIDTH_Px_DIS_8P_3_4_FIELD 4 - -#define STV090x_Px_MODCODLST9(__x) (0xf4b9 - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLST9 STV090x_Px_MODCODLST9(1) -#define STV090x_P2_MODCODLST9 STV090x_Px_MODCODLST9(2) -#define STV090x_OFFST_Px_DIS_8P_2_3_FIELD 4 -#define STV090x_WIDTH_Px_DIS_8P_2_3_FIELD 4 -#define STV090x_OFFST_Px_DIS_8P_3_5_FIELD 0 -#define STV090x_WIDTH_Px_DIS_8P_3_5_FIELD 4 - -#define STV090x_Px_MODCODLSTA(__x) (0xf4ba - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLSTA STV090x_Px_MODCODLSTA(1) -#define STV090x_P2_MODCODLSTA STV090x_Px_MODCODLSTA(2) -#define STV090x_OFFST_Px_DIS_QP_9_10_FIELD 4 -#define STV090x_WIDTH_Px_DIS_QP_9_10_FIELD 4 -#define STV090x_OFFST_Px_DIS_QP_8_9_FIELD 0 -#define STV090x_WIDTH_Px_DIS_QP_8_9_FIELD 4 - -#define STV090x_Px_MODCODLSTB(__x) (0xf4bb - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLSTB STV090x_Px_MODCODLSTB(1) -#define STV090x_P2_MODCODLSTB STV090x_Px_MODCODLSTB(2) -#define STV090x_OFFST_Px_DIS_QP_5_6_FIELD 4 -#define STV090x_WIDTH_Px_DIS_QP_5_6_FIELD 4 -#define STV090x_OFFST_Px_DIS_QP_4_5_FIELD 0 -#define STV090x_WIDTH_Px_DIS_QP_4_5_FIELD 4 - -#define STV090x_Px_MODCODLSTC(__x) (0xf4bc - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLSTC STV090x_Px_MODCODLSTC(1) -#define STV090x_P2_MODCODLSTC STV090x_Px_MODCODLSTC(2) -#define STV090x_OFFST_Px_DIS_QP_3_4_FIELD 4 -#define STV090x_WIDTH_Px_DIS_QP_3_4_FIELD 4 -#define STV090x_OFFST_Px_DIS_QP_2_3_FIELD 0 -#define STV090x_WIDTH_Px_DIS_QP_2_3_FIELD 4 - -#define STV090x_Px_MODCODLSTD(__x) (0xf4bd - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLSTD STV090x_Px_MODCODLSTD(1) -#define STV090x_P2_MODCODLSTD STV090x_Px_MODCODLSTD(2) -#define STV090x_OFFST_Px_DIS_QP_3_5_FIELD 4 -#define STV090x_WIDTH_Px_DIS_QP_3_5_FIELD 4 -#define STV090x_OFFST_Px_DIS_QP_1_2_FIELD 0 -#define STV090x_WIDTH_Px_DIS_QP_1_2_FIELD 4 - -#define STV090x_Px_MODCODLSTE(__x) (0xf4be - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLSTE STV090x_Px_MODCODLSTE(1) -#define STV090x_P2_MODCODLSTE STV090x_Px_MODCODLSTE(2) -#define STV090x_OFFST_Px_DIS_QP_2_5_FIELD 4 -#define STV090x_WIDTH_Px_DIS_QP_2_5_FIELD 4 -#define STV090x_OFFST_Px_DIS_QP_1_3_FIELD 0 -#define STV090x_WIDTH_Px_DIS_QP_1_3_FIELD 4 - -#define STV090x_Px_MODCODLSTF(__x) (0xf4bf - (__x - 1) * 0x200) -#define STV090x_P1_MODCODLSTF STV090x_Px_MODCODLSTF(1) -#define STV090x_P2_MODCODLSTF STV090x_Px_MODCODLSTF(2) -#define STV090x_OFFST_Px_DIS_QP_1_4_FIELD 4 -#define STV090x_WIDTH_Px_DIS_QP_1_4_FIELD 4 - -#define STV090x_Px_GAUSSR0(__x) (0xf4c0 - (__x - 1) * 0x200) -#define STV090x_P1_GAUSSR0 STV090x_Px_GAUSSR0(1) -#define STV090x_P2_GAUSSR0 STV090x_Px_GAUSSR0(2) -#define STV090x_OFFST_Px_EN_CCIMODE_FIELD 7 -#define STV090x_WIDTH_Px_EN_CCIMODE_FIELD 1 -#define STV090x_OFFST_Px_R0_GAUSSIEN_FIELD 0 -#define STV090x_WIDTH_Px_R0_GAUSSIEN_FIELD 7 - -#define STV090x_Px_CCIR0(__x) (0xf4c1 - (__x - 1) * 0x200) -#define STV090x_P1_CCIR0 STV090x_Px_CCIR0(1) -#define STV090x_P2_CCIR0 STV090x_Px_CCIR0(2) -#define STV090x_OFFST_Px_CCIDETECT_PLH_FIELD 7 -#define STV090x_WIDTH_Px_CCIDETECT_PLH_FIELD 1 -#define STV090x_OFFST_Px_R0_CCI_FIELD 0 -#define STV090x_WIDTH_Px_R0_CCI_FIELD 7 - -#define STV090x_Px_CCIQUANT(__x) (0xf4c2 - (__x - 1) * 0x200) -#define STV090x_P1_CCIQUANT STV090x_Px_CCIQUANT(1) -#define STV090x_P2_CCIQUANT STV090x_Px_CCIQUANT(2) -#define STV090x_OFFST_Px_CCI_BETA_FIELD 5 -#define STV090x_WIDTH_Px_CCI_BETA_FIELD 3 -#define STV090x_OFFST_Px_CCI_QUANT_FIELD 0 -#define STV090x_WIDTH_Px_CCI_QUANT_FIELD 5 - -#define STV090x_Px_CCITHRESH(__x) (0xf4c3 - (__x - 1) * 0x200) -#define STV090x_P1_CCITHRESH STV090x_Px_CCITHRESH(1) -#define STV090x_P2_CCITHRESH STV090x_Px_CCITHRESH(2) -#define STV090x_OFFST_Px_CCI_THRESHOLD_FIELD 0 -#define STV090x_WIDTH_Px_CCI_THRESHOLD_FIELD 8 - -#define STV090x_Px_CCIACC(__x) (0xf4c4 - (__x - 1) * 0x200) -#define STV090x_P1_CCIACC STV090x_Px_CCIACC(1) -#define STV090x_P2_CCIACC STV090x_Px_CCIACC(2) -#define STV090x_OFFST_Px_CCI_VALUE_FIELD 0 -#define STV090x_WIDTH_Px_CCI_VALUE_FIELD 8 - -#define STV090x_Px_DMDRESCFG(__x) (0xF4C6 - (__x - 1) * 0x200) -#define STV090x_P1_DMDRESCFG STV090x_Px_DMDRESCFG(1) -#define STV090x_P2_DMDRESCFG STV090x_Px_DMDRESCFG(2) -#define STV090x_OFFST_Px_DMDRES_RESET_FIELD 7 -#define STV090x_WIDTH_Px_DMDRES_RESET_FIELD 1 - -#define STV090x_Px_DMDRESADR(__x) (0xF4C7 - (__x - 1) * 0x200) -#define STV090x_P1_DMDRESADR STV090x_Px_DMDRESADR(1) -#define STV090x_P2_DMDRESADR STV090x_Px_DMDRESADR(2) -#define STV090x_OFFST_Px_DMDRES_RESNBR_FIELD 0 -#define STV090x_WIDTH_Px_DMDRES_RESNBR_FIELD 4 - -#define STV090x_Px_DMDRESDATAy(__x, __y) (0xF4C8 - (__x - 1) * 0x200 + (7 - __y)) -#define STV090x_P1_DMDRESDATA0 STV090x_Px_DMDRESDATAy(1, 0) -#define STV090x_P1_DMDRESDATA1 STV090x_Px_DMDRESDATAy(1, 1) -#define STV090x_P1_DMDRESDATA2 STV090x_Px_DMDRESDATAy(1, 2) -#define STV090x_P1_DMDRESDATA3 STV090x_Px_DMDRESDATAy(1, 3) -#define STV090x_P1_DMDRESDATA4 STV090x_Px_DMDRESDATAy(1, 4) -#define STV090x_P1_DMDRESDATA5 STV090x_Px_DMDRESDATAy(1, 5) -#define STV090x_P1_DMDRESDATA6 STV090x_Px_DMDRESDATAy(1, 6) -#define STV090x_P1_DMDRESDATA7 STV090x_Px_DMDRESDATAy(1, 7) -#define STV090x_P2_DMDRESDATA0 STV090x_Px_DMDRESDATAy(2, 0) -#define STV090x_P2_DMDRESDATA1 STV090x_Px_DMDRESDATAy(2, 1) -#define STV090x_P2_DMDRESDATA2 STV090x_Px_DMDRESDATAy(2, 2) -#define STV090x_P2_DMDRESDATA3 STV090x_Px_DMDRESDATAy(2, 3) -#define STV090x_P2_DMDRESDATA4 STV090x_Px_DMDRESDATAy(2, 4) -#define STV090x_P2_DMDRESDATA5 STV090x_Px_DMDRESDATAy(2, 5) -#define STV090x_P2_DMDRESDATA6 STV090x_Px_DMDRESDATAy(2, 6) -#define STV090x_P2_DMDRESDATA7 STV090x_Px_DMDRESDATAy(2, 7) -#define STV090x_OFFST_Px_DMDRES_DATA_FIELD 0 -#define STV090x_WIDTH_Px_DMDRES_DATA_FIELD 8 - -#define STV090x_Px_FFEIy(__x, __y) (0xf4d0 - (__x - 1) * 0x200 + 0x2 * (__y - 1)) -#define STV090x_P1_FFEI1 STV090x_Px_FFEIy(1, 1) -#define STV090x_P1_FFEI2 STV090x_Px_FFEIy(1, 2) -#define STV090x_P1_FFEI3 STV090x_Px_FFEIy(1, 3) -#define STV090x_P1_FFEI4 STV090x_Px_FFEIy(1, 4) -#define STV090x_P2_FFEI1 STV090x_Px_FFEIy(2, 1) -#define STV090x_P2_FFEI2 STV090x_Px_FFEIy(2, 2) -#define STV090x_P2_FFEI3 STV090x_Px_FFEIy(2, 3) -#define STV090x_P2_FFEI4 STV090x_Px_FFEIy(2, 4) -#define STV090x_OFFST_Px_FFE_ACCIy_FIELD 0 -#define STV090x_WIDTH_Px_FFE_ACCIy_FIELD 8 - -#define STV090x_Px_FFEQy(__x, __y) (0xf4d1 - (__x - 1) * 0x200 + 0x2 * (__y - 1)) -#define STV090x_P1_FFEQ1 STV090x_Px_FFEQy(1, 1) -#define STV090x_P1_FFEQ2 STV090x_Px_FFEQy(1, 2) -#define STV090x_P1_FFEQ3 STV090x_Px_FFEQy(1, 3) -#define STV090x_P1_FFEQ4 STV090x_Px_FFEQy(1, 4) -#define STV090x_P2_FFEQ1 STV090x_Px_FFEQy(2, 1) -#define STV090x_P2_FFEQ2 STV090x_Px_FFEQy(2, 2) -#define STV090x_P2_FFEQ3 STV090x_Px_FFEQy(2, 3) -#define STV090x_P2_FFEQ4 STV090x_Px_FFEQy(2, 4) -#define STV090x_OFFST_Px_FFE_ACCQy_FIELD 0 -#define STV090x_WIDTH_Px_FFE_ACCQy_FIELD 8 - -#define STV090x_Px_FFECFG(__x) (0xf4d8 - (__x - 1) * 0x200) -#define STV090x_P1_FFECFG STV090x_Px_FFECFG(1) -#define STV090x_P2_FFECFG STV090x_Px_FFECFG(2) -#define STV090x_OFFST_Px_EQUALFFE_ON_FIELD 6 -#define STV090x_WIDTH_Px_EQUALFFE_ON_FIELD 1 - -#define STV090x_Px_SMAPCOEF7(__x) (0xf500 - (__x - 1) * 0x200) -#define STV090x_P1_SMAPCOEF7 STV090x_Px_SMAPCOEF7(1) -#define STV090x_P2_SMAPCOEF7 STV090x_Px_SMAPCOEF7(2) -#define STV090x_OFFST_Px_DIS_QSCALE_FIELD 7 -#define STV090x_WIDTH_Px_DIS_QSCALE_FIELD 1 -#define STV090x_OFFST_Px_SMAPCOEF_Q_LLR12_FIELD 0 -#define STV090x_WIDTH_Px_SMAPCOEF_Q_LLR12_FIELD 7 - -#define STV090x_Px_SMAPCOEF6(__x) (0xf501 - (__x - 1) * 0x200) -#define STV090x_P1_SMAPCOEF6 STV090x_Px_SMAPCOEF6(1) -#define STV090x_P2_SMAPCOEF6 STV090x_Px_SMAPCOEF6(2) -#define STV090x_OFFST_Px_ADJ_8PSKLLR1_FIELD 2 -#define STV090x_WIDTH_Px_ADJ_8PSKLLR1_FIELD 1 -#define STV090x_OFFST_Px_OLD_8PSKLLR1_FIELD 1 -#define STV090x_WIDTH_Px_OLD_8PSKLLR1_FIELD 1 -#define STV090x_OFFST_Px_DIS_AB8PSK_FIELD 0 -#define STV090x_WIDTH_Px_DIS_AB8PSK_FIELD 1 - -#define STV090x_Px_SMAPCOEF5(__x) (0xf502 - (__x - 1) * 0x200) -#define STV090x_P1_SMAPCOEF5 STV090x_Px_SMAPCOEF5(1) -#define STV090x_P2_SMAPCOEF5 STV090x_Px_SMAPCOEF5(2) -#define STV090x_OFFST_Px_DIS_8SCALE_FIELD 7 -#define STV090x_WIDTH_Px_DIS_8SCALE_FIELD 1 -#define STV090x_OFFST_Px_SMAPCOEF_8P_LLR23_FIELD 0 -#define STV090x_WIDTH_Px_SMAPCOEF_8P_LLR23_FIELD 7 - -#define STV090x_Px_DMDPLHSTAT(__x) (0xF520 - (__x - 1) * 0x200) -#define STV090x_P1_DMDPLHSTAT STV090x_Px_DMDPLHSTAT(1) -#define STV090x_P2_DMDPLHSTAT STV090x_Px_DMDPLHSTAT(2) -#define STV090x_OFFST_Px_PLH_STATISTIC_FIELD 0 -#define STV090x_WIDTH_Px_PLH_STATISTIC_FIELD 8 - -#define STV090x_Px_LOCKTIMEy(__x, __y) (0xF525 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_LOCKTIME0 STV090x_Px_LOCKTIMEy(1, 0) -#define STV090x_P1_LOCKTIME1 STV090x_Px_LOCKTIMEy(1, 1) -#define STV090x_P1_LOCKTIME2 STV090x_Px_LOCKTIMEy(1, 2) -#define STV090x_P1_LOCKTIME3 STV090x_Px_LOCKTIMEy(1, 3) -#define STV090x_P2_LOCKTIME0 STV090x_Px_LOCKTIMEy(2, 0) -#define STV090x_P2_LOCKTIME1 STV090x_Px_LOCKTIMEy(2, 1) -#define STV090x_P2_LOCKTIME2 STV090x_Px_LOCKTIMEy(2, 2) -#define STV090x_P2_LOCKTIME3 STV090x_Px_LOCKTIMEy(2, 3) -#define STV090x_OFFST_Px_DEMOD_LOCKTIME_FIELD 0 -#define STV090x_WIDTH_Px_DEMOD_LOCKTIME_FIELD 8 - -#define STV090x_Px_TNRCFG(__x) (0xf4e0 - (__x - 1) * 0x200) /* check */ -#define STV090x_P1_TNRCFG STV090x_Px_TNRCFG(1) -#define STV090x_P2_TNRCFG STV090x_Px_TNRCFG(2) - -#define STV090x_Px_TNRCFG2(__x) (0xf4e1 - (__x - 1) * 0x200) -#define STV090x_P1_TNRCFG2 STV090x_Px_TNRCFG2(1) -#define STV090x_P2_TNRCFG2 STV090x_Px_TNRCFG2(2) -#define STV090x_OFFST_Px_TUN_IQSWAP_FIELD 7 -#define STV090x_WIDTH_Px_TUN_IQSWAP_FIELD 1 - -#define STV090x_Px_VITSCALE(__x) (0xf532 - (__x - 1) * 0x200) -#define STV090x_P1_VITSCALE STV090x_Px_VITSCALE(1) -#define STV090x_P2_VITSCALE STV090x_Px_VITSCALE(2) -#define STV090x_OFFST_Px_NVTH_NOSRANGE_FIELD 7 -#define STV090x_WIDTH_Px_NVTH_NOSRANGE_FIELD 1 -#define STV090x_OFFST_Px_VERROR_MAXMODE_FIELD 6 -#define STV090x_WIDTH_Px_VERROR_MAXMODE_FIELD 1 -#define STV090x_OFFST_Px_NSLOWSN_LOCKED_FIELD 3 -#define STV090x_WIDTH_Px_NSLOWSN_LOCKED_FIELD 1 -#define STV090x_OFFST_Px_DIS_RSFLOCK_FIELD 1 -#define STV090x_WIDTH_Px_DIS_RSFLOCK_FIELD 1 - -#define STV090x_Px_FECM(__x) (0xf533 - (__x - 1) * 0x200) -#define STV090x_P1_FECM STV090x_Px_FECM(1) -#define STV090x_P2_FECM STV090x_Px_FECM(2) -#define STV090x_OFFST_Px_DSS_DVB_FIELD 7 -#define STV090x_WIDTH_Px_DSS_DVB_FIELD 1 -#define STV090x_OFFST_Px_DSS_SRCH_FIELD 4 -#define STV090x_WIDTH_Px_DSS_SRCH_FIELD 1 -#define STV090x_OFFST_Px_SYNCVIT_FIELD 1 -#define STV090x_WIDTH_Px_SYNCVIT_FIELD 1 -#define STV090x_OFFST_Px_IQINV_FIELD 0 -#define STV090x_WIDTH_Px_IQINV_FIELD 1 - -#define STV090x_Px_VTH12(__x) (0xf534 - (__x - 1) * 0x200) -#define STV090x_P1_VTH12 STV090x_Px_VTH12(1) -#define STV090x_P2_VTH12 STV090x_Px_VTH12(2) -#define STV090x_OFFST_Px_VTH12_FIELD 0 -#define STV090x_WIDTH_Px_VTH12_FIELD 8 - -#define STV090x_Px_VTH23(__x) (0xf535 - (__x - 1) * 0x200) -#define STV090x_P1_VTH23 STV090x_Px_VTH23(1) -#define STV090x_P2_VTH23 STV090x_Px_VTH23(2) -#define STV090x_OFFST_Px_VTH23_FIELD 0 -#define STV090x_WIDTH_Px_VTH23_FIELD 8 - -#define STV090x_Px_VTH34(__x) (0xf536 - (__x - 1) * 0x200) -#define STV090x_P1_VTH34 STV090x_Px_VTH34(1) -#define STV090x_P2_VTH34 STV090x_Px_VTH34(2) -#define STV090x_OFFST_Px_VTH34_FIELD 0 -#define STV090x_WIDTH_Px_VTH34_FIELD 8 - -#define STV090x_Px_VTH56(__x) (0xf537 - (__x - 1) * 0x200) -#define STV090x_P1_VTH56 STV090x_Px_VTH56(1) -#define STV090x_P2_VTH56 STV090x_Px_VTH56(2) -#define STV090x_OFFST_Px_VTH56_FIELD 0 -#define STV090x_WIDTH_Px_VTH56_FIELD 8 - -#define STV090x_Px_VTH67(__x) (0xf538 - (__x - 1) * 0x200) -#define STV090x_P1_VTH67 STV090x_Px_VTH67(1) -#define STV090x_P2_VTH67 STV090x_Px_VTH67(2) -#define STV090x_OFFST_Px_VTH67_FIELD 0 -#define STV090x_WIDTH_Px_VTH67_FIELD 8 - -#define STV090x_Px_VTH78(__x) (0xf539 - (__x - 1) * 0x200) -#define STV090x_P1_VTH78 STV090x_Px_VTH78(1) -#define STV090x_P2_VTH78 STV090x_Px_VTH78(2) -#define STV090x_OFFST_Px_VTH78_FIELD 0 -#define STV090x_WIDTH_Px_VTH78_FIELD 8 - -#define STV090x_Px_VITCURPUN(__x) (0xf53a - (__x - 1) * 0x200) -#define STV090x_P1_VITCURPUN STV090x_Px_VITCURPUN(1) -#define STV090x_P2_VITCURPUN STV090x_Px_VITCURPUN(2) -#define STV090x_OFFST_Px_VIT_CURPUN_FIELD 0 -#define STV090x_WIDTH_Px_VIT_CURPUN_FIELD 5 - -#define STV090x_Px_VERROR(__x) (0xf53b - (__x - 1) * 0x200) -#define STV090x_P1_VERROR STV090x_Px_VERROR(1) -#define STV090x_P2_VERROR STV090x_Px_VERROR(2) -#define STV090x_OFFST_Px_REGERR_VIT_FIELD 0 -#define STV090x_WIDTH_Px_REGERR_VIT_FIELD 8 - -#define STV090x_Px_PRVIT(__x) (0xf53c - (__x - 1) * 0x200) -#define STV090x_P1_PRVIT STV090x_Px_PRVIT(1) -#define STV090x_P2_PRVIT STV090x_Px_PRVIT(2) -#define STV090x_OFFST_Px_DIS_VTHLOCK_FIELD 6 -#define STV090x_WIDTH_Px_DIS_VTHLOCK_FIELD 1 -#define STV090x_OFFST_Px_E7_8VIT_FIELD 5 -#define STV090x_WIDTH_Px_E7_8VIT_FIELD 1 -#define STV090x_OFFST_Px_E6_7VIT_FIELD 4 -#define STV090x_WIDTH_Px_E6_7VIT_FIELD 1 -#define STV090x_OFFST_Px_E5_6VIT_FIELD 3 -#define STV090x_WIDTH_Px_E5_6VIT_FIELD 1 -#define STV090x_OFFST_Px_E3_4VIT_FIELD 2 -#define STV090x_WIDTH_Px_E3_4VIT_FIELD 1 -#define STV090x_OFFST_Px_E2_3VIT_FIELD 1 -#define STV090x_WIDTH_Px_E2_3VIT_FIELD 1 -#define STV090x_OFFST_Px_E1_2VIT_FIELD 0 -#define STV090x_WIDTH_Px_E1_2VIT_FIELD 1 - -#define STV090x_Px_VAVSRVIT(__x) (0xf53d - (__x - 1) * 0x200) -#define STV090x_P1_VAVSRVIT STV090x_Px_VAVSRVIT(1) -#define STV090x_P2_VAVSRVIT STV090x_Px_VAVSRVIT(2) -#define STV090x_OFFST_Px_SNVIT_FIELD 4 -#define STV090x_WIDTH_Px_SNVIT_FIELD 2 -#define STV090x_OFFST_Px_TOVVIT_FIELD 2 -#define STV090x_WIDTH_Px_TOVVIT_FIELD 2 -#define STV090x_OFFST_Px_HYPVIT_FIELD 0 -#define STV090x_WIDTH_Px_HYPVIT_FIELD 2 - -#define STV090x_Px_VSTATUSVIT(__x) (0xf53e - (__x - 1) * 0x200) -#define STV090x_P1_VSTATUSVIT STV090x_Px_VSTATUSVIT(1) -#define STV090x_P2_VSTATUSVIT STV090x_Px_VSTATUSVIT(2) -#define STV090x_OFFST_Px_PRFVIT_FIELD 4 -#define STV090x_WIDTH_Px_PRFVIT_FIELD 1 -#define STV090x_OFFST_Px_LOCKEDVIT_FIELD 3 -#define STV090x_WIDTH_Px_LOCKEDVIT_FIELD 1 - -#define STV090x_Px_VTHINUSE(__x) (0xf53f - (__x - 1) * 0x200) -#define STV090x_P1_VTHINUSE STV090x_Px_VTHINUSE(1) -#define STV090x_P2_VTHINUSE STV090x_Px_VTHINUSE(2) -#define STV090x_OFFST_Px_VIT_INUSE_FIELD 0 -#define STV090x_WIDTH_Px_VIT_INUSE_FIELD 8 - -#define STV090x_Px_KDIV12(__x) (0xf540 - (__x - 1) * 0x200) -#define STV090x_P1_KDIV12 STV090x_Px_KDIV12(1) -#define STV090x_P2_KDIV12 STV090x_Px_KDIV12(2) -#define STV090x_OFFST_Px_K_DIVIDER_12_FIELD 0 -#define STV090x_WIDTH_Px_K_DIVIDER_12_FIELD 7 - -#define STV090x_Px_KDIV23(__x) (0xf541 - (__x - 1) * 0x200) -#define STV090x_P1_KDIV23 STV090x_Px_KDIV23(1) -#define STV090x_P2_KDIV23 STV090x_Px_KDIV23(2) -#define STV090x_OFFST_Px_K_DIVIDER_23_FIELD 0 -#define STV090x_WIDTH_Px_K_DIVIDER_23_FIELD 7 - -#define STV090x_Px_KDIV34(__x) (0xf542 - (__x - 1) * 0x200) -#define STV090x_P1_KDIV34 STV090x_Px_KDIV34(1) -#define STV090x_P2_KDIV34 STV090x_Px_KDIV34(2) -#define STV090x_OFFST_Px_K_DIVIDER_34_FIELD 0 -#define STV090x_WIDTH_Px_K_DIVIDER_34_FIELD 7 - -#define STV090x_Px_KDIV56(__x) (0xf543 - (__x - 1) * 0x200) -#define STV090x_P1_KDIV56 STV090x_Px_KDIV56(1) -#define STV090x_P2_KDIV56 STV090x_Px_KDIV56(2) -#define STV090x_OFFST_Px_K_DIVIDER_56_FIELD 0 -#define STV090x_WIDTH_Px_K_DIVIDER_56_FIELD 7 - -#define STV090x_Px_KDIV67(__x) (0xf544 - (__x - 1) * 0x200) -#define STV090x_P1_KDIV67 STV090x_Px_KDIV67(1) -#define STV090x_P2_KDIV67 STV090x_Px_KDIV67(2) -#define STV090x_OFFST_Px_K_DIVIDER_67_FIELD 0 -#define STV090x_WIDTH_Px_K_DIVIDER_67_FIELD 7 - -#define STV090x_Px_KDIV78(__x) (0xf545 - (__x - 1) * 0x200) -#define STV090x_P1_KDIV78 STV090x_Px_KDIV78(1) -#define STV090x_P2_KDIV78 STV090x_Px_KDIV78(2) -#define STV090x_OFFST_Px_K_DIVIDER_78_FIELD 0 -#define STV090x_WIDTH_Px_K_DIVIDER_78_FIELD 7 - -#define STV090x_Px_PDELCTRL1(__x) (0xf550 - (__x - 1) * 0x200) -#define STV090x_P1_PDELCTRL1 STV090x_Px_PDELCTRL1(1) -#define STV090x_P2_PDELCTRL1 STV090x_Px_PDELCTRL1(2) -#define STV090x_OFFST_Px_INV_MISMASK_FIELD 7 -#define STV090x_WIDTH_Px_INV_MISMASK_FIELD 1 -#define STV090x_OFFST_Px_FILTER_EN_FIELD 5 -#define STV090x_WIDTH_Px_FILTER_EN_FIELD 1 -#define STV090x_OFFST_Px_EN_MIS00_FIELD 1 -#define STV090x_WIDTH_Px_EN_MIS00_FIELD 1 -#define STV090x_OFFST_Px_ALGOSWRST_FIELD 0 -#define STV090x_WIDTH_Px_ALGOSWRST_FIELD 1 - -#define STV090x_Px_PDELCTRL2(__x) (0xf551 - (__x - 1) * 0x200) -#define STV090x_P1_PDELCTRL2 STV090x_Px_PDELCTRL2(1) -#define STV090x_P2_PDELCTRL2 STV090x_Px_PDELCTRL2(2) -#define STV090x_OFFST_Px_FORCE_CONTINUOUS 7 -#define STV090x_WIDTH_Px_FORCE_CONTINUOUS 1 -#define STV090x_OFFST_Px_RESET_UPKO_COUNT 6 -#define STV090x_WIDTH_Px_RESET_UPKO_COUNT 1 -#define STV090x_OFFST_Px_USER_PKTDELIN_NB 5 -#define STV090x_WIDTH_Px_USER_PKTDELIN_NB 1 -#define STV090x_OFFST_Px_FORCE_LOCKED 4 -#define STV090x_WIDTH_Px_FORCE_LOCKED 1 -#define STV090x_OFFST_Px_DATA_UNBBSCRAM 3 -#define STV090x_WIDTH_Px_DATA_UNBBSCRAM 1 -#define STV090x_OFFST_Px_FORCE_LONGPACKET 2 -#define STV090x_WIDTH_Px_FORCE_LONGPACKET 1 -#define STV090x_OFFST_Px_FRAME_MODE_FIELD 1 -#define STV090x_WIDTH_Px_FRAME_MODE_FIELD 1 - -#define STV090x_Px_HYSTTHRESH(__x) (0xf554 - (__x - 1) * 0x200) -#define STV090x_P1_HYSTTHRESH STV090x_Px_HYSTTHRESH(1) -#define STV090x_P2_HYSTTHRESH STV090x_Px_HYSTTHRESH(2) -#define STV090x_OFFST_Px_UNLCK_THRESH_FIELD 4 -#define STV090x_WIDTH_Px_UNLCK_THRESH_FIELD 4 -#define STV090x_OFFST_Px_DELIN_LCK_THRESH_FIELD 0 -#define STV090x_WIDTH_Px_DELIN_LCK_THRESH_FIELD 4 - -#define STV090x_Px_ISIENTRY(__x) (0xf55e - (__x - 1) * 0x200) -#define STV090x_P1_ISIENTRY STV090x_Px_ISIENTRY(1) -#define STV090x_P2_ISIENTRY STV090x_Px_ISIENTRY(2) -#define STV090x_OFFST_Px_ISI_ENTRY_FIELD 0 -#define STV090x_WIDTH_Px_ISI_ENTRY_FIELD 8 - -#define STV090x_Px_ISIBITENA(__x) (0xf55f - (__x - 1) * 0x200) -#define STV090x_P1_ISIBITENA STV090x_Px_ISIBITENA(1) -#define STV090x_P2_ISIBITENA STV090x_Px_ISIBITENA(2) -#define STV090x_OFFST_Px_ISI_BIT_EN_FIELD 0 -#define STV090x_WIDTH_Px_ISI_BIT_EN_FIELD 8 - -#define STV090x_Px_MATSTRy(__x, __y) (0xf561 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_MATSTR0 STV090x_Px_MATSTRy(1, 0) -#define STV090x_P1_MATSTR1 STV090x_Px_MATSTRy(1, 1) -#define STV090x_P2_MATSTR0 STV090x_Px_MATSTRy(2, 0) -#define STV090x_P2_MATSTR1 STV090x_Px_MATSTRy(2, 1) -#define STV090x_OFFST_Px_MATYPE_CURRENT_FIELD 0 -#define STV090x_WIDTH_Px_MATYPE_CURRENT_FIELD 8 - -#define STV090x_Px_UPLSTRy(__x, __y) (0xf563 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_UPLSTR0 STV090x_Px_UPLSTRy(1, 0) -#define STV090x_P1_UPLSTR1 STV090x_Px_UPLSTRy(1, 1) -#define STV090x_P2_UPLSTR0 STV090x_Px_UPLSTRy(2, 0) -#define STV090x_P2_UPLSTR1 STV090x_Px_UPLSTRy(2, 1) -#define STV090x_OFFST_Px_UPL_CURRENT_FIELD 0 -#define STV090x_WIDTH_Px_UPL_CURRENT_FIELD 8 - -#define STV090x_Px_DFLSTRy(__x, __y) (0xf565 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_DFLSTR0 STV090x_Px_DFLSTRy(1, 0) -#define STV090x_P1_DFLSTR1 STV090x_Px_DFLSTRy(1, 1) -#define STV090x_P2_DFLSTR0 STV090x_Px_DFLSTRy(2, 0) -#define STV090x_P2_DFLSTR1 STV090x_Px_DFLSTRy(2, 1) -#define STV090x_OFFST_Px_DFL_CURRENT_FIELD 0 -#define STV090x_WIDTH_Px_DFL_CURRENT_FIELD 8 - -#define STV090x_Px_SYNCSTR(__x) (0xf566 - (__x - 1) * 0x200) -#define STV090x_P1_SYNCSTR STV090x_Px_SYNCSTR(1) -#define STV090x_P2_SYNCSTR STV090x_Px_SYNCSTR(2) -#define STV090x_OFFST_Px_SYNC_CURRENT_FIELD 0 -#define STV090x_WIDTH_Px_SYNC_CURRENT_FIELD 8 - -#define STV090x_Px_SYNCDSTRy(__x, __y) (0xf568 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_SYNCDSTR0 STV090x_Px_SYNCDSTRy(1, 0) -#define STV090x_P1_SYNCDSTR1 STV090x_Px_SYNCDSTRy(1, 1) -#define STV090x_P2_SYNCDSTR0 STV090x_Px_SYNCDSTRy(2, 0) -#define STV090x_P2_SYNCDSTR1 STV090x_Px_SYNCDSTRy(2, 1) -#define STV090x_OFFST_Px_SYNCD_CURRENT_FIELD 0 -#define STV090x_WIDTH_Px_SYNCD_CURRENT_FIELD 8 - -#define STV090x_Px_PDELSTATUS1(__x) (0xf569 - (__x - 1) * 0x200) -#define STV090x_P1_PDELSTATUS1 STV090x_Px_PDELSTATUS1(1) -#define STV090x_P2_PDELSTATUS1 STV090x_Px_PDELSTATUS1(2) -#define STV090x_OFFST_Px_PKTDELIN_LOCK_FIELD 1 -#define STV090x_WIDTH_Px_PKTDELIN_LOCK_FIELD 1 -#define STV090x_OFFST_Px_FIRST_LOCK_FIELD 0 -#define STV090x_WIDTH_Px_FIRST_LOCK_FIELD 1 - -#define STV090x_Px_PDELSTATUS2(__x) (0xf56a - (__x - 1) * 0x200) -#define STV090x_P1_PDELSTATUS2 STV090x_Px_PDELSTATUS2(1) -#define STV090x_P2_PDELSTATUS2 STV090x_Px_PDELSTATUS2(2) -#define STV090x_OFFST_Px_FRAME_MODCOD_FIELD 2 -#define STV090x_WIDTH_Px_FRAME_MODCOD_FIELD 5 -#define STV090x_OFFST_Px_FRAME_TYPE_FIELD 0 -#define STV090x_WIDTH_Px_FRAME_TYPE_FIELD 2 - -#define STV090x_Px_BBFCRCKO1(__x) (0xf56b - (__x - 1) * 0x200) -#define STV090x_P1_BBFCRCKO1 STV090x_Px_BBFCRCKO1(1) -#define STV090x_P2_BBFCRCKO1 STV090x_Px_BBFCRCKO1(2) -#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD 0 -#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD 8 - -#define STV090x_Px_BBFCRCKO0(__x) (0xf56c - (__x - 1) * 0x200) -#define STV090x_P1_BBFCRCKO0 STV090x_Px_BBFCRCKO0(1) -#define STV090x_P2_BBFCRCKO0 STV090x_Px_BBFCRCKO0(2) -#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD 0 -#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD 8 - -#define STV090x_Px_UPCRCKO1(__x) (0xf56d - (__x - 1) * 0x200) -#define STV090x_P1_UPCRCKO1 STV090x_Px_UPCRCKO1(1) -#define STV090x_P2_UPCRCKO1 STV090x_Px_UPCRCKO1(2) -#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD 0 -#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD 8 - -#define STV090x_Px_UPCRCKO0(__x) (0xf56e - (__x - 1) * 0x200) -#define STV090x_P1_UPCRCKO0 STV090x_Px_UPCRCKO0(1) -#define STV090x_P2_UPCRCKO0 STV090x_Px_UPCRCKO0(2) -#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD 0 -#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD 8 - -#define STV090x_NBITER_NFx(__x) (0xFA03 + (__x - 4) * 0x1) -#define STV090x_NBITER_NF4 STV090x_NBITER_NFx(4) -#define STV090x_NBITER_NF5 STV090x_NBITER_NFx(5) -#define STV090x_NBITER_NF6 STV090x_NBITER_NFx(6) -#define STV090x_NBITER_NF7 STV090x_NBITER_NFx(7) -#define STV090x_NBITER_NF8 STV090x_NBITER_NFx(8) -#define STV090x_NBITER_NF9 STV090x_NBITER_NFx(9) -#define STV090x_NBITER_NF10 STV090x_NBITER_NFx(10) -#define STV090x_NBITER_NF11 STV090x_NBITER_NFx(11) -#define STV090x_NBITER_NF12 STV090x_NBITER_NFx(12) -#define STV090x_NBITER_NF13 STV090x_NBITER_NFx(13) -#define STV090x_NBITER_NF14 STV090x_NBITER_NFx(14) -#define STV090x_NBITER_NF15 STV090x_NBITER_NFx(15) -#define STV090x_NBITER_NF16 STV090x_NBITER_NFx(16) -#define STV090x_NBITER_NF17 STV090x_NBITER_NFx(17) - -#define STV090x_NBITERNOERR 0xFA3F -#define STV090x_OFFST_NBITER_STOP_CRIT_FIELD 0 -#define STV090x_WIDTH_NBITER_STOP_CRIT_FIELD 4 - -#define STV090x_GAINLLR_NFx(__x) (0xFA43 + (__x - 4) * 0x1) -#define STV090x_GAINLLR_NF4 STV090x_GAINLLR_NFx(4) -#define STV090x_OFFST_GAINLLR_NF_QP_1_2_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_QP_1_2_FIELD 7 - -#define STV090x_GAINLLR_NF5 STV090x_GAINLLR_NFx(5) -#define STV090x_OFFST_GAINLLR_NF_QP_3_5_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_QP_3_5_FIELD 7 - -#define STV090x_GAINLLR_NF6 STV090x_GAINLLR_NFx(6) -#define STV090x_OFFST_GAINLLR_NF_QP_2_3_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_QP_2_3_FIELD 7 - -#define STV090x_GAINLLR_NF7 STV090x_GAINLLR_NFx(7) -#define STV090x_OFFST_GAINLLR_NF_QP_3_4_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_QP_3_4_FIELD 7 - -#define STV090x_GAINLLR_NF8 STV090x_GAINLLR_NFx(8) -#define STV090x_OFFST_GAINLLR_NF_QP_4_5_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_QP_4_5_FIELD 7 - -#define STV090x_GAINLLR_NF9 STV090x_GAINLLR_NFx(9) -#define STV090x_OFFST_GAINLLR_NF_QP_5_6_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_QP_5_6_FIELD 7 - -#define STV090x_GAINLLR_NF10 STV090x_GAINLLR_NFx(10) -#define STV090x_OFFST_GAINLLR_NF_QP_8_9_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_QP_8_9_FIELD 7 - -#define STV090x_GAINLLR_NF11 STV090x_GAINLLR_NFx(11) -#define STV090x_OFFST_GAINLLR_NF_QP_9_10_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_QP_9_10_FIELD 7 - -#define STV090x_GAINLLR_NF12 STV090x_GAINLLR_NFx(12) -#define STV090x_OFFST_GAINLLR_NF_8P_3_5_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_8P_3_5_FIELD 7 - -#define STV090x_GAINLLR_NF13 STV090x_GAINLLR_NFx(13) -#define STV090x_OFFST_GAINLLR_NF_8P_2_3_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_8P_2_3_FIELD 7 - -#define STV090x_GAINLLR_NF14 STV090x_GAINLLR_NFx(14) -#define STV090x_OFFST_GAINLLR_NF_8P_3_4_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_8P_3_4_FIELD 7 - -#define STV090x_GAINLLR_NF15 STV090x_GAINLLR_NFx(15) -#define STV090x_OFFST_GAINLLR_NF_8P_5_6_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_8P_5_6_FIELD 7 - -#define STV090x_GAINLLR_NF16 STV090x_GAINLLR_NFx(16) -#define STV090x_OFFST_GAINLLR_NF_8P_8_9_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_8P_8_9_FIELD 7 - -#define STV090x_GAINLLR_NF17 STV090x_GAINLLR_NFx(17) -#define STV090x_OFFST_GAINLLR_NF_8P_9_10_FIELD 0 -#define STV090x_WIDTH_GAINLLR_NF_8P_9_10_FIELD 7 - -#define STV090x_GENCFG 0xFA86 -#define STV090x_OFFST_BROADCAST_FIELD 4 -#define STV090x_WIDTH_BROADCAST_FIELD 1 -#define STV090x_OFFST_PRIORITY_FIELD 1 -#define STV090x_WIDTH_PRIORITY_FIELD 1 -#define STV090x_OFFST_DDEMOD_FIELD 0 -#define STV090x_WIDTH_DDEMOD_FIELD 1 - -#define STV090x_LDPCERRx(__x) (0xFA97 - (__x * 0x1)) -#define STV090x_LDPCERR0 STV090x_LDPCERRx(0) -#define STV090x_LDPCERR1 STV090x_LDPCERRx(1) -#define STV090x_OFFST_Px_LDPC_ERRORS_COUNTER_FIELD 0 -#define STV090x_WIDTH_Px_LDPC_ERRORS_COUNTER_FIELD 8 - -#define STV090x_BCHERR 0xFA98 -#define STV090x_OFFST_Px_ERRORFLAG_FIELD 4 -#define STV090x_WIDTH_Px_ERRORFLAG_FIELD 1 -#define STV090x_OFFST_Px_BCH_ERRORS_COUNTER_FIELD 0 -#define STV090x_WIDTH_Px_BCH_ERRORS_COUNTER_FIELD 4 - -#define STV090x_Px_TSSTATEM(__x) (0xF570 - (__x - 1) * 0x200) -#define STV090x_P1_TSSTATEM STV090x_Px_TSSTATEM(1) -#define STV090x_P2_TSSTATEM STV090x_Px_TSSTATEM(2) -#define STV090x_OFFST_Px_TSDIL_ON_FIELD 7 -#define STV090x_WIDTH_Px_TSDIL_ON_FIELD 1 -#define STV090x_OFFST_Px_TSRS_ON_FIELD 5 -#define STV090x_WIDTH_Px_TSRS_ON_FIELD 1 - -#define STV090x_Px_TSCFGH(__x) (0xF572 - (__x - 1) * 0x200) -#define STV090x_P1_TSCFGH STV090x_Px_TSCFGH(1) -#define STV090x_P2_TSCFGH STV090x_Px_TSCFGH(2) -#define STV090x_OFFST_Px_TSFIFO_DVBCI_FIELD 7 -#define STV090x_WIDTH_Px_TSFIFO_DVBCI_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_SERIAL_FIELD 6 -#define STV090x_WIDTH_Px_TSFIFO_SERIAL_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_TEIUPDATE_FIELD 5 -#define STV090x_WIDTH_Px_TSFIFO_TEIUPDATE_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_DUTY50_FIELD 4 -#define STV090x_WIDTH_Px_TSFIFO_DUTY50_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_HSGNLOUT_FIELD 3 -#define STV090x_WIDTH_Px_TSFIFO_HSGNLOUT_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_ERRORMODE_FIELD 1 -#define STV090x_WIDTH_Px_TSFIFO_ERRORMODE_FIELD 2 -#define STV090x_OFFST_Px_RST_HWARE_FIELD 0 -#define STV090x_WIDTH_Px_RST_HWARE_FIELD 1 - -#define STV090x_Px_TSCFGM(__x) (0xF573 - (__x - 1) * 0x200) -#define STV090x_P1_TSCFGM STV090x_Px_TSCFGM(1) -#define STV090x_P2_TSCFGM STV090x_Px_TSCFGM(2) -#define STV090x_OFFST_Px_TSFIFO_MANSPEED_FIELD 6 -#define STV090x_WIDTH_Px_TSFIFO_MANSPEED_FIELD 2 -#define STV090x_OFFST_Px_TSFIFO_PERMDATA_FIELD 5 -#define STV090x_WIDTH_Px_TSFIFO_PERMDATA_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_INVDATA_FIELD 0 -#define STV090x_WIDTH_Px_TSFIFO_INVDATA_FIELD 1 - -#define STV090x_Px_TSCFGL(__x) (0xF574 - (__x - 1) * 0x200) -#define STV090x_P1_TSCFGL STV090x_Px_TSCFGL(1) -#define STV090x_P2_TSCFGL STV090x_Px_TSCFGL(2) -#define STV090x_OFFST_Px_TSFIFO_BCLKDEL1CK_FIELD 6 -#define STV090x_WIDTH_Px_TSFIFO_BCLKDEL1CK_FIELD 2 -#define STV090x_OFFST_Px_BCHERROR_MODE_FIELD 4 -#define STV090x_WIDTH_Px_BCHERROR_MODE_FIELD 2 -#define STV090x_OFFST_Px_TSFIFO_NSGNL2DATA_FIELD 3 -#define STV090x_WIDTH_Px_TSFIFO_NSGNL2DATA_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_EMBINDVB_FIELD 2 -#define STV090x_WIDTH_Px_TSFIFO_EMBINDVB_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_DPUNACT_FIELD 1 -#define STV090x_WIDTH_Px_TSFIFO_DPUNACT_FIELD 1 - -#define STV090x_Px_TSINSDELH(__x) (0xF576 - (__x - 1) * 0x200) -#define STV090x_P1_TSINSDELH STV090x_Px_TSINSDELH(1) -#define STV090x_P2_TSINSDELH STV090x_Px_TSINSDELH(2) -#define STV090x_OFFST_Px_TSDEL_SYNCBYTE_FIELD 7 -#define STV090x_WIDTH_Px_TSDEL_SYNCBYTE_FIELD 1 -#define STV090x_OFFST_Px_TSDEL_XXHEADER_FIELD 6 -#define STV090x_WIDTH_Px_TSDEL_XXHEADER_FIELD 1 - -#define STV090x_Px_TSSPEED(__x) (0xF580 - (__x - 1) * 0x200) -#define STV090x_P1_TSSPEED STV090x_Px_TSSPEED(1) -#define STV090x_P2_TSSPEED STV090x_Px_TSSPEED(2) -#define STV090x_OFFST_Px_TSFIFO_OUTSPEED_FIELD 0 -#define STV090x_WIDTH_Px_TSFIFO_OUTSPEED_FIELD 8 - -#define STV090x_Px_TSSTATUS(__x) (0xF581 - (__x - 1) * 0x200) -#define STV090x_P1_TSSTATUS STV090x_Px_TSSTATUS(1) -#define STV090x_P2_TSSTATUS STV090x_Px_TSSTATUS(2) -#define STV090x_OFFST_Px_TSFIFO_LINEOK_FIELD 7 -#define STV090x_WIDTH_Px_TSFIFO_LINEOK_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_ERROR_FIELD 6 -#define STV090x_WIDTH_Px_TSFIFO_ERROR_FIELD 1 - -#define STV090x_Px_TSSTATUS2(__x) (0xF582 - (__x - 1) * 0x200) -#define STV090x_P1_TSSTATUS2 STV090x_Px_TSSTATUS2(1) -#define STV090x_P2_TSSTATUS2 STV090x_Px_TSSTATUS2(2) -#define STV090x_OFFST_Px_TSFIFO_DEMODSEL_FIELD 7 -#define STV090x_WIDTH_Px_TSFIFO_DEMODSEL_FIELD 1 -#define STV090x_OFFST_Px_TSFIFOSPEED_STORE_FIELD 6 -#define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD 1 -#define STV090x_OFFST_Px_DILXX_RESET_FIELD 5 -#define STV090x_WIDTH_Px_DILXX_RESET_FIELD 1 -#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD 4 -#define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD 1 -#define STV090x_OFFST_Px_SCRAMBDETECT_FIELD 1 -#define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD 1 - -#define STV090x_Px_TSBITRATEy(__x, __y) (0xF584 - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_TSBITRATE0 STV090x_Px_TSBITRATEy(1, 0) -#define STV090x_P1_TSBITRATE1 STV090x_Px_TSBITRATEy(1, 1) -#define STV090x_P2_TSBITRATE0 STV090x_Px_TSBITRATEy(2, 0) -#define STV090x_P2_TSBITRATE1 STV090x_Px_TSBITRATEy(2, 1) -#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD 0 -#define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD 8 - -#define STV090x_Px_ERRCTRL1(__x) (0xF598 - (__x - 1) * 0x200) -#define STV090x_P1_ERRCTRL1 STV090x_Px_ERRCTRL1(1) -#define STV090x_P2_ERRCTRL1 STV090x_Px_ERRCTRL1(2) -#define STV090x_OFFST_Px_ERR_SOURCE_FIELD 4 -#define STV090x_WIDTH_Px_ERR_SOURCE_FIELD 4 -#define STV090x_OFFST_Px_NUM_EVENT_FIELD 0 -#define STV090x_WIDTH_Px_NUM_EVENT_FIELD 3 - -#define STV090x_Px_ERRCNT12(__x) (0xF599 - (__x - 1) * 0x200) -#define STV090x_P1_ERRCNT12 STV090x_Px_ERRCNT12(1) -#define STV090x_P2_ERRCNT12 STV090x_Px_ERRCNT12(2) -#define STV090x_OFFST_Px_ERRCNT1_OLDVALUE_FIELD 7 -#define STV090x_WIDTH_Px_ERRCNT1_OLDVALUE_FIELD 1 -#define STV090x_OFFST_Px_ERR_CNT12_FIELD 0 -#define STV090x_WIDTH_Px_ERR_CNT12_FIELD 7 - -#define STV090x_Px_ERRCNT11(__x) (0xF59A - (__x - 1) * 0x200) -#define STV090x_P1_ERRCNT11 STV090x_Px_ERRCNT11(1) -#define STV090x_P2_ERRCNT11 STV090x_Px_ERRCNT11(2) -#define STV090x_OFFST_Px_ERR_CNT11_FIELD 0 -#define STV090x_WIDTH_Px_ERR_CNT11_FIELD 8 - -#define STV090x_Px_ERRCNT10(__x) (0xF59B - (__x - 1) * 0x200) -#define STV090x_P1_ERRCNT10 STV090x_Px_ERRCNT10(1) -#define STV090x_P2_ERRCNT10 STV090x_Px_ERRCNT10(2) -#define STV090x_OFFST_Px_ERR_CNT10_FIELD 0 -#define STV090x_WIDTH_Px_ERR_CNT10_FIELD 8 - -#define STV090x_Px_ERRCTRL2(__x) (0xF59C - (__x - 1) * 0x200) -#define STV090x_P1_ERRCTRL2 STV090x_Px_ERRCTRL2(1) -#define STV090x_P2_ERRCTRL2 STV090x_Px_ERRCTRL2(2) -#define STV090x_OFFST_Px_ERR_SOURCE2_FIELD 4 -#define STV090x_WIDTH_Px_ERR_SOURCE2_FIELD 4 -#define STV090x_OFFST_Px_NUM_EVENT2_FIELD 0 -#define STV090x_WIDTH_Px_NUM_EVENT2_FIELD 3 - -#define STV090x_Px_ERRCNT22(__x) (0xF59D - (__x - 1) * 0x200) -#define STV090x_P1_ERRCNT22 STV090x_Px_ERRCNT22(1) -#define STV090x_P2_ERRCNT22 STV090x_Px_ERRCNT22(2) -#define STV090x_OFFST_Px_ERRCNT2_OLDVALUE_FIELD 7 -#define STV090x_WIDTH_Px_ERRCNT2_OLDVALUE_FIELD 1 -#define STV090x_OFFST_Px_ERR_CNT2_FIELD 0 -#define STV090x_WIDTH_Px_ERR_CNT2_FIELD 7 - -#define STV090x_Px_ERRCNT21(__x) (0xF59E - (__x - 1) * 0x200) -#define STV090x_P1_ERRCNT21 STV090x_Px_ERRCNT21(1) -#define STV090x_P2_ERRCNT21 STV090x_Px_ERRCNT21(2) -#define STV090x_OFFST_Px_ERR_CNT21_FIELD 0 -#define STV090x_WIDTH_Px_ERR_CNT21_FIELD 8 - -#define STV090x_Px_ERRCNT20(__x) (0xF59F - (__x - 1) * 0x200) -#define STV090x_P1_ERRCNT20 STV090x_Px_ERRCNT20(1) -#define STV090x_P2_ERRCNT20 STV090x_Px_ERRCNT20(2) -#define STV090x_OFFST_Px_ERR_CNT20_FIELD 0 -#define STV090x_WIDTH_Px_ERR_CNT20_FIELD 8 - -#define STV090x_Px_FECSPY(__x) (0xF5A0 - (__x - 1) * 0x200) -#define STV090x_P1_FECSPY STV090x_Px_FECSPY(1) -#define STV090x_P2_FECSPY STV090x_Px_FECSPY(2) -#define STV090x_OFFST_Px_SPY_ENABLE_FIELD 7 -#define STV090x_WIDTH_Px_SPY_ENABLE_FIELD 1 -#define STV090x_OFFST_Px_BERMETER_DATAMAODE_FIELD 2 -#define STV090x_WIDTH_Px_BERMETER_DATAMAODE_FIELD 2 - -#define STV090x_Px_FSPYCFG(__x) (0xF5A1 - (__x - 1) * 0x200) -#define STV090x_P1_FSPYCFG STV090x_Px_FSPYCFG(1) -#define STV090x_P2_FSPYCFG STV090x_Px_FSPYCFG(2) -#define STV090x_OFFST_Px_RST_ON_ERROR_FIELD 5 -#define STV090x_WIDTH_Px_RST_ON_ERROR_FIELD 1 -#define STV090x_OFFST_Px_ONE_SHOT_FIELD 4 -#define STV090x_WIDTH_Px_ONE_SHOT_FIELD 1 -#define STV090x_OFFST_Px_I2C_MODE_FIELD 2 -#define STV090x_WIDTH_Px_I2C_MODE_FIELD 2 - -#define STV090x_Px_FSPYDATA(__x) (0xF5A2 - (__x - 1) * 0x200) -#define STV090x_P1_FSPYDATA STV090x_Px_FSPYDATA(1) -#define STV090x_P2_FSPYDATA STV090x_Px_FSPYDATA(2) -#define STV090x_OFFST_Px_SPY_STUFFING_FIELD 7 -#define STV090x_WIDTH_Px_SPY_STUFFING_FIELD 1 -#define STV090x_OFFST_Px_SPY_CNULLPKT_FIELD 5 -#define STV090x_WIDTH_Px_SPY_CNULLPKT_FIELD 1 -#define STV090x_OFFST_Px_SPY_OUTDATA_MODE_FIELD 0 -#define STV090x_WIDTH_Px_SPY_OUTDATA_MODE_FIELD 5 - -#define STV090x_Px_FSPYOUT(__x) (0xF5A3 - (__x - 1) * 0x200) -#define STV090x_P1_FSPYOUT STV090x_Px_FSPYOUT(1) -#define STV090x_P2_FSPYOUT STV090x_Px_FSPYOUT(2) -#define STV090x_OFFST_Px_FSPY_DIRECT_FIELD 7 -#define STV090x_WIDTH_Px_FSPY_DIRECT_FIELD 1 -#define STV090x_OFFST_Px_STUFF_MODE_FIELD 0 -#define STV090x_WIDTH_Px_STUFF_MODE_FIELD 3 - -#define STV090x_Px_FSTATUS(__x) (0xF5A4 - (__x - 1) * 0x200) -#define STV090x_P1_FSTATUS STV090x_Px_FSTATUS(1) -#define STV090x_P2_FSTATUS STV090x_Px_FSTATUS(2) -#define STV090x_OFFST_Px_SPY_ENDSIM_FIELD 7 -#define STV090x_WIDTH_Px_SPY_ENDSIM_FIELD 1 -#define STV090x_OFFST_Px_VALID_SIM_FIELD 6 -#define STV090x_WIDTH_Px_VALID_SIM_FIELD 1 -#define STV090x_OFFST_Px_FOUND_SIGNAL_FIELD 5 -#define STV090x_WIDTH_Px_FOUND_SIGNAL_FIELD 1 -#define STV090x_OFFST_Px_DSS_SYNCBYTE_FIELD 4 -#define STV090x_WIDTH_Px_DSS_SYNCBYTE_FIELD 1 -#define STV090x_OFFST_Px_RESULT_STATE_FIELD 0 -#define STV090x_WIDTH_Px_RESULT_STATE_FIELD 4 - -#define STV090x_Px_FBERCPT4(__x) (0xF5A8 - (__x - 1) * 0x200) -#define STV090x_P1_FBERCPT4 STV090x_Px_FBERCPT4(1) -#define STV090x_P2_FBERCPT4 STV090x_Px_FBERCPT4(2) -#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 -#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 - -#define STV090x_Px_FBERCPT3(__x) (0xF5A9 - (__x - 1) * 0x200) -#define STV090x_P1_FBERCPT3 STV090x_Px_FBERCPT3(1) -#define STV090x_P2_FBERCPT3 STV090x_Px_FBERCPT3(2) -#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 -#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 - -#define STV090x_Px_FBERCPT2(__x) (0xF5AA - (__x - 1) * 0x200) -#define STV090x_P1_FBERCPT2 STV090x_Px_FBERCPT2(1) -#define STV090x_P2_FBERCPT2 STV090x_Px_FBERCPT2(2) -#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 -#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 - -#define STV090x_Px_FBERCPT1(__x) (0xF5AB - (__x - 1) * 0x200) -#define STV090x_P1_FBERCPT1 STV090x_Px_FBERCPT1(1) -#define STV090x_P2_FBERCPT1 STV090x_Px_FBERCPT1(2) -#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 -#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 - -#define STV090x_Px_FBERCPT0(__x) (0xF5AC - (__x - 1) * 0x200) -#define STV090x_P1_FBERCPT0 STV090x_Px_FBERCPT0(1) -#define STV090x_P2_FBERCPT0 STV090x_Px_FBERCPT0(2) -#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 -#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 - -#define STV090x_Px_FBERERRy(__x, __y) (0xF5AF - (__x - 1) * 0x200 - __y * 0x1) -#define STV090x_P1_FBERERR0 STV090x_Px_FBERERRy(1, 0) -#define STV090x_P1_FBERERR1 STV090x_Px_FBERERRy(1, 1) -#define STV090x_P1_FBERERR2 STV090x_Px_FBERERRy(1, 2) -#define STV090x_P2_FBERERR0 STV090x_Px_FBERERRy(2, 0) -#define STV090x_P2_FBERERR1 STV090x_Px_FBERERRy(2, 1) -#define STV090x_P2_FBERERR2 STV090x_Px_FBERERRy(2, 2) -#define STV090x_OFFST_Px_FBERMETER_CPT_ERR_FIELD 0 -#define STV090x_WIDTH_Px_FBERMETER_CPT_ERR_FIELD 8 - -#define STV090x_Px_FSPYBER(__x) (0xF5B2 - (__x - 1) * 0x200) -#define STV090x_P1_FSPYBER STV090x_Px_FSPYBER(1) -#define STV090x_P2_FSPYBER STV090x_Px_FSPYBER(2) -#define STV090x_OFFST_Px_FSPYBER_SYNCBYTE_FIELD 4 -#define STV090x_WIDTH_Px_FSPYBER_SYNCBYTE_FIELD 1 -#define STV090x_OFFST_Px_FSPYBER_UNSYNC_FIELD 3 -#define STV090x_WIDTH_Px_FSPYBER_UNSYNC_FIELD 1 -#define STV090x_OFFST_Px_FSPYBER_CTIME_FIELD 0 -#define STV090x_WIDTH_Px_FSPYBER_CTIME_FIELD 3 - -#define STV090x_RCCFGH 0xf600 - -#define STV090x_TSGENERAL 0xF630 -#define STV090x_OFFST_Px_MUXSTREAM_OUT_FIELD 3 -#define STV090x_WIDTH_Px_MUXSTREAM_OUT_FIELD 1 -#define STV090x_OFFST_Px_TSFIFO_PERMPARAL_FIELD 1 -#define STV090x_WIDTH_Px_TSFIFO_PERMPARAL_FIELD 2 - -#define STV090x_TSGENERAL1X 0xf670 -#define STV090x_CFGEXT 0xfa80 - -#define STV090x_TSTRES0 0xFF11 -#define STV090x_OFFST_FRESFEC_FIELD 7 -#define STV090x_WIDTH_FRESFEC_FIELD 1 - -#define STV090x_Px_TSTDISRX(__x) (0xFF67 - (__x - 1) * 0x2) -#define STV090x_P1_TSTDISRX STV090x_Px_TSTDISRX(1) -#define STV090x_P2_TSTDISRX STV090x_Px_TSTDISRX(2) -#define STV090x_OFFST_Px_TSTDISRX_SELECT_FIELD 3 -#define STV090x_WIDTH_Px_TSTDISRX_SELECT_FIELD 1 - -#endif /* __STV090x_REG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,452 +0,0 @@ -/* - * stv6110.c - * - * Driver for ST STV6110 satellite tuner IC. - * - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include - -#include - -#include "stv6110.h" - -static int debug; - -struct stv6110_priv { - int i2c_address; - struct i2c_adapter *i2c; - - u32 mclk; - u8 clk_div; - u8 gain; - u8 regs[8]; -}; - -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG args); \ - } while (0) - -static s32 abssub(s32 a, s32 b) -{ - if (a > b) - return a - b; - else - return b - a; -}; - -static int stv6110_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[], - int start, int len) -{ - struct stv6110_priv *priv = fe->tuner_priv; - int rc; - u8 cmdbuf[len + 1]; - struct i2c_msg msg = { - .addr = priv->i2c_address, - .flags = 0, - .buf = cmdbuf, - .len = len + 1 - }; - - dprintk("%s\n", __func__); - - if (start + len > 8) - return -EINVAL; - - memcpy(&cmdbuf[1], buf, len); - cmdbuf[0] = start; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - rc = i2c_transfer(priv->i2c, &msg, 1); - if (rc != 1) - dprintk("%s: i2c error\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int stv6110_read_regs(struct dvb_frontend *fe, u8 regs[], - int start, int len) -{ - struct stv6110_priv *priv = fe->tuner_priv; - int rc; - u8 reg[] = { start }; - struct i2c_msg msg[] = { - { - .addr = priv->i2c_address, - .flags = 0, - .buf = reg, - .len = 1, - }, { - .addr = priv->i2c_address, - .flags = I2C_M_RD, - .buf = regs, - .len = len, - }, - }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - rc = i2c_transfer(priv->i2c, msg, 2); - if (rc != 2) - dprintk("%s: i2c error\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - memcpy(&priv->regs[start], regs, len); - - return 0; -} - -static int stv6110_read_reg(struct dvb_frontend *fe, int start) -{ - u8 buf[] = { 0 }; - stv6110_read_regs(fe, buf, start, 1); - - return buf[0]; -} - -static int stv6110_sleep(struct dvb_frontend *fe) -{ - u8 reg[] = { 0 }; - stv6110_write_regs(fe, reg, 0, 1); - - return 0; -} - -static u32 carrier_width(u32 symbol_rate, fe_rolloff_t rolloff) -{ - u32 rlf; - - switch (rolloff) { - case ROLLOFF_20: - rlf = 20; - break; - case ROLLOFF_25: - rlf = 25; - break; - default: - rlf = 35; - break; - } - - return symbol_rate + ((symbol_rate * rlf) / 100); -} - -static int stv6110_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) -{ - struct stv6110_priv *priv = fe->tuner_priv; - u8 r8, ret = 0x04; - int i; - - if ((bandwidth / 2) > 36000000) /*BW/2 max=31+5=36 mhz for r8=31*/ - r8 = 31; - else if ((bandwidth / 2) < 5000000) /* BW/2 min=5Mhz for F=0 */ - r8 = 0; - else /*if 5 < BW/2 < 36*/ - r8 = (bandwidth / 2) / 1000000 - 5; - - /* ctrl3, RCCLKOFF = 0 Activate the calibration Clock */ - /* ctrl3, CF = r8 Set the LPF value */ - priv->regs[RSTV6110_CTRL3] &= ~((1 << 6) | 0x1f); - priv->regs[RSTV6110_CTRL3] |= (r8 & 0x1f); - stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1); - /* stat1, CALRCSTRT = 1 Start LPF auto calibration*/ - priv->regs[RSTV6110_STAT1] |= 0x02; - stv6110_write_regs(fe, &priv->regs[RSTV6110_STAT1], RSTV6110_STAT1, 1); - - i = 0; - /* Wait for CALRCSTRT == 0 */ - while ((i < 10) && (ret != 0)) { - ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x02); - mdelay(1); /* wait for LPF auto calibration */ - i++; - } - - /* RCCLKOFF = 1 calibration done, desactivate the calibration Clock */ - priv->regs[RSTV6110_CTRL3] |= (1 << 6); - stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1); - return 0; -} - -static int stv6110_init(struct dvb_frontend *fe) -{ - struct stv6110_priv *priv = fe->tuner_priv; - u8 buf0[] = { 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e }; - - memcpy(priv->regs, buf0, 8); - /* K = (Reference / 1000000) - 16 */ - priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3); - priv->regs[RSTV6110_CTRL1] |= - ((((priv->mclk / 1000000) - 16) & 0x1f) << 3); - - /* divisor value for the output clock */ - priv->regs[RSTV6110_CTRL2] &= ~0xc0; - priv->regs[RSTV6110_CTRL2] |= (priv->clk_div << 6); - - stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], RSTV6110_CTRL1, 8); - msleep(1); - stv6110_set_bandwidth(fe, 72000000); - - return 0; -} - -static int stv6110_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct stv6110_priv *priv = fe->tuner_priv; - u32 nbsteps, divider, psd2, freq; - u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - stv6110_read_regs(fe, regs, 0, 8); - /*N*/ - divider = (priv->regs[RSTV6110_TUNING2] & 0x0f) << 8; - divider += priv->regs[RSTV6110_TUNING1]; - - /*R*/ - nbsteps = (priv->regs[RSTV6110_TUNING2] >> 6) & 3; - /*p*/ - psd2 = (priv->regs[RSTV6110_TUNING2] >> 4) & 1; - - freq = divider * (priv->mclk / 1000); - freq /= (1 << (nbsteps + psd2)); - freq /= 4; - - *frequency = freq; - - return 0; -} - -static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency) -{ - struct stv6110_priv *priv = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u8 ret = 0x04; - u32 divider, ref, p, presc, i, result_freq, vco_freq; - s32 p_calc, p_calc_opt = 1000, r_div, r_div_opt = 0, p_val; - s32 srate; - - dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__, - frequency, priv->mclk); - - /* K = (Reference / 1000000) - 16 */ - priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3); - priv->regs[RSTV6110_CTRL1] |= - ((((priv->mclk / 1000000) - 16) & 0x1f) << 3); - - /* BB_GAIN = db/2 */ - if (fe->ops.set_property && fe->ops.get_property) { - srate = c->symbol_rate; - dprintk("%s: Get Frontend parameters: srate=%d\n", - __func__, srate); - } else - srate = 15000000; - - priv->regs[RSTV6110_CTRL2] &= ~0x0f; - priv->regs[RSTV6110_CTRL2] |= (priv->gain & 0x0f); - - if (frequency <= 1023000) { - p = 1; - presc = 0; - } else if (frequency <= 1300000) { - p = 1; - presc = 1; - } else if (frequency <= 2046000) { - p = 0; - presc = 0; - } else { - p = 0; - presc = 1; - } - /* DIV4SEL = p*/ - priv->regs[RSTV6110_TUNING2] &= ~(1 << 4); - priv->regs[RSTV6110_TUNING2] |= (p << 4); - - /* PRESC32ON = presc */ - priv->regs[RSTV6110_TUNING2] &= ~(1 << 5); - priv->regs[RSTV6110_TUNING2] |= (presc << 5); - - p_val = (int)(1 << (p + 1)) * 10;/* P = 2 or P = 4 */ - for (r_div = 0; r_div <= 3; r_div++) { - p_calc = (priv->mclk / 100000); - p_calc /= (1 << (r_div + 1)); - if ((abssub(p_calc, p_val)) < (abssub(p_calc_opt, p_val))) - r_div_opt = r_div; - - p_calc_opt = (priv->mclk / 100000); - p_calc_opt /= (1 << (r_div_opt + 1)); - } - - ref = priv->mclk / ((1 << (r_div_opt + 1)) * (1 << (p + 1))); - divider = (((frequency * 1000) + (ref >> 1)) / ref); - - /* RDIV = r_div_opt */ - priv->regs[RSTV6110_TUNING2] &= ~(3 << 6); - priv->regs[RSTV6110_TUNING2] |= (((r_div_opt) & 3) << 6); - - /* NDIV_MSB = MSB(divider) */ - priv->regs[RSTV6110_TUNING2] &= ~0x0f; - priv->regs[RSTV6110_TUNING2] |= (((divider) >> 8) & 0x0f); - - /* NDIV_LSB, LSB(divider) */ - priv->regs[RSTV6110_TUNING1] = (divider & 0xff); - - /* CALVCOSTRT = 1 VCO Auto Calibration */ - priv->regs[RSTV6110_STAT1] |= 0x04; - stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], - RSTV6110_CTRL1, 8); - - i = 0; - /* Wait for CALVCOSTRT == 0 */ - while ((i < 10) && (ret != 0)) { - ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x04); - msleep(1); /* wait for VCO auto calibration */ - i++; - } - - ret = stv6110_read_reg(fe, RSTV6110_STAT1); - stv6110_get_frequency(fe, &result_freq); - - vco_freq = divider * ((priv->mclk / 1000) / ((1 << (r_div_opt + 1)))); - dprintk("%s, stat1=%x, lo_freq=%d kHz, vco_frec=%d kHz\n", __func__, - ret, result_freq, vco_freq); - - return 0; -} - -static int stv6110_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff); - - stv6110_set_frequency(fe, c->frequency); - stv6110_set_bandwidth(fe, bandwidth); - - return 0; -} - -static int stv6110_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct stv6110_priv *priv = fe->tuner_priv; - u8 r8 = 0; - u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - stv6110_read_regs(fe, regs, 0, 8); - - /* CF */ - r8 = priv->regs[RSTV6110_CTRL3] & 0x1f; - *bandwidth = (r8 + 5) * 2000000;/* x2 for ZIF tuner BW/2 = F+5 Mhz */ - - return 0; -} - -static struct dvb_tuner_ops stv6110_tuner_ops = { - .info = { - .name = "ST STV6110", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_step = 1000, - }, - .init = stv6110_init, - .release = stv6110_release, - .sleep = stv6110_sleep, - .set_params = stv6110_set_params, - .get_frequency = stv6110_get_frequency, - .set_frequency = stv6110_set_frequency, - .get_bandwidth = stv6110_get_bandwidth, - .set_bandwidth = stv6110_set_bandwidth, - -}; - -struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, - const struct stv6110_config *config, - struct i2c_adapter *i2c) -{ - struct stv6110_priv *priv = NULL; - u8 reg0[] = { 0x00, 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e }; - - struct i2c_msg msg[] = { - { - .addr = config->i2c_address, - .flags = 0, - .buf = reg0, - .len = 9 - } - }; - int ret; - - /* divisor value for the output clock */ - reg0[2] &= ~0xc0; - reg0[2] |= (config->clk_div << 6); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = i2c_transfer(i2c, msg, 1); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (ret != 1) - return NULL; - - priv = kzalloc(sizeof(struct stv6110_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c_address = config->i2c_address; - priv->i2c = i2c; - priv->mclk = config->mclk; - priv->clk_div = config->clk_div; - priv->gain = config->gain; - - memcpy(&priv->regs, ®0[1], 8); - - memcpy(&fe->ops.tuner_ops, &stv6110_tuner_ops, - sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - printk(KERN_INFO "STV6110 attached on addr=%x!\n", priv->i2c_address); - - return fe; -} -EXPORT_SYMBOL(stv6110_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("ST STV6110 driver"); -MODULE_AUTHOR("Igor M. Liplianin"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* - * stv6110.h - * - * Driver for ST STV6110 satellite tuner IC. - * - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __DVB_STV6110_H__ -#define __DVB_STV6110_H__ - -#include -#include "dvb_frontend.h" - -/* registers */ -#define RSTV6110_CTRL1 0 -#define RSTV6110_CTRL2 1 -#define RSTV6110_TUNING1 2 -#define RSTV6110_TUNING2 3 -#define RSTV6110_CTRL3 4 -#define RSTV6110_STAT1 5 -#define RSTV6110_STAT2 6 -#define RSTV6110_STAT3 7 - -struct stv6110_config { - u8 i2c_address; - u32 mclk; - u8 gain; - u8 clk_div; /* divisor value for the output clock */ -}; - -#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \ - && defined(MODULE)) -extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, - const struct stv6110_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, - const struct stv6110_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,405 +0,0 @@ -/* - STV6110(A) Silicon tuner driver - - Copyright (C) Manu Abraham - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "stv6110x_reg.h" -#include "stv6110x.h" -#include "stv6110x_priv.h" - -static unsigned int verbose; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "Set Verbosity level"); - -static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data) -{ - int ret; - const struct stv6110x_config *config = stv6110x->config; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { .addr = config->addr, .flags = 0, .buf = b0, .len = 1 }, - { .addr = config->addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } - }; - - ret = i2c_transfer(stv6110x->i2c, msg, 2); - if (ret != 2) { - dprintk(FE_ERROR, 1, "I/O Error"); - return -EREMOTEIO; - } - *data = b1[0]; - - return 0; -} - -static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 data[], int len) -{ - int ret; - const struct stv6110x_config *config = stv6110x->config; - u8 buf[len + 1]; - struct i2c_msg msg = { - .addr = config->addr, - .flags = 0, - .buf = buf, - .len = len + 1 - }; - - if (start + len > 8) - return -EINVAL; - - buf[0] = start; - memcpy(&buf[1], data, len); - - ret = i2c_transfer(stv6110x->i2c, &msg, 1); - if (ret != 1) { - dprintk(FE_ERROR, 1, "I/O Error"); - return -EREMOTEIO; - } - - return 0; -} - -static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data) -{ - return stv6110x_write_regs(stv6110x, reg, &data, 1); -} - -static int stv6110x_init(struct dvb_frontend *fe) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - int ret; - - ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs, - ARRAY_SIZE(stv6110x->regs)); - if (ret < 0) { - dprintk(FE_ERROR, 1, "Initialization failed"); - return -1; - } - - return 0; -} - -static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - u32 rDiv, divider; - s32 pVal, pCalc, rDivOpt = 0, pCalcOpt = 1000; - u8 i; - - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16)); - - if (frequency <= 1023000) { - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0); - pVal = 40; - } else if (frequency <= 1300000) { - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1); - pVal = 40; - } else if (frequency <= 2046000) { - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0); - pVal = 20; - } else { - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1); - pVal = 20; - } - - for (rDiv = 0; rDiv <= 3; rDiv++) { - pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv); - - if ((abs((s32)(pCalc - pVal))) < (abs((s32)(pCalcOpt - pVal)))) - rDivOpt = rDiv; - - pCalcOpt = (REFCLOCK_kHz / 100) / R_DIV(rDivOpt); - } - - divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz; - divider = (divider + 5) / 10; - - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider)); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider)); - - /* VCO Auto calibration */ - STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1); - - stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]); - stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x->regs[STV6110x_TNG1]); - stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x->regs[STV6110x_TNG0]); - stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]); - - for (i = 0; i < TRIALS; i++) { - stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]); - if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x->regs[STV6110x_STAT1])) - break; - msleep(1); - } - - return 0; -} - -static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - - stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x->regs[STV6110x_TNG1]); - stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x->regs[STV6110x_TNG0]); - - *frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x->regs[STV6110x_TNG1]), - STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x->regs[STV6110x_TNG0]))) * REFCLOCK_kHz; - - *frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x->regs[STV6110x_TNG1]) + - STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x->regs[STV6110x_TNG1]))); - - *frequency >>= 2; - - return 0; -} - -static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - u32 halfbw; - u8 i; - - halfbw = bandwidth >> 1; - - if (halfbw > 36000000) - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */ - else if (halfbw < 5000000) - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */ - else - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */ - - - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */ - STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */ - - stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]); - stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]); - - for (i = 0; i < TRIALS; i++) { - stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]); - if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x->regs[STV6110x_STAT1])) - break; - msleep(1); - } - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */ - stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]); - - return 0; -} - -static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - - stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x->regs[STV6110x_CTRL3]); - *bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x->regs[STV6110x_CTRL3]) + 5) * 2000000; - - return 0; -} - -static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - - /* setup divider */ - switch (refclock) { - default: - case 1: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0); - break; - case 2: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1); - break; - case 4: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2); - break; - case 8: - case 0: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3); - break; - } - stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]); - - return 0; -} - -static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - - stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x->regs[STV6110x_CTRL2]); - *gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x->regs[STV6110x_CTRL2]); - - return 0; -} - -static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2); - stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]); - - return 0; -} - -static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - int ret; - - switch (mode) { - case TUNER_SLEEP: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 0); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 0); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 0); - break; - - case TUNER_WAKE: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 1); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 1); - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 1); - break; - } - - ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]); - if (ret < 0) { - dprintk(FE_ERROR, 1, "I/O Error"); - return -EIO; - } - - return 0; -} - -static int stv6110x_sleep(struct dvb_frontend *fe) -{ - if (fe->tuner_priv) - return stv6110x_set_mode(fe, TUNER_SLEEP); - - return 0; -} - -static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - - stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]); - - if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x->regs[STV6110x_STAT1])) - *status = TUNER_PHASELOCKED; - else - *status = 0; - - return 0; -} - - -static int stv6110x_release(struct dvb_frontend *fe) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(stv6110x); - - return 0; -} - -static struct dvb_tuner_ops stv6110x_ops = { - .info = { - .name = "STV6110(A) Silicon Tuner", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_step = 0, - }, - .release = stv6110x_release -}; - -static struct stv6110x_devctl stv6110x_ctl = { - .tuner_init = stv6110x_init, - .tuner_sleep = stv6110x_sleep, - .tuner_set_mode = stv6110x_set_mode, - .tuner_set_frequency = stv6110x_set_frequency, - .tuner_get_frequency = stv6110x_get_frequency, - .tuner_set_bandwidth = stv6110x_set_bandwidth, - .tuner_get_bandwidth = stv6110x_get_bandwidth, - .tuner_set_bbgain = stv6110x_set_bbgain, - .tuner_get_bbgain = stv6110x_get_bbgain, - .tuner_set_refclk = stv6110x_set_refclock, - .tuner_get_status = stv6110x_get_status, -}; - -struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, - const struct stv6110x_config *config, - struct i2c_adapter *i2c) -{ - struct stv6110x_state *stv6110x; - u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e}; - - stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL); - if (!stv6110x) - return NULL; - - stv6110x->i2c = i2c; - stv6110x->config = config; - stv6110x->devctl = &stv6110x_ctl; - memcpy(stv6110x->regs, default_regs, 8); - - /* setup divider */ - switch (stv6110x->config->clk_div) { - default: - case 1: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0); - break; - case 2: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1); - break; - case 4: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2); - break; - case 8: - case 0: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3); - break; - } - - fe->tuner_priv = stv6110x; - fe->ops.tuner_ops = stv6110x_ops; - - printk(KERN_INFO "%s: Attaching STV6110x\n", __func__); - return stv6110x->devctl; -} -EXPORT_SYMBOL(stv6110x_attach); - -MODULE_AUTHOR("Manu Abraham"); -MODULE_DESCRIPTION("STV6110x Silicon tuner"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* - STV6110(A) Silicon tuner driver - - Copyright (C) Manu Abraham - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STV6110x_H -#define __STV6110x_H - -struct stv6110x_config { - u8 addr; - u32 refclk; - u8 clk_div; /* divisor value for the output clock */ -}; - -enum tuner_mode { - TUNER_SLEEP = 1, - TUNER_WAKE, -}; - -enum tuner_status { - TUNER_PHASELOCKED = 1, -}; - -struct stv6110x_devctl { - int (*tuner_init) (struct dvb_frontend *fe); - int (*tuner_sleep) (struct dvb_frontend *fe); - int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); - int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); - int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency); - int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth); - int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth); - int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain); - int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain); - int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk); - int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status); -}; - - -#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE)) - -extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, - const struct stv6110x_config *config, - struct i2c_adapter *i2c); - -#else -static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, - const struct stv6110x_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -#endif /* CONFIG_DVB_STV6110x */ - -#endif /* __STV6110x_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/* - STV6110(A) Silicon tuner driver - - Copyright (C) Manu Abraham - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STV6110x_PRIV_H -#define __STV6110x_PRIV_H - -#define FE_ERROR 0 -#define FE_NOTICE 1 -#define FE_INFO 2 -#define FE_DEBUG 3 -#define FE_DEBUGREG 4 - -#define dprintk(__y, __z, format, arg...) do { \ - if (__z) { \ - if ((verbose > FE_ERROR) && (verbose > __y)) \ - printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ - else if ((verbose > FE_NOTICE) && (verbose > __y)) \ - printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ - else if ((verbose > FE_INFO) && (verbose > __y)) \ - printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ - else if ((verbose > FE_DEBUG) && (verbose > __y)) \ - printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ - } else { \ - if (verbose > __y) \ - printk(format, ##arg); \ - } \ -} while (0) - - -#define STV6110x_SETFIELD(mask, bitf, val) \ - (mask = (mask & (~(((1 << STV6110x_WIDTH_##bitf) - 1) << \ - STV6110x_OFFST_##bitf))) | \ - (val << STV6110x_OFFST_##bitf)) - -#define STV6110x_GETFIELD(bitf, val) \ - ((val >> STV6110x_OFFST_##bitf) & \ - ((1 << STV6110x_WIDTH_##bitf) - 1)) - -#define MAKEWORD16(a, b) (((a) << 8) | (b)) - -#define LSB(x) ((x & 0xff)) -#define MSB(y) ((y >> 8) & 0xff) - -#define TRIALS 10 -#define R_DIV(__div) (1 << (__div + 1)) -#define REFCLOCK_kHz (stv6110x->config->refclk / 1000) -#define REFCLOCK_MHz (stv6110x->config->refclk / 1000000) - -struct stv6110x_state { - struct i2c_adapter *i2c; - const struct stv6110x_config *config; - u8 regs[8]; - - struct stv6110x_devctl *devctl; -}; - -#endif /* __STV6110x_PRIV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x_reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/stv6110x_reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* - STV6110(A) Silicon tuner driver - - Copyright (C) Manu Abraham - - Copyright (C) ST Microelectronics - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __STV6110x_REG_H -#define __STV6110x_REG_H - -#define STV6110x_CTRL1 0x00 -#define STV6110x_OFFST_CTRL1_K 3 -#define STV6110x_WIDTH_CTRL1_K 5 -#define STV6110x_OFFST_CTRL1_LPT 2 -#define STV6110x_WIDTH_CTRL1_LPT 1 -#define STV6110x_OFFST_CTRL1_RX 1 -#define STV6110x_WIDTH_CTRL1_RX 1 -#define STV6110x_OFFST_CTRL1_SYN 0 -#define STV6110x_WIDTH_CTRL1_SYN 1 - -#define STV6110x_CTRL2 0x01 -#define STV6110x_OFFST_CTRL2_CO_DIV 6 -#define STV6110x_WIDTH_CTRL2_CO_DIV 2 -#define STV6110x_OFFST_CTRL2_RSVD 5 -#define STV6110x_WIDTH_CTRL2_RSVD 1 -#define STV6110x_OFFST_CTRL2_REFOUT_SEL 4 -#define STV6110x_WIDTH_CTRL2_REFOUT_SEL 1 -#define STV6110x_OFFST_CTRL2_BBGAIN 0 -#define STV6110x_WIDTH_CTRL2_BBGAIN 4 - -#define STV6110x_TNG0 0x02 -#define STV6110x_OFFST_TNG0_N_DIV_7_0 0 -#define STV6110x_WIDTH_TNG0_N_DIV_7_0 8 - -#define STV6110x_TNG1 0x03 -#define STV6110x_OFFST_TNG1_R_DIV 6 -#define STV6110x_WIDTH_TNG1_R_DIV 2 -#define STV6110x_OFFST_TNG1_PRESC32_ON 5 -#define STV6110x_WIDTH_TNG1_PRESC32_ON 1 -#define STV6110x_OFFST_TNG1_DIV4SEL 4 -#define STV6110x_WIDTH_TNG1_DIV4SEL 1 -#define STV6110x_OFFST_TNG1_N_DIV_11_8 0 -#define STV6110x_WIDTH_TNG1_N_DIV_11_8 4 - - -#define STV6110x_CTRL3 0x04 -#define STV6110x_OFFST_CTRL3_DCLOOP_OFF 7 -#define STV6110x_WIDTH_CTRL3_DCLOOP_OFF 1 -#define STV6110x_OFFST_CTRL3_RCCLK_OFF 6 -#define STV6110x_WIDTH_CTRL3_RCCLK_OFF 1 -#define STV6110x_OFFST_CTRL3_ICP 5 -#define STV6110x_WIDTH_CTRL3_ICP 1 -#define STV6110x_OFFST_CTRL3_CF 0 -#define STV6110x_WIDTH_CTRL3_CF 5 - -#define STV6110x_STAT1 0x05 -#define STV6110x_OFFST_STAT1_CALVCO_STRT 2 -#define STV6110x_WIDTH_STAT1_CALVCO_STRT 1 -#define STV6110x_OFFST_STAT1_CALRC_STRT 1 -#define STV6110x_WIDTH_STAT1_CALRC_STRT 1 -#define STV6110x_OFFST_STAT1_LOCK 0 -#define STV6110x_WIDTH_STAT1_LOCK 1 - -#define STV6110x_STAT2 0x06 -#define STV6110x_STAT3 0x07 - -#endif /* __STV6110x_REG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10021.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10021.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10021.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10021.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,489 +0,0 @@ -/* - TDA10021 - Single Chip Cable Channel Receiver driver module - used on the Siemens DVB-C cards - - Copyright (C) 1999 Convergence Integrated Media GmbH - Copyright (C) 2004 Markus Schulz - Support for TDA10021 - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "tda1002x.h" - - -struct tda10021_state { - struct i2c_adapter* i2c; - /* configuration settings */ - const struct tda1002x_config* config; - struct dvb_frontend frontend; - - u8 pwm; - u8 reg0; -}; - - -#if 0 -#define dprintk(x...) printk(x) -#else -#define dprintk(x...) -#endif - -static int verbose; - -#define XIN 57840000UL - -#define FIN (XIN >> 4) - -static int tda10021_inittab_size = 0x40; -static u8 tda10021_inittab[0x40]= -{ - 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a, - 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40, - 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff, - 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58, - 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00, - 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00, -}; - -static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - int ret; - - ret = i2c_transfer (state->i2c, &msg, 1); - if (ret != 1) - printk("DVB: TDA10021(%d): %s, writereg error " - "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", - state->frontend.dvb->num, __func__, reg, data, ret); - - msleep(10); - return (ret != 1) ? -EREMOTEIO : 0; -} - -static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) -{ - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - int ret; - - ret = i2c_transfer (state->i2c, msg, 2); - // Don't print an error message if the id is read. - if (ret != 2 && reg != 0x1a) - printk("DVB: TDA10021: %s: readreg error (ret == %i)\n", - __func__, ret); - return b1[0]; -} - -//get access to tuner -static int lock_tuner(struct tda10021_state* state) -{ - u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 }; - struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; - - if(i2c_transfer(state->i2c, &msg, 1) != 1) - { - printk("tda10021: lock tuner fails\n"); - return -EREMOTEIO; - } - return 0; -} - -//release access from tuner -static int unlock_tuner(struct tda10021_state* state) -{ - u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f }; - struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; - - if(i2c_transfer(state->i2c, &msg_post, 1) != 1) - { - printk("tda10021: unlock tuner fails\n"); - return -EREMOTEIO; - } - return 0; -} - -static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0, - fe_spectral_inversion_t inversion) -{ - reg0 |= state->reg0 & 0x63; - - if ((INVERSION_ON == inversion) ^ (state->config->invert == 0)) - reg0 &= ~0x20; - else - reg0 |= 0x20; - - _tda10021_writereg (state, 0x00, reg0 & 0xfe); - _tda10021_writereg (state, 0x00, reg0 | 0x01); - - state->reg0 = reg0; - return 0; -} - -static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate) -{ - s32 BDR; - s32 BDRI; - s16 SFIL=0; - u16 NDEC = 0; - u32 tmp, ratio; - - if (symbolrate > XIN/2) - symbolrate = XIN/2; - if (symbolrate < 500000) - symbolrate = 500000; - - if (symbolrate < XIN/16) NDEC = 1; - if (symbolrate < XIN/32) NDEC = 2; - if (symbolrate < XIN/64) NDEC = 3; - - if (symbolrate < (u32)(XIN/12.3)) SFIL = 1; - if (symbolrate < (u32)(XIN/16)) SFIL = 0; - if (symbolrate < (u32)(XIN/24.6)) SFIL = 1; - if (symbolrate < (u32)(XIN/32)) SFIL = 0; - if (symbolrate < (u32)(XIN/49.2)) SFIL = 1; - if (symbolrate < (u32)(XIN/64)) SFIL = 0; - if (symbolrate < (u32)(XIN/98.4)) SFIL = 1; - - symbolrate <<= NDEC; - ratio = (symbolrate << 4) / FIN; - tmp = ((symbolrate << 4) % FIN) << 8; - ratio = (ratio << 8) + tmp / FIN; - tmp = (tmp % FIN) << 8; - ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN); - - BDR = ratio; - BDRI = (((XIN << 5) / symbolrate) + 1) / 2; - - if (BDRI > 0xFF) - BDRI = 0xFF; - - SFIL = (SFIL << 4) | tda10021_inittab[0x0E]; - - NDEC = (NDEC << 6) | tda10021_inittab[0x03]; - - _tda10021_writereg (state, 0x03, NDEC); - _tda10021_writereg (state, 0x0a, BDR&0xff); - _tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff); - _tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f); - - _tda10021_writereg (state, 0x0d, BDRI); - _tda10021_writereg (state, 0x0e, SFIL); - - return 0; -} - -static int tda10021_init (struct dvb_frontend *fe) -{ - struct tda10021_state* state = fe->demodulator_priv; - int i; - - dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num); - - //_tda10021_writereg (fe, 0, 0); - - for (i=0; ipwm); - - //Comment by markus - //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0) - //0x2A[4] == BYPPLL -> Power down mode (default 1) - //0x2A[5] == LCK -> PLL Lock Flag - //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0) - - //Activate PLL - _tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef); - return 0; -} - -static int tda10021_set_parameters (struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct tda10021_state* state = fe->demodulator_priv; - - //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256 - //CONF - static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c, 0x10 }; - //AGCREF value - static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78, 0x5c }; - //LTHR value - static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36, 0x26 }; - //MSETH - static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34, 0x23 }; - //AREF - static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e, 0x6b }; - - int qam = p->u.qam.modulation; - - if (qam < 0 || qam > 5) - return -EINVAL; - - if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF) - return -EINVAL; - - //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - tda10021_set_symbolrate (state, p->u.qam.symbol_rate); - _tda10021_writereg (state, 0x34, state->pwm); - - _tda10021_writereg (state, 0x01, reg0x01[qam]); - _tda10021_writereg (state, 0x05, reg0x05[qam]); - _tda10021_writereg (state, 0x08, reg0x08[qam]); - _tda10021_writereg (state, 0x09, reg0x09[qam]); - - tda10021_setup_reg0 (state, reg0x00[qam], p->inversion); - - return 0; -} - -static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct tda10021_state* state = fe->demodulator_priv; - int sync; - - *status = 0; - //0x11[0] == EQALGO -> Equalizer algorithms state - //0x11[1] == CARLOCK -> Carrier locked - //0x11[2] == FSYNC -> Frame synchronisation - //0x11[3] == FEL -> Front End locked - //0x11[6] == NODVB -> DVB Mode Information - sync = tda10021_readreg (state, 0x11); - - if (sync & 2) - *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; - - if (sync & 4) - *status |= FE_HAS_SYNC|FE_HAS_VITERBI; - - if (sync & 8) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct tda10021_state* state = fe->demodulator_priv; - - u32 _ber = tda10021_readreg(state, 0x14) | - (tda10021_readreg(state, 0x15) << 8) | - ((tda10021_readreg(state, 0x16) & 0x0f) << 16); - _tda10021_writereg(state, 0x10, (tda10021_readreg(state, 0x10) & ~0xc0) - | (tda10021_inittab[0x10] & 0xc0)); - *ber = 10 * _ber; - - return 0; -} - -static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct tda10021_state* state = fe->demodulator_priv; - - u8 config = tda10021_readreg(state, 0x02); - u8 gain = tda10021_readreg(state, 0x17); - if (config & 0x02) - /* the agc value is inverted */ - gain = ~gain; - *strength = (gain << 8) | gain; - - return 0; -} - -static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct tda10021_state* state = fe->demodulator_priv; - - u8 quality = ~tda10021_readreg(state, 0x18); - *snr = (quality << 8) | quality; - - return 0; -} - -static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct tda10021_state* state = fe->demodulator_priv; - - *ucblocks = tda10021_readreg (state, 0x13) & 0x7f; - if (*ucblocks == 0x7f) - *ucblocks = 0xffffffff; - - /* reset uncorrected block counter */ - _tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf); - _tda10021_writereg (state, 0x10, tda10021_inittab[0x10]); - - return 0; -} - -static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct tda10021_state* state = fe->demodulator_priv; - int sync; - s8 afc = 0; - - sync = tda10021_readreg(state, 0x11); - afc = tda10021_readreg(state, 0x19); - if (verbose) { - /* AFC only valid when carrier has been recovered */ - printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" : - "DVB: TDA10021(%d): [AFC (%d) %dHz]\n", - state->frontend.dvb->num, afc, - -((s32)p->u.qam.symbol_rate * afc) >> 10); - } - - p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF; - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; - - p->u.qam.fec_inner = FEC_NONE; - p->frequency = ((p->frequency + 31250) / 62500) * 62500; - - if (sync & 2) - p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; - - return 0; -} - -static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct tda10021_state* state = fe->demodulator_priv; - - if (enable) { - lock_tuner(state); - } else { - unlock_tuner(state); - } - return 0; -} - -static int tda10021_sleep(struct dvb_frontend* fe) -{ - struct tda10021_state* state = fe->demodulator_priv; - - _tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */ - _tda10021_writereg (state, 0x00, 0x80); /* standby */ - - return 0; -} - -static void tda10021_release(struct dvb_frontend* fe) -{ - struct tda10021_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops tda10021_ops; - -struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, - struct i2c_adapter* i2c, - u8 pwm) -{ - struct tda10021_state* state = NULL; - u8 id; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct tda10021_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->pwm = pwm; - state->reg0 = tda10021_inittab[0]; - - /* check if the demod is there */ - id = tda10021_readreg(state, 0x1a); - if ((id & 0xf0) != 0x70) goto error; - - /* Don't claim TDA10023 */ - if (id == 0x7d) - goto error; - - printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n", - state->config->demod_address, id); - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops tda10021_ops = { - - .info = { - .name = "Philips TDA10021 DVB-C", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 47000000, - .frequency_max = 862000000, - .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ - .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ - #if 0 - .frequency_tolerance = ???, - .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ - #endif - .caps = 0x400 | //FE_CAN_QAM_4 - FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO - }, - - .release = tda10021_release, - - .init = tda10021_init, - .sleep = tda10021_sleep, - .i2c_gate_ctrl = tda10021_i2c_gate_ctrl, - - .set_frontend = tda10021_set_parameters, - .get_frontend = tda10021_get_frontend, - - .read_status = tda10021_read_status, - .read_ber = tda10021_read_ber, - .read_signal_strength = tda10021_read_signal_strength, - .read_snr = tda10021_read_snr, - .read_ucblocks = tda10021_read_ucblocks, -}; - -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting"); - -MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver"); -MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(tda10021_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10023.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10023.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10023.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10023.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,573 +0,0 @@ -/* - TDA10023 - DVB-C decoder - (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card) - - Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de) - Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com) - - Remotely based on tda10021.c - Copyright (C) 1999 Convergence Integrated Media GmbH - Copyright (C) 2004 Markus Schulz - Support for TDA10021 - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "dvb_frontend.h" -#include "tda1002x.h" - -#define REG0_INIT_VAL 0x23 - -struct tda10023_state { - struct i2c_adapter* i2c; - /* configuration settings */ - const struct tda10023_config *config; - struct dvb_frontend frontend; - - u8 pwm; - u8 reg0; - - /* clock settings */ - u32 xtal; - u8 pll_m; - u8 pll_p; - u8 pll_n; - u32 sysclk; -}; - -#define dprintk(x...) - -static int verbose; - -static u8 tda10023_readreg (struct tda10023_state* state, u8 reg) -{ - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - int ret; - - ret = i2c_transfer (state->i2c, msg, 2); - if (ret != 2) { - int num = state->frontend.dvb ? state->frontend.dvb->num : -1; - printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error " - "(reg == 0x%02x, ret == %i)\n", - num, __func__, reg, ret); - } - return b1[0]; -} - -static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data) -{ - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - int ret; - - ret = i2c_transfer (state->i2c, &msg, 1); - if (ret != 1) { - int num = state->frontend.dvb ? state->frontend.dvb->num : -1; - printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error " - "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", - num, __func__, reg, data, ret); - } - return (ret != 1) ? -EREMOTEIO : 0; -} - - -static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data) -{ - if (mask==0xff) - return tda10023_writereg(state, reg, data); - else { - u8 val; - val=tda10023_readreg(state,reg); - val&=~mask; - val|=(data&mask); - return tda10023_writereg(state, reg, val); - } -} - -static void tda10023_writetab(struct tda10023_state* state, u8* tab) -{ - u8 r,m,v; - while (1) { - r=*tab++; - m=*tab++; - v=*tab++; - if (r==0xff) { - if (m==0xff) - break; - else - msleep(m); - } - else - tda10023_writebit(state,r,m,v); - } -} - -//get access to tuner -static int lock_tuner(struct tda10023_state* state) -{ - u8 buf[2] = { 0x0f, 0xc0 }; - struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; - - if(i2c_transfer(state->i2c, &msg, 1) != 1) - { - printk("tda10023: lock tuner fails\n"); - return -EREMOTEIO; - } - return 0; -} - -//release access from tuner -static int unlock_tuner(struct tda10023_state* state) -{ - u8 buf[2] = { 0x0f, 0x40 }; - struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; - - if(i2c_transfer(state->i2c, &msg_post, 1) != 1) - { - printk("tda10023: unlock tuner fails\n"); - return -EREMOTEIO; - } - return 0; -} - -static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0) -{ - reg0 |= state->reg0 & 0x63; - - tda10023_writereg (state, 0x00, reg0 & 0xfe); - tda10023_writereg (state, 0x00, reg0 | 0x01); - - state->reg0 = reg0; - return 0; -} - -static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) -{ - s32 BDR; - s32 BDRI; - s16 SFIL=0; - u16 NDEC = 0; - - /* avoid floating point operations multiplying syscloc and divider - by 10 */ - u32 sysclk_x_10 = state->sysclk * 10; - - if (sr < (u32)(sysclk_x_10/984)) { - NDEC=3; - SFIL=1; - } else if (sr < (u32)(sysclk_x_10/640)) { - NDEC=3; - SFIL=0; - } else if (sr < (u32)(sysclk_x_10/492)) { - NDEC=2; - SFIL=1; - } else if (sr < (u32)(sysclk_x_10/320)) { - NDEC=2; - SFIL=0; - } else if (sr < (u32)(sysclk_x_10/246)) { - NDEC=1; - SFIL=1; - } else if (sr < (u32)(sysclk_x_10/160)) { - NDEC=1; - SFIL=0; - } else if (sr < (u32)(sysclk_x_10/123)) { - NDEC=0; - SFIL=1; - } - - BDRI = (state->sysclk)*16; - BDRI>>=NDEC; - BDRI +=sr/2; - BDRI /=sr; - - if (BDRI>255) - BDRI=255; - - { - u64 BDRX; - - BDRX=1<<(24+NDEC); - BDRX*=sr; - do_div(BDRX, state->sysclk); /* BDRX/=SYSCLK; */ - - BDR=(s32)BDRX; - } - dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n", - sr, BDR, BDRI, NDEC); - tda10023_writebit (state, 0x03, 0xc0, NDEC<<6); - tda10023_writereg (state, 0x0a, BDR&255); - tda10023_writereg (state, 0x0b, (BDR>>8)&255); - tda10023_writereg (state, 0x0c, (BDR>>16)&31); - tda10023_writereg (state, 0x0d, BDRI); - tda10023_writereg (state, 0x3d, (SFIL<<7)); - return 0; -} - -static int tda10023_init (struct dvb_frontend *fe) -{ - struct tda10023_state* state = fe->demodulator_priv; - u8 tda10023_inittab[] = { -/* reg mask val */ -/* 000 */ 0x2a, 0xff, 0x02, /* PLL3, Bypass, Power Down */ -/* 003 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ -/* 006 */ 0x2a, 0xff, 0x03, /* PLL3, Bypass, Power Down */ -/* 009 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ - /* PLL1 */ -/* 012 */ 0x28, 0xff, (state->pll_m-1), - /* PLL2 */ -/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1), - /* GPR FSAMPLING=1 */ -/* 018 */ 0x00, 0xff, REG0_INIT_VAL, -/* 021 */ 0x2a, 0xff, 0x08, /* PLL3 PSACLK=1 */ -/* 024 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ -/* 027 */ 0x1f, 0xff, 0x00, /* RESET */ -/* 030 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ -/* 033 */ 0xe6, 0x0c, 0x04, /* RSCFG_IND */ -/* 036 */ 0x10, 0xc0, 0x80, /* DECDVBCFG1 PBER=1 */ - -/* 039 */ 0x0e, 0xff, 0x82, /* GAIN1 */ -/* 042 */ 0x03, 0x08, 0x08, /* CLKCONF DYN=1 */ -/* 045 */ 0x2e, 0xbf, 0x30, /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 - PPWMTUN=0 PPWMIF=0 */ -/* 048 */ 0x01, 0xff, 0x30, /* AGCREF */ -/* 051 */ 0x1e, 0x84, 0x84, /* CONTROL SACLK_ON=1 */ -/* 054 */ 0x1b, 0xff, 0xc8, /* ADC TWOS=1 */ -/* 057 */ 0x3b, 0xff, 0xff, /* IFMAX */ -/* 060 */ 0x3c, 0xff, 0x00, /* IFMIN */ -/* 063 */ 0x34, 0xff, 0x00, /* PWMREF */ -/* 066 */ 0x35, 0xff, 0xff, /* TUNMAX */ -/* 069 */ 0x36, 0xff, 0x00, /* TUNMIN */ -/* 072 */ 0x06, 0xff, 0x7f, /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */ -/* 075 */ 0x1c, 0x30, 0x30, /* EQCONF2 STEPALGO=SGNALGO=1 */ -/* 078 */ 0x37, 0xff, 0xf6, /* DELTAF_LSB */ -/* 081 */ 0x38, 0xff, 0xff, /* DELTAF_MSB */ -/* 084 */ 0x02, 0xff, 0x93, /* AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 */ -/* 087 */ 0x2d, 0xff, 0xf6, /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */ -/* 090 */ 0x04, 0x10, 0x00, /* SWRAMP=1 */ -/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /* - INTP1 POCLKP=1 FEL=1 MFS=0 */ -/* 096 */ 0x2b, 0x01, 0xa1, /* INTS1 */ -/* 099 */ 0x20, 0xff, 0x04, /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */ -/* 102 */ 0x2c, 0xff, 0x0d, /* INTP/S TRIP=0 TRIS=0 */ -/* 105 */ 0xc4, 0xff, 0x00, -/* 108 */ 0xc3, 0x30, 0x00, -/* 111 */ 0xb5, 0xff, 0x19, /* ERAGC_THD */ -/* 114 */ 0x00, 0x03, 0x01, /* GPR, CLBS soft reset */ -/* 117 */ 0x00, 0x03, 0x03, /* GPR, CLBS soft reset */ -/* 120 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ -/* 123 */ 0xff, 0xff, 0xff -}; - dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num); - - /* override default values if set in config */ - if (state->config->deltaf) { - tda10023_inittab[80] = (state->config->deltaf & 0xff); - tda10023_inittab[83] = (state->config->deltaf >> 8); - } - - if (state->config->output_mode) - tda10023_inittab[95] = state->config->output_mode; - - tda10023_writetab(state, tda10023_inittab); - - return 0; -} - -static int tda10023_set_parameters (struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct tda10023_state* state = fe->demodulator_priv; - - static int qamvals[6][6] = { - // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD - { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM - { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM - { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM - { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM - { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM - { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM - }; - - int qam = p->u.qam.modulation; - - if (qam < 0 || qam > 5) - return -EINVAL; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - tda10023_set_symbolrate (state, p->u.qam.symbol_rate); - tda10023_writereg (state, 0x05, qamvals[qam][1]); - tda10023_writereg (state, 0x08, qamvals[qam][2]); - tda10023_writereg (state, 0x09, qamvals[qam][3]); - tda10023_writereg (state, 0xb4, qamvals[qam][4]); - tda10023_writereg (state, 0xb6, qamvals[qam][5]); - -// tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32)); -// tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20)); - tda10023_writebit (state, 0x04, 0x40, 0x40); - tda10023_setup_reg0 (state, qamvals[qam][0]); - - return 0; -} - -static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct tda10023_state* state = fe->demodulator_priv; - int sync; - - *status = 0; - - //0x11[1] == CARLOCK -> Carrier locked - //0x11[2] == FSYNC -> Frame synchronisation - //0x11[3] == FEL -> Front End locked - //0x11[6] == NODVB -> DVB Mode Information - sync = tda10023_readreg (state, 0x11); - - if (sync & 2) - *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; - - if (sync & 4) - *status |= FE_HAS_SYNC|FE_HAS_VITERBI; - - if (sync & 8) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct tda10023_state* state = fe->demodulator_priv; - u8 a,b,c; - a=tda10023_readreg(state, 0x14); - b=tda10023_readreg(state, 0x15); - c=tda10023_readreg(state, 0x16)&0xf; - tda10023_writebit (state, 0x10, 0xc0, 0x00); - - *ber = a | (b<<8)| (c<<16); - return 0; -} - -static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct tda10023_state* state = fe->demodulator_priv; - u8 ifgain=tda10023_readreg(state, 0x2f); - - u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16; - // Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90 - if (gain>0x90) - gain=gain+2*(gain-0x90); - if (gain>255) - gain=255; - - *strength = (gain<<8)|gain; - return 0; -} - -static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct tda10023_state* state = fe->demodulator_priv; - - u8 quality = ~tda10023_readreg(state, 0x18); - *snr = (quality << 8) | quality; - return 0; -} - -static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct tda10023_state* state = fe->demodulator_priv; - u8 a,b,c,d; - a= tda10023_readreg (state, 0x74); - b= tda10023_readreg (state, 0x75); - c= tda10023_readreg (state, 0x76); - d= tda10023_readreg (state, 0x77); - *ucblocks = a | (b<<8)|(c<<16)|(d<<24); - - tda10023_writebit (state, 0x10, 0x20,0x00); - tda10023_writebit (state, 0x10, 0x20,0x20); - tda10023_writebit (state, 0x13, 0x01, 0x00); - - return 0; -} - -static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct tda10023_state* state = fe->demodulator_priv; - int sync,inv; - s8 afc = 0; - - sync = tda10023_readreg(state, 0x11); - afc = tda10023_readreg(state, 0x19); - inv = tda10023_readreg(state, 0x04); - - if (verbose) { - /* AFC only valid when carrier has been recovered */ - printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" : - "DVB: TDA10023(%d): [AFC (%d) %dHz]\n", - state->frontend.dvb->num, afc, - -((s32)p->u.qam.symbol_rate * afc) >> 10); - } - - p->inversion = (inv&0x20?0:1); - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; - - p->u.qam.fec_inner = FEC_NONE; - p->frequency = ((p->frequency + 31250) / 62500) * 62500; - - if (sync & 2) - p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; - - return 0; -} - -static int tda10023_sleep(struct dvb_frontend* fe) -{ - struct tda10023_state* state = fe->demodulator_priv; - - tda10023_writereg (state, 0x1b, 0x02); /* pdown ADC */ - tda10023_writereg (state, 0x00, 0x80); /* standby */ - - return 0; -} - -static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct tda10023_state* state = fe->demodulator_priv; - - if (enable) { - lock_tuner(state); - } else { - unlock_tuner(state); - } - return 0; -} - -static void tda10023_release(struct dvb_frontend* fe) -{ - struct tda10023_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops tda10023_ops; - -struct dvb_frontend *tda10023_attach(const struct tda10023_config *config, - struct i2c_adapter *i2c, - u8 pwm) -{ - struct tda10023_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* wakeup if in standby */ - tda10023_writereg (state, 0x00, 0x33); - /* check if the demod is there */ - if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); - state->pwm = pwm; - state->reg0 = REG0_INIT_VAL; - if (state->config->xtal) { - state->xtal = state->config->xtal; - state->pll_m = state->config->pll_m; - state->pll_p = state->config->pll_p; - state->pll_n = state->config->pll_n; - } else { - /* set default values if not defined in config */ - state->xtal = 28920000; - state->pll_m = 8; - state->pll_p = 4; - state->pll_n = 1; - } - - /* calc sysclk */ - state->sysclk = (state->xtal * state->pll_m / \ - (state->pll_n * state->pll_p)); - - state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64; - state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4; - - dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n", - __func__, state->xtal, state->pll_m, state->pll_p, - state->pll_n); - - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops tda10023_ops = { - - .info = { - .name = "Philips TDA10023 DVB-C", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 47000000, - .frequency_max = 862000000, - .symbol_rate_min = 0, /* set in tda10023_attach */ - .symbol_rate_max = 0, /* set in tda10023_attach */ - .caps = 0x400 | //FE_CAN_QAM_4 - FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO - }, - - .release = tda10023_release, - - .init = tda10023_init, - .sleep = tda10023_sleep, - .i2c_gate_ctrl = tda10023_i2c_gate_ctrl, - - .set_frontend = tda10023_set_parameters, - .get_frontend = tda10023_get_frontend, - - .read_status = tda10023_read_status, - .read_ber = tda10023_read_ber, - .read_signal_strength = tda10023_read_signal_strength, - .read_snr = tda10023_read_snr, - .read_ucblocks = tda10023_read_ucblocks, -}; - - -MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver"); -MODULE_AUTHOR("Georg Acher, Hartmut Birr"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(tda10023_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1002x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1002x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1002x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1002x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/* - TDA10021/TDA10023 - Single Chip Cable Channel Receiver driver module - used on the the Siemens DVB-C cards - - Copyright (C) 1999 Convergence Integrated Media GmbH - Copyright (C) 2004 Markus Schulz - Support for TDA10021 - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef TDA1002x_H -#define TDA1002x_H - -#include - -struct tda1002x_config { - /* the demodulator's i2c address */ - u8 demod_address; - u8 invert; -}; - -enum tda10023_output_mode { - TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0, - TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1, - TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0, - TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */ -}; - -struct tda10023_config { - /* the demodulator's i2c address */ - u8 demod_address; - u8 invert; - - /* clock settings */ - u32 xtal; /* defaults: 28920000 */ - u8 pll_m; /* defaults: 8 */ - u8 pll_p; /* defaults: 4 */ - u8 pll_n; /* defaults: 1 */ - - /* MPEG2 TS output mode */ - u8 output_mode; - - /* input freq offset + baseband conversion type */ - u16 deltaf; -}; - -#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, - struct i2c_adapter* i2c, u8 pwm); -#else -static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, - struct i2c_adapter* i2c, u8 pwm) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_TDA10021 - -#if defined(CONFIG_DVB_TDA10023) || \ - (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda10023_attach( - const struct tda10023_config *config, - struct i2c_adapter *i2c, u8 pwm); -#else -static inline struct dvb_frontend *tda10023_attach( - const struct tda10023_config *config, - struct i2c_adapter *i2c, u8 pwm) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_TDA10023 - -#endif // TDA1002x_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10048.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10048.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10048.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10048.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1193 +0,0 @@ -/* - NXP TDA10048HN DVB OFDM demodulator driver - - Copyright (C) 2009 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "dvb_math.h" -#include "tda10048.h" - -#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw" -#define TDA10048_DEFAULT_FIRMWARE_SIZE 24878 - -/* Register name definitions */ -#define TDA10048_IDENTITY 0x00 -#define TDA10048_VERSION 0x01 -#define TDA10048_DSP_CODE_CPT 0x0C -#define TDA10048_DSP_CODE_IN 0x0E -#define TDA10048_IN_CONF1 0x10 -#define TDA10048_IN_CONF2 0x11 -#define TDA10048_IN_CONF3 0x12 -#define TDA10048_OUT_CONF1 0x14 -#define TDA10048_OUT_CONF2 0x15 -#define TDA10048_OUT_CONF3 0x16 -#define TDA10048_AUTO 0x18 -#define TDA10048_SYNC_STATUS 0x1A -#define TDA10048_CONF_C4_1 0x1E -#define TDA10048_CONF_C4_2 0x1F -#define TDA10048_CODE_IN_RAM 0x20 -#define TDA10048_CHANNEL_INFO1_R 0x22 -#define TDA10048_CHANNEL_INFO2_R 0x23 -#define TDA10048_CHANNEL_INFO1 0x24 -#define TDA10048_CHANNEL_INFO2 0x25 -#define TDA10048_TIME_ERROR_R 0x26 -#define TDA10048_TIME_ERROR 0x27 -#define TDA10048_FREQ_ERROR_LSB_R 0x28 -#define TDA10048_FREQ_ERROR_MSB_R 0x29 -#define TDA10048_FREQ_ERROR_LSB 0x2A -#define TDA10048_FREQ_ERROR_MSB 0x2B -#define TDA10048_IT_SEL 0x30 -#define TDA10048_IT_STAT 0x32 -#define TDA10048_DSP_AD_LSB 0x3C -#define TDA10048_DSP_AD_MSB 0x3D -#define TDA10048_DSP_REG_LSB 0x3E -#define TDA10048_DSP_REG_MSB 0x3F -#define TDA10048_CONF_TRISTATE1 0x44 -#define TDA10048_CONF_TRISTATE2 0x45 -#define TDA10048_CONF_POLARITY 0x46 -#define TDA10048_GPIO_SP_DS0 0x48 -#define TDA10048_GPIO_SP_DS1 0x49 -#define TDA10048_GPIO_SP_DS2 0x4A -#define TDA10048_GPIO_SP_DS3 0x4B -#define TDA10048_GPIO_OUT_SEL 0x4C -#define TDA10048_GPIO_SELECT 0x4D -#define TDA10048_IC_MODE 0x4E -#define TDA10048_CONF_XO 0x50 -#define TDA10048_CONF_PLL1 0x51 -#define TDA10048_CONF_PLL2 0x52 -#define TDA10048_CONF_PLL3 0x53 -#define TDA10048_CONF_ADC 0x54 -#define TDA10048_CONF_ADC_2 0x55 -#define TDA10048_CONF_C1_1 0x60 -#define TDA10048_CONF_C1_3 0x62 -#define TDA10048_AGC_CONF 0x70 -#define TDA10048_AGC_THRESHOLD_LSB 0x72 -#define TDA10048_AGC_THRESHOLD_MSB 0x73 -#define TDA10048_AGC_RENORM 0x74 -#define TDA10048_AGC_GAINS 0x76 -#define TDA10048_AGC_TUN_MIN 0x78 -#define TDA10048_AGC_TUN_MAX 0x79 -#define TDA10048_AGC_IF_MIN 0x7A -#define TDA10048_AGC_IF_MAX 0x7B -#define TDA10048_AGC_TUN_LEVEL 0x7E -#define TDA10048_AGC_IF_LEVEL 0x7F -#define TDA10048_DIG_AGC_LEVEL 0x81 -#define TDA10048_FREQ_PHY2_LSB 0x86 -#define TDA10048_FREQ_PHY2_MSB 0x87 -#define TDA10048_TIME_INVWREF_LSB 0x88 -#define TDA10048_TIME_INVWREF_MSB 0x89 -#define TDA10048_TIME_WREF_LSB 0x8A -#define TDA10048_TIME_WREF_MID1 0x8B -#define TDA10048_TIME_WREF_MID2 0x8C -#define TDA10048_TIME_WREF_MSB 0x8D -#define TDA10048_NP_OUT 0xA2 -#define TDA10048_CELL_ID_LSB 0xA4 -#define TDA10048_CELL_ID_MSB 0xA5 -#define TDA10048_EXTTPS_ODD 0xAA -#define TDA10048_EXTTPS_EVEN 0xAB -#define TDA10048_TPS_LENGTH 0xAC -#define TDA10048_FREE_REG_1 0xB2 -#define TDA10048_FREE_REG_2 0xB3 -#define TDA10048_CONF_C3_1 0xC0 -#define TDA10048_CVBER_CTRL 0xC2 -#define TDA10048_CBER_NMAX_LSB 0xC4 -#define TDA10048_CBER_NMAX_MSB 0xC5 -#define TDA10048_CBER_LSB 0xC6 -#define TDA10048_CBER_MSB 0xC7 -#define TDA10048_VBER_LSB 0xC8 -#define TDA10048_VBER_MID 0xC9 -#define TDA10048_VBER_MSB 0xCA -#define TDA10048_CVBER_LUT 0xCC -#define TDA10048_UNCOR_CTRL 0xCD -#define TDA10048_UNCOR_CPT_LSB 0xCE -#define TDA10048_UNCOR_CPT_MSB 0xCF -#define TDA10048_SOFT_IT_C3 0xD6 -#define TDA10048_CONF_TS2 0xE0 -#define TDA10048_CONF_TS1 0xE1 - -static unsigned int debug; - -#define dprintk(level, fmt, arg...)\ - do { if (debug >= level)\ - printk(KERN_DEBUG "tda10048: " fmt, ## arg);\ - } while (0) - -struct tda10048_state { - - struct i2c_adapter *i2c; - - /* We'll cache and update the attach config settings */ - struct tda10048_config config; - struct dvb_frontend frontend; - - int fwloaded; - - u32 freq_if_hz; - u32 xtal_hz; - u32 pll_mfactor; - u32 pll_nfactor; - u32 pll_pfactor; - u32 sample_freq; - - enum fe_bandwidth bandwidth; -}; - -static struct init_tab { - u8 reg; - u16 data; -} init_tab[] = { - { TDA10048_CONF_PLL1, 0x08 }, - { TDA10048_CONF_ADC_2, 0x00 }, - { TDA10048_CONF_C4_1, 0x00 }, - { TDA10048_CONF_PLL1, 0x0f }, - { TDA10048_CONF_PLL2, 0x0a }, - { TDA10048_CONF_PLL3, 0x43 }, - { TDA10048_FREQ_PHY2_LSB, 0x02 }, - { TDA10048_FREQ_PHY2_MSB, 0x0a }, - { TDA10048_TIME_WREF_LSB, 0xbd }, - { TDA10048_TIME_WREF_MID1, 0xe4 }, - { TDA10048_TIME_WREF_MID2, 0xa8 }, - { TDA10048_TIME_WREF_MSB, 0x02 }, - { TDA10048_TIME_INVWREF_LSB, 0x04 }, - { TDA10048_TIME_INVWREF_MSB, 0x06 }, - { TDA10048_CONF_C4_1, 0x00 }, - { TDA10048_CONF_C1_1, 0xa8 }, - { TDA10048_AGC_CONF, 0x16 }, - { TDA10048_CONF_C1_3, 0x0b }, - { TDA10048_AGC_TUN_MIN, 0x00 }, - { TDA10048_AGC_TUN_MAX, 0xff }, - { TDA10048_AGC_IF_MIN, 0x00 }, - { TDA10048_AGC_IF_MAX, 0xff }, - { TDA10048_AGC_THRESHOLD_MSB, 0x00 }, - { TDA10048_AGC_THRESHOLD_LSB, 0x70 }, - { TDA10048_CVBER_CTRL, 0x38 }, - { TDA10048_AGC_GAINS, 0x12 }, - { TDA10048_CONF_XO, 0x00 }, - { TDA10048_CONF_TS1, 0x07 }, - { TDA10048_IC_MODE, 0x00 }, - { TDA10048_CONF_TS2, 0xc0 }, - { TDA10048_CONF_TRISTATE1, 0x21 }, - { TDA10048_CONF_TRISTATE2, 0x00 }, - { TDA10048_CONF_POLARITY, 0x00 }, - { TDA10048_CONF_C4_2, 0x04 }, - { TDA10048_CONF_ADC, 0x60 }, - { TDA10048_CONF_ADC_2, 0x10 }, - { TDA10048_CONF_ADC, 0x60 }, - { TDA10048_CONF_ADC_2, 0x00 }, - { TDA10048_CONF_C1_1, 0xa8 }, - { TDA10048_UNCOR_CTRL, 0x00 }, - { TDA10048_CONF_C4_2, 0x04 }, -}; - -static struct pll_tab { - u32 clk_freq_khz; - u32 if_freq_khz; - u8 m, n, p; -} pll_tab[] = { - { TDA10048_CLK_4000, TDA10048_IF_36130, 10, 0, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_3300, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_3500, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_3800, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_4000, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_4300, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 }, -}; - -static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) -{ - struct tda10048_config *config = &state->config; - int ret; - u8 buf[] = { reg, data }; - struct i2c_msg msg = { - .addr = config->demod_address, - .flags = 0, .buf = buf, .len = 2 }; - - dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data); - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - printk("%s: writereg error (ret == %i)\n", __func__, ret); - - return (ret != 1) ? -1 : 0; -} - -static u8 tda10048_readreg(struct tda10048_state *state, u8 reg) -{ - struct tda10048_config *config = &state->config; - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - { .addr = config->demod_address, - .flags = 0, .buf = b0, .len = 1 }, - { .addr = config->demod_address, - .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg); - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - printk(KERN_ERR "%s: readreg error (ret == %i)\n", - __func__, ret); - - return b1[0]; -} - -static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg, - const u8 *data, u16 len) -{ - struct tda10048_config *config = &state->config; - int ret = -EREMOTEIO; - struct i2c_msg msg; - u8 *buf; - - dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len); - - buf = kmalloc(len + 1, GFP_KERNEL); - if (buf == NULL) { - ret = -ENOMEM; - goto error; - } - - *buf = reg; - memcpy(buf + 1, data, len); - - msg.addr = config->demod_address; - msg.flags = 0; - msg.buf = buf; - msg.len = len + 1; - - dprintk(2, "%s(): write len = %d\n", - __func__, msg.len); - - ret = i2c_transfer(state->i2c, &msg, 1); - if (ret != 1) { - printk(KERN_ERR "%s(): writereg error err %i\n", - __func__, ret); - ret = -EREMOTEIO; - } - -error: - kfree(buf); - - return ret; -} - -static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz, - u32 if_hz) -{ - struct tda10048_state *state = fe->demodulator_priv; - u64 t; - - dprintk(1, "%s()\n", __func__); - - if (sample_freq_hz == 0) - return -EINVAL; - - if (if_hz < (sample_freq_hz / 2)) { - /* PHY2 = (if2/fs) * 2^15 */ - t = if_hz; - t *= 10; - t *= 32768; - do_div(t, sample_freq_hz); - t += 5; - do_div(t, 10); - } else { - /* PHY2 = ((IF1-fs)/fs) * 2^15 */ - t = sample_freq_hz - if_hz; - t *= 10; - t *= 32768; - do_div(t, sample_freq_hz); - t += 5; - do_div(t, 10); - t = ~t + 1; - } - - tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t); - tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8)); - - return 0; -} - -static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz, - u32 bw) -{ - struct tda10048_state *state = fe->demodulator_priv; - u64 t, z; - u32 b = 8000000; - - dprintk(1, "%s()\n", __func__); - - if (sample_freq_hz == 0) - return -EINVAL; - - if (bw == BANDWIDTH_6_MHZ) - b = 6000000; - else - if (bw == BANDWIDTH_7_MHZ) - b = 7000000; - - /* WREF = (B / (7 * fs)) * 2^31 */ - t = b * 10; - /* avoid warning: this decimal constant is unsigned only in ISO C90 */ - /* t *= 2147483648 on 32bit platforms */ - t *= (2048 * 1024); - t *= 1024; - z = 7 * sample_freq_hz; - do_div(t, z); - t += 5; - do_div(t, 10); - - tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t); - tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8)); - tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16)); - tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24)); - - return 0; -} - -static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz, - u32 bw) -{ - struct tda10048_state *state = fe->demodulator_priv; - u64 t; - u32 b = 8000000; - - dprintk(1, "%s()\n", __func__); - - if (sample_freq_hz == 0) - return -EINVAL; - - if (bw == BANDWIDTH_6_MHZ) - b = 6000000; - else - if (bw == BANDWIDTH_7_MHZ) - b = 7000000; - - /* INVWREF = ((7 * fs) / B) * 2^5 */ - t = sample_freq_hz; - t *= 7; - t *= 32; - t *= 10; - do_div(t, b); - t += 5; - do_div(t, 10); - - tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t); - tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8)); - - return 0; -} - -static int tda10048_set_bandwidth(struct dvb_frontend *fe, - enum fe_bandwidth bw) -{ - struct tda10048_state *state = fe->demodulator_priv; - dprintk(1, "%s(bw=%d)\n", __func__, bw); - - /* Bandwidth setting may need to be adjusted */ - switch (bw) { - case BANDWIDTH_6_MHZ: - case BANDWIDTH_7_MHZ: - case BANDWIDTH_8_MHZ: - tda10048_set_wref(fe, state->sample_freq, bw); - tda10048_set_invwref(fe, state->sample_freq, bw); - break; - default: - printk(KERN_ERR "%s() invalid bandwidth\n", __func__); - return -EINVAL; - } - - state->bandwidth = bw; - - return 0; -} - -static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw) -{ - struct tda10048_state *state = fe->demodulator_priv; - struct tda10048_config *config = &state->config; - int i; - u32 if_freq_khz; - - dprintk(1, "%s(bw = %d)\n", __func__, bw); - - /* based on target bandwidth and clk we calculate pll factors */ - switch (bw) { - case BANDWIDTH_6_MHZ: - if_freq_khz = config->dtv6_if_freq_khz; - break; - case BANDWIDTH_7_MHZ: - if_freq_khz = config->dtv7_if_freq_khz; - break; - case BANDWIDTH_8_MHZ: - if_freq_khz = config->dtv8_if_freq_khz; - break; - default: - printk(KERN_ERR "%s() no default\n", __func__); - return -EINVAL; - } - - for (i = 0; i < ARRAY_SIZE(pll_tab); i++) { - if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) && - (pll_tab[i].if_freq_khz == if_freq_khz)) { - - state->freq_if_hz = pll_tab[i].if_freq_khz * 1000; - state->xtal_hz = pll_tab[i].clk_freq_khz * 1000; - state->pll_mfactor = pll_tab[i].m; - state->pll_nfactor = pll_tab[i].n; - state->pll_pfactor = pll_tab[i].p; - break; - } - } - if (i == ARRAY_SIZE(pll_tab)) { - printk(KERN_ERR "%s() Incorrect attach settings\n", - __func__); - return -EINVAL; - } - - dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz); - dprintk(1, "- xtal_hz = %d\n", state->xtal_hz); - dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor); - dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor); - dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor); - - /* Calculate the sample frequency */ - state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45); - state->sample_freq /= (state->pll_nfactor + 1); - state->sample_freq /= (state->pll_pfactor + 4); - dprintk(1, "- sample_freq = %d\n", state->sample_freq); - - /* Update the I/F */ - tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz); - - return 0; -} - -static int tda10048_firmware_upload(struct dvb_frontend *fe) -{ - struct tda10048_state *state = fe->demodulator_priv; - struct tda10048_config *config = &state->config; - const struct firmware *fw; - int ret; - int pos = 0; - int cnt; - u8 wlen = config->fwbulkwritelen; - - if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50)) - wlen = TDA10048_BULKWRITE_200; - - /* request the firmware, this will block and timeout */ - printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n", - __func__, - TDA10048_DEFAULT_FIRMWARE); - - ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE, - state->i2c->dev.parent); - if (ret) { - printk(KERN_ERR "%s: Upload failed. (file not found?)\n", - __func__); - return -EIO; - } else { - printk(KERN_INFO "%s: firmware read %Zu bytes.\n", - __func__, - fw->size); - ret = 0; - } - - if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) { - printk(KERN_ERR "%s: firmware incorrect size\n", __func__); - ret = -EIO; - } else { - printk(KERN_INFO "%s: firmware uploading\n", __func__); - - /* Soft reset */ - tda10048_writereg(state, TDA10048_CONF_TRISTATE1, - tda10048_readreg(state, TDA10048_CONF_TRISTATE1) - & 0xfe); - tda10048_writereg(state, TDA10048_CONF_TRISTATE1, - tda10048_readreg(state, TDA10048_CONF_TRISTATE1) - | 0x01); - - /* Put the demod into host download mode */ - tda10048_writereg(state, TDA10048_CONF_C4_1, - tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9); - - /* Boot the DSP */ - tda10048_writereg(state, TDA10048_CONF_C4_1, - tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08); - - /* Prepare for download */ - tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0); - - /* Download the firmware payload */ - while (pos < fw->size) { - - if ((fw->size - pos) > wlen) - cnt = wlen; - else - cnt = fw->size - pos; - - tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN, - &fw->data[pos], cnt); - - pos += cnt; - } - - ret = -EIO; - /* Wait up to 250ms for the DSP to boot */ - for (cnt = 0; cnt < 250 ; cnt += 10) { - - msleep(10); - - if (tda10048_readreg(state, TDA10048_SYNC_STATUS) - & 0x40) { - ret = 0; - break; - } - } - } - - release_firmware(fw); - - if (ret == 0) { - printk(KERN_INFO "%s: firmware uploaded\n", __func__); - state->fwloaded = 1; - } else - printk(KERN_ERR "%s: firmware upload failed\n", __func__); - - return ret; -} - -static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion) -{ - struct tda10048_state *state = fe->demodulator_priv; - - dprintk(1, "%s(%d)\n", __func__, inversion); - - if (inversion == TDA10048_INVERSION_ON) - tda10048_writereg(state, TDA10048_CONF_C1_1, - tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20); - else - tda10048_writereg(state, TDA10048_CONF_C1_1, - tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf); - - return 0; -} - -/* Retrieve the demod settings */ -static int tda10048_get_tps(struct tda10048_state *state, - struct dvb_ofdm_parameters *p) -{ - u8 val; - - /* Make sure the TPS regs are valid */ - if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01)) - return -EAGAIN; - - val = tda10048_readreg(state, TDA10048_OUT_CONF2); - switch ((val & 0x60) >> 5) { - case 0: - p->constellation = QPSK; - break; - case 1: - p->constellation = QAM_16; - break; - case 2: - p->constellation = QAM_64; - break; - } - switch ((val & 0x18) >> 3) { - case 0: - p->hierarchy_information = HIERARCHY_NONE; - break; - case 1: - p->hierarchy_information = HIERARCHY_1; - break; - case 2: - p->hierarchy_information = HIERARCHY_2; - break; - case 3: - p->hierarchy_information = HIERARCHY_4; - break; - } - switch (val & 0x07) { - case 0: - p->code_rate_HP = FEC_1_2; - break; - case 1: - p->code_rate_HP = FEC_2_3; - break; - case 2: - p->code_rate_HP = FEC_3_4; - break; - case 3: - p->code_rate_HP = FEC_5_6; - break; - case 4: - p->code_rate_HP = FEC_7_8; - break; - } - - val = tda10048_readreg(state, TDA10048_OUT_CONF3); - switch (val & 0x07) { - case 0: - p->code_rate_LP = FEC_1_2; - break; - case 1: - p->code_rate_LP = FEC_2_3; - break; - case 2: - p->code_rate_LP = FEC_3_4; - break; - case 3: - p->code_rate_LP = FEC_5_6; - break; - case 4: - p->code_rate_LP = FEC_7_8; - break; - } - - val = tda10048_readreg(state, TDA10048_OUT_CONF1); - switch ((val & 0x0c) >> 2) { - case 0: - p->guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - p->guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - p->guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - p->guard_interval = GUARD_INTERVAL_1_4; - break; - } - switch (val & 0x03) { - case 0: - p->transmission_mode = TRANSMISSION_MODE_2K; - break; - case 1: - p->transmission_mode = TRANSMISSION_MODE_8K; - break; - } - - return 0; -} - -static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct tda10048_state *state = fe->demodulator_priv; - struct tda10048_config *config = &state->config; - dprintk(1, "%s(%d)\n", __func__, enable); - - if (config->disable_gate_access) - return 0; - - if (enable) - return tda10048_writereg(state, TDA10048_CONF_C4_1, - tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02); - else - return tda10048_writereg(state, TDA10048_CONF_C4_1, - tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd); -} - -static int tda10048_output_mode(struct dvb_frontend *fe, int serial) -{ - struct tda10048_state *state = fe->demodulator_priv; - dprintk(1, "%s(%d)\n", __func__, serial); - - /* Ensure pins are out of tri-state */ - tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21); - tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00); - - if (serial) { - tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20); - tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0); - } else { - tda10048_writereg(state, TDA10048_IC_MODE, 0x00); - tda10048_writereg(state, TDA10048_CONF_TS2, 0x01); - } - - return 0; -} - -/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -/* TODO: Support manual tuning with specific params */ -static int tda10048_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct tda10048_state *state = fe->demodulator_priv; - - dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); - - /* Update the I/F pll's if the bandwidth changes */ - if (p->u.ofdm.bandwidth != state->bandwidth) { - tda10048_set_if(fe, p->u.ofdm.bandwidth); - tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth); - } - - if (fe->ops.tuner_ops.set_params) { - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - fe->ops.tuner_ops.set_params(fe, p); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* Enable demod TPS auto detection and begin acquisition */ - tda10048_writereg(state, TDA10048_AUTO, 0x57); - /* trigger cber and vber acquisition */ - tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B); - - return 0; -} - -/* Establish sane defaults and load firmware. */ -static int tda10048_init(struct dvb_frontend *fe) -{ - struct tda10048_state *state = fe->demodulator_priv; - struct tda10048_config *config = &state->config; - int ret = 0, i; - - dprintk(1, "%s()\n", __func__); - - /* Apply register defaults */ - for (i = 0; i < ARRAY_SIZE(init_tab); i++) - tda10048_writereg(state, init_tab[i].reg, init_tab[i].data); - - if (state->fwloaded == 0) - ret = tda10048_firmware_upload(fe); - - /* Set either serial or parallel */ - tda10048_output_mode(fe, config->output_mode); - - /* Set inversion */ - tda10048_set_inversion(fe, config->inversion); - - /* Establish default RF values */ - tda10048_set_if(fe, BANDWIDTH_8_MHZ); - tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ); - - /* Ensure we leave the gate closed */ - tda10048_i2c_gate_ctrl(fe, 0); - - return ret; -} - -static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct tda10048_state *state = fe->demodulator_priv; - u8 reg; - - *status = 0; - - reg = tda10048_readreg(state, TDA10048_SYNC_STATUS); - - dprintk(1, "%s() status =0x%02x\n", __func__, reg); - - if (reg & 0x02) - *status |= FE_HAS_CARRIER; - - if (reg & 0x04) - *status |= FE_HAS_SIGNAL; - - if (reg & 0x08) { - *status |= FE_HAS_LOCK; - *status |= FE_HAS_VITERBI; - *status |= FE_HAS_SYNC; - } - - return 0; -} - -static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct tda10048_state *state = fe->demodulator_priv; - static u32 cber_current; - u32 cber_nmax; - u64 cber_tmp; - - dprintk(1, "%s()\n", __func__); - - /* update cber on interrupt */ - if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) { - cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 | - tda10048_readreg(state, TDA10048_CBER_LSB); - cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 | - tda10048_readreg(state, TDA10048_CBER_NMAX_LSB); - cber_tmp *= 100000000; - cber_tmp *= 2; - cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1); - cber_current = (u32)cber_tmp; - /* retrigger cber acquisition */ - tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39); - } - /* actual cber is (*ber)/1e8 */ - *ber = cber_current; - - return 0; -} - -static int tda10048_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) -{ - struct tda10048_state *state = fe->demodulator_priv; - u8 v; - - dprintk(1, "%s()\n", __func__); - - *signal_strength = 65535; - - v = tda10048_readreg(state, TDA10048_NP_OUT); - if (v > 0) - *signal_strength -= (v << 8) | v; - - return 0; -} - -/* SNR lookup table */ -static struct snr_tab { - u8 val; - u8 data; -} snr_tab[] = { - { 0, 0 }, - { 1, 246 }, - { 2, 215 }, - { 3, 198 }, - { 4, 185 }, - { 5, 176 }, - { 6, 168 }, - { 7, 161 }, - { 8, 155 }, - { 9, 150 }, - { 10, 146 }, - { 11, 141 }, - { 12, 138 }, - { 13, 134 }, - { 14, 131 }, - { 15, 128 }, - { 16, 125 }, - { 17, 122 }, - { 18, 120 }, - { 19, 118 }, - { 20, 115 }, - { 21, 113 }, - { 22, 111 }, - { 23, 109 }, - { 24, 107 }, - { 25, 106 }, - { 26, 104 }, - { 27, 102 }, - { 28, 101 }, - { 29, 99 }, - { 30, 98 }, - { 31, 96 }, - { 32, 95 }, - { 33, 94 }, - { 34, 92 }, - { 35, 91 }, - { 36, 90 }, - { 37, 89 }, - { 38, 88 }, - { 39, 86 }, - { 40, 85 }, - { 41, 84 }, - { 42, 83 }, - { 43, 82 }, - { 44, 81 }, - { 45, 80 }, - { 46, 79 }, - { 47, 78 }, - { 48, 77 }, - { 49, 76 }, - { 50, 76 }, - { 51, 75 }, - { 52, 74 }, - { 53, 73 }, - { 54, 72 }, - { 56, 71 }, - { 57, 70 }, - { 58, 69 }, - { 60, 68 }, - { 61, 67 }, - { 63, 66 }, - { 64, 65 }, - { 66, 64 }, - { 67, 63 }, - { 68, 62 }, - { 69, 62 }, - { 70, 61 }, - { 72, 60 }, - { 74, 59 }, - { 75, 58 }, - { 77, 57 }, - { 79, 56 }, - { 81, 55 }, - { 83, 54 }, - { 85, 53 }, - { 87, 52 }, - { 89, 51 }, - { 91, 50 }, - { 93, 49 }, - { 95, 48 }, - { 97, 47 }, - { 100, 46 }, - { 102, 45 }, - { 104, 44 }, - { 107, 43 }, - { 109, 42 }, - { 112, 41 }, - { 114, 40 }, - { 117, 39 }, - { 120, 38 }, - { 123, 37 }, - { 125, 36 }, - { 128, 35 }, - { 131, 34 }, - { 134, 33 }, - { 138, 32 }, - { 141, 31 }, - { 144, 30 }, - { 147, 29 }, - { 151, 28 }, - { 154, 27 }, - { 158, 26 }, - { 162, 25 }, - { 165, 24 }, - { 169, 23 }, - { 173, 22 }, - { 177, 21 }, - { 181, 20 }, - { 186, 19 }, - { 190, 18 }, - { 194, 17 }, - { 199, 16 }, - { 204, 15 }, - { 208, 14 }, - { 213, 13 }, - { 218, 12 }, - { 223, 11 }, - { 229, 10 }, - { 234, 9 }, - { 239, 8 }, - { 245, 7 }, - { 251, 6 }, - { 255, 5 }, -}; - -static int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct tda10048_state *state = fe->demodulator_priv; - u8 v; - int i, ret = -EINVAL; - - dprintk(1, "%s()\n", __func__); - - v = tda10048_readreg(state, TDA10048_NP_OUT); - for (i = 0; i < ARRAY_SIZE(snr_tab); i++) { - if (v <= snr_tab[i].val) { - *snr = snr_tab[i].data; - ret = 0; - break; - } - } - - return ret; -} - -static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct tda10048_state *state = fe->demodulator_priv; - - dprintk(1, "%s()\n", __func__); - - *ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 | - tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB); - /* clear the uncorrected TS packets counter when saturated */ - if (*ucblocks == 0xFFFF) - tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80); - - return 0; -} - -static int tda10048_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct tda10048_state *state = fe->demodulator_priv; - - dprintk(1, "%s()\n", __func__); - - p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1) - & 0x20 ? INVERSION_ON : INVERSION_OFF; - - return tda10048_get_tps(state, &p->u.ofdm); -} - -static int tda10048_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void tda10048_release(struct dvb_frontend *fe) -{ - struct tda10048_state *state = fe->demodulator_priv; - dprintk(1, "%s()\n", __func__); - kfree(state); -} - -static void tda10048_establish_defaults(struct dvb_frontend *fe) -{ - struct tda10048_state *state = fe->demodulator_priv; - struct tda10048_config *config = &state->config; - - /* Validate/default the config */ - if (config->dtv6_if_freq_khz == 0) { - config->dtv6_if_freq_khz = TDA10048_IF_4300; - printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz " - "is not set (defaulting to %d)\n", - __func__, - config->dtv6_if_freq_khz); - } - - if (config->dtv7_if_freq_khz == 0) { - config->dtv7_if_freq_khz = TDA10048_IF_4300; - printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz " - "is not set (defaulting to %d)\n", - __func__, - config->dtv7_if_freq_khz); - } - - if (config->dtv8_if_freq_khz == 0) { - config->dtv8_if_freq_khz = TDA10048_IF_4300; - printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz " - "is not set (defaulting to %d)\n", - __func__, - config->dtv8_if_freq_khz); - } - - if (config->clk_freq_khz == 0) { - config->clk_freq_khz = TDA10048_CLK_16000; - printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz " - "is not set (defaulting to %d)\n", - __func__, - config->clk_freq_khz); - } -} - -static struct dvb_frontend_ops tda10048_ops; - -struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, - struct i2c_adapter *i2c) -{ - struct tda10048_state *state = NULL; - - dprintk(1, "%s()\n", __func__); - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct tda10048_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state and clone the config */ - memcpy(&state->config, config, sizeof(*config)); - state->i2c = i2c; - state->fwloaded = 0; - state->bandwidth = BANDWIDTH_8_MHZ; - - /* check if the demod is present */ - if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &tda10048_ops, - sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - /* Establish any defaults the the user didn't pass */ - tda10048_establish_defaults(&state->frontend); - - /* Set the xtal and freq defaults */ - if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0) - goto error; - - /* Default bandwidth */ - if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0) - goto error; - - /* Leave the gate closed */ - tda10048_i2c_gate_ctrl(&state->frontend, 0); - - return &state->frontend; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(tda10048_attach); - -static struct dvb_frontend_ops tda10048_ops = { - - .info = { - .name = "NXP TDA10048HN DVB-T", - .type = FE_OFDM, - .frequency_min = 177000000, - .frequency_max = 858000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER - }, - - .release = tda10048_release, - .init = tda10048_init, - .i2c_gate_ctrl = tda10048_i2c_gate_ctrl, - .set_frontend = tda10048_set_frontend, - .get_frontend = tda10048_get_frontend, - .get_tune_settings = tda10048_get_tune_settings, - .read_status = tda10048_read_status, - .read_ber = tda10048_read_ber, - .read_signal_strength = tda10048_read_signal_strength, - .read_snr = tda10048_read_snr, - .read_ucblocks = tda10048_read_ucblocks, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable verbose debug messages"); - -MODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver"); -MODULE_AUTHOR("Steven Toth"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10048.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10048.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10048.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10048.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* - NXP TDA10048HN DVB OFDM demodulator driver - - Copyright (C) 2009 Steven Toth - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef TDA10048_H -#define TDA10048_H - -#include -#include - -struct tda10048_config { - - /* the demodulator's i2c address */ - u8 demod_address; - - /* serial/parallel output */ -#define TDA10048_PARALLEL_OUTPUT 0 -#define TDA10048_SERIAL_OUTPUT 1 - u8 output_mode; - -#define TDA10048_BULKWRITE_200 200 -#define TDA10048_BULKWRITE_50 50 - u8 fwbulkwritelen; - - /* Spectral Inversion */ -#define TDA10048_INVERSION_OFF 0 -#define TDA10048_INVERSION_ON 1 - u8 inversion; - -#define TDA10048_IF_3300 3300 -#define TDA10048_IF_3500 3500 -#define TDA10048_IF_3800 3800 -#define TDA10048_IF_4000 4000 -#define TDA10048_IF_4300 4300 -#define TDA10048_IF_4500 4500 -#define TDA10048_IF_4750 4750 -#define TDA10048_IF_36130 36130 - u16 dtv6_if_freq_khz; - u16 dtv7_if_freq_khz; - u16 dtv8_if_freq_khz; - -#define TDA10048_CLK_4000 4000 -#define TDA10048_CLK_16000 16000 - u16 clk_freq_khz; - - /* Disable I2C gate access */ - u8 disable_gate_access; -}; - -#if defined(CONFIG_DVB_TDA10048) || \ - (defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda10048_attach( - const struct tda10048_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *tda10048_attach( - const struct tda10048_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_TDA10048 */ - -#endif /* TDA10048_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1004x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1004x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1004x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1004x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1380 +0,0 @@ - /* - Driver for Philips tda1004xh OFDM Demodulator - - (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ -/* - * This driver needs external firmware. Please use the commands - * "/Documentation/dvb/get_dvb_firmware tda10045", - * "/Documentation/dvb/get_dvb_firmware tda10046" to - * download/extract them, and then copy them to /usr/lib/hotplug/firmware - * or /lib/firmware (depending on configuration of firmware hotplug). - */ -#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw" -#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw" - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "tda1004x.h" - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "tda1004x: " args); \ - } while (0) - -#define TDA1004X_CHIPID 0x00 -#define TDA1004X_AUTO 0x01 -#define TDA1004X_IN_CONF1 0x02 -#define TDA1004X_IN_CONF2 0x03 -#define TDA1004X_OUT_CONF1 0x04 -#define TDA1004X_OUT_CONF2 0x05 -#define TDA1004X_STATUS_CD 0x06 -#define TDA1004X_CONFC4 0x07 -#define TDA1004X_DSSPARE2 0x0C -#define TDA10045H_CODE_IN 0x0D -#define TDA10045H_FWPAGE 0x0E -#define TDA1004X_SCAN_CPT 0x10 -#define TDA1004X_DSP_CMD 0x11 -#define TDA1004X_DSP_ARG 0x12 -#define TDA1004X_DSP_DATA1 0x13 -#define TDA1004X_DSP_DATA2 0x14 -#define TDA1004X_CONFADC1 0x15 -#define TDA1004X_CONFC1 0x16 -#define TDA10045H_S_AGC 0x1a -#define TDA10046H_AGC_TUN_LEVEL 0x1a -#define TDA1004X_SNR 0x1c -#define TDA1004X_CONF_TS1 0x1e -#define TDA1004X_CONF_TS2 0x1f -#define TDA1004X_CBER_RESET 0x20 -#define TDA1004X_CBER_MSB 0x21 -#define TDA1004X_CBER_LSB 0x22 -#define TDA1004X_CVBER_LUT 0x23 -#define TDA1004X_VBER_MSB 0x24 -#define TDA1004X_VBER_MID 0x25 -#define TDA1004X_VBER_LSB 0x26 -#define TDA1004X_UNCOR 0x27 - -#define TDA10045H_CONFPLL_P 0x2D -#define TDA10045H_CONFPLL_M_MSB 0x2E -#define TDA10045H_CONFPLL_M_LSB 0x2F -#define TDA10045H_CONFPLL_N 0x30 - -#define TDA10046H_CONFPLL1 0x2D -#define TDA10046H_CONFPLL2 0x2F -#define TDA10046H_CONFPLL3 0x30 -#define TDA10046H_TIME_WREF1 0x31 -#define TDA10046H_TIME_WREF2 0x32 -#define TDA10046H_TIME_WREF3 0x33 -#define TDA10046H_TIME_WREF4 0x34 -#define TDA10046H_TIME_WREF5 0x35 - -#define TDA10045H_UNSURW_MSB 0x31 -#define TDA10045H_UNSURW_LSB 0x32 -#define TDA10045H_WREF_MSB 0x33 -#define TDA10045H_WREF_MID 0x34 -#define TDA10045H_WREF_LSB 0x35 -#define TDA10045H_MUXOUT 0x36 -#define TDA1004X_CONFADC2 0x37 - -#define TDA10045H_IOFFSET 0x38 - -#define TDA10046H_CONF_TRISTATE1 0x3B -#define TDA10046H_CONF_TRISTATE2 0x3C -#define TDA10046H_CONF_POLARITY 0x3D -#define TDA10046H_FREQ_OFFSET 0x3E -#define TDA10046H_GPIO_OUT_SEL 0x41 -#define TDA10046H_GPIO_SELECT 0x42 -#define TDA10046H_AGC_CONF 0x43 -#define TDA10046H_AGC_THR 0x44 -#define TDA10046H_AGC_RENORM 0x45 -#define TDA10046H_AGC_GAINS 0x46 -#define TDA10046H_AGC_TUN_MIN 0x47 -#define TDA10046H_AGC_TUN_MAX 0x48 -#define TDA10046H_AGC_IF_MIN 0x49 -#define TDA10046H_AGC_IF_MAX 0x4A - -#define TDA10046H_FREQ_PHY2_MSB 0x4D -#define TDA10046H_FREQ_PHY2_LSB 0x4E - -#define TDA10046H_CVBER_CTRL 0x4F -#define TDA10046H_AGC_IF_LEVEL 0x52 -#define TDA10046H_CODE_CPT 0x57 -#define TDA10046H_CODE_IN 0x58 - - -static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data) -{ - int ret; - u8 buf[] = { reg, data }; - struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; - - dprintk("%s: reg=0x%x, data=0x%x\n", __func__, reg, data); - - msg.addr = state->config->demod_address; - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", - __func__, reg, data, ret); - - dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__, - reg, data, ret); - return (ret != 1) ? -1 : 0; -} - -static int tda1004x_read_byte(struct tda1004x_state *state, int reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 }, - { .flags = I2C_M_RD, .buf = b1, .len = 1 }}; - - dprintk("%s: reg=0x%x\n", __func__, reg); - - msg[0].addr = state->config->demod_address; - msg[1].addr = state->config->demod_address; - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, - ret); - return -EINVAL; - } - - dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__, - reg, b1[0], ret); - return b1[0]; -} - -static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data) -{ - int val; - dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __func__, reg, - mask, data); - - // read a byte and check - val = tda1004x_read_byte(state, reg); - if (val < 0) - return val; - - // mask if off - val = val & ~mask; - val |= data & 0xff; - - // write it out again - return tda1004x_write_byteI(state, reg, val); -} - -static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len) -{ - int i; - int result; - - dprintk("%s: reg=0x%x, len=0x%x\n", __func__, reg, len); - - result = 0; - for (i = 0; i < len; i++) { - result = tda1004x_write_byteI(state, reg + i, buf[i]); - if (result != 0) - break; - } - - return result; -} - -static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state) -{ - int result; - dprintk("%s\n", __func__); - - result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2); - msleep(20); - return result; -} - -static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state) -{ - dprintk("%s\n", __func__); - - return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0); -} - -static int tda10045h_set_bandwidth(struct tda1004x_state *state, - fe_bandwidth_t bandwidth) -{ - static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; - static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb }; - static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 }; - - switch (bandwidth) { - case BANDWIDTH_6_MHZ: - tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); - break; - - case BANDWIDTH_7_MHZ: - tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); - break; - - case BANDWIDTH_8_MHZ: - tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); - break; - - default: - return -EINVAL; - } - - tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0); - - return 0; -} - -static int tda10046h_set_bandwidth(struct tda1004x_state *state, - fe_bandwidth_t bandwidth) -{ - static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 }; - static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f }; - static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d }; - - static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 }; - static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab }; - static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 }; - int tda10046_clk53m; - - if ((state->config->if_freq == TDA10046_FREQ_045) || - (state->config->if_freq == TDA10046_FREQ_052)) - tda10046_clk53m = 0; - else - tda10046_clk53m = 1; - switch (bandwidth) { - case BANDWIDTH_6_MHZ: - if (tda10046_clk53m) - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M, - sizeof(bandwidth_6mhz_53M)); - else - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M, - sizeof(bandwidth_6mhz_48M)); - if (state->config->if_freq == TDA10046_FREQ_045) { - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab); - } - break; - - case BANDWIDTH_7_MHZ: - if (tda10046_clk53m) - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M, - sizeof(bandwidth_7mhz_53M)); - else - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M, - sizeof(bandwidth_7mhz_48M)); - if (state->config->if_freq == TDA10046_FREQ_045) { - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); - } - break; - - case BANDWIDTH_8_MHZ: - if (tda10046_clk53m) - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M, - sizeof(bandwidth_8mhz_53M)); - else - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M, - sizeof(bandwidth_8mhz_48M)); - if (state->config->if_freq == TDA10046_FREQ_045) { - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55); - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int tda1004x_do_upload(struct tda1004x_state *state, - const unsigned char *mem, unsigned int len, - u8 dspCodeCounterReg, u8 dspCodeInReg) -{ - u8 buf[65]; - struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 }; - int tx_size; - int pos = 0; - - /* clear code counter */ - tda1004x_write_byteI(state, dspCodeCounterReg, 0); - fw_msg.addr = state->config->demod_address; - - buf[0] = dspCodeInReg; - while (pos != len) { - // work out how much to send this time - tx_size = len - pos; - if (tx_size > 0x10) - tx_size = 0x10; - - // send the chunk - memcpy(buf + 1, mem + pos, tx_size); - fw_msg.len = tx_size + 1; - if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) { - printk(KERN_ERR "tda1004x: Error during firmware upload\n"); - return -EIO; - } - pos += tx_size; - - dprintk("%s: fw_pos=0x%x\n", __func__, pos); - } - // give the DSP a chance to settle 03/10/05 Hac - msleep(100); - - return 0; -} - -static int tda1004x_check_upload_ok(struct tda1004x_state *state) -{ - u8 data1, data2; - unsigned long timeout; - - if (state->demod_type == TDA1004X_DEMOD_TDA10046) { - timeout = jiffies + 2 * HZ; - while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { - if (time_after(jiffies, timeout)) { - printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n"); - break; - } - msleep(1); - } - } else - msleep(100); - - // check upload was OK - tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP - tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67); - - data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1); - data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2); - if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) { - printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2); - return -EIO; - } - printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2); - return 0; -} - -static int tda10045_fwupload(struct dvb_frontend* fe) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int ret; - const struct firmware *fw; - - /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state) == 0) - return 0; - - /* request the firmware, this will block until someone uploads it */ - printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE); - ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); - if (ret) { - printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); - return ret; - } - - /* reset chip */ - tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); - tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); - tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); - msleep(10); - - /* set parameters */ - tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ); - - ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); - release_firmware(fw); - if (ret) - return ret; - printk(KERN_INFO "tda1004x: firmware upload complete\n"); - - /* wait for DSP to initialise */ - /* DSPREADY doesn't seem to work on the TDA10045H */ - msleep(100); - - return tda1004x_check_upload_ok(state); -} - -static void tda10046_init_plls(struct dvb_frontend* fe) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int tda10046_clk53m; - - if ((state->config->if_freq == TDA10046_FREQ_045) || - (state->config->if_freq == TDA10046_FREQ_052)) - tda10046_clk53m = 0; - else - tda10046_clk53m = 1; - - tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0); - if(tda10046_clk53m) { - printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n"); - tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8 - } else { - printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n"); - tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3 - } - if (state->config->xtal_freq == TDA10046_XTAL_4M ) { - dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __func__); - tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 - } else { - dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __func__); - tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3 - } - if(tda10046_clk53m) - tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67); - else - tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72); - /* Note clock frequency is handled implicitly */ - switch (state->config->if_freq) { - case TDA10046_FREQ_045: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); - break; - case TDA10046_FREQ_052: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7); - break; - case TDA10046_FREQ_3617: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59); - break; - case TDA10046_FREQ_3613: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f); - break; - } - tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz - /* let the PLLs settle */ - msleep(120); -} - -static int tda10046_fwupload(struct dvb_frontend* fe) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int ret, confc4; - const struct firmware *fw; - - /* reset + wake up chip */ - if (state->config->xtal_freq == TDA10046_XTAL_4M) { - confc4 = 0; - } else { - dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__); - confc4 = 0x80; - } - tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4); - - tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); - /* set GPIO 1 and 3 */ - if (state->config->gpio_config != TDA10046_GPTRI) { - tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33); - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f); - } - /* let the clocks recover from sleep */ - msleep(10); - - /* The PLLs need to be reprogrammed after sleep */ - tda10046_init_plls(fe); - tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0); - - /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state) == 0) - return 0; - - /* - For i2c normal work, we need to slow down the bus speed. - However, the slow down breaks the eeprom firmware load. - So, use normal speed for eeprom booting and then restore the - i2c speed after that. Tested with MSI TV @nyware A/D board, - that comes with firmware version 29 inside their eeprom. - - It should also be noticed that no other I2C transfer should - be in course while booting from eeprom, otherwise, tda10046 - goes into an instable state. So, proper locking are needed - at the i2c bus master. - */ - printk(KERN_INFO "tda1004x: trying to boot from eeprom\n"); - tda1004x_write_byteI(state, TDA1004X_CONFC4, 4); - msleep(300); - tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4); - - /* Checks if eeprom firmware went without troubles */ - if (tda1004x_check_upload_ok(state) == 0) - return 0; - - /* eeprom firmware didn't work. Load one manually. */ - - if (state->config->request_firmware != NULL) { - /* request the firmware, this will block until someone uploads it */ - printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); - ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); - if (ret) { - /* remain compatible to old bug: try to load with tda10045 image name */ - ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); - if (ret) { - printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); - return ret; - } else { - printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n", - TDA10046_DEFAULT_FIRMWARE); - } - } - } else { - printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n"); - return -EIO; - } - tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST - ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); - release_firmware(fw); - return tda1004x_check_upload_ok(state); -} - -static int tda1004x_encode_fec(int fec) -{ - // convert known FEC values - switch (fec) { - case FEC_1_2: - return 0; - case FEC_2_3: - return 1; - case FEC_3_4: - return 2; - case FEC_5_6: - return 3; - case FEC_7_8: - return 4; - } - - // unsupported - return -EINVAL; -} - -static int tda1004x_decode_fec(int tdafec) -{ - // convert known FEC values - switch (tdafec) { - case 0: - return FEC_1_2; - case 1: - return FEC_2_3; - case 2: - return FEC_3_4; - case 3: - return FEC_5_6; - case 4: - return FEC_7_8; - } - - // unsupported - return -1; -} - -static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len) -{ - struct tda1004x_state* state = fe->demodulator_priv; - - if (len != 2) - return -EINVAL; - - return tda1004x_write_byteI(state, buf[0], buf[1]); -} - -static int tda10045_init(struct dvb_frontend* fe) -{ - struct tda1004x_state* state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - if (tda10045_fwupload(fe)) { - printk("tda1004x: firmware upload failed\n"); - return -EIO; - } - - tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC - - // tda setup - tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer - tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream - tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal - tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer - tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset - tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset - tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface - tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface - tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits - tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity - tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e); - - tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk); - - return 0; -} - -static int tda10046_init(struct dvb_frontend* fe) -{ - struct tda1004x_state* state = fe->demodulator_priv; - dprintk("%s\n", __func__); - - if (tda10046_fwupload(fe)) { - printk("tda1004x: firmware upload failed\n"); - return -EIO; - } - - // tda setup - tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer - tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream - tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88); // enable pulse killer - - switch (state->config->agc_config) { - case TDA10046_AGC_DEFAULT: - tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities - break; - case TDA10046_AGC_IFO_AUTO_NEG: - tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities - break; - case TDA10046_AGC_IFO_AUTO_POS: - tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00); // set AGC polarities - break; - case TDA10046_AGC_TDA827X: - tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup - tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold - tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities - break; - } - if (state->config->ts_mode == 0) { - tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40); - tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); - } else { - tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80); - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10, - state->config->invert_oclk << 4); - } - tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); - tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on - tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } - tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values - tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } - tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } - tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1 - tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits - tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config - tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config - // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes - - return 0; -} - -static int tda1004x_set_fe(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fe_params) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int tmp; - int inversion; - - dprintk("%s\n", __func__); - - if (state->demod_type == TDA1004X_DEMOD_TDA10046) { - // setup auto offset - tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0); - tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0); - - // disable agc_conf[2] - tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0); - } - - // set frequency - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - // Hardcoded to use auto as much as possible on the TDA10045 as it - // is very unreliable if AUTO mode is _not_ used. - if (state->demod_type == TDA1004X_DEMOD_TDA10045) { - fe_params->u.ofdm.code_rate_HP = FEC_AUTO; - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - } - - // Set standard params.. or put them to auto - if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) || - (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || - (fe_params->u.ofdm.constellation == QAM_AUTO) || - (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { - tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits - tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits - } else { - tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto - - // set HP FEC - tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP); - if (tmp < 0) - return tmp; - tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp); - - // set LP FEC - tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP); - if (tmp < 0) - return tmp; - tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3); - - // set constellation - switch (fe_params->u.ofdm.constellation) { - case QPSK: - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0); - break; - - case QAM_16: - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1); - break; - - case QAM_64: - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2); - break; - - default: - return -EINVAL; - } - - // set hierarchy - switch (fe_params->u.ofdm.hierarchy_information) { - case HIERARCHY_NONE: - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5); - break; - - case HIERARCHY_1: - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5); - break; - - case HIERARCHY_2: - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5); - break; - - case HIERARCHY_4: - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5); - break; - - default: - return -EINVAL; - } - } - - // set bandwidth - switch (state->demod_type) { - case TDA1004X_DEMOD_TDA10045: - tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); - break; - - case TDA1004X_DEMOD_TDA10046: - tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); - break; - } - - // set inversion - inversion = fe_params->inversion; - if (state->config->invert) - inversion = inversion ? INVERSION_OFF : INVERSION_ON; - switch (inversion) { - case INVERSION_OFF: - tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0); - break; - - case INVERSION_ON: - tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20); - break; - - default: - return -EINVAL; - } - - // set guard interval - switch (fe_params->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_32: - tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); - break; - - case GUARD_INTERVAL_1_16: - tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2); - break; - - case GUARD_INTERVAL_1_8: - tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2); - break; - - case GUARD_INTERVAL_1_4: - tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2); - break; - - case GUARD_INTERVAL_AUTO: - tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2); - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); - break; - - default: - return -EINVAL; - } - - // set transmission mode - switch (fe_params->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: - tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4); - break; - - case TRANSMISSION_MODE_8K: - tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4); - break; - - case TRANSMISSION_MODE_AUTO: - tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4); - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0); - break; - - default: - return -EINVAL; - } - - // start the lock - switch (state->demod_type) { - case TDA1004X_DEMOD_TDA10045: - tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); - tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); - break; - - case TDA1004X_DEMOD_TDA10046: - tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40); - msleep(1); - tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1); - break; - } - - msleep(10); - - return 0; -} - -static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) -{ - struct tda1004x_state* state = fe->demodulator_priv; - - dprintk("%s\n", __func__); - - // inversion status - fe_params->inversion = INVERSION_OFF; - if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) - fe_params->inversion = INVERSION_ON; - if (state->config->invert) - fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON; - - // bandwidth - switch (state->demod_type) { - case TDA1004X_DEMOD_TDA10045: - switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) { - case 0x14: - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - break; - case 0xdb: - fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - break; - case 0x4f: - fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - break; - } - break; - case TDA1004X_DEMOD_TDA10046: - switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { - case 0x5c: - case 0x54: - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - break; - case 0x6a: - case 0x60: - fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - break; - case 0x7b: - case 0x70: - fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - break; - } - break; - } - - // FEC - fe_params->u.ofdm.code_rate_HP = - tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7); - fe_params->u.ofdm.code_rate_LP = - tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7); - - // constellation - switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) { - case 0: - fe_params->u.ofdm.constellation = QPSK; - break; - case 1: - fe_params->u.ofdm.constellation = QAM_16; - break; - case 2: - fe_params->u.ofdm.constellation = QAM_64; - break; - } - - // transmission mode - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - - // guard interval - switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { - case 0: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; - break; - } - - // hierarchy - switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { - case 0: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; - break; - case 1: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_1; - break; - case 2: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_2; - break; - case 3: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_4; - break; - } - - return 0; -} - -static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int status; - int cber; - int vber; - - dprintk("%s\n", __func__); - - // read status - status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); - if (status == -1) - return -EIO; - - // decode - *fe_status = 0; - if (status & 4) - *fe_status |= FE_HAS_SIGNAL; - if (status & 2) - *fe_status |= FE_HAS_CARRIER; - if (status & 8) - *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - - // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi - // is getting anything valid - if (!(*fe_status & FE_HAS_VITERBI)) { - // read the CBER - cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB); - if (cber == -1) - return -EIO; - status = tda1004x_read_byte(state, TDA1004X_CBER_MSB); - if (status == -1) - return -EIO; - cber |= (status << 8); - // The address 0x20 should be read to cope with a TDA10046 bug - tda1004x_read_byte(state, TDA1004X_CBER_RESET); - - if (cber != 65535) - *fe_status |= FE_HAS_VITERBI; - } - - // if we DO have some valid VITERBI output, but don't already have SYNC - // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid. - if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) { - // read the VBER - vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB); - if (vber == -1) - return -EIO; - status = tda1004x_read_byte(state, TDA1004X_VBER_MID); - if (status == -1) - return -EIO; - vber |= (status << 8); - status = tda1004x_read_byte(state, TDA1004X_VBER_MSB); - if (status == -1) - return -EIO; - vber |= (status & 0x0f) << 16; - // The CVBER_LUT should be read to cope with TDA10046 hardware bug - tda1004x_read_byte(state, TDA1004X_CVBER_LUT); - - // if RS has passed some valid TS packets, then we must be - // getting some SYNC bytes - if (vber < 16632) - *fe_status |= FE_HAS_SYNC; - } - - // success - dprintk("%s: fe_status=0x%x\n", __func__, *fe_status); - return 0; -} - -static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int tmp; - int reg = 0; - - dprintk("%s\n", __func__); - - // determine the register to use - switch (state->demod_type) { - case TDA1004X_DEMOD_TDA10045: - reg = TDA10045H_S_AGC; - break; - - case TDA1004X_DEMOD_TDA10046: - reg = TDA10046H_AGC_IF_LEVEL; - break; - } - - // read it - tmp = tda1004x_read_byte(state, reg); - if (tmp < 0) - return -EIO; - - *signal = (tmp << 8) | tmp; - dprintk("%s: signal=0x%x\n", __func__, *signal); - return 0; -} - -static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int tmp; - - dprintk("%s\n", __func__); - - // read it - tmp = tda1004x_read_byte(state, TDA1004X_SNR); - if (tmp < 0) - return -EIO; - tmp = 255 - tmp; - - *snr = ((tmp << 8) | tmp); - dprintk("%s: snr=0x%x\n", __func__, *snr); - return 0; -} - -static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int tmp; - int tmp2; - int counter; - - dprintk("%s\n", __func__); - - // read the UCBLOCKS and reset - counter = 0; - tmp = tda1004x_read_byte(state, TDA1004X_UNCOR); - if (tmp < 0) - return -EIO; - tmp &= 0x7f; - while (counter++ < 5) { - tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); - tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); - tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); - - tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR); - if (tmp2 < 0) - return -EIO; - tmp2 &= 0x7f; - if ((tmp2 < tmp) || (tmp2 == 0)) - break; - } - - if (tmp != 0x7f) - *ucblocks = tmp; - else - *ucblocks = 0xffffffff; - - dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks); - return 0; -} - -static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int tmp; - - dprintk("%s\n", __func__); - - // read it in - tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB); - if (tmp < 0) - return -EIO; - *ber = tmp << 1; - tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB); - if (tmp < 0) - return -EIO; - *ber |= (tmp << 9); - // The address 0x20 should be read to cope with a TDA10046 bug - tda1004x_read_byte(state, TDA1004X_CBER_RESET); - - dprintk("%s: ber=0x%x\n", __func__, *ber); - return 0; -} - -static int tda1004x_sleep(struct dvb_frontend* fe) -{ - struct tda1004x_state* state = fe->demodulator_priv; - int gpio_conf; - - switch (state->demod_type) { - case TDA1004X_DEMOD_TDA10045: - tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10); - break; - - case TDA1004X_DEMOD_TDA10046: - /* set outputs to tristate */ - tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff); - /* invert GPIO 1 and 3 if desired*/ - gpio_conf = state->config->gpio_config; - if (gpio_conf >= TDA10046_GP00_I) - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, - (gpio_conf & 0x0f) ^ 0x0a); - - tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0); - tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); - break; - } - - return 0; -} - -static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct tda1004x_state* state = fe->demodulator_priv; - - if (enable) { - return tda1004x_enable_tuner_i2c(state); - } else { - return tda1004x_disable_tuner_i2c(state); - } -} - -static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) -{ - fesettings->min_delay_ms = 800; - /* Drift compensation makes no sense for DVB-T */ - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static void tda1004x_release(struct dvb_frontend* fe) -{ - struct tda1004x_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops tda10045_ops = { - .info = { - .name = "Philips TDA10045H DVB-T", - .type = FE_OFDM, - .frequency_min = 51000000, - .frequency_max = 858000000, - .frequency_stepsize = 166667, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO - }, - - .release = tda1004x_release, - - .init = tda10045_init, - .sleep = tda1004x_sleep, - .write = tda1004x_write, - .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl, - - .set_frontend = tda1004x_set_fe, - .get_frontend = tda1004x_get_fe, - .get_tune_settings = tda1004x_get_tune_settings, - - .read_status = tda1004x_read_status, - .read_ber = tda1004x_read_ber, - .read_signal_strength = tda1004x_read_signal_strength, - .read_snr = tda1004x_read_snr, - .read_ucblocks = tda1004x_read_ucblocks, -}; - -struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, - struct i2c_adapter* i2c) -{ - struct tda1004x_state *state; - int id; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); - if (!state) { - printk(KERN_ERR "Can't alocate memory for tda10045 state\n"); - return NULL; - } - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->demod_type = TDA1004X_DEMOD_TDA10045; - - /* check if the demod is there */ - id = tda1004x_read_byte(state, TDA1004X_CHIPID); - if (id < 0) { - printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n"); - kfree(state); - return NULL; - } - - if (id != 0x25) { - printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id); - kfree(state); - return NULL; - } - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; -} - -static struct dvb_frontend_ops tda10046_ops = { - .info = { - .name = "Philips TDA10046H DVB-T", - .type = FE_OFDM, - .frequency_min = 51000000, - .frequency_max = 858000000, - .frequency_stepsize = 166667, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO - }, - - .release = tda1004x_release, - - .init = tda10046_init, - .sleep = tda1004x_sleep, - .write = tda1004x_write, - .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl, - - .set_frontend = tda1004x_set_fe, - .get_frontend = tda1004x_get_fe, - .get_tune_settings = tda1004x_get_tune_settings, - - .read_status = tda1004x_read_status, - .read_ber = tda1004x_read_ber, - .read_signal_strength = tda1004x_read_signal_strength, - .read_snr = tda1004x_read_snr, - .read_ucblocks = tda1004x_read_ucblocks, -}; - -struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, - struct i2c_adapter* i2c) -{ - struct tda1004x_state *state; - int id; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); - if (!state) { - printk(KERN_ERR "Can't alocate memory for tda10046 state\n"); - return NULL; - } - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->demod_type = TDA1004X_DEMOD_TDA10046; - - /* check if the demod is there */ - id = tda1004x_read_byte(state, TDA1004X_CHIPID); - if (id < 0) { - printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n"); - kfree(state); - return NULL; - } - if (id != 0x46) { - printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id); - kfree(state); - return NULL; - } - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; -} - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator"); -MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(tda10045_attach); -EXPORT_SYMBOL(tda10046_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1004x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1004x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1004x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda1004x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,149 +0,0 @@ - /* - Driver for Philips tda1004xh OFDM Frontend - - (c) 2004 Andrew de Quincey - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef TDA1004X_H -#define TDA1004X_H - -#include -#include - -enum tda10046_xtal { - TDA10046_XTAL_4M, - TDA10046_XTAL_16M, -}; - -enum tda10046_agc { - TDA10046_AGC_DEFAULT, /* original configuration */ - TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ - TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ - TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ -}; - -/* Many (hybrid) boards use GPIO 1 and 3 - GPIO1 analog - dvb switch - GPIO3 firmware eeprom address switch -*/ -enum tda10046_gpio { - TDA10046_GPTRI = 0x00, /* All GPIOs tristate */ - TDA10046_GP00 = 0x40, /* GPIO3=0, GPIO1=0 */ - TDA10046_GP01 = 0x42, /* GPIO3=0, GPIO1=1 */ - TDA10046_GP10 = 0x48, /* GPIO3=1, GPIO1=0 */ - TDA10046_GP11 = 0x4a, /* GPIO3=1, GPIO1=1 */ - TDA10046_GP00_I = 0x80, /* GPIO3=0, GPIO1=0, invert in sleep mode*/ - TDA10046_GP01_I = 0x82, /* GPIO3=0, GPIO1=1, invert in sleep mode */ - TDA10046_GP10_I = 0x88, /* GPIO3=1, GPIO1=0, invert in sleep mode */ - TDA10046_GP11_I = 0x8a, /* GPIO3=1, GPIO1=1, invert in sleep mode */ -}; - -enum tda10046_if { - TDA10046_FREQ_3617, /* original config, 36,166 MHZ */ - TDA10046_FREQ_3613, /* 36,13 MHZ */ - TDA10046_FREQ_045, /* low IF, 4.0, 4.5, or 5.0 MHZ */ - TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */ -}; - -enum tda10046_tsout { - TDA10046_TS_PARALLEL = 0x00, /* parallel transport stream, default */ - TDA10046_TS_SERIAL = 0x01, /* serial transport stream */ -}; - -struct tda1004x_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* does the "inversion" need inverted? */ - u8 invert; - - /* Does the OCLK signal need inverted? */ - u8 invert_oclk; - - /* parallel or serial transport stream */ - enum tda10046_tsout ts_mode; - - /* Xtal frequency, 4 or 16MHz*/ - enum tda10046_xtal xtal_freq; - - /* IF frequency */ - enum tda10046_if if_freq; - - /* AGC configuration */ - enum tda10046_agc agc_config; - - /* setting of GPIO1 and 3 */ - enum tda10046_gpio gpio_config; - - /* slave address and configuration of the tuner */ - u8 tuner_address; - u8 antenna_switch; - - /* if the board uses another I2c Bridge (tda8290), its address */ - u8 i2c_gate; - - /* request firmware for device */ - int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); -}; - -enum tda1004x_demod { - TDA1004X_DEMOD_TDA10045, - TDA1004X_DEMOD_TDA10046, -}; - -struct tda1004x_state { - struct i2c_adapter* i2c; - const struct tda1004x_config* config; - struct dvb_frontend frontend; - - /* private demod data */ - enum tda1004x_demod demod_type; -}; - -#if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, - struct i2c_adapter* i2c); - -extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static inline struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_TDA1004X - -static inline int tda1004x_writereg(struct dvb_frontend *fe, u8 reg, u8 val) { - int r = 0; - u8 buf[] = {reg, val}; - if (fe->ops.write) - r = fe->ops.write(fe, buf, 2); - return r; -} - -#endif // TDA1004X_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10086.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10086.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10086.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10086.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,775 +0,0 @@ - /* - Driver for Philips tda10086 DVBS Demodulator - - (c) 2006 Andrew de Quincey - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "tda10086.h" - -#define SACLK 96000000 - -struct tda10086_state { - struct i2c_adapter* i2c; - const struct tda10086_config* config; - struct dvb_frontend frontend; - - /* private demod data */ - u32 frequency; - u32 symbol_rate; - bool has_lock; -}; - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "tda10086: " args); \ - } while (0) - -static int tda10086_write_byte(struct tda10086_state *state, int reg, int data) -{ - int ret; - u8 b0[] = { reg, data }; - struct i2c_msg msg = { .flags = 0, .buf = b0, .len = 2 }; - - msg.addr = state->config->demod_address; - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", - __func__, reg, data, ret); - - return (ret != 1) ? ret : 0; -} - -static int tda10086_read_byte(struct tda10086_state *state, int reg) -{ - int ret; - u8 b0[] = { reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 }, - { .flags = I2C_M_RD, .buf = b1, .len = 1 }}; - - msg[0].addr = state->config->demod_address; - msg[1].addr = state->config->demod_address; - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, - ret); - return ret; - } - - return b1[0]; -} - -static int tda10086_write_mask(struct tda10086_state *state, int reg, int mask, int data) -{ - int val; - - /* read a byte and check */ - val = tda10086_read_byte(state, reg); - if (val < 0) - return val; - - /* mask if off */ - val = val & ~mask; - val |= data & 0xff; - - /* write it out again */ - return tda10086_write_byte(state, reg, val); -} - -static int tda10086_init(struct dvb_frontend* fe) -{ - struct tda10086_state* state = fe->demodulator_priv; - u8 t22k_off = 0x80; - - dprintk ("%s\n", __func__); - - if (state->config->diseqc_tone) - t22k_off = 0; - /* reset */ - tda10086_write_byte(state, 0x00, 0x00); - msleep(10); - - /* misc setup */ - tda10086_write_byte(state, 0x01, 0x94); - tda10086_write_byte(state, 0x02, 0x35); /* NOTE: TT drivers appear to disable CSWP */ - tda10086_write_byte(state, 0x03, 0xe4); - tda10086_write_byte(state, 0x04, 0x43); - tda10086_write_byte(state, 0x0c, 0x0c); - tda10086_write_byte(state, 0x1b, 0xb0); /* noise threshold */ - tda10086_write_byte(state, 0x20, 0x89); /* misc */ - tda10086_write_byte(state, 0x30, 0x04); /* acquisition period length */ - tda10086_write_byte(state, 0x32, 0x00); /* irq off */ - tda10086_write_byte(state, 0x31, 0x56); /* setup AFC */ - - /* setup PLL (this assumes SACLK = 96MHz) */ - tda10086_write_byte(state, 0x55, 0x2c); /* misc PLL setup */ - if (state->config->xtal_freq == TDA10086_XTAL_16M) { - tda10086_write_byte(state, 0x3a, 0x0b); /* M=12 */ - tda10086_write_byte(state, 0x3b, 0x01); /* P=2 */ - } else { - tda10086_write_byte(state, 0x3a, 0x17); /* M=24 */ - tda10086_write_byte(state, 0x3b, 0x00); /* P=1 */ - } - tda10086_write_mask(state, 0x55, 0x20, 0x00); /* powerup PLL */ - - /* setup TS interface */ - tda10086_write_byte(state, 0x11, 0x81); - tda10086_write_byte(state, 0x12, 0x81); - tda10086_write_byte(state, 0x19, 0x40); /* parallel mode A + MSBFIRST */ - tda10086_write_byte(state, 0x56, 0x80); /* powerdown WPLL - unused in the mode we use */ - tda10086_write_byte(state, 0x57, 0x08); /* bypass WPLL - unused in the mode we use */ - tda10086_write_byte(state, 0x10, 0x2a); - - /* setup ADC */ - tda10086_write_byte(state, 0x58, 0x61); /* ADC setup */ - tda10086_write_mask(state, 0x58, 0x01, 0x00); /* powerup ADC */ - - /* setup AGC */ - tda10086_write_byte(state, 0x05, 0x0B); - tda10086_write_byte(state, 0x37, 0x63); - tda10086_write_byte(state, 0x3f, 0x0a); /* NOTE: flydvb varies it */ - tda10086_write_byte(state, 0x40, 0x64); - tda10086_write_byte(state, 0x41, 0x4f); - tda10086_write_byte(state, 0x42, 0x43); - - /* setup viterbi */ - tda10086_write_byte(state, 0x1a, 0x11); /* VBER 10^6, DVB, QPSK */ - - /* setup carrier recovery */ - tda10086_write_byte(state, 0x3d, 0x80); - - /* setup SEC */ - tda10086_write_byte(state, 0x36, t22k_off); /* all SEC off, 22k tone */ - tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000))); - tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); - - return 0; -} - -static void tda10086_diseqc_wait(struct tda10086_state *state) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(200); - while (!(tda10086_read_byte(state, 0x50) & 0x01)) { - if(time_after(jiffies, timeout)) { - printk("%s: diseqc queue not ready, command may be lost.\n", __func__); - break; - } - msleep(10); - } -} - -static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct tda10086_state* state = fe->demodulator_priv; - u8 t22k_off = 0x80; - - dprintk ("%s\n", __func__); - - if (state->config->diseqc_tone) - t22k_off = 0; - - switch (tone) { - case SEC_TONE_OFF: - tda10086_write_byte(state, 0x36, t22k_off); - break; - - case SEC_TONE_ON: - tda10086_write_byte(state, 0x36, 0x01 + t22k_off); - break; - } - - return 0; -} - -static int tda10086_send_master_cmd (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd* cmd) -{ - struct tda10086_state* state = fe->demodulator_priv; - int i; - u8 oldval; - u8 t22k_off = 0x80; - - dprintk ("%s\n", __func__); - - if (state->config->diseqc_tone) - t22k_off = 0; - - if (cmd->msg_len > 6) - return -EINVAL; - oldval = tda10086_read_byte(state, 0x36); - - for(i=0; i< cmd->msg_len; i++) { - tda10086_write_byte(state, 0x48+i, cmd->msg[i]); - } - tda10086_write_byte(state, 0x36, (0x08 + t22k_off) - | ((cmd->msg_len - 1) << 4)); - - tda10086_diseqc_wait(state); - - tda10086_write_byte(state, 0x36, oldval); - - return 0; -} - -static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct tda10086_state* state = fe->demodulator_priv; - u8 oldval = tda10086_read_byte(state, 0x36); - u8 t22k_off = 0x80; - - dprintk ("%s\n", __func__); - - if (state->config->diseqc_tone) - t22k_off = 0; - - switch(minicmd) { - case SEC_MINI_A: - tda10086_write_byte(state, 0x36, 0x04 + t22k_off); - break; - - case SEC_MINI_B: - tda10086_write_byte(state, 0x36, 0x06 + t22k_off); - break; - } - - tda10086_diseqc_wait(state); - - tda10086_write_byte(state, 0x36, oldval); - - return 0; -} - -static int tda10086_set_inversion(struct tda10086_state *state, - struct dvb_frontend_parameters *fe_params) -{ - u8 invval = 0x80; - - dprintk ("%s %i %i\n", __func__, fe_params->inversion, state->config->invert); - - switch(fe_params->inversion) { - case INVERSION_OFF: - if (state->config->invert) - invval = 0x40; - break; - case INVERSION_ON: - if (!state->config->invert) - invval = 0x40; - break; - case INVERSION_AUTO: - invval = 0x00; - break; - } - tda10086_write_mask(state, 0x0c, 0xc0, invval); - - return 0; -} - -static int tda10086_set_symbol_rate(struct tda10086_state *state, - struct dvb_frontend_parameters *fe_params) -{ - u8 dfn = 0; - u8 afs = 0; - u8 byp = 0; - u8 reg37 = 0x43; - u8 reg42 = 0x43; - u64 big; - u32 tmp; - u32 bdr; - u32 bdri; - u32 symbol_rate = fe_params->u.qpsk.symbol_rate; - - dprintk ("%s %i\n", __func__, symbol_rate); - - /* setup the decimation and anti-aliasing filters.. */ - if (symbol_rate < (u32) (SACLK * 0.0137)) { - dfn=4; - afs=1; - } else if (symbol_rate < (u32) (SACLK * 0.0208)) { - dfn=4; - afs=0; - } else if (symbol_rate < (u32) (SACLK * 0.0270)) { - dfn=3; - afs=1; - } else if (symbol_rate < (u32) (SACLK * 0.0416)) { - dfn=3; - afs=0; - } else if (symbol_rate < (u32) (SACLK * 0.0550)) { - dfn=2; - afs=1; - } else if (symbol_rate < (u32) (SACLK * 0.0833)) { - dfn=2; - afs=0; - } else if (symbol_rate < (u32) (SACLK * 0.1100)) { - dfn=1; - afs=1; - } else if (symbol_rate < (u32) (SACLK * 0.1666)) { - dfn=1; - afs=0; - } else if (symbol_rate < (u32) (SACLK * 0.2200)) { - dfn=0; - afs=1; - } else if (symbol_rate < (u32) (SACLK * 0.3333)) { - dfn=0; - afs=0; - } else { - reg37 = 0x63; - reg42 = 0x4f; - byp=1; - } - - /* calculate BDR */ - big = (1ULL<<21) * ((u64) symbol_rate/1000ULL) * (1ULL<> 8); - tda10086_write_byte(state, 0x08, bdr >> 16); - tda10086_write_byte(state, 0x09, bdri); - tda10086_write_byte(state, 0x37, reg37); - tda10086_write_byte(state, 0x42, reg42); - - return 0; -} - -static int tda10086_set_fec(struct tda10086_state *state, - struct dvb_frontend_parameters *fe_params) -{ - u8 fecval; - - dprintk ("%s %i\n", __func__, fe_params->u.qpsk.fec_inner); - - switch(fe_params->u.qpsk.fec_inner) { - case FEC_1_2: - fecval = 0x00; - break; - case FEC_2_3: - fecval = 0x01; - break; - case FEC_3_4: - fecval = 0x02; - break; - case FEC_4_5: - fecval = 0x03; - break; - case FEC_5_6: - fecval = 0x04; - break; - case FEC_6_7: - fecval = 0x05; - break; - case FEC_7_8: - fecval = 0x06; - break; - case FEC_8_9: - fecval = 0x07; - break; - case FEC_AUTO: - fecval = 0x08; - break; - default: - return -1; - } - tda10086_write_byte(state, 0x0d, fecval); - - return 0; -} - -static int tda10086_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fe_params) -{ - struct tda10086_state *state = fe->demodulator_priv; - int ret; - u32 freq = 0; - int freqoff; - - dprintk ("%s\n", __func__); - - /* modify parameters for tuning */ - tda10086_write_byte(state, 0x02, 0x35); - state->has_lock = false; - - /* set params */ - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (fe->ops.tuner_ops.get_frequency) - fe->ops.tuner_ops.get_frequency(fe, &freq); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - - /* calcluate the frequency offset (in *Hz* not kHz) */ - freqoff = fe_params->frequency - freq; - freqoff = ((1<<16) * freqoff) / (SACLK/1000); - tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f)); - tda10086_write_byte(state, 0x3e, freqoff); - - if ((ret = tda10086_set_inversion(state, fe_params)) < 0) - return ret; - if ((ret = tda10086_set_symbol_rate(state, fe_params)) < 0) - return ret; - if ((ret = tda10086_set_fec(state, fe_params)) < 0) - return ret; - - /* soft reset + disable TS output until lock */ - tda10086_write_mask(state, 0x10, 0x40, 0x40); - tda10086_write_mask(state, 0x00, 0x01, 0x00); - - state->symbol_rate = fe_params->u.qpsk.symbol_rate; - state->frequency = fe_params->frequency; - return 0; -} - -static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) -{ - struct tda10086_state* state = fe->demodulator_priv; - u8 val; - int tmp; - u64 tmp64; - - dprintk ("%s\n", __func__); - - /* check for invalid symbol rate */ - if (fe_params->u.qpsk.symbol_rate < 500000) - return -EINVAL; - - /* calculate the updated frequency (note: we convert from Hz->kHz) */ - tmp64 = tda10086_read_byte(state, 0x52); - tmp64 |= (tda10086_read_byte(state, 0x51) << 8); - if (tmp64 & 0x8000) - tmp64 |= 0xffffffffffff0000ULL; - tmp64 = (tmp64 * (SACLK/1000ULL)); - do_div(tmp64, (1ULL<<15) * (1ULL<<1)); - fe_params->frequency = (int) state->frequency + (int) tmp64; - - /* the inversion */ - val = tda10086_read_byte(state, 0x0c); - if (val & 0x80) { - switch(val & 0x40) { - case 0x00: - fe_params->inversion = INVERSION_OFF; - if (state->config->invert) - fe_params->inversion = INVERSION_ON; - break; - default: - fe_params->inversion = INVERSION_ON; - if (state->config->invert) - fe_params->inversion = INVERSION_OFF; - break; - } - } else { - tda10086_read_byte(state, 0x0f); - switch(val & 0x02) { - case 0x00: - fe_params->inversion = INVERSION_OFF; - if (state->config->invert) - fe_params->inversion = INVERSION_ON; - break; - default: - fe_params->inversion = INVERSION_ON; - if (state->config->invert) - fe_params->inversion = INVERSION_OFF; - break; - } - } - - /* calculate the updated symbol rate */ - tmp = tda10086_read_byte(state, 0x1d); - if (tmp & 0x80) - tmp |= 0xffffff00; - tmp = (tmp * 480 * (1<<1)) / 128; - tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000); - fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp; - - /* the FEC */ - val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4; - switch(val) { - case 0x00: - fe_params->u.qpsk.fec_inner = FEC_1_2; - break; - case 0x01: - fe_params->u.qpsk.fec_inner = FEC_2_3; - break; - case 0x02: - fe_params->u.qpsk.fec_inner = FEC_3_4; - break; - case 0x03: - fe_params->u.qpsk.fec_inner = FEC_4_5; - break; - case 0x04: - fe_params->u.qpsk.fec_inner = FEC_5_6; - break; - case 0x05: - fe_params->u.qpsk.fec_inner = FEC_6_7; - break; - case 0x06: - fe_params->u.qpsk.fec_inner = FEC_7_8; - break; - case 0x07: - fe_params->u.qpsk.fec_inner = FEC_8_9; - break; - } - - return 0; -} - -static int tda10086_read_status(struct dvb_frontend* fe, fe_status_t *fe_status) -{ - struct tda10086_state* state = fe->demodulator_priv; - u8 val; - - dprintk ("%s\n", __func__); - - val = tda10086_read_byte(state, 0x0e); - *fe_status = 0; - if (val & 0x01) - *fe_status |= FE_HAS_SIGNAL; - if (val & 0x02) - *fe_status |= FE_HAS_CARRIER; - if (val & 0x04) - *fe_status |= FE_HAS_VITERBI; - if (val & 0x08) - *fe_status |= FE_HAS_SYNC; - if (val & 0x10) { - *fe_status |= FE_HAS_LOCK; - if (!state->has_lock) { - state->has_lock = true; - /* modify parameters for stable reception */ - tda10086_write_byte(state, 0x02, 0x00); - } - } - - return 0; -} - -static int tda10086_read_signal_strength(struct dvb_frontend* fe, u16 * signal) -{ - struct tda10086_state* state = fe->demodulator_priv; - u8 _str; - - dprintk ("%s\n", __func__); - - _str = 0xff - tda10086_read_byte(state, 0x43); - *signal = (_str << 8) | _str; - - return 0; -} - -static int tda10086_read_snr(struct dvb_frontend* fe, u16 * snr) -{ - struct tda10086_state* state = fe->demodulator_priv; - u8 _snr; - - dprintk ("%s\n", __func__); - - _snr = 0xff - tda10086_read_byte(state, 0x1c); - *snr = (_snr << 8) | _snr; - - return 0; -} - -static int tda10086_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct tda10086_state* state = fe->demodulator_priv; - - dprintk ("%s\n", __func__); - - /* read it */ - *ucblocks = tda10086_read_byte(state, 0x18) & 0x7f; - - /* reset counter */ - tda10086_write_byte(state, 0x18, 0x00); - tda10086_write_byte(state, 0x18, 0x80); - - return 0; -} - -static int tda10086_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct tda10086_state* state = fe->demodulator_priv; - - dprintk ("%s\n", __func__); - - /* read it */ - *ber = 0; - *ber |= tda10086_read_byte(state, 0x15); - *ber |= tda10086_read_byte(state, 0x16) << 8; - *ber |= (tda10086_read_byte(state, 0x17) & 0xf) << 16; - - return 0; -} - -static int tda10086_sleep(struct dvb_frontend* fe) -{ - struct tda10086_state* state = fe->demodulator_priv; - - dprintk ("%s\n", __func__); - - tda10086_write_mask(state, 0x00, 0x08, 0x08); - - return 0; -} - -static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct tda10086_state* state = fe->demodulator_priv; - - dprintk ("%s\n", __func__); - - if (enable) { - tda10086_write_mask(state, 0x00, 0x10, 0x10); - } else { - tda10086_write_mask(state, 0x00, 0x10, 0x00); - } - - return 0; -} - -static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) -{ - if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { - fesettings->min_delay_ms = 50; - fesettings->step_size = 2000; - fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { - fesettings->min_delay_ms = 100; - fesettings->step_size = 1500; - fesettings->max_drift = 9000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { - fesettings->min_delay_ms = 100; - fesettings->step_size = 1000; - fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { - fesettings->min_delay_ms = 100; - fesettings->step_size = 500; - fesettings->max_drift = 7000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { - fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); - fesettings->max_drift = 14 * fesettings->step_size; - } else { - fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); - fesettings->max_drift = 18 * fesettings->step_size; - } - - return 0; -} - -static void tda10086_release(struct dvb_frontend* fe) -{ - struct tda10086_state *state = fe->demodulator_priv; - tda10086_sleep(fe); - kfree(state); -} - -static struct dvb_frontend_ops tda10086_ops = { - - .info = { - .name = "Philips TDA10086 DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, /* kHz for QPSK frontends */ - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK - }, - - .release = tda10086_release, - - .init = tda10086_init, - .sleep = tda10086_sleep, - .i2c_gate_ctrl = tda10086_i2c_gate_ctrl, - - .set_frontend = tda10086_set_frontend, - .get_frontend = tda10086_get_frontend, - .get_tune_settings = tda10086_get_tune_settings, - - .read_status = tda10086_read_status, - .read_ber = tda10086_read_ber, - .read_signal_strength = tda10086_read_signal_strength, - .read_snr = tda10086_read_snr, - .read_ucblocks = tda10086_read_ucblocks, - - .diseqc_send_master_cmd = tda10086_send_master_cmd, - .diseqc_send_burst = tda10086_send_burst, - .set_tone = tda10086_set_tone, -}; - -struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, - struct i2c_adapter* i2c) -{ - struct tda10086_state *state; - - dprintk ("%s\n", __func__); - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct tda10086_state), GFP_KERNEL); - if (!state) - return NULL; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* check if the demod is there */ - if (tda10086_read_byte(state, 0x1e) != 0xe1) { - kfree(state); - return NULL; - } - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &tda10086_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; -} - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Philips TDA10086 DVB-S Demodulator"); -MODULE_AUTHOR("Andrew de Quincey"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(tda10086_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10086.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10086.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10086.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda10086.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ - /* - Driver for Philips tda10086 DVBS Frontend - - (c) 2006 Andrew de Quincey - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef TDA10086_H -#define TDA10086_H - -#include -#include - -enum tda10086_xtal { - TDA10086_XTAL_16M, - TDA10086_XTAL_4M -}; - -struct tda10086_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* does the "inversion" need inverted? */ - u8 invert; - - /* do we need the diseqc signal with carrier? */ - u8 diseqc_tone; - - /* frequency of the reference xtal */ - enum tda10086_xtal xtal_freq; -}; - -#if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_TDA10086 */ - -#endif /* TDA10086_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda665x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda665x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda665x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda665x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,258 +0,0 @@ -/* - TDA665x tuner driver - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "tda665x.h" - -struct tda665x_state { - struct dvb_frontend *fe; - struct i2c_adapter *i2c; - const struct tda665x_config *config; - - u32 frequency; - u32 bandwidth; -}; - -static int tda665x_read(struct tda665x_state *state, u8 *buf) -{ - const struct tda665x_config *config = state->config; - int err = 0; - struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 }; - - err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) - goto exit; - - return err; -exit: - printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err); - return err; -} - -static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length) -{ - const struct tda665x_config *config = state->config; - int err = 0; - struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length }; - - err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) - goto exit; - - return err; -exit: - printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err); - return err; -} - -static int tda665x_get_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *tstate) -{ - struct tda665x_state *state = fe->tuner_priv; - int err = 0; - - switch (param) { - case DVBFE_TUNER_FREQUENCY: - tstate->frequency = state->frequency; - break; - case DVBFE_TUNER_BANDWIDTH: - break; - default: - printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); - err = -EINVAL; - break; - } - - return err; -} - -static int tda665x_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct tda665x_state *state = fe->tuner_priv; - u8 result = 0; - int err = 0; - - *status = 0; - - err = tda665x_read(state, &result); - if (err < 0) - goto exit; - - if ((result >> 6) & 0x01) { - printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__); - *status = 1; - } - - return err; -exit: - printk(KERN_ERR "%s: I/O Error\n", __func__); - return err; -} - -static int tda665x_set_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *tstate) -{ - struct tda665x_state *state = fe->tuner_priv; - const struct tda665x_config *config = state->config; - u32 frequency, status = 0; - u8 buf[4]; - int err = 0; - - if (param & DVBFE_TUNER_FREQUENCY) { - - frequency = tstate->frequency; - if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) { - printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); - return -EINVAL; - } - - frequency += config->frequency_offst; - frequency *= config->ref_multiplier; - frequency += config->ref_divider >> 1; - frequency /= config->ref_divider; - - buf[0] = (u8) ((frequency & 0x7f00) >> 8); - buf[1] = (u8) (frequency & 0x00ff) >> 0; - buf[2] = 0x80 | 0x40 | 0x02; - buf[3] = 0x00; - - /* restore frequency */ - frequency = tstate->frequency; - - if (frequency < 153000000) { - /* VHF-L */ - buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */ - if (frequency < 68000000) - buf[3] |= 0x40; /* 83uA */ - if (frequency < 1040000000) - buf[3] |= 0x60; /* 122uA */ - if (frequency < 1250000000) - buf[3] |= 0x80; /* 163uA */ - else - buf[3] |= 0xa0; /* 254uA */ - } else if (frequency < 438000000) { - /* VHF-H */ - buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */ - if (frequency < 230000000) - buf[3] |= 0x40; - if (frequency < 300000000) - buf[3] |= 0x60; - else - buf[3] |= 0x80; - } else { - /* UHF */ - buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */ - if (frequency < 470000000) - buf[3] |= 0x60; - if (frequency < 526000000) - buf[3] |= 0x80; - else - buf[3] |= 0xa0; - } - - /* Set params */ - err = tda665x_write(state, buf, 5); - if (err < 0) - goto exit; - - /* sleep for some time */ - printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__); - msleep(20); - /* check status */ - err = tda665x_get_status(fe, &status); - if (err < 0) - goto exit; - - if (status == 1) { - printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status); - state->frequency = frequency; /* cache successful state */ - } else { - printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status); - } - } else { - printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); - return -EINVAL; - } - - return 0; -exit: - printk(KERN_ERR "%s: I/O Error\n", __func__); - return err; -} - -static int tda665x_release(struct dvb_frontend *fe) -{ - struct tda665x_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - return 0; -} - -static struct dvb_tuner_ops tda665x_ops = { - - .set_state = tda665x_set_state, - .get_state = tda665x_get_state, - .get_status = tda665x_get_status, - .release = tda665x_release -}; - -struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, - const struct tda665x_config *config, - struct i2c_adapter *i2c) -{ - struct tda665x_state *state = NULL; - struct dvb_tuner_info *info; - - state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL); - if (state == NULL) - goto exit; - - state->config = config; - state->i2c = i2c; - state->fe = fe; - fe->tuner_priv = state; - fe->ops.tuner_ops = tda665x_ops; - info = &fe->ops.tuner_ops.info; - - memcpy(info->name, config->name, sizeof(config->name)); - info->frequency_min = config->frequency_min; - info->frequency_max = config->frequency_max; - info->frequency_step = config->frequency_offst; - - printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name); - - return fe; - -exit: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(tda665x_attach); - -MODULE_DESCRIPTION("TDA665x driver"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda665x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda665x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda665x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda665x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - TDA665x tuner driver - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TDA665x_H -#define __TDA665x_H - -struct tda665x_config { - char name[128]; - - u8 addr; - u32 frequency_min; - u32 frequency_max; - u32 frequency_offst; - u32 ref_multiplier; - u32 ref_divider; -}; - -#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE)) - -extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, - const struct tda665x_config *config, - struct i2c_adapter *i2c); - -#else - -static inline struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, - const struct tda665x_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); - return NULL; -} - -#endif /* CONFIG_DVB_TDA665x */ - -#endif /* __TDA665x_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8083.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8083.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8083.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8083.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,486 +0,0 @@ -/* - Driver for Philips TDA8083 based QPSK Demodulator - - Copyright (C) 2001 Convergence Integrated Media GmbH - - written by Ralph Metzler - - adoption to the new DVB frontend API and diagnostic ioctl's - by Holger Waechtler - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "tda8083.h" - - -struct tda8083_state { - struct i2c_adapter* i2c; - /* configuration settings */ - const struct tda8083_config* config; - struct dvb_frontend frontend; -}; - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "tda8083: " args); \ - } while (0) - - -static u8 tda8083_init_tab [] = { - 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea, - 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10, - 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8, - 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00, - 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - - -static int tda8083_writereg (struct tda8083_state* state, u8 reg, u8 data) -{ - int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - dprintk ("%s: writereg error (reg %02x, ret == %i)\n", - __func__, reg, ret); - - return (ret != 1) ? -1 : 0; -} - -static int tda8083_readregs (struct tda8083_state* state, u8 reg1, u8 *b, u8 len) -{ - int ret; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - dprintk ("%s: readreg error (reg %02x, ret == %i)\n", - __func__, reg1, ret); - - return ret == 2 ? 0 : -1; -} - -static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg) -{ - u8 val; - - tda8083_readregs (state, reg, &val, 1); - - return val; -} - -static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion) -{ - /* XXX FIXME: implement other modes than FEC_AUTO */ - if (inversion == INVERSION_AUTO) - return 0; - - return -EINVAL; -} - -static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec) -{ - if (fec == FEC_AUTO) - return tda8083_writereg (state, 0x07, 0xff); - - if (fec >= FEC_1_2 && fec <= FEC_8_9) - return tda8083_writereg (state, 0x07, 1 << (FEC_8_9 - fec)); - - return -EINVAL; -} - -static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state) -{ - u8 index; - static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, - FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 }; - - index = tda8083_readreg(state, 0x0e) & 0x07; - - return fec_tab [index]; -} - -static int tda8083_set_symbolrate (struct tda8083_state* state, u32 srate) -{ - u32 ratio; - u32 tmp; - u8 filter; - - if (srate > 32000000) - srate = 32000000; - if (srate < 500000) - srate = 500000; - - filter = 0; - if (srate < 24000000) - filter = 2; - if (srate < 16000000) - filter = 3; - - tmp = 31250 << 16; - ratio = tmp / srate; - - tmp = (tmp % srate) << 8; - ratio = (ratio << 8) + tmp / srate; - - tmp = (tmp % srate) << 8; - ratio = (ratio << 8) + tmp / srate; - - dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio); - - tda8083_writereg (state, 0x05, filter); - tda8083_writereg (state, 0x02, (ratio >> 16) & 0xff); - tda8083_writereg (state, 0x03, (ratio >> 8) & 0xff); - tda8083_writereg (state, 0x04, (ratio ) & 0xff); - - tda8083_writereg (state, 0x00, 0x3c); - tda8083_writereg (state, 0x00, 0x04); - - return 1; -} - -static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout) -{ - unsigned long start = jiffies; - - while (jiffies - start < timeout && - !(tda8083_readreg(state, 0x02) & 0x80)) - { - msleep(50); - }; -} - -static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone) -{ - tda8083_writereg (state, 0x26, 0xf1); - - switch (tone) { - case SEC_TONE_OFF: - return tda8083_writereg (state, 0x29, 0x00); - case SEC_TONE_ON: - return tda8083_writereg (state, 0x29, 0x80); - default: - return -EINVAL; - }; -} - -static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage) -{ - switch (voltage) { - case SEC_VOLTAGE_13: - return tda8083_writereg (state, 0x20, 0x00); - case SEC_VOLTAGE_18: - return tda8083_writereg (state, 0x20, 0x11); - default: - return -EINVAL; - }; -} - -static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst) -{ - switch (burst) { - case SEC_MINI_A: - tda8083_writereg (state, 0x29, (5 << 2)); /* send burst A */ - break; - case SEC_MINI_B: - tda8083_writereg (state, 0x29, (7 << 2)); /* send B */ - break; - default: - return -EINVAL; - }; - - tda8083_wait_diseqc_fifo (state, 100); - - return 0; -} - -static int tda8083_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) -{ - struct tda8083_state* state = fe->demodulator_priv; - int i; - - tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */ - - for (i=0; imsg_len; i++) - tda8083_writereg (state, 0x23 + i, m->msg[i]); - - tda8083_writereg (state, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */ - - tda8083_wait_diseqc_fifo (state, 100); - - return 0; -} - -static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct tda8083_state* state = fe->demodulator_priv; - - u8 signal = ~tda8083_readreg (state, 0x01); - u8 sync = tda8083_readreg (state, 0x02); - - *status = 0; - - if (signal > 10) - *status |= FE_HAS_SIGNAL; - - if (sync & 0x01) - *status |= FE_HAS_CARRIER; - - if (sync & 0x02) - *status |= FE_HAS_VITERBI; - - if (sync & 0x10) - *status |= FE_HAS_SYNC; - - if (sync & 0x20) /* frontend can not lock */ - *status |= FE_TIMEDOUT; - - if ((sync & 0x1f) == 0x1f) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int tda8083_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct tda8083_state* state = fe->demodulator_priv; - int ret; - u8 buf[3]; - - if ((ret = tda8083_readregs(state, 0x0b, buf, sizeof(buf)))) - return ret; - - *ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2]; - - return 0; -} - -static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct tda8083_state* state = fe->demodulator_priv; - - u8 signal = ~tda8083_readreg (state, 0x01); - *strength = (signal << 8) | signal; - - return 0; -} - -static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct tda8083_state* state = fe->demodulator_priv; - - u8 _snr = tda8083_readreg (state, 0x08); - *snr = (_snr << 8) | _snr; - - return 0; -} - -static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct tda8083_state* state = fe->demodulator_priv; - - *ucblocks = tda8083_readreg(state, 0x0f); - if (*ucblocks == 0xff) - *ucblocks = 0xffffffff; - - return 0; -} - -static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct tda8083_state* state = fe->demodulator_priv; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - tda8083_set_inversion (state, p->inversion); - tda8083_set_fec (state, p->u.qpsk.fec_inner); - tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate); - - tda8083_writereg (state, 0x00, 0x3c); - tda8083_writereg (state, 0x00, 0x04); - - return 0; -} - -static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct tda8083_state* state = fe->demodulator_priv; - - /* FIXME: get symbolrate & frequency offset...*/ - /*p->frequency = ???;*/ - p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ? - INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = tda8083_get_fec (state); - /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/ - - return 0; -} - -static int tda8083_sleep(struct dvb_frontend* fe) -{ - struct tda8083_state* state = fe->demodulator_priv; - - tda8083_writereg (state, 0x00, 0x02); - return 0; -} - -static int tda8083_init(struct dvb_frontend* fe) -{ - struct tda8083_state* state = fe->demodulator_priv; - int i; - - for (i=0; i<44; i++) - tda8083_writereg (state, i, tda8083_init_tab[i]); - - tda8083_writereg (state, 0x00, 0x3c); - tda8083_writereg (state, 0x00, 0x04); - - return 0; -} - -static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) -{ - struct tda8083_state* state = fe->demodulator_priv; - - tda8083_send_diseqc_burst (state, burst); - tda8083_writereg (state, 0x00, 0x3c); - tda8083_writereg (state, 0x00, 0x04); - - return 0; -} - -static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct tda8083_state* state = fe->demodulator_priv; - - tda8083_set_tone (state, tone); - tda8083_writereg (state, 0x00, 0x3c); - tda8083_writereg (state, 0x00, 0x04); - - return 0; -} - -static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct tda8083_state* state = fe->demodulator_priv; - - tda8083_set_voltage (state, voltage); - tda8083_writereg (state, 0x00, 0x3c); - tda8083_writereg (state, 0x00, 0x04); - - return 0; -} - -static void tda8083_release(struct dvb_frontend* fe) -{ - struct tda8083_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops tda8083_ops; - -struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, - struct i2c_adapter* i2c) -{ - struct tda8083_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct tda8083_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - - /* check if the demod is there */ - if ((tda8083_readreg(state, 0x00)) != 0x05) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops tda8083_ops = { - - .info = { - .name = "Philips TDA8083 DVB-S", - .type = FE_QPSK, - .frequency_min = 920000, /* TDA8060 */ - .frequency_max = 2200000, /* TDA8060 */ - .frequency_stepsize = 125, /* kHz for QPSK frontends */ - /* .frequency_tolerance = ???,*/ - .symbol_rate_min = 12000000, - .symbol_rate_max = 30000000, - /* .symbol_rate_tolerance = ???,*/ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_MUTE_TS - }, - - .release = tda8083_release, - - .init = tda8083_init, - .sleep = tda8083_sleep, - - .set_frontend = tda8083_set_frontend, - .get_frontend = tda8083_get_frontend, - - .read_status = tda8083_read_status, - .read_signal_strength = tda8083_read_signal_strength, - .read_snr = tda8083_read_snr, - .read_ber = tda8083_read_ber, - .read_ucblocks = tda8083_read_ucblocks, - - .diseqc_send_master_cmd = tda8083_send_diseqc_msg, - .diseqc_send_burst = tda8083_diseqc_send_burst, - .set_tone = tda8083_diseqc_set_tone, - .set_voltage = tda8083_diseqc_set_voltage, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("Philips TDA8083 DVB-S Demodulator"); -MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(tda8083_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8083.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8083.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8083.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8083.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend - - Copyright (C) 2001 Convergence Integrated Media GmbH - - written by Ralph Metzler - - adoption to the new DVB frontend API and diagnostic ioctl's - by Holger Waechtler - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef TDA8083_H -#define TDA8083_H - -#include - -struct tda8083_config -{ - /* the demodulator's i2c address */ - u8 demod_address; -}; - -#if defined(CONFIG_DVB_TDA8083) || (defined(CONFIG_DVB_TDA8083_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_TDA8083 - -#endif // TDA8083_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,231 +0,0 @@ -/* - TDA8261 8PSK/QPSK tuner driver - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "tda8261.h" - -struct tda8261_state { - struct dvb_frontend *fe; - struct i2c_adapter *i2c; - const struct tda8261_config *config; - - /* state cache */ - u32 frequency; - u32 bandwidth; -}; - -static int tda8261_read(struct tda8261_state *state, u8 *buf) -{ - const struct tda8261_config *config = state->config; - int err = 0; - struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 1 }; - - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) - printk("%s: read error, err=%d\n", __func__, err); - - return err; -} - -static int tda8261_write(struct tda8261_state *state, u8 *buf) -{ - const struct tda8261_config *config = state->config; - int err = 0; - struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 }; - - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) - printk("%s: write error, err=%d\n", __func__, err); - - return err; -} - -static int tda8261_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct tda8261_state *state = fe->tuner_priv; - u8 result = 0; - int err = 0; - - *status = 0; - - if ((err = tda8261_read(state, &result)) < 0) { - printk("%s: I/O Error\n", __func__); - return err; - } - if ((result >> 6) & 0x01) { - printk("%s: Tuner Phase Locked\n", __func__); - *status = 1; - } - - return err; -} - -static const u32 div_tab[] = { 2000, 1000, 500, 250, 125 }; /* kHz */ -static const u8 ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 }; - -static int tda8261_get_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *tstate) -{ - struct tda8261_state *state = fe->tuner_priv; - int err = 0; - - switch (param) { - case DVBFE_TUNER_FREQUENCY: - tstate->frequency = state->frequency; - break; - case DVBFE_TUNER_BANDWIDTH: - tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */ - break; - default: - printk("%s: Unknown parameter (param=%d)\n", __func__, param); - err = -EINVAL; - break; - } - - return err; -} - -static int tda8261_set_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *tstate) -{ - struct tda8261_state *state = fe->tuner_priv; - const struct tda8261_config *config = state->config; - u32 frequency, N, status = 0; - u8 buf[4]; - int err = 0; - - if (param & DVBFE_TUNER_FREQUENCY) { - /** - * N = Max VCO Frequency / Channel Spacing - * Max VCO Frequency = VCO frequency + (channel spacing - 1) - * (to account for half channel spacing on either side) - */ - frequency = tstate->frequency; - if ((frequency < 950000) || (frequency > 2150000)) { - printk("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); - return -EINVAL; - } - N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size]; - printk("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n", - __func__, config->step_size, div_tab[config->step_size], N, N); - - buf[0] = (N >> 8) & 0xff; - buf[1] = N & 0xff; - buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1); - - if (frequency < 1450000) - buf[3] = 0x00; - else if (frequency < 2000000) - buf[3] = 0x40; - else if (frequency < 2150000) - buf[3] = 0x80; - - /* Set params */ - if ((err = tda8261_write(state, buf)) < 0) { - printk("%s: I/O Error\n", __func__); - return err; - } - /* sleep for some time */ - printk("%s: Waiting to Phase LOCK\n", __func__); - msleep(20); - /* check status */ - if ((err = tda8261_get_status(fe, &status)) < 0) { - printk("%s: I/O Error\n", __func__); - return err; - } - if (status == 1) { - printk("%s: Tuner Phase locked: status=%d\n", __func__, status); - state->frequency = frequency; /* cache successful state */ - } else { - printk("%s: No Phase lock: status=%d\n", __func__, status); - } - } else { - printk("%s: Unknown parameter (param=%d)\n", __func__, param); - return -EINVAL; - } - - return 0; -} - -static int tda8261_release(struct dvb_frontend *fe) -{ - struct tda8261_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - return 0; -} - -static struct dvb_tuner_ops tda8261_ops = { - - .info = { - .name = "TDA8261", -// .tuner_name = NULL, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_step = 0 - }, - - .set_state = tda8261_set_state, - .get_state = tda8261_get_state, - .get_status = tda8261_get_status, - .release = tda8261_release -}; - -struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, - const struct tda8261_config *config, - struct i2c_adapter *i2c) -{ - struct tda8261_state *state = NULL; - - if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL) - goto exit; - - state->config = config; - state->i2c = i2c; - state->fe = fe; - fe->tuner_priv = state; - fe->ops.tuner_ops = tda8261_ops; - - fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size]; -// fe->ops.tuner_ops.tuner_name = &config->buf; - -// printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n", -// __func__, fe->ops.tuner_ops.tuner_name); - printk("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__); - - return fe; - -exit: - kfree(state); - return NULL; -} - -EXPORT_SYMBOL(tda8261_attach); -MODULE_PARM_DESC(verbose, "Set verbosity level"); - -MODULE_AUTHOR("Manu Abraham"); -MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261_cfg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261_cfg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261_cfg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261_cfg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/* - TDA8261 8PSK/QPSK tuner driver - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - struct tuner_state t_state; - int err = 0; - - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->get_state) { - if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { - printk("%s: Invalid parameter\n", __func__); - return err; - } - *frequency = t_state.frequency; - printk("%s: Frequency=%d\n", __func__, t_state.frequency); - } - return 0; -} - -static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency) -{ - struct dvb_frontend_ops *frontend_ops = NULL; - struct dvb_tuner_ops *tuner_ops = NULL; - struct tuner_state t_state; - int err = 0; - - t_state.frequency = frequency; - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->set_state) { - if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { - printk("%s: Invalid parameter\n", __func__); - return err; - } - } - printk("%s: Frequency=%d\n", __func__, t_state.frequency); - return 0; -} - -static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct dvb_frontend_ops *frontend_ops = &fe->ops; - struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state t_state; - int err = 0; - - if (&fe->ops) - frontend_ops = &fe->ops; - if (&frontend_ops->tuner_ops) - tuner_ops = &frontend_ops->tuner_ops; - if (tuner_ops->get_state) { - if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { - printk("%s: Invalid parameter\n", __func__); - return err; - } - *bandwidth = t_state.bandwidth; - } - printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda8261.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/* - TDA8261 8PSK/QPSK tuner driver - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TDA8261_H -#define __TDA8261_H - -enum tda8261_step { - TDA8261_STEP_2000 = 0, /* 2000 kHz */ - TDA8261_STEP_1000, /* 1000 kHz */ - TDA8261_STEP_500, /* 500 kHz */ - TDA8261_STEP_250, /* 250 kHz */ - TDA8261_STEP_125 /* 125 kHz */ -}; - -struct tda8261_config { -// u8 buf[16]; - u8 addr; - enum tda8261_step step_size; -}; - -#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE)) - -extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, - const struct tda8261_config *config, - struct i2c_adapter *i2c); - -#else - -static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, - const struct tda8261_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); - return NULL; -} - -#endif //CONFIG_DVB_TDA8261 - -#endif// __TDA8261_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda826x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda826x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda826x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda826x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ - /* - Driver for Philips tda8262/tda8263 DVBS Silicon tuners - - (c) 2006 Andrew de Quincey - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#include -#include -#include -#include - -#include "tda826x.h" - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "tda826x: " args); \ - } while (0) - -struct tda826x_priv { - /* i2c details */ - int i2c_address; - struct i2c_adapter *i2c; - u8 has_loopthrough:1; - u32 frequency; -}; - -static int tda826x_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int tda826x_sleep(struct dvb_frontend *fe) -{ - struct tda826x_priv *priv = fe->tuner_priv; - int ret; - u8 buf [] = { 0x00, 0x8d }; - struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 2 }; - - dprintk("%s:\n", __func__); - - if (!priv->has_loopthrough) - buf[1] = 0xad; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) { - dprintk("%s: i2c error\n", __func__); - } - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return (ret == 1) ? 0 : ret; -} - -static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct tda826x_priv *priv = fe->tuner_priv; - int ret; - u32 div; - u32 ksyms; - u32 bandwidth; - u8 buf [11]; - struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 11 }; - - dprintk("%s:\n", __func__); - - div = (params->frequency + (1000-1)) / 1000; - - /* BW = ((1 + RO) * SR/2 + 5) * 1.3 [SR in MSPS, BW in MHz] */ - /* with R0 = 0.35 and some transformations: */ - ksyms = params->u.qpsk.symbol_rate / 1000; - bandwidth = (878 * ksyms + 6500000) / 1000000 + 1; - if (bandwidth < 5) - bandwidth = 5; - else if (bandwidth > 36) - bandwidth = 36; - - buf[0] = 0x00; // subaddress - buf[1] = 0x09; // powerdown RSSI + the magic value 1 - if (!priv->has_loopthrough) - buf[1] |= 0x20; // power down loopthrough if not needed - buf[2] = (1<<5) | 0x0b; // 1Mhz + 0.45 VCO - buf[3] = div >> 7; - buf[4] = div << 1; - buf[5] = ((bandwidth - 5) << 3) | 7; /* baseband cut-off */ - buf[6] = 0xfe; // baseband gain 9 db + no RF attenuation - buf[7] = 0x83; // charge pumps at high, tests off - buf[8] = 0x80; // recommended value 4 for AMPVCO + disable ports. - buf[9] = 0x1a; // normal caltime + recommended values for SELTH + SELVTL - buf[10] = 0xd4; // recommended value 13 for BBIAS + unknown bit set on - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) { - dprintk("%s: i2c error\n", __func__); - } - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - priv->frequency = div * 1000; - - return (ret == 1) ? 0 : ret; -} - -static int tda826x_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda826x_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static struct dvb_tuner_ops tda826x_tuner_ops = { - .info = { - .name = "Philips TDA826X", - .frequency_min = 950000, - .frequency_max = 2175000 - }, - .release = tda826x_release, - .sleep = tda826x_sleep, - .set_params = tda826x_set_params, - .get_frequency = tda826x_get_frequency, -}; - -struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough) -{ - struct tda826x_priv *priv = NULL; - u8 b1 [] = { 0, 0 }; - struct i2c_msg msg[2] = { - { .addr = addr, .flags = 0, .buf = NULL, .len = 0 }, - { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } - }; - int ret; - - dprintk("%s:\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = i2c_transfer (i2c, msg, 2); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (ret != 2) - return NULL; - if (!(b1[1] & 0x80)) - return NULL; - - priv = kzalloc(sizeof(struct tda826x_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c_address = addr; - priv->i2c = i2c; - priv->has_loopthrough = has_loopthrough; - - memcpy(&fe->ops.tuner_ops, &tda826x_tuner_ops, sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - - return fe; -} -EXPORT_SYMBOL(tda826x_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -MODULE_DESCRIPTION("DVB TDA826x driver"); -MODULE_AUTHOR("Andrew de Quincey"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda826x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda826x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda826x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tda826x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ - /* - Driver for Philips tda8262/tda8263 DVBS Silicon tuners - - (c) 2006 Andrew de Quincey - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef __DVB_TDA826X_H__ -#define __DVB_TDA826X_H__ - -#include -#include "dvb_frontend.h" - -/** - * Attach a tda826x tuner to the supplied frontend structure. - * - * @param fe Frontend to attach to. - * @param addr i2c address of the tuner. - * @param i2c i2c adapter to use. - * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector. - * @return FE pointer on success, NULL on failure. - */ -#if defined(CONFIG_DVB_TDA826X) || (defined(CONFIG_DVB_TDA826X_MODULE) && defined(MODULE)) -extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr, - struct i2c_adapter *i2c, - int has_loopthrough); -#else -static inline struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, - int addr, - struct i2c_adapter *i2c, - int has_loopthrough) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_TDA826X - -#endif // __DVB_TDA826X_H__ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tdhd1.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tdhd1.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tdhd1.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tdhd1.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* - * tdhd1.h - ALPS TDHD1-204A tuner support - * - * Copyright (C) 2008 Oliver Endriss - * - * - * 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, or (at your option) any later version. - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * The project's page is at http://www.linuxtv.org - */ - -#ifndef TDHD1_H -#define TDHD1_H - -#include "tda1004x.h" - -static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name); - -static struct tda1004x_config alps_tdhd1_204a_config = { - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = alps_tdhd1_204_request_firmware -}; - -static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct i2c_adapter *i2c = fe->tuner_priv; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - u32 div; - - div = (params->frequency + 36166666) / 166666; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85; - - if (params->frequency >= 174000000 && params->frequency <= 230000000) - data[3] = 0x02; - else if (params->frequency >= 470000000 && params->frequency <= 823000000) - data[3] = 0x0C; - else if (params->frequency > 823000000 && params->frequency <= 862000000) - data[3] = 0x8C; - else - return -EINVAL; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(i2c, &msg, 1) != 1) - return -EIO; - - return 0; -} - -#endif /* TDHD1_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tua6100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tua6100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tua6100.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tua6100.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,205 +0,0 @@ -/** - * Driver for Infineon tua6100 pll. - * - * (c) 2006 Andrew de Quincey - * - * Based on code found in budget-av.c, which has the following: - * Compiled from various sources by Michael Hunold - * - * CI interface support (c) 2004 Olivier Gournet & - * Andrew de Quincey - * - * Copyright (C) 2002 Ralph Metzler - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "tua6100.h" - -struct tua6100_priv { - /* i2c details */ - int i2c_address; - struct i2c_adapter *i2c; - u32 frequency; -}; - -static int tua6100_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int tua6100_sleep(struct dvb_frontend *fe) -{ - struct tua6100_priv *priv = fe->tuner_priv; - int ret; - u8 reg0[] = { 0x00, 0x00 }; - struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) { - printk("%s: i2c error\n", __func__); - } - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return (ret == 1) ? 0 : ret; -} - -static int tua6100_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tua6100_priv *priv = fe->tuner_priv; - u32 div; - u32 prediv; - u8 reg0[] = { 0x00, 0x00 }; - u8 reg1[] = { 0x01, 0x00, 0x00, 0x00 }; - u8 reg2[] = { 0x02, 0x00, 0x00 }; - struct i2c_msg msg0 = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 }; - struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 }; - struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 }; - -#define _R 4 -#define _P 32 -#define _ri 4000000 - - // setup register 0 - if (params->frequency < 2000000) { - reg0[1] = 0x03; - } else { - reg0[1] = 0x07; - } - - // setup register 1 - if (params->frequency < 1630000) { - reg1[1] = 0x2c; - } else { - reg1[1] = 0x0c; - } - if (_P == 64) - reg1[1] |= 0x40; - if (params->frequency >= 1525000) - reg1[1] |= 0x80; - - // register 2 - reg2[1] = (_R >> 8) & 0x03; - reg2[2] = _R; - if (params->frequency < 1455000) { - reg2[1] |= 0x1c; - } else if (params->frequency < 1630000) { - reg2[1] |= 0x0c; - } else { - reg2[1] |= 0x1c; - } - - // The N divisor ratio (note: params->frequency is in kHz, but we need it in Hz) - prediv = (params->frequency * _R) / (_ri / 1000); - div = prediv / _P; - reg1[1] |= (div >> 9) & 0x03; - reg1[2] = div >> 1; - reg1[3] = (div << 7); - priv->frequency = ((div * _P) * (_ri / 1000)) / _R; - - // Finally, calculate and store the value for A - reg1[3] |= (prediv - (div*_P)) & 0x7f; - -#undef _R -#undef _P -#undef _ri - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(priv->i2c, &msg0, 1) != 1) - return -EIO; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(priv->i2c, &msg2, 1) != 1) - return -EIO; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(priv->i2c, &msg1, 1) != 1) - return -EIO; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tua6100_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static struct dvb_tuner_ops tua6100_tuner_ops = { - .info = { - .name = "Infineon TUA6100", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_step = 1000, - }, - .release = tua6100_release, - .sleep = tua6100_sleep, - .set_params = tua6100_set_params, - .get_frequency = tua6100_get_frequency, -}; - -struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c) -{ - struct tua6100_priv *priv = NULL; - u8 b1 [] = { 0x80 }; - u8 b2 [] = { 0x00 }; - struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b1, .len = 1 }, - { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } }; - int ret; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = i2c_transfer (i2c, msg, 2); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - if (ret != 2) - return NULL; - - priv = kzalloc(sizeof(struct tua6100_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c_address = addr; - priv->i2c = i2c; - - memcpy(&fe->ops.tuner_ops, &tua6100_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - return fe; -} -EXPORT_SYMBOL(tua6100_attach); - -MODULE_DESCRIPTION("DVB tua6100 driver"); -MODULE_AUTHOR("Andrew de Quincey"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tua6100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tua6100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tua6100.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/tua6100.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/** - * Driver for Infineon tua6100 PLL. - * - * (c) 2006 Andrew de Quincey - * - * Based on code found in budget-av.c, which has the following: - * Compiled from various sources by Michael Hunold - * - * CI interface support (c) 2004 Olivier Gournet & - * Andrew de Quincey - * - * Copyright (C) 2002 Ralph Metzler - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __DVB_TUA6100_H__ -#define __DVB_TUA6100_H__ - -#include -#include "dvb_frontend.h" - -#if defined(CONFIG_DVB_TUA6100) || (defined(CONFIG_DVB_TUA6100_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_TUA6100 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1820.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1820.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1820.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1820.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,446 +0,0 @@ -/* - VES1820 - Single Chip Cable Channel Receiver driver module - - Copyright (C) 1999 Convergence Integrated Media GmbH - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "ves1820.h" - - - -struct ves1820_state { - struct i2c_adapter* i2c; - /* configuration settings */ - const struct ves1820_config* config; - struct dvb_frontend frontend; - - /* private demodulator data */ - u8 reg0; - u8 pwm; -}; - - -static int verbose; - -static u8 ves1820_inittab[] = { - 0x69, 0x6A, 0x93, 0x1A, 0x12, 0x46, 0x26, 0x1A, - 0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20, - 0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40 -}; - -static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) -{ - u8 buf[] = { 0x00, reg, data }; - struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 }; - int ret; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - printk("ves1820: %s(): writereg error (reg == 0x%02x, " - "val == 0x%02x, ret == %i)\n", __func__, reg, data, ret); - - return (ret != 1) ? -EREMOTEIO : 0; -} - -static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) -{ - u8 b0[] = { 0x00, reg }; - u8 b1[] = { 0 }; - struct i2c_msg msg[] = { - {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2}, - {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} - }; - int ret; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - printk("ves1820: %s(): readreg error (reg == 0x%02x, " - "ret == %i)\n", __func__, reg, ret); - - return b1[0]; -} - -static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion) -{ - reg0 |= state->reg0 & 0x62; - - if (INVERSION_ON == inversion) { - if (!state->config->invert) reg0 |= 0x20; - else reg0 &= ~0x20; - } else if (INVERSION_OFF == inversion) { - if (!state->config->invert) reg0 &= ~0x20; - else reg0 |= 0x20; - } - - ves1820_writereg(state, 0x00, reg0 & 0xfe); - ves1820_writereg(state, 0x00, reg0 | 0x01); - - state->reg0 = reg0; - - return 0; -} - -static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) -{ - s32 BDR; - s32 BDRI; - s16 SFIL = 0; - u16 NDEC = 0; - u32 ratio; - u32 fin; - u32 tmp; - u64 fptmp; - u64 fpxin; - - if (symbolrate > state->config->xin / 2) - symbolrate = state->config->xin / 2; - - if (symbolrate < 500000) - symbolrate = 500000; - - if (symbolrate < state->config->xin / 16) - NDEC = 1; - if (symbolrate < state->config->xin / 32) - NDEC = 2; - if (symbolrate < state->config->xin / 64) - NDEC = 3; - - /* yeuch! */ - fpxin = state->config->xin * 10; - fptmp = fpxin; do_div(fptmp, 123); - if (symbolrate < fptmp) - SFIL = 1; - fptmp = fpxin; do_div(fptmp, 160); - if (symbolrate < fptmp) - SFIL = 0; - fptmp = fpxin; do_div(fptmp, 246); - if (symbolrate < fptmp) - SFIL = 1; - fptmp = fpxin; do_div(fptmp, 320); - if (symbolrate < fptmp) - SFIL = 0; - fptmp = fpxin; do_div(fptmp, 492); - if (symbolrate < fptmp) - SFIL = 1; - fptmp = fpxin; do_div(fptmp, 640); - if (symbolrate < fptmp) - SFIL = 0; - fptmp = fpxin; do_div(fptmp, 984); - if (symbolrate < fptmp) - SFIL = 1; - - fin = state->config->xin >> 4; - symbolrate <<= NDEC; - ratio = (symbolrate << 4) / fin; - tmp = ((symbolrate << 4) % fin) << 8; - ratio = (ratio << 8) + tmp / fin; - tmp = (tmp % fin) << 8; - ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin); - - BDR = ratio; - BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2; - - if (BDRI > 0xFF) - BDRI = 0xFF; - - SFIL = (SFIL << 4) | ves1820_inittab[0x0E]; - - NDEC = (NDEC << 6) | ves1820_inittab[0x03]; - - ves1820_writereg(state, 0x03, NDEC); - ves1820_writereg(state, 0x0a, BDR & 0xff); - ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff); - ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f); - - ves1820_writereg(state, 0x0d, BDRI); - ves1820_writereg(state, 0x0e, SFIL); - - return 0; -} - -static int ves1820_init(struct dvb_frontend* fe) -{ - struct ves1820_state* state = fe->demodulator_priv; - int i; - - ves1820_writereg(state, 0, 0); - - for (i = 0; i < sizeof(ves1820_inittab); i++) - ves1820_writereg(state, i, ves1820_inittab[i]); - if (state->config->selagc) - ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08); - - ves1820_writereg(state, 0x34, state->pwm); - - return 0; -} - -static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct ves1820_state* state = fe->demodulator_priv; - static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 }; - static const u8 reg0x01[] = { 140, 140, 106, 100, 92 }; - static const u8 reg0x05[] = { 135, 100, 70, 54, 38 }; - static const u8 reg0x08[] = { 162, 116, 67, 52, 35 }; - static const u8 reg0x09[] = { 145, 150, 106, 126, 107 }; - int real_qam = p->u.qam.modulation - QAM_16; - - if (real_qam < 0 || real_qam > 4) - return -EINVAL; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - ves1820_set_symbolrate(state, p->u.qam.symbol_rate); - ves1820_writereg(state, 0x34, state->pwm); - - ves1820_writereg(state, 0x01, reg0x01[real_qam]); - ves1820_writereg(state, 0x05, reg0x05[real_qam]); - ves1820_writereg(state, 0x08, reg0x08[real_qam]); - ves1820_writereg(state, 0x09, reg0x09[real_qam]); - - ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion); - ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0)); - return 0; -} - -static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct ves1820_state* state = fe->demodulator_priv; - int sync; - - *status = 0; - sync = ves1820_readreg(state, 0x11); - - if (sync & 1) - *status |= FE_HAS_SIGNAL; - - if (sync & 2) - *status |= FE_HAS_CARRIER; - - if (sync & 2) /* XXX FIXME! */ - *status |= FE_HAS_VITERBI; - - if (sync & 4) - *status |= FE_HAS_SYNC; - - if (sync & 8) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct ves1820_state* state = fe->demodulator_priv; - - u32 _ber = ves1820_readreg(state, 0x14) | - (ves1820_readreg(state, 0x15) << 8) | - ((ves1820_readreg(state, 0x16) & 0x0f) << 16); - *ber = 10 * _ber; - - return 0; -} - -static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct ves1820_state* state = fe->demodulator_priv; - - u8 gain = ves1820_readreg(state, 0x17); - *strength = (gain << 8) | gain; - - return 0; -} - -static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct ves1820_state* state = fe->demodulator_priv; - - u8 quality = ~ves1820_readreg(state, 0x18); - *snr = (quality << 8) | quality; - - return 0; -} - -static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct ves1820_state* state = fe->demodulator_priv; - - *ucblocks = ves1820_readreg(state, 0x13) & 0x7f; - if (*ucblocks == 0x7f) - *ucblocks = 0xffffffff; - - /* reset uncorrected block counter */ - ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf); - ves1820_writereg(state, 0x10, ves1820_inittab[0x10]); - - return 0; -} - -static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct ves1820_state* state = fe->demodulator_priv; - int sync; - s8 afc = 0; - - sync = ves1820_readreg(state, 0x11); - afc = ves1820_readreg(state, 0x19); - if (verbose) { - /* AFC only valid when carrier has been recovered */ - printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" : - "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10); - } - - if (!state->config->invert) { - p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF; - } else { - p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF; - } - - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; - - p->u.qam.fec_inner = FEC_NONE; - - p->frequency = ((p->frequency + 31250) / 62500) * 62500; - if (sync & 2) - p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10; - - return 0; -} - -static int ves1820_sleep(struct dvb_frontend* fe) -{ - struct ves1820_state* state = fe->demodulator_priv; - - ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */ - ves1820_writereg(state, 0x00, 0x80); /* standby */ - - return 0; -} - -static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) -{ - - fesettings->min_delay_ms = 200; - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static void ves1820_release(struct dvb_frontend* fe) -{ - struct ves1820_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops ves1820_ops; - -struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, - struct i2c_adapter* i2c, - u8 pwm) -{ - struct ves1820_state* state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->reg0 = ves1820_inittab[0]; - state->config = config; - state->i2c = i2c; - state->pwm = pwm; - - /* check if the demod is there */ - if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70) - goto error; - - if (verbose) - printk("ves1820: pwm=0x%02x\n", state->pwm); - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */ - state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */ - state->frontend.demodulator_priv = state; - - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops ves1820_ops = { - - .info = { - .name = "VLSI VES1820 DVB-C", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 47000000, - .frequency_max = 862000000, - .caps = FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO - }, - - .release = ves1820_release, - - .init = ves1820_init, - .sleep = ves1820_sleep, - - .set_frontend = ves1820_set_parameters, - .get_frontend = ves1820_get_frontend, - .get_tune_settings = ves1820_get_tune_settings, - - .read_status = ves1820_read_status, - .read_ber = ves1820_read_ber, - .read_signal_strength = ves1820_read_signal_strength, - .read_snr = ves1820_read_snr, - .read_ucblocks = ves1820_read_ucblocks, -}; - -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting"); - -MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver"); -MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(ves1820_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1820.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1820.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1820.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1820.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - VES1820 - Single Chip Cable Channel Receiver driver module - - Copyright (C) 1999 Convergence Integrated Media GmbH - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef VES1820_H -#define VES1820_H - -#include - -#define VES1820_SELAGC_PWM 0 -#define VES1820_SELAGC_SIGNAMPERR 1 - -struct ves1820_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* value of XIN to use */ - u32 xin; - - /* does inversion need inverted? */ - u8 invert:1; - - /* SELAGC control */ - u8 selagc:1; -}; - -#if defined(CONFIG_DVB_VES1820) || (defined(CONFIG_DVB_VES1820_MODULE) && defined(MODULE)) -extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, - struct i2c_adapter* i2c, u8 pwm); -#else -static inline struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, - struct i2c_adapter* i2c, u8 pwm) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_VES1820 - -#endif // VES1820_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1x93.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1x93.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1x93.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1x93.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,550 +0,0 @@ -/* - Driver for VES1893 and VES1993 QPSK Demodulators - - Copyright (C) 1999 Convergence Integrated Media GmbH - Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de> - Copyright (C) 2002 Dennis Noermann - Copyright (C) 2002-2003 Andreas Oberritter - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "ves1x93.h" - - -struct ves1x93_state { - struct i2c_adapter* i2c; - /* configuration settings */ - const struct ves1x93_config* config; - struct dvb_frontend frontend; - - /* previous uncorrected block counter */ - fe_spectral_inversion_t inversion; - u8 *init_1x93_tab; - u8 *init_1x93_wtab; - u8 tab_size; - u8 demod_type; -}; - -static int debug; -#define dprintk if (debug) printk - -#define DEMOD_VES1893 0 -#define DEMOD_VES1993 1 - -static u8 init_1893_tab [] = { - 0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4, - 0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7f, 0x00, - 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x21, 0xb0, 0x14, 0x00, 0xdc, 0x00, - 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x55, 0x00, 0x00, 0x7f, 0x00 -}; - -static u8 init_1993_tab [] = { - 0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c, - 0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00, - 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x40, 0x21, 0xb0, 0x00, 0x00, 0x00, 0x10, - 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x0e, 0x80, 0x00 -}; - -static u8 init_1893_wtab[] = -{ - 1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0, - 0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1, - 1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0, - 1,1,1,0,1,1 -}; - -static u8 init_1993_wtab[] = -{ - 1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0, - 0,1,0,0,0,0,0,0, 1,1,1,1,0,0,0,1, - 1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0, - 1,1,1,0,1,1,1,1, 1,1,1,1,1 -}; - -static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data) -{ - u8 buf [] = { 0x00, reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; - int err; - - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { - dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data); - return -EREMOTEIO; - } - - return 0; -} - -static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg) -{ - int ret; - u8 b0 [] = { 0x00, reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - ret = i2c_transfer (state->i2c, msg, 2); - - if (ret != 2) return ret; - - return b1[0]; -} - -static int ves1x93_clr_bit (struct ves1x93_state* state) -{ - msleep(10); - ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe); - ves1x93_writereg (state, 0, state->init_1x93_tab[0]); - msleep(50); - return 0; -} - -static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion) -{ - u8 val; - - /* - * inversion on/off are interchanged because i and q seem to - * be swapped on the hardware - */ - - switch (inversion) { - case INVERSION_OFF: - val = 0xc0; - break; - case INVERSION_ON: - val = 0x80; - break; - case INVERSION_AUTO: - val = 0x00; - break; - default: - return -EINVAL; - } - - return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val); -} - -static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec) -{ - if (fec == FEC_AUTO) - return ves1x93_writereg (state, 0x0d, 0x08); - else if (fec < FEC_1_2 || fec > FEC_8_9) - return -EINVAL; - else - return ves1x93_writereg (state, 0x0d, fec - FEC_1_2); -} - -static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state) -{ - return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7); -} - -static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate) -{ - u32 BDR; - u32 ratio; - u8 ADCONF, FCONF, FNR, AGCR; - u32 BDRI; - u32 tmp; - u32 FIN; - - dprintk("%s: srate == %d\n", __func__, (unsigned int) srate); - - if (srate > state->config->xin/2) - srate = state->config->xin/2; - - if (srate < 500000) - srate = 500000; - -#define MUL (1UL<<26) - - FIN = (state->config->xin + 6000) >> 4; - - tmp = srate << 6; - ratio = tmp / FIN; - - tmp = (tmp % FIN) << 8; - ratio = (ratio << 8) + tmp / FIN; - - tmp = (tmp % FIN) << 8; - ratio = (ratio << 8) + tmp / FIN; - - FNR = 0xff; - - if (ratio < MUL/3) FNR = 0; - if (ratio < (MUL*11)/50) FNR = 1; - if (ratio < MUL/6) FNR = 2; - if (ratio < MUL/9) FNR = 3; - if (ratio < MUL/12) FNR = 4; - if (ratio < (MUL*11)/200) FNR = 5; - if (ratio < MUL/24) FNR = 6; - if (ratio < (MUL*27)/1000) FNR = 7; - if (ratio < MUL/48) FNR = 8; - if (ratio < (MUL*137)/10000) FNR = 9; - - if (FNR == 0xff) { - ADCONF = 0x89; - FCONF = 0x80; - FNR = 0; - } else { - ADCONF = 0x81; - FCONF = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5); - /*FCONF = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/ - } - - BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1; - BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1; - - dprintk("FNR= %d\n", FNR); - dprintk("ratio= %08x\n", (unsigned int) ratio); - dprintk("BDR= %08x\n", (unsigned int) BDR); - dprintk("BDRI= %02x\n", (unsigned int) BDRI); - - if (BDRI > 0xff) - BDRI = 0xff; - - ves1x93_writereg (state, 0x06, 0xff & BDR); - ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8)); - ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16)); - - ves1x93_writereg (state, 0x09, BDRI); - ves1x93_writereg (state, 0x20, ADCONF); - ves1x93_writereg (state, 0x21, FCONF); - - AGCR = state->init_1x93_tab[0x05]; - if (state->config->invert_pwm) - AGCR |= 0x20; - - if (srate < 6000000) - AGCR |= 0x80; - else - AGCR &= ~0x80; - - ves1x93_writereg (state, 0x05, AGCR); - - /* ves1993 hates this, will lose lock */ - if (state->demod_type != DEMOD_VES1993) - ves1x93_clr_bit (state); - - return 0; -} - -static int ves1x93_init (struct dvb_frontend* fe) -{ - struct ves1x93_state* state = fe->demodulator_priv; - int i; - int val; - - dprintk("%s: init chip\n", __func__); - - for (i = 0; i < state->tab_size; i++) { - if (state->init_1x93_wtab[i]) { - val = state->init_1x93_tab[i]; - - if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */ - ves1x93_writereg (state, i, val); - } - } - - return 0; -} - -static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct ves1x93_state* state = fe->demodulator_priv; - - switch (voltage) { - case SEC_VOLTAGE_13: - return ves1x93_writereg (state, 0x1f, 0x20); - case SEC_VOLTAGE_18: - return ves1x93_writereg (state, 0x1f, 0x30); - case SEC_VOLTAGE_OFF: - return ves1x93_writereg (state, 0x1f, 0x00); - default: - return -EINVAL; - } -} - -static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct ves1x93_state* state = fe->demodulator_priv; - - u8 sync = ves1x93_readreg (state, 0x0e); - - /* - * The ves1893 sometimes returns sync values that make no sense, - * because, e.g., the SIGNAL bit is 0, while some of the higher - * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?). - * Tests showed that the VITERBI and SYNC bits are returned - * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong. - * If such a case occurs, we read the value again, until we get a - * valid value. - */ - int maxtry = 10; /* just for safety - let's not get stuck here */ - while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) { - msleep(10); - sync = ves1x93_readreg (state, 0x0e); - } - - *status = 0; - - if (sync & 1) - *status |= FE_HAS_SIGNAL; - - if (sync & 2) - *status |= FE_HAS_CARRIER; - - if (sync & 4) - *status |= FE_HAS_VITERBI; - - if (sync & 8) - *status |= FE_HAS_SYNC; - - if ((sync & 0x1f) == 0x1f) - *status |= FE_HAS_LOCK; - - return 0; -} - -static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber) -{ - struct ves1x93_state* state = fe->demodulator_priv; - - *ber = ves1x93_readreg (state, 0x15); - *ber |= (ves1x93_readreg (state, 0x16) << 8); - *ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16); - *ber *= 10; - - return 0; -} - -static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - struct ves1x93_state* state = fe->demodulator_priv; - - u8 signal = ~ves1x93_readreg (state, 0x0b); - *strength = (signal << 8) | signal; - - return 0; -} - -static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr) -{ - struct ves1x93_state* state = fe->demodulator_priv; - - u8 _snr = ~ves1x93_readreg (state, 0x1c); - *snr = (_snr << 8) | _snr; - - return 0; -} - -static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct ves1x93_state* state = fe->demodulator_priv; - - *ucblocks = ves1x93_readreg (state, 0x18) & 0x7f; - - if (*ucblocks == 0x7f) - *ucblocks = 0xffffffff; /* counter overflow... */ - - ves1x93_writereg (state, 0x18, 0x00); /* reset the counter */ - ves1x93_writereg (state, 0x18, 0x80); /* dto. */ - - return 0; -} - -static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct ves1x93_state* state = fe->demodulator_priv; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - ves1x93_set_inversion (state, p->inversion); - ves1x93_set_fec (state, p->u.qpsk.fec_inner); - ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate); - state->inversion = p->inversion; - - return 0; -} - -static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct ves1x93_state* state = fe->demodulator_priv; - int afc; - - afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2; - afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16; - - p->frequency -= afc; - - /* - * inversion indicator is only valid - * if auto inversion was used - */ - if (state->inversion == INVERSION_AUTO) - p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ? - INVERSION_OFF : INVERSION_ON; - p->u.qpsk.fec_inner = ves1x93_get_fec (state); - /* XXX FIXME: timing offset !! */ - - return 0; -} - -static int ves1x93_sleep(struct dvb_frontend* fe) -{ - struct ves1x93_state* state = fe->demodulator_priv; - - return ves1x93_writereg (state, 0x00, 0x08); -} - -static void ves1x93_release(struct dvb_frontend* fe) -{ - struct ves1x93_state* state = fe->demodulator_priv; - kfree(state); -} - -static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct ves1x93_state* state = fe->demodulator_priv; - - if (enable) { - return ves1x93_writereg(state, 0x00, 0x11); - } else { - return ves1x93_writereg(state, 0x00, 0x01); - } -} - -static struct dvb_frontend_ops ves1x93_ops; - -struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, - struct i2c_adapter* i2c) -{ - struct ves1x93_state* state = NULL; - u8 identity; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct ves1x93_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->inversion = INVERSION_OFF; - - /* check if the demod is there + identify it */ - identity = ves1x93_readreg(state, 0x1e); - switch (identity) { - case 0xdc: /* VES1893A rev1 */ - printk("ves1x93: Detected ves1893a rev1\n"); - state->demod_type = DEMOD_VES1893; - state->init_1x93_tab = init_1893_tab; - state->init_1x93_wtab = init_1893_wtab; - state->tab_size = sizeof(init_1893_tab); - break; - - case 0xdd: /* VES1893A rev2 */ - printk("ves1x93: Detected ves1893a rev2\n"); - state->demod_type = DEMOD_VES1893; - state->init_1x93_tab = init_1893_tab; - state->init_1x93_wtab = init_1893_wtab; - state->tab_size = sizeof(init_1893_tab); - break; - - case 0xde: /* VES1993 */ - printk("ves1x93: Detected ves1993\n"); - state->demod_type = DEMOD_VES1993; - state->init_1x93_tab = init_1993_tab; - state->init_1x93_wtab = init_1993_wtab; - state->tab_size = sizeof(init_1993_tab); - break; - - default: - goto error; - } - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops ves1x93_ops = { - - .info = { - .name = "VLSI VES1x93 DVB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - /* .symbol_rate_tolerance = ???,*/ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK - }, - - .release = ves1x93_release, - - .init = ves1x93_init, - .sleep = ves1x93_sleep, - .i2c_gate_ctrl = ves1x93_i2c_gate_ctrl, - - .set_frontend = ves1x93_set_frontend, - .get_frontend = ves1x93_get_frontend, - - .read_status = ves1x93_read_status, - .read_ber = ves1x93_read_ber, - .read_signal_strength = ves1x93_read_signal_strength, - .read_snr = ves1x93_read_snr, - .read_ucblocks = ves1x93_read_ucblocks, - - .set_voltage = ves1x93_set_voltage, -}; - -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver"); -MODULE_AUTHOR("Ralph Metzler"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(ves1x93_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1x93.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1x93.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1x93.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/ves1x93.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/* - Driver for VES1893 and VES1993 QPSK Demodulators - - Copyright (C) 1999 Convergence Integrated Media GmbH - Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de> - Copyright (C) 2002 Dennis Noermann - Copyright (C) 2002-2003 Andreas Oberritter - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef VES1X93_H -#define VES1X93_H - -#include - -struct ves1x93_config -{ - /* the demodulator's i2c address */ - u8 demod_address; - - /* value of XIN to use */ - u32 xin; - - /* should PWM be inverted? */ - u8 invert_pwm:1; -}; - -#if defined(CONFIG_DVB_VES1X93) || (defined(CONFIG_DVB_VES1X93_MODULE) && defined(MODULE)) -extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, - struct i2c_adapter* i2c); -#else -static inline struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, - struct i2c_adapter* i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif // CONFIG_DVB_VES1X93 - -#endif // VES1X93_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/z0194a.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/z0194a.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/z0194a.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/z0194a.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* z0194a.h Sharp z0194a tuner support -* -* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) -* -* 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, version 2. -* -* see Documentation/dvb/README.dvb-usb for more information -*/ - -#ifndef Z0194A -#define Z0194A - -static int sharp_z0194a_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { - aclk = 0xb7; bclk = 0x47; } - else if (srate < 3000000) { - aclk = 0xb7; bclk = 0x4b; } - else if (srate < 7000000) { - aclk = 0xb7; bclk = 0x4f; } - else if (srate < 14000000) { - aclk = 0xb7; bclk = 0x53; } - else if (srate < 30000000) { - aclk = 0xb6; bclk = 0x53; } - else if (srate < 45000000) { - aclk = 0xb4; bclk = 0x51; } - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - - return 0; -} - -static u8 sharp_z0194a_inittab[] = { - 0x01, 0x15, - 0x02, 0x00, - 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - 0x10, 0x3f, /* AGC2 0x3d */ - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, /* lock detector threshold */ - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, /* out imp: normal out type: parallel FEC mode:0 */ - 0x29, 0x1e, /* 1/2 threshold */ - 0x2a, 0x14, /* 2/3 threshold */ - 0x2b, 0x0f, /* 3/4 threshold */ - 0x2c, 0x09, /* 5/6 threshold */ - 0x2d, 0x05, /* 7/8 threshold */ - 0x2e, 0x01, - 0x31, 0x1f, /* test all FECs */ - 0x32, 0x19, /* viterbi and synchro search */ - 0x33, 0xfc, /* rs control */ - 0x34, 0x93, /* error control */ - 0x0f, 0x52, - 0xff, 0xff -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10036.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10036.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10036.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10036.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,520 +0,0 @@ -/** - * Driver for Zarlink zl10036 DVB-S silicon tuner - * - * Copyright (C) 2006 Tino Reichardt - * Copyright (C) 2007-2009 Matthias Schwarzott - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2, as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ** - * The data sheet for this tuner can be found at: - * http://www.mcmilk.de/projects/dvb-card/datasheets/ZL10036.pdf - * - * This one is working: (at my Avermedia DVB-S Pro) - * - zl10036 (40pin, FTA) - * - * A driver for zl10038 should be very similar. - */ - -#include -#include -#include -#include - -#include "zl10036.h" - -static int zl10036_debug; -#define dprintk(level, args...) \ - do { if (zl10036_debug & level) printk(KERN_DEBUG "zl10036: " args); \ - } while (0) - -#define deb_info(args...) dprintk(0x01, args) -#define deb_i2c(args...) dprintk(0x02, args) - -struct zl10036_state { - struct i2c_adapter *i2c; - const struct zl10036_config *config; - u32 frequency; - u8 br, bf; -}; - - -/* This driver assumes the tuner is driven by a 10.111MHz Cristal */ -#define _XTAL 10111 - -/* Some of the possible dividers: - * 64, (write 0x05 to reg), freq step size 158kHz - * 10, (write 0x0a to reg), freq step size 1.011kHz (used here) - * 5, (write 0x09 to reg), freq step size 2.022kHz - */ - -#define _RDIV 10 -#define _RDIV_REG 0x0a -#define _FR (_XTAL/_RDIV) - -#define STATUS_POR 0x80 /* Power on Reset */ -#define STATUS_FL 0x40 /* Frequency & Phase Lock */ - -/* read/write for zl10036 and zl10038 */ - -static int zl10036_read_status_reg(struct zl10036_state *state) -{ - u8 status; - struct i2c_msg msg[1] = { - { .addr = state->config->tuner_address, .flags = I2C_M_RD, - .buf = &status, .len = sizeof(status) }, - }; - - if (i2c_transfer(state->i2c, msg, 1) != 1) { - printk(KERN_ERR "%s: i2c read failed at addr=%02x\n", - __func__, state->config->tuner_address); - return -EIO; - } - - deb_i2c("R(status): %02x [FL=%d]\n", status, - (status & STATUS_FL) ? 1 : 0); - if (status & STATUS_POR) - deb_info("%s: Power-On-Reset bit enabled - " - "need to initialize the tuner\n", __func__); - - return status; -} - -static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count) -{ - struct i2c_msg msg[1] = { - { .addr = state->config->tuner_address, .flags = 0, - .buf = buf, .len = count }, - }; - u8 reg = 0; - int ret; - - if (zl10036_debug & 0x02) { - /* every 8bit-value satisifes this! - * so only check for debug log */ - if ((buf[0] & 0x80) == 0x00) - reg = 2; - else if ((buf[0] & 0xc0) == 0x80) - reg = 4; - else if ((buf[0] & 0xf0) == 0xc0) - reg = 6; - else if ((buf[0] & 0xf0) == 0xd0) - reg = 8; - else if ((buf[0] & 0xf0) == 0xe0) - reg = 10; - else if ((buf[0] & 0xf0) == 0xf0) - reg = 12; - - deb_i2c("W(%d):", reg); - { - int i; - for (i = 0; i < count; i++) - printk(KERN_CONT " %02x", buf[i]); - printk(KERN_CONT "\n"); - } - } - - ret = i2c_transfer(state->i2c, msg, 1); - if (ret != 1) { - printk(KERN_ERR "%s: i2c error, ret=%d\n", __func__, ret); - return -EIO; - } - - return 0; -} - -static int zl10036_release(struct dvb_frontend *fe) -{ - struct zl10036_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - - return 0; -} - -static int zl10036_sleep(struct dvb_frontend *fe) -{ - struct zl10036_state *state = fe->tuner_priv; - u8 buf[] = { 0xf0, 0x80 }; /* regs 12/13 */ - int ret; - - deb_info("%s\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = zl10036_write(state, buf, sizeof(buf)); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return ret; -} - -/** - * register map of the ZL10036/ZL10038 - * - * reg[default] content - * 2[0x00]: 0 | N14 | N13 | N12 | N11 | N10 | N9 | N8 - * 3[0x00]: N7 | N6 | N5 | N4 | N3 | N2 | N1 | N0 - * 4[0x80]: 1 | 0 | RFG | BA1 | BA0 | BG1 | BG0 | LEN - * 5[0x00]: P0 | C1 | C0 | R4 | R3 | R2 | R1 | R0 - * 6[0xc0]: 1 | 1 | 0 | 0 | RSD | 0 | 0 | 0 - * 7[0x20]: P1 | BF6 | BF5 | BF4 | BF3 | BF2 | BF1 | 0 - * 8[0xdb]: 1 | 1 | 0 | 1 | 0 | CC | 1 | 1 - * 9[0x30]: VSD | V2 | V1 | V0 | S3 | S2 | S1 | S0 - * 10[0xe1]: 1 | 1 | 1 | 0 | 0 | LS2 | LS1 | LS0 - * 11[0xf5]: WS | WH2 | WH1 | WH0 | WL2 | WL1 | WL0 | WRE - * 12[0xf0]: 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 - * 13[0x28]: PD | BR4 | BR3 | BR2 | BR1 | BR0 | CLR | TL - */ - -static int zl10036_set_frequency(struct zl10036_state *state, u32 frequency) -{ - u8 buf[2]; - u32 div, foffset; - - div = (frequency + _FR/2) / _FR; - state->frequency = div * _FR; - - foffset = frequency - state->frequency; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = (div >> 0) & 0xff; - - deb_info("%s: ftodo=%u fpriv=%u ferr=%d div=%u\n", __func__, - frequency, state->frequency, foffset, div); - - return zl10036_write(state, buf, sizeof(buf)); -} - -static int zl10036_set_bandwidth(struct zl10036_state *state, u32 fbw) -{ - /* fbw is measured in kHz */ - u8 br, bf; - int ret; - u8 buf_bf[] = { - 0xc0, 0x00, /* 6/7: rsd=0 bf=0 */ - }; - u8 buf_br[] = { - 0xf0, 0x00, /* 12/13: br=0xa clr=0 tl=0*/ - }; - u8 zl10036_rsd_off[] = { 0xc8 }; /* set RSD=1 */ - - /* ensure correct values */ - if (fbw > 35000) - fbw = 35000; - if (fbw < 8000) - fbw = 8000; - -#define _BR_MAXIMUM (_XTAL/575) /* _XTAL / 575kHz = 17 */ - - /* <= 28,82 MHz */ - if (fbw <= 28820) { - br = _BR_MAXIMUM; - } else { - /** - * f(bw)=34,6MHz f(xtal)=10.111MHz - * br = (10111/34600) * 63 * 1/K = 14; - */ - br = ((_XTAL * 21 * 1000) / (fbw * 419)); - } - - /* ensure correct values */ - if (br < 4) - br = 4; - if (br > _BR_MAXIMUM) - br = _BR_MAXIMUM; - - /* - * k = 1.257 - * bf = fbw/_XTAL * br * k - 1 */ - - bf = (fbw * br * 1257) / (_XTAL * 1000) - 1; - - /* ensure correct values */ - if (bf > 62) - bf = 62; - - buf_bf[1] = (bf << 1) & 0x7e; - buf_br[1] = (br << 2) & 0x7c; - deb_info("%s: BW=%d br=%u bf=%u\n", __func__, fbw, br, bf); - - if (br != state->br) { - ret = zl10036_write(state, buf_br, sizeof(buf_br)); - if (ret < 0) - return ret; - } - - if (bf != state->bf) { - ret = zl10036_write(state, buf_bf, sizeof(buf_bf)); - if (ret < 0) - return ret; - - /* time = br/(32* fxtal) */ - /* minimal sleep time to be calculated - * maximum br is 63 -> max time = 2 /10 MHz = 2e-7 */ - msleep(1); - - ret = zl10036_write(state, zl10036_rsd_off, - sizeof(zl10036_rsd_off)); - if (ret < 0) - return ret; - } - - state->br = br; - state->bf = bf; - - return 0; -} - -static int zl10036_set_gain_params(struct zl10036_state *state, - int c) -{ - u8 buf[2]; - u8 rfg, ba, bg; - - /* default values */ - rfg = 0; /* enable when using an lna */ - ba = 1; - bg = 1; - - /* reg 4 */ - buf[0] = 0x80 | ((rfg << 5) & 0x20) - | ((ba << 3) & 0x18) | ((bg << 1) & 0x06); - - if (!state->config->rf_loop_enable) - buf[0] |= 0x01; - - /* P0=0 */ - buf[1] = _RDIV_REG | ((c << 5) & 0x60); - - deb_info("%s: c=%u rfg=%u ba=%u bg=%u\n", __func__, c, rfg, ba, bg); - return zl10036_write(state, buf, sizeof(buf)); -} - -static int zl10036_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct zl10036_state *state = fe->tuner_priv; - int ret = 0; - u32 frequency = params->frequency; - u32 fbw; - int i; - u8 c; - - /* ensure correct values - * maybe redundant as core already checks this */ - if ((frequency < fe->ops.info.frequency_min) - || (frequency > fe->ops.info.frequency_max)) - return -EINVAL; - - /** - * alpha = 1.35 for dvb-s - * fBW = (alpha*symbolrate)/(2*0.8) - * 1.35 / (2*0.8) = 27 / 32 - */ - fbw = (27 * params->u.qpsk.symbol_rate) / 32; - - /* scale to kHz */ - fbw /= 1000; - - /* Add safe margin of 3MHz */ - fbw += 3000; - - /* setting the charge pump - guessed values */ - if (frequency < 950000) - return -EINVAL; - else if (frequency < 1250000) - c = 0; - else if (frequency < 1750000) - c = 1; - else if (frequency < 2175000) - c = 2; - else - return -EINVAL; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = zl10036_set_gain_params(state, c); - if (ret < 0) - goto error; - - ret = zl10036_set_frequency(state, params->frequency); - if (ret < 0) - goto error; - - ret = zl10036_set_bandwidth(state, fbw); - if (ret < 0) - goto error; - - /* wait for tuner lock - no idea if this is really needed */ - for (i = 0; i < 20; i++) { - ret = zl10036_read_status_reg(state); - if (ret < 0) - goto error; - - /* check Frequency & Phase Lock Bit */ - if (ret & STATUS_FL) - break; - - msleep(10); - } - -error: - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return ret; -} - -static int zl10036_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct zl10036_state *state = fe->tuner_priv; - - *frequency = state->frequency; - - return 0; -} - -static int zl10036_init_regs(struct zl10036_state *state) -{ - int ret; - int i; - - /* could also be one block from reg 2 to 13 and additional 10/11 */ - u8 zl10036_init_tab[][2] = { - { 0x04, 0x00 }, /* 2/3: div=0x400 - arbitrary value */ - { 0x8b, _RDIV_REG }, /* 4/5: rfg=0 ba=1 bg=1 len=? */ - /* p0=0 c=0 r=_RDIV_REG */ - { 0xc0, 0x20 }, /* 6/7: rsd=0 bf=0x10 */ - { 0xd3, 0x40 }, /* 8/9: from datasheet */ - { 0xe3, 0x5b }, /* 10/11: lock window level */ - { 0xf0, 0x28 }, /* 12/13: br=0xa clr=0 tl=0*/ - { 0xe3, 0xf9 }, /* 10/11: unlock window level */ - }; - - /* invalid values to trigger writing */ - state->br = 0xff; - state->bf = 0xff; - - if (!state->config->rf_loop_enable) - zl10036_init_tab[1][0] |= 0x01; - - deb_info("%s\n", __func__); - - for (i = 0; i < ARRAY_SIZE(zl10036_init_tab); i++) { - ret = zl10036_write(state, zl10036_init_tab[i], 2); - if (ret < 0) - return ret; - } - - return 0; -} - -static int zl10036_init(struct dvb_frontend *fe) -{ - struct zl10036_state *state = fe->tuner_priv; - int ret = 0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = zl10036_read_status_reg(state); - if (ret < 0) - return ret; - - /* Only init if Power-on-Reset bit is set? */ - ret = zl10036_init_regs(state); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - return ret; -} - -static struct dvb_tuner_ops zl10036_tuner_ops = { - .info = { - .name = "Zarlink ZL10036", - .frequency_min = 950000, - .frequency_max = 2175000 - }, - .init = zl10036_init, - .release = zl10036_release, - .sleep = zl10036_sleep, - .set_params = zl10036_set_params, - .get_frequency = zl10036_get_frequency, -}; - -struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, - const struct zl10036_config *config, - struct i2c_adapter *i2c) -{ - struct zl10036_state *state; - int ret; - - if (!config) { - printk(KERN_ERR "%s: no config specified", __func__); - return NULL; - } - - state = kzalloc(sizeof(struct zl10036_state), GFP_KERNEL); - if (!state) - return NULL; - - state->config = config; - state->i2c = i2c; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ - - ret = zl10036_read_status_reg(state); - if (ret < 0) { - printk(KERN_ERR "%s: No zl10036 found\n", __func__); - goto error; - } - - ret = zl10036_init_regs(state); - if (ret < 0) { - printk(KERN_ERR "%s: tuner initialization failed\n", - __func__); - goto error; - } - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - - fe->tuner_priv = state; - - memcpy(&fe->ops.tuner_ops, &zl10036_tuner_ops, - sizeof(struct dvb_tuner_ops)); - printk(KERN_INFO "%s: tuner initialization (%s addr=0x%02x) ok\n", - __func__, fe->ops.tuner_ops.info.name, config->tuner_address); - - return fe; - -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(zl10036_attach); - -module_param_named(debug, zl10036_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("DVB ZL10036 driver"); -MODULE_AUTHOR("Tino Reichardt"); -MODULE_AUTHOR("Matthias Schwarzott"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10036.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10036.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10036.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10036.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/** - * Driver for Zarlink ZL10036 DVB-S silicon tuner - * - * Copyright (C) 2006 Tino Reichardt - * Copyright (C) 2007-2009 Matthias Schwarzott - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2, as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef DVB_ZL10036_H -#define DVB_ZL10036_H - -#include -#include "dvb_frontend.h" - -/** - * Attach a zl10036 tuner to the supplied frontend structure. - * - * @param fe Frontend to attach to. - * @param config zl10036_config structure - * @return FE pointer on success, NULL on failure. - */ - -struct zl10036_config { - u8 tuner_address; - int rf_loop_enable; -}; - -#if defined(CONFIG_DVB_ZL10036) || \ - (defined(CONFIG_DVB_ZL10036_MODULE) && defined(MODULE)) -extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, - const struct zl10036_config *config, struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, - const struct zl10036_config *config, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif /* DVB_ZL10036_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10039.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10039.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10039.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10039.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,307 +0,0 @@ -/* - * Driver for Zarlink ZL10039 DVB-S tuner - * - * Copyright 2007 Jan D. Louw - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "zl10039.h" - -static int debug; - -#define dprintk(args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG args); \ - } while (0) - -enum zl10039_model_id { - ID_ZL10039 = 1 -}; - -struct zl10039_state { - struct i2c_adapter *i2c; - u8 i2c_addr; - u8 id; -}; - -enum zl10039_reg_addr { - PLL0 = 0, - PLL1, - PLL2, - PLL3, - RFFE, - BASE0, - BASE1, - BASE2, - LO0, - LO1, - LO2, - LO3, - LO4, - LO5, - LO6, - GENERAL -}; - -static int zl10039_read(const struct zl10039_state *state, - const enum zl10039_reg_addr reg, u8 *buf, - const size_t count) -{ - u8 regbuf[] = { reg }; - struct i2c_msg msg[] = { - {/* Write register address */ - .addr = state->i2c_addr, - .flags = 0, - .buf = regbuf, - .len = 1, - }, {/* Read count bytes */ - .addr = state->i2c_addr, - .flags = I2C_M_RD, - .buf = buf, - .len = count, - }, - }; - - dprintk("%s\n", __func__); - - if (i2c_transfer(state->i2c, msg, 2) != 2) { - dprintk("%s: i2c read error\n", __func__); - return -EREMOTEIO; - } - - return 0; /* Success */ -} - -static int zl10039_write(struct zl10039_state *state, - const enum zl10039_reg_addr reg, const u8 *src, - const size_t count) -{ - u8 buf[count + 1]; - struct i2c_msg msg = { - .addr = state->i2c_addr, - .flags = 0, - .buf = buf, - .len = count + 1, - }; - - dprintk("%s\n", __func__); - /* Write register address and data in one go */ - buf[0] = reg; - memcpy(&buf[1], src, count); - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - dprintk("%s: i2c write error\n", __func__); - return -EREMOTEIO; - } - - return 0; /* Success */ -} - -static inline int zl10039_readreg(struct zl10039_state *state, - const enum zl10039_reg_addr reg, u8 *val) -{ - return zl10039_read(state, reg, val, 1); -} - -static inline int zl10039_writereg(struct zl10039_state *state, - const enum zl10039_reg_addr reg, - const u8 val) -{ - return zl10039_write(state, reg, &val, 1); -} - -static int zl10039_init(struct dvb_frontend *fe) -{ - struct zl10039_state *state = fe->tuner_priv; - int ret; - - dprintk("%s\n", __func__); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - /* Reset logic */ - ret = zl10039_writereg(state, GENERAL, 0x40); - if (ret < 0) { - dprintk("Note: i2c write error normal when resetting the " - "tuner\n"); - } - /* Wake up */ - ret = zl10039_writereg(state, GENERAL, 0x01); - if (ret < 0) { - dprintk("Tuner power up failed\n"); - return ret; - } - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int zl10039_sleep(struct dvb_frontend *fe) -{ - struct zl10039_state *state = fe->tuner_priv; - int ret; - - dprintk("%s\n", __func__); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = zl10039_writereg(state, GENERAL, 0x80); - if (ret < 0) { - dprintk("Tuner sleep failed\n"); - return ret; - } - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int zl10039_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct zl10039_state *state = fe->tuner_priv; - u8 buf[6]; - u8 bf; - u32 fbw; - u32 div; - int ret; - - dprintk("%s\n", __func__); - dprintk("Set frequency = %d, symbol rate = %d\n", - params->frequency, params->u.qpsk.symbol_rate); - - /* Assumed 10.111 MHz crystal oscillator */ - /* Cancelled num/den 80 to prevent overflow */ - div = (params->frequency * 1000) / 126387; - fbw = (params->u.qpsk.symbol_rate * 27) / 32000; - /* Cancelled num/den 10 to prevent overflow */ - bf = ((fbw * 5088) / 1011100) - 1; - - /*PLL divider*/ - buf[0] = (div >> 8) & 0x7f; - buf[1] = (div >> 0) & 0xff; - /*Reference divider*/ - /* Select reference ratio of 80 */ - buf[2] = 0x1D; - /*PLL test modes*/ - buf[3] = 0x40; - /*RF Control register*/ - buf[4] = 0x6E; /* Bypass enable */ - /*Baseband filter cutoff */ - buf[5] = bf; - - /* Open i2c gate */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - /* BR = 10, Enable filter adjustment */ - ret = zl10039_writereg(state, BASE1, 0x0A); - if (ret < 0) - goto error; - /* Write new config values */ - ret = zl10039_write(state, PLL0, buf, sizeof(buf)); - if (ret < 0) - goto error; - /* BR = 10, Disable filter adjustment */ - ret = zl10039_writereg(state, BASE1, 0x6A); - if (ret < 0) - goto error; - - /* Close i2c gate */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - return 0; -error: - dprintk("Error setting tuner\n"); - return ret; -} - -static int zl10039_release(struct dvb_frontend *fe) -{ - struct zl10039_state *state = fe->tuner_priv; - - dprintk("%s\n", __func__); - kfree(state); - fe->tuner_priv = NULL; - return 0; -} - -static struct dvb_tuner_ops zl10039_ops = { - .release = zl10039_release, - .init = zl10039_init, - .sleep = zl10039_sleep, - .set_params = zl10039_set_params, -}; - -struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, - u8 i2c_addr, struct i2c_adapter *i2c) -{ - struct zl10039_state *state = NULL; - - dprintk("%s\n", __func__); - state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL); - if (state == NULL) - goto error; - - state->i2c = i2c; - state->i2c_addr = i2c_addr; - - /* Open i2c gate */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - /* check if this is a valid tuner */ - if (zl10039_readreg(state, GENERAL, &state->id) < 0) { - /* Close i2c gate */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - goto error; - } - /* Close i2c gate */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - state->id = state->id & 0x0f; - switch (state->id) { - case ID_ZL10039: - strcpy(fe->ops.tuner_ops.info.name, - "Zarlink ZL10039 DVB-S tuner"); - break; - default: - dprintk("Chip ID=%x does not match a known type\n", state->id); - goto error; - } - - memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = state; - dprintk("Tuner attached @ i2c address 0x%02x\n", i2c_addr); - return fe; -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(zl10039_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver"); -MODULE_AUTHOR("Jan D. Louw "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10039.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10039.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10039.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10039.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - Driver for Zarlink ZL10039 DVB-S tuner - - Copyright (C) 2007 Jan D. Louw - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef ZL10039_H -#define ZL10039_H - -#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \ - && defined(MODULE)) -struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, - u8 i2c_addr, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, - u8 i2c_addr, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_ZL10039 */ - -#endif /* ZL10039_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,699 +0,0 @@ -/* - * Driver for Zarlink DVB-T ZL10353 demodulator - * - * Copyright (C) 2006, 2007 Christopher Pascoe - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "zl10353_priv.h" -#include "zl10353.h" - -struct zl10353_state { - struct i2c_adapter *i2c; - struct dvb_frontend frontend; - - struct zl10353_config config; - - enum fe_bandwidth bandwidth; - u32 ucblocks; - u32 frequency; -}; - -static int debug; -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG "zl10353: " args); \ - } while (0) - -static int debug_regs; - -static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val) -{ - struct zl10353_state *state = fe->demodulator_priv; - u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0, - .buf = buf, .len = 2 }; - int err = i2c_transfer(state->i2c, &msg, 1); - if (err != 1) { - printk("zl10353: write to reg %x failed (err = %d)!\n", reg, err); - return err; - } - return 0; -} - -static int zl10353_write(struct dvb_frontend *fe, const u8 ibuf[], int ilen) -{ - int err, i; - for (i = 0; i < ilen - 1; i++) - if ((err = zl10353_single_write(fe, ibuf[0] + i, ibuf[i + 1]))) - return err; - - return 0; -} - -static int zl10353_read_register(struct zl10353_state *state, u8 reg) -{ - int ret; - u8 b0[1] = { reg }; - u8 b1[1] = { 0 }; - struct i2c_msg msg[2] = { { .addr = state->config.demod_address, - .flags = 0, - .buf = b0, .len = 1 }, - { .addr = state->config.demod_address, - .flags = I2C_M_RD, - .buf = b1, .len = 1 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) { - printk("%s: readreg error (reg=%d, ret==%i)\n", - __func__, reg, ret); - return ret; - } - - return b1[0]; -} - -static void zl10353_dump_regs(struct dvb_frontend *fe) -{ - struct zl10353_state *state = fe->demodulator_priv; - int ret; - u8 reg; - - /* Dump all registers. */ - for (reg = 0; ; reg++) { - if (reg % 16 == 0) { - if (reg) - printk(KERN_CONT "\n"); - printk(KERN_DEBUG "%02x:", reg); - } - ret = zl10353_read_register(state, reg); - if (ret >= 0) - printk(KERN_CONT " %02x", (u8)ret); - else - printk(KERN_CONT " --"); - if (reg == 0xff) - break; - } - printk(KERN_CONT "\n"); -} - -static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, - enum fe_bandwidth bandwidth, - u16 *nominal_rate) -{ - struct zl10353_state *state = fe->demodulator_priv; - u32 adc_clock = 450560; /* 45.056 MHz */ - u64 value; - u8 bw; - - if (state->config.adc_clock) - adc_clock = state->config.adc_clock; - - switch (bandwidth) { - case BANDWIDTH_6_MHZ: - bw = 6; - break; - case BANDWIDTH_7_MHZ: - bw = 7; - break; - case BANDWIDTH_8_MHZ: - default: - bw = 8; - break; - } - - value = (u64)10 * (1 << 23) / 7 * 125; - value = (bw * value) + adc_clock / 2; - do_div(value, adc_clock); - *nominal_rate = value; - - dprintk("%s: bw %d, adc_clock %d => 0x%x\n", - __func__, bw, adc_clock, *nominal_rate); -} - -static void zl10353_calc_input_freq(struct dvb_frontend *fe, - u16 *input_freq) -{ - struct zl10353_state *state = fe->demodulator_priv; - u32 adc_clock = 450560; /* 45.056 MHz */ - int if2 = 361667; /* 36.1667 MHz */ - int ife; - u64 value; - - if (state->config.adc_clock) - adc_clock = state->config.adc_clock; - if (state->config.if2) - if2 = state->config.if2; - - if (adc_clock >= if2 * 2) - ife = if2; - else { - ife = adc_clock - (if2 % adc_clock); - if (ife > adc_clock / 2) - ife = adc_clock - ife; - } - value = (u64)65536 * ife + adc_clock / 2; - do_div(value, adc_clock); - *input_freq = -value; - - dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", - __func__, if2, ife, adc_clock, -(int)value, *input_freq); -} - -static int zl10353_sleep(struct dvb_frontend *fe) -{ - static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 }; - - zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown)); - return 0; -} - -static int zl10353_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct zl10353_state *state = fe->demodulator_priv; - u16 nominal_rate, input_freq; - u8 pllbuf[6] = { 0x67 }, acq_ctl = 0; - u16 tps = 0; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - - state->frequency = param->frequency; - - zl10353_single_write(fe, RESET, 0x80); - udelay(200); - zl10353_single_write(fe, 0xEA, 0x01); - udelay(200); - zl10353_single_write(fe, 0xEA, 0x00); - - zl10353_single_write(fe, AGC_TARGET, 0x28); - - if (op->transmission_mode != TRANSMISSION_MODE_AUTO) - acq_ctl |= (1 << 0); - if (op->guard_interval != GUARD_INTERVAL_AUTO) - acq_ctl |= (1 << 1); - zl10353_single_write(fe, ACQ_CTL, acq_ctl); - - switch (op->bandwidth) { - case BANDWIDTH_6_MHZ: - /* These are extrapolated from the 7 and 8MHz values */ - zl10353_single_write(fe, MCLK_RATIO, 0x97); - zl10353_single_write(fe, 0x64, 0x34); - zl10353_single_write(fe, 0xcc, 0xdd); - break; - case BANDWIDTH_7_MHZ: - zl10353_single_write(fe, MCLK_RATIO, 0x86); - zl10353_single_write(fe, 0x64, 0x35); - zl10353_single_write(fe, 0xcc, 0x73); - break; - case BANDWIDTH_8_MHZ: - default: - zl10353_single_write(fe, MCLK_RATIO, 0x75); - zl10353_single_write(fe, 0x64, 0x36); - zl10353_single_write(fe, 0xcc, 0x73); - } - - zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); - zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate)); - zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate)); - state->bandwidth = op->bandwidth; - - zl10353_calc_input_freq(fe, &input_freq); - zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq)); - zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq)); - - /* Hint at TPS settings */ - switch (op->code_rate_HP) { - case FEC_2_3: - tps |= (1 << 7); - break; - case FEC_3_4: - tps |= (2 << 7); - break; - case FEC_5_6: - tps |= (3 << 7); - break; - case FEC_7_8: - tps |= (4 << 7); - break; - case FEC_1_2: - case FEC_AUTO: - break; - default: - return -EINVAL; - } - - switch (op->code_rate_LP) { - case FEC_2_3: - tps |= (1 << 4); - break; - case FEC_3_4: - tps |= (2 << 4); - break; - case FEC_5_6: - tps |= (3 << 4); - break; - case FEC_7_8: - tps |= (4 << 4); - break; - case FEC_1_2: - case FEC_AUTO: - break; - case FEC_NONE: - if (op->hierarchy_information == HIERARCHY_AUTO || - op->hierarchy_information == HIERARCHY_NONE) - break; - default: - return -EINVAL; - } - - switch (op->constellation) { - case QPSK: - break; - case QAM_AUTO: - case QAM_16: - tps |= (1 << 13); - break; - case QAM_64: - tps |= (2 << 13); - break; - default: - return -EINVAL; - } - - switch (op->transmission_mode) { - case TRANSMISSION_MODE_2K: - case TRANSMISSION_MODE_AUTO: - break; - case TRANSMISSION_MODE_8K: - tps |= (1 << 0); - break; - default: - return -EINVAL; - } - - switch (op->guard_interval) { - case GUARD_INTERVAL_1_32: - case GUARD_INTERVAL_AUTO: - break; - case GUARD_INTERVAL_1_16: - tps |= (1 << 2); - break; - case GUARD_INTERVAL_1_8: - tps |= (2 << 2); - break; - case GUARD_INTERVAL_1_4: - tps |= (3 << 2); - break; - default: - return -EINVAL; - } - - switch (op->hierarchy_information) { - case HIERARCHY_AUTO: - case HIERARCHY_NONE: - break; - case HIERARCHY_1: - tps |= (1 << 10); - break; - case HIERARCHY_2: - tps |= (2 << 10); - break; - case HIERARCHY_4: - tps |= (3 << 10); - break; - default: - return -EINVAL; - } - - zl10353_single_write(fe, TPS_GIVEN_1, msb(tps)); - zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps)); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - /* - * If there is no tuner attached to the secondary I2C bus, we call - * set_params to program a potential tuner attached somewhere else. - * Otherwise, we update the PLL registers via calc_regs. - */ - if (state->config.no_tuner) { - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - } - } else if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5); - pllbuf[1] <<= 1; - zl10353_write(fe, pllbuf, sizeof(pllbuf)); - } - - zl10353_single_write(fe, 0x5F, 0x13); - - /* If no attached tuner or invalid PLL registers, just start the FSM. */ - if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL) - zl10353_single_write(fe, FSM_GO, 0x01); - else - zl10353_single_write(fe, TUNER_GO, 0x01); - - return 0; -} - -static int zl10353_get_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct zl10353_state *state = fe->demodulator_priv; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - int s6, s9; - u16 tps; - static const u8 tps_fec_to_api[8] = { - FEC_1_2, - FEC_2_3, - FEC_3_4, - FEC_5_6, - FEC_7_8, - FEC_AUTO, - FEC_AUTO, - FEC_AUTO - }; - - s6 = zl10353_read_register(state, STATUS_6); - s9 = zl10353_read_register(state, STATUS_9); - if (s6 < 0 || s9 < 0) - return -EREMOTEIO; - if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0) - return -EINVAL; /* no FE or TPS lock */ - - tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 | - zl10353_read_register(state, TPS_RECEIVED_0); - - op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; - op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; - - switch ((tps >> 13) & 3) { - case 0: - op->constellation = QPSK; - break; - case 1: - op->constellation = QAM_16; - break; - case 2: - op->constellation = QAM_64; - break; - default: - op->constellation = QAM_AUTO; - break; - } - - op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : - TRANSMISSION_MODE_2K; - - switch ((tps >> 2) & 3) { - case 0: - op->guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - op->guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - op->guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - op->guard_interval = GUARD_INTERVAL_1_4; - break; - default: - op->guard_interval = GUARD_INTERVAL_AUTO; - break; - } - - switch ((tps >> 10) & 7) { - case 0: - op->hierarchy_information = HIERARCHY_NONE; - break; - case 1: - op->hierarchy_information = HIERARCHY_1; - break; - case 2: - op->hierarchy_information = HIERARCHY_2; - break; - case 3: - op->hierarchy_information = HIERARCHY_4; - break; - default: - op->hierarchy_information = HIERARCHY_AUTO; - break; - } - - param->frequency = state->frequency; - op->bandwidth = state->bandwidth; - param->inversion = INVERSION_AUTO; - - return 0; -} - -static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct zl10353_state *state = fe->demodulator_priv; - int s6, s7, s8; - - if ((s6 = zl10353_read_register(state, STATUS_6)) < 0) - return -EREMOTEIO; - if ((s7 = zl10353_read_register(state, STATUS_7)) < 0) - return -EREMOTEIO; - if ((s8 = zl10353_read_register(state, STATUS_8)) < 0) - return -EREMOTEIO; - - *status = 0; - if (s6 & (1 << 2)) - *status |= FE_HAS_CARRIER; - if (s6 & (1 << 1)) - *status |= FE_HAS_VITERBI; - if (s6 & (1 << 5)) - *status |= FE_HAS_LOCK; - if (s7 & (1 << 4)) - *status |= FE_HAS_SYNC; - if (s8 & (1 << 6)) - *status |= FE_HAS_SIGNAL; - - if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != - (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) - *status &= ~FE_HAS_LOCK; - - return 0; -} - -static int zl10353_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct zl10353_state *state = fe->demodulator_priv; - - *ber = zl10353_read_register(state, RS_ERR_CNT_2) << 16 | - zl10353_read_register(state, RS_ERR_CNT_1) << 8 | - zl10353_read_register(state, RS_ERR_CNT_0); - - return 0; -} - -static int zl10353_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct zl10353_state *state = fe->demodulator_priv; - - u16 signal = zl10353_read_register(state, AGC_GAIN_1) << 10 | - zl10353_read_register(state, AGC_GAIN_0) << 2 | 3; - - *strength = ~signal; - - return 0; -} - -static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct zl10353_state *state = fe->demodulator_priv; - u8 _snr; - - if (debug_regs) - zl10353_dump_regs(fe); - - _snr = zl10353_read_register(state, SNR); - *snr = (_snr << 8) | _snr; - - return 0; -} - -static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct zl10353_state *state = fe->demodulator_priv; - u32 ubl = 0; - - ubl = zl10353_read_register(state, RS_UBC_1) << 8 | - zl10353_read_register(state, RS_UBC_0); - - state->ucblocks += ubl; - *ucblocks = state->ucblocks; - - return 0; -} - -static int zl10353_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings - *fe_tune_settings) -{ - fe_tune_settings->min_delay_ms = 1000; - fe_tune_settings->step_size = 0; - fe_tune_settings->max_drift = 0; - - return 0; -} - -static int zl10353_init(struct dvb_frontend *fe) -{ - struct zl10353_state *state = fe->demodulator_priv; - u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F }; - int rc = 0; - - if (debug_regs) - zl10353_dump_regs(fe); - if (state->config.parallel_ts) - zl10353_reset_attach[2] &= ~0x20; - if (state->config.clock_ctl_1) - zl10353_reset_attach[3] = state->config.clock_ctl_1; - if (state->config.pll_0) - zl10353_reset_attach[4] = state->config.pll_0; - - /* Do a "hard" reset if not already done */ - if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] || - zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) { - rc = zl10353_write(fe, zl10353_reset_attach, - sizeof(zl10353_reset_attach)); - if (debug_regs) - zl10353_dump_regs(fe); - } - - return 0; -} - -static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct zl10353_state *state = fe->demodulator_priv; - u8 val = 0x0a; - - if (state->config.disable_i2c_gate_ctrl) { - /* No tuner attached to the internal I2C bus */ - /* If set enable I2C bridge, the main I2C bus stopped hardly */ - return 0; - } - - if (enable) - val |= 0x10; - - return zl10353_single_write(fe, 0x62, val); -} - -static void zl10353_release(struct dvb_frontend *fe) -{ - struct zl10353_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops zl10353_ops; - -struct dvb_frontend *zl10353_attach(const struct zl10353_config *config, - struct i2c_adapter *i2c) -{ - struct zl10353_state *state = NULL; - int id; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL); - if (state == NULL) - goto error; - - /* setup the state */ - state->i2c = i2c; - memcpy(&state->config, config, sizeof(struct zl10353_config)); - - /* check if the demod is there */ - id = zl10353_read_register(state, CHIP_ID); - if ((id != ID_ZL10353) && (id != ID_CE6230) && (id != ID_CE6231)) - goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - - return &state->frontend; -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops zl10353_ops = { - - .info = { - .name = "Zarlink ZL10353 DVB-T", - .type = FE_OFDM, - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .frequency_tolerance = 0, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | - FE_CAN_MUTE_TS - }, - - .release = zl10353_release, - - .init = zl10353_init, - .sleep = zl10353_sleep, - .i2c_gate_ctrl = zl10353_i2c_gate_ctrl, - .write = zl10353_write, - - .set_frontend = zl10353_set_parameters, - .get_frontend = zl10353_get_parameters, - .get_tune_settings = zl10353_get_tune_settings, - - .read_status = zl10353_read_status, - .read_ber = zl10353_read_ber, - .read_signal_strength = zl10353_read_signal_strength, - .read_snr = zl10353_read_snr, - .read_ucblocks = zl10353_read_ucblocks, -}; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -module_param(debug_regs, int, 0644); -MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off)."); - -MODULE_DESCRIPTION("Zarlink ZL10353 DVB-T demodulator driver"); -MODULE_AUTHOR("Chris Pascoe"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(zl10353_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* - * Driver for Zarlink DVB-T ZL10353 demodulator - * - * Copyright (C) 2006, 2007 Christopher Pascoe - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef ZL10353_H -#define ZL10353_H - -#include - -struct zl10353_config -{ - /* demodulator's I2C address */ - u8 demod_address; - - /* frequencies in units of 0.1kHz */ - int adc_clock; /* default: 450560 (45.056 MHz) */ - int if2; /* default: 361667 (36.1667 MHz) */ - - /* set if no pll is connected to the secondary i2c bus */ - int no_tuner; - - /* set if parallel ts output is required */ - int parallel_ts; - - /* set if i2c_gate_ctrl disable is required */ - u8 disable_i2c_gate_ctrl:1; - - /* clock control registers (0x51-0x54) */ - u8 clock_ctl_1; /* default: 0x46 */ - u8 pll_0; /* default: 0x15 */ -}; - -#if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE)) -extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *config, - struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_ZL10353 */ - -#endif /* ZL10353_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353_priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/frontends/zl10353_priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/* - * Driver for Zarlink DVB-T ZL10353 demodulator - * - * Copyright (C) 2006, 2007 Christopher Pascoe - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _ZL10353_PRIV_ -#define _ZL10353_PRIV_ - -#define ID_ZL10353 0x14 /* Zarlink ZL10353 */ -#define ID_CE6230 0x18 /* Intel CE6230 */ -#define ID_CE6231 0x19 /* Intel CE6231 */ - -#define msb(x) (((x) >> 8) & 0xff) -#define lsb(x) ((x) & 0xff) - -enum zl10353_reg_addr { - INTERRUPT_0 = 0x00, - INTERRUPT_1 = 0x01, - INTERRUPT_2 = 0x02, - INTERRUPT_3 = 0x03, - INTERRUPT_4 = 0x04, - INTERRUPT_5 = 0x05, - STATUS_6 = 0x06, - STATUS_7 = 0x07, - STATUS_8 = 0x08, - STATUS_9 = 0x09, - AGC_GAIN_1 = 0x0A, - AGC_GAIN_0 = 0x0B, - SNR = 0x10, - RS_ERR_CNT_2 = 0x11, - RS_ERR_CNT_1 = 0x12, - RS_ERR_CNT_0 = 0x13, - RS_UBC_1 = 0x14, - RS_UBC_0 = 0x15, - TPS_RECEIVED_1 = 0x1D, - TPS_RECEIVED_0 = 0x1E, - TPS_CURRENT_1 = 0x1F, - TPS_CURRENT_0 = 0x20, - CLOCK_CTL_0 = 0x51, - CLOCK_CTL_1 = 0x52, - PLL_0 = 0x53, - PLL_1 = 0x54, - RESET = 0x55, - AGC_TARGET = 0x56, - MCLK_RATIO = 0x5C, - ACQ_CTL = 0x5E, - TRL_NOMINAL_RATE_1 = 0x65, - TRL_NOMINAL_RATE_0 = 0x66, - INPUT_FREQ_1 = 0x6C, - INPUT_FREQ_0 = 0x6D, - TPS_GIVEN_1 = 0x6E, - TPS_GIVEN_0 = 0x6F, - TUNER_GO = 0x70, - FSM_GO = 0x71, - CHIP_ID = 0x7F, - CHAN_STEP_1 = 0xE4, - CHAN_STEP_0 = 0xE5, - OFDM_LOCK_TIME = 0xE7, - FEC_LOCK_TIME = 0xE8, - ACQ_DELAY = 0xE9, -}; - -#endif /* _ZL10353_PRIV_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -# -# DVB device configuration -# - -config DVB_MAX_ADAPTERS - int "maximum number of DVB/ATSC adapters" - depends on DVB_CORE - default 8 - range 1 255 - help - Maximum number of DVB/ATSC adapters. Increasing this number - increases the memory consumption of the DVB subsystem even - if a much lower number of DVB/ATSC adapters is present. - Only values in the range 4-32 are tested. - - If you are unsure about this, use the default value 8 - -config DVB_DYNAMIC_MINORS - bool "Dynamic DVB minor allocation" - depends on DVB_CORE - default n - help - If you say Y here, the DVB subsystem will use dynamic minor - allocation for any device that uses the DVB major number. - This means that you can have more than 4 of a single type - of device (like demuxes and frontends) per adapter, but udev - will be required to manage the device nodes. - - If you are unsure about this, say N here. - -menuconfig DVB_CAPTURE_DRIVERS - bool "DVB/ATSC adapters" - depends on DVB_CORE - default y - ---help--- - Say Y to select Digital TV adapters - -if DVB_CAPTURE_DRIVERS && DVB_CORE - -comment "Supported SAA7146 based PCI Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/ttpci/Kconfig" - -comment "Supported USB Adapters" - depends on DVB_CORE && USB && I2C -source "drivers/media/dvb/dvb-usb/Kconfig" -source "drivers/media/dvb/ttusb-budget/Kconfig" -source "drivers/media/dvb/ttusb-dec/Kconfig" -source "drivers/media/dvb/siano/Kconfig" - -comment "Supported FlexCopII (B2C2) Adapters" - depends on DVB_CORE && (PCI || USB) && I2C -source "drivers/media/dvb/b2c2/Kconfig" - -comment "Supported BT878 Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/bt8xx/Kconfig" - -comment "Supported Pluto2 Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/pluto2/Kconfig" - -comment "Supported SDMC DM1105 Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/dm1105/Kconfig" - -comment "Supported FireWire (IEEE 1394) Adapters" - depends on DVB_CORE && FIREWIRE -source "drivers/media/dvb/firewire/Kconfig" - -comment "Supported Earthsoft PT1 Adapters" - depends on DVB_CORE && PCI && I2C -source "drivers/media/dvb/pt1/Kconfig" - -comment "Supported Mantis Adapters" - depends on DVB_CORE && PCI && I2C - source "drivers/media/dvb/mantis/Kconfig" - -comment "Supported nGene Adapters" - depends on DVB_CORE && PCI && I2C - source "drivers/media/dvb/ngene/Kconfig" - -comment "Supported DVB Frontends" - depends on DVB_CORE -source "drivers/media/dvb/frontends/Kconfig" - -endif # DVB_CAPTURE_DRIVERS diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -# -# Makefile for the kernel multimedia device drivers. -# - -obj-y := dvb-core/ \ - frontends/ \ - ttpci/ \ - ttusb-dec/ \ - ttusb-budget/ \ - b2c2/ \ - bt8xx/ \ - dvb-usb/ \ - pluto2/ \ - siano/ \ - dm1105/ \ - pt1/ \ - mantis/ \ - ngene/ - -obj-$(CONFIG_DVB_FIREDTV) += firewire/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_cards.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,278 +0,0 @@ -/* - Hopper PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "hopper_vp3028.h" -#include "mantis_dma.h" -#include "mantis_dvb.h" -#include "mantis_uart.h" -#include "mantis_ioc.h" -#include "mantis_pci.h" -#include "mantis_i2c.h" -#include "mantis_reg.h" - -static unsigned int verbose; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); - -#define DRIVER_NAME "Hopper" - -static char *label[10] = { - "DMA", - "IRQ-0", - "IRQ-1", - "OCERR", - "PABRT", - "RIPRR", - "PPERR", - "FTRGT", - "RISCI", - "RACK" -}; - -static int devs; - -static irqreturn_t hopper_irq_handler(int irq, void *dev_id) -{ - u32 stat = 0, mask = 0, lstat = 0, mstat = 0; - u32 rst_stat = 0, rst_mask = 0; - - struct mantis_pci *mantis; - struct mantis_ca *ca; - - mantis = (struct mantis_pci *) dev_id; - if (unlikely(mantis == NULL)) { - dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); - return IRQ_NONE; - } - ca = mantis->mantis_ca; - - stat = mmread(MANTIS_INT_STAT); - mask = mmread(MANTIS_INT_MASK); - mstat = lstat = stat & ~MANTIS_INT_RISCSTAT; - if (!(stat & mask)) - return IRQ_NONE; - - rst_mask = MANTIS_GPIF_WRACK | - MANTIS_GPIF_OTHERR | - MANTIS_SBUF_WSTO | - MANTIS_GPIF_EXTIRQ; - - rst_stat = mmread(MANTIS_GPIF_STATUS); - rst_stat &= rst_mask; - mmwrite(rst_stat, MANTIS_GPIF_STATUS); - - mantis->mantis_int_stat = stat; - mantis->mantis_int_mask = mask; - dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); - if (stat & MANTIS_INT_RISCEN) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); - } - if (stat & MANTIS_INT_IRQ0) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); - mantis->gpif_status = rst_stat; - wake_up(&ca->hif_write_wq); - schedule_work(&ca->hif_evm_work); - } - if (stat & MANTIS_INT_IRQ1) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); - schedule_work(&mantis->uart_work); - } - if (stat & MANTIS_INT_OCERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); - } - if (stat & MANTIS_INT_PABORT) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); - } - if (stat & MANTIS_INT_RIPERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); - } - if (stat & MANTIS_INT_PPERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); - } - if (stat & MANTIS_INT_FTRGT) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); - } - if (stat & MANTIS_INT_RISCI) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); - mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; - tasklet_schedule(&mantis->tasklet); - } - if (stat & MANTIS_INT_I2CDONE) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); - wake_up(&mantis->i2c_wq); - } - mmwrite(stat, MANTIS_INT_STAT); - stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | - MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | - MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | - MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | - MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | - MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | - MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | - MANTIS_INT_PABORT | MANTIS_INT_RIPERR | - MANTIS_INT_PPERR | MANTIS_INT_FTRGT | - MANTIS_INT_RISCI); - - if (stat) - dprintk(MANTIS_DEBUG, 0, " Stat=<%02x> Mask=<%02x>", stat, mask); - - dprintk(MANTIS_DEBUG, 0, "\n"); - return IRQ_HANDLED; -} - -static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) -{ - struct mantis_pci *mantis; - struct mantis_hwconfig *config; - int err = 0; - - mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); - if (mantis == NULL) { - printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); - err = -ENOMEM; - goto fail0; - } - - mantis->num = devs; - mantis->verbose = verbose; - mantis->pdev = pdev; - config = (struct mantis_hwconfig *) pci_id->driver_data; - config->irq_handler = &hopper_irq_handler; - mantis->hwconfig = config; - - err = mantis_pci_init(mantis); - if (err) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); - goto fail1; - } - - err = mantis_stream_control(mantis, STREAM_TO_HIF); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); - goto fail1; - } - - err = mantis_i2c_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); - goto fail2; - } - - err = mantis_get_mac(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); - goto fail2; - } - - err = mantis_dma_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); - goto fail3; - } - - err = mantis_dvb_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); - goto fail4; - } - devs++; - - return err; - -fail4: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); - mantis_dma_exit(mantis); - -fail3: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); - mantis_i2c_exit(mantis); - -fail2: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); - mantis_pci_exit(mantis); - -fail1: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); - kfree(mantis); - -fail0: - return err; -} - -static void __devexit hopper_pci_remove(struct pci_dev *pdev) -{ - struct mantis_pci *mantis = pci_get_drvdata(pdev); - - if (mantis) { - mantis_dvb_exit(mantis); - mantis_dma_exit(mantis); - mantis_i2c_exit(mantis); - mantis_pci_exit(mantis); - kfree(mantis); - } - return; - -} - -static struct pci_device_id hopper_pci_table[] = { - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config), - { } -}; - -MODULE_DEVICE_TABLE(pci, hopper_pci_table); - -static struct pci_driver hopper_pci_driver = { - .name = DRIVER_NAME, - .id_table = hopper_pci_table, - .probe = hopper_pci_probe, - .remove = hopper_pci_remove, -}; - -static int __devinit hopper_init(void) -{ - return pci_register_driver(&hopper_pci_driver); -} - -static void __devexit hopper_exit(void) -{ - return pci_unregister_driver(&hopper_pci_driver); -} - -module_init(hopper_init); -module_exit(hopper_exit); - -MODULE_DESCRIPTION("HOPPER driver"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_vp3028.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_vp3028.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_vp3028.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_vp3028.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -/* - Hopper VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "zl10353.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "hopper_vp3028.h" - -struct zl10353_config hopper_vp3028_config = { - .demod_address = 0x0f, -}; - -#define MANTIS_MODEL_NAME "VP-3028" -#define MANTIS_DEV_TYPE "DVB-T" - -static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - struct mantis_hwconfig *config = mantis->hwconfig; - int err = 0; - - mantis_gpio_set_bits(mantis, config->reset, 0); - msleep(100); - err = mantis_frontend_power(mantis, POWER_ON); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 1); - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - msleep(250); - dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); - fe = dvb_attach(zl10353_attach, &hopper_vp3028_config, adapter); - - if (!fe) - return -1; - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp3028_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp3028_frontend_init, - .power = GPIF_A00, - .reset = GPIF_A03, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_vp3028.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_vp3028.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_vp3028.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/hopper_vp3028.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - Hopper VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP3028_H -#define __MANTIS_VP3028_H - -#include "mantis_common.h" - -#define MANTIS_VP_3028_DVB_T 0x0028 - -extern struct mantis_hwconfig vp3028_config; - -#endif /* __MANTIS_VP3028_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -config MANTIS_CORE - tristate "Mantis/Hopper PCI bridge based devices" - depends on PCI && I2C && INPUT && RC_CORE - - help - Support for PCI cards based on the Mantis and Hopper PCi bridge. - - Say Y if you own such a device and want to use it. - -config DVB_MANTIS - tristate "MANTIS based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C - select DVB_MB86A16 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select DVB_TDA665x if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_PLL - help - Support for PCI cards based on the Mantis PCI bridge. - Say Y when you have a Mantis based DVB card and want to use it. - - If unsure say N. - -config DVB_HOPPER - tristate "HOPPER based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_PLL - help - Support for PCI cards based on the Hopper PCI bridge. - Say Y when you have a Hopper based DVB card and want to use it. - - If unsure say N diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -mantis_core-objs := mantis_ioc.o \ - mantis_uart.o \ - mantis_dma.o \ - mantis_pci.o \ - mantis_i2c.o \ - mantis_dvb.o \ - mantis_evm.o \ - mantis_hif.o \ - mantis_ca.o \ - mantis_pcmcia.o \ - mantis_input.o - -mantis-objs := mantis_cards.o \ - mantis_vp1033.o \ - mantis_vp1034.o \ - mantis_vp1041.o \ - mantis_vp2033.o \ - mantis_vp2040.o \ - mantis_vp3030.o - -hopper-objs := hopper_cards.o \ - hopper_vp3028.o - -obj-$(CONFIG_MANTIS_CORE) += mantis_core.o -obj-$(CONFIG_DVB_MANTIS) += mantis.o -obj-$(CONFIG_DVB_HOPPER) += hopper.o - -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ca.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ca.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ca.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ca.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,208 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_link.h" -#include "mantis_hif.h" -#include "mantis_reg.h" - -#include "mantis_ca.h" - -static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot); - - if (slot != 0) - return -EINVAL; - - return mantis_hif_read_mem(ca, addr); -} - -static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot); - - if (slot != 0) - return -EINVAL; - - return mantis_hif_write_mem(ca, addr, data); -} - -static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot); - - if (slot != 0) - return -EINVAL; - - return mantis_hif_read_iom(ca, addr); -} - -static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot); - - if (slot != 0) - return -EINVAL; - - return mantis_hif_write_iom(ca, addr, data); -} - -static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot); - udelay(500); /* Wait.. */ - mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */ - udelay(500); - mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */ - msleep(1000); - dvb_ca_en50221_camready_irq(&ca->en50221, 0); - - return 0; -} - -static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot); - - return 0; -} - -static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot); -/* mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */ - - return 0; -} - -static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) -{ - struct mantis_ca *ca = en50221->data; - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot); - - if (ca->slot_state == MODULE_INSERTED) { - dprintk(MANTIS_DEBUG, 1, "CA Module present and ready"); - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - } else { - dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready"); - } - - return 0; -} - -int mantis_ca_init(struct mantis_pci *mantis) -{ - struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter; - struct mantis_ca *ca; - int ca_flags = 0, result; - - dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA"); - ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL); - if (!ca) { - dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting .."); - result = -ENOMEM; - goto err; - } - - ca->ca_priv = mantis; - mantis->mantis_ca = ca; - ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE; - /* register CA interface */ - ca->en50221.owner = THIS_MODULE; - ca->en50221.read_attribute_mem = mantis_ca_read_attr_mem; - ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem; - ca->en50221.read_cam_control = mantis_ca_read_cam_ctl; - ca->en50221.write_cam_control = mantis_ca_write_cam_ctl; - ca->en50221.slot_reset = mantis_ca_slot_reset; - ca->en50221.slot_shutdown = mantis_ca_slot_shutdown; - ca->en50221.slot_ts_enable = mantis_ts_control; - ca->en50221.poll_slot_status = mantis_slot_status; - ca->en50221.data = ca; - - mutex_init(&ca->ca_lock); - - init_waitqueue_head(&ca->hif_data_wq); - init_waitqueue_head(&ca->hif_opdone_wq); - init_waitqueue_head(&ca->hif_write_wq); - - dprintk(MANTIS_ERROR, 1, "Registering EN50221 device"); - result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1); - if (result != 0) { - dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result); - goto err; - } - dprintk(MANTIS_ERROR, 1, "Registered EN50221 device"); - mantis_evmgr_init(ca); - return 0; -err: - kfree(ca); - return result; -} -EXPORT_SYMBOL_GPL(mantis_ca_init); - -void mantis_ca_exit(struct mantis_pci *mantis) -{ - struct mantis_ca *ca = mantis->mantis_ca; - - dprintk(MANTIS_DEBUG, 1, "Mantis CA exit"); - - mantis_evmgr_exit(ca); - dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device"); - if (ca) - dvb_ca_en50221_release(&ca->en50221); - - kfree(ca); -} -EXPORT_SYMBOL_GPL(mantis_ca_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ca.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ca.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ca.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ca.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_CA_H -#define __MANTIS_CA_H - -extern int mantis_ca_init(struct mantis_pci *mantis); -extern void mantis_ca_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_CA_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_cards.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,308 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" - -#include "mantis_vp1033.h" -#include "mantis_vp1034.h" -#include "mantis_vp1041.h" -#include "mantis_vp2033.h" -#include "mantis_vp2040.h" -#include "mantis_vp3030.h" - -#include "mantis_dma.h" -#include "mantis_ca.h" -#include "mantis_dvb.h" -#include "mantis_uart.h" -#include "mantis_ioc.h" -#include "mantis_pci.h" -#include "mantis_i2c.h" -#include "mantis_reg.h" - -static unsigned int verbose; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); - -static int devs; - -#define DRIVER_NAME "Mantis" - -static char *label[10] = { - "DMA", - "IRQ-0", - "IRQ-1", - "OCERR", - "PABRT", - "RIPRR", - "PPERR", - "FTRGT", - "RISCI", - "RACK" -}; - -static irqreturn_t mantis_irq_handler(int irq, void *dev_id) -{ - u32 stat = 0, mask = 0, lstat = 0, mstat = 0; - u32 rst_stat = 0, rst_mask = 0; - - struct mantis_pci *mantis; - struct mantis_ca *ca; - - mantis = (struct mantis_pci *) dev_id; - if (unlikely(mantis == NULL)) { - dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); - return IRQ_NONE; - } - ca = mantis->mantis_ca; - - stat = mmread(MANTIS_INT_STAT); - mask = mmread(MANTIS_INT_MASK); - mstat = lstat = stat & ~MANTIS_INT_RISCSTAT; - if (!(stat & mask)) - return IRQ_NONE; - - rst_mask = MANTIS_GPIF_WRACK | - MANTIS_GPIF_OTHERR | - MANTIS_SBUF_WSTO | - MANTIS_GPIF_EXTIRQ; - - rst_stat = mmread(MANTIS_GPIF_STATUS); - rst_stat &= rst_mask; - mmwrite(rst_stat, MANTIS_GPIF_STATUS); - - mantis->mantis_int_stat = stat; - mantis->mantis_int_mask = mask; - dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); - if (stat & MANTIS_INT_RISCEN) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); - } - if (stat & MANTIS_INT_IRQ0) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); - mantis->gpif_status = rst_stat; - wake_up(&ca->hif_write_wq); - schedule_work(&ca->hif_evm_work); - } - if (stat & MANTIS_INT_IRQ1) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); - schedule_work(&mantis->uart_work); - } - if (stat & MANTIS_INT_OCERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); - } - if (stat & MANTIS_INT_PABORT) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); - } - if (stat & MANTIS_INT_RIPERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); - } - if (stat & MANTIS_INT_PPERR) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); - } - if (stat & MANTIS_INT_FTRGT) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); - } - if (stat & MANTIS_INT_RISCI) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); - mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; - tasklet_schedule(&mantis->tasklet); - } - if (stat & MANTIS_INT_I2CDONE) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); - wake_up(&mantis->i2c_wq); - } - mmwrite(stat, MANTIS_INT_STAT); - stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | - MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | - MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | - MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | - MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | - MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | - MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | - MANTIS_INT_PABORT | MANTIS_INT_RIPERR | - MANTIS_INT_PPERR | MANTIS_INT_FTRGT | - MANTIS_INT_RISCI); - - if (stat) - dprintk(MANTIS_DEBUG, 0, " Stat=<%02x> Mask=<%02x>", stat, mask); - - dprintk(MANTIS_DEBUG, 0, "\n"); - return IRQ_HANDLED; -} - -static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) -{ - struct mantis_pci *mantis; - struct mantis_hwconfig *config; - int err = 0; - - mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); - if (mantis == NULL) { - printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); - err = -ENOMEM; - goto fail0; - } - - mantis->num = devs; - mantis->verbose = verbose; - mantis->pdev = pdev; - config = (struct mantis_hwconfig *) pci_id->driver_data; - config->irq_handler = &mantis_irq_handler; - mantis->hwconfig = config; - - err = mantis_pci_init(mantis); - if (err) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); - goto fail1; - } - - err = mantis_stream_control(mantis, STREAM_TO_HIF); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); - goto fail1; - } - - err = mantis_i2c_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); - goto fail2; - } - - err = mantis_get_mac(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); - goto fail2; - } - - err = mantis_dma_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); - goto fail3; - } - - err = mantis_dvb_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); - goto fail4; - } - err = mantis_uart_init(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err); - goto fail6; - } - - devs++; - - return err; - - - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err); - mantis_uart_exit(mantis); - -fail6: -fail4: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); - mantis_dma_exit(mantis); - -fail3: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); - mantis_i2c_exit(mantis); - -fail2: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); - mantis_pci_exit(mantis); - -fail1: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); - kfree(mantis); - -fail0: - return err; -} - -static void __devexit mantis_pci_remove(struct pci_dev *pdev) -{ - struct mantis_pci *mantis = pci_get_drvdata(pdev); - - if (mantis) { - - mantis_uart_exit(mantis); - mantis_dvb_exit(mantis); - mantis_dma_exit(mantis); - mantis_i2c_exit(mantis); - mantis_pci_exit(mantis); - kfree(mantis); - } - return; -} - -static struct pci_device_id mantis_pci_table[] = { - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config), - MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config), - MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config), - MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config), - MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config), - MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2033_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config), - { } -}; - -MODULE_DEVICE_TABLE(pci, mantis_pci_table); - -static struct pci_driver mantis_pci_driver = { - .name = DRIVER_NAME, - .id_table = mantis_pci_table, - .probe = mantis_pci_probe, - .remove = mantis_pci_remove, -}; - -static int __devinit mantis_init(void) -{ - return pci_register_driver(&mantis_pci_driver); -} - -static void __devexit mantis_exit(void) -{ - return pci_unregister_driver(&mantis_pci_driver); -} - -module_init(mantis_init); -module_exit(mantis_exit); - -MODULE_DESCRIPTION("MANTIS driver"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_common.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,181 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_COMMON_H -#define __MANTIS_COMMON_H - -#include -#include - -#include "mantis_uart.h" - -#include "mantis_link.h" - -#define MANTIS_ERROR 0 -#define MANTIS_NOTICE 1 -#define MANTIS_INFO 2 -#define MANTIS_DEBUG 3 -#define MANTIS_TMG 9 - -#define dprintk(y, z, format, arg...) do { \ - if (z) { \ - if ((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y)) \ - printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - else if ((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y)) \ - printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y)) \ - printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y)) \ - printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y)) \ - printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ - } else { \ - if (mantis->verbose > y) \ - printk(format , ##arg); \ - } \ -} while(0) - -#define mwrite(dat, addr) writel((dat), addr) -#define mread(addr) readl(addr) - -#define mmwrite(dat, addr) mwrite((dat), (mantis->mmio + (addr))) -#define mmread(addr) mread(mantis->mmio + (addr)) - -#define MANTIS_TS_188 0 -#define MANTIS_TS_204 1 - -#define TWINHAN_TECHNOLOGIES 0x1822 -#define MANTIS 0x4e35 - -#define TECHNISAT 0x1ae4 -#define TERRATEC 0x153b - -#define MAKE_ENTRY(__subven, __subdev, __configptr) { \ - .vendor = TWINHAN_TECHNOLOGIES, \ - .device = MANTIS, \ - .subvendor = (__subven), \ - .subdevice = (__subdev), \ - .driver_data = (unsigned long) (__configptr) \ -} - -enum mantis_i2c_mode { - MANTIS_PAGE_MODE = 0, - MANTIS_BYTE_MODE, -}; - -struct mantis_pci; - -struct mantis_hwconfig { - char *model_name; - char *dev_type; - u32 ts_size; - - enum mantis_baud baud_rate; - enum mantis_parity parity; - u32 bytes; - - irqreturn_t (*irq_handler)(int irq, void *dev_id); - int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe); - - u8 power; - u8 reset; - - enum mantis_i2c_mode i2c_mode; -}; - -struct mantis_pci { - unsigned int verbose; - - /* PCI stuff */ - u16 vendor_id; - u16 device_id; - u16 subsystem_vendor; - u16 subsystem_device; - - u8 latency; - - struct pci_dev *pdev; - - unsigned long mantis_addr; - void __iomem *mmio; - - u8 irq; - u8 revision; - - unsigned int num; - - /* RISC Core */ - u32 finished_block; - u32 last_block; - u32 line_bytes; - u32 line_count; - u32 risc_pos; - u8 *buf_cpu; - dma_addr_t buf_dma; - u32 *risc_cpu; - dma_addr_t risc_dma; - - struct tasklet_struct tasklet; - - struct i2c_adapter adapter; - int i2c_rc; - wait_queue_head_t i2c_wq; - struct mutex i2c_lock; - - /* DVB stuff */ - struct dvb_adapter dvb_adapter; - struct dvb_frontend *fe; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net dvbnet; - - u8 feeds; - - struct mantis_hwconfig *hwconfig; - - u32 mantis_int_stat; - u32 mantis_int_mask; - - /* board specific */ - u8 mac_address[8]; - u32 sub_vendor_id; - u32 sub_device_id; - - /* A12 A13 A14 */ - u32 gpio_status; - - u32 gpif_status; - - struct mantis_ca *mantis_ca; - - wait_queue_head_t uart_wq; - struct work_struct uart_work; - spinlock_t uart_lock; - - struct rc_dev *rc; - char input_name[80]; - char input_phys[80]; -}; - -#define MANTIS_HIF_STATUS (mantis->gpio_status) - -#endif /* __MANTIS_COMMON_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,235 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "mantis_common.h" -#include "mantis_core.h" -#include "mantis_vp1033.h" -#include "mantis_vp1034.h" -#include "mantis_vp1041.h" -#include "mantis_vp2033.h" -#include "mantis_vp2040.h" -#include "mantis_vp3030.h" - -static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) -{ - int err; - struct i2c_msg msg[] = { - { - .addr = 0x50, - .flags = 0, - .buf = data, - .len = 1 - }, { - .addr = 0x50, - .flags = I2C_M_RD, - .buf = data, - .len = length - }, - }; - - err = i2c_transfer(&mantis->adapter, msg, 2); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, - "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", - err, data[0], data[1]); - - return err; - } - - return 0; -} - -static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) -{ - int err; - - struct i2c_msg msg = { - .addr = 0x50, - .flags = 0, - .buf = data, - .len = length - }; - - err = i2c_transfer(&mantis->adapter, &msg, 1); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, - "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >", - err, length, data[0], data[1]); - - return err; - } - - return 0; -} - -static int get_mac_address(struct mantis_pci *mantis) -{ - int err; - - mantis->mac_address[0] = 0x08; - err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error"); - - return err; - } - dprintk(verbose, MANTIS_ERROR, 0, - " MAC Address=[%pM]\n", mantis->mac_address); - - return 0; -} - -#define MANTIS_MODEL_UNKNOWN "UNKNOWN" -#define MANTIS_DEV_UNKNOWN "UNKNOWN" - -struct mantis_hwconfig unknown_device = { - .model_name = MANTIS_MODEL_UNKNOWN, - .dev_type = MANTIS_DEV_UNKNOWN, -}; - -static void mantis_load_config(struct mantis_pci *mantis) -{ - switch (mantis->subsystem_device) { - case MANTIS_VP_1033_DVB_S: /* VP-1033 */ - mantis->hwconfig = &vp1033_mantis_config; - break; - case MANTIS_VP_1034_DVB_S: /* VP-1034 */ - mantis->hwconfig = &vp1034_mantis_config; - break; - case MANTIS_VP_1041_DVB_S2: /* VP-1041 */ - case TECHNISAT_SKYSTAR_HD2: - mantis->hwconfig = &vp1041_mantis_config; - break; - case MANTIS_VP_2033_DVB_C: /* VP-2033 */ - mantis->hwconfig = &vp2033_mantis_config; - break; - case MANTIS_VP_2040_DVB_C: /* VP-2040 */ - case TERRATEC_CINERGY_C_PCI: /* VP-2040 clone */ - case TECHNISAT_CABLESTAR_HD2: - mantis->hwconfig = &vp2040_mantis_config; - break; - case MANTIS_VP_3030_DVB_T: /* VP-3030 */ - mantis->hwconfig = &vp3030_mantis_config; - break; - default: - mantis->hwconfig = &unknown_device; - break; - } -} - -int mantis_core_init(struct mantis_pci *mantis) -{ - int err = 0; - - mantis_load_config(mantis); - dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", - mantis->hwconfig->model_name, mantis->hwconfig->dev_type, - mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn)); - dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", - mantis->revision, - mantis->subsystem_vendor, mantis->subsystem_device); - dprintk(verbose, MANTIS_ERROR, 0, - "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", - mantis->pdev->irq, mantis->latency, - mantis->mantis_addr, mantis->mantis_mmio); - - err = mantis_i2c_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed"); - return err; - } - err = get_mac_address(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed"); - return err; - } - err = mantis_dma_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed"); - return err; - } - err = mantis_dvb_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed"); - return err; - } - err = mantis_uart_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed"); - return err; - } - - return 0; -} - -int mantis_core_exit(struct mantis_pci *mantis) -{ - mantis_dma_stop(mantis); - dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping"); - - mantis_uart_exit(mantis); - dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed"); - - if (mantis_dma_exit(mantis) < 0) - dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed"); - if (mantis_dvb_exit(mantis) < 0) - dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed"); - if (mantis_i2c_exit(mantis) < 0) - dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed"); - - return 0; -} - -/* Turn the given bit on or off. */ -void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) -{ - u32 cur; - - cur = mmread(MANTIS_GPIF_ADDR); - if (value) - mantis->gpio_status = cur | (1 << bitpos); - else - mantis->gpio_status = cur & (~(1 << bitpos)); - - mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); - mmwrite(0x00, MANTIS_GPIF_DOUT); - udelay(100); -} - -/* direction = 0 , no CI passthrough ; 1 , CI passthrough */ -void mantis_set_direction(struct mantis_pci *mantis, int direction) -{ - u32 reg; - - reg = mmread(0x28); - dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup"); - if (direction == 0x01) { - /* to CI */ - reg |= 0x04; - mmwrite(reg, 0x28); - reg &= 0xff - 0x04; - mmwrite(reg, 0x28); - } else { - reg &= 0xff - 0x04; - mmwrite(reg, 0x28); - reg |= 0x04; - mmwrite(reg, 0x28); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_core.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_core.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_CORE_H -#define __MANTIS_CORE_H - -#include "mantis_common.h" - - -#define FE_TYPE_SAT 0 -#define FE_TYPE_CAB 1 -#define FE_TYPE_TER 2 - -#define FE_TYPE_TS204 0 -#define FE_TYPE_TS188 1 - - -struct vendorname { - u8 *sub_vendor_name; - u32 sub_vendor_id; -}; - -struct devicetype { - u8 *sub_device_name; - u32 sub_device_id; - u8 device_type; - u32 type_flags; -}; - - -extern int mantis_dma_init(struct mantis_pci *mantis); -extern int mantis_dma_exit(struct mantis_pci *mantis); -extern void mantis_dma_start(struct mantis_pci *mantis); -extern void mantis_dma_stop(struct mantis_pci *mantis); -extern int mantis_i2c_init(struct mantis_pci *mantis); -extern int mantis_i2c_exit(struct mantis_pci *mantis); -extern int mantis_core_init(struct mantis_pci *mantis); -extern int mantis_core_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_CORE_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dma.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dma.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dma.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dma.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,256 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_dma.h" - -#define RISC_WRITE (0x01 << 28) -#define RISC_JUMP (0x07 << 28) -#define RISC_IRQ (0x01 << 24) - -#define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) -#define RISC_FLUSH() (mantis->risc_pos = 0) -#define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode)) - -#define MANTIS_BUF_SIZE (64 * 1024) -#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4) -#define MANTIS_BLOCK_COUNT (1 << 4) -#define MANTIS_RISC_SIZE PAGE_SIZE - -int mantis_dma_exit(struct mantis_pci *mantis) -{ - if (mantis->buf_cpu) { - dprintk(MANTIS_ERROR, 1, - "DMA=0x%lx cpu=0x%p size=%d", - (unsigned long) mantis->buf_dma, - mantis->buf_cpu, - MANTIS_BUF_SIZE); - - pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE, - mantis->buf_cpu, mantis->buf_dma); - - mantis->buf_cpu = NULL; - } - if (mantis->risc_cpu) { - dprintk(MANTIS_ERROR, 1, - "RISC=0x%lx cpu=0x%p size=%lx", - (unsigned long) mantis->risc_dma, - mantis->risc_cpu, - MANTIS_RISC_SIZE); - - pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE, - mantis->risc_cpu, mantis->risc_dma); - - mantis->risc_cpu = NULL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_dma_exit); - -static inline int mantis_alloc_buffers(struct mantis_pci *mantis) -{ - if (!mantis->buf_cpu) { - mantis->buf_cpu = pci_alloc_consistent(mantis->pdev, - MANTIS_BUF_SIZE, - &mantis->buf_dma); - if (!mantis->buf_cpu) { - dprintk(MANTIS_ERROR, 1, - "DMA buffer allocation failed"); - - goto err; - } - dprintk(MANTIS_ERROR, 1, - "DMA=0x%lx cpu=0x%p size=%d", - (unsigned long) mantis->buf_dma, - mantis->buf_cpu, MANTIS_BUF_SIZE); - } - if (!mantis->risc_cpu) { - mantis->risc_cpu = pci_alloc_consistent(mantis->pdev, - MANTIS_RISC_SIZE, - &mantis->risc_dma); - - if (!mantis->risc_cpu) { - dprintk(MANTIS_ERROR, 1, - "RISC program allocation failed"); - - mantis_dma_exit(mantis); - - goto err; - } - dprintk(MANTIS_ERROR, 1, - "RISC=0x%lx cpu=0x%p size=%lx", - (unsigned long) mantis->risc_dma, - mantis->risc_cpu, MANTIS_RISC_SIZE); - } - - return 0; -err: - dprintk(MANTIS_ERROR, 1, "Out of memory (?) ....."); - return -ENOMEM; -} - -static inline int mantis_calc_lines(struct mantis_pci *mantis) -{ - mantis->line_bytes = MANTIS_BLOCK_BYTES; - mantis->line_count = MANTIS_BLOCK_COUNT; - - while (mantis->line_bytes > 4095) { - mantis->line_bytes >>= 1; - mantis->line_count <<= 1; - } - - dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]", - MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count); - - if (mantis->line_count > 255) { - dprintk(MANTIS_ERROR, 1, "Buffer size error"); - return -EINVAL; - } - - return 0; -} - -int mantis_dma_init(struct mantis_pci *mantis) -{ - int err = 0; - - dprintk(MANTIS_DEBUG, 1, "Mantis DMA init"); - if (mantis_alloc_buffers(mantis) < 0) { - dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer"); - - /* Stop RISC Engine */ - mmwrite(0, MANTIS_DMA_CTL); - - goto err; - } - err = mantis_calc_lines(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed"); - - goto err; - } - - return 0; -err: - return err; -} -EXPORT_SYMBOL_GPL(mantis_dma_init); - -static inline void mantis_risc_program(struct mantis_pci *mantis) -{ - u32 buf_pos = 0; - u32 line; - - dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program"); - RISC_FLUSH(); - - dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u", - mantis->line_count, mantis->line_bytes); - - for (line = 0; line < mantis->line_count; line++) { - dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line); - if (!(buf_pos % MANTIS_BLOCK_BYTES)) { - RISC_INSTR(RISC_WRITE | - RISC_IRQ | - RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) + - (MANTIS_BLOCK_COUNT - 1)) % - MANTIS_BLOCK_COUNT) | - mantis->line_bytes); - } else { - RISC_INSTR(RISC_WRITE | mantis->line_bytes); - } - RISC_INSTR(mantis->buf_dma + buf_pos); - buf_pos += mantis->line_bytes; - } - RISC_INSTR(RISC_JUMP); - RISC_INSTR(mantis->risc_dma); -} - -void mantis_dma_start(struct mantis_pci *mantis) -{ - dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine"); - - mantis_risc_program(mantis); - mmwrite(mantis->risc_dma, MANTIS_RISC_START); - mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); - - mmwrite(0, MANTIS_DMA_CTL); - mantis->last_block = mantis->finished_block = 0; - - mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); - - mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN - | MANTIS_RISC_EN, MANTIS_DMA_CTL); - -} - -void mantis_dma_stop(struct mantis_pci *mantis) -{ - u32 stat = 0, mask = 0; - - stat = mmread(MANTIS_INT_STAT); - mask = mmread(MANTIS_INT_MASK); - dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine"); - - mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR); - - mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN | - MANTIS_DCAP_EN | - MANTIS_RISC_EN)), MANTIS_DMA_CTL); - - mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); - - mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI | - MANTIS_INT_RISCEN), MANTIS_INT_MASK); -} - - -void mantis_dma_xfer(unsigned long data) -{ - struct mantis_pci *mantis = (struct mantis_pci *) data; - struct mantis_hwconfig *config = mantis->hwconfig; - - while (mantis->last_block != mantis->finished_block) { - dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]", - mantis->last_block, mantis->finished_block); - - (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) - (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); - mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT; - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dma.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dma.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dma.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dma.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_DMA_H -#define __MANTIS_DMA_H - -extern int mantis_dma_init(struct mantis_pci *mantis); -extern int mantis_dma_exit(struct mantis_pci *mantis); -extern void mantis_dma_start(struct mantis_pci *mantis); -extern void mantis_dma_stop(struct mantis_pci *mantis); -extern void mantis_dma_xfer(unsigned long data); - -#endif /* __MANTIS_DMA_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dvb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,299 +0,0 @@ -/* - Mantis PCI bridge driver - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include - -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_dma.h" -#include "mantis_ca.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - - switch (power) { - case POWER_ON: - dprintk(MANTIS_DEBUG, 1, "Power ON"); - mantis_gpio_set_bits(mantis, config->power, POWER_ON); - msleep(100); - mantis_gpio_set_bits(mantis, config->power, POWER_ON); - msleep(100); - break; - - case POWER_OFF: - dprintk(MANTIS_DEBUG, 1, "Power OFF"); - mantis_gpio_set_bits(mantis, config->power, POWER_OFF); - msleep(100); - break; - - default: - dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power); - return -1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_frontend_power); - -void mantis_frontend_soft_reset(struct mantis_pci *mantis) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - - dprintk(MANTIS_DEBUG, 1, "Frontend RESET"); - mantis_gpio_set_bits(mantis, config->reset, 0); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 0); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 1); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 1); - msleep(100); - - return; -} -EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset); - -static int mantis_frontend_shutdown(struct mantis_pci *mantis) -{ - int err; - - mantis_frontend_soft_reset(mantis); - err = mantis_frontend_power(mantis, POWER_OFF); - if (err != 0) { - dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err); - return 1; - } - - return 0; -} - -static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct mantis_pci *mantis = dvbdmx->priv; - - dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed"); - if (!dvbdmx->dmx.frontend) { - dprintk(MANTIS_DEBUG, 1, "no frontend ?"); - return -EINVAL; - } - - mantis->feeds++; - dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds); - - if (mantis->feeds == 1) { - dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); - mantis_dma_start(mantis); - tasklet_enable(&mantis->tasklet); - } - - return mantis->feeds; -} - -static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct mantis_pci *mantis = dvbdmx->priv; - - dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed"); - if (!dvbdmx->dmx.frontend) { - dprintk(MANTIS_DEBUG, 1, "no frontend ?"); - return -EINVAL; - } - - mantis->feeds--; - if (mantis->feeds == 0) { - dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); - tasklet_disable(&mantis->tasklet); - mantis_dma_stop(mantis); - } - - return 0; -} - -int __devinit mantis_dvb_init(struct mantis_pci *mantis) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - int result = -1; - - dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter"); - - result = dvb_register_adapter(&mantis->dvb_adapter, - "Mantis DVB adapter", - THIS_MODULE, - &mantis->pdev->dev, - adapter_nr); - - if (result < 0) { - - dprintk(MANTIS_ERROR, 1, "Error registering adapter"); - return -ENODEV; - } - - mantis->dvb_adapter.priv = mantis; - mantis->demux.dmx.capabilities = DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - - mantis->demux.priv = mantis; - mantis->demux.filternum = 256; - mantis->demux.feednum = 256; - mantis->demux.start_feed = mantis_dvb_start_feed; - mantis->demux.stop_feed = mantis_dvb_stop_feed; - mantis->demux.write_to_decoder = NULL; - - dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init"); - result = dvb_dmx_init(&mantis->demux); - if (result < 0) { - dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); - - goto err0; - } - - mantis->dmxdev.filternum = 256; - mantis->dmxdev.demux = &mantis->demux.dmx; - mantis->dmxdev.capabilities = 0; - dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init"); - - result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter); - if (result < 0) { - - dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result); - goto err1; - } - - mantis->fe_hw.source = DMX_FRONTEND_0; - result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw); - if (result < 0) { - - dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); - goto err2; - } - - mantis->fe_mem.source = DMX_MEMORY_FE; - result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem); - if (result < 0) { - dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); - goto err3; - } - - result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw); - if (result < 0) { - dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); - goto err4; - } - - dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); - tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis); - tasklet_disable(&mantis->tasklet); - if (mantis->hwconfig) { - result = config->frontend_init(mantis, mantis->fe); - if (result < 0) { - dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!"); - goto err5; - } else { - if (mantis->fe == NULL) { - dprintk(MANTIS_ERROR, 1, "FE "); - goto err5; - } - - if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) { - dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed"); - - if (mantis->fe->ops.release) - mantis->fe->ops.release(mantis->fe); - - mantis->fe = NULL; - goto err5; - } - } - } - - return 0; - - /* Error conditions .. */ -err5: - tasklet_kill(&mantis->tasklet); - dvb_net_release(&mantis->dvbnet); - dvb_unregister_frontend(mantis->fe); - dvb_frontend_detach(mantis->fe); -err4: - mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); - -err3: - mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); - -err2: - dvb_dmxdev_release(&mantis->dmxdev); - -err1: - dvb_dmx_release(&mantis->demux); - -err0: - dvb_unregister_adapter(&mantis->dvb_adapter); - - return result; -} -EXPORT_SYMBOL_GPL(mantis_dvb_init); - -int __devexit mantis_dvb_exit(struct mantis_pci *mantis) -{ - int err; - - if (mantis->fe) { - /* mantis_ca_exit(mantis); */ - err = mantis_frontend_shutdown(mantis); - if (err != 0) - dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err); - dvb_unregister_frontend(mantis->fe); - dvb_frontend_detach(mantis->fe); - } - - tasklet_kill(&mantis->tasklet); - dvb_net_release(&mantis->dvbnet); - - mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); - mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); - - dvb_dmxdev_release(&mantis->dmxdev); - dvb_dmx_release(&mantis->demux); - - dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter"); - dvb_unregister_adapter(&mantis->dvb_adapter); - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_dvb_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dvb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dvb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dvb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_dvb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_DVB_H -#define __MANTIS_DVB_H - -enum mantis_power { - POWER_OFF = 0, - POWER_ON = 1 -}; - -extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power); -extern void mantis_frontend_soft_reset(struct mantis_pci *mantis); - -extern int mantis_dvb_init(struct mantis_pci *mantis); -extern int mantis_dvb_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_DVB_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_evm.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_evm.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_evm.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_evm.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_link.h" -#include "mantis_hif.h" -#include "mantis_reg.h" - -static void mantis_hifevm_work(struct work_struct *work) -{ - struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work); - struct mantis_pci *mantis = ca->ca_priv; - - u32 gpif_stat, gpif_mask; - - gpif_stat = mmread(MANTIS_GPIF_STATUS); - gpif_mask = mmread(MANTIS_GPIF_IRQCFG); - - if (gpif_stat & MANTIS_GPIF_DETSTAT) { - if (gpif_stat & MANTIS_CARD_PLUGIN) { - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num); - mmwrite(0xdada0000, MANTIS_CARD_RESET); - mantis_event_cam_plugin(ca); - dvb_ca_en50221_camchange_irq(&ca->en50221, - 0, - DVB_CA_EN50221_CAMCHANGE_INSERTED); - } - } else { - if (gpif_stat & MANTIS_CARD_PLUGOUT) { - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num); - mmwrite(0xdada0000, MANTIS_CARD_RESET); - mantis_event_cam_unplug(ca); - dvb_ca_en50221_camchange_irq(&ca->en50221, - 0, - DVB_CA_EN50221_CAMCHANGE_REMOVED); - } - } - - if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num); - - if (mantis->gpif_status & MANTIS_SBUF_WSTO) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num); - - if (mantis->gpif_status & MANTIS_GPIF_OTHERR) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num); - - if (gpif_stat & MANTIS_SBUF_OVFLW) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num); - - if (gpif_stat & MANTIS_GPIF_BRRDY) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num); - - if (gpif_stat & MANTIS_GPIF_INTSTAT) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num); - - if (gpif_stat & MANTIS_SBUF_EMPTY) - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num); - - if (gpif_stat & MANTIS_SBUF_OPDONE) { - dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num); - ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL; - ca->hif_event = MANTIS_SBUF_OPDONE; - wake_up(&ca->hif_opdone_wq); - } -} - -int mantis_evmgr_init(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager"); - INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work); - mantis_pcmcia_init(ca); - schedule_work(&ca->hif_evm_work); - mantis_hif_init(ca); - return 0; -} - -void mantis_evmgr_exit(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting"); - flush_work_sync(&ca->hif_evm_work); - mantis_hif_exit(ca); - mantis_pcmcia_exit(ca); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_hif.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_hif.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_hif.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_hif.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,238 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" - -#include "mantis_hif.h" -#include "mantis_link.h" /* temporary due to physical layer stuff */ - -#include "mantis_reg.h" - - -static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - int rc = 0; - - if (wait_event_timeout(ca->hif_opdone_wq, - ca->hif_event & MANTIS_SBUF_OPDONE, - msecs_to_jiffies(500)) == -ERESTARTSYS) { - - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num); - rc = -EREMOTEIO; - } - dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete"); - ca->hif_event &= ~MANTIS_SBUF_OPDONE; - return rc; -} - -static int mantis_hif_write_wait(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 opdone = 0, timeout = 0; - int rc = 0; - - if (wait_event_timeout(ca->hif_write_wq, - mantis->gpif_status & MANTIS_GPIF_WRACK, - msecs_to_jiffies(500)) == -ERESTARTSYS) { - - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num); - rc = -EREMOTEIO; - } - dprintk(MANTIS_DEBUG, 1, "Write Acknowledged"); - mantis->gpif_status &= ~MANTIS_GPIF_WRACK; - while (!opdone) { - opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE); - udelay(500); - timeout++; - if (timeout > 100) { - dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num); - rc = -ETIMEDOUT; - break; - } - } - dprintk(MANTIS_DEBUG, 1, "HIF Write success"); - return rc; -} - - -int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 hif_addr = 0, data, count = 4; - - dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num); - mutex_lock(&ca->ca_lock); - hif_addr &= ~MANTIS_GPIF_PCMCIAREG; - hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; - hif_addr |= MANTIS_HIF_STATUS; - hif_addr |= addr; - - mmwrite(hif_addr, MANTIS_GPIF_BRADDR); - mmwrite(count, MANTIS_GPIF_BRBYTES); - udelay(20); - mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); - - if (mantis_hif_sbuf_opdone_wait(ca) != 0) { - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num); - mutex_unlock(&ca->ca_lock); - return -EREMOTEIO; - } - data = mmread(MANTIS_GPIF_DIN); - mutex_unlock(&ca->ca_lock); - dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data); - return (data >> 24) & 0xff; -} - -int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data) -{ - struct mantis_slot *slot = ca->slot; - struct mantis_pci *mantis = ca->ca_priv; - u32 hif_addr = 0; - - dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num); - mutex_lock(&ca->ca_lock); - hif_addr &= ~MANTIS_GPIF_HIFRDWRN; - hif_addr &= ~MANTIS_GPIF_PCMCIAREG; - hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; - hif_addr |= MANTIS_HIF_STATUS; - hif_addr |= addr; - - mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */ - mmwrite(hif_addr, MANTIS_GPIF_ADDR); - mmwrite(data, MANTIS_GPIF_DOUT); - - if (mantis_hif_write_wait(ca) != 0) { - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); - mutex_unlock(&ca->ca_lock); - return -EREMOTEIO; - } - dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr); - mutex_unlock(&ca->ca_lock); - - return 0; -} - -int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 data, hif_addr = 0; - - dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num); - mutex_lock(&ca->ca_lock); - hif_addr &= ~MANTIS_GPIF_PCMCIAREG; - hif_addr |= MANTIS_GPIF_PCMCIAIOM; - hif_addr |= MANTIS_HIF_STATUS; - hif_addr |= addr; - - mmwrite(hif_addr, MANTIS_GPIF_BRADDR); - mmwrite(1, MANTIS_GPIF_BRBYTES); - udelay(20); - mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); - - if (mantis_hif_sbuf_opdone_wait(ca) != 0) { - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); - mutex_unlock(&ca->ca_lock); - return -EREMOTEIO; - } - data = mmread(MANTIS_GPIF_DIN); - dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data); - udelay(50); - mutex_unlock(&ca->ca_lock); - - return (u8) data; -} - -int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 hif_addr = 0; - - dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num); - mutex_lock(&ca->ca_lock); - hif_addr &= ~MANTIS_GPIF_PCMCIAREG; - hif_addr &= ~MANTIS_GPIF_HIFRDWRN; - hif_addr |= MANTIS_GPIF_PCMCIAIOM; - hif_addr |= MANTIS_HIF_STATUS; - hif_addr |= addr; - - mmwrite(hif_addr, MANTIS_GPIF_ADDR); - mmwrite(data, MANTIS_GPIF_DOUT); - - if (mantis_hif_write_wait(ca) != 0) { - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); - mutex_unlock(&ca->ca_lock); - return -EREMOTEIO; - } - dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr); - mutex_unlock(&ca->ca_lock); - udelay(50); - - return 0; -} - -int mantis_hif_init(struct mantis_ca *ca) -{ - struct mantis_slot *slot = ca->slot; - struct mantis_pci *mantis = ca->ca_priv; - u32 irqcfg; - - slot[0].slave_cfg = 0x70773028; - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num); - - mutex_lock(&ca->ca_lock); - irqcfg = mmread(MANTIS_GPIF_IRQCFG); - irqcfg = MANTIS_MASK_BRRDY | - MANTIS_MASK_WRACK | - MANTIS_MASK_EXTIRQ | - MANTIS_MASK_WSTO | - MANTIS_MASK_OTHERR | - MANTIS_MASK_OVFLW; - - mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); - mutex_unlock(&ca->ca_lock); - - return 0; -} - -void mantis_hif_exit(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - u32 irqcfg; - - dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num); - mutex_lock(&ca->ca_lock); - irqcfg = mmread(MANTIS_GPIF_IRQCFG); - irqcfg &= ~MANTIS_MASK_BRRDY; - mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); - mutex_unlock(&ca->ca_lock); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_hif.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_hif.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_hif.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_hif.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_HIF_H -#define __MANTIS_HIF_H - -#define MANTIS_HIF_MEMRD 1 -#define MANTIS_HIF_MEMWR 2 -#define MANTIS_HIF_IOMRD 3 -#define MANTIS_HIF_IOMWR 4 - -#endif /* __MANTIS_HIF_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_i2c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,266 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_i2c.h" - -#define TRIALS 10000 - -static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg) -{ - u32 rxd, i, stat, trials; - - dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] [ ", - __func__, msg->addr); - - for (i = 0; i < msg->len; i++) { - rxd = (msg->addr << 25) | (1 << 24) - | MANTIS_I2C_RATE_3 - | MANTIS_I2C_STOP - | MANTIS_I2C_PGMODE; - - if (i == (msg->len - 1)) - rxd &= ~MANTIS_I2C_STOP; - - mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); - mmwrite(rxd, MANTIS_I2CDATA_CTL); - - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CDONE) - break; - } - - dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); - - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CRACK) - break; - } - - dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); - - rxd = mmread(MANTIS_I2CDATA_CTL); - msg->buf[i] = (u8)((rxd >> 8) & 0xFF); - dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); - } - dprintk(MANTIS_INFO, 0, "]\n"); - - return 0; -} - -static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg) -{ - int i; - u32 txd = 0, stat, trials; - - dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] [ ", - __func__, msg->addr); - - for (i = 0; i < msg->len; i++) { - dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); - txd = (msg->addr << 25) | (msg->buf[i] << 8) - | MANTIS_I2C_RATE_3 - | MANTIS_I2C_STOP - | MANTIS_I2C_PGMODE; - - if (i == (msg->len - 1)) - txd &= ~MANTIS_I2C_STOP; - - mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); - mmwrite(txd, MANTIS_I2CDATA_CTL); - - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CDONE) - break; - } - - dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); - - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CRACK) - break; - } - - dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); - } - dprintk(MANTIS_INFO, 0, "]\n"); - - return 0; -} - -static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) -{ - int ret = 0, i = 0, trials; - u32 stat, data, txd; - struct mantis_pci *mantis; - struct mantis_hwconfig *config; - - mantis = i2c_get_adapdata(adapter); - BUG_ON(!mantis); - config = mantis->hwconfig; - BUG_ON(!config); - - dprintk(MANTIS_DEBUG, 1, "Messages:%d", num); - mutex_lock(&mantis->i2c_lock); - - while (i < num) { - /* Byte MODE */ - if ((config->i2c_mode & MANTIS_BYTE_MODE) && - ((i + 1) < num) && - (msgs[i].len < 2) && - (msgs[i + 1].len < 2) && - (msgs[i + 1].flags & I2C_M_RD)) { - - dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n"); - - /* Read operation */ - txd = msgs[i].addr << 25 | (0x1 << 24) - | (msgs[i].buf[0] << 16) - | MANTIS_I2C_RATE_3; - - mmwrite(txd, MANTIS_I2CDATA_CTL); - /* wait for xfer completion */ - for (trials = 0; trials < TRIALS; trials++) { - stat = mmread(MANTIS_INT_STAT); - if (stat & MANTIS_INT_I2CDONE) - break; - } - - /* check for xfer completion */ - if (stat & MANTIS_INT_I2CDONE) { - /* check xfer was acknowledged */ - if (stat & MANTIS_INT_I2CRACK) { - data = mmread(MANTIS_I2CDATA_CTL); - msgs[i + 1].buf[0] = (data >> 8) & 0xff; - dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]); - } else { - /* I/O error */ - dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); - ret = -EIO; - break; - } - } else { - /* I/O error */ - dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); - ret = -EIO; - break; - } - i += 2; /* Write/Read operation in one go */ - } - - if (i < num) { - if (msgs[i].flags & I2C_M_RD) - ret = mantis_i2c_read(mantis, &msgs[i]); - else - ret = mantis_i2c_write(mantis, &msgs[i]); - - i++; - if (ret < 0) - goto bail_out; - } - - } - - mutex_unlock(&mantis->i2c_lock); - - return num; - -bail_out: - mutex_unlock(&mantis->i2c_lock); - return ret; -} - -static u32 mantis_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm mantis_algo = { - .master_xfer = mantis_i2c_xfer, - .functionality = mantis_i2c_func, -}; - -int __devinit mantis_i2c_init(struct mantis_pci *mantis) -{ - u32 intstat, intmask; - struct i2c_adapter *i2c_adapter = &mantis->adapter; - struct pci_dev *pdev = mantis->pdev; - - init_waitqueue_head(&mantis->i2c_wq); - mutex_init(&mantis->i2c_lock); - strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); - i2c_set_adapdata(i2c_adapter, mantis); - - i2c_adapter->owner = THIS_MODULE; - i2c_adapter->algo = &mantis_algo; - i2c_adapter->algo_data = NULL; - i2c_adapter->timeout = 500; - i2c_adapter->retries = 3; - i2c_adapter->dev.parent = &pdev->dev; - - mantis->i2c_rc = i2c_add_adapter(i2c_adapter); - if (mantis->i2c_rc < 0) - return mantis->i2c_rc; - - dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); - - intstat = mmread(MANTIS_INT_STAT); - intmask = mmread(MANTIS_INT_MASK); - mmwrite(intstat, MANTIS_INT_STAT); - dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); - intmask = mmread(MANTIS_INT_MASK); - mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_i2c_init); - -int mantis_i2c_exit(struct mantis_pci *mantis) -{ - u32 intmask; - - dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); - intmask = mmread(MANTIS_INT_MASK); - mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); - - dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); - return i2c_del_adapter(&mantis->adapter); -} -EXPORT_SYMBOL_GPL(mantis_i2c_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_i2c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_i2c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_I2C_H -#define __MANTIS_I2C_H - -#define I2C_STOP (1 << 0) -#define I2C_READ (1 << 1) - -extern int mantis_i2c_init(struct mantis_pci *mantis); -extern int mantis_i2c_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_I2C_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_input.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_input.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_uart.h" - -#define MODULE_NAME "mantis_core" -#define RC_MAP_MANTIS "rc-mantis" - -static struct rc_map_table mantis_ir_table[] = { - { 0x29, KEY_POWER }, - { 0x28, KEY_FAVORITES }, - { 0x30, KEY_TEXT }, - { 0x17, KEY_INFO }, /* Preview */ - { 0x23, KEY_EPG }, - { 0x3b, KEY_F22 }, /* Record List */ - { 0x3c, KEY_1 }, - { 0x3e, KEY_2 }, - { 0x39, KEY_3 }, - { 0x36, KEY_4 }, - { 0x22, KEY_5 }, - { 0x20, KEY_6 }, - { 0x32, KEY_7 }, - { 0x26, KEY_8 }, - { 0x24, KEY_9 }, - { 0x2a, KEY_0 }, - - { 0x33, KEY_CANCEL }, - { 0x2c, KEY_BACK }, - { 0x15, KEY_CLEAR }, - { 0x3f, KEY_TAB }, - { 0x10, KEY_ENTER }, - { 0x14, KEY_UP }, - { 0x0d, KEY_RIGHT }, - { 0x0e, KEY_DOWN }, - { 0x11, KEY_LEFT }, - - { 0x21, KEY_VOLUMEUP }, - { 0x35, KEY_VOLUMEDOWN }, - { 0x3d, KEY_CHANNELDOWN }, - { 0x3a, KEY_CHANNELUP }, - { 0x2e, KEY_RECORD }, - { 0x2b, KEY_PLAY }, - { 0x13, KEY_PAUSE }, - { 0x25, KEY_STOP }, - - { 0x1f, KEY_REWIND }, - { 0x2d, KEY_FASTFORWARD }, - { 0x1e, KEY_PREVIOUS }, /* Replay |< */ - { 0x1d, KEY_NEXT }, /* Skip >| */ - - { 0x0b, KEY_CAMERA }, /* Capture */ - { 0x0f, KEY_LANGUAGE }, /* SAP */ - { 0x18, KEY_MODE }, /* PIP */ - { 0x12, KEY_ZOOM }, /* Full screen */ - { 0x1c, KEY_SUBTITLE }, - { 0x2f, KEY_MUTE }, - { 0x16, KEY_F20 }, /* L/R */ - { 0x38, KEY_F21 }, /* Hibernate */ - - { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */ - { 0x31, KEY_AGAIN }, /* Recall */ - { 0x1a, KEY_KPPLUS }, /* Zoom+ */ - { 0x19, KEY_KPMINUS }, /* Zoom- */ - { 0x27, KEY_RED }, - { 0x0C, KEY_GREEN }, - { 0x01, KEY_YELLOW }, - { 0x00, KEY_BLUE }, -}; - -static struct rc_map_list ir_mantis_map = { - .map = { - .scan = mantis_ir_table, - .size = ARRAY_SIZE(mantis_ir_table), - .rc_type = RC_TYPE_UNKNOWN, - .name = RC_MAP_MANTIS, - } -}; - -int mantis_input_init(struct mantis_pci *mantis) -{ - struct rc_dev *dev; - int err; - - err = rc_map_register(&ir_mantis_map); - if (err) - goto out; - - dev = rc_allocate_device(); - if (!dev) { - dprintk(MANTIS_ERROR, 1, "Remote device allocation failed"); - err = -ENOMEM; - goto out_map; - } - - sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name); - sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev)); - - dev->input_name = mantis->input_name; - dev->input_phys = mantis->input_phys; - dev->input_id.bustype = BUS_PCI; - dev->input_id.vendor = mantis->vendor_id; - dev->input_id.product = mantis->device_id; - dev->input_id.version = 1; - dev->driver_name = MODULE_NAME; - dev->map_name = RC_MAP_MANTIS; - dev->dev.parent = &mantis->pdev->dev; - - err = rc_register_device(dev); - if (err) { - dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err); - goto out_dev; - } - - mantis->rc = dev; - return 0; - -out_dev: - rc_free_device(dev); -out_map: - rc_map_unregister(&ir_mantis_map); -out: - return err; -} - -int mantis_exit(struct mantis_pci *mantis) -{ - rc_unregister_device(mantis->rc); - rc_map_unregister(&ir_mantis_map); - return 0; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ioc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ioc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ioc.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ioc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_ioc.h" - -static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length) -{ - struct i2c_adapter *adapter = &mantis->adapter; - int err; - u8 buf = reg; - - struct i2c_msg msg[] = { - { .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 }, - { .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length }, - }; - - err = i2c_transfer(adapter, msg, 2); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", - err, data[0], data[1]); - - return err; - } - - return 0; -} -int mantis_get_mac(struct mantis_pci *mantis) -{ - int err; - u8 mac_addr[6] = {0}; - - err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err); - - return err; - } - - dprintk(MANTIS_ERROR, 0, " MAC Address=[%pM]\n", mac_addr); - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_get_mac); - -/* Turn the given bit on or off. */ -void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) -{ - u32 cur; - - dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value); - cur = mmread(MANTIS_GPIF_ADDR); - if (value) - mantis->gpio_status = cur | (1 << bitpos); - else - mantis->gpio_status = cur & (~(1 << bitpos)); - - dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status); - mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); - mmwrite(0x00, MANTIS_GPIF_DOUT); -} -EXPORT_SYMBOL_GPL(mantis_gpio_set_bits); - -int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl) -{ - u32 reg; - - reg = mmread(MANTIS_CONTROL); - switch (stream_ctl) { - case STREAM_TO_HIF: - dprintk(MANTIS_DEBUG, 1, "Set stream to HIF"); - reg &= 0xff - MANTIS_BYPASS; - mmwrite(reg, MANTIS_CONTROL); - reg |= MANTIS_BYPASS; - mmwrite(reg, MANTIS_CONTROL); - break; - - case STREAM_TO_CAM: - dprintk(MANTIS_DEBUG, 1, "Set stream to CAM"); - reg |= MANTIS_BYPASS; - mmwrite(reg, MANTIS_CONTROL); - reg &= 0xff - MANTIS_BYPASS; - mmwrite(reg, MANTIS_CONTROL); - break; - default: - dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl); - return -1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_stream_control); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ioc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ioc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ioc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_ioc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_IOC_H -#define __MANTIS_IOC_H - -#define GPIF_A00 0x00 -#define GPIF_A01 0x01 -#define GPIF_A02 0x02 -#define GPIF_A03 0x03 -#define GPIF_A04 0x04 -#define GPIF_A05 0x05 -#define GPIF_A06 0x06 -#define GPIF_A07 0x07 -#define GPIF_A08 0x08 -#define GPIF_A09 0x09 -#define GPIF_A10 0x0a -#define GPIF_A11 0x0b - -#define GPIF_A12 0x0c -#define GPIF_A13 0x0d -#define GPIF_A14 0x0e - -enum mantis_stream_control { - STREAM_TO_HIF = 0, - STREAM_TO_CAM -}; - -extern int mantis_get_mac(struct mantis_pci *mantis); -extern void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value); - -extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl); - -#endif /* __MANTIS_IOC_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_link.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_link.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_link.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_link.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_LINK_H -#define __MANTIS_LINK_H - -#include -#include -#include "dvb_ca_en50221.h" - -enum mantis_sbuf_status { - MANTIS_SBUF_DATA_AVAIL = 1, - MANTIS_SBUF_DATA_EMPTY = 2, - MANTIS_SBUF_DATA_OVFLW = 3 -}; - -struct mantis_slot { - u32 timeout; - u32 slave_cfg; - u32 bar; -}; - -/* Physical layer */ -enum mantis_slot_state { - MODULE_INSERTED = 3, - MODULE_XTRACTED = 4 -}; - -struct mantis_ca { - struct mantis_slot slot[4]; - - struct work_struct hif_evm_work; - - u32 hif_event; - wait_queue_head_t hif_opdone_wq; - wait_queue_head_t hif_brrdyw_wq; - wait_queue_head_t hif_data_wq; - wait_queue_head_t hif_write_wq; /* HIF Write op */ - - enum mantis_sbuf_status sbuf_status; - - enum mantis_slot_state slot_state; - - void *ca_priv; - - struct dvb_ca_en50221 en50221; - struct mutex ca_lock; -}; - -/* CA */ -extern void mantis_event_cam_plugin(struct mantis_ca *ca); -extern void mantis_event_cam_unplug(struct mantis_ca *ca); -extern int mantis_pcmcia_init(struct mantis_ca *ca); -extern void mantis_pcmcia_exit(struct mantis_ca *ca); -extern int mantis_evmgr_init(struct mantis_ca *ca); -extern void mantis_evmgr_exit(struct mantis_ca *ca); - -/* HIF */ -extern int mantis_hif_init(struct mantis_ca *ca); -extern void mantis_hif_exit(struct mantis_ca *ca); -extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr); -extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data); -extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr); -extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data); - -#endif /* __MANTIS_LINK_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pci.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pci.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,171 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_pci.h" - -#define DRIVER_NAME "Mantis Core" - -int __devinit mantis_pci_init(struct mantis_pci *mantis) -{ - u8 revision, latency; - struct mantis_hwconfig *config = mantis->hwconfig; - struct pci_dev *pdev = mantis->pdev; - int err, ret = 0; - - dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", - config->model_name, - config->dev_type, - mantis->pdev->bus->number, - PCI_SLOT(mantis->pdev->devfn), - PCI_FUNC(mantis->pdev->devfn)); - - err = pci_enable_device(pdev); - if (err != 0) { - ret = -ENODEV; - dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err); - goto fail0; - } - - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err != 0) { - dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err); - ret = -ENOMEM; - goto fail1; - } - - pci_set_master(pdev); - - if (!request_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0), - DRIVER_NAME)) { - - dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !"); - ret = -ENODEV; - goto fail1; - } - - mantis->mmio = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - - if (!mantis->mmio) { - dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !"); - ret = -ENODEV; - goto fail2; - } - - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency); - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - mantis->latency = latency; - mantis->revision = revision; - - dprintk(MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", - mantis->revision, - mantis->pdev->subsystem_vendor, - mantis->pdev->subsystem_device); - - dprintk(MANTIS_ERROR, 0, - "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", - mantis->pdev->irq, - mantis->latency, - mantis->mantis_addr, - mantis->mmio); - - err = request_irq(pdev->irq, - config->irq_handler, - IRQF_SHARED, - DRIVER_NAME, - mantis); - - if (err != 0) { - - dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err); - ret = -ENODEV; - goto fail3; - } - - pci_set_drvdata(pdev, mantis); - return ret; - - /* Error conditions */ -fail3: - dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret); - if (mantis->mmio) - iounmap(mantis->mmio); - -fail2: - dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret); - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - -fail1: - dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret); - pci_disable_device(pdev); - -fail0: - dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret); - pci_set_drvdata(pdev, NULL); - return ret; -} -EXPORT_SYMBOL_GPL(mantis_pci_init); - -void mantis_pci_exit(struct mantis_pci *mantis) -{ - struct pci_dev *pdev = mantis->pdev; - - dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio); - free_irq(pdev->irq, mantis); - if (mantis->mmio) { - iounmap(mantis->mmio); - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - } - - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} -EXPORT_SYMBOL_GPL(mantis_pci_exit); - -MODULE_DESCRIPTION("Mantis PCI DTV bridge driver"); -MODULE_AUTHOR("Manu Abraham"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pci.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pci.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pci.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pci.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_PCI_H -#define __MANTIS_PCI_H - -extern int mantis_pci_init(struct mantis_pci *mantis); -extern void mantis_pci_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_PCI_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pcmcia.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pcmcia.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pcmcia.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_pcmcia.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_link.h" /* temporary due to physical layer stuff */ -#include "mantis_reg.h" - -/* - * If Slot state is already PLUG_IN event and we are called - * again, definitely it is jitter alone - */ -void mantis_event_cam_plugin(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - u32 gpif_irqcfg; - - if (ca->slot_state == MODULE_XTRACTED) { - dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num); - udelay(50); - mmwrite(0xda000000, MANTIS_CARD_RESET); - gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); - gpif_irqcfg |= MANTIS_MASK_PLUGOUT; - gpif_irqcfg &= ~MANTIS_MASK_PLUGIN; - mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); - udelay(500); - ca->slot_state = MODULE_INSERTED; - } - udelay(100); -} - -/* - * If Slot state is already UN_PLUG event and we are called - * again, definitely it is jitter alone - */ -void mantis_event_cam_unplug(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - u32 gpif_irqcfg; - - if (ca->slot_state == MODULE_INSERTED) { - dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num); - udelay(50); - mmwrite(0x00da0000, MANTIS_CARD_RESET); - gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); - gpif_irqcfg |= MANTIS_MASK_PLUGIN; - gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT; - mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); - udelay(500); - ca->slot_state = MODULE_XTRACTED; - } - udelay(100); -} - -int mantis_pcmcia_init(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - u32 gpif_stat, card_stat; - - mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK); - gpif_stat = mmread(MANTIS_GPIF_STATUS); - card_stat = mmread(MANTIS_GPIF_IRQCFG); - - if (gpif_stat & MANTIS_GPIF_DETSTAT) { - dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num); - mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG); - ca->slot_state = MODULE_INSERTED; - dvb_ca_en50221_camchange_irq(&ca->en50221, - 0, - DVB_CA_EN50221_CAMCHANGE_INSERTED); - } else { - dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num); - mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG); - ca->slot_state = MODULE_XTRACTED; - dvb_ca_en50221_camchange_irq(&ca->en50221, - 0, - DVB_CA_EN50221_CAMCHANGE_REMOVED); - } - - return 0; -} - -void mantis_pcmcia_exit(struct mantis_ca *ca) -{ - struct mantis_pci *mantis = ca->ca_priv; - - mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS); - mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,197 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_REG_H -#define __MANTIS_REG_H - -/* Interrupts */ -#define MANTIS_INT_STAT 0x00 -#define MANTIS_INT_MASK 0x04 - -#define MANTIS_INT_RISCSTAT (0x0f << 28) -#define MANTIS_INT_RISCEN (0x01 << 27) -#define MANTIS_INT_I2CRACK (0x01 << 26) - -/* #define MANTIS_INT_GPIF (0xff << 12) */ - -#define MANTIS_INT_PCMCIA7 (0x01 << 19) -#define MANTIS_INT_PCMCIA6 (0x01 << 18) -#define MANTIS_INT_PCMCIA5 (0x01 << 17) -#define MANTIS_INT_PCMCIA4 (0x01 << 16) -#define MANTIS_INT_PCMCIA3 (0x01 << 15) -#define MANTIS_INT_PCMCIA2 (0x01 << 14) -#define MANTIS_INT_PCMCIA1 (0x01 << 13) -#define MANTIS_INT_PCMCIA0 (0x01 << 12) -#define MANTIS_INT_IRQ1 (0x01 << 11) -#define MANTIS_INT_IRQ0 (0x01 << 10) -#define MANTIS_INT_OCERR (0x01 << 8) -#define MANTIS_INT_PABORT (0x01 << 7) -#define MANTIS_INT_RIPERR (0x01 << 6) -#define MANTIS_INT_PPERR (0x01 << 5) -#define MANTIS_INT_FTRGT (0x01 << 3) -#define MANTIS_INT_RISCI (0x01 << 1) -#define MANTIS_INT_I2CDONE (0x01 << 0) - -/* DMA */ -#define MANTIS_DMA_CTL 0x08 -#define MANTIS_GPIF_RD (0xff << 24) -#define MANTIS_GPIF_WR (0xff << 16) -#define MANTIS_CPU_DO (0x01 << 10) -#define MANTIS_DRV_DO (0x01 << 9) -#define MANTIS_I2C_RD (0x01 << 7) -#define MANTIS_I2C_WR (0x01 << 6) -#define MANTIS_DCAP_MODE (0x01 << 5) -#define MANTIS_FIFO_TP_4 (0x00 << 3) -#define MANTIS_FIFO_TP_8 (0x01 << 3) -#define MANTIS_FIFO_TP_16 (0x02 << 3) -#define MANTIS_FIFO_EN (0x01 << 2) -#define MANTIS_DCAP_EN (0x01 << 1) -#define MANTIS_RISC_EN (0x01 << 0) - -/* DEBUG */ -#define MANTIS_DEBUGREG 0x0c -#define MANTIS_DATINV (0x0e << 7) -#define MANTIS_TOP_DEBUGSEL (0x07 << 4) -#define MANTIS_PCMCIA_DEBUGSEL (0x0f << 0) - -#define MANTIS_RISC_START 0x10 -#define MANTIS_RISC_PC 0x14 - -/* I2C */ -#define MANTIS_I2CDATA_CTL 0x18 -#define MANTIS_I2C_RATE_1 (0x00 << 6) -#define MANTIS_I2C_RATE_2 (0x01 << 6) -#define MANTIS_I2C_RATE_3 (0x02 << 6) -#define MANTIS_I2C_RATE_4 (0x03 << 6) -#define MANTIS_I2C_STOP (0x01 << 5) -#define MANTIS_I2C_PGMODE (0x01 << 3) - -/* DATA */ -#define MANTIS_CMD_DATA_R1 0x20 -#define MANTIS_CMD_DATA_3 (0xff << 24) -#define MANTIS_CMD_DATA_2 (0xff << 16) -#define MANTIS_CMD_DATA_1 (0xff << 8) -#define MANTIS_CMD_DATA_0 (0xff << 0) - -#define MANTIS_CMD_DATA_R2 0x24 -#define MANTIS_CMD_DATA_7 (0xff << 24) -#define MANTIS_CMD_DATA_6 (0xff << 16) -#define MANTIS_CMD_DATA_5 (0xff << 8) -#define MANTIS_CMD_DATA_4 (0xff << 0) - -#define MANTIS_CONTROL 0x28 -#define MANTIS_DET (0x01 << 7) -#define MANTIS_DAT_CF_EN (0x01 << 6) -#define MANTIS_ACS (0x03 << 4) -#define MANTIS_VCCEN (0x01 << 3) -#define MANTIS_BYPASS (0x01 << 2) -#define MANTIS_MRST (0x01 << 1) -#define MANTIS_CRST_INT (0x01 << 0) - -#define MANTIS_GPIF_CFGSLA 0x84 -#define MANTIS_GPIF_WAITSMPL (0x07 << 28) -#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25) -#define MANTIS_GPIF_WAITPOL (0x01 << 24) -#define MANTIS_GPIF_NCDELAY (0x07 << 20) -#define MANTIS_GPIF_RW2CSDELAY (0x07 << 16) -#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15) -#define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8) -#define MANTIS_GPIF_DEVTYPE (0x07 << 4) -#define MANTIS_GPIF_BIGENDIAN (0x01 << 3) -#define MANTIS_GPIF_FETCHCMD (0x03 << 1) -#define MANTIS_GPIF_HWORDDEV (0x01 << 0) - -#define MANTIS_GPIF_WSTOPER 0x90 -#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31) -#define MANTIS_GPIF_PARBOOTN (0x01 << 29) -#define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24) -#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23) -#define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16) -#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15) -#define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8) -#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7) -#define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0) - -#define MANTIS_GPIF_CS2RW 0x94 -#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31) -#define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24) -#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23) -#define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16) -#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15) -#define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8) -#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7) -#define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0) - -#define MANTIS_GPIF_IRQCFG 0x98 -#define MANTIS_GPIF_IRQPOL (0x01 << 8) -#define MANTIS_MASK_WRACK (0x01 << 7) -#define MANTIS_MASK_BRRDY (0x01 << 6) -#define MANTIS_MASK_OVFLW (0x01 << 5) -#define MANTIS_MASK_OTHERR (0x01 << 4) -#define MANTIS_MASK_WSTO (0x01 << 3) -#define MANTIS_MASK_EXTIRQ (0x01 << 2) -#define MANTIS_MASK_PLUGIN (0x01 << 1) -#define MANTIS_MASK_PLUGOUT (0x01 << 0) - -#define MANTIS_GPIF_STATUS 0x9c -#define MANTIS_SBUF_KILLOP (0x01 << 15) -#define MANTIS_SBUF_OPDONE (0x01 << 14) -#define MANTIS_SBUF_EMPTY (0x01 << 13) -#define MANTIS_GPIF_DETSTAT (0x01 << 9) -#define MANTIS_GPIF_INTSTAT (0x01 << 8) -#define MANTIS_GPIF_WRACK (0x01 << 7) -#define MANTIS_GPIF_BRRDY (0x01 << 6) -#define MANTIS_SBUF_OVFLW (0x01 << 5) -#define MANTIS_GPIF_OTHERR (0x01 << 4) -#define MANTIS_SBUF_WSTO (0x01 << 3) -#define MANTIS_GPIF_EXTIRQ (0x01 << 2) -#define MANTIS_CARD_PLUGIN (0x01 << 1) -#define MANTIS_CARD_PLUGOUT (0x01 << 0) - -#define MANTIS_GPIF_BRADDR 0xa0 -#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) -#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) -#define MANTIS_GPIF_BR_ADDR (0xfffffff << 0) - -#define MANTIS_GPIF_BRBYTES 0xa4 -#define MANTIS_GPIF_BRCNT (0xfff << 0) - -#define MANTIS_PCMCIA_RESET 0xa8 -#define MANTIS_PCMCIA_RSTVAL (0xff << 0) - -#define MANTIS_CARD_RESET 0xac - -#define MANTIS_GPIF_ADDR 0xb0 -#define MANTIS_GPIF_HIFRDWRN (0x01 << 31) -#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) -#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) -#define MANTIS_GPIF_HIFADDR (0xfffffff << 0) - -#define MANTIS_GPIF_DOUT 0xb4 -#define MANTIS_GPIF_HIFDOUT (0xfffffff << 0) - -#define MANTIS_GPIF_DIN 0xb8 -#define MANTIS_GPIF_HIFDIN (0xfffffff << 0) - -#define MANTIS_GPIF_SPARE 0xbc -#define MANTIS_GPIF_LOGICRD (0xffff << 16) -#define MANTIS_GPIF_LOGICRW (0xffff << 0) - -#endif /* __MANTIS_REG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_uart.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_uart.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_uart.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_uart.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_uart.h" - -struct mantis_uart_params { - enum mantis_baud baud_rate; - enum mantis_parity parity; -}; - -static struct { - char string[7]; -} rates[5] = { - { "9600" }, - { "19200" }, - { "38400" }, - { "57600" }, - { "115200" } -}; - -static struct { - char string[5]; -} parity[3] = { - { "NONE" }, - { "ODD" }, - { "EVEN" } -}; - -#define UART_MAX_BUF 16 - -int mantis_uart_read(struct mantis_pci *mantis, u8 *data) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - u32 stat = 0, i; - - /* get data */ - for (i = 0; i < (config->bytes + 1); i++) { - - stat = mmread(MANTIS_UART_STAT); - - if (stat & MANTIS_UART_RXFIFO_FULL) { - dprintk(MANTIS_ERROR, 1, "RX Fifo FULL"); - } - data[i] = mmread(MANTIS_UART_RXD) & 0x3f; - - dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f); - - if (data[i] & (1 << 7)) { - dprintk(MANTIS_ERROR, 1, "UART framing error"); - return -EINVAL; - } - if (data[i] & (1 << 6)) { - dprintk(MANTIS_ERROR, 1, "UART parity error"); - return -EINVAL; - } - } - - return 0; -} - -static void mantis_uart_work(struct work_struct *work) -{ - struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work); - struct mantis_hwconfig *config = mantis->hwconfig; - u8 buf[16]; - int i; - - mantis_uart_read(mantis, buf); - - for (i = 0; i < (config->bytes + 1); i++) - dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]); - - dprintk(MANTIS_DEBUG, 0, "\n"); -} - -static int mantis_uart_setup(struct mantis_pci *mantis, - struct mantis_uart_params *params) -{ - u32 reg; - - mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL); - - reg = mmread(MANTIS_UART_BAUD); - - switch (params->baud_rate) { - case MANTIS_BAUD_9600: - reg |= 0xd8; - break; - case MANTIS_BAUD_19200: - reg |= 0x6c; - break; - case MANTIS_BAUD_38400: - reg |= 0x36; - break; - case MANTIS_BAUD_57600: - reg |= 0x23; - break; - case MANTIS_BAUD_115200: - reg |= 0x11; - break; - default: - return -EINVAL; - } - - mmwrite(reg, MANTIS_UART_BAUD); - - return 0; -} - -int mantis_uart_init(struct mantis_pci *mantis) -{ - struct mantis_hwconfig *config = mantis->hwconfig; - struct mantis_uart_params params; - - /* default parity: */ - params.baud_rate = config->baud_rate; - params.parity = config->parity; - dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s", - rates[params.baud_rate].string, - parity[params.parity].string); - - init_waitqueue_head(&mantis->uart_wq); - spin_lock_init(&mantis->uart_lock); - - INIT_WORK(&mantis->uart_work, mantis_uart_work); - - /* disable interrupt */ - mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); - - mantis_uart_setup(mantis, ¶ms); - - /* default 1 byte */ - mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD); - - /* flush buffer */ - mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL); - - /* enable interrupt */ - mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK); - mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL); - - schedule_work(&mantis->uart_work); - dprintk(MANTIS_DEBUG, 1, "UART succesfully initialized"); - - return 0; -} -EXPORT_SYMBOL_GPL(mantis_uart_init); - -void mantis_uart_exit(struct mantis_pci *mantis) -{ - /* disable interrupt */ - mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); - flush_work_sync(&mantis->uart_work); -} -EXPORT_SYMBOL_GPL(mantis_uart_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_uart.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_uart.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_uart.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_uart.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_UART_H -#define __MANTIS_UART_H - -#define MANTIS_UART_CTL 0xe0 -#define MANTIS_UART_RXINT (1 << 4) -#define MANTIS_UART_RXFLUSH (1 << 2) - -#define MANTIS_UART_RXD 0xe8 -#define MANTIS_UART_BAUD 0xec - -#define MANTIS_UART_STAT 0xf0 -#define MANTIS_UART_RXFIFO_DATA (1 << 7) -#define MANTIS_UART_RXFIFO_EMPTY (1 << 6) -#define MANTIS_UART_RXFIFO_FULL (1 << 3) -#define MANTIS_UART_FRAME_ERR (1 << 2) -#define MANTIS_UART_PARITY_ERR (1 << 1) -#define MANTIS_UART_RXTHRESH_INT (1 << 0) - -enum mantis_baud { - MANTIS_BAUD_9600 = 0, - MANTIS_BAUD_19200, - MANTIS_BAUD_38400, - MANTIS_BAUD_57600, - MANTIS_BAUD_115200 -}; - -enum mantis_parity { - MANTIS_PARITY_NONE = 0, - MANTIS_PARITY_EVEN, - MANTIS_PARITY_ODD, -}; - -struct mantis_pci; - -extern int mantis_uart_init(struct mantis_pci *mantis); -extern void mantis_uart_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_UART_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1033.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1033.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1033.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1033.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -/* - Mantis VP-1033 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "stv0299.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp1033.h" -#include "mantis_reg.h" - -u8 lgtdqcs001f_inittab[] = { - 0x01, 0x15, - 0x02, 0x00, - 0x03, 0x00, - 0x04, 0x2a, - 0x05, 0x85, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0x00, - 0x0c, 0x01, - 0x0d, 0x81, - 0x0e, 0x44, - 0x0f, 0x94, - 0x10, 0x3c, - 0x11, 0x84, - 0x12, 0xb9, - 0x13, 0xb5, - 0x14, 0x4f, - 0x15, 0xc9, - 0x16, 0x80, - 0x17, 0x36, - 0x18, 0xfb, - 0x19, 0xcf, - 0x1a, 0xbc, - 0x1c, 0x2b, - 0x1d, 0x27, - 0x1e, 0x00, - 0x1f, 0x0b, - 0x20, 0xa1, - 0x21, 0x60, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, - 0x29, 0x28, - 0x2a, 0x14, - 0x2b, 0x0f, - 0x2c, 0x09, - 0x2d, 0x05, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x13, - 0xff, 0xff, -}; - -#define MANTIS_MODEL_NAME "VP-1033" -#define MANTIS_DEV_TYPE "DVB-S/DSS" - -int lgtdqcs001f_tuner_set(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct mantis_pci *mantis = fe->dvb->priv; - struct i2c_adapter *adapter = &mantis->adapter; - - u8 buf[4]; - u32 div; - - - struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)}; - - div = params->frequency / 250; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x83; - buf[3] = 0xc0; - - if (params->frequency < 1531000) - buf[3] |= 0x04; - else - buf[3] &= ~0x04; - if (i2c_transfer(adapter, &msg, 1) < 0) { - dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed"); - return -EIO; - } - msleep_interruptible(100); - - return 0; -} - -int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { - aclk = 0xb7; - bclk = 0x47; - } else if (srate < 3000000) { - aclk = 0xb7; - bclk = 0x4b; - } else if (srate < 7000000) { - aclk = 0xb7; - bclk = 0x4f; - } else if (srate < 14000000) { - aclk = 0xb7; - bclk = 0x53; - } else if (srate < 30000000) { - aclk = 0xb6; - bclk = 0x53; - } else if (srate < 45000000) { - aclk = 0xb4; - bclk = 0x51; - } - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, ratio & 0xf0); - - return 0; -} - -struct stv0299_config lgtdqcs001f_config = { - .demod_address = 0x68, - .inittab = lgtdqcs001f_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = lgtdqcs001f_set_symbol_rate, -}; - -static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - - dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)"); - fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter); - - if (fe) { - fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set; - dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x", - lgtdqcs001f_config.demod_address); - - dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success"); - } else { - return -1; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - mantis->fe = fe; - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp1033_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_204, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp1033_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1033.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1033.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1033.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1033.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - Mantis VP-1033 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP1033_H -#define __MANTIS_VP1033_H - -#include "mantis_common.h" - -#define MANTIS_VP_1033_DVB_S 0x0016 - -extern struct mantis_hwconfig vp1033_config; - -#endif /* __MANTIS_VP1033_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1034.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1034.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1034.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1034.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,119 +0,0 @@ -/* - Mantis VP-1034 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mb86a16.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp1034.h" -#include "mantis_reg.h" - -struct mb86a16_config vp1034_mb86a16_config = { - .demod_address = 0x08, - .set_voltage = vp1034_set_voltage, -}; - -#define MANTIS_MODEL_NAME "VP-1034" -#define MANTIS_DEV_TYPE "DVB-S/DSS" - -int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct mantis_pci *mantis = fe->dvb->priv; - - switch (voltage) { - case SEC_VOLTAGE_13: - dprintk(MANTIS_ERROR, 1, "Polarization=[13V]"); - mantis_gpio_set_bits(mantis, 13, 1); - mantis_gpio_set_bits(mantis, 14, 0); - break; - case SEC_VOLTAGE_18: - dprintk(MANTIS_ERROR, 1, "Polarization=[18V]"); - mantis_gpio_set_bits(mantis, 13, 1); - mantis_gpio_set_bits(mantis, 14, 1); - break; - case SEC_VOLTAGE_OFF: - dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN"); - break; - default: - dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage); - return -EINVAL; - } - mmwrite(0x00, MANTIS_GPIF_DOUT); - - return 0; -} - -static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - - dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)"); - fe = dvb_attach(mb86a16_attach, &vp1034_mb86a16_config, adapter); - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found MB86A16 DVB-S/DSS frontend @0x%02x", - vp1034_mb86a16_config.demod_address); - - } else { - return -1; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - mantis->fe = fe; - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp1034_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_204, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp1034_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1034.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1034.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1034.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1034.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - Mantis VP-1034 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP1034_H -#define __MANTIS_VP1034_H - -#include "dvb_frontend.h" -#include "mantis_common.h" - - -#define MANTIS_VP_1034_DVB_S 0x0014 - -extern struct mantis_hwconfig vp1034_config; -extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); - -#endif /* __MANTIS_VP1034_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1041.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1041.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1041.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1041.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,358 +0,0 @@ -/* - Mantis VP-1041 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp1041.h" -#include "stb0899_reg.h" -#include "stb0899_drv.h" -#include "stb0899_cfg.h" -#include "stb6100_cfg.h" -#include "stb6100.h" -#include "lnbp21.h" - -#define MANTIS_MODEL_NAME "VP-1041" -#define MANTIS_DEV_TYPE "DSS/DVB-S/DVB-S2" - -static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = { - - /* 0x0000000b, *//* SYSREG */ - { STB0899_DEV_ID , 0x30 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISFIFO , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x99 }, - { STB0899_DISF22RX , 0xa8 }, - /* SYSREG ? */ - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0xfe }, - { STB0899_IRQSTATUS_2 , 0x03 }, - { STB0899_IRQSTATUS_1 , 0x7c }, - { STB0899_IRQSTATUS_0 , 0xf4 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x58 }, - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x33 }, - { STB0899_IOPVALUE3 , 0x6d }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x60 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x01 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x01 }, - { STB0899_AGC1REF , 0x10 }, - { STB0899_RTC , 0x23 }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x34 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xf7 }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xf1 }, - { STB0899_LDT2 , 0xe3 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfd }, - { STB0899_QDCCOMP , 0xff }, - { STB0899_POWERI , 0x0c }, - { STB0899_POWERQ , 0x0f }, - { STB0899_RCOMP , 0x6c }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x06 }, - { STB0899_AGC2I2 , 0x00 }, - { STB0899_TLIR , 0x30 }, - { STB0899_RTF , 0x7f }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xbc }, - { STB0899_CFRM , 0xea }, - { STB0899_CFRL , 0x31 }, - { STB0899_NIRM , 0x2b }, - { STB0899_NIRL , 0x80 }, - { STB0899_ISYMB , 0x1d }, - { STB0899_QSYMB , 0xa6 }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0x02 }, - { STB0899_EQUAQ1 , 0xff }, - { STB0899_EQUAI2 , 0x04 }, - { STB0899_EQUAQ2 , 0x05 }, - { STB0899_EQUAI3 , 0x02 }, - { STB0899_EQUAQ3 , 0xfd }, - { STB0899_EQUAI4 , 0x03 }, - { STB0899_EQUAQ4 , 0x07 }, - { STB0899_EQUAI5 , 0x08 }, - { STB0899_EQUAQ5 , 0xf5 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0x86 }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x0a }, - { STB0899_ECNT3L , 0xad }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xb0 }, - { STB0899_VTH23 , 0x7a }, - { STB0899_VTH34 , 0x58 }, - { STB0899_VTH56 , 0x38 }, - { STB0899_VTH67 , 0x34 }, - { STB0899_VTH78 , 0x24 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x41 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x00 }, - { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x1b }, - { STB0899_TSLLSTKL , 0xb3 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0x00 }, - { STB0899_PCKLENUL , 0xbc }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xbd }, - { STB0899_TSSTATUS , 0x90 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x95 }, - { STB0899_ERRCTRL3 , 0x8d }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x19 }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0xf0 }, - { STB0899_MATSTRL , 0x02 }, - { STB0899_UPLSTRM , 0x45 }, - { STB0899_UPLSTRL , 0x60 }, - { STB0899_DFLSTRM , 0xe3 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x47 }, - { STB0899_SYNCDSTRM , 0x05 }, - { STB0899_SYNCDSTRL , 0x18 }, - { STB0899_CFGPDELSTATUS1 , 0x19 }, - { STB0899_CFGPDELSTATUS2 , 0x2b }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x01 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - -struct stb0899_config vp1041_stb0899_config = { - .init_dev = vp1041_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = vp1041_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .demod_address = 0x68, /* 0xd0 >> 1 */ - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_ON, /* 1 */ - - .lo_clk = 76500000, - .hi_clk = 99000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = stb6100_get_frequency, - .tuner_set_frequency = stb6100_set_frequency, - .tuner_set_bandwidth = stb6100_set_bandwidth, - .tuner_get_bandwidth = stb6100_get_bandwidth, - .tuner_set_rfsiggain = NULL, -}; - -struct stb6100_config vp1041_stb6100_config = { - .tuner_address = 0x60, - .refclock = 27000000, -}; - -static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - mantis->fe = dvb_attach(stb0899_attach, &vp1041_stb0899_config, adapter); - if (mantis->fe) { - dprintk(MANTIS_ERROR, 1, - "found STB0899 DVB-S/DVB-S2 frontend @0x%02x", - vp1041_stb0899_config.demod_address); - - if (dvb_attach(stb6100_attach, mantis->fe, &vp1041_stb6100_config, adapter)) { - if (!dvb_attach(lnbp21_attach, mantis->fe, adapter, 0, 0)) - dprintk(MANTIS_ERROR, 1, "No LNBP21 found!"); - } - } else { - return -EREMOTEIO; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - - - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp1041_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp1041_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1041.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1041.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1041.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp1041.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - Mantis VP-1041 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP1041_H -#define __MANTIS_VP1041_H - -#include "mantis_common.h" - -#define MANTIS_VP_1041_DVB_S2 0x0031 -#define SKYSTAR_HD2_10 0x0001 -#define SKYSTAR_HD2_20 0x0003 -#define CINERGY_S2_PCI_HD 0x1179 - -extern struct mantis_hwconfig vp1041_config; - -#endif /* __MANTIS_VP1041_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2033.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2033.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2033.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2033.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -/* - Mantis VP-2033 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "tda1002x.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp2033.h" - -#define MANTIS_MODEL_NAME "VP-2033" -#define MANTIS_DEV_TYPE "DVB-C" - -struct tda1002x_config vp2033_tda1002x_cu1216_config = { - .demod_address = 0x18 >> 1, - .invert = 1, -}; - -struct tda10023_config vp2033_tda10023_cu1216_config = { - .demod_address = 0x18 >> 1, - .invert = 1, -}; - -static u8 read_pwm(struct mantis_pci *mantis) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { - {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, - {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} - }; - - if ((i2c_transfer(adapter, msg, 2) != 2) - || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct mantis_pci *mantis = fe->dvb->priv; - struct i2c_adapter *adapter = &mantis->adapter; - - u8 buf[6]; - struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; - int i; - -#define CU1216_IF 36125000 -#define TUNER_MUL 62500 - - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0xce; - buf[3] = (params->frequency < 150000000 ? 0x01 : - params->frequency < 445000000 ? 0x02 : 0x04); - buf[4] = 0xde; - buf[5] = 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) != 1) - return -EIO; - - /* wait for the pll lock */ - msg.flags = I2C_M_RD; - msg.len = 1; - for (i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) - break; - - msleep(10); - } - - /* switch the charge pump to the lower current */ - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[2]; - buf[2] &= ~0x40; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - - dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); - fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config, - adapter, - read_pwm(mantis)); - - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", - vp2033_tda1002x_cu1216_config.demod_address); - } else { - fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config, - adapter, - read_pwm(mantis)); - - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", - vp2033_tda1002x_cu1216_config.demod_address); - } - } - - if (fe) { - fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; - dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); - } else { - return -1; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - - mantis->fe = fe; - dprintk(MANTIS_DEBUG, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp2033_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_204, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp2033_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2033.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2033.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2033.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2033.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - Mantis VP-2033 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP2033_H -#define __MANTIS_VP2033_H - -#include "mantis_common.h" - -#define MANTIS_VP_2033_DVB_C 0x0008 - -extern struct mantis_hwconfig vp2033_config; - -#endif /* __MANTIS_VP2033_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2040.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2040.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2040.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2040.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,186 +0,0 @@ -/* - Mantis VP-2040 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "tda1002x.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp2040.h" - -#define MANTIS_MODEL_NAME "VP-2040" -#define MANTIS_DEV_TYPE "DVB-C" - -struct tda1002x_config vp2040_tda1002x_cu1216_config = { - .demod_address = 0x18 >> 1, - .invert = 1, -}; - -struct tda10023_config vp2040_tda10023_cu1216_config = { - .demod_address = 0x18 >> 1, - .invert = 1, -}; - -static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct mantis_pci *mantis = fe->dvb->priv; - struct i2c_adapter *adapter = &mantis->adapter; - - u8 buf[6]; - struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; - int i; - -#define CU1216_IF 36125000 -#define TUNER_MUL 62500 - - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0xce; - buf[3] = (params->frequency < 150000000 ? 0x01 : - params->frequency < 445000000 ? 0x02 : 0x04); - buf[4] = 0xde; - buf[5] = 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) != 1) - return -EIO; - - /* wait for the pll lock */ - msg.flags = I2C_M_RD; - msg.len = 1; - for (i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) - break; - - msleep(10); - } - - /* switch the charge pump to the lower current */ - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[2]; - buf[2] &= ~0x40; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(adapter, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static u8 read_pwm(struct mantis_pci *mantis) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { - {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, - {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} - }; - - if ((i2c_transfer(adapter, msg, 2) != 2) - || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - - int err = 0; - - err = mantis_frontend_power(mantis, POWER_ON); - if (err == 0) { - mantis_frontend_soft_reset(mantis); - msleep(250); - - dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); - fe = dvb_attach(tda10021_attach, &vp2040_tda1002x_cu1216_config, - adapter, - read_pwm(mantis)); - - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", - vp2040_tda1002x_cu1216_config.demod_address); - } else { - fe = dvb_attach(tda10023_attach, &vp2040_tda10023_cu1216_config, - adapter, - read_pwm(mantis)); - - if (fe) { - dprintk(MANTIS_ERROR, 1, - "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", - vp2040_tda1002x_cu1216_config.demod_address); - } - } - - if (fe) { - fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; - dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); - } else { - return -1; - } - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - } - mantis->fe = fe; - dprintk(MANTIS_DEBUG, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp2040_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_204, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp2040_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2040.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2040.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2040.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp2040.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/* - Mantis VP-2040 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP2040_H -#define __MANTIS_VP2040_H - -#include "mantis_common.h" - -#define MANTIS_VP_2040_DVB_C 0x0043 -#define CINERGY_C 0x1178 -#define CABLESTAR_HD2 0x0002 - -extern struct mantis_hwconfig vp2040_config; - -#endif /* __MANTIS_VP2040_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3028.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3028.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3028.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3028.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* - Mantis VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "mantis_common.h" -#include "mantis_vp3028.h" - -struct zl10353_config mantis_vp3028_config = { - .demod_address = 0x0f, -}; - -#define MANTIS_MODEL_NAME "VP-3028" -#define MANTIS_DEV_TYPE "DVB-T" - -struct mantis_hwconfig vp3028_mantis_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3028.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3028.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3028.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3028.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - Mantis VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP3028_H -#define __MANTIS_VP3028_H - -#include "dvb_frontend.h" -#include "mantis_common.h" -#include "zl10353.h" - -#define MANTIS_VP_3028_DVB_T 0x0028 - -extern struct zl10353_config mantis_vp3028_config; -extern struct mantis_hwconfig vp3028_mantis_config; - -#endif /* __MANTIS_VP3028_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3030.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3030.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3030.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3030.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/* - Mantis VP-3030 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -#include "zl10353.h" -#include "tda665x.h" -#include "mantis_common.h" -#include "mantis_ioc.h" -#include "mantis_dvb.h" -#include "mantis_vp3030.h" - -struct zl10353_config mantis_vp3030_config = { - .demod_address = 0x0f, -}; - -struct tda665x_config env57h12d5_config = { - .name = "ENV57H12D5 (ET-50DT)", - .addr = 0x60, - .frequency_min = 47000000, - .frequency_max = 862000000, - .frequency_offst = 3616667, - .ref_multiplier = 6, /* 1/6 MHz */ - .ref_divider = 100000, /* 1/6 MHz */ -}; - -#define MANTIS_MODEL_NAME "VP-3030" -#define MANTIS_DEV_TYPE "DVB-T" - - -static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) -{ - struct i2c_adapter *adapter = &mantis->adapter; - struct mantis_hwconfig *config = mantis->hwconfig; - int err = 0; - - mantis_gpio_set_bits(mantis, config->reset, 0); - msleep(100); - err = mantis_frontend_power(mantis, POWER_ON); - msleep(100); - mantis_gpio_set_bits(mantis, config->reset, 1); - - if (err == 0) { - msleep(250); - dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); - fe = dvb_attach(zl10353_attach, &mantis_vp3030_config, adapter); - - if (!fe) - return -1; - - dvb_attach(tda665x_attach, fe, &env57h12d5_config, adapter); - } else { - dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", - adapter->name, - err); - - return -EIO; - - } - mantis->fe = fe; - dprintk(MANTIS_ERROR, 1, "Done!"); - - return 0; -} - -struct mantis_hwconfig vp3030_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, - - .frontend_init = vp3030_frontend_init, - .power = GPIF_A12, - .reset = GPIF_A13, - - .i2c_mode = MANTIS_BYTE_MODE -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3030.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3030.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3030.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/mantis/mantis_vp3030.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - Mantis VP-3030 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP3030_H -#define __MANTIS_VP3030_H - -#include "mantis_common.h" - -#define MANTIS_VP_3030_DVB_T 0x0024 - -extern struct mantis_hwconfig vp3030_config; - -#endif /* __MANTIS_VP3030_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -config DVB_NGENE - tristate "Micronas nGene support" - depends on DVB_CORE && PCI && I2C - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE - ---help--- - Support for Micronas PCI express cards with nGene bridge. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -# -# Makefile for the nGene device driver -# - -ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o - -obj-$(CONFIG_DVB_NGENE) += ngene.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners/ - -# For the staging CI driver cxd2099 -EXTRA_CFLAGS += -Idrivers/staging/cxd2099/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-cards.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,460 +0,0 @@ -/* - * ngene-cards.c: nGene PCIe bridge driver - card specific info - * - * Copyright (C) 2005-2007 Micronas - * - * Copyright (C) 2008-2009 Ralph Metzler - * Modifications for new nGene firmware, - * support for EEPROM-copying, - * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include - -#include "ngene.h" - -/* demods/tuners */ -#include "stv6110x.h" -#include "stv090x.h" -#include "lnbh24.h" -#include "lgdt330x.h" -#include "mt2131.h" - - -/****************************************************************************/ -/* Demod/tuner attachment ***************************************************/ -/****************************************************************************/ - -static int tuner_attach_stv6110(struct ngene_channel *chan) -{ - struct i2c_adapter *i2c; - struct stv090x_config *feconf = (struct stv090x_config *) - chan->dev->card_info->fe_config[chan->number]; - struct stv6110x_config *tunerconf = (struct stv6110x_config *) - chan->dev->card_info->tuner_config[chan->number]; - struct stv6110x_devctl *ctl; - - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - - ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); - if (ctl == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); - return -ENODEV; - } - - feconf->tuner_init = ctl->tuner_init; - feconf->tuner_sleep = ctl->tuner_sleep; - feconf->tuner_set_mode = ctl->tuner_set_mode; - feconf->tuner_set_frequency = ctl->tuner_set_frequency; - feconf->tuner_get_frequency = ctl->tuner_get_frequency; - feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; - feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; - feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; - feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; - feconf->tuner_set_refclk = ctl->tuner_set_refclk; - feconf->tuner_get_status = ctl->tuner_get_status; - - return 0; -} - - -static int demod_attach_stv0900(struct ngene_channel *chan) -{ - struct i2c_adapter *i2c; - struct stv090x_config *feconf = (struct stv090x_config *) - chan->dev->card_info->fe_config[chan->number]; - - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - /* Note: Both adapters share the same i2c bus, but the demod */ - /* driver requires that each demod has its own i2c adapter */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - - chan->fe = dvb_attach(stv090x_attach, feconf, i2c, - (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 - : STV090x_DEMODULATOR_1); - if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); - return -ENODEV; - } - - /* store channel info */ - if (feconf->tuner_i2c_lock) - chan->fe->analog_demod_priv = chan; - - if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, - 0, chan->dev->card_info->lnb[chan->number])) { - printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); - dvb_frontend_detach(chan->fe); - chan->fe = NULL; - return -ENODEV; - } - - return 0; -} - -static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) -{ - struct ngene_channel *chan = fe->analog_demod_priv; - - if (lock) - down(&chan->dev->pll_mutex); - else - up(&chan->dev->pll_mutex); -} - -static int cineS2_probe(struct ngene_channel *chan) -{ - struct i2c_adapter *i2c; - struct stv090x_config *fe_conf; - u8 buf[3]; - struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; - int rc; - - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - - fe_conf = chan->dev->card_info->fe_config[chan->number]; - i2c_msg.addr = fe_conf->address; - - /* probe demod */ - i2c_msg.len = 2; - buf[0] = 0xf1; - buf[1] = 0x00; - rc = i2c_transfer(i2c, &i2c_msg, 1); - if (rc != 1) - return -ENODEV; - - /* demod found, attach it */ - rc = demod_attach_stv0900(chan); - if (rc < 0 || chan->number < 2) - return rc; - - /* demod #2: reprogram outputs DPN1 & DPN2 */ - i2c_msg.len = 3; - buf[0] = 0xf1; - switch (chan->number) { - case 2: - buf[1] = 0x5c; - buf[2] = 0xc2; - break; - case 3: - buf[1] = 0x61; - buf[2] = 0xcc; - break; - default: - return -ENODEV; - } - rc = i2c_transfer(i2c, &i2c_msg, 1); - if (rc != 1) { - printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); - return -EIO; - } - - return 0; -} - - -static struct lgdt330x_config aver_m780 = { - .demod_address = 0xb2 >> 1, - .demod_chip = LGDT3303, - .serial_mpeg = 0x00, /* PARALLEL */ - .clock_polarity_flip = 1, -}; - -static struct mt2131_config m780_tunerconfig = { - 0xc0 >> 1 -}; - -/* A single func to attach the demo and tuner, rather than - * use two sep funcs like the current design mandates. - */ -static int demod_attach_lg330x(struct ngene_channel *chan) -{ - chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter); - if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n"); - return -ENODEV; - } - - dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter, - &m780_tunerconfig, 0); - - return (chan->fe) ? 0 : -ENODEV; -} - -/****************************************************************************/ -/* Switch control (I2C gates, etc.) *****************************************/ -/****************************************************************************/ - - -static struct stv090x_config fe_cineS2 = { - .device = STV0900, - .demod_mode = STV090x_DUAL, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 27000000, - .address = 0x68, - - .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - - .repeater_level = STV090x_RPTLEVEL_16, - - .adc1_range = STV090x_ADC_1Vpp, - .adc2_range = STV090x_ADC_1Vpp, - - .diseqc_envelope_mode = true, - - .tuner_i2c_lock = cineS2_tuner_i2c_lock, -}; - -static struct stv090x_config fe_cineS2_2 = { - .device = STV0900, - .demod_mode = STV090x_DUAL, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 27000000, - .address = 0x69, - - .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, - - .repeater_level = STV090x_RPTLEVEL_16, - - .adc1_range = STV090x_ADC_1Vpp, - .adc2_range = STV090x_ADC_1Vpp, - - .diseqc_envelope_mode = true, - - .tuner_i2c_lock = cineS2_tuner_i2c_lock, -}; - -static struct stv6110x_config tuner_cineS2_0 = { - .addr = 0x60, - .refclk = 27000000, - .clk_div = 1, -}; - -static struct stv6110x_config tuner_cineS2_1 = { - .addr = 0x63, - .refclk = 27000000, - .clk_div = 1, -}; - -static struct ngene_info ngene_info_cineS2 = { - .type = NGENE_SIDEWINDER, - .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0b, 0x08}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - -static struct ngene_info ngene_info_satixS2 = { - .type = NGENE_SIDEWINDER, - .name = "Mystique SaTiX-S2 Dual", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0b, 0x08}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - -static struct ngene_info ngene_info_satixS2v2 = { - .type = NGENE_SIDEWINDER, - .name = "Mystique SaTiX-S2 Dual (v2)", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, - NGENE_IO_TSOUT}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0a, 0x08, 0x0b, 0x09}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - -static struct ngene_info ngene_info_cineS2v5 = { - .type = NGENE_SIDEWINDER, - .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, - NGENE_IO_TSOUT}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0a, 0x08, 0x0b, 0x09}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - - -static struct ngene_info ngene_info_duoFlexS2 = { - .type = NGENE_SIDEWINDER, - .name = "Digital Devices DuoFlex S2 miniPCIe", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, - NGENE_IO_TSOUT}, - .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0a, 0x08, 0x0b, 0x09}, - .tsf = {3, 3}, - .fw_version = 18, - .msi_supported = true, -}; - -static struct ngene_info ngene_info_m780 = { - .type = NGENE_APP, - .name = "Aver M780 ATSC/QAM-B", - - /* Channel 0 is analog, which is currently unsupported */ - .io_type = { NGENE_IO_NONE, NGENE_IO_TSIN }, - .demod_attach = { NULL, demod_attach_lg330x }, - - /* Ensure these are NULL else the frame will call them (as funcs) */ - .tuner_attach = { 0, 0, 0, 0 }, - .fe_config = { NULL, &aver_m780 }, - .avf = { 0 }, - - /* A custom electrical interface config for the demod to bridge */ - .tsf = { 4, 4 }, - .fw_version = 15, -}; - -/****************************************************************************/ - - - -/****************************************************************************/ -/* PCI Subsystem ID *********************************************************/ -/****************************************************************************/ - -#define NGENE_ID(_subvend, _subdev, _driverdata) { \ - .vendor = NGENE_VID, .device = NGENE_PID, \ - .subvendor = _subvend, .subdevice = _subdev, \ - .driver_data = (unsigned long) &_driverdata } - -/****************************************************************************/ - -static const struct pci_device_id ngene_id_tbl[] __devinitdata = { - NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), - NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), - NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), - NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), - NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), - NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2), - NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2), - NGENE_ID(0x1461, 0x062e, ngene_info_m780), - {0} -}; -MODULE_DEVICE_TABLE(pci, ngene_id_tbl); - -/****************************************************************************/ -/* Init/Exit ****************************************************************/ -/****************************************************************************/ - -static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, - enum pci_channel_state state) -{ - printk(KERN_ERR DEVICE_NAME ": PCI error\n"); - if (state == pci_channel_io_perm_failure) - return PCI_ERS_RESULT_DISCONNECT; - if (state == pci_channel_io_frozen) - return PCI_ERS_RESULT_NEED_RESET; - return PCI_ERS_RESULT_CAN_RECOVER; -} - -static pci_ers_result_t ngene_link_reset(struct pci_dev *dev) -{ - printk(KERN_INFO DEVICE_NAME ": link reset\n"); - return 0; -} - -static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) -{ - printk(KERN_INFO DEVICE_NAME ": slot reset\n"); - return 0; -} - -static void ngene_resume(struct pci_dev *dev) -{ - printk(KERN_INFO DEVICE_NAME ": resume\n"); -} - -static struct pci_error_handlers ngene_errors = { - .error_detected = ngene_error_detected, - .link_reset = ngene_link_reset, - .slot_reset = ngene_slot_reset, - .resume = ngene_resume, -}; - -static struct pci_driver ngene_pci_driver = { - .name = "ngene", - .id_table = ngene_id_tbl, - .probe = ngene_probe, - .remove = __devexit_p(ngene_remove), - .err_handler = &ngene_errors, - .shutdown = ngene_shutdown, -}; - -static __init int module_init_ngene(void) -{ - printk(KERN_INFO - "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); - return pci_register_driver(&ngene_pci_driver); -} - -static __exit void module_exit_ngene(void) -{ - pci_unregister_driver(&ngene_pci_driver); -} - -module_init(module_init_ngene); -module_exit(module_exit_ngene); - -MODULE_DESCRIPTION("nGene"); -MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1696 +0,0 @@ -/* - * ngene.c: nGene PCIe bridge driver - * - * Copyright (C) 2005-2007 Micronas - * - * Copyright (C) 2008-2009 Ralph Metzler - * Modifications for new nGene firmware, - * support for EEPROM-copying, - * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ngene.h" - -static int one_adapter = 1; -module_param(one_adapter, int, 0444); -MODULE_PARM_DESC(one_adapter, "Use only one adapter."); - -static int shutdown_workaround; -module_param(shutdown_workaround, int, 0644); -MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets."); - -static int debug; -module_param(debug, int, 0444); -MODULE_PARM_DESC(debug, "Print debugging information."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk if (debug) printk - -#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) -#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr))) -#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) -#define ngreadl(adr) readl(dev->iomem + (adr)) -#define ngreadb(adr) readb(dev->iomem + (adr)) -#define ngcpyto(adr, src, count) memcpy_toio((char *) \ - (dev->iomem + (adr)), (src), (count)) -#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \ - (dev->iomem + (adr)), (count)) - -/****************************************************************************/ -/* nGene interrupt handler **************************************************/ -/****************************************************************************/ - -static void event_tasklet(unsigned long data) -{ - struct ngene *dev = (struct ngene *)data; - - while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { - struct EVENT_BUFFER Event = - dev->EventQueue[dev->EventQueueReadIndex]; - dev->EventQueueReadIndex = - (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1); - - if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify)) - dev->TxEventNotify(dev, Event.TimeStamp); - if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify)) - dev->RxEventNotify(dev, Event.TimeStamp, - Event.RXCharacter); - } -} - -static void demux_tasklet(unsigned long data) -{ - struct ngene_channel *chan = (struct ngene_channel *)data; - struct SBufferHeader *Cur = chan->nextBuffer; - - spin_lock_irq(&chan->state_lock); - - while (Cur->ngeneBuffer.SR.Flags & 0x80) { - if (chan->mode & NGENE_IO_TSOUT) { - u32 Flags = chan->DataFormatFlags; - if (Cur->ngeneBuffer.SR.Flags & 0x20) - Flags |= BEF_OVERFLOW; - if (chan->pBufferExchange) { - if (!chan->pBufferExchange(chan, - Cur->Buffer1, - chan->Capture1Length, - Cur->ngeneBuffer.SR. - Clock, Flags)) { - /* - We didn't get data - Clear in service flag to make sure we - get called on next interrupt again. - leave fill/empty (0x80) flag alone - to avoid hardware running out of - buffers during startup, we hold only - in run state ( the source may be late - delivering data ) - */ - - if (chan->HWState == HWSTATE_RUN) { - Cur->ngeneBuffer.SR.Flags &= - ~0x40; - break; - /* Stop proccessing stream */ - } - } else { - /* We got a valid buffer, - so switch to run state */ - chan->HWState = HWSTATE_RUN; - } - } else { - printk(KERN_ERR DEVICE_NAME ": OOPS\n"); - if (chan->HWState == HWSTATE_RUN) { - Cur->ngeneBuffer.SR.Flags &= ~0x40; - break; /* Stop proccessing stream */ - } - } - if (chan->AudioDTOUpdated) { - printk(KERN_INFO DEVICE_NAME - ": Update AudioDTO = %d\n", - chan->AudioDTOValue); - Cur->ngeneBuffer.SR.DTOUpdate = - chan->AudioDTOValue; - chan->AudioDTOUpdated = 0; - } - } else { - if (chan->HWState == HWSTATE_RUN) { - u32 Flags = chan->DataFormatFlags; - IBufferExchange *exch1 = chan->pBufferExchange; - IBufferExchange *exch2 = chan->pBufferExchange2; - if (Cur->ngeneBuffer.SR.Flags & 0x01) - Flags |= BEF_EVEN_FIELD; - if (Cur->ngeneBuffer.SR.Flags & 0x20) - Flags |= BEF_OVERFLOW; - spin_unlock_irq(&chan->state_lock); - if (exch1) - exch1(chan, Cur->Buffer1, - chan->Capture1Length, - Cur->ngeneBuffer.SR.Clock, - Flags); - if (exch2) - exch2(chan, Cur->Buffer2, - chan->Capture2Length, - Cur->ngeneBuffer.SR.Clock, - Flags); - spin_lock_irq(&chan->state_lock); - } else if (chan->HWState != HWSTATE_STOP) - chan->HWState = HWSTATE_RUN; - } - Cur->ngeneBuffer.SR.Flags = 0x00; - Cur = Cur->Next; - } - chan->nextBuffer = Cur; - - spin_unlock_irq(&chan->state_lock); -} - -static irqreturn_t irq_handler(int irq, void *dev_id) -{ - struct ngene *dev = (struct ngene *)dev_id; - u32 icounts = 0; - irqreturn_t rc = IRQ_NONE; - u32 i = MAX_STREAM; - u8 *tmpCmdDoneByte; - - if (dev->BootFirmware) { - icounts = ngreadl(NGENE_INT_COUNTS); - if (icounts != dev->icounts) { - ngwritel(0, FORCE_NMI); - dev->cmd_done = 1; - wake_up(&dev->cmd_wq); - dev->icounts = icounts; - rc = IRQ_HANDLED; - } - return rc; - } - - ngwritel(0, FORCE_NMI); - - spin_lock(&dev->cmd_lock); - tmpCmdDoneByte = dev->CmdDoneByte; - if (tmpCmdDoneByte && - (*tmpCmdDoneByte || - (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) { - dev->CmdDoneByte = NULL; - dev->cmd_done = 1; - wake_up(&dev->cmd_wq); - rc = IRQ_HANDLED; - } - spin_unlock(&dev->cmd_lock); - - if (dev->EventBuffer->EventStatus & 0x80) { - u8 nextWriteIndex = - (dev->EventQueueWriteIndex + 1) & - (EVENT_QUEUE_SIZE - 1); - if (nextWriteIndex != dev->EventQueueReadIndex) { - dev->EventQueue[dev->EventQueueWriteIndex] = - *(dev->EventBuffer); - dev->EventQueueWriteIndex = nextWriteIndex; - } else { - printk(KERN_ERR DEVICE_NAME ": event overflow\n"); - dev->EventQueueOverflowCount += 1; - dev->EventQueueOverflowFlag = 1; - } - dev->EventBuffer->EventStatus &= ~0x80; - tasklet_schedule(&dev->event_tasklet); - rc = IRQ_HANDLED; - } - - while (i > 0) { - i--; - spin_lock(&dev->channel[i].state_lock); - /* if (dev->channel[i].State>=KSSTATE_RUN) { */ - if (dev->channel[i].nextBuffer) { - if ((dev->channel[i].nextBuffer-> - ngeneBuffer.SR.Flags & 0xC0) == 0x80) { - dev->channel[i].nextBuffer-> - ngeneBuffer.SR.Flags |= 0x40; - tasklet_schedule( - &dev->channel[i].demux_tasklet); - rc = IRQ_HANDLED; - } - } - spin_unlock(&dev->channel[i].state_lock); - } - - /* Request might have been processed by a previous call. */ - return IRQ_HANDLED; -} - -/****************************************************************************/ -/* nGene command interface **************************************************/ -/****************************************************************************/ - -static void dump_command_io(struct ngene *dev) -{ - u8 buf[8], *b; - - ngcpyfrom(buf, HOST_TO_NGENE, 8); - printk(KERN_ERR "host_to_ngene (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n", - HOST_TO_NGENE, buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7]); - - ngcpyfrom(buf, NGENE_TO_HOST, 8); - printk(KERN_ERR "ngene_to_host (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n", - NGENE_TO_HOST, buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7]); - - b = dev->hosttongene; - printk(KERN_ERR "dev->hosttongene (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n", - b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); - - b = dev->ngenetohost; - printk(KERN_ERR "dev->ngenetohost (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n", - b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); -} - -static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) -{ - int ret; - u8 *tmpCmdDoneByte; - - dev->cmd_done = 0; - - if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) { - dev->BootFirmware = 1; - dev->icounts = ngreadl(NGENE_INT_COUNTS); - ngwritel(0, NGENE_COMMAND); - ngwritel(0, NGENE_COMMAND_HI); - ngwritel(0, NGENE_STATUS); - ngwritel(0, NGENE_STATUS_HI); - ngwritel(0, NGENE_EVENT); - ngwritel(0, NGENE_EVENT_HI); - } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) { - u64 fwio = dev->PAFWInterfaceBuffer; - - ngwritel(fwio & 0xffffffff, NGENE_COMMAND); - ngwritel(fwio >> 32, NGENE_COMMAND_HI); - ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS); - ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI); - ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT); - ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI); - } - - memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2); - - if (dev->BootFirmware) - ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2); - - spin_lock_irq(&dev->cmd_lock); - tmpCmdDoneByte = dev->ngenetohost + com->out_len; - if (!com->out_len) - tmpCmdDoneByte++; - *tmpCmdDoneByte = 0; - dev->ngenetohost[0] = 0; - dev->ngenetohost[1] = 0; - dev->CmdDoneByte = tmpCmdDoneByte; - spin_unlock_irq(&dev->cmd_lock); - - /* Notify 8051. */ - ngwritel(1, FORCE_INT); - - ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ); - if (!ret) { - /*ngwritel(0, FORCE_NMI);*/ - - printk(KERN_ERR DEVICE_NAME - ": Command timeout cmd=%02x prev=%02x\n", - com->cmd.hdr.Opcode, dev->prev_cmd); - dump_command_io(dev); - return -1; - } - if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) - dev->BootFirmware = 0; - - dev->prev_cmd = com->cmd.hdr.Opcode; - - if (!com->out_len) - return 0; - - memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len); - - return 0; -} - -int ngene_command(struct ngene *dev, struct ngene_command *com) -{ - int result; - - down(&dev->cmd_mutex); - result = ngene_command_mutex(dev, com); - up(&dev->cmd_mutex); - return result; -} - - -static int ngene_command_load_firmware(struct ngene *dev, - u8 *ngene_fw, u32 size) -{ -#define FIRSTCHUNK (1024) - u32 cleft; - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE; - com.cmd.hdr.Length = 0; - com.in_len = 0; - com.out_len = 0; - - ngene_command(dev, &com); - - cleft = (size + 3) & ~3; - if (cleft > FIRSTCHUNK) { - ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK, - cleft - FIRSTCHUNK); - cleft = FIRSTCHUNK; - } - ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft); - - memset(&com, 0, sizeof(struct ngene_command)); - com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH; - com.cmd.hdr.Length = 4; - com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA; - com.cmd.FWLoadFinish.Length = (unsigned short)cleft; - com.in_len = 4; - com.out_len = 0; - - return ngene_command(dev, &com); -} - - -static int ngene_command_config_buf(struct ngene *dev, u8 config) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER; - com.cmd.hdr.Length = 1; - com.cmd.ConfigureBuffers.config = config; - com.in_len = 1; - com.out_len = 0; - - if (ngene_command(dev, &com) < 0) - return -EIO; - return 0; -} - -static int ngene_command_config_free_buf(struct ngene *dev, u8 *config) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER; - com.cmd.hdr.Length = 6; - memcpy(&com.cmd.ConfigureBuffers.config, config, 6); - com.in_len = 6; - com.out_len = 0; - - if (ngene_command(dev, &com) < 0) - return -EIO; - - return 0; -} - -int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN; - com.cmd.hdr.Length = 1; - com.cmd.SetGpioPin.select = select | (level << 7); - com.in_len = 1; - com.out_len = 0; - - return ngene_command(dev, &com); -} - - -/* - 02000640 is sample on rising edge. - 02000740 is sample on falling edge. - 02000040 is ignore "valid" signal - - 0: FD_CTL1 Bit 7,6 must be 0,1 - 7 disable(fw controlled) - 6 0-AUX,1-TS - 5 0-par,1-ser - 4 0-lsb/1-msb - 3,2 reserved - 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both - 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge - 2: FD_STA is read-only. 0-sync - 3: FD_INSYNC is number of 47s to trigger "in sync". - 4: FD_OUTSYNC is number of 47s to trigger "out of sync". - 5: FD_MAXBYTE1 is low-order of bytes per packet. - 6: FD_MAXBYTE2 is high-order of bytes per packet. - 7: Top byte is unused. -*/ - -/****************************************************************************/ - -static u8 TSFeatureDecoderSetup[8 * 5] = { - 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, - 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ - 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ - 0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ - 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */ -}; - -/* Set NGENE I2S Config to 16 bit packed */ -static u8 I2SConfiguration[] = { - 0x00, 0x10, 0x00, 0x00, - 0x80, 0x10, 0x00, 0x00, -}; - -static u8 SPDIFConfiguration[10] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -/* Set NGENE I2S Config to transport stream compatible mode */ - -static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 }; - -static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 }; - -static u8 ITUDecoderSetup[4][16] = { - {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */ - 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00}, - {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, - {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */ - 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, - {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */ - 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, -}; - -/* - * 50 48 60 gleich - * 27p50 9f 00 22 80 42 69 18 ... - * 27p60 93 00 22 80 82 69 1c ... - */ - -/* Maxbyte to 1144 (for raw data) */ -static u8 ITUFeatureDecoderSetup[8] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00 -}; - -void FillTSBuffer(void *Buffer, int Length, u32 Flags) -{ - u32 *ptr = Buffer; - - memset(Buffer, 0xff, Length); - while (Length > 0) { - if (Flags & DF_SWAP32) - *ptr = 0x471FFF10; - else - *ptr = 0x10FF1F47; - ptr += (188 / 4); - Length -= 188; - } -} - - -static void flush_buffers(struct ngene_channel *chan) -{ - u8 val; - - do { - msleep(1); - spin_lock_irq(&chan->state_lock); - val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80; - spin_unlock_irq(&chan->state_lock); - } while (val); -} - -static void clear_buffers(struct ngene_channel *chan) -{ - struct SBufferHeader *Cur = chan->nextBuffer; - - do { - memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR)); - if (chan->mode & NGENE_IO_TSOUT) - FillTSBuffer(Cur->Buffer1, - chan->Capture1Length, - chan->DataFormatFlags); - Cur = Cur->Next; - } while (Cur != chan->nextBuffer); - - if (chan->mode & NGENE_IO_TSOUT) { - chan->nextBuffer->ngeneBuffer.SR.DTOUpdate = - chan->AudioDTOValue; - chan->AudioDTOUpdated = 0; - - Cur = chan->TSIdleBuffer.Head; - - do { - memset(&Cur->ngeneBuffer.SR, 0, - sizeof(Cur->ngeneBuffer.SR)); - FillTSBuffer(Cur->Buffer1, - chan->Capture1Length, - chan->DataFormatFlags); - Cur = Cur->Next; - } while (Cur != chan->TSIdleBuffer.Head); - } -} - -static int ngene_command_stream_control(struct ngene *dev, u8 stream, - u8 control, u8 mode, u8 flags) -{ - struct ngene_channel *chan = &dev->channel[stream]; - struct ngene_command com; - u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300); - u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500); - u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700); - u16 BsSDO = 0x9B00; - - down(&dev->stream_mutex); - memset(&com, 0, sizeof(com)); - com.cmd.hdr.Opcode = CMD_CONTROL; - com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2; - com.cmd.StreamControl.Stream = stream | (control ? 8 : 0); - if (chan->mode & NGENE_IO_TSOUT) - com.cmd.StreamControl.Stream |= 0x07; - com.cmd.StreamControl.Control = control | - (flags & SFLAG_ORDER_LUMA_CHROMA); - com.cmd.StreamControl.Mode = mode; - com.in_len = sizeof(struct FW_STREAM_CONTROL); - com.out_len = 0; - - dprintk(KERN_INFO DEVICE_NAME - ": Stream=%02x, Control=%02x, Mode=%02x\n", - com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control, - com.cmd.StreamControl.Mode); - - chan->Mode = mode; - - if (!(control & 0x80)) { - spin_lock_irq(&chan->state_lock); - if (chan->State == KSSTATE_RUN) { - chan->State = KSSTATE_ACQUIRE; - chan->HWState = HWSTATE_STOP; - spin_unlock_irq(&chan->state_lock); - if (ngene_command(dev, &com) < 0) { - up(&dev->stream_mutex); - return -1; - } - /* clear_buffers(chan); */ - flush_buffers(chan); - up(&dev->stream_mutex); - return 0; - } - spin_unlock_irq(&chan->state_lock); - up(&dev->stream_mutex); - return 0; - } - - if (mode & SMODE_AUDIO_CAPTURE) { - com.cmd.StreamControl.CaptureBlockCount = - chan->Capture1Length / AUDIO_BLOCK_SIZE; - com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; - } else if (mode & SMODE_TRANSPORT_STREAM) { - com.cmd.StreamControl.CaptureBlockCount = - chan->Capture1Length / TS_BLOCK_SIZE; - com.cmd.StreamControl.MaxLinesPerField = - chan->Capture1Length / TS_BLOCK_SIZE; - com.cmd.StreamControl.Buffer_Address = - chan->TSRingBuffer.PAHead; - if (chan->mode & NGENE_IO_TSOUT) { - com.cmd.StreamControl.BytesPerVBILine = - chan->Capture1Length / TS_BLOCK_SIZE; - com.cmd.StreamControl.Stream |= 0x07; - } - } else { - com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine; - com.cmd.StreamControl.MaxLinesPerField = chan->nLines; - com.cmd.StreamControl.MinLinesPerField = 100; - com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; - - if (mode & SMODE_VBI_CAPTURE) { - com.cmd.StreamControl.MaxVBILinesPerField = - chan->nVBILines; - com.cmd.StreamControl.MinVBILinesPerField = 0; - com.cmd.StreamControl.BytesPerVBILine = - chan->nBytesPerVBILine; - } - if (flags & SFLAG_COLORBAR) - com.cmd.StreamControl.Stream |= 0x04; - } - - spin_lock_irq(&chan->state_lock); - if (mode & SMODE_AUDIO_CAPTURE) { - chan->nextBuffer = chan->RingBuffer.Head; - if (mode & SMODE_AUDIO_SPDIF) { - com.cmd.StreamControl.SetupDataLen = - sizeof(SPDIFConfiguration); - com.cmd.StreamControl.SetupDataAddr = BsSPI; - memcpy(com.cmd.StreamControl.SetupData, - SPDIFConfiguration, sizeof(SPDIFConfiguration)); - } else { - com.cmd.StreamControl.SetupDataLen = 4; - com.cmd.StreamControl.SetupDataAddr = BsSDI; - memcpy(com.cmd.StreamControl.SetupData, - I2SConfiguration + - 4 * dev->card_info->i2s[stream], 4); - } - } else if (mode & SMODE_TRANSPORT_STREAM) { - chan->nextBuffer = chan->TSRingBuffer.Head; - if (stream >= STREAM_AUDIOIN1) { - if (chan->mode & NGENE_IO_TSOUT) { - com.cmd.StreamControl.SetupDataLen = - sizeof(TS_I2SOutConfiguration); - com.cmd.StreamControl.SetupDataAddr = BsSDO; - memcpy(com.cmd.StreamControl.SetupData, - TS_I2SOutConfiguration, - sizeof(TS_I2SOutConfiguration)); - } else { - com.cmd.StreamControl.SetupDataLen = - sizeof(TS_I2SConfiguration); - com.cmd.StreamControl.SetupDataAddr = BsSDI; - memcpy(com.cmd.StreamControl.SetupData, - TS_I2SConfiguration, - sizeof(TS_I2SConfiguration)); - } - } else { - com.cmd.StreamControl.SetupDataLen = 8; - com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10; - memcpy(com.cmd.StreamControl.SetupData, - TSFeatureDecoderSetup + - 8 * dev->card_info->tsf[stream], 8); - } - } else { - chan->nextBuffer = chan->RingBuffer.Head; - com.cmd.StreamControl.SetupDataLen = - 16 + sizeof(ITUFeatureDecoderSetup); - com.cmd.StreamControl.SetupDataAddr = BsUVI; - memcpy(com.cmd.StreamControl.SetupData, - ITUDecoderSetup[chan->itumode], 16); - memcpy(com.cmd.StreamControl.SetupData + 16, - ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup)); - } - clear_buffers(chan); - chan->State = KSSTATE_RUN; - if (mode & SMODE_TRANSPORT_STREAM) - chan->HWState = HWSTATE_RUN; - else - chan->HWState = HWSTATE_STARTUP; - spin_unlock_irq(&chan->state_lock); - - if (ngene_command(dev, &com) < 0) { - up(&dev->stream_mutex); - return -1; - } - up(&dev->stream_mutex); - return 0; -} - -void set_transfer(struct ngene_channel *chan, int state) -{ - u8 control = 0, mode = 0, flags = 0; - struct ngene *dev = chan->dev; - int ret; - - /* - printk(KERN_INFO DEVICE_NAME ": st %d\n", state); - msleep(100); - */ - - if (state) { - if (chan->running) { - printk(KERN_INFO DEVICE_NAME ": already running\n"); - return; - } - } else { - if (!chan->running) { - printk(KERN_INFO DEVICE_NAME ": already stopped\n"); - return; - } - } - - if (dev->card_info->switch_ctrl) - dev->card_info->switch_ctrl(chan, 1, state ^ 1); - - if (state) { - spin_lock_irq(&chan->state_lock); - - /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", - ngreadl(0x9310)); */ - dvb_ringbuffer_flush(&dev->tsout_rbuf); - control = 0x80; - if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { - chan->Capture1Length = 512 * 188; - mode = SMODE_TRANSPORT_STREAM; - } - if (chan->mode & NGENE_IO_TSOUT) { - chan->pBufferExchange = tsout_exchange; - /* 0x66666666 = 50MHz *2^33 /250MHz */ - chan->AudioDTOValue = 0x80000000; - chan->AudioDTOUpdated = 1; - } - if (chan->mode & NGENE_IO_TSIN) - chan->pBufferExchange = tsin_exchange; - spin_unlock_irq(&chan->state_lock); - } else - ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", - ngreadl(0x9310)); */ - - ret = ngene_command_stream_control(dev, chan->number, - control, mode, flags); - if (!ret) - chan->running = state; - else - printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n", - state); - if (!state) { - spin_lock_irq(&chan->state_lock); - chan->pBufferExchange = NULL; - dvb_ringbuffer_flush(&dev->tsout_rbuf); - spin_unlock_irq(&chan->state_lock); - } -} - - -/****************************************************************************/ -/* nGene hardware init and release functions ********************************/ -/****************************************************************************/ - -static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb) -{ - struct SBufferHeader *Cur = rb->Head; - u32 j; - - if (!Cur) - return; - - for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) { - if (Cur->Buffer1) - pci_free_consistent(dev->pci_dev, - rb->Buffer1Length, - Cur->Buffer1, - Cur->scList1->Address); - - if (Cur->Buffer2) - pci_free_consistent(dev->pci_dev, - rb->Buffer2Length, - Cur->Buffer2, - Cur->scList2->Address); - } - - if (rb->SCListMem) - pci_free_consistent(dev->pci_dev, rb->SCListMemSize, - rb->SCListMem, rb->PASCListMem); - - pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead); -} - -static void free_idlebuffer(struct ngene *dev, - struct SRingBufferDescriptor *rb, - struct SRingBufferDescriptor *tb) -{ - int j; - struct SBufferHeader *Cur = tb->Head; - - if (!rb->Head) - return; - free_ringbuffer(dev, rb); - for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) { - Cur->Buffer2 = NULL; - Cur->scList2 = NULL; - Cur->ngeneBuffer.Address_of_first_entry_2 = 0; - Cur->ngeneBuffer.Number_of_entries_2 = 0; - } -} - -static void free_common_buffers(struct ngene *dev) -{ - u32 i; - struct ngene_channel *chan; - - for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { - chan = &dev->channel[i]; - free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer); - free_ringbuffer(dev, &chan->RingBuffer); - free_ringbuffer(dev, &chan->TSRingBuffer); - } - - if (dev->OverflowBuffer) - pci_free_consistent(dev->pci_dev, - OVERFLOW_BUFFER_SIZE, - dev->OverflowBuffer, dev->PAOverflowBuffer); - - if (dev->FWInterfaceBuffer) - pci_free_consistent(dev->pci_dev, - 4096, - dev->FWInterfaceBuffer, - dev->PAFWInterfaceBuffer); -} - -/****************************************************************************/ -/* Ring buffer handling *****************************************************/ -/****************************************************************************/ - -static int create_ring_buffer(struct pci_dev *pci_dev, - struct SRingBufferDescriptor *descr, u32 NumBuffers) -{ - dma_addr_t tmp; - struct SBufferHeader *Head; - u32 i; - u32 MemSize = SIZEOF_SBufferHeader * NumBuffers; - u64 PARingBufferHead; - u64 PARingBufferCur; - u64 PARingBufferNext; - struct SBufferHeader *Cur, *Next; - - descr->Head = NULL; - descr->MemSize = 0; - descr->PAHead = 0; - descr->NumBuffers = 0; - - if (MemSize < 4096) - MemSize = 4096; - - Head = pci_alloc_consistent(pci_dev, MemSize, &tmp); - PARingBufferHead = tmp; - - if (!Head) - return -ENOMEM; - - memset(Head, 0, MemSize); - - PARingBufferCur = PARingBufferHead; - Cur = Head; - - for (i = 0; i < NumBuffers - 1; i++) { - Next = (struct SBufferHeader *) - (((u8 *) Cur) + SIZEOF_SBufferHeader); - PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader; - Cur->Next = Next; - Cur->ngeneBuffer.Next = PARingBufferNext; - Cur = Next; - PARingBufferCur = PARingBufferNext; - } - /* Last Buffer points back to first one */ - Cur->Next = Head; - Cur->ngeneBuffer.Next = PARingBufferHead; - - descr->Head = Head; - descr->MemSize = MemSize; - descr->PAHead = PARingBufferHead; - descr->NumBuffers = NumBuffers; - - return 0; -} - -static int AllocateRingBuffers(struct pci_dev *pci_dev, - dma_addr_t of, - struct SRingBufferDescriptor *pRingBuffer, - u32 Buffer1Length, u32 Buffer2Length) -{ - dma_addr_t tmp; - u32 i, j; - int status = 0; - u32 SCListMemSize = pRingBuffer->NumBuffers - * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) : - NUM_SCATTER_GATHER_ENTRIES) - * sizeof(struct HW_SCATTER_GATHER_ELEMENT); - - u64 PASCListMem; - struct HW_SCATTER_GATHER_ELEMENT *SCListEntry; - u64 PASCListEntry; - struct SBufferHeader *Cur; - void *SCListMem; - - if (SCListMemSize < 4096) - SCListMemSize = 4096; - - SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp); - - PASCListMem = tmp; - if (SCListMem == NULL) - return -ENOMEM; - - memset(SCListMem, 0, SCListMemSize); - - pRingBuffer->SCListMem = SCListMem; - pRingBuffer->PASCListMem = PASCListMem; - pRingBuffer->SCListMemSize = SCListMemSize; - pRingBuffer->Buffer1Length = Buffer1Length; - pRingBuffer->Buffer2Length = Buffer2Length; - - SCListEntry = SCListMem; - PASCListEntry = PASCListMem; - Cur = pRingBuffer->Head; - - for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) { - u64 PABuffer; - - void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length, - &tmp); - PABuffer = tmp; - - if (Buffer == NULL) - return -ENOMEM; - - Cur->Buffer1 = Buffer; - - SCListEntry->Address = PABuffer; - SCListEntry->Length = Buffer1Length; - - Cur->scList1 = SCListEntry; - Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry; - Cur->ngeneBuffer.Number_of_entries_1 = - NUM_SCATTER_GATHER_ENTRIES; - - SCListEntry += 1; - PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); - -#if NUM_SCATTER_GATHER_ENTRIES > 1 - for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) { - SCListEntry->Address = of; - SCListEntry->Length = OVERFLOW_BUFFER_SIZE; - SCListEntry += 1; - PASCListEntry += - sizeof(struct HW_SCATTER_GATHER_ELEMENT); - } -#endif - - if (!Buffer2Length) - continue; - - Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp); - PABuffer = tmp; - - if (Buffer == NULL) - return -ENOMEM; - - Cur->Buffer2 = Buffer; - - SCListEntry->Address = PABuffer; - SCListEntry->Length = Buffer2Length; - - Cur->scList2 = SCListEntry; - Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry; - Cur->ngeneBuffer.Number_of_entries_2 = - NUM_SCATTER_GATHER_ENTRIES; - - SCListEntry += 1; - PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); - -#if NUM_SCATTER_GATHER_ENTRIES > 1 - for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) { - SCListEntry->Address = of; - SCListEntry->Length = OVERFLOW_BUFFER_SIZE; - SCListEntry += 1; - PASCListEntry += - sizeof(struct HW_SCATTER_GATHER_ELEMENT); - } -#endif - - } - - return status; -} - -static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer, - struct SRingBufferDescriptor *pRingBuffer) -{ - int status = 0; - - /* Copy pointer to scatter gather list in TSRingbuffer - structure for buffer 2 - Load number of buffer - */ - u32 n = pRingBuffer->NumBuffers; - - /* Point to first buffer entry */ - struct SBufferHeader *Cur = pRingBuffer->Head; - int i; - /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */ - for (i = 0; i < n; i++) { - Cur->Buffer2 = pIdleBuffer->Head->Buffer1; - Cur->scList2 = pIdleBuffer->Head->scList1; - Cur->ngeneBuffer.Address_of_first_entry_2 = - pIdleBuffer->Head->ngeneBuffer. - Address_of_first_entry_1; - Cur->ngeneBuffer.Number_of_entries_2 = - pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1; - Cur = Cur->Next; - } - return status; -} - -static u32 RingBufferSizes[MAX_STREAM] = { - RING_SIZE_VIDEO, - RING_SIZE_VIDEO, - RING_SIZE_AUDIO, - RING_SIZE_AUDIO, - RING_SIZE_AUDIO, -}; - -static u32 Buffer1Sizes[MAX_STREAM] = { - MAX_VIDEO_BUFFER_SIZE, - MAX_VIDEO_BUFFER_SIZE, - MAX_AUDIO_BUFFER_SIZE, - MAX_AUDIO_BUFFER_SIZE, - MAX_AUDIO_BUFFER_SIZE -}; - -static u32 Buffer2Sizes[MAX_STREAM] = { - MAX_VBI_BUFFER_SIZE, - MAX_VBI_BUFFER_SIZE, - 0, - 0, - 0 -}; - - -static int AllocCommonBuffers(struct ngene *dev) -{ - int status = 0, i; - - dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096, - &dev->PAFWInterfaceBuffer); - if (!dev->FWInterfaceBuffer) - return -ENOMEM; - dev->hosttongene = dev->FWInterfaceBuffer; - dev->ngenetohost = dev->FWInterfaceBuffer + 256; - dev->EventBuffer = dev->FWInterfaceBuffer + 512; - - dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev, - OVERFLOW_BUFFER_SIZE, - &dev->PAOverflowBuffer); - if (!dev->OverflowBuffer) - return -ENOMEM; - memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE); - - for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { - int type = dev->card_info->io_type[i]; - - dev->channel[i].State = KSSTATE_STOP; - - if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) { - status = create_ring_buffer(dev->pci_dev, - &dev->channel[i].RingBuffer, - RingBufferSizes[i]); - if (status < 0) - break; - - if (type & (NGENE_IO_TV | NGENE_IO_AIN)) { - status = AllocateRingBuffers(dev->pci_dev, - dev-> - PAOverflowBuffer, - &dev->channel[i]. - RingBuffer, - Buffer1Sizes[i], - Buffer2Sizes[i]); - if (status < 0) - break; - } else if (type & NGENE_IO_HDTV) { - status = AllocateRingBuffers(dev->pci_dev, - dev-> - PAOverflowBuffer, - &dev->channel[i]. - RingBuffer, - MAX_HDTV_BUFFER_SIZE, - 0); - if (status < 0) - break; - } - } - - if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { - - status = create_ring_buffer(dev->pci_dev, - &dev->channel[i]. - TSRingBuffer, RING_SIZE_TS); - if (status < 0) - break; - - status = AllocateRingBuffers(dev->pci_dev, - dev->PAOverflowBuffer, - &dev->channel[i]. - TSRingBuffer, - MAX_TS_BUFFER_SIZE, 0); - if (status) - break; - } - - if (type & NGENE_IO_TSOUT) { - status = create_ring_buffer(dev->pci_dev, - &dev->channel[i]. - TSIdleBuffer, 1); - if (status < 0) - break; - status = AllocateRingBuffers(dev->pci_dev, - dev->PAOverflowBuffer, - &dev->channel[i]. - TSIdleBuffer, - MAX_TS_BUFFER_SIZE, 0); - if (status) - break; - FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer, - &dev->channel[i].TSRingBuffer); - } - } - return status; -} - -static void ngene_release_buffers(struct ngene *dev) -{ - if (dev->iomem) - iounmap(dev->iomem); - free_common_buffers(dev); - vfree(dev->tsout_buf); - vfree(dev->tsin_buf); - vfree(dev->ain_buf); - vfree(dev->vin_buf); - vfree(dev); -} - -static int ngene_get_buffers(struct ngene *dev) -{ - if (AllocCommonBuffers(dev)) - return -ENOMEM; - if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) { - dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE); - if (!dev->tsout_buf) - return -ENOMEM; - dvb_ringbuffer_init(&dev->tsout_rbuf, - dev->tsout_buf, TSOUT_BUF_SIZE); - } - if (dev->card_info->io_type[2]&NGENE_IO_TSIN) { - dev->tsin_buf = vmalloc(TSIN_BUF_SIZE); - if (!dev->tsin_buf) - return -ENOMEM; - dvb_ringbuffer_init(&dev->tsin_rbuf, - dev->tsin_buf, TSIN_BUF_SIZE); - } - if (dev->card_info->io_type[2] & NGENE_IO_AIN) { - dev->ain_buf = vmalloc(AIN_BUF_SIZE); - if (!dev->ain_buf) - return -ENOMEM; - dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE); - } - if (dev->card_info->io_type[0] & NGENE_IO_HDTV) { - dev->vin_buf = vmalloc(VIN_BUF_SIZE); - if (!dev->vin_buf) - return -ENOMEM; - dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE); - } - dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0), - pci_resource_len(dev->pci_dev, 0)); - if (!dev->iomem) - return -ENOMEM; - - return 0; -} - -static void ngene_init(struct ngene *dev) -{ - int i; - - tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev); - - memset_io(dev->iomem + 0xc000, 0x00, 0x220); - memset_io(dev->iomem + 0xc400, 0x00, 0x100); - - for (i = 0; i < MAX_STREAM; i++) { - dev->channel[i].dev = dev; - dev->channel[i].number = i; - } - - dev->fw_interface_version = 0; - - ngwritel(0, NGENE_INT_ENABLE); - - dev->icounts = ngreadl(NGENE_INT_COUNTS); - - dev->device_version = ngreadl(DEV_VER) & 0x0f; - printk(KERN_INFO DEVICE_NAME ": Device version %d\n", - dev->device_version); -} - -static int ngene_load_firm(struct ngene *dev) -{ - u32 size; - const struct firmware *fw = NULL; - u8 *ngene_fw; - char *fw_name; - int err, version; - - version = dev->card_info->fw_version; - - switch (version) { - default: - case 15: - version = 15; - size = 23466; - fw_name = "ngene_15.fw"; - dev->cmd_timeout_workaround = true; - break; - case 16: - size = 23498; - fw_name = "ngene_16.fw"; - dev->cmd_timeout_workaround = true; - break; - case 17: - size = 24446; - fw_name = "ngene_17.fw"; - dev->cmd_timeout_workaround = true; - break; - case 18: - size = 0; - fw_name = "ngene_18.fw"; - break; - } - - if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { - printk(KERN_ERR DEVICE_NAME - ": Could not load firmware file %s.\n", fw_name); - printk(KERN_INFO DEVICE_NAME - ": Copy %s to your hotplug directory!\n", fw_name); - return -1; - } - if (size == 0) - size = fw->size; - if (size != fw->size) { - printk(KERN_ERR DEVICE_NAME - ": Firmware %s has invalid size!", fw_name); - err = -1; - } else { - printk(KERN_INFO DEVICE_NAME - ": Loading firmware file %s.\n", fw_name); - ngene_fw = (u8 *) fw->data; - err = ngene_command_load_firmware(dev, ngene_fw, size); - } - - release_firmware(fw); - - return err; -} - -static void ngene_stop(struct ngene *dev) -{ - down(&dev->cmd_mutex); - i2c_del_adapter(&(dev->channel[0].i2c_adapter)); - i2c_del_adapter(&(dev->channel[1].i2c_adapter)); - ngwritel(0, NGENE_INT_ENABLE); - ngwritel(0, NGENE_COMMAND); - ngwritel(0, NGENE_COMMAND_HI); - ngwritel(0, NGENE_STATUS); - ngwritel(0, NGENE_STATUS_HI); - ngwritel(0, NGENE_EVENT); - ngwritel(0, NGENE_EVENT_HI); - free_irq(dev->pci_dev->irq, dev); -#ifdef CONFIG_PCI_MSI - if (dev->msi_enabled) - pci_disable_msi(dev->pci_dev); -#endif -} - -static int ngene_buffer_config(struct ngene *dev) -{ - int stat; - - if (dev->card_info->fw_version >= 17) { - u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }; - u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 }; - u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 }; - u8 *bconf = tsin12_config; - - if (dev->card_info->io_type[2]&NGENE_IO_TSIN && - dev->card_info->io_type[3]&NGENE_IO_TSIN) { - bconf = tsin1234_config; - if (dev->card_info->io_type[4]&NGENE_IO_TSOUT && - dev->ci.en) - bconf = tsio1235_config; - } - stat = ngene_command_config_free_buf(dev, bconf); - } else { - int bconf = BUFFER_CONFIG_4422; - - if (dev->card_info->io_type[3] == NGENE_IO_TSIN) - bconf = BUFFER_CONFIG_3333; - stat = ngene_command_config_buf(dev, bconf); - } - return stat; -} - - -static int ngene_start(struct ngene *dev) -{ - int stat; - int i; - - pci_set_master(dev->pci_dev); - ngene_init(dev); - - stat = request_irq(dev->pci_dev->irq, irq_handler, - IRQF_SHARED, "nGene", - (void *)dev); - if (stat < 0) - return stat; - - init_waitqueue_head(&dev->cmd_wq); - init_waitqueue_head(&dev->tx_wq); - init_waitqueue_head(&dev->rx_wq); - sema_init(&dev->cmd_mutex, 1); - sema_init(&dev->stream_mutex, 1); - sema_init(&dev->pll_mutex, 1); - sema_init(&dev->i2c_switch_mutex, 1); - spin_lock_init(&dev->cmd_lock); - for (i = 0; i < MAX_STREAM; i++) - spin_lock_init(&dev->channel[i].state_lock); - ngwritel(1, TIMESTAMPS); - - ngwritel(1, NGENE_INT_ENABLE); - - stat = ngene_load_firm(dev); - if (stat < 0) - goto fail; - -#ifdef CONFIG_PCI_MSI - /* enable MSI if kernel and card support it */ - if (pci_msi_enabled() && dev->card_info->msi_supported) { - unsigned long flags; - - ngwritel(0, NGENE_INT_ENABLE); - free_irq(dev->pci_dev->irq, dev); - stat = pci_enable_msi(dev->pci_dev); - if (stat) { - printk(KERN_INFO DEVICE_NAME - ": MSI not available\n"); - flags = IRQF_SHARED; - } else { - flags = 0; - dev->msi_enabled = true; - } - stat = request_irq(dev->pci_dev->irq, irq_handler, - flags, "nGene", dev); - if (stat < 0) - goto fail2; - ngwritel(1, NGENE_INT_ENABLE); - } -#endif - - stat = ngene_i2c_init(dev, 0); - if (stat < 0) - goto fail; - - stat = ngene_i2c_init(dev, 1); - if (stat < 0) - goto fail; - - if (!stat) - return stat; - - /* otherwise error: fall through */ -fail: - ngwritel(0, NGENE_INT_ENABLE); - free_irq(dev->pci_dev->irq, dev); -#ifdef CONFIG_PCI_MSI -fail2: - if (dev->msi_enabled) - pci_disable_msi(dev->pci_dev); -#endif - return stat; -} - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -static void release_channel(struct ngene_channel *chan) -{ - struct dvb_demux *dvbdemux = &chan->demux; - struct ngene *dev = chan->dev; - - if (chan->running) - set_transfer(chan, 0); - - tasklet_kill(&chan->demux_tasklet); - - if (chan->ci_dev) { - dvb_unregister_device(chan->ci_dev); - chan->ci_dev = NULL; - } - - if (chan->fe) { - dvb_unregister_frontend(chan->fe); - dvb_frontend_detach(chan->fe); - chan->fe = NULL; - } - - if (chan->has_demux) { - dvb_net_release(&chan->dvbnet); - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &chan->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &chan->mem_frontend); - dvb_dmxdev_release(&chan->dmxdev); - dvb_dmx_release(&chan->demux); - chan->has_demux = false; - } - - if (chan->has_adapter) { - dvb_unregister_adapter(&dev->adapter[chan->number]); - chan->has_adapter = false; - } -} - -static int init_channel(struct ngene_channel *chan) -{ - int ret = 0, nr = chan->number; - struct dvb_adapter *adapter = NULL; - struct dvb_demux *dvbdemux = &chan->demux; - struct ngene *dev = chan->dev; - struct ngene_info *ni = dev->card_info; - int io = ni->io_type[nr]; - - tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan); - chan->users = 0; - chan->type = io; - chan->mode = chan->type; /* for now only one mode */ - - if (io & NGENE_IO_TSIN) { - chan->fe = NULL; - if (ni->demod_attach[nr]) { - ret = ni->demod_attach[nr](chan); - if (ret < 0) - goto err; - } - if (chan->fe && ni->tuner_attach[nr]) { - ret = ni->tuner_attach[nr](chan); - if (ret < 0) - goto err; - } - } - - if (!dev->ci.en && (io & NGENE_IO_TSOUT)) - return 0; - - if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { - if (nr >= STREAM_AUDIOIN1) - chan->DataFormatFlags = DF_SWAP32; - - if (nr == 0 || !one_adapter || dev->first_adapter == NULL) { - adapter = &dev->adapter[nr]; - ret = dvb_register_adapter(adapter, "nGene", - THIS_MODULE, - &chan->dev->pci_dev->dev, - adapter_nr); - if (ret < 0) - goto err; - if (dev->first_adapter == NULL) - dev->first_adapter = adapter; - chan->has_adapter = true; - } else - adapter = dev->first_adapter; - } - - if (dev->ci.en && (io & NGENE_IO_TSOUT)) { - dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); - set_transfer(chan, 1); - set_transfer(&chan->dev->channel[2], 1); - dvb_register_device(adapter, &chan->ci_dev, - &ngene_dvbdev_ci, (void *) chan, - DVB_DEVICE_SEC); - if (!chan->ci_dev) - goto err; - } - - if (chan->fe) { - if (dvb_register_frontend(adapter, chan->fe) < 0) - goto err; - chan->has_demux = true; - } - - if (chan->has_demux) { - ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", - ngene_start_feed, - ngene_stop_feed, chan); - ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, - &chan->hw_frontend, - &chan->mem_frontend, adapter); - ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx); - } - - return ret; - -err: - if (chan->fe) { - dvb_frontend_detach(chan->fe); - chan->fe = NULL; - } - release_channel(chan); - return 0; -} - -static int init_channels(struct ngene *dev) -{ - int i, j; - - for (i = 0; i < MAX_STREAM; i++) { - dev->channel[i].number = i; - if (init_channel(&dev->channel[i]) < 0) { - for (j = i - 1; j >= 0; j--) - release_channel(&dev->channel[j]); - return -1; - } - } - return 0; -} - -static void cxd_attach(struct ngene *dev) -{ - struct ngene_ci *ci = &dev->ci; - - ci->en = cxd2099_attach(0x40, dev, &dev->channel[0].i2c_adapter); - ci->dev = dev; - return; -} - -static void cxd_detach(struct ngene *dev) -{ - struct ngene_ci *ci = &dev->ci; - - dvb_ca_en50221_release(ci->en); - kfree(ci->en); - ci->en = 0; -} - -/***********************************/ -/* workaround for shutdown failure */ -/***********************************/ - -static void ngene_unlink(struct ngene *dev) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_MEM_WRITE; - com.cmd.hdr.Length = 3; - com.cmd.MemoryWrite.address = 0x910c; - com.cmd.MemoryWrite.data = 0xff; - com.in_len = 3; - com.out_len = 1; - - down(&dev->cmd_mutex); - ngwritel(0, NGENE_INT_ENABLE); - ngene_command_mutex(dev, &com); - up(&dev->cmd_mutex); -} - -void ngene_shutdown(struct pci_dev *pdev) -{ - struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev); - - if (!dev || !shutdown_workaround) - return; - - printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n"); - ngene_unlink(dev); - pci_disable_device(pdev); -} - -/****************************************************************************/ -/* device probe/remove calls ************************************************/ -/****************************************************************************/ - -void __devexit ngene_remove(struct pci_dev *pdev) -{ - struct ngene *dev = pci_get_drvdata(pdev); - int i; - - tasklet_kill(&dev->event_tasklet); - for (i = MAX_STREAM - 1; i >= 0; i--) - release_channel(&dev->channel[i]); - if (dev->ci.en) - cxd_detach(dev); - ngene_stop(dev); - ngene_release_buffers(dev); - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); -} - -int __devinit ngene_probe(struct pci_dev *pci_dev, - const struct pci_device_id *id) -{ - struct ngene *dev; - int stat = 0; - - if (pci_enable_device(pci_dev) < 0) - return -ENODEV; - - dev = vzalloc(sizeof(struct ngene)); - if (dev == NULL) { - stat = -ENOMEM; - goto fail0; - } - - dev->pci_dev = pci_dev; - dev->card_info = (struct ngene_info *)id->driver_data; - printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name); - - pci_set_drvdata(pci_dev, dev); - - /* Alloc buffers and start nGene */ - stat = ngene_get_buffers(dev); - if (stat < 0) - goto fail1; - stat = ngene_start(dev); - if (stat < 0) - goto fail1; - - cxd_attach(dev); - - stat = ngene_buffer_config(dev); - if (stat < 0) - goto fail1; - - - dev->i2c_current_bus = -1; - - /* Register DVB adapters and devices for both channels */ - if (init_channels(dev) < 0) - goto fail2; - - return 0; - -fail2: - ngene_stop(dev); -fail1: - ngene_release_buffers(dev); -fail0: - pci_disable_device(pci_dev); - pci_set_drvdata(pci_dev, NULL); - return stat; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-dvb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,231 +0,0 @@ -/* - * ngene-dvb.c: nGene PCIe bridge driver - DVB functions - * - * Copyright (C) 2005-2007 Micronas - * - * Copyright (C) 2008-2009 Ralph Metzler - * Modifications for new nGene firmware, - * support for EEPROM-copying, - * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ngene.h" - - -/****************************************************************************/ -/* COMMAND API interface ****************************************************/ -/****************************************************************************/ - -static ssize_t ts_write(struct file *file, const char *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct ngene_channel *chan = dvbdev->priv; - struct ngene *dev = chan->dev; - - if (wait_event_interruptible(dev->tsout_rbuf.queue, - dvb_ringbuffer_free - (&dev->tsout_rbuf) >= count) < 0) - return 0; - - dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count); - - return count; -} - -static ssize_t ts_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct ngene_channel *chan = dvbdev->priv; - struct ngene *dev = chan->dev; - int left, avail; - - left = count; - while (left) { - if (wait_event_interruptible( - dev->tsin_rbuf.queue, - dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0) - return -EAGAIN; - avail = dvb_ringbuffer_avail(&dev->tsin_rbuf); - if (avail > left) - avail = left; - dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail); - left -= avail; - buf += avail; - } - return count; -} - -static const struct file_operations ci_fops = { - .owner = THIS_MODULE, - .read = ts_read, - .write = ts_write, - .open = dvb_generic_open, - .release = dvb_generic_release, -}; - -struct dvb_device ngene_dvbdev_ci = { - .priv = 0, - .readers = -1, - .writers = -1, - .users = -1, - .fops = &ci_fops, -}; - - -/****************************************************************************/ -/* DVB functions and API interface ******************************************/ -/****************************************************************************/ - -static void swap_buffer(u32 *p, u32 len) -{ - while (len) { - *p = swab32(*p); - p++; - len -= 4; - } -} - -void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) -{ - struct ngene_channel *chan = priv; - struct ngene *dev = chan->dev; - - - if (flags & DF_SWAP32) - swap_buffer(buf, len); - if (dev->ci.en && chan->number == 2) { - if (dvb_ringbuffer_free(&dev->tsin_rbuf) > len) { - dvb_ringbuffer_write(&dev->tsin_rbuf, buf, len); - wake_up_interruptible(&dev->tsin_rbuf.queue); - } - return 0; - } - if (chan->users > 0) { - dvb_dmx_swfilter(&chan->demux, buf, len); - } - return NULL; -} - -u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 }; - -void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) -{ - struct ngene_channel *chan = priv; - struct ngene *dev = chan->dev; - u32 alen; - - alen = dvb_ringbuffer_avail(&dev->tsout_rbuf); - alen -= alen % 188; - - if (alen < len) - FillTSBuffer(buf + alen, len - alen, flags); - else - alen = len; - dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen); - if (flags & DF_SWAP32) - swap_buffer((u32 *)buf, alen); - wake_up_interruptible(&dev->tsout_rbuf.queue); - return buf; -} - - - -int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ngene_channel *chan = dvbdmx->priv; - - if (chan->users == 0) { - if (!chan->dev->cmd_timeout_workaround || !chan->running) - set_transfer(chan, 1); - } - - return ++chan->users; -} - -int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ngene_channel *chan = dvbdmx->priv; - - if (--chan->users) - return chan->users; - - if (!chan->dev->cmd_timeout_workaround) - set_transfer(chan, 0); - - return 0; -} - -int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, - int (*start_feed)(struct dvb_demux_feed *), - int (*stop_feed)(struct dvb_demux_feed *), - void *priv) -{ - dvbdemux->priv = priv; - - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = start_feed; - dvbdemux->stop_feed = stop_feed; - dvbdemux->write_to_decoder = NULL; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - return dvb_dmx_init(dvbdemux); -} - -int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, - struct dvb_demux *dvbdemux, - struct dmx_frontend *hw_frontend, - struct dmx_frontend *mem_frontend, - struct dvb_adapter *dvb_adapter) -{ - int ret; - - dmxdev->filternum = 256; - dmxdev->demux = &dvbdemux->dmx; - dmxdev->capabilities = 0; - ret = dvb_dmxdev_init(dmxdev, dvb_adapter); - if (ret < 0) - return ret; - - hw_frontend->source = DMX_FRONTEND_0; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); - mem_frontend->source = DMX_MEMORY_FE; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); - return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,916 +0,0 @@ -/* - * ngene.h: nGene PCIe bridge driver - * - * Copyright (C) 2005-2007 Micronas - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#ifndef _NGENE_H_ -#define _NGENE_H_ - -#include -#include -#include -#include -#include -#include - -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_ca_en50221.h" -#include "dvb_frontend.h" -#include "dvb_ringbuffer.h" -#include "dvb_net.h" -#include "cxd2099.h" - -#define DEVICE_NAME "ngene" - -#define NGENE_VID 0x18c3 -#define NGENE_PID 0x0720 - -#ifndef VIDEO_CAP_VC1 -#define VIDEO_CAP_AVC 128 -#define VIDEO_CAP_H264 128 -#define VIDEO_CAP_VC1 256 -#define VIDEO_CAP_WMV9 256 -#define VIDEO_CAP_MPEG4 512 -#endif - -enum STREAM { - STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ - STREAM_VIDEOIN2, - STREAM_AUDIOIN1, /* I2S or SPI Input */ - STREAM_AUDIOIN2, - STREAM_AUDIOOUT, - MAX_STREAM -}; - -enum SMODE_BITS { - SMODE_AUDIO_SPDIF = 0x20, - SMODE_AVSYNC = 0x10, - SMODE_TRANSPORT_STREAM = 0x08, - SMODE_AUDIO_CAPTURE = 0x04, - SMODE_VBI_CAPTURE = 0x02, - SMODE_VIDEO_CAPTURE = 0x01 -}; - -enum STREAM_FLAG_BITS { - SFLAG_CHROMA_FORMAT_2COMP = 0x01, /* Chroma Format : 2's complement */ - SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */ - SFLAG_ORDER_LUMA_CHROMA = 0x02, /* Byte order: Y,Cb,Y,Cr */ - SFLAG_ORDER_CHROMA_LUMA = 0x00, /* Byte order: Cb,Y,Cr,Y */ - SFLAG_COLORBAR = 0x04, /* Select colorbar */ -}; - -#define PROGRAM_ROM 0x0000 -#define PROGRAM_SRAM 0x1000 -#define PERIPHERALS0 0x8000 -#define PERIPHERALS1 0x9000 -#define SHARED_BUFFER 0xC000 - -#define HOST_TO_NGENE (SHARED_BUFFER+0x0000) -#define NGENE_TO_HOST (SHARED_BUFFER+0x0100) -#define NGENE_COMMAND (SHARED_BUFFER+0x0200) -#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204) -#define NGENE_STATUS (SHARED_BUFFER+0x0208) -#define NGENE_STATUS_HI (SHARED_BUFFER+0x020C) -#define NGENE_EVENT (SHARED_BUFFER+0x0210) -#define NGENE_EVENT_HI (SHARED_BUFFER+0x0214) -#define VARIABLES (SHARED_BUFFER+0x0210) - -#define NGENE_INT_COUNTS (SHARED_BUFFER+0x0260) -#define NGENE_INT_ENABLE (SHARED_BUFFER+0x0264) -#define NGENE_VBI_LINE_COUNT (SHARED_BUFFER+0x0268) - -#define BUFFER_GP_XMIT (SHARED_BUFFER+0x0800) -#define BUFFER_GP_RECV (SHARED_BUFFER+0x0900) -#define EEPROM_AREA (SHARED_BUFFER+0x0A00) - -#define SG_V_IN_1 (SHARED_BUFFER+0x0A80) -#define SG_VBI_1 (SHARED_BUFFER+0x0B00) -#define SG_A_IN_1 (SHARED_BUFFER+0x0B80) -#define SG_V_IN_2 (SHARED_BUFFER+0x0C00) -#define SG_VBI_2 (SHARED_BUFFER+0x0C80) -#define SG_A_IN_2 (SHARED_BUFFER+0x0D00) -#define SG_V_OUT (SHARED_BUFFER+0x0D80) -#define SG_A_OUT2 (SHARED_BUFFER+0x0E00) - -#define DATA_A_IN_1 (SHARED_BUFFER+0x0E80) -#define DATA_A_IN_2 (SHARED_BUFFER+0x0F00) -#define DATA_A_OUT (SHARED_BUFFER+0x0F80) -#define DATA_V_IN_1 (SHARED_BUFFER+0x1000) -#define DATA_V_IN_2 (SHARED_BUFFER+0x2000) -#define DATA_V_OUT (SHARED_BUFFER+0x3000) - -#define DATA_FIFO_AREA (SHARED_BUFFER+0x1000) - -#define TIMESTAMPS 0xA000 -#define SCRATCHPAD 0xA080 -#define FORCE_INT 0xA088 -#define FORCE_NMI 0xA090 -#define INT_STATUS 0xA0A0 - -#define DEV_VER 0x9004 - -#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF) - -struct SG_ADDR { - u64 start; - u64 curr; - u16 curr_ptr; - u16 elements; - u32 pad[3]; -} __attribute__ ((__packed__)); - -struct SHARED_MEMORY { - /* C000 */ - u32 HostToNgene[64]; - - /* C100 */ - u32 NgeneToHost[64]; - - /* C200 */ - u64 NgeneCommand; - u64 NgeneStatus; - u64 NgeneEvent; - - /* C210 */ - u8 pad1[0xc260 - 0xc218]; - - /* C260 */ - u32 IntCounts; - u32 IntEnable; - - /* C268 */ - u8 pad2[0xd000 - 0xc268]; - -} __attribute__ ((__packed__)); - -struct BUFFER_STREAM_RESULTS { - u32 Clock; /* Stream time in 100ns units */ - u16 RemainingLines; /* Remaining lines in this field. - 0 for complete field */ - u8 FieldCount; /* Video field number */ - u8 Flags; /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow, - Bit 0 = FieldID */ - u16 BlockCount; /* Audio block count (unused) */ - u8 Reserved[2]; - u32 DTOUpdate; -} __attribute__ ((__packed__)); - -struct HW_SCATTER_GATHER_ELEMENT { - u64 Address; - u32 Length; - u32 Reserved; -} __attribute__ ((__packed__)); - -struct BUFFER_HEADER { - u64 Next; - struct BUFFER_STREAM_RESULTS SR; - - u32 Number_of_entries_1; - u32 Reserved5; - u64 Address_of_first_entry_1; - - u32 Number_of_entries_2; - u32 Reserved7; - u64 Address_of_first_entry_2; -} __attribute__ ((__packed__)); - -struct EVENT_BUFFER { - u32 TimeStamp; - u8 GPIOStatus; - u8 UARTStatus; - u8 RXCharacter; - u8 EventStatus; - u32 Reserved[2]; -} __attribute__ ((__packed__)); - -/* Firmware commands. */ - -enum OPCODES { - CMD_NOP = 0, - CMD_FWLOAD_PREPARE = 0x01, - CMD_FWLOAD_FINISH = 0x02, - CMD_I2C_READ = 0x03, - CMD_I2C_WRITE = 0x04, - - CMD_I2C_WRITE_NOSTOP = 0x05, - CMD_I2C_CONTINUE_WRITE = 0x06, - CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07, - - CMD_DEBUG_OUTPUT = 0x09, - - CMD_CONTROL = 0x10, - CMD_CONFIGURE_BUFFER = 0x11, - CMD_CONFIGURE_FREE_BUFFER = 0x12, - - CMD_SPI_READ = 0x13, - CMD_SPI_WRITE = 0x14, - - CMD_MEM_READ = 0x20, - CMD_MEM_WRITE = 0x21, - CMD_SFR_READ = 0x22, - CMD_SFR_WRITE = 0x23, - CMD_IRAM_READ = 0x24, - CMD_IRAM_WRITE = 0x25, - CMD_SET_GPIO_PIN = 0x26, - CMD_SET_GPIO_INT = 0x27, - CMD_CONFIGURE_UART = 0x28, - CMD_WRITE_UART = 0x29, - MAX_CMD -}; - -enum RESPONSES { - OK = 0, - ERROR = 1 -}; - -struct FW_HEADER { - u8 Opcode; - u8 Length; -} __attribute__ ((__packed__)); - -struct FW_I2C_WRITE { - struct FW_HEADER hdr; - u8 Device; - u8 Data[250]; -} __attribute__ ((__packed__)); - -struct FW_I2C_CONTINUE_WRITE { - struct FW_HEADER hdr; - u8 Data[250]; -} __attribute__ ((__packed__)); - -struct FW_I2C_READ { - struct FW_HEADER hdr; - u8 Device; - u8 Data[252]; /* followed by two bytes of read data count */ -} __attribute__ ((__packed__)); - -struct FW_SPI_WRITE { - struct FW_HEADER hdr; - u8 ModeSelect; - u8 Data[250]; -} __attribute__ ((__packed__)); - -struct FW_SPI_READ { - struct FW_HEADER hdr; - u8 ModeSelect; - u8 Data[252]; /* followed by two bytes of read data count */ -} __attribute__ ((__packed__)); - -struct FW_FWLOAD_PREPARE { - struct FW_HEADER hdr; -} __attribute__ ((__packed__)); - -struct FW_FWLOAD_FINISH { - struct FW_HEADER hdr; - u16 Address; /* address of final block */ - u16 Length; -} __attribute__ ((__packed__)); - -/* - * Meaning of FW_STREAM_CONTROL::Mode bits: - * Bit 7: Loopback PEXin to PEXout using TVOut channel - * Bit 6: AVLOOP - * Bit 5: Audio select; 0=I2S, 1=SPDIF - * Bit 4: AVSYNC - * Bit 3: Enable transport stream - * Bit 2: Enable audio capture - * Bit 1: Enable ITU-Video VBI capture - * Bit 0: Enable ITU-Video capture - * - * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL) - * Bit 7: continuous capture - * Bit 6: capture one field - * Bit 5: capture one frame - * Bit 4: unused - * Bit 3: starting field; 0=odd, 1=even - * Bit 2: sample size; 0=8-bit, 1=10-bit - * Bit 1: data format; 0=UYVY, 1=YUY2 - * Bit 0: resets buffer pointers -*/ - -enum FSC_MODE_BITS { - SMODE_LOOPBACK = 0x80, - SMODE_AVLOOP = 0x40, - _SMODE_AUDIO_SPDIF = 0x20, - _SMODE_AVSYNC = 0x10, - _SMODE_TRANSPORT_STREAM = 0x08, - _SMODE_AUDIO_CAPTURE = 0x04, - _SMODE_VBI_CAPTURE = 0x02, - _SMODE_VIDEO_CAPTURE = 0x01 -}; - - -/* Meaning of FW_STREAM_CONTROL::Stream bits: - * Bit 3: Audio sample count: 0 = relative, 1 = absolute - * Bit 2: color bar select; 1=color bars, 0=CV3 decoder - * Bits 1-0: stream select, UVI1, UVI2, TVOUT - */ - -struct FW_STREAM_CONTROL { - struct FW_HEADER hdr; - u8 Stream; /* Stream number (UVI1, UVI2, TVOUT) */ - u8 Control; /* Value written to UVI1_CTL */ - u8 Mode; /* Controls clock source */ - u8 SetupDataLen; /* Length of setup data, MSB=1 write - backwards */ - u16 CaptureBlockCount; /* Blocks (a 256 Bytes) to capture per buffer - for TS and Audio */ - u64 Buffer_Address; /* Address of first buffer header */ - u16 BytesPerVideoLine; - u16 MaxLinesPerField; - u16 MinLinesPerField; - u16 Reserved_1; - u16 BytesPerVBILine; - u16 MaxVBILinesPerField; - u16 MinVBILinesPerField; - u16 SetupDataAddr; /* ngene relative address of setup data */ - u8 SetupData[32]; /* setup data */ -} __attribute__((__packed__)); - -#define AUDIO_BLOCK_SIZE 256 -#define TS_BLOCK_SIZE 256 - -struct FW_MEM_READ { - struct FW_HEADER hdr; - u16 address; -} __attribute__ ((__packed__)); - -struct FW_MEM_WRITE { - struct FW_HEADER hdr; - u16 address; - u8 data; -} __attribute__ ((__packed__)); - -struct FW_SFR_IRAM_READ { - struct FW_HEADER hdr; - u8 address; -} __attribute__ ((__packed__)); - -struct FW_SFR_IRAM_WRITE { - struct FW_HEADER hdr; - u8 address; - u8 data; -} __attribute__ ((__packed__)); - -struct FW_SET_GPIO_PIN { - struct FW_HEADER hdr; - u8 select; -} __attribute__ ((__packed__)); - -struct FW_SET_GPIO_INT { - struct FW_HEADER hdr; - u8 select; -} __attribute__ ((__packed__)); - -struct FW_SET_DEBUGMODE { - struct FW_HEADER hdr; - u8 debug_flags; -} __attribute__ ((__packed__)); - -struct FW_CONFIGURE_BUFFERS { - struct FW_HEADER hdr; - u8 config; -} __attribute__ ((__packed__)); - -enum _BUFFER_CONFIGS { - /* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2 (standard usage) */ - BUFFER_CONFIG_4422 = 0, - /* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2 (4x TS input usage) */ - BUFFER_CONFIG_3333 = 1, - /* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut (HDTV decoder usage) */ - BUFFER_CONFIG_8022 = 2, - BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */ -}; - -struct FW_CONFIGURE_FREE_BUFFERS { - struct FW_HEADER hdr; - u8 UVI1_BufferLength; - u8 UVI2_BufferLength; - u8 TVO_BufferLength; - u8 AUD1_BufferLength; - u8 AUD2_BufferLength; - u8 TVA_BufferLength; -} __attribute__ ((__packed__)); - -struct FW_CONFIGURE_UART { - struct FW_HEADER hdr; - u8 UartControl; -} __attribute__ ((__packed__)); - -enum _UART_CONFIG { - _UART_BAUDRATE_19200 = 0, - _UART_BAUDRATE_9600 = 1, - _UART_BAUDRATE_4800 = 2, - _UART_BAUDRATE_2400 = 3, - _UART_RX_ENABLE = 0x40, - _UART_TX_ENABLE = 0x80, -}; - -struct FW_WRITE_UART { - struct FW_HEADER hdr; - u8 Data[252]; -} __attribute__ ((__packed__)); - - -struct ngene_command { - u32 in_len; - u32 out_len; - union { - u32 raw[64]; - u8 raw8[256]; - struct FW_HEADER hdr; - struct FW_I2C_WRITE I2CWrite; - struct FW_I2C_CONTINUE_WRITE I2CContinueWrite; - struct FW_I2C_READ I2CRead; - struct FW_STREAM_CONTROL StreamControl; - struct FW_FWLOAD_PREPARE FWLoadPrepare; - struct FW_FWLOAD_FINISH FWLoadFinish; - struct FW_MEM_READ MemoryRead; - struct FW_MEM_WRITE MemoryWrite; - struct FW_SFR_IRAM_READ SfrIramRead; - struct FW_SFR_IRAM_WRITE SfrIramWrite; - struct FW_SPI_WRITE SPIWrite; - struct FW_SPI_READ SPIRead; - struct FW_SET_GPIO_PIN SetGpioPin; - struct FW_SET_GPIO_INT SetGpioInt; - struct FW_SET_DEBUGMODE SetDebugMode; - struct FW_CONFIGURE_BUFFERS ConfigureBuffers; - struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers; - struct FW_CONFIGURE_UART ConfigureUart; - struct FW_WRITE_UART WriteUart; - } cmd; -} __attribute__ ((__packed__)); - -#define NGENE_INTERFACE_VERSION 0x103 -#define MAX_VIDEO_BUFFER_SIZE (417792) /* 288*1440 rounded up to next page */ -#define MAX_AUDIO_BUFFER_SIZE (8192) /* Gives room for about 23msec@48KHz */ -#define MAX_VBI_BUFFER_SIZE (28672) /* 1144*18 rounded up to next page */ -#define MAX_TS_BUFFER_SIZE (98304) /* 512*188 rounded up to next page */ -#define MAX_HDTV_BUFFER_SIZE (2080768) /* 541*1920*2 rounded up to next page - Max: (1920x1080i60) */ - -#define OVERFLOW_BUFFER_SIZE (8192) - -#define RING_SIZE_VIDEO 4 -#define RING_SIZE_AUDIO 8 -#define RING_SIZE_TS 8 - -#define NUM_SCATTER_GATHER_ENTRIES 8 - -#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \ - RING_SIZE_VIDEO * 2) + \ - (MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \ - (MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \ - (RING_SIZE_VIDEO * PAGE_SIZE * 2) + \ - (RING_SIZE_AUDIO * PAGE_SIZE * 2) + \ - (RING_SIZE_TS * PAGE_SIZE * 4) + \ - 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE) - -#define EVENT_QUEUE_SIZE 16 - -/* Gathers the current state of a single channel. */ - -struct SBufferHeader { - struct BUFFER_HEADER ngeneBuffer; /* Physical descriptor */ - struct SBufferHeader *Next; - void *Buffer1; - struct HW_SCATTER_GATHER_ELEMENT *scList1; - void *Buffer2; - struct HW_SCATTER_GATHER_ELEMENT *scList2; -}; - -/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */ -#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63) - -enum HWSTATE { - HWSTATE_STOP, - HWSTATE_STARTUP, - HWSTATE_RUN, - HWSTATE_PAUSE, -}; - -enum KSSTATE { - KSSTATE_STOP, - KSSTATE_ACQUIRE, - KSSTATE_PAUSE, - KSSTATE_RUN, -}; - -struct SRingBufferDescriptor { - struct SBufferHeader *Head; /* Points to first buffer in ring buffer - structure*/ - u64 PAHead; /* Physical address of first buffer */ - u32 MemSize; /* Memory size of allocated ring buffers - (needed for freeing) */ - u32 NumBuffers; /* Number of buffers in the ring */ - u32 Buffer1Length; /* Allocated length of Buffer 1 */ - u32 Buffer2Length; /* Allocated length of Buffer 2 */ - void *SCListMem; /* Memory to hold scatter gather lists for this - ring */ - u64 PASCListMem; /* Physical address .. */ - u32 SCListMemSize; /* Size of this memory */ -}; - -enum STREAMMODEFLAGS { - StreamMode_NONE = 0, /* Stream not used */ - StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */ - StreamMode_TSIN = 2, /* Transport stream input (all) */ - StreamMode_HDTV = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60 - (only stream 0) */ - StreamMode_TSOUT = 8, /* Transport stream output (only stream 3) */ -}; - - -enum BufferExchangeFlags { - BEF_EVEN_FIELD = 0x00000001, - BEF_CONTINUATION = 0x00000002, - BEF_MORE_DATA = 0x00000004, - BEF_OVERFLOW = 0x00000008, - DF_SWAP32 = 0x00010000, -}; - -typedef void *(IBufferExchange)(void *, void *, u32, u32, u32); - -struct MICI_STREAMINFO { - IBufferExchange *pExchange; - IBufferExchange *pExchangeVBI; /* Secondary (VBI, ancillary) */ - u8 Stream; - u8 Flags; - u8 Mode; - u8 Reserved; - u16 nLinesVideo; - u16 nBytesPerLineVideo; - u16 nLinesVBI; - u16 nBytesPerLineVBI; - u32 CaptureLength; /* Used for audio and transport stream */ -}; - -/****************************************************************************/ -/* STRUCTS ******************************************************************/ -/****************************************************************************/ - -/* sound hardware definition */ -#define MIXER_ADDR_TVTUNER 0 -#define MIXER_ADDR_LAST 0 - -struct ngene_channel; - -/*struct sound chip*/ - -struct mychip { - struct ngene_channel *chan; - struct snd_card *card; - struct pci_dev *pci; - struct snd_pcm_substream *substream; - struct snd_pcm *pcm; - unsigned long port; - int irq; - spinlock_t mixer_lock; - spinlock_t lock; - int mixer_volume[MIXER_ADDR_LAST + 1][2]; - int capture_source[MIXER_ADDR_LAST + 1][2]; -}; - -#ifdef NGENE_V4L -struct ngene_overlay { - int tvnorm; - struct v4l2_rect w; - enum v4l2_field field; - struct v4l2_clip *clips; - int nclips; - int setup_ok; -}; - -struct ngene_tvnorm { - int v4l2_id; - char *name; - u16 swidth, sheight; /* scaled standard width, height */ - int tuner_norm; - int soundstd; -}; - -struct ngene_vopen { - struct ngene_channel *ch; - enum v4l2_priority prio; - int width; - int height; - int depth; - struct videobuf_queue vbuf_q; - struct videobuf_queue vbi; - int fourcc; - int picxcount; - int resources; - enum v4l2_buf_type type; - const struct ngene_format *fmt; - - const struct ngene_format *ovfmt; - struct ngene_overlay ov; -}; -#endif - -struct ngene_channel { - struct device device; - struct i2c_adapter i2c_adapter; - - struct ngene *dev; - int number; - int type; - int mode; - bool has_adapter; - bool has_demux; - - struct dvb_frontend *fe; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvbnet; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - int users; - struct video_device *v4l_dev; - struct dvb_device *ci_dev; - struct tasklet_struct demux_tasklet; - - struct SBufferHeader *nextBuffer; - enum KSSTATE State; - enum HWSTATE HWState; - u8 Stream; - u8 Flags; - u8 Mode; - IBufferExchange *pBufferExchange; - IBufferExchange *pBufferExchange2; - - spinlock_t state_lock; - u16 nLines; - u16 nBytesPerLine; - u16 nVBILines; - u16 nBytesPerVBILine; - u16 itumode; - u32 Capture1Length; - u32 Capture2Length; - struct SRingBufferDescriptor RingBuffer; - struct SRingBufferDescriptor TSRingBuffer; - struct SRingBufferDescriptor TSIdleBuffer; - - u32 DataFormatFlags; - - int AudioDTOUpdated; - u32 AudioDTOValue; - - int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t); - u8 lnbh; - - /* stuff from analog driver */ - - int minor; - struct mychip *mychip; - struct snd_card *soundcard; - u8 *evenbuffer; - u8 dma_on; - int soundstreamon; - int audiomute; - int soundbuffisallocated; - int sndbuffflag; - int tun_rdy; - int dec_rdy; - int tun_dec_rdy; - int lastbufferflag; - - struct ngene_tvnorm *tvnorms; - int tvnorm_num; - int tvnorm; - -#ifdef NGENE_V4L - int videousers; - struct v4l2_prio_state prio; - struct ngene_vopen init; - int resources; - struct v4l2_framebuffer fbuf; - struct ngene_buffer *screen; /* overlay */ - struct list_head capture; /* video capture queue */ - spinlock_t s_lock; - struct semaphore reslock; -#endif - - int running; -}; - - -struct ngene_ci { - struct device device; - struct i2c_adapter i2c_adapter; - - struct ngene *dev; - struct dvb_ca_en50221 *en; -}; - -struct ngene; - -typedef void (rx_cb_t)(struct ngene *, u32, u8); -typedef void (tx_cb_t)(struct ngene *, u32); - -struct ngene { - int nr; - struct pci_dev *pci_dev; - unsigned char *iomem; - - /*struct i2c_adapter i2c_adapter;*/ - - u32 device_version; - u32 fw_interface_version; - u32 icounts; - bool msi_enabled; - bool cmd_timeout_workaround; - - u8 *CmdDoneByte; - int BootFirmware; - void *OverflowBuffer; - dma_addr_t PAOverflowBuffer; - void *FWInterfaceBuffer; - dma_addr_t PAFWInterfaceBuffer; - u8 *ngenetohost; - u8 *hosttongene; - - struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; - int EventQueueOverflowCount; - int EventQueueOverflowFlag; - struct tasklet_struct event_tasklet; - struct EVENT_BUFFER *EventBuffer; - int EventQueueWriteIndex; - int EventQueueReadIndex; - - wait_queue_head_t cmd_wq; - int cmd_done; - struct semaphore cmd_mutex; - struct semaphore stream_mutex; - struct semaphore pll_mutex; - struct semaphore i2c_switch_mutex; - int i2c_current_channel; - int i2c_current_bus; - spinlock_t cmd_lock; - - struct dvb_adapter adapter[MAX_STREAM]; - struct dvb_adapter *first_adapter; /* "one_adapter" modprobe opt */ - struct ngene_channel channel[MAX_STREAM]; - - struct ngene_info *card_info; - - tx_cb_t *TxEventNotify; - rx_cb_t *RxEventNotify; - int tx_busy; - wait_queue_head_t tx_wq; - wait_queue_head_t rx_wq; -#define UART_RBUF_LEN 4096 - u8 uart_rbuf[UART_RBUF_LEN]; - int uart_rp, uart_wp; - - u8 *tsout_buf; -#define TSOUT_BUF_SIZE (512*188*8) - struct dvb_ringbuffer tsout_rbuf; - - u8 *tsin_buf; -#define TSIN_BUF_SIZE (512*188*8) - struct dvb_ringbuffer tsin_rbuf; - - u8 *ain_buf; -#define AIN_BUF_SIZE (128*1024) - struct dvb_ringbuffer ain_rbuf; - - - u8 *vin_buf; -#define VIN_BUF_SIZE (4*1920*1080) - struct dvb_ringbuffer vin_rbuf; - - unsigned long exp_val; - int prev_cmd; - - struct ngene_ci ci; -}; - -struct ngene_info { - int type; -#define NGENE_APP 0 -#define NGENE_TERRATEC 1 -#define NGENE_SIDEWINDER 2 -#define NGENE_RACER 3 -#define NGENE_VIPER 4 -#define NGENE_PYTHON 5 -#define NGENE_VBOX_V1 6 -#define NGENE_VBOX_V2 7 - - int fw_version; - bool msi_supported; - char *name; - - int io_type[MAX_STREAM]; -#define NGENE_IO_NONE 0 -#define NGENE_IO_TV 1 -#define NGENE_IO_HDTV 2 -#define NGENE_IO_TSIN 4 -#define NGENE_IO_TSOUT 8 -#define NGENE_IO_AIN 16 - - void *fe_config[4]; - void *tuner_config[4]; - - int (*demod_attach[4])(struct ngene_channel *); - int (*tuner_attach[4])(struct ngene_channel *); - - u8 avf[4]; - u8 msp[4]; - u8 demoda[4]; - u8 lnb[4]; - int i2c_access; - u8 ntsc; - u8 tsf[4]; - u8 i2s[4]; - - int (*gate_ctrl)(struct dvb_frontend *, int); - int (*switch_ctrl)(struct ngene_channel *, int, int); -}; - -#ifdef NGENE_V4L -struct ngene_format{ - char *name; - int fourcc; /* video4linux 2 */ - int btformat; /* BT848_COLOR_FMT_* */ - int format; - int btswap; /* BT848_COLOR_CTL_* */ - int depth; /* bit/pixel */ - int flags; - int hshift, vshift; /* for planar modes */ - int palette; -}; - -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 - -struct ngene_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* ngene specific */ - const struct ngene_format *fmt; - int tvnorm; - int btformat; - int btswap; -}; -#endif - - -/* Provided by ngene-core.c */ -int __devinit ngene_probe(struct pci_dev *pci_dev, - const struct pci_device_id *id); -void __devexit ngene_remove(struct pci_dev *pdev); -void ngene_shutdown(struct pci_dev *pdev); -int ngene_command(struct ngene *dev, struct ngene_command *com); -int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); -void set_transfer(struct ngene_channel *chan, int state); -void FillTSBuffer(void *Buffer, int Length, u32 Flags); - -/* Provided by ngene-i2c.c */ -int ngene_i2c_init(struct ngene *dev, int dev_nr); - -/* Provided by ngene-dvb.c */ -extern struct dvb_device ngene_dvbdev_ci; -void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); -void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); -int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed); -int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed); -int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, - int (*start_feed)(struct dvb_demux_feed *), - int (*stop_feed)(struct dvb_demux_feed *), - void *priv); -int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, - struct dvb_demux *dvbdemux, - struct dmx_frontend *hw_frontend, - struct dmx_frontend *mem_frontend, - struct dvb_adapter *dvb_adapter); - -#endif - -/* LocalWords: Endif - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-i2c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ngene/ngene-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,176 +0,0 @@ -/* - * ngene-i2c.c: nGene PCIe bridge driver i2c functions - * - * Copyright (C) 2005-2007 Micronas - * - * Copyright (C) 2008-2009 Ralph Metzler - * Modifications for new nGene firmware, - * support for EEPROM-copying, - * support for new dual DVB-S2 card prototype - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -/* FIXME - some of these can probably be removed */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ngene.h" - -/* Firmware command for i2c operations */ -static int ngene_command_i2c_read(struct ngene *dev, u8 adr, - u8 *out, u8 outlen, u8 *in, u8 inlen, int flag) -{ - struct ngene_command com; - - com.cmd.hdr.Opcode = CMD_I2C_READ; - com.cmd.hdr.Length = outlen + 3; - com.cmd.I2CRead.Device = adr << 1; - memcpy(com.cmd.I2CRead.Data, out, outlen); - com.cmd.I2CRead.Data[outlen] = inlen; - com.cmd.I2CRead.Data[outlen + 1] = 0; - com.in_len = outlen + 3; - com.out_len = inlen + 1; - - if (ngene_command(dev, &com) < 0) - return -EIO; - - if ((com.cmd.raw8[0] >> 1) != adr) - return -EIO; - - if (flag) - memcpy(in, com.cmd.raw8, inlen + 1); - else - memcpy(in, com.cmd.raw8 + 1, inlen); - return 0; -} - -static int ngene_command_i2c_write(struct ngene *dev, u8 adr, - u8 *out, u8 outlen) -{ - struct ngene_command com; - - - com.cmd.hdr.Opcode = CMD_I2C_WRITE; - com.cmd.hdr.Length = outlen + 1; - com.cmd.I2CRead.Device = adr << 1; - memcpy(com.cmd.I2CRead.Data, out, outlen); - com.in_len = outlen + 1; - com.out_len = 1; - - if (ngene_command(dev, &com) < 0) - return -EIO; - - if (com.cmd.raw8[0] == 1) - return -EIO; - - return 0; -} - -static void ngene_i2c_set_bus(struct ngene *dev, int bus) -{ - if (!(dev->card_info->i2c_access & 2)) - return; - if (dev->i2c_current_bus == bus) - return; - - switch (bus) { - case 0: - ngene_command_gpio_set(dev, 3, 0); - ngene_command_gpio_set(dev, 2, 1); - break; - - case 1: - ngene_command_gpio_set(dev, 2, 0); - ngene_command_gpio_set(dev, 3, 1); - break; - } - dev->i2c_current_bus = bus; -} - -static int ngene_i2c_master_xfer(struct i2c_adapter *adapter, - struct i2c_msg msg[], int num) -{ - struct ngene_channel *chan = - (struct ngene_channel *)i2c_get_adapdata(adapter); - struct ngene *dev = chan->dev; - - down(&dev->i2c_switch_mutex); - ngene_i2c_set_bus(dev, chan->number); - - if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD)) - if (!ngene_command_i2c_read(dev, msg[0].addr, - msg[0].buf, msg[0].len, - msg[1].buf, msg[1].len, 0)) - goto done; - - if (num == 1 && !(msg[0].flags & I2C_M_RD)) - if (!ngene_command_i2c_write(dev, msg[0].addr, - msg[0].buf, msg[0].len)) - goto done; - if (num == 1 && (msg[0].flags & I2C_M_RD)) - if (!ngene_command_i2c_read(dev, msg[0].addr, NULL, 0, - msg[0].buf, msg[0].len, 0)) - goto done; - - up(&dev->i2c_switch_mutex); - return -EIO; - -done: - up(&dev->i2c_switch_mutex); - return num; -} - - -static u32 ngene_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm ngene_i2c_algo = { - .master_xfer = ngene_i2c_master_xfer, - .functionality = ngene_i2c_functionality, -}; - -int ngene_i2c_init(struct ngene *dev, int dev_nr) -{ - struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter); - - i2c_set_adapdata(adap, &(dev->channel[dev_nr])); - - strcpy(adap->name, "nGene"); - - adap->algo = &ngene_i2c_algo; - adap->algo_data = (void *)&(dev->channel[dev_nr]); - adap->dev.parent = &dev->pci_dev->dev; - - return i2c_add_adapter(adap); -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -config DVB_PLUTO2 - tristate "Pluto2 cards" - depends on DVB_CORE && PCI && I2C - select I2C_ALGOBIT - select DVB_TDA1004X - help - Support for PCI cards based on the Pluto2 FPGA like the Satelco - Easywatch Mobile Terrestrial DVB-T Receiver. - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the PCI bus, so you need - an external software decoder to watch TV on your computer. - - Say Y or M if you own such a device and want to use it. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_PLUTO2) += pluto2.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/pluto2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/pluto2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/pluto2.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pluto2/pluto2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,822 +0,0 @@ -/* - * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T] - * - * Copyright (C) 2005 Andreas Oberritter - * - * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/ - * by Dany Salman - * Copyright (c) 2004 TDF - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "demux.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "dvbdev.h" -#include "tda1004x.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define DRIVER_NAME "pluto2" - -#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */ -#define REG_PCAR 0x0020 /* PC address register */ -#define REG_TSCR 0x0024 /* TS ctrl & status */ -#define REG_MISC 0x0028 /* miscellaneous */ -#define REG_MMAC 0x002c /* MSB MAC address */ -#define REG_IMAC 0x0030 /* ISB MAC address */ -#define REG_LMAC 0x0034 /* LSB MAC address */ -#define REG_SPID 0x0038 /* SPI data */ -#define REG_SLCS 0x003c /* serial links ctrl/status */ - -#define PID0_NOFIL (0x0001 << 16) -#define PIDn_ENP (0x0001 << 15) -#define PID0_END (0x0001 << 14) -#define PID0_AFIL (0x0001 << 13) -#define PIDn_PID (0x1fff << 0) - -#define TSCR_NBPACKETS (0x00ff << 24) -#define TSCR_DEM (0x0001 << 17) -#define TSCR_DE (0x0001 << 16) -#define TSCR_RSTN (0x0001 << 15) -#define TSCR_MSKO (0x0001 << 14) -#define TSCR_MSKA (0x0001 << 13) -#define TSCR_MSKL (0x0001 << 12) -#define TSCR_OVR (0x0001 << 11) -#define TSCR_AFUL (0x0001 << 10) -#define TSCR_LOCK (0x0001 << 9) -#define TSCR_IACK (0x0001 << 8) -#define TSCR_ADEF (0x007f << 0) - -#define MISC_DVR (0x0fff << 4) -#define MISC_ALED (0x0001 << 3) -#define MISC_FRST (0x0001 << 2) -#define MISC_LED1 (0x0001 << 1) -#define MISC_LED0 (0x0001 << 0) - -#define SPID_SPIDR (0x00ff << 0) - -#define SLCS_SCL (0x0001 << 7) -#define SLCS_SDA (0x0001 << 6) -#define SLCS_CSN (0x0001 << 2) -#define SLCS_OVR (0x0001 << 1) -#define SLCS_SWC (0x0001 << 0) - -#define TS_DMA_PACKETS (8) -#define TS_DMA_BYTES (188 * TS_DMA_PACKETS) - -#define I2C_ADDR_TDA10046 0x10 -#define I2C_ADDR_TUA6034 0xc2 -#define NHWFILTERS 8 - -struct pluto { - /* pci */ - struct pci_dev *pdev; - u8 __iomem *io_mem; - - /* dvb */ - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - struct dmxdev dmxdev; - struct dvb_adapter dvb_adapter; - struct dvb_demux demux; - struct dvb_frontend *fe; - struct dvb_net dvbnet; - unsigned int full_ts_users; - unsigned int users; - - /* i2c */ - struct i2c_algo_bit_data i2c_bit; - struct i2c_adapter i2c_adap; - unsigned int i2cbug; - - /* irq */ - unsigned int overflow; - unsigned int dead; - - /* dma */ - dma_addr_t dma_addr; - u8 dma_buf[TS_DMA_BYTES]; - u8 dummy[4096]; -}; - -static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed) -{ - return container_of(feed->demux, struct pluto, demux); -} - -static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe) -{ - return container_of(fe->dvb, struct pluto, dvb_adapter); -} - -static inline u32 pluto_readreg(struct pluto *pluto, u32 reg) -{ - return readl(&pluto->io_mem[reg]); -} - -static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val) -{ - writel(val, &pluto->io_mem[reg]); -} - -static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits) -{ - u32 val = readl(&pluto->io_mem[reg]); - val &= ~mask; - val |= bits; - writel(val, &pluto->io_mem[reg]); -} - -static void pluto_write_tscr(struct pluto *pluto, u32 val) -{ - /* set the number of packets */ - val &= ~TSCR_ADEF; - val |= TS_DMA_PACKETS / 2; - - pluto_writereg(pluto, REG_TSCR, val); -} - -static void pluto_setsda(void *data, int state) -{ - struct pluto *pluto = data; - - if (state) - pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA); - else - pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0); -} - -static void pluto_setscl(void *data, int state) -{ - struct pluto *pluto = data; - - if (state) - pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL); - else - pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0); - - /* try to detect i2c_inb() to workaround hardware bug: - * reset SDA to high after SCL has been set to low */ - if ((state) && (pluto->i2cbug == 0)) { - pluto->i2cbug = 1; - } else { - if ((!state) && (pluto->i2cbug == 1)) - pluto_setsda(pluto, 1); - pluto->i2cbug = 0; - } -} - -static int pluto_getsda(void *data) -{ - struct pluto *pluto = data; - - return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA; -} - -static int pluto_getscl(void *data) -{ - struct pluto *pluto = data; - - return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL; -} - -static void pluto_reset_frontend(struct pluto *pluto, int reenable) -{ - u32 val = pluto_readreg(pluto, REG_MISC); - - if (val & MISC_FRST) { - val &= ~MISC_FRST; - pluto_writereg(pluto, REG_MISC, val); - } - if (reenable) { - val |= MISC_FRST; - pluto_writereg(pluto, REG_MISC, val); - } -} - -static void pluto_reset_ts(struct pluto *pluto, int reenable) -{ - u32 val = pluto_readreg(pluto, REG_TSCR); - - if (val & TSCR_RSTN) { - val &= ~TSCR_RSTN; - pluto_write_tscr(pluto, val); - } - if (reenable) { - val |= TSCR_RSTN; - pluto_write_tscr(pluto, val); - } -} - -static void pluto_set_dma_addr(struct pluto *pluto) -{ - pluto_writereg(pluto, REG_PCAR, pluto->dma_addr); -} - -static int __devinit pluto_dma_map(struct pluto *pluto) -{ - pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); - - return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr); -} - -static void pluto_dma_unmap(struct pluto *pluto) -{ - pci_unmap_single(pluto->pdev, pluto->dma_addr, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); -} - -static int pluto_start_feed(struct dvb_demux_feed *f) -{ - struct pluto *pluto = feed_to_pluto(f); - - /* enable PID filtering */ - if (pluto->users++ == 0) - pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0); - - if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) - pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid); - else if (pluto->full_ts_users++ == 0) - pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL); - - return 0; -} - -static int pluto_stop_feed(struct dvb_demux_feed *f) -{ - struct pluto *pluto = feed_to_pluto(f); - - /* disable PID filtering */ - if (--pluto->users == 0) - pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL); - - if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) - pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff); - else if (--pluto->full_ts_users == 0) - pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0); - - return 0; -} - -static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) -{ - /* synchronize the DMA transfer with the CPU - * first so that we see updated contents. */ - pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); - - /* Workaround for broken hardware: - * [1] On startup NBPACKETS seems to contain an uninitialized value, - * but no packets have been transfered. - * [2] Sometimes (actually very often) NBPACKETS stays at zero - * although one packet has been transfered. - * [3] Sometimes (actually rarely), the card gets into an erroneous - * mode where it continuously generates interrupts, claiming it - * has recieved nbpackets>TS_DMA_PACKETS packets, but no packet - * has been transfered. Only a reset seems to solve this - */ - if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { - unsigned int i = 0; - while (pluto->dma_buf[i] == 0x47) - i += 188; - nbpackets = i / 188; - if (i == 0) { - pluto_reset_ts(pluto, 1); - dev_printk(KERN_DEBUG, &pluto->pdev->dev, "resetting TS because of invalid packet counter\n"); - } - } - - dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets); - - /* clear the dma buffer. this is needed to be able to identify - * new valid ts packets above */ - memset(pluto->dma_buf, 0, nbpackets * 188); - - /* reset the dma address */ - pluto_set_dma_addr(pluto); - - /* sync the buffer and give it back to the card */ - pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr, - TS_DMA_BYTES, PCI_DMA_FROMDEVICE); -} - -static irqreturn_t pluto_irq(int irq, void *dev_id) -{ - struct pluto *pluto = dev_id; - u32 tscr; - - /* check whether an interrupt occured on this device */ - tscr = pluto_readreg(pluto, REG_TSCR); - if (!(tscr & (TSCR_DE | TSCR_OVR))) - return IRQ_NONE; - - if (tscr == 0xffffffff) { - if (pluto->dead == 0) - dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n"); - /* It's dead Jim */ - pluto->dead = 1; - return IRQ_HANDLED; - } - - /* dma end interrupt */ - if (tscr & TSCR_DE) { - pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24); - /* overflow interrupt */ - if (tscr & TSCR_OVR) - pluto->overflow++; - if (pluto->overflow) { - dev_err(&pluto->pdev->dev, "overflow irq (%d)\n", - pluto->overflow); - pluto_reset_ts(pluto, 1); - pluto->overflow = 0; - } - } else if (tscr & TSCR_OVR) { - pluto->overflow++; - } - - /* ACK the interrupt */ - pluto_write_tscr(pluto, tscr | TSCR_IACK); - - return IRQ_HANDLED; -} - -static void __devinit pluto_enable_irqs(struct pluto *pluto) -{ - u32 val = pluto_readreg(pluto, REG_TSCR); - - /* disable AFUL and LOCK interrupts */ - val |= (TSCR_MSKA | TSCR_MSKL); - /* enable DMA and OVERFLOW interrupts */ - val &= ~(TSCR_DEM | TSCR_MSKO); - /* clear pending interrupts */ - val |= TSCR_IACK; - - pluto_write_tscr(pluto, val); -} - -static void pluto_disable_irqs(struct pluto *pluto) -{ - u32 val = pluto_readreg(pluto, REG_TSCR); - - /* disable all interrupts */ - val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL); - /* clear pending interrupts */ - val |= TSCR_IACK; - - pluto_write_tscr(pluto, val); -} - -static int __devinit pluto_hw_init(struct pluto *pluto) -{ - pluto_reset_frontend(pluto, 1); - - /* set automatic LED control by FPGA */ - pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED); - - /* set data endianess */ -#ifdef __LITTLE_ENDIAN - pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END); -#else - pluto_rw(pluto, REG_PIDn(0), PID0_END, 0); -#endif - /* map DMA and set address */ - pluto_dma_map(pluto); - pluto_set_dma_addr(pluto); - - /* enable interrupts */ - pluto_enable_irqs(pluto); - - /* reset TS logic */ - pluto_reset_ts(pluto, 1); - - return 0; -} - -static void pluto_hw_exit(struct pluto *pluto) -{ - /* disable interrupts */ - pluto_disable_irqs(pluto); - - pluto_reset_ts(pluto, 0); - - /* LED: disable automatic control, enable yellow, disable green */ - pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1); - - /* unmap DMA */ - pluto_dma_unmap(pluto); - - pluto_reset_frontend(pluto, 0); -} - -static inline u32 divide(u32 numerator, u32 denominator) -{ - if (denominator == 0) - return ~0; - - return DIV_ROUND_CLOSEST(numerator, denominator); -} - -/* LG Innotek TDTE-E001P (Infineon TUA6034) */ -static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct pluto *pluto = frontend_to_pluto(fe); - struct i2c_msg msg; - int ret; - u8 buf[4]; - u32 div; - - // Fref = 166.667 Hz - // Fref * 3 = 500.000 Hz - // IF = 36166667 - // IF / Fref = 217 - //div = divide(p->frequency + 36166667, 166667); - div = divide(p->frequency * 3, 500000) + 217; - buf[0] = (div >> 8) & 0x7f; - buf[1] = (div >> 0) & 0xff; - - if (p->frequency < 611000000) - buf[2] = 0xb4; - else if (p->frequency < 811000000) - buf[2] = 0xbc; - else - buf[2] = 0xf4; - - // VHF: 174-230 MHz - // center: 350 MHz - // UHF: 470-862 MHz - if (p->frequency < 350000000) - buf[3] = 0x02; - else - buf[3] = 0x04; - - if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) - buf[3] |= 0x08; - - if (sizeof(buf) == 6) { - buf[4] = buf[2]; - buf[4] &= ~0x1c; - buf[4] |= 0x18; - - buf[5] = (0 << 7) | (2 << 4); - } - - msg.addr = I2C_ADDR_TUA6034 >> 1; - msg.flags = 0; - msg.buf = buf; - msg.len = sizeof(buf); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - ret = i2c_transfer(&pluto->i2c_adap, &msg, 1); - if (ret < 0) - return ret; - else if (ret == 0) - return -EREMOTEIO; - - return 0; -} - -static int pluto2_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct pluto *pluto = frontend_to_pluto(fe); - - return request_firmware(fw, name, &pluto->pdev->dev); -} - -static struct tda1004x_config pluto2_fe_config __devinitdata = { - .demod_address = I2C_ADDR_TDA10046 >> 1, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = pluto2_request_firmware, -}; - -static int __devinit frontend_init(struct pluto *pluto) -{ - int ret; - - pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap); - if (!pluto->fe) { - dev_err(&pluto->pdev->dev, "could not attach frontend\n"); - return -ENODEV; - } - pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params; - - ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe); - if (ret < 0) { - if (pluto->fe->ops.release) - pluto->fe->ops.release(pluto->fe); - return ret; - } - - return 0; -} - -static void __devinit pluto_read_rev(struct pluto *pluto) -{ - u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR; - dev_info(&pluto->pdev->dev, "board revision %d.%d\n", - (val >> 12) & 0x0f, (val >> 4) & 0xff); -} - -static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac) -{ - u32 val = pluto_readreg(pluto, REG_MMAC); - mac[0] = (val >> 8) & 0xff; - mac[1] = (val >> 0) & 0xff; - - val = pluto_readreg(pluto, REG_IMAC); - mac[2] = (val >> 8) & 0xff; - mac[3] = (val >> 0) & 0xff; - - val = pluto_readreg(pluto, REG_LMAC); - mac[4] = (val >> 8) & 0xff; - mac[5] = (val >> 0) & 0xff; - - dev_info(&pluto->pdev->dev, "MAC %pM\n", mac); -} - -static int __devinit pluto_read_serial(struct pluto *pluto) -{ - struct pci_dev *pdev = pluto->pdev; - unsigned int i, j; - u8 __iomem *cis; - - cis = pci_iomap(pdev, 1, 0); - if (!cis) - return -EIO; - - dev_info(&pdev->dev, "S/N "); - - for (i = 0xe0; i < 0x100; i += 4) { - u32 val = readl(&cis[i]); - for (j = 0; j < 32; j += 8) { - if ((val & 0xff) == 0xff) - goto out; - printk("%c", val & 0xff); - val >>= 8; - } - } -out: - printk("\n"); - pci_iounmap(pdev, cis); - - return 0; -} - -static int __devinit pluto2_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct pluto *pluto; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - int ret = -ENOMEM; - - pluto = kzalloc(sizeof(struct pluto), GFP_KERNEL); - if (!pluto) - goto out; - - pluto->pdev = pdev; - - ret = pci_enable_device(pdev); - if (ret < 0) - goto err_kfree; - - /* enable interrupts */ - pci_write_config_dword(pdev, 0x6c, 0x8000); - - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret < 0) - goto err_pci_disable_device; - - pci_set_master(pdev); - - ret = pci_request_regions(pdev, DRIVER_NAME); - if (ret < 0) - goto err_pci_disable_device; - - pluto->io_mem = pci_iomap(pdev, 0, 0x40); - if (!pluto->io_mem) { - ret = -EIO; - goto err_pci_release_regions; - } - - pci_set_drvdata(pdev, pluto); - - ret = request_irq(pdev->irq, pluto_irq, IRQF_SHARED, DRIVER_NAME, pluto); - if (ret < 0) - goto err_pci_iounmap; - - ret = pluto_hw_init(pluto); - if (ret < 0) - goto err_free_irq; - - /* i2c */ - i2c_set_adapdata(&pluto->i2c_adap, pluto); - strcpy(pluto->i2c_adap.name, DRIVER_NAME); - pluto->i2c_adap.owner = THIS_MODULE; - pluto->i2c_adap.dev.parent = &pdev->dev; - pluto->i2c_adap.algo_data = &pluto->i2c_bit; - pluto->i2c_bit.data = pluto; - pluto->i2c_bit.setsda = pluto_setsda; - pluto->i2c_bit.setscl = pluto_setscl; - pluto->i2c_bit.getsda = pluto_getsda; - pluto->i2c_bit.getscl = pluto_getscl; - pluto->i2c_bit.udelay = 10; - pluto->i2c_bit.timeout = 10; - - /* Raise SCL and SDA */ - pluto_setsda(pluto, 1); - pluto_setscl(pluto, 1); - - ret = i2c_bit_add_bus(&pluto->i2c_adap); - if (ret < 0) - goto err_pluto_hw_exit; - - /* dvb */ - ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, - THIS_MODULE, &pdev->dev, adapter_nr); - if (ret < 0) - goto err_i2c_del_adapter; - - dvb_adapter = &pluto->dvb_adapter; - - pluto_read_rev(pluto); - pluto_read_serial(pluto); - pluto_read_mac(pluto, dvb_adapter->proposed_mac); - - dvbdemux = &pluto->demux; - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = pluto_start_feed; - dvbdemux->stop_feed = pluto_stop_feed; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); - ret = dvb_dmx_init(dvbdemux); - if (ret < 0) - goto err_dvb_unregister_adapter; - - dmx = &dvbdemux->dmx; - - pluto->hw_frontend.source = DMX_FRONTEND_0; - pluto->mem_frontend.source = DMX_MEMORY_FE; - pluto->dmxdev.filternum = NHWFILTERS; - pluto->dmxdev.demux = dmx; - - ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter); - if (ret < 0) - goto err_dvb_dmx_release; - - ret = dmx->add_frontend(dmx, &pluto->hw_frontend); - if (ret < 0) - goto err_dvb_dmxdev_release; - - ret = dmx->add_frontend(dmx, &pluto->mem_frontend); - if (ret < 0) - goto err_remove_hw_frontend; - - ret = dmx->connect_frontend(dmx, &pluto->hw_frontend); - if (ret < 0) - goto err_remove_mem_frontend; - - ret = frontend_init(pluto); - if (ret < 0) - goto err_disconnect_frontend; - - dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx); -out: - return ret; - -err_disconnect_frontend: - dmx->disconnect_frontend(dmx); -err_remove_mem_frontend: - dmx->remove_frontend(dmx, &pluto->mem_frontend); -err_remove_hw_frontend: - dmx->remove_frontend(dmx, &pluto->hw_frontend); -err_dvb_dmxdev_release: - dvb_dmxdev_release(&pluto->dmxdev); -err_dvb_dmx_release: - dvb_dmx_release(dvbdemux); -err_dvb_unregister_adapter: - dvb_unregister_adapter(dvb_adapter); -err_i2c_del_adapter: - i2c_del_adapter(&pluto->i2c_adap); -err_pluto_hw_exit: - pluto_hw_exit(pluto); -err_free_irq: - free_irq(pdev->irq, pluto); -err_pci_iounmap: - pci_iounmap(pdev, pluto->io_mem); -err_pci_release_regions: - pci_release_regions(pdev); -err_pci_disable_device: - pci_disable_device(pdev); -err_kfree: - pci_set_drvdata(pdev, NULL); - kfree(pluto); - goto out; -} - -static void __devexit pluto2_remove(struct pci_dev *pdev) -{ - struct pluto *pluto = pci_get_drvdata(pdev); - struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter; - struct dvb_demux *dvbdemux = &pluto->demux; - struct dmx_demux *dmx = &dvbdemux->dmx; - - dmx->close(dmx); - dvb_net_release(&pluto->dvbnet); - if (pluto->fe) - dvb_unregister_frontend(pluto->fe); - - dmx->disconnect_frontend(dmx); - dmx->remove_frontend(dmx, &pluto->mem_frontend); - dmx->remove_frontend(dmx, &pluto->hw_frontend); - dvb_dmxdev_release(&pluto->dmxdev); - dvb_dmx_release(dvbdemux); - dvb_unregister_adapter(dvb_adapter); - i2c_del_adapter(&pluto->i2c_adap); - pluto_hw_exit(pluto); - free_irq(pdev->irq, pluto); - pci_iounmap(pdev, pluto->io_mem); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - kfree(pluto); -} - -#ifndef PCI_VENDOR_ID_SCM -#define PCI_VENDOR_ID_SCM 0x0432 -#endif -#ifndef PCI_DEVICE_ID_PLUTO2 -#define PCI_DEVICE_ID_PLUTO2 0x0001 -#endif - -static struct pci_device_id pluto2_id_table[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_SCM, - .device = PCI_DEVICE_ID_PLUTO2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { - /* empty */ - }, -}; - -MODULE_DEVICE_TABLE(pci, pluto2_id_table); - -static struct pci_driver pluto2_driver = { - .name = DRIVER_NAME, - .id_table = pluto2_id_table, - .probe = pluto2_probe, - .remove = __devexit_p(pluto2_remove), -}; - -static int __init pluto2_init(void) -{ - return pci_register_driver(&pluto2_driver); -} - -static void __exit pluto2_exit(void) -{ - pci_unregister_driver(&pluto2_driver); -} - -module_init(pluto2_init); -module_exit(pluto2_exit); - -MODULE_AUTHOR("Andreas Oberritter "); -MODULE_DESCRIPTION("Pluto2 driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -config DVB_PT1 - tristate "PT1 cards" - depends on DVB_CORE && PCI && I2C - help - Support for Earthsoft PT1 PCI cards. - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the PCI bus, so you need - an external software decoder to watch TV on your computer. - - Say Y or M if you own such a device and want to use it. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o - -obj-$(CONFIG_DVB_PT1) += earth-pt1.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/pt1.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/pt1.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/pt1.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/pt1.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1208 +0,0 @@ -/* - * driver for Earthsoft PT1/PT2 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dmxdev.h" -#include "dvb_net.h" -#include "dvb_frontend.h" - -#include "va1j5jf8007t.h" -#include "va1j5jf8007s.h" - -#define DRIVER_NAME "earth-pt1" - -#define PT1_PAGE_SHIFT 12 -#define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT) -#define PT1_NR_UPACKETS 1024 -#define PT1_NR_BUFS 511 - -struct pt1_buffer_page { - __le32 upackets[PT1_NR_UPACKETS]; -}; - -struct pt1_table_page { - __le32 next_pfn; - __le32 buf_pfns[PT1_NR_BUFS]; -}; - -struct pt1_buffer { - struct pt1_buffer_page *page; - dma_addr_t addr; -}; - -struct pt1_table { - struct pt1_table_page *page; - dma_addr_t addr; - struct pt1_buffer bufs[PT1_NR_BUFS]; -}; - -#define PT1_NR_ADAPS 4 - -struct pt1_adapter; - -struct pt1 { - struct pci_dev *pdev; - void __iomem *regs; - struct i2c_adapter i2c_adap; - int i2c_running; - struct pt1_adapter *adaps[PT1_NR_ADAPS]; - struct pt1_table *tables; - struct task_struct *kthread; - - struct mutex lock; - int power; - int reset; -}; - -struct pt1_adapter { - struct pt1 *pt1; - int index; - - u8 *buf; - int upacket_count; - int packet_count; - - struct dvb_adapter adap; - struct dvb_demux demux; - int users; - struct dmxdev dmxdev; - struct dvb_net net; - struct dvb_frontend *fe; - int (*orig_set_voltage)(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); - int (*orig_sleep)(struct dvb_frontend *fe); - int (*orig_init)(struct dvb_frontend *fe); - - fe_sec_voltage_t voltage; - int sleep; -}; - -#define pt1_printk(level, pt1, format, arg...) \ - dev_printk(level, &(pt1)->pdev->dev, format, ##arg) - -static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data) -{ - writel(data, pt1->regs + reg * 4); -} - -static u32 pt1_read_reg(struct pt1 *pt1, int reg) -{ - return readl(pt1->regs + reg * 4); -} - -static int pt1_nr_tables = 64; -module_param_named(nr_tables, pt1_nr_tables, int, 0); - -static void pt1_increment_table_count(struct pt1 *pt1) -{ - pt1_write_reg(pt1, 0, 0x00000020); -} - -static void pt1_init_table_count(struct pt1 *pt1) -{ - pt1_write_reg(pt1, 0, 0x00000010); -} - -static void pt1_register_tables(struct pt1 *pt1, u32 first_pfn) -{ - pt1_write_reg(pt1, 5, first_pfn); - pt1_write_reg(pt1, 0, 0x0c000040); -} - -static void pt1_unregister_tables(struct pt1 *pt1) -{ - pt1_write_reg(pt1, 0, 0x08080000); -} - -static int pt1_sync(struct pt1 *pt1) -{ - int i; - for (i = 0; i < 57; i++) { - if (pt1_read_reg(pt1, 0) & 0x20000000) - return 0; - pt1_write_reg(pt1, 0, 0x00000008); - } - pt1_printk(KERN_ERR, pt1, "could not sync\n"); - return -EIO; -} - -static u64 pt1_identify(struct pt1 *pt1) -{ - int i; - u64 id; - id = 0; - for (i = 0; i < 57; i++) { - id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i; - pt1_write_reg(pt1, 0, 0x00000008); - } - return id; -} - -static int pt1_unlock(struct pt1 *pt1) -{ - int i; - pt1_write_reg(pt1, 0, 0x00000008); - for (i = 0; i < 3; i++) { - if (pt1_read_reg(pt1, 0) & 0x80000000) - return 0; - schedule_timeout_uninterruptible((HZ + 999) / 1000); - } - pt1_printk(KERN_ERR, pt1, "could not unlock\n"); - return -EIO; -} - -static int pt1_reset_pci(struct pt1 *pt1) -{ - int i; - pt1_write_reg(pt1, 0, 0x01010000); - pt1_write_reg(pt1, 0, 0x01000000); - for (i = 0; i < 10; i++) { - if (pt1_read_reg(pt1, 0) & 0x00000001) - return 0; - schedule_timeout_uninterruptible((HZ + 999) / 1000); - } - pt1_printk(KERN_ERR, pt1, "could not reset PCI\n"); - return -EIO; -} - -static int pt1_reset_ram(struct pt1 *pt1) -{ - int i; - pt1_write_reg(pt1, 0, 0x02020000); - pt1_write_reg(pt1, 0, 0x02000000); - for (i = 0; i < 10; i++) { - if (pt1_read_reg(pt1, 0) & 0x00000002) - return 0; - schedule_timeout_uninterruptible((HZ + 999) / 1000); - } - pt1_printk(KERN_ERR, pt1, "could not reset RAM\n"); - return -EIO; -} - -static int pt1_do_enable_ram(struct pt1 *pt1) -{ - int i, j; - u32 status; - status = pt1_read_reg(pt1, 0) & 0x00000004; - pt1_write_reg(pt1, 0, 0x00000002); - for (i = 0; i < 10; i++) { - for (j = 0; j < 1024; j++) { - if ((pt1_read_reg(pt1, 0) & 0x00000004) != status) - return 0; - } - schedule_timeout_uninterruptible((HZ + 999) / 1000); - } - pt1_printk(KERN_ERR, pt1, "could not enable RAM\n"); - return -EIO; -} - -static int pt1_enable_ram(struct pt1 *pt1) -{ - int i, ret; - int phase; - schedule_timeout_uninterruptible((HZ + 999) / 1000); - phase = pt1->pdev->device == 0x211a ? 128 : 166; - for (i = 0; i < phase; i++) { - ret = pt1_do_enable_ram(pt1); - if (ret < 0) - return ret; - } - return 0; -} - -static void pt1_disable_ram(struct pt1 *pt1) -{ - pt1_write_reg(pt1, 0, 0x0b0b0000); -} - -static void pt1_set_stream(struct pt1 *pt1, int index, int enabled) -{ - pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index); -} - -static void pt1_init_streams(struct pt1 *pt1) -{ - int i; - for (i = 0; i < PT1_NR_ADAPS; i++) - pt1_set_stream(pt1, i, 0); -} - -static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page) -{ - u32 upacket; - int i; - int index; - struct pt1_adapter *adap; - int offset; - u8 *buf; - - if (!page->upackets[PT1_NR_UPACKETS - 1]) - return 0; - - for (i = 0; i < PT1_NR_UPACKETS; i++) { - upacket = le32_to_cpu(page->upackets[i]); - index = (upacket >> 29) - 1; - if (index < 0 || index >= PT1_NR_ADAPS) - continue; - - adap = pt1->adaps[index]; - if (upacket >> 25 & 1) - adap->upacket_count = 0; - else if (!adap->upacket_count) - continue; - - buf = adap->buf; - offset = adap->packet_count * 188 + adap->upacket_count * 3; - buf[offset] = upacket >> 16; - buf[offset + 1] = upacket >> 8; - if (adap->upacket_count != 62) - buf[offset + 2] = upacket; - - if (++adap->upacket_count >= 63) { - adap->upacket_count = 0; - if (++adap->packet_count >= 21) { - dvb_dmx_swfilter_packets(&adap->demux, buf, 21); - adap->packet_count = 0; - } - } - } - - page->upackets[PT1_NR_UPACKETS - 1] = 0; - return 1; -} - -static int pt1_thread(void *data) -{ - struct pt1 *pt1; - int table_index; - int buf_index; - struct pt1_buffer_page *page; - - pt1 = data; - set_freezable(); - - table_index = 0; - buf_index = 0; - - while (!kthread_should_stop()) { - try_to_freeze(); - - page = pt1->tables[table_index].bufs[buf_index].page; - if (!pt1_filter(pt1, page)) { - schedule_timeout_interruptible((HZ + 999) / 1000); - continue; - } - - if (++buf_index >= PT1_NR_BUFS) { - pt1_increment_table_count(pt1); - buf_index = 0; - if (++table_index >= pt1_nr_tables) - table_index = 0; - } - } - - return 0; -} - -static void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr) -{ - dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr); -} - -static void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp) -{ - void *page; - dma_addr_t addr; - - page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr, - GFP_KERNEL); - if (page == NULL) - return NULL; - - BUG_ON(addr & (PT1_PAGE_SIZE - 1)); - BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1); - - *addrp = addr; - *pfnp = addr >> PT1_PAGE_SHIFT; - return page; -} - -static void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf) -{ - pt1_free_page(pt1, buf->page, buf->addr); -} - -static int -pt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf, u32 *pfnp) -{ - struct pt1_buffer_page *page; - dma_addr_t addr; - - page = pt1_alloc_page(pt1, &addr, pfnp); - if (page == NULL) - return -ENOMEM; - - page->upackets[PT1_NR_UPACKETS - 1] = 0; - - buf->page = page; - buf->addr = addr; - return 0; -} - -static void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table) -{ - int i; - - for (i = 0; i < PT1_NR_BUFS; i++) - pt1_cleanup_buffer(pt1, &table->bufs[i]); - - pt1_free_page(pt1, table->page, table->addr); -} - -static int -pt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp) -{ - struct pt1_table_page *page; - dma_addr_t addr; - int i, ret; - u32 buf_pfn; - - page = pt1_alloc_page(pt1, &addr, pfnp); - if (page == NULL) - return -ENOMEM; - - for (i = 0; i < PT1_NR_BUFS; i++) { - ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn); - if (ret < 0) - goto err; - - page->buf_pfns[i] = cpu_to_le32(buf_pfn); - } - - pt1_increment_table_count(pt1); - table->page = page; - table->addr = addr; - return 0; - -err: - while (i--) - pt1_cleanup_buffer(pt1, &table->bufs[i]); - - pt1_free_page(pt1, page, addr); - return ret; -} - -static void pt1_cleanup_tables(struct pt1 *pt1) -{ - struct pt1_table *tables; - int i; - - tables = pt1->tables; - pt1_unregister_tables(pt1); - - for (i = 0; i < pt1_nr_tables; i++) - pt1_cleanup_table(pt1, &tables[i]); - - vfree(tables); -} - -static int pt1_init_tables(struct pt1 *pt1) -{ - struct pt1_table *tables; - int i, ret; - u32 first_pfn, pfn; - - tables = vmalloc(sizeof(struct pt1_table) * pt1_nr_tables); - if (tables == NULL) - return -ENOMEM; - - pt1_init_table_count(pt1); - - i = 0; - if (pt1_nr_tables) { - ret = pt1_init_table(pt1, &tables[0], &first_pfn); - if (ret) - goto err; - i++; - } - - while (i < pt1_nr_tables) { - ret = pt1_init_table(pt1, &tables[i], &pfn); - if (ret) - goto err; - tables[i - 1].page->next_pfn = cpu_to_le32(pfn); - i++; - } - - tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn); - - pt1_register_tables(pt1, first_pfn); - pt1->tables = tables; - return 0; - -err: - while (i--) - pt1_cleanup_table(pt1, &tables[i]); - - vfree(tables); - return ret; -} - -static int pt1_start_feed(struct dvb_demux_feed *feed) -{ - struct pt1_adapter *adap; - adap = container_of(feed->demux, struct pt1_adapter, demux); - if (!adap->users++) - pt1_set_stream(adap->pt1, adap->index, 1); - return 0; -} - -static int pt1_stop_feed(struct dvb_demux_feed *feed) -{ - struct pt1_adapter *adap; - adap = container_of(feed->demux, struct pt1_adapter, demux); - if (!--adap->users) - pt1_set_stream(adap->pt1, adap->index, 0); - return 0; -} - -static void -pt1_update_power(struct pt1 *pt1) -{ - int bits; - int i; - struct pt1_adapter *adap; - static const int sleep_bits[] = { - 1 << 4, - 1 << 6 | 1 << 7, - 1 << 5, - 1 << 6 | 1 << 8, - }; - - bits = pt1->power | !pt1->reset << 3; - mutex_lock(&pt1->lock); - for (i = 0; i < PT1_NR_ADAPS; i++) { - adap = pt1->adaps[i]; - switch (adap->voltage) { - case SEC_VOLTAGE_13: /* actually 11V */ - bits |= 1 << 1; - break; - case SEC_VOLTAGE_18: /* actually 15V */ - bits |= 1 << 1 | 1 << 2; - break; - default: - break; - } - - /* XXX: The bits should be changed depending on adap->sleep. */ - bits |= sleep_bits[i]; - } - pt1_write_reg(pt1, 1, bits); - mutex_unlock(&pt1->lock); -} - -static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct pt1_adapter *adap; - - adap = container_of(fe->dvb, struct pt1_adapter, adap); - adap->voltage = voltage; - pt1_update_power(adap->pt1); - - if (adap->orig_set_voltage) - return adap->orig_set_voltage(fe, voltage); - else - return 0; -} - -static int pt1_sleep(struct dvb_frontend *fe) -{ - struct pt1_adapter *adap; - - adap = container_of(fe->dvb, struct pt1_adapter, adap); - adap->sleep = 1; - pt1_update_power(adap->pt1); - - if (adap->orig_sleep) - return adap->orig_sleep(fe); - else - return 0; -} - -static int pt1_wakeup(struct dvb_frontend *fe) -{ - struct pt1_adapter *adap; - - adap = container_of(fe->dvb, struct pt1_adapter, adap); - adap->sleep = 0; - pt1_update_power(adap->pt1); - schedule_timeout_uninterruptible((HZ + 999) / 1000); - - if (adap->orig_init) - return adap->orig_init(fe); - else - return 0; -} - -static void pt1_free_adapter(struct pt1_adapter *adap) -{ - dvb_net_release(&adap->net); - adap->demux.dmx.close(&adap->demux.dmx); - dvb_dmxdev_release(&adap->dmxdev); - dvb_dmx_release(&adap->demux); - dvb_unregister_adapter(&adap->adap); - free_page((unsigned long)adap->buf); - kfree(adap); -} - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static struct pt1_adapter * -pt1_alloc_adapter(struct pt1 *pt1) -{ - struct pt1_adapter *adap; - void *buf; - struct dvb_adapter *dvb_adap; - struct dvb_demux *demux; - struct dmxdev *dmxdev; - int ret; - - adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL); - if (!adap) { - ret = -ENOMEM; - goto err; - } - - adap->pt1 = pt1; - - adap->voltage = SEC_VOLTAGE_OFF; - adap->sleep = 1; - - buf = (u8 *)__get_free_page(GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto err_kfree; - } - - adap->buf = buf; - adap->upacket_count = 0; - adap->packet_count = 0; - - dvb_adap = &adap->adap; - dvb_adap->priv = adap; - ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE, - &pt1->pdev->dev, adapter_nr); - if (ret < 0) - goto err_free_page; - - demux = &adap->demux; - demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - demux->priv = adap; - demux->feednum = 256; - demux->filternum = 256; - demux->start_feed = pt1_start_feed; - demux->stop_feed = pt1_stop_feed; - demux->write_to_decoder = NULL; - ret = dvb_dmx_init(demux); - if (ret < 0) - goto err_unregister_adapter; - - dmxdev = &adap->dmxdev; - dmxdev->filternum = 256; - dmxdev->demux = &demux->dmx; - dmxdev->capabilities = 0; - ret = dvb_dmxdev_init(dmxdev, dvb_adap); - if (ret < 0) - goto err_dmx_release; - - dvb_net_init(dvb_adap, &adap->net, &demux->dmx); - - return adap; - -err_dmx_release: - dvb_dmx_release(demux); -err_unregister_adapter: - dvb_unregister_adapter(dvb_adap); -err_free_page: - free_page((unsigned long)buf); -err_kfree: - kfree(adap); -err: - return ERR_PTR(ret); -} - -static void pt1_cleanup_adapters(struct pt1 *pt1) -{ - int i; - for (i = 0; i < PT1_NR_ADAPS; i++) - pt1_free_adapter(pt1->adaps[i]); -} - -static int pt1_init_adapters(struct pt1 *pt1) -{ - int i; - struct pt1_adapter *adap; - int ret; - - for (i = 0; i < PT1_NR_ADAPS; i++) { - adap = pt1_alloc_adapter(pt1); - if (IS_ERR(adap)) { - ret = PTR_ERR(adap); - goto err; - } - - adap->index = i; - pt1->adaps[i] = adap; - } - return 0; - -err: - while (i--) - pt1_free_adapter(pt1->adaps[i]); - - return ret; -} - -static void pt1_cleanup_frontend(struct pt1_adapter *adap) -{ - dvb_unregister_frontend(adap->fe); -} - -static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe) -{ - int ret; - - adap->orig_set_voltage = fe->ops.set_voltage; - adap->orig_sleep = fe->ops.sleep; - adap->orig_init = fe->ops.init; - fe->ops.set_voltage = pt1_set_voltage; - fe->ops.sleep = pt1_sleep; - fe->ops.init = pt1_wakeup; - - ret = dvb_register_frontend(&adap->adap, fe); - if (ret < 0) - return ret; - - adap->fe = fe; - return 0; -} - -static void pt1_cleanup_frontends(struct pt1 *pt1) -{ - int i; - for (i = 0; i < PT1_NR_ADAPS; i++) - pt1_cleanup_frontend(pt1->adaps[i]); -} - -struct pt1_config { - struct va1j5jf8007s_config va1j5jf8007s_config; - struct va1j5jf8007t_config va1j5jf8007t_config; -}; - -static const struct pt1_config pt1_configs[2] = { - { - { - .demod_address = 0x1b, - .frequency = VA1J5JF8007S_20MHZ, - }, - { - .demod_address = 0x1a, - .frequency = VA1J5JF8007T_20MHZ, - }, - }, { - { - .demod_address = 0x19, - .frequency = VA1J5JF8007S_20MHZ, - }, - { - .demod_address = 0x18, - .frequency = VA1J5JF8007T_20MHZ, - }, - }, -}; - -static const struct pt1_config pt2_configs[2] = { - { - { - .demod_address = 0x1b, - .frequency = VA1J5JF8007S_25MHZ, - }, - { - .demod_address = 0x1a, - .frequency = VA1J5JF8007T_25MHZ, - }, - }, { - { - .demod_address = 0x19, - .frequency = VA1J5JF8007S_25MHZ, - }, - { - .demod_address = 0x18, - .frequency = VA1J5JF8007T_25MHZ, - }, - }, -}; - -static int pt1_init_frontends(struct pt1 *pt1) -{ - int i, j; - struct i2c_adapter *i2c_adap; - const struct pt1_config *configs, *config; - struct dvb_frontend *fe[4]; - int ret; - - i = 0; - j = 0; - - i2c_adap = &pt1->i2c_adap; - configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs; - do { - config = &configs[i / 2]; - - fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config, - i2c_adap); - if (!fe[i]) { - ret = -ENODEV; /* This does not sound nice... */ - goto err; - } - i++; - - fe[i] = va1j5jf8007t_attach(&config->va1j5jf8007t_config, - i2c_adap); - if (!fe[i]) { - ret = -ENODEV; - goto err; - } - i++; - - ret = va1j5jf8007s_prepare(fe[i - 2]); - if (ret < 0) - goto err; - - ret = va1j5jf8007t_prepare(fe[i - 1]); - if (ret < 0) - goto err; - - } while (i < 4); - - do { - ret = pt1_init_frontend(pt1->adaps[j], fe[j]); - if (ret < 0) - goto err; - } while (++j < 4); - - return 0; - -err: - while (i-- > j) - fe[i]->ops.release(fe[i]); - - while (j--) - dvb_unregister_frontend(fe[j]); - - return ret; -} - -static void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable, - int clock, int data, int next_addr) -{ - pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 | - !clock << 11 | !data << 10 | next_addr); -} - -static void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data) -{ - pt1_i2c_emit(pt1, addr, 1, 0, 0, data, addr + 1); - pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2); - pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3); - *addrp = addr + 3; -} - -static void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp) -{ - pt1_i2c_emit(pt1, addr, 1, 0, 0, 1, addr + 1); - pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2); - pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3); - pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4); - *addrp = addr + 4; -} - -static void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data) -{ - int i; - for (i = 0; i < 8; i++) - pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1); - pt1_i2c_write_bit(pt1, addr, &addr, 1); - *addrp = addr; -} - -static void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last) -{ - int i; - for (i = 0; i < 8; i++) - pt1_i2c_read_bit(pt1, addr, &addr); - pt1_i2c_write_bit(pt1, addr, &addr, last); - *addrp = addr; -} - -static void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp) -{ - pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); - pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); - pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3); - *addrp = addr + 3; -} - -static void -pt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) -{ - int i; - pt1_i2c_prepare(pt1, addr, &addr); - pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1); - for (i = 0; i < msg->len; i++) - pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]); - *addrp = addr; -} - -static void -pt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) -{ - int i; - pt1_i2c_prepare(pt1, addr, &addr); - pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1); - for (i = 0; i < msg->len; i++) - pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1); - *addrp = addr; -} - -static int pt1_i2c_end(struct pt1 *pt1, int addr) -{ - pt1_i2c_emit(pt1, addr, 1, 0, 0, 0, addr + 1); - pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); - pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0); - - pt1_write_reg(pt1, 0, 0x00000004); - do { - if (signal_pending(current)) - return -EINTR; - schedule_timeout_interruptible((HZ + 999) / 1000); - } while (pt1_read_reg(pt1, 0) & 0x00000080); - return 0; -} - -static void pt1_i2c_begin(struct pt1 *pt1, int *addrp) -{ - int addr; - addr = 0; - - pt1_i2c_emit(pt1, addr, 0, 0, 1, 1, addr /* itself */); - addr = addr + 1; - - if (!pt1->i2c_running) { - pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); - pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); - addr = addr + 2; - pt1->i2c_running = 1; - } - *addrp = addr; -} - -static int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) -{ - struct pt1 *pt1; - int i; - struct i2c_msg *msg, *next_msg; - int addr, ret; - u16 len; - u32 word; - - pt1 = i2c_get_adapdata(adap); - - for (i = 0; i < num; i++) { - msg = &msgs[i]; - if (msg->flags & I2C_M_RD) - return -ENOTSUPP; - - if (i + 1 < num) - next_msg = &msgs[i + 1]; - else - next_msg = NULL; - - if (next_msg && next_msg->flags & I2C_M_RD) { - i++; - - len = next_msg->len; - if (len > 4) - return -ENOTSUPP; - - pt1_i2c_begin(pt1, &addr); - pt1_i2c_write_msg(pt1, addr, &addr, msg); - pt1_i2c_read_msg(pt1, addr, &addr, next_msg); - ret = pt1_i2c_end(pt1, addr); - if (ret < 0) - return ret; - - word = pt1_read_reg(pt1, 2); - while (len--) { - next_msg->buf[len] = word; - word >>= 8; - } - } else { - pt1_i2c_begin(pt1, &addr); - pt1_i2c_write_msg(pt1, addr, &addr, msg); - ret = pt1_i2c_end(pt1, addr); - if (ret < 0) - return ret; - } - } - - return num; -} - -static u32 pt1_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C; -} - -static const struct i2c_algorithm pt1_i2c_algo = { - .master_xfer = pt1_i2c_xfer, - .functionality = pt1_i2c_func, -}; - -static void pt1_i2c_wait(struct pt1 *pt1) -{ - int i; - for (i = 0; i < 128; i++) - pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0); -} - -static void pt1_i2c_init(struct pt1 *pt1) -{ - int i; - for (i = 0; i < 1024; i++) - pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0); -} - -static void __devexit pt1_remove(struct pci_dev *pdev) -{ - struct pt1 *pt1; - void __iomem *regs; - - pt1 = pci_get_drvdata(pdev); - regs = pt1->regs; - - kthread_stop(pt1->kthread); - pt1_cleanup_tables(pt1); - pt1_cleanup_frontends(pt1); - pt1_disable_ram(pt1); - pt1->power = 0; - pt1->reset = 1; - pt1_update_power(pt1); - pt1_cleanup_adapters(pt1); - i2c_del_adapter(&pt1->i2c_adap); - pci_set_drvdata(pdev, NULL); - kfree(pt1); - pci_iounmap(pdev, regs); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static int __devinit -pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int ret; - void __iomem *regs; - struct pt1 *pt1; - struct i2c_adapter *i2c_adap; - struct task_struct *kthread; - - ret = pci_enable_device(pdev); - if (ret < 0) - goto err; - - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret < 0) - goto err_pci_disable_device; - - pci_set_master(pdev); - - ret = pci_request_regions(pdev, DRIVER_NAME); - if (ret < 0) - goto err_pci_disable_device; - - regs = pci_iomap(pdev, 0, 0); - if (!regs) { - ret = -EIO; - goto err_pci_release_regions; - } - - pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL); - if (!pt1) { - ret = -ENOMEM; - goto err_pci_iounmap; - } - - mutex_init(&pt1->lock); - pt1->pdev = pdev; - pt1->regs = regs; - pci_set_drvdata(pdev, pt1); - - ret = pt1_init_adapters(pt1); - if (ret < 0) - goto err_kfree; - - mutex_init(&pt1->lock); - - pt1->power = 0; - pt1->reset = 1; - pt1_update_power(pt1); - - i2c_adap = &pt1->i2c_adap; - i2c_adap->algo = &pt1_i2c_algo; - i2c_adap->algo_data = NULL; - i2c_adap->dev.parent = &pdev->dev; - i2c_set_adapdata(i2c_adap, pt1); - ret = i2c_add_adapter(i2c_adap); - if (ret < 0) - goto err_pt1_cleanup_adapters; - - pt1_i2c_init(pt1); - pt1_i2c_wait(pt1); - - ret = pt1_sync(pt1); - if (ret < 0) - goto err_i2c_del_adapter; - - pt1_identify(pt1); - - ret = pt1_unlock(pt1); - if (ret < 0) - goto err_i2c_del_adapter; - - ret = pt1_reset_pci(pt1); - if (ret < 0) - goto err_i2c_del_adapter; - - ret = pt1_reset_ram(pt1); - if (ret < 0) - goto err_i2c_del_adapter; - - ret = pt1_enable_ram(pt1); - if (ret < 0) - goto err_i2c_del_adapter; - - pt1_init_streams(pt1); - - pt1->power = 1; - pt1_update_power(pt1); - schedule_timeout_uninterruptible((HZ + 49) / 50); - - pt1->reset = 0; - pt1_update_power(pt1); - schedule_timeout_uninterruptible((HZ + 999) / 1000); - - ret = pt1_init_frontends(pt1); - if (ret < 0) - goto err_pt1_disable_ram; - - ret = pt1_init_tables(pt1); - if (ret < 0) - goto err_pt1_cleanup_frontends; - - kthread = kthread_run(pt1_thread, pt1, "pt1"); - if (IS_ERR(kthread)) { - ret = PTR_ERR(kthread); - goto err_pt1_cleanup_tables; - } - - pt1->kthread = kthread; - return 0; - -err_pt1_cleanup_tables: - pt1_cleanup_tables(pt1); -err_pt1_cleanup_frontends: - pt1_cleanup_frontends(pt1); -err_pt1_disable_ram: - pt1_disable_ram(pt1); - pt1->power = 0; - pt1->reset = 1; - pt1_update_power(pt1); -err_pt1_cleanup_adapters: - pt1_cleanup_adapters(pt1); -err_i2c_del_adapter: - i2c_del_adapter(i2c_adap); -err_kfree: - pci_set_drvdata(pdev, NULL); - kfree(pt1); -err_pci_iounmap: - pci_iounmap(pdev, regs); -err_pci_release_regions: - pci_release_regions(pdev); -err_pci_disable_device: - pci_disable_device(pdev); -err: - return ret; - -} - -static struct pci_device_id pt1_id_table[] = { - { PCI_DEVICE(0x10ee, 0x211a) }, - { PCI_DEVICE(0x10ee, 0x222a) }, - { }, -}; -MODULE_DEVICE_TABLE(pci, pt1_id_table); - -static struct pci_driver pt1_driver = { - .name = DRIVER_NAME, - .probe = pt1_probe, - .remove = __devexit_p(pt1_remove), - .id_table = pt1_id_table, -}; - - -static int __init pt1_init(void) -{ - return pci_register_driver(&pt1_driver); -} - - -static void __exit pt1_cleanup(void) -{ - pci_unregister_driver(&pt1_driver); -} - -module_init(pt1_init); -module_exit(pt1_cleanup); - -MODULE_AUTHOR("Takahito HIRANO "); -MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007s.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007s.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007s.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007s.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,735 +0,0 @@ -/* - * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "va1j5jf8007s.h" - -enum va1j5jf8007s_tune_state { - VA1J5JF8007S_IDLE, - VA1J5JF8007S_SET_FREQUENCY_1, - VA1J5JF8007S_SET_FREQUENCY_2, - VA1J5JF8007S_SET_FREQUENCY_3, - VA1J5JF8007S_CHECK_FREQUENCY, - VA1J5JF8007S_SET_MODULATION, - VA1J5JF8007S_CHECK_MODULATION, - VA1J5JF8007S_SET_TS_ID, - VA1J5JF8007S_CHECK_TS_ID, - VA1J5JF8007S_TRACK, -}; - -struct va1j5jf8007s_state { - const struct va1j5jf8007s_config *config; - struct i2c_adapter *adap; - struct dvb_frontend fe; - enum va1j5jf8007s_tune_state tune_state; -}; - -static int va1j5jf8007s_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct va1j5jf8007s_state *state; - u8 addr; - int i; - u8 write_buf[1], read_buf[1]; - struct i2c_msg msgs[2]; - s32 word, x1, x2, x3, x4, x5, y; - - state = fe->demodulator_priv; - addr = state->config->demod_address; - - word = 0; - for (i = 0; i < 2; i++) { - write_buf[0] = 0xbc + i; - - msgs[0].addr = addr; - msgs[0].flags = 0; - msgs[0].len = sizeof(write_buf); - msgs[0].buf = write_buf; - - msgs[1].addr = addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(read_buf); - msgs[1].buf = read_buf; - - if (i2c_transfer(state->adap, msgs, 2) != 2) - return -EREMOTEIO; - - word <<= 8; - word |= read_buf[0]; - } - - word -= 3000; - if (word < 0) - word = 0; - - x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000); - x2 = (s64)x1 * x1 >> 31; - x3 = (s64)x2 * x1 >> 31; - x4 = (s64)x2 * x2 >> 31; - x5 = (s64)x4 * x1 >> 31; - - y = (58857ll << 23) / 1000; - y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30; - y += (s64)x2 * ((88977ll << 24) / 1000) >> 28; - y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27; - y += (s64)x4 * ((14341ll << 27) / 1000) >> 27; - y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28; - - *snr = y < 0 ? 0 : y >> 15; - return 0; -} - -static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe) -{ - return DVBFE_ALGO_HW; -} - -static int -va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct va1j5jf8007s_state *state; - - state = fe->demodulator_priv; - - switch (state->tune_state) { - case VA1J5JF8007S_IDLE: - case VA1J5JF8007S_SET_FREQUENCY_1: - case VA1J5JF8007S_SET_FREQUENCY_2: - case VA1J5JF8007S_SET_FREQUENCY_3: - case VA1J5JF8007S_CHECK_FREQUENCY: - *status = 0; - return 0; - - - case VA1J5JF8007S_SET_MODULATION: - case VA1J5JF8007S_CHECK_MODULATION: - *status |= FE_HAS_SIGNAL; - return 0; - - case VA1J5JF8007S_SET_TS_ID: - case VA1J5JF8007S_CHECK_TS_ID: - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; - return 0; - - case VA1J5JF8007S_TRACK: - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; - return 0; - } - - BUG(); -} - -struct va1j5jf8007s_cb_map { - u32 frequency; - u8 cb; -}; - -static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = { - { 986000, 0xb2 }, - { 1072000, 0xd2 }, - { 1154000, 0xe2 }, - { 1291000, 0x20 }, - { 1447000, 0x40 }, - { 1615000, 0x60 }, - { 1791000, 0x80 }, - { 1972000, 0xa0 }, -}; - -static u8 va1j5jf8007s_lookup_cb(u32 frequency) -{ - int i; - const struct va1j5jf8007s_cb_map *map; - - for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) { - map = &va1j5jf8007s_cb_maps[i]; - if (frequency < map->frequency) - return map->cb; - } - return 0xc0; -} - -static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state) -{ - u32 frequency; - u16 word; - u8 buf[6]; - struct i2c_msg msg; - - frequency = state->fe.dtv_property_cache.frequency; - - word = (frequency + 500) / 1000; - if (frequency < 1072000) - word = (word << 1 & ~0x1f) | (word & 0x0f); - - buf[0] = 0xfe; - buf[1] = 0xc0; - buf[2] = 0x40 | word >> 8; - buf[3] = word; - buf[4] = 0xe0; - buf[5] = va1j5jf8007s_lookup_cb(frequency); - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state) -{ - u8 buf[3]; - struct i2c_msg msg; - - buf[0] = 0xfe; - buf[1] = 0xc0; - buf[2] = 0xe4; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state) -{ - u32 frequency; - u8 buf[4]; - struct i2c_msg msg; - - frequency = state->fe.dtv_property_cache.frequency; - - buf[0] = 0xfe; - buf[1] = 0xc0; - buf[2] = 0xf4; - buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int -va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock) -{ - u8 addr; - u8 write_buf[2], read_buf[1]; - struct i2c_msg msgs[2]; - - addr = state->config->demod_address; - - write_buf[0] = 0xfe; - write_buf[1] = 0xc1; - - msgs[0].addr = addr; - msgs[0].flags = 0; - msgs[0].len = sizeof(write_buf); - msgs[0].buf = write_buf; - - msgs[1].addr = addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(read_buf); - msgs[1].buf = read_buf; - - if (i2c_transfer(state->adap, msgs, 2) != 2) - return -EREMOTEIO; - - *lock = read_buf[0] & 0x40; - return 0; -} - -static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state) -{ - u8 buf[2]; - struct i2c_msg msg; - - buf[0] = 0x03; - buf[1] = 0x01; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int -va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock) -{ - u8 addr; - u8 write_buf[1], read_buf[1]; - struct i2c_msg msgs[2]; - - addr = state->config->demod_address; - - write_buf[0] = 0xc3; - - msgs[0].addr = addr; - msgs[0].flags = 0; - msgs[0].len = sizeof(write_buf); - msgs[0].buf = write_buf; - - msgs[1].addr = addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(read_buf); - msgs[1].buf = read_buf; - - if (i2c_transfer(state->adap, msgs, 2) != 2) - return -EREMOTEIO; - - *lock = !(read_buf[0] & 0x10); - return 0; -} - -static int -va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state) -{ - u32 ts_id; - u8 buf[3]; - struct i2c_msg msg; - - ts_id = state->fe.dtv_property_cache.isdbs_ts_id; - if (!ts_id) - return 0; - - buf[0] = 0x8f; - buf[1] = ts_id >> 8; - buf[2] = ts_id; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int -va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock) -{ - u8 addr; - u8 write_buf[1], read_buf[2]; - struct i2c_msg msgs[2]; - u32 ts_id; - - ts_id = state->fe.dtv_property_cache.isdbs_ts_id; - if (!ts_id) { - *lock = 1; - return 0; - } - - addr = state->config->demod_address; - - write_buf[0] = 0xe6; - - msgs[0].addr = addr; - msgs[0].flags = 0; - msgs[0].len = sizeof(write_buf); - msgs[0].buf = write_buf; - - msgs[1].addr = addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(read_buf); - msgs[1].buf = read_buf; - - if (i2c_transfer(state->adap, msgs, 2) != 2) - return -EREMOTEIO; - - *lock = (read_buf[0] << 8 | read_buf[1]) == ts_id; - return 0; -} - -static int -va1j5jf8007s_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, - unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) -{ - struct va1j5jf8007s_state *state; - int ret; - int lock = 0; - - state = fe->demodulator_priv; - - if (params != NULL) - state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1; - - switch (state->tune_state) { - case VA1J5JF8007S_IDLE: - *delay = 3 * HZ; - *status = 0; - return 0; - - case VA1J5JF8007S_SET_FREQUENCY_1: - ret = va1j5jf8007s_set_frequency_1(state); - if (ret < 0) - return ret; - - state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2; - *delay = 0; - *status = 0; - return 0; - - case VA1J5JF8007S_SET_FREQUENCY_2: - ret = va1j5jf8007s_set_frequency_2(state); - if (ret < 0) - return ret; - - state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3; - *delay = (HZ + 99) / 100; - *status = 0; - return 0; - - case VA1J5JF8007S_SET_FREQUENCY_3: - ret = va1j5jf8007s_set_frequency_3(state); - if (ret < 0) - return ret; - - state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY; - *delay = 0; - *status = 0; - return 0; - - case VA1J5JF8007S_CHECK_FREQUENCY: - ret = va1j5jf8007s_check_frequency(state, &lock); - if (ret < 0) - return ret; - - if (!lock) { - *delay = (HZ + 999) / 1000; - *status = 0; - return 0; - } - - state->tune_state = VA1J5JF8007S_SET_MODULATION; - *delay = 0; - *status = FE_HAS_SIGNAL; - return 0; - - case VA1J5JF8007S_SET_MODULATION: - ret = va1j5jf8007s_set_modulation(state); - if (ret < 0) - return ret; - - state->tune_state = VA1J5JF8007S_CHECK_MODULATION; - *delay = 0; - *status = FE_HAS_SIGNAL; - return 0; - - case VA1J5JF8007S_CHECK_MODULATION: - ret = va1j5jf8007s_check_modulation(state, &lock); - if (ret < 0) - return ret; - - if (!lock) { - *delay = (HZ + 49) / 50; - *status = FE_HAS_SIGNAL; - return 0; - } - - state->tune_state = VA1J5JF8007S_SET_TS_ID; - *delay = 0; - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - return 0; - - case VA1J5JF8007S_SET_TS_ID: - ret = va1j5jf8007s_set_ts_id(state); - if (ret < 0) - return ret; - - state->tune_state = VA1J5JF8007S_CHECK_TS_ID; - return 0; - - case VA1J5JF8007S_CHECK_TS_ID: - ret = va1j5jf8007s_check_ts_id(state, &lock); - if (ret < 0) - return ret; - - if (!lock) { - *delay = (HZ + 99) / 100; - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - return 0; - } - - state->tune_state = VA1J5JF8007S_TRACK; - /* fall through */ - - case VA1J5JF8007S_TRACK: - *delay = 3 * HZ; - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; - return 0; - } - - BUG(); -} - -static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state) -{ - u8 buf[4]; - struct i2c_msg msg; - - buf[0] = 0xfe; - buf[1] = 0xc0; - buf[2] = 0xf0; - buf[3] = 0x04; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep) -{ - u8 buf[2]; - struct i2c_msg msg; - - buf[0] = 0x17; - buf[1] = sleep ? 0x01 : 0x00; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int va1j5jf8007s_sleep(struct dvb_frontend *fe) -{ - struct va1j5jf8007s_state *state; - int ret; - - state = fe->demodulator_priv; - - ret = va1j5jf8007s_init_frequency(state); - if (ret < 0) - return ret; - - return va1j5jf8007s_set_sleep(state, 1); -} - -static int va1j5jf8007s_init(struct dvb_frontend *fe) -{ - struct va1j5jf8007s_state *state; - - state = fe->demodulator_priv; - state->tune_state = VA1J5JF8007S_IDLE; - - return va1j5jf8007s_set_sleep(state, 0); -} - -static void va1j5jf8007s_release(struct dvb_frontend *fe) -{ - struct va1j5jf8007s_state *state; - state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops va1j5jf8007s_ops = { - .info = { - .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1000, - .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, - }, - - .read_snr = va1j5jf8007s_read_snr, - .get_frontend_algo = va1j5jf8007s_get_frontend_algo, - .read_status = va1j5jf8007s_read_status, - .tune = va1j5jf8007s_tune, - .sleep = va1j5jf8007s_sleep, - .init = va1j5jf8007s_init, - .release = va1j5jf8007s_release, -}; - -static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state) -{ - u8 addr; - u8 write_buf[1], read_buf[1]; - struct i2c_msg msgs[2]; - - addr = state->config->demod_address; - - write_buf[0] = 0x07; - - msgs[0].addr = addr; - msgs[0].flags = 0; - msgs[0].len = sizeof(write_buf); - msgs[0].buf = write_buf; - - msgs[1].addr = addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(read_buf); - msgs[1].buf = read_buf; - - if (i2c_transfer(state->adap, msgs, 2) != 2) - return -EREMOTEIO; - - if (read_buf[0] != 0x41) - return -EIO; - - return 0; -} - -static const u8 va1j5jf8007s_20mhz_prepare_bufs[][2] = { - {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, - {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, - {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, - {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0}, -}; - -static const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = { - {0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a}, - {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89}, - {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04}, - {0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0}, -}; - -static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state) -{ - const u8 (*bufs)[2]; - int size; - u8 addr; - u8 buf[2]; - struct i2c_msg msg; - int i; - - switch (state->config->frequency) { - case VA1J5JF8007S_20MHZ: - bufs = va1j5jf8007s_20mhz_prepare_bufs; - size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs); - break; - case VA1J5JF8007S_25MHZ: - bufs = va1j5jf8007s_25mhz_prepare_bufs; - size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs); - break; - default: - return -EINVAL; - } - - addr = state->config->demod_address; - - msg.addr = addr; - msg.flags = 0; - msg.len = 2; - msg.buf = buf; - for (i = 0; i < size; i++) { - memcpy(buf, bufs[i], sizeof(buf)); - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - } - - return 0; -} - -/* must be called after va1j5jf8007t_attach */ -int va1j5jf8007s_prepare(struct dvb_frontend *fe) -{ - struct va1j5jf8007s_state *state; - int ret; - - state = fe->demodulator_priv; - - ret = va1j5jf8007s_prepare_1(state); - if (ret < 0) - return ret; - - ret = va1j5jf8007s_prepare_2(state); - if (ret < 0) - return ret; - - return va1j5jf8007s_init_frequency(state); -} - -struct dvb_frontend * -va1j5jf8007s_attach(const struct va1j5jf8007s_config *config, - struct i2c_adapter *adap) -{ - struct va1j5jf8007s_state *state; - struct dvb_frontend *fe; - u8 buf[2]; - struct i2c_msg msg; - - state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL); - if (!state) - return NULL; - - state->config = config; - state->adap = adap; - - fe = &state->fe; - memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops)); - fe->demodulator_priv = state; - - buf[0] = 0x01; - buf[1] = 0x80; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) { - kfree(state); - return NULL; - } - - return fe; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007s.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007s.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007s.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007s.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef VA1J5JF8007S_H -#define VA1J5JF8007S_H - -enum va1j5jf8007s_frequency { - VA1J5JF8007S_20MHZ, - VA1J5JF8007S_25MHZ, -}; - -struct va1j5jf8007s_config { - u8 demod_address; - enum va1j5jf8007s_frequency frequency; -}; - -struct i2c_adapter; - -struct dvb_frontend * -va1j5jf8007s_attach(const struct va1j5jf8007s_config *config, - struct i2c_adapter *adap); - -/* must be called after va1j5jf8007t_attach */ -int va1j5jf8007s_prepare(struct dvb_frontend *fe); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007t.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007t.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007t.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007t.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,536 +0,0 @@ -/* - * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include "dvb_frontend.h" -#include "dvb_math.h" -#include "va1j5jf8007t.h" - -enum va1j5jf8007t_tune_state { - VA1J5JF8007T_IDLE, - VA1J5JF8007T_SET_FREQUENCY, - VA1J5JF8007T_CHECK_FREQUENCY, - VA1J5JF8007T_SET_MODULATION, - VA1J5JF8007T_CHECK_MODULATION, - VA1J5JF8007T_TRACK, - VA1J5JF8007T_ABORT, -}; - -struct va1j5jf8007t_state { - const struct va1j5jf8007t_config *config; - struct i2c_adapter *adap; - struct dvb_frontend fe; - enum va1j5jf8007t_tune_state tune_state; -}; - -static int va1j5jf8007t_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct va1j5jf8007t_state *state; - u8 addr; - int i; - u8 write_buf[1], read_buf[1]; - struct i2c_msg msgs[2]; - s32 word, x, y; - - state = fe->demodulator_priv; - addr = state->config->demod_address; - - word = 0; - for (i = 0; i < 3; i++) { - write_buf[0] = 0x8b + i; - - msgs[0].addr = addr; - msgs[0].flags = 0; - msgs[0].len = sizeof(write_buf); - msgs[0].buf = write_buf; - - msgs[1].addr = addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(read_buf); - msgs[1].buf = read_buf; - - if (i2c_transfer(state->adap, msgs, 2) != 2) - return -EREMOTEIO; - - word <<= 8; - word |= read_buf[0]; - } - - if (!word) - return -EIO; - - x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24)); - y = (24ll << 46) / 1000000; - y = ((s64)y * x >> 30) - (16ll << 40) / 10000; - y = ((s64)y * x >> 29) + (398ll << 35) / 10000; - y = ((s64)y * x >> 30) + (5491ll << 29) / 10000; - y = ((s64)y * x >> 30) + (30965ll << 23) / 10000; - *snr = y >> 15; - return 0; -} - -static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe) -{ - return DVBFE_ALGO_HW; -} - -static int -va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct va1j5jf8007t_state *state; - - state = fe->demodulator_priv; - - switch (state->tune_state) { - case VA1J5JF8007T_IDLE: - case VA1J5JF8007T_SET_FREQUENCY: - case VA1J5JF8007T_CHECK_FREQUENCY: - *status = 0; - return 0; - - - case VA1J5JF8007T_SET_MODULATION: - case VA1J5JF8007T_CHECK_MODULATION: - case VA1J5JF8007T_ABORT: - *status |= FE_HAS_SIGNAL; - return 0; - - case VA1J5JF8007T_TRACK: - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; - return 0; - } - - BUG(); -} - -struct va1j5jf8007t_cb_map { - u32 frequency; - u8 cb; -}; - -static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = { - { 90000000, 0x80 }, - { 140000000, 0x81 }, - { 170000000, 0xa1 }, - { 220000000, 0x62 }, - { 330000000, 0xa2 }, - { 402000000, 0xe2 }, - { 450000000, 0x64 }, - { 550000000, 0x84 }, - { 600000000, 0xa4 }, - { 700000000, 0xc4 }, -}; - -static u8 va1j5jf8007t_lookup_cb(u32 frequency) -{ - int i; - const struct va1j5jf8007t_cb_map *map; - - for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) { - map = &va1j5jf8007t_cb_maps[i]; - if (frequency < map->frequency) - return map->cb; - } - return 0xe4; -} - -static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state) -{ - u32 frequency; - u16 word; - u8 buf[6]; - struct i2c_msg msg; - - frequency = state->fe.dtv_property_cache.frequency; - - word = (frequency + 71428) / 142857 + 399; - buf[0] = 0xfe; - buf[1] = 0xc2; - buf[2] = word >> 8; - buf[3] = word; - buf[4] = 0x80; - buf[5] = va1j5jf8007t_lookup_cb(frequency); - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int -va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock) -{ - u8 addr; - u8 write_buf[2], read_buf[1]; - struct i2c_msg msgs[2]; - - addr = state->config->demod_address; - - write_buf[0] = 0xfe; - write_buf[1] = 0xc3; - - msgs[0].addr = addr; - msgs[0].flags = 0; - msgs[0].len = sizeof(write_buf); - msgs[0].buf = write_buf; - - msgs[1].addr = addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(read_buf); - msgs[1].buf = read_buf; - - if (i2c_transfer(state->adap, msgs, 2) != 2) - return -EREMOTEIO; - - *lock = read_buf[0] & 0x40; - return 0; -} - -static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state) -{ - u8 buf[2]; - struct i2c_msg msg; - - buf[0] = 0x01; - buf[1] = 0x40; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state, - int *lock, int *retry) -{ - u8 addr; - u8 write_buf[1], read_buf[1]; - struct i2c_msg msgs[2]; - - addr = state->config->demod_address; - - write_buf[0] = 0x80; - - msgs[0].addr = addr; - msgs[0].flags = 0; - msgs[0].len = sizeof(write_buf); - msgs[0].buf = write_buf; - - msgs[1].addr = addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(read_buf); - msgs[1].buf = read_buf; - - if (i2c_transfer(state->adap, msgs, 2) != 2) - return -EREMOTEIO; - - *lock = !(read_buf[0] & 0x10); - *retry = read_buf[0] & 0x80; - return 0; -} - -static int -va1j5jf8007t_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, - unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) -{ - struct va1j5jf8007t_state *state; - int ret; - int lock = 0, retry = 0; - - state = fe->demodulator_priv; - - if (params != NULL) - state->tune_state = VA1J5JF8007T_SET_FREQUENCY; - - switch (state->tune_state) { - case VA1J5JF8007T_IDLE: - *delay = 3 * HZ; - *status = 0; - return 0; - - case VA1J5JF8007T_SET_FREQUENCY: - ret = va1j5jf8007t_set_frequency(state); - if (ret < 0) - return ret; - - state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY; - *delay = 0; - *status = 0; - return 0; - - case VA1J5JF8007T_CHECK_FREQUENCY: - ret = va1j5jf8007t_check_frequency(state, &lock); - if (ret < 0) - return ret; - - if (!lock) { - *delay = (HZ + 999) / 1000; - *status = 0; - return 0; - } - - state->tune_state = VA1J5JF8007T_SET_MODULATION; - *delay = 0; - *status = FE_HAS_SIGNAL; - return 0; - - case VA1J5JF8007T_SET_MODULATION: - ret = va1j5jf8007t_set_modulation(state); - if (ret < 0) - return ret; - - state->tune_state = VA1J5JF8007T_CHECK_MODULATION; - *delay = 0; - *status = FE_HAS_SIGNAL; - return 0; - - case VA1J5JF8007T_CHECK_MODULATION: - ret = va1j5jf8007t_check_modulation(state, &lock, &retry); - if (ret < 0) - return ret; - - if (!lock) { - if (!retry) { - state->tune_state = VA1J5JF8007T_ABORT; - *delay = 3 * HZ; - *status = FE_HAS_SIGNAL; - return 0; - } - *delay = (HZ + 999) / 1000; - *status = FE_HAS_SIGNAL; - return 0; - } - - state->tune_state = VA1J5JF8007T_TRACK; - /* fall through */ - - case VA1J5JF8007T_TRACK: - *delay = 3 * HZ; - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; - return 0; - - case VA1J5JF8007T_ABORT: - *delay = 3 * HZ; - *status = FE_HAS_SIGNAL; - return 0; - } - - BUG(); -} - -static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state) -{ - u8 buf[7]; - struct i2c_msg msg; - - buf[0] = 0xfe; - buf[1] = 0xc2; - buf[2] = 0x01; - buf[3] = 0x8f; - buf[4] = 0xc1; - buf[5] = 0x80; - buf[6] = 0x80; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep) -{ - u8 buf[2]; - struct i2c_msg msg; - - buf[0] = 0x03; - buf[1] = sleep ? 0x90 : 0x80; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - - return 0; -} - -static int va1j5jf8007t_sleep(struct dvb_frontend *fe) -{ - struct va1j5jf8007t_state *state; - int ret; - - state = fe->demodulator_priv; - - ret = va1j5jf8007t_init_frequency(state); - if (ret < 0) - return ret; - - return va1j5jf8007t_set_sleep(state, 1); -} - -static int va1j5jf8007t_init(struct dvb_frontend *fe) -{ - struct va1j5jf8007t_state *state; - - state = fe->demodulator_priv; - state->tune_state = VA1J5JF8007T_IDLE; - - return va1j5jf8007t_set_sleep(state, 0); -} - -static void va1j5jf8007t_release(struct dvb_frontend *fe) -{ - struct va1j5jf8007t_state *state; - state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops va1j5jf8007t_ops = { - .info = { - .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T", - .type = FE_OFDM, - .frequency_min = 90000000, - .frequency_max = 770000000, - .frequency_stepsize = 142857, - .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, - }, - - .read_snr = va1j5jf8007t_read_snr, - .get_frontend_algo = va1j5jf8007t_get_frontend_algo, - .read_status = va1j5jf8007t_read_status, - .tune = va1j5jf8007t_tune, - .sleep = va1j5jf8007t_sleep, - .init = va1j5jf8007t_init, - .release = va1j5jf8007t_release, -}; - -static const u8 va1j5jf8007t_20mhz_prepare_bufs[][2] = { - {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, - {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00}, - {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03}, - {0xef, 0x01} -}; - -static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = { - {0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83}, - {0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c}, - {0x77, 0x03}, {0xef, 0x01} -}; - -int va1j5jf8007t_prepare(struct dvb_frontend *fe) -{ - struct va1j5jf8007t_state *state; - const u8 (*bufs)[2]; - int size; - u8 buf[2]; - struct i2c_msg msg; - int i; - - state = fe->demodulator_priv; - - switch (state->config->frequency) { - case VA1J5JF8007T_20MHZ: - bufs = va1j5jf8007t_20mhz_prepare_bufs; - size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs); - break; - case VA1J5JF8007T_25MHZ: - bufs = va1j5jf8007t_25mhz_prepare_bufs; - size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs); - break; - default: - return -EINVAL; - } - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - for (i = 0; i < size; i++) { - memcpy(buf, bufs[i], sizeof(buf)); - if (i2c_transfer(state->adap, &msg, 1) != 1) - return -EREMOTEIO; - } - - return va1j5jf8007t_init_frequency(state); -} - -struct dvb_frontend * -va1j5jf8007t_attach(const struct va1j5jf8007t_config *config, - struct i2c_adapter *adap) -{ - struct va1j5jf8007t_state *state; - struct dvb_frontend *fe; - u8 buf[2]; - struct i2c_msg msg; - - state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL); - if (!state) - return NULL; - - state->config = config; - state->adap = adap; - - fe = &state->fe; - memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops)); - fe->demodulator_priv = state; - - buf[0] = 0x01; - buf[1] = 0x80; - - msg.addr = state->config->demod_address; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(state->adap, &msg, 1) != 1) { - kfree(state); - return NULL; - } - - return fe; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007t.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007t.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007t.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/pt1/va1j5jf8007t.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 - * - * Copyright (C) 2009 HIRANO Takahito - * - * based on pt1dvr - http://pt1dvr.sourceforge.jp/ - * by Tomoaki Ishikawa - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef VA1J5JF8007T_H -#define VA1J5JF8007T_H - -enum va1j5jf8007t_frequency { - VA1J5JF8007T_20MHZ, - VA1J5JF8007T_25MHZ, -}; - -struct va1j5jf8007t_config { - u8 demod_address; - enum va1j5jf8007t_frequency frequency; -}; - -struct i2c_adapter; - -struct dvb_frontend * -va1j5jf8007t_attach(const struct va1j5jf8007t_config *config, - struct i2c_adapter *adap); - -/* must be called after va1j5jf8007s_attach */ -int va1j5jf8007t_prepare(struct dvb_frontend *fe); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -# -# Siano Mobile Silicon Digital TV device configuration -# - -config SMS_SIANO_MDTV - tristate "Siano SMS1xxx based MDTV receiver" - depends on DVB_CORE && RC_CORE && HAS_DMA - ---help--- - Choose Y or M here if you have MDTV receiver with a Siano chipset. - - To compile this driver as a module, choose M here - (The module will be called smsmdtv). - - Further documentation on this driver can be found on the WWW - at http://www.siano-ms.com/ - -if SMS_SIANO_MDTV -menu "Siano module components" - -# Hardware interfaces support - -config SMS_USB_DRV - tristate "USB interface support" - depends on DVB_CORE && USB - ---help--- - Choose if you would like to have Siano's support for USB interface - -config SMS_SDIO_DRV - tristate "SDIO interface support" - depends on DVB_CORE && MMC - ---help--- - Choose if you would like to have Siano's support for SDIO interface -endmenu -endif # SMS_SIANO_MDTV diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ - -smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o - -obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o -obj-$(CONFIG_SMS_USB_DRV) += smsusb.o -obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core - -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/sms-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/sms-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/sms-cards.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/sms-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,310 +0,0 @@ -/* - * Card-specific functions for the Siano SMS1xxx USB dongle - * - * Copyright (c) 2008 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "sms-cards.h" -#include "smsir.h" - -static int sms_dbg; -module_param_named(cards_dbg, sms_dbg, int, 0644); -MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))"); - -static struct sms_board sms_boards[] = { - [SMS_BOARD_UNKNOWN] = { - .name = "Unknown board", - }, - [SMS1XXX_BOARD_SIANO_STELLAR] = { - .name = "Siano Stellar Digital Receiver", - .type = SMS_STELLAR, - }, - [SMS1XXX_BOARD_SIANO_NOVA_A] = { - .name = "Siano Nova A Digital Receiver", - .type = SMS_NOVA_A0, - }, - [SMS1XXX_BOARD_SIANO_NOVA_B] = { - .name = "Siano Nova B Digital Receiver", - .type = SMS_NOVA_B0, - }, - [SMS1XXX_BOARD_SIANO_VEGA] = { - .name = "Siano Vega Digital Receiver", - .type = SMS_VEGA, - }, - [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = { - .name = "Hauppauge Catamount", - .type = SMS_STELLAR, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", - }, - [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = { - .name = "Hauppauge Okemo-A", - .type = SMS_NOVA_A0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", - }, - [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = { - .name = "Hauppauge Okemo-B", - .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", - }, - [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { - .name = "Hauppauge WinTV MiniStick", - .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw", - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", - .rc_codes = RC_MAP_HAUPPAUGE, - .board_cfg.leds_power = 26, - .board_cfg.led0 = 27, - .board_cfg.led1 = 28, - .board_cfg.ir = 9, - .led_power = 26, - .led_lo = 27, - .led_hi = 28, - }, - [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = { - .name = "Hauppauge WinTV MiniCard", - .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", - .lna_ctrl = 29, - .board_cfg.foreign_lna0_ctrl = 29, - .rf_switch = 17, - .board_cfg.rf_switch_uhf = 17, - }, - [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { - .name = "Hauppauge WinTV MiniCard", - .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", - .lna_ctrl = -1, - }, - [SMS1XXX_BOARD_SIANO_NICE] = { - /* 11 */ - .name = "Siano Nice Digital Receiver", - .type = SMS_NOVA_B0, - }, - [SMS1XXX_BOARD_SIANO_VENICE] = { - /* 12 */ - .name = "Siano Venice Digital Receiver", - .type = SMS_VEGA, - }, -}; - -struct sms_board *sms_get_board(unsigned id) -{ - BUG_ON(id >= ARRAY_SIZE(sms_boards)); - - return &sms_boards[id]; -} -EXPORT_SYMBOL_GPL(sms_get_board); -static inline void sms_gpio_assign_11xx_default_led_config( - struct smscore_gpio_config *pGpioConfig) { - pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT; - pGpioConfig->InputCharacteristics = - SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL; - pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA; - pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; - pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE; -} - -int sms_board_event(struct smscore_device_t *coredev, - enum SMS_BOARD_EVENTS gevent) { - struct smscore_gpio_config MyGpioConfig; - - sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); - - switch (gevent) { - case BOARD_EVENT_POWER_INIT: /* including hotplug */ - break; /* BOARD_EVENT_BIND */ - - case BOARD_EVENT_POWER_SUSPEND: - break; /* BOARD_EVENT_POWER_SUSPEND */ - - case BOARD_EVENT_POWER_RESUME: - break; /* BOARD_EVENT_POWER_RESUME */ - - case BOARD_EVENT_BIND: - break; /* BOARD_EVENT_BIND */ - - case BOARD_EVENT_SCAN_PROG: - break; /* BOARD_EVENT_SCAN_PROG */ - case BOARD_EVENT_SCAN_COMP: - break; /* BOARD_EVENT_SCAN_COMP */ - case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL: - break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */ - case BOARD_EVENT_FE_LOCK: - break; /* BOARD_EVENT_FE_LOCK */ - case BOARD_EVENT_FE_UNLOCK: - break; /* BOARD_EVENT_FE_UNLOCK */ - case BOARD_EVENT_DEMOD_LOCK: - break; /* BOARD_EVENT_DEMOD_LOCK */ - case BOARD_EVENT_DEMOD_UNLOCK: - break; /* BOARD_EVENT_DEMOD_UNLOCK */ - case BOARD_EVENT_RECEPTION_MAX_4: - break; /* BOARD_EVENT_RECEPTION_MAX_4 */ - case BOARD_EVENT_RECEPTION_3: - break; /* BOARD_EVENT_RECEPTION_3 */ - case BOARD_EVENT_RECEPTION_2: - break; /* BOARD_EVENT_RECEPTION_2 */ - case BOARD_EVENT_RECEPTION_1: - break; /* BOARD_EVENT_RECEPTION_1 */ - case BOARD_EVENT_RECEPTION_LOST_0: - break; /* BOARD_EVENT_RECEPTION_LOST_0 */ - case BOARD_EVENT_MULTIPLEX_OK: - break; /* BOARD_EVENT_MULTIPLEX_OK */ - case BOARD_EVENT_MULTIPLEX_ERRORS: - break; /* BOARD_EVENT_MULTIPLEX_ERRORS */ - - default: - sms_err("Unknown SMS board event"); - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_event); - -static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable) -{ - int lvl, ret; - u32 gpio; - struct smscore_config_gpio gpioconfig = { - .direction = SMS_GPIO_DIRECTION_OUTPUT, - .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, - .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, - .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST, - .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA, - }; - - if (pin == 0) - return -EINVAL; - - if (pin < 0) { - /* inverted gpio */ - gpio = pin * -1; - lvl = enable ? 0 : 1; - } else { - gpio = pin; - lvl = enable ? 1 : 0; - } - - ret = smscore_configure_gpio(coredev, gpio, &gpioconfig); - if (ret < 0) - return ret; - - return smscore_set_gpio(coredev, gpio, lvl); -} - -int sms_board_setup(struct smscore_device_t *coredev) -{ - int board_id = smscore_get_board_id(coredev); - struct sms_board *board = sms_get_board(board_id); - - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - /* turn off all LEDs */ - sms_set_gpio(coredev, board->led_power, 0); - sms_set_gpio(coredev, board->led_hi, 0); - sms_set_gpio(coredev, board->led_lo, 0); - break; - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - /* turn off LNA */ - sms_set_gpio(coredev, board->lna_ctrl, 0); - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_setup); - -int sms_board_power(struct smscore_device_t *coredev, int onoff) -{ - int board_id = smscore_get_board_id(coredev); - struct sms_board *board = sms_get_board(board_id); - - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - /* power LED */ - sms_set_gpio(coredev, - board->led_power, onoff ? 1 : 0); - break; - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - /* LNA */ - if (!onoff) - sms_set_gpio(coredev, board->lna_ctrl, 0); - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_power); - -int sms_board_led_feedback(struct smscore_device_t *coredev, int led) -{ - int board_id = smscore_get_board_id(coredev); - struct sms_board *board = sms_get_board(board_id); - - /* dont touch GPIO if LEDs are already set */ - if (smscore_led_state(coredev, -1) == led) - return 0; - - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - sms_set_gpio(coredev, - board->led_lo, (led & SMS_LED_LO) ? 1 : 0); - sms_set_gpio(coredev, - board->led_hi, (led & SMS_LED_HI) ? 1 : 0); - - smscore_led_state(coredev, led); - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_led_feedback); - -int sms_board_lna_control(struct smscore_device_t *coredev, int onoff) -{ - int board_id = smscore_get_board_id(coredev); - struct sms_board *board = sms_get_board(board_id); - - sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled"); - - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - sms_set_gpio(coredev, - board->rf_switch, onoff ? 1 : 0); - return sms_set_gpio(coredev, - board->lna_ctrl, onoff ? 1 : 0); - } - return -EINVAL; -} -EXPORT_SYMBOL_GPL(sms_board_lna_control); - -int sms_board_load_modules(int id) -{ - switch (id) { - case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT: - case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A: - case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B: - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - request_module("smsdvb"); - break; - default: - /* do nothing */ - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(sms_board_load_modules); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/sms-cards.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/sms-cards.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/sms-cards.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/sms-cards.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -/* - * Card-specific functions for the Siano SMS1xxx USB dongle - * - * Copyright (c) 2008 Michael Krufky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __SMS_CARDS_H__ -#define __SMS_CARDS_H__ - -#include -#include "smscoreapi.h" -#include "smsir.h" - -#define SMS_BOARD_UNKNOWN 0 -#define SMS1XXX_BOARD_SIANO_STELLAR 1 -#define SMS1XXX_BOARD_SIANO_NOVA_A 2 -#define SMS1XXX_BOARD_SIANO_NOVA_B 3 -#define SMS1XXX_BOARD_SIANO_VEGA 4 -#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5 -#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6 -#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7 -#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8 -#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9 -#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 -#define SMS1XXX_BOARD_SIANO_NICE 11 -#define SMS1XXX_BOARD_SIANO_VENICE 12 - -struct sms_board_gpio_cfg { - int lna_vhf_exist; - int lna_vhf_ctrl; - int lna_uhf_exist; - int lna_uhf_ctrl; - int lna_uhf_d_ctrl; - int lna_sband_exist; - int lna_sband_ctrl; - int lna_sband_d_ctrl; - int foreign_lna0_ctrl; - int foreign_lna1_ctrl; - int foreign_lna2_ctrl; - int rf_switch_vhf; - int rf_switch_uhf; - int rf_switch_sband; - int leds_power; - int led0; - int led1; - int led2; - int led3; - int led4; - int ir; - int eeprom_wp; - int mrc_sense; - int mrc_pdn_resetn; - int mrc_gp0; /* mrcs spi int */ - int mrc_gp1; - int mrc_gp2; - int mrc_gp3; - int mrc_gp4; - int host_spi_gsp_ts_int; -}; - -struct sms_board { - enum sms_device_type_st type; - char *name, *fw[DEVICE_MODE_MAX]; - struct sms_board_gpio_cfg board_cfg; - char *rc_codes; /* Name of IR codes table */ - - /* gpios */ - int led_power, led_hi, led_lo, lna_ctrl, rf_switch; -}; - -struct sms_board *sms_get_board(unsigned id); - -extern struct smscore_device_t *coredev; - -enum SMS_BOARD_EVENTS { - BOARD_EVENT_POWER_INIT, - BOARD_EVENT_POWER_SUSPEND, - BOARD_EVENT_POWER_RESUME, - BOARD_EVENT_BIND, - BOARD_EVENT_SCAN_PROG, - BOARD_EVENT_SCAN_COMP, - BOARD_EVENT_EMERGENCY_WARNING_SIGNAL, - BOARD_EVENT_FE_LOCK, - BOARD_EVENT_FE_UNLOCK, - BOARD_EVENT_DEMOD_LOCK, - BOARD_EVENT_DEMOD_UNLOCK, - BOARD_EVENT_RECEPTION_MAX_4, - BOARD_EVENT_RECEPTION_3, - BOARD_EVENT_RECEPTION_2, - BOARD_EVENT_RECEPTION_1, - BOARD_EVENT_RECEPTION_LOST_0, - BOARD_EVENT_MULTIPLEX_OK, - BOARD_EVENT_MULTIPLEX_ERRORS -}; - -int sms_board_event(struct smscore_device_t *coredev, - enum SMS_BOARD_EVENTS gevent); - -int sms_board_setup(struct smscore_device_t *coredev); - -#define SMS_LED_OFF 0 -#define SMS_LED_LO 1 -#define SMS_LED_HI 2 -int sms_board_led_feedback(struct smscore_device_t *coredev, int led); -int sms_board_power(struct smscore_device_t *coredev, int onoff); -int sms_board_lna_control(struct smscore_device_t *coredev, int onoff); - -extern int sms_board_load_modules(int id); - -#endif /* __SMS_CARDS_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smscoreapi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smscoreapi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smscoreapi.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smscoreapi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1644 +0,0 @@ -/* - * Siano core API module - * - * This file contains implementation for the interface to sms core component - * - * author: Uri Shkolnik - * - * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "smscoreapi.h" -#include "sms-cards.h" -#include "smsir.h" -#include "smsendian.h" - -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - -struct smscore_device_notifyee_t { - struct list_head entry; - hotplug_t hotplug; -}; - -struct smscore_idlist_t { - struct list_head entry; - int id; - int data_type; -}; - -struct smscore_client_t { - struct list_head entry; - struct smscore_device_t *coredev; - void *context; - struct list_head idlist; - onresponse_t onresponse_handler; - onremove_t onremove_handler; -}; - -void smscore_set_board_id(struct smscore_device_t *core, int id) -{ - core->board_id = id; -} - -int smscore_led_state(struct smscore_device_t *core, int led) -{ - if (led >= 0) - core->led_state = led; - return core->led_state; -} -EXPORT_SYMBOL_GPL(smscore_set_board_id); - -int smscore_get_board_id(struct smscore_device_t *core) -{ - return core->board_id; -} -EXPORT_SYMBOL_GPL(smscore_get_board_id); - -struct smscore_registry_entry_t { - struct list_head entry; - char devpath[32]; - int mode; - enum sms_device_type_st type; -}; - -static struct list_head g_smscore_notifyees; -static struct list_head g_smscore_devices; -static struct mutex g_smscore_deviceslock; - -static struct list_head g_smscore_registry; -static struct mutex g_smscore_registrylock; - -static int default_mode = 4; - -module_param(default_mode, int, 0644); -MODULE_PARM_DESC(default_mode, "default firmware id (device mode)"); - -static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) -{ - struct smscore_registry_entry_t *entry; - struct list_head *next; - - kmutex_lock(&g_smscore_registrylock); - for (next = g_smscore_registry.next; - next != &g_smscore_registry; - next = next->next) { - entry = (struct smscore_registry_entry_t *) next; - if (!strcmp(entry->devpath, devpath)) { - kmutex_unlock(&g_smscore_registrylock); - return entry; - } - } - entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL); - if (entry) { - entry->mode = default_mode; - strcpy(entry->devpath, devpath); - list_add(&entry->entry, &g_smscore_registry); - } else - sms_err("failed to create smscore_registry."); - kmutex_unlock(&g_smscore_registrylock); - return entry; -} - -int smscore_registry_getmode(char *devpath) -{ - struct smscore_registry_entry_t *entry; - - entry = smscore_find_registry(devpath); - if (entry) - return entry->mode; - else - sms_err("No registry found."); - - return default_mode; -} -EXPORT_SYMBOL_GPL(smscore_registry_getmode); - -static enum sms_device_type_st smscore_registry_gettype(char *devpath) -{ - struct smscore_registry_entry_t *entry; - - entry = smscore_find_registry(devpath); - if (entry) - return entry->type; - else - sms_err("No registry found."); - - return -1; -} - -void smscore_registry_setmode(char *devpath, int mode) -{ - struct smscore_registry_entry_t *entry; - - entry = smscore_find_registry(devpath); - if (entry) - entry->mode = mode; - else - sms_err("No registry found."); -} - -static void smscore_registry_settype(char *devpath, - enum sms_device_type_st type) -{ - struct smscore_registry_entry_t *entry; - - entry = smscore_find_registry(devpath); - if (entry) - entry->type = type; - else - sms_err("No registry found."); -} - - -static void list_add_locked(struct list_head *new, struct list_head *head, - spinlock_t *lock) -{ - unsigned long flags; - - spin_lock_irqsave(lock, flags); - - list_add(new, head); - - spin_unlock_irqrestore(lock, flags); -} - -/** - * register a client callback that called when device plugged in/unplugged - * NOTE: if devices exist callback is called immediately for each device - * - * @param hotplug callback - * - * @return 0 on success, <0 on error. - */ -int smscore_register_hotplug(hotplug_t hotplug) -{ - struct smscore_device_notifyee_t *notifyee; - struct list_head *next, *first; - int rc = 0; - - kmutex_lock(&g_smscore_deviceslock); - - notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t), - GFP_KERNEL); - if (notifyee) { - /* now notify callback about existing devices */ - first = &g_smscore_devices; - for (next = first->next; - next != first && !rc; - next = next->next) { - struct smscore_device_t *coredev = - (struct smscore_device_t *) next; - rc = hotplug(coredev, coredev->device, 1); - } - - if (rc >= 0) { - notifyee->hotplug = hotplug; - list_add(¬ifyee->entry, &g_smscore_notifyees); - } else - kfree(notifyee); - } else - rc = -ENOMEM; - - kmutex_unlock(&g_smscore_deviceslock); - - return rc; -} -EXPORT_SYMBOL_GPL(smscore_register_hotplug); - -/** - * unregister a client callback that called when device plugged in/unplugged - * - * @param hotplug callback - * - */ -void smscore_unregister_hotplug(hotplug_t hotplug) -{ - struct list_head *next, *first; - - kmutex_lock(&g_smscore_deviceslock); - - first = &g_smscore_notifyees; - - for (next = first->next; next != first;) { - struct smscore_device_notifyee_t *notifyee = - (struct smscore_device_notifyee_t *) next; - next = next->next; - - if (notifyee->hotplug == hotplug) { - list_del(¬ifyee->entry); - kfree(notifyee); - } - } - - kmutex_unlock(&g_smscore_deviceslock); -} -EXPORT_SYMBOL_GPL(smscore_unregister_hotplug); - -static void smscore_notify_clients(struct smscore_device_t *coredev) -{ - struct smscore_client_t *client; - - /* the client must call smscore_unregister_client from remove handler */ - while (!list_empty(&coredev->clients)) { - client = (struct smscore_client_t *) coredev->clients.next; - client->onremove_handler(client->context); - } -} - -static int smscore_notify_callbacks(struct smscore_device_t *coredev, - struct device *device, int arrival) -{ - struct list_head *next, *first; - int rc = 0; - - /* note: must be called under g_deviceslock */ - - first = &g_smscore_notifyees; - - for (next = first->next; next != first; next = next->next) { - rc = ((struct smscore_device_notifyee_t *) next)-> - hotplug(coredev, device, arrival); - if (rc < 0) - break; - } - - return rc; -} - -static struct -smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, - dma_addr_t common_buffer_phys) -{ - struct smscore_buffer_t *cb = - kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); - if (!cb) { - sms_info("kmalloc(...) failed"); - return NULL; - } - - cb->p = buffer; - cb->offset_in_common = buffer - (u8 *) common_buffer; - cb->phys = common_buffer_phys + cb->offset_in_common; - - return cb; -} - -/** - * creates coredev object for a device, prepares buffers, - * creates buffer mappings, notifies registered hotplugs about new device. - * - * @param params device pointer to struct with device specific parameters - * and handlers - * @param coredev pointer to a value that receives created coredev object - * - * @return 0 on success, <0 on error. - */ -int smscore_register_device(struct smsdevice_params_t *params, - struct smscore_device_t **coredev) -{ - struct smscore_device_t *dev; - u8 *buffer; - - dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); - if (!dev) { - sms_info("kzalloc(...) failed"); - return -ENOMEM; - } - - /* init list entry so it could be safe in smscore_unregister_device */ - INIT_LIST_HEAD(&dev->entry); - - /* init queues */ - INIT_LIST_HEAD(&dev->clients); - INIT_LIST_HEAD(&dev->buffers); - - /* init locks */ - spin_lock_init(&dev->clientslock); - spin_lock_init(&dev->bufferslock); - - /* init completion events */ - init_completion(&dev->version_ex_done); - init_completion(&dev->data_download_done); - init_completion(&dev->trigger_done); - init_completion(&dev->init_device_done); - init_completion(&dev->reload_start_done); - init_completion(&dev->resume_done); - init_completion(&dev->gpio_configuration_done); - init_completion(&dev->gpio_set_level_done); - init_completion(&dev->gpio_get_level_done); - init_completion(&dev->ir_init_done); - - /* Buffer management */ - init_waitqueue_head(&dev->buffer_mng_waitq); - - /* alloc common buffer */ - dev->common_buffer_size = params->buffer_size * params->num_buffers; - dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, - &dev->common_buffer_phys, - GFP_KERNEL | GFP_DMA); - if (!dev->common_buffer) { - smscore_unregister_device(dev); - return -ENOMEM; - } - - /* prepare dma buffers */ - for (buffer = dev->common_buffer; - dev->num_buffers < params->num_buffers; - dev->num_buffers++, buffer += params->buffer_size) { - struct smscore_buffer_t *cb = - smscore_createbuffer(buffer, dev->common_buffer, - dev->common_buffer_phys); - if (!cb) { - smscore_unregister_device(dev); - return -ENOMEM; - } - - smscore_putbuffer(dev, cb); - } - - sms_info("allocated %d buffers", dev->num_buffers); - - dev->mode = DEVICE_MODE_NONE; - dev->context = params->context; - dev->device = params->device; - dev->setmode_handler = params->setmode_handler; - dev->detectmode_handler = params->detectmode_handler; - dev->sendrequest_handler = params->sendrequest_handler; - dev->preload_handler = params->preload_handler; - dev->postload_handler = params->postload_handler; - - dev->device_flags = params->flags; - strcpy(dev->devpath, params->devpath); - - smscore_registry_settype(dev->devpath, params->device_type); - - /* add device to devices list */ - kmutex_lock(&g_smscore_deviceslock); - list_add(&dev->entry, &g_smscore_devices); - kmutex_unlock(&g_smscore_deviceslock); - - *coredev = dev; - - sms_info("device %p created", dev); - - return 0; -} -EXPORT_SYMBOL_GPL(smscore_register_device); - - -static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, - void *buffer, size_t size, struct completion *completion) { - int rc = coredev->sendrequest_handler(coredev->context, buffer, size); - if (rc < 0) { - sms_info("sendrequest returned error %d", rc); - return rc; - } - - return wait_for_completion_timeout(completion, - msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ? - 0 : -ETIME; -} - -/** - * Starts & enables IR operations - * - * @return 0 on success, < 0 on error. - */ -static int smscore_init_ir(struct smscore_device_t *coredev) -{ - int ir_io; - int rc; - void *buffer; - - coredev->ir.dev = NULL; - ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir; - if (ir_io) {/* only if IR port exist we use IR sub-module */ - sms_info("IR loading"); - rc = sms_ir_init(coredev); - - if (rc != 0) - sms_err("Error initialization DTV IR sub-module"); - else { - buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + - SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - if (buffer) { - struct SmsMsgData_ST2 *msg = - (struct SmsMsgData_ST2 *) - SMS_ALIGN_ADDRESS(buffer); - - SMS_INIT_MSG(&msg->xMsgHeader, - MSG_SMS_START_IR_REQ, - sizeof(struct SmsMsgData_ST2)); - msg->msgData[0] = coredev->ir.controller; - msg->msgData[1] = coredev->ir.timeout; - - smsendian_handle_tx_message( - (struct SmsMsgHdr_ST2 *)msg); - rc = smscore_sendrequest_and_wait(coredev, msg, - msg->xMsgHeader. msgLength, - &coredev->ir_init_done); - - kfree(buffer); - } else - sms_err - ("Sending IR initialization message failed"); - } - } else - sms_info("IR port has not been detected"); - - return 0; -} - -/** - * sets initial device mode and notifies client hotplugs that device is ready - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * - * @return 0 on success, <0 on error. - */ -int smscore_start_device(struct smscore_device_t *coredev) -{ - int rc = smscore_set_device_mode( - coredev, smscore_registry_getmode(coredev->devpath)); - if (rc < 0) { - sms_info("set device mode faile , rc %d", rc); - return rc; - } - - kmutex_lock(&g_smscore_deviceslock); - - rc = smscore_notify_callbacks(coredev, coredev->device, 1); - smscore_init_ir(coredev); - - sms_info("device %p started, rc %d", coredev, rc); - - kmutex_unlock(&g_smscore_deviceslock); - - return rc; -} -EXPORT_SYMBOL_GPL(smscore_start_device); - - -static int smscore_load_firmware_family2(struct smscore_device_t *coredev, - void *buffer, size_t size) -{ - struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; - struct SmsMsgHdr_ST *msg; - u32 mem_address; - u8 *payload = firmware->Payload; - int rc = 0; - firmware->StartAddress = le32_to_cpu(firmware->StartAddress); - firmware->Length = le32_to_cpu(firmware->Length); - - mem_address = firmware->StartAddress; - - sms_info("loading FW to addr 0x%x size %d", - mem_address, firmware->Length); - if (coredev->preload_handler) { - rc = coredev->preload_handler(coredev->context); - if (rc < 0) - return rc; - } - - /* PAGE_SIZE buffer shall be enough and dma aligned */ - msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); - if (!msg) - return -ENOMEM; - - if (coredev->mode != DEVICE_MODE_NONE) { - sms_debug("sending reload command."); - SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, - sizeof(struct SmsMsgHdr_ST)); - rc = smscore_sendrequest_and_wait(coredev, msg, - msg->msgLength, - &coredev->reload_start_done); - mem_address = *(u32 *) &payload[20]; - } - - while (size && rc >= 0) { - struct SmsDataDownload_ST *DataMsg = - (struct SmsDataDownload_ST *) msg; - int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); - - SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, - (u16)(sizeof(struct SmsMsgHdr_ST) + - sizeof(u32) + payload_size)); - - DataMsg->MemAddr = mem_address; - memcpy(DataMsg->Payload, payload, payload_size); - - if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && - (coredev->mode == DEVICE_MODE_NONE)) - rc = coredev->sendrequest_handler( - coredev->context, DataMsg, - DataMsg->xMsgHeader.msgLength); - else - rc = smscore_sendrequest_and_wait( - coredev, DataMsg, - DataMsg->xMsgHeader.msgLength, - &coredev->data_download_done); - - payload += payload_size; - size -= payload_size; - mem_address += payload_size; - } - - if (rc >= 0) { - if (coredev->mode == DEVICE_MODE_NONE) { - struct SmsMsgData_ST *TriggerMsg = - (struct SmsMsgData_ST *) msg; - - SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, - sizeof(struct SmsMsgHdr_ST) + - sizeof(u32) * 5); - - TriggerMsg->msgData[0] = firmware->StartAddress; - /* Entry point */ - TriggerMsg->msgData[1] = 5; /* Priority */ - TriggerMsg->msgData[2] = 0x200; /* Stack size */ - TriggerMsg->msgData[3] = 0; /* Parameter */ - TriggerMsg->msgData[4] = 4; /* Task ID */ - - if (coredev->device_flags & SMS_ROM_NO_RESPONSE) { - rc = coredev->sendrequest_handler( - coredev->context, TriggerMsg, - TriggerMsg->xMsgHeader.msgLength); - msleep(100); - } else - rc = smscore_sendrequest_and_wait( - coredev, TriggerMsg, - TriggerMsg->xMsgHeader.msgLength, - &coredev->trigger_done); - } else { - SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, - sizeof(struct SmsMsgHdr_ST)); - - rc = coredev->sendrequest_handler(coredev->context, - msg, msg->msgLength); - } - msleep(500); - } - - sms_debug("rc=%d, postload=%p ", rc, - coredev->postload_handler); - - kfree(msg); - - return ((rc >= 0) && coredev->postload_handler) ? - coredev->postload_handler(coredev->context) : - rc; -} - -/** - * loads specified firmware into a buffer and calls device loadfirmware_handler - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param filename null-terminated string specifies firmware file name - * @param loadfirmware_handler device handler that loads firmware - * - * @return 0 on success, <0 on error. - */ -static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, - char *filename, - loadfirmware_t loadfirmware_handler) -{ - int rc = -ENOENT; - const struct firmware *fw; - u8 *fw_buffer; - - if (loadfirmware_handler == NULL && !(coredev->device_flags & - SMS_DEVICE_FAMILY2)) - return -EINVAL; - - rc = request_firmware(&fw, filename, coredev->device); - if (rc < 0) { - sms_info("failed to open \"%s\"", filename); - return rc; - } - sms_info("read FW %s, size=%zd", filename, fw->size); - fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), - GFP_KERNEL | GFP_DMA); - if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); - - rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? - smscore_load_firmware_family2(coredev, - fw_buffer, - fw->size) : - loadfirmware_handler(coredev->context, - fw_buffer, fw->size); - - kfree(fw_buffer); - } else { - sms_info("failed to allocate firmware buffer"); - rc = -ENOMEM; - } - - release_firmware(fw); - - return rc; -} - -/** - * notifies all clients registered with the device, notifies hotplugs, - * frees all buffers and coredev object - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * - * @return 0 on success, <0 on error. - */ -void smscore_unregister_device(struct smscore_device_t *coredev) -{ - struct smscore_buffer_t *cb; - int num_buffers = 0; - int retry = 0; - - kmutex_lock(&g_smscore_deviceslock); - - /* Release input device (IR) resources */ - sms_ir_exit(coredev); - - smscore_notify_clients(coredev); - smscore_notify_callbacks(coredev, NULL, 0); - - /* at this point all buffers should be back - * onresponse must no longer be called */ - - while (1) { - while (!list_empty(&coredev->buffers)) { - cb = (struct smscore_buffer_t *) coredev->buffers.next; - list_del(&cb->entry); - kfree(cb); - num_buffers++; - } - if (num_buffers == coredev->num_buffers) - break; - if (++retry > 10) { - sms_info("exiting although " - "not all buffers released."); - break; - } - - sms_info("waiting for %d buffer(s)", - coredev->num_buffers - num_buffers); - msleep(100); - } - - sms_info("freed %d buffers", num_buffers); - - if (coredev->common_buffer) - dma_free_coherent(NULL, coredev->common_buffer_size, - coredev->common_buffer, coredev->common_buffer_phys); - - if (coredev->fw_buf != NULL) - kfree(coredev->fw_buf); - - list_del(&coredev->entry); - kfree(coredev); - - kmutex_unlock(&g_smscore_deviceslock); - - sms_info("device %p destroyed", coredev); -} -EXPORT_SYMBOL_GPL(smscore_unregister_device); - -static int smscore_detect_mode(struct smscore_device_t *coredev) -{ - void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - struct SmsMsgHdr_ST *msg = - (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); - int rc; - - if (!buffer) - return -ENOMEM; - - SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, - sizeof(struct SmsMsgHdr_ST)); - - rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, - &coredev->version_ex_done); - if (rc == -ETIME) { - sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); - - if (wait_for_completion_timeout(&coredev->resume_done, - msecs_to_jiffies(5000))) { - rc = smscore_sendrequest_and_wait( - coredev, msg, msg->msgLength, - &coredev->version_ex_done); - if (rc < 0) - sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " - "second try, rc %d", rc); - } else - rc = -ETIME; - } - - kfree(buffer); - - return rc; -} - -static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { - /*Stellar NOVA A0 Nova B0 VEGA*/ - /*DVBT*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*DVBH*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*TDMB*/ - {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"}, - /*DABIP*/ - {"none", "none", "none", "none"}, - /*BDA*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*ISDBT*/ - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, - /*ISDBTBDA*/ - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, - /*CMMB*/ - {"none", "none", "none", "cmmb_vega_12mhz.inp"} -}; - -static inline char *sms_get_fw_name(struct smscore_device_t *coredev, - int mode, enum sms_device_type_st type) -{ - char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; - return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; -} - -/** - * calls device handler to change mode of operation - * NOTE: stellar/usb may disconnect when changing mode - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param mode requested mode of operation - * - * @return 0 on success, <0 on error. - */ -int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) -{ - void *buffer; - int rc = 0; - enum sms_device_type_st type; - - sms_debug("set device mode to %d", mode); - if (coredev->device_flags & SMS_DEVICE_FAMILY2) { - if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) { - sms_err("invalid mode specified %d", mode); - return -EINVAL; - } - - smscore_registry_setmode(coredev->devpath, mode); - - if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) { - rc = smscore_detect_mode(coredev); - if (rc < 0) { - sms_err("mode detect failed %d", rc); - return rc; - } - } - - if (coredev->mode == mode) { - sms_info("device mode %d already set", mode); - return 0; - } - - if (!(coredev->modes_supported & (1 << mode))) { - char *fw_filename; - - type = smscore_registry_gettype(coredev->devpath); - fw_filename = sms_get_fw_name(coredev, mode, type); - - rc = smscore_load_firmware_from_file(coredev, - fw_filename, NULL); - if (rc < 0) { - sms_warn("error %d loading firmware: %s, " - "trying again with default firmware", - rc, fw_filename); - - /* try again with the default firmware */ - fw_filename = smscore_fw_lkup[mode][type]; - rc = smscore_load_firmware_from_file(coredev, - fw_filename, NULL); - - if (rc < 0) { - sms_warn("error %d loading " - "firmware: %s", rc, - fw_filename); - return rc; - } - } - sms_log("firmware download success: %s", fw_filename); - } else - sms_info("mode %d supported by running " - "firmware", mode); - - buffer = kmalloc(sizeof(struct SmsMsgData_ST) + - SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); - if (buffer) { - struct SmsMsgData_ST *msg = - (struct SmsMsgData_ST *) - SMS_ALIGN_ADDRESS(buffer); - - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, - sizeof(struct SmsMsgData_ST)); - msg->msgData[0] = mode; - - rc = smscore_sendrequest_and_wait( - coredev, msg, msg->xMsgHeader.msgLength, - &coredev->init_device_done); - - kfree(buffer); - } else { - sms_err("Could not allocate buffer for " - "init device message."); - rc = -ENOMEM; - } - } else { - if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { - sms_err("invalid mode specified %d", mode); - return -EINVAL; - } - - smscore_registry_setmode(coredev->devpath, mode); - - if (coredev->detectmode_handler) - coredev->detectmode_handler(coredev->context, - &coredev->mode); - - if (coredev->mode != mode && coredev->setmode_handler) - rc = coredev->setmode_handler(coredev->context, mode); - } - - if (rc >= 0) { - coredev->mode = mode; - coredev->device_flags &= ~SMS_DEVICE_NOT_READY; - } - - if (rc < 0) - sms_err("return error code %d.", rc); - return rc; -} - -/** - * calls device handler to get current mode of operation - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * - * @return current mode - */ -int smscore_get_device_mode(struct smscore_device_t *coredev) -{ - return coredev->mode; -} -EXPORT_SYMBOL_GPL(smscore_get_device_mode); - -/** - * find client by response id & type within the clients list. - * return client handle or NULL. - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param data_type client data type (SMS_DONT_CARE for all types) - * @param id client id (SMS_DONT_CARE for all id) - * - */ -static struct -smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, - int data_type, int id) -{ - struct smscore_client_t *client = NULL; - struct list_head *next, *first; - unsigned long flags; - struct list_head *firstid, *nextid; - - - spin_lock_irqsave(&coredev->clientslock, flags); - first = &coredev->clients; - for (next = first->next; - (next != first) && !client; - next = next->next) { - firstid = &((struct smscore_client_t *)next)->idlist; - for (nextid = firstid->next; - nextid != firstid; - nextid = nextid->next) { - if ((((struct smscore_idlist_t *)nextid)->id == id) && - (((struct smscore_idlist_t *)nextid)->data_type == data_type || - (((struct smscore_idlist_t *)nextid)->data_type == 0))) { - client = (struct smscore_client_t *) next; - break; - } - } - } - spin_unlock_irqrestore(&coredev->clientslock, flags); - return client; -} - -/** - * find client by response id/type, call clients onresponse handler - * return buffer to pool on error - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param cb pointer to response buffer descriptor - * - */ -void smscore_onresponse(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb) { - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p - + cb->offset); - struct smscore_client_t *client; - int rc = -EBUSY; - static unsigned long last_sample_time; /* = 0; */ - static int data_total; /* = 0; */ - unsigned long time_now = jiffies_to_msecs(jiffies); - - if (!last_sample_time) - last_sample_time = time_now; - - if (time_now - last_sample_time > 10000) { - sms_debug("\ndata rate %d bytes/secs", - (int)((data_total * 1000) / - (time_now - last_sample_time))); - - last_sample_time = time_now; - data_total = 0; - } - - data_total += cb->size; - /* Do we need to re-route? */ - if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || - (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { - if (coredev->mode == DEVICE_MODE_DVBT_BDA) - phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; - } - - - client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); - - /* If no client registered for type & id, - * check for control client where type is not registered */ - if (client) - rc = client->onresponse_handler(client->context, cb); - - if (rc < 0) { - switch (phdr->msgType) { - case MSG_SMS_GET_VERSION_EX_RES: - { - struct SmsVersionRes_ST *ver = - (struct SmsVersionRes_ST *) phdr; - sms_debug("MSG_SMS_GET_VERSION_EX_RES " - "id %d prots 0x%x ver %d.%d", - ver->FirmwareId, ver->SupportedProtocols, - ver->RomVersionMajor, ver->RomVersionMinor); - - coredev->mode = ver->FirmwareId == 255 ? - DEVICE_MODE_NONE : ver->FirmwareId; - coredev->modes_supported = ver->SupportedProtocols; - - complete(&coredev->version_ex_done); - break; - } - case MSG_SMS_INIT_DEVICE_RES: - sms_debug("MSG_SMS_INIT_DEVICE_RES"); - complete(&coredev->init_device_done); - break; - case MSG_SW_RELOAD_START_RES: - sms_debug("MSG_SW_RELOAD_START_RES"); - complete(&coredev->reload_start_done); - break; - case MSG_SMS_DATA_DOWNLOAD_RES: - complete(&coredev->data_download_done); - break; - case MSG_SW_RELOAD_EXEC_RES: - sms_debug("MSG_SW_RELOAD_EXEC_RES"); - break; - case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: - sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); - complete(&coredev->trigger_done); - break; - case MSG_SMS_SLEEP_RESUME_COMP_IND: - complete(&coredev->resume_done); - break; - case MSG_SMS_GPIO_CONFIG_EX_RES: - sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES"); - complete(&coredev->gpio_configuration_done); - break; - case MSG_SMS_GPIO_SET_LEVEL_RES: - sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES"); - complete(&coredev->gpio_set_level_done); - break; - case MSG_SMS_GPIO_GET_LEVEL_RES: - { - u32 *msgdata = (u32 *) phdr; - coredev->gpio_get_res = msgdata[1]; - sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", - coredev->gpio_get_res); - complete(&coredev->gpio_get_level_done); - break; - } - case MSG_SMS_START_IR_RES: - complete(&coredev->ir_init_done); - break; - case MSG_SMS_IR_SAMPLES_IND: - sms_ir_event(coredev, - (const char *) - ((char *)phdr - + sizeof(struct SmsMsgHdr_ST)), - (int)phdr->msgLength - - sizeof(struct SmsMsgHdr_ST)); - break; - - default: - break; - } - smscore_putbuffer(coredev, cb); - } -} -EXPORT_SYMBOL_GPL(smscore_onresponse); - -/** - * return pointer to next free buffer descriptor from core pool - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * - * @return pointer to descriptor on success, NULL on error. - */ - -struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev) -{ - struct smscore_buffer_t *cb = NULL; - unsigned long flags; - - spin_lock_irqsave(&coredev->bufferslock, flags); - if (!list_empty(&coredev->buffers)) { - cb = (struct smscore_buffer_t *) coredev->buffers.next; - list_del(&cb->entry); - } - spin_unlock_irqrestore(&coredev->bufferslock, flags); - return cb; -} - -struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) -{ - struct smscore_buffer_t *cb = NULL; - - wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev))); - - return cb; -} -EXPORT_SYMBOL_GPL(smscore_getbuffer); - -/** - * return buffer descriptor to a pool - * - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param cb pointer buffer descriptor - * - */ -void smscore_putbuffer(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb) { - wake_up_interruptible(&coredev->buffer_mng_waitq); - list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); -} -EXPORT_SYMBOL_GPL(smscore_putbuffer); - -static int smscore_validate_client(struct smscore_device_t *coredev, - struct smscore_client_t *client, - int data_type, int id) -{ - struct smscore_idlist_t *listentry; - struct smscore_client_t *registered_client; - - if (!client) { - sms_err("bad parameter."); - return -EFAULT; - } - registered_client = smscore_find_client(coredev, data_type, id); - if (registered_client == client) - return 0; - - if (registered_client) { - sms_err("The msg ID already registered to another client."); - return -EEXIST; - } - listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); - if (!listentry) { - sms_err("Can't allocate memory for client id."); - return -ENOMEM; - } - listentry->id = id; - listentry->data_type = data_type; - list_add_locked(&listentry->entry, &client->idlist, - &coredev->clientslock); - return 0; -} - -/** - * creates smsclient object, check that id is taken by another client - * - * @param coredev pointer to a coredev object from clients hotplug - * @param initial_id all messages with this id would be sent to this client - * @param data_type all messages of this type would be sent to this client - * @param onresponse_handler client handler that is called to - * process incoming messages - * @param onremove_handler client handler that is called when device is removed - * @param context client-specific context - * @param client pointer to a value that receives created smsclient object - * - * @return 0 on success, <0 on error. - */ -int smscore_register_client(struct smscore_device_t *coredev, - struct smsclient_params_t *params, - struct smscore_client_t **client) -{ - struct smscore_client_t *newclient; - /* check that no other channel with same parameters exists */ - if (smscore_find_client(coredev, params->data_type, - params->initial_id)) { - sms_err("Client already exist."); - return -EEXIST; - } - - newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); - if (!newclient) { - sms_err("Failed to allocate memory for client."); - return -ENOMEM; - } - - INIT_LIST_HEAD(&newclient->idlist); - newclient->coredev = coredev; - newclient->onresponse_handler = params->onresponse_handler; - newclient->onremove_handler = params->onremove_handler; - newclient->context = params->context; - list_add_locked(&newclient->entry, &coredev->clients, - &coredev->clientslock); - smscore_validate_client(coredev, newclient, params->data_type, - params->initial_id); - *client = newclient; - sms_debug("%p %d %d", params->context, params->data_type, - params->initial_id); - - return 0; -} -EXPORT_SYMBOL_GPL(smscore_register_client); - -/** - * frees smsclient object and all subclients associated with it - * - * @param client pointer to smsclient object returned by - * smscore_register_client - * - */ -void smscore_unregister_client(struct smscore_client_t *client) -{ - struct smscore_device_t *coredev = client->coredev; - unsigned long flags; - - spin_lock_irqsave(&coredev->clientslock, flags); - - - while (!list_empty(&client->idlist)) { - struct smscore_idlist_t *identry = - (struct smscore_idlist_t *) client->idlist.next; - list_del(&identry->entry); - kfree(identry); - } - - sms_info("%p", client->context); - - list_del(&client->entry); - kfree(client); - - spin_unlock_irqrestore(&coredev->clientslock, flags); -} -EXPORT_SYMBOL_GPL(smscore_unregister_client); - -/** - * verifies that source id is not taken by another client, - * calls device handler to send requests to the device - * - * @param client pointer to smsclient object returned by - * smscore_register_client - * @param buffer pointer to a request buffer - * @param size size (in bytes) of request buffer - * - * @return 0 on success, <0 on error. - */ -int smsclient_sendrequest(struct smscore_client_t *client, - void *buffer, size_t size) -{ - struct smscore_device_t *coredev; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; - int rc; - - if (client == NULL) { - sms_err("Got NULL client"); - return -EINVAL; - } - - coredev = client->coredev; - - /* check that no other channel with same id exists */ - if (coredev == NULL) { - sms_err("Got NULL coredev"); - return -EINVAL; - } - - rc = smscore_validate_client(client->coredev, client, 0, - phdr->msgSrcId); - if (rc < 0) - return rc; - - return coredev->sendrequest_handler(coredev->context, buffer, size); -} -EXPORT_SYMBOL_GPL(smsclient_sendrequest); - - -/* old GPIO managements implementation */ -int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, - struct smscore_config_gpio *pinconfig) -{ - struct { - struct SmsMsgHdr_ST hdr; - u32 data[6]; - } msg; - - if (coredev->device_flags & SMS_DEVICE_FAMILY2) { - msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - msg.hdr.msgDstId = HIF_TASK; - msg.hdr.msgFlags = 0; - msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; - msg.hdr.msgLength = sizeof(msg); - - msg.data[0] = pin; - msg.data[1] = pinconfig->pullupdown; - - /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */ - msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; - - switch (pinconfig->outputdriving) { - case SMS_GPIO_OUTPUTDRIVING_16mA: - msg.data[3] = 7; /* Nova - 16mA */ - break; - case SMS_GPIO_OUTPUTDRIVING_12mA: - msg.data[3] = 5; /* Nova - 11mA */ - break; - case SMS_GPIO_OUTPUTDRIVING_8mA: - msg.data[3] = 3; /* Nova - 7mA */ - break; - case SMS_GPIO_OUTPUTDRIVING_4mA: - default: - msg.data[3] = 2; /* Nova - 4mA */ - break; - } - - msg.data[4] = pinconfig->direction; - msg.data[5] = 0; - } else /* TODO: SMS_DEVICE_FAMILY1 */ - return -EINVAL; - - return coredev->sendrequest_handler(coredev->context, - &msg, sizeof(msg)); -} - -int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) -{ - struct { - struct SmsMsgHdr_ST hdr; - u32 data[3]; - } msg; - - if (pin > MAX_GPIO_PIN_NUMBER) - return -EINVAL; - - msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - msg.hdr.msgDstId = HIF_TASK; - msg.hdr.msgFlags = 0; - msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; - msg.hdr.msgLength = sizeof(msg); - - msg.data[0] = pin; - msg.data[1] = level ? 1 : 0; - msg.data[2] = 0; - - return coredev->sendrequest_handler(coredev->context, - &msg, sizeof(msg)); -} - -/* new GPIO management implementation */ -static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, - u32 *pGroupNum, u32 *pGroupCfg) { - - *pGroupCfg = 1; - - if (PinNum <= 1) { - *pTranslatedPinNum = 0; - *pGroupNum = 9; - *pGroupCfg = 2; - } else if (PinNum >= 2 && PinNum <= 6) { - *pTranslatedPinNum = 2; - *pGroupNum = 0; - *pGroupCfg = 2; - } else if (PinNum >= 7 && PinNum <= 11) { - *pTranslatedPinNum = 7; - *pGroupNum = 1; - } else if (PinNum >= 12 && PinNum <= 15) { - *pTranslatedPinNum = 12; - *pGroupNum = 2; - *pGroupCfg = 3; - } else if (PinNum == 16) { - *pTranslatedPinNum = 16; - *pGroupNum = 23; - } else if (PinNum >= 17 && PinNum <= 24) { - *pTranslatedPinNum = 17; - *pGroupNum = 3; - } else if (PinNum == 25) { - *pTranslatedPinNum = 25; - *pGroupNum = 6; - } else if (PinNum >= 26 && PinNum <= 28) { - *pTranslatedPinNum = 26; - *pGroupNum = 4; - } else if (PinNum == 29) { - *pTranslatedPinNum = 29; - *pGroupNum = 5; - *pGroupCfg = 2; - } else if (PinNum == 30) { - *pTranslatedPinNum = 30; - *pGroupNum = 8; - } else if (PinNum == 31) { - *pTranslatedPinNum = 31; - *pGroupNum = 17; - } else - return -1; - - *pGroupCfg <<= 24; - - return 0; -} - -int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_gpio_config *pGpioConfig) { - - u32 totalLen; - u32 TranslatedPinNum = 0; - u32 GroupNum = 0; - u32 ElectricChar; - u32 groupCfg; - void *buffer; - int rc; - - struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[6]; - } *pMsg; - - - if (PinNum > MAX_GPIO_PIN_NUMBER) - return -EINVAL; - - if (pGpioConfig == NULL) - return -EINVAL; - - totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6); - - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); - - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; - - if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ; - if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum, - &groupCfg) != 0) { - rc = -EINVAL; - goto free; - } - - pMsg->msgData[1] = TranslatedPinNum; - pMsg->msgData[2] = GroupNum; - ElectricChar = (pGpioConfig->PullUpDown) - | (pGpioConfig->InputCharacteristics << 2) - | (pGpioConfig->OutputSlewRate << 3) - | (pGpioConfig->OutputDriving << 4); - pMsg->msgData[3] = ElectricChar; - pMsg->msgData[4] = pGpioConfig->Direction; - pMsg->msgData[5] = groupCfg; - } else { - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; - pMsg->msgData[1] = pGpioConfig->PullUpDown; - pMsg->msgData[2] = pGpioConfig->OutputSlewRate; - pMsg->msgData[3] = pGpioConfig->OutputDriving; - pMsg->msgData[4] = pGpioConfig->Direction; - pMsg->msgData[5] = 0; - } - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, - &coredev->gpio_configuration_done); - - if (rc != 0) { - if (rc == -ETIME) - sms_err("smscore_gpio_configure timeout"); - else - sms_err("smscore_gpio_configure error"); - } -free: - kfree(buffer); - - return rc; -} - -int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, - u8 NewLevel) { - - u32 totalLen; - int rc; - void *buffer; - - struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[3]; /* keep it 3 ! */ - } *pMsg; - - if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER)) - return -EINVAL; - - totalLen = sizeof(struct SmsMsgHdr_ST) + - (3 * sizeof(u32)); /* keep it 3 ! */ - - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); - - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; - pMsg->msgData[1] = NewLevel; - - /* Send message to SMS */ - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, - &coredev->gpio_set_level_done); - - if (rc != 0) { - if (rc == -ETIME) - sms_err("smscore_gpio_set_level timeout"); - else - sms_err("smscore_gpio_set_level error"); - } - kfree(buffer); - - return rc; -} - -int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, - u8 *level) { - - u32 totalLen; - int rc; - void *buffer; - - struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[2]; - } *pMsg; - - - if (PinNum > MAX_GPIO_PIN_NUMBER) - return -EINVAL; - - totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32)); - - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, - GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); - - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; - pMsg->msgData[1] = 0; - - /* Send message to SMS */ - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, - &coredev->gpio_get_level_done); - - if (rc != 0) { - if (rc == -ETIME) - sms_err("smscore_gpio_get_level timeout"); - else - sms_err("smscore_gpio_get_level error"); - } - kfree(buffer); - - /* Its a race between other gpio_get_level() and the copy of the single - * global 'coredev->gpio_get_res' to the function's variable 'level' - */ - *level = coredev->gpio_get_res; - - return rc; -} - -static int __init smscore_module_init(void) -{ - int rc = 0; - - INIT_LIST_HEAD(&g_smscore_notifyees); - INIT_LIST_HEAD(&g_smscore_devices); - kmutex_init(&g_smscore_deviceslock); - - INIT_LIST_HEAD(&g_smscore_registry); - kmutex_init(&g_smscore_registrylock); - - return rc; -} - -static void __exit smscore_module_exit(void) -{ - kmutex_lock(&g_smscore_deviceslock); - while (!list_empty(&g_smscore_notifyees)) { - struct smscore_device_notifyee_t *notifyee = - (struct smscore_device_notifyee_t *) - g_smscore_notifyees.next; - - list_del(¬ifyee->entry); - kfree(notifyee); - } - kmutex_unlock(&g_smscore_deviceslock); - - kmutex_lock(&g_smscore_registrylock); - while (!list_empty(&g_smscore_registry)) { - struct smscore_registry_entry_t *entry = - (struct smscore_registry_entry_t *) - g_smscore_registry.next; - - list_del(&entry->entry); - kfree(entry); - } - kmutex_unlock(&g_smscore_registrylock); - - sms_debug(""); -} - -module_init(smscore_module_init); -module_exit(smscore_module_exit); - -MODULE_DESCRIPTION("Siano MDTV Core module"); -MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smscoreapi.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smscoreapi.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smscoreapi.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smscoreapi.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,776 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat - -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, or -(at your option) any later version. - - 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, see . - -****************************************************************/ - -#ifndef __SMS_CORE_API_H__ -#define __SMS_CORE_API_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "smsir.h" - -#define kmutex_init(_p_) mutex_init(_p_) -#define kmutex_lock(_p_) mutex_lock(_p_) -#define kmutex_trylock(_p_) mutex_trylock(_p_) -#define kmutex_unlock(_p_) mutex_unlock(_p_) - -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000) -#define SMS_ALLOC_ALIGNMENT 128 -#define SMS_DMA_ALIGNMENT 16 -#define SMS_ALIGN_ADDRESS(addr) \ - ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) - -#define SMS_DEVICE_FAMILY2 1 -#define SMS_ROM_NO_RESPONSE 2 -#define SMS_DEVICE_NOT_READY 0x8000000 - -enum sms_device_type_st { - SMS_STELLAR = 0, - SMS_NOVA_A0, - SMS_NOVA_B0, - SMS_VEGA, - SMS_NUM_OF_DEVICE_TYPES -}; - -struct smscore_device_t; -struct smscore_client_t; -struct smscore_buffer_t; - -typedef int (*hotplug_t)(struct smscore_device_t *coredev, - struct device *device, int arrival); - -typedef int (*setmode_t)(void *context, int mode); -typedef void (*detectmode_t)(void *context, int *mode); -typedef int (*sendrequest_t)(void *context, void *buffer, size_t size); -typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size); -typedef int (*preload_t)(void *context); -typedef int (*postload_t)(void *context); - -typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb); -typedef void (*onremove_t)(void *context); - -struct smscore_buffer_t { - /* public members, once passed to clients can be changed freely */ - struct list_head entry; - int size; - int offset; - - /* private members, read-only for clients */ - void *p; - dma_addr_t phys; - unsigned long offset_in_common; -}; - -struct smsdevice_params_t { - struct device *device; - - int buffer_size; - int num_buffers; - - char devpath[32]; - unsigned long flags; - - setmode_t setmode_handler; - detectmode_t detectmode_handler; - sendrequest_t sendrequest_handler; - preload_t preload_handler; - postload_t postload_handler; - - void *context; - enum sms_device_type_st device_type; -}; - -struct smsclient_params_t { - int initial_id; - int data_type; - onresponse_t onresponse_handler; - onremove_t onremove_handler; - void *context; -}; - -struct smscore_device_t { - struct list_head entry; - - struct list_head clients; - struct list_head subclients; - spinlock_t clientslock; - - struct list_head buffers; - spinlock_t bufferslock; - int num_buffers; - - void *common_buffer; - int common_buffer_size; - dma_addr_t common_buffer_phys; - - void *context; - struct device *device; - - char devpath[32]; - unsigned long device_flags; - - setmode_t setmode_handler; - detectmode_t detectmode_handler; - sendrequest_t sendrequest_handler; - preload_t preload_handler; - postload_t postload_handler; - - int mode, modes_supported; - - /* host <--> device messages */ - struct completion version_ex_done, data_download_done, trigger_done; - struct completion init_device_done, reload_start_done, resume_done; - struct completion gpio_configuration_done, gpio_set_level_done; - struct completion gpio_get_level_done, ir_init_done; - - /* Buffer management */ - wait_queue_head_t buffer_mng_waitq; - - /* GPIO */ - int gpio_get_res; - - /* Target hardware board */ - int board_id; - - /* Firmware */ - u8 *fw_buf; - u32 fw_buf_size; - - /* Infrared (IR) */ - struct ir_t ir; - - int led_state; -}; - -/* GPIO definitions for antenna frequency domain control (SMS8021) */ -#define SMS_ANTENNA_GPIO_0 1 -#define SMS_ANTENNA_GPIO_1 0 - -#define BW_8_MHZ 0 -#define BW_7_MHZ 1 -#define BW_6_MHZ 2 -#define BW_5_MHZ 3 -#define BW_ISDBT_1SEG 4 -#define BW_ISDBT_3SEG 5 - -#define MSG_HDR_FLAG_SPLIT_MSG 4 - -#define MAX_GPIO_PIN_NUMBER 31 - -#define HIF_TASK 11 -#define SMS_HOST_LIB 150 -#define DVBT_BDA_CONTROL_MSG_ID 201 - -#define SMS_MAX_PAYLOAD_SIZE 240 -#define SMS_TUNE_TIMEOUT 500 - -#define MSG_SMS_GPIO_CONFIG_REQ 507 -#define MSG_SMS_GPIO_CONFIG_RES 508 -#define MSG_SMS_GPIO_SET_LEVEL_REQ 509 -#define MSG_SMS_GPIO_SET_LEVEL_RES 510 -#define MSG_SMS_GPIO_GET_LEVEL_REQ 511 -#define MSG_SMS_GPIO_GET_LEVEL_RES 512 -#define MSG_SMS_RF_TUNE_REQ 561 -#define MSG_SMS_RF_TUNE_RES 562 -#define MSG_SMS_INIT_DEVICE_REQ 578 -#define MSG_SMS_INIT_DEVICE_RES 579 -#define MSG_SMS_ADD_PID_FILTER_REQ 601 -#define MSG_SMS_ADD_PID_FILTER_RES 602 -#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 -#define MSG_SMS_REMOVE_PID_FILTER_RES 604 -#define MSG_SMS_DAB_CHANNEL 607 -#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 -#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 -#define MSG_SMS_GET_STATISTICS_RES 616 -#define MSG_SMS_GET_STATISTICS_REQ 615 -#define MSG_SMS_HO_PER_SLICES_IND 630 -#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 -#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 -#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 -#define MSG_SMS_DATA_DOWNLOAD_REQ 660 -#define MSG_SMS_DATA_DOWNLOAD_RES 661 -#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 -#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 -#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 -#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 -#define MSG_SMS_GET_VERSION_EX_REQ 668 -#define MSG_SMS_GET_VERSION_EX_RES 669 -#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 -#define MSG_SMS_I2C_SET_FREQ_REQ 685 -#define MSG_SMS_GENERIC_I2C_REQ 687 -#define MSG_SMS_GENERIC_I2C_RES 688 -#define MSG_SMS_DVBT_BDA_DATA 693 -#define MSG_SW_RELOAD_REQ 697 -#define MSG_SMS_DATA_MSG 699 -#define MSG_SW_RELOAD_START_REQ 702 -#define MSG_SW_RELOAD_START_RES 703 -#define MSG_SW_RELOAD_EXEC_REQ 704 -#define MSG_SW_RELOAD_EXEC_RES 705 -#define MSG_SMS_SPI_INT_LINE_SET_REQ 710 -#define MSG_SMS_GPIO_CONFIG_EX_REQ 712 -#define MSG_SMS_GPIO_CONFIG_EX_RES 713 -#define MSG_SMS_ISDBT_TUNE_REQ 776 -#define MSG_SMS_ISDBT_TUNE_RES 777 -#define MSG_SMS_TRANSMISSION_IND 782 -#define MSG_SMS_START_IR_REQ 800 -#define MSG_SMS_START_IR_RES 801 -#define MSG_SMS_IR_SAMPLES_IND 802 -#define MSG_SMS_SIGNAL_DETECTED_IND 827 -#define MSG_SMS_NO_SIGNAL_IND 828 - -#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ - (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ - (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ -} while (0) - -#define SMS_INIT_MSG(ptr, type, len) \ - SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len) - -enum SMS_DVB3_EVENTS { - DVB3_EVENT_INIT = 0, - DVB3_EVENT_SLEEP, - DVB3_EVENT_HOTPLUG, - DVB3_EVENT_FE_LOCK, - DVB3_EVENT_FE_UNLOCK, - DVB3_EVENT_UNC_OK, - DVB3_EVENT_UNC_ERR -}; - -enum SMS_DEVICE_MODE { - DEVICE_MODE_NONE = -1, - DEVICE_MODE_DVBT = 0, - DEVICE_MODE_DVBH, - DEVICE_MODE_DAB_TDMB, - DEVICE_MODE_DAB_TDMB_DABIP, - DEVICE_MODE_DVBT_BDA, - DEVICE_MODE_ISDBT, - DEVICE_MODE_ISDBT_BDA, - DEVICE_MODE_CMMB, - DEVICE_MODE_RAW_TUNER, - DEVICE_MODE_MAX, -}; - -struct SmsMsgHdr_ST { - u16 msgType; - u8 msgSrcId; - u8 msgDstId; - u16 msgLength; /* Length of entire message, including header */ - u16 msgFlags; -}; - -struct SmsMsgData_ST { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[1]; -}; - -struct SmsMsgData_ST2 { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[2]; -}; - -struct SmsDataDownload_ST { - struct SmsMsgHdr_ST xMsgHeader; - u32 MemAddr; - u8 Payload[SMS_MAX_PAYLOAD_SIZE]; -}; - -struct SmsVersionRes_ST { - struct SmsMsgHdr_ST xMsgHeader; - - u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ - u8 Step; /* 0 - Step A */ - u8 MetalFix; /* 0 - Metal 0 */ - - /* FirmwareId 0xFF if ROM, otherwise the - * value indicated by SMSHOSTLIB_DEVICE_MODES_E */ - u8 FirmwareId; - /* SupportedProtocols Bitwise OR combination of - * supported protocols */ - u8 SupportedProtocols; - - u8 VersionMajor; - u8 VersionMinor; - u8 VersionPatch; - u8 VersionFieldPatch; - - u8 RomVersionMajor; - u8 RomVersionMinor; - u8 RomVersionPatch; - u8 RomVersionFieldPatch; - - u8 TextLabel[34]; -}; - -struct SmsFirmware_ST { - u32 CheckSum; - u32 Length; - u32 StartAddress; - u8 Payload[1]; -}; - -/* Statistics information returned as response for - * SmsHostApiGetStatistics_Req */ -struct SMSHOSTLIB_STATISTICS_ST { - u32 Reserved; /* Reserved */ - - /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ - - /* Reception quality */ - s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ - u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ - u32 TS_PER; /* Transport stream PER, - 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */ - u32 MFER; /* DVB-H frame error rate in percentage, - 0xFFFFFFFF indicate N/A, valid only for DVB-H */ - s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - - /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ - u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, - for DVB-T/H FFT mode carriers in Kilos */ - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, - valid only for DVB-T/H */ - u32 GuardInterval; /* Guard Interval from - SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, - valid only for DVB-T/H */ - u32 LPCodeRate; /* Low Priority Code Rate from - SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ - u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, - valid only for DVB-T/H */ - u32 Constellation; /* Constellation from - SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ - - /* Burst parameters, valid only for DVB-H */ - u32 BurstSize; /* Current burst size in bytes, - valid only for DVB-H */ - u32 BurstDuration; /* Current burst duration in mSec, - valid only for DVB-H */ - u32 BurstCycleTime; /* Current burst cycle time in mSec, - valid only for DVB-H */ - u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, - as calculated by demodulator, valid only for DVB-H */ - u32 NumOfRows; /* Number of rows in MPE table, - valid only for DVB-H */ - u32 NumOfPaddCols; /* Number of padding columns in MPE table, - valid only for DVB-H */ - u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, - valid only for DVB-H */ - u32 ErrorTSPackets; /* Number of erroneous - transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include - errors after MPE RS decoding */ - u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors - after MPE RS decoding */ - u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were - corrected by MPE RS decoding */ - /* Common params */ - u32 BERErrorCount; /* Number of errornous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ - - /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ - - /* DAB/T-DMB */ - u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ - - /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; - if set to 0xFFFFFFFF cell_id not yet recovered */ - u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - - u32 NumMPEReceived; /* DVB-H, Num MPE section received */ - - u32 ReservedFields[10]; /* Reserved */ -}; - -struct SmsMsgStatisticsInfo_ST { - u32 RequestResult; - - struct SMSHOSTLIB_STATISTICS_ST Stat; - - /* Split the calc of the SNR in DAB */ - u32 Signal; /* dB */ - u32 Noise; /* dB */ - -}; - -struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST { - /* Per-layer information */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, - * 255 means layer does not exist */ - u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET, - * 255 means layer does not exist */ - u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 BERErrorCount; /* Post Viterbi Error Bits Count */ - u32 BERBitCount; /* Post Viterbi Total Bits Count */ - u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ - u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 TILdepthI; /* Time interleaver depth I parameter, - * 255 means layer does not exist */ - u32 NumberOfSegments; /* Number of segments in layer A, - * 255 means layer does not exist */ - u32 TMCCErrors; /* TMCC errors */ -}; - -struct SMSHOSTLIB_STATISTICS_ISDBT_ST { - u32 StatisticsType; /* Enumerator identifying the type of the - * structure. Values are the same as - * SMSHOSTLIB_DEVICE_MODES_E - * - * This field MUST always be first in any - * statistics structure */ - - u32 FullSize; /* Total size of the structure returned by the modem. - * If the size requested by the host is smaller than - * FullSize, the struct will be truncated */ - - /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ - - /* Reception quality */ - s32 SNR; /* dB */ - s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in Hz */ - - /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* ISDB-T transmission mode */ - u32 ModemState; /* 0 - Acquisition, 1 - Locked */ - u32 GuardInterval; /* Guard Interval, 1 divided by value */ - u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ - u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */ - u32 NumOfLayers; /* Number of ISDB-T layers in the network */ - - /* Per-layer information */ - /* Layers A, B and C */ - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; - /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ - - /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ -}; - -struct PID_STATISTICS_DATA_S { - struct PID_BURST_S { - u32 size; - u32 padding_cols; - u32 punct_cols; - u32 duration; - u32 cycle; - u32 calc_cycle; - } burst; - - u32 tot_tbl_cnt; - u32 invalid_tbl_cnt; - u32 tot_cor_tbl; -}; - -struct PID_DATA_S { - u32 pid; - u32 num_rows; - struct PID_STATISTICS_DATA_S pid_statistics; -}; - -#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) -#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) -#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ - if (_stat.TransmissionMode == 0) \ - _stat.TransmissionMode = 2; \ - else if (_stat.TransmissionMode == 1) \ - _stat.TransmissionMode = 8; \ - else \ - _stat.TransmissionMode = 4; - -struct TRANSMISSION_STATISTICS_S { - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* FFT mode carriers in Kilos */ - u32 GuardInterval; /* Guard Interval from - SMSHOSTLIB_GUARD_INTERVALS_ET */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ - u32 LPCodeRate; /* Low Priority Code Rate from - SMSHOSTLIB_CODE_RATE_ET */ - u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ - u32 Constellation; /* Constellation from - SMSHOSTLIB_CONSTELLATION_ET */ - - /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; - if set to 0xFFFFFFFF cell_id not yet recovered */ - u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ -}; - -struct RECEPTION_STATISTICS_S { - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ - - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ - s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ - u32 BERErrorCount; /* Number of erronous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ - u32 TS_PER; /* Transport stream PER, - 0xFFFFFFFF indicate N/A */ - u32 MFER; /* DVB-H frame error rate in percentage, - 0xFFFFFFFF indicate N/A, valid only for DVB-H */ - s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - u32 ErrorTSPackets; /* Number of erroneous - transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - - s32 MRC_SNR; /* dB */ - s32 MRC_RSSI; /* dBm */ - s32 MRC_InBandPwr; /* In band power in dBM */ -}; - - -/* Statistics information returned as response for - * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ -struct SMSHOSTLIB_STATISTICS_DVB_S { - /* Reception */ - struct RECEPTION_STATISTICS_S ReceptionData; - - /* Transmission parameters */ - struct TRANSMISSION_STATISTICS_S TransmissionData; - - /* Burst parameters, valid only for DVB-H */ -#define SRVM_MAX_PID_FILTERS 8 - struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; -}; - -struct SRVM_SIGNAL_STATUS_S { - u32 result; - u32 snr; - u32 tsPackets; - u32 etsPackets; - u32 constellation; - u32 hpCode; - u32 tpsSrvIndLP; - u32 tpsSrvIndHP; - u32 cellId; - u32 reason; - - s32 inBandPower; - u32 requestId; -}; - -struct SMSHOSTLIB_I2C_REQ_ST { - u32 DeviceAddress; /* I2c device address */ - u32 WriteCount; /* number of bytes to write */ - u32 ReadCount; /* number of bytes to read */ - u8 Data[1]; -}; - -struct SMSHOSTLIB_I2C_RES_ST { - u32 Status; /* non-zero value in case of failure */ - u32 ReadCount; /* number of bytes read */ - u8 Data[1]; -}; - - -struct smscore_config_gpio { -#define SMS_GPIO_DIRECTION_INPUT 0 -#define SMS_GPIO_DIRECTION_OUTPUT 1 - u8 direction; - -#define SMS_GPIO_PULLUPDOWN_NONE 0 -#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1 -#define SMS_GPIO_PULLUPDOWN_PULLUP 2 -#define SMS_GPIO_PULLUPDOWN_KEEPER 3 - u8 pullupdown; - -#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0 -#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 - u8 inputcharacteristics; - -#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 -#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 - u8 outputslewrate; - -#define SMS_GPIO_OUTPUTDRIVING_4mA 0 -#define SMS_GPIO_OUTPUTDRIVING_8mA 1 -#define SMS_GPIO_OUTPUTDRIVING_12mA 2 -#define SMS_GPIO_OUTPUTDRIVING_16mA 3 - u8 outputdriving; -}; - -struct smscore_gpio_config { -#define SMS_GPIO_DIRECTION_INPUT 0 -#define SMS_GPIO_DIRECTION_OUTPUT 1 - u8 Direction; - -#define SMS_GPIO_PULL_UP_DOWN_NONE 0 -#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1 -#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2 -#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3 - u8 PullUpDown; - -#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0 -#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1 - u8 InputCharacteristics; - -#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */ - - -#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */ - u8 OutputSlewRate; - -#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */ - -#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */ - u8 OutputDriving; -}; - -extern void smscore_registry_setmode(char *devpath, int mode); -extern int smscore_registry_getmode(char *devpath); - -extern int smscore_register_hotplug(hotplug_t hotplug); -extern void smscore_unregister_hotplug(hotplug_t hotplug); - -extern int smscore_register_device(struct smsdevice_params_t *params, - struct smscore_device_t **coredev); -extern void smscore_unregister_device(struct smscore_device_t *coredev); - -extern int smscore_start_device(struct smscore_device_t *coredev); -extern int smscore_load_firmware(struct smscore_device_t *coredev, - char *filename, - loadfirmware_t loadfirmware_handler); - -extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode); -extern int smscore_get_device_mode(struct smscore_device_t *coredev); - -extern int smscore_register_client(struct smscore_device_t *coredev, - struct smsclient_params_t *params, - struct smscore_client_t **client); -extern void smscore_unregister_client(struct smscore_client_t *client); - -extern int smsclient_sendrequest(struct smscore_client_t *client, - void *buffer, size_t size); -extern void smscore_onresponse(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb); - -extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); -extern int smscore_map_common_buffer(struct smscore_device_t *coredev, - struct vm_area_struct *vma); -extern int smscore_get_fw_filename(struct smscore_device_t *coredev, - int mode, char *filename); -extern int smscore_send_fw_file(struct smscore_device_t *coredev, - u8 *ufwbuf, int size); - -extern -struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev); -extern void smscore_putbuffer(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb); - -/* old GPIO management */ -int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, - struct smscore_config_gpio *pinconfig); -int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); - -/* new GPIO management */ -extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_gpio_config *pGpioConfig); -extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, - u8 NewLevel); -extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, - u8 *level); - -void smscore_set_board_id(struct smscore_device_t *core, int id); -int smscore_get_board_id(struct smscore_device_t *core); - -int smscore_led_state(struct smscore_device_t *core, int led); - - -/* ------------------------------------------------------------------------ */ - -#define DBG_INFO 1 -#define DBG_ADV 2 - -#define sms_printk(kern, fmt, arg...) \ - printk(kern "%s: " fmt "\n", __func__, ##arg) - -#define dprintk(kern, lvl, fmt, arg...) do {\ - if (sms_dbg & lvl) \ - sms_printk(kern, fmt, ##arg); } while (0) - -#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) -#define sms_err(fmt, arg...) \ - sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg) -#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg) -#define sms_info(fmt, arg...) \ - dprintk(KERN_INFO, DBG_INFO, fmt, ##arg) -#define sms_debug(fmt, arg...) \ - dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) - - -#endif /* __SMS_CORE_API_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsdvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsdvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsdvb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsdvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,962 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2008, Uri Shkolnik - -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, or -(at your option) any later version. - - 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, see . - -****************************************************************/ - -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" - -#include "smscoreapi.h" -#include "smsendian.h" -#include "sms-cards.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct smsdvb_client_t { - struct list_head entry; - - struct smscore_device_t *coredev; - struct smscore_client_t *smsclient; - - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dvb_frontend frontend; - - fe_status_t fe_status; - - struct completion tune_done; - - /* todo: save freq/band instead whole struct */ - struct dvb_frontend_parameters fe_params; - - struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; - int event_fe_state; - int event_unc_state; -}; - -static struct list_head g_smsdvb_clients; -static struct mutex g_smsdvb_clientslock; - -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - -/* Events that may come from DVB v3 adapter */ -static void sms_board_dvb3_event(struct smsdvb_client_t *client, - enum SMS_DVB3_EVENTS event) { - - struct smscore_device_t *coredev = client->coredev; - switch (event) { - case DVB3_EVENT_INIT: - sms_debug("DVB3_EVENT_INIT"); - sms_board_event(coredev, BOARD_EVENT_BIND); - break; - case DVB3_EVENT_SLEEP: - sms_debug("DVB3_EVENT_SLEEP"); - sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); - break; - case DVB3_EVENT_HOTPLUG: - sms_debug("DVB3_EVENT_HOTPLUG"); - sms_board_event(coredev, BOARD_EVENT_POWER_INIT); - break; - case DVB3_EVENT_FE_LOCK: - if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { - client->event_fe_state = DVB3_EVENT_FE_LOCK; - sms_debug("DVB3_EVENT_FE_LOCK"); - sms_board_event(coredev, BOARD_EVENT_FE_LOCK); - } - break; - case DVB3_EVENT_FE_UNLOCK: - if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { - client->event_fe_state = DVB3_EVENT_FE_UNLOCK; - sms_debug("DVB3_EVENT_FE_UNLOCK"); - sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); - } - break; - case DVB3_EVENT_UNC_OK: - if (client->event_unc_state != DVB3_EVENT_UNC_OK) { - client->event_unc_state = DVB3_EVENT_UNC_OK; - sms_debug("DVB3_EVENT_UNC_OK"); - sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); - } - break; - case DVB3_EVENT_UNC_ERR: - if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { - client->event_unc_state = DVB3_EVENT_UNC_ERR; - sms_debug("DVB3_EVENT_UNC_ERR"); - sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); - } - break; - - default: - sms_err("Unknown dvb3 api event"); - break; - } -} - - -static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData, - struct SMSHOSTLIB_STATISTICS_ST *p) -{ - if (sms_dbg & 2) { - printk(KERN_DEBUG "Reserved = %d", p->Reserved); - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "BER = %d", p->BER); - printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC); - printk(KERN_DEBUG "TS_PER = %d", p->TS_PER); - printk(KERN_DEBUG "MFER = %d", p->MFER); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "CodeRate = %d", p->CodeRate); - printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate); - printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy); - printk(KERN_DEBUG "Constellation = %d", p->Constellation); - printk(KERN_DEBUG "BurstSize = %d", p->BurstSize); - printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration); - printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime); - printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime); - printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows); - printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols); - printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols); - printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets); - printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets); - printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs); - printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs); - printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs); - printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount); - printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); - printk(KERN_DEBUG "PreBER = %d", p->PreBER); - printk(KERN_DEBUG "CellId = %d", p->CellId); - printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP); - printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP); - printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived); - } - - pReceptionData->IsDemodLocked = p->IsDemodLocked; - - pReceptionData->SNR = p->SNR; - pReceptionData->BER = p->BER; - pReceptionData->BERErrorCount = p->BERErrorCount; - pReceptionData->InBandPwr = p->InBandPwr; - pReceptionData->ErrorTSPackets = p->ErrorTSPackets; -}; - - -static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData, - struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) -{ - int i; - - if (sms_dbg & 2) { - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "SystemType = %d", p->SystemType); - printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); - printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); - - for (i = 0; i < 3; i++) { - printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); - printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); - printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); - printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); - printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); - printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); - printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); - printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); - printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); - printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); - printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); - printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); - } - } - - pReceptionData->IsDemodLocked = p->IsDemodLocked; - - pReceptionData->SNR = p->SNR; - pReceptionData->InBandPwr = p->InBandPwr; - - pReceptionData->ErrorTSPackets = 0; - pReceptionData->BER = 0; - pReceptionData->BERErrorCount = 0; - for (i = 0; i < 3; i++) { - pReceptionData->BER += p->LayerInfo[i].BER; - pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount; - pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets; - } -} - -static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) -{ - struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) - + cb->offset); - u32 *pMsgData = (u32 *) phdr + 1; - /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/ - bool is_status_update = false; - - smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); - - switch (phdr->msgType) { - case MSG_SMS_DVBT_BDA_DATA: - dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1), - cb->size - sizeof(struct SmsMsgHdr_ST)); - break; - - case MSG_SMS_RF_TUNE_RES: - case MSG_SMS_ISDBT_TUNE_RES: - complete(&client->tune_done); - break; - - case MSG_SMS_SIGNAL_DETECTED_IND: - sms_info("MSG_SMS_SIGNAL_DETECTED_IND"); - client->sms_stat_dvb.TransmissionData.IsDemodLocked = true; - is_status_update = true; - break; - - case MSG_SMS_NO_SIGNAL_IND: - sms_info("MSG_SMS_NO_SIGNAL_IND"); - client->sms_stat_dvb.TransmissionData.IsDemodLocked = false; - is_status_update = true; - break; - - case MSG_SMS_TRANSMISSION_IND: { - sms_info("MSG_SMS_TRANSMISSION_IND"); - - pMsgData++; - memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, - sizeof(struct TRANSMISSION_STATISTICS_S)); - - /* Mo need to correct guard interval - * (as opposed to old statistics message). - */ - CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData); - CORRECT_STAT_TRANSMISSON_MODE( - client->sms_stat_dvb.TransmissionData); - is_status_update = true; - break; - } - case MSG_SMS_HO_PER_SLICES_IND: { - struct RECEPTION_STATISTICS_S *pReceptionData = - &client->sms_stat_dvb.ReceptionData; - struct SRVM_SIGNAL_STATUS_S SignalStatusData; - - /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/ - pMsgData++; - SignalStatusData.result = pMsgData[0]; - SignalStatusData.snr = pMsgData[1]; - SignalStatusData.inBandPower = (s32) pMsgData[2]; - SignalStatusData.tsPackets = pMsgData[3]; - SignalStatusData.etsPackets = pMsgData[4]; - SignalStatusData.constellation = pMsgData[5]; - SignalStatusData.hpCode = pMsgData[6]; - SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03; - SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03; - SignalStatusData.cellId = pMsgData[9] & 0xFFFF; - SignalStatusData.reason = pMsgData[10]; - SignalStatusData.requestId = pMsgData[11]; - pReceptionData->IsRfLocked = pMsgData[16]; - pReceptionData->IsDemodLocked = pMsgData[17]; - pReceptionData->ModemState = pMsgData[12]; - pReceptionData->SNR = pMsgData[1]; - pReceptionData->BER = pMsgData[13]; - pReceptionData->RSSI = pMsgData[14]; - CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData); - - pReceptionData->InBandPwr = (s32) pMsgData[2]; - pReceptionData->CarrierOffset = (s32) pMsgData[15]; - pReceptionData->TotalTSPackets = pMsgData[3]; - pReceptionData->ErrorTSPackets = pMsgData[4]; - - /* TS PER */ - if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets) - > 0) { - pReceptionData->TS_PER = (SignalStatusData.etsPackets - * 100) / (SignalStatusData.tsPackets - + SignalStatusData.etsPackets); - } else { - pReceptionData->TS_PER = 0; - } - - pReceptionData->BERBitCount = pMsgData[18]; - pReceptionData->BERErrorCount = pMsgData[19]; - - pReceptionData->MRC_SNR = pMsgData[20]; - pReceptionData->MRC_InBandPwr = pMsgData[21]; - pReceptionData->MRC_RSSI = pMsgData[22]; - - is_status_update = true; - break; - } - case MSG_SMS_GET_STATISTICS_RES: { - union { - struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt; - struct SmsMsgStatisticsInfo_ST dvb; - } *p = (void *) (phdr + 1); - struct RECEPTION_STATISTICS_S *pReceptionData = - &client->sms_stat_dvb.ReceptionData; - - sms_info("MSG_SMS_GET_STATISTICS_RES"); - - is_status_update = true; - - switch (smscore_get_device_mode(client->coredev)) { - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt); - break; - default: - smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat); - } - if (!pReceptionData->IsDemodLocked) { - pReceptionData->SNR = 0; - pReceptionData->BER = 0; - pReceptionData->BERErrorCount = 0; - pReceptionData->InBandPwr = 0; - pReceptionData->ErrorTSPackets = 0; - } - - complete(&client->tune_done); - break; - } - default: - sms_info("Unhandled message %d", phdr->msgType); - - } - smscore_putbuffer(client->coredev, cb); - - if (is_status_update) { - if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) { - client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER - | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); - if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets - == 0) - sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); - else - sms_board_dvb3_event(client, - DVB3_EVENT_UNC_ERR); - - } else { - if (client->sms_stat_dvb.ReceptionData.IsRfLocked) - client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - else - client->fe_status = 0; - sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); - } - } - - return 0; -} - -static void smsdvb_unregister_client(struct smsdvb_client_t *client) -{ - /* must be called under clientslock */ - - list_del(&client->entry); - - smscore_unregister_client(client->smsclient); - dvb_unregister_frontend(&client->frontend); - dvb_dmxdev_release(&client->dmxdev); - dvb_dmx_release(&client->demux); - dvb_unregister_adapter(&client->adapter); - kfree(client); -} - -static void smsdvb_onremove(void *context) -{ - kmutex_lock(&g_smsdvb_clientslock); - - smsdvb_unregister_client((struct smsdvb_client_t *) context); - - kmutex_unlock(&g_smsdvb_clientslock); -} - -static int smsdvb_start_feed(struct dvb_demux_feed *feed) -{ - struct smsdvb_client_t *client = - container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; - - sms_debug("add pid %d(%x)", - feed->pid, feed->pid); - - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); - return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); -} - -static int smsdvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct smsdvb_client_t *client = - container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; - - sms_debug("remove pid %d(%x)", - feed->pid, feed->pid); - - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); - return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); -} - -static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, - void *buffer, size_t size, - struct completion *completion) -{ - int rc; - - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer); - rc = smsclient_sendrequest(client->smsclient, buffer, size); - if (rc < 0) - return rc; - - return wait_for_completion_timeout(completion, - msecs_to_jiffies(2000)) ? - 0 : -ETIME; -} - -static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) -{ - int rc; - struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, - DVBT_BDA_CONTROL_MSG_ID, - HIF_TASK, - sizeof(struct SmsMsgHdr_ST), 0 }; - - rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - return rc; -} - -static inline int led_feedback(struct smsdvb_client_t *client) -{ - if (client->fe_status & FE_HAS_LOCK) - return sms_board_led_feedback(client->coredev, - (client->sms_stat_dvb.ReceptionData.BER - == 0) ? SMS_LED_HI : SMS_LED_LO); - else - return sms_board_led_feedback(client->coredev, SMS_LED_OFF); -} - -static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *stat = client->fe_status; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *ber = client->sms_stat_dvb.ReceptionData.BER; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - int rc; - - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95) - *strength = 0; - else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29) - *strength = 100; - else - *strength = - (client->sms_stat_dvb.ReceptionData.InBandPwr - + 95) * 3 / 2; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *snr = client->sms_stat_dvb.ReceptionData.SNR; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets; - - led_feedback(client); - - return rc; -} - -static int smsdvb_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - sms_debug(""); - - tune->min_delay_ms = 400; - tune->step_size = 250000; - tune->max_drift = 0; - return 0; -} - -static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - struct { - struct SmsMsgHdr_ST Msg; - u32 Data[3]; - } Msg; - - int ret; - - client->fe_status = FE_HAS_SIGNAL; - client->event_fe_state = -1; - client->event_unc_state = -1; - fe->dtv_property_cache.delivery_system = SYS_DVBT; - - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); - Msg.Data[0] = c->frequency; - Msg.Data[2] = 12000000; - - sms_info("%s: freq %d band %d", __func__, c->frequency, - c->bandwidth_hz); - - switch (c->bandwidth_hz / 1000000) { - case 8: - Msg.Data[1] = BW_8_MHZ; - break; - case 7: - Msg.Data[1] = BW_7_MHZ; - break; - case 6: - Msg.Data[1] = BW_6_MHZ; - break; - case 0: - return -EOPNOTSUPP; - default: - return -EINVAL; - } - /* Disable LNA, if any. An error is returned if no LNA is present */ - ret = sms_board_lna_control(client->coredev, 0); - if (ret == 0) { - fe_status_t status; - - /* tune with LNA off at first */ - ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - smsdvb_read_status(fe, &status); - - if (status & FE_HAS_LOCK) - return ret; - - /* previous tune didnt lock - enable LNA and tune again */ - sms_board_lna_control(client->coredev, 1); - } - - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); -} - -static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - struct { - struct SmsMsgHdr_ST Msg; - u32 Data[4]; - } Msg; - - fe->dtv_property_cache.delivery_system = SYS_ISDBT; - - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); - - if (c->isdbt_sb_segment_idx == -1) - c->isdbt_sb_segment_idx = 0; - - switch (c->isdbt_sb_segment_count) { - case 3: - Msg.Data[1] = BW_ISDBT_3SEG; - break; - case 1: - Msg.Data[1] = BW_ISDBT_1SEG; - break; - case 0: /* AUTO */ - switch (c->bandwidth_hz / 1000000) { - case 8: - case 7: - c->isdbt_sb_segment_count = 3; - Msg.Data[1] = BW_ISDBT_3SEG; - break; - case 6: - c->isdbt_sb_segment_count = 1; - Msg.Data[1] = BW_ISDBT_1SEG; - break; - default: /* Assumes 6 MHZ bw */ - c->isdbt_sb_segment_count = 1; - c->bandwidth_hz = 6000; - Msg.Data[1] = BW_ISDBT_1SEG; - break; - } - break; - default: - sms_info("Segment count %d not supported", c->isdbt_sb_segment_count); - return -EINVAL; - } - - Msg.Data[0] = c->frequency; - Msg.Data[2] = 12000000; - Msg.Data[3] = c->isdbt_sb_segment_idx; - - sms_info("%s: freq %d segwidth %d segindex %d\n", __func__, - c->frequency, c->isdbt_sb_segment_count, - c->isdbt_sb_segment_idx); - - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); -} - -static int smsdvb_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct smscore_device_t *coredev = client->coredev; - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - return smsdvb_dvbt_set_frontend(fe, fep); - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - return smsdvb_isdbt_set_frontend(fe, fep); - default: - return -EINVAL; - } -} - -static int smsdvb_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - sms_debug(""); - - /* todo: */ - memcpy(fep, &client->fe_params, - sizeof(struct dvb_frontend_parameters)); - - return 0; -} - -static int smsdvb_init(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - sms_board_power(client->coredev, 1); - - sms_board_dvb3_event(client, DVB3_EVENT_INIT); - return 0; -} - -static int smsdvb_sleep(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - sms_board_led_feedback(client->coredev, SMS_LED_OFF); - sms_board_power(client->coredev, 0); - - sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); - - return 0; -} - -static void smsdvb_release(struct dvb_frontend *fe) -{ - /* do nothing */ -} - -static struct dvb_frontend_ops smsdvb_fe_ops = { - .info = { - .name = "Siano Mobile Digital MDTV Receiver", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = smsdvb_release, - - .set_frontend = smsdvb_set_frontend, - .get_frontend = smsdvb_get_frontend, - .get_tune_settings = smsdvb_get_tune_settings, - - .read_status = smsdvb_read_status, - .read_ber = smsdvb_read_ber, - .read_signal_strength = smsdvb_read_signal_strength, - .read_snr = smsdvb_read_snr, - .read_ucblocks = smsdvb_read_ucblocks, - - .init = smsdvb_init, - .sleep = smsdvb_sleep, -}; - -static int smsdvb_hotplug(struct smscore_device_t *coredev, - struct device *device, int arrival) -{ - struct smsclient_params_t params; - struct smsdvb_client_t *client; - int rc; - - /* device removal handled by onremove callback */ - if (!arrival) - return 0; - client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); - if (!client) { - sms_err("kmalloc() failed"); - return -ENOMEM; - } - - /* register dvb adapter */ - rc = dvb_register_adapter(&client->adapter, - sms_get_board( - smscore_get_board_id(coredev))->name, - THIS_MODULE, device, adapter_nr); - if (rc < 0) { - sms_err("dvb_register_adapter() failed %d", rc); - goto adapter_error; - } - - /* init dvb demux */ - client->demux.dmx.capabilities = DMX_TS_FILTERING; - client->demux.filternum = 32; /* todo: nova ??? */ - client->demux.feednum = 32; - client->demux.start_feed = smsdvb_start_feed; - client->demux.stop_feed = smsdvb_stop_feed; - - rc = dvb_dmx_init(&client->demux); - if (rc < 0) { - sms_err("dvb_dmx_init failed %d", rc); - goto dvbdmx_error; - } - - /* init dmxdev */ - client->dmxdev.filternum = 32; - client->dmxdev.demux = &client->demux.dmx; - client->dmxdev.capabilities = 0; - - rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); - if (rc < 0) { - sms_err("dvb_dmxdev_init failed %d", rc); - goto dmxdev_error; - } - - /* init and register frontend */ - memcpy(&client->frontend.ops, &smsdvb_fe_ops, - sizeof(struct dvb_frontend_ops)); - - rc = dvb_register_frontend(&client->adapter, &client->frontend); - if (rc < 0) { - sms_err("frontend registration failed %d", rc); - goto frontend_error; - } - - params.initial_id = 1; - params.data_type = MSG_SMS_DVBT_BDA_DATA; - params.onresponse_handler = smsdvb_onresponse; - params.onremove_handler = smsdvb_onremove; - params.context = client; - - rc = smscore_register_client(coredev, ¶ms, &client->smsclient); - if (rc < 0) { - sms_err("smscore_register_client() failed %d", rc); - goto client_error; - } - - client->coredev = coredev; - - init_completion(&client->tune_done); - - kmutex_lock(&g_smsdvb_clientslock); - - list_add(&client->entry, &g_smsdvb_clients); - - kmutex_unlock(&g_smsdvb_clientslock); - - client->event_fe_state = -1; - client->event_unc_state = -1; - sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); - - sms_info("success"); - sms_board_setup(coredev); - - return 0; - -client_error: - dvb_unregister_frontend(&client->frontend); - -frontend_error: - dvb_dmxdev_release(&client->dmxdev); - -dmxdev_error: - dvb_dmx_release(&client->demux); - -dvbdmx_error: - dvb_unregister_adapter(&client->adapter); - -adapter_error: - kfree(client); - return rc; -} - -static int __init smsdvb_module_init(void) -{ - int rc; - - INIT_LIST_HEAD(&g_smsdvb_clients); - kmutex_init(&g_smsdvb_clientslock); - - rc = smscore_register_hotplug(smsdvb_hotplug); - - sms_debug(""); - - return rc; -} - -static void __exit smsdvb_module_exit(void) -{ - smscore_unregister_hotplug(smsdvb_hotplug); - - kmutex_lock(&g_smsdvb_clientslock); - - while (!list_empty(&g_smsdvb_clients)) - smsdvb_unregister_client( - (struct smsdvb_client_t *) g_smsdvb_clients.next); - - kmutex_unlock(&g_smsdvb_clientslock); -} - -module_init(smsdvb_module_init); -module_exit(smsdvb_module_exit); - -MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); -MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsendian.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsendian.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsendian.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsendian.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/**************************************************************** - - Siano Mobile Silicon, Inc. - MDTV receiver kernel modules. - Copyright (C) 2006-2009, Uri Shkolnik - - 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, or - (at your option) any later version. - - 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, see . - - ****************************************************************/ - -#include - -#include "smsendian.h" -#include "smscoreapi.h" - -void smsendian_handle_tx_message(void *buffer) -{ -#ifdef __BIG_ENDIAN - struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; - int i; - int msgWords; - - switch (msg->xMsgHeader.msgType) { - case MSG_SMS_DATA_DOWNLOAD_REQ: - { - msg->msgData[0] = le32_to_cpu(msg->msgData[0]); - break; - } - - default: - msgWords = (msg->xMsgHeader.msgLength - - sizeof(struct SmsMsgHdr_ST))/4; - - for (i = 0; i < msgWords; i++) - msg->msgData[i] = le32_to_cpu(msg->msgData[i]); - - break; - } -#endif /* __BIG_ENDIAN */ -} -EXPORT_SYMBOL_GPL(smsendian_handle_tx_message); - -void smsendian_handle_rx_message(void *buffer) -{ -#ifdef __BIG_ENDIAN - struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; - int i; - int msgWords; - - switch (msg->xMsgHeader.msgType) { - case MSG_SMS_GET_VERSION_EX_RES: - { - struct SmsVersionRes_ST *ver = - (struct SmsVersionRes_ST *) msg; - ver->ChipModel = le16_to_cpu(ver->ChipModel); - break; - } - - case MSG_SMS_DVBT_BDA_DATA: - case MSG_SMS_DAB_CHANNEL: - case MSG_SMS_DATA_MSG: - { - break; - } - - default: - { - msgWords = (msg->xMsgHeader.msgLength - - sizeof(struct SmsMsgHdr_ST))/4; - - for (i = 0; i < msgWords; i++) - msg->msgData[i] = le32_to_cpu(msg->msgData[i]); - - break; - } - } -#endif /* __BIG_ENDIAN */ -} -EXPORT_SYMBOL_GPL(smsendian_handle_rx_message); - -void smsendian_handle_message_header(void *msg) -{ -#ifdef __BIG_ENDIAN - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg; - - phdr->msgType = le16_to_cpu(phdr->msgType); - phdr->msgLength = le16_to_cpu(phdr->msgLength); - phdr->msgFlags = le16_to_cpu(phdr->msgFlags); -#endif /* __BIG_ENDIAN */ -} -EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsendian.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsendian.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsendian.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsendian.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2009, Uri Shkolnik - -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, or -(at your option) any later version. - - 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, see . - -****************************************************************/ - -#ifndef __SMS_ENDIAN_H__ -#define __SMS_ENDIAN_H__ - -#include - -extern void smsendian_handle_tx_message(void *buffer); -extern void smsendian_handle_rx_message(void *buffer); -extern void smsendian_handle_message_header(void *msg); - -#endif /* __SMS_ENDIAN_H__ */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsir.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/**************************************************************** - - Siano Mobile Silicon, Inc. - MDTV receiver kernel modules. - Copyright (C) 2006-2009, Uri Shkolnik - - Copyright (c) 2010 - Mauro Carvalho Chehab - - Ported the driver to use rc-core - - IR raw event decoding is now done at rc-core - - Code almost re-written - - 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, or - (at your option) any later version. - - 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, see . - - ****************************************************************/ - - -#include -#include - -#include "smscoreapi.h" -#include "smsir.h" -#include "sms-cards.h" - -#define MODULE_NAME "smsmdtv" - -void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len) -{ - int i; - const s32 *samples = (const void *)buf; - - for (i = 0; i < len >> 2; i++) { - DEFINE_IR_RAW_EVENT(ev); - - ev.duration = abs(samples[i]) * 1000; /* Convert to ns */ - ev.pulse = (samples[i] > 0) ? false : true; - - ir_raw_event_store(coredev->ir.dev, &ev); - } - ir_raw_event_handle(coredev->ir.dev); -} - -int sms_ir_init(struct smscore_device_t *coredev) -{ - int err; - int board_id = smscore_get_board_id(coredev); - struct rc_dev *dev; - - sms_log("Allocating rc device"); - dev = rc_allocate_device(); - if (!dev) { - sms_err("Not enough memory"); - return -ENOMEM; - } - - coredev->ir.controller = 0; /* Todo: vega/nova SPI number */ - coredev->ir.timeout = IR_DEFAULT_TIMEOUT; - sms_log("IR port %d, timeout %d ms", - coredev->ir.controller, coredev->ir.timeout); - - snprintf(coredev->ir.name, sizeof(coredev->ir.name), - "SMS IR (%s)", sms_get_board(board_id)->name); - - strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys)); - strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys)); - - dev->input_name = coredev->ir.name; - dev->input_phys = coredev->ir.phys; - dev->dev.parent = coredev->device; - -#if 0 - /* TODO: properly initialize the parameters bellow */ - dev->input_id.bustype = BUS_USB; - dev->input_id.version = 1; - dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); -#endif - - dev->priv = coredev; - dev->driver_type = RC_DRIVER_IR_RAW; - dev->allowed_protos = RC_TYPE_ALL; - dev->map_name = sms_get_board(board_id)->rc_codes; - dev->driver_name = MODULE_NAME; - - sms_log("Input device (IR) %s is set for key events", dev->input_name); - - err = rc_register_device(dev); - if (err < 0) { - sms_err("Failed to register device"); - rc_free_device(dev); - return err; - } - - coredev->ir.dev = dev; - return 0; -} - -void sms_ir_exit(struct smscore_device_t *coredev) -{ - if (coredev->ir.dev) - rc_unregister_device(coredev->ir.dev); - - sms_log(""); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsir.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsir.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2009, Uri Shkolnik - - Copyright (c) 2010 - Mauro Carvalho Chehab - - Ported the driver to use rc-core - - IR raw event decoding is now done at rc-core - - Code almost re-written - -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, or -(at your option) any later version. - - 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, see . - -****************************************************************/ - -#ifndef __SMS_IR_H__ -#define __SMS_IR_H__ - -#include -#include - -#define IR_DEFAULT_TIMEOUT 100 - -struct smscore_device_t; - -struct ir_t { - struct rc_dev *dev; - char name[40]; - char phys[32]; - - char *rc_codes; - u64 protocol; - - u32 timeout; - u32 controller; -}; - -int sms_ir_init(struct smscore_device_t *coredev); -void sms_ir_exit(struct smscore_device_t *coredev); -void sms_ir_event(struct smscore_device_t *coredev, - const char *buf, int len); - -#endif /* __SMS_IR_H__ */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smssdio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smssdio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smssdio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smssdio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,364 +0,0 @@ -/* - * smssdio.c - Siano 1xxx SDIO interface driver - * - * Copyright 2008 Pierre Ossman - * - * Based on code by Siano Mobile Silicon, Inc., - * Copyright (C) 2006-2008, Uri Shkolnik - * - * 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, or (at - * your option) any later version. - * - * - * This hardware is a bit odd in that all transfers should be done - * to/from the SMSSDIO_DATA register, yet the "increase address" bit - * always needs to be set. - * - * Also, buffers from the card are always aligned to 128 byte - * boundaries. - */ - -/* - * General cleanup notes: - * - * - only typedefs should be name *_t - * - * - use ERR_PTR and friends for smscore_register_device() - * - * - smscore_getbuffer should zero fields - * - * Fix stop command - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "smscoreapi.h" -#include "sms-cards.h" - -/* Registers */ - -#define SMSSDIO_DATA 0x00 -#define SMSSDIO_INT 0x04 -#define SMSSDIO_BLOCK_SIZE 128 - -static const struct sdio_device_id smssdio_ids[] __devinitconst = { - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), - .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), - .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0), - .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0), - .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE), - .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, - { /* end: all zeroes */ }, -}; - -MODULE_DEVICE_TABLE(sdio, smssdio_ids); - -struct smssdio_device { - struct sdio_func *func; - - struct smscore_device_t *coredev; - - struct smscore_buffer_t *split_cb; -}; - -/*******************************************************************/ -/* Siano core callbacks */ -/*******************************************************************/ - -static int smssdio_sendrequest(void *context, void *buffer, size_t size) -{ - int ret = 0; - struct smssdio_device *smsdev; - - smsdev = context; - - sdio_claim_host(smsdev->func); - - while (size >= smsdev->func->cur_blksize) { - ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, - buffer, smsdev->func->cur_blksize); - if (ret) - goto out; - - buffer += smsdev->func->cur_blksize; - size -= smsdev->func->cur_blksize; - } - - if (size) { - ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, - buffer, size); - } - -out: - sdio_release_host(smsdev->func); - - return ret; -} - -/*******************************************************************/ -/* SDIO callbacks */ -/*******************************************************************/ - -static void smssdio_interrupt(struct sdio_func *func) -{ - int ret, isr; - - struct smssdio_device *smsdev; - struct smscore_buffer_t *cb; - struct SmsMsgHdr_ST *hdr; - size_t size; - - smsdev = sdio_get_drvdata(func); - - /* - * The interrupt register has no defined meaning. It is just - * a way of turning of the level triggered interrupt. - */ - isr = sdio_readb(func, SMSSDIO_INT, &ret); - if (ret) { - sms_err("Unable to read interrupt register!\n"); - return; - } - - if (smsdev->split_cb == NULL) { - cb = smscore_getbuffer(smsdev->coredev); - if (!cb) { - sms_err("Unable to allocate data buffer!\n"); - return; - } - - ret = sdio_memcpy_fromio(smsdev->func, - cb->p, - SMSSDIO_DATA, - SMSSDIO_BLOCK_SIZE); - if (ret) { - sms_err("Error %d reading initial block!\n", ret); - return; - } - - hdr = cb->p; - - if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) { - smsdev->split_cb = cb; - return; - } - - if (hdr->msgLength > smsdev->func->cur_blksize) - size = hdr->msgLength - smsdev->func->cur_blksize; - else - size = 0; - } else { - cb = smsdev->split_cb; - hdr = cb->p; - - size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST); - - smsdev->split_cb = NULL; - } - - if (size) { - void *buffer; - - buffer = cb->p + (hdr->msgLength - size); - size = ALIGN(size, SMSSDIO_BLOCK_SIZE); - - BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE); - - /* - * First attempt to transfer all of it in one go... - */ - ret = sdio_memcpy_fromio(smsdev->func, - buffer, - SMSSDIO_DATA, - size); - if (ret && ret != -EINVAL) { - smscore_putbuffer(smsdev->coredev, cb); - sms_err("Error %d reading data from card!\n", ret); - return; - } - - /* - * ..then fall back to one block at a time if that is - * not possible... - * - * (we have to do this manually because of the - * problem with the "increase address" bit) - */ - if (ret == -EINVAL) { - while (size) { - ret = sdio_memcpy_fromio(smsdev->func, - buffer, SMSSDIO_DATA, - smsdev->func->cur_blksize); - if (ret) { - smscore_putbuffer(smsdev->coredev, cb); - sms_err("Error %d reading " - "data from card!\n", ret); - return; - } - - buffer += smsdev->func->cur_blksize; - if (size > smsdev->func->cur_blksize) - size -= smsdev->func->cur_blksize; - else - size = 0; - } - } - } - - cb->size = hdr->msgLength; - cb->offset = 0; - - smscore_onresponse(smsdev->coredev, cb); -} - -static int __devinit smssdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - int ret; - - int board_id; - struct smssdio_device *smsdev; - struct smsdevice_params_t params; - - board_id = id->driver_data; - - smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL); - if (!smsdev) - return -ENOMEM; - - smsdev->func = func; - - memset(¶ms, 0, sizeof(struct smsdevice_params_t)); - - params.device = &func->dev; - params.buffer_size = 0x5000; /* ?? */ - params.num_buffers = 22; /* ?? */ - params.context = smsdev; - - snprintf(params.devpath, sizeof(params.devpath), - "sdio\\%s", sdio_func_id(func)); - - params.sendrequest_handler = smssdio_sendrequest; - - params.device_type = sms_get_board(board_id)->type; - - if (params.device_type != SMS_STELLAR) - params.flags |= SMS_DEVICE_FAMILY2; - else { - /* - * FIXME: Stellar needs special handling... - */ - ret = -ENODEV; - goto free; - } - - ret = smscore_register_device(¶ms, &smsdev->coredev); - if (ret < 0) - goto free; - - smscore_set_board_id(smsdev->coredev, board_id); - - sdio_claim_host(func); - - ret = sdio_enable_func(func); - if (ret) - goto release; - - ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE); - if (ret) - goto disable; - - ret = sdio_claim_irq(func, smssdio_interrupt); - if (ret) - goto disable; - - sdio_set_drvdata(func, smsdev); - - sdio_release_host(func); - - ret = smscore_start_device(smsdev->coredev); - if (ret < 0) - goto reclaim; - - return 0; - -reclaim: - sdio_claim_host(func); - sdio_release_irq(func); -disable: - sdio_disable_func(func); -release: - sdio_release_host(func); - smscore_unregister_device(smsdev->coredev); -free: - kfree(smsdev); - - return ret; -} - -static void smssdio_remove(struct sdio_func *func) -{ - struct smssdio_device *smsdev; - - smsdev = sdio_get_drvdata(func); - - /* FIXME: racy! */ - if (smsdev->split_cb) - smscore_putbuffer(smsdev->coredev, smsdev->split_cb); - - smscore_unregister_device(smsdev->coredev); - - sdio_claim_host(func); - sdio_release_irq(func); - sdio_disable_func(func); - sdio_release_host(func); - - kfree(smsdev); -} - -static struct sdio_driver smssdio_driver = { - .name = "smssdio", - .id_table = smssdio_ids, - .probe = smssdio_probe, - .remove = smssdio_remove, -}; - -/*******************************************************************/ -/* Module functions */ -/*******************************************************************/ - -static int __init smssdio_module_init(void) -{ - int ret = 0; - - printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n"); - printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n"); - - ret = sdio_register_driver(&smssdio_driver); - - return ret; -} - -static void __exit smssdio_module_exit(void) -{ - sdio_unregister_driver(&smssdio_driver); -} - -module_init(smssdio_module_init); -module_exit(smssdio_module_exit); - -MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver"); -MODULE_AUTHOR("Pierre Ossman"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsusb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsusb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsusb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/siano/smsusb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,583 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat - -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, or -(at your option) any later version. - - 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, see . - -****************************************************************/ - -#include -#include -#include -#include -#include - -#include "smscoreapi.h" -#include "sms-cards.h" -#include "smsendian.h" - -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - -#define USB1_BUFFER_SIZE 0x1000 -#define USB2_BUFFER_SIZE 0x4000 - -#define MAX_BUFFERS 50 -#define MAX_URBS 10 - -struct smsusb_device_t; - -struct smsusb_urb_t { - struct smscore_buffer_t *cb; - struct smsusb_device_t *dev; - - struct urb urb; -}; - -struct smsusb_device_t { - struct usb_device *udev; - struct smscore_device_t *coredev; - - struct smsusb_urb_t surbs[MAX_URBS]; - - int response_alignment; - int buffer_size; -}; - -static int smsusb_submit_urb(struct smsusb_device_t *dev, - struct smsusb_urb_t *surb); - -static void smsusb_onresponse(struct urb *urb) -{ - struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context; - struct smsusb_device_t *dev = surb->dev; - - if (urb->status == -ESHUTDOWN) { - sms_err("error, urb status %d (-ESHUTDOWN), %d bytes", - urb->status, urb->actual_length); - return; - } - - if ((urb->actual_length > 0) && (urb->status == 0)) { - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p; - - smsendian_handle_message_header(phdr); - if (urb->actual_length >= phdr->msgLength) { - surb->cb->size = phdr->msgLength; - - if (dev->response_alignment && - (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) { - - surb->cb->offset = - dev->response_alignment + - ((phdr->msgFlags >> 8) & 3); - - /* sanity check */ - if (((int) phdr->msgLength + - surb->cb->offset) > urb->actual_length) { - sms_err("invalid response " - "msglen %d offset %d " - "size %d", - phdr->msgLength, - surb->cb->offset, - urb->actual_length); - goto exit_and_resubmit; - } - - /* move buffer pointer and - * copy header to its new location */ - memcpy((char *) phdr + surb->cb->offset, - phdr, sizeof(struct SmsMsgHdr_ST)); - } else - surb->cb->offset = 0; - - smscore_onresponse(dev->coredev, surb->cb); - surb->cb = NULL; - } else { - sms_err("invalid response " - "msglen %d actual %d", - phdr->msgLength, urb->actual_length); - } - } else - sms_err("error, urb status %d, %d bytes", - urb->status, urb->actual_length); - - -exit_and_resubmit: - smsusb_submit_urb(dev, surb); -} - -static int smsusb_submit_urb(struct smsusb_device_t *dev, - struct smsusb_urb_t *surb) -{ - if (!surb->cb) { - surb->cb = smscore_getbuffer(dev->coredev); - if (!surb->cb) { - sms_err("smscore_getbuffer(...) returned NULL"); - return -ENOMEM; - } - } - - usb_fill_bulk_urb( - &surb->urb, - dev->udev, - usb_rcvbulkpipe(dev->udev, 0x81), - surb->cb->p, - dev->buffer_size, - smsusb_onresponse, - surb - ); - surb->urb.transfer_dma = surb->cb->phys; - surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - return usb_submit_urb(&surb->urb, GFP_ATOMIC); -} - -static void smsusb_stop_streaming(struct smsusb_device_t *dev) -{ - int i; - - for (i = 0; i < MAX_URBS; i++) { - usb_kill_urb(&dev->surbs[i].urb); - - if (dev->surbs[i].cb) { - smscore_putbuffer(dev->coredev, dev->surbs[i].cb); - dev->surbs[i].cb = NULL; - } - } -} - -static int smsusb_start_streaming(struct smsusb_device_t *dev) -{ - int i, rc; - - for (i = 0; i < MAX_URBS; i++) { - rc = smsusb_submit_urb(dev, &dev->surbs[i]); - if (rc < 0) { - sms_err("smsusb_submit_urb(...) failed"); - smsusb_stop_streaming(dev); - break; - } - } - - return rc; -} - -static int smsusb_sendrequest(void *context, void *buffer, size_t size) -{ - struct smsusb_device_t *dev = (struct smsusb_device_t *) context; - int dummy; - - smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); - return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), - buffer, size, &dummy, 1000); -} - -static char *smsusb1_fw_lkup[] = { - "dvbt_stellar_usb.inp", - "dvbh_stellar_usb.inp", - "tdmb_stellar_usb.inp", - "none", - "dvbt_bda_stellar_usb.inp", -}; - -static inline char *sms_get_fw_name(int mode, int board_id) -{ - char **fw = sms_get_board(board_id)->fw; - return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode]; -} - -static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) -{ - const struct firmware *fw; - u8 *fw_buffer; - int rc, dummy; - char *fw_filename; - - if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) { - sms_err("invalid firmware id specified %d", id); - return -EINVAL; - } - - fw_filename = sms_get_fw_name(id, board_id); - - rc = request_firmware(&fw, fw_filename, &udev->dev); - if (rc < 0) { - sms_warn("failed to open \"%s\" mode %d, " - "trying again with default firmware", fw_filename, id); - - fw_filename = smsusb1_fw_lkup[id]; - rc = request_firmware(&fw, fw_filename, &udev->dev); - if (rc < 0) { - sms_warn("failed to open \"%s\" mode %d", - fw_filename, id); - - return rc; - } - } - - fw_buffer = kmalloc(fw->size, GFP_KERNEL); - if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); - - rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), - fw_buffer, fw->size, &dummy, 1000); - - sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc); - - kfree(fw_buffer); - } else { - sms_err("failed to allocate firmware buffer"); - rc = -ENOMEM; - } - sms_info("read FW %s, size=%zd", fw_filename, fw->size); - - release_firmware(fw); - - return rc; -} - -static void smsusb1_detectmode(void *context, int *mode) -{ - char *product_string = - ((struct smsusb_device_t *) context)->udev->product; - - *mode = DEVICE_MODE_NONE; - - if (!product_string) { - product_string = "none"; - sms_err("product string not found"); - } else if (strstr(product_string, "DVBH")) - *mode = 1; - else if (strstr(product_string, "BDA")) - *mode = 4; - else if (strstr(product_string, "DVBT")) - *mode = 0; - else if (strstr(product_string, "TDMB")) - *mode = 2; - - sms_info("%d \"%s\"", *mode, product_string); -} - -static int smsusb1_setmode(void *context, int mode) -{ - struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, - sizeof(struct SmsMsgHdr_ST), 0 }; - - if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { - sms_err("invalid firmware id specified %d", mode); - return -EINVAL; - } - - return smsusb_sendrequest(context, &Msg, sizeof(Msg)); -} - -static void smsusb_term_device(struct usb_interface *intf) -{ - struct smsusb_device_t *dev = usb_get_intfdata(intf); - - if (dev) { - smsusb_stop_streaming(dev); - - /* unregister from smscore */ - if (dev->coredev) - smscore_unregister_device(dev->coredev); - - kfree(dev); - - sms_info("device %p destroyed", dev); - } - - usb_set_intfdata(intf, NULL); -} - -static int smsusb_init_device(struct usb_interface *intf, int board_id) -{ - struct smsdevice_params_t params; - struct smsusb_device_t *dev; - int i, rc; - - /* create device object */ - dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL); - if (!dev) { - sms_err("kzalloc(sizeof(struct smsusb_device_t) failed"); - return -ENOMEM; - } - - memset(¶ms, 0, sizeof(params)); - usb_set_intfdata(intf, dev); - dev->udev = interface_to_usbdev(intf); - - params.device_type = sms_get_board(board_id)->type; - - switch (params.device_type) { - case SMS_STELLAR: - dev->buffer_size = USB1_BUFFER_SIZE; - - params.setmode_handler = smsusb1_setmode; - params.detectmode_handler = smsusb1_detectmode; - break; - default: - sms_err("Unspecified sms device type!"); - /* fall-thru */ - case SMS_NOVA_A0: - case SMS_NOVA_B0: - case SMS_VEGA: - dev->buffer_size = USB2_BUFFER_SIZE; - dev->response_alignment = - le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - - sizeof(struct SmsMsgHdr_ST); - - params.flags |= SMS_DEVICE_FAMILY2; - break; - } - - params.device = &dev->udev->dev; - params.buffer_size = dev->buffer_size; - params.num_buffers = MAX_BUFFERS; - params.sendrequest_handler = smsusb_sendrequest; - params.context = dev; - usb_make_path(dev->udev, params.devpath, sizeof(params.devpath)); - - /* register in smscore */ - rc = smscore_register_device(¶ms, &dev->coredev); - if (rc < 0) { - sms_err("smscore_register_device(...) failed, rc %d", rc); - smsusb_term_device(intf); - return rc; - } - - smscore_set_board_id(dev->coredev, board_id); - - /* initialize urbs */ - for (i = 0; i < MAX_URBS; i++) { - dev->surbs[i].dev = dev; - usb_init_urb(&dev->surbs[i].urb); - } - - sms_info("smsusb_start_streaming(...)."); - rc = smsusb_start_streaming(dev); - if (rc < 0) { - sms_err("smsusb_start_streaming(...) failed"); - smsusb_term_device(intf); - return rc; - } - - rc = smscore_start_device(dev->coredev); - if (rc < 0) { - sms_err("smscore_start_device(...) failed"); - smsusb_term_device(intf); - return rc; - } - - sms_info("device %p created", dev); - - return rc; -} - -static int __devinit smsusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - char devpath[32]; - int i, rc; - - rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); - rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); - - if (intf->num_altsetting > 0) { - rc = usb_set_interface( - udev, intf->cur_altsetting->desc.bInterfaceNumber, 0); - if (rc < 0) { - sms_err("usb_set_interface failed, rc %d", rc); - return rc; - } - } - - sms_info("smsusb_probe %d", - intf->cur_altsetting->desc.bInterfaceNumber); - for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) - sms_info("endpoint %d %02x %02x %d", i, - intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, - intf->cur_altsetting->endpoint[i].desc.bmAttributes, - intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); - - if ((udev->actconfig->desc.bNumInterfaces == 2) && - (intf->cur_altsetting->desc.bInterfaceNumber == 0)) { - sms_err("rom interface 0 is not used"); - return -ENODEV; - } - - if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { - snprintf(devpath, sizeof(devpath), "usb\\%d-%s", - udev->bus->busnum, udev->devpath); - sms_info("stellar device was found."); - return smsusb1_load_firmware( - udev, smscore_registry_getmode(devpath), - id->driver_info); - } - - rc = smsusb_init_device(intf, id->driver_info); - sms_info("rc %d", rc); - sms_board_load_modules(id->driver_info); - return rc; -} - -static void smsusb_disconnect(struct usb_interface *intf) -{ - smsusb_term_device(intf); -} - -static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg) -{ - struct smsusb_device_t *dev = usb_get_intfdata(intf); - printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event); - smsusb_stop_streaming(dev); - return 0; -} - -static int smsusb_resume(struct usb_interface *intf) -{ - int rc, i; - struct smsusb_device_t *dev = usb_get_intfdata(intf); - struct usb_device *udev = interface_to_usbdev(intf); - - printk(KERN_INFO "%s: Entering.\n", __func__); - usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); - usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); - - for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) - printk(KERN_INFO "endpoint %d %02x %02x %d\n", i, - intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, - intf->cur_altsetting->endpoint[i].desc.bmAttributes, - intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); - - if (intf->num_altsetting > 0) { - rc = usb_set_interface(udev, - intf->cur_altsetting->desc. - bInterfaceNumber, 0); - if (rc < 0) { - printk(KERN_INFO "%s usb_set_interface failed, " - "rc %d\n", __func__, rc); - return rc; - } - } - - smsusb_start_streaming(dev); - return 0; -} - -static const struct usb_device_id smsusb_id_table[] __devinitconst = { - { USB_DEVICE(0x187f, 0x0010), - .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, - { USB_DEVICE(0x187f, 0x0100), - .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, - { USB_DEVICE(0x187f, 0x0200), - .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A }, - { USB_DEVICE(0x187f, 0x0201), - .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B }, - { USB_DEVICE(0x187f, 0x0300), - .driver_info = SMS1XXX_BOARD_SIANO_VEGA }, - { USB_DEVICE(0x2040, 0x1700), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT }, - { USB_DEVICE(0x2040, 0x1800), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A }, - { USB_DEVICE(0x2040, 0x1801), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B }, - { USB_DEVICE(0x2040, 0x2000), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x2009), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 }, - { USB_DEVICE(0x2040, 0x200a), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x2010), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x2011), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x2019), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, - { USB_DEVICE(0x2040, 0x5500), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5510), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5520), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5530), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5580), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5590), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x187f, 0x0202), - .driver_info = SMS1XXX_BOARD_SIANO_NICE }, - { USB_DEVICE(0x187f, 0x0301), - .driver_info = SMS1XXX_BOARD_SIANO_VENICE }, - { USB_DEVICE(0x2040, 0xb900), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xb910), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xb980), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xb990), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc000), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc010), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc080), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc090), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { } /* Terminating entry */ - }; - -MODULE_DEVICE_TABLE(usb, smsusb_id_table); - -static struct usb_driver smsusb_driver = { - .name = "smsusb", - .probe = smsusb_probe, - .disconnect = smsusb_disconnect, - .id_table = smsusb_id_table, - - .suspend = smsusb_suspend, - .resume = smsusb_resume, -}; - -static int __init smsusb_module_init(void) -{ - int rc = usb_register(&smsusb_driver); - if (rc) - sms_err("usb_register failed. Error number %d", rc); - - sms_debug(""); - - return rc; -} - -static void __exit smsusb_module_exit(void) -{ - /* Regular USB Cleanup */ - usb_deregister(&smsusb_driver); - sms_info("end"); -} - -module_init(smsusb_module_init); -module_exit(smsusb_module_exit); - -MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle"); -MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_av.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_av.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_av.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_av.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1626 +0,0 @@ -/* - * av7110_av.c: audio and video MPEG decoder stuff - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" -#include "av7110_av.h" -#include "av7110_ipack.h" - -/* MPEG-2 (ISO 13818 / H.222.0) stream types */ -#define PROG_STREAM_MAP 0xBC -#define PRIVATE_STREAM1 0xBD -#define PADDING_STREAM 0xBE -#define PRIVATE_STREAM2 0xBF -#define AUDIO_STREAM_S 0xC0 -#define AUDIO_STREAM_E 0xDF -#define VIDEO_STREAM_S 0xE0 -#define VIDEO_STREAM_E 0xEF -#define ECM_STREAM 0xF0 -#define EMM_STREAM 0xF1 -#define DSM_CC_STREAM 0xF2 -#define ISO13522_STREAM 0xF3 -#define PROG_STREAM_DIR 0xFF - -#define PTS_DTS_FLAGS 0xC0 - -//pts_dts flags -#define PTS_ONLY 0x80 -#define PTS_DTS 0xC0 -#define TS_SIZE 188 -#define TRANS_ERROR 0x80 -#define PAY_START 0x40 -#define TRANS_PRIO 0x20 -#define PID_MASK_HI 0x1F -//flags -#define TRANS_SCRMBL1 0x80 -#define TRANS_SCRMBL2 0x40 -#define ADAPT_FIELD 0x20 -#define PAYLOAD 0x10 -#define COUNT_MASK 0x0F - -// adaptation flags -#define DISCON_IND 0x80 -#define RAND_ACC_IND 0x40 -#define ES_PRI_IND 0x20 -#define PCR_FLAG 0x10 -#define OPCR_FLAG 0x08 -#define SPLICE_FLAG 0x04 -#define TRANS_PRIV 0x02 -#define ADAP_EXT_FLAG 0x01 - -// adaptation extension flags -#define LTW_FLAG 0x80 -#define PIECE_RATE 0x40 -#define SEAM_SPLICE 0x20 - - -static void p_to_t(u8 const *buf, long int length, u16 pid, - u8 *counter, struct dvb_demux_feed *feed); -static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len); - - -int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) -{ - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv; - - if (!(dvbdmxfeed->ts_type & TS_PACKET)) - return 0; - if (buf[3] == 0xe0) // video PES do not have a length in TS - buf[4] = buf[5] = 0; - if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) - return dvbdmxfeed->cb.ts(buf, len, NULL, 0, - &dvbdmxfeed->feed.ts, DMX_OK); - else - return dvb_filter_pes2ts(p2t, buf, len, 1); -} - -static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) -{ - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; - - dvbdmxfeed->cb.ts(data, 188, NULL, 0, - &dvbdmxfeed->feed.ts, DMX_OK); - return 0; -} - -int av7110_av_start_record(struct av7110 *av7110, int av, - struct dvb_demux_feed *dvbdmxfeed) -{ - int ret = 0; - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - - dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed); - - if (av7110->playing || (av7110->rec_mode & av)) - return -EBUSY; - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); - dvbdmx->recording = 1; - av7110->rec_mode |= av; - - switch (av7110->rec_mode) { - case RP_AUDIO: - dvb_filter_pes2ts_init(&av7110->p2t[0], - dvbdmx->pesfilter[0]->pid, - dvb_filter_pes2ts_cb, - (void *) dvbdmx->pesfilter[0]); - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); - break; - - case RP_VIDEO: - dvb_filter_pes2ts_init(&av7110->p2t[1], - dvbdmx->pesfilter[1]->pid, - dvb_filter_pes2ts_cb, - (void *) dvbdmx->pesfilter[1]); - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); - break; - - case RP_AV: - dvb_filter_pes2ts_init(&av7110->p2t[0], - dvbdmx->pesfilter[0]->pid, - dvb_filter_pes2ts_cb, - (void *) dvbdmx->pesfilter[0]); - dvb_filter_pes2ts_init(&av7110->p2t[1], - dvbdmx->pesfilter[1]->pid, - dvb_filter_pes2ts_cb, - (void *) dvbdmx->pesfilter[1]); - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); - break; - } - return ret; -} - -int av7110_av_start_play(struct av7110 *av7110, int av) -{ - int ret = 0; - dprintk(2, "av7110:%p, \n", av7110); - - if (av7110->rec_mode) - return -EBUSY; - if (av7110->playing & av) - return -EBUSY; - - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); - - if (av7110->playing == RP_NONE) { - av7110_ipack_reset(&av7110->ipack[0]); - av7110_ipack_reset(&av7110->ipack[1]); - } - - av7110->playing |= av; - switch (av7110->playing) { - case RP_AUDIO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); - break; - case RP_VIDEO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); - av7110->sinfo = 0; - break; - case RP_AV: - av7110->sinfo = 0; - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); - break; - } - return ret; -} - -int av7110_av_stop(struct av7110 *av7110, int av) -{ - int ret = 0; - dprintk(2, "av7110:%p, \n", av7110); - - if (!(av7110->playing & av) && !(av7110->rec_mode & av)) - return 0; - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); - if (av7110->playing) { - av7110->playing &= ~av; - switch (av7110->playing) { - case RP_AUDIO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); - break; - case RP_VIDEO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); - break; - case RP_NONE: - ret = av7110_set_vidmode(av7110, av7110->vidmode); - break; - } - } else { - av7110->rec_mode &= ~av; - switch (av7110->rec_mode) { - case RP_AUDIO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); - break; - case RP_VIDEO: - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); - break; - case RP_NONE: - break; - } - } - return ret; -} - - -int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen) -{ - int len; - u32 sync; - u16 blen; - - if (!dlen) { - wake_up(&buf->queue); - return -1; - } - while (1) { - len = dvb_ringbuffer_avail(buf); - if (len < 6) { - wake_up(&buf->queue); - return -1; - } - sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24; - sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16; - sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8; - sync |= DVB_RINGBUFFER_PEEK(buf, 3); - - if (((sync &~ 0x0f) == 0x000001e0) || - ((sync &~ 0x1f) == 0x000001c0) || - (sync == 0x000001bd)) - break; - printk("resync\n"); - DVB_RINGBUFFER_SKIP(buf, 1); - } - blen = DVB_RINGBUFFER_PEEK(buf, 4) << 8; - blen |= DVB_RINGBUFFER_PEEK(buf, 5); - blen += 6; - if (len < blen || blen > dlen) { - //printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen); - wake_up(&buf->queue); - return -1; - } - - dvb_ringbuffer_read(buf, dest, (size_t) blen); - - dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n", - (unsigned long) buf->pread, (unsigned long) buf->pwrite); - wake_up(&buf->queue); - return blen; -} - - -int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) -{ - int err, vol, val, balance = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - av7110->mixer.volume_left = volleft; - av7110->mixer.volume_right = volright; - - switch (av7110->adac_type) { - case DVB_ADAC_TI: - volleft = (volleft * 256) / 1036; - volright = (volright * 256) / 1036; - if (volleft > 0x3f) - volleft = 0x3f; - if (volright > 0x3f) - volright = 0x3f; - if ((err = SendDAC(av7110, 3, 0x80 + volleft))) - return err; - return SendDAC(av7110, 4, volright); - - case DVB_ADAC_CRYSTAL: - volleft = 127 - volleft / 2; - volright = 127 - volright / 2; - i2c_writereg(av7110, 0x20, 0x03, volleft); - i2c_writereg(av7110, 0x20, 0x04, volright); - return 0; - - case DVB_ADAC_MSP34x0: - vol = (volleft > volright) ? volleft : volright; - val = (vol * 0x73 / 255) << 8; - if (vol > 0) - balance = ((volright - volleft) * 127) / vol; - msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ - msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ - return 0; - - case DVB_ADAC_MSP34x5: - vol = (volleft > volright) ? volleft : volright; - val = (vol * 0x73 / 255) << 8; - if (vol > 0) - balance = ((volright - volleft) * 127) / vol; - msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ - return 0; - } - - return 0; -} - -int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) -{ - int ret; - dprintk(2, "av7110:%p, \n", av7110); - - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); - - if (!ret && !av7110->playing) { - ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], - av7110->pids[DMX_PES_AUDIO], - av7110->pids[DMX_PES_TELETEXT], - 0, av7110->pids[DMX_PES_PCR]); - if (!ret) - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); - } - return ret; -} - - -static enum av7110_video_mode sw2mode[16] = { - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, - AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, -}; - -static int get_video_format(struct av7110 *av7110, u8 *buf, int count) -{ - int i; - int hsize, vsize; - int sw; - u8 *p; - int ret = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - if (av7110->sinfo) - return 0; - for (i = 7; i < count - 10; i++) { - p = buf + i; - if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3) - continue; - p += 4; - hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4); - vsize = ((p[1] &0x0F) << 8) | (p[2]); - sw = (p[3] & 0x0F); - ret = av7110_set_vidmode(av7110, sw2mode[sw]); - if (!ret) { - dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); - av7110->sinfo = 1; - } - break; - } - return ret; -} - - -/**************************************************************************** - * I/O buffer management and control - ****************************************************************************/ - -static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf, - const u8 *buf, unsigned long count) -{ - unsigned long todo = count; - int free; - - while (todo > 0) { - if (dvb_ringbuffer_free(rbuf) < 2048) { - if (wait_event_interruptible(rbuf->queue, - (dvb_ringbuffer_free(rbuf) >= 2048))) - return count - todo; - } - free = dvb_ringbuffer_free(rbuf); - if (free > todo) - free = todo; - dvb_ringbuffer_write(rbuf, buf, free); - todo -= free; - buf += free; - } - - return count - todo; -} - -static void play_video_cb(u8 *buf, int count, void *priv) -{ - struct av7110 *av7110 = (struct av7110 *) priv; - dprintk(2, "av7110:%p, \n", av7110); - - if ((buf[3] & 0xe0) == 0xe0) { - get_video_format(av7110, buf, count); - aux_ring_buffer_write(&av7110->avout, buf, count); - } else - aux_ring_buffer_write(&av7110->aout, buf, count); -} - -static void play_audio_cb(u8 *buf, int count, void *priv) -{ - struct av7110 *av7110 = (struct av7110 *) priv; - dprintk(2, "av7110:%p, \n", av7110); - - aux_ring_buffer_write(&av7110->aout, buf, count); -} - - -#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096) - -static ssize_t ts_play(struct av7110 *av7110, const char __user *buf, - unsigned long count, int nonblock, int type) -{ - struct dvb_ringbuffer *rb; - u8 *kb; - unsigned long todo = count; - - dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count); - - rb = (type) ? &av7110->avout : &av7110->aout; - kb = av7110->kbuf[type]; - - if (!kb) - return -ENOBUFS; - - if (nonblock && !FREE_COND_TS) - return -EWOULDBLOCK; - - while (todo >= TS_SIZE) { - if (!FREE_COND_TS) { - if (nonblock) - return count - todo; - if (wait_event_interruptible(rb->queue, FREE_COND_TS)) - return count - todo; - } - if (copy_from_user(kb, buf, TS_SIZE)) - return -EFAULT; - write_ts_to_decoder(av7110, type, kb, TS_SIZE); - todo -= TS_SIZE; - buf += TS_SIZE; - } - - return count - todo; -} - - -#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ - dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) - -static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf, - unsigned long count, int nonblock, int type) -{ - unsigned long todo = count, n; - dprintk(2, "av7110:%p, \n", av7110); - - if (!av7110->kbuf[type]) - return -ENOBUFS; - - if (nonblock && !FREE_COND) - return -EWOULDBLOCK; - - while (todo > 0) { - if (!FREE_COND) { - if (nonblock) - return count - todo; - if (wait_event_interruptible(av7110->avout.queue, - FREE_COND)) - return count - todo; - } - n = todo; - if (n > IPACKS * 2) - n = IPACKS * 2; - if (copy_from_user(av7110->kbuf[type], buf, n)) - return -EFAULT; - av7110_ipack_instant_repack(av7110->kbuf[type], n, - &av7110->ipack[type]); - todo -= n; - buf += n; - } - return count - todo; -} - -static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf, - unsigned long count, int nonblock, int type) -{ - unsigned long todo = count, n; - dprintk(2, "av7110:%p, \n", av7110); - - if (!av7110->kbuf[type]) - return -ENOBUFS; - - if (nonblock && !FREE_COND) - return -EWOULDBLOCK; - - while (todo > 0) { - if (!FREE_COND) { - if (nonblock) - return count - todo; - if (wait_event_interruptible(av7110->avout.queue, - FREE_COND)) - return count - todo; - } - n = todo; - if (n > IPACKS * 2) - n = IPACKS * 2; - av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]); - todo -= n; - buf += n; - } - return count - todo; -} - -static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf, - unsigned long count, int nonblock, int type) -{ - unsigned long todo = count, n; - dprintk(2, "av7110:%p, \n", av7110); - - if (!av7110->kbuf[type]) - return -ENOBUFS; - if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) - return -EWOULDBLOCK; - - while (todo > 0) { - if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) { - if (nonblock) - return count - todo; - if (wait_event_interruptible(av7110->aout.queue, - (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024))) - return count-todo; - } - n = todo; - if (n > IPACKS * 2) - n = IPACKS * 2; - if (copy_from_user(av7110->kbuf[type], buf, n)) - return -EFAULT; - av7110_ipack_instant_repack(av7110->kbuf[type], n, - &av7110->ipack[type]); - todo -= n; - buf += n; - } - return count - todo; -} - -void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed) -{ - memset(p->pes, 0, TS_SIZE); - p->counter = 0; - p->pos = 0; - p->frags = 0; - if (feed) - p->feed = feed; -} - -static void clear_p2t(struct av7110_p2t *p) -{ - memset(p->pes, 0, TS_SIZE); -// p->counter = 0; - p->pos = 0; - p->frags = 0; -} - - -static int find_pes_header(u8 const *buf, long int length, int *frags) -{ - int c = 0; - int found = 0; - - *frags = 0; - - while (c < length - 3 && !found) { - if (buf[c] == 0x00 && buf[c + 1] == 0x00 && - buf[c + 2] == 0x01) { - switch ( buf[c + 3] ) { - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - case PRIVATE_STREAM1: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - found = 1; - break; - - default: - c++; - break; - } - } else - c++; - } - if (c == length - 3 && !found) { - if (buf[length - 1] == 0x00) - *frags = 1; - if (buf[length - 2] == 0x00 && - buf[length - 1] == 0x00) - *frags = 2; - if (buf[length - 3] == 0x00 && - buf[length - 2] == 0x00 && - buf[length - 1] == 0x01) - *frags = 3; - return -1; - } - - return c; -} - -void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p) -{ - int c, c2, l, add; - int check, rest; - - c = 0; - c2 = 0; - if (p->frags){ - check = 0; - switch(p->frags) { - case 1: - if (buf[c] == 0x00 && buf[c + 1] == 0x01) { - check = 1; - c += 2; - } - break; - case 2: - if (buf[c] == 0x01) { - check = 1; - c++; - } - break; - case 3: - check = 1; - } - if (check) { - switch (buf[c]) { - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - case PRIVATE_STREAM1: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - p->pes[0] = 0x00; - p->pes[1] = 0x00; - p->pes[2] = 0x01; - p->pes[3] = buf[c]; - p->pos = 4; - memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos); - c += (TS_SIZE - 4) - p->pos; - p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed); - clear_p2t(p); - break; - - default: - c = 0; - break; - } - } - p->frags = 0; - } - - if (p->pos) { - c2 = find_pes_header(buf + c, length - c, &p->frags); - if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos) - l = c2+c; - else - l = (TS_SIZE - 4) - p->pos; - memcpy(p->pes + p->pos, buf, l); - c += l; - p->pos += l; - p_to_t(p->pes, p->pos, pid, &p->counter, p->feed); - clear_p2t(p); - } - - add = 0; - while (c < length) { - c2 = find_pes_header(buf + c + add, length - c - add, &p->frags); - if (c2 >= 0) { - c2 += c + add; - if (c2 > c){ - p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed); - c = c2; - clear_p2t(p); - add = 0; - } else - add = 1; - } else { - l = length - c; - rest = l % (TS_SIZE - 4); - l -= rest; - p_to_t(buf + c, l, pid, &p->counter, p->feed); - memcpy(p->pes, buf + c + l, rest); - p->pos = rest; - c = length; - } - } -} - - -static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length) -{ - int i; - int c = 0; - int fill; - u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 }; - - fill = (TS_SIZE - 4) - length; - if (pes_start) - tshead[1] = 0x40; - if (fill) - tshead[3] = 0x30; - tshead[1] |= (u8)((pid & 0x1F00) >> 8); - tshead[2] |= (u8)(pid & 0x00FF); - tshead[3] |= ((*counter)++ & 0x0F); - memcpy(buf, tshead, 4); - c += 4; - - if (fill) { - buf[4] = fill - 1; - c++; - if (fill > 1) { - buf[5] = 0x00; - c++; - } - for (i = 6; i < fill + 4; i++) { - buf[i] = 0xFF; - c++; - } - } - - return c; -} - - -static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, - struct dvb_demux_feed *feed) -{ - int l, pes_start; - u8 obuf[TS_SIZE]; - long c = 0; - - pes_start = 0; - if (length > 3 && - buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) - switch (buf[3]) { - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - case PRIVATE_STREAM1: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - pes_start = 1; - break; - - default: - break; - } - - while (c < length) { - memset(obuf, 0, TS_SIZE); - if (length - c >= (TS_SIZE - 4)){ - l = write_ts_header2(pid, counter, pes_start, - obuf, (TS_SIZE - 4)); - memcpy(obuf + l, buf + c, TS_SIZE - l); - c += TS_SIZE - l; - } else { - l = write_ts_header2(pid, counter, pes_start, - obuf, length - c); - memcpy(obuf + l, buf + c, TS_SIZE - l); - c = length; - } - feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, DMX_OK); - pes_start = 0; - } -} - - -static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len) -{ - struct ipack *ipack = &av7110->ipack[type]; - - if (buf[1] & TRANS_ERROR) { - av7110_ipack_reset(ipack); - return -1; - } - - if (!(buf[3] & PAYLOAD)) - return -1; - - if (buf[1] & PAY_START) - av7110_ipack_flush(ipack); - - if (buf[3] & ADAPT_FIELD) { - len -= buf[4] + 1; - buf += buf[4] + 1; - if (!len) - return 0; - } - - av7110_ipack_instant_repack(buf + 4, len - 4, ipack); - return 0; -} - - -int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *av7110 = (struct av7110 *) demux->priv; - - dprintk(2, "av7110:%p, \n", av7110); - - if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE) - return 0; - - switch (feed->pes_type) { - case 0: - if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - return -EINVAL; - break; - case 1: - if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) - return -EINVAL; - break; - default: - return -1; - } - - return write_ts_to_decoder(av7110, feed->pes_type, buf, len); -} - - - -/****************************************************************************** - * Video MPEG decoder events - ******************************************************************************/ -void dvb_video_add_event(struct av7110 *av7110, struct video_event *event) -{ - struct dvb_video_events *events = &av7110->video_events; - int wp; - - spin_lock_bh(&events->lock); - - wp = (events->eventw + 1) % MAX_VIDEO_EVENT; - if (wp == events->eventr) { - events->overflow = 1; - events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; - } - - //FIXME: timestamp? - memcpy(&events->events[events->eventw], event, sizeof(struct video_event)); - events->eventw = wp; - - spin_unlock_bh(&events->lock); - - wake_up_interruptible(&events->wait_queue); -} - - -static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags) -{ - struct dvb_video_events *events = &av7110->video_events; - - if (events->overflow) { - events->overflow = 0; - return -EOVERFLOW; - } - if (events->eventw == events->eventr) { - int ret; - - if (flags & O_NONBLOCK) - return -EWOULDBLOCK; - - ret = wait_event_interruptible(events->wait_queue, - events->eventw != events->eventr); - if (ret < 0) - return ret; - } - - spin_lock_bh(&events->lock); - - memcpy(event, &events->events[events->eventr], - sizeof(struct video_event)); - events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; - - spin_unlock_bh(&events->lock); - - return 0; -} - - -/****************************************************************************** - * DVB device file operations - ******************************************************************************/ - -static unsigned int dvb_video_poll(struct file *file, poll_table *wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned int mask = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) - poll_wait(file, &av7110->avout.queue, wait); - - poll_wait(file, &av7110->video_events.wait_queue, wait); - - if (av7110->video_events.eventw != av7110->video_events.eventr) - mask = POLLPRI; - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - if (av7110->playing) { - if (FREE_COND) - mask |= (POLLOUT | POLLWRNORM); - } else /* if not playing: may play if asked for */ - mask |= (POLLOUT | POLLWRNORM); - } - - return mask; -} - -static ssize_t dvb_video_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned char c; - - dprintk(2, "av7110:%p, \n", av7110); - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - return -EPERM; - - if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) - return -EPERM; - - if (get_user(c, buf)) - return -EFAULT; - if (c == 0x47 && count % TS_SIZE == 0) - return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); - else - return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); -} - -static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned int mask = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - poll_wait(file, &av7110->aout.queue, wait); - - if (av7110->playing) { - if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) - mask |= (POLLOUT | POLLWRNORM); - } else /* if not playing: may play if asked for */ - mask = (POLLOUT | POLLWRNORM); - - return mask; -} - -static ssize_t dvb_audio_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned char c; - - dprintk(2, "av7110:%p, \n", av7110); - - if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) { - printk(KERN_ERR "not audio source memory\n"); - return -EPERM; - } - - if (get_user(c, buf)) - return -EFAULT; - if (c == 0x47 && count % TS_SIZE == 0) - return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); - else - return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); -} - -static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; - -#define MIN_IFRAME 400000 - -static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock) -{ - unsigned i, n; - int progressive = 0; - int match = 0; - - dprintk(2, "av7110:%p, \n", av7110); - - if (!(av7110->playing & RP_VIDEO)) { - if (av7110_av_start_play(av7110, RP_VIDEO) < 0) - return -EBUSY; - } - - /* search in buf for instances of 00 00 01 b5 1? */ - for (i = 0; i < len; i++) { - unsigned char c; - if (get_user(c, buf + i)) - return -EFAULT; - if (match == 5) { - progressive = c & 0x08; - match = 0; - } - if (c == 0x00) { - match = (match == 1 || match == 2) ? 2 : 1; - continue; - } - switch (match++) { - case 2: if (c == 0x01) - continue; - break; - case 3: if (c == 0xb5) - continue; - break; - case 4: if ((c & 0xf0) == 0x10) - continue; - break; - } - match = 0; - } - - /* setting n always > 1, fixes problems when playing stillframes - consisting of I- and P-Frames */ - n = MIN_IFRAME / len + 1; - - /* FIXME: nonblock? */ - dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1); - - for (i = 0; i < n; i++) - dvb_play(av7110, buf, len, 0, 1); - - av7110_ipack_flush(&av7110->ipack[1]); - - if (progressive) - return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); - else - return 0; -} - - -static int dvb_video_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned long arg = (unsigned long) parg; - int ret = 0; - - dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT && - cmd != VIDEO_GET_SIZE ) { - return -EPERM; - } - } - - switch (cmd) { - case VIDEO_STOP: - av7110->videostate.play_state = VIDEO_STOPPED; - if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) - ret = av7110_av_stop(av7110, RP_VIDEO); - else - ret = vidcom(av7110, AV_VIDEO_CMD_STOP, - av7110->videostate.video_blank ? 0 : 1); - if (!ret) - av7110->trickmode = TRICK_NONE; - break; - - case VIDEO_PLAY: - av7110->trickmode = TRICK_NONE; - if (av7110->videostate.play_state == VIDEO_FREEZED) { - av7110->videostate.play_state = VIDEO_PLAYING; - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); - if (ret) - break; - } - if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { - if (av7110->playing == RP_AV) { - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); - if (ret) - break; - av7110->playing &= ~RP_VIDEO; - } - ret = av7110_av_start_play(av7110, RP_VIDEO); - } - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); - if (!ret) - av7110->videostate.play_state = VIDEO_PLAYING; - break; - - case VIDEO_FREEZE: - av7110->videostate.play_state = VIDEO_FREEZED; - if (av7110->playing & RP_VIDEO) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); - else - ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); - if (!ret) - av7110->trickmode = TRICK_FREEZE; - break; - - case VIDEO_CONTINUE: - if (av7110->playing & RP_VIDEO) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); - if (!ret) { - av7110->videostate.play_state = VIDEO_PLAYING; - av7110->trickmode = TRICK_NONE; - } - break; - - case VIDEO_SELECT_SOURCE: - av7110->videostate.stream_source = (video_stream_source_t) arg; - break; - - case VIDEO_SET_BLANK: - av7110->videostate.video_blank = (int) arg; - break; - - case VIDEO_GET_STATUS: - memcpy(parg, &av7110->videostate, sizeof(struct video_status)); - break; - - case VIDEO_GET_EVENT: - ret = dvb_video_get_event(av7110, parg, file->f_flags); - break; - - case VIDEO_GET_SIZE: - memcpy(parg, &av7110->video_size, sizeof(video_size_t)); - break; - - case VIDEO_SET_DISPLAY_FORMAT: - { - video_displayformat_t format = (video_displayformat_t) arg; - switch (format) { - case VIDEO_PAN_SCAN: - av7110->display_panscan = VID_PAN_SCAN_PREF; - break; - case VIDEO_LETTER_BOX: - av7110->display_panscan = VID_VC_AND_PS_PREF; - break; - case VIDEO_CENTER_CUT_OUT: - av7110->display_panscan = VID_CENTRE_CUT_PREF; - break; - default: - ret = -EINVAL; - } - if (ret < 0) - break; - av7110->videostate.display_format = format; - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, - 1, av7110->display_panscan); - break; - } - - case VIDEO_SET_FORMAT: - if (arg > 1) { - ret = -EINVAL; - break; - } - av7110->display_ar = arg; - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, - 1, (u16) arg); - break; - - case VIDEO_STILLPICTURE: - { - struct video_still_picture *pic = - (struct video_still_picture *) parg; - av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY; - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - ret = play_iframe(av7110, pic->iFrame, pic->size, - file->f_flags & O_NONBLOCK); - break; - } - - case VIDEO_FAST_FORWARD: - //note: arg is ignored by firmware - if (av7110->playing & RP_VIDEO) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Scan_I, 2, AV_PES, 0); - else - ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg); - if (!ret) { - av7110->trickmode = TRICK_FAST; - av7110->videostate.play_state = VIDEO_PLAYING; - } - break; - - case VIDEO_SLOWMOTION: - if (av7110->playing&RP_VIDEO) { - if (av7110->trickmode != TRICK_SLOW) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); - } else { - ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); - } - if (!ret) { - av7110->trickmode = TRICK_SLOW; - av7110->videostate.play_state = VIDEO_PLAYING; - } - break; - - case VIDEO_GET_CAPABILITIES: - *(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 | - VIDEO_CAP_SYS | VIDEO_CAP_PROG; - break; - - case VIDEO_CLEAR_BUFFER: - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - av7110_ipack_reset(&av7110->ipack[1]); - if (av7110->playing == RP_AV) { - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Play, 2, AV_PES, 0); - if (ret) - break; - if (av7110->trickmode == TRICK_FAST) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Scan_I, 2, AV_PES, 0); - if (av7110->trickmode == TRICK_SLOW) { - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Slow, 2, 0, 0); - if (!ret) - ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); - } - if (av7110->trickmode == TRICK_FREEZE) - ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1); - } - break; - - case VIDEO_SET_STREAMTYPE: - break; - - default: - ret = -ENOIOCTLCMD; - break; - } - - return ret; -} - -static int dvb_audio_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned long arg = (unsigned long) parg; - int ret = 0; - - dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); - - if (((file->f_flags & O_ACCMODE) == O_RDONLY) && - (cmd != AUDIO_GET_STATUS)) - return -EPERM; - - switch (cmd) { - case AUDIO_STOP: - if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - ret = av7110_av_stop(av7110, RP_AUDIO); - else - ret = audcom(av7110, AUDIO_CMD_MUTE); - if (!ret) - av7110->audiostate.play_state = AUDIO_STOPPED; - break; - - case AUDIO_PLAY: - if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - ret = av7110_av_start_play(av7110, RP_AUDIO); - if (!ret) - ret = audcom(av7110, AUDIO_CMD_UNMUTE); - if (!ret) - av7110->audiostate.play_state = AUDIO_PLAYING; - break; - - case AUDIO_PAUSE: - ret = audcom(av7110, AUDIO_CMD_MUTE); - if (!ret) - av7110->audiostate.play_state = AUDIO_PAUSED; - break; - - case AUDIO_CONTINUE: - if (av7110->audiostate.play_state == AUDIO_PAUSED) { - av7110->audiostate.play_state = AUDIO_PLAYING; - ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); - } - break; - - case AUDIO_SELECT_SOURCE: - av7110->audiostate.stream_source = (audio_stream_source_t) arg; - break; - - case AUDIO_SET_MUTE: - { - ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); - if (!ret) - av7110->audiostate.mute_state = (int) arg; - break; - } - - case AUDIO_SET_AV_SYNC: - av7110->audiostate.AV_sync_state = (int) arg; - ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); - break; - - case AUDIO_SET_BYPASS_MODE: - if (FW_VERSION(av7110->arm_app) < 0x2621) - ret = -EINVAL; - av7110->audiostate.bypass_mode = (int)arg; - break; - - case AUDIO_CHANNEL_SELECT: - av7110->audiostate.channel_select = (audio_channel_select_t) arg; - switch(av7110->audiostate.channel_select) { - case AUDIO_STEREO: - ret = audcom(av7110, AUDIO_CMD_STEREO); - if (!ret) { - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x49); - else if (av7110->adac_type == DVB_ADAC_MSP34x5) - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); - } - break; - case AUDIO_MONO_LEFT: - ret = audcom(av7110, AUDIO_CMD_MONO_L); - if (!ret) { - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x4a); - else if (av7110->adac_type == DVB_ADAC_MSP34x5) - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); - } - break; - case AUDIO_MONO_RIGHT: - ret = audcom(av7110, AUDIO_CMD_MONO_R); - if (!ret) { - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x45); - else if (av7110->adac_type == DVB_ADAC_MSP34x5) - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); - } - break; - default: - ret = -EINVAL; - break; - } - break; - - case AUDIO_GET_STATUS: - memcpy(parg, &av7110->audiostate, sizeof(struct audio_status)); - break; - - case AUDIO_GET_CAPABILITIES: - if (FW_VERSION(av7110->arm_app) < 0x2621) - *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; - else - *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 | - AUDIO_CAP_MP1 | AUDIO_CAP_MP2; - break; - - case AUDIO_CLEAR_BUFFER: - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - av7110_ipack_reset(&av7110->ipack[0]); - if (av7110->playing == RP_AV) - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Play, 2, AV_PES, 0); - break; - - case AUDIO_SET_ID: - break; - - case AUDIO_SET_MIXER: - { - struct audio_mixer *amix = (struct audio_mixer *)parg; - ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right); - break; - } - - case AUDIO_SET_STREAMTYPE: - break; - - default: - ret = -ENOIOCTLCMD; - } - - return ret; -} - - -static int dvb_video_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - int err; - - dprintk(2, "av7110:%p, \n", av7110); - - if ((err = dvb_generic_open(inode, file)) < 0) - return err; - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - av7110->video_blank = 1; - av7110->audiostate.AV_sync_state = 1; - av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; - - /* empty event queue */ - av7110->video_events.eventr = av7110->video_events.eventw = 0; - } - - return 0; -} - -static int dvb_video_release(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(2, "av7110:%p, \n", av7110); - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - av7110_av_stop(av7110, RP_VIDEO); - } - - return dvb_generic_release(inode, file); -} - -static int dvb_audio_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - int err = dvb_generic_open(inode, file); - - dprintk(2, "av7110:%p, \n", av7110); - - if (err < 0) - return err; - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; - return 0; -} - -static int dvb_audio_release(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(2, "av7110:%p, \n", av7110); - - av7110_av_stop(av7110, RP_AUDIO); - return dvb_generic_release(inode, file); -} - - - -/****************************************************************************** - * driver registration - ******************************************************************************/ - -static const struct file_operations dvb_video_fops = { - .owner = THIS_MODULE, - .write = dvb_video_write, - .unlocked_ioctl = dvb_generic_ioctl, - .open = dvb_video_open, - .release = dvb_video_release, - .poll = dvb_video_poll, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_video = { - .priv = NULL, - .users = 6, - .readers = 5, /* arbitrary */ - .writers = 1, - .fops = &dvb_video_fops, - .kernel_ioctl = dvb_video_ioctl, -}; - -static const struct file_operations dvb_audio_fops = { - .owner = THIS_MODULE, - .write = dvb_audio_write, - .unlocked_ioctl = dvb_generic_ioctl, - .open = dvb_audio_open, - .release = dvb_audio_release, - .poll = dvb_audio_poll, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_audio = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_audio_fops, - .kernel_ioctl = dvb_audio_ioctl, -}; - - -int av7110_av_register(struct av7110 *av7110) -{ - av7110->audiostate.AV_sync_state = 0; - av7110->audiostate.mute_state = 0; - av7110->audiostate.play_state = AUDIO_STOPPED; - av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; - av7110->audiostate.channel_select = AUDIO_STEREO; - av7110->audiostate.bypass_mode = 0; - - av7110->videostate.video_blank = 0; - av7110->videostate.play_state = VIDEO_STOPPED; - av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; - av7110->videostate.video_format = VIDEO_FORMAT_4_3; - av7110->videostate.display_format = VIDEO_LETTER_BOX; - av7110->display_ar = VIDEO_FORMAT_4_3; - av7110->display_panscan = VID_VC_AND_PS_PREF; - - init_waitqueue_head(&av7110->video_events.wait_queue); - spin_lock_init(&av7110->video_events.lock); - av7110->video_events.eventw = av7110->video_events.eventr = 0; - av7110->video_events.overflow = 0; - memset(&av7110->video_size, 0, sizeof (video_size_t)); - - dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev, - &dvbdev_video, av7110, DVB_DEVICE_VIDEO); - - dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev, - &dvbdev_audio, av7110, DVB_DEVICE_AUDIO); - - return 0; -} - -void av7110_av_unregister(struct av7110 *av7110) -{ - dvb_unregister_device(av7110->audio_dev); - dvb_unregister_device(av7110->video_dev); -} - -int av7110_av_init(struct av7110 *av7110) -{ - void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb }; - int i, ret; - - for (i = 0; i < 2; i++) { - struct ipack *ipack = av7110->ipack + i; - - ret = av7110_ipack_init(ipack, IPACKS, play[i]); - if (ret < 0) { - if (i) - av7110_ipack_free(--ipack); - goto out; - } - ipack->data = av7110; - } - - dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN); - dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN); - - av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN); - av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS; -out: - return ret; -} - -void av7110_av_exit(struct av7110 *av7110) -{ - av7110_ipack_free(&av7110->ipack[0]); - av7110_ipack_free(&av7110->ipack[1]); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_av.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_av.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_av.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_av.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -#ifndef _AV7110_AV_H_ -#define _AV7110_AV_H_ - -struct av7110; - -extern int av7110_set_vidmode(struct av7110 *av7110, - enum av7110_video_mode mode); - -extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); -extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); -extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len); - -extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright); -extern int av7110_av_stop(struct av7110 *av7110, int av); -extern int av7110_av_start_record(struct av7110 *av7110, int av, - struct dvb_demux_feed *dvbdmxfeed); -extern int av7110_av_start_play(struct av7110 *av7110, int av); - -extern void dvb_video_add_event(struct av7110 *av7110, struct video_event *event); - -extern void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed); -extern void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p); - -extern int av7110_av_register(struct av7110 *av7110); -extern void av7110_av_unregister(struct av7110 *av7110); -extern int av7110_av_init(struct av7110 *av7110); -extern void av7110_av_exit(struct av7110 *av7110); - - -#endif /* _AV7110_AV_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2920 +0,0 @@ -/* - * driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB) - * av7110.c: initialization and demux stuff - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "dvb_frontend.h" - -#include "ttpci-eeprom.h" -#include "av7110.h" -#include "av7110_hw.h" -#include "av7110_av.h" -#include "av7110_ca.h" -#include "av7110_ipack.h" - -#include "bsbe1.h" -#include "lnbp21.h" -#include "bsru6.h" - -#define TS_WIDTH 376 -#define TS_HEIGHT 512 -#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT) -#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE) - - -int av7110_debug; - -static int vidmode = CVBS_RGB_OUT; -static int pids_off; -static int adac = DVB_ADAC_TI; -static int hw_sections; -static int rgb_on; -static int volume = 255; -static int budgetpatch; -static int wss_cfg_4_3 = 0x4008; -static int wss_cfg_16_9 = 0x0007; -static int tv_standard; -static int full_ts; - -module_param_named(debug, av7110_debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); -module_param(vidmode, int, 0444); -MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC"); -module_param(pids_off, int, 0444); -MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed"); -module_param(adac, int, 0444); -MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)"); -module_param(hw_sections, int, 0444); -MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware"); -module_param(rgb_on, int, 0444); -MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control" - " signal on SCART pin 16 to switch SCART video mode from CVBS to RGB"); -module_param(volume, int, 0444); -MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); -module_param(budgetpatch, int, 0444); -MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); -module_param(full_ts, int, 0444); -MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable"); -module_param(wss_cfg_4_3, int, 0444); -MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); -module_param(wss_cfg_16_9, int, 0444); -MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data"); -module_param(tv_standard, int, 0444); -MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static void restart_feeds(struct av7110 *av7110); -static int budget_start_feed(struct dvb_demux_feed *feed); -static int budget_stop_feed(struct dvb_demux_feed *feed); - -static int av7110_num; - -#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \ -{\ - if (fe_func != NULL) { \ - av7110_copy = fe_func; \ - fe_func = av7110_func; \ - } \ -} - - -static void init_av7110_av(struct av7110 *av7110) -{ - int ret; - struct saa7146_dev *dev = av7110->dev; - - /* set internal volume control to maximum */ - av7110->adac_type = DVB_ADAC_TI; - ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - if (ret < 0) - printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret); - - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, - 1, (u16) av7110->display_ar); - if (ret < 0) - printk("dvb-ttpci: unable to set aspect ratio\n"); - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, - 1, av7110->display_panscan); - if (ret < 0) - printk("dvb-ttpci: unable to set pan scan\n"); - - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3); - if (ret < 0) - printk("dvb-ttpci: unable to configure 4:3 wss\n"); - ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9); - if (ret < 0) - printk("dvb-ttpci: unable to configure 16:9 wss\n"); - - ret = av7710_set_video_mode(av7110, vidmode); - if (ret < 0) - printk("dvb-ttpci:cannot set video mode:%d\n",ret); - - /* handle different card types */ - /* remaining inits according to card and frontend type */ - av7110->analog_tuner_flags = 0; - av7110->current_input = 0; - if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on - if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { - printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_CRYSTAL; - i2c_writereg(av7110, 0x20, 0x01, 0xd2); - i2c_writereg(av7110, 0x20, 0x02, 0x49); - i2c_writereg(av7110, 0x20, 0x03, 0x00); - i2c_writereg(av7110, 0x20, 0x04, 0x00); - - /** - * some special handling for the Siemens DVB-C cards... - */ - } else if (0 == av7110_init_analog_module(av7110)) { - /* done. */ - } - else if (dev->pci->subsystem_vendor == 0x110a) { - printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_NONE; - } - else { - av7110->adac_type = adac; - printk("dvb-ttpci: adac type set to %d @ card %d\n", - av7110->adac_type, av7110->dvb_adapter.num); - } - - if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) { - // switch DVB SCART on - ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); - if (ret < 0) - printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret); - ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); - if (ret < 0) - printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); - if (rgb_on && - ((av7110->dev->pci->subsystem_vendor == 0x110a) || - (av7110->dev->pci->subsystem_vendor == 0x13c2)) && - (av7110->dev->pci->subsystem_device == 0x0000)) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16 - //saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8 - } - } - - if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000e) - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, SpdifSwitch, 1, 0); // SPDIF on - - ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - if (ret < 0) - printk("dvb-ttpci:cannot set volume :%d\n",ret); -} - -static void recover_arm(struct av7110 *av7110) -{ - dprintk(4, "%p\n",av7110); - - av7110_bootarm(av7110); - msleep(100); - - init_av7110_av(av7110); - - /* card-specific recovery */ - if (av7110->recover) - av7110->recover(av7110); - - restart_feeds(av7110); - -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_check_ir_config(av7110, true); -#endif -} - -static void av7110_arm_sync(struct av7110 *av7110) -{ - if (av7110->arm_thread) - kthread_stop(av7110->arm_thread); - - av7110->arm_thread = NULL; -} - -static int arm_thread(void *data) -{ - struct av7110 *av7110 = data; - u16 newloops = 0; - int timeout; - - dprintk(4, "%p\n",av7110); - - for (;;) { - timeout = wait_event_interruptible_timeout(av7110->arm_wait, - kthread_should_stop(), 5 * HZ); - - if (-ERESTARTSYS == timeout || kthread_should_stop()) { - /* got signal or told to quit*/ - break; - } - - if (!av7110->arm_ready) - continue; - -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_check_ir_config(av7110, false); -#endif - - if (mutex_lock_interruptible(&av7110->dcomlock)) - break; - newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); - mutex_unlock(&av7110->dcomlock); - - if (newloops == av7110->arm_loops || av7110->arm_errors > 3) { - printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", - av7110->dvb_adapter.num); - - recover_arm(av7110); - - if (mutex_lock_interruptible(&av7110->dcomlock)) - break; - newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1; - mutex_unlock(&av7110->dcomlock); - } - av7110->arm_loops = newloops; - av7110->arm_errors = 0; - } - - return 0; -} - - -/**************************************************************************** - * IRQ handling - ****************************************************************************/ - -static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len, - u8 *buffer2, size_t buffer2_len, - struct dvb_demux_filter *dvbdmxfilter, - enum dmx_success success, - struct av7110 *av7110) -{ - if (!dvbdmxfilter->feed->demux->dmx.frontend) - return 0; - if (dvbdmxfilter->feed->demux->dmx.frontend->source == DMX_MEMORY_FE) - return 0; - - switch (dvbdmxfilter->type) { - case DMX_TYPE_SEC: - if ((((buffer1[1] << 8) | buffer1[2]) & 0xfff) + 3 != buffer1_len) - return 0; - if (dvbdmxfilter->doneq) { - struct dmx_section_filter *filter = &dvbdmxfilter->filter; - int i; - u8 xor, neq = 0; - - for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { - xor = filter->filter_value[i] ^ buffer1[i]; - neq |= dvbdmxfilter->maskandnotmode[i] & xor; - } - if (!neq) - return 0; - } - return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len, - buffer2, buffer2_len, - &dvbdmxfilter->filter, - DMX_OK); - case DMX_TYPE_TS: - if (!(dvbdmxfilter->feed->ts_type & TS_PACKET)) - return 0; - if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY) - return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len, - buffer2, buffer2_len, - &dvbdmxfilter->feed->feed.ts, - DMX_OK); - else - av7110_p2t_write(buffer1, buffer1_len, - dvbdmxfilter->feed->pid, - &av7110->p2t_filter[dvbdmxfilter->index]); - default: - return 0; - } -} - - -//#define DEBUG_TIMING -static inline void print_time(char *s) -{ -#ifdef DEBUG_TIMING - struct timeval tv; - do_gettimeofday(&tv); - printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec); -#endif -} - -#define DEBI_READ 0 -#define DEBI_WRITE 1 -static inline void start_debi_dma(struct av7110 *av7110, int dir, - unsigned long addr, unsigned int len) -{ - dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len); - if (saa7146_wait_for_debi_done(av7110->dev, 0)) { - printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); - return; - } - - SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */ - SAA7146_IER_ENABLE(av7110->dev, MASK_19); - if (len < 5) - len = 5; /* we want a real DEBI DMA */ - if (dir == DEBI_WRITE) - iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3); - else - irdebi(av7110, DEBISWAB, addr, 0, len); -} - -static void debiirq(unsigned long cookie) -{ - struct av7110 *av7110 = (struct av7110 *)cookie; - int type = av7110->debitype; - int handle = (type >> 8) & 0x1f; - unsigned int xfer = 0; - - print_time("debi"); - dprintk(4, "type 0x%04x\n", type); - - if (type == -1) { - printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", - jiffies, saa7146_read(av7110->dev, PSR), - saa7146_read(av7110->dev, SSR)); - goto debi_done; - } - av7110->debitype = -1; - - switch (type & 0xff) { - - case DATA_TS_RECORD: - dvb_dmx_swfilter_packets(&av7110->demux, - (const u8 *) av7110->debi_virt, - av7110->debilen / 188); - xfer = RX_BUFF; - break; - - case DATA_PES_RECORD: - if (av7110->demux.recording) - av7110_record_cb(&av7110->p2t[handle], - (u8 *) av7110->debi_virt, - av7110->debilen); - xfer = RX_BUFF; - break; - - case DATA_IPMPE: - case DATA_FSECTION: - case DATA_PIPING: - if (av7110->handle2filter[handle]) - DvbDmxFilterCallback((u8 *)av7110->debi_virt, - av7110->debilen, NULL, 0, - av7110->handle2filter[handle], - DMX_OK, av7110); - xfer = RX_BUFF; - break; - - case DATA_CI_GET: - { - u8 *data = av7110->debi_virt; - - if ((data[0] < 2) && data[2] == 0xff) { - int flags = 0; - if (data[5] > 0) - flags |= CA_CI_MODULE_PRESENT; - if (data[5] > 5) - flags |= CA_CI_MODULE_READY; - av7110->ci_slot[data[0]].flags = flags; - } else - ci_get_data(&av7110->ci_rbuffer, - av7110->debi_virt, - av7110->debilen); - xfer = RX_BUFF; - break; - } - - case DATA_COMMON_INTERFACE: - CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen); -#if 0 - { - int i; - - printk("av7110%d: ", av7110->num); - printk("%02x ", *(u8 *)av7110->debi_virt); - printk("%02x ", *(1+(u8 *)av7110->debi_virt)); - for (i = 2; i < av7110->debilen; i++) - printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt))); - for (i = 2; i < av7110->debilen; i++) - printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt))); - - printk("\n"); - } -#endif - xfer = RX_BUFF; - break; - - case DATA_DEBUG_MESSAGE: - ((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0; - printk("%s\n", (s8 *) av7110->debi_virt); - xfer = RX_BUFF; - break; - - case DATA_CI_PUT: - dprintk(4, "debi DATA_CI_PUT\n"); - case DATA_MPEG_PLAY: - dprintk(4, "debi DATA_MPEG_PLAY\n"); - case DATA_BMP_LOAD: - dprintk(4, "debi DATA_BMP_LOAD\n"); - xfer = TX_BUFF; - break; - default: - break; - } -debi_done: - spin_lock(&av7110->debilock); - if (xfer) - iwdebi(av7110, DEBINOSWAP, xfer, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); -} - -/* irq from av7110 firmware writing the mailbox register in the DPRAM */ -static void gpioirq(unsigned long cookie) -{ - struct av7110 *av7110 = (struct av7110 *)cookie; - u32 rxbuf, txbuf; - int len; - - if (av7110->debitype != -1) - /* we shouldn't get any irq while a debi xfer is running */ - printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", - jiffies, saa7146_read(av7110->dev, PSR), - saa7146_read(av7110->dev, SSR)); - - if (saa7146_wait_for_debi_done(av7110->dev, 0)) { - printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); - BUG(); /* maybe we should try resetting the debi? */ - } - - spin_lock(&av7110->debilock); - ARM_ClearIrq(av7110); - - /* see what the av7110 wants */ - av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2); - av7110->debilen = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - len = (av7110->debilen + 3) & ~3; - - print_time("gpio"); - dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen); - - switch (av7110->debitype & 0xff) { - - case DATA_TS_PLAY: - case DATA_PES_PLAY: - break; - - case DATA_MPEG_VIDEO_EVENT: - { - u32 h_ar; - struct video_event event; - - av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2); - h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2); - - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - - av7110->video_size.h = h_ar & 0xfff; - - event.type = VIDEO_EVENT_SIZE_CHANGED; - event.u.size.w = av7110->video_size.w; - event.u.size.h = av7110->video_size.h; - switch ((h_ar >> 12) & 0xf) - { - case 3: - av7110->video_size.aspect_ratio = VIDEO_FORMAT_16_9; - event.u.size.aspect_ratio = VIDEO_FORMAT_16_9; - av7110->videostate.video_format = VIDEO_FORMAT_16_9; - break; - case 4: - av7110->video_size.aspect_ratio = VIDEO_FORMAT_221_1; - event.u.size.aspect_ratio = VIDEO_FORMAT_221_1; - av7110->videostate.video_format = VIDEO_FORMAT_221_1; - break; - default: - av7110->video_size.aspect_ratio = VIDEO_FORMAT_4_3; - event.u.size.aspect_ratio = VIDEO_FORMAT_4_3; - av7110->videostate.video_format = VIDEO_FORMAT_4_3; - } - - dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n", - av7110->video_size.w, av7110->video_size.h, - av7110->video_size.aspect_ratio); - - dvb_video_add_event(av7110, &event); - break; - } - - case DATA_CI_PUT: - { - int avail; - struct dvb_ringbuffer *cibuf = &av7110->ci_wbuffer; - - avail = dvb_ringbuffer_avail(cibuf); - if (avail <= 2) { - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - break; - } - len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; - len |= DVB_RINGBUFFER_PEEK(cibuf, 1); - if (avail < len + 2) { - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - break; - } - DVB_RINGBUFFER_SKIP(cibuf, 2); - - dvb_ringbuffer_read(cibuf, av7110->debi_virt, len); - - iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - dprintk(8, "DMA: CI\n"); - start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); - spin_unlock(&av7110->debilock); - wake_up(&cibuf->queue); - return; - } - - case DATA_MPEG_PLAY: - if (!av7110->playing) { - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - break; - } - len = 0; - if (av7110->debitype & 0x100) { - spin_lock(&av7110->aout.lock); - len = av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048); - spin_unlock(&av7110->aout.lock); - } - if (len <= 0 && (av7110->debitype & 0x200) - &&av7110->videostate.play_state != VIDEO_FREEZED) { - spin_lock(&av7110->avout.lock); - len = av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048); - spin_unlock(&av7110->avout.lock); - } - if (len <= 0) { - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - break; - } - dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len); - iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - dprintk(8, "DMA: MPEG_PLAY\n"); - start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); - spin_unlock(&av7110->debilock); - return; - - case DATA_BMP_LOAD: - len = av7110->debilen; - dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len); - if (!len) { - av7110->bmp_state = BMP_LOADED; - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - wake_up(&av7110->bmpq); - dprintk(8, "gpio DATA_BMP_LOAD done\n"); - break; - } - if (len > av7110->bmplen) - len = av7110->bmplen; - if (len > 2 * 1024) - len = 2 * 1024; - iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); - iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len); - av7110->bmpp += len; - av7110->bmplen -= len; - dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len); - start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len); - spin_unlock(&av7110->debilock); - return; - - case DATA_CI_GET: - case DATA_COMMON_INTERFACE: - case DATA_FSECTION: - case DATA_IPMPE: - case DATA_PIPING: - if (!len || len > 4 * 1024) { - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - break; - } - /* fall through */ - - case DATA_TS_RECORD: - case DATA_PES_RECORD: - dprintk(8, "DMA: TS_REC etc.\n"); - start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len); - spin_unlock(&av7110->debilock); - return; - - case DATA_DEBUG_MESSAGE: - if (!len || len > 0xff) { - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - break; - } - start_debi_dma(av7110, DEBI_READ, Reserved, len); - spin_unlock(&av7110->debilock); - return; - - case DATA_IRCOMMAND: - if (av7110->ir.ir_handler) - av7110->ir.ir_handler(av7110, - swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - break; - - default: - printk("dvb-ttpci: gpioirq unknown type=%d len=%d\n", - av7110->debitype, av7110->debilen); - break; - } - av7110->debitype = -1; - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); -} - - -#ifdef CONFIG_DVB_AV7110_OSD -static int dvb_osd_ioctl(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(4, "%p\n", av7110); - - if (cmd == OSD_SEND_CMD) - return av7110_osd_cmd(av7110, (osd_cmd_t *) parg); - if (cmd == OSD_GET_CAPABILITY) - return av7110_osd_capability(av7110, (osd_cap_t *) parg); - - return -EINVAL; -} - - -static const struct file_operations dvb_osd_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = dvb_generic_ioctl, - .open = dvb_generic_open, - .release = dvb_generic_release, - .llseek = noop_llseek, -}; - -static struct dvb_device dvbdev_osd = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_osd_fops, - .kernel_ioctl = dvb_osd_ioctl, -}; -#endif /* CONFIG_DVB_AV7110_OSD */ - - -static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, - u16 subpid, u16 pcrpid) -{ - u16 aflags = 0; - - dprintk(4, "%p\n", av7110); - - if (vpid == 0x1fff || apid == 0x1fff || - ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) { - vpid = apid = ttpid = subpid = pcrpid = 0; - av7110->pids[DMX_PES_VIDEO] = 0; - av7110->pids[DMX_PES_AUDIO] = 0; - av7110->pids[DMX_PES_TELETEXT] = 0; - av7110->pids[DMX_PES_PCR] = 0; - } - - if (av7110->audiostate.bypass_mode) - aflags |= 0x8000; - - return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6, - pcrpid, vpid, apid, ttpid, subpid, aflags); -} - -int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, - u16 subpid, u16 pcrpid) -{ - int ret = 0; - dprintk(4, "%p\n", av7110); - - if (mutex_lock_interruptible(&av7110->pid_mutex)) - return -ERESTARTSYS; - - if (!(vpid & 0x8000)) - av7110->pids[DMX_PES_VIDEO] = vpid; - if (!(apid & 0x8000)) - av7110->pids[DMX_PES_AUDIO] = apid; - if (!(ttpid & 0x8000)) - av7110->pids[DMX_PES_TELETEXT] = ttpid; - if (!(pcrpid & 0x8000)) - av7110->pids[DMX_PES_PCR] = pcrpid; - - av7110->pids[DMX_PES_SUBTITLE] = 0; - - if (av7110->fe_synced) { - pcrpid = av7110->pids[DMX_PES_PCR]; - ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); - } - - mutex_unlock(&av7110->pid_mutex); - return ret; -} - - -/****************************************************************************** - * hardware filter functions - ******************************************************************************/ - -static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) -{ - struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed; - struct av7110 *av7110 = dvbdmxfeed->demux->priv; - u16 buf[20]; - int ret, i; - u16 handle; -// u16 mode = 0x0320; - u16 mode = 0xb96a; - - dprintk(4, "%p\n", av7110); - - if (av7110->full_ts) - return 0; - - if (dvbdmxfilter->type == DMX_TYPE_SEC) { - if (hw_sections) { - buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | - dvbdmxfilter->maskandmode[0]; - for (i = 3; i < 18; i++) - buf[i + 4 - 2] = - (dvbdmxfilter->filter.filter_value[i] << 8) | - dvbdmxfilter->maskandmode[i]; - mode = 4; - } - } else if ((dvbdmxfeed->ts_type & TS_PACKET) && - !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) { - av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed); - } - - buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter; - buf[1] = 16; - buf[2] = dvbdmxfeed->pid; - buf[3] = mode; - - ret = av7110_fw_request(av7110, buf, 20, &handle, 1); - if (ret != 0 || handle >= 32) { - printk("dvb-ttpci: %s error buf %04x %04x %04x %04x " - "ret %d handle %04x\n", - __func__, buf[0], buf[1], buf[2], buf[3], - ret, handle); - dvbdmxfilter->hw_handle = 0xffff; - if (!ret) - ret = -1; - return ret; - } - - av7110->handle2filter[handle] = dvbdmxfilter; - dvbdmxfilter->hw_handle = handle; - - return ret; -} - -static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) -{ - struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv; - u16 buf[3]; - u16 answ[2]; - int ret; - u16 handle; - - dprintk(4, "%p\n", av7110); - - if (av7110->full_ts) - return 0; - - handle = dvbdmxfilter->hw_handle; - if (handle >= 32) { - printk("%s tried to stop invalid filter %04x, filter type = %x\n", - __func__, handle, dvbdmxfilter->type); - return -EINVAL; - } - - av7110->handle2filter[handle] = NULL; - - buf[0] = (COMTYPE_PID_FILTER << 8) + DelPIDFilter; - buf[1] = 1; - buf[2] = handle; - ret = av7110_fw_request(av7110, buf, 3, answ, 2); - if (ret != 0 || answ[1] != handle) { - printk("dvb-ttpci: %s error cmd %04x %04x %04x ret %x " - "resp %04x %04x pid %d\n", - __func__, buf[0], buf[1], buf[2], ret, - answ[0], answ[1], dvbdmxfilter->feed->pid); - if (!ret) - ret = -1; - } - return ret; -} - - -static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct av7110 *av7110 = dvbdmx->priv; - u16 *pid = dvbdmx->pids, npids[5]; - int i; - int ret = 0; - - dprintk(4, "%p\n", av7110); - - npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; - i = dvbdmxfeed->pes_type; - npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; - if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) { - npids[i] = 0; - ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); - if (!ret) - ret = StartHWFilter(dvbdmxfeed->filter); - return ret; - } - if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) { - ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); - if (ret) - return ret; - } - - if (dvbdmxfeed->pes_type < 2 && npids[0]) - if (av7110->fe_synced) - { - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); - if (ret) - return ret; - } - - if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) { - if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) - ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); - if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) - ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); - } - return ret; -} - -static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct av7110 *av7110 = dvbdmx->priv; - u16 *pid = dvbdmx->pids, npids[5]; - int i; - - int ret = 0; - - dprintk(4, "%p\n", av7110); - - if (dvbdmxfeed->pes_type <= 1) { - ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); - if (ret) - return ret; - if (!av7110->rec_mode) - dvbdmx->recording = 0; - if (!av7110->playing) - dvbdmx->playing = 0; - } - npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; - i = dvbdmxfeed->pes_type; - switch (i) { - case 2: //teletext - if (dvbdmxfeed->ts_type & TS_PACKET) - ret = StopHWFilter(dvbdmxfeed->filter); - npids[2] = 0; - break; - case 0: - case 1: - case 4: - if (!pids_off) - return 0; - npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; - break; - } - if (!ret) - ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); - return ret; -} - -static int av7110_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *av7110 = demux->priv; - int ret = 0; - - dprintk(4, "%p\n", av7110); - - if (!demux->dmx.frontend) - return -EINVAL; - - if (!av7110->full_ts && feed->pid > 0x1fff) - return -EINVAL; - - if (feed->type == DMX_TYPE_TS) { - if ((feed->ts_type & TS_DECODER) && - (feed->pes_type < DMX_TS_PES_OTHER)) { - switch (demux->dmx.frontend->source) { - case DMX_MEMORY_FE: - if (feed->ts_type & TS_DECODER) - if (feed->pes_type < 2 && - !(demux->pids[0] & 0x8000) && - !(demux->pids[1] & 0x8000)) { - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - ret = av7110_av_start_play(av7110,RP_AV); - if (!ret) - demux->playing = 1; - } - break; - default: - ret = dvb_feed_start_pid(feed); - break; - } - } else if ((feed->ts_type & TS_PACKET) && - (demux->dmx.frontend->source != DMX_MEMORY_FE)) { - ret = StartHWFilter(feed->filter); - } - } - - if (av7110->full_ts) { - budget_start_feed(feed); - return ret; - } - - if (feed->type == DMX_TYPE_SEC) { - int i; - - for (i = 0; i < demux->filternum; i++) { - if (demux->filter[i].state != DMX_STATE_READY) - continue; - if (demux->filter[i].type != DMX_TYPE_SEC) - continue; - if (demux->filter[i].filter.parent != &feed->feed.sec) - continue; - demux->filter[i].state = DMX_STATE_GO; - if (demux->dmx.frontend->source != DMX_MEMORY_FE) { - ret = StartHWFilter(&demux->filter[i]); - if (ret) - break; - } - } - } - - return ret; -} - - -static int av7110_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *av7110 = demux->priv; - int i, rc, ret = 0; - dprintk(4, "%p\n", av7110); - - if (feed->type == DMX_TYPE_TS) { - if (feed->ts_type & TS_DECODER) { - if (feed->pes_type >= DMX_TS_PES_OTHER || - !demux->pesfilter[feed->pes_type]) - return -EINVAL; - demux->pids[feed->pes_type] |= 0x8000; - demux->pesfilter[feed->pes_type] = NULL; - } - if (feed->ts_type & TS_DECODER && - feed->pes_type < DMX_TS_PES_OTHER) { - ret = dvb_feed_stop_pid(feed); - } else - if ((feed->ts_type & TS_PACKET) && - (demux->dmx.frontend->source != DMX_MEMORY_FE)) - ret = StopHWFilter(feed->filter); - } - - if (av7110->full_ts) { - budget_stop_feed(feed); - return ret; - } - - if (feed->type == DMX_TYPE_SEC) { - for (i = 0; ifilternum; i++) { - if (demux->filter[i].state == DMX_STATE_GO && - demux->filter[i].filter.parent == &feed->feed.sec) { - demux->filter[i].state = DMX_STATE_READY; - if (demux->dmx.frontend->source != DMX_MEMORY_FE) { - rc = StopHWFilter(&demux->filter[i]); - if (!ret) - ret = rc; - /* keep going, stop as many filters as possible */ - } - } - } - } - - return ret; -} - - -static void restart_feeds(struct av7110 *av7110) -{ - struct dvb_demux *dvbdmx = &av7110->demux; - struct dvb_demux_feed *feed; - int mode; - int feeding; - int i, j; - - dprintk(4, "%p\n", av7110); - - mode = av7110->playing; - av7110->playing = 0; - av7110->rec_mode = 0; - - feeding = av7110->feeding1; /* full_ts mod */ - - for (i = 0; i < dvbdmx->feednum; i++) { - feed = &dvbdmx->feed[i]; - if (feed->state == DMX_STATE_GO) { - if (feed->type == DMX_TYPE_SEC) { - for (j = 0; j < dvbdmx->filternum; j++) { - if (dvbdmx->filter[j].type != DMX_TYPE_SEC) - continue; - if (dvbdmx->filter[j].filter.parent != &feed->feed.sec) - continue; - if (dvbdmx->filter[j].state == DMX_STATE_GO) - dvbdmx->filter[j].state = DMX_STATE_READY; - } - } - av7110_start_feed(feed); - } - } - - av7110->feeding1 = feeding; /* full_ts mod */ - - if (mode) - av7110_av_start_play(av7110, mode); -} - -static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, - uint64_t *stc, unsigned int *base) -{ - int ret; - u16 fwstc[4]; - u16 tag = ((COMTYPE_REQUEST << 8) + ReqSTC); - struct dvb_demux *dvbdemux; - struct av7110 *av7110; - - /* pointer casting paranoia... */ - BUG_ON(!demux); - dvbdemux = demux->priv; - BUG_ON(!dvbdemux); - av7110 = dvbdemux->priv; - - dprintk(4, "%p\n", av7110); - - if (num != 0) - return -EINVAL; - - ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4); - if (ret) { - printk(KERN_ERR "%s: av7110_fw_request error\n", __func__); - return ret; - } - dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n", - fwstc[0], fwstc[1], fwstc[2], fwstc[3]); - - *stc = (((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) | - (((uint64_t) fwstc[1]) << 16) | ((uint64_t) fwstc[0]); - *base = 1; - - dprintk(4, "stc = %lu\n", (unsigned long)*stc); - - return 0; -} - - -/****************************************************************************** - * SEC device file operations - ******************************************************************************/ - - -static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct av7110* av7110 = fe->dvb->priv; - - switch (tone) { - case SEC_TONE_ON: - return Set22K(av7110, 1); - - case SEC_TONE_OFF: - return Set22K(av7110, 0); - - default: - return -EINVAL; - } -} - -static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd* cmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); -} - -static int av7110_diseqc_send_burst(struct dvb_frontend* fe, - fe_sec_mini_cmd_t minicmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - return av7110_diseqc_send(av7110, 0, NULL, minicmd); -} - -/* simplified code from budget-core.c */ -static int stop_ts_capture(struct av7110 *budget) -{ - dprintk(2, "budget: %p\n", budget); - - if (--budget->feeding1) - return budget->feeding1; - saa7146_write(budget->dev, MC1, MASK_20); /* DMA3 off */ - SAA7146_IER_DISABLE(budget->dev, MASK_10); - SAA7146_ISR_CLEAR(budget->dev, MASK_10); - return 0; -} - -static int start_ts_capture(struct av7110 *budget) -{ - dprintk(2, "budget: %p\n", budget); - - if (budget->feeding1) - return ++budget->feeding1; - memset(budget->grabbing, 0x00, TS_BUFLEN); - budget->ttbp = 0; - SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ - SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ - saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ - return ++budget->feeding1; -} - -static int budget_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *budget = demux->priv; - int status; - - dprintk(2, "av7110: %p\n", budget); - - spin_lock(&budget->feedlock1); - feed->pusi_seen = 0; /* have a clean section start */ - status = start_ts_capture(budget); - spin_unlock(&budget->feedlock1); - return status; -} - -static int budget_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct av7110 *budget = demux->priv; - int status; - - dprintk(2, "budget: %p\n", budget); - - spin_lock(&budget->feedlock1); - status = stop_ts_capture(budget); - spin_unlock(&budget->feedlock1); - return status; -} - -static void vpeirq(unsigned long cookie) -{ - struct av7110 *budget = (struct av7110 *)cookie; - u8 *mem = (u8 *) (budget->grabbing); - u32 olddma = budget->ttbp; - u32 newdma = saa7146_read(budget->dev, PCI_VDP3); - struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1; - - /* nearest lower position divisible by 188 */ - newdma -= newdma % 188; - - if (newdma >= TS_BUFLEN) - return; - - budget->ttbp = newdma; - - if (!budget->feeding1 || (newdma == olddma)) - return; - - /* Ensure streamed PCI data is synced to CPU */ - pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); - -#if 0 - /* track rps1 activity */ - printk("vpeirq: %02x Event Counter 1 0x%04x\n", - mem[olddma], - saa7146_read(budget->dev, EC1R) & 0x3fff); -#endif - - if (newdma > olddma) - /* no wraparound, dump olddma..newdma */ - dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188); - else { - /* wraparound, dump olddma..buflen and 0..newdma */ - dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188); - dvb_dmx_swfilter_packets(demux, mem, newdma / 188); - } -} - -static int av7110_register(struct av7110 *av7110) -{ - int ret, i; - struct dvb_demux *dvbdemux = &av7110->demux; - struct dvb_demux *dvbdemux1 = &av7110->demux1; - - dprintk(4, "%p\n", av7110); - - if (av7110->registered) - return -1; - - av7110->registered = 1; - - dvbdemux->priv = (void *) av7110; - - for (i = 0; i < 32; i++) - av7110->handle2filter[i] = NULL; - - dvbdemux->filternum = (av7110->full_ts) ? 256 : 32; - dvbdemux->feednum = (av7110->full_ts) ? 256 : 32; - dvbdemux->start_feed = av7110_start_feed; - dvbdemux->stop_feed = av7110_stop_feed; - dvbdemux->write_to_decoder = av7110_write_to_decoder; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - - dvb_dmx_init(&av7110->demux); - av7110->demux.dmx.get_stc = dvb_get_stc; - - av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32; - av7110->dmxdev.demux = &dvbdemux->dmx; - av7110->dmxdev.capabilities = 0; - - dvb_dmxdev_init(&av7110->dmxdev, &av7110->dvb_adapter); - - av7110->hw_frontend.source = DMX_FRONTEND_0; - - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->hw_frontend); - - if (ret < 0) - return ret; - - av7110->mem_frontend.source = DMX_MEMORY_FE; - - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->mem_frontend); - - if (ret < 0) - return ret; - - ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, - &av7110->hw_frontend); - if (ret < 0) - return ret; - - av7110_av_register(av7110); - av7110_ca_register(av7110); - -#ifdef CONFIG_DVB_AV7110_OSD - dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev, - &dvbdev_osd, av7110, DVB_DEVICE_OSD); -#endif - - dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); - - if (budgetpatch) { - /* initialize software demux1 without its own frontend - * demux1 hardware is connected to frontend0 of demux0 - */ - dvbdemux1->priv = (void *) av7110; - - dvbdemux1->filternum = 256; - dvbdemux1->feednum = 256; - dvbdemux1->start_feed = budget_start_feed; - dvbdemux1->stop_feed = budget_stop_feed; - dvbdemux1->write_to_decoder = NULL; - - dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - - dvb_dmx_init(&av7110->demux1); - - av7110->dmxdev1.filternum = 256; - av7110->dmxdev1.demux = &dvbdemux1->dmx; - av7110->dmxdev1.capabilities = 0; - - dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter); - - dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx); - printk("dvb-ttpci: additional demux1 for budget-patch registered\n"); - } - return 0; -} - - -static void dvb_unregister(struct av7110 *av7110) -{ - struct dvb_demux *dvbdemux = &av7110->demux; - struct dvb_demux *dvbdemux1 = &av7110->demux1; - - dprintk(4, "%p\n", av7110); - - if (!av7110->registered) - return; - - if (budgetpatch) { - dvb_net_release(&av7110->dvb_net1); - dvbdemux->dmx.close(&dvbdemux1->dmx); - dvb_dmxdev_release(&av7110->dmxdev1); - dvb_dmx_release(&av7110->demux1); - } - - dvb_net_release(&av7110->dvb_net); - - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend); - - dvb_dmxdev_release(&av7110->dmxdev); - dvb_dmx_release(&av7110->demux); - - if (av7110->fe != NULL) { - dvb_unregister_frontend(av7110->fe); - dvb_frontend_detach(av7110->fe); - } - dvb_unregister_device(av7110->osd_dev); - av7110_av_unregister(av7110); - av7110_ca_unregister(av7110); -} - - -/**************************************************************************** - * I2C client commands - ****************************************************************************/ - -int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val) -{ - u8 msg[2] = { reg, val }; - struct i2c_msg msgs; - - msgs.flags = 0; - msgs.addr = id / 2; - msgs.len = 2; - msgs.buf = msg; - return i2c_transfer(&av7110->i2c_adap, &msgs, 1); -} - -u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) -{ - u8 mm1[] = {0x00}; - u8 mm2[] = {0x00}; - struct i2c_msg msgs[2]; - - msgs[0].flags = 0; - msgs[1].flags = I2C_M_RD; - msgs[0].addr = msgs[1].addr = id / 2; - mm1[0] = reg; - msgs[0].len = 1; msgs[1].len = 1; - msgs[0].buf = mm1; msgs[1].buf = mm2; - i2c_transfer(&av7110->i2c_adap, msgs, 2); - - return mm2[0]; -} - -/**************************************************************************** - * INITIALIZATION - ****************************************************************************/ - - -static int check_firmware(struct av7110* av7110) -{ - u32 crc = 0, len = 0; - unsigned char *ptr; - - /* check for firmware magic */ - ptr = av7110->bin_fw; - if (ptr[0] != 'A' || ptr[1] != 'V' || - ptr[2] != 'F' || ptr[3] != 'W') { - printk("dvb-ttpci: this is not an av7110 firmware\n"); - return -EINVAL; - } - ptr += 4; - - /* check dpram file */ - crc = get_unaligned_be32(ptr); - ptr += 4; - len = get_unaligned_be32(ptr); - ptr += 4; - if (len >= 512) { - printk("dvb-ttpci: dpram file is way too big.\n"); - return -EINVAL; - } - if (crc != crc32_le(0, ptr, len)) { - printk("dvb-ttpci: crc32 of dpram file does not match.\n"); - return -EINVAL; - } - av7110->bin_dpram = ptr; - av7110->size_dpram = len; - ptr += len; - - /* check root file */ - crc = get_unaligned_be32(ptr); - ptr += 4; - len = get_unaligned_be32(ptr); - ptr += 4; - - if (len <= 200000 || len >= 300000 || - len > ((av7110->bin_fw + av7110->size_fw) - ptr)) { - printk("dvb-ttpci: root file has strange size (%d). aborting.\n", len); - return -EINVAL; - } - if( crc != crc32_le(0, ptr, len)) { - printk("dvb-ttpci: crc32 of root file does not match.\n"); - return -EINVAL; - } - av7110->bin_root = ptr; - av7110->size_root = len; - return 0; -} - -static void put_firmware(struct av7110* av7110) -{ - vfree(av7110->bin_fw); -} - -static int get_firmware(struct av7110* av7110) -{ - int ret; - const struct firmware *fw; - - /* request the av7110 firmware, this will block until someone uploads it */ - ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev); - if (ret) { - if (ret == -ENOENT) { - printk(KERN_ERR "dvb-ttpci: could not load firmware," - " file not found: dvb-ttpci-01.fw\n"); - printk(KERN_ERR "dvb-ttpci: usually this should be in " - "/usr/lib/hotplug/firmware or /lib/firmware\n"); - printk(KERN_ERR "dvb-ttpci: and can be downloaded from" - " http://www.linuxtv.org/download/dvb/firmware/\n"); - } else - printk(KERN_ERR "dvb-ttpci: cannot request firmware" - " (error %i)\n", ret); - return -EINVAL; - } - - if (fw->size <= 200000) { - printk("dvb-ttpci: this firmware is way too small.\n"); - release_firmware(fw); - return -EINVAL; - } - - /* check if the firmware is available */ - av7110->bin_fw = vmalloc(fw->size); - if (NULL == av7110->bin_fw) { - dprintk(1, "out of memory\n"); - release_firmware(fw); - return -ENOMEM; - } - - memcpy(av7110->bin_fw, fw->data, fw->size); - av7110->size_fw = fw->size; - if ((ret = check_firmware(av7110))) - vfree(av7110->bin_fw); - - release_firmware(fw); - return ret; -} - -static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) -{ - struct av7110* av7110 = fe->dvb->priv; - u8 pwr = 0; - u8 buf[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (params->frequency + 479500) / 125; - - if (params->frequency > 2000000) pwr = 3; - else if (params->frequency > 1800000) pwr = 2; - else if (params->frequency > 1600000) pwr = 1; - else if (params->frequency > 1200000) pwr = 0; - else if (params->frequency >= 1100000) pwr = 1; - else pwr = 2; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = ((div & 0x18000) >> 10) | 0x95; - buf[3] = (pwr << 6) | 0x30; - - // NOTE: since we're using a prescaler of 2, we set the - // divisor frequency to 62.5kHz and divide by 125 above - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct ves1x93_config alps_bsrv2_config = { - .demod_address = 0x08, - .xin = 90100000UL, - .invert_pwm = 0, -}; - -static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) -{ - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (params->frequency + 35937500 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct ves1820_config alps_tdbe2_config = { - .demod_address = 0x09, - .xin = 57840000UL, - .invert = 1, - .selagc = VES1820_SELAGC_SIGNAMPERR, -}; - - - - -static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) -{ - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = params->frequency / 125; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x8e; - data[3] = 0x00; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct tda8083_config grundig_29504_451_config = { - .demod_address = 0x68, -}; - - - -static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) -{ - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u32 f = params->frequency; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (f + 36125000 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x8e; - data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct ves1820_config philips_cd1516_config = { - .demod_address = 0x09, - .xin = 57840000UL, - .invert = 1, - .selagc = VES1820_SELAGC_SIGNAMPERR, -}; - - - -static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) -{ - struct av7110* av7110 = fe->dvb->priv; - u32 div, pwr; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (params->frequency + 36200000) / 166666; - - if (params->frequency <= 782000000) - pwr = 1; - else - pwr = 2; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85; - data[3] = pwr << 6; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ -#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE) - struct av7110* av7110 = fe->dvb->priv; - - return request_firmware(fw, name, &av7110->dev->pci->dev); -#else - return -EINVAL; -#endif -} - -static struct sp8870_config alps_tdlb7_config = { - - .demod_address = 0x71, - .request_firmware = alps_tdlb7_request_firmware, -}; - - -static u8 nexusca_stv0297_inittab[] = { - 0x80, 0x01, - 0x80, 0x00, - 0x81, 0x01, - 0x81, 0x00, - 0x00, 0x09, - 0x01, 0x69, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x20, 0x00, - 0x21, 0x40, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x40, - 0x25, 0x88, - 0x30, 0xff, - 0x31, 0x00, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x50, - 0x35, 0x7f, - 0x36, 0x00, - 0x37, 0x20, - 0x38, 0x00, - 0x40, 0x1c, - 0x41, 0xff, - 0x42, 0x29, - 0x43, 0x00, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0x00, - 0x4b, 0x7b, - 0x52, 0x30, - 0x55, 0xae, - 0x56, 0x47, - 0x57, 0xe1, - 0x58, 0x3a, - 0x5a, 0x1e, - 0x5b, 0x34, - 0x60, 0x00, - 0x63, 0x00, - 0x64, 0x00, - 0x65, 0x00, - 0x66, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x69, 0x00, - 0x6a, 0x02, - 0x6b, 0x00, - 0x70, 0xff, - 0x71, 0x00, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x00, - 0x81, 0x00, - 0x82, 0x00, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x80, - 0x86, 0x24, - 0x87, 0x78, - 0x88, 0x10, - 0x89, 0x00, - 0x90, 0x01, - 0x91, 0x01, - 0xa0, 0x04, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x53, - 0xc1, 0x70, - 0xc2, 0x12, - 0xd0, 0x00, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x00, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x00, - 0x61, 0x49, - 0x62, 0x0b, - 0x53, 0x08, - 0x59, 0x08, - 0xff, 0xff, -}; - -static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) -{ - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) }; - struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 }; - int i; - - div = (params->frequency + 36150000 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0xce; - - if (params->frequency < 45000000) - return -EINVAL; - else if (params->frequency < 137000000) - data[3] = 0x01; - else if (params->frequency < 403000000) - data[3] = 0x02; - else if (params->frequency < 860000000) - data[3] = 0x04; - else - return -EINVAL; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) { - printk("nexusca: pll transfer failed!\n"); - return -EIO; - } - - // wait for PLL lock - for(i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1) - if (data[0] & 0x40) break; - msleep(10); - } - - return 0; -} - -static struct stv0297_config nexusca_stv0297_config = { - - .demod_address = 0x1C, - .inittab = nexusca_stv0297_inittab, - .invert = 1, - .stop_during_read = 1, -}; - - - -static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) -{ - struct av7110* av7110 = fe->dvb->priv; - u32 div; - u8 cfg, cpump, band_select; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (36125000 + params->frequency) / 166666; - - cfg = 0x88; - - if (params->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) cpump = 1; - else cpump = 3; - - if (params->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) band_select = 0x05; - else band_select = 0x03; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = ((div >> 10) & 0x60) | cfg; - data[3] = (cpump << 6) | band_select; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct l64781_config grundig_29504_401_config = { - .demod_address = 0x55, -}; - - - -static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) -{ - int ret = 0; - int synced = (status & FE_HAS_LOCK) ? 1 : 0; - - av7110->fe_status = status; - - if (av7110->fe_synced == synced) - return 0; - - if (av7110->playing) { - av7110->fe_synced = synced; - return 0; - } - - if (mutex_lock_interruptible(&av7110->pid_mutex)) - return -ERESTARTSYS; - - if (synced) { - ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], - av7110->pids[DMX_PES_AUDIO], - av7110->pids[DMX_PES_TELETEXT], 0, - av7110->pids[DMX_PES_PCR]); - if (!ret) - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); - } else { - ret = SetPIDs(av7110, 0, 0, 0, 0, 0); - if (!ret) { - ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); - if (!ret) - ret = av7110_wait_msgstate(av7110, GPMQBusy); - } - } - - if (!ret) - av7110->fe_synced = synced; - - mutex_unlock(&av7110->pid_mutex); - return ret; -} - -static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_fe_params = *params; - ret = av7110->fe_set_frontend(fe, params); - } - return ret; -} - -static int av7110_fe_init(struct dvb_frontend* fe) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) - ret = av7110->fe_init(fe); - return ret; -} - -static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct av7110* av7110 = fe->dvb->priv; - - /* call the real implementation */ - int ret = av7110->fe_read_status(fe, status); - if (!ret) - if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) - ret = av7110_fe_lock_fix(av7110, *status); - return ret; -} - -static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) - ret = av7110->fe_diseqc_reset_overload(fe); - return ret; -} - -static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd* cmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_master_cmd = *cmd; - ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); - } - return ret; -} - -static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_minicmd = minicmd; - ret = av7110->fe_diseqc_send_burst(fe, minicmd); - } - return ret; -} - -static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_tone = tone; - ret = av7110->fe_set_tone(fe, tone); - } - return ret; -} - -static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_voltage = voltage; - ret = av7110->fe_set_voltage(fe, voltage); - } - return ret; -} - -static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd) -{ - struct av7110* av7110 = fe->dvb->priv; - - int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) - ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd); - return ret; -} - -static void dvb_s_recover(struct av7110* av7110) -{ - av7110_fe_init(av7110->fe); - - av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage); - if (av7110->saved_master_cmd.msg_len) { - msleep(20); - av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd); - } - msleep(20); - av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd); - msleep(20); - av7110_fe_set_tone(av7110->fe, av7110->saved_tone); - - av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params); -} - -static u8 read_pwm(struct av7110* av7110) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, - { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; - - if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -static int frontend_init(struct av7110 *av7110) -{ - int ret; - - if (av7110->dev->pci->subsystem_vendor == 0x110a) { - switch(av7110->dev->pci->subsystem_device) { - case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??)) - av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, - &av7110->i2c_adap, read_pwm(av7110)); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; - } - break; - } - - } else if (av7110->dev->pci->subsystem_vendor == 0x13c2) { - switch(av7110->dev->pci->subsystem_device) { - case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X - case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X - case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE - - // try the ALPS BSRV2 first of all - av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - break; - } - - // try the ALPS BSRU6 now - av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - av7110->fe->tuner_priv = &av7110->i2c_adap; - - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - break; - } - - // Try the grundig 29504-451 - av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - break; - } - - /* Try DVB-C cards */ - switch(av7110->dev->pci->subsystem_device) { - case 0x0000: - /* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */ - av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap, - read_pwm(av7110)); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; - } - break; - case 0x0003: - /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */ - av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, - read_pwm(av7110)); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; - } - break; - } - break; - - case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X - // try ALPS TDLB7 first, then Grundig 29504-401 - av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params; - break; - } - /* fall-thru */ - - case 0x0008: // Hauppauge/TT DVB-T - // Grundig 29504-401 - av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap); - if (av7110->fe) - av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; - break; - - case 0x0002: // Hauppauge/TT DVB-C premium rev2.X - - av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; - } - break; - - case 0x0004: // Galaxis DVB-S rev1.3 - /* ALPS BSRV2 */ - av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - } - break; - - case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */ - /* Grundig 29504-451 */ - av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; - av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops.set_tone = av7110_set_tone; - av7110->recover = dvb_s_recover; - } - break; - - case 0x000A: // Hauppauge/TT Nexus-CA rev1.X - - av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params; - - /* set TDA9819 into DVB mode */ - saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) - saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) - - /* tuner on this needs a slower i2c bus speed */ - av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - break; - } - break; - - case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ - /* ALPS BSBE1 */ - av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap); - if (av7110->fe) { - av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; - av7110->fe->tuner_priv = &av7110->i2c_adap; - - if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) { - printk("dvb-ttpci: LNBP21 not found!\n"); - if (av7110->fe->ops.release) - av7110->fe->ops.release(av7110->fe); - av7110->fe = NULL; - } else { - av7110->fe->ops.dishnetwork_send_legacy_command = NULL; - av7110->recover = dvb_s_recover; - } - } - break; - } - } - - if (!av7110->fe) { - /* FIXME: propagate the failure code from the lower layers */ - ret = -ENOMEM; - printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - av7110->dev->pci->vendor, - av7110->dev->pci->device, - av7110->dev->pci->subsystem_vendor, - av7110->dev->pci->subsystem_device); - } else { - FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init); - FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status); - FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload); - FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd); - FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst); - FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone); - FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage); - FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); - FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend); - - ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe); - if (ret < 0) { - printk("av7110: Frontend registration failed!\n"); - dvb_frontend_detach(av7110->fe); - av7110->fe = NULL; - } - } - return ret; -} - -/* Budgetpatch note: - * Original hardware design by Roberto Deza: - * There is a DVB_Wiki at - * http://www.linuxtv.org/ - * - * New software triggering design by Emard that works on - * original Roberto Deza's hardware: - * - * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin. - * GPIO3 is in budget-patch hardware connectd to port B VSYNC - * HS is an internal event of 7146, accessible with RPS - * and temporarily raised high every n lines - * (n in defined in the RPS_THRESH1 counter threshold) - * I think HS is raised high on the beginning of the n-th line - * and remains high until this n-th line that triggered - * it is completely received. When the receiption of n-th line - * ends, HS is lowered. - * - * To transmit data over DMA, 7146 needs changing state at - * port B VSYNC pin. Any changing of port B VSYNC will - * cause some DMA data transfer, with more or less packets loss. - * It depends on the phase and frequency of VSYNC and - * the way of 7146 is instructed to trigger on port B (defined - * in DD1_INIT register, 3rd nibble from the right valid - * numbers are 0-7, see datasheet) - * - * The correct triggering can minimize packet loss, - * dvbtraffic should give this stable bandwidths: - * 22k transponder = 33814 kbit/s - * 27.5k transponder = 38045 kbit/s - * by experiment it is found that the best results - * (stable bandwidths and almost no packet loss) - * are obtained using DD1_INIT triggering number 2 - * (Va at rising edge of VS Fa = HS x VS-failing forced toggle) - * and a VSYNC phase that occurs in the middle of DMA transfer - * (about byte 188*512=96256 in the DMA window). - * - * Phase of HS is still not clear to me how to control, - * It just happens to be so. It can be seen if one enables - * RPS_IRQ and print Event Counter 1 in vpeirq(). Every - * time RPS_INTERRUPT is called, the Event Counter 1 will - * increment. That's how the 7146 is programmed to do event - * counting in this budget-patch.c - * I *think* HPS setting has something to do with the phase - * of HS but I cant be 100% sure in that. - * - * hardware debug note: a working budget card (including budget patch) - * with vpeirq() interrupt setup in mode "0x90" (every 64K) will - * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes - * and that means 3*25=75 Hz of interrupt freqency, as seen by - * watch cat /proc/interrupts - * - * If this frequency is 3x lower (and data received in the DMA - * buffer don't start with 0x47, but in the middle of packets, - * whose lengths appear to be like 188 292 188 104 etc. - * this means VSYNC line is not connected in the hardware. - * (check soldering pcb and pins) - * The same behaviour of missing VSYNC can be duplicated on budget - * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. - */ -static int __devinit av7110_attach(struct saa7146_dev* dev, - struct saa7146_pci_extension_data *pci_ext) -{ - const int length = TS_WIDTH * TS_HEIGHT; - struct pci_dev *pdev = dev->pci; - struct av7110 *av7110; - struct task_struct *thread; - int ret, count = 0; - - dprintk(4, "dev: %p\n", dev); - - /* Set RPS_IRQ to 1 to track rps1 activity. - * Enabling this won't send any interrupt to PC CPU. - */ -#define RPS_IRQ 0 - - if (budgetpatch == 1) { - budgetpatch = 0; - /* autodetect the presence of budget patch - * this only works if saa7146 has been recently - * reset with with MASK_31 to MC1 - * - * will wait for VBI_B event (vertical blank at port B) - * and will reset GPIO3 after VBI_B is detected. - * (GPIO3 should be raised high by CPU to - * test if GPIO3 will generate vertical blank signal - * in budget patch GPIO3 is connected to VSYNC_B - */ - - /* RESET SAA7146 */ - saa7146_write(dev, MC1, MASK_31); - /* autodetection success seems to be time-dependend after reset */ - - /* Fix VSYNC level */ - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - /* set vsync_b triggering */ - saa7146_write(dev, DD1_STREAM_B, 0); - /* port B VSYNC at rising edge */ - saa7146_write(dev, DD1_INIT, 0x00000200); - saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI - saa7146_write(dev, MC2, - 1 * (MASK_08 | MASK_24) | // BRS control - 0 * (MASK_09 | MASK_25) | // a - 1 * (MASK_10 | MASK_26) | // b - 0 * (MASK_06 | MASK_22) | // HPS_CTRL1 - 0 * (MASK_05 | MASK_21) | // HPS_CTRL2 - 0 * (MASK_01 | MASK_15) // DEBI - ); - - /* start writing RPS1 code from beginning */ - count = 0; - /* Disable RPS1 */ - saa7146_write(dev, MC1, MASK_29); - /* RPS1 timeout disable */ - saa7146_write(dev, RPS_TOV1, 0); - WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); -#if RPS_IRQ - /* issue RPS1 interrupt to increment counter */ - WRITE_RPS1(CMD_INTERRUPT); -#endif - WRITE_RPS1(CMD_STOP); - /* Jump to begin of RPS program as safety measure (p37) */ - WRITE_RPS1(CMD_JUMP); - WRITE_RPS1(dev->d_rps1.dma_handle); - -#if RPS_IRQ - /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) - * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled - * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called - */ - saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); - /* set event counter 1 threshold to maximum allowed value (rEC p55) */ - saa7146_write(dev, ECT1R, 0x3fff ); -#endif - /* Set RPS1 Address register to point to RPS code (r108 p42) */ - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - /* Enable RPS1, (rFC p33) */ - saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); - - mdelay(10); - /* now send VSYNC_B to rps1 by rising GPIO3 */ - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - mdelay(10); - /* if rps1 responded by lowering the GPIO3, - * then we have budgetpatch hardware - */ - if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) { - budgetpatch = 1; - printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n"); - } - /* Disable RPS1 */ - saa7146_write(dev, MC1, ( MASK_29 )); -#if RPS_IRQ - printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); -#endif - } - - /* prepare the av7110 device struct */ - av7110 = kzalloc(sizeof(struct av7110), GFP_KERNEL); - if (!av7110) { - dprintk(1, "out of memory\n"); - return -ENOMEM; - } - - av7110->card_name = (char*) pci_ext->ext_priv; - av7110->dev = dev; - dev->ext_priv = av7110; - - ret = get_firmware(av7110); - if (ret < 0) - goto err_kfree_0; - - ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, - THIS_MODULE, &dev->pci->dev, adapter_nr); - if (ret < 0) - goto err_put_firmware_1; - - /* the Siemens DVB needs this if you want to have the i2c chips - get recognized before the main driver is fully loaded */ - saa7146_write(dev, GPIO_CTRL, 0x500000); - - strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name)); - - saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */ - - ret = i2c_add_adapter(&av7110->i2c_adap); - if (ret < 0) - goto err_dvb_unregister_adapter_2; - - ttpci_eeprom_parse_mac(&av7110->i2c_adap, - av7110->dvb_adapter.proposed_mac); - ret = -ENOMEM; - - /* full-ts mod? */ - if (full_ts) - av7110->full_ts = true; - - /* check for full-ts flag in eeprom */ - if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) { - u8 flags = i2c_readreg(av7110, 0xaa, 2); - if (flags != 0xff && (flags & 0x01)) - av7110->full_ts = true; - } - - if (av7110->full_ts) { - printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n"); - spin_lock_init(&av7110->feedlock1); - av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, - &av7110->pt); - if (!av7110->grabbing) - goto err_i2c_del_3; - - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, MC2, (MASK_10 | MASK_26)); - - saa7146_write(dev, DD1_INIT, 0x00000600); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - saa7146_write(dev, BRS_CTRL, 0x60000000); - saa7146_write(dev, MC2, MASK_08 | MASK_24); - - /* dma3 */ - saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); - saa7146_write(dev, BASE_ODD3, 0); - saa7146_write(dev, BASE_EVEN3, 0); - saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); - saa7146_write(dev, PITCH3, TS_WIDTH); - saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); - saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); - saa7146_write(dev, MC2, MASK_04 | MASK_20); - - tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); - - } else if (budgetpatch) { - spin_lock_init(&av7110->feedlock1); - av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, - &av7110->pt); - if (!av7110->grabbing) - goto err_i2c_del_3; - - saa7146_write(dev, PCI_BT_V1, 0x1c1f101f); - saa7146_write(dev, BCS_CTRL, 0x80400040); - /* set dd1 stream a & b */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, DD1_INIT, 0x03000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - saa7146_write(dev, BASE_ODD3, 0); - saa7146_write(dev, BASE_EVEN3, 0); - saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); - saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); - - saa7146_write(dev, PITCH3, TS_WIDTH); - saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); - - /* upload all */ - saa7146_write(dev, MC2, 0x077c077c); - saa7146_write(dev, GPIO_CTRL, 0x000000); -#if RPS_IRQ - /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) - * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled - * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called - */ - saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); - /* set event counter 1 threshold to maximum allowed value (rEC p55) */ - saa7146_write(dev, ECT1R, 0x3fff ); -#endif - /* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */ - count = 0; - - /* Wait Source Line Counter Threshold (p36) */ - WRITE_RPS1(CMD_PAUSE | EVT_HS); - /* Set GPIO3=1 (p42) */ - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); -#if RPS_IRQ - /* issue RPS1 interrupt */ - WRITE_RPS1(CMD_INTERRUPT); -#endif - /* Wait reset Source Line Counter Threshold (p36) */ - WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); - /* Set GPIO3=0 (p42) */ - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); -#if RPS_IRQ - /* issue RPS1 interrupt */ - WRITE_RPS1(CMD_INTERRUPT); -#endif - /* Jump to begin of RPS program (p37) */ - WRITE_RPS1(CMD_JUMP); - WRITE_RPS1(dev->d_rps1.dma_handle); - - /* Fix VSYNC level */ - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - /* Set RPS1 Address register to point to RPS code (r108 p42) */ - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - /* Set Source Line Counter Threshold, using BRS (rCC p43) - * It generates HS event every TS_HEIGHT lines - * this is related to TS_WIDTH set in register - * NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits - * are set to TS_WIDTH bytes (TS_WIDTH=2*188), - * then RPS_THRESH1 should be set to trigger - * every TS_HEIGHT (512) lines. - */ - saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 ); - - /* Enable RPS1 (rFC p33) */ - saa7146_write(dev, MC1, (MASK_13 | MASK_29)); - - /* end of budgetpatch register initialization */ - tasklet_init (&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); - } else { - saa7146_write(dev, PCI_BT_V1, 0x1c00101f); - saa7146_write(dev, BCS_CTRL, 0x80400040); - - /* set dd1 stream a & b */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, DD1_INIT, 0x03000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - /* upload all */ - saa7146_write(dev, MC2, 0x077c077c); - saa7146_write(dev, GPIO_CTRL, 0x000000); - } - - tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110); - tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110); - - mutex_init(&av7110->pid_mutex); - - /* locks for data transfers from/to AV7110 */ - spin_lock_init(&av7110->debilock); - mutex_init(&av7110->dcomlock); - av7110->debitype = -1; - - /* default OSD window */ - av7110->osdwin = 1; - mutex_init(&av7110->osd_mutex); - - /* TV standard */ - av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC - : AV7110_VIDEO_MODE_PAL; - - /* ARM "watchdog" */ - init_waitqueue_head(&av7110->arm_wait); - av7110->arm_thread = NULL; - - /* allocate and init buffers */ - av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus); - if (!av7110->debi_virt) - goto err_saa71466_vfree_4; - - - av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS); - if (!av7110->iobuf) - goto err_pci_free_5; - - ret = av7110_av_init(av7110); - if (ret < 0) - goto err_iobuf_vfree_6; - - /* init BMP buffer */ - av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN; - init_waitqueue_head(&av7110->bmpq); - - ret = av7110_ca_init(av7110); - if (ret < 0) - goto err_av7110_av_exit_7; - - /* load firmware into AV7110 cards */ - ret = av7110_bootarm(av7110); - if (ret < 0) - goto err_av7110_ca_exit_8; - - ret = av7110_firmversion(av7110); - if (ret < 0) - goto err_stop_arm_9; - - if (FW_VERSION(av7110->arm_app)<0x2501) - printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. " - "System might be unstable!\n", FW_VERSION(av7110->arm_app)); - - thread = kthread_run(arm_thread, (void *) av7110, "arm_mon"); - if (IS_ERR(thread)) { - ret = PTR_ERR(thread); - goto err_stop_arm_9; - } - av7110->arm_thread = thread; - - /* set initial volume in mixer struct */ - av7110->mixer.volume_left = volume; - av7110->mixer.volume_right = volume; - - ret = av7110_register(av7110); - if (ret < 0) - goto err_arm_thread_stop_10; - - init_av7110_av(av7110); - - /* special case DVB-C: these cards have an analog tuner - plus need some special handling, so we have separate - saa7146_ext_vv data for these... */ - ret = av7110_init_v4l(av7110); - if (ret < 0) - goto err_av7110_unregister_11; - - av7110->dvb_adapter.priv = av7110; - ret = frontend_init(av7110); - if (ret < 0) - goto err_av7110_exit_v4l_12; - -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_ir_init(av7110); -#endif - printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); - av7110_num++; -out: - return ret; - -err_av7110_exit_v4l_12: - av7110_exit_v4l(av7110); -err_av7110_unregister_11: - dvb_unregister(av7110); -err_arm_thread_stop_10: - av7110_arm_sync(av7110); -err_stop_arm_9: - /* Nothing to do. Rejoice. */ -err_av7110_ca_exit_8: - av7110_ca_exit(av7110); -err_av7110_av_exit_7: - av7110_av_exit(av7110); -err_iobuf_vfree_6: - vfree(av7110->iobuf); -err_pci_free_5: - pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus); -err_saa71466_vfree_4: - if (av7110->grabbing) - saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt); -err_i2c_del_3: - i2c_del_adapter(&av7110->i2c_adap); -err_dvb_unregister_adapter_2: - dvb_unregister_adapter(&av7110->dvb_adapter); -err_put_firmware_1: - put_firmware(av7110); -err_kfree_0: - kfree(av7110); - goto out; -} - -static int __devexit av7110_detach(struct saa7146_dev* saa) -{ - struct av7110 *av7110 = saa->ext_priv; - dprintk(4, "%p\n", av7110); - -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_ir_exit(av7110); -#endif - if (budgetpatch || av7110->full_ts) { - if (budgetpatch) { - /* Disable RPS1 */ - saa7146_write(saa, MC1, MASK_29); - /* VSYNC LOW (inactive) */ - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - } - saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ - SAA7146_IER_DISABLE(saa, MASK_10); - SAA7146_ISR_CLEAR(saa, MASK_10); - msleep(50); - tasklet_kill(&av7110->vpe_tasklet); - saa7146_vfree_destroy_pgtable(saa->pci, av7110->grabbing, &av7110->pt); - } - av7110_exit_v4l(av7110); - - av7110_arm_sync(av7110); - - tasklet_kill(&av7110->debi_tasklet); - tasklet_kill(&av7110->gpio_tasklet); - - dvb_unregister(av7110); - - SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03); - SAA7146_ISR_CLEAR(saa, MASK_19 | MASK_03); - - av7110_ca_exit(av7110); - av7110_av_exit(av7110); - - vfree(av7110->iobuf); - pci_free_consistent(saa->pci, 8192, av7110->debi_virt, - av7110->debi_bus); - - i2c_del_adapter(&av7110->i2c_adap); - - dvb_unregister_adapter (&av7110->dvb_adapter); - - av7110_num--; - - put_firmware(av7110); - - kfree(av7110); - - saa->ext_priv = NULL; - - return 0; -} - - -static void av7110_irq(struct saa7146_dev* dev, u32 *isr) -{ - struct av7110 *av7110 = dev->ext_priv; - - //print_time("av7110_irq"); - - /* Note: Don't try to handle the DEBI error irq (MASK_18), in - * intel mode the timeout is asserted all the time... - */ - - if (*isr & MASK_19) { - //printk("av7110_irq: DEBI\n"); - /* Note 1: The DEBI irq is level triggered: We must enable it - * only after we started a DMA xfer, and disable it here - * immediately, or it will be signalled all the time while - * DEBI is idle. - * Note 2: You would think that an irq which is masked is - * not signalled by the hardware. Not so for the SAA7146: - * An irq is signalled as long as the corresponding bit - * in the ISR is set, and disabling irqs just prevents the - * hardware from setting the ISR bit. This means a) that we - * must clear the ISR *after* disabling the irq (which is why - * we must do it here even though saa7146_core did it already), - * and b) that if we were to disable an edge triggered irq - * (like the gpio irqs sadly are) temporarily we would likely - * loose some. This sucks :-( - */ - SAA7146_IER_DISABLE(av7110->dev, MASK_19); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19); - tasklet_schedule(&av7110->debi_tasklet); - } - - if (*isr & MASK_03) { - //printk("av7110_irq: GPIO\n"); - tasklet_schedule(&av7110->gpio_tasklet); - } - - if (*isr & MASK_10) - tasklet_schedule(&av7110->vpe_tasklet); -} - - -static struct saa7146_extension av7110_extension_driver; - -#define MAKE_AV7110_INFO(x_var,x_name) \ -static struct saa7146_pci_extension_data x_var = { \ - .ext_priv = x_name, \ - .ext = &av7110_extension_driver } - -MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C"); -MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); -MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); -MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); -MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X"); -MAKE_AV7110_INFO(tts_2_3, "Technotrend/Hauppauge WinTV Nexus-S rev2.3"); -MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE"); -MAKE_AV7110_INFO(ttt, "Technotrend/Hauppauge DVB-T"); -MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); -MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); -MAKE_AV7110_INFO(gxs_1_3, "Galaxis DVB-S rev1.3"); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), - MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000), - MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), - MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), - MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), - MAKE_EXTENSION_PCI(gxs_1_3, 0x13c2, 0x0004), - MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), - MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), - MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), - MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), - MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), - -/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 -/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v???? - - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - - -static struct saa7146_extension av7110_extension_driver = { - .name = "av7110", - .flags = SAA7146_USE_I2C_IRQ, - - .module = THIS_MODULE, - .pci_tbl = &pci_tbl[0], - .attach = av7110_attach, - .detach = __devexit_p(av7110_detach), - - .irq_mask = MASK_19 | MASK_03 | MASK_10, - .irq_func = av7110_irq, -}; - - -static int __init av7110_init(void) -{ - int retval; - retval = saa7146_register_extension(&av7110_extension_driver); - return retval; -} - - -static void __exit av7110_exit(void) -{ - saa7146_unregister_extension(&av7110_extension_driver); -} - -module_init(av7110_init); -module_exit(av7110_exit); - -MODULE_DESCRIPTION("driver for the SAA7146 based AV110 PCI DVB cards by " - "Siemens, Technotrend, Hauppauge"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ca.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ca.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ca.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ca.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,387 +0,0 @@ -/* - * av7110_ca.c: CA and CI stuff - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" -#include "av7110_ca.h" - - -void CI_handle(struct av7110 *av7110, u8 *data, u16 len) -{ - dprintk(8, "av7110:%p\n",av7110); - - if (len < 3) - return; - switch (data[0]) { - case CI_MSG_CI_INFO: - if (data[2] != 1 && data[2] != 2) - break; - switch (data[1]) { - case 0: - av7110->ci_slot[data[2] - 1].flags = 0; - break; - case 1: - av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT; - break; - case 2: - av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY; - break; - } - break; - case CI_SWITCH_PRG_REPLY: - //av7110->ci_stat=data[1]; - break; - default: - break; - } -} - - -void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len) -{ - if (dvb_ringbuffer_free(cibuf) < len + 2) - return; - - DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8); - DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff); - dvb_ringbuffer_write(cibuf, data, len); - wake_up_interruptible(&cibuf->queue); -} - - -/****************************************************************************** - * CI link layer file ops - ******************************************************************************/ - -static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size) -{ - struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p; - void *data; - - for (p = tab; *p; p++) { - data = vmalloc(size); - if (!data) { - while (p-- != tab) { - vfree(p[0]->data); - p[0]->data = NULL; - } - return -ENOMEM; - } - dvb_ringbuffer_init(*p, data, size); - } - return 0; -} - -static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) -{ - dvb_ringbuffer_flush_spinlock_wakeup(cirbuf); - dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf); -} - -static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) -{ - vfree(cirbuf->data); - cirbuf->data = NULL; - vfree(ciwbuf->data); - ciwbuf->data = NULL; -} - -static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, - int slots, ca_slot_info_t *slot) -{ - int i; - int len = 0; - u8 msg[8] = { 0x00, 0x06, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00 }; - - for (i = 0; i < 2; i++) { - if (slots & (1 << i)) - len += 8; - } - - if (dvb_ringbuffer_free(cibuf) < len) - return -EBUSY; - - for (i = 0; i < 2; i++) { - if (slots & (1 << i)) { - msg[2] = i; - dvb_ringbuffer_write(cibuf, msg, 8); - slot[i].flags = 0; - } - } - - return 0; -} - -static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - int free; - int non_blocking = file->f_flags & O_NONBLOCK; - u8 *page = (u8 *)__get_free_page(GFP_USER); - int res; - - if (!page) - return -ENOMEM; - - res = -EINVAL; - if (count > 2048) - goto out; - - res = -EFAULT; - if (copy_from_user(page, buf, count)) - goto out; - - free = dvb_ringbuffer_free(cibuf); - if (count + 2 > free) { - res = -EWOULDBLOCK; - if (non_blocking) - goto out; - res = -ERESTARTSYS; - if (wait_event_interruptible(cibuf->queue, - (dvb_ringbuffer_free(cibuf) >= count + 2))) - goto out; - } - - DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8); - DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff); - - res = dvb_ringbuffer_write(cibuf, page, count); -out: - free_page((unsigned long)page); - return res; -} - -static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file, - char __user *buf, size_t count, loff_t *ppos) -{ - int avail; - int non_blocking = file->f_flags & O_NONBLOCK; - ssize_t len; - - if (!cibuf->data || !count) - return 0; - if (non_blocking && (dvb_ringbuffer_empty(cibuf))) - return -EWOULDBLOCK; - if (wait_event_interruptible(cibuf->queue, - !dvb_ringbuffer_empty(cibuf))) - return -ERESTARTSYS; - avail = dvb_ringbuffer_avail(cibuf); - if (avail < 4) - return 0; - len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; - len |= DVB_RINGBUFFER_PEEK(cibuf, 1); - if (avail < len + 2 || count < len) - return -EINVAL; - DVB_RINGBUFFER_SKIP(cibuf, 2); - - return dvb_ringbuffer_read_user(cibuf, buf, len); -} - -static int dvb_ca_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - int err = dvb_generic_open(inode, file); - - dprintk(8, "av7110:%p\n",av7110); - - if (err < 0) - return err; - ci_ll_flush(&av7110->ci_rbuffer, &av7110->ci_wbuffer); - return 0; -} - -static unsigned int dvb_ca_poll (struct file *file, poll_table *wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer; - struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer; - unsigned int mask = 0; - - dprintk(8, "av7110:%p\n",av7110); - - poll_wait(file, &rbuf->queue, wait); - poll_wait(file, &wbuf->queue, wait); - - if (!dvb_ringbuffer_empty(rbuf)) - mask |= (POLLIN | POLLRDNORM); - - if (dvb_ringbuffer_free(wbuf) > 1024) - mask |= (POLLOUT | POLLWRNORM); - - return mask; -} - -static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - unsigned long arg = (unsigned long) parg; - - dprintk(8, "av7110:%p\n",av7110); - - switch (cmd) { - case CA_RESET: - return ci_ll_reset(&av7110->ci_wbuffer, file, arg, &av7110->ci_slot[0]); - break; - case CA_GET_CAP: - { - ca_caps_t cap; - - cap.slot_num = 2; - cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ? - CA_CI_LINK : CA_CI) | CA_DESCR; - cap.descr_num = 16; - cap.descr_type = CA_ECD; - memcpy(parg, &cap, sizeof(cap)); - break; - } - - case CA_GET_SLOT_INFO: - { - ca_slot_info_t *info=(ca_slot_info_t *)parg; - - if (info->num < 0 || info->num > 1) - return -EINVAL; - av7110->ci_slot[info->num].num = info->num; - av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? - CA_CI_LINK : CA_CI; - memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); - break; - } - - case CA_GET_MSG: - break; - - case CA_SEND_MSG: - break; - - case CA_GET_DESCR_INFO: - { - ca_descr_info_t info; - - info.num = 16; - info.type = CA_ECD; - memcpy(parg, &info, sizeof (info)); - break; - } - - case CA_SET_DESCR: - { - ca_descr_t *descr = (ca_descr_t*) parg; - - if (descr->index >= 16) - return -EINVAL; - if (descr->parity > 1) - return -EINVAL; - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5, - (descr->index<<8)|descr->parity, - (descr->cw[0]<<8)|descr->cw[1], - (descr->cw[2]<<8)|descr->cw[3], - (descr->cw[4]<<8)|descr->cw[5], - (descr->cw[6]<<8)|descr->cw[7]); - break; - } - - default: - return -EINVAL; - } - return 0; -} - -static ssize_t dvb_ca_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(8, "av7110:%p\n",av7110); - return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos); -} - -static ssize_t dvb_ca_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct dvb_device *dvbdev = file->private_data; - struct av7110 *av7110 = dvbdev->priv; - - dprintk(8, "av7110:%p\n",av7110); - return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos); -} - -static const struct file_operations dvb_ca_fops = { - .owner = THIS_MODULE, - .read = dvb_ca_read, - .write = dvb_ca_write, - .unlocked_ioctl = dvb_generic_ioctl, - .open = dvb_ca_open, - .release = dvb_generic_release, - .poll = dvb_ca_poll, - .llseek = default_llseek, -}; - -static struct dvb_device dvbdev_ca = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_ca_fops, - .kernel_ioctl = dvb_ca_ioctl, -}; - - -int av7110_ca_register(struct av7110 *av7110) -{ - return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev, - &dvbdev_ca, av7110, DVB_DEVICE_CA); -} - -void av7110_ca_unregister(struct av7110 *av7110) -{ - dvb_unregister_device(av7110->ca_dev); -} - -int av7110_ca_init(struct av7110* av7110) -{ - return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192); -} - -void av7110_ca_exit(struct av7110* av7110) -{ - ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ca.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ca.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ca.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ca.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -#ifndef _AV7110_CA_H_ -#define _AV7110_CA_H_ - -struct av7110; - -extern void CI_handle(struct av7110 *av7110, u8 *data, u16 len); -extern void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len); - -extern int av7110_ca_register(struct av7110 *av7110); -extern void av7110_ca_unregister(struct av7110 *av7110); -extern int av7110_ca_init(struct av7110* av7110); -extern void av7110_ca_exit(struct av7110* av7110); - -#endif /* _AV7110_CA_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,315 +0,0 @@ -#ifndef _AV7110_H_ -#define _AV7110_H_ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "dvbdev.h" -#include "demux.h" -#include "dvb_demux.h" -#include "dmxdev.h" -#include "dvb_filter.h" -#include "dvb_net.h" -#include "dvb_ringbuffer.h" -#include "dvb_frontend.h" -#include "ves1820.h" -#include "ves1x93.h" -#include "stv0299.h" -#include "tda8083.h" -#include "sp8870.h" -#include "stv0297.h" -#include "l64781.h" - -#include - - -#define ANALOG_TUNER_VES1820 1 -#define ANALOG_TUNER_STV0297 2 - -extern int av7110_debug; - -#define dprintk(level,args...) \ - do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __func__); printk(args); } } while (0) - -#define MAXFILT 32 - -enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM}; - -enum av7110_video_mode { - AV7110_VIDEO_MODE_PAL = 0, - AV7110_VIDEO_MODE_NTSC = 1 -}; - -struct av7110_p2t { - u8 pes[TS_SIZE]; - u8 counter; - long int pos; - int frags; - struct dvb_demux_feed *feed; -}; - -/* video MPEG decoder events: */ -/* (code copied from dvb_frontend.c, should maybe be factored out...) */ -#define MAX_VIDEO_EVENT 8 -struct dvb_video_events { - struct video_event events[MAX_VIDEO_EVENT]; - int eventw; - int eventr; - int overflow; - wait_queue_head_t wait_queue; - spinlock_t lock; -}; - - -struct av7110; - -/* infrared remote control */ -struct infrared { - u16 key_map[256]; - struct input_dev *input_dev; - char input_phys[32]; - struct timer_list keyup_timer; - struct tasklet_struct ir_tasklet; - void (*ir_handler)(struct av7110 *av7110, u32 ircom); - u32 ir_command; - u32 ir_config; - u32 device_mask; - u8 protocol; - u8 inversion; - u16 last_key; - u16 last_toggle; - u8 delay_timer_finished; -}; - - -/* place to store all the necessary device information */ -struct av7110 { - - /* devices */ - - struct dvb_device dvb_dev; - struct dvb_net dvb_net; - - struct video_device *v4l_dev; - struct video_device *vbi_dev; - - struct saa7146_dev *dev; - - struct i2c_adapter i2c_adap; - - char *card_name; - - /* support for analog module of dvb-c */ - int analog_tuner_flags; - int current_input; - u32 current_freq; - - struct tasklet_struct debi_tasklet; - struct tasklet_struct gpio_tasklet; - - int adac_type; /* audio DAC type */ -#define DVB_ADAC_TI 0 -#define DVB_ADAC_CRYSTAL 1 -#define DVB_ADAC_MSP34x0 2 -#define DVB_ADAC_MSP34x5 3 -#define DVB_ADAC_NONE -1 - - - /* buffers */ - - void *iobuf; /* memory for all buffers */ - struct dvb_ringbuffer avout; /* buffer for video or A/V mux */ -#define AVOUTLEN (128*1024) - struct dvb_ringbuffer aout; /* buffer for audio */ -#define AOUTLEN (64*1024) - void *bmpbuf; -#define BMPLEN (8*32768+1024) - - /* bitmap buffers and states */ - - int bmpp; - int bmplen; - volatile int bmp_state; -#define BMP_NONE 0 -#define BMP_LOADING 1 -#define BMP_LOADED 2 - wait_queue_head_t bmpq; - - - /* DEBI and polled command interface */ - - spinlock_t debilock; - struct mutex dcomlock; - volatile int debitype; - volatile int debilen; - - - /* Recording and playback flags */ - - int rec_mode; - int playing; -#define RP_NONE 0 -#define RP_VIDEO 1 -#define RP_AUDIO 2 -#define RP_AV 3 - - - /* OSD */ - - int osdwin; /* currently active window */ - u16 osdbpp[8]; - struct mutex osd_mutex; - - /* CA */ - - ca_slot_info_t ci_slot[2]; - - enum av7110_video_mode vidmode; - struct dmxdev dmxdev; - struct dvb_demux demux; - - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - - /* for budget mode demux1 */ - struct dmxdev dmxdev1; - struct dvb_demux demux1; - struct dvb_net dvb_net1; - spinlock_t feedlock1; - int feeding1; - u32 ttbp; - unsigned char *grabbing; - struct saa7146_pgtable pt; - struct tasklet_struct vpe_tasklet; - bool full_ts; - - int fe_synced; - struct mutex pid_mutex; - - int video_blank; - struct video_status videostate; - u16 display_panscan; - int display_ar; - int trickmode; -#define TRICK_NONE 0 -#define TRICK_FAST 1 -#define TRICK_SLOW 2 -#define TRICK_FREEZE 3 - struct audio_status audiostate; - - struct dvb_demux_filter *handle2filter[32]; - struct av7110_p2t p2t_filter[MAXFILT]; - struct dvb_filter_pes2ts p2t[2]; - struct ipack ipack[2]; - u8 *kbuf[2]; - - int sinfo; - int feeding; - - int arm_errors; - int registered; - - - /* AV711X */ - - u32 arm_fw; - u32 arm_rtsl; - u32 arm_vid; - u32 arm_app; - u32 avtype; - int arm_ready; - struct task_struct *arm_thread; - wait_queue_head_t arm_wait; - u16 arm_loops; - - void *debi_virt; - dma_addr_t debi_bus; - - u16 pids[DMX_PES_OTHER]; - - struct dvb_ringbuffer ci_rbuffer; - struct dvb_ringbuffer ci_wbuffer; - - struct audio_mixer mixer; - - struct dvb_adapter dvb_adapter; - struct dvb_device *video_dev; - struct dvb_device *audio_dev; - struct dvb_device *ca_dev; - struct dvb_device *osd_dev; - - struct dvb_video_events video_events; - video_size_t video_size; - - u16 wssMode; - u16 wssData; - - struct infrared ir; - - /* firmware stuff */ - unsigned char *bin_fw; - unsigned long size_fw; - - unsigned char *bin_dpram; - unsigned long size_dpram; - - unsigned char *bin_root; - unsigned long size_root; - - struct dvb_frontend* fe; - fe_status_t fe_status; - - /* crash recovery */ - void (*recover)(struct av7110* av7110); - struct dvb_frontend_parameters saved_fe_params; - fe_sec_voltage_t saved_voltage; - fe_sec_tone_mode_t saved_tone; - struct dvb_diseqc_master_cmd saved_master_cmd; - fe_sec_mini_cmd_t saved_minicmd; - - int (*fe_init)(struct dvb_frontend* fe); - int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); - int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); - int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); - int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); - int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); - int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); - int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); - int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); -}; - - -extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, - u16 subpid, u16 pcrpid); - -extern int av7110_check_ir_config(struct av7110 *av7110, int force); -extern int av7110_ir_init(struct av7110 *av7110); -extern void av7110_ir_exit(struct av7110 *av7110); - -/* msp3400 i2c subaddresses */ -#define MSP_WR_DEM 0x10 -#define MSP_RD_DEM 0x11 -#define MSP_WR_DSP 0x12 -#define MSP_RD_DSP 0x13 - -extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val); -extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg); -extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val); - - -extern int av7110_init_analog_module(struct av7110 *av7110); -extern int av7110_init_v4l(struct av7110 *av7110); -extern int av7110_exit_v4l(struct av7110 *av7110); - -#endif /* _AV7110_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_hw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_hw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_hw.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_hw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1208 +0,0 @@ -/* - * av7110_hw.c: av7110 low level hardware access and firmware interface - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * 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, or (at your option) any later version. - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * the project's page is at http://www.linuxtv.org/ - */ - -/* for debugging ARM communication: */ -//#define COM_DEBUG - -#include -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" - -#define _NOHANDSHAKE - -/**************************************************************************** - * DEBI functions - ****************************************************************************/ - -/* This DEBI code is based on the Stradis driver - by Nathan Laredo */ - -int av7110_debiwrite(struct av7110 *av7110, u32 config, - int addr, u32 val, int count) -{ - struct saa7146_dev *dev = av7110->dev; - - if (count <= 0 || count > 32764) { - printk("%s: invalid count %d\n", __func__, count); - return -1; - } - if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { - printk("%s: wait_for_debi_done failed\n", __func__); - return -1; - } - saa7146_write(dev, DEBI_CONFIG, config); - if (count <= 4) /* immediate transfer */ - saa7146_write(dev, DEBI_AD, val); - else /* block transfer */ - saa7146_write(dev, DEBI_AD, av7110->debi_bus); - saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff)); - saa7146_write(dev, MC2, (2 << 16) | 2); - return 0; -} - -u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count) -{ - struct saa7146_dev *dev = av7110->dev; - u32 result = 0; - - if (count > 32764 || count <= 0) { - printk("%s: invalid count %d\n", __func__, count); - return 0; - } - if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { - printk("%s: wait_for_debi_done #1 failed\n", __func__); - return 0; - } - saa7146_write(dev, DEBI_AD, av7110->debi_bus); - saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); - - saa7146_write(dev, DEBI_CONFIG, config); - saa7146_write(dev, MC2, (2 << 16) | 2); - if (count > 4) - return count; - if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { - printk("%s: wait_for_debi_done #2 failed\n", __func__); - return 0; - } - - result = saa7146_read(dev, DEBI_AD); - result &= (0xffffffffUL >> ((4 - count) * 8)); - return result; -} - - - -/* av7110 ARM core boot stuff */ -#if 0 -void av7110_reset_arm(struct av7110 *av7110) -{ - saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO); - - /* Disable DEBI and GPIO irq */ - SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); - - saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI); - msleep(30); /* the firmware needs some time to initialize */ - - ARM_ResetMailBox(av7110); - - SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); - SAA7146_IER_ENABLE(av7110->dev, MASK_03); - - av7110->arm_ready = 1; - dprintk(1, "reset ARM\n"); -} -#endif /* 0 */ - -static int waitdebi(struct av7110 *av7110, int adr, int state) -{ - int k; - - dprintk(4, "%p\n", av7110); - - for (k = 0; k < 100; k++) { - if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state) - return 0; - udelay(5); - } - return -ETIMEDOUT; -} - -static int load_dram(struct av7110 *av7110, u32 *data, int len) -{ - int i; - int blocks, rest; - u32 base, bootblock = AV7110_BOOT_BLOCK; - - dprintk(4, "%p\n", av7110); - - blocks = len / AV7110_BOOT_MAX_SIZE; - rest = len % AV7110_BOOT_MAX_SIZE; - base = DRAM_START_CODE; - - for (i = 0; i < blocks; i++) { - if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { - printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); - return -ETIMEDOUT; - } - dprintk(4, "writing DRAM block %d\n", i); - mwdebi(av7110, DEBISWAB, bootblock, - ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE); - bootblock ^= 0x1400; - iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - base += AV7110_BOOT_MAX_SIZE; - } - - if (rest > 0) { - if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { - printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); - return -ETIMEDOUT; - } - if (rest > 4) - mwdebi(av7110, DEBISWAB, bootblock, - ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest); - else - mwdebi(av7110, DEBISWAB, bootblock, - ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4); - - iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - } - if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { - printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); - return -ETIMEDOUT; - } - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) { - printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); - return -ETIMEDOUT; - } - return 0; -} - - -/* we cannot write av7110 DRAM directly, so load a bootloader into - * the DPRAM which implements a simple boot protocol */ -int av7110_bootarm(struct av7110 *av7110) -{ - const struct firmware *fw; - const char *fw_name = "av7110/bootcode.bin"; - struct saa7146_dev *dev = av7110->dev; - u32 ret; - int i; - - dprintk(4, "%p\n", av7110); - - av7110->arm_ready = 0; - - saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); - - /* Disable DEBI and GPIO irq */ - SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); - - /* enable DEBI */ - saa7146_write(av7110->dev, MC1, 0x08800880); - saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); - saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - /* test DEBI */ - iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); - /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */ - iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); - - if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) { - printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: " - "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n", - ret, 0x10325476); - return -1; - } - for (i = 0; i < 8192; i += 4) - iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4); - dprintk(2, "debi test OK\n"); - - /* boot */ - dprintk(1, "load boot code\n"); - saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO); - //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT); - //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT); - - ret = request_firmware(&fw, fw_name, &dev->pci->dev); - if (ret) { - printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n", - fw_name); - return ret; - } - - mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size); - release_firmware(fw); - iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - - if (saa7146_wait_for_debi_done(av7110->dev, 1)) { - printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " - "saa7146_wait_for_debi_done() timed out\n"); - return -ETIMEDOUT; - } - saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); - mdelay(1); - - dprintk(1, "load dram code\n"); - if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) { - printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " - "load_dram() failed\n"); - return -1; - } - - saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); - mdelay(1); - - dprintk(1, "load dpram code\n"); - mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram); - - if (saa7146_wait_for_debi_done(av7110->dev, 1)) { - printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " - "saa7146_wait_for_debi_done() timed out after loading DRAM\n"); - return -ETIMEDOUT; - } - saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); - msleep(30); /* the firmware needs some time to initialize */ - - //ARM_ClearIrq(av7110); - ARM_ResetMailBox(av7110); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); - SAA7146_IER_ENABLE(av7110->dev, MASK_03); - - av7110->arm_errors = 0; - av7110->arm_ready = 1; - return 0; -} -MODULE_FIRMWARE("av7110/bootcode.bin"); - -/**************************************************************************** - * DEBI command polling - ****************************************************************************/ - -int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) -{ - unsigned long start; - u32 stat; - int err; - - if (FW_VERSION(av7110->arm_app) <= 0x261c) { - /* not supported by old firmware */ - msleep(50); - return 0; - } - - /* new firmware */ - start = jiffies; - for (;;) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); - mutex_unlock(&av7110->dcomlock); - if ((stat & flags) == 0) - break; - if (err) { - printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", - __func__, stat & flags); - return -ETIMEDOUT; - } - msleep(1); - } - return 0; -} - -static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) -{ - int i; - unsigned long start; - char *type = NULL; - u16 flags[2] = {0, 0}; - u32 stat; - int err; - -// dprintk(4, "%p\n", av7110); - - if (!av7110->arm_ready) { - dprintk(1, "arm not ready.\n"); - return -ENXIO; - } - - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__); - av7110->arm_errors++; - return -ETIMEDOUT; - } - msleep(1); - } - - if (FW_VERSION(av7110->arm_app) <= 0x261f) - wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); - -#ifndef _NOHANDSHAKE - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_SHAKE); - if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__); - return -ETIMEDOUT; - } - msleep(1); - } -#endif - - switch ((buf[0] >> 8) & 0xff) { - case COMTYPE_PIDFILTER: - case COMTYPE_ENCODER: - case COMTYPE_REC_PLAY: - case COMTYPE_MPEGDECODER: - type = "MSG"; - flags[0] = GPMQOver; - flags[1] = GPMQFull; - break; - case COMTYPE_OSD: - type = "OSD"; - flags[0] = OSDQOver; - flags[1] = OSDQFull; - break; - case COMTYPE_MISC: - if (FW_VERSION(av7110->arm_app) >= 0x261d) { - type = "MSG"; - flags[0] = GPMQOver; - flags[1] = GPMQBusy; - } - break; - default: - break; - } - - if (type != NULL) { - /* non-immediate COMMAND type */ - start = jiffies; - for (;;) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); - if (stat & flags[0]) { - printk(KERN_ERR "%s: %s QUEUE overflow\n", - __func__, type); - return -1; - } - if ((stat & flags[1]) == 0) - break; - if (err) { - printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", - __func__, type); - av7110->arm_errors++; - return -ETIMEDOUT; - } - msleep(1); - } - } - - for (i = 2; i < length; i++) - wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2); - - if (length) - wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2); - else - wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2); - - wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2); - - if (FW_VERSION(av7110->arm_app) <= 0x261f) - wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); - -#ifdef COM_DEBUG - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", - __func__, (buf[0] >> 8) & 0xff); - return -ETIMEDOUT; - } - msleep(1); - } - - stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); - if (stat & GPMQOver) { - printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__); - return -ENOSPC; - } - else if (stat & OSDQOver) { - printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__); - return -ENOSPC; - } -#endif - - return 0; -} - -static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) -{ - int ret; - -// dprintk(4, "%p\n", av7110); - - if (!av7110->arm_ready) { - dprintk(1, "arm not ready.\n"); - return -1; - } - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - - ret = __av7110_send_fw_cmd(av7110, buf, length); - mutex_unlock(&av7110->dcomlock); - if (ret && ret!=-ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n", - __func__, ret); - return ret; -} - -int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) -{ - va_list args; - u16 buf[num + 2]; - int i, ret; - -// dprintk(4, "%p\n", av7110); - - buf[0] = ((type << 8) | com); - buf[1] = num; - - if (num) { - va_start(args, num); - for (i = 0; i < num; i++) - buf[i + 2] = va_arg(args, u32); - va_end(args); - } - - ret = av7110_send_fw_cmd(av7110, buf, num + 2); - if (ret && ret != -ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret); - return ret; -} - -#if 0 -int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) -{ - int i, ret; - u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom), - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - dprintk(4, "%p\n", av7110); - - for(i = 0; i < len && i < 32; i++) - { - if(i % 2 == 0) - cmd[(i / 2) + 2] = (u16)(buf[i]) << 8; - else - cmd[(i / 2) + 2] |= buf[i]; - } - - ret = av7110_send_fw_cmd(av7110, cmd, 18); - if (ret && ret != -ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); - return ret; -} -#endif /* 0 */ - -int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, - int request_buf_len, u16 *reply_buf, int reply_buf_len) -{ - int err; - s16 i; - unsigned long start; -#ifdef COM_DEBUG - u32 stat; -#endif - - dprintk(4, "%p\n", av7110); - - if (!av7110->arm_ready) { - dprintk(1, "arm not ready.\n"); - return -1; - } - - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - - if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) { - mutex_unlock(&av7110->dcomlock); - printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err); - return err; - } - - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_FREE); - if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } -#ifdef _NOHANDSHAKE - msleep(1); -#endif - } - -#ifndef _NOHANDSHAKE - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_SHAKE); - if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } - msleep(1); - } -#endif - -#ifdef COM_DEBUG - stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); - if (stat & GPMQOver) { - printk(KERN_ERR "%s: GPMQOver\n", __func__); - mutex_unlock(&av7110->dcomlock); - return -1; - } - else if (stat & OSDQOver) { - printk(KERN_ERR "%s: OSDQOver\n", __func__); - mutex_unlock(&av7110->dcomlock); - return -1; - } -#endif - - for (i = 0; i < reply_buf_len; i++) - reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2); - - mutex_unlock(&av7110->dcomlock); - return 0; -} - -static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length) -{ - int ret; - ret = av7110_fw_request(av7110, &tag, 0, buf, length); - if (ret) - printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret); - return ret; -} - - -/**************************************************************************** - * Firmware commands - ****************************************************************************/ - -/* get version of the firmware ROM, RTSL, video ucode and ARM application */ -int av7110_firmversion(struct av7110 *av7110) -{ - u16 buf[20]; - u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion); - - dprintk(4, "%p\n", av7110); - - if (av7110_fw_query(av7110, tag, buf, 16)) { - printk("dvb-ttpci: failed to boot firmware @ card %d\n", - av7110->dvb_adapter.num); - return -EIO; - } - - av7110->arm_fw = (buf[0] << 16) + buf[1]; - av7110->arm_rtsl = (buf[2] << 16) + buf[3]; - av7110->arm_vid = (buf[4] << 16) + buf[5]; - av7110->arm_app = (buf[6] << 16) + buf[7]; - av7110->avtype = (buf[8] << 16) + buf[9]; - - printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n", - av7110->dvb_adapter.num, av7110->arm_fw, - av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app); - - /* print firmware capabilities */ - if (FW_CI_LL_SUPPORT(av7110->arm_app)) - printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n", - av7110->dvb_adapter.num); - else - printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n", - av7110->dvb_adapter.num); - - return 0; -} - - -int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst) -{ - int i, ret; - u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC), - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - dprintk(4, "%p\n", av7110); - - if (len > 10) - len = 10; - - buf[1] = len + 2; - buf[2] = len; - - if (burst != -1) - buf[3] = burst ? 0x01 : 0x00; - else - buf[3] = 0xffff; - - for (i = 0; i < len; i++) - buf[i + 4] = msg[i]; - - ret = av7110_send_fw_cmd(av7110, buf, 18); - if (ret && ret!=-ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret); - return ret; -} - - -#ifdef CONFIG_DVB_AV7110_OSD - -static inline int SetColorBlend(struct av7110 *av7110, u8 windownr) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr); -} - -static inline int SetBlend_(struct av7110 *av7110, u8 windownr, - enum av7110_osd_palette_type colordepth, u16 index, u8 blending) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4, - windownr, colordepth, index, blending); -} - -static inline int SetColor_(struct av7110 *av7110, u8 windownr, - enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5, - windownr, colordepth, index, colorhi, colorlo); -} - -static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize, - u16 colorfg, u16 colorbg) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4, - windownr, fontsize, colorfg, colorbg); -} - -static int FlushText(struct av7110 *av7110) -{ - unsigned long start; - int err; - - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - start = jiffies; - while (1) { - err = time_after(jiffies, start + ARM_WAIT_OSD); - if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) - break; - if (err) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", - __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } - msleep(1); - } - mutex_unlock(&av7110->dcomlock); - return 0; -} - -static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf) -{ - int i, ret; - unsigned long start; - int length = strlen(buf) + 1; - u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y }; - - if (mutex_lock_interruptible(&av7110->dcomlock)) - return -ERESTARTSYS; - - start = jiffies; - while (1) { - ret = time_after(jiffies, start + ARM_WAIT_OSD); - if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) - break; - if (ret) { - printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", - __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } - msleep(1); - } -#ifndef _NOHANDSHAKE - start = jiffies; - while (1) { - ret = time_after(jiffies, start + ARM_WAIT_SHAKE); - if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) - break; - if (ret) { - printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", - __func__); - mutex_unlock(&av7110->dcomlock); - return -ETIMEDOUT; - } - msleep(1); - } -#endif - for (i = 0; i < length / 2; i++) - wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, - swab16(*(u16 *)(buf + 2 * i)), 2); - if (length & 1) - wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2); - ret = __av7110_send_fw_cmd(av7110, cbuf, 5); - mutex_unlock(&av7110->dcomlock); - if (ret && ret!=-ERESTARTSYS) - printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret); - return ret; -} - -static inline int DrawLine(struct av7110 *av7110, u8 windownr, - u16 x, u16 y, u16 dx, u16 dy, u16 color) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6, - windownr, x, y, dx, dy, color); -} - -static inline int DrawBlock(struct av7110 *av7110, u8 windownr, - u16 x, u16 y, u16 dx, u16 dy, u16 color) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6, - windownr, x, y, dx, dy, color); -} - -static inline int HideWindow(struct av7110 *av7110, u8 windownr) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr); -} - -static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y); -} - -static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y); -} - -static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr); -} - -static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr, - osd_raw_window_t disptype, - u16 width, u16 height) -{ - return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4, - windownr, disptype, width, height); -} - - -static enum av7110_osd_palette_type bpp2pal[8] = { - Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit -}; -static osd_raw_window_t bpp2bit[8] = { - OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8 -}; - -static inline int WaitUntilBmpLoaded(struct av7110 *av7110) -{ - int ret = wait_event_timeout(av7110->bmpq, - av7110->bmp_state != BMP_LOADING, 10*HZ); - if (ret == 0) { - printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", - ret, av7110->bmp_state); - av7110->bmp_state = BMP_NONE; - return -ETIMEDOUT; - } - return 0; -} - -static inline int LoadBitmap(struct av7110 *av7110, - u16 dx, u16 dy, int inc, u8 __user * data) -{ - u16 format; - int bpp; - int i; - int d, delta; - u8 c; - int ret; - - dprintk(4, "%p\n", av7110); - - format = bpp2bit[av7110->osdbpp[av7110->osdwin]]; - - av7110->bmp_state = BMP_LOADING; - if (format == OSD_BITMAP8) { - bpp=8; delta = 1; - } else if (format == OSD_BITMAP4) { - bpp=4; delta = 2; - } else if (format == OSD_BITMAP2) { - bpp=2; delta = 4; - } else if (format == OSD_BITMAP1) { - bpp=1; delta = 8; - } else { - av7110->bmp_state = BMP_NONE; - return -EINVAL; - } - av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8; - av7110->bmpp = 0; - if (av7110->bmplen > 32768) { - av7110->bmp_state = BMP_NONE; - return -EINVAL; - } - for (i = 0; i < dy; i++) { - if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) { - av7110->bmp_state = BMP_NONE; - return -EINVAL; - } - } - if (format != OSD_BITMAP8) { - for (i = 0; i < dx * dy / delta; i++) { - c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1]; - for (d = delta - 2; d >= 0; d--) { - c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d] - << ((delta - d - 1) * bpp)); - ((u8 *)av7110->bmpbuf)[1024 + i] = c; - } - } - } - av7110->bmplen += 1024; - dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen); - ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); - if (!ret) - ret = WaitUntilBmpLoaded(av7110); - return ret; -} - -static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y) -{ - dprintk(4, "%p\n", av7110); - - return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0); -} - -static inline int ReleaseBitmap(struct av7110 *av7110) -{ - dprintk(4, "%p\n", av7110); - - if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e) - return -1; - if (av7110->bmp_state == BMP_LOADING) - dprintk(1,"ReleaseBitmap called while BMP_LOADING\n"); - av7110->bmp_state = BMP_NONE; - return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0); -} - -static u32 RGB2YUV(u16 R, u16 G, u16 B) -{ - u16 y, u, v; - u16 Y, Cr, Cb; - - y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */ - u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */ - v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */ - - Y = y / 256; - Cb = u / 16; - Cr = v / 16; - - return Cr | (Cb << 16) | (Y << 8); -} - -static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) -{ - int ret; - - u16 ch, cl; - u32 yuv; - - yuv = blend ? RGB2YUV(r,g,b) : 0; - cl = (yuv & 0xffff); - ch = ((yuv >> 16) & 0xffff); - ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], - color, ch, cl); - if (!ret) - ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], - color, ((blend >> 4) & 0x0f)); - return ret; -} - -static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) -{ - int i; - int length = last - first + 1; - - if (length * 4 > DATA_BUFF3_SIZE) - return -EINVAL; - - for (i = 0; i < length; i++) { - u32 color, blend, yuv; - - if (get_user(color, colors + i)) - return -EFAULT; - blend = (color & 0xF0000000) >> 4; - yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, - (color >> 16) & 0xFF) | blend : 0; - yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); - wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); - } - return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, - av7110->osdwin, - bpp2pal[av7110->osdbpp[av7110->osdwin]], - first, last); -} - -static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, - int x1, int y1, int inc, u8 __user * data) -{ - uint w, h, bpp, bpl, size, lpb, bnum, brest; - int i; - int rc,release_rc; - - w = x1 - x0 + 1; - h = y1 - y0 + 1; - if (inc <= 0) - inc = w; - if (w <= 0 || w > 720 || h <= 0 || h > 576) - return -EINVAL; - bpp = av7110->osdbpp[av7110->osdwin] + 1; - bpl = ((w * bpp + 7) & ~7) / 8; - size = h * bpl; - lpb = (32 * 1024) / bpl; - bnum = size / (lpb * bpl); - brest = size - bnum * lpb * bpl; - - if (av7110->bmp_state == BMP_LOADING) { - /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */ - BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e); - rc = WaitUntilBmpLoaded(av7110); - if (rc) - return rc; - /* just continue. This should work for all fw versions - * if bnum==1 && !brest && LoadBitmap was successful - */ - } - - rc = 0; - for (i = 0; i < bnum; i++) { - rc = LoadBitmap(av7110, w, lpb, inc, data); - if (rc) - break; - rc = BlitBitmap(av7110, x0, y0 + i * lpb); - if (rc) - break; - data += lpb * inc; - } - if (!rc && brest) { - rc = LoadBitmap(av7110, w, brest / bpl, inc, data); - if (!rc) - rc = BlitBitmap(av7110, x0, y0 + bnum * lpb); - } - release_rc = ReleaseBitmap(av7110); - if (!rc) - rc = release_rc; - if (rc) - dprintk(1,"returns %d\n",rc); - return rc; -} - -int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc) -{ - int ret; - - if (mutex_lock_interruptible(&av7110->osd_mutex)) - return -ERESTARTSYS; - - switch (dc->cmd) { - case OSD_Close: - ret = DestroyOSDWindow(av7110, av7110->osdwin); - break; - case OSD_Open: - av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7; - ret = CreateOSDWindow(av7110, av7110->osdwin, - bpp2bit[av7110->osdbpp[av7110->osdwin]], - dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); - if (ret) - break; - if (!dc->data) { - ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - if (ret) - break; - ret = SetColorBlend(av7110, av7110->osdwin); - } - break; - case OSD_Show: - ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0); - break; - case OSD_Hide: - ret = HideWindow(av7110, av7110->osdwin); - break; - case OSD_Clear: - ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); - break; - case OSD_Fill: - ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); - break; - case OSD_SetColor: - ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); - break; - case OSD_SetPalette: - if (FW_VERSION(av7110->arm_app) >= 0x2618) - ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0); - else { - int i, len = dc->x0-dc->color+1; - u8 __user *colors = (u8 __user *)dc->data; - u8 r, g = 0, b = 0, blend = 0; - ret = 0; - for (i = 0; icolor + i, r, g, b, blend); - if (ret) - break; - } - } - break; - case OSD_SetPixel: - ret = DrawLine(av7110, av7110->osdwin, - dc->x0, dc->y0, 0, 0, dc->color); - break; - case OSD_SetRow: - dc->y1 = dc->y0; - /* fall through */ - case OSD_SetBlock: - ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); - break; - case OSD_FillRow: - ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, - dc->x1-dc->x0+1, dc->y1, dc->color); - break; - case OSD_FillBlock: - ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, - dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color); - break; - case OSD_Line: - ret = DrawLine(av7110, av7110->osdwin, - dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color); - break; - case OSD_Text: - { - char textbuf[240]; - - if (strncpy_from_user(textbuf, dc->data, 240) < 0) { - ret = -EFAULT; - break; - } - textbuf[239] = 0; - if (dc->x1 > 3) - dc->x1 = 3; - ret = SetFont(av7110, av7110->osdwin, dc->x1, - (u16) (dc->color & 0xffff), (u16) (dc->color >> 16)); - if (!ret) - ret = FlushText(av7110); - if (!ret) - ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); - break; - } - case OSD_SetWindow: - if (dc->x0 < 1 || dc->x0 > 7) - ret = -EINVAL; - else { - av7110->osdwin = dc->x0; - ret = 0; - } - break; - case OSD_MoveWindow: - ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - if (!ret) - ret = SetColorBlend(av7110, av7110->osdwin); - break; - case OSD_OpenRaw: - if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) { - ret = -EINVAL; - break; - } - if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) - av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1; - else - av7110->osdbpp[av7110->osdwin] = 0; - ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, - dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); - if (ret) - break; - if (!dc->data) { - ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - if (!ret) - ret = SetColorBlend(av7110, av7110->osdwin); - } - break; - default: - ret = -EINVAL; - break; - } - - mutex_unlock(&av7110->osd_mutex); - if (ret==-ERESTARTSYS) - dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd); - else if (ret) - dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret); - - return ret; -} - -int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap) -{ - switch (cap->cmd) { - case OSD_CAP_MEMSIZE: - if (FW_4M_SDRAM(av7110->arm_app)) - cap->val = 1000000; - else - cap->val = 92000; - return 0; - default: - return -EINVAL; - } -} -#endif /* CONFIG_DVB_AV7110_OSD */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_hw.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_hw.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_hw.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_hw.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,495 +0,0 @@ -#ifndef _AV7110_HW_H_ -#define _AV7110_HW_H_ - -#include "av7110.h" - -/* DEBI transfer mode defs */ - -#define DEBINOSWAP 0x000e0000 -#define DEBISWAB 0x001e0000 -#define DEBISWAP 0x002e0000 - -#define ARM_WAIT_FREE (HZ) -#define ARM_WAIT_SHAKE (HZ/5) -#define ARM_WAIT_OSD (HZ) - - -enum av7110_bootstate -{ - BOOTSTATE_BUFFER_EMPTY = 0, - BOOTSTATE_BUFFER_FULL = 1, - BOOTSTATE_AV7110_BOOT_COMPLETE = 2 -}; - -enum av7110_type_rec_play_format -{ RP_None, - AudioPES, - AudioMp2, - AudioPCM, - VideoPES, - AV_PES -}; - -enum av7110_osd_palette_type -{ - NoPalet = 0, /* No palette */ - Pal1Bit = 2, /* 2 colors for 1 Bit Palette */ - Pal2Bit = 4, /* 4 colors for 2 bit palette */ - Pal4Bit = 16, /* 16 colors for 4 bit palette */ - Pal8Bit = 256 /* 256 colors for 16 bit palette */ -}; - -/* switch defines */ -#define SB_GPIO 3 -#define SB_OFF SAA7146_GPIO_OUTLO /* SlowBlank off (TV-Mode) */ -#define SB_ON SAA7146_GPIO_INPUT /* SlowBlank on (AV-Mode) */ -#define SB_WIDE SAA7146_GPIO_OUTHI /* SlowBlank 6V (16/9-Mode) (not implemented) */ - -#define FB_GPIO 1 -#define FB_OFF SAA7146_GPIO_LO /* FastBlank off (CVBS-Mode) */ -#define FB_ON SAA7146_GPIO_OUTHI /* FastBlank on (RGB-Mode) */ -#define FB_LOOP SAA7146_GPIO_INPUT /* FastBlank loop-through (PC graphics ???) */ - -enum av7110_video_output_mode -{ - NO_OUT = 0, /* disable analog output */ - CVBS_RGB_OUT = 1, - CVBS_YC_OUT = 2, - YC_OUT = 3 -}; - -/* firmware internal msg q status: */ -#define GPMQFull 0x0001 /* Main Message Queue Full */ -#define GPMQOver 0x0002 /* Main Message Queue Overflow */ -#define HPQFull 0x0004 /* High Priority Msg Queue Full */ -#define HPQOver 0x0008 -#define OSDQFull 0x0010 /* OSD Queue Full */ -#define OSDQOver 0x0020 -#define GPMQBusy 0x0040 /* Queue not empty, FW >= 261d */ -#define HPQBusy 0x0080 -#define OSDQBusy 0x0100 - -/* hw section filter flags */ -#define SECTION_EIT 0x01 -#define SECTION_SINGLE 0x00 -#define SECTION_CYCLE 0x02 -#define SECTION_CONTINUOS 0x04 -#define SECTION_MODE 0x06 -#define SECTION_IPMPE 0x0C /* size up to 4k */ -#define SECTION_HIGH_SPEED 0x1C /* larger buffer */ -#define DATA_PIPING_FLAG 0x20 /* for Data Piping Filter */ - -#define PBUFSIZE_NONE 0x0000 -#define PBUFSIZE_1P 0x0100 -#define PBUFSIZE_2P 0x0200 -#define PBUFSIZE_1K 0x0300 -#define PBUFSIZE_2K 0x0400 -#define PBUFSIZE_4K 0x0500 -#define PBUFSIZE_8K 0x0600 -#define PBUFSIZE_16K 0x0700 -#define PBUFSIZE_32K 0x0800 - - -/* firmware command codes */ -enum av7110_osd_command { - WCreate, - WDestroy, - WMoveD, - WMoveA, - WHide, - WTop, - DBox, - DLine, - DText, - Set_Font, - SetColor, - SetBlend, - SetWBlend, - SetCBlend, - SetNonBlend, - LoadBmp, - BlitBmp, - ReleaseBmp, - SetWTrans, - SetWNoTrans, - Set_Palette -}; - -enum av7110_pid_command { - MultiPID, - VideoPID, - AudioPID, - InitFilt, - FiltError, - NewVersion, - CacheError, - AddPIDFilter, - DelPIDFilter, - Scan, - SetDescr, - SetIR, - FlushTSQueue -}; - -enum av7110_mpeg_command { - SelAudChannels -}; - -enum av7110_audio_command { - AudioDAC, - CabADAC, - ON22K, - OFF22K, - MainSwitch, - ADSwitch, - SendDiSEqC, - SetRegister, - SpdifSwitch -}; - -enum av7110_request_command { - AudioState, - AudioBuffState, - VideoState1, - VideoState2, - VideoState3, - CrashCounter, - ReqVersion, - ReqVCXO, - ReqRegister, - ReqSecFilterError, - ReqSTC -}; - -enum av7110_encoder_command { - SetVidMode, - SetTestMode, - LoadVidCode, - SetMonitorType, - SetPanScanType, - SetFreezeMode, - SetWSSConfig -}; - -enum av7110_rec_play_state { - __Record, - __Stop, - __Play, - __Pause, - __Slow, - __FF_IP, - __Scan_I, - __Continue -}; - -enum av7110_fw_cmd_misc { - AV7110_FW_VIDEO_ZOOM = 1, - AV7110_FW_VIDEO_COMMAND, - AV7110_FW_AUDIO_COMMAND -}; - -enum av7110_command_type { - COMTYPE_NOCOM, - COMTYPE_PIDFILTER, - COMTYPE_MPEGDECODER, - COMTYPE_OSD, - COMTYPE_BMP, - COMTYPE_ENCODER, - COMTYPE_AUDIODAC, - COMTYPE_REQUEST, - COMTYPE_SYSTEM, - COMTYPE_REC_PLAY, - COMTYPE_COMMON_IF, - COMTYPE_PID_FILTER, - COMTYPE_PES, - COMTYPE_TS, - COMTYPE_VIDEO, - COMTYPE_AUDIO, - COMTYPE_CI_LL, - COMTYPE_MISC = 0x80 -}; - -#define VID_NONE_PREF 0x00 /* No aspect ration processing preferred */ -#define VID_PAN_SCAN_PREF 0x01 /* Pan and Scan Display preferred */ -#define VID_VERT_COMP_PREF 0x02 /* Vertical compression display preferred */ -#define VID_VC_AND_PS_PREF 0x03 /* PanScan and vertical Compression if allowed */ -#define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */ - -/* MPEG video decoder commands */ -#define AV_VIDEO_CMD_STOP 0x000e -#define AV_VIDEO_CMD_PLAY 0x000d -#define AV_VIDEO_CMD_FREEZE 0x0102 -#define AV_VIDEO_CMD_FFWD 0x0016 -#define AV_VIDEO_CMD_SLOW 0x0022 - -/* MPEG audio decoder commands */ -#define AUDIO_CMD_MUTE 0x0001 -#define AUDIO_CMD_UNMUTE 0x0002 -#define AUDIO_CMD_PCM16 0x0010 -#define AUDIO_CMD_STEREO 0x0080 -#define AUDIO_CMD_MONO_L 0x0100 -#define AUDIO_CMD_MONO_R 0x0200 -#define AUDIO_CMD_SYNC_OFF 0x000e -#define AUDIO_CMD_SYNC_ON 0x000f - -/* firmware data interface codes */ -#define DATA_NONE 0x00 -#define DATA_FSECTION 0x01 -#define DATA_IPMPE 0x02 -#define DATA_MPEG_RECORD 0x03 -#define DATA_DEBUG_MESSAGE 0x04 -#define DATA_COMMON_INTERFACE 0x05 -#define DATA_MPEG_PLAY 0x06 -#define DATA_BMP_LOAD 0x07 -#define DATA_IRCOMMAND 0x08 -#define DATA_PIPING 0x09 -#define DATA_STREAMING 0x0a -#define DATA_CI_GET 0x0b -#define DATA_CI_PUT 0x0c -#define DATA_MPEG_VIDEO_EVENT 0x0d - -#define DATA_PES_RECORD 0x10 -#define DATA_PES_PLAY 0x11 -#define DATA_TS_RECORD 0x12 -#define DATA_TS_PLAY 0x13 - -/* ancient CI command codes, only two are actually still used - * by the link level CI firmware */ -#define CI_CMD_ERROR 0x00 -#define CI_CMD_ACK 0x01 -#define CI_CMD_SYSTEM_READY 0x02 -#define CI_CMD_KEYPRESS 0x03 -#define CI_CMD_ON_TUNED 0x04 -#define CI_CMD_ON_SWITCH_PROGRAM 0x05 -#define CI_CMD_SECTION_ARRIVED 0x06 -#define CI_CMD_SECTION_TIMEOUT 0x07 -#define CI_CMD_TIME 0x08 -#define CI_CMD_ENTER_MENU 0x09 -#define CI_CMD_FAST_PSI 0x0a -#define CI_CMD_GET_SLOT_INFO 0x0b - -#define CI_MSG_NONE 0x00 -#define CI_MSG_CI_INFO 0x01 -#define CI_MSG_MENU 0x02 -#define CI_MSG_LIST 0x03 -#define CI_MSG_TEXT 0x04 -#define CI_MSG_REQUEST_INPUT 0x05 -#define CI_MSG_INPUT_COMPLETE 0x06 -#define CI_MSG_LIST_MORE 0x07 -#define CI_MSG_MENU_MORE 0x08 -#define CI_MSG_CLOSE_MMI_IMM 0x09 -#define CI_MSG_SECTION_REQUEST 0x0a -#define CI_MSG_CLOSE_FILTER 0x0b -#define CI_PSI_COMPLETE 0x0c -#define CI_MODULE_READY 0x0d -#define CI_SWITCH_PRG_REPLY 0x0e -#define CI_MSG_TEXT_MORE 0x0f - -#define CI_MSG_CA_PMT 0xe0 -#define CI_MSG_ERROR 0xf0 - - -/* base address of the dual ported RAM which serves as communication - * area between PCI bus and av7110, - * as seen by the DEBI bus of the saa7146 */ -#define DPRAM_BASE 0x4000 - -/* boot protocol area */ -#define AV7110_BOOT_STATE (DPRAM_BASE + 0x3F8) -#define AV7110_BOOT_SIZE (DPRAM_BASE + 0x3FA) -#define AV7110_BOOT_BASE (DPRAM_BASE + 0x3FC) -#define AV7110_BOOT_BLOCK (DPRAM_BASE + 0x400) -#define AV7110_BOOT_MAX_SIZE 0xc00 - -/* firmware command protocol area */ -#define IRQ_STATE (DPRAM_BASE + 0x0F4) -#define IRQ_STATE_EXT (DPRAM_BASE + 0x0F6) -#define MSGSTATE (DPRAM_BASE + 0x0F8) -#define COMMAND (DPRAM_BASE + 0x0FC) -#define COM_BUFF (DPRAM_BASE + 0x100) -#define COM_BUFF_SIZE 0x20 - -/* various data buffers */ -#define BUFF1_BASE (DPRAM_BASE + 0x120) -#define BUFF1_SIZE 0xE0 - -#define DATA_BUFF0_BASE (DPRAM_BASE + 0x200) -#define DATA_BUFF0_SIZE 0x0800 - -#define DATA_BUFF1_BASE (DATA_BUFF0_BASE+DATA_BUFF0_SIZE) -#define DATA_BUFF1_SIZE 0x0800 - -#define DATA_BUFF2_BASE (DATA_BUFF1_BASE+DATA_BUFF1_SIZE) -#define DATA_BUFF2_SIZE 0x0800 - -#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE) -#define DATA_BUFF3_SIZE 0x0400 - -#define Reserved (DPRAM_BASE + 0x1E00) -#define Reserved_SIZE 0x1C0 - - -/* firmware status area */ -#define STATUS_BASE (DPRAM_BASE + 0x1FC0) -#define STATUS_LOOPS (STATUS_BASE + 0x08) - -#define STATUS_MPEG_WIDTH (STATUS_BASE + 0x0C) -/* ((aspect_ratio & 0xf) << 12) | (height & 0xfff) */ -#define STATUS_MPEG_HEIGHT_AR (STATUS_BASE + 0x0E) - -/* firmware data protocol area */ -#define RX_TYPE (DPRAM_BASE + 0x1FE8) -#define RX_LEN (DPRAM_BASE + 0x1FEA) -#define TX_TYPE (DPRAM_BASE + 0x1FEC) -#define TX_LEN (DPRAM_BASE + 0x1FEE) - -#define RX_BUFF (DPRAM_BASE + 0x1FF4) -#define TX_BUFF (DPRAM_BASE + 0x1FF6) - -#define HANDSHAKE_REG (DPRAM_BASE + 0x1FF8) -#define COM_IF_LOCK (DPRAM_BASE + 0x1FFA) - -#define IRQ_RX (DPRAM_BASE + 0x1FFC) -#define IRQ_TX (DPRAM_BASE + 0x1FFE) - -/* used by boot protocol to load firmware into av7110 DRAM */ -#define DRAM_START_CODE 0x2e000404 -#define DRAM_MAX_CODE_SIZE 0x00100000 - -/* saa7146 gpio lines */ -#define RESET_LINE 2 -#define DEBI_DONE_LINE 1 -#define ARM_IRQ_LINE 0 - - - -extern int av7110_bootarm(struct av7110 *av7110); -extern int av7110_firmversion(struct av7110 *av7110); -#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000) -#define FW_4M_SDRAM(arm_app) ((arm_app) & 0x40000000) -#define FW_VERSION(arm_app) ((arm_app) & 0x0000FFFF) - -extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags); -extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...); -extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, - int request_buf_len, u16 *reply_buf, int reply_buf_len); - - -/* DEBI (saa7146 data extension bus interface) access */ -extern int av7110_debiwrite(struct av7110 *av7110, u32 config, - int addr, u32 val, int count); -extern u32 av7110_debiread(struct av7110 *av7110, u32 config, - int addr, int count); - - -/* DEBI during interrupt */ -/* single word writes */ -static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) -{ - av7110_debiwrite(av7110, config, addr, val, count); -} - -/* buffer writes */ -static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, - const u8 *val, int count) -{ - memcpy(av7110->debi_virt, val, count); - av7110_debiwrite(av7110, config, addr, 0, count); -} - -static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) -{ - u32 res; - - res=av7110_debiread(av7110, config, addr, count); - if (count<=4) - memcpy(av7110->debi_virt, (char *) &res, count); - return res; -} - -/* DEBI outside interrupts, only for count <= 4! */ -static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) -{ - unsigned long flags; - - spin_lock_irqsave(&av7110->debilock, flags); - av7110_debiwrite(av7110, config, addr, val, count); - spin_unlock_irqrestore(&av7110->debilock, flags); -} - -static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) -{ - unsigned long flags; - u32 res; - - spin_lock_irqsave(&av7110->debilock, flags); - res=av7110_debiread(av7110, config, addr, count); - spin_unlock_irqrestore(&av7110->debilock, flags); - return res; -} - -/* handle mailbox registers of the dual ported RAM */ -static inline void ARM_ResetMailBox(struct av7110 *av7110) -{ - unsigned long flags; - - spin_lock_irqsave(&av7110->debilock, flags); - av7110_debiread(av7110, DEBINOSWAP, IRQ_RX, 2); - av7110_debiwrite(av7110, DEBINOSWAP, IRQ_RX, 0, 2); - spin_unlock_irqrestore(&av7110->debilock, flags); -} - -static inline void ARM_ClearMailBox(struct av7110 *av7110) -{ - iwdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); -} - -static inline void ARM_ClearIrq(struct av7110 *av7110) -{ - irdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); -} - -/**************************************************************************** - * Firmware commands - ****************************************************************************/ - -static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data) -{ - return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data); -} - -static inline int av7710_set_video_mode(struct av7110 *av7110, int mode) -{ - return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); -} - -static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg) -{ - return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4, - (com>>16), (com&0xffff), - (arg>>16), (arg&0xffff)); -} - -static inline int audcom(struct av7110 *av7110, u32 com) -{ - return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2, - (com>>16), (com&0xffff)); -} - -static inline int Set22K(struct av7110 *av7110, int state) -{ - return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0); -} - - -extern int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst); - - -#ifdef CONFIG_DVB_AV7110_OSD -extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc); -extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap); -#endif /* CONFIG_DVB_AV7110_OSD */ - - - -#endif /* _AV7110_HW_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ipack.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ipack.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ipack.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ipack.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,403 +0,0 @@ -#include "dvb_filter.h" -#include "av7110_ipack.h" -#include /* for memcpy() */ -#include - - -void av7110_ipack_reset(struct ipack *p) -{ - p->found = 0; - p->cid = 0; - p->plength = 0; - p->flag1 = 0; - p->flag2 = 0; - p->hlength = 0; - p->mpeg = 0; - p->check = 0; - p->which = 0; - p->done = 0; - p->count = 0; -} - - -int av7110_ipack_init(struct ipack *p, int size, - void (*func)(u8 *buf, int size, void *priv)) -{ - if (!(p->buf = vmalloc(size*sizeof(u8)))) { - printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); - return -ENOMEM; - } - p->size = size; - p->func = func; - p->repack_subids = 0; - av7110_ipack_reset(p); - return 0; -} - - -void av7110_ipack_free(struct ipack *p) -{ - vfree(p->buf); -} - - -static void send_ipack(struct ipack *p) -{ - int off; - struct dvb_audio_info ai; - int ac3_off = 0; - int streamid = 0; - int nframes = 0; - int f = 0; - - switch (p->mpeg) { - case 2: - if (p->count < 10) - return; - p->buf[3] = p->cid; - p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); - p->buf[5] = (u8)((p->count - 6) & 0x00ff); - if (p->repack_subids && p->cid == PRIVATE_STREAM1) { - off = 9 + p->buf[8]; - streamid = p->buf[off]; - if ((streamid & 0xf8) == 0x80) { - ai.off = 0; - ac3_off = ((p->buf[off + 2] << 8)| - p->buf[off + 3]); - if (ac3_off < p->count) - f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off, - p->count - ac3_off, &ai, 0); - if (!f) { - nframes = (p->count - off - 3 - ac3_off) / - ai.framesize + 1; - p->buf[off + 2] = (ac3_off >> 8) & 0xff; - p->buf[off + 3] = (ac3_off) & 0xff; - p->buf[off + 1] = nframes; - ac3_off += nframes * ai.framesize - p->count; - } - } - } - p->func(p->buf, p->count, p->data); - - p->buf[6] = 0x80; - p->buf[7] = 0x00; - p->buf[8] = 0x00; - p->count = 9; - if (p->repack_subids && p->cid == PRIVATE_STREAM1 - && (streamid & 0xf8) == 0x80) { - p->count += 4; - p->buf[9] = streamid; - p->buf[10] = (ac3_off >> 8) & 0xff; - p->buf[11] = (ac3_off) & 0xff; - p->buf[12] = 0; - } - break; - - case 1: - if (p->count < 8) - return; - p->buf[3] = p->cid; - p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); - p->buf[5] = (u8)((p->count - 6) & 0x00ff); - p->func(p->buf, p->count, p->data); - - p->buf[6] = 0x0f; - p->count = 7; - break; - } -} - - -void av7110_ipack_flush(struct ipack *p) -{ - if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6) - return; - p->plength = p->found - 6; - p->found = 0; - send_ipack(p); - av7110_ipack_reset(p); -} - - -static void write_ipack(struct ipack *p, const u8 *data, int count) -{ - u8 headr[3] = { 0x00, 0x00, 0x01 }; - - if (p->count < 6) { - memcpy(p->buf, headr, 3); - p->count = 6; - } - - if (p->count + count < p->size){ - memcpy(p->buf+p->count, data, count); - p->count += count; - } else { - int rest = p->size - p->count; - memcpy(p->buf+p->count, data, rest); - p->count += rest; - send_ipack(p); - if (count - rest > 0) - write_ipack(p, data + rest, count - rest); - } -} - - -int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p) -{ - int l; - int c = 0; - - while (c < count && (p->mpeg == 0 || - (p->mpeg == 1 && p->found < 7) || - (p->mpeg == 2 && p->found < 9)) - && (p->found < 5 || !p->done)) { - switch (p->found) { - case 0: - case 1: - if (buf[c] == 0x00) - p->found++; - else - p->found = 0; - c++; - break; - case 2: - if (buf[c] == 0x01) - p->found++; - else if (buf[c] == 0) - p->found = 2; - else - p->found = 0; - c++; - break; - case 3: - p->cid = 0; - switch (buf[c]) { - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - p->done = 1; - /* fall through */ - case PRIVATE_STREAM1: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - p->found++; - p->cid = buf[c]; - c++; - break; - default: - p->found = 0; - break; - } - break; - - case 4: - if (count-c > 1) { - p->plen[0] = buf[c]; - c++; - p->plen[1] = buf[c]; - c++; - p->found += 2; - p->plength = (p->plen[0] << 8) | p->plen[1]; - } else { - p->plen[0] = buf[c]; - p->found++; - return count; - } - break; - case 5: - p->plen[1] = buf[c]; - c++; - p->found++; - p->plength = (p->plen[0] << 8) | p->plen[1]; - break; - case 6: - if (!p->done) { - p->flag1 = buf[c]; - c++; - p->found++; - if ((p->flag1 & 0xc0) == 0x80) - p->mpeg = 2; - else { - p->hlength = 0; - p->which = 0; - p->mpeg = 1; - p->flag2 = 0; - } - } - break; - - case 7: - if (!p->done && p->mpeg == 2) { - p->flag2 = buf[c]; - c++; - p->found++; - } - break; - - case 8: - if (!p->done && p->mpeg == 2) { - p->hlength = buf[c]; - c++; - p->found++; - } - break; - } - } - - if (c == count) - return count; - - if (!p->plength) - p->plength = MMAX_PLENGTH - 6; - - if (p->done || ((p->mpeg == 2 && p->found >= 9) || - (p->mpeg == 1 && p->found >= 7))) { - switch (p->cid) { - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - case PRIVATE_STREAM1: - if (p->mpeg == 2 && p->found == 9) { - write_ipack(p, &p->flag1, 1); - write_ipack(p, &p->flag2, 1); - write_ipack(p, &p->hlength, 1); - } - - if (p->mpeg == 1 && p->found == 7) - write_ipack(p, &p->flag1, 1); - - if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && - p->found < 14) { - while (c < count && p->found < 14) { - p->pts[p->found - 9] = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - } - if (c == count) - return count; - } - - if (p->mpeg == 1 && p->which < 2000) { - - if (p->found == 7) { - p->check = p->flag1; - p->hlength = 1; - } - - while (!p->which && c < count && - p->check == 0xff){ - p->check = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->hlength++; - } - - if (c == count) - return count; - - if ((p->check & 0xc0) == 0x40 && !p->which) { - p->check = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->hlength++; - - p->which = 1; - if (c == count) - return count; - p->check = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->hlength++; - p->which = 2; - if (c == count) - return count; - } - - if (p->which == 1) { - p->check = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->hlength++; - p->which = 2; - if (c == count) - return count; - } - - if ((p->check & 0x30) && p->check != 0xff) { - p->flag2 = (p->check & 0xf0) << 2; - p->pts[0] = p->check; - p->which = 3; - } - - if (c == count) - return count; - if (p->which > 2){ - if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) { - while (c < count && p->which < 7) { - p->pts[p->which - 2] = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->which++; - p->hlength++; - } - if (c == count) - return count; - } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) { - while (c < count && p->which < 12) { - if (p->which < 7) - p->pts[p->which - 2] = buf[c]; - write_ipack(p, buf + c, 1); - c++; - p->found++; - p->which++; - p->hlength++; - } - if (c == count) - return count; - } - p->which = 2000; - } - - } - - while (c < count && p->found < p->plength + 6) { - l = count - c; - if (l + p->found > p->plength + 6) - l = p->plength + 6 - p->found; - write_ipack(p, buf + c, l); - p->found += l; - c += l; - } - break; - } - - - if (p->done) { - if (p->found + count - c < p->plength + 6) { - p->found += count - c; - c = count; - } else { - c += p->plength + 6 - p->found; - p->found = p->plength + 6; - } - } - - if (p->plength && p->found == p->plength + 6) { - send_ipack(p); - av7110_ipack_reset(p); - if (c < count) - av7110_ipack_instant_repack(buf + c, count - c, p); - } - } - return count; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ipack.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ipack.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ipack.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ipack.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -#ifndef _AV7110_IPACK_H_ -#define _AV7110_IPACK_H_ - -extern int av7110_ipack_init(struct ipack *p, int size, - void (*func)(u8 *buf, int size, void *priv)); - -extern void av7110_ipack_reset(struct ipack *p); -extern int av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p); -extern void av7110_ipack_free(struct ipack * p); -extern void av7110_ipack_flush(struct ipack *p); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ir.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_ir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,415 +0,0 @@ -/* - * Driver for the remote control of SAA7146 based AV7110 cards - * - * Copyright (C) 1999-2003 Holger Waechtler - * Copyright (C) 2003-2007 Oliver Endriss - * - * 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, or (at your option) any later version. - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - */ - - -#include -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" - - -#define AV_CNT 4 - -#define IR_RC5 0 -#define IR_RCMM 1 -#define IR_RC5_EXT 2 /* internal only */ - -#define IR_ALL 0xffffffff - -#define UP_TIMEOUT (HZ*7/25) - - -/* Note: enable ir debugging by or'ing debug with 16 */ - -static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM}; -module_param_array(ir_protocol, int, NULL, 0644); -MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)"); - -static int ir_inversion[AV_CNT]; -module_param_array(ir_inversion, int, NULL, 0644); -MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted"); - -static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL }; -module_param_array(ir_device_mask, uint, NULL, 0644); -MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)"); - - -static int av_cnt; -static struct av7110 *av_list[AV_CNT]; - -static u16 default_key_map [256] = { - KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, - KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, - KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - KEY_CHANNELUP, KEY_CHANNELDOWN, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0, - 0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0, - KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0, - KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW, - KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN, - 0, 0, 0, 0, KEY_EPG, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR -}; - - -/* key-up timer */ -static void av7110_emit_keyup(unsigned long parm) -{ - struct infrared *ir = (struct infrared *) parm; - - if (!ir || !test_bit(ir->last_key, ir->input_dev->key)) - return; - - input_report_key(ir->input_dev, ir->last_key, 0); - input_sync(ir->input_dev); -} - - -/* tasklet */ -static void av7110_emit_key(unsigned long parm) -{ - struct infrared *ir = (struct infrared *) parm; - u32 ircom = ir->ir_command; - u8 data; - u8 addr; - u16 toggle; - u16 keycode; - - /* extract device address and data */ - switch (ir->protocol) { - case IR_RC5: /* RC5: 5 bits device address, 6 bits data */ - data = ircom & 0x3f; - addr = (ircom >> 6) & 0x1f; - toggle = ircom & 0x0800; - break; - - case IR_RCMM: /* RCMM: ? bits device address, ? bits data */ - data = ircom & 0xff; - addr = (ircom >> 8) & 0x1f; - toggle = ircom & 0x8000; - break; - - case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */ - data = ircom & 0x3f; - addr = (ircom >> 6) & 0x1f; - /* invert 7th data bit for backward compatibility with RC5 keymaps */ - if (!(ircom & 0x1000)) - data |= 0x40; - toggle = ircom & 0x0800; - break; - - default: - printk("%s invalid protocol %x\n", __func__, ir->protocol); - return; - } - - input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); - input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); - - keycode = ir->key_map[data]; - - dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", - __func__, ircom, addr, data, keycode); - - /* check device address */ - if (!(ir->device_mask & (1 << addr))) - return; - - if (!keycode) { - printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", - __func__, ircom, addr, data); - return; - } - - if (timer_pending(&ir->keyup_timer)) { - del_timer(&ir->keyup_timer); - if (ir->last_key != keycode || toggle != ir->last_toggle) { - ir->delay_timer_finished = 0; - input_event(ir->input_dev, EV_KEY, ir->last_key, 0); - input_event(ir->input_dev, EV_KEY, keycode, 1); - input_sync(ir->input_dev); - } else if (ir->delay_timer_finished) { - input_event(ir->input_dev, EV_KEY, keycode, 2); - input_sync(ir->input_dev); - } - } else { - ir->delay_timer_finished = 0; - input_event(ir->input_dev, EV_KEY, keycode, 1); - input_sync(ir->input_dev); - } - - ir->last_key = keycode; - ir->last_toggle = toggle; - - ir->keyup_timer.expires = jiffies + UP_TIMEOUT; - add_timer(&ir->keyup_timer); - -} - - -/* register with input layer */ -static void input_register_keys(struct infrared *ir) -{ - int i; - - set_bit(EV_KEY, ir->input_dev->evbit); - set_bit(EV_REP, ir->input_dev->evbit); - set_bit(EV_MSC, ir->input_dev->evbit); - - set_bit(MSC_RAW, ir->input_dev->mscbit); - set_bit(MSC_SCAN, ir->input_dev->mscbit); - - memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); - - for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { - if (ir->key_map[i] > KEY_MAX) - ir->key_map[i] = 0; - else if (ir->key_map[i] > KEY_RESERVED) - set_bit(ir->key_map[i], ir->input_dev->keybit); - } - - ir->input_dev->keycode = ir->key_map; - ir->input_dev->keycodesize = sizeof(ir->key_map[0]); - ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); -} - - -/* called by the input driver after rep[REP_DELAY] ms */ -static void input_repeat_key(unsigned long parm) -{ - struct infrared *ir = (struct infrared *) parm; - - ir->delay_timer_finished = 1; -} - - -/* check for configuration changes */ -int av7110_check_ir_config(struct av7110 *av7110, int force) -{ - int i; - int modified = force; - int ret = -ENODEV; - - for (i = 0; i < av_cnt; i++) - if (av7110 == av_list[i]) - break; - - if (i < av_cnt && av7110) { - if ((av7110->ir.protocol & 1) != ir_protocol[i] || - av7110->ir.inversion != ir_inversion[i]) - modified = true; - - if (modified) { - /* protocol */ - if (ir_protocol[i]) { - ir_protocol[i] = 1; - av7110->ir.protocol = IR_RCMM; - av7110->ir.ir_config = 0x0001; - } else if (FW_VERSION(av7110->arm_app) >= 0x2620) { - av7110->ir.protocol = IR_RC5_EXT; - av7110->ir.ir_config = 0x0002; - } else { - av7110->ir.protocol = IR_RC5; - av7110->ir.ir_config = 0x0000; - } - /* inversion */ - if (ir_inversion[i]) { - ir_inversion[i] = 1; - av7110->ir.ir_config |= 0x8000; - } - av7110->ir.inversion = ir_inversion[i]; - /* update ARM */ - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, - av7110->ir.ir_config); - } else - ret = 0; - - /* address */ - if (av7110->ir.device_mask != ir_device_mask[i]) - av7110->ir.device_mask = ir_device_mask[i]; - } - - return ret; -} - - -/* /proc/av7110_ir interface */ -static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - char *page; - u32 ir_config; - int size = sizeof ir_config + sizeof av_list[0]->ir.key_map; - int i; - - if (count < size) - return -EINVAL; - - page = vmalloc(size); - if (!page) - return -ENOMEM; - - if (copy_from_user(page, buffer, size)) { - vfree(page); - return -EFAULT; - } - - memcpy(&ir_config, page, sizeof ir_config); - - for (i = 0; i < av_cnt; i++) { - /* keymap */ - memcpy(av_list[i]->ir.key_map, page + sizeof ir_config, - sizeof(av_list[i]->ir.key_map)); - /* protocol, inversion, address */ - ir_protocol[i] = ir_config & 0x0001; - ir_inversion[i] = ir_config & 0x8000 ? 1 : 0; - if (ir_config & 0x4000) - ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f); - else - ir_device_mask[i] = IR_ALL; - /* update configuration */ - av7110_check_ir_config(av_list[i], false); - input_register_keys(&av_list[i]->ir); - } - vfree(page); - return count; -} - -static const struct file_operations av7110_ir_proc_fops = { - .owner = THIS_MODULE, - .write = av7110_ir_proc_write, - .llseek = noop_llseek, -}; - -/* interrupt handler */ -static void ir_handler(struct av7110 *av7110, u32 ircom) -{ - dprintk(4, "ir command = %08x\n", ircom); - av7110->ir.ir_command = ircom; - tasklet_schedule(&av7110->ir.ir_tasklet); -} - - -int __devinit av7110_ir_init(struct av7110 *av7110) -{ - struct input_dev *input_dev; - static struct proc_dir_entry *e; - int err; - - if (av_cnt >= ARRAY_SIZE(av_list)) - return -ENOSPC; - - av_list[av_cnt++] = av7110; - av7110_check_ir_config(av7110, true); - - init_timer(&av7110->ir.keyup_timer); - av7110->ir.keyup_timer.function = av7110_emit_keyup; - av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - av7110->ir.input_dev = input_dev; - snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), - "pci-%s/ir0", pci_name(av7110->dev->pci)); - - input_dev->name = "DVB on-card IR receiver"; - - input_dev->phys = av7110->ir.input_phys; - input_dev->id.bustype = BUS_PCI; - input_dev->id.version = 2; - if (av7110->dev->pci->subsystem_vendor) { - input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; - input_dev->id.product = av7110->dev->pci->subsystem_device; - } else { - input_dev->id.vendor = av7110->dev->pci->vendor; - input_dev->id.product = av7110->dev->pci->device; - } - input_dev->dev.parent = &av7110->dev->pci->dev; - /* initial keymap */ - memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); - input_register_keys(&av7110->ir); - err = input_register_device(input_dev); - if (err) { - input_free_device(input_dev); - return err; - } - input_dev->timer.function = input_repeat_key; - input_dev->timer.data = (unsigned long) &av7110->ir; - - if (av_cnt == 1) { - e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops); - if (e) - e->size = 4 + 256 * sizeof(u16); - } - - tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir); - av7110->ir.ir_handler = ir_handler; - - return 0; -} - - -void __devexit av7110_ir_exit(struct av7110 *av7110) -{ - int i; - - if (av_cnt == 0) - return; - - del_timer_sync(&av7110->ir.keyup_timer); - av7110->ir.ir_handler = NULL; - tasklet_kill(&av7110->ir.ir_tasklet); - - for (i = 0; i < av_cnt; i++) - if (av_list[i] == av7110) { - av_list[i] = av_list[av_cnt-1]; - av_list[av_cnt-1] = NULL; - break; - } - - if (av_cnt == 1) - remove_proc_entry("av7110_ir", NULL); - - input_unregister_device(av7110->ir.input_dev); - - av_cnt--; -} - -//MODULE_AUTHOR("Holger Waechtler , Oliver Endriss "); -//MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_v4l.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_v4l.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_v4l.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/av7110_v4l.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,932 +0,0 @@ -/* - * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * originally based on code by: - * Copyright (C) 1998,1999 Christian Theiss - * - * 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, or (at your option) any later version. - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include -#include -#include -#include -#include -#include - -#include "av7110.h" -#include "av7110_hw.h" -#include "av7110_av.h" - -int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) -{ - u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; - struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg }; - - switch (av7110->adac_type) { - case DVB_ADAC_MSP34x0: - msgs.addr = 0x40; - break; - case DVB_ADAC_MSP34x5: - msgs.addr = 0x42; - break; - default: - return 0; - } - - if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { - dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", - av7110->dvb_adapter.num, reg, val); - return -EIO; - } - return 0; -} - -static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) -{ - u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; - u8 msg2[2]; - struct i2c_msg msgs[2] = { - { .flags = 0 , .len = 3, .buf = msg1 }, - { .flags = I2C_M_RD, .len = 2, .buf = msg2 } - }; - - switch (av7110->adac_type) { - case DVB_ADAC_MSP34x0: - msgs[0].addr = 0x40; - msgs[1].addr = 0x40; - break; - case DVB_ADAC_MSP34x5: - msgs[0].addr = 0x42; - msgs[1].addr = 0x42; - break; - default: - return 0; - } - - if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { - dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", - av7110->dvb_adapter.num, reg); - return -EIO; - } - *val = (msg2[0] << 8) | msg2[1]; - return 0; -} - -static struct v4l2_input inputs[4] = { - { - .index = 0, - .name = "DVB", - .type = V4L2_INPUT_TYPE_CAMERA, - .audioset = 1, - .tuner = 0, /* ignored */ - .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, - .status = 0, - .capabilities = V4L2_IN_CAP_STD, - }, { - .index = 1, - .name = "Television", - .type = V4L2_INPUT_TYPE_TUNER, - .audioset = 2, - .tuner = 0, - .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, - .status = 0, - .capabilities = V4L2_IN_CAP_STD, - }, { - .index = 2, - .name = "Video", - .type = V4L2_INPUT_TYPE_CAMERA, - .audioset = 0, - .tuner = 0, - .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, - .status = 0, - .capabilities = V4L2_IN_CAP_STD, - }, { - .index = 3, - .name = "Y/C", - .type = V4L2_INPUT_TYPE_CAMERA, - .audioset = 0, - .tuner = 0, - .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, - .status = 0, - .capabilities = V4L2_IN_CAP_STD, - } -}; - -static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) -{ - struct av7110 *av7110 = dev->ext_priv; - u8 buf[] = { 0x00, reg, data }; - struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; - - dprintk(4, "dev: %p\n", dev); - - if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) - return -1; - return 0; -} - -static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) -{ - struct av7110 *av7110 = dev->ext_priv; - struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; - - dprintk(4, "dev: %p\n", dev); - - if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) - return -1; - return 0; -} - -static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq) -{ - u32 div; - u8 config; - u8 buf[4]; - - dprintk(4, "freq: 0x%08x\n", freq); - - /* magic number: 614. tuning with the frequency given by v4l2 - is always off by 614*62.5 = 38375 kHz...*/ - div = freq + 614; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x8e; - - if (freq < (u32) (16 * 168.25)) - config = 0xa0; - else if (freq < (u32) (16 * 447.25)) - config = 0x90; - else - config = 0x30; - config &= ~0x02; - - buf[3] = config; - - return tuner_write(dev, 0x61, buf); -} - -static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq) -{ - struct av7110 *av7110 = (struct av7110*)dev->ext_priv; - u32 div; - u8 data[4]; - - div = (freq + 38900000 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0xce; - - if (freq < 45000000) - return -EINVAL; - else if (freq < 137000000) - data[3] = 0x01; - else if (freq < 403000000) - data[3] = 0x02; - else if (freq < 860000000) - data[3] = 0x04; - else - return -EINVAL; - - if (av7110->fe->ops.i2c_gate_ctrl) - av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1); - return tuner_write(dev, 0x63, data); -} - - - -static struct saa7146_standard analog_standard[]; -static struct saa7146_standard dvb_standard[]; -static struct saa7146_standard standard[]; - -static struct v4l2_audio msp3400_v4l2_audio = { - .index = 0, - .name = "Television", - .capability = V4L2_AUDCAP_STEREO -}; - -static int av7110_dvb_c_switch(struct saa7146_fh *fh) -{ - struct saa7146_dev *dev = fh->dev; - struct saa7146_vv *vv = dev->vv_data; - struct av7110 *av7110 = (struct av7110*)dev->ext_priv; - u16 adswitch; - int source, sync, err; - - dprintk(4, "%p\n", av7110); - - if ((vv->video_status & STATUS_OVERLAY) != 0) { - vv->ov_suspend = vv->video_fh; - err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ - if (err != 0) { - dprintk(2, "suspending video failed\n"); - vv->ov_suspend = NULL; - } - } - - if (0 != av7110->current_input) { - dprintk(1, "switching to analog TV:\n"); - adswitch = 1; - source = SAA7146_HPS_SOURCE_PORT_B; - sync = SAA7146_HPS_SYNC_PORT_B; - memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2); - - switch (av7110->current_input) { - case 1: - dprintk(1, "switching SAA7113 to Analog Tuner Input.\n"); - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source - msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source - msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source - msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume - - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { - if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) - dprintk(1, "setting band in demodulator failed.\n"); - } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD) - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF) - } - if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1) - dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); - break; - case 2: - dprintk(1, "switching SAA7113 to Video AV CVBS Input.\n"); - if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1) - dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); - break; - case 3: - dprintk(1, "switching SAA7113 to Video AV Y/C Input.\n"); - if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1) - dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); - break; - default: - dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input.\n"); - } - } else { - adswitch = 0; - source = SAA7146_HPS_SOURCE_PORT_A; - sync = SAA7146_HPS_SYNC_PORT_A; - memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); - dprintk(1, "switching DVB mode\n"); - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source - msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source - msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source - msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume - - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { - if (ves1820_writereg(dev, 0x09, 0x0f, 0x20)) - dprintk(1, "setting band in demodulator failed.\n"); - } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) - } - } - - /* hmm, this does not do anything!? */ - if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch)) - dprintk(1, "ADSwitch error\n"); - - saa7146_set_hps_source_and_sync(dev, source, sync); - - if (vv->ov_suspend != NULL) { - saa7146_start_preview(vv->ov_suspend); - vv->ov_suspend = NULL; - } - - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - u16 stereo_det; - s8 stereo; - - dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index); - - if (!av7110->analog_tuner_flags || t->index != 0) - return -EINVAL; - - memset(t, 0, sizeof(*t)); - strcpy((char *)t->name, "Television"); - - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ - t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ - /* FIXME: add the real signal strength here */ - t->signal = 0xffff; - t->afc = 0; - - /* FIXME: standard / stereo detection is still broken */ - msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); - dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); - msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); - dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); - stereo = (s8)(stereo_det >> 8); - if (stereo > 0x10) { - /* stereo */ - t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; - t->audmode = V4L2_TUNER_MODE_STEREO; - } else if (stereo < -0x10) { - /* bilingual */ - t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - t->audmode = V4L2_TUNER_MODE_LANG1; - } else /* mono */ - t->rxsubchans = V4L2_TUNER_SUB_MONO; - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - u16 fm_matrix, src; - dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index); - - if (!av7110->analog_tuner_flags || av7110->current_input != 1) - return -EINVAL; - - switch (t->audmode) { - case V4L2_TUNER_MODE_STEREO: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"); - fm_matrix = 0x3001; /* stereo */ - src = 0x0020; - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"); - fm_matrix = 0x3000; /* bilingual */ - src = 0x0020; - break; - case V4L2_TUNER_MODE_LANG1: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"); - fm_matrix = 0x3000; /* mono */ - src = 0x0000; - break; - case V4L2_TUNER_MODE_LANG2: - dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"); - fm_matrix = 0x3000; /* mono */ - src = 0x0010; - break; - default: /* case V4L2_TUNER_MODE_MONO: */ - dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); - fm_matrix = 0x3000; /* mono */ - src = 0x0030; - break; - } - msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix); - msp_writereg(av7110, MSP_WR_DSP, 0x0008, src); - msp_writereg(av7110, MSP_WR_DSP, 0x0009, src); - msp_writereg(av7110, MSP_WR_DSP, 0x000a, src); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency); - - if (!av7110->analog_tuner_flags || av7110->current_input != 1) - return -EINVAL; - - memset(f, 0, sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = av7110->current_freq; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency); - - if (!av7110->analog_tuner_flags || av7110->current_input != 1) - return -EINVAL; - - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */ - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0); - - /* tune in desired frequency */ - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) - ves1820_set_tv_freq(dev, f->frequency); - else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) - stv0297_set_tv_freq(dev, f->frequency); - av7110->current_freq = f->frequency; - - msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */ - msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */ - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */ - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); - - if (av7110->analog_tuner_flags) { - if (i->index >= 4) - return -EINVAL; - } else { - if (i->index != 0) - return -EINVAL; - } - - memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); - - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - *input = av7110->current_input; - dprintk(2, "VIDIOC_G_INPUT: %d\n", *input); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_S_INPUT: %d\n", input); - - if (!av7110->analog_tuner_flags) - return 0; - - if (input >= 4) - return -EINVAL; - - av7110->current_input = input; - return av7110_dvb_c_switch(fh); -} - -static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); - if (a->index != 0) - return -EINVAL; - memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio)); - return 0; -} - -static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); - return 0; -} - -static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_sliced_vbi_cap *cap) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); - if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) - return -EINVAL; - if (FW_VERSION(av7110->arm_app) >= 0x2623) { - cap->service_set = V4L2_SLICED_WSS_625; - cap->service_lines[0][23] = V4L2_SLICED_WSS_625; - } - return 0; -} - -static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_G_FMT:\n"); - if (FW_VERSION(av7110->arm_app) < 0x2623) - return -EINVAL; - memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); - if (av7110->wssMode) { - f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; - f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; - f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); - } - return 0; -} - -static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - - dprintk(2, "VIDIOC_S_FMT\n"); - if (FW_VERSION(av7110->arm_app) < 0x2623) - return -EINVAL; - if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && - f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { - memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); - /* WSS controlled by firmware */ - av7110->wssMode = 0; - av7110->wssData = 0; - return av7110_fw_cmd(av7110, COMTYPE_ENCODER, - SetWSSConfig, 1, 0); - } else { - memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); - f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; - f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; - f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); - /* WSS controlled by userspace */ - av7110->wssMode = 1; - av7110->wssData = 0; - } - return 0; -} - -static int av7110_vbi_reset(struct file *file) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct av7110 *av7110 = (struct av7110*) dev->ext_priv; - - dprintk(2, "%s\n", __func__); - av7110->wssMode = 0; - av7110->wssData = 0; - if (FW_VERSION(av7110->arm_app) < 0x2623) - return 0; - else - return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0); -} - -static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) -{ - struct saa7146_fh *fh = file->private_data; - struct saa7146_dev *dev = fh->dev; - struct av7110 *av7110 = (struct av7110*) dev->ext_priv; - struct v4l2_sliced_vbi_data d; - int rc; - - dprintk(2, "%s\n", __func__); - if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d) - return -EINVAL; - if (copy_from_user(&d, data, count)) - return -EFAULT; - if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23) - return -EINVAL; - if (d.id) - av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0]; - else - av7110->wssData = 0x8000; - rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData); - return (rc < 0) ? rc : count; -} - -/**************************************************************************** - * INITIALIZATION - ****************************************************************************/ - -static u8 saa7113_init_regs[] = { - 0x02, 0xd0, - 0x03, 0x23, - 0x04, 0x00, - 0x05, 0x00, - 0x06, 0xe9, - 0x07, 0x0d, - 0x08, 0x98, - 0x09, 0x02, - 0x0a, 0x80, - 0x0b, 0x40, - 0x0c, 0x40, - 0x0d, 0x00, - 0x0e, 0x01, - 0x0f, 0x7c, - 0x10, 0x48, - 0x11, 0x0c, - 0x12, 0x8b, - 0x13, 0x1a, - 0x14, 0x00, - 0x15, 0x00, - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1b, 0x00, - 0x1c, 0x00, - 0x1d, 0x00, - 0x1e, 0x00, - - 0x41, 0x77, - 0x42, 0x77, - 0x43, 0x77, - 0x44, 0x77, - 0x45, 0x77, - 0x46, 0x77, - 0x47, 0x77, - 0x48, 0x77, - 0x49, 0x77, - 0x4a, 0x77, - 0x4b, 0x77, - 0x4c, 0x77, - 0x4d, 0x77, - 0x4e, 0x77, - 0x4f, 0x77, - 0x50, 0x77, - 0x51, 0x77, - 0x52, 0x77, - 0x53, 0x77, - 0x54, 0x77, - 0x55, 0x77, - 0x56, 0x77, - 0x57, 0xff, - - 0xff -}; - - -static struct saa7146_ext_vv av7110_vv_data_st; -static struct saa7146_ext_vv av7110_vv_data_c; - -int av7110_init_analog_module(struct av7110 *av7110) -{ - u16 version1, version2; - - if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 && - i2c_writereg(av7110, 0x80, 0x0, 0) == 1) { - printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_MSP34x0; - } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 && - i2c_writereg(av7110, 0x84, 0x0, 0) == 1) { - printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_MSP34x5; - } else - return -ENODEV; - - msleep(100); // the probing above resets the msp... - msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); - msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); - dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n", - av7110->dvb_adapter.num, version1, version2); - msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source - msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source - msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume - msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume - msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART - - if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { - INFO(("saa7113 not accessible.\n")); - } else { - u8 *i = saa7113_init_regs; - - if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { - /* Fujitsu/Siemens DVB-Cable */ - av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; - } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) { - /* Hauppauge/TT DVB-C premium */ - av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; - } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) { - /* Hauppauge/TT DVB-C premium */ - av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297; - } - - /* setup for DVB by default */ - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { - if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20)) - dprintk(1, "setting band in demodulator failed.\n"); - } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) - saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) - } - - /* init the saa7113 */ - while (*i != 0xff) { - if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) { - dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num); - break; - } - i += 2; - } - /* setup msp for analog sound: B/G Dual-FM */ - msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 3); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 4); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 0); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 3); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2 - msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG - msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz - msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI - msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz - msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI - msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2 - } - - memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); - /* set dd1 stream a & b */ - saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); - saa7146_write(av7110->dev, DD1_INIT, 0x03000700); - saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - return 0; -} - -int av7110_init_v4l(struct av7110 *av7110) -{ - struct saa7146_dev* dev = av7110->dev; - struct saa7146_ext_vv *vv_data; - int ret; - - /* special case DVB-C: these cards have an analog tuner - plus need some special handling, so we have separate - saa7146_ext_vv data for these... */ - if (av7110->analog_tuner_flags) - vv_data = &av7110_vv_data_c; - else - vv_data = &av7110_vv_data_st; - ret = saa7146_vv_init(dev, vv_data); - - if (ret) { - ERR(("cannot init capture device. skipping.\n")); - return -ENODEV; - } - vv_data->ops.vidioc_enum_input = vidioc_enum_input; - vv_data->ops.vidioc_g_input = vidioc_g_input; - vv_data->ops.vidioc_s_input = vidioc_s_input; - vv_data->ops.vidioc_g_tuner = vidioc_g_tuner; - vv_data->ops.vidioc_s_tuner = vidioc_s_tuner; - vv_data->ops.vidioc_g_frequency = vidioc_g_frequency; - vv_data->ops.vidioc_s_frequency = vidioc_s_frequency; - vv_data->ops.vidioc_g_audio = vidioc_g_audio; - vv_data->ops.vidioc_s_audio = vidioc_s_audio; - vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; - vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; - vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; - - if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { - ERR(("cannot register capture device. skipping.\n")); - saa7146_vv_release(dev); - return -ENODEV; - } - if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) - ERR(("cannot register vbi v4l2 device. skipping.\n")); - return 0; -} - -int av7110_exit_v4l(struct av7110 *av7110) -{ - struct saa7146_dev* dev = av7110->dev; - - saa7146_unregister_device(&av7110->v4l_dev, av7110->dev); - saa7146_unregister_device(&av7110->vbi_dev, av7110->dev); - - saa7146_vv_release(dev); - - return 0; -} - - - -/* FIXME: these values are experimental values that look better than the - values from the latest "official" driver -- at least for me... (MiHu) */ -static struct saa7146_standard standard[] = { - { - .name = "PAL", .id = V4L2_STD_PAL_BG, - .v_offset = 0x15, .v_field = 288, - .h_offset = 0x48, .h_pixels = 708, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 0x10, .v_field = 244, - .h_offset = 0x40, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - } -}; - -static struct saa7146_standard analog_standard[] = { - { - .name = "PAL", .id = V4L2_STD_PAL_BG, - .v_offset = 0x1b, .v_field = 288, - .h_offset = 0x08, .h_pixels = 708, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 0x10, .v_field = 244, - .h_offset = 0x40, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - } -}; - -static struct saa7146_standard dvb_standard[] = { - { - .name = "PAL", .id = V4L2_STD_PAL_BG, - .v_offset = 0x14, .v_field = 288, - .h_offset = 0x48, .h_pixels = 708, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 0x10, .v_field = 244, - .h_offset = 0x40, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - } -}; - -static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) -{ - struct av7110 *av7110 = (struct av7110*) dev->ext_priv; - - if (std->id & V4L2_STD_PAL) { - av7110->vidmode = AV7110_VIDEO_MODE_PAL; - av7110_set_vidmode(av7110, av7110->vidmode); - } - else if (std->id & V4L2_STD_NTSC) { - av7110->vidmode = AV7110_VIDEO_MODE_NTSC; - av7110_set_vidmode(av7110, av7110->vidmode); - } - else - return -1; - - return 0; -} - - -static struct saa7146_ext_vv av7110_vv_data_st = { - .inputs = 1, - .audios = 1, - .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT, - .flags = 0, - - .stds = &standard[0], - .num_stds = ARRAY_SIZE(standard), - .std_callback = &std_callback, - - .vbi_fops.open = av7110_vbi_reset, - .vbi_fops.release = av7110_vbi_reset, - .vbi_fops.write = av7110_vbi_write, -}; - -static struct saa7146_ext_vv av7110_vv_data_c = { - .inputs = 1, - .audios = 1, - .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT, - .flags = SAA7146_USE_PORT_B_FOR_VBI, - - .stds = &standard[0], - .num_stds = ARRAY_SIZE(standard), - .std_callback = &std_callback, - - .vbi_fops.open = av7110_vbi_reset, - .vbi_fops.release = av7110_vbi_reset, - .vbi_fops.write = av7110_vbi_write, -}; - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-av.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-av.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-av.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-av.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1635 +0,0 @@ -/* - * budget-av.c: driver for the SAA7146 based Budget DVB cards - * with analog video in - * - * Compiled from various sources by Michael Hunold - * - * CI interface support (c) 2004 Olivier Gournet & - * Andrew de Quincey - * - * Copyright (C) 2002 Ralph Metzler - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include "budget.h" -#include "stv0299.h" -#include "stb0899_drv.h" -#include "stb0899_reg.h" -#include "stb0899_cfg.h" -#include "tda8261.h" -#include "tda8261_cfg.h" -#include "tda1002x.h" -#include "tda1004x.h" -#include "tua6100.h" -#include "dvb-pll.h" -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_ca_en50221.h" - -#define DEBICICAM 0x02420000 - -#define SLOTSTATUS_NONE 1 -#define SLOTSTATUS_PRESENT 2 -#define SLOTSTATUS_RESET 4 -#define SLOTSTATUS_READY 8 -#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct budget_av { - struct budget budget; - struct video_device *vd; - int cur_input; - int has_saa7113; - struct tasklet_struct ciintf_irq_tasklet; - int slot_status; - struct dvb_ca_en50221 ca; - u8 reinitialise_demod:1; -}; - -static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); - - -/* GPIO Connections: - * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! - * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory - * 2 - CI Card Enable (Active Low) - * 3 - CI Card Detect - */ - -/**************************************************************************** - * INITIALIZATION - ****************************************************************************/ - -static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg) -{ - u8 mm1[] = { 0x00 }; - u8 mm2[] = { 0x00 }; - struct i2c_msg msgs[2]; - - msgs[0].flags = 0; - msgs[1].flags = I2C_M_RD; - msgs[0].addr = msgs[1].addr = id / 2; - mm1[0] = reg; - msgs[0].len = 1; - msgs[1].len = 1; - msgs[0].buf = mm1; - msgs[1].buf = mm2; - - i2c_transfer(i2c, msgs, 2); - - return mm2[0]; -} - -static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len) -{ - u8 mm1[] = { reg }; - struct i2c_msg msgs[2] = { - {.addr = id / 2,.flags = 0,.buf = mm1,.len = 1}, - {.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len} - }; - - if (i2c_transfer(i2c, msgs, 2) != 2) - return -EIO; - - return 0; -} - -static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val) -{ - u8 msg[2] = { reg, val }; - struct i2c_msg msgs; - - msgs.flags = 0; - msgs.addr = id / 2; - msgs.len = 2; - msgs.buf = msg; - return i2c_transfer(i2c, &msgs, 1); -} - -static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); - udelay(1); - - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 1\n"); - } - return result; -} - -static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); - udelay(1); - - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 2\n"); - } - return result; -} - -static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - udelay(1); - - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 3\n"); - return -ETIMEDOUT; - } - return result; -} - -static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - udelay(1); - - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 5\n"); - } - return result; -} - -static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - - if (slot != 0) - return -EINVAL; - - dprintk(1, "ciintf_slot_reset\n"); - budget_av->slot_status = SLOTSTATUS_RESET; - - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ - msleep(2); - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */ - msleep(20); /* 20 ms Vcc settling time */ - - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - msleep(20); - - /* reinitialise the frontend if necessary */ - if (budget_av->reinitialise_demod) - dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); - - return 0; -} - -static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - - if (slot != 0) - return -EINVAL; - - dprintk(1, "ciintf_slot_shutdown\n"); - - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - budget_av->slot_status = SLOTSTATUS_NONE; - - return 0; -} - -static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - - if (slot != 0) - return -EINVAL; - - dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); - - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); - - return 0; -} - -static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - int result; - - if (slot != 0) - return -EINVAL; - - /* test the card detect line - needs to be done carefully - * since it never goes high for some CAMs on this interface (e.g. topuptv) */ - if (budget_av->slot_status == SLOTSTATUS_NONE) { - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - udelay(1); - if (saa7146_read(saa, PSR) & MASK_06) { - if (budget_av->slot_status == SLOTSTATUS_NONE) { - budget_av->slot_status = SLOTSTATUS_PRESENT; - printk(KERN_INFO "budget-av: cam inserted A\n"); - } - } - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - } - - /* We also try and read from IO memory to work round the above detection bug. If - * there is no CAM, we will get a timeout. Only done if there is no cam - * present, since this test actually breaks some cams :( - * - * if the CI interface is not open, we also do the above test since we - * don't care if the cam has problems - we'll be resetting it on open() anyway */ - if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) { - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1); - if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) { - budget_av->slot_status = SLOTSTATUS_PRESENT; - printk(KERN_INFO "budget-av: cam inserted B\n"); - } else if (result < 0) { - if (budget_av->slot_status != SLOTSTATUS_NONE) { - ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 5\n"); - return 0; - } - } - } - - /* read from attribute memory in reset/ready state to know when the CAM is ready */ - if (budget_av->slot_status == SLOTSTATUS_RESET) { - result = ciintf_read_attribute_mem(ca, slot, 0); - if (result == 0x1d) { - budget_av->slot_status = SLOTSTATUS_READY; - } - } - - /* work out correct return code */ - if (budget_av->slot_status != SLOTSTATUS_NONE) { - if (budget_av->slot_status & SLOTSTATUS_READY) { - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - } - return DVB_CA_EN50221_POLL_CAM_PRESENT; - } - return 0; -} - -static int ciintf_init(struct budget_av *budget_av) -{ - struct saa7146_dev *saa = budget_av->budget.dev; - int result; - - memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221)); - - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - - /* Enable DEBI pins */ - saa7146_write(saa, MC1, MASK_27 | MASK_11); - - /* register CI interface */ - budget_av->ca.owner = THIS_MODULE; - budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem; - budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem; - budget_av->ca.read_cam_control = ciintf_read_cam_control; - budget_av->ca.write_cam_control = ciintf_write_cam_control; - budget_av->ca.slot_reset = ciintf_slot_reset; - budget_av->ca.slot_shutdown = ciintf_slot_shutdown; - budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; - budget_av->ca.poll_slot_status = ciintf_poll_slot_status; - budget_av->ca.data = budget_av; - budget_av->budget.ci_present = 1; - budget_av->slot_status = SLOTSTATUS_NONE; - - if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, - &budget_av->ca, 0, 1)) != 0) { - printk(KERN_ERR "budget-av: ci initialisation failed.\n"); - goto error; - } - - printk(KERN_INFO "budget-av: ci interface initialised.\n"); - return 0; - -error: - saa7146_write(saa, MC1, MASK_27); - return result; -} - -static void ciintf_deinit(struct budget_av *budget_av) -{ - struct saa7146_dev *saa = budget_av->budget.dev; - - saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); - saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); - saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - - /* release the CA device */ - dvb_ca_en50221_release(&budget_av->ca); - - /* disable DEBI pins */ - saa7146_write(saa, MC1, MASK_27); -} - - -static const u8 saa7113_tab[] = { - 0x01, 0x08, - 0x02, 0xc0, - 0x03, 0x33, - 0x04, 0x00, - 0x05, 0x00, - 0x06, 0xeb, - 0x07, 0xe0, - 0x08, 0x28, - 0x09, 0x00, - 0x0a, 0x80, - 0x0b, 0x47, - 0x0c, 0x40, - 0x0d, 0x00, - 0x0e, 0x01, - 0x0f, 0x44, - - 0x10, 0x08, - 0x11, 0x0c, - 0x12, 0x7b, - 0x13, 0x00, - 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, - - 0x57, 0xff, - 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07, - 0x5b, 0x83, 0x5e, 0x00, - 0xff -}; - -static int saa7113_init(struct budget_av *budget_av) -{ - struct budget *budget = &budget_av->budget; - struct saa7146_dev *saa = budget->dev; - const u8 *data = saa7113_tab; - - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); - msleep(200); - - if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) { - dprintk(1, "saa7113 not found on KNC card\n"); - return -ENODEV; - } - - dprintk(1, "saa7113 detected and initializing\n"); - - while (*data != 0xff) { - i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1)); - data += 2; - } - - dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f)); - - return 0; -} - -static int saa7113_setinput(struct budget_av *budget_av, int input) -{ - struct budget *budget = &budget_av->budget; - - if (1 != budget_av->has_saa7113) - return -ENODEV; - - if (input == 1) { - i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7); - i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80); - } else if (input == 0) { - i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0); - i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00); - } else - return -EINVAL; - - budget_av->cur_input = input; - return 0; -} - - -static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - u8 m1; - - aclk = 0xb5; - if (srate < 2000000) - bclk = 0x86; - else if (srate < 5000000) - bclk = 0x89; - else if (srate < 15000000) - bclk = 0x8f; - else if (srate < 45000000) - bclk = 0x95; - - m1 = 0x14; - if (srate < 4000000) - m1 = 0x10; - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - stv0299_writereg(fe, 0x0f, 0x80 | m1); - - return 0; -} - -static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - u32 div; - u8 buf[4]; - struct budget *budget = (struct budget *) fe->dvb->priv; - struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - if ((params->frequency < 950000) || (params->frequency > 2150000)) - return -EINVAL; - - div = (params->frequency + (125 - 1)) / 125; // round correctly - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; - buf[3] = 0x20; - - if (params->u.qpsk.symbol_rate < 4000000) - buf[3] |= 1; - - if (params->frequency < 1250000) - buf[3] |= 0; - else if (params->frequency < 1550000) - buf[3] |= 0x40; - else if (params->frequency < 2050000) - buf[3] |= 0x80; - else if (params->frequency < 2150000) - buf[3] |= 0xC0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static u8 typhoon_cinergy1200s_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - 0x08, 0x40, /* DiSEqC off */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - 0x10, 0x3f, // AGC2 0x3d - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, // lock detector threshold - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 - 0x29, 0x1e, // 1/2 threshold - 0x2a, 0x14, // 2/3 threshold - 0x2b, 0x0f, // 3/4 threshold - 0x2c, 0x09, // 5/6 threshold - 0x2d, 0x05, // 7/8 threshold - 0x2e, 0x01, - 0x31, 0x1f, // test all FECs - 0x32, 0x19, // viterbi and synchro search - 0x33, 0xfc, // rs control - 0x34, 0x93, // error control - 0x0f, 0x92, - 0xff, 0xff -}; - -static struct stv0299_config typhoon_config = { - .demod_address = 0x68, - .inittab = typhoon_cinergy1200s_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, -}; - - -static struct stv0299_config cinergy_1200s_config = { - .demod_address = 0x68, - .inittab = typhoon_cinergy1200s_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_0, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, -}; - -static struct stv0299_config cinergy_1200s_1894_0010_config = { - .demod_address = 0x68, - .inittab = typhoon_cinergy1200s_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, -}; - -static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - u8 buf[6]; - struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; - int i; - -#define CU1216_IF 36125000 -#define TUNER_MUL 62500 - - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0xce; - buf[3] = (params->frequency < 150000000 ? 0x01 : - params->frequency < 445000000 ? 0x02 : 0x04); - buf[4] = 0xde; - buf[5] = 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - - /* wait for the pll lock */ - msg.flags = I2C_M_RD; - msg.len = 1; - for (i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40)) - break; - msleep(10); - } - - /* switch the charge pump to the lower current */ - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[2]; - buf[2] &= ~0x40; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static struct tda1002x_config philips_cu1216_config = { - .demod_address = 0x0c, - .invert = 1, -}; - -static struct tda1002x_config philips_cu1216_config_altaddress = { - .demod_address = 0x0d, - .invert = 0, -}; - -static struct tda10023_config philips_cu1216_tda10023_config = { - .demod_address = 0x0c, - .invert = 1, -}; - -static int philips_tu1216_tuner_init(struct dvb_frontend *fe) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; - - // setup PLL configuration - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - msleep(1); - - return 0; -} - -static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = - sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = params->frequency + 36166000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) - cp = 3; - else if (tuner_frequency < 160000000) - cp = 5; - else if (tuner_frequency < 200000000) - cp = 6; - else if (tuner_frequency < 290000000) - cp = 3; - else if (tuner_frequency < 420000000) - cp = 5; - else if (tuner_frequency < 480000000) - cp = 6; - else if (tuner_frequency < 620000000) - cp = 3; - else if (tuner_frequency < 830000000) - cp = 5; - else if (tuner_frequency < 895000000) - cp = 7; - else - return -EINVAL; - - // determine band - if (params->frequency < 49000000) - return -EINVAL; - else if (params->frequency < 161000000) - band = 1; - else if (params->frequency < 444000000) - band = 2; - else if (params->frequency < 861000000) - band = 4; - else - return -EINVAL; - - // setup PLL filter - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - filter = 0; - break; - - case BANDWIDTH_7_MHZ: - filter = 0; - break; - - case BANDWIDTH_8_MHZ: - filter = 1; - break; - - default: - return -EINVAL; - } - - // calculate divisor - // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; - - // setup tuner buffer - tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - return 0; -} - -static int philips_tu1216_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - - return request_firmware(fw, name, &budget->dev->pci->dev); -} - -static struct tda1004x_config philips_tu1216_config = { - - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 1, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tu1216_request_firmware, -}; - -static u8 philips_sd1878_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, - 0x05, 0x35, - 0x06, 0x40, - 0x07, 0x00, - 0x08, 0x43, - 0x09, 0x02, - 0x0C, 0x51, - 0x0D, 0x82, - 0x0E, 0x23, - 0x10, 0x3f, - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, - 0x16, 0x19, - 0x17, 0x8c, - 0x18, 0x59, - 0x19, 0xf8, - 0x1a, 0xfe, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, - 0x29, 0x28, - 0x2a, 0x14, - 0x2b, 0x0f, - 0x2c, 0x09, - 0x2d, 0x09, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x93, - 0xff, 0xff -}; - -static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - u8 m1; - - aclk = 0xb5; - if (srate < 2000000) - bclk = 0x86; - else if (srate < 5000000) - bclk = 0x89; - else if (srate < 15000000) - bclk = 0x8f; - else if (srate < 45000000) - bclk = 0x95; - - m1 = 0x14; - if (srate < 4000000) - m1 = 0x10; - - stv0299_writereg(fe, 0x0e, 0x23); - stv0299_writereg(fe, 0x0f, 0x94); - stv0299_writereg(fe, 0x10, 0x39); - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x15, 0xc9); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - stv0299_writereg(fe, 0x0f, 0x80 | m1); - - return 0; -} - -static struct stv0299_config philips_sd1878_config = { - .demod_address = 0x68, - .inittab = philips_sd1878_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, -}; - -/* KNC1 DVB-S (STB0899) Inittab */ -static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = { - - { STB0899_DEV_ID , 0x81 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISFIFO , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x8c }, - { STB0899_DISF22RX , 0x9a }, - { STB0899_SYSREG , 0x0b }, - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0x30 }, - { STB0899_IRQSTATUS_2 , 0x00 }, - { STB0899_IRQSTATUS_1 , 0x00 }, - { STB0899_IRQSTATUS_0 , 0x00 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */ - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x20 }, - { STB0899_IOPVALUE3 , 0xc9 }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x40 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x08 }, /* 0x1c */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x00 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x41 }, - { STB0899_AGC1REF , 0x08 }, - { STB0899_RTC , 0x7a }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x33 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xee }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xdd }, - { STB0899_LDT2 , 0xc9 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfb }, - { STB0899_QDCCOMP , 0x03 }, - { STB0899_POWERI , 0x3b }, - { STB0899_POWERQ , 0x3d }, - { STB0899_RCOMP , 0x81 }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x04 }, - { STB0899_AGC2I2 , 0xf5 }, - { STB0899_TLIR , 0x25 }, - { STB0899_RTF , 0x80 }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xca }, - { STB0899_CFRM , 0xf1 }, - { STB0899_CFRL , 0xf3 }, - { STB0899_NIRM , 0x2a }, - { STB0899_NIRL , 0x05 }, - { STB0899_ISYMB , 0x17 }, - { STB0899_QSYMB , 0xfa }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0xfd }, - { STB0899_EQUAQ1 , 0x04 }, - { STB0899_EQUAI2 , 0x0f }, - { STB0899_EQUAQ2 , 0xff }, - { STB0899_EQUAI3 , 0xdf }, - { STB0899_EQUAQ3 , 0xfa }, - { STB0899_EQUAI4 , 0x37 }, - { STB0899_EQUAQ4 , 0x0d }, - { STB0899_EQUAI5 , 0xbd }, - { STB0899_EQUAQ5 , 0xf7 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0xff }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x00 }, - { STB0899_ECNT3L , 0x00 }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xf0 }, - { STB0899_VTH23 , 0xa0 }, - { STB0899_VTH34 , 0x78 }, - { STB0899_VTH56 , 0x4e }, - { STB0899_VTH67 , 0x48 }, - { STB0899_VTH78 , 0x38 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x40 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x0c }, - { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x00 }, - { STB0899_TSLLSTKL , 0x00 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0xab }, - { STB0899_PCKLENUL , 0x00 }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xcc }, - { STB0899_TSSTATUS , 0x80 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x96 }, - { STB0899_ERRCTRL3 , 0x89 }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x1f }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0x00 }, - { STB0899_MATSTRL , 0x00 }, - { STB0899_UPLSTRM , 0x00 }, - { STB0899_UPLSTRL , 0x00 }, - { STB0899_DFLSTRM , 0x00 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x00 }, - { STB0899_SYNCDSTRM , 0x00 }, - { STB0899_SYNCDSTRL , 0x00 }, - { STB0899_CFGPDELSTATUS1 , 0x10 }, - { STB0899_CFGPDELSTATUS2 , 0x00 }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x00 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - -/* STB0899 demodulator config for the KNC1 and clones */ -static struct stb0899_config knc1_dvbs2_config = { - .init_dev = knc1_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = knc1_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .postproc = NULL, - - .demod_address = 0x68, -// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */ - .block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */ -// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */ - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_OFF, /* 1 */ - - .lo_clk = 76500000, - .hi_clk = 90000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = tda8261_get_frequency, - .tuner_set_frequency = tda8261_set_frequency, - .tuner_set_bandwidth = NULL, - .tuner_get_bandwidth = tda8261_get_bandwidth, - .tuner_set_rfsiggain = NULL -}; - -/* - * SD1878/SHA tuner config - * 1F, Single I/P, Horizontal mount, High Sensitivity - */ -static const struct tda8261_config sd1878c_config = { -// .name = "SD1878/SHA", - .addr = 0x60, - .step_size = TDA8261_STEP_1000 /* kHz */ -}; - -static u8 read_pwm(struct budget_av *budget_av) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1}, - {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} - }; - - if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2) - || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -#define SUBID_DVBS_KNC1 0x0010 -#define SUBID_DVBS_KNC1_PLUS 0x0011 -#define SUBID_DVBS_TYPHOON 0x4f56 -#define SUBID_DVBS_CINERGY1200 0x1154 -#define SUBID_DVBS_CYNERGY1200N 0x1155 -#define SUBID_DVBS_TV_STAR 0x0014 -#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015 -#define SUBID_DVBS_TV_STAR_CI 0x0016 -#define SUBID_DVBS2_KNC1 0x0018 -#define SUBID_DVBS2_KNC1_OEM 0x0019 -#define SUBID_DVBS_EASYWATCH_1 0x001a -#define SUBID_DVBS_EASYWATCH_2 0x001b -#define SUBID_DVBS2_EASYWATCH 0x001d -#define SUBID_DVBS_EASYWATCH 0x001e - -#define SUBID_DVBC_EASYWATCH 0x002a -#define SUBID_DVBC_EASYWATCH_MK3 0x002c -#define SUBID_DVBC_KNC1 0x0020 -#define SUBID_DVBC_KNC1_PLUS 0x0021 -#define SUBID_DVBC_KNC1_MK3 0x0022 -#define SUBID_DVBC_KNC1_PLUS_MK3 0x0023 -#define SUBID_DVBC_CINERGY1200 0x1156 -#define SUBID_DVBC_CINERGY1200_MK3 0x1176 - -#define SUBID_DVBT_EASYWATCH 0x003a -#define SUBID_DVBT_KNC1_PLUS 0x0031 -#define SUBID_DVBT_KNC1 0x0030 -#define SUBID_DVBT_CINERGY1200 0x1157 - -static void frontend_init(struct budget_av *budget_av) -{ - struct saa7146_dev * saa = budget_av->budget.dev; - struct dvb_frontend * fe = NULL; - - /* Enable / PowerON Frontend */ - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); - - /* Wait for PowerON */ - msleep(100); - - /* additional setup necessary for the PLUS cards */ - switch (saa->pci->subsystem_device) { - case SUBID_DVBS_KNC1_PLUS: - case SUBID_DVBC_KNC1_PLUS: - case SUBID_DVBT_KNC1_PLUS: - case SUBID_DVBC_EASYWATCH: - case SUBID_DVBC_KNC1_PLUS_MK3: - case SUBID_DVBS2_KNC1: - case SUBID_DVBS2_KNC1_OEM: - case SUBID_DVBS2_EASYWATCH: - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); - break; - } - - switch (saa->pci->subsystem_device) { - - case SUBID_DVBS_KNC1: - /* - * maybe that setting is needed for other dvb-s cards as well, - * but so far it has been only confirmed for this type - */ - budget_av->reinitialise_demod = 1; - /* fall through */ - case SUBID_DVBS_KNC1_PLUS: - case SUBID_DVBS_EASYWATCH_1: - if (saa->pci->subsystem_vendor == 0x1894) { - fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config, - &budget_av->budget.i2c_adap); - if (fe) { - dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap); - } - } else { - fe = dvb_attach(stv0299_attach, &typhoon_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; - } - } - break; - - case SUBID_DVBS_TV_STAR: - case SUBID_DVBS_TV_STAR_PLUS_X4: - case SUBID_DVBS_TV_STAR_CI: - case SUBID_DVBS_CYNERGY1200N: - case SUBID_DVBS_EASYWATCH: - case SUBID_DVBS_EASYWATCH_2: - fe = dvb_attach(stv0299_attach, &philips_sd1878_config, - &budget_av->budget.i2c_adap); - if (fe) { - dvb_attach(dvb_pll_attach, fe, 0x60, - &budget_av->budget.i2c_adap, - DVB_PLL_PHILIPS_SD1878_TDA8261); - } - break; - - case SUBID_DVBS_TYPHOON: - fe = dvb_attach(stv0299_attach, &typhoon_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; - } - break; - case SUBID_DVBS2_KNC1: - case SUBID_DVBS2_KNC1_OEM: - case SUBID_DVBS2_EASYWATCH: - budget_av->reinitialise_demod = 1; - if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap))) - dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap); - - break; - case SUBID_DVBS_CINERGY1200: - fe = dvb_attach(stv0299_attach, &cinergy_1200s_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; - } - break; - - case SUBID_DVBC_KNC1: - case SUBID_DVBC_KNC1_PLUS: - case SUBID_DVBC_CINERGY1200: - case SUBID_DVBC_EASYWATCH: - budget_av->reinitialise_demod = 1; - budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - fe = dvb_attach(tda10021_attach, &philips_cu1216_config, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe == NULL) - fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe) { - fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; - } - break; - - case SUBID_DVBC_EASYWATCH_MK3: - case SUBID_DVBC_CINERGY1200_MK3: - case SUBID_DVBC_KNC1_MK3: - case SUBID_DVBC_KNC1_PLUS_MK3: - budget_av->reinitialise_demod = 1; - budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - fe = dvb_attach(tda10023_attach, - &philips_cu1216_tda10023_config, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe) { - fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; - } - break; - - case SUBID_DVBT_EASYWATCH: - case SUBID_DVBT_KNC1: - case SUBID_DVBT_KNC1_PLUS: - case SUBID_DVBT_CINERGY1200: - budget_av->reinitialise_demod = 1; - fe = dvb_attach(tda10046_attach, &philips_tu1216_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.init = philips_tu1216_tuner_init; - fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params; - } - break; - } - - if (fe == NULL) { - printk(KERN_ERR "budget-av: A frontend driver was not found " - "for device [%04x:%04x] subsystem [%04x:%04x]\n", - saa->pci->vendor, - saa->pci->device, - saa->pci->subsystem_vendor, - saa->pci->subsystem_device); - return; - } - - budget_av->budget.dvb_frontend = fe; - - if (dvb_register_frontend(&budget_av->budget.dvb_adapter, - budget_av->budget.dvb_frontend)) { - printk(KERN_ERR "budget-av: Frontend registration failed!\n"); - dvb_frontend_detach(budget_av->budget.dvb_frontend); - budget_av->budget.dvb_frontend = NULL; - } -} - - -static void budget_av_irq(struct saa7146_dev *dev, u32 * isr) -{ - struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; - - dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av); - - if (*isr & MASK_10) - ttpci_budget_irq10_handler(dev, isr); -} - -static int budget_av_detach(struct saa7146_dev *dev) -{ - struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; - int err; - - dprintk(2, "dev: %p\n", dev); - - if (1 == budget_av->has_saa7113) { - saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); - - msleep(200); - - saa7146_unregister_device(&budget_av->vd, dev); - - saa7146_vv_release(dev); - } - - if (budget_av->budget.ci_present) - ciintf_deinit(budget_av); - - if (budget_av->budget.dvb_frontend != NULL) { - dvb_unregister_frontend(budget_av->budget.dvb_frontend); - dvb_frontend_detach(budget_av->budget.dvb_frontend); - } - err = ttpci_budget_deinit(&budget_av->budget); - - kfree(budget_av); - - return err; -} - -#define KNC1_INPUTS 2 -static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { - { 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, - V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, - V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, -}; - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); - if (i->index >= KNC1_INPUTS) - return -EINVAL; - memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; - - *i = budget_av->cur_input; - - dprintk(1, "VIDIOC_G_INPUT %d.\n", *i); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; - - dprintk(1, "VIDIOC_S_INPUT %d.\n", input); - return saa7113_setinput(budget_av, input); -} - -static struct saa7146_ext_vv vv_data; - -static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct budget_av *budget_av; - u8 *mac; - int err; - - dprintk(2, "dev: %p\n", dev); - - if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL))) - return -ENOMEM; - - budget_av->has_saa7113 = 0; - budget_av->budget.ci_present = 0; - - dev->ext_priv = budget_av; - - err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE, - adapter_nr); - if (err) { - kfree(budget_av); - return err; - } - - /* knc1 initialization */ - saa7146_write(dev, DD1_STREAM_B, 0x04000000); - saa7146_write(dev, DD1_INIT, 0x07000600); - saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26); - - if (saa7113_init(budget_av) == 0) { - budget_av->has_saa7113 = 1; - - if (0 != saa7146_vv_init(dev, &vv_data)) { - /* fixme: proper cleanup here */ - ERR(("cannot init vv subsystem.\n")); - return err; - } - vv_data.ops.vidioc_enum_input = vidioc_enum_input; - vv_data.ops.vidioc_g_input = vidioc_g_input; - vv_data.ops.vidioc_s_input = vidioc_s_input; - - if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { - /* fixme: proper cleanup here */ - ERR(("cannot register capture v4l2 device.\n")); - saa7146_vv_release(dev); - return err; - } - - /* beware: this modifies dev->vv ... */ - saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A, - SAA7146_HPS_SYNC_PORT_A); - - saa7113_setinput(budget_av, 0); - } - - /* fixme: find some sane values here... */ - saa7146_write(dev, PCI_BT_V1, 0x1c00101f); - - mac = budget_av->budget.dvb_adapter.proposed_mac; - if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) { - printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n", - budget_av->budget.dvb_adapter.num); - memset(mac, 0, 6); - } else { - printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - budget_av->budget.dvb_adapter.num, - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - } - - budget_av->budget.dvb_adapter.priv = budget_av; - frontend_init(budget_av); - ciintf_init(budget_av); - - ttpci_budget_init_hooks(&budget_av->budget); - - return 0; -} - -static struct saa7146_standard standard[] = { - {.name = "PAL",.id = V4L2_STD_PAL, - .v_offset = 0x17,.v_field = 288, - .h_offset = 0x14,.h_pixels = 680, - .v_max_out = 576,.h_max_out = 768 }, - - {.name = "NTSC",.id = V4L2_STD_NTSC, - .v_offset = 0x16,.v_field = 240, - .h_offset = 0x06,.h_pixels = 708, - .v_max_out = 480,.h_max_out = 640, }, -}; - -static struct saa7146_ext_vv vv_data = { - .inputs = 2, - .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 - .flags = 0, - .stds = &standard[0], - .num_stds = ARRAY_SIZE(standard), -}; - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); -MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2); -MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2); -MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); -MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); -MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); -MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); -MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); -MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S); -MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); -MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); -MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T); -MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); -MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP); -MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); -MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); -MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); -MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); -MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); -MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); -MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); -MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); -MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), - MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), - MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), - MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), - MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011), - MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), - MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015), - MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), - MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018), - MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019), - MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d), - MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), - MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), - MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), - MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), - MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), - MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a), - MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), - MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), - MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), - MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023), - MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), - MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), - MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), - MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), - MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), - MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176), - MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_extension budget_extension = { - .name = "budget_av", - .flags = SAA7146_USE_I2C_IRQ, - - .pci_tbl = pci_tbl, - - .module = THIS_MODULE, - .attach = budget_av_attach, - .detach = budget_av_detach, - - .irq_mask = MASK_10, - .irq_func = budget_av_irq, -}; - -static int __init budget_av_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_av_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -module_init(budget_av_init); -module_exit(budget_av_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,793 +0,0 @@ -/* - * budget.c: driver for the SAA7146 based Budget DVB cards - * - * Compiled from various sources by Michael Hunold - * - * Copyright (C) 2002 Ralph Metzler - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * 26feb2004 Support for FS Activy Card (Grundig tuner) by - * Michael Dreher , - * Oliver Endriss and - * Andreas 'randy' Weinberger - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include "budget.h" -#include "stv0299.h" -#include "ves1x93.h" -#include "ves1820.h" -#include "l64781.h" -#include "tda8083.h" -#include "s5h1420.h" -#include "tda10086.h" -#include "tda826x.h" -#include "lnbp21.h" -#include "bsru6.h" -#include "bsbe1.h" -#include "tdhd1.h" -#include "stv6110x.h" -#include "stv090x.h" -#include "isl6423.h" - -static int diseqc_method; -module_param(diseqc_method, int, 0444); -MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static void Set22K (struct budget *budget, int state) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); -} - -/* Diseqc functions only for TT Budget card */ -/* taken from the Skyvision DVB driver by - Ralph Metzler */ - -static void DiseqcSendBit (struct budget *budget, int data) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - udelay(data ? 500 : 1000); - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - udelay(data ? 1000 : 500); -} - -static void DiseqcSendByte (struct budget *budget, int data) -{ - int i, par=1, d; - - dprintk(2, "budget: %p\n", budget); - - for (i=7; i>=0; i--) { - d = (data>>i)&1; - par ^= d; - DiseqcSendBit(budget, d); - } - - DiseqcSendBit(budget, par); -} - -static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) -{ - struct saa7146_dev *dev=budget->dev; - int i; - - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - mdelay(16); - - for (i=0; idev; - - dprintk(2, "budget: %p\n", budget); - - switch (voltage) { - case SEC_VOLTAGE_13: - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); - break; - case SEC_VOLTAGE_18: - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - break; - case SEC_VOLTAGE_OFF: - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - return SetVoltage_Activy (budget, voltage); -} - -static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - switch (tone) { - case SEC_TONE_ON: - Set22K (budget, 1); - break; - - case SEC_TONE_OFF: - Set22K (budget, 0); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); - - return 0; -} - -static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, 0, NULL, minicmd); - - return 0; -} - -static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - u8 pwr = 0; - u8 buf[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (params->frequency + 479500) / 125; - - if (params->frequency > 2000000) pwr = 3; - else if (params->frequency > 1800000) pwr = 2; - else if (params->frequency > 1600000) pwr = 1; - else if (params->frequency > 1200000) pwr = 0; - else if (params->frequency >= 1100000) pwr = 1; - else pwr = 2; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = ((div & 0x18000) >> 10) | 0x95; - buf[3] = (pwr << 6) | 0x30; - - // NOTE: since we're using a prescaler of 2, we set the - // divisor frequency to 62.5kHz and divide by 125 above - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct ves1x93_config alps_bsrv2_config = -{ - .demod_address = 0x08, - .xin = 90100000UL, - .invert_pwm = 0, -}; - -static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (params->frequency + 35937500 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct ves1820_config alps_tdbe2_config = { - .demod_address = 0x09, - .xin = 57840000UL, - .invert = 1, - .selagc = VES1820_SELAGC_SIGNAMPERR, -}; - -static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct budget *budget = fe->dvb->priv; - u8 *tuner_addr = fe->tuner_priv; - u32 div; - u8 cfg, cpump, band_select; - u8 data[4]; - struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) }; - - if (tuner_addr) - msg.addr = *tuner_addr; - else - msg.addr = 0x61; - - div = (36125000 + params->frequency) / 166666; - - cfg = 0x88; - - if (params->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) cpump = 1; - else cpump = 3; - - if (params->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) band_select = 0x05; - else band_select = 0x03; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = ((div >> 10) & 0x60) | cfg; - data[3] = (cpump << 6) | band_select; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct l64781_config grundig_29504_401_config = { - .demod_address = 0x55, -}; - -static struct l64781_config grundig_29504_401_config_activy = { - .demod_address = 0x54, -}; - -static u8 tuner_address_grundig_29504_401_activy = 0x60; - -static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = params->frequency / 125; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x8e; - data[3] = 0x00; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct tda8083_config grundig_29504_451_config = { - .demod_address = 0x68, -}; - -static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = params->frequency / 1000; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0xc2; - - if (div < 1450) - data[3] = 0x00; - else if (div < 1850) - data[3] = 0x40; - else if (div < 2000) - data[3] = 0x80; - else - data[3] = 0xc0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - - return 0; -} - -static struct s5h1420_config s5h1420_config = { - .demod_address = 0x53, - .invert = 1, - .cdclk_polarity = 1, -}; - -static struct tda10086_config tda10086_config = { - .demod_address = 0x0e, - .invert = 0, - .diseqc_tone = 1, - .xtal_freq = TDA10086_XTAL_16M, -}; - -static struct stv0299_config alps_bsru6_config_activy = { - .demod_address = 0x68, - .inittab = alps_bsru6_inittab, - .mclk = 88000000UL, - .invert = 1, - .op0_off = 1, - .min_delay_ms = 100, - .set_symbol_rate = alps_bsru6_set_symbol_rate, -}; - -static struct stv0299_config alps_bsbe1_config_activy = { - .demod_address = 0x68, - .inittab = alps_bsbe1_inittab, - .mclk = 88000000UL, - .invert = 1, - .op0_off = 1, - .min_delay_ms = 100, - .set_symbol_rate = alps_bsbe1_set_symbol_rate, -}; - -static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) -{ - struct budget *budget = (struct budget *)fe->dvb->priv; - - return request_firmware(fw, name, &budget->dev->pci->dev); -} - - -static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) -{ - u8 val; - struct i2c_msg msg[] = { - { .addr = adr, .flags = 0, .buf = ®, .len = 1 }, - { .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 } - }; - - return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val; -} - -static u8 read_pwm(struct budget* budget) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, - { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; - - if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -static struct stv090x_config tt1600_stv090x_config = { - .device = STV0903, - .demod_mode = STV090x_SINGLE, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 13500000, - .address = 0x68, - - .ts1_mode = STV090x_TSMODE_DVBCI, - .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, - - .repeater_level = STV090x_RPTLEVEL_16, - - .tuner_init = NULL, - .tuner_sleep = NULL, - .tuner_set_mode = NULL, - .tuner_set_frequency = NULL, - .tuner_get_frequency = NULL, - .tuner_set_bandwidth = NULL, - .tuner_get_bandwidth = NULL, - .tuner_set_bbgain = NULL, - .tuner_get_bbgain = NULL, - .tuner_set_refclk = NULL, - .tuner_get_status = NULL, -}; - -static struct stv6110x_config tt1600_stv6110x_config = { - .addr = 0x60, - .refclk = 27000000, - .clk_div = 2, -}; - -static struct isl6423_config tt1600_isl6423_config = { - .current_max = SEC_CURRENT_515m, - .curlim = SEC_CURRENT_LIM_ON, - .mod_extern = 1, - .addr = 0x08, -}; - -static void frontend_init(struct budget *budget) -{ - (void)alps_bsbe1_config; /* avoid warning */ - - switch(budget->dev->pci->subsystem_device) { - case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659)) - case 0x1013: - // try the ALPS BSRV2 first of all - budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - break; - } - - // try the ALPS BSRU6 now - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) { - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - } - break; - } - break; - - case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) - - budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget)); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; - break; - } - break; - - case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060)) - - budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; - budget->dvb_frontend->tuner_priv = NULL; - break; - } - break; - - case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */ - { - int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67); - - if (subtype < 0) - break; - /* fixme: find a better way to identify the card */ - if (subtype < 0x36) { - /* assume ALPS BSRU6 */ - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap); - if (budget->dvb_frontend) { - printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n"); - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - break; - } - } else { - /* assume ALPS BSBE1 */ - /* reset tuner */ - saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO); - msleep(50); - saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI); - msleep(250); - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap); - if (budget->dvb_frontend) { - printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n"); - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - break; - } - } - break; - } - - case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522)) - budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; - budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - } - break; - - case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */ - budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - } - break; - - case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ - budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy; - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; - } - break; - - case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) - budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params; - if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { - printk("%s: No LNBP21 found!\n", __func__); - goto error_out; - } - break; - } - - case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262) - // gpio2 is connected to CLB - reset it + leave it high - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); - msleep(1); - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); - msleep(1); - - budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL) - printk("%s: No tda826x found!\n", __func__); - if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { - printk("%s: No LNBP21 found!\n", __func__); - goto error_out; - } - break; - } - - case 0x101c: { /* TT S2-1600 */ - struct stv6110x_devctl *ctl; - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); - msleep(50); - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); - msleep(250); - - budget->dvb_frontend = dvb_attach(stv090x_attach, - &tt1600_stv090x_config, - &budget->i2c_adap, - STV090x_DEMODULATOR_0); - - if (budget->dvb_frontend) { - - ctl = dvb_attach(stv6110x_attach, - budget->dvb_frontend, - &tt1600_stv6110x_config, - &budget->i2c_adap); - - if (ctl) { - tt1600_stv090x_config.tuner_init = ctl->tuner_init; - tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; - tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; - tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; - tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; - tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; - tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; - tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; - tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; - tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; - tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; - - /* call the init function once to initialize - tuner's clock output divider and demod's - master clock */ - if (budget->dvb_frontend->ops.init) - budget->dvb_frontend->ops.init(budget->dvb_frontend); - - if (dvb_attach(isl6423_attach, - budget->dvb_frontend, - &budget->i2c_adap, - &tt1600_isl6423_config) == NULL) { - printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__); - goto error_out; - } - } else { - printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); - goto error_out; - } - } - } - break; - } - - if (budget->dvb_frontend == NULL) { - printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - budget->dev->pci->vendor, - budget->dev->pci->device, - budget->dev->pci->subsystem_vendor, - budget->dev->pci->subsystem_device); - } else { - if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) - goto error_out; - } - return; - -error_out: - printk("budget: Frontend registration failed!\n"); - dvb_frontend_detach(budget->dvb_frontend); - budget->dvb_frontend = NULL; - return; -} - -static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) -{ - struct budget *budget = NULL; - int err; - - budget = kmalloc(sizeof(struct budget), GFP_KERNEL); - if( NULL == budget ) { - return -ENOMEM; - } - - dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget); - - dev->ext_priv = budget; - - err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); - if (err) { - printk("==> failed\n"); - kfree (budget); - return err; - } - - budget->dvb_adapter.priv = budget; - frontend_init(budget); - - ttpci_budget_init_hooks(budget); - - return 0; -} - -static int budget_detach (struct saa7146_dev* dev) -{ - struct budget *budget = (struct budget*) dev->ext_priv; - int err; - - if (budget->dvb_frontend) { - dvb_unregister_frontend(budget->dvb_frontend); - dvb_frontend_detach(budget->dvb_frontend); - } - - err = ttpci_budget_deinit (budget); - - kfree (budget); - dev->ext_priv = NULL; - - return err; -} - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); -MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); -MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), - MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), - MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), - MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), - MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), - MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), - MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c), - MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), - MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), - MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), - MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_extension budget_extension = { - .name = "budget dvb", - .flags = SAA7146_USE_I2C_IRQ, - - .module = THIS_MODULE, - .pci_tbl = pci_tbl, - .attach = budget_attach, - .detach = budget_detach, - - .irq_mask = MASK_10, - .irq_func = ttpci_budget_irq10_handler, -}; - -static int __init budget_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -module_init(budget_init); -module_exit(budget_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB cards by Siemens, Technotrend, Hauppauge"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-ci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-ci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-ci.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-ci.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1568 +0,0 @@ -/* - * budget-ci.c: driver for the SAA7146 based Budget DVB cards - * - * Compiled from various sources by Michael Hunold - * - * msp430 IR support contributed by Jack Thomasson - * partially based on the Siemens DVB driver by Ralph+Marcus Metzler - * - * CI interface support (c) 2004 Andrew de Quincey - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include -#include -#include -#include -#include -#include - -#include "budget.h" - -#include "dvb_ca_en50221.h" -#include "stv0299.h" -#include "stv0297.h" -#include "tda1004x.h" -#include "stb0899_drv.h" -#include "stb0899_reg.h" -#include "stb0899_cfg.h" -#include "stb6100.h" -#include "stb6100_cfg.h" -#include "lnbp21.h" -#include "bsbe1.h" -#include "bsru6.h" -#include "tda1002x.h" -#include "tda827x.h" - -#define MODULE_NAME "budget_ci" - -/* - * Regarding DEBIADDR_IR: - * Some CI modules hang if random addresses are read. - * Using address 0x4000 for the IR read means that we - * use the same address as for CI version, which should - * be a safe default. - */ -#define DEBIADDR_IR 0x4000 -#define DEBIADDR_CICONTROL 0x0000 -#define DEBIADDR_CIVERSION 0x4000 -#define DEBIADDR_IO 0x1000 -#define DEBIADDR_ATTR 0x3000 - -#define CICONTROL_RESET 0x01 -#define CICONTROL_ENABLETS 0x02 -#define CICONTROL_CAMDETECT 0x08 - -#define DEBICICTL 0x00420000 -#define DEBICICAM 0x02420000 - -#define SLOTSTATUS_NONE 1 -#define SLOTSTATUS_PRESENT 2 -#define SLOTSTATUS_RESET 4 -#define SLOTSTATUS_READY 8 -#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) - -/* RC5 device wildcard */ -#define IR_DEVICE_ANY 255 - -static int rc5_device = -1; -module_param(rc5_device, int, 0644); -MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)"); - -static int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct budget_ci_ir { - struct rc_dev *dev; - struct tasklet_struct msp430_irq_tasklet; - char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ - char phys[32]; - int rc5_device; - u32 ir_key; - bool have_command; - bool full_rc5; /* Outputs a full RC5 code */ -}; - -struct budget_ci { - struct budget budget; - struct tasklet_struct ciintf_irq_tasklet; - int slot_status; - int ci_irq; - struct dvb_ca_en50221 ca; - struct budget_ci_ir ir; - u8 tuner_pll_address; /* used for philips_tdm1316l configs */ -}; - -static void msp430_ir_interrupt(unsigned long data) -{ - struct budget_ci *budget_ci = (struct budget_ci *) data; - struct rc_dev *dev = budget_ci->ir.dev; - u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; - - /* - * The msp430 chip can generate two different bytes, command and device - * - * type1: X1CCCCCC, C = command bits (0 - 63) - * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit - * - * Each signal from the remote control can generate one or more command - * bytes and one or more device bytes. For the repeated bytes, the - * highest bit (X) is set. The first command byte is always generated - * before the first device byte. Other than that, no specific order - * seems to apply. To make life interesting, bytes can also be lost. - * - * Only when we have a command and device byte, a keypress is - * generated. - */ - - if (ir_debug) - printk("budget_ci: received byte 0x%02x\n", command); - - /* Remove repeat bit, we use every command */ - command = command & 0x7f; - - /* Is this a RC5 command byte? */ - if (command & 0x40) { - budget_ci->ir.have_command = true; - budget_ci->ir.ir_key = command & 0x3f; - return; - } - - /* It's a RC5 device byte */ - if (!budget_ci->ir.have_command) - return; - budget_ci->ir.have_command = false; - - if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && - budget_ci->ir.rc5_device != (command & 0x1f)) - return; - - if (budget_ci->ir.full_rc5) { - rc_keydown(dev, - budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key, - (command & 0x20) ? 1 : 0); - return; - } - - /* FIXME: We should generate complete scancodes for all devices */ - rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0); -} - -static int msp430_ir_init(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - struct rc_dev *dev; - int error; - - dev = rc_allocate_device(); - if (!dev) { - printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); - return -ENOMEM; - } - - snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), - "Budget-CI dvb ir receiver %s", saa->name); - snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys), - "pci-%s/ir0", pci_name(saa->pci)); - - dev->driver_name = MODULE_NAME; - dev->input_name = budget_ci->ir.name; - dev->input_phys = budget_ci->ir.phys; - dev->input_id.bustype = BUS_PCI; - dev->input_id.version = 1; - dev->scanmask = 0xff; - if (saa->pci->subsystem_vendor) { - dev->input_id.vendor = saa->pci->subsystem_vendor; - dev->input_id.product = saa->pci->subsystem_device; - } else { - dev->input_id.vendor = saa->pci->vendor; - dev->input_id.product = saa->pci->device; - } - dev->dev.parent = &saa->pci->dev; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = IR_DEVICE_ANY; - else - budget_ci->ir.rc5_device = rc5_device; - - /* Select keymap and address */ - switch (budget_ci->budget.dev->pci->subsystem_device) { - case 0x100c: - case 0x100f: - case 0x1011: - case 0x1012: - /* The hauppauge keymap is a superset of these remotes */ - dev->map_name = RC_MAP_HAUPPAUGE; - budget_ci->ir.full_rc5 = true; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = 0x1f; - break; - case 0x1010: - case 0x1017: - case 0x1019: - case 0x101a: - /* for the Technotrend 1500 bundled remote */ - dev->map_name = RC_MAP_TT_1500; - break; - default: - /* unknown remote */ - dev->map_name = RC_MAP_BUDGET_CI_OLD; - break; - } - - error = rc_register_device(dev); - if (error) { - printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); - rc_free_device(dev); - return error; - } - - budget_ci->ir.dev = dev; - - tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt, - (unsigned long) budget_ci); - - SAA7146_IER_ENABLE(saa, MASK_06); - saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); - - return 0; -} - -static void msp430_ir_deinit(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - - SAA7146_IER_DISABLE(saa, MASK_06); - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); - - rc_unregister_device(budget_ci->ir.dev); -} - -static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, - DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0); -} - -static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, - DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0); -} - -static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, - DEBIADDR_IO | (address & 3), 1, 1, 0); -} - -static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, - DEBIADDR_IO | (address & 3), 1, value, 1, 0); -} - -static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - struct saa7146_dev *saa = budget_ci->budget.dev; - - if (slot != 0) - return -EINVAL; - - if (budget_ci->ci_irq) { - // trigger on RISING edge during reset so we know when READY is re-asserted - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); - } - budget_ci->slot_status = SLOTSTATUS_RESET; - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); - msleep(1); - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - CICONTROL_RESET, 1, 0); - - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - return 0; -} - -static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - struct saa7146_dev *saa = budget_ci->budget.dev; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - return 0; -} - -static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - struct saa7146_dev *saa = budget_ci->budget.dev; - int tmp; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); - - tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - tmp | CICONTROL_ENABLETS, 1, 0); - - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); - return 0; -} - -static void ciintf_interrupt(unsigned long data) -{ - struct budget_ci *budget_ci = (struct budget_ci *) data; - struct saa7146_dev *saa = budget_ci->budget.dev; - unsigned int flags; - - // ensure we don't get spurious IRQs during initialisation - if (!budget_ci->budget.ci_present) - return; - - // read the CAM status - flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - if (flags & CICONTROL_CAMDETECT) { - - // GPIO should be set to trigger on falling edge if a CAM is present - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); - - if (budget_ci->slot_status & SLOTSTATUS_NONE) { - // CAM insertion IRQ - budget_ci->slot_status = SLOTSTATUS_PRESENT; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, - DVB_CA_EN50221_CAMCHANGE_INSERTED); - - } else if (budget_ci->slot_status & SLOTSTATUS_RESET) { - // CAM ready (reset completed) - budget_ci->slot_status = SLOTSTATUS_READY; - dvb_ca_en50221_camready_irq(&budget_ci->ca, 0); - - } else if (budget_ci->slot_status & SLOTSTATUS_READY) { - // FR/DA IRQ - dvb_ca_en50221_frda_irq(&budget_ci->ca, 0); - } - } else { - - // trigger on rising edge if a CAM is not present - when a CAM is inserted, we - // only want to get the IRQ when it sets READY. If we trigger on the falling edge, - // the CAM might not actually be ready yet. - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); - - // generate a CAM removal IRQ if we haven't already - if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) { - // CAM removal IRQ - budget_ci->slot_status = SLOTSTATUS_NONE; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, - DVB_CA_EN50221_CAMCHANGE_REMOVED); - } - } -} - -static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - unsigned int flags; - - // ensure we don't get spurious IRQs during initialisation - if (!budget_ci->budget.ci_present) - return -EINVAL; - - // read the CAM status - flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - if (flags & CICONTROL_CAMDETECT) { - // mark it as present if it wasn't before - if (budget_ci->slot_status & SLOTSTATUS_NONE) { - budget_ci->slot_status = SLOTSTATUS_PRESENT; - } - - // during a RESET, we check if we can read from IO memory to see when CAM is ready - if (budget_ci->slot_status & SLOTSTATUS_RESET) { - if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) { - budget_ci->slot_status = SLOTSTATUS_READY; - } - } - } else { - budget_ci->slot_status = SLOTSTATUS_NONE; - } - - if (budget_ci->slot_status != SLOTSTATUS_NONE) { - if (budget_ci->slot_status & SLOTSTATUS_READY) { - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - } - return DVB_CA_EN50221_POLL_CAM_PRESENT; - } - - return 0; -} - -static int ciintf_init(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - int flags; - int result; - int ci_version; - int ca_flags; - - memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); - - // enable DEBI pins - saa7146_write(saa, MC1, MASK_27 | MASK_11); - - // test if it is there - ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0); - if ((ci_version & 0xa0) != 0xa0) { - result = -ENODEV; - goto error; - } - - // determine whether a CAM is present or not - flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - budget_ci->slot_status = SLOTSTATUS_NONE; - if (flags & CICONTROL_CAMDETECT) - budget_ci->slot_status = SLOTSTATUS_PRESENT; - - // version 0xa2 of the CI firmware doesn't generate interrupts - if (ci_version == 0xa2) { - ca_flags = 0; - budget_ci->ci_irq = 0; - } else { - ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | - DVB_CA_EN50221_FLAG_IRQ_FR | - DVB_CA_EN50221_FLAG_IRQ_DA; - budget_ci->ci_irq = 1; - } - - // register CI interface - budget_ci->ca.owner = THIS_MODULE; - budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; - budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem; - budget_ci->ca.read_cam_control = ciintf_read_cam_control; - budget_ci->ca.write_cam_control = ciintf_write_cam_control; - budget_ci->ca.slot_reset = ciintf_slot_reset; - budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; - budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; - budget_ci->ca.poll_slot_status = ciintf_poll_slot_status; - budget_ci->ca.data = budget_ci; - if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, - &budget_ci->ca, - ca_flags, 1)) != 0) { - printk("budget_ci: CI interface detected, but initialisation failed.\n"); - goto error; - } - - // Setup CI slot IRQ - if (budget_ci->ci_irq) { - tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci); - if (budget_ci->slot_status != SLOTSTATUS_NONE) { - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); - } else { - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); - } - SAA7146_IER_ENABLE(saa, MASK_03); - } - - // enable interface - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - CICONTROL_RESET, 1, 0); - - // success! - printk("budget_ci: CI interface initialised\n"); - budget_ci->budget.ci_present = 1; - - // forge a fake CI IRQ so the CAM state is setup correctly - if (budget_ci->ci_irq) { - flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; - if (budget_ci->slot_status != SLOTSTATUS_NONE) - flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); - } - - return 0; - -error: - saa7146_write(saa, MC1, MASK_27); - return result; -} - -static void ciintf_deinit(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - - // disable CI interrupts - if (budget_ci->ci_irq) { - SAA7146_IER_DISABLE(saa, MASK_03); - saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); - tasklet_kill(&budget_ci->ciintf_irq_tasklet); - } - - // reset interface - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); - msleep(1); - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - CICONTROL_RESET, 1, 0); - - // disable TS data stream to CI interface - saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); - - // release the CA device - dvb_ca_en50221_release(&budget_ci->ca); - - // disable DEBI pins - saa7146_write(saa, MC1, MASK_27); -} - -static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr) -{ - struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; - - dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); - - if (*isr & MASK_06) - tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet); - - if (*isr & MASK_10) - ttpci_budget_irq10_handler(dev, isr); - - if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) - tasklet_schedule(&budget_ci->ciintf_irq_tasklet); -} - -static u8 philips_su1278_tt_inittab[] = { - 0x01, 0x0f, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x5b, - 0x05, 0x85, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0x02, - 0x09, 0x00, - 0x0C, 0x01, - 0x0D, 0x81, - 0x0E, 0x44, - 0x0f, 0x14, - 0x10, 0x3c, - 0x11, 0x84, - 0x12, 0xda, - 0x13, 0x97, - 0x14, 0x95, - 0x15, 0xc9, - 0x16, 0x19, - 0x17, 0x8c, - 0x18, 0x59, - 0x19, 0xf8, - 0x1a, 0xfe, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, - 0x29, 0x28, - 0x2a, 0x14, - 0x2b, 0x0f, - 0x2c, 0x09, - 0x2d, 0x09, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x93, - 0xff, 0xff -}; - -static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) -{ - stv0299_writereg(fe, 0x0e, 0x44); - if (srate >= 10000000) { - stv0299_writereg(fe, 0x13, 0x97); - stv0299_writereg(fe, 0x14, 0x95); - stv0299_writereg(fe, 0x15, 0xc9); - stv0299_writereg(fe, 0x17, 0x8c); - stv0299_writereg(fe, 0x1a, 0xfe); - stv0299_writereg(fe, 0x1c, 0x7f); - stv0299_writereg(fe, 0x2d, 0x09); - } else { - stv0299_writereg(fe, 0x13, 0x99); - stv0299_writereg(fe, 0x14, 0x8d); - stv0299_writereg(fe, 0x15, 0xce); - stv0299_writereg(fe, 0x17, 0x43); - stv0299_writereg(fe, 0x1a, 0x1d); - stv0299_writereg(fe, 0x1c, 0x12); - stv0299_writereg(fe, 0x2d, 0x05); - } - stv0299_writereg(fe, 0x0e, 0x23); - stv0299_writereg(fe, 0x0f, 0x94); - stv0299_writereg(fe, 0x10, 0x39); - stv0299_writereg(fe, 0x15, 0xc9); - - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - - return 0; -} - -static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - u32 div; - u8 buf[4]; - struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - if ((params->frequency < 950000) || (params->frequency > 2150000)) - return -EINVAL; - - div = (params->frequency + (500 - 1)) / 500; // round correctly - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; - buf[3] = 0x20; - - if (params->u.qpsk.symbol_rate < 4000000) - buf[3] |= 1; - - if (params->frequency < 1250000) - buf[3] |= 0; - else if (params->frequency < 1550000) - buf[3] |= 0x40; - else if (params->frequency < 2050000) - buf[3] |= 0x80; - else if (params->frequency < 2150000) - buf[3] |= 0xC0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct stv0299_config philips_su1278_tt_config = { - - .demod_address = 0x68, - .inittab = philips_su1278_tt_inittab, - .mclk = 64000000UL, - .invert = 0, - .skip_reinit = 1, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 50, - .set_symbol_rate = philips_su1278_tt_set_symbol_rate, -}; - - - -static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) -{ - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; - struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len = - sizeof(td1316_init) }; - - // setup PLL configuration - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - msleep(1); - - // disable the mc44BC374c (do not check for errors) - tuner_msg.addr = 0x65; - tuner_msg.buf = disable_mc44BC374c; - tuner_msg.len = sizeof(disable_mc44BC374c); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1); - } - - return 0; -} - -static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = params->frequency + 36130000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) - cp = 3; - else if (tuner_frequency < 160000000) - cp = 5; - else if (tuner_frequency < 200000000) - cp = 6; - else if (tuner_frequency < 290000000) - cp = 3; - else if (tuner_frequency < 420000000) - cp = 5; - else if (tuner_frequency < 480000000) - cp = 6; - else if (tuner_frequency < 620000000) - cp = 3; - else if (tuner_frequency < 830000000) - cp = 5; - else if (tuner_frequency < 895000000) - cp = 7; - else - return -EINVAL; - - // determine band - if (params->frequency < 49000000) - return -EINVAL; - else if (params->frequency < 159000000) - band = 1; - else if (params->frequency < 444000000) - band = 2; - else if (params->frequency < 861000000) - band = 4; - else - return -EINVAL; - - // setup PLL filter and TDA9889 - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - tda1004x_writereg(fe, 0x0C, 0x14); - filter = 0; - break; - - case BANDWIDTH_7_MHZ: - tda1004x_writereg(fe, 0x0C, 0x80); - filter = 0; - break; - - case BANDWIDTH_8_MHZ: - tda1004x_writereg(fe, 0x0C, 0x14); - filter = 1; - break; - - default: - return -EINVAL; - } - - // calculate divisor - // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - return 0; -} - -static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - - return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev); -} - -static struct tda1004x_config philips_tdm1316l_config = { - - .demod_address = 0x8, - .invert = 0, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tdm1316l_request_firmware, -}; - -static struct tda1004x_config philips_tdm1316l_config_invert = { - - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tdm1316l_request_firmware, -}; - -static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - u8 tuner_buf[5]; - struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, - .flags = 0, - .buf = tuner_buf, - .len = sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = params->frequency + 36125000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) { - cp = 3; - band = 1; - } else if (tuner_frequency < 160000000) { - cp = 5; - band = 1; - } else if (tuner_frequency < 200000000) { - cp = 6; - band = 1; - } else if (tuner_frequency < 290000000) { - cp = 3; - band = 2; - } else if (tuner_frequency < 420000000) { - cp = 5; - band = 2; - } else if (tuner_frequency < 480000000) { - cp = 6; - band = 2; - } else if (tuner_frequency < 620000000) { - cp = 3; - band = 4; - } else if (tuner_frequency < 830000000) { - cp = 5; - band = 4; - } else if (tuner_frequency < 895000000) { - cp = 7; - band = 4; - } else - return -EINVAL; - - // assume PLL filter should always be 8MHz for the moment. - filter = 1; - - // calculate divisor - tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500; - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xc8; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - tuner_buf[4] = 0x80; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(50); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - - return 0; -} - -static u8 dvbc_philips_tdm1316l_inittab[] = { - 0x80, 0x01, - 0x80, 0x00, - 0x81, 0x01, - 0x81, 0x00, - 0x00, 0x09, - 0x01, 0x69, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x20, 0x00, - 0x21, 0x40, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x40, - 0x25, 0x88, - 0x30, 0xff, - 0x31, 0x00, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x50, - 0x35, 0x7f, - 0x36, 0x00, - 0x37, 0x20, - 0x38, 0x00, - 0x40, 0x1c, - 0x41, 0xff, - 0x42, 0x29, - 0x43, 0x20, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0x00, - 0x4b, 0x7b, - 0x52, 0x30, - 0x55, 0xae, - 0x56, 0x47, - 0x57, 0xe1, - 0x58, 0x3a, - 0x5a, 0x1e, - 0x5b, 0x34, - 0x60, 0x00, - 0x63, 0x00, - 0x64, 0x00, - 0x65, 0x00, - 0x66, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x69, 0x00, - 0x6a, 0x02, - 0x6b, 0x00, - 0x70, 0xff, - 0x71, 0x00, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x00, - 0x81, 0x00, - 0x82, 0x00, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x80, - 0x86, 0x24, - 0x87, 0x78, - 0x88, 0x10, - 0x89, 0x00, - 0x90, 0x01, - 0x91, 0x01, - 0xa0, 0x04, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x53, - 0xc1, 0x70, - 0xc2, 0x12, - 0xd0, 0x00, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x00, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x00, - 0x61, 0x38, - 0x62, 0x0a, - 0x53, 0x13, - 0x59, 0x08, - 0xff, 0xff, -}; - -static struct stv0297_config dvbc_philips_tdm1316l_config = { - .demod_address = 0x1c, - .inittab = dvbc_philips_tdm1316l_inittab, - .invert = 0, - .stop_during_read = 1, -}; - -static struct tda10023_config tda10023_config = { - .demod_address = 0xc, - .invert = 0, - .xtal = 16000000, - .pll_m = 11, - .pll_p = 3, - .pll_n = 1, - .deltaf = 0xa511, -}; - -static struct tda827x_config tda827x_config = { - .config = 0, -}; - -/* TT S2-3200 DVB-S (STB0899) Inittab */ -static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { - - { STB0899_DEV_ID , 0x81 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISFIFO , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x8c }, - { STB0899_DISF22RX , 0x9a }, - { STB0899_SYSREG , 0x0b }, - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0x30 }, - { STB0899_IRQSTATUS_2 , 0x00 }, - { STB0899_IRQSTATUS_1 , 0x00 }, - { STB0899_IRQSTATUS_0 , 0x00 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */ - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x20 }, - { STB0899_IOPVALUE3 , 0xc9 }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x40 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x00 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x41 }, - { STB0899_AGC1REF , 0x10 }, - { STB0899_RTC , 0x7a }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x34 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xc7 }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xdd }, - { STB0899_LDT2 , 0xc9 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfb }, - { STB0899_QDCCOMP , 0x03 }, - { STB0899_POWERI , 0x3b }, - { STB0899_POWERQ , 0x3d }, - { STB0899_RCOMP , 0x81 }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x04 }, - { STB0899_AGC2I2 , 0xf5 }, - { STB0899_TLIR , 0x25 }, - { STB0899_RTF , 0x80 }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xca }, - { STB0899_CFRM , 0xf1 }, - { STB0899_CFRL , 0xf3 }, - { STB0899_NIRM , 0x2a }, - { STB0899_NIRL , 0x05 }, - { STB0899_ISYMB , 0x17 }, - { STB0899_QSYMB , 0xfa }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0xfd }, - { STB0899_EQUAQ1 , 0x04 }, - { STB0899_EQUAI2 , 0x0f }, - { STB0899_EQUAQ2 , 0xff }, - { STB0899_EQUAI3 , 0xdf }, - { STB0899_EQUAQ3 , 0xfa }, - { STB0899_EQUAI4 , 0x37 }, - { STB0899_EQUAQ4 , 0x0d }, - { STB0899_EQUAI5 , 0xbd }, - { STB0899_EQUAQ5 , 0xf7 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0xff }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x00 }, - { STB0899_ECNT3L , 0x00 }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xf0 }, - { STB0899_VTH23 , 0xa0 }, - { STB0899_VTH34 , 0x78 }, - { STB0899_VTH56 , 0x4e }, - { STB0899_VTH67 , 0x48 }, - { STB0899_VTH78 , 0x38 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x40 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x0c }, - { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x00 }, - { STB0899_TSLLSTKL , 0x00 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0xab }, - { STB0899_PCKLENUL , 0x00 }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xcc }, - { STB0899_TSSTATUS , 0x80 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x96 }, - { STB0899_ERRCTRL3 , 0x89 }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x1f }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0x00 }, - { STB0899_MATSTRL , 0x00 }, - { STB0899_UPLSTRM , 0x00 }, - { STB0899_UPLSTRL , 0x00 }, - { STB0899_DFLSTRM , 0x00 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x00 }, - { STB0899_SYNCDSTRM , 0x00 }, - { STB0899_SYNCDSTRL , 0x00 }, - { STB0899_CFGPDELSTATUS1 , 0x10 }, - { STB0899_CFGPDELSTATUS2 , 0x00 }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x00 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - -static struct stb0899_config tt3200_config = { - .init_dev = tt3200_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = tt3200_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .postproc = NULL, - - .demod_address = 0x68, - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_ON, /* 1 */ - - .lo_clk = 76500000, - .hi_clk = 99000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = stb6100_get_frequency, - .tuner_set_frequency = stb6100_set_frequency, - .tuner_set_bandwidth = stb6100_set_bandwidth, - .tuner_get_bandwidth = stb6100_get_bandwidth, - .tuner_set_rfsiggain = NULL -}; - -static struct stb6100_config tt3200_stb6100_config = { - .tuner_address = 0x60, - .refclock = 27000000, -}; - -static void frontend_init(struct budget_ci *budget_ci) -{ - switch (budget_ci->budget.dev->pci->subsystem_device) { - case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059)) - budget_ci->budget.dvb_frontend = - dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; - break; - } - break; - - case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059)) - budget_ci->budget.dvb_frontend = - dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params; - break; - } - break; - - case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) - budget_ci->tuner_pll_address = 0x61; - budget_ci->budget.dvb_frontend = - dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) - budget_ci->tuner_pll_address = 0x63; - budget_ci->budget.dvb_frontend = - dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) - budget_ci->tuner_pll_address = 0x60; - budget_ci->budget.dvb_frontend = - dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1017: // TT S-1500 PCI - budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; - budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; - - budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) { - printk("%s: No LNBP21 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */ - budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48); - if (budget_ci->budget.dvb_frontend) { - if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) { - printk(KERN_ERR "%s: No tda827x found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - case 0x1019: // TT S2-3200 PCI - /* - * NOTE! on some STB0899 versions, the internal PLL takes a longer time - * to settle, aka LOCK. On the older revisions of the chip, we don't see - * this, as a result on the newer chips the entire clock tree, will not - * be stable after a freshly POWER 'ed up situation. - * In this case, we should RESET the STB0899 (Active LOW) and wait for - * PLL stabilization. - * - * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is - * connected to the SAA7146 GPIO, GPIO2, Pin 142 - */ - /* Reset Demodulator */ - saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO); - /* Wait for everything to die */ - msleep(50); - /* Pull it up out of Reset state */ - saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI); - /* Wait for PLL to stabilize */ - msleep(250); - /* - * PLL state should be stable now. Ideally, we should check - * for PLL LOCK status. But well, never mind! - */ - budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) { - if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { - printk("%s: No LNBP21 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } else { - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - } - - if (budget_ci->budget.dvb_frontend == NULL) { - printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - budget_ci->budget.dev->pci->vendor, - budget_ci->budget.dev->pci->device, - budget_ci->budget.dev->pci->subsystem_vendor, - budget_ci->budget.dev->pci->subsystem_device); - } else { - if (dvb_register_frontend - (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { - printk("budget-ci: Frontend registration failed!\n"); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } -} - -static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct budget_ci *budget_ci; - int err; - - budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL); - if (!budget_ci) { - err = -ENOMEM; - goto out1; - } - - dprintk(2, "budget_ci: %p\n", budget_ci); - - dev->ext_priv = budget_ci; - - err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE, - adapter_nr); - if (err) - goto out2; - - err = msp430_ir_init(budget_ci); - if (err) - goto out3; - - ciintf_init(budget_ci); - - budget_ci->budget.dvb_adapter.priv = budget_ci; - frontend_init(budget_ci); - - ttpci_budget_init_hooks(&budget_ci->budget); - - return 0; - -out3: - ttpci_budget_deinit(&budget_ci->budget); -out2: - kfree(budget_ci); -out1: - return err; -} - -static int budget_ci_detach(struct saa7146_dev *dev) -{ - struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; - struct saa7146_dev *saa = budget_ci->budget.dev; - int err; - - if (budget_ci->budget.ci_present) - ciintf_deinit(budget_ci); - msp430_ir_deinit(budget_ci); - if (budget_ci->budget.dvb_frontend) { - dvb_unregister_frontend(budget_ci->budget.dvb_frontend); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - } - err = ttpci_budget_deinit(&budget_ci->budget); - - // disable frontend and CI interface - saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); - - kfree(budget_ci); - - return err; -} - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); -MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), - MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), - MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), - MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), - MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), - MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), - MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), - MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_extension budget_extension = { - .name = "budget_ci dvb", - .flags = SAA7146_USE_I2C_IRQ, - - .module = THIS_MODULE, - .pci_tbl = &pci_tbl[0], - .attach = budget_ci_attach, - .detach = budget_ci_detach, - - .irq_mask = MASK_03 | MASK_06 | MASK_10, - .irq_func = budget_ci_irq, -}; - -static int __init budget_ci_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_ci_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -module_init(budget_ci_init); -module_exit(budget_ci_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB cards w/ CI-module produced by " - "Siemens, Technotrend, Hauppauge"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,600 +0,0 @@ -/* - * budget-core.c: driver for the SAA7146 based Budget DVB cards - * - * Compiled from various sources by Michael Hunold - * - * Copyright (C) 2002 Ralph Metzler - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * 26feb2004 Support for FS Activy Card (Grundig tuner) by - * Michael Dreher , - * Oliver Endriss , - * Andreas 'randy' Weinberger - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - - -#include "budget.h" -#include "ttpci-eeprom.h" - -#define TS_WIDTH (2 * TS_SIZE) -#define TS_WIDTH_ACTIVY TS_SIZE -#define TS_WIDTH_DVBC TS_SIZE -#define TS_HEIGHT_MASK 0xf00 -#define TS_HEIGHT_MASK_ACTIVY 0xc00 -#define TS_HEIGHT_MASK_DVBC 0xe00 -#define TS_MIN_BUFSIZE_K 188 -#define TS_MAX_BUFSIZE_K 1410 -#define TS_MAX_BUFSIZE_K_ACTIVY 564 -#define TS_MAX_BUFSIZE_K_DVBC 1316 -#define BUFFER_WARNING_WAIT (30*HZ) - -int budget_debug; -static int dma_buffer_size = TS_MIN_BUFSIZE_K; -module_param_named(debug, budget_debug, int, 0644); -module_param_named(bufsize, dma_buffer_size, int, 0444); -MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); -MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); - -/**************************************************************************** - * TT budget / WinTV Nova - ****************************************************************************/ - -static int stop_ts_capture(struct budget *budget) -{ - dprintk(2, "budget: %p\n", budget); - - saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off - SAA7146_IER_DISABLE(budget->dev, MASK_10); - return 0; -} - -static int start_ts_capture(struct budget *budget) -{ - struct saa7146_dev *dev = budget->dev; - - dprintk(2, "budget: %p\n", budget); - - if (!budget->feeding || !budget->fe_synced) - return 0; - - saa7146_write(dev, MC1, MASK_20); // DMA3 off - - memset(budget->grabbing, 0x00, budget->buffer_size); - - saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); - - budget->ttbp = 0; - - /* - * Signal path on the Activy: - * - * tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory - * - * Since the tuner feeds 204 bytes packets into the SAA7146, - * DMA3 is configured to strip the trailing 16 FEC bytes: - * Pitch: 188, NumBytes3: 188, NumLines3: 1024 - */ - - switch(budget->card->type) { - case BUDGET_FS_ACTIVY: - saa7146_write(dev, DD1_INIT, 0x04000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - break; - case BUDGET_PATCH: - saa7146_write(dev, DD1_INIT, 0x00000200); - saa7146_write(dev, MC2, (MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - break; - case BUDGET_CIN1200C_MK3: - case BUDGET_KNC1C_MK3: - case BUDGET_KNC1CP_MK3: - if (budget->video_port == BUDGET_VIDEO_PORTA) { - saa7146_write(dev, DD1_INIT, 0x06000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - } else { - saa7146_write(dev, DD1_INIT, 0x00000600); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - } - break; - default: - if (budget->video_port == BUDGET_VIDEO_PORTA) { - saa7146_write(dev, DD1_INIT, 0x06000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - } else { - saa7146_write(dev, DD1_INIT, 0x02000600); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - } - } - - saa7146_write(dev, MC2, (MASK_08 | MASK_24)); - mdelay(10); - - saa7146_write(dev, BASE_ODD3, 0); - if (budget->buffer_size > budget->buffer_height * budget->buffer_width) { - // using odd/even buffers - saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width); - } else { - // using a single buffer - saa7146_write(dev, BASE_EVEN3, 0); - } - saa7146_write(dev, PROT_ADDR3, budget->buffer_size); - saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); - - saa7146_write(dev, PITCH3, budget->buffer_width); - saa7146_write(dev, NUM_LINE_BYTE3, - (budget->buffer_height << 16) | budget->buffer_width); - - saa7146_write(dev, MC2, (MASK_04 | MASK_20)); - - SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ - SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ - saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ - - return 0; -} - -static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - int synced; - int ret; - - if (budget->read_fe_status) - ret = budget->read_fe_status(fe, status); - else - ret = -EINVAL; - - if (!ret) { - synced = (*status & FE_HAS_LOCK); - if (synced != budget->fe_synced) { - budget->fe_synced = synced; - spin_lock(&budget->feedlock); - if (synced) - start_ts_capture(budget); - else - stop_ts_capture(budget); - spin_unlock(&budget->feedlock); - } - } - return ret; -} - -static void vpeirq(unsigned long data) -{ - struct budget *budget = (struct budget *) data; - u8 *mem = (u8 *) (budget->grabbing); - u32 olddma = budget->ttbp; - u32 newdma = saa7146_read(budget->dev, PCI_VDP3); - u32 count; - - /* Ensure streamed PCI data is synced to CPU */ - pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); - - /* nearest lower position divisible by 188 */ - newdma -= newdma % 188; - - if (newdma >= budget->buffer_size) - return; - - budget->ttbp = newdma; - - if (budget->feeding == 0 || newdma == olddma) - return; - - if (newdma > olddma) { /* no wraparound, dump olddma..newdma */ - count = newdma - olddma; - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); - } else { /* wraparound, dump olddma..buflen and 0..newdma */ - count = budget->buffer_size - olddma; - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); - count += newdma; - dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188); - } - - if (count > budget->buffer_warning_threshold) - budget->buffer_warnings++; - - if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) { - printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n", - budget->dev->name, __func__, budget->buffer_warnings, count); - budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT; - budget->buffer_warnings = 0; - } -} - - -int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, - int uselocks, int nobusyloop) -{ - struct saa7146_dev *saa = budget->dev; - int result = 0; - unsigned long flags = 0; - - if (count > 4 || count <= 0) - return 0; - - if (uselocks) - spin_lock_irqsave(&budget->debilock, flags); - - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - - saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); - saa7146_write(saa, DEBI_CONFIG, config); - saa7146_write(saa, DEBI_PAGE, 0); - saa7146_write(saa, MC2, (2 << 16) | 2); - - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - - result = saa7146_read(saa, DEBI_AD); - result &= (0xffffffffUL >> ((4 - count) * 8)); - - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - - return result; -} - -int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, - int count, u32 value, int uselocks, int nobusyloop) -{ - struct saa7146_dev *saa = budget->dev; - unsigned long flags = 0; - int result; - - if (count > 4 || count <= 0) - return 0; - - if (uselocks) - spin_lock_irqsave(&budget->debilock, flags); - - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - - saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff)); - saa7146_write(saa, DEBI_CONFIG, config); - saa7146_write(saa, DEBI_PAGE, 0); - saa7146_write(saa, DEBI_AD, value); - saa7146_write(saa, MC2, (2 << 16) | 2); - - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return 0; -} - - -/**************************************************************************** - * DVB API SECTION - ****************************************************************************/ - -static int budget_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct budget *budget = (struct budget *) demux->priv; - int status = 0; - - dprintk(2, "budget: %p\n", budget); - - if (!demux->dmx.frontend) - return -EINVAL; - - spin_lock(&budget->feedlock); - feed->pusi_seen = 0; /* have a clean section start */ - if (budget->feeding++ == 0) - status = start_ts_capture(budget); - spin_unlock(&budget->feedlock); - return status; -} - -static int budget_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct budget *budget = (struct budget *) demux->priv; - int status = 0; - - dprintk(2, "budget: %p\n", budget); - - spin_lock(&budget->feedlock); - if (--budget->feeding == 0) - status = stop_ts_capture(budget); - spin_unlock(&budget->feedlock); - return status; -} - -static int budget_register(struct budget *budget) -{ - struct dvb_demux *dvbdemux = &budget->demux; - int ret; - - dprintk(2, "budget: %p\n", budget); - - dvbdemux->priv = (void *) budget; - - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = budget_start_feed; - dvbdemux->stop_feed = budget_stop_feed; - dvbdemux->write_to_decoder = NULL; - - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - - dvb_dmx_init(&budget->demux); - - budget->dmxdev.filternum = 256; - budget->dmxdev.demux = &dvbdemux->dmx; - budget->dmxdev.capabilities = 0; - - dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter); - - budget->hw_frontend.source = DMX_FRONTEND_0; - - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend); - - if (ret < 0) - return ret; - - budget->mem_frontend.source = DMX_MEMORY_FE; - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend); - if (ret < 0) - return ret; - - ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend); - if (ret < 0) - return ret; - - dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); - - return 0; -} - -static void budget_unregister(struct budget *budget) -{ - struct dvb_demux *dvbdemux = &budget->demux; - - dprintk(2, "budget: %p\n", budget); - - dvb_net_release(&budget->dvb_net); - - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend); - - dvb_dmxdev_release(&budget->dmxdev); - dvb_dmx_release(&budget->demux); -} - -int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, - struct saa7146_pci_extension_data *info, - struct module *owner, short *adapter_nums) -{ - int ret = 0; - struct budget_info *bi = info->ext_priv; - int max_bufsize; - int height_mask; - - memset(budget, 0, sizeof(struct budget)); - - dprintk(2, "dev: %p, budget: %p\n", dev, budget); - - budget->card = bi; - budget->dev = (struct saa7146_dev *) dev; - - switch(budget->card->type) { - case BUDGET_FS_ACTIVY: - budget->buffer_width = TS_WIDTH_ACTIVY; - max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; - height_mask = TS_HEIGHT_MASK_ACTIVY; - break; - - case BUDGET_KNC1C: - case BUDGET_KNC1CP: - case BUDGET_CIN1200C: - case BUDGET_KNC1C_MK3: - case BUDGET_KNC1CP_MK3: - case BUDGET_CIN1200C_MK3: - budget->buffer_width = TS_WIDTH_DVBC; - max_bufsize = TS_MAX_BUFSIZE_K_DVBC; - height_mask = TS_HEIGHT_MASK_DVBC; - break; - - default: - budget->buffer_width = TS_WIDTH; - max_bufsize = TS_MAX_BUFSIZE_K; - height_mask = TS_HEIGHT_MASK; - } - - if (dma_buffer_size < TS_MIN_BUFSIZE_K) - dma_buffer_size = TS_MIN_BUFSIZE_K; - else if (dma_buffer_size > max_bufsize) - dma_buffer_size = max_bufsize; - - budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; - if (budget->buffer_height > 0xfff) { - budget->buffer_height /= 2; - budget->buffer_height &= height_mask; - budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width; - } else { - budget->buffer_height &= height_mask; - budget->buffer_size = budget->buffer_height * budget->buffer_width; - } - budget->buffer_warning_threshold = budget->buffer_size * 80/100; - budget->buffer_warnings = 0; - budget->buffer_warning_time = jiffies; - - dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n", - budget->dev->name, - budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single", - budget->buffer_width, budget->buffer_height); - printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); - - ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, - owner, &budget->dev->pci->dev, adapter_nums); - if (ret < 0) - return ret; - - /* set dd1 stream a & b */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25)); - saa7146_write(dev, MC2, (MASK_10 | MASK_26)); - saa7146_write(dev, DD1_INIT, 0x02000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - if (bi->type != BUDGET_FS_ACTIVY) - budget->video_port = BUDGET_VIDEO_PORTB; - else - budget->video_port = BUDGET_VIDEO_PORTA; - spin_lock_init(&budget->feedlock); - spin_lock_init(&budget->debilock); - - /* the Siemens DVB needs this if you want to have the i2c chips - get recognized before the main driver is loaded */ - if (bi->type != BUDGET_FS_ACTIVY) - saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */ - - strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name)); - - saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); - strcpy(budget->i2c_adap.name, budget->card->name); - - if (i2c_add_adapter(&budget->i2c_adap) < 0) { - ret = -ENOMEM; - goto err_dvb_unregister; - } - - ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); - - budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt); - if (NULL == budget->grabbing) { - ret = -ENOMEM; - goto err_del_i2c; - } - - saa7146_write(dev, PCI_BT_V1, 0x001c0000); - /* upload all */ - saa7146_write(dev, GPIO_CTRL, 0x000000); - - tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget); - - /* frontend power on */ - if (bi->type != BUDGET_FS_ACTIVY) - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - - if ((ret = budget_register(budget)) == 0) - return 0; /* Everything OK */ - - /* An error occurred, cleanup resources */ - saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); - -err_del_i2c: - i2c_del_adapter(&budget->i2c_adap); - -err_dvb_unregister: - dvb_unregister_adapter(&budget->dvb_adapter); - - return ret; -} - -void ttpci_budget_init_hooks(struct budget *budget) -{ - if (budget->dvb_frontend && !budget->read_fe_status) { - budget->read_fe_status = budget->dvb_frontend->ops.read_status; - budget->dvb_frontend->ops.read_status = budget_read_fe_status; - } -} - -int ttpci_budget_deinit(struct budget *budget) -{ - struct saa7146_dev *dev = budget->dev; - - dprintk(2, "budget: %p\n", budget); - - budget_unregister(budget); - - tasklet_kill(&budget->vpe_tasklet); - - saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); - - i2c_del_adapter(&budget->i2c_adap); - - dvb_unregister_adapter(&budget->dvb_adapter); - - return 0; -} - -void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr) -{ - struct budget *budget = (struct budget *) dev->ext_priv; - - dprintk(8, "dev: %p, budget: %p\n", dev, budget); - - if (*isr & MASK_10) - tasklet_schedule(&budget->vpe_tasklet); -} - -void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port) -{ - struct budget *budget = (struct budget *) dev->ext_priv; - - spin_lock(&budget->feedlock); - budget->video_port = video_port; - if (budget->feeding) { - stop_ts_capture(budget); - start_ts_capture(budget); - } - spin_unlock(&budget->feedlock); -} - -EXPORT_SYMBOL_GPL(ttpci_budget_debiread); -EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite); -EXPORT_SYMBOL_GPL(ttpci_budget_init); -EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks); -EXPORT_SYMBOL_GPL(ttpci_budget_deinit); -EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); -EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port); -EXPORT_SYMBOL_GPL(budget_debug); - -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ - -#ifndef __BUDGET_DVB__ -#define __BUDGET_DVB__ - -#include "dvb_frontend.h" -#include "dvbdev.h" -#include "demux.h" -#include "dvb_demux.h" -#include "dmxdev.h" -#include "dvb_filter.h" -#include "dvb_net.h" - -#include -#include - -#include - -extern int budget_debug; - -#ifdef dprintk -#undef dprintk -#endif - -#define dprintk(level,args...) \ - do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __func__); printk(args); } } while (0) - -struct budget_info { - char *name; - int type; -}; - -/* place to store all the necessary device information */ -struct budget { - - /* devices */ - struct dvb_device dvb_dev; - struct dvb_net dvb_net; - - struct saa7146_dev *dev; - - struct i2c_adapter i2c_adap; - struct budget_info *card; - - unsigned char *grabbing; - struct saa7146_pgtable pt; - - struct tasklet_struct fidb_tasklet; - struct tasklet_struct vpe_tasklet; - - struct dmxdev dmxdev; - struct dvb_demux demux; - - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - - int ci_present; - int video_port; - - u32 buffer_width; - u32 buffer_height; - u32 buffer_size; - u32 buffer_warning_threshold; - u32 buffer_warnings; - unsigned long buffer_warning_time; - - u32 ttbp; - int feeding; - - spinlock_t feedlock; - - spinlock_t debilock; - - struct dvb_adapter dvb_adapter; - struct dvb_frontend *dvb_frontend; - int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status); - int fe_synced; - - void *priv; -}; - -#define MAKE_BUDGET_INFO(x_var,x_name,x_type) \ -static struct budget_info x_var ## _info = { \ - .name=x_name, \ - .type=x_type }; \ -static struct saa7146_pci_extension_data x_var = { \ - .ext_priv = &x_var ## _info, \ - .ext = &budget_extension }; - -#define BUDGET_TT 0 -#define BUDGET_TT_HW_DISEQC 1 -#define BUDGET_PATCH 3 -#define BUDGET_FS_ACTIVY 4 -#define BUDGET_CIN1200S 5 -#define BUDGET_CIN1200C 6 -#define BUDGET_CIN1200T 7 -#define BUDGET_KNC1S 8 -#define BUDGET_KNC1C 9 -#define BUDGET_KNC1T 10 -#define BUDGET_KNC1SP 11 -#define BUDGET_KNC1CP 12 -#define BUDGET_KNC1TP 13 -#define BUDGET_TVSTAR 14 -#define BUDGET_CIN1200C_MK3 15 -#define BUDGET_KNC1C_MK3 16 -#define BUDGET_KNC1CP_MK3 17 -#define BUDGET_KNC1S2 18 - -#define BUDGET_VIDEO_PORTA 0 -#define BUDGET_VIDEO_PORTB 1 - -extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, - struct saa7146_pci_extension_data *info, - struct module *owner, short *adapter_nums); -extern void ttpci_budget_init_hooks(struct budget *budget); -extern int ttpci_budget_deinit(struct budget *budget); -extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr); -extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port); -extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, - int uselocks, int nobusyloop); -extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value, - int uselocks, int nobusyloop); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-patch.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-patch.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-patch.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/budget-patch.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,673 +0,0 @@ -/* - * budget-patch.c: driver for Budget Patch, - * hardware modification of DVB-S cards enabling full TS - * - * Written by Emard - * - * Original idea by Roberto Deza - * - * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic - * and Metzlerbros - * - * 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, or (at your option) any later version. - * - * - * 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. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * - * the project's page is at http://www.linuxtv.org/ - */ - -#include "av7110.h" -#include "av7110_hw.h" -#include "budget.h" -#include "stv0299.h" -#include "ves1x93.h" -#include "tda8083.h" - -#include "bsru6.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define budget_patch budget - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH); -//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC); - -static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000), -// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), - { - .vendor = 0, - } -}; - -/* those lines are for budget-patch to be tried -** on a true budget card and observe the -** behaviour of VSYNC generated by rps1. -** this code was shamelessly copy/pasted from budget.c -*/ -static void gpio_Set22K (struct budget *budget, int state) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); -} - -/* Diseqc functions only for TT Budget card */ -/* taken from the Skyvision DVB driver by - Ralph Metzler */ - -static void DiseqcSendBit (struct budget *budget, int data) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - udelay(data ? 500 : 1000); - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - udelay(data ? 1000 : 500); -} - -static void DiseqcSendByte (struct budget *budget, int data) -{ - int i, par=1, d; - - dprintk(2, "budget: %p\n", budget); - - for (i=7; i>=0; i--) { - d = (data>>i)&1; - par ^= d; - DiseqcSendBit(budget, d); - } - - DiseqcSendBit(budget, par); -} - -static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) -{ - struct saa7146_dev *dev=budget->dev; - int i; - - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - mdelay(16); - - for (i=0; idvb->priv; - - switch (tone) { - case SEC_TONE_ON: - gpio_Set22K (budget, 1); - break; - - case SEC_TONE_OFF: - gpio_Set22K (budget, 0); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); - - return 0; -} - -static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, 0, NULL, minicmd); - - return 0; -} - -static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length) -{ - int i; - - dprintk(2, "budget: %p\n", budget); - - for (i = 2; i < length; i++) - { - ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0); - msleep(5); - } - if (length) - ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0); - else - ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0); - msleep(5); - ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0); - msleep(5); - return 0; -} - -static void av7110_set22k(struct budget_patch *budget, int state) -{ - u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0}; - - dprintk(2, "budget: %p\n", budget); - budget_av7110_send_fw_cmd(budget, buf, 2); -} - -static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst) -{ - int i; - u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC), - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - dprintk(2, "budget: %p\n", budget); - - if (len>10) - len=10; - - buf[1] = len+2; - buf[2] = len; - - if (burst != -1) - buf[3]=burst ? 0x01 : 0x00; - else - buf[3]=0xffff; - - for (i=0; idvb->priv; - - switch (tone) { - case SEC_TONE_ON: - av7110_set22k (budget, 1); - break; - - case SEC_TONE_OFF: - av7110_set22k (budget, 0); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) -{ - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; - - av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0); - - return 0; -} - -static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; - - av7110_send_diseqc_msg (budget, 0, NULL, minicmd); - - return 0; -} - -static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; - u8 pwr = 0; - u8 buf[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (params->frequency + 479500) / 125; - - if (params->frequency > 2000000) pwr = 3; - else if (params->frequency > 1800000) pwr = 2; - else if (params->frequency > 1600000) pwr = 1; - else if (params->frequency > 1200000) pwr = 0; - else if (params->frequency >= 1100000) pwr = 1; - else pwr = 2; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = ((div & 0x18000) >> 10) | 0x95; - buf[3] = (pwr << 6) | 0x30; - - // NOTE: since we're using a prescaler of 2, we set the - // divisor frequency to 62.5kHz and divide by 125 above - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct ves1x93_config alps_bsrv2_config = { - .demod_address = 0x08, - .xin = 90100000UL, - .invert_pwm = 0, -}; - -static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = params->frequency / 125; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x8e; - data[3] = 0x00; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static struct tda8083_config grundig_29504_451_config = { - .demod_address = 0x68, -}; - -static void frontend_init(struct budget_patch* budget) -{ - switch(budget->dev->pci->subsystem_device) { - case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X - case 0x1013: // SATELCO Multimedia PCI - - // try the ALPS BSRV2 first of all - budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_patch_set_tone; - break; - } - - // try the ALPS BSRU6 now - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - break; - } - - // Try the grundig 29504-451 - budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - break; - } - break; - } - - if (budget->dvb_frontend == NULL) { - printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - budget->dev->pci->vendor, - budget->dev->pci->device, - budget->dev->pci->subsystem_vendor, - budget->dev->pci->subsystem_device); - } else { - if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { - printk("budget-av: Frontend registration failed!\n"); - dvb_frontend_detach(budget->dvb_frontend); - budget->dvb_frontend = NULL; - } - } -} - -/* written by Emard */ -static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) -{ - struct budget_patch *budget; - int err; - int count = 0; - int detected = 0; - -#define PATCH_RESET 0 -#define RPS_IRQ 0 -#define HPS_SETUP 0 -#if PATCH_RESET - saa7146_write(dev, MC1, MASK_31); - msleep(40); -#endif -#if HPS_SETUP - // initialize registers. Better to have it like this - // than leaving something unconfigured - saa7146_write(dev, DD1_STREAM_B, 0); - // port B VSYNC at rising edge - saa7146_write(dev, DD1_INIT, 0x00000200); // have this in budget-core too! - saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI - - // debi config - // saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18); - - // zero all HPS registers - saa7146_write(dev, HPS_H_PRESCALE, 0); // r68 - saa7146_write(dev, HPS_H_SCALE, 0); // r6c - saa7146_write(dev, BCS_CTRL, 0); // r70 - saa7146_write(dev, HPS_V_SCALE, 0); // r60 - saa7146_write(dev, HPS_V_GAIN, 0); // r64 - saa7146_write(dev, CHROMA_KEY_RANGE, 0); // r74 - saa7146_write(dev, CLIP_FORMAT_CTRL, 0); // r78 - // Set HPS prescaler for port B input - saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) ); - saa7146_write(dev, MC2, - 0 * (MASK_08 | MASK_24) | // BRS control - 0 * (MASK_09 | MASK_25) | // a - 0 * (MASK_10 | MASK_26) | // b - 1 * (MASK_06 | MASK_22) | // HPS_CTRL1 - 1 * (MASK_05 | MASK_21) | // HPS_CTRL2 - 0 * (MASK_01 | MASK_15) // DEBI - ); -#endif - // Disable RPS1 and RPS0 - saa7146_write(dev, MC1, ( MASK_29 | MASK_28)); - // RPS1 timeout disable - saa7146_write(dev, RPS_TOV1, 0); - - // code for autodetection - // will wait for VBI_B event (vertical blank at port B) - // and will reset GPIO3 after VBI_B is detected. - // (GPIO3 should be raised high by CPU to - // test if GPIO3 will generate vertical blank signal - // in budget patch GPIO3 is connected to VSYNC_B - count = 0; -#if 0 - WRITE_RPS1(CMD_UPLOAD | - MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ); -#endif - WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); -#if RPS_IRQ - // issue RPS1 interrupt to increment counter - WRITE_RPS1(CMD_INTERRUPT); - // at least a NOP is neede between two interrupts - WRITE_RPS1(CMD_NOP); - // interrupt again - WRITE_RPS1(CMD_INTERRUPT); -#endif - WRITE_RPS1(CMD_STOP); - -#if RPS_IRQ - // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) - // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled - // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called - saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); - // set event counter 1 threshold to maximum allowed value (rEC p55) - saa7146_write(dev, ECT1R, 0x3fff ); -#endif - // Fix VSYNC level - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - // Set RPS1 Address register to point to RPS code (r108 p42) - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - // Enable RPS1, (rFC p33) - saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); - - - mdelay(50); - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - mdelay(150); - - - if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) - detected = 1; - -#if RPS_IRQ - printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); -#endif - // Disable RPS1 - saa7146_write(dev, MC1, ( MASK_29 )); - - if(detected == 0) - printk("budget-patch not detected or saa7146 in non-default state.\n" - "try enabling ressetting of 7146 with MASK_31 in MC1 register\n"); - - else - printk("BUDGET-PATCH DETECTED.\n"); - - -/* OLD (Original design by Roberto Deza): -** This code will setup the SAA7146_RPS1 to generate a square -** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of -** TS_WIDTH packets) has been acquired on SAA7146_D1B video port; -** then, this GPIO3 output which is connected to the D1B_VSYNC -** input, will trigger the acquisition of the alternate field -** and so on. -** Currently, the TT_budget / WinTV_Nova cards have two ICs -** (74HCT4040, LVC74) for the generation of this VSYNC signal, -** which seems that can be done perfectly without this :-)). -*/ - -/* New design (By Emard) -** this rps1 code will copy internal HS event to GPIO3 pin. -** GPIO3 is in budget-patch hardware connected to port B VSYNC - -** HS is an internal event of 7146, accessible with RPS -** and temporarily raised high every n lines -** (n in defined in the RPS_THRESH1 counter threshold) -** I think HS is raised high on the beginning of the n-th line -** and remains high until this n-th line that triggered -** it is completely received. When the reception of n-th line -** ends, HS is lowered. - -** To transmit data over DMA, 7146 needs changing state at -** port B VSYNC pin. Any changing of port B VSYNC will -** cause some DMA data transfer, with more or less packets loss. -** It depends on the phase and frequency of VSYNC and -** the way of 7146 is instructed to trigger on port B (defined -** in DD1_INIT register, 3rd nibble from the right valid -** numbers are 0-7, see datasheet) -** -** The correct triggering can minimize packet loss, -** dvbtraffic should give this stable bandwidths: -** 22k transponder = 33814 kbit/s -** 27.5k transponder = 38045 kbit/s -** by experiment it is found that the best results -** (stable bandwidths and almost no packet loss) -** are obtained using DD1_INIT triggering number 2 -** (Va at rising edge of VS Fa = HS x VS-failing forced toggle) -** and a VSYNC phase that occurs in the middle of DMA transfer -** (about byte 188*512=96256 in the DMA window). -** -** Phase of HS is still not clear to me how to control, -** It just happens to be so. It can be seen if one enables -** RPS_IRQ and print Event Counter 1 in vpeirq(). Every -** time RPS_INTERRUPT is called, the Event Counter 1 will -** increment. That's how the 7146 is programmed to do event -** counting in this budget-patch.c -** I *think* HPS setting has something to do with the phase -** of HS but I cant be 100% sure in that. - -** hardware debug note: a working budget card (including budget patch) -** with vpeirq() interrupt setup in mode "0x90" (every 64K) will -** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes -** and that means 3*25=75 Hz of interrupt frequency, as seen by -** watch cat /proc/interrupts -** -** If this frequency is 3x lower (and data received in the DMA -** buffer don't start with 0x47, but in the middle of packets, -** whose lengths appear to be like 188 292 188 104 etc. -** this means VSYNC line is not connected in the hardware. -** (check soldering pcb and pins) -** The same behaviour of missing VSYNC can be duplicated on budget -** cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. -*/ - - // Setup RPS1 "program" (p35) - count = 0; - - - // Wait Source Line Counter Threshold (p36) - WRITE_RPS1(CMD_PAUSE | EVT_HS); - // Set GPIO3=1 (p42) - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); -#if RPS_IRQ - // issue RPS1 interrupt - WRITE_RPS1(CMD_INTERRUPT); -#endif - // Wait reset Source Line Counter Threshold (p36) - WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); - // Set GPIO3=0 (p42) - WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); - WRITE_RPS1(GPIO3_MSK); - WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); -#if RPS_IRQ - // issue RPS1 interrupt - WRITE_RPS1(CMD_INTERRUPT); -#endif - // Jump to begin of RPS program (p37) - WRITE_RPS1(CMD_JUMP); - WRITE_RPS1(dev->d_rps1.dma_handle); - - // Fix VSYNC level - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - // Set RPS1 Address register to point to RPS code (r108 p42) - saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - - if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) - return -ENOMEM; - - dprintk(2, "budget: %p\n", budget); - - err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); - if (err) { - kfree(budget); - return err; - } - - // Set Source Line Counter Threshold, using BRS (rCC p43) - // It generates HS event every TS_HEIGHT lines - // this is related to TS_WIDTH set in register - // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE - // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188 - //,then RPS_THRESH1 - // should be set to trigger every TS_HEIGHT (512) lines. - // - saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 ); - - // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); - // Enable RPS1 (rFC p33) - saa7146_write(dev, MC1, (MASK_13 | MASK_29)); - - - dev->ext_priv = budget; - - budget->dvb_adapter.priv = budget; - frontend_init(budget); - - ttpci_budget_init_hooks(budget); - - return 0; -} - -static int budget_patch_detach (struct saa7146_dev* dev) -{ - struct budget_patch *budget = (struct budget_patch*) dev->ext_priv; - int err; - - if (budget->dvb_frontend) { - dvb_unregister_frontend(budget->dvb_frontend); - dvb_frontend_detach(budget->dvb_frontend); - } - err = ttpci_budget_deinit (budget); - - kfree (budget); - - return err; -} - -static int __init budget_patch_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_patch_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -static struct saa7146_extension budget_extension = { - .name = "budget_patch dvb", - .flags = 0, - - .module = THIS_MODULE, - .pci_tbl = pci_tbl, - .attach = budget_patch_attach, - .detach = budget_patch_detach, - - .irq_mask = MASK_10, - .irq_func = ttpci_budget_irq10_handler, -}; - -module_init(budget_patch_init); -module_exit(budget_patch_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others"); -MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 " - "based so-called Budget Patch cards"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -config TTPCI_EEPROM - tristate - depends on I2C - default n - -config DVB_AV7110 - tristate "AV7110 cards" - depends on DVB_CORE && PCI && I2C - select TTPCI_EEPROM - select VIDEO_SAA7146_VV - depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - select DVB_VES1820 if !DVB_FE_CUSTOMISE - select DVB_VES1X93 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_SP8870 if !DVB_FE_CUSTOMISE - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_L64781 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - help - Support for SAA7146 and AV7110 based DVB cards as produced - by Fujitsu-Siemens, Technotrend, Hauppauge and others. - - This driver only supports the fullfeatured cards with - onboard MPEG2 decoder. - - This driver needs an external firmware. Please use the script - "/Documentation/dvb/get_dvb_firmware av7110" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - - Alternatively, you can download the file and use the kernel's - EXTRA_FIRMWARE configuration option to build it into your - kernel image by adding the filename to the EXTRA_FIRMWARE - configuration option string. - - Say Y if you own such a card and want to use it. - -config DVB_AV7110_OSD - bool "AV7110 OSD support" - depends on DVB_AV7110 - default y if DVB_AV7110=y || DVB_AV7110=m - help - The AV7110 firmware provides some code to generate an OnScreenDisplay - on the video output. This is kind of nonstandard and not guaranteed to - be maintained. - - Anyway, some popular DVB software like VDR uses this OSD to render - its menus, so say Y if you want to use this software. - - All other people say N. - -config DVB_BUDGET_CORE - tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" - depends on DVB_CORE && PCI && I2C - select VIDEO_SAA7146 - select TTPCI_EEPROM - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder. - -config DVB_BUDGET - tristate "Budget cards" - depends on DVB_BUDGET_CORE && I2C - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_VES1X93 if !DVB_FE_CUSTOMISE - select DVB_VES1820 if !DVB_FE_CUSTOMISE - select DVB_L64781 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_S5H1420 if !DVB_FE_CUSTOMISE - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_ISL6423 if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - help - Support for simple SAA7146 based DVB cards (so called Budget- - or Nova-PCI cards) without onboard MPEG2 decoder, and without - analog inputs or an onboard Common Interface connector. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget. - -config DVB_BUDGET_CI - tristate "Budget cards with onboard CI connector" - depends on DVB_BUDGET_CORE && I2C - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE - depends on RC_CORE - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder, but with onboard Common Interface connector. - - Note: The Common Interface is not yet supported by this driver - due to lack of information from the vendor. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-ci. - -config DVB_BUDGET_AV - tristate "Budget cards with analog video inputs" - depends on DVB_BUDGET_CORE && I2C - select VIDEO_SAA7146_VV - depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_TDA8261 if !DVB_FE_CUSTOMISE - select DVB_TUA6100 if !DVB_FE_CUSTOMISE - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder, but with one or more analog video inputs. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-av. - -config DVB_BUDGET_PATCH - tristate "AV7110 cards with Budget Patch" - depends on DVB_BUDGET_CORE && I2C - depends on DVB_AV7110 - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_VES1X93 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - help - Support for Budget Patch (full TS) modification on - SAA7146+AV7110 based cards (DVB-S cards). This - driver doesn't use onboard MPEG2 decoder. The - card is driven in Budget-only mode. Card is - required to have loaded firmware to tune properly. - Firmware can be loaded by insertion and removal of - standard AV7110 driver prior to loading this - driver. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-patch. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# -# Makefile for the kernel SAA7146 FULL TS DVB device driver -# and the AV7110 DVB device driver -# - -dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o - -ifdef CONFIG_INPUT_EVDEV -dvb-ttpci-objs += av7110_ir.o -endif - -obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o -obj-$(CONFIG_DVB_BUDGET) += budget.o -obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o -obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o -obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o -obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/ttpci-eeprom.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/ttpci-eeprom.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/ttpci-eeprom.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/ttpci-eeprom.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -/* - Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM, - decode it and store it in the associated adapter struct for - use by dvb_net.c - - This card appear to have the 24C16 write protect held to ground, - thus permitting normal read/write operation. Theoretically it - would be possible to write routines to burn a different (encoded) - MAC address into the EEPROM. - - Robert Schlabbach GMX - Michael Glaum KVH Industries - Holger Waechtler Convergence - - Copyright (C) 2002-2003 Ralph Metzler - Metzler Brothers Systementwicklung GbR - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include - -#include "ttpci-eeprom.h" - -#if 1 -#define dprintk(x...) do { printk(x); } while (0) -#else -#define dprintk(x...) do { } while (0) -#endif - - -static int check_mac_tt(u8 *buf) -{ - int i; - u16 tmp = 0xffff; - - for (i = 0; i < 8; i++) { - tmp = (tmp << 8) | ((tmp >> 8) ^ buf[i]); - tmp ^= (tmp >> 4) & 0x0f; - tmp ^= (tmp << 12) ^ ((tmp & 0xff) << 5); - } - tmp ^= 0xffff; - return (((tmp >> 8) ^ buf[8]) | ((tmp & 0xff) ^ buf[9])); -} - -static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC) -{ - u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, - 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, - 0x1d, 0x36, 0x64, 0x78}; - u8 data[20]; - int i; - - /* In case there is a sig check failure have the orig contents available */ - memcpy(data, encodedMAC, 20); - - for (i = 0; i < 20; i++) - data[i] ^= xor[i]; - for (i = 0; i < 10; i++) - data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) - >> ((data[2 * i + 1] >> 6) & 3); - - if (check_mac_tt(data)) - return -ENODEV; - - decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0]; - decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4]; - return 0; -} - -static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC) -{ - int ret; - u8 b0[] = { 0xcc }; - - struct i2c_msg msg[] = { - { .addr = 0x50, .flags = 0, .buf = b0, .len = 1 }, - { .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 } - }; - - /* dprintk("%s\n", __func__); */ - - ret = i2c_transfer(adapter, msg, 2); - - if (ret != 2) /* Assume EEPROM isn't there */ - return (-ENODEV); - - return 0; -} - - -int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) -{ - int ret, i; - u8 encodedMAC[20]; - u8 decodedMAC[6]; - - ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC); - - if (ret != 0) { /* Will only be -ENODEV */ - dprintk("Couldn't read from EEPROM: not there?\n"); - memset(proposed_mac, 0, 6); - return ret; - } - - ret = getmac_tt(decodedMAC, encodedMAC); - if( ret != 0 ) { - dprintk("adapter failed MAC signature check\n"); - dprintk("encoded MAC from EEPROM was " ); - for(i=0; i<19; i++) { - dprintk( "%.2x:", encodedMAC[i]); - } - dprintk("%.2x\n", encodedMAC[19]); - memset(proposed_mac, 0, 6); - return ret; - } - - memcpy(proposed_mac, decodedMAC, 6); - dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - decodedMAC[0], decodedMAC[1], decodedMAC[2], - decodedMAC[3], decodedMAC[4], decodedMAC[5]); - return 0; -} - -EXPORT_SYMBOL(ttpci_eeprom_parse_mac); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); -MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards " - "made by Siemens, Technotrend, Hauppauge"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/ttpci-eeprom.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/ttpci-eeprom.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/ttpci-eeprom.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttpci/ttpci-eeprom.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - Retrieve encoded MAC address from ATMEL ttpci_eeprom serial 2-wire EEPROM, - decode it and store it in associated adapter net device - - Robert Schlabbach GMX - Michael Glaum KVH Industries - Holger Waechtler Convergence - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __TTPCI_EEPROM_H__ -#define __TTPCI_EEPROM_H__ - -#include -#include - -extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1827 +0,0 @@ -/* - * TTUSB DVB driver - * - * Copyright (c) 2002 Holger Waechtler - * Copyright (c) 2003 Felix Domke - * - * 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, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_net.h" -#include "ves1820.h" -#include "cx22700.h" -#include "tda1004x.h" -#include "stv0299.h" -#include "tda8083.h" -#include "stv0297.h" -#include "lnbp21.h" - -#include -#include -#include - -/* - TTUSB_HWSECTIONS: - the DSP supports filtering in hardware, however, since the "muxstream" - is a bit braindead (no matching channel masks or no matching filter mask), - we won't support this - yet. it doesn't event support negative filters, - so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just - parse TS data. USB bandwidth will be a problem when having large - datastreams, especially for dvb-net, but hey, that's not my problem. - - TTUSB_DISEQC, TTUSB_TONE: - let the STC do the diseqc/tone stuff. this isn't supported at least with - my TTUSB, so let it undef'd unless you want to implement another - frontend. never tested. - - DEBUG: - define it to > 3 for really hardcore debugging. you probably don't want - this unless the device doesn't load at all. > 2 for bandwidth statistics. -*/ - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0) - -#define ISO_BUF_COUNT 4 -#define FRAMES_PER_ISO_BUF 4 -#define ISO_FRAME_SIZE 912 -#define TTUSB_MAXCHANNEL 32 -#ifdef TTUSB_HWSECTIONS -#define TTUSB_MAXFILTER 16 /* ??? */ -#endif - -#define TTUSB_REV_2_2 0x22 -#define TTUSB_BUDGET_NAME "ttusb_stc_fw" - -/** - * since we're casting (struct ttusb*) <-> (struct dvb_demux*) around - * the dvb_demux field must be the first in struct!! - */ -struct ttusb { - struct dvb_demux dvb_demux; - struct dmxdev dmxdev; - struct dvb_net dvbnet; - - /* and one for USB access. */ - struct mutex semi2c; - struct mutex semusb; - - struct dvb_adapter adapter; - struct usb_device *dev; - - struct i2c_adapter i2c_adap; - - int disconnecting; - int iso_streaming; - - unsigned int bulk_out_pipe; - unsigned int bulk_in_pipe; - unsigned int isoc_in_pipe; - - void *iso_buffer; - dma_addr_t iso_dma_handle; - - struct urb *iso_urb[ISO_BUF_COUNT]; - - int running_feed_count; - int last_channel; - int last_filter; - - u8 c; /* transaction counter, wraps around... */ - fe_sec_tone_mode_t tone; - fe_sec_voltage_t voltage; - - int mux_state; // 0..2 - MuxSyncWord, 3 - nMuxPacks, 4 - muxpack - u8 mux_npacks; - u8 muxpack[256 + 8]; - int muxpack_ptr, muxpack_len; - - int insync; - - int cc; /* MuxCounter - will increment on EVERY MUX PACKET */ - /* (including stuffing. yes. really.) */ - - u8 last_result[32]; - - int revision; - - struct dvb_frontend* fe; -}; - -/* ugly workaround ... don't know why it's necessary to read */ -/* all result codes. */ - -#define DEBUG 0 -static int ttusb_cmd(struct ttusb *ttusb, - const u8 * data, int len, int needresult) -{ - int actual_len; - int err; -#if DEBUG >= 3 - int i; - - printk(">"); - for (i = 0; i < len; ++i) - printk(" %02x", data[i]); - printk("\n"); -#endif - - if (mutex_lock_interruptible(&ttusb->semusb) < 0) - return -EAGAIN; - - err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe, - (u8 *) data, len, &actual_len, 1000); - if (err != 0) { - dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n", - __func__, err); - mutex_unlock(&ttusb->semusb); - return err; - } - if (actual_len != len) { - dprintk("%s: only wrote %d of %d bytes\n", __func__, - actual_len, len); - mutex_unlock(&ttusb->semusb); - return -1; - } - - err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe, - ttusb->last_result, 32, &actual_len, 1000); - - if (err != 0) { - printk("%s: failed, receive error %d\n", __func__, - err); - mutex_unlock(&ttusb->semusb); - return err; - } -#if DEBUG >= 3 - actual_len = ttusb->last_result[3] + 4; - printk("<"); - for (i = 0; i < actual_len; ++i) - printk(" %02x", ttusb->last_result[i]); - printk("\n"); -#endif - if (!needresult) - mutex_unlock(&ttusb->semusb); - return 0; -} - -static int ttusb_result(struct ttusb *ttusb, u8 * data, int len) -{ - memcpy(data, ttusb->last_result, len); - mutex_unlock(&ttusb->semusb); - return 0; -} - -static int ttusb_i2c_msg(struct ttusb *ttusb, - u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf, - u8 rcv_len) -{ - u8 b[0x28]; - u8 id = ++ttusb->c; - int i, err; - - if (snd_len > 0x28 - 7 || rcv_len > 0x20 - 7) - return -EINVAL; - - b[0] = 0xaa; - b[1] = id; - b[2] = 0x31; - b[3] = snd_len + 3; - b[4] = addr << 1; - b[5] = snd_len; - b[6] = rcv_len; - - for (i = 0; i < snd_len; i++) - b[7 + i] = snd_buf[i]; - - err = ttusb_cmd(ttusb, b, snd_len + 7, 1); - - if (err) - return -EREMOTEIO; - - err = ttusb_result(ttusb, b, 0x20); - - /* check if the i2c transaction was successful */ - if ((snd_len != b[5]) || (rcv_len != b[6])) return -EREMOTEIO; - - if (rcv_len > 0) { - - if (err || b[0] != 0x55 || b[1] != id) { - dprintk - ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ", - __func__, err, id); - return -EREMOTEIO; - } - - for (i = 0; i < rcv_len; i++) - rcv_buf[i] = b[7 + i]; - } - - return rcv_len; -} - -static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) -{ - struct ttusb *ttusb = i2c_get_adapdata(adapter); - int i = 0; - int inc; - - if (mutex_lock_interruptible(&ttusb->semi2c) < 0) - return -EAGAIN; - - while (i < num) { - u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf; - int err; - - if (num > i + 1 && (msg[i + 1].flags & I2C_M_RD)) { - addr = msg[i].addr; - snd_buf = msg[i].buf; - snd_len = msg[i].len; - rcv_buf = msg[i + 1].buf; - rcv_len = msg[i + 1].len; - inc = 2; - } else { - addr = msg[i].addr; - snd_buf = msg[i].buf; - snd_len = msg[i].len; - rcv_buf = NULL; - rcv_len = 0; - inc = 1; - } - - err = ttusb_i2c_msg(ttusb, addr, - snd_buf, snd_len, rcv_buf, rcv_len); - - if (err < rcv_len) { - dprintk("%s: i == %i\n", __func__, i); - break; - } - - i += inc; - } - - mutex_unlock(&ttusb->semi2c); - return i; -} - -static int ttusb_boot_dsp(struct ttusb *ttusb) -{ - const struct firmware *fw; - int i, err; - u8 b[40]; - - err = request_firmware(&fw, "ttusb-budget/dspbootcode.bin", - &ttusb->dev->dev); - if (err) { - printk(KERN_ERR "ttusb-budget: failed to request firmware\n"); - return err; - } - - /* BootBlock */ - b[0] = 0xaa; - b[2] = 0x13; - b[3] = 28; - - /* upload dsp code in 32 byte steps (36 didn't work for me ...) */ - /* 32 is max packet size, no messages should be splitted. */ - for (i = 0; i < fw->size; i += 28) { - memcpy(&b[4], &fw->data[i], 28); - - b[1] = ++ttusb->c; - - err = ttusb_cmd(ttusb, b, 32, 0); - if (err) - goto done; - } - - /* last block ... */ - b[1] = ++ttusb->c; - b[2] = 0x13; - b[3] = 0; - - err = ttusb_cmd(ttusb, b, 4, 0); - if (err) - goto done; - - /* BootEnd */ - b[1] = ++ttusb->c; - b[2] = 0x14; - b[3] = 0; - - err = ttusb_cmd(ttusb, b, 4, 0); - - done: - release_firmware(fw); - if (err) { - dprintk("%s: usb_bulk_msg() failed, return value %i!\n", - __func__, err); - } - - return err; -} - -static int ttusb_set_channel(struct ttusb *ttusb, int chan_id, int filter_type, - int pid) -{ - int err; - /* SetChannel */ - u8 b[] = { 0xaa, ++ttusb->c, 0x22, 4, chan_id, filter_type, - (pid >> 8) & 0xff, pid & 0xff - }; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - return err; -} - -static int ttusb_del_channel(struct ttusb *ttusb, int channel_id) -{ - int err; - /* DelChannel */ - u8 b[] = { 0xaa, ++ttusb->c, 0x23, 1, channel_id }; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - return err; -} - -#ifdef TTUSB_HWSECTIONS -static int ttusb_set_filter(struct ttusb *ttusb, int filter_id, - int associated_chan, u8 filter[8], u8 mask[8]) -{ - int err; - /* SetFilter */ - u8 b[] = { 0xaa, 0, 0x24, 0x1a, filter_id, associated_chan, - filter[0], filter[1], filter[2], filter[3], - filter[4], filter[5], filter[6], filter[7], - filter[8], filter[9], filter[10], filter[11], - mask[0], mask[1], mask[2], mask[3], - mask[4], mask[5], mask[6], mask[7], - mask[8], mask[9], mask[10], mask[11] - }; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - return err; -} - -static int ttusb_del_filter(struct ttusb *ttusb, int filter_id) -{ - int err; - /* DelFilter */ - u8 b[] = { 0xaa, ++ttusb->c, 0x25, 1, filter_id }; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - return err; -} -#endif - -static int ttusb_init_controller(struct ttusb *ttusb) -{ - u8 b0[] = { 0xaa, ++ttusb->c, 0x15, 1, 0 }; - u8 b1[] = { 0xaa, ++ttusb->c, 0x15, 1, 1 }; - u8 b2[] = { 0xaa, ++ttusb->c, 0x32, 1, 0 }; - /* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */ - u8 b3[] = - { 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e }; - u8 b4[] = - { 0x55, ttusb->c, 0x31, 4, 0x10, 0x02, 0x01, 0x00, 0x1e }; - - u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 }; - u8 get_dsp_version[0x20] = - { 0xaa, ++ttusb->c, 0x26, 28, 0, 0, 0, 0, 0 }; - int err; - - /* reset board */ - if ((err = ttusb_cmd(ttusb, b0, sizeof(b0), 0))) - return err; - - /* reset board (again?) */ - if ((err = ttusb_cmd(ttusb, b1, sizeof(b1), 0))) - return err; - - ttusb_boot_dsp(ttusb); - - /* set i2c bit rate */ - if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0))) - return err; - - if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 1))) - return err; - - err = ttusb_result(ttusb, b4, sizeof(b4)); - - if ((err = ttusb_cmd(ttusb, get_version, sizeof(get_version), 1))) - return err; - - if ((err = ttusb_result(ttusb, get_version, sizeof(get_version)))) - return err; - - dprintk("%s: stc-version: %c%c%c%c%c\n", __func__, - get_version[4], get_version[5], get_version[6], - get_version[7], get_version[8]); - - if (memcmp(get_version + 4, "V 0.0", 5) && - memcmp(get_version + 4, "V 1.1", 5) && - memcmp(get_version + 4, "V 2.1", 5) && - memcmp(get_version + 4, "V 2.2", 5)) { - printk - ("%s: unknown STC version %c%c%c%c%c, please report!\n", - __func__, get_version[4], get_version[5], - get_version[6], get_version[7], get_version[8]); - } - - ttusb->revision = ((get_version[6] - '0') << 4) | - (get_version[8] - '0'); - - err = - ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1); - if (err) - return err; - - err = - ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version)); - if (err) - return err; - printk("%s: dsp-version: %c%c%c\n", __func__, - get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]); - return 0; -} - -#ifdef TTUSB_DISEQC -static int ttusb_send_diseqc(struct dvb_frontend* fe, - const struct dvb_diseqc_master_cmd *cmd) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 b[12] = { 0xaa, ++ttusb->c, 0x18 }; - - int err; - - b[3] = 4 + 2 + cmd->msg_len; - b[4] = 0xFF; /* send diseqc master, not burst */ - b[5] = cmd->msg_len; - - memcpy(b + 5, cmd->msg, cmd->msg_len); - - /* Diseqc */ - if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) { - dprintk("%s: usb_bulk_msg() failed, return value %i!\n", - __func__, err); - } - - return err; -} -#endif - -static int ttusb_update_lnb(struct ttusb *ttusb) -{ - u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1, - ttusb->voltage == SEC_VOLTAGE_18 ? 0 : 1, - ttusb->tone == SEC_TONE_ON ? 1 : 0, 1, 1 - }; - int err; - - /* SetLNB */ - if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) { - dprintk("%s: usb_bulk_msg() failed, return value %i!\n", - __func__, err); - } - - return err; -} - -static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - - ttusb->voltage = voltage; - return ttusb_update_lnb(ttusb); -} - -#ifdef TTUSB_TONE -static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - - ttusb->tone = tone; - return ttusb_update_lnb(ttusb); -} -#endif - - -#if 0 -static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq) -{ - u8 b[] = { 0xaa, ++ttusb->c, 0x19, 1, freq }; - int err, actual_len; - - err = ttusb_cmd(ttusb, b, sizeof(b), 0); - if (err) { - dprintk("%s: usb_bulk_msg() failed, return value %i!\n", - __func__, err); - } -} -#endif - -/*****************************************************************************/ - -#ifdef TTUSB_HWSECTIONS -static void ttusb_handle_ts_data(struct ttusb_channel *channel, - const u8 * data, int len); -static void ttusb_handle_sec_data(struct ttusb_channel *channel, - const u8 * data, int len); -#endif - -static int numpkt, numts, numstuff, numsec, numinvalid; -static unsigned long lastj; - -static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack, - int len) -{ - u16 csum = 0, cc; - int i; - for (i = 0; i < len; i += 2) - csum ^= le16_to_cpup((__le16 *) (muxpack + i)); - if (csum) { - printk("%s: muxpack with incorrect checksum, ignoring\n", - __func__); - numinvalid++; - return; - } - - cc = (muxpack[len - 4] << 8) | muxpack[len - 3]; - cc &= 0x7FFF; - if ((cc != ttusb->cc) && (ttusb->cc != -1)) - printk("%s: cc discontinuity (%d frames missing)\n", - __func__, (cc - ttusb->cc) & 0x7FFF); - ttusb->cc = (cc + 1) & 0x7FFF; - if (muxpack[0] & 0x80) { -#ifdef TTUSB_HWSECTIONS - /* section data */ - int pusi = muxpack[0] & 0x40; - int channel = muxpack[0] & 0x1F; - int payload = muxpack[1]; - const u8 *data = muxpack + 2; - /* check offset flag */ - if (muxpack[0] & 0x20) - data++; - - ttusb_handle_sec_data(ttusb->channel + channel, data, - payload); - data += payload; - - if ((!!(ttusb->muxpack[0] & 0x20)) ^ - !!(ttusb->muxpack[1] & 1)) - data++; -#warning TODO: pusi - printk("cc: %04x\n", (data[0] << 8) | data[1]); -#endif - numsec++; - } else if (muxpack[0] == 0x47) { -#ifdef TTUSB_HWSECTIONS - /* we have TS data here! */ - int pid = ((muxpack[1] & 0x0F) << 8) | muxpack[2]; - int channel; - for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) - if (ttusb->channel[channel].active - && (pid == ttusb->channel[channel].pid)) - ttusb_handle_ts_data(ttusb->channel + - channel, muxpack, - 188); -#endif - numts++; - dvb_dmx_swfilter_packets(&ttusb->dvb_demux, muxpack, 1); - } else if (muxpack[0] != 0) { - numinvalid++; - printk("illegal muxpack type %02x\n", muxpack[0]); - } else - numstuff++; -} - -static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len) -{ - int maxwork = 1024; - while (len) { - if (!(maxwork--)) { - printk("%s: too much work\n", __func__); - break; - } - - switch (ttusb->mux_state) { - case 0: - case 1: - case 2: - len--; - if (*data++ == 0xAA) - ++ttusb->mux_state; - else { - ttusb->mux_state = 0; -#if DEBUG > 3 - if (ttusb->insync) - printk("%02x ", data[-1]); -#else - if (ttusb->insync) { - printk("%s: lost sync.\n", - __func__); - ttusb->insync = 0; - } -#endif - } - break; - case 3: - ttusb->insync = 1; - len--; - ttusb->mux_npacks = *data++; - ++ttusb->mux_state; - ttusb->muxpack_ptr = 0; - /* maximum bytes, until we know the length */ - ttusb->muxpack_len = 2; - break; - case 4: - { - int avail; - avail = len; - if (avail > - (ttusb->muxpack_len - - ttusb->muxpack_ptr)) - avail = - ttusb->muxpack_len - - ttusb->muxpack_ptr; - memcpy(ttusb->muxpack + ttusb->muxpack_ptr, - data, avail); - ttusb->muxpack_ptr += avail; - BUG_ON(ttusb->muxpack_ptr > 264); - data += avail; - len -= avail; - /* determine length */ - if (ttusb->muxpack_ptr == 2) { - if (ttusb->muxpack[0] & 0x80) { - ttusb->muxpack_len = - ttusb->muxpack[1] + 2; - if (ttusb-> - muxpack[0] & 0x20) - ttusb-> - muxpack_len++; - if ((!! - (ttusb-> - muxpack[0] & 0x20)) ^ - !!(ttusb-> - muxpack[1] & 1)) - ttusb-> - muxpack_len++; - ttusb->muxpack_len += 4; - } else if (ttusb->muxpack[0] == - 0x47) - ttusb->muxpack_len = - 188 + 4; - else if (ttusb->muxpack[0] == 0x00) - ttusb->muxpack_len = - ttusb->muxpack[1] + 2 + - 4; - else { - dprintk - ("%s: invalid state: first byte is %x\n", - __func__, - ttusb->muxpack[0]); - ttusb->mux_state = 0; - } - } - - /** - * if length is valid and we reached the end: - * goto next muxpack - */ - if ((ttusb->muxpack_ptr >= 2) && - (ttusb->muxpack_ptr == - ttusb->muxpack_len)) { - ttusb_process_muxpack(ttusb, - ttusb-> - muxpack, - ttusb-> - muxpack_ptr); - ttusb->muxpack_ptr = 0; - /* maximum bytes, until we know the length */ - ttusb->muxpack_len = 2; - - /** - * no muxpacks left? - * return to search-sync state - */ - if (!ttusb->mux_npacks--) { - ttusb->mux_state = 0; - break; - } - } - break; - } - default: - BUG(); - break; - } - } -} - -static void ttusb_iso_irq(struct urb *urb) -{ - struct ttusb *ttusb = urb->context; - - if (!ttusb->iso_streaming) - return; - -#if 0 - printk("%s: status %d, errcount == %d, length == %i\n", - __func__, - urb->status, urb->error_count, urb->actual_length); -#endif - - if (!urb->status) { - int i; - for (i = 0; i < urb->number_of_packets; ++i) { - struct usb_iso_packet_descriptor *d; - u8 *data; - int len; - numpkt++; - if (time_after_eq(jiffies, lastj + HZ)) { -#if DEBUG > 2 - printk - ("frames/s: %d (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n", - numpkt * HZ / (jiffies - lastj), - numts, numstuff, numsec, numinvalid, - numts + numstuff + numsec + - numinvalid); -#endif - numts = numstuff = numsec = numinvalid = 0; - lastj = jiffies; - numpkt = 0; - } - d = &urb->iso_frame_desc[i]; - data = urb->transfer_buffer + d->offset; - len = d->actual_length; - d->actual_length = 0; - d->status = 0; - ttusb_process_frame(ttusb, data, len); - } - } - usb_submit_urb(urb, GFP_ATOMIC); -} - -static void ttusb_free_iso_urbs(struct ttusb *ttusb) -{ - int i; - - for (i = 0; i < ISO_BUF_COUNT; i++) - if (ttusb->iso_urb[i]) - usb_free_urb(ttusb->iso_urb[i]); - - pci_free_consistent(NULL, - ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * - ISO_BUF_COUNT, ttusb->iso_buffer, - ttusb->iso_dma_handle); -} - -static int ttusb_alloc_iso_urbs(struct ttusb *ttusb) -{ - int i; - - ttusb->iso_buffer = pci_alloc_consistent(NULL, - ISO_FRAME_SIZE * - FRAMES_PER_ISO_BUF * - ISO_BUF_COUNT, - &ttusb->iso_dma_handle); - - if (!ttusb->iso_buffer) { - dprintk("%s: pci_alloc_consistent - not enough memory\n", - __func__); - return -ENOMEM; - } - - memset(ttusb->iso_buffer, 0, - ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT); - - for (i = 0; i < ISO_BUF_COUNT; i++) { - struct urb *urb; - - if (! - (urb = - usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { - ttusb_free_iso_urbs(ttusb); - return -ENOMEM; - } - - ttusb->iso_urb[i] = urb; - } - - return 0; -} - -static void ttusb_stop_iso_xfer(struct ttusb *ttusb) -{ - int i; - - for (i = 0; i < ISO_BUF_COUNT; i++) - usb_kill_urb(ttusb->iso_urb[i]); - - ttusb->iso_streaming = 0; -} - -static int ttusb_start_iso_xfer(struct ttusb *ttusb) -{ - int i, j, err, buffer_offset = 0; - - if (ttusb->iso_streaming) { - printk("%s: iso xfer already running!\n", __func__); - return 0; - } - - ttusb->cc = -1; - ttusb->insync = 0; - ttusb->mux_state = 0; - - for (i = 0; i < ISO_BUF_COUNT; i++) { - int frame_offset = 0; - struct urb *urb = ttusb->iso_urb[i]; - - urb->dev = ttusb->dev; - urb->context = ttusb; - urb->complete = ttusb_iso_irq; - urb->pipe = ttusb->isoc_in_pipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->interval = 1; - urb->number_of_packets = FRAMES_PER_ISO_BUF; - urb->transfer_buffer_length = - ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; - urb->transfer_buffer = ttusb->iso_buffer + buffer_offset; - buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; - - for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; - frame_offset += ISO_FRAME_SIZE; - } - } - - for (i = 0; i < ISO_BUF_COUNT; i++) { - if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_ATOMIC))) { - ttusb_stop_iso_xfer(ttusb); - printk - ("%s: failed urb submission (%i: err = %i)!\n", - __func__, i, err); - return err; - } - } - - ttusb->iso_streaming = 1; - - return 0; -} - -#ifdef TTUSB_HWSECTIONS -static void ttusb_handle_ts_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data, - int len) -{ - dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0); -} - -static void ttusb_handle_sec_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data, - int len) -{ -// struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed; -#error TODO: handle ugly stuff -// dvbdmxfeed->cb.sec(data, len, 0, 0, &dvbdmxfeed->feed.sec, 0); -} -#endif - -static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; - int feed_type = 1; - - dprintk("ttusb_start_feed\n"); - - switch (dvbdmxfeed->type) { - case DMX_TYPE_TS: - break; - case DMX_TYPE_SEC: - break; - default: - return -EINVAL; - } - - if (dvbdmxfeed->type == DMX_TYPE_TS) { - switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - case DMX_TS_PES_AUDIO: - case DMX_TS_PES_TELETEXT: - case DMX_TS_PES_PCR: - case DMX_TS_PES_OTHER: - break; - default: - return -EINVAL; - } - } - -#ifdef TTUSB_HWSECTIONS -#error TODO: allocate filters - if (dvbdmxfeed->type == DMX_TYPE_TS) { - feed_type = 1; - } else if (dvbdmxfeed->type == DMX_TYPE_SEC) { - feed_type = 2; - } -#endif - - ttusb_set_channel(ttusb, dvbdmxfeed->index, feed_type, dvbdmxfeed->pid); - - if (0 == ttusb->running_feed_count++) - ttusb_start_iso_xfer(ttusb); - - return 0; -} - -static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; - - ttusb_del_channel(ttusb, dvbdmxfeed->index); - - if (--ttusb->running_feed_count == 0) - ttusb_stop_iso_xfer(ttusb); - - return 0; -} - -static int ttusb_setup_interfaces(struct ttusb *ttusb) -{ - usb_set_interface(ttusb->dev, 1, 1); - - ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1); - ttusb->bulk_in_pipe = usb_rcvbulkpipe(ttusb->dev, 1); - ttusb->isoc_in_pipe = usb_rcvisocpipe(ttusb->dev, 2); - - return 0; -} - -#if 0 -static u8 stc_firmware[8192]; - -static int stc_open(struct inode *inode, struct file *file) -{ - struct ttusb *ttusb = file->private_data; - int addr; - - for (addr = 0; addr < 8192; addr += 16) { - u8 snd_buf[2] = { addr >> 8, addr & 0xFF }; - ttusb_i2c_msg(ttusb, 0x50, snd_buf, 2, stc_firmware + addr, - 16); - } - - return 0; -} - -static ssize_t stc_read(struct file *file, char *buf, size_t count, - loff_t *offset) -{ - return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192); -} - -static int stc_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static const struct file_operations stc_fops = { - .owner = THIS_MODULE, - .read = stc_read, - .open = stc_open, - .release = stc_release, -}; -#endif - -static u32 functionality(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - - - -static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 data[4]; - struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) }; - u32 div; - - div = (params->frequency + 36166667) / 166667; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = ((div >> 10) & 0x60) | 0x85; - data[3] = params->frequency < 592000000 ? 0x40 : 0x80; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct cx22700_config alps_tdmb7_config = { - .demod_address = 0x43, -}; - - - - - -static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; - struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) }; - - // setup PLL configuration - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; - msleep(1); - - // disable the mc44BC374c (do not check for errors) - tuner_msg.addr = 0x65; - tuner_msg.buf = disable_mc44BC374c; - tuner_msg.len = sizeof(disable_mc44BC374c); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { - i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1); - } - - return 0; -} - -static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = params->frequency + 36130000; - if (tuner_frequency < 87000000) return -EINVAL; - else if (tuner_frequency < 130000000) cp = 3; - else if (tuner_frequency < 160000000) cp = 5; - else if (tuner_frequency < 200000000) cp = 6; - else if (tuner_frequency < 290000000) cp = 3; - else if (tuner_frequency < 420000000) cp = 5; - else if (tuner_frequency < 480000000) cp = 6; - else if (tuner_frequency < 620000000) cp = 3; - else if (tuner_frequency < 830000000) cp = 5; - else if (tuner_frequency < 895000000) cp = 7; - else return -EINVAL; - - // determine band - if (params->frequency < 49000000) return -EINVAL; - else if (params->frequency < 159000000) band = 1; - else if (params->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) band = 4; - else return -EINVAL; - - // setup PLL filter - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - tda1004x_writereg(fe, 0x0C, 0); - filter = 0; - break; - - case BANDWIDTH_7_MHZ: - tda1004x_writereg(fe, 0x0C, 0); - filter = 0; - break; - - case BANDWIDTH_8_MHZ: - tda1004x_writereg(fe, 0x0C, 0xFF); - filter = 1; - break; - - default: - return -EINVAL; - } - - // calculate divisor - // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - return 0; -} - -static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - - return request_firmware(fw, name, &ttusb->dev->dev); -} - -static struct tda1004x_config philips_tdm1316l_config = { - - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 0, - .request_firmware = philips_tdm1316l_request_firmware, -}; - -static u8 alps_bsbe1_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - 0x10, 0x3f, // AGC2 0x3d - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, // lock detector threshold - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 - 0x29, 0x1e, // 1/2 threshold - 0x2a, 0x14, // 2/3 threshold - 0x2b, 0x0f, // 3/4 threshold - 0x2c, 0x09, // 5/6 threshold - 0x2d, 0x05, // 7/8 threshold - 0x2e, 0x01, - 0x31, 0x1f, // test all FECs - 0x32, 0x19, // viterbi and synchro search - 0x33, 0xfc, // rs control - 0x34, 0x93, // error control - 0x0f, 0x92, - 0xff, 0xff -}; - -static u8 alps_bsru6_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - 0x10, 0x3f, // AGC2 0x3d - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, // lock detector threshold - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 - 0x29, 0x1e, // 1/2 threshold - 0x2a, 0x14, // 2/3 threshold - 0x2b, 0x0f, // 3/4 threshold - 0x2c, 0x09, // 5/6 threshold - 0x2d, 0x05, // 7/8 threshold - 0x2e, 0x01, - 0x31, 0x1f, // test all FECs - 0x32, 0x19, // viterbi and synchro search - 0x33, 0xfc, // rs control - 0x34, 0x93, // error control - 0x0f, 0x52, - 0xff, 0xff -}; - -static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { - aclk = 0xb7; - bclk = 0x47; - } else if (srate < 3000000) { - aclk = 0xb7; - bclk = 0x4b; - } else if (srate < 7000000) { - aclk = 0xb7; - bclk = 0x4f; - } else if (srate < 14000000) { - aclk = 0xb7; - bclk = 0x53; - } else if (srate < 30000000) { - aclk = 0xb6; - bclk = 0x53; - } else if (srate < 45000000) { - aclk = 0xb4; - bclk = 0x51; - } - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - - return 0; -} - -static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 buf[4]; - u32 div; - struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - if ((params->frequency < 950000) || (params->frequency > 2150000)) - return -EINVAL; - - div = (params->frequency + (125 - 1)) / 125; // round correctly - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; - buf[3] = 0xC4; - - if (params->frequency > 1530000) - buf[3] = 0xC0; - - /* BSBE1 wants XCE bit set */ - if (ttusb->revision == TTUSB_REV_2_2) - buf[3] |= 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static struct stv0299_config alps_stv0299_config = { - .demod_address = 0x68, - .inittab = alps_bsru6_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = alps_stv0299_set_symbol_rate, -}; - -static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - u8 buf[4]; - u32 div; - struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - div = params->frequency / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x8e; - buf[3] = 0x00; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static struct tda8083_config ttusb_novas_grundig_29504_491_config = { - - .demod_address = 0x68, -}; - -static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - struct ttusb* ttusb = fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (params->frequency + 35937500 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - - -static struct ves1820_config alps_tdbe2_config = { - .demod_address = 0x09, - .xin = 57840000UL, - .invert = 1, - .selagc = VES1820_SELAGC_SIGNAMPERR, -}; - -static u8 read_pwm(struct ttusb* ttusb) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, - { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; - - if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - - -static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv; - u8 tuner_buf[5]; - struct i2c_msg tuner_msg = {.addr = 0x60, - .flags = 0, - .buf = tuner_buf, - .len = sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = params->frequency; - if (tuner_frequency < 87000000) {return -EINVAL;} - else if (tuner_frequency < 130000000) {cp = 3; band = 1;} - else if (tuner_frequency < 160000000) {cp = 5; band = 1;} - else if (tuner_frequency < 200000000) {cp = 6; band = 1;} - else if (tuner_frequency < 290000000) {cp = 3; band = 2;} - else if (tuner_frequency < 420000000) {cp = 5; band = 2;} - else if (tuner_frequency < 480000000) {cp = 6; band = 2;} - else if (tuner_frequency < 620000000) {cp = 3; band = 4;} - else if (tuner_frequency < 830000000) {cp = 5; band = 4;} - else if (tuner_frequency < 895000000) {cp = 7; band = 4;} - else {return -EINVAL;} - - // assume PLL filter should always be 8MHz for the moment. - filter = 1; - - // calculate divisor - // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz - tuner_frequency = ((params->frequency + 36125000) / 62500); - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xc8; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - tuner_buf[4] = 0x80; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { - printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n"); - return -EIO; - } - - msleep(50); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { - printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n"); - return -EIO; - } - - msleep(1); - - return 0; -} - -static u8 dvbc_philips_tdm1316l_inittab[] = { - 0x80, 0x21, - 0x80, 0x20, - 0x81, 0x01, - 0x81, 0x00, - 0x00, 0x09, - 0x01, 0x69, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x20, 0x00, - 0x21, 0x40, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x40, - 0x25, 0x88, - 0x30, 0xff, - 0x31, 0x00, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x50, - 0x35, 0x7f, - 0x36, 0x00, - 0x37, 0x20, - 0x38, 0x00, - 0x40, 0x1c, - 0x41, 0xff, - 0x42, 0x29, - 0x43, 0x20, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0xff, - 0x4b, 0x7f, - 0x52, 0x30, - 0x55, 0xae, - 0x56, 0x47, - 0x57, 0xe1, - 0x58, 0x3a, - 0x5a, 0x1e, - 0x5b, 0x34, - 0x60, 0x00, - 0x63, 0x00, - 0x64, 0x00, - 0x65, 0x00, - 0x66, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x69, 0x00, - 0x6a, 0x02, - 0x6b, 0x00, - 0x70, 0xff, - 0x71, 0x00, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x00, - 0x81, 0x00, - 0x82, 0x00, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x80, - 0x86, 0x24, - 0x87, 0x78, - 0x88, 0x00, - 0x89, 0x00, - 0x90, 0x01, - 0x91, 0x01, - 0xa0, 0x00, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x4b, - 0xc1, 0x00, - 0xc2, 0x00, - 0xd0, 0x00, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x00, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x00, - 0x61, 0x38, - 0x62, 0x0a, - 0x53, 0x13, - 0x59, 0x08, - 0x55, 0x00, - 0x56, 0x40, - 0x57, 0x08, - 0x58, 0x3d, - 0x88, 0x10, - 0xa0, 0x00, - 0xa0, 0x00, - 0xa0, 0x00, - 0xa0, 0x04, - 0xff, 0xff, -}; - -static struct stv0297_config dvbc_philips_tdm1316l_config = { - .demod_address = 0x1c, - .inittab = dvbc_philips_tdm1316l_inittab, - .invert = 0, -}; - -static void frontend_init(struct ttusb* ttusb) -{ - switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) { - case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059)) - // try the stv0299 based first - ttusb->fe = dvb_attach(stv0299_attach, &alps_stv0299_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params; - - if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1 - alps_stv0299_config.inittab = alps_bsbe1_inittab; - dvb_attach(lnbp21_attach, ttusb->fe, &ttusb->i2c_adap, 0, 0); - } else { // ALPS BSRU6 - ttusb->fe->ops.set_voltage = ttusb_set_voltage; - } - break; - } - - // Grundig 29504-491 - ttusb->fe = dvb_attach(tda8083_attach, &ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params; - ttusb->fe->ops.set_voltage = ttusb_set_voltage; - break; - } - break; - - case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) - ttusb->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb)); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; - break; - } - - ttusb->fe = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??)) - // try the ALPS TDMB7 first - ttusb->fe = dvb_attach(cx22700_attach, &alps_tdmb7_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params; - break; - } - - // Philips td1316 - ttusb->fe = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) { - ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init; - ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; - break; - } - break; - } - - if (ttusb->fe == NULL) { - printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n", - le16_to_cpu(ttusb->dev->descriptor.idVendor), - le16_to_cpu(ttusb->dev->descriptor.idProduct)); - } else { - if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) { - printk("dvb-ttusb-budget: Frontend registration failed!\n"); - dvb_frontend_detach(ttusb->fe); - ttusb->fe = NULL; - } - } -} - - - -static struct i2c_algorithm ttusb_dec_algo = { - .master_xfer = master_xfer, - .functionality = functionality, -}; - -static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev; - struct ttusb *ttusb; - int result; - - dprintk("%s: TTUSB DVB connected\n", __func__); - - udev = interface_to_usbdev(intf); - - if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV; - - if (!(ttusb = kzalloc(sizeof(struct ttusb), GFP_KERNEL))) - return -ENOMEM; - - ttusb->dev = udev; - ttusb->c = 0; - ttusb->mux_state = 0; - mutex_init(&ttusb->semi2c); - - mutex_lock(&ttusb->semi2c); - - mutex_init(&ttusb->semusb); - - ttusb_setup_interfaces(ttusb); - - result = ttusb_alloc_iso_urbs(ttusb); - if (result < 0) { - dprintk("%s: ttusb_alloc_iso_urbs - failed\n", __func__); - mutex_unlock(&ttusb->semi2c); - kfree(ttusb); - return result; - } - - if (ttusb_init_controller(ttusb)) - printk("ttusb_init_controller: error\n"); - - mutex_unlock(&ttusb->semi2c); - - result = dvb_register_adapter(&ttusb->adapter, - "Technotrend/Hauppauge Nova-USB", - THIS_MODULE, &udev->dev, adapter_nr); - if (result < 0) { - ttusb_free_iso_urbs(ttusb); - kfree(ttusb); - return result; - } - ttusb->adapter.priv = ttusb; - - /* i2c */ - memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter)); - strcpy(ttusb->i2c_adap.name, "TTUSB DEC"); - - i2c_set_adapdata(&ttusb->i2c_adap, ttusb); - - ttusb->i2c_adap.algo = &ttusb_dec_algo; - ttusb->i2c_adap.algo_data = NULL; - ttusb->i2c_adap.dev.parent = &udev->dev; - - result = i2c_add_adapter(&ttusb->i2c_adap); - if (result) { - dvb_unregister_adapter (&ttusb->adapter); - return result; - } - - memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); - - ttusb->dvb_demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING; - ttusb->dvb_demux.priv = NULL; -#ifdef TTUSB_HWSECTIONS - ttusb->dvb_demux.filternum = TTUSB_MAXFILTER; -#else - ttusb->dvb_demux.filternum = 32; -#endif - ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL; - ttusb->dvb_demux.start_feed = ttusb_start_feed; - ttusb->dvb_demux.stop_feed = ttusb_stop_feed; - ttusb->dvb_demux.write_to_decoder = NULL; - - if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) { - printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result); - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (&ttusb->adapter); - return -ENODEV; - } -//FIXME dmxdev (nur WAS?) - ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum; - ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx; - ttusb->dmxdev.capabilities = 0; - - if ((result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter)) < 0) { - printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n", - result); - dvb_dmx_release(&ttusb->dvb_demux); - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (&ttusb->adapter); - return -ENODEV; - } - - if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { - printk("ttusb_dvb: dvb_net_init failed!\n"); - dvb_dmxdev_release(&ttusb->dmxdev); - dvb_dmx_release(&ttusb->dvb_demux); - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (&ttusb->adapter); - return -ENODEV; - } - - usb_set_intfdata(intf, (void *) ttusb); - - frontend_init(ttusb); - - return 0; -} - -static void ttusb_disconnect(struct usb_interface *intf) -{ - struct ttusb *ttusb = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - - ttusb->disconnecting = 1; - - ttusb_stop_iso_xfer(ttusb); - - ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx); - dvb_net_release(&ttusb->dvbnet); - dvb_dmxdev_release(&ttusb->dmxdev); - dvb_dmx_release(&ttusb->dvb_demux); - if (ttusb->fe != NULL) { - dvb_unregister_frontend(ttusb->fe); - dvb_frontend_detach(ttusb->fe); - } - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter(&ttusb->adapter); - - ttusb_free_iso_urbs(ttusb); - - kfree(ttusb); - - dprintk("%s: TTUSB DVB disconnected\n", __func__); -} - -static struct usb_device_id ttusb_table[] = { - {USB_DEVICE(0xb48, 0x1003)}, - {USB_DEVICE(0xb48, 0x1004)}, - {USB_DEVICE(0xb48, 0x1005)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, ttusb_table); - -static struct usb_driver ttusb_driver = { - .name = "ttusb", - .probe = ttusb_probe, - .disconnect = ttusb_disconnect, - .id_table = ttusb_table, -}; - -static int __init ttusb_init(void) -{ - int err; - - if ((err = usb_register(&ttusb_driver)) < 0) { - printk("%s: usb_register failed! Error number %d", - __FILE__, err); - return err; - } - - return 0; -} - -static void __exit ttusb_exit(void) -{ - usb_deregister(&ttusb_driver); -} - -module_init(ttusb_init); -module_exit(ttusb_exit); - -MODULE_AUTHOR("Holger Waechtler "); -MODULE_DESCRIPTION("TTUSB DVB Driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("ttusb-budget/dspbootcode.bin"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -config DVB_TTUSB_BUDGET - tristate "Technotrend/Hauppauge Nova-USB devices" - depends on DVB_CORE && USB && I2C && PCI - select DVB_CX22700 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_VES1820 if !DVB_FE_CUSTOMISE - select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0297 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - help - Support for external USB adapters designed by Technotrend and - produced by Hauppauge, shipped under the brand name 'Nova-USB'. - - These devices don't have a MPEG decoder built in, so you need - an external software decoder to watch TV. - - Say Y if you own such a device and want to use it. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-budget/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -config DVB_TTUSB_DEC - tristate "Technotrend/Hauppauge USB DEC devices" - depends on DVB_CORE && USB && INPUT && PCI - select CRC32 - help - Support for external USB adapters designed by Technotrend and - produced by Hauppauge, shipped under the brand name 'DEC2000-t' - and 'DEC3000-s'. - - Even if these devices have a MPEG decoder built in, they transmit - only compressed MPEG data over the USB bus, so you need - an external software decoder to watch TV on your computer. - - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware dec2000t", - "/Documentation/dvb/get_dvb_firmware dec2540t", - "/Documentation/dvb/get_dvb_firmware dec3000s", - download/extract them, and then copy them to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - - Say Y if you own such a device and want to use it. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1783 +0,0 @@ -/* - * TTUSB DEC Driver - * - * Copyright (C) 2003-2004 Alex Woods - * IR support by Peter Beutner - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_filter.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "ttusbdecfe.h" - -static int debug; -static int output_pva; -static int enable_rc; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); -module_param(output_pva, int, 0444); -MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)"); -module_param(enable_rc, int, 0644); -MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk if (debug) printk - -#define DRIVER_NAME "TechnoTrend/Hauppauge DEC USB" - -#define COMMAND_PIPE 0x03 -#define RESULT_PIPE 0x04 -#define IN_PIPE 0x08 -#define OUT_PIPE 0x07 -#define IRQ_PIPE 0x0A - -#define COMMAND_PACKET_SIZE 0x3c -#define ARM_PACKET_SIZE 0x1000 -#define IRQ_PACKET_SIZE 0x8 - -#define ISO_BUF_COUNT 0x04 -#define FRAMES_PER_ISO_BUF 0x04 -#define ISO_FRAME_SIZE 0x0380 - -#define MAX_PVA_LENGTH 6144 - -enum ttusb_dec_model { - TTUSB_DEC2000T, - TTUSB_DEC2540T, - TTUSB_DEC3000S -}; - -enum ttusb_dec_packet_type { - TTUSB_DEC_PACKET_PVA, - TTUSB_DEC_PACKET_SECTION, - TTUSB_DEC_PACKET_EMPTY -}; - -enum ttusb_dec_interface { - TTUSB_DEC_INTERFACE_INITIAL, - TTUSB_DEC_INTERFACE_IN, - TTUSB_DEC_INTERFACE_OUT -}; - -struct ttusb_dec { - enum ttusb_dec_model model; - char *model_name; - char *firmware_name; - int can_playback; - - /* DVB bits */ - struct dvb_adapter adapter; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dmx_frontend frontend; - struct dvb_net dvb_net; - struct dvb_frontend* fe; - - u16 pid[DMX_PES_OTHER]; - - /* USB bits */ - struct usb_device *udev; - u8 trans_count; - unsigned int command_pipe; - unsigned int result_pipe; - unsigned int in_pipe; - unsigned int out_pipe; - unsigned int irq_pipe; - enum ttusb_dec_interface interface; - struct mutex usb_mutex; - - void *irq_buffer; - struct urb *irq_urb; - dma_addr_t irq_dma_handle; - void *iso_buffer; - dma_addr_t iso_dma_handle; - struct urb *iso_urb[ISO_BUF_COUNT]; - int iso_stream_count; - struct mutex iso_mutex; - - u8 packet[MAX_PVA_LENGTH + 4]; - enum ttusb_dec_packet_type packet_type; - int packet_state; - int packet_length; - int packet_payload_length; - u16 next_packet_id; - - int pva_stream_count; - int filter_stream_count; - - struct dvb_filter_pes2ts a_pes2ts; - struct dvb_filter_pes2ts v_pes2ts; - - u8 v_pes[16 + MAX_PVA_LENGTH]; - int v_pes_length; - int v_pes_postbytes; - - struct list_head urb_frame_list; - struct tasklet_struct urb_tasklet; - spinlock_t urb_frame_list_lock; - - struct dvb_demux_filter *audio_filter; - struct dvb_demux_filter *video_filter; - struct list_head filter_info_list; - spinlock_t filter_info_list_lock; - - struct input_dev *rc_input_dev; - char rc_phys[64]; - - int active; /* Loaded successfully */ -}; - -struct urb_frame { - u8 data[ISO_FRAME_SIZE]; - int length; - struct list_head urb_frame_list; -}; - -struct filter_info { - u8 stream_id; - struct dvb_demux_filter *filter; - struct list_head filter_info_list; -}; - -static u16 rc_keys[] = { - KEY_POWER, - KEY_MUTE, - KEY_1, - KEY_2, - KEY_3, - KEY_4, - KEY_5, - KEY_6, - KEY_7, - KEY_8, - KEY_9, - KEY_0, - KEY_CHANNELUP, - KEY_VOLUMEDOWN, - KEY_OK, - KEY_VOLUMEUP, - KEY_CHANNELDOWN, - KEY_PREVIOUS, - KEY_ESC, - KEY_RED, - KEY_GREEN, - KEY_YELLOW, - KEY_BLUE, - KEY_OPTION, - KEY_M, - KEY_RADIO -}; - -static void ttusb_dec_set_model(struct ttusb_dec *dec, - enum ttusb_dec_model model); - -static void ttusb_dec_handle_irq( struct urb *urb) -{ - struct ttusb_dec * dec = urb->context; - char *buffer = dec->irq_buffer; - int retval; - - switch(urb->status) { - case 0: /*success*/ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - case -ETIME: - /* this urb is dead, cleanup */ - dprintk("%s:urb shutting down with status: %d\n", - __func__, urb->status); - return; - default: - dprintk("%s:nonzero status received: %d\n", - __func__,urb->status); - goto exit; - } - - if( (buffer[0] == 0x1) && (buffer[2] == 0x15) ) { - /* IR - Event */ - /* this is an fact a bit too simple implementation; - * the box also reports a keyrepeat signal - * (with buffer[3] == 0x40) in an intervall of ~100ms. - * But to handle this correctly we had to imlemenent some - * kind of timer which signals a 'key up' event if no - * keyrepeat signal is recieved for lets say 200ms. - * this should/could be added later ... - * for now lets report each signal as a key down and up*/ - dprintk("%s:rc signal:%d\n", __func__, buffer[4]); - input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); - input_sync(dec->rc_input_dev); - input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); - input_sync(dec->rc_input_dev); - } - -exit: retval = usb_submit_urb(urb, GFP_ATOMIC); - if(retval) - printk("%s - usb_commit_urb failed with result: %d\n", - __func__, retval); -} - -static u16 crc16(u16 crc, const u8 *buf, size_t len) -{ - u16 tmp; - - while (len--) { - crc ^= *buf++; - crc ^= (u8)crc >> 4; - tmp = (u8)crc; - crc ^= (tmp ^ (tmp << 1)) << 4; - } - return crc; -} - -static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, - int param_length, const u8 params[], - int *result_length, u8 cmd_result[]) -{ - int result, actual_len, i; - u8 *b; - - dprintk("%s\n", __func__); - - b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); - if (!b) - return -ENOMEM; - - if ((result = mutex_lock_interruptible(&dec->usb_mutex))) { - kfree(b); - printk("%s: Failed to lock usb mutex.\n", __func__); - return result; - } - - b[0] = 0xaa; - b[1] = ++dec->trans_count; - b[2] = command; - b[3] = param_length; - - if (params) - memcpy(&b[4], params, param_length); - - if (debug) { - printk("%s: command: ", __func__); - for (i = 0; i < param_length + 4; i++) - printk("0x%02X ", b[i]); - printk("\n"); - } - - result = usb_bulk_msg(dec->udev, dec->command_pipe, b, - COMMAND_PACKET_SIZE + 4, &actual_len, 1000); - - if (result) { - printk("%s: command bulk message failed: error %d\n", - __func__, result); - mutex_unlock(&dec->usb_mutex); - kfree(b); - return result; - } - - result = usb_bulk_msg(dec->udev, dec->result_pipe, b, - COMMAND_PACKET_SIZE + 4, &actual_len, 1000); - - if (result) { - printk("%s: result bulk message failed: error %d\n", - __func__, result); - mutex_unlock(&dec->usb_mutex); - kfree(b); - return result; - } else { - if (debug) { - printk("%s: result: ", __func__); - for (i = 0; i < actual_len; i++) - printk("0x%02X ", b[i]); - printk("\n"); - } - - if (result_length) - *result_length = b[3]; - if (cmd_result && b[3] > 0) - memcpy(cmd_result, &b[4], b[3]); - - mutex_unlock(&dec->usb_mutex); - - kfree(b); - return 0; - } -} - -static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, - unsigned int *model, unsigned int *version) -{ - u8 c[COMMAND_PACKET_SIZE]; - int c_length; - int result; - __be32 tmp; - - dprintk("%s\n", __func__); - - result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); - if (result) - return result; - - if (c_length >= 0x0c) { - if (mode != NULL) { - memcpy(&tmp, c, 4); - *mode = ntohl(tmp); - } - if (model != NULL) { - memcpy(&tmp, &c[4], 4); - *model = ntohl(tmp); - } - if (version != NULL) { - memcpy(&tmp, &c[8], 4); - *version = ntohl(tmp); - } - return 0; - } else { - return -1; - } -} - -static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) -{ - struct ttusb_dec *dec = priv; - - dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, - &dec->audio_filter->feed->feed.ts, - DMX_OK); - - return 0; -} - -static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) -{ - struct ttusb_dec *dec = priv; - - dec->video_filter->feed->cb.ts(data, 188, NULL, 0, - &dec->video_filter->feed->feed.ts, - DMX_OK); - - return 0; -} - -static void ttusb_dec_set_pids(struct ttusb_dec *dec) -{ - u8 b[] = { 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff }; - - __be16 pcr = htons(dec->pid[DMX_PES_PCR]); - __be16 audio = htons(dec->pid[DMX_PES_AUDIO]); - __be16 video = htons(dec->pid[DMX_PES_VIDEO]); - - dprintk("%s\n", __func__); - - memcpy(&b[0], &pcr, 2); - memcpy(&b[2], &audio, 2); - memcpy(&b[4], &video, 2); - - ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL); - - dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], - ttusb_dec_audio_pes2ts_cb, dec); - dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], - ttusb_dec_video_pes2ts_cb, dec); - dec->v_pes_length = 0; - dec->v_pes_postbytes = 0; -} - -static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) -{ - if (length < 8) { - printk("%s: packet too short - discarding\n", __func__); - return; - } - - if (length > 8 + MAX_PVA_LENGTH) { - printk("%s: packet too long - discarding\n", __func__); - return; - } - - switch (pva[2]) { - - case 0x01: { /* VideoStream */ - int prebytes = pva[5] & 0x03; - int postbytes = (pva[5] & 0x0c) >> 2; - __be16 v_pes_payload_length; - - if (output_pva) { - dec->video_filter->feed->cb.ts(pva, length, NULL, 0, - &dec->video_filter->feed->feed.ts, DMX_OK); - return; - } - - if (dec->v_pes_postbytes > 0 && - dec->v_pes_postbytes == prebytes) { - memcpy(&dec->v_pes[dec->v_pes_length], - &pva[12], prebytes); - - dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, - dec->v_pes_length + prebytes, 1); - } - - if (pva[5] & 0x10) { - dec->v_pes[7] = 0x80; - dec->v_pes[8] = 0x05; - - dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5); - dec->v_pes[10] = ((pva[8] & 0x3f) << 2) | - ((pva[9] & 0xc0) >> 6); - dec->v_pes[11] = 0x01 | - ((pva[9] & 0x3f) << 2) | - ((pva[10] & 0x80) >> 6); - dec->v_pes[12] = ((pva[10] & 0x7f) << 1) | - ((pva[11] & 0xc0) >> 7); - dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1); - - memcpy(&dec->v_pes[14], &pva[12 + prebytes], - length - 12 - prebytes); - dec->v_pes_length = 14 + length - 12 - prebytes; - } else { - dec->v_pes[7] = 0x00; - dec->v_pes[8] = 0x00; - - memcpy(&dec->v_pes[9], &pva[8], length - 8); - dec->v_pes_length = 9 + length - 8; - } - - dec->v_pes_postbytes = postbytes; - - if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 && - dec->v_pes[10 + dec->v_pes[8]] == 0x00 && - dec->v_pes[11 + dec->v_pes[8]] == 0x01) - dec->v_pes[6] = 0x84; - else - dec->v_pes[6] = 0x80; - - v_pes_payload_length = htons(dec->v_pes_length - 6 + - postbytes); - memcpy(&dec->v_pes[4], &v_pes_payload_length, 2); - - if (postbytes == 0) - dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, - dec->v_pes_length, 1); - - break; - } - - case 0x02: /* MainAudioStream */ - if (output_pva) { - dec->audio_filter->feed->cb.ts(pva, length, NULL, 0, - &dec->audio_filter->feed->feed.ts, DMX_OK); - return; - } - - dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8, - pva[5] & 0x10); - break; - - default: - printk("%s: unknown PVA type: %02x.\n", __func__, - pva[2]); - break; - } -} - -static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet, - int length) -{ - struct list_head *item; - struct filter_info *finfo; - struct dvb_demux_filter *filter = NULL; - unsigned long flags; - u8 sid; - - sid = packet[1]; - spin_lock_irqsave(&dec->filter_info_list_lock, flags); - for (item = dec->filter_info_list.next; item != &dec->filter_info_list; - item = item->next) { - finfo = list_entry(item, struct filter_info, filter_info_list); - if (finfo->stream_id == sid) { - filter = finfo->filter; - break; - } - } - spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); - - if (filter) - filter->feed->cb.sec(&packet[2], length - 2, NULL, 0, - &filter->filter, DMX_OK); -} - -static void ttusb_dec_process_packet(struct ttusb_dec *dec) -{ - int i; - u16 csum = 0; - u16 packet_id; - - if (dec->packet_length % 2) { - printk("%s: odd sized packet - discarding\n", __func__); - return; - } - - for (i = 0; i < dec->packet_length; i += 2) - csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]); - - if (csum) { - printk("%s: checksum failed - discarding\n", __func__); - return; - } - - packet_id = dec->packet[dec->packet_length - 4] << 8; - packet_id += dec->packet[dec->packet_length - 3]; - - if ((packet_id != dec->next_packet_id) && dec->next_packet_id) { - printk("%s: warning: lost packets between %u and %u\n", - __func__, dec->next_packet_id - 1, packet_id); - } - - if (packet_id == 0xffff) - dec->next_packet_id = 0x8000; - else - dec->next_packet_id = packet_id + 1; - - switch (dec->packet_type) { - case TTUSB_DEC_PACKET_PVA: - if (dec->pva_stream_count) - ttusb_dec_process_pva(dec, dec->packet, - dec->packet_payload_length); - break; - - case TTUSB_DEC_PACKET_SECTION: - if (dec->filter_stream_count) - ttusb_dec_process_filter(dec, dec->packet, - dec->packet_payload_length); - break; - - case TTUSB_DEC_PACKET_EMPTY: - break; - } -} - -static void swap_bytes(u8 *b, int length) -{ - u8 c; - - length -= length % 2; - for (; length; b += 2, length -= 2) { - c = *b; - *b = *(b + 1); - *(b + 1) = c; - } -} - -static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, - int length) -{ - swap_bytes(b, length); - - while (length) { - switch (dec->packet_state) { - - case 0: - case 1: - case 2: - if (*b++ == 0xaa) - dec->packet_state++; - else - dec->packet_state = 0; - - length--; - break; - - case 3: - if (*b == 0x00) { - dec->packet_state++; - dec->packet_length = 0; - } else if (*b != 0xaa) { - dec->packet_state = 0; - } - - b++; - length--; - break; - - case 4: - dec->packet[dec->packet_length++] = *b++; - - if (dec->packet_length == 2) { - if (dec->packet[0] == 'A' && - dec->packet[1] == 'V') { - dec->packet_type = - TTUSB_DEC_PACKET_PVA; - dec->packet_state++; - } else if (dec->packet[0] == 'S') { - dec->packet_type = - TTUSB_DEC_PACKET_SECTION; - dec->packet_state++; - } else if (dec->packet[0] == 0x00) { - dec->packet_type = - TTUSB_DEC_PACKET_EMPTY; - dec->packet_payload_length = 2; - dec->packet_state = 7; - } else { - printk("%s: unknown packet type: " - "%02x%02x\n", __func__, - dec->packet[0], dec->packet[1]); - dec->packet_state = 0; - } - } - - length--; - break; - - case 5: - dec->packet[dec->packet_length++] = *b++; - - if (dec->packet_type == TTUSB_DEC_PACKET_PVA && - dec->packet_length == 8) { - dec->packet_state++; - dec->packet_payload_length = 8 + - (dec->packet[6] << 8) + - dec->packet[7]; - } else if (dec->packet_type == - TTUSB_DEC_PACKET_SECTION && - dec->packet_length == 5) { - dec->packet_state++; - dec->packet_payload_length = 5 + - ((dec->packet[3] & 0x0f) << 8) + - dec->packet[4]; - } - - length--; - break; - - case 6: { - int remainder = dec->packet_payload_length - - dec->packet_length; - - if (length >= remainder) { - memcpy(dec->packet + dec->packet_length, - b, remainder); - dec->packet_length += remainder; - b += remainder; - length -= remainder; - dec->packet_state++; - } else { - memcpy(&dec->packet[dec->packet_length], - b, length); - dec->packet_length += length; - length = 0; - } - - break; - } - - case 7: { - int tail = 4; - - dec->packet[dec->packet_length++] = *b++; - - if (dec->packet_type == TTUSB_DEC_PACKET_SECTION && - dec->packet_payload_length % 2) - tail++; - - if (dec->packet_length == - dec->packet_payload_length + tail) { - ttusb_dec_process_packet(dec); - dec->packet_state = 0; - } - - length--; - break; - } - - default: - printk("%s: illegal packet state encountered.\n", - __func__); - dec->packet_state = 0; - } - } -} - -static void ttusb_dec_process_urb_frame_list(unsigned long data) -{ - struct ttusb_dec *dec = (struct ttusb_dec *)data; - struct list_head *item; - struct urb_frame *frame; - unsigned long flags; - - while (1) { - spin_lock_irqsave(&dec->urb_frame_list_lock, flags); - if ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { - frame = list_entry(item, struct urb_frame, - urb_frame_list); - list_del(&frame->urb_frame_list); - } else { - spin_unlock_irqrestore(&dec->urb_frame_list_lock, - flags); - return; - } - spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); - - ttusb_dec_process_urb_frame(dec, frame->data, frame->length); - kfree(frame); - } -} - -static void ttusb_dec_process_urb(struct urb *urb) -{ - struct ttusb_dec *dec = urb->context; - - if (!urb->status) { - int i; - - for (i = 0; i < FRAMES_PER_ISO_BUF; i++) { - struct usb_iso_packet_descriptor *d; - u8 *b; - int length; - struct urb_frame *frame; - - d = &urb->iso_frame_desc[i]; - b = urb->transfer_buffer + d->offset; - length = d->actual_length; - - if ((frame = kmalloc(sizeof(struct urb_frame), - GFP_ATOMIC))) { - unsigned long flags; - - memcpy(frame->data, b, length); - frame->length = length; - - spin_lock_irqsave(&dec->urb_frame_list_lock, - flags); - list_add_tail(&frame->urb_frame_list, - &dec->urb_frame_list); - spin_unlock_irqrestore(&dec->urb_frame_list_lock, - flags); - - tasklet_schedule(&dec->urb_tasklet); - } - } - } else { - /* -ENOENT is expected when unlinking urbs */ - if (urb->status != -ENOENT) - dprintk("%s: urb error: %d\n", __func__, - urb->status); - } - - if (dec->iso_stream_count) - usb_submit_urb(urb, GFP_ATOMIC); -} - -static void ttusb_dec_setup_urbs(struct ttusb_dec *dec) -{ - int i, j, buffer_offset = 0; - - dprintk("%s\n", __func__); - - for (i = 0; i < ISO_BUF_COUNT; i++) { - int frame_offset = 0; - struct urb *urb = dec->iso_urb[i]; - - urb->dev = dec->udev; - urb->context = dec; - urb->complete = ttusb_dec_process_urb; - urb->pipe = dec->in_pipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->interval = 1; - urb->number_of_packets = FRAMES_PER_ISO_BUF; - urb->transfer_buffer_length = ISO_FRAME_SIZE * - FRAMES_PER_ISO_BUF; - urb->transfer_buffer = dec->iso_buffer + buffer_offset; - buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; - - for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; - frame_offset += ISO_FRAME_SIZE; - } - } -} - -static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec) -{ - int i; - - dprintk("%s\n", __func__); - - if (mutex_lock_interruptible(&dec->iso_mutex)) - return; - - dec->iso_stream_count--; - - if (!dec->iso_stream_count) { - for (i = 0; i < ISO_BUF_COUNT; i++) - usb_kill_urb(dec->iso_urb[i]); - } - - mutex_unlock(&dec->iso_mutex); -} - -/* Setting the interface of the DEC tends to take down the USB communications - * for a short period, so it's important not to call this function just before - * trying to talk to it. - */ -static int ttusb_dec_set_interface(struct ttusb_dec *dec, - enum ttusb_dec_interface interface) -{ - int result = 0; - u8 b[] = { 0x05 }; - - if (interface != dec->interface) { - switch (interface) { - case TTUSB_DEC_INTERFACE_INITIAL: - result = usb_set_interface(dec->udev, 0, 0); - break; - case TTUSB_DEC_INTERFACE_IN: - result = ttusb_dec_send_command(dec, 0x80, sizeof(b), - b, NULL, NULL); - if (result) - return result; - result = usb_set_interface(dec->udev, 0, 8); - break; - case TTUSB_DEC_INTERFACE_OUT: - result = usb_set_interface(dec->udev, 0, 1); - break; - } - - if (result) - return result; - - dec->interface = interface; - } - - return 0; -} - -static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) -{ - int i, result; - - dprintk("%s\n", __func__); - - if (mutex_lock_interruptible(&dec->iso_mutex)) - return -EAGAIN; - - if (!dec->iso_stream_count) { - ttusb_dec_setup_urbs(dec); - - dec->packet_state = 0; - dec->v_pes_postbytes = 0; - dec->next_packet_id = 0; - - for (i = 0; i < ISO_BUF_COUNT; i++) { - if ((result = usb_submit_urb(dec->iso_urb[i], - GFP_ATOMIC))) { - printk("%s: failed urb submission %d: " - "error %d\n", __func__, i, result); - - while (i) { - usb_kill_urb(dec->iso_urb[i - 1]); - i--; - } - - mutex_unlock(&dec->iso_mutex); - return result; - } - } - } - - dec->iso_stream_count++; - - mutex_unlock(&dec->iso_mutex); - - return 0; -} - -static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ttusb_dec *dec = dvbdmx->priv; - u8 b0[] = { 0x05 }; - int result = 0; - - dprintk("%s\n", __func__); - - dprintk(" ts_type:"); - - if (dvbdmxfeed->ts_type & TS_DECODER) - dprintk(" TS_DECODER"); - - if (dvbdmxfeed->ts_type & TS_PACKET) - dprintk(" TS_PACKET"); - - if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) - dprintk(" TS_PAYLOAD_ONLY"); - - dprintk("\n"); - - switch (dvbdmxfeed->pes_type) { - - case DMX_TS_PES_VIDEO: - dprintk(" pes_type: DMX_TS_PES_VIDEO\n"); - dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; - dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; - dec->video_filter = dvbdmxfeed->filter; - ttusb_dec_set_pids(dec); - break; - - case DMX_TS_PES_AUDIO: - dprintk(" pes_type: DMX_TS_PES_AUDIO\n"); - dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; - dec->audio_filter = dvbdmxfeed->filter; - ttusb_dec_set_pids(dec); - break; - - case DMX_TS_PES_TELETEXT: - dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; - dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n"); - return -ENOSYS; - - case DMX_TS_PES_PCR: - dprintk(" pes_type: DMX_TS_PES_PCR\n"); - dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; - ttusb_dec_set_pids(dec); - break; - - case DMX_TS_PES_OTHER: - dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n"); - return -ENOSYS; - - default: - dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); - return -EINVAL; - - } - - result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); - if (result) - return result; - - dec->pva_stream_count++; - return ttusb_dec_start_iso_xfer(dec); -} - -static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb_dec *dec = dvbdmxfeed->demux->priv; - u8 b0[] = { 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00 }; - __be16 pid; - u8 c[COMMAND_PACKET_SIZE]; - int c_length; - int result; - struct filter_info *finfo; - unsigned long flags; - u8 x = 1; - - dprintk("%s\n", __func__); - - pid = htons(dvbdmxfeed->pid); - memcpy(&b0[0], &pid, 2); - memcpy(&b0[4], &x, 1); - memcpy(&b0[5], &dvbdmxfeed->filter->filter.filter_value[0], 1); - - result = ttusb_dec_send_command(dec, 0x60, sizeof(b0), b0, - &c_length, c); - - if (!result) { - if (c_length == 2) { - if (!(finfo = kmalloc(sizeof(struct filter_info), - GFP_ATOMIC))) - return -ENOMEM; - - finfo->stream_id = c[1]; - finfo->filter = dvbdmxfeed->filter; - - spin_lock_irqsave(&dec->filter_info_list_lock, flags); - list_add_tail(&finfo->filter_info_list, - &dec->filter_info_list); - spin_unlock_irqrestore(&dec->filter_info_list_lock, - flags); - - dvbdmxfeed->priv = finfo; - - dec->filter_stream_count++; - return ttusb_dec_start_iso_xfer(dec); - } - - return -EAGAIN; - } else - return result; -} - -static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - - dprintk("%s\n", __func__); - - if (!dvbdmx->dmx.frontend) - return -EINVAL; - - dprintk(" pid: 0x%04X\n", dvbdmxfeed->pid); - - switch (dvbdmxfeed->type) { - - case DMX_TYPE_TS: - return ttusb_dec_start_ts_feed(dvbdmxfeed); - break; - - case DMX_TYPE_SEC: - return ttusb_dec_start_sec_feed(dvbdmxfeed); - break; - - default: - dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); - return -EINVAL; - - } -} - -static int ttusb_dec_stop_ts_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb_dec *dec = dvbdmxfeed->demux->priv; - u8 b0[] = { 0x00 }; - - ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL); - - dec->pva_stream_count--; - - ttusb_dec_stop_iso_xfer(dec); - - return 0; -} - -static int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct ttusb_dec *dec = dvbdmxfeed->demux->priv; - u8 b0[] = { 0x00, 0x00 }; - struct filter_info *finfo = (struct filter_info *)dvbdmxfeed->priv; - unsigned long flags; - - b0[1] = finfo->stream_id; - spin_lock_irqsave(&dec->filter_info_list_lock, flags); - list_del(&finfo->filter_info_list); - spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); - kfree(finfo); - ttusb_dec_send_command(dec, 0x62, sizeof(b0), b0, NULL, NULL); - - dec->filter_stream_count--; - - ttusb_dec_stop_iso_xfer(dec); - - return 0; -} - -static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - dprintk("%s\n", __func__); - - switch (dvbdmxfeed->type) { - case DMX_TYPE_TS: - return ttusb_dec_stop_ts_feed(dvbdmxfeed); - break; - - case DMX_TYPE_SEC: - return ttusb_dec_stop_sec_feed(dvbdmxfeed); - break; - } - - return 0; -} - -static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec) -{ - int i; - - dprintk("%s\n", __func__); - - for (i = 0; i < ISO_BUF_COUNT; i++) - usb_free_urb(dec->iso_urb[i]); - - pci_free_consistent(NULL, - ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * - ISO_BUF_COUNT), - dec->iso_buffer, dec->iso_dma_handle); -} - -static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) -{ - int i; - - dprintk("%s\n", __func__); - - dec->iso_buffer = pci_alloc_consistent(NULL, - ISO_FRAME_SIZE * - (FRAMES_PER_ISO_BUF * - ISO_BUF_COUNT), - &dec->iso_dma_handle); - - if (!dec->iso_buffer) { - dprintk("%s: pci_alloc_consistent - not enough memory\n", - __func__); - return -ENOMEM; - } - - memset(dec->iso_buffer, 0, - ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)); - - for (i = 0; i < ISO_BUF_COUNT; i++) { - struct urb *urb; - - if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { - ttusb_dec_free_iso_urbs(dec); - return -ENOMEM; - } - - dec->iso_urb[i] = urb; - } - - ttusb_dec_setup_urbs(dec); - - return 0; -} - -static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) -{ - spin_lock_init(&dec->urb_frame_list_lock); - INIT_LIST_HEAD(&dec->urb_frame_list); - tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list, - (unsigned long)dec); -} - -static int ttusb_init_rc( struct ttusb_dec *dec) -{ - struct input_dev *input_dev; - u8 b[] = { 0x00, 0x01 }; - int i; - int err; - - usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); - strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - input_dev->name = "ttusb_dec remote control"; - input_dev->phys = dec->rc_phys; - input_dev->evbit[0] = BIT_MASK(EV_KEY); - input_dev->keycodesize = sizeof(u16); - input_dev->keycodemax = 0x1a; - input_dev->keycode = rc_keys; - - for (i = 0; i < ARRAY_SIZE(rc_keys); i++) - set_bit(rc_keys[i], input_dev->keybit); - - err = input_register_device(input_dev); - if (err) { - input_free_device(input_dev); - return err; - } - - dec->rc_input_dev = input_dev; - if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) - printk("%s: usb_submit_urb failed\n",__func__); - /* enable irq pipe */ - ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); - - return 0; -} - -static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) -{ - dprintk("%s\n", __func__); - - dec->v_pes[0] = 0x00; - dec->v_pes[1] = 0x00; - dec->v_pes[2] = 0x01; - dec->v_pes[3] = 0xe0; -} - -static int ttusb_dec_init_usb(struct ttusb_dec *dec) -{ - dprintk("%s\n", __func__); - - mutex_init(&dec->usb_mutex); - mutex_init(&dec->iso_mutex); - - dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); - dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); - dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE); - dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE); - dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE); - - if(enable_rc) { - dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL); - if(!dec->irq_urb) { - return -ENOMEM; - } - dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE, - GFP_ATOMIC, &dec->irq_dma_handle); - if(!dec->irq_buffer) { - usb_free_urb(dec->irq_urb); - return -ENOMEM; - } - usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe, - dec->irq_buffer, IRQ_PACKET_SIZE, - ttusb_dec_handle_irq, dec, 1); - dec->irq_urb->transfer_dma = dec->irq_dma_handle; - dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - } - - return ttusb_dec_alloc_iso_urbs(dec); -} - -static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) -{ - int i, j, actual_len, result, size, trans_count; - u8 b0[] = { 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x61, 0x00 }; - u8 b1[] = { 0x61 }; - u8 *b; - char idstring[21]; - const u8 *firmware = NULL; - size_t firmware_size = 0; - u16 firmware_csum = 0; - __be16 firmware_csum_ns; - __be32 firmware_size_nl; - u32 crc32_csum, crc32_check; - __be32 tmp; - const struct firmware *fw_entry = NULL; - - dprintk("%s\n", __func__); - - if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) { - printk(KERN_ERR "%s: Firmware (%s) unavailable.\n", - __func__, dec->firmware_name); - return 1; - } - - firmware = fw_entry->data; - firmware_size = fw_entry->size; - - if (firmware_size < 60) { - printk("%s: firmware size too small for DSP code (%zu < 60).\n", - __func__, firmware_size); - release_firmware(fw_entry); - return -1; - } - - /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored - at offset 56 of file, so use it to check if the firmware file is - valid. */ - crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; - memcpy(&tmp, &firmware[56], 4); - crc32_check = ntohl(tmp); - if (crc32_csum != crc32_check) { - printk("%s: crc32 check of DSP code failed (calculated " - "0x%08x != 0x%08x in file), file invalid.\n", - __func__, crc32_csum, crc32_check); - release_firmware(fw_entry); - return -1; - } - memcpy(idstring, &firmware[36], 20); - idstring[20] = '\0'; - printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); - - firmware_size_nl = htonl(firmware_size); - memcpy(b0, &firmware_size_nl, 4); - firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0; - firmware_csum_ns = htons(firmware_csum); - memcpy(&b0[6], &firmware_csum_ns, 2); - - result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); - - if (result) { - release_firmware(fw_entry); - return result; - } - - trans_count = 0; - j = 0; - - b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); - if (b == NULL) { - release_firmware(fw_entry); - return -ENOMEM; - } - - for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { - size = firmware_size - i; - if (size > COMMAND_PACKET_SIZE) - size = COMMAND_PACKET_SIZE; - - b[j + 0] = 0xaa; - b[j + 1] = trans_count++; - b[j + 2] = 0xf0; - b[j + 3] = size; - memcpy(&b[j + 4], &firmware[i], size); - - j += COMMAND_PACKET_SIZE + 4; - - if (j >= ARM_PACKET_SIZE) { - result = usb_bulk_msg(dec->udev, dec->command_pipe, b, - ARM_PACKET_SIZE, &actual_len, - 100); - j = 0; - } else if (size < COMMAND_PACKET_SIZE) { - result = usb_bulk_msg(dec->udev, dec->command_pipe, b, - j - COMMAND_PACKET_SIZE + size, - &actual_len, 100); - } - } - - result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); - - release_firmware(fw_entry); - kfree(b); - - return result; -} - -static int ttusb_dec_init_stb(struct ttusb_dec *dec) -{ - int result; - unsigned int mode = 0, model = 0, version = 0; - - dprintk("%s\n", __func__); - - result = ttusb_dec_get_stb_state(dec, &mode, &model, &version); - - if (!result) { - if (!mode) { - if (version == 0xABCDEFAB) - printk(KERN_INFO "ttusb_dec: no version " - "info in Firmware\n"); - else - printk(KERN_INFO "ttusb_dec: Firmware " - "%x.%02x%c%c\n", - version >> 24, (version >> 16) & 0xff, - (version >> 8) & 0xff, version & 0xff); - - result = ttusb_dec_boot_dsp(dec); - if (result) - return result; - else - return 1; - } else { - /* We can't trust the USB IDs that some firmwares - give the box */ - switch (model) { - case 0x00070001: - case 0x00070008: - case 0x0007000c: - ttusb_dec_set_model(dec, TTUSB_DEC3000S); - break; - case 0x00070009: - case 0x00070013: - ttusb_dec_set_model(dec, TTUSB_DEC2000T); - break; - case 0x00070011: - ttusb_dec_set_model(dec, TTUSB_DEC2540T); - break; - default: - printk(KERN_ERR "%s: unknown model returned " - "by firmware (%08x) - please report\n", - __func__, model); - return -1; - break; - } - - if (version >= 0x01770000) - dec->can_playback = 1; - - return 0; - } - } - else - return result; -} - -static int ttusb_dec_init_dvb(struct ttusb_dec *dec) -{ - int result; - - dprintk("%s\n", __func__); - - if ((result = dvb_register_adapter(&dec->adapter, - dec->model_name, THIS_MODULE, - &dec->udev->dev, - adapter_nr)) < 0) { - printk("%s: dvb_register_adapter failed: error %d\n", - __func__, result); - - return result; - } - - dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - - dec->demux.priv = (void *)dec; - dec->demux.filternum = 31; - dec->demux.feednum = 31; - dec->demux.start_feed = ttusb_dec_start_feed; - dec->demux.stop_feed = ttusb_dec_stop_feed; - dec->demux.write_to_decoder = NULL; - - if ((result = dvb_dmx_init(&dec->demux)) < 0) { - printk("%s: dvb_dmx_init failed: error %d\n", __func__, - result); - - dvb_unregister_adapter(&dec->adapter); - - return result; - } - - dec->dmxdev.filternum = 32; - dec->dmxdev.demux = &dec->demux.dmx; - dec->dmxdev.capabilities = 0; - - if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) { - printk("%s: dvb_dmxdev_init failed: error %d\n", - __func__, result); - - dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(&dec->adapter); - - return result; - } - - dec->frontend.source = DMX_FRONTEND_0; - - if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx, - &dec->frontend)) < 0) { - printk("%s: dvb_dmx_init failed: error %d\n", __func__, - result); - - dvb_dmxdev_release(&dec->dmxdev); - dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(&dec->adapter); - - return result; - } - - if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx, - &dec->frontend)) < 0) { - printk("%s: dvb_dmx_init failed: error %d\n", __func__, - result); - - dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); - dvb_dmxdev_release(&dec->dmxdev); - dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(&dec->adapter); - - return result; - } - - dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx); - - return 0; -} - -static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) -{ - dprintk("%s\n", __func__); - - dvb_net_release(&dec->dvb_net); - dec->demux.dmx.close(&dec->demux.dmx); - dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); - dvb_dmxdev_release(&dec->dmxdev); - dvb_dmx_release(&dec->demux); - if (dec->fe) { - dvb_unregister_frontend(dec->fe); - if (dec->fe->ops.release) - dec->fe->ops.release(dec->fe); - } - dvb_unregister_adapter(&dec->adapter); -} - -static void ttusb_dec_exit_rc(struct ttusb_dec *dec) -{ - - dprintk("%s\n", __func__); - /* we have to check whether the irq URB is already submitted. - * As the irq is submitted after the interface is changed, - * this is the best method i figured out. - * Any others?*/ - if (dec->interface == TTUSB_DEC_INTERFACE_IN) - usb_kill_urb(dec->irq_urb); - - usb_free_urb(dec->irq_urb); - - usb_free_coherent(dec->udev,IRQ_PACKET_SIZE, - dec->irq_buffer, dec->irq_dma_handle); - - if (dec->rc_input_dev) { - input_unregister_device(dec->rc_input_dev); - dec->rc_input_dev = NULL; - } -} - - -static void ttusb_dec_exit_usb(struct ttusb_dec *dec) -{ - int i; - - dprintk("%s\n", __func__); - - dec->iso_stream_count = 0; - - for (i = 0; i < ISO_BUF_COUNT; i++) - usb_kill_urb(dec->iso_urb[i]); - - ttusb_dec_free_iso_urbs(dec); -} - -static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) -{ - struct list_head *item; - struct urb_frame *frame; - - tasklet_kill(&dec->urb_tasklet); - - while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { - frame = list_entry(item, struct urb_frame, urb_frame_list); - list_del(&frame->urb_frame_list); - kfree(frame); - } -} - -static void ttusb_dec_init_filters(struct ttusb_dec *dec) -{ - INIT_LIST_HEAD(&dec->filter_info_list); - spin_lock_init(&dec->filter_info_list_lock); -} - -static void ttusb_dec_exit_filters(struct ttusb_dec *dec) -{ - struct list_head *item; - struct filter_info *finfo; - - while ((item = dec->filter_info_list.next) != &dec->filter_info_list) { - finfo = list_entry(item, struct filter_info, filter_info_list); - list_del(&finfo->filter_info_list); - kfree(finfo); - } -} - -static int fe_send_command(struct dvb_frontend* fe, const u8 command, - int param_length, const u8 params[], - int *result_length, u8 cmd_result[]) -{ - struct ttusb_dec* dec = fe->dvb->priv; - return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); -} - -static struct ttusbdecfe_config fe_config = { - .send_command = fe_send_command -}; - -static int ttusb_dec_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev; - struct ttusb_dec *dec; - - dprintk("%s\n", __func__); - - udev = interface_to_usbdev(intf); - - if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { - printk("%s: couldn't allocate memory.\n", __func__); - return -ENOMEM; - } - - usb_set_intfdata(intf, (void *)dec); - - switch (id->idProduct) { - case 0x1006: - ttusb_dec_set_model(dec, TTUSB_DEC3000S); - break; - - case 0x1008: - ttusb_dec_set_model(dec, TTUSB_DEC2000T); - break; - - case 0x1009: - ttusb_dec_set_model(dec, TTUSB_DEC2540T); - break; - } - - dec->udev = udev; - - if (ttusb_dec_init_usb(dec)) - return 0; - if (ttusb_dec_init_stb(dec)) { - ttusb_dec_exit_usb(dec); - return 0; - } - ttusb_dec_init_dvb(dec); - - dec->adapter.priv = dec; - switch (id->idProduct) { - case 0x1006: - dec->fe = ttusbdecfe_dvbs_attach(&fe_config); - break; - - case 0x1008: - case 0x1009: - dec->fe = ttusbdecfe_dvbt_attach(&fe_config); - break; - } - - if (dec->fe == NULL) { - printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n", - le16_to_cpu(dec->udev->descriptor.idVendor), - le16_to_cpu(dec->udev->descriptor.idProduct)); - } else { - if (dvb_register_frontend(&dec->adapter, dec->fe)) { - printk("budget-ci: Frontend registration failed!\n"); - if (dec->fe->ops.release) - dec->fe->ops.release(dec->fe); - dec->fe = NULL; - } - } - - ttusb_dec_init_v_pes(dec); - ttusb_dec_init_filters(dec); - ttusb_dec_init_tasklet(dec); - - dec->active = 1; - - ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); - - if (enable_rc) - ttusb_init_rc(dec); - - return 0; -} - -static void ttusb_dec_disconnect(struct usb_interface *intf) -{ - struct ttusb_dec *dec = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - - dprintk("%s\n", __func__); - - if (dec->active) { - ttusb_dec_exit_tasklet(dec); - ttusb_dec_exit_filters(dec); - if(enable_rc) - ttusb_dec_exit_rc(dec); - ttusb_dec_exit_usb(dec); - ttusb_dec_exit_dvb(dec); - } - - kfree(dec); -} - -static void ttusb_dec_set_model(struct ttusb_dec *dec, - enum ttusb_dec_model model) -{ - dec->model = model; - - switch (model) { - case TTUSB_DEC2000T: - dec->model_name = "DEC2000-t"; - dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; - break; - - case TTUSB_DEC2540T: - dec->model_name = "DEC2540-t"; - dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; - break; - - case TTUSB_DEC3000S: - dec->model_name = "DEC3000-s"; - dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; - break; - } -} - -static struct usb_device_id ttusb_dec_table[] = { - {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */ - /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */ - {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */ - {USB_DEVICE(0x0b48, 0x1009)}, /* DEC2540-t */ - {} -}; - -static struct usb_driver ttusb_dec_driver = { - .name = "ttusb-dec", - .probe = ttusb_dec_probe, - .disconnect = ttusb_dec_disconnect, - .id_table = ttusb_dec_table, -}; - -static int __init ttusb_dec_init(void) -{ - int result; - - if ((result = usb_register(&ttusb_dec_driver)) < 0) { - printk("%s: initialisation failed: error %d.\n", __func__, - result); - return result; - } - - return 0; -} - -static void __exit ttusb_dec_exit(void) -{ - usb_deregister(&ttusb_dec_driver); -} - -module_init(ttusb_dec_init); -module_exit(ttusb_dec_exit); - -MODULE_AUTHOR("Alex Woods "); -MODULE_DESCRIPTION(DRIVER_NAME); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, ttusb_dec_table); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,298 +0,0 @@ -/* - * TTUSB DEC Frontend Driver - * - * Copyright (C) 2003-2004 Alex Woods - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include "dvb_frontend.h" -#include "ttusbdecfe.h" - - -#define LOF_HI 10600000 -#define LOF_LO 9750000 - -struct ttusbdecfe_state { - - /* configuration settings */ - const struct ttusbdecfe_config* config; - - struct dvb_frontend frontend; - - u8 hi_band; - u8 voltage; -}; - - -static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - return 0; -} - - -static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - struct ttusbdecfe_state* state = fe->demodulator_priv; - u8 b[] = { 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - u8 result[4]; - int len, ret; - - *status=0; - - ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result); - if(ret) - return ret; - - if(len != 4) { - printk(KERN_ERR "%s: unexpected reply\n", __func__); - return -EIO; - } - - switch(result[3]) { - case 1: /* not tuned yet */ - case 2: /* no signal/no lock*/ - break; - case 3: /* signal found and locked*/ - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - break; - case 4: - *status = FE_TIMEDOUT; - break; - default: - pr_info("%s: returned unknown value: %d\n", - __func__, result[3]); - return -EIO; - } - - return 0; -} - -static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - u8 b[] = { 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff }; - - __be32 freq = htonl(p->frequency / 1000); - memcpy(&b[4], &freq, sizeof (u32)); - state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); - - return 0; -} - -static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, - struct dvb_frontend_tune_settings* fesettings) -{ - fesettings->min_delay_ms = 1500; - /* Drift compensation makes no sense for DVB-T */ - fesettings->step_size = 0; - fesettings->max_drift = 0; - return 0; -} - -static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - - u8 b[] = { 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - __be32 freq; - __be32 sym_rate; - __be32 band; - __be32 lnb_voltage; - - freq = htonl(p->frequency + - (state->hi_band ? LOF_HI : LOF_LO)); - memcpy(&b[4], &freq, sizeof(u32)); - sym_rate = htonl(p->u.qam.symbol_rate); - memcpy(&b[12], &sym_rate, sizeof(u32)); - band = htonl(state->hi_band ? LOF_HI : LOF_LO); - memcpy(&b[24], &band, sizeof(u32)); - lnb_voltage = htonl(state->voltage); - memcpy(&b[28], &lnb_voltage, sizeof(u32)); - - state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); - - return 0; -} - -static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - u8 b[] = { 0x00, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; - - memcpy(&b[4], cmd->msg, cmd->msg_len); - - state->config->send_command(fe, 0x72, - sizeof(b) - (6 - cmd->msg_len), b, - NULL, NULL); - - return 0; -} - - -static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - - state->hi_band = (SEC_TONE_ON == tone); - - return 0; -} - - -static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - - switch (voltage) { - case SEC_VOLTAGE_13: - state->voltage = 13; - break; - case SEC_VOLTAGE_18: - state->voltage = 18; - break; - default: - return -EINVAL; - } - - return 0; -} - -static void ttusbdecfe_release(struct dvb_frontend* fe) -{ - struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops ttusbdecfe_dvbt_ops; - -struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config) -{ - struct ttusbdecfe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - /* setup the state */ - state->config = config; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; -} - -static struct dvb_frontend_ops ttusbdecfe_dvbs_ops; - -struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config) -{ - struct ttusbdecfe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - /* setup the state */ - state->config = config; - state->voltage = 0; - state->hi_band = 0; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; -} - -static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { - - .info = { - .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", - .type = FE_OFDM, - .frequency_min = 51000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = ttusbdecfe_release, - - .set_frontend = ttusbdecfe_dvbt_set_frontend, - - .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, - - .read_status = ttusbdecfe_dvbt_read_status, -}; - -static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { - - .info = { - .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, - .symbol_rate_min = 1000000, /* guessed */ - .symbol_rate_max = 45000000, /* guessed */ - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK - }, - - .release = ttusbdecfe_release, - - .set_frontend = ttusbdecfe_dvbs_set_frontend, - - .read_status = ttusbdecfe_dvbs_read_status, - - .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, - .set_voltage = ttusbdecfe_dvbs_set_voltage, - .set_tone = ttusbdecfe_dvbs_set_tone, -}; - -MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver"); -MODULE_AUTHOR("Alex Woods/Andrew de Quincey"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(ttusbdecfe_dvbt_attach); -EXPORT_SYMBOL(ttusbdecfe_dvbs_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* - * TTUSB DEC Driver - * - * Copyright (C) 2003-2004 Alex Woods - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef TTUSBDECFE_H -#define TTUSBDECFE_H - -#include - -struct ttusbdecfe_config -{ - int (*send_command)(struct dvb_frontend* fe, const u8 command, - int param_length, const u8 params[], - int *result_length, u8 cmd_result[]); -}; - -extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config); - -extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config); - -#endif // TTUSBDECFE_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -# -# Multimedia device configuration -# - -menuconfig MEDIA_SUPPORT - tristate "Multimedia support" - depends on HAS_IOMEM - help - If you want to use Video for Linux, DVB for Linux, or DAB adapters, - enable this option and other options below. - -if MEDIA_SUPPORT - -comment "Multimedia core support" - -# -# Media controller -# - -config MEDIA_CONTROLLER - bool "Media Controller API (EXPERIMENTAL)" - depends on EXPERIMENTAL - ---help--- - Enable the media controller API used to query media devices internal - topology and configure it dynamically. - - This API is mostly used by camera interfaces in embedded platforms. - -# -# V4L core and enabled API's -# - -config VIDEO_DEV - tristate "Video For Linux" - ---help--- - V4L core support for video capture and overlay devices, webcams and - AM/FM radio cards. - - This kernel includes support for the new Video for Linux Two API, - (V4L2). - - Additional info and docs are available on the web at - - - Documentation for V4L2 is also available on the web at - . - - To compile this driver as a module, choose M here: the - module will be called videodev. - -config VIDEO_V4L2_COMMON - tristate - depends on (I2C || I2C=n) && VIDEO_DEV - default (I2C || I2C=n) && VIDEO_DEV - -config VIDEO_V4L2_SUBDEV_API - bool "V4L2 sub-device userspace API (EXPERIMENTAL)" - depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL - ---help--- - Enables the V4L2 sub-device pad-level userspace API used to configure - video format, size and frame rate between hardware blocks. - - This API is mostly used by camera interfaces in embedded platforms. - -# -# DVB Core -# - -config DVB_CORE - tristate "DVB for Linux" - depends on NET && INET - select CRC32 - help - DVB core utility functions for device handling, software fallbacks etc. - - Enable this if you own a DVB/ATSC adapter and want to use it or if - you compile Linux for a digital SetTopBox. - - Say Y when you have a DVB or an ATSC card and want to use it. - - API specs and user tools are available from . - - Please report problems regarding this support to the LinuxDVB - mailing list. - - If unsure say N. - -config VIDEO_MEDIA - tristate - default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV) - -comment "Multimedia drivers" - -source "drivers/media/common/Kconfig" -source "drivers/media/rc/Kconfig" - -# -# Tuner drivers for DVB and V4L -# - -source "drivers/media/common/tuners/Kconfig" - -# -# Video/Radio/Hybrid adapters -# - -source "drivers/media/video/Kconfig" - -source "drivers/media/radio/Kconfig" - -# -# DVB adapters -# - -source "drivers/media/dvb/Kconfig" - -endif # MEDIA_SUPPORT diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -# -# Makefile for the kernel multimedia device drivers. -# - -media-objs := media-device.o media-devnode.o media-entity.o - -ifeq ($(CONFIG_MEDIA_CONTROLLER),y) - obj-$(CONFIG_MEDIA_SUPPORT) += media.o -endif - -obj-y += common/ rc/ video/ - -obj-$(CONFIG_VIDEO_DEV) += radio/ -obj-$(CONFIG_DVB_CORE) += dvb/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-device.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-device.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-device.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-device.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,382 +0,0 @@ -/* - * Media device - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 -#include -#include - -#include -#include -#include - -/* ----------------------------------------------------------------------------- - * Userspace API - */ - -static int media_device_open(struct file *filp) -{ - return 0; -} - -static int media_device_close(struct file *filp) -{ - return 0; -} - -static int media_device_get_info(struct media_device *dev, - struct media_device_info __user *__info) -{ - struct media_device_info info; - - memset(&info, 0, sizeof(info)); - - strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver)); - strlcpy(info.model, dev->model, sizeof(info.model)); - strlcpy(info.serial, dev->serial, sizeof(info.serial)); - strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info)); - - info.media_version = MEDIA_API_VERSION; - info.hw_revision = dev->hw_revision; - info.driver_version = dev->driver_version; - - return copy_to_user(__info, &info, sizeof(*__info)); -} - -static struct media_entity *find_entity(struct media_device *mdev, u32 id) -{ - struct media_entity *entity; - int next = id & MEDIA_ENT_ID_FLAG_NEXT; - - id &= ~MEDIA_ENT_ID_FLAG_NEXT; - - spin_lock(&mdev->lock); - - media_device_for_each_entity(entity, mdev) { - if ((entity->id == id && !next) || - (entity->id > id && next)) { - spin_unlock(&mdev->lock); - return entity; - } - } - - spin_unlock(&mdev->lock); - - return NULL; -} - -static long media_device_enum_entities(struct media_device *mdev, - struct media_entity_desc __user *uent) -{ - struct media_entity *ent; - struct media_entity_desc u_ent; - - if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id))) - return -EFAULT; - - ent = find_entity(mdev, u_ent.id); - - if (ent == NULL) - return -EINVAL; - - u_ent.id = ent->id; - u_ent.name[0] = '\0'; - if (ent->name) - strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); - u_ent.type = ent->type; - u_ent.revision = ent->revision; - u_ent.flags = ent->flags; - u_ent.group_id = ent->group_id; - u_ent.pads = ent->num_pads; - u_ent.links = ent->num_links - ent->num_backlinks; - u_ent.v4l.major = ent->v4l.major; - u_ent.v4l.minor = ent->v4l.minor; - if (copy_to_user(uent, &u_ent, sizeof(u_ent))) - return -EFAULT; - return 0; -} - -static void media_device_kpad_to_upad(const struct media_pad *kpad, - struct media_pad_desc *upad) -{ - upad->entity = kpad->entity->id; - upad->index = kpad->index; - upad->flags = kpad->flags; -} - -static long media_device_enum_links(struct media_device *mdev, - struct media_links_enum __user *ulinks) -{ - struct media_entity *entity; - struct media_links_enum links; - - if (copy_from_user(&links, ulinks, sizeof(links))) - return -EFAULT; - - entity = find_entity(mdev, links.entity); - if (entity == NULL) - return -EINVAL; - - if (links.pads) { - unsigned int p; - - for (p = 0; p < entity->num_pads; p++) { - struct media_pad_desc pad; - media_device_kpad_to_upad(&entity->pads[p], &pad); - if (copy_to_user(&links.pads[p], &pad, sizeof(pad))) - return -EFAULT; - } - } - - if (links.links) { - struct media_link_desc __user *ulink; - unsigned int l; - - for (l = 0, ulink = links.links; l < entity->num_links; l++) { - struct media_link_desc link; - - /* Ignore backlinks. */ - if (entity->links[l].source->entity != entity) - continue; - - media_device_kpad_to_upad(entity->links[l].source, - &link.source); - media_device_kpad_to_upad(entity->links[l].sink, - &link.sink); - link.flags = entity->links[l].flags; - if (copy_to_user(ulink, &link, sizeof(*ulink))) - return -EFAULT; - ulink++; - } - } - if (copy_to_user(ulinks, &links, sizeof(*ulinks))) - return -EFAULT; - return 0; -} - -static long media_device_setup_link(struct media_device *mdev, - struct media_link_desc __user *_ulink) -{ - struct media_link *link = NULL; - struct media_link_desc ulink; - struct media_entity *source; - struct media_entity *sink; - int ret; - - if (copy_from_user(&ulink, _ulink, sizeof(ulink))) - return -EFAULT; - - /* Find the source and sink entities and link. - */ - source = find_entity(mdev, ulink.source.entity); - sink = find_entity(mdev, ulink.sink.entity); - - if (source == NULL || sink == NULL) - return -EINVAL; - - if (ulink.source.index >= source->num_pads || - ulink.sink.index >= sink->num_pads) - return -EINVAL; - - link = media_entity_find_link(&source->pads[ulink.source.index], - &sink->pads[ulink.sink.index]); - if (link == NULL) - return -EINVAL; - - /* Setup the link on both entities. */ - ret = __media_entity_setup_link(link, ulink.flags); - - if (copy_to_user(_ulink, &ulink, sizeof(ulink))) - return -EFAULT; - - return ret; -} - -static long media_device_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *dev = to_media_device(devnode); - long ret; - - switch (cmd) { - case MEDIA_IOC_DEVICE_INFO: - ret = media_device_get_info(dev, - (struct media_device_info __user *)arg); - break; - - case MEDIA_IOC_ENUM_ENTITIES: - ret = media_device_enum_entities(dev, - (struct media_entity_desc __user *)arg); - break; - - case MEDIA_IOC_ENUM_LINKS: - mutex_lock(&dev->graph_mutex); - ret = media_device_enum_links(dev, - (struct media_links_enum __user *)arg); - mutex_unlock(&dev->graph_mutex); - break; - - case MEDIA_IOC_SETUP_LINK: - mutex_lock(&dev->graph_mutex); - ret = media_device_setup_link(dev, - (struct media_link_desc __user *)arg); - mutex_unlock(&dev->graph_mutex); - break; - - default: - ret = -ENOIOCTLCMD; - } - - return ret; -} - -static const struct media_file_operations media_device_fops = { - .owner = THIS_MODULE, - .open = media_device_open, - .ioctl = media_device_ioctl, - .release = media_device_close, -}; - -/* ----------------------------------------------------------------------------- - * sysfs - */ - -static ssize_t show_model(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct media_device *mdev = to_media_device(to_media_devnode(cd)); - - return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); -} - -static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); - -/* ----------------------------------------------------------------------------- - * Registration/unregistration - */ - -static void media_device_release(struct media_devnode *mdev) -{ -} - -/** - * media_device_register - register a media device - * @mdev: The media device - * - * The caller is responsible for initializing the media device before - * registration. The following fields must be set: - * - * - dev must point to the parent device - * - model must be filled with the device model name - */ -int __must_check media_device_register(struct media_device *mdev) -{ - int ret; - - if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0)) - return -EINVAL; - - mdev->entity_id = 1; - INIT_LIST_HEAD(&mdev->entities); - spin_lock_init(&mdev->lock); - mutex_init(&mdev->graph_mutex); - - /* Register the device node. */ - mdev->devnode.fops = &media_device_fops; - mdev->devnode.parent = mdev->dev; - mdev->devnode.release = media_device_release; - ret = media_devnode_register(&mdev->devnode); - if (ret < 0) - return ret; - - ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); - if (ret < 0) { - media_devnode_unregister(&mdev->devnode); - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(media_device_register); - -/** - * media_device_unregister - unregister a media device - * @mdev: The media device - * - */ -void media_device_unregister(struct media_device *mdev) -{ - struct media_entity *entity; - struct media_entity *next; - - list_for_each_entry_safe(entity, next, &mdev->entities, list) - media_device_unregister_entity(entity); - - device_remove_file(&mdev->devnode.dev, &dev_attr_model); - media_devnode_unregister(&mdev->devnode); -} -EXPORT_SYMBOL_GPL(media_device_unregister); - -/** - * media_device_register_entity - Register an entity with a media device - * @mdev: The media device - * @entity: The entity - */ -int __must_check media_device_register_entity(struct media_device *mdev, - struct media_entity *entity) -{ - /* Warn if we apparently re-register an entity */ - WARN_ON(entity->parent != NULL); - entity->parent = mdev; - - spin_lock(&mdev->lock); - if (entity->id == 0) - entity->id = mdev->entity_id++; - else - mdev->entity_id = max(entity->id + 1, mdev->entity_id); - list_add_tail(&entity->list, &mdev->entities); - spin_unlock(&mdev->lock); - - return 0; -} -EXPORT_SYMBOL_GPL(media_device_register_entity); - -/** - * media_device_unregister_entity - Unregister an entity - * @entity: The entity - * - * If the entity has never been registered this function will return - * immediately. - */ -void media_device_unregister_entity(struct media_entity *entity) -{ - struct media_device *mdev = entity->parent; - - if (mdev == NULL) - return; - - spin_lock(&mdev->lock); - list_del(&entity->list); - spin_unlock(&mdev->lock); - entity->parent = NULL; -} -EXPORT_SYMBOL_GPL(media_device_unregister_entity); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-devnode.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-devnode.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-devnode.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-devnode.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,320 +0,0 @@ -/* - * Media device node - * - * Copyright (C) 2010 Nokia Corporation - * - * Based on drivers/media/video/v4l2_dev.c code authored by - * Mauro Carvalho Chehab (version 2) - * Alan Cox, (version 1) - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - * - * -- - * - * Generic media device node infrastructure to register and unregister - * character devices using a dynamic major number and proper reference - * counting. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MEDIA_NUM_DEVICES 256 -#define MEDIA_NAME "media" - -static dev_t media_dev_t; - -/* - * Active devices - */ -static DEFINE_MUTEX(media_devnode_lock); -static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); - -/* Called when the last user of the media device exits. */ -static void media_devnode_release(struct device *cd) -{ - struct media_devnode *mdev = to_media_devnode(cd); - - mutex_lock(&media_devnode_lock); - - /* Delete the cdev on this minor as well */ - cdev_del(&mdev->cdev); - - /* Mark device node number as free */ - clear_bit(mdev->minor, media_devnode_nums); - - mutex_unlock(&media_devnode_lock); - - /* Release media_devnode and perform other cleanups as needed. */ - if (mdev->release) - mdev->release(mdev); -} - -static struct bus_type media_bus_type = { - .name = MEDIA_NAME, -}; - -static ssize_t media_read(struct file *filp, char __user *buf, - size_t sz, loff_t *off) -{ - struct media_devnode *mdev = media_devnode_data(filp); - - if (!mdev->fops->read) - return -EINVAL; - if (!media_devnode_is_registered(mdev)) - return -EIO; - return mdev->fops->read(filp, buf, sz, off); -} - -static ssize_t media_write(struct file *filp, const char __user *buf, - size_t sz, loff_t *off) -{ - struct media_devnode *mdev = media_devnode_data(filp); - - if (!mdev->fops->write) - return -EINVAL; - if (!media_devnode_is_registered(mdev)) - return -EIO; - return mdev->fops->write(filp, buf, sz, off); -} - -static unsigned int media_poll(struct file *filp, - struct poll_table_struct *poll) -{ - struct media_devnode *mdev = media_devnode_data(filp); - - if (!media_devnode_is_registered(mdev)) - return POLLERR | POLLHUP; - if (!mdev->fops->poll) - return DEFAULT_POLLMASK; - return mdev->fops->poll(filp, poll); -} - -static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct media_devnode *mdev = media_devnode_data(filp); - - if (!mdev->fops->ioctl) - return -ENOTTY; - - if (!media_devnode_is_registered(mdev)) - return -EIO; - - return mdev->fops->ioctl(filp, cmd, arg); -} - -/* Override for the open function */ -static int media_open(struct inode *inode, struct file *filp) -{ - struct media_devnode *mdev; - int ret; - - /* Check if the media device is available. This needs to be done with - * the media_devnode_lock held to prevent an open/unregister race: - * without the lock, the device could be unregistered and freed between - * the media_devnode_is_registered() and get_device() calls, leading to - * a crash. - */ - mutex_lock(&media_devnode_lock); - mdev = container_of(inode->i_cdev, struct media_devnode, cdev); - /* return ENXIO if the media device has been removed - already or if it is not registered anymore. */ - if (!media_devnode_is_registered(mdev)) { - mutex_unlock(&media_devnode_lock); - return -ENXIO; - } - /* and increase the device refcount */ - get_device(&mdev->dev); - mutex_unlock(&media_devnode_lock); - - filp->private_data = mdev; - - if (mdev->fops->open) { - ret = mdev->fops->open(filp); - if (ret) { - put_device(&mdev->dev); - return ret; - } - } - - return 0; -} - -/* Override for the release function */ -static int media_release(struct inode *inode, struct file *filp) -{ - struct media_devnode *mdev = media_devnode_data(filp); - int ret = 0; - - if (mdev->fops->release) - mdev->fops->release(filp); - - /* decrease the refcount unconditionally since the release() - return value is ignored. */ - put_device(&mdev->dev); - filp->private_data = NULL; - return ret; -} - -static const struct file_operations media_devnode_fops = { - .owner = THIS_MODULE, - .read = media_read, - .write = media_write, - .open = media_open, - .unlocked_ioctl = media_ioctl, - .release = media_release, - .poll = media_poll, - .llseek = no_llseek, -}; - -/** - * media_devnode_register - register a media device node - * @mdev: media device node structure we want to register - * - * The registration code assigns minor numbers and registers the new device node - * with the kernel. An error is returned if no free minor number can be found, - * or if the registration of the device node fails. - * - * Zero is returned on success. - * - * Note that if the media_devnode_register call fails, the release() callback of - * the media_devnode structure is *not* called, so the caller is responsible for - * freeing any data. - */ -int __must_check media_devnode_register(struct media_devnode *mdev) -{ - int minor; - int ret; - - /* Part 1: Find a free minor number */ - mutex_lock(&media_devnode_lock); - minor = find_next_zero_bit(media_devnode_nums, 0, MEDIA_NUM_DEVICES); - if (minor == MEDIA_NUM_DEVICES) { - mutex_unlock(&media_devnode_lock); - printk(KERN_ERR "could not get a free minor\n"); - return -ENFILE; - } - - set_bit(mdev->minor, media_devnode_nums); - mutex_unlock(&media_devnode_lock); - - mdev->minor = minor; - - /* Part 2: Initialize and register the character device */ - cdev_init(&mdev->cdev, &media_devnode_fops); - mdev->cdev.owner = mdev->fops->owner; - - ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1); - if (ret < 0) { - printk(KERN_ERR "%s: cdev_add failed\n", __func__); - goto error; - } - - /* Part 3: Register the media device */ - mdev->dev.bus = &media_bus_type; - mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor); - mdev->dev.release = media_devnode_release; - if (mdev->parent) - mdev->dev.parent = mdev->parent; - dev_set_name(&mdev->dev, "media%d", mdev->minor); - ret = device_register(&mdev->dev); - if (ret < 0) { - printk(KERN_ERR "%s: device_register failed\n", __func__); - goto error; - } - - /* Part 4: Activate this minor. The char device can now be used. */ - set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); - - return 0; - -error: - cdev_del(&mdev->cdev); - clear_bit(mdev->minor, media_devnode_nums); - return ret; -} - -/** - * media_devnode_unregister - unregister a media device node - * @mdev: the device node to unregister - * - * This unregisters the passed device. Future open calls will be met with - * errors. - * - * This function can safely be called if the device node has never been - * registered or has already been unregistered. - */ -void media_devnode_unregister(struct media_devnode *mdev) -{ - /* Check if mdev was ever registered at all */ - if (!media_devnode_is_registered(mdev)) - return; - - mutex_lock(&media_devnode_lock); - clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); - mutex_unlock(&media_devnode_lock); - device_unregister(&mdev->dev); -} - -/* - * Initialise media for linux - */ -static int __init media_devnode_init(void) -{ - int ret; - - printk(KERN_INFO "Linux media interface: v0.10\n"); - ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES, - MEDIA_NAME); - if (ret < 0) { - printk(KERN_WARNING "media: unable to allocate major\n"); - return ret; - } - - ret = bus_register(&media_bus_type); - if (ret < 0) { - unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); - printk(KERN_WARNING "media: bus_register failed\n"); - return -EIO; - } - - return 0; -} - -static void __exit media_devnode_exit(void) -{ - bus_unregister(&media_bus_type); - unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); -} - -module_init(media_devnode_init) -module_exit(media_devnode_exit) - -MODULE_AUTHOR("Laurent Pinchart "); -MODULE_DESCRIPTION("Device node registration for media drivers"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-entity.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-entity.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-entity.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/media-entity.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,536 +0,0 @@ -/* - * Media entity - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include - -/** - * media_entity_init - Initialize a media entity - * - * @num_pads: Total number of sink and source pads. - * @extra_links: Initial estimate of the number of extra links. - * @pads: Array of 'num_pads' pads. - * - * The total number of pads is an intrinsic property of entities known by the - * entity driver, while the total number of links depends on hardware design - * and is an extrinsic property unknown to the entity driver. However, in most - * use cases the entity driver can guess the number of links which can safely - * be assumed to be equal to or larger than the number of pads. - * - * For those reasons the links array can be preallocated based on the entity - * driver guess and will be reallocated later if extra links need to be - * created. - * - * This function allocates a links array with enough space to hold at least - * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will - * be set to the number of allocated elements. - * - * The pads array is managed by the entity driver and passed to - * media_entity_init() where its pointer will be stored in the entity structure. - */ -int -media_entity_init(struct media_entity *entity, u16 num_pads, - struct media_pad *pads, u16 extra_links) -{ - struct media_link *links; - unsigned int max_links = num_pads + extra_links; - unsigned int i; - - links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL); - if (links == NULL) - return -ENOMEM; - - entity->group_id = 0; - entity->max_links = max_links; - entity->num_links = 0; - entity->num_backlinks = 0; - entity->num_pads = num_pads; - entity->pads = pads; - entity->links = links; - - for (i = 0; i < num_pads; i++) { - pads[i].entity = entity; - pads[i].index = i; - } - - return 0; -} -EXPORT_SYMBOL_GPL(media_entity_init); - -void -media_entity_cleanup(struct media_entity *entity) -{ - kfree(entity->links); -} -EXPORT_SYMBOL_GPL(media_entity_cleanup); - -/* ----------------------------------------------------------------------------- - * Graph traversal - */ - -static struct media_entity * -media_entity_other(struct media_entity *entity, struct media_link *link) -{ - if (link->source->entity == entity) - return link->sink->entity; - else - return link->source->entity; -} - -/* push an entity to traversal stack */ -static void stack_push(struct media_entity_graph *graph, - struct media_entity *entity) -{ - if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) { - WARN_ON(1); - return; - } - graph->top++; - graph->stack[graph->top].link = 0; - graph->stack[graph->top].entity = entity; -} - -static struct media_entity *stack_pop(struct media_entity_graph *graph) -{ - struct media_entity *entity; - - entity = graph->stack[graph->top].entity; - graph->top--; - - return entity; -} - -#define stack_peek(en) ((en)->stack[(en)->top - 1].entity) -#define link_top(en) ((en)->stack[(en)->top].link) -#define stack_top(en) ((en)->stack[(en)->top].entity) - -/** - * media_entity_graph_walk_start - Start walking the media graph at a given entity - * @graph: Media graph structure that will be used to walk the graph - * @entity: Starting entity - * - * This function initializes the graph traversal structure to walk the entities - * graph starting at the given entity. The traversal structure must not be - * modified by the caller during graph traversal. When done the structure can - * safely be freed. - */ -void media_entity_graph_walk_start(struct media_entity_graph *graph, - struct media_entity *entity) -{ - graph->top = 0; - graph->stack[graph->top].entity = NULL; - stack_push(graph, entity); -} -EXPORT_SYMBOL_GPL(media_entity_graph_walk_start); - -/** - * media_entity_graph_walk_next - Get the next entity in the graph - * @graph: Media graph structure - * - * Perform a depth-first traversal of the given media entities graph. - * - * The graph structure must have been previously initialized with a call to - * media_entity_graph_walk_start(). - * - * Return the next entity in the graph or NULL if the whole graph have been - * traversed. - */ -struct media_entity * -media_entity_graph_walk_next(struct media_entity_graph *graph) -{ - if (stack_top(graph) == NULL) - return NULL; - - /* - * Depth first search. Push entity to stack and continue from - * top of the stack until no more entities on the level can be - * found. - */ - while (link_top(graph) < stack_top(graph)->num_links) { - struct media_entity *entity = stack_top(graph); - struct media_link *link = &entity->links[link_top(graph)]; - struct media_entity *next; - - /* The link is not enabled so we do not follow. */ - if (!(link->flags & MEDIA_LNK_FL_ENABLED)) { - link_top(graph)++; - continue; - } - - /* Get the entity in the other end of the link . */ - next = media_entity_other(entity, link); - - /* Was it the entity we came here from? */ - if (next == stack_peek(graph)) { - link_top(graph)++; - continue; - } - - /* Push the new entity to stack and start over. */ - link_top(graph)++; - stack_push(graph, next); - } - - return stack_pop(graph); -} -EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); - -/* ----------------------------------------------------------------------------- - * Pipeline management - */ - -/** - * media_entity_pipeline_start - Mark a pipeline as streaming - * @entity: Starting entity - * @pipe: Media pipeline to be assigned to all entities in the pipeline. - * - * Mark all entities connected to a given entity through enabled links, either - * directly or indirectly, as streaming. The given pipeline object is assigned to - * every entity in the pipeline and stored in the media_entity pipe field. - * - * Calls to this function can be nested, in which case the same number of - * media_entity_pipeline_stop() calls will be required to stop streaming. The - * pipeline pointer must be identical for all nested calls to - * media_entity_pipeline_start(). - */ -void media_entity_pipeline_start(struct media_entity *entity, - struct media_pipeline *pipe) -{ - struct media_device *mdev = entity->parent; - struct media_entity_graph graph; - - mutex_lock(&mdev->graph_mutex); - - media_entity_graph_walk_start(&graph, entity); - - while ((entity = media_entity_graph_walk_next(&graph))) { - entity->stream_count++; - WARN_ON(entity->pipe && entity->pipe != pipe); - entity->pipe = pipe; - } - - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_entity_pipeline_start); - -/** - * media_entity_pipeline_stop - Mark a pipeline as not streaming - * @entity: Starting entity - * - * Mark all entities connected to a given entity through enabled links, either - * directly or indirectly, as not streaming. The media_entity pipe field is - * reset to NULL. - * - * If multiple calls to media_entity_pipeline_start() have been made, the same - * number of calls to this function are required to mark the pipeline as not - * streaming. - */ -void media_entity_pipeline_stop(struct media_entity *entity) -{ - struct media_device *mdev = entity->parent; - struct media_entity_graph graph; - - mutex_lock(&mdev->graph_mutex); - - media_entity_graph_walk_start(&graph, entity); - - while ((entity = media_entity_graph_walk_next(&graph))) { - entity->stream_count--; - if (entity->stream_count == 0) - entity->pipe = NULL; - } - - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_entity_pipeline_stop); - -/* ----------------------------------------------------------------------------- - * Module use count - */ - -/* - * media_entity_get - Get a reference to the parent module - * @entity: The entity - * - * Get a reference to the parent media device module. - * - * The function will return immediately if @entity is NULL. - * - * Return a pointer to the entity on success or NULL on failure. - */ -struct media_entity *media_entity_get(struct media_entity *entity) -{ - if (entity == NULL) - return NULL; - - if (entity->parent->dev && - !try_module_get(entity->parent->dev->driver->owner)) - return NULL; - - return entity; -} -EXPORT_SYMBOL_GPL(media_entity_get); - -/* - * media_entity_put - Release the reference to the parent module - * @entity: The entity - * - * Release the reference count acquired by media_entity_get(). - * - * The function will return immediately if @entity is NULL. - */ -void media_entity_put(struct media_entity *entity) -{ - if (entity == NULL) - return; - - if (entity->parent->dev) - module_put(entity->parent->dev->driver->owner); -} -EXPORT_SYMBOL_GPL(media_entity_put); - -/* ----------------------------------------------------------------------------- - * Links management - */ - -static struct media_link *media_entity_add_link(struct media_entity *entity) -{ - if (entity->num_links >= entity->max_links) { - struct media_link *links = entity->links; - unsigned int max_links = entity->max_links + 2; - unsigned int i; - - links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL); - if (links == NULL) - return NULL; - - for (i = 0; i < entity->num_links; i++) - links[i].reverse->reverse = &links[i]; - - entity->max_links = max_links; - entity->links = links; - } - - return &entity->links[entity->num_links++]; -} - -int -media_entity_create_link(struct media_entity *source, u16 source_pad, - struct media_entity *sink, u16 sink_pad, u32 flags) -{ - struct media_link *link; - struct media_link *backlink; - - BUG_ON(source == NULL || sink == NULL); - BUG_ON(source_pad >= source->num_pads); - BUG_ON(sink_pad >= sink->num_pads); - - link = media_entity_add_link(source); - if (link == NULL) - return -ENOMEM; - - link->source = &source->pads[source_pad]; - link->sink = &sink->pads[sink_pad]; - link->flags = flags; - - /* Create the backlink. Backlinks are used to help graph traversal and - * are not reported to userspace. - */ - backlink = media_entity_add_link(sink); - if (backlink == NULL) { - source->num_links--; - return -ENOMEM; - } - - backlink->source = &source->pads[source_pad]; - backlink->sink = &sink->pads[sink_pad]; - backlink->flags = flags; - - link->reverse = backlink; - backlink->reverse = link; - - sink->num_backlinks++; - - return 0; -} -EXPORT_SYMBOL_GPL(media_entity_create_link); - -static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) -{ - const u32 mask = MEDIA_LNK_FL_ENABLED; - int ret; - - /* Notify both entities. */ - ret = media_entity_call(link->source->entity, link_setup, - link->source, link->sink, flags); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - - ret = media_entity_call(link->sink->entity, link_setup, - link->sink, link->source, flags); - if (ret < 0 && ret != -ENOIOCTLCMD) { - media_entity_call(link->source->entity, link_setup, - link->source, link->sink, link->flags); - return ret; - } - - link->flags = (link->flags & ~mask) | (flags & mask); - link->reverse->flags = link->flags; - - return 0; -} - -/** - * __media_entity_setup_link - Configure a media link - * @link: The link being configured - * @flags: Link configuration flags - * - * The bulk of link setup is handled by the two entities connected through the - * link. This function notifies both entities of the link configuration change. - * - * If the link is immutable or if the current and new configuration are - * identical, return immediately. - * - * The user is expected to hold link->source->parent->mutex. If not, - * media_entity_setup_link() should be used instead. - */ -int __media_entity_setup_link(struct media_link *link, u32 flags) -{ - struct media_device *mdev; - struct media_entity *source, *sink; - int ret = -EBUSY; - - if (link == NULL) - return -EINVAL; - - if (link->flags & MEDIA_LNK_FL_IMMUTABLE) - return link->flags == flags ? 0 : -EINVAL; - - if (link->flags == flags) - return 0; - - source = link->source->entity; - sink = link->sink->entity; - - if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) && - (source->stream_count || sink->stream_count)) - return -EBUSY; - - mdev = source->parent; - - if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) { - ret = mdev->link_notify(link->source, link->sink, - MEDIA_LNK_FL_ENABLED); - if (ret < 0) - return ret; - } - - ret = __media_entity_setup_link_notify(link, flags); - if (ret < 0) - goto err; - - if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) - mdev->link_notify(link->source, link->sink, 0); - - return 0; - -err: - if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) - mdev->link_notify(link->source, link->sink, 0); - - return ret; -} - -int media_entity_setup_link(struct media_link *link, u32 flags) -{ - int ret; - - mutex_lock(&link->source->entity->parent->graph_mutex); - ret = __media_entity_setup_link(link, flags); - mutex_unlock(&link->source->entity->parent->graph_mutex); - - return ret; -} -EXPORT_SYMBOL_GPL(media_entity_setup_link); - -/** - * media_entity_find_link - Find a link between two pads - * @source: Source pad - * @sink: Sink pad - * - * Return a pointer to the link between the two entities. If no such link - * exists, return NULL. - */ -struct media_link * -media_entity_find_link(struct media_pad *source, struct media_pad *sink) -{ - struct media_link *link; - unsigned int i; - - for (i = 0; i < source->entity->num_links; ++i) { - link = &source->entity->links[i]; - - if (link->source->entity == source->entity && - link->source->index == source->index && - link->sink->entity == sink->entity && - link->sink->index == sink->index) - return link; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(media_entity_find_link); - -/** - * media_entity_remote_source - Find the source pad at the remote end of a link - * @pad: Sink pad at the local end of the link - * - * Search for a remote source pad connected to the given sink pad by iterating - * over all links originating or terminating at that pad until an enabled link - * is found. - * - * Return a pointer to the pad at the remote end of the first found enabled - * link, or NULL if no enabled link has been found. - */ -struct media_pad *media_entity_remote_source(struct media_pad *pad) -{ - unsigned int i; - - for (i = 0; i < pad->entity->num_links; i++) { - struct media_link *link = &pad->entity->links[i]; - - if (!(link->flags & MEDIA_LNK_FL_ENABLED)) - continue; - - if (link->source == pad) - return link->sink; - - if (link->sink == pad) - return link->source; - } - - return NULL; - -} -EXPORT_SYMBOL_GPL(media_entity_remote_source); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/dsbr100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/dsbr100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/dsbr100.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/dsbr100.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,649 +0,0 @@ -/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21. - The device plugs into both the USB and an analog audio input, so this thing - only deals with initialisation and frequency setting, the - audio data has to be handled by a sound driver. - - Major issue: I can't find out where the device reports the signal - strength, and indeed the windows software appearantly just looks - at the stereo indicator as well. So, scanning will only find - stereo stations. Sad, but I can't help it. - - Also, the windows program sends oodles of messages over to the - device, and I couldn't figure out their meaning. My suspicion - is that they don't have any:-) - - You might find some interesting stuff about this module at - http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr - - Copyright (c) 2000 Markus Demleitner - - 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, or - (at your option) any later version. - - 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 - - History: - - Version 0.46: - Removed usb_dsbr100_open/close calls and radio->users counter. Also, - radio->muted changed to radio->status and suspend/resume calls updated. - - Version 0.45: - Converted to v4l2_device. - - Version 0.44: - Add suspend/resume functions, fix unplug of device, - a lot of cleanups and fixes by Alexey Klimov - - Version 0.43: - Oliver Neukum: avoided DMA coherency issue - - Version 0.42: - Converted dsbr100 to use video_ioctl2 - by Douglas Landgraf - - Version 0.41-ac1: - Alan Cox: Some cleanups and fixes - - Version 0.41: - Converted to V4L2 API by Mauro Carvalho Chehab - - Version 0.40: - Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing - - Version 0.30: - Markus: Updates for 2.5.x kernel and more ISO compliant source - - Version 0.25: - PSL and Markus: Cleanup, radio now doesn't stop on device close - - Version 0.24: - Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally - right. Some minor cleanup, improved standalone compilation - - Version 0.23: - Markus: Sign extension bug fixed by declaring transfer_buffer unsigned - - Version 0.22: - Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, - thanks to Mike Cox for pointing the problem out. - - Version 0.21: - Markus: Minor cleanup, warnings if something goes wrong, lame attempt - to adhere to Documentation/CodingStyle - - Version 0.2: - Brad Hards : Fixes to make it work as non-module - Markus: Copyright clarification - - Version 0.01: Markus: initial release - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#include /* for KERNEL_VERSION MACRO */ - -#define DRIVER_VERSION "v0.46" -#define RADIO_VERSION KERNEL_VERSION(0, 4, 6) - -#define DRIVER_AUTHOR "Markus Demleitner " -#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" - -#define DSB100_VENDOR 0x04b4 -#define DSB100_PRODUCT 0x1002 - -/* Commands the device appears to understand */ -#define DSB100_TUNE 1 -#define DSB100_ONOFF 2 - -#define TB_LEN 16 - -/* Frequency limits in MHz -- these are European values. For Japanese -devices, that would be 76 and 91. */ -#define FREQ_MIN 87.5 -#define FREQ_MAX 108.0 -#define FREQ_MUL 16000 - -/* defines for radio->status */ -#define STARTED 0 -#define STOPPED 1 - -#define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev) - -static int usb_dsbr100_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void usb_dsbr100_disconnect(struct usb_interface *intf); -static int usb_dsbr100_suspend(struct usb_interface *intf, - pm_message_t message); -static int usb_dsbr100_resume(struct usb_interface *intf); - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -/* Data for one (physical) device */ -struct dsbr100_device { - struct usb_device *usbdev; - struct video_device videodev; - struct v4l2_device v4l2_dev; - - u8 *transfer_buffer; - struct mutex v4l2_lock; - int curfreq; - int stereo; - int status; -}; - -static struct usb_device_id usb_dsbr100_device_table [] = { - { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); - -/* USB subsystem interface */ -static struct usb_driver usb_dsbr100_driver = { - .name = "dsbr100", - .probe = usb_dsbr100_probe, - .disconnect = usb_dsbr100_disconnect, - .id_table = usb_dsbr100_device_table, - .suspend = usb_dsbr100_suspend, - .resume = usb_dsbr100_resume, - .reset_resume = usb_dsbr100_resume, - .supports_autosuspend = 0, -}; - -/* Low-level device interface begins here */ - -/* switch on radio */ -static int dsbr100_start(struct dsbr100_device *radio) -{ - int retval; - int request; - - retval = usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0xC7, radio->transfer_buffer, 8, 300); - - if (retval < 0) { - request = USB_REQ_GET_STATUS; - goto usb_control_msg_failed; - } - - retval = usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - DSB100_ONOFF, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x01, 0x00, radio->transfer_buffer, 8, 300); - - if (retval < 0) { - request = DSB100_ONOFF; - goto usb_control_msg_failed; - } - - radio->status = STARTED; - return (radio->transfer_buffer)[0]; - -usb_control_msg_failed: - dev_err(&radio->usbdev->dev, - "%s - usb_control_msg returned %i, request %i\n", - __func__, retval, request); - return retval; - -} - -/* switch off radio */ -static int dsbr100_stop(struct dsbr100_device *radio) -{ - int retval; - int request; - - retval = usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x16, 0x1C, radio->transfer_buffer, 8, 300); - - if (retval < 0) { - request = USB_REQ_GET_STATUS; - goto usb_control_msg_failed; - } - - retval = usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - DSB100_ONOFF, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0x00, radio->transfer_buffer, 8, 300); - - if (retval < 0) { - request = DSB100_ONOFF; - goto usb_control_msg_failed; - } - - radio->status = STOPPED; - return (radio->transfer_buffer)[0]; - -usb_control_msg_failed: - dev_err(&radio->usbdev->dev, - "%s - usb_control_msg returned %i, request %i\n", - __func__, retval, request); - return retval; - -} - -/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ -static int dsbr100_setfreq(struct dsbr100_device *radio) -{ - int retval; - int request; - int freq = (radio->curfreq / 16 * 80) / 1000 + 856; - - retval = usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - DSB100_TUNE, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - (freq >> 8) & 0x00ff, freq & 0xff, - radio->transfer_buffer, 8, 300); - - if (retval < 0) { - request = DSB100_TUNE; - goto usb_control_msg_failed; - } - - retval = usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x96, 0xB7, radio->transfer_buffer, 8, 300); - - if (retval < 0) { - request = USB_REQ_GET_STATUS; - goto usb_control_msg_failed; - } - - retval = usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0x24, radio->transfer_buffer, 8, 300); - - if (retval < 0) { - request = USB_REQ_GET_STATUS; - goto usb_control_msg_failed; - } - - radio->stereo = !((radio->transfer_buffer)[0] & 0x01); - return (radio->transfer_buffer)[0]; - -usb_control_msg_failed: - radio->stereo = -1; - dev_err(&radio->usbdev->dev, - "%s - usb_control_msg returned %i, request %i\n", - __func__, retval, request); - return retval; -} - -/* return the device status. This is, in effect, just whether it -sees a stereo signal or not. Pity. */ -static void dsbr100_getstat(struct dsbr100_device *radio) -{ - int retval; - - retval = usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00 , 0x24, radio->transfer_buffer, 8, 300); - - if (retval < 0) { - radio->stereo = -1; - dev_err(&radio->usbdev->dev, - "%s - usb_control_msg returned %i, request %i\n", - __func__, retval, USB_REQ_GET_STATUS); - } else { - radio->stereo = !(radio->transfer_buffer[0] & 0x01); - } -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - struct dsbr100_device *radio = video_drvdata(file); - - strlcpy(v->driver, "dsbr100", sizeof(v->driver)); - strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card)); - usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct dsbr100_device *radio = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - dsbr100_getstat(radio); - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = FREQ_MIN * FREQ_MUL; - v->rangehigh = FREQ_MAX * FREQ_MUL; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if(radio->stereo) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff; /* We can't get the signal strength */ - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct dsbr100_device *radio = video_drvdata(file); - int retval; - - radio->curfreq = f->frequency; - - retval = dsbr100_setfreq(radio); - if (retval < 0) - dev_warn(&radio->usbdev->dev, "Set frequency failed\n"); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct dsbr100_device *radio = video_drvdata(file); - - f->type = V4L2_TUNER_RADIO; - f->frequency = radio->curfreq; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct dsbr100_device *radio = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = radio->status; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct dsbr100_device *radio = video_drvdata(file); - int retval; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) { - retval = dsbr100_stop(radio); - if (retval < 0) { - dev_warn(&radio->usbdev->dev, - "Radio did not respond properly\n"); - return -EBUSY; - } - } else { - retval = dsbr100_start(radio); - if (retval < 0) { - dev_warn(&radio->usbdev->dev, - "Radio did not respond properly\n"); - return -EBUSY; - } - } - return 0; - } - return -EINVAL; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -/* USB subsystem interface begins here */ - -/* - * Handle unplugging of the device. - * We call video_unregister_device in any case. - * The last function called in this procedure is - * usb_dsbr100_video_device_release - */ -static void usb_dsbr100_disconnect(struct usb_interface *intf) -{ - struct dsbr100_device *radio = usb_get_intfdata(intf); - - v4l2_device_get(&radio->v4l2_dev); - mutex_lock(&radio->v4l2_lock); - usb_set_intfdata(intf, NULL); - video_unregister_device(&radio->videodev); - v4l2_device_disconnect(&radio->v4l2_dev); - mutex_unlock(&radio->v4l2_lock); - v4l2_device_put(&radio->v4l2_dev); -} - - -/* Suspend device - stop device. */ -static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct dsbr100_device *radio = usb_get_intfdata(intf); - int retval; - - mutex_lock(&radio->v4l2_lock); - if (radio->status == STARTED) { - retval = dsbr100_stop(radio); - if (retval < 0) - dev_warn(&intf->dev, "dsbr100_stop failed\n"); - - /* After dsbr100_stop() status set to STOPPED. - * If we want driver to start radio on resume - * we set status equal to STARTED. - * On resume we will check status and run radio if needed. - */ - radio->status = STARTED; - } - mutex_unlock(&radio->v4l2_lock); - - dev_info(&intf->dev, "going into suspend..\n"); - - return 0; -} - -/* Resume device - start device. */ -static int usb_dsbr100_resume(struct usb_interface *intf) -{ - struct dsbr100_device *radio = usb_get_intfdata(intf); - int retval; - - mutex_lock(&radio->v4l2_lock); - if (radio->status == STARTED) { - retval = dsbr100_start(radio); - if (retval < 0) - dev_warn(&intf->dev, "dsbr100_start failed\n"); - } - mutex_unlock(&radio->v4l2_lock); - - dev_info(&intf->dev, "coming out of suspend..\n"); - - return 0; -} - -/* free data structures */ -static void usb_dsbr100_release(struct v4l2_device *v4l2_dev) -{ - struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev); - - v4l2_device_unregister(&radio->v4l2_dev); - kfree(radio->transfer_buffer); - kfree(radio); -} - -/* File system interface */ -static const struct v4l2_file_operations usb_dsbr100_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, -}; - -/* check if the device is present and register with v4l and usb if it is */ -static int usb_dsbr100_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dsbr100_device *radio; - struct v4l2_device *v4l2_dev; - int retval; - - radio = kzalloc(sizeof(struct dsbr100_device), GFP_KERNEL); - - if (!radio) - return -ENOMEM; - - radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL); - - if (!(radio->transfer_buffer)) { - kfree(radio); - return -ENOMEM; - } - - v4l2_dev = &radio->v4l2_dev; - v4l2_dev->release = usb_dsbr100_release; - - retval = v4l2_device_register(&intf->dev, v4l2_dev); - if (retval < 0) { - v4l2_err(v4l2_dev, "couldn't register v4l2_device\n"); - kfree(radio->transfer_buffer); - kfree(radio); - return retval; - } - - mutex_init(&radio->v4l2_lock); - strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name)); - radio->videodev.v4l2_dev = v4l2_dev; - radio->videodev.fops = &usb_dsbr100_fops; - radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops; - radio->videodev.release = video_device_release_empty; - radio->videodev.lock = &radio->v4l2_lock; - - radio->usbdev = interface_to_usbdev(intf); - radio->curfreq = FREQ_MIN * FREQ_MUL; - radio->status = STOPPED; - - video_set_drvdata(&radio->videodev, radio); - - retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); - if (retval < 0) { - v4l2_err(v4l2_dev, "couldn't register video device\n"); - v4l2_device_unregister(v4l2_dev); - kfree(radio->transfer_buffer); - kfree(radio); - return -EIO; - } - usb_set_intfdata(intf, radio); - return 0; -} - -static int __init dsbr100_init(void) -{ - int retval = usb_register(&usb_dsbr100_driver); - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return retval; -} - -static void __exit dsbr100_exit(void) -{ - usb_deregister(&usb_dsbr100_driver); -} - -module_init (dsbr100_init); -module_exit (dsbr100_exit); - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,461 +0,0 @@ -# -# Multimedia Video device configuration -# - -menuconfig RADIO_ADAPTERS - bool "Radio Adapters" - depends on VIDEO_V4L2 - default y - ---help--- - Say Y here to enable selecting AM/FM radio adapters. - -if RADIO_ADAPTERS && VIDEO_V4L2 - -config RADIO_CADET - tristate "ADS Cadet AM/FM Tuner" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have one of these AM/FM radio cards, and then - fill in the port address below. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - Further documentation on this driver can be found on the WWW at - . - - To compile this driver as a module, choose M here: the - module will be called radio-cadet. - -config RADIO_RTRACK - tristate "AIMSlab RadioTrack (aka RadioReveal) support" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - - Note that newer AIMSlab RadioTrack cards have a different chipset - and are not supported by this driver. For these cards, use the - RadioTrack II driver below. - - If you have a GemTeks combined (PnP) sound- and radio card you must - use this driver as a module and setup the card with isapnptools. - You must also pass the module a suitable io parameter, 0x248 has - been reported to be used by these cards. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . More information is - contained in the file - . - - To compile this driver as a module, choose M here: the - module will be called radio-aimslab. - -config RADIO_RTRACK_PORT - hex "RadioTrack i/o port (0x20f or 0x30f)" - depends on RADIO_RTRACK=y - default "20f" - help - Enter either 0x30f or 0x20f here. The card default is 0x30f, if you - haven't changed the jumper setting on the card. - -config RADIO_RTRACK2 - tristate "AIMSlab RadioTrack II support" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have this FM radio card, and then fill in the - port address below. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-rtrack2. - -config RADIO_RTRACK2_PORT - hex "RadioTrack II i/o port (0x20c or 0x30c)" - depends on RADIO_RTRACK2=y - default "30c" - help - Enter either 0x30c or 0x20c here. The card default is 0x30c, if you - haven't changed the jumper setting on the card. - -config RADIO_AZTECH - tristate "Aztech/Packard Bell Radio" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-aztech. - -config RADIO_AZTECH_PORT - hex "Aztech/Packard Bell I/O port (0x350 or 0x358)" - depends on RADIO_AZTECH=y - default "350" - help - Enter either 0x350 or 0x358 here. The card default is 0x350, if you - haven't changed the setting of jumper JP3 on the card. Removing the - jumper sets the card to 0x358. - -config RADIO_GEMTEK - tristate "GemTek Radio card (or compatible) support" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have this FM radio card, and then fill in the - I/O port address and settings below. The following cards either have - GemTek Radio tuner or are rebranded GemTek Radio cards: - - - Sound Vision 16 Gold with FM Radio - - Typhoon Radio card (some models) - - Hama Radio card - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-gemtek. - -config RADIO_GEMTEK_PORT - hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)" - depends on RADIO_GEMTEK=y - default "34c" - help - Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is - 0x34c, if you haven't changed the jumper setting on the card. On - Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O - port is 0x20c, 0x248 or 0x28c. - If automatic I/O port probing is enabled this port will be used only - in case of automatic probing failure, ie. as a fallback. - -config RADIO_GEMTEK_PROBE - bool "Automatic I/O port probing" - depends on RADIO_GEMTEK=y - default y - help - Say Y here to enable automatic probing for GemTek Radio card. The - following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and - 0x28c. - -config RADIO_MAXIRADIO - tristate "Guillemot MAXI Radio FM 2000 radio" - depends on VIDEO_V4L2 && PCI - ---help--- - Choose Y here if you have this radio card. This card may also be - found as Gemtek PCI FM. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-maxiradio. - -config RADIO_MAESTRO - tristate "Maestro on board radio" - depends on VIDEO_V4L2 && PCI - ---help--- - Say Y here to directly support the on-board radio tuner on the - Maestro 2 or 2E sound card. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-maestro. - -config RADIO_MIROPCM20 - tristate "miroSOUND PCM20 radio" - depends on ISA && VIDEO_V4L2 && SND - select SND_ISA - select SND_MIRO - ---help--- - Choose Y here if you have this FM radio card. You also need to enable - the ALSA sound system. This choice automatically selects the ALSA - sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this - is required for the radio-miropcm20. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-miropcm20. - -config RADIO_SF16FMI - tristate "SF16-FMI/SF16-FMP Radio" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have one of these FM radio cards. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-sf16fmi. - -config RADIO_SF16FMR2 - tristate "SF16FMR2 Radio" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have one of these FM radio cards. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found on the WWW at - . - - To compile this driver as a module, choose M here: the - module will be called radio-sf16fmr2. - -config RADIO_TERRATEC - tristate "TerraTec ActiveRadio ISA Standalone" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have this FM radio card, and then fill in the - port address below. (TODO) - - Note: This driver is in its early stages. Right now volume and - frequency control and muting works at least for me, but - unfortunately I have not found anybody who wants to use this card - with Linux. So if it is this what YOU are trying to do right now, - PLEASE DROP ME A NOTE!! Rolf Offermanns . - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-terratec. - -config RADIO_TERRATEC_PORT - hex "Terratec i/o port (normally 0x590)" - depends on RADIO_TERRATEC=y - default "590" - help - Fill in the I/O port of your TerraTec FM radio card. If unsure, go - with the default. - -config RADIO_TRUST - tristate "Trust FM radio card" - depends on ISA && VIDEO_V4L2 - help - This is a driver for the Trust FM radio cards. Say Y if you have - such a card and want to use it under Linux. - - To compile this driver as a module, choose M here: the - module will be called radio-trust. - -config RADIO_TRUST_PORT - hex "Trust i/o port (usually 0x350 or 0x358)" - depends on RADIO_TRUST=y - default "350" - help - Enter the I/O port of your Trust FM radio card. If unsure, try the - values "0x350" or "0x358". - -config RADIO_TYPHOON - tristate "Typhoon Radio (a.k.a. EcoRadio)" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address and the frequency used for muting below. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-typhoon. - -config RADIO_TYPHOON_PORT - hex "Typhoon I/O port (0x316 or 0x336)" - depends on RADIO_TYPHOON=y - default "316" - help - Enter the I/O port of your Typhoon or EcoRadio radio card. - -config RADIO_TYPHOON_MUTEFREQ - int "Typhoon frequency set when muting the device (kHz)" - depends on RADIO_TYPHOON=y - default "87500" - help - Enter the frequency used for muting the radio. The device is never - completely silent. If the volume is just turned down, you can still - hear silent voices and music. For that reason, the frequency of the - radio device is set to the frequency you can enter here whenever - the device is muted. There should be no local radio station at that - frequency. - -config RADIO_ZOLTRIX - tristate "Zoltrix Radio" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-zoltrix. - -config RADIO_ZOLTRIX_PORT - hex "ZOLTRIX I/O port (0x20c or 0x30c)" - depends on RADIO_ZOLTRIX=y - default "20c" - help - Enter the I/O port of your Zoltrix radio card. - -config I2C_SI4713 - tristate "I2C driver for Silicon Labs Si4713 device" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want support to Si4713 I2C device. - This device driver supports only i2c bus. - - To compile this driver as a module, choose M here: the - module will be called si4713. - -config RADIO_SI4713 - tristate "Silicon Labs Si4713 FM Radio Transmitter support" - depends on I2C && VIDEO_V4L2 - select I2C_SI4713 - ---help--- - Say Y here if you want support to Si4713 FM Radio Transmitter. - This device can transmit audio through FM. It can transmit - RDS and RBDS signals as well. This module is the v4l2 radio - interface for the i2c driver of this device. - - To compile this driver as a module, choose M here: the - module will be called radio-si4713. - -config USB_DSBR - tristate "D-Link/GemTek USB FM radio support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - To compile this driver as a module, choose M here: the - module will be called dsbr100. - -config RADIO_SI470X - bool "Silicon Labs Si470x FM Radio Receiver support" - depends on VIDEO_V4L2 - -source "drivers/media/radio/si470x/Kconfig" - -config USB_MR800 - tristate "AverMedia MR 800 USB FM radio support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - To compile this driver as a module, choose M here: the - module will be called radio-mr800. - -config RADIO_TEA5764 - tristate "TEA5764 I2C FM radio support" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the TEA5764 FM chip found in - EZX phones. This FM chip is present in EZX phones from Motorola, - connected to internal pxa I2C bus. - - To compile this driver as a module, choose M here: the - module will be called radio-tea5764. - -config RADIO_TEA5764_XTAL - bool "TEA5764 crystal reference" - depends on RADIO_TEA5764=y - default y - help - Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N - here if TEA5764 reference frequency is connected in FREQIN. - -config RADIO_SAA7706H - tristate "SAA7706H Car Radio DSP" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the SAA7706H Car radio Digital - Signal Processor, found for instance on the Russellville development - board. On the russellville the device is connected to internal - timberdale I2C bus. - - To compile this driver as a module, choose M here: the - module will be called SAA7706H. - -config RADIO_TEF6862 - tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the TEF6862 Car Radio Enhanced - Selectivity Tuner, found for instance on the Russellville development - board. On the russellville the device is connected to internal - timberdale I2C bus. - - To compile this driver as a module, choose M here: the - module will be called TEF6862. - -config RADIO_TIMBERDALE - tristate "Enable the Timberdale radio driver" - depends on MFD_TIMBERDALE && VIDEO_V4L2 - depends on I2C # for RADIO_SAA7706H - select RADIO_TEF6862 - select RADIO_SAA7706H - ---help--- - This is a kind of umbrella driver for the Radio Tuner and DSP - found behind the Timberdale FPGA on the Russellville board. - Enabling this driver will automatically select the DSP and tuner. - -config RADIO_WL1273 - tristate "Texas Instruments WL1273 I2C FM Radio" - depends on I2C && VIDEO_V4L2 - select MFD_CORE - select MFD_WL1273_CORE - select FW_LOADER - ---help--- - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-wl1273. - -# TI's ST based wl128x FM radio -source "drivers/media/radio/wl128x/Kconfig" - -endif # RADIO_ADAPTERS diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# -# Makefile for the kernel character device drivers. -# - -obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o -obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o -obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o -obj-$(CONFIG_RADIO_SF16FMR2) += radio-sf16fmr2.o -obj-$(CONFIG_RADIO_CADET) += radio-cadet.o -obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o -obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o -obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o -obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o -obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o -obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o -obj-$(CONFIG_RADIO_TRUST) += radio-trust.o -obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o -obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o -obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o -obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o -obj-$(CONFIG_USB_DSBR) += dsbr100.o -obj-$(CONFIG_RADIO_SI470X) += si470x/ -obj-$(CONFIG_USB_MR800) += radio-mr800.o -obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o -obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o -obj-$(CONFIG_RADIO_TEF6862) += tef6862.o -obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o -obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o -obj-$(CONFIG_RADIO_WL128X) += wl128x/ - -EXTRA_CFLAGS += -Isound diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-aimslab.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-aimslab.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-aimslab.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-aimslab.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,437 +0,0 @@ -/* radiotrack (radioreveal) driver for Linux radio support - * (c) 1997 M. Kirkwood - * Converted to V4L2 API by Mauro Carvalho Chehab - * Converted to new API by Alan Cox - * Various bugfixes and enhancements by Russell Kroll - * - * History: - * 1999-02-24 Russell Kroll - * Fine tuning/VIDEO_TUNER_LOW - * Frequency range expanded to start at 87 MHz - * - * TODO: Allow for more than one of these foolish entities :-) - * - * Notes on the hardware (reverse engineered from other peoples' - * reverse engineering of AIMS' code :-) - * - * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); - * - * The signal strength query is unsurprisingly inaccurate. And it seems - * to indicate that (on my card, at least) the frequency setting isn't - * too great. (I have to tune up .025MHz from what the freq should be - * to get a report that the thing is tuned.) - * - * Volume control is (ugh) analogue: - * out(port, start_increasing_volume); - * wait(a_wee_while); - * out(port, stop_changing_the_volume); - * - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* msleep */ -#include /* kernel radio structs */ -#include /* for KERNEL_VERSION MACRO */ -#include /* outb, outb_p */ -#include -#include - -MODULE_AUTHOR("M.Kirkwood"); -MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); -MODULE_LICENSE("GPL"); - -#ifndef CONFIG_RADIO_RTRACK_PORT -#define CONFIG_RADIO_RTRACK_PORT -1 -#endif - -static int io = CONFIG_RADIO_RTRACK_PORT; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - -struct rtrack -{ - struct v4l2_device v4l2_dev; - struct video_device vdev; - int port; - int curvol; - unsigned long curfreq; - int muted; - int io; - struct mutex lock; -}; - -static struct rtrack rtrack_card; - -/* local things */ - -static void rt_decvol(struct rtrack *rt) -{ - outb(0x58, rt->io); /* volume down + sigstr + on */ - msleep(100); - outb(0xd8, rt->io); /* volume steady + sigstr + on */ -} - -static void rt_incvol(struct rtrack *rt) -{ - outb(0x98, rt->io); /* volume up + sigstr + on */ - msleep(100); - outb(0xd8, rt->io); /* volume steady + sigstr + on */ -} - -static void rt_mute(struct rtrack *rt) -{ - rt->muted = 1; - mutex_lock(&rt->lock); - outb(0xd0, rt->io); /* volume steady, off */ - mutex_unlock(&rt->lock); -} - -static int rt_setvol(struct rtrack *rt, int vol) -{ - int i; - - mutex_lock(&rt->lock); - - if (vol == rt->curvol) { /* requested volume = current */ - if (rt->muted) { /* user is unmuting the card */ - rt->muted = 0; - outb(0xd8, rt->io); /* enable card */ - } - mutex_unlock(&rt->lock); - return 0; - } - - if (vol == 0) { /* volume = 0 means mute the card */ - outb(0x48, rt->io); /* volume down but still "on" */ - msleep(2000); /* make sure it's totally down */ - outb(0xd0, rt->io); /* volume steady, off */ - rt->curvol = 0; /* track the volume state! */ - mutex_unlock(&rt->lock); - return 0; - } - - rt->muted = 0; - if (vol > rt->curvol) - for (i = rt->curvol; i < vol; i++) - rt_incvol(rt); - else - for (i = rt->curvol; i > vol; i--) - rt_decvol(rt); - - rt->curvol = vol; - mutex_unlock(&rt->lock); - return 0; -} - -/* the 128+64 on these outb's is to keep the volume stable while tuning - * without them, the volume _will_ creep up with each frequency change - * and bit 4 (+16) is to keep the signal strength meter enabled - */ - -static void send_0_byte(struct rtrack *rt) -{ - if (rt->curvol == 0 || rt->muted) { - outb_p(128+64+16+ 1, rt->io); /* wr-enable + data low */ - outb_p(128+64+16+2+1, rt->io); /* clock */ - } - else { - outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */ - outb_p(128+64+16+8+2+1, rt->io); /* clock */ - } - msleep(1); -} - -static void send_1_byte(struct rtrack *rt) -{ - if (rt->curvol == 0 || rt->muted) { - outb_p(128+64+16+4 +1, rt->io); /* wr-enable+data high */ - outb_p(128+64+16+4+2+1, rt->io); /* clock */ - } - else { - outb_p(128+64+16+8+4 +1, rt->io); /* on+wr-enable+data high */ - outb_p(128+64+16+8+4+2+1, rt->io); /* clock */ - } - - msleep(1); -} - -static int rt_setfreq(struct rtrack *rt, unsigned long freq) -{ - int i; - - mutex_lock(&rt->lock); /* Stop other ops interfering */ - - rt->curfreq = freq; - - /* now uses VIDEO_TUNER_LOW for fine tuning */ - - freq += 171200; /* Add 10.7 MHz IF */ - freq /= 800; /* Convert to 50 kHz units */ - - send_0_byte(rt); /* 0: LSB of frequency */ - - for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ - if (freq & (1 << i)) - send_1_byte(rt); - else - send_0_byte(rt); - - send_0_byte(rt); /* 14: test bit - always 0 */ - send_0_byte(rt); /* 15: test bit - always 0 */ - - send_0_byte(rt); /* 16: band data 0 - always 0 */ - send_0_byte(rt); /* 17: band data 1 - always 0 */ - send_0_byte(rt); /* 18: band data 2 - always 0 */ - send_0_byte(rt); /* 19: time base - always 0 */ - - send_0_byte(rt); /* 20: spacing (0 = 25 kHz) */ - send_1_byte(rt); /* 21: spacing (1 = 25 kHz) */ - send_0_byte(rt); /* 22: spacing (0 = 25 kHz) */ - send_1_byte(rt); /* 23: AM/FM (FM = 1, always) */ - - if (rt->curvol == 0 || rt->muted) - outb(0xd0, rt->io); /* volume steady + sigstr */ - else - outb(0xd8, rt->io); /* volume steady + sigstr + on */ - - mutex_unlock(&rt->lock); - - return 0; -} - -static int rt_getsigstr(struct rtrack *rt) -{ - int sig = 1; - - mutex_lock(&rt->lock); - if (inb(rt->io) & 2) /* bit set = no signal present */ - sig = 0; - mutex_unlock(&rt->lock); - return sig; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-aimslab", sizeof(v->driver)); - strlcpy(v->card, "RadioTrack", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct rtrack *rt = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = 87 * 16000; - v->rangehigh = 108 * 16000; - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff * rt_getsigstr(rt); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct rtrack *rt = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - rt_setfreq(rt, f->frequency); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct rtrack *rt = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = rt->curfreq; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct rtrack *rt = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = rt->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = rt->curvol; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct rtrack *rt = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - rt_mute(rt); - else - rt_setvol(rt, rt->curvol); - return 0; - case V4L2_CID_AUDIO_VOLUME: - rt_setvol(rt, ctrl->value); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static const struct v4l2_file_operations rtrack_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static int __init rtrack_init(void) -{ - struct rtrack *rt = &rtrack_card; - struct v4l2_device *v4l2_dev = &rt->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name)); - rt->io = io; - - if (rt->io == -1) { - v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n"); - return -EINVAL; - } - - if (!request_region(rt->io, 2, "rtrack")) { - v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io); - return -EBUSY; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(rt->io, 2); - v4l2_err(v4l2_dev, "could not register v4l2_device\n"); - return res; - } - - strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name)); - rt->vdev.v4l2_dev = v4l2_dev; - rt->vdev.fops = &rtrack_fops; - rt->vdev.ioctl_ops = &rtrack_ioctl_ops; - rt->vdev.release = video_device_release_empty; - video_set_drvdata(&rt->vdev, rt); - - /* Set up the I/O locking */ - - mutex_init(&rt->lock); - - /* mute card - prevents noisy bootups */ - - /* this ensures that the volume is all the way down */ - outb(0x48, rt->io); /* volume down but still "on" */ - msleep(2000); /* make sure it's totally down */ - outb(0xc0, rt->io); /* steady volume, mute card */ - - if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(&rt->v4l2_dev); - release_region(rt->io, 2); - return -EINVAL; - } - v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); - - return 0; -} - -static void __exit rtrack_exit(void) -{ - struct rtrack *rt = &rtrack_card; - - video_unregister_device(&rt->vdev); - v4l2_device_unregister(&rt->v4l2_dev); - release_region(rt->io, 2); -} - -module_init(rtrack_init); -module_exit(rtrack_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-aztech.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-aztech.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-aztech.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-aztech.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,401 +0,0 @@ -/* radio-aztech.c - Aztech radio card driver for Linux 2.2 - * - * Converted to V4L2 API by Mauro Carvalho Chehab - * Adapted to support the Video for Linux API by - * Russell Kroll . Based on original tuner code by: - * - * Quay Ly - * Donald Song - * Jason Lewis (jlewis@twilight.vtc.vsc.edu) - * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) - * William McGrath (wmcgrath@twilight.vtc.vsc.edu) - * - * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ - * along with more information on the card itself. - * - * History: - * 1999-02-24 Russell Kroll - * Fine tuning/VIDEO_TUNER_LOW - * Range expanded to 87-108 MHz (from 87.9-107.8) - * - * Notable changes from the original source: - * - includes stripped down to the essentials - * - for loops used as delays replaced with udelay() - * - #defines removed, changed to static values - * - tuning structure changed - no more character arrays, other changes -*/ - -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* udelay */ -#include /* kernel radio structs */ -#include /* for KERNEL_VERSION MACRO */ -#include /* outb, outb_p */ -#include -#include - -MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); -MODULE_DESCRIPTION("A driver for the Aztech radio card."); -MODULE_LICENSE("GPL"); - -/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ - -#ifndef CONFIG_RADIO_AZTECH_PORT -#define CONFIG_RADIO_AZTECH_PORT -1 -#endif - -static int io = CONFIG_RADIO_AZTECH_PORT; -static int radio_nr = -1; -static int radio_wait_time = 1000; - -module_param(io, int, 0); -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - -struct aztech -{ - struct v4l2_device v4l2_dev; - struct video_device vdev; - int io; - int curvol; - unsigned long curfreq; - int stereo; - struct mutex lock; -}; - -static struct aztech aztech_card; - -static int volconvert(int level) -{ - level >>= 14; /* Map 16bits down to 2 bit */ - level &= 3; - - /* convert to card-friendly values */ - switch (level) { - case 0: - return 0; - case 1: - return 1; - case 2: - return 4; - case 3: - return 5; - } - return 0; /* Quieten gcc */ -} - -static void send_0_byte(struct aztech *az) -{ - udelay(radio_wait_time); - outb_p(2 + volconvert(az->curvol), az->io); - outb_p(64 + 2 + volconvert(az->curvol), az->io); -} - -static void send_1_byte(struct aztech *az) -{ - udelay (radio_wait_time); - outb_p(128 + 2 + volconvert(az->curvol), az->io); - outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io); -} - -static int az_setvol(struct aztech *az, int vol) -{ - mutex_lock(&az->lock); - outb(volconvert(vol), az->io); - mutex_unlock(&az->lock); - return 0; -} - -/* thanks to Michael Dwyer for giving me a dose of clues in - * the signal strength department.. - * - * This card has a stereo bit - bit 0 set = mono, not set = stereo - * It also has a "signal" bit - bit 1 set = bad signal, not set = good - * - */ - -static int az_getsigstr(struct aztech *az) -{ - int sig = 1; - - mutex_lock(&az->lock); - if (inb(az->io) & 2) /* bit set = no signal present */ - sig = 0; - mutex_unlock(&az->lock); - return sig; -} - -static int az_getstereo(struct aztech *az) -{ - int stereo = 1; - - mutex_lock(&az->lock); - if (inb(az->io) & 1) /* bit set = mono */ - stereo = 0; - mutex_unlock(&az->lock); - return stereo; -} - -static int az_setfreq(struct aztech *az, unsigned long frequency) -{ - int i; - - mutex_lock(&az->lock); - - az->curfreq = frequency; - frequency += 171200; /* Add 10.7 MHz IF */ - frequency /= 800; /* Convert to 50 kHz units */ - - send_0_byte(az); /* 0: LSB of frequency */ - - for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ - if (frequency & (1 << i)) - send_1_byte(az); - else - send_0_byte(az); - - send_0_byte(az); /* 14: test bit - always 0 */ - send_0_byte(az); /* 15: test bit - always 0 */ - send_0_byte(az); /* 16: band data 0 - always 0 */ - if (az->stereo) /* 17: stereo (1 to enable) */ - send_1_byte(az); - else - send_0_byte(az); - - send_1_byte(az); /* 18: band data 1 - unknown */ - send_0_byte(az); /* 19: time base - always 0 */ - send_0_byte(az); /* 20: spacing (0 = 25 kHz) */ - send_1_byte(az); /* 21: spacing (1 = 25 kHz) */ - send_0_byte(az); /* 22: spacing (0 = 25 kHz) */ - send_1_byte(az); /* 23: AM/FM (FM = 1, always) */ - - /* latch frequency */ - - udelay(radio_wait_time); - outb_p(128 + 64 + volconvert(az->curvol), az->io); - - mutex_unlock(&az->lock); - - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-aztech", sizeof(v->driver)); - strlcpy(v->card, "Aztech Radio", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct aztech *az = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - - v->rangelow = 87 * 16000; - v->rangehigh = 108 * 16000; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if (az_getstereo(az)) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF * az_getsigstr(az); - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct aztech *az = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - az_setfreq(az, f->frequency); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct aztech *az = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = az->curfreq; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct aztech *az = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (az->curvol == 0) - ctrl->value = 1; - else - ctrl->value = 0; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = az->curvol * 6554; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct aztech *az = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - az_setvol(az, 0); - else - az_setvol(az, az->curvol); - return 0; - case V4L2_CID_AUDIO_VOLUME: - az_setvol(az, ctrl->value); - return 0; - } - return -EINVAL; -} - -static const struct v4l2_file_operations aztech_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops aztech_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static int __init aztech_init(void) -{ - struct aztech *az = &aztech_card; - struct v4l2_device *v4l2_dev = &az->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name)); - az->io = io; - - if (az->io == -1) { - v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n"); - return -EINVAL; - } - - if (!request_region(az->io, 2, "aztech")) { - v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io); - return -EBUSY; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(az->io, 2); - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } - - mutex_init(&az->lock); - strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name)); - az->vdev.v4l2_dev = v4l2_dev; - az->vdev.fops = &aztech_fops; - az->vdev.ioctl_ops = &aztech_ioctl_ops; - az->vdev.release = video_device_release_empty; - video_set_drvdata(&az->vdev, az); - /* mute card - prevents noisy bootups */ - outb(0, az->io); - - if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(az->io, 2); - return -EINVAL; - } - - v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); - return 0; -} - -static void __exit aztech_exit(void) -{ - struct aztech *az = &aztech_card; - - video_unregister_device(&az->vdev); - v4l2_device_unregister(&az->v4l2_dev); - release_region(az->io, 2); -} - -module_init(aztech_init); -module_exit(aztech_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-cadet.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-cadet.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-cadet.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-cadet.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,717 +0,0 @@ -/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card - * - * by Fred Gleason - * Version 0.3.3 - * - * (Loosely) based on code for the Aztech radio card by - * - * Russell Kroll (rkroll@exploits.org) - * Quay Ly - * Donald Song - * Jason Lewis (jlewis@twilight.vtc.vsc.edu) - * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) - * William McGrath (wmcgrath@twilight.vtc.vsc.edu) - * - * History: - * 2000-04-29 Russell Kroll - * Added ISAPnP detection for Linux 2.3/2.4 - * - * 2001-01-10 Russell Kroll - * Removed dead CONFIG_RADIO_CADET_PORT code - * PnP detection on load is now default (no args necessary) - * - * 2002-01-17 Adam Belay - * Updated to latest pnp code - * - * 2003-01-31 Alan Cox - * Cleaned up locking, delay code, general odds and ends - * - * 2006-07-30 Hans J. Koch - * Changed API to V4L2 - */ - -#include -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* udelay */ -#include /* V4L2 API defs */ -#include -#include -#include -#include /* outb, outb_p */ -#include -#include - -MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); -MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); -MODULE_LICENSE("GPL"); - -static int io = -1; /* default to isapnp activation */ -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); -module_param(radio_nr, int, 0); - -#define CADET_VERSION KERNEL_VERSION(0, 3, 3) - -#define RDS_BUFFER 256 -#define RDS_RX_FLAG 1 -#define MBS_RX_FLAG 2 - -struct cadet { - struct v4l2_device v4l2_dev; - struct video_device vdev; - int io; - int users; - int curtuner; - int tunestat; - int sigstrength; - wait_queue_head_t read_queue; - struct timer_list readtimer; - __u8 rdsin, rdsout, rdsstat; - unsigned char rdsbuf[RDS_BUFFER]; - struct mutex lock; - int reading; -}; - -static struct cadet cadet_card; - -/* - * Signal Strength Threshold Values - * The V4L API spec does not define any particular unit for the signal - * strength value. These values are in microvolts of RF at the tuner's input. - */ -static __u16 sigtable[2][4] = { - { 5, 10, 30, 150 }, - { 28, 40, 63, 1000 } -}; - - -static int cadet_getstereo(struct cadet *dev) -{ - int ret = V4L2_TUNER_SUB_MONO; - - if (dev->curtuner != 0) /* Only FM has stereo capability! */ - return V4L2_TUNER_SUB_MONO; - - mutex_lock(&dev->lock); - outb(7, dev->io); /* Select tuner control */ - if ((inb(dev->io + 1) & 0x40) == 0) - ret = V4L2_TUNER_SUB_STEREO; - mutex_unlock(&dev->lock); - return ret; -} - -static unsigned cadet_gettune(struct cadet *dev) -{ - int curvol, i; - unsigned fifo = 0; - - /* - * Prepare for read - */ - - mutex_lock(&dev->lock); - - outb(7, dev->io); /* Select tuner control */ - curvol = inb(dev->io + 1); /* Save current volume/mute setting */ - outb(0x00, dev->io + 1); /* Ensure WRITE-ENABLE is LOW */ - dev->tunestat = 0xffff; - - /* - * Read the shift register - */ - for (i = 0; i < 25; i++) { - fifo = (fifo << 1) | ((inb(dev->io + 1) >> 7) & 0x01); - if (i < 24) { - outb(0x01, dev->io + 1); - dev->tunestat &= inb(dev->io + 1); - outb(0x00, dev->io + 1); - } - } - - /* - * Restore volume/mute setting - */ - outb(curvol, dev->io + 1); - mutex_unlock(&dev->lock); - - return fifo; -} - -static unsigned cadet_getfreq(struct cadet *dev) -{ - int i; - unsigned freq = 0, test, fifo = 0; - - /* - * Read current tuning - */ - fifo = cadet_gettune(dev); - - /* - * Convert to actual frequency - */ - if (dev->curtuner == 0) { /* FM */ - test = 12500; - for (i = 0; i < 14; i++) { - if ((fifo & 0x01) != 0) - freq += test; - test = test << 1; - fifo = fifo >> 1; - } - freq -= 10700000; /* IF frequency is 10.7 MHz */ - freq = (freq * 16) / 1000000; /* Make it 1/16 MHz */ - } - if (dev->curtuner == 1) /* AM */ - freq = ((fifo & 0x7fff) - 2010) * 16; - - return freq; -} - -static void cadet_settune(struct cadet *dev, unsigned fifo) -{ - int i; - unsigned test; - - mutex_lock(&dev->lock); - - outb(7, dev->io); /* Select tuner control */ - /* - * Write the shift register - */ - test = 0; - test = (fifo >> 23) & 0x02; /* Align data for SDO */ - test |= 0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */ - outb(7, dev->io); /* Select tuner control */ - outb(test, dev->io + 1); /* Initialize for write */ - for (i = 0; i < 25; i++) { - test |= 0x01; /* Toggle SCK High */ - outb(test, dev->io + 1); - test &= 0xfe; /* Toggle SCK Low */ - outb(test, dev->io + 1); - fifo = fifo << 1; /* Prepare the next bit */ - test = 0x1c | ((fifo >> 23) & 0x02); - outb(test, dev->io + 1); - } - mutex_unlock(&dev->lock); -} - -static void cadet_setfreq(struct cadet *dev, unsigned freq) -{ - unsigned fifo; - int i, j, test; - int curvol; - - /* - * Formulate a fifo command - */ - fifo = 0; - if (dev->curtuner == 0) { /* FM */ - test = 102400; - freq = (freq * 1000) / 16; /* Make it kHz */ - freq += 10700; /* IF is 10700 kHz */ - for (i = 0; i < 14; i++) { - fifo = fifo << 1; - if (freq >= test) { - fifo |= 0x01; - freq -= test; - } - test = test >> 1; - } - } - if (dev->curtuner == 1) { /* AM */ - fifo = (freq / 16) + 2010; /* Make it kHz */ - fifo |= 0x100000; /* Select AM Band */ - } - - /* - * Save current volume/mute setting - */ - - mutex_lock(&dev->lock); - outb(7, dev->io); /* Select tuner control */ - curvol = inb(dev->io + 1); - mutex_unlock(&dev->lock); - - /* - * Tune the card - */ - for (j = 3; j > -1; j--) { - cadet_settune(dev, fifo | (j << 16)); - - mutex_lock(&dev->lock); - outb(7, dev->io); /* Select tuner control */ - outb(curvol, dev->io + 1); - mutex_unlock(&dev->lock); - - msleep(100); - - cadet_gettune(dev); - if ((dev->tunestat & 0x40) == 0) { /* Tuned */ - dev->sigstrength = sigtable[dev->curtuner][j]; - return; - } - } - dev->sigstrength = 0; -} - - -static int cadet_getvol(struct cadet *dev) -{ - int ret = 0; - - mutex_lock(&dev->lock); - - outb(7, dev->io); /* Select tuner control */ - if ((inb(dev->io + 1) & 0x20) != 0) - ret = 0xffff; - - mutex_unlock(&dev->lock); - return ret; -} - - -static void cadet_setvol(struct cadet *dev, int vol) -{ - mutex_lock(&dev->lock); - outb(7, dev->io); /* Select tuner control */ - if (vol > 0) - outb(0x20, dev->io + 1); - else - outb(0x00, dev->io + 1); - mutex_unlock(&dev->lock); -} - -static void cadet_handler(unsigned long data) -{ - struct cadet *dev = (void *)data; - - /* Service the RDS fifo */ - if (mutex_trylock(&dev->lock)) { - outb(0x3, dev->io); /* Select RDS Decoder Control */ - if ((inb(dev->io + 1) & 0x20) != 0) - printk(KERN_CRIT "cadet: RDS fifo overflow\n"); - outb(0x80, dev->io); /* Select RDS fifo */ - while ((inb(dev->io) & 0x80) != 0) { - dev->rdsbuf[dev->rdsin] = inb(dev->io + 1); - if (dev->rdsin == dev->rdsout) - printk(KERN_WARNING "cadet: RDS buffer overflow\n"); - else - dev->rdsin++; - } - mutex_unlock(&dev->lock); - } - - /* - * Service pending read - */ - if (dev->rdsin != dev->rdsout) - wake_up_interruptible(&dev->read_queue); - - /* - * Clean up and exit - */ - init_timer(&dev->readtimer); - dev->readtimer.function = cadet_handler; - dev->readtimer.data = (unsigned long)0; - dev->readtimer.expires = jiffies + msecs_to_jiffies(50); - add_timer(&dev->readtimer); -} - - -static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct cadet *dev = video_drvdata(file); - unsigned char readbuf[RDS_BUFFER]; - int i = 0; - - mutex_lock(&dev->lock); - if (dev->rdsstat == 0) { - dev->rdsstat = 1; - outb(0x80, dev->io); /* Select RDS fifo */ - init_timer(&dev->readtimer); - dev->readtimer.function = cadet_handler; - dev->readtimer.data = (unsigned long)dev; - dev->readtimer.expires = jiffies + msecs_to_jiffies(50); - add_timer(&dev->readtimer); - } - if (dev->rdsin == dev->rdsout) { - mutex_unlock(&dev->lock); - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - interruptible_sleep_on(&dev->read_queue); - mutex_lock(&dev->lock); - } - while (i < count && dev->rdsin != dev->rdsout) - readbuf[i++] = dev->rdsbuf[dev->rdsout++]; - mutex_unlock(&dev->lock); - - if (copy_to_user(data, readbuf, i)) - return -EFAULT; - return i; -} - - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "ADS Cadet", sizeof(v->driver)); - strlcpy(v->card, "ADS Cadet", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = CADET_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | - V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct cadet *dev = video_drvdata(file); - - v->type = V4L2_TUNER_RADIO; - switch (v->index) { - case 0: - strlcpy(v->name, "FM", sizeof(v->name)); - v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_RDS_BLOCK_IO; - v->rangelow = 1400; /* 87.5 MHz */ - v->rangehigh = 1728; /* 108.0 MHz */ - v->rxsubchans = cadet_getstereo(dev); - switch (v->rxsubchans) { - case V4L2_TUNER_SUB_MONO: - v->audmode = V4L2_TUNER_MODE_MONO; - break; - case V4L2_TUNER_SUB_STEREO: - v->audmode = V4L2_TUNER_MODE_STEREO; - break; - default: - break; - } - v->rxsubchans |= V4L2_TUNER_SUB_RDS; - break; - case 1: - strlcpy(v->name, "AM", sizeof(v->name)); - v->capability = V4L2_TUNER_CAP_LOW; - v->rangelow = 8320; /* 520 kHz */ - v->rangehigh = 26400; /* 1650 kHz */ - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->audmode = V4L2_TUNER_MODE_MONO; - break; - default: - return -EINVAL; - } - v->signal = dev->sigstrength; /* We might need to modify scaling of this */ - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct cadet *dev = video_drvdata(file); - - if (v->index != 0 && v->index != 1) - return -EINVAL; - dev->curtuner = v->index; - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cadet *dev = video_drvdata(file); - - f->tuner = dev->curtuner; - f->type = V4L2_TUNER_RADIO; - f->frequency = cadet_getfreq(dev); - return 0; -} - - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cadet *dev = video_drvdata(file); - - if (f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (dev->curtuner == 0 && (f->frequency < 1400 || f->frequency > 1728)) - return -EINVAL; - if (dev->curtuner == 1 && (f->frequency < 8320 || f->frequency > 26400)) - return -EINVAL; - cadet_setfreq(dev, f->frequency); - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct cadet *dev = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ - ctrl->value = (cadet_getvol(dev) == 0); - break; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = cadet_getvol(dev); - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct cadet *dev = video_drvdata(file); - - switch (ctrl->id){ - case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ - if (ctrl->value) - cadet_setvol(dev, 0); - else - cadet_setvol(dev, 0xffff); - break; - case V4L2_CID_AUDIO_VOLUME: - cadet_setvol(dev, ctrl->value); - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static int cadet_open(struct file *file) -{ - struct cadet *dev = video_drvdata(file); - - mutex_lock(&dev->lock); - dev->users++; - if (1 == dev->users) - init_waitqueue_head(&dev->read_queue); - mutex_unlock(&dev->lock); - return 0; -} - -static int cadet_release(struct file *file) -{ - struct cadet *dev = video_drvdata(file); - - mutex_lock(&dev->lock); - dev->users--; - if (0 == dev->users) { - del_timer_sync(&dev->readtimer); - dev->rdsstat = 0; - } - mutex_unlock(&dev->lock); - return 0; -} - -static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait) -{ - struct cadet *dev = video_drvdata(file); - - poll_wait(file, &dev->read_queue, wait); - if (dev->rdsin != dev->rdsout) - return POLLIN | POLLRDNORM; - return 0; -} - - -static const struct v4l2_file_operations cadet_fops = { - .owner = THIS_MODULE, - .open = cadet_open, - .release = cadet_release, - .read = cadet_read, - .unlocked_ioctl = video_ioctl2, - .poll = cadet_poll, -}; - -static const struct v4l2_ioctl_ops cadet_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, -}; - -#ifdef CONFIG_PNP - -static struct pnp_device_id cadet_pnp_devices[] = { - /* ADS Cadet AM/FM Radio Card */ - {.id = "MSM0c24", .driver_data = 0}, - {.id = ""} -}; - -MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices); - -static int cadet_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) -{ - if (!dev) - return -ENODEV; - /* only support one device */ - if (io > 0) - return -EBUSY; - - if (!pnp_port_valid(dev, 0)) - return -ENODEV; - - io = pnp_port_start(dev, 0); - - printk(KERN_INFO "radio-cadet: PnP reports device at %#x\n", io); - - return io; -} - -static struct pnp_driver cadet_pnp_driver = { - .name = "radio-cadet", - .id_table = cadet_pnp_devices, - .probe = cadet_pnp_probe, - .remove = NULL, -}; - -#else -static struct pnp_driver cadet_pnp_driver; -#endif - -static void cadet_probe(struct cadet *dev) -{ - static int iovals[8] = { 0x330, 0x332, 0x334, 0x336, 0x338, 0x33a, 0x33c, 0x33e }; - int i; - - for (i = 0; i < 8; i++) { - dev->io = iovals[i]; - if (request_region(dev->io, 2, "cadet-probe")) { - cadet_setfreq(dev, 1410); - if (cadet_getfreq(dev) == 1410) { - release_region(dev->io, 2); - return; - } - release_region(dev->io, 2); - } - } - dev->io = -1; -} - -/* - * io should only be set if the user has used something like - * isapnp (the userspace program) to initialize this card for us - */ - -static int __init cadet_init(void) -{ - struct cadet *dev = &cadet_card; - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name)); - mutex_init(&dev->lock); - - /* If a probe was requested then probe ISAPnP first (safest) */ - if (io < 0) - pnp_register_driver(&cadet_pnp_driver); - dev->io = io; - - /* If that fails then probe unsafely if probe is requested */ - if (dev->io < 0) - cadet_probe(dev); - - /* Else we bail out */ - if (dev->io < 0) { -#ifdef MODULE - v4l2_err(v4l2_dev, "you must set an I/O address with io=0x330, 0x332, 0x334,\n"); - v4l2_err(v4l2_dev, "0x336, 0x338, 0x33a, 0x33c or 0x33e\n"); -#endif - goto fail; - } - if (!request_region(dev->io, 2, "cadet")) - goto fail; - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(dev->io, 2); - v4l2_err(v4l2_dev, "could not register v4l2_device\n"); - goto fail; - } - - strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; - dev->vdev.fops = &cadet_fops; - dev->vdev.ioctl_ops = &cadet_ioctl_ops; - dev->vdev.release = video_device_release_empty; - video_set_drvdata(&dev->vdev, dev); - - if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(dev->io, 2); - goto fail; - } - v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io); - return 0; -fail: - pnp_unregister_driver(&cadet_pnp_driver); - return -ENODEV; -} - -static void __exit cadet_exit(void) -{ - struct cadet *dev = &cadet_card; - - video_unregister_device(&dev->vdev); - v4l2_device_unregister(&dev->v4l2_dev); - release_region(dev->io, 2); - pnp_unregister_driver(&cadet_pnp_driver); -} - -module_init(cadet_init); -module_exit(cadet_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-gemtek.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-gemtek.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-gemtek.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-gemtek.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,617 +0,0 @@ -/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin - * - * GemTek hasn't released any specs on the card, so the protocol had to - * be reverse engineered with dosemu. - * - * Besides the protocol changes, this is mostly a copy of: - * - * RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff - * - * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood - * Converted to new API by Alan Cox - * Various bugfixes and enhancements by Russell Kroll - * - * TODO: Allow for more than one of these foolish entities :-) - * - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* udelay */ -#include /* kernel radio structs */ -#include /* for KERNEL_VERSION MACRO */ -#include -#include /* outb, outb_p */ -#include -#include - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 3) - -/* - * Module info. - */ - -MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen "); -MODULE_DESCRIPTION("A driver for the GemTek Radio card."); -MODULE_LICENSE("GPL"); - -/* - * Module params. - */ - -#ifndef CONFIG_RADIO_GEMTEK_PORT -#define CONFIG_RADIO_GEMTEK_PORT -1 -#endif -#ifndef CONFIG_RADIO_GEMTEK_PROBE -#define CONFIG_RADIO_GEMTEK_PROBE 1 -#endif - -static int io = CONFIG_RADIO_GEMTEK_PORT; -static int probe = CONFIG_RADIO_GEMTEK_PROBE; -static int hardmute; -static int shutdown = 1; -static int keepmuted = 1; -static int initmute = 1; -static int radio_nr = -1; - -module_param(io, int, 0444); -MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " - "probing is disabled or fails. The most common I/O ports are: 0x20c " - "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " - "work for the combined sound/radiocard)."); - -module_param(probe, bool, 0444); -MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " - "common I/O ports used by the card are probed."); - -module_param(hardmute, bool, 0644); -MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may " - "reduce static noise."); - -module_param(shutdown, bool, 0644); -MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when " - "module is unloaded."); - -module_param(keepmuted, bool, 0644); -MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed."); - -module_param(initmute, bool, 0444); -MODULE_PARM_DESC(initmute, "Mute card when module is loaded."); - -module_param(radio_nr, int, 0444); - -/* - * Functions for controlling the card. - */ -#define GEMTEK_LOWFREQ (87*16000) -#define GEMTEK_HIGHFREQ (108*16000) - -/* - * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal - * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz). - */ -#define FSCALE 8 -#define IF_OFFSET ((unsigned int)(10.52 * 16000 * (1<bu2614data = \ - ((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT)) - -/* - * Transmit settings to BU2614FS over GemTek IC. - */ -static void gemtek_bu2614_transmit(struct gemtek *gt) -{ - int i, bit, q, mute; - - mutex_lock(>->lock); - - mute = gt->muted ? GEMTEK_MT : 0x00; - - outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); - udelay(LONG_DELAY); - - for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) { - bit = (q & 1) ? GEMTEK_DA : 0; - outb_p(mute | GEMTEK_CE | bit, gt->io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io); - udelay(SHORT_DELAY); - } - - outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); - udelay(LONG_DELAY); - - mutex_unlock(>->lock); -} - -/* - * Calculate divisor from FM-frequency for BU2614FS (3.125 KHz STDF expected). - */ -static unsigned long gemtek_convfreq(unsigned long freq) -{ - return ((freq<muted) - return; - - freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ); - - gt->lastfreq = freq; - gt->muted = 0; - - gemtek_bu2614_set(gt, BU2614_PORT, 0); - gemtek_bu2614_set(gt, BU2614_FMES, 0); - gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */ - gemtek_bu2614_set(gt, BU2614_SWAL, 0); - gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */ - gemtek_bu2614_set(gt, BU2614_TEST, 0); - - gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); - gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq)); - - gemtek_bu2614_transmit(gt); -} - -/* - * Set mute flag. - */ -static void gemtek_mute(struct gemtek *gt) -{ - int i; - - gt->muted = 1; - - if (hardmute) { - /* Turn off PLL, disable data output */ - gemtek_bu2614_set(gt, BU2614_PORT, 0); - gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */ - gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */ - gemtek_bu2614_set(gt, BU2614_SWAL, 0); - gemtek_bu2614_set(gt, BU2614_FMUN, 0); /* GT bit off */ - gemtek_bu2614_set(gt, BU2614_TEST, 0); - gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF); - gemtek_bu2614_set(gt, BU2614_FREQ, 0); - gemtek_bu2614_transmit(gt); - return; - } - - mutex_lock(>->lock); - - /* Read bus contents (CE, CK and DA). */ - i = inb_p(gt->io); - /* Write it back with mute flag set. */ - outb_p((i >> 5) | GEMTEK_MT, gt->io); - udelay(SHORT_DELAY); - - mutex_unlock(>->lock); -} - -/* - * Unset mute flag. - */ -static void gemtek_unmute(struct gemtek *gt) -{ - int i; - - gt->muted = 0; - if (hardmute) { - /* Turn PLL back on. */ - gemtek_setfreq(gt, gt->lastfreq); - return; - } - mutex_lock(>->lock); - - i = inb_p(gt->io); - outb_p(i >> 5, gt->io); - udelay(SHORT_DELAY); - - mutex_unlock(>->lock); -} - -/* - * Get signal strength (= stereo status). - */ -static inline int gemtek_getsigstr(struct gemtek *gt) -{ - int sig; - - mutex_lock(>->lock); - sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1; - mutex_unlock(>->lock); - return sig; -} - -/* - * Check if requested card acts like GemTek Radio card. - */ -static int gemtek_verify(struct gemtek *gt, int port) -{ - int i, q; - - if (gt->verified == port) - return 1; - - mutex_lock(>->lock); - - q = inb_p(port); /* Read bus contents before probing. */ - /* Try to turn on CE, CK and DA respectively and check if card responds - properly. */ - for (i = 0; i < 3; ++i) { - outb_p(1 << i, port); - udelay(SHORT_DELAY); - - if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) { - mutex_unlock(>->lock); - return 0; - } - } - outb_p(q >> 5, port); /* Write bus contents back. */ - udelay(SHORT_DELAY); - - mutex_unlock(>->lock); - gt->verified = port; - - return 1; -} - -/* - * Automatic probing for card. - */ -static int gemtek_probe(struct gemtek *gt) -{ - struct v4l2_device *v4l2_dev = >->v4l2_dev; - int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; - int i; - - if (!probe) { - v4l2_info(v4l2_dev, "Automatic device probing disabled.\n"); - return -1; - } - - v4l2_info(v4l2_dev, "Automatic device probing enabled.\n"); - - for (i = 0; i < ARRAY_SIZE(ioports); ++i) { - v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]); - - if (!request_region(ioports[i], 1, "gemtek-probe")) { - v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n", - ioports[i]); - continue; - } - - if (gemtek_verify(gt, ioports[i])) { - v4l2_info(v4l2_dev, "Card found from I/O port " - "0x%x!\n", ioports[i]); - - release_region(ioports[i], 1); - gt->io = ioports[i]; - return gt->io; - } - - release_region(ioports[i], 1); - } - - v4l2_err(v4l2_dev, "Automatic probing failed!\n"); - return -1; -} - -/* - * Video 4 Linux stuff. - */ - -static const struct v4l2_file_operations gemtek_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); - strlcpy(v->card, "GemTek", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) -{ - struct gemtek *gt = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = GEMTEK_LOWFREQ; - v->rangehigh = GEMTEK_HIGHFREQ; - v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - v->signal = 0xffff * gemtek_getsigstr(gt); - if (v->signal) { - v->audmode = V4L2_TUNER_MODE_STEREO; - v->rxsubchans = V4L2_TUNER_SUB_STEREO; - } else { - v->audmode = V4L2_TUNER_MODE_MONO; - v->rxsubchans = V4L2_TUNER_SUB_MONO; - } - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) -{ - return (v->index != 0) ? -EINVAL : 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct gemtek *gt = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = gt->lastfreq; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct gemtek *gt = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - gemtek_setfreq(gt, f->frequency); - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - default: - return -EINVAL; - } -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct gemtek *gt = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = gt->muted; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct gemtek *gt = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - gemtek_mute(gt); - else - gemtek_unmute(gt); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return (i != 0) ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - return (a->index != 0) ? -EINVAL : 0; -} - -static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl -}; - -/* - * Initialization / cleanup related stuff. - */ - -static int __init gemtek_init(void) -{ - struct gemtek *gt = &gemtek_card; - struct v4l2_device *v4l2_dev = >->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name)); - - v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n"); - - mutex_init(>->lock); - - gt->verified = -1; - gt->io = io; - gemtek_probe(gt); - if (gt->io) { - if (!request_region(gt->io, 1, "gemtek")) { - v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io); - return -EBUSY; - } - - if (!gemtek_verify(gt, gt->io)) - v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not " - "respond properly, check your " - "configuration.\n", gt->io); - else - v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io); - } else if (probe) { - v4l2_err(v4l2_dev, "Automatic probing failed and no " - "fixed I/O port defined.\n"); - return -ENODEV; - } else { - v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed " - "I/O port defined."); - return -EINVAL; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - release_region(gt->io, 1); - return res; - } - - strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name)); - gt->vdev.v4l2_dev = v4l2_dev; - gt->vdev.fops = &gemtek_fops; - gt->vdev.ioctl_ops = &gemtek_ioctl_ops; - gt->vdev.release = video_device_release_empty; - video_set_drvdata(>->vdev, gt); - - /* Set defaults */ - gt->lastfreq = GEMTEK_LOWFREQ; - gt->bu2614data = 0; - - if (initmute) - gemtek_mute(gt); - - if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(gt->io, 1); - return -EBUSY; - } - - return 0; -} - -/* - * Module cleanup - */ -static void __exit gemtek_exit(void) -{ - struct gemtek *gt = &gemtek_card; - struct v4l2_device *v4l2_dev = >->v4l2_dev; - - if (shutdown) { - hardmute = 1; /* Turn off PLL */ - gemtek_mute(gt); - } else { - v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n"); - } - - video_unregister_device(>->vdev); - v4l2_device_unregister(>->v4l2_dev); - release_region(gt->io, 1); -} - -module_init(gemtek_init); -module_exit(gemtek_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-maestro.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-maestro.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-maestro.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-maestro.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,452 +0,0 @@ -/* Maestro PCI sound card radio driver for Linux support - * (c) 2000 A. Tlalka, atlka@pg.gda.pl - * Notes on the hardware - * - * + Frequency control is done digitally - * + No volume control - only mute/unmute - you have to use Aux line volume - * control on Maestro card to set the volume - * + Radio status (tuned/not_tuned and stereo/mono) is valid some time after - * frequency setting (>100ms) and only when the radio is unmuted. - * version 0.02 - * + io port is automatically detected - only the first radio is used - * version 0.03 - * + thread access locking additions - * version 0.04 - * + code improvements - * + VIDEO_TUNER_LOW is permanent - * - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -#include -#include -#include -#include -#include /* for KERNEL_VERSION MACRO */ -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl"); -MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio."); -MODULE_LICENSE("GPL"); - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 6) -#define DRIVER_VERSION "0.06" - -#define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */ - -#define IO_MASK 4 /* mask register offset from GPIO_DATA - bits 1=unmask write to given bit */ -#define IO_DIR 8 /* direction register offset from GPIO_DATA - bits 0/1=read/write direction */ - -#define GPIO6 0x0040 /* mask bits for GPIO lines */ -#define GPIO7 0x0080 -#define GPIO8 0x0100 -#define GPIO9 0x0200 - -#define STR_DATA GPIO6 /* radio TEA5757 pins and GPIO bits */ -#define STR_CLK GPIO7 -#define STR_WREN GPIO8 -#define STR_MOST GPIO9 - -#define FREQ_LO 50*16000 -#define FREQ_HI 150*16000 - -#define FREQ_IF 171200 /* 10.7*16000 */ -#define FREQ_STEP 200 /* 12.5*16 */ - -#define FREQ2BITS(x) ((((unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\ - /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */ - -#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) - -struct maestro { - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct pci_dev *pdev; - struct mutex lock; - - u16 io; /* base of Maestro card radio io (GPIO_DATA)*/ - u16 muted; /* VIDEO_AUDIO_MUTE */ - u16 stereo; /* VIDEO_TUNER_STEREO_ON */ - u16 tuned; /* signal strength (0 or 0xffff) */ -}; - -static inline struct maestro *to_maestro(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct maestro, v4l2_dev); -} - -static u32 radio_bits_get(struct maestro *dev) -{ - u16 io = dev->io, l, rdata; - u32 data = 0; - u16 omask; - - omask = inw(io + IO_MASK); - outw(~(STR_CLK | STR_WREN), io + IO_MASK); - outw(0, io); - udelay(16); - - for (l = 24; l--;) { - outw(STR_CLK, io); /* HI state */ - udelay(2); - if (!l) - dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff; - outw(0, io); /* LO state */ - udelay(2); - data <<= 1; /* shift data */ - rdata = inw(io); - if (!l) - dev->stereo = (rdata & STR_MOST) ? 0 : 1; - else if (rdata & STR_DATA) - data++; - udelay(2); - } - - if (dev->muted) - outw(STR_WREN, io); - - udelay(4); - outw(omask, io + IO_MASK); - - return data & 0x3ffe; -} - -static void radio_bits_set(struct maestro *dev, u32 data) -{ - u16 io = dev->io, l, bits; - u16 omask, odir; - - omask = inw(io + IO_MASK); - odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); - outw(odir | STR_DATA, io + IO_DIR); - outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); - udelay(16); - for (l = 25; l; l--) { - bits = ((data >> 18) & STR_DATA) | STR_WREN; - data <<= 1; /* shift data */ - outw(bits, io); /* start strobe */ - udelay(2); - outw(bits | STR_CLK, io); /* HI level */ - udelay(2); - outw(bits, io); /* LO level */ - udelay(4); - } - - if (!dev->muted) - outw(0, io); - - udelay(4); - outw(omask, io + IO_MASK); - outw(odir, io + IO_DIR); - msleep(125); -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - struct maestro *dev = video_drvdata(file); - - strlcpy(v->driver, "radio-maestro", sizeof(v->driver)); - strlcpy(v->card, "Maestro Radio", sizeof(v->card)); - snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct maestro *dev = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - mutex_lock(&dev->lock); - radio_bits_get(dev); - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = FREQ_LO; - v->rangehigh = FREQ_HI; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if (dev->stereo) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = dev->tuned; - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct maestro *dev = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) - return -EINVAL; - mutex_lock(&dev->lock); - radio_bits_set(dev, FREQ2BITS(f->frequency)); - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct maestro *dev = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - mutex_lock(&dev->lock); - f->frequency = BITS2FREQ(radio_bits_get(dev)); - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct maestro *dev = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = dev->muted; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct maestro *dev = video_drvdata(file); - u16 io = dev->io; - u16 omask; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - mutex_lock(&dev->lock); - omask = inw(io + IO_MASK); - outw(~STR_WREN, io + IO_MASK); - dev->muted = ctrl->value; - outw(dev->muted ? STR_WREN : 0, io); - udelay(4); - outw(omask, io + IO_MASK); - msleep(125); - mutex_unlock(&dev->lock); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static const struct v4l2_file_operations maestro_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops maestro_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static u16 __devinit radio_power_on(struct maestro *dev) -{ - register u16 io = dev->io; - register u32 ofreq; - u16 omask, odir; - - omask = inw(io + IO_MASK); - odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); - outw(odir & ~STR_WREN, io + IO_DIR); - dev->muted = inw(io) & STR_WREN ? 0 : 1; - outw(odir, io + IO_DIR); - outw(~(STR_WREN | STR_CLK), io + IO_MASK); - outw(dev->muted ? 0 : STR_WREN, io); - udelay(16); - outw(omask, io + IO_MASK); - ofreq = radio_bits_get(dev); - - if ((ofreq < FREQ2BITS(FREQ_LO)) || (ofreq > FREQ2BITS(FREQ_HI))) - ofreq = FREQ2BITS(FREQ_LO); - radio_bits_set(dev, ofreq); - - return (ofreq == radio_bits_get(dev)); -} - -static int __devinit maestro_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct maestro *dev; - struct v4l2_device *v4l2_dev; - int retval; - - retval = pci_enable_device(pdev); - if (retval) { - dev_err(&pdev->dev, "enabling pci device failed!\n"); - goto err; - } - - retval = -ENOMEM; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&pdev->dev, "not enough memory\n"); - goto err; - } - - v4l2_dev = &dev->v4l2_dev; - mutex_init(&dev->lock); - dev->pdev = pdev; - - strlcpy(v4l2_dev->name, "maestro", sizeof(v4l2_dev->name)); - - retval = v4l2_device_register(&pdev->dev, v4l2_dev); - if (retval < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - goto errfr; - } - - dev->io = pci_resource_start(pdev, 0) + GPIO_DATA; - - strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; - dev->vdev.fops = &maestro_fops; - dev->vdev.ioctl_ops = &maestro_ioctl_ops; - dev->vdev.release = video_device_release_empty; - video_set_drvdata(&dev->vdev, dev); - - if (!radio_power_on(dev)) { - retval = -EIO; - goto errfr1; - } - - retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr); - if (retval) { - v4l2_err(v4l2_dev, "can't register video device!\n"); - goto errfr1; - } - - v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n"); - - return 0; -errfr1: - v4l2_device_unregister(v4l2_dev); -errfr: - kfree(dev); -err: - return retval; - -} - -static void __devexit maestro_remove(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct maestro *dev = to_maestro(v4l2_dev); - - video_unregister_device(&dev->vdev); - v4l2_device_unregister(&dev->v4l2_dev); -} - -static struct pci_device_id maestro_r_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968), - .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, - .class_mask = 0xffff00 }, - { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978), - .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, - .class_mask = 0xffff00 }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl); - -static struct pci_driver maestro_r_driver = { - .name = "maestro_radio", - .id_table = maestro_r_pci_tbl, - .probe = maestro_probe, - .remove = __devexit_p(maestro_remove), -}; - -static int __init maestro_radio_init(void) -{ - int retval = pci_register_driver(&maestro_r_driver); - - if (retval) - printk(KERN_ERR "error during registration pci driver\n"); - - return retval; -} - -static void __exit maestro_radio_exit(void) -{ - pci_unregister_driver(&maestro_r_driver); -} - -module_init(maestro_radio_init); -module_exit(maestro_radio_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-maxiradio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-maxiradio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-maxiradio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-maxiradio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,467 +0,0 @@ -/* - * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux - * (C) 2001 Dimitromanolakis Apostolos - * - * Based in the radio Maestro PCI driver. Actually it uses the same chip - * for radio but different pci controller. - * - * I didn't have any specs I reversed engineered the protocol from - * the windows driver (radio.dll). - * - * The card uses the TEA5757 chip that includes a search function but it - * is useless as I haven't found any way to read back the frequency. If - * anybody does please mail me. - * - * For the pdf file see: - * http://www.nxp.com/acrobat_download2/expired_datasheets/TEA5757_5759_3.pdf - * - * - * CHANGES: - * 0.75b - * - better pci interface thanks to Francois Romieu - * - * 0.75 Sun Feb 4 22:51:27 EET 2001 - * - tiding up - * - removed support for multiple devices as it didn't work anyway - * - * BUGS: - * - card unmutes if you change frequency - * - * (c) 2006, 2007 by Mauro Carvalho Chehab : - * - Conversion to V4L2 API - * - Uses video_ioctl2 for parsing and to add debug support - */ - - -#include -#include -#include -#include -#include -#include -#include -#include /* for KERNEL_VERSION MACRO */ -#include -#include -#include -#include - -MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); -MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); -MODULE_LICENSE("GPL"); - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); - -#define DRIVER_VERSION "0.77" - -#define RADIO_VERSION KERNEL_VERSION(0, 7, 7) - -#define dprintk(dev, num, fmt, arg...) \ - v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg) - -#ifndef PCI_VENDOR_ID_GUILLEMOT -#define PCI_VENDOR_ID_GUILLEMOT 0x5046 -#endif - -#ifndef PCI_DEVICE_ID_GUILLEMOT -#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 -#endif - - -/* TEA5757 pin mappings */ -static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; - -#define FREQ_LO (87 * 16000) -#define FREQ_HI (108 * 16000) - -#define FREQ_IF 171200 /* 10.7*16000 */ -#define FREQ_STEP 200 /* 12.5*16 */ - -/* (x==fmhz*16*1000) -> bits */ -#define FREQ2BITS(x) \ - ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2) - -#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) - - -struct maxiradio -{ - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct pci_dev *pdev; - - u16 io; /* base of radio io */ - u16 muted; /* VIDEO_AUDIO_MUTE */ - u16 stereo; /* VIDEO_TUNER_STEREO_ON */ - u16 tuned; /* signal strength (0 or 0xffff) */ - - unsigned long freq; - - struct mutex lock; -}; - -static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct maxiradio, v4l2_dev); -} - -static void outbit(unsigned long bit, u16 io) -{ - int val = power | wren | (bit ? data : 0); - - outb(val, io); - udelay(4); - outb(val | clk, io); - udelay(4); - outb(val, io); - udelay(4); -} - -static void turn_power(struct maxiradio *dev, int p) -{ - if (p != 0) { - dprintk(dev, 1, "Radio powered on\n"); - outb(power, dev->io); - } else { - dprintk(dev, 1, "Radio powered off\n"); - outb(0, dev->io); - } -} - -static void set_freq(struct maxiradio *dev, u32 freq) -{ - unsigned long int si; - int bl; - int io = dev->io; - int val = FREQ2BITS(freq); - - /* TEA5757 shift register bits (see pdf) */ - - outbit(0, io); /* 24 search */ - outbit(1, io); /* 23 search up/down */ - - outbit(0, io); /* 22 stereo/mono */ - - outbit(0, io); /* 21 band */ - outbit(0, io); /* 20 band (only 00=FM works I think) */ - - outbit(0, io); /* 19 port ? */ - outbit(0, io); /* 18 port ? */ - - outbit(0, io); /* 17 search level */ - outbit(0, io); /* 16 search level */ - - si = 0x8000; - for (bl = 1; bl <= 16; bl++) { - outbit(val & si, io); - si >>= 1; - } - - dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n", - freq / 16000, - freq % 16000 * 100 / 16000); - - turn_power(dev, 1); -} - -static int get_stereo(u16 io) -{ - outb(power,io); - udelay(4); - - return !(inb(io) & mo_st); -} - -static int get_tune(u16 io) -{ - outb(power+clk,io); - udelay(4); - - return !(inb(io) & mo_st); -} - - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - struct maxiradio *dev = video_drvdata(file); - - strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver)); - strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card)); - snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct maxiradio *dev = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - mutex_lock(&dev->lock); - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = FREQ_LO; - v->rangehigh = FREQ_HI; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if (get_stereo(dev->io)) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff * get_tune(dev->io); - mutex_unlock(&dev->lock); - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct maxiradio *dev = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { - dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", - f->frequency / 16000, - f->frequency % 16000 * 100 / 16000, - FREQ_LO / 16000, FREQ_HI / 16000); - - return -EINVAL; - } - - mutex_lock(&dev->lock); - dev->freq = f->frequency; - set_freq(dev, dev->freq); - msleep(125); - mutex_unlock(&dev->lock); - - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct maxiradio *dev = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = dev->freq; - - dprintk(dev, 4, "radio freq is %d.%02d MHz", - f->frequency / 16000, - f->frequency % 16000 * 100 / 16000); - - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct maxiradio *dev = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = dev->muted; - return 0; - } - - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct maxiradio *dev = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - mutex_lock(&dev->lock); - dev->muted = ctrl->value; - if (dev->muted) - turn_power(dev, 0); - else - set_freq(dev, dev->freq); - mutex_unlock(&dev->lock); - return 0; - } - - return -EINVAL; -} - -static const struct v4l2_file_operations maxiradio_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct maxiradio *dev; - struct v4l2_device *v4l2_dev; - int retval = -ENOMEM; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&pdev->dev, "not enough memory\n"); - return -ENOMEM; - } - - v4l2_dev = &dev->v4l2_dev; - mutex_init(&dev->lock); - dev->pdev = pdev; - dev->muted = 1; - dev->freq = FREQ_LO; - - strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name)); - - retval = v4l2_device_register(&pdev->dev, v4l2_dev); - if (retval < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - goto errfr; - } - - if (!request_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { - v4l2_err(v4l2_dev, "can't reserve I/O ports\n"); - goto err_out; - } - - if (pci_enable_device(pdev)) - goto err_out_free_region; - - dev->io = pci_resource_start(pdev, 0); - strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; - dev->vdev.fops = &maxiradio_fops; - dev->vdev.ioctl_ops = &maxiradio_ioctl_ops; - dev->vdev.release = video_device_release_empty; - video_set_drvdata(&dev->vdev, dev); - - if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_err(v4l2_dev, "can't register device!"); - goto err_out_free_region; - } - - v4l2_info(v4l2_dev, "version " DRIVER_VERSION - " time " __TIME__ " " __DATE__ "\n"); - - v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n", - dev->io); - return 0; - -err_out_free_region: - release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); -err_out: - v4l2_device_unregister(v4l2_dev); -errfr: - kfree(dev); - return -ENODEV; -} - -static void __devexit maxiradio_remove_one(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct maxiradio *dev = to_maxiradio(v4l2_dev); - - video_unregister_device(&dev->vdev); - v4l2_device_unregister(&dev->v4l2_dev); - release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); -} - -static struct pci_device_id maxiradio_pci_tbl[] = { - { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO, - PCI_ANY_ID, PCI_ANY_ID, }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl); - -static struct pci_driver maxiradio_driver = { - .name = "radio-maxiradio", - .id_table = maxiradio_pci_tbl, - .probe = maxiradio_init_one, - .remove = __devexit_p(maxiradio_remove_one), -}; - -static int __init maxiradio_radio_init(void) -{ - return pci_register_driver(&maxiradio_driver); -} - -static void __exit maxiradio_radio_exit(void) -{ - pci_unregister_driver(&maxiradio_driver); -} - -module_init(maxiradio_radio_init); -module_exit(maxiradio_radio_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-miropcm20.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-miropcm20.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-miropcm20.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-miropcm20.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,272 +0,0 @@ -/* Miro PCM20 radio driver for Linux radio support - * (c) 1998 Ruurd Reitsma - * Thanks to Norberto Pellici for the ACI device interface specification - * The API part is based on the radiotrack driver by M. Kirkwood - * This driver relies on the aci mixer provided by the snd-miro - * ALSA driver. - * Look there for further info... - */ - -/* What ever you think about the ACI, version 0x07 is not very well! - * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono - * conditions... Robert - */ - -#include -#include -#include -#include -#include -#include - -static int radio_nr = -1; -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); - -static int mono; -module_param(mono, bool, 0); -MODULE_PARM_DESC(mono, "Force tuner into mono mode."); - -struct pcm20 { - struct v4l2_device v4l2_dev; - struct video_device vdev; - unsigned long freq; - int muted; - struct snd_miro_aci *aci; - struct mutex lock; -}; - -static struct pcm20 pcm20_card = { - .freq = 87*16000, - .muted = 1, -}; - -static int pcm20_mute(struct pcm20 *dev, unsigned char mute) -{ - dev->muted = mute; - return snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, mute, -1); -} - -static int pcm20_stereo(struct pcm20 *dev, unsigned char stereo) -{ - return snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, !stereo, -1); -} - -static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) -{ - unsigned char freql; - unsigned char freqh; - struct snd_miro_aci *aci = dev->aci; - - dev->freq = freq; - - freq /= 160; - if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0)) - freq /= 10; /* I don't know exactly which version - * needs this hack */ - freql = freq & 0xff; - freqh = freq >> 8; - - pcm20_stereo(dev, !mono); - return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh); -} - -static const struct v4l2_file_operations pcm20_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "Miro PCM20", sizeof(v->driver)); - strlcpy(v->card, "Miro PCM20", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = 0x1; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index) /* Only 1 tuner */ - return -EINVAL; - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = 87*16000; - v->rangehigh = 108*16000; - v->signal = 0xffff; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct pcm20 *dev = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - - f->type = V4L2_TUNER_RADIO; - f->frequency = dev->freq; - return 0; -} - - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct pcm20 *dev = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - - dev->freq = f->frequency; - pcm20_setfreq(dev, f->frequency); - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct pcm20 *dev = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = dev->muted; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct pcm20 *dev = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - pcm20_mute(dev, ctrl->value); - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static const struct v4l2_ioctl_ops pcm20_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, -}; - -static int __init pcm20_init(void) -{ - struct pcm20 *dev = &pcm20_card; - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - int res; - - dev->aci = snd_aci_get_aci(); - if (dev->aci == NULL) { - v4l2_err(v4l2_dev, - "you must load the snd-miro driver first!\n"); - return -ENODEV; - } - strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name)); - mutex_init(&dev->lock); - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - v4l2_err(v4l2_dev, "could not register v4l2_device\n"); - return -EINVAL; - } - - strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; - dev->vdev.fops = &pcm20_fops; - dev->vdev.ioctl_ops = &pcm20_ioctl_ops; - dev->vdev.release = video_device_release_empty; - dev->vdev.lock = &dev->lock; - video_set_drvdata(&dev->vdev, dev); - - if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) - goto fail; - - v4l2_info(v4l2_dev, "Mirosound PCM20 Radio tuner\n"); - return 0; -fail: - v4l2_device_unregister(v4l2_dev); - return -EINVAL; -} - -MODULE_AUTHOR("Ruurd Reitsma, Krzysztof Helt"); -MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); -MODULE_LICENSE("GPL"); - -static void __exit pcm20_cleanup(void) -{ - struct pcm20 *dev = &pcm20_card; - - video_unregister_device(&dev->vdev); - v4l2_device_unregister(&dev->v4l2_dev); -} - -module_init(pcm20_init); -module_exit(pcm20_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-mr800.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-mr800.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-mr800.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-mr800.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,685 +0,0 @@ -/* - * A driver for the AverMedia MR 800 USB FM radio. This device plugs - * into both the USB and an analog audio input, so this thing - * only deals with initialization and frequency setting, the - * audio data has to be handled by a sound driver. - * - * Copyright (c) 2008 Alexey Klimov - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -/* - * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c - * - * When work was looked pretty good, i discover this: - * http://av-usbradio.sourceforge.net/index.php - * http://sourceforge.net/projects/av-usbradio/ - * Latest release of theirs project was in 2005. - * Probably, this driver could be improved through using their - * achievements (specifications given). - * Also, Faidon Liambotis wrote nice driver for this radio - * in 2007. He allowed to use his driver to improve current mr800 radio driver. - * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492 - * - * Version 0.01: First working version. - * It's required to blacklist AverMedia USB Radio - * in usbhid/hid-quirks.c - * Version 0.10: A lot of cleanups and fixes: unpluging the device, - * few mutex locks were added, codinstyle issues, etc. - * Added stereo support. Thanks to - * Douglas Schilling Landgraf and - * David Ellingsworth - * for discussion, help and support. - * Version 0.11: Converted to v4l2_device. - * - * Many things to do: - * - Correct power management of device (suspend & resume) - * - Add code for scanning and smooth tuning - * - Add code for sensitivity value - * - Correct mistakes - * - In Japan another FREQ_MIN and FREQ_MAX - */ - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for KERNEL_VERSION MACRO */ -#include - -/* driver and module definitions */ -#define DRIVER_AUTHOR "Alexey Klimov " -#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver" -#define DRIVER_VERSION "0.11" -#define RADIO_VERSION KERNEL_VERSION(0, 1, 1) - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -#define USB_AMRADIO_VENDOR 0x07ca -#define USB_AMRADIO_PRODUCT 0xb800 - -/* dev_warn macro with driver name */ -#define MR800_DRIVER_NAME "radio-mr800" -#define amradio_dev_warn(dev, fmt, arg...) \ - dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) - -#define amradio_dev_err(dev, fmt, arg...) \ - dev_err(dev, MR800_DRIVER_NAME " - " fmt, ##arg) - -/* Probably USB_TIMEOUT should be modified in module parameter */ -#define BUFFER_LENGTH 8 -#define USB_TIMEOUT 500 - -/* Frequency limits in MHz -- these are European values. For Japanese -devices, that would be 76 and 91. */ -#define FREQ_MIN 87.5 -#define FREQ_MAX 108.0 -#define FREQ_MUL 16000 - -/* - * Commands that device should understand - * List isnt full and will be updated with implementation of new functions - */ -#define AMRADIO_SET_FREQ 0xa4 -#define AMRADIO_SET_MUTE 0xab -#define AMRADIO_SET_MONO 0xae - -/* Comfortable defines for amradio_set_mute */ -#define AMRADIO_START 0x00 -#define AMRADIO_STOP 0x01 - -/* Comfortable defines for amradio_set_stereo */ -#define WANT_STEREO 0x00 -#define WANT_MONO 0x01 - -/* module parameter */ -static int radio_nr = -1; -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(radio_nr, "Radio Nr"); - -static int usb_amradio_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void usb_amradio_disconnect(struct usb_interface *intf); -static int usb_amradio_open(struct file *file); -static int usb_amradio_close(struct file *file); -static int usb_amradio_suspend(struct usb_interface *intf, - pm_message_t message); -static int usb_amradio_resume(struct usb_interface *intf); - -/* Data for one (physical) device */ -struct amradio_device { - /* reference to USB and video device */ - struct usb_device *usbdev; - struct usb_interface *intf; - struct video_device videodev; - struct v4l2_device v4l2_dev; - - unsigned char *buffer; - struct mutex lock; /* buffer locking */ - int curfreq; - int stereo; - int muted; - int initialized; -}; - -static inline struct amradio_device *to_amradio_dev(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct amradio_device, v4l2_dev); -} - -/* USB Device ID List */ -static struct usb_device_id usb_amradio_device_table[] = { - {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, - USB_CLASS_HID, 0, 0) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, usb_amradio_device_table); - -/* USB subsystem interface */ -static struct usb_driver usb_amradio_driver = { - .name = MR800_DRIVER_NAME, - .probe = usb_amradio_probe, - .disconnect = usb_amradio_disconnect, - .suspend = usb_amradio_suspend, - .resume = usb_amradio_resume, - .reset_resume = usb_amradio_resume, - .id_table = usb_amradio_device_table, - .supports_autosuspend = 1, -}; - -/* switch on/off the radio. Send 8 bytes to device */ -static int amradio_set_mute(struct amradio_device *radio, char argument) -{ - int retval; - int size; - - radio->buffer[0] = 0x00; - radio->buffer[1] = 0x55; - radio->buffer[2] = 0xaa; - radio->buffer[3] = 0x00; - radio->buffer[4] = AMRADIO_SET_MUTE; - radio->buffer[5] = argument; - radio->buffer[6] = 0x00; - radio->buffer[7] = 0x00; - - retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), - (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - - if (retval < 0 || size != BUFFER_LENGTH) { - amradio_dev_warn(&radio->videodev.dev, "set mute failed\n"); - return retval; - } - - radio->muted = argument; - - return retval; -} - -/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ -static int amradio_setfreq(struct amradio_device *radio, int freq) -{ - int retval; - int size; - unsigned short freq_send = 0x10 + (freq >> 3) / 25; - - radio->buffer[0] = 0x00; - radio->buffer[1] = 0x55; - radio->buffer[2] = 0xaa; - radio->buffer[3] = 0x03; - radio->buffer[4] = AMRADIO_SET_FREQ; - radio->buffer[5] = 0x00; - radio->buffer[6] = 0x00; - radio->buffer[7] = 0x08; - - retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), - (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - - if (retval < 0 || size != BUFFER_LENGTH) - goto out_err; - - /* frequency is calculated from freq_send and placed in first 2 bytes */ - radio->buffer[0] = (freq_send >> 8) & 0xff; - radio->buffer[1] = freq_send & 0xff; - radio->buffer[2] = 0x01; - radio->buffer[3] = 0x00; - radio->buffer[4] = 0x00; - /* 5 and 6 bytes of buffer already = 0x00 */ - radio->buffer[7] = 0x00; - - retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), - (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - - if (retval < 0 || size != BUFFER_LENGTH) - goto out_err; - - radio->curfreq = freq; - goto out; - -out_err: - amradio_dev_warn(&radio->videodev.dev, "set frequency failed\n"); -out: - return retval; -} - -static int amradio_set_stereo(struct amradio_device *radio, char argument) -{ - int retval; - int size; - - radio->buffer[0] = 0x00; - radio->buffer[1] = 0x55; - radio->buffer[2] = 0xaa; - radio->buffer[3] = 0x00; - radio->buffer[4] = AMRADIO_SET_MONO; - radio->buffer[5] = argument; - radio->buffer[6] = 0x00; - radio->buffer[7] = 0x00; - - retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), - (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - - if (retval < 0 || size != BUFFER_LENGTH) { - amradio_dev_warn(&radio->videodev.dev, "set stereo failed\n"); - return retval; - } - - if (argument == WANT_STEREO) - radio->stereo = 1; - else - radio->stereo = 0; - - return retval; -} - -/* Handle unplugging the device. - * We call video_unregister_device in any case. - * The last function called in this procedure is - * usb_amradio_device_release. - */ -static void usb_amradio_disconnect(struct usb_interface *intf) -{ - struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); - - mutex_lock(&radio->lock); - /* increase the device node's refcount */ - get_device(&radio->videodev.dev); - v4l2_device_disconnect(&radio->v4l2_dev); - video_unregister_device(&radio->videodev); - mutex_unlock(&radio->lock); - /* decrease the device node's refcount, allowing it to be released */ - put_device(&radio->videodev.dev); -} - -/* vidioc_querycap - query device capabilities */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - struct amradio_device *radio = file->private_data; - - strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); - strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); - usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -/* vidioc_g_tuner - get tuner attributes */ -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct amradio_device *radio = file->private_data; - int retval; - - if (v->index > 0) - return -EINVAL; - -/* TODO: Add function which look is signal stereo or not - * amradio_getstat(radio); - */ - -/* we call amradio_set_stereo to set radio->stereo - * Honestly, amradio_getstat should cover this in future and - * amradio_set_stereo shouldn't be here - */ - retval = amradio_set_stereo(radio, WANT_STEREO); - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = FREQ_MIN * FREQ_MUL; - v->rangehigh = FREQ_MAX * FREQ_MUL; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if (radio->stereo) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff; /* Can't get the signal strength, sad.. */ - v->afc = 0; /* Don't know what is this */ - - return retval; -} - -/* vidioc_s_tuner - set tuner attributes */ -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct amradio_device *radio = file->private_data; - int retval = -EINVAL; - - if (v->index > 0) - return -EINVAL; - - /* mono/stereo selector */ - switch (v->audmode) { - case V4L2_TUNER_MODE_MONO: - retval = amradio_set_stereo(radio, WANT_MONO); - break; - case V4L2_TUNER_MODE_STEREO: - retval = amradio_set_stereo(radio, WANT_STEREO); - break; - } - - return retval; -} - -/* vidioc_s_frequency - set tuner radio frequency */ -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct amradio_device *radio = file->private_data; - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - return amradio_setfreq(radio, f->frequency); -} - -/* vidioc_g_frequency - get tuner radio frequency */ -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct amradio_device *radio = file->private_data; - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = radio->curfreq; - - return 0; -} - -/* vidioc_queryctrl - enumerate control items */ -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - - return -EINVAL; -} - -/* vidioc_g_ctrl - get the value of a control */ -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct amradio_device *radio = file->private_data; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = radio->muted; - return 0; - } - - return -EINVAL; -} - -/* vidioc_s_ctrl - set the value of a control */ -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct amradio_device *radio = file->private_data; - int retval = -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - retval = amradio_set_mute(radio, AMRADIO_STOP); - else - retval = amradio_set_mute(radio, AMRADIO_START); - - break; - } - - return retval; -} - -/* vidioc_g_audio - get audio attributes */ -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -/* vidioc_s_audio - set audio attributes */ -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - return 0; -} - -/* vidioc_g_input - get input */ -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -/* vidioc_s_input - set input */ -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int usb_amradio_init(struct amradio_device *radio) -{ - int retval; - - retval = amradio_set_mute(radio, AMRADIO_STOP); - if (retval) - goto out_err; - - retval = amradio_set_stereo(radio, WANT_STEREO); - if (retval) - goto out_err; - - radio->initialized = 1; - goto out; - -out_err: - amradio_dev_err(&radio->videodev.dev, "initialization failed\n"); -out: - return retval; -} - -/* open device - amradio_start() and amradio_setfreq() */ -static int usb_amradio_open(struct file *file) -{ - struct amradio_device *radio = video_drvdata(file); - int retval; - - file->private_data = radio; - retval = usb_autopm_get_interface(radio->intf); - if (retval) - return retval; - - if (unlikely(!radio->initialized)) { - retval = usb_amradio_init(radio); - if (retval) - usb_autopm_put_interface(radio->intf); - } - return retval; -} - -/*close device */ -static int usb_amradio_close(struct file *file) -{ - struct amradio_device *radio = file->private_data; - - if (video_is_registered(&radio->videodev)) - usb_autopm_put_interface(radio->intf); - return 0; -} - -/* Suspend device - stop device. Need to be checked and fixed */ -static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); - - mutex_lock(&radio->lock); - if (!radio->muted && radio->initialized) { - amradio_set_mute(radio, AMRADIO_STOP); - radio->muted = 0; - } - mutex_unlock(&radio->lock); - - dev_info(&intf->dev, "going into suspend..\n"); - return 0; -} - -/* Resume device - start device. Need to be checked and fixed */ -static int usb_amradio_resume(struct usb_interface *intf) -{ - struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); - - mutex_lock(&radio->lock); - if (unlikely(!radio->initialized)) - goto unlock; - - if (radio->stereo) - amradio_set_stereo(radio, WANT_STEREO); - else - amradio_set_stereo(radio, WANT_MONO); - - amradio_setfreq(radio, radio->curfreq); - - if (!radio->muted) - amradio_set_mute(radio, AMRADIO_START); - -unlock: - mutex_unlock(&radio->lock); - - dev_info(&intf->dev, "coming out of suspend..\n"); - return 0; -} - -/* File system interface */ -static const struct v4l2_file_operations usb_amradio_fops = { - .owner = THIS_MODULE, - .open = usb_amradio_open, - .release = usb_amradio_close, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, -}; - -static void usb_amradio_video_device_release(struct video_device *videodev) -{ - struct amradio_device *radio = video_get_drvdata(videodev); - - /* free rest memory */ - kfree(radio->buffer); - kfree(radio); -} - -/* check if the device is present and register with v4l and usb if it is */ -static int usb_amradio_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct amradio_device *radio; - int retval = 0; - - radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); - - if (!radio) { - dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); - retval = -ENOMEM; - goto err; - } - - radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); - - if (!radio->buffer) { - dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); - retval = -ENOMEM; - goto err_nobuf; - } - - retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); - if (retval < 0) { - dev_err(&intf->dev, "couldn't register v4l2_device\n"); - goto err_v4l2; - } - - mutex_init(&radio->lock); - - strlcpy(radio->videodev.name, radio->v4l2_dev.name, - sizeof(radio->videodev.name)); - radio->videodev.v4l2_dev = &radio->v4l2_dev; - radio->videodev.fops = &usb_amradio_fops; - radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops; - radio->videodev.release = usb_amradio_video_device_release; - radio->videodev.lock = &radio->lock; - - radio->usbdev = interface_to_usbdev(intf); - radio->intf = intf; - radio->curfreq = 95.16 * FREQ_MUL; - - video_set_drvdata(&radio->videodev, radio); - - retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, - radio_nr); - if (retval < 0) { - dev_err(&intf->dev, "could not register video device\n"); - goto err_vdev; - } - - return 0; - -err_vdev: - v4l2_device_unregister(&radio->v4l2_dev); -err_v4l2: - kfree(radio->buffer); -err_nobuf: - kfree(radio); -err: - return retval; -} - -static int __init amradio_init(void) -{ - int retval = usb_register(&usb_amradio_driver); - - pr_info(KBUILD_MODNAME - ": version " DRIVER_VERSION " " DRIVER_DESC "\n"); - - if (retval) - pr_err(KBUILD_MODNAME - ": usb_register failed. Error number %d\n", retval); - - return retval; -} - -static void __exit amradio_exit(void) -{ - usb_deregister(&usb_amradio_driver); -} - -module_init(amradio_init); -module_exit(amradio_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-rtrack2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-rtrack2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-rtrack2.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-rtrack2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,344 +0,0 @@ -/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff - * - * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood - * Converted to new API by Alan Cox - * Various bugfixes and enhancements by Russell Kroll - * - * TODO: Allow for more than one of these foolish entities :-) - * - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* udelay */ -#include /* kernel radio structs */ -#include -#include /* for KERNEL_VERSION MACRO */ -#include /* outb, outb_p */ -#include -#include - -MODULE_AUTHOR("Ben Pfaff"); -MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); -MODULE_LICENSE("GPL"); - -#ifndef CONFIG_RADIO_RTRACK2_PORT -#define CONFIG_RADIO_RTRACK2_PORT -1 -#endif - -static int io = CONFIG_RADIO_RTRACK2_PORT; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - -struct rtrack2 -{ - struct v4l2_device v4l2_dev; - struct video_device vdev; - int io; - unsigned long curfreq; - int muted; - struct mutex lock; -}; - -static struct rtrack2 rtrack2_card; - - -/* local things */ - -static void rt_mute(struct rtrack2 *dev) -{ - if (dev->muted) - return; - mutex_lock(&dev->lock); - outb(1, dev->io); - mutex_unlock(&dev->lock); - dev->muted = 1; -} - -static void rt_unmute(struct rtrack2 *dev) -{ - if(dev->muted == 0) - return; - mutex_lock(&dev->lock); - outb(0, dev->io); - mutex_unlock(&dev->lock); - dev->muted = 0; -} - -static void zero(struct rtrack2 *dev) -{ - outb_p(1, dev->io); - outb_p(3, dev->io); - outb_p(1, dev->io); -} - -static void one(struct rtrack2 *dev) -{ - outb_p(5, dev->io); - outb_p(7, dev->io); - outb_p(5, dev->io); -} - -static int rt_setfreq(struct rtrack2 *dev, unsigned long freq) -{ - int i; - - mutex_lock(&dev->lock); - dev->curfreq = freq; - freq = freq / 200 + 856; - - outb_p(0xc8, dev->io); - outb_p(0xc9, dev->io); - outb_p(0xc9, dev->io); - - for (i = 0; i < 10; i++) - zero(dev); - - for (i = 14; i >= 0; i--) - if (freq & (1 << i)) - one(dev); - else - zero(dev); - - outb_p(0xc8, dev->io); - if (!dev->muted) - outb_p(0, dev->io); - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver)); - strlcpy(v->card, "RadioTrack II", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int rt_getsigstr(struct rtrack2 *dev) -{ - int sig = 1; - - mutex_lock(&dev->lock); - if (inb(dev->io) & 2) /* bit set = no signal present */ - sig = 0; - mutex_unlock(&dev->lock); - return sig; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct rtrack2 *rt = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = 88 * 16000; - v->rangehigh = 108 * 16000; - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF * rt_getsigstr(rt); - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct rtrack2 *rt = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - rt_setfreq(rt, f->frequency); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct rtrack2 *rt = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = rt->curfreq; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct rtrack2 *rt = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = rt->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (rt->muted) - ctrl->value = 0; - else - ctrl->value = 65535; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct rtrack2 *rt = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - rt_mute(rt); - else - rt_unmute(rt); - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (ctrl->value) - rt_unmute(rt); - else - rt_mute(rt); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static const struct v4l2_file_operations rtrack2_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, -}; - -static int __init rtrack2_init(void) -{ - struct rtrack2 *dev = &rtrack2_card; - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name)); - dev->io = io; - if (dev->io == -1) { - v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n"); - return -EINVAL; - } - if (!request_region(dev->io, 4, "rtrack2")) { - v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io); - return -EBUSY; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(dev->io, 4); - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } - - strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; - dev->vdev.fops = &rtrack2_fops; - dev->vdev.ioctl_ops = &rtrack2_ioctl_ops; - dev->vdev.release = video_device_release_empty; - video_set_drvdata(&dev->vdev, dev); - - /* mute card - prevents noisy bootups */ - outb(1, dev->io); - dev->muted = 1; - - mutex_init(&dev->lock); - if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(dev->io, 4); - return -EINVAL; - } - - v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n"); - - return 0; -} - -static void __exit rtrack2_exit(void) -{ - struct rtrack2 *dev = &rtrack2_card; - - video_unregister_device(&dev->vdev); - v4l2_device_unregister(&dev->v4l2_dev); - release_region(dev->io, 4); -} - -module_init(rtrack2_init); -module_exit(rtrack2_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-sf16fmi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-sf16fmi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-sf16fmi.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-sf16fmi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,412 +0,0 @@ -/* SF16-FMI and SF16-FMP radio driver for Linux radio support - * heavily based on rtrack driver... - * (c) 1997 M. Kirkwood - * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz - * - * Fitted to new interface by Alan Cox - * Made working and cleaned up functions - * Support for ISAPnP by Ladislav Michl - * - * Notes on the hardware - * - * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); - * No volume control - only mute/unmute - you have to use line volume - * control on SB-part of SF16-FMI/SF16-FMP - * - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -#include -#include /* __setup */ -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* udelay */ -#include -#include -#include /* kernel radio structs */ -#include /* outb, outb_p */ -#include -#include - -MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); -MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio."); -MODULE_LICENSE("GPL"); - -static int io = -1; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)"); -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - -struct fmi -{ - struct v4l2_device v4l2_dev; - struct video_device vdev; - int io; - bool mute; - unsigned long curfreq; /* freq in kHz */ - struct mutex lock; -}; - -static struct fmi fmi_card; -static struct pnp_dev *dev; -bool pnp_attached; - -/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ -/* It is only useful to give freq in interval of 800 (=0.05Mhz), - * other bits will be truncated, e.g 92.7400016 -> 92.7, but - * 92.7400017 -> 92.75 - */ -#define RSF16_ENCODE(x) ((x) / 800 + 214) -#define RSF16_MINFREQ (87 * 16000) -#define RSF16_MAXFREQ (108 * 16000) - -static void outbits(int bits, unsigned int data, int io) -{ - while (bits--) { - if (data & 1) { - outb(5, io); - udelay(6); - outb(7, io); - udelay(6); - } else { - outb(1, io); - udelay(6); - outb(3, io); - udelay(6); - } - data >>= 1; - } -} - -static inline void fmi_mute(struct fmi *fmi) -{ - mutex_lock(&fmi->lock); - outb(0x00, fmi->io); - mutex_unlock(&fmi->lock); -} - -static inline void fmi_unmute(struct fmi *fmi) -{ - mutex_lock(&fmi->lock); - outb(0x08, fmi->io); - mutex_unlock(&fmi->lock); -} - -static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq) -{ - mutex_lock(&fmi->lock); - fmi->curfreq = freq; - - outbits(16, RSF16_ENCODE(freq), fmi->io); - outbits(8, 0xC0, fmi->io); - msleep(143); /* was schedule_timeout(HZ/7) */ - mutex_unlock(&fmi->lock); - if (!fmi->mute) - fmi_unmute(fmi); - return 0; -} - -static inline int fmi_getsigstr(struct fmi *fmi) -{ - int val; - int res; - - mutex_lock(&fmi->lock); - val = fmi->mute ? 0x00 : 0x08; /* mute/unmute */ - outb(val, fmi->io); - outb(val | 0x10, fmi->io); - msleep(143); /* was schedule_timeout(HZ/7) */ - res = (int)inb(fmi->io + 1); - outb(val, fmi->io); - - mutex_unlock(&fmi->lock); - return (res & 2) ? 0 : 0xFFFF; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); - strlcpy(v->card, "SF16-FMx radio", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct fmi *fmi = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = RSF16_MINFREQ; - v->rangehigh = RSF16_MAXFREQ; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_STEREO; - v->signal = fmi_getsigstr(fmi); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct fmi *fmi = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (f->frequency < RSF16_MINFREQ || - f->frequency > RSF16_MAXFREQ) - return -EINVAL; - /* rounding in steps of 800 to match the freq - that will be used */ - fmi_setfreq(fmi, (f->frequency / 800) * 800); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct fmi *fmi = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = fmi->curfreq; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fmi *fmi = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = fmi->mute; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fmi *fmi = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - fmi_mute(fmi); - else - fmi_unmute(fmi); - fmi->mute = ctrl->value; - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static const struct v4l2_file_operations fmi_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops fmi_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -/* ladis: this is my card. does any other types exist? */ -static struct isapnp_device_id id_table[] __devinitdata = { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('M','F','R'), ISAPNP_FUNCTION(0xad10), 0}, - { ISAPNP_CARD_END, }, -}; - -MODULE_DEVICE_TABLE(isapnp, id_table); - -static int __init isapnp_fmi_probe(void) -{ - int i = 0; - - while (id_table[i].card_vendor != 0 && dev == NULL) { - dev = pnp_find_dev(NULL, id_table[i].vendor, - id_table[i].function, NULL); - i++; - } - - if (!dev) - return -ENODEV; - if (pnp_device_attach(dev) < 0) - return -EAGAIN; - if (pnp_activate_dev(dev) < 0) { - printk(KERN_ERR "radio-sf16fmi: PnP configure failed (out of resources?)\n"); - pnp_device_detach(dev); - return -ENOMEM; - } - if (!pnp_port_valid(dev, 0)) { - pnp_device_detach(dev); - return -ENODEV; - } - - i = pnp_port_start(dev, 0); - printk(KERN_INFO "radio-sf16fmi: PnP reports card at %#x\n", i); - - return i; -} - -static int __init fmi_init(void) -{ - struct fmi *fmi = &fmi_card; - struct v4l2_device *v4l2_dev = &fmi->v4l2_dev; - int res, i; - int probe_ports[] = { 0, 0x284, 0x384 }; - - if (io < 0) { - for (i = 0; i < ARRAY_SIZE(probe_ports); i++) { - io = probe_ports[i]; - if (io == 0) { - io = isapnp_fmi_probe(); - if (io < 0) - continue; - pnp_attached = 1; - } - if (!request_region(io, 2, "radio-sf16fmi")) { - if (pnp_attached) - pnp_device_detach(dev); - io = -1; - continue; - } - if (pnp_attached || - ((inb(io) & 0xf9) == 0xf9 && (inb(io) & 0x4) == 0)) - break; - release_region(io, 2); - io = -1; - } - } else { - if (!request_region(io, 2, "radio-sf16fmi")) { - printk(KERN_ERR "radio-sf16fmi: port %#x already in use\n", io); - return -EBUSY; - } - if (inb(io) == 0xff) { - printk(KERN_ERR "radio-sf16fmi: card not present at %#x\n", io); - release_region(io, 2); - return -ENODEV; - } - } - if (io < 0) { - printk(KERN_ERR "radio-sf16fmi: no cards found\n"); - return -ENODEV; - } - - strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name)); - fmi->io = io; - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(fmi->io, 2); - if (pnp_attached) - pnp_device_detach(dev); - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } - - strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name)); - fmi->vdev.v4l2_dev = v4l2_dev; - fmi->vdev.fops = &fmi_fops; - fmi->vdev.ioctl_ops = &fmi_ioctl_ops; - fmi->vdev.release = video_device_release_empty; - video_set_drvdata(&fmi->vdev, fmi); - - mutex_init(&fmi->lock); - - /* mute card - prevents noisy bootups */ - fmi_mute(fmi); - - if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(fmi->io, 2); - if (pnp_attached) - pnp_device_detach(dev); - return -EINVAL; - } - - v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io); - return 0; -} - -static void __exit fmi_exit(void) -{ - struct fmi *fmi = &fmi_card; - - video_unregister_device(&fmi->vdev); - v4l2_device_unregister(&fmi->v4l2_dev); - release_region(fmi->io, 2); - if (dev && pnp_attached) - pnp_device_detach(dev); -} - -module_init(fmi_init); -module_exit(fmi_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-sf16fmr2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-sf16fmr2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-sf16fmr2.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-sf16fmr2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,464 +0,0 @@ -/* SF16FMR2 radio driver for Linux radio support - * heavily based on fmi driver... - * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com - * - * Notes on the hardware - * - * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); - * No volume control - only mute/unmute - you have to use line volume - * - * For read stereo/mono you must wait 0.1 sec after set frequency and - * card unmuted so I set frequency on unmute - * Signal handling seem to work only on autoscanning (not implemented) - * - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* udelay */ -#include /* kernel radio structs */ -#include -#include /* for KERNEL_VERSION MACRO */ -#include /* outb, outb_p */ -#include -#include - -MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com"); -MODULE_DESCRIPTION("A driver for the SF16FMR2 radio."); -MODULE_LICENSE("GPL"); - -static int io = 0x384; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)"); -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0,0,2) - -#define AUD_VOL_INDEX 1 - -#undef DEBUG -//#define DEBUG 1 - -#ifdef DEBUG -# define debug_print(s) printk s -#else -# define debug_print(s) -#endif - -/* this should be static vars for module size */ -struct fmr2 -{ - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct mutex lock; - int io; - int curvol; /* 0-15 */ - int mute; - int stereo; /* card is producing stereo audio */ - unsigned long curfreq; /* freq in kHz */ - int card_type; -}; - -static struct fmr2 fmr2_card; - -/* hw precision is 12.5 kHz - * It is only useful to give freq in interval of 200 (=0.0125Mhz), - * other bits will be truncated - */ -#define RSF16_ENCODE(x) ((x) / 200 + 856) -#define RSF16_MINFREQ (87 * 16000) -#define RSF16_MAXFREQ (108 * 16000) - -static inline void wait(int n, int io) -{ - for (; n; --n) - inb(io); -} - -static void outbits(int bits, unsigned int data, int nWait, int io) -{ - int bit; - - for (; --bits >= 0;) { - bit = (data >> bits) & 1; - outb(bit, io); - wait(nWait, io); - outb(bit | 2, io); - wait(nWait, io); - outb(bit, io); - wait(nWait, io); - } -} - -static inline void fmr2_mute(int io) -{ - outb(0x00, io); - wait(4, io); -} - -static inline void fmr2_unmute(int io) -{ - outb(0x04, io); - wait(4, io); -} - -static inline int fmr2_stereo_mode(int io) -{ - int n = inb(io); - - outb(6, io); - inb(io); - n = ((n >> 3) & 1) ^ 1; - debug_print((KERN_DEBUG "stereo: %d\n", n)); - return n; -} - -static int fmr2_product_info(struct fmr2 *dev) -{ - int n = inb(dev->io); - - n &= 0xC1; - if (n == 0) { - /* this should support volume set */ - dev->card_type = 12; - return 0; - } - /* not volume (mine is 11) */ - dev->card_type = (n == 128) ? 11 : 0; - return n; -} - -static inline int fmr2_getsigstr(struct fmr2 *dev) -{ - /* !!! works only if scanning freq */ - int res = 0xffff; - - outb(5, dev->io); - wait(4, dev->io); - if (!(inb(dev->io) & 1)) - res = 0; - debug_print((KERN_DEBUG "signal: %d\n", res)); - return res; -} - -/* set frequency and unmute card */ -static int fmr2_setfreq(struct fmr2 *dev) -{ - unsigned long freq = dev->curfreq; - - fmr2_mute(dev->io); - - /* 0x42 for mono output - * 0x102 forward scanning - * 0x182 scansione avanti - */ - outbits(9, 0x2, 3, dev->io); - outbits(16, RSF16_ENCODE(freq), 2, dev->io); - - fmr2_unmute(dev->io); - - /* wait 0.11 sec */ - msleep(110); - - /* NOTE if mute this stop radio - you must set freq on unmute */ - dev->stereo = fmr2_stereo_mode(dev->io); - return 0; -} - -/* !!! not tested, in my card this does't work !!! */ -static int fmr2_setvolume(struct fmr2 *dev) -{ - int vol[16] = { 0x021, 0x084, 0x090, 0x104, - 0x110, 0x204, 0x210, 0x402, - 0x404, 0x408, 0x410, 0x801, - 0x802, 0x804, 0x808, 0x810 }; - int i, a; - int n = vol[dev->curvol & 0x0f]; - - if (dev->card_type != 11) - return 1; - - for (i = 12; --i >= 0; ) { - a = ((n >> i) & 1) << 6; /* if (a==0) a = 0; else a = 0x40; */ - outb(a | 4, dev->io); - wait(4, dev->io); - outb(a | 0x24, dev->io); - wait(4, dev->io); - outb(a | 4, dev->io); - wait(4, dev->io); - } - for (i = 6; --i >= 0; ) { - a = ((0x18 >> i) & 1) << 6; - outb(a | 4, dev->io); - wait(4, dev->io); - outb(a | 0x24, dev->io); - wait(4, dev->io); - outb(a | 4, dev->io); - wait(4, dev->io); - } - wait(4, dev->io); - outb(0x14, dev->io); - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver)); - strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - - v->rangelow = RSF16_MINFREQ; - v->rangehigh = RSF16_MAXFREQ; - v->rxsubchans = fmr2->stereo ? V4L2_TUNER_SUB_STEREO : - V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_STEREO; - mutex_lock(&fmr2->lock); - v->signal = fmr2_getsigstr(fmr2); - mutex_unlock(&fmr2->lock); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (f->frequency < RSF16_MINFREQ || - f->frequency > RSF16_MAXFREQ) - return -EINVAL; - /* rounding in steps of 200 to match the freq - that will be used */ - fmr2->curfreq = (f->frequency / 200) * 200; - - /* set card freq (if not muted) */ - if (fmr2->curvol && !fmr2->mute) { - mutex_lock(&fmr2->lock); - fmr2_setfreq(fmr2); - mutex_unlock(&fmr2->lock); - } - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = fmr2->curfreq; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - /* Only card_type == 11 implements volume */ - if (fmr2->card_type == 11) - return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0); - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = fmr2->mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = fmr2->curvol; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fmr2 *fmr2 = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - fmr2->mute = ctrl->value; - break; - case V4L2_CID_AUDIO_VOLUME: - fmr2->curvol = ctrl->value; - break; - default: - return -EINVAL; - } - -#ifdef DEBUG - if (fmr2->curvol && !fmr2->mute) - printk(KERN_DEBUG "unmute\n"); - else - printk(KERN_DEBUG "mute\n"); -#endif - - mutex_lock(&fmr2->lock); - if (fmr2->curvol && !fmr2->mute) { - fmr2_setvolume(fmr2); - /* Set frequency and unmute card */ - fmr2_setfreq(fmr2); - } else - fmr2_mute(fmr2->io); - mutex_unlock(&fmr2->lock); - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static const struct v4l2_file_operations fmr2_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static int __init fmr2_init(void) -{ - struct fmr2 *fmr2 = &fmr2_card; - struct v4l2_device *v4l2_dev = &fmr2->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name)); - fmr2->io = io; - fmr2->stereo = 1; - mutex_init(&fmr2->lock); - - if (!request_region(fmr2->io, 2, "sf16fmr2")) { - v4l2_err(v4l2_dev, "request_region failed!\n"); - return -EBUSY; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(fmr2->io, 2); - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } - - strlcpy(fmr2->vdev.name, v4l2_dev->name, sizeof(fmr2->vdev.name)); - fmr2->vdev.v4l2_dev = v4l2_dev; - fmr2->vdev.fops = &fmr2_fops; - fmr2->vdev.ioctl_ops = &fmr2_ioctl_ops; - fmr2->vdev.release = video_device_release_empty; - video_set_drvdata(&fmr2->vdev, fmr2); - - /* mute card - prevents noisy bootups */ - fmr2_mute(fmr2->io); - fmr2_product_info(fmr2); - - if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(fmr2->io, 2); - return -EINVAL; - } - - v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io); - debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type)); - return 0; -} - -static void __exit fmr2_exit(void) -{ - struct fmr2 *fmr2 = &fmr2_card; - - video_unregister_device(&fmr2->vdev); - v4l2_device_unregister(&fmr2->v4l2_dev); - release_region(fmr2->io, 2); -} - -module_init(fmr2_init); -module_exit(fmr2_exit); - -#ifndef MODULE - -static int __init fmr2_setup_io(char *str) -{ - get_option(&str, &io); - return 1; -} - -__setup("sf16fmr2=", fmr2_setup_io); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-si4713.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-si4713.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-si4713.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-si4713.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,374 +0,0 @@ -/* - * drivers/media/radio/radio-si4713.c - * - * Platform Driver for Silicon Labs Si4713 FM Radio Transmitter: - * - * Copyright (c) 2008 Instituto Nokia de Tecnologia - INdT - * Contact: Eduardo Valentin - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* module parameters */ -static int radio_nr = -1; /* radio device minor (-1 ==> auto assign) */ -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(radio_nr, - "Minor number for radio device (-1 ==> auto assign)"); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Eduardo Valentin "); -MODULE_DESCRIPTION("Platform driver for Si4713 FM Radio Transmitter"); - -/* Driver state struct */ -struct radio_si4713_device { - struct v4l2_device v4l2_dev; - struct video_device *radio_dev; -}; - -/* radio_si4713_fops - file operations interface */ -static const struct v4l2_file_operations radio_si4713_fops = { - .owner = THIS_MODULE, - /* Note: locking is done at the subdev level in the i2c driver. */ - .unlocked_ioctl = video_ioctl2, -}; - -/* Video4Linux Interface */ -static int radio_si4713_fill_audout(struct v4l2_audioout *vao) -{ - /* TODO: check presence of audio output */ - strlcpy(vao->name, "FM Modulator Audio Out", 32); - - return 0; -} - -static int radio_si4713_enumaudout(struct file *file, void *priv, - struct v4l2_audioout *vao) -{ - return radio_si4713_fill_audout(vao); -} - -static int radio_si4713_g_audout(struct file *file, void *priv, - struct v4l2_audioout *vao) -{ - int rval = radio_si4713_fill_audout(vao); - - vao->index = 0; - - return rval; -} - -static int radio_si4713_s_audout(struct file *file, void *priv, - struct v4l2_audioout *vao) -{ - return vao->index ? -EINVAL : 0; -} - -/* radio_si4713_querycap - query device capabilities */ -static int radio_si4713_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - struct radio_si4713_device *rsdev; - - rsdev = video_get_drvdata(video_devdata(file)); - - strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver)); - strlcpy(capability->card, "Silicon Labs Si4713 Modulator", - sizeof(capability->card)); - capability->capabilities = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; - - return 0; -} - -/* radio_si4713_queryctrl - enumerate control items */ -static int radio_si4713_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - /* Must be sorted from low to high control ID! */ - static const u32 user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_AUDIO_MUTE, - 0 - }; - - /* Must be sorted from low to high control ID! */ - static const u32 fmtx_ctrls[] = { - V4L2_CID_FM_TX_CLASS, - V4L2_CID_RDS_TX_DEVIATION, - V4L2_CID_RDS_TX_PI, - V4L2_CID_RDS_TX_PTY, - V4L2_CID_RDS_TX_PS_NAME, - V4L2_CID_RDS_TX_RADIO_TEXT, - V4L2_CID_AUDIO_LIMITER_ENABLED, - V4L2_CID_AUDIO_LIMITER_RELEASE_TIME, - V4L2_CID_AUDIO_LIMITER_DEVIATION, - V4L2_CID_AUDIO_COMPRESSION_ENABLED, - V4L2_CID_AUDIO_COMPRESSION_GAIN, - V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, - V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, - V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME, - V4L2_CID_PILOT_TONE_ENABLED, - V4L2_CID_PILOT_TONE_DEVIATION, - V4L2_CID_PILOT_TONE_FREQUENCY, - V4L2_CID_TUNE_PREEMPHASIS, - V4L2_CID_TUNE_POWER_LEVEL, - V4L2_CID_TUNE_ANTENNA_CAPACITOR, - 0 - }; - static const u32 *ctrl_classes[] = { - user_ctrls, - fmtx_ctrls, - NULL - }; - struct radio_si4713_device *rsdev; - - rsdev = video_get_drvdata(video_devdata(file)); - - qc->id = v4l2_ctrl_next(ctrl_classes, qc->id); - if (qc->id == 0) - return -EINVAL; - - if (qc->id == V4L2_CID_USER_CLASS || qc->id == V4L2_CID_FM_TX_CLASS) - return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0); - - return v4l2_device_call_until_err(&rsdev->v4l2_dev, 0, core, - queryctrl, qc); -} - -/* - * v4l2 ioctl call backs. - * we are just a wrapper for v4l2_sub_devs. - */ -static inline struct v4l2_device *get_v4l2_dev(struct file *file) -{ - return &((struct radio_si4713_device *)video_drvdata(file))->v4l2_dev; -} - -static int radio_si4713_g_ext_ctrls(struct file *file, void *p, - struct v4l2_ext_controls *vecs) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - g_ext_ctrls, vecs); -} - -static int radio_si4713_s_ext_ctrls(struct file *file, void *p, - struct v4l2_ext_controls *vecs) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - s_ext_ctrls, vecs); -} - -static int radio_si4713_g_ctrl(struct file *file, void *p, - struct v4l2_control *vc) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - g_ctrl, vc); -} - -static int radio_si4713_s_ctrl(struct file *file, void *p, - struct v4l2_control *vc) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - s_ctrl, vc); -} - -static int radio_si4713_g_modulator(struct file *file, void *p, - struct v4l2_modulator *vm) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, - g_modulator, vm); -} - -static int radio_si4713_s_modulator(struct file *file, void *p, - struct v4l2_modulator *vm) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, - s_modulator, vm); -} - -static int radio_si4713_g_frequency(struct file *file, void *p, - struct v4l2_frequency *vf) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, - g_frequency, vf); -} - -static int radio_si4713_s_frequency(struct file *file, void *p, - struct v4l2_frequency *vf) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, - s_frequency, vf); -} - -static long radio_si4713_default(struct file *file, void *p, - bool valid_prio, int cmd, void *arg) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - ioctl, cmd, arg); -} - -static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = { - .vidioc_enumaudout = radio_si4713_enumaudout, - .vidioc_g_audout = radio_si4713_g_audout, - .vidioc_s_audout = radio_si4713_s_audout, - .vidioc_querycap = radio_si4713_querycap, - .vidioc_queryctrl = radio_si4713_queryctrl, - .vidioc_g_ext_ctrls = radio_si4713_g_ext_ctrls, - .vidioc_s_ext_ctrls = radio_si4713_s_ext_ctrls, - .vidioc_g_ctrl = radio_si4713_g_ctrl, - .vidioc_s_ctrl = radio_si4713_s_ctrl, - .vidioc_g_modulator = radio_si4713_g_modulator, - .vidioc_s_modulator = radio_si4713_s_modulator, - .vidioc_g_frequency = radio_si4713_g_frequency, - .vidioc_s_frequency = radio_si4713_s_frequency, - .vidioc_default = radio_si4713_default, -}; - -/* radio_si4713_vdev_template - video device interface */ -static struct video_device radio_si4713_vdev_template = { - .fops = &radio_si4713_fops, - .name = "radio-si4713", - .release = video_device_release, - .ioctl_ops = &radio_si4713_ioctl_ops, -}; - -/* Platform driver interface */ -/* radio_si4713_pdriver_probe - probe for the device */ -static int radio_si4713_pdriver_probe(struct platform_device *pdev) -{ - struct radio_si4713_platform_data *pdata = pdev->dev.platform_data; - struct radio_si4713_device *rsdev; - struct i2c_adapter *adapter; - struct v4l2_subdev *sd; - int rval = 0; - - if (!pdata) { - dev_err(&pdev->dev, "Cannot proceed without platform data.\n"); - rval = -EINVAL; - goto exit; - } - - rsdev = kzalloc(sizeof *rsdev, GFP_KERNEL); - if (!rsdev) { - dev_err(&pdev->dev, "Failed to alloc video device.\n"); - rval = -ENOMEM; - goto exit; - } - - rval = v4l2_device_register(&pdev->dev, &rsdev->v4l2_dev); - if (rval) { - dev_err(&pdev->dev, "Failed to register v4l2 device.\n"); - goto free_rsdev; - } - - adapter = i2c_get_adapter(pdata->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "Cannot get i2c adapter %d\n", - pdata->i2c_bus); - rval = -ENODEV; - goto unregister_v4l2_dev; - } - - sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, - pdata->subdev_board_info, NULL); - if (!sd) { - dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n"); - rval = -ENODEV; - goto put_adapter; - } - - rsdev->radio_dev = video_device_alloc(); - if (!rsdev->radio_dev) { - dev_err(&pdev->dev, "Failed to alloc video device.\n"); - rval = -ENOMEM; - goto put_adapter; - } - - memcpy(rsdev->radio_dev, &radio_si4713_vdev_template, - sizeof(radio_si4713_vdev_template)); - video_set_drvdata(rsdev->radio_dev, rsdev); - if (video_register_device(rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) { - dev_err(&pdev->dev, "Could not register video device.\n"); - rval = -EIO; - goto free_vdev; - } - dev_info(&pdev->dev, "New device successfully probed\n"); - - goto exit; - -free_vdev: - video_device_release(rsdev->radio_dev); -put_adapter: - i2c_put_adapter(adapter); -unregister_v4l2_dev: - v4l2_device_unregister(&rsdev->v4l2_dev); -free_rsdev: - kfree(rsdev); -exit: - return rval; -} - -/* radio_si4713_pdriver_remove - remove the device */ -static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev) -{ - struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); - struct radio_si4713_device *rsdev = container_of(v4l2_dev, - struct radio_si4713_device, - v4l2_dev); - struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next, - struct v4l2_subdev, list); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - video_unregister_device(rsdev->radio_dev); - i2c_put_adapter(client->adapter); - v4l2_device_unregister(&rsdev->v4l2_dev); - kfree(rsdev); - - return 0; -} - -static struct platform_driver radio_si4713_pdriver = { - .driver = { - .name = "radio-si4713", - }, - .probe = radio_si4713_pdriver_probe, - .remove = __exit_p(radio_si4713_pdriver_remove), -}; - -/* Module Interface */ -static int __init radio_si4713_module_init(void) -{ - return platform_driver_register(&radio_si4713_pdriver); -} - -static void __exit radio_si4713_module_exit(void) -{ - platform_driver_unregister(&radio_si4713_pdriver); -} - -module_init(radio_si4713_module_init); -module_exit(radio_si4713_module_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-tea5764.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-tea5764.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-tea5764.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-tea5764.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,605 +0,0 @@ -/* - * driver/media/radio/radio-tea5764.c - * - * Driver for TEA5764 radio chip for linux 2.6. - * This driver is for TEA5764 chip from NXP, used in EZX phones from Motorola. - * The I2C protocol is used for communicate with chip. - * - * Based in radio-tea5761.c Copyright (C) 2005 Nokia Corporation - * - * Copyright (c) 2008 Fabio Belavenuto - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * History: - * 2008-12-06 Fabio Belavenuto - * initial code - * - * TODO: - * add platform_data support for IRQs platform dependencies - * add RDS support - */ -#include -#include -#include -#include /* Initdata */ -#include /* kernel radio structs */ -#include /* I2C */ -#include -#include -#include /* for KERNEL_VERSION MACRO */ - -#define DRIVER_VERSION "v0.01" -#define RADIO_VERSION KERNEL_VERSION(0, 0, 1) - -#define DRIVER_AUTHOR "Fabio Belavenuto " -#define DRIVER_DESC "A driver for the TEA5764 radio chip for EZX Phones." - -#define PINFO(format, ...)\ - printk(KERN_INFO KBUILD_MODNAME ": "\ - DRIVER_VERSION ": " format "\n", ## __VA_ARGS__) -#define PWARN(format, ...)\ - printk(KERN_WARNING KBUILD_MODNAME ": "\ - DRIVER_VERSION ": " format "\n", ## __VA_ARGS__) -# define PDEBUG(format, ...)\ - printk(KERN_DEBUG KBUILD_MODNAME ": "\ - DRIVER_VERSION ": " format "\n", ## __VA_ARGS__) - -/* Frequency limits in MHz -- these are European values. For Japanese -devices, that would be 76000 and 91000. */ -#define FREQ_MIN 87500 -#define FREQ_MAX 108000 -#define FREQ_MUL 16 - -/* TEA5764 registers */ -#define TEA5764_MANID 0x002b -#define TEA5764_CHIPID 0x5764 - -#define TEA5764_INTREG_BLMSK 0x0001 -#define TEA5764_INTREG_FRRMSK 0x0002 -#define TEA5764_INTREG_LEVMSK 0x0008 -#define TEA5764_INTREG_IFMSK 0x0010 -#define TEA5764_INTREG_BLMFLAG 0x0100 -#define TEA5764_INTREG_FRRFLAG 0x0200 -#define TEA5764_INTREG_LEVFLAG 0x0800 -#define TEA5764_INTREG_IFFLAG 0x1000 - -#define TEA5764_FRQSET_SUD 0x8000 -#define TEA5764_FRQSET_SM 0x4000 - -#define TEA5764_TNCTRL_PUPD1 0x8000 -#define TEA5764_TNCTRL_PUPD0 0x4000 -#define TEA5764_TNCTRL_BLIM 0x2000 -#define TEA5764_TNCTRL_SWPM 0x1000 -#define TEA5764_TNCTRL_IFCTC 0x0800 -#define TEA5764_TNCTRL_AFM 0x0400 -#define TEA5764_TNCTRL_SMUTE 0x0200 -#define TEA5764_TNCTRL_SNC 0x0100 -#define TEA5764_TNCTRL_MU 0x0080 -#define TEA5764_TNCTRL_SSL1 0x0040 -#define TEA5764_TNCTRL_SSL0 0x0020 -#define TEA5764_TNCTRL_HLSI 0x0010 -#define TEA5764_TNCTRL_MST 0x0008 -#define TEA5764_TNCTRL_SWP 0x0004 -#define TEA5764_TNCTRL_DTC 0x0002 -#define TEA5764_TNCTRL_AHLSI 0x0001 - -#define TEA5764_TUNCHK_LEVEL(x) (((x) & 0x00F0) >> 4) -#define TEA5764_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9) -#define TEA5764_TUNCHK_TUNTO 0x0100 -#define TEA5764_TUNCHK_LD 0x0008 -#define TEA5764_TUNCHK_STEREO 0x0004 - -#define TEA5764_TESTREG_TRIGFR 0x0800 - -struct tea5764_regs { - u16 intreg; /* INTFLAG & INTMSK */ - u16 frqset; /* FRQSETMSB & FRQSETLSB */ - u16 tnctrl; /* TNCTRL1 & TNCTRL2 */ - u16 frqchk; /* FRQCHKMSB & FRQCHKLSB */ - u16 tunchk; /* IFCHK & LEVCHK */ - u16 testreg; /* TESTBITS & TESTMODE */ - u16 rdsstat; /* RDSSTAT1 & RDSSTAT2 */ - u16 rdslb; /* RDSLBMSB & RDSLBLSB */ - u16 rdspb; /* RDSPBMSB & RDSPBLSB */ - u16 rdsbc; /* RDSBBC & RDSGBC */ - u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */ - u16 rdsbbl; /* PAUSEDET & RDSBBL */ - u16 manid; /* MANID1 & MANID2 */ - u16 chipid; /* CHIPID1 & CHIPID2 */ -} __attribute__ ((packed)); - -struct tea5764_write_regs { - u8 intreg; /* INTMSK */ - u16 frqset; /* FRQSETMSB & FRQSETLSB */ - u16 tnctrl; /* TNCTRL1 & TNCTRL2 */ - u16 testreg; /* TESTBITS & TESTMODE */ - u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */ - u16 rdsbbl; /* PAUSEDET & RDSBBL */ -} __attribute__ ((packed)); - -#ifndef RADIO_TEA5764_XTAL -#define RADIO_TEA5764_XTAL 1 -#endif - -static int radio_nr = -1; -static int use_xtal = RADIO_TEA5764_XTAL; - -struct tea5764_device { - struct i2c_client *i2c_client; - struct video_device *videodev; - struct tea5764_regs regs; - struct mutex mutex; -}; - -/* I2C code related */ -int tea5764_i2c_read(struct tea5764_device *radio) -{ - int i; - u16 *p = (u16 *) &radio->regs; - - struct i2c_msg msgs[1] = { - { radio->i2c_client->addr, I2C_M_RD, sizeof(radio->regs), - (void *)&radio->regs }, - }; - if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1) - return -EIO; - for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++) - p[i] = __be16_to_cpu(p[i]); - - return 0; -} - -int tea5764_i2c_write(struct tea5764_device *radio) -{ - struct tea5764_write_regs wr; - struct tea5764_regs *r = &radio->regs; - struct i2c_msg msgs[1] = { - { radio->i2c_client->addr, 0, sizeof(wr), (void *) &wr }, - }; - wr.intreg = r->intreg & 0xff; - wr.frqset = __cpu_to_be16(r->frqset); - wr.tnctrl = __cpu_to_be16(r->tnctrl); - wr.testreg = __cpu_to_be16(r->testreg); - wr.rdsctrl = __cpu_to_be16(r->rdsctrl); - wr.rdsbbl = __cpu_to_be16(r->rdsbbl); - if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1) - return -EIO; - return 0; -} - -/* V4L2 code related */ -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - } -}; - -static void tea5764_power_up(struct tea5764_device *radio) -{ - struct tea5764_regs *r = &radio->regs; - - if (!(r->tnctrl & TEA5764_TNCTRL_PUPD0)) { - r->tnctrl &= ~(TEA5764_TNCTRL_AFM | TEA5764_TNCTRL_MU | - TEA5764_TNCTRL_HLSI); - if (!use_xtal) - r->testreg |= TEA5764_TESTREG_TRIGFR; - else - r->testreg &= ~TEA5764_TESTREG_TRIGFR; - - r->tnctrl |= TEA5764_TNCTRL_PUPD0; - tea5764_i2c_write(radio); - } -} - -static void tea5764_power_down(struct tea5764_device *radio) -{ - struct tea5764_regs *r = &radio->regs; - - if (r->tnctrl & TEA5764_TNCTRL_PUPD0) { - r->tnctrl &= ~TEA5764_TNCTRL_PUPD0; - tea5764_i2c_write(radio); - } -} - -static void tea5764_set_freq(struct tea5764_device *radio, int freq) -{ - struct tea5764_regs *r = &radio->regs; - - /* formula: (freq [+ or -] 225000) / 8192 */ - if (r->tnctrl & TEA5764_TNCTRL_HLSI) - r->frqset = (freq + 225000) / 8192; - else - r->frqset = (freq - 225000) / 8192; -} - -static int tea5764_get_freq(struct tea5764_device *radio) -{ - struct tea5764_regs *r = &radio->regs; - - if (r->tnctrl & TEA5764_TNCTRL_HLSI) - return (r->frqchk * 8192) - 225000; - else - return (r->frqchk * 8192) + 225000; -} - -/* tune an frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ -static void tea5764_tune(struct tea5764_device *radio, int freq) -{ - tea5764_set_freq(radio, freq); - if (tea5764_i2c_write(radio)) - PWARN("Could not set frequency!"); -} - -static void tea5764_set_audout_mode(struct tea5764_device *radio, int audmode) -{ - struct tea5764_regs *r = &radio->regs; - int tnctrl = r->tnctrl; - - if (audmode == V4L2_TUNER_MODE_MONO) - r->tnctrl |= TEA5764_TNCTRL_MST; - else - r->tnctrl &= ~TEA5764_TNCTRL_MST; - if (tnctrl != r->tnctrl) - tea5764_i2c_write(radio); -} - -static int tea5764_get_audout_mode(struct tea5764_device *radio) -{ - struct tea5764_regs *r = &radio->regs; - - if (r->tnctrl & TEA5764_TNCTRL_MST) - return V4L2_TUNER_MODE_MONO; - else - return V4L2_TUNER_MODE_STEREO; -} - -static void tea5764_mute(struct tea5764_device *radio, int on) -{ - struct tea5764_regs *r = &radio->regs; - int tnctrl = r->tnctrl; - - if (on) - r->tnctrl |= TEA5764_TNCTRL_MU; - else - r->tnctrl &= ~TEA5764_TNCTRL_MU; - if (tnctrl != r->tnctrl) - tea5764_i2c_write(radio); -} - -static int tea5764_is_muted(struct tea5764_device *radio) -{ - return radio->regs.tnctrl & TEA5764_TNCTRL_MU; -} - -/* V4L2 vidioc */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - struct tea5764_device *radio = video_drvdata(file); - struct video_device *dev = radio->videodev; - - strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver)); - strlcpy(v->card, dev->name, sizeof(v->card)); - snprintf(v->bus_info, sizeof(v->bus_info), - "I2C:%s", dev_name(&dev->dev)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct tea5764_device *radio = video_drvdata(file); - struct tea5764_regs *r = &radio->regs; - - if (v->index > 0) - return -EINVAL; - - memset(v, 0, sizeof(*v)); - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - tea5764_i2c_read(radio); - v->rangelow = FREQ_MIN * FREQ_MUL; - v->rangehigh = FREQ_MAX * FREQ_MUL; - v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - if (r->tunchk & TEA5764_TUNCHK_STEREO) - v->rxsubchans = V4L2_TUNER_SUB_STEREO; - else - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->audmode = tea5764_get_audout_mode(radio); - v->signal = TEA5764_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf; - v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk); - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct tea5764_device *radio = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - tea5764_set_audout_mode(radio, v->audmode); - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tea5764_device *radio = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (f->frequency == 0) { - /* We special case this as a power down control. */ - tea5764_power_down(radio); - } - if (f->frequency < (FREQ_MIN * FREQ_MUL)) - return -EINVAL; - if (f->frequency > (FREQ_MAX * FREQ_MUL)) - return -EINVAL; - tea5764_power_up(radio); - tea5764_tune(radio, (f->frequency * 125) / 2); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tea5764_device *radio = video_drvdata(file); - struct tea5764_regs *r = &radio->regs; - - if (f->tuner != 0) - return -EINVAL; - tea5764_i2c_read(radio); - memset(f, 0, sizeof(*f)); - f->type = V4L2_TUNER_RADIO; - if (r->tnctrl & TEA5764_TNCTRL_PUPD0) - f->frequency = (tea5764_get_freq(radio) * 2) / 125; - else - f->frequency = 0; - - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); - return 0; - } - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct tea5764_device *radio = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - tea5764_i2c_read(radio); - ctrl->value = tea5764_is_muted(radio) ? 1 : 0; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct tea5764_device *radio = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - tea5764_mute(radio, ctrl->value); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - - return 0; -} - -/* File system interface */ -static const struct v4l2_file_operations tea5764_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops tea5764_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -/* V4L2 interface */ -static struct video_device tea5764_radio_template = { - .name = "TEA5764 FM-Radio", - .fops = &tea5764_fops, - .ioctl_ops = &tea5764_ioctl_ops, - .release = video_device_release, -}; - -/* I2C probe: check if the device exists and register with v4l if it is */ -static int __devinit tea5764_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tea5764_device *radio; - struct tea5764_regs *r; - int ret; - - PDEBUG("probe"); - radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL); - if (!radio) - return -ENOMEM; - - mutex_init(&radio->mutex); - radio->i2c_client = client; - ret = tea5764_i2c_read(radio); - if (ret) - goto errfr; - r = &radio->regs; - PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid); - if (r->chipid != TEA5764_CHIPID || - (r->manid & 0x0fff) != TEA5764_MANID) { - PWARN("This chip is not a TEA5764!"); - ret = -EINVAL; - goto errfr; - } - - radio->videodev = video_device_alloc(); - if (!(radio->videodev)) { - ret = -ENOMEM; - goto errfr; - } - memcpy(radio->videodev, &tea5764_radio_template, - sizeof(tea5764_radio_template)); - - i2c_set_clientdata(client, radio); - video_set_drvdata(radio->videodev, radio); - radio->videodev->lock = &radio->mutex; - - /* initialize and power off the chip */ - tea5764_i2c_read(radio); - tea5764_set_audout_mode(radio, V4L2_TUNER_MODE_STEREO); - tea5764_mute(radio, 1); - tea5764_power_down(radio); - - ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); - if (ret < 0) { - PWARN("Could not register video device!"); - goto errrel; - } - - PINFO("registered."); - return 0; -errrel: - video_device_release(radio->videodev); -errfr: - kfree(radio); - return ret; -} - -static int __devexit tea5764_i2c_remove(struct i2c_client *client) -{ - struct tea5764_device *radio = i2c_get_clientdata(client); - - PDEBUG("remove"); - if (radio) { - tea5764_power_down(radio); - video_unregister_device(radio->videodev); - kfree(radio); - } - return 0; -} - -/* I2C subsystem interface */ -static const struct i2c_device_id tea5764_id[] = { - { "radio-tea5764", 0 }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(i2c, tea5764_id); - -static struct i2c_driver tea5764_i2c_driver = { - .driver = { - .name = "radio-tea5764", - .owner = THIS_MODULE, - }, - .probe = tea5764_i2c_probe, - .remove = __devexit_p(tea5764_i2c_remove), - .id_table = tea5764_id, -}; - -/* init the driver */ -static int __init tea5764_init(void) -{ - int ret = i2c_add_driver(&tea5764_i2c_driver); - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": " - DRIVER_DESC "\n"); - return ret; -} - -/* cleanup the driver */ -static void __exit tea5764_exit(void) -{ - i2c_del_driver(&tea5764_i2c_driver); -} - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(use_xtal, int, 1); -MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board"); -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(radio_nr, "video4linux device number to use"); - -module_init(tea5764_init); -module_exit(tea5764_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-terratec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-terratec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-terratec.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-terratec.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,418 +0,0 @@ -/* Terratec ActiveRadio ISA Standalone card driver for Linux radio support - * (c) 1999 R. Offermanns (rolf@offermanns.de) - * based on the aimslab radio driver from M. Kirkwood - * many thanks to Michael Becker and Friedhelm Birth (from TerraTec) - * - * - * History: - * 1999-05-21 First preview release - * - * Notes on the hardware: - * There are two "main" chips on the card: - * - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf) - * - Philips SAA6588 (http://www-us.semiconductors.philips.com/acrobat/datasheets/SAA6588_1.pdf) - * (you can get the datasheet at the above links) - * - * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); - * Volume Control is done digitally - * - * there is a I2C controlled RDS decoder (SAA6588) onboard, which i would like to support someday - * (as soon i have understand how to get started :) - * If you can help me out with that, please contact me!! - * - * - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* kernel radio structs */ -#include -#include /* for KERNEL_VERSION MACRO */ -#include /* outb, outb_p */ -#include -#include - -MODULE_AUTHOR("R.OFFERMANNS & others"); -MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); -MODULE_LICENSE("GPL"); - -#ifndef CONFIG_RADIO_TERRATEC_PORT -#define CONFIG_RADIO_TERRATEC_PORT 0x590 -#endif - -static int io = CONFIG_RADIO_TERRATEC_PORT; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; - -#define WRT_DIS 0x00 -#define CLK_OFF 0x00 -#define IIC_DATA 0x01 -#define IIC_CLK 0x02 -#define DATA 0x04 -#define CLK_ON 0x08 -#define WRT_EN 0x10 - -struct terratec -{ - struct v4l2_device v4l2_dev; - struct video_device vdev; - int io; - int curvol; - unsigned long curfreq; - int muted; - struct mutex lock; -}; - -static struct terratec terratec_card; - -/* local things */ - -static void tt_write_vol(struct terratec *tt, int volume) -{ - int i; - - volume = volume + (volume * 32); /* change both channels */ - mutex_lock(&tt->lock); - for (i = 0; i < 8; i++) { - if (volume & (0x80 >> i)) - outb(0x80, tt->io + 1); - else - outb(0x00, tt->io + 1); - } - mutex_unlock(&tt->lock); -} - - - -static void tt_mute(struct terratec *tt) -{ - tt->muted = 1; - tt_write_vol(tt, 0); -} - -static int tt_setvol(struct terratec *tt, int vol) -{ - if (vol == tt->curvol) { /* requested volume = current */ - if (tt->muted) { /* user is unmuting the card */ - tt->muted = 0; - tt_write_vol(tt, vol); /* enable card */ - } - return 0; - } - - if (vol == 0) { /* volume = 0 means mute the card */ - tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */ - tt->curvol = vol; /* track the volume state! */ - return 0; - } - - tt->muted = 0; - tt_write_vol(tt, vol); - tt->curvol = vol; - return 0; -} - - -/* this is the worst part in this driver */ -/* many more or less strange things are going on here, but hey, it works :) */ - -static int tt_setfreq(struct terratec *tt, unsigned long freq1) -{ - int freq; - int i; - int p; - int temp; - long rest; - unsigned char buffer[25]; /* we have to bit shift 25 registers */ - - mutex_lock(&tt->lock); - - tt->curfreq = freq1; - - freq = freq1 / 160; /* convert the freq. to a nice to handle value */ - memset(buffer, 0, sizeof(buffer)); - - rest = freq * 10 + 10700; /* I once had understood what is going on here */ - /* maybe some wise guy (friedhelm?) can comment this stuff */ - i = 13; - p = 10; - temp = 102400; - while (rest != 0) { - if (rest % temp == rest) - buffer[i] = 0; - else { - buffer[i] = 1; - rest = rest - temp; - } - i--; - p--; - temp = temp / 2; - } - - for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */ - if (buffer[i] == 1) { - outb(WRT_EN | DATA, tt->io); - outb(WRT_EN | DATA | CLK_ON, tt->io); - outb(WRT_EN | DATA, tt->io); - } else { - outb(WRT_EN | 0x00, tt->io); - outb(WRT_EN | 0x00 | CLK_ON, tt->io); - } - } - outb(0x00, tt->io); - - mutex_unlock(&tt->lock); - - return 0; -} - -static int tt_getsigstr(struct terratec *tt) -{ - if (inb(tt->io) & 2) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); - strlcpy(v->card, "ActiveRadio", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct terratec *tt = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = 87 * 16000; - v->rangehigh = 108 * 16000; - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF * tt_getsigstr(tt); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct terratec *tt = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - tt_setfreq(tt, f->frequency); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct terratec *tt = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = tt->curfreq; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); - return 0; - } - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct terratec *tt = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (tt->muted) - ctrl->value = 1; - else - ctrl->value = 0; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = tt->curvol * 6554; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct terratec *tt = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - tt_mute(tt); - else - tt_setvol(tt,tt->curvol); - return 0; - case V4L2_CID_AUDIO_VOLUME: - tt_setvol(tt,ctrl->value); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static const struct v4l2_file_operations terratec_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops terratec_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, -}; - -static int __init terratec_init(void) -{ - struct terratec *tt = &terratec_card; - struct v4l2_device *v4l2_dev = &tt->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name)); - tt->io = io; - if (tt->io == -1) { - v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n"); - return -EINVAL; - } - if (!request_region(tt->io, 2, "terratec")) { - v4l2_err(v4l2_dev, "port 0x%x already in use\n", io); - return -EBUSY; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(tt->io, 2); - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } - - strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name)); - tt->vdev.v4l2_dev = v4l2_dev; - tt->vdev.fops = &terratec_fops; - tt->vdev.ioctl_ops = &terratec_ioctl_ops; - tt->vdev.release = video_device_release_empty; - video_set_drvdata(&tt->vdev, tt); - - mutex_init(&tt->lock); - - /* mute card - prevents noisy bootups */ - tt_write_vol(tt, 0); - - if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(&tt->v4l2_dev); - release_region(tt->io, 2); - return -EINVAL; - } - - v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); - return 0; -} - -static void __exit terratec_exit(void) -{ - struct terratec *tt = &terratec_card; - struct v4l2_device *v4l2_dev = &tt->v4l2_dev; - - video_unregister_device(&tt->vdev); - v4l2_device_unregister(&tt->v4l2_dev); - release_region(tt->io, 2); - v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n"); -} - -module_init(terratec_init); -module_exit(terratec_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-timb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-timb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-timb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-timb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,248 +0,0 @@ -/* - * radio-timb.c Timberdale FPGA Radio driver - * Copyright (c) 2009 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "timb-radio" - -struct timbradio { - struct timb_radio_platform_data pdata; - struct v4l2_subdev *sd_tuner; - struct v4l2_subdev *sd_dsp; - struct video_device video_dev; - struct v4l2_device v4l2_dev; - struct mutex lock; -}; - - -static int timbradio_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver)); - strlcpy(v->card, "Timberdale Radio", sizeof(v->card)); - snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME); - v->version = KERNEL_VERSION(0, 0, 1); - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int timbradio_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_tuner, tuner, g_tuner, v); -} - -static int timbradio_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v); -} - -static int timbradio_vidioc_g_input(struct file *filp, void *priv, - unsigned int *i) -{ - *i = 0; - return 0; -} - -static int timbradio_vidioc_s_input(struct file *filp, void *priv, - unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int timbradio_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int timbradio_vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static int timbradio_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_tuner, tuner, s_frequency, f); -} - -static int timbradio_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_tuner, tuner, g_frequency, f); -} - -static int timbradio_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_dsp, core, queryctrl, qc); -} - -static int timbradio_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_dsp, core, g_ctrl, ctrl); -} - -static int timbradio_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_dsp, core, s_ctrl, ctrl); -} - -static const struct v4l2_ioctl_ops timbradio_ioctl_ops = { - .vidioc_querycap = timbradio_vidioc_querycap, - .vidioc_g_tuner = timbradio_vidioc_g_tuner, - .vidioc_s_tuner = timbradio_vidioc_s_tuner, - .vidioc_g_frequency = timbradio_vidioc_g_frequency, - .vidioc_s_frequency = timbradio_vidioc_s_frequency, - .vidioc_g_input = timbradio_vidioc_g_input, - .vidioc_s_input = timbradio_vidioc_s_input, - .vidioc_g_audio = timbradio_vidioc_g_audio, - .vidioc_s_audio = timbradio_vidioc_s_audio, - .vidioc_queryctrl = timbradio_vidioc_queryctrl, - .vidioc_g_ctrl = timbradio_vidioc_g_ctrl, - .vidioc_s_ctrl = timbradio_vidioc_s_ctrl -}; - -static const struct v4l2_file_operations timbradio_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static int __devinit timbradio_probe(struct platform_device *pdev) -{ - struct timb_radio_platform_data *pdata = pdev->dev.platform_data; - struct timbradio *tr; - int err; - - if (!pdata) { - dev_err(&pdev->dev, "Platform data missing\n"); - err = -EINVAL; - goto err; - } - - tr = kzalloc(sizeof(*tr), GFP_KERNEL); - if (!tr) { - err = -ENOMEM; - goto err; - } - - tr->pdata = *pdata; - mutex_init(&tr->lock); - - strlcpy(tr->video_dev.name, "Timberdale Radio", - sizeof(tr->video_dev.name)); - tr->video_dev.fops = &timbradio_fops; - tr->video_dev.ioctl_ops = &timbradio_ioctl_ops; - tr->video_dev.release = video_device_release_empty; - tr->video_dev.minor = -1; - tr->video_dev.lock = &tr->lock; - - strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name)); - err = v4l2_device_register(NULL, &tr->v4l2_dev); - if (err) - goto err_v4l2_dev; - - tr->video_dev.v4l2_dev = &tr->v4l2_dev; - - err = video_register_device(&tr->video_dev, VFL_TYPE_RADIO, -1); - if (err) { - dev_err(&pdev->dev, "Error reg video\n"); - goto err_video_req; - } - - video_set_drvdata(&tr->video_dev, tr); - - platform_set_drvdata(pdev, tr); - return 0; - -err_video_req: - video_device_release_empty(&tr->video_dev); - v4l2_device_unregister(&tr->v4l2_dev); -err_v4l2_dev: - kfree(tr); -err: - dev_err(&pdev->dev, "Failed to register: %d\n", err); - - return err; -} - -static int __devexit timbradio_remove(struct platform_device *pdev) -{ - struct timbradio *tr = platform_get_drvdata(pdev); - - video_unregister_device(&tr->video_dev); - video_device_release_empty(&tr->video_dev); - - v4l2_device_unregister(&tr->v4l2_dev); - - kfree(tr); - - return 0; -} - -static struct platform_driver timbradio_platform_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, - .probe = timbradio_probe, - .remove = timbradio_remove, -}; - -/*--------------------------------------------------------------------------*/ - -static int __init timbradio_init(void) -{ - return platform_driver_register(&timbradio_platform_driver); -} - -static void __exit timbradio_exit(void) -{ - platform_driver_unregister(&timbradio_platform_driver); -} - -module_init(timbradio_init); -module_exit(timbradio_exit); - -MODULE_DESCRIPTION("Timberdale Radio driver"); -MODULE_AUTHOR("Mocean Laboratories "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:"DRIVER_NAME); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-trust.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-trust.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-trust.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-trust.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,434 +0,0 @@ -/* radio-trust.c - Trust FM Radio card driver for Linux 2.2 - * by Eric Lammerts - * - * Based on radio-aztech.c. Original notes: - * - * Adapted to support the Video for Linux API by - * Russell Kroll . Based on original tuner code by: - * - * Quay Ly - * Donald Song - * Jason Lewis (jlewis@twilight.vtc.vsc.edu) - * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) - * William McGrath (wmcgrath@twilight.vtc.vsc.edu) - * - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -#include -#include -#include -#include -#include /* for KERNEL_VERSION MACRO */ -#include -#include -#include -#include - -MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); -MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); -MODULE_LICENSE("GPL"); - -/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ - -#ifndef CONFIG_RADIO_TRUST_PORT -#define CONFIG_RADIO_TRUST_PORT -1 -#endif - -static int io = CONFIG_RADIO_TRUST_PORT; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - -struct trust { - struct v4l2_device v4l2_dev; - struct video_device vdev; - int io; - int ioval; - __u16 curvol; - __u16 curbass; - __u16 curtreble; - int muted; - unsigned long curfreq; - int curstereo; - int curmute; - struct mutex lock; -}; - -static struct trust trust_card; - -/* i2c addresses */ -#define TDA7318_ADDR 0x88 -#define TSA6060T_ADDR 0xc4 - -#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0) -#define TR_SET_SCL outb(tr->ioval |= 2, tr->io) -#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io) -#define TR_SET_SDA outb(tr->ioval |= 1, tr->io) -#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io) - -static void write_i2c(struct trust *tr, int n, ...) -{ - unsigned char val, mask; - va_list args; - - va_start(args, n); - - /* start condition */ - TR_SET_SDA; - TR_SET_SCL; - TR_DELAY; - TR_CLR_SDA; - TR_CLR_SCL; - TR_DELAY; - - for(; n; n--) { - val = va_arg(args, unsigned); - for(mask = 0x80; mask; mask >>= 1) { - if(val & mask) - TR_SET_SDA; - else - TR_CLR_SDA; - TR_SET_SCL; - TR_DELAY; - TR_CLR_SCL; - TR_DELAY; - } - /* acknowledge bit */ - TR_SET_SDA; - TR_SET_SCL; - TR_DELAY; - TR_CLR_SCL; - TR_DELAY; - } - - /* stop condition */ - TR_CLR_SDA; - TR_DELAY; - TR_SET_SCL; - TR_DELAY; - TR_SET_SDA; - TR_DELAY; - - va_end(args); -} - -static void tr_setvol(struct trust *tr, __u16 vol) -{ - mutex_lock(&tr->lock); - tr->curvol = vol / 2048; - write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f); - mutex_unlock(&tr->lock); -} - -static int basstreble2chip[15] = { - 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 -}; - -static void tr_setbass(struct trust *tr, __u16 bass) -{ - mutex_lock(&tr->lock); - tr->curbass = bass / 4370; - write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]); - mutex_unlock(&tr->lock); -} - -static void tr_settreble(struct trust *tr, __u16 treble) -{ - mutex_lock(&tr->lock); - tr->curtreble = treble / 4370; - write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]); - mutex_unlock(&tr->lock); -} - -static void tr_setstereo(struct trust *tr, int stereo) -{ - mutex_lock(&tr->lock); - tr->curstereo = !!stereo; - tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2); - outb(tr->ioval, tr->io); - mutex_unlock(&tr->lock); -} - -static void tr_setmute(struct trust *tr, int mute) -{ - mutex_lock(&tr->lock); - tr->curmute = !!mute; - tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3); - outb(tr->ioval, tr->io); - mutex_unlock(&tr->lock); -} - -static int tr_getsigstr(struct trust *tr) -{ - int i, v; - - mutex_lock(&tr->lock); - for (i = 0, v = 0; i < 100; i++) - v |= inb(tr->io); - mutex_unlock(&tr->lock); - return (v & 1) ? 0 : 0xffff; -} - -static int tr_getstereo(struct trust *tr) -{ - /* don't know how to determine it, just return the setting */ - return tr->curstereo; -} - -static void tr_setfreq(struct trust *tr, unsigned long f) -{ - mutex_lock(&tr->lock); - tr->curfreq = f; - f /= 160; /* Convert to 10 kHz units */ - f += 1070; /* Add 10.7 MHz IF */ - write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); - mutex_unlock(&tr->lock); -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-trust", sizeof(v->driver)); - strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct trust *tr = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = 87.5 * 16000; - v->rangehigh = 108 * 16000; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if (tr_getstereo(tr)) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = tr_getsigstr(tr); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct trust *tr = video_drvdata(file); - - if (v->index) - return -EINVAL; - tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO); - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct trust *tr = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - tr_setfreq(tr, f->frequency); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct trust *tr = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = tr->curfreq; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535); - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct trust *tr = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = tr->curmute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = tr->curvol * 2048; - return 0; - case V4L2_CID_AUDIO_BASS: - ctrl->value = tr->curbass * 4370; - return 0; - case V4L2_CID_AUDIO_TREBLE: - ctrl->value = tr->curtreble * 4370; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct trust *tr = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - tr_setmute(tr, ctrl->value); - return 0; - case V4L2_CID_AUDIO_VOLUME: - tr_setvol(tr, ctrl->value); - return 0; - case V4L2_CID_AUDIO_BASS: - tr_setbass(tr, ctrl->value); - return 0; - case V4L2_CID_AUDIO_TREBLE: - tr_settreble(tr, ctrl->value); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static const struct v4l2_file_operations trust_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops trust_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, -}; - -static int __init trust_init(void) -{ - struct trust *tr = &trust_card; - struct v4l2_device *v4l2_dev = &tr->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name)); - tr->io = io; - tr->ioval = 0xf; - mutex_init(&tr->lock); - - if (tr->io == -1) { - v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n"); - return -EINVAL; - } - if (!request_region(tr->io, 2, "Trust FM Radio")) { - v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io); - return -EBUSY; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(tr->io, 2); - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } - - strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name)); - tr->vdev.v4l2_dev = v4l2_dev; - tr->vdev.fops = &trust_fops; - tr->vdev.ioctl_ops = &trust_ioctl_ops; - tr->vdev.release = video_device_release_empty; - video_set_drvdata(&tr->vdev, tr); - - write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ - write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ - write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ - write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ - write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ - - tr_setvol(tr, 0xffff); - tr_setbass(tr, 0x8000); - tr_settreble(tr, 0x8000); - tr_setstereo(tr, 1); - - /* mute card - prevents noisy bootups */ - tr_setmute(tr, 1); - - if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(tr->io, 2); - return -EINVAL; - } - - v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); - - return 0; -} - -static void __exit cleanup_trust_module(void) -{ - struct trust *tr = &trust_card; - - video_unregister_device(&tr->vdev); - v4l2_device_unregister(&tr->v4l2_dev); - release_region(tr->io, 2); -} - -module_init(trust_init); -module_exit(cleanup_trust_module); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-typhoon.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-typhoon.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-typhoon.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-typhoon.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,407 +0,0 @@ -/* Typhoon Radio Card driver for radio support - * (c) 1999 Dr. Henrik Seidel - * - * Notes on the hardware - * - * This card has two output sockets, one for speakers and one for line. - * The speaker output has volume control, but only in four discrete - * steps. The line output has neither volume control nor mute. - * - * The card has auto-stereo according to its manual, although it all - * sounds mono to me (even with the Win/DOS drivers). Maybe it's my - * antenna - I really don't know for sure. - * - * Frequency control is done digitally. - * - * Volume control is done digitally, but there are only four different - * possible values. So you should better always turn the volume up and - * use line control. I got the best results by connecting line output - * to the sound card microphone input. For such a configuration the - * volume control has no effect, since volume control only influences - * the speaker output. - * - * There is no explicit mute/unmute. So I set the radio frequency to a - * value where I do expect just noise and turn the speaker volume down. - * The frequency change is necessary since the card never seems to be - * completely silent. - * - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* for KERNEL_VERSION MACRO */ -#include /* kernel radio structs */ -#include /* outb, outb_p */ -#include -#include - -MODULE_AUTHOR("Dr. Henrik Seidel"); -MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); -MODULE_LICENSE("GPL"); - -#ifndef CONFIG_RADIO_TYPHOON_PORT -#define CONFIG_RADIO_TYPHOON_PORT -1 -#endif - -#ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ -#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 -#endif - -static int io = CONFIG_RADIO_TYPHOON_PORT; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); - -module_param(radio_nr, int, 0); - -static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ; -module_param(mutefreq, ulong, 0); -MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); - -#define RADIO_VERSION KERNEL_VERSION(0, 1, 1) - -#define BANNER "Typhoon Radio Card driver v0.1.1\n" - -struct typhoon { - struct v4l2_device v4l2_dev; - struct video_device vdev; - int io; - int curvol; - int muted; - unsigned long curfreq; - unsigned long mutefreq; - struct mutex lock; -}; - -static struct typhoon typhoon_card; - -static void typhoon_setvol_generic(struct typhoon *dev, int vol) -{ - mutex_lock(&dev->lock); - vol >>= 14; /* Map 16 bit to 2 bit */ - vol &= 3; - outb_p(vol / 2, dev->io); /* Set the volume, high bit. */ - outb_p(vol % 2, dev->io + 2); /* Set the volume, low bit. */ - mutex_unlock(&dev->lock); -} - -static int typhoon_setfreq_generic(struct typhoon *dev, - unsigned long frequency) -{ - unsigned long outval; - unsigned long x; - - /* - * The frequency transfer curve is not linear. The best fit I could - * get is - * - * outval = -155 + exp((f + 15.55) * 0.057)) - * - * where frequency f is in MHz. Since we don't have exp in the kernel, - * I approximate this function by a third order polynomial. - * - */ - - mutex_lock(&dev->lock); - x = frequency / 160; - outval = (x * x + 2500) / 5000; - outval = (outval * x + 5000) / 10000; - outval -= (10 * x * x + 10433) / 20866; - outval += 4 * x - 11505; - - outb_p((outval >> 8) & 0x01, dev->io + 4); - outb_p(outval >> 9, dev->io + 6); - outb_p(outval & 0xff, dev->io + 8); - mutex_unlock(&dev->lock); - - return 0; -} - -static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency) -{ - typhoon_setfreq_generic(dev, frequency); - dev->curfreq = frequency; - return 0; -} - -static void typhoon_mute(struct typhoon *dev) -{ - if (dev->muted == 1) - return; - typhoon_setvol_generic(dev, 0); - typhoon_setfreq_generic(dev, dev->mutefreq); - dev->muted = 1; -} - -static void typhoon_unmute(struct typhoon *dev) -{ - if (dev->muted == 0) - return; - typhoon_setfreq_generic(dev, dev->curfreq); - typhoon_setvol_generic(dev, dev->curvol); - dev->muted = 0; -} - -static int typhoon_setvol(struct typhoon *dev, int vol) -{ - if (dev->muted && vol != 0) { /* user is unmuting the card */ - dev->curvol = vol; - typhoon_unmute(dev); - return 0; - } - if (vol == dev->curvol) /* requested volume == current */ - return 0; - - if (vol == 0) { /* volume == 0 means mute the card */ - typhoon_mute(dev); - dev->curvol = vol; - return 0; - } - typhoon_setvol_generic(dev, vol); - dev->curvol = vol; - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-typhoon", sizeof(v->driver)); - strlcpy(v->card, "Typhoon Radio", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = 87.5 * 16000; - v->rangehigh = 108 * 16000; - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF; /* We can't get the signal strength */ - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct typhoon *dev = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = dev->curfreq; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct typhoon *dev = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - dev->curfreq = f->frequency; - typhoon_setfreq(dev, dev->curfreq); - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct typhoon *dev = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = dev->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = dev->curvol; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl (struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct typhoon *dev = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - typhoon_mute(dev); - else - typhoon_unmute(dev); - return 0; - case V4L2_CID_AUDIO_VOLUME: - typhoon_setvol(dev, ctrl->value); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static int vidioc_log_status(struct file *file, void *priv) -{ - struct typhoon *dev = video_drvdata(file); - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - - v4l2_info(v4l2_dev, BANNER); -#ifdef MODULE - v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n"); -#else - v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n"); -#endif - v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4); - v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol); - v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ? "on" : "off"); - v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io); - v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4); - return 0; -} - -static const struct v4l2_file_operations typhoon_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { - .vidioc_log_status = vidioc_log_status, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static int __init typhoon_init(void) -{ - struct typhoon *dev = &typhoon_card; - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name)); - dev->io = io; - - if (dev->io == -1) { - v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n"); - return -EINVAL; - } - - if (mutefreq < 87000 || mutefreq > 108500) { - v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n"); - v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); - return -EINVAL; - } - dev->curfreq = dev->mutefreq = mutefreq << 4; - - mutex_init(&dev->lock); - if (!request_region(dev->io, 8, "typhoon")) { - v4l2_err(v4l2_dev, "port 0x%x already in use\n", - dev->io); - return -EBUSY; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(dev->io, 8); - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } - v4l2_info(v4l2_dev, BANNER); - - strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; - dev->vdev.fops = &typhoon_fops; - dev->vdev.ioctl_ops = &typhoon_ioctl_ops; - dev->vdev.release = video_device_release_empty; - video_set_drvdata(&dev->vdev, dev); - - /* mute card - prevents noisy bootups */ - typhoon_mute(dev); - - if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(&dev->v4l2_dev); - release_region(dev->io, 8); - return -EINVAL; - } - v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io); - v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq); - - return 0; -} - -static void __exit typhoon_exit(void) -{ - struct typhoon *dev = &typhoon_card; - - video_unregister_device(&dev->vdev); - v4l2_device_unregister(&dev->v4l2_dev); - release_region(dev->io, 8); -} - -module_init(typhoon_init); -module_exit(typhoon_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-wl1273.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-wl1273.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-wl1273.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-wl1273.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2177 +0,0 @@ -/* - * Driver for the Texas Instruments WL1273 FM radio. - * - * Copyright (C) 2011 Nokia Corporation - * Author: Matti J. Aaltonen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_DESC "Wl1273 FM Radio" - -#define WL1273_POWER_SET_OFF 0 -#define WL1273_POWER_SET_FM BIT(0) -#define WL1273_POWER_SET_RDS BIT(1) -#define WL1273_POWER_SET_RETENTION BIT(4) - -#define WL1273_PUPD_SET_OFF 0x00 -#define WL1273_PUPD_SET_ON 0x01 -#define WL1273_PUPD_SET_RETENTION 0x10 - -#define WL1273_FREQ(x) (x * 10000 / 625) -#define WL1273_INV_FREQ(x) (x * 625 / 10000) - -/* - * static int radio_nr - The number of the radio device - * - * The default is 0. - */ -static int radio_nr; -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(radio_nr, "The number of the radio device. Default = 0"); - -struct wl1273_device { - char *bus_type; - - u8 forbidden; - unsigned int preemphasis; - unsigned int spacing; - unsigned int tx_power; - unsigned int rx_frequency; - unsigned int tx_frequency; - unsigned int rangelow; - unsigned int rangehigh; - unsigned int band; - bool stereo; - - /* RDS */ - unsigned int rds_on; - - wait_queue_head_t read_queue; - struct mutex lock; /* for serializing fm radio operations */ - struct completion busy; - - unsigned char *buffer; - unsigned int buf_size; - unsigned int rd_index; - unsigned int wr_index; - - /* Selected interrupts */ - u16 irq_flags; - u16 irq_received; - - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_device v4l2dev; - struct video_device videodev; - struct device *dev; - struct wl1273_core *core; - struct file *owner; - char *write_buf; - unsigned int rds_users; -}; - -#define WL1273_IRQ_MASK (WL1273_FR_EVENT | \ - WL1273_POW_ENB_EVENT) - -/* - * static unsigned int rds_buf - the number of RDS buffer blocks used. - * - * The default number is 100. - */ -static unsigned int rds_buf = 100; -module_param(rds_buf, uint, 0); -MODULE_PARM_DESC(rds_buf, "Number of RDS buffer entries. Default = 100"); - -static int wl1273_fm_write_fw(struct wl1273_core *core, - __u8 *fw, int len) -{ - struct i2c_client *client = core->client; - struct i2c_msg msg; - int i, r = 0; - - msg.addr = client->addr; - msg.flags = 0; - - for (i = 0; i <= len; i++) { - msg.len = fw[0]; - msg.buf = fw + 1; - - fw += msg.len + 1; - dev_dbg(&client->dev, "%s:len[%d]: %d\n", __func__, i, msg.len); - - r = i2c_transfer(client->adapter, &msg, 1); - if (r < 0 && i < len + 1) - break; - } - - dev_dbg(&client->dev, "%s: i: %d\n", __func__, i); - dev_dbg(&client->dev, "%s: len + 1: %d\n", __func__, len + 1); - - /* Last transfer always fails. */ - if (i == len || r == 1) - r = 0; - - return r; -} - -#define WL1273_FIFO_HAS_DATA(status) (1 << 5 & status) -#define WL1273_RDS_CORRECTABLE_ERROR (1 << 3) -#define WL1273_RDS_UNCORRECTABLE_ERROR (1 << 4) - -static int wl1273_fm_rds(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - struct i2c_client *client = core->client; - u16 val; - u8 b0 = WL1273_RDS_DATA_GET, status; - struct v4l2_rds_data rds = { 0, 0, 0 }; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .buf = &b0, - .len = 1, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .buf = (u8 *) &rds, - .len = sizeof(rds), - } - }; - int r; - - if (core->mode != WL1273_MODE_RX) - return 0; - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) - return r; - - if ((val & 0x01) == 0) { - /* RDS decoder not synchronized */ - return -EAGAIN; - } - - /* copy all four RDS blocks to internal buffer */ - do { - r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); - if (r != ARRAY_SIZE(msg)) { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME - ": %s: read_rds error r == %i)\n", - __func__, r); - } - - status = rds.block; - - if (!WL1273_FIFO_HAS_DATA(status)) - break; - - /* copy bits 0-2 (the block ID) to bits 3-5 */ - rds.block = V4L2_RDS_BLOCK_MSK & status; - rds.block |= rds.block << 3; - - /* copy the error bits to standard positions */ - if (WL1273_RDS_UNCORRECTABLE_ERROR & status) { - rds.block |= V4L2_RDS_BLOCK_ERROR; - rds.block &= ~V4L2_RDS_BLOCK_CORRECTED; - } else if (WL1273_RDS_CORRECTABLE_ERROR & status) { - rds.block &= ~V4L2_RDS_BLOCK_ERROR; - rds.block |= V4L2_RDS_BLOCK_CORRECTED; - } - - /* copy RDS block to internal buffer */ - memcpy(&radio->buffer[radio->wr_index], &rds, RDS_BLOCK_SIZE); - radio->wr_index += 3; - - /* wrap write pointer */ - if (radio->wr_index >= radio->buf_size) - radio->wr_index = 0; - - /* check for overflow & start over */ - if (radio->wr_index == radio->rd_index) { - dev_dbg(radio->dev, "RDS OVERFLOW"); - - radio->rd_index = 0; - radio->wr_index = 0; - break; - } - } while (WL1273_FIFO_HAS_DATA(status)); - - /* wake up read queue */ - if (radio->wr_index != radio->rd_index) - wake_up_interruptible(&radio->read_queue); - - return 0; -} - -static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) -{ - struct wl1273_device *radio = dev_id; - struct wl1273_core *core = radio->core; - u16 flags; - int r; - - r = core->read(core, WL1273_FLAG_GET, &flags); - if (r) - goto out; - - if (flags & WL1273_BL_EVENT) { - radio->irq_received = flags; - dev_dbg(radio->dev, "IRQ: BL\n"); - } - - if (flags & WL1273_RDS_EVENT) { - msleep(200); - - wl1273_fm_rds(radio); - } - - if (flags & WL1273_BBLK_EVENT) - dev_dbg(radio->dev, "IRQ: BBLK\n"); - - if (flags & WL1273_LSYNC_EVENT) - dev_dbg(radio->dev, "IRQ: LSYNC\n"); - - if (flags & WL1273_LEV_EVENT) { - u16 level; - - r = core->read(core, WL1273_RSSI_LVL_GET, &level); - if (r) - goto out; - - if (level > 14) - dev_dbg(radio->dev, "IRQ: LEV: 0x%x04\n", level); - } - - if (flags & WL1273_IFFR_EVENT) - dev_dbg(radio->dev, "IRQ: IFFR\n"); - - if (flags & WL1273_PI_EVENT) - dev_dbg(radio->dev, "IRQ: PI\n"); - - if (flags & WL1273_PD_EVENT) - dev_dbg(radio->dev, "IRQ: PD\n"); - - if (flags & WL1273_STIC_EVENT) - dev_dbg(radio->dev, "IRQ: STIC\n"); - - if (flags & WL1273_MAL_EVENT) - dev_dbg(radio->dev, "IRQ: MAL\n"); - - if (flags & WL1273_POW_ENB_EVENT) { - complete(&radio->busy); - dev_dbg(radio->dev, "NOT BUSY\n"); - dev_dbg(radio->dev, "IRQ: POW_ENB\n"); - } - - if (flags & WL1273_SCAN_OVER_EVENT) - dev_dbg(radio->dev, "IRQ: SCAN_OVER\n"); - - if (flags & WL1273_ERROR_EVENT) - dev_dbg(radio->dev, "IRQ: ERROR\n"); - - if (flags & WL1273_FR_EVENT) { - u16 freq; - - dev_dbg(radio->dev, "IRQ: FR:\n"); - - if (core->mode == WL1273_MODE_RX) { - r = core->write(core, WL1273_TUNER_MODE_SET, - TUNER_MODE_STOP_SEARCH); - if (r) { - dev_err(radio->dev, - "%s: TUNER_MODE_SET fails: %d\n", - __func__, r); - goto out; - } - - r = core->read(core, WL1273_FREQ_SET, &freq); - if (r) - goto out; - - if (radio->band == WL1273_BAND_JAPAN) - radio->rx_frequency = WL1273_BAND_JAPAN_LOW + - freq * 50; - else - radio->rx_frequency = WL1273_BAND_OTHER_LOW + - freq * 50; - /* - * The driver works better with this msleep, - * the documentation doesn't mention it. - */ - usleep_range(10000, 15000); - - dev_dbg(radio->dev, "%dkHz\n", radio->rx_frequency); - - } else { - r = core->read(core, WL1273_CHANL_SET, &freq); - if (r) - goto out; - - dev_dbg(radio->dev, "%dkHz\n", freq); - } - dev_dbg(radio->dev, "%s: NOT BUSY\n", __func__); - } - -out: - core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - complete(&radio->busy); - - return IRQ_HANDLED; -} - -static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) -{ - struct wl1273_core *core = radio->core; - int r = 0; - - if (freq < WL1273_BAND_TX_LOW) { - dev_err(radio->dev, - "Frequency out of range: %d < %d\n", freq, - WL1273_BAND_TX_LOW); - return -ERANGE; - } - - if (freq > WL1273_BAND_TX_HIGH) { - dev_err(radio->dev, - "Frequency out of range: %d > %d\n", freq, - WL1273_BAND_TX_HIGH); - return -ERANGE; - } - - /* - * The driver works better with this sleep, - * the documentation doesn't mention it. - */ - usleep_range(5000, 10000); - - dev_dbg(radio->dev, "%s: freq: %d kHz\n", __func__, freq); - - /* Set the current tx channel */ - r = core->write(core, WL1273_CHANL_SET, freq / 10); - if (r) - return r; - - INIT_COMPLETION(radio->busy); - - /* wait for the FR IRQ */ - r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); - if (!r) - return -ETIMEDOUT; - - dev_dbg(radio->dev, "WL1273_CHANL_SET: %d\n", r); - - /* Enable the output power */ - r = core->write(core, WL1273_POWER_ENB_SET, 1); - if (r) - return r; - - INIT_COMPLETION(radio->busy); - - /* wait for the POWER_ENB IRQ */ - r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); - if (!r) - return -ETIMEDOUT; - - radio->tx_frequency = freq; - dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %d\n", r); - - return 0; -} - -static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq) -{ - struct wl1273_core *core = radio->core; - int r, f; - - if (freq < radio->rangelow) { - dev_err(radio->dev, - "Frequency out of range: %d < %d\n", freq, - radio->rangelow); - r = -ERANGE; - goto err; - } - - if (freq > radio->rangehigh) { - dev_err(radio->dev, - "Frequency out of range: %d > %d\n", freq, - radio->rangehigh); - r = -ERANGE; - goto err; - } - - dev_dbg(radio->dev, "%s: %dkHz\n", __func__, freq); - - core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - - if (radio->band == WL1273_BAND_JAPAN) - f = (freq - WL1273_BAND_JAPAN_LOW) / 50; - else - f = (freq - WL1273_BAND_OTHER_LOW) / 50; - - r = core->write(core, WL1273_FREQ_SET, f); - if (r) { - dev_err(radio->dev, "FREQ_SET fails\n"); - goto err; - } - - r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET); - if (r) { - dev_err(radio->dev, "TUNER_MODE_SET fails\n"); - goto err; - } - - INIT_COMPLETION(radio->busy); - - r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); - if (!r) { - dev_err(radio->dev, "%s: TIMEOUT\n", __func__); - return -ETIMEDOUT; - } - - radio->rd_index = 0; - radio->wr_index = 0; - radio->rx_frequency = freq; - return 0; -err: - return r; -} - -static int wl1273_fm_get_freq(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - unsigned int freq; - u16 f; - int r; - - if (core->mode == WL1273_MODE_RX) { - r = core->read(core, WL1273_FREQ_SET, &f); - if (r) - return r; - - dev_dbg(radio->dev, "Freq get: 0x%04x\n", f); - if (radio->band == WL1273_BAND_JAPAN) - freq = WL1273_BAND_JAPAN_LOW + 50 * f; - else - freq = WL1273_BAND_OTHER_LOW + 50 * f; - } else { - r = core->read(core, WL1273_CHANL_SET, &f); - if (r) - return r; - - freq = f * 10; - } - - return freq; -} - -/** - * wl1273_fm_upload_firmware_patch() - Upload the firmware. - * @radio: A pointer to the device struct. - * - * The firmware file consists of arrays of bytes where the first byte - * gives the array length. The first byte in the file gives the - * number of these arrays. - */ -static int wl1273_fm_upload_firmware_patch(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - unsigned int packet_num; - const struct firmware *fw_p; - const char *fw_name = "radio-wl1273-fw.bin"; - struct device *dev = radio->dev; - __u8 *ptr; - int r; - - dev_dbg(dev, "%s:\n", __func__); - - /* - * Uploading the firmware patch is not always necessary, - * so we only print an info message. - */ - if (request_firmware(&fw_p, fw_name, dev)) { - dev_info(dev, "%s - %s not found\n", __func__, fw_name); - - return 0; - } - - ptr = (__u8 *) fw_p->data; - packet_num = ptr[0]; - dev_dbg(dev, "%s: packets: %d\n", __func__, packet_num); - - r = wl1273_fm_write_fw(core, ptr + 1, packet_num); - if (r) { - dev_err(dev, "FW upload error: %d\n", r); - goto out; - } - - /* ignore possible error here */ - core->write(core, WL1273_RESET, 0); - - dev_dbg(dev, "%s - download OK, r: %d\n", __func__, r); -out: - release_firmware(fw_p); - return r; -} - -static int wl1273_fm_stop(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - - if (core->mode == WL1273_MODE_RX) { - int r = core->write(core, WL1273_POWER_SET, - WL1273_POWER_SET_OFF); - if (r) - dev_err(radio->dev, "%s: POWER_SET fails: %d\n", - __func__, r); - } else if (core->mode == WL1273_MODE_TX) { - int r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_OFF); - if (r) - dev_err(radio->dev, - "%s: PUPD_SET fails: %d\n", __func__, r); - } - - if (core->pdata->disable) { - core->pdata->disable(); - dev_dbg(radio->dev, "Back to reset\n"); - } - - return 0; -} - -static int wl1273_fm_start(struct wl1273_device *radio, int new_mode) -{ - struct wl1273_core *core = radio->core; - struct wl1273_fm_platform_data *pdata = core->pdata; - struct device *dev = radio->dev; - int r = -EINVAL; - - if (pdata->enable && core->mode == WL1273_MODE_OFF) { - dev_dbg(radio->dev, "Out of reset\n"); - - pdata->enable(); - msleep(250); - } - - if (new_mode == WL1273_MODE_RX) { - u16 val = WL1273_POWER_SET_FM; - - if (radio->rds_on) - val |= WL1273_POWER_SET_RDS; - - /* If this fails try again */ - r = core->write(core, WL1273_POWER_SET, val); - if (r) { - msleep(100); - - r = core->write(core, WL1273_POWER_SET, val); - if (r) { - dev_err(dev, "%s: POWER_SET fails\n", __func__); - goto fail; - } - } - - /* rds buffer configuration */ - radio->wr_index = 0; - radio->rd_index = 0; - - } else if (new_mode == WL1273_MODE_TX) { - /* If this fails try again once */ - r = core->write(core, WL1273_PUPD_SET, WL1273_PUPD_SET_ON); - if (r) { - msleep(100); - r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_ON); - if (r) { - dev_err(dev, "%s: PUPD_SET fails\n", __func__); - goto fail; - } - } - - if (radio->rds_on) - r = core->write(core, WL1273_RDS_DATA_ENB, 1); - else - r = core->write(core, WL1273_RDS_DATA_ENB, 0); - } else { - dev_warn(dev, "%s: Illegal mode.\n", __func__); - } - - if (core->mode == WL1273_MODE_OFF) { - r = wl1273_fm_upload_firmware_patch(radio); - if (r) - dev_warn(dev, "Firmware upload failed.\n"); - - /* - * Sometimes the chip is in a wrong power state at this point. - * So we set the power once again. - */ - if (new_mode == WL1273_MODE_RX) { - u16 val = WL1273_POWER_SET_FM; - - if (radio->rds_on) - val |= WL1273_POWER_SET_RDS; - - r = core->write(core, WL1273_POWER_SET, val); - if (r) { - dev_err(dev, "%s: POWER_SET fails\n", __func__); - goto fail; - } - } else if (new_mode == WL1273_MODE_TX) { - r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_ON); - if (r) { - dev_err(dev, "%s: PUPD_SET fails\n", __func__); - goto fail; - } - } - } - - return 0; -fail: - if (pdata->disable) - pdata->disable(); - - dev_dbg(dev, "%s: return: %d\n", __func__, r); - return r; -} - -static int wl1273_fm_suspend(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - int r = 0; - - /* Cannot go from OFF to SUSPENDED */ - if (core->mode == WL1273_MODE_RX) - r = core->write(core, WL1273_POWER_SET, - WL1273_POWER_SET_RETENTION); - else if (core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_RETENTION); - else - r = -EINVAL; - - if (r) { - dev_err(radio->dev, "%s: POWER_SET fails: %d\n", __func__, r); - goto out; - } - -out: - return r; -} - -static int wl1273_fm_set_mode(struct wl1273_device *radio, int mode) -{ - struct wl1273_core *core = radio->core; - struct device *dev = radio->dev; - int old_mode; - int r; - - dev_dbg(dev, "%s\n", __func__); - dev_dbg(dev, "Forbidden modes: 0x%02x\n", radio->forbidden); - - old_mode = core->mode; - if (mode & radio->forbidden) { - r = -EPERM; - goto out; - } - - switch (mode) { - case WL1273_MODE_RX: - case WL1273_MODE_TX: - r = wl1273_fm_start(radio, mode); - if (r) { - dev_err(dev, "%s: Cannot start.\n", __func__); - wl1273_fm_stop(radio); - goto out; - } - - core->mode = mode; - r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - if (r) { - dev_err(dev, "INT_MASK_SET fails.\n"); - goto out; - } - - /* remember previous settings */ - if (mode == WL1273_MODE_RX) { - r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); - if (r) { - dev_err(dev, "set freq fails: %d.\n", r); - goto out; - } - - r = core->set_volume(core, core->volume); - if (r) { - dev_err(dev, "set volume fails: %d.\n", r); - goto out; - } - - dev_dbg(dev, "%s: Set vol: %d.\n", __func__, - core->volume); - } else { - r = wl1273_fm_set_tx_freq(radio, radio->tx_frequency); - if (r) { - dev_err(dev, "set freq fails: %d.\n", r); - goto out; - } - } - - dev_dbg(radio->dev, "%s: Set audio mode.\n", __func__); - - r = core->set_audio(core, core->audio_mode); - if (r) - dev_err(dev, "Cannot set audio mode.\n"); - break; - - case WL1273_MODE_OFF: - r = wl1273_fm_stop(radio); - if (r) - dev_err(dev, "%s: Off fails: %d\n", __func__, r); - else - core->mode = WL1273_MODE_OFF; - - break; - - case WL1273_MODE_SUSPENDED: - r = wl1273_fm_suspend(radio); - if (r) - dev_err(dev, "%s: Suspend fails: %d\n", __func__, r); - else - core->mode = WL1273_MODE_SUSPENDED; - - break; - - default: - dev_err(dev, "%s: Unknown mode: %d\n", __func__, mode); - r = -EINVAL; - break; - } -out: - if (r) - core->mode = old_mode; - - return r; -} - -static int wl1273_fm_set_seek(struct wl1273_device *radio, - unsigned int wrap_around, - unsigned int seek_upward, - int level) -{ - struct wl1273_core *core = radio->core; - int r = 0; - unsigned int dir = (seek_upward == 0) ? 0 : 1; - unsigned int f; - - f = radio->rx_frequency; - dev_dbg(radio->dev, "rx_frequency: %d\n", f); - - if (dir && f + radio->spacing <= radio->rangehigh) - r = wl1273_fm_set_rx_freq(radio, f + radio->spacing); - else if (dir && wrap_around) - r = wl1273_fm_set_rx_freq(radio, radio->rangelow); - else if (f - radio->spacing >= radio->rangelow) - r = wl1273_fm_set_rx_freq(radio, f - radio->spacing); - else if (wrap_around) - r = wl1273_fm_set_rx_freq(radio, radio->rangehigh); - - if (r) - goto out; - - if (level < SCHAR_MIN || level > SCHAR_MAX) - return -EINVAL; - - INIT_COMPLETION(radio->busy); - dev_dbg(radio->dev, "%s: BUSY\n", __func__); - - r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - if (r) - goto out; - - dev_dbg(radio->dev, "%s\n", __func__); - - r = core->write(core, WL1273_SEARCH_LVL_SET, level); - if (r) - goto out; - - r = core->write(core, WL1273_SEARCH_DIR_SET, dir); - if (r) - goto out; - - r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); - if (r) - goto out; - - wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); - if (!(radio->irq_received & WL1273_BL_EVENT)) - goto out; - - radio->irq_received &= ~WL1273_BL_EVENT; - - if (!wrap_around) - goto out; - - /* Wrap around */ - dev_dbg(radio->dev, "Wrap around in HW seek.\n"); - - if (seek_upward) - f = radio->rangelow; - else - f = radio->rangehigh; - - r = wl1273_fm_set_rx_freq(radio, f); - if (r) - goto out; - - INIT_COMPLETION(radio->busy); - dev_dbg(radio->dev, "%s: BUSY\n", __func__); - - r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); - if (r) - goto out; - - wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); -out: - dev_dbg(radio->dev, "%s: Err: %d\n", __func__, r); - return r; -} - -/** - * wl1273_fm_get_tx_ctune() - Get the TX tuning capacitor value. - * @radio: A pointer to the device struct. - */ -static unsigned int wl1273_fm_get_tx_ctune(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - struct device *dev = radio->dev; - u16 val; - int r; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - r = core->read(core, WL1273_READ_FMANT_TUNE_VALUE, &val); - if (r) { - dev_err(dev, "%s: read error: %d\n", __func__, r); - goto out; - } - -out: - return val; -} - -/** - * wl1273_fm_set_preemphasis() - Set the TX pre-emphasis value. - * @radio: A pointer to the device struct. - * @preemphasis: The new pre-amphasis value. - * - * Possible pre-emphasis values are: V4L2_PREEMPHASIS_DISABLED, - * V4L2_PREEMPHASIS_50_uS and V4L2_PREEMPHASIS_75_uS. - */ -static int wl1273_fm_set_preemphasis(struct wl1273_device *radio, - unsigned int preemphasis) -{ - struct wl1273_core *core = radio->core; - int r; - u16 em; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - mutex_lock(&core->lock); - - switch (preemphasis) { - case V4L2_PREEMPHASIS_DISABLED: - em = 1; - break; - case V4L2_PREEMPHASIS_50_uS: - em = 0; - break; - case V4L2_PREEMPHASIS_75_uS: - em = 2; - break; - default: - r = -EINVAL; - goto out; - } - - r = core->write(core, WL1273_PREMPH_SET, em); - if (r) - goto out; - - radio->preemphasis = preemphasis; - -out: - mutex_unlock(&core->lock); - return r; -} - -static int wl1273_fm_rds_on(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - if (radio->rds_on) - return 0; - - r = core->write(core, WL1273_POWER_SET, - WL1273_POWER_SET_FM | WL1273_POWER_SET_RDS); - if (r) - goto out; - - r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); - if (r) - dev_err(radio->dev, "set freq fails: %d.\n", r); -out: - return r; -} - -static int wl1273_fm_rds_off(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - int r; - - if (!radio->rds_on) - return 0; - - radio->irq_flags &= ~WL1273_RDS_EVENT; - - r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - if (r) - goto out; - - /* Service pending read */ - wake_up_interruptible(&radio->read_queue); - - dev_dbg(radio->dev, "%s\n", __func__); - - r = core->write(core, WL1273_POWER_SET, WL1273_POWER_SET_FM); - if (r) - goto out; - - r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); - if (r) - dev_err(radio->dev, "set freq fails: %d.\n", r); -out: - dev_dbg(radio->dev, "%s: exiting...\n", __func__); - - return r; -} - -static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode) -{ - int r = 0; - struct wl1273_core *core = radio->core; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - if (new_mode == WL1273_RDS_RESET) { - r = core->write(core, WL1273_RDS_CNTRL_SET, 1); - return r; - } - - if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_OFF) { - r = core->write(core, WL1273_RDS_DATA_ENB, 0); - } else if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_ON) { - r = core->write(core, WL1273_RDS_DATA_ENB, 1); - } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_OFF) { - r = wl1273_fm_rds_off(radio); - } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_ON) { - r = wl1273_fm_rds_on(radio); - } else { - dev_err(radio->dev, "%s: Unknown mode: %d\n", - __func__, new_mode); - r = -EINVAL; - } - - if (!r) - radio->rds_on = (new_mode == WL1273_RDS_ON) ? true : false; - - return r; -} - -static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - u16 val; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (core->mode != WL1273_MODE_TX) - return count; - - if (radio->rds_users == 0) { - dev_warn(radio->dev, "%s: RDS not on.\n", __func__); - return 0; - } - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - /* - * Multiple processes can open the device, but only - * one gets to write to it. - */ - if (radio->owner && radio->owner != file) { - r = -EBUSY; - goto out; - } - radio->owner = file; - - /* Manual Mode */ - if (count > 255) - val = 255; - else - val = count; - - core->write(core, WL1273_RDS_CONFIG_DATA_SET, val); - - if (copy_from_user(radio->write_buf + 1, buf, val)) { - r = -EFAULT; - goto out; - } - - dev_dbg(radio->dev, "Count: %d\n", val); - dev_dbg(radio->dev, "From user: \"%s\"\n", radio->write_buf); - - radio->write_buf[0] = WL1273_RDS_DATA_SET; - core->write_data(core, radio->write_buf, val + 1); - - r = val; -out: - mutex_unlock(&core->lock); - - return r; -} - -static unsigned int wl1273_fm_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - - if (radio->owner && radio->owner != file) - return -EBUSY; - - radio->owner = file; - - if (core->mode == WL1273_MODE_RX) { - poll_wait(file, &radio->read_queue, pts); - - if (radio->rd_index != radio->wr_index) - return POLLIN | POLLRDNORM; - - } else if (core->mode == WL1273_MODE_TX) { - return POLLOUT | POLLWRNORM; - } - - return 0; -} - -static int wl1273_fm_fops_open(struct file *file) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (core->mode == WL1273_MODE_RX && radio->rds_on && - !radio->rds_users) { - dev_dbg(radio->dev, "%s: Mode: %d\n", __func__, core->mode); - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - radio->irq_flags |= WL1273_RDS_EVENT; - - r = core->write(core, WL1273_INT_MASK_SET, - radio->irq_flags); - if (r) { - mutex_unlock(&core->lock); - goto out; - } - - radio->rds_users++; - - mutex_unlock(&core->lock); - } -out: - return r; -} - -static int wl1273_fm_fops_release(struct file *file) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (radio->rds_users > 0) { - radio->rds_users--; - if (radio->rds_users == 0) { - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - radio->irq_flags &= ~WL1273_RDS_EVENT; - - if (core->mode == WL1273_MODE_RX) { - r = core->write(core, - WL1273_INT_MASK_SET, - radio->irq_flags); - if (r) { - mutex_unlock(&core->lock); - goto out; - } - } - mutex_unlock(&core->lock); - } - } - - if (file == radio->owner) - radio->owner = NULL; -out: - return r; -} - -static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - int r = 0; - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - unsigned int block_count = 0; - u16 val; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (core->mode != WL1273_MODE_RX) - return 0; - - if (radio->rds_users == 0) { - dev_warn(radio->dev, "%s: RDS not on.\n", __func__); - return 0; - } - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - /* - * Multiple processes can open the device, but only - * one at a time gets read access. - */ - if (radio->owner && radio->owner != file) { - r = -EBUSY; - goto out; - } - radio->owner = file; - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) { - dev_err(radio->dev, "%s: Get RDS_SYNC fails.\n", __func__); - goto out; - } else if (val == 0) { - dev_info(radio->dev, "RDS_SYNC: Not synchronized\n"); - r = -ENODATA; - goto out; - } - - /* block if no new data available */ - while (radio->wr_index == radio->rd_index) { - if (file->f_flags & O_NONBLOCK) { - r = -EWOULDBLOCK; - goto out; - } - - dev_dbg(radio->dev, "%s: Wait for RDS data.\n", __func__); - if (wait_event_interruptible(radio->read_queue, - radio->wr_index != - radio->rd_index) < 0) { - r = -EINTR; - goto out; - } - } - - /* calculate block count from byte count */ - count /= RDS_BLOCK_SIZE; - - /* copy RDS blocks from the internal buffer and to user buffer */ - while (block_count < count) { - if (radio->rd_index == radio->wr_index) - break; - - /* always transfer complete RDS blocks */ - if (copy_to_user(buf, &radio->buffer[radio->rd_index], - RDS_BLOCK_SIZE)) - break; - - /* increment and wrap the read pointer */ - radio->rd_index += RDS_BLOCK_SIZE; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - - /* increment counters */ - block_count++; - buf += RDS_BLOCK_SIZE; - r += RDS_BLOCK_SIZE; - } - -out: - dev_dbg(radio->dev, "%s: exit\n", __func__); - mutex_unlock(&core->lock); - - return r; -} - -static const struct v4l2_file_operations wl1273_fops = { - .owner = THIS_MODULE, - .read = wl1273_fm_fops_read, - .write = wl1273_fm_fops_write, - .poll = wl1273_fm_fops_poll, - .unlocked_ioctl = video_ioctl2, - .open = wl1273_fm_fops_open, - .release = wl1273_fm_fops_release, -}; - -static int wl1273_fm_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - strlcpy(capability->driver, WL1273_FM_DRIVER_NAME, - sizeof(capability->driver)); - strlcpy(capability->card, "Texas Instruments Wl1273 FM Radio", - sizeof(capability->card)); - strlcpy(capability->bus_info, radio->bus_type, - sizeof(capability->bus_info)); - - capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | - V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_AUDIO | - V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR | - V4L2_CAP_RDS_OUTPUT; - - return 0; -} - -static int wl1273_fm_vidioc_g_input(struct file *file, void *priv, - unsigned int *i) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - *i = 0; - - return 0; -} - -static int wl1273_fm_vidioc_s_input(struct file *file, void *priv, - unsigned int i) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - if (i != 0) - return -EINVAL; - - return 0; -} - -/** - * wl1273_fm_set_tx_power() - Set the transmission power value. - * @core: A pointer to the device struct. - * @power: The new power value. - */ -static int wl1273_fm_set_tx_power(struct wl1273_device *radio, u16 power) -{ - struct wl1273_core *core = radio->core; - int r; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - mutex_lock(&core->lock); - - /* Convert the dBuV value to chip presentation */ - r = core->write(core, WL1273_POWER_LEV_SET, 122 - power); - if (r) - goto out; - - radio->tx_power = power; - -out: - mutex_unlock(&core->lock); - return r; -} - -#define WL1273_SPACING_50kHz 1 -#define WL1273_SPACING_100kHz 2 -#define WL1273_SPACING_200kHz 4 - -static int wl1273_fm_tx_set_spacing(struct wl1273_device *radio, - unsigned int spacing) -{ - struct wl1273_core *core = radio->core; - int r; - - if (spacing == 0) { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_100kHz); - radio->spacing = 100; - } else if (spacing - 50000 < 25000) { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_50kHz); - radio->spacing = 50; - } else if (spacing - 100000 < 50000) { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_100kHz); - radio->spacing = 100; - } else { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_200kHz); - radio->spacing = 200; - } - - return r; -} - -static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct wl1273_device *radio = ctrl->priv; - struct wl1273_core *core = radio->core; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - switch (ctrl->id) { - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - ctrl->val = wl1273_fm_get_tx_ctune(radio); - break; - - default: - dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n", - __func__, ctrl->id); - break; - } - - mutex_unlock(&core->lock); - - return 0; -} - -#define WL1273_MUTE_SOFT_ENABLE (1 << 0) -#define WL1273_MUTE_AC (1 << 1) -#define WL1273_MUTE_HARD_LEFT (1 << 2) -#define WL1273_MUTE_HARD_RIGHT (1 << 3) -#define WL1273_MUTE_SOFT_FORCE (1 << 4) - -static inline struct wl1273_device *to_radio(struct v4l2_ctrl *ctrl) -{ - return container_of(ctrl->handler, struct wl1273_device, ctrl_handler); -} - -static int wl1273_fm_vidioc_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct wl1273_device *radio = to_radio(ctrl); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - if (core->mode == WL1273_MODE_RX && ctrl->val) - r = core->write(core, - WL1273_MUTE_STATUS_SET, - WL1273_MUTE_HARD_LEFT | - WL1273_MUTE_HARD_RIGHT); - else if (core->mode == WL1273_MODE_RX) - r = core->write(core, - WL1273_MUTE_STATUS_SET, 0x0); - else if (core->mode == WL1273_MODE_TX && ctrl->val) - r = core->write(core, WL1273_MUTE, 1); - else if (core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_MUTE, 0); - - mutex_unlock(&core->lock); - break; - - case V4L2_CID_AUDIO_VOLUME: - if (ctrl->val == 0) - r = wl1273_fm_set_mode(radio, WL1273_MODE_OFF); - else - r = core->set_volume(core, core->volume); - break; - - case V4L2_CID_TUNE_PREEMPHASIS: - r = wl1273_fm_set_preemphasis(radio, ctrl->val); - break; - - case V4L2_CID_TUNE_POWER_LEVEL: - r = wl1273_fm_set_tx_power(radio, ctrl->val); - break; - - default: - dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n", - __func__, ctrl->id); - break; - } - - dev_dbg(radio->dev, "%s\n", __func__); - return r; -} - -static int wl1273_fm_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - if (audio->index > 1) - return -EINVAL; - - strlcpy(audio->name, "Radio", sizeof(audio->name)); - audio->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - -static int wl1273_fm_vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - if (audio->index != 0) - return -EINVAL; - - return 0; -} - -#define WL1273_RDS_NOT_SYNCHRONIZED 0 -#define WL1273_RDS_SYNCHRONIZED 1 - -static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - u16 val; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (tuner->index > 0) - return -EINVAL; - - strlcpy(tuner->name, WL1273_FM_DRIVER_NAME, sizeof(tuner->name)); - tuner->type = V4L2_TUNER_RADIO; - - tuner->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW); - tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH); - - tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO; - - if (radio->stereo) - tuner->audmode = V4L2_TUNER_MODE_STEREO; - else - tuner->audmode = V4L2_TUNER_MODE_MONO; - - if (core->mode != WL1273_MODE_RX) - return 0; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = core->read(core, WL1273_STEREO_GET, &val); - if (r) - goto out; - - if (val == 1) - tuner->rxsubchans = V4L2_TUNER_SUB_STEREO; - else - tuner->rxsubchans = V4L2_TUNER_SUB_MONO; - - r = core->read(core, WL1273_RSSI_LVL_GET, &val); - if (r) - goto out; - - tuner->signal = (s16) val; - dev_dbg(radio->dev, "Signal: %d\n", tuner->signal); - - tuner->afc = 0; - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) - goto out; - - if (val == WL1273_RDS_SYNCHRONIZED) - tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; -out: - mutex_unlock(&core->lock); - - return r; -} - -static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - dev_dbg(radio->dev, "tuner->index: %d\n", tuner->index); - dev_dbg(radio->dev, "tuner->name: %s\n", tuner->name); - dev_dbg(radio->dev, "tuner->capability: 0x%04x\n", tuner->capability); - dev_dbg(radio->dev, "tuner->rxsubchans: 0x%04x\n", tuner->rxsubchans); - dev_dbg(radio->dev, "tuner->rangelow: %d\n", tuner->rangelow); - dev_dbg(radio->dev, "tuner->rangehigh: %d\n", tuner->rangehigh); - - if (tuner->index > 0) - return -EINVAL; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = wl1273_fm_set_mode(radio, WL1273_MODE_RX); - if (r) - goto out; - - if (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) - r = wl1273_fm_set_rds(radio, WL1273_RDS_ON); - else - r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF); - - if (r) - dev_warn(radio->dev, "%s: RDS fails: %d\n", __func__, r); - - if (tuner->audmode == V4L2_TUNER_MODE_MONO) { - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO); - if (r < 0) { - dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", - __func__, r); - goto out; - } - radio->stereo = false; - } else if (tuner->audmode == V4L2_TUNER_MODE_STEREO) { - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO); - if (r < 0) { - dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", - __func__, r); - goto out; - } - radio->stereo = true; - } else { - dev_err(radio->dev, "%s: tuner->audmode: %d\n", - __func__, tuner->audmode); - r = -EINVAL; - goto out; - } - -out: - mutex_unlock(&core->lock); - - return r; -} - -static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - freq->type = V4L2_TUNER_RADIO; - freq->frequency = WL1273_FREQ(wl1273_fm_get_freq(radio)); - - mutex_unlock(&core->lock); - - return 0; -} - -static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r; - - dev_dbg(radio->dev, "%s: %d\n", __func__, freq->frequency); - - if (freq->type != V4L2_TUNER_RADIO) { - dev_dbg(radio->dev, - "freq->type != V4L2_TUNER_RADIO: %d\n", freq->type); - return -EINVAL; - } - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - if (core->mode == WL1273_MODE_RX) { - dev_dbg(radio->dev, "freq: %d\n", freq->frequency); - - r = wl1273_fm_set_rx_freq(radio, - WL1273_INV_FREQ(freq->frequency)); - if (r) - dev_warn(radio->dev, WL1273_FM_DRIVER_NAME - ": set frequency failed with %d\n", r); - } else { - r = wl1273_fm_set_tx_freq(radio, - WL1273_INV_FREQ(freq->frequency)); - if (r) - dev_warn(radio->dev, WL1273_FM_DRIVER_NAME - ": set frequency failed with %d\n", r); - } - - mutex_unlock(&core->lock); - - dev_dbg(radio->dev, "wl1273_vidioc_s_frequency: DONE\n"); - return r; -} - -#define WL1273_DEFAULT_SEEK_LEVEL 7 - -static int wl1273_fm_vidioc_s_hw_freq_seek(struct file *file, void *priv, - struct v4l2_hw_freq_seek *seek) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (seek->tuner != 0 || seek->type != V4L2_TUNER_RADIO) - return -EINVAL; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = wl1273_fm_set_mode(radio, WL1273_MODE_RX); - if (r) - goto out; - - r = wl1273_fm_tx_set_spacing(radio, seek->spacing); - if (r) - dev_warn(radio->dev, "HW seek failed: %d\n", r); - - r = wl1273_fm_set_seek(radio, seek->wrap_around, seek->seek_upward, - WL1273_DEFAULT_SEEK_LEVEL); - if (r) - dev_warn(radio->dev, "HW seek failed: %d\n", r); - -out: - mutex_unlock(&core->lock); - return r; -} - -static int wl1273_fm_vidioc_s_modulator(struct file *file, void *priv, - struct v4l2_modulator *modulator) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (modulator->index > 0) - return -EINVAL; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = wl1273_fm_set_mode(radio, WL1273_MODE_TX); - if (r) - goto out; - - if (modulator->txsubchans & V4L2_TUNER_SUB_RDS) - r = wl1273_fm_set_rds(radio, WL1273_RDS_ON); - else - r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF); - - if (modulator->txsubchans & V4L2_TUNER_SUB_MONO) - r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO); - else - r = core->write(core, WL1273_MONO_SET, - WL1273_RX_STEREO); - if (r < 0) - dev_warn(radio->dev, WL1273_FM_DRIVER_NAME - "MONO_SET fails: %d\n", r); -out: - mutex_unlock(&core->lock); - - return r; -} - -static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv, - struct v4l2_modulator *modulator) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - u16 val; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - strlcpy(modulator->name, WL1273_FM_DRIVER_NAME, - sizeof(modulator->name)); - - modulator->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW); - modulator->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH); - - modulator->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO; - - if (core->mode != WL1273_MODE_TX) - return 0; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = core->read(core, WL1273_MONO_SET, &val); - if (r) - goto out; - - if (val == WL1273_TX_STEREO) - modulator->txsubchans = V4L2_TUNER_SUB_STEREO; - else - modulator->txsubchans = V4L2_TUNER_SUB_MONO; - - if (radio->rds_on) - modulator->txsubchans |= V4L2_TUNER_SUB_RDS; -out: - mutex_unlock(&core->lock); - - return 0; -} - -static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - struct device *dev = radio->dev; - u16 val; - int r; - - dev_info(dev, DRIVER_DESC); - - if (core->mode == WL1273_MODE_OFF) { - dev_info(dev, "Mode: Off\n"); - return 0; - } - - if (core->mode == WL1273_MODE_SUSPENDED) { - dev_info(dev, "Mode: Suspended\n"); - return 0; - } - - r = core->read(core, WL1273_ASIC_ID_GET, &val); - if (r) - dev_err(dev, "%s: Get ASIC_ID fails.\n", __func__); - else - dev_info(dev, "ASIC_ID: 0x%04x\n", val); - - r = core->read(core, WL1273_ASIC_VER_GET, &val); - if (r) - dev_err(dev, "%s: Get ASIC_VER fails.\n", __func__); - else - dev_info(dev, "ASIC Version: 0x%04x\n", val); - - r = core->read(core, WL1273_FIRM_VER_GET, &val); - if (r) - dev_err(dev, "%s: Get FIRM_VER fails.\n", __func__); - else - dev_info(dev, "FW version: %d(0x%04x)\n", val, val); - - r = core->read(core, WL1273_BAND_SET, &val); - if (r) - dev_err(dev, "%s: Get BAND fails.\n", __func__); - else - dev_info(dev, "BAND: %d\n", val); - - if (core->mode == WL1273_MODE_TX) { - r = core->read(core, WL1273_PUPD_SET, &val); - if (r) - dev_err(dev, "%s: Get PUPD fails.\n", __func__); - else - dev_info(dev, "PUPD: 0x%04x\n", val); - - r = core->read(core, WL1273_CHANL_SET, &val); - if (r) - dev_err(dev, "%s: Get CHANL fails.\n", __func__); - else - dev_info(dev, "Tx frequency: %dkHz\n", val*10); - } else if (core->mode == WL1273_MODE_RX) { - int bf = radio->rangelow; - - r = core->read(core, WL1273_FREQ_SET, &val); - if (r) - dev_err(dev, "%s: Get FREQ fails.\n", __func__); - else - dev_info(dev, "RX Frequency: %dkHz\n", bf + val*50); - - r = core->read(core, WL1273_MOST_MODE_SET, &val); - if (r) - dev_err(dev, "%s: Get MOST_MODE fails.\n", - __func__); - else if (val == 0) - dev_info(dev, "MOST_MODE: Stereo according to blend\n"); - else if (val == 1) - dev_info(dev, "MOST_MODE: Force mono output\n"); - else - dev_info(dev, "MOST_MODE: Unexpected value: %d\n", val); - - r = core->read(core, WL1273_MOST_BLEND_SET, &val); - if (r) - dev_err(dev, "%s: Get MOST_BLEND fails.\n", __func__); - else if (val == 0) - dev_info(dev, - "MOST_BLEND: Switched blend & hysteresis.\n"); - else if (val == 1) - dev_info(dev, "MOST_BLEND: Soft blend.\n"); - else - dev_info(dev, "MOST_BLEND: Unexpected val: %d\n", val); - - r = core->read(core, WL1273_STEREO_GET, &val); - if (r) - dev_err(dev, "%s: Get STEREO fails.\n", __func__); - else if (val == 0) - dev_info(dev, "STEREO: Not detected\n"); - else if (val == 1) - dev_info(dev, "STEREO: Detected\n"); - else - dev_info(dev, "STEREO: Unexpected value: %d\n", val); - - r = core->read(core, WL1273_RSSI_LVL_GET, &val); - if (r) - dev_err(dev, "%s: Get RSSI_LVL fails.\n", __func__); - else - dev_info(dev, "RX signal strength: %d\n", (s16) val); - - r = core->read(core, WL1273_POWER_SET, &val); - if (r) - dev_err(dev, "%s: Get POWER fails.\n", __func__); - else - dev_info(dev, "POWER: 0x%04x\n", val); - - r = core->read(core, WL1273_INT_MASK_SET, &val); - if (r) - dev_err(dev, "%s: Get INT_MASK fails.\n", __func__); - else - dev_info(dev, "INT_MASK: 0x%04x\n", val); - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) - dev_err(dev, "%s: Get RDS_SYNC fails.\n", - __func__); - else if (val == 0) - dev_info(dev, "RDS_SYNC: Not synchronized\n"); - - else if (val == 1) - dev_info(dev, "RDS_SYNC: Synchronized\n"); - else - dev_info(dev, "RDS_SYNC: Unexpected value: %d\n", val); - - r = core->read(core, WL1273_I2S_MODE_CONFIG_SET, &val); - if (r) - dev_err(dev, "%s: Get I2S_MODE_CONFIG fails.\n", - __func__); - else - dev_info(dev, "I2S_MODE_CONFIG: 0x%04x\n", val); - - r = core->read(core, WL1273_VOLUME_SET, &val); - if (r) - dev_err(dev, "%s: Get VOLUME fails.\n", __func__); - else - dev_info(dev, "VOLUME: 0x%04x\n", val); - } - - return 0; -} - -static void wl1273_vdev_release(struct video_device *dev) -{ -} - -static const struct v4l2_ctrl_ops wl1273_ctrl_ops = { - .s_ctrl = wl1273_fm_vidioc_s_ctrl, - .g_volatile_ctrl = wl1273_fm_g_volatile_ctrl, -}; - -static const struct v4l2_ioctl_ops wl1273_ioctl_ops = { - .vidioc_querycap = wl1273_fm_vidioc_querycap, - .vidioc_g_input = wl1273_fm_vidioc_g_input, - .vidioc_s_input = wl1273_fm_vidioc_s_input, - .vidioc_g_audio = wl1273_fm_vidioc_g_audio, - .vidioc_s_audio = wl1273_fm_vidioc_s_audio, - .vidioc_g_tuner = wl1273_fm_vidioc_g_tuner, - .vidioc_s_tuner = wl1273_fm_vidioc_s_tuner, - .vidioc_g_frequency = wl1273_fm_vidioc_g_frequency, - .vidioc_s_frequency = wl1273_fm_vidioc_s_frequency, - .vidioc_s_hw_freq_seek = wl1273_fm_vidioc_s_hw_freq_seek, - .vidioc_g_modulator = wl1273_fm_vidioc_g_modulator, - .vidioc_s_modulator = wl1273_fm_vidioc_s_modulator, - .vidioc_log_status = wl1273_fm_vidioc_log_status, -}; - -static struct video_device wl1273_viddev_template = { - .fops = &wl1273_fops, - .ioctl_ops = &wl1273_ioctl_ops, - .name = WL1273_FM_DRIVER_NAME, - .release = wl1273_vdev_release, -}; - -static int wl1273_fm_radio_remove(struct platform_device *pdev) -{ - struct wl1273_device *radio = platform_get_drvdata(pdev); - struct wl1273_core *core = radio->core; - - dev_info(&pdev->dev, "%s.\n", __func__); - - free_irq(core->client->irq, radio); - core->pdata->free_resources(); - - v4l2_ctrl_handler_free(&radio->ctrl_handler); - video_unregister_device(&radio->videodev); - v4l2_device_unregister(&radio->v4l2dev); - kfree(radio->buffer); - kfree(radio->write_buf); - kfree(radio); - - return 0; -} - -static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev) -{ - struct wl1273_core **core = pdev->dev.platform_data; - struct wl1273_device *radio; - struct v4l2_ctrl *ctrl; - int r = 0; - - pr_debug("%s\n", __func__); - - if (!core) { - dev_err(&pdev->dev, "No platform data.\n"); - r = -EINVAL; - goto pdata_err; - } - - radio = kzalloc(sizeof(*radio), GFP_KERNEL); - if (!radio) { - r = -ENOMEM; - goto pdata_err; - } - - /* RDS buffer allocation */ - radio->buf_size = rds_buf * RDS_BLOCK_SIZE; - radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); - if (!radio->buffer) { - pr_err("Cannot allocate memory for RDS buffer.\n"); - r = -ENOMEM; - goto err_kmalloc; - } - - radio->core = *core; - radio->irq_flags = WL1273_IRQ_MASK; - radio->dev = &radio->core->client->dev; - radio->rds_on = false; - radio->core->mode = WL1273_MODE_OFF; - radio->tx_power = 118; - radio->core->audio_mode = WL1273_AUDIO_ANALOG; - radio->band = WL1273_BAND_OTHER; - radio->core->i2s_mode = WL1273_I2S_DEF_MODE; - radio->core->channel_number = 2; - radio->core->volume = WL1273_DEFAULT_VOLUME; - radio->rx_frequency = WL1273_BAND_OTHER_LOW; - radio->tx_frequency = WL1273_BAND_OTHER_HIGH; - radio->rangelow = WL1273_BAND_OTHER_LOW; - radio->rangehigh = WL1273_BAND_OTHER_HIGH; - radio->stereo = true; - radio->bus_type = "I2C"; - - if (radio->core->pdata->request_resources) { - r = radio->core->pdata->request_resources(radio->core->client); - if (r) { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME - ": Cannot get platform data\n"); - goto err_resources; - } - - dev_dbg(radio->dev, "irq: %d\n", radio->core->client->irq); - - r = request_threaded_irq(radio->core->client->irq, NULL, - wl1273_fm_irq_thread_handler, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, - "wl1273-fm", radio); - if (r < 0) { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME - ": Unable to register IRQ handler: %d\n", r); - goto err_request_irq; - } - } else { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ" - " not configured"); - r = -EINVAL; - goto err_resources; - } - - init_completion(&radio->busy); - init_waitqueue_head(&radio->read_queue); - - radio->write_buf = kmalloc(256, GFP_KERNEL); - if (!radio->write_buf) { - r = -ENOMEM; - goto write_buf_err; - } - - radio->dev = &pdev->dev; - radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; - radio->rds_users = 0; - - r = v4l2_device_register(&pdev->dev, &radio->v4l2dev); - if (r) { - dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); - goto device_register_err; - } - - /* V4L2 configuration */ - memcpy(&radio->videodev, &wl1273_viddev_template, - sizeof(wl1273_viddev_template)); - - radio->videodev.v4l2_dev = &radio->v4l2dev; - - v4l2_ctrl_handler_init(&radio->ctrl_handler, 6); - - /* add in ascending ID order */ - v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, WL1273_MAX_VOLUME, 1, - WL1273_DEFAULT_VOLUME); - - v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); - - v4l2_ctrl_new_std_menu(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_TUNE_PREEMPHASIS, - V4L2_PREEMPHASIS_75_uS, 0x03, - V4L2_PREEMPHASIS_50_uS); - - v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_TUNE_POWER_LEVEL, 91, 122, 1, 118); - - ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_TUNE_ANTENNA_CAPACITOR, - 0, 255, 1, 255); - if (ctrl) - ctrl->is_volatile = 1; - - if (radio->ctrl_handler.error) { - r = radio->ctrl_handler.error; - dev_err(&pdev->dev, "Ctrl handler error: %d\n", r); - goto handler_init_err; - } - - video_set_drvdata(&radio->videodev, radio); - platform_set_drvdata(pdev, radio); - - /* register video device */ - r = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); - if (r) { - dev_err(&pdev->dev, WL1273_FM_DRIVER_NAME - ": Could not register video device\n"); - goto handler_init_err; - } - - return 0; - -handler_init_err: - v4l2_ctrl_handler_free(&radio->ctrl_handler); - v4l2_device_unregister(&radio->v4l2dev); -device_register_err: - kfree(radio->write_buf); -write_buf_err: - free_irq(radio->core->client->irq, radio); -err_request_irq: - radio->core->pdata->free_resources(); -err_resources: - kfree(radio->buffer); -err_kmalloc: - kfree(radio); -pdata_err: - return r; -} - -MODULE_ALIAS("platform:wl1273_fm_radio"); - -static struct platform_driver wl1273_fm_radio_driver = { - .probe = wl1273_fm_radio_probe, - .remove = __devexit_p(wl1273_fm_radio_remove), - .driver = { - .name = "wl1273_fm_radio", - .owner = THIS_MODULE, - }, -}; - -static int __init wl1273_fm_module_init(void) -{ - pr_info("%s\n", __func__); - return platform_driver_register(&wl1273_fm_radio_driver); -} -module_init(wl1273_fm_module_init); - -static void __exit wl1273_fm_module_exit(void) -{ - platform_driver_unregister(&wl1273_fm_radio_driver); - pr_info(DRIVER_DESC ", Exiting.\n"); -} -module_exit(wl1273_fm_module_exit); - -MODULE_AUTHOR("Matti Aaltonen "); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-zoltrix.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-zoltrix.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-zoltrix.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/radio-zoltrix.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,469 +0,0 @@ -/* zoltrix radio plus driver for Linux radio support - * (c) 1998 C. van Schaik - * - * BUGS - * Due to the inconsistency in reading from the signal flags - * it is difficult to get an accurate tuned signal. - * - * It seems that the card is not linear to 0 volume. It cuts off - * at a low volume, and it is not possible (at least I have not found) - * to get fine volume control over the low volume range. - * - * Some code derived from code by Romolo Manfredini - * romolo@bicnet.it - * - * 1999-05-06 - (C. van Schaik) - * - Make signal strength and stereo scans - * kinder to cpu while in delay - * 1999-01-05 - (C. van Schaik) - * - Changed tuning to 1/160Mhz accuracy - * - Added stereo support - * (card defaults to stereo) - * (can explicitly force mono on the card) - * (can detect if station is in stereo) - * - Added unmute function - * - Reworked ioctl functions - * 2002-07-15 - Fix Stereo typo - * - * 2006-07-24 - Converted to V4L2 API - * by Mauro Carvalho Chehab - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* request_region */ -#include /* udelay, msleep */ -#include /* kernel radio structs */ -#include -#include /* for KERNEL_VERSION MACRO */ -#include /* outb, outb_p */ -#include -#include - -MODULE_AUTHOR("C.van Schaik"); -MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); -MODULE_LICENSE("GPL"); - -#ifndef CONFIG_RADIO_ZOLTRIX_PORT -#define CONFIG_RADIO_ZOLTRIX_PORT -1 -#endif - -static int io = CONFIG_RADIO_ZOLTRIX_PORT; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - -struct zoltrix { - struct v4l2_device v4l2_dev; - struct video_device vdev; - int io; - int curvol; - unsigned long curfreq; - int muted; - unsigned int stereo; - struct mutex lock; -}; - -static struct zoltrix zoltrix_card; - -static int zol_setvol(struct zoltrix *zol, int vol) -{ - zol->curvol = vol; - if (zol->muted) - return 0; - - mutex_lock(&zol->lock); - if (vol == 0) { - outb(0, zol->io); - outb(0, zol->io); - inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ - mutex_unlock(&zol->lock); - return 0; - } - - outb(zol->curvol-1, zol->io); - msleep(10); - inb(zol->io + 2); - mutex_unlock(&zol->lock); - return 0; -} - -static void zol_mute(struct zoltrix *zol) -{ - zol->muted = 1; - mutex_lock(&zol->lock); - outb(0, zol->io); - outb(0, zol->io); - inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ - mutex_unlock(&zol->lock); -} - -static void zol_unmute(struct zoltrix *zol) -{ - zol->muted = 0; - zol_setvol(zol, zol->curvol); -} - -static int zol_setfreq(struct zoltrix *zol, unsigned long freq) -{ - /* tunes the radio to the desired frequency */ - struct v4l2_device *v4l2_dev = &zol->v4l2_dev; - unsigned long long bitmask, f, m; - unsigned int stereo = zol->stereo; - int i; - - if (freq == 0) { - v4l2_warn(v4l2_dev, "cannot set a frequency of 0.\n"); - return -EINVAL; - } - - m = (freq / 160 - 8800) * 2; - f = (unsigned long long)m + 0x4d1c; - - bitmask = 0xc480402c10080000ull; - i = 45; - - mutex_lock(&zol->lock); - - zol->curfreq = freq; - - outb(0, zol->io); - outb(0, zol->io); - inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ - - outb(0x40, zol->io); - outb(0xc0, zol->io); - - bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31)); - while (i--) { - if ((bitmask & 0x8000000000000000ull) != 0) { - outb(0x80, zol->io); - udelay(50); - outb(0x00, zol->io); - udelay(50); - outb(0x80, zol->io); - udelay(50); - } else { - outb(0xc0, zol->io); - udelay(50); - outb(0x40, zol->io); - udelay(50); - outb(0xc0, zol->io); - udelay(50); - } - bitmask *= 2; - } - /* termination sequence */ - outb(0x80, zol->io); - outb(0xc0, zol->io); - outb(0x40, zol->io); - udelay(1000); - inb(zol->io + 2); - - udelay(1000); - - if (zol->muted) { - outb(0, zol->io); - outb(0, zol->io); - inb(zol->io + 3); - udelay(1000); - } - - mutex_unlock(&zol->lock); - - if (!zol->muted) - zol_setvol(zol, zol->curvol); - return 0; -} - -/* Get signal strength */ -static int zol_getsigstr(struct zoltrix *zol) -{ - int a, b; - - mutex_lock(&zol->lock); - outb(0x00, zol->io); /* This stuff I found to do nothing */ - outb(zol->curvol, zol->io); - msleep(20); - - a = inb(zol->io); - msleep(10); - b = inb(zol->io); - - mutex_unlock(&zol->lock); - - if (a != b) - return 0; - - /* I found this out by playing with a binary scanner on the card io */ - return a == 0xcf || a == 0xdf || a == 0xef; -} - -static int zol_is_stereo(struct zoltrix *zol) -{ - int x1, x2; - - mutex_lock(&zol->lock); - - outb(0x00, zol->io); - outb(zol->curvol, zol->io); - msleep(20); - - x1 = inb(zol->io); - msleep(10); - x2 = inb(zol->io); - - mutex_unlock(&zol->lock); - - return x1 == x2 && x1 == 0xcf; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); - strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct zoltrix *zol = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = 88 * 16000; - v->rangehigh = 108 * 16000; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - if (zol_is_stereo(zol)) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF * zol_getsigstr(zol); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct zoltrix *zol = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (zol_setfreq(zol, f->frequency) != 0) - return -EINVAL; - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct zoltrix *zol = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = zol->curfreq; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct zoltrix *zol = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = zol->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = zol->curvol * 4096; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct zoltrix *zol = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - zol_mute(zol); - else { - zol_unmute(zol); - zol_setvol(zol, zol->curvol); - } - return 0; - case V4L2_CID_AUDIO_VOLUME: - zol_setvol(zol, ctrl->value / 4096); - return 0; - } - zol->stereo = 1; - if (zol_setfreq(zol, zol->curfreq) != 0) - return -EINVAL; -#if 0 -/* FIXME: Implement stereo/mono switch on V4L2 */ - if (v->mode & VIDEO_SOUND_STEREO) { - zol->stereo = 1; - zol_setfreq(zol, zol->curfreq); - } - if (v->mode & VIDEO_SOUND_MONO) { - zol->stereo = 0; - zol_setfreq(zol, zol->curfreq); - } -#endif - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -static const struct v4l2_file_operations zoltrix_fops = -{ - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static int __init zoltrix_init(void) -{ - struct zoltrix *zol = &zoltrix_card; - struct v4l2_device *v4l2_dev = &zol->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name)); - zol->io = io; - if (zol->io == -1) { - v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n"); - return -EINVAL; - } - if (zol->io != 0x20c && zol->io != 0x30c) { - v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n"); - return -ENXIO; - } - - if (!request_region(zol->io, 2, "zoltrix")) { - v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io); - return -EBUSY; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - release_region(zol->io, 2); - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } - - mutex_init(&zol->lock); - - /* mute card - prevents noisy bootups */ - - /* this ensures that the volume is all the way down */ - - outb(0, zol->io); - outb(0, zol->io); - msleep(20); - inb(zol->io + 3); - - zol->curvol = 0; - zol->stereo = 1; - - strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); - zol->vdev.v4l2_dev = v4l2_dev; - zol->vdev.fops = &zoltrix_fops; - zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; - zol->vdev.release = video_device_release_empty; - video_set_drvdata(&zol->vdev, zol); - - if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(zol->io, 2); - return -EINVAL; - } - v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); - - return 0; -} - -static void __exit zoltrix_exit(void) -{ - struct zoltrix *zol = &zoltrix_card; - - video_unregister_device(&zol->vdev); - v4l2_device_unregister(&zol->v4l2_dev); - release_region(zol->io, 2); -} - -module_init(zoltrix_init); -module_exit(zoltrix_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/saa7706h.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/saa7706h.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/saa7706h.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/saa7706h.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,452 +0,0 @@ -/* - * saa7706.c Philips SAA7706H Car Radio DSP driver - * Copyright (c) 2009 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "saa7706h" - -/* the I2C memory map looks like this - - $1C00 - $FFFF Not Used - $2200 - $3FFF Reserved YRAM (DSP2) space - $2000 - $21FF YRAM (DSP2) - $1FF0 - $1FFF Hardware Registers - $1280 - $1FEF Reserved XRAM (DSP2) space - $1000 - $127F XRAM (DSP2) - $0FFF DSP CONTROL - $0A00 - $0FFE Reserved - $0980 - $09FF Reserved YRAM (DSP1) space - $0800 - $097F YRAM (DSP1) - $0200 - $07FF Not Used - $0180 - $01FF Reserved XRAM (DSP1) space - $0000 - $017F XRAM (DSP1) -*/ - -#define SAA7706H_REG_CTRL 0x0fff -#define SAA7706H_CTRL_BYP_PLL 0x0001 -#define SAA7706H_CTRL_PLL_DIV_MASK 0x003e -#define SAA7706H_CTRL_PLL3_62975MHZ 0x003e -#define SAA7706H_CTRL_DSP_TURBO 0x0040 -#define SAA7706H_CTRL_PC_RESET_DSP1 0x0080 -#define SAA7706H_CTRL_PC_RESET_DSP2 0x0100 -#define SAA7706H_CTRL_DSP1_ROM_EN_MASK 0x0600 -#define SAA7706H_CTRL_DSP1_FUNC_PROM 0x0000 -#define SAA7706H_CTRL_DSP2_ROM_EN_MASK 0x1800 -#define SAA7706H_CTRL_DSP2_FUNC_PROM 0x0000 -#define SAA7706H_CTRL_DIG_SIL_INTERPOL 0x8000 - -#define SAA7706H_REG_EVALUATION 0x1ff0 -#define SAA7706H_EVAL_DISABLE_CHARGE_PUMP 0x000001 -#define SAA7706H_EVAL_DCS_CLOCK 0x000002 -#define SAA7706H_EVAL_GNDRC1_ENABLE 0x000004 -#define SAA7706H_EVAL_GNDRC2_ENABLE 0x000008 - -#define SAA7706H_REG_CL_GEN1 0x1ff3 -#define SAA7706H_CL_GEN1_MIN_LOOPGAIN_MASK 0x00000f -#define SAA7706H_CL_GEN1_LOOPGAIN_MASK 0x0000f0 -#define SAA7706H_CL_GEN1_COARSE_RATION 0xffff00 - -#define SAA7706H_REG_CL_GEN2 0x1ff4 -#define SAA7706H_CL_GEN2_WSEDGE_FALLING 0x000001 -#define SAA7706H_CL_GEN2_STOP_VCO 0x000002 -#define SAA7706H_CL_GEN2_FRERUN 0x000004 -#define SAA7706H_CL_GEN2_ADAPTIVE 0x000008 -#define SAA7706H_CL_GEN2_FINE_RATIO_MASK 0x0ffff0 - -#define SAA7706H_REG_CL_GEN4 0x1ff6 -#define SAA7706H_CL_GEN4_BYPASS_PLL1 0x001000 -#define SAA7706H_CL_GEN4_PLL1_DIV_MASK 0x03e000 -#define SAA7706H_CL_GEN4_DSP1_TURBO 0x040000 - -#define SAA7706H_REG_SEL 0x1ff7 -#define SAA7706H_SEL_DSP2_SRCA_MASK 0x000007 -#define SAA7706H_SEL_DSP2_FMTA_MASK 0x000031 -#define SAA7706H_SEL_DSP2_SRCB_MASK 0x0001c0 -#define SAA7706H_SEL_DSP2_FMTB_MASK 0x000e00 -#define SAA7706H_SEL_DSP1_SRC_MASK 0x003000 -#define SAA7706H_SEL_DSP1_FMT_MASK 0x01c003 -#define SAA7706H_SEL_SPDIF2 0x020000 -#define SAA7706H_SEL_HOST_IO_FMT_MASK 0x1c0000 -#define SAA7706H_SEL_EN_HOST_IO 0x200000 - -#define SAA7706H_REG_IAC 0x1ff8 -#define SAA7706H_REG_CLK_SET 0x1ff9 -#define SAA7706H_REG_CLK_COEFF 0x1ffa -#define SAA7706H_REG_INPUT_SENS 0x1ffb -#define SAA7706H_INPUT_SENS_RDS_VOL_MASK 0x0003f -#define SAA7706H_INPUT_SENS_FM_VOL_MASK 0x00fc0 -#define SAA7706H_INPUT_SENS_FM_MPX 0x01000 -#define SAA7706H_INPUT_SENS_OFF_FILTER_A_EN 0x02000 -#define SAA7706H_INPUT_SENS_OFF_FILTER_B_EN 0x04000 -#define SAA7706H_REG_PHONE_NAV_AUDIO 0x1ffc -#define SAA7706H_REG_IO_CONF_DSP2 0x1ffd -#define SAA7706H_REG_STATUS_DSP2 0x1ffe -#define SAA7706H_REG_PC_DSP2 0x1fff - -#define SAA7706H_DSP1_MOD0 0x0800 -#define SAA7706H_DSP1_ROM_VER 0x097f -#define SAA7706H_DSP2_MPTR0 0x1000 - -#define SAA7706H_DSP1_MODPNTR 0x0000 - -#define SAA7706H_DSP2_XMEM_CONTLLCW 0x113e -#define SAA7706H_DSP2_XMEM_BUSAMP 0x114a -#define SAA7706H_DSP2_XMEM_FDACPNTR 0x11f9 -#define SAA7706H_DSP2_XMEM_IIS1PNTR 0x11fb - -#define SAA7706H_DSP2_YMEM_PVGA 0x212a -#define SAA7706H_DSP2_YMEM_PVAT1 0x212b -#define SAA7706H_DSP2_YMEM_PVAT 0x212c -#define SAA7706H_DSP2_YMEM_ROM_VER 0x21ff - -#define SUPPORTED_DSP1_ROM_VER 0x667 - -struct saa7706h_state { - struct v4l2_subdev sd; - unsigned muted; -}; - -static inline struct saa7706h_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa7706h_state, sd); -} - -static int saa7706h_i2c_send(struct i2c_client *client, const u8 *data, int len) -{ - int err = i2c_master_send(client, data, len); - if (err == len) - return 0; - return err > 0 ? -EIO : err; -} - -static int saa7706h_i2c_transfer(struct i2c_client *client, - struct i2c_msg *msgs, int num) -{ - int err = i2c_transfer(client->adapter, msgs, num); - if (err == num) - return 0; - return err > 0 ? -EIO : err; -} - -static int saa7706h_set_reg24(struct v4l2_subdev *sd, u16 reg, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 buf[5]; - int pos = 0; - - buf[pos++] = reg >> 8; - buf[pos++] = reg; - buf[pos++] = val >> 16; - buf[pos++] = val >> 8; - buf[pos++] = val; - - return saa7706h_i2c_send(client, buf, pos); -} - -static int saa7706h_set_reg24_err(struct v4l2_subdev *sd, u16 reg, u32 val, - int *err) -{ - return *err ? *err : saa7706h_set_reg24(sd, reg, val); -} - -static int saa7706h_set_reg16(struct v4l2_subdev *sd, u16 reg, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 buf[4]; - int pos = 0; - - buf[pos++] = reg >> 8; - buf[pos++] = reg; - buf[pos++] = val >> 8; - buf[pos++] = val; - - return saa7706h_i2c_send(client, buf, pos); -} - -static int saa7706h_set_reg16_err(struct v4l2_subdev *sd, u16 reg, u16 val, - int *err) -{ - return *err ? *err : saa7706h_set_reg16(sd, reg, val); -} - -static int saa7706h_get_reg16(struct v4l2_subdev *sd, u16 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 buf[2]; - int err; - u8 regaddr[] = {reg >> 8, reg}; - struct i2c_msg msg[] = { {client->addr, 0, sizeof(regaddr), regaddr}, - {client->addr, I2C_M_RD, sizeof(buf), buf} }; - - err = saa7706h_i2c_transfer(client, msg, ARRAY_SIZE(msg)); - if (err) - return err; - - return buf[0] << 8 | buf[1]; -} - -static int saa7706h_unmute(struct v4l2_subdev *sd) -{ - struct saa7706h_state *state = to_state(sd); - int err = 0; - - err = saa7706h_set_reg16_err(sd, SAA7706H_REG_CTRL, - SAA7706H_CTRL_PLL3_62975MHZ | SAA7706H_CTRL_PC_RESET_DSP1 | - SAA7706H_CTRL_PC_RESET_DSP2, &err); - - /* newer versions of the chip requires a small sleep after reset */ - msleep(1); - - err = saa7706h_set_reg16_err(sd, SAA7706H_REG_CTRL, - SAA7706H_CTRL_PLL3_62975MHZ, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_EVALUATION, 0, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CL_GEN1, 0x040022, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CL_GEN2, - SAA7706H_CL_GEN2_WSEDGE_FALLING, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CL_GEN4, 0x024080, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_SEL, 0x200080, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_IAC, 0xf4caed, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CLK_SET, 0x124334, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CLK_COEFF, 0x004a1a, - &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_INPUT_SENS, 0x0071c7, - &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_PHONE_NAV_AUDIO, - 0x0e22ff, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_IO_CONF_DSP2, 0x001ff8, - &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_STATUS_DSP2, 0x080003, - &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_REG_PC_DSP2, 0x000004, &err); - - err = saa7706h_set_reg16_err(sd, SAA7706H_DSP1_MOD0, 0x0c6c, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_MPTR0, 0x000b4b, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_DSP1_MODPNTR, 0x000600, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_DSP1_MODPNTR, 0x0000c0, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_CONTLLCW, 0x000819, - &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_CONTLLCW, 0x00085a, - &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_BUSAMP, 0x7fffff, - &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_FDACPNTR, 0x2000cb, - &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_IIS1PNTR, 0x2000cb, - &err); - - err = saa7706h_set_reg16_err(sd, SAA7706H_DSP2_YMEM_PVGA, 0x0f80, &err); - - err = saa7706h_set_reg16_err(sd, SAA7706H_DSP2_YMEM_PVAT1, 0x0800, - &err); - - err = saa7706h_set_reg16_err(sd, SAA7706H_DSP2_YMEM_PVAT, 0x0800, &err); - - err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_CONTLLCW, 0x000905, - &err); - if (!err) - state->muted = 0; - return err; -} - -static int saa7706h_mute(struct v4l2_subdev *sd) -{ - struct saa7706h_state *state = to_state(sd); - int err; - - err = saa7706h_set_reg16(sd, SAA7706H_REG_CTRL, - SAA7706H_CTRL_PLL3_62975MHZ | SAA7706H_CTRL_PC_RESET_DSP1 | - SAA7706H_CTRL_PC_RESET_DSP2); - if (!err) - state->muted = 1; - return err; -} - -static int saa7706h_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - return -EINVAL; -} - -static int saa7706h_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct saa7706h_state *state = to_state(sd); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = state->muted; - return 0; - } - return -EINVAL; -} - -static int saa7706h_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - return saa7706h_mute(sd); - return saa7706h_unmute(sd); - } - return -EINVAL; -} - -static int saa7706h_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7706H, 0); -} - -static const struct v4l2_subdev_core_ops saa7706h_core_ops = { - .g_chip_ident = saa7706h_g_chip_ident, - .queryctrl = saa7706h_queryctrl, - .g_ctrl = saa7706h_g_ctrl, - .s_ctrl = saa7706h_s_ctrl, -}; - -static const struct v4l2_subdev_ops saa7706h_ops = { - .core = &saa7706h_core_ops, -}; - -/* - * Generic i2c probe - * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' - */ - -static int __devinit saa7706h_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct saa7706h_state *state; - struct v4l2_subdev *sd; - int err; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kmalloc(sizeof(struct saa7706h_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &saa7706h_ops); - - /* check the rom versions */ - err = saa7706h_get_reg16(sd, SAA7706H_DSP1_ROM_VER); - if (err < 0) - goto err; - if (err != SUPPORTED_DSP1_ROM_VER) - v4l2_warn(sd, "Unknown DSP1 ROM code version: 0x%x\n", err); - - state->muted = 1; - - /* startup in a muted state */ - err = saa7706h_mute(sd); - if (err) - goto err; - - return 0; - -err: - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - - printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", err); - - return err; -} - -static int __devexit saa7706h_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - saa7706h_mute(sd); - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id saa7706h_id[] = { - {DRIVER_NAME, 0}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, saa7706h_id); - -static struct i2c_driver saa7706h_driver = { - .driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - }, - .probe = saa7706h_probe, - .remove = saa7706h_remove, - .id_table = saa7706h_id, -}; - -static __init int saa7706h_init(void) -{ - return i2c_add_driver(&saa7706h_driver); -} - -static __exit void saa7706h_exit(void) -{ - i2c_del_driver(&saa7706h_driver); -} - -module_init(saa7706h_init); -module_exit(saa7706h_exit); - -MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver"); -MODULE_AUTHOR("Mocean Laboratories"); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -config USB_SI470X - tristate "Silicon Labs Si470x FM Radio Receiver support with USB" - depends on USB && RADIO_SI470X - ---help--- - This is a driver for USB devices with the Silicon Labs SI470x - chip. Currently these devices are known to work: - - 10c4:818a: Silicon Labs USB FM Radio Reference Design - - 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music) - - 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700) - - 10c5:819a: Sanei Electric FM USB Radio (aka DealExtreme.com PCear) - - Sound is provided by the ALSA USB Audio/MIDI driver. Therefore - if you don't want to use the device solely for RDS receiving, - it is recommended to also select SND_USB_AUDIO. - - Please have a look at the documentation, especially on how - to redirect the audio stream from the radio to your sound device: - Documentation/video4linux/si470x.txt - - Say Y here if you want to connect this type of radio to your - computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called radio-usb-si470x. - -config I2C_SI470X - tristate "Silicon Labs Si470x FM Radio Receiver support with I2C" - depends on I2C && RADIO_SI470X && !USB_SI470X - ---help--- - This is a driver for I2C devices with the Silicon Labs SI470x - chip. - - Say Y here if you want to connect this type of radio to your - computer's I2C port. - - To compile this driver as a module, choose M here: the - module will be called radio-i2c-si470x. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -# -# Makefile for radios with Silicon Labs Si470x FM Radio Receivers -# - -radio-usb-si470x-objs := radio-si470x-usb.o radio-si470x-common.o -radio-i2c-si470x-objs := radio-si470x-i2c.o radio-si470x-common.o - -obj-$(CONFIG_USB_SI470X) += radio-usb-si470x.o -obj-$(CONFIG_I2C_SI470X) += radio-i2c-si470x.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-common.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,907 +0,0 @@ -/* - * drivers/media/radio/si470x/radio-si470x-common.c - * - * Driver for radios with Silicon Labs Si470x FM Radio Receivers - * - * Copyright (c) 2009 Tobias Lorenz - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - - -/* - * History: - * 2008-01-12 Tobias Lorenz - * Version 1.0.0 - * - First working version - * 2008-01-13 Tobias Lorenz - * Version 1.0.1 - * - Improved error handling, every function now returns errno - * - Improved multi user access (start/mute/stop) - * - Channel doesn't get lost anymore after start/mute/stop - * - RDS support added (polling mode via interrupt EP 1) - * - marked default module parameters with *value* - * - switched from bit structs to bit masks - * - header file cleaned and integrated - * 2008-01-14 Tobias Lorenz - * Version 1.0.2 - * - hex values are now lower case - * - commented USB ID for ADS/Tech moved on todo list - * - blacklisted si470x in hid-quirks.c - * - rds buffer handling functions integrated into *_work, *_read - * - rds_command in si470x_poll exchanged against simple retval - * - check for firmware version 15 - * - code order and prototypes still remain the same - * - spacing and bottom of band codes remain the same - * 2008-01-16 Tobias Lorenz - * Version 1.0.3 - * - code reordered to avoid function prototypes - * - switch/case defaults are now more user-friendly - * - unified comment style - * - applied all checkpatch.pl v1.12 suggestions - * except the warning about the too long lines with bit comments - * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) - * 2008-01-22 Tobias Lorenz - * Version 1.0.4 - * - avoid poss. locking when doing copy_to_user which may sleep - * - RDS is automatically activated on read now - * - code cleaned of unnecessary rds_commands - * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified - * (thanks to Guillaume RAMOUSSE) - * 2008-01-27 Tobias Lorenz - * Version 1.0.5 - * - number of seek_retries changed to tune_timeout - * - fixed problem with incomplete tune operations by own buffers - * - optimization of variables and printf types - * - improved error logging - * 2008-01-31 Tobias Lorenz - * Oliver Neukum - * Version 1.0.6 - * - fixed coverity checker warnings in *_usb_driver_disconnect - * - probe()/open() race by correct ordering in probe() - * - DMA coherency rules by separate allocation of all buffers - * - use of endianness macros - * - abuse of spinlock, replaced by mutex - * - racy handling of timer in disconnect, - * replaced by delayed_work - * - racy interruptible_sleep_on(), - * replaced with wait_event_interruptible() - * - handle signals in read() - * 2008-02-08 Tobias Lorenz - * Oliver Neukum - * Version 1.0.7 - * - usb autosuspend support - * - unplugging fixed - * 2008-05-07 Tobias Lorenz - * Version 1.0.8 - * - hardware frequency seek support - * - afc indication - * - more safety checks, let si470x_get_freq return errno - * - vidioc behavior corrected according to v4l2 spec - * 2008-10-20 Alexey Klimov - * - add support for KWorld USB FM Radio FM700 - * - blacklisted KWorld radio in hid-core.c and hid-ids.h - * 2008-12-03 Mark Lord - * - add support for DealExtreme USB Radio - * 2009-01-31 Bob Ross - * - correction of stereo detection/setting - * - correction of signal strength indicator scaling - * 2009-01-31 Rick Bronson - * Tobias Lorenz - * - add LED status output - * - get HW/SW version from scratchpad - * 2009-06-16 Edouard Lafargue - * Version 1.0.10 - * - add support for interrupt mode for RDS endpoint, - * instead of polling. - * Improves RDS reception significantly - */ - - -/* kernel includes */ -#include "radio-si470x.h" - - - -/************************************************************************** - * Module Parameters - **************************************************************************/ - -/* Spacing (kHz) */ -/* 0: 200 kHz (USA, Australia) */ -/* 1: 100 kHz (Europe, Japan) */ -/* 2: 50 kHz */ -static unsigned short space = 2; -module_param(space, ushort, 0444); -MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*"); - -/* Bottom of Band (MHz) */ -/* 0: 87.5 - 108 MHz (USA, Europe)*/ -/* 1: 76 - 108 MHz (Japan wide band) */ -/* 2: 76 - 90 MHz (Japan) */ -static unsigned short band = 1; -module_param(band, ushort, 0444); -MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz"); - -/* De-emphasis */ -/* 0: 75 us (USA) */ -/* 1: 50 us (Europe, Australia, Japan) */ -static unsigned short de = 1; -module_param(de, ushort, 0444); -MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*"); - -/* Tune timeout */ -static unsigned int tune_timeout = 3000; -module_param(tune_timeout, uint, 0644); -MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*"); - -/* Seek timeout */ -static unsigned int seek_timeout = 5000; -module_param(seek_timeout, uint, 0644); -MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*"); - - - -/************************************************************************** - * Generic Functions - **************************************************************************/ - -/* - * si470x_set_chan - set the channel - */ -static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) -{ - int retval; - unsigned long timeout; - bool timed_out = 0; - - /* start tuning */ - radio->registers[CHANNEL] &= ~CHANNEL_CHAN; - radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; - retval = si470x_set_register(radio, CHANNEL); - if (retval < 0) - goto done; - - /* wait till tune operation has completed */ - timeout = jiffies + msecs_to_jiffies(tune_timeout); - do { - retval = si470x_get_register(radio, STATUSRSSI); - if (retval < 0) - goto stop; - timed_out = time_after(jiffies, timeout); - } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) && - (!timed_out)); - if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) - dev_warn(&radio->videodev->dev, "tune does not complete\n"); - if (timed_out) - dev_warn(&radio->videodev->dev, - "tune timed out after %u ms\n", tune_timeout); - -stop: - /* stop tuning */ - radio->registers[CHANNEL] &= ~CHANNEL_TUNE; - retval = si470x_set_register(radio, CHANNEL); - -done: - return retval; -} - - -/* - * si470x_get_freq - get the frequency - */ -static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) -{ - unsigned int spacing, band_bottom; - unsigned short chan; - int retval; - - /* Spacing (kHz) */ - switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) { - /* 0: 200 kHz (USA, Australia) */ - case 0: - spacing = 0.200 * FREQ_MUL; break; - /* 1: 100 kHz (Europe, Japan) */ - case 1: - spacing = 0.100 * FREQ_MUL; break; - /* 2: 50 kHz */ - default: - spacing = 0.050 * FREQ_MUL; break; - }; - - /* Bottom of Band (MHz) */ - switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { - /* 0: 87.5 - 108 MHz (USA, Europe) */ - case 0: - band_bottom = 87.5 * FREQ_MUL; break; - /* 1: 76 - 108 MHz (Japan wide band) */ - default: - band_bottom = 76 * FREQ_MUL; break; - /* 2: 76 - 90 MHz (Japan) */ - case 2: - band_bottom = 76 * FREQ_MUL; break; - }; - - /* read channel */ - retval = si470x_get_register(radio, READCHAN); - chan = radio->registers[READCHAN] & READCHAN_READCHAN; - - /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */ - *freq = chan * spacing + band_bottom; - - return retval; -} - - -/* - * si470x_set_freq - set the frequency - */ -int si470x_set_freq(struct si470x_device *radio, unsigned int freq) -{ - unsigned int spacing, band_bottom; - unsigned short chan; - - /* Spacing (kHz) */ - switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) { - /* 0: 200 kHz (USA, Australia) */ - case 0: - spacing = 0.200 * FREQ_MUL; break; - /* 1: 100 kHz (Europe, Japan) */ - case 1: - spacing = 0.100 * FREQ_MUL; break; - /* 2: 50 kHz */ - default: - spacing = 0.050 * FREQ_MUL; break; - }; - - /* Bottom of Band (MHz) */ - switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { - /* 0: 87.5 - 108 MHz (USA, Europe) */ - case 0: - band_bottom = 87.5 * FREQ_MUL; break; - /* 1: 76 - 108 MHz (Japan wide band) */ - default: - band_bottom = 76 * FREQ_MUL; break; - /* 2: 76 - 90 MHz (Japan) */ - case 2: - band_bottom = 76 * FREQ_MUL; break; - }; - - /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ - chan = (freq - band_bottom) / spacing; - - return si470x_set_chan(radio, chan); -} - - -/* - * si470x_set_seek - set seek - */ -static int si470x_set_seek(struct si470x_device *radio, - unsigned int wrap_around, unsigned int seek_upward) -{ - int retval = 0; - unsigned long timeout; - bool timed_out = 0; - - /* start seeking */ - radio->registers[POWERCFG] |= POWERCFG_SEEK; - if (wrap_around == 1) - radio->registers[POWERCFG] &= ~POWERCFG_SKMODE; - else - radio->registers[POWERCFG] |= POWERCFG_SKMODE; - if (seek_upward == 1) - radio->registers[POWERCFG] |= POWERCFG_SEEKUP; - else - radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP; - retval = si470x_set_register(radio, POWERCFG); - if (retval < 0) - goto done; - - /* wait till seek operation has completed */ - timeout = jiffies + msecs_to_jiffies(seek_timeout); - do { - retval = si470x_get_register(radio, STATUSRSSI); - if (retval < 0) - goto stop; - timed_out = time_after(jiffies, timeout); - } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) && - (!timed_out)); - if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) - dev_warn(&radio->videodev->dev, "seek does not complete\n"); - if (radio->registers[STATUSRSSI] & STATUSRSSI_SF) - dev_warn(&radio->videodev->dev, - "seek failed / band limit reached\n"); - if (timed_out) - dev_warn(&radio->videodev->dev, - "seek timed out after %u ms\n", seek_timeout); - -stop: - /* stop seeking */ - radio->registers[POWERCFG] &= ~POWERCFG_SEEK; - retval = si470x_set_register(radio, POWERCFG); - -done: - /* try again, if timed out */ - if ((retval == 0) && timed_out) - retval = -EAGAIN; - - return retval; -} - - -/* - * si470x_start - switch on radio - */ -int si470x_start(struct si470x_device *radio) -{ - int retval; - - /* powercfg */ - radio->registers[POWERCFG] = - POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; - retval = si470x_set_register(radio, POWERCFG); - if (retval < 0) - goto done; - - /* sysconfig 1 */ - radio->registers[SYSCONFIG1] = - (de << 11) & SYSCONFIG1_DE; /* DE*/ - retval = si470x_set_register(radio, SYSCONFIG1); - if (retval < 0) - goto done; - - /* sysconfig 2 */ - radio->registers[SYSCONFIG2] = - (0x3f << 8) | /* SEEKTH */ - ((band << 6) & SYSCONFIG2_BAND) | /* BAND */ - ((space << 4) & SYSCONFIG2_SPACE) | /* SPACE */ - 15; /* VOLUME (max) */ - retval = si470x_set_register(radio, SYSCONFIG2); - if (retval < 0) - goto done; - - /* reset last channel */ - retval = si470x_set_chan(radio, - radio->registers[CHANNEL] & CHANNEL_CHAN); - -done: - return retval; -} - - -/* - * si470x_stop - switch off radio - */ -int si470x_stop(struct si470x_device *radio) -{ - int retval; - - /* sysconfig 1 */ - radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; - retval = si470x_set_register(radio, SYSCONFIG1); - if (retval < 0) - goto done; - - /* powercfg */ - radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; - /* POWERCFG_ENABLE has to automatically go low */ - radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; - retval = si470x_set_register(radio, POWERCFG); - -done: - return retval; -} - - -/* - * si470x_rds_on - switch on rds reception - */ -static int si470x_rds_on(struct si470x_device *radio) -{ - int retval; - - /* sysconfig 1 */ - radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; - retval = si470x_set_register(radio, SYSCONFIG1); - if (retval < 0) - radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; - - return retval; -} - - - -/************************************************************************** - * File Operations Interface - **************************************************************************/ - -/* - * si470x_fops_read - read RDS data - */ -static ssize_t si470x_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - unsigned int block_count = 0; - - /* switch on rds reception */ - mutex_lock(&radio->lock); - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) - si470x_rds_on(radio); - - /* block if no new data available */ - while (radio->wr_index == radio->rd_index) { - if (file->f_flags & O_NONBLOCK) { - retval = -EWOULDBLOCK; - goto done; - } - if (wait_event_interruptible(radio->read_queue, - radio->wr_index != radio->rd_index) < 0) { - retval = -EINTR; - goto done; - } - } - - /* calculate block count from byte count */ - count /= 3; - - /* copy RDS block out of internal buffer and to user buffer */ - while (block_count < count) { - if (radio->rd_index == radio->wr_index) - break; - - /* always transfer rds complete blocks */ - if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) - /* retval = -EFAULT; */ - break; - - /* increment and wrap read pointer */ - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - - /* increment counters */ - block_count++; - buf += 3; - retval += 3; - } - -done: - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_fops_poll - poll RDS data - */ -static unsigned int si470x_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - /* switch on rds reception */ - - mutex_lock(&radio->lock); - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) - si470x_rds_on(radio); - mutex_unlock(&radio->lock); - - poll_wait(file, &radio->read_queue, pts); - - if (radio->rd_index != radio->wr_index) - retval = POLLIN | POLLRDNORM; - - return retval; -} - - -/* - * si470x_fops - file operations interface - */ -static const struct v4l2_file_operations si470x_fops = { - .owner = THIS_MODULE, - .read = si470x_fops_read, - .poll = si470x_fops_poll, - .unlocked_ioctl = video_ioctl2, - .open = si470x_fops_open, - .release = si470x_fops_release, -}; - - - -/************************************************************************** - * Video4Linux Interface - **************************************************************************/ - -/* - * si470x_vidioc_queryctrl - enumerate control items - */ -static int si470x_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = -EINVAL; - - /* abort if qc->id is below V4L2_CID_BASE */ - if (qc->id < V4L2_CID_BASE) - goto done; - - /* search video control */ - switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15); - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - - /* disable unsupported base controls */ - /* to satisfy kradio and such apps */ - if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) { - qc->flags = V4L2_CTRL_FLAG_DISABLED; - retval = 0; - } - -done: - if (retval < 0) - dev_warn(&radio->videodev->dev, - "query controls failed with %d\n", retval); - return retval; -} - - -/* - * si470x_vidioc_g_ctrl - get the value of a control - */ -static int si470x_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - mutex_lock(&radio->lock); - /* safety checks */ - retval = si470x_disconnect_check(radio); - if (retval) - goto done; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = radio->registers[SYSCONFIG2] & - SYSCONFIG2_VOLUME; - break; - case V4L2_CID_AUDIO_MUTE: - ctrl->value = ((radio->registers[POWERCFG] & - POWERCFG_DMUTE) == 0) ? 1 : 0; - break; - default: - retval = -EINVAL; - } - -done: - if (retval < 0) - dev_warn(&radio->videodev->dev, - "get control failed with %d\n", retval); - - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_vidioc_s_ctrl - set the value of a control - */ -static int si470x_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - mutex_lock(&radio->lock); - /* safety checks */ - retval = si470x_disconnect_check(radio); - if (retval) - goto done; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; - radio->registers[SYSCONFIG2] |= ctrl->value; - retval = si470x_set_register(radio, SYSCONFIG2); - break; - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value == 1) - radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; - else - radio->registers[POWERCFG] |= POWERCFG_DMUTE; - retval = si470x_set_register(radio, POWERCFG); - break; - default: - retval = -EINVAL; - } - -done: - if (retval < 0) - dev_warn(&radio->videodev->dev, - "set control failed with %d\n", retval); - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_vidioc_g_audio - get audio attributes - */ -static int si470x_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - /* driver constants */ - audio->index = 0; - strcpy(audio->name, "Radio"); - audio->capability = V4L2_AUDCAP_STEREO; - audio->mode = 0; - - return 0; -} - - -/* - * si470x_vidioc_g_tuner - get tuner attributes - */ -static int si470x_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - mutex_lock(&radio->lock); - /* safety checks */ - retval = si470x_disconnect_check(radio); - if (retval) - goto done; - - if (tuner->index != 0) { - retval = -EINVAL; - goto done; - } - - retval = si470x_get_register(radio, STATUSRSSI); - if (retval < 0) - goto done; - - /* driver constants */ - strcpy(tuner->name, "FM"); - tuner->type = V4L2_TUNER_RADIO; - tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; - - /* range limits */ - switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { - /* 0: 87.5 - 108 MHz (USA, Europe, default) */ - default: - tuner->rangelow = 87.5 * FREQ_MUL; - tuner->rangehigh = 108 * FREQ_MUL; - break; - /* 1: 76 - 108 MHz (Japan wide band) */ - case 1: - tuner->rangelow = 76 * FREQ_MUL; - tuner->rangehigh = 108 * FREQ_MUL; - break; - /* 2: 76 - 90 MHz (Japan) */ - case 2: - tuner->rangelow = 76 * FREQ_MUL; - tuner->rangehigh = 90 * FREQ_MUL; - break; - }; - - /* stereo indicator == stereo (instead of mono) */ - if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0) - tuner->rxsubchans = V4L2_TUNER_SUB_MONO; - else - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - /* If there is a reliable method of detecting an RDS channel, - then this code should check for that before setting this - RDS subchannel. */ - tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; - - /* mono/stereo selector */ - if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0) - tuner->audmode = V4L2_TUNER_MODE_STEREO; - else - tuner->audmode = V4L2_TUNER_MODE_MONO; - - /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */ - /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */ - tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI); - /* the ideal factor is 0xffff/75 = 873,8 */ - tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10); - - /* automatic frequency control: -1: freq to low, 1 freq to high */ - /* AFCRL does only indicate that freq. differs, not if too low/high */ - tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0; - -done: - if (retval < 0) - dev_warn(&radio->videodev->dev, - "get tuner failed with %d\n", retval); - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_vidioc_s_tuner - set tuner attributes - */ -static int si470x_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - mutex_lock(&radio->lock); - /* safety checks */ - retval = si470x_disconnect_check(radio); - if (retval) - goto done; - - if (tuner->index != 0) - goto done; - - /* mono/stereo selector */ - switch (tuner->audmode) { - case V4L2_TUNER_MODE_MONO: - radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ - break; - case V4L2_TUNER_MODE_STEREO: - radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ - break; - default: - goto done; - } - - retval = si470x_set_register(radio, POWERCFG); - -done: - if (retval < 0) - dev_warn(&radio->videodev->dev, - "set tuner failed with %d\n", retval); - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_vidioc_g_frequency - get tuner or modulator radio frequency - */ -static int si470x_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - /* safety checks */ - mutex_lock(&radio->lock); - retval = si470x_disconnect_check(radio); - if (retval) - goto done; - - if (freq->tuner != 0) { - retval = -EINVAL; - goto done; - } - - freq->type = V4L2_TUNER_RADIO; - retval = si470x_get_freq(radio, &freq->frequency); - -done: - if (retval < 0) - dev_warn(&radio->videodev->dev, - "get frequency failed with %d\n", retval); - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_vidioc_s_frequency - set tuner or modulator radio frequency - */ -static int si470x_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - mutex_lock(&radio->lock); - /* safety checks */ - retval = si470x_disconnect_check(radio); - if (retval) - goto done; - - if (freq->tuner != 0) { - retval = -EINVAL; - goto done; - } - - retval = si470x_set_freq(radio, freq->frequency); - -done: - if (retval < 0) - dev_warn(&radio->videodev->dev, - "set frequency failed with %d\n", retval); - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek - */ -static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, - struct v4l2_hw_freq_seek *seek) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - mutex_lock(&radio->lock); - /* safety checks */ - retval = si470x_disconnect_check(radio); - if (retval) - goto done; - - if (seek->tuner != 0) { - retval = -EINVAL; - goto done; - } - - retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward); - -done: - if (retval < 0) - dev_warn(&radio->videodev->dev, - "set hardware frequency seek failed with %d\n", retval); - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_ioctl_ops - video device ioctl operations - */ -static const struct v4l2_ioctl_ops si470x_ioctl_ops = { - .vidioc_querycap = si470x_vidioc_querycap, - .vidioc_queryctrl = si470x_vidioc_queryctrl, - .vidioc_g_ctrl = si470x_vidioc_g_ctrl, - .vidioc_s_ctrl = si470x_vidioc_s_ctrl, - .vidioc_g_audio = si470x_vidioc_g_audio, - .vidioc_g_tuner = si470x_vidioc_g_tuner, - .vidioc_s_tuner = si470x_vidioc_s_tuner, - .vidioc_g_frequency = si470x_vidioc_g_frequency, - .vidioc_s_frequency = si470x_vidioc_s_frequency, - .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, -}; - - -/* - * si470x_viddev_template - video device interface - */ -struct video_device si470x_viddev_template = { - .fops = &si470x_fops, - .name = DRIVER_NAME, - .release = video_device_release, - .ioctl_ops = &si470x_ioctl_ops, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,224 +0,0 @@ -/* - * drivers/media/radio/si470x/radio-si470x.h - * - * Driver for radios with Silicon Labs Si470x FM Radio Receivers - * - * Copyright (c) 2009 Tobias Lorenz - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - - -/* driver definitions */ -#define DRIVER_NAME "radio-si470x" - - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/************************************************************************** - * Register Definitions - **************************************************************************/ -#define RADIO_REGISTER_SIZE 2 /* 16 register bit width */ -#define RADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ -#define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */ - -#define DEVICEID 0 /* Device ID */ -#define DEVICEID_PN 0xf000 /* bits 15..12: Part Number */ -#define DEVICEID_MFGID 0x0fff /* bits 11..00: Manufacturer ID */ - -#define CHIPID 1 /* Chip ID */ -#define CHIPID_REV 0xfc00 /* bits 15..10: Chip Version */ -#define CHIPID_DEV 0x0200 /* bits 09..09: Device */ -#define CHIPID_FIRMWARE 0x01ff /* bits 08..00: Firmware Version */ - -#define POWERCFG 2 /* Power Configuration */ -#define POWERCFG_DSMUTE 0x8000 /* bits 15..15: Softmute Disable */ -#define POWERCFG_DMUTE 0x4000 /* bits 14..14: Mute Disable */ -#define POWERCFG_MONO 0x2000 /* bits 13..13: Mono Select */ -#define POWERCFG_RDSM 0x0800 /* bits 11..11: RDS Mode (Si4701 only) */ -#define POWERCFG_SKMODE 0x0400 /* bits 10..10: Seek Mode */ -#define POWERCFG_SEEKUP 0x0200 /* bits 09..09: Seek Direction */ -#define POWERCFG_SEEK 0x0100 /* bits 08..08: Seek */ -#define POWERCFG_DISABLE 0x0040 /* bits 06..06: Powerup Disable */ -#define POWERCFG_ENABLE 0x0001 /* bits 00..00: Powerup Enable */ - -#define CHANNEL 3 /* Channel */ -#define CHANNEL_TUNE 0x8000 /* bits 15..15: Tune */ -#define CHANNEL_CHAN 0x03ff /* bits 09..00: Channel Select */ - -#define SYSCONFIG1 4 /* System Configuration 1 */ -#define SYSCONFIG1_RDSIEN 0x8000 /* bits 15..15: RDS Interrupt Enable (Si4701 only) */ -#define SYSCONFIG1_STCIEN 0x4000 /* bits 14..14: Seek/Tune Complete Interrupt Enable */ -#define SYSCONFIG1_RDS 0x1000 /* bits 12..12: RDS Enable (Si4701 only) */ -#define SYSCONFIG1_DE 0x0800 /* bits 11..11: De-emphasis (0=75us 1=50us) */ -#define SYSCONFIG1_AGCD 0x0400 /* bits 10..10: AGC Disable */ -#define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */ -#define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */ -#define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */ -#define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */ - -#define SYSCONFIG2 5 /* System Configuration 2 */ -#define SYSCONFIG2_SEEKTH 0xff00 /* bits 15..08: RSSI Seek Threshold */ -#define SYSCONFIG2_BAND 0x0080 /* bits 07..06: Band Select */ -#define SYSCONFIG2_SPACE 0x0030 /* bits 05..04: Channel Spacing */ -#define SYSCONFIG2_VOLUME 0x000f /* bits 03..00: Volume */ - -#define SYSCONFIG3 6 /* System Configuration 3 */ -#define SYSCONFIG3_SMUTER 0xc000 /* bits 15..14: Softmute Attack/Recover Rate */ -#define SYSCONFIG3_SMUTEA 0x3000 /* bits 13..12: Softmute Attenuation */ -#define SYSCONFIG3_SKSNR 0x00f0 /* bits 07..04: Seek SNR Threshold */ -#define SYSCONFIG3_SKCNT 0x000f /* bits 03..00: Seek FM Impulse Detection Threshold */ - -#define TEST1 7 /* Test 1 */ -#define TEST1_AHIZEN 0x4000 /* bits 14..14: Audio High-Z Enable */ - -#define TEST2 8 /* Test 2 */ -/* TEST2 only contains reserved bits */ - -#define BOOTCONFIG 9 /* Boot Configuration */ -/* BOOTCONFIG only contains reserved bits */ - -#define STATUSRSSI 10 /* Status RSSI */ -#define STATUSRSSI_RDSR 0x8000 /* bits 15..15: RDS Ready (Si4701 only) */ -#define STATUSRSSI_STC 0x4000 /* bits 14..14: Seek/Tune Complete */ -#define STATUSRSSI_SF 0x2000 /* bits 13..13: Seek Fail/Band Limit */ -#define STATUSRSSI_AFCRL 0x1000 /* bits 12..12: AFC Rail */ -#define STATUSRSSI_RDSS 0x0800 /* bits 11..11: RDS Synchronized (Si4701 only) */ -#define STATUSRSSI_BLERA 0x0600 /* bits 10..09: RDS Block A Errors (Si4701 only) */ -#define STATUSRSSI_ST 0x0100 /* bits 08..08: Stereo Indicator */ -#define STATUSRSSI_RSSI 0x00ff /* bits 07..00: RSSI (Received Signal Strength Indicator) */ - -#define READCHAN 11 /* Read Channel */ -#define READCHAN_BLERB 0xc000 /* bits 15..14: RDS Block D Errors (Si4701 only) */ -#define READCHAN_BLERC 0x3000 /* bits 13..12: RDS Block C Errors (Si4701 only) */ -#define READCHAN_BLERD 0x0c00 /* bits 11..10: RDS Block B Errors (Si4701 only) */ -#define READCHAN_READCHAN 0x03ff /* bits 09..00: Read Channel */ - -#define RDSA 12 /* RDSA */ -#define RDSA_RDSA 0xffff /* bits 15..00: RDS Block A Data (Si4701 only) */ - -#define RDSB 13 /* RDSB */ -#define RDSB_RDSB 0xffff /* bits 15..00: RDS Block B Data (Si4701 only) */ - -#define RDSC 14 /* RDSC */ -#define RDSC_RDSC 0xffff /* bits 15..00: RDS Block C Data (Si4701 only) */ - -#define RDSD 15 /* RDSD */ -#define RDSD_RDSD 0xffff /* bits 15..00: RDS Block D Data (Si4701 only) */ - - - -/************************************************************************** - * General Driver Definitions - **************************************************************************/ - -/* - * si470x_device - private data - */ -struct si470x_device { - struct video_device *videodev; - - /* driver management */ - unsigned int users; - - /* Silabs internal registers (0..15) */ - unsigned short registers[RADIO_REGISTER_NUM]; - - /* RDS receive buffer */ - wait_queue_head_t read_queue; - struct mutex lock; /* buffer locking */ - unsigned char *buffer; /* size is always multiple of three */ - unsigned int buf_size; - unsigned int rd_index; - unsigned int wr_index; - -#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE) - /* reference to USB and video device */ - struct usb_device *usbdev; - struct usb_interface *intf; - - /* Interrupt endpoint handling */ - char *int_in_buffer; - struct usb_endpoint_descriptor *int_in_endpoint; - struct urb *int_in_urb; - int int_in_running; - - /* scratch page */ - unsigned char software_version; - unsigned char hardware_version; - - /* driver management */ - unsigned char disconnected; -#endif - -#if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE) - struct i2c_client *client; - struct work_struct radio_work; -#endif -}; - - - -/************************************************************************** - * Firmware Versions - **************************************************************************/ - -#define RADIO_FW_VERSION 15 - - - -/************************************************************************** - * Frequency Multiplicator - **************************************************************************/ - -/* - * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, - * 62.5 kHz otherwise. - * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. - * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW - * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 - */ -#define FREQ_MUL (1000000 / 62.5) - - - -/************************************************************************** - * Common Functions - **************************************************************************/ -extern struct video_device si470x_viddev_template; -int si470x_get_register(struct si470x_device *radio, int regnr); -int si470x_set_register(struct si470x_device *radio, int regnr); -int si470x_disconnect_check(struct si470x_device *radio); -int si470x_set_freq(struct si470x_device *radio, unsigned int freq); -int si470x_start(struct si470x_device *radio); -int si470x_stop(struct si470x_device *radio); -int si470x_fops_open(struct file *file); -int si470x_fops_release(struct file *file); -int si470x_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-i2c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,573 +0,0 @@ -/* - * drivers/media/radio/si470x/radio-si470x-i2c.c - * - * I2C driver for radios with Silicon Labs Si470x FM Radio Receivers - * - * Copyright (c) 2009 Samsung Electronics Co.Ltd - * Author: Joonyoung Shim - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - - -/* driver definitions */ -#define DRIVER_AUTHOR "Joonyoung Shim "; -#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1) -#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" -#define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" -#define DRIVER_VERSION "1.0.1" - -/* kernel includes */ -#include -#include -#include -#include - -#include "radio-si470x.h" - - -/* I2C Device ID List */ -static const struct i2c_device_id si470x_i2c_id[] = { - /* Generic Entry */ - { "si470x", 0 }, - /* Terminating entry */ - { } -}; -MODULE_DEVICE_TABLE(i2c, si470x_i2c_id); - - - -/************************************************************************** - * Module Parameters - **************************************************************************/ - -/* Radio Nr */ -static int radio_nr = -1; -module_param(radio_nr, int, 0444); -MODULE_PARM_DESC(radio_nr, "Radio Nr"); - -/* RDS buffer blocks */ -static unsigned int rds_buf = 100; -module_param(rds_buf, uint, 0444); -MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); - -/* RDS maximum block errors */ -static unsigned short max_rds_errors = 1; -/* 0 means 0 errors requiring correction */ -/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ -/* 2 means 3-5 errors requiring correction */ -/* 3 means 6+ errors or errors in checkword, correction not possible */ -module_param(max_rds_errors, ushort, 0644); -MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); - - - -/************************************************************************** - * I2C Definitions - **************************************************************************/ - -/* Write starts with the upper byte of register 0x02 */ -#define WRITE_REG_NUM 8 -#define WRITE_INDEX(i) (i + 0x02) - -/* Read starts with the upper byte of register 0x0a */ -#define READ_REG_NUM RADIO_REGISTER_NUM -#define READ_INDEX(i) ((i + RADIO_REGISTER_NUM - 0x0a) % READ_REG_NUM) - - - -/************************************************************************** - * General Driver Functions - REGISTERs - **************************************************************************/ - -/* - * si470x_get_register - read register - */ -int si470x_get_register(struct si470x_device *radio, int regnr) -{ - u16 buf[READ_REG_NUM]; - struct i2c_msg msgs[1] = { - { radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM, - (void *)buf }, - }; - - if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) - return -EIO; - - radio->registers[regnr] = __be16_to_cpu(buf[READ_INDEX(regnr)]); - - return 0; -} - - -/* - * si470x_set_register - write register - */ -int si470x_set_register(struct si470x_device *radio, int regnr) -{ - int i; - u16 buf[WRITE_REG_NUM]; - struct i2c_msg msgs[1] = { - { radio->client->addr, 0, sizeof(u16) * WRITE_REG_NUM, - (void *)buf }, - }; - - for (i = 0; i < WRITE_REG_NUM; i++) - buf[i] = __cpu_to_be16(radio->registers[WRITE_INDEX(i)]); - - if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) - return -EIO; - - return 0; -} - - - -/************************************************************************** - * General Driver Functions - ENTIRE REGISTERS - **************************************************************************/ - -/* - * si470x_get_all_registers - read entire registers - */ -static int si470x_get_all_registers(struct si470x_device *radio) -{ - int i; - u16 buf[READ_REG_NUM]; - struct i2c_msg msgs[1] = { - { radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM, - (void *)buf }, - }; - - if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) - return -EIO; - - for (i = 0; i < READ_REG_NUM; i++) - radio->registers[i] = __be16_to_cpu(buf[READ_INDEX(i)]); - - return 0; -} - - - -/************************************************************************** - * General Driver Functions - DISCONNECT_CHECK - **************************************************************************/ - -/* - * si470x_disconnect_check - check whether radio disconnects - */ -int si470x_disconnect_check(struct si470x_device *radio) -{ - return 0; -} - - - -/************************************************************************** - * File Operations Interface - **************************************************************************/ - -/* - * si470x_fops_open - file open - */ -int si470x_fops_open(struct file *file) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - mutex_lock(&radio->lock); - radio->users++; - - if (radio->users == 1) { - /* start radio */ - retval = si470x_start(radio); - if (retval < 0) - goto done; - - /* enable RDS interrupt */ - radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN; - radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2; - radio->registers[SYSCONFIG1] |= 0x1 << 2; - retval = si470x_set_register(radio, SYSCONFIG1); - } - -done: - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_fops_release - file release - */ -int si470x_fops_release(struct file *file) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - /* safety check */ - if (!radio) - return -ENODEV; - - mutex_lock(&radio->lock); - radio->users--; - if (radio->users == 0) - /* stop radio */ - retval = si470x_stop(radio); - - mutex_unlock(&radio->lock); - - return retval; -} - - - -/************************************************************************** - * Video4Linux Interface - **************************************************************************/ - -/* - * si470x_vidioc_querycap - query device capabilities - */ -int si470x_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); - strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - capability->version = DRIVER_KERNEL_VERSION; - capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | - V4L2_CAP_TUNER | V4L2_CAP_RADIO; - - return 0; -} - - - -/************************************************************************** - * I2C Interface - **************************************************************************/ - -/* - * si470x_i2c_interrupt_work - rds processing function - */ -static void si470x_i2c_interrupt_work(struct work_struct *work) -{ - struct si470x_device *radio = container_of(work, - struct si470x_device, radio_work); - unsigned char regnr; - unsigned char blocknum; - unsigned short bler; /* rds block errors */ - unsigned short rds; - unsigned char tmpbuf[3]; - int retval = 0; - - /* safety checks */ - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) - return; - - /* Update RDS registers */ - for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) { - retval = si470x_get_register(radio, STATUSRSSI + regnr); - if (retval < 0) - return; - } - - /* get rds blocks */ - if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) - /* No RDS group ready, better luck next time */ - return; - - for (blocknum = 0; blocknum < 4; blocknum++) { - switch (blocknum) { - default: - bler = (radio->registers[STATUSRSSI] & - STATUSRSSI_BLERA) >> 9; - rds = radio->registers[RDSA]; - break; - case 1: - bler = (radio->registers[READCHAN] & - READCHAN_BLERB) >> 14; - rds = radio->registers[RDSB]; - break; - case 2: - bler = (radio->registers[READCHAN] & - READCHAN_BLERC) >> 12; - rds = radio->registers[RDSC]; - break; - case 3: - bler = (radio->registers[READCHAN] & - READCHAN_BLERD) >> 10; - rds = radio->registers[RDSD]; - break; - }; - - /* Fill the V4L2 RDS buffer */ - put_unaligned_le16(rds, &tmpbuf); - tmpbuf[2] = blocknum; /* offset name */ - tmpbuf[2] |= blocknum << 3; /* received offset */ - if (bler > max_rds_errors) - tmpbuf[2] |= 0x80; /* uncorrectable errors */ - else if (bler > 0) - tmpbuf[2] |= 0x40; /* corrected error(s) */ - - /* copy RDS block to internal buffer */ - memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); - radio->wr_index += 3; - - /* wrap write pointer */ - if (radio->wr_index >= radio->buf_size) - radio->wr_index = 0; - - /* check for overflow */ - if (radio->wr_index == radio->rd_index) { - /* increment and wrap read pointer */ - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - } - } - - if (radio->wr_index != radio->rd_index) - wake_up_interruptible(&radio->read_queue); -} - - -/* - * si470x_i2c_interrupt - interrupt handler - */ -static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id) -{ - struct si470x_device *radio = dev_id; - - if (!work_pending(&radio->radio_work)) - schedule_work(&radio->radio_work); - - return IRQ_HANDLED; -} - - -/* - * si470x_i2c_probe - probe for the device - */ -static int __devinit si470x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct si470x_device *radio; - int retval = 0; - unsigned char version_warning = 0; - - /* private data allocation and initialization */ - radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); - if (!radio) { - retval = -ENOMEM; - goto err_initial; - } - - INIT_WORK(&radio->radio_work, si470x_i2c_interrupt_work); - radio->users = 0; - radio->client = client; - mutex_init(&radio->lock); - - /* video device allocation and initialization */ - radio->videodev = video_device_alloc(); - if (!radio->videodev) { - retval = -ENOMEM; - goto err_radio; - } - memcpy(radio->videodev, &si470x_viddev_template, - sizeof(si470x_viddev_template)); - video_set_drvdata(radio->videodev, radio); - - /* power up : need 110ms */ - radio->registers[POWERCFG] = POWERCFG_ENABLE; - if (si470x_set_register(radio, POWERCFG) < 0) { - retval = -EIO; - goto err_video; - } - msleep(110); - - /* get device and chip versions */ - if (si470x_get_all_registers(radio) < 0) { - retval = -EIO; - goto err_video; - } - dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", - radio->registers[DEVICEID], radio->registers[CHIPID]); - if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) { - dev_warn(&client->dev, - "This driver is known to work with " - "firmware version %hu,\n", RADIO_FW_VERSION); - dev_warn(&client->dev, - "but the device has firmware version %hu.\n", - radio->registers[CHIPID] & CHIPID_FIRMWARE); - version_warning = 1; - } - - /* give out version warning */ - if (version_warning == 1) { - dev_warn(&client->dev, - "If you have some trouble using this driver,\n"); - dev_warn(&client->dev, - "please report to V4L ML at " - "linux-media@vger.kernel.org\n"); - } - - /* set initial frequency */ - si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ - - /* rds buffer allocation */ - radio->buf_size = rds_buf * 3; - radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); - if (!radio->buffer) { - retval = -EIO; - goto err_video; - } - - /* rds buffer configuration */ - radio->wr_index = 0; - radio->rd_index = 0; - init_waitqueue_head(&radio->read_queue); - - retval = request_irq(client->irq, si470x_i2c_interrupt, - IRQF_TRIGGER_FALLING, DRIVER_NAME, radio); - if (retval) { - dev_err(&client->dev, "Failed to register interrupt\n"); - goto err_rds; - } - - /* register video device */ - retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, - radio_nr); - if (retval) { - dev_warn(&client->dev, "Could not register video device\n"); - goto err_all; - } - i2c_set_clientdata(client, radio); - - return 0; -err_all: - free_irq(client->irq, radio); -err_rds: - kfree(radio->buffer); -err_video: - video_device_release(radio->videodev); -err_radio: - kfree(radio); -err_initial: - return retval; -} - - -/* - * si470x_i2c_remove - remove the device - */ -static __devexit int si470x_i2c_remove(struct i2c_client *client) -{ - struct si470x_device *radio = i2c_get_clientdata(client); - - free_irq(client->irq, radio); - cancel_work_sync(&radio->radio_work); - video_unregister_device(radio->videodev); - kfree(radio); - - return 0; -} - - -#ifdef CONFIG_PM -/* - * si470x_i2c_suspend - suspend the device - */ -static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg) -{ - struct si470x_device *radio = i2c_get_clientdata(client); - - /* power down */ - radio->registers[POWERCFG] |= POWERCFG_DISABLE; - if (si470x_set_register(radio, POWERCFG) < 0) - return -EIO; - - return 0; -} - - -/* - * si470x_i2c_resume - resume the device - */ -static int si470x_i2c_resume(struct i2c_client *client) -{ - struct si470x_device *radio = i2c_get_clientdata(client); - - /* power up : need 110ms */ - radio->registers[POWERCFG] |= POWERCFG_ENABLE; - if (si470x_set_register(radio, POWERCFG) < 0) - return -EIO; - msleep(110); - - return 0; -} -#else -#define si470x_i2c_suspend NULL -#define si470x_i2c_resume NULL -#endif - - -/* - * si470x_i2c_driver - i2c driver interface - */ -static struct i2c_driver si470x_i2c_driver = { - .driver = { - .name = "si470x", - .owner = THIS_MODULE, - }, - .probe = si470x_i2c_probe, - .remove = __devexit_p(si470x_i2c_remove), - .suspend = si470x_i2c_suspend, - .resume = si470x_i2c_resume, - .id_table = si470x_i2c_id, -}; - - - -/************************************************************************** - * Module Interface - **************************************************************************/ - -/* - * si470x_i2c_init - module init - */ -static int __init si470x_i2c_init(void) -{ - printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); - return i2c_add_driver(&si470x_i2c_driver); -} - - -/* - * si470x_i2c_exit - module exit - */ -static void __exit si470x_i2c_exit(void) -{ - i2c_del_driver(&si470x_i2c_driver); -} - - -module_init(si470x_i2c_init); -module_exit(si470x_i2c_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-usb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-usb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-usb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si470x/radio-si470x-usb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,896 +0,0 @@ -/* - * drivers/media/radio/si470x/radio-si470x-usb.c - * - * USB driver for radios with Silicon Labs Si470x FM Radio Receivers - * - * Copyright (c) 2009 Tobias Lorenz - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - - -/* - * ToDo: - * - add firmware download/update support - */ - - -/* driver definitions */ -#define DRIVER_AUTHOR "Tobias Lorenz " -#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 10) -#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" -#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" -#define DRIVER_VERSION "1.0.10" - -/* kernel includes */ -#include -#include -#include - -#include "radio-si470x.h" - - -/* USB Device ID List */ -static struct usb_device_id si470x_usb_driver_id_table[] = { - /* Silicon Labs USB FM Radio Reference Design */ - { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, - /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */ - { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) }, - /* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */ - { USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) }, - /* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */ - { USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) }, - /* Terminating entry */ - { } -}; -MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table); - - - -/************************************************************************** - * Module Parameters - **************************************************************************/ - -/* Radio Nr */ -static int radio_nr = -1; -module_param(radio_nr, int, 0444); -MODULE_PARM_DESC(radio_nr, "Radio Nr"); - -/* USB timeout */ -static unsigned int usb_timeout = 500; -module_param(usb_timeout, uint, 0644); -MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*"); - -/* RDS buffer blocks */ -static unsigned int rds_buf = 100; -module_param(rds_buf, uint, 0444); -MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); - -/* RDS maximum block errors */ -static unsigned short max_rds_errors = 1; -/* 0 means 0 errors requiring correction */ -/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ -/* 2 means 3-5 errors requiring correction */ -/* 3 means 6+ errors or errors in checkword, correction not possible */ -module_param(max_rds_errors, ushort, 0644); -MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); - - - -/************************************************************************** - * USB HID Reports - **************************************************************************/ - -/* Reports 1-16 give direct read/write access to the 16 Si470x registers */ -/* with the (REPORT_ID - 1) corresponding to the register address across USB */ -/* endpoint 0 using GET_REPORT and SET_REPORT */ -#define REGISTER_REPORT_SIZE (RADIO_REGISTER_SIZE + 1) -#define REGISTER_REPORT(reg) ((reg) + 1) - -/* Report 17 gives direct read/write access to the entire Si470x register */ -/* map across endpoint 0 using GET_REPORT and SET_REPORT */ -#define ENTIRE_REPORT_SIZE (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) -#define ENTIRE_REPORT 17 - -/* Report 18 is used to send the lowest 6 Si470x registers up the HID */ -/* interrupt endpoint 1 to Windows every 20 milliseconds for status */ -#define RDS_REPORT_SIZE (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) -#define RDS_REPORT 18 - -/* Report 19: LED state */ -#define LED_REPORT_SIZE 3 -#define LED_REPORT 19 - -/* Report 19: stream */ -#define STREAM_REPORT_SIZE 3 -#define STREAM_REPORT 19 - -/* Report 20: scratch */ -#define SCRATCH_PAGE_SIZE 63 -#define SCRATCH_REPORT_SIZE (SCRATCH_PAGE_SIZE + 1) -#define SCRATCH_REPORT 20 - -/* Reports 19-22: flash upgrade of the C8051F321 */ -#define WRITE_REPORT_SIZE 4 -#define WRITE_REPORT 19 -#define FLASH_REPORT_SIZE 64 -#define FLASH_REPORT 20 -#define CRC_REPORT_SIZE 3 -#define CRC_REPORT 21 -#define RESPONSE_REPORT_SIZE 2 -#define RESPONSE_REPORT 22 - -/* Report 23: currently unused, but can accept 60 byte reports on the HID */ -/* interrupt out endpoint 2 every 1 millisecond */ -#define UNUSED_REPORT 23 - - - -/************************************************************************** - * Software/Hardware Versions from Scratch Page - **************************************************************************/ -#define RADIO_SW_VERSION_NOT_BOOTLOADABLE 6 -#define RADIO_SW_VERSION 7 -#define RADIO_HW_VERSION 1 - - - -/************************************************************************** - * LED State Definitions - **************************************************************************/ -#define LED_COMMAND 0x35 - -#define NO_CHANGE_LED 0x00 -#define ALL_COLOR_LED 0x01 /* streaming state */ -#define BLINK_GREEN_LED 0x02 /* connect state */ -#define BLINK_RED_LED 0x04 -#define BLINK_ORANGE_LED 0x10 /* disconnect state */ -#define SOLID_GREEN_LED 0x20 /* tuning/seeking state */ -#define SOLID_RED_LED 0x40 /* bootload state */ -#define SOLID_ORANGE_LED 0x80 - - - -/************************************************************************** - * Stream State Definitions - **************************************************************************/ -#define STREAM_COMMAND 0x36 -#define STREAM_VIDPID 0x00 -#define STREAM_AUDIO 0xff - - - -/************************************************************************** - * Bootloader / Flash Commands - **************************************************************************/ - -/* unique id sent to bootloader and required to put into a bootload state */ -#define UNIQUE_BL_ID 0x34 - -/* mask for the flash data */ -#define FLASH_DATA_MASK 0x55 - -/* bootloader commands */ -#define GET_SW_VERSION_COMMAND 0x00 -#define SET_PAGE_COMMAND 0x01 -#define ERASE_PAGE_COMMAND 0x02 -#define WRITE_PAGE_COMMAND 0x03 -#define CRC_ON_PAGE_COMMAND 0x04 -#define READ_FLASH_BYTE_COMMAND 0x05 -#define RESET_DEVICE_COMMAND 0x06 -#define GET_HW_VERSION_COMMAND 0x07 -#define BLANK 0xff - -/* bootloader command responses */ -#define COMMAND_OK 0x01 -#define COMMAND_FAILED 0x02 -#define COMMAND_PENDING 0x03 - - - -/************************************************************************** - * General Driver Functions - REGISTER_REPORTs - **************************************************************************/ - -/* - * si470x_get_report - receive a HID report - */ -static int si470x_get_report(struct si470x_device *radio, void *buf, int size) -{ - unsigned char *report = (unsigned char *) buf; - int retval; - - retval = usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - HID_REQ_GET_REPORT, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - report[0], 2, - buf, size, usb_timeout); - - if (retval < 0) - dev_warn(&radio->intf->dev, - "si470x_get_report: usb_control_msg returned %d\n", - retval); - return retval; -} - - -/* - * si470x_set_report - send a HID report - */ -static int si470x_set_report(struct si470x_device *radio, void *buf, int size) -{ - unsigned char *report = (unsigned char *) buf; - int retval; - - retval = usb_control_msg(radio->usbdev, - usb_sndctrlpipe(radio->usbdev, 0), - HID_REQ_SET_REPORT, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - report[0], 2, - buf, size, usb_timeout); - - if (retval < 0) - dev_warn(&radio->intf->dev, - "si470x_set_report: usb_control_msg returned %d\n", - retval); - return retval; -} - - -/* - * si470x_get_register - read register - */ -int si470x_get_register(struct si470x_device *radio, int regnr) -{ - unsigned char buf[REGISTER_REPORT_SIZE]; - int retval; - - buf[0] = REGISTER_REPORT(regnr); - - retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); - - if (retval >= 0) - radio->registers[regnr] = get_unaligned_be16(&buf[1]); - - return (retval < 0) ? -EINVAL : 0; -} - - -/* - * si470x_set_register - write register - */ -int si470x_set_register(struct si470x_device *radio, int regnr) -{ - unsigned char buf[REGISTER_REPORT_SIZE]; - int retval; - - buf[0] = REGISTER_REPORT(regnr); - put_unaligned_be16(radio->registers[regnr], &buf[1]); - - retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); - - return (retval < 0) ? -EINVAL : 0; -} - - - -/************************************************************************** - * General Driver Functions - ENTIRE_REPORT - **************************************************************************/ - -/* - * si470x_get_all_registers - read entire registers - */ -static int si470x_get_all_registers(struct si470x_device *radio) -{ - unsigned char buf[ENTIRE_REPORT_SIZE]; - int retval; - unsigned char regnr; - - buf[0] = ENTIRE_REPORT; - - retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); - - if (retval >= 0) - for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) - radio->registers[regnr] = get_unaligned_be16( - &buf[regnr * RADIO_REGISTER_SIZE + 1]); - - return (retval < 0) ? -EINVAL : 0; -} - - - -/************************************************************************** - * General Driver Functions - LED_REPORT - **************************************************************************/ - -/* - * si470x_set_led_state - sets the led state - */ -static int si470x_set_led_state(struct si470x_device *radio, - unsigned char led_state) -{ - unsigned char buf[LED_REPORT_SIZE]; - int retval; - - buf[0] = LED_REPORT; - buf[1] = LED_COMMAND; - buf[2] = led_state; - - retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); - - return (retval < 0) ? -EINVAL : 0; -} - - - -/************************************************************************** - * General Driver Functions - SCRATCH_REPORT - **************************************************************************/ - -/* - * si470x_get_scratch_versions - gets the scratch page and version infos - */ -static int si470x_get_scratch_page_versions(struct si470x_device *radio) -{ - unsigned char buf[SCRATCH_REPORT_SIZE]; - int retval; - - buf[0] = SCRATCH_REPORT; - - retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); - - if (retval < 0) - dev_warn(&radio->intf->dev, "si470x_get_scratch: " - "si470x_get_report returned %d\n", retval); - else { - radio->software_version = buf[1]; - radio->hardware_version = buf[2]; - } - - return (retval < 0) ? -EINVAL : 0; -} - - - -/************************************************************************** - * General Driver Functions - DISCONNECT_CHECK - **************************************************************************/ - -/* - * si470x_disconnect_check - check whether radio disconnects - */ -int si470x_disconnect_check(struct si470x_device *radio) -{ - if (radio->disconnected) - return -EIO; - else - return 0; -} - - - -/************************************************************************** - * RDS Driver Functions - **************************************************************************/ - -/* - * si470x_int_in_callback - rds callback and processing function - * - * TODO: do we need to use mutex locks in some sections? - */ -static void si470x_int_in_callback(struct urb *urb) -{ - struct si470x_device *radio = urb->context; - unsigned char buf[RDS_REPORT_SIZE]; - int retval; - unsigned char regnr; - unsigned char blocknum; - unsigned short bler; /* rds block errors */ - unsigned short rds; - unsigned char tmpbuf[3]; - - if (urb->status) { - if (urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN) { - return; - } else { - dev_warn(&radio->intf->dev, - "non-zero urb status (%d)\n", urb->status); - goto resubmit; /* Maybe we can recover. */ - } - } - - /* safety checks */ - if (radio->disconnected) - return; - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) - goto resubmit; - - if (urb->actual_length > 0) { - /* Update RDS registers with URB data */ - buf[0] = RDS_REPORT; - for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) - radio->registers[STATUSRSSI + regnr] = - get_unaligned_be16(&radio->int_in_buffer[ - regnr * RADIO_REGISTER_SIZE + 1]); - /* get rds blocks */ - if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) { - /* No RDS group ready, better luck next time */ - goto resubmit; - } - if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) { - /* RDS decoder not synchronized */ - goto resubmit; - } - for (blocknum = 0; blocknum < 4; blocknum++) { - switch (blocknum) { - default: - bler = (radio->registers[STATUSRSSI] & - STATUSRSSI_BLERA) >> 9; - rds = radio->registers[RDSA]; - break; - case 1: - bler = (radio->registers[READCHAN] & - READCHAN_BLERB) >> 14; - rds = radio->registers[RDSB]; - break; - case 2: - bler = (radio->registers[READCHAN] & - READCHAN_BLERC) >> 12; - rds = radio->registers[RDSC]; - break; - case 3: - bler = (radio->registers[READCHAN] & - READCHAN_BLERD) >> 10; - rds = radio->registers[RDSD]; - break; - }; - - /* Fill the V4L2 RDS buffer */ - put_unaligned_le16(rds, &tmpbuf); - tmpbuf[2] = blocknum; /* offset name */ - tmpbuf[2] |= blocknum << 3; /* received offset */ - if (bler > max_rds_errors) - tmpbuf[2] |= 0x80; /* uncorrectable errors */ - else if (bler > 0) - tmpbuf[2] |= 0x40; /* corrected error(s) */ - - /* copy RDS block to internal buffer */ - memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); - radio->wr_index += 3; - - /* wrap write pointer */ - if (radio->wr_index >= radio->buf_size) - radio->wr_index = 0; - - /* check for overflow */ - if (radio->wr_index == radio->rd_index) { - /* increment and wrap read pointer */ - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - } - } - if (radio->wr_index != radio->rd_index) - wake_up_interruptible(&radio->read_queue); - } - -resubmit: - /* Resubmit if we're still running. */ - if (radio->int_in_running && radio->usbdev) { - retval = usb_submit_urb(radio->int_in_urb, GFP_ATOMIC); - if (retval) { - dev_warn(&radio->intf->dev, - "resubmitting urb failed (%d)", retval); - radio->int_in_running = 0; - } - } -} - - - -/************************************************************************** - * File Operations Interface - **************************************************************************/ - -/* - * si470x_fops_open - file open - */ -int si470x_fops_open(struct file *file) -{ - struct si470x_device *radio = video_drvdata(file); - int retval; - - mutex_lock(&radio->lock); - radio->users++; - - retval = usb_autopm_get_interface(radio->intf); - if (retval < 0) { - radio->users--; - retval = -EIO; - goto done; - } - - if (radio->users == 1) { - /* start radio */ - retval = si470x_start(radio); - if (retval < 0) { - usb_autopm_put_interface(radio->intf); - goto done; - } - - /* initialize interrupt urb */ - usb_fill_int_urb(radio->int_in_urb, radio->usbdev, - usb_rcvintpipe(radio->usbdev, - radio->int_in_endpoint->bEndpointAddress), - radio->int_in_buffer, - le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize), - si470x_int_in_callback, - radio, - radio->int_in_endpoint->bInterval); - - radio->int_in_running = 1; - mb(); - - retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL); - if (retval) { - dev_info(&radio->intf->dev, - "submitting int urb failed (%d)\n", retval); - radio->int_in_running = 0; - usb_autopm_put_interface(radio->intf); - } - } - -done: - mutex_unlock(&radio->lock); - return retval; -} - - -/* - * si470x_fops_release - file release - */ -int si470x_fops_release(struct file *file) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - /* safety check */ - if (!radio) { - retval = -ENODEV; - goto done; - } - - mutex_lock(&radio->lock); - radio->users--; - if (radio->users == 0) { - /* shutdown interrupt handler */ - if (radio->int_in_running) { - radio->int_in_running = 0; - if (radio->int_in_urb) - usb_kill_urb(radio->int_in_urb); - } - - if (radio->disconnected) { - video_unregister_device(radio->videodev); - kfree(radio->int_in_buffer); - kfree(radio->buffer); - mutex_unlock(&radio->lock); - kfree(radio); - goto done; - } - - /* cancel read processes */ - wake_up_interruptible(&radio->read_queue); - - /* stop radio */ - retval = si470x_stop(radio); - usb_autopm_put_interface(radio->intf); - } - mutex_unlock(&radio->lock); -done: - return retval; -} - - - -/************************************************************************** - * Video4Linux Interface - **************************************************************************/ - -/* - * si470x_vidioc_querycap - query device capabilities - */ -int si470x_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - struct si470x_device *radio = video_drvdata(file); - - strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); - strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - usb_make_path(radio->usbdev, capability->bus_info, - sizeof(capability->bus_info)); - capability->version = DRIVER_KERNEL_VERSION; - capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | - V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; - - return 0; -} - - - -/************************************************************************** - * USB Interface - **************************************************************************/ - -/* - * si470x_usb_driver_probe - probe for the device - */ -static int si470x_usb_driver_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct si470x_device *radio; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int i, int_end_size, retval = 0; - unsigned char version_warning = 0; - - /* private data allocation and initialization */ - radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); - if (!radio) { - retval = -ENOMEM; - goto err_initial; - } - radio->users = 0; - radio->disconnected = 0; - radio->usbdev = interface_to_usbdev(intf); - radio->intf = intf; - mutex_init(&radio->lock); - - iface_desc = intf->cur_altsetting; - - /* Set up interrupt endpoint information. */ - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == - USB_DIR_IN) && ((endpoint->bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) - radio->int_in_endpoint = endpoint; - } - if (!radio->int_in_endpoint) { - dev_info(&intf->dev, "could not find interrupt in endpoint\n"); - retval = -EIO; - goto err_radio; - } - - int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize); - - radio->int_in_buffer = kmalloc(int_end_size, GFP_KERNEL); - if (!radio->int_in_buffer) { - dev_info(&intf->dev, "could not allocate int_in_buffer"); - retval = -ENOMEM; - goto err_radio; - } - - radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!radio->int_in_urb) { - dev_info(&intf->dev, "could not allocate int_in_urb"); - retval = -ENOMEM; - goto err_intbuffer; - } - - /* video device allocation and initialization */ - radio->videodev = video_device_alloc(); - if (!radio->videodev) { - retval = -ENOMEM; - goto err_intbuffer; - } - memcpy(radio->videodev, &si470x_viddev_template, - sizeof(si470x_viddev_template)); - video_set_drvdata(radio->videodev, radio); - - /* get device and chip versions */ - if (si470x_get_all_registers(radio) < 0) { - retval = -EIO; - goto err_video; - } - dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", - radio->registers[DEVICEID], radio->registers[CHIPID]); - if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) { - dev_warn(&intf->dev, - "This driver is known to work with " - "firmware version %hu,\n", RADIO_FW_VERSION); - dev_warn(&intf->dev, - "but the device has firmware version %hu.\n", - radio->registers[CHIPID] & CHIPID_FIRMWARE); - version_warning = 1; - } - - /* get software and hardware versions */ - if (si470x_get_scratch_page_versions(radio) < 0) { - retval = -EIO; - goto err_video; - } - dev_info(&intf->dev, "software version %d, hardware version %d\n", - radio->software_version, radio->hardware_version); - if (radio->software_version < RADIO_SW_VERSION) { - dev_warn(&intf->dev, - "This driver is known to work with " - "software version %hu,\n", RADIO_SW_VERSION); - dev_warn(&intf->dev, - "but the device has software version %hu.\n", - radio->software_version); - version_warning = 1; - } - if (radio->hardware_version < RADIO_HW_VERSION) { - dev_warn(&intf->dev, - "This driver is known to work with " - "hardware version %hu,\n", RADIO_HW_VERSION); - dev_warn(&intf->dev, - "but the device has hardware version %hu.\n", - radio->hardware_version); - version_warning = 1; - } - - /* give out version warning */ - if (version_warning == 1) { - dev_warn(&intf->dev, - "If you have some trouble using this driver,\n"); - dev_warn(&intf->dev, - "please report to V4L ML at " - "linux-media@vger.kernel.org\n"); - } - - /* set initial frequency */ - si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ - - /* set led to connect state */ - si470x_set_led_state(radio, BLINK_GREEN_LED); - - /* rds buffer allocation */ - radio->buf_size = rds_buf * 3; - radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); - if (!radio->buffer) { - retval = -EIO; - goto err_video; - } - - /* rds buffer configuration */ - radio->wr_index = 0; - radio->rd_index = 0; - init_waitqueue_head(&radio->read_queue); - - /* register video device */ - retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, - radio_nr); - if (retval) { - dev_warn(&intf->dev, "Could not register video device\n"); - goto err_all; - } - usb_set_intfdata(intf, radio); - - return 0; -err_all: - kfree(radio->buffer); -err_video: - video_device_release(radio->videodev); -err_intbuffer: - kfree(radio->int_in_buffer); -err_radio: - kfree(radio); -err_initial: - return retval; -} - - -/* - * si470x_usb_driver_suspend - suspend the device - */ -static int si470x_usb_driver_suspend(struct usb_interface *intf, - pm_message_t message) -{ - dev_info(&intf->dev, "suspending now...\n"); - - return 0; -} - - -/* - * si470x_usb_driver_resume - resume the device - */ -static int si470x_usb_driver_resume(struct usb_interface *intf) -{ - dev_info(&intf->dev, "resuming now...\n"); - - return 0; -} - - -/* - * si470x_usb_driver_disconnect - disconnect the device - */ -static void si470x_usb_driver_disconnect(struct usb_interface *intf) -{ - struct si470x_device *radio = usb_get_intfdata(intf); - - mutex_lock(&radio->lock); - radio->disconnected = 1; - usb_set_intfdata(intf, NULL); - if (radio->users == 0) { - /* set led to disconnect state */ - si470x_set_led_state(radio, BLINK_ORANGE_LED); - - /* Free data structures. */ - usb_free_urb(radio->int_in_urb); - - kfree(radio->int_in_buffer); - video_unregister_device(radio->videodev); - kfree(radio->buffer); - mutex_unlock(&radio->lock); - kfree(radio); - } else { - mutex_unlock(&radio->lock); - } -} - - -/* - * si470x_usb_driver - usb driver interface - */ -static struct usb_driver si470x_usb_driver = { - .name = DRIVER_NAME, - .probe = si470x_usb_driver_probe, - .disconnect = si470x_usb_driver_disconnect, - .suspend = si470x_usb_driver_suspend, - .resume = si470x_usb_driver_resume, - .id_table = si470x_usb_driver_id_table, - .supports_autosuspend = 1, -}; - - - -/************************************************************************** - * Module Interface - **************************************************************************/ - -/* - * si470x_module_init - module init - */ -static int __init si470x_module_init(void) -{ - printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); - return usb_register(&si470x_usb_driver); -} - - -/* - * si470x_module_exit - module exit - */ -static void __exit si470x_module_exit(void) -{ - usb_deregister(&si470x_usb_driver); -} - - -module_init(si470x_module_init); -module_exit(si470x_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si4713-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si4713-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si4713-i2c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si4713-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2120 +0,0 @@ -/* - * drivers/media/radio/si4713-i2c.c - * - * Silicon Labs Si4713 FM Radio Transmitter I2C commands. - * - * Copyright (c) 2009 Nokia Corporation - * Contact: Eduardo Valentin - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "si4713-i2c.h" - -/* module parameters */ -static int debug; -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug level (0 - 2)"); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Eduardo Valentin "); -MODULE_DESCRIPTION("I2C driver for Si4713 FM Radio Transmitter"); - -static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = { - "vio", - "vdd", -}; - -#define DEFAULT_RDS_PI 0x00 -#define DEFAULT_RDS_PTY 0x00 -#define DEFAULT_RDS_PS_NAME "" -#define DEFAULT_RDS_RADIO_TEXT DEFAULT_RDS_PS_NAME -#define DEFAULT_RDS_DEVIATION 0x00C8 -#define DEFAULT_RDS_PS_REPEAT_COUNT 0x0003 -#define DEFAULT_LIMITER_RTIME 0x1392 -#define DEFAULT_LIMITER_DEV 0x102CA -#define DEFAULT_PILOT_FREQUENCY 0x4A38 -#define DEFAULT_PILOT_DEVIATION 0x1A5E -#define DEFAULT_ACOMP_ATIME 0x0000 -#define DEFAULT_ACOMP_RTIME 0xF4240L -#define DEFAULT_ACOMP_GAIN 0x0F -#define DEFAULT_ACOMP_THRESHOLD (-0x28) -#define DEFAULT_MUTE 0x01 -#define DEFAULT_POWER_LEVEL 88 -#define DEFAULT_FREQUENCY 8800 -#define DEFAULT_PREEMPHASIS FMPE_EU -#define DEFAULT_TUNE_RNL 0xFF - -#define to_si4713_device(sd) container_of(sd, struct si4713_device, sd) - -/* frequency domain transformation (using times 10 to avoid floats) */ -#define FREQDEV_UNIT 100000 -#define FREQV4L2_MULTI 625 -#define si4713_to_v4l2(f) ((f * FREQDEV_UNIT) / FREQV4L2_MULTI) -#define v4l2_to_si4713(f) ((f * FREQV4L2_MULTI) / FREQDEV_UNIT) -#define FREQ_RANGE_LOW 7600 -#define FREQ_RANGE_HIGH 10800 - -#define MAX_ARGS 7 - -#define RDS_BLOCK 8 -#define RDS_BLOCK_CLEAR 0x03 -#define RDS_BLOCK_LOAD 0x04 -#define RDS_RADIOTEXT_2A 0x20 -#define RDS_RADIOTEXT_BLK_SIZE 4 -#define RDS_RADIOTEXT_INDEX_MAX 0x0F -#define RDS_CARRIAGE_RETURN 0x0D - -#define rds_ps_nblocks(len) ((len / RDS_BLOCK) + (len % RDS_BLOCK ? 1 : 0)) - -#define get_status_bit(p, b, m) (((p) & (m)) >> (b)) -#define set_bits(p, v, b, m) (((p) & ~(m)) | ((v) << (b))) - -#define ATTACK_TIME_UNIT 500 - -#define POWER_OFF 0x00 -#define POWER_ON 0x01 - -#define msb(x) ((u8)((u16) x >> 8)) -#define lsb(x) ((u8)((u16) x & 0x00FF)) -#define compose_u16(msb, lsb) (((u16)msb << 8) | lsb) -#define check_command_failed(status) (!(status & SI4713_CTS) || \ - (status & SI4713_ERR)) -/* mute definition */ -#define set_mute(p) ((p & 1) | ((p & 1) << 1)); -#define get_mute(p) (p & 0x01) - -#ifdef DEBUG -#define DBG_BUFFER(device, message, buffer, size) \ - { \ - int i; \ - char str[(size)*5]; \ - for (i = 0; i < size; i++) \ - sprintf(str + i * 5, " 0x%02x", buffer[i]); \ - v4l2_dbg(2, debug, device, "%s:%s\n", message, str); \ - } -#else -#define DBG_BUFFER(device, message, buffer, size) -#endif - -/* - * Values for limiter release time (sorted by second column) - * device release - * value time (us) - */ -static long limiter_times[] = { - 2000, 250, - 1000, 500, - 510, 1000, - 255, 2000, - 170, 3000, - 127, 4020, - 102, 5010, - 85, 6020, - 73, 7010, - 64, 7990, - 57, 8970, - 51, 10030, - 25, 20470, - 17, 30110, - 13, 39380, - 10, 51190, - 8, 63690, - 7, 73140, - 6, 85330, - 5, 102390, -}; - -/* - * Values for audio compression release time (sorted by second column) - * device release - * value time (us) - */ -static unsigned long acomp_rtimes[] = { - 0, 100000, - 1, 200000, - 2, 350000, - 3, 525000, - 4, 1000000, -}; - -/* - * Values for preemphasis (sorted by second column) - * device preemphasis - * value value (v4l2) - */ -static unsigned long preemphasis_values[] = { - FMPE_DISABLED, V4L2_PREEMPHASIS_DISABLED, - FMPE_EU, V4L2_PREEMPHASIS_50_uS, - FMPE_USA, V4L2_PREEMPHASIS_75_uS, -}; - -static int usecs_to_dev(unsigned long usecs, unsigned long const array[], - int size) -{ - int i; - int rval = -EINVAL; - - for (i = 0; i < size / 2; i++) - if (array[(i * 2) + 1] >= usecs) { - rval = array[i * 2]; - break; - } - - return rval; -} - -static unsigned long dev_to_usecs(int value, unsigned long const array[], - int size) -{ - int i; - int rval = -EINVAL; - - for (i = 0; i < size / 2; i++) - if (array[i * 2] == value) { - rval = array[(i * 2) + 1]; - break; - } - - return rval; -} - -/* si4713_handler: IRQ handler, just complete work */ -static irqreturn_t si4713_handler(int irq, void *dev) -{ - struct si4713_device *sdev = dev; - - v4l2_dbg(2, debug, &sdev->sd, - "%s: sending signal to completion work.\n", __func__); - complete(&sdev->work); - - return IRQ_HANDLED; -} - -/* - * si4713_send_command - sends a command to si4713 and waits its response - * @sdev: si4713_device structure for the device we are communicating - * @command: command id - * @args: command arguments we are sending (up to 7) - * @argn: actual size of @args - * @response: buffer to place the expected response from the device (up to 15) - * @respn: actual size of @response - * @usecs: amount of time to wait before reading the response (in usecs) - */ -static int si4713_send_command(struct si4713_device *sdev, const u8 command, - const u8 args[], const int argn, - u8 response[], const int respn, const int usecs) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); - u8 data1[MAX_ARGS + 1]; - int err; - - if (!client->adapter) - return -ENODEV; - - /* First send the command and its arguments */ - data1[0] = command; - memcpy(data1 + 1, args, argn); - DBG_BUFFER(&sdev->sd, "Parameters", data1, argn + 1); - - err = i2c_master_send(client, data1, argn + 1); - if (err != argn + 1) { - v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n", - command); - return (err > 0) ? -EIO : err; - } - - /* Wait response from interrupt */ - if (!wait_for_completion_timeout(&sdev->work, - usecs_to_jiffies(usecs) + 1)) - v4l2_warn(&sdev->sd, - "(%s) Device took too much time to answer.\n", - __func__); - - /* Then get the response */ - err = i2c_master_recv(client, response, respn); - if (err != respn) { - v4l2_err(&sdev->sd, - "Error while reading response for command 0x%02x\n", - command); - return (err > 0) ? -EIO : err; - } - - DBG_BUFFER(&sdev->sd, "Response", response, respn); - if (check_command_failed(response[0])) - return -EBUSY; - - return 0; -} - -/* - * si4713_read_property - reads a si4713 property - * @sdev: si4713_device structure for the device we are communicating - * @prop: property identification number - * @pv: property value to be returned on success - */ -static int si4713_read_property(struct si4713_device *sdev, u16 prop, u32 *pv) -{ - int err; - u8 val[SI4713_GET_PROP_NRESP]; - /* - * .First byte = 0 - * .Second byte = property's MSB - * .Third byte = property's LSB - */ - const u8 args[SI4713_GET_PROP_NARGS] = { - 0x00, - msb(prop), - lsb(prop), - }; - - err = si4713_send_command(sdev, SI4713_CMD_GET_PROPERTY, - args, ARRAY_SIZE(args), val, - ARRAY_SIZE(val), DEFAULT_TIMEOUT); - - if (err < 0) - return err; - - *pv = compose_u16(val[2], val[3]); - - v4l2_dbg(1, debug, &sdev->sd, - "%s: property=0x%02x value=0x%02x status=0x%02x\n", - __func__, prop, *pv, val[0]); - - return err; -} - -/* - * si4713_write_property - modifies a si4713 property - * @sdev: si4713_device structure for the device we are communicating - * @prop: property identification number - * @val: new value for that property - */ -static int si4713_write_property(struct si4713_device *sdev, u16 prop, u16 val) -{ - int rval; - u8 resp[SI4713_SET_PROP_NRESP]; - /* - * .First byte = 0 - * .Second byte = property's MSB - * .Third byte = property's LSB - * .Fourth byte = value's MSB - * .Fifth byte = value's LSB - */ - const u8 args[SI4713_SET_PROP_NARGS] = { - 0x00, - msb(prop), - lsb(prop), - msb(val), - lsb(val), - }; - - rval = si4713_send_command(sdev, SI4713_CMD_SET_PROPERTY, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - DEFAULT_TIMEOUT); - - if (rval < 0) - return rval; - - v4l2_dbg(1, debug, &sdev->sd, - "%s: property=0x%02x value=0x%02x status=0x%02x\n", - __func__, prop, val, resp[0]); - - /* - * As there is no command response for SET_PROPERTY, - * wait Tcomp time to finish before proceed, in order - * to have property properly set. - */ - msleep(TIMEOUT_SET_PROPERTY); - - return rval; -} - -/* - * si4713_powerup - Powers the device up - * @sdev: si4713_device structure for the device we are communicating - */ -static int si4713_powerup(struct si4713_device *sdev) -{ - int err; - u8 resp[SI4713_PWUP_NRESP]; - /* - * .First byte = Enabled interrupts and boot function - * .Second byte = Input operation mode - */ - const u8 args[SI4713_PWUP_NARGS] = { - SI4713_PWUP_CTSIEN | SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX, - SI4713_PWUP_OPMOD_ANALOG, - }; - - if (sdev->power_state) - return 0; - - err = regulator_bulk_enable(ARRAY_SIZE(sdev->supplies), - sdev->supplies); - if (err) { - v4l2_err(&sdev->sd, "Failed to enable supplies: %d\n", err); - return err; - } - if (gpio_is_valid(sdev->gpio_reset)) { - udelay(50); - gpio_set_value(sdev->gpio_reset, 1); - } - - err = si4713_send_command(sdev, SI4713_CMD_POWER_UP, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - TIMEOUT_POWER_UP); - - if (!err) { - v4l2_dbg(1, debug, &sdev->sd, "Powerup response: 0x%02x\n", - resp[0]); - v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n"); - sdev->power_state = POWER_ON; - - err = si4713_write_property(sdev, SI4713_GPO_IEN, - SI4713_STC_INT | SI4713_CTS); - } else { - if (gpio_is_valid(sdev->gpio_reset)) - gpio_set_value(sdev->gpio_reset, 0); - err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies), - sdev->supplies); - if (err) - v4l2_err(&sdev->sd, - "Failed to disable supplies: %d\n", err); - } - - return err; -} - -/* - * si4713_powerdown - Powers the device down - * @sdev: si4713_device structure for the device we are communicating - */ -static int si4713_powerdown(struct si4713_device *sdev) -{ - int err; - u8 resp[SI4713_PWDN_NRESP]; - - if (!sdev->power_state) - return 0; - - err = si4713_send_command(sdev, SI4713_CMD_POWER_DOWN, - NULL, 0, - resp, ARRAY_SIZE(resp), - DEFAULT_TIMEOUT); - - if (!err) { - v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n", - resp[0]); - v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n"); - if (gpio_is_valid(sdev->gpio_reset)) - gpio_set_value(sdev->gpio_reset, 0); - err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies), - sdev->supplies); - if (err) - v4l2_err(&sdev->sd, - "Failed to disable supplies: %d\n", err); - sdev->power_state = POWER_OFF; - } - - return err; -} - -/* - * si4713_checkrev - Checks if we are treating a device with the correct rev. - * @sdev: si4713_device structure for the device we are communicating - */ -static int si4713_checkrev(struct si4713_device *sdev) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); - int rval; - u8 resp[SI4713_GETREV_NRESP]; - - mutex_lock(&sdev->mutex); - - rval = si4713_send_command(sdev, SI4713_CMD_GET_REV, - NULL, 0, - resp, ARRAY_SIZE(resp), - DEFAULT_TIMEOUT); - - if (rval < 0) - goto unlock; - - if (resp[1] == SI4713_PRODUCT_NUMBER) { - v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n", - client->addr << 1, client->adapter->name); - } else { - v4l2_err(&sdev->sd, "Invalid product number\n"); - rval = -EINVAL; - } - -unlock: - mutex_unlock(&sdev->mutex); - return rval; -} - -/* - * si4713_wait_stc - Waits STC interrupt and clears status bits. Usefull - * for TX_TUNE_POWER, TX_TUNE_FREQ and TX_TUNE_MEAS - * @sdev: si4713_device structure for the device we are communicating - * @usecs: timeout to wait for STC interrupt signal - */ -static int si4713_wait_stc(struct si4713_device *sdev, const int usecs) -{ - int err; - u8 resp[SI4713_GET_STATUS_NRESP]; - - /* Wait response from STC interrupt */ - if (!wait_for_completion_timeout(&sdev->work, - usecs_to_jiffies(usecs) + 1)) - v4l2_warn(&sdev->sd, - "%s: device took too much time to answer (%d usec).\n", - __func__, usecs); - - /* Clear status bits */ - err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS, - NULL, 0, - resp, ARRAY_SIZE(resp), - DEFAULT_TIMEOUT); - - if (err < 0) - goto exit; - - v4l2_dbg(1, debug, &sdev->sd, - "%s: status bits: 0x%02x\n", __func__, resp[0]); - - if (!(resp[0] & SI4713_STC_INT)) - err = -EIO; - -exit: - return err; -} - -/* - * si4713_tx_tune_freq - Sets the state of the RF carrier and sets the tuning - * frequency between 76 and 108 MHz in 10 kHz units and - * steps of 50 kHz. - * @sdev: si4713_device structure for the device we are communicating - * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz) - */ -static int si4713_tx_tune_freq(struct si4713_device *sdev, u16 frequency) -{ - int err; - u8 val[SI4713_TXFREQ_NRESP]; - /* - * .First byte = 0 - * .Second byte = frequency's MSB - * .Third byte = frequency's LSB - */ - const u8 args[SI4713_TXFREQ_NARGS] = { - 0x00, - msb(frequency), - lsb(frequency), - }; - - err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_FREQ, - args, ARRAY_SIZE(args), val, - ARRAY_SIZE(val), DEFAULT_TIMEOUT); - - if (err < 0) - return err; - - v4l2_dbg(1, debug, &sdev->sd, - "%s: frequency=0x%02x status=0x%02x\n", __func__, - frequency, val[0]); - - err = si4713_wait_stc(sdev, TIMEOUT_TX_TUNE); - if (err < 0) - return err; - - return compose_u16(args[1], args[2]); -} - -/* - * si4713_tx_tune_power - Sets the RF voltage level between 88 and 115 dBuV in - * 1 dB units. A value of 0x00 indicates off. The command - * also sets the antenna tuning capacitance. A value of 0 - * indicates autotuning, and a value of 1 - 191 indicates - * a manual override, which results in a tuning - * capacitance of 0.25 pF x @antcap. - * @sdev: si4713_device structure for the device we are communicating - * @power: tuning power (88 - 115 dBuV, unit/step 1 dB) - * @antcap: value of antenna tuning capacitor (0 - 191) - */ -static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power, - u8 antcap) -{ - int err; - u8 val[SI4713_TXPWR_NRESP]; - /* - * .First byte = 0 - * .Second byte = 0 - * .Third byte = power - * .Fourth byte = antcap - */ - const u8 args[SI4713_TXPWR_NARGS] = { - 0x00, - 0x00, - power, - antcap, - }; - - if (((power > 0) && (power < SI4713_MIN_POWER)) || - power > SI4713_MAX_POWER || antcap > SI4713_MAX_ANTCAP) - return -EDOM; - - err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_POWER, - args, ARRAY_SIZE(args), val, - ARRAY_SIZE(val), DEFAULT_TIMEOUT); - - if (err < 0) - return err; - - v4l2_dbg(1, debug, &sdev->sd, - "%s: power=0x%02x antcap=0x%02x status=0x%02x\n", - __func__, power, antcap, val[0]); - - return si4713_wait_stc(sdev, TIMEOUT_TX_TUNE_POWER); -} - -/* - * si4713_tx_tune_measure - Enters receive mode and measures the received noise - * level in units of dBuV on the selected frequency. - * The Frequency must be between 76 and 108 MHz in 10 kHz - * units and steps of 50 kHz. The command also sets the - * antenna tuning capacitance. A value of 0 means - * autotuning, and a value of 1 to 191 indicates manual - * override. - * @sdev: si4713_device structure for the device we are communicating - * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz) - * @antcap: value of antenna tuning capacitor (0 - 191) - */ -static int si4713_tx_tune_measure(struct si4713_device *sdev, u16 frequency, - u8 antcap) -{ - int err; - u8 val[SI4713_TXMEA_NRESP]; - /* - * .First byte = 0 - * .Second byte = frequency's MSB - * .Third byte = frequency's LSB - * .Fourth byte = antcap - */ - const u8 args[SI4713_TXMEA_NARGS] = { - 0x00, - msb(frequency), - lsb(frequency), - antcap, - }; - - sdev->tune_rnl = DEFAULT_TUNE_RNL; - - if (antcap > SI4713_MAX_ANTCAP) - return -EDOM; - - err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_MEASURE, - args, ARRAY_SIZE(args), val, - ARRAY_SIZE(val), DEFAULT_TIMEOUT); - - if (err < 0) - return err; - - v4l2_dbg(1, debug, &sdev->sd, - "%s: frequency=0x%02x antcap=0x%02x status=0x%02x\n", - __func__, frequency, antcap, val[0]); - - return si4713_wait_stc(sdev, TIMEOUT_TX_TUNE); -} - -/* - * si4713_tx_tune_status- Returns the status of the tx_tune_freq, tx_tune_mea or - * tx_tune_power commands. This command return the current - * frequency, output voltage in dBuV, the antenna tunning - * capacitance value and the received noise level. The - * command also clears the stcint interrupt bit when the - * first bit of its arguments is high. - * @sdev: si4713_device structure for the device we are communicating - * @intack: 0x01 to clear the seek/tune complete interrupt status indicator. - * @frequency: returned frequency - * @power: returned power - * @antcap: returned antenna capacitance - * @noise: returned noise level - */ -static int si4713_tx_tune_status(struct si4713_device *sdev, u8 intack, - u16 *frequency, u8 *power, - u8 *antcap, u8 *noise) -{ - int err; - u8 val[SI4713_TXSTATUS_NRESP]; - /* - * .First byte = intack bit - */ - const u8 args[SI4713_TXSTATUS_NARGS] = { - intack & SI4713_INTACK_MASK, - }; - - err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_STATUS, - args, ARRAY_SIZE(args), val, - ARRAY_SIZE(val), DEFAULT_TIMEOUT); - - if (!err) { - v4l2_dbg(1, debug, &sdev->sd, - "%s: status=0x%02x\n", __func__, val[0]); - *frequency = compose_u16(val[2], val[3]); - sdev->frequency = *frequency; - *power = val[5]; - *antcap = val[6]; - *noise = val[7]; - v4l2_dbg(1, debug, &sdev->sd, "%s: response: %d x 10 kHz " - "(power %d, antcap %d, rnl %d)\n", __func__, - *frequency, *power, *antcap, *noise); - } - - return err; -} - -/* - * si4713_tx_rds_buff - Loads the RDS group buffer FIFO or circular buffer. - * @sdev: si4713_device structure for the device we are communicating - * @mode: the buffer operation mode. - * @rdsb: RDS Block B - * @rdsc: RDS Block C - * @rdsd: RDS Block D - * @cbleft: returns the number of available circular buffer blocks minus the - * number of used circular buffer blocks. - */ -static int si4713_tx_rds_buff(struct si4713_device *sdev, u8 mode, u16 rdsb, - u16 rdsc, u16 rdsd, s8 *cbleft) -{ - int err; - u8 val[SI4713_RDSBUFF_NRESP]; - - const u8 args[SI4713_RDSBUFF_NARGS] = { - mode & SI4713_RDSBUFF_MODE_MASK, - msb(rdsb), - lsb(rdsb), - msb(rdsc), - lsb(rdsc), - msb(rdsd), - lsb(rdsd), - }; - - err = si4713_send_command(sdev, SI4713_CMD_TX_RDS_BUFF, - args, ARRAY_SIZE(args), val, - ARRAY_SIZE(val), DEFAULT_TIMEOUT); - - if (!err) { - v4l2_dbg(1, debug, &sdev->sd, - "%s: status=0x%02x\n", __func__, val[0]); - *cbleft = (s8)val[2] - val[3]; - v4l2_dbg(1, debug, &sdev->sd, "%s: response: interrupts" - " 0x%02x cb avail: %d cb used %d fifo avail" - " %d fifo used %d\n", __func__, val[1], - val[2], val[3], val[4], val[5]); - } - - return err; -} - -/* - * si4713_tx_rds_ps - Loads the program service buffer. - * @sdev: si4713_device structure for the device we are communicating - * @psid: program service id to be loaded. - * @pschar: assumed 4 size char array to be loaded into the program service - */ -static int si4713_tx_rds_ps(struct si4713_device *sdev, u8 psid, - unsigned char *pschar) -{ - int err; - u8 val[SI4713_RDSPS_NRESP]; - - const u8 args[SI4713_RDSPS_NARGS] = { - psid & SI4713_RDSPS_PSID_MASK, - pschar[0], - pschar[1], - pschar[2], - pschar[3], - }; - - err = si4713_send_command(sdev, SI4713_CMD_TX_RDS_PS, - args, ARRAY_SIZE(args), val, - ARRAY_SIZE(val), DEFAULT_TIMEOUT); - - if (err < 0) - return err; - - v4l2_dbg(1, debug, &sdev->sd, "%s: status=0x%02x\n", __func__, val[0]); - - return err; -} - -static int si4713_set_power_state(struct si4713_device *sdev, u8 value) -{ - int rval; - - mutex_lock(&sdev->mutex); - - if (value) - rval = si4713_powerup(sdev); - else - rval = si4713_powerdown(sdev); - - mutex_unlock(&sdev->mutex); - return rval; -} - -static int si4713_set_mute(struct si4713_device *sdev, u16 mute) -{ - int rval = 0; - - mute = set_mute(mute); - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) - rval = si4713_write_property(sdev, - SI4713_TX_LINE_INPUT_MUTE, mute); - - if (rval >= 0) - sdev->mute = get_mute(mute); - - mutex_unlock(&sdev->mutex); - - return rval; -} - -static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name) -{ - int rval = 0, i; - u8 len = 0; - - /* We want to clear the whole thing */ - if (!strlen(ps_name)) - memset(ps_name, 0, MAX_RDS_PS_NAME + 1); - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) { - /* Write the new ps name and clear the padding */ - for (i = 0; i < MAX_RDS_PS_NAME; i += (RDS_BLOCK / 2)) { - rval = si4713_tx_rds_ps(sdev, (i / (RDS_BLOCK / 2)), - ps_name + i); - if (rval < 0) - goto unlock; - } - - /* Setup the size to be sent */ - if (strlen(ps_name)) - len = strlen(ps_name) - 1; - else - len = 1; - - rval = si4713_write_property(sdev, - SI4713_TX_RDS_PS_MESSAGE_COUNT, - rds_ps_nblocks(len)); - if (rval < 0) - goto unlock; - - rval = si4713_write_property(sdev, - SI4713_TX_RDS_PS_REPEAT_COUNT, - DEFAULT_RDS_PS_REPEAT_COUNT * 2); - if (rval < 0) - goto unlock; - } - - strncpy(sdev->rds_info.ps_name, ps_name, MAX_RDS_PS_NAME); - -unlock: - mutex_unlock(&sdev->mutex); - return rval; -} - -static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt) -{ - int rval = 0, i; - u16 t_index = 0; - u8 b_index = 0, cr_inserted = 0; - s8 left; - - mutex_lock(&sdev->mutex); - - if (!sdev->power_state) - goto copy; - - rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_CLEAR, 0, 0, 0, &left); - if (rval < 0) - goto unlock; - - if (!strlen(rt)) - goto copy; - - do { - /* RDS spec says that if the last block isn't used, - * then apply a carriage return - */ - if (t_index < (RDS_RADIOTEXT_INDEX_MAX * - RDS_RADIOTEXT_BLK_SIZE)) { - for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) { - if (!rt[t_index + i] || rt[t_index + i] == - RDS_CARRIAGE_RETURN) { - rt[t_index + i] = RDS_CARRIAGE_RETURN; - cr_inserted = 1; - break; - } - } - } - - rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_LOAD, - compose_u16(RDS_RADIOTEXT_2A, b_index++), - compose_u16(rt[t_index], rt[t_index + 1]), - compose_u16(rt[t_index + 2], rt[t_index + 3]), - &left); - if (rval < 0) - goto unlock; - - t_index += RDS_RADIOTEXT_BLK_SIZE; - - if (cr_inserted) - break; - } while (left > 0); - -copy: - strncpy(sdev->rds_info.radio_text, rt, MAX_RDS_RADIO_TEXT); - -unlock: - mutex_unlock(&sdev->mutex); - return rval; -} - -static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id, - u32 **shadow, s32 *bit, s32 *mask, u16 *property, int *mul, - unsigned long **table, int *size) -{ - s32 rval = 0; - - switch (id) { - /* FM_TX class controls */ - case V4L2_CID_RDS_TX_PI: - *property = SI4713_TX_RDS_PI; - *mul = 1; - *shadow = &sdev->rds_info.pi; - break; - case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: - *property = SI4713_TX_ACOMP_THRESHOLD; - *mul = 1; - *shadow = &sdev->acomp_info.threshold; - break; - case V4L2_CID_AUDIO_COMPRESSION_GAIN: - *property = SI4713_TX_ACOMP_GAIN; - *mul = 1; - *shadow = &sdev->acomp_info.gain; - break; - case V4L2_CID_PILOT_TONE_FREQUENCY: - *property = SI4713_TX_PILOT_FREQUENCY; - *mul = 1; - *shadow = &sdev->pilot_info.frequency; - break; - case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: - *property = SI4713_TX_ACOMP_ATTACK_TIME; - *mul = ATTACK_TIME_UNIT; - *shadow = &sdev->acomp_info.attack_time; - break; - case V4L2_CID_PILOT_TONE_DEVIATION: - *property = SI4713_TX_PILOT_DEVIATION; - *mul = 10; - *shadow = &sdev->pilot_info.deviation; - break; - case V4L2_CID_AUDIO_LIMITER_DEVIATION: - *property = SI4713_TX_AUDIO_DEVIATION; - *mul = 10; - *shadow = &sdev->limiter_info.deviation; - break; - case V4L2_CID_RDS_TX_DEVIATION: - *property = SI4713_TX_RDS_DEVIATION; - *mul = 1; - *shadow = &sdev->rds_info.deviation; - break; - - case V4L2_CID_RDS_TX_PTY: - *property = SI4713_TX_RDS_PS_MISC; - *bit = 5; - *mask = 0x1F << 5; - *shadow = &sdev->rds_info.pty; - break; - case V4L2_CID_AUDIO_LIMITER_ENABLED: - *property = SI4713_TX_ACOMP_ENABLE; - *bit = 1; - *mask = 1 << 1; - *shadow = &sdev->limiter_info.enabled; - break; - case V4L2_CID_AUDIO_COMPRESSION_ENABLED: - *property = SI4713_TX_ACOMP_ENABLE; - *bit = 0; - *mask = 1 << 0; - *shadow = &sdev->acomp_info.enabled; - break; - case V4L2_CID_PILOT_TONE_ENABLED: - *property = SI4713_TX_COMPONENT_ENABLE; - *bit = 0; - *mask = 1 << 0; - *shadow = &sdev->pilot_info.enabled; - break; - - case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: - *property = SI4713_TX_LIMITER_RELEASE_TIME; - *table = limiter_times; - *size = ARRAY_SIZE(limiter_times); - *shadow = &sdev->limiter_info.release_time; - break; - case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: - *property = SI4713_TX_ACOMP_RELEASE_TIME; - *table = acomp_rtimes; - *size = ARRAY_SIZE(acomp_rtimes); - *shadow = &sdev->acomp_info.release_time; - break; - case V4L2_CID_TUNE_PREEMPHASIS: - *property = SI4713_TX_PREEMPHASIS; - *table = preemphasis_values; - *size = ARRAY_SIZE(preemphasis_values); - *shadow = &sdev->preemphasis; - break; - - default: - rval = -EINVAL; - }; - - return rval; -} - -static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc); - -/* write string property */ -static int si4713_write_econtrol_string(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - struct v4l2_queryctrl vqc; - int len; - s32 rval = 0; - - vqc.id = control->id; - rval = si4713_queryctrl(&sdev->sd, &vqc); - if (rval < 0) - goto exit; - - switch (control->id) { - case V4L2_CID_RDS_TX_PS_NAME: { - char ps_name[MAX_RDS_PS_NAME + 1]; - - len = control->size - 1; - if (len > MAX_RDS_PS_NAME) { - rval = -ERANGE; - goto exit; - } - rval = copy_from_user(ps_name, control->string, len); - if (rval) { - rval = -EFAULT; - goto exit; - } - ps_name[len] = '\0'; - - if (strlen(ps_name) % vqc.step) { - rval = -ERANGE; - goto exit; - } - - rval = si4713_set_rds_ps_name(sdev, ps_name); - } - break; - - case V4L2_CID_RDS_TX_RADIO_TEXT: { - char radio_text[MAX_RDS_RADIO_TEXT + 1]; - - len = control->size - 1; - if (len > MAX_RDS_RADIO_TEXT) { - rval = -ERANGE; - goto exit; - } - rval = copy_from_user(radio_text, control->string, len); - if (rval) { - rval = -EFAULT; - goto exit; - } - radio_text[len] = '\0'; - - if (strlen(radio_text) % vqc.step) { - rval = -ERANGE; - goto exit; - } - - rval = si4713_set_rds_radio_text(sdev, radio_text); - } - break; - - default: - rval = -EINVAL; - break; - }; - -exit: - return rval; -} - -static int validate_range(struct v4l2_subdev *sd, - struct v4l2_ext_control *control) -{ - struct v4l2_queryctrl vqc; - int rval; - - vqc.id = control->id; - rval = si4713_queryctrl(sd, &vqc); - if (rval < 0) - goto exit; - - if (control->value < vqc.minimum || control->value > vqc.maximum) - rval = -ERANGE; - -exit: - return rval; -} - -/* properties which use tx_tune_power*/ -static int si4713_write_econtrol_tune(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - s32 rval = 0; - u8 power, antcap; - - rval = validate_range(&sdev->sd, control); - if (rval < 0) - goto exit; - - mutex_lock(&sdev->mutex); - - switch (control->id) { - case V4L2_CID_TUNE_POWER_LEVEL: - power = control->value; - antcap = sdev->antenna_capacitor; - break; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - power = sdev->power_level; - antcap = control->value; - break; - default: - rval = -EINVAL; - goto unlock; - }; - - if (sdev->power_state) - rval = si4713_tx_tune_power(sdev, power, antcap); - - if (rval == 0) { - sdev->power_level = power; - sdev->antenna_capacitor = antcap; - } - -unlock: - mutex_unlock(&sdev->mutex); -exit: - return rval; -} - -static int si4713_write_econtrol_integers(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - s32 rval; - u32 *shadow = NULL, val = 0; - s32 bit = 0, mask = 0; - u16 property = 0; - int mul = 0; - unsigned long *table = NULL; - int size = 0; - - rval = validate_range(&sdev->sd, control); - if (rval < 0) - goto exit; - - rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit, - &mask, &property, &mul, &table, &size); - if (rval < 0) - goto exit; - - val = control->value; - if (mul) { - val = control->value / mul; - } else if (table) { - rval = usecs_to_dev(control->value, table, size); - if (rval < 0) - goto exit; - val = rval; - rval = 0; - } - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) { - if (mask) { - rval = si4713_read_property(sdev, property, &val); - if (rval < 0) - goto unlock; - val = set_bits(val, control->value, bit, mask); - } - - rval = si4713_write_property(sdev, property, val); - if (rval < 0) - goto unlock; - if (mask) - val = control->value; - } - - if (mul) { - *shadow = val * mul; - } else if (table) { - rval = dev_to_usecs(val, table, size); - if (rval < 0) - goto unlock; - *shadow = rval; - rval = 0; - } else { - *shadow = val; - } - -unlock: - mutex_unlock(&sdev->mutex); -exit: - return rval; -} - -static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f); -static int si4713_s_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *); -/* - * si4713_setup - Sets the device up with current configuration. - * @sdev: si4713_device structure for the device we are communicating - */ -static int si4713_setup(struct si4713_device *sdev) -{ - struct v4l2_ext_control ctrl; - struct v4l2_frequency f; - struct v4l2_modulator vm; - struct si4713_device *tmp; - int rval = 0; - - tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - /* Get a local copy to avoid race */ - mutex_lock(&sdev->mutex); - memcpy(tmp, sdev, sizeof(*sdev)); - mutex_unlock(&sdev->mutex); - - ctrl.id = V4L2_CID_RDS_TX_PI; - ctrl.value = tmp->rds_info.pi; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_THRESHOLD; - ctrl.value = tmp->acomp_info.threshold; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_GAIN; - ctrl.value = tmp->acomp_info.gain; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_PILOT_TONE_FREQUENCY; - ctrl.value = tmp->pilot_info.frequency; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME; - ctrl.value = tmp->acomp_info.attack_time; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_PILOT_TONE_DEVIATION; - ctrl.value = tmp->pilot_info.deviation; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_LIMITER_DEVIATION; - ctrl.value = tmp->limiter_info.deviation; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_RDS_TX_DEVIATION; - ctrl.value = tmp->rds_info.deviation; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_RDS_TX_PTY; - ctrl.value = tmp->rds_info.pty; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_LIMITER_ENABLED; - ctrl.value = tmp->limiter_info.enabled; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ENABLED; - ctrl.value = tmp->acomp_info.enabled; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_PILOT_TONE_ENABLED; - ctrl.value = tmp->pilot_info.enabled; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_LIMITER_RELEASE_TIME; - ctrl.value = tmp->limiter_info.release_time; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME; - ctrl.value = tmp->acomp_info.release_time; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_TUNE_PREEMPHASIS; - ctrl.value = tmp->preemphasis; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_RDS_TX_PS_NAME; - rval |= si4713_set_rds_ps_name(sdev, tmp->rds_info.ps_name); - - ctrl.id = V4L2_CID_RDS_TX_RADIO_TEXT; - rval |= si4713_set_rds_radio_text(sdev, tmp->rds_info.radio_text); - - /* Device procedure needs to set frequency first */ - f.frequency = tmp->frequency ? tmp->frequency : DEFAULT_FREQUENCY; - f.frequency = si4713_to_v4l2(f.frequency); - rval |= si4713_s_frequency(&sdev->sd, &f); - - ctrl.id = V4L2_CID_TUNE_POWER_LEVEL; - ctrl.value = tmp->power_level; - rval |= si4713_write_econtrol_tune(sdev, &ctrl); - - ctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR; - ctrl.value = tmp->antenna_capacitor; - rval |= si4713_write_econtrol_tune(sdev, &ctrl); - - vm.index = 0; - if (tmp->stereo) - vm.txsubchans = V4L2_TUNER_SUB_STEREO; - else - vm.txsubchans = V4L2_TUNER_SUB_MONO; - if (tmp->rds_info.enabled) - vm.txsubchans |= V4L2_TUNER_SUB_RDS; - si4713_s_modulator(&sdev->sd, &vm); - - kfree(tmp); - - return rval; -} - -/* - * si4713_initialize - Sets the device up with default configuration. - * @sdev: si4713_device structure for the device we are communicating - */ -static int si4713_initialize(struct si4713_device *sdev) -{ - int rval; - - rval = si4713_set_power_state(sdev, POWER_ON); - if (rval < 0) - goto exit; - - rval = si4713_checkrev(sdev); - if (rval < 0) - goto exit; - - rval = si4713_set_power_state(sdev, POWER_OFF); - if (rval < 0) - goto exit; - - mutex_lock(&sdev->mutex); - - sdev->rds_info.pi = DEFAULT_RDS_PI; - sdev->rds_info.pty = DEFAULT_RDS_PTY; - sdev->rds_info.deviation = DEFAULT_RDS_DEVIATION; - strlcpy(sdev->rds_info.ps_name, DEFAULT_RDS_PS_NAME, MAX_RDS_PS_NAME); - strlcpy(sdev->rds_info.radio_text, DEFAULT_RDS_RADIO_TEXT, - MAX_RDS_RADIO_TEXT); - sdev->rds_info.enabled = 1; - - sdev->limiter_info.release_time = DEFAULT_LIMITER_RTIME; - sdev->limiter_info.deviation = DEFAULT_LIMITER_DEV; - sdev->limiter_info.enabled = 1; - - sdev->pilot_info.deviation = DEFAULT_PILOT_DEVIATION; - sdev->pilot_info.frequency = DEFAULT_PILOT_FREQUENCY; - sdev->pilot_info.enabled = 1; - - sdev->acomp_info.release_time = DEFAULT_ACOMP_RTIME; - sdev->acomp_info.attack_time = DEFAULT_ACOMP_ATIME; - sdev->acomp_info.threshold = DEFAULT_ACOMP_THRESHOLD; - sdev->acomp_info.gain = DEFAULT_ACOMP_GAIN; - sdev->acomp_info.enabled = 1; - - sdev->frequency = DEFAULT_FREQUENCY; - sdev->preemphasis = DEFAULT_PREEMPHASIS; - sdev->mute = DEFAULT_MUTE; - sdev->power_level = DEFAULT_POWER_LEVEL; - sdev->antenna_capacitor = 0; - sdev->stereo = 1; - sdev->tune_rnl = DEFAULT_TUNE_RNL; - - mutex_unlock(&sdev->mutex); - -exit: - return rval; -} - -/* read string property */ -static int si4713_read_econtrol_string(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - s32 rval = 0; - - switch (control->id) { - case V4L2_CID_RDS_TX_PS_NAME: - if (strlen(sdev->rds_info.ps_name) + 1 > control->size) { - control->size = MAX_RDS_PS_NAME + 1; - rval = -ENOSPC; - goto exit; - } - rval = copy_to_user(control->string, sdev->rds_info.ps_name, - strlen(sdev->rds_info.ps_name) + 1); - if (rval) - rval = -EFAULT; - break; - - case V4L2_CID_RDS_TX_RADIO_TEXT: - if (strlen(sdev->rds_info.radio_text) + 1 > control->size) { - control->size = MAX_RDS_RADIO_TEXT + 1; - rval = -ENOSPC; - goto exit; - } - rval = copy_to_user(control->string, sdev->rds_info.radio_text, - strlen(sdev->rds_info.radio_text) + 1); - if (rval) - rval = -EFAULT; - break; - - default: - rval = -EINVAL; - break; - }; - -exit: - return rval; -} - -/* - * si4713_update_tune_status - update properties from tx_tune_status - * command. Must be called with sdev->mutex held. - * @sdev: si4713_device structure for the device we are communicating - */ -static int si4713_update_tune_status(struct si4713_device *sdev) -{ - int rval; - u16 f = 0; - u8 p = 0, a = 0, n = 0; - - rval = si4713_tx_tune_status(sdev, 0x00, &f, &p, &a, &n); - - if (rval < 0) - goto exit; - - sdev->power_level = p; - sdev->antenna_capacitor = a; - sdev->tune_rnl = n; - -exit: - return rval; -} - -/* properties which use tx_tune_status */ -static int si4713_read_econtrol_tune(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - s32 rval = 0; - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) { - rval = si4713_update_tune_status(sdev); - if (rval < 0) - goto unlock; - } - - switch (control->id) { - case V4L2_CID_TUNE_POWER_LEVEL: - control->value = sdev->power_level; - break; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - control->value = sdev->antenna_capacitor; - break; - default: - rval = -EINVAL; - }; - -unlock: - mutex_unlock(&sdev->mutex); - return rval; -} - -static int si4713_read_econtrol_integers(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - s32 rval; - u32 *shadow = NULL, val = 0; - s32 bit = 0, mask = 0; - u16 property = 0; - int mul = 0; - unsigned long *table = NULL; - int size = 0; - - rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit, - &mask, &property, &mul, &table, &size); - if (rval < 0) - goto exit; - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) { - rval = si4713_read_property(sdev, property, &val); - if (rval < 0) - goto unlock; - - /* Keep negative values for threshold */ - if (control->id == V4L2_CID_AUDIO_COMPRESSION_THRESHOLD) - *shadow = (s16)val; - else if (mask) - *shadow = get_status_bit(val, bit, mask); - else if (mul) - *shadow = val * mul; - else - *shadow = dev_to_usecs(val, table, size); - } - - control->value = *shadow; - -unlock: - mutex_unlock(&sdev->mutex); -exit: - return rval; -} - -/* - * Video4Linux Subdev Interface - */ -/* si4713_s_ext_ctrls - set extended controls value */ -static int si4713_s_ext_ctrls(struct v4l2_subdev *sd, - struct v4l2_ext_controls *ctrls) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) - return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - int err; - - switch ((ctrls->controls + i)->id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - err = si4713_write_econtrol_string(sdev, - ctrls->controls + i); - break; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - case V4L2_CID_TUNE_POWER_LEVEL: - err = si4713_write_econtrol_tune(sdev, - ctrls->controls + i); - break; - default: - err = si4713_write_econtrol_integers(sdev, - ctrls->controls + i); - } - - if (err < 0) { - ctrls->error_idx = i; - return err; - } - } - - return 0; -} - -/* si4713_g_ext_ctrls - get extended controls value */ -static int si4713_g_ext_ctrls(struct v4l2_subdev *sd, - struct v4l2_ext_controls *ctrls) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) - return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - int err; - - switch ((ctrls->controls + i)->id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - err = si4713_read_econtrol_string(sdev, - ctrls->controls + i); - break; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - case V4L2_CID_TUNE_POWER_LEVEL: - err = si4713_read_econtrol_tune(sdev, - ctrls->controls + i); - break; - default: - err = si4713_read_econtrol_integers(sdev, - ctrls->controls + i); - } - - if (err < 0) { - ctrls->error_idx = i; - return err; - } - } - - return 0; -} - -/* si4713_queryctrl - enumerate control items */ -static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - int rval = 0; - - switch (qc->id) { - /* User class controls */ - case V4L2_CID_AUDIO_MUTE: - rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, DEFAULT_MUTE); - break; - /* FM_TX class controls */ - case V4L2_CID_RDS_TX_PI: - rval = v4l2_ctrl_query_fill(qc, 0, 0xFFFF, 1, DEFAULT_RDS_PI); - break; - case V4L2_CID_RDS_TX_PTY: - rval = v4l2_ctrl_query_fill(qc, 0, 31, 1, DEFAULT_RDS_PTY); - break; - case V4L2_CID_RDS_TX_DEVIATION: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_DEVIATION, - 10, DEFAULT_RDS_DEVIATION); - break; - case V4L2_CID_RDS_TX_PS_NAME: - /* - * Report step as 8. From RDS spec, psname - * should be 8. But there are receivers which scroll strings - * sized as 8xN. - */ - rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_PS_NAME, 8, 0); - break; - case V4L2_CID_RDS_TX_RADIO_TEXT: - /* - * Report step as 32 (2A block). From RDS spec, - * radio text should be 32 for 2A block. But there are receivers - * which scroll strings sized as 32xN. Setting default to 32. - */ - rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_RADIO_TEXT, 32, 0); - break; - - case V4L2_CID_AUDIO_LIMITER_ENABLED: - rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - break; - case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: - rval = v4l2_ctrl_query_fill(qc, 250, MAX_LIMITER_RELEASE_TIME, - 50, DEFAULT_LIMITER_RTIME); - break; - case V4L2_CID_AUDIO_LIMITER_DEVIATION: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_LIMITER_DEVIATION, - 10, DEFAULT_LIMITER_DEV); - break; - - case V4L2_CID_AUDIO_COMPRESSION_ENABLED: - rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - break; - case V4L2_CID_AUDIO_COMPRESSION_GAIN: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_GAIN, 1, - DEFAULT_ACOMP_GAIN); - break; - case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: - rval = v4l2_ctrl_query_fill(qc, MIN_ACOMP_THRESHOLD, - MAX_ACOMP_THRESHOLD, 1, - DEFAULT_ACOMP_THRESHOLD); - break; - case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_ATTACK_TIME, - 500, DEFAULT_ACOMP_ATIME); - break; - case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: - rval = v4l2_ctrl_query_fill(qc, 100000, MAX_ACOMP_RELEASE_TIME, - 100000, DEFAULT_ACOMP_RTIME); - break; - - case V4L2_CID_PILOT_TONE_ENABLED: - rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - break; - case V4L2_CID_PILOT_TONE_DEVIATION: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_DEVIATION, - 10, DEFAULT_PILOT_DEVIATION); - break; - case V4L2_CID_PILOT_TONE_FREQUENCY: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_FREQUENCY, - 1, DEFAULT_PILOT_FREQUENCY); - break; - - case V4L2_CID_TUNE_PREEMPHASIS: - rval = v4l2_ctrl_query_fill(qc, V4L2_PREEMPHASIS_DISABLED, - V4L2_PREEMPHASIS_75_uS, 1, - V4L2_PREEMPHASIS_50_uS); - break; - case V4L2_CID_TUNE_POWER_LEVEL: - rval = v4l2_ctrl_query_fill(qc, 0, 120, 1, DEFAULT_POWER_LEVEL); - break; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - rval = v4l2_ctrl_query_fill(qc, 0, 191, 1, 0); - break; - default: - rval = -EINVAL; - break; - }; - - return rval; -} - -/* si4713_g_ctrl - get the value of a control */ -static int si4713_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int rval = 0; - - if (!sdev) - return -ENODEV; - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) { - rval = si4713_read_property(sdev, SI4713_TX_LINE_INPUT_MUTE, - &sdev->mute); - - if (rval < 0) - goto unlock; - } - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = get_mute(sdev->mute); - break; - } - -unlock: - mutex_unlock(&sdev->mutex); - return rval; -} - -/* si4713_s_ctrl - set the value of a control */ -static int si4713_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int rval = 0; - - if (!sdev) - return -ENODEV; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) { - rval = si4713_set_mute(sdev, ctrl->value); - if (rval < 0) - goto exit; - - rval = si4713_set_power_state(sdev, POWER_DOWN); - } else { - rval = si4713_set_power_state(sdev, POWER_UP); - if (rval < 0) - goto exit; - - rval = si4713_setup(sdev); - if (rval < 0) - goto exit; - - rval = si4713_set_mute(sdev, ctrl->value); - } - break; - } - -exit: - return rval; -} - -/* si4713_ioctl - deal with private ioctls (only rnl for now) */ -long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct si4713_device *sdev = to_si4713_device(sd); - struct si4713_rnl *rnl = arg; - u16 frequency; - int rval = 0; - - if (!arg) - return -EINVAL; - - mutex_lock(&sdev->mutex); - switch (cmd) { - case SI4713_IOC_MEASURE_RNL: - frequency = v4l2_to_si4713(rnl->frequency); - - if (sdev->power_state) { - /* Set desired measurement frequency */ - rval = si4713_tx_tune_measure(sdev, frequency, 0); - if (rval < 0) - goto unlock; - /* get results from tune status */ - rval = si4713_update_tune_status(sdev); - if (rval < 0) - goto unlock; - } - rnl->rnl = sdev->tune_rnl; - break; - - default: - /* nothing */ - rval = -ENOIOCTLCMD; - } - -unlock: - mutex_unlock(&sdev->mutex); - return rval; -} - -static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = { - .queryctrl = si4713_queryctrl, - .g_ext_ctrls = si4713_g_ext_ctrls, - .s_ext_ctrls = si4713_s_ext_ctrls, - .g_ctrl = si4713_g_ctrl, - .s_ctrl = si4713_s_ctrl, - .ioctl = si4713_ioctl, -}; - -/* si4713_g_modulator - get modulator attributes */ -static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int rval = 0; - - if (!sdev) { - rval = -ENODEV; - goto exit; - } - - if (vm->index > 0) { - rval = -EINVAL; - goto exit; - } - - strncpy(vm->name, "FM Modulator", 32); - vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW | - V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS; - - /* Report current frequency range limits */ - vm->rangelow = si4713_to_v4l2(FREQ_RANGE_LOW); - vm->rangehigh = si4713_to_v4l2(FREQ_RANGE_HIGH); - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) { - u32 comp_en = 0; - - rval = si4713_read_property(sdev, SI4713_TX_COMPONENT_ENABLE, - &comp_en); - if (rval < 0) - goto unlock; - - sdev->stereo = get_status_bit(comp_en, 1, 1 << 1); - sdev->rds_info.enabled = get_status_bit(comp_en, 2, 1 << 2); - } - - /* Report current audio mode: mono or stereo */ - if (sdev->stereo) - vm->txsubchans = V4L2_TUNER_SUB_STEREO; - else - vm->txsubchans = V4L2_TUNER_SUB_MONO; - - /* Report rds feature status */ - if (sdev->rds_info.enabled) - vm->txsubchans |= V4L2_TUNER_SUB_RDS; - else - vm->txsubchans &= ~V4L2_TUNER_SUB_RDS; - -unlock: - mutex_unlock(&sdev->mutex); -exit: - return rval; -} - -/* si4713_s_modulator - set modulator attributes */ -static int si4713_s_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int rval = 0; - u16 stereo, rds; - u32 p; - - if (!sdev) - return -ENODEV; - - if (vm->index > 0) - return -EINVAL; - - /* Set audio mode: mono or stereo */ - if (vm->txsubchans & V4L2_TUNER_SUB_STEREO) - stereo = 1; - else if (vm->txsubchans & V4L2_TUNER_SUB_MONO) - stereo = 0; - else - return -EINVAL; - - rds = !!(vm->txsubchans & V4L2_TUNER_SUB_RDS); - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) { - rval = si4713_read_property(sdev, - SI4713_TX_COMPONENT_ENABLE, &p); - if (rval < 0) - goto unlock; - - p = set_bits(p, stereo, 1, 1 << 1); - p = set_bits(p, rds, 2, 1 << 2); - - rval = si4713_write_property(sdev, - SI4713_TX_COMPONENT_ENABLE, p); - if (rval < 0) - goto unlock; - } - - sdev->stereo = stereo; - sdev->rds_info.enabled = rds; - -unlock: - mutex_unlock(&sdev->mutex); - return rval; -} - -/* si4713_g_frequency - get tuner or modulator radio frequency */ -static int si4713_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int rval = 0; - - f->type = V4L2_TUNER_RADIO; - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) { - u16 freq; - u8 p, a, n; - - rval = si4713_tx_tune_status(sdev, 0x00, &freq, &p, &a, &n); - if (rval < 0) - goto unlock; - - sdev->frequency = freq; - } - - f->frequency = si4713_to_v4l2(sdev->frequency); - -unlock: - mutex_unlock(&sdev->mutex); - return rval; -} - -/* si4713_s_frequency - set tuner or modulator radio frequency */ -static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int rval = 0; - u16 frequency = v4l2_to_si4713(f->frequency); - - /* Check frequency range */ - if (frequency < FREQ_RANGE_LOW || frequency > FREQ_RANGE_HIGH) - return -EDOM; - - mutex_lock(&sdev->mutex); - - if (sdev->power_state) { - rval = si4713_tx_tune_freq(sdev, frequency); - if (rval < 0) - goto unlock; - frequency = rval; - rval = 0; - } - sdev->frequency = frequency; - f->frequency = si4713_to_v4l2(frequency); - -unlock: - mutex_unlock(&sdev->mutex); - return rval; -} - -static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = { - .g_frequency = si4713_g_frequency, - .s_frequency = si4713_s_frequency, - .g_modulator = si4713_g_modulator, - .s_modulator = si4713_s_modulator, -}; - -static const struct v4l2_subdev_ops si4713_subdev_ops = { - .core = &si4713_subdev_core_ops, - .tuner = &si4713_subdev_tuner_ops, -}; - -/* - * I2C driver interface - */ -/* si4713_probe - probe for the device */ -static int si4713_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct si4713_device *sdev; - struct si4713_platform_data *pdata = client->dev.platform_data; - int rval, i; - - sdev = kzalloc(sizeof *sdev, GFP_KERNEL); - if (!sdev) { - dev_err(&client->dev, "Failed to alloc video device.\n"); - rval = -ENOMEM; - goto exit; - } - - sdev->gpio_reset = -1; - if (pdata && gpio_is_valid(pdata->gpio_reset)) { - rval = gpio_request(pdata->gpio_reset, "si4713 reset"); - if (rval) { - dev_err(&client->dev, - "Failed to request gpio: %d\n", rval); - goto free_sdev; - } - sdev->gpio_reset = pdata->gpio_reset; - gpio_direction_output(sdev->gpio_reset, 0); - } - - for (i = 0; i < ARRAY_SIZE(sdev->supplies); i++) - sdev->supplies[i].supply = si4713_supply_names[i]; - - rval = regulator_bulk_get(&client->dev, ARRAY_SIZE(sdev->supplies), - sdev->supplies); - if (rval) { - dev_err(&client->dev, "Cannot get regulators: %d\n", rval); - goto free_gpio; - } - - v4l2_i2c_subdev_init(&sdev->sd, client, &si4713_subdev_ops); - - mutex_init(&sdev->mutex); - init_completion(&sdev->work); - - if (client->irq) { - rval = request_irq(client->irq, - si4713_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, - client->name, sdev); - if (rval < 0) { - v4l2_err(&sdev->sd, "Could not request IRQ\n"); - goto put_reg; - } - v4l2_dbg(1, debug, &sdev->sd, "IRQ requested.\n"); - } else { - v4l2_warn(&sdev->sd, "IRQ not configured. Using timeouts.\n"); - } - - rval = si4713_initialize(sdev); - if (rval < 0) { - v4l2_err(&sdev->sd, "Failed to probe device information.\n"); - goto free_irq; - } - - return 0; - -free_irq: - if (client->irq) - free_irq(client->irq, sdev); -put_reg: - regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies); -free_gpio: - if (gpio_is_valid(sdev->gpio_reset)) - gpio_free(sdev->gpio_reset); -free_sdev: - kfree(sdev); -exit: - return rval; -} - -/* si4713_remove - remove the device */ -static int si4713_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct si4713_device *sdev = to_si4713_device(sd); - - if (sdev->power_state) - si4713_set_power_state(sdev, POWER_DOWN); - - if (client->irq > 0) - free_irq(client->irq, sdev); - - v4l2_device_unregister_subdev(sd); - regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies); - if (gpio_is_valid(sdev->gpio_reset)) - gpio_free(sdev->gpio_reset); - kfree(sdev); - - return 0; -} - -/* si4713_i2c_driver - i2c driver interface */ -static const struct i2c_device_id si4713_id[] = { - { "si4713" , 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, si4713_id); - -static struct i2c_driver si4713_i2c_driver = { - .driver = { - .name = "si4713", - }, - .probe = si4713_probe, - .remove = si4713_remove, - .id_table = si4713_id, -}; - -/* Module Interface */ -static int __init si4713_module_init(void) -{ - return i2c_add_driver(&si4713_i2c_driver); -} - -static void __exit si4713_module_exit(void) -{ - i2c_del_driver(&si4713_i2c_driver); -} - -module_init(si4713_module_init); -module_exit(si4713_module_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si4713-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si4713-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si4713-i2c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/si4713-i2c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,240 +0,0 @@ -/* - * drivers/media/radio/si4713-i2c.h - * - * Property and commands definitions for Si4713 radio transmitter chip. - * - * Copyright (c) 2008 Instituto Nokia de Tecnologia - INdT - * Contact: Eduardo Valentin - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - */ - -#ifndef SI4713_I2C_H -#define SI4713_I2C_H - -#include -#include - -#define SI4713_PRODUCT_NUMBER 0x0D - -/* Command Timeouts */ -#define DEFAULT_TIMEOUT 500 -#define TIMEOUT_SET_PROPERTY 20 -#define TIMEOUT_TX_TUNE_POWER 30000 -#define TIMEOUT_TX_TUNE 110000 -#define TIMEOUT_POWER_UP 200000 - -/* - * Command and its arguments definitions - */ -#define SI4713_PWUP_CTSIEN (1<<7) -#define SI4713_PWUP_GPO2OEN (1<<6) -#define SI4713_PWUP_PATCH (1<<5) -#define SI4713_PWUP_XOSCEN (1<<4) -#define SI4713_PWUP_FUNC_TX 0x02 -#define SI4713_PWUP_FUNC_PATCH 0x0F -#define SI4713_PWUP_OPMOD_ANALOG 0x50 -#define SI4713_PWUP_OPMOD_DIGITAL 0x0F -#define SI4713_PWUP_NARGS 2 -#define SI4713_PWUP_NRESP 1 -#define SI4713_CMD_POWER_UP 0x01 - -#define SI4713_GETREV_NRESP 9 -#define SI4713_CMD_GET_REV 0x10 - -#define SI4713_PWDN_NRESP 1 -#define SI4713_CMD_POWER_DOWN 0x11 - -#define SI4713_SET_PROP_NARGS 5 -#define SI4713_SET_PROP_NRESP 1 -#define SI4713_CMD_SET_PROPERTY 0x12 - -#define SI4713_GET_PROP_NARGS 3 -#define SI4713_GET_PROP_NRESP 4 -#define SI4713_CMD_GET_PROPERTY 0x13 - -#define SI4713_GET_STATUS_NRESP 1 -#define SI4713_CMD_GET_INT_STATUS 0x14 - -#define SI4713_CMD_PATCH_ARGS 0x15 -#define SI4713_CMD_PATCH_DATA 0x16 - -#define SI4713_MAX_FREQ 10800 -#define SI4713_MIN_FREQ 7600 -#define SI4713_TXFREQ_NARGS 3 -#define SI4713_TXFREQ_NRESP 1 -#define SI4713_CMD_TX_TUNE_FREQ 0x30 - -#define SI4713_MAX_POWER 120 -#define SI4713_MIN_POWER 88 -#define SI4713_MAX_ANTCAP 191 -#define SI4713_MIN_ANTCAP 0 -#define SI4713_TXPWR_NARGS 4 -#define SI4713_TXPWR_NRESP 1 -#define SI4713_CMD_TX_TUNE_POWER 0x31 - -#define SI4713_TXMEA_NARGS 4 -#define SI4713_TXMEA_NRESP 1 -#define SI4713_CMD_TX_TUNE_MEASURE 0x32 - -#define SI4713_INTACK_MASK 0x01 -#define SI4713_TXSTATUS_NARGS 1 -#define SI4713_TXSTATUS_NRESP 8 -#define SI4713_CMD_TX_TUNE_STATUS 0x33 - -#define SI4713_OVERMOD_BIT (1 << 2) -#define SI4713_IALH_BIT (1 << 1) -#define SI4713_IALL_BIT (1 << 0) -#define SI4713_ASQSTATUS_NARGS 1 -#define SI4713_ASQSTATUS_NRESP 5 -#define SI4713_CMD_TX_ASQ_STATUS 0x34 - -#define SI4713_RDSBUFF_MODE_MASK 0x87 -#define SI4713_RDSBUFF_NARGS 7 -#define SI4713_RDSBUFF_NRESP 6 -#define SI4713_CMD_TX_RDS_BUFF 0x35 - -#define SI4713_RDSPS_PSID_MASK 0x1F -#define SI4713_RDSPS_NARGS 5 -#define SI4713_RDSPS_NRESP 1 -#define SI4713_CMD_TX_RDS_PS 0x36 - -#define SI4713_CMD_GPO_CTL 0x80 -#define SI4713_CMD_GPO_SET 0x81 - -/* - * Bits from status response - */ -#define SI4713_CTS (1<<7) -#define SI4713_ERR (1<<6) -#define SI4713_RDS_INT (1<<2) -#define SI4713_ASQ_INT (1<<1) -#define SI4713_STC_INT (1<<0) - -/* - * Property definitions - */ -#define SI4713_GPO_IEN 0x0001 -#define SI4713_DIG_INPUT_FORMAT 0x0101 -#define SI4713_DIG_INPUT_SAMPLE_RATE 0x0103 -#define SI4713_REFCLK_FREQ 0x0201 -#define SI4713_REFCLK_PRESCALE 0x0202 -#define SI4713_TX_COMPONENT_ENABLE 0x2100 -#define SI4713_TX_AUDIO_DEVIATION 0x2101 -#define SI4713_TX_PILOT_DEVIATION 0x2102 -#define SI4713_TX_RDS_DEVIATION 0x2103 -#define SI4713_TX_LINE_INPUT_LEVEL 0x2104 -#define SI4713_TX_LINE_INPUT_MUTE 0x2105 -#define SI4713_TX_PREEMPHASIS 0x2106 -#define SI4713_TX_PILOT_FREQUENCY 0x2107 -#define SI4713_TX_ACOMP_ENABLE 0x2200 -#define SI4713_TX_ACOMP_THRESHOLD 0x2201 -#define SI4713_TX_ACOMP_ATTACK_TIME 0x2202 -#define SI4713_TX_ACOMP_RELEASE_TIME 0x2203 -#define SI4713_TX_ACOMP_GAIN 0x2204 -#define SI4713_TX_LIMITER_RELEASE_TIME 0x2205 -#define SI4713_TX_ASQ_INTERRUPT_SOURCE 0x2300 -#define SI4713_TX_ASQ_LEVEL_LOW 0x2301 -#define SI4713_TX_ASQ_DURATION_LOW 0x2302 -#define SI4713_TX_ASQ_LEVEL_HIGH 0x2303 -#define SI4713_TX_ASQ_DURATION_HIGH 0x2304 -#define SI4713_TX_RDS_INTERRUPT_SOURCE 0x2C00 -#define SI4713_TX_RDS_PI 0x2C01 -#define SI4713_TX_RDS_PS_MIX 0x2C02 -#define SI4713_TX_RDS_PS_MISC 0x2C03 -#define SI4713_TX_RDS_PS_REPEAT_COUNT 0x2C04 -#define SI4713_TX_RDS_PS_MESSAGE_COUNT 0x2C05 -#define SI4713_TX_RDS_PS_AF 0x2C06 -#define SI4713_TX_RDS_FIFO_SIZE 0x2C07 - -#define PREEMPHASIS_USA 75 -#define PREEMPHASIS_EU 50 -#define PREEMPHASIS_DISABLED 0 -#define FMPE_USA 0x00 -#define FMPE_EU 0x01 -#define FMPE_DISABLED 0x02 - -#define POWER_UP 0x01 -#define POWER_DOWN 0x00 - -struct rds_info { - u32 pi; -#define MAX_RDS_PTY 31 - u32 pty; -#define MAX_RDS_DEVIATION 90000 - u32 deviation; -/* - * PSNAME is known to be defined as 8 character sized (RDS Spec). - * However, there is receivers which scroll PSNAME 8xN sized. - */ -#define MAX_RDS_PS_NAME 96 - u8 ps_name[MAX_RDS_PS_NAME + 1]; -/* - * MAX_RDS_RADIO_TEXT is known to be defined as 32 (2A group) or 64 (2B group) - * character sized (RDS Spec). - * However, there is receivers which scroll them as well. - */ -#define MAX_RDS_RADIO_TEXT 384 - u8 radio_text[MAX_RDS_RADIO_TEXT + 1]; - u32 enabled; -}; - -struct limiter_info { -#define MAX_LIMITER_RELEASE_TIME 102390 - u32 release_time; -#define MAX_LIMITER_DEVIATION 90000 - u32 deviation; - u32 enabled; -}; - -struct pilot_info { -#define MAX_PILOT_DEVIATION 90000 - u32 deviation; -#define MAX_PILOT_FREQUENCY 19000 - u32 frequency; - u32 enabled; -}; - -struct acomp_info { -#define MAX_ACOMP_RELEASE_TIME 1000000 - u32 release_time; -#define MAX_ACOMP_ATTACK_TIME 5000 - u32 attack_time; -#define MAX_ACOMP_THRESHOLD 0 -#define MIN_ACOMP_THRESHOLD (-40) - s32 threshold; -#define MAX_ACOMP_GAIN 20 - u32 gain; - u32 enabled; -}; - -#define SI4713_NUM_SUPPLIES 2 - -/* - * si4713_device - private data - */ -struct si4713_device { - /* v4l2_subdev and i2c reference (v4l2_subdev priv data) */ - struct v4l2_subdev sd; - /* private data structures */ - struct mutex mutex; - struct completion work; - struct rds_info rds_info; - struct limiter_info limiter_info; - struct pilot_info pilot_info; - struct acomp_info acomp_info; - struct regulator_bulk_data supplies[SI4713_NUM_SUPPLIES]; - int gpio_reset; - u32 frequency; - u32 preemphasis; - u32 mute; - u32 power_level; - u32 power_state; - u32 antenna_capacitor; - u32 stereo; - u32 tune_rnl; -}; -#endif /* ifndef SI4713_I2C_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/tef6862.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/tef6862.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/tef6862.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/tef6862.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,232 +0,0 @@ -/* - * tef6862.c Philips TEF6862 Car Radio Enhanced Selectivity Tuner - * Copyright (c) 2009 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "tef6862" - -#define FREQ_MUL 16000 - -#define TEF6862_LO_FREQ (875 * FREQ_MUL / 10) -#define TEF6862_HI_FREQ (108 * FREQ_MUL) - -/* Write mode sub addresses */ -#define WM_SUB_BANDWIDTH 0x0 -#define WM_SUB_PLLM 0x1 -#define WM_SUB_PLLL 0x2 -#define WM_SUB_DAA 0x3 -#define WM_SUB_AGC 0x4 -#define WM_SUB_BAND 0x5 -#define WM_SUB_CONTROL 0x6 -#define WM_SUB_LEVEL 0x7 -#define WM_SUB_IFCF 0x8 -#define WM_SUB_IFCAP 0x9 -#define WM_SUB_ACD 0xA -#define WM_SUB_TEST 0xF - -/* Different modes of the MSA register */ -#define MODE_BUFFER 0x0 -#define MODE_PRESET 0x1 -#define MODE_SEARCH 0x2 -#define MODE_AF_UPDATE 0x3 -#define MODE_JUMP 0x4 -#define MODE_CHECK 0x5 -#define MODE_LOAD 0x6 -#define MODE_END 0x7 -#define MODE_SHIFT 5 - -struct tef6862_state { - struct v4l2_subdev sd; - unsigned long freq; -}; - -static inline struct tef6862_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct tef6862_state, sd); -} - -static u16 tef6862_sigstr(struct i2c_client *client) -{ - u8 buf[4]; - int err = i2c_master_recv(client, buf, sizeof(buf)); - if (err == sizeof(buf)) - return buf[3] << 8; - return 0; -} - -static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - - /* only support FM for now */ - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = TEF6862_LO_FREQ; - v->rangehigh = TEF6862_HI_FREQ; - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_STEREO; - v->signal = tef6862_sigstr(v4l2_get_subdevdata(sd)); - - return 0; -} - -static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) -{ - struct tef6862_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 pll; - u8 i2cmsg[3]; - int err; - - if (f->tuner != 0) - return -EINVAL; - - pll = 1964 + ((f->frequency - TEF6862_LO_FREQ) * 20) / FREQ_MUL; - i2cmsg[0] = (MODE_PRESET << MODE_SHIFT) | WM_SUB_PLLM; - i2cmsg[1] = (pll >> 8) & 0xff; - i2cmsg[2] = pll & 0xff; - - err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg)); - if (!err) - state->freq = f->frequency; - return err; -} - -static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) -{ - struct tef6862_state *state = to_state(sd); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = state->freq; - return 0; -} - -static int tef6862_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEF6862, 0); -} - -static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = { - .g_tuner = tef6862_g_tuner, - .s_tuner = tef6862_s_tuner, - .s_frequency = tef6862_s_frequency, - .g_frequency = tef6862_g_frequency, -}; - -static const struct v4l2_subdev_core_ops tef6862_core_ops = { - .g_chip_ident = tef6862_g_chip_ident, -}; - -static const struct v4l2_subdev_ops tef6862_ops = { - .core = &tef6862_core_ops, - .tuner = &tef6862_tuner_ops, -}; - -/* - * Generic i2c probe - * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' - */ - -static int __devinit tef6862_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tef6862_state *state; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kmalloc(sizeof(struct tef6862_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - state->freq = TEF6862_LO_FREQ; - - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &tef6862_ops); - - return 0; -} - -static int __devexit tef6862_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id tef6862_id[] = { - {DRIVER_NAME, 0}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, tef6862_id); - -static struct i2c_driver tef6862_driver = { - .driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - }, - .probe = tef6862_probe, - .remove = tef6862_remove, - .id_table = tef6862_id, -}; - -static __init int tef6862_init(void) -{ - return i2c_add_driver(&tef6862_driver); -} - -static __exit void tef6862_exit(void) -{ - i2c_del_driver(&tef6862_driver); -} - -module_init(tef6862_init); -module_exit(tef6862_exit); - -MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner"); -MODULE_AUTHOR("Mocean Laboratories"); -MODULE_LICENSE("GPL v2"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_common.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1676 +0,0 @@ -/* - * FM Driver for Connectivity chip of Texas Instruments. - * - * This sub-module of FM driver is common for FM RX and TX - * functionality. This module is responsible for: - * 1) Forming group of Channel-8 commands to perform particular - * functionality (eg., frequency set require more than - * one Channel-8 command to be sent to the chip). - * 2) Sending each Channel-8 command to the chip and reading - * response back over Shared Transport. - * 3) Managing TX and RX Queues and Tasklets. - * 4) Handling FM Interrupt packet and taking appropriate action. - * 5) Loading FM firmware to the chip (common, FM TX, and FM RX - * firmware files based on mode selection) - * - * Copyright (C) 2011 Texas Instruments - * Author: Raja Mani - * Author: Manjunatha Halli - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include "fmdrv.h" -#include "fmdrv_v4l2.h" -#include "fmdrv_common.h" -#include -#include "fmdrv_rx.h" -#include "fmdrv_tx.h" - -/* Region info */ -static struct region_info region_configs[] = { - /* Europe/US */ - { - .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, - .bot_freq = 87500, /* 87.5 MHz */ - .top_freq = 108000, /* 108 MHz */ - .fm_band = 0, - }, - /* Japan */ - { - .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, - .bot_freq = 76000, /* 76 MHz */ - .top_freq = 90000, /* 90 MHz */ - .fm_band = 1, - }, -}; - -/* Band selection */ -static u8 default_radio_region; /* Europe/US */ -module_param(default_radio_region, byte, 0); -MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan"); - -/* RDS buffer blocks */ -static u32 default_rds_buf = 300; -module_param(default_rds_buf, uint, 0444); -MODULE_PARM_DESC(rds_buf, "RDS buffer entries"); - -/* Radio Nr */ -static u32 radio_nr = -1; -module_param(radio_nr, int, 0444); -MODULE_PARM_DESC(radio_nr, "Radio Nr"); - -/* FM irq handlers forward declaration */ -static void fm_irq_send_flag_getcmd(struct fmdev *); -static void fm_irq_handle_flag_getcmd_resp(struct fmdev *); -static void fm_irq_handle_hw_malfunction(struct fmdev *); -static void fm_irq_handle_rds_start(struct fmdev *); -static void fm_irq_send_rdsdata_getcmd(struct fmdev *); -static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *); -static void fm_irq_handle_rds_finish(struct fmdev *); -static void fm_irq_handle_tune_op_ended(struct fmdev *); -static void fm_irq_handle_power_enb(struct fmdev *); -static void fm_irq_handle_low_rssi_start(struct fmdev *); -static void fm_irq_afjump_set_pi(struct fmdev *); -static void fm_irq_handle_set_pi_resp(struct fmdev *); -static void fm_irq_afjump_set_pimask(struct fmdev *); -static void fm_irq_handle_set_pimask_resp(struct fmdev *); -static void fm_irq_afjump_setfreq(struct fmdev *); -static void fm_irq_handle_setfreq_resp(struct fmdev *); -static void fm_irq_afjump_enableint(struct fmdev *); -static void fm_irq_afjump_enableint_resp(struct fmdev *); -static void fm_irq_start_afjump(struct fmdev *); -static void fm_irq_handle_start_afjump_resp(struct fmdev *); -static void fm_irq_afjump_rd_freq(struct fmdev *); -static void fm_irq_afjump_rd_freq_resp(struct fmdev *); -static void fm_irq_handle_low_rssi_finish(struct fmdev *); -static void fm_irq_send_intmsk_cmd(struct fmdev *); -static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *); - -/* - * When FM common module receives interrupt packet, following handlers - * will be executed one after another to service the interrupt(s) - */ -enum fmc_irq_handler_index { - FM_SEND_FLAG_GETCMD_IDX, - FM_HANDLE_FLAG_GETCMD_RESP_IDX, - - /* HW malfunction irq handler */ - FM_HW_MAL_FUNC_IDX, - - /* RDS threshold reached irq handler */ - FM_RDS_START_IDX, - FM_RDS_SEND_RDS_GETCMD_IDX, - FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX, - FM_RDS_FINISH_IDX, - - /* Tune operation ended irq handler */ - FM_HW_TUNE_OP_ENDED_IDX, - - /* TX power enable irq handler */ - FM_HW_POWER_ENB_IDX, - - /* Low RSSI irq handler */ - FM_LOW_RSSI_START_IDX, - FM_AF_JUMP_SETPI_IDX, - FM_AF_JUMP_HANDLE_SETPI_RESP_IDX, - FM_AF_JUMP_SETPI_MASK_IDX, - FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX, - FM_AF_JUMP_SET_AF_FREQ_IDX, - FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX, - FM_AF_JUMP_ENABLE_INT_IDX, - FM_AF_JUMP_ENABLE_INT_RESP_IDX, - FM_AF_JUMP_START_AFJUMP_IDX, - FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX, - FM_AF_JUMP_RD_FREQ_IDX, - FM_AF_JUMP_RD_FREQ_RESP_IDX, - FM_LOW_RSSI_FINISH_IDX, - - /* Interrupt process post action */ - FM_SEND_INTMSK_CMD_IDX, - FM_HANDLE_INTMSK_CMD_RESP_IDX, -}; - -/* FM interrupt handler table */ -static int_handler_prototype int_handler_table[] = { - fm_irq_send_flag_getcmd, - fm_irq_handle_flag_getcmd_resp, - fm_irq_handle_hw_malfunction, - fm_irq_handle_rds_start, /* RDS threshold reached irq handler */ - fm_irq_send_rdsdata_getcmd, - fm_irq_handle_rdsdata_getcmd_resp, - fm_irq_handle_rds_finish, - fm_irq_handle_tune_op_ended, - fm_irq_handle_power_enb, /* TX power enable irq handler */ - fm_irq_handle_low_rssi_start, - fm_irq_afjump_set_pi, - fm_irq_handle_set_pi_resp, - fm_irq_afjump_set_pimask, - fm_irq_handle_set_pimask_resp, - fm_irq_afjump_setfreq, - fm_irq_handle_setfreq_resp, - fm_irq_afjump_enableint, - fm_irq_afjump_enableint_resp, - fm_irq_start_afjump, - fm_irq_handle_start_afjump_resp, - fm_irq_afjump_rd_freq, - fm_irq_afjump_rd_freq_resp, - fm_irq_handle_low_rssi_finish, - fm_irq_send_intmsk_cmd, /* Interrupt process post action */ - fm_irq_handle_intmsk_cmd_resp -}; - -long (*g_st_write) (struct sk_buff *skb); -static struct completion wait_for_fmdrv_reg_comp; - -static inline void fm_irq_call(struct fmdev *fmdev) -{ - fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); -} - -/* Continue next function in interrupt handler table */ -static inline void fm_irq_call_stage(struct fmdev *fmdev, u8 stage) -{ - fmdev->irq_info.stage = stage; - fm_irq_call(fmdev); -} - -static inline void fm_irq_timeout_stage(struct fmdev *fmdev, u8 stage) -{ - fmdev->irq_info.stage = stage; - mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); -} - -#ifdef FM_DUMP_TXRX_PKT - /* To dump outgoing FM Channel-8 packets */ -inline void dump_tx_skb_data(struct sk_buff *skb) -{ - int len, len_org; - u8 index; - struct fm_cmd_msg_hdr *cmd_hdr; - - cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data; - printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x", - fm_cb(skb)->completion ? " " : "*", cmd_hdr->hdr, - cmd_hdr->len, cmd_hdr->op, - cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen); - - len_org = skb->len - FM_CMD_MSG_HDR_SIZE; - if (len_org > 0) { - printk("\n data(%d): ", cmd_hdr->dlen); - len = min(len_org, 14); - for (index = 0; index < len; index++) - printk("%x ", - skb->data[FM_CMD_MSG_HDR_SIZE + index]); - printk("%s", (len_org > 14) ? ".." : ""); - } - printk("\n"); -} - - /* To dump incoming FM Channel-8 packets */ -inline void dump_rx_skb_data(struct sk_buff *skb) -{ - int len, len_org; - u8 index; - struct fm_event_msg_hdr *evt_hdr; - - evt_hdr = (struct fm_event_msg_hdr *)skb->data; - printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x " - "opcode:%02x type:%s dlen:%02x", evt_hdr->hdr, evt_hdr->len, - evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op, - (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen); - - len_org = skb->len - FM_EVT_MSG_HDR_SIZE; - if (len_org > 0) { - printk("\n data(%d): ", evt_hdr->dlen); - len = min(len_org, 14); - for (index = 0; index < len; index++) - printk("%x ", - skb->data[FM_EVT_MSG_HDR_SIZE + index]); - printk("%s", (len_org > 14) ? ".." : ""); - } - printk("\n"); -} -#endif - -void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set) -{ - fmdev->rx.region = region_configs[region_to_set]; -} - -/* - * FM common sub-module will schedule this tasklet whenever it receives - * FM packet from ST driver. - */ -static void recv_tasklet(unsigned long arg) -{ - struct fmdev *fmdev; - struct fm_irq *irq_info; - struct fm_event_msg_hdr *evt_hdr; - struct sk_buff *skb; - u8 num_fm_hci_cmds; - unsigned long flags; - - fmdev = (struct fmdev *)arg; - irq_info = &fmdev->irq_info; - /* Process all packets in the RX queue */ - while ((skb = skb_dequeue(&fmdev->rx_q))) { - if (skb->len < sizeof(struct fm_event_msg_hdr)) { - fmerr("skb(%p) has only %d bytes, " - "at least need %zu bytes to decode\n", skb, - skb->len, sizeof(struct fm_event_msg_hdr)); - kfree_skb(skb); - continue; - } - - evt_hdr = (void *)skb->data; - num_fm_hci_cmds = evt_hdr->num_fm_hci_cmds; - - /* FM interrupt packet? */ - if (evt_hdr->op == FM_INTERRUPT) { - /* FM interrupt handler started already? */ - if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { - set_bit(FM_INTTASK_RUNNING, &fmdev->flag); - if (irq_info->stage != 0) { - fmerr("Inval stage resetting to zero\n"); - irq_info->stage = 0; - } - - /* - * Execute first function in interrupt handler - * table. - */ - irq_info->handlers[irq_info->stage](fmdev); - } else { - set_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag); - } - kfree_skb(skb); - } - /* Anyone waiting for this with completion handler? */ - else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp != NULL) { - - spin_lock_irqsave(&fmdev->resp_skb_lock, flags); - fmdev->resp_skb = skb; - spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); - complete(fmdev->resp_comp); - - fmdev->resp_comp = NULL; - atomic_set(&fmdev->tx_cnt, 1); - } - /* Is this for interrupt handler? */ - else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp == NULL) { - if (fmdev->resp_skb != NULL) - fmerr("Response SKB ptr not NULL\n"); - - spin_lock_irqsave(&fmdev->resp_skb_lock, flags); - fmdev->resp_skb = skb; - spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); - - /* Execute interrupt handler where state index points */ - irq_info->handlers[irq_info->stage](fmdev); - - kfree_skb(skb); - atomic_set(&fmdev->tx_cnt, 1); - } else { - fmerr("Nobody claimed SKB(%p),purging\n", skb); - } - - /* - * Check flow control field. If Num_FM_HCI_Commands field is - * not zero, schedule FM TX tasklet. - */ - if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt)) - if (!skb_queue_empty(&fmdev->tx_q)) - tasklet_schedule(&fmdev->tx_task); - } -} - -/* FM send tasklet: is scheduled when FM packet has to be sent to chip */ -static void send_tasklet(unsigned long arg) -{ - struct fmdev *fmdev; - struct sk_buff *skb; - int len; - - fmdev = (struct fmdev *)arg; - - if (!atomic_read(&fmdev->tx_cnt)) - return; - - /* Check, is there any timeout happenned to last transmitted packet */ - if ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT) { - fmerr("TX timeout occurred\n"); - atomic_set(&fmdev->tx_cnt, 1); - } - - /* Send queued FM TX packets */ - skb = skb_dequeue(&fmdev->tx_q); - if (!skb) - return; - - atomic_dec(&fmdev->tx_cnt); - fmdev->pre_op = fm_cb(skb)->fm_op; - - if (fmdev->resp_comp != NULL) - fmerr("Response completion handler is not NULL\n"); - - fmdev->resp_comp = fm_cb(skb)->completion; - - /* Write FM packet to ST driver */ - len = g_st_write(skb); - if (len < 0) { - kfree_skb(skb); - fmdev->resp_comp = NULL; - fmerr("TX tasklet failed to send skb(%p)\n", skb); - atomic_set(&fmdev->tx_cnt, 1); - } else { - fmdev->last_tx_jiffies = jiffies; - } -} - -/* - * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for - * transmission - */ -static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, - int payload_len, struct completion *wait_completion) -{ - struct sk_buff *skb; - struct fm_cmd_msg_hdr *hdr; - int size; - - if (fm_op >= FM_INTERRUPT) { - fmerr("Invalid fm opcode - %d\n", fm_op); - return -EINVAL; - } - if (test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) && payload == NULL) { - fmerr("Payload data is NULL during fw download\n"); - return -EINVAL; - } - if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag)) - size = - FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len); - else - size = payload_len; - - skb = alloc_skb(size, GFP_ATOMIC); - if (!skb) { - fmerr("No memory to create new SKB\n"); - return -ENOMEM; - } - /* - * Don't fill FM header info for the commands which come from - * FM firmware file. - */ - if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) || - test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { - /* Fill command header info */ - hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE); - hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */ - - /* 3 (fm_opcode,rd_wr,dlen) + payload len) */ - hdr->len = ((payload == NULL) ? 0 : payload_len) + 3; - - /* FM opcode */ - hdr->op = fm_op; - - /* read/write type */ - hdr->rd_wr = type; - hdr->dlen = payload_len; - fm_cb(skb)->fm_op = fm_op; - - /* - * If firmware download has finished and the command is - * not a read command then payload is != NULL - a write - * command with u16 payload - convert to be16 - */ - if (payload != NULL) - *(u16 *)payload = cpu_to_be16(*(u16 *)payload); - - } else if (payload != NULL) { - fm_cb(skb)->fm_op = *((u8 *)payload + 2); - } - if (payload != NULL) - memcpy(skb_put(skb, payload_len), payload, payload_len); - - fm_cb(skb)->completion = wait_completion; - skb_queue_tail(&fmdev->tx_q, skb); - tasklet_schedule(&fmdev->tx_task); - - return 0; -} - -/* Sends FM Channel-8 command to the chip and waits for the response */ -u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, - unsigned int payload_len, void *response, int *response_len) -{ - struct sk_buff *skb; - struct fm_event_msg_hdr *evt_hdr; - unsigned long flags; - u32 ret; - - init_completion(&fmdev->maintask_comp); - ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len, - &fmdev->maintask_comp); - if (ret) - return ret; - - ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT); - if (!ret) { - fmerr("Timeout(%d sec),didn't get reg" - "completion signal from RX tasklet\n", - jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); - return -ETIMEDOUT; - } - if (!fmdev->resp_skb) { - fmerr("Reponse SKB is missing\n"); - return -EFAULT; - } - spin_lock_irqsave(&fmdev->resp_skb_lock, flags); - skb = fmdev->resp_skb; - fmdev->resp_skb = NULL; - spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); - - evt_hdr = (void *)skb->data; - if (evt_hdr->status != 0) { - fmerr("Received event pkt status(%d) is not zero\n", - evt_hdr->status); - kfree_skb(skb); - return -EIO; - } - /* Send response data to caller */ - if (response != NULL && response_len != NULL && evt_hdr->dlen) { - /* Skip header info and copy only response data */ - skb_pull(skb, sizeof(struct fm_event_msg_hdr)); - memcpy(response, skb->data, evt_hdr->dlen); - *response_len = evt_hdr->dlen; - } else if (response_len != NULL && evt_hdr->dlen == 0) { - *response_len = 0; - } - kfree_skb(skb); - - return 0; -} - -/* --- Helper functions used in FM interrupt handlers ---*/ -static inline u32 check_cmdresp_status(struct fmdev *fmdev, - struct sk_buff **skb) -{ - struct fm_event_msg_hdr *fm_evt_hdr; - unsigned long flags; - - del_timer(&fmdev->irq_info.timer); - - spin_lock_irqsave(&fmdev->resp_skb_lock, flags); - *skb = fmdev->resp_skb; - fmdev->resp_skb = NULL; - spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); - - fm_evt_hdr = (void *)(*skb)->data; - if (fm_evt_hdr->status != 0) { - fmerr("irq: opcode %x response status is not zero " - "Initiating irq recovery process\n", - fm_evt_hdr->op); - - mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); - return -1; - } - - return 0; -} - -static inline void fm_irq_common_cmd_resp_helper(struct fmdev *fmdev, u8 stage) -{ - struct sk_buff *skb; - - if (!check_cmdresp_status(fmdev, &skb)) - fm_irq_call_stage(fmdev, stage); -} - -/* - * Interrupt process timeout handler. - * One of the irq handler did not get proper response from the chip. So take - * recovery action here. FM interrupts are disabled in the beginning of - * interrupt process. Therefore reset stage index to re-enable default - * interrupts. So that next interrupt will be processed as usual. - */ -static void int_timeout_handler(unsigned long data) -{ - struct fmdev *fmdev; - struct fm_irq *fmirq; - - fmdbg("irq: timeout,trying to re-enable fm interrupts\n"); - fmdev = (struct fmdev *)data; - fmirq = &fmdev->irq_info; - fmirq->retry++; - - if (fmirq->retry > FM_IRQ_TIMEOUT_RETRY_MAX) { - /* Stop recovery action (interrupt reenable process) and - * reset stage index & retry count values */ - fmirq->stage = 0; - fmirq->retry = 0; - fmerr("Recovery action failed during" - "irq processing, max retry reached\n"); - return; - } - fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); -} - -/* --------- FM interrupt handlers ------------*/ -static void fm_irq_send_flag_getcmd(struct fmdev *fmdev) -{ - u16 flag; - - /* Send FLAG_GET command , to know the source of interrupt */ - if (!fm_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, sizeof(flag), NULL)) - fm_irq_timeout_stage(fmdev, FM_HANDLE_FLAG_GETCMD_RESP_IDX); -} - -static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev) -{ - struct sk_buff *skb; - struct fm_event_msg_hdr *fm_evt_hdr; - - if (check_cmdresp_status(fmdev, &skb)) - return; - - fm_evt_hdr = (void *)skb->data; - - /* Skip header info and copy only response data */ - skb_pull(skb, sizeof(struct fm_event_msg_hdr)); - memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen); - - fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag); - fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag); - - /* Continue next function in interrupt handler table */ - fm_irq_call_stage(fmdev, FM_HW_MAL_FUNC_IDX); -} - -static void fm_irq_handle_hw_malfunction(struct fmdev *fmdev) -{ - if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask) - fmerr("irq: HW MAL int received - do nothing\n"); - - /* Continue next function in interrupt handler table */ - fm_irq_call_stage(fmdev, FM_RDS_START_IDX); -} - -static void fm_irq_handle_rds_start(struct fmdev *fmdev) -{ - if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) { - fmdbg("irq: rds threshold reached\n"); - fmdev->irq_info.stage = FM_RDS_SEND_RDS_GETCMD_IDX; - } else { - /* Continue next function in interrupt handler table */ - fmdev->irq_info.stage = FM_HW_TUNE_OP_ENDED_IDX; - } - - fm_irq_call(fmdev); -} - -static void fm_irq_send_rdsdata_getcmd(struct fmdev *fmdev) -{ - /* Send the command to read RDS data from the chip */ - if (!fm_send_cmd(fmdev, RDS_DATA_GET, REG_RD, NULL, - (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL)) - fm_irq_timeout_stage(fmdev, FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX); -} - -/* Keeps track of current RX channel AF (Alternate Frequency) */ -static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af) -{ - struct tuned_station_info *stat_info = &fmdev->rx.stat_info; - u8 reg_idx = fmdev->rx.region.fm_band; - u8 index; - u32 freq; - - /* First AF indicates the number of AF follows. Reset the list */ - if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) { - fmdev->rx.stat_info.af_list_max = (af - FM_RDS_1_AF_FOLLOWS + 1); - fmdev->rx.stat_info.afcache_size = 0; - fmdbg("No of expected AF : %d\n", fmdev->rx.stat_info.af_list_max); - return; - } - - if (af < FM_RDS_MIN_AF) - return; - if (reg_idx == FM_BAND_EUROPE_US && af > FM_RDS_MAX_AF) - return; - if (reg_idx == FM_BAND_JAPAN && af > FM_RDS_MAX_AF_JAPAN) - return; - - freq = fmdev->rx.region.bot_freq + (af * 100); - if (freq == fmdev->rx.freq) { - fmdbg("Current freq(%d) is matching with received AF(%d)\n", - fmdev->rx.freq, freq); - return; - } - /* Do check in AF cache */ - for (index = 0; index < stat_info->afcache_size; index++) { - if (stat_info->af_cache[index] == freq) - break; - } - /* Reached the limit of the list - ignore the next AF */ - if (index == stat_info->af_list_max) { - fmdbg("AF cache is full\n"); - return; - } - /* - * If we reached the end of the list then this AF is not - * in the list - add it. - */ - if (index == stat_info->afcache_size) { - fmdbg("Storing AF %d to cache index %d\n", freq, index); - stat_info->af_cache[index] = freq; - stat_info->afcache_size++; - } -} - -/* - * Converts RDS buffer data from big endian format - * to little endian format. - */ -static void fm_rdsparse_swapbytes(struct fmdev *fmdev, - struct fm_rdsdata_format *rds_format) -{ - u8 byte1; - u8 index = 0; - u8 *rds_buff; - - /* - * Since in Orca the 2 RDS Data bytes are in little endian and - * in Dolphin they are in big endian, the parsing of the RDS data - * is chip dependent - */ - if (fmdev->asci_id != 0x6350) { - rds_buff = &rds_format->data.groupdatabuff.buff[0]; - while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) { - byte1 = rds_buff[index]; - rds_buff[index] = rds_buff[index + 1]; - rds_buff[index + 1] = byte1; - index += 2; - } - } -} - -static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) -{ - struct sk_buff *skb; - struct fm_rdsdata_format rds_fmt; - struct fm_rds *rds = &fmdev->rx.rds; - unsigned long group_idx, flags; - u8 *rds_data, meta_data, tmpbuf[3]; - u8 type, blk_idx; - u16 cur_picode; - u32 rds_len; - - if (check_cmdresp_status(fmdev, &skb)) - return; - - /* Skip header info */ - skb_pull(skb, sizeof(struct fm_event_msg_hdr)); - rds_data = skb->data; - rds_len = skb->len; - - /* Parse the RDS data */ - while (rds_len >= FM_RDS_BLK_SIZE) { - meta_data = rds_data[2]; - /* Get the type: 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */ - type = (meta_data & 0x07); - - /* Transform the blk type into index sequence (0, 1, 2, 3, 4) */ - blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); - fmdbg("Block index:%d(%s)\n", blk_idx, - (meta_data & FM_RDS_STATUS_ERR_MASK) ? "Bad" : "Ok"); - - if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0) - break; - - if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) { - fmdbg("Block sequence mismatch\n"); - rds->last_blk_idx = -1; - break; - } - - /* Skip checkword (control) byte and copy only data byte */ - memcpy(&rds_fmt.data.groupdatabuff. - buff[blk_idx * (FM_RDS_BLK_SIZE - 1)], - rds_data, (FM_RDS_BLK_SIZE - 1)); - - rds->last_blk_idx = blk_idx; - - /* If completed a whole group then handle it */ - if (blk_idx == FM_RDS_BLK_IDX_D) { - fmdbg("Good block received\n"); - fm_rdsparse_swapbytes(fmdev, &rds_fmt); - - /* - * Extract PI code and store in local cache. - * We need this during AF switch processing. - */ - cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata); - if (fmdev->rx.stat_info.picode != cur_picode) - fmdev->rx.stat_info.picode = cur_picode; - - fmdbg("picode:%d\n", cur_picode); - - group_idx = (rds_fmt.data.groupgeneral.blk_b[0] >> 3); - fmdbg("(fmdrv):Group:%ld%s\n", group_idx/2, - (group_idx % 2) ? "B" : "A"); - - group_idx = 1 << (rds_fmt.data.groupgeneral.blk_b[0] >> 3); - if (group_idx == FM_RDS_GROUP_TYPE_MASK_0A) { - fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[0]); - fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[1]); - } - } - rds_len -= FM_RDS_BLK_SIZE; - rds_data += FM_RDS_BLK_SIZE; - } - - /* Copy raw rds data to internal rds buffer */ - rds_data = skb->data; - rds_len = skb->len; - - spin_lock_irqsave(&fmdev->rds_buff_lock, flags); - while (rds_len > 0) { - /* - * Fill RDS buffer as per V4L2 specification. - * Store control byte - */ - type = (rds_data[2] & 0x07); - blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); - tmpbuf[2] = blk_idx; /* Offset name */ - tmpbuf[2] |= blk_idx << 3; /* Received offset */ - - /* Store data byte */ - tmpbuf[0] = rds_data[0]; - tmpbuf[1] = rds_data[1]; - - memcpy(&rds->buff[rds->wr_idx], &tmpbuf, FM_RDS_BLK_SIZE); - rds->wr_idx = (rds->wr_idx + FM_RDS_BLK_SIZE) % rds->buf_size; - - /* Check for overflow & start over */ - if (rds->wr_idx == rds->rd_idx) { - fmdbg("RDS buffer overflow\n"); - rds->wr_idx = 0; - rds->rd_idx = 0; - break; - } - rds_len -= FM_RDS_BLK_SIZE; - rds_data += FM_RDS_BLK_SIZE; - } - spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); - - /* Wakeup read queue */ - if (rds->wr_idx != rds->rd_idx) - wake_up_interruptible(&rds->read_queue); - - fm_irq_call_stage(fmdev, FM_RDS_FINISH_IDX); -} - -static void fm_irq_handle_rds_finish(struct fmdev *fmdev) -{ - fm_irq_call_stage(fmdev, FM_HW_TUNE_OP_ENDED_IDX); -} - -static void fm_irq_handle_tune_op_ended(struct fmdev *fmdev) -{ - if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev-> - irq_info.mask) { - fmdbg("irq: tune ended/bandlimit reached\n"); - if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) { - fmdev->irq_info.stage = FM_AF_JUMP_RD_FREQ_IDX; - } else { - complete(&fmdev->maintask_comp); - fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; - } - } else - fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; - - fm_irq_call(fmdev); -} - -static void fm_irq_handle_power_enb(struct fmdev *fmdev) -{ - if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) { - fmdbg("irq: Power Enabled/Disabled\n"); - complete(&fmdev->maintask_comp); - } - - fm_irq_call_stage(fmdev, FM_LOW_RSSI_START_IDX); -} - -static void fm_irq_handle_low_rssi_start(struct fmdev *fmdev) -{ - if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) && - (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) && - (fmdev->rx.freq != FM_UNDEFINED_FREQ) && - (fmdev->rx.stat_info.afcache_size != 0)) { - fmdbg("irq: rssi level has fallen below threshold level\n"); - - /* Disable further low RSSI interrupts */ - fmdev->irq_info.mask &= ~FM_LEV_EVENT; - - fmdev->rx.afjump_idx = 0; - fmdev->rx.freq_before_jump = fmdev->rx.freq; - fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; - } else { - /* Continue next function in interrupt handler table */ - fmdev->irq_info.stage = FM_SEND_INTMSK_CMD_IDX; - } - - fm_irq_call(fmdev); -} - -static void fm_irq_afjump_set_pi(struct fmdev *fmdev) -{ - u16 payload; - - /* Set PI code - must be updated if the AF list is not empty */ - payload = fmdev->rx.stat_info.picode; - if (!fm_send_cmd(fmdev, RDS_PI_SET, REG_WR, &payload, sizeof(payload), NULL)) - fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_RESP_IDX); -} - -static void fm_irq_handle_set_pi_resp(struct fmdev *fmdev) -{ - fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SETPI_MASK_IDX); -} - -/* - * Set PI mask. - * 0xFFFF = Enable PI code matching - * 0x0000 = Disable PI code matching - */ -static void fm_irq_afjump_set_pimask(struct fmdev *fmdev) -{ - u16 payload; - - payload = 0x0000; - if (!fm_send_cmd(fmdev, RDS_PI_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) - fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX); -} - -static void fm_irq_handle_set_pimask_resp(struct fmdev *fmdev) -{ - fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SET_AF_FREQ_IDX); -} - -static void fm_irq_afjump_setfreq(struct fmdev *fmdev) -{ - u16 frq_index; - u16 payload; - - fmdbg("Swtich to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]); - frq_index = (fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx] - - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; - - payload = frq_index; - if (!fm_send_cmd(fmdev, AF_FREQ_SET, REG_WR, &payload, sizeof(payload), NULL)) - fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX); -} - -static void fm_irq_handle_setfreq_resp(struct fmdev *fmdev) -{ - fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_ENABLE_INT_IDX); -} - -static void fm_irq_afjump_enableint(struct fmdev *fmdev) -{ - u16 payload; - - /* Enable FR (tuning operation ended) interrupt */ - payload = FM_FR_EVENT; - if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) - fm_irq_timeout_stage(fmdev, FM_AF_JUMP_ENABLE_INT_RESP_IDX); -} - -static void fm_irq_afjump_enableint_resp(struct fmdev *fmdev) -{ - fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_START_AFJUMP_IDX); -} - -static void fm_irq_start_afjump(struct fmdev *fmdev) -{ - u16 payload; - - payload = FM_TUNER_AF_JUMP_MODE; - if (!fm_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, - sizeof(payload), NULL)) - fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX); -} - -static void fm_irq_handle_start_afjump_resp(struct fmdev *fmdev) -{ - struct sk_buff *skb; - - if (check_cmdresp_status(fmdev, &skb)) - return; - - fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; - set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag); - clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); -} - -static void fm_irq_afjump_rd_freq(struct fmdev *fmdev) -{ - u16 payload; - - if (!fm_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, sizeof(payload), NULL)) - fm_irq_timeout_stage(fmdev, FM_AF_JUMP_RD_FREQ_RESP_IDX); -} - -static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev) -{ - struct sk_buff *skb; - u16 read_freq; - u32 curr_freq, jumped_freq; - - if (check_cmdresp_status(fmdev, &skb)) - return; - - /* Skip header info and copy only response data */ - skb_pull(skb, sizeof(struct fm_event_msg_hdr)); - memcpy(&read_freq, skb->data, sizeof(read_freq)); - read_freq = be16_to_cpu(read_freq); - curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL); - - jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]; - - /* If the frequency was changed the jump succeeded */ - if ((curr_freq != fmdev->rx.freq_before_jump) && (curr_freq == jumped_freq)) { - fmdbg("Successfully switched to alternate freq %d\n", curr_freq); - fmdev->rx.freq = curr_freq; - fm_rx_reset_rds_cache(fmdev); - - /* AF feature is on, enable low level RSSI interrupt */ - if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) - fmdev->irq_info.mask |= FM_LEV_EVENT; - - fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; - } else { /* jump to the next freq in the AF list */ - fmdev->rx.afjump_idx++; - - /* If we reached the end of the list - stop searching */ - if (fmdev->rx.afjump_idx >= fmdev->rx.stat_info.afcache_size) { - fmdbg("AF switch processing failed\n"); - fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; - } else { /* AF List is not over - try next one */ - - fmdbg("Trying next freq in AF cache\n"); - fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; - } - } - fm_irq_call(fmdev); -} - -static void fm_irq_handle_low_rssi_finish(struct fmdev *fmdev) -{ - fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); -} - -static void fm_irq_send_intmsk_cmd(struct fmdev *fmdev) -{ - u16 payload; - - /* Re-enable FM interrupts */ - payload = fmdev->irq_info.mask; - - if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, - sizeof(payload), NULL)) - fm_irq_timeout_stage(fmdev, FM_HANDLE_INTMSK_CMD_RESP_IDX); -} - -static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev) -{ - struct sk_buff *skb; - - if (check_cmdresp_status(fmdev, &skb)) - return; - /* - * This is last function in interrupt table to be executed. - * So, reset stage index to 0. - */ - fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; - - /* Start processing any pending interrupt */ - if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag)) - fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); - else - clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); -} - -/* Returns availability of RDS data in internel buffer */ -u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, - struct poll_table_struct *pts) -{ - poll_wait(file, &fmdev->rx.rds.read_queue, pts); - if (fmdev->rx.rds.rd_idx != fmdev->rx.rds.wr_idx) - return 0; - - return -EAGAIN; -} - -/* Copies RDS data from internal buffer to user buffer */ -u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, - u8 __user *buf, size_t count) -{ - u32 block_count; - unsigned long flags; - int ret; - - if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) { - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - - ret = wait_event_interruptible(fmdev->rx.rds.read_queue, - (fmdev->rx.rds.wr_idx != fmdev->rx.rds.rd_idx)); - if (ret) - return -EINTR; - } - - /* Calculate block count from byte count */ - count /= 3; - block_count = 0; - ret = 0; - - spin_lock_irqsave(&fmdev->rds_buff_lock, flags); - - while (block_count < count) { - if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) - break; - - if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], - FM_RDS_BLK_SIZE)) - break; - - fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE; - if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size) - fmdev->rx.rds.rd_idx = 0; - - block_count++; - buf += FM_RDS_BLK_SIZE; - ret += FM_RDS_BLK_SIZE; - } - spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); - return ret; -} - -u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) -{ - switch (fmdev->curr_fmmode) { - case FM_MODE_RX: - return fm_rx_set_freq(fmdev, freq_to_set); - - case FM_MODE_TX: - return fm_tx_set_freq(fmdev, freq_to_set); - - default: - return -EINVAL; - } -} - -u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) -{ - if (fmdev->rx.freq == FM_UNDEFINED_FREQ) { - fmerr("RX frequency is not set\n"); - return -EPERM; - } - if (cur_tuned_frq == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - switch (fmdev->curr_fmmode) { - case FM_MODE_RX: - *cur_tuned_frq = fmdev->rx.freq; - return 0; - - case FM_MODE_TX: - *cur_tuned_frq = 0; /* TODO : Change this later */ - return 0; - - default: - return -EINVAL; - } - -} - -u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) -{ - switch (fmdev->curr_fmmode) { - case FM_MODE_RX: - return fm_rx_set_region(fmdev, region_to_set); - - case FM_MODE_TX: - return fm_tx_set_region(fmdev, region_to_set); - - default: - return -EINVAL; - } -} - -u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) -{ - switch (fmdev->curr_fmmode) { - case FM_MODE_RX: - return fm_rx_set_mute_mode(fmdev, mute_mode_toset); - - case FM_MODE_TX: - return fm_tx_set_mute_mode(fmdev, mute_mode_toset); - - default: - return -EINVAL; - } -} - -u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) -{ - switch (fmdev->curr_fmmode) { - case FM_MODE_RX: - return fm_rx_set_stereo_mono(fmdev, mode); - - case FM_MODE_TX: - return fm_tx_set_stereo_mono(fmdev, mode); - - default: - return -EINVAL; - } -} - -u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) -{ - switch (fmdev->curr_fmmode) { - case FM_MODE_RX: - return fm_rx_set_rds_mode(fmdev, rds_en_dis); - - case FM_MODE_TX: - return fm_tx_set_rds_mode(fmdev, rds_en_dis); - - default: - return -EINVAL; - } -} - -/* Sends power off command to the chip */ -static u32 fm_power_down(struct fmdev *fmdev) -{ - u16 payload; - u32 ret; - - if (!test_bit(FM_CORE_READY, &fmdev->flag)) { - fmerr("FM core is not ready\n"); - return -EPERM; - } - if (fmdev->curr_fmmode == FM_MODE_OFF) { - fmdbg("FM chip is already in OFF state\n"); - return 0; - } - - payload = 0x0; - ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - return fmc_release(fmdev); -} - -/* Reads init command from FM firmware file and loads to the chip */ -static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) -{ - const struct firmware *fw_entry; - struct bts_header *fw_header; - struct bts_action *action; - struct bts_action_delay *delay; - u8 *fw_data; - int ret, fw_len, cmd_cnt; - - cmd_cnt = 0; - set_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); - - ret = request_firmware(&fw_entry, fw_name, - &fmdev->radio_dev->dev); - if (ret < 0) { - fmerr("Unable to read firmware(%s) content\n", fw_name); - return ret; - } - fmdbg("Firmware(%s) length : %d bytes\n", fw_name, fw_entry->size); - - fw_data = (void *)fw_entry->data; - fw_len = fw_entry->size; - - fw_header = (struct bts_header *)fw_data; - if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) { - fmerr("%s not a legal TI firmware file\n", fw_name); - ret = -EINVAL; - goto rel_fw; - } - fmdbg("FW(%s) magic number : 0x%x\n", fw_name, fw_header->magic); - - /* Skip file header info , we already verified it */ - fw_data += sizeof(struct bts_header); - fw_len -= sizeof(struct bts_header); - - while (fw_data && fw_len > 0) { - action = (struct bts_action *)fw_data; - - switch (action->type) { - case ACTION_SEND_COMMAND: /* Send */ - if (fmc_send_cmd(fmdev, 0, 0, action->data, - action->size, NULL, NULL)) - goto rel_fw; - - cmd_cnt++; - break; - - case ACTION_DELAY: /* Delay */ - delay = (struct bts_action_delay *)action->data; - mdelay(delay->msec); - break; - } - - fw_data += (sizeof(struct bts_action) + (action->size)); - fw_len -= (sizeof(struct bts_action) + (action->size)); - } - fmdbg("Firmware commands(%d) loaded to chip\n", cmd_cnt); -rel_fw: - release_firmware(fw_entry); - clear_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); - - return ret; -} - -/* Loads default RX configuration to the chip */ -static u32 load_default_rx_configuration(struct fmdev *fmdev) -{ - int ret; - - ret = fm_rx_set_volume(fmdev, FM_DEFAULT_RX_VOLUME); - if (ret < 0) - return ret; - - return fm_rx_set_rssi_threshold(fmdev, FM_DEFAULT_RSSI_THRESHOLD); -} - -/* Does FM power on sequence */ -static u32 fm_power_up(struct fmdev *fmdev, u8 mode) -{ - u16 payload, asic_id, asic_ver; - int resp_len, ret; - u8 fw_name[50]; - - if (mode >= FM_MODE_ENTRY_MAX) { - fmerr("Invalid firmware download option\n"); - return -EINVAL; - } - - /* - * Initialize FM common module. FM GPIO toggling is - * taken care in Shared Transport driver. - */ - ret = fmc_prepare(fmdev); - if (ret < 0) { - fmerr("Unable to prepare FM Common\n"); - return ret; - } - - payload = FM_ENABLE; - if (fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, - sizeof(payload), NULL, NULL)) - goto rel; - - /* Allow the chip to settle down in Channel-8 mode */ - msleep(20); - - if (fmc_send_cmd(fmdev, ASIC_ID_GET, REG_RD, NULL, - sizeof(asic_id), &asic_id, &resp_len)) - goto rel; - - if (fmc_send_cmd(fmdev, ASIC_VER_GET, REG_RD, NULL, - sizeof(asic_ver), &asic_ver, &resp_len)) - goto rel; - - fmdbg("ASIC ID: 0x%x , ASIC Version: %d\n", - be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); - - sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START, - be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); - - ret = fm_download_firmware(fmdev, fw_name); - if (ret < 0) { - fmdbg("Failed to download firmware file %s\n", fw_name); - goto rel; - } - sprintf(fw_name, "%s_%x.%d.bts", (mode == FM_MODE_RX) ? - FM_RX_FW_FILE_START : FM_TX_FW_FILE_START, - be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); - - ret = fm_download_firmware(fmdev, fw_name); - if (ret < 0) { - fmdbg("Failed to download firmware file %s\n", fw_name); - goto rel; - } else - return ret; -rel: - return fmc_release(fmdev); -} - -/* Set FM Modes(TX, RX, OFF) */ -u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) -{ - int ret = 0; - - if (fm_mode >= FM_MODE_ENTRY_MAX) { - fmerr("Invalid FM mode\n"); - return -EINVAL; - } - if (fmdev->curr_fmmode == fm_mode) { - fmdbg("Already fm is in mode(%d)\n", fm_mode); - return ret; - } - - switch (fm_mode) { - case FM_MODE_OFF: /* OFF Mode */ - ret = fm_power_down(fmdev); - if (ret < 0) { - fmerr("Failed to set OFF mode\n"); - return ret; - } - break; - - case FM_MODE_TX: /* TX Mode */ - case FM_MODE_RX: /* RX Mode */ - /* Power down before switching to TX or RX mode */ - if (fmdev->curr_fmmode != FM_MODE_OFF) { - ret = fm_power_down(fmdev); - if (ret < 0) { - fmerr("Failed to set OFF mode\n"); - return ret; - } - msleep(30); - } - ret = fm_power_up(fmdev, fm_mode); - if (ret < 0) { - fmerr("Failed to load firmware\n"); - return ret; - } - } - fmdev->curr_fmmode = fm_mode; - - /* Set default configuration */ - if (fmdev->curr_fmmode == FM_MODE_RX) { - fmdbg("Loading default rx configuration..\n"); - ret = load_default_rx_configuration(fmdev); - if (ret < 0) - fmerr("Failed to load default values\n"); - } - - return ret; -} - -/* Returns current FM mode (TX, RX, OFF) */ -u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) -{ - if (!test_bit(FM_CORE_READY, &fmdev->flag)) { - fmerr("FM core is not ready\n"); - return -EPERM; - } - if (fmmode == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *fmmode = fmdev->curr_fmmode; - return 0; -} - -/* Called by ST layer when FM packet is available */ -static long fm_st_receive(void *arg, struct sk_buff *skb) -{ - struct fmdev *fmdev; - - fmdev = (struct fmdev *)arg; - - if (skb == NULL) { - fmerr("Invalid SKB received from ST\n"); - return -EFAULT; - } - - if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) { - fmerr("Received SKB (%p) is not FM Channel 8 pkt\n", skb); - return -EINVAL; - } - - memcpy(skb_push(skb, 1), &skb->cb[0], 1); - skb_queue_tail(&fmdev->rx_q, skb); - tasklet_schedule(&fmdev->rx_task); - - return 0; -} - -/* - * Called by ST layer to indicate protocol registration completion - * status. - */ -static void fm_st_reg_comp_cb(void *arg, char data) -{ - struct fmdev *fmdev; - - fmdev = (struct fmdev *)arg; - fmdev->streg_cbdata = data; - complete(&wait_for_fmdrv_reg_comp); -} - -/* - * This function will be called from FM V4L2 open function. - * Register with ST driver and initialize driver data. - */ -u32 fmc_prepare(struct fmdev *fmdev) -{ - static struct st_proto_s fm_st_proto; - u32 ret; - - if (test_bit(FM_CORE_READY, &fmdev->flag)) { - fmdbg("FM Core is already up\n"); - return 0; - } - - memset(&fm_st_proto, 0, sizeof(fm_st_proto)); - fm_st_proto.type = ST_FM; - fm_st_proto.recv = fm_st_receive; - fm_st_proto.match_packet = NULL; - fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb; - fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */ - fm_st_proto.priv_data = fmdev; - - ret = st_register(&fm_st_proto); - if (ret == -EINPROGRESS) { - init_completion(&wait_for_fmdrv_reg_comp); - fmdev->streg_cbdata = -EINPROGRESS; - fmdbg("%s waiting for ST reg completion signal\n", __func__); - - ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, - FM_ST_REG_TIMEOUT); - - if (!ret) { - fmerr("Timeout(%d sec), didn't get reg " - "completion signal from ST\n", - jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000); - return -ETIMEDOUT; - } - if (fmdev->streg_cbdata != 0) { - fmerr("ST reg comp CB called with error " - "status %d\n", fmdev->streg_cbdata); - return -EAGAIN; - } - - ret = 0; - } else if (ret == -1) { - fmerr("st_register failed %d\n", ret); - return -EAGAIN; - } - - if (fm_st_proto.write != NULL) { - g_st_write = fm_st_proto.write; - } else { - fmerr("Failed to get ST write func pointer\n"); - ret = st_unregister(ST_FM); - if (ret < 0) - fmerr("st_unregister failed %d\n", ret); - return -EAGAIN; - } - - spin_lock_init(&fmdev->rds_buff_lock); - spin_lock_init(&fmdev->resp_skb_lock); - - /* Initialize TX queue and TX tasklet */ - skb_queue_head_init(&fmdev->tx_q); - tasklet_init(&fmdev->tx_task, send_tasklet, (unsigned long)fmdev); - - /* Initialize RX Queue and RX tasklet */ - skb_queue_head_init(&fmdev->rx_q); - tasklet_init(&fmdev->rx_task, recv_tasklet, (unsigned long)fmdev); - - fmdev->irq_info.stage = 0; - atomic_set(&fmdev->tx_cnt, 1); - fmdev->resp_comp = NULL; - - init_timer(&fmdev->irq_info.timer); - fmdev->irq_info.timer.function = &int_timeout_handler; - fmdev->irq_info.timer.data = (unsigned long)fmdev; - /*TODO: add FM_STIC_EVENT later */ - fmdev->irq_info.mask = FM_MAL_EVENT; - - /* Region info */ - memcpy(&fmdev->rx.region, ®ion_configs[default_radio_region], - sizeof(struct region_info)); - - fmdev->rx.mute_mode = FM_MUTE_OFF; - fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF; - fmdev->rx.rds.flag = FM_RDS_DISABLE; - fmdev->rx.freq = FM_UNDEFINED_FREQ; - fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS; - fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF; - fmdev->irq_info.retry = 0; - - fm_rx_reset_rds_cache(fmdev); - init_waitqueue_head(&fmdev->rx.rds.read_queue); - - fm_rx_reset_station_info(fmdev); - set_bit(FM_CORE_READY, &fmdev->flag); - - return ret; -} - -/* - * This function will be called from FM V4L2 release function. - * Unregister from ST driver. - */ -u32 fmc_release(struct fmdev *fmdev) -{ - u32 ret; - - if (!test_bit(FM_CORE_READY, &fmdev->flag)) { - fmdbg("FM Core is already down\n"); - return 0; - } - /* Sevice pending read */ - wake_up_interruptible(&fmdev->rx.rds.read_queue); - - tasklet_kill(&fmdev->tx_task); - tasklet_kill(&fmdev->rx_task); - - skb_queue_purge(&fmdev->tx_q); - skb_queue_purge(&fmdev->rx_q); - - fmdev->resp_comp = NULL; - fmdev->rx.freq = 0; - - ret = st_unregister(ST_FM); - if (ret < 0) - fmerr("Failed to de-register FM from ST %d\n", ret); - else - fmdbg("Successfully unregistered from ST\n"); - - clear_bit(FM_CORE_READY, &fmdev->flag); - return ret; -} - -/* - * Module init function. Ask FM V4L module to register video device. - * Allocate memory for FM driver context and RX RDS buffer. - */ -static int __init fm_drv_init(void) -{ - struct fmdev *fmdev = NULL; - u32 ret = -ENOMEM; - - fmdbg("FM driver version %s\n", FM_DRV_VERSION); - - fmdev = kzalloc(sizeof(struct fmdev), GFP_KERNEL); - if (NULL == fmdev) { - fmerr("Can't allocate operation structure memory\n"); - return ret; - } - fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLK_SIZE; - fmdev->rx.rds.buff = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL); - if (NULL == fmdev->rx.rds.buff) { - fmerr("Can't allocate rds ring buffer\n"); - goto rel_dev; - } - - ret = fm_v4l2_init_video_device(fmdev, radio_nr); - if (ret < 0) - goto rel_rdsbuf; - - fmdev->irq_info.handlers = int_handler_table; - fmdev->curr_fmmode = FM_MODE_OFF; - fmdev->tx_data.pwr_lvl = FM_PWR_LVL_DEF; - fmdev->tx_data.preemph = FM_TX_PREEMPH_50US; - return ret; - -rel_rdsbuf: - kfree(fmdev->rx.rds.buff); -rel_dev: - kfree(fmdev); - - return ret; -} - -/* Module exit function. Ask FM V4L module to unregister video device */ -static void __exit fm_drv_exit(void) -{ - struct fmdev *fmdev = NULL; - - fmdev = fm_v4l2_deinit_video_device(); - if (fmdev != NULL) { - kfree(fmdev->rx.rds.buff); - kfree(fmdev); - } -} - -module_init(fm_drv_init); -module_exit(fm_drv_exit); - -/* ------------- Module Info ------------- */ -MODULE_AUTHOR("Manjunatha Halli "); -MODULE_DESCRIPTION("FM Driver for TI's Connectivity chip. " FM_DRV_VERSION); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_common.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,402 +0,0 @@ -/* - * FM Driver for Connectivity chip of Texas Instruments. - * FM Common module header file - * - * Copyright (C) 2011 Texas Instruments - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - * - */ - -#ifndef _FMDRV_COMMON_H -#define _FMDRV_COMMON_H - -#define FM_ST_REG_TIMEOUT msecs_to_jiffies(6000) /* 6 sec */ -#define FM_PKT_LOGICAL_CHAN_NUMBER 0x08 /* Logical channel 8 */ - -#define REG_RD 0x1 -#define REG_WR 0x0 - -struct fm_reg_table { - u8 opcode; - u8 type; - u8 *name; -}; - -#define STEREO_GET 0 -#define RSSI_LVL_GET 1 -#define IF_COUNT_GET 2 -#define FLAG_GET 3 -#define RDS_SYNC_GET 4 -#define RDS_DATA_GET 5 -#define FREQ_SET 10 -#define AF_FREQ_SET 11 -#define MOST_MODE_SET 12 -#define MOST_BLEND_SET 13 -#define DEMPH_MODE_SET 14 -#define SEARCH_LVL_SET 15 -#define BAND_SET 16 -#define MUTE_STATUS_SET 17 -#define RDS_PAUSE_LVL_SET 18 -#define RDS_PAUSE_DUR_SET 19 -#define RDS_MEM_SET 20 -#define RDS_BLK_B_SET 21 -#define RDS_MSK_B_SET 22 -#define RDS_PI_MASK_SET 23 -#define RDS_PI_SET 24 -#define RDS_SYSTEM_SET 25 -#define INT_MASK_SET 26 -#define SEARCH_DIR_SET 27 -#define VOLUME_SET 28 -#define AUDIO_ENABLE_SET 29 -#define PCM_MODE_SET 30 -#define I2S_MODE_CONFIG_SET 31 -#define POWER_SET 32 -#define INTX_CONFIG_SET 33 -#define PULL_EN_SET 34 -#define HILO_SET 35 -#define SWITCH2FREF 36 -#define FREQ_DRIFT_REPORT 37 - -#define PCE_GET 40 -#define FIRM_VER_GET 41 -#define ASIC_VER_GET 42 -#define ASIC_ID_GET 43 -#define MAN_ID_GET 44 -#define TUNER_MODE_SET 45 -#define STOP_SEARCH 46 -#define RDS_CNTRL_SET 47 - -#define WRITE_HARDWARE_REG 100 -#define CODE_DOWNLOAD 101 -#define RESET 102 - -#define FM_POWER_MODE 254 -#define FM_INTERRUPT 255 - -/* Transmitter API */ - -#define CHANL_SET 55 -#define CHANL_BW_SET 56 -#define REF_SET 57 -#define POWER_ENB_SET 90 -#define POWER_ATT_SET 58 -#define POWER_LEV_SET 59 -#define AUDIO_DEV_SET 60 -#define PILOT_DEV_SET 61 -#define RDS_DEV_SET 62 -#define TX_BAND_SET 65 -#define PUPD_SET 91 -#define AUDIO_IO_SET 63 -#define PREMPH_SET 64 -#define MONO_SET 66 -#define MUTE 92 -#define MPX_LMT_ENABLE 67 -#define PI_SET 93 -#define ECC_SET 69 -#define PTY 70 -#define AF 71 -#define DISPLAY_MODE 74 -#define RDS_REP_SET 77 -#define RDS_CONFIG_DATA_SET 98 -#define RDS_DATA_SET 99 -#define RDS_DATA_ENB 94 -#define TA_SET 78 -#define TP_SET 79 -#define DI_SET 80 -#define MS_SET 81 -#define PS_SCROLL_SPEED 82 -#define TX_AUDIO_LEVEL_TEST 96 -#define TX_AUDIO_LEVEL_TEST_THRESHOLD 73 -#define TX_AUDIO_INPUT_LEVEL_RANGE_SET 54 -#define RX_ANTENNA_SELECT 87 -#define I2C_DEV_ADDR_SET 86 -#define REF_ERR_CALIB_PARAM_SET 88 -#define REF_ERR_CALIB_PERIODICITY_SET 89 -#define SOC_INT_TRIGGER 52 -#define SOC_AUDIO_PATH_SET 83 -#define SOC_PCMI_OVERRIDE 84 -#define SOC_I2S_OVERRIDE 85 -#define RSSI_BLOCK_SCAN_FREQ_SET 95 -#define RSSI_BLOCK_SCAN_START 97 -#define RSSI_BLOCK_SCAN_DATA_GET 5 -#define READ_FMANT_TUNE_VALUE 104 - -/* SKB helpers */ -struct fm_skb_cb { - __u8 fm_op; - struct completion *completion; -}; - -#define fm_cb(skb) ((struct fm_skb_cb *)(skb->cb)) - -/* FM Channel-8 command message format */ -struct fm_cmd_msg_hdr { - __u8 hdr; /* Logical Channel-8 */ - __u8 len; /* Number of bytes follows */ - __u8 op; /* FM Opcode */ - __u8 rd_wr; /* Read/Write command */ - __u8 dlen; /* Length of payload */ -} __attribute__ ((packed)); - -#define FM_CMD_MSG_HDR_SIZE 5 /* sizeof(struct fm_cmd_msg_hdr) */ - -/* FM Channel-8 event messgage format */ -struct fm_event_msg_hdr { - __u8 header; /* Logical Channel-8 */ - __u8 len; /* Number of bytes follows */ - __u8 status; /* Event status */ - __u8 num_fm_hci_cmds; /* Number of pkts the host allowed to send */ - __u8 op; /* FM Opcode */ - __u8 rd_wr; /* Read/Write command */ - __u8 dlen; /* Length of payload */ -} __attribute__ ((packed)); - -#define FM_EVT_MSG_HDR_SIZE 7 /* sizeof(struct fm_event_msg_hdr) */ - -/* TI's magic number in firmware file */ -#define FM_FW_FILE_HEADER_MAGIC 0x42535442 - -#define FM_ENABLE 1 -#define FM_DISABLE 0 - -/* FLAG_GET register bits */ -#define FM_FR_EVENT (1 << 0) -#define FM_BL_EVENT (1 << 1) -#define FM_RDS_EVENT (1 << 2) -#define FM_BBLK_EVENT (1 << 3) -#define FM_LSYNC_EVENT (1 << 4) -#define FM_LEV_EVENT (1 << 5) -#define FM_IFFR_EVENT (1 << 6) -#define FM_PI_EVENT (1 << 7) -#define FM_PD_EVENT (1 << 8) -#define FM_STIC_EVENT (1 << 9) -#define FM_MAL_EVENT (1 << 10) -#define FM_POW_ENB_EVENT (1 << 11) - -/* - * Firmware files of FM. ASIC ID and ASIC version will be appened to this, - * later. - */ -#define FM_FMC_FW_FILE_START ("fmc_ch8") -#define FM_RX_FW_FILE_START ("fm_rx_ch8") -#define FM_TX_FW_FILE_START ("fm_tx_ch8") - -#define FM_UNDEFINED_FREQ 0xFFFFFFFF - -/* Band types */ -#define FM_BAND_EUROPE_US 0 -#define FM_BAND_JAPAN 1 - -/* Seek directions */ -#define FM_SEARCH_DIRECTION_DOWN 0 -#define FM_SEARCH_DIRECTION_UP 1 - -/* Tunner modes */ -#define FM_TUNER_STOP_SEARCH_MODE 0 -#define FM_TUNER_PRESET_MODE 1 -#define FM_TUNER_AUTONOMOUS_SEARCH_MODE 2 -#define FM_TUNER_AF_JUMP_MODE 3 - -/* Min and Max volume */ -#define FM_RX_VOLUME_MIN 0 -#define FM_RX_VOLUME_MAX 70 - -/* Volume gain step */ -#define FM_RX_VOLUME_GAIN_STEP 0x370 - -/* Mute modes */ -#define FM_MUTE_ON 0 -#define FM_MUTE_OFF 1 -#define FM_MUTE_ATTENUATE 2 - -#define FM_RX_UNMUTE_MODE 0x00 -#define FM_RX_RF_DEP_MODE 0x01 -#define FM_RX_AC_MUTE_MODE 0x02 -#define FM_RX_HARD_MUTE_LEFT_MODE 0x04 -#define FM_RX_HARD_MUTE_RIGHT_MODE 0x08 -#define FM_RX_SOFT_MUTE_FORCE_MODE 0x10 - -/* RF dependent mute mode */ -#define FM_RX_RF_DEPENDENT_MUTE_ON 1 -#define FM_RX_RF_DEPENDENT_MUTE_OFF 0 - -/* RSSI threshold min and max */ -#define FM_RX_RSSI_THRESHOLD_MIN -128 -#define FM_RX_RSSI_THRESHOLD_MAX 127 - -/* Stereo/Mono mode */ -#define FM_STEREO_MODE 0 -#define FM_MONO_MODE 1 -#define FM_STEREO_SOFT_BLEND 1 - -/* FM RX De-emphasis filter modes */ -#define FM_RX_EMPHASIS_FILTER_50_USEC 0 -#define FM_RX_EMPHASIS_FILTER_75_USEC 1 - -/* FM RDS modes */ -#define FM_RDS_DISABLE 0 -#define FM_RDS_ENABLE 1 - -#define FM_NO_PI_CODE 0 - -/* FM and RX RDS block enable/disable */ -#define FM_RX_PWR_SET_FM_ON_RDS_OFF 0x1 -#define FM_RX_PWR_SET_FM_AND_RDS_BLK_ON 0x3 -#define FM_RX_PWR_SET_FM_AND_RDS_BLK_OFF 0x0 - -/* RX RDS */ -#define FM_RX_RDS_FLUSH_FIFO 0x1 -#define FM_RX_RDS_FIFO_THRESHOLD 64 /* tuples */ -#define FM_RDS_BLK_SIZE 3 /* 3 bytes */ - -/* RDS block types */ -#define FM_RDS_BLOCK_A 0 -#define FM_RDS_BLOCK_B 1 -#define FM_RDS_BLOCK_C 2 -#define FM_RDS_BLOCK_Ctag 3 -#define FM_RDS_BLOCK_D 4 -#define FM_RDS_BLOCK_E 5 - -#define FM_RDS_BLK_IDX_A 0 -#define FM_RDS_BLK_IDX_B 1 -#define FM_RDS_BLK_IDX_C 2 -#define FM_RDS_BLK_IDX_D 3 -#define FM_RDS_BLK_IDX_UNKNOWN 0xF0 - -#define FM_RDS_STATUS_ERR_MASK 0x18 - -/* - * Represents an RDS group type & version. - * There are 15 groups, each group has 2 versions: A and B. - */ -#define FM_RDS_GROUP_TYPE_MASK_0A ((unsigned long)1<<0) -#define FM_RDS_GROUP_TYPE_MASK_0B ((unsigned long)1<<1) -#define FM_RDS_GROUP_TYPE_MASK_1A ((unsigned long)1<<2) -#define FM_RDS_GROUP_TYPE_MASK_1B ((unsigned long)1<<3) -#define FM_RDS_GROUP_TYPE_MASK_2A ((unsigned long)1<<4) -#define FM_RDS_GROUP_TYPE_MASK_2B ((unsigned long)1<<5) -#define FM_RDS_GROUP_TYPE_MASK_3A ((unsigned long)1<<6) -#define FM_RDS_GROUP_TYPE_MASK_3B ((unsigned long)1<<7) -#define FM_RDS_GROUP_TYPE_MASK_4A ((unsigned long)1<<8) -#define FM_RDS_GROUP_TYPE_MASK_4B ((unsigned long)1<<9) -#define FM_RDS_GROUP_TYPE_MASK_5A ((unsigned long)1<<10) -#define FM_RDS_GROUP_TYPE_MASK_5B ((unsigned long)1<<11) -#define FM_RDS_GROUP_TYPE_MASK_6A ((unsigned long)1<<12) -#define FM_RDS_GROUP_TYPE_MASK_6B ((unsigned long)1<<13) -#define FM_RDS_GROUP_TYPE_MASK_7A ((unsigned long)1<<14) -#define FM_RDS_GROUP_TYPE_MASK_7B ((unsigned long)1<<15) -#define FM_RDS_GROUP_TYPE_MASK_8A ((unsigned long)1<<16) -#define FM_RDS_GROUP_TYPE_MASK_8B ((unsigned long)1<<17) -#define FM_RDS_GROUP_TYPE_MASK_9A ((unsigned long)1<<18) -#define FM_RDS_GROUP_TYPE_MASK_9B ((unsigned long)1<<19) -#define FM_RDS_GROUP_TYPE_MASK_10A ((unsigned long)1<<20) -#define FM_RDS_GROUP_TYPE_MASK_10B ((unsigned long)1<<21) -#define FM_RDS_GROUP_TYPE_MASK_11A ((unsigned long)1<<22) -#define FM_RDS_GROUP_TYPE_MASK_11B ((unsigned long)1<<23) -#define FM_RDS_GROUP_TYPE_MASK_12A ((unsigned long)1<<24) -#define FM_RDS_GROUP_TYPE_MASK_12B ((unsigned long)1<<25) -#define FM_RDS_GROUP_TYPE_MASK_13A ((unsigned long)1<<26) -#define FM_RDS_GROUP_TYPE_MASK_13B ((unsigned long)1<<27) -#define FM_RDS_GROUP_TYPE_MASK_14A ((unsigned long)1<<28) -#define FM_RDS_GROUP_TYPE_MASK_14B ((unsigned long)1<<29) -#define FM_RDS_GROUP_TYPE_MASK_15A ((unsigned long)1<<30) -#define FM_RDS_GROUP_TYPE_MASK_15B ((unsigned long)1<<31) - -/* RX Alternate Frequency info */ -#define FM_RDS_MIN_AF 1 -#define FM_RDS_MAX_AF 204 -#define FM_RDS_MAX_AF_JAPAN 140 -#define FM_RDS_1_AF_FOLLOWS 225 -#define FM_RDS_25_AF_FOLLOWS 249 - -/* RDS system type (RDS/RBDS) */ -#define FM_RDS_SYSTEM_RDS 0 -#define FM_RDS_SYSTEM_RBDS 1 - -/* AF on/off */ -#define FM_RX_RDS_AF_SWITCH_MODE_ON 1 -#define FM_RX_RDS_AF_SWITCH_MODE_OFF 0 - -/* Retry count when interrupt process goes wrong */ -#define FM_IRQ_TIMEOUT_RETRY_MAX 5 /* 5 times */ - -/* Audio IO set values */ -#define FM_RX_AUDIO_ENABLE_I2S 0x01 -#define FM_RX_AUDIO_ENABLE_ANALOG 0x02 -#define FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG 0x03 -#define FM_RX_AUDIO_ENABLE_DISABLE 0x00 - -/* HI/LO set values */ -#define FM_RX_IFFREQ_TO_HI_SIDE 0x0 -#define FM_RX_IFFREQ_TO_LO_SIDE 0x1 -#define FM_RX_IFFREQ_HILO_AUTOMATIC 0x2 - -/* - * Default RX mode configuration. Chip will be configured - * with this default values after loading RX firmware. - */ -#define FM_DEFAULT_RX_VOLUME 10 -#define FM_DEFAULT_RSSI_THRESHOLD 3 - -/* Range for TX power level in units for dB/uV */ -#define FM_PWR_LVL_LOW 91 -#define FM_PWR_LVL_HIGH 122 - -/* Chip specific default TX power level value */ -#define FM_PWR_LVL_DEF 4 - -/* FM TX Pre-emphasis filter values */ -#define FM_TX_PREEMPH_OFF 1 -#define FM_TX_PREEMPH_50US 0 -#define FM_TX_PREEMPH_75US 2 - -/* FM TX antenna impedence values */ -#define FM_TX_ANT_IMP_50 0 -#define FM_TX_ANT_IMP_200 1 -#define FM_TX_ANT_IMP_500 2 - -/* Functions exported by FM common sub-module */ -u32 fmc_prepare(struct fmdev *); -u32 fmc_release(struct fmdev *); - -void fmc_update_region_info(struct fmdev *, u8); -u32 fmc_send_cmd(struct fmdev *, u8, u16, - void *, unsigned int, void *, int *); -u32 fmc_is_rds_data_available(struct fmdev *, struct file *, - struct poll_table_struct *); -u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *, - u8 __user *, size_t); - -u32 fmc_set_freq(struct fmdev *, u32); -u32 fmc_set_mode(struct fmdev *, u8); -u32 fmc_set_region(struct fmdev *, u8); -u32 fmc_set_mute_mode(struct fmdev *, u8); -u32 fmc_set_stereo_mono(struct fmdev *, u16); -u32 fmc_set_rds_mode(struct fmdev *, u8); - -u32 fmc_get_freq(struct fmdev *, u32 *); -u32 fmc_get_region(struct fmdev *, u8 *); -u32 fmc_get_mode(struct fmdev *, u8 *); - -/* - * channel spacing - */ -#define FM_CHANNEL_SPACING_50KHZ 1 -#define FM_CHANNEL_SPACING_100KHZ 2 -#define FM_CHANNEL_SPACING_200KHZ 4 -#define FM_FREQ_MUL 50 - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,244 +0,0 @@ -/* - * FM Driver for Connectivity chip of Texas Instruments. - * - * Common header for all FM driver sub-modules. - * - * Copyright (C) 2011 Texas Instruments - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - * - */ - -#ifndef _FM_DRV_H -#define _FM_DRV_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FM_DRV_VERSION "0.10" -/* Should match with FM_DRV_VERSION */ -#define FM_DRV_RADIO_VERSION KERNEL_VERSION(0, 0, 1) -#define FM_DRV_NAME "ti_fmdrv" -#define FM_DRV_CARD_SHORT_NAME "TI FM Radio" -#define FM_DRV_CARD_LONG_NAME "Texas Instruments FM Radio" - -/* Flag info */ -#define FM_INTTASK_RUNNING 0 -#define FM_INTTASK_SCHEDULE_PENDING 1 -#define FM_FW_DW_INPROGRESS 2 -#define FM_CORE_READY 3 -#define FM_CORE_TRANSPORT_READY 4 -#define FM_AF_SWITCH_INPROGRESS 5 -#define FM_CORE_TX_XMITING 6 - -#define FM_TUNE_COMPLETE 0x1 -#define FM_BAND_LIMIT 0x2 - -#define FM_DRV_TX_TIMEOUT (5*HZ) /* 5 seconds */ -#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */ - -#define NO_OF_ENTRIES_IN_ARRAY(array) (sizeof(array) / sizeof(array[0])) - -#define fmerr(format, ...) \ - printk(KERN_ERR "fmdrv: " format, ## __VA_ARGS__) -#define fmwarn(format, ...) \ - printk(KERN_WARNING "fmdrv: " format, ##__VA_ARGS__) -#ifdef DEBUG -#define fmdbg(format, ...) \ - printk(KERN_DEBUG "fmdrv: " format, ## __VA_ARGS__) -#else /* DEBUG */ -#define fmdbg(format, ...) -#endif -enum { - FM_MODE_OFF, - FM_MODE_TX, - FM_MODE_RX, - FM_MODE_ENTRY_MAX -}; - -#define FM_RX_RDS_INFO_FIELD_MAX 8 /* 4 Group * 2 Bytes */ - -/* RX RDS data format */ -struct fm_rdsdata_format { - union { - struct { - u8 buff[FM_RX_RDS_INFO_FIELD_MAX]; - } groupdatabuff; - struct { - u16 pidata; - u8 blk_b[2]; - u8 blk_c[2]; - u8 blk_d[2]; - } groupgeneral; - struct { - u16 pidata; - u8 blk_b[2]; - u8 af[2]; - u8 ps[2]; - } group0A; - struct { - u16 pi[2]; - u8 blk_b[2]; - u8 ps[2]; - } group0B; - } data; -}; - -/* FM region (Europe/US, Japan) info */ -struct region_info { - u32 chanl_space; - u32 bot_freq; - u32 top_freq; - u8 fm_band; -}; -struct fmdev; -typedef void (*int_handler_prototype) (struct fmdev *); - -/* FM Interrupt processing related info */ -struct fm_irq { - u8 stage; - u16 flag; /* FM interrupt flag */ - u16 mask; /* FM interrupt mask */ - /* Interrupt process timeout handler */ - struct timer_list timer; - u8 retry; - int_handler_prototype *handlers; -}; - -/* RDS info */ -struct fm_rds { - u8 flag; /* RX RDS on/off status */ - u8 last_blk_idx; /* Last received RDS block */ - - /* RDS buffer */ - wait_queue_head_t read_queue; - u32 buf_size; /* Size is always multiple of 3 */ - u32 wr_idx; - u32 rd_idx; - u8 *buff; -}; - -#define FM_RDS_MAX_AF_LIST 25 - -/* - * Current RX channel Alternate Frequency cache. - * This info is used to switch to other freq (AF) - * when current channel signal strengh is below RSSI threshold. - */ -struct tuned_station_info { - u16 picode; - u32 af_cache[FM_RDS_MAX_AF_LIST]; - u8 afcache_size; - u8 af_list_max; -}; - -/* FM RX mode info */ -struct fm_rx { - struct region_info region; /* Current selected band */ - u32 freq; /* Current RX frquency */ - u8 mute_mode; /* Current mute mode */ - u8 deemphasis_mode; /* Current deemphasis mode */ - /* RF dependent soft mute mode */ - u8 rf_depend_mute; - u16 volume; /* Current volume level */ - u16 rssi_threshold; /* Current RSSI threshold level */ - /* Holds the index of the current AF jump */ - u8 afjump_idx; - /* Will hold the frequency before the jump */ - u32 freq_before_jump; - u8 rds_mode; /* RDS operation mode (RDS/RDBS) */ - u8 af_mode; /* Alternate frequency on/off */ - struct tuned_station_info stat_info; - struct fm_rds rds; -}; - -#define FMTX_RDS_TXT_STR_SIZE 25 -/* - * FM TX RDS data - * - * @ text_type: is the text following PS or RT - * @ text: radio text string which could either be PS or RT - * @ af_freq: alternate frequency for Tx - * TODO: to be declared in application - */ -struct tx_rds { - u8 text_type; - u8 text[FMTX_RDS_TXT_STR_SIZE]; - u8 flag; - u32 af_freq; -}; -/* - * FM TX global data - * - * @ pwr_lvl: Power Level of the Transmission from mixer control - * @ xmit_state: Transmission state = Updated locally upon Start/Stop - * @ audio_io: i2S/Analog - * @ tx_frq: Transmission frequency - */ -struct fmtx_data { - u8 pwr_lvl; - u8 xmit_state; - u8 audio_io; - u8 region; - u16 aud_mode; - u32 preemph; - u32 tx_frq; - struct tx_rds rds; -}; - -/* FM driver operation structure */ -struct fmdev { - struct video_device *radio_dev; /* V4L2 video device pointer */ - struct snd_card *card; /* Card which holds FM mixer controls */ - u16 asci_id; - spinlock_t rds_buff_lock; /* To protect access to RDS buffer */ - spinlock_t resp_skb_lock; /* To protect access to received SKB */ - - long flag; /* FM driver state machine info */ - u8 streg_cbdata; /* status of ST registration */ - - struct sk_buff_head rx_q; /* RX queue */ - struct tasklet_struct rx_task; /* RX Tasklet */ - - struct sk_buff_head tx_q; /* TX queue */ - struct tasklet_struct tx_task; /* TX Tasklet */ - unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */ - atomic_t tx_cnt; /* Number of packets can send at a time */ - - struct sk_buff *resp_skb; /* Response from the chip */ - /* Main task completion handler */ - struct completion maintask_comp; - /* Opcode of last command sent to the chip */ - u8 pre_op; - /* Handler used for wakeup when response packet is received */ - struct completion *resp_comp; - struct fm_irq irq_info; - u8 curr_fmmode; /* Current FM chip mode (TX, RX, OFF) */ - struct fm_rx rx; /* FM receiver info */ - struct fmtx_data tx_data; - - /* V4L2 ctrl framwork handler*/ - struct v4l2_ctrl_handler ctrl_handler; - - /* For core assisted locking */ - struct mutex mutex; -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_rx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_rx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_rx.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_rx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,847 +0,0 @@ -/* - * FM Driver for Connectivity chip of Texas Instruments. - * This sub-module of FM driver implements FM RX functionality. - * - * Copyright (C) 2011 Texas Instruments - * Author: Raja Mani - * Author: Manjunatha Halli - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 "fmdrv.h" -#include "fmdrv_common.h" -#include "fmdrv_rx.h" - -void fm_rx_reset_rds_cache(struct fmdev *fmdev) -{ - fmdev->rx.rds.flag = FM_RDS_DISABLE; - fmdev->rx.rds.last_blk_idx = 0; - fmdev->rx.rds.wr_idx = 0; - fmdev->rx.rds.rd_idx = 0; - - if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) - fmdev->irq_info.mask |= FM_LEV_EVENT; -} - -void fm_rx_reset_station_info(struct fmdev *fmdev) -{ - fmdev->rx.stat_info.picode = FM_NO_PI_CODE; - fmdev->rx.stat_info.afcache_size = 0; - fmdev->rx.stat_info.af_list_max = 0; -} - -u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq) -{ - unsigned long timeleft; - u16 payload, curr_frq, intr_flag; - u32 curr_frq_in_khz; - u32 ret, resp_len; - - if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) { - fmerr("Invalid frequency %d\n", freq); - return -EINVAL; - } - - /* Set audio enable */ - payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG; - - ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Set hilo to automatic selection */ - payload = FM_RX_IFFREQ_HILO_AUTOMATIC; - ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Calculate frequency index and set*/ - payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; - - ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Read flags - just to clear any pending interrupts if we had */ - ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); - if (ret < 0) - return ret; - - /* Enable FR, BL interrupts */ - intr_flag = fmdev->irq_info.mask; - fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); - payload = fmdev->irq_info.mask; - ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Start tune */ - payload = FM_TUNER_PRESET_MODE; - ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - goto exit; - - /* Wait for tune ended interrupt */ - init_completion(&fmdev->maintask_comp); - timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, - FM_DRV_TX_TIMEOUT); - if (!timeleft) { - fmerr("Timeout(%d sec),didn't get tune ended int\n", - jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); - ret = -ETIMEDOUT; - goto exit; - } - - /* Read freq back to confirm */ - ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len); - if (ret < 0) - goto exit; - - curr_frq = be16_to_cpu(curr_frq); - curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL)); - - if (curr_frq_in_khz != freq) { - pr_info("Frequency is set to (%d) but " - "requested freq is (%d)\n", curr_frq_in_khz, freq); - } - - /* Update local cache */ - fmdev->rx.freq = curr_frq_in_khz; -exit: - /* Re-enable default FM interrupts */ - fmdev->irq_info.mask = intr_flag; - payload = fmdev->irq_info.mask; - ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Reset RDS cache and current station pointers */ - fm_rx_reset_rds_cache(fmdev); - fm_rx_reset_station_info(fmdev); - - return ret; -} - -static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) -{ - u16 payload; - u32 ret; - - if (spacing > 0 && spacing <= 50000) - spacing = FM_CHANNEL_SPACING_50KHZ; - else if (spacing > 50000 && spacing <= 100000) - spacing = FM_CHANNEL_SPACING_100KHZ; - else - spacing = FM_CHANNEL_SPACING_200KHZ; - - /* set channel spacing */ - payload = spacing; - ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL; - - return ret; -} - -u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, - u32 wrap_around, u32 spacing) -{ - u32 resp_len; - u16 curr_frq, next_frq, last_frq; - u16 payload, int_reason, intr_flag; - u16 offset, space_idx; - unsigned long timeleft; - u32 ret; - - /* Set channel spacing */ - ret = fm_rx_set_channel_spacing(fmdev, spacing); - if (ret < 0) { - fmerr("Failed to set channel spacing\n"); - return ret; - } - - /* Read the current frequency from chip */ - ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, - sizeof(curr_frq), &curr_frq, &resp_len); - if (ret < 0) - return ret; - - curr_frq = be16_to_cpu(curr_frq); - last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; - - /* Check the offset in order to be aligned to the channel spacing*/ - space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL; - offset = curr_frq % space_idx; - - next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ : - curr_frq - space_idx /* Seek Down */ ; - - /* - * Add or subtract offset in order to stay aligned to the channel - * spacing. - */ - if ((short)next_frq < 0) - next_frq = last_frq - offset; - else if (next_frq > last_frq) - next_frq = 0 + offset; - -again: - /* Set calculated next frequency to perform seek */ - payload = next_frq; - ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Set search direction (0:Seek Down, 1:Seek Up) */ - payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN); - ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Read flags - just to clear any pending interrupts if we had */ - ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); - if (ret < 0) - return ret; - - /* Enable FR, BL interrupts */ - intr_flag = fmdev->irq_info.mask; - fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); - payload = fmdev->irq_info.mask; - ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Start seek */ - payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE; - ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Wait for tune ended/band limit reached interrupt */ - init_completion(&fmdev->maintask_comp); - timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, - FM_DRV_RX_SEEK_TIMEOUT); - if (!timeleft) { - fmerr("Timeout(%d sec),didn't get tune ended int\n", - jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000); - return -ETIMEDOUT; - } - - int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT); - - /* Re-enable default FM interrupts */ - fmdev->irq_info.mask = intr_flag; - payload = fmdev->irq_info.mask; - ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - if (int_reason & FM_BL_EVENT) { - if (wrap_around == 0) { - fmdev->rx.freq = seek_upward ? - fmdev->rx.region.top_freq : - fmdev->rx.region.bot_freq; - } else { - fmdev->rx.freq = seek_upward ? - fmdev->rx.region.bot_freq : - fmdev->rx.region.top_freq; - /* Calculate frequency index to write */ - next_frq = (fmdev->rx.freq - - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; - goto again; - } - } else { - /* Read freq to know where operation tune operation stopped */ - ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, - &curr_frq, &resp_len); - if (ret < 0) - return ret; - - curr_frq = be16_to_cpu(curr_frq); - fmdev->rx.freq = (fmdev->rx.region.bot_freq + - ((u32)curr_frq * FM_FREQ_MUL)); - - } - /* Reset RDS cache and current station pointers */ - fm_rx_reset_rds_cache(fmdev); - fm_rx_reset_station_info(fmdev); - - return ret; -} - -u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) -{ - u16 payload; - u32 ret; - - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) { - fmerr("Volume is not within(%d-%d) range\n", - FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX); - return -EINVAL; - } - vol_to_set *= FM_RX_VOLUME_GAIN_STEP; - - payload = vol_to_set; - ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - fmdev->rx.volume = vol_to_set; - return ret; -} - -/* Get volume */ -u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) -{ - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (curr_vol == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP; - - return 0; -} - -/* To get current band's bottom and top frequency */ -u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) -{ - if (bot_freq != NULL) - *bot_freq = fmdev->rx.region.bot_freq; - - if (top_freq != NULL) - *top_freq = fmdev->rx.region.top_freq; - - return 0; -} - -/* Returns current band index (0-Europe/US; 1-Japan) */ -void fm_rx_get_region(struct fmdev *fmdev, u8 *region) -{ - *region = fmdev->rx.region.fm_band; -} - -/* Sets band (0-Europe/US; 1-Japan) */ -u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) -{ - u16 payload; - u32 new_frq = 0; - u32 ret; - - if (region_to_set != FM_BAND_EUROPE_US && - region_to_set != FM_BAND_JAPAN) { - fmerr("Invalid band\n"); - return -EINVAL; - } - - if (fmdev->rx.region.fm_band == region_to_set) { - fmerr("Requested band is already configured\n"); - return 0; - } - - /* Send cmd to set the band */ - payload = (u16)region_to_set; - ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - fmc_update_region_info(fmdev, region_to_set); - - /* Check whether current RX frequency is within band boundary */ - if (fmdev->rx.freq < fmdev->rx.region.bot_freq) - new_frq = fmdev->rx.region.bot_freq; - else if (fmdev->rx.freq > fmdev->rx.region.top_freq) - new_frq = fmdev->rx.region.top_freq; - - if (new_frq) { - fmdbg("Current freq is not within band limit boundary," - "switching to %d KHz\n", new_frq); - /* Current RX frequency is not in range. So, update it */ - ret = fm_rx_set_freq(fmdev, new_frq); - } - - return ret; -} - -/* Reads current mute mode (Mute Off/On/Attenuate)*/ -u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) -{ - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (curr_mute_mode == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *curr_mute_mode = fmdev->rx.mute_mode; - - return 0; -} - -static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) -{ - u16 payload, muteval; - u32 ret; - - muteval = 0; - switch (fmdev->rx.mute_mode) { - case FM_MUTE_ON: - muteval = FM_RX_AC_MUTE_MODE; - break; - - case FM_MUTE_OFF: - muteval = FM_RX_UNMUTE_MODE; - break; - - case FM_MUTE_ATTENUATE: - muteval = FM_RX_SOFT_MUTE_FORCE_MODE; - break; - } - if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON) - muteval |= FM_RX_RF_DEP_MODE; - else - muteval &= ~FM_RX_RF_DEP_MODE; - - payload = muteval; - ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - return 0; -} - -/* Configures mute mode (Mute Off/On/Attenuate) */ -u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) -{ - u8 org_state; - u32 ret; - - if (fmdev->rx.mute_mode == mute_mode_toset) - return 0; - - org_state = fmdev->rx.mute_mode; - fmdev->rx.mute_mode = mute_mode_toset; - - ret = fm_config_rx_mute_reg(fmdev); - if (ret < 0) { - fmdev->rx.mute_mode = org_state; - return ret; - } - - return 0; -} - -/* Gets RF dependent soft mute mode enable/disable status */ -u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) -{ - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (curr_mute_mode == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *curr_mute_mode = fmdev->rx.rf_depend_mute; - - return 0; -} - -/* Sets RF dependent soft mute mode */ -u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) -{ - u8 org_state; - u32 ret; - - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON && - rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) { - fmerr("Invalid RF dependent soft mute\n"); - return -EINVAL; - } - if (fmdev->rx.rf_depend_mute == rfdepend_mute) - return 0; - - org_state = fmdev->rx.rf_depend_mute; - fmdev->rx.rf_depend_mute = rfdepend_mute; - - ret = fm_config_rx_mute_reg(fmdev); - if (ret < 0) { - fmdev->rx.rf_depend_mute = org_state; - return ret; - } - - return 0; -} - -/* Returns the signal strength level of current channel */ -u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) -{ - u16 curr_rssi_lel; - u32 resp_len; - u32 ret; - - if (rssilvl == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - /* Read current RSSI level */ - ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2, - &curr_rssi_lel, &resp_len); - if (ret < 0) - return ret; - - *rssilvl = be16_to_cpu(curr_rssi_lel); - - return 0; -} - -/* - * Sets the signal strength level that once reached - * will stop the auto search process - */ -u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) -{ - u16 payload; - u32 ret; - - if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN || - rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) { - fmerr("Invalid RSSI threshold level\n"); - return -EINVAL; - } - payload = (u16)rssi_lvl_toset; - ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - fmdev->rx.rssi_threshold = rssi_lvl_toset; - - return 0; -} - -/* Returns current RX RSSI threshold value */ -u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) -{ - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (curr_rssi_lvl == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *curr_rssi_lvl = fmdev->rx.rssi_threshold; - - return 0; -} - -/* Sets RX stereo/mono modes */ -u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) -{ - u16 payload; - u32 ret; - - if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) { - fmerr("Invalid mode\n"); - return -EINVAL; - } - - /* Set stereo/mono mode */ - payload = (u16)mode; - ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Set stereo blending mode */ - payload = FM_STEREO_SOFT_BLEND; - ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - return 0; -} - -/* Gets current RX stereo/mono mode */ -u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) -{ - u16 curr_mode; - u32 ret, resp_len; - - if (mode == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2, - &curr_mode, &resp_len); - if (ret < 0) - return ret; - - *mode = be16_to_cpu(curr_mode); - - return 0; -} - -/* Choose RX de-emphasis filter mode (50us/75us) */ -u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) -{ - u16 payload; - u32 ret; - - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (mode != FM_RX_EMPHASIS_FILTER_50_USEC && - mode != FM_RX_EMPHASIS_FILTER_75_USEC) { - fmerr("Invalid rx de-emphasis mode (%d)\n", mode); - return -EINVAL; - } - - payload = mode; - ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - fmdev->rx.deemphasis_mode = mode; - - return 0; -} - -/* Gets current RX de-emphasis filter mode */ -u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) -{ - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (curr_deemphasis_mode == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *curr_deemphasis_mode = fmdev->rx.deemphasis_mode; - - return 0; -} - -/* Enable/Disable RX RDS */ -u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) -{ - u16 payload; - u32 ret; - - if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) { - fmerr("Invalid rds option\n"); - return -EINVAL; - } - - if (rds_en_dis == FM_RDS_ENABLE - && fmdev->rx.rds.flag == FM_RDS_DISABLE) { - /* Turn on RX RDS and RDS circuit */ - payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON; - ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Clear and reset RDS FIFO */ - payload = FM_RX_RDS_FLUSH_FIFO; - ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Read flags - just to clear any pending interrupts. */ - ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, - NULL, NULL); - if (ret < 0) - return ret; - - /* Set RDS FIFO threshold value */ - payload = FM_RX_RDS_FIFO_THRESHOLD; - ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Enable RDS interrupt */ - fmdev->irq_info.mask |= FM_RDS_EVENT; - payload = fmdev->irq_info.mask; - ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) { - fmdev->irq_info.mask &= ~FM_RDS_EVENT; - return ret; - } - - /* Update our local flag */ - fmdev->rx.rds.flag = FM_RDS_ENABLE; - } else if (rds_en_dis == FM_RDS_DISABLE - && fmdev->rx.rds.flag == FM_RDS_ENABLE) { - /* Turn off RX RDS */ - payload = FM_RX_PWR_SET_FM_ON_RDS_OFF; - ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Reset RDS pointers */ - fmdev->rx.rds.last_blk_idx = 0; - fmdev->rx.rds.wr_idx = 0; - fmdev->rx.rds.rd_idx = 0; - fm_rx_reset_station_info(fmdev); - - /* Update RDS local cache */ - fmdev->irq_info.mask &= ~(FM_RDS_EVENT); - fmdev->rx.rds.flag = FM_RDS_DISABLE; - } - - return 0; -} - -/* Returns current RX RDS enable/disable status */ -u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) -{ - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (curr_rds_en_dis == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *curr_rds_en_dis = fmdev->rx.rds.flag; - - return 0; -} - -/* Sets RDS operation mode (RDS/RDBS) */ -u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) -{ - u16 payload; - u32 ret; - - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) { - fmerr("Invalid rds mode\n"); - return -EINVAL; - } - /* Set RDS operation mode */ - payload = (u16)rds_mode; - ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - fmdev->rx.rds_mode = rds_mode; - - return 0; -} - -/* Returns current RDS operation mode */ -u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) -{ - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (rds_mode == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *rds_mode = fmdev->rx.rds_mode; - - return 0; -} - -/* Configures Alternate Frequency switch mode */ -u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) -{ - u16 payload; - u32 ret; - - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON && - af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) { - fmerr("Invalid af mode\n"); - return -EINVAL; - } - /* Enable/disable low RSSI interrupt based on af_mode */ - if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) - fmdev->irq_info.mask |= FM_LEV_EVENT; - else - fmdev->irq_info.mask &= ~FM_LEV_EVENT; - - payload = fmdev->irq_info.mask; - ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - fmdev->rx.af_mode = af_mode; - - return 0; -} - -/* Returns Alternate Frequency switch status */ -u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) -{ - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (af_mode == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *af_mode = fmdev->rx.af_mode; - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_rx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_rx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_rx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_rx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -/* - * FM Driver for Connectivity chip of Texas Instruments. - * FM RX module header. - * - * Copyright (C) 2011 Texas Instruments - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - * - */ - -#ifndef _FMDRV_RX_H -#define _FMDRV_RX_H - -u32 fm_rx_set_freq(struct fmdev *, u32); -u32 fm_rx_set_mute_mode(struct fmdev *, u8); -u32 fm_rx_set_stereo_mono(struct fmdev *, u16); -u32 fm_rx_set_rds_mode(struct fmdev *, u8); -u32 fm_rx_set_rds_system(struct fmdev *, u8); -u32 fm_rx_set_volume(struct fmdev *, u16); -u32 fm_rx_set_rssi_threshold(struct fmdev *, short); -u32 fm_rx_set_region(struct fmdev *, u8); -u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8); -u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16); -u32 fm_rx_set_af_switch(struct fmdev *, u8); - -void fm_rx_reset_rds_cache(struct fmdev *); -void fm_rx_reset_station_info(struct fmdev *); - -u32 fm_rx_seek(struct fmdev *, u32, u32, u32); - -u32 fm_rx_get_rds_mode(struct fmdev *, u8 *); -u32 fm_rx_get_rds_system(struct fmdev *, u8 *); -u32 fm_rx_get_mute_mode(struct fmdev *, u8 *); -u32 fm_rx_get_volume(struct fmdev *, u16 *); -u32 fm_rx_get_band_freq_range(struct fmdev *, - u32 *, u32 *); -u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *); -u32 fm_rx_get_rssi_level(struct fmdev *, u16 *); -u32 fm_rx_get_rssi_threshold(struct fmdev *, short *); -u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *); -u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *); -u32 fm_rx_get_af_switch(struct fmdev *, u8 *); -void fm_rx_get_region(struct fmdev *, u8 *); - -u32 fm_rx_set_chanl_spacing(struct fmdev *, u8); -u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *); -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_tx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_tx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_tx.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_tx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,425 +0,0 @@ -/* - * FM Driver for Connectivity chip of Texas Instruments. - * This sub-module of FM driver implements FM TX functionality. - * - * Copyright (C) 2011 Texas Instruments - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 -#include "fmdrv.h" -#include "fmdrv_common.h" -#include "fmdrv_tx.h" - -u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) -{ - u16 payload; - u32 ret; - - if (fmdev->tx_data.aud_mode == mode) - return 0; - - fmdbg("stereo mode: %d\n", mode); - - /* Set Stereo/Mono mode */ - payload = (1 - mode); - ret = fmc_send_cmd(fmdev, MONO_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - fmdev->tx_data.aud_mode = mode; - - return ret; -} - -static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text) -{ - u16 payload; - u32 ret; - - ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text, - strlen(rds_text), NULL, NULL); - if (ret < 0) - return ret; - - /* Scroll mode */ - payload = (u16)0x1; - ret = fmc_send_cmd(fmdev, DISPLAY_MODE, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - return 0; -} - -static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode) -{ - u16 payload; - u32 ret; - - /* Setting unique PI TODO: how unique? */ - payload = (u16)0xcafe; - ret = fmc_send_cmd(fmdev, PI_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Set decoder id */ - payload = (u16)0xa; - ret = fmc_send_cmd(fmdev, DI_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* TODO: RDS_MODE_GET? */ - return 0; -} - -static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len) -{ - u16 payload; - u32 ret; - - len |= type << 8; - payload = len; - ret = fmc_send_cmd(fmdev, RDS_CONFIG_DATA_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* TODO: LENGTH_GET? */ - return 0; -} - -u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) -{ - u16 payload; - u32 ret; - u8 rds_text[] = "Zoom2\n"; - - fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis, - FM_RDS_ENABLE, FM_RDS_DISABLE); - - if (rds_en_dis == FM_RDS_ENABLE) { - /* Set RDS length */ - set_rds_len(fmdev, 0, strlen(rds_text)); - - /* Set RDS text */ - set_rds_text(fmdev, rds_text); - - /* Set RDS mode */ - set_rds_data_mode(fmdev, 0x0); - } - - /* Send command to enable RDS */ - if (rds_en_dis == FM_RDS_ENABLE) - payload = 0x01; - else - payload = 0x00; - - ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - if (rds_en_dis == FM_RDS_ENABLE) { - /* Set RDS length */ - set_rds_len(fmdev, 0, strlen(rds_text)); - - /* Set RDS text */ - set_rds_text(fmdev, rds_text); - } - fmdev->tx_data.rds.flag = rds_en_dis; - - return 0; -} - -u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) -{ - u16 payload; - u32 ret; - - if (fmdev->curr_fmmode != FM_MODE_TX) - return -EPERM; - - fm_tx_set_rds_mode(fmdev, 0); - - /* Set RDS length */ - set_rds_len(fmdev, rds_type, strlen(rds_text)); - - /* Set RDS text */ - set_rds_text(fmdev, rds_text); - - /* Set RDS mode */ - set_rds_data_mode(fmdev, 0x0); - - payload = 1; - ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - return 0; -} - -u32 fm_tx_set_af(struct fmdev *fmdev, u32 af) -{ - u16 payload; - u32 ret; - - if (fmdev->curr_fmmode != FM_MODE_TX) - return -EPERM; - - fmdbg("AF: %d\n", af); - - af = (af - 87500) / 100; - payload = (u16)af; - ret = fmc_send_cmd(fmdev, TA_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - return 0; -} - -u32 fm_tx_set_region(struct fmdev *fmdev, u8 region) -{ - u16 payload; - u32 ret; - - if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) { - fmerr("Invalid band\n"); - return -EINVAL; - } - - /* Send command to set the band */ - payload = (u16)region; - ret = fmc_send_cmd(fmdev, TX_BAND_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - return 0; -} - -u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) -{ - u16 payload; - u32 ret; - - fmdbg("tx: mute mode %d\n", mute_mode_toset); - - payload = mute_mode_toset; - ret = fmc_send_cmd(fmdev, MUTE, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - return 0; -} - -/* Set TX Audio I/O */ -static u32 set_audio_io(struct fmdev *fmdev) -{ - struct fmtx_data *tx = &fmdev->tx_data; - u16 payload; - u32 ret; - - /* Set Audio I/O Enable */ - payload = tx->audio_io; - ret = fmc_send_cmd(fmdev, AUDIO_IO_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* TODO: is audio set? */ - return 0; -} - -/* Start TX Transmission */ -static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) -{ - struct fmtx_data *tx = &fmdev->tx_data; - unsigned long timeleft; - u16 payload; - u32 ret; - - /* Enable POWER_ENB interrupts */ - payload = FM_POW_ENB_EVENT; - ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Set Power Enable */ - payload = new_xmit_state; - ret = fmc_send_cmd(fmdev, POWER_ENB_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* Wait for Power Enabled */ - init_completion(&fmdev->maintask_comp); - timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, - FM_DRV_TX_TIMEOUT); - if (!timeleft) { - fmerr("Timeout(%d sec),didn't get tune ended interrupt\n", - jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); - return -ETIMEDOUT; - } - - set_bit(FM_CORE_TX_XMITING, &fmdev->flag); - tx->xmit_state = new_xmit_state; - - return 0; -} - -/* Set TX power level */ -u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) -{ - u16 payload; - struct fmtx_data *tx = &fmdev->tx_data; - u32 ret; - - if (fmdev->curr_fmmode != FM_MODE_TX) - return -EPERM; - fmdbg("tx: pwr_level_to_set %ld\n", (long int)new_pwr_lvl); - - /* If the core isn't ready update global variable */ - if (!test_bit(FM_CORE_READY, &fmdev->flag)) { - tx->pwr_lvl = new_pwr_lvl; - return 0; - } - - /* Set power level: Application will specify power level value in - * units of dB/uV, whereas range and step are specific to FM chip. - * For TI's WL chips, convert application specified power level value - * to chip specific value by subtracting 122 from it. Refer to TI FM - * data sheet for details. - * */ - - payload = (FM_PWR_LVL_HIGH - new_pwr_lvl); - ret = fmc_send_cmd(fmdev, POWER_LEV_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - /* TODO: is the power level set? */ - tx->pwr_lvl = new_pwr_lvl; - - return 0; -} - -/* - * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us) - * Convert V4L2 specified filter values to chip specific filter values. - */ -u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) -{ - struct fmtx_data *tx = &fmdev->tx_data; - u16 payload; - u32 ret; - - if (fmdev->curr_fmmode != FM_MODE_TX) - return -EPERM; - - switch (preemphasis) { - case V4L2_PREEMPHASIS_DISABLED: - payload = FM_TX_PREEMPH_OFF; - break; - case V4L2_PREEMPHASIS_50_uS: - payload = FM_TX_PREEMPH_50US; - break; - case V4L2_PREEMPHASIS_75_uS: - payload = FM_TX_PREEMPH_75US; - break; - } - - ret = fmc_send_cmd(fmdev, PREMPH_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - tx->preemph = payload; - - return ret; -} - -/* Get the TX tuning capacitor value.*/ -u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev) -{ - u16 curr_val; - u32 ret, resp_len; - - if (fmdev->curr_fmmode != FM_MODE_TX) - return -EPERM; - - ret = fmc_send_cmd(fmdev, READ_FMANT_TUNE_VALUE, REG_RD, - NULL, sizeof(curr_val), &curr_val, &resp_len); - if (ret < 0) - return ret; - - curr_val = be16_to_cpu(curr_val); - - return curr_val; -} - -/* Set TX Frequency */ -u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) -{ - struct fmtx_data *tx = &fmdev->tx_data; - u16 payload, chanl_index; - u32 ret; - - if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) { - enable_xmit(fmdev, 0); - clear_bit(FM_CORE_TX_XMITING, &fmdev->flag); - } - - /* Enable FR, BL interrupts */ - payload = (FM_FR_EVENT | FM_BL_EVENT); - ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - tx->tx_frq = (unsigned long)freq_to_set; - fmdbg("tx: freq_to_set %ld\n", (long int)tx->tx_frq); - - chanl_index = freq_to_set / 10; - - /* Set current tuner channel */ - payload = chanl_index; - ret = fmc_send_cmd(fmdev, CHANL_SET, REG_WR, &payload, - sizeof(payload), NULL, NULL); - if (ret < 0) - return ret; - - fm_tx_set_pwr_lvl(fmdev, tx->pwr_lvl); - fm_tx_set_preemph_filter(fmdev, tx->preemph); - - tx->audio_io = 0x01; /* I2S */ - set_audio_io(fmdev); - - enable_xmit(fmdev, 0x01); /* Enable transmission */ - - tx->aud_mode = FM_STEREO_MODE; - tx->rds.flag = FM_RDS_DISABLE; - - return 0; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_tx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_tx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_tx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_tx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* - * FM Driver for Connectivity chip of Texas Instruments. - * FM TX module header. - * - * Copyright (C) 2011 Texas Instruments - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - * - */ - -#ifndef _FMDRV_TX_H -#define _FMDRV_TX_H - -u32 fm_tx_set_freq(struct fmdev *, u32); -u32 fm_tx_set_pwr_lvl(struct fmdev *, u8); -u32 fm_tx_set_region(struct fmdev *, u8); -u32 fm_tx_set_mute_mode(struct fmdev *, u8); -u32 fm_tx_set_stereo_mono(struct fmdev *, u16); -u32 fm_tx_set_rds_mode(struct fmdev *, u8); -u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8); -u32 fm_tx_set_af(struct fmdev *, u32); -u32 fm_tx_set_preemph_filter(struct fmdev *, u32); -u32 fm_tx_get_tune_cap_val(struct fmdev *); - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_v4l2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_v4l2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_v4l2.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_v4l2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,580 +0,0 @@ -/* - * FM Driver for Connectivity chip of Texas Instruments. - * This file provides interfaces to V4L2 subsystem. - * - * This module registers with V4L2 subsystem as Radio - * data system interface (/dev/radio). During the registration, - * it will expose two set of function pointers. - * - * 1) File operation related API (open, close, read, write, poll...etc). - * 2) Set of V4L2 IOCTL complaint API. - * - * Copyright (C) 2011 Texas Instruments - * Author: Raja Mani - * Author: Manjunatha Halli - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 "fmdrv.h" -#include "fmdrv_v4l2.h" -#include "fmdrv_common.h" -#include "fmdrv_rx.h" -#include "fmdrv_tx.h" - -static struct video_device *gradio_dev; -static u8 radio_disconnected; - -/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */ - -/* Read RX RDS data */ -static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf, - size_t count, loff_t *ppos) -{ - u8 rds_mode; - int ret; - struct fmdev *fmdev; - - fmdev = video_drvdata(file); - - if (!radio_disconnected) { - fmerr("FM device is already disconnected\n"); - return -EIO; - } - - /* Turn on RDS mode , if it is disabled */ - ret = fm_rx_get_rds_mode(fmdev, &rds_mode); - if (ret < 0) { - fmerr("Unable to read current rds mode\n"); - return ret; - } - - if (rds_mode == FM_RDS_DISABLE) { - ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE); - if (ret < 0) { - fmerr("Failed to enable rds mode\n"); - return ret; - } - } - - /* Copy RDS data from internal buffer to user buffer */ - return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count); -} - -/* Write TX RDS data */ -static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf, - size_t count, loff_t *ppos) -{ - struct tx_rds rds; - int ret; - struct fmdev *fmdev; - - ret = copy_from_user(&rds, buf, sizeof(rds)); - fmdbg("(%d)type: %d, text %s, af %d\n", - ret, rds.text_type, rds.text, rds.af_freq); - - fmdev = video_drvdata(file); - fm_tx_set_radio_text(fmdev, rds.text, rds.text_type); - fm_tx_set_af(fmdev, rds.af_freq); - - return 0; -} - -static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts) -{ - int ret; - struct fmdev *fmdev; - - fmdev = video_drvdata(file); - ret = fmc_is_rds_data_available(fmdev, file, pts); - if (ret < 0) - return POLLIN | POLLRDNORM; - - return 0; -} - -/* - * Handle open request for "/dev/radioX" device. - * Start with FM RX mode as default. - */ -static int fm_v4l2_fops_open(struct file *file) -{ - int ret; - struct fmdev *fmdev = NULL; - - /* Don't allow multiple open */ - if (radio_disconnected) { - fmerr("FM device is already opened\n"); - return -EBUSY; - } - - fmdev = video_drvdata(file); - - ret = fmc_prepare(fmdev); - if (ret < 0) { - fmerr("Unable to prepare FM CORE\n"); - return ret; - } - - fmdbg("Load FM RX firmware..\n"); - - ret = fmc_set_mode(fmdev, FM_MODE_RX); - if (ret < 0) { - fmerr("Unable to load FM RX firmware\n"); - return ret; - } - radio_disconnected = 1; - - return ret; -} - -static int fm_v4l2_fops_release(struct file *file) -{ - int ret; - struct fmdev *fmdev; - - fmdev = video_drvdata(file); - if (!radio_disconnected) { - fmdbg("FM device is already closed\n"); - return 0; - } - - ret = fmc_set_mode(fmdev, FM_MODE_OFF); - if (ret < 0) { - fmerr("Unable to turn off the chip\n"); - return ret; - } - - ret = fmc_release(fmdev); - if (ret < 0) { - fmerr("FM CORE release failed\n"); - return ret; - } - radio_disconnected = 0; - - return ret; -} - -/* V4L2 RADIO (/dev/radioX) device IOCTL interfaces */ -static int fm_v4l2_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver)); - strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME, - sizeof(capability->card)); - sprintf(capability->bus_info, "UART"); - capability->version = FM_DRV_RADIO_VERSION; - capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | - V4L2_CAP_RADIO | V4L2_CAP_MODULATOR | - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | - V4L2_CAP_RDS_CAPTURE; - - return 0; -} - -static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct fmdev *fmdev = container_of(ctrl->handler, - struct fmdev, ctrl_handler); - - switch (ctrl->id) { - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - ctrl->val = fm_tx_get_tune_cap_val(fmdev); - break; - default: - fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id); - break; - } - - return 0; -} - -static int fm_v4l2_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct fmdev *fmdev = container_of(ctrl->handler, - struct fmdev, ctrl_handler); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: /* set volume */ - return fm_rx_set_volume(fmdev, (u16)ctrl->val); - - case V4L2_CID_AUDIO_MUTE: /* set mute */ - return fmc_set_mute_mode(fmdev, (u8)ctrl->val); - - case V4L2_CID_TUNE_POWER_LEVEL: - /* set TX power level - ext control */ - return fm_tx_set_pwr_lvl(fmdev, (u8)ctrl->val); - - case V4L2_CID_TUNE_PREEMPHASIS: - return fm_tx_set_preemph_filter(fmdev, (u8) ctrl->val); - - default: - return -EINVAL; - } -} - -static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - memset(audio, 0, sizeof(*audio)); - strcpy(audio->name, "Radio"); - audio->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - -static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - if (audio->index != 0) - return -EINVAL; - - return 0; -} - -/* Get tuner attributes. If current mode is NOT RX, return error */ -static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct fmdev *fmdev = video_drvdata(file); - u32 bottom_freq; - u32 top_freq; - u16 stereo_mono_mode; - u16 rssilvl; - int ret; - - if (tuner->index != 0) - return -EINVAL; - - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - ret = fm_rx_get_band_freq_range(fmdev, &bottom_freq, &top_freq); - if (ret != 0) - return ret; - - ret = fm_rx_get_stereo_mono(fmdev, &stereo_mono_mode); - if (ret != 0) - return ret; - - ret = fm_rx_get_rssi_level(fmdev, &rssilvl); - if (ret != 0) - return ret; - - strcpy(tuner->name, "FM"); - tuner->type = V4L2_TUNER_RADIO; - /* Store rangelow and rangehigh freq in unit of 62.5 Hz */ - tuner->rangelow = bottom_freq * 16; - tuner->rangehigh = top_freq * 16; - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO | - ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0); - tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_LOW; - tuner->audmode = (stereo_mono_mode ? - V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO); - - /* - * Actual rssi value lies in between -128 to +127. - * Convert this range from 0 to 255 by adding +128 - */ - rssilvl += 128; - - /* - * Return signal strength value should be within 0 to 65535. - * Find out correct signal radio by multiplying (65535/255) = 257 - */ - tuner->signal = rssilvl * 257; - tuner->afc = 0; - - return ret; -} - -/* - * Set tuner attributes. If current mode is NOT RX, set to RX. - * Currently, we set only audio mode (mono/stereo) and RDS state (on/off). - * Should we set other tuner attributes, too? - */ -static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct fmdev *fmdev = video_drvdata(file); - u16 aud_mode; - u8 rds_mode; - int ret; - - if (tuner->index != 0) - return -EINVAL; - - aud_mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ? - FM_STEREO_MODE : FM_MONO_MODE; - rds_mode = (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ? - FM_RDS_ENABLE : FM_RDS_DISABLE; - - if (fmdev->curr_fmmode != FM_MODE_RX) { - ret = fmc_set_mode(fmdev, FM_MODE_RX); - if (ret < 0) { - fmerr("Failed to set RX mode\n"); - return ret; - } - } - - ret = fmc_set_stereo_mono(fmdev, aud_mode); - if (ret < 0) { - fmerr("Failed to set RX stereo/mono mode\n"); - return ret; - } - - ret = fmc_set_rds_mode(fmdev, rds_mode); - if (ret < 0) - fmerr("Failed to set RX RDS mode\n"); - - return ret; -} - -/* Get tuner or modulator radio frequency */ -static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct fmdev *fmdev = video_drvdata(file); - int ret; - - ret = fmc_get_freq(fmdev, &freq->frequency); - if (ret < 0) { - fmerr("Failed to get frequency\n"); - return ret; - } - - /* Frequency unit of 62.5 Hz*/ - freq->frequency = (u32) freq->frequency * 16; - - return 0; -} - -/* Set tuner or modulator radio frequency */ -static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct fmdev *fmdev = video_drvdata(file); - - /* - * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency - * in units of 62.5 Hz. - */ - freq->frequency = (u32)(freq->frequency / 16); - - return fmc_set_freq(fmdev, freq->frequency); -} - -/* Set hardware frequency seek. If current mode is NOT RX, set it RX. */ -static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv, - struct v4l2_hw_freq_seek *seek) -{ - struct fmdev *fmdev = video_drvdata(file); - int ret; - - if (fmdev->curr_fmmode != FM_MODE_RX) { - ret = fmc_set_mode(fmdev, FM_MODE_RX); - if (ret != 0) { - fmerr("Failed to set RX mode\n"); - return ret; - } - } - - ret = fm_rx_seek(fmdev, seek->seek_upward, seek->wrap_around, - seek->spacing); - if (ret < 0) - fmerr("RX seek failed - %d\n", ret); - - return ret; -} -/* Get modulator attributes. If mode is not TX, return no attributes. */ -static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv, - struct v4l2_modulator *mod) -{ - struct fmdev *fmdev = video_drvdata(file);; - - if (mod->index != 0) - return -EINVAL; - - if (fmdev->curr_fmmode != FM_MODE_TX) - return -EPERM; - - mod->txsubchans = ((fmdev->tx_data.aud_mode == FM_STEREO_MODE) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO) | - ((fmdev->tx_data.rds.flag == FM_RDS_ENABLE) ? - V4L2_TUNER_SUB_RDS : 0); - - mod->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_LOW; - - return 0; -} - -/* Set modulator attributes. If mode is not TX, set to TX. */ -static int fm_v4l2_vidioc_s_modulator(struct file *file, void *priv, - struct v4l2_modulator *mod) -{ - struct fmdev *fmdev = video_drvdata(file); - u8 rds_mode; - u16 aud_mode; - int ret; - - if (mod->index != 0) - return -EINVAL; - - if (fmdev->curr_fmmode != FM_MODE_TX) { - ret = fmc_set_mode(fmdev, FM_MODE_TX); - if (ret != 0) { - fmerr("Failed to set TX mode\n"); - return ret; - } - } - - aud_mode = (mod->txsubchans & V4L2_TUNER_SUB_STEREO) ? - FM_STEREO_MODE : FM_MONO_MODE; - rds_mode = (mod->txsubchans & V4L2_TUNER_SUB_RDS) ? - FM_RDS_ENABLE : FM_RDS_DISABLE; - ret = fm_tx_set_stereo_mono(fmdev, aud_mode); - if (ret < 0) { - fmerr("Failed to set mono/stereo mode for TX\n"); - return ret; - } - ret = fm_tx_set_rds_mode(fmdev, rds_mode); - if (ret < 0) - fmerr("Failed to set rds mode for TX\n"); - - return ret; -} - -static const struct v4l2_file_operations fm_drv_fops = { - .owner = THIS_MODULE, - .read = fm_v4l2_fops_read, - .write = fm_v4l2_fops_write, - .poll = fm_v4l2_fops_poll, - .unlocked_ioctl = video_ioctl2, - .open = fm_v4l2_fops_open, - .release = fm_v4l2_fops_release, -}; - -static const struct v4l2_ctrl_ops fm_ctrl_ops = { - .s_ctrl = fm_v4l2_s_ctrl, - .g_volatile_ctrl = fm_g_volatile_ctrl, -}; -static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = { - .vidioc_querycap = fm_v4l2_vidioc_querycap, - .vidioc_g_audio = fm_v4l2_vidioc_g_audio, - .vidioc_s_audio = fm_v4l2_vidioc_s_audio, - .vidioc_g_tuner = fm_v4l2_vidioc_g_tuner, - .vidioc_s_tuner = fm_v4l2_vidioc_s_tuner, - .vidioc_g_frequency = fm_v4l2_vidioc_g_freq, - .vidioc_s_frequency = fm_v4l2_vidioc_s_freq, - .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek, - .vidioc_g_modulator = fm_v4l2_vidioc_g_modulator, - .vidioc_s_modulator = fm_v4l2_vidioc_s_modulator -}; - -/* V4L2 RADIO device parent structure */ -static struct video_device fm_viddev_template = { - .fops = &fm_drv_fops, - .ioctl_ops = &fm_drv_ioctl_ops, - .name = FM_DRV_NAME, - .release = video_device_release, -}; - -int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) -{ - struct v4l2_ctrl *ctrl; - int ret; - - /* Init mutex for core locking */ - mutex_init(&fmdev->mutex); - - /* Allocate new video device */ - gradio_dev = video_device_alloc(); - if (NULL == gradio_dev) { - fmerr("Can't allocate video device\n"); - return -ENOMEM; - } - - /* Setup FM driver's V4L2 properties */ - memcpy(gradio_dev, &fm_viddev_template, sizeof(fm_viddev_template)); - - video_set_drvdata(gradio_dev, fmdev); - - gradio_dev->lock = &fmdev->mutex; - - /* Register with V4L2 subsystem as RADIO device */ - if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) { - video_device_release(gradio_dev); - fmerr("Could not register video device\n"); - return -ENOMEM; - } - - fmdev->radio_dev = gradio_dev; - - /* Register to v4l2 ctrl handler framework */ - fmdev->radio_dev->ctrl_handler = &fmdev->ctrl_handler; - - ret = v4l2_ctrl_handler_init(&fmdev->ctrl_handler, 5); - if (ret < 0) { - fmerr("(fmdev): Can't init ctrl handler\n"); - v4l2_ctrl_handler_free(&fmdev->ctrl_handler); - return -EBUSY; - } - - /* - * Following controls are handled by V4L2 control framework. - * Added in ascending ID order. - */ - v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, FM_RX_VOLUME_MIN, - FM_RX_VOLUME_MAX, 1, FM_RX_VOLUME_MAX); - - v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); - - v4l2_ctrl_new_std_menu(&fmdev->ctrl_handler, &fm_ctrl_ops, - V4L2_CID_TUNE_PREEMPHASIS, V4L2_PREEMPHASIS_75_uS, - 0, V4L2_PREEMPHASIS_75_uS); - - v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, - V4L2_CID_TUNE_POWER_LEVEL, FM_PWR_LVL_LOW, - FM_PWR_LVL_HIGH, 1, FM_PWR_LVL_HIGH); - - ctrl = v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, - V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, - 255, 1, 255); - - if (ctrl) - ctrl->is_volatile = 1; - - return 0; -} - -void *fm_v4l2_deinit_video_device(void) -{ - struct fmdev *fmdev; - - - fmdev = video_get_drvdata(gradio_dev); - - /* Unregister to v4l2 ctrl handler framework*/ - v4l2_ctrl_handler_free(&fmdev->ctrl_handler); - - /* Unregister RADIO device from V4L2 subsystem */ - video_unregister_device(gradio_dev); - - return fmdev; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_v4l2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_v4l2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_v4l2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/fmdrv_v4l2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - * FM Driver for Connectivity chip of Texas Instruments. - * - * FM V4L2 module header. - * - * Copyright (C) 2011 Texas Instruments - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - * - */ - -#ifndef _FMDRV_V4L2_H -#define _FMDRV_V4L2_H - -#include -#include -#include - -int fm_v4l2_init_video_device(struct fmdev *, int); -void *fm_v4l2_deinit_video_device(void); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -# -# TI's wl128x FM driver based on TI's ST driver. -# -menu "Texas Instruments WL128x FM driver (ST based)" -config RADIO_WL128X - tristate "Texas Instruments WL128x FM Radio" - depends on VIDEO_V4L2 && RFKILL - select TI_ST - help - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . - -endmenu diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/radio/wl128x/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -# -# Makefile for TI's shared transport driver based wl128x -# FM radio. -# -obj-$(CONFIG_RADIO_WL128X) += fm_drv.o -fm_drv-objs := fmdrv_common.o fmdrv_rx.o fmdrv_tx.o fmdrv_v4l2.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ene_ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ene_ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ene_ir.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ene_ir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1213 +0,0 @@ -/* - * driver for ENE KB3926 B/C/D/E/F CIR (pnp id: ENE0XXX) - * - * Copyright (C) 2010 Maxim Levitsky - * - * 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, or (at your option) any later version. - * - * 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 - * - * Special thanks to: - * Sami R. for lot of help in debugging and therefore - * bringing to life support for transmission & learning mode. - * - * Charlie Andrews for lots of help in - * bringing up the support of new firmware buffer that is popular - * on latest notebooks - * - * ENE for partial device documentation - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "ene_ir.h" - -static int sample_period; -static bool learning_mode_force; -static int debug; -static bool txsim; - -static void ene_set_reg_addr(struct ene_device *dev, u16 reg) -{ - outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); - outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); -} - -/* read a hardware register */ -static u8 ene_read_reg(struct ene_device *dev, u16 reg) -{ - u8 retval; - ene_set_reg_addr(dev, reg); - retval = inb(dev->hw_io + ENE_IO); - dbg_regs("reg %04x == %02x", reg, retval); - return retval; -} - -/* write a hardware register */ -static void ene_write_reg(struct ene_device *dev, u16 reg, u8 value) -{ - dbg_regs("reg %04x <- %02x", reg, value); - ene_set_reg_addr(dev, reg); - outb(value, dev->hw_io + ENE_IO); -} - -/* Set bits in hardware register */ -static void ene_set_reg_mask(struct ene_device *dev, u16 reg, u8 mask) -{ - dbg_regs("reg %04x |= %02x", reg, mask); - ene_set_reg_addr(dev, reg); - outb(inb(dev->hw_io + ENE_IO) | mask, dev->hw_io + ENE_IO); -} - -/* Clear bits in hardware register */ -static void ene_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask) -{ - dbg_regs("reg %04x &= ~%02x ", reg, mask); - ene_set_reg_addr(dev, reg); - outb(inb(dev->hw_io + ENE_IO) & ~mask, dev->hw_io + ENE_IO); -} - -/* A helper to set/clear a bit in register according to boolean variable */ -static void ene_set_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask, - bool set) -{ - if (set) - ene_set_reg_mask(dev, reg, mask); - else - ene_clear_reg_mask(dev, reg, mask); -} - -/* detect hardware features */ -static int ene_hw_detect(struct ene_device *dev) -{ - u8 chip_major, chip_minor; - u8 hw_revision, old_ver; - u8 fw_reg2, fw_reg1; - - ene_clear_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD); - chip_major = ene_read_reg(dev, ENE_ECVER_MAJOR); - chip_minor = ene_read_reg(dev, ENE_ECVER_MINOR); - ene_set_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD); - - hw_revision = ene_read_reg(dev, ENE_ECHV); - old_ver = ene_read_reg(dev, ENE_HW_VER_OLD); - - dev->pll_freq = (ene_read_reg(dev, ENE_PLLFRH) << 4) + - (ene_read_reg(dev, ENE_PLLFRL) >> 4); - - if (sample_period != ENE_DEFAULT_SAMPLE_PERIOD) - dev->rx_period_adjust = - dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4; - - if (hw_revision == 0xFF) { - ene_warn("device seems to be disabled"); - ene_warn("send a mail to lirc-list@lists.sourceforge.net"); - ene_warn("please attach output of acpidump and dmidecode"); - return -ENODEV; - } - - ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x", - chip_major, chip_minor, old_ver, hw_revision); - - ene_notice("PLL freq = %d", dev->pll_freq); - - if (chip_major == 0x33) { - ene_warn("chips 0x33xx aren't supported"); - return -ENODEV; - } - - if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { - dev->hw_revision = ENE_HW_C; - ene_notice("KB3926C detected"); - } else if (old_ver == 0x24 && hw_revision == 0xC0) { - dev->hw_revision = ENE_HW_B; - ene_notice("KB3926B detected"); - } else { - dev->hw_revision = ENE_HW_D; - ene_notice("KB3926D or higher detected"); - } - - /* detect features hardware supports */ - if (dev->hw_revision < ENE_HW_C) - return 0; - - fw_reg1 = ene_read_reg(dev, ENE_FW1); - fw_reg2 = ene_read_reg(dev, ENE_FW2); - - ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2); - - dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A); - dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING); - dev->hw_extra_buffer = !!(fw_reg1 & ENE_FW1_HAS_EXTRA_BUF); - - if (dev->hw_learning_and_tx_capable) - dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT); - - ene_notice("Hardware features:"); - - if (dev->hw_learning_and_tx_capable) { - ene_notice("* Supports transmitting & learning mode"); - ene_notice(" This feature is rare and therefore,"); - ene_notice(" you are welcome to test it,"); - ene_notice(" and/or contact the author via:"); - ene_notice(" lirc-list@lists.sourceforge.net"); - ene_notice(" or maximlevitsky@gmail.com"); - - ene_notice("* Uses GPIO %s for IR raw input", - dev->hw_use_gpio_0a ? "40" : "0A"); - - if (dev->hw_fan_input) - ene_notice("* Uses unused fan feedback input as source" - " of demodulated IR data"); - } - - if (!dev->hw_fan_input) - ene_notice("* Uses GPIO %s for IR demodulated input", - dev->hw_use_gpio_0a ? "0A" : "40"); - - if (dev->hw_extra_buffer) - ene_notice("* Uses new style input buffer"); - return 0; -} - -/* Read properities of hw sample buffer */ -static void ene_rx_setup_hw_buffer(struct ene_device *dev) -{ - u16 tmp; - - ene_rx_read_hw_pointer(dev); - dev->r_pointer = dev->w_pointer; - - if (!dev->hw_extra_buffer) { - dev->buffer_len = ENE_FW_PACKET_SIZE * 2; - return; - } - - tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER); - tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER+1) << 8; - dev->extra_buf1_address = tmp; - - dev->extra_buf1_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 2); - - tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 3); - tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 4) << 8; - dev->extra_buf2_address = tmp; - - dev->extra_buf2_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 5); - - dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8; - - ene_notice("Hardware uses 2 extended buffers:"); - ene_notice(" 0x%04x - len : %d", dev->extra_buf1_address, - dev->extra_buf1_len); - ene_notice(" 0x%04x - len : %d", dev->extra_buf2_address, - dev->extra_buf2_len); - - ene_notice("Total buffer len = %d", dev->buffer_len); - - if (dev->buffer_len > 64 || dev->buffer_len < 16) - goto error; - - if (dev->extra_buf1_address > 0xFBFC || - dev->extra_buf1_address < 0xEC00) - goto error; - - if (dev->extra_buf2_address > 0xFBFC || - dev->extra_buf2_address < 0xEC00) - goto error; - - if (dev->r_pointer > dev->buffer_len) - goto error; - - ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); - return; -error: - ene_warn("Error validating extra buffers, device probably won't work"); - dev->hw_extra_buffer = false; - ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); -} - - -/* Restore the pointers to extra buffers - to make module reload work*/ -static void ene_rx_restore_hw_buffer(struct ene_device *dev) -{ - if (!dev->hw_extra_buffer) - return; - - ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 0, - dev->extra_buf1_address & 0xFF); - ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 1, - dev->extra_buf1_address >> 8); - ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 2, dev->extra_buf1_len); - - ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 3, - dev->extra_buf2_address & 0xFF); - ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 4, - dev->extra_buf2_address >> 8); - ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 5, - dev->extra_buf2_len); - ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); -} - -/* Read hardware write pointer */ -static void ene_rx_read_hw_pointer(struct ene_device *dev) -{ - if (dev->hw_extra_buffer) - dev->w_pointer = ene_read_reg(dev, ENE_FW_RX_POINTER); - else - dev->w_pointer = ene_read_reg(dev, ENE_FW2) - & ENE_FW2_BUF_WPTR ? 0 : ENE_FW_PACKET_SIZE; - - dbg_verbose("RB: HW write pointer: %02x, driver read pointer: %02x", - dev->w_pointer, dev->r_pointer); -} - -/* Gets address of next sample from HW ring buffer */ -static int ene_rx_get_sample_reg(struct ene_device *dev) -{ - int r_pointer; - - if (dev->r_pointer == dev->w_pointer) { - dbg_verbose("RB: hit end, try update w_pointer"); - ene_rx_read_hw_pointer(dev); - } - - if (dev->r_pointer == dev->w_pointer) { - dbg_verbose("RB: end of data at %d", dev->r_pointer); - return 0; - } - - dbg_verbose("RB: reading at offset %d", dev->r_pointer); - r_pointer = dev->r_pointer; - - dev->r_pointer++; - if (dev->r_pointer == dev->buffer_len) - dev->r_pointer = 0; - - dbg_verbose("RB: next read will be from offset %d", dev->r_pointer); - - if (r_pointer < 8) { - dbg_verbose("RB: read at main buffer at %d", r_pointer); - return ENE_FW_SAMPLE_BUFFER + r_pointer; - } - - r_pointer -= 8; - - if (r_pointer < dev->extra_buf1_len) { - dbg_verbose("RB: read at 1st extra buffer at %d", r_pointer); - return dev->extra_buf1_address + r_pointer; - } - - r_pointer -= dev->extra_buf1_len; - - if (r_pointer < dev->extra_buf2_len) { - dbg_verbose("RB: read at 2nd extra buffer at %d", r_pointer); - return dev->extra_buf2_address + r_pointer; - } - - dbg("attempt to read beyong ring bufer end"); - return 0; -} - -/* Sense current received carrier */ -void ene_rx_sense_carrier(struct ene_device *dev) -{ - DEFINE_IR_RAW_EVENT(ev); - - int carrier, duty_cycle; - int period = ene_read_reg(dev, ENE_CIRCAR_PRD); - int hperiod = ene_read_reg(dev, ENE_CIRCAR_HPRD); - - if (!(period & ENE_CIRCAR_PRD_VALID)) - return; - - period &= ~ENE_CIRCAR_PRD_VALID; - - if (!period) - return; - - dbg("RX: hardware carrier period = %02x", period); - dbg("RX: hardware carrier pulse period = %02x", hperiod); - - carrier = 2000000 / period; - duty_cycle = (hperiod * 100) / period; - dbg("RX: sensed carrier = %d Hz, duty cycle %d%%", - carrier, duty_cycle); - if (dev->carrier_detect_enabled) { - ev.carrier_report = true; - ev.carrier = carrier; - ev.duty_cycle = duty_cycle; - ir_raw_event_store(dev->rdev, &ev); - } -} - -/* this enables/disables the CIR RX engine */ -static void ene_rx_enable_cir_engine(struct ene_device *dev, bool enable) -{ - ene_set_clear_reg_mask(dev, ENE_CIRCFG, - ENE_CIRCFG_RX_EN | ENE_CIRCFG_RX_IRQ, enable); -} - -/* this selects input for CIR engine. Ether GPIO 0A or GPIO40*/ -static void ene_rx_select_input(struct ene_device *dev, bool gpio_0a) -{ - ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_GPIO0A, gpio_0a); -} - -/* - * this enables alternative input via fan tachometer sensor and bypasses - * the hw CIR engine - */ -static void ene_rx_enable_fan_input(struct ene_device *dev, bool enable) -{ - if (!dev->hw_fan_input) - return; - - if (!enable) - ene_write_reg(dev, ENE_FAN_AS_IN1, 0); - else { - ene_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); - ene_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); - } -} - -/* setup the receiver for RX*/ -static void ene_rx_setup(struct ene_device *dev) -{ - bool learning_mode = dev->learning_mode_enabled || - dev->carrier_detect_enabled; - int sample_period_adjust = 0; - - dbg("RX: setup receiver, learning mode = %d", learning_mode); - - - /* This selects RLC input and clears CFG2 settings */ - ene_write_reg(dev, ENE_CIRCFG2, 0x00); - - /* set sample period*/ - if (sample_period == ENE_DEFAULT_SAMPLE_PERIOD) - sample_period_adjust = - dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 1 : 2; - - ene_write_reg(dev, ENE_CIRRLC_CFG, - (sample_period + sample_period_adjust) | - ENE_CIRRLC_CFG_OVERFLOW); - /* revB doesn't support inputs */ - if (dev->hw_revision < ENE_HW_C) - goto select_timeout; - - if (learning_mode) { - - WARN_ON(!dev->hw_learning_and_tx_capable); - - /* Enable the opposite of the normal input - That means that if GPIO40 is normally used, use GPIO0A - and vice versa. - This input will carry non demodulated - signal, and we will tell the hw to demodulate it itself */ - ene_rx_select_input(dev, !dev->hw_use_gpio_0a); - dev->rx_fan_input_inuse = false; - - /* Enable carrier demodulation */ - ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD); - - /* Enable carrier detection */ - ene_write_reg(dev, ENE_CIRCAR_PULS, 0x63); - ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT, - dev->carrier_detect_enabled || debug); - } else { - if (dev->hw_fan_input) - dev->rx_fan_input_inuse = true; - else - ene_rx_select_input(dev, dev->hw_use_gpio_0a); - - /* Disable carrier detection & demodulation */ - ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD); - ene_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT); - } - -select_timeout: - if (dev->rx_fan_input_inuse) { - dev->rdev->rx_resolution = US_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN); - - /* Fan input doesn't support timeouts, it just ends the - input with a maximum sample */ - dev->rdev->min_timeout = dev->rdev->max_timeout = - US_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK * - ENE_FW_SAMPLE_PERIOD_FAN); - } else { - dev->rdev->rx_resolution = US_TO_NS(sample_period); - - /* Theoreticly timeout is unlimited, but we cap it - * because it was seen that on one device, it - * would stop sending spaces after around 250 msec. - * Besides, this is close to 2^32 anyway and timeout is u32. - */ - dev->rdev->min_timeout = US_TO_NS(127 * sample_period); - dev->rdev->max_timeout = US_TO_NS(200000); - } - - if (dev->hw_learning_and_tx_capable) - dev->rdev->tx_resolution = US_TO_NS(sample_period); - - if (dev->rdev->timeout > dev->rdev->max_timeout) - dev->rdev->timeout = dev->rdev->max_timeout; - if (dev->rdev->timeout < dev->rdev->min_timeout) - dev->rdev->timeout = dev->rdev->min_timeout; -} - -/* Enable the device for receive */ -static void ene_rx_enable(struct ene_device *dev) -{ - u8 reg_value; - - /* Enable system interrupt */ - if (dev->hw_revision < ENE_HW_C) { - ene_write_reg(dev, ENEB_IRQ, dev->irq << 1); - ene_write_reg(dev, ENEB_IRQ_UNK1, 0x01); - } else { - reg_value = ene_read_reg(dev, ENE_IRQ) & 0xF0; - reg_value |= ENE_IRQ_UNK_EN; - reg_value &= ~ENE_IRQ_STATUS; - reg_value |= (dev->irq & ENE_IRQ_MASK); - ene_write_reg(dev, ENE_IRQ, reg_value); - } - - /* Enable inputs */ - ene_rx_enable_fan_input(dev, dev->rx_fan_input_inuse); - ene_rx_enable_cir_engine(dev, !dev->rx_fan_input_inuse); - - /* ack any pending irqs - just in case */ - ene_irq_status(dev); - - /* enable firmware bits */ - ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ); - - /* enter idle mode */ - ir_raw_event_set_idle(dev->rdev, true); - dev->rx_enabled = true; -} - -/* Disable the device receiver */ -static void ene_rx_disable(struct ene_device *dev) -{ - /* disable inputs */ - ene_rx_enable_cir_engine(dev, false); - ene_rx_enable_fan_input(dev, false); - - /* disable hardware IRQ and firmware flag */ - ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ); - - ir_raw_event_set_idle(dev->rdev, true); - dev->rx_enabled = false; -} - -/* This resets the receiver. Usefull to stop stream of spaces at end of - * transmission - */ -static void ene_rx_reset(struct ene_device *dev) -{ - ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN); - ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN); -} - -/* Set up the TX carrier frequency and duty cycle */ -static void ene_tx_set_carrier(struct ene_device *dev) -{ - u8 tx_puls_width; - unsigned long flags; - - spin_lock_irqsave(&dev->hw_lock, flags); - - ene_set_clear_reg_mask(dev, ENE_CIRCFG, - ENE_CIRCFG_TX_CARR, dev->tx_period > 0); - - if (!dev->tx_period) - goto unlock; - - BUG_ON(dev->tx_duty_cycle >= 100 || dev->tx_duty_cycle <= 0); - - tx_puls_width = dev->tx_period / (100 / dev->tx_duty_cycle); - - if (!tx_puls_width) - tx_puls_width = 1; - - dbg("TX: pulse distance = %d * 500 ns", dev->tx_period); - dbg("TX: pulse width = %d * 500 ns", tx_puls_width); - - ene_write_reg(dev, ENE_CIRMOD_PRD, dev->tx_period | ENE_CIRMOD_PRD_POL); - ene_write_reg(dev, ENE_CIRMOD_HPRD, tx_puls_width); -unlock: - spin_unlock_irqrestore(&dev->hw_lock, flags); -} - -/* Enable/disable transmitters */ -static void ene_tx_set_transmitters(struct ene_device *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->hw_lock, flags); - ene_set_clear_reg_mask(dev, ENE_GPIOFS8, ENE_GPIOFS8_GPIO41, - !!(dev->transmitter_mask & 0x01)); - ene_set_clear_reg_mask(dev, ENE_GPIOFS1, ENE_GPIOFS1_GPIO0D, - !!(dev->transmitter_mask & 0x02)); - spin_unlock_irqrestore(&dev->hw_lock, flags); -} - -/* prepare transmission */ -static void ene_tx_enable(struct ene_device *dev) -{ - u8 conf1 = ene_read_reg(dev, ENE_CIRCFG); - u8 fwreg2 = ene_read_reg(dev, ENE_FW2); - - dev->saved_conf1 = conf1; - - /* Show information about currently connected transmitter jacks */ - if (fwreg2 & ENE_FW2_EMMITER1_CONN) - dbg("TX: Transmitter #1 is connected"); - - if (fwreg2 & ENE_FW2_EMMITER2_CONN) - dbg("TX: Transmitter #2 is connected"); - - if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN))) - ene_warn("TX: transmitter cable isn't connected!"); - - /* disable receive on revc */ - if (dev->hw_revision == ENE_HW_C) - conf1 &= ~ENE_CIRCFG_RX_EN; - - /* Enable TX engine */ - conf1 |= ENE_CIRCFG_TX_EN | ENE_CIRCFG_TX_IRQ; - ene_write_reg(dev, ENE_CIRCFG, conf1); -} - -/* end transmission */ -static void ene_tx_disable(struct ene_device *dev) -{ - ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1); - dev->tx_buffer = NULL; -} - - -/* TX one sample - must be called with dev->hw_lock*/ -static void ene_tx_sample(struct ene_device *dev) -{ - u8 raw_tx; - u32 sample; - bool pulse = dev->tx_sample_pulse; - - if (!dev->tx_buffer) { - ene_warn("TX: BUG: attempt to transmit NULL buffer"); - return; - } - - /* Grab next TX sample */ - if (!dev->tx_sample) { - - if (dev->tx_pos == dev->tx_len) { - if (!dev->tx_done) { - dbg("TX: no more data to send"); - dev->tx_done = true; - goto exit; - } else { - dbg("TX: last sample sent by hardware"); - ene_tx_disable(dev); - complete(&dev->tx_complete); - return; - } - } - - sample = dev->tx_buffer[dev->tx_pos++]; - dev->tx_sample_pulse = !dev->tx_sample_pulse; - - dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period); - - if (!dev->tx_sample) - dev->tx_sample = 1; - } - - raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK); - dev->tx_sample -= raw_tx; - - dbg("TX: sample %8d (%s)", raw_tx * sample_period, - pulse ? "pulse" : "space"); - if (pulse) - raw_tx |= ENE_CIRRLC_OUT_PULSE; - - ene_write_reg(dev, - dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx); - - dev->tx_reg = !dev->tx_reg; -exit: - /* simulate TX done interrupt */ - if (txsim) - mod_timer(&dev->tx_sim_timer, jiffies + HZ / 500); -} - -/* timer to simulate tx done interrupt */ -static void ene_tx_irqsim(unsigned long data) -{ - struct ene_device *dev = (struct ene_device *)data; - unsigned long flags; - - spin_lock_irqsave(&dev->hw_lock, flags); - ene_tx_sample(dev); - spin_unlock_irqrestore(&dev->hw_lock, flags); -} - - -/* read irq status and ack it */ -static int ene_irq_status(struct ene_device *dev) -{ - u8 irq_status; - u8 fw_flags1, fw_flags2; - int retval = 0; - - fw_flags2 = ene_read_reg(dev, ENE_FW2); - - if (dev->hw_revision < ENE_HW_C) { - irq_status = ene_read_reg(dev, ENEB_IRQ_STATUS); - - if (!(irq_status & ENEB_IRQ_STATUS_IR)) - return 0; - - ene_clear_reg_mask(dev, ENEB_IRQ_STATUS, ENEB_IRQ_STATUS_IR); - return ENE_IRQ_RX; - } - - irq_status = ene_read_reg(dev, ENE_IRQ); - if (!(irq_status & ENE_IRQ_STATUS)) - return 0; - - /* original driver does that twice - a workaround ? */ - ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS); - ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS); - - /* check RX interrupt */ - if (fw_flags2 & ENE_FW2_RXIRQ) { - retval |= ENE_IRQ_RX; - ene_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_RXIRQ); - } - - /* check TX interrupt */ - fw_flags1 = ene_read_reg(dev, ENE_FW1); - if (fw_flags1 & ENE_FW1_TXIRQ) { - ene_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); - retval |= ENE_IRQ_TX; - } - - return retval; -} - -/* interrupt handler */ -static irqreturn_t ene_isr(int irq, void *data) -{ - u16 hw_value, reg; - int hw_sample, irq_status; - bool pulse; - unsigned long flags; - irqreturn_t retval = IRQ_NONE; - struct ene_device *dev = (struct ene_device *)data; - DEFINE_IR_RAW_EVENT(ev); - - spin_lock_irqsave(&dev->hw_lock, flags); - - dbg_verbose("ISR called"); - ene_rx_read_hw_pointer(dev); - irq_status = ene_irq_status(dev); - - if (!irq_status) - goto unlock; - - retval = IRQ_HANDLED; - - if (irq_status & ENE_IRQ_TX) { - dbg_verbose("TX interrupt"); - if (!dev->hw_learning_and_tx_capable) { - dbg("TX interrupt on unsupported device!"); - goto unlock; - } - ene_tx_sample(dev); - } - - if (!(irq_status & ENE_IRQ_RX)) - goto unlock; - - dbg_verbose("RX interrupt"); - - if (dev->hw_learning_and_tx_capable) - ene_rx_sense_carrier(dev); - - /* On hardware that don't support extra buffer we need to trust - the interrupt and not track the read pointer */ - if (!dev->hw_extra_buffer) - dev->r_pointer = dev->w_pointer == 0 ? ENE_FW_PACKET_SIZE : 0; - - while (1) { - - reg = ene_rx_get_sample_reg(dev); - - dbg_verbose("next sample to read at: %04x", reg); - if (!reg) - break; - - hw_value = ene_read_reg(dev, reg); - - if (dev->rx_fan_input_inuse) { - - int offset = ENE_FW_SMPL_BUF_FAN - ENE_FW_SAMPLE_BUFFER; - - /* read high part of the sample */ - hw_value |= ene_read_reg(dev, reg + offset) << 8; - pulse = hw_value & ENE_FW_SMPL_BUF_FAN_PLS; - - /* clear space bit, and other unused bits */ - hw_value &= ENE_FW_SMPL_BUF_FAN_MSK; - hw_sample = hw_value * ENE_FW_SAMPLE_PERIOD_FAN; - - } else { - pulse = !(hw_value & ENE_FW_SAMPLE_SPACE); - hw_value &= ~ENE_FW_SAMPLE_SPACE; - hw_sample = hw_value * sample_period; - - if (dev->rx_period_adjust) { - hw_sample *= 100; - hw_sample /= (100 + dev->rx_period_adjust); - } - } - - if (!dev->hw_extra_buffer && !hw_sample) { - dev->r_pointer = dev->w_pointer; - continue; - } - - dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space"); - - ev.duration = US_TO_NS(hw_sample); - ev.pulse = pulse; - ir_raw_event_store_with_filter(dev->rdev, &ev); - } - - ir_raw_event_handle(dev->rdev); -unlock: - spin_unlock_irqrestore(&dev->hw_lock, flags); - return retval; -} - -/* Initialize default settings */ -static void ene_setup_default_settings(struct ene_device *dev) -{ - dev->tx_period = 32; - dev->tx_duty_cycle = 50; /*%*/ - dev->transmitter_mask = 0x03; - dev->learning_mode_enabled = learning_mode_force; - - /* Set reasonable default timeout */ - dev->rdev->timeout = US_TO_NS(150000); -} - -/* Upload all hardware settings at once. Used at load and resume time */ -static void ene_setup_hw_settings(struct ene_device *dev) -{ - if (dev->hw_learning_and_tx_capable) { - ene_tx_set_carrier(dev); - ene_tx_set_transmitters(dev); - } - - ene_rx_setup(dev); -} - -/* outside interface: called on first open*/ -static int ene_open(struct rc_dev *rdev) -{ - struct ene_device *dev = rdev->priv; - unsigned long flags; - - spin_lock_irqsave(&dev->hw_lock, flags); - ene_rx_enable(dev); - spin_unlock_irqrestore(&dev->hw_lock, flags); - return 0; -} - -/* outside interface: called on device close*/ -static void ene_close(struct rc_dev *rdev) -{ - struct ene_device *dev = rdev->priv; - unsigned long flags; - spin_lock_irqsave(&dev->hw_lock, flags); - - ene_rx_disable(dev); - spin_unlock_irqrestore(&dev->hw_lock, flags); -} - -/* outside interface: set transmitter mask */ -static int ene_set_tx_mask(struct rc_dev *rdev, u32 tx_mask) -{ - struct ene_device *dev = rdev->priv; - dbg("TX: attempt to set transmitter mask %02x", tx_mask); - - /* invalid txmask */ - if (!tx_mask || tx_mask & ~0x03) { - dbg("TX: invalid mask"); - /* return count of transmitters */ - return 2; - } - - dev->transmitter_mask = tx_mask; - ene_tx_set_transmitters(dev); - return 0; -} - -/* outside interface : set tx carrier */ -static int ene_set_tx_carrier(struct rc_dev *rdev, u32 carrier) -{ - struct ene_device *dev = rdev->priv; - u32 period = 2000000 / carrier; - - dbg("TX: attempt to set tx carrier to %d kHz", carrier); - - if (period && (period > ENE_CIRMOD_PRD_MAX || - period < ENE_CIRMOD_PRD_MIN)) { - - dbg("TX: out of range %d-%d kHz carrier", - 2000 / ENE_CIRMOD_PRD_MIN, 2000 / ENE_CIRMOD_PRD_MAX); - return -1; - } - - dev->tx_period = period; - ene_tx_set_carrier(dev); - return 0; -} - -/*outside interface : set tx duty cycle */ -static int ene_set_tx_duty_cycle(struct rc_dev *rdev, u32 duty_cycle) -{ - struct ene_device *dev = rdev->priv; - dbg("TX: setting duty cycle to %d%%", duty_cycle); - dev->tx_duty_cycle = duty_cycle; - ene_tx_set_carrier(dev); - return 0; -} - -/* outside interface: enable learning mode */ -static int ene_set_learning_mode(struct rc_dev *rdev, int enable) -{ - struct ene_device *dev = rdev->priv; - unsigned long flags; - if (enable == dev->learning_mode_enabled) - return 0; - - spin_lock_irqsave(&dev->hw_lock, flags); - dev->learning_mode_enabled = enable; - ene_rx_disable(dev); - ene_rx_setup(dev); - ene_rx_enable(dev); - spin_unlock_irqrestore(&dev->hw_lock, flags); - return 0; -} - -static int ene_set_carrier_report(struct rc_dev *rdev, int enable) -{ - struct ene_device *dev = rdev->priv; - unsigned long flags; - - if (enable == dev->carrier_detect_enabled) - return 0; - - spin_lock_irqsave(&dev->hw_lock, flags); - dev->carrier_detect_enabled = enable; - ene_rx_disable(dev); - ene_rx_setup(dev); - ene_rx_enable(dev); - spin_unlock_irqrestore(&dev->hw_lock, flags); - return 0; -} - -/* outside interface: enable or disable idle mode */ -static void ene_set_idle(struct rc_dev *rdev, bool idle) -{ - struct ene_device *dev = rdev->priv; - - if (idle) { - ene_rx_reset(dev); - dbg("RX: end of data"); - } -} - -/* outside interface: transmit */ -static int ene_transmit(struct rc_dev *rdev, int *buf, u32 n) -{ - struct ene_device *dev = rdev->priv; - unsigned long flags; - - dev->tx_buffer = buf; - dev->tx_len = n / sizeof(int); - dev->tx_pos = 0; - dev->tx_reg = 0; - dev->tx_done = 0; - dev->tx_sample = 0; - dev->tx_sample_pulse = 0; - - dbg("TX: %d samples", dev->tx_len); - - spin_lock_irqsave(&dev->hw_lock, flags); - - ene_tx_enable(dev); - - /* Transmit first two samples */ - ene_tx_sample(dev); - ene_tx_sample(dev); - - spin_unlock_irqrestore(&dev->hw_lock, flags); - - if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) { - dbg("TX: timeout"); - spin_lock_irqsave(&dev->hw_lock, flags); - ene_tx_disable(dev); - spin_unlock_irqrestore(&dev->hw_lock, flags); - } else - dbg("TX: done"); - return n; -} - -/* probe entry */ -static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) -{ - int error = -ENOMEM; - struct rc_dev *rdev; - struct ene_device *dev; - - /* allocate memory */ - dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); - rdev = rc_allocate_device(); - if (!dev || !rdev) - goto error1; - - /* validate resources */ - error = -ENODEV; - - /* init these to -1, as 0 is valid for both */ - dev->hw_io = -1; - dev->irq = -1; - - if (!pnp_port_valid(pnp_dev, 0) || - pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE) - goto error; - - if (!pnp_irq_valid(pnp_dev, 0)) - goto error; - - spin_lock_init(&dev->hw_lock); - - /* claim the resources */ - error = -EBUSY; - dev->hw_io = pnp_port_start(pnp_dev, 0); - if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) { - dev->hw_io = -1; - dev->irq = -1; - goto error; - } - - dev->irq = pnp_irq(pnp_dev, 0); - if (request_irq(dev->irq, ene_isr, - IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) { - dev->irq = -1; - goto error; - } - - pnp_set_drvdata(pnp_dev, dev); - dev->pnp_dev = pnp_dev; - - /* don't allow too short/long sample periods */ - if (sample_period < 5 || sample_period > 0x7F) - sample_period = ENE_DEFAULT_SAMPLE_PERIOD; - - /* detect hardware version and features */ - error = ene_hw_detect(dev); - if (error) - goto error; - - if (!dev->hw_learning_and_tx_capable && txsim) { - dev->hw_learning_and_tx_capable = true; - setup_timer(&dev->tx_sim_timer, ene_tx_irqsim, - (long unsigned int)dev); - ene_warn("Simulation of TX activated"); - } - - if (!dev->hw_learning_and_tx_capable) - learning_mode_force = false; - - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; - rdev->priv = dev; - rdev->open = ene_open; - rdev->close = ene_close; - rdev->s_idle = ene_set_idle; - rdev->driver_name = ENE_DRIVER_NAME; - rdev->map_name = RC_MAP_RC6_MCE; - rdev->input_name = "ENE eHome Infrared Remote Receiver"; - - if (dev->hw_learning_and_tx_capable) { - rdev->s_learning_mode = ene_set_learning_mode; - init_completion(&dev->tx_complete); - rdev->tx_ir = ene_transmit; - rdev->s_tx_mask = ene_set_tx_mask; - rdev->s_tx_carrier = ene_set_tx_carrier; - rdev->s_tx_duty_cycle = ene_set_tx_duty_cycle; - rdev->s_carrier_report = ene_set_carrier_report; - rdev->input_name = "ENE eHome Infrared Remote Transceiver"; - } - - dev->rdev = rdev; - - ene_rx_setup_hw_buffer(dev); - ene_setup_default_settings(dev); - ene_setup_hw_settings(dev); - - device_set_wakeup_capable(&pnp_dev->dev, true); - device_set_wakeup_enable(&pnp_dev->dev, true); - - error = rc_register_device(rdev); - if (error < 0) - goto error; - - ene_notice("driver has been succesfully loaded"); - return 0; -error: - if (dev && dev->irq >= 0) - free_irq(dev->irq, dev); - if (dev && dev->hw_io >= 0) - release_region(dev->hw_io, ENE_IO_SIZE); -error1: - rc_free_device(rdev); - kfree(dev); - return error; -} - -/* main unload function */ -static void ene_remove(struct pnp_dev *pnp_dev) -{ - struct ene_device *dev = pnp_get_drvdata(pnp_dev); - unsigned long flags; - - spin_lock_irqsave(&dev->hw_lock, flags); - ene_rx_disable(dev); - ene_rx_restore_hw_buffer(dev); - spin_unlock_irqrestore(&dev->hw_lock, flags); - - free_irq(dev->irq, dev); - release_region(dev->hw_io, ENE_IO_SIZE); - rc_unregister_device(dev->rdev); - kfree(dev); -} - -/* enable wake on IR (wakes on specific button on original remote) */ -static void ene_enable_wake(struct ene_device *dev, int enable) -{ - enable = enable && device_may_wakeup(&dev->pnp_dev->dev); - dbg("wake on IR %s", enable ? "enabled" : "disabled"); - ene_set_clear_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, enable); -} - -#ifdef CONFIG_PM -static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) -{ - struct ene_device *dev = pnp_get_drvdata(pnp_dev); - ene_enable_wake(dev, true); - - /* TODO: add support for wake pattern */ - return 0; -} - -static int ene_resume(struct pnp_dev *pnp_dev) -{ - struct ene_device *dev = pnp_get_drvdata(pnp_dev); - ene_setup_hw_settings(dev); - - if (dev->rx_enabled) - ene_rx_enable(dev); - - ene_enable_wake(dev, false); - return 0; -} -#endif - -static void ene_shutdown(struct pnp_dev *pnp_dev) -{ - struct ene_device *dev = pnp_get_drvdata(pnp_dev); - ene_enable_wake(dev, true); -} - -static const struct pnp_device_id ene_ids[] = { - {.id = "ENE0100",}, - {.id = "ENE0200",}, - {.id = "ENE0201",}, - {.id = "ENE0202",}, - {}, -}; - -static struct pnp_driver ene_driver = { - .name = ENE_DRIVER_NAME, - .id_table = ene_ids, - .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, - - .probe = ene_probe, - .remove = __devexit_p(ene_remove), -#ifdef CONFIG_PM - .suspend = ene_suspend, - .resume = ene_resume, -#endif - .shutdown = ene_shutdown, -}; - -static int __init ene_init(void) -{ - return pnp_register_driver(&ene_driver); -} - -static void ene_exit(void) -{ - pnp_unregister_driver(&ene_driver); -} - -module_param(sample_period, int, S_IRUGO); -MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)"); - -module_param(learning_mode_force, bool, S_IRUGO); -MODULE_PARM_DESC(learning_mode_force, "Enable learning mode by default"); - -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug level"); - -module_param(txsim, bool, S_IRUGO); -MODULE_PARM_DESC(txsim, - "Simulate TX features on unsupported hardware (dangerous)"); - -MODULE_DEVICE_TABLE(pnp, ene_ids); -MODULE_DESCRIPTION - ("Infrared input driver for KB3926B/C/D/E/F " - "(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port"); - -MODULE_AUTHOR("Maxim Levitsky"); -MODULE_LICENSE("GPL"); - -module_init(ene_init); -module_exit(ene_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ene_ir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ene_ir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ene_ir.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ene_ir.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,259 +0,0 @@ -/* - * driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX) - * - * Copyright (C) 2010 Maxim Levitsky - * - * 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, or (at your option) any later version. - * - * 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 - - -/* hardware address */ -#define ENE_STATUS 0 /* hardware status - unused */ -#define ENE_ADDR_HI 1 /* hi byte of register address */ -#define ENE_ADDR_LO 2 /* low byte of register address */ -#define ENE_IO 3 /* read/write window */ -#define ENE_IO_SIZE 4 - -/* 8 bytes of samples, divided in 2 packets*/ -#define ENE_FW_SAMPLE_BUFFER 0xF8F0 /* sample buffer */ -#define ENE_FW_SAMPLE_SPACE 0x80 /* sample is space */ -#define ENE_FW_PACKET_SIZE 4 - -/* first firmware flag register */ -#define ENE_FW1 0xF8F8 /* flagr */ -#define ENE_FW1_ENABLE 0x01 /* enable fw processing */ -#define ENE_FW1_TXIRQ 0x02 /* TX interrupt pending */ -#define ENE_FW1_HAS_EXTRA_BUF 0x04 /* fw uses extra buffer*/ -#define ENE_FW1_EXTRA_BUF_HND 0x08 /* extra buffer handshake bit*/ -#define ENE_FW1_LED_ON 0x10 /* turn on a led */ - -#define ENE_FW1_WPATTERN 0x20 /* enable wake pattern */ -#define ENE_FW1_WAKE 0x40 /* enable wake from S3 */ -#define ENE_FW1_IRQ 0x80 /* enable interrupt */ - -/* second firmware flag register */ -#define ENE_FW2 0xF8F9 /* flagw */ -#define ENE_FW2_BUF_WPTR 0x01 /* which half of the buffer to read */ -#define ENE_FW2_RXIRQ 0x04 /* RX IRQ pending*/ -#define ENE_FW2_GP0A 0x08 /* Use GPIO0A for demodulated input */ -#define ENE_FW2_EMMITER1_CONN 0x10 /* TX emmiter 1 connected */ -#define ENE_FW2_EMMITER2_CONN 0x20 /* TX emmiter 2 connected */ - -#define ENE_FW2_FAN_INPUT 0x40 /* fan input used for demodulated data*/ -#define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */ - -/* firmware RX pointer for new style buffer */ -#define ENE_FW_RX_POINTER 0xF8FA - -/* high parts of samples for fan input (8 samples)*/ -#define ENE_FW_SMPL_BUF_FAN 0xF8FB -#define ENE_FW_SMPL_BUF_FAN_PLS 0x8000 /* combined sample is pulse */ -#define ENE_FW_SMPL_BUF_FAN_MSK 0x0FFF /* combined sample maximum value */ -#define ENE_FW_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */ - -/* transmitter ports */ -#define ENE_GPIOFS1 0xFC01 -#define ENE_GPIOFS1_GPIO0D 0x20 /* enable tx output on GPIO0D */ -#define ENE_GPIOFS8 0xFC08 -#define ENE_GPIOFS8_GPIO41 0x02 /* enable tx output on GPIO40 */ - -/* IRQ registers block (for revision B) */ -#define ENEB_IRQ 0xFD09 /* IRQ number */ -#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ -#define ENEB_IRQ_STATUS 0xFD80 /* irq status */ -#define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */ - -/* fan as input settings */ -#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ -#define ENE_FAN_AS_IN1_EN 0xCD -#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ -#define ENE_FAN_AS_IN2_EN 0x03 - -/* IRQ registers block (for revision C,D) */ -#define ENE_IRQ 0xFE9B /* new irq settings register */ -#define ENE_IRQ_MASK 0x0F /* irq number mask */ -#define ENE_IRQ_UNK_EN 0x10 /* always enabled */ -#define ENE_IRQ_STATUS 0x20 /* irq status and ACK */ - -/* CIR Config register #1 */ -#define ENE_CIRCFG 0xFEC0 -#define ENE_CIRCFG_RX_EN 0x01 /* RX enable */ -#define ENE_CIRCFG_RX_IRQ 0x02 /* Enable hardware interrupt */ -#define ENE_CIRCFG_REV_POL 0x04 /* Input polarity reversed */ -#define ENE_CIRCFG_CARR_DEMOD 0x08 /* Enable carrier demodulator */ - -#define ENE_CIRCFG_TX_EN 0x10 /* TX enable */ -#define ENE_CIRCFG_TX_IRQ 0x20 /* Send interrupt on TX done */ -#define ENE_CIRCFG_TX_POL_REV 0x40 /* TX polarity reversed */ -#define ENE_CIRCFG_TX_CARR 0x80 /* send TX carrier or not */ - -/* CIR config register #2 */ -#define ENE_CIRCFG2 0xFEC1 -#define ENE_CIRCFG2_RLC 0x00 -#define ENE_CIRCFG2_RC5 0x01 -#define ENE_CIRCFG2_RC6 0x02 -#define ENE_CIRCFG2_NEC 0x03 -#define ENE_CIRCFG2_CARR_DETECT 0x10 /* Enable carrier detection */ -#define ENE_CIRCFG2_GPIO0A 0x20 /* Use GPIO0A instead of GPIO40 for input */ -#define ENE_CIRCFG2_FAST_SAMPL1 0x40 /* Fast leading pulse detection for RC6 */ -#define ENE_CIRCFG2_FAST_SAMPL2 0x80 /* Fast data detection for RC6 */ - -/* Knobs for protocol decoding - will document when/if will use them */ -#define ENE_CIRPF 0xFEC2 -#define ENE_CIRHIGH 0xFEC3 -#define ENE_CIRBIT 0xFEC4 -#define ENE_CIRSTART 0xFEC5 -#define ENE_CIRSTART2 0xFEC6 - -/* Actual register which contains RLC RX data - read by firmware */ -#define ENE_CIRDAT_IN 0xFEC7 - - -/* RLC configuration - sample period (1us resulution) + idle mode */ -#define ENE_CIRRLC_CFG 0xFEC8 -#define ENE_CIRRLC_CFG_OVERFLOW 0x80 /* interrupt on overflows if set */ -#define ENE_DEFAULT_SAMPLE_PERIOD 50 - -/* Two byte RLC TX buffer */ -#define ENE_CIRRLC_OUT0 0xFEC9 -#define ENE_CIRRLC_OUT1 0xFECA -#define ENE_CIRRLC_OUT_PULSE 0x80 /* Transmitted sample is pulse */ -#define ENE_CIRRLC_OUT_MASK 0x7F - - -/* Carrier detect setting - * Low nibble - number of carrier pulses to average - * High nibble - number of initial carrier pulses to discard - */ -#define ENE_CIRCAR_PULS 0xFECB - -/* detected RX carrier period (resolution: 500 ns) */ -#define ENE_CIRCAR_PRD 0xFECC -#define ENE_CIRCAR_PRD_VALID 0x80 /* data valid content valid */ - -/* detected RX carrier pulse width (resolution: 500 ns) */ -#define ENE_CIRCAR_HPRD 0xFECD - -/* TX period (resolution: 500 ns, minimum 2)*/ -#define ENE_CIRMOD_PRD 0xFECE -#define ENE_CIRMOD_PRD_POL 0x80 /* TX carrier polarity*/ - -#define ENE_CIRMOD_PRD_MAX 0x7F /* 15.87 kHz */ -#define ENE_CIRMOD_PRD_MIN 0x02 /* 1 Mhz */ - -/* TX pulse width (resolution: 500 ns)*/ -#define ENE_CIRMOD_HPRD 0xFECF - -/* Hardware versions */ -#define ENE_ECHV 0xFF00 /* hardware revision */ -#define ENE_PLLFRH 0xFF16 -#define ENE_PLLFRL 0xFF17 -#define ENE_DEFAULT_PLL_FREQ 1000 - -#define ENE_ECSTS 0xFF1D -#define ENE_ECSTS_RSRVD 0x04 - -#define ENE_ECVER_MAJOR 0xFF1E /* chip version */ -#define ENE_ECVER_MINOR 0xFF1F -#define ENE_HW_VER_OLD 0xFD00 - -/******************************************************************************/ - -#define ENE_DRIVER_NAME "ene_ir" - -#define ENE_IRQ_RX 1 -#define ENE_IRQ_TX 2 - -#define ENE_HW_B 1 /* 3926B */ -#define ENE_HW_C 2 /* 3926C */ -#define ENE_HW_D 3 /* 3926D or later */ - -#define ene_printk(level, text, ...) \ - printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__) - -#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__) -#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__) - - -#define __dbg(level, format, ...) \ - do { \ - if (debug >= level) \ - printk(KERN_DEBUG ENE_DRIVER_NAME \ - ": " format "\n", ## __VA_ARGS__); \ - } while (0) - - -#define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__) -#define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__) -#define dbg_regs(format, ...) __dbg(3, format, ## __VA_ARGS__) - -struct ene_device { - struct pnp_dev *pnp_dev; - struct rc_dev *rdev; - - /* hw IO settings */ - long hw_io; - int irq; - spinlock_t hw_lock; - - /* HW features */ - int hw_revision; /* hardware revision */ - bool hw_use_gpio_0a; /* gpio0a is demodulated input*/ - bool hw_extra_buffer; /* hardware has 'extra buffer' */ - bool hw_fan_input; /* fan input is IR data source */ - bool hw_learning_and_tx_capable; /* learning & tx capable */ - int pll_freq; - int buffer_len; - - /* Extra RX buffer location */ - int extra_buf1_address; - int extra_buf1_len; - int extra_buf2_address; - int extra_buf2_len; - - /* HW state*/ - int r_pointer; /* pointer to next sample to read */ - int w_pointer; /* pointer to next sample hw will write */ - bool rx_fan_input_inuse; /* is fan input in use for rx*/ - int tx_reg; /* current reg used for TX */ - u8 saved_conf1; /* saved FEC0 reg */ - unsigned int tx_sample; /* current sample for TX */ - bool tx_sample_pulse; /* current sample is pulse */ - - /* TX buffer */ - int *tx_buffer; /* input samples buffer*/ - int tx_pos; /* position in that bufer */ - int tx_len; /* current len of tx buffer */ - int tx_done; /* done transmitting */ - /* one more sample pending*/ - struct completion tx_complete; /* TX completion */ - struct timer_list tx_sim_timer; - - /* TX settings */ - int tx_period; - int tx_duty_cycle; - int transmitter_mask; - - /* RX settings */ - bool learning_mode_enabled; /* learning input enabled */ - bool carrier_detect_enabled; /* carrier detect enabled */ - int rx_period_adjust; - bool rx_enabled; -}; - -static int ene_irq_status(struct ene_device *dev); -static void ene_rx_read_hw_pointer(struct ene_device *dev); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/imon.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/imon.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/imon.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/imon.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2457 +0,0 @@ -/* - * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD - * - * Copyright(C) 2010 Jarod Wilson - * Portions based on the original lirc_imon driver, - * Copyright(C) 2004 Venky Raju(dev@venky.ws) - * - * Huge thanks to R. Geoff Newbury for invaluable debugging on the - * 0xffdc iMON devices, and for sending me one to hack on, without - * which the support for them wouldn't be nearly as good. Thanks - * also to the numerous 0xffdc device owners that tested auto-config - * support for me and provided debug dumps from their devices. - * - * imon 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#define MOD_AUTHOR "Jarod Wilson " -#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" -#define MOD_NAME "imon" -#define MOD_VERSION "0.9.2" - -#define DISPLAY_MINOR_BASE 144 -#define DEVICE_NAME "lcd%d" - -#define BUF_CHUNK_SIZE 8 -#define BUF_SIZE 128 - -#define BIT_DURATION 250 /* each bit received is 250us */ - -#define IMON_CLOCK_ENABLE_PACKETS 2 - -/*** P R O T O T Y P E S ***/ - -/* USB Callback prototypes */ -static int imon_probe(struct usb_interface *interface, - const struct usb_device_id *id); -static void imon_disconnect(struct usb_interface *interface); -static void usb_rx_callback_intf0(struct urb *urb); -static void usb_rx_callback_intf1(struct urb *urb); -static void usb_tx_callback(struct urb *urb); - -/* suspend/resume support */ -static int imon_resume(struct usb_interface *intf); -static int imon_suspend(struct usb_interface *intf, pm_message_t message); - -/* Display file_operations function prototypes */ -static int display_open(struct inode *inode, struct file *file); -static int display_close(struct inode *inode, struct file *file); - -/* VFD write operation */ -static ssize_t vfd_write(struct file *file, const char *buf, - size_t n_bytes, loff_t *pos); - -/* LCD file_operations override function prototypes */ -static ssize_t lcd_write(struct file *file, const char *buf, - size_t n_bytes, loff_t *pos); - -/*** G L O B A L S ***/ - -struct imon_context { - struct device *dev; - /* Newer devices have two interfaces */ - struct usb_device *usbdev_intf0; - struct usb_device *usbdev_intf1; - - bool display_supported; /* not all controllers do */ - bool display_isopen; /* display port has been opened */ - bool rf_device; /* true if iMON 2.4G LT/DT RF device */ - bool rf_isassociating; /* RF remote associating */ - bool dev_present_intf0; /* USB device presence, interface 0 */ - bool dev_present_intf1; /* USB device presence, interface 1 */ - - struct mutex lock; /* to lock this object */ - wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ - - struct usb_endpoint_descriptor *rx_endpoint_intf0; - struct usb_endpoint_descriptor *rx_endpoint_intf1; - struct usb_endpoint_descriptor *tx_endpoint; - struct urb *rx_urb_intf0; - struct urb *rx_urb_intf1; - struct urb *tx_urb; - bool tx_control; - unsigned char usb_rx_buf[8]; - unsigned char usb_tx_buf[8]; - - struct tx_t { - unsigned char data_buf[35]; /* user data buffer */ - struct completion finished; /* wait for write to finish */ - bool busy; /* write in progress */ - int status; /* status of tx completion */ - } tx; - - u16 vendor; /* usb vendor ID */ - u16 product; /* usb product ID */ - - struct rc_dev *rdev; /* rc-core device for remote */ - struct input_dev *idev; /* input device for panel & IR mouse */ - struct input_dev *touch; /* input device for touchscreen */ - - spinlock_t kc_lock; /* make sure we get keycodes right */ - u32 kc; /* current input keycode */ - u32 last_keycode; /* last reported input keycode */ - u32 rc_scancode; /* the computed remote scancode */ - u8 rc_toggle; /* the computed remote toggle bit */ - u64 rc_type; /* iMON or MCE (RC6) IR protocol? */ - bool release_code; /* some keys send a release code */ - - u8 display_type; /* store the display type */ - bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */ - - char name_rdev[128]; /* rc input device name */ - char phys_rdev[64]; /* rc input device phys path */ - - char name_idev[128]; /* input device name */ - char phys_idev[64]; /* input device phys path */ - - char name_touch[128]; /* touch screen name */ - char phys_touch[64]; /* touch screen phys path */ - struct timer_list ttimer; /* touch screen timer */ - int touch_x; /* x coordinate on touchscreen */ - int touch_y; /* y coordinate on touchscreen */ -}; - -#define TOUCH_TIMEOUT (HZ/30) - -/* vfd character device file operations */ -static const struct file_operations vfd_fops = { - .owner = THIS_MODULE, - .open = &display_open, - .write = &vfd_write, - .release = &display_close, - .llseek = noop_llseek, -}; - -/* lcd character device file operations */ -static const struct file_operations lcd_fops = { - .owner = THIS_MODULE, - .open = &display_open, - .write = &lcd_write, - .release = &display_close, - .llseek = noop_llseek, -}; - -enum { - IMON_DISPLAY_TYPE_AUTO = 0, - IMON_DISPLAY_TYPE_VFD = 1, - IMON_DISPLAY_TYPE_LCD = 2, - IMON_DISPLAY_TYPE_VGA = 3, - IMON_DISPLAY_TYPE_NONE = 4, -}; - -enum { - IMON_KEY_IMON = 0, - IMON_KEY_MCE = 1, - IMON_KEY_PANEL = 2, -}; - -/* - * USB Device ID for iMON USB Control Boards - * - * The Windows drivers contain 6 different inf files, more or less one for - * each new device until the 0x0034-0x0046 devices, which all use the same - * driver. Some of the devices in the 34-46 range haven't been definitively - * identified yet. Early devices have either a TriGem Computer, Inc. or a - * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later - * devices use the SoundGraph vendor ID (0x15c2). This driver only supports - * the ffdc and later devices, which do onboard decoding. - */ -static struct usb_device_id imon_usb_id_table[] = { - /* - * Several devices with this same device ID, all use iMON_PAD.inf - * SoundGraph iMON PAD (IR & VFD) - * SoundGraph iMON PAD (IR & LCD) - * SoundGraph iMON Knob (IR only) - */ - { USB_DEVICE(0x15c2, 0xffdc) }, - - /* - * Newer devices, all driven by the latest iMON Windows driver, full - * list of device IDs extracted via 'strings Setup/data1.hdr |grep 15c2' - * Need user input to fill in details on unknown devices. - */ - /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ - { USB_DEVICE(0x15c2, 0x0034) }, - /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ - { USB_DEVICE(0x15c2, 0x0035) }, - /* SoundGraph iMON OEM VFD (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0036) }, - /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0037) }, - /* SoundGraph iMON OEM LCD (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0038) }, - /* SoundGraph iMON UltraBay (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0039) }, - /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003a) }, - /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003b) }, - /* SoundGraph iMON OEM Inside (IR only) */ - { USB_DEVICE(0x15c2, 0x003c) }, - /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003d) }, - /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003e) }, - /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003f) }, - /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0040) }, - /* SoundGraph iMON MINI (IR only) */ - { USB_DEVICE(0x15c2, 0x0041) }, - /* Antec Veris Multimedia Station EZ External (IR only) */ - { USB_DEVICE(0x15c2, 0x0042) }, - /* Antec Veris Multimedia Station Basic Internal (IR only) */ - { USB_DEVICE(0x15c2, 0x0043) }, - /* Antec Veris Multimedia Station Elite (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0044) }, - /* Antec Veris Multimedia Station Premiere (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0045) }, - /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0046) }, - {} -}; - -/* USB Device data */ -static struct usb_driver imon_driver = { - .name = MOD_NAME, - .probe = imon_probe, - .disconnect = imon_disconnect, - .suspend = imon_suspend, - .resume = imon_resume, - .id_table = imon_usb_id_table, -}; - -static struct usb_class_driver imon_vfd_class = { - .name = DEVICE_NAME, - .fops = &vfd_fops, - .minor_base = DISPLAY_MINOR_BASE, -}; - -static struct usb_class_driver imon_lcd_class = { - .name = DEVICE_NAME, - .fops = &lcd_fops, - .minor_base = DISPLAY_MINOR_BASE, -}; - -/* imon receiver front panel/knob key table */ -static const struct { - u64 hw_code; - u32 keycode; -} imon_panel_key_table[] = { - { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ - { 0x000000001200ffeell, KEY_UP }, - { 0x000000001300ffeell, KEY_DOWN }, - { 0x000000001400ffeell, KEY_LEFT }, - { 0x000000001500ffeell, KEY_RIGHT }, - { 0x000000001600ffeell, KEY_ENTER }, - { 0x000000001700ffeell, KEY_ESC }, - { 0x000000001f00ffeell, KEY_AUDIO }, - { 0x000000002000ffeell, KEY_VIDEO }, - { 0x000000002100ffeell, KEY_CAMERA }, - { 0x000000002700ffeell, KEY_DVD }, - { 0x000000002300ffeell, KEY_TV }, - { 0x000000002b00ffeell, KEY_EXIT }, - { 0x000000002c00ffeell, KEY_SELECT }, - { 0x000000002d00ffeell, KEY_MENU }, - { 0x000000000500ffeell, KEY_PREVIOUS }, - { 0x000000000700ffeell, KEY_REWIND }, - { 0x000000000400ffeell, KEY_STOP }, - { 0x000000003c00ffeell, KEY_PLAYPAUSE }, - { 0x000000000800ffeell, KEY_FASTFORWARD }, - { 0x000000000600ffeell, KEY_NEXT }, - { 0x000000010000ffeell, KEY_RIGHT }, - { 0x000001000000ffeell, KEY_LEFT }, - { 0x000000003d00ffeell, KEY_SELECT }, - { 0x000100000000ffeell, KEY_VOLUMEUP }, - { 0x010000000000ffeell, KEY_VOLUMEDOWN }, - { 0x000000000100ffeell, KEY_MUTE }, - /* 0xffdc iMON MCE VFD */ - { 0x00010000ffffffeell, KEY_VOLUMEUP }, - { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, - /* iMON Knob values */ - { 0x000100ffffffffeell, KEY_VOLUMEUP }, - { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, - { 0x000008ffffffffeell, KEY_MUTE }, -}; - -/* to prevent races between open() and disconnect(), probing, etc */ -static DEFINE_MUTEX(driver_lock); - -/* Module bookkeeping bits */ -MODULE_AUTHOR(MOD_AUTHOR); -MODULE_DESCRIPTION(MOD_DESC); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, imon_usb_id_table); - -static bool debug; -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); - -/* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */ -static int display_type; -module_param(display_type, int, S_IRUGO); -MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, " - "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); - -static int pad_stabilize = 1; -module_param(pad_stabilize, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD " - "presses in arrow key mode. 0=disable, 1=enable (default)."); - -/* - * In certain use cases, mouse mode isn't really helpful, and could actually - * cause confusion, so allow disabling it when the IR device is open. - */ -static bool nomouse; -module_param(nomouse, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is " - "open. 0=don't disable, 1=disable. (default: don't disable)"); - -/* threshold at which a pad push registers as an arrow key in kbd mode */ -static int pad_thresh; -module_param(pad_thresh, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an " - "arrow key in kbd mode (default: 28)"); - - -static void free_imon_context(struct imon_context *ictx) -{ - struct device *dev = ictx->dev; - - usb_free_urb(ictx->tx_urb); - usb_free_urb(ictx->rx_urb_intf0); - usb_free_urb(ictx->rx_urb_intf1); - kfree(ictx); - - dev_dbg(dev, "%s: iMON context freed\n", __func__); -} - -/** - * Called when the Display device (e.g. /dev/lcd0) - * is opened by the application. - */ -static int display_open(struct inode *inode, struct file *file) -{ - struct usb_interface *interface; - struct imon_context *ictx = NULL; - int subminor; - int retval = 0; - - /* prevent races with disconnect */ - mutex_lock(&driver_lock); - - subminor = iminor(inode); - interface = usb_find_interface(&imon_driver, subminor); - if (!interface) { - pr_err("could not find interface for minor %d\n", subminor); - retval = -ENODEV; - goto exit; - } - ictx = usb_get_intfdata(interface); - - if (!ictx) { - pr_err("no context found for minor %d\n", subminor); - retval = -ENODEV; - goto exit; - } - - mutex_lock(&ictx->lock); - - if (!ictx->display_supported) { - pr_err("display not supported by device\n"); - retval = -ENODEV; - } else if (ictx->display_isopen) { - pr_err("display port is already open\n"); - retval = -EBUSY; - } else { - ictx->display_isopen = true; - file->private_data = ictx; - dev_dbg(ictx->dev, "display port opened\n"); - } - - mutex_unlock(&ictx->lock); - -exit: - mutex_unlock(&driver_lock); - return retval; -} - -/** - * Called when the display device (e.g. /dev/lcd0) - * is closed by the application. - */ -static int display_close(struct inode *inode, struct file *file) -{ - struct imon_context *ictx = NULL; - int retval = 0; - - ictx = file->private_data; - - if (!ictx) { - pr_err("no context for device\n"); - return -ENODEV; - } - - mutex_lock(&ictx->lock); - - if (!ictx->display_supported) { - pr_err("display not supported by device\n"); - retval = -ENODEV; - } else if (!ictx->display_isopen) { - pr_err("display is not open\n"); - retval = -EIO; - } else { - ictx->display_isopen = false; - dev_dbg(ictx->dev, "display port closed\n"); - if (!ictx->dev_present_intf0) { - /* - * Device disconnected before close and IR port is not - * open. If IR port is open, context will be deleted by - * ir_close. - */ - mutex_unlock(&ictx->lock); - free_imon_context(ictx); - return retval; - } - } - - mutex_unlock(&ictx->lock); - return retval; -} - -/** - * Sends a packet to the device -- this function must be called - * with ictx->lock held. - */ -static int send_packet(struct imon_context *ictx) -{ - unsigned int pipe; - unsigned long timeout; - int interval = 0; - int retval = 0; - struct usb_ctrlrequest *control_req = NULL; - - /* Check if we need to use control or interrupt urb */ - if (!ictx->tx_control) { - pipe = usb_sndintpipe(ictx->usbdev_intf0, - ictx->tx_endpoint->bEndpointAddress); - interval = ictx->tx_endpoint->bInterval; - - usb_fill_int_urb(ictx->tx_urb, ictx->usbdev_intf0, pipe, - ictx->usb_tx_buf, - sizeof(ictx->usb_tx_buf), - usb_tx_callback, ictx, interval); - - ictx->tx_urb->actual_length = 0; - } else { - /* fill request into kmalloc'ed space: */ - control_req = kmalloc(sizeof(struct usb_ctrlrequest), - GFP_KERNEL); - if (control_req == NULL) - return -ENOMEM; - - /* setup packet is '21 09 0200 0001 0008' */ - control_req->bRequestType = 0x21; - control_req->bRequest = 0x09; - control_req->wValue = cpu_to_le16(0x0200); - control_req->wIndex = cpu_to_le16(0x0001); - control_req->wLength = cpu_to_le16(0x0008); - - /* control pipe is endpoint 0x00 */ - pipe = usb_sndctrlpipe(ictx->usbdev_intf0, 0); - - /* build the control urb */ - usb_fill_control_urb(ictx->tx_urb, ictx->usbdev_intf0, - pipe, (unsigned char *)control_req, - ictx->usb_tx_buf, - sizeof(ictx->usb_tx_buf), - usb_tx_callback, ictx); - ictx->tx_urb->actual_length = 0; - } - - init_completion(&ictx->tx.finished); - ictx->tx.busy = true; - smp_rmb(); /* ensure later readers know we're busy */ - - retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL); - if (retval) { - ictx->tx.busy = false; - smp_rmb(); /* ensure later readers know we're not busy */ - pr_err("error submitting urb(%d)\n", retval); - } else { - /* Wait for transmission to complete (or abort) */ - mutex_unlock(&ictx->lock); - retval = wait_for_completion_interruptible( - &ictx->tx.finished); - if (retval) - pr_err("task interrupted\n"); - mutex_lock(&ictx->lock); - - retval = ictx->tx.status; - if (retval) - pr_err("packet tx failed (%d)\n", retval); - } - - kfree(control_req); - - /* - * Induce a mandatory 5ms delay before returning, as otherwise, - * send_packet can get called so rapidly as to overwhelm the device, - * particularly on faster systems and/or those with quirky usb. - */ - timeout = msecs_to_jiffies(5); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(timeout); - - return retval; -} - -/** - * Sends an associate packet to the iMON 2.4G. - * - * This might not be such a good idea, since it has an id collision with - * some versions of the "IR & VFD" combo. The only way to determine if it - * is an RF version is to look at the product description string. (Which - * we currently do not fetch). - */ -static int send_associate_24g(struct imon_context *ictx) -{ - int retval; - const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20 }; - - if (!ictx) { - pr_err("no context for device\n"); - return -ENODEV; - } - - if (!ictx->dev_present_intf0) { - pr_err("no iMON device present\n"); - return -ENODEV; - } - - memcpy(ictx->usb_tx_buf, packet, sizeof(packet)); - retval = send_packet(ictx); - - return retval; -} - -/** - * Sends packets to setup and show clock on iMON display - * - * Arguments: year - last 2 digits of year, month - 1..12, - * day - 1..31, dow - day of the week (0-Sun...6-Sat), - * hour - 0..23, minute - 0..59, second - 0..59 - */ -static int send_set_imon_clock(struct imon_context *ictx, - unsigned int year, unsigned int month, - unsigned int day, unsigned int dow, - unsigned int hour, unsigned int minute, - unsigned int second) -{ - unsigned char clock_enable_pkt[IMON_CLOCK_ENABLE_PACKETS][8]; - int retval = 0; - int i; - - if (!ictx) { - pr_err("no context for device\n"); - return -ENODEV; - } - - switch (ictx->display_type) { - case IMON_DISPLAY_TYPE_LCD: - clock_enable_pkt[0][0] = 0x80; - clock_enable_pkt[0][1] = year; - clock_enable_pkt[0][2] = month-1; - clock_enable_pkt[0][3] = day; - clock_enable_pkt[0][4] = hour; - clock_enable_pkt[0][5] = minute; - clock_enable_pkt[0][6] = second; - - clock_enable_pkt[1][0] = 0x80; - clock_enable_pkt[1][1] = 0; - clock_enable_pkt[1][2] = 0; - clock_enable_pkt[1][3] = 0; - clock_enable_pkt[1][4] = 0; - clock_enable_pkt[1][5] = 0; - clock_enable_pkt[1][6] = 0; - - if (ictx->product == 0xffdc) { - clock_enable_pkt[0][7] = 0x50; - clock_enable_pkt[1][7] = 0x51; - } else { - clock_enable_pkt[0][7] = 0x88; - clock_enable_pkt[1][7] = 0x8a; - } - - break; - - case IMON_DISPLAY_TYPE_VFD: - clock_enable_pkt[0][0] = year; - clock_enable_pkt[0][1] = month-1; - clock_enable_pkt[0][2] = day; - clock_enable_pkt[0][3] = dow; - clock_enable_pkt[0][4] = hour; - clock_enable_pkt[0][5] = minute; - clock_enable_pkt[0][6] = second; - clock_enable_pkt[0][7] = 0x40; - - clock_enable_pkt[1][0] = 0; - clock_enable_pkt[1][1] = 0; - clock_enable_pkt[1][2] = 1; - clock_enable_pkt[1][3] = 0; - clock_enable_pkt[1][4] = 0; - clock_enable_pkt[1][5] = 0; - clock_enable_pkt[1][6] = 0; - clock_enable_pkt[1][7] = 0x42; - - break; - - default: - return -ENODEV; - } - - for (i = 0; i < IMON_CLOCK_ENABLE_PACKETS; i++) { - memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8); - retval = send_packet(ictx); - if (retval) { - pr_err("send_packet failed for packet %d\n", i); - break; - } - } - - return retval; -} - -/** - * These are the sysfs functions to handle the association on the iMON 2.4G LT. - */ -static ssize_t show_associate_remote(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct imon_context *ictx = dev_get_drvdata(d); - - if (!ictx) - return -ENODEV; - - mutex_lock(&ictx->lock); - if (ictx->rf_isassociating) - strcpy(buf, "associating\n"); - else - strcpy(buf, "closed\n"); - - dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for " - "instructions on how to associate your iMON 2.4G DT/LT " - "remote\n"); - mutex_unlock(&ictx->lock); - return strlen(buf); -} - -static ssize_t store_associate_remote(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct imon_context *ictx; - - ictx = dev_get_drvdata(d); - - if (!ictx) - return -ENODEV; - - mutex_lock(&ictx->lock); - ictx->rf_isassociating = true; - send_associate_24g(ictx); - mutex_unlock(&ictx->lock); - - return count; -} - -/** - * sysfs functions to control internal imon clock - */ -static ssize_t show_imon_clock(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct imon_context *ictx = dev_get_drvdata(d); - size_t len; - - if (!ictx) - return -ENODEV; - - mutex_lock(&ictx->lock); - - if (!ictx->display_supported) { - len = snprintf(buf, PAGE_SIZE, "Not supported."); - } else { - len = snprintf(buf, PAGE_SIZE, - "To set the clock on your iMON display:\n" - "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n" - "%s", ictx->display_isopen ? - "\nNOTE: imon device must be closed\n" : ""); - } - - mutex_unlock(&ictx->lock); - - return len; -} - -static ssize_t store_imon_clock(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct imon_context *ictx = dev_get_drvdata(d); - ssize_t retval; - unsigned int year, month, day, dow, hour, minute, second; - - if (!ictx) - return -ENODEV; - - mutex_lock(&ictx->lock); - - if (!ictx->display_supported) { - retval = -ENODEV; - goto exit; - } else if (ictx->display_isopen) { - retval = -EBUSY; - goto exit; - } - - if (sscanf(buf, "%u %u %u %u %u %u %u", &year, &month, &day, &dow, - &hour, &minute, &second) != 7) { - retval = -EINVAL; - goto exit; - } - - if ((month < 1 || month > 12) || - (day < 1 || day > 31) || (dow > 6) || - (hour > 23) || (minute > 59) || (second > 59)) { - retval = -EINVAL; - goto exit; - } - - retval = send_set_imon_clock(ictx, year, month, day, dow, - hour, minute, second); - if (retval) - goto exit; - - retval = count; -exit: - mutex_unlock(&ictx->lock); - - return retval; -} - - -static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock, - store_imon_clock); - -static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote, - store_associate_remote); - -static struct attribute *imon_display_sysfs_entries[] = { - &dev_attr_imon_clock.attr, - NULL -}; - -static struct attribute_group imon_display_attr_group = { - .attrs = imon_display_sysfs_entries -}; - -static struct attribute *imon_rf_sysfs_entries[] = { - &dev_attr_associate_remote.attr, - NULL -}; - -static struct attribute_group imon_rf_attr_group = { - .attrs = imon_rf_sysfs_entries -}; - -/** - * Writes data to the VFD. The iMON VFD is 2x16 characters - * and requires data in 5 consecutive USB interrupt packets, - * each packet but the last carrying 7 bytes. - * - * I don't know if the VFD board supports features such as - * scrolling, clearing rows, blanking, etc. so at - * the caller must provide a full screen of data. If fewer - * than 32 bytes are provided spaces will be appended to - * generate a full screen. - */ -static ssize_t vfd_write(struct file *file, const char *buf, - size_t n_bytes, loff_t *pos) -{ - int i; - int offset; - int seq; - int retval = 0; - struct imon_context *ictx; - const unsigned char vfd_packet6[] = { - 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; - - ictx = file->private_data; - if (!ictx) { - pr_err("no context for device\n"); - return -ENODEV; - } - - mutex_lock(&ictx->lock); - - if (!ictx->dev_present_intf0) { - pr_err("no iMON device present\n"); - retval = -ENODEV; - goto exit; - } - - if (n_bytes <= 0 || n_bytes > 32) { - pr_err("invalid payload size\n"); - retval = -EINVAL; - goto exit; - } - - if (copy_from_user(ictx->tx.data_buf, buf, n_bytes)) { - retval = -EFAULT; - goto exit; - } - - /* Pad with spaces */ - for (i = n_bytes; i < 32; ++i) - ictx->tx.data_buf[i] = ' '; - - for (i = 32; i < 35; ++i) - ictx->tx.data_buf[i] = 0xFF; - - offset = 0; - seq = 0; - - do { - memcpy(ictx->usb_tx_buf, ictx->tx.data_buf + offset, 7); - ictx->usb_tx_buf[7] = (unsigned char) seq; - - retval = send_packet(ictx); - if (retval) { - pr_err("send packet failed for packet #%d\n", seq / 2); - goto exit; - } else { - seq += 2; - offset += 7; - } - - } while (offset < 35); - - /* Send packet #6 */ - memcpy(ictx->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); - ictx->usb_tx_buf[7] = (unsigned char) seq; - retval = send_packet(ictx); - if (retval) - pr_err("send packet failed for packet #%d\n", seq / 2); - -exit: - mutex_unlock(&ictx->lock); - - return (!retval) ? n_bytes : retval; -} - -/** - * Writes data to the LCD. The iMON OEM LCD screen expects 8-byte - * packets. We accept data as 16 hexadecimal digits, followed by a - * newline (to make it easy to drive the device from a command-line - * -- even though the actual binary data is a bit complicated). - * - * The device itself is not a "traditional" text-mode display. It's - * actually a 16x96 pixel bitmap display. That means if you want to - * display text, you've got to have your own "font" and translate the - * text into bitmaps for display. This is really flexible (you can - * display whatever diacritics you need, and so on), but it's also - * a lot more complicated than most LCDs... - */ -static ssize_t lcd_write(struct file *file, const char *buf, - size_t n_bytes, loff_t *pos) -{ - int retval = 0; - struct imon_context *ictx; - - ictx = file->private_data; - if (!ictx) { - pr_err("no context for device\n"); - return -ENODEV; - } - - mutex_lock(&ictx->lock); - - if (!ictx->display_supported) { - pr_err("no iMON display present\n"); - retval = -ENODEV; - goto exit; - } - - if (n_bytes != 8) { - pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes); - retval = -EINVAL; - goto exit; - } - - if (copy_from_user(ictx->usb_tx_buf, buf, 8)) { - retval = -EFAULT; - goto exit; - } - - retval = send_packet(ictx); - if (retval) { - pr_err("send packet failed!\n"); - goto exit; - } else { - dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", - __func__, (int) n_bytes); - } -exit: - mutex_unlock(&ictx->lock); - return (!retval) ? n_bytes : retval; -} - -/** - * Callback function for USB core API: transmit data - */ -static void usb_tx_callback(struct urb *urb) -{ - struct imon_context *ictx; - - if (!urb) - return; - ictx = (struct imon_context *)urb->context; - if (!ictx) - return; - - ictx->tx.status = urb->status; - - /* notify waiters that write has finished */ - ictx->tx.busy = false; - smp_rmb(); /* ensure later readers know we're not busy */ - complete(&ictx->tx.finished); -} - -/** - * report touchscreen input - */ -static void imon_touch_display_timeout(unsigned long data) -{ - struct imon_context *ictx = (struct imon_context *)data; - - if (ictx->display_type != IMON_DISPLAY_TYPE_VGA) - return; - - input_report_abs(ictx->touch, ABS_X, ictx->touch_x); - input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); - input_report_key(ictx->touch, BTN_TOUCH, 0x00); - input_sync(ictx->touch); -} - -/** - * iMON IR receivers support two different signal sets -- those used by - * the iMON remotes, and those used by the Windows MCE remotes (which is - * really just RC-6), but only one or the other at a time, as the signals - * are decoded onboard the receiver. - */ -static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) -{ - int retval; - struct imon_context *ictx = rc->priv; - struct device *dev = ictx->dev; - unsigned char ir_proto_packet[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; - - if (rc_type && !(rc_type & rc->allowed_protos)) - dev_warn(dev, "Looks like you're trying to use an IR protocol " - "this device does not support\n"); - - switch (rc_type) { - case RC_TYPE_RC6: - dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); - ir_proto_packet[0] = 0x01; - break; - case RC_TYPE_UNKNOWN: - case RC_TYPE_OTHER: - dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); - if (!pad_stabilize) - dev_dbg(dev, "PAD stabilize functionality disabled\n"); - /* ir_proto_packet[0] = 0x00; // already the default */ - rc_type = RC_TYPE_OTHER; - break; - default: - dev_warn(dev, "Unsupported IR protocol specified, overriding " - "to iMON IR protocol\n"); - if (!pad_stabilize) - dev_dbg(dev, "PAD stabilize functionality disabled\n"); - /* ir_proto_packet[0] = 0x00; // already the default */ - rc_type = RC_TYPE_OTHER; - break; - } - - memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); - - retval = send_packet(ictx); - if (retval) - goto out; - - ictx->rc_type = rc_type; - ictx->pad_mouse = false; - -out: - return retval; -} - -static inline int tv2int(const struct timeval *a, const struct timeval *b) -{ - int usecs = 0; - int sec = 0; - - if (b->tv_usec > a->tv_usec) { - usecs = 1000000; - sec--; - } - - usecs += a->tv_usec - b->tv_usec; - - sec += a->tv_sec - b->tv_sec; - sec *= 1000; - usecs /= 1000; - sec += usecs; - - if (sec < 0) - sec = 1000; - - return sec; -} - -/** - * The directional pad behaves a bit differently, depending on whether this is - * one of the older ffdc devices or a newer device. Newer devices appear to - * have a higher resolution matrix for more precise mouse movement, but it - * makes things overly sensitive in keyboard mode, so we do some interesting - * contortions to make it less touchy. Older devices run through the same - * routine with shorter timeout and a smaller threshold. - */ -static int stabilize(int a, int b, u16 timeout, u16 threshold) -{ - struct timeval ct; - static struct timeval prev_time = {0, 0}; - static struct timeval hit_time = {0, 0}; - static int x, y, prev_result, hits; - int result = 0; - int msec, msec_hit; - - do_gettimeofday(&ct); - msec = tv2int(&ct, &prev_time); - msec_hit = tv2int(&ct, &hit_time); - - if (msec > 100) { - x = 0; - y = 0; - hits = 0; - } - - x += a; - y += b; - - prev_time = ct; - - if (abs(x) > threshold || abs(y) > threshold) { - if (abs(y) > abs(x)) - result = (y > 0) ? 0x7F : 0x80; - else - result = (x > 0) ? 0x7F00 : 0x8000; - - x = 0; - y = 0; - - if (result == prev_result) { - hits++; - - if (hits > 3) { - switch (result) { - case 0x7F: - y = 17 * threshold / 30; - break; - case 0x80: - y -= 17 * threshold / 30; - break; - case 0x7F00: - x = 17 * threshold / 30; - break; - case 0x8000: - x -= 17 * threshold / 30; - break; - } - } - - if (hits == 2 && msec_hit < timeout) { - result = 0; - hits = 1; - } - } else { - prev_result = result; - hits = 1; - hit_time = ct; - } - } - - return result; -} - -static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode) -{ - u32 keycode; - u32 release; - bool is_release_code = false; - - /* Look for the initial press of a button */ - keycode = rc_g_keycode_from_table(ictx->rdev, scancode); - ictx->rc_toggle = 0x0; - ictx->rc_scancode = scancode; - - /* Look for the release of a button */ - if (keycode == KEY_RESERVED) { - release = scancode & ~0x4000; - keycode = rc_g_keycode_from_table(ictx->rdev, release); - if (keycode != KEY_RESERVED) - is_release_code = true; - } - - ictx->release_code = is_release_code; - - return keycode; -} - -static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode) -{ - u32 keycode; - -#define MCE_KEY_MASK 0x7000 -#define MCE_TOGGLE_BIT 0x8000 - - /* - * On some receivers, mce keys decode to 0x8000f04xx and 0x8000f84xx - * (the toggle bit flipping between alternating key presses), while - * on other receivers, we see 0x8000f74xx and 0x8000ff4xx. To keep - * the table trim, we always or in the bits to look up 0x8000ff4xx, - * but we can't or them into all codes, as some keys are decoded in - * a different way w/o the same use of the toggle bit... - */ - if (scancode & 0x80000000) - scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT; - - ictx->rc_scancode = scancode; - keycode = rc_g_keycode_from_table(ictx->rdev, scancode); - - /* not used in mce mode, but make sure we know its false */ - ictx->release_code = false; - - return keycode; -} - -static u32 imon_panel_key_lookup(u64 code) -{ - int i; - u32 keycode = KEY_RESERVED; - - for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { - if (imon_panel_key_table[i].hw_code == (code | 0xffee)) { - keycode = imon_panel_key_table[i].keycode; - break; - } - } - - return keycode; -} - -static bool imon_mouse_event(struct imon_context *ictx, - unsigned char *buf, int len) -{ - char rel_x = 0x00, rel_y = 0x00; - u8 right_shift = 1; - bool mouse_input = true; - int dir = 0; - unsigned long flags; - - spin_lock_irqsave(&ictx->kc_lock, flags); - - /* newer iMON device PAD or mouse button */ - if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) { - rel_x = buf[2]; - rel_y = buf[3]; - right_shift = 1; - /* 0xffdc iMON PAD or mouse button input */ - } else if (ictx->product == 0xffdc && (buf[0] & 0x40) && - !((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01))) { - rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | - (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; - if (buf[0] & 0x02) - rel_x |= ~0x0f; - rel_x = rel_x + rel_x / 2; - rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | - (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; - if (buf[0] & 0x01) - rel_y |= ~0x0f; - rel_y = rel_y + rel_y / 2; - right_shift = 2; - /* some ffdc devices decode mouse buttons differently... */ - } else if (ictx->product == 0xffdc && (buf[0] == 0x68)) { - right_shift = 2; - /* ch+/- buttons, which we use for an emulated scroll wheel */ - } else if (ictx->kc == KEY_CHANNELUP && (buf[2] & 0x40) != 0x40) { - dir = 1; - } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) { - dir = -1; - } else - mouse_input = false; - - spin_unlock_irqrestore(&ictx->kc_lock, flags); - - if (mouse_input) { - dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); - - if (dir) { - input_report_rel(ictx->idev, REL_WHEEL, dir); - } else if (rel_x || rel_y) { - input_report_rel(ictx->idev, REL_X, rel_x); - input_report_rel(ictx->idev, REL_Y, rel_y); - } else { - input_report_key(ictx->idev, BTN_LEFT, buf[1] & 0x1); - input_report_key(ictx->idev, BTN_RIGHT, - buf[1] >> right_shift & 0x1); - } - input_sync(ictx->idev); - spin_lock_irqsave(&ictx->kc_lock, flags); - ictx->last_keycode = ictx->kc; - spin_unlock_irqrestore(&ictx->kc_lock, flags); - } - - return mouse_input; -} - -static void imon_touch_event(struct imon_context *ictx, unsigned char *buf) -{ - mod_timer(&ictx->ttimer, jiffies + TOUCH_TIMEOUT); - ictx->touch_x = (buf[0] << 4) | (buf[1] >> 4); - ictx->touch_y = 0xfff - ((buf[2] << 4) | (buf[1] & 0xf)); - input_report_abs(ictx->touch, ABS_X, ictx->touch_x); - input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); - input_report_key(ictx->touch, BTN_TOUCH, 0x01); - input_sync(ictx->touch); -} - -static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) -{ - int dir = 0; - char rel_x = 0x00, rel_y = 0x00; - u16 timeout, threshold; - u32 scancode = KEY_RESERVED; - unsigned long flags; - - /* - * The imon directional pad functions more like a touchpad. Bytes 3 & 4 - * contain a position coordinate (x,y), with each component ranging - * from -14 to 14. We want to down-sample this to only 4 discrete values - * for up/down/left/right arrow keys. Also, when you get too close to - * diagonals, it has a tendancy to jump back and forth, so lets try to - * ignore when they get too close. - */ - if (ictx->product != 0xffdc) { - /* first, pad to 8 bytes so it conforms with everything else */ - buf[5] = buf[6] = buf[7] = 0; - timeout = 500; /* in msecs */ - /* (2*threshold) x (2*threshold) square */ - threshold = pad_thresh ? pad_thresh : 28; - rel_x = buf[2]; - rel_y = buf[3]; - - if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) { - if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { - dir = stabilize((int)rel_x, (int)rel_y, - timeout, threshold); - if (!dir) { - spin_lock_irqsave(&ictx->kc_lock, - flags); - ictx->kc = KEY_UNKNOWN; - spin_unlock_irqrestore(&ictx->kc_lock, - flags); - return; - } - buf[2] = dir & 0xFF; - buf[3] = (dir >> 8) & 0xFF; - scancode = be32_to_cpu(*((u32 *)buf)); - } - } else { - /* - * Hack alert: instead of using keycodes, we have - * to use hard-coded scancodes here... - */ - if (abs(rel_y) > abs(rel_x)) { - buf[2] = (rel_y > 0) ? 0x7F : 0x80; - buf[3] = 0; - if (rel_y > 0) - scancode = 0x01007f00; /* KEY_DOWN */ - else - scancode = 0x01008000; /* KEY_UP */ - } else { - buf[2] = 0; - buf[3] = (rel_x > 0) ? 0x7F : 0x80; - if (rel_x > 0) - scancode = 0x0100007f; /* KEY_RIGHT */ - else - scancode = 0x01000080; /* KEY_LEFT */ - } - } - - /* - * Handle on-board decoded pad events for e.g. older VFD/iMON-Pad - * device (15c2:ffdc). The remote generates various codes from - * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates - * 0x688301b7 and the right one 0x688481b7. All other keys generate - * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with - * reversed endianess. Extract direction from buffer, rotate endianess, - * adjust sign and feed the values into stabilize(). The resulting codes - * will be 0x01008000, 0x01007F00, which match the newer devices. - */ - } else { - timeout = 10; /* in msecs */ - /* (2*threshold) x (2*threshold) square */ - threshold = pad_thresh ? pad_thresh : 15; - - /* buf[1] is x */ - rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | - (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; - if (buf[0] & 0x02) - rel_x |= ~0x10+1; - /* buf[2] is y */ - rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | - (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; - if (buf[0] & 0x01) - rel_y |= ~0x10+1; - - buf[0] = 0x01; - buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; - - if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) { - dir = stabilize((int)rel_x, (int)rel_y, - timeout, threshold); - if (!dir) { - spin_lock_irqsave(&ictx->kc_lock, flags); - ictx->kc = KEY_UNKNOWN; - spin_unlock_irqrestore(&ictx->kc_lock, flags); - return; - } - buf[2] = dir & 0xFF; - buf[3] = (dir >> 8) & 0xFF; - scancode = be32_to_cpu(*((u32 *)buf)); - } else { - /* - * Hack alert: instead of using keycodes, we have - * to use hard-coded scancodes here... - */ - if (abs(rel_y) > abs(rel_x)) { - buf[2] = (rel_y > 0) ? 0x7F : 0x80; - buf[3] = 0; - if (rel_y > 0) - scancode = 0x01007f00; /* KEY_DOWN */ - else - scancode = 0x01008000; /* KEY_UP */ - } else { - buf[2] = 0; - buf[3] = (rel_x > 0) ? 0x7F : 0x80; - if (rel_x > 0) - scancode = 0x0100007f; /* KEY_RIGHT */ - else - scancode = 0x01000080; /* KEY_LEFT */ - } - } - } - - if (scancode) { - spin_lock_irqsave(&ictx->kc_lock, flags); - ictx->kc = imon_remote_key_lookup(ictx, scancode); - spin_unlock_irqrestore(&ictx->kc_lock, flags); - } -} - -/** - * figure out if these is a press or a release. We don't actually - * care about repeats, as those will be auto-generated within the IR - * subsystem for repeating scancodes. - */ -static int imon_parse_press_type(struct imon_context *ictx, - unsigned char *buf, u8 ktype) -{ - int press_type = 0; - unsigned long flags; - - spin_lock_irqsave(&ictx->kc_lock, flags); - - /* key release of 0x02XXXXXX key */ - if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00) - ictx->kc = ictx->last_keycode; - - /* mouse button release on (some) 0xffdc devices */ - else if (ictx->kc == KEY_RESERVED && buf[0] == 0x68 && buf[1] == 0x82 && - buf[2] == 0x81 && buf[3] == 0xb7) - ictx->kc = ictx->last_keycode; - - /* mouse button release on (some other) 0xffdc devices */ - else if (ictx->kc == KEY_RESERVED && buf[0] == 0x01 && buf[1] == 0x00 && - buf[2] == 0x81 && buf[3] == 0xb7) - ictx->kc = ictx->last_keycode; - - /* mce-specific button handling, no keyup events */ - else if (ktype == IMON_KEY_MCE) { - ictx->rc_toggle = buf[2]; - press_type = 1; - - /* incoherent or irrelevant data */ - } else if (ictx->kc == KEY_RESERVED) - press_type = -EINVAL; - - /* key release of 0xXXXXXXb7 key */ - else if (ictx->release_code) - press_type = 0; - - /* this is a button press */ - else - press_type = 1; - - spin_unlock_irqrestore(&ictx->kc_lock, flags); - - return press_type; -} - -/** - * Process the incoming packet - */ -static void imon_incoming_packet(struct imon_context *ictx, - struct urb *urb, int intf) -{ - int len = urb->actual_length; - unsigned char *buf = urb->transfer_buffer; - struct device *dev = ictx->dev; - unsigned long flags; - u32 kc; - bool norelease = false; - int i; - u64 scancode; - int press_type = 0; - int msec; - struct timeval t; - static struct timeval prev_time = { 0, 0 }; - u8 ktype; - - /* filter out junk data on the older 0xffdc imon devices */ - if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) - return; - - /* Figure out what key was pressed */ - if (len == 8 && buf[7] == 0xee) { - scancode = be64_to_cpu(*((u64 *)buf)); - ktype = IMON_KEY_PANEL; - kc = imon_panel_key_lookup(scancode); - } else { - scancode = be32_to_cpu(*((u32 *)buf)); - if (ictx->rc_type == RC_TYPE_RC6) { - ktype = IMON_KEY_IMON; - if (buf[0] == 0x80) - ktype = IMON_KEY_MCE; - kc = imon_mce_key_lookup(ictx, scancode); - } else { - ktype = IMON_KEY_IMON; - kc = imon_remote_key_lookup(ictx, scancode); - } - } - - spin_lock_irqsave(&ictx->kc_lock, flags); - /* keyboard/mouse mode toggle button */ - if (kc == KEY_KEYBOARD && !ictx->release_code) { - ictx->last_keycode = kc; - if (!nomouse) { - ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1; - dev_dbg(dev, "toggling to %s mode\n", - ictx->pad_mouse ? "mouse" : "keyboard"); - spin_unlock_irqrestore(&ictx->kc_lock, flags); - return; - } else { - ictx->pad_mouse = false; - dev_dbg(dev, "mouse mode disabled, passing key value\n"); - } - } - - ictx->kc = kc; - spin_unlock_irqrestore(&ictx->kc_lock, flags); - - /* send touchscreen events through input subsystem if touchpad data */ - if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && - buf[7] == 0x86) { - imon_touch_event(ictx, buf); - return; - - /* look for mouse events with pad in mouse mode */ - } else if (ictx->pad_mouse) { - if (imon_mouse_event(ictx, buf, len)) - return; - } - - /* Now for some special handling to convert pad input to arrow keys */ - if (((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) || - ((len == 8) && (buf[0] & 0x40) && - !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) { - len = 8; - imon_pad_to_keys(ictx, buf); - norelease = true; - } - - if (debug) { - printk(KERN_INFO "intf%d decoded packet: ", intf); - for (i = 0; i < len; ++i) - printk("%02x ", buf[i]); - printk("\n"); - } - - press_type = imon_parse_press_type(ictx, buf, ktype); - if (press_type < 0) - goto not_input_data; - - spin_lock_irqsave(&ictx->kc_lock, flags); - if (ictx->kc == KEY_UNKNOWN) - goto unknown_key; - spin_unlock_irqrestore(&ictx->kc_lock, flags); - - if (ktype != IMON_KEY_PANEL) { - if (press_type == 0) - rc_keyup(ictx->rdev); - else { - rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle); - spin_lock_irqsave(&ictx->kc_lock, flags); - ictx->last_keycode = ictx->kc; - spin_unlock_irqrestore(&ictx->kc_lock, flags); - } - return; - } - - /* Only panel type events left to process now */ - spin_lock_irqsave(&ictx->kc_lock, flags); - - /* KEY_MUTE repeats from knob need to be suppressed */ - if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) { - do_gettimeofday(&t); - msec = tv2int(&t, &prev_time); - prev_time = t; - if (msec < ictx->idev->rep[REP_DELAY]) { - spin_unlock_irqrestore(&ictx->kc_lock, flags); - return; - } - } - kc = ictx->kc; - - spin_unlock_irqrestore(&ictx->kc_lock, flags); - - input_report_key(ictx->idev, kc, press_type); - input_sync(ictx->idev); - - /* panel keys don't generate a release */ - input_report_key(ictx->idev, kc, 0); - input_sync(ictx->idev); - - ictx->last_keycode = kc; - - return; - -unknown_key: - spin_unlock_irqrestore(&ictx->kc_lock, flags); - dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, - (long long)scancode); - return; - -not_input_data: - if (len != 8) { - dev_warn(dev, "imon %s: invalid incoming packet " - "size (len = %d, intf%d)\n", __func__, len, intf); - return; - } - - /* iMON 2.4G associate frame */ - if (buf[0] == 0x00 && - buf[2] == 0xFF && /* REFID */ - buf[3] == 0xFF && - buf[4] == 0xFF && - buf[5] == 0xFF && /* iMON 2.4G */ - ((buf[6] == 0x4E && buf[7] == 0xDF) || /* LT */ - (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */ - dev_warn(dev, "%s: remote associated refid=%02X\n", - __func__, buf[1]); - ictx->rf_isassociating = false; - } -} - -/** - * Callback function for USB core API: receive data - */ -static void usb_rx_callback_intf0(struct urb *urb) -{ - struct imon_context *ictx; - int intfnum = 0; - - if (!urb) - return; - - ictx = (struct imon_context *)urb->context; - if (!ictx) - return; - - switch (urb->status) { - case -ENOENT: /* usbcore unlink successful! */ - return; - - case -ESHUTDOWN: /* transport endpoint was shut down */ - break; - - case 0: - imon_incoming_packet(ictx, urb, intfnum); - break; - - default: - dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", - __func__, urb->status); - break; - } - - usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); -} - -static void usb_rx_callback_intf1(struct urb *urb) -{ - struct imon_context *ictx; - int intfnum = 1; - - if (!urb) - return; - - ictx = (struct imon_context *)urb->context; - if (!ictx) - return; - - switch (urb->status) { - case -ENOENT: /* usbcore unlink successful! */ - return; - - case -ESHUTDOWN: /* transport endpoint was shut down */ - break; - - case 0: - imon_incoming_packet(ictx, urb, intfnum); - break; - - default: - dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", - __func__, urb->status); - break; - } - - usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); -} - -/* - * The 0x15c2:0xffdc device ID was used for umpteen different imon - * devices, and all of them constantly spew interrupts, even when there - * is no actual data to report. However, byte 6 of this buffer looks like - * its unique across device variants, so we're trying to key off that to - * figure out which display type (if any) and what IR protocol the device - * actually supports. These devices have their IR protocol hard-coded into - * their firmware, they can't be changed on the fly like the newer hardware. - */ -static void imon_get_ffdc_type(struct imon_context *ictx) -{ - u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; - u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; - u64 allowed_protos = RC_TYPE_OTHER; - - switch (ffdc_cfg_byte) { - /* iMON Knob, no display, iMON IR + vol knob */ - case 0x21: - dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR"); - ictx->display_supported = false; - break; - /* iMON 2.4G LT (usb stick), no display, iMON RF */ - case 0x4e: - dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF"); - ictx->display_supported = false; - ictx->rf_device = true; - break; - /* iMON VFD, no IR (does have vol knob tho) */ - case 0x35: - dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR"); - detected_display_type = IMON_DISPLAY_TYPE_VFD; - break; - /* iMON VFD, iMON IR */ - case 0x24: - case 0x85: - dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR"); - detected_display_type = IMON_DISPLAY_TYPE_VFD; - break; - /* iMON VFD, MCE IR */ - case 0x9e: - dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); - detected_display_type = IMON_DISPLAY_TYPE_VFD; - allowed_protos = RC_TYPE_RC6; - break; - /* iMON LCD, MCE IR */ - case 0x9f: - dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); - detected_display_type = IMON_DISPLAY_TYPE_LCD; - allowed_protos = RC_TYPE_RC6; - break; - default: - dev_info(ictx->dev, "Unknown 0xffdc device, " - "defaulting to VFD and iMON IR"); - detected_display_type = IMON_DISPLAY_TYPE_VFD; - break; - } - - printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte); - - ictx->display_type = detected_display_type; - ictx->rc_type = allowed_protos; -} - -static void imon_set_display_type(struct imon_context *ictx) -{ - u8 configured_display_type = IMON_DISPLAY_TYPE_VFD; - - /* - * Try to auto-detect the type of display if the user hasn't set - * it by hand via the display_type modparam. Default is VFD. - */ - - if (display_type == IMON_DISPLAY_TYPE_AUTO) { - switch (ictx->product) { - case 0xffdc: - /* set in imon_get_ffdc_type() */ - configured_display_type = ictx->display_type; - break; - case 0x0034: - case 0x0035: - configured_display_type = IMON_DISPLAY_TYPE_VGA; - break; - case 0x0038: - case 0x0039: - case 0x0045: - configured_display_type = IMON_DISPLAY_TYPE_LCD; - break; - case 0x003c: - case 0x0041: - case 0x0042: - case 0x0043: - configured_display_type = IMON_DISPLAY_TYPE_NONE; - ictx->display_supported = false; - break; - case 0x0036: - case 0x0044: - default: - configured_display_type = IMON_DISPLAY_TYPE_VFD; - break; - } - } else { - configured_display_type = display_type; - if (display_type == IMON_DISPLAY_TYPE_NONE) - ictx->display_supported = false; - else - ictx->display_supported = true; - dev_info(ictx->dev, "%s: overriding display type to %d via " - "modparam\n", __func__, display_type); - } - - ictx->display_type = configured_display_type; -} - -static struct rc_dev *imon_init_rdev(struct imon_context *ictx) -{ - struct rc_dev *rdev; - int ret; - const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x88 }; - - rdev = rc_allocate_device(); - if (!rdev) { - dev_err(ictx->dev, "remote control dev allocation failed\n"); - goto out; - } - - snprintf(ictx->name_rdev, sizeof(ictx->name_rdev), - "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product); - usb_make_path(ictx->usbdev_intf0, ictx->phys_rdev, - sizeof(ictx->phys_rdev)); - strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev)); - - rdev->input_name = ictx->name_rdev; - rdev->input_phys = ictx->phys_rdev; - usb_to_input_id(ictx->usbdev_intf0, &rdev->input_id); - rdev->dev.parent = ictx->dev; - - rdev->priv = ictx; - rdev->driver_type = RC_DRIVER_SCANCODE; - rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */ - rdev->change_protocol = imon_ir_change_protocol; - rdev->driver_name = MOD_NAME; - - /* Enable front-panel buttons and/or knobs */ - memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet)); - ret = send_packet(ictx); - /* Not fatal, but warn about it */ - if (ret) - dev_info(ictx->dev, "panel buttons/knobs setup failed\n"); - - if (ictx->product == 0xffdc) { - imon_get_ffdc_type(ictx); - rdev->allowed_protos = ictx->rc_type; - } - - imon_set_display_type(ictx); - - if (ictx->rc_type == RC_TYPE_RC6) - rdev->map_name = RC_MAP_IMON_MCE; - else - rdev->map_name = RC_MAP_IMON_PAD; - - ret = rc_register_device(rdev); - if (ret < 0) { - dev_err(ictx->dev, "remote input dev register failed\n"); - goto out; - } - - return rdev; - -out: - rc_free_device(rdev); - return NULL; -} - -static struct input_dev *imon_init_idev(struct imon_context *ictx) -{ - struct input_dev *idev; - int ret, i; - - idev = input_allocate_device(); - if (!idev) { - dev_err(ictx->dev, "input dev allocation failed\n"); - goto out; - } - - snprintf(ictx->name_idev, sizeof(ictx->name_idev), - "iMON Panel, Knob and Mouse(%04x:%04x)", - ictx->vendor, ictx->product); - idev->name = ictx->name_idev; - - usb_make_path(ictx->usbdev_intf0, ictx->phys_idev, - sizeof(ictx->phys_idev)); - strlcat(ictx->phys_idev, "/input1", sizeof(ictx->phys_idev)); - idev->phys = ictx->phys_idev; - - idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL); - - idev->keybit[BIT_WORD(BTN_MOUSE)] = - BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); - idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | - BIT_MASK(REL_WHEEL); - - /* panel and/or knob code support */ - for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { - u32 kc = imon_panel_key_table[i].keycode; - __set_bit(kc, idev->keybit); - } - - usb_to_input_id(ictx->usbdev_intf0, &idev->id); - idev->dev.parent = ictx->dev; - input_set_drvdata(idev, ictx); - - ret = input_register_device(idev); - if (ret < 0) { - dev_err(ictx->dev, "input dev register failed\n"); - goto out; - } - - return idev; - -out: - input_free_device(idev); - return NULL; -} - -static struct input_dev *imon_init_touch(struct imon_context *ictx) -{ - struct input_dev *touch; - int ret; - - touch = input_allocate_device(); - if (!touch) { - dev_err(ictx->dev, "touchscreen input dev allocation failed\n"); - goto touch_alloc_failed; - } - - snprintf(ictx->name_touch, sizeof(ictx->name_touch), - "iMON USB Touchscreen (%04x:%04x)", - ictx->vendor, ictx->product); - touch->name = ictx->name_touch; - - usb_make_path(ictx->usbdev_intf1, ictx->phys_touch, - sizeof(ictx->phys_touch)); - strlcat(ictx->phys_touch, "/input2", sizeof(ictx->phys_touch)); - touch->phys = ictx->phys_touch; - - touch->evbit[0] = - BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - touch->keybit[BIT_WORD(BTN_TOUCH)] = - BIT_MASK(BTN_TOUCH); - input_set_abs_params(touch, ABS_X, - 0x00, 0xfff, 0, 0); - input_set_abs_params(touch, ABS_Y, - 0x00, 0xfff, 0, 0); - - input_set_drvdata(touch, ictx); - - usb_to_input_id(ictx->usbdev_intf1, &touch->id); - touch->dev.parent = ictx->dev; - ret = input_register_device(touch); - if (ret < 0) { - dev_info(ictx->dev, "touchscreen input dev register failed\n"); - goto touch_register_failed; - } - - return touch; - -touch_register_failed: - input_free_device(ictx->touch); - -touch_alloc_failed: - return NULL; -} - -static bool imon_find_endpoints(struct imon_context *ictx, - struct usb_host_interface *iface_desc) -{ - struct usb_endpoint_descriptor *ep; - struct usb_endpoint_descriptor *rx_endpoint = NULL; - struct usb_endpoint_descriptor *tx_endpoint = NULL; - int ifnum = iface_desc->desc.bInterfaceNumber; - int num_endpts = iface_desc->desc.bNumEndpoints; - int i, ep_dir, ep_type; - bool ir_ep_found = false; - bool display_ep_found = false; - bool tx_control = false; - - /* - * Scan the endpoint list and set: - * first input endpoint = IR endpoint - * first output endpoint = display endpoint - */ - for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { - ep = &iface_desc->endpoint[i].desc; - ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; - ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - - if (!ir_ep_found && ep_dir == USB_DIR_IN && - ep_type == USB_ENDPOINT_XFER_INT) { - - rx_endpoint = ep; - ir_ep_found = true; - dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__); - - } else if (!display_ep_found && ep_dir == USB_DIR_OUT && - ep_type == USB_ENDPOINT_XFER_INT) { - tx_endpoint = ep; - display_ep_found = true; - dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__); - } - } - - if (ifnum == 0) { - ictx->rx_endpoint_intf0 = rx_endpoint; - /* - * tx is used to send characters to lcd/vfd, associate RF - * remotes, set IR protocol, and maybe more... - */ - ictx->tx_endpoint = tx_endpoint; - } else { - ictx->rx_endpoint_intf1 = rx_endpoint; - } - - /* - * If we didn't find a display endpoint, this is probably one of the - * newer iMON devices that use control urb instead of interrupt - */ - if (!display_ep_found) { - tx_control = true; - display_ep_found = true; - dev_dbg(ictx->dev, "%s: device uses control endpoint, not " - "interface OUT endpoint\n", __func__); - } - - /* - * Some iMON receivers have no display. Unfortunately, it seems - * that SoundGraph recycles device IDs between devices both with - * and without... :\ - */ - if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) { - display_ep_found = false; - dev_dbg(ictx->dev, "%s: device has no display\n", __func__); - } - - /* - * iMON Touch devices have a VGA touchscreen, but no "display", as - * that refers to e.g. /dev/lcd0 (a character device LCD or VFD). - */ - if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { - display_ep_found = false; - dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__); - } - - /* Input endpoint is mandatory */ - if (!ir_ep_found) - pr_err("no valid input (IR) endpoint found\n"); - - ictx->tx_control = tx_control; - - if (display_ep_found) - ictx->display_supported = true; - - return ir_ep_found; - -} - -static struct imon_context *imon_init_intf0(struct usb_interface *intf) -{ - struct imon_context *ictx; - struct urb *rx_urb; - struct urb *tx_urb; - struct device *dev = &intf->dev; - struct usb_host_interface *iface_desc; - int ret = -ENOMEM; - - ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL); - if (!ictx) { - dev_err(dev, "%s: kzalloc failed for context", __func__); - goto exit; - } - rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rx_urb) { - dev_err(dev, "%s: usb_alloc_urb failed for IR urb", __func__); - goto rx_urb_alloc_failed; - } - tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!tx_urb) { - dev_err(dev, "%s: usb_alloc_urb failed for display urb", - __func__); - goto tx_urb_alloc_failed; - } - - mutex_init(&ictx->lock); - spin_lock_init(&ictx->kc_lock); - - mutex_lock(&ictx->lock); - - ictx->dev = dev; - ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf0 = true; - ictx->rx_urb_intf0 = rx_urb; - ictx->tx_urb = tx_urb; - ictx->rf_device = false; - - ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); - ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); - - ret = -ENODEV; - iface_desc = intf->cur_altsetting; - if (!imon_find_endpoints(ictx, iface_desc)) { - goto find_endpoint_failed; - } - - usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, - usb_rcvintpipe(ictx->usbdev_intf0, - ictx->rx_endpoint_intf0->bEndpointAddress), - ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), - usb_rx_callback_intf0, ictx, - ictx->rx_endpoint_intf0->bInterval); - - ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL); - if (ret) { - pr_err("usb_submit_urb failed for intf0 (%d)\n", ret); - goto urb_submit_failed; - } - - ictx->idev = imon_init_idev(ictx); - if (!ictx->idev) { - dev_err(dev, "%s: input device setup failed\n", __func__); - goto idev_setup_failed; - } - - ictx->rdev = imon_init_rdev(ictx); - if (!ictx->rdev) { - dev_err(dev, "%s: rc device setup failed\n", __func__); - goto rdev_setup_failed; - } - - return ictx; - -rdev_setup_failed: - input_unregister_device(ictx->idev); -idev_setup_failed: - usb_kill_urb(ictx->rx_urb_intf0); -urb_submit_failed: -find_endpoint_failed: - mutex_unlock(&ictx->lock); - usb_free_urb(tx_urb); -tx_urb_alloc_failed: - usb_free_urb(rx_urb); -rx_urb_alloc_failed: - kfree(ictx); -exit: - dev_err(dev, "unable to initialize intf0, err %d\n", ret); - - return NULL; -} - -static struct imon_context *imon_init_intf1(struct usb_interface *intf, - struct imon_context *ictx) -{ - struct urb *rx_urb; - struct usb_host_interface *iface_desc; - int ret = -ENOMEM; - - rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rx_urb) { - pr_err("usb_alloc_urb failed for IR urb\n"); - goto rx_urb_alloc_failed; - } - - mutex_lock(&ictx->lock); - - if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { - init_timer(&ictx->ttimer); - ictx->ttimer.data = (unsigned long)ictx; - ictx->ttimer.function = imon_touch_display_timeout; - } - - ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf1 = true; - ictx->rx_urb_intf1 = rx_urb; - - ret = -ENODEV; - iface_desc = intf->cur_altsetting; - if (!imon_find_endpoints(ictx, iface_desc)) - goto find_endpoint_failed; - - if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { - ictx->touch = imon_init_touch(ictx); - if (!ictx->touch) - goto touch_setup_failed; - } else - ictx->touch = NULL; - - usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, - usb_rcvintpipe(ictx->usbdev_intf1, - ictx->rx_endpoint_intf1->bEndpointAddress), - ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), - usb_rx_callback_intf1, ictx, - ictx->rx_endpoint_intf1->bInterval); - - ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL); - - if (ret) { - pr_err("usb_submit_urb failed for intf1 (%d)\n", ret); - goto urb_submit_failed; - } - - return ictx; - -urb_submit_failed: - if (ictx->touch) - input_unregister_device(ictx->touch); -touch_setup_failed: -find_endpoint_failed: - mutex_unlock(&ictx->lock); - usb_free_urb(rx_urb); -rx_urb_alloc_failed: - dev_err(ictx->dev, "unable to initialize intf0, err %d\n", ret); - - return NULL; -} - -static void imon_init_display(struct imon_context *ictx, - struct usb_interface *intf) -{ - int ret; - - dev_dbg(ictx->dev, "Registering iMON display with sysfs\n"); - - /* set up sysfs entry for built-in clock */ - ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group); - if (ret) - dev_err(ictx->dev, "Could not create display sysfs " - "entries(%d)", ret); - - if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) - ret = usb_register_dev(intf, &imon_lcd_class); - else - ret = usb_register_dev(intf, &imon_vfd_class); - if (ret) - /* Not a fatal error, so ignore */ - dev_info(ictx->dev, "could not get a minor number for " - "display\n"); - -} - -/** - * Callback function for USB core API: Probe - */ -static int __devinit imon_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *usbdev = NULL; - struct usb_host_interface *iface_desc = NULL; - struct usb_interface *first_if; - struct device *dev = &interface->dev; - int ifnum, code_length, sysfs_err; - int ret = 0; - struct imon_context *ictx = NULL; - struct imon_context *first_if_ctx = NULL; - u16 vendor, product; - - code_length = BUF_CHUNK_SIZE * 8; - - usbdev = usb_get_dev(interface_to_usbdev(interface)); - iface_desc = interface->cur_altsetting; - ifnum = iface_desc->desc.bInterfaceNumber; - vendor = le16_to_cpu(usbdev->descriptor.idVendor); - product = le16_to_cpu(usbdev->descriptor.idProduct); - - dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", - __func__, vendor, product, ifnum); - - /* prevent races probing devices w/multiple interfaces */ - mutex_lock(&driver_lock); - - first_if = usb_ifnum_to_if(usbdev, 0); - first_if_ctx = usb_get_intfdata(first_if); - - if (ifnum == 0) { - ictx = imon_init_intf0(interface); - if (!ictx) { - pr_err("failed to initialize context!\n"); - ret = -ENODEV; - goto fail; - } - - } else { - /* this is the secondary interface on the device */ - ictx = imon_init_intf1(interface, first_if_ctx); - if (!ictx) { - pr_err("failed to attach to context!\n"); - ret = -ENODEV; - goto fail; - } - - } - - usb_set_intfdata(interface, ictx); - - if (ifnum == 0) { - if (product == 0xffdc && ictx->rf_device) { - sysfs_err = sysfs_create_group(&interface->dev.kobj, - &imon_rf_attr_group); - if (sysfs_err) - pr_err("Could not create RF sysfs entries(%d)\n", - sysfs_err); - } - - if (ictx->display_supported) - imon_init_display(ictx, interface); - } - - dev_info(dev, "iMON device (%04x:%04x, intf%d) on " - "usb<%d:%d> initialized\n", vendor, product, ifnum, - usbdev->bus->busnum, usbdev->devnum); - - mutex_unlock(&ictx->lock); - mutex_unlock(&driver_lock); - - return 0; - -fail: - mutex_unlock(&driver_lock); - dev_err(dev, "unable to register, err %d\n", ret); - - return ret; -} - -/** - * Callback function for USB core API: disconnect - */ -static void __devexit imon_disconnect(struct usb_interface *interface) -{ - struct imon_context *ictx; - struct device *dev; - int ifnum; - - /* prevent races with multi-interface device probing and display_open */ - mutex_lock(&driver_lock); - - ictx = usb_get_intfdata(interface); - dev = ictx->dev; - ifnum = interface->cur_altsetting->desc.bInterfaceNumber; - - mutex_lock(&ictx->lock); - - /* - * sysfs_remove_group is safe to call even if sysfs_create_group - * hasn't been called - */ - sysfs_remove_group(&interface->dev.kobj, &imon_display_attr_group); - sysfs_remove_group(&interface->dev.kobj, &imon_rf_attr_group); - - usb_set_intfdata(interface, NULL); - - /* Abort ongoing write */ - if (ictx->tx.busy) { - usb_kill_urb(ictx->tx_urb); - complete_all(&ictx->tx.finished); - } - - if (ifnum == 0) { - ictx->dev_present_intf0 = false; - usb_kill_urb(ictx->rx_urb_intf0); - input_unregister_device(ictx->idev); - rc_unregister_device(ictx->rdev); - if (ictx->display_supported) { - if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) - usb_deregister_dev(interface, &imon_lcd_class); - else - usb_deregister_dev(interface, &imon_vfd_class); - } - } else { - ictx->dev_present_intf1 = false; - usb_kill_urb(ictx->rx_urb_intf1); - if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) - input_unregister_device(ictx->touch); - } - - if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) { - if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) - del_timer_sync(&ictx->ttimer); - mutex_unlock(&ictx->lock); - if (!ictx->display_isopen) - free_imon_context(ictx); - } else - mutex_unlock(&ictx->lock); - - mutex_unlock(&driver_lock); - - dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n", - __func__, ifnum); -} - -static int imon_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct imon_context *ictx = usb_get_intfdata(intf); - int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - - if (ifnum == 0) - usb_kill_urb(ictx->rx_urb_intf0); - else - usb_kill_urb(ictx->rx_urb_intf1); - - return 0; -} - -static int imon_resume(struct usb_interface *intf) -{ - int rc = 0; - struct imon_context *ictx = usb_get_intfdata(intf); - int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - - if (ifnum == 0) { - usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, - usb_rcvintpipe(ictx->usbdev_intf0, - ictx->rx_endpoint_intf0->bEndpointAddress), - ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), - usb_rx_callback_intf0, ictx, - ictx->rx_endpoint_intf0->bInterval); - - rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); - - } else { - usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, - usb_rcvintpipe(ictx->usbdev_intf1, - ictx->rx_endpoint_intf1->bEndpointAddress), - ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), - usb_rx_callback_intf1, ictx, - ictx->rx_endpoint_intf1->bInterval); - - rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); - } - - return rc; -} - -static int __init imon_init(void) -{ - int rc; - - rc = usb_register(&imon_driver); - if (rc) { - pr_err("usb register failed(%d)\n", rc); - rc = -ENODEV; - } - - return rc; -} - -static void __exit imon_exit(void) -{ - usb_deregister(&imon_driver); -} - -module_init(imon_init); -module_exit(imon_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-jvc-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-jvc-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-jvc-decoder.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-jvc-decoder.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,198 +0,0 @@ -/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol - * - * Copyright (C) 2010 by David Härdeman - * - * 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 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. - */ - -#include -#include "rc-core-priv.h" - -#define JVC_NBITS 16 /* dev(8) + func(8) */ -#define JVC_UNIT 525000 /* ns */ -#define JVC_HEADER_PULSE (16 * JVC_UNIT) /* lack of header -> repeat */ -#define JVC_HEADER_SPACE (8 * JVC_UNIT) -#define JVC_BIT_PULSE (1 * JVC_UNIT) -#define JVC_BIT_0_SPACE (1 * JVC_UNIT) -#define JVC_BIT_1_SPACE (3 * JVC_UNIT) -#define JVC_TRAILER_PULSE (1 * JVC_UNIT) -#define JVC_TRAILER_SPACE (35 * JVC_UNIT) - -enum jvc_state { - STATE_INACTIVE, - STATE_HEADER_SPACE, - STATE_BIT_PULSE, - STATE_BIT_SPACE, - STATE_TRAILER_PULSE, - STATE_TRAILER_SPACE, - STATE_CHECK_REPEAT, -}; - -/** - * ir_jvc_decode() - Decode one JVC pulse or space - * @dev: the struct rc_dev descriptor of the device - * @duration: the struct ir_raw_event descriptor of the pulse/space - * - * This function returns -EINVAL if the pulse violates the state machine - */ -static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) -{ - struct jvc_dec *data = &dev->raw->jvc; - - if (!(dev->raw->enabled_protocols & RC_TYPE_JVC)) - return 0; - - if (!is_timing_event(ev)) { - if (ev.reset) - data->state = STATE_INACTIVE; - return 0; - } - - if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2)) - goto out; - - IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - -again: - switch (data->state) { - - case STATE_INACTIVE: - if (!ev.pulse) - break; - - if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) - break; - - data->count = 0; - data->first = true; - data->toggle = !data->toggle; - data->state = STATE_HEADER_SPACE; - return 0; - - case STATE_HEADER_SPACE: - if (ev.pulse) - break; - - if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2)) - break; - - data->state = STATE_BIT_PULSE; - return 0; - - case STATE_BIT_PULSE: - if (!ev.pulse) - break; - - if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2)) - break; - - data->state = STATE_BIT_SPACE; - return 0; - - case STATE_BIT_SPACE: - if (ev.pulse) - break; - - data->bits <<= 1; - if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) { - data->bits |= 1; - decrease_duration(&ev, JVC_BIT_1_SPACE); - } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2)) - decrease_duration(&ev, JVC_BIT_0_SPACE); - else - break; - data->count++; - - if (data->count == JVC_NBITS) - data->state = STATE_TRAILER_PULSE; - else - data->state = STATE_BIT_PULSE; - return 0; - - case STATE_TRAILER_PULSE: - if (!ev.pulse) - break; - - if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2)) - break; - - data->state = STATE_TRAILER_SPACE; - return 0; - - case STATE_TRAILER_SPACE: - if (ev.pulse) - break; - - if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2)) - break; - - if (data->first) { - u32 scancode; - scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | - (bitrev8((data->bits >> 0) & 0xff) << 0); - IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); - rc_keydown(dev, scancode, data->toggle); - data->first = false; - data->old_bits = data->bits; - } else if (data->bits == data->old_bits) { - IR_dprintk(1, "JVC repeat\n"); - rc_repeat(dev); - } else { - IR_dprintk(1, "JVC invalid repeat msg\n"); - break; - } - - data->count = 0; - data->state = STATE_CHECK_REPEAT; - return 0; - - case STATE_CHECK_REPEAT: - if (!ev.pulse) - break; - - if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) - data->state = STATE_INACTIVE; - else - data->state = STATE_BIT_PULSE; - goto again; - } - -out: - IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - data->state = STATE_INACTIVE; - return -EINVAL; -} - -static struct ir_raw_handler jvc_handler = { - .protocols = RC_TYPE_JVC, - .decode = ir_jvc_decode, -}; - -static int __init ir_jvc_decode_init(void) -{ - ir_raw_handler_register(&jvc_handler); - - printk(KERN_INFO "IR JVC protocol handler initialized\n"); - return 0; -} - -static void __exit ir_jvc_decode_exit(void) -{ - ir_raw_handler_unregister(&jvc_handler); -} - -module_init(ir_jvc_decode_init); -module_exit(ir_jvc_decode_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Härdeman "); -MODULE_DESCRIPTION("JVC IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-lirc-codec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-lirc-codec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-lirc-codec.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-lirc-codec.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,406 +0,0 @@ -/* ir-lirc-codec.c - rc-core to classic lirc interface bridge - * - * Copyright (C) 2010 by Jarod Wilson - * - * 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 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. - */ - -#include -#include -#include -#include -#include -#include "rc-core-priv.h" - -#define LIRCBUF_SIZE 256 - -/** - * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the - * lircd userspace daemon for decoding. - * @input_dev: the struct rc_dev descriptor of the device - * @duration: the struct ir_raw_event descriptor of the pulse/space - * - * This function returns -EINVAL if the lirc interfaces aren't wired up. - */ -static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) -{ - struct lirc_codec *lirc = &dev->raw->lirc; - int sample; - - if (!(dev->raw->enabled_protocols & RC_TYPE_LIRC)) - return 0; - - if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) - return -EINVAL; - - /* Packet start */ - if (ev.reset) - return 0; - - /* Carrier reports */ - if (ev.carrier_report) { - sample = LIRC_FREQUENCY(ev.carrier); - IR_dprintk(2, "carrier report (freq: %d)\n", sample); - - /* Packet end */ - } else if (ev.timeout) { - - if (lirc->gap) - return 0; - - lirc->gap_start = ktime_get(); - lirc->gap = true; - lirc->gap_duration = ev.duration; - - if (!lirc->send_timeout_reports) - return 0; - - sample = LIRC_TIMEOUT(ev.duration / 1000); - IR_dprintk(2, "timeout report (duration: %d)\n", sample); - - /* Normal sample */ - } else { - - if (lirc->gap) { - int gap_sample; - - lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), - lirc->gap_start)); - - /* Convert to ms and cap by LIRC_VALUE_MASK */ - do_div(lirc->gap_duration, 1000); - lirc->gap_duration = min(lirc->gap_duration, - (u64)LIRC_VALUE_MASK); - - gap_sample = LIRC_SPACE(lirc->gap_duration); - lirc_buffer_write(dev->raw->lirc.drv->rbuf, - (unsigned char *) &gap_sample); - lirc->gap = false; - } - - sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : - LIRC_SPACE(ev.duration / 1000); - IR_dprintk(2, "delivering %uus %s to lirc_dev\n", - TO_US(ev.duration), TO_STR(ev.pulse)); - } - - lirc_buffer_write(dev->raw->lirc.drv->rbuf, - (unsigned char *) &sample); - wake_up(&dev->raw->lirc.drv->rbuf->wait_poll); - - return 0; -} - -static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, - size_t n, loff_t *ppos) -{ - struct lirc_codec *lirc; - struct rc_dev *dev; - int *txbuf; /* buffer with values to transmit */ - int ret = 0; - size_t count; - - lirc = lirc_get_pdata(file); - if (!lirc) - return -EFAULT; - - if (n % sizeof(int)) - return -EINVAL; - - count = n / sizeof(int); - if (count > LIRCBUF_SIZE || count % 2 == 0 || n % sizeof(int) != 0) - return -EINVAL; - - txbuf = memdup_user(buf, n); - if (IS_ERR(txbuf)) - return PTR_ERR(txbuf); - - dev = lirc->dev; - if (!dev) { - ret = -EFAULT; - goto out; - } - - if (dev->tx_ir) - ret = dev->tx_ir(dev, txbuf, (u32)n); - -out: - kfree(txbuf); - return ret; -} - -static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, - unsigned long __user arg) -{ - struct lirc_codec *lirc; - struct rc_dev *dev; - int ret = 0; - __u32 val = 0, tmp; - - lirc = lirc_get_pdata(filep); - if (!lirc) - return -EFAULT; - - dev = lirc->dev; - if (!dev) - return -EFAULT; - - if (_IOC_DIR(cmd) & _IOC_WRITE) { - ret = get_user(val, (__u32 *)arg); - if (ret) - return ret; - } - - switch (cmd) { - - /* legacy support */ - case LIRC_GET_SEND_MODE: - val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; - break; - - case LIRC_SET_SEND_MODE: - if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) - return -EINVAL; - return 0; - - /* TX settings */ - case LIRC_SET_TRANSMITTER_MASK: - if (!dev->s_tx_mask) - return -EINVAL; - - return dev->s_tx_mask(dev, val); - - case LIRC_SET_SEND_CARRIER: - if (!dev->s_tx_carrier) - return -EINVAL; - - return dev->s_tx_carrier(dev, val); - - case LIRC_SET_SEND_DUTY_CYCLE: - if (!dev->s_tx_duty_cycle) - return -ENOSYS; - - if (val <= 0 || val >= 100) - return -EINVAL; - - return dev->s_tx_duty_cycle(dev, val); - - /* RX settings */ - case LIRC_SET_REC_CARRIER: - if (!dev->s_rx_carrier_range) - return -ENOSYS; - - if (val <= 0) - return -EINVAL; - - return dev->s_rx_carrier_range(dev, - dev->raw->lirc.carrier_low, - val); - - case LIRC_SET_REC_CARRIER_RANGE: - if (val <= 0) - return -EINVAL; - - dev->raw->lirc.carrier_low = val; - return 0; - - case LIRC_GET_REC_RESOLUTION: - val = dev->rx_resolution; - break; - - case LIRC_SET_WIDEBAND_RECEIVER: - if (!dev->s_learning_mode) - return -ENOSYS; - - return dev->s_learning_mode(dev, !!val); - - case LIRC_SET_MEASURE_CARRIER_MODE: - if (!dev->s_carrier_report) - return -ENOSYS; - - return dev->s_carrier_report(dev, !!val); - - /* Generic timeout support */ - case LIRC_GET_MIN_TIMEOUT: - if (!dev->max_timeout) - return -ENOSYS; - val = dev->min_timeout / 1000; - break; - - case LIRC_GET_MAX_TIMEOUT: - if (!dev->max_timeout) - return -ENOSYS; - val = dev->max_timeout / 1000; - break; - - case LIRC_SET_REC_TIMEOUT: - if (!dev->max_timeout) - return -ENOSYS; - - tmp = val * 1000; - - if (tmp < dev->min_timeout || - tmp > dev->max_timeout) - return -EINVAL; - - dev->timeout = tmp; - break; - - case LIRC_SET_REC_TIMEOUT_REPORTS: - lirc->send_timeout_reports = !!val; - break; - - default: - return lirc_dev_fop_ioctl(filep, cmd, arg); - } - - if (_IOC_DIR(cmd) & _IOC_READ) - ret = put_user(val, (__u32 *)arg); - - return ret; -} - -static int ir_lirc_open(void *data) -{ - return 0; -} - -static void ir_lirc_close(void *data) -{ - return; -} - -static struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .write = ir_lirc_transmit_ir, - .unlocked_ioctl = ir_lirc_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ir_lirc_ioctl, -#endif - .read = lirc_dev_fop_read, - .poll = lirc_dev_fop_poll, - .open = lirc_dev_fop_open, - .release = lirc_dev_fop_close, - .llseek = no_llseek, -}; - -static int ir_lirc_register(struct rc_dev *dev) -{ - struct lirc_driver *drv; - struct lirc_buffer *rbuf; - int rc = -ENOMEM; - unsigned long features; - - drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); - if (!drv) - return rc; - - rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); - if (!rbuf) - goto rbuf_alloc_failed; - - rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); - if (rc) - goto rbuf_init_failed; - - features = LIRC_CAN_REC_MODE2; - if (dev->tx_ir) { - features |= LIRC_CAN_SEND_PULSE; - if (dev->s_tx_mask) - features |= LIRC_CAN_SET_TRANSMITTER_MASK; - if (dev->s_tx_carrier) - features |= LIRC_CAN_SET_SEND_CARRIER; - if (dev->s_tx_duty_cycle) - features |= LIRC_CAN_SET_SEND_DUTY_CYCLE; - } - - if (dev->s_rx_carrier_range) - features |= LIRC_CAN_SET_REC_CARRIER | - LIRC_CAN_SET_REC_CARRIER_RANGE; - - if (dev->s_learning_mode) - features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; - - if (dev->s_carrier_report) - features |= LIRC_CAN_MEASURE_CARRIER; - - if (dev->max_timeout) - features |= LIRC_CAN_SET_REC_TIMEOUT; - - snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", - dev->driver_name); - drv->minor = -1; - drv->features = features; - drv->data = &dev->raw->lirc; - drv->rbuf = rbuf; - drv->set_use_inc = &ir_lirc_open; - drv->set_use_dec = &ir_lirc_close; - drv->code_length = sizeof(struct ir_raw_event) * 8; - drv->fops = &lirc_fops; - drv->dev = &dev->dev; - drv->owner = THIS_MODULE; - - drv->minor = lirc_register_driver(drv); - if (drv->minor < 0) { - rc = -ENODEV; - goto lirc_register_failed; - } - - dev->raw->lirc.drv = drv; - dev->raw->lirc.dev = dev; - return 0; - -lirc_register_failed: -rbuf_init_failed: - kfree(rbuf); -rbuf_alloc_failed: - kfree(drv); - - return rc; -} - -static int ir_lirc_unregister(struct rc_dev *dev) -{ - struct lirc_codec *lirc = &dev->raw->lirc; - - lirc_unregister_driver(lirc->drv->minor); - lirc_buffer_free(lirc->drv->rbuf); - kfree(lirc->drv); - - return 0; -} - -static struct ir_raw_handler lirc_handler = { - .protocols = RC_TYPE_LIRC, - .decode = ir_lirc_decode, - .raw_register = ir_lirc_register, - .raw_unregister = ir_lirc_unregister, -}; - -static int __init ir_lirc_codec_init(void) -{ - ir_raw_handler_register(&lirc_handler); - - printk(KERN_INFO "IR LIRC bridge handler initialized\n"); - return 0; -} - -static void __exit ir_lirc_codec_exit(void) -{ - ir_raw_handler_unregister(&lirc_handler); -} - -module_init(ir_lirc_codec_init); -module_exit(ir_lirc_codec_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson "); -MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -MODULE_DESCRIPTION("LIRC IR handler bridge"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-nec-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-nec-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-nec-decoder.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-nec-decoder.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,226 +0,0 @@ -/* ir-nec-decoder.c - handle NEC IR Pulse/Space protocol - * - * Copyright (C) 2010 by Mauro Carvalho Chehab - * - * 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 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. - */ - -#include -#include "rc-core-priv.h" - -#define NEC_NBITS 32 -#define NEC_UNIT 562500 /* ns */ -#define NEC_HEADER_PULSE (16 * NEC_UNIT) -#define NECX_HEADER_PULSE (8 * NEC_UNIT) /* Less common NEC variant */ -#define NEC_HEADER_SPACE (8 * NEC_UNIT) -#define NEC_REPEAT_SPACE (4 * NEC_UNIT) -#define NEC_BIT_PULSE (1 * NEC_UNIT) -#define NEC_BIT_0_SPACE (1 * NEC_UNIT) -#define NEC_BIT_1_SPACE (3 * NEC_UNIT) -#define NEC_TRAILER_PULSE (1 * NEC_UNIT) -#define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */ -#define NECX_REPEAT_BITS 1 - -enum nec_state { - STATE_INACTIVE, - STATE_HEADER_SPACE, - STATE_BIT_PULSE, - STATE_BIT_SPACE, - STATE_TRAILER_PULSE, - STATE_TRAILER_SPACE, -}; - -/** - * ir_nec_decode() - Decode one NEC pulse or space - * @dev: the struct rc_dev descriptor of the device - * @duration: the struct ir_raw_event descriptor of the pulse/space - * - * This function returns -EINVAL if the pulse violates the state machine - */ -static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) -{ - struct nec_dec *data = &dev->raw->nec; - u32 scancode; - u8 address, not_address, command, not_command; - bool send_32bits = false; - - if (!(dev->raw->enabled_protocols & RC_TYPE_NEC)) - return 0; - - if (!is_timing_event(ev)) { - if (ev.reset) - data->state = STATE_INACTIVE; - return 0; - } - - IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - - switch (data->state) { - - case STATE_INACTIVE: - if (!ev.pulse) - break; - - if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) { - data->is_nec_x = false; - data->necx_repeat = false; - } else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2)) - data->is_nec_x = true; - else - break; - - data->count = 0; - data->state = STATE_HEADER_SPACE; - return 0; - - case STATE_HEADER_SPACE: - if (ev.pulse) - break; - - if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) { - data->state = STATE_BIT_PULSE; - return 0; - } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) { - if (!dev->keypressed) { - IR_dprintk(1, "Discarding last key repeat: event after key up\n"); - } else { - rc_repeat(dev); - IR_dprintk(1, "Repeat last key\n"); - data->state = STATE_TRAILER_PULSE; - } - return 0; - } - - break; - - case STATE_BIT_PULSE: - if (!ev.pulse) - break; - - if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2)) - break; - - data->state = STATE_BIT_SPACE; - return 0; - - case STATE_BIT_SPACE: - if (ev.pulse) - break; - - if (data->necx_repeat && data->count == NECX_REPEAT_BITS && - geq_margin(ev.duration, - NEC_TRAILER_SPACE, NEC_UNIT / 2)) { - IR_dprintk(1, "Repeat last key\n"); - rc_repeat(dev); - data->state = STATE_INACTIVE; - return 0; - - } else if (data->count > NECX_REPEAT_BITS) - data->necx_repeat = false; - - data->bits <<= 1; - if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2)) - data->bits |= 1; - else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2)) - break; - data->count++; - - if (data->count == NEC_NBITS) - data->state = STATE_TRAILER_PULSE; - else - data->state = STATE_BIT_PULSE; - - return 0; - - case STATE_TRAILER_PULSE: - if (!ev.pulse) - break; - - if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2)) - break; - - data->state = STATE_TRAILER_SPACE; - return 0; - - case STATE_TRAILER_SPACE: - if (ev.pulse) - break; - - if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) - break; - - address = bitrev8((data->bits >> 24) & 0xff); - not_address = bitrev8((data->bits >> 16) & 0xff); - command = bitrev8((data->bits >> 8) & 0xff); - not_command = bitrev8((data->bits >> 0) & 0xff); - - if ((command ^ not_command) != 0xff) { - IR_dprintk(1, "NEC checksum error: received 0x%08x\n", - data->bits); - send_32bits = true; - } - - if (send_32bits) { - /* NEC transport, but modified protocol, used by at - * least Apple and TiVo remotes */ - scancode = data->bits; - IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode); - } else if ((address ^ not_address) != 0xff) { - /* Extended NEC */ - scancode = address << 16 | - not_address << 8 | - command; - IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode); - } else { - /* Normal NEC */ - scancode = address << 8 | command; - IR_dprintk(1, "NEC scancode 0x%04x\n", scancode); - } - - if (data->is_nec_x) - data->necx_repeat = true; - - rc_keydown(dev, scancode, 0); - data->state = STATE_INACTIVE; - return 0; - } - - IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - data->state = STATE_INACTIVE; - return -EINVAL; -} - -static struct ir_raw_handler nec_handler = { - .protocols = RC_TYPE_NEC, - .decode = ir_nec_decode, -}; - -static int __init ir_nec_decode_init(void) -{ - ir_raw_handler_register(&nec_handler); - - printk(KERN_INFO "IR NEC protocol handler initialized\n"); - return 0; -} - -static void __exit ir_nec_decode_exit(void) -{ - ir_raw_handler_unregister(&nec_handler); -} - -module_init(ir_nec_decode_init); -module_exit(ir_nec_decode_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -MODULE_DESCRIPTION("NEC IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-raw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-raw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-raw.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-raw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,370 +0,0 @@ -/* ir-raw.c - handle IR pulse/space events - * - * Copyright (C) 2010 by Mauro Carvalho Chehab - * - * 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 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. - */ - -#include -#include -#include -#include -#include "rc-core-priv.h" - -/* Define the max number of pulse/space transitions to buffer */ -#define MAX_IR_EVENT_SIZE 512 - -/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ -static LIST_HEAD(ir_raw_client_list); - -/* Used to handle IR raw handler extensions */ -static DEFINE_MUTEX(ir_raw_handler_lock); -static LIST_HEAD(ir_raw_handler_list); -static u64 available_protocols; - -#ifdef MODULE -/* Used to load the decoders */ -static struct work_struct wq_load; -#endif - -static int ir_raw_event_thread(void *data) -{ - struct ir_raw_event ev; - struct ir_raw_handler *handler; - struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; - int retval; - - while (!kthread_should_stop()) { - - spin_lock_irq(&raw->lock); - retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev)); - - if (!retval) { - set_current_state(TASK_INTERRUPTIBLE); - - if (kthread_should_stop()) - set_current_state(TASK_RUNNING); - - spin_unlock_irq(&raw->lock); - schedule(); - continue; - } - - spin_unlock_irq(&raw->lock); - - - BUG_ON(retval != sizeof(ev)); - - mutex_lock(&ir_raw_handler_lock); - list_for_each_entry(handler, &ir_raw_handler_list, list) - handler->decode(raw->dev, ev); - raw->prev_ev = ev; - mutex_unlock(&ir_raw_handler_lock); - } - - return 0; -} - -/** - * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders - * @dev: the struct rc_dev device descriptor - * @ev: the struct ir_raw_event descriptor of the pulse/space - * - * This routine (which may be called from an interrupt context) stores a - * pulse/space duration for the raw ir decoding state machines. Pulses are - * signalled as positive values and spaces as negative values. A zero value - * will reset the decoding state machines. - */ -int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev) -{ - if (!dev->raw) - return -EINVAL; - - IR_dprintk(2, "sample: (%05dus %s)\n", - TO_US(ev->duration), TO_STR(ev->pulse)); - - if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) - return -ENOMEM; - - return 0; -} -EXPORT_SYMBOL_GPL(ir_raw_event_store); - -/** - * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space - * @dev: the struct rc_dev device descriptor - * @type: the type of the event that has occurred - * - * This routine (which may be called from an interrupt context) is used to - * store the beginning of an ir pulse or space (or the start/end of ir - * reception) for the raw ir decoding state machines. This is used by - * hardware which does not provide durations directly but only interrupts - * (or similar events) on state change. - */ -int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type) -{ - ktime_t now; - s64 delta; /* ns */ - DEFINE_IR_RAW_EVENT(ev); - int rc = 0; - - if (!dev->raw) - return -EINVAL; - - now = ktime_get(); - delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); - - /* Check for a long duration since last event or if we're - * being called for the first time, note that delta can't - * possibly be negative. - */ - if (delta > IR_MAX_DURATION || !dev->raw->last_type) - type |= IR_START_EVENT; - else - ev.duration = delta; - - if (type & IR_START_EVENT) - ir_raw_event_reset(dev); - else if (dev->raw->last_type & IR_SPACE) { - ev.pulse = false; - rc = ir_raw_event_store(dev, &ev); - } else if (dev->raw->last_type & IR_PULSE) { - ev.pulse = true; - rc = ir_raw_event_store(dev, &ev); - } else - return 0; - - dev->raw->last_event = now; - dev->raw->last_type = type; - return rc; -} -EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); - -/** - * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing - * @dev: the struct rc_dev device descriptor - * @type: the type of the event that has occurred - * - * This routine (which may be called from an interrupt context) works - * in similiar manner to ir_raw_event_store_edge. - * This routine is intended for devices with limited internal buffer - * It automerges samples of same type, and handles timeouts - */ -int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev) -{ - if (!dev->raw) - return -EINVAL; - - /* Ignore spaces in idle mode */ - if (dev->idle && !ev->pulse) - return 0; - else if (dev->idle) - ir_raw_event_set_idle(dev, false); - - if (!dev->raw->this_ev.duration) - dev->raw->this_ev = *ev; - else if (ev->pulse == dev->raw->this_ev.pulse) - dev->raw->this_ev.duration += ev->duration; - else { - ir_raw_event_store(dev, &dev->raw->this_ev); - dev->raw->this_ev = *ev; - } - - /* Enter idle mode if nessesary */ - if (!ev->pulse && dev->timeout && - dev->raw->this_ev.duration >= dev->timeout) - ir_raw_event_set_idle(dev, true); - - return 0; -} -EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter); - -/** - * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not - * @dev: the struct rc_dev device descriptor - * @idle: whether the device is idle or not - */ -void ir_raw_event_set_idle(struct rc_dev *dev, bool idle) -{ - if (!dev->raw) - return; - - IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave"); - - if (idle) { - dev->raw->this_ev.timeout = true; - ir_raw_event_store(dev, &dev->raw->this_ev); - init_ir_raw_event(&dev->raw->this_ev); - } - - if (dev->s_idle) - dev->s_idle(dev, idle); - - dev->idle = idle; -} -EXPORT_SYMBOL_GPL(ir_raw_event_set_idle); - -/** - * ir_raw_event_handle() - schedules the decoding of stored ir data - * @dev: the struct rc_dev device descriptor - * - * This routine will tell rc-core to start decoding stored ir data. - */ -void ir_raw_event_handle(struct rc_dev *dev) -{ - unsigned long flags; - - if (!dev->raw) - return; - - spin_lock_irqsave(&dev->raw->lock, flags); - wake_up_process(dev->raw->thread); - spin_unlock_irqrestore(&dev->raw->lock, flags); -} -EXPORT_SYMBOL_GPL(ir_raw_event_handle); - -/* used internally by the sysfs interface */ -u64 -ir_raw_get_allowed_protocols(void) -{ - u64 protocols; - mutex_lock(&ir_raw_handler_lock); - protocols = available_protocols; - mutex_unlock(&ir_raw_handler_lock); - return protocols; -} - -/* - * Used to (un)register raw event clients - */ -int ir_raw_event_register(struct rc_dev *dev) -{ - int rc; - struct ir_raw_handler *handler; - - if (!dev) - return -EINVAL; - - dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL); - if (!dev->raw) - return -ENOMEM; - - dev->raw->dev = dev; - dev->raw->enabled_protocols = ~0; - rc = kfifo_alloc(&dev->raw->kfifo, - sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, - GFP_KERNEL); - if (rc < 0) - goto out; - - spin_lock_init(&dev->raw->lock); - dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, - "rc%ld", dev->devno); - - if (IS_ERR(dev->raw->thread)) { - rc = PTR_ERR(dev->raw->thread); - goto out; - } - - mutex_lock(&ir_raw_handler_lock); - list_add_tail(&dev->raw->list, &ir_raw_client_list); - list_for_each_entry(handler, &ir_raw_handler_list, list) - if (handler->raw_register) - handler->raw_register(dev); - mutex_unlock(&ir_raw_handler_lock); - - return 0; - -out: - kfree(dev->raw); - dev->raw = NULL; - return rc; -} - -void ir_raw_event_unregister(struct rc_dev *dev) -{ - struct ir_raw_handler *handler; - - if (!dev || !dev->raw) - return; - - kthread_stop(dev->raw->thread); - - mutex_lock(&ir_raw_handler_lock); - list_del(&dev->raw->list); - list_for_each_entry(handler, &ir_raw_handler_list, list) - if (handler->raw_unregister) - handler->raw_unregister(dev); - mutex_unlock(&ir_raw_handler_lock); - - kfifo_free(&dev->raw->kfifo); - kfree(dev->raw); - dev->raw = NULL; -} - -/* - * Extension interface - used to register the IR decoders - */ - -int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) -{ - struct ir_raw_event_ctrl *raw; - - mutex_lock(&ir_raw_handler_lock); - list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); - if (ir_raw_handler->raw_register) - list_for_each_entry(raw, &ir_raw_client_list, list) - ir_raw_handler->raw_register(raw->dev); - available_protocols |= ir_raw_handler->protocols; - mutex_unlock(&ir_raw_handler_lock); - - return 0; -} -EXPORT_SYMBOL(ir_raw_handler_register); - -void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) -{ - struct ir_raw_event_ctrl *raw; - - mutex_lock(&ir_raw_handler_lock); - list_del(&ir_raw_handler->list); - if (ir_raw_handler->raw_unregister) - list_for_each_entry(raw, &ir_raw_client_list, list) - ir_raw_handler->raw_unregister(raw->dev); - available_protocols &= ~ir_raw_handler->protocols; - mutex_unlock(&ir_raw_handler_lock); -} -EXPORT_SYMBOL(ir_raw_handler_unregister); - -#ifdef MODULE -static void init_decoders(struct work_struct *work) -{ - /* Load the decoder modules */ - - load_nec_decode(); - load_rc5_decode(); - load_rc6_decode(); - load_jvc_decode(); - load_sony_decode(); - load_lirc_codec(); - - /* If needed, we may later add some init code. In this case, - it is needed to change the CONFIG_MODULE test at rc-core.h - */ -} -#endif - -void ir_raw_init(void) -{ -#ifdef MODULE - INIT_WORK(&wq_load, init_decoders); - schedule_work(&wq_load); -#endif -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc5-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc5-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc5-decoder.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc5-decoder.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,189 +0,0 @@ -/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol - * - * Copyright (C) 2010 by Mauro Carvalho Chehab - * - * 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 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. - */ - -/* - * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols. - * There are other variants that use a different number of bits. - * This is currently unsupported. - * It considers a carrier of 36 kHz, with a total of 14/20 bits, where - * the first two bits are start bits, and a third one is a filing bit - */ - -#include "rc-core-priv.h" - -#define RC5_NBITS 14 -#define RC5X_NBITS 20 -#define CHECK_RC5X_NBITS 8 -#define RC5_UNIT 888888 /* ns */ -#define RC5_BIT_START (1 * RC5_UNIT) -#define RC5_BIT_END (1 * RC5_UNIT) -#define RC5X_SPACE (4 * RC5_UNIT) - -enum rc5_state { - STATE_INACTIVE, - STATE_BIT_START, - STATE_BIT_END, - STATE_CHECK_RC5X, - STATE_FINISHED, -}; - -/** - * ir_rc5_decode() - Decode one RC-5 pulse or space - * @dev: the struct rc_dev descriptor of the device - * @ev: the struct ir_raw_event descriptor of the pulse/space - * - * This function returns -EINVAL if the pulse violates the state machine - */ -static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) -{ - struct rc5_dec *data = &dev->raw->rc5; - u8 toggle; - u32 scancode; - - if (!(dev->raw->enabled_protocols & RC_TYPE_RC5)) - return 0; - - if (!is_timing_event(ev)) { - if (ev.reset) - data->state = STATE_INACTIVE; - return 0; - } - - if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) - goto out; - -again: - IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - - if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) - return 0; - - switch (data->state) { - - case STATE_INACTIVE: - if (!ev.pulse) - break; - - data->state = STATE_BIT_START; - data->count = 1; - /* We just need enough bits to get to STATE_CHECK_RC5X */ - data->wanted_bits = RC5X_NBITS; - decrease_duration(&ev, RC5_BIT_START); - goto again; - - case STATE_BIT_START: - if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) - break; - - data->bits <<= 1; - if (!ev.pulse) - data->bits |= 1; - data->count++; - data->state = STATE_BIT_END; - return 0; - - case STATE_BIT_END: - if (!is_transition(&ev, &dev->raw->prev_ev)) - break; - - if (data->count == data->wanted_bits) - data->state = STATE_FINISHED; - else if (data->count == CHECK_RC5X_NBITS) - data->state = STATE_CHECK_RC5X; - else - data->state = STATE_BIT_START; - - decrease_duration(&ev, RC5_BIT_END); - goto again; - - case STATE_CHECK_RC5X: - if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) { - /* RC5X */ - data->wanted_bits = RC5X_NBITS; - decrease_duration(&ev, RC5X_SPACE); - } else { - /* RC5 */ - data->wanted_bits = RC5_NBITS; - } - data->state = STATE_BIT_START; - goto again; - - case STATE_FINISHED: - if (ev.pulse) - break; - - if (data->wanted_bits == RC5X_NBITS) { - /* RC5X */ - u8 xdata, command, system; - xdata = (data->bits & 0x0003F) >> 0; - command = (data->bits & 0x00FC0) >> 6; - system = (data->bits & 0x1F000) >> 12; - toggle = (data->bits & 0x20000) ? 1 : 0; - command += (data->bits & 0x01000) ? 0 : 0x40; - scancode = system << 16 | command << 8 | xdata; - - IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n", - scancode, toggle); - - } else { - /* RC5 */ - u8 command, system; - command = (data->bits & 0x0003F) >> 0; - system = (data->bits & 0x007C0) >> 6; - toggle = (data->bits & 0x00800) ? 1 : 0; - command += (data->bits & 0x01000) ? 0 : 0x40; - scancode = system << 8 | command; - - IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n", - scancode, toggle); - } - - rc_keydown(dev, scancode, toggle); - data->state = STATE_INACTIVE; - return 0; - } - -out: - IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - data->state = STATE_INACTIVE; - return -EINVAL; -} - -static struct ir_raw_handler rc5_handler = { - .protocols = RC_TYPE_RC5, - .decode = ir_rc5_decode, -}; - -static int __init ir_rc5_decode_init(void) -{ - ir_raw_handler_register(&rc5_handler); - - printk(KERN_INFO "IR RC5(x) protocol handler initialized\n"); - return 0; -} - -static void __exit ir_rc5_decode_exit(void) -{ - ir_raw_handler_unregister(&rc5_handler); -} - -module_init(ir_rc5_decode_init); -module_exit(ir_rc5_decode_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -MODULE_DESCRIPTION("RC5(x) IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc5-sz-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc5-sz-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc5-sz-decoder.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc5-sz-decoder.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,153 +0,0 @@ -/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol - * - * Copyright (C) 2010 by Mauro Carvalho Chehab - * Copyright (C) 2010 by Jarod Wilson - * - * 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 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. - */ - -/* - * This code handles the 15 bit RC5-ish protocol used by the Streamzap - * PC Remote. - * It considers a carrier of 36 kHz, with a total of 15 bits, where - * the first two bits are start bits, and a third one is a filing bit - */ - -#include "rc-core-priv.h" - -#define RC5_SZ_NBITS 15 -#define RC5_UNIT 888888 /* ns */ -#define RC5_BIT_START (1 * RC5_UNIT) -#define RC5_BIT_END (1 * RC5_UNIT) - -enum rc5_sz_state { - STATE_INACTIVE, - STATE_BIT_START, - STATE_BIT_END, - STATE_FINISHED, -}; - -/** - * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space - * @dev: the struct rc_dev descriptor of the device - * @ev: the struct ir_raw_event descriptor of the pulse/space - * - * This function returns -EINVAL if the pulse violates the state machine - */ -static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev) -{ - struct rc5_sz_dec *data = &dev->raw->rc5_sz; - u8 toggle, command, system; - u32 scancode; - - if (!(dev->raw->enabled_protocols & RC_TYPE_RC5_SZ)) - return 0; - - if (!is_timing_event(ev)) { - if (ev.reset) - data->state = STATE_INACTIVE; - return 0; - } - - if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) - goto out; - -again: - IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - - if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) - return 0; - - switch (data->state) { - - case STATE_INACTIVE: - if (!ev.pulse) - break; - - data->state = STATE_BIT_START; - data->count = 1; - data->wanted_bits = RC5_SZ_NBITS; - decrease_duration(&ev, RC5_BIT_START); - goto again; - - case STATE_BIT_START: - if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) - break; - - data->bits <<= 1; - if (!ev.pulse) - data->bits |= 1; - data->count++; - data->state = STATE_BIT_END; - return 0; - - case STATE_BIT_END: - if (!is_transition(&ev, &dev->raw->prev_ev)) - break; - - if (data->count == data->wanted_bits) - data->state = STATE_FINISHED; - else - data->state = STATE_BIT_START; - - decrease_duration(&ev, RC5_BIT_END); - goto again; - - case STATE_FINISHED: - if (ev.pulse) - break; - - /* RC5-sz */ - command = (data->bits & 0x0003F) >> 0; - system = (data->bits & 0x02FC0) >> 6; - toggle = (data->bits & 0x01000) ? 1 : 0; - scancode = system << 6 | command; - - IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n", - scancode, toggle); - - rc_keydown(dev, scancode, toggle); - data->state = STATE_INACTIVE; - return 0; - } - -out: - IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - data->state = STATE_INACTIVE; - return -EINVAL; -} - -static struct ir_raw_handler rc5_sz_handler = { - .protocols = RC_TYPE_RC5_SZ, - .decode = ir_rc5_sz_decode, -}; - -static int __init ir_rc5_sz_decode_init(void) -{ - ir_raw_handler_register(&rc5_sz_handler); - - printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n"); - return 0; -} - -static void __exit ir_rc5_sz_decode_exit(void) -{ - ir_raw_handler_unregister(&rc5_sz_handler); -} - -module_init(ir_rc5_sz_decode_init); -module_exit(ir_rc5_sz_decode_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson "); -MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc6-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc6-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc6-decoder.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-rc6-decoder.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,280 +0,0 @@ -/* ir-rc6-decoder.c - A decoder for the RC6 IR protocol - * - * Copyright (C) 2010 by David Härdeman - * - * 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 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. - */ - -#include "rc-core-priv.h" - -/* - * This decoder currently supports: - * RC6-0-16 (standard toggle bit in header) - * RC6-6A-24 (no toggle bit) - * RC6-6A-32 (MCE version with toggle bit in body) - */ - -#define RC6_UNIT 444444 /* us */ -#define RC6_HEADER_NBITS 4 /* not including toggle bit */ -#define RC6_0_NBITS 16 -#define RC6_6A_SMALL_NBITS 24 -#define RC6_6A_LARGE_NBITS 32 -#define RC6_PREFIX_PULSE (6 * RC6_UNIT) -#define RC6_PREFIX_SPACE (2 * RC6_UNIT) -#define RC6_BIT_START (1 * RC6_UNIT) -#define RC6_BIT_END (1 * RC6_UNIT) -#define RC6_TOGGLE_START (2 * RC6_UNIT) -#define RC6_TOGGLE_END (2 * RC6_UNIT) -#define RC6_MODE_MASK 0x07 /* for the header bits */ -#define RC6_STARTBIT_MASK 0x08 /* for the header bits */ -#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ - -enum rc6_mode { - RC6_MODE_0, - RC6_MODE_6A, - RC6_MODE_UNKNOWN, -}; - -enum rc6_state { - STATE_INACTIVE, - STATE_PREFIX_SPACE, - STATE_HEADER_BIT_START, - STATE_HEADER_BIT_END, - STATE_TOGGLE_START, - STATE_TOGGLE_END, - STATE_BODY_BIT_START, - STATE_BODY_BIT_END, - STATE_FINISHED, -}; - -static enum rc6_mode rc6_mode(struct rc6_dec *data) -{ - switch (data->header & RC6_MODE_MASK) { - case 0: - return RC6_MODE_0; - case 6: - if (!data->toggle) - return RC6_MODE_6A; - /* fall through */ - default: - return RC6_MODE_UNKNOWN; - } -} - -/** - * ir_rc6_decode() - Decode one RC6 pulse or space - * @dev: the struct rc_dev descriptor of the device - * @ev: the struct ir_raw_event descriptor of the pulse/space - * - * This function returns -EINVAL if the pulse violates the state machine - */ -static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) -{ - struct rc6_dec *data = &dev->raw->rc6; - u32 scancode; - u8 toggle; - - if (!(dev->raw->enabled_protocols & RC_TYPE_RC6)) - return 0; - - if (!is_timing_event(ev)) { - if (ev.reset) - data->state = STATE_INACTIVE; - return 0; - } - - if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) - goto out; - -again: - IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - - if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) - return 0; - - switch (data->state) { - - case STATE_INACTIVE: - if (!ev.pulse) - break; - - /* Note: larger margin on first pulse since each RC6_UNIT - is quite short and some hardware takes some time to - adjust to the signal */ - if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT)) - break; - - data->state = STATE_PREFIX_SPACE; - data->count = 0; - return 0; - - case STATE_PREFIX_SPACE: - if (ev.pulse) - break; - - if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2)) - break; - - data->state = STATE_HEADER_BIT_START; - return 0; - - case STATE_HEADER_BIT_START: - if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) - break; - - data->header <<= 1; - if (ev.pulse) - data->header |= 1; - data->count++; - data->state = STATE_HEADER_BIT_END; - return 0; - - case STATE_HEADER_BIT_END: - if (!is_transition(&ev, &dev->raw->prev_ev)) - break; - - if (data->count == RC6_HEADER_NBITS) - data->state = STATE_TOGGLE_START; - else - data->state = STATE_HEADER_BIT_START; - - decrease_duration(&ev, RC6_BIT_END); - goto again; - - case STATE_TOGGLE_START: - if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2)) - break; - - data->toggle = ev.pulse; - data->state = STATE_TOGGLE_END; - return 0; - - case STATE_TOGGLE_END: - if (!is_transition(&ev, &dev->raw->prev_ev) || - !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2)) - break; - - if (!(data->header & RC6_STARTBIT_MASK)) { - IR_dprintk(1, "RC6 invalid start bit\n"); - break; - } - - data->state = STATE_BODY_BIT_START; - decrease_duration(&ev, RC6_TOGGLE_END); - data->count = 0; - - switch (rc6_mode(data)) { - case RC6_MODE_0: - data->wanted_bits = RC6_0_NBITS; - break; - case RC6_MODE_6A: - /* This might look weird, but we basically - check the value of the first body bit to - determine the number of bits in mode 6A */ - if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) || - geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) - data->wanted_bits = RC6_6A_LARGE_NBITS; - else - data->wanted_bits = RC6_6A_SMALL_NBITS; - break; - default: - IR_dprintk(1, "RC6 unknown mode\n"); - goto out; - } - goto again; - - case STATE_BODY_BIT_START: - if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) - break; - - data->body <<= 1; - if (ev.pulse) - data->body |= 1; - data->count++; - data->state = STATE_BODY_BIT_END; - return 0; - - case STATE_BODY_BIT_END: - if (!is_transition(&ev, &dev->raw->prev_ev)) - break; - - if (data->count == data->wanted_bits) - data->state = STATE_FINISHED; - else - data->state = STATE_BODY_BIT_START; - - decrease_duration(&ev, RC6_BIT_END); - goto again; - - case STATE_FINISHED: - if (ev.pulse) - break; - - switch (rc6_mode(data)) { - case RC6_MODE_0: - scancode = data->body & 0xffff; - toggle = data->toggle; - IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", - scancode, toggle); - break; - case RC6_MODE_6A: - if (data->wanted_bits == RC6_6A_LARGE_NBITS) { - toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0; - scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK; - } else { - toggle = 0; - scancode = data->body & 0xffffff; - } - - IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n", - scancode, toggle); - break; - default: - IR_dprintk(1, "RC6 unknown mode\n"); - goto out; - } - - rc_keydown(dev, scancode, toggle); - data->state = STATE_INACTIVE; - return 0; - } - -out: - IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - data->state = STATE_INACTIVE; - return -EINVAL; -} - -static struct ir_raw_handler rc6_handler = { - .protocols = RC_TYPE_RC6, - .decode = ir_rc6_decode, -}; - -static int __init ir_rc6_decode_init(void) -{ - ir_raw_handler_register(&rc6_handler); - - printk(KERN_INFO "IR RC6 protocol handler initialized\n"); - return 0; -} - -static void __exit ir_rc6_decode_exit(void) -{ - ir_raw_handler_unregister(&rc6_handler); -} - -module_init(ir_rc6_decode_init); -module_exit(ir_rc6_decode_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Härdeman "); -MODULE_DESCRIPTION("RC6 IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-sony-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-sony-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-sony-decoder.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ir-sony-decoder.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,181 +0,0 @@ -/* ir-sony-decoder.c - handle Sony IR Pulse/Space protocol - * - * Copyright (C) 2010 by David Härdeman - * - * 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 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. - */ - -#include -#include "rc-core-priv.h" - -#define SONY_UNIT 600000 /* ns */ -#define SONY_HEADER_PULSE (4 * SONY_UNIT) -#define SONY_HEADER_SPACE (1 * SONY_UNIT) -#define SONY_BIT_0_PULSE (1 * SONY_UNIT) -#define SONY_BIT_1_PULSE (2 * SONY_UNIT) -#define SONY_BIT_SPACE (1 * SONY_UNIT) -#define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */ - -enum sony_state { - STATE_INACTIVE, - STATE_HEADER_SPACE, - STATE_BIT_PULSE, - STATE_BIT_SPACE, - STATE_FINISHED, -}; - -/** - * ir_sony_decode() - Decode one Sony pulse or space - * @dev: the struct rc_dev descriptor of the device - * @ev: the struct ir_raw_event descriptor of the pulse/space - * - * This function returns -EINVAL if the pulse violates the state machine - */ -static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) -{ - struct sony_dec *data = &dev->raw->sony; - u32 scancode; - u8 device, subdevice, function; - - if (!(dev->raw->enabled_protocols & RC_TYPE_SONY)) - return 0; - - if (!is_timing_event(ev)) { - if (ev.reset) - data->state = STATE_INACTIVE; - return 0; - } - - if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) - goto out; - - IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - - switch (data->state) { - - case STATE_INACTIVE: - if (!ev.pulse) - break; - - if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2)) - break; - - data->count = 0; - data->state = STATE_HEADER_SPACE; - return 0; - - case STATE_HEADER_SPACE: - if (ev.pulse) - break; - - if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2)) - break; - - data->state = STATE_BIT_PULSE; - return 0; - - case STATE_BIT_PULSE: - if (!ev.pulse) - break; - - data->bits <<= 1; - if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2)) - data->bits |= 1; - else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2)) - break; - - data->count++; - data->state = STATE_BIT_SPACE; - return 0; - - case STATE_BIT_SPACE: - if (ev.pulse) - break; - - if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2)) - break; - - decrease_duration(&ev, SONY_BIT_SPACE); - - if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) { - data->state = STATE_BIT_PULSE; - return 0; - } - - data->state = STATE_FINISHED; - /* Fall through */ - - case STATE_FINISHED: - if (ev.pulse) - break; - - if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2)) - break; - - switch (data->count) { - case 12: - device = bitrev8((data->bits << 3) & 0xF8); - subdevice = 0; - function = bitrev8((data->bits >> 4) & 0xFE); - break; - case 15: - device = bitrev8((data->bits >> 0) & 0xFF); - subdevice = 0; - function = bitrev8((data->bits >> 7) & 0xFD); - break; - case 20: - device = bitrev8((data->bits >> 5) & 0xF8); - subdevice = bitrev8((data->bits >> 0) & 0xFF); - function = bitrev8((data->bits >> 12) & 0xFE); - break; - default: - IR_dprintk(1, "Sony invalid bitcount %u\n", data->count); - goto out; - } - - scancode = device << 16 | subdevice << 8 | function; - IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode); - rc_keydown(dev, scancode, 0); - data->state = STATE_INACTIVE; - return 0; - } - -out: - IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - data->state = STATE_INACTIVE; - return -EINVAL; -} - -static struct ir_raw_handler sony_handler = { - .protocols = RC_TYPE_SONY, - .decode = ir_sony_decode, -}; - -static int __init ir_sony_decode_init(void) -{ - ir_raw_handler_register(&sony_handler); - - printk(KERN_INFO "IR Sony protocol handler initialized\n"); - return 0; -} - -static void __exit ir_sony_decode_exit(void) -{ - ir_raw_handler_unregister(&sony_handler); -} - -module_init(ir_sony_decode_init); -module_exit(ir_sony_decode_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Härdeman "); -MODULE_DESCRIPTION("Sony IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ite-cir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ite-cir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ite-cir.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ite-cir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1736 +0,0 @@ -/* - * Driver for ITE Tech Inc. IT8712F/IT8512 CIR - * - * Copyright (C) 2010 Juan Jesús García de Soria - * - * 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, or (at your option) any later version. - * - * 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. - * - * Inspired by the original lirc_it87 and lirc_ite8709 drivers, on top of the - * skeleton provided by the nuvoton-cir driver. - * - * The lirc_it87 driver was originally written by Hans-Gunter Lutke Uphues - * in 2001, with enhancements by Christoph Bartelmus - * , Andrew Calkin and James Edwards - * . - * - * The lirc_ite8709 driver was written by Grégory Lardière - * in 2008. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ite-cir.h" - -/* module parameters */ - -/* debug level */ -static int debug; -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging output"); - -/* low limit for RX carrier freq, Hz, 0 for no RX demodulation */ -static int rx_low_carrier_freq; -module_param(rx_low_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, " - "0 for no RX demodulation"); - -/* high limit for RX carrier freq, Hz, 0 for no RX demodulation */ -static int rx_high_carrier_freq; -module_param(rx_high_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, " - "Hz, 0 for no RX demodulation"); - -/* override tx carrier frequency */ -static int tx_carrier_freq; -module_param(tx_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(tx_carrier_freq, "Override TX carrier frequency, Hz"); - -/* override tx duty cycle */ -static int tx_duty_cycle; -module_param(tx_duty_cycle, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(tx_duty_cycle, "Override TX duty cycle, 1-100"); - -/* override default sample period */ -static long sample_period; -module_param(sample_period, long, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(sample_period, "Override carrier sample period, us"); - -/* override detected model id */ -static int model_number = -1; -module_param(model_number, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(model_number, "Use this model number, don't autodetect"); - - -/* HW-independent code functions */ - -/* check whether carrier frequency is high frequency */ -static inline bool ite_is_high_carrier_freq(unsigned int freq) -{ - return freq >= ITE_HCF_MIN_CARRIER_FREQ; -} - -/* get the bits required to program the carrier frequency in CFQ bits, - * unshifted */ -static u8 ite_get_carrier_freq_bits(unsigned int freq) -{ - if (ite_is_high_carrier_freq(freq)) { - if (freq < 425000) - return ITE_CFQ_400; - - else if (freq < 465000) - return ITE_CFQ_450; - - else if (freq < 490000) - return ITE_CFQ_480; - - else - return ITE_CFQ_500; - } else { - /* trim to limits */ - if (freq < ITE_LCF_MIN_CARRIER_FREQ) - freq = ITE_LCF_MIN_CARRIER_FREQ; - if (freq > ITE_LCF_MAX_CARRIER_FREQ) - freq = ITE_LCF_MAX_CARRIER_FREQ; - - /* convert to kHz and subtract the base freq */ - freq = - DIV_ROUND_CLOSEST(freq - ITE_LCF_MIN_CARRIER_FREQ, - 1000); - - return (u8) freq; - } -} - -/* get the bits required to program the pulse with in TXMPW */ -static u8 ite_get_pulse_width_bits(unsigned int freq, int duty_cycle) -{ - unsigned long period_ns, on_ns; - - /* sanitize freq into range */ - if (freq < ITE_LCF_MIN_CARRIER_FREQ) - freq = ITE_LCF_MIN_CARRIER_FREQ; - if (freq > ITE_HCF_MAX_CARRIER_FREQ) - freq = ITE_HCF_MAX_CARRIER_FREQ; - - period_ns = 1000000000UL / freq; - on_ns = period_ns * duty_cycle / 100; - - if (ite_is_high_carrier_freq(freq)) { - if (on_ns < 750) - return ITE_TXMPW_A; - - else if (on_ns < 850) - return ITE_TXMPW_B; - - else if (on_ns < 950) - return ITE_TXMPW_C; - - else if (on_ns < 1080) - return ITE_TXMPW_D; - - else - return ITE_TXMPW_E; - } else { - if (on_ns < 6500) - return ITE_TXMPW_A; - - else if (on_ns < 7850) - return ITE_TXMPW_B; - - else if (on_ns < 9650) - return ITE_TXMPW_C; - - else if (on_ns < 11950) - return ITE_TXMPW_D; - - else - return ITE_TXMPW_E; - } -} - -/* decode raw bytes as received by the hardware, and push them to the ir-core - * layer */ -static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int - length) -{ - u32 sample_period; - unsigned long *ldata; - unsigned int next_one, next_zero, size; - DEFINE_IR_RAW_EVENT(ev); - - if (length == 0) - return; - - sample_period = dev->params.sample_period; - ldata = (unsigned long *)data; - size = length << 3; - next_one = generic_find_next_le_bit(ldata, size, 0); - if (next_one > 0) { - ev.pulse = true; - ev.duration = - ITE_BITS_TO_NS(next_one, sample_period); - ir_raw_event_store_with_filter(dev->rdev, &ev); - } - - while (next_one < size) { - next_zero = generic_find_next_zero_le_bit(ldata, size, next_one + 1); - ev.pulse = false; - ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period); - ir_raw_event_store_with_filter(dev->rdev, &ev); - - if (next_zero < size) { - next_one = - generic_find_next_le_bit(ldata, - size, - next_zero + 1); - ev.pulse = true; - ev.duration = - ITE_BITS_TO_NS(next_one - next_zero, - sample_period); - ir_raw_event_store_with_filter - (dev->rdev, &ev); - } else - next_one = size; - } - - ir_raw_event_handle(dev->rdev); - - ite_dbg_verbose("decoded %d bytes.", length); -} - -/* set all the rx/tx carrier parameters; this must be called with the device - * spinlock held */ -static void ite_set_carrier_params(struct ite_dev *dev) -{ - unsigned int freq, low_freq, high_freq; - int allowance; - bool use_demodulator; - bool for_tx = dev->transmitting; - - ite_dbg("%s called", __func__); - - if (for_tx) { - /* we don't need no stinking calculations */ - freq = dev->params.tx_carrier_freq; - allowance = ITE_RXDCR_DEFAULT; - use_demodulator = false; - } else { - low_freq = dev->params.rx_low_carrier_freq; - high_freq = dev->params.rx_high_carrier_freq; - - if (low_freq == 0) { - /* don't demodulate */ - freq = - ITE_DEFAULT_CARRIER_FREQ; - allowance = ITE_RXDCR_DEFAULT; - use_demodulator = false; - } else { - /* calculate the middle freq */ - freq = (low_freq + high_freq) / 2; - - /* calculate the allowance */ - allowance = - DIV_ROUND_CLOSEST(10000 * (high_freq - low_freq), - ITE_RXDCR_PER_10000_STEP - * (high_freq + low_freq)); - - if (allowance < 1) - allowance = 1; - - if (allowance > ITE_RXDCR_MAX) - allowance = ITE_RXDCR_MAX; - } - } - - /* set the carrier parameters in a device-dependent way */ - dev->params.set_carrier_params(dev, ite_is_high_carrier_freq(freq), - use_demodulator, ite_get_carrier_freq_bits(freq), allowance, - ite_get_pulse_width_bits(freq, dev->params.tx_duty_cycle)); -} - -/* interrupt service routine for incoming and outgoing CIR data */ -static irqreturn_t ite_cir_isr(int irq, void *data) -{ - struct ite_dev *dev = data; - unsigned long flags; - irqreturn_t ret = IRQ_RETVAL(IRQ_NONE); - u8 rx_buf[ITE_RX_FIFO_LEN]; - int rx_bytes; - int iflags; - - ite_dbg_verbose("%s firing", __func__); - - /* grab the spinlock */ - spin_lock_irqsave(&dev->lock, flags); - - /* read the interrupt flags */ - iflags = dev->params.get_irq_causes(dev); - - /* check for the receive interrupt */ - if (iflags & (ITE_IRQ_RX_FIFO | ITE_IRQ_RX_FIFO_OVERRUN)) { - /* read the FIFO bytes */ - rx_bytes = - dev->params.get_rx_bytes(dev, rx_buf, - ITE_RX_FIFO_LEN); - - if (rx_bytes > 0) { - /* drop the spinlock, since the ir-core layer - * may call us back again through - * ite_s_idle() */ - spin_unlock_irqrestore(&dev-> - lock, - flags); - - /* decode the data we've just received */ - ite_decode_bytes(dev, rx_buf, - rx_bytes); - - /* reacquire the spinlock */ - spin_lock_irqsave(&dev->lock, - flags); - - /* mark the interrupt as serviced */ - ret = IRQ_RETVAL(IRQ_HANDLED); - } - } else if (iflags & ITE_IRQ_TX_FIFO) { - /* FIFO space available interrupt */ - ite_dbg_verbose("got interrupt for TX FIFO"); - - /* wake any sleeping transmitter */ - wake_up_interruptible(&dev->tx_queue); - - /* mark the interrupt as serviced */ - ret = IRQ_RETVAL(IRQ_HANDLED); - } - - /* drop the spinlock */ - spin_unlock_irqrestore(&dev->lock, flags); - - ite_dbg_verbose("%s done returning %d", __func__, (int)ret); - - return ret; -} - -/* set the rx carrier freq range, guess it's in Hz... */ -static int ite_set_rx_carrier_range(struct rc_dev *rcdev, u32 carrier_low, u32 - carrier_high) -{ - unsigned long flags; - struct ite_dev *dev = rcdev->priv; - - spin_lock_irqsave(&dev->lock, flags); - dev->params.rx_low_carrier_freq = carrier_low; - dev->params.rx_high_carrier_freq = carrier_high; - ite_set_carrier_params(dev); - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/* set the tx carrier freq, guess it's in Hz... */ -static int ite_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) -{ - unsigned long flags; - struct ite_dev *dev = rcdev->priv; - - spin_lock_irqsave(&dev->lock, flags); - dev->params.tx_carrier_freq = carrier; - ite_set_carrier_params(dev); - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/* set the tx duty cycle by controlling the pulse width */ -static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle) -{ - unsigned long flags; - struct ite_dev *dev = rcdev->priv; - - spin_lock_irqsave(&dev->lock, flags); - dev->params.tx_duty_cycle = duty_cycle; - ite_set_carrier_params(dev); - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/* transmit out IR pulses; what you get here is a batch of alternating - * pulse/space/pulse/space lengths that we should write out completely through - * the FIFO, blocking on a full FIFO */ -static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n) -{ - unsigned long flags; - struct ite_dev *dev = rcdev->priv; - bool is_pulse = false; - int remaining_us, fifo_avail, fifo_remaining, last_idx = 0; - int max_rle_us, next_rle_us; - int ret = n; - u8 last_sent[ITE_TX_FIFO_LEN]; - u8 val; - - ite_dbg("%s called", __func__); - - /* clear the array just in case */ - memset(last_sent, 0, ARRAY_SIZE(last_sent)); - - /* n comes in bytes; convert to ints */ - n /= sizeof(int); - - spin_lock_irqsave(&dev->lock, flags); - - /* let everybody know we're now transmitting */ - dev->transmitting = true; - - /* and set the carrier values for transmission */ - ite_set_carrier_params(dev); - - /* calculate how much time we can send in one byte */ - max_rle_us = - (ITE_BAUDRATE_DIVISOR * dev->params.sample_period * - ITE_TX_MAX_RLE) / 1000; - - /* disable the receiver */ - dev->params.disable_rx(dev); - - /* this is where we'll begin filling in the FIFO, until it's full. - * then we'll just activate the interrupt, wait for it to wake us up - * again, disable it, continue filling the FIFO... until everything - * has been pushed out */ - fifo_avail = - ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); - - while (n > 0 && dev->in_use) { - /* transmit the next sample */ - is_pulse = !is_pulse; - remaining_us = *(txbuf++); - n--; - - ite_dbg("%s: %ld", - ((is_pulse) ? "pulse" : "space"), - (long int) - remaining_us); - - /* repeat while the pulse is non-zero length */ - while (remaining_us > 0 && dev->in_use) { - if (remaining_us > max_rle_us) - next_rle_us = max_rle_us; - - else - next_rle_us = remaining_us; - - remaining_us -= next_rle_us; - - /* check what's the length we have to pump out */ - val = (ITE_TX_MAX_RLE * next_rle_us) / max_rle_us; - - /* put it into the sent buffer */ - last_sent[last_idx++] = val; - last_idx &= (ITE_TX_FIFO_LEN); - - /* encode it for 7 bits */ - val = (val - 1) & ITE_TX_RLE_MASK; - - /* take into account pulse/space prefix */ - if (is_pulse) - val |= ITE_TX_PULSE; - - else - val |= ITE_TX_SPACE; - - /* - * if we get to 0 available, read again, just in case - * some other slot got freed - */ - if (fifo_avail <= 0) - fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); - - /* if it's still full */ - if (fifo_avail <= 0) { - /* enable the tx interrupt */ - dev->params. - enable_tx_interrupt(dev); - - /* drop the spinlock */ - spin_unlock_irqrestore(&dev->lock, flags); - - /* wait for the FIFO to empty enough */ - wait_event_interruptible(dev->tx_queue, (fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev)) >= 8); - - /* get the spinlock again */ - spin_lock_irqsave(&dev->lock, flags); - - /* disable the tx interrupt again. */ - dev->params. - disable_tx_interrupt(dev); - } - - /* now send the byte through the FIFO */ - dev->params.put_tx_byte(dev, val); - fifo_avail--; - } - } - - /* wait and don't return until the whole FIFO has been sent out; - * otherwise we could configure the RX carrier params instead of the - * TX ones while the transmission is still being performed! */ - fifo_remaining = dev->params.get_tx_used_slots(dev); - remaining_us = 0; - while (fifo_remaining > 0) { - fifo_remaining--; - last_idx--; - last_idx &= (ITE_TX_FIFO_LEN - 1); - remaining_us += last_sent[last_idx]; - } - remaining_us = (remaining_us * max_rle_us) / (ITE_TX_MAX_RLE); - - /* drop the spinlock while we sleep */ - spin_unlock_irqrestore(&dev->lock, flags); - - /* sleep remaining_us microseconds */ - mdelay(DIV_ROUND_UP(remaining_us, 1000)); - - /* reacquire the spinlock */ - spin_lock_irqsave(&dev->lock, flags); - - /* now we're not transmitting anymore */ - dev->transmitting = false; - - /* and set the carrier values for reception */ - ite_set_carrier_params(dev); - - /* reenable the receiver */ - if (dev->in_use) - dev->params.enable_rx(dev); - - /* notify transmission end */ - wake_up_interruptible(&dev->tx_ended); - - spin_unlock_irqrestore(&dev->lock, flags); - - return ret; -} - -/* idle the receiver if needed */ -static void ite_s_idle(struct rc_dev *rcdev, bool enable) -{ - unsigned long flags; - struct ite_dev *dev = rcdev->priv; - - ite_dbg("%s called", __func__); - - if (enable) { - spin_lock_irqsave(&dev->lock, flags); - dev->params.idle_rx(dev); - spin_unlock_irqrestore(&dev->lock, flags); - } -} - - -/* IT8712F HW-specific functions */ - -/* retrieve a bitmask of the current causes for a pending interrupt; this may - * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN - * */ -static int it87_get_irq_causes(struct ite_dev *dev) -{ - u8 iflags; - int ret = 0; - - ite_dbg("%s called", __func__); - - /* read the interrupt flags */ - iflags = inb(dev->cir_addr + IT87_IIR) & IT87_II; - - switch (iflags) { - case IT87_II_RXDS: - ret = ITE_IRQ_RX_FIFO; - break; - case IT87_II_RXFO: - ret = ITE_IRQ_RX_FIFO_OVERRUN; - break; - case IT87_II_TXLDL: - ret = ITE_IRQ_TX_FIFO; - break; - } - - return ret; -} - -/* set the carrier parameters; to be called with the spinlock held */ -static void it87_set_carrier_params(struct ite_dev *dev, bool high_freq, - bool use_demodulator, - u8 carrier_freq_bits, u8 allowance_bits, - u8 pulse_width_bits) -{ - u8 val; - - ite_dbg("%s called", __func__); - - /* program the RCR register */ - val = inb(dev->cir_addr + IT87_RCR) - & ~(IT87_HCFS | IT87_RXEND | IT87_RXDCR); - - if (high_freq) - val |= IT87_HCFS; - - if (use_demodulator) - val |= IT87_RXEND; - - val |= allowance_bits; - - outb(val, dev->cir_addr + IT87_RCR); - - /* program the TCR2 register */ - outb((carrier_freq_bits << IT87_CFQ_SHIFT) | pulse_width_bits, - dev->cir_addr + IT87_TCR2); -} - -/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock - * held */ -static int it87_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) -{ - int fifo, read = 0; - - ite_dbg("%s called", __func__); - - /* read how many bytes are still in the FIFO */ - fifo = inb(dev->cir_addr + IT87_RSR) & IT87_RXFBC; - - while (fifo > 0 && buf_size > 0) { - *(buf++) = inb(dev->cir_addr + IT87_DR); - fifo--; - read++; - buf_size--; - } - - return read; -} - -/* return how many bytes are still in the FIFO; this will be called - * with the device spinlock NOT HELD while waiting for the TX FIFO to get - * empty; let's expect this won't be a problem */ -static int it87_get_tx_used_slots(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - return inb(dev->cir_addr + IT87_TSR) & IT87_TXFBC; -} - -/* put a byte to the TX fifo; this should be called with the spinlock held */ -static void it87_put_tx_byte(struct ite_dev *dev, u8 value) -{ - outb(value, dev->cir_addr + IT87_DR); -} - -/* idle the receiver so that we won't receive samples until another - pulse is detected; this must be called with the device spinlock held */ -static void it87_idle_rx(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable streaming by clearing RXACT writing it as 1 */ - outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXACT, - dev->cir_addr + IT87_RCR); - - /* clear the FIFO */ - outb(inb(dev->cir_addr + IT87_TCR1) | IT87_FIFOCLR, - dev->cir_addr + IT87_TCR1); -} - -/* disable the receiver; this must be called with the device spinlock held */ -static void it87_disable_rx(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable the receiver interrupts */ - outb(inb(dev->cir_addr + IT87_IER) & ~(IT87_RDAIE | IT87_RFOIE), - dev->cir_addr + IT87_IER); - - /* disable the receiver */ - outb(inb(dev->cir_addr + IT87_RCR) & ~IT87_RXEN, - dev->cir_addr + IT87_RCR); - - /* clear the FIFO and RXACT (actually RXACT should have been cleared - * in the previous outb() call) */ - it87_idle_rx(dev); -} - -/* enable the receiver; this must be called with the device spinlock held */ -static void it87_enable_rx(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* enable the receiver by setting RXEN */ - outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXEN, - dev->cir_addr + IT87_RCR); - - /* just prepare it to idle for the next reception */ - it87_idle_rx(dev); - - /* enable the receiver interrupts and master enable flag */ - outb(inb(dev->cir_addr + IT87_IER) | IT87_RDAIE | IT87_RFOIE | IT87_IEC, - dev->cir_addr + IT87_IER); -} - -/* disable the transmitter interrupt; this must be called with the device - * spinlock held */ -static void it87_disable_tx_interrupt(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable the transmitter interrupts */ - outb(inb(dev->cir_addr + IT87_IER) & ~IT87_TLDLIE, - dev->cir_addr + IT87_IER); -} - -/* enable the transmitter interrupt; this must be called with the device - * spinlock held */ -static void it87_enable_tx_interrupt(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* enable the transmitter interrupts and master enable flag */ - outb(inb(dev->cir_addr + IT87_IER) | IT87_TLDLIE | IT87_IEC, - dev->cir_addr + IT87_IER); -} - -/* disable the device; this must be called with the device spinlock held */ -static void it87_disable(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* clear out all interrupt enable flags */ - outb(inb(dev->cir_addr + IT87_IER) & - ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE), - dev->cir_addr + IT87_IER); - - /* disable the receiver */ - it87_disable_rx(dev); - - /* erase the FIFO */ - outb(IT87_FIFOCLR | inb(dev->cir_addr + IT87_TCR1), - dev->cir_addr + IT87_TCR1); -} - -/* initialize the hardware */ -static void it87_init_hardware(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* enable just the baud rate divisor register, - disabling all the interrupts at the same time */ - outb((inb(dev->cir_addr + IT87_IER) & - ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE)) | IT87_BR, - dev->cir_addr + IT87_IER); - - /* write out the baud rate divisor */ - outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT87_BDLR); - outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff, dev->cir_addr + IT87_BDHR); - - /* disable the baud rate divisor register again */ - outb(inb(dev->cir_addr + IT87_IER) & ~IT87_BR, - dev->cir_addr + IT87_IER); - - /* program the RCR register defaults */ - outb(ITE_RXDCR_DEFAULT, dev->cir_addr + IT87_RCR); - - /* program the TCR1 register */ - outb(IT87_TXMPM_DEFAULT | IT87_TXENDF | IT87_TXRLE - | IT87_FIFOTL_DEFAULT | IT87_FIFOCLR, - dev->cir_addr + IT87_TCR1); - - /* program the carrier parameters */ - ite_set_carrier_params(dev); -} - -/* IT8512F on ITE8708 HW-specific functions */ - -/* retrieve a bitmask of the current causes for a pending interrupt; this may - * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN - * */ -static int it8708_get_irq_causes(struct ite_dev *dev) -{ - u8 iflags; - int ret = 0; - - ite_dbg("%s called", __func__); - - /* read the interrupt flags */ - iflags = inb(dev->cir_addr + IT8708_C0IIR); - - if (iflags & IT85_TLDLI) - ret |= ITE_IRQ_TX_FIFO; - if (iflags & IT85_RDAI) - ret |= ITE_IRQ_RX_FIFO; - if (iflags & IT85_RFOI) - ret |= ITE_IRQ_RX_FIFO_OVERRUN; - - return ret; -} - -/* set the carrier parameters; to be called with the spinlock held */ -static void it8708_set_carrier_params(struct ite_dev *dev, bool high_freq, - bool use_demodulator, - u8 carrier_freq_bits, u8 allowance_bits, - u8 pulse_width_bits) -{ - u8 val; - - ite_dbg("%s called", __func__); - - /* program the C0CFR register, with HRAE=1 */ - outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE, - dev->cir_addr + IT8708_BANKSEL); - - val = (inb(dev->cir_addr + IT8708_C0CFR) - & ~(IT85_HCFS | IT85_CFQ)) | carrier_freq_bits; - - if (high_freq) - val |= IT85_HCFS; - - outb(val, dev->cir_addr + IT8708_C0CFR); - - outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE, - dev->cir_addr + IT8708_BANKSEL); - - /* program the C0RCR register */ - val = inb(dev->cir_addr + IT8708_C0RCR) - & ~(IT85_RXEND | IT85_RXDCR); - - if (use_demodulator) - val |= IT85_RXEND; - - val |= allowance_bits; - - outb(val, dev->cir_addr + IT8708_C0RCR); - - /* program the C0TCR register */ - val = inb(dev->cir_addr + IT8708_C0TCR) & ~IT85_TXMPW; - val |= pulse_width_bits; - outb(val, dev->cir_addr + IT8708_C0TCR); -} - -/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock - * held */ -static int it8708_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) -{ - int fifo, read = 0; - - ite_dbg("%s called", __func__); - - /* read how many bytes are still in the FIFO */ - fifo = inb(dev->cir_addr + IT8708_C0RFSR) & IT85_RXFBC; - - while (fifo > 0 && buf_size > 0) { - *(buf++) = inb(dev->cir_addr + IT8708_C0DR); - fifo--; - read++; - buf_size--; - } - - return read; -} - -/* return how many bytes are still in the FIFO; this will be called - * with the device spinlock NOT HELD while waiting for the TX FIFO to get - * empty; let's expect this won't be a problem */ -static int it8708_get_tx_used_slots(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - return inb(dev->cir_addr + IT8708_C0TFSR) & IT85_TXFBC; -} - -/* put a byte to the TX fifo; this should be called with the spinlock held */ -static void it8708_put_tx_byte(struct ite_dev *dev, u8 value) -{ - outb(value, dev->cir_addr + IT8708_C0DR); -} - -/* idle the receiver so that we won't receive samples until another - pulse is detected; this must be called with the device spinlock held */ -static void it8708_idle_rx(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable streaming by clearing RXACT writing it as 1 */ - outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXACT, - dev->cir_addr + IT8708_C0RCR); - - /* clear the FIFO */ - outb(inb(dev->cir_addr + IT8708_C0MSTCR) | IT85_FIFOCLR, - dev->cir_addr + IT8708_C0MSTCR); -} - -/* disable the receiver; this must be called with the device spinlock held */ -static void it8708_disable_rx(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable the receiver interrupts */ - outb(inb(dev->cir_addr + IT8708_C0IER) & - ~(IT85_RDAIE | IT85_RFOIE), - dev->cir_addr + IT8708_C0IER); - - /* disable the receiver */ - outb(inb(dev->cir_addr + IT8708_C0RCR) & ~IT85_RXEN, - dev->cir_addr + IT8708_C0RCR); - - /* clear the FIFO and RXACT (actually RXACT should have been cleared - * in the previous outb() call) */ - it8708_idle_rx(dev); -} - -/* enable the receiver; this must be called with the device spinlock held */ -static void it8708_enable_rx(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* enable the receiver by setting RXEN */ - outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXEN, - dev->cir_addr + IT8708_C0RCR); - - /* just prepare it to idle for the next reception */ - it8708_idle_rx(dev); - - /* enable the receiver interrupts and master enable flag */ - outb(inb(dev->cir_addr + IT8708_C0IER) - |IT85_RDAIE | IT85_RFOIE | IT85_IEC, - dev->cir_addr + IT8708_C0IER); -} - -/* disable the transmitter interrupt; this must be called with the device - * spinlock held */ -static void it8708_disable_tx_interrupt(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable the transmitter interrupts */ - outb(inb(dev->cir_addr + IT8708_C0IER) & ~IT85_TLDLIE, - dev->cir_addr + IT8708_C0IER); -} - -/* enable the transmitter interrupt; this must be called with the device - * spinlock held */ -static void it8708_enable_tx_interrupt(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* enable the transmitter interrupts and master enable flag */ - outb(inb(dev->cir_addr + IT8708_C0IER) - |IT85_TLDLIE | IT85_IEC, - dev->cir_addr + IT8708_C0IER); -} - -/* disable the device; this must be called with the device spinlock held */ -static void it8708_disable(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* clear out all interrupt enable flags */ - outb(inb(dev->cir_addr + IT8708_C0IER) & - ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), - dev->cir_addr + IT8708_C0IER); - - /* disable the receiver */ - it8708_disable_rx(dev); - - /* erase the FIFO */ - outb(IT85_FIFOCLR | inb(dev->cir_addr + IT8708_C0MSTCR), - dev->cir_addr + IT8708_C0MSTCR); -} - -/* initialize the hardware */ -static void it8708_init_hardware(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable all the interrupts */ - outb(inb(dev->cir_addr + IT8708_C0IER) & - ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), - dev->cir_addr + IT8708_C0IER); - - /* program the baud rate divisor */ - outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE, - dev->cir_addr + IT8708_BANKSEL); - - outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT8708_C0BDLR); - outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff, - dev->cir_addr + IT8708_C0BDHR); - - outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE, - dev->cir_addr + IT8708_BANKSEL); - - /* program the C0MSTCR register defaults */ - outb((inb(dev->cir_addr + IT8708_C0MSTCR) & - ~(IT85_ILSEL | IT85_ILE | IT85_FIFOTL | - IT85_FIFOCLR | IT85_RESET)) | - IT85_FIFOTL_DEFAULT, - dev->cir_addr + IT8708_C0MSTCR); - - /* program the C0RCR register defaults */ - outb((inb(dev->cir_addr + IT8708_C0RCR) & - ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND | - IT85_RXACT | IT85_RXDCR)) | - ITE_RXDCR_DEFAULT, - dev->cir_addr + IT8708_C0RCR); - - /* program the C0TCR register defaults */ - outb((inb(dev->cir_addr + IT8708_C0TCR) & - ~(IT85_TXMPM | IT85_TXMPW)) - |IT85_TXRLE | IT85_TXENDF | - IT85_TXMPM_DEFAULT | IT85_TXMPW_DEFAULT, - dev->cir_addr + IT8708_C0TCR); - - /* program the carrier parameters */ - ite_set_carrier_params(dev); -} - -/* IT8512F on ITE8709 HW-specific functions */ - -/* read a byte from the SRAM module */ -static inline u8 it8709_rm(struct ite_dev *dev, int index) -{ - outb(index, dev->cir_addr + IT8709_RAM_IDX); - return inb(dev->cir_addr + IT8709_RAM_VAL); -} - -/* write a byte to the SRAM module */ -static inline void it8709_wm(struct ite_dev *dev, u8 val, int index) -{ - outb(index, dev->cir_addr + IT8709_RAM_IDX); - outb(val, dev->cir_addr + IT8709_RAM_VAL); -} - -static void it8709_wait(struct ite_dev *dev) -{ - int i = 0; - /* - * loop until device tells it's ready to continue - * iterations count is usually ~750 but can sometimes achieve 13000 - */ - for (i = 0; i < 15000; i++) { - udelay(2); - if (it8709_rm(dev, IT8709_MODE) == IT8709_IDLE) - break; - } -} - -/* read the value of a CIR register */ -static u8 it8709_rr(struct ite_dev *dev, int index) -{ - /* just wait in case the previous access was a write */ - it8709_wait(dev); - it8709_wm(dev, index, IT8709_REG_IDX); - it8709_wm(dev, IT8709_READ, IT8709_MODE); - - /* wait for the read data to be available */ - it8709_wait(dev); - - /* return the read value */ - return it8709_rm(dev, IT8709_REG_VAL); -} - -/* write the value of a CIR register */ -static void it8709_wr(struct ite_dev *dev, u8 val, int index) -{ - /* we wait before writing, and not afterwards, since this allows us to - * pipeline the host CPU with the microcontroller */ - it8709_wait(dev); - it8709_wm(dev, val, IT8709_REG_VAL); - it8709_wm(dev, index, IT8709_REG_IDX); - it8709_wm(dev, IT8709_WRITE, IT8709_MODE); -} - -/* retrieve a bitmask of the current causes for a pending interrupt; this may - * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN - * */ -static int it8709_get_irq_causes(struct ite_dev *dev) -{ - u8 iflags; - int ret = 0; - - ite_dbg("%s called", __func__); - - /* read the interrupt flags */ - iflags = it8709_rm(dev, IT8709_IIR); - - if (iflags & IT85_TLDLI) - ret |= ITE_IRQ_TX_FIFO; - if (iflags & IT85_RDAI) - ret |= ITE_IRQ_RX_FIFO; - if (iflags & IT85_RFOI) - ret |= ITE_IRQ_RX_FIFO_OVERRUN; - - return ret; -} - -/* set the carrier parameters; to be called with the spinlock held */ -static void it8709_set_carrier_params(struct ite_dev *dev, bool high_freq, - bool use_demodulator, - u8 carrier_freq_bits, u8 allowance_bits, - u8 pulse_width_bits) -{ - u8 val; - - ite_dbg("%s called", __func__); - - val = (it8709_rr(dev, IT85_C0CFR) - &~(IT85_HCFS | IT85_CFQ)) | - carrier_freq_bits; - - if (high_freq) - val |= IT85_HCFS; - - it8709_wr(dev, val, IT85_C0CFR); - - /* program the C0RCR register */ - val = it8709_rr(dev, IT85_C0RCR) - & ~(IT85_RXEND | IT85_RXDCR); - - if (use_demodulator) - val |= IT85_RXEND; - - val |= allowance_bits; - - it8709_wr(dev, val, IT85_C0RCR); - - /* program the C0TCR register */ - val = it8709_rr(dev, IT85_C0TCR) & ~IT85_TXMPW; - val |= pulse_width_bits; - it8709_wr(dev, val, IT85_C0TCR); -} - -/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock - * held */ -static int it8709_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) -{ - int fifo, read = 0; - - ite_dbg("%s called", __func__); - - /* read how many bytes are still in the FIFO */ - fifo = it8709_rm(dev, IT8709_RFSR) & IT85_RXFBC; - - while (fifo > 0 && buf_size > 0) { - *(buf++) = it8709_rm(dev, IT8709_FIFO + read); - fifo--; - read++; - buf_size--; - } - - /* 'clear' the FIFO by setting the writing index to 0; this is - * completely bound to be racy, but we can't help it, since it's a - * limitation of the protocol */ - it8709_wm(dev, 0, IT8709_RFSR); - - return read; -} - -/* return how many bytes are still in the FIFO; this will be called - * with the device spinlock NOT HELD while waiting for the TX FIFO to get - * empty; let's expect this won't be a problem */ -static int it8709_get_tx_used_slots(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - return it8709_rr(dev, IT85_C0TFSR) & IT85_TXFBC; -} - -/* put a byte to the TX fifo; this should be called with the spinlock held */ -static void it8709_put_tx_byte(struct ite_dev *dev, u8 value) -{ - it8709_wr(dev, value, IT85_C0DR); -} - -/* idle the receiver so that we won't receive samples until another - pulse is detected; this must be called with the device spinlock held */ -static void it8709_idle_rx(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable streaming by clearing RXACT writing it as 1 */ - it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXACT, - IT85_C0RCR); - - /* clear the FIFO */ - it8709_wr(dev, it8709_rr(dev, IT85_C0MSTCR) | IT85_FIFOCLR, - IT85_C0MSTCR); -} - -/* disable the receiver; this must be called with the device spinlock held */ -static void it8709_disable_rx(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable the receiver interrupts */ - it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & - ~(IT85_RDAIE | IT85_RFOIE), - IT85_C0IER); - - /* disable the receiver */ - it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) & ~IT85_RXEN, - IT85_C0RCR); - - /* clear the FIFO and RXACT (actually RXACT should have been cleared - * in the previous it8709_wr(dev, ) call) */ - it8709_idle_rx(dev); -} - -/* enable the receiver; this must be called with the device spinlock held */ -static void it8709_enable_rx(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* enable the receiver by setting RXEN */ - it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXEN, - IT85_C0RCR); - - /* just prepare it to idle for the next reception */ - it8709_idle_rx(dev); - - /* enable the receiver interrupts and master enable flag */ - it8709_wr(dev, it8709_rr(dev, IT85_C0IER) - |IT85_RDAIE | IT85_RFOIE | IT85_IEC, - IT85_C0IER); -} - -/* disable the transmitter interrupt; this must be called with the device - * spinlock held */ -static void it8709_disable_tx_interrupt(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable the transmitter interrupts */ - it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & ~IT85_TLDLIE, - IT85_C0IER); -} - -/* enable the transmitter interrupt; this must be called with the device - * spinlock held */ -static void it8709_enable_tx_interrupt(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* enable the transmitter interrupts and master enable flag */ - it8709_wr(dev, it8709_rr(dev, IT85_C0IER) - |IT85_TLDLIE | IT85_IEC, - IT85_C0IER); -} - -/* disable the device; this must be called with the device spinlock held */ -static void it8709_disable(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* clear out all interrupt enable flags */ - it8709_wr(dev, - it8709_rr(dev, - IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE | - IT85_RDAIE | - IT85_TLDLIE), IT85_C0IER); - - /* disable the receiver */ - it8709_disable_rx(dev); - - /* erase the FIFO */ - it8709_wr(dev, IT85_FIFOCLR | it8709_rr(dev, IT85_C0MSTCR), - IT85_C0MSTCR); -} - -/* initialize the hardware */ -static void it8709_init_hardware(struct ite_dev *dev) -{ - ite_dbg("%s called", __func__); - - /* disable all the interrupts */ - it8709_wr(dev, - it8709_rr(dev, - IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE | - IT85_RDAIE | - IT85_TLDLIE), IT85_C0IER); - - /* program the baud rate divisor */ - it8709_wr(dev, ITE_BAUDRATE_DIVISOR & 0xff, IT85_C0BDLR); - it8709_wr(dev, (ITE_BAUDRATE_DIVISOR >> 8) & 0xff, - IT85_C0BDHR); - - /* program the C0MSTCR register defaults */ - it8709_wr(dev, (it8709_rr(dev, IT85_C0MSTCR) & ~(IT85_ILSEL | - IT85_ILE - | IT85_FIFOTL - | - IT85_FIFOCLR - | - IT85_RESET)) - | IT85_FIFOTL_DEFAULT, IT85_C0MSTCR); - - /* program the C0RCR register defaults */ - it8709_wr(dev, - (it8709_rr(dev, IT85_C0RCR) & - ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND - | IT85_RXACT | IT85_RXDCR)) | - ITE_RXDCR_DEFAULT, IT85_C0RCR); - - /* program the C0TCR register defaults */ - it8709_wr(dev, (it8709_rr(dev, IT85_C0TCR) - &~(IT85_TXMPM | IT85_TXMPW)) - |IT85_TXRLE | IT85_TXENDF | - IT85_TXMPM_DEFAULT | - IT85_TXMPW_DEFAULT, IT85_C0TCR); - - /* program the carrier parameters */ - ite_set_carrier_params(dev); -} - - -/* generic hardware setup/teardown code */ - -/* activate the device for use */ -static int ite_open(struct rc_dev *rcdev) -{ - struct ite_dev *dev = rcdev->priv; - unsigned long flags; - - ite_dbg("%s called", __func__); - - spin_lock_irqsave(&dev->lock, flags); - dev->in_use = true; - - /* enable the receiver */ - dev->params.enable_rx(dev); - - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/* deactivate the device for use */ -static void ite_close(struct rc_dev *rcdev) -{ - struct ite_dev *dev = rcdev->priv; - unsigned long flags; - - ite_dbg("%s called", __func__); - - spin_lock_irqsave(&dev->lock, flags); - dev->in_use = false; - - /* wait for any transmission to end */ - spin_unlock_irqrestore(&dev->lock, flags); - wait_event_interruptible(dev->tx_ended, !dev->transmitting); - spin_lock_irqsave(&dev->lock, flags); - - dev->params.disable(dev); - - spin_unlock_irqrestore(&dev->lock, flags); -} - -/* supported models and their parameters */ -static const struct ite_dev_params ite_dev_descs[] = { - { /* 0: ITE8704 */ - .model = "ITE8704 CIR transceiver", - .io_region_size = IT87_IOREG_LENGTH, - .hw_tx_capable = true, - .sample_period = (u32) (1000000000ULL / 115200), - .tx_carrier_freq = 38000, - .tx_duty_cycle = 33, - .rx_low_carrier_freq = 0, - .rx_high_carrier_freq = 0, - - /* operations */ - .get_irq_causes = it87_get_irq_causes, - .enable_rx = it87_enable_rx, - .idle_rx = it87_idle_rx, - .disable_rx = it87_idle_rx, - .get_rx_bytes = it87_get_rx_bytes, - .enable_tx_interrupt = it87_enable_tx_interrupt, - .disable_tx_interrupt = it87_disable_tx_interrupt, - .get_tx_used_slots = it87_get_tx_used_slots, - .put_tx_byte = it87_put_tx_byte, - .disable = it87_disable, - .init_hardware = it87_init_hardware, - .set_carrier_params = it87_set_carrier_params, - }, - { /* 1: ITE8713 */ - .model = "ITE8713 CIR transceiver", - .io_region_size = IT87_IOREG_LENGTH, - .hw_tx_capable = true, - .sample_period = (u32) (1000000000ULL / 115200), - .tx_carrier_freq = 38000, - .tx_duty_cycle = 33, - .rx_low_carrier_freq = 0, - .rx_high_carrier_freq = 0, - - /* operations */ - .get_irq_causes = it87_get_irq_causes, - .enable_rx = it87_enable_rx, - .idle_rx = it87_idle_rx, - .disable_rx = it87_idle_rx, - .get_rx_bytes = it87_get_rx_bytes, - .enable_tx_interrupt = it87_enable_tx_interrupt, - .disable_tx_interrupt = it87_disable_tx_interrupt, - .get_tx_used_slots = it87_get_tx_used_slots, - .put_tx_byte = it87_put_tx_byte, - .disable = it87_disable, - .init_hardware = it87_init_hardware, - .set_carrier_params = it87_set_carrier_params, - }, - { /* 2: ITE8708 */ - .model = "ITE8708 CIR transceiver", - .io_region_size = IT8708_IOREG_LENGTH, - .hw_tx_capable = true, - .sample_period = (u32) (1000000000ULL / 115200), - .tx_carrier_freq = 38000, - .tx_duty_cycle = 33, - .rx_low_carrier_freq = 0, - .rx_high_carrier_freq = 0, - - /* operations */ - .get_irq_causes = it8708_get_irq_causes, - .enable_rx = it8708_enable_rx, - .idle_rx = it8708_idle_rx, - .disable_rx = it8708_idle_rx, - .get_rx_bytes = it8708_get_rx_bytes, - .enable_tx_interrupt = it8708_enable_tx_interrupt, - .disable_tx_interrupt = - it8708_disable_tx_interrupt, - .get_tx_used_slots = it8708_get_tx_used_slots, - .put_tx_byte = it8708_put_tx_byte, - .disable = it8708_disable, - .init_hardware = it8708_init_hardware, - .set_carrier_params = it8708_set_carrier_params, - }, - { /* 3: ITE8709 */ - .model = "ITE8709 CIR transceiver", - .io_region_size = IT8709_IOREG_LENGTH, - .hw_tx_capable = true, - .sample_period = (u32) (1000000000ULL / 115200), - .tx_carrier_freq = 38000, - .tx_duty_cycle = 33, - .rx_low_carrier_freq = 0, - .rx_high_carrier_freq = 0, - - /* operations */ - .get_irq_causes = it8709_get_irq_causes, - .enable_rx = it8709_enable_rx, - .idle_rx = it8709_idle_rx, - .disable_rx = it8709_idle_rx, - .get_rx_bytes = it8709_get_rx_bytes, - .enable_tx_interrupt = it8709_enable_tx_interrupt, - .disable_tx_interrupt = - it8709_disable_tx_interrupt, - .get_tx_used_slots = it8709_get_tx_used_slots, - .put_tx_byte = it8709_put_tx_byte, - .disable = it8709_disable, - .init_hardware = it8709_init_hardware, - .set_carrier_params = it8709_set_carrier_params, - }, -}; - -static const struct pnp_device_id ite_ids[] = { - {"ITE8704", 0}, /* Default model */ - {"ITE8713", 1}, /* CIR found in EEEBox 1501U */ - {"ITE8708", 2}, /* Bridged IT8512 */ - {"ITE8709", 3}, /* SRAM-Bridged IT8512 */ - {"", 0}, -}; - -/* allocate memory, probe hardware, and initialize everything */ -static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id - *dev_id) -{ - const struct ite_dev_params *dev_desc = NULL; - struct ite_dev *itdev = NULL; - struct rc_dev *rdev = NULL; - int ret = -ENOMEM; - int model_no; - - ite_dbg("%s called", __func__); - - itdev = kzalloc(sizeof(struct ite_dev), GFP_KERNEL); - if (!itdev) - return ret; - - /* input device for IR remote (and tx) */ - rdev = rc_allocate_device(); - if (!rdev) - goto failure; - - ret = -ENODEV; - - /* get the model number */ - model_no = (int)dev_id->driver_data; - ite_pr(KERN_NOTICE, "Auto-detected model: %s\n", - ite_dev_descs[model_no].model); - - if (model_number >= 0 && model_number < ARRAY_SIZE(ite_dev_descs)) { - model_no = model_number; - ite_pr(KERN_NOTICE, "The model has been fixed by a module " - "parameter."); - } - - ite_pr(KERN_NOTICE, "Using model: %s\n", ite_dev_descs[model_no].model); - - /* get the description for the device */ - dev_desc = &ite_dev_descs[model_no]; - - /* validate pnp resources */ - if (!pnp_port_valid(pdev, 0) || - pnp_port_len(pdev, 0) != dev_desc->io_region_size) { - dev_err(&pdev->dev, "IR PNP Port not valid!\n"); - goto failure; - } - - if (!pnp_irq_valid(pdev, 0)) { - dev_err(&pdev->dev, "PNP IRQ not valid!\n"); - goto failure; - } - - /* store resource values */ - itdev->cir_addr = pnp_port_start(pdev, 0); - itdev->cir_irq = pnp_irq(pdev, 0); - - /* initialize spinlocks */ - spin_lock_init(&itdev->lock); - - /* initialize raw event */ - init_ir_raw_event(&itdev->rawir); - - ret = -EBUSY; - /* now claim resources */ - if (!request_region(itdev->cir_addr, - dev_desc->io_region_size, ITE_DRIVER_NAME)) - goto failure; - - if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED, - ITE_DRIVER_NAME, (void *)itdev)) - goto failure; - - /* set driver data into the pnp device */ - pnp_set_drvdata(pdev, itdev); - itdev->pdev = pdev; - - /* initialize waitqueues for transmission */ - init_waitqueue_head(&itdev->tx_queue); - init_waitqueue_head(&itdev->tx_ended); - - /* copy model-specific parameters */ - itdev->params = *dev_desc; - - /* apply any overrides */ - if (sample_period > 0) - itdev->params.sample_period = sample_period; - - if (tx_carrier_freq > 0) - itdev->params.tx_carrier_freq = tx_carrier_freq; - - if (tx_duty_cycle > 0 && tx_duty_cycle <= 100) - itdev->params.tx_duty_cycle = tx_duty_cycle; - - if (rx_low_carrier_freq > 0) - itdev->params.rx_low_carrier_freq = rx_low_carrier_freq; - - if (rx_high_carrier_freq > 0) - itdev->params.rx_high_carrier_freq = rx_high_carrier_freq; - - /* print out parameters */ - ite_pr(KERN_NOTICE, "TX-capable: %d\n", (int) - itdev->params.hw_tx_capable); - ite_pr(KERN_NOTICE, "Sample period (ns): %ld\n", (long) - itdev->params.sample_period); - ite_pr(KERN_NOTICE, "TX carrier frequency (Hz): %d\n", (int) - itdev->params.tx_carrier_freq); - ite_pr(KERN_NOTICE, "TX duty cycle (%%): %d\n", (int) - itdev->params.tx_duty_cycle); - ite_pr(KERN_NOTICE, "RX low carrier frequency (Hz): %d\n", (int) - itdev->params.rx_low_carrier_freq); - ite_pr(KERN_NOTICE, "RX high carrier frequency (Hz): %d\n", (int) - itdev->params.rx_high_carrier_freq); - - /* set up hardware initial state */ - itdev->params.init_hardware(itdev); - - /* set up ir-core props */ - rdev->priv = itdev; - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; - rdev->open = ite_open; - rdev->close = ite_close; - rdev->s_idle = ite_s_idle; - rdev->s_rx_carrier_range = ite_set_rx_carrier_range; - rdev->min_timeout = ITE_MIN_IDLE_TIMEOUT; - rdev->max_timeout = ITE_MAX_IDLE_TIMEOUT; - rdev->timeout = ITE_IDLE_TIMEOUT; - rdev->rx_resolution = ITE_BAUDRATE_DIVISOR * - itdev->params.sample_period; - rdev->tx_resolution = ITE_BAUDRATE_DIVISOR * - itdev->params.sample_period; - - /* set up transmitter related values if needed */ - if (itdev->params.hw_tx_capable) { - rdev->tx_ir = ite_tx_ir; - rdev->s_tx_carrier = ite_set_tx_carrier; - rdev->s_tx_duty_cycle = ite_set_tx_duty_cycle; - } - - rdev->input_name = dev_desc->model; - rdev->input_id.bustype = BUS_HOST; - rdev->input_id.vendor = PCI_VENDOR_ID_ITE; - rdev->input_id.product = 0; - rdev->input_id.version = 0; - rdev->driver_name = ITE_DRIVER_NAME; - rdev->map_name = RC_MAP_RC6_MCE; - - ret = rc_register_device(rdev); - if (ret) - goto failure; - - itdev->rdev = rdev; - ite_pr(KERN_NOTICE, "driver has been successfully loaded\n"); - - return 0; - -failure: - if (itdev->cir_irq) - free_irq(itdev->cir_irq, itdev); - - if (itdev->cir_addr) - release_region(itdev->cir_addr, itdev->params.io_region_size); - - rc_free_device(rdev); - kfree(itdev); - - return ret; -} - -static void __devexit ite_remove(struct pnp_dev *pdev) -{ - struct ite_dev *dev = pnp_get_drvdata(pdev); - unsigned long flags; - - ite_dbg("%s called", __func__); - - spin_lock_irqsave(&dev->lock, flags); - - /* disable hardware */ - dev->params.disable(dev); - - spin_unlock_irqrestore(&dev->lock, flags); - - /* free resources */ - free_irq(dev->cir_irq, dev); - release_region(dev->cir_addr, dev->params.io_region_size); - - rc_unregister_device(dev->rdev); - - kfree(dev); -} - -static int ite_suspend(struct pnp_dev *pdev, pm_message_t state) -{ - struct ite_dev *dev = pnp_get_drvdata(pdev); - unsigned long flags; - - ite_dbg("%s called", __func__); - - spin_lock_irqsave(&dev->lock, flags); - - /* disable all interrupts */ - dev->params.disable(dev); - - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -static int ite_resume(struct pnp_dev *pdev) -{ - int ret = 0; - struct ite_dev *dev = pnp_get_drvdata(pdev); - unsigned long flags; - - ite_dbg("%s called", __func__); - - spin_lock_irqsave(&dev->lock, flags); - - if (dev->transmitting) { - /* wake up the transmitter */ - wake_up_interruptible(&dev->tx_queue); - } else { - /* enable the receiver */ - dev->params.enable_rx(dev); - } - - spin_unlock_irqrestore(&dev->lock, flags); - - return ret; -} - -static void ite_shutdown(struct pnp_dev *pdev) -{ - struct ite_dev *dev = pnp_get_drvdata(pdev); - unsigned long flags; - - ite_dbg("%s called", __func__); - - spin_lock_irqsave(&dev->lock, flags); - - /* disable all interrupts */ - dev->params.disable(dev); - - spin_unlock_irqrestore(&dev->lock, flags); -} - -static struct pnp_driver ite_driver = { - .name = ITE_DRIVER_NAME, - .id_table = ite_ids, - .probe = ite_probe, - .remove = __devexit_p(ite_remove), - .suspend = ite_suspend, - .resume = ite_resume, - .shutdown = ite_shutdown, -}; - -int ite_init(void) -{ - return pnp_register_driver(&ite_driver); -} - -void ite_exit(void) -{ - pnp_unregister_driver(&ite_driver); -} - -MODULE_DEVICE_TABLE(pnp, ite_ids); -MODULE_DESCRIPTION("ITE Tech Inc. IT8712F/ITE8512F CIR driver"); - -MODULE_AUTHOR("Juan J. Garcia de Soria "); -MODULE_LICENSE("GPL"); - -module_init(ite_init); -module_exit(ite_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ite-cir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ite-cir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ite-cir.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/ite-cir.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,481 +0,0 @@ -/* - * Driver for ITE Tech Inc. IT8712F/IT8512F CIR - * - * Copyright (C) 2010 Juan Jesús García de Soria - * - * 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, or (at your option) any later version. - * - * 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. - */ - -/* platform driver name to register */ -#define ITE_DRIVER_NAME "ite-cir" - -/* logging macros */ -#define ite_pr(level, text, ...) \ - printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) -#define ite_dbg(text, ...) do { \ - if (debug) \ - printk(KERN_DEBUG \ - KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \ -} while (0) - -#define ite_dbg_verbose(text, ...) do {\ - if (debug > 1) \ - printk(KERN_DEBUG \ - KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \ -} while (0) - -/* FIFO sizes */ -#define ITE_TX_FIFO_LEN 32 -#define ITE_RX_FIFO_LEN 32 - -/* interrupt types */ -#define ITE_IRQ_TX_FIFO 1 -#define ITE_IRQ_RX_FIFO 2 -#define ITE_IRQ_RX_FIFO_OVERRUN 4 - -/* forward declaration */ -struct ite_dev; - -/* struct for storing the parameters of different recognized devices */ -struct ite_dev_params { - /* model of the device */ - const char *model; - - /* size of the I/O region */ - int io_region_size; - - /* true if the hardware supports transmission */ - bool hw_tx_capable; - - /* base sampling period, in ns */ - u32 sample_period; - - /* rx low carrier frequency, in Hz, 0 means no demodulation */ - unsigned int rx_low_carrier_freq; - - /* tx high carrier frequency, in Hz, 0 means no demodulation */ - unsigned int rx_high_carrier_freq; - - /* tx carrier frequency, in Hz */ - unsigned int tx_carrier_freq; - - /* duty cycle, 0-100 */ - int tx_duty_cycle; - - /* hw-specific operation function pointers; most of these must be - * called while holding the spin lock, except for the TX FIFO length - * one */ - /* get pending interrupt causes */ - int (*get_irq_causes) (struct ite_dev *dev); - - /* enable rx */ - void (*enable_rx) (struct ite_dev *dev); - - /* make rx enter the idle state; keep listening for a pulse, but stop - * streaming space bytes */ - void (*idle_rx) (struct ite_dev *dev); - - /* disable rx completely */ - void (*disable_rx) (struct ite_dev *dev); - - /* read bytes from RX FIFO; return read count */ - int (*get_rx_bytes) (struct ite_dev *dev, u8 *buf, int buf_size); - - /* enable tx FIFO space available interrupt */ - void (*enable_tx_interrupt) (struct ite_dev *dev); - - /* disable tx FIFO space available interrupt */ - void (*disable_tx_interrupt) (struct ite_dev *dev); - - /* get number of full TX FIFO slots */ - int (*get_tx_used_slots) (struct ite_dev *dev); - - /* put a byte to the TX FIFO */ - void (*put_tx_byte) (struct ite_dev *dev, u8 value); - - /* disable hardware completely */ - void (*disable) (struct ite_dev *dev); - - /* initialize the hardware */ - void (*init_hardware) (struct ite_dev *dev); - - /* set the carrier parameters */ - void (*set_carrier_params) (struct ite_dev *dev, bool high_freq, - bool use_demodulator, u8 carrier_freq_bits, - u8 allowance_bits, u8 pulse_width_bits); -}; - -/* ITE CIR device structure */ -struct ite_dev { - struct pnp_dev *pdev; - struct rc_dev *rdev; - struct ir_raw_event rawir; - - /* sync data */ - spinlock_t lock; - bool in_use, transmitting; - - /* transmit support */ - int tx_fifo_allowance; - wait_queue_head_t tx_queue, tx_ended; - - /* hardware I/O settings */ - unsigned long cir_addr; - int cir_irq; - - /* overridable copy of model parameters */ - struct ite_dev_params params; -}; - -/* common values for all kinds of hardware */ - -/* baud rate divisor default */ -#define ITE_BAUDRATE_DIVISOR 1 - -/* low-speed carrier frequency limits (Hz) */ -#define ITE_LCF_MIN_CARRIER_FREQ 27000 -#define ITE_LCF_MAX_CARRIER_FREQ 58000 - -/* high-speed carrier frequency limits (Hz) */ -#define ITE_HCF_MIN_CARRIER_FREQ 400000 -#define ITE_HCF_MAX_CARRIER_FREQ 500000 - -/* default carrier freq for when demodulator is off (Hz) */ -#define ITE_DEFAULT_CARRIER_FREQ 38000 - -/* default idling timeout in ns (0.2 seconds) */ -#define ITE_IDLE_TIMEOUT 200000000UL - -/* limit timeout values */ -#define ITE_MIN_IDLE_TIMEOUT 100000000UL -#define ITE_MAX_IDLE_TIMEOUT 1000000000UL - -/* convert bits to us */ -#define ITE_BITS_TO_NS(bits, sample_period) \ -((u32) ((bits) * ITE_BAUDRATE_DIVISOR * sample_period)) - -/* - * n in RDCR produces a tolerance of +/- n * 6.25% around the center - * carrier frequency... - * - * From two limit frequencies, L (low) and H (high), we can get both the - * center frequency F = (L + H) / 2 and the variation from the center - * frequency A = (H - L) / (H + L). We can use this in order to honor the - * s_rx_carrier_range() call in ir-core. We'll suppose that any request - * setting L=0 means we must shut down the demodulator. - */ -#define ITE_RXDCR_PER_10000_STEP 625 - -/* high speed carrier freq values */ -#define ITE_CFQ_400 0x03 -#define ITE_CFQ_450 0x08 -#define ITE_CFQ_480 0x0b -#define ITE_CFQ_500 0x0d - -/* values for pulse widths */ -#define ITE_TXMPW_A 0x02 -#define ITE_TXMPW_B 0x03 -#define ITE_TXMPW_C 0x04 -#define ITE_TXMPW_D 0x05 -#define ITE_TXMPW_E 0x06 - -/* values for demodulator carrier range allowance */ -#define ITE_RXDCR_DEFAULT 0x01 /* default carrier range */ -#define ITE_RXDCR_MAX 0x07 /* default carrier range */ - -/* DR TX bits */ -#define ITE_TX_PULSE 0x00 -#define ITE_TX_SPACE 0x80 -#define ITE_TX_MAX_RLE 0x80 -#define ITE_TX_RLE_MASK 0x7f - -/* - * IT8712F - * - * hardware data obtained from: - * - * IT8712F - * Environment Control – Low Pin Count Input / Output - * (EC - LPC I/O) - * Preliminary Specification V0. 81 - */ - -/* register offsets */ -#define IT87_DR 0x00 /* data register */ -#define IT87_IER 0x01 /* interrupt enable register */ -#define IT87_RCR 0x02 /* receiver control register */ -#define IT87_TCR1 0x03 /* transmitter control register 1 */ -#define IT87_TCR2 0x04 /* transmitter control register 2 */ -#define IT87_TSR 0x05 /* transmitter status register */ -#define IT87_RSR 0x06 /* receiver status register */ -#define IT87_BDLR 0x05 /* baud rate divisor low byte register */ -#define IT87_BDHR 0x06 /* baud rate divisor high byte register */ -#define IT87_IIR 0x07 /* interrupt identification register */ - -#define IT87_IOREG_LENGTH 0x08 /* length of register file */ - -/* IER bits */ -#define IT87_TLDLIE 0x01 /* transmitter low data interrupt enable */ -#define IT87_RDAIE 0x02 /* receiver data available interrupt enable */ -#define IT87_RFOIE 0x04 /* receiver FIFO overrun interrupt enable */ -#define IT87_IEC 0x08 /* interrupt enable control */ -#define IT87_BR 0x10 /* baud rate register enable */ -#define IT87_RESET 0x20 /* reset */ - -/* RCR bits */ -#define IT87_RXDCR 0x07 /* receiver demodulation carrier range mask */ -#define IT87_RXACT 0x08 /* receiver active */ -#define IT87_RXEND 0x10 /* receiver demodulation enable */ -#define IT87_RXEN 0x20 /* receiver enable */ -#define IT87_HCFS 0x40 /* high-speed carrier frequency select */ -#define IT87_RDWOS 0x80 /* receiver data without sync */ - -/* TCR1 bits */ -#define IT87_TXMPM 0x03 /* transmitter modulation pulse mode mask */ -#define IT87_TXMPM_DEFAULT 0x00 /* modulation pulse mode default */ -#define IT87_TXENDF 0x04 /* transmitter deferral */ -#define IT87_TXRLE 0x08 /* transmitter run length enable */ -#define IT87_FIFOTL 0x30 /* FIFO level threshold mask */ -#define IT87_FIFOTL_DEFAULT 0x20 /* FIFO level threshold default - * 0x00 -> 1, 0x10 -> 7, 0x20 -> 17, - * 0x30 -> 25 */ -#define IT87_ILE 0x40 /* internal loopback enable */ -#define IT87_FIFOCLR 0x80 /* FIFO clear bit */ - -/* TCR2 bits */ -#define IT87_TXMPW 0x07 /* transmitter modulation pulse width mask */ -#define IT87_TXMPW_DEFAULT 0x04 /* default modulation pulse width */ -#define IT87_CFQ 0xf8 /* carrier frequency mask */ -#define IT87_CFQ_SHIFT 3 /* carrier frequency bit shift */ - -/* TSR bits */ -#define IT87_TXFBC 0x3f /* transmitter FIFO byte count mask */ - -/* RSR bits */ -#define IT87_RXFBC 0x3f /* receiver FIFO byte count mask */ -#define IT87_RXFTO 0x80 /* receiver FIFO time-out */ - -/* IIR bits */ -#define IT87_IP 0x01 /* interrupt pending */ -#define IT87_II 0x06 /* interrupt identification mask */ -#define IT87_II_NOINT 0x00 /* no interrupt */ -#define IT87_II_TXLDL 0x02 /* transmitter low data level */ -#define IT87_II_RXDS 0x04 /* receiver data stored */ -#define IT87_II_RXFO 0x06 /* receiver FIFO overrun */ - -/* - * IT8512E/F - * - * Hardware data obtained from: - * - * IT8512E/F - * Embedded Controller - * Preliminary Specification V0.4.1 - * - * Note that the CIR registers are not directly available to the host, because - * they only are accessible to the integrated microcontroller. Thus, in order - * use it, some kind of bridging is required. As the bridging may depend on - * the controller firmware in use, we are going to use the PNP ID in order to - * determine the strategy and ports available. See after these generic - * IT8512E/F register definitions for register definitions for those - * strategies. - */ - -/* register offsets */ -#define IT85_C0DR 0x00 /* data register */ -#define IT85_C0MSTCR 0x01 /* master control register */ -#define IT85_C0IER 0x02 /* interrupt enable register */ -#define IT85_C0IIR 0x03 /* interrupt identification register */ -#define IT85_C0CFR 0x04 /* carrier frequency register */ -#define IT85_C0RCR 0x05 /* receiver control register */ -#define IT85_C0TCR 0x06 /* transmitter control register */ -#define IT85_C0SCK 0x07 /* slow clock control register */ -#define IT85_C0BDLR 0x08 /* baud rate divisor low byte register */ -#define IT85_C0BDHR 0x09 /* baud rate divisor high byte register */ -#define IT85_C0TFSR 0x0a /* transmitter FIFO status register */ -#define IT85_C0RFSR 0x0b /* receiver FIFO status register */ -#define IT85_C0WCL 0x0d /* wakeup code length register */ -#define IT85_C0WCR 0x0e /* wakeup code read/write register */ -#define IT85_C0WPS 0x0f /* wakeup power control/status register */ - -#define IT85_IOREG_LENGTH 0x10 /* length of register file */ - -/* C0MSTCR bits */ -#define IT85_RESET 0x01 /* reset */ -#define IT85_FIFOCLR 0x02 /* FIFO clear bit */ -#define IT85_FIFOTL 0x0c /* FIFO level threshold mask */ -#define IT85_FIFOTL_DEFAULT 0x08 /* FIFO level threshold default - * 0x00 -> 1, 0x04 -> 7, 0x08 -> 17, - * 0x0c -> 25 */ -#define IT85_ILE 0x10 /* internal loopback enable */ -#define IT85_ILSEL 0x20 /* internal loopback select */ - -/* C0IER bits */ -#define IT85_TLDLIE 0x01 /* TX low data level interrupt enable */ -#define IT85_RDAIE 0x02 /* RX data available interrupt enable */ -#define IT85_RFOIE 0x04 /* RX FIFO overrun interrupt enable */ -#define IT85_IEC 0x80 /* interrupt enable function control */ - -/* C0IIR bits */ -#define IT85_TLDLI 0x01 /* transmitter low data level interrupt */ -#define IT85_RDAI 0x02 /* receiver data available interrupt */ -#define IT85_RFOI 0x04 /* receiver FIFO overrun interrupt */ -#define IT85_NIP 0x80 /* no interrupt pending */ - -/* C0CFR bits */ -#define IT85_CFQ 0x1f /* carrier frequency mask */ -#define IT85_HCFS 0x20 /* high speed carrier frequency select */ - -/* C0RCR bits */ -#define IT85_RXDCR 0x07 /* receiver demodulation carrier range mask */ -#define IT85_RXACT 0x08 /* receiver active */ -#define IT85_RXEND 0x10 /* receiver demodulation enable */ -#define IT85_RDWOS 0x20 /* receiver data without sync */ -#define IT85_RXEN 0x80 /* receiver enable */ - -/* C0TCR bits */ -#define IT85_TXMPW 0x07 /* transmitter modulation pulse width mask */ -#define IT85_TXMPW_DEFAULT 0x04 /* default modulation pulse width */ -#define IT85_TXMPM 0x18 /* transmitter modulation pulse mode mask */ -#define IT85_TXMPM_DEFAULT 0x00 /* modulation pulse mode default */ -#define IT85_TXENDF 0x20 /* transmitter deferral */ -#define IT85_TXRLE 0x40 /* transmitter run length enable */ - -/* C0SCK bits */ -#define IT85_SCKS 0x01 /* slow clock select */ -#define IT85_TXDCKG 0x02 /* TXD clock gating */ -#define IT85_DLL1P8E 0x04 /* DLL 1.8432M enable */ -#define IT85_DLLTE 0x08 /* DLL test enable */ -#define IT85_BRCM 0x70 /* baud rate count mode */ -#define IT85_DLLOCK 0x80 /* DLL lock */ - -/* C0TFSR bits */ -#define IT85_TXFBC 0x3f /* transmitter FIFO count mask */ - -/* C0RFSR bits */ -#define IT85_RXFBC 0x3f /* receiver FIFO count mask */ -#define IT85_RXFTO 0x80 /* receiver FIFO time-out */ - -/* C0WCL bits */ -#define IT85_WCL 0x3f /* wakeup code length mask */ - -/* C0WPS bits */ -#define IT85_CIRPOSIE 0x01 /* power on/off status interrupt enable */ -#define IT85_CIRPOIS 0x02 /* power on/off interrupt status */ -#define IT85_CIRPOII 0x04 /* power on/off interrupt identification */ -#define IT85_RCRST 0x10 /* wakeup code reading counter reset bit */ -#define IT85_WCRST 0x20 /* wakeup code writing counter reset bit */ - -/* - * ITE8708 - * - * Hardware data obtained from hacked driver for IT8512 in this forum post: - * - * http://ubuntuforums.org/showthread.php?t=1028640 - * - * Although there's no official documentation for that driver, analysis would - * suggest that it maps the 16 registers of IT8512 onto two 8-register banks, - * selectable by a single bank-select bit that's mapped onto both banks. The - * IT8512 registers are mapped in a different order, so that the first bank - * maps the ones that are used more often, and two registers that share a - * reserved high-order bit are placed at the same offset in both banks in - * order to reuse the reserved bit as the bank select bit. - */ - -/* register offsets */ - -/* mapped onto both banks */ -#define IT8708_BANKSEL 0x07 /* bank select register */ -#define IT8708_HRAE 0x80 /* high registers access enable */ - -/* mapped onto the low bank */ -#define IT8708_C0DR 0x00 /* data register */ -#define IT8708_C0MSTCR 0x01 /* master control register */ -#define IT8708_C0IER 0x02 /* interrupt enable register */ -#define IT8708_C0IIR 0x03 /* interrupt identification register */ -#define IT8708_C0RFSR 0x04 /* receiver FIFO status register */ -#define IT8708_C0RCR 0x05 /* receiver control register */ -#define IT8708_C0TFSR 0x06 /* transmitter FIFO status register */ -#define IT8708_C0TCR 0x07 /* transmitter control register */ - -/* mapped onto the high bank */ -#define IT8708_C0BDLR 0x01 /* baud rate divisor low byte register */ -#define IT8708_C0BDHR 0x02 /* baud rate divisor high byte register */ -#define IT8708_C0CFR 0x04 /* carrier frequency register */ - -/* registers whose bank mapping we don't know, since they weren't being used - * in the hacked driver... most probably they belong to the high bank too, - * since they fit in the holes the other registers leave */ -#define IT8708_C0SCK 0x03 /* slow clock control register */ -#define IT8708_C0WCL 0x05 /* wakeup code length register */ -#define IT8708_C0WCR 0x06 /* wakeup code read/write register */ -#define IT8708_C0WPS 0x07 /* wakeup power control/status register */ - -#define IT8708_IOREG_LENGTH 0x08 /* length of register file */ - -/* two more registers that are defined in the hacked driver, but can't be - * found in the data sheets; no idea what they are or how they are accessed, - * since the hacked driver doesn't seem to use them */ -#define IT8708_CSCRR 0x00 -#define IT8708_CGPINTR 0x01 - -/* CSCRR bits */ -#define IT8708_CSCRR_SCRB 0x3f -#define IT8708_CSCRR_PM 0x80 - -/* CGPINTR bits */ -#define IT8708_CGPINT 0x01 - -/* - * ITE8709 - * - * Hardware interfacing data obtained from the original lirc_ite8709 driver. - * Verbatim from its sources: - * - * The ITE8709 device seems to be the combination of IT8512 superIO chip and - * a specific firmware running on the IT8512's embedded micro-controller. - * In addition of the embedded micro-controller, the IT8512 chip contains a - * CIR module and several other modules. A few modules are directly accessible - * by the host CPU, but most of them are only accessible by the - * micro-controller. The CIR module is only accessible by the - * micro-controller. - * - * The battery-backed SRAM module is accessible by the host CPU and the - * micro-controller. So one of the MC's firmware role is to act as a bridge - * between the host CPU and the CIR module. The firmware implements a kind of - * communication protocol using the SRAM module as a shared memory. The IT8512 - * specification is publicly available on ITE's web site, but the - * communication protocol is not, so it was reverse-engineered. - */ - -/* register offsets */ -#define IT8709_RAM_IDX 0x00 /* index into the SRAM module bytes */ -#define IT8709_RAM_VAL 0x01 /* read/write data to the indexed byte */ - -#define IT8709_IOREG_LENGTH 0x02 /* length of register file */ - -/* register offsets inside the SRAM module */ -#define IT8709_MODE 0x1a /* request/ack byte */ -#define IT8709_REG_IDX 0x1b /* index of the CIR register to access */ -#define IT8709_REG_VAL 0x1c /* value read/to be written */ -#define IT8709_IIR 0x1e /* interrupt identification register */ -#define IT8709_RFSR 0x1f /* receiver FIFO status register */ -#define IT8709_FIFO 0x20 /* start of in RAM RX FIFO copy */ - -/* MODE values */ -#define IT8709_IDLE 0x00 -#define IT8709_WRITE 0x01 -#define IT8709_READ 0x02 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,206 +0,0 @@ -menuconfig RC_CORE - tristate "Remote Controller adapters" - depends on INPUT - default INPUT - ---help--- - Enable support for Remote Controllers on Linux. This is - needed in order to support several video capture adapters. - Currently, all supported devices use InfraRed. - - Enable this option if you have a video capture board even - if you don't need IR, as otherwise, you may not be able to - compile the driver for your adapter. - -if RC_CORE - -config LIRC - tristate - default y - - ---help--- - Enable this option to build the Linux Infrared Remote - Control (LIRC) core device interface driver. The LIRC - interface passes raw IR to and from userspace, where the - LIRC daemon handles protocol decoding for IR reception and - encoding for IR transmitting (aka "blasting"). - -source "drivers/media/rc/keymaps/Kconfig" - -config IR_NEC_DECODER - tristate "Enable IR raw decoder for the NEC protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have IR with NEC protocol, and - if the IR is decoded in software - -config IR_RC5_DECODER - tristate "Enable IR raw decoder for the RC-5 protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have IR with RC-5 protocol, and - if the IR is decoded in software - -config IR_RC6_DECODER - tristate "Enable IR raw decoder for the RC6 protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have an infrared remote control which - uses the RC6 protocol, and you need software decoding support. - -config IR_JVC_DECODER - tristate "Enable IR raw decoder for the JVC protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have an infrared remote control which - uses the JVC protocol, and you need software decoding support. - -config IR_SONY_DECODER - tristate "Enable IR raw decoder for the Sony protocol" - depends on RC_CORE - default y - - ---help--- - Enable this option if you have an infrared remote control which - uses the Sony protocol, and you need software decoding support. - -config IR_RC5_SZ_DECODER - tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have IR with RC-5 (streamzap) protocol, - and if the IR is decoded in software. (The Streamzap PC Remote - uses an IR protocol that is almost standard RC-5, but not quite, - as it uses an additional bit). - -config IR_LIRC_CODEC - tristate "Enable IR to LIRC bridge" - depends on RC_CORE - depends on LIRC - default y - - ---help--- - Enable this option to pass raw IR to and from userspace via - the LIRC interface. - -config IR_ENE - tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)" - depends on PNP - depends on RC_CORE - ---help--- - Say Y here to enable support for integrated infrared receiver - /transceiver made by ENE. - - You can see if you have it by looking at lspnp output. - Output should include ENE0100 ENE0200 or something similar. - - To compile this driver as a module, choose M here: the - module will be called ene_ir. - -config IR_IMON - tristate "SoundGraph iMON Receiver and Display" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - ---help--- - Say Y here if you want to use a SoundGraph iMON (aka Antec Veris) - IR Receiver and/or LCD/VFD/VGA display. - - To compile this driver as a module, choose M here: the - module will be called imon. - -config IR_MCEUSB - tristate "Windows Media Center Ed. eHome Infrared Transceiver" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - ---help--- - Say Y here if you want to use a Windows Media Center Edition - eHome Infrared Transceiver. - - To compile this driver as a module, choose M here: the - module will be called mceusb. - -config IR_ITE_CIR - tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver" - depends on PNP - depends on RC_CORE - ---help--- - Say Y here to enable support for integrated infrared receivers - /transceivers made by ITE Tech Inc. These are found in - several ASUS devices, like the ASUS Digimatrix or the ASUS - EEEBox 1501U. - - To compile this driver as a module, choose M here: the - module will be called ite-cir. - -config IR_NUVOTON - tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" - depends on PNP - depends on RC_CORE - ---help--- - Say Y here to enable support for integrated infrared receiver - /transciever made by Nuvoton (formerly Winbond). This chip is - found in the ASRock ION 330HT, as well as assorted Intel - DP55-series motherboards (and of course, possibly others). - - To compile this driver as a module, choose M here: the - module will be called nuvoton-cir. - -config IR_STREAMZAP - tristate "Streamzap PC Remote IR Receiver" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - ---help--- - Say Y here if you want to use a Streamzap PC Remote - Infrared Receiver. - - To compile this driver as a module, choose M here: the - module will be called streamzap. - -config IR_WINBOND_CIR - tristate "Winbond IR remote control" - depends on X86 && PNP - depends on RC_CORE - select NEW_LEDS - select LEDS_CLASS - select LEDS_TRIGGERS - select BITREVERSE - ---help--- - Say Y here if you want to use the IR remote functionality found - in some Winbond SuperI/O chips. Currently only the WPCD376I - chip is supported (included in some Intel Media series - motherboards). - - To compile this driver as a module, choose M here: the module will - be called winbond_cir. - -config RC_LOOPBACK - tristate "Remote Control Loopback Driver" - depends on RC_CORE - ---help--- - Say Y here if you want support for the remote control loopback - driver which allows TX data to be sent back as RX data. - This is mostly useful for debugging purposes. - - If you're not sure, select N here. - - To compile this driver as a module, choose M here: the module will - be called rc_loopback. - -endif #RC_CORE diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -config RC_MAP - tristate "Compile Remote Controller keymap modules" - depends on RC_CORE - default y - - ---help--- - This option enables the compilation of lots of Remote - Controller tables. They are short tables, but if you - don't use a remote controller, or prefer to load the - tables on userspace, you should disable it. - - The ir-keytable program, available at v4l-utils package - provide the tool and the same RC maps for load from - userspace. Its available at - http://git.linuxtv.org/v4l-utils diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-alink-dtu-m.o \ - rc-anysee.o \ - rc-apac-viewcomp.o \ - rc-asus-pc39.o \ - rc-ati-tv-wonder-hd-600.o \ - rc-avermedia-a16d.o \ - rc-avermedia.o \ - rc-avermedia-cardbus.o \ - rc-avermedia-dvbt.o \ - rc-avermedia-m135a.o \ - rc-avermedia-m733a-rm-k6.o \ - rc-avermedia-rm-ks.o \ - rc-avertv-303.o \ - rc-azurewave-ad-tu700.o \ - rc-behold.o \ - rc-behold-columbus.o \ - rc-budget-ci-old.o \ - rc-cinergy-1400.o \ - rc-cinergy.o \ - rc-dib0700-nec.o \ - rc-dib0700-rc5.o \ - rc-digitalnow-tinytwin.o \ - rc-digittrade.o \ - rc-dm1105-nec.o \ - rc-dntv-live-dvb-t.o \ - rc-dntv-live-dvbt-pro.o \ - rc-em-terratec.o \ - rc-encore-enltv2.o \ - rc-encore-enltv.o \ - rc-encore-enltv-fm53.o \ - rc-evga-indtube.o \ - rc-eztv.o \ - rc-flydvb.o \ - rc-flyvideo.o \ - rc-fusionhdtv-mce.o \ - rc-gadmei-rm008z.o \ - rc-genius-tvgo-a11mce.o \ - rc-gotview7135.o \ - rc-imon-mce.o \ - rc-imon-pad.o \ - rc-iodata-bctv7e.o \ - rc-kaiomy.o \ - rc-kworld-315u.o \ - rc-kworld-plus-tv-analog.o \ - rc-leadtek-y04g0051.o \ - rc-lirc.o \ - rc-lme2510.o \ - rc-manli.o \ - rc-msi-digivox-ii.o \ - rc-msi-digivox-iii.o \ - rc-msi-tvanywhere.o \ - rc-msi-tvanywhere-plus.o \ - rc-nebula.o \ - rc-nec-terratec-cinergy-xs.o \ - rc-norwood.o \ - rc-npgtech.o \ - rc-pctv-sedna.o \ - rc-pinnacle-color.o \ - rc-pinnacle-grey.o \ - rc-pinnacle-pctv-hd.o \ - rc-pixelview.o \ - rc-pixelview-mk12.o \ - rc-pixelview-002t.o \ - rc-pixelview-new.o \ - rc-powercolor-real-angel.o \ - rc-proteus-2309.o \ - rc-purpletv.o \ - rc-pv951.o \ - rc-hauppauge.o \ - rc-rc6-mce.o \ - rc-real-audio-220-32-keys.o \ - rc-streamzap.o \ - rc-tbs-nec.o \ - rc-technisat-usb2.o \ - rc-terratec-cinergy-xs.o \ - rc-terratec-slim.o \ - rc-terratec-slim-2.o \ - rc-tevii-nec.o \ - rc-total-media-in-hand.o \ - rc-trekstor.o \ - rc-tt-1500.o \ - rc-twinhan1027.o \ - rc-videomate-m1f.o \ - rc-videomate-s350.o \ - rc-videomate-tv-pvr.o \ - rc-winfast.o \ - rc-winfast-usbii-deluxe.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -/* adstech-dvb-t-pci.h - Keytable for adstech_dvb_t_pci Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* ADS Tech Instant TV DVB-T PCI Remote */ - -static struct rc_map_table adstech_dvb_t_pci[] = { - /* Keys 0 to 9 */ - { 0x4d, KEY_0 }, - { 0x57, KEY_1 }, - { 0x4f, KEY_2 }, - { 0x53, KEY_3 }, - { 0x56, KEY_4 }, - { 0x4e, KEY_5 }, - { 0x5e, KEY_6 }, - { 0x54, KEY_7 }, - { 0x4c, KEY_8 }, - { 0x5c, KEY_9 }, - - { 0x5b, KEY_POWER }, - { 0x5f, KEY_MUTE }, - { 0x55, KEY_GOTO }, - { 0x5d, KEY_SEARCH }, - { 0x17, KEY_EPG }, /* Guide */ - { 0x1f, KEY_MENU }, - { 0x0f, KEY_UP }, - { 0x46, KEY_DOWN }, - { 0x16, KEY_LEFT }, - { 0x1e, KEY_RIGHT }, - { 0x0e, KEY_SELECT }, /* Enter */ - { 0x5a, KEY_INFO }, - { 0x52, KEY_EXIT }, - { 0x59, KEY_PREVIOUS }, - { 0x51, KEY_NEXT }, - { 0x58, KEY_REWIND }, - { 0x50, KEY_FORWARD }, - { 0x44, KEY_PLAYPAUSE }, - { 0x07, KEY_STOP }, - { 0x1b, KEY_RECORD }, - { 0x13, KEY_TUNER }, /* Live */ - { 0x0a, KEY_A }, - { 0x12, KEY_B }, - { 0x03, KEY_RED }, /* 1 */ - { 0x01, KEY_GREEN }, /* 2 */ - { 0x00, KEY_YELLOW }, /* 3 */ - { 0x06, KEY_DVD }, - { 0x48, KEY_AUX }, /* Photo */ - { 0x40, KEY_VIDEO }, - { 0x19, KEY_AUDIO }, /* Music */ - { 0x0b, KEY_CHANNELUP }, - { 0x08, KEY_CHANNELDOWN }, - { 0x15, KEY_VOLUMEUP }, - { 0x1c, KEY_VOLUMEDOWN }, -}; - -static struct rc_map_list adstech_dvb_t_pci_map = { - .map = { - .scan = adstech_dvb_t_pci, - .size = ARRAY_SIZE(adstech_dvb_t_pci), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ADSTECH_DVB_T_PCI, - } -}; - -static int __init init_rc_map_adstech_dvb_t_pci(void) -{ - return rc_map_register(&adstech_dvb_t_pci_map); -} - -static void __exit exit_rc_map_adstech_dvb_t_pci(void) -{ - rc_map_unregister(&adstech_dvb_t_pci_map); -} - -module_init(init_rc_map_adstech_dvb_t_pci) -module_exit(exit_rc_map_adstech_dvb_t_pci) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-alink-dtu-m.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-alink-dtu-m.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-alink-dtu-m.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-alink-dtu-m.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -/* - * A-Link DTU(m) remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -/* A-Link DTU(m) slim remote, 6 rows, 3 columns. */ -static struct rc_map_table alink_dtu_m[] = { - { 0x0800, KEY_VOLUMEUP }, - { 0x0801, KEY_1 }, - { 0x0802, KEY_3 }, - { 0x0803, KEY_7 }, - { 0x0804, KEY_9 }, - { 0x0805, KEY_NEW }, /* symbol: PIP */ - { 0x0806, KEY_0 }, - { 0x0807, KEY_CHANNEL }, /* JUMP */ - { 0x080d, KEY_5 }, - { 0x080f, KEY_2 }, - { 0x0812, KEY_POWER2 }, - { 0x0814, KEY_CHANNELUP }, - { 0x0816, KEY_VOLUMEDOWN }, - { 0x0818, KEY_6 }, - { 0x081a, KEY_MUTE }, - { 0x081b, KEY_8 }, - { 0x081c, KEY_4 }, - { 0x081d, KEY_CHANNELDOWN }, -}; - -static struct rc_map_list alink_dtu_m_map = { - .map = { - .scan = alink_dtu_m, - .size = ARRAY_SIZE(alink_dtu_m), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_ALINK_DTU_M, - } -}; - -static int __init init_rc_map_alink_dtu_m(void) -{ - return rc_map_register(&alink_dtu_m_map); -} - -static void __exit exit_rc_map_alink_dtu_m(void) -{ - rc_map_unregister(&alink_dtu_m_map); -} - -module_init(init_rc_map_alink_dtu_m) -module_exit(exit_rc_map_alink_dtu_m) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-anysee.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-anysee.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-anysee.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-anysee.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/* - * Anysee remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -static struct rc_map_table anysee[] = { - { 0x0800, KEY_0 }, - { 0x0801, KEY_1 }, - { 0x0802, KEY_2 }, - { 0x0803, KEY_3 }, - { 0x0804, KEY_4 }, - { 0x0805, KEY_5 }, - { 0x0806, KEY_6 }, - { 0x0807, KEY_7 }, - { 0x0808, KEY_8 }, - { 0x0809, KEY_9 }, - { 0x080a, KEY_POWER2 }, /* [red power button] */ - { 0x080b, KEY_VIDEO }, /* [*] MODE */ - { 0x080c, KEY_CHANNEL }, /* [symbol counterclockwise arrow] */ - { 0x080d, KEY_NEXT }, /* [>>|] */ - { 0x080e, KEY_MENU }, /* MENU */ - { 0x080f, KEY_EPG }, /* [EPG] */ - { 0x0810, KEY_CLEAR }, /* EXIT */ - { 0x0811, KEY_CHANNELUP }, - { 0x0812, KEY_VOLUMEDOWN }, - { 0x0813, KEY_VOLUMEUP }, - { 0x0814, KEY_CHANNELDOWN }, - { 0x0815, KEY_OK }, - { 0x0816, KEY_RADIO }, /* [symbol TV/radio] */ - { 0x0817, KEY_INFO }, /* [i] */ - { 0x0818, KEY_PREVIOUS }, /* [|<<] */ - { 0x0819, KEY_FAVORITES }, /* FAV. */ - { 0x081a, KEY_SUBTITLE }, /* Subtitle */ - { 0x081b, KEY_CAMERA }, /* [symbol camera] */ - { 0x081c, KEY_YELLOW }, - { 0x081d, KEY_RED }, - { 0x081e, KEY_LANGUAGE }, /* [symbol Second Audio Program] */ - { 0x081f, KEY_GREEN }, - { 0x0820, KEY_SLEEP }, /* Sleep */ - { 0x0821, KEY_SCREEN }, /* 16:9 / 4:3 */ - { 0x0822, KEY_ZOOM }, /* SIZE */ - { 0x0824, KEY_FN }, /* [F1] */ - { 0x0825, KEY_FN }, /* [F2] */ - { 0x0842, KEY_MUTE }, /* symbol mute */ - { 0x0844, KEY_BLUE }, - { 0x0847, KEY_TEXT }, /* TEXT */ - { 0x0848, KEY_STOP }, - { 0x0849, KEY_RECORD }, - { 0x0850, KEY_PLAY }, - { 0x0851, KEY_PAUSE }, -}; - -static struct rc_map_list anysee_map = { - .map = { - .scan = anysee, - .size = ARRAY_SIZE(anysee), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_ANYSEE, - } -}; - -static int __init init_rc_map_anysee(void) -{ - return rc_map_register(&anysee_map); -} - -static void __exit exit_rc_map_anysee(void) -{ - rc_map_unregister(&anysee_map); -} - -module_init(init_rc_map_anysee) -module_exit(exit_rc_map_anysee) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-apac-viewcomp.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-apac-viewcomp.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-apac-viewcomp.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-apac-viewcomp.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/* apac-viewcomp.h - Keytable for apac_viewcomp Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Attila Kondoros */ - -static struct rc_map_table apac_viewcomp[] = { - - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x00, KEY_0 }, - { 0x17, KEY_LAST }, /* +100 */ - { 0x0a, KEY_LIST }, /* recall */ - - - { 0x1c, KEY_TUNER }, /* TV/FM */ - { 0x15, KEY_SEARCH }, /* scan */ - { 0x12, KEY_POWER }, /* power */ - { 0x1f, KEY_VOLUMEDOWN }, /* vol up */ - { 0x1b, KEY_VOLUMEUP }, /* vol down */ - { 0x1e, KEY_CHANNELDOWN }, /* chn up */ - { 0x1a, KEY_CHANNELUP }, /* chn down */ - - { 0x11, KEY_VIDEO }, /* video */ - { 0x0f, KEY_ZOOM }, /* full screen */ - { 0x13, KEY_MUTE }, /* mute/unmute */ - { 0x10, KEY_TEXT }, /* min */ - - { 0x0d, KEY_STOP }, /* freeze */ - { 0x0e, KEY_RECORD }, /* record */ - { 0x1d, KEY_PLAYPAUSE }, /* stop */ - { 0x19, KEY_PLAY }, /* play */ - - { 0x16, KEY_GOTO }, /* osd */ - { 0x14, KEY_REFRESH }, /* default */ - { 0x0c, KEY_KPPLUS }, /* fine tune >>>> */ - { 0x18, KEY_KPMINUS }, /* fine tune <<<< */ -}; - -static struct rc_map_list apac_viewcomp_map = { - .map = { - .scan = apac_viewcomp, - .size = ARRAY_SIZE(apac_viewcomp), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_APAC_VIEWCOMP, - } -}; - -static int __init init_rc_map_apac_viewcomp(void) -{ - return rc_map_register(&apac_viewcomp_map); -} - -static void __exit exit_rc_map_apac_viewcomp(void) -{ - rc_map_unregister(&apac_viewcomp_map); -} - -module_init(init_rc_map_apac_viewcomp) -module_exit(exit_rc_map_apac_viewcomp) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-asus-pc39.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-asus-pc39.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-asus-pc39.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-asus-pc39.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -/* asus-pc39.h - Keytable for asus_pc39 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Marc Fargas - * this is the remote control that comes with the asus p7131 - * which has a label saying is "Model PC-39" - */ - -static struct rc_map_table asus_pc39[] = { - /* Keys 0 to 9 */ - { 0x082a, KEY_0 }, - { 0x0816, KEY_1 }, - { 0x0812, KEY_2 }, - { 0x0814, KEY_3 }, - { 0x0836, KEY_4 }, - { 0x0832, KEY_5 }, - { 0x0834, KEY_6 }, - { 0x080e, KEY_7 }, - { 0x080a, KEY_8 }, - { 0x080c, KEY_9 }, - - { 0x0801, KEY_RADIO }, /* radio */ - { 0x083c, KEY_MENU }, /* dvd/menu */ - { 0x0815, KEY_VOLUMEUP }, - { 0x0826, KEY_VOLUMEDOWN }, - { 0x0808, KEY_UP }, - { 0x0804, KEY_DOWN }, - { 0x0818, KEY_LEFT }, - { 0x0810, KEY_RIGHT }, - { 0x081a, KEY_VIDEO }, /* video */ - { 0x0806, KEY_AUDIO }, /* music */ - - { 0x081e, KEY_TV }, /* tv */ - { 0x0822, KEY_EXIT }, /* back */ - { 0x0835, KEY_CHANNELUP }, /* channel / program + */ - { 0x0824, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x0825, KEY_ENTER }, /* enter */ - - { 0x0839, KEY_PAUSE }, /* play/pause */ - { 0x0821, KEY_PREVIOUS }, /* rew */ - { 0x0819, KEY_NEXT }, /* forward */ - { 0x0831, KEY_REWIND }, /* backward << */ - { 0x0805, KEY_FASTFORWARD }, /* forward >> */ - { 0x0809, KEY_STOP }, - { 0x0811, KEY_RECORD }, /* recording */ - { 0x0829, KEY_POWER }, /* the button that reads "close" */ - - { 0x082e, KEY_ZOOM }, /* full screen */ - { 0x082c, KEY_MACRO }, /* recall */ - { 0x081c, KEY_HOME }, /* home */ - { 0x083a, KEY_PVR }, /* picture */ - { 0x0802, KEY_MUTE }, /* mute */ - { 0x083e, KEY_DVD }, /* dvd */ -}; - -static struct rc_map_list asus_pc39_map = { - .map = { - .scan = asus_pc39, - .size = ARRAY_SIZE(asus_pc39), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_ASUS_PC39, - } -}; - -static int __init init_rc_map_asus_pc39(void) -{ - return rc_map_register(&asus_pc39_map); -} - -static void __exit exit_rc_map_asus_pc39(void) -{ - rc_map_unregister(&asus_pc39_map); -} - -module_init(init_rc_map_asus_pc39) -module_exit(exit_rc_map_asus_pc39) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* ati-tv-wonder-hd-600.h - Keytable for ati_tv_wonder_hd_600 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* ATI TV Wonder HD 600 USB - Devin Heitmueller - */ - -static struct rc_map_table ati_tv_wonder_hd_600[] = { - { 0x00, KEY_RECORD}, /* Row 1 */ - { 0x01, KEY_PLAYPAUSE}, - { 0x02, KEY_STOP}, - { 0x03, KEY_POWER}, - { 0x04, KEY_PREVIOUS}, /* Row 2 */ - { 0x05, KEY_REWIND}, - { 0x06, KEY_FORWARD}, - { 0x07, KEY_NEXT}, - { 0x08, KEY_EPG}, /* Row 3 */ - { 0x09, KEY_HOME}, - { 0x0a, KEY_MENU}, - { 0x0b, KEY_CHANNELUP}, - { 0x0c, KEY_BACK}, /* Row 4 */ - { 0x0d, KEY_UP}, - { 0x0e, KEY_INFO}, - { 0x0f, KEY_CHANNELDOWN}, - { 0x10, KEY_LEFT}, /* Row 5 */ - { 0x11, KEY_SELECT}, - { 0x12, KEY_RIGHT}, - { 0x13, KEY_VOLUMEUP}, - { 0x14, KEY_LAST}, /* Row 6 */ - { 0x15, KEY_DOWN}, - { 0x16, KEY_MUTE}, - { 0x17, KEY_VOLUMEDOWN}, -}; - -static struct rc_map_list ati_tv_wonder_hd_600_map = { - .map = { - .scan = ati_tv_wonder_hd_600, - .size = ARRAY_SIZE(ati_tv_wonder_hd_600), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ATI_TV_WONDER_HD_600, - } -}; - -static int __init init_rc_map_ati_tv_wonder_hd_600(void) -{ - return rc_map_register(&ati_tv_wonder_hd_600_map); -} - -static void __exit exit_rc_map_ati_tv_wonder_hd_600(void) -{ - rc_map_unregister(&ati_tv_wonder_hd_600_map); -} - -module_init(init_rc_map_ati_tv_wonder_hd_600) -module_exit(exit_rc_map_ati_tv_wonder_hd_600) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-a16d.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-a16d.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-a16d.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-a16d.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/* avermedia-a16d.h - Keytable for avermedia_a16d Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table avermedia_a16d[] = { - { 0x20, KEY_LIST}, - { 0x00, KEY_POWER}, - { 0x28, KEY_1}, - { 0x18, KEY_2}, - { 0x38, KEY_3}, - { 0x24, KEY_4}, - { 0x14, KEY_5}, - { 0x34, KEY_6}, - { 0x2c, KEY_7}, - { 0x1c, KEY_8}, - { 0x3c, KEY_9}, - { 0x12, KEY_SUBTITLE}, - { 0x22, KEY_0}, - { 0x32, KEY_REWIND}, - { 0x3a, KEY_SHUFFLE}, - { 0x02, KEY_PRINT}, - { 0x11, KEY_CHANNELDOWN}, - { 0x31, KEY_CHANNELUP}, - { 0x0c, KEY_ZOOM}, - { 0x1e, KEY_VOLUMEDOWN}, - { 0x3e, KEY_VOLUMEUP}, - { 0x0a, KEY_MUTE}, - { 0x04, KEY_AUDIO}, - { 0x26, KEY_RECORD}, - { 0x06, KEY_PLAY}, - { 0x36, KEY_STOP}, - { 0x16, KEY_PAUSE}, - { 0x2e, KEY_REWIND}, - { 0x0e, KEY_FASTFORWARD}, - { 0x30, KEY_TEXT}, - { 0x21, KEY_GREEN}, - { 0x01, KEY_BLUE}, - { 0x08, KEY_EPG}, - { 0x2a, KEY_MENU}, -}; - -static struct rc_map_list avermedia_a16d_map = { - .map = { - .scan = avermedia_a16d, - .size = ARRAY_SIZE(avermedia_a16d), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERMEDIA_A16D, - } -}; - -static int __init init_rc_map_avermedia_a16d(void) -{ - return rc_map_register(&avermedia_a16d_map); -} - -static void __exit exit_rc_map_avermedia_a16d(void) -{ - rc_map_unregister(&avermedia_a16d_map); -} - -module_init(init_rc_map_avermedia_a16d) -module_exit(exit_rc_map_avermedia_a16d) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -/* avermedia.h - Keytable for avermedia Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Alex Hermann */ - -static struct rc_map_table avermedia[] = { - { 0x28, KEY_1 }, - { 0x18, KEY_2 }, - { 0x38, KEY_3 }, - { 0x24, KEY_4 }, - { 0x14, KEY_5 }, - { 0x34, KEY_6 }, - { 0x2c, KEY_7 }, - { 0x1c, KEY_8 }, - { 0x3c, KEY_9 }, - { 0x22, KEY_0 }, - - { 0x20, KEY_TV }, /* TV/FM */ - { 0x10, KEY_CD }, /* CD */ - { 0x30, KEY_TEXT }, /* TELETEXT */ - { 0x00, KEY_POWER }, /* POWER */ - - { 0x08, KEY_VIDEO }, /* VIDEO */ - { 0x04, KEY_AUDIO }, /* AUDIO */ - { 0x0c, KEY_ZOOM }, /* FULL SCREEN */ - - { 0x12, KEY_SUBTITLE }, /* DISPLAY */ - { 0x32, KEY_REWIND }, /* LOOP */ - { 0x02, KEY_PRINT }, /* PREVIEW */ - - { 0x2a, KEY_SEARCH }, /* AUTOSCAN */ - { 0x1a, KEY_SLEEP }, /* FREEZE */ - { 0x3a, KEY_CAMERA }, /* SNAPSHOT */ - { 0x0a, KEY_MUTE }, /* MUTE */ - - { 0x26, KEY_RECORD }, /* RECORD */ - { 0x16, KEY_PAUSE }, /* PAUSE */ - { 0x36, KEY_STOP }, /* STOP */ - { 0x06, KEY_PLAY }, /* PLAY */ - - { 0x2e, KEY_RED }, /* RED */ - { 0x21, KEY_GREEN }, /* GREEN */ - { 0x0e, KEY_YELLOW }, /* YELLOW */ - { 0x01, KEY_BLUE }, /* BLUE */ - - { 0x1e, KEY_VOLUMEDOWN }, /* VOLUME- */ - { 0x3e, KEY_VOLUMEUP }, /* VOLUME+ */ - { 0x11, KEY_CHANNELDOWN }, /* CHANNEL/PAGE- */ - { 0x31, KEY_CHANNELUP } /* CHANNEL/PAGE+ */ -}; - -static struct rc_map_list avermedia_map = { - .map = { - .scan = avermedia, - .size = ARRAY_SIZE(avermedia), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERMEDIA, - } -}; - -static int __init init_rc_map_avermedia(void) -{ - return rc_map_register(&avermedia_map); -} - -static void __exit exit_rc_map_avermedia(void) -{ - rc_map_unregister(&avermedia_map); -} - -module_init(init_rc_map_avermedia) -module_exit(exit_rc_map_avermedia) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-cardbus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-cardbus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-cardbus.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-cardbus.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/* avermedia-cardbus.h - Keytable for avermedia_cardbus Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Oldrich Jedlicka */ - -static struct rc_map_table avermedia_cardbus[] = { - { 0x00, KEY_POWER }, - { 0x01, KEY_TUNER }, /* TV/FM */ - { 0x03, KEY_TEXT }, /* Teletext */ - { 0x04, KEY_EPG }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, - { 0x08, KEY_AUDIO }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, - { 0x0c, KEY_ZOOM }, /* Full screen */ - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, - { 0x10, KEY_PAGEUP }, /* 16-CH PREV */ - { 0x11, KEY_0 }, - { 0x12, KEY_INFO }, - { 0x13, KEY_AGAIN }, /* CH RTN - channel return */ - { 0x14, KEY_MUTE }, - { 0x15, KEY_EDIT }, /* Autoscan */ - { 0x17, KEY_SAVE }, /* Screenshot */ - { 0x18, KEY_PLAYPAUSE }, - { 0x19, KEY_RECORD }, - { 0x1a, KEY_PLAY }, - { 0x1b, KEY_STOP }, - { 0x1c, KEY_FASTFORWARD }, - { 0x1d, KEY_REWIND }, - { 0x1e, KEY_VOLUMEDOWN }, - { 0x1f, KEY_VOLUMEUP }, - { 0x22, KEY_SLEEP }, /* Sleep */ - { 0x23, KEY_ZOOM }, /* Aspect */ - { 0x26, KEY_SCREEN }, /* Pos */ - { 0x27, KEY_ANGLE }, /* Size */ - { 0x28, KEY_SELECT }, /* Select */ - { 0x29, KEY_BLUE }, /* Blue/Picture */ - { 0x2a, KEY_BACKSPACE }, /* Back */ - { 0x2b, KEY_MEDIA }, /* PIP (Picture-in-picture) */ - { 0x2c, KEY_DOWN }, - { 0x2e, KEY_DOT }, - { 0x2f, KEY_TV }, /* Live TV */ - { 0x32, KEY_LEFT }, - { 0x33, KEY_CLEAR }, /* Clear */ - { 0x35, KEY_RED }, /* Red/TV */ - { 0x36, KEY_UP }, - { 0x37, KEY_HOME }, /* Home */ - { 0x39, KEY_GREEN }, /* Green/Video */ - { 0x3d, KEY_YELLOW }, /* Yellow/Music */ - { 0x3e, KEY_OK }, /* Ok */ - { 0x3f, KEY_RIGHT }, - { 0x40, KEY_NEXT }, /* Next */ - { 0x41, KEY_PREVIOUS }, /* Previous */ - { 0x42, KEY_CHANNELDOWN }, /* Channel down */ - { 0x43, KEY_CHANNELUP }, /* Channel up */ -}; - -static struct rc_map_list avermedia_cardbus_map = { - .map = { - .scan = avermedia_cardbus, - .size = ARRAY_SIZE(avermedia_cardbus), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERMEDIA_CARDBUS, - } -}; - -static int __init init_rc_map_avermedia_cardbus(void) -{ - return rc_map_register(&avermedia_cardbus_map); -} - -static void __exit exit_rc_map_avermedia_cardbus(void) -{ - rc_map_unregister(&avermedia_cardbus_map); -} - -module_init(init_rc_map_avermedia_cardbus) -module_exit(exit_rc_map_avermedia_cardbus) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-dvbt.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-dvbt.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-dvbt.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-dvbt.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* avermedia-dvbt.h - Keytable for avermedia_dvbt Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Matt Jesson >' */ - { 0x3a, KEY_RECORD }, /* 'capture' */ - { 0x0a, KEY_MUTE }, /* 'mute' */ - { 0x2c, KEY_RECORD }, /* 'record' */ - { 0x1c, KEY_PAUSE }, /* 'pause' */ - { 0x3c, KEY_STOP }, /* 'stop' */ - { 0x0c, KEY_PLAY }, /* 'play' */ - { 0x2e, KEY_RED }, /* 'red' */ - { 0x01, KEY_BLUE }, /* 'blue' / 'cancel' */ - { 0x0e, KEY_YELLOW }, /* 'yellow' / 'ok' */ - { 0x21, KEY_GREEN }, /* 'green' */ - { 0x11, KEY_CHANNELDOWN }, /* 'channel -' */ - { 0x31, KEY_CHANNELUP }, /* 'channel +' */ - { 0x1e, KEY_VOLUMEDOWN }, /* 'volume -' */ - { 0x3e, KEY_VOLUMEUP }, /* 'volume +' */ -}; - -static struct rc_map_list avermedia_dvbt_map = { - .map = { - .scan = avermedia_dvbt, - .size = ARRAY_SIZE(avermedia_dvbt), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERMEDIA_DVBT, - } -}; - -static int __init init_rc_map_avermedia_dvbt(void) -{ - return rc_map_register(&avermedia_dvbt_map); -} - -static void __exit exit_rc_map_avermedia_dvbt(void) -{ - rc_map_unregister(&avermedia_dvbt_map); -} - -module_init(init_rc_map_avermedia_dvbt) -module_exit(exit_rc_map_avermedia_dvbt) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-m135a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-m135a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-m135a.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-m135a.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -/* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * Copyright (c) 2010 by Herton Ronaldo Krzesinski - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Avermedia M135A with RM-JX and RM-K6 remote controls - * - * On Avermedia M135A with IR model RM-JX, the same codes exist on both - * Positivo (BR) and original IR, initial version and remote control codes - * added by Mauro Carvalho Chehab - * - * Positivo also ships Avermedia M135A with model RM-K6, extra control - * codes added by Herton Ronaldo Krzesinski - */ - -static struct rc_map_table avermedia_m135a[] = { - /* RM-JX */ - { 0x0200, KEY_POWER2 }, - { 0x022e, KEY_DOT }, /* '.' */ - { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */ - - { 0x0205, KEY_1 }, - { 0x0206, KEY_2 }, - { 0x0207, KEY_3 }, - { 0x0209, KEY_4 }, - { 0x020a, KEY_5 }, - { 0x020b, KEY_6 }, - { 0x020d, KEY_7 }, - { 0x020e, KEY_8 }, - { 0x020f, KEY_9 }, - { 0x0211, KEY_0 }, - - { 0x0213, KEY_RIGHT }, /* -> or L */ - { 0x0212, KEY_LEFT }, /* <- or R */ - - { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */ - { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */ - - { 0x0303, KEY_CHANNELUP }, - { 0x0302, KEY_CHANNELDOWN }, - { 0x021f, KEY_VOLUMEUP }, - { 0x021e, KEY_VOLUMEDOWN }, - { 0x020c, KEY_ENTER }, /* Full Screen */ - - { 0x0214, KEY_MUTE }, - { 0x0208, KEY_AUDIO }, - - { 0x0203, KEY_TEXT }, /* Teletext */ - { 0x0204, KEY_EPG }, - { 0x022b, KEY_TV2 }, /* TV2 or PIP */ - - { 0x021d, KEY_RED }, - { 0x021c, KEY_YELLOW }, - { 0x0301, KEY_GREEN }, - { 0x0300, KEY_BLUE }, - - { 0x021a, KEY_PLAYPAUSE }, - { 0x0219, KEY_RECORD }, - { 0x0218, KEY_PLAY }, - { 0x021b, KEY_STOP }, - - /* RM-K6 */ - { 0x0401, KEY_POWER2 }, - { 0x0406, KEY_MUTE }, - { 0x0408, KEY_MODE }, /* TV/FM */ - - { 0x0409, KEY_1 }, - { 0x040a, KEY_2 }, - { 0x040b, KEY_3 }, - { 0x040c, KEY_4 }, - { 0x040d, KEY_5 }, - { 0x040e, KEY_6 }, - { 0x040f, KEY_7 }, - { 0x0410, KEY_8 }, - { 0x0411, KEY_9 }, - { 0x044c, KEY_DOT }, /* '.' */ - { 0x0412, KEY_0 }, - { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ - - { 0x0413, KEY_AUDIO }, - { 0x0440, KEY_SCREEN }, /* Full Screen toggle */ - { 0x0441, KEY_HOME }, - { 0x0442, KEY_BACK }, - { 0x0447, KEY_UP }, - { 0x0448, KEY_DOWN }, - { 0x0449, KEY_LEFT }, - { 0x044a, KEY_RIGHT }, - { 0x044b, KEY_OK }, - { 0x0404, KEY_VOLUMEUP }, - { 0x0405, KEY_VOLUMEDOWN }, - { 0x0402, KEY_CHANNELUP }, - { 0x0403, KEY_CHANNELDOWN }, - - { 0x0443, KEY_RED }, - { 0x0444, KEY_GREEN }, - { 0x0445, KEY_YELLOW }, - { 0x0446, KEY_BLUE }, - - { 0x0414, KEY_TEXT }, - { 0x0415, KEY_EPG }, - { 0x041a, KEY_TV2 }, /* PIP */ - { 0x041b, KEY_CAMERA }, /* Snapshot */ - - { 0x0417, KEY_RECORD }, - { 0x0416, KEY_PLAYPAUSE }, - { 0x0418, KEY_STOP }, - { 0x0419, KEY_PAUSE }, - - { 0x041f, KEY_PREVIOUS }, - { 0x041c, KEY_REWIND }, - { 0x041d, KEY_FORWARD }, - { 0x041e, KEY_NEXT }, -}; - -static struct rc_map_list avermedia_m135a_map = { - .map = { - .scan = avermedia_m135a, - .size = ARRAY_SIZE(avermedia_m135a), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_AVERMEDIA_M135A, - } -}; - -static int __init init_rc_map_avermedia_m135a(void) -{ - return rc_map_register(&avermedia_m135a_map); -} - -static void __exit exit_rc_map_avermedia_m135a(void) -{ - rc_map_unregister(&avermedia_m135a_map); -} - -module_init(init_rc_map_avermedia_m135a) -module_exit(exit_rc_map_avermedia_m135a) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* avermedia-m733a-rm-k6.h - Keytable for avermedia_m733a_rm_k6 Remote Controller - * - * Copyright (c) 2010 by Herton Ronaldo Krzesinski - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Avermedia M733A with IR model RM-K6 - * This is the stock remote controller used with Positivo machines with M733A - * Herton Ronaldo Krzesinski - */ - -static struct rc_map_table avermedia_m733a_rm_k6[] = { - { 0x0401, KEY_POWER2 }, - { 0x0406, KEY_MUTE }, - { 0x0408, KEY_MODE }, /* TV/FM */ - - { 0x0409, KEY_1 }, - { 0x040a, KEY_2 }, - { 0x040b, KEY_3 }, - { 0x040c, KEY_4 }, - { 0x040d, KEY_5 }, - { 0x040e, KEY_6 }, - { 0x040f, KEY_7 }, - { 0x0410, KEY_8 }, - { 0x0411, KEY_9 }, - { 0x044c, KEY_DOT }, /* '.' */ - { 0x0412, KEY_0 }, - { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ - - { 0x0413, KEY_AUDIO }, - { 0x0440, KEY_SCREEN }, /* Full Screen toggle */ - { 0x0441, KEY_HOME }, - { 0x0442, KEY_BACK }, - { 0x0447, KEY_UP }, - { 0x0448, KEY_DOWN }, - { 0x0449, KEY_LEFT }, - { 0x044a, KEY_RIGHT }, - { 0x044b, KEY_OK }, - { 0x0404, KEY_VOLUMEUP }, - { 0x0405, KEY_VOLUMEDOWN }, - { 0x0402, KEY_CHANNELUP }, - { 0x0403, KEY_CHANNELDOWN }, - - { 0x0443, KEY_RED }, - { 0x0444, KEY_GREEN }, - { 0x0445, KEY_YELLOW }, - { 0x0446, KEY_BLUE }, - - { 0x0414, KEY_TEXT }, - { 0x0415, KEY_EPG }, - { 0x041a, KEY_TV2 }, /* PIP */ - { 0x041b, KEY_CAMERA }, /* Snapshot */ - - { 0x0417, KEY_RECORD }, - { 0x0416, KEY_PLAYPAUSE }, - { 0x0418, KEY_STOP }, - { 0x0419, KEY_PAUSE }, - - { 0x041f, KEY_PREVIOUS }, - { 0x041c, KEY_REWIND }, - { 0x041d, KEY_FORWARD }, - { 0x041e, KEY_NEXT }, -}; - -static struct rc_map_list avermedia_m733a_rm_k6_map = { - .map = { - .scan = avermedia_m733a_rm_k6, - .size = ARRAY_SIZE(avermedia_m733a_rm_k6), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_AVERMEDIA_M733A_RM_K6, - } -}; - -static int __init init_rc_map_avermedia_m733a_rm_k6(void) -{ - return rc_map_register(&avermedia_m733a_rm_k6_map); -} - -static void __exit exit_rc_map_avermedia_m733a_rm_k6(void) -{ - rc_map_unregister(&avermedia_m733a_rm_k6_map); -} - -module_init(init_rc_map_avermedia_m733a_rm_k6) -module_exit(exit_rc_map_avermedia_m733a_rm_k6) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/* - * AverMedia RM-KS remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -/* Initial keytable is from Jose Alberto Reguero - and Felipe Morales Moreno */ -/* FIXME: mappings are not 100% correct? */ -static struct rc_map_table avermedia_rm_ks[] = { - { 0x0501, KEY_POWER2 }, - { 0x0502, KEY_CHANNELUP }, - { 0x0503, KEY_CHANNELDOWN }, - { 0x0504, KEY_VOLUMEUP }, - { 0x0505, KEY_VOLUMEDOWN }, - { 0x0506, KEY_MUTE }, - { 0x0507, KEY_RIGHT }, - { 0x0508, KEY_RED }, - { 0x0509, KEY_1 }, - { 0x050a, KEY_2 }, - { 0x050b, KEY_3 }, - { 0x050c, KEY_4 }, - { 0x050d, KEY_5 }, - { 0x050e, KEY_6 }, - { 0x050f, KEY_7 }, - { 0x0510, KEY_8 }, - { 0x0511, KEY_9 }, - { 0x0512, KEY_0 }, - { 0x0513, KEY_AUDIO }, - { 0x0515, KEY_EPG }, - { 0x0516, KEY_PLAY }, - { 0x0517, KEY_RECORD }, - { 0x0518, KEY_STOP }, - { 0x051c, KEY_BACK }, - { 0x051d, KEY_FORWARD }, - { 0x054d, KEY_LEFT }, - { 0x0556, KEY_ZOOM }, -}; - -static struct rc_map_list avermedia_rm_ks_map = { - .map = { - .scan = avermedia_rm_ks, - .size = ARRAY_SIZE(avermedia_rm_ks), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_AVERMEDIA_RM_KS, - } -}; - -static int __init init_rc_map_avermedia_rm_ks(void) -{ - return rc_map_register(&avermedia_rm_ks_map); -} - -static void __exit exit_rc_map_avermedia_rm_ks(void) -{ - rc_map_unregister(&avermedia_rm_ks_map); -} - -module_init(init_rc_map_avermedia_rm_ks) -module_exit(exit_rc_map_avermedia_rm_ks) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avertv-303.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avertv-303.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avertv-303.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-avertv-303.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* avertv-303.h - Keytable for avertv_303 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* AVERTV STUDIO 303 Remote */ - -static struct rc_map_table avertv_303[] = { - { 0x2a, KEY_1 }, - { 0x32, KEY_2 }, - { 0x3a, KEY_3 }, - { 0x4a, KEY_4 }, - { 0x52, KEY_5 }, - { 0x5a, KEY_6 }, - { 0x6a, KEY_7 }, - { 0x72, KEY_8 }, - { 0x7a, KEY_9 }, - { 0x0e, KEY_0 }, - - { 0x02, KEY_POWER }, - { 0x22, KEY_VIDEO }, - { 0x42, KEY_AUDIO }, - { 0x62, KEY_ZOOM }, - { 0x0a, KEY_TV }, - { 0x12, KEY_CD }, - { 0x1a, KEY_TEXT }, - - { 0x16, KEY_SUBTITLE }, - { 0x1e, KEY_REWIND }, - { 0x06, KEY_PRINT }, - - { 0x2e, KEY_SEARCH }, - { 0x36, KEY_SLEEP }, - { 0x3e, KEY_SHUFFLE }, - { 0x26, KEY_MUTE }, - - { 0x4e, KEY_RECORD }, - { 0x56, KEY_PAUSE }, - { 0x5e, KEY_STOP }, - { 0x46, KEY_PLAY }, - - { 0x6e, KEY_RED }, - { 0x0b, KEY_GREEN }, - { 0x66, KEY_YELLOW }, - { 0x03, KEY_BLUE }, - - { 0x76, KEY_LEFT }, - { 0x7e, KEY_RIGHT }, - { 0x13, KEY_DOWN }, - { 0x1b, KEY_UP }, -}; - -static struct rc_map_list avertv_303_map = { - .map = { - .scan = avertv_303, - .size = ARRAY_SIZE(avertv_303), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERTV_303, - } -}; - -static int __init init_rc_map_avertv_303(void) -{ - return rc_map_register(&avertv_303_map); -} - -static void __exit exit_rc_map_avertv_303(void) -{ - rc_map_unregister(&avertv_303_map); -} - -module_init(init_rc_map_avertv_303) -module_exit(exit_rc_map_avertv_303) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/* - * TwinHan AzureWave AD-TU700(704J) remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -static struct rc_map_table azurewave_ad_tu700[] = { - { 0x0000, KEY_TAB }, /* Tab */ - { 0x0001, KEY_2 }, - { 0x0002, KEY_CHANNELDOWN }, - { 0x0003, KEY_1 }, - { 0x0004, KEY_MENU }, /* Record List */ - { 0x0005, KEY_CHANNELUP }, - { 0x0006, KEY_3 }, - { 0x0007, KEY_SLEEP }, /* Hibernate */ - { 0x0008, KEY_VIDEO }, /* A/V */ - { 0x0009, KEY_4 }, - { 0x000a, KEY_VOLUMEDOWN }, - { 0x000c, KEY_CANCEL }, /* Cancel */ - { 0x000d, KEY_7 }, - { 0x000e, KEY_AGAIN }, /* Recall */ - { 0x000f, KEY_TEXT }, /* Teletext */ - { 0x0010, KEY_MUTE }, - { 0x0011, KEY_RECORD }, - { 0x0012, KEY_FASTFORWARD }, /* FF >> */ - { 0x0013, KEY_BACK }, /* Back */ - { 0x0014, KEY_PLAY }, - { 0x0015, KEY_0 }, - { 0x0016, KEY_POWER2 }, /* [red power button] */ - { 0x0017, KEY_FAVORITES }, /* Favorite List */ - { 0x0018, KEY_RED }, - { 0x0019, KEY_8 }, - { 0x001a, KEY_STOP }, - { 0x001b, KEY_9 }, - { 0x001c, KEY_EPG }, /* Info/EPG */ - { 0x001d, KEY_5 }, - { 0x001e, KEY_VOLUMEUP }, - { 0x001f, KEY_6 }, - { 0x0040, KEY_REWIND }, /* FR << */ - { 0x0041, KEY_PREVIOUS }, /* Replay */ - { 0x0042, KEY_NEXT }, /* Skip */ - { 0x0043, KEY_SUBTITLE }, /* Subtitle / CC */ - { 0x0045, KEY_KPPLUS }, /* Zoom+ */ - { 0x0046, KEY_KPMINUS }, /* Zoom- */ - { 0x0047, KEY_NEW }, /* PIP */ - { 0x0048, KEY_INFO }, /* Preview */ - { 0x0049, KEY_MODE }, /* L/R */ - { 0x004a, KEY_CLEAR }, /* Clear */ - { 0x004b, KEY_UP }, /* up arrow */ - { 0x004c, KEY_PAUSE }, - { 0x004d, KEY_ZOOM }, /* Full Screen */ - { 0x004e, KEY_LEFT }, /* left arrow */ - { 0x004f, KEY_OK }, /* Enter / ok */ - { 0x0050, KEY_LANGUAGE }, /* SAP */ - { 0x0051, KEY_DOWN }, /* down arrow */ - { 0x0052, KEY_RIGHT }, /* right arrow */ - { 0x0053, KEY_GREEN }, - { 0x0054, KEY_CAMERA }, /* Capture */ - { 0x005e, KEY_YELLOW }, - { 0x005f, KEY_BLUE }, -}; - -static struct rc_map_list azurewave_ad_tu700_map = { - .map = { - .scan = azurewave_ad_tu700, - .size = ARRAY_SIZE(azurewave_ad_tu700), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_AZUREWAVE_AD_TU700, - } -}; - -static int __init init_rc_map_azurewave_ad_tu700(void) -{ - return rc_map_register(&azurewave_ad_tu700_map); -} - -static void __exit exit_rc_map_azurewave_ad_tu700(void) -{ - rc_map_unregister(&azurewave_ad_tu700_map); -} - -module_init(init_rc_map_azurewave_ad_tu700) -module_exit(exit_rc_map_azurewave_ad_tu700) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-behold.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-behold.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-behold.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-behold.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/* behold.h - Keytable for behold Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Igor Kuznetsov - * Andrey J. Melnikov - * - * Keytable is used by BeholdTV 60x series, M6 series at - * least, and probably other cards too. - * The "ascii-art picture" below (in comments, first row - * is the keycode in hex, and subsequent row(s) shows - * the button labels (several variants when appropriate) - * helps to descide which keycodes to assign to the buttons. - */ - -static struct rc_map_table behold[] = { - - /* 0x1c 0x12 * - * TV/FM POWER * - * */ - { 0x6b861c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */ - { 0x6b8612, KEY_POWER }, - - /* 0x01 0x02 0x03 * - * 1 2 3 * - * * - * 0x04 0x05 0x06 * - * 4 5 6 * - * * - * 0x07 0x08 0x09 * - * 7 8 9 * - * */ - { 0x6b8601, KEY_1 }, - { 0x6b8602, KEY_2 }, - { 0x6b8603, KEY_3 }, - { 0x6b8604, KEY_4 }, - { 0x6b8605, KEY_5 }, - { 0x6b8606, KEY_6 }, - { 0x6b8607, KEY_7 }, - { 0x6b8608, KEY_8 }, - { 0x6b8609, KEY_9 }, - - /* 0x0a 0x00 0x17 * - * RECALL 0 MODE * - * */ - { 0x6b860a, KEY_AGAIN }, - { 0x6b8600, KEY_0 }, - { 0x6b8617, KEY_MODE }, - - /* 0x14 0x10 * - * ASPECT FULLSCREEN * - * */ - { 0x6b8614, KEY_SCREEN }, - { 0x6b8610, KEY_ZOOM }, - - /* 0x0b * - * Up * - * * - * 0x18 0x16 0x0c * - * Left Ok Right * - * * - * 0x015 * - * Down * - * */ - { 0x6b860b, KEY_CHANNELUP }, - { 0x6b8618, KEY_VOLUMEDOWN }, - { 0x6b8616, KEY_OK }, /* XXX KEY_ENTER */ - { 0x6b860c, KEY_VOLUMEUP }, - { 0x6b8615, KEY_CHANNELDOWN }, - - /* 0x11 0x0d * - * MUTE INFO * - * */ - { 0x6b8611, KEY_MUTE }, - { 0x6b860d, KEY_INFO }, - - /* 0x0f 0x1b 0x1a * - * RECORD PLAY/PAUSE STOP * - * * - * 0x0e 0x1f 0x1e * - *TELETEXT AUDIO SOURCE * - * RED YELLOW * - * */ - { 0x6b860f, KEY_RECORD }, - { 0x6b861b, KEY_PLAYPAUSE }, - { 0x6b861a, KEY_STOP }, - { 0x6b860e, KEY_TEXT }, - { 0x6b861f, KEY_RED }, /*XXX KEY_AUDIO */ - { 0x6b861e, KEY_VIDEO }, - - /* 0x1d 0x13 0x19 * - * SLEEP PREVIEW DVB * - * GREEN BLUE * - * */ - { 0x6b861d, KEY_SLEEP }, - { 0x6b8613, KEY_GREEN }, - { 0x6b8619, KEY_BLUE }, /* XXX KEY_SAT */ - - /* 0x58 0x5c * - * FREEZE SNAPSHOT * - * */ - { 0x6b8658, KEY_SLOW }, - { 0x6b865c, KEY_CAMERA }, - -}; - -static struct rc_map_list behold_map = { - .map = { - .scan = behold, - .size = ARRAY_SIZE(behold), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_BEHOLD, - } -}; - -static int __init init_rc_map_behold(void) -{ - return rc_map_register(&behold_map); -} - -static void __exit exit_rc_map_behold(void) -{ - rc_map_unregister(&behold_map); -} - -module_init(init_rc_map_behold) -module_exit(exit_rc_map_behold) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-behold-columbus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-behold-columbus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-behold-columbus.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-behold-columbus.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/* behold-columbus.h - Keytable for behold_columbus Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Beholder Intl. Ltd. 2008 - * Dmitry Belimov d.belimov@google.com - * Keytable is used by BeholdTV Columbus - * The "ascii-art picture" below (in comments, first row - * is the keycode in hex, and subsequent row(s) shows - * the button labels (several variants when appropriate) - * helps to descide which keycodes to assign to the buttons. - */ - -static struct rc_map_table behold_columbus[] = { - - /* 0x13 0x11 0x1C 0x12 * - * Mute Source TV/FM Power * - * */ - - { 0x13, KEY_MUTE }, - { 0x11, KEY_VIDEO }, - { 0x1C, KEY_TUNER }, /* KEY_TV/KEY_RADIO */ - { 0x12, KEY_POWER }, - - /* 0x01 0x02 0x03 0x0D * - * 1 2 3 Stereo * - * * - * 0x04 0x05 0x06 0x19 * - * 4 5 6 Snapshot * - * * - * 0x07 0x08 0x09 0x10 * - * 7 8 9 Zoom * - * */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x0D, KEY_SETUP }, /* Setup key */ - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x19, KEY_CAMERA }, /* Snapshot key */ - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x10, KEY_ZOOM }, - - /* 0x0A 0x00 0x0B 0x0C * - * RECALL 0 ChannelUp VolumeUp * - * */ - { 0x0A, KEY_AGAIN }, - { 0x00, KEY_0 }, - { 0x0B, KEY_CHANNELUP }, - { 0x0C, KEY_VOLUMEUP }, - - /* 0x1B 0x1D 0x15 0x18 * - * Timeshift Record ChannelDown VolumeDown * - * */ - - { 0x1B, KEY_TIME }, - { 0x1D, KEY_RECORD }, - { 0x15, KEY_CHANNELDOWN }, - { 0x18, KEY_VOLUMEDOWN }, - - /* 0x0E 0x1E 0x0F 0x1A * - * Stop Pause Previouse Next * - * */ - - { 0x0E, KEY_STOP }, - { 0x1E, KEY_PAUSE }, - { 0x0F, KEY_PREVIOUS }, - { 0x1A, KEY_NEXT }, - -}; - -static struct rc_map_list behold_columbus_map = { - .map = { - .scan = behold_columbus, - .size = ARRAY_SIZE(behold_columbus), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_BEHOLD_COLUMBUS, - } -}; - -static int __init init_rc_map_behold_columbus(void) -{ - return rc_map_register(&behold_columbus_map); -} - -static void __exit exit_rc_map_behold_columbus(void) -{ - rc_map_unregister(&behold_columbus_map); -} - -module_init(init_rc_map_behold_columbus) -module_exit(exit_rc_map_behold_columbus) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-budget-ci-old.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-budget-ci-old.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-budget-ci-old.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-budget-ci-old.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/* budget-ci-old.h - Keytable for budget_ci_old Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * From reading the following remotes: - * Zenith Universal 7 / TV Mode 807 / VCR Mode 837 - * Hauppauge (from NOVA-CI-s box product) - * This is a "middle of the road" approach, differences are noted - */ - -static struct rc_map_table budget_ci_old[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x0a, KEY_ENTER }, - { 0x0b, KEY_RED }, - { 0x0c, KEY_POWER }, /* RADIO on Hauppauge */ - { 0x0d, KEY_MUTE }, - { 0x0f, KEY_A }, /* TV on Hauppauge */ - { 0x10, KEY_VOLUMEUP }, - { 0x11, KEY_VOLUMEDOWN }, - { 0x14, KEY_B }, - { 0x1c, KEY_UP }, - { 0x1d, KEY_DOWN }, - { 0x1e, KEY_OPTION }, /* RESERVED on Hauppauge */ - { 0x1f, KEY_BREAK }, - { 0x20, KEY_CHANNELUP }, - { 0x21, KEY_CHANNELDOWN }, - { 0x22, KEY_PREVIOUS }, /* Prev Ch on Zenith, SOURCE on Hauppauge */ - { 0x24, KEY_RESTART }, - { 0x25, KEY_OK }, - { 0x26, KEY_CYCLEWINDOWS }, /* MINIMIZE on Hauppauge */ - { 0x28, KEY_ENTER }, /* VCR mode on Zenith */ - { 0x29, KEY_PAUSE }, - { 0x2b, KEY_RIGHT }, - { 0x2c, KEY_LEFT }, - { 0x2e, KEY_MENU }, /* FULL SCREEN on Hauppauge */ - { 0x30, KEY_SLOW }, - { 0x31, KEY_PREVIOUS }, /* VCR mode on Zenith */ - { 0x32, KEY_REWIND }, - { 0x34, KEY_FASTFORWARD }, - { 0x35, KEY_PLAY }, - { 0x36, KEY_STOP }, - { 0x37, KEY_RECORD }, - { 0x38, KEY_TUNER }, /* TV/VCR on Zenith */ - { 0x3a, KEY_C }, - { 0x3c, KEY_EXIT }, - { 0x3d, KEY_POWER2 }, - { 0x3e, KEY_TUNER }, -}; - -static struct rc_map_list budget_ci_old_map = { - .map = { - .scan = budget_ci_old, - .size = ARRAY_SIZE(budget_ci_old), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_BUDGET_CI_OLD, - } -}; - -static int __init init_rc_map_budget_ci_old(void) -{ - return rc_map_register(&budget_ci_old_map); -} - -static void __exit exit_rc_map_budget_ci_old(void) -{ - rc_map_unregister(&budget_ci_old_map); -} - -module_init(init_rc_map_budget_ci_old) -module_exit(exit_rc_map_budget_ci_old) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-cinergy-1400.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-cinergy-1400.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-cinergy-1400.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-cinergy-1400.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/* cinergy-1400.h - Keytable for cinergy_1400 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Cinergy 1400 DVB-T */ - -static struct rc_map_table cinergy_1400[] = { - { 0x01, KEY_POWER }, - { 0x02, KEY_1 }, - { 0x03, KEY_2 }, - { 0x04, KEY_3 }, - { 0x05, KEY_4 }, - { 0x06, KEY_5 }, - { 0x07, KEY_6 }, - { 0x08, KEY_7 }, - { 0x09, KEY_8 }, - { 0x0a, KEY_9 }, - { 0x0c, KEY_0 }, - - { 0x0b, KEY_VIDEO }, - { 0x0d, KEY_REFRESH }, - { 0x0e, KEY_SELECT }, - { 0x0f, KEY_EPG }, - { 0x10, KEY_UP }, - { 0x11, KEY_LEFT }, - { 0x12, KEY_OK }, - { 0x13, KEY_RIGHT }, - { 0x14, KEY_DOWN }, - { 0x15, KEY_TEXT }, - { 0x16, KEY_INFO }, - - { 0x17, KEY_RED }, - { 0x18, KEY_GREEN }, - { 0x19, KEY_YELLOW }, - { 0x1a, KEY_BLUE }, - - { 0x1b, KEY_CHANNELUP }, - { 0x1c, KEY_VOLUMEUP }, - { 0x1d, KEY_MUTE }, - { 0x1e, KEY_VOLUMEDOWN }, - { 0x1f, KEY_CHANNELDOWN }, - - { 0x40, KEY_PAUSE }, - { 0x4c, KEY_PLAY }, - { 0x58, KEY_RECORD }, - { 0x54, KEY_PREVIOUS }, - { 0x48, KEY_STOP }, - { 0x5c, KEY_NEXT }, -}; - -static struct rc_map_list cinergy_1400_map = { - .map = { - .scan = cinergy_1400, - .size = ARRAY_SIZE(cinergy_1400), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_CINERGY_1400, - } -}; - -static int __init init_rc_map_cinergy_1400(void) -{ - return rc_map_register(&cinergy_1400_map); -} - -static void __exit exit_rc_map_cinergy_1400(void) -{ - rc_map_unregister(&cinergy_1400_map); -} - -module_init(init_rc_map_cinergy_1400) -module_exit(exit_rc_map_cinergy_1400) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-cinergy.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-cinergy.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-cinergy.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-cinergy.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* cinergy.h - Keytable for cinergy Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table cinergy[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x0a, KEY_POWER }, - { 0x0b, KEY_MEDIA }, /* app */ - { 0x0c, KEY_ZOOM }, /* zoom/fullscreen */ - { 0x0d, KEY_CHANNELUP }, /* channel */ - { 0x0e, KEY_CHANNELDOWN }, /* channel- */ - { 0x0f, KEY_VOLUMEUP }, - { 0x10, KEY_VOLUMEDOWN }, - { 0x11, KEY_TUNER }, /* AV */ - { 0x12, KEY_NUMLOCK }, /* -/-- */ - { 0x13, KEY_AUDIO }, /* audio */ - { 0x14, KEY_MUTE }, - { 0x15, KEY_UP }, - { 0x16, KEY_DOWN }, - { 0x17, KEY_LEFT }, - { 0x18, KEY_RIGHT }, - { 0x19, BTN_LEFT, }, - { 0x1a, BTN_RIGHT, }, - { 0x1b, KEY_WWW }, /* text */ - { 0x1c, KEY_REWIND }, - { 0x1d, KEY_FORWARD }, - { 0x1e, KEY_RECORD }, - { 0x1f, KEY_PLAY }, - { 0x20, KEY_PREVIOUSSONG }, - { 0x21, KEY_NEXTSONG }, - { 0x22, KEY_PAUSE }, - { 0x23, KEY_STOP }, -}; - -static struct rc_map_list cinergy_map = { - .map = { - .scan = cinergy, - .size = ARRAY_SIZE(cinergy), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_CINERGY, - } -}; - -static int __init init_rc_map_cinergy(void) -{ - return rc_map_register(&cinergy_map); -} - -static void __exit exit_rc_map_cinergy(void) -{ - rc_map_unregister(&cinergy_map); -} - -module_init(init_rc_map_cinergy) -module_exit(exit_rc_map_cinergy) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dib0700-nec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dib0700-nec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dib0700-nec.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dib0700-nec.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -/* rc-dvb0700-big.c - Keytable for devices in dvb0700 - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * TODO: This table is a real mess, as it merges RC codes from several - * devices into a big table. It also has both RC-5 and NEC codes inside. - * It should be broken into small tables, and the protocols should properly - * be indentificated. - * - * The table were imported from dib0700_devices.c. - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table dib0700_nec_table[] = { - /* Key codes for the Pixelview SBTVD remote */ - { 0x866b13, KEY_MUTE }, - { 0x866b12, KEY_POWER }, - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, - { 0x866b00, KEY_0 }, - { 0x866b0d, KEY_CHANNELUP }, - { 0x866b19, KEY_CHANNELDOWN }, - { 0x866b10, KEY_VOLUMEUP }, - { 0x866b0c, KEY_VOLUMEDOWN }, - - { 0x866b0a, KEY_CAMERA }, - { 0x866b0b, KEY_ZOOM }, - { 0x866b1b, KEY_BACKSPACE }, - { 0x866b15, KEY_ENTER }, - - { 0x866b1d, KEY_UP }, - { 0x866b1e, KEY_DOWN }, - { 0x866b0e, KEY_LEFT }, - { 0x866b0f, KEY_RIGHT }, - - { 0x866b18, KEY_RECORD }, - { 0x866b1a, KEY_STOP }, - - /* Key codes for the EvolutePC TVWay+ remote */ - { 0x7a00, KEY_MENU }, - { 0x7a01, KEY_RECORD }, - { 0x7a02, KEY_PLAY }, - { 0x7a03, KEY_STOP }, - { 0x7a10, KEY_CHANNELUP }, - { 0x7a11, KEY_CHANNELDOWN }, - { 0x7a12, KEY_VOLUMEUP }, - { 0x7a13, KEY_VOLUMEDOWN }, - { 0x7a40, KEY_POWER }, - { 0x7a41, KEY_MUTE }, - - /* Key codes for the Elgato EyeTV Diversity silver remote */ - { 0x4501, KEY_POWER }, - { 0x4502, KEY_MUTE }, - { 0x4503, KEY_1 }, - { 0x4504, KEY_2 }, - { 0x4505, KEY_3 }, - { 0x4506, KEY_4 }, - { 0x4507, KEY_5 }, - { 0x4508, KEY_6 }, - { 0x4509, KEY_7 }, - { 0x450a, KEY_8 }, - { 0x450b, KEY_9 }, - { 0x450c, KEY_LAST }, - { 0x450d, KEY_0 }, - { 0x450e, KEY_ENTER }, - { 0x450f, KEY_RED }, - { 0x4510, KEY_CHANNELUP }, - { 0x4511, KEY_GREEN }, - { 0x4512, KEY_VOLUMEDOWN }, - { 0x4513, KEY_OK }, - { 0x4514, KEY_VOLUMEUP }, - { 0x4515, KEY_YELLOW }, - { 0x4516, KEY_CHANNELDOWN }, - { 0x4517, KEY_BLUE }, - { 0x4518, KEY_LEFT }, /* Skip backwards */ - { 0x4519, KEY_PLAYPAUSE }, - { 0x451a, KEY_RIGHT }, /* Skip forward */ - { 0x451b, KEY_REWIND }, - { 0x451c, KEY_L }, /* Live */ - { 0x451d, KEY_FASTFORWARD }, - { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */ - { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */ - { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */ - { 0x4541, KEY_SCREEN }, /* Full screen toggle, 'Hold' for Teletext */ - { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */ -}; - -static struct rc_map_list dib0700_nec_map = { - .map = { - .scan = dib0700_nec_table, - .size = ARRAY_SIZE(dib0700_nec_table), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DIB0700_NEC_TABLE, - } -}; - -static int __init init_rc_map(void) -{ - return rc_map_register(&dib0700_nec_map); -} - -static void __exit exit_rc_map(void) -{ - rc_map_unregister(&dib0700_nec_map); -} - -module_init(init_rc_map) -module_exit(exit_rc_map) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dib0700-rc5.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dib0700-rc5.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dib0700-rc5.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dib0700-rc5.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,235 +0,0 @@ -/* rc-dvb0700-big.c - Keytable for devices in dvb0700 - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * TODO: This table is a real mess, as it merges RC codes from several - * devices into a big table. It also has both RC-5 and NEC codes inside. - * It should be broken into small tables, and the protocols should properly - * be indentificated. - * - * The table were imported from dib0700_devices.c. - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table dib0700_rc5_table[] = { - /* Key codes for the tiny Pinnacle remote*/ - { 0x0700, KEY_MUTE }, - { 0x0701, KEY_MENU }, /* Pinnacle logo */ - { 0x0739, KEY_POWER }, - { 0x0703, KEY_VOLUMEUP }, - { 0x0709, KEY_VOLUMEDOWN }, - { 0x0706, KEY_CHANNELUP }, - { 0x070c, KEY_CHANNELDOWN }, - { 0x070f, KEY_1 }, - { 0x0715, KEY_2 }, - { 0x0710, KEY_3 }, - { 0x0718, KEY_4 }, - { 0x071b, KEY_5 }, - { 0x071e, KEY_6 }, - { 0x0711, KEY_7 }, - { 0x0721, KEY_8 }, - { 0x0712, KEY_9 }, - { 0x0727, KEY_0 }, - { 0x0724, KEY_SCREEN }, /* 'Square' key */ - { 0x072a, KEY_TEXT }, /* 'T' key */ - { 0x072d, KEY_REWIND }, - { 0x0730, KEY_PLAY }, - { 0x0733, KEY_FASTFORWARD }, - { 0x0736, KEY_RECORD }, - { 0x073c, KEY_STOP }, - { 0x073f, KEY_CANCEL }, /* '?' key */ - - /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */ - { 0xeb01, KEY_POWER }, - { 0xeb02, KEY_1 }, - { 0xeb03, KEY_2 }, - { 0xeb04, KEY_3 }, - { 0xeb05, KEY_4 }, - { 0xeb06, KEY_5 }, - { 0xeb07, KEY_6 }, - { 0xeb08, KEY_7 }, - { 0xeb09, KEY_8 }, - { 0xeb0a, KEY_9 }, - { 0xeb0b, KEY_VIDEO }, - { 0xeb0c, KEY_0 }, - { 0xeb0d, KEY_REFRESH }, - { 0xeb0f, KEY_EPG }, - { 0xeb10, KEY_UP }, - { 0xeb11, KEY_LEFT }, - { 0xeb12, KEY_OK }, - { 0xeb13, KEY_RIGHT }, - { 0xeb14, KEY_DOWN }, - { 0xeb16, KEY_INFO }, - { 0xeb17, KEY_RED }, - { 0xeb18, KEY_GREEN }, - { 0xeb19, KEY_YELLOW }, - { 0xeb1a, KEY_BLUE }, - { 0xeb1b, KEY_CHANNELUP }, - { 0xeb1c, KEY_VOLUMEUP }, - { 0xeb1d, KEY_MUTE }, - { 0xeb1e, KEY_VOLUMEDOWN }, - { 0xeb1f, KEY_CHANNELDOWN }, - { 0xeb40, KEY_PAUSE }, - { 0xeb41, KEY_HOME }, - { 0xeb42, KEY_MENU }, /* DVD Menu */ - { 0xeb43, KEY_SUBTITLE }, - { 0xeb44, KEY_TEXT }, /* Teletext */ - { 0xeb45, KEY_DELETE }, - { 0xeb46, KEY_TV }, - { 0xeb47, KEY_DVD }, - { 0xeb48, KEY_STOP }, - { 0xeb49, KEY_VIDEO }, - { 0xeb4a, KEY_AUDIO }, /* Music */ - { 0xeb4b, KEY_SCREEN }, /* Pic */ - { 0xeb4c, KEY_PLAY }, - { 0xeb4d, KEY_BACK }, - { 0xeb4e, KEY_REWIND }, - { 0xeb4f, KEY_FASTFORWARD }, - { 0xeb54, KEY_PREVIOUS }, - { 0xeb58, KEY_RECORD }, - { 0xeb5c, KEY_NEXT }, - - /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */ - { 0x1e00, KEY_0 }, - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, - { 0x1e0a, KEY_KPASTERISK }, - { 0x1e0b, KEY_RED }, - { 0x1e0c, KEY_RADIO }, - { 0x1e0d, KEY_MENU }, - { 0x1e0e, KEY_GRAVE }, /* # */ - { 0x1e0f, KEY_MUTE }, - { 0x1e10, KEY_VOLUMEUP }, - { 0x1e11, KEY_VOLUMEDOWN }, - { 0x1e12, KEY_CHANNEL }, - { 0x1e14, KEY_UP }, - { 0x1e15, KEY_DOWN }, - { 0x1e16, KEY_LEFT }, - { 0x1e17, KEY_RIGHT }, - { 0x1e18, KEY_VIDEO }, - { 0x1e19, KEY_AUDIO }, - { 0x1e1a, KEY_MEDIA }, - { 0x1e1b, KEY_EPG }, - { 0x1e1c, KEY_TV }, - { 0x1e1e, KEY_NEXT }, - { 0x1e1f, KEY_BACK }, - { 0x1e20, KEY_CHANNELUP }, - { 0x1e21, KEY_CHANNELDOWN }, - { 0x1e24, KEY_LAST }, /* Skip backwards */ - { 0x1e25, KEY_OK }, - { 0x1e29, KEY_BLUE}, - { 0x1e2e, KEY_GREEN }, - { 0x1e30, KEY_PAUSE }, - { 0x1e32, KEY_REWIND }, - { 0x1e34, KEY_FASTFORWARD }, - { 0x1e35, KEY_PLAY }, - { 0x1e36, KEY_STOP }, - { 0x1e37, KEY_RECORD }, - { 0x1e38, KEY_YELLOW }, - { 0x1e3b, KEY_GOTO }, - { 0x1e3d, KEY_POWER }, - - /* Key codes for the Leadtek Winfast DTV Dongle */ - { 0x0042, KEY_POWER }, - { 0x077c, KEY_TUNER }, - { 0x0f4e, KEY_PRINT }, /* PREVIEW */ - { 0x0840, KEY_SCREEN }, /* full screen toggle*/ - { 0x0f71, KEY_DOT }, /* frequency */ - { 0x0743, KEY_0 }, - { 0x0c41, KEY_1 }, - { 0x0443, KEY_2 }, - { 0x0b7f, KEY_3 }, - { 0x0e41, KEY_4 }, - { 0x0643, KEY_5 }, - { 0x097f, KEY_6 }, - { 0x0d7e, KEY_7 }, - { 0x057c, KEY_8 }, - { 0x0a40, KEY_9 }, - { 0x0e4e, KEY_CLEAR }, - { 0x047c, KEY_CHANNEL }, /* show channel number */ - { 0x0f41, KEY_LAST }, /* recall */ - { 0x0342, KEY_MUTE }, - { 0x064c, KEY_RESERVED }, /* PIP button*/ - { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */ - { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */ - { 0x0b70, KEY_RECORD }, - { 0x037d, KEY_VOLUMEUP }, - { 0x017d, KEY_VOLUMEDOWN }, - { 0x0242, KEY_CHANNELUP }, - { 0x007d, KEY_CHANNELDOWN }, - - /* Key codes for Nova-TD "credit card" remote control. */ - { 0x1d00, KEY_0 }, - { 0x1d01, KEY_1 }, - { 0x1d02, KEY_2 }, - { 0x1d03, KEY_3 }, - { 0x1d04, KEY_4 }, - { 0x1d05, KEY_5 }, - { 0x1d06, KEY_6 }, - { 0x1d07, KEY_7 }, - { 0x1d08, KEY_8 }, - { 0x1d09, KEY_9 }, - { 0x1d0a, KEY_TEXT }, - { 0x1d0d, KEY_MENU }, - { 0x1d0f, KEY_MUTE }, - { 0x1d10, KEY_VOLUMEUP }, - { 0x1d11, KEY_VOLUMEDOWN }, - { 0x1d12, KEY_CHANNEL }, - { 0x1d14, KEY_UP }, - { 0x1d15, KEY_DOWN }, - { 0x1d16, KEY_LEFT }, - { 0x1d17, KEY_RIGHT }, - { 0x1d1c, KEY_TV }, - { 0x1d1e, KEY_NEXT }, - { 0x1d1f, KEY_BACK }, - { 0x1d20, KEY_CHANNELUP }, - { 0x1d21, KEY_CHANNELDOWN }, - { 0x1d24, KEY_LAST }, - { 0x1d25, KEY_OK }, - { 0x1d30, KEY_PAUSE }, - { 0x1d32, KEY_REWIND }, - { 0x1d34, KEY_FASTFORWARD }, - { 0x1d35, KEY_PLAY }, - { 0x1d36, KEY_STOP }, - { 0x1d37, KEY_RECORD }, - { 0x1d3b, KEY_GOTO }, - { 0x1d3d, KEY_POWER }, -}; - -static struct rc_map_list dib0700_rc5_map = { - .map = { - .scan = dib0700_rc5_table, - .size = ARRAY_SIZE(dib0700_rc5_table), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_DIB0700_RC5_TABLE, - } -}; - -static int __init init_rc_map(void) -{ - return rc_map_register(&dib0700_rc5_map); -} - -static void __exit exit_rc_map(void) -{ - rc_map_unregister(&dib0700_rc5_map); -} - -module_init(init_rc_map) -module_exit(exit_rc_map) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -/* - * DigitalNow TinyTwin remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -static struct rc_map_table digitalnow_tinytwin[] = { - { 0x0000, KEY_MUTE }, /* [symbol speaker] */ - { 0x0001, KEY_VOLUMEUP }, - { 0x0002, KEY_POWER2 }, /* TV [power button] */ - { 0x0003, KEY_2 }, - { 0x0004, KEY_3 }, - { 0x0005, KEY_4 }, - { 0x0006, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_NUMERIC_STAR }, /* [*] */ - { 0x000a, KEY_0 }, - { 0x000b, KEY_NUMERIC_POUND }, /* [#] */ - { 0x000c, KEY_RIGHT }, /* [right arrow] */ - { 0x000d, KEY_HOMEPAGE }, /* [symbol home] Start */ - { 0x000e, KEY_RED }, /* [red] Videos */ - { 0x0010, KEY_POWER }, /* PC [power button] */ - { 0x0011, KEY_YELLOW }, /* [yellow] Pictures */ - { 0x0012, KEY_DOWN }, /* [down arrow] */ - { 0x0013, KEY_GREEN }, /* [green] Music */ - { 0x0014, KEY_CYCLEWINDOWS }, /* BACK */ - { 0x0015, KEY_FAVORITES }, /* MORE */ - { 0x0016, KEY_UP }, /* [up arrow] */ - { 0x0017, KEY_LEFT }, /* [left arrow] */ - { 0x0018, KEY_OK }, /* OK */ - { 0x0019, KEY_BLUE }, /* [blue] MyTV */ - { 0x001a, KEY_REWIND }, /* REW [<<] */ - { 0x001b, KEY_PLAY }, /* PLAY */ - { 0x001c, KEY_5 }, - { 0x001d, KEY_9 }, - { 0x001e, KEY_VOLUMEDOWN }, - { 0x001f, KEY_1 }, - { 0x0040, KEY_STOP }, /* STOP */ - { 0x0042, KEY_PAUSE }, /* PAUSE */ - { 0x0043, KEY_SCREEN }, /* Aspect */ - { 0x0044, KEY_FORWARD }, /* FWD [>>] */ - { 0x0045, KEY_NEXT }, /* SKIP */ - { 0x0048, KEY_RECORD }, /* RECORD */ - { 0x0049, KEY_VIDEO }, /* RTV */ - { 0x004a, KEY_EPG }, /* Guide */ - { 0x004b, KEY_CHANNELUP }, - { 0x004c, KEY_HELP }, /* Help */ - { 0x004d, KEY_RADIO }, /* Radio */ - { 0x004f, KEY_CHANNELDOWN }, - { 0x0050, KEY_DVD }, /* DVD */ - { 0x0051, KEY_AUDIO }, /* Audio */ - { 0x0052, KEY_TITLE }, /* Title */ - { 0x0053, KEY_NEW }, /* [symbol PIP?] */ - { 0x0057, KEY_MENU }, /* Mouse */ - { 0x005a, KEY_PREVIOUS }, /* REPLAY */ -}; - -static struct rc_map_list digitalnow_tinytwin_map = { - .map = { - .scan = digitalnow_tinytwin, - .size = ARRAY_SIZE(digitalnow_tinytwin), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DIGITALNOW_TINYTWIN, - } -}; - -static int __init init_rc_map_digitalnow_tinytwin(void) -{ - return rc_map_register(&digitalnow_tinytwin_map); -} - -static void __exit exit_rc_map_digitalnow_tinytwin(void) -{ - rc_map_unregister(&digitalnow_tinytwin_map); -} - -module_init(init_rc_map_digitalnow_tinytwin) -module_exit(exit_rc_map_digitalnow_tinytwin) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-digittrade.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-digittrade.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-digittrade.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-digittrade.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* - * Digittrade DVB-T USB Stick remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -/* Digittrade DVB-T USB Stick remote controller. */ -/* Imported from af9015.h. - Initial keytable was from Alain Kalker */ - -/* Digittrade DVB-T USB Stick */ -static struct rc_map_table digittrade[] = { - { 0x0000, KEY_9 }, - { 0x0001, KEY_EPG }, /* EPG */ - { 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */ - { 0x0003, KEY_TEXT }, /* TELETEXT */ - { 0x0004, KEY_8 }, - { 0x0005, KEY_MUTE }, /* MUTE */ - { 0x0006, KEY_POWER2 }, /* POWER */ - { 0x0009, KEY_ZOOM }, /* FULLSCREEN */ - { 0x000a, KEY_RECORD }, /* RECORD */ - { 0x000d, KEY_SUBTITLE }, /* SUBTITLE */ - { 0x000e, KEY_STOP }, /* STOP */ - { 0x0010, KEY_OK }, /* RETURN */ - { 0x0011, KEY_2 }, - { 0x0012, KEY_4 }, - { 0x0015, KEY_3 }, - { 0x0016, KEY_5 }, - { 0x0017, KEY_CHANNELDOWN }, /* Ch Dn */ - { 0x0019, KEY_CHANNELUP }, /* CH Up */ - { 0x001a, KEY_PAUSE }, /* PAUSE */ - { 0x001b, KEY_1 }, - { 0x001d, KEY_AUDIO }, /* DUAL SOUND */ - { 0x001e, KEY_PLAY }, /* PLAY */ - { 0x001f, KEY_CAMERA }, /* SNAPSHOT */ - { 0x0040, KEY_VOLUMEUP }, /* Vol Up */ - { 0x0048, KEY_7 }, - { 0x004c, KEY_6 }, - { 0x004d, KEY_PLAYPAUSE }, /* TIMESHIFT */ - { 0x0054, KEY_0 }, -}; - -static struct rc_map_list digittrade_map = { - .map = { - .scan = digittrade, - .size = ARRAY_SIZE(digittrade), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DIGITTRADE, - } -}; - -static int __init init_rc_map_digittrade(void) -{ - return rc_map_register(&digittrade_map); -} - -static void __exit exit_rc_map_digittrade(void) -{ - rc_map_unregister(&digittrade_map); -} - -module_init(init_rc_map_digittrade) -module_exit(exit_rc_map_digittrade) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dm1105-nec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dm1105-nec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dm1105-nec.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dm1105-nec.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/* dm1105-nec.h - Keytable for dm1105_nec Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* DVBWorld remotes - Igor M. Liplianin - */ - -static struct rc_map_table dm1105_nec[] = { - { 0x0a, KEY_POWER2}, /* power */ - { 0x0c, KEY_MUTE}, /* mute */ - { 0x11, KEY_1}, - { 0x12, KEY_2}, - { 0x13, KEY_3}, - { 0x14, KEY_4}, - { 0x15, KEY_5}, - { 0x16, KEY_6}, - { 0x17, KEY_7}, - { 0x18, KEY_8}, - { 0x19, KEY_9}, - { 0x10, KEY_0}, - { 0x1c, KEY_CHANNELUP}, /* ch+ */ - { 0x0f, KEY_CHANNELDOWN}, /* ch- */ - { 0x1a, KEY_VOLUMEUP}, /* vol+ */ - { 0x0e, KEY_VOLUMEDOWN}, /* vol- */ - { 0x04, KEY_RECORD}, /* rec */ - { 0x09, KEY_CHANNEL}, /* fav */ - { 0x08, KEY_BACKSPACE}, /* rewind */ - { 0x07, KEY_FASTFORWARD}, /* fast */ - { 0x0b, KEY_PAUSE}, /* pause */ - { 0x02, KEY_ESC}, /* cancel */ - { 0x03, KEY_TAB}, /* tab */ - { 0x00, KEY_UP}, /* up */ - { 0x1f, KEY_ENTER}, /* ok */ - { 0x01, KEY_DOWN}, /* down */ - { 0x05, KEY_RECORD}, /* cap */ - { 0x06, KEY_STOP}, /* stop */ - { 0x40, KEY_ZOOM}, /* full */ - { 0x1e, KEY_TV}, /* tvmode */ - { 0x1b, KEY_B}, /* recall */ -}; - -static struct rc_map_list dm1105_nec_map = { - .map = { - .scan = dm1105_nec, - .size = ARRAY_SIZE(dm1105_nec), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_DM1105_NEC, - } -}; - -static int __init init_rc_map_dm1105_nec(void) -{ - return rc_map_register(&dm1105_nec_map); -} - -static void __exit exit_rc_map_dm1105_nec(void) -{ - rc_map_unregister(&dm1105_nec_map); -} - -module_init(init_rc_map_dm1105_nec) -module_exit(exit_rc_map_dm1105_nec) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* dntv-live-dvb-t.h - Keytable for dntv_live_dvb_t Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* DigitalNow DNTV Live DVB-T Remote */ - -static struct rc_map_table dntv_live_dvb_t[] = { - { 0x00, KEY_ESC }, /* 'go up a level?' */ - /* Keys 0 to 9 */ - { 0x0a, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x0b, KEY_TUNER }, /* tv/fm */ - { 0x0c, KEY_SEARCH }, /* scan */ - { 0x0d, KEY_STOP }, - { 0x0e, KEY_PAUSE }, - { 0x0f, KEY_VIDEO }, /* source */ - - { 0x10, KEY_MUTE }, - { 0x11, KEY_REWIND }, /* backward << */ - { 0x12, KEY_POWER }, - { 0x13, KEY_CAMERA }, /* snap */ - { 0x14, KEY_AUDIO }, /* stereo */ - { 0x15, KEY_CLEAR }, /* reset */ - { 0x16, KEY_PLAY }, - { 0x17, KEY_ENTER }, - { 0x18, KEY_ZOOM }, /* full screen */ - { 0x19, KEY_FASTFORWARD }, /* forward >> */ - { 0x1a, KEY_CHANNELUP }, - { 0x1b, KEY_VOLUMEUP }, - { 0x1c, KEY_INFO }, /* preview */ - { 0x1d, KEY_RECORD }, /* record */ - { 0x1e, KEY_CHANNELDOWN }, - { 0x1f, KEY_VOLUMEDOWN }, -}; - -static struct rc_map_list dntv_live_dvb_t_map = { - .map = { - .scan = dntv_live_dvb_t, - .size = ARRAY_SIZE(dntv_live_dvb_t), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_DNTV_LIVE_DVB_T, - } -}; - -static int __init init_rc_map_dntv_live_dvb_t(void) -{ - return rc_map_register(&dntv_live_dvb_t_map); -} - -static void __exit exit_rc_map_dntv_live_dvb_t(void) -{ - rc_map_unregister(&dntv_live_dvb_t_map); -} - -module_init(init_rc_map_dntv_live_dvb_t) -module_exit(exit_rc_map_dntv_live_dvb_t) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/* dntv-live-dvbt-pro.h - Keytable for dntv_live_dvbt_pro Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* DigitalNow DNTV Live! DVB-T Pro Remote */ - -static struct rc_map_table dntv_live_dvbt_pro[] = { - { 0x16, KEY_POWER }, - { 0x5b, KEY_HOME }, - - { 0x55, KEY_TV }, /* live tv */ - { 0x58, KEY_TUNER }, /* digital Radio */ - { 0x5a, KEY_RADIO }, /* FM radio */ - { 0x59, KEY_DVD }, /* dvd menu */ - { 0x03, KEY_1 }, - { 0x01, KEY_2 }, - { 0x06, KEY_3 }, - { 0x09, KEY_4 }, - { 0x1d, KEY_5 }, - { 0x1f, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x19, KEY_8 }, - { 0x1b, KEY_9 }, - { 0x0c, KEY_CANCEL }, - { 0x15, KEY_0 }, - { 0x4a, KEY_CLEAR }, - { 0x13, KEY_BACK }, - { 0x00, KEY_TAB }, - { 0x4b, KEY_UP }, - { 0x4e, KEY_LEFT }, - { 0x4f, KEY_OK }, - { 0x52, KEY_RIGHT }, - { 0x51, KEY_DOWN }, - { 0x1e, KEY_VOLUMEUP }, - { 0x0a, KEY_VOLUMEDOWN }, - { 0x02, KEY_CHANNELDOWN }, - { 0x05, KEY_CHANNELUP }, - { 0x11, KEY_RECORD }, - { 0x14, KEY_PLAY }, - { 0x4c, KEY_PAUSE }, - { 0x1a, KEY_STOP }, - { 0x40, KEY_REWIND }, - { 0x12, KEY_FASTFORWARD }, - { 0x41, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x42, KEY_NEXTSONG }, /* skip >| */ - { 0x54, KEY_CAMERA }, /* capture */ - { 0x50, KEY_LANGUAGE }, /* sap */ - { 0x47, KEY_TV2 }, /* pip */ - { 0x4d, KEY_SCREEN }, - { 0x43, KEY_SUBTITLE }, - { 0x10, KEY_MUTE }, - { 0x49, KEY_AUDIO }, /* l/r */ - { 0x07, KEY_SLEEP }, - { 0x08, KEY_VIDEO }, /* a/v */ - { 0x0e, KEY_PREVIOUS }, /* recall */ - { 0x45, KEY_ZOOM }, /* zoom + */ - { 0x46, KEY_ANGLE }, /* zoom - */ - { 0x56, KEY_RED }, - { 0x57, KEY_GREEN }, - { 0x5c, KEY_YELLOW }, - { 0x5d, KEY_BLUE }, -}; - -static struct rc_map_list dntv_live_dvbt_pro_map = { - .map = { - .scan = dntv_live_dvbt_pro, - .size = ARRAY_SIZE(dntv_live_dvbt_pro), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_DNTV_LIVE_DVBT_PRO, - } -}; - -static int __init init_rc_map_dntv_live_dvbt_pro(void) -{ - return rc_map_register(&dntv_live_dvbt_pro_map); -} - -static void __exit exit_rc_map_dntv_live_dvbt_pro(void) -{ - rc_map_unregister(&dntv_live_dvbt_pro_map); -} - -module_init(init_rc_map_dntv_live_dvbt_pro) -module_exit(exit_rc_map_dntv_live_dvbt_pro) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-em-terratec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-em-terratec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-em-terratec.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-em-terratec.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* em-terratec.h - Keytable for em_terratec Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table em_terratec[] = { - { 0x01, KEY_CHANNEL }, - { 0x02, KEY_SELECT }, - { 0x03, KEY_MUTE }, - { 0x04, KEY_POWER }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, - { 0x08, KEY_CHANNELUP }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, - { 0x0c, KEY_CHANNELDOWN }, - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, - { 0x10, KEY_VOLUMEUP }, - { 0x11, KEY_0 }, - { 0x12, KEY_MENU }, - { 0x13, KEY_PRINT }, - { 0x14, KEY_VOLUMEDOWN }, - { 0x16, KEY_PAUSE }, - { 0x18, KEY_RECORD }, - { 0x19, KEY_REWIND }, - { 0x1a, KEY_PLAY }, - { 0x1b, KEY_FORWARD }, - { 0x1c, KEY_BACKSPACE }, - { 0x1e, KEY_STOP }, - { 0x40, KEY_ZOOM }, -}; - -static struct rc_map_list em_terratec_map = { - .map = { - .scan = em_terratec, - .size = ARRAY_SIZE(em_terratec), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_EM_TERRATEC, - } -}; - -static int __init init_rc_map_em_terratec(void) -{ - return rc_map_register(&em_terratec_map); -} - -static void __exit exit_rc_map_em_terratec(void) -{ - rc_map_unregister(&em_terratec_map); -} - -module_init(init_rc_map_em_terratec) -module_exit(exit_rc_map_em_terratec) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -/* encore-enltv2.h - Keytable for encore_enltv2 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton - Mauro Carvalho Chehab */ - -static struct rc_map_table encore_enltv2[] = { - { 0x4c, KEY_POWER2 }, - { 0x4a, KEY_TUNER }, - { 0x40, KEY_1 }, - { 0x60, KEY_2 }, - { 0x50, KEY_3 }, - { 0x70, KEY_4 }, - { 0x48, KEY_5 }, - { 0x68, KEY_6 }, - { 0x58, KEY_7 }, - { 0x78, KEY_8 }, - { 0x44, KEY_9 }, - { 0x54, KEY_0 }, - - { 0x64, KEY_LAST }, /* +100 */ - { 0x4e, KEY_AGAIN }, /* Recall */ - - { 0x6c, KEY_VIDEO }, /* Video Source */ - { 0x5e, KEY_MENU }, - { 0x56, KEY_SCREEN }, - { 0x7a, KEY_SETUP }, - - { 0x46, KEY_MUTE }, - { 0x5c, KEY_MODE }, /* Stereo */ - { 0x74, KEY_INFO }, - { 0x7c, KEY_CLEAR }, - - { 0x55, KEY_UP }, - { 0x49, KEY_DOWN }, - { 0x7e, KEY_LEFT }, - { 0x59, KEY_RIGHT }, - { 0x6a, KEY_ENTER }, - - { 0x42, KEY_VOLUMEUP }, - { 0x62, KEY_VOLUMEDOWN }, - { 0x52, KEY_CHANNELUP }, - { 0x72, KEY_CHANNELDOWN }, - - { 0x41, KEY_RECORD }, - { 0x51, KEY_CAMERA }, /* Snapshot */ - { 0x75, KEY_TIME }, /* Timeshift */ - { 0x71, KEY_TV2 }, /* PIP */ - - { 0x45, KEY_REWIND }, - { 0x6f, KEY_PAUSE }, - { 0x7d, KEY_FORWARD }, - { 0x79, KEY_STOP }, -}; - -static struct rc_map_list encore_enltv2_map = { - .map = { - .scan = encore_enltv2, - .size = ARRAY_SIZE(encore_enltv2), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ENCORE_ENLTV2, - } -}; - -static int __init init_rc_map_encore_enltv2(void) -{ - return rc_map_register(&encore_enltv2_map); -} - -static void __exit exit_rc_map_encore_enltv2(void) -{ - rc_map_unregister(&encore_enltv2_map); -} - -module_init(init_rc_map_encore_enltv2) -module_exit(exit_rc_map_encore_enltv2) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/* encore-enltv.h - Keytable for encore_enltv Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons - Juan Pablo Sormani */ - -static struct rc_map_table encore_enltv[] = { - - /* Power button does nothing, neither in Windows app, - although it sends data (used for BIOS wakeup?) */ - { 0x0d, KEY_MUTE }, - - { 0x1e, KEY_TV }, - { 0x00, KEY_VIDEO }, - { 0x01, KEY_AUDIO }, /* music */ - { 0x02, KEY_CAMERA }, /* picture */ - - { 0x1f, KEY_1 }, - { 0x03, KEY_2 }, - { 0x04, KEY_3 }, - { 0x05, KEY_4 }, - { 0x1c, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x1d, KEY_9 }, - { 0x0a, KEY_0 }, - - { 0x09, KEY_LIST }, /* -/-- */ - { 0x0b, KEY_LAST }, /* recall */ - - { 0x14, KEY_HOME }, /* win start menu */ - { 0x15, KEY_EXIT }, /* exit */ - { 0x16, KEY_CHANNELUP }, /* UP */ - { 0x12, KEY_CHANNELDOWN }, /* DOWN */ - { 0x0c, KEY_VOLUMEUP }, /* RIGHT */ - { 0x17, KEY_VOLUMEDOWN }, /* LEFT */ - - { 0x18, KEY_ENTER }, /* OK */ - - { 0x0e, KEY_ESC }, - { 0x13, KEY_CYCLEWINDOWS }, /* desktop */ - { 0x11, KEY_TAB }, - { 0x19, KEY_SWITCHVIDEOMODE }, /* switch */ - - { 0x1a, KEY_MENU }, - { 0x1b, KEY_ZOOM }, /* fullscreen */ - { 0x44, KEY_TIME }, /* time shift */ - { 0x40, KEY_MODE }, /* source */ - - { 0x5a, KEY_RECORD }, - { 0x42, KEY_PLAY }, /* play/pause */ - { 0x45, KEY_STOP }, - { 0x43, KEY_CAMERA }, /* camera icon */ - - { 0x48, KEY_REWIND }, - { 0x4a, KEY_FASTFORWARD }, - { 0x49, KEY_PREVIOUS }, - { 0x4b, KEY_NEXT }, - - { 0x4c, KEY_FAVORITES }, /* tv wall */ - { 0x4d, KEY_SOUND }, /* DVD sound */ - { 0x4e, KEY_LANGUAGE }, /* DVD lang */ - { 0x4f, KEY_TEXT }, /* DVD text */ - - { 0x50, KEY_SLEEP }, /* shutdown */ - { 0x51, KEY_MODE }, /* stereo > main */ - { 0x52, KEY_SELECT }, /* stereo > sap */ - { 0x53, KEY_TEXT }, /* teletext */ - - - { 0x59, KEY_RED }, /* AP1 */ - { 0x41, KEY_GREEN }, /* AP2 */ - { 0x47, KEY_YELLOW }, /* AP3 */ - { 0x57, KEY_BLUE }, /* AP4 */ -}; - -static struct rc_map_list encore_enltv_map = { - .map = { - .scan = encore_enltv, - .size = ARRAY_SIZE(encore_enltv), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ENCORE_ENLTV, - } -}; - -static int __init init_rc_map_encore_enltv(void) -{ - return rc_map_register(&encore_enltv_map); -} - -static void __exit exit_rc_map_encore_enltv(void) -{ - rc_map_unregister(&encore_enltv_map); -} - -module_init(init_rc_map_encore_enltv) -module_exit(exit_rc_map_encore_enltv) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/* encore-enltv-fm53.h - Keytable for encore_enltv_fm53 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Encore ENLTV-FM v5.3 - Mauro Carvalho Chehab - */ - -static struct rc_map_table encore_enltv_fm53[] = { - { 0x10, KEY_POWER2}, - { 0x06, KEY_MUTE}, - - { 0x09, KEY_1}, - { 0x1d, KEY_2}, - { 0x1f, KEY_3}, - { 0x19, KEY_4}, - { 0x1b, KEY_5}, - { 0x11, KEY_6}, - { 0x17, KEY_7}, - { 0x12, KEY_8}, - { 0x16, KEY_9}, - { 0x48, KEY_0}, - - { 0x04, KEY_LIST}, /* -/-- */ - { 0x40, KEY_LAST}, /* recall */ - - { 0x02, KEY_MODE}, /* TV/AV */ - { 0x05, KEY_CAMERA}, /* SNAPSHOT */ - - { 0x4c, KEY_CHANNELUP}, /* UP */ - { 0x00, KEY_CHANNELDOWN}, /* DOWN */ - { 0x0d, KEY_VOLUMEUP}, /* RIGHT */ - { 0x15, KEY_VOLUMEDOWN}, /* LEFT */ - { 0x49, KEY_ENTER}, /* OK */ - - { 0x54, KEY_RECORD}, - { 0x4d, KEY_PLAY}, /* pause */ - - { 0x1e, KEY_MENU}, /* video setting */ - { 0x0e, KEY_RIGHT}, /* <- */ - { 0x1a, KEY_LEFT}, /* -> */ - - { 0x0a, KEY_CLEAR}, /* video default */ - { 0x0c, KEY_ZOOM}, /* hide pannel */ - { 0x47, KEY_SLEEP}, /* shutdown */ -}; - -static struct rc_map_list encore_enltv_fm53_map = { - .map = { - .scan = encore_enltv_fm53, - .size = ARRAY_SIZE(encore_enltv_fm53), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ENCORE_ENLTV_FM53, - } -}; - -static int __init init_rc_map_encore_enltv_fm53(void) -{ - return rc_map_register(&encore_enltv_fm53_map); -} - -static void __exit exit_rc_map_encore_enltv_fm53(void) -{ - rc_map_unregister(&encore_enltv_fm53_map); -} - -module_init(init_rc_map_encore_enltv_fm53) -module_exit(exit_rc_map_encore_enltv_fm53) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-evga-indtube.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-evga-indtube.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-evga-indtube.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-evga-indtube.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* evga-indtube.h - Keytable for evga_indtube Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* EVGA inDtube - Devin Heitmueller - */ - -static struct rc_map_table evga_indtube[] = { - { 0x12, KEY_POWER}, - { 0x02, KEY_MODE}, /* TV */ - { 0x14, KEY_MUTE}, - { 0x1a, KEY_CHANNELUP}, - { 0x16, KEY_TV2}, /* PIP */ - { 0x1d, KEY_VOLUMEUP}, - { 0x05, KEY_CHANNELDOWN}, - { 0x0f, KEY_PLAYPAUSE}, - { 0x19, KEY_VOLUMEDOWN}, - { 0x1c, KEY_REWIND}, - { 0x0d, KEY_RECORD}, - { 0x18, KEY_FORWARD}, - { 0x1e, KEY_PREVIOUS}, - { 0x1b, KEY_STOP}, - { 0x1f, KEY_NEXT}, - { 0x13, KEY_CAMERA}, -}; - -static struct rc_map_list evga_indtube_map = { - .map = { - .scan = evga_indtube, - .size = ARRAY_SIZE(evga_indtube), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_EVGA_INDTUBE, - } -}; - -static int __init init_rc_map_evga_indtube(void) -{ - return rc_map_register(&evga_indtube_map); -} - -static void __exit exit_rc_map_evga_indtube(void) -{ - rc_map_unregister(&evga_indtube_map); -} - -module_init(init_rc_map_evga_indtube) -module_exit(exit_rc_map_evga_indtube) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-eztv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-eztv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-eztv.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-eztv.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/* eztv.h - Keytable for eztv Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Alfons Geser - * updates from Job D. R. Borges */ - -static struct rc_map_table eztv[] = { - { 0x12, KEY_POWER }, - { 0x01, KEY_TV }, /* DVR */ - { 0x15, KEY_DVD }, /* DVD */ - { 0x17, KEY_AUDIO }, /* music */ - /* DVR mode / DVD mode / music mode */ - - { 0x1b, KEY_MUTE }, /* mute */ - { 0x02, KEY_LANGUAGE }, /* MTS/SAP / audio / autoseek */ - { 0x1e, KEY_SUBTITLE }, /* closed captioning / subtitle / seek */ - { 0x16, KEY_ZOOM }, /* full screen */ - { 0x1c, KEY_VIDEO }, /* video source / eject / delall */ - { 0x1d, KEY_RESTART }, /* playback / angle / del */ - { 0x2f, KEY_SEARCH }, /* scan / menu / playlist */ - { 0x30, KEY_CHANNEL }, /* CH surfing / bookmark / memo */ - - { 0x31, KEY_HELP }, /* help */ - { 0x32, KEY_MODE }, /* num/memo */ - { 0x33, KEY_ESC }, /* cancel */ - - { 0x0c, KEY_UP }, /* up */ - { 0x10, KEY_DOWN }, /* down */ - { 0x08, KEY_LEFT }, /* left */ - { 0x04, KEY_RIGHT }, /* right */ - { 0x03, KEY_SELECT }, /* select */ - - { 0x1f, KEY_REWIND }, /* rewind */ - { 0x20, KEY_PLAYPAUSE },/* play/pause */ - { 0x29, KEY_FORWARD }, /* forward */ - { 0x14, KEY_AGAIN }, /* repeat */ - { 0x2b, KEY_RECORD }, /* recording */ - { 0x2c, KEY_STOP }, /* stop */ - { 0x2d, KEY_PLAY }, /* play */ - { 0x2e, KEY_CAMERA }, /* snapshot / shuffle */ - - { 0x00, KEY_0 }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, - - { 0x2a, KEY_VOLUMEUP }, - { 0x11, KEY_VOLUMEDOWN }, - { 0x18, KEY_CHANNELUP },/* CH.tracking up */ - { 0x19, KEY_CHANNELDOWN },/* CH.tracking down */ - - { 0x13, KEY_ENTER }, /* enter */ - { 0x21, KEY_DOT }, /* . (decimal dot) */ -}; - -static struct rc_map_list eztv_map = { - .map = { - .scan = eztv, - .size = ARRAY_SIZE(eztv), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_EZTV, - } -}; - -static int __init init_rc_map_eztv(void) -{ - return rc_map_register(&eztv_map); -} - -static void __exit exit_rc_map_eztv(void) -{ - rc_map_unregister(&eztv_map); -} - -module_init(init_rc_map_eztv) -module_exit(exit_rc_map_eztv) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-flydvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-flydvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-flydvb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-flydvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/* flydvb.h - Keytable for flydvb Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table flydvb[] = { - { 0x01, KEY_ZOOM }, /* Full Screen */ - { 0x00, KEY_POWER }, /* Power */ - - { 0x03, KEY_1 }, - { 0x04, KEY_2 }, - { 0x05, KEY_3 }, - { 0x07, KEY_4 }, - { 0x08, KEY_5 }, - { 0x09, KEY_6 }, - { 0x0b, KEY_7 }, - { 0x0c, KEY_8 }, - { 0x0d, KEY_9 }, - { 0x06, KEY_AGAIN }, /* Recall */ - { 0x0f, KEY_0 }, - { 0x10, KEY_MUTE }, /* Mute */ - { 0x02, KEY_RADIO }, /* TV/Radio */ - { 0x1b, KEY_LANGUAGE }, /* SAP (Second Audio Program) */ - - { 0x14, KEY_VOLUMEUP }, /* VOL+ */ - { 0x17, KEY_VOLUMEDOWN }, /* VOL- */ - { 0x12, KEY_CHANNELUP }, /* CH+ */ - { 0x13, KEY_CHANNELDOWN }, /* CH- */ - { 0x1d, KEY_ENTER }, /* Enter */ - - { 0x1a, KEY_TV2 }, /* PIP */ - { 0x18, KEY_VIDEO }, /* Source */ - - { 0x1e, KEY_RECORD }, /* Record/Pause */ - { 0x15, KEY_ANGLE }, /* Swap (no label on key) */ - { 0x1c, KEY_PAUSE }, /* Timeshift/Pause */ - { 0x19, KEY_BACK }, /* Rewind << */ - { 0x0a, KEY_PLAYPAUSE }, /* Play/Pause */ - { 0x1f, KEY_FORWARD }, /* Forward >> */ - { 0x16, KEY_PREVIOUS }, /* Back |<< */ - { 0x11, KEY_STOP }, /* Stop */ - { 0x0e, KEY_NEXT }, /* End >>| */ -}; - -static struct rc_map_list flydvb_map = { - .map = { - .scan = flydvb, - .size = ARRAY_SIZE(flydvb), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_FLYDVB, - } -}; - -static int __init init_rc_map_flydvb(void) -{ - return rc_map_register(&flydvb_map); -} - -static void __exit exit_rc_map_flydvb(void) -{ - rc_map_unregister(&flydvb_map); -} - -module_init(init_rc_map_flydvb) -module_exit(exit_rc_map_flydvb) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-flyvideo.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-flyvideo.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-flyvideo.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-flyvideo.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/* flyvideo.h - Keytable for flyvideo Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table flyvideo[] = { - { 0x0f, KEY_0 }, - { 0x03, KEY_1 }, - { 0x04, KEY_2 }, - { 0x05, KEY_3 }, - { 0x07, KEY_4 }, - { 0x08, KEY_5 }, - { 0x09, KEY_6 }, - { 0x0b, KEY_7 }, - { 0x0c, KEY_8 }, - { 0x0d, KEY_9 }, - - { 0x0e, KEY_MODE }, /* Air/Cable */ - { 0x11, KEY_VIDEO }, /* Video */ - { 0x15, KEY_AUDIO }, /* Audio */ - { 0x00, KEY_POWER }, /* Power */ - { 0x18, KEY_TUNER }, /* AV Source */ - { 0x02, KEY_ZOOM }, /* Fullscreen */ - { 0x1a, KEY_LANGUAGE }, /* Stereo */ - { 0x1b, KEY_MUTE }, /* Mute */ - { 0x14, KEY_VOLUMEUP }, /* Volume + */ - { 0x17, KEY_VOLUMEDOWN },/* Volume - */ - { 0x12, KEY_CHANNELUP },/* Channel + */ - { 0x13, KEY_CHANNELDOWN },/* Channel - */ - { 0x06, KEY_AGAIN }, /* Recall */ - { 0x10, KEY_ENTER }, /* Enter */ - - { 0x19, KEY_BACK }, /* Rewind ( <<< ) */ - { 0x1f, KEY_FORWARD }, /* Forward ( >>> ) */ - { 0x0a, KEY_ANGLE }, /* no label, may be used as the PAUSE button */ -}; - -static struct rc_map_list flyvideo_map = { - .map = { - .scan = flyvideo, - .size = ARRAY_SIZE(flyvideo), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_FLYVIDEO, - } -}; - -static int __init init_rc_map_flyvideo(void) -{ - return rc_map_register(&flyvideo_map); -} - -static void __exit exit_rc_map_flyvideo(void) -{ - rc_map_unregister(&flyvideo_map); -} - -module_init(init_rc_map_flyvideo) -module_exit(exit_rc_map_flyvideo) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -/* fusionhdtv-mce.h - Keytable for fusionhdtv_mce Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* DViCO FUSION HDTV MCE remote */ - -static struct rc_map_table fusionhdtv_mce[] = { - - { 0x0b, KEY_1 }, - { 0x17, KEY_2 }, - { 0x1b, KEY_3 }, - { 0x07, KEY_4 }, - { 0x50, KEY_5 }, - { 0x54, KEY_6 }, - { 0x48, KEY_7 }, - { 0x4c, KEY_8 }, - { 0x58, KEY_9 }, - { 0x03, KEY_0 }, - - { 0x5e, KEY_OK }, - { 0x51, KEY_UP }, - { 0x53, KEY_DOWN }, - { 0x5b, KEY_LEFT }, - { 0x5f, KEY_RIGHT }, - - { 0x02, KEY_TV }, /* Labeled DTV on remote */ - { 0x0e, KEY_MP3 }, - { 0x1a, KEY_DVD }, - { 0x1e, KEY_FAVORITES }, /* Labeled CPF on remote */ - { 0x16, KEY_SETUP }, - { 0x46, KEY_POWER2 }, /* TV On/Off button on remote */ - { 0x0a, KEY_EPG }, /* Labeled Guide on remote */ - - { 0x49, KEY_BACK }, - { 0x59, KEY_INFO }, /* Labeled MORE on remote */ - { 0x4d, KEY_MENU }, /* Labeled DVDMENU on remote */ - { 0x55, KEY_CYCLEWINDOWS }, /* Labeled ALT-TAB on remote */ - - { 0x0f, KEY_PREVIOUSSONG }, /* Labeled |<< REPLAY on remote */ - { 0x12, KEY_NEXTSONG }, /* Labeled >>| SKIP on remote */ - { 0x42, KEY_ENTER }, /* Labeled START with a green - MS windows logo on remote */ - - { 0x15, KEY_VOLUMEUP }, - { 0x05, KEY_VOLUMEDOWN }, - { 0x11, KEY_CHANNELUP }, - { 0x09, KEY_CHANNELDOWN }, - - { 0x52, KEY_CAMERA }, - { 0x5a, KEY_TUNER }, - { 0x19, KEY_OPEN }, - - { 0x13, KEY_MODE }, /* 4:3 16:9 select */ - { 0x1f, KEY_ZOOM }, - - { 0x43, KEY_REWIND }, - { 0x47, KEY_PLAYPAUSE }, - { 0x4f, KEY_FASTFORWARD }, - { 0x57, KEY_MUTE }, - { 0x0d, KEY_STOP }, - { 0x01, KEY_RECORD }, - { 0x4e, KEY_POWER }, -}; - -static struct rc_map_list fusionhdtv_mce_map = { - .map = { - .scan = fusionhdtv_mce, - .size = ARRAY_SIZE(fusionhdtv_mce), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_FUSIONHDTV_MCE, - } -}; - -static int __init init_rc_map_fusionhdtv_mce(void) -{ - return rc_map_register(&fusionhdtv_mce_map); -} - -static void __exit exit_rc_map_fusionhdtv_mce(void) -{ - rc_map_unregister(&fusionhdtv_mce_map); -} - -module_init(init_rc_map_fusionhdtv_mce) -module_exit(exit_rc_map_fusionhdtv_mce) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-gadmei-rm008z.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-gadmei-rm008z.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-gadmei-rm008z.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-gadmei-rm008z.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/* gadmei-rm008z.h - Keytable for gadmei_rm008z Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* GADMEI UTV330+ RM008Z remote - Shine Liu - */ - -static struct rc_map_table gadmei_rm008z[] = { - { 0x14, KEY_POWER2}, /* POWER OFF */ - { 0x0c, KEY_MUTE}, /* MUTE */ - - { 0x18, KEY_TV}, /* TV */ - { 0x0e, KEY_VIDEO}, /* AV */ - { 0x0b, KEY_AUDIO}, /* SV */ - { 0x0f, KEY_RADIO}, /* FM */ - - { 0x00, KEY_1}, - { 0x01, KEY_2}, - { 0x02, KEY_3}, - { 0x03, KEY_4}, - { 0x04, KEY_5}, - { 0x05, KEY_6}, - { 0x06, KEY_7}, - { 0x07, KEY_8}, - { 0x08, KEY_9}, - { 0x09, KEY_0}, - { 0x0a, KEY_INFO}, /* OSD */ - { 0x1c, KEY_BACKSPACE}, /* LAST */ - - { 0x0d, KEY_PLAY}, /* PLAY */ - { 0x1e, KEY_CAMERA}, /* SNAPSHOT */ - { 0x1a, KEY_RECORD}, /* RECORD */ - { 0x17, KEY_STOP}, /* STOP */ - - { 0x1f, KEY_UP}, /* UP */ - { 0x44, KEY_DOWN}, /* DOWN */ - { 0x46, KEY_TAB}, /* BACK */ - { 0x4a, KEY_ZOOM}, /* FULLSECREEN */ - - { 0x10, KEY_VOLUMEUP}, /* VOLUMEUP */ - { 0x11, KEY_VOLUMEDOWN}, /* VOLUMEDOWN */ - { 0x12, KEY_CHANNELUP}, /* CHANNELUP */ - { 0x13, KEY_CHANNELDOWN}, /* CHANNELDOWN */ - { 0x15, KEY_ENTER}, /* OK */ -}; - -static struct rc_map_list gadmei_rm008z_map = { - .map = { - .scan = gadmei_rm008z, - .size = ARRAY_SIZE(gadmei_rm008z), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_GADMEI_RM008Z, - } -}; - -static int __init init_rc_map_gadmei_rm008z(void) -{ - return rc_map_register(&gadmei_rm008z_map); -} - -static void __exit exit_rc_map_gadmei_rm008z(void) -{ - rc_map_unregister(&gadmei_rm008z_map); -} - -module_init(init_rc_map_gadmei_rm008z) -module_exit(exit_rc_map_gadmei_rm008z) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/* genius-tvgo-a11mce.h - Keytable for genius_tvgo_a11mce Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Remote control for the Genius TVGO A11MCE - * Adrian Pardini - */ - -static struct rc_map_table genius_tvgo_a11mce[] = { - /* Keys 0 to 9 */ - { 0x48, KEY_0 }, - { 0x09, KEY_1 }, - { 0x1d, KEY_2 }, - { 0x1f, KEY_3 }, - { 0x19, KEY_4 }, - { 0x1b, KEY_5 }, - { 0x11, KEY_6 }, - { 0x17, KEY_7 }, - { 0x12, KEY_8 }, - { 0x16, KEY_9 }, - - { 0x54, KEY_RECORD }, /* recording */ - { 0x06, KEY_MUTE }, /* mute */ - { 0x10, KEY_POWER }, - { 0x40, KEY_LAST }, /* recall */ - { 0x4c, KEY_CHANNELUP }, /* channel / program + */ - { 0x00, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x0d, KEY_VOLUMEUP }, - { 0x15, KEY_VOLUMEDOWN }, - { 0x4d, KEY_OK }, /* also labeled as Pause */ - { 0x1c, KEY_ZOOM }, /* full screen and Stop*/ - { 0x02, KEY_MODE }, /* AV Source or Rewind*/ - { 0x04, KEY_LIST }, /* -/-- */ - /* small arrows above numbers */ - { 0x1a, KEY_NEXT }, /* also Fast Forward */ - { 0x0e, KEY_PREVIOUS }, /* also Rewind */ - /* these are in a rather non standard layout and have - an alternate name written */ - { 0x1e, KEY_UP }, /* Video Setting */ - { 0x0a, KEY_DOWN }, /* Video Default */ - { 0x05, KEY_CAMERA }, /* Snapshot */ - { 0x0c, KEY_RIGHT }, /* Hide Panel */ - /* Four buttons without label */ - { 0x49, KEY_RED }, - { 0x0b, KEY_GREEN }, - { 0x13, KEY_YELLOW }, - { 0x50, KEY_BLUE }, -}; - -static struct rc_map_list genius_tvgo_a11mce_map = { - .map = { - .scan = genius_tvgo_a11mce, - .size = ARRAY_SIZE(genius_tvgo_a11mce), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_GENIUS_TVGO_A11MCE, - } -}; - -static int __init init_rc_map_genius_tvgo_a11mce(void) -{ - return rc_map_register(&genius_tvgo_a11mce_map); -} - -static void __exit exit_rc_map_genius_tvgo_a11mce(void) -{ - rc_map_unregister(&genius_tvgo_a11mce_map); -} - -module_init(init_rc_map_genius_tvgo_a11mce) -module_exit(exit_rc_map_genius_tvgo_a11mce) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-gotview7135.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-gotview7135.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-gotview7135.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-gotview7135.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/* gotview7135.h - Keytable for gotview7135 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Mike Baikov */ - -static struct rc_map_table gotview7135[] = { - - { 0x11, KEY_POWER }, - { 0x35, KEY_TV }, - { 0x1b, KEY_0 }, - { 0x29, KEY_1 }, - { 0x19, KEY_2 }, - { 0x39, KEY_3 }, - { 0x1f, KEY_4 }, - { 0x2c, KEY_5 }, - { 0x21, KEY_6 }, - { 0x24, KEY_7 }, - { 0x18, KEY_8 }, - { 0x2b, KEY_9 }, - { 0x3b, KEY_AGAIN }, /* LOOP */ - { 0x06, KEY_AUDIO }, - { 0x31, KEY_PRINT }, /* PREVIEW */ - { 0x3e, KEY_VIDEO }, - { 0x10, KEY_CHANNELUP }, - { 0x20, KEY_CHANNELDOWN }, - { 0x0c, KEY_VOLUMEDOWN }, - { 0x28, KEY_VOLUMEUP }, - { 0x08, KEY_MUTE }, - { 0x26, KEY_SEARCH }, /* SCAN */ - { 0x3f, KEY_CAMERA }, /* SNAPSHOT */ - { 0x12, KEY_RECORD }, - { 0x32, KEY_STOP }, - { 0x3c, KEY_PLAY }, - { 0x1d, KEY_REWIND }, - { 0x2d, KEY_PAUSE }, - { 0x0d, KEY_FORWARD }, - { 0x05, KEY_ZOOM }, /*FULL*/ - - { 0x2a, KEY_F21 }, /* LIVE TIMESHIFT */ - { 0x0e, KEY_F22 }, /* MIN TIMESHIFT */ - { 0x1e, KEY_TIME }, /* TIMESHIFT */ - { 0x38, KEY_F24 }, /* NORMAL TIMESHIFT */ -}; - -static struct rc_map_list gotview7135_map = { - .map = { - .scan = gotview7135, - .size = ARRAY_SIZE(gotview7135), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_GOTVIEW7135, - } -}; - -static int __init init_rc_map_gotview7135(void) -{ - return rc_map_register(&gotview7135_map); -} - -static void __exit exit_rc_map_gotview7135(void) -{ - rc_map_unregister(&gotview7135_map); -} - -module_init(init_rc_map_gotview7135) -module_exit(exit_rc_map_gotview7135) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-hauppauge.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-hauppauge.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-hauppauge.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-hauppauge.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,241 +0,0 @@ -/* rc-hauppauge.c - Keytable for Hauppauge Remote Controllers - * - * keymap imported from ir-keymaps.c - * - * This map currently contains the code for four different RCs: - * - New Hauppauge Gray; - * - Old Hauppauge Gray (with a golden screen for media keys); - * - Hauppauge Black; - * - DSR-0112 remote bundled with Haupauge MiniStick. - * - * Copyright (c) 2010-2011 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Hauppauge:the newer, gray remotes (seems there are multiple - * slightly different versions), shipped with cx88+ivtv cards. - * - * This table contains the complete RC5 code, instead of just the data part - */ - -static struct rc_map_table rc5_hauppauge_new[] = { - /* - * Remote Controller Hauppauge Gray found on modern devices - * Keycodes start with address = 0x1e - */ - - { 0x1e3b, KEY_SELECT }, /* GO / house symbol */ - { 0x1e3d, KEY_POWER2 }, /* system power (green button) */ - - { 0x1e1c, KEY_TV }, - { 0x1e18, KEY_VIDEO }, /* Videos */ - { 0x1e19, KEY_AUDIO }, /* Music */ - { 0x1e1a, KEY_CAMERA }, /* Pictures */ - - { 0x1e1b, KEY_EPG }, /* Guide */ - { 0x1e0c, KEY_RADIO }, - - { 0x1e14, KEY_UP }, - { 0x1e15, KEY_DOWN }, - { 0x1e16, KEY_LEFT }, - { 0x1e17, KEY_RIGHT }, - { 0x1e25, KEY_OK }, /* OK */ - - { 0x1e1f, KEY_EXIT }, /* back/exit */ - { 0x1e0d, KEY_MENU }, - - { 0x1e10, KEY_VOLUMEUP }, - { 0x1e11, KEY_VOLUMEDOWN }, - - { 0x1e12, KEY_PREVIOUS }, /* previous channel */ - { 0x1e0f, KEY_MUTE }, - - { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ - { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ - - { 0x1e37, KEY_RECORD }, /* recording */ - { 0x1e36, KEY_STOP }, - - { 0x1e32, KEY_REWIND }, /* backward << */ - { 0x1e35, KEY_PLAY }, - { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ - - { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x1e30, KEY_PAUSE }, /* pause */ - { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ - - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, - - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, - - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, - - { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ - { 0x1e00, KEY_0 }, - { 0x1e0e, KEY_SUBTITLE }, /* also the Pound key (#) */ - - { 0x1e0b, KEY_RED }, /* red button */ - { 0x1e2e, KEY_GREEN }, /* green button */ - { 0x1e38, KEY_YELLOW }, /* yellow key */ - { 0x1e29, KEY_BLUE }, /* blue key */ - - /* - * Old Remote Controller Hauppauge Gray with a golden screen - * Keycodes start with address = 0x1f - */ - { 0x1f3d, KEY_POWER2 }, /* system power (green button) */ - { 0x1f3b, KEY_SELECT }, /* GO */ - - /* Keys 0 to 9 */ - { 0x1f00, KEY_0 }, - { 0x1f01, KEY_1 }, - { 0x1f02, KEY_2 }, - { 0x1f03, KEY_3 }, - { 0x1f04, KEY_4 }, - { 0x1f05, KEY_5 }, - { 0x1f06, KEY_6 }, - { 0x1f07, KEY_7 }, - { 0x1f08, KEY_8 }, - { 0x1f09, KEY_9 }, - - { 0x1f1f, KEY_EXIT }, /* back/exit */ - { 0x1f0d, KEY_MENU }, - - { 0x1f10, KEY_VOLUMEUP }, - { 0x1f11, KEY_VOLUMEDOWN }, - { 0x1f20, KEY_CHANNELUP }, /* channel / program + */ - { 0x1f21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x1f25, KEY_ENTER }, /* OK */ - - { 0x1f0b, KEY_RED }, /* red button */ - { 0x1f2e, KEY_GREEN }, /* green button */ - { 0x1f38, KEY_YELLOW }, /* yellow key */ - { 0x1f29, KEY_BLUE }, /* blue key */ - - { 0x1f0f, KEY_MUTE }, - { 0x1f0c, KEY_RADIO }, /* There's no indicator on this key */ - { 0x1f3c, KEY_ZOOM }, /* full */ - - { 0x1f32, KEY_REWIND }, /* backward << */ - { 0x1f35, KEY_PLAY }, - { 0x1f34, KEY_FASTFORWARD }, /* forward >> */ - - { 0x1f37, KEY_RECORD }, /* recording */ - { 0x1f36, KEY_STOP }, - { 0x1f30, KEY_PAUSE }, /* pause */ - - { 0x1f24, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x1f1e, KEY_NEXTSONG }, /* skip >| */ - - /* - * Keycodes for DSR-0112 remote bundled with Haupauge MiniStick - * Keycodes start with address = 0x1d - */ - { 0x1d00, KEY_0 }, - { 0x1d01, KEY_1 }, - { 0x1d02, KEY_2 }, - { 0x1d03, KEY_3 }, - { 0x1d04, KEY_4 }, - { 0x1d05, KEY_5 }, - { 0x1d06, KEY_6 }, - { 0x1d07, KEY_7 }, - { 0x1d08, KEY_8 }, - { 0x1d09, KEY_9 }, - { 0x1d0a, KEY_TEXT }, - { 0x1d0d, KEY_MENU }, - { 0x1d0f, KEY_MUTE }, - { 0x1d10, KEY_VOLUMEUP }, - { 0x1d11, KEY_VOLUMEDOWN }, - { 0x1d12, KEY_PREVIOUS }, /* Prev.Ch .. ??? */ - { 0x1d14, KEY_UP }, - { 0x1d15, KEY_DOWN }, - { 0x1d16, KEY_LEFT }, - { 0x1d17, KEY_RIGHT }, - { 0x1d1c, KEY_TV }, - { 0x1d1e, KEY_NEXT }, /* >| */ - { 0x1d1f, KEY_EXIT }, - { 0x1d20, KEY_CHANNELUP }, - { 0x1d21, KEY_CHANNELDOWN }, - { 0x1d24, KEY_LAST }, /* <| */ - { 0x1d25, KEY_OK }, - { 0x1d30, KEY_PAUSE }, - { 0x1d32, KEY_REWIND }, - { 0x1d34, KEY_FASTFORWARD }, - { 0x1d35, KEY_PLAY }, - { 0x1d36, KEY_STOP }, - { 0x1d37, KEY_RECORD }, - { 0x1d3b, KEY_GOTO }, - { 0x1d3d, KEY_POWER }, - { 0x1d3f, KEY_HOME }, - - /* - * Keycodes for the old Black Remote Controller - * This one also uses RC-5 protocol - * Keycodes start with address = 0x00 - */ - { 0x001f, KEY_TV }, - { 0x0020, KEY_CHANNELUP }, - { 0x000c, KEY_RADIO }, - - { 0x0011, KEY_VOLUMEDOWN }, - { 0x002e, KEY_ZOOM }, /* full screen */ - { 0x0010, KEY_VOLUMEUP }, - - { 0x000d, KEY_MUTE }, - { 0x0021, KEY_CHANNELDOWN }, - { 0x0022, KEY_VIDEO }, /* source */ - - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, - - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, - - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, - - { 0x001e, KEY_RED }, /* Reserved */ - { 0x0000, KEY_0 }, - { 0x0026, KEY_SLEEP }, /* Minimize */ -}; - -static struct rc_map_list rc5_hauppauge_new_map = { - .map = { - .scan = rc5_hauppauge_new, - .size = ARRAY_SIZE(rc5_hauppauge_new), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_HAUPPAUGE, - } -}; - -static int __init init_rc_map_rc5_hauppauge_new(void) -{ - return rc_map_register(&rc5_hauppauge_new_map); -} - -static void __exit exit_rc_map_rc5_hauppauge_new(void) -{ - rc_map_unregister(&rc5_hauppauge_new_map); -} - -module_init(init_rc_map_rc5_hauppauge_new) -module_exit(exit_rc_map_rc5_hauppauge_new) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-hauppauge-new.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-hauppauge-new.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-hauppauge-new.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-hauppauge-new.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -/* hauppauge-new.h - Keytable for hauppauge_new Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Hauppauge: the newer, gray remotes (seems there are multiple - * slightly different versions), shipped with cx88+ivtv cards. - * almost rc5 coding, but some non-standard keys */ - -static struct rc_map_table hauppauge_new[] = { - /* Keys 0 to 9 */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x0a, KEY_TEXT }, /* keypad asterisk as well */ - { 0x0b, KEY_RED }, /* red button */ - { 0x0c, KEY_RADIO }, - { 0x0d, KEY_MENU }, - { 0x0e, KEY_SUBTITLE }, /* also the # key */ - { 0x0f, KEY_MUTE }, - { 0x10, KEY_VOLUMEUP }, - { 0x11, KEY_VOLUMEDOWN }, - { 0x12, KEY_PREVIOUS }, /* previous channel */ - { 0x14, KEY_UP }, - { 0x15, KEY_DOWN }, - { 0x16, KEY_LEFT }, - { 0x17, KEY_RIGHT }, - { 0x18, KEY_VIDEO }, /* Videos */ - { 0x19, KEY_AUDIO }, /* Music */ - /* 0x1a: Pictures - presume this means - "Multimedia Home Platform" - - no "PICTURES" key in input.h - */ - { 0x1a, KEY_MHP }, - - { 0x1b, KEY_EPG }, /* Guide */ - { 0x1c, KEY_TV }, - { 0x1e, KEY_NEXTSONG }, /* skip >| */ - { 0x1f, KEY_EXIT }, /* back/exit */ - { 0x20, KEY_CHANNELUP }, /* channel / program + */ - { 0x21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x22, KEY_CHANNEL }, /* source (old black remote) */ - { 0x24, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x25, KEY_ENTER }, /* OK */ - { 0x26, KEY_SLEEP }, /* minimize (old black remote) */ - { 0x29, KEY_BLUE }, /* blue key */ - { 0x2e, KEY_GREEN }, /* green button */ - { 0x30, KEY_PAUSE }, /* pause */ - { 0x32, KEY_REWIND }, /* backward << */ - { 0x34, KEY_FASTFORWARD }, /* forward >> */ - { 0x35, KEY_PLAY }, - { 0x36, KEY_STOP }, - { 0x37, KEY_RECORD }, /* recording */ - { 0x38, KEY_YELLOW }, /* yellow key */ - { 0x3b, KEY_SELECT }, /* top right button */ - { 0x3c, KEY_ZOOM }, /* full */ - { 0x3d, KEY_POWER }, /* system power (green button) */ -}; - -static struct rc_map_list hauppauge_new_map = { - .map = { - .scan = hauppauge_new, - .size = ARRAY_SIZE(hauppauge_new), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_HAUPPAUGE_NEW, - } -}; - -static int __init init_rc_map_hauppauge_new(void) -{ - return rc_map_register(&hauppauge_new_map); -} - -static void __exit exit_rc_map_hauppauge_new(void) -{ - rc_map_unregister(&hauppauge_new_map); -} - -module_init(init_rc_map_hauppauge_new) -module_exit(exit_rc_map_hauppauge_new) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-imon-mce.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-imon-mce.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-imon-mce.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-imon-mce.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,142 +0,0 @@ -/* rc5-imon-mce.c - Keytable for Windows Media Center RC-6 remotes for use - * with the SoundGraph iMON/Antec Veris hardware IR decoder - * - * Copyright (c) 2010 by Jarod Wilson - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* mce-mode imon mce remote key table */ -static struct rc_map_table imon_mce[] = { - /* keys sorted mostly by frequency of use to optimize lookups */ - { 0x800ff415, KEY_REWIND }, - { 0x800ff414, KEY_FASTFORWARD }, - { 0x800ff41b, KEY_PREVIOUS }, - { 0x800ff41a, KEY_NEXT }, - - { 0x800ff416, KEY_PLAY }, - { 0x800ff418, KEY_PAUSE }, - { 0x800ff419, KEY_STOP }, - { 0x800ff417, KEY_RECORD }, - - { 0x02000052, KEY_UP }, - { 0x02000051, KEY_DOWN }, - { 0x02000050, KEY_LEFT }, - { 0x0200004f, KEY_RIGHT }, - - { 0x800ff41e, KEY_UP }, - { 0x800ff41f, KEY_DOWN }, - { 0x800ff420, KEY_LEFT }, - { 0x800ff421, KEY_RIGHT }, - - /* 0x800ff40b also KEY_NUMERIC_POUND on some receivers */ - { 0x800ff40b, KEY_ENTER }, - { 0x02000028, KEY_ENTER }, -/* the OK and Enter buttons decode to the same value on some remotes - { 0x02000028, KEY_OK }, */ - { 0x800ff422, KEY_OK }, - { 0x0200002a, KEY_EXIT }, - { 0x800ff423, KEY_EXIT }, - { 0x02000029, KEY_DELETE }, - /* 0x800ff40a also KEY_NUMERIC_STAR on some receivers */ - { 0x800ff40a, KEY_DELETE }, - - { 0x800ff40e, KEY_MUTE }, - { 0x800ff410, KEY_VOLUMEUP }, - { 0x800ff411, KEY_VOLUMEDOWN }, - { 0x800ff412, KEY_CHANNELUP }, - { 0x800ff413, KEY_CHANNELDOWN }, - - { 0x0200001e, KEY_NUMERIC_1 }, - { 0x0200001f, KEY_NUMERIC_2 }, - { 0x02000020, KEY_NUMERIC_3 }, - { 0x02000021, KEY_NUMERIC_4 }, - { 0x02000022, KEY_NUMERIC_5 }, - { 0x02000023, KEY_NUMERIC_6 }, - { 0x02000024, KEY_NUMERIC_7 }, - { 0x02000025, KEY_NUMERIC_8 }, - { 0x02000026, KEY_NUMERIC_9 }, - { 0x02000027, KEY_NUMERIC_0 }, - - { 0x800ff401, KEY_NUMERIC_1 }, - { 0x800ff402, KEY_NUMERIC_2 }, - { 0x800ff403, KEY_NUMERIC_3 }, - { 0x800ff404, KEY_NUMERIC_4 }, - { 0x800ff405, KEY_NUMERIC_5 }, - { 0x800ff406, KEY_NUMERIC_6 }, - { 0x800ff407, KEY_NUMERIC_7 }, - { 0x800ff408, KEY_NUMERIC_8 }, - { 0x800ff409, KEY_NUMERIC_9 }, - { 0x800ff400, KEY_NUMERIC_0 }, - - { 0x02200025, KEY_NUMERIC_STAR }, - { 0x02200020, KEY_NUMERIC_POUND }, - /* 0x800ff41d also KEY_BLUE on some receivers */ - { 0x800ff41d, KEY_NUMERIC_STAR }, - /* 0x800ff41c also KEY_PREVIOUS on some receivers */ - { 0x800ff41c, KEY_NUMERIC_POUND }, - - { 0x800ff446, KEY_TV }, - { 0x800ff447, KEY_AUDIO }, /* My Music */ - { 0x800ff448, KEY_PVR }, /* RecordedTV */ - { 0x800ff449, KEY_CAMERA }, - { 0x800ff44a, KEY_VIDEO }, - /* 0x800ff424 also KEY_MENU on some receivers */ - { 0x800ff424, KEY_DVD }, - /* 0x800ff425 also KEY_GREEN on some receivers */ - { 0x800ff425, KEY_TUNER }, /* LiveTV */ - { 0x800ff450, KEY_RADIO }, - - { 0x800ff44c, KEY_LANGUAGE }, - { 0x800ff427, KEY_ZOOM }, /* Aspect */ - - { 0x800ff45b, KEY_RED }, - { 0x800ff45c, KEY_GREEN }, - { 0x800ff45d, KEY_YELLOW }, - { 0x800ff45e, KEY_BLUE }, - - { 0x800ff466, KEY_RED }, - /* { 0x800ff425, KEY_GREEN }, */ - { 0x800ff468, KEY_YELLOW }, - /* { 0x800ff41d, KEY_BLUE }, */ - - { 0x800ff40f, KEY_INFO }, - { 0x800ff426, KEY_EPG }, /* Guide */ - { 0x800ff45a, KEY_SUBTITLE }, /* Caption/Teletext */ - { 0x800ff44d, KEY_TITLE }, - - { 0x800ff40c, KEY_POWER }, - { 0x800ff40d, KEY_LEFTMETA }, /* Windows MCE button */ - -}; - -static struct rc_map_list imon_mce_map = { - .map = { - .scan = imon_mce, - .size = ARRAY_SIZE(imon_mce), - /* its RC6, but w/a hardware decoder */ - .rc_type = RC_TYPE_RC6, - .name = RC_MAP_IMON_MCE, - } -}; - -static int __init init_rc_map_imon_mce(void) -{ - return rc_map_register(&imon_mce_map); -} - -static void __exit exit_rc_map_imon_mce(void) -{ - rc_map_unregister(&imon_mce_map); -} - -module_init(init_rc_map_imon_mce) -module_exit(exit_rc_map_imon_mce) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-imon-pad.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-imon-pad.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-imon-pad.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-imon-pad.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +0,0 @@ -/* rc5-imon-pad.c - Keytable for SoundGraph iMON PAD and Antec Veris - * RM-200 Remote Control - * - * Copyright (c) 2010 by Jarod Wilson - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * standard imon remote key table, which isn't really entirely - * "standard", as different receivers decode the same key on the - * same remote to different hex codes, and the silkscreened names - * vary a bit between the SoundGraph and Antec remotes... ugh. - */ -static struct rc_map_table imon_pad[] = { - /* keys sorted mostly by frequency of use to optimize lookups */ - { 0x2a8195b7, KEY_REWIND }, - { 0x298315b7, KEY_REWIND }, - { 0x2b8115b7, KEY_FASTFORWARD }, - { 0x2b8315b7, KEY_FASTFORWARD }, - { 0x2b9115b7, KEY_PREVIOUS }, - { 0x298195b7, KEY_NEXT }, - - { 0x2a8115b7, KEY_PLAY }, - { 0x2a8315b7, KEY_PLAY }, - { 0x2a9115b7, KEY_PAUSE }, - { 0x2b9715b7, KEY_STOP }, - { 0x298115b7, KEY_RECORD }, - - { 0x01008000, KEY_UP }, - { 0x01007f00, KEY_DOWN }, - { 0x01000080, KEY_LEFT }, - { 0x0100007f, KEY_RIGHT }, - - { 0x2aa515b7, KEY_UP }, - { 0x289515b7, KEY_DOWN }, - { 0x29a515b7, KEY_LEFT }, - { 0x2ba515b7, KEY_RIGHT }, - - { 0x0200002c, KEY_SPACE }, /* Select/Space */ - { 0x2a9315b7, KEY_SPACE }, /* Select/Space */ - { 0x02000028, KEY_ENTER }, - { 0x28a195b7, KEY_ENTER }, - { 0x288195b7, KEY_EXIT }, - { 0x02000029, KEY_ESC }, - { 0x2bb715b7, KEY_ESC }, - { 0x0200002a, KEY_BACKSPACE }, - { 0x28a115b7, KEY_BACKSPACE }, - - { 0x2b9595b7, KEY_MUTE }, - { 0x28a395b7, KEY_VOLUMEUP }, - { 0x28a595b7, KEY_VOLUMEDOWN }, - { 0x289395b7, KEY_CHANNELUP }, - { 0x288795b7, KEY_CHANNELDOWN }, - - { 0x0200001e, KEY_NUMERIC_1 }, - { 0x0200001f, KEY_NUMERIC_2 }, - { 0x02000020, KEY_NUMERIC_3 }, - { 0x02000021, KEY_NUMERIC_4 }, - { 0x02000022, KEY_NUMERIC_5 }, - { 0x02000023, KEY_NUMERIC_6 }, - { 0x02000024, KEY_NUMERIC_7 }, - { 0x02000025, KEY_NUMERIC_8 }, - { 0x02000026, KEY_NUMERIC_9 }, - { 0x02000027, KEY_NUMERIC_0 }, - - { 0x28b595b7, KEY_NUMERIC_1 }, - { 0x2bb195b7, KEY_NUMERIC_2 }, - { 0x28b195b7, KEY_NUMERIC_3 }, - { 0x2a8595b7, KEY_NUMERIC_4 }, - { 0x299595b7, KEY_NUMERIC_5 }, - { 0x2aa595b7, KEY_NUMERIC_6 }, - { 0x2b9395b7, KEY_NUMERIC_7 }, - { 0x2a8515b7, KEY_NUMERIC_8 }, - { 0x2aa115b7, KEY_NUMERIC_9 }, - { 0x2ba595b7, KEY_NUMERIC_0 }, - - { 0x02200025, KEY_NUMERIC_STAR }, - { 0x28b515b7, KEY_NUMERIC_STAR }, - { 0x02200020, KEY_NUMERIC_POUND }, - { 0x29a115b7, KEY_NUMERIC_POUND }, - - { 0x2b8515b7, KEY_VIDEO }, - { 0x299195b7, KEY_AUDIO }, - { 0x2ba115b7, KEY_CAMERA }, - { 0x28a515b7, KEY_TV }, - { 0x29a395b7, KEY_DVD }, - { 0x29a295b7, KEY_DVD }, - - /* the Menu key between DVD and Subtitle on the RM-200... */ - { 0x2ba385b7, KEY_MENU }, - { 0x2ba395b7, KEY_MENU }, - - { 0x288515b7, KEY_BOOKMARKS }, - { 0x2ab715b7, KEY_MEDIA }, /* Thumbnail */ - { 0x298595b7, KEY_SUBTITLE }, - { 0x2b8595b7, KEY_LANGUAGE }, - - { 0x29a595b7, KEY_ZOOM }, - { 0x2aa395b7, KEY_SCREEN }, /* FullScreen */ - - { 0x299115b7, KEY_KEYBOARD }, - { 0x299135b7, KEY_KEYBOARD }, - - { 0x01010000, BTN_LEFT }, - { 0x01020000, BTN_RIGHT }, - { 0x01010080, BTN_LEFT }, - { 0x01020080, BTN_RIGHT }, - { 0x688301b7, BTN_LEFT }, - { 0x688481b7, BTN_RIGHT }, - - { 0x2a9395b7, KEY_CYCLEWINDOWS }, /* TaskSwitcher */ - { 0x2b8395b7, KEY_TIME }, /* Timer */ - - { 0x289115b7, KEY_POWER }, - { 0x29b195b7, KEY_EJECTCD }, /* the one next to play */ - { 0x299395b7, KEY_EJECTCLOSECD }, /* eject (by TaskSw) */ - - { 0x02800000, KEY_CONTEXT_MENU }, /* Left Menu */ - { 0x2b8195b7, KEY_CONTEXT_MENU }, /* Left Menu*/ - { 0x02000065, KEY_COMPOSE }, /* RightMenu */ - { 0x28b715b7, KEY_COMPOSE }, /* RightMenu */ - { 0x2ab195b7, KEY_LEFTMETA }, /* Go or MultiMon */ - { 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */ -}; - -static struct rc_map_list imon_pad_map = { - .map = { - .scan = imon_pad, - .size = ARRAY_SIZE(imon_pad), - /* actual protocol details unknown, hardware decoder */ - .rc_type = RC_TYPE_OTHER, - .name = RC_MAP_IMON_PAD, - } -}; - -static int __init init_rc_map_imon_pad(void) -{ - return rc_map_register(&imon_pad_map); -} - -static void __exit exit_rc_map_imon_pad(void) -{ - rc_map_unregister(&imon_pad_map); -} - -module_init(init_rc_map_imon_pad) -module_exit(exit_rc_map_imon_pad) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-iodata-bctv7e.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-iodata-bctv7e.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-iodata-bctv7e.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-iodata-bctv7e.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -/* iodata-bctv7e.h - Keytable for iodata_bctv7e Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* IO-DATA BCTV7E Remote */ - -static struct rc_map_table iodata_bctv7e[] = { - { 0x40, KEY_TV }, - { 0x20, KEY_RADIO }, /* FM */ - { 0x60, KEY_EPG }, - { 0x00, KEY_POWER }, - - /* Keys 0 to 9 */ - { 0x44, KEY_0 }, /* 10 */ - { 0x50, KEY_1 }, - { 0x30, KEY_2 }, - { 0x70, KEY_3 }, - { 0x48, KEY_4 }, - { 0x28, KEY_5 }, - { 0x68, KEY_6 }, - { 0x58, KEY_7 }, - { 0x38, KEY_8 }, - { 0x78, KEY_9 }, - - { 0x10, KEY_L }, /* Live */ - { 0x08, KEY_TIME }, /* Time Shift */ - - { 0x18, KEY_PLAYPAUSE }, /* Play */ - - { 0x24, KEY_ENTER }, /* 11 */ - { 0x64, KEY_ESC }, /* 12 */ - { 0x04, KEY_M }, /* Multi */ - - { 0x54, KEY_VIDEO }, - { 0x34, KEY_CHANNELUP }, - { 0x74, KEY_VOLUMEUP }, - { 0x14, KEY_MUTE }, - - { 0x4c, KEY_VCR }, /* SVIDEO */ - { 0x2c, KEY_CHANNELDOWN }, - { 0x6c, KEY_VOLUMEDOWN }, - { 0x0c, KEY_ZOOM }, - - { 0x5c, KEY_PAUSE }, - { 0x3c, KEY_RED }, /* || (red) */ - { 0x7c, KEY_RECORD }, /* recording */ - { 0x1c, KEY_STOP }, - - { 0x41, KEY_REWIND }, /* backward << */ - { 0x21, KEY_PLAY }, - { 0x61, KEY_FASTFORWARD }, /* forward >> */ - { 0x01, KEY_NEXT }, /* skip >| */ -}; - -static struct rc_map_list iodata_bctv7e_map = { - .map = { - .scan = iodata_bctv7e, - .size = ARRAY_SIZE(iodata_bctv7e), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_IODATA_BCTV7E, - } -}; - -static int __init init_rc_map_iodata_bctv7e(void) -{ - return rc_map_register(&iodata_bctv7e_map); -} - -static void __exit exit_rc_map_iodata_bctv7e(void) -{ - rc_map_unregister(&iodata_bctv7e_map); -} - -module_init(init_rc_map_iodata_bctv7e) -module_exit(exit_rc_map_iodata_bctv7e) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kaiomy.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kaiomy.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kaiomy.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kaiomy.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/* kaiomy.h - Keytable for kaiomy Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Kaiomy TVnPC U2 - Mauro Carvalho Chehab - */ - -static struct rc_map_table kaiomy[] = { - { 0x43, KEY_POWER2}, - { 0x01, KEY_LIST}, - { 0x0b, KEY_ZOOM}, - { 0x03, KEY_POWER}, - - { 0x04, KEY_1}, - { 0x08, KEY_2}, - { 0x02, KEY_3}, - - { 0x0f, KEY_4}, - { 0x05, KEY_5}, - { 0x06, KEY_6}, - - { 0x0c, KEY_7}, - { 0x0d, KEY_8}, - { 0x0a, KEY_9}, - - { 0x11, KEY_0}, - - { 0x09, KEY_CHANNELUP}, - { 0x07, KEY_CHANNELDOWN}, - - { 0x0e, KEY_VOLUMEUP}, - { 0x13, KEY_VOLUMEDOWN}, - - { 0x10, KEY_HOME}, - { 0x12, KEY_ENTER}, - - { 0x14, KEY_RECORD}, - { 0x15, KEY_STOP}, - { 0x16, KEY_PLAY}, - { 0x17, KEY_MUTE}, - - { 0x18, KEY_UP}, - { 0x19, KEY_DOWN}, - { 0x1a, KEY_LEFT}, - { 0x1b, KEY_RIGHT}, - - { 0x1c, KEY_RED}, - { 0x1d, KEY_GREEN}, - { 0x1e, KEY_YELLOW}, - { 0x1f, KEY_BLUE}, -}; - -static struct rc_map_list kaiomy_map = { - .map = { - .scan = kaiomy, - .size = ARRAY_SIZE(kaiomy), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_KAIOMY, - } -}; - -static int __init init_rc_map_kaiomy(void) -{ - return rc_map_register(&kaiomy_map); -} - -static void __exit exit_rc_map_kaiomy(void) -{ - rc_map_unregister(&kaiomy_map); -} - -module_init(init_rc_map_kaiomy) -module_exit(exit_rc_map_kaiomy) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kworld-315u.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kworld-315u.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kworld-315u.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kworld-315u.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/* kworld-315u.h - Keytable for kworld_315u Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Kworld 315U - */ - -static struct rc_map_table kworld_315u[] = { - { 0x6143, KEY_POWER }, - { 0x6101, KEY_VIDEO }, /* source */ - { 0x610b, KEY_ZOOM }, - { 0x6103, KEY_POWER2 }, /* shutdown */ - - { 0x6104, KEY_1 }, - { 0x6108, KEY_2 }, - { 0x6102, KEY_3 }, - { 0x6109, KEY_CHANNELUP }, - - { 0x610f, KEY_4 }, - { 0x6105, KEY_5 }, - { 0x6106, KEY_6 }, - { 0x6107, KEY_CHANNELDOWN }, - - { 0x610c, KEY_7 }, - { 0x610d, KEY_8 }, - { 0x610a, KEY_9 }, - { 0x610e, KEY_VOLUMEUP }, - - { 0x6110, KEY_LAST }, - { 0x6111, KEY_0 }, - { 0x6112, KEY_ENTER }, - { 0x6113, KEY_VOLUMEDOWN }, - - { 0x6114, KEY_RECORD }, - { 0x6115, KEY_STOP }, - { 0x6116, KEY_PLAY }, - { 0x6117, KEY_MUTE }, - - { 0x6118, KEY_UP }, - { 0x6119, KEY_DOWN }, - { 0x611a, KEY_LEFT }, - { 0x611b, KEY_RIGHT }, - - { 0x611c, KEY_RED }, - { 0x611d, KEY_GREEN }, - { 0x611e, KEY_YELLOW }, - { 0x611f, KEY_BLUE }, -}; - -static struct rc_map_list kworld_315u_map = { - .map = { - .scan = kworld_315u, - .size = ARRAY_SIZE(kworld_315u), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_KWORLD_315U, - } -}; - -static int __init init_rc_map_kworld_315u(void) -{ - return rc_map_register(&kworld_315u_map); -} - -static void __exit exit_rc_map_kworld_315u(void) -{ - rc_map_unregister(&kworld_315u_map); -} - -module_init(init_rc_map_kworld_315u) -module_exit(exit_rc_map_kworld_315u) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -/* kworld-plus-tv-analog.h - Keytable for kworld_plus_tv_analog Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Kworld Plus TV Analog Lite PCI IR - Mauro Carvalho Chehab - */ - -static struct rc_map_table kworld_plus_tv_analog[] = { - { 0x0c, KEY_LEFTMETA }, /* Kworld key */ - { 0x16, KEY_CLOSECD }, /* -> ) */ - { 0x1d, KEY_POWER2 }, - - { 0x00, KEY_1 }, - { 0x01, KEY_2 }, - { 0x02, KEY_3 }, /* Two keys have the same code: 3 and left */ - { 0x03, KEY_4 }, /* Two keys have the same code: 3 and right */ - { 0x04, KEY_5 }, - { 0x05, KEY_6 }, - { 0x06, KEY_7 }, - { 0x07, KEY_8 }, - { 0x08, KEY_9 }, - { 0x0a, KEY_0 }, - - { 0x09, KEY_AGAIN }, - { 0x14, KEY_MUTE }, - - { 0x20, KEY_UP }, - { 0x21, KEY_DOWN }, - { 0x0b, KEY_ENTER }, - - { 0x10, KEY_CHANNELUP }, - { 0x11, KEY_CHANNELDOWN }, - - /* Couldn't map key left/key right since those - conflict with '3' and '4' scancodes - I dunno what the original driver does - */ - - { 0x13, KEY_VOLUMEUP }, - { 0x12, KEY_VOLUMEDOWN }, - - /* The lower part of the IR - There are several duplicated keycodes there. - Most of them conflict with digits. - Add mappings just to the unused scancodes. - Somehow, the original driver has a way to know, - but this doesn't seem to be on some GPIO. - Also, it is not related to the time between keyup - and keydown. - */ - { 0x19, KEY_TIME}, /* Timeshift */ - { 0x1a, KEY_STOP}, - { 0x1b, KEY_RECORD}, - - { 0x22, KEY_TEXT}, - - { 0x15, KEY_AUDIO}, /* ((*)) */ - { 0x0f, KEY_ZOOM}, - { 0x1c, KEY_CAMERA}, /* snapshot */ - - { 0x18, KEY_RED}, /* B */ - { 0x23, KEY_GREEN}, /* C */ -}; - -static struct rc_map_list kworld_plus_tv_analog_map = { - .map = { - .scan = kworld_plus_tv_analog, - .size = ARRAY_SIZE(kworld_plus_tv_analog), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_KWORLD_PLUS_TV_ANALOG, - } -}; - -static int __init init_rc_map_kworld_plus_tv_analog(void) -{ - return rc_map_register(&kworld_plus_tv_analog_map); -} - -static void __exit exit_rc_map_kworld_plus_tv_analog(void) -{ - rc_map_unregister(&kworld_plus_tv_analog_map); -} - -module_init(init_rc_map_kworld_plus_tv_analog) -module_exit(exit_rc_map_kworld_plus_tv_analog) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -/* - * LeadTek Y04G0051 remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -static struct rc_map_table leadtek_y04g0051[] = { - { 0x0300, KEY_POWER2 }, - { 0x0303, KEY_SCREEN }, - { 0x0304, KEY_RIGHT }, - { 0x0305, KEY_1 }, - { 0x0306, KEY_2 }, - { 0x0307, KEY_3 }, - { 0x0308, KEY_LEFT }, - { 0x0309, KEY_4 }, - { 0x030a, KEY_5 }, - { 0x030b, KEY_6 }, - { 0x030c, KEY_UP }, - { 0x030d, KEY_7 }, - { 0x030e, KEY_8 }, - { 0x030f, KEY_9 }, - { 0x0310, KEY_DOWN }, - { 0x0311, KEY_AGAIN }, - { 0x0312, KEY_0 }, - { 0x0313, KEY_OK }, /* 1st ok */ - { 0x0314, KEY_MUTE }, - { 0x0316, KEY_OK }, /* 2nd ok */ - { 0x031e, KEY_VIDEO }, /* 2nd video */ - { 0x031b, KEY_AUDIO }, - { 0x031f, KEY_TEXT }, - { 0x0340, KEY_SLEEP }, - { 0x0341, KEY_DOT }, - { 0x0342, KEY_REWIND }, - { 0x0343, KEY_PLAY }, - { 0x0344, KEY_FASTFORWARD }, - { 0x0345, KEY_TIME }, - { 0x0346, KEY_STOP }, /* 2nd stop */ - { 0x0347, KEY_RECORD }, - { 0x0348, KEY_CAMERA }, - { 0x0349, KEY_ESC }, - { 0x034a, KEY_NEW }, - { 0x034b, KEY_RED }, - { 0x034c, KEY_GREEN }, - { 0x034d, KEY_YELLOW }, - { 0x034e, KEY_BLUE }, - { 0x034f, KEY_MENU }, - { 0x0350, KEY_STOP }, /* 1st stop */ - { 0x0351, KEY_CHANNEL }, - { 0x0352, KEY_VIDEO }, /* 1st video */ - { 0x0353, KEY_EPG }, - { 0x0354, KEY_PREVIOUS }, - { 0x0355, KEY_NEXT }, - { 0x0356, KEY_TV }, - { 0x035a, KEY_VOLUMEDOWN }, - { 0x035b, KEY_CHANNELUP }, - { 0x035e, KEY_VOLUMEUP }, - { 0x035f, KEY_CHANNELDOWN }, -}; - -static struct rc_map_list leadtek_y04g0051_map = { - .map = { - .scan = leadtek_y04g0051, - .size = ARRAY_SIZE(leadtek_y04g0051), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_LEADTEK_Y04G0051, - } -}; - -static int __init init_rc_map_leadtek_y04g0051(void) -{ - return rc_map_register(&leadtek_y04g0051_map); -} - -static void __exit exit_rc_map_leadtek_y04g0051(void) -{ - rc_map_unregister(&leadtek_y04g0051_map); -} - -module_init(init_rc_map_leadtek_y04g0051) -module_exit(exit_rc_map_leadtek_y04g0051) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-lirc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-lirc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-lirc.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-lirc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass - * all raw IR data to the lirc userspace decoder. - * - * Copyright (c) 2010 by Jarod Wilson - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table lirc[] = { - { }, -}; - -static struct rc_map_list lirc_map = { - .map = { - .scan = lirc, - .size = ARRAY_SIZE(lirc), - .rc_type = RC_TYPE_LIRC, - .name = RC_MAP_LIRC, - } -}; - -static int __init init_rc_map_lirc(void) -{ - return rc_map_register(&lirc_map); -} - -static void __exit exit_rc_map_lirc(void) -{ - rc_map_unregister(&lirc_map); -} - -module_init(init_rc_map_lirc) -module_exit(exit_rc_map_lirc) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-lme2510.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-lme2510.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-lme2510.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-lme2510.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -/* LME2510 remote control - * - * - * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.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, or - * (at your option) any later version. - */ - -#include - - -static struct rc_map_table lme2510_rc[] = { - /* Type 1 - 26 buttons */ - { 0xef12ba45, KEY_0 }, - { 0xef12a05f, KEY_1 }, - { 0xef12af50, KEY_2 }, - { 0xef12a25d, KEY_3 }, - { 0xef12be41, KEY_4 }, - { 0xef12f50a, KEY_5 }, - { 0xef12bd42, KEY_6 }, - { 0xef12b847, KEY_7 }, - { 0xef12b649, KEY_8 }, - { 0xef12fa05, KEY_9 }, - { 0xef12bc43, KEY_POWER }, - { 0xef12b946, KEY_SUBTITLE }, - { 0xef12f906, KEY_PAUSE }, - { 0xef12fc03, KEY_MEDIA_REPEAT}, - { 0xef12fd02, KEY_PAUSE }, - { 0xef12a15e, KEY_VOLUMEUP }, - { 0xef12a35c, KEY_VOLUMEDOWN }, - { 0xef12f609, KEY_CHANNELUP }, - { 0xef12e51a, KEY_CHANNELDOWN }, - { 0xef12e11e, KEY_PLAY }, - { 0xef12e41b, KEY_ZOOM }, - { 0xef12a659, KEY_MUTE }, - { 0xef12a55a, KEY_TV }, - { 0xef12e718, KEY_RECORD }, - { 0xef12f807, KEY_EPG }, - { 0xef12fe01, KEY_STOP }, - /* Type 2 - 20 buttons */ - { 0xff40ea15, KEY_0 }, - { 0xff40f708, KEY_1 }, - { 0xff40f609, KEY_2 }, - { 0xff40f50a, KEY_3 }, - { 0xff40f30c, KEY_4 }, - { 0xff40f20d, KEY_5 }, - { 0xff40f10e, KEY_6 }, - { 0xff40ef10, KEY_7 }, - { 0xff40ee11, KEY_8 }, - { 0xff40ed12, KEY_9 }, - { 0xff40ff00, KEY_POWER }, - { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */ - { 0xff40e51a, KEY_PAUSE }, /* Timeshift */ - { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0xff40f906, KEY_VOLUMEDOWN }, /* Volumne defined as right hand*/ - { 0xff40fe01, KEY_CHANNELUP }, - { 0xff40fa05, KEY_CHANNELDOWN }, - { 0xff40eb14, KEY_ZOOM }, - { 0xff40e718, KEY_RECORD }, - { 0xff40e916, KEY_STOP }, - /* Type 3 - 20 buttons */ - { 0xff00e31c, KEY_0 }, - { 0xff00f807, KEY_1 }, - { 0xff00ea15, KEY_2 }, - { 0xff00f609, KEY_3 }, - { 0xff00e916, KEY_4 }, - { 0xff00e619, KEY_5 }, - { 0xff00f20d, KEY_6 }, - { 0xff00f30c, KEY_7 }, - { 0xff00e718, KEY_8 }, - { 0xff00a15e, KEY_9 }, - { 0xff00ba45, KEY_POWER }, - { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */ - { 0xff00b54a, KEY_PAUSE }, /* Timeshift */ - { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volumne defined as right hand*/ - { 0xff00b946, KEY_CHANNELUP }, - { 0xff00bf40, KEY_CHANNELDOWN }, - { 0xff00f708, KEY_ZOOM }, - { 0xff00bd42, KEY_RECORD }, - { 0xff00a55a, KEY_STOP }, -}; - -static struct rc_map_list lme2510_map = { - .map = { - .scan = lme2510_rc, - .size = ARRAY_SIZE(lme2510_rc), - .rc_type = RC_TYPE_UNKNOWN, - .name = RC_MAP_LME2510, - } -}; - -static int __init init_rc_lme2510_map(void) -{ - return rc_map_register(&lme2510_map); -} - -static void __exit exit_rc_lme2510_map(void) -{ - rc_map_unregister(&lme2510_map); -} - -module_init(init_rc_lme2510_map) -module_exit(exit_rc_lme2510_map) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-manli.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-manli.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-manli.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-manli.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -/* manli.h - Keytable for manli Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Michael Tokarev - keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at - least, and probably other cards too. - The "ascii-art picture" below (in comments, first row - is the keycode in hex, and subsequent row(s) shows - the button labels (several variants when appropriate) - helps to descide which keycodes to assign to the buttons. - */ - -static struct rc_map_table manli[] = { - - /* 0x1c 0x12 * - * FUNCTION POWER * - * FM (|) * - * */ - { 0x1c, KEY_RADIO }, /*XXX*/ - { 0x12, KEY_POWER }, - - /* 0x01 0x02 0x03 * - * 1 2 3 * - * * - * 0x04 0x05 0x06 * - * 4 5 6 * - * * - * 0x07 0x08 0x09 * - * 7 8 9 * - * */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - /* 0x0a 0x00 0x17 * - * RECALL 0 +100 * - * PLUS * - * */ - { 0x0a, KEY_AGAIN }, /*XXX KEY_REWIND? */ - { 0x00, KEY_0 }, - { 0x17, KEY_DIGITS }, /*XXX*/ - - /* 0x14 0x10 * - * MENU INFO * - * OSD */ - { 0x14, KEY_MENU }, - { 0x10, KEY_INFO }, - - /* 0x0b * - * Up * - * * - * 0x18 0x16 0x0c * - * Left Ok Right * - * * - * 0x015 * - * Down * - * */ - { 0x0b, KEY_UP }, - { 0x18, KEY_LEFT }, - { 0x16, KEY_OK }, /*XXX KEY_SELECT? KEY_ENTER? */ - { 0x0c, KEY_RIGHT }, - { 0x15, KEY_DOWN }, - - /* 0x11 0x0d * - * TV/AV MODE * - * SOURCE STEREO * - * */ - { 0x11, KEY_TV }, /*XXX*/ - { 0x0d, KEY_MODE }, /*XXX there's no KEY_STEREO */ - - /* 0x0f 0x1b 0x1a * - * AUDIO Vol+ Chan+ * - * TIMESHIFT??? * - * * - * 0x0e 0x1f 0x1e * - * SLEEP Vol- Chan- * - * */ - { 0x0f, KEY_AUDIO }, - { 0x1b, KEY_VOLUMEUP }, - { 0x1a, KEY_CHANNELUP }, - { 0x0e, KEY_TIME }, - { 0x1f, KEY_VOLUMEDOWN }, - { 0x1e, KEY_CHANNELDOWN }, - - /* 0x13 0x19 * - * MUTE SNAPSHOT* - * */ - { 0x13, KEY_MUTE }, - { 0x19, KEY_CAMERA }, - - /* 0x1d unused ? */ -}; - -static struct rc_map_list manli_map = { - .map = { - .scan = manli, - .size = ARRAY_SIZE(manli), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_MANLI, - } -}; - -static int __init init_rc_map_manli(void) -{ - return rc_map_register(&manli_map); -} - -static void __exit exit_rc_map_manli(void) -{ - rc_map_unregister(&manli_map); -} - -module_init(init_rc_map_manli) -module_exit(exit_rc_map_manli) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-digivox-ii.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-digivox-ii.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-digivox-ii.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-digivox-ii.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -/* - * MSI DIGIVOX mini II remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -static struct rc_map_table msi_digivox_ii[] = { - { 0x0002, KEY_2 }, - { 0x0003, KEY_UP }, /* up */ - { 0x0004, KEY_3 }, - { 0x0005, KEY_CHANNELDOWN }, - { 0x0008, KEY_5 }, - { 0x0009, KEY_0 }, - { 0x000b, KEY_8 }, - { 0x000d, KEY_DOWN }, /* down */ - { 0x0010, KEY_9 }, - { 0x0011, KEY_7 }, - { 0x0014, KEY_VOLUMEUP }, - { 0x0015, KEY_CHANNELUP }, - { 0x0016, KEY_OK }, - { 0x0017, KEY_POWER2 }, - { 0x001a, KEY_1 }, - { 0x001c, KEY_4 }, - { 0x001d, KEY_6 }, - { 0x001f, KEY_VOLUMEDOWN }, -}; - -static struct rc_map_list msi_digivox_ii_map = { - .map = { - .scan = msi_digivox_ii, - .size = ARRAY_SIZE(msi_digivox_ii), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_MSI_DIGIVOX_II, - } -}; - -static int __init init_rc_map_msi_digivox_ii(void) -{ - return rc_map_register(&msi_digivox_ii_map); -} - -static void __exit exit_rc_map_msi_digivox_ii(void) -{ - rc_map_unregister(&msi_digivox_ii_map); -} - -module_init(init_rc_map_msi_digivox_ii) -module_exit(exit_rc_map_msi_digivox_ii) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-digivox-iii.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-digivox-iii.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-digivox-iii.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-digivox-iii.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* - * MSI DIGIVOX mini III remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -/* MSI DIGIVOX mini III */ -/* Uses NEC extended 0x61d6. */ -/* This remote seems to be same as rc-kworld-315u.c. Anyhow, add new remote - since rc-kworld-315u.c lacks NEC extended address byte. */ -static struct rc_map_table msi_digivox_iii[] = { - { 0x61d601, KEY_VIDEO }, /* Source */ - { 0x61d602, KEY_3 }, - { 0x61d603, KEY_POWER }, /* ShutDown */ - { 0x61d604, KEY_1 }, - { 0x61d605, KEY_5 }, - { 0x61d606, KEY_6 }, - { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ - { 0x61d608, KEY_2 }, - { 0x61d609, KEY_CHANNELUP }, /* CH+ */ - { 0x61d60a, KEY_9 }, - { 0x61d60b, KEY_ZOOM }, /* Zoom */ - { 0x61d60c, KEY_7 }, - { 0x61d60d, KEY_8 }, - { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ - { 0x61d60f, KEY_4 }, - { 0x61d610, KEY_ESC }, /* [back up arrow] */ - { 0x61d611, KEY_0 }, - { 0x61d612, KEY_OK }, /* [enter arrow] */ - { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ - { 0x61d614, KEY_RECORD }, /* Rec */ - { 0x61d615, KEY_STOP }, /* Stop */ - { 0x61d616, KEY_PLAY }, /* Play */ - { 0x61d617, KEY_MUTE }, /* Mute */ - { 0x61d618, KEY_UP }, - { 0x61d619, KEY_DOWN }, - { 0x61d61a, KEY_LEFT }, - { 0x61d61b, KEY_RIGHT }, - { 0x61d61c, KEY_RED }, - { 0x61d61d, KEY_GREEN }, - { 0x61d61e, KEY_YELLOW }, - { 0x61d61f, KEY_BLUE }, - { 0x61d643, KEY_POWER2 }, /* [red power button] */ -}; - -static struct rc_map_list msi_digivox_iii_map = { - .map = { - .scan = msi_digivox_iii, - .size = ARRAY_SIZE(msi_digivox_iii), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_MSI_DIGIVOX_III, - } -}; - -static int __init init_rc_map_msi_digivox_iii(void) -{ - return rc_map_register(&msi_digivox_iii_map); -} - -static void __exit exit_rc_map_msi_digivox_iii(void) -{ - rc_map_unregister(&msi_digivox_iii_map); -} - -module_init(init_rc_map_msi_digivox_iii) -module_exit(exit_rc_map_msi_digivox_iii) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* msi-tvanywhere.h - Keytable for msi_tvanywhere Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* MSI TV@nywhere MASTER remote */ - -static struct rc_map_table msi_tvanywhere[] = { - /* Keys 0 to 9 */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x0c, KEY_MUTE }, - { 0x0f, KEY_SCREEN }, /* Full Screen */ - { 0x10, KEY_FN }, /* Funtion */ - { 0x11, KEY_TIME }, /* Time shift */ - { 0x12, KEY_POWER }, - { 0x13, KEY_MEDIA }, /* MTS */ - { 0x14, KEY_SLOW }, - { 0x16, KEY_REWIND }, /* backward << */ - { 0x17, KEY_ENTER }, /* Return */ - { 0x18, KEY_FASTFORWARD }, /* forward >> */ - { 0x1a, KEY_CHANNELUP }, - { 0x1b, KEY_VOLUMEUP }, - { 0x1e, KEY_CHANNELDOWN }, - { 0x1f, KEY_VOLUMEDOWN }, -}; - -static struct rc_map_list msi_tvanywhere_map = { - .map = { - .scan = msi_tvanywhere, - .size = ARRAY_SIZE(msi_tvanywhere), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_MSI_TVANYWHERE, - } -}; - -static int __init init_rc_map_msi_tvanywhere(void) -{ - return rc_map_register(&msi_tvanywhere_map); -} - -static void __exit exit_rc_map_msi_tvanywhere(void) -{ - rc_map_unregister(&msi_tvanywhere_map); -} - -module_init(init_rc_map_msi_tvanywhere) -module_exit(exit_rc_map_msi_tvanywhere) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -/* msi-tvanywhere-plus.h - Keytable for msi_tvanywhere_plus Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card - is marked "KS003". The controller is I2C at address 0x30, but does not seem - to respond to probes until a read is performed from a valid device. - I don't know why... - - Note: This remote may be of similar or identical design to the - Pixelview remote (?). The raw codes and duplicate button codes - appear to be the same. - - Henry Wong - Some changes to formatting and keycodes by Mark Schultz -*/ - -static struct rc_map_table msi_tvanywhere_plus[] = { - -/* ---- Remote Button Layout ---- - - POWER SOURCE SCAN MUTE - TV/FM 1 2 3 - |> 4 5 6 - <| 7 8 9 - ^^UP 0 + RECALL - vvDN RECORD STOP PLAY - - MINIMIZE ZOOM - - CH+ - VOL- VOL+ - CH- - - SNAPSHOT MTS - - << FUNC >> RESET -*/ - - { 0x01, KEY_1 }, /* 1 */ - { 0x0b, KEY_2 }, /* 2 */ - { 0x1b, KEY_3 }, /* 3 */ - { 0x05, KEY_4 }, /* 4 */ - { 0x09, KEY_5 }, /* 5 */ - { 0x15, KEY_6 }, /* 6 */ - { 0x06, KEY_7 }, /* 7 */ - { 0x0a, KEY_8 }, /* 8 */ - { 0x12, KEY_9 }, /* 9 */ - { 0x02, KEY_0 }, /* 0 */ - { 0x10, KEY_KPPLUS }, /* + */ - { 0x13, KEY_AGAIN }, /* Recall */ - - { 0x1e, KEY_POWER }, /* Power */ - { 0x07, KEY_VIDEO }, /* Source */ - { 0x1c, KEY_SEARCH }, /* Scan */ - { 0x18, KEY_MUTE }, /* Mute */ - - { 0x03, KEY_RADIO }, /* TV/FM */ - /* The next four keys are duplicates that appear to send the - same IR code as Ch+, Ch-, >>, and << . The raw code assigned - to them is the actual code + 0x20 - they will never be - detected as such unless some way is discovered to distinguish - these buttons from those that have the same code. */ - { 0x3f, KEY_RIGHT }, /* |> and Ch+ */ - { 0x37, KEY_LEFT }, /* <| and Ch- */ - { 0x2c, KEY_UP }, /* ^^Up and >> */ - { 0x24, KEY_DOWN }, /* vvDn and << */ - - { 0x00, KEY_RECORD }, /* Record */ - { 0x08, KEY_STOP }, /* Stop */ - { 0x11, KEY_PLAY }, /* Play */ - - { 0x0f, KEY_CLOSE }, /* Minimize */ - { 0x19, KEY_ZOOM }, /* Zoom */ - { 0x1a, KEY_CAMERA }, /* Snapshot */ - { 0x0d, KEY_LANGUAGE }, /* MTS */ - - { 0x14, KEY_VOLUMEDOWN }, /* Vol- */ - { 0x16, KEY_VOLUMEUP }, /* Vol+ */ - { 0x17, KEY_CHANNELDOWN }, /* Ch- */ - { 0x1f, KEY_CHANNELUP }, /* Ch+ */ - - { 0x04, KEY_REWIND }, /* << */ - { 0x0e, KEY_MENU }, /* Function */ - { 0x0c, KEY_FASTFORWARD }, /* >> */ - { 0x1d, KEY_RESTART }, /* Reset */ -}; - -static struct rc_map_list msi_tvanywhere_plus_map = { - .map = { - .scan = msi_tvanywhere_plus, - .size = ARRAY_SIZE(msi_tvanywhere_plus), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_MSI_TVANYWHERE_PLUS, - } -}; - -static int __init init_rc_map_msi_tvanywhere_plus(void) -{ - return rc_map_register(&msi_tvanywhere_plus_map); -} - -static void __exit exit_rc_map_msi_tvanywhere_plus(void) -{ - rc_map_unregister(&msi_tvanywhere_plus_map); -} - -module_init(init_rc_map_msi_tvanywhere_plus) -module_exit(exit_rc_map_msi_tvanywhere_plus) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-nebula.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-nebula.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-nebula.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-nebula.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/* nebula.h - Keytable for nebula Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table nebula[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x0a, KEY_TV }, - { 0x0b, KEY_AUX }, - { 0x0c, KEY_DVD }, - { 0x0d, KEY_POWER }, - { 0x0e, KEY_CAMERA }, /* labelled 'Picture' */ - { 0x0f, KEY_AUDIO }, - { 0x10, KEY_INFO }, - { 0x11, KEY_F13 }, /* 16:9 */ - { 0x12, KEY_F14 }, /* 14:9 */ - { 0x13, KEY_EPG }, - { 0x14, KEY_EXIT }, - { 0x15, KEY_MENU }, - { 0x16, KEY_UP }, - { 0x17, KEY_DOWN }, - { 0x18, KEY_LEFT }, - { 0x19, KEY_RIGHT }, - { 0x1a, KEY_ENTER }, - { 0x1b, KEY_CHANNELUP }, - { 0x1c, KEY_CHANNELDOWN }, - { 0x1d, KEY_VOLUMEUP }, - { 0x1e, KEY_VOLUMEDOWN }, - { 0x1f, KEY_RED }, - { 0x20, KEY_GREEN }, - { 0x21, KEY_YELLOW }, - { 0x22, KEY_BLUE }, - { 0x23, KEY_SUBTITLE }, - { 0x24, KEY_F15 }, /* AD */ - { 0x25, KEY_TEXT }, - { 0x26, KEY_MUTE }, - { 0x27, KEY_REWIND }, - { 0x28, KEY_STOP }, - { 0x29, KEY_PLAY }, - { 0x2a, KEY_FASTFORWARD }, - { 0x2b, KEY_F16 }, /* chapter */ - { 0x2c, KEY_PAUSE }, - { 0x2d, KEY_PLAY }, - { 0x2e, KEY_RECORD }, - { 0x2f, KEY_F17 }, /* picture in picture */ - { 0x30, KEY_KPPLUS }, /* zoom in */ - { 0x31, KEY_KPMINUS }, /* zoom out */ - { 0x32, KEY_F18 }, /* capture */ - { 0x33, KEY_F19 }, /* web */ - { 0x34, KEY_EMAIL }, - { 0x35, KEY_PHONE }, - { 0x36, KEY_PC }, -}; - -static struct rc_map_list nebula_map = { - .map = { - .scan = nebula, - .size = ARRAY_SIZE(nebula), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_NEBULA, - } -}; - -static int __init init_rc_map_nebula(void) -{ - return rc_map_register(&nebula_map); -} - -static void __exit exit_rc_map_nebula(void) -{ - rc_map_unregister(&nebula_map); -} - -module_init(init_rc_map_nebula) -module_exit(exit_rc_map_nebula) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/* nec-terratec-cinergy-xs.h - Keytable for nec_terratec_cinergy_xs Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Terratec Cinergy Hybrid T USB XS FM - Mauro Carvalho Chehab - */ - -static struct rc_map_table nec_terratec_cinergy_xs[] = { - { 0x1441, KEY_HOME}, - { 0x1401, KEY_POWER2}, - - { 0x1442, KEY_MENU}, /* DVD menu */ - { 0x1443, KEY_SUBTITLE}, - { 0x1444, KEY_TEXT}, /* Teletext */ - { 0x1445, KEY_DELETE}, - - { 0x1402, KEY_1}, - { 0x1403, KEY_2}, - { 0x1404, KEY_3}, - { 0x1405, KEY_4}, - { 0x1406, KEY_5}, - { 0x1407, KEY_6}, - { 0x1408, KEY_7}, - { 0x1409, KEY_8}, - { 0x140a, KEY_9}, - { 0x140c, KEY_0}, - - { 0x140b, KEY_TUNER}, /* AV */ - { 0x140d, KEY_MODE}, /* A.B */ - - { 0x1446, KEY_TV}, - { 0x1447, KEY_DVD}, - { 0x1449, KEY_VIDEO}, - { 0x144a, KEY_RADIO}, /* Music */ - { 0x144b, KEY_CAMERA}, /* PIC */ - - { 0x1410, KEY_UP}, - { 0x1411, KEY_LEFT}, - { 0x1412, KEY_OK}, - { 0x1413, KEY_RIGHT}, - { 0x1414, KEY_DOWN}, - - { 0x140f, KEY_EPG}, - { 0x1416, KEY_INFO}, - { 0x144d, KEY_BACKSPACE}, - - { 0x141c, KEY_VOLUMEUP}, - { 0x141e, KEY_VOLUMEDOWN}, - - { 0x144c, KEY_PLAY}, - { 0x141d, KEY_MUTE}, - - { 0x141b, KEY_CHANNELUP}, - { 0x141f, KEY_CHANNELDOWN}, - - { 0x1417, KEY_RED}, - { 0x1418, KEY_GREEN}, - { 0x1419, KEY_YELLOW}, - { 0x141a, KEY_BLUE}, - - { 0x1458, KEY_RECORD}, - { 0x1448, KEY_STOP}, - { 0x1440, KEY_PAUSE}, - - { 0x1454, KEY_LAST}, - { 0x144e, KEY_REWIND}, - { 0x144f, KEY_FASTFORWARD}, - { 0x145c, KEY_NEXT}, -}; - -static struct rc_map_list nec_terratec_cinergy_xs_map = { - .map = { - .scan = nec_terratec_cinergy_xs, - .size = ARRAY_SIZE(nec_terratec_cinergy_xs), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_NEC_TERRATEC_CINERGY_XS, - } -}; - -static int __init init_rc_map_nec_terratec_cinergy_xs(void) -{ - return rc_map_register(&nec_terratec_cinergy_xs_map); -} - -static void __exit exit_rc_map_nec_terratec_cinergy_xs(void) -{ - rc_map_unregister(&nec_terratec_cinergy_xs_map); -} - -module_init(init_rc_map_nec_terratec_cinergy_xs) -module_exit(exit_rc_map_nec_terratec_cinergy_xs) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-norwood.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-norwood.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-norwood.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-norwood.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* norwood.h - Keytable for norwood Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Norwood Micro (non-Pro) TV Tuner - By Peter Naulls - Key comments are the functions given in the manual */ - -static struct rc_map_table norwood[] = { - /* Keys 0 to 9 */ - { 0x20, KEY_0 }, - { 0x21, KEY_1 }, - { 0x22, KEY_2 }, - { 0x23, KEY_3 }, - { 0x24, KEY_4 }, - { 0x25, KEY_5 }, - { 0x26, KEY_6 }, - { 0x27, KEY_7 }, - { 0x28, KEY_8 }, - { 0x29, KEY_9 }, - - { 0x78, KEY_VIDEO }, /* Video Source */ - { 0x2c, KEY_EXIT }, /* Open/Close software */ - { 0x2a, KEY_SELECT }, /* 2 Digit Select */ - { 0x69, KEY_AGAIN }, /* Recall */ - - { 0x32, KEY_BRIGHTNESSUP }, /* Brightness increase */ - { 0x33, KEY_BRIGHTNESSDOWN }, /* Brightness decrease */ - { 0x6b, KEY_KPPLUS }, /* (not named >>>>>) */ - { 0x6c, KEY_KPMINUS }, /* (not named <<<<<) */ - - { 0x2d, KEY_MUTE }, /* Mute */ - { 0x30, KEY_VOLUMEUP }, /* Volume up */ - { 0x31, KEY_VOLUMEDOWN }, /* Volume down */ - { 0x60, KEY_CHANNELUP }, /* Channel up */ - { 0x61, KEY_CHANNELDOWN }, /* Channel down */ - - { 0x3f, KEY_RECORD }, /* Record */ - { 0x37, KEY_PLAY }, /* Play */ - { 0x36, KEY_PAUSE }, /* Pause */ - { 0x2b, KEY_STOP }, /* Stop */ - { 0x67, KEY_FASTFORWARD }, /* Foward */ - { 0x66, KEY_REWIND }, /* Rewind */ - { 0x3e, KEY_SEARCH }, /* Auto Scan */ - { 0x2e, KEY_CAMERA }, /* Capture Video */ - { 0x6d, KEY_MENU }, /* Show/Hide Control */ - { 0x2f, KEY_ZOOM }, /* Full Screen */ - { 0x34, KEY_RADIO }, /* FM */ - { 0x65, KEY_POWER }, /* Computer power */ -}; - -static struct rc_map_list norwood_map = { - .map = { - .scan = norwood, - .size = ARRAY_SIZE(norwood), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_NORWOOD, - } -}; - -static int __init init_rc_map_norwood(void) -{ - return rc_map_register(&norwood_map); -} - -static void __exit exit_rc_map_norwood(void) -{ - rc_map_unregister(&norwood_map); -} - -module_init(init_rc_map_norwood) -module_exit(exit_rc_map_norwood) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-npgtech.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-npgtech.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-npgtech.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-npgtech.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/* npgtech.h - Keytable for npgtech Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table npgtech[] = { - { 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */ - { 0x2a, KEY_FRONT }, - - { 0x3e, KEY_1 }, - { 0x02, KEY_2 }, - { 0x06, KEY_3 }, - { 0x0a, KEY_4 }, - { 0x0e, KEY_5 }, - { 0x12, KEY_6 }, - { 0x16, KEY_7 }, - { 0x1a, KEY_8 }, - { 0x1e, KEY_9 }, - { 0x3a, KEY_0 }, - { 0x22, KEY_NUMLOCK }, /* -/-- */ - { 0x20, KEY_REFRESH }, - - { 0x03, KEY_BRIGHTNESSDOWN }, - { 0x28, KEY_AUDIO }, - { 0x3c, KEY_CHANNELUP }, - { 0x3f, KEY_VOLUMEDOWN }, - { 0x2e, KEY_MUTE }, - { 0x3b, KEY_VOLUMEUP }, - { 0x00, KEY_CHANNELDOWN }, - { 0x07, KEY_BRIGHTNESSUP }, - { 0x2c, KEY_TEXT }, - - { 0x37, KEY_RECORD }, - { 0x17, KEY_PLAY }, - { 0x13, KEY_PAUSE }, - { 0x26, KEY_STOP }, - { 0x18, KEY_FASTFORWARD }, - { 0x14, KEY_REWIND }, - { 0x33, KEY_ZOOM }, - { 0x32, KEY_KEYBOARD }, - { 0x30, KEY_GOTO }, /* Pointing arrow */ - { 0x36, KEY_MACRO }, /* Maximize/Minimize (yellow) */ - { 0x0b, KEY_RADIO }, - { 0x10, KEY_POWER }, - -}; - -static struct rc_map_list npgtech_map = { - .map = { - .scan = npgtech, - .size = ARRAY_SIZE(npgtech), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_NPGTECH, - } -}; - -static int __init init_rc_map_npgtech(void) -{ - return rc_map_register(&npgtech_map); -} - -static void __exit exit_rc_map_npgtech(void) -{ - rc_map_unregister(&npgtech_map); -} - -module_init(init_rc_map_npgtech) -module_exit(exit_rc_map_npgtech) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pctv-sedna.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pctv-sedna.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pctv-sedna.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pctv-sedna.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/* pctv-sedna.h - Keytable for pctv_sedna Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Mapping for the 28 key remote control as seen at - http://www.sednacomputer.com/photo/cardbus-tv.jpg - Pavel Mihaylov - Also for the remote bundled with Kozumi KTV-01C card */ - -static struct rc_map_table pctv_sedna[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x0a, KEY_AGAIN }, /* Recall */ - { 0x0b, KEY_CHANNELUP }, - { 0x0c, KEY_VOLUMEUP }, - { 0x0d, KEY_MODE }, /* Stereo */ - { 0x0e, KEY_STOP }, - { 0x0f, KEY_PREVIOUSSONG }, - { 0x10, KEY_ZOOM }, - { 0x11, KEY_VIDEO }, /* Source */ - { 0x12, KEY_POWER }, - { 0x13, KEY_MUTE }, - { 0x15, KEY_CHANNELDOWN }, - { 0x18, KEY_VOLUMEDOWN }, - { 0x19, KEY_CAMERA }, /* Snapshot */ - { 0x1a, KEY_NEXTSONG }, - { 0x1b, KEY_TIME }, /* Time Shift */ - { 0x1c, KEY_RADIO }, /* FM Radio */ - { 0x1d, KEY_RECORD }, - { 0x1e, KEY_PAUSE }, - /* additional codes for Kozumi's remote */ - { 0x14, KEY_INFO }, /* OSD */ - { 0x16, KEY_OK }, /* OK */ - { 0x17, KEY_DIGITS }, /* Plus */ - { 0x1f, KEY_PLAY }, /* Play */ -}; - -static struct rc_map_list pctv_sedna_map = { - .map = { - .scan = pctv_sedna, - .size = ARRAY_SIZE(pctv_sedna), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PCTV_SEDNA, - } -}; - -static int __init init_rc_map_pctv_sedna(void) -{ - return rc_map_register(&pctv_sedna_map); -} - -static void __exit exit_rc_map_pctv_sedna(void) -{ - rc_map_unregister(&pctv_sedna_map); -} - -module_init(init_rc_map_pctv_sedna) -module_exit(exit_rc_map_pctv_sedna) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-color.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-color.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-color.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-color.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -/* pinnacle-color.h - Keytable for pinnacle_color Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table pinnacle_color[] = { - { 0x59, KEY_MUTE }, - { 0x4a, KEY_POWER }, - - { 0x18, KEY_TEXT }, - { 0x26, KEY_TV }, - { 0x3d, KEY_PRINT }, - - { 0x48, KEY_RED }, - { 0x04, KEY_GREEN }, - { 0x11, KEY_YELLOW }, - { 0x00, KEY_BLUE }, - - { 0x2d, KEY_VOLUMEUP }, - { 0x1e, KEY_VOLUMEDOWN }, - - { 0x49, KEY_MENU }, - - { 0x16, KEY_CHANNELUP }, - { 0x17, KEY_CHANNELDOWN }, - - { 0x20, KEY_UP }, - { 0x21, KEY_DOWN }, - { 0x22, KEY_LEFT }, - { 0x23, KEY_RIGHT }, - { 0x0d, KEY_SELECT }, - - { 0x08, KEY_BACK }, - { 0x07, KEY_REFRESH }, - - { 0x2f, KEY_ZOOM }, - { 0x29, KEY_RECORD }, - - { 0x4b, KEY_PAUSE }, - { 0x4d, KEY_REWIND }, - { 0x2e, KEY_PLAY }, - { 0x4e, KEY_FORWARD }, - { 0x53, KEY_PREVIOUS }, - { 0x4c, KEY_STOP }, - { 0x54, KEY_NEXT }, - - { 0x69, KEY_0 }, - { 0x6a, KEY_1 }, - { 0x6b, KEY_2 }, - { 0x6c, KEY_3 }, - { 0x6d, KEY_4 }, - { 0x6e, KEY_5 }, - { 0x6f, KEY_6 }, - { 0x70, KEY_7 }, - { 0x71, KEY_8 }, - { 0x72, KEY_9 }, - - { 0x74, KEY_CHANNEL }, - { 0x0a, KEY_BACKSPACE }, -}; - -static struct rc_map_list pinnacle_color_map = { - .map = { - .scan = pinnacle_color, - .size = ARRAY_SIZE(pinnacle_color), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PINNACLE_COLOR, - } -}; - -static int __init init_rc_map_pinnacle_color(void) -{ - return rc_map_register(&pinnacle_color_map); -} - -static void __exit exit_rc_map_pinnacle_color(void) -{ - rc_map_unregister(&pinnacle_color_map); -} - -module_init(init_rc_map_pinnacle_color) -module_exit(exit_rc_map_pinnacle_color) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-grey.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-grey.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-grey.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-grey.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -/* pinnacle-grey.h - Keytable for pinnacle_grey Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table pinnacle_grey[] = { - { 0x3a, KEY_0 }, - { 0x31, KEY_1 }, - { 0x32, KEY_2 }, - { 0x33, KEY_3 }, - { 0x34, KEY_4 }, - { 0x35, KEY_5 }, - { 0x36, KEY_6 }, - { 0x37, KEY_7 }, - { 0x38, KEY_8 }, - { 0x39, KEY_9 }, - - { 0x2f, KEY_POWER }, - - { 0x2e, KEY_P }, - { 0x1f, KEY_L }, - { 0x2b, KEY_I }, - - { 0x2d, KEY_SCREEN }, - { 0x1e, KEY_ZOOM }, - { 0x1b, KEY_VOLUMEUP }, - { 0x0f, KEY_VOLUMEDOWN }, - { 0x17, KEY_CHANNELUP }, - { 0x1c, KEY_CHANNELDOWN }, - { 0x25, KEY_INFO }, - - { 0x3c, KEY_MUTE }, - - { 0x3d, KEY_LEFT }, - { 0x3b, KEY_RIGHT }, - - { 0x3f, KEY_UP }, - { 0x3e, KEY_DOWN }, - { 0x1a, KEY_ENTER }, - - { 0x1d, KEY_MENU }, - { 0x19, KEY_AGAIN }, - { 0x16, KEY_PREVIOUSSONG }, - { 0x13, KEY_NEXTSONG }, - { 0x15, KEY_PAUSE }, - { 0x0e, KEY_REWIND }, - { 0x0d, KEY_PLAY }, - { 0x0b, KEY_STOP }, - { 0x07, KEY_FORWARD }, - { 0x27, KEY_RECORD }, - { 0x26, KEY_TUNER }, - { 0x29, KEY_TEXT }, - { 0x2a, KEY_MEDIA }, - { 0x18, KEY_EPG }, -}; - -static struct rc_map_list pinnacle_grey_map = { - .map = { - .scan = pinnacle_grey, - .size = ARRAY_SIZE(pinnacle_grey), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PINNACLE_GREY, - } -}; - -static int __init init_rc_map_pinnacle_grey(void) -{ - return rc_map_register(&pinnacle_grey_map); -} - -static void __exit exit_rc_map_pinnacle_grey(void) -{ - rc_map_unregister(&pinnacle_grey_map); -} - -module_init(init_rc_map_pinnacle_grey) -module_exit(exit_rc_map_pinnacle_grey) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* pinnacle-pctv-hd.h - Keytable for pinnacle_pctv_hd Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Pinnacle PCTV HD 800i mini remote */ - -static struct rc_map_table pinnacle_pctv_hd[] = { - - { 0x0f, KEY_1 }, - { 0x15, KEY_2 }, - { 0x10, KEY_3 }, - { 0x18, KEY_4 }, - { 0x1b, KEY_5 }, - { 0x1e, KEY_6 }, - { 0x11, KEY_7 }, - { 0x21, KEY_8 }, - { 0x12, KEY_9 }, - { 0x27, KEY_0 }, - - { 0x24, KEY_ZOOM }, - { 0x2a, KEY_SUBTITLE }, - - { 0x00, KEY_MUTE }, - { 0x01, KEY_ENTER }, /* Pinnacle Logo */ - { 0x39, KEY_POWER }, - - { 0x03, KEY_VOLUMEUP }, - { 0x09, KEY_VOLUMEDOWN }, - { 0x06, KEY_CHANNELUP }, - { 0x0c, KEY_CHANNELDOWN }, - - { 0x2d, KEY_REWIND }, - { 0x30, KEY_PLAYPAUSE }, - { 0x33, KEY_FASTFORWARD }, - { 0x3c, KEY_STOP }, - { 0x36, KEY_RECORD }, - { 0x3f, KEY_EPG }, /* Labeled "?" */ -}; - -static struct rc_map_list pinnacle_pctv_hd_map = { - .map = { - .scan = pinnacle_pctv_hd, - .size = ARRAY_SIZE(pinnacle_pctv_hd), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PINNACLE_PCTV_HD, - } -}; - -static int __init init_rc_map_pinnacle_pctv_hd(void) -{ - return rc_map_register(&pinnacle_pctv_hd_map); -} - -static void __exit exit_rc_map_pinnacle_pctv_hd(void) -{ - rc_map_unregister(&pinnacle_pctv_hd_map); -} - -module_init(init_rc_map_pinnacle_pctv_hd) -module_exit(exit_rc_map_pinnacle_pctv_hd) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-002t.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-002t.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-002t.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-002t.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/* rc-pixelview-mk12.h - Keytable for pixelview Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Keytable for 002-T IR remote provided together with Pixelview - * SBTVD Hybrid Remote Controller. Uses NEC extended format. - */ -static struct rc_map_table pixelview_002t[] = { - { 0x866b13, KEY_MUTE }, - { 0x866b12, KEY_POWER2 }, /* power */ - - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, - { 0x866b00, KEY_0 }, - - { 0x866b0d, KEY_CHANNELUP }, - { 0x866b19, KEY_CHANNELDOWN }, - { 0x866b10, KEY_VOLUMEUP }, /* vol + */ - { 0x866b0c, KEY_VOLUMEDOWN }, /* vol - */ - - { 0x866b0a, KEY_CAMERA }, /* snapshot */ - { 0x866b0b, KEY_ZOOM }, /* zoom */ - - { 0x866b1b, KEY_BACKSPACE }, - { 0x866b15, KEY_ENTER }, - - { 0x866b1d, KEY_UP }, - { 0x866b1e, KEY_DOWN }, - { 0x866b0e, KEY_LEFT }, - { 0x866b0f, KEY_RIGHT }, - - { 0x866b18, KEY_RECORD }, - { 0x866b1a, KEY_STOP }, -}; - -static struct rc_map_list pixelview_map = { - .map = { - .scan = pixelview_002t, - .size = ARRAY_SIZE(pixelview_002t), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_PIXELVIEW_002T, - } -}; - -static int __init init_rc_map_pixelview(void) -{ - return rc_map_register(&pixelview_map); -} - -static void __exit exit_rc_map_pixelview(void) -{ - rc_map_unregister(&pixelview_map); -} - -module_init(init_rc_map_pixelview) -module_exit(exit_rc_map_pixelview) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* pixelview.h - Keytable for pixelview Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table pixelview[] = { - - { 0x1e, KEY_POWER }, /* power */ - { 0x07, KEY_VIDEO }, /* source */ - { 0x1c, KEY_SEARCH }, /* scan */ - - - { 0x03, KEY_TUNER }, /* TV/FM */ - - { 0x00, KEY_RECORD }, - { 0x08, KEY_STOP }, - { 0x11, KEY_PLAY }, - - { 0x1a, KEY_PLAYPAUSE }, /* freeze */ - { 0x19, KEY_ZOOM }, /* zoom */ - { 0x0f, KEY_TEXT }, /* min */ - - { 0x01, KEY_1 }, - { 0x0b, KEY_2 }, - { 0x1b, KEY_3 }, - { 0x05, KEY_4 }, - { 0x09, KEY_5 }, - { 0x15, KEY_6 }, - { 0x06, KEY_7 }, - { 0x0a, KEY_8 }, - { 0x12, KEY_9 }, - { 0x02, KEY_0 }, - { 0x10, KEY_LAST }, /* +100 */ - { 0x13, KEY_LIST }, /* recall */ - - { 0x1f, KEY_CHANNELUP }, /* chn down */ - { 0x17, KEY_CHANNELDOWN }, /* chn up */ - { 0x16, KEY_VOLUMEUP }, /* vol down */ - { 0x14, KEY_VOLUMEDOWN }, /* vol up */ - - { 0x04, KEY_KPMINUS }, /* <<< */ - { 0x0e, KEY_SETUP }, /* function */ - { 0x0c, KEY_KPPLUS }, /* >>> */ - - { 0x0d, KEY_GOTO }, /* mts */ - { 0x1d, KEY_REFRESH }, /* reset */ - { 0x18, KEY_MUTE }, /* mute/unmute */ -}; - -static struct rc_map_list pixelview_map = { - .map = { - .scan = pixelview, - .size = ARRAY_SIZE(pixelview), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PIXELVIEW, - } -}; - -static int __init init_rc_map_pixelview(void) -{ - return rc_map_register(&pixelview_map); -} - -static void __exit exit_rc_map_pixelview(void) -{ - rc_map_unregister(&pixelview_map); -} - -module_init(init_rc_map_pixelview) -module_exit(exit_rc_map_pixelview) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-mk12.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-mk12.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-mk12.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-mk12.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/* rc-pixelview-mk12.h - Keytable for pixelview Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Keytable for MK-F12 IR remote provided together with Pixelview - * Ultra Pro Remote Controller. Uses NEC extended format. - */ -static struct rc_map_table pixelview_mk12[] = { - { 0x866b03, KEY_TUNER }, /* Timeshift */ - { 0x866b1e, KEY_POWER2 }, /* power */ - - { 0x866b01, KEY_1 }, - { 0x866b0b, KEY_2 }, - { 0x866b1b, KEY_3 }, - { 0x866b05, KEY_4 }, - { 0x866b09, KEY_5 }, - { 0x866b15, KEY_6 }, - { 0x866b06, KEY_7 }, - { 0x866b0a, KEY_8 }, - { 0x866b12, KEY_9 }, - { 0x866b02, KEY_0 }, - - { 0x866b13, KEY_AGAIN }, /* loop */ - { 0x866b10, KEY_DIGITS }, /* +100 */ - - { 0x866b00, KEY_VIDEO }, /* source */ - { 0x866b18, KEY_MUTE }, /* mute */ - { 0x866b19, KEY_CAMERA }, /* snapshot */ - { 0x866b1a, KEY_SEARCH }, /* scan */ - - { 0x866b16, KEY_CHANNELUP }, /* chn + */ - { 0x866b14, KEY_CHANNELDOWN }, /* chn - */ - { 0x866b1f, KEY_VOLUMEUP }, /* vol + */ - { 0x866b17, KEY_VOLUMEDOWN }, /* vol - */ - { 0x866b1c, KEY_ZOOM }, /* zoom */ - - { 0x866b04, KEY_REWIND }, - { 0x866b0e, KEY_RECORD }, - { 0x866b0c, KEY_FORWARD }, - - { 0x866b1d, KEY_STOP }, - { 0x866b08, KEY_PLAY }, - { 0x866b0f, KEY_PAUSE }, - - { 0x866b0d, KEY_TV }, - { 0x866b07, KEY_RADIO }, /* FM */ -}; - -static struct rc_map_list pixelview_map = { - .map = { - .scan = pixelview_mk12, - .size = ARRAY_SIZE(pixelview_mk12), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_PIXELVIEW_MK12, - } -}; - -static int __init init_rc_map_pixelview(void) -{ - return rc_map_register(&pixelview_map); -} - -static void __exit exit_rc_map_pixelview(void) -{ - rc_map_unregister(&pixelview_map); -} - -module_init(init_rc_map_pixelview) -module_exit(exit_rc_map_pixelview) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-new.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-new.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-new.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pixelview-new.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/* pixelview-new.h - Keytable for pixelview_new Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - Mauro Carvalho Chehab - present on PV MPEG 8000GT - */ - -static struct rc_map_table pixelview_new[] = { - { 0x3c, KEY_TIME }, /* Timeshift */ - { 0x12, KEY_POWER }, - - { 0x3d, KEY_1 }, - { 0x38, KEY_2 }, - { 0x18, KEY_3 }, - { 0x35, KEY_4 }, - { 0x39, KEY_5 }, - { 0x15, KEY_6 }, - { 0x36, KEY_7 }, - { 0x3a, KEY_8 }, - { 0x1e, KEY_9 }, - { 0x3e, KEY_0 }, - - { 0x1c, KEY_AGAIN }, /* LOOP */ - { 0x3f, KEY_VIDEO }, /* Source */ - { 0x1f, KEY_LAST }, /* +100 */ - { 0x1b, KEY_MUTE }, - - { 0x17, KEY_CHANNELDOWN }, - { 0x16, KEY_CHANNELUP }, - { 0x10, KEY_VOLUMEUP }, - { 0x14, KEY_VOLUMEDOWN }, - { 0x13, KEY_ZOOM }, - - { 0x19, KEY_CAMERA }, /* SNAPSHOT */ - { 0x1a, KEY_SEARCH }, /* scan */ - - { 0x37, KEY_REWIND }, /* << */ - { 0x32, KEY_RECORD }, /* o (red) */ - { 0x33, KEY_FORWARD }, /* >> */ - { 0x11, KEY_STOP }, /* square */ - { 0x3b, KEY_PLAY }, /* > */ - { 0x30, KEY_PLAYPAUSE }, /* || */ - - { 0x31, KEY_TV }, - { 0x34, KEY_RADIO }, -}; - -static struct rc_map_list pixelview_new_map = { - .map = { - .scan = pixelview_new, - .size = ARRAY_SIZE(pixelview_new), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PIXELVIEW_NEW, - } -}; - -static int __init init_rc_map_pixelview_new(void) -{ - return rc_map_register(&pixelview_new_map); -} - -static void __exit exit_rc_map_pixelview_new(void) -{ - rc_map_unregister(&pixelview_new_map); -} - -module_init(init_rc_map_pixelview_new) -module_exit(exit_rc_map_pixelview_new) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-powercolor-real-angel.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-powercolor-real-angel.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-powercolor-real-angel.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-powercolor-real-angel.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/* powercolor-real-angel.h - Keytable for powercolor_real_angel Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Remote control for Powercolor Real Angel 330 - * Daniel Fraga - */ - -static struct rc_map_table powercolor_real_angel[] = { - { 0x38, KEY_SWITCHVIDEOMODE }, /* switch inputs */ - { 0x0c, KEY_MEDIA }, /* Turn ON/OFF App */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x0a, KEY_DIGITS }, /* single, double, tripple digit */ - { 0x29, KEY_PREVIOUS }, /* previous channel */ - { 0x12, KEY_BRIGHTNESSUP }, - { 0x13, KEY_BRIGHTNESSDOWN }, - { 0x2b, KEY_MODE }, /* stereo/mono */ - { 0x2c, KEY_TEXT }, /* teletext */ - { 0x20, KEY_CHANNELUP }, /* channel up */ - { 0x21, KEY_CHANNELDOWN }, /* channel down */ - { 0x10, KEY_VOLUMEUP }, /* volume up */ - { 0x11, KEY_VOLUMEDOWN }, /* volume down */ - { 0x0d, KEY_MUTE }, - { 0x1f, KEY_RECORD }, - { 0x17, KEY_PLAY }, - { 0x16, KEY_PAUSE }, - { 0x0b, KEY_STOP }, - { 0x27, KEY_FASTFORWARD }, - { 0x26, KEY_REWIND }, - { 0x1e, KEY_SEARCH }, /* autoscan */ - { 0x0e, KEY_CAMERA }, /* snapshot */ - { 0x2d, KEY_SETUP }, - { 0x0f, KEY_SCREEN }, /* full screen */ - { 0x14, KEY_RADIO }, /* FM radio */ - { 0x25, KEY_POWER }, /* power */ -}; - -static struct rc_map_list powercolor_real_angel_map = { - .map = { - .scan = powercolor_real_angel, - .size = ARRAY_SIZE(powercolor_real_angel), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_POWERCOLOR_REAL_ANGEL, - } -}; - -static int __init init_rc_map_powercolor_real_angel(void) -{ - return rc_map_register(&powercolor_real_angel_map); -} - -static void __exit exit_rc_map_powercolor_real_angel(void) -{ - rc_map_unregister(&powercolor_real_angel_map); -} - -module_init(init_rc_map_powercolor_real_angel) -module_exit(exit_rc_map_powercolor_real_angel) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-proteus-2309.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-proteus-2309.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-proteus-2309.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-proteus-2309.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* proteus-2309.h - Keytable for proteus_2309 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Michal Majchrowicz */ - -static struct rc_map_table proteus_2309[] = { - /* numeric */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x5c, KEY_POWER }, /* power */ - { 0x20, KEY_ZOOM }, /* full screen */ - { 0x0f, KEY_BACKSPACE }, /* recall */ - { 0x1b, KEY_ENTER }, /* mute */ - { 0x41, KEY_RECORD }, /* record */ - { 0x43, KEY_STOP }, /* stop */ - { 0x16, KEY_S }, - { 0x1a, KEY_POWER2 }, /* off */ - { 0x2e, KEY_RED }, - { 0x1f, KEY_CHANNELDOWN }, /* channel - */ - { 0x1c, KEY_CHANNELUP }, /* channel + */ - { 0x10, KEY_VOLUMEDOWN }, /* volume - */ - { 0x1e, KEY_VOLUMEUP }, /* volume + */ - { 0x14, KEY_F1 }, -}; - -static struct rc_map_list proteus_2309_map = { - .map = { - .scan = proteus_2309, - .size = ARRAY_SIZE(proteus_2309), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PROTEUS_2309, - } -}; - -static int __init init_rc_map_proteus_2309(void) -{ - return rc_map_register(&proteus_2309_map); -} - -static void __exit exit_rc_map_proteus_2309(void) -{ - rc_map_unregister(&proteus_2309_map); -} - -module_init(init_rc_map_proteus_2309) -module_exit(exit_rc_map_proteus_2309) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-purpletv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-purpletv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-purpletv.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-purpletv.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/* purpletv.h - Keytable for purpletv Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table purpletv[] = { - { 0x03, KEY_POWER }, - { 0x6f, KEY_MUTE }, - { 0x10, KEY_BACKSPACE }, /* Recall */ - - { 0x11, KEY_0 }, - { 0x04, KEY_1 }, - { 0x05, KEY_2 }, - { 0x06, KEY_3 }, - { 0x08, KEY_4 }, - { 0x09, KEY_5 }, - { 0x0a, KEY_6 }, - { 0x0c, KEY_7 }, - { 0x0d, KEY_8 }, - { 0x0e, KEY_9 }, - { 0x12, KEY_DOT }, /* 100+ */ - - { 0x07, KEY_VOLUMEUP }, - { 0x0b, KEY_VOLUMEDOWN }, - { 0x1a, KEY_KPPLUS }, - { 0x18, KEY_KPMINUS }, - { 0x15, KEY_UP }, - { 0x1d, KEY_DOWN }, - { 0x0f, KEY_CHANNELUP }, - { 0x13, KEY_CHANNELDOWN }, - { 0x48, KEY_ZOOM }, - - { 0x1b, KEY_VIDEO }, /* Video source */ - { 0x1f, KEY_CAMERA }, /* Snapshot */ - { 0x49, KEY_LANGUAGE }, /* MTS Select */ - { 0x19, KEY_SEARCH }, /* Auto Scan */ - - { 0x4b, KEY_RECORD }, - { 0x46, KEY_PLAY }, - { 0x45, KEY_PAUSE }, /* Pause */ - { 0x44, KEY_STOP }, - { 0x43, KEY_TIME }, /* Time Shift */ - { 0x17, KEY_CHANNEL }, /* SURF CH */ - { 0x40, KEY_FORWARD }, /* Forward ? */ - { 0x42, KEY_REWIND }, /* Backward ? */ - -}; - -static struct rc_map_list purpletv_map = { - .map = { - .scan = purpletv, - .size = ARRAY_SIZE(purpletv), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PURPLETV, - } -}; - -static int __init init_rc_map_purpletv(void) -{ - return rc_map_register(&purpletv_map); -} - -static void __exit exit_rc_map_purpletv(void) -{ - rc_map_unregister(&purpletv_map); -} - -module_init(init_rc_map_purpletv) -module_exit(exit_rc_map_purpletv) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pv951.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pv951.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pv951.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-pv951.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* pv951.h - Keytable for pv951 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Mark Phalan */ - -static struct rc_map_table pv951[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x12, KEY_POWER }, - { 0x10, KEY_MUTE }, - { 0x1f, KEY_VOLUMEDOWN }, - { 0x1b, KEY_VOLUMEUP }, - { 0x1a, KEY_CHANNELUP }, - { 0x1e, KEY_CHANNELDOWN }, - { 0x0e, KEY_PAGEUP }, - { 0x1d, KEY_PAGEDOWN }, - { 0x13, KEY_SOUND }, - - { 0x18, KEY_KPPLUSMINUS }, /* CH +/- */ - { 0x16, KEY_SUBTITLE }, /* CC */ - { 0x0d, KEY_TEXT }, /* TTX */ - { 0x0b, KEY_TV }, /* AIR/CBL */ - { 0x11, KEY_PC }, /* PC/TV */ - { 0x17, KEY_OK }, /* CH RTN */ - { 0x19, KEY_MODE }, /* FUNC */ - { 0x0c, KEY_SEARCH }, /* AUTOSCAN */ - - /* Not sure what to do with these ones! */ - { 0x0f, KEY_VIDEO }, /* SOURCE */ - { 0x0a, KEY_KPPLUS }, /* +100 */ - { 0x14, KEY_EQUAL }, /* SYNC */ - { 0x1c, KEY_TV }, /* PC/TV */ -}; - -static struct rc_map_list pv951_map = { - .map = { - .scan = pv951, - .size = ARRAY_SIZE(pv951), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PV951, - } -}; - -static int __init init_rc_map_pv951(void) -{ - return rc_map_register(&pv951_map); -} - -static void __exit exit_rc_map_pv951(void) -{ - rc_map_unregister(&pv951_map); -} - -module_init(init_rc_map_pv951) -module_exit(exit_rc_map_pv951) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/* rc5-hauppauge-new.h - Keytable for rc5_hauppauge_new Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* - * Hauppauge:the newer, gray remotes (seems there are multiple - * slightly different versions), shipped with cx88+ivtv cards. - * - * This table contains the complete RC5 code, instead of just the data part - */ - -static struct rc_map_table rc5_hauppauge_new[] = { - /* Keys 0 to 9 */ - { 0x1e00, KEY_0 }, - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, - - { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ - { 0x1e0b, KEY_RED }, /* red button */ - { 0x1e0c, KEY_RADIO }, - { 0x1e0d, KEY_MENU }, - { 0x1e0e, KEY_SUBTITLE }, /* also the # key */ - { 0x1e0f, KEY_MUTE }, - { 0x1e10, KEY_VOLUMEUP }, - { 0x1e11, KEY_VOLUMEDOWN }, - { 0x1e12, KEY_PREVIOUS }, /* previous channel */ - { 0x1e14, KEY_UP }, - { 0x1e15, KEY_DOWN }, - { 0x1e16, KEY_LEFT }, - { 0x1e17, KEY_RIGHT }, - { 0x1e18, KEY_VIDEO }, /* Videos */ - { 0x1e19, KEY_AUDIO }, /* Music */ - /* 0x1e1a: Pictures - presume this means - "Multimedia Home Platform" - - no "PICTURES" key in input.h - */ - { 0x1e1a, KEY_MHP }, - - { 0x1e1b, KEY_EPG }, /* Guide */ - { 0x1e1c, KEY_TV }, - { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ - { 0x1e1f, KEY_EXIT }, /* back/exit */ - { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ - { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x1e22, KEY_CHANNEL }, /* source (old black remote) */ - { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x1e25, KEY_ENTER }, /* OK */ - { 0x1e26, KEY_SLEEP }, /* minimize (old black remote) */ - { 0x1e29, KEY_BLUE }, /* blue key */ - { 0x1e2e, KEY_GREEN }, /* green button */ - { 0x1e30, KEY_PAUSE }, /* pause */ - { 0x1e32, KEY_REWIND }, /* backward << */ - { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ - { 0x1e35, KEY_PLAY }, - { 0x1e36, KEY_STOP }, - { 0x1e37, KEY_RECORD }, /* recording */ - { 0x1e38, KEY_YELLOW }, /* yellow key */ - { 0x1e3b, KEY_SELECT }, /* top right button */ - { 0x1e3c, KEY_ZOOM }, /* full */ - { 0x1e3d, KEY_POWER }, /* system power (green button) */ - - /* Keycodes for DSR-0112 remote bundled with Haupauge MiniStick */ - { 0x1d00, KEY_0 }, - { 0x1d01, KEY_1 }, - { 0x1d02, KEY_2 }, - { 0x1d03, KEY_3 }, - { 0x1d04, KEY_4 }, - { 0x1d05, KEY_5 }, - { 0x1d06, KEY_6 }, - { 0x1d07, KEY_7 }, - { 0x1d08, KEY_8 }, - { 0x1d09, KEY_9 }, - { 0x1d0a, KEY_TEXT }, - { 0x1d0d, KEY_MENU }, - { 0x1d0f, KEY_MUTE }, - { 0x1d10, KEY_VOLUMEUP }, - { 0x1d11, KEY_VOLUMEDOWN }, - { 0x1d12, KEY_PREVIOUS }, /* Prev.Ch .. ??? */ - { 0x1d14, KEY_UP }, - { 0x1d15, KEY_DOWN }, - { 0x1d16, KEY_LEFT }, - { 0x1d17, KEY_RIGHT }, - { 0x1d1c, KEY_TV }, - { 0x1d1e, KEY_NEXT }, /* >| */ - { 0x1d1f, KEY_EXIT }, - { 0x1d20, KEY_CHANNELUP }, - { 0x1d21, KEY_CHANNELDOWN }, - { 0x1d24, KEY_LAST }, /* <| */ - { 0x1d25, KEY_OK }, - { 0x1d30, KEY_PAUSE }, - { 0x1d32, KEY_REWIND }, - { 0x1d34, KEY_FASTFORWARD }, - { 0x1d35, KEY_PLAY }, - { 0x1d36, KEY_STOP }, - { 0x1d37, KEY_RECORD }, - { 0x1d3b, KEY_GOTO }, - { 0x1d3d, KEY_POWER }, - { 0x1d3f, KEY_HOME }, -}; - -static struct rc_map_list rc5_hauppauge_new_map = { - .map = { - .scan = rc5_hauppauge_new, - .size = ARRAY_SIZE(rc5_hauppauge_new), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_RC5_HAUPPAUGE_NEW, - } -}; - -static int __init init_rc_map_rc5_hauppauge_new(void) -{ - return rc_map_register(&rc5_hauppauge_new_map); -} - -static void __exit exit_rc_map_rc5_hauppauge_new(void) -{ - rc_map_unregister(&rc5_hauppauge_new_map); -} - -module_init(init_rc_map_rc5_hauppauge_new) -module_exit(exit_rc_map_rc5_hauppauge_new) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc5-tv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc5-tv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc5-tv.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc5-tv.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/* rc5-tv.h - Keytable for rc5_tv Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* generic RC5 keytable */ -/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */ -/* used by old (black) Hauppauge remotes */ - -static struct rc_map_table rc5_tv[] = { - /* Keys 0 to 9 */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x0b, KEY_CHANNEL }, /* channel / program (japan: 11) */ - { 0x0c, KEY_POWER }, /* standby */ - { 0x0d, KEY_MUTE }, /* mute / demute */ - { 0x0f, KEY_TV }, /* display */ - { 0x10, KEY_VOLUMEUP }, - { 0x11, KEY_VOLUMEDOWN }, - { 0x12, KEY_BRIGHTNESSUP }, - { 0x13, KEY_BRIGHTNESSDOWN }, - { 0x1e, KEY_SEARCH }, /* search + */ - { 0x20, KEY_CHANNELUP }, /* channel / program + */ - { 0x21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x22, KEY_CHANNEL }, /* alt / channel */ - { 0x23, KEY_LANGUAGE }, /* 1st / 2nd language */ - { 0x26, KEY_SLEEP }, /* sleeptimer */ - { 0x2e, KEY_MENU }, /* 2nd controls (USA: menu) */ - { 0x30, KEY_PAUSE }, - { 0x32, KEY_REWIND }, - { 0x33, KEY_GOTO }, - { 0x35, KEY_PLAY }, - { 0x36, KEY_STOP }, - { 0x37, KEY_RECORD }, /* recording */ - { 0x3c, KEY_TEXT }, /* teletext submode (Japan: 12) */ - { 0x3d, KEY_SUSPEND }, /* system standby */ - -}; - -static struct rc_map_list rc5_tv_map = { - .map = { - .scan = rc5_tv, - .size = ARRAY_SIZE(rc5_tv), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_RC5_TV, - } -}; - -static int __init init_rc_map_rc5_tv(void) -{ - return rc_map_register(&rc5_tv_map); -} - -static void __exit exit_rc_map_rc5_tv(void) -{ - rc_map_unregister(&rc5_tv_map); -} - -module_init(init_rc_map_rc5_tv) -module_exit(exit_rc_map_rc5_tv) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc6-mce.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc6-mce.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc6-mce.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-rc6-mce.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,119 +0,0 @@ -/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use - * with the Media Center Edition eHome Infrared Transceiver. - * - * Copyright (c) 2010 by Jarod Wilson - * - * See http://mediacenterguides.com/book/export/html/31 for details on - * key mappings. - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table rc6_mce[] = { - - { 0x800f0400, KEY_NUMERIC_0 }, - { 0x800f0401, KEY_NUMERIC_1 }, - { 0x800f0402, KEY_NUMERIC_2 }, - { 0x800f0403, KEY_NUMERIC_3 }, - { 0x800f0404, KEY_NUMERIC_4 }, - { 0x800f0405, KEY_NUMERIC_5 }, - { 0x800f0406, KEY_NUMERIC_6 }, - { 0x800f0407, KEY_NUMERIC_7 }, - { 0x800f0408, KEY_NUMERIC_8 }, - { 0x800f0409, KEY_NUMERIC_9 }, - - { 0x800f040a, KEY_DELETE }, - { 0x800f040b, KEY_ENTER }, - { 0x800f040c, KEY_POWER }, /* PC Power */ - { 0x800f040d, KEY_LEFTMETA }, /* Windows MCE button */ - { 0x800f040e, KEY_MUTE }, - { 0x800f040f, KEY_INFO }, - - { 0x800f0410, KEY_VOLUMEUP }, - { 0x800f0411, KEY_VOLUMEDOWN }, - { 0x800f0412, KEY_CHANNELUP }, - { 0x800f0413, KEY_CHANNELDOWN }, - - { 0x800f0414, KEY_FASTFORWARD }, - { 0x800f0415, KEY_REWIND }, - { 0x800f0416, KEY_PLAY }, - { 0x800f0417, KEY_RECORD }, - { 0x800f0418, KEY_PAUSE }, - { 0x800f046e, KEY_PLAYPAUSE }, - { 0x800f0419, KEY_STOP }, - { 0x800f041a, KEY_NEXT }, - { 0x800f041b, KEY_PREVIOUS }, - { 0x800f041c, KEY_NUMERIC_POUND }, - { 0x800f041d, KEY_NUMERIC_STAR }, - - { 0x800f041e, KEY_UP }, - { 0x800f041f, KEY_DOWN }, - { 0x800f0420, KEY_LEFT }, - { 0x800f0421, KEY_RIGHT }, - - { 0x800f0422, KEY_OK }, - { 0x800f0423, KEY_EXIT }, - { 0x800f0424, KEY_DVD }, - { 0x800f0425, KEY_TUNER }, /* LiveTV */ - { 0x800f0426, KEY_EPG }, /* Guide */ - { 0x800f0427, KEY_ZOOM }, /* Aspect */ - - { 0x800f0432, KEY_MODE }, /* Visualization */ - { 0x800f0433, KEY_PRESENTATION }, /* Slide Show */ - { 0x800f0434, KEY_EJECTCD }, - { 0x800f043a, KEY_BRIGHTNESSUP }, - - { 0x800f0446, KEY_TV }, - { 0x800f0447, KEY_AUDIO }, /* My Music */ - { 0x800f0448, KEY_PVR }, /* RecordedTV */ - { 0x800f0449, KEY_CAMERA }, - { 0x800f044a, KEY_VIDEO }, - { 0x800f044c, KEY_LANGUAGE }, - { 0x800f044d, KEY_TITLE }, - { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */ - - { 0x800f0450, KEY_RADIO }, - - { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */ - { 0x800f045b, KEY_RED }, - { 0x800f045c, KEY_GREEN }, - { 0x800f045d, KEY_YELLOW }, - { 0x800f045e, KEY_BLUE }, - - { 0x800f0465, KEY_POWER2 }, /* TV Power */ - { 0x800f046e, KEY_PLAYPAUSE }, - { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */ - - { 0x800f0480, KEY_BRIGHTNESSDOWN }, - { 0x800f0481, KEY_PLAYPAUSE }, -}; - -static struct rc_map_list rc6_mce_map = { - .map = { - .scan = rc6_mce, - .size = ARRAY_SIZE(rc6_mce), - .rc_type = RC_TYPE_RC6, - .name = RC_MAP_RC6_MCE, - } -}; - -static int __init init_rc_map_rc6_mce(void) -{ - return rc_map_register(&rc6_mce_map); -} - -static void __exit exit_rc_map_rc6_mce(void) -{ - rc_map_unregister(&rc6_mce_map); -} - -module_init(init_rc_map_rc6_mce) -module_exit(exit_rc_map_rc6_mce) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* real-audio-220-32-keys.h - Keytable for real_audio_220_32_keys Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Zogis Real Audio 220 - 32 keys IR */ - -static struct rc_map_table real_audio_220_32_keys[] = { - { 0x1c, KEY_RADIO}, - { 0x12, KEY_POWER2}, - - { 0x01, KEY_1}, - { 0x02, KEY_2}, - { 0x03, KEY_3}, - { 0x04, KEY_4}, - { 0x05, KEY_5}, - { 0x06, KEY_6}, - { 0x07, KEY_7}, - { 0x08, KEY_8}, - { 0x09, KEY_9}, - { 0x00, KEY_0}, - - { 0x0c, KEY_VOLUMEUP}, - { 0x18, KEY_VOLUMEDOWN}, - { 0x0b, KEY_CHANNELUP}, - { 0x15, KEY_CHANNELDOWN}, - { 0x16, KEY_ENTER}, - - { 0x11, KEY_VIDEO}, /* Source */ - { 0x0d, KEY_AUDIO}, /* stereo */ - - { 0x0f, KEY_PREVIOUS}, /* Prev */ - { 0x1b, KEY_TIME}, /* Timeshift */ - { 0x1a, KEY_NEXT}, /* Next */ - - { 0x0e, KEY_STOP}, - { 0x1f, KEY_PLAY}, - { 0x1e, KEY_PLAYPAUSE}, /* Pause */ - - { 0x1d, KEY_RECORD}, - { 0x13, KEY_MUTE}, - { 0x19, KEY_CAMERA}, /* Snapshot */ - -}; - -static struct rc_map_list real_audio_220_32_keys_map = { - .map = { - .scan = real_audio_220_32_keys, - .size = ARRAY_SIZE(real_audio_220_32_keys), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_REAL_AUDIO_220_32_KEYS, - } -}; - -static int __init init_rc_map_real_audio_220_32_keys(void) -{ - return rc_map_register(&real_audio_220_32_keys_map); -} - -static void __exit exit_rc_map_real_audio_220_32_keys(void) -{ - rc_map_unregister(&real_audio_220_32_keys_map); -} - -module_init(init_rc_map_real_audio_220_32_keys) -module_exit(exit_rc_map_real_audio_220_32_keys) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-streamzap.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-streamzap.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-streamzap.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-streamzap.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* rc-streamzap.c - Keytable for Streamzap PC Remote, for use - * with the Streamzap PC Remote IR Receiver. - * - * Copyright (c) 2010 by Jarod Wilson - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table streamzap[] = { -/* - * The Streamzap remote is almost, but not quite, RC-5, as it has an extra - * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently, - * an additional RC-5-sz decoder is being deployed to support it, but it - * may be possible to merge it back with the standard RC-5 decoder. - */ - { 0x28c0, KEY_NUMERIC_0 }, - { 0x28c1, KEY_NUMERIC_1 }, - { 0x28c2, KEY_NUMERIC_2 }, - { 0x28c3, KEY_NUMERIC_3 }, - { 0x28c4, KEY_NUMERIC_4 }, - { 0x28c5, KEY_NUMERIC_5 }, - { 0x28c6, KEY_NUMERIC_6 }, - { 0x28c7, KEY_NUMERIC_7 }, - { 0x28c8, KEY_NUMERIC_8 }, - { 0x28c9, KEY_NUMERIC_9 }, - { 0x28ca, KEY_POWER }, - { 0x28cb, KEY_MUTE }, - { 0x28cc, KEY_CHANNELUP }, - { 0x28cd, KEY_VOLUMEUP }, - { 0x28ce, KEY_CHANNELDOWN }, - { 0x28cf, KEY_VOLUMEDOWN }, - { 0x28d0, KEY_UP }, - { 0x28d1, KEY_LEFT }, - { 0x28d2, KEY_OK }, - { 0x28d3, KEY_RIGHT }, - { 0x28d4, KEY_DOWN }, - { 0x28d5, KEY_MENU }, - { 0x28d6, KEY_EXIT }, - { 0x28d7, KEY_PLAY }, - { 0x28d8, KEY_PAUSE }, - { 0x28d9, KEY_STOP }, - { 0x28da, KEY_BACK }, - { 0x28db, KEY_FORWARD }, - { 0x28dc, KEY_RECORD }, - { 0x28dd, KEY_REWIND }, - { 0x28de, KEY_FASTFORWARD }, - { 0x28e0, KEY_RED }, - { 0x28e1, KEY_GREEN }, - { 0x28e2, KEY_YELLOW }, - { 0x28e3, KEY_BLUE }, - -}; - -static struct rc_map_list streamzap_map = { - .map = { - .scan = streamzap, - .size = ARRAY_SIZE(streamzap), - .rc_type = RC_TYPE_RC5_SZ, - .name = RC_MAP_STREAMZAP, - } -}; - -static int __init init_rc_map_streamzap(void) -{ - return rc_map_register(&streamzap_map); -} - -static void __exit exit_rc_map_streamzap(void) -{ - rc_map_unregister(&streamzap_map); -} - -module_init(init_rc_map_streamzap) -module_exit(exit_rc_map_streamzap) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tbs-nec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tbs-nec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tbs-nec.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tbs-nec.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/* tbs-nec.h - Keytable for tbs_nec Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table tbs_nec[] = { - { 0x84, KEY_POWER2}, /* power */ - { 0x94, KEY_MUTE}, /* mute */ - { 0x87, KEY_1}, - { 0x86, KEY_2}, - { 0x85, KEY_3}, - { 0x8b, KEY_4}, - { 0x8a, KEY_5}, - { 0x89, KEY_6}, - { 0x8f, KEY_7}, - { 0x8e, KEY_8}, - { 0x8d, KEY_9}, - { 0x92, KEY_0}, - { 0xc0, KEY_10CHANNELSUP}, /* 10+ */ - { 0xd0, KEY_10CHANNELSDOWN}, /* 10- */ - { 0x96, KEY_CHANNELUP}, /* ch+ */ - { 0x91, KEY_CHANNELDOWN}, /* ch- */ - { 0x93, KEY_VOLUMEUP}, /* vol+ */ - { 0x8c, KEY_VOLUMEDOWN}, /* vol- */ - { 0x83, KEY_RECORD}, /* rec */ - { 0x98, KEY_PAUSE}, /* pause, yellow */ - { 0x99, KEY_OK}, /* ok */ - { 0x9a, KEY_CAMERA}, /* snapshot */ - { 0x81, KEY_UP}, - { 0x90, KEY_LEFT}, - { 0x82, KEY_RIGHT}, - { 0x88, KEY_DOWN}, - { 0x95, KEY_FAVORITES}, /* blue */ - { 0x97, KEY_SUBTITLE}, /* green */ - { 0x9d, KEY_ZOOM}, - { 0x9f, KEY_EXIT}, - { 0x9e, KEY_MENU}, - { 0x9c, KEY_EPG}, - { 0x80, KEY_PREVIOUS}, /* red */ - { 0x9b, KEY_MODE}, -}; - -static struct rc_map_list tbs_nec_map = { - .map = { - .scan = tbs_nec, - .size = ARRAY_SIZE(tbs_nec), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TBS_NEC, - } -}; - -static int __init init_rc_map_tbs_nec(void) -{ - return rc_map_register(&tbs_nec_map); -} - -static void __exit exit_rc_map_tbs_nec(void) -{ - rc_map_unregister(&tbs_nec_map); -} - -module_init(init_rc_map_tbs_nec) -module_exit(exit_rc_map_tbs_nec) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-technisat-usb2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-technisat-usb2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-technisat-usb2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-technisat-usb2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/* rc-technisat-usb2.c - Keytable for SkyStar HD USB - * - * Copyright (C) 2010 Patrick Boettcher, - * Kernel Labs Inc. PO Box 745, St James, NY 11780 - * - * Development was sponsored by Technisat Digital UK Limited, whose - * registered office is Witan Gate House 500 - 600 Witan Gate West, - * Milton Keynes, MK9 1SH - * - * 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, or (at your option) any later version. - * - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND - * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO - * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR - * FITNESS FOR A PARTICULAR PURPOSE. NEITHER THE COPYRIGHT HOLDER - * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL, - * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR - * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the - * GNU General Public License for more details. - */ - -#include - -static struct rc_map_table technisat_usb2[] = { - {0x0a0c, KEY_POWER}, - {0x0a01, KEY_1}, - {0x0a02, KEY_2}, - {0x0a03, KEY_3}, - {0x0a0d, KEY_MUTE}, - {0x0a04, KEY_4}, - {0x0a05, KEY_5}, - {0x0a06, KEY_6}, - {0x0a38, KEY_VIDEO}, /* EXT */ - {0x0a07, KEY_7}, - {0x0a08, KEY_8}, - {0x0a09, KEY_9}, - {0x0a00, KEY_0}, - {0x0a4f, KEY_INFO}, - {0x0a20, KEY_CHANNELUP}, - {0x0a52, KEY_MENU}, - {0x0a11, KEY_VOLUMEUP}, - {0x0a57, KEY_OK}, - {0x0a10, KEY_VOLUMEDOWN}, - {0x0a2f, KEY_EPG}, - {0x0a21, KEY_CHANNELDOWN}, - {0x0a22, KEY_REFRESH}, - {0x0a3c, KEY_TEXT}, - {0x0a76, KEY_ENTER}, /* HOOK */ - {0x0a0f, KEY_HELP}, - {0x0a6b, KEY_RED}, - {0x0a6c, KEY_GREEN}, - {0x0a6d, KEY_YELLOW}, - {0x0a6e, KEY_BLUE}, - {0x0a29, KEY_STOP}, - {0x0a23, KEY_LANGUAGE}, - {0x0a53, KEY_TV}, - {0x0a0a, KEY_PROGRAM}, -}; - -static struct rc_map_list technisat_usb2_map = { - .map = { - .scan = technisat_usb2, - .size = ARRAY_SIZE(technisat_usb2), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_TECHNISAT_USB2, - } -}; - -static int __init init_rc_map(void) -{ - return rc_map_register(&technisat_usb2_map); -} - -static void __exit exit_rc_map(void) -{ - rc_map_unregister(&technisat_usb2_map); -} - -module_init(init_rc_map) -module_exit(exit_rc_map) - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/* terratec-cinergy-xs.h - Keytable for terratec_cinergy_xs Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Terratec Cinergy Hybrid T USB XS - Devin Heitmueller - */ - -static struct rc_map_table terratec_cinergy_xs[] = { - { 0x41, KEY_HOME}, - { 0x01, KEY_POWER}, - { 0x42, KEY_MENU}, - { 0x02, KEY_1}, - { 0x03, KEY_2}, - { 0x04, KEY_3}, - { 0x43, KEY_SUBTITLE}, - { 0x05, KEY_4}, - { 0x06, KEY_5}, - { 0x07, KEY_6}, - { 0x44, KEY_TEXT}, - { 0x08, KEY_7}, - { 0x09, KEY_8}, - { 0x0a, KEY_9}, - { 0x45, KEY_DELETE}, - { 0x0b, KEY_TUNER}, - { 0x0c, KEY_0}, - { 0x0d, KEY_MODE}, - { 0x46, KEY_TV}, - { 0x47, KEY_DVD}, - { 0x49, KEY_VIDEO}, - { 0x4b, KEY_AUX}, - { 0x10, KEY_UP}, - { 0x11, KEY_LEFT}, - { 0x12, KEY_OK}, - { 0x13, KEY_RIGHT}, - { 0x14, KEY_DOWN}, - { 0x0f, KEY_EPG}, - { 0x16, KEY_INFO}, - { 0x4d, KEY_BACKSPACE}, - { 0x1c, KEY_VOLUMEUP}, - { 0x4c, KEY_PLAY}, - { 0x1b, KEY_CHANNELUP}, - { 0x1e, KEY_VOLUMEDOWN}, - { 0x1d, KEY_MUTE}, - { 0x1f, KEY_CHANNELDOWN}, - { 0x17, KEY_RED}, - { 0x18, KEY_GREEN}, - { 0x19, KEY_YELLOW}, - { 0x1a, KEY_BLUE}, - { 0x58, KEY_RECORD}, - { 0x48, KEY_STOP}, - { 0x40, KEY_PAUSE}, - { 0x54, KEY_LAST}, - { 0x4e, KEY_REWIND}, - { 0x4f, KEY_FASTFORWARD}, - { 0x5c, KEY_NEXT}, -}; - -static struct rc_map_list terratec_cinergy_xs_map = { - .map = { - .scan = terratec_cinergy_xs, - .size = ARRAY_SIZE(terratec_cinergy_xs), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TERRATEC_CINERGY_XS, - } -}; - -static int __init init_rc_map_terratec_cinergy_xs(void) -{ - return rc_map_register(&terratec_cinergy_xs_map); -} - -static void __exit exit_rc_map_terratec_cinergy_xs(void) -{ - rc_map_unregister(&terratec_cinergy_xs_map); -} - -module_init(init_rc_map_terratec_cinergy_xs) -module_exit(exit_rc_map_terratec_cinergy_xs) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-slim-2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-slim-2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-slim-2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-slim-2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/* - * TerraTec remote controller keytable - * - * Copyright (C) 2011 Martin Groszhauser - * Copyright (C) 2011 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -/* - * TerraTec slim remote, 6 rows, 3 columns. - * Keytable from Martin Groszhauser - */ -static struct rc_map_table terratec_slim_2[] = { - { 0x8001, KEY_MUTE }, /* MUTE */ - { 0x8002, KEY_VOLUMEDOWN }, - { 0x8003, KEY_CHANNELDOWN }, - { 0x8004, KEY_1 }, - { 0x8005, KEY_2 }, - { 0x8006, KEY_3 }, - { 0x8007, KEY_4 }, - { 0x8008, KEY_5 }, - { 0x8009, KEY_6 }, - { 0x800a, KEY_7 }, - { 0x800c, KEY_ZOOM }, /* [fullscreen] */ - { 0x800d, KEY_0 }, - { 0x800e, KEY_AGAIN }, /* [two arrows forming a circle] */ - { 0x8012, KEY_POWER2 }, /* [red power button] */ - { 0x801a, KEY_VOLUMEUP }, - { 0x801b, KEY_8 }, - { 0x801e, KEY_CHANNELUP }, - { 0x801f, KEY_9 }, -}; - -static struct rc_map_list terratec_slim_2_map = { - .map = { - .scan = terratec_slim_2, - .size = ARRAY_SIZE(terratec_slim_2), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_TERRATEC_SLIM_2, - } -}; - -static int __init init_rc_map_terratec_slim_2(void) -{ - return rc_map_register(&terratec_slim_2_map); -} - -static void __exit exit_rc_map_terratec_slim_2(void) -{ - rc_map_unregister(&terratec_slim_2_map); -} - -module_init(init_rc_map_terratec_slim_2) -module_exit(exit_rc_map_terratec_slim_2) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-slim.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-slim.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-slim.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-terratec-slim.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/* - * TerraTec remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -/* TerraTec slim remote, 7 rows, 4 columns. */ -/* Uses NEC extended 0x02bd. */ -static struct rc_map_table terratec_slim[] = { - { 0x02bd00, KEY_1 }, - { 0x02bd01, KEY_2 }, - { 0x02bd02, KEY_3 }, - { 0x02bd03, KEY_4 }, - { 0x02bd04, KEY_5 }, - { 0x02bd05, KEY_6 }, - { 0x02bd06, KEY_7 }, - { 0x02bd07, KEY_8 }, - { 0x02bd08, KEY_9 }, - { 0x02bd09, KEY_0 }, - { 0x02bd0a, KEY_MUTE }, - { 0x02bd0b, KEY_NEW }, /* symbol: PIP */ - { 0x02bd0e, KEY_VOLUMEDOWN }, - { 0x02bd0f, KEY_PLAYPAUSE }, - { 0x02bd10, KEY_RIGHT }, - { 0x02bd11, KEY_LEFT }, - { 0x02bd12, KEY_UP }, - { 0x02bd13, KEY_DOWN }, - { 0x02bd15, KEY_OK }, - { 0x02bd16, KEY_STOP }, - { 0x02bd17, KEY_CAMERA }, /* snapshot */ - { 0x02bd18, KEY_CHANNELUP }, - { 0x02bd19, KEY_RECORD }, - { 0x02bd1a, KEY_CHANNELDOWN }, - { 0x02bd1c, KEY_ESC }, - { 0x02bd1f, KEY_VOLUMEUP }, - { 0x02bd44, KEY_EPG }, - { 0x02bd45, KEY_POWER2 }, /* [red power button] */ -}; - -static struct rc_map_list terratec_slim_map = { - .map = { - .scan = terratec_slim, - .size = ARRAY_SIZE(terratec_slim), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_TERRATEC_SLIM, - } -}; - -static int __init init_rc_map_terratec_slim(void) -{ - return rc_map_register(&terratec_slim_map); -} - -static void __exit exit_rc_map_terratec_slim(void) -{ - rc_map_unregister(&terratec_slim_map); -} - -module_init(init_rc_map_terratec_slim) -module_exit(exit_rc_map_terratec_slim) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tevii-nec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tevii-nec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tevii-nec.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tevii-nec.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -/* tevii-nec.h - Keytable for tevii_nec Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table tevii_nec[] = { - { 0x0a, KEY_POWER2}, - { 0x0c, KEY_MUTE}, - { 0x11, KEY_1}, - { 0x12, KEY_2}, - { 0x13, KEY_3}, - { 0x14, KEY_4}, - { 0x15, KEY_5}, - { 0x16, KEY_6}, - { 0x17, KEY_7}, - { 0x18, KEY_8}, - { 0x19, KEY_9}, - { 0x10, KEY_0}, - { 0x1c, KEY_MENU}, - { 0x0f, KEY_VOLUMEDOWN}, - { 0x1a, KEY_LAST}, - { 0x0e, KEY_OPEN}, - { 0x04, KEY_RECORD}, - { 0x09, KEY_VOLUMEUP}, - { 0x08, KEY_CHANNELUP}, - { 0x07, KEY_PVR}, - { 0x0b, KEY_TIME}, - { 0x02, KEY_RIGHT}, - { 0x03, KEY_LEFT}, - { 0x00, KEY_UP}, - { 0x1f, KEY_OK}, - { 0x01, KEY_DOWN}, - { 0x05, KEY_TUNER}, - { 0x06, KEY_CHANNELDOWN}, - { 0x40, KEY_PLAYPAUSE}, - { 0x1e, KEY_REWIND}, - { 0x1b, KEY_FAVORITES}, - { 0x1d, KEY_BACK}, - { 0x4d, KEY_FASTFORWARD}, - { 0x44, KEY_EPG}, - { 0x4c, KEY_INFO}, - { 0x41, KEY_AB}, - { 0x43, KEY_AUDIO}, - { 0x45, KEY_SUBTITLE}, - { 0x4a, KEY_LIST}, - { 0x46, KEY_F1}, - { 0x47, KEY_F2}, - { 0x5e, KEY_F3}, - { 0x5c, KEY_F4}, - { 0x52, KEY_F5}, - { 0x5a, KEY_F6}, - { 0x56, KEY_MODE}, - { 0x58, KEY_SWITCHVIDEOMODE}, -}; - -static struct rc_map_list tevii_nec_map = { - .map = { - .scan = tevii_nec, - .size = ARRAY_SIZE(tevii_nec), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TEVII_NEC, - } -}; - -static int __init init_rc_map_tevii_nec(void) -{ - return rc_map_register(&tevii_nec_map); -} - -static void __exit exit_rc_map_tevii_nec(void) -{ - rc_map_unregister(&tevii_nec_map); -} - -module_init(init_rc_map_tevii_nec) -module_exit(exit_rc_map_tevii_nec) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-total-media-in-hand.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-total-media-in-hand.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-total-media-in-hand.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-total-media-in-hand.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* - * Total Media In Hand remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -/* Uses NEC extended 0x02bd */ -static struct rc_map_table total_media_in_hand[] = { - { 0x02bd00, KEY_1 }, - { 0x02bd01, KEY_2 }, - { 0x02bd02, KEY_3 }, - { 0x02bd03, KEY_4 }, - { 0x02bd04, KEY_5 }, - { 0x02bd05, KEY_6 }, - { 0x02bd06, KEY_7 }, - { 0x02bd07, KEY_8 }, - { 0x02bd08, KEY_9 }, - { 0x02bd09, KEY_0 }, - { 0x02bd0a, KEY_MUTE }, - { 0x02bd0b, KEY_CYCLEWINDOWS }, /* yellow, [min / max] */ - { 0x02bd0c, KEY_VIDEO }, /* TV / AV */ - { 0x02bd0e, KEY_VOLUMEDOWN }, - { 0x02bd0f, KEY_TIME }, /* TimeShift */ - { 0x02bd10, KEY_RIGHT }, /* right arrow */ - { 0x02bd11, KEY_LEFT }, /* left arrow */ - { 0x02bd12, KEY_UP }, /* up arrow */ - { 0x02bd13, KEY_DOWN }, /* down arrow */ - { 0x02bd14, KEY_POWER2 }, /* [red] */ - { 0x02bd15, KEY_OK }, /* OK */ - { 0x02bd16, KEY_STOP }, - { 0x02bd17, KEY_CAMERA }, /* Snapshot */ - { 0x02bd18, KEY_CHANNELUP }, - { 0x02bd19, KEY_RECORD }, - { 0x02bd1a, KEY_CHANNELDOWN }, - { 0x02bd1c, KEY_ESC }, /* Esc */ - { 0x02bd1e, KEY_PLAY }, - { 0x02bd1f, KEY_VOLUMEUP }, - { 0x02bd40, KEY_PAUSE }, - { 0x02bd41, KEY_FASTFORWARD }, /* FF >> */ - { 0x02bd42, KEY_REWIND }, /* FR << */ - { 0x02bd43, KEY_ZOOM }, /* [window + mouse pointer] */ - { 0x02bd44, KEY_SHUFFLE }, /* Shuffle */ - { 0x02bd45, KEY_INFO }, /* [red (I)] */ -}; - -static struct rc_map_list total_media_in_hand_map = { - .map = { - .scan = total_media_in_hand, - .size = ARRAY_SIZE(total_media_in_hand), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_TOTAL_MEDIA_IN_HAND, - } -}; - -static int __init init_rc_map_total_media_in_hand(void) -{ - return rc_map_register(&total_media_in_hand_map); -} - -static void __exit exit_rc_map_total_media_in_hand(void) -{ - rc_map_unregister(&total_media_in_hand_map); -} - -module_init(init_rc_map_total_media_in_hand) -module_exit(exit_rc_map_total_media_in_hand) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-trekstor.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-trekstor.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-trekstor.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-trekstor.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/* - * TrekStor remote controller keytable - * - * Copyright (C) 2010 Antti Palosaari - * - * 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, or - * (at your option) any later version. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -/* TrekStor DVB-T USB Stick remote controller. */ -/* Imported from af9015.h. - Initial keytable was from Marc Schneider */ -static struct rc_map_table trekstor[] = { - { 0x0084, KEY_0 }, - { 0x0085, KEY_MUTE }, /* Mute */ - { 0x0086, KEY_HOMEPAGE }, /* Home */ - { 0x0087, KEY_UP }, /* Up */ - { 0x0088, KEY_OK }, /* OK */ - { 0x0089, KEY_RIGHT }, /* Right */ - { 0x008a, KEY_FASTFORWARD }, /* Fast forward */ - { 0x008b, KEY_VOLUMEUP }, /* Volume + */ - { 0x008c, KEY_DOWN }, /* Down */ - { 0x008d, KEY_PLAY }, /* Play/Pause */ - { 0x008e, KEY_STOP }, /* Stop */ - { 0x008f, KEY_EPG }, /* Info/EPG */ - { 0x0090, KEY_7 }, - { 0x0091, KEY_4 }, - { 0x0092, KEY_1 }, - { 0x0093, KEY_CHANNELDOWN }, /* Channel - */ - { 0x0094, KEY_8 }, - { 0x0095, KEY_5 }, - { 0x0096, KEY_2 }, - { 0x0097, KEY_CHANNELUP }, /* Channel + */ - { 0x0098, KEY_9 }, - { 0x0099, KEY_6 }, - { 0x009a, KEY_3 }, - { 0x009b, KEY_VOLUMEDOWN }, /* Volume - */ - { 0x009c, KEY_TV }, /* TV */ - { 0x009d, KEY_RECORD }, /* Record */ - { 0x009e, KEY_REWIND }, /* Rewind */ - { 0x009f, KEY_LEFT }, /* Left */ -}; - -static struct rc_map_list trekstor_map = { - .map = { - .scan = trekstor, - .size = ARRAY_SIZE(trekstor), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_TREKSTOR, - } -}; - -static int __init init_rc_map_trekstor(void) -{ - return rc_map_register(&trekstor_map); -} - -static void __exit exit_rc_map_trekstor(void) -{ - rc_map_unregister(&trekstor_map); -} - -module_init(init_rc_map_trekstor) -module_exit(exit_rc_map_trekstor) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tt-1500.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tt-1500.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tt-1500.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-tt-1500.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* tt-1500.h - Keytable for tt_1500 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* for the Technotrend 1500 bundled remotes (grey and black): */ - -static struct rc_map_table tt_1500[] = { - { 0x1501, KEY_POWER }, - { 0x1502, KEY_SHUFFLE }, /* ? double-arrow key */ - { 0x1503, KEY_1 }, - { 0x1504, KEY_2 }, - { 0x1505, KEY_3 }, - { 0x1506, KEY_4 }, - { 0x1507, KEY_5 }, - { 0x1508, KEY_6 }, - { 0x1509, KEY_7 }, - { 0x150a, KEY_8 }, - { 0x150b, KEY_9 }, - { 0x150c, KEY_0 }, - { 0x150d, KEY_UP }, - { 0x150e, KEY_LEFT }, - { 0x150f, KEY_OK }, - { 0x1510, KEY_RIGHT }, - { 0x1511, KEY_DOWN }, - { 0x1512, KEY_INFO }, - { 0x1513, KEY_EXIT }, - { 0x1514, KEY_RED }, - { 0x1515, KEY_GREEN }, - { 0x1516, KEY_YELLOW }, - { 0x1517, KEY_BLUE }, - { 0x1518, KEY_MUTE }, - { 0x1519, KEY_TEXT }, - { 0x151a, KEY_MODE }, /* ? TV/Radio */ - { 0x1521, KEY_OPTION }, - { 0x1522, KEY_EPG }, - { 0x1523, KEY_CHANNELUP }, - { 0x1524, KEY_CHANNELDOWN }, - { 0x1525, KEY_VOLUMEUP }, - { 0x1526, KEY_VOLUMEDOWN }, - { 0x1527, KEY_SETUP }, - { 0x153a, KEY_RECORD }, /* these keys are only in the black remote */ - { 0x153b, KEY_PLAY }, - { 0x153c, KEY_STOP }, - { 0x153d, KEY_REWIND }, - { 0x153e, KEY_PAUSE }, - { 0x153f, KEY_FORWARD }, -}; - -static struct rc_map_list tt_1500_map = { - .map = { - .scan = tt_1500, - .size = ARRAY_SIZE(tt_1500), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TT_1500, - } -}; - -static int __init init_rc_map_tt_1500(void) -{ - return rc_map_register(&tt_1500_map); -} - -static void __exit exit_rc_map_tt_1500(void) -{ - rc_map_unregister(&tt_1500_map); -} - -module_init(init_rc_map_tt_1500) -module_exit(exit_rc_map_tt_1500) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-twinhan1027.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-twinhan1027.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-twinhan1027.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-twinhan1027.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -#include - -static struct rc_map_table twinhan_vp1027[] = { - { 0x16, KEY_POWER2 }, - { 0x17, KEY_FAVORITES }, - { 0x0f, KEY_TEXT }, - { 0x48, KEY_INFO}, - { 0x1c, KEY_EPG }, - { 0x04, KEY_LIST }, - - { 0x03, KEY_1 }, - { 0x01, KEY_2 }, - { 0x06, KEY_3 }, - { 0x09, KEY_4 }, - { 0x1d, KEY_5 }, - { 0x1f, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x19, KEY_8 }, - { 0x1b, KEY_9 }, - { 0x15, KEY_0 }, - - { 0x0c, KEY_CANCEL }, - { 0x4a, KEY_CLEAR }, - { 0x13, KEY_BACKSPACE }, - { 0x00, KEY_TAB }, - - { 0x4b, KEY_UP }, - { 0x51, KEY_DOWN }, - { 0x4e, KEY_LEFT }, - { 0x52, KEY_RIGHT }, - { 0x4f, KEY_ENTER }, - - { 0x1e, KEY_VOLUMEUP }, - { 0x0a, KEY_VOLUMEDOWN }, - { 0x02, KEY_CHANNELDOWN }, - { 0x05, KEY_CHANNELUP }, - { 0x11, KEY_RECORD }, - - { 0x14, KEY_PLAY }, - { 0x4c, KEY_PAUSE }, - { 0x1a, KEY_STOP }, - { 0x40, KEY_REWIND }, - { 0x12, KEY_FASTFORWARD }, - { 0x41, KEY_PREVIOUSSONG }, - { 0x42, KEY_NEXTSONG }, - { 0x54, KEY_SAVE }, - { 0x50, KEY_LANGUAGE }, - { 0x47, KEY_MEDIA }, - { 0x4d, KEY_SCREEN }, - { 0x43, KEY_SUBTITLE }, - { 0x10, KEY_MUTE }, - { 0x49, KEY_AUDIO }, - { 0x07, KEY_SLEEP }, - { 0x08, KEY_VIDEO }, - { 0x0e, KEY_AGAIN }, - { 0x45, KEY_EQUAL }, - { 0x46, KEY_MINUS }, - { 0x18, KEY_RED }, - { 0x53, KEY_GREEN }, - { 0x5e, KEY_YELLOW }, - { 0x5f, KEY_BLUE }, -}; - -static struct rc_map_list twinhan_vp1027_map = { - .map = { - .scan = twinhan_vp1027, - .size = ARRAY_SIZE(twinhan_vp1027), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TWINHAN_VP1027_DVBS, - } -}; - -static int __init init_rc_map_twinhan_vp1027(void) -{ - return rc_map_register(&twinhan_vp1027_map); -} - -static void __exit exit_rc_map_twinhan_vp1027(void) -{ - rc_map_unregister(&twinhan_vp1027_map); -} - -module_init(init_rc_map_twinhan_vp1027) -module_exit(exit_rc_map_twinhan_vp1027) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Sergey Ivanov <123kash@gmail.com>"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-m1f.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-m1f.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-m1f.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-m1f.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/* videomate-m1f.h - Keytable for videomate_m1f Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Pavel Osnova - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table videomate_m1f[] = { - { 0x01, KEY_POWER }, - { 0x31, KEY_TUNER }, - { 0x33, KEY_VIDEO }, - { 0x2f, KEY_RADIO }, - { 0x30, KEY_CAMERA }, - { 0x2d, KEY_NEW }, /* TV record button */ - { 0x17, KEY_CYCLEWINDOWS }, - { 0x2c, KEY_ANGLE }, - { 0x2b, KEY_LANGUAGE }, - { 0x32, KEY_SEARCH }, /* '...' button */ - { 0x11, KEY_UP }, - { 0x13, KEY_LEFT }, - { 0x15, KEY_OK }, - { 0x14, KEY_RIGHT }, - { 0x12, KEY_DOWN }, - { 0x16, KEY_BACKSPACE }, - { 0x02, KEY_ZOOM }, /* WIN key */ - { 0x04, KEY_INFO }, - { 0x05, KEY_VOLUMEUP }, - { 0x03, KEY_MUTE }, - { 0x07, KEY_CHANNELUP }, - { 0x06, KEY_VOLUMEDOWN }, - { 0x08, KEY_CHANNELDOWN }, - { 0x0c, KEY_RECORD }, - { 0x0e, KEY_STOP }, - { 0x0a, KEY_BACK }, - { 0x0b, KEY_PLAY }, - { 0x09, KEY_FORWARD }, - { 0x10, KEY_PREVIOUS }, - { 0x0d, KEY_PAUSE }, - { 0x0f, KEY_NEXT }, - { 0x1e, KEY_1 }, - { 0x1f, KEY_2 }, - { 0x20, KEY_3 }, - { 0x21, KEY_4 }, - { 0x22, KEY_5 }, - { 0x23, KEY_6 }, - { 0x24, KEY_7 }, - { 0x25, KEY_8 }, - { 0x26, KEY_9 }, - { 0x2a, KEY_NUMERIC_STAR }, /* * key */ - { 0x1d, KEY_0 }, - { 0x29, KEY_SUBTITLE }, /* # key */ - { 0x27, KEY_CLEAR }, - { 0x34, KEY_SCREEN }, - { 0x28, KEY_ENTER }, - { 0x19, KEY_RED }, - { 0x1a, KEY_GREEN }, - { 0x1b, KEY_YELLOW }, - { 0x1c, KEY_BLUE }, - { 0x18, KEY_TEXT }, -}; - -static struct rc_map_list videomate_m1f_map = { - .map = { - .scan = videomate_m1f, - .size = ARRAY_SIZE(videomate_m1f), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_VIDEOMATE_M1F, - } -}; - -static int __init init_rc_map_videomate_m1f(void) -{ - return rc_map_register(&videomate_m1f_map); -} - -static void __exit exit_rc_map_videomate_m1f(void) -{ - rc_map_unregister(&videomate_m1f_map); -} - -module_init(init_rc_map_videomate_m1f) -module_exit(exit_rc_map_videomate_m1f) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Pavel Osnova "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-s350.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-s350.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-s350.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-s350.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* videomate-s350.h - Keytable for videomate_s350 Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table videomate_s350[] = { - { 0x00, KEY_TV}, - { 0x01, KEY_DVD}, - { 0x04, KEY_RECORD}, - { 0x05, KEY_VIDEO}, /* TV/Video */ - { 0x07, KEY_STOP}, - { 0x08, KEY_PLAYPAUSE}, - { 0x0a, KEY_REWIND}, - { 0x0f, KEY_FASTFORWARD}, - { 0x10, KEY_CHANNELUP}, - { 0x12, KEY_VOLUMEUP}, - { 0x13, KEY_CHANNELDOWN}, - { 0x14, KEY_MUTE}, - { 0x15, KEY_VOLUMEDOWN}, - { 0x16, KEY_1}, - { 0x17, KEY_2}, - { 0x18, KEY_3}, - { 0x19, KEY_4}, - { 0x1a, KEY_5}, - { 0x1b, KEY_6}, - { 0x1c, KEY_7}, - { 0x1d, KEY_8}, - { 0x1e, KEY_9}, - { 0x1f, KEY_0}, - { 0x21, KEY_SLEEP}, - { 0x24, KEY_ZOOM}, - { 0x25, KEY_LAST}, /* Recall */ - { 0x26, KEY_SUBTITLE}, /* CC */ - { 0x27, KEY_LANGUAGE}, /* MTS */ - { 0x29, KEY_CHANNEL}, /* SURF */ - { 0x2b, KEY_A}, - { 0x2c, KEY_B}, - { 0x2f, KEY_CAMERA}, /* Snapshot */ - { 0x23, KEY_RADIO}, - { 0x02, KEY_PREVIOUSSONG}, - { 0x06, KEY_NEXTSONG}, - { 0x03, KEY_EPG}, - { 0x09, KEY_SETUP}, - { 0x22, KEY_BACKSPACE}, - { 0x0c, KEY_UP}, - { 0x0e, KEY_DOWN}, - { 0x0b, KEY_LEFT}, - { 0x0d, KEY_RIGHT}, - { 0x11, KEY_ENTER}, - { 0x20, KEY_TEXT}, -}; - -static struct rc_map_list videomate_s350_map = { - .map = { - .scan = videomate_s350, - .size = ARRAY_SIZE(videomate_s350), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_VIDEOMATE_S350, - } -}; - -static int __init init_rc_map_videomate_s350(void) -{ - return rc_map_register(&videomate_s350_map); -} - -static void __exit exit_rc_map_videomate_s350(void) -{ - rc_map_unregister(&videomate_s350_map); -} - -module_init(init_rc_map_videomate_s350) -module_exit(exit_rc_map_videomate_s350) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/* videomate-tv-pvr.h - Keytable for videomate_tv_pvr Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -static struct rc_map_table videomate_tv_pvr[] = { - { 0x14, KEY_MUTE }, - { 0x24, KEY_ZOOM }, - - { 0x01, KEY_DVD }, - { 0x23, KEY_RADIO }, - { 0x00, KEY_TV }, - - { 0x0a, KEY_REWIND }, - { 0x08, KEY_PLAYPAUSE }, - { 0x0f, KEY_FORWARD }, - - { 0x02, KEY_PREVIOUS }, - { 0x07, KEY_STOP }, - { 0x06, KEY_NEXT }, - - { 0x0c, KEY_UP }, - { 0x0e, KEY_DOWN }, - { 0x0b, KEY_LEFT }, - { 0x0d, KEY_RIGHT }, - { 0x11, KEY_OK }, - - { 0x03, KEY_MENU }, - { 0x09, KEY_SETUP }, - { 0x05, KEY_VIDEO }, - { 0x22, KEY_CHANNEL }, - - { 0x12, KEY_VOLUMEUP }, - { 0x15, KEY_VOLUMEDOWN }, - { 0x10, KEY_CHANNELUP }, - { 0x13, KEY_CHANNELDOWN }, - - { 0x04, KEY_RECORD }, - - { 0x16, KEY_1 }, - { 0x17, KEY_2 }, - { 0x18, KEY_3 }, - { 0x19, KEY_4 }, - { 0x1a, KEY_5 }, - { 0x1b, KEY_6 }, - { 0x1c, KEY_7 }, - { 0x1d, KEY_8 }, - { 0x1e, KEY_9 }, - { 0x1f, KEY_0 }, - - { 0x20, KEY_LANGUAGE }, - { 0x21, KEY_SLEEP }, -}; - -static struct rc_map_list videomate_tv_pvr_map = { - .map = { - .scan = videomate_tv_pvr, - .size = ARRAY_SIZE(videomate_tv_pvr), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_VIDEOMATE_TV_PVR, - } -}; - -static int __init init_rc_map_videomate_tv_pvr(void) -{ - return rc_map_register(&videomate_tv_pvr_map); -} - -static void __exit exit_rc_map_videomate_tv_pvr(void) -{ - rc_map_unregister(&videomate_tv_pvr_map); -} - -module_init(init_rc_map_videomate_tv_pvr) -module_exit(exit_rc_map_videomate_tv_pvr) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-winfast.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-winfast.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-winfast.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-winfast.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/* winfast.h - Keytable for winfast Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */ - -static struct rc_map_table winfast[] = { - /* Keys 0 to 9 */ - { 0x12, KEY_0 }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, - - { 0x00, KEY_POWER2 }, - { 0x1b, KEY_AUDIO }, /* Audio Source */ - { 0x02, KEY_TUNER }, /* TV/FM, not on Y0400052 */ - { 0x1e, KEY_VIDEO }, /* Video Source */ - { 0x16, KEY_INFO }, /* Display information */ - { 0x04, KEY_LEFT }, - { 0x08, KEY_RIGHT }, - { 0x0c, KEY_UP }, - { 0x10, KEY_DOWN }, - { 0x03, KEY_ZOOM }, /* fullscreen */ - { 0x1f, KEY_TEXT }, /* closed caption/teletext */ - { 0x20, KEY_SLEEP }, - { 0x29, KEY_CLEAR }, /* boss key */ - { 0x14, KEY_MUTE }, - { 0x2b, KEY_RED }, - { 0x2c, KEY_GREEN }, - { 0x2d, KEY_YELLOW }, - { 0x2e, KEY_BLUE }, - { 0x18, KEY_KPPLUS }, /* fine tune + , not on Y040052 */ - { 0x19, KEY_KPMINUS }, /* fine tune - , not on Y040052 */ - { 0x2a, KEY_TV2 }, /* PIP (Picture in picture */ - { 0x21, KEY_DOT }, - { 0x13, KEY_ENTER }, - { 0x11, KEY_LAST }, /* Recall (last channel */ - { 0x22, KEY_PREVIOUS }, - { 0x23, KEY_PLAYPAUSE }, - { 0x24, KEY_NEXT }, - { 0x25, KEY_TIME }, /* Time Shifting */ - { 0x26, KEY_STOP }, - { 0x27, KEY_RECORD }, - { 0x28, KEY_CAMERA }, /* Screenshot */ - { 0x2f, KEY_MENU }, - { 0x30, KEY_CANCEL }, - { 0x31, KEY_CHANNEL }, /* Channel Surf */ - { 0x32, KEY_SUBTITLE }, - { 0x33, KEY_LANGUAGE }, - { 0x34, KEY_REWIND }, - { 0x35, KEY_FASTFORWARD }, - { 0x36, KEY_TV }, - { 0x37, KEY_RADIO }, /* FM */ - { 0x38, KEY_DVD }, - - { 0x1a, KEY_MODE}, /* change to MCE mode on Y04G0051 */ - { 0x3e, KEY_VOLUMEUP }, /* MCE +VOL, on Y04G0033 */ - { 0x3a, KEY_VOLUMEDOWN }, /* MCE -VOL, on Y04G0033 */ - { 0x3b, KEY_CHANNELUP }, /* MCE +CH, on Y04G0033 */ - { 0x3f, KEY_CHANNELDOWN } /* MCE -CH, on Y04G0033 */ -}; - -static struct rc_map_list winfast_map = { - .map = { - .scan = winfast, - .size = ARRAY_SIZE(winfast), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_WINFAST, - } -}; - -static int __init init_rc_map_winfast(void) -{ - return rc_map_register(&winfast_map); -} - -static void __exit exit_rc_map_winfast(void) -{ - rc_map_unregister(&winfast_map); -} - -module_init(init_rc_map_winfast) -module_exit(exit_rc_map_winfast) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* winfast-usbii-deluxe.h - Keytable for winfast_usbii_deluxe Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -/* Leadtek Winfast TV USB II Deluxe remote - Magnus Alm - */ - -static struct rc_map_table winfast_usbii_deluxe[] = { - { 0x62, KEY_0}, - { 0x75, KEY_1}, - { 0x76, KEY_2}, - { 0x77, KEY_3}, - { 0x79, KEY_4}, - { 0x7a, KEY_5}, - { 0x7b, KEY_6}, - { 0x7d, KEY_7}, - { 0x7e, KEY_8}, - { 0x7f, KEY_9}, - - { 0x38, KEY_CAMERA}, /* SNAPSHOT */ - { 0x37, KEY_RECORD}, /* RECORD */ - { 0x35, KEY_TIME}, /* TIMESHIFT */ - - { 0x74, KEY_VOLUMEUP}, /* VOLUMEUP */ - { 0x78, KEY_VOLUMEDOWN}, /* VOLUMEDOWN */ - { 0x64, KEY_MUTE}, /* MUTE */ - - { 0x21, KEY_CHANNEL}, /* SURF */ - { 0x7c, KEY_CHANNELUP}, /* CHANNELUP */ - { 0x60, KEY_CHANNELDOWN}, /* CHANNELDOWN */ - { 0x61, KEY_LAST}, /* LAST CHANNEL (RECALL) */ - - { 0x72, KEY_VIDEO}, /* INPUT MODES (TV/FM) */ - - { 0x70, KEY_POWER2}, /* TV ON/OFF */ - - { 0x39, KEY_CYCLEWINDOWS}, /* MINIMIZE (BOSS) */ - { 0x3a, KEY_NEW}, /* PIP */ - { 0x73, KEY_ZOOM}, /* FULLSECREEN */ - - { 0x66, KEY_INFO}, /* OSD (DISPLAY) */ - - { 0x31, KEY_DOT}, /* '.' */ - { 0x63, KEY_ENTER}, /* ENTER */ - -}; - -static struct rc_map_list winfast_usbii_deluxe_map = { - .map = { - .scan = winfast_usbii_deluxe, - .size = ARRAY_SIZE(winfast_usbii_deluxe), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_WINFAST_USBII_DELUXE, - } -}; - -static int __init init_rc_map_winfast_usbii_deluxe(void) -{ - return rc_map_register(&winfast_usbii_deluxe_map); -} - -static void __exit exit_rc_map_winfast_usbii_deluxe(void) -{ - rc_map_unregister(&winfast_usbii_deluxe_map); -} - -module_init(init_rc_map_winfast_usbii_deluxe) -module_exit(exit_rc_map_winfast_usbii_deluxe) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/lirc_dev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/lirc_dev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/lirc_dev.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/lirc_dev.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,816 +0,0 @@ -/* - * LIRC base driver - * - * by Artur Lipowski - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static int debug; - -#define IRCTL_DEV_NAME "BaseRemoteCtl" -#define NOPLUG -1 -#define LOGHEAD "lirc_dev (%s[%d]): " - -static dev_t lirc_base_dev; - -struct irctl { - struct lirc_driver d; - int attached; - int open; - - struct mutex irctl_lock; - struct lirc_buffer *buf; - unsigned int chunk_size; - - struct task_struct *task; - long jiffies_to_wait; -}; - -static DEFINE_MUTEX(lirc_dev_lock); - -static struct irctl *irctls[MAX_IRCTL_DEVICES]; -static struct cdev cdevs[MAX_IRCTL_DEVICES]; - -/* Only used for sysfs but defined to void otherwise */ -static struct class *lirc_class; - -/* helper function - * initializes the irctl structure - */ -static void lirc_irctl_init(struct irctl *ir) -{ - mutex_init(&ir->irctl_lock); - ir->d.minor = NOPLUG; -} - -static void lirc_irctl_cleanup(struct irctl *ir) -{ - dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); - - device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); - - if (ir->buf != ir->d.rbuf) { - lirc_buffer_free(ir->buf); - kfree(ir->buf); - } - ir->buf = NULL; -} - -/* helper function - * reads key codes from driver and puts them into buffer - * returns 0 on success - */ -static int lirc_add_to_buf(struct irctl *ir) -{ - if (ir->d.add_to_buf) { - int res = -ENODATA; - int got_data = 0; - - /* - * service the device as long as it is returning - * data and we have space - */ -get_data: - res = ir->d.add_to_buf(ir->d.data, ir->buf); - if (res == 0) { - got_data++; - goto get_data; - } - - if (res == -ENODEV) - kthread_stop(ir->task); - - return got_data ? 0 : res; - } - - return 0; -} - -/* main function of the polling thread - */ -static int lirc_thread(void *irctl) -{ - struct irctl *ir = irctl; - - dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n", - ir->d.name, ir->d.minor); - - do { - if (ir->open) { - if (ir->jiffies_to_wait) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(ir->jiffies_to_wait); - } - if (kthread_should_stop()) - break; - if (!lirc_add_to_buf(ir)) - wake_up_interruptible(&ir->buf->wait_poll); - } else { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - } while (!kthread_should_stop()); - - dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n", - ir->d.name, ir->d.minor); - - return 0; -} - - -static struct file_operations lirc_dev_fops = { - .owner = THIS_MODULE, - .read = lirc_dev_fop_read, - .write = lirc_dev_fop_write, - .poll = lirc_dev_fop_poll, - .unlocked_ioctl = lirc_dev_fop_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = lirc_dev_fop_ioctl, -#endif - .open = lirc_dev_fop_open, - .release = lirc_dev_fop_close, - .llseek = noop_llseek, -}; - -static int lirc_cdev_add(struct irctl *ir) -{ - int retval; - struct lirc_driver *d = &ir->d; - struct cdev *cdev = &cdevs[d->minor]; - - if (d->fops) { - cdev_init(cdev, d->fops); - cdev->owner = d->owner; - } else { - cdev_init(cdev, &lirc_dev_fops); - cdev->owner = THIS_MODULE; - } - retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); - if (retval) - return retval; - - retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); - if (retval) - kobject_put(&cdev->kobj); - - return retval; -} - -int lirc_register_driver(struct lirc_driver *d) -{ - struct irctl *ir; - int minor; - int bytes_in_key; - unsigned int chunk_size; - unsigned int buffer_size; - int err; - - if (!d) { - printk(KERN_ERR "lirc_dev: lirc_register_driver: " - "driver pointer must be not NULL!\n"); - err = -EBADRQC; - goto out; - } - - if (!d->dev) { - printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__); - err = -EINVAL; - goto out; - } - - if (MAX_IRCTL_DEVICES <= d->minor) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "\"minor\" must be between 0 and %d (%d)!\n", - MAX_IRCTL_DEVICES-1, d->minor); - err = -EBADRQC; - goto out; - } - - if (1 > d->code_length || (BUFLEN * 8) < d->code_length) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "code length in bits for minor (%d) " - "must be less than %d!\n", - d->minor, BUFLEN * 8); - err = -EBADRQC; - goto out; - } - - dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n", - d->sample_rate); - if (d->sample_rate) { - if (2 > d->sample_rate || HZ < d->sample_rate) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "sample_rate must be between 2 and %d!\n", HZ); - err = -EBADRQC; - goto out; - } - if (!d->add_to_buf) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "add_to_buf cannot be NULL when " - "sample_rate is set\n"); - err = -EBADRQC; - goto out; - } - } else if (!(d->fops && d->fops->read) && !d->rbuf) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "fops->read and rbuf cannot all be NULL!\n"); - err = -EBADRQC; - goto out; - } else if (!d->rbuf) { - if (!(d->fops && d->fops->read && d->fops->poll && - d->fops->unlocked_ioctl)) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "neither read, poll nor unlocked_ioctl can be NULL!\n"); - err = -EBADRQC; - goto out; - } - } - - mutex_lock(&lirc_dev_lock); - - minor = d->minor; - - if (minor < 0) { - /* find first free slot for driver */ - for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) - if (!irctls[minor]) - break; - if (MAX_IRCTL_DEVICES == minor) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "no free slots for drivers!\n"); - err = -ENOMEM; - goto out_lock; - } - } else if (irctls[minor]) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "minor (%d) just registered!\n", minor); - err = -EBUSY; - goto out_lock; - } - - ir = kzalloc(sizeof(struct irctl), GFP_KERNEL); - if (!ir) { - err = -ENOMEM; - goto out_lock; - } - lirc_irctl_init(ir); - irctls[minor] = ir; - d->minor = minor; - - if (d->sample_rate) { - ir->jiffies_to_wait = HZ / d->sample_rate; - } else { - /* it means - wait for external event in task queue */ - ir->jiffies_to_wait = 0; - } - - /* some safety check 8-) */ - d->name[sizeof(d->name)-1] = '\0'; - - bytes_in_key = BITS_TO_LONGS(d->code_length) + - (d->code_length % 8 ? 1 : 0); - buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; - chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; - - if (d->rbuf) { - ir->buf = d->rbuf; - } else { - ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); - if (!ir->buf) { - err = -ENOMEM; - goto out_lock; - } - err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); - if (err) { - kfree(ir->buf); - goto out_lock; - } - } - ir->chunk_size = ir->buf->chunk_size; - - if (d->features == 0) - d->features = LIRC_CAN_REC_LIRCCODE; - - ir->d = *d; - - device_create(lirc_class, ir->d.dev, - MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL, - "lirc%u", ir->d.minor); - - if (d->sample_rate) { - /* try to fire up polling thread */ - ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev"); - if (IS_ERR(ir->task)) { - dev_err(d->dev, "lirc_dev: lirc_register_driver: " - "cannot run poll thread for minor = %d\n", - d->minor); - err = -ECHILD; - goto out_sysfs; - } - } - - err = lirc_cdev_add(ir); - if (err) - goto out_sysfs; - - ir->attached = 1; - mutex_unlock(&lirc_dev_lock); - - dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", - ir->d.name, ir->d.minor); - return minor; - -out_sysfs: - device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); -out_lock: - mutex_unlock(&lirc_dev_lock); -out: - return err; -} -EXPORT_SYMBOL(lirc_register_driver); - -int lirc_unregister_driver(int minor) -{ - struct irctl *ir; - struct cdev *cdev; - - if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { - printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between " - "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1); - return -EBADRQC; - } - - ir = irctls[minor]; - if (!ir) { - printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct " - "for minor %d!\n", __func__, minor); - return -ENOENT; - } - - cdev = &cdevs[minor]; - - mutex_lock(&lirc_dev_lock); - - if (ir->d.minor != minor) { - printk(KERN_ERR "lirc_dev: %s: minor (%d) device not " - "registered!\n", __func__, minor); - mutex_unlock(&lirc_dev_lock); - return -ENOENT; - } - - /* end up polling thread */ - if (ir->task) - kthread_stop(ir->task); - - dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", - ir->d.name, ir->d.minor); - - ir->attached = 0; - if (ir->open) { - dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", - ir->d.name, ir->d.minor); - wake_up_interruptible(&ir->buf->wait_poll); - mutex_lock(&ir->irctl_lock); - ir->d.set_use_dec(ir->d.data); - module_put(cdev->owner); - mutex_unlock(&ir->irctl_lock); - } else { - lirc_irctl_cleanup(ir); - cdev_del(cdev); - kfree(ir); - irctls[minor] = NULL; - } - - mutex_unlock(&lirc_dev_lock); - - return 0; -} -EXPORT_SYMBOL(lirc_unregister_driver); - -int lirc_dev_fop_open(struct inode *inode, struct file *file) -{ - struct irctl *ir; - struct cdev *cdev; - int retval = 0; - - if (iminor(inode) >= MAX_IRCTL_DEVICES) { - printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n", - iminor(inode)); - return -ENODEV; - } - - if (mutex_lock_interruptible(&lirc_dev_lock)) - return -ERESTARTSYS; - - ir = irctls[iminor(inode)]; - if (!ir) { - retval = -ENODEV; - goto error; - } - - dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); - - if (ir->d.minor == NOPLUG) { - retval = -ENODEV; - goto error; - } - - if (ir->open) { - retval = -EBUSY; - goto error; - } - - cdev = &cdevs[iminor(inode)]; - if (try_module_get(cdev->owner)) { - ir->open++; - retval = ir->d.set_use_inc(ir->d.data); - - if (retval) { - module_put(cdev->owner); - ir->open--; - } else { - lirc_buffer_clear(ir->buf); - } - if (ir->task) - wake_up_process(ir->task); - } - -error: - if (ir) - dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n", - ir->d.name, ir->d.minor, retval); - - mutex_unlock(&lirc_dev_lock); - - nonseekable_open(inode, file); - - return retval; -} -EXPORT_SYMBOL(lirc_dev_fop_open); - -int lirc_dev_fop_close(struct inode *inode, struct file *file) -{ - struct irctl *ir = irctls[iminor(inode)]; - struct cdev *cdev = &cdevs[iminor(inode)]; - - if (!ir) { - printk(KERN_ERR "%s: called with invalid irctl\n", __func__); - return -EINVAL; - } - - dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); - - WARN_ON(mutex_lock_killable(&lirc_dev_lock)); - - ir->open--; - if (ir->attached) { - ir->d.set_use_dec(ir->d.data); - module_put(cdev->owner); - } else { - lirc_irctl_cleanup(ir); - cdev_del(cdev); - irctls[ir->d.minor] = NULL; - kfree(ir); - } - - mutex_unlock(&lirc_dev_lock); - - return 0; -} -EXPORT_SYMBOL(lirc_dev_fop_close); - -unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) -{ - struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; - unsigned int ret; - - if (!ir) { - printk(KERN_ERR "%s: called with invalid irctl\n", __func__); - return POLLERR; - } - - dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); - - if (!ir->attached) - return POLLERR; - - poll_wait(file, &ir->buf->wait_poll, wait); - - if (ir->buf) - if (lirc_buffer_empty(ir->buf)) - ret = 0; - else - ret = POLLIN | POLLRDNORM; - else - ret = POLLERR; - - dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n", - ir->d.name, ir->d.minor, ret); - - return ret; -} -EXPORT_SYMBOL(lirc_dev_fop_poll); - -long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - __u32 mode; - int result = 0; - struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; - - if (!ir) { - printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__); - return -ENODEV; - } - - dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", - ir->d.name, ir->d.minor, cmd); - - if (ir->d.minor == NOPLUG || !ir->attached) { - dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", - ir->d.name, ir->d.minor); - return -ENODEV; - } - - mutex_lock(&ir->irctl_lock); - - switch (cmd) { - case LIRC_GET_FEATURES: - result = put_user(ir->d.features, (__u32 *)arg); - break; - case LIRC_GET_REC_MODE: - if (!(ir->d.features & LIRC_CAN_REC_MASK)) { - result = -ENOSYS; - break; - } - - result = put_user(LIRC_REC2MODE - (ir->d.features & LIRC_CAN_REC_MASK), - (__u32 *)arg); - break; - case LIRC_SET_REC_MODE: - if (!(ir->d.features & LIRC_CAN_REC_MASK)) { - result = -ENOSYS; - break; - } - - result = get_user(mode, (__u32 *)arg); - if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) - result = -EINVAL; - /* - * FIXME: We should actually set the mode somehow but - * for now, lirc_serial doesn't support mode changing either - */ - break; - case LIRC_GET_LENGTH: - result = put_user(ir->d.code_length, (__u32 *)arg); - break; - case LIRC_GET_MIN_TIMEOUT: - if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || - ir->d.min_timeout == 0) { - result = -ENOSYS; - break; - } - - result = put_user(ir->d.min_timeout, (__u32 *)arg); - break; - case LIRC_GET_MAX_TIMEOUT: - if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || - ir->d.max_timeout == 0) { - result = -ENOSYS; - break; - } - - result = put_user(ir->d.max_timeout, (__u32 *)arg); - break; - default: - result = -EINVAL; - } - - dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n", - ir->d.name, ir->d.minor, result); - - mutex_unlock(&ir->irctl_lock); - - return result; -} -EXPORT_SYMBOL(lirc_dev_fop_ioctl); - -ssize_t lirc_dev_fop_read(struct file *file, - char __user *buffer, - size_t length, - loff_t *ppos) -{ - struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; - unsigned char *buf; - int ret = 0, written = 0; - DECLARE_WAITQUEUE(wait, current); - - if (!ir) { - printk(KERN_ERR "%s: called with invalid irctl\n", __func__); - return -ENODEV; - } - - dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); - - buf = kzalloc(ir->chunk_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (mutex_lock_interruptible(&ir->irctl_lock)) { - ret = -ERESTARTSYS; - goto out_unlocked; - } - if (!ir->attached) { - ret = -ENODEV; - goto out_locked; - } - - if (length % ir->chunk_size) { - ret = -EINVAL; - goto out_locked; - } - - /* - * we add ourselves to the task queue before buffer check - * to avoid losing scan code (in case when queue is awaken somewhere - * between while condition checking and scheduling) - */ - add_wait_queue(&ir->buf->wait_poll, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - /* - * while we didn't provide 'length' bytes, device is opened in blocking - * mode and 'copy_to_user' is happy, wait for data. - */ - while (written < length && ret == 0) { - if (lirc_buffer_empty(ir->buf)) { - /* According to the read(2) man page, 'written' can be - * returned as less than 'length', instead of blocking - * again, returning -EWOULDBLOCK, or returning - * -ERESTARTSYS */ - if (written) - break; - if (file->f_flags & O_NONBLOCK) { - ret = -EWOULDBLOCK; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - mutex_unlock(&ir->irctl_lock); - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - - if (mutex_lock_interruptible(&ir->irctl_lock)) { - ret = -ERESTARTSYS; - remove_wait_queue(&ir->buf->wait_poll, &wait); - set_current_state(TASK_RUNNING); - goto out_unlocked; - } - - if (!ir->attached) { - ret = -ENODEV; - break; - } - } else { - lirc_buffer_read(ir->buf, buf); - ret = copy_to_user((void *)buffer+written, buf, - ir->buf->chunk_size); - if (!ret) - written += ir->buf->chunk_size; - else - ret = -EFAULT; - } - } - - remove_wait_queue(&ir->buf->wait_poll, &wait); - set_current_state(TASK_RUNNING); - -out_locked: - mutex_unlock(&ir->irctl_lock); - -out_unlocked: - kfree(buf); - dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", - ir->d.name, ir->d.minor, ret ? "" : "", ret); - - return ret ? ret : written; -} -EXPORT_SYMBOL(lirc_dev_fop_read); - -void *lirc_get_pdata(struct file *file) -{ - void *data = NULL; - - if (file && file->f_dentry && file->f_dentry->d_inode && - file->f_dentry->d_inode->i_rdev) { - struct irctl *ir; - ir = irctls[iminor(file->f_dentry->d_inode)]; - data = ir->d.data; - } - - return data; -} -EXPORT_SYMBOL(lirc_get_pdata); - - -ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer, - size_t length, loff_t *ppos) -{ - struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; - - if (!ir) { - printk(KERN_ERR "%s: called with invalid irctl\n", __func__); - return -ENODEV; - } - - dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); - - if (!ir->attached) - return -ENODEV; - - return -EINVAL; -} -EXPORT_SYMBOL(lirc_dev_fop_write); - - -static int __init lirc_dev_init(void) -{ - int retval; - - lirc_class = class_create(THIS_MODULE, "lirc"); - if (IS_ERR(lirc_class)) { - retval = PTR_ERR(lirc_class); - printk(KERN_ERR "lirc_dev: class_create failed\n"); - goto error; - } - - retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES, - IRCTL_DEV_NAME); - if (retval) { - class_destroy(lirc_class); - printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n"); - goto error; - } - - - printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, " - "major %d \n", MAJOR(lirc_base_dev)); - -error: - return retval; -} - - - -static void __exit lirc_dev_exit(void) -{ - class_destroy(lirc_class); - unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES); - printk(KERN_INFO "lirc_dev: module unloaded\n"); -} - -module_init(lirc_dev_init); -module_exit(lirc_dev_exit); - -MODULE_DESCRIPTION("LIRC base driver module"); -MODULE_AUTHOR("Artur Lipowski"); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -rc-core-objs := rc-main.o ir-raw.o - -obj-y += keymaps/ - -obj-$(CONFIG_RC_CORE) += rc-core.o -obj-$(CONFIG_LIRC) += lirc_dev.o -obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o -obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o -obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o -obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o -obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o -obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o -obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o - -# stand-alone IR receivers/transmitters -obj-$(CONFIG_IR_IMON) += imon.o -obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o -obj-$(CONFIG_IR_MCEUSB) += mceusb.o -obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o -obj-$(CONFIG_IR_ENE) += ene_ir.o -obj-$(CONFIG_IR_STREAMZAP) += streamzap.o -obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o -obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/mceusb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/mceusb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/mceusb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/mceusb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1318 +0,0 @@ -/* - * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers - * - * Copyright (c) 2010 by Jarod Wilson - * - * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan - * Conti, Martin Blatter and Daniel Melander, the latter of which was - * in turn also based on the lirc_atiusb driver by Paul Miller. The - * two mce drivers were merged into one by Jarod Wilson, with transmit - * support for the 1st-gen device added primarily by Patrick Calhoun, - * with a bit of tweaks by Jarod. Debugging improvements and proper - * support for what appears to be 3rd-gen hardware added by Jarod. - * Initial port from lirc driver to ir-core drivery by Jarod, based - * partially on a port to an earlier proposed IR infrastructure by - * Jon Smirl, which included enhancements and simplifications to the - * incoming IR buffer parsing routines. - * - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include - -#define DRIVER_VERSION "1.91" -#define DRIVER_AUTHOR "Jarod Wilson " -#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ - "device driver" -#define DRIVER_NAME "mceusb" - -#define USB_BUFLEN 32 /* USB reception buffer length */ -#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ -#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ - -/* MCE constants */ -#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ -#define MCE_TIME_UNIT 50 /* Approx 50us resolution */ -#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ -#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ -#define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ -#define MCE_IRDATA_TRAILER 0x80 /* End of IR data */ -#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ -#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ -#define MCE_DEFAULT_TX_MASK 0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */ -#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */ -#define MCE_PULSE_MASK 0x7f /* Pulse mask */ -#define MCE_MAX_PULSE_LENGTH 0x7f /* Longest transmittable pulse symbol */ - -#define MCE_HW_CMD_HEADER 0xff /* MCE hardware command header */ -#define MCE_COMMAND_HEADER 0x9f /* MCE command header */ -#define MCE_COMMAND_MASK 0xe0 /* Mask out command bits */ -#define MCE_COMMAND_NULL 0x00 /* These show up various places... */ -/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER, - * then we're looking at a raw IR data sample */ -#define MCE_COMMAND_IRDATA 0x80 -#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ - -/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */ -#define MCE_CMD_SIG_END 0x01 /* End of signal */ -#define MCE_CMD_PING 0x03 /* Ping device */ -#define MCE_CMD_UNKNOWN 0x04 /* Unknown */ -#define MCE_CMD_UNKNOWN2 0x05 /* Unknown */ -#define MCE_CMD_S_CARRIER 0x06 /* Set TX carrier frequency */ -#define MCE_CMD_G_CARRIER 0x07 /* Get TX carrier frequency */ -#define MCE_CMD_S_TXMASK 0x08 /* Set TX port bitmask */ -#define MCE_CMD_UNKNOWN3 0x09 /* Unknown */ -#define MCE_CMD_UNKNOWN4 0x0a /* Unknown */ -#define MCE_CMD_G_REVISION 0x0b /* Get hw/sw revision */ -#define MCE_CMD_S_TIMEOUT 0x0c /* Set RX timeout value */ -#define MCE_CMD_G_TIMEOUT 0x0d /* Get RX timeout value */ -#define MCE_CMD_UNKNOWN5 0x0e /* Unknown */ -#define MCE_CMD_UNKNOWN6 0x0f /* Unknown */ -#define MCE_CMD_G_RXPORTSTS 0x11 /* Get RX port status */ -#define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */ -#define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */ -#define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */ -#define MCE_RSP_PULSE_COUNT 0x15 /* RX pulse count (only if learning) */ -#define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */ -#define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */ -#define MCE_CMD_UNKNOWN7 0x18 /* Unknown */ -#define MCE_CMD_UNKNOWN8 0x19 /* Unknown */ -#define MCE_CMD_UNKNOWN9 0x1b /* Unknown */ -#define MCE_CMD_DEVICE_RESET 0xaa /* Reset the hardware */ -#define MCE_RSP_CMD_INVALID 0xfe /* Invalid command issued */ - - -/* module parameters */ -#ifdef CONFIG_USB_DEBUG -static int debug = 1; -#else -static int debug; -#endif - -/* general constants */ -#define SEND_FLAG_IN_PROGRESS 1 -#define SEND_FLAG_COMPLETE 2 -#define RECV_FLAG_IN_PROGRESS 3 -#define RECV_FLAG_COMPLETE 4 - -#define MCEUSB_RX 1 -#define MCEUSB_TX 2 - -#define VENDOR_PHILIPS 0x0471 -#define VENDOR_SMK 0x0609 -#define VENDOR_TATUNG 0x1460 -#define VENDOR_GATEWAY 0x107b -#define VENDOR_SHUTTLE 0x1308 -#define VENDOR_SHUTTLE2 0x051c -#define VENDOR_MITSUMI 0x03ee -#define VENDOR_TOPSEED 0x1784 -#define VENDOR_RICAVISION 0x179d -#define VENDOR_ITRON 0x195d -#define VENDOR_FIC 0x1509 -#define VENDOR_LG 0x043e -#define VENDOR_MICROSOFT 0x045e -#define VENDOR_FORMOSA 0x147a -#define VENDOR_FINTEK 0x1934 -#define VENDOR_PINNACLE 0x2304 -#define VENDOR_ECS 0x1019 -#define VENDOR_WISTRON 0x0fb8 -#define VENDOR_COMPRO 0x185b -#define VENDOR_NORTHSTAR 0x04eb -#define VENDOR_REALTEK 0x0bda -#define VENDOR_TIVO 0x105a -#define VENDOR_CONEXANT 0x0572 - -enum mceusb_model_type { - MCE_GEN2 = 0, /* Most boards */ - MCE_GEN1, - MCE_GEN3, - MCE_GEN2_TX_INV, - POLARIS_EVK, - CX_HYBRID_TV, - MULTIFUNCTION, -}; - -struct mceusb_model { - u32 mce_gen1:1; - u32 mce_gen2:1; - u32 mce_gen3:1; - u32 tx_mask_normal:1; - u32 no_tx:1; - - int ir_intfnum; - - const char *rc_map; /* Allow specify a per-board map */ - const char *name; /* per-board name */ -}; - -static const struct mceusb_model mceusb_model[] = { - [MCE_GEN1] = { - .mce_gen1 = 1, - .tx_mask_normal = 1, - }, - [MCE_GEN2] = { - .mce_gen2 = 1, - }, - [MCE_GEN2_TX_INV] = { - .mce_gen2 = 1, - .tx_mask_normal = 1, - }, - [MCE_GEN3] = { - .mce_gen3 = 1, - .tx_mask_normal = 1, - }, - [POLARIS_EVK] = { - /* - * In fact, the EVK is shipped without - * remotes, but we should have something handy, - * to allow testing it - */ - .rc_map = RC_MAP_HAUPPAUGE, - .name = "Conexant Hybrid TV (cx231xx) MCE IR", - }, - [CX_HYBRID_TV] = { - .no_tx = 1, /* tx isn't wired up at all */ - .name = "Conexant Hybrid TV (cx231xx) MCE IR", - }, - [MULTIFUNCTION] = { - .mce_gen2 = 1, - .ir_intfnum = 2, - }, -}; - -static struct usb_device_id mceusb_dev_table[] = { - /* Original Microsoft MCE IR Transceiver (often HP-branded) */ - { USB_DEVICE(VENDOR_MICROSOFT, 0x006d), - .driver_info = MCE_GEN1 }, - /* Philips Infrared Transceiver - Sahara branded */ - { USB_DEVICE(VENDOR_PHILIPS, 0x0608) }, - /* Philips Infrared Transceiver - HP branded */ - { USB_DEVICE(VENDOR_PHILIPS, 0x060c), - .driver_info = MCE_GEN2_TX_INV }, - /* Philips SRM5100 */ - { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, - /* Philips Infrared Transceiver - Omaura */ - { USB_DEVICE(VENDOR_PHILIPS, 0x060f) }, - /* Philips Infrared Transceiver - Spinel plus */ - { USB_DEVICE(VENDOR_PHILIPS, 0x0613) }, - /* Philips eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_PHILIPS, 0x0815) }, - /* Philips/Spinel plus IR transceiver for ASUS */ - { USB_DEVICE(VENDOR_PHILIPS, 0x206c) }, - /* Philips/Spinel plus IR transceiver for ASUS */ - { USB_DEVICE(VENDOR_PHILIPS, 0x2088) }, - /* Realtek MCE IR Receiver and card reader */ - { USB_DEVICE(VENDOR_REALTEK, 0x0161), - .driver_info = MULTIFUNCTION }, - /* SMK/Toshiba G83C0004D410 */ - { USB_DEVICE(VENDOR_SMK, 0x031d), - .driver_info = MCE_GEN2_TX_INV }, - /* SMK eHome Infrared Transceiver (Sony VAIO) */ - { USB_DEVICE(VENDOR_SMK, 0x0322), - .driver_info = MCE_GEN2_TX_INV }, - /* bundled with Hauppauge PVR-150 */ - { USB_DEVICE(VENDOR_SMK, 0x0334), - .driver_info = MCE_GEN2_TX_INV }, - /* SMK eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_SMK, 0x0338) }, - /* Tatung eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, - /* Shuttle eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) }, - /* Shuttle eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) }, - /* Gateway eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_GATEWAY, 0x3009) }, - /* Mitsumi */ - { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, - /* Topseed eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_TOPSEED, 0x0001), - .driver_info = MCE_GEN2_TX_INV }, - /* Topseed HP eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_TOPSEED, 0x0006), - .driver_info = MCE_GEN2_TX_INV }, - /* Topseed eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_TOPSEED, 0x0007), - .driver_info = MCE_GEN2_TX_INV }, - /* Topseed eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_TOPSEED, 0x0008), - .driver_info = MCE_GEN3 }, - /* Topseed eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_TOPSEED, 0x000a), - .driver_info = MCE_GEN2_TX_INV }, - /* Topseed eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_TOPSEED, 0x0011), - .driver_info = MCE_GEN3 }, - /* Ricavision internal Infrared Transceiver */ - { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, - /* Itron ione Libra Q-11 */ - { USB_DEVICE(VENDOR_ITRON, 0x7002) }, - /* FIC eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_FIC, 0x9242) }, - /* LG eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_LG, 0x9803) }, - /* Microsoft MCE Infrared Transceiver */ - { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) }, - /* Formosa eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_FORMOSA, 0xe015) }, - /* Formosa21 / eHome Infrared Receiver */ - { USB_DEVICE(VENDOR_FORMOSA, 0xe016) }, - /* Formosa aim / Trust MCE Infrared Receiver */ - { USB_DEVICE(VENDOR_FORMOSA, 0xe017) }, - /* Formosa Industrial Computing / Beanbag Emulation Device */ - { USB_DEVICE(VENDOR_FORMOSA, 0xe018) }, - /* Formosa21 / eHome Infrared Receiver */ - { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) }, - /* Formosa Industrial Computing AIM IR605/A */ - { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, - /* Formosa Industrial Computing */ - { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, - /* Fintek eHome Infrared Transceiver (HP branded) */ - { USB_DEVICE(VENDOR_FINTEK, 0x5168) }, - /* Fintek eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, - /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ - { USB_DEVICE(VENDOR_FINTEK, 0x0702) }, - /* Pinnacle Remote Kit */ - { USB_DEVICE(VENDOR_PINNACLE, 0x0225), - .driver_info = MCE_GEN3 }, - /* Elitegroup Computer Systems IR */ - { USB_DEVICE(VENDOR_ECS, 0x0f38) }, - /* Wistron Corp. eHome Infrared Receiver */ - { USB_DEVICE(VENDOR_WISTRON, 0x0002) }, - /* Compro K100 */ - { USB_DEVICE(VENDOR_COMPRO, 0x3020) }, - /* Compro K100 v2 */ - { USB_DEVICE(VENDOR_COMPRO, 0x3082) }, - /* Northstar Systems, Inc. eHome Infrared Transceiver */ - { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, - /* TiVo PC IR Receiver */ - { USB_DEVICE(VENDOR_TIVO, 0x2000) }, - /* Conexant Hybrid TV "Shelby" Polaris SDK */ - { USB_DEVICE(VENDOR_CONEXANT, 0x58a1), - .driver_info = POLARIS_EVK }, - /* Conexant Hybrid TV RDU253S Polaris */ - { USB_DEVICE(VENDOR_CONEXANT, 0x58a5), - .driver_info = CX_HYBRID_TV }, - /* Terminating entry */ - { } -}; - -/* data structure for each usb transceiver */ -struct mceusb_dev { - /* ir-core bits */ - struct rc_dev *rc; - - /* optional features we can enable */ - bool carrier_report_enabled; - bool learning_enabled; - - /* core device bits */ - struct device *dev; - - /* usb */ - struct usb_device *usbdev; - struct urb *urb_in; - struct usb_endpoint_descriptor *usb_ep_in; - struct usb_endpoint_descriptor *usb_ep_out; - - /* buffers and dma */ - unsigned char *buf_in; - unsigned int len_in; - dma_addr_t dma_in; - dma_addr_t dma_out; - - enum { - CMD_HEADER = 0, - SUBCMD, - CMD_DATA, - PARSE_IRDATA, - } parser_state; - - u8 cmd, rem; /* Remaining IR data bytes in packet */ - - struct { - u32 connected:1; - u32 tx_mask_normal:1; - u32 microsoft_gen1:1; - u32 no_tx:1; - } flags; - - /* transmit support */ - int send_flags; - u32 carrier; - unsigned char tx_mask; - - char name[128]; - char phys[64]; - enum mceusb_model_type model; -}; - -/* - * MCE Device Command Strings - * Device command responses vary from device to device... - * - DEVICE_RESET resets the hardware to its default state - * - GET_REVISION fetches the hardware/software revision, common - * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42 - * - GET_CARRIER_FREQ gets the carrier mode and frequency of the - * device, with replies in the form of 9f 06 MM FF, where MM is 0-3, - * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is - * ((clk / frequency) - 1) - * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us, - * response in the form of 9f 0c msb lsb - * - GET_TX_BITMASK fetches the transmitter bitmask, replies in - * the form of 9f 08 bm, where bm is the bitmask - * - GET_RX_SENSOR fetches the RX sensor setting -- long-range - * general use one or short-range learning one, in the form of - * 9f 14 ss, where ss is either 01 for long-range or 02 for short - * - SET_CARRIER_FREQ sets a new carrier mode and frequency - * - SET_TX_BITMASK sets the transmitter bitmask - * - SET_RX_TIMEOUT sets the receiver timeout - * - SET_RX_SENSOR sets which receiver sensor to use - */ -static char DEVICE_RESET[] = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER, - MCE_CMD_DEVICE_RESET}; -static char GET_REVISION[] = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION}; -static char GET_UNKNOWN[] = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7}; -static char GET_UNKNOWN2[] = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2}; -static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER}; -static char GET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT}; -static char GET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK}; -static char GET_RX_SENSOR[] = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR}; -/* sub in desired values in lower byte or bytes for full command */ -/* FIXME: make use of these for transmit. -static char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, - MCE_CMD_S_CARRIER, 0x00, 0x00}; -static char SET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00}; -static char SET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, - MCE_CMD_S_TIMEOUT, 0x00, 0x00}; -static char SET_RX_SENSOR[] = {MCE_COMMAND_HEADER, - MCE_CMD_S_RXSENSOR, 0x00}; -*/ - -static int mceusb_cmdsize(u8 cmd, u8 subcmd) -{ - int datasize = 0; - - switch (cmd) { - case MCE_COMMAND_NULL: - if (subcmd == MCE_HW_CMD_HEADER) - datasize = 1; - break; - case MCE_HW_CMD_HEADER: - switch (subcmd) { - case MCE_CMD_G_REVISION: - datasize = 2; - break; - } - case MCE_COMMAND_HEADER: - switch (subcmd) { - case MCE_CMD_UNKNOWN: - case MCE_CMD_S_CARRIER: - case MCE_CMD_S_TIMEOUT: - case MCE_RSP_PULSE_COUNT: - datasize = 2; - break; - case MCE_CMD_SIG_END: - case MCE_CMD_S_TXMASK: - case MCE_CMD_S_RXSENSOR: - datasize = 1; - break; - } - } - return datasize; -} - -static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, - int offset, int len, bool out) -{ - char codes[USB_BUFLEN * 3 + 1]; - char inout[9]; - u8 cmd, subcmd, data1, data2; - struct device *dev = ir->dev; - int i, start, skip = 0; - - if (!debug) - return; - - /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ - if (ir->flags.microsoft_gen1 && !out && !offset) - skip = 2; - - if (len <= skip) - return; - - for (i = 0; i < len && i < USB_BUFLEN; i++) - snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff); - - dev_info(dev, "%sx data: %s(length=%d)\n", - (out ? "t" : "r"), codes, len); - - if (out) - strcpy(inout, "Request\0"); - else - strcpy(inout, "Got\0"); - - start = offset + skip; - cmd = buf[start] & 0xff; - subcmd = buf[start + 1] & 0xff; - data1 = buf[start + 2] & 0xff; - data2 = buf[start + 3] & 0xff; - - switch (cmd) { - case MCE_COMMAND_NULL: - if ((subcmd == MCE_HW_CMD_HEADER) && - (data1 == MCE_CMD_DEVICE_RESET)) - dev_info(dev, "Device reset requested\n"); - else - dev_info(dev, "Unknown command 0x%02x 0x%02x\n", - cmd, subcmd); - break; - case MCE_HW_CMD_HEADER: - switch (subcmd) { - case MCE_CMD_G_REVISION: - if (len == 2) - dev_info(dev, "Get hw/sw rev?\n"); - else - dev_info(dev, "hw/sw rev 0x%02x 0x%02x " - "0x%02x 0x%02x\n", data1, data2, - buf[start + 4], buf[start + 5]); - break; - case MCE_CMD_DEVICE_RESET: - dev_info(dev, "Device reset requested\n"); - break; - case MCE_RSP_CMD_INVALID: - dev_info(dev, "Previous command not supported\n"); - break; - case MCE_CMD_UNKNOWN7: - case MCE_CMD_UNKNOWN9: - default: - dev_info(dev, "Unknown command 0x%02x 0x%02x\n", - cmd, subcmd); - break; - } - break; - case MCE_COMMAND_HEADER: - switch (subcmd) { - case MCE_CMD_SIG_END: - dev_info(dev, "End of signal\n"); - break; - case MCE_CMD_PING: - dev_info(dev, "Ping\n"); - break; - case MCE_CMD_UNKNOWN: - dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", - data1, data2); - break; - case MCE_CMD_S_CARRIER: - dev_info(dev, "%s carrier mode and freq of " - "0x%02x 0x%02x\n", inout, data1, data2); - break; - case MCE_CMD_G_CARRIER: - dev_info(dev, "Get carrier mode and freq\n"); - break; - case MCE_CMD_S_TXMASK: - dev_info(dev, "%s transmit blaster mask of 0x%02x\n", - inout, data1); - break; - case MCE_CMD_S_TIMEOUT: - /* value is in units of 50us, so x*50/100 or x/2 ms */ - dev_info(dev, "%s receive timeout of %d ms\n", - inout, ((data1 << 8) | data2) / 2); - break; - case MCE_CMD_G_TIMEOUT: - dev_info(dev, "Get receive timeout\n"); - break; - case MCE_CMD_G_TXMASK: - dev_info(dev, "Get transmit blaster mask\n"); - break; - case MCE_CMD_S_RXSENSOR: - dev_info(dev, "%s %s-range receive sensor in use\n", - inout, data1 == 0x02 ? "short" : "long"); - break; - case MCE_CMD_G_RXSENSOR: - /* aka MCE_RSP_PULSE_COUNT */ - if (out) - dev_info(dev, "Get receive sensor\n"); - else if (ir->learning_enabled) - dev_info(dev, "RX pulse count: %d\n", - ((data1 << 8) | data2)); - break; - case MCE_RSP_CMD_INVALID: - dev_info(dev, "Error! Hardware is likely wedged...\n"); - break; - case MCE_CMD_UNKNOWN2: - case MCE_CMD_UNKNOWN3: - case MCE_CMD_UNKNOWN5: - default: - dev_info(dev, "Unknown command 0x%02x 0x%02x\n", - cmd, subcmd); - break; - } - break; - default: - break; - } - - if (cmd == MCE_IRDATA_TRAILER) - dev_info(dev, "End of raw IR data\n"); - else if ((cmd != MCE_COMMAND_HEADER) && - ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA)) - dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem); -} - -static void mce_async_callback(struct urb *urb, struct pt_regs *regs) -{ - struct mceusb_dev *ir; - int len; - - if (!urb) - return; - - ir = urb->context; - if (ir) { - len = urb->actual_length; - - dev_dbg(ir->dev, "callback called (status=%d len=%d)\n", - urb->status, len); - - mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true); - } - -} - -/* request incoming or send outgoing usb packet - used to initialize remote */ -static void mce_request_packet(struct mceusb_dev *ir, - struct usb_endpoint_descriptor *ep, - unsigned char *data, int size, int urb_type) -{ - int res; - struct urb *async_urb; - struct device *dev = ir->dev; - unsigned char *async_buf; - - if (urb_type == MCEUSB_TX) { - async_urb = usb_alloc_urb(0, GFP_KERNEL); - if (unlikely(!async_urb)) { - dev_err(dev, "Error, couldn't allocate urb!\n"); - return; - } - - async_buf = kzalloc(size, GFP_KERNEL); - if (!async_buf) { - dev_err(dev, "Error, couldn't allocate buf!\n"); - usb_free_urb(async_urb); - return; - } - - /* outbound data */ - usb_fill_int_urb(async_urb, ir->usbdev, - usb_sndintpipe(ir->usbdev, ep->bEndpointAddress), - async_buf, size, (usb_complete_t)mce_async_callback, - ir, ep->bInterval); - memcpy(async_buf, data, size); - - } else if (urb_type == MCEUSB_RX) { - /* standard request */ - async_urb = ir->urb_in; - ir->send_flags = RECV_FLAG_IN_PROGRESS; - - } else { - dev_err(dev, "Error! Unknown urb type %d\n", urb_type); - return; - } - - dev_dbg(dev, "receive request called (size=%#x)\n", size); - - async_urb->transfer_buffer_length = size; - async_urb->dev = ir->usbdev; - - res = usb_submit_urb(async_urb, GFP_ATOMIC); - if (res) { - dev_dbg(dev, "receive request FAILED! (res=%d)\n", res); - return; - } - dev_dbg(dev, "receive request complete (res=%d)\n", res); -} - -static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) -{ - mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_TX); -} - -static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) -{ - mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX); -} - -/* Send data out the IR blaster port(s) */ -static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) -{ - struct mceusb_dev *ir = dev->priv; - int i, ret = 0; - int count, cmdcount = 0; - unsigned char *cmdbuf; /* MCE command buffer */ - long signal_duration = 0; /* Singnal length in us */ - struct timeval start_time, end_time; - - do_gettimeofday(&start_time); - - count = n / sizeof(int); - - cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL); - if (!cmdbuf) - return -ENOMEM; - - /* MCE tx init header */ - cmdbuf[cmdcount++] = MCE_COMMAND_HEADER; - cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK; - cmdbuf[cmdcount++] = ir->tx_mask; - - /* Generate mce packet data */ - for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { - signal_duration += txbuf[i]; - txbuf[i] = txbuf[i] / MCE_TIME_UNIT; - - do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ - - /* Insert mce packet header every 4th entry */ - if ((cmdcount < MCE_CMDBUF_SIZE) && - (cmdcount - MCE_TX_HEADER_LENGTH) % - MCE_CODE_LENGTH == 0) - cmdbuf[cmdcount++] = MCE_IRDATA_HEADER; - - /* Insert mce packet data */ - if (cmdcount < MCE_CMDBUF_SIZE) - cmdbuf[cmdcount++] = - (txbuf[i] < MCE_PULSE_BIT ? - txbuf[i] : MCE_MAX_PULSE_LENGTH) | - (i & 1 ? 0x00 : MCE_PULSE_BIT); - else { - ret = -EINVAL; - goto out; - } - - } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) && - (txbuf[i] -= MCE_MAX_PULSE_LENGTH)); - } - - /* Fix packet length in last header */ - cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] = - MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) % - MCE_CODE_LENGTH - 1; - - /* Check if we have room for the empty packet at the end */ - if (cmdcount >= MCE_CMDBUF_SIZE) { - ret = -EINVAL; - goto out; - } - - /* All mce commands end with an empty packet (0x80) */ - cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER; - - /* Transmit the command to the mce device */ - mce_async_out(ir, cmdbuf, cmdcount); - - /* - * The lircd gap calculation expects the write function to - * wait the time it takes for the ircommand to be sent before - * it returns. - */ - do_gettimeofday(&end_time); - signal_duration -= (end_time.tv_usec - start_time.tv_usec) + - (end_time.tv_sec - start_time.tv_sec) * 1000000; - - /* delay with the closest number of ticks */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(signal_duration)); - -out: - kfree(cmdbuf); - return ret ? ret : n; -} - -/* Sets active IR outputs -- mce devices typically have two */ -static int mceusb_set_tx_mask(struct rc_dev *dev, u32 mask) -{ - struct mceusb_dev *ir = dev->priv; - - if (ir->flags.tx_mask_normal) - ir->tx_mask = mask; - else - ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ? - mask ^ MCE_DEFAULT_TX_MASK : mask) << 1; - - return 0; -} - -/* Sets the send carrier frequency and mode */ -static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) -{ - struct mceusb_dev *ir = dev->priv; - int clk = 10000000; - int prescaler = 0, divisor = 0; - unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER, - MCE_CMD_S_CARRIER, 0x00, 0x00 }; - - /* Carrier has changed */ - if (ir->carrier != carrier) { - - if (carrier == 0) { - ir->carrier = carrier; - cmdbuf[2] = MCE_CMD_SIG_END; - cmdbuf[3] = MCE_IRDATA_TRAILER; - dev_dbg(ir->dev, "%s: disabling carrier " - "modulation\n", __func__); - mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); - return carrier; - } - - for (prescaler = 0; prescaler < 4; ++prescaler) { - divisor = (clk >> (2 * prescaler)) / carrier; - if (divisor <= 0xff) { - ir->carrier = carrier; - cmdbuf[2] = prescaler; - cmdbuf[3] = divisor; - dev_dbg(ir->dev, "%s: requesting %u HZ " - "carrier\n", __func__, carrier); - - /* Transmit new carrier to mce device */ - mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); - return carrier; - } - } - - return -EINVAL; - - } - - return carrier; -} - -/* - * We don't do anything but print debug spew for many of the command bits - * we receive from the hardware, but some of them are useful information - * we want to store so that we can use them. - */ -static void mceusb_handle_command(struct mceusb_dev *ir, int index) -{ - u8 hi = ir->buf_in[index + 1] & 0xff; - u8 lo = ir->buf_in[index + 2] & 0xff; - - switch (ir->buf_in[index]) { - /* 2-byte return value commands */ - case MCE_CMD_S_TIMEOUT: - ir->rc->timeout = US_TO_NS((hi << 8 | lo) / 2); - break; - - /* 1-byte return value commands */ - case MCE_CMD_S_TXMASK: - ir->tx_mask = hi; - break; - case MCE_CMD_S_RXSENSOR: - ir->learning_enabled = (hi == 0x02); - break; - default: - break; - } -} - -static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) -{ - DEFINE_IR_RAW_EVENT(rawir); - int i = 0; - - /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ - if (ir->flags.microsoft_gen1) - i = 2; - - /* if there's no data, just return now */ - if (buf_len <= i) - return; - - for (; i < buf_len; i++) { - switch (ir->parser_state) { - case SUBCMD: - ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]); - mceusb_dev_printdata(ir, ir->buf_in, i - 1, - ir->rem + 2, false); - mceusb_handle_command(ir, i); - ir->parser_state = CMD_DATA; - break; - case PARSE_IRDATA: - ir->rem--; - init_ir_raw_event(&rawir); - rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); - rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) - * US_TO_NS(MCE_TIME_UNIT); - - dev_dbg(ir->dev, "Storing %s with duration %d\n", - rawir.pulse ? "pulse" : "space", - rawir.duration); - - ir_raw_event_store_with_filter(ir->rc, &rawir); - break; - case CMD_DATA: - ir->rem--; - break; - case CMD_HEADER: - /* decode mce packets of the form (84),AA,BB,CC,DD */ - /* IR data packets can span USB messages - rem */ - ir->cmd = ir->buf_in[i]; - if ((ir->cmd == MCE_COMMAND_HEADER) || - ((ir->cmd & MCE_COMMAND_MASK) != - MCE_COMMAND_IRDATA)) { - ir->parser_state = SUBCMD; - continue; - } - ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK); - mceusb_dev_printdata(ir, ir->buf_in, - i, ir->rem + 1, false); - if (ir->rem) - ir->parser_state = PARSE_IRDATA; - else - ir_raw_event_reset(ir->rc); - break; - } - - if (ir->parser_state != CMD_HEADER && !ir->rem) - ir->parser_state = CMD_HEADER; - } - dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n"); - ir_raw_event_handle(ir->rc); -} - -static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) -{ - struct mceusb_dev *ir; - int buf_len; - - if (!urb) - return; - - ir = urb->context; - if (!ir) { - usb_unlink_urb(urb); - return; - } - - buf_len = urb->actual_length; - - if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { - ir->send_flags = SEND_FLAG_COMPLETE; - dev_dbg(ir->dev, "setup answer received %d bytes\n", - buf_len); - } - - switch (urb->status) { - /* success */ - case 0: - mceusb_process_ir_data(ir, buf_len); - break; - - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - usb_unlink_urb(urb); - return; - - case -EPIPE: - default: - dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status); - break; - } - - usb_submit_urb(urb, GFP_ATOMIC); -} - -static void mceusb_gen1_init(struct mceusb_dev *ir) -{ - int ret; - int maxp = ir->len_in; - struct device *dev = ir->dev; - char *data; - - data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL); - if (!data) { - dev_err(dev, "%s: memory allocation failed!\n", __func__); - return; - } - - /* - * This is a strange one. Windows issues a set address to the device - * on the receive control pipe and expect a certain value pair back - */ - ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), - USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, - data, USB_CTRL_MSG_SZ, HZ * 3); - dev_dbg(dev, "%s - ret = %d\n", __func__, ret); - dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", - __func__, data[0], data[1]); - - /* set feature: bit rate 38400 bps */ - ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), - USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, - 0xc04e, 0x0000, NULL, 0, HZ * 3); - - dev_dbg(dev, "%s - ret = %d\n", __func__, ret); - - /* bRequest 4: set char length to 8 bits */ - ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), - 4, USB_TYPE_VENDOR, - 0x0808, 0x0000, NULL, 0, HZ * 3); - dev_dbg(dev, "%s - retB = %d\n", __func__, ret); - - /* bRequest 2: set handshaking to use DTR/DSR */ - ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), - 2, USB_TYPE_VENDOR, - 0x0000, 0x0100, NULL, 0, HZ * 3); - dev_dbg(dev, "%s - retC = %d\n", __func__, ret); - - /* device reset */ - mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); - mce_sync_in(ir, NULL, maxp); - - /* get hw/sw revision? */ - mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); - mce_sync_in(ir, NULL, maxp); - - kfree(data); -}; - -static void mceusb_gen2_init(struct mceusb_dev *ir) -{ - int maxp = ir->len_in; - - /* device reset */ - mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); - mce_sync_in(ir, NULL, maxp); - - /* get hw/sw revision? */ - mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); - mce_sync_in(ir, NULL, maxp); - - /* unknown what the next two actually return... */ - mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); - mce_sync_in(ir, NULL, maxp); - mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); - mce_sync_in(ir, NULL, maxp); -} - -static void mceusb_get_parameters(struct mceusb_dev *ir) -{ - int maxp = ir->len_in; - - /* get the carrier and frequency */ - mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); - mce_sync_in(ir, NULL, maxp); - - if (!ir->flags.no_tx) { - /* get the transmitter bitmask */ - mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); - mce_sync_in(ir, NULL, maxp); - } - - /* get receiver timeout value */ - mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); - mce_sync_in(ir, NULL, maxp); - - /* get receiver sensor setting */ - mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); - mce_sync_in(ir, NULL, maxp); -} - -static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) -{ - struct device *dev = ir->dev; - struct rc_dev *rc; - int ret; - - rc = rc_allocate_device(); - if (!rc) { - dev_err(dev, "remote dev allocation failed\n"); - goto out; - } - - snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)", - mceusb_model[ir->model].name ? - mceusb_model[ir->model].name : - "Media Center Ed. eHome Infrared Remote Transceiver", - le16_to_cpu(ir->usbdev->descriptor.idVendor), - le16_to_cpu(ir->usbdev->descriptor.idProduct)); - - usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys)); - - rc->input_name = ir->name; - rc->input_phys = ir->phys; - usb_to_input_id(ir->usbdev, &rc->input_id); - rc->dev.parent = dev; - rc->priv = ir; - rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_TYPE_ALL; - rc->timeout = US_TO_NS(1000); - if (!ir->flags.no_tx) { - rc->s_tx_mask = mceusb_set_tx_mask; - rc->s_tx_carrier = mceusb_set_tx_carrier; - rc->tx_ir = mceusb_tx_ir; - } - rc->driver_name = DRIVER_NAME; - rc->map_name = mceusb_model[ir->model].rc_map ? - mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE; - - ret = rc_register_device(rc); - if (ret < 0) { - dev_err(dev, "remote dev registration failed\n"); - goto out; - } - - return rc; - -out: - rc_free_device(rc); - return NULL; -} - -static int __devinit mceusb_dev_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_host_interface *idesc; - struct usb_endpoint_descriptor *ep = NULL; - struct usb_endpoint_descriptor *ep_in = NULL; - struct usb_endpoint_descriptor *ep_out = NULL; - struct mceusb_dev *ir = NULL; - int pipe, maxp, i; - char buf[63], name[128] = ""; - enum mceusb_model_type model = id->driver_info; - bool is_gen3; - bool is_microsoft_gen1; - bool tx_mask_normal; - int ir_intfnum; - - dev_dbg(&intf->dev, "%s called\n", __func__); - - idesc = intf->cur_altsetting; - - is_gen3 = mceusb_model[model].mce_gen3; - is_microsoft_gen1 = mceusb_model[model].mce_gen1; - tx_mask_normal = mceusb_model[model].tx_mask_normal; - ir_intfnum = mceusb_model[model].ir_intfnum; - - /* There are multi-function devices with non-IR interfaces */ - if (idesc->desc.bInterfaceNumber != ir_intfnum) - return -ENODEV; - - /* step through the endpoints to find first bulk in and out endpoint */ - for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { - ep = &idesc->endpoint[i].desc; - - if ((ep_in == NULL) - && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) - && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_BULK) - || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_INT))) { - - ep_in = ep; - ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; - ep_in->bInterval = 1; - dev_dbg(&intf->dev, "acceptable inbound endpoint " - "found\n"); - } - - if ((ep_out == NULL) - && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_OUT) - && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_BULK) - || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_INT))) { - - ep_out = ep; - ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; - ep_out->bInterval = 1; - dev_dbg(&intf->dev, "acceptable outbound endpoint " - "found\n"); - } - } - if (ep_in == NULL) { - dev_dbg(&intf->dev, "inbound and/or endpoint not found\n"); - return -ENODEV; - } - - pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress); - maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL); - if (!ir) - goto mem_alloc_fail; - - ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in); - if (!ir->buf_in) - goto buf_in_alloc_fail; - - ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); - if (!ir->urb_in) - goto urb_in_alloc_fail; - - ir->usbdev = dev; - ir->dev = &intf->dev; - ir->len_in = maxp; - ir->flags.microsoft_gen1 = is_microsoft_gen1; - ir->flags.tx_mask_normal = tx_mask_normal; - ir->flags.no_tx = mceusb_model[model].no_tx; - ir->model = model; - - /* Saving usb interface data for use by the transmitter routine */ - ir->usb_ep_in = ep_in; - ir->usb_ep_out = ep_out; - - if (dev->descriptor.iManufacturer - && usb_string(dev, dev->descriptor.iManufacturer, - buf, sizeof(buf)) > 0) - strlcpy(name, buf, sizeof(name)); - if (dev->descriptor.iProduct - && usb_string(dev, dev->descriptor.iProduct, - buf, sizeof(buf)) > 0) - snprintf(name + strlen(name), sizeof(name) - strlen(name), - " %s", buf); - - ir->rc = mceusb_init_rc_dev(ir); - if (!ir->rc) - goto rc_dev_fail; - - /* flush buffers on the device */ - mce_sync_in(ir, NULL, maxp); - mce_sync_in(ir, NULL, maxp); - - /* wire up inbound data handler */ - usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, - maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); - ir->urb_in->transfer_dma = ir->dma_in; - ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - /* initialize device */ - if (ir->flags.microsoft_gen1) - mceusb_gen1_init(ir); - else if (!is_gen3) - mceusb_gen2_init(ir); - - mceusb_get_parameters(ir); - - if (!ir->flags.no_tx) - mceusb_set_tx_mask(ir->rc, MCE_DEFAULT_TX_MASK); - - usb_set_intfdata(intf, ir); - - dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name, - dev->bus->busnum, dev->devnum); - - return 0; - - /* Error-handling path */ -rc_dev_fail: - usb_free_urb(ir->urb_in); -urb_in_alloc_fail: - usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in); -buf_in_alloc_fail: - kfree(ir); -mem_alloc_fail: - dev_err(&intf->dev, "%s: device setup failed!\n", __func__); - - return -ENOMEM; -} - - -static void __devexit mceusb_dev_disconnect(struct usb_interface *intf) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct mceusb_dev *ir = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - - if (!ir) - return; - - ir->usbdev = NULL; - rc_unregister_device(ir->rc); - usb_kill_urb(ir->urb_in); - usb_free_urb(ir->urb_in); - usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); - - kfree(ir); -} - -static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct mceusb_dev *ir = usb_get_intfdata(intf); - dev_info(ir->dev, "suspend\n"); - usb_kill_urb(ir->urb_in); - return 0; -} - -static int mceusb_dev_resume(struct usb_interface *intf) -{ - struct mceusb_dev *ir = usb_get_intfdata(intf); - dev_info(ir->dev, "resume\n"); - if (usb_submit_urb(ir->urb_in, GFP_ATOMIC)) - return -EIO; - return 0; -} - -static struct usb_driver mceusb_dev_driver = { - .name = DRIVER_NAME, - .probe = mceusb_dev_probe, - .disconnect = mceusb_dev_disconnect, - .suspend = mceusb_dev_suspend, - .resume = mceusb_dev_resume, - .reset_resume = mceusb_dev_resume, - .id_table = mceusb_dev_table -}; - -static int __init mceusb_dev_init(void) -{ - int ret; - - ret = usb_register(&mceusb_dev_driver); - if (ret < 0) - printk(KERN_ERR DRIVER_NAME - ": usb register failed, result = %d\n", ret); - - return ret; -} - -static void __exit mceusb_dev_exit(void) -{ - usb_deregister(&mceusb_dev_driver); -} - -module_init(mceusb_dev_init); -module_exit(mceusb_dev_exit); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, mceusb_dev_table); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/nuvoton-cir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/nuvoton-cir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/nuvoton-cir.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/nuvoton-cir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1245 +0,0 @@ -/* - * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR - * - * Copyright (C) 2010 Jarod Wilson - * Copyright (C) 2009 Nuvoton PS Team - * - * Special thanks to Nuvoton for providing hardware, spec sheets and - * sample code upon which portions of this driver are based. Indirect - * thanks also to Maxim Levitsky, whose ene_ir driver this driver is - * modeled after. - * - * 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, or (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nuvoton-cir.h" - -static char *chip_id = "w836x7hg"; - -/* write val to config reg */ -static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg) -{ - outb(reg, nvt->cr_efir); - outb(val, nvt->cr_efdr); -} - -/* read val from config reg */ -static inline u8 nvt_cr_read(struct nvt_dev *nvt, u8 reg) -{ - outb(reg, nvt->cr_efir); - return inb(nvt->cr_efdr); -} - -/* update config register bit without changing other bits */ -static inline void nvt_set_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg) -{ - u8 tmp = nvt_cr_read(nvt, reg) | val; - nvt_cr_write(nvt, tmp, reg); -} - -/* clear config register bit without changing other bits */ -static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg) -{ - u8 tmp = nvt_cr_read(nvt, reg) & ~val; - nvt_cr_write(nvt, tmp, reg); -} - -/* enter extended function mode */ -static inline void nvt_efm_enable(struct nvt_dev *nvt) -{ - /* Enabling Extended Function Mode explicitly requires writing 2x */ - outb(EFER_EFM_ENABLE, nvt->cr_efir); - outb(EFER_EFM_ENABLE, nvt->cr_efir); -} - -/* exit extended function mode */ -static inline void nvt_efm_disable(struct nvt_dev *nvt) -{ - outb(EFER_EFM_DISABLE, nvt->cr_efir); -} - -/* - * When you want to address a specific logical device, write its logical - * device number to CR_LOGICAL_DEV_SEL, then enable/disable by writing - * 0x1/0x0 respectively to CR_LOGICAL_DEV_EN. - */ -static inline void nvt_select_logical_dev(struct nvt_dev *nvt, u8 ldev) -{ - outb(CR_LOGICAL_DEV_SEL, nvt->cr_efir); - outb(ldev, nvt->cr_efdr); -} - -/* write val to cir config register */ -static inline void nvt_cir_reg_write(struct nvt_dev *nvt, u8 val, u8 offset) -{ - outb(val, nvt->cir_addr + offset); -} - -/* read val from cir config register */ -static u8 nvt_cir_reg_read(struct nvt_dev *nvt, u8 offset) -{ - u8 val; - - val = inb(nvt->cir_addr + offset); - - return val; -} - -/* write val to cir wake register */ -static inline void nvt_cir_wake_reg_write(struct nvt_dev *nvt, - u8 val, u8 offset) -{ - outb(val, nvt->cir_wake_addr + offset); -} - -/* read val from cir wake config register */ -static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset) -{ - u8 val; - - val = inb(nvt->cir_wake_addr + offset); - - return val; -} - -#define pr_reg(text, ...) \ - printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__) - -/* dump current cir register contents */ -static void cir_dump_regs(struct nvt_dev *nvt) -{ - nvt_efm_enable(nvt); - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - - pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME); - pr_reg(" * CR CIR ACTIVE : 0x%x\n", - nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); - pr_reg(" * CR CIR BASE ADDR: 0x%x\n", - (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | - nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO)); - pr_reg(" * CR CIR IRQ NUM: 0x%x\n", - nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); - - nvt_efm_disable(nvt); - - pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME); - pr_reg(" * IRCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON)); - pr_reg(" * IRSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS)); - pr_reg(" * IREN: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN)); - pr_reg(" * RXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT)); - pr_reg(" * CP: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CP)); - pr_reg(" * CC: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CC)); - pr_reg(" * SLCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH)); - pr_reg(" * SLCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL)); - pr_reg(" * FIFOCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON)); - pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS)); - pr_reg(" * SRXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO)); - pr_reg(" * TXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT)); - pr_reg(" * STXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO)); - pr_reg(" * FCCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH)); - pr_reg(" * FCCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL)); - pr_reg(" * IRFSM: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM)); -} - -/* dump current cir wake register contents */ -static void cir_wake_dump_regs(struct nvt_dev *nvt) -{ - u8 i, fifo_len; - - nvt_efm_enable(nvt); - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); - - pr_reg("%s: Dump CIR WAKE logical device registers:\n", - NVT_DRIVER_NAME); - pr_reg(" * CR CIR WAKE ACTIVE : 0x%x\n", - nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); - pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n", - (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | - nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO)); - pr_reg(" * CR CIR WAKE IRQ NUM: 0x%x\n", - nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); - - nvt_efm_disable(nvt); - - pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME); - pr_reg(" * IRCON: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON)); - pr_reg(" * IRSTS: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS)); - pr_reg(" * IREN: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN)); - pr_reg(" * FIFO CMP DEEP: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP)); - pr_reg(" * FIFO CMP TOL: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL)); - pr_reg(" * FIFO COUNT: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT)); - pr_reg(" * SLCH: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH)); - pr_reg(" * SLCL: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL)); - pr_reg(" * FIFOCON: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON)); - pr_reg(" * SRXFSTS: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS)); - pr_reg(" * SAMPLE RX FIFO: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO)); - pr_reg(" * WR FIFO DATA: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA)); - pr_reg(" * RD FIFO ONLY: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); - pr_reg(" * RD FIFO ONLY IDX: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)); - pr_reg(" * FIFO IGNORE: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE)); - pr_reg(" * IRFSM: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM)); - - fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT); - pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len); - pr_reg("* Contents = "); - for (i = 0; i < fifo_len; i++) - printk(KERN_CONT "%02x ", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); - printk(KERN_CONT "\n"); -} - -/* detect hardware features */ -static int nvt_hw_detect(struct nvt_dev *nvt) -{ - unsigned long flags; - u8 chip_major, chip_minor; - int ret = 0; - - nvt_efm_enable(nvt); - - /* Check if we're wired for the alternate EFER setup */ - chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); - if (chip_major == 0xff) { - nvt->cr_efir = CR_EFIR2; - nvt->cr_efdr = CR_EFDR2; - nvt_efm_enable(nvt); - chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); - } - - chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO); - nvt_dbg("%s: chip id: 0x%02x 0x%02x", chip_id, chip_major, chip_minor); - - if (chip_major != CHIP_ID_HIGH || - (chip_minor != CHIP_ID_LOW && chip_minor != CHIP_ID_LOW2)) { - nvt_pr(KERN_ERR, "%s: unsupported chip, id: 0x%02x 0x%02x", - chip_id, chip_major, chip_minor); - ret = -ENODEV; - } - - nvt_efm_disable(nvt); - - spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->chip_major = chip_major; - nvt->chip_minor = chip_minor; - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - - return ret; -} - -static void nvt_cir_ldev_init(struct nvt_dev *nvt) -{ - u8 val; - - /* output pin selection (Pin95=CIRRX, Pin96=CIRTX1, WB enabled */ - val = nvt_cr_read(nvt, CR_OUTPUT_PIN_SEL); - val &= OUTPUT_PIN_SEL_MASK; - val |= (OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB); - nvt_cr_write(nvt, val, CR_OUTPUT_PIN_SEL); - - /* Select CIR logical device and enable */ - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - - nvt_cr_write(nvt, nvt->cir_addr >> 8, CR_CIR_BASE_ADDR_HI); - nvt_cr_write(nvt, nvt->cir_addr & 0xff, CR_CIR_BASE_ADDR_LO); - - nvt_cr_write(nvt, nvt->cir_irq, CR_CIR_IRQ_RSRC); - - nvt_dbg("CIR initialized, base io port address: 0x%lx, irq: %d", - nvt->cir_addr, nvt->cir_irq); -} - -static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt) -{ - /* Select ACPI logical device, enable it and CIR Wake */ - nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - - /* Enable CIR Wake via PSOUT# (Pin60) */ - nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE); - - /* enable cir interrupt of mouse/keyboard IRQ event */ - nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS); - - /* enable pme interrupt of cir wakeup event */ - nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2); - - /* Select CIR Wake logical device and enable */ - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - - nvt_cr_write(nvt, nvt->cir_wake_addr >> 8, CR_CIR_BASE_ADDR_HI); - nvt_cr_write(nvt, nvt->cir_wake_addr & 0xff, CR_CIR_BASE_ADDR_LO); - - nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC); - - nvt_dbg("CIR Wake initialized, base io port address: 0x%lx, irq: %d", - nvt->cir_wake_addr, nvt->cir_wake_irq); -} - -/* clear out the hardware's cir rx fifo */ -static void nvt_clear_cir_fifo(struct nvt_dev *nvt) -{ - u8 val; - - val = nvt_cir_reg_read(nvt, CIR_FIFOCON); - nvt_cir_reg_write(nvt, val | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); -} - -/* clear out the hardware's cir wake rx fifo */ -static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt) -{ - u8 val; - - val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON); - nvt_cir_wake_reg_write(nvt, val | CIR_WAKE_FIFOCON_RXFIFOCLR, - CIR_WAKE_FIFOCON); -} - -/* clear out the hardware's cir tx fifo */ -static void nvt_clear_tx_fifo(struct nvt_dev *nvt) -{ - u8 val; - - val = nvt_cir_reg_read(nvt, CIR_FIFOCON); - nvt_cir_reg_write(nvt, val | CIR_FIFOCON_TXFIFOCLR, CIR_FIFOCON); -} - -/* enable RX Trigger Level Reach and Packet End interrupts */ -static void nvt_set_cir_iren(struct nvt_dev *nvt) -{ - u8 iren; - - iren = CIR_IREN_RTR | CIR_IREN_PE; - nvt_cir_reg_write(nvt, iren, CIR_IREN); -} - -static void nvt_cir_regs_init(struct nvt_dev *nvt) -{ - /* set sample limit count (PE interrupt raised when reached) */ - nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH); - nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL); - - /* set fifo irq trigger levels */ - nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV | - CIR_FIFOCON_RX_TRIGGER_LEV, CIR_FIFOCON); - - /* - * Enable TX and RX, specify carrier on = low, off = high, and set - * sample period (currently 50us) - */ - nvt_cir_reg_write(nvt, - CIR_IRCON_TXEN | CIR_IRCON_RXEN | - CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, - CIR_IRCON); - - /* clear hardware rx and tx fifos */ - nvt_clear_cir_fifo(nvt); - nvt_clear_tx_fifo(nvt); - - /* clear any and all stray interrupts */ - nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); - - /* and finally, enable interrupts */ - nvt_set_cir_iren(nvt); -} - -static void nvt_cir_wake_regs_init(struct nvt_dev *nvt) -{ - /* set number of bytes needed for wake from s3 (default 65) */ - nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_CMP_BYTES, - CIR_WAKE_FIFO_CMP_DEEP); - - /* set tolerance/variance allowed per byte during wake compare */ - nvt_cir_wake_reg_write(nvt, CIR_WAKE_CMP_TOLERANCE, - CIR_WAKE_FIFO_CMP_TOL); - - /* set sample limit count (PE interrupt raised when reached) */ - nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH); - nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL); - - /* set cir wake fifo rx trigger level (currently 67) */ - nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFOCON_RX_TRIGGER_LEV, - CIR_WAKE_FIFOCON); - - /* - * Enable TX and RX, specific carrier on = low, off = high, and set - * sample period (currently 50us) - */ - nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | - CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | - CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, - CIR_WAKE_IRCON); - - /* clear cir wake rx fifo */ - nvt_clear_cir_wake_fifo(nvt); - - /* clear any and all stray interrupts */ - nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); -} - -static void nvt_enable_wake(struct nvt_dev *nvt) -{ - nvt_efm_enable(nvt); - - nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI); - nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE); - nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS); - nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2); - - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - - nvt_efm_disable(nvt); - - nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | - CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | - CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, - CIR_WAKE_IRCON); - nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); - nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); -} - -/* rx carrier detect only works in learning mode, must be called w/nvt_lock */ -static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) -{ - u32 count, carrier, duration = 0; - int i; - - count = nvt_cir_reg_read(nvt, CIR_FCCL) | - nvt_cir_reg_read(nvt, CIR_FCCH) << 8; - - for (i = 0; i < nvt->pkts; i++) { - if (nvt->buf[i] & BUF_PULSE_BIT) - duration += nvt->buf[i] & BUF_LEN_MASK; - } - - duration *= SAMPLE_PERIOD; - - if (!count || !duration) { - nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)", - count, duration); - return 0; - } - - carrier = MS_TO_NS(count) / duration; - - if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER)) - nvt_dbg("WTF? Carrier frequency out of range!"); - - nvt_dbg("Carrier frequency: %u (count %u, duration %u)", - carrier, count, duration); - - return carrier; -} - -/* - * set carrier frequency - * - * set carrier on 2 registers: CP & CC - * always set CP as 0x81 - * set CC by SPEC, CC = 3MHz/carrier - 1 - */ -static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) -{ - struct nvt_dev *nvt = dev->priv; - u16 val; - - nvt_cir_reg_write(nvt, 1, CIR_CP); - val = 3000000 / (carrier) - 1; - nvt_cir_reg_write(nvt, val & 0xff, CIR_CC); - - nvt_dbg("cp: 0x%x cc: 0x%x\n", - nvt_cir_reg_read(nvt, CIR_CP), nvt_cir_reg_read(nvt, CIR_CC)); - - return 0; -} - -/* - * nvt_tx_ir - * - * 1) clean TX fifo first (handled by AP) - * 2) copy data from user space - * 3) disable RX interrupts, enable TX interrupts: TTR & TFU - * 4) send 9 packets to TX FIFO to open TTR - * in interrupt_handler: - * 5) send all data out - * go back to write(): - * 6) disable TX interrupts, re-enable RX interupts - * - * The key problem of this function is user space data may larger than - * driver's data buf length. So nvt_tx_ir() will only copy TX_BUF_LEN data to - * buf, and keep current copied data buf num in cur_buf_num. But driver's buf - * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to - * set TXFCONT as 0xff, until buf_count less than 0xff. - */ -static int nvt_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) -{ - struct nvt_dev *nvt = dev->priv; - unsigned long flags; - size_t cur_count; - unsigned int i; - u8 iren; - int ret; - - spin_lock_irqsave(&nvt->tx.lock, flags); - - if (n >= TX_BUF_LEN) { - nvt->tx.buf_count = cur_count = TX_BUF_LEN; - ret = TX_BUF_LEN; - } else { - nvt->tx.buf_count = cur_count = n; - ret = n; - } - - memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count); - - nvt->tx.cur_buf_num = 0; - - /* save currently enabled interrupts */ - iren = nvt_cir_reg_read(nvt, CIR_IREN); - - /* now disable all interrupts, save TFU & TTR */ - nvt_cir_reg_write(nvt, CIR_IREN_TFU | CIR_IREN_TTR, CIR_IREN); - - nvt->tx.tx_state = ST_TX_REPLY; - - nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV_8 | - CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); - - /* trigger TTR interrupt by writing out ones, (yes, it's ugly) */ - for (i = 0; i < 9; i++) - nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO); - - spin_unlock_irqrestore(&nvt->tx.lock, flags); - - wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST); - - spin_lock_irqsave(&nvt->tx.lock, flags); - nvt->tx.tx_state = ST_TX_NONE; - spin_unlock_irqrestore(&nvt->tx.lock, flags); - - /* restore enabled interrupts to prior state */ - nvt_cir_reg_write(nvt, iren, CIR_IREN); - - return ret; -} - -/* dump contents of the last rx buffer we got from the hw rx fifo */ -static void nvt_dump_rx_buf(struct nvt_dev *nvt) -{ - int i; - - printk(KERN_DEBUG "%s (len %d): ", __func__, nvt->pkts); - for (i = 0; (i < nvt->pkts) && (i < RX_BUF_LEN); i++) - printk(KERN_CONT "0x%02x ", nvt->buf[i]); - printk(KERN_CONT "\n"); -} - -/* - * Process raw data in rx driver buffer, store it in raw IR event kfifo, - * trigger decode when appropriate. - * - * We get IR data samples one byte at a time. If the msb is set, its a pulse, - * otherwise its a space. The lower 7 bits are the count of SAMPLE_PERIOD - * (default 50us) intervals for that pulse/space. A discrete signal is - * followed by a series of 0x7f packets, then either 0x7 or 0x80 - * to signal more IR coming (repeats) or end of IR, respectively. We store - * sample data in the raw event kfifo until we see 0x7 (except f) - * or 0x80, at which time, we trigger a decode operation. - */ -static void nvt_process_rx_ir_data(struct nvt_dev *nvt) -{ - DEFINE_IR_RAW_EVENT(rawir); - unsigned int count; - u32 carrier; - u8 sample; - int i; - - nvt_dbg_verbose("%s firing", __func__); - - if (debug) - nvt_dump_rx_buf(nvt); - - if (nvt->carrier_detect_enabled) - carrier = nvt_rx_carrier_detect(nvt); - - count = nvt->pkts; - nvt_dbg_verbose("Processing buffer of len %d", count); - - init_ir_raw_event(&rawir); - - for (i = 0; i < count; i++) { - nvt->pkts--; - sample = nvt->buf[i]; - - rawir.pulse = ((sample & BUF_PULSE_BIT) != 0); - rawir.duration = US_TO_NS((sample & BUF_LEN_MASK) - * SAMPLE_PERIOD); - - if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) { - if (nvt->rawir.pulse == rawir.pulse) - nvt->rawir.duration += rawir.duration; - else { - nvt->rawir.duration = rawir.duration; - nvt->rawir.pulse = rawir.pulse; - } - continue; - } - - rawir.duration += nvt->rawir.duration; - - init_ir_raw_event(&nvt->rawir); - nvt->rawir.duration = 0; - nvt->rawir.pulse = rawir.pulse; - - if (sample == BUF_PULSE_BIT) - rawir.pulse = false; - - if (rawir.duration) { - nvt_dbg("Storing %s with duration %d", - rawir.pulse ? "pulse" : "space", - rawir.duration); - - ir_raw_event_store(nvt->rdev, &rawir); - } - - /* - * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE - * indicates end of IR signal, but new data incoming. In both - * cases, it means we're ready to call ir_raw_event_handle - */ - if ((sample == BUF_PULSE_BIT) && nvt->pkts) { - nvt_dbg("Calling ir_raw_event_handle (signal end)\n"); - ir_raw_event_handle(nvt->rdev); - } - } - - nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n"); - ir_raw_event_handle(nvt->rdev); - - if (nvt->pkts) { - nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts); - nvt->pkts = 0; - } - - nvt_dbg_verbose("%s done", __func__); -} - -static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt) -{ - nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!"); - - nvt->pkts = 0; - nvt_clear_cir_fifo(nvt); - ir_raw_event_reset(nvt->rdev); -} - -/* copy data from hardware rx fifo into driver buffer */ -static void nvt_get_rx_ir_data(struct nvt_dev *nvt) -{ - unsigned long flags; - u8 fifocount, val; - unsigned int b_idx; - bool overrun = false; - int i; - - /* Get count of how many bytes to read from RX FIFO */ - fifocount = nvt_cir_reg_read(nvt, CIR_RXFCONT); - /* if we get 0xff, probably means the logical dev is disabled */ - if (fifocount == 0xff) - return; - /* watch out for a fifo overrun condition */ - else if (fifocount > RX_BUF_LEN) { - overrun = true; - fifocount = RX_BUF_LEN; - } - - nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount); - - spin_lock_irqsave(&nvt->nvt_lock, flags); - - b_idx = nvt->pkts; - - /* This should never happen, but lets check anyway... */ - if (b_idx + fifocount > RX_BUF_LEN) { - nvt_process_rx_ir_data(nvt); - b_idx = 0; - } - - /* Read fifocount bytes from CIR Sample RX FIFO register */ - for (i = 0; i < fifocount; i++) { - val = nvt_cir_reg_read(nvt, CIR_SRXFIFO); - nvt->buf[b_idx + i] = val; - } - - nvt->pkts += fifocount; - nvt_dbg("%s: pkts now %d", __func__, nvt->pkts); - - nvt_process_rx_ir_data(nvt); - - if (overrun) - nvt_handle_rx_fifo_overrun(nvt); - - spin_unlock_irqrestore(&nvt->nvt_lock, flags); -} - -static void nvt_cir_log_irqs(u8 status, u8 iren) -{ - nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s", - status, iren, - status & CIR_IRSTS_RDR ? " RDR" : "", - status & CIR_IRSTS_RTR ? " RTR" : "", - status & CIR_IRSTS_PE ? " PE" : "", - status & CIR_IRSTS_RFO ? " RFO" : "", - status & CIR_IRSTS_TE ? " TE" : "", - status & CIR_IRSTS_TTR ? " TTR" : "", - status & CIR_IRSTS_TFU ? " TFU" : "", - status & CIR_IRSTS_GH ? " GH" : "", - status & ~(CIR_IRSTS_RDR | CIR_IRSTS_RTR | CIR_IRSTS_PE | - CIR_IRSTS_RFO | CIR_IRSTS_TE | CIR_IRSTS_TTR | - CIR_IRSTS_TFU | CIR_IRSTS_GH) ? " ?" : ""); -} - -static bool nvt_cir_tx_inactive(struct nvt_dev *nvt) -{ - unsigned long flags; - bool tx_inactive; - u8 tx_state; - - spin_lock_irqsave(&nvt->tx.lock, flags); - tx_state = nvt->tx.tx_state; - spin_unlock_irqrestore(&nvt->tx.lock, flags); - - tx_inactive = (tx_state == ST_TX_NONE); - - return tx_inactive; -} - -/* interrupt service routine for incoming and outgoing CIR data */ -static irqreturn_t nvt_cir_isr(int irq, void *data) -{ - struct nvt_dev *nvt = data; - u8 status, iren, cur_state; - unsigned long flags; - - nvt_dbg_verbose("%s firing", __func__); - - nvt_efm_enable(nvt); - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_efm_disable(nvt); - - /* - * Get IR Status register contents. Write 1 to ack/clear - * - * bit: reg name - description - * 7: CIR_IRSTS_RDR - RX Data Ready - * 6: CIR_IRSTS_RTR - RX FIFO Trigger Level Reach - * 5: CIR_IRSTS_PE - Packet End - * 4: CIR_IRSTS_RFO - RX FIFO Overrun (RDR will also be set) - * 3: CIR_IRSTS_TE - TX FIFO Empty - * 2: CIR_IRSTS_TTR - TX FIFO Trigger Level Reach - * 1: CIR_IRSTS_TFU - TX FIFO Underrun - * 0: CIR_IRSTS_GH - Min Length Detected - */ - status = nvt_cir_reg_read(nvt, CIR_IRSTS); - if (!status) { - nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__); - nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); - return IRQ_RETVAL(IRQ_NONE); - } - - /* ack/clear all irq flags we've got */ - nvt_cir_reg_write(nvt, status, CIR_IRSTS); - nvt_cir_reg_write(nvt, 0, CIR_IRSTS); - - /* Interrupt may be shared with CIR Wake, bail if CIR not enabled */ - iren = nvt_cir_reg_read(nvt, CIR_IREN); - if (!iren) { - nvt_dbg_verbose("%s exiting, CIR not enabled", __func__); - return IRQ_RETVAL(IRQ_NONE); - } - - if (debug) - nvt_cir_log_irqs(status, iren); - - if (status & CIR_IRSTS_RTR) { - /* FIXME: add code for study/learn mode */ - /* We only do rx if not tx'ing */ - if (nvt_cir_tx_inactive(nvt)) - nvt_get_rx_ir_data(nvt); - } - - if (status & CIR_IRSTS_PE) { - if (nvt_cir_tx_inactive(nvt)) - nvt_get_rx_ir_data(nvt); - - spin_lock_irqsave(&nvt->nvt_lock, flags); - - cur_state = nvt->study_state; - - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - - if (cur_state == ST_STUDY_NONE) - nvt_clear_cir_fifo(nvt); - } - - if (status & CIR_IRSTS_TE) - nvt_clear_tx_fifo(nvt); - - if (status & CIR_IRSTS_TTR) { - unsigned int pos, count; - u8 tmp; - - spin_lock_irqsave(&nvt->tx.lock, flags); - - pos = nvt->tx.cur_buf_num; - count = nvt->tx.buf_count; - - /* Write data into the hardware tx fifo while pos < count */ - if (pos < count) { - nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO); - nvt->tx.cur_buf_num++; - /* Disable TX FIFO Trigger Level Reach (TTR) interrupt */ - } else { - tmp = nvt_cir_reg_read(nvt, CIR_IREN); - nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN); - } - - spin_unlock_irqrestore(&nvt->tx.lock, flags); - - } - - if (status & CIR_IRSTS_TFU) { - spin_lock_irqsave(&nvt->tx.lock, flags); - if (nvt->tx.tx_state == ST_TX_REPLY) { - nvt->tx.tx_state = ST_TX_REQUEST; - wake_up(&nvt->tx.queue); - } - spin_unlock_irqrestore(&nvt->tx.lock, flags); - } - - nvt_dbg_verbose("%s done", __func__); - return IRQ_RETVAL(IRQ_HANDLED); -} - -/* Interrupt service routine for CIR Wake */ -static irqreturn_t nvt_cir_wake_isr(int irq, void *data) -{ - u8 status, iren, val; - struct nvt_dev *nvt = data; - unsigned long flags; - - nvt_dbg_wake("%s firing", __func__); - - status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS); - if (!status) - return IRQ_RETVAL(IRQ_NONE); - - if (status & CIR_WAKE_IRSTS_IR_PENDING) - nvt_clear_cir_wake_fifo(nvt); - - nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS); - nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS); - - /* Interrupt may be shared with CIR, bail if Wake not enabled */ - iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN); - if (!iren) { - nvt_dbg_wake("%s exiting, wake not enabled", __func__); - return IRQ_RETVAL(IRQ_HANDLED); - } - - if ((status & CIR_WAKE_IRSTS_PE) && - (nvt->wake_state == ST_WAKE_START)) { - while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) { - val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); - nvt_dbg("setting wake up key: 0x%x", val); - } - - nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); - spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->wake_state = ST_WAKE_FINISH; - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - } - - nvt_dbg_wake("%s done", __func__); - return IRQ_RETVAL(IRQ_HANDLED); -} - -static void nvt_enable_cir(struct nvt_dev *nvt) -{ - /* set function enable flags */ - nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | - CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, - CIR_IRCON); - - nvt_efm_enable(nvt); - - /* enable the CIR logical device */ - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - - nvt_efm_disable(nvt); - - /* clear all pending interrupts */ - nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); - - /* enable interrupts */ - nvt_set_cir_iren(nvt); -} - -static void nvt_disable_cir(struct nvt_dev *nvt) -{ - /* disable CIR interrupts */ - nvt_cir_reg_write(nvt, 0, CIR_IREN); - - /* clear any and all pending interrupts */ - nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); - - /* clear all function enable flags */ - nvt_cir_reg_write(nvt, 0, CIR_IRCON); - - /* clear hardware rx and tx fifos */ - nvt_clear_cir_fifo(nvt); - nvt_clear_tx_fifo(nvt); - - nvt_efm_enable(nvt); - - /* disable the CIR logical device */ - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN); - - nvt_efm_disable(nvt); -} - -static int nvt_open(struct rc_dev *dev) -{ - struct nvt_dev *nvt = dev->priv; - unsigned long flags; - - spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->in_use = true; - nvt_enable_cir(nvt); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - - return 0; -} - -static void nvt_close(struct rc_dev *dev) -{ - struct nvt_dev *nvt = dev->priv; - unsigned long flags; - - spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->in_use = false; - nvt_disable_cir(nvt); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); -} - -/* Allocate memory, probe hardware, and initialize everything */ -static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) -{ - struct nvt_dev *nvt; - struct rc_dev *rdev; - int ret = -ENOMEM; - - nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL); - if (!nvt) - return ret; - - /* input device for IR remote (and tx) */ - rdev = rc_allocate_device(); - if (!rdev) - goto failure; - - ret = -ENODEV; - /* validate pnp resources */ - if (!pnp_port_valid(pdev, 0) || - pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) { - dev_err(&pdev->dev, "IR PNP Port not valid!\n"); - goto failure; - } - - if (!pnp_irq_valid(pdev, 0)) { - dev_err(&pdev->dev, "PNP IRQ not valid!\n"); - goto failure; - } - - if (!pnp_port_valid(pdev, 1) || - pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) { - dev_err(&pdev->dev, "Wake PNP Port not valid!\n"); - goto failure; - } - - nvt->cir_addr = pnp_port_start(pdev, 0); - nvt->cir_irq = pnp_irq(pdev, 0); - - nvt->cir_wake_addr = pnp_port_start(pdev, 1); - /* irq is always shared between cir and cir wake */ - nvt->cir_wake_irq = nvt->cir_irq; - - nvt->cr_efir = CR_EFIR; - nvt->cr_efdr = CR_EFDR; - - spin_lock_init(&nvt->nvt_lock); - spin_lock_init(&nvt->tx.lock); - init_ir_raw_event(&nvt->rawir); - - ret = -EBUSY; - /* now claim resources */ - if (!request_region(nvt->cir_addr, - CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) - goto failure; - - if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED, - NVT_DRIVER_NAME, (void *)nvt)) - goto failure; - - if (!request_region(nvt->cir_wake_addr, - CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) - goto failure; - - if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED, - NVT_DRIVER_NAME, (void *)nvt)) - goto failure; - - pnp_set_drvdata(pdev, nvt); - nvt->pdev = pdev; - - init_waitqueue_head(&nvt->tx.queue); - - ret = nvt_hw_detect(nvt); - if (ret) - goto failure; - - /* Initialize CIR & CIR Wake Logical Devices */ - nvt_efm_enable(nvt); - nvt_cir_ldev_init(nvt); - nvt_cir_wake_ldev_init(nvt); - nvt_efm_disable(nvt); - - /* Initialize CIR & CIR Wake Config Registers */ - nvt_cir_regs_init(nvt); - nvt_cir_wake_regs_init(nvt); - - /* Set up the rc device */ - rdev->priv = nvt; - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; - rdev->open = nvt_open; - rdev->close = nvt_close; - rdev->tx_ir = nvt_tx_ir; - rdev->s_tx_carrier = nvt_set_tx_carrier; - rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; - rdev->input_id.bustype = BUS_HOST; - rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2; - rdev->input_id.product = nvt->chip_major; - rdev->input_id.version = nvt->chip_minor; - rdev->driver_name = NVT_DRIVER_NAME; - rdev->map_name = RC_MAP_RC6_MCE; -#if 0 - rdev->min_timeout = XYZ; - rdev->max_timeout = XYZ; - rdev->timeout = XYZ; - /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */ - rdev->rx_resolution = XYZ; - /* tx bits */ - rdev->tx_resolution = XYZ; -#endif - - ret = rc_register_device(rdev); - if (ret) - goto failure; - - device_set_wakeup_capable(&pdev->dev, 1); - device_set_wakeup_enable(&pdev->dev, 1); - nvt->rdev = rdev; - nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n"); - if (debug) { - cir_dump_regs(nvt); - cir_wake_dump_regs(nvt); - } - - return 0; - -failure: - if (nvt->cir_irq) - free_irq(nvt->cir_irq, nvt); - if (nvt->cir_addr) - release_region(nvt->cir_addr, CIR_IOREG_LENGTH); - - if (nvt->cir_wake_irq) - free_irq(nvt->cir_wake_irq, nvt); - if (nvt->cir_wake_addr) - release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); - - rc_free_device(rdev); - kfree(nvt); - - return ret; -} - -static void __devexit nvt_remove(struct pnp_dev *pdev) -{ - struct nvt_dev *nvt = pnp_get_drvdata(pdev); - unsigned long flags; - - spin_lock_irqsave(&nvt->nvt_lock, flags); - /* disable CIR */ - nvt_cir_reg_write(nvt, 0, CIR_IREN); - nvt_disable_cir(nvt); - /* enable CIR Wake (for IR power-on) */ - nvt_enable_wake(nvt); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - - /* free resources */ - free_irq(nvt->cir_irq, nvt); - free_irq(nvt->cir_wake_irq, nvt); - release_region(nvt->cir_addr, CIR_IOREG_LENGTH); - release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); - - rc_unregister_device(nvt->rdev); - - kfree(nvt); -} - -static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) -{ - struct nvt_dev *nvt = pnp_get_drvdata(pdev); - unsigned long flags; - - nvt_dbg("%s called", __func__); - - /* zero out misc state tracking */ - spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->study_state = ST_STUDY_NONE; - nvt->wake_state = ST_WAKE_NONE; - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - - spin_lock_irqsave(&nvt->tx.lock, flags); - nvt->tx.tx_state = ST_TX_NONE; - spin_unlock_irqrestore(&nvt->tx.lock, flags); - - /* disable all CIR interrupts */ - nvt_cir_reg_write(nvt, 0, CIR_IREN); - - nvt_efm_enable(nvt); - - /* disable cir logical dev */ - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN); - - nvt_efm_disable(nvt); - - /* make sure wake is enabled */ - nvt_enable_wake(nvt); - - return 0; -} - -static int nvt_resume(struct pnp_dev *pdev) -{ - int ret = 0; - struct nvt_dev *nvt = pnp_get_drvdata(pdev); - - nvt_dbg("%s called", __func__); - - /* open interrupt */ - nvt_set_cir_iren(nvt); - - /* Enable CIR logical device */ - nvt_efm_enable(nvt); - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - - nvt_efm_disable(nvt); - - nvt_cir_regs_init(nvt); - nvt_cir_wake_regs_init(nvt); - - return ret; -} - -static void nvt_shutdown(struct pnp_dev *pdev) -{ - struct nvt_dev *nvt = pnp_get_drvdata(pdev); - nvt_enable_wake(nvt); -} - -static const struct pnp_device_id nvt_ids[] = { - { "WEC0530", 0 }, /* CIR */ - { "NTN0530", 0 }, /* CIR for new chip's pnp id*/ - { "", 0 }, -}; - -static struct pnp_driver nvt_driver = { - .name = NVT_DRIVER_NAME, - .id_table = nvt_ids, - .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, - .probe = nvt_probe, - .remove = __devexit_p(nvt_remove), - .suspend = nvt_suspend, - .resume = nvt_resume, - .shutdown = nvt_shutdown, -}; - -int nvt_init(void) -{ - return pnp_register_driver(&nvt_driver); -} - -void nvt_exit(void) -{ - pnp_unregister_driver(&nvt_driver); -} - -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging output"); - -MODULE_DEVICE_TABLE(pnp, nvt_ids); -MODULE_DESCRIPTION("Nuvoton W83667HG-A & W83677HG-I CIR driver"); - -MODULE_AUTHOR("Jarod Wilson "); -MODULE_LICENSE("GPL"); - -module_init(nvt_init); -module_exit(nvt_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/nuvoton-cir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/nuvoton-cir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/nuvoton-cir.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/nuvoton-cir.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,410 +0,0 @@ -/* - * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR - * - * Copyright (C) 2010 Jarod Wilson - * Copyright (C) 2009 Nuvoton PS Team - * - * Special thanks to Nuvoton for providing hardware, spec sheets and - * sample code upon which portions of this driver are based. Indirect - * thanks also to Maxim Levitsky, whose ene_ir driver this driver is - * modeled after. - * - * 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, or (at your option) any later version. - * - * 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 -#include - -/* platform driver name to register */ -#define NVT_DRIVER_NAME "nuvoton-cir" - -/* debugging module parameter */ -static int debug; - - -#define nvt_pr(level, text, ...) \ - printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) - -#define nvt_dbg(text, ...) \ - if (debug) \ - printk(KERN_DEBUG \ - KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) - -#define nvt_dbg_verbose(text, ...) \ - if (debug > 1) \ - printk(KERN_DEBUG \ - KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) - -#define nvt_dbg_wake(text, ...) \ - if (debug > 2) \ - printk(KERN_DEBUG \ - KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) - - -/* - * Original lirc driver said min value of 76, and recommended value of 256 - * for the buffer length, but then used 2048. Never mind that the size of the - * RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm - * not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes), - * and I don't have TX-capable hardware to test/debug on... - */ -#define TX_BUF_LEN 256 -#define RX_BUF_LEN 32 - -struct nvt_dev { - struct pnp_dev *pdev; - struct rc_dev *rdev; - struct ir_raw_event rawir; - - spinlock_t nvt_lock; - bool in_use; - - /* for rx */ - u8 buf[RX_BUF_LEN]; - unsigned int pkts; - - struct { - spinlock_t lock; - u8 buf[TX_BUF_LEN]; - unsigned int buf_count; - unsigned int cur_buf_num; - wait_queue_head_t queue; - u8 tx_state; - } tx; - - /* EFER Config register index/data pair */ - u8 cr_efir; - u8 cr_efdr; - - /* hardware I/O settings */ - unsigned long cir_addr; - unsigned long cir_wake_addr; - int cir_irq; - int cir_wake_irq; - - /* hardware id */ - u8 chip_major; - u8 chip_minor; - - /* hardware features */ - bool hw_learning_capable; - bool hw_tx_capable; - - /* rx settings */ - bool learning_enabled; - bool carrier_detect_enabled; - - /* track cir wake state */ - u8 wake_state; - /* for study */ - u8 study_state; - /* carrier period = 1 / frequency */ - u32 carrier; -}; - -/* study states */ -#define ST_STUDY_NONE 0x0 -#define ST_STUDY_START 0x1 -#define ST_STUDY_CARRIER 0x2 -#define ST_STUDY_ALL_RECV 0x4 - -/* wake states */ -#define ST_WAKE_NONE 0x0 -#define ST_WAKE_START 0x1 -#define ST_WAKE_FINISH 0x2 - -/* receive states */ -#define ST_RX_WAIT_7F 0x1 -#define ST_RX_WAIT_HEAD 0x2 -#define ST_RX_WAIT_SILENT_END 0x4 - -/* send states */ -#define ST_TX_NONE 0x0 -#define ST_TX_REQUEST 0x2 -#define ST_TX_REPLY 0x4 - -/* buffer packet constants */ -#define BUF_PULSE_BIT 0x80 -#define BUF_LEN_MASK 0x7f -#define BUF_REPEAT_BYTE 0x70 -#define BUF_REPEAT_MASK 0xf0 - -/* CIR settings */ - -/* total length of CIR and CIR WAKE */ -#define CIR_IOREG_LENGTH 0x0f - -/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL (0x7d0 = 2000) */ -#define CIR_RX_LIMIT_COUNT 0x7d0 - -/* CIR Regs */ -#define CIR_IRCON 0x00 -#define CIR_IRSTS 0x01 -#define CIR_IREN 0x02 -#define CIR_RXFCONT 0x03 -#define CIR_CP 0x04 -#define CIR_CC 0x05 -#define CIR_SLCH 0x06 -#define CIR_SLCL 0x07 -#define CIR_FIFOCON 0x08 -#define CIR_IRFIFOSTS 0x09 -#define CIR_SRXFIFO 0x0a -#define CIR_TXFCONT 0x0b -#define CIR_STXFIFO 0x0c -#define CIR_FCCH 0x0d -#define CIR_FCCL 0x0e -#define CIR_IRFSM 0x0f - -/* CIR IRCON settings */ -#define CIR_IRCON_RECV 0x80 -#define CIR_IRCON_WIREN 0x40 -#define CIR_IRCON_TXEN 0x20 -#define CIR_IRCON_RXEN 0x10 -#define CIR_IRCON_WRXINV 0x08 -#define CIR_IRCON_RXINV 0x04 - -#define CIR_IRCON_SAMPLE_PERIOD_SEL_1 0x00 -#define CIR_IRCON_SAMPLE_PERIOD_SEL_25 0x01 -#define CIR_IRCON_SAMPLE_PERIOD_SEL_50 0x02 -#define CIR_IRCON_SAMPLE_PERIOD_SEL_100 0x03 - -/* FIXME: make this a runtime option */ -/* select sample period as 50us */ -#define CIR_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50 - -/* CIR IRSTS settings */ -#define CIR_IRSTS_RDR 0x80 -#define CIR_IRSTS_RTR 0x40 -#define CIR_IRSTS_PE 0x20 -#define CIR_IRSTS_RFO 0x10 -#define CIR_IRSTS_TE 0x08 -#define CIR_IRSTS_TTR 0x04 -#define CIR_IRSTS_TFU 0x02 -#define CIR_IRSTS_GH 0x01 - -/* CIR IREN settings */ -#define CIR_IREN_RDR 0x80 -#define CIR_IREN_RTR 0x40 -#define CIR_IREN_PE 0x20 -#define CIR_IREN_RFO 0x10 -#define CIR_IREN_TE 0x08 -#define CIR_IREN_TTR 0x04 -#define CIR_IREN_TFU 0x02 -#define CIR_IREN_GH 0x01 - -/* CIR FIFOCON settings */ -#define CIR_FIFOCON_TXFIFOCLR 0x80 - -#define CIR_FIFOCON_TX_TRIGGER_LEV_31 0x00 -#define CIR_FIFOCON_TX_TRIGGER_LEV_24 0x10 -#define CIR_FIFOCON_TX_TRIGGER_LEV_16 0x20 -#define CIR_FIFOCON_TX_TRIGGER_LEV_8 0x30 - -/* FIXME: make this a runtime option */ -/* select TX trigger level as 16 */ -#define CIR_FIFOCON_TX_TRIGGER_LEV CIR_FIFOCON_TX_TRIGGER_LEV_16 - -#define CIR_FIFOCON_RXFIFOCLR 0x08 - -#define CIR_FIFOCON_RX_TRIGGER_LEV_1 0x00 -#define CIR_FIFOCON_RX_TRIGGER_LEV_8 0x01 -#define CIR_FIFOCON_RX_TRIGGER_LEV_16 0x02 -#define CIR_FIFOCON_RX_TRIGGER_LEV_24 0x03 - -/* FIXME: make this a runtime option */ -/* select RX trigger level as 24 */ -#define CIR_FIFOCON_RX_TRIGGER_LEV CIR_FIFOCON_RX_TRIGGER_LEV_24 - -/* CIR IRFIFOSTS settings */ -#define CIR_IRFIFOSTS_IR_PENDING 0x80 -#define CIR_IRFIFOSTS_RX_GS 0x40 -#define CIR_IRFIFOSTS_RX_FTA 0x20 -#define CIR_IRFIFOSTS_RX_EMPTY 0x10 -#define CIR_IRFIFOSTS_RX_FULL 0x08 -#define CIR_IRFIFOSTS_TX_FTA 0x04 -#define CIR_IRFIFOSTS_TX_EMPTY 0x02 -#define CIR_IRFIFOSTS_TX_FULL 0x01 - - -/* CIR WAKE UP Regs */ -#define CIR_WAKE_IRCON 0x00 -#define CIR_WAKE_IRSTS 0x01 -#define CIR_WAKE_IREN 0x02 -#define CIR_WAKE_FIFO_CMP_DEEP 0x03 -#define CIR_WAKE_FIFO_CMP_TOL 0x04 -#define CIR_WAKE_FIFO_COUNT 0x05 -#define CIR_WAKE_SLCH 0x06 -#define CIR_WAKE_SLCL 0x07 -#define CIR_WAKE_FIFOCON 0x08 -#define CIR_WAKE_SRXFSTS 0x09 -#define CIR_WAKE_SAMPLE_RX_FIFO 0x0a -#define CIR_WAKE_WR_FIFO_DATA 0x0b -#define CIR_WAKE_RD_FIFO_ONLY 0x0c -#define CIR_WAKE_RD_FIFO_ONLY_IDX 0x0d -#define CIR_WAKE_FIFO_IGNORE 0x0e -#define CIR_WAKE_IRFSM 0x0f - -/* CIR WAKE UP IRCON settings */ -#define CIR_WAKE_IRCON_DEC_RST 0x80 -#define CIR_WAKE_IRCON_MODE1 0x40 -#define CIR_WAKE_IRCON_MODE0 0x20 -#define CIR_WAKE_IRCON_RXEN 0x10 -#define CIR_WAKE_IRCON_R 0x08 -#define CIR_WAKE_IRCON_RXINV 0x04 - -/* FIXME/jarod: make this a runtime option */ -/* select a same sample period like cir register */ -#define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50 - -/* CIR WAKE IRSTS Bits */ -#define CIR_WAKE_IRSTS_RDR 0x80 -#define CIR_WAKE_IRSTS_RTR 0x40 -#define CIR_WAKE_IRSTS_PE 0x20 -#define CIR_WAKE_IRSTS_RFO 0x10 -#define CIR_WAKE_IRSTS_GH 0x08 -#define CIR_WAKE_IRSTS_IR_PENDING 0x01 - -/* CIR WAKE UP IREN Bits */ -#define CIR_WAKE_IREN_RDR 0x80 -#define CIR_WAKE_IREN_RTR 0x40 -#define CIR_WAKE_IREN_PE 0x20 -#define CIR_WAKE_IREN_RFO 0x10 -#define CIR_WAKE_IREN_TE 0x08 -#define CIR_WAKE_IREN_TTR 0x04 -#define CIR_WAKE_IREN_TFU 0x02 -#define CIR_WAKE_IREN_GH 0x01 - -/* CIR WAKE FIFOCON settings */ -#define CIR_WAKE_FIFOCON_RXFIFOCLR 0x08 - -#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 0x00 -#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_66 0x01 -#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_65 0x02 -#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_64 0x03 - -/* FIXME: make this a runtime option */ -/* select WAKE UP RX trigger level as 67 */ -#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 - -/* CIR WAKE SRXFSTS settings */ -#define CIR_WAKE_IRFIFOSTS_RX_GS 0x80 -#define CIR_WAKE_IRFIFOSTS_RX_FTA 0x40 -#define CIR_WAKE_IRFIFOSTS_RX_EMPTY 0x20 -#define CIR_WAKE_IRFIFOSTS_RX_FULL 0x10 - -/* - * The CIR Wake FIFO buffer is 67 bytes long, but the stock remote wakes - * the system comparing only 65 bytes (fails with this set to 67) - */ -#define CIR_WAKE_FIFO_CMP_BYTES 65 -/* CIR Wake byte comparison tolerance */ -#define CIR_WAKE_CMP_TOLERANCE 5 - -/* - * Extended Function Enable Registers: - * Extended Function Index Register - * Extended Function Data Register - */ -#define CR_EFIR 0x2e -#define CR_EFDR 0x2f - -/* Possible alternate EFER values, depends on how the chip is wired */ -#define CR_EFIR2 0x4e -#define CR_EFDR2 0x4f - -/* Extended Function Mode enable/disable magic values */ -#define EFER_EFM_ENABLE 0x87 -#define EFER_EFM_DISABLE 0xaa - -/* Chip IDs found in CR_CHIP_ID_{HI,LO} */ -#define CHIP_ID_HIGH 0xb4 -#define CHIP_ID_LOW 0x72 -#define CHIP_ID_LOW2 0x73 - -/* Config regs we need to care about */ -#define CR_SOFTWARE_RESET 0x02 -#define CR_LOGICAL_DEV_SEL 0x07 -#define CR_CHIP_ID_HI 0x20 -#define CR_CHIP_ID_LO 0x21 -#define CR_DEV_POWER_DOWN 0x22 /* bit 2 is CIR power, default power on */ -#define CR_OUTPUT_PIN_SEL 0x27 -#define CR_LOGICAL_DEV_EN 0x30 /* valid for all logical devices */ -/* next three regs valid for both the CIR and CIR_WAKE logical devices */ -#define CR_CIR_BASE_ADDR_HI 0x60 -#define CR_CIR_BASE_ADDR_LO 0x61 -#define CR_CIR_IRQ_RSRC 0x70 -/* next three regs valid only for ACPI logical dev */ -#define CR_ACPI_CIR_WAKE 0xe0 -#define CR_ACPI_IRQ_EVENTS 0xf6 -#define CR_ACPI_IRQ_EVENTS2 0xf7 - -/* Logical devices that we need to care about */ -#define LOGICAL_DEV_LPT 0x01 -#define LOGICAL_DEV_CIR 0x06 -#define LOGICAL_DEV_ACPI 0x0a -#define LOGICAL_DEV_CIR_WAKE 0x0e - -#define LOGICAL_DEV_DISABLE 0x00 -#define LOGICAL_DEV_ENABLE 0x01 - -#define CIR_WAKE_ENABLE_BIT 0x08 -#define CIR_INTR_MOUSE_IRQ_BIT 0x80 -#define PME_INTR_CIR_PASS_BIT 0x08 - -#define OUTPUT_PIN_SEL_MASK 0xbc -#define OUTPUT_ENABLE_CIR 0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */ -#define OUTPUT_ENABLE_CIRWB 0x40 /* enable wide-band sensor */ - -/* MCE CIR signal length, related on sample period */ - -/* MCE CIR controller signal length: about 43ms - * 43ms / 50us (sample period) * 0.85 (inaccuracy) - */ -#define CONTROLLER_BUF_LEN_MIN 830 - -/* MCE CIR keyboard signal length: about 26ms - * 26ms / 50us (sample period) * 0.85 (inaccuracy) - */ -#define KEYBOARD_BUF_LEN_MAX 650 -#define KEYBOARD_BUF_LEN_MIN 610 - -/* MCE CIR mouse signal length: about 24ms - * 24ms / 50us (sample period) * 0.85 (inaccuracy) - */ -#define MOUSE_BUF_LEN_MIN 565 - -#define CIR_SAMPLE_PERIOD 50 -#define CIR_SAMPLE_LOW_INACCURACY 0.85 - -/* MAX silence time that driver will sent to lirc */ -#define MAX_SILENCE_TIME 60000 - -#if CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_100 -#define SAMPLE_PERIOD 100 - -#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_50 -#define SAMPLE_PERIOD 50 - -#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_25 -#define SAMPLE_PERIOD 25 - -#else -#define SAMPLE_PERIOD 1 -#endif - -/* as VISTA MCE definition, valid carrier value */ -#define MAX_CARRIER 60000 -#define MIN_CARRIER 30000 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-core-priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-core-priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-core-priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-core-priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,193 +0,0 @@ -/* - * Remote Controller core raw events header - * - * Copyright (C) 2010 by Mauro Carvalho Chehab - * - * 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 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. - */ - -#ifndef _RC_CORE_PRIV -#define _RC_CORE_PRIV - -#include -#include -#include - -struct ir_raw_handler { - struct list_head list; - - u64 protocols; /* which are handled by this handler */ - int (*decode)(struct rc_dev *dev, struct ir_raw_event event); - - /* These two should only be used by the lirc decoder */ - int (*raw_register)(struct rc_dev *dev); - int (*raw_unregister)(struct rc_dev *dev); -}; - -struct ir_raw_event_ctrl { - struct list_head list; /* to keep track of raw clients */ - struct task_struct *thread; - spinlock_t lock; - struct kfifo kfifo; /* fifo for the pulse/space durations */ - ktime_t last_event; /* when last event occurred */ - enum raw_event_type last_type; /* last event type */ - struct rc_dev *dev; /* pointer to the parent rc_dev */ - u64 enabled_protocols; /* enabled raw protocol decoders */ - - /* raw decoder state follows */ - struct ir_raw_event prev_ev; - struct ir_raw_event this_ev; - struct nec_dec { - int state; - unsigned count; - u32 bits; - bool is_nec_x; - bool necx_repeat; - } nec; - struct rc5_dec { - int state; - u32 bits; - unsigned count; - unsigned wanted_bits; - } rc5; - struct rc6_dec { - int state; - u8 header; - u32 body; - bool toggle; - unsigned count; - unsigned wanted_bits; - } rc6; - struct sony_dec { - int state; - u32 bits; - unsigned count; - } sony; - struct jvc_dec { - int state; - u16 bits; - u16 old_bits; - unsigned count; - bool first; - bool toggle; - } jvc; - struct rc5_sz_dec { - int state; - u32 bits; - unsigned count; - unsigned wanted_bits; - } rc5_sz; - struct lirc_codec { - struct rc_dev *dev; - struct lirc_driver *drv; - int carrier_low; - - ktime_t gap_start; - u64 gap_duration; - bool gap; - bool send_timeout_reports; - - } lirc; -}; - -/* macros for IR decoders */ -static inline bool geq_margin(unsigned d1, unsigned d2, unsigned margin) -{ - return d1 > (d2 - margin); -} - -static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin) -{ - return ((d1 > (d2 - margin)) && (d1 < (d2 + margin))); -} - -static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y) -{ - return x->pulse != y->pulse; -} - -static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration) -{ - if (duration > ev->duration) - ev->duration = 0; - else - ev->duration -= duration; -} - -/* Returns true if event is normal pulse/space event */ -static inline bool is_timing_event(struct ir_raw_event ev) -{ - return !ev.carrier_report && !ev.reset; -} - -#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000) -#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space") - -/* - * Routines from rc-raw.c to be used internally and by decoders - */ -u64 ir_raw_get_allowed_protocols(void); -int ir_raw_event_register(struct rc_dev *dev); -void ir_raw_event_unregister(struct rc_dev *dev); -int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); -void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler); -void ir_raw_init(void); - -/* - * Decoder initialization code - * - * Those load logic are called during ir-core init, and automatically - * loads the compiled decoders for their usage with IR raw events - */ - -/* from ir-nec-decoder.c */ -#ifdef CONFIG_IR_NEC_DECODER_MODULE -#define load_nec_decode() request_module("ir-nec-decoder") -#else -#define load_nec_decode() 0 -#endif - -/* from ir-rc5-decoder.c */ -#ifdef CONFIG_IR_RC5_DECODER_MODULE -#define load_rc5_decode() request_module("ir-rc5-decoder") -#else -#define load_rc5_decode() 0 -#endif - -/* from ir-rc6-decoder.c */ -#ifdef CONFIG_IR_RC6_DECODER_MODULE -#define load_rc6_decode() request_module("ir-rc6-decoder") -#else -#define load_rc6_decode() 0 -#endif - -/* from ir-jvc-decoder.c */ -#ifdef CONFIG_IR_JVC_DECODER_MODULE -#define load_jvc_decode() request_module("ir-jvc-decoder") -#else -#define load_jvc_decode() 0 -#endif - -/* from ir-sony-decoder.c */ -#ifdef CONFIG_IR_SONY_DECODER_MODULE -#define load_sony_decode() request_module("ir-sony-decoder") -#else -#define load_sony_decode() 0 -#endif - -/* from ir-lirc-codec.c */ -#ifdef CONFIG_IR_LIRC_CODEC_MODULE -#define load_lirc_codec() request_module("ir-lirc-codec") -#else -#define load_lirc_codec() 0 -#endif - - -#endif /* _RC_CORE_PRIV */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-loopback.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-loopback.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-loopback.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-loopback.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,260 +0,0 @@ -/* - * Loopback driver for rc-core, - * - * Copyright (c) 2010 David Härdeman - * - * This driver receives TX data and passes it back as RX data, - * which is useful for (scripted) debugging of rc-core without - * having to use actual hardware. - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include - -#define DRIVER_NAME "rc-loopback" -#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x) -#define RXMASK_REGULAR 0x1 -#define RXMASK_LEARNING 0x2 - -static bool debug; - -struct loopback_dev { - struct rc_dev *dev; - u32 txmask; - u32 txcarrier; - u32 txduty; - bool idle; - bool learning; - bool carrierreport; - u32 rxcarriermin; - u32 rxcarriermax; -}; - -static struct loopback_dev loopdev; - -static int loop_set_tx_mask(struct rc_dev *dev, u32 mask) -{ - struct loopback_dev *lodev = dev->priv; - - if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) { - dprintk("invalid tx mask: %u\n", mask); - return -EINVAL; - } - - dprintk("setting tx mask: %u\n", mask); - lodev->txmask = mask; - return 0; -} - -static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier) -{ - struct loopback_dev *lodev = dev->priv; - - dprintk("setting tx carrier: %u\n", carrier); - lodev->txcarrier = carrier; - return 0; -} - -static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle) -{ - struct loopback_dev *lodev = dev->priv; - - if (duty_cycle < 1 || duty_cycle > 99) { - dprintk("invalid duty cycle: %u\n", duty_cycle); - return -EINVAL; - } - - dprintk("setting duty cycle: %u\n", duty_cycle); - lodev->txduty = duty_cycle; - return 0; -} - -static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max) -{ - struct loopback_dev *lodev = dev->priv; - - if (min < 1 || min > max) { - dprintk("invalid rx carrier range %u to %u\n", min, max); - return -EINVAL; - } - - dprintk("setting rx carrier range %u to %u\n", min, max); - lodev->rxcarriermin = min; - lodev->rxcarriermax = max; - return 0; -} - -static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) -{ - struct loopback_dev *lodev = dev->priv; - u32 rxmask; - unsigned count; - unsigned total_duration = 0; - unsigned i; - DEFINE_IR_RAW_EVENT(rawir); - - if (n == 0 || n % sizeof(int)) { - dprintk("invalid tx buffer size\n"); - return -EINVAL; - } - - count = n / sizeof(int); - for (i = 0; i < count; i++) - total_duration += abs(txbuf[i]); - - if (total_duration == 0) { - dprintk("invalid tx data, total duration zero\n"); - return -EINVAL; - } - - if (lodev->txcarrier < lodev->rxcarriermin || - lodev->txcarrier > lodev->rxcarriermax) { - dprintk("ignoring tx, carrier out of range\n"); - goto out; - } - - if (lodev->learning) - rxmask = RXMASK_LEARNING; - else - rxmask = RXMASK_REGULAR; - - if (!(rxmask & lodev->txmask)) { - dprintk("ignoring tx, rx mask mismatch\n"); - goto out; - } - - for (i = 0; i < count; i++) { - rawir.pulse = i % 2 ? false : true; - rawir.duration = abs(txbuf[i]) * 1000; - if (rawir.duration) - ir_raw_event_store_with_filter(dev, &rawir); - } - ir_raw_event_handle(dev); - -out: - /* Lirc expects this function to take as long as the total duration */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(total_duration)); - return n; -} - -static void loop_set_idle(struct rc_dev *dev, bool enable) -{ - struct loopback_dev *lodev = dev->priv; - - if (lodev->idle != enable) { - dprintk("%sing idle mode\n", enable ? "enter" : "exit"); - lodev->idle = enable; - } -} - -static int loop_set_learning_mode(struct rc_dev *dev, int enable) -{ - struct loopback_dev *lodev = dev->priv; - - if (lodev->learning != enable) { - dprintk("%sing learning mode\n", enable ? "enter" : "exit"); - lodev->learning = !!enable; - } - - return 0; -} - -static int loop_set_carrier_report(struct rc_dev *dev, int enable) -{ - struct loopback_dev *lodev = dev->priv; - - if (lodev->carrierreport != enable) { - dprintk("%sabling carrier reports\n", enable ? "en" : "dis"); - lodev->carrierreport = !!enable; - } - - return 0; -} - -static int __init loop_init(void) -{ - struct rc_dev *rc; - int ret; - - rc = rc_allocate_device(); - if (!rc) { - printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n"); - return -ENOMEM; - } - - rc->input_name = "rc-core loopback device"; - rc->input_phys = "rc-core/virtual"; - rc->input_id.bustype = BUS_VIRTUAL; - rc->input_id.version = 1; - rc->driver_name = DRIVER_NAME; - rc->map_name = RC_MAP_EMPTY; - rc->priv = &loopdev; - rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_TYPE_ALL; - rc->timeout = 100 * 1000 * 1000; /* 100 ms */ - rc->min_timeout = 1; - rc->max_timeout = UINT_MAX; - rc->rx_resolution = 1000; - rc->tx_resolution = 1000; - rc->s_tx_mask = loop_set_tx_mask; - rc->s_tx_carrier = loop_set_tx_carrier; - rc->s_tx_duty_cycle = loop_set_tx_duty_cycle; - rc->s_rx_carrier_range = loop_set_rx_carrier_range; - rc->tx_ir = loop_tx_ir; - rc->s_idle = loop_set_idle; - rc->s_learning_mode = loop_set_learning_mode; - rc->s_carrier_report = loop_set_carrier_report; - rc->priv = &loopdev; - - loopdev.txmask = RXMASK_REGULAR; - loopdev.txcarrier = 36000; - loopdev.txduty = 50; - loopdev.rxcarriermin = 1; - loopdev.rxcarriermax = ~0; - loopdev.idle = true; - loopdev.learning = false; - loopdev.carrierreport = false; - - ret = rc_register_device(rc); - if (ret < 0) { - printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n"); - rc_free_device(rc); - return ret; - } - - loopdev.dev = rc; - return 0; -} - -static void __exit loop_exit(void) -{ - rc_unregister_device(loopdev.dev); -} - -module_init(loop_init); -module_exit(loop_exit); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debug messages"); - -MODULE_DESCRIPTION("Loopback device for rc-core debugging"); -MODULE_AUTHOR("David Härdeman "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-main.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-main.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-main.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/rc-main.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1141 +0,0 @@ -/* rc-main.c - Remote Controller core module - * - * Copyright (C) 2009-2010 by Mauro Carvalho Chehab - * - * 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 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. - */ - -#include -#include -#include -#include -#include -#include -#include "rc-core-priv.h" - -/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ -#define IR_TAB_MIN_SIZE 256 -#define IR_TAB_MAX_SIZE 8192 - -/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */ -#define IR_KEYPRESS_TIMEOUT 250 - -/* Used to keep track of known keymaps */ -static LIST_HEAD(rc_map_list); -static DEFINE_SPINLOCK(rc_map_lock); - -static struct rc_map_list *seek_rc_map(const char *name) -{ - struct rc_map_list *map = NULL; - - spin_lock(&rc_map_lock); - list_for_each_entry(map, &rc_map_list, list) { - if (!strcmp(name, map->map.name)) { - spin_unlock(&rc_map_lock); - return map; - } - } - spin_unlock(&rc_map_lock); - - return NULL; -} - -struct rc_map *rc_map_get(const char *name) -{ - - struct rc_map_list *map; - - map = seek_rc_map(name); -#ifdef MODULE - if (!map) { - int rc = request_module(name); - if (rc < 0) { - printk(KERN_ERR "Couldn't load IR keymap %s\n", name); - return NULL; - } - msleep(20); /* Give some time for IR to register */ - - map = seek_rc_map(name); - } -#endif - if (!map) { - printk(KERN_ERR "IR keymap %s not found\n", name); - return NULL; - } - - printk(KERN_INFO "Registered IR keymap %s\n", map->map.name); - - return &map->map; -} -EXPORT_SYMBOL_GPL(rc_map_get); - -int rc_map_register(struct rc_map_list *map) -{ - spin_lock(&rc_map_lock); - list_add_tail(&map->list, &rc_map_list); - spin_unlock(&rc_map_lock); - return 0; -} -EXPORT_SYMBOL_GPL(rc_map_register); - -void rc_map_unregister(struct rc_map_list *map) -{ - spin_lock(&rc_map_lock); - list_del(&map->list); - spin_unlock(&rc_map_lock); -} -EXPORT_SYMBOL_GPL(rc_map_unregister); - - -static struct rc_map_table empty[] = { - { 0x2a, KEY_COFFEE }, -}; - -static struct rc_map_list empty_map = { - .map = { - .scan = empty, - .size = ARRAY_SIZE(empty), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_EMPTY, - } -}; - -/** - * ir_create_table() - initializes a scancode table - * @rc_map: the rc_map to initialize - * @name: name to assign to the table - * @rc_type: ir type to assign to the new table - * @size: initial size of the table - * @return: zero on success or a negative error code - * - * This routine will initialize the rc_map and will allocate - * memory to hold at least the specified number of elements. - */ -static int ir_create_table(struct rc_map *rc_map, - const char *name, u64 rc_type, size_t size) -{ - rc_map->name = name; - rc_map->rc_type = rc_type; - rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table)); - rc_map->size = rc_map->alloc / sizeof(struct rc_map_table); - rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL); - if (!rc_map->scan) - return -ENOMEM; - - IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n", - rc_map->size, rc_map->alloc); - return 0; -} - -/** - * ir_free_table() - frees memory allocated by a scancode table - * @rc_map: the table whose mappings need to be freed - * - * This routine will free memory alloctaed for key mappings used by given - * scancode table. - */ -static void ir_free_table(struct rc_map *rc_map) -{ - rc_map->size = 0; - kfree(rc_map->scan); - rc_map->scan = NULL; -} - -/** - * ir_resize_table() - resizes a scancode table if necessary - * @rc_map: the rc_map to resize - * @gfp_flags: gfp flags to use when allocating memory - * @return: zero on success or a negative error code - * - * This routine will shrink the rc_map if it has lots of - * unused entries and grow it if it is full. - */ -static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags) -{ - unsigned int oldalloc = rc_map->alloc; - unsigned int newalloc = oldalloc; - struct rc_map_table *oldscan = rc_map->scan; - struct rc_map_table *newscan; - - if (rc_map->size == rc_map->len) { - /* All entries in use -> grow keytable */ - if (rc_map->alloc >= IR_TAB_MAX_SIZE) - return -ENOMEM; - - newalloc *= 2; - IR_dprintk(1, "Growing table to %u bytes\n", newalloc); - } - - if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) { - /* Less than 1/3 of entries in use -> shrink keytable */ - newalloc /= 2; - IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc); - } - - if (newalloc == oldalloc) - return 0; - - newscan = kmalloc(newalloc, gfp_flags); - if (!newscan) { - IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc); - return -ENOMEM; - } - - memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table)); - rc_map->scan = newscan; - rc_map->alloc = newalloc; - rc_map->size = rc_map->alloc / sizeof(struct rc_map_table); - kfree(oldscan); - return 0; -} - -/** - * ir_update_mapping() - set a keycode in the scancode->keycode table - * @dev: the struct rc_dev device descriptor - * @rc_map: scancode table to be adjusted - * @index: index of the mapping that needs to be updated - * @keycode: the desired keycode - * @return: previous keycode assigned to the mapping - * - * This routine is used to update scancode->keycode mapping at given - * position. - */ -static unsigned int ir_update_mapping(struct rc_dev *dev, - struct rc_map *rc_map, - unsigned int index, - unsigned int new_keycode) -{ - int old_keycode = rc_map->scan[index].keycode; - int i; - - /* Did the user wish to remove the mapping? */ - if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) { - IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", - index, rc_map->scan[index].scancode); - rc_map->len--; - memmove(&rc_map->scan[index], &rc_map->scan[index+ 1], - (rc_map->len - index) * sizeof(struct rc_map_table)); - } else { - IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n", - index, - old_keycode == KEY_RESERVED ? "New" : "Replacing", - rc_map->scan[index].scancode, new_keycode); - rc_map->scan[index].keycode = new_keycode; - __set_bit(new_keycode, dev->input_dev->keybit); - } - - if (old_keycode != KEY_RESERVED) { - /* A previous mapping was updated... */ - __clear_bit(old_keycode, dev->input_dev->keybit); - /* ... but another scancode might use the same keycode */ - for (i = 0; i < rc_map->len; i++) { - if (rc_map->scan[i].keycode == old_keycode) { - __set_bit(old_keycode, dev->input_dev->keybit); - break; - } - } - - /* Possibly shrink the keytable, failure is not a problem */ - ir_resize_table(rc_map, GFP_ATOMIC); - } - - return old_keycode; -} - -/** - * ir_establish_scancode() - set a keycode in the scancode->keycode table - * @dev: the struct rc_dev device descriptor - * @rc_map: scancode table to be searched - * @scancode: the desired scancode - * @resize: controls whether we allowed to resize the table to - * accomodate not yet present scancodes - * @return: index of the mapping containing scancode in question - * or -1U in case of failure. - * - * This routine is used to locate given scancode in rc_map. - * If scancode is not yet present the routine will allocate a new slot - * for it. - */ -static unsigned int ir_establish_scancode(struct rc_dev *dev, - struct rc_map *rc_map, - unsigned int scancode, - bool resize) -{ - unsigned int i; - - /* - * Unfortunately, some hardware-based IR decoders don't provide - * all bits for the complete IR code. In general, they provide only - * the command part of the IR code. Yet, as it is possible to replace - * the provided IR with another one, it is needed to allow loading - * IR tables from other remotes. So, we support specifying a mask to - * indicate the valid bits of the scancodes. - */ - if (dev->scanmask) - scancode &= dev->scanmask; - - /* First check if we already have a mapping for this ir command */ - for (i = 0; i < rc_map->len; i++) { - if (rc_map->scan[i].scancode == scancode) - return i; - - /* Keytable is sorted from lowest to highest scancode */ - if (rc_map->scan[i].scancode >= scancode) - break; - } - - /* No previous mapping found, we might need to grow the table */ - if (rc_map->size == rc_map->len) { - if (!resize || ir_resize_table(rc_map, GFP_ATOMIC)) - return -1U; - } - - /* i is the proper index to insert our new keycode */ - if (i < rc_map->len) - memmove(&rc_map->scan[i + 1], &rc_map->scan[i], - (rc_map->len - i) * sizeof(struct rc_map_table)); - rc_map->scan[i].scancode = scancode; - rc_map->scan[i].keycode = KEY_RESERVED; - rc_map->len++; - - return i; -} - -/** - * ir_setkeycode() - set a keycode in the scancode->keycode table - * @idev: the struct input_dev device descriptor - * @scancode: the desired scancode - * @keycode: result - * @return: -EINVAL if the keycode could not be inserted, otherwise zero. - * - * This routine is used to handle evdev EVIOCSKEY ioctl. - */ -static int ir_setkeycode(struct input_dev *idev, - const struct input_keymap_entry *ke, - unsigned int *old_keycode) -{ - struct rc_dev *rdev = input_get_drvdata(idev); - struct rc_map *rc_map = &rdev->rc_map; - unsigned int index; - unsigned int scancode; - int retval = 0; - unsigned long flags; - - spin_lock_irqsave(&rc_map->lock, flags); - - if (ke->flags & INPUT_KEYMAP_BY_INDEX) { - index = ke->index; - if (index >= rc_map->len) { - retval = -EINVAL; - goto out; - } - } else { - retval = input_scancode_to_scalar(ke, &scancode); - if (retval) - goto out; - - index = ir_establish_scancode(rdev, rc_map, scancode, true); - if (index >= rc_map->len) { - retval = -ENOMEM; - goto out; - } - } - - *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode); - -out: - spin_unlock_irqrestore(&rc_map->lock, flags); - return retval; -} - -/** - * ir_setkeytable() - sets several entries in the scancode->keycode table - * @dev: the struct rc_dev device descriptor - * @to: the struct rc_map to copy entries to - * @from: the struct rc_map to copy entries from - * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero. - * - * This routine is used to handle table initialization. - */ -static int ir_setkeytable(struct rc_dev *dev, - const struct rc_map *from) -{ - struct rc_map *rc_map = &dev->rc_map; - unsigned int i, index; - int rc; - - rc = ir_create_table(rc_map, from->name, - from->rc_type, from->size); - if (rc) - return rc; - - IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n", - rc_map->size, rc_map->alloc); - - for (i = 0; i < from->size; i++) { - index = ir_establish_scancode(dev, rc_map, - from->scan[i].scancode, false); - if (index >= rc_map->len) { - rc = -ENOMEM; - break; - } - - ir_update_mapping(dev, rc_map, index, - from->scan[i].keycode); - } - - if (rc) - ir_free_table(rc_map); - - return rc; -} - -/** - * ir_lookup_by_scancode() - locate mapping by scancode - * @rc_map: the struct rc_map to search - * @scancode: scancode to look for in the table - * @return: index in the table, -1U if not found - * - * This routine performs binary search in RC keykeymap table for - * given scancode. - */ -static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map, - unsigned int scancode) -{ - int start = 0; - int end = rc_map->len - 1; - int mid; - - while (start <= end) { - mid = (start + end) / 2; - if (rc_map->scan[mid].scancode < scancode) - start = mid + 1; - else if (rc_map->scan[mid].scancode > scancode) - end = mid - 1; - else - return mid; - } - - return -1U; -} - -/** - * ir_getkeycode() - get a keycode from the scancode->keycode table - * @idev: the struct input_dev device descriptor - * @scancode: the desired scancode - * @keycode: used to return the keycode, if found, or KEY_RESERVED - * @return: always returns zero. - * - * This routine is used to handle evdev EVIOCGKEY ioctl. - */ -static int ir_getkeycode(struct input_dev *idev, - struct input_keymap_entry *ke) -{ - struct rc_dev *rdev = input_get_drvdata(idev); - struct rc_map *rc_map = &rdev->rc_map; - struct rc_map_table *entry; - unsigned long flags; - unsigned int index; - unsigned int scancode; - int retval; - - spin_lock_irqsave(&rc_map->lock, flags); - - if (ke->flags & INPUT_KEYMAP_BY_INDEX) { - index = ke->index; - } else { - retval = input_scancode_to_scalar(ke, &scancode); - if (retval) - goto out; - - index = ir_lookup_by_scancode(rc_map, scancode); - } - - if (index < rc_map->len) { - entry = &rc_map->scan[index]; - - ke->index = index; - ke->keycode = entry->keycode; - ke->len = sizeof(entry->scancode); - memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode)); - - } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) { - /* - * We do not really know the valid range of scancodes - * so let's respond with KEY_RESERVED to anything we - * do not have mapping for [yet]. - */ - ke->index = index; - ke->keycode = KEY_RESERVED; - } else { - retval = -EINVAL; - goto out; - } - - retval = 0; - -out: - spin_unlock_irqrestore(&rc_map->lock, flags); - return retval; -} - -/** - * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode - * @dev: the struct rc_dev descriptor of the device - * @scancode: the scancode to look for - * @return: the corresponding keycode, or KEY_RESERVED - * - * This routine is used by drivers which need to convert a scancode to a - * keycode. Normally it should not be used since drivers should have no - * interest in keycodes. - */ -u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode) -{ - struct rc_map *rc_map = &dev->rc_map; - unsigned int keycode; - unsigned int index; - unsigned long flags; - - spin_lock_irqsave(&rc_map->lock, flags); - - index = ir_lookup_by_scancode(rc_map, scancode); - keycode = index < rc_map->len ? - rc_map->scan[index].keycode : KEY_RESERVED; - - spin_unlock_irqrestore(&rc_map->lock, flags); - - if (keycode != KEY_RESERVED) - IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n", - dev->input_name, scancode, keycode); - - return keycode; -} -EXPORT_SYMBOL_GPL(rc_g_keycode_from_table); - -/** - * ir_do_keyup() - internal function to signal the release of a keypress - * @dev: the struct rc_dev descriptor of the device - * - * This function is used internally to release a keypress, it must be - * called with keylock held. - */ -static void ir_do_keyup(struct rc_dev *dev) -{ - if (!dev->keypressed) - return; - - IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); - input_report_key(dev->input_dev, dev->last_keycode, 0); - input_sync(dev->input_dev); - dev->keypressed = false; -} - -/** - * rc_keyup() - signals the release of a keypress - * @dev: the struct rc_dev descriptor of the device - * - * This routine is used to signal that a key has been released on the - * remote control. - */ -void rc_keyup(struct rc_dev *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->keylock, flags); - ir_do_keyup(dev); - spin_unlock_irqrestore(&dev->keylock, flags); -} -EXPORT_SYMBOL_GPL(rc_keyup); - -/** - * ir_timer_keyup() - generates a keyup event after a timeout - * @cookie: a pointer to the struct rc_dev for the device - * - * This routine will generate a keyup event some time after a keydown event - * is generated when no further activity has been detected. - */ -static void ir_timer_keyup(unsigned long cookie) -{ - struct rc_dev *dev = (struct rc_dev *)cookie; - unsigned long flags; - - /* - * ir->keyup_jiffies is used to prevent a race condition if a - * hardware interrupt occurs at this point and the keyup timer - * event is moved further into the future as a result. - * - * The timer will then be reactivated and this function called - * again in the future. We need to exit gracefully in that case - * to allow the input subsystem to do its auto-repeat magic or - * a keyup event might follow immediately after the keydown. - */ - spin_lock_irqsave(&dev->keylock, flags); - if (time_is_before_eq_jiffies(dev->keyup_jiffies)) - ir_do_keyup(dev); - spin_unlock_irqrestore(&dev->keylock, flags); -} - -/** - * rc_repeat() - signals that a key is still pressed - * @dev: the struct rc_dev descriptor of the device - * - * This routine is used by IR decoders when a repeat message which does - * not include the necessary bits to reproduce the scancode has been - * received. - */ -void rc_repeat(struct rc_dev *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->keylock, flags); - - input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); - - if (!dev->keypressed) - goto out; - - dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); - mod_timer(&dev->timer_keyup, dev->keyup_jiffies); - -out: - spin_unlock_irqrestore(&dev->keylock, flags); -} -EXPORT_SYMBOL_GPL(rc_repeat); - -/** - * ir_do_keydown() - internal function to process a keypress - * @dev: the struct rc_dev descriptor of the device - * @scancode: the scancode of the keypress - * @keycode: the keycode of the keypress - * @toggle: the toggle value of the keypress - * - * This function is used internally to register a keypress, it must be - * called with keylock held. - */ -static void ir_do_keydown(struct rc_dev *dev, int scancode, - u32 keycode, u8 toggle) -{ - input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); - - /* Repeat event? */ - if (dev->keypressed && - dev->last_scancode == scancode && - dev->last_toggle == toggle) - return; - - /* Release old keypress */ - ir_do_keyup(dev); - - dev->last_scancode = scancode; - dev->last_toggle = toggle; - dev->last_keycode = keycode; - - if (keycode == KEY_RESERVED) - return; - - /* Register a keypress */ - dev->keypressed = true; - IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n", - dev->input_name, keycode, scancode); - input_report_key(dev->input_dev, dev->last_keycode, 1); - input_sync(dev->input_dev); -} - -/** - * rc_keydown() - generates input event for a key press - * @dev: the struct rc_dev descriptor of the device - * @scancode: the scancode that we're seeking - * @toggle: the toggle value (protocol dependent, if the protocol doesn't - * support toggle values, this should be set to zero) - * - * This routine is used to signal that a key has been pressed on the - * remote control. - */ -void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle) -{ - unsigned long flags; - u32 keycode = rc_g_keycode_from_table(dev, scancode); - - spin_lock_irqsave(&dev->keylock, flags); - ir_do_keydown(dev, scancode, keycode, toggle); - - if (dev->keypressed) { - dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); - mod_timer(&dev->timer_keyup, dev->keyup_jiffies); - } - spin_unlock_irqrestore(&dev->keylock, flags); -} -EXPORT_SYMBOL_GPL(rc_keydown); - -/** - * rc_keydown_notimeout() - generates input event for a key press without - * an automatic keyup event at a later time - * @dev: the struct rc_dev descriptor of the device - * @scancode: the scancode that we're seeking - * @toggle: the toggle value (protocol dependent, if the protocol doesn't - * support toggle values, this should be set to zero) - * - * This routine is used to signal that a key has been pressed on the - * remote control. The driver must manually call rc_keyup() at a later stage. - */ -void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle) -{ - unsigned long flags; - u32 keycode = rc_g_keycode_from_table(dev, scancode); - - spin_lock_irqsave(&dev->keylock, flags); - ir_do_keydown(dev, scancode, keycode, toggle); - spin_unlock_irqrestore(&dev->keylock, flags); -} -EXPORT_SYMBOL_GPL(rc_keydown_notimeout); - -static int ir_open(struct input_dev *idev) -{ - struct rc_dev *rdev = input_get_drvdata(idev); - - return rdev->open(rdev); -} - -static void ir_close(struct input_dev *idev) -{ - struct rc_dev *rdev = input_get_drvdata(idev); - - rdev->close(rdev); -} - -/* class for /sys/class/rc */ -static char *ir_devnode(struct device *dev, mode_t *mode) -{ - return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev)); -} - -static struct class ir_input_class = { - .name = "rc", - .devnode = ir_devnode, -}; - -static struct { - u64 type; - char *name; -} proto_names[] = { - { RC_TYPE_UNKNOWN, "unknown" }, - { RC_TYPE_RC5, "rc-5" }, - { RC_TYPE_NEC, "nec" }, - { RC_TYPE_RC6, "rc-6" }, - { RC_TYPE_JVC, "jvc" }, - { RC_TYPE_SONY, "sony" }, - { RC_TYPE_RC5_SZ, "rc-5-sz" }, - { RC_TYPE_LIRC, "lirc" }, -}; - -#define PROTO_NONE "none" - -/** - * show_protocols() - shows the current IR protocol(s) - * @device: the device descriptor - * @mattr: the device attribute struct (unused) - * @buf: a pointer to the output buffer - * - * This routine is a callback routine for input read the IR protocol type(s). - * it is trigged by reading /sys/class/rc/rc?/protocols. - * It returns the protocol names of supported protocols. - * Enabled protocols are printed in brackets. - */ -static ssize_t show_protocols(struct device *device, - struct device_attribute *mattr, char *buf) -{ - struct rc_dev *dev = to_rc_dev(device); - u64 allowed, enabled; - char *tmp = buf; - int i; - - /* Device is being removed */ - if (!dev) - return -EINVAL; - - if (dev->driver_type == RC_DRIVER_SCANCODE) { - enabled = dev->rc_map.rc_type; - allowed = dev->allowed_protos; - } else { - enabled = dev->raw->enabled_protocols; - allowed = ir_raw_get_allowed_protocols(); - } - - IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", - (long long)allowed, - (long long)enabled); - - for (i = 0; i < ARRAY_SIZE(proto_names); i++) { - if (allowed & enabled & proto_names[i].type) - tmp += sprintf(tmp, "[%s] ", proto_names[i].name); - else if (allowed & proto_names[i].type) - tmp += sprintf(tmp, "%s ", proto_names[i].name); - } - - if (tmp != buf) - tmp--; - *tmp = '\n'; - return tmp + 1 - buf; -} - -/** - * store_protocols() - changes the current IR protocol(s) - * @device: the device descriptor - * @mattr: the device attribute struct (unused) - * @buf: a pointer to the input buffer - * @len: length of the input buffer - * - * This routine is for changing the IR protocol type. - * It is trigged by writing to /sys/class/rc/rc?/protocols. - * Writing "+proto" will add a protocol to the list of enabled protocols. - * Writing "-proto" will remove a protocol from the list of enabled protocols. - * Writing "proto" will enable only "proto". - * Writing "none" will disable all protocols. - * Returns -EINVAL if an invalid protocol combination or unknown protocol name - * is used, otherwise @len. - */ -static ssize_t store_protocols(struct device *device, - struct device_attribute *mattr, - const char *data, - size_t len) -{ - struct rc_dev *dev = to_rc_dev(device); - bool enable, disable; - const char *tmp; - u64 type; - u64 mask; - int rc, i, count = 0; - unsigned long flags; - - /* Device is being removed */ - if (!dev) - return -EINVAL; - - if (dev->driver_type == RC_DRIVER_SCANCODE) - type = dev->rc_map.rc_type; - else if (dev->raw) - type = dev->raw->enabled_protocols; - else { - IR_dprintk(1, "Protocol switching not supported\n"); - return -EINVAL; - } - - while ((tmp = strsep((char **) &data, " \n")) != NULL) { - if (!*tmp) - break; - - if (*tmp == '+') { - enable = true; - disable = false; - tmp++; - } else if (*tmp == '-') { - enable = false; - disable = true; - tmp++; - } else { - enable = false; - disable = false; - } - - if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) { - tmp += sizeof(PROTO_NONE); - mask = 0; - count++; - } else { - for (i = 0; i < ARRAY_SIZE(proto_names); i++) { - if (!strcasecmp(tmp, proto_names[i].name)) { - tmp += strlen(proto_names[i].name); - mask = proto_names[i].type; - break; - } - } - if (i == ARRAY_SIZE(proto_names)) { - IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); - return -EINVAL; - } - count++; - } - - if (enable) - type |= mask; - else if (disable) - type &= ~mask; - else - type = mask; - } - - if (!count) { - IR_dprintk(1, "Protocol not specified\n"); - return -EINVAL; - } - - if (dev->change_protocol) { - rc = dev->change_protocol(dev, type); - if (rc < 0) { - IR_dprintk(1, "Error setting protocols to 0x%llx\n", - (long long)type); - return -EINVAL; - } - } - - if (dev->driver_type == RC_DRIVER_SCANCODE) { - spin_lock_irqsave(&dev->rc_map.lock, flags); - dev->rc_map.rc_type = type; - spin_unlock_irqrestore(&dev->rc_map.lock, flags); - } else { - dev->raw->enabled_protocols = type; - } - - IR_dprintk(1, "Current protocol(s): 0x%llx\n", - (long long)type); - - return len; -} - -static void rc_dev_release(struct device *device) -{ - struct rc_dev *dev = to_rc_dev(device); - - kfree(dev); - module_put(THIS_MODULE); -} - -#define ADD_HOTPLUG_VAR(fmt, val...) \ - do { \ - int err = add_uevent_var(env, fmt, val); \ - if (err) \ - return err; \ - } while (0) - -static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) -{ - struct rc_dev *dev = to_rc_dev(device); - - if (dev->rc_map.name) - ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); - if (dev->driver_name) - ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name); - - return 0; -} - -/* - * Static device attribute struct with the sysfs attributes for IR's - */ -static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, - show_protocols, store_protocols); - -static struct attribute *rc_dev_attrs[] = { - &dev_attr_protocols.attr, - NULL, -}; - -static struct attribute_group rc_dev_attr_grp = { - .attrs = rc_dev_attrs, -}; - -static const struct attribute_group *rc_dev_attr_groups[] = { - &rc_dev_attr_grp, - NULL -}; - -static struct device_type rc_dev_type = { - .groups = rc_dev_attr_groups, - .release = rc_dev_release, - .uevent = rc_dev_uevent, -}; - -struct rc_dev *rc_allocate_device(void) -{ - struct rc_dev *dev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - - dev->input_dev = input_allocate_device(); - if (!dev->input_dev) { - kfree(dev); - return NULL; - } - - dev->input_dev->getkeycode_new = ir_getkeycode; - dev->input_dev->setkeycode_new = ir_setkeycode; - input_set_drvdata(dev->input_dev, dev); - - spin_lock_init(&dev->rc_map.lock); - spin_lock_init(&dev->keylock); - setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev); - - dev->dev.type = &rc_dev_type; - dev->dev.class = &ir_input_class; - device_initialize(&dev->dev); - - __module_get(THIS_MODULE); - return dev; -} -EXPORT_SYMBOL_GPL(rc_allocate_device); - -void rc_free_device(struct rc_dev *dev) -{ - if (dev) { - input_free_device(dev->input_dev); - put_device(&dev->dev); - } -} -EXPORT_SYMBOL_GPL(rc_free_device); - -int rc_register_device(struct rc_dev *dev) -{ - static atomic_t devno = ATOMIC_INIT(0); - struct rc_map *rc_map; - const char *path; - int rc; - - if (!dev || !dev->map_name) - return -EINVAL; - - rc_map = rc_map_get(dev->map_name); - if (!rc_map) - rc_map = rc_map_get(RC_MAP_EMPTY); - if (!rc_map || !rc_map->scan || rc_map->size == 0) - return -EINVAL; - - set_bit(EV_KEY, dev->input_dev->evbit); - set_bit(EV_REP, dev->input_dev->evbit); - set_bit(EV_MSC, dev->input_dev->evbit); - set_bit(MSC_SCAN, dev->input_dev->mscbit); - if (dev->open) - dev->input_dev->open = ir_open; - if (dev->close) - dev->input_dev->close = ir_close; - - dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1); - dev_set_name(&dev->dev, "rc%ld", dev->devno); - dev_set_drvdata(&dev->dev, dev); - rc = device_add(&dev->dev); - if (rc) - return rc; - - rc = ir_setkeytable(dev, rc_map); - if (rc) - goto out_dev; - - dev->input_dev->dev.parent = &dev->dev; - memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id)); - dev->input_dev->phys = dev->input_phys; - dev->input_dev->name = dev->input_name; - rc = input_register_device(dev->input_dev); - if (rc) - goto out_table; - - /* - * Default delay of 250ms is too short for some protocols, expecially - * since the timeout is currently set to 250ms. Increase it to 500ms, - * to avoid wrong repetition of the keycodes. Note that this must be - * set after the call to input_register_device(). - */ - dev->input_dev->rep[REP_DELAY] = 500; - - path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); - printk(KERN_INFO "%s: %s as %s\n", - dev_name(&dev->dev), - dev->input_name ? dev->input_name : "Unspecified device", - path ? path : "N/A"); - kfree(path); - - if (dev->driver_type == RC_DRIVER_IR_RAW) { - rc = ir_raw_event_register(dev); - if (rc < 0) - goto out_input; - } - - if (dev->change_protocol) { - rc = dev->change_protocol(dev, rc_map->rc_type); - if (rc < 0) - goto out_raw; - } - - IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n", - dev->devno, - dev->driver_name ? dev->driver_name : "unknown", - rc_map->name ? rc_map->name : "unknown", - dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked"); - - return 0; - -out_raw: - if (dev->driver_type == RC_DRIVER_IR_RAW) - ir_raw_event_unregister(dev); -out_input: - input_unregister_device(dev->input_dev); - dev->input_dev = NULL; -out_table: - ir_free_table(&dev->rc_map); -out_dev: - device_del(&dev->dev); - return rc; -} -EXPORT_SYMBOL_GPL(rc_register_device); - -void rc_unregister_device(struct rc_dev *dev) -{ - if (!dev) - return; - - del_timer_sync(&dev->timer_keyup); - - if (dev->driver_type == RC_DRIVER_IR_RAW) - ir_raw_event_unregister(dev); - - input_unregister_device(dev->input_dev); - dev->input_dev = NULL; - - ir_free_table(&dev->rc_map); - IR_dprintk(1, "Freed keycode table\n"); - - device_unregister(&dev->dev); -} -EXPORT_SYMBOL_GPL(rc_unregister_device); - -/* - * Init/exit code for the module. Basically, creates/removes /sys/class/rc - */ - -static int __init rc_core_init(void) -{ - int rc = class_register(&ir_input_class); - if (rc) { - printk(KERN_ERR "rc_core: unable to register rc class\n"); - return rc; - } - - /* Initialize/load the decoders/keymap code that will be used */ - ir_raw_init(); - rc_map_register(&empty_map); - - return 0; -} - -static void __exit rc_core_exit(void) -{ - class_unregister(&ir_input_class); - rc_map_unregister(&empty_map); -} - -module_init(rc_core_init); -module_exit(rc_core_exit); - -int rc_core_debug; /* ir_debug level (0,1,2) */ -EXPORT_SYMBOL_GPL(rc_core_debug); -module_param_named(debug, rc_core_debug, int, 0644); - -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/streamzap.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/streamzap.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/streamzap.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/streamzap.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,559 +0,0 @@ -/* - * Streamzap Remote Control driver - * - * Copyright (c) 2005 Christoph Bartelmus - * Copyright (c) 2010 Jarod Wilson - * - * This driver was based on the work of Greg Wickham and Adrian - * Dewhurst. It was substantially rewritten to support correct signal - * gaps and now maintains a delay buffer, which is used to present - * consistent timing behaviour to user space applications. Without the - * delay buffer an ugly hack would be required in lircd, which can - * cause sluggish signal decoding in certain situations. - * - * Ported to in-kernel ir-core interface by Jarod Wilson - * - * This driver is based on the USB skeleton driver packaged with the - * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include - -#define DRIVER_VERSION "1.61" -#define DRIVER_NAME "streamzap" -#define DRIVER_DESC "Streamzap Remote Control driver" - -#ifdef CONFIG_USB_DEBUG -static int debug = 1; -#else -static int debug; -#endif - -#define USB_STREAMZAP_VENDOR_ID 0x0e9c -#define USB_STREAMZAP_PRODUCT_ID 0x0000 - -/* table of devices that work with this driver */ -static struct usb_device_id streamzap_table[] = { - /* Streamzap Remote Control */ - { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) }, - /* Terminating entry */ - { } -}; - -MODULE_DEVICE_TABLE(usb, streamzap_table); - -#define SZ_PULSE_MASK 0xf0 -#define SZ_SPACE_MASK 0x0f -#define SZ_TIMEOUT 0xff -#define SZ_RESOLUTION 256 - -/* number of samples buffered */ -#define SZ_BUF_LEN 128 - -/* from ir-rc5-sz-decoder.c */ -#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE -#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder") -#else -#define load_rc5_sz_decode() {} -#endif - -enum StreamzapDecoderState { - PulseSpace, - FullPulse, - FullSpace, - IgnorePulse -}; - -/* structure to hold our device specific stuff */ -struct streamzap_ir { - /* ir-core */ - struct rc_dev *rdev; - - /* core device info */ - struct device *dev; - - /* usb */ - struct usb_device *usbdev; - struct usb_interface *interface; - struct usb_endpoint_descriptor *endpoint; - struct urb *urb_in; - - /* buffer & dma */ - unsigned char *buf_in; - dma_addr_t dma_in; - unsigned int buf_in_len; - - /* track what state we're in */ - enum StreamzapDecoderState decoder_state; - /* tracks whether we are currently receiving some signal */ - bool idle; - /* sum of signal lengths received since signal start */ - unsigned long sum; - /* start time of signal; necessary for gap tracking */ - struct timeval signal_last; - struct timeval signal_start; - bool timeout_enabled; - - char name[128]; - char phys[64]; -}; - - -/* local function prototypes */ -static int streamzap_probe(struct usb_interface *interface, - const struct usb_device_id *id); -static void streamzap_disconnect(struct usb_interface *interface); -static void streamzap_callback(struct urb *urb); -static int streamzap_suspend(struct usb_interface *intf, pm_message_t message); -static int streamzap_resume(struct usb_interface *intf); - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver streamzap_driver = { - .name = DRIVER_NAME, - .probe = streamzap_probe, - .disconnect = streamzap_disconnect, - .suspend = streamzap_suspend, - .resume = streamzap_resume, - .id_table = streamzap_table, -}; - -static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir) -{ - dev_dbg(sz->dev, "Storing %s with duration %u us\n", - (rawir.pulse ? "pulse" : "space"), rawir.duration); - ir_raw_event_store_with_filter(sz->rdev, &rawir); -} - -static void sz_push_full_pulse(struct streamzap_ir *sz, - unsigned char value) -{ - DEFINE_IR_RAW_EVENT(rawir); - - if (sz->idle) { - long deltv; - - sz->signal_last = sz->signal_start; - do_gettimeofday(&sz->signal_start); - - deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec; - rawir.pulse = false; - if (deltv > 15) { - /* really long time */ - rawir.duration = IR_MAX_DURATION; - } else { - rawir.duration = (int)(deltv * 1000000 + - sz->signal_start.tv_usec - - sz->signal_last.tv_usec); - rawir.duration -= sz->sum; - rawir.duration = US_TO_NS(rawir.duration); - rawir.duration &= IR_MAX_DURATION; - } - sz_push(sz, rawir); - - sz->idle = false; - sz->sum = 0; - } - - rawir.pulse = true; - rawir.duration = ((int) value) * SZ_RESOLUTION; - rawir.duration += SZ_RESOLUTION / 2; - sz->sum += rawir.duration; - rawir.duration = US_TO_NS(rawir.duration); - rawir.duration &= IR_MAX_DURATION; - sz_push(sz, rawir); -} - -static void sz_push_half_pulse(struct streamzap_ir *sz, - unsigned char value) -{ - sz_push_full_pulse(sz, (value & SZ_PULSE_MASK) >> 4); -} - -static void sz_push_full_space(struct streamzap_ir *sz, - unsigned char value) -{ - DEFINE_IR_RAW_EVENT(rawir); - - rawir.pulse = false; - rawir.duration = ((int) value) * SZ_RESOLUTION; - rawir.duration += SZ_RESOLUTION / 2; - sz->sum += rawir.duration; - rawir.duration = US_TO_NS(rawir.duration); - sz_push(sz, rawir); -} - -static void sz_push_half_space(struct streamzap_ir *sz, - unsigned long value) -{ - sz_push_full_space(sz, value & SZ_SPACE_MASK); -} - -/** - * streamzap_callback - usb IRQ handler callback - * - * This procedure is invoked on reception of data from - * the usb remote. - */ -static void streamzap_callback(struct urb *urb) -{ - struct streamzap_ir *sz; - unsigned int i; - int len; - - if (!urb) - return; - - sz = urb->context; - len = urb->actual_length; - - switch (urb->status) { - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* - * this urb is terminated, clean up. - * sz might already be invalid at this point - */ - dev_err(sz->dev, "urb terminated, status: %d\n", urb->status); - return; - default: - break; - } - - dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); - for (i = 0; i < len; i++) { - dev_dbg(sz->dev, "sz->buf_in[%d]: %x\n", - i, (unsigned char)sz->buf_in[i]); - switch (sz->decoder_state) { - case PulseSpace: - if ((sz->buf_in[i] & SZ_PULSE_MASK) == - SZ_PULSE_MASK) { - sz->decoder_state = FullPulse; - continue; - } else if ((sz->buf_in[i] & SZ_SPACE_MASK) - == SZ_SPACE_MASK) { - sz_push_half_pulse(sz, sz->buf_in[i]); - sz->decoder_state = FullSpace; - continue; - } else { - sz_push_half_pulse(sz, sz->buf_in[i]); - sz_push_half_space(sz, sz->buf_in[i]); - } - break; - case FullPulse: - sz_push_full_pulse(sz, sz->buf_in[i]); - sz->decoder_state = IgnorePulse; - break; - case FullSpace: - if (sz->buf_in[i] == SZ_TIMEOUT) { - DEFINE_IR_RAW_EVENT(rawir); - - rawir.pulse = false; - rawir.duration = sz->rdev->timeout; - sz->idle = true; - if (sz->timeout_enabled) - sz_push(sz, rawir); - ir_raw_event_handle(sz->rdev); - ir_raw_event_reset(sz->rdev); - } else { - sz_push_full_space(sz, sz->buf_in[i]); - } - sz->decoder_state = PulseSpace; - break; - case IgnorePulse: - if ((sz->buf_in[i] & SZ_SPACE_MASK) == - SZ_SPACE_MASK) { - sz->decoder_state = FullSpace; - continue; - } - sz_push_half_space(sz, sz->buf_in[i]); - sz->decoder_state = PulseSpace; - break; - } - } - - ir_raw_event_handle(sz->rdev); - usb_submit_urb(urb, GFP_ATOMIC); - - return; -} - -static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) -{ - struct rc_dev *rdev; - struct device *dev = sz->dev; - int ret; - - rdev = rc_allocate_device(); - if (!rdev) { - dev_err(dev, "remote dev allocation failed\n"); - goto out; - } - - snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared " - "Receiver (%04x:%04x)", - le16_to_cpu(sz->usbdev->descriptor.idVendor), - le16_to_cpu(sz->usbdev->descriptor.idProduct)); - usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys)); - strlcat(sz->phys, "/input0", sizeof(sz->phys)); - - rdev->input_name = sz->name; - rdev->input_phys = sz->phys; - usb_to_input_id(sz->usbdev, &rdev->input_id); - rdev->dev.parent = dev; - rdev->priv = sz; - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; - rdev->driver_name = DRIVER_NAME; - rdev->map_name = RC_MAP_STREAMZAP; - - ret = rc_register_device(rdev); - if (ret < 0) { - dev_err(dev, "remote input device register failed\n"); - goto out; - } - - return rdev; - -out: - rc_free_device(rdev); - return NULL; -} - -/** - * streamzap_probe - * - * Called by usb-core to associated with a candidate device - * On any failure the return value is the ERROR - * On success return 0 - */ -static int __devinit streamzap_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usbdev = interface_to_usbdev(intf); - struct usb_host_interface *iface_host; - struct streamzap_ir *sz = NULL; - char buf[63], name[128] = ""; - int retval = -ENOMEM; - int pipe, maxp; - - /* Allocate space for device driver specific data */ - sz = kzalloc(sizeof(struct streamzap_ir), GFP_KERNEL); - if (!sz) - return -ENOMEM; - - sz->usbdev = usbdev; - sz->interface = intf; - - /* Check to ensure endpoint information matches requirements */ - iface_host = intf->cur_altsetting; - - if (iface_host->desc.bNumEndpoints != 1) { - dev_err(&intf->dev, "%s: Unexpected desc.bNumEndpoints (%d)\n", - __func__, iface_host->desc.bNumEndpoints); - retval = -ENODEV; - goto free_sz; - } - - sz->endpoint = &(iface_host->endpoint[0].desc); - if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - != USB_DIR_IN) { - dev_err(&intf->dev, "%s: endpoint doesn't match input device " - "02%02x\n", __func__, sz->endpoint->bEndpointAddress); - retval = -ENODEV; - goto free_sz; - } - - if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) { - dev_err(&intf->dev, "%s: endpoint attributes don't match xfer " - "02%02x\n", __func__, sz->endpoint->bmAttributes); - retval = -ENODEV; - goto free_sz; - } - - pipe = usb_rcvintpipe(usbdev, sz->endpoint->bEndpointAddress); - maxp = usb_maxpacket(usbdev, pipe, usb_pipeout(pipe)); - - if (maxp == 0) { - dev_err(&intf->dev, "%s: endpoint Max Packet Size is 0!?!\n", - __func__); - retval = -ENODEV; - goto free_sz; - } - - /* Allocate the USB buffer and IRQ URB */ - sz->buf_in = usb_alloc_coherent(usbdev, maxp, GFP_ATOMIC, &sz->dma_in); - if (!sz->buf_in) - goto free_sz; - - sz->urb_in = usb_alloc_urb(0, GFP_KERNEL); - if (!sz->urb_in) - goto free_buf_in; - - sz->dev = &intf->dev; - sz->buf_in_len = maxp; - - if (usbdev->descriptor.iManufacturer - && usb_string(usbdev, usbdev->descriptor.iManufacturer, - buf, sizeof(buf)) > 0) - strlcpy(name, buf, sizeof(name)); - - if (usbdev->descriptor.iProduct - && usb_string(usbdev, usbdev->descriptor.iProduct, - buf, sizeof(buf)) > 0) - snprintf(name + strlen(name), sizeof(name) - strlen(name), - " %s", buf); - - sz->rdev = streamzap_init_rc_dev(sz); - if (!sz->rdev) - goto rc_dev_fail; - - sz->idle = true; - sz->decoder_state = PulseSpace; - /* FIXME: don't yet have a way to set this */ - sz->timeout_enabled = true; - sz->rdev->timeout = ((US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION) & - IR_MAX_DURATION) | 0x03000000); - #if 0 - /* not yet supported, depends on patches from maxim */ - /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */ - sz->min_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION); - sz->max_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION); - #endif - - do_gettimeofday(&sz->signal_start); - - /* Complete final initialisations */ - usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in, - maxp, (usb_complete_t)streamzap_callback, - sz, sz->endpoint->bInterval); - sz->urb_in->transfer_dma = sz->dma_in; - sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - usb_set_intfdata(intf, sz); - - if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) - dev_err(sz->dev, "urb submit failed\n"); - - dev_info(sz->dev, "Registered %s on usb%d:%d\n", name, - usbdev->bus->busnum, usbdev->devnum); - - /* Load the streamzap not-quite-rc5 decoder too */ - load_rc5_sz_decode(); - - return 0; - -rc_dev_fail: - usb_free_urb(sz->urb_in); -free_buf_in: - usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in); -free_sz: - kfree(sz); - - return retval; -} - -/** - * streamzap_disconnect - * - * Called by the usb core when the device is removed from the system. - * - * This routine guarantees that the driver will not submit any more urbs - * by clearing dev->usbdev. It is also supposed to terminate any currently - * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(), - * does not provide any way to do this. - */ -static void streamzap_disconnect(struct usb_interface *interface) -{ - struct streamzap_ir *sz = usb_get_intfdata(interface); - struct usb_device *usbdev = interface_to_usbdev(interface); - - usb_set_intfdata(interface, NULL); - - if (!sz) - return; - - sz->usbdev = NULL; - rc_unregister_device(sz->rdev); - usb_kill_urb(sz->urb_in); - usb_free_urb(sz->urb_in); - usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in); - - kfree(sz); -} - -static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct streamzap_ir *sz = usb_get_intfdata(intf); - - usb_kill_urb(sz->urb_in); - - return 0; -} - -static int streamzap_resume(struct usb_interface *intf) -{ - struct streamzap_ir *sz = usb_get_intfdata(intf); - - if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { - dev_err(sz->dev, "Error sumbiting urb\n"); - return -EIO; - } - - return 0; -} - -/** - * streamzap_init - */ -static int __init streamzap_init(void) -{ - int ret; - - /* register this driver with the USB subsystem */ - ret = usb_register(&streamzap_driver); - if (ret < 0) - printk(KERN_ERR DRIVER_NAME ": usb register failed, " - "result = %d\n", ret); - - return ret; -} - -/** - * streamzap_exit - */ -static void __exit streamzap_exit(void) -{ - usb_deregister(&streamzap_driver); -} - - -module_init(streamzap_init); -module_exit(streamzap_exit); - -MODULE_AUTHOR("Jarod Wilson "); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/winbond-cir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/winbond-cir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/winbond-cir.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/rc/winbond-cir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,932 +0,0 @@ -/* - * winbond-cir.c - Driver for the Consumer IR functionality of Winbond - * SuperI/O chips. - * - * Currently supports the Winbond WPCD376i chip (PNP id WEC1022), but - * could probably support others (Winbond WEC102X, NatSemi, etc) - * with minor modifications. - * - * Original Author: David Härdeman - * Copyright (C) 2009 - 2010 David Härdeman - * - * Dedicated to my daughter Matilda, without whose loving attention this - * driver would have been finished in half the time and with a fraction - * of the bugs. - * - * Written using: - * o Winbond WPCD376I datasheet helpfully provided by Jesse Barnes at Intel - * o NatSemi PC87338/PC97338 datasheet (for the serial port stuff) - * o DSDT dumps - * - * Supported features: - * o Wake-On-CIR functionality - * - * To do: - * o Learning - * o IR Transmit - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRVNAME "winbond-cir" - -/* CEIR Wake-Up Registers, relative to data->wbase */ -#define WBCIR_REG_WCEIR_CTL 0x03 /* CEIR Receiver Control */ -#define WBCIR_REG_WCEIR_STS 0x04 /* CEIR Receiver Status */ -#define WBCIR_REG_WCEIR_EV_EN 0x05 /* CEIR Receiver Event Enable */ -#define WBCIR_REG_WCEIR_CNTL 0x06 /* CEIR Receiver Counter Low */ -#define WBCIR_REG_WCEIR_CNTH 0x07 /* CEIR Receiver Counter High */ -#define WBCIR_REG_WCEIR_INDEX 0x08 /* CEIR Receiver Index */ -#define WBCIR_REG_WCEIR_DATA 0x09 /* CEIR Receiver Data */ -#define WBCIR_REG_WCEIR_CSL 0x0A /* CEIR Re. Compare Strlen */ -#define WBCIR_REG_WCEIR_CFG1 0x0B /* CEIR Re. Configuration 1 */ -#define WBCIR_REG_WCEIR_CFG2 0x0C /* CEIR Re. Configuration 2 */ - -/* CEIR Enhanced Functionality Registers, relative to data->ebase */ -#define WBCIR_REG_ECEIR_CTS 0x00 /* Enhanced IR Control Status */ -#define WBCIR_REG_ECEIR_CCTL 0x01 /* Infrared Counter Control */ -#define WBCIR_REG_ECEIR_CNT_LO 0x02 /* Infrared Counter LSB */ -#define WBCIR_REG_ECEIR_CNT_HI 0x03 /* Infrared Counter MSB */ -#define WBCIR_REG_ECEIR_IREM 0x04 /* Infrared Emitter Status */ - -/* SP3 Banked Registers, relative to data->sbase */ -#define WBCIR_REG_SP3_BSR 0x03 /* Bank Select, all banks */ - /* Bank 0 */ -#define WBCIR_REG_SP3_RXDATA 0x00 /* FIFO RX data (r) */ -#define WBCIR_REG_SP3_TXDATA 0x00 /* FIFO TX data (w) */ -#define WBCIR_REG_SP3_IER 0x01 /* Interrupt Enable */ -#define WBCIR_REG_SP3_EIR 0x02 /* Event Identification (r) */ -#define WBCIR_REG_SP3_FCR 0x02 /* FIFO Control (w) */ -#define WBCIR_REG_SP3_MCR 0x04 /* Mode Control */ -#define WBCIR_REG_SP3_LSR 0x05 /* Link Status */ -#define WBCIR_REG_SP3_MSR 0x06 /* Modem Status */ -#define WBCIR_REG_SP3_ASCR 0x07 /* Aux Status and Control */ - /* Bank 2 */ -#define WBCIR_REG_SP3_BGDL 0x00 /* Baud Divisor LSB */ -#define WBCIR_REG_SP3_BGDH 0x01 /* Baud Divisor MSB */ -#define WBCIR_REG_SP3_EXCR1 0x02 /* Extended Control 1 */ -#define WBCIR_REG_SP3_EXCR2 0x04 /* Extended Control 2 */ -#define WBCIR_REG_SP3_TXFLV 0x06 /* TX FIFO Level */ -#define WBCIR_REG_SP3_RXFLV 0x07 /* RX FIFO Level */ - /* Bank 3 */ -#define WBCIR_REG_SP3_MRID 0x00 /* Module Identification */ -#define WBCIR_REG_SP3_SH_LCR 0x01 /* LCR Shadow */ -#define WBCIR_REG_SP3_SH_FCR 0x02 /* FCR Shadow */ - /* Bank 4 */ -#define WBCIR_REG_SP3_IRCR1 0x02 /* Infrared Control 1 */ - /* Bank 5 */ -#define WBCIR_REG_SP3_IRCR2 0x04 /* Infrared Control 2 */ - /* Bank 6 */ -#define WBCIR_REG_SP3_IRCR3 0x00 /* Infrared Control 3 */ -#define WBCIR_REG_SP3_SIR_PW 0x02 /* SIR Pulse Width */ - /* Bank 7 */ -#define WBCIR_REG_SP3_IRRXDC 0x00 /* IR RX Demod Control */ -#define WBCIR_REG_SP3_IRTXMC 0x01 /* IR TX Mod Control */ -#define WBCIR_REG_SP3_RCCFG 0x02 /* CEIR Config */ -#define WBCIR_REG_SP3_IRCFG1 0x04 /* Infrared Config 1 */ -#define WBCIR_REG_SP3_IRCFG4 0x07 /* Infrared Config 4 */ - -/* - * Magic values follow - */ - -/* No interrupts for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ -#define WBCIR_IRQ_NONE 0x00 -/* RX data bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ -#define WBCIR_IRQ_RX 0x01 -/* Over/Under-flow bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ -#define WBCIR_IRQ_ERR 0x04 -/* Led enable/disable bit for WBCIR_REG_ECEIR_CTS */ -#define WBCIR_LED_ENABLE 0x80 -/* RX data available bit for WBCIR_REG_SP3_LSR */ -#define WBCIR_RX_AVAIL 0x01 -/* RX disable bit for WBCIR_REG_SP3_ASCR */ -#define WBCIR_RX_DISABLE 0x20 -/* Extended mode enable bit for WBCIR_REG_SP3_EXCR1 */ -#define WBCIR_EXT_ENABLE 0x01 -/* Select compare register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */ -#define WBCIR_REGSEL_COMPARE 0x10 -/* Select mask register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */ -#define WBCIR_REGSEL_MASK 0x20 -/* Starting address of selected register in WBCIR_REG_WCEIR_INDEX */ -#define WBCIR_REG_ADDR0 0x00 - -/* Valid banks for the SP3 UART */ -enum wbcir_bank { - WBCIR_BANK_0 = 0x00, - WBCIR_BANK_1 = 0x80, - WBCIR_BANK_2 = 0xE0, - WBCIR_BANK_3 = 0xE4, - WBCIR_BANK_4 = 0xE8, - WBCIR_BANK_5 = 0xEC, - WBCIR_BANK_6 = 0xF0, - WBCIR_BANK_7 = 0xF4, -}; - -/* Supported power-on IR Protocols */ -enum wbcir_protocol { - IR_PROTOCOL_RC5 = 0x0, - IR_PROTOCOL_NEC = 0x1, - IR_PROTOCOL_RC6 = 0x2, -}; - -/* Misc */ -#define WBCIR_NAME "Winbond CIR" -#define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */ -#define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */ -#define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */ -#define WAKEUP_IOMEM_LEN 0x10 /* Wake-Up I/O Reg Len */ -#define EHFUNC_IOMEM_LEN 0x10 /* Enhanced Func I/O Reg Len */ -#define SP_IOMEM_LEN 0x08 /* Serial Port 3 (IR) Reg Len */ - -/* Per-device data */ -struct wbcir_data { - spinlock_t spinlock; - - unsigned long wbase; /* Wake-Up Baseaddr */ - unsigned long ebase; /* Enhanced Func. Baseaddr */ - unsigned long sbase; /* Serial Port Baseaddr */ - unsigned int irq; /* Serial Port IRQ */ - - struct rc_dev *dev; - - struct led_trigger *rxtrigger; - struct led_trigger *txtrigger; - struct led_classdev led; - - /* RX irdata state */ - bool irdata_active; - bool irdata_error; - struct ir_raw_event ev; -}; - -static enum wbcir_protocol protocol = IR_PROTOCOL_RC6; -module_param(protocol, uint, 0444); -MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command " - "(0 = RC5, 1 = NEC, 2 = RC6A, default)"); - -static int invert; /* default = 0 */ -module_param(invert, bool, 0444); -MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver"); - -static unsigned int wake_sc = 0x800F040C; -module_param(wake_sc, uint, 0644); -MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command"); - -static unsigned int wake_rc6mode = 6; -module_param(wake_rc6mode, uint, 0644); -MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command " - "(0 = 0, 6 = 6A, default)"); - - - -/***************************************************************************** - * - * UTILITY FUNCTIONS - * - *****************************************************************************/ - -/* Caller needs to hold wbcir_lock */ -static void -wbcir_set_bits(unsigned long addr, u8 bits, u8 mask) -{ - u8 val; - - val = inb(addr); - val = ((val & ~mask) | (bits & mask)); - outb(val, addr); -} - -/* Selects the register bank for the serial port */ -static inline void -wbcir_select_bank(struct wbcir_data *data, enum wbcir_bank bank) -{ - outb(bank, data->sbase + WBCIR_REG_SP3_BSR); -} - -static enum led_brightness -wbcir_led_brightness_get(struct led_classdev *led_cdev) -{ - struct wbcir_data *data = container_of(led_cdev, - struct wbcir_data, - led); - - if (inb(data->ebase + WBCIR_REG_ECEIR_CTS) & WBCIR_LED_ENABLE) - return LED_FULL; - else - return LED_OFF; -} - -static void -wbcir_led_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct wbcir_data *data = container_of(led_cdev, - struct wbcir_data, - led); - - wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CTS, - brightness == LED_OFF ? 0x00 : WBCIR_LED_ENABLE, - WBCIR_LED_ENABLE); -} - -/* Manchester encodes bits to RC6 message cells (see wbcir_shutdown) */ -static u8 -wbcir_to_rc6cells(u8 val) -{ - u8 coded = 0x00; - int i; - - val &= 0x0F; - for (i = 0; i < 4; i++) { - if (val & 0x01) - coded |= 0x02 << (i * 2); - else - coded |= 0x01 << (i * 2); - val >>= 1; - } - - return coded; -} - -/***************************************************************************** - * - * INTERRUPT FUNCTIONS - * - *****************************************************************************/ - -static irqreturn_t -wbcir_irq_handler(int irqno, void *cookie) -{ - struct pnp_dev *device = cookie; - struct wbcir_data *data = pnp_get_drvdata(device); - unsigned long flags; - u8 irdata[8]; - u8 disable = true; - u8 status; - int i; - - spin_lock_irqsave(&data->spinlock, flags); - - wbcir_select_bank(data, WBCIR_BANK_0); - - status = inb(data->sbase + WBCIR_REG_SP3_EIR); - - if (!(status & (WBCIR_IRQ_RX | WBCIR_IRQ_ERR))) { - spin_unlock_irqrestore(&data->spinlock, flags); - return IRQ_NONE; - } - - /* Check for e.g. buffer overflow */ - if (status & WBCIR_IRQ_ERR) { - data->irdata_error = true; - ir_raw_event_reset(data->dev); - } - - if (!(status & WBCIR_IRQ_RX)) - goto out; - - if (!data->irdata_active) { - data->irdata_active = true; - led_trigger_event(data->rxtrigger, LED_FULL); - } - - /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */ - insb(data->sbase + WBCIR_REG_SP3_RXDATA, &irdata[0], 8); - - for (i = 0; i < 8; i++) { - u8 pulse; - u32 duration; - - if (irdata[i] != 0xFF && irdata[i] != 0x00) - disable = false; - - if (data->irdata_error) - continue; - - pulse = irdata[i] & 0x80 ? false : true; - duration = (irdata[i] & 0x7F) * 10000; /* ns */ - - if (data->ev.pulse != pulse) { - if (data->ev.duration != 0) { - ir_raw_event_store(data->dev, &data->ev); - data->ev.duration = 0; - } - - data->ev.pulse = pulse; - } - - data->ev.duration += duration; - } - - if (disable) { - if (data->ev.duration != 0 && !data->irdata_error) { - ir_raw_event_store(data->dev, &data->ev); - data->ev.duration = 0; - } - - /* Set RXINACTIVE */ - outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR); - - /* Drain the FIFO */ - while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) - inb(data->sbase + WBCIR_REG_SP3_RXDATA); - - ir_raw_event_reset(data->dev); - data->irdata_error = false; - data->irdata_active = false; - led_trigger_event(data->rxtrigger, LED_OFF); - } - - ir_raw_event_handle(data->dev); - -out: - spin_unlock_irqrestore(&data->spinlock, flags); - return IRQ_HANDLED; -} - - - -/***************************************************************************** - * - * SETUP/INIT/SUSPEND/RESUME FUNCTIONS - * - *****************************************************************************/ - -static void -wbcir_shutdown(struct pnp_dev *device) -{ - struct device *dev = &device->dev; - struct wbcir_data *data = pnp_get_drvdata(device); - int do_wake = 1; - u8 match[11]; - u8 mask[11]; - u8 rc6_csl = 0; - int i; - - memset(match, 0, sizeof(match)); - memset(mask, 0, sizeof(mask)); - - if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) { - do_wake = 0; - goto finish; - } - - switch (protocol) { - case IR_PROTOCOL_RC5: - if (wake_sc > 0xFFF) { - do_wake = 0; - dev_err(dev, "RC5 - Invalid wake scancode\n"); - break; - } - - /* Mask = 13 bits, ex toggle */ - mask[0] = 0xFF; - mask[1] = 0x17; - - match[0] = (wake_sc & 0x003F); /* 6 command bits */ - match[0] |= (wake_sc & 0x0180) >> 1; /* 2 address bits */ - match[1] = (wake_sc & 0x0E00) >> 9; /* 3 address bits */ - if (!(wake_sc & 0x0040)) /* 2nd start bit */ - match[1] |= 0x10; - - break; - - case IR_PROTOCOL_NEC: - if (wake_sc > 0xFFFFFF) { - do_wake = 0; - dev_err(dev, "NEC - Invalid wake scancode\n"); - break; - } - - mask[0] = mask[1] = mask[2] = mask[3] = 0xFF; - - match[1] = bitrev8((wake_sc & 0xFF)); - match[0] = ~match[1]; - - match[3] = bitrev8((wake_sc & 0xFF00) >> 8); - if (wake_sc > 0xFFFF) - match[2] = bitrev8((wake_sc & 0xFF0000) >> 16); - else - match[2] = ~match[3]; - - break; - - case IR_PROTOCOL_RC6: - - if (wake_rc6mode == 0) { - if (wake_sc > 0xFFFF) { - do_wake = 0; - dev_err(dev, "RC6 - Invalid wake scancode\n"); - break; - } - - /* Command */ - match[0] = wbcir_to_rc6cells(wake_sc >> 0); - mask[0] = 0xFF; - match[1] = wbcir_to_rc6cells(wake_sc >> 4); - mask[1] = 0xFF; - - /* Address */ - match[2] = wbcir_to_rc6cells(wake_sc >> 8); - mask[2] = 0xFF; - match[3] = wbcir_to_rc6cells(wake_sc >> 12); - mask[3] = 0xFF; - - /* Header */ - match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */ - mask[4] = 0xF0; - match[5] = 0x09; /* start bit = 1, mode2 = 0 */ - mask[5] = 0x0F; - - rc6_csl = 44; - - } else if (wake_rc6mode == 6) { - i = 0; - - /* Command */ - match[i] = wbcir_to_rc6cells(wake_sc >> 0); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 4); - mask[i++] = 0xFF; - - /* Address + Toggle */ - match[i] = wbcir_to_rc6cells(wake_sc >> 8); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 12); - mask[i++] = 0x3F; - - /* Customer bits 7 - 0 */ - match[i] = wbcir_to_rc6cells(wake_sc >> 16); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 20); - mask[i++] = 0xFF; - - if (wake_sc & 0x80000000) { - /* Customer range bit and bits 15 - 8 */ - match[i] = wbcir_to_rc6cells(wake_sc >> 24); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 28); - mask[i++] = 0xFF; - rc6_csl = 76; - } else if (wake_sc <= 0x007FFFFF) { - rc6_csl = 60; - } else { - do_wake = 0; - dev_err(dev, "RC6 - Invalid wake scancode\n"); - break; - } - - /* Header */ - match[i] = 0x93; /* mode1 = mode0 = 1, submode = 0 */ - mask[i++] = 0xFF; - match[i] = 0x0A; /* start bit = 1, mode2 = 1 */ - mask[i++] = 0x0F; - - } else { - do_wake = 0; - dev_err(dev, "RC6 - Invalid wake mode\n"); - } - - break; - - default: - do_wake = 0; - break; - } - -finish: - if (do_wake) { - /* Set compare and compare mask */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX, - WBCIR_REGSEL_COMPARE | WBCIR_REG_ADDR0, - 0x3F); - outsb(data->wbase + WBCIR_REG_WCEIR_DATA, match, 11); - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX, - WBCIR_REGSEL_MASK | WBCIR_REG_ADDR0, - 0x3F); - outsb(data->wbase + WBCIR_REG_WCEIR_DATA, mask, 11); - - /* RC6 Compare String Len */ - outb(rc6_csl, data->wbase + WBCIR_REG_WCEIR_CSL); - - /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); - - /* Clear BUFF_EN, Clear END_EN, Set MATCH_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x01, 0x07); - - /* Set CEIR_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x01, 0x01); - - } else { - /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); - - /* Clear CEIR_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01); - } - - /* Disable interrupts */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER); - - /* Disable LED */ - data->irdata_active = false; - led_trigger_event(data->rxtrigger, LED_OFF); - - /* - * ACPI will set the HW disable bit for SP3 which means that the - * output signals are left in an undefined state which may cause - * spurious interrupts which we need to ignore until the hardware - * is reinitialized. - */ - disable_irq(data->irq); -} - -static int -wbcir_suspend(struct pnp_dev *device, pm_message_t state) -{ - wbcir_shutdown(device); - return 0; -} - -static void -wbcir_init_hw(struct wbcir_data *data) -{ - u8 tmp; - - /* Disable interrupts */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER); - - /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */ - tmp = protocol << 4; - if (invert) - tmp |= 0x08; - outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL); - - /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); - - /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); - - /* Set RC5 cell time to correspond to 36 kHz */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CFG1, 0x4A, 0x7F); - - /* Set IRTX_INV */ - if (invert) - outb(0x04, data->ebase + WBCIR_REG_ECEIR_CCTL); - else - outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL); - - /* - * Clear IR LED, set SP3 clock to 24Mhz - * set SP3_IRRX_SW to binary 01, helpfully not documented - */ - outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS); - - /* Enable extended mode */ - wbcir_select_bank(data, WBCIR_BANK_2); - outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1); - - /* - * Configure baud generator, IR data will be sampled at - * a bitrate of: (24Mhz * prescaler) / (divisor * 16). - * - * The ECIR registers include a flag to change the - * 24Mhz clock freq to 48Mhz. - * - * It's not documented in the specs, but fifo levels - * other than 16 seems to be unsupported. - */ - - /* prescaler 1.0, tx/rx fifo lvl 16 */ - outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2); - - /* Set baud divisor to generate one byte per bit/cell */ - switch (protocol) { - case IR_PROTOCOL_RC5: - outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL); - break; - case IR_PROTOCOL_RC6: - outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL); - break; - case IR_PROTOCOL_NEC: - outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL); - break; - } - outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH); - - /* Set CEIR mode */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR); - inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */ - inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */ - - /* Disable RX demod, run-length encoding/decoding, set freq span */ - wbcir_select_bank(data, WBCIR_BANK_7); - outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG); - - /* Disable timer */ - wbcir_select_bank(data, WBCIR_BANK_4); - outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1); - - /* Enable MSR interrupt, Clear AUX_IRX */ - wbcir_select_bank(data, WBCIR_BANK_5); - outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2); - - /* Disable CRC */ - wbcir_select_bank(data, WBCIR_BANK_6); - outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3); - - /* Set RX/TX (de)modulation freq, not really used */ - wbcir_select_bank(data, WBCIR_BANK_7); - outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC); - outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC); - - /* Set invert and pin direction */ - if (invert) - outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4); - else - outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4); - - /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(0x97, data->sbase + WBCIR_REG_SP3_FCR); - - /* Clear AUX status bits */ - outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR); - - /* Clear IR decoding state */ - data->irdata_active = false; - led_trigger_event(data->rxtrigger, LED_OFF); - data->irdata_error = false; - data->ev.duration = 0; - ir_raw_event_reset(data->dev); - ir_raw_event_handle(data->dev); - - /* Enable interrupts */ - outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER); -} - -static int -wbcir_resume(struct pnp_dev *device) -{ - struct wbcir_data *data = pnp_get_drvdata(device); - - wbcir_init_hw(data); - enable_irq(data->irq); - - return 0; -} - -static int __devinit -wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) -{ - struct device *dev = &device->dev; - struct wbcir_data *data; - int err; - - if (!(pnp_port_len(device, 0) == EHFUNC_IOMEM_LEN && - pnp_port_len(device, 1) == WAKEUP_IOMEM_LEN && - pnp_port_len(device, 2) == SP_IOMEM_LEN)) { - dev_err(dev, "Invalid resources\n"); - return -ENODEV; - } - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - err = -ENOMEM; - goto exit; - } - - pnp_set_drvdata(device, data); - - spin_lock_init(&data->spinlock); - data->ebase = pnp_port_start(device, 0); - data->wbase = pnp_port_start(device, 1); - data->sbase = pnp_port_start(device, 2); - data->irq = pnp_irq(device, 0); - - if (data->wbase == 0 || data->ebase == 0 || - data->sbase == 0 || data->irq == 0) { - err = -ENODEV; - dev_err(dev, "Invalid resources\n"); - goto exit_free_data; - } - - dev_dbg(&device->dev, "Found device " - "(w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n", - data->wbase, data->ebase, data->sbase, data->irq); - - if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) { - dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", - data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1); - err = -EBUSY; - goto exit_free_data; - } - - if (!request_region(data->ebase, EHFUNC_IOMEM_LEN, DRVNAME)) { - dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", - data->ebase, data->ebase + EHFUNC_IOMEM_LEN - 1); - err = -EBUSY; - goto exit_release_wbase; - } - - if (!request_region(data->sbase, SP_IOMEM_LEN, DRVNAME)) { - dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", - data->sbase, data->sbase + SP_IOMEM_LEN - 1); - err = -EBUSY; - goto exit_release_ebase; - } - - err = request_irq(data->irq, wbcir_irq_handler, - IRQF_DISABLED, DRVNAME, device); - if (err) { - dev_err(dev, "Failed to claim IRQ %u\n", data->irq); - err = -EBUSY; - goto exit_release_sbase; - } - - led_trigger_register_simple("cir-tx", &data->txtrigger); - if (!data->txtrigger) { - err = -ENOMEM; - goto exit_free_irq; - } - - led_trigger_register_simple("cir-rx", &data->rxtrigger); - if (!data->rxtrigger) { - err = -ENOMEM; - goto exit_unregister_txtrigger; - } - - data->led.name = "cir::activity"; - data->led.default_trigger = "cir-rx"; - data->led.brightness_set = wbcir_led_brightness_set; - data->led.brightness_get = wbcir_led_brightness_get; - err = led_classdev_register(&device->dev, &data->led); - if (err) - goto exit_unregister_rxtrigger; - - data->dev = rc_allocate_device(); - if (!data->dev) { - err = -ENOMEM; - goto exit_unregister_led; - } - - data->dev->driver_name = WBCIR_NAME; - data->dev->input_name = WBCIR_NAME; - data->dev->input_phys = "wbcir/cir0"; - data->dev->input_id.bustype = BUS_HOST; - data->dev->input_id.vendor = PCI_VENDOR_ID_WINBOND; - data->dev->input_id.product = WBCIR_ID_FAMILY; - data->dev->input_id.version = WBCIR_ID_CHIP; - data->dev->priv = data; - data->dev->dev.parent = &device->dev; - - err = rc_register_device(data->dev); - if (err) - goto exit_free_rc; - - device_init_wakeup(&device->dev, 1); - - wbcir_init_hw(data); - - return 0; - -exit_free_rc: - rc_free_device(data->dev); -exit_unregister_led: - led_classdev_unregister(&data->led); -exit_unregister_rxtrigger: - led_trigger_unregister_simple(data->rxtrigger); -exit_unregister_txtrigger: - led_trigger_unregister_simple(data->txtrigger); -exit_free_irq: - free_irq(data->irq, device); -exit_release_sbase: - release_region(data->sbase, SP_IOMEM_LEN); -exit_release_ebase: - release_region(data->ebase, EHFUNC_IOMEM_LEN); -exit_release_wbase: - release_region(data->wbase, WAKEUP_IOMEM_LEN); -exit_free_data: - kfree(data); - pnp_set_drvdata(device, NULL); -exit: - return err; -} - -static void __devexit -wbcir_remove(struct pnp_dev *device) -{ - struct wbcir_data *data = pnp_get_drvdata(device); - - /* Disable interrupts */ - wbcir_select_bank(data, WBCIR_BANK_0); - outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER); - - free_irq(data->irq, device); - - /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); - - /* Clear CEIR_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01); - - /* Clear BUFF_EN, END_EN, MATCH_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); - - rc_unregister_device(data->dev); - - led_trigger_unregister_simple(data->rxtrigger); - led_trigger_unregister_simple(data->txtrigger); - led_classdev_unregister(&data->led); - - /* This is ok since &data->led isn't actually used */ - wbcir_led_brightness_set(&data->led, LED_OFF); - - release_region(data->wbase, WAKEUP_IOMEM_LEN); - release_region(data->ebase, EHFUNC_IOMEM_LEN); - release_region(data->sbase, SP_IOMEM_LEN); - - kfree(data); - - pnp_set_drvdata(device, NULL); -} - -static const struct pnp_device_id wbcir_ids[] = { - { "WEC1022", 0 }, - { "", 0 } -}; -MODULE_DEVICE_TABLE(pnp, wbcir_ids); - -static struct pnp_driver wbcir_driver = { - .name = WBCIR_NAME, - .id_table = wbcir_ids, - .probe = wbcir_probe, - .remove = __devexit_p(wbcir_remove), - .suspend = wbcir_suspend, - .resume = wbcir_resume, - .shutdown = wbcir_shutdown -}; - -static int __init -wbcir_init(void) -{ - int ret; - - switch (protocol) { - case IR_PROTOCOL_RC5: - case IR_PROTOCOL_NEC: - case IR_PROTOCOL_RC6: - break; - default: - printk(KERN_ERR DRVNAME ": Invalid power-on protocol\n"); - } - - ret = pnp_register_driver(&wbcir_driver); - if (ret) - printk(KERN_ERR DRVNAME ": Unable to register driver\n"); - - return ret; -} - -static void __exit -wbcir_exit(void) -{ - pnp_unregister_driver(&wbcir_driver); -} - -module_init(wbcir_init); -module_exit(wbcir_exit); - -MODULE_AUTHOR("David Härdeman "); -MODULE_DESCRIPTION("Winbond SuperI/O Consumer IR Driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7170.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7170.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7170.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7170.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,359 +0,0 @@ -/* - * adv7170 - adv7170, adv7171 video encoder driver version 0.0.1 - * - * Copyright (C) 2002 Maxim Yevtyushkin - * - * Based on adv7176 driver by: - * - * Copyright (C) 1998 Dave Perks - * Copyright (C) 1999 Wolfgang Scherr - * Copyright (C) 2000 Serguei Miridonov - * - some corrections for Pinnacle Systems Inc. DC10plus card. - * - * Changes by Ronald Bultje - * - moved over to linux>=2.4.x i2c protocol (1/1/2003) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver"); -MODULE_AUTHOR("Maxim Yevtyushkin"); -MODULE_LICENSE("GPL"); - - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -/* ----------------------------------------------------------------------- */ - -struct adv7170 { - struct v4l2_subdev sd; - unsigned char reg[128]; - - v4l2_std_id norm; - int input; -}; - -static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd) -{ - return container_of(sd, struct adv7170, sd); -} - -static char *inputs[] = { "pass_through", "play_back" }; - -/* ----------------------------------------------------------------------- */ - -static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct adv7170 *encoder = to_adv7170(sd); - - encoder->reg[reg] = value; - return i2c_smbus_write_byte_data(client, reg, value); -} - -static inline int adv7170_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_read_byte_data(client, reg); -} - -static int adv7170_write_block(struct v4l2_subdev *sd, - const u8 *data, unsigned int len) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct adv7170 *encoder = to_adv7170(sd); - int ret = -1; - u8 reg; - - /* the adv7170 has an autoincrement function, use it if - * the adapter understands raw I2C */ - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - /* do raw I2C, not smbus compatible */ - u8 block_data[32]; - int block_len; - - while (len >= 2) { - block_len = 0; - block_data[block_len++] = reg = data[0]; - do { - block_data[block_len++] = - encoder->reg[reg++] = data[1]; - len -= 2; - data += 2; - } while (len >= 2 && data[0] == reg && block_len < 32); - ret = i2c_master_send(client, block_data, block_len); - if (ret < 0) - break; - } - } else { - /* do some slow I2C emulation kind of thing */ - while (len >= 2) { - reg = *data++; - ret = adv7170_write(sd, reg, *data++); - if (ret < 0) - break; - len -= 2; - } - } - return ret; -} - -/* ----------------------------------------------------------------------- */ - -#define TR0MODE 0x4c -#define TR0RST 0x80 - -#define TR1CAPT 0x00 -#define TR1PLAY 0x00 - -static const unsigned char init_NTSC[] = { - 0x00, 0x10, /* MR0 */ - 0x01, 0x20, /* MR1 */ - 0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */ - 0x03, 0x80, /* MR3 */ - 0x04, 0x30, /* MR4 */ - 0x05, 0x00, /* Reserved */ - 0x06, 0x00, /* Reserved */ - 0x07, TR0MODE, /* TM0 */ - 0x08, TR1CAPT, /* TM1 */ - 0x09, 0x16, /* Fsc0 */ - 0x0a, 0x7c, /* Fsc1 */ - 0x0b, 0xf0, /* Fsc2 */ - 0x0c, 0x21, /* Fsc3 */ - 0x0d, 0x00, /* Subcarrier Phase */ - 0x0e, 0x00, /* Closed Capt. Ext 0 */ - 0x0f, 0x00, /* Closed Capt. Ext 1 */ - 0x10, 0x00, /* Closed Capt. 0 */ - 0x11, 0x00, /* Closed Capt. 1 */ - 0x12, 0x00, /* Pedestal Ctl 0 */ - 0x13, 0x00, /* Pedestal Ctl 1 */ - 0x14, 0x00, /* Pedestal Ctl 2 */ - 0x15, 0x00, /* Pedestal Ctl 3 */ - 0x16, 0x00, /* CGMS_WSS_0 */ - 0x17, 0x00, /* CGMS_WSS_1 */ - 0x18, 0x00, /* CGMS_WSS_2 */ - 0x19, 0x00, /* Teletext Ctl */ -}; - -static const unsigned char init_PAL[] = { - 0x00, 0x71, /* MR0 */ - 0x01, 0x20, /* MR1 */ - 0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */ - 0x03, 0x80, /* MR3 */ - 0x04, 0x30, /* MR4 */ - 0x05, 0x00, /* Reserved */ - 0x06, 0x00, /* Reserved */ - 0x07, TR0MODE, /* TM0 */ - 0x08, TR1CAPT, /* TM1 */ - 0x09, 0xcb, /* Fsc0 */ - 0x0a, 0x8a, /* Fsc1 */ - 0x0b, 0x09, /* Fsc2 */ - 0x0c, 0x2a, /* Fsc3 */ - 0x0d, 0x00, /* Subcarrier Phase */ - 0x0e, 0x00, /* Closed Capt. Ext 0 */ - 0x0f, 0x00, /* Closed Capt. Ext 1 */ - 0x10, 0x00, /* Closed Capt. 0 */ - 0x11, 0x00, /* Closed Capt. 1 */ - 0x12, 0x00, /* Pedestal Ctl 0 */ - 0x13, 0x00, /* Pedestal Ctl 1 */ - 0x14, 0x00, /* Pedestal Ctl 2 */ - 0x15, 0x00, /* Pedestal Ctl 3 */ - 0x16, 0x00, /* CGMS_WSS_0 */ - 0x17, 0x00, /* CGMS_WSS_1 */ - 0x18, 0x00, /* CGMS_WSS_2 */ - 0x19, 0x00, /* Teletext Ctl */ -}; - - -static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct adv7170 *encoder = to_adv7170(sd); - - v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); - - if (std & V4L2_STD_NTSC) { - adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC)); - if (encoder->input == 0) - adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */ - adv7170_write(sd, 0x07, TR0MODE | TR0RST); - adv7170_write(sd, 0x07, TR0MODE); - } else if (std & V4L2_STD_PAL) { - adv7170_write_block(sd, init_PAL, sizeof(init_PAL)); - if (encoder->input == 0) - adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */ - adv7170_write(sd, 0x07, TR0MODE | TR0RST); - adv7170_write(sd, 0x07, TR0MODE); - } else { - v4l2_dbg(1, debug, sd, "illegal norm: %llx\n", - (unsigned long long)std); - return -EINVAL; - } - v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std); - encoder->norm = std; - return 0; -} - -static int adv7170_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct adv7170 *encoder = to_adv7170(sd); - - /* RJ: input = 0: input is from decoder - input = 1: input is from ZR36060 - input = 2: color bar */ - - v4l2_dbg(1, debug, sd, "set input from %s\n", - input == 0 ? "decoder" : "ZR36060"); - - switch (input) { - case 0: - adv7170_write(sd, 0x01, 0x20); - adv7170_write(sd, 0x08, TR1CAPT); /* TR1 */ - adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */ - adv7170_write(sd, 0x07, TR0MODE | TR0RST); - adv7170_write(sd, 0x07, TR0MODE); - /* udelay(10); */ - break; - - case 1: - adv7170_write(sd, 0x01, 0x00); - adv7170_write(sd, 0x08, TR1PLAY); /* TR1 */ - adv7170_write(sd, 0x02, 0x08); - adv7170_write(sd, 0x07, TR0MODE | TR0RST); - adv7170_write(sd, 0x07, TR0MODE); - /* udelay(10); */ - break; - - default: - v4l2_dbg(1, debug, sd, "illegal input: %d\n", input); - return -EINVAL; - } - v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]); - encoder->input = input; - return 0; -} - -static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7170, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops adv7170_core_ops = { - .g_chip_ident = adv7170_g_chip_ident, -}; - -static const struct v4l2_subdev_video_ops adv7170_video_ops = { - .s_std_output = adv7170_s_std_output, - .s_routing = adv7170_s_routing, -}; - -static const struct v4l2_subdev_ops adv7170_ops = { - .core = &adv7170_core_ops, - .video = &adv7170_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int adv7170_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct adv7170 *encoder; - struct v4l2_subdev *sd; - int i; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL); - if (encoder == NULL) - return -ENOMEM; - sd = &encoder->sd; - v4l2_i2c_subdev_init(sd, client, &adv7170_ops); - encoder->norm = V4L2_STD_NTSC; - encoder->input = 0; - - i = adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC)); - if (i >= 0) { - i = adv7170_write(sd, 0x07, TR0MODE | TR0RST); - i = adv7170_write(sd, 0x07, TR0MODE); - i = adv7170_read(sd, 0x12); - v4l2_dbg(1, debug, sd, "revision %d\n", i & 1); - } - if (i < 0) - v4l2_dbg(1, debug, sd, "init error 0x%x\n", i); - return 0; -} - -static int adv7170_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_adv7170(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id adv7170_id[] = { - { "adv7170", 0 }, - { "adv7171", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adv7170_id); - -static struct i2c_driver adv7170_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "adv7170", - }, - .probe = adv7170_probe, - .remove = adv7170_remove, - .id_table = adv7170_id, -}; - -static __init int init_adv7170(void) -{ - return i2c_add_driver(&adv7170_driver); -} - -static __exit void exit_adv7170(void) -{ - i2c_del_driver(&adv7170_driver); -} - -module_init(init_adv7170); -module_exit(exit_adv7170); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7175.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7175.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7175.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7175.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,409 +0,0 @@ -/* - * adv7175 - adv7175a video encoder driver version 0.0.3 - * - * Copyright (C) 1998 Dave Perks - * Copyright (C) 1999 Wolfgang Scherr - * Copyright (C) 2000 Serguei Miridonov - * - some corrections for Pinnacle Systems Inc. DC10plus card. - * - * Changes by Ronald Bultje - * - moved over to linux>=2.4.x i2c protocol (9/9/2002) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver"); -MODULE_AUTHOR("Dave Perks"); -MODULE_LICENSE("GPL"); - -#define I2C_ADV7175 0xd4 -#define I2C_ADV7176 0x54 - - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -/* ----------------------------------------------------------------------- */ - -struct adv7175 { - struct v4l2_subdev sd; - v4l2_std_id norm; - int input; -}; - -static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd) -{ - return container_of(sd, struct adv7175, sd); -} - -static char *inputs[] = { "pass_through", "play_back", "color_bar" }; - -/* ----------------------------------------------------------------------- */ - -static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_write_byte_data(client, reg, value); -} - -static inline int adv7175_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_read_byte_data(client, reg); -} - -static int adv7175_write_block(struct v4l2_subdev *sd, - const u8 *data, unsigned int len) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = -1; - u8 reg; - - /* the adv7175 has an autoincrement function, use it if - * the adapter understands raw I2C */ - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - /* do raw I2C, not smbus compatible */ - u8 block_data[32]; - int block_len; - - while (len >= 2) { - block_len = 0; - block_data[block_len++] = reg = data[0]; - do { - block_data[block_len++] = data[1]; - reg++; - len -= 2; - data += 2; - } while (len >= 2 && data[0] == reg && block_len < 32); - ret = i2c_master_send(client, block_data, block_len); - if (ret < 0) - break; - } - } else { - /* do some slow I2C emulation kind of thing */ - while (len >= 2) { - reg = *data++; - ret = adv7175_write(sd, reg, *data++); - if (ret < 0) - break; - len -= 2; - } - } - - return ret; -} - -static void set_subcarrier_freq(struct v4l2_subdev *sd, int pass_through) -{ - /* for some reason pass_through NTSC needs - * a different sub-carrier freq to remain stable. */ - if (pass_through) - adv7175_write(sd, 0x02, 0x00); - else - adv7175_write(sd, 0x02, 0x55); - - adv7175_write(sd, 0x03, 0x55); - adv7175_write(sd, 0x04, 0x55); - adv7175_write(sd, 0x05, 0x25); -} - -/* ----------------------------------------------------------------------- */ -/* Output filter: S-Video Composite */ - -#define MR050 0x11 /* 0x09 */ -#define MR060 0x14 /* 0x0c */ - -/* ----------------------------------------------------------------------- */ - -#define TR0MODE 0x46 -#define TR0RST 0x80 - -#define TR1CAPT 0x80 -#define TR1PLAY 0x00 - -static const unsigned char init_common[] = { - - 0x00, MR050, /* MR0, PAL enabled */ - 0x01, 0x00, /* MR1 */ - 0x02, 0x0c, /* subc. freq. */ - 0x03, 0x8c, /* subc. freq. */ - 0x04, 0x79, /* subc. freq. */ - 0x05, 0x26, /* subc. freq. */ - 0x06, 0x40, /* subc. phase */ - - 0x07, TR0MODE, /* TR0, 16bit */ - 0x08, 0x21, /* */ - 0x09, 0x00, /* */ - 0x0a, 0x00, /* */ - 0x0b, 0x00, /* */ - 0x0c, TR1CAPT, /* TR1 */ - 0x0d, 0x4f, /* MR2 */ - 0x0e, 0x00, /* */ - 0x0f, 0x00, /* */ - 0x10, 0x00, /* */ - 0x11, 0x00, /* */ -}; - -static const unsigned char init_pal[] = { - 0x00, MR050, /* MR0, PAL enabled */ - 0x01, 0x00, /* MR1 */ - 0x02, 0x0c, /* subc. freq. */ - 0x03, 0x8c, /* subc. freq. */ - 0x04, 0x79, /* subc. freq. */ - 0x05, 0x26, /* subc. freq. */ - 0x06, 0x40, /* subc. phase */ -}; - -static const unsigned char init_ntsc[] = { - 0x00, MR060, /* MR0, NTSC enabled */ - 0x01, 0x00, /* MR1 */ - 0x02, 0x55, /* subc. freq. */ - 0x03, 0x55, /* subc. freq. */ - 0x04, 0x55, /* subc. freq. */ - 0x05, 0x25, /* subc. freq. */ - 0x06, 0x1a, /* subc. phase */ -}; - -static int adv7175_init(struct v4l2_subdev *sd, u32 val) -{ - /* This is just for testing!!! */ - adv7175_write_block(sd, init_common, sizeof(init_common)); - adv7175_write(sd, 0x07, TR0MODE | TR0RST); - adv7175_write(sd, 0x07, TR0MODE); - return 0; -} - -static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct adv7175 *encoder = to_adv7175(sd); - - if (std & V4L2_STD_NTSC) { - adv7175_write_block(sd, init_ntsc, sizeof(init_ntsc)); - if (encoder->input == 0) - adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */ - adv7175_write(sd, 0x07, TR0MODE | TR0RST); - adv7175_write(sd, 0x07, TR0MODE); - } else if (std & V4L2_STD_PAL) { - adv7175_write_block(sd, init_pal, sizeof(init_pal)); - if (encoder->input == 0) - adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */ - adv7175_write(sd, 0x07, TR0MODE | TR0RST); - adv7175_write(sd, 0x07, TR0MODE); - } else if (std & V4L2_STD_SECAM) { - /* This is an attempt to convert - * SECAM->PAL (typically it does not work - * due to genlock: when decoder is in SECAM - * and encoder in in PAL the subcarrier can - * not be syncronized with horizontal - * quency) */ - adv7175_write_block(sd, init_pal, sizeof(init_pal)); - if (encoder->input == 0) - adv7175_write(sd, 0x0d, 0x49); /* Disable genlock */ - adv7175_write(sd, 0x07, TR0MODE | TR0RST); - adv7175_write(sd, 0x07, TR0MODE); - } else { - v4l2_dbg(1, debug, sd, "illegal norm: %llx\n", - (unsigned long long)std); - return -EINVAL; - } - v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std); - encoder->norm = std; - return 0; -} - -static int adv7175_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct adv7175 *encoder = to_adv7175(sd); - - /* RJ: input = 0: input is from decoder - input = 1: input is from ZR36060 - input = 2: color bar */ - - switch (input) { - case 0: - adv7175_write(sd, 0x01, 0x00); - - if (encoder->norm & V4L2_STD_NTSC) - set_subcarrier_freq(sd, 1); - - adv7175_write(sd, 0x0c, TR1CAPT); /* TR1 */ - if (encoder->norm & V4L2_STD_SECAM) - adv7175_write(sd, 0x0d, 0x49); /* Disable genlock */ - else - adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */ - adv7175_write(sd, 0x07, TR0MODE | TR0RST); - adv7175_write(sd, 0x07, TR0MODE); - /*udelay(10);*/ - break; - - case 1: - adv7175_write(sd, 0x01, 0x00); - - if (encoder->norm & V4L2_STD_NTSC) - set_subcarrier_freq(sd, 0); - - adv7175_write(sd, 0x0c, TR1PLAY); /* TR1 */ - adv7175_write(sd, 0x0d, 0x49); - adv7175_write(sd, 0x07, TR0MODE | TR0RST); - adv7175_write(sd, 0x07, TR0MODE); - /* udelay(10); */ - break; - - case 2: - adv7175_write(sd, 0x01, 0x80); - - if (encoder->norm & V4L2_STD_NTSC) - set_subcarrier_freq(sd, 0); - - adv7175_write(sd, 0x0d, 0x49); - adv7175_write(sd, 0x07, TR0MODE | TR0RST); - adv7175_write(sd, 0x07, TR0MODE); - /* udelay(10); */ - break; - - default: - v4l2_dbg(1, debug, sd, "illegal input: %d\n", input); - return -EINVAL; - } - v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]); - encoder->input = input; - return 0; -} - -static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0); -} - -static int adv7175_s_power(struct v4l2_subdev *sd, int on) -{ - if (on) - adv7175_write(sd, 0x01, 0x00); - else - adv7175_write(sd, 0x01, 0x78); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops adv7175_core_ops = { - .g_chip_ident = adv7175_g_chip_ident, - .init = adv7175_init, - .s_power = adv7175_s_power, -}; - -static const struct v4l2_subdev_video_ops adv7175_video_ops = { - .s_std_output = adv7175_s_std_output, - .s_routing = adv7175_s_routing, -}; - -static const struct v4l2_subdev_ops adv7175_ops = { - .core = &adv7175_core_ops, - .video = &adv7175_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int adv7175_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int i; - struct adv7175 *encoder; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL); - if (encoder == NULL) - return -ENOMEM; - sd = &encoder->sd; - v4l2_i2c_subdev_init(sd, client, &adv7175_ops); - encoder->norm = V4L2_STD_NTSC; - encoder->input = 0; - - i = adv7175_write_block(sd, init_common, sizeof(init_common)); - if (i >= 0) { - i = adv7175_write(sd, 0x07, TR0MODE | TR0RST); - i = adv7175_write(sd, 0x07, TR0MODE); - i = adv7175_read(sd, 0x12); - v4l2_dbg(1, debug, sd, "revision %d\n", i & 1); - } - if (i < 0) - v4l2_dbg(1, debug, sd, "init error 0x%x\n", i); - return 0; -} - -static int adv7175_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_adv7175(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id adv7175_id[] = { - { "adv7175", 0 }, - { "adv7176", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adv7175_id); - -static struct i2c_driver adv7175_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "adv7175", - }, - .probe = adv7175_probe, - .remove = adv7175_remove, - .id_table = adv7175_id, -}; - -static __init int init_adv7175(void) -{ - return i2c_add_driver(&adv7175_driver); -} - -static __exit void exit_adv7175(void) -{ - i2c_del_driver(&adv7175_driver); -} - -module_init(init_adv7175); -module_exit(exit_adv7175); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7180.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7180.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7180.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7180.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,463 +0,0 @@ -/* - * adv7180.c Analog Devices ADV7180 video decoder driver - * Copyright (c) 2009 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "adv7180" - -#define ADV7180_INPUT_CONTROL_REG 0x00 -#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00 -#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10 -#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20 -#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30 -#define ADV7180_INPUT_CONTROL_NTSC_J 0x40 -#define ADV7180_INPUT_CONTROL_NTSC_M 0x50 -#define ADV7180_INPUT_CONTROL_PAL60 0x60 -#define ADV7180_INPUT_CONTROL_NTSC_443 0x70 -#define ADV7180_INPUT_CONTROL_PAL_BG 0x80 -#define ADV7180_INPUT_CONTROL_PAL_N 0x90 -#define ADV7180_INPUT_CONTROL_PAL_M 0xa0 -#define ADV7180_INPUT_CONTROL_PAL_M_PED 0xb0 -#define ADV7180_INPUT_CONTROL_PAL_COMB_N 0xc0 -#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED 0xd0 -#define ADV7180_INPUT_CONTROL_PAL_SECAM 0xe0 -#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED 0xf0 - -#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG 0x04 -#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 - -#define ADV7180_AUTODETECT_ENABLE_REG 0x07 -#define ADV7180_AUTODETECT_DEFAULT 0x7f - -#define ADV7180_ADI_CTRL_REG 0x0e -#define ADV7180_ADI_CTRL_IRQ_SPACE 0x20 - -#define ADV7180_STATUS1_REG 0x10 -#define ADV7180_STATUS1_IN_LOCK 0x01 -#define ADV7180_STATUS1_AUTOD_MASK 0x70 -#define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00 -#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10 -#define ADV7180_STATUS1_AUTOD_PAL_M 0x20 -#define ADV7180_STATUS1_AUTOD_PAL_60 0x30 -#define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40 -#define ADV7180_STATUS1_AUTOD_SECAM 0x50 -#define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60 -#define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 - -#define ADV7180_IDENT_REG 0x11 -#define ADV7180_ID_7180 0x18 - -#define ADV7180_ICONF1_ADI 0x40 -#define ADV7180_ICONF1_ACTIVE_LOW 0x01 -#define ADV7180_ICONF1_PSYNC_ONLY 0x10 -#define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 - -#define ADV7180_IRQ1_LOCK 0x01 -#define ADV7180_IRQ1_UNLOCK 0x02 -#define ADV7180_ISR1_ADI 0x42 -#define ADV7180_ICR1_ADI 0x43 -#define ADV7180_IMR1_ADI 0x44 -#define ADV7180_IMR2_ADI 0x48 -#define ADV7180_IRQ3_AD_CHANGE 0x08 -#define ADV7180_ISR3_ADI 0x4A -#define ADV7180_ICR3_ADI 0x4B -#define ADV7180_IMR3_ADI 0x4C -#define ADV7180_IMR4_ADI 0x50 - -struct adv7180_state { - struct v4l2_subdev sd; - struct work_struct work; - struct mutex mutex; /* mutual excl. when accessing chip */ - int irq; - v4l2_std_id curr_norm; - bool autodetect; -}; - -static v4l2_std_id adv7180_std_to_v4l2(u8 status1) -{ - switch (status1 & ADV7180_STATUS1_AUTOD_MASK) { - case ADV7180_STATUS1_AUTOD_NTSM_M_J: - return V4L2_STD_NTSC; - case ADV7180_STATUS1_AUTOD_NTSC_4_43: - return V4L2_STD_NTSC_443; - case ADV7180_STATUS1_AUTOD_PAL_M: - return V4L2_STD_PAL_M; - case ADV7180_STATUS1_AUTOD_PAL_60: - return V4L2_STD_PAL_60; - case ADV7180_STATUS1_AUTOD_PAL_B_G: - return V4L2_STD_PAL; - case ADV7180_STATUS1_AUTOD_SECAM: - return V4L2_STD_SECAM; - case ADV7180_STATUS1_AUTOD_PAL_COMB: - return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; - case ADV7180_STATUS1_AUTOD_SECAM_525: - return V4L2_STD_SECAM; - default: - return V4L2_STD_UNKNOWN; - } -} - -static int v4l2_std_to_adv7180(v4l2_std_id std) -{ - if (std == V4L2_STD_PAL_60) - return ADV7180_INPUT_CONTROL_PAL60; - if (std == V4L2_STD_NTSC_443) - return ADV7180_INPUT_CONTROL_NTSC_443; - if (std == V4L2_STD_PAL_N) - return ADV7180_INPUT_CONTROL_PAL_N; - if (std == V4L2_STD_PAL_M) - return ADV7180_INPUT_CONTROL_PAL_M; - if (std == V4L2_STD_PAL_Nc) - return ADV7180_INPUT_CONTROL_PAL_COMB_N; - - if (std & V4L2_STD_PAL) - return ADV7180_INPUT_CONTROL_PAL_BG; - if (std & V4L2_STD_NTSC) - return ADV7180_INPUT_CONTROL_NTSC_M; - if (std & V4L2_STD_SECAM) - return ADV7180_INPUT_CONTROL_PAL_SECAM; - - return -EINVAL; -} - -static u32 adv7180_status_to_v4l2(u8 status1) -{ - if (!(status1 & ADV7180_STATUS1_IN_LOCK)) - return V4L2_IN_ST_NO_SIGNAL; - - return 0; -} - -static int __adv7180_status(struct i2c_client *client, u32 *status, - v4l2_std_id *std) -{ - int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG); - - if (status1 < 0) - return status1; - - if (status) - *status = adv7180_status_to_v4l2(status1); - if (std) - *std = adv7180_std_to_v4l2(status1); - - return 0; -} - -static inline struct adv7180_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct adv7180_state, sd); -} - -static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) -{ - struct adv7180_state *state = to_state(sd); - int err = mutex_lock_interruptible(&state->mutex); - if (err) - return err; - - /* when we are interrupt driven we know the state */ - if (!state->autodetect || state->irq > 0) - *std = state->curr_norm; - else - err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std); - - mutex_unlock(&state->mutex); - return err; -} - -static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) -{ - struct adv7180_state *state = to_state(sd); - int ret = mutex_lock_interruptible(&state->mutex); - if (ret) - return ret; - - ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL); - mutex_unlock(&state->mutex); - return ret; -} - -static int adv7180_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0); -} - -static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct adv7180_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = mutex_lock_interruptible(&state->mutex); - if (ret) - return ret; - - /* all standards -> autodetect */ - if (std == V4L2_STD_ALL) { - ret = i2c_smbus_write_byte_data(client, - ADV7180_INPUT_CONTROL_REG, - ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM); - if (ret < 0) - goto out; - - __adv7180_status(client, NULL, &state->curr_norm); - state->autodetect = true; - } else { - ret = v4l2_std_to_adv7180(std); - if (ret < 0) - goto out; - - ret = i2c_smbus_write_byte_data(client, - ADV7180_INPUT_CONTROL_REG, ret); - if (ret < 0) - goto out; - - state->curr_norm = std; - state->autodetect = false; - } - ret = 0; -out: - mutex_unlock(&state->mutex); - return ret; -} - -static const struct v4l2_subdev_video_ops adv7180_video_ops = { - .querystd = adv7180_querystd, - .g_input_status = adv7180_g_input_status, -}; - -static const struct v4l2_subdev_core_ops adv7180_core_ops = { - .g_chip_ident = adv7180_g_chip_ident, - .s_std = adv7180_s_std, -}; - -static const struct v4l2_subdev_ops adv7180_ops = { - .core = &adv7180_core_ops, - .video = &adv7180_video_ops, -}; - -static void adv7180_work(struct work_struct *work) -{ - struct adv7180_state *state = container_of(work, struct adv7180_state, - work); - struct i2c_client *client = v4l2_get_subdevdata(&state->sd); - u8 isr3; - - mutex_lock(&state->mutex); - i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, - ADV7180_ADI_CTRL_IRQ_SPACE); - isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI); - /* clear */ - i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3); - i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0); - - if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect) - __adv7180_status(client, NULL, &state->curr_norm); - mutex_unlock(&state->mutex); - - enable_irq(state->irq); -} - -static irqreturn_t adv7180_irq(int irq, void *devid) -{ - struct adv7180_state *state = devid; - - schedule_work(&state->work); - - disable_irq_nosync(state->irq); - - return IRQ_HANDLED; -} - -/* - * Generic i2c probe - * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' - */ - -static __devinit int adv7180_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct adv7180_state *state; - struct v4l2_subdev *sd; - int ret; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL); - if (state == NULL) { - ret = -ENOMEM; - goto err; - } - - state->irq = client->irq; - INIT_WORK(&state->work, adv7180_work); - mutex_init(&state->mutex); - state->autodetect = true; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &adv7180_ops); - - /* Initialize adv7180 */ - /* Enable autodetection */ - ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG, - ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM); - if (ret < 0) - goto err_unreg_subdev; - - ret = i2c_smbus_write_byte_data(client, ADV7180_AUTODETECT_ENABLE_REG, - ADV7180_AUTODETECT_DEFAULT); - if (ret < 0) - goto err_unreg_subdev; - - /* ITU-R BT.656-4 compatible */ - ret = i2c_smbus_write_byte_data(client, - ADV7180_EXTENDED_OUTPUT_CONTROL_REG, - ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); - if (ret < 0) - goto err_unreg_subdev; - - /* read current norm */ - __adv7180_status(client, NULL, &state->curr_norm); - - /* register for interrupts */ - if (state->irq > 0) { - ret = request_irq(state->irq, adv7180_irq, 0, DRIVER_NAME, - state); - if (ret) - goto err_unreg_subdev; - - ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, - ADV7180_ADI_CTRL_IRQ_SPACE); - if (ret < 0) - goto err_unreg_subdev; - - /* config the Interrupt pin to be active low */ - ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI, - ADV7180_ICONF1_ACTIVE_LOW | ADV7180_ICONF1_PSYNC_ONLY); - if (ret < 0) - goto err_unreg_subdev; - - ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0); - if (ret < 0) - goto err_unreg_subdev; - - ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0); - if (ret < 0) - goto err_unreg_subdev; - - /* enable AD change interrupts interrupts */ - ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI, - ADV7180_IRQ3_AD_CHANGE); - if (ret < 0) - goto err_unreg_subdev; - - ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0); - if (ret < 0) - goto err_unreg_subdev; - - ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, - 0); - if (ret < 0) - goto err_unreg_subdev; - } - - return 0; - -err_unreg_subdev: - mutex_destroy(&state->mutex); - v4l2_device_unregister_subdev(sd); - kfree(state); -err: - printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", ret); - return ret; -} - -static __devexit int adv7180_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct adv7180_state *state = to_state(sd); - - if (state->irq > 0) { - free_irq(client->irq, state); - if (cancel_work_sync(&state->work)) { - /* - * Work was pending, therefore we need to enable - * IRQ here to balance the disable_irq() done in the - * interrupt handler. - */ - enable_irq(state->irq); - } - } - - mutex_destroy(&state->mutex); - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id adv7180_id[] = { - {DRIVER_NAME, 0}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, adv7180_id); - -static struct i2c_driver adv7180_driver = { - .driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - }, - .probe = adv7180_probe, - .remove = __devexit_p(adv7180_remove), - .id_table = adv7180_id, -}; - -static __init int adv7180_init(void) -{ - return i2c_add_driver(&adv7180_driver); -} - -static __exit void adv7180_exit(void) -{ - i2c_del_driver(&adv7180_driver); -} - -module_init(adv7180_init); -module_exit(adv7180_exit); - -MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); -MODULE_AUTHOR("Mocean Laboratories"); -MODULE_LICENSE("GPL v2"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7343.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7343.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7343.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7343.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,489 +0,0 @@ -/* - * adv7343 - ADV7343 Video Encoder Driver - * - * The encoder hardware does not support SECAM. - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "adv7343_regs.h" - -MODULE_DESCRIPTION("ADV7343 video encoder driver"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -struct adv7343_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - u8 reg00; - u8 reg01; - u8 reg02; - u8 reg35; - u8 reg80; - u8 reg82; - u32 output; - v4l2_std_id std; -}; - -static inline struct adv7343_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct adv7343_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd; -} - -static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_write_byte_data(client, reg, value); -} - -static const u8 adv7343_init_reg_val[] = { - ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT, - ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT, - - ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT, - ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT, - ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT, - ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT, - ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT, - ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT, - ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT, - - ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT, - ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT, - ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT, - ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT, - ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT, - ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT, - ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT, - ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT, - - ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT, - ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT, - ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT, -}; - -/* - * 2^32 - * FSC(reg) = FSC (HZ) * -------- - * 27000000 - */ -static const struct adv7343_std_info stdinfo[] = { - { - /* FSC(Hz) = 3,579,545.45 Hz */ - SD_STD_NTSC, 569408542, V4L2_STD_NTSC, - }, { - /* FSC(Hz) = 3,575,611.00 Hz */ - SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M, - }, { - /* FSC(Hz) = 3,582,056.00 */ - SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc, - }, { - /* FSC(Hz) = 4,433,618.75 Hz */ - SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N, - }, { - /* FSC(Hz) = 4,433,618.75 Hz */ - SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL, - }, { - /* FSC(Hz) = 4,433,618.75 Hz */ - SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443, - }, { - /* FSC(Hz) = 4,433,618.75 Hz */ - SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60, - }, -}; - -static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct adv7343_state *state = to_state(sd); - struct adv7343_std_info *std_info; - int output_idx, num_std; - char *fsc_ptr; - u8 reg, val; - int err = 0; - int i = 0; - - output_idx = state->output; - - std_info = (struct adv7343_std_info *)stdinfo; - num_std = ARRAY_SIZE(stdinfo); - - for (i = 0; i < num_std; i++) { - if (std_info[i].stdid & std) - break; - } - - if (i == num_std) { - v4l2_dbg(1, debug, sd, - "Invalid std or std is not supported: %llx\n", - (unsigned long long)std); - return -EINVAL; - } - - /* Set the standard */ - val = state->reg80 & (~(SD_STD_MASK)); - val |= std_info[i].standard_val3; - err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); - if (err < 0) - goto setstd_exit; - - state->reg80 = val; - - /* Configure the input mode register */ - val = state->reg01 & (~((u8) INPUT_MODE_MASK)); - val |= SD_INPUT_MODE; - err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val); - if (err < 0) - goto setstd_exit; - - state->reg01 = val; - - /* Program the sub carrier frequency registers */ - fsc_ptr = (unsigned char *)&std_info[i].fsc_val; - reg = ADV7343_FSC_REG0; - for (i = 0; i < 4; i++, reg++, fsc_ptr++) { - err = adv7343_write(sd, reg, *fsc_ptr); - if (err < 0) - goto setstd_exit; - } - - val = state->reg80; - - /* Filter settings */ - if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443)) - val &= 0x03; - else if (std & ~V4L2_STD_SECAM) - val |= 0x04; - - err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); - if (err < 0) - goto setstd_exit; - - state->reg80 = val; - -setstd_exit: - if (err != 0) - v4l2_err(sd, "Error setting std, write failed\n"); - - return err; -} - -static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type) -{ - struct adv7343_state *state = to_state(sd); - unsigned char val; - int err = 0; - - if (output_type > ADV7343_SVIDEO_ID) { - v4l2_dbg(1, debug, sd, - "Invalid output type or output type not supported:%d\n", - output_type); - return -EINVAL; - } - - /* Enable Appropriate DAC */ - val = state->reg00 & 0x03; - - if (output_type == ADV7343_COMPOSITE_ID) - val |= ADV7343_COMPOSITE_POWER_VALUE; - else if (output_type == ADV7343_COMPONENT_ID) - val |= ADV7343_COMPONENT_POWER_VALUE; - else - val |= ADV7343_SVIDEO_POWER_VALUE; - - err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val); - if (err < 0) - goto setoutput_exit; - - state->reg00 = val; - - /* Enable YUV output */ - val = state->reg02 | YUV_OUTPUT_SELECT; - err = adv7343_write(sd, ADV7343_MODE_REG0, val); - if (err < 0) - goto setoutput_exit; - - state->reg02 = val; - - /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */ - val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI); - err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val); - if (err < 0) - goto setoutput_exit; - - state->reg82 = val; - - /* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to - * zero */ - val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI); - err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val); - if (err < 0) - goto setoutput_exit; - - state->reg35 = val; - -setoutput_exit: - if (err != 0) - v4l2_err(sd, "Error setting output, write failed\n"); - - return err; -} - -static int adv7343_log_status(struct v4l2_subdev *sd) -{ - struct adv7343_state *state = to_state(sd); - - v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std); - v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" : - ((state->output == 1) ? "Component" : "S-Video")); - return 0; -} - -static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, - ctrl->val); - - case V4L2_CID_HUE: - return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val); - - case V4L2_CID_GAIN: - return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val); - } - return -EINVAL; -} - -static int adv7343_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0); -} - -static const struct v4l2_ctrl_ops adv7343_ctrl_ops = { - .s_ctrl = adv7343_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops adv7343_core_ops = { - .log_status = adv7343_log_status, - .g_chip_ident = adv7343_g_chip_ident, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - -static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct adv7343_state *state = to_state(sd); - int err = 0; - - if (state->std == std) - return 0; - - err = adv7343_setstd(sd, std); - if (!err) - state->std = std; - - return err; -} - -static int adv7343_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct adv7343_state *state = to_state(sd); - int err = 0; - - if (state->output == output) - return 0; - - err = adv7343_setoutput(sd, output); - if (!err) - state->output = output; - - return err; -} - -static const struct v4l2_subdev_video_ops adv7343_video_ops = { - .s_std_output = adv7343_s_std_output, - .s_routing = adv7343_s_routing, -}; - -static const struct v4l2_subdev_ops adv7343_ops = { - .core = &adv7343_core_ops, - .video = &adv7343_video_ops, -}; - -static int adv7343_initialize(struct v4l2_subdev *sd) -{ - struct adv7343_state *state = to_state(sd); - int err = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) { - - err = adv7343_write(sd, adv7343_init_reg_val[i], - adv7343_init_reg_val[i+1]); - if (err) { - v4l2_err(sd, "Error initializing\n"); - return err; - } - } - - /* Configure for default video standard */ - err = adv7343_setoutput(sd, state->output); - if (err < 0) { - v4l2_err(sd, "Error setting output during init\n"); - return -EINVAL; - } - - err = adv7343_setstd(sd, state->std); - if (err < 0) { - v4l2_err(sd, "Error setting std during init\n"); - return -EINVAL; - } - - return err; -} - -static int adv7343_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct adv7343_state *state; - int err; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - - state->reg00 = 0x80; - state->reg01 = 0x00; - state->reg02 = 0x20; - state->reg35 = 0x00; - state->reg80 = ADV7343_SD_MODE_REG1_DEFAULT; - state->reg82 = ADV7343_SD_MODE_REG2_DEFAULT; - - state->output = ADV7343_COMPOSITE_ID; - state->std = V4L2_STD_NTSC; - - v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops); - - v4l2_ctrl_handler_init(&state->hdl, 2); - v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, - V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN, - ADV7343_BRIGHTNESS_MAX, 1, - ADV7343_BRIGHTNESS_DEF); - v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, - V4L2_CID_HUE, ADV7343_HUE_MIN, - ADV7343_HUE_MAX, 1, - ADV7343_HUE_DEF); - v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, - V4L2_CID_GAIN, ADV7343_GAIN_MIN, - ADV7343_GAIN_MAX, 1, - ADV7343_GAIN_DEF); - state->sd.ctrl_handler = &state->hdl; - if (state->hdl.error) { - int err = state->hdl.error; - - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return err; - } - v4l2_ctrl_handler_setup(&state->hdl); - - err = adv7343_initialize(&state->sd); - if (err) { - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - } - return err; -} - -static int adv7343_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct adv7343_state *state = to_state(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - - return 0; -} - -static const struct i2c_device_id adv7343_id[] = { - {"adv7343", 0}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, adv7343_id); - -static struct i2c_driver adv7343_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "adv7343", - }, - .probe = adv7343_probe, - .remove = adv7343_remove, - .id_table = adv7343_id, -}; - -static __init int init_adv7343(void) -{ - return i2c_add_driver(&adv7343_driver); -} - -static __exit void exit_adv7343(void) -{ - i2c_del_driver(&adv7343_driver); -} - -module_init(init_adv7343); -module_exit(exit_adv7343); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7343_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7343_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7343_regs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/adv7343_regs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,181 +0,0 @@ -/* - * ADV7343 encoder related structure and register definitions - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef ADV7343_REG_H -#define ADV7343_REGS_H - -struct adv7343_std_info { - u32 standard_val3; - u32 fsc_val; - v4l2_std_id stdid; -}; - -/* Register offset macros */ -#define ADV7343_POWER_MODE_REG (0x00) -#define ADV7343_MODE_SELECT_REG (0x01) -#define ADV7343_MODE_REG0 (0x02) - -#define ADV7343_DAC2_OUTPUT_LEVEL (0x0b) - -#define ADV7343_SOFT_RESET (0x17) - -#define ADV7343_HD_MODE_REG1 (0x30) -#define ADV7343_HD_MODE_REG2 (0x31) -#define ADV7343_HD_MODE_REG3 (0x32) -#define ADV7343_HD_MODE_REG4 (0x33) -#define ADV7343_HD_MODE_REG5 (0x34) -#define ADV7343_HD_MODE_REG6 (0x35) - -#define ADV7343_HD_MODE_REG7 (0x39) - -#define ADV7343_SD_MODE_REG1 (0x80) -#define ADV7343_SD_MODE_REG2 (0x82) -#define ADV7343_SD_MODE_REG3 (0x83) -#define ADV7343_SD_MODE_REG4 (0x84) -#define ADV7343_SD_MODE_REG5 (0x86) -#define ADV7343_SD_MODE_REG6 (0x87) -#define ADV7343_SD_MODE_REG7 (0x88) -#define ADV7343_SD_MODE_REG8 (0x89) - -#define ADV7343_FSC_REG0 (0x8C) -#define ADV7343_FSC_REG1 (0x8D) -#define ADV7343_FSC_REG2 (0x8E) -#define ADV7343_FSC_REG3 (0x8F) - -#define ADV7343_SD_CGMS_WSS0 (0x99) - -#define ADV7343_SD_HUE_REG (0xA0) -#define ADV7343_SD_BRIGHTNESS_WSS (0xA1) - -/* Default values for the registers */ -#define ADV7343_POWER_MODE_REG_DEFAULT (0x10) -#define ADV7343_HD_MODE_REG1_DEFAULT (0x3C) /* Changed Default - 720p EAVSAV code*/ -#define ADV7343_HD_MODE_REG2_DEFAULT (0x01) /* Changed Pixel data - valid */ -#define ADV7343_HD_MODE_REG3_DEFAULT (0x00) /* Color delay 0 clks */ -#define ADV7343_HD_MODE_REG4_DEFAULT (0xE8) /* Changed */ -#define ADV7343_HD_MODE_REG5_DEFAULT (0x08) -#define ADV7343_HD_MODE_REG6_DEFAULT (0x00) -#define ADV7343_HD_MODE_REG7_DEFAULT (0x00) -#define ADV7343_SD_MODE_REG8_DEFAULT (0x00) -#define ADV7343_SOFT_RESET_DEFAULT (0x02) -#define ADV7343_COMPOSITE_POWER_VALUE (0x80) -#define ADV7343_COMPONENT_POWER_VALUE (0x1C) -#define ADV7343_SVIDEO_POWER_VALUE (0x60) -#define ADV7343_SD_HUE_REG_DEFAULT (127) -#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT (0x03) - -#define ADV7343_SD_CGMS_WSS0_DEFAULT (0x10) - -#define ADV7343_SD_MODE_REG1_DEFAULT (0x00) -#define ADV7343_SD_MODE_REG2_DEFAULT (0xC9) -#define ADV7343_SD_MODE_REG3_DEFAULT (0x10) -#define ADV7343_SD_MODE_REG4_DEFAULT (0x01) -#define ADV7343_SD_MODE_REG5_DEFAULT (0x02) -#define ADV7343_SD_MODE_REG6_DEFAULT (0x0C) -#define ADV7343_SD_MODE_REG7_DEFAULT (0x04) -#define ADV7343_SD_MODE_REG8_DEFAULT (0x00) - -/* Bit masks for Mode Select Register */ -#define INPUT_MODE_MASK (0x70) -#define SD_INPUT_MODE (0x00) -#define HD_720P_INPUT_MODE (0x10) -#define HD_1080I_INPUT_MODE (0x10) - -/* Bit masks for Mode Register 0 */ -#define TEST_PATTERN_BLACK_BAR_EN (0x04) -#define YUV_OUTPUT_SELECT (0x20) -#define RGB_OUTPUT_SELECT (0xDF) - -/* Bit masks for DAC output levels */ -#define DAC_OUTPUT_LEVEL_MASK (0xFF) - -/* Bit masks for soft reset register */ -#define SOFT_RESET (0x02) - -/* Bit masks for HD Mode Register 1 */ -#define OUTPUT_STD_MASK (0x03) -#define OUTPUT_STD_SHIFT (0) -#define OUTPUT_STD_EIA0_2 (0x00) -#define OUTPUT_STD_EIA0_1 (0x01) -#define OUTPUT_STD_FULL (0x02) -#define EMBEDDED_SYNC (0x04) -#define EXTERNAL_SYNC (0xFB) -#define STD_MODE_SHIFT (3) -#define STD_MODE_MASK (0x1F) -#define STD_MODE_720P (0x05) -#define STD_MODE_720P_25 (0x08) -#define STD_MODE_720P_30 (0x07) -#define STD_MODE_720P_50 (0x06) -#define STD_MODE_1080I (0x0D) -#define STD_MODE_1080I_25fps (0x0E) -#define STD_MODE_1080P_24 (0x12) -#define STD_MODE_1080P_25 (0x10) -#define STD_MODE_1080P_30 (0x0F) -#define STD_MODE_525P (0x00) -#define STD_MODE_625P (0x03) - -/* Bit masks for SD Mode Register 1 */ -#define SD_STD_MASK (0x03) -#define SD_STD_NTSC (0x00) -#define SD_STD_PAL_BDGHI (0x01) -#define SD_STD_PAL_M (0x02) -#define SD_STD_PAL_N (0x03) -#define SD_LUMA_FLTR_MASK (0x7) -#define SD_LUMA_FLTR_SHIFT (0x2) -#define SD_CHROMA_FLTR_MASK (0x7) -#define SD_CHROMA_FLTR_SHIFT (0x5) - -/* Bit masks for SD Mode Register 2 */ -#define SD_PBPR_SSAF_EN (0x01) -#define SD_PBPR_SSAF_DI (0xFE) -#define SD_DAC_1_DI (0xFD) -#define SD_DAC_2_DI (0xFB) -#define SD_PEDESTAL_EN (0x08) -#define SD_PEDESTAL_DI (0xF7) -#define SD_SQUARE_PIXEL_EN (0x10) -#define SD_SQUARE_PIXEL_DI (0xEF) -#define SD_PIXEL_DATA_VALID (0x40) -#define SD_ACTIVE_EDGE_EN (0x80) -#define SD_ACTIVE_EDGE_DI (0x7F) - -/* Bit masks for HD Mode Register 6 */ -#define HD_RGB_INPUT_EN (0x02) -#define HD_RGB_INPUT_DI (0xFD) -#define HD_PBPR_SYNC_EN (0x04) -#define HD_PBPR_SYNC_DI (0xFB) -#define HD_DAC_SWAP_EN (0x08) -#define HD_DAC_SWAP_DI (0xF7) -#define HD_GAMMA_CURVE_A (0xEF) -#define HD_GAMMA_CURVE_B (0x10) -#define HD_GAMMA_EN (0x20) -#define HD_GAMMA_DI (0xDF) -#define HD_ADPT_FLTR_MODEB (0x40) -#define HD_ADPT_FLTR_MODEA (0xBF) -#define HD_ADPT_FLTR_EN (0x80) -#define HD_ADPT_FLTR_DI (0x7F) - -#define ADV7343_BRIGHTNESS_MAX (127) -#define ADV7343_BRIGHTNESS_MIN (0) -#define ADV7343_BRIGHTNESS_DEF (3) -#define ADV7343_HUE_MAX (255) -#define ADV7343_HUE_MIN (0) -#define ADV7343_HUE_DEF (127) -#define ADV7343_GAIN_MAX (64) -#define ADV7343_GAIN_MIN (-64) -#define ADV7343_GAIN_DEF (0) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ak881x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ak881x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ak881x.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ak881x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,369 +0,0 @@ -/* - * Driver for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM) - * - * Copyright (C) 2010, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define AK881X_INTERFACE_MODE 0 -#define AK881X_VIDEO_PROCESS1 1 -#define AK881X_VIDEO_PROCESS2 2 -#define AK881X_VIDEO_PROCESS3 3 -#define AK881X_DAC_MODE 5 -#define AK881X_STATUS 0x24 -#define AK881X_DEVICE_ID 0x25 -#define AK881X_DEVICE_REVISION 0x26 - -struct ak881x { - struct v4l2_subdev subdev; - struct ak881x_pdata *pdata; - unsigned int lines; - int id; /* DEVICE_ID code V4L2_IDENT_AK881X code from v4l2-chip-ident.h */ - char revision; /* DEVICE_REVISION content */ -}; - -static int reg_read(struct i2c_client *client, const u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int reg_write(struct i2c_client *client, const u8 reg, - const u8 data) -{ - return i2c_smbus_write_byte_data(client, reg, data); -} - -static int reg_set(struct i2c_client *client, const u8 reg, - const u8 data, u8 mask) -{ - int ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, (ret & ~mask) | (data & mask)); -} - -static struct ak881x *to_ak881x(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct ak881x, subdev); -} - -static int ak881x_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ak881x *ak881x = to_ak881x(client); - - if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) - return -EINVAL; - - if (id->match.addr != client->addr) - return -ENODEV; - - id->ident = ak881x->id; - id->revision = ak881x->revision; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ak881x_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26) - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - reg->val = reg_read(client, reg->reg); - - if (reg->val > 0xffff) - return -EIO; - - return 0; -} - -static int ak881x_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26) - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - if (reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ak881x *ak881x = to_ak881x(client); - - v4l_bound_align_image(&mf->width, 0, 720, 2, - &mf->height, 0, ak881x->lines, 1, 0); - mf->field = V4L2_FIELD_INTERLACED; - mf->code = V4L2_MBUS_FMT_YUYV8_2X8; - mf->colorspace = V4L2_COLORSPACE_SMPTE170M; - - return 0; -} - -static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - if (mf->field != V4L2_FIELD_INTERLACED || - mf->code != V4L2_MBUS_FMT_YUYV8_2X8) - return -EINVAL; - - return ak881x_try_g_mbus_fmt(sd, mf); -} - -static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index) - return -EINVAL; - - *code = V4L2_MBUS_FMT_YUYV8_2X8; - return 0; -} - -static int ak881x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ak881x *ak881x = to_ak881x(client); - - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = 720; - a->bounds.height = ak881x->lines; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ak881x *ak881x = to_ak881x(client); - u8 vp1; - - if (std == V4L2_STD_NTSC_443) { - vp1 = 3; - ak881x->lines = 480; - } else if (std == V4L2_STD_PAL_M) { - vp1 = 5; - ak881x->lines = 480; - } else if (std == V4L2_STD_PAL_60) { - vp1 = 7; - ak881x->lines = 480; - } else if (std && !(std & ~V4L2_STD_PAL)) { - vp1 = 0xf; - ak881x->lines = 576; - } else if (std && !(std & ~V4L2_STD_NTSC)) { - vp1 = 0; - ak881x->lines = 480; - } else { - /* No SECAM or PAL_N/Nc supported */ - return -EINVAL; - } - - reg_set(client, AK881X_VIDEO_PROCESS1, vp1, 0xf); - - return 0; -} - -static int ak881x_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ak881x *ak881x = to_ak881x(client); - - if (enable) { - u8 dac; - /* For colour-bar testing set bit 6 of AK881X_VIDEO_PROCESS1 */ - /* Default: composite output */ - if (ak881x->pdata->flags & AK881X_COMPONENT) - dac = 3; - else - dac = 4; - /* Turn on the DAC(s) */ - reg_write(client, AK881X_DAC_MODE, dac); - dev_dbg(&client->dev, "chip status 0x%x\n", - reg_read(client, AK881X_STATUS)); - } else { - /* ...and clear bit 6 of AK881X_VIDEO_PROCESS1 here */ - reg_write(client, AK881X_DAC_MODE, 0); - dev_dbg(&client->dev, "chip status 0x%x\n", - reg_read(client, AK881X_STATUS)); - } - - return 0; -} - -static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = { - .g_chip_ident = ak881x_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ak881x_g_register, - .s_register = ak881x_s_register, -#endif -}; - -static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = { - .s_mbus_fmt = ak881x_s_mbus_fmt, - .g_mbus_fmt = ak881x_try_g_mbus_fmt, - .try_mbus_fmt = ak881x_try_g_mbus_fmt, - .cropcap = ak881x_cropcap, - .enum_mbus_fmt = ak881x_enum_mbus_fmt, - .s_std_output = ak881x_s_std_output, - .s_stream = ak881x_s_stream, -}; - -static struct v4l2_subdev_ops ak881x_subdev_ops = { - .core = &ak881x_subdev_core_ops, - .video = &ak881x_subdev_video_ops, -}; - -static int ak881x_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct ak881x *ak881x; - u8 ifmode, data; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); - return -EIO; - } - - ak881x = kzalloc(sizeof(struct ak881x), GFP_KERNEL); - if (!ak881x) - return -ENOMEM; - - v4l2_i2c_subdev_init(&ak881x->subdev, client, &ak881x_subdev_ops); - - data = reg_read(client, AK881X_DEVICE_ID); - - switch (data) { - case 0x13: - ak881x->id = V4L2_IDENT_AK8813; - break; - case 0x14: - ak881x->id = V4L2_IDENT_AK8814; - break; - default: - dev_err(&client->dev, - "No ak881x chip detected, register read %x\n", data); - kfree(ak881x); - return -ENODEV; - } - - ak881x->revision = reg_read(client, AK881X_DEVICE_REVISION); - ak881x->pdata = client->dev.platform_data; - - if (ak881x->pdata) { - if (ak881x->pdata->flags & AK881X_FIELD) - ifmode = 4; - else - ifmode = 0; - - switch (ak881x->pdata->flags & AK881X_IF_MODE_MASK) { - case AK881X_IF_MODE_BT656: - ifmode |= 1; - break; - case AK881X_IF_MODE_MASTER: - ifmode |= 2; - break; - case AK881X_IF_MODE_SLAVE: - default: - break; - } - - dev_dbg(&client->dev, "IF mode %x\n", ifmode); - - /* - * "Line Blanking No." seems to be the same as the number of - * "black" lines on, e.g., SuperH VOU, whose default value of 20 - * "incidentally" matches ak881x' default - */ - reg_write(client, AK881X_INTERFACE_MODE, ifmode | (20 << 3)); - } - - /* Hardware default: NTSC-M */ - ak881x->lines = 480; - - dev_info(&client->dev, "Detected an ak881x chip ID %x, revision %x\n", - data, ak881x->revision); - - return 0; -} - -static int ak881x_remove(struct i2c_client *client) -{ - struct ak881x *ak881x = to_ak881x(client); - - v4l2_device_unregister_subdev(&ak881x->subdev); - kfree(ak881x); - - return 0; -} - -static const struct i2c_device_id ak881x_id[] = { - { "ak8813", 0 }, - { "ak8814", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ak881x_id); - -static struct i2c_driver ak881x_i2c_driver = { - .driver = { - .name = "ak881x", - }, - .probe = ak881x_probe, - .remove = ak881x_remove, - .id_table = ak881x_id, -}; - -static int __init ak881x_module_init(void) -{ - return i2c_add_driver(&ak881x_i2c_driver); -} - -static void __exit ak881x_module_exit(void) -{ - i2c_del_driver(&ak881x_i2c_driver); -} - -module_init(ak881x_module_init); -module_exit(ak881x_module_exit); - -MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/arv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/arv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/arv.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/arv.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,881 +0,0 @@ -/* - * Colour AR M64278(VGA) driver for Video4Linux - * - * Copyright (C) 2003 Takeo Takahashi - * - * 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, or (at your option) any later version. - * - * Some code is taken from AR driver sample program for M3T-M32700UT. - * - * AR driver sample (M32R SDK): - * Copyright (c) 2003 RENESAS TECHNOROGY CORPORATION - * AND RENESAS SOLUTIONS CORPORATION - * All Rights Reserved. - * - * 2003-09-01: Support w3cam by Takeo Takahashi - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if 0 -#define DEBUG(n, args...) printk(KERN_INFO args) -#define CHECK_LOST 1 -#else -#define DEBUG(n, args...) -#define CHECK_LOST 0 -#endif - -/* - * USE_INT is always 0, interrupt mode is not available - * on linux due to lack of speed - */ -#define USE_INT 0 /* Don't modify */ - -#define VERSION "0.04" - -#define ar_inl(addr) inl((unsigned long)(addr)) -#define ar_outl(val, addr) outl((unsigned long)(val), (unsigned long)(addr)) - -extern struct cpuinfo_m32r boot_cpu_data; - -/* - * CCD pixel size - * Note that M32700UT does not support CIF mode, but QVGA is - * supported by M32700UT hardware using VGA mode of AR LSI. - * - * Supported: VGA (Normal mode, Interlace mode) - * QVGA (Always Interlace mode of VGA) - * - */ -#define AR_WIDTH_VGA 640 -#define AR_HEIGHT_VGA 480 -#define AR_WIDTH_QVGA 320 -#define AR_HEIGHT_QVGA 240 -#define MIN_AR_WIDTH AR_WIDTH_QVGA -#define MIN_AR_HEIGHT AR_HEIGHT_QVGA -#define MAX_AR_WIDTH AR_WIDTH_VGA -#define MAX_AR_HEIGHT AR_HEIGHT_VGA - -/* bits & bytes per pixel */ -#define AR_BITS_PER_PIXEL 16 -#define AR_BYTES_PER_PIXEL (AR_BITS_PER_PIXEL / 8) - -/* line buffer size */ -#define AR_LINE_BYTES_VGA (AR_WIDTH_VGA * AR_BYTES_PER_PIXEL) -#define AR_LINE_BYTES_QVGA (AR_WIDTH_QVGA * AR_BYTES_PER_PIXEL) -#define MAX_AR_LINE_BYTES AR_LINE_BYTES_VGA - -/* frame size & type */ -#define AR_FRAME_BYTES_VGA \ - (AR_WIDTH_VGA * AR_HEIGHT_VGA * AR_BYTES_PER_PIXEL) -#define AR_FRAME_BYTES_QVGA \ - (AR_WIDTH_QVGA * AR_HEIGHT_QVGA * AR_BYTES_PER_PIXEL) -#define MAX_AR_FRAME_BYTES \ - (MAX_AR_WIDTH * MAX_AR_HEIGHT * AR_BYTES_PER_PIXEL) - -#define AR_MAX_FRAME 15 - -/* capture size */ -#define AR_SIZE_VGA 0 -#define AR_SIZE_QVGA 1 - -/* capture mode */ -#define AR_MODE_INTERLACE 0 -#define AR_MODE_NORMAL 1 - -struct ar { - struct v4l2_device v4l2_dev; - struct video_device vdev; - unsigned int start_capture; /* duaring capture in INT. mode. */ -#if USE_INT - unsigned char *line_buff; /* DMA line buffer */ -#endif - unsigned char *frame[MAX_AR_HEIGHT]; /* frame data */ - short size; /* capture size */ - short mode; /* capture mode */ - int width, height; - int frame_bytes, line_bytes; - wait_queue_head_t wait; - struct mutex lock; -}; - -static struct ar ardev; - -static int video_nr = -1; /* video device number (first free) */ -static unsigned char yuv[MAX_AR_FRAME_BYTES]; - -/* module parameters */ -/* default frequency */ -#define DEFAULT_FREQ 50 /* 50 or 75 (MHz) is available as BCLK */ -static int freq = DEFAULT_FREQ; /* BCLK: available 50 or 70 (MHz) */ -static int vga; /* default mode(0:QVGA mode, other:VGA mode) */ -static int vga_interlace; /* 0 is normal mode for, else interlace mode */ -module_param(freq, int, 0); -module_param(vga, int, 0); -module_param(vga_interlace, int, 0); - -static void wait_for_vsync(void) -{ - while (ar_inl(ARVCR0) & ARVCR0_VDS) /* wait for VSYNC */ - cpu_relax(); - while (!(ar_inl(ARVCR0) & ARVCR0_VDS)) /* wait for VSYNC */ - cpu_relax(); -} - -static void wait_acknowledge(void) -{ - int i; - - for (i = 0; i < 1000; i++) - cpu_relax(); - while (ar_inl(PLDI2CSTS) & PLDI2CSTS_NOACK) - cpu_relax(); -} - -/******************************************************************* - * I2C functions - *******************************************************************/ -static void iic(int n, unsigned long addr, unsigned long data1, unsigned long data2, - unsigned long data3) -{ - int i; - - /* Slave Address */ - ar_outl(addr, PLDI2CDATA); - wait_for_vsync(); - - /* Start */ - ar_outl(1, PLDI2CCND); - wait_acknowledge(); - - /* Transfer data 1 */ - ar_outl(data1, PLDI2CDATA); - wait_for_vsync(); - ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN); - wait_acknowledge(); - - /* Transfer data 2 */ - ar_outl(data2, PLDI2CDATA); - wait_for_vsync(); - ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN); - wait_acknowledge(); - - if (n == 3) { - /* Transfer data 3 */ - ar_outl(data3, PLDI2CDATA); - wait_for_vsync(); - ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN); - wait_acknowledge(); - } - - /* Stop */ - for (i = 0; i < 100; i++) - cpu_relax(); - ar_outl(2, PLDI2CCND); - ar_outl(2, PLDI2CCND); - - while (ar_inl(PLDI2CSTS) & PLDI2CSTS_BB) - cpu_relax(); -} - - -static void init_iic(void) -{ - DEBUG(1, "init_iic:\n"); - - /* - * ICU Setting (iic) - */ - /* I2C Setting */ - ar_outl(0x0, PLDI2CCR); /* I2CCR Disable */ - ar_outl(0x0300, PLDI2CMOD); /* I2CMOD ACK/8b-data/7b-addr/auto */ - ar_outl(0x1, PLDI2CACK); /* I2CACK ACK */ - - /* I2C CLK */ - /* 50MH-100k */ - if (freq == 75) - ar_outl(369, PLDI2CFREQ); /* BCLK = 75MHz */ - else if (freq == 50) - ar_outl(244, PLDI2CFREQ); /* BCLK = 50MHz */ - else - ar_outl(244, PLDI2CFREQ); /* default: BCLK = 50MHz */ - ar_outl(0x1, PLDI2CCR); /* I2CCR Enable */ -} - -/************************************************************************** - * - * Video4Linux Interface functions - * - **************************************************************************/ - -static inline void disable_dma(void) -{ - ar_outl(0x8000, M32R_DMAEN_PORTL); /* disable DMA0 */ -} - -static inline void enable_dma(void) -{ - ar_outl(0x8080, M32R_DMAEN_PORTL); /* enable DMA0 */ -} - -static inline void clear_dma_status(void) -{ - ar_outl(0x8000, M32R_DMAEDET_PORTL); /* clear status */ -} - -static void wait_for_vertical_sync(struct ar *ar, int exp_line) -{ -#if CHECK_LOST - int tmout = 10000; /* FIXME */ - int l; - - /* - * check HCOUNT because we cannot check vertical sync. - */ - for (; tmout >= 0; tmout--) { - l = ar_inl(ARVHCOUNT); - if (l == exp_line) - break; - } - if (tmout < 0) - v4l2_err(&ar->v4l2_dev, "lost %d -> %d\n", exp_line, l); -#else - while (ar_inl(ARVHCOUNT) != exp_line) - cpu_relax(); -#endif -} - -static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - struct ar *ar = video_drvdata(file); - long ret = ar->frame_bytes; /* return read bytes */ - unsigned long arvcr1 = 0; - unsigned long flags; - unsigned char *p; - int h, w; - unsigned char *py, *pu, *pv; -#if !USE_INT - int l; -#endif - - DEBUG(1, "ar_read()\n"); - - if (ar->size == AR_SIZE_QVGA) - arvcr1 |= ARVCR1_QVGA; - if (ar->mode == AR_MODE_NORMAL) - arvcr1 |= ARVCR1_NORMAL; - - mutex_lock(&ar->lock); - -#if USE_INT - local_irq_save(flags); - disable_dma(); - ar_outl(0xa1871300, M32R_DMA0CR0_PORTL); - ar_outl(0x01000000, M32R_DMA0CR1_PORTL); - - /* set AR FIFO address as source(BSEL5) */ - ar_outl(ARDATA32, M32R_DMA0CSA_PORTL); - ar_outl(ARDATA32, M32R_DMA0RSA_PORTL); - ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); /* destination addr. */ - ar_outl(ar->line_buff, M32R_DMA0RDA_PORTL); /* reload address */ - ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL); /* byte count (bytes) */ - ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL); /* reload count (bytes) */ - - /* - * Okay, kick AR LSI to invoke an interrupt - */ - ar->start_capture = 0; - ar_outl(arvcr1 | ARVCR1_HIEN, ARVCR1); - local_irq_restore(flags); - /* .... AR interrupts .... */ - interruptible_sleep_on(&ar->wait); - if (signal_pending(current)) { - printk(KERN_ERR "arv: interrupted while get frame data.\n"); - ret = -EINTR; - goto out_up; - } -#else /* ! USE_INT */ - /* polling */ - ar_outl(arvcr1, ARVCR1); - disable_dma(); - ar_outl(0x8000, M32R_DMAEDET_PORTL); - ar_outl(0xa0861300, M32R_DMA0CR0_PORTL); - ar_outl(0x01000000, M32R_DMA0CR1_PORTL); - ar_outl(ARDATA32, M32R_DMA0CSA_PORTL); - ar_outl(ARDATA32, M32R_DMA0RSA_PORTL); - ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL); - ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL); - - local_irq_save(flags); - while (ar_inl(ARVHCOUNT) != 0) /* wait for 0 */ - cpu_relax(); - if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) { - for (h = 0; h < ar->height; h++) { - wait_for_vertical_sync(ar, h); - if (h < (AR_HEIGHT_VGA/2)) - l = h << 1; - else - l = (((h - (AR_HEIGHT_VGA/2)) << 1) + 1); - ar_outl(virt_to_phys(ar->frame[l]), M32R_DMA0CDA_PORTL); - enable_dma(); - while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000)) - cpu_relax(); - disable_dma(); - clear_dma_status(); - ar_outl(0xa0861300, M32R_DMA0CR0_PORTL); - } - } else { - for (h = 0; h < ar->height; h++) { - wait_for_vertical_sync(ar, h); - ar_outl(virt_to_phys(ar->frame[h]), M32R_DMA0CDA_PORTL); - enable_dma(); - while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000)) - cpu_relax(); - disable_dma(); - clear_dma_status(); - ar_outl(0xa0861300, M32R_DMA0CR0_PORTL); - } - } - local_irq_restore(flags); -#endif /* ! USE_INT */ - - /* - * convert YUV422 to YUV422P - * +--------------------+ - * | Y0,Y1,... | - * | ..............Yn | - * +--------------------+ - * | U0,U1,........Un | - * +--------------------+ - * | V0,V1,........Vn | - * +--------------------+ - */ - py = yuv; - pu = py + (ar->frame_bytes / 2); - pv = pu + (ar->frame_bytes / 4); - for (h = 0; h < ar->height; h++) { - p = ar->frame[h]; - for (w = 0; w < ar->line_bytes; w += 4) { - *py++ = *p++; - *pu++ = *p++; - *py++ = *p++; - *pv++ = *p++; - } - } - if (copy_to_user(buf, yuv, ar->frame_bytes)) { - v4l2_err(&ar->v4l2_dev, "failed while copy_to_user yuv.\n"); - ret = -EFAULT; - goto out_up; - } - DEBUG(1, "ret = %d\n", ret); -out_up: - mutex_unlock(&ar->lock); - return ret; -} - -static int ar_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct ar *ar = video_drvdata(file); - - strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card)); - strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info)); - vcap->version = KERNEL_VERSION(0, 0, 4); - vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - return 0; -} - -static int ar_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - if (vin->index > 0) - return -EINVAL; - strlcpy(vin->name, "Camera", sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = V4L2_STD_ALL; - vin->status = 0; - return 0; -} - -static int ar_g_input(struct file *file, void *fh, unsigned int *inp) -{ - *inp = 0; - return 0; -} - -static int ar_s_input(struct file *file, void *fh, unsigned int inp) -{ - return inp ? -EINVAL : 0; -} - -static int ar_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ar *ar = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = ar->width; - pix->height = ar->height; - pix->pixelformat = V4L2_PIX_FMT_YUV422P; - pix->field = (ar->mode == AR_MODE_NORMAL) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED; - pix->bytesperline = ar->width; - pix->sizeimage = 2 * ar->width * ar->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int ar_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ar *ar = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->height <= AR_HEIGHT_QVGA || pix->width <= AR_WIDTH_QVGA) { - pix->height = AR_HEIGHT_QVGA; - pix->width = AR_WIDTH_QVGA; - pix->field = V4L2_FIELD_INTERLACED; - } else { - pix->height = AR_HEIGHT_VGA; - pix->width = AR_WIDTH_VGA; - pix->field = vga_interlace ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; - } - pix->pixelformat = V4L2_PIX_FMT_YUV422P; - pix->bytesperline = ar->width; - pix->sizeimage = 2 * ar->width * ar->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int ar_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ar *ar = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = ar_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - mutex_lock(&ar->lock); - ar->width = pix->width; - ar->height = pix->height; - if (ar->width == AR_WIDTH_VGA) { - ar->size = AR_SIZE_VGA; - ar->frame_bytes = AR_FRAME_BYTES_VGA; - ar->line_bytes = AR_LINE_BYTES_VGA; - if (vga_interlace) - ar->mode = AR_MODE_INTERLACE; - else - ar->mode = AR_MODE_NORMAL; - } else { - ar->size = AR_SIZE_QVGA; - ar->frame_bytes = AR_FRAME_BYTES_QVGA; - ar->line_bytes = AR_LINE_BYTES_QVGA; - ar->mode = AR_MODE_INTERLACE; - } - /* Ok we figured out what to use from our wide choice */ - mutex_unlock(&ar->lock); - return 0; -} - -static int ar_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "YUV 4:2:2 Planar", V4L2_PIX_FMT_YUV422P, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 0) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -#if USE_INT -/* - * Interrupt handler - */ -static void ar_interrupt(int irq, void *dev) -{ - struct ar *ar = dev; - unsigned int line_count; - unsigned int line_number; - unsigned int arvcr1; - - line_count = ar_inl(ARVHCOUNT); /* line number */ - if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) { - /* operations for interlace mode */ - if (line_count < (AR_HEIGHT_VGA / 2)) /* even line */ - line_number = (line_count << 1); - else /* odd line */ - line_number = - (((line_count - (AR_HEIGHT_VGA / 2)) << 1) + 1); - } else { - line_number = line_count; - } - - if (line_number == 0) { - /* - * It is an interrupt for line 0. - * we have to start capture. - */ - disable_dma(); -#if 0 - ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); /* needless? */ -#endif - memcpy(ar->frame[0], ar->line_buff, ar->line_bytes); -#if 0 - ar_outl(0xa1861300, M32R_DMA0CR0_PORTL); -#endif - enable_dma(); - ar->start_capture = 1; /* during capture */ - return; - } - - if (ar->start_capture == 1 && line_number <= (ar->height - 1)) { - disable_dma(); - memcpy(ar->frame[line_number], ar->line_buff, ar->line_bytes); - - /* - * if captured all line of a frame, disable AR interrupt - * and wake a process up. - */ - if (line_number == (ar->height - 1)) { /* end of line */ - - ar->start_capture = 0; - - /* disable AR interrupt request */ - arvcr1 = ar_inl(ARVCR1); - arvcr1 &= ~ARVCR1_HIEN; /* clear int. flag */ - ar_outl(arvcr1, ARVCR1); /* disable */ - wake_up_interruptible(&ar->wait); - } else { -#if 0 - ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); - ar_outl(0xa1861300, M32R_DMA0CR0_PORTL); -#endif - enable_dma(); - } - } -} -#endif - -/* - * ar_initialize() - * ar_initialize() is called by video_register_device() and - * initializes AR LSI and peripherals. - * - * -1 is returned in all failures. - * 0 is returned in success. - * - */ -static int ar_initialize(struct ar *ar) -{ - unsigned long cr = 0; - int i, found = 0; - - DEBUG(1, "ar_initialize:\n"); - - /* - * initialize AR LSI - */ - ar_outl(0, ARVCR0); /* assert reset of AR LSI */ - for (i = 0; i < 0x18; i++) /* wait for over 10 cycles @ 27MHz */ - cpu_relax(); - ar_outl(ARVCR0_RST, ARVCR0); /* negate reset of AR LSI (enable) */ - for (i = 0; i < 0x40d; i++) /* wait for over 420 cycles @ 27MHz */ - cpu_relax(); - - /* AR uses INT3 of CPU as interrupt pin. */ - ar_outl(ARINTSEL_INT3, ARINTSEL); - - if (ar->size == AR_SIZE_QVGA) - cr |= ARVCR1_QVGA; - if (ar->mode == AR_MODE_NORMAL) - cr |= ARVCR1_NORMAL; - ar_outl(cr, ARVCR1); - - /* - * Initialize IIC so that CPU can communicate with AR LSI, - * and send boot commands to AR LSI. - */ - init_iic(); - - for (i = 0; i < 0x100000; i++) { /* > 0xa1d10, 56ms */ - if ((ar_inl(ARVCR0) & ARVCR0_VDS)) { /* VSYNC */ - found = 1; - break; - } - } - - if (found == 0) - return -ENODEV; - - v4l2_info(&ar->v4l2_dev, "Initializing "); - - iic(2, 0x78, 0x11, 0x01, 0x00); /* start */ - iic(3, 0x78, 0x12, 0x00, 0x06); - iic(3, 0x78, 0x12, 0x12, 0x30); - iic(3, 0x78, 0x12, 0x15, 0x58); - iic(3, 0x78, 0x12, 0x17, 0x30); - printk(KERN_CONT "."); - iic(3, 0x78, 0x12, 0x1a, 0x97); - iic(3, 0x78, 0x12, 0x1b, 0xff); - iic(3, 0x78, 0x12, 0x1c, 0xff); - iic(3, 0x78, 0x12, 0x26, 0x10); - iic(3, 0x78, 0x12, 0x27, 0x00); - printk(KERN_CONT "."); - iic(2, 0x78, 0x34, 0x02, 0x00); - iic(2, 0x78, 0x7a, 0x10, 0x00); - iic(2, 0x78, 0x80, 0x39, 0x00); - iic(2, 0x78, 0x81, 0xe6, 0x00); - iic(2, 0x78, 0x8d, 0x00, 0x00); - printk(KERN_CONT "."); - iic(2, 0x78, 0x8e, 0x0c, 0x00); - iic(2, 0x78, 0x8f, 0x00, 0x00); -#if 0 - iic(2, 0x78, 0x90, 0x00, 0x00); /* AWB on=1 off=0 */ -#endif - iic(2, 0x78, 0x93, 0x01, 0x00); - iic(2, 0x78, 0x94, 0xcd, 0x00); - iic(2, 0x78, 0x95, 0x00, 0x00); - printk(KERN_CONT "."); - iic(2, 0x78, 0x96, 0xa0, 0x00); - iic(2, 0x78, 0x97, 0x00, 0x00); - iic(2, 0x78, 0x98, 0x60, 0x00); - iic(2, 0x78, 0x99, 0x01, 0x00); - iic(2, 0x78, 0x9a, 0x19, 0x00); - printk(KERN_CONT "."); - iic(2, 0x78, 0x9b, 0x02, 0x00); - iic(2, 0x78, 0x9c, 0xe8, 0x00); - iic(2, 0x78, 0x9d, 0x02, 0x00); - iic(2, 0x78, 0x9e, 0x2e, 0x00); - iic(2, 0x78, 0xb8, 0x78, 0x00); - iic(2, 0x78, 0xba, 0x05, 0x00); -#if 0 - iic(2, 0x78, 0x83, 0x8c, 0x00); /* brightness */ -#endif - printk(KERN_CONT "."); - - /* color correction */ - iic(3, 0x78, 0x49, 0x00, 0x95); /* a */ - iic(3, 0x78, 0x49, 0x01, 0x96); /* b */ - iic(3, 0x78, 0x49, 0x03, 0x85); /* c */ - iic(3, 0x78, 0x49, 0x04, 0x97); /* d */ - iic(3, 0x78, 0x49, 0x02, 0x7e); /* e(Lo) */ - iic(3, 0x78, 0x49, 0x05, 0xa4); /* f(Lo) */ - iic(3, 0x78, 0x49, 0x06, 0x04); /* e(Hi) */ - iic(3, 0x78, 0x49, 0x07, 0x04); /* e(Hi) */ - iic(2, 0x78, 0x48, 0x01, 0x00); /* on=1 off=0 */ - - printk(KERN_CONT "."); - iic(2, 0x78, 0x11, 0x00, 0x00); /* end */ - printk(KERN_CONT " done\n"); - return 0; -} - - -/**************************************************************************** - * - * Video4Linux Module functions - * - ****************************************************************************/ - -static const struct v4l2_file_operations ar_fops = { - .owner = THIS_MODULE, - .read = ar_read, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops ar_ioctl_ops = { - .vidioc_querycap = ar_querycap, - .vidioc_g_input = ar_g_input, - .vidioc_s_input = ar_s_input, - .vidioc_enum_input = ar_enum_input, - .vidioc_enum_fmt_vid_cap = ar_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = ar_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = ar_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = ar_try_fmt_vid_cap, -}; - -#define ALIGN4(x) ((((int)(x)) & 0x3) == 0) - -static int __init ar_init(void) -{ - struct ar *ar; - struct v4l2_device *v4l2_dev; - int ret; - int i; - - ar = &ardev; - v4l2_dev = &ar->v4l2_dev; - strlcpy(v4l2_dev->name, "arv", sizeof(v4l2_dev->name)); - v4l2_info(v4l2_dev, "Colour AR VGA driver %s\n", VERSION); - - ret = v4l2_device_register(NULL, v4l2_dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return ret; - } - ret = -EIO; - -#if USE_INT - /* allocate a DMA buffer for 1 line. */ - ar->line_buff = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL | GFP_DMA); - if (ar->line_buff == NULL || !ALIGN4(ar->line_buff)) { - v4l2_err(v4l2_dev, "buffer allocation failed for DMA.\n"); - ret = -ENOMEM; - goto out_end; - } -#endif - /* allocate buffers for a frame */ - for (i = 0; i < MAX_AR_HEIGHT; i++) { - ar->frame[i] = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL); - if (ar->frame[i] == NULL || !ALIGN4(ar->frame[i])) { - v4l2_err(v4l2_dev, "buffer allocation failed for frame.\n"); - ret = -ENOMEM; - goto out_line_buff; - } - } - - strlcpy(ar->vdev.name, "Colour AR VGA", sizeof(ar->vdev.name)); - ar->vdev.v4l2_dev = v4l2_dev; - ar->vdev.fops = &ar_fops; - ar->vdev.ioctl_ops = &ar_ioctl_ops; - ar->vdev.release = video_device_release_empty; - video_set_drvdata(&ar->vdev, ar); - - if (vga) { - ar->width = AR_WIDTH_VGA; - ar->height = AR_HEIGHT_VGA; - ar->size = AR_SIZE_VGA; - ar->frame_bytes = AR_FRAME_BYTES_VGA; - ar->line_bytes = AR_LINE_BYTES_VGA; - if (vga_interlace) - ar->mode = AR_MODE_INTERLACE; - else - ar->mode = AR_MODE_NORMAL; - } else { - ar->width = AR_WIDTH_QVGA; - ar->height = AR_HEIGHT_QVGA; - ar->size = AR_SIZE_QVGA; - ar->frame_bytes = AR_FRAME_BYTES_QVGA; - ar->line_bytes = AR_LINE_BYTES_QVGA; - ar->mode = AR_MODE_INTERLACE; - } - mutex_init(&ar->lock); - init_waitqueue_head(&ar->wait); - -#if USE_INT - if (request_irq(M32R_IRQ_INT3, ar_interrupt, 0, "arv", ar)) { - v4l2_err("request_irq(%d) failed.\n", M32R_IRQ_INT3); - ret = -EIO; - goto out_irq; - } -#endif - - if (ar_initialize(ar) != 0) { - v4l2_err(v4l2_dev, "M64278 not found.\n"); - ret = -ENODEV; - goto out_dev; - } - - /* - * ok, we can initialize h/w according to parameters, - * so register video device as a frame grabber type. - * device is named "video[0-64]". - * video_register_device() initializes h/w using ar_initialize(). - */ - if (video_register_device(&ar->vdev, VFL_TYPE_GRABBER, video_nr) != 0) { - /* return -1, -ENFILE(full) or others */ - v4l2_err(v4l2_dev, "register video (Colour AR) failed.\n"); - ret = -ENODEV; - goto out_dev; - } - - v4l2_info(v4l2_dev, "%s: Found M64278 VGA (IRQ %d, Freq %dMHz).\n", - video_device_node_name(&ar->vdev), M32R_IRQ_INT3, freq); - - return 0; - -out_dev: -#if USE_INT - free_irq(M32R_IRQ_INT3, ar); - -out_irq: -#endif - for (i = 0; i < MAX_AR_HEIGHT; i++) - kfree(ar->frame[i]); - -out_line_buff: -#if USE_INT - kfree(ar->line_buff); - -out_end: -#endif - v4l2_device_unregister(&ar->v4l2_dev); - return ret; -} - - -static int __init ar_init_module(void) -{ - freq = (boot_cpu_data.bus_clock / 1000000); - printk(KERN_INFO "arv: Bus clock %d\n", freq); - if (freq != 50 && freq != 75) - freq = DEFAULT_FREQ; - return ar_init(); -} - -static void __exit ar_cleanup_module(void) -{ - struct ar *ar; - int i; - - ar = &ardev; - video_unregister_device(&ar->vdev); -#if USE_INT - free_irq(M32R_IRQ_INT3, ar); -#endif - for (i = 0; i < MAX_AR_HEIGHT; i++) - kfree(ar->frame[i]); -#if USE_INT - kfree(ar->line_buff); -#endif - v4l2_device_unregister(&ar->v4l2_dev); -} - -module_init(ar_init_module); -module_exit(ar_cleanup_module); - -MODULE_AUTHOR("Takeo Takahashi "); -MODULE_DESCRIPTION("Colour AR M64278(VGA) for Video4Linux"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-cards.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,330 +0,0 @@ -/* - * Driver for the Auvitek USB bridge - * - * Copyright (c) 2008 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "au0828.h" -#include "au0828-cards.h" -#include "au8522.h" -#include "media/tuner.h" -#include "media/v4l2-common.h" - -void hvr950q_cs5340_audio(void *priv, int enable) -{ - /* Because the HVR-950q shares an i2s bus between the cs5340 and the - au8522, we need to hold cs5340 in reset when using the au8522 */ - struct au0828_dev *dev = priv; - if (enable == 1) - au0828_set(dev, REG_000, 0x10); - else - au0828_clear(dev, REG_000, 0x10); -} - -struct au0828_board au0828_boards[] = { - [AU0828_BOARD_UNKNOWN] = { - .name = "Unknown board", - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [AU0828_BOARD_HAUPPAUGE_HVR850] = { - .name = "Hauppauge HVR850", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x61, - .i2c_clk_divider = AU0828_I2C_CLK_30KHZ, - .input = { - { - .type = AU0828_VMUX_TELEVISION, - .vmux = AU8522_COMPOSITE_CH4_SIF, - .amux = AU8522_AUDIO_SIF, - }, - { - .type = AU0828_VMUX_COMPOSITE, - .vmux = AU8522_COMPOSITE_CH1, - .amux = AU8522_AUDIO_NONE, - .audio_setup = hvr950q_cs5340_audio, - }, - { - .type = AU0828_VMUX_SVIDEO, - .vmux = AU8522_SVIDEO_CH13, - .amux = AU8522_AUDIO_NONE, - .audio_setup = hvr950q_cs5340_audio, - }, - }, - }, - [AU0828_BOARD_HAUPPAUGE_HVR950Q] = { - .name = "Hauppauge HVR950Q", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x61, - /* The au0828 hardware i2c implementation does not properly - support the xc5000's i2c clock stretching. So we need to - lower the clock frequency enough where the 15us clock - stretch fits inside of a normal clock cycle, or else the - au0828 fails to set the STOP bit. A 30 KHz clock puts the - clock pulse width at 18us */ - .i2c_clk_divider = AU0828_I2C_CLK_30KHZ, - .input = { - { - .type = AU0828_VMUX_TELEVISION, - .vmux = AU8522_COMPOSITE_CH4_SIF, - .amux = AU8522_AUDIO_SIF, - }, - { - .type = AU0828_VMUX_COMPOSITE, - .vmux = AU8522_COMPOSITE_CH1, - .amux = AU8522_AUDIO_NONE, - .audio_setup = hvr950q_cs5340_audio, - }, - { - .type = AU0828_VMUX_SVIDEO, - .vmux = AU8522_SVIDEO_CH13, - .amux = AU8522_AUDIO_NONE, - .audio_setup = hvr950q_cs5340_audio, - }, - }, - }, - [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = { - .name = "Hauppauge HVR950Q rev xxF8", - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, - }, - [AU0828_BOARD_DVICO_FUSIONHDTV7] = { - .name = "DViCO FusionHDTV USB", - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, - }, - [AU0828_BOARD_HAUPPAUGE_WOODBURY] = { - .name = "Hauppauge Woodbury", - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, - }, -}; - -/* Tuner callback function for au0828 boards. Currently only needed - * for HVR1500Q, which has an xc5000 tuner. - */ -int au0828_tuner_callback(void *priv, int component, int command, int arg) -{ - struct au0828_dev *dev = priv; - - dprintk(1, "%s()\n", __func__); - - switch (dev->boardnr) { - case AU0828_BOARD_HAUPPAUGE_HVR850: - case AU0828_BOARD_HAUPPAUGE_HVR950Q: - case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: - case AU0828_BOARD_DVICO_FUSIONHDTV7: - if (command == 0) { - /* Tuner Reset Command from xc5000 */ - /* Drive the tuner into reset and out */ - au0828_clear(dev, REG_001, 2); - mdelay(10); - au0828_set(dev, REG_001, 2); - mdelay(10); - return 0; - } else { - printk(KERN_ERR - "%s(): Unknown command.\n", __func__); - return -EINVAL; - } - break; - } - - return 0; /* Should never be here */ -} - -static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) -{ - struct tveeprom tv; - - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); - dev->board.tuner_type = tv.tuner_type; - - /* Make sure we support the board model */ - switch (tv.model) { - case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */ - case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ - case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ - case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ - case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ - case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */ - case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ - case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */ - case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ - break; - default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", __func__, tv.model); - break; - } - - printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", - __func__, tv.model); -} - -void au0828_card_setup(struct au0828_dev *dev) -{ - static u8 eeprom[256]; - struct tuner_setup tun_setup; - struct v4l2_subdev *sd; - unsigned int mode_mask = T_ANALOG_TV; - - dprintk(1, "%s()\n", __func__); - - memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board)); - - if (dev->i2c_rc == 0) { - dev->i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom)); - } - - switch (dev->boardnr) { - case AU0828_BOARD_HAUPPAUGE_HVR850: - case AU0828_BOARD_HAUPPAUGE_HVR950Q: - case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: - case AU0828_BOARD_HAUPPAUGE_WOODBURY: - if (dev->i2c_rc == 0) - hauppauge_eeprom(dev, eeprom+0xa0); - break; - } - - if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) { - /* Load the analog demodulator driver (note this would need to - be abstracted out if we ever need to support a different - demod) */ - sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "au8522", 0x8e >> 1, NULL); - if (sd == NULL) - printk(KERN_ERR "analog subdev registration failed\n"); - } - - /* Setup tuners */ - if (dev->board.tuner_type != TUNER_ABSENT) { - /* Load the tuner module, which does the attach */ - sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tuner", dev->board.tuner_addr, NULL); - if (sd == NULL) - printk(KERN_ERR "tuner subdev registration fail\n"); - - tun_setup.mode_mask = mode_mask; - tun_setup.type = dev->board.tuner_type; - tun_setup.addr = dev->board.tuner_addr; - tun_setup.tuner_callback = au0828_tuner_callback; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, - &tun_setup); - } -} - -/* - * The bridge has between 8 and 12 gpios. - * Regs 1 and 0 deal with output enables. - * Regs 3 and 2 deal with direction. - */ -void au0828_gpio_setup(struct au0828_dev *dev) -{ - dprintk(1, "%s()\n", __func__); - - switch (dev->boardnr) { - case AU0828_BOARD_HAUPPAUGE_HVR850: - case AU0828_BOARD_HAUPPAUGE_HVR950Q: - case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: - case AU0828_BOARD_HAUPPAUGE_WOODBURY: - /* GPIO's - * 4 - CS5340 - * 5 - AU8522 Demodulator - * 6 - eeprom W/P - * 7 - power supply - * 9 - XC5000 Tuner - */ - - /* Into reset */ - au0828_write(dev, REG_003, 0x02); - au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10); - au0828_write(dev, REG_001, 0x0); - au0828_write(dev, REG_000, 0x0); - msleep(100); - - /* Out of reset (leave the cs5340 in reset until needed) */ - au0828_write(dev, REG_003, 0x02); - au0828_write(dev, REG_001, 0x02); - au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10); - au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20); - - msleep(250); - break; - case AU0828_BOARD_DVICO_FUSIONHDTV7: - /* GPIO's - * 6 - ? - * 8 - AU8522 Demodulator - * 9 - XC5000 Tuner - */ - - /* Into reset */ - au0828_write(dev, REG_003, 0x02); - au0828_write(dev, REG_002, 0xa0); - au0828_write(dev, REG_001, 0x0); - au0828_write(dev, REG_000, 0x0); - msleep(100); - - /* Out of reset */ - au0828_write(dev, REG_003, 0x02); - au0828_write(dev, REG_002, 0xa0); - au0828_write(dev, REG_001, 0x02); - au0828_write(dev, REG_000, 0xa0); - msleep(250); - break; - } -} - -/* table of devices that work with this driver */ -struct usb_device_id au0828_usb_id_table[] = { - { USB_DEVICE(0x2040, 0x7200), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, - { USB_DEVICE(0x2040, 0x7240), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 }, - { USB_DEVICE(0x0fe9, 0xd620), - .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 }, - { USB_DEVICE(0x2040, 0x7210), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, - { USB_DEVICE(0x2040, 0x7217), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, - { USB_DEVICE(0x2040, 0x721b), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, - { USB_DEVICE(0x2040, 0x721e), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, - { USB_DEVICE(0x2040, 0x721f), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, - { USB_DEVICE(0x2040, 0x7280), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, - { USB_DEVICE(0x0fd9, 0x0008), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, - { USB_DEVICE(0x2040, 0x7201), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, - { USB_DEVICE(0x2040, 0x7211), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, - { USB_DEVICE(0x2040, 0x7281), - .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, - { USB_DEVICE(0x2040, 0x8200), - .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, - { }, -}; - -MODULE_DEVICE_TABLE(usb, au0828_usb_id_table); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-cards.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-cards.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-cards.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-cards.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* - * Driver for the Auvitek USB bridge - * - * Copyright (c) 2008 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define AU0828_BOARD_UNKNOWN 0 -#define AU0828_BOARD_HAUPPAUGE_HVR950Q 1 -#define AU0828_BOARD_HAUPPAUGE_HVR850 2 -#define AU0828_BOARD_DVICO_FUSIONHDTV7 3 -#define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL 4 -#define AU0828_BOARD_HAUPPAUGE_WOODBURY 5 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,294 +0,0 @@ -/* - * Driver for the Auvitek USB bridge - * - * Copyright (c) 2008 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "au0828.h" - -/* - * 1 = General debug messages - * 2 = USB handling - * 4 = I2C related - * 8 = Bridge related - */ -int au0828_debug; -module_param_named(debug, au0828_debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); - -static unsigned int disable_usb_speed_check; -module_param(disable_usb_speed_check, int, 0444); -MODULE_PARM_DESC(disable_usb_speed_check, - "override min bandwidth requirement of 480M bps"); - -#define _AU0828_BULKPIPE 0x03 -#define _BULKPIPESIZE 0xffff - -static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, - u16 index, unsigned char *cp, u16 size); -static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, - u16 index, unsigned char *cp, u16 size); - -/* USB Direction */ -#define CMD_REQUEST_IN 0x00 -#define CMD_REQUEST_OUT 0x01 - -u32 au0828_readreg(struct au0828_dev *dev, u16 reg) -{ - recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1); - dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, dev->ctrlmsg[0]); - return dev->ctrlmsg[0]; -} - -u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val) -{ - dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val); - return send_control_msg(dev, CMD_REQUEST_OUT, val, reg, - dev->ctrlmsg, 0); -} - -static void cmd_msg_dump(struct au0828_dev *dev) -{ - int i; - - for (i = 0; i < sizeof(dev->ctrlmsg); i += 16) - dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - __func__, - dev->ctrlmsg[i+0], dev->ctrlmsg[i+1], - dev->ctrlmsg[i+2], dev->ctrlmsg[i+3], - dev->ctrlmsg[i+4], dev->ctrlmsg[i+5], - dev->ctrlmsg[i+6], dev->ctrlmsg[i+7], - dev->ctrlmsg[i+8], dev->ctrlmsg[i+9], - dev->ctrlmsg[i+10], dev->ctrlmsg[i+11], - dev->ctrlmsg[i+12], dev->ctrlmsg[i+13], - dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]); -} - -static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, - u16 index, unsigned char *cp, u16 size) -{ - int status = -ENODEV; - mutex_lock(&dev->mutex); - if (dev->usbdev) { - - /* cp must be memory that has been allocated by kmalloc */ - status = usb_control_msg(dev->usbdev, - usb_sndctrlpipe(dev->usbdev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, - value, index, - cp, size, 1000); - - status = min(status, 0); - - if (status < 0) { - printk(KERN_ERR "%s() Failed sending control message, error %d.\n", - __func__, status); - } - - } - mutex_unlock(&dev->mutex); - return status; -} - -static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, - u16 index, unsigned char *cp, u16 size) -{ - int status = -ENODEV; - mutex_lock(&dev->mutex); - if (dev->usbdev) { - - memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg)); - - /* cp must be memory that has been allocated by kmalloc */ - status = usb_control_msg(dev->usbdev, - usb_rcvctrlpipe(dev->usbdev, 0), - request, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, - cp, size, 1000); - - status = min(status, 0); - - if (status < 0) { - printk(KERN_ERR "%s() Failed receiving control message, error %d.\n", - __func__, status); - } else - cmd_msg_dump(dev); - } - mutex_unlock(&dev->mutex); - return status; -} - -static void au0828_usb_disconnect(struct usb_interface *interface) -{ - struct au0828_dev *dev = usb_get_intfdata(interface); - - dprintk(1, "%s()\n", __func__); - - /* Digital TV */ - au0828_dvb_unregister(dev); - - if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) - au0828_analog_unregister(dev); - - /* I2C */ - au0828_i2c_unregister(dev); - - v4l2_device_unregister(&dev->v4l2_dev); - - usb_set_intfdata(interface, NULL); - - mutex_lock(&dev->mutex); - dev->usbdev = NULL; - mutex_unlock(&dev->mutex); - - kfree(dev); - -} - -static int au0828_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - int ifnum, retval; - struct au0828_dev *dev; - struct usb_device *usbdev = interface_to_usbdev(interface); - - ifnum = interface->altsetting->desc.bInterfaceNumber; - - if (ifnum != 0) - return -ENODEV; - - dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__, - le16_to_cpu(usbdev->descriptor.idVendor), - le16_to_cpu(usbdev->descriptor.idProduct), - ifnum); - - /* - * Make sure we have 480 Mbps of bandwidth, otherwise things like - * video stream wouldn't likely work, since 12 Mbps is generally - * not enough even for most Digital TV streams. - */ - if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - printk(KERN_ERR "au0828: Device initialization failed.\n"); - printk(KERN_ERR "au0828: Device must be connected to a " - "high-speed USB 2.0 port.\n"); - return -ENODEV; - } - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - printk(KERN_ERR "%s() Unable to allocate memory\n", __func__); - return -ENOMEM; - } - - mutex_init(&dev->mutex); - mutex_init(&dev->dvb.lock); - dev->usbdev = usbdev; - dev->boardnr = id->driver_info; - - /* Create the v4l2_device */ - retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); - if (retval) { - printk(KERN_ERR "%s() v4l2_device_register failed\n", - __func__); - kfree(dev); - return -EIO; - } - - /* Power Up the bridge */ - au0828_write(dev, REG_600, 1 << 4); - - /* Bring up the GPIO's and supporting devices */ - au0828_gpio_setup(dev); - - /* I2C */ - au0828_i2c_register(dev); - - /* Setup */ - au0828_card_setup(dev); - - /* Analog TV */ - if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) - au0828_analog_register(dev, interface); - - /* Digital TV */ - au0828_dvb_register(dev); - - /* Store the pointer to the au0828_dev so it can be accessed in - au0828_usb_disconnect */ - usb_set_intfdata(interface, dev); - - printk(KERN_INFO "Registered device AU0828 [%s]\n", - dev->board.name == NULL ? "Unset" : dev->board.name); - - return 0; -} - -static struct usb_driver au0828_usb_driver = { - .name = DRIVER_NAME, - .probe = au0828_usb_probe, - .disconnect = au0828_usb_disconnect, - .id_table = au0828_usb_id_table, -}; - -static int __init au0828_init(void) -{ - int ret; - - if (au0828_debug & 1) - printk(KERN_INFO "%s() Debugging is enabled\n", __func__); - - if (au0828_debug & 2) - printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__); - - if (au0828_debug & 4) - printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__); - - if (au0828_debug & 8) - printk(KERN_INFO "%s() Bridge Debugging is enabled\n", - __func__); - - printk(KERN_INFO "au0828 driver loaded\n"); - - ret = usb_register(&au0828_usb_driver); - if (ret) - printk(KERN_ERR "usb_register failed, error = %d\n", ret); - - return ret; -} - -static void __exit au0828_exit(void) -{ - usb_deregister(&au0828_usb_driver); -} - -module_init(au0828_init); -module_exit(au0828_exit); - -MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); -MODULE_AUTHOR("Steven Toth "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-dvb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,439 +0,0 @@ -/* - * Driver for the Auvitek USB bridge - * - * Copyright (c) 2008 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "au0828.h" -#include "au8522.h" -#include "xc5000.h" -#include "mxl5007t.h" -#include "tda18271.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define _AU0828_BULKPIPE 0x83 -#define _BULKPIPESIZE 0xe522 - -static u8 hauppauge_hvr950q_led_states[] = { - 0x00, /* off */ - 0x02, /* yellow */ - 0x04, /* green */ -}; - -static struct au8522_led_config hauppauge_hvr950q_led_cfg = { - .gpio_output = 0x00e0, - .gpio_output_enable = 0x6006, - .gpio_output_disable = 0x0660, - - .gpio_leds = 0x00e2, - .led_states = hauppauge_hvr950q_led_states, - .num_led_states = sizeof(hauppauge_hvr950q_led_states), - - .vsb8_strong = 20 /* dB */ * 10, - .qam64_strong = 25 /* dB */ * 10, - .qam256_strong = 32 /* dB */ * 10, -}; - -static struct au8522_config hauppauge_hvr950q_config = { - .demod_address = 0x8e >> 1, - .status_mode = AU8522_DEMODLOCKING, - .qam_if = AU8522_IF_6MHZ, - .vsb_if = AU8522_IF_6MHZ, - .led_cfg = &hauppauge_hvr950q_led_cfg, -}; - -static struct au8522_config fusionhdtv7usb_config = { - .demod_address = 0x8e >> 1, - .status_mode = AU8522_DEMODLOCKING, - .qam_if = AU8522_IF_6MHZ, - .vsb_if = AU8522_IF_6MHZ, -}; - -static struct au8522_config hauppauge_woodbury_config = { - .demod_address = 0x8e >> 1, - .status_mode = AU8522_DEMODLOCKING, - .qam_if = AU8522_IF_4MHZ, - .vsb_if = AU8522_IF_3_25MHZ, -}; - -static struct xc5000_config hauppauge_hvr950q_tunerconfig = { - .i2c_address = 0x61, - .if_khz = 6000, -}; - -static struct mxl5007t_config mxl5007t_hvr950q_config = { - .xtal_freq_hz = MxL_XTAL_24_MHZ, - .if_freq_hz = MxL_IF_6_MHZ, -}; - -static struct tda18271_config hauppauge_woodbury_tunerconfig = { - .gate = TDA18271_GATE_DIGITAL, -}; - -/*-------------------------------------------------------------------*/ -static void urb_completion(struct urb *purb) -{ - struct au0828_dev *dev = purb->context; - int ptype = usb_pipetype(purb->pipe); - - dprintk(2, "%s()\n", __func__); - - if (!dev) - return; - - if (dev->urb_streaming == 0) - return; - - if (ptype != PIPE_BULK) { - printk(KERN_ERR "%s() Unsupported URB type %d\n", - __func__, ptype); - return; - } - - /* Feed the transport payload into the kernel demux */ - dvb_dmx_swfilter_packets(&dev->dvb.demux, - purb->transfer_buffer, purb->actual_length / 188); - - /* Clean the buffer before we requeue */ - memset(purb->transfer_buffer, 0, URB_BUFSIZE); - - /* Requeue URB */ - usb_submit_urb(purb, GFP_ATOMIC); -} - -static int stop_urb_transfer(struct au0828_dev *dev) -{ - int i; - - dprintk(2, "%s()\n", __func__); - - for (i = 0; i < URB_COUNT; i++) { - usb_kill_urb(dev->urbs[i]); - kfree(dev->urbs[i]->transfer_buffer); - usb_free_urb(dev->urbs[i]); - } - - dev->urb_streaming = 0; - - return 0; -} - -static int start_urb_transfer(struct au0828_dev *dev) -{ - struct urb *purb; - int i, ret = -ENOMEM; - - dprintk(2, "%s()\n", __func__); - - if (dev->urb_streaming) { - dprintk(2, "%s: bulk xfer already running!\n", __func__); - return 0; - } - - for (i = 0; i < URB_COUNT; i++) { - - dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->urbs[i]) - goto err; - - purb = dev->urbs[i]; - - purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL); - if (!purb->transfer_buffer) { - usb_free_urb(purb); - dev->urbs[i] = NULL; - goto err; - } - - purb->status = -EINPROGRESS; - usb_fill_bulk_urb(purb, - dev->usbdev, - usb_rcvbulkpipe(dev->usbdev, - _AU0828_BULKPIPE), - purb->transfer_buffer, - URB_BUFSIZE, - urb_completion, - dev); - - } - - for (i = 0; i < URB_COUNT; i++) { - ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC); - if (ret != 0) { - stop_urb_transfer(dev); - printk(KERN_ERR "%s: failed urb submission, " - "err = %d\n", __func__, ret); - return ret; - } - } - - dev->urb_streaming = 1; - ret = 0; - -err: - return ret; -} - -static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct au0828_dev *dev = (struct au0828_dev *) demux->priv; - struct au0828_dvb *dvb = &dev->dvb; - int ret = 0; - - dprintk(1, "%s()\n", __func__); - - if (!demux->dmx.frontend) - return -EINVAL; - - if (dvb) { - mutex_lock(&dvb->lock); - if (dvb->feeding++ == 0) { - /* Start transport */ - au0828_write(dev, 0x608, 0x90); - au0828_write(dev, 0x609, 0x72); - au0828_write(dev, 0x60a, 0x71); - au0828_write(dev, 0x60b, 0x01); - ret = start_urb_transfer(dev); - } - mutex_unlock(&dvb->lock); - } - - return ret; -} - -static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct au0828_dev *dev = (struct au0828_dev *) demux->priv; - struct au0828_dvb *dvb = &dev->dvb; - int ret = 0; - - dprintk(1, "%s()\n", __func__); - - if (dvb) { - mutex_lock(&dvb->lock); - if (--dvb->feeding == 0) { - /* Stop transport */ - au0828_write(dev, 0x608, 0x00); - au0828_write(dev, 0x609, 0x00); - au0828_write(dev, 0x60a, 0x00); - au0828_write(dev, 0x60b, 0x00); - ret = stop_urb_transfer(dev); - } - mutex_unlock(&dvb->lock); - } - - return ret; -} - -static int dvb_register(struct au0828_dev *dev) -{ - struct au0828_dvb *dvb = &dev->dvb; - int result; - - dprintk(1, "%s()\n", __func__); - - /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, - &dev->usbdev->dev, adapter_nr); - if (result < 0) { - printk(KERN_ERR "%s: dvb_register_adapter failed " - "(errno = %d)\n", DRIVER_NAME, result); - goto fail_adapter; - } - dvb->adapter.priv = dev; - - /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (result < 0) { - printk(KERN_ERR "%s: dvb_register_frontend failed " - "(errno = %d)\n", DRIVER_NAME, result); - goto fail_frontend; - } - - /* register demux stuff */ - dvb->demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dev; - dvb->demux.filternum = 256; - dvb->demux.feednum = 256; - dvb->demux.start_feed = au0828_dvb_start_feed; - dvb->demux.stop_feed = au0828_dvb_stop_feed; - result = dvb_dmx_init(&dvb->demux); - if (result < 0) { - printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n", - DRIVER_NAME, result); - goto fail_dmx; - } - - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = &dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (result < 0) { - printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n", - DRIVER_NAME, result); - goto fail_dmxdev; - } - - dvb->fe_hw.source = DMX_FRONTEND_0; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_ERR "%s: add_frontend failed " - "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result); - goto fail_fe_hw; - } - - dvb->fe_mem.source = DMX_MEMORY_FE; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); - if (result < 0) { - printk(KERN_ERR "%s: add_frontend failed " - "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result); - goto fail_fe_mem; - } - - result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", - DRIVER_NAME, result); - goto fail_fe_conn; - } - - /* register network adapter */ - dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); - return 0; - -fail_fe_conn: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); -fail_fe_mem: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); -fail_fe_hw: - dvb_dmxdev_release(&dvb->dmxdev); -fail_dmxdev: - dvb_dmx_release(&dvb->demux); -fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -fail_adapter: - return result; -} - -void au0828_dvb_unregister(struct au0828_dev *dev) -{ - struct au0828_dvb *dvb = &dev->dvb; - - dprintk(1, "%s()\n", __func__); - - if (dvb->frontend == NULL) - return; - - dvb_net_release(&dvb->net); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -} - -/* All the DVB attach calls go here, this function get's modified - * for each new card. No other function in this file needs - * to change. - */ -int au0828_dvb_register(struct au0828_dev *dev) -{ - struct au0828_dvb *dvb = &dev->dvb; - int ret; - - dprintk(1, "%s()\n", __func__); - - /* init frontend */ - switch (dev->boardnr) { - case AU0828_BOARD_HAUPPAUGE_HVR850: - case AU0828_BOARD_HAUPPAUGE_HVR950Q: - dvb->frontend = dvb_attach(au8522_attach, - &hauppauge_hvr950q_config, - &dev->i2c_adap); - if (dvb->frontend != NULL) - dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, - &hauppauge_hvr950q_tunerconfig); - break; - case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: - dvb->frontend = dvb_attach(au8522_attach, - &hauppauge_hvr950q_config, - &dev->i2c_adap); - if (dvb->frontend != NULL) - dvb_attach(mxl5007t_attach, dvb->frontend, - &dev->i2c_adap, 0x60, - &mxl5007t_hvr950q_config); - break; - case AU0828_BOARD_HAUPPAUGE_WOODBURY: - dvb->frontend = dvb_attach(au8522_attach, - &hauppauge_woodbury_config, - &dev->i2c_adap); - if (dvb->frontend != NULL) - dvb_attach(tda18271_attach, dvb->frontend, - 0x60, &dev->i2c_adap, - &hauppauge_woodbury_tunerconfig); - break; - case AU0828_BOARD_DVICO_FUSIONHDTV7: - dvb->frontend = dvb_attach(au8522_attach, - &fusionhdtv7usb_config, - &dev->i2c_adap); - if (dvb->frontend != NULL) { - dvb_attach(xc5000_attach, dvb->frontend, - &dev->i2c_adap, - &hauppauge_hvr950q_tunerconfig); - } - break; - default: - printk(KERN_WARNING "The frontend of your DVB/ATSC card " - "isn't supported yet\n"); - break; - } - if (NULL == dvb->frontend) { - printk(KERN_ERR "%s() Frontend initialization failed\n", - __func__); - return -1; - } - /* define general-purpose callback pointer */ - dvb->frontend->callback = au0828_tuner_callback; - - /* register everything */ - ret = dvb_register(dev); - if (ret < 0) { - if (dvb->frontend->ops.release) - dvb->frontend->ops.release(dvb->frontend); - return ret; - } - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,302 +0,0 @@ -/* - * Driver for the Auvitek AU0828 USB bridge - * - * Copyright (c) 2008 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -/* Analog */ -#include -#include -#include - -/* DVB */ -#include "demux.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "dvbdev.h" - -#include "au0828-reg.h" -#include "au0828-cards.h" - -#define DRIVER_NAME "au0828" -#define URB_COUNT 16 -#define URB_BUFSIZE (0xe522) - -/* Analog constants */ -#define NTSC_STD_W 720 -#define NTSC_STD_H 480 - -#define AU0828_INTERLACED_DEFAULT 1 -#define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0) - -/* Defination for AU0828 USB transfer */ -#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */ -#define AU0828_ISO_PACKETS_PER_URB 128 - -#define AU0828_MIN_BUF 4 -#define AU0828_DEF_BUF 8 - -#define AU0828_MAX_INPUT 4 - -/* au0828 resource types (used for res_get/res_lock etc */ -#define AU0828_RESOURCE_VIDEO 0x01 -#define AU0828_RESOURCE_VBI 0x02 - -enum au0828_itype { - AU0828_VMUX_UNDEFINED = 0, - AU0828_VMUX_COMPOSITE, - AU0828_VMUX_SVIDEO, - AU0828_VMUX_CABLE, - AU0828_VMUX_TELEVISION, - AU0828_VMUX_DVB, - AU0828_VMUX_DEBUG -}; - -struct au0828_input { - enum au0828_itype type; - unsigned int vmux; - unsigned int amux; - void (*audio_setup) (void *priv, int enable); -}; - -struct au0828_board { - char *name; - unsigned int tuner_type; - unsigned char tuner_addr; - unsigned char i2c_clk_divider; - struct au0828_input input[AU0828_MAX_INPUT]; - -}; - -struct au0828_dvb { - struct mutex lock; - struct dvb_adapter adapter; - struct dvb_frontend *frontend; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net net; - int feeding; -}; - -enum au0828_stream_state { - STREAM_OFF, - STREAM_INTERRUPT, - STREAM_ON -}; - -#define AUVI_INPUT(nr) (dev->board.input[nr]) - -/* device state */ -enum au0828_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04 -}; - -struct au0828_fh { - struct au0828_dev *dev; - unsigned int resources; - - struct videobuf_queue vb_vidq; - struct videobuf_queue vb_vbiq; - enum v4l2_buf_type type; -}; - -struct au0828_usb_isoc_ctl { - /* max packet size of isoc transaction */ - int max_pkt_size; - - /* number of allocated urbs */ - int num_bufs; - - /* urb for isoc transfers */ - struct urb **urb; - - /* transfer buffers for isoc transfer */ - char **transfer_buffer; - - /* Last buffer command and region */ - u8 cmd; - int pos, size, pktsize; - - /* Last field: ODD or EVEN? */ - int field; - - /* Stores incomplete commands */ - u32 tmp_buf; - int tmp_buf_len; - - /* Stores already requested buffers */ - struct au0828_buffer *buf; - struct au0828_buffer *vbi_buf; - - /* Stores the number of received fields */ - int nfields; - - /* isoc urb callback */ - int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb); - -}; - -/* buffer for one video frame */ -struct au0828_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - struct list_head frame; - int top_field; - int receiving; -}; - -struct au0828_dmaqueue { - struct list_head active; - struct list_head queued; - - wait_queue_head_t wq; - - /* Counters to control buffer fill */ - int pos; -}; - -struct au0828_dev { - struct mutex mutex; - struct usb_device *usbdev; - int boardnr; - struct au0828_board board; - u8 ctrlmsg[64]; - - /* I2C */ - struct i2c_adapter i2c_adap; - struct i2c_algorithm i2c_algo; - struct i2c_client i2c_client; - u32 i2c_rc; - - /* Digital */ - struct au0828_dvb dvb; - - /* Analog */ - struct v4l2_device v4l2_dev; - int users; - unsigned int resources; /* resources in use */ - struct video_device *vdev; - struct video_device *vbi_dev; - struct timer_list vid_timeout; - int vid_timeout_running; - struct timer_list vbi_timeout; - int vbi_timeout_running; - int width; - int height; - int vbi_width; - int vbi_height; - u32 vbi_read; - u32 field_size; - u32 frame_size; - u32 bytesperline; - int type; - u8 ctrl_ainput; - __u8 isoc_in_endpointaddr; - u8 isoc_init_ok; - int greenscreen_detected; - unsigned int frame_count; - int ctrl_freq; - int input_type; - unsigned int ctrl_input; - enum au0828_dev_state dev_state; - enum au0828_stream_state stream_state; - wait_queue_head_t open; - - struct mutex lock; - - /* Isoc control struct */ - struct au0828_dmaqueue vidq; - struct au0828_dmaqueue vbiq; - struct au0828_usb_isoc_ctl isoc_ctl; - spinlock_t slock; - - /* usb transfer */ - int alt; /* alternate */ - int max_pkt_size; /* max packet size of isoc transaction */ - int num_alt; /* Number of alternative settings */ - unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ - struct urb *urb[AU0828_MAX_ISO_BUFS]; /* urb for isoc transfers */ - char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc - transfer */ - - /* USB / URB Related */ - int urb_streaming; - struct urb *urbs[URB_COUNT]; -}; - -/* ----------------------------------------------------------- */ -#define au0828_read(dev, reg) au0828_readreg(dev, reg) -#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value) -#define au0828_andor(dev, reg, mask, value) \ - au0828_writereg(dev, reg, \ - (au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask))) - -#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit)) -#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0) - -/* ----------------------------------------------------------- */ -/* au0828-core.c */ -extern u32 au0828_read(struct au0828_dev *dev, u16 reg); -extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val); -extern int au0828_debug; - -/* ----------------------------------------------------------- */ -/* au0828-cards.c */ -extern struct au0828_board au0828_boards[]; -extern struct usb_device_id au0828_usb_id_table[]; -extern void au0828_gpio_setup(struct au0828_dev *dev); -extern int au0828_tuner_callback(void *priv, int component, - int command, int arg); -extern void au0828_card_setup(struct au0828_dev *dev); - -/* ----------------------------------------------------------- */ -/* au0828-i2c.c */ -extern int au0828_i2c_register(struct au0828_dev *dev); -extern int au0828_i2c_unregister(struct au0828_dev *dev); - -/* ----------------------------------------------------------- */ -/* au0828-video.c */ -int au0828_analog_register(struct au0828_dev *dev, - struct usb_interface *interface); -int au0828_analog_stream_disable(struct au0828_dev *d); -void au0828_analog_unregister(struct au0828_dev *dev); - -/* ----------------------------------------------------------- */ -/* au0828-dvb.c */ -extern int au0828_dvb_register(struct au0828_dev *dev); -extern void au0828_dvb_unregister(struct au0828_dev *dev); - -/* au0828-vbi.c */ -extern struct videobuf_queue_ops au0828_vbi_qops; - -#define dprintk(level, fmt, arg...)\ - do { if (au0828_debug & level)\ - printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\ - } while (0) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,390 +0,0 @@ -/* - * Driver for the Auvitek AU0828 USB bridge - * - * Copyright (c) 2008 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "au0828.h" - -#include - -static int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); - -#define I2C_WAIT_DELAY 512 -#define I2C_WAIT_RETRY 64 - -static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap) -{ - struct au0828_dev *dev = i2c_adap->algo_data; - return au0828_read(dev, AU0828_I2C_STATUS_201) & - AU0828_I2C_STATUS_NO_WRITE_ACK ? 0 : 1; -} - -static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap) -{ - struct au0828_dev *dev = i2c_adap->algo_data; - return au0828_read(dev, AU0828_I2C_STATUS_201) & - AU0828_I2C_STATUS_NO_READ_ACK ? 0 : 1; -} - -static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap) -{ - int count; - - for (count = 0; count < I2C_WAIT_RETRY; count++) { - if (!i2c_slave_did_read_ack(i2c_adap)) - break; - udelay(I2C_WAIT_DELAY); - } - - if (I2C_WAIT_RETRY == count) - return 0; - - return 1; -} - -static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap) -{ - struct au0828_dev *dev = i2c_adap->algo_data; - return au0828_read(dev, AU0828_I2C_STATUS_201) & - AU0828_I2C_STATUS_READ_DONE ? 0 : 1; -} - -static int i2c_wait_read_done(struct i2c_adapter *i2c_adap) -{ - int count; - - for (count = 0; count < I2C_WAIT_RETRY; count++) { - if (!i2c_is_read_busy(i2c_adap)) - break; - udelay(I2C_WAIT_DELAY); - } - - if (I2C_WAIT_RETRY == count) - return 0; - - return 1; -} - -static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap) -{ - struct au0828_dev *dev = i2c_adap->algo_data; - return au0828_read(dev, AU0828_I2C_STATUS_201) & - AU0828_I2C_STATUS_WRITE_DONE ? 1 : 0; -} - -static int i2c_wait_write_done(struct i2c_adapter *i2c_adap) -{ - int count; - - for (count = 0; count < I2C_WAIT_RETRY; count++) { - if (i2c_is_write_done(i2c_adap)) - break; - udelay(I2C_WAIT_DELAY); - } - - if (I2C_WAIT_RETRY == count) - return 0; - - return 1; -} - -static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) -{ - struct au0828_dev *dev = i2c_adap->algo_data; - return au0828_read(dev, AU0828_I2C_STATUS_201) & - AU0828_I2C_STATUS_BUSY ? 1 : 0; -} - -static int i2c_wait_done(struct i2c_adapter *i2c_adap) -{ - int count; - - for (count = 0; count < I2C_WAIT_RETRY; count++) { - if (!i2c_is_busy(i2c_adap)) - break; - udelay(I2C_WAIT_DELAY); - } - - if (I2C_WAIT_RETRY == count) - return 0; - - return 1; -} - -/* FIXME: Implement join handling correctly */ -static int i2c_sendbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int joined_rlen) -{ - int i, strobe = 0; - struct au0828_dev *dev = i2c_adap->algo_data; - - dprintk(4, "%s()\n", __func__); - - au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01); - - /* Set the I2C clock */ - au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202, - dev->board.i2c_clk_divider); - - /* Hardware needs 8 bit addresses */ - au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1); - - dprintk(4, "SEND: %02x\n", msg->addr); - - /* Deal with i2c_scan */ - if (msg->len == 0) { - /* The analog tuner detection code makes use of the SMBUS_QUICK - message (which involves a zero length i2c write). To avoid - checking the status register when we didn't strobe out any - actual bytes to the bus, just do a read check. This is - consistent with how I saw i2c device checking done in the - USB trace of the Windows driver */ - au0828_write(dev, AU0828_I2C_TRIGGER_200, - AU0828_I2C_TRIGGER_READ); - - if (!i2c_wait_done(i2c_adap)) - return -EIO; - - if (i2c_wait_read_ack(i2c_adap)) - return -EIO; - - return 0; - } - - for (i = 0; i < msg->len;) { - - dprintk(4, " %02x\n", msg->buf[i]); - - au0828_write(dev, AU0828_I2C_WRITE_FIFO_205, msg->buf[i]); - - strobe++; - i++; - - if ((strobe >= 4) || (i >= msg->len)) { - - /* Strobe the byte into the bus */ - if (i < msg->len) - au0828_write(dev, AU0828_I2C_TRIGGER_200, - AU0828_I2C_TRIGGER_WRITE | - AU0828_I2C_TRIGGER_HOLD); - else - au0828_write(dev, AU0828_I2C_TRIGGER_200, - AU0828_I2C_TRIGGER_WRITE); - - /* Reset strobe trigger */ - strobe = 0; - - if (!i2c_wait_write_done(i2c_adap)) - return -EIO; - - } - - } - if (!i2c_wait_done(i2c_adap)) - return -EIO; - - dprintk(4, "\n"); - - return msg->len; -} - -/* FIXME: Implement join handling correctly */ -static int i2c_readbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int joined) -{ - struct au0828_dev *dev = i2c_adap->algo_data; - int i; - - dprintk(4, "%s()\n", __func__); - - au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01); - - /* Set the I2C clock */ - au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202, - dev->board.i2c_clk_divider); - - /* Hardware needs 8 bit addresses */ - au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1); - - dprintk(4, " RECV:\n"); - - /* Deal with i2c_scan */ - if (msg->len == 0) { - au0828_write(dev, AU0828_I2C_TRIGGER_200, - AU0828_I2C_TRIGGER_READ); - - if (i2c_wait_read_ack(i2c_adap)) - return -EIO; - return 0; - } - - for (i = 0; i < msg->len;) { - - i++; - - if (i < msg->len) - au0828_write(dev, AU0828_I2C_TRIGGER_200, - AU0828_I2C_TRIGGER_READ | - AU0828_I2C_TRIGGER_HOLD); - else - au0828_write(dev, AU0828_I2C_TRIGGER_200, - AU0828_I2C_TRIGGER_READ); - - if (!i2c_wait_read_done(i2c_adap)) - return -EIO; - - msg->buf[i-1] = au0828_read(dev, AU0828_I2C_READ_FIFO_209) & - 0xff; - - dprintk(4, " %02x\n", msg->buf[i-1]); - } - if (!i2c_wait_done(i2c_adap)) - return -EIO; - - dprintk(4, "\n"); - - return msg->len; -} - -static int i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, int num) -{ - int i, retval = 0; - - dprintk(4, "%s(num = %d)\n", __func__, num); - - for (i = 0; i < num; i++) { - dprintk(4, "%s(num = %d) addr = 0x%02x len = 0x%x\n", - __func__, num, msgs[i].addr, msgs[i].len); - if (msgs[i].flags & I2C_M_RD) { - /* read */ - retval = i2c_readbytes(i2c_adap, &msgs[i], 0); - } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && - msgs[i].addr == msgs[i + 1].addr) { - /* write then read from same address */ - retval = i2c_sendbytes(i2c_adap, &msgs[i], - msgs[i + 1].len); - if (retval < 0) - goto err; - i++; - retval = i2c_readbytes(i2c_adap, &msgs[i], 1); - } else { - /* write */ - retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); - } - if (retval < 0) - goto err; - } - return num; - -err: - return retval; -} - -static u32 au0828_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; -} - -static struct i2c_algorithm au0828_i2c_algo_template = { - .master_xfer = i2c_xfer, - .functionality = au0828_functionality, -}; - -/* ----------------------------------------------------------------------- */ - -static struct i2c_adapter au0828_i2c_adap_template = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .algo = &au0828_i2c_algo_template, -}; - -static struct i2c_client au0828_i2c_client_template = { - .name = "au0828 internal", -}; - -static char *i2c_devs[128] = { - [0x8e >> 1] = "au8522", - [0xa0 >> 1] = "eeprom", - [0xc2 >> 1] = "tuner/xc5000", -}; - -static void do_i2c_scan(char *name, struct i2c_client *c) -{ - unsigned char buf; - int i, rc; - - for (i = 0; i < 128; i++) { - c->addr = i; - rc = i2c_master_recv(c, &buf, 0); - if (rc < 0) - continue; - printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); - } -} - -/* init + register i2c algo-bit adapter */ -int au0828_i2c_register(struct au0828_dev *dev) -{ - dprintk(1, "%s()\n", __func__); - - memcpy(&dev->i2c_adap, &au0828_i2c_adap_template, - sizeof(dev->i2c_adap)); - memcpy(&dev->i2c_algo, &au0828_i2c_algo_template, - sizeof(dev->i2c_algo)); - memcpy(&dev->i2c_client, &au0828_i2c_client_template, - sizeof(dev->i2c_client)); - - dev->i2c_adap.dev.parent = &dev->usbdev->dev; - - strlcpy(dev->i2c_adap.name, DRIVER_NAME, - sizeof(dev->i2c_adap.name)); - - dev->i2c_adap.algo = &dev->i2c_algo; - dev->i2c_adap.algo_data = dev; - i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); - i2c_add_adapter(&dev->i2c_adap); - - dev->i2c_client.adapter = &dev->i2c_adap; - - if (0 == dev->i2c_rc) { - printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME); - if (i2c_scan) - do_i2c_scan(DRIVER_NAME, &dev->i2c_client); - } else - printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME); - - return dev->i2c_rc; -} - -int au0828_i2c_unregister(struct au0828_dev *dev) -{ - i2c_del_adapter(&dev->i2c_adap); - return 0; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -/* - * Driver for the Auvitek USB bridge - * - * Copyright (c) 2008 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* We'll start to rename these registers once we have a better - * understanding of their meaning. - */ -#define REG_000 0x000 -#define REG_001 0x001 -#define REG_002 0x002 -#define REG_003 0x003 - -#define AU0828_SENSORCTRL_100 0x100 -#define AU0828_SENSORCTRL_VBI_103 0x103 - -/* I2C registers */ -#define AU0828_I2C_TRIGGER_200 0x200 -#define AU0828_I2C_STATUS_201 0x201 -#define AU0828_I2C_CLK_DIVIDER_202 0x202 -#define AU0828_I2C_DEST_ADDR_203 0x203 -#define AU0828_I2C_WRITE_FIFO_205 0x205 -#define AU0828_I2C_READ_FIFO_209 0x209 -#define AU0828_I2C_MULTIBYTE_MODE_2FF 0x2ff - -/* Audio registers */ -#define AU0828_AUDIOCTRL_50C 0x50C - -#define REG_600 0x600 - -/*********************************************************************/ -/* Here are constants for values associated with the above registers */ - -/* I2C Trigger (Reg 0x200) */ -#define AU0828_I2C_TRIGGER_WRITE 0x01 -#define AU0828_I2C_TRIGGER_READ 0x20 -#define AU0828_I2C_TRIGGER_HOLD 0x40 - -/* I2C Status (Reg 0x201) */ -#define AU0828_I2C_STATUS_READ_DONE 0x01 -#define AU0828_I2C_STATUS_NO_READ_ACK 0x02 -#define AU0828_I2C_STATUS_WRITE_DONE 0x04 -#define AU0828_I2C_STATUS_NO_WRITE_ACK 0x08 -#define AU0828_I2C_STATUS_BUSY 0x10 - -/* I2C Clock Divider (Reg 0x202) */ -#define AU0828_I2C_CLK_250KHZ 0x07 -#define AU0828_I2C_CLK_100KHZ 0x14 -#define AU0828_I2C_CLK_30KHZ 0x40 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-vbi.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,138 +0,0 @@ -/* - au0828-vbi.c - VBI driver for au0828 - - Copyright (C) 2010 Devin Heitmueller - - This work was sponsored by GetWellNetwork Inc. - - 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, or - (at your option) any later version. - - 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., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - */ - -#include -#include -#include -#include - -#include "au0828.h" - -static unsigned int vbibufs = 5; -module_param(vbibufs, int, 0644); -MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); - -/* ------------------------------------------------------------------ */ - -static void -free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf) -{ - struct au0828_fh *fh = vq->priv_data; - struct au0828_dev *dev = fh->dev; - unsigned long flags = 0; - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.vbi_buf == buf) - dev->isoc_ctl.vbi_buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct au0828_fh *fh = q->priv_data; - struct au0828_dev *dev = fh->dev; - - *size = dev->vbi_width * dev->vbi_height * 2; - - if (0 == *count) - *count = vbibufs; - if (*count < 2) - *count = 2; - if (*count > 32) - *count = 32; - return 0; -} - -static int -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct au0828_fh *fh = q->priv_data; - struct au0828_dev *dev = fh->dev; - struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); - int rc = 0; - - buf->vb.size = dev->vbi_width * dev->vbi_height * 2; - - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - buf->vb.width = dev->vbi_width; - buf->vb.height = dev->vbi_height; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(q, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(q, buf); - return rc; -} - -static void -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct au0828_buffer *buf = container_of(vb, - struct au0828_buffer, - vb); - struct au0828_fh *fh = vq->priv_data; - struct au0828_dev *dev = fh->dev; - struct au0828_dmaqueue *vbiq = &dev->vbiq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vbiq->active); -} - -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); - free_buffer(q, buf); -} - -struct videobuf_queue_ops au0828_vbi_qops = { - .buf_setup = vbi_setup, - .buf_prepare = vbi_prepare, - .buf_queue = vbi_queue, - .buf_release = vbi_release, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/au0828-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1998 +0,0 @@ -/* - * Auvitek AU0828 USB Bridge (Analog video support) - * - * Copyright (C) 2009 Devin Heitmueller - * Copyright (C) 2005-2008 Auvitek International, Ltd. - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/* Developer Notes: - * - * VBI support is not yet working - * The hardware scaler supported is unimplemented - * AC97 audio support is unimplemented (only i2s audio mode) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "au0828.h" -#include "au0828-reg.h" - -static DEFINE_MUTEX(au0828_sysfs_lock); - -#define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1) - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ - -static unsigned int isoc_debug; -module_param(isoc_debug, int, 0644); -MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); - -#define au0828_isocdbg(fmt, arg...) \ -do {\ - if (isoc_debug) { \ - printk(KERN_INFO "au0828 %s :"fmt, \ - __func__ , ##arg); \ - } \ - } while (0) - -static inline void print_err_status(struct au0828_dev *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - au0828_isocdbg("URB status %d [%s].\n", status, errmsg); - } else { - au0828_isocdbg("URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -static int check_dev(struct au0828_dev *dev) -{ - if (dev->dev_state & DEV_DISCONNECTED) { - printk(KERN_INFO "v4l2 ioctl: device not present\n"); - return -ENODEV; - } - - if (dev->dev_state & DEV_MISCONFIGURED) { - printk(KERN_INFO "v4l2 ioctl: device is misconfigured; " - "close and open it again\n"); - return -EIO; - } - return 0; -} - -/* - * IRQ callback, called by URB callback - */ -static void au0828_irq_callback(struct urb *urb) -{ - struct au0828_dmaqueue *dma_q = urb->context; - struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq); - unsigned long flags = 0; - int rc, i; - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - au0828_isocdbg("au0828_irq_callback called: status kill\n"); - return; - default: /* unknown error */ - au0828_isocdbg("urb completition error %d.\n", urb->status); - break; - } - - /* Copy data from URB */ - spin_lock_irqsave(&dev->slock, flags); - rc = dev->isoc_ctl.isoc_copy(dev, urb); - spin_unlock_irqrestore(&dev->slock, flags); - - /* Reset urb buffers */ - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - urb->status = 0; - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) { - au0828_isocdbg("urb resubmit failed (error=%i)\n", - urb->status); - } -} - -/* - * Stop and Deallocate URBs - */ -void au0828_uninit_isoc(struct au0828_dev *dev) -{ - struct urb *urb; - int i; - - au0828_isocdbg("au0828: called au0828_uninit_isoc\n"); - - dev->isoc_ctl.nfields = -1; - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = dev->isoc_ctl.urb[i]; - if (urb) { - if (!irqs_disabled()) - usb_kill_urb(urb); - else - usb_unlink_urb(urb); - - if (dev->isoc_ctl.transfer_buffer[i]) { - usb_free_coherent(dev->usbdev, - urb->transfer_buffer_length, - dev->isoc_ctl.transfer_buffer[i], - urb->transfer_dma); - } - usb_free_urb(urb); - dev->isoc_ctl.urb[i] = NULL; - } - dev->isoc_ctl.transfer_buffer[i] = NULL; - } - - kfree(dev->isoc_ctl.urb); - kfree(dev->isoc_ctl.transfer_buffer); - - dev->isoc_ctl.urb = NULL; - dev->isoc_ctl.transfer_buffer = NULL; - dev->isoc_ctl.num_bufs = 0; -} - -/* - * Allocate URBs and start IRQ - */ -int au0828_init_isoc(struct au0828_dev *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb)) -{ - struct au0828_dmaqueue *dma_q = &dev->vidq; - int i; - int sb_size, pipe; - struct urb *urb; - int j, k; - int rc; - - au0828_isocdbg("au0828: called au0828_prepare_isoc\n"); - - /* De-allocates all pending stuff */ - au0828_uninit_isoc(dev); - - dev->isoc_ctl.isoc_copy = isoc_copy; - dev->isoc_ctl.num_bufs = num_bufs; - - dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); - if (!dev->isoc_ctl.urb) { - au0828_isocdbg("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - - dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); - if (!dev->isoc_ctl.transfer_buffer) { - au0828_isocdbg("cannot allocate memory for usb transfer\n"); - kfree(dev->isoc_ctl.urb); - return -ENOMEM; - } - - dev->isoc_ctl.max_pkt_size = max_pkt_size; - dev->isoc_ctl.buf = NULL; - - sb_size = max_packets * dev->isoc_ctl.max_pkt_size; - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = usb_alloc_urb(max_packets, GFP_KERNEL); - if (!urb) { - au0828_isocdbg("cannot alloc isoc_ctl.urb %i\n", i); - au0828_uninit_isoc(dev); - return -ENOMEM; - } - dev->isoc_ctl.urb[i] = urb; - - dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev, - sb_size, GFP_KERNEL, &urb->transfer_dma); - if (!dev->isoc_ctl.transfer_buffer[i]) { - printk("unable to allocate %i bytes for transfer" - " buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); - au0828_uninit_isoc(dev); - return -ENOMEM; - } - memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); - - pipe = usb_rcvisocpipe(dev->usbdev, - dev->isoc_in_endpointaddr), - - usb_fill_int_urb(urb, dev->usbdev, pipe, - dev->isoc_ctl.transfer_buffer[i], sb_size, - au0828_irq_callback, dma_q, 1); - - urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - - k = 0; - for (j = 0; j < max_packets; j++) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - dev->isoc_ctl.max_pkt_size; - k += dev->isoc_ctl.max_pkt_size; - } - } - - init_waitqueue_head(&dma_q->wq); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); - if (rc) { - au0828_isocdbg("submit of urb %i failed (error=%i)\n", - i, rc); - au0828_uninit_isoc(dev); - return rc; - } - } - - return 0; -} - -/* - * Announces that a buffer were filled and request the next - */ -static inline void buffer_filled(struct au0828_dev *dev, - struct au0828_dmaqueue *dma_q, - struct au0828_buffer *buf) -{ - /* Advice that buffer was filled */ - au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); - - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - - dev->isoc_ctl.buf = NULL; - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -static inline void vbi_buffer_filled(struct au0828_dev *dev, - struct au0828_dmaqueue *dma_q, - struct au0828_buffer *buf) -{ - /* Advice that buffer was filled */ - au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); - - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - - dev->isoc_ctl.vbi_buf = NULL; - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -/* - * Identify the buffer header type and properly handles - */ -static void au0828_copy_video(struct au0828_dev *dev, - struct au0828_dmaqueue *dma_q, - struct au0828_buffer *buf, - unsigned char *p, - unsigned char *outp, unsigned long len) -{ - void *fieldstart, *startwrite, *startread; - int linesdone, currlinedone, offset, lencopy, remain; - int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */ - - if (len == 0) - return; - - if (dma_q->pos + len > buf->vb.size) - len = buf->vb.size - dma_q->pos; - - startread = p; - remain = len; - - /* Interlaces frame */ - if (buf->top_field) - fieldstart = outp; - else - fieldstart = outp + bytesperline; - - linesdone = dma_q->pos / bytesperline; - currlinedone = dma_q->pos % bytesperline; - offset = linesdone * bytesperline * 2 + currlinedone; - startwrite = fieldstart + offset; - lencopy = bytesperline - currlinedone; - lencopy = lencopy > remain ? remain : lencopy; - - if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) { - au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n", - ((char *)startwrite + lencopy) - - ((char *)outp + buf->vb.size)); - remain = (char *)outp + buf->vb.size - (char *)startwrite; - lencopy = remain; - } - if (lencopy <= 0) - return; - memcpy(startwrite, startread, lencopy); - - remain -= lencopy; - - while (remain > 0) { - startwrite += lencopy + bytesperline; - startread += lencopy; - if (bytesperline > remain) - lencopy = remain; - else - lencopy = bytesperline; - - if ((char *)startwrite + lencopy > (char *)outp + - buf->vb.size) { - au0828_isocdbg("Overflow %zi bytes past buf end (2)\n", - ((char *)startwrite + lencopy) - - ((char *)outp + buf->vb.size)); - lencopy = remain = (char *)outp + buf->vb.size - - (char *)startwrite; - } - if (lencopy <= 0) - break; - - memcpy(startwrite, startread, lencopy); - - remain -= lencopy; - } - - if (offset > 1440) { - /* We have enough data to check for greenscreen */ - if (outp[0] < 0x60 && outp[1440] < 0x60) - dev->greenscreen_detected = 1; - } - - dma_q->pos += len; -} - -/* - * video-buf generic routine to get the next available buffer - */ -static inline void get_next_buf(struct au0828_dmaqueue *dma_q, - struct au0828_buffer **buf) -{ - struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq); - - if (list_empty(&dma_q->active)) { - au0828_isocdbg("No active queue to serve\n"); - dev->isoc_ctl.buf = NULL; - *buf = NULL; - return; - } - - /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue); - dev->isoc_ctl.buf = *buf; - - return; -} - -static void au0828_copy_vbi(struct au0828_dev *dev, - struct au0828_dmaqueue *dma_q, - struct au0828_buffer *buf, - unsigned char *p, - unsigned char *outp, unsigned long len) -{ - unsigned char *startwrite, *startread; - int bytesperline; - int i, j = 0; - - if (dev == NULL) { - au0828_isocdbg("dev is null\n"); - return; - } - - if (dma_q == NULL) { - au0828_isocdbg("dma_q is null\n"); - return; - } - if (buf == NULL) - return; - if (p == NULL) { - au0828_isocdbg("p is null\n"); - return; - } - if (outp == NULL) { - au0828_isocdbg("outp is null\n"); - return; - } - - bytesperline = dev->vbi_width; - - if (dma_q->pos + len > buf->vb.size) - len = buf->vb.size - dma_q->pos; - - startread = p; - startwrite = outp + (dma_q->pos / 2); - - /* Make sure the bottom field populates the second half of the frame */ - if (buf->top_field == 0) - startwrite += bytesperline * dev->vbi_height; - - for (i = 0; i < len; i += 2) - startwrite[j++] = startread[i+1]; - - dma_q->pos += len; -} - - -/* - * video-buf generic routine to get the next available VBI buffer - */ -static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q, - struct au0828_buffer **buf) -{ - struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq); - char *outp; - - if (list_empty(&dma_q->active)) { - au0828_isocdbg("No active queue to serve\n"); - dev->isoc_ctl.vbi_buf = NULL; - *buf = NULL; - return; - } - - /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue); - /* Cleans up buffer - Usefull for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - memset(outp, 0x00, (*buf)->vb.size); - - dev->isoc_ctl.vbi_buf = *buf; - - return; -} - -/* - * Controls the isoc copy of each urb packet - */ -static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) -{ - struct au0828_buffer *buf; - struct au0828_buffer *vbi_buf; - struct au0828_dmaqueue *dma_q = urb->context; - struct au0828_dmaqueue *vbi_dma_q = &dev->vbiq; - unsigned char *outp = NULL; - unsigned char *vbioutp = NULL; - int i, len = 0, rc = 1; - unsigned char *p; - unsigned char fbyte; - unsigned int vbi_field_size; - unsigned int remain, lencopy; - - if (!dev) - return 0; - - if ((dev->dev_state & DEV_DISCONNECTED) || - (dev->dev_state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - buf = dev->isoc_ctl.buf; - if (buf != NULL) - outp = videobuf_to_vmalloc(&buf->vb); - - vbi_buf = dev->isoc_ctl.vbi_buf; - if (vbi_buf != NULL) - vbioutp = videobuf_to_vmalloc(&vbi_buf->vb); - - for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - if (urb->iso_frame_desc[i].status != -EPROTO) - continue; - } - - if (urb->iso_frame_desc[i].actual_length <= 0) - continue; - - if (urb->iso_frame_desc[i].actual_length > - dev->max_pkt_size) { - au0828_isocdbg("packet bigger than packet size"); - continue; - } - - p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - fbyte = p[0]; - len = urb->iso_frame_desc[i].actual_length - 4; - p += 4; - - if (fbyte & 0x80) { - len -= 4; - p += 4; - au0828_isocdbg("Video frame %s\n", - (fbyte & 0x40) ? "odd" : "even"); - if (fbyte & 0x40) { - /* VBI */ - if (vbi_buf != NULL) - vbi_buffer_filled(dev, - vbi_dma_q, - vbi_buf); - vbi_get_next_buf(vbi_dma_q, &vbi_buf); - if (vbi_buf == NULL) - vbioutp = NULL; - else - vbioutp = videobuf_to_vmalloc( - &vbi_buf->vb); - - /* Video */ - if (buf != NULL) - buffer_filled(dev, dma_q, buf); - get_next_buf(dma_q, &buf); - if (buf == NULL) - outp = NULL; - else - outp = videobuf_to_vmalloc(&buf->vb); - - /* As long as isoc traffic is arriving, keep - resetting the timer */ - if (dev->vid_timeout_running) - mod_timer(&dev->vid_timeout, - jiffies + (HZ / 10)); - if (dev->vbi_timeout_running) - mod_timer(&dev->vbi_timeout, - jiffies + (HZ / 10)); - } - - if (buf != NULL) { - if (fbyte & 0x40) - buf->top_field = 1; - else - buf->top_field = 0; - } - - if (vbi_buf != NULL) { - if (fbyte & 0x40) - vbi_buf->top_field = 1; - else - vbi_buf->top_field = 0; - } - - dev->vbi_read = 0; - vbi_dma_q->pos = 0; - dma_q->pos = 0; - } - - vbi_field_size = dev->vbi_width * dev->vbi_height * 2; - if (dev->vbi_read < vbi_field_size) { - remain = vbi_field_size - dev->vbi_read; - if (len < remain) - lencopy = len; - else - lencopy = remain; - - if (vbi_buf != NULL) - au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p, - vbioutp, len); - - len -= lencopy; - p += lencopy; - dev->vbi_read += lencopy; - } - - if (dev->vbi_read >= vbi_field_size && buf != NULL) - au0828_copy_video(dev, dma_q, buf, p, outp, len); - } - return rc; -} - -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct au0828_fh *fh = vq->priv_data; - *size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3; - - if (0 == *count) - *count = AU0828_DEF_BUF; - - if (*count < AU0828_MIN_BUF) - *count = AU0828_MIN_BUF; - return 0; -} - -/* This is called *without* dev->slock held; please keep it that way */ -static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf) -{ - struct au0828_fh *fh = vq->priv_data; - struct au0828_dev *dev = fh->dev; - unsigned long flags = 0; - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.buf == buf) - dev->isoc_ctl.buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct au0828_fh *fh = vq->priv_data; - struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); - struct au0828_dev *dev = fh->dev; - int rc = 0, urb_init = 0; - - buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3; - - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) { - printk(KERN_INFO "videobuf_iolock failed\n"); - goto fail; - } - } - - if (!dev->isoc_ctl.num_bufs) - urb_init = 1; - - if (urb_init) { - rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB, - AU0828_MAX_ISO_BUFS, dev->max_pkt_size, - au0828_isoc_copy); - if (rc < 0) { - printk(KERN_INFO "au0828_init_isoc failed\n"); - goto fail; - } - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct au0828_buffer *buf = container_of(vb, - struct au0828_buffer, - vb); - struct au0828_fh *fh = vq->priv_data; - struct au0828_dev *dev = fh->dev; - struct au0828_dmaqueue *vidq = &dev->vidq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct au0828_buffer *buf = container_of(vb, - struct au0828_buffer, - vb); - - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops au0828_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ - V4L2 interface - ------------------------------------------------------------------*/ - -static int au0828_i2s_init(struct au0828_dev *dev) -{ - /* Enable i2s mode */ - au0828_writereg(dev, AU0828_AUDIOCTRL_50C, 0x01); - return 0; -} - -/* - * Auvitek au0828 analog stream enable - * Please set interface0 to AS5 before enable the stream - */ -int au0828_analog_stream_enable(struct au0828_dev *d) -{ - dprintk(1, "au0828_analog_stream_enable called\n"); - au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00); - au0828_writereg(d, 0x106, 0x00); - /* set x position */ - au0828_writereg(d, 0x110, 0x00); - au0828_writereg(d, 0x111, 0x00); - au0828_writereg(d, 0x114, 0xa0); - au0828_writereg(d, 0x115, 0x05); - /* set y position */ - au0828_writereg(d, 0x112, 0x00); - au0828_writereg(d, 0x113, 0x00); - au0828_writereg(d, 0x116, 0xf2); - au0828_writereg(d, 0x117, 0x00); - au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3); - - return 0; -} - -int au0828_analog_stream_disable(struct au0828_dev *d) -{ - dprintk(1, "au0828_analog_stream_disable called\n"); - au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0); - return 0; -} - -void au0828_analog_stream_reset(struct au0828_dev *dev) -{ - dprintk(1, "au0828_analog_stream_reset called\n"); - au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0); - mdelay(30); - au0828_writereg(dev, AU0828_SENSORCTRL_100, 0xb3); -} - -/* - * Some operations needs to stop current streaming - */ -static int au0828_stream_interrupt(struct au0828_dev *dev) -{ - int ret = 0; - - dev->stream_state = STREAM_INTERRUPT; - if (dev->dev_state == DEV_DISCONNECTED) - return -ENODEV; - else if (ret) { - dev->dev_state = DEV_MISCONFIGURED; - dprintk(1, "%s device is misconfigured!\n", __func__); - return ret; - } - return 0; -} - -/* - * au0828_release_resources - * unregister v4l2 devices - */ -void au0828_analog_unregister(struct au0828_dev *dev) -{ - dprintk(1, "au0828_release_resources called\n"); - mutex_lock(&au0828_sysfs_lock); - - if (dev->vdev) - video_unregister_device(dev->vdev); - if (dev->vbi_dev) - video_unregister_device(dev->vbi_dev); - - mutex_unlock(&au0828_sysfs_lock); -} - - -/* Usage lock check functions */ -static int res_get(struct au0828_fh *fh, unsigned int bit) -{ - struct au0828_dev *dev = fh->dev; - - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources & bit) { - /* no, someone else uses it */ - mutex_unlock(&dev->lock); - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(1, "res: get %d\n", bit); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_check(struct au0828_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct au0828_dev *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct au0828_fh *fh, unsigned int bits) -{ - struct au0828_dev *dev = fh->dev; - - BUG_ON((fh->resources & bits) != bits); - - mutex_lock(&dev->lock); - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk(1, "res: put %d\n", bits); - mutex_unlock(&dev->lock); -} - -static int get_ressource(struct au0828_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return AU0828_RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return AU0828_RESOURCE_VBI; - default: - BUG(); - return 0; - } -} - -/* This function ensures that video frames continue to be delivered even if - the ITU-656 input isn't receiving any data (thereby preventing applications - such as tvtime from hanging) */ -void au0828_vid_buffer_timeout(unsigned long data) -{ - struct au0828_dev *dev = (struct au0828_dev *) data; - struct au0828_dmaqueue *dma_q = &dev->vidq; - struct au0828_buffer *buf; - unsigned char *vid_data; - unsigned long flags = 0; - - spin_lock_irqsave(&dev->slock, flags); - - buf = dev->isoc_ctl.buf; - if (buf != NULL) { - vid_data = videobuf_to_vmalloc(&buf->vb); - memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */ - buffer_filled(dev, dma_q, buf); - } - get_next_buf(dma_q, &buf); - - if (dev->vid_timeout_running == 1) - mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); - - spin_unlock_irqrestore(&dev->slock, flags); -} - -void au0828_vbi_buffer_timeout(unsigned long data) -{ - struct au0828_dev *dev = (struct au0828_dev *) data; - struct au0828_dmaqueue *dma_q = &dev->vbiq; - struct au0828_buffer *buf; - unsigned char *vbi_data; - unsigned long flags = 0; - - spin_lock_irqsave(&dev->slock, flags); - - buf = dev->isoc_ctl.vbi_buf; - if (buf != NULL) { - vbi_data = videobuf_to_vmalloc(&buf->vb); - memset(vbi_data, 0x00, buf->vb.size); - vbi_buffer_filled(dev, dma_q, buf); - } - vbi_get_next_buf(dma_q, &buf); - - if (dev->vbi_timeout_running == 1) - mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); - spin_unlock_irqrestore(&dev->slock, flags); -} - - -static int au0828_v4l2_open(struct file *filp) -{ - int ret = 0; - struct video_device *vdev = video_devdata(filp); - struct au0828_dev *dev = video_drvdata(filp); - struct au0828_fh *fh; - int type; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - default: - return -EINVAL; - } - - fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL); - if (NULL == fh) { - dprintk(1, "Failed allocate au0828_fh struct!\n"); - return -ENOMEM; - } - - fh->type = type; - fh->dev = dev; - filp->private_data = fh; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { - /* set au0828 interface0 to AS5 here again */ - ret = usb_set_interface(dev->usbdev, 0, 5); - if (ret < 0) { - printk(KERN_INFO "Au0828 can't set alternate to 5!\n"); - return -EBUSY; - } - dev->width = NTSC_STD_W; - dev->height = NTSC_STD_H; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->width * dev->height; - dev->bytesperline = dev->width * 2; - - au0828_analog_stream_enable(dev); - au0828_analog_stream_reset(dev); - - /* If we were doing ac97 instead of i2s, it would go here...*/ - au0828_i2s_init(dev); - - dev->stream_state = STREAM_OFF; - dev->dev_state |= DEV_INITIALIZED; - } - - dev->users++; - - videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops, - NULL, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct au0828_buffer), fh, NULL); - - /* VBI Setup */ - dev->vbi_width = 720; - dev->vbi_height = 1; - videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops, - NULL, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct au0828_buffer), fh, NULL); - - return ret; -} - -static int au0828_v4l2_close(struct file *filp) -{ - int ret; - struct au0828_fh *fh = filp->private_data; - struct au0828_dev *dev = fh->dev; - - if (res_check(fh, AU0828_RESOURCE_VIDEO)) { - /* Cancel timeout thread in case they didn't call streamoff */ - dev->vid_timeout_running = 0; - del_timer_sync(&dev->vid_timeout); - - videobuf_stop(&fh->vb_vidq); - res_free(fh, AU0828_RESOURCE_VIDEO); - } - - if (res_check(fh, AU0828_RESOURCE_VBI)) { - /* Cancel timeout thread in case they didn't call streamoff */ - dev->vbi_timeout_running = 0; - del_timer_sync(&dev->vbi_timeout); - - videobuf_stop(&fh->vb_vbiq); - res_free(fh, AU0828_RESOURCE_VBI); - } - - if (dev->users == 1) { - if (dev->dev_state & DEV_DISCONNECTED) { - au0828_analog_unregister(dev); - kfree(dev); - return 0; - } - - au0828_analog_stream_disable(dev); - - au0828_uninit_isoc(dev); - - /* Save some power by putting tuner to sleep */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); - - /* When close the device, set the usb intf0 into alt0 to free - USB bandwidth */ - ret = usb_set_interface(dev->usbdev, 0, 0); - if (ret < 0) - printk(KERN_INFO "Au0828 can't set alternate to 0!\n"); - } - - videobuf_mmap_free(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vbiq); - kfree(fh); - dev->users--; - wake_up_interruptible_nr(&dev->open, 1); - return 0; -} - -static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf, - size_t count, loff_t *pos) -{ - struct au0828_fh *fh = filp->private_data; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (res_locked(dev, AU0828_RESOURCE_VIDEO)) - return -EBUSY; - - return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - } - - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (!res_get(fh, AU0828_RESOURCE_VBI)) - return -EBUSY; - - if (dev->vbi_timeout_running == 0) { - /* Handle case where caller tries to read without - calling streamon first */ - dev->vbi_timeout_running = 1; - mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); - } - - return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - } - - return 0; -} - -static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait) -{ - struct au0828_fh *fh = filp->private_data; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (!res_get(fh, AU0828_RESOURCE_VIDEO)) - return POLLERR; - return videobuf_poll_stream(filp, &fh->vb_vidq, wait); - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (!res_get(fh, AU0828_RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(filp, &fh->vb_vbiq, wait); - } else { - return POLLERR; - } -} - -static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct au0828_fh *fh = filp->private_data; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma); - - return rc; -} - -static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, - struct v4l2_format *format) -{ - int ret; - int width = format->fmt.pix.width; - int height = format->fmt.pix.height; - - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - /* If they are demanding a format other than the one we support, - bail out (tvtime asks for UYVY and then retries with YUYV) */ - if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY) - return -EINVAL; - - /* format->fmt.pix.width only support 720 and height 480 */ - if (width != 720) - width = 720; - if (height != 480) - height = 480; - - format->fmt.pix.width = width; - format->fmt.pix.height = height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; - format->fmt.pix.bytesperline = width * 2; - format->fmt.pix.sizeimage = width * height * 2; - format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - format->fmt.pix.field = V4L2_FIELD_INTERLACED; - - if (cmd == VIDIOC_TRY_FMT) - return 0; - - /* maybe set new image format, driver current only support 720*480 */ - dev->width = width; - dev->height = height; - dev->frame_size = width * height * 2; - dev->field_size = width * height; - dev->bytesperline = width * 2; - - if (dev->stream_state == STREAM_ON) { - dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n"); - ret = au0828_stream_interrupt(dev); - if (ret != 0) { - dprintk(1, "error interrupting video stream!\n"); - return ret; - } - } - - /* set au0828 interface0 to AS5 here again */ - ret = usb_set_interface(dev->usbdev, 0, 5); - if (ret < 0) { - printk(KERN_INFO "Au0828 can't set alt setting to 5!\n"); - return -EBUSY; - } - - au0828_analog_stream_enable(dev); - - return 0; -} - - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc); - if (qc->type) - return 0; - else - return -EINVAL; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - strlcpy(cap->driver, "au0828", sizeof(cap->driver)); - strlcpy(cap->card, dev->board.name, sizeof(cap->card)); - strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); - - cap->version = AU0828_VERSION_CODE; - - /*set the device capabilities */ - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index) - return -EINVAL; - - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(f->description, "Packed YUV2"); - - f->flags = 0; - f->pixelformat = V4L2_PIX_FMT_UYVY; - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; - f->fmt.pix.bytesperline = dev->bytesperline; - f->fmt.pix.sizeimage = dev->frame_size; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */ - f->fmt.pix.field = V4L2_FIELD_INTERLACED; - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - return au0828_set_format(dev, VIDIOC_TRY_FMT, f); -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - mutex_lock(&dev->lock); - - if (videobuf_queue_is_busy(&fh->vb_vidq)) { - printk(KERN_INFO "%s queue busy\n", __func__); - rc = -EBUSY; - goto out; - } - - rc = au0828_set_format(dev, VIDIOC_S_FMT, f); -out: - mutex_unlock(&dev->lock); - return rc; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - /* FIXME: when we support something other than NTSC, we are going to - have to make the au0828 bridge adjust the size of its capture - buffer, which is currently hardcoded at 720x480 */ - - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm); - return 0; -} - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *input) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - unsigned int tmp; - - static const char *inames[] = { - [AU0828_VMUX_UNDEFINED] = "Undefined", - [AU0828_VMUX_COMPOSITE] = "Composite", - [AU0828_VMUX_SVIDEO] = "S-Video", - [AU0828_VMUX_CABLE] = "Cable TV", - [AU0828_VMUX_TELEVISION] = "Television", - [AU0828_VMUX_DVB] = "DVB", - [AU0828_VMUX_DEBUG] = "tv debug" - }; - - tmp = input->index; - - if (tmp >= AU0828_MAX_INPUT) - return -EINVAL; - if (AUVI_INPUT(tmp).type == 0) - return -EINVAL; - - input->index = tmp; - strcpy(input->name, inames[AUVI_INPUT(tmp).type]); - if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) || - (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE)) - input->type |= V4L2_INPUT_TYPE_TUNER; - else - input->type |= V4L2_INPUT_TYPE_CAMERA; - - input->std = dev->vdev->tvnorms; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - *i = dev->ctrl_input; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int index) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int i; - - dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__, - index); - if (index >= AU0828_MAX_INPUT) - return -EINVAL; - if (AUVI_INPUT(index).type == 0) - return -EINVAL; - dev->ctrl_input = index; - - switch (AUVI_INPUT(index).type) { - case AU0828_VMUX_SVIDEO: - dev->input_type = AU0828_VMUX_SVIDEO; - break; - case AU0828_VMUX_COMPOSITE: - dev->input_type = AU0828_VMUX_COMPOSITE; - break; - case AU0828_VMUX_TELEVISION: - dev->input_type = AU0828_VMUX_TELEVISION; - break; - default: - dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n", - AUVI_INPUT(index).type); - break; - } - - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, - AUVI_INPUT(index).vmux, 0, 0); - - for (i = 0; i < AU0828_MAX_INPUT; i++) { - int enable = 0; - if (AUVI_INPUT(i).audio_setup == NULL) - continue; - - if (i == index) - enable = 1; - else - enable = 0; - if (enable) { - (AUVI_INPUT(i).audio_setup)(dev, enable); - } else { - /* Make sure we leave it turned on if some - other input is routed to this callback */ - if ((AUVI_INPUT(i).audio_setup) != - ((AUVI_INPUT(index).audio_setup))) { - (AUVI_INPUT(i).audio_setup)(dev, enable); - } - } - } - - v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, - AUVI_INPUT(index).amux, 0, 0); - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - unsigned int index = a->index; - - if (a->index > 1) - return -EINVAL; - - index = dev->ctrl_ainput; - if (index == 0) - strcpy(a->name, "Television"); - else - strcpy(a->name, "Line in"); - - a->capability = V4L2_AUDCAP_STEREO; - a->index = index; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - if (a->index != dev->ctrl_ainput) - return -EINVAL; - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); - return 0; - -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl); - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - if (t->index != 0) - return -EINVAL; - - strcpy(t->name, "Auvitek tuner"); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - if (t->index != 0) - return -EINVAL; - - t->type = V4L2_TUNER_ANALOG_TV; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal, - t->afc); - return 0; - -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - freq->type = V4L2_TUNER_ANALOG_TV; - freq->frequency = dev->ctrl_freq; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - if (freq->tuner != 0) - return -EINVAL; - if (freq->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - - dev->ctrl_freq = freq->frequency; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq); - - au0828_analog_stream_reset(dev); - - return 0; -} - - -/* RAW VBI ioctls */ - -static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - format->fmt.vbi.samples_per_line = dev->vbi_width; - format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - format->fmt.vbi.offset = 0; - format->fmt.vbi.flags = 0; - format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; - - format->fmt.vbi.count[0] = dev->vbi_height; - format->fmt.vbi.count[1] = dev->vbi_height; - format->fmt.vbi.start[0] = 21; - format->fmt.vbi.start[1] = 284; - - return 0; -} - -static int vidioc_g_chip_ident(struct file *file, void *priv, - struct v4l2_dbg_chip_ident *chip) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - - if (v4l2_chip_match_host(&chip->match)) { - chip->ident = V4L2_IDENT_AU0828; - return 0; - } - - v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip); - if (chip->ident == V4L2_IDENT_NONE) - return -EINVAL; - - return 0; -} - -static int vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cc) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - cc->bounds.left = 0; - cc->bounds.top = 0; - cc->bounds.width = dev->width; - cc->bounds.height = dev->height; - - cc->defrect = cc->bounds; - - cc->pixelaspect.numerator = 54; - cc->pixelaspect.denominator = 59; - - return 0; -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc = -EINVAL; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (unlikely(type != fh->type)) - return -EINVAL; - - dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n", - fh, type, fh->resources, dev->resources); - - if (unlikely(!res_get(fh, get_ressource(fh)))) - return -EBUSY; - - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - au0828_analog_stream_enable(dev); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); - } - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - rc = videobuf_streamon(&fh->vb_vidq); - dev->vid_timeout_running = 1; - mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - rc = videobuf_streamon(&fh->vb_vbiq); - dev->vbi_timeout_running = 1; - mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); - } - - return rc; -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - int i; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) - return -EINVAL; - if (type != fh->type) - return -EINVAL; - - dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n", - fh, type, fh->resources, dev->resources); - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev->vid_timeout_running = 0; - del_timer_sync(&dev->vid_timeout); - - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); - rc = au0828_stream_interrupt(dev); - if (rc != 0) - return rc; - - for (i = 0; i < AU0828_MAX_INPUT; i++) { - if (AUVI_INPUT(i).audio_setup == NULL) - continue; - (AUVI_INPUT(i).audio_setup)(dev, 0); - } - - videobuf_streamoff(&fh->vb_vidq); - res_free(fh, AU0828_RESOURCE_VIDEO); - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - dev->vbi_timeout_running = 0; - del_timer_sync(&dev->vbi_timeout); - - videobuf_streamoff(&fh->vb_vbiq); - res_free(fh, AU0828_RESOURCE_VBI); - } - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - switch (reg->match.type) { - case V4L2_CHIP_MATCH_I2C_DRIVER: - v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); - return 0; - default: - return -EINVAL; - } -} - -static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - switch (reg->match.type) { - case V4L2_CHIP_MATCH_I2C_DRIVER: - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); - return 0; - default: - return -EINVAL; - } - return 0; -} -#endif - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_reqbufs(&fh->vb_vidq, rb); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_reqbufs(&fh->vb_vbiq, rb); - - return rc; -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_querybuf(&fh->vb_vidq, b); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_querybuf(&fh->vb_vbiq, b); - - return rc; -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_qbuf(&fh->vb_vidq, b); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_qbuf(&fh->vb_vbiq, b); - - return rc; -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - /* Workaround for a bug in the au0828 hardware design that sometimes - results in the colorspace being inverted */ - if (dev->greenscreen_detected == 1) { - dprintk(1, "Detected green frame. Resetting stream...\n"); - au0828_analog_stream_reset(dev); - dev->greenscreen_detected = 0; - } - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK); - - return rc; -} - -static struct v4l2_file_operations au0828_v4l_fops = { - .owner = THIS_MODULE, - .open = au0828_v4l2_open, - .release = au0828_v4l2_close, - .read = au0828_v4l2_read, - .poll = au0828_v4l2_poll, - .mmap = au0828_v4l2_mmap, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_cropcap = vidioc_cropcap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif - .vidioc_g_chip_ident = vidioc_g_chip_ident, -}; - -static const struct video_device au0828_video_template = { - .fops = &au0828_v4l_fops, - .release = video_device_release, - .ioctl_ops = &video_ioctl_ops, - .tvnorms = V4L2_STD_NTSC_M, - .current_norm = V4L2_STD_NTSC_M, -}; - -/**************************************************************************/ - -int au0828_analog_register(struct au0828_dev *dev, - struct usb_interface *interface) -{ - int retval = -ENOMEM; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int i; - - dprintk(1, "au0828_analog_register called!\n"); - - /* set au0828 usb interface0 to as5 */ - retval = usb_set_interface(dev->usbdev, - interface->cur_altsetting->desc.bInterfaceNumber, 5); - if (retval != 0) { - printk(KERN_INFO "Failure setting usb interface0 to as5\n"); - return retval; - } - - /* Figure out which endpoint has the isoc interface */ - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - endpoint = &iface_desc->endpoint[i].desc; - if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) && - ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_ISOC)) { - - /* we find our isoc in endpoint */ - u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize); - dev->max_pkt_size = (tmp & 0x07ff) * - (((tmp & 0x1800) >> 11) + 1); - dev->isoc_in_endpointaddr = endpoint->bEndpointAddress; - } - } - if (!(dev->isoc_in_endpointaddr)) { - printk(KERN_INFO "Could not locate isoc endpoint\n"); - kfree(dev); - return -ENODEV; - } - - init_waitqueue_head(&dev->open); - spin_lock_init(&dev->slock); - mutex_init(&dev->lock); - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - INIT_LIST_HEAD(&dev->vbiq.active); - INIT_LIST_HEAD(&dev->vbiq.queued); - - dev->vid_timeout.function = au0828_vid_buffer_timeout; - dev->vid_timeout.data = (unsigned long) dev; - init_timer(&dev->vid_timeout); - - dev->vbi_timeout.function = au0828_vbi_buffer_timeout; - dev->vbi_timeout.data = (unsigned long) dev; - init_timer(&dev->vbi_timeout); - - dev->width = NTSC_STD_W; - dev->height = NTSC_STD_H; - dev->field_size = dev->width * dev->height; - dev->frame_size = dev->field_size << 1; - dev->bytesperline = dev->width << 1; - dev->ctrl_ainput = 0; - - /* allocate and fill v4l2 video struct */ - dev->vdev = video_device_alloc(); - if (NULL == dev->vdev) { - dprintk(1, "Can't allocate video_device.\n"); - return -ENOMEM; - } - - /* allocate the VBI struct */ - dev->vbi_dev = video_device_alloc(); - if (NULL == dev->vbi_dev) { - dprintk(1, "Can't allocate vbi_device.\n"); - kfree(dev->vdev); - return -ENOMEM; - } - - /* Fill the video capture device struct */ - *dev->vdev = au0828_video_template; - dev->vdev->parent = &dev->usbdev->dev; - strcpy(dev->vdev->name, "au0828a video"); - - /* Setup the VBI device */ - *dev->vbi_dev = au0828_video_template; - dev->vbi_dev->parent = &dev->usbdev->dev; - strcpy(dev->vbi_dev->name, "au0828a vbi"); - - /* Register the v4l2 device */ - video_set_drvdata(dev->vdev, dev); - retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1); - if (retval != 0) { - dprintk(1, "unable to register video device (error = %d).\n", - retval); - video_device_release(dev->vdev); - return -ENODEV; - } - - /* Register the vbi device */ - video_set_drvdata(dev->vbi_dev, dev); - retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1); - if (retval != 0) { - dprintk(1, "unable to register vbi device (error = %d).\n", - retval); - video_device_release(dev->vbi_dev); - video_device_release(dev->vdev); - return -ENODEV; - } - - dprintk(1, "%s completed!\n", __func__); - - return 0; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ - -config VIDEO_AU0828 - tristate "Auvitek AU0828 support" - depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 - select I2C_ALGOBIT - select VIDEO_TVEEPROM - select VIDEOBUF_VMALLOC - select DVB_AU8522 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - ---help--- - This is a video4linux driver for Auvitek's USB device. - - To compile this driver as a module, choose M here: the - module will be called au0828 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/au0828/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o - -obj-$(CONFIG_VIDEO_AU0828) += au0828.o - -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends - -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt819.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt819.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt819.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt819.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,528 +0,0 @@ -/* - * bt819 - BT819A VideoStream Decoder (Rockwell Part) - * - * Copyright (C) 1999 Mike Bernson - * Copyright (C) 1998 Dave Perks - * - * Modifications for LML33/DC10plus unified driver - * Copyright (C) 2000 Serguei Miridonov - * - * Changes by Ronald Bultje - * - moved over to linux>=2.4.x i2c protocol (9/9/2002) - * - * This code was modify/ported from the saa7111 driver written - * by Dave Perks. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("Brooktree-819 video decoder driver"); -MODULE_AUTHOR("Mike Bernson & Dave Perks"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -/* ----------------------------------------------------------------------- */ - -struct bt819 { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - unsigned char reg[32]; - - v4l2_std_id norm; - int ident; - int input; - int enable; -}; - -static inline struct bt819 *to_bt819(struct v4l2_subdev *sd) -{ - return container_of(sd, struct bt819, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct bt819, hdl)->sd; -} - -struct timing { - int hactive; - int hdelay; - int vactive; - int vdelay; - int hscale; - int vscale; -}; - -/* for values, see the bt819 datasheet */ -static struct timing timing_data[] = { - {864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000}, - {858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000}, -}; - -/* ----------------------------------------------------------------------- */ - -static inline int bt819_write(struct bt819 *decoder, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); - - decoder->reg[reg] = value; - return i2c_smbus_write_byte_data(client, reg, value); -} - -static inline int bt819_setbit(struct bt819 *decoder, u8 reg, u8 bit, u8 value) -{ - return bt819_write(decoder, reg, - (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0)); -} - -static int bt819_write_block(struct bt819 *decoder, const u8 *data, unsigned int len) -{ - struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); - int ret = -1; - u8 reg; - - /* the bt819 has an autoincrement function, use it if - * the adapter understands raw I2C */ - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - /* do raw I2C, not smbus compatible */ - u8 block_data[32]; - int block_len; - - while (len >= 2) { - block_len = 0; - block_data[block_len++] = reg = data[0]; - do { - block_data[block_len++] = - decoder->reg[reg++] = data[1]; - len -= 2; - data += 2; - } while (len >= 2 && data[0] == reg && block_len < 32); - ret = i2c_master_send(client, block_data, block_len); - if (ret < 0) - break; - } - } else { - /* do some slow I2C emulation kind of thing */ - while (len >= 2) { - reg = *data++; - ret = bt819_write(decoder, reg, *data++); - if (ret < 0) - break; - len -= 2; - } - } - - return ret; -} - -static inline int bt819_read(struct bt819 *decoder, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); - - return i2c_smbus_read_byte_data(client, reg); -} - -static int bt819_init(struct v4l2_subdev *sd) -{ - static unsigned char init[] = { - /*0x1f, 0x00,*/ /* Reset */ - 0x01, 0x59, /* 0x01 input format */ - 0x02, 0x00, /* 0x02 temporal decimation */ - 0x03, 0x12, /* 0x03 Cropping msb */ - 0x04, 0x16, /* 0x04 Vertical Delay, lsb */ - 0x05, 0xe0, /* 0x05 Vertical Active lsb */ - 0x06, 0x80, /* 0x06 Horizontal Delay lsb */ - 0x07, 0xd0, /* 0x07 Horizontal Active lsb */ - 0x08, 0x00, /* 0x08 Horizontal Scaling msb */ - 0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */ - 0x0a, 0x00, /* 0x0a Brightness control */ - 0x0b, 0x30, /* 0x0b Miscellaneous control */ - 0x0c, 0xd8, /* 0x0c Luma Gain lsb */ - 0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */ - 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */ - 0x0f, 0x00, /* 0x0f Hue control */ - 0x12, 0x04, /* 0x12 Output Format */ - 0x13, 0x20, /* 0x13 Vertial Scaling msb 0x00 - chroma comb OFF, line drop scaling, interlace scaling - BUG? Why does turning the chroma comb on fuck up color? - Bug in the bt819 stepping on my board? - */ - 0x14, 0x00, /* 0x14 Vertial Scaling lsb */ - 0x16, 0x07, /* 0x16 Video Timing Polarity - ACTIVE=active low - FIELD: high=odd, - vreset=active high, - hreset=active high */ - 0x18, 0x68, /* 0x18 AGC Delay */ - 0x19, 0x5d, /* 0x19 Burst Gate Delay */ - 0x1a, 0x80, /* 0x1a ADC Interface */ - }; - - struct bt819 *decoder = to_bt819(sd); - struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0]; - - init[0x03 * 2 - 1] = - (((timing->vdelay >> 8) & 0x03) << 6) | - (((timing->vactive >> 8) & 0x03) << 4) | - (((timing->hdelay >> 8) & 0x03) << 2) | - ((timing->hactive >> 8) & 0x03); - init[0x04 * 2 - 1] = timing->vdelay & 0xff; - init[0x05 * 2 - 1] = timing->vactive & 0xff; - init[0x06 * 2 - 1] = timing->hdelay & 0xff; - init[0x07 * 2 - 1] = timing->hactive & 0xff; - init[0x08 * 2 - 1] = timing->hscale >> 8; - init[0x09 * 2 - 1] = timing->hscale & 0xff; - /* 0x15 in array is address 0x19 */ - init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93; /* Chroma burst delay */ - /* reset */ - bt819_write(decoder, 0x1f, 0x00); - mdelay(1); - - /* init */ - return bt819_write_block(decoder, init, sizeof(init)); -} - -/* ----------------------------------------------------------------------- */ - -static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) -{ - struct bt819 *decoder = to_bt819(sd); - int status = bt819_read(decoder, 0x00); - int res = V4L2_IN_ST_NO_SIGNAL; - v4l2_std_id std; - - if ((status & 0x80)) - res = 0; - - if ((status & 0x10)) - std = V4L2_STD_PAL; - else - std = V4L2_STD_NTSC; - if (pstd) - *pstd = std; - if (pstatus) - *pstatus = status; - - v4l2_dbg(1, debug, sd, "get status %x\n", status); - return 0; -} - -static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) -{ - return bt819_status(sd, NULL, std); -} - -static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status) -{ - return bt819_status(sd, status, NULL); -} - -static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct bt819 *decoder = to_bt819(sd); - struct timing *timing = NULL; - - v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); - - if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL) - v4l2_err(sd, "no notify found!\n"); - - if (std & V4L2_STD_NTSC) { - v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL); - bt819_setbit(decoder, 0x01, 0, 1); - bt819_setbit(decoder, 0x01, 1, 0); - bt819_setbit(decoder, 0x01, 5, 0); - bt819_write(decoder, 0x18, 0x68); - bt819_write(decoder, 0x19, 0x5d); - /* bt819_setbit(decoder, 0x1a, 5, 1); */ - timing = &timing_data[1]; - } else if (std & V4L2_STD_PAL) { - v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL); - bt819_setbit(decoder, 0x01, 0, 1); - bt819_setbit(decoder, 0x01, 1, 1); - bt819_setbit(decoder, 0x01, 5, 1); - bt819_write(decoder, 0x18, 0x7f); - bt819_write(decoder, 0x19, 0x72); - /* bt819_setbit(decoder, 0x1a, 5, 0); */ - timing = &timing_data[0]; - } else { - v4l2_dbg(1, debug, sd, "unsupported norm %llx\n", - (unsigned long long)std); - return -EINVAL; - } - bt819_write(decoder, 0x03, - (((timing->vdelay >> 8) & 0x03) << 6) | - (((timing->vactive >> 8) & 0x03) << 4) | - (((timing->hdelay >> 8) & 0x03) << 2) | - ((timing->hactive >> 8) & 0x03)); - bt819_write(decoder, 0x04, timing->vdelay & 0xff); - bt819_write(decoder, 0x05, timing->vactive & 0xff); - bt819_write(decoder, 0x06, timing->hdelay & 0xff); - bt819_write(decoder, 0x07, timing->hactive & 0xff); - bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff); - bt819_write(decoder, 0x09, timing->hscale & 0xff); - decoder->norm = std; - v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL); - return 0; -} - -static int bt819_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct bt819 *decoder = to_bt819(sd); - - v4l2_dbg(1, debug, sd, "set input %x\n", input); - - if (input > 7) - return -EINVAL; - - if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL) - v4l2_err(sd, "no notify found!\n"); - - if (decoder->input != input) { - v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL); - decoder->input = input; - /* select mode */ - if (decoder->input == 0) { - bt819_setbit(decoder, 0x0b, 6, 0); - bt819_setbit(decoder, 0x1a, 1, 1); - } else { - bt819_setbit(decoder, 0x0b, 6, 1); - bt819_setbit(decoder, 0x1a, 1, 0); - } - v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL); - } - return 0; -} - -static int bt819_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct bt819 *decoder = to_bt819(sd); - - v4l2_dbg(1, debug, sd, "enable output %x\n", enable); - - if (decoder->enable != enable) { - decoder->enable = enable; - bt819_setbit(decoder, 0x16, 7, !enable); - } - return 0; -} - -static int bt819_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct bt819 *decoder = to_bt819(sd); - int temp; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - bt819_write(decoder, 0x0a, ctrl->val); - break; - - case V4L2_CID_CONTRAST: - bt819_write(decoder, 0x0c, ctrl->val & 0xff); - bt819_setbit(decoder, 0x0b, 2, ((ctrl->val >> 8) & 0x01)); - break; - - case V4L2_CID_SATURATION: - bt819_write(decoder, 0x0d, (ctrl->val >> 7) & 0xff); - bt819_setbit(decoder, 0x0b, 1, ((ctrl->val >> 15) & 0x01)); - - /* Ratio between U gain and V gain must stay the same as - the ratio between the default U and V gain values. */ - temp = (ctrl->val * 180) / 254; - bt819_write(decoder, 0x0e, (temp >> 7) & 0xff); - bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01); - break; - - case V4L2_CID_HUE: - bt819_write(decoder, 0x0f, ctrl->val); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct bt819 *decoder = to_bt819(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops bt819_ctrl_ops = { - .s_ctrl = bt819_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops bt819_core_ops = { - .g_chip_ident = bt819_g_chip_ident, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = bt819_s_std, -}; - -static const struct v4l2_subdev_video_ops bt819_video_ops = { - .s_routing = bt819_s_routing, - .s_stream = bt819_s_stream, - .querystd = bt819_querystd, - .g_input_status = bt819_g_input_status, -}; - -static const struct v4l2_subdev_ops bt819_ops = { - .core = &bt819_core_ops, - .video = &bt819_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int bt819_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int i, ver; - struct bt819 *decoder; - struct v4l2_subdev *sd; - const char *name; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL); - if (decoder == NULL) - return -ENOMEM; - sd = &decoder->sd; - v4l2_i2c_subdev_init(sd, client, &bt819_ops); - - ver = bt819_read(decoder, 0x17); - switch (ver & 0xf0) { - case 0x70: - name = "bt819a"; - decoder->ident = V4L2_IDENT_BT819A; - break; - case 0x60: - name = "bt817a"; - decoder->ident = V4L2_IDENT_BT817A; - break; - case 0x20: - name = "bt815a"; - decoder->ident = V4L2_IDENT_BT815A; - break; - default: - v4l2_dbg(1, debug, sd, - "unknown chip version 0x%02x\n", ver); - return -ENODEV; - } - - v4l_info(client, "%s found @ 0x%x (%s)\n", name, - client->addr << 1, client->adapter->name); - - decoder->norm = V4L2_STD_NTSC; - decoder->input = 0; - decoder->enable = 1; - - i = bt819_init(sd); - if (i < 0) - v4l2_dbg(1, debug, sd, "init status %d\n", i); - - v4l2_ctrl_handler_init(&decoder->hdl, 4); - v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, - V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); - v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, - V4L2_CID_CONTRAST, 0, 511, 1, 0xd8); - v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, - V4L2_CID_SATURATION, 0, 511, 1, 0xfe); - v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - sd->ctrl_handler = &decoder->hdl; - if (decoder->hdl.error) { - int err = decoder->hdl.error; - - v4l2_ctrl_handler_free(&decoder->hdl); - kfree(decoder); - return err; - } - v4l2_ctrl_handler_setup(&decoder->hdl); - return 0; -} - -static int bt819_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct bt819 *decoder = to_bt819(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&decoder->hdl); - kfree(decoder); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id bt819_id[] = { - { "bt819a", 0 }, - { "bt817a", 0 }, - { "bt815a", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, bt819_id); - -static struct i2c_driver bt819_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "bt819", - }, - .probe = bt819_probe, - .remove = bt819_remove, - .id_table = bt819_id, -}; - -static __init int init_bt819(void) -{ - return i2c_add_driver(&bt819_driver); -} - -static __exit void exit_bt819(void) -{ - i2c_del_driver(&bt819_driver); -} - -module_init(init_bt819); -module_exit(exit_bt819); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt856.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt856.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt856.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt856.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,284 +0,0 @@ -/* - * bt856 - BT856A Digital Video Encoder (Rockwell Part) - * - * Copyright (C) 1999 Mike Bernson - * Copyright (C) 1998 Dave Perks - * - * Modifications for LML33/DC10plus unified driver - * Copyright (C) 2000 Serguei Miridonov - * - * This code was modify/ported from the saa7111 driver written - * by Dave Perks. - * - * Changes by Ronald Bultje - * - moved over to linux>=2.4.x i2c protocol (9/9/2002) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("Brooktree-856A video encoder driver"); -MODULE_AUTHOR("Mike Bernson & Dave Perks"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -/* ----------------------------------------------------------------------- */ - -#define BT856_REG_OFFSET 0xDA -#define BT856_NR_REG 6 - -struct bt856 { - struct v4l2_subdev sd; - unsigned char reg[BT856_NR_REG]; - - v4l2_std_id norm; -}; - -static inline struct bt856 *to_bt856(struct v4l2_subdev *sd) -{ - return container_of(sd, struct bt856, sd); -} - -/* ----------------------------------------------------------------------- */ - -static inline int bt856_write(struct bt856 *encoder, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd); - - encoder->reg[reg - BT856_REG_OFFSET] = value; - return i2c_smbus_write_byte_data(client, reg, value); -} - -static inline int bt856_setbit(struct bt856 *encoder, u8 reg, u8 bit, u8 value) -{ - return bt856_write(encoder, reg, - (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) | - (value ? (1 << bit) : 0)); -} - -static void bt856_dump(struct bt856 *encoder) -{ - int i; - - v4l2_info(&encoder->sd, "register dump:\n"); - for (i = 0; i < BT856_NR_REG; i += 2) - printk(KERN_CONT " %02x", encoder->reg[i]); - printk(KERN_CONT "\n"); -} - -/* ----------------------------------------------------------------------- */ - -static int bt856_init(struct v4l2_subdev *sd, u32 arg) -{ - struct bt856 *encoder = to_bt856(sd); - - /* This is just for testing!!! */ - v4l2_dbg(1, debug, sd, "init\n"); - bt856_write(encoder, 0xdc, 0x18); - bt856_write(encoder, 0xda, 0); - bt856_write(encoder, 0xde, 0); - - bt856_setbit(encoder, 0xdc, 3, 1); - /*bt856_setbit(encoder, 0xdc, 6, 0);*/ - bt856_setbit(encoder, 0xdc, 4, 1); - - if (encoder->norm & V4L2_STD_NTSC) - bt856_setbit(encoder, 0xdc, 2, 0); - else - bt856_setbit(encoder, 0xdc, 2, 1); - - bt856_setbit(encoder, 0xdc, 1, 1); - bt856_setbit(encoder, 0xde, 4, 0); - bt856_setbit(encoder, 0xde, 3, 1); - if (debug != 0) - bt856_dump(encoder); - return 0; -} - -static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct bt856 *encoder = to_bt856(sd); - - v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); - - if (std & V4L2_STD_NTSC) { - bt856_setbit(encoder, 0xdc, 2, 0); - } else if (std & V4L2_STD_PAL) { - bt856_setbit(encoder, 0xdc, 2, 1); - bt856_setbit(encoder, 0xda, 0, 0); - /*bt856_setbit(encoder, 0xda, 0, 1);*/ - } else { - return -EINVAL; - } - encoder->norm = std; - if (debug != 0) - bt856_dump(encoder); - return 0; -} - -static int bt856_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct bt856 *encoder = to_bt856(sd); - - v4l2_dbg(1, debug, sd, "set input %d\n", input); - - /* We only have video bus. - * input= 0: input is from bt819 - * input= 1: input is from ZR36060 */ - switch (input) { - case 0: - bt856_setbit(encoder, 0xde, 4, 0); - bt856_setbit(encoder, 0xde, 3, 1); - bt856_setbit(encoder, 0xdc, 3, 1); - bt856_setbit(encoder, 0xdc, 6, 0); - break; - case 1: - bt856_setbit(encoder, 0xde, 4, 0); - bt856_setbit(encoder, 0xde, 3, 1); - bt856_setbit(encoder, 0xdc, 3, 1); - bt856_setbit(encoder, 0xdc, 6, 1); - break; - case 2: /* Color bar */ - bt856_setbit(encoder, 0xdc, 3, 0); - bt856_setbit(encoder, 0xde, 4, 1); - break; - default: - return -EINVAL; - } - - if (debug != 0) - bt856_dump(encoder); - return 0; -} - -static int bt856_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT856, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops bt856_core_ops = { - .g_chip_ident = bt856_g_chip_ident, - .init = bt856_init, -}; - -static const struct v4l2_subdev_video_ops bt856_video_ops = { - .s_std_output = bt856_s_std_output, - .s_routing = bt856_s_routing, -}; - -static const struct v4l2_subdev_ops bt856_ops = { - .core = &bt856_core_ops, - .video = &bt856_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int bt856_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct bt856 *encoder; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL); - if (encoder == NULL) - return -ENOMEM; - sd = &encoder->sd; - v4l2_i2c_subdev_init(sd, client, &bt856_ops); - encoder->norm = V4L2_STD_NTSC; - - bt856_write(encoder, 0xdc, 0x18); - bt856_write(encoder, 0xda, 0); - bt856_write(encoder, 0xde, 0); - - bt856_setbit(encoder, 0xdc, 3, 1); - /*bt856_setbit(encoder, 0xdc, 6, 0);*/ - bt856_setbit(encoder, 0xdc, 4, 1); - - if (encoder->norm & V4L2_STD_NTSC) - bt856_setbit(encoder, 0xdc, 2, 0); - else - bt856_setbit(encoder, 0xdc, 2, 1); - - bt856_setbit(encoder, 0xdc, 1, 1); - bt856_setbit(encoder, 0xde, 4, 0); - bt856_setbit(encoder, 0xde, 3, 1); - - if (debug != 0) - bt856_dump(encoder); - return 0; -} - -static int bt856_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_bt856(sd)); - return 0; -} - -static const struct i2c_device_id bt856_id[] = { - { "bt856", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, bt856_id); - -static struct i2c_driver bt856_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "bt856", - }, - .probe = bt856_probe, - .remove = bt856_remove, - .id_table = bt856_id, -}; - -static __init int init_bt856(void) -{ - return i2c_add_driver(&bt856_driver); -} - -static __exit void exit_bt856(void) -{ - i2c_del_driver(&bt856_driver); -} - -module_init(init_bt856); -module_exit(exit_bt856); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt866.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt866.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt866.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt866.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,254 +0,0 @@ -/* - bt866 - BT866 Digital Video Encoder (Rockwell Part) - - Copyright (C) 1999 Mike Bernson - Copyright (C) 1998 Dave Perks - - Modifications for LML33/DC10plus unified driver - Copyright (C) 2000 Serguei Miridonov - - This code was modify/ported from the saa7111 driver written - by Dave Perks. - - This code was adapted for the bt866 by Christer Weinigel and ported - to 2.6 by Martin Samuelsson. - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("Brooktree-866 video encoder driver"); -MODULE_AUTHOR("Mike Bernson & Dave Perks"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -/* ----------------------------------------------------------------------- */ - -struct bt866 { - struct v4l2_subdev sd; - u8 reg[256]; -}; - -static inline struct bt866 *to_bt866(struct v4l2_subdev *sd) -{ - return container_of(sd, struct bt866, sd); -} - -static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data) -{ - struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd); - u8 buffer[2]; - int err; - - buffer[0] = subaddr; - buffer[1] = data; - - encoder->reg[subaddr] = data; - - v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data); - - for (err = 0; err < 3;) { - if (i2c_master_send(client, buffer, 2) == 2) - break; - err++; - v4l_warn(client, "error #%d writing to 0x%02x\n", - err, subaddr); - schedule_timeout_interruptible(msecs_to_jiffies(100)); - } - if (err == 3) { - v4l_warn(client, "giving up\n"); - return -1; - } - - return 0; -} - -static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -{ - v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); - - /* Only PAL supported by this driver at the moment! */ - if (!(std & V4L2_STD_NTSC)) - return -EINVAL; - return 0; -} - -static int bt866_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - static const __u8 init[] = { - 0xc8, 0xcc, /* CRSCALE */ - 0xca, 0x91, /* CBSCALE */ - 0xcc, 0x24, /* YC16 | OSDNUM */ - 0xda, 0x00, /* */ - 0xdc, 0x24, /* SETMODE | PAL */ - 0xde, 0x02, /* EACTIVE */ - - /* overlay colors */ - 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */ - 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */ - 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */ - 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */ - 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */ - 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */ - 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */ - 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */ - - 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */ - 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */ - 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */ - 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */ - 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */ - 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */ - 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */ - 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */ - }; - struct bt866 *encoder = to_bt866(sd); - u8 val; - int i; - - for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2) - bt866_write(encoder, init[i], init[i+1]); - - val = encoder->reg[0xdc]; - - if (input == 0) - val |= 0x40; /* CBSWAP */ - else - val &= ~0x40; /* !CBSWAP */ - - bt866_write(encoder, 0xdc, val); - - val = encoder->reg[0xcc]; - if (input == 2) - val |= 0x01; /* OSDBAR */ - else - val &= ~0x01; /* !OSDBAR */ - bt866_write(encoder, 0xcc, val); - - v4l2_dbg(1, debug, sd, "set input %d\n", input); - - switch (input) { - case 0: - case 1: - case 2: - break; - default: - return -EINVAL; - } - return 0; -} - -#if 0 -/* Code to setup square pixels, might be of some use in the future, - but is currently unused. */ - val = encoder->reg[0xdc]; - if (*iarg) - val |= 1; /* SQUARE */ - else - val &= ~1; /* !SQUARE */ - bt866_write(client, 0xdc, val); -#endif - -static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops bt866_core_ops = { - .g_chip_ident = bt866_g_chip_ident, -}; - -static const struct v4l2_subdev_video_ops bt866_video_ops = { - .s_std_output = bt866_s_std_output, - .s_routing = bt866_s_routing, -}; - -static const struct v4l2_subdev_ops bt866_ops = { - .core = &bt866_core_ops, - .video = &bt866_video_ops, -}; - -static int bt866_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct bt866 *encoder; - struct v4l2_subdev *sd; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - encoder = kzalloc(sizeof(*encoder), GFP_KERNEL); - if (encoder == NULL) - return -ENOMEM; - sd = &encoder->sd; - v4l2_i2c_subdev_init(sd, client, &bt866_ops); - return 0; -} - -static int bt866_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_bt866(sd)); - return 0; -} - -static const struct i2c_device_id bt866_id[] = { - { "bt866", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, bt866_id); - -static struct i2c_driver bt866_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "bt866", - }, - .probe = bt866_probe, - .remove = bt866_remove, - .id_table = bt866_id, -}; - -static __init int init_bt866(void) -{ - return i2c_add_driver(&bt866_driver); -} - -static __exit void exit_bt866(void) -{ - i2c_del_driver(&bt866_driver); -} - -module_init(init_bt866); -module_exit(exit_bt866); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bt848.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bt848.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bt848.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bt848.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,366 +0,0 @@ -/* - bt848.h - Bt848 register offsets - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _BT848_H_ -#define _BT848_H_ - -#ifndef PCI_VENDOR_ID_BROOKTREE -#define PCI_VENDOR_ID_BROOKTREE 0x109e -#endif -#ifndef PCI_DEVICE_ID_BT848 -#define PCI_DEVICE_ID_BT848 0x350 -#endif -#ifndef PCI_DEVICE_ID_BT849 -#define PCI_DEVICE_ID_BT849 0x351 -#endif -#ifndef PCI_DEVICE_ID_BT878 -#define PCI_DEVICE_ID_BT878 0x36e -#endif -#ifndef PCI_DEVICE_ID_BT879 -#define PCI_DEVICE_ID_BT879 0x36f -#endif - - -/* Brooktree 848 registers */ - -#define BT848_DSTATUS 0x000 -#define BT848_DSTATUS_PRES (1<<7) -#define BT848_DSTATUS_HLOC (1<<6) -#define BT848_DSTATUS_FIELD (1<<5) -#define BT848_DSTATUS_NUML (1<<4) -#define BT848_DSTATUS_CSEL (1<<3) -#define BT848_DSTATUS_PLOCK (1<<2) -#define BT848_DSTATUS_LOF (1<<1) -#define BT848_DSTATUS_COF (1<<0) - -#define BT848_IFORM 0x004 -#define BT848_IFORM_HACTIVE (1<<7) -#define BT848_IFORM_MUXSEL (3<<5) -#define BT848_IFORM_MUX0 (2<<5) -#define BT848_IFORM_MUX1 (3<<5) -#define BT848_IFORM_MUX2 (1<<5) -#define BT848_IFORM_XTSEL (3<<3) -#define BT848_IFORM_XT0 (1<<3) -#define BT848_IFORM_XT1 (2<<3) -#define BT848_IFORM_XTAUTO (3<<3) -#define BT848_IFORM_XTBOTH (3<<3) -#define BT848_IFORM_NTSC 1 -#define BT848_IFORM_NTSC_J 2 -#define BT848_IFORM_PAL_BDGHI 3 -#define BT848_IFORM_PAL_M 4 -#define BT848_IFORM_PAL_N 5 -#define BT848_IFORM_SECAM 6 -#define BT848_IFORM_PAL_NC 7 -#define BT848_IFORM_AUTO 0 -#define BT848_IFORM_NORM 7 - -#define BT848_TDEC 0x008 -#define BT848_TDEC_DEC_FIELD (1<<7) -#define BT848_TDEC_FLDALIGN (1<<6) -#define BT848_TDEC_DEC_RAT (0x1f) - -#define BT848_E_CROP 0x00C -#define BT848_O_CROP 0x08C - -#define BT848_E_VDELAY_LO 0x010 -#define BT848_O_VDELAY_LO 0x090 - -#define BT848_E_VACTIVE_LO 0x014 -#define BT848_O_VACTIVE_LO 0x094 - -#define BT848_E_HDELAY_LO 0x018 -#define BT848_O_HDELAY_LO 0x098 - -#define BT848_E_HACTIVE_LO 0x01C -#define BT848_O_HACTIVE_LO 0x09C - -#define BT848_E_HSCALE_HI 0x020 -#define BT848_O_HSCALE_HI 0x0A0 - -#define BT848_E_HSCALE_LO 0x024 -#define BT848_O_HSCALE_LO 0x0A4 - -#define BT848_BRIGHT 0x028 - -#define BT848_E_CONTROL 0x02C -#define BT848_O_CONTROL 0x0AC -#define BT848_CONTROL_LNOTCH (1<<7) -#define BT848_CONTROL_COMP (1<<6) -#define BT848_CONTROL_LDEC (1<<5) -#define BT848_CONTROL_CBSENSE (1<<4) -#define BT848_CONTROL_CON_MSB (1<<2) -#define BT848_CONTROL_SAT_U_MSB (1<<1) -#define BT848_CONTROL_SAT_V_MSB (1<<0) - -#define BT848_CONTRAST_LO 0x030 -#define BT848_SAT_U_LO 0x034 -#define BT848_SAT_V_LO 0x038 -#define BT848_HUE 0x03C - -#define BT848_E_SCLOOP 0x040 -#define BT848_O_SCLOOP 0x0C0 -#define BT848_SCLOOP_CAGC (1<<6) -#define BT848_SCLOOP_CKILL (1<<5) -#define BT848_SCLOOP_HFILT_AUTO (0<<3) -#define BT848_SCLOOP_HFILT_CIF (1<<3) -#define BT848_SCLOOP_HFILT_QCIF (2<<3) -#define BT848_SCLOOP_HFILT_ICON (3<<3) - -#define BT848_SCLOOP_PEAK (1<<7) -#define BT848_SCLOOP_HFILT_MINP (1<<3) -#define BT848_SCLOOP_HFILT_MEDP (2<<3) -#define BT848_SCLOOP_HFILT_MAXP (3<<3) - - -#define BT848_OFORM 0x048 -#define BT848_OFORM_RANGE (1<<7) -#define BT848_OFORM_CORE0 (0<<5) -#define BT848_OFORM_CORE8 (1<<5) -#define BT848_OFORM_CORE16 (2<<5) -#define BT848_OFORM_CORE32 (3<<5) - -#define BT848_E_VSCALE_HI 0x04C -#define BT848_O_VSCALE_HI 0x0CC -#define BT848_VSCALE_YCOMB (1<<7) -#define BT848_VSCALE_COMB (1<<6) -#define BT848_VSCALE_INT (1<<5) -#define BT848_VSCALE_HI 15 - -#define BT848_E_VSCALE_LO 0x050 -#define BT848_O_VSCALE_LO 0x0D0 -#define BT848_TEST 0x054 -#define BT848_ADELAY 0x060 -#define BT848_BDELAY 0x064 - -#define BT848_ADC 0x068 -#define BT848_ADC_RESERVED (2<<6) -#define BT848_ADC_SYNC_T (1<<5) -#define BT848_ADC_AGC_EN (1<<4) -#define BT848_ADC_CLK_SLEEP (1<<3) -#define BT848_ADC_Y_SLEEP (1<<2) -#define BT848_ADC_C_SLEEP (1<<1) -#define BT848_ADC_CRUSH (1<<0) - -#define BT848_WC_UP 0x044 -#define BT848_WC_DOWN 0x078 - -#define BT848_E_VTC 0x06C -#define BT848_O_VTC 0x0EC -#define BT848_VTC_HSFMT (1<<7) -#define BT848_VTC_VFILT_2TAP 0 -#define BT848_VTC_VFILT_3TAP 1 -#define BT848_VTC_VFILT_4TAP 2 -#define BT848_VTC_VFILT_5TAP 3 - -#define BT848_SRESET 0x07C - -#define BT848_COLOR_FMT 0x0D4 -#define BT848_COLOR_FMT_O_RGB32 (0<<4) -#define BT848_COLOR_FMT_O_RGB24 (1<<4) -#define BT848_COLOR_FMT_O_RGB16 (2<<4) -#define BT848_COLOR_FMT_O_RGB15 (3<<4) -#define BT848_COLOR_FMT_O_YUY2 (4<<4) -#define BT848_COLOR_FMT_O_BtYUV (5<<4) -#define BT848_COLOR_FMT_O_Y8 (6<<4) -#define BT848_COLOR_FMT_O_RGB8 (7<<4) -#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) -#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) -#define BT848_COLOR_FMT_O_RAW (14<<4) -#define BT848_COLOR_FMT_E_RGB32 0 -#define BT848_COLOR_FMT_E_RGB24 1 -#define BT848_COLOR_FMT_E_RGB16 2 -#define BT848_COLOR_FMT_E_RGB15 3 -#define BT848_COLOR_FMT_E_YUY2 4 -#define BT848_COLOR_FMT_E_BtYUV 5 -#define BT848_COLOR_FMT_E_Y8 6 -#define BT848_COLOR_FMT_E_RGB8 7 -#define BT848_COLOR_FMT_E_YCrCb422 8 -#define BT848_COLOR_FMT_E_YCrCb411 9 -#define BT848_COLOR_FMT_E_RAW 14 - -#define BT848_COLOR_FMT_RGB32 0x00 -#define BT848_COLOR_FMT_RGB24 0x11 -#define BT848_COLOR_FMT_RGB16 0x22 -#define BT848_COLOR_FMT_RGB15 0x33 -#define BT848_COLOR_FMT_YUY2 0x44 -#define BT848_COLOR_FMT_BtYUV 0x55 -#define BT848_COLOR_FMT_Y8 0x66 -#define BT848_COLOR_FMT_RGB8 0x77 -#define BT848_COLOR_FMT_YCrCb422 0x88 -#define BT848_COLOR_FMT_YCrCb411 0x99 -#define BT848_COLOR_FMT_RAW 0xee - -#define BT848_VTOTAL_LO 0xB0 -#define BT848_VTOTAL_HI 0xB4 - -#define BT848_COLOR_CTL 0x0D8 -#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) -#define BT848_COLOR_CTL_COLOR_BARS (1<<6) -#define BT848_COLOR_CTL_RGB_DED (1<<5) -#define BT848_COLOR_CTL_GAMMA (1<<4) -#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) -#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) -#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) -#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) - -#define BT848_CAP_CTL 0x0DC -#define BT848_CAP_CTL_DITH_FRAME (1<<4) -#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) -#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) -#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) -#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) - -#define BT848_VBI_PACK_SIZE 0x0E0 - -#define BT848_VBI_PACK_DEL 0x0E4 -#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc -#define BT848_VBI_PACK_DEL_EXT_FRAME 2 -#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 - - -#define BT848_INT_STAT 0x100 -#define BT848_INT_MASK 0x104 - -#define BT848_INT_ETBF (1<<23) - -#define BT848_INT_RISCS (0xf<<28) -#define BT848_INT_RISC_EN (1<<27) -#define BT848_INT_RACK (1<<25) -#define BT848_INT_FIELD (1<<24) -#define BT848_INT_SCERR (1<<19) -#define BT848_INT_OCERR (1<<18) -#define BT848_INT_PABORT (1<<17) -#define BT848_INT_RIPERR (1<<16) -#define BT848_INT_PPERR (1<<15) -#define BT848_INT_FDSR (1<<14) -#define BT848_INT_FTRGT (1<<13) -#define BT848_INT_FBUS (1<<12) -#define BT848_INT_RISCI (1<<11) -#define BT848_INT_GPINT (1<<9) -#define BT848_INT_I2CDONE (1<<8) -#define BT848_INT_VPRES (1<<5) -#define BT848_INT_HLOCK (1<<4) -#define BT848_INT_OFLOW (1<<3) -#define BT848_INT_HSYNC (1<<2) -#define BT848_INT_VSYNC (1<<1) -#define BT848_INT_FMTCHG (1<<0) - - -#define BT848_GPIO_DMA_CTL 0x10C -#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) -#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) -#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) -#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) -#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) -#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) -#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) -#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) -#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) -#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) -#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) -#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) -#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) -#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) -#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) -#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) -#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) -#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) -#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) - -#define BT848_I2C 0x110 -#define BT878_I2C_MODE (1<<7) -#define BT878_I2C_RATE (1<<6) -#define BT878_I2C_NOSTOP (1<<5) -#define BT878_I2C_NOSTART (1<<4) -#define BT848_I2C_DIV (0xf<<4) -#define BT848_I2C_SYNC (1<<3) -#define BT848_I2C_W3B (1<<2) -#define BT848_I2C_SCL (1<<1) -#define BT848_I2C_SDA (1<<0) - -#define BT848_RISC_STRT_ADD 0x114 -#define BT848_GPIO_OUT_EN 0x118 -#define BT848_GPIO_REG_INP 0x11C -#define BT848_RISC_COUNT 0x120 -#define BT848_GPIO_DATA 0x200 - - -/* Bt848 RISC commands */ - -/* only for the SYNC RISC command */ -#define BT848_FIFO_STATUS_FM1 0x06 -#define BT848_FIFO_STATUS_FM3 0x0e -#define BT848_FIFO_STATUS_SOL 0x02 -#define BT848_FIFO_STATUS_EOL4 0x01 -#define BT848_FIFO_STATUS_EOL3 0x0d -#define BT848_FIFO_STATUS_EOL2 0x09 -#define BT848_FIFO_STATUS_EOL1 0x05 -#define BT848_FIFO_STATUS_VRE 0x04 -#define BT848_FIFO_STATUS_VRO 0x0c -#define BT848_FIFO_STATUS_PXV 0x00 - -#define BT848_RISC_RESYNC (1<<15) - -/* WRITE and SKIP */ -/* disable which bytes of each DWORD */ -#define BT848_RISC_BYTE0 (1U<<12) -#define BT848_RISC_BYTE1 (1U<<13) -#define BT848_RISC_BYTE2 (1U<<14) -#define BT848_RISC_BYTE3 (1U<<15) -#define BT848_RISC_BYTE_ALL (0x0fU<<12) -#define BT848_RISC_BYTE_NONE 0 -/* cause RISCI */ -#define BT848_RISC_IRQ (1U<<24) -/* RISC command is last one in this line */ -#define BT848_RISC_EOL (1U<<26) -/* RISC command is first one in this line */ -#define BT848_RISC_SOL (1U<<27) - -#define BT848_RISC_WRITE (0x01U<<28) -#define BT848_RISC_SKIP (0x02U<<28) -#define BT848_RISC_WRITEC (0x05U<<28) -#define BT848_RISC_JUMP (0x07U<<28) -#define BT848_RISC_SYNC (0x08U<<28) - -#define BT848_RISC_WRITE123 (0x09U<<28) -#define BT848_RISC_SKIP123 (0x0aU<<28) -#define BT848_RISC_WRITE1S23 (0x0bU<<28) - - -/* Bt848A and higher only !! */ -#define BT848_TGLB 0x080 -#define BT848_TGCTRL 0x084 -#define BT848_FCAP 0x0E8 -#define BT848_PLL_F_LO 0x0F0 -#define BT848_PLL_F_HI 0x0F4 - -#define BT848_PLL_XCI 0x0F8 -#define BT848_PLL_X (1<<7) -#define BT848_PLL_C (1<<6) - -#define BT848_DVSIF 0x0FC - -/* Bt878 register */ - -#define BT878_DEVCTRL 0x40 -#define BT878_EN_TBFX 0x02 -#define BT878_EN_VSFX 0x04 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-audio-hook.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-audio-hook.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-audio-hook.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-audio-hook.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,382 +0,0 @@ -/* - * Handlers for board audio hooks, splitted from bttv-cards - * - * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License - */ - -#include "bttv-audio-hook.h" - -#include - -/* ----------------------------------------------------------------------- */ -/* winview */ - -void winview_volume(struct bttv *btv, __u16 volume) -{ - /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ - int bits_out, loops, vol, data; - - /* 32 levels logarithmic */ - vol = 32 - ((volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; - data = gpio_read(); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1<audmode & V4L2_TUNER_MODE_LANG1) - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x300; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x200; -/* if (t->audmode & V4L2_TUNER_MODE_MONO) - * con = 0x100; */ - gpio_bits(0x300, con); - } else { - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int val, con; - - if (btv->radio_user) - return; - - val = gpio_read(); - if (set) { - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) { - if (t->audmode & V4L2_TUNER_MODE_LANG1) { - /* LANG1 + LANG2 */ - con = 0x100; - } - else { - /* LANG2 */ - con = 0x300; - } - } - if (con != (val & 0x300)) { - gpio_bits(0x300, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"gvbctv5pci"); - } - } else { - switch (val & 0x70) { - case 0x10: - t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - break; - case 0x30: - t->rxsubchans = V4L2_TUNER_SUB_LANG2; - break; - case 0x50: - t->rxsubchans = V4L2_TUNER_SUB_LANG1; - break; - case 0x60: - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - break; - case 0x70: - t->rxsubchans = V4L2_TUNER_SUB_MONO; - break; - default: - t->rxsubchans = V4L2_TUNER_SUB_MONO | - V4L2_TUNER_SUB_STEREO | - V4L2_TUNER_SUB_LANG1 | - V4L2_TUNER_SUB_LANG2; - } - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * Mario Medina Nussbaum - * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, - * 0xdde enables mono and 0xccd enables sap - * - * Petr Vandrovec - * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select - * input/output sound connection, so both must be set for output mode. - * - * Looks like it's needed only for the "tvphone", the "tvphone 98" - * handles this with a tda9840 - * - */ - -void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - int val = 0; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x02; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0x01; - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1; - return; - } -} - - -void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - int val = 0; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x01; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ - val = 0x02; - btaor(val, ~0x03, BT848_GPIO_DATA); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - return; - } -} - -/* Lifetec 9415 handling */ - -void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - int val = 0; - - if (gpio_read() & 0x4000) { - t->audmode = V4L2_TUNER_MODE_MONO; - return; - } - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ - val = 0x0080; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ - val = 0x0880; - if ((t->audmode & V4L2_TUNER_MODE_LANG1) || - (t->audmode & V4L2_TUNER_MODE_MONO)) - val = 0; - gpio_bits(0x0880, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"lt9415"); - } else { - /* autodetect doesn't work with this card :-( */ - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - return; - } -} - -/* TDA9821 on TerraTV+ Bt848, Bt878 */ -void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int con = 0; - - if (set) { - gpio_inout(0x180000,0x180000); - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x080000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x180000; - gpio_bits(0x180000, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"terratv"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - - -void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned long val = 0; - - if (set) { - /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ - if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x410000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ - val = 0x020000; - if (val) { - gpio_bits(0x430000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"winfast2000"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM - * revision 9B has on-board TDA9874A sound decoder). - * - * Note: There are card variants without tda9874a. Forcing the "stereo sound route" - * will mute this cards. - */ -void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int val = 0; - - if (btv->radio_user) - return; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x01; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x02; - } - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pvbt878p9b"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for FlyVideo 2000S (with tda9874 decoder) - * based on pvbt878p9b_audio() - this is not tested, please fix!!! - */ -void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int val = 0xffff; - - if (btv->radio_user) - return; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x0000; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ - } - if (val != 0xffff) { - gpio_bits(0x1800, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"fv2000s"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * sound control for Canopus WinDVR PCI - * Masaki Suzuki - */ -void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned long val = 0; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) - val = 0x040000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) - val = 0; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - val = 0x100000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0; - if (val) { - gpio_bits(0x140000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"windvr"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * sound control for AD-TVK503 - * Hiroshi Takekawa - */ -void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int con = 0xffffff; - - /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ - - if (set) { - /* btor(***, BT848_GPIO_OUT_EN); */ - if (t->audmode & V4L2_TUNER_MODE_LANG1) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x00180000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_MONO) - con = 0x00060000; - if (con != 0xffffff) { - gpio_bits(0x1e0000,con); - if (bttv_gpio) - bttv_gpio_tracking(btv, "adtvk503"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-audio-hook.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-audio-hook.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-audio-hook.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-audio-hook.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * Handlers for board audio hooks, splitted from bttv-cards - * - * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License - */ - -#include "bttvp.h" - -void winview_volume (struct bttv *btv, __u16 volume); - -void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void terratv_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-cards.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,4919 +0,0 @@ -/* - - bttv-cards.c - - this file has configuration informations - card-specific stuff - like the big tvcards array for the most part - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999-2001 Gerd Knorr - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bttvp.h" -#include -#include -#include "bttv-audio-hook.h" - -/* fwd decl */ -static void boot_msp34xx(struct bttv *btv, int pin); -static void hauppauge_eeprom(struct bttv *btv); -static void avermedia_eeprom(struct bttv *btv); -static void osprey_eeprom(struct bttv *btv, const u8 ee[256]); -static void modtec_eeprom(struct bttv *btv); -static void init_PXC200(struct bttv *btv); -static void init_RTV24(struct bttv *btv); - -static void rv605_muxsel(struct bttv *btv, unsigned int input); -static void eagle_muxsel(struct bttv *btv, unsigned int input); -static void xguard_muxsel(struct bttv *btv, unsigned int input); -static void ivc120_muxsel(struct bttv *btv, unsigned int input); -static void gvc1100_muxsel(struct bttv *btv, unsigned int input); - -static void PXC200_muxsel(struct bttv *btv, unsigned int input); - -static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input); -static void picolo_tetra_init(struct bttv *btv); - -static void tibetCS16_muxsel(struct bttv *btv, unsigned int input); -static void tibetCS16_init(struct bttv *btv); - -static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input); -static void kodicom4400r_init(struct bttv *btv); - -static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input); -static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input); - -static void geovision_muxsel(struct bttv *btv, unsigned int input); - -static void phytec_muxsel(struct bttv *btv, unsigned int input); - -static void gv800s_muxsel(struct bttv *btv, unsigned int input); -static void gv800s_init(struct bttv *btv); - -static int terratec_active_radio_upgrade(struct bttv *btv); -static int tea5757_read(struct bttv *btv); -static int tea5757_write(struct bttv *btv, int value); -static void identify_by_eeprom(struct bttv *btv, - unsigned char eeprom_data[256]); -static int __devinit pvr_boot(struct bttv *btv); - -/* config variables */ -static unsigned int triton1; -static unsigned int vsfx; -static unsigned int latency = UNSET; -int no_overlay=-1; - -static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; -static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; -static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; -static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; -static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; -static unsigned int audiodev[BTTV_MAX]; -static unsigned int saa6588[BTTV_MAX]; -static struct bttv *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL }; -static unsigned int autoload = UNSET; -static unsigned int gpiomask = UNSET; -static unsigned int audioall = UNSET; -static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET }; - -/* insmod options */ -module_param(triton1, int, 0444); -module_param(vsfx, int, 0444); -module_param(no_overlay, int, 0444); -module_param(latency, int, 0444); -module_param(gpiomask, int, 0444); -module_param(audioall, int, 0444); -module_param(autoload, int, 0444); - -module_param_array(card, int, NULL, 0444); -module_param_array(pll, int, NULL, 0444); -module_param_array(tuner, int, NULL, 0444); -module_param_array(svhs, int, NULL, 0444); -module_param_array(remote, int, NULL, 0444); -module_param_array(audiodev, int, NULL, 0444); -module_param_array(audiomux, int, NULL, 0444); - -MODULE_PARM_DESC(triton1,"set ETBF pci config bit " - "[enable bug compatibility for triton1 + others]"); -MODULE_PARM_DESC(vsfx,"set VSFX pci config bit " - "[yet another chipset flaw workaround]"); -MODULE_PARM_DESC(latency,"pci latency timer"); -MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list"); -MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)"); -MODULE_PARM_DESC(tuner,"specify installed tuner type"); -MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore"); -MODULE_PARM_DESC(audiodev, "specify audio device:\n" - "\t\t-1 = no audio\n" - "\t\t 0 = autodetect (default)\n" - "\t\t 1 = msp3400\n" - "\t\t 2 = tda7432\n" - "\t\t 3 = tvaudio"); -MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition."); -MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" - " [some VIA/SIS chipsets are known to have problem with overlay]"); - -/* ----------------------------------------------------------------------- */ -/* list of card IDs for bt878+ cards */ - -static struct CARD { - unsigned id; - int cardnr; - char *name; -} cards[] __devinitdata = { - { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV" }, - { 0x39000070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV-D" }, - { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" }, - { 0xff000070, BTTV_BOARD_OSPREY1x0, "Osprey-100" }, - { 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" }, - { 0xff020070, BTTV_BOARD_OSPREY500, "Osprey-500" }, - { 0xff030070, BTTV_BOARD_OSPREY2000, "Osprey-2000" }, - { 0xff040070, BTTV_BOARD_OSPREY540, "Osprey-540" }, - { 0xff070070, BTTV_BOARD_OSPREY440, "Osprey-440" }, - - { 0x00011002, BTTV_BOARD_ATI_TVWONDER, "ATI TV Wonder" }, - { 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" }, - - { 0x6606107d, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0x6607107d, BTTV_BOARD_WINFASTVC100, "Leadtek WinFast VC 100" }, - { 0x6609107d, BTTV_BOARD_WINFAST2000, "Leadtek TV 2000 XP" }, - { 0x263610b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, - { 0x264510b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, - { 0x402010fc, BTTV_BOARD_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" }, - { 0x405010fc, BTTV_BOARD_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" }, - { 0x407010fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, - { 0xd01810fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, - - { 0x001211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" }, - /* some cards ship with byteswapped IDs ... */ - { 0x1200bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" }, - { 0xff00bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" }, - /* this seems to happen as well ... */ - { 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" }, - - { 0x3000121a, BTTV_BOARD_VOODOOTV_200, "3Dfx VoodooTV 200" }, - { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM" }, - { 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" }, - - { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" }, - { 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" }, - { 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" }, - { 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" }, - { 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" }, - { 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" }, - { 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" }, - - { 0x00011461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00021461, BTTV_BOARD_AVERMEDIA98, "AVermedia TVCapture 98" }, - { 0x00031461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00041461, BTTV_BOARD_AVERMEDIA98, "AVerMedia TVCapture 98" }, - { 0x03001461, BTTV_BOARD_AVERMEDIA98, "VDOMATE TV TUNER CARD" }, - - { 0x1117153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" }, - { 0x1118153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" }, - { 0x1119153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL I)" }, - { 0x111a153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL I)" }, - - { 0x1123153b, BTTV_BOARD_TERRATVRADIO, "Terratec TV Radio+" }, - { 0x1127153b, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.05)" }, - /* clashes with FlyVideo - *{ 0x18521852, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.10)" }, */ - { 0x1134153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (LR102)" }, - { 0x1135153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */ - { 0x5018153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue" }, /* ?? */ - { 0xff3b153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */ - - { 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, - { 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, - { 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, - { 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, - { 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, - - { 0x1430aa00, BTTV_BOARD_PV143, "Provideo PV143A" }, - { 0x1431aa00, BTTV_BOARD_PV143, "Provideo PV143B" }, - { 0x1432aa00, BTTV_BOARD_PV143, "Provideo PV143C" }, - { 0x1433aa00, BTTV_BOARD_PV143, "Provideo PV143D" }, - { 0x1433aa03, BTTV_BOARD_PV143, "Security Eyes" }, - - { 0x1460aa00, BTTV_BOARD_PV150, "Provideo PV150A-1" }, - { 0x1461aa01, BTTV_BOARD_PV150, "Provideo PV150A-2" }, - { 0x1462aa02, BTTV_BOARD_PV150, "Provideo PV150A-3" }, - { 0x1463aa03, BTTV_BOARD_PV150, "Provideo PV150A-4" }, - - { 0x1464aa04, BTTV_BOARD_PV150, "Provideo PV150B-1" }, - { 0x1465aa05, BTTV_BOARD_PV150, "Provideo PV150B-2" }, - { 0x1466aa06, BTTV_BOARD_PV150, "Provideo PV150B-3" }, - { 0x1467aa07, BTTV_BOARD_PV150, "Provideo PV150B-4" }, - - { 0xa132ff00, BTTV_BOARD_IVC100, "IVC-100" }, - { 0xa1550000, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550001, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550002, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550003, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550100, BTTV_BOARD_IVC200, "IVC-200G" }, - { 0xa1550101, BTTV_BOARD_IVC200, "IVC-200G" }, - { 0xa1550102, BTTV_BOARD_IVC200, "IVC-200G" }, - { 0xa1550103, BTTV_BOARD_IVC200, "IVC-200G" }, - { 0xa1550800, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550801, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550802, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550803, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa182ff00, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff01, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff02, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff03, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff04, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff05, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff06, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff07, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff08, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff09, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0a, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0b, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0c, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0d, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0e, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0f, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xf0500000, BTTV_BOARD_IVCE8784, "IVCE-8784" }, - { 0xf0500001, BTTV_BOARD_IVCE8784, "IVCE-8784" }, - { 0xf0500002, BTTV_BOARD_IVCE8784, "IVCE-8784" }, - { 0xf0500003, BTTV_BOARD_IVCE8784, "IVCE-8784" }, - - { 0x41424344, BTTV_BOARD_GRANDTEC, "GrandTec Multi Capture" }, - { 0x01020304, BTTV_BOARD_XGUARD, "Grandtec Grand X-Guard" }, - - { 0x18501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, - { 0xa0501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, - { 0x18511851, BTTV_BOARD_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" }, - { 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" }, - { 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" }, - { 0x18501f7f, BTTV_BOARD_FLYVIDEO_98, "Lifeview Flyvideo 98" }, - - { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" }, - { 0x010114c7, BTTV_BOARD_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" }, - - { 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" }, - { 0x217d6606, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0xfff6f6ff, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0x03116000, BTTV_BOARD_SENSORAY311, "Sensoray 311" }, - { 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" }, - { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" }, - { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" }, - { 0x146caa0c, BTTV_BOARD_PV951, "ituner spectra8" }, - { 0x200a1295, BTTV_BOARD_PXC200, "ImageNation PXC200A" }, - - { 0x40111554, BTTV_BOARD_PV_BT878P_9B, "Prolink Pixelview PV-BT" }, - { 0x17de0a01, BTTV_BOARD_KWORLD, "Mecer TV/FM/Video Tuner" }, - - { 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" }, - { 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" }, - { 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" }, - { 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" }, - - { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" }, - - { 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" }, - { 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" }, - - /* likely broken, vendor id doesn't match the other magic views ... - * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ - - /* Duplicate PCI ID, reconfigure for this board during the eeprom read. - * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */ - - { 0x109e036e, BTTV_BOARD_CONCEPTRONIC_CTVFMI2, "Conceptronic CTVFMi v2"}, - - /* DVB cards (using pci function .1 for mpeg data xfer) */ - { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" }, - { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, - { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"}, - { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, - { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" }, - { 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, - { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, - { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, - { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, - { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, - { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, - { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "}, - { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" }, - { 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" }, - { 0x18011000, BTTV_BOARD_ENLTV_FM_2, "Encore ENL TV-FM-2" }, - { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" }, - { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, - { 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, - { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, - - { 0x15401830, BTTV_BOARD_PV183, "Provideo PV183-1" }, - { 0x15401831, BTTV_BOARD_PV183, "Provideo PV183-2" }, - { 0x15401832, BTTV_BOARD_PV183, "Provideo PV183-3" }, - { 0x15401833, BTTV_BOARD_PV183, "Provideo PV183-4" }, - { 0x15401834, BTTV_BOARD_PV183, "Provideo PV183-5" }, - { 0x15401835, BTTV_BOARD_PV183, "Provideo PV183-6" }, - { 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" }, - { 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" }, - - { 0, -1, NULL } -}; - -/* ----------------------------------------------------------------------- */ -/* array with description for bt848 / bt878 tv/grabber cards */ - -struct tvcard bttv_tvcards[] = { - /* ---- card 0x00 ---------------------------------- */ - [BTTV_BOARD_UNKNOWN] = { - .name = " *** UNKNOWN/GENERIC *** ", - .video_inputs = 4, - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 0), - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MIRO] = { - .name = "MIRO PCTV", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 10, - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_HAUPPAUGE] = { - .name = "Hauppauge (bt848)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_STB] = { - .name = "STB, Gateway P/N 6000699 (bt848)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 4, 0, 2, 3 }, - .gpiomute = 1, - .no_msp34xx = 1, - .needs_tvaudio = 1, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - - /* ---- card 0x04 ---------------------------------- */ - [BTTV_BOARD_INTEL] = { - .name = "Intel Create and Share PCI/ Smart Video Recorder III", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 2, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0 }, - .needs_tvaudio = 0, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_DIAMOND] = { - .name = "Diamond DTV2000", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 3, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0, 1, 0, 1 }, - .gpiomute = 3, - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_AVERMEDIA] = { - .name = "AVerMedia TVPhone", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 3, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomask = 0x0f, - .gpiomux = { 0x0c, 0x04, 0x08, 0x04 }, - /* 0x04 for some cards ?? */ - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= avermedia_tvphone_audio, - .has_remote = 1, - }, - [BTTV_BOARD_MATRIX_VISION] = { - .name = "MATRIX-Vision MV-Delta", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0, 0), - .gpiomux = { 0 }, - .needs_tvaudio = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x08 ---------------------------------- */ - [BTTV_BOARD_FLYVIDEO] = { - .name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xc00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0xc00, 0x800, 0x400 }, - .gpiomute = 0xc00, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TURBOTV] = { - .name = "IMS/IXmicro TurboTV", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 3, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 1, 2, 3 }, - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_HAUPPAUGE878] = { - .name = "Hauppauge (bt878)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x0f, /* old: 7 */ - .muxsel = MUXSEL(2, 0, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MIROPRO] = { - .name = "MIRO PCTV pro", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3014f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20001,0x10001, 0, 0 }, - .gpiomute = 10, - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x0c ---------------------------------- */ - [BTTV_BOARD_ADSTECH_TV] = { - .name = "ADS Technologies Channel Surfer TV (bt848)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 13, 14, 11, 7 }, - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_AVERMEDIA98] = { - .name = "AVerMedia TVCapture 98", - .video_inputs = 3, - /* .audio_inputs= 4, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 13, 14, 11, 7 }, - .needs_tvaudio = 1, - .msp34xx_alt = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= avermedia_tv_stereo_audio, - .no_gpioirq = 1, - }, - [BTTV_BOARD_VHX] = { - .name = "Aimslab Video Highway Xtreme (VHX)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 2, 1, 3 }, /* old: {0, 1, 2, 3, 4} */ - .gpiomute = 4, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ZOLTRIX] = { - .name = "Zoltrix TV-Max", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 1, 0 }, - .gpiomute = 10, - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x10 ---------------------------------- */ - [BTTV_BOARD_PIXVIEWPLAYTV] = { - .name = "Prolink Pixelview PlayTV (bt878)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x01fe00, - .muxsel = MUXSEL(2, 3, 1, 1), - /* 2003-10-20 by "Anton A. Arapov" */ - .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 }, - .gpiomute = 0x002000, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_WINVIEW_601] = { - .name = "Leadtek WinView 601", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x8300f8, - .muxsel = MUXSEL(2, 3, 1, 1, 0), - .gpiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 }, - .gpiomute = 0xcfa007, - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .volume_gpio = winview_volume, - .has_radio = 1, - }, - [BTTV_BOARD_AVEC_INTERCAP] = { - .name = "AVEC Intercapture", - .video_inputs = 3, - /* .audio_inputs= 2, */ - .svhs = 2, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 0, 0, 0 }, - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_LIFE_FLYKIT] = { - .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 0x8dff00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0 }, - .no_msp34xx = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x14 ---------------------------------- */ - [BTTV_BOARD_CEI_RAFFLES] = { - .name = "CEI Raffles Card", - .video_inputs = 3, - /* .audio_inputs= 3, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 1), - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_CONFERENCETV] = { - .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50", - .video_inputs = 4, - /* .audio_inputs= 2, tuner, line in */ - .svhs = 2, - .gpiomask = 0x1800, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_PHOEBE_TVMAS] = { - .name = "Askey CPH050/ Phoebe Tv Master + FM", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xc00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 0x800, 0x400 }, - .gpiomute = 0xc00, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MODTEC_205] = { - .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .has_dig_in = 1, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 0), /* input 2 is digital */ - /* .digital_mode= DIGITAL_MODE_CAMERA, */ - .gpiomux = { 0, 0, 0, 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ALPS_TSBB5_PAL_I, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x18 ---------------------------------- */ - [BTTV_BOARD_MAGICTVIEW061] = { - .name = "Askey CPH05X/06X (bt878) [many vendors]", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xe00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = {0x400, 0x400, 0x400, 0x400 }, - .gpiomute = 0xc00, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - }, - [BTTV_BOARD_VOBIS_BOOSTAR] = { - .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x1f0fff, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20000, 0x30000, 0x10000, 0 }, - .gpiomute = 0x40000, - .needs_tvaudio = 0, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= terratv_audio, - }, - [BTTV_BOARD_HAUPPAUG_WCAM] = { - .name = "Hauppauge WinCam newer (bt878)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 7, - .muxsel = MUXSEL(2, 0, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .needs_tvaudio = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MAXI] = { - .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50", - .video_inputs = 4, - /* .audio_inputs= 2, */ - .svhs = 2, - .gpiomask = 0x1800, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_SECAM, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x1c ---------------------------------- */ - [BTTV_BOARD_TERRATV] = { - .name = "Terratec TerraTV+ Version 1.1 (bt878)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x1f0fff, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20000, 0x30000, 0x10000, 0x00000 }, - .gpiomute = 0x40000, - .needs_tvaudio = 0, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= terratv_audio, - /* GPIO wiring: - External 20 pin connector (for Active Radio Upgrade board) - gpio00: i2c-sda - gpio01: i2c-scl - gpio02: om5610-data - gpio03: om5610-clk - gpio04: om5610-wre - gpio05: om5610-stereo - gpio06: rds6588-davn - gpio07: Pin 7 n.c. - gpio08: nIOW - gpio09+10: nIOR, nSEL ?? (bt878) - gpio09: nIOR (bt848) - gpio10: nSEL (bt848) - Sound Routing: - gpio16: u2-A0 (1st 4052bt) - gpio17: u2-A1 - gpio18: u2-nEN - gpio19: u4-A0 (2nd 4052) - gpio20: u4-A1 - u4-nEN - GND - Btspy: - 00000 : Cdrom (internal audio input) - 10000 : ext. Video audio input - 20000 : TV Mono - a0000 : TV Mono/2 - 1a0000 : TV Stereo - 30000 : Radio - 40000 : Mute - */ - - }, - [BTTV_BOARD_PXC200] = { - /* Jannik Fritsch */ - .name = "Imagenation PXC200", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 1, /* was: 4 */ - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0, 0), - .gpiomux = { 0 }, - .needs_tvaudio = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .muxsel_hook = PXC200_muxsel, - - }, - [BTTV_BOARD_FLYVIDEO_98] = { - .name = "Lifeview FlyVideo 98 LR50", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x1800, /* 0x8dfe00 */ - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x0800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_IPROTV] = { - .name = "Formac iProTV, Formac ProTV I (bt848)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 1, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 0, 0, 0 }, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x20 ---------------------------------- */ - [BTTV_BOARD_INTEL_C_S_PCI] = { - .name = "Intel Create and Share PCI/ Smart Video Recorder III", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 2, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0 }, - .needs_tvaudio = 0, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TERRATVALUE] = { - .name = "Terratec TerraTValue Version Bt878", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xffff00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x500, 0, 0x300, 0x900 }, - .gpiomute = 0x900, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_WINFAST2000] = { - .name = "Leadtek WinFast 2000/ WinFast 2000 XP", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - /* TV, CVid, SVid, CVid over SVid connector */ - .muxsel = MUXSEL(2, 3, 1, 1, 0), - /* Alexander Varakin [stereo version] */ - .gpiomask = 0xb33000, - .gpiomux = { 0x122000,0x1000,0x0000,0x620000 }, - .gpiomute = 0x800000, - /* Audio Routing for "WinFast 2000 XP" (no tv stereo !) - gpio23 -- hef4052:nEnable (0x800000) - gpio12 -- hef4052:A1 - gpio13 -- hef4052:A0 - 0x0000: external audio - 0x1000: FM - 0x2000: TV - 0x3000: n.c. - Note: There exists another variant "Winfast 2000" with tv stereo !? - Note: eeprom only contains FF and pci subsystem id 107d:6606 - */ - .needs_tvaudio = 0, - .pll = PLL_28, - .has_radio = 1, - .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */ - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= winfast2000_audio, - .has_remote = 1, - }, - [BTTV_BOARD_CHRONOS_VS2] = { - .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II", - .video_inputs = 4, - /* .audio_inputs= 3, */ - .svhs = 2, - .gpiomask = 0x1800, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x24 ---------------------------------- */ - [BTTV_BOARD_TYPHOON_TVIEW] = { - .name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner", - .video_inputs = 4, - /* .audio_inputs= 3, */ - .svhs = 2, - .gpiomask = 0x1800, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - }, - [BTTV_BOARD_PXELVWPLTVPRO] = { - .name = "Prolink PixelView PlayTV pro", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xff, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x21, 0x20, 0x24, 0x2c }, - .gpiomute = 0x29, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MAGICTVIEW063] = { - .name = "Askey CPH06X TView99", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x551e00, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0x551400, 0x551200, 0, 0 }, - .gpiomute = 0x551c00, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - }, - [BTTV_BOARD_PINNACLE] = { - .name = "Pinnacle PCTV Studio/Rave", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x03000F, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0xd0001, 0, 0 }, - .gpiomute = 1, - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x28 ---------------------------------- */ - [BTTV_BOARD_STB2] = { - .name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 4, 0, 2, 3 }, - .gpiomute = 1, - .no_msp34xx = 1, - .needs_tvaudio = 1, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - [BTTV_BOARD_AVPHONE98] = { - .name = "AVerMedia TVPhone 98", - .video_inputs = 3, - /* .audio_inputs= 4, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 13, 4, 11, 7 }, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - .audio_mode_gpio= avermedia_tvphone_audio, - }, - [BTTV_BOARD_PV951] = { - .name = "ProVideo PV951", /* pic16c54 */ - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 0, 0}, - .needs_tvaudio = 1, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ONAIR_TV] = { - .name = "Little OnAir TV", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xe00b, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 }, - .gpiomute = 0xff3ffc, - .no_msp34xx = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x2c ---------------------------------- */ - [BTTV_BOARD_SIGMA_TVII_FM] = { - .name = "Sigma TVII-FM", - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 3, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 1, 0, 2 }, - .gpiomute = 3, - .no_msp34xx = 1, - .pll = PLL_NONE, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MATRIX_VISION2] = { - .name = "MATRIX-Vision MV-Delta 2", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0, 0), - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ZOLTRIX_GENIE] = { - .name = "Zoltrix Genie TV/FM", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xbcf03f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0 }, - .gpiomute = 0xbcb03f, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4039FR5_NTSC, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TERRATVRADIO] = { - .name = "Terratec TV/Radio+", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x70000, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20000, 0x30000, 0x10000, 0 }, - .gpiomute = 0x40000, - .needs_tvaudio = 1, - .no_msp34xx = 1, - .pll = PLL_35, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - }, - - /* ---- card 0x30 ---------------------------------- */ - [BTTV_BOARD_DYNALINK] = { - .name = "Askey CPH03x/ Dynalink Magic TView", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = {2,0,0,0 }, - .gpiomute = 1, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_GVBCTV3PCI] = { - .name = "IODATA GV-BCTV3/PCI", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x010f00, - .muxsel = MUXSEL(2, 3, 0, 0), - .gpiomux = {0x10000, 0, 0x10000, 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ALPS_TSHC6_NTSC, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= gvbctv3pci_audio, - }, - [BTTV_BOARD_PXELVWPLTVPAK] = { - .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 3, - .has_dig_in = 1, - .gpiomask = 0xAA0000, - .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */ - /* .digital_mode= DIGITAL_MODE_CAMERA, */ - .gpiomux = { 0x20000, 0, 0x80000, 0x80000 }, - .gpiomute = 0xa8000, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - /* GPIO wiring: (different from Rev.4C !) - GPIO17: U4.A0 (first hef4052bt) - GPIO19: U4.A1 - GPIO20: U5.A1 (second hef4052bt) - GPIO21: U4.nEN - GPIO22: BT832 Reset Line - GPIO23: A5,A0, U5,nEN - Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22 - */ - }, - [BTTV_BOARD_EAGLE] = { - .name = "Eagle Wireless Capricorn2 (bt878A)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 0, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .pll = PLL_28, - .tuner_type = UNSET /* TUNER_ALPS_TMDH2_NTSC */, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x34 ---------------------------------- */ - [BTTV_BOARD_PINNACLEPRO] = { - /* David Härdeman */ - .name = "Pinnacle PCTV Studio Pro", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 0x03000F, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 0xd0001, 0, 0 }, - .gpiomute = 10, - /* sound path (5 sources): - MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable) - 0= ext. Audio IN - 1= from MUX2 - 2= Mono TV sound from Tuner - 3= not connected - MUX2 (mask 0x30000): - 0,2,3= from MSP34xx - 1= FM stereo Radio from Tuner */ - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TVIEW_RDS_FM] = { - /* Claas Langbehn , - Sven Grothklags */ - .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS", - .video_inputs = 4, - /* .audio_inputs= 3, */ - .svhs = 2, - .gpiomask = 0x1c, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 0x10, 8 }, - .gpiomute = 4, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - }, - [BTTV_BOARD_LIFETEC_9415] = { - /* Tim Röstermundt - in de.comp.os.unix.linux.hardware: - options bttv card=0 pll=1 radio=1 gpiomask=0x18e0 - gpiomux =0x44c71f,0x44d71f,0,0x44d71f,0x44dfff - options tuner type=5 */ - .name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x18e0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x0000,0x0800,0x1000,0x1000 }, - .gpiomute = 0x18e0, - /* For cards with tda9820/tda9821: - 0x0000: Tuner normal stereo - 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) - 0x0880: Tuner A2 stereo */ - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_BESTBUY_EASYTV] = { - /* Miguel Angel Alvarez - old Easy TV BT848 version (model CPH031) */ - .name = "Askey CPH031/ BESTBUY Easy TV", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xF, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 10, - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x38 ---------------------------------- */ - [BTTV_BOARD_FLYVIDEO_98FM] = { - /* Gordon Heydon */ - [BTTV_BOARD_GRANDTEC] = { - .name = "GrandTec 'Grand Video Capture' (Bt848)", - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .gpiomask = 0, - .muxsel = MUXSEL(3, 1), - .gpiomux = { 0 }, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_35, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ASKEY_CPH060] = { - /* Daniel Herrington */ - .name = "Askey CPH060/ Phoebe TV Master Only (No FM)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xe00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x400, 0x400, 0x400, 0x400 }, - .gpiomute = 0x800, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4036FY5_NTSC, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ASKEY_CPH03X] = { - /* Matti Mottus */ - .name = "Askey CPH03x TV Capturer", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x03000F, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 1, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - }, - - /* ---- card 0x3c ---------------------------------- */ - [BTTV_BOARD_MM100PCTV] = { - /* Philip Blundell */ - .name = "Modular Technology MM100PCTV", - .video_inputs = 2, - /* .audio_inputs= 2, */ - .svhs = NO_SVHS, - .gpiomask = 11, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0, 0, 1 }, - .gpiomute = 8, - .pll = PLL_35, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_GMV1] = { - /* Adrian Cox - new Easy TV BT878 version (model CPH061) - special thanks to Informatica Mieres for providing the card */ - .name = "Askey CPH061/ BESTBUY Easy TV (bt878)", - .video_inputs = 3, - /* .audio_inputs= 2, */ - .svhs = 2, - .gpiomask = 0xFF, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 1, 0, 4, 4 }, - .gpiomute = 9, - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ATI_TVWONDER] = { - /* Lukas Gebauer */ - .name = "ATI TV-Wonder", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xf03f, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0xbffe, 0, 0xbfff, 0 }, - .gpiomute = 0xbffe, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x40 ---------------------------------- */ - [BTTV_BOARD_ATI_TVWONDERVE] = { - /* Lukas Gebauer */ - .name = "ATI TV-Wonder VE", - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 1, - .muxsel = MUXSEL(2, 3, 0, 1), - .gpiomux = { 0, 0, 1, 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_FLYVIDEO2000] = { - /* DeeJay */ - .name = "IODATA GV-BCTV4/PCI", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x010f00, - .muxsel = MUXSEL(2, 3, 0, 0), - .gpiomux = {0x10000, 0, 0x10000, 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= gvbctv3pci_audio, - }, - - /* ---- card 0x44 ---------------------------------- */ - [BTTV_BOARD_VOODOOTV_FM] = { - .name = "3Dfx VoodooTV FM (Euro)", - /* try "insmod msp3400 simple=0" if you have - * sound problems with this card. */ - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 0x4f8a00, - /* 0x100000: 1=MSP enabled (0=disable again) - * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ - .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, - .gpiomute = 0x947fff, - /* tvtuner, radio, external,internal, mute, stereo - * tuner, Composit, SVid, Composit-on-Svid-adapter */ - .muxsel = MUXSEL(2, 3, 0, 1), - .tuner_type = TUNER_MT2032, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - [BTTV_BOARD_VOODOOTV_200] = { - .name = "VoodooTV 200 (USA)", - /* try "insmod msp3400 simple=0" if you have - * sound problems with this card. */ - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 0x4f8a00, - /* 0x100000: 1=MSP enabled (0=disable again) - * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ - .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, - .gpiomute = 0x947fff, - /* tvtuner, radio, external,internal, mute, stereo - * tuner, Composit, SVid, Composit-on-Svid-adapter */ - .muxsel = MUXSEL(2, 3, 0, 1), - .tuner_type = TUNER_MT2032, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - [BTTV_BOARD_AIMMS] = { - /* Philip Blundell */ - .name = "Active Imaging AIMMS", - .video_inputs = 1, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .muxsel = MUXSEL(2), - .gpiomask = 0 - }, - [BTTV_BOARD_PV_BT878P_PLUS] = { - /* Tomasz Pyra */ - .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)", - .video_inputs = 3, - /* .audio_inputs= 4, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 11, 7 }, /* TV and Radio with same GPIO ! */ - .gpiomute = 13, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_LG_PAL_I_FM, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - /* GPIO wiring: - GPIO0: U4.A0 (hef4052bt) - GPIO1: U4.A1 - GPIO2: U4.A1 (second hef4052bt) - GPIO3: U4.nEN, U5.A0, A5.nEN - GPIO8-15: vrd866b ? - */ - }, - [BTTV_BOARD_FLYVIDEO98EZ] = { - .name = "Lifeview FlyVideo 98EZ (capture only) LR51", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 2, - /* AV1, AV2, SVHS, CVid adapter on SVHS */ - .muxsel = MUXSEL(2, 3, 1, 1), - .pll = PLL_28, - .no_msp34xx = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x48 ---------------------------------- */ - [BTTV_BOARD_PV_BT878P_9B] = { - /* Dariusz Kowalewski */ - .name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x01, 0x00, 0x03, 0x03 }, - .gpiomute = 0x09, - .needs_tvaudio = 1, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */ - .has_radio = 1, /* Note: not all cards have radio */ - .has_remote = 1, - /* GPIO wiring: - GPIO0: A0 hef4052 - GPIO1: A1 hef4052 - GPIO3: nEN hef4052 - GPIO8-15: vrd866b - GPIO20,22,23: R30,R29,R28 - */ - }, - [BTTV_BOARD_SENSORAY311] = { - /* Clay Kunz */ - /* you must jumper JP5 for the card to work */ - .name = "Sensoray 311", - .video_inputs = 5, - /* .audio_inputs= 0, */ - .svhs = 4, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0, 0), - .gpiomux = { 0 }, - .needs_tvaudio = 0, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_RV605] = { - /* Miguel Freitas */ - .name = "RemoteVision MX (RV605)", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x00, - .gpiomask2 = 0x07ff, - .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), - .no_msp34xx = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .muxsel_hook = rv605_muxsel, - }, - [BTTV_BOARD_POWERCLR_MTV878] = { - .name = "Powercolor MTV878/ MTV878R/ MTV878F", - .video_inputs = 3, - /* .audio_inputs= 2, */ - .svhs = 2, - .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */ - .muxsel = MUXSEL(2, 1, 1), - .gpiomux = { 0, 1, 2, 2 }, - .gpiomute = 4, - .needs_tvaudio = 0, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - - /* ---- card 0x4c ---------------------------------- */ - [BTTV_BOARD_WINDVR] = { - /* Masaki Suzuki */ - .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x140007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= windvr_audio, - }, - [BTTV_BOARD_GRANDTEC_MULTI] = { - .name = "GrandTec Multi Capture Card (Bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0 }, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_KWORLD] = { - .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF", - .video_inputs = 4, - /* .audio_inputs= 3, */ - .svhs = 2, - .gpiomask = 7, - /* Tuner, SVid, SVHS, SVid to SVHS connector */ - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 4, 4 },/* Yes, this tuner uses the same audio output for TV and FM radio! - * This card lacks external Audio In, so we mute it on Ext. & Int. - * The PCB can take a sbx1637/sbx1673, wiring unknown. - * This card lacks PCI subsystem ID, sigh. - * gpiomux =1: lower volume, 2+3: mute - * btwincap uses 0x80000/0x80003 - */ - .gpiomute = 4, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and - radio signal strength indicators work fine. */ - .has_radio = 1, - /* GPIO Info: - GPIO0,1: HEF4052 A0,A1 - GPIO2: HEF4052 nENABLE - GPIO3-7: n.c. - GPIO8-13: IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card] - GPIO14,15: ?? - GPIO16-21: n.c. - GPIO22,23: ?? - ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/ - }, - [BTTV_BOARD_DSP_TCVIDEO] = { - /* Arthur Tetzlaff-Deas, DSP Design Ltd */ - .name = "DSP Design TCVIDEO", - .video_inputs = 4, - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 3, 1, 0), - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x50 ---------------------------------- */ - [BTTV_BOARD_HAUPPAUGEPVR] = { - .name = "Hauppauge WinTV PVR", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 0, 1, 1), - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - - .gpiomask = 7, - .gpiomux = {7}, - }, - [BTTV_BOARD_GVBCTV5PCI] = { - .name = "IODATA GV-BCTV5/PCI", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x0f0f80, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = {0x030000, 0x010000, 0, 0 }, - .gpiomute = 0x020000, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= gvbctv5pci_audio, - .has_radio = 1, - }, - [BTTV_BOARD_OSPREY1x0] = { - .name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */ - .video_inputs = 4, /* id-inputs-clock */ - /* .audio_inputs= 0, */ - .svhs = 3, - .muxsel = MUXSEL(3, 2, 0, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY1x0_848] = { - .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */ - .video_inputs = 3, - /* .audio_inputs= 0, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - - /* ---- card 0x54 ---------------------------------- */ - [BTTV_BOARD_OSPREY101_848] = { - .name = "Osprey 101 (848)", /* 0x05-40C0-C1 */ - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .muxsel = MUXSEL(3, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY1x1] = { - .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */ - .video_inputs = 1, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(0), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY1x1_SVID] = { - .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */ - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .muxsel = MUXSEL(0, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY2xx] = { - .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */ - .video_inputs = 1, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(0), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - - /* ---- card 0x58 ---------------------------------- */ - [BTTV_BOARD_OSPREY2x0_SVID] = { - .name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */ - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = 1, - .muxsel = MUXSEL(0, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY2x0] = { - .name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */ - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = 1, - .muxsel = MUXSEL(2, 3), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY500] = { - .name = "Osprey 500", /* 500 */ - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = 1, - .muxsel = MUXSEL(2, 3), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY540] = { - .name = "Osprey 540", /* 540 */ - .video_inputs = 4, - /* .audio_inputs= 1, */ - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - - /* ---- card 0x5C ---------------------------------- */ - [BTTV_BOARD_OSPREY2000] = { - .name = "Osprey 2000", /* 2000 */ - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = 1, - .muxsel = MUXSEL(2, 3), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */ - }, - [BTTV_BOARD_IDS_EAGLE] = { - /* M G Berberich */ - .name = "IDS Eagle", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 2, 2, 2), - .muxsel_hook = eagle_muxsel, - .no_msp34xx = 1, - .pll = PLL_28, - }, - [BTTV_BOARD_PINNACLESAT] = { - .name = "Pinnacle PCTV Sat", - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel = MUXSEL(3, 1), - .pll = PLL_28, - .no_gpioirq = 1, - .has_dvb = 1, - }, - [BTTV_BOARD_FORMAC_PROTV] = { - .name = "Formac ProTV II (bt878)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 2, - /* TV, Comp1, Composite over SVID con, SVID */ - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 2, 0, 0 }, - .pll = PLL_28, - .has_radio = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - /* sound routing: - GPIO=0x00,0x01,0x03: mute (?) - 0x02: both TV and radio (tuner: FM1216/I) - The card has onboard audio connectors labeled "cdrom" and "board", - not soldered here, though unknown wiring. - Card lacks: external audio in, pci subsystem id. - */ - }, - - /* ---- card 0x60 ---------------------------------- */ - [BTTV_BOARD_MACHTV] = { - .name = "MachTV", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 3}, - .gpiomute = 4, - .needs_tvaudio = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - }, - [BTTV_BOARD_EURESYS_PICOLO] = { - .name = "Euresys Picolo", - .video_inputs = 3, - /* .audio_inputs= 0, */ - .svhs = 2, - .gpiomask = 0, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel = MUXSEL(2, 0, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_PV150] = { - /* Luc Van Hoeylandt */ - .name = "ProVideo PV150", /* 0x4f */ - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3), - .gpiomux = { 0 }, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_AD_TVK503] = { - /* Hiroshi Takekawa */ - /* This card lacks subsystem ID */ - .name = "AD-TVK503", /* 0x63 */ - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x001e8007, - .muxsel = MUXSEL(2, 3, 1, 0), - /* Tuner, Radio, external, internal, off, on */ - .gpiomux = { 0x08, 0x0f, 0x0a, 0x08 }, - .gpiomute = 0x0f, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= adtvk503_audio, - }, - - /* ---- card 0x64 ---------------------------------- */ - [BTTV_BOARD_HERCULES_SM_TV] = { - .name = "Hercules Smart TV Stereo", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x00, - .muxsel = MUXSEL(2, 3, 1, 1), - .needs_tvaudio = 1, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - /* Notes: - - card lacks subsystem ID - - stereo variant w/ daughter board with tda9874a @0xb0 - - Audio Routing: - always from tda9874 independent of GPIO (?) - external line in: unknown - - Other chips: em78p156elp @ 0x96 (probably IR remote control) - hef4053 (instead 4052) for unknown function - */ - }, - [BTTV_BOARD_PACETV] = { - .name = "Pace TV & Radio Card", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - /* Tuner, CVid, SVid, CVid over SVid connector */ - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomask = 0, - .no_tda7432 = 1, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - .pll = PLL_28, - /* Bt878, Bt832, FI1246 tuner; no pci subsystem id - only internal line out: (4pin header) RGGL - Radio must be decoded by msp3410d (not routed through)*/ - /* - .digital_mode = DIGITAL_MODE_CAMERA, todo! - */ - }, - [BTTV_BOARD_IVC200] = { - /* Chris Willing */ - .name = "IVC-200", - .video_inputs = 1, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0xdf, - .muxsel = MUXSEL(2), - .pll = PLL_28, - }, - [BTTV_BOARD_IVCE8784] = { - .name = "IVCE-8784", - .video_inputs = 1, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0xdf, - .muxsel = MUXSEL(2), - .pll = PLL_28, - }, - [BTTV_BOARD_XGUARD] = { - .name = "Grand X-Guard / Trust 814PCI", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .gpiomask2 = 0xff, - .muxsel = MUXSEL(2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0), - .muxsel_hook = xguard_muxsel, - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - }, - - /* ---- card 0x68 ---------------------------------- */ - [BTTV_BOARD_NEBULA_DIGITV] = { - .name = "Nebula Electronics DigiTV", - .video_inputs = 1, - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 3, 1, 0), - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .has_dvb = 1, - .has_remote = 1, - .gpiomask = 0x1b, - .no_gpioirq = 1, - }, - [BTTV_BOARD_PV143] = { - /* Jorge Boncompte - DTI2 */ - .name = "ProVideo PV143", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0 }, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD009X1_VD011_MINIDIN] = { - /* M.Klahr@phytec.de */ - .name = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 3, - .gpiomask = 0x00, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD009X1_VD011_COMBI] = { - .name = "PHYTEC VD-009-X1 VD-011 Combi (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 3, - .gpiomask = 0x00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x6c ---------------------------------- */ - [BTTV_BOARD_VD009_MINIDIN] = { - .name = "PHYTEC VD-009 MiniDIN (bt878)", - .video_inputs = 10, - /* .audio_inputs= 0, */ - .svhs = 9, - .gpiomask = 0x00, - .gpiomask2 = 0x03, /* used for external vodeo mux */ - .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 0), - .muxsel_hook = phytec_muxsel, - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD009_COMBI] = { - .name = "PHYTEC VD-009 Combi (bt878)", - .video_inputs = 10, - /* .audio_inputs= 0, */ - .svhs = 9, - .gpiomask = 0x00, - .gpiomask2 = 0x03, /* used for external vodeo mux */ - .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 1), - .muxsel_hook = phytec_muxsel, - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_IVC100] = { - .name = "IVC-100", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0xdf, - .muxsel = MUXSEL(2, 3, 1, 0), - .pll = PLL_28, - }, - [BTTV_BOARD_IVC120] = { - /* IVC-120G - Alan Garfield */ - .name = "IVC-120G", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, /* card has no svhs */ - .needs_tvaudio = 0, - .no_msp34xx = 1, - .no_tda7432 = 1, - .gpiomask = 0x00, - .muxsel = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - .muxsel_hook = ivc120_muxsel, - .pll = PLL_28, - }, - - /* ---- card 0x70 ---------------------------------- */ - [BTTV_BOARD_PC_HDTV] = { - .name = "pcHDTV HD-2000 TV", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 0), - .tuner_type = TUNER_PHILIPS_FCV1236D, - .tuner_addr = ADDR_UNSET, - .has_dvb = 1, - }, - [BTTV_BOARD_TWINHAN_DST] = { - .name = "Twinhan DST + clones", - .no_msp34xx = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_video = 1, - .has_dvb = 1, - }, - [BTTV_BOARD_WINFASTVC100] = { - .name = "Winfast VC100", - .video_inputs = 3, - /* .audio_inputs= 0, */ - .svhs = 1, - /* Vid In, SVid In, Vid over SVid in connector */ - .muxsel = MUXSEL(3, 1, 1, 3), - .no_msp34xx = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - }, - [BTTV_BOARD_TEV560] = { - .name = "Teppro TEV-560/InterVision IV-560", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 3, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 1, 1, 1 }, - .needs_tvaudio = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .pll = PLL_35, - }, - - /* ---- card 0x74 ---------------------------------- */ - [BTTV_BOARD_SIMUS_GVC1100] = { - .name = "SIMUS GVC1100", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .muxsel = MUXSEL(2, 2, 2, 2), - .gpiomask = 0x3F, - .muxsel_hook = gvc1100_muxsel, - }, - [BTTV_BOARD_NGSTV_PLUS] = { - /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */ - .name = "NGS NGSTV+", - .video_inputs = 3, - .svhs = 2, - .gpiomask = 0x008007, - .muxsel = MUXSEL(2, 3, 0, 0), - .gpiomux = { 0, 0, 0, 0 }, - .gpiomute = 0x000003, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - }, - [BTTV_BOARD_LMLBT4] = { - /* http://linuxmedialabs.com */ - .name = "LMLBT4", - .video_inputs = 4, /* IN1,IN2,IN3,IN4 */ - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 3, 1, 0), - .no_msp34xx = 1, - .no_tda7432 = 1, - .needs_tvaudio = 0, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TEKRAM_M205] = { - /* Helmroos Harri */ - .name = "Tekram M205 PRO", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .svhs = 2, - .needs_tvaudio = 0, - .gpiomask = 0x68, - .muxsel = MUXSEL(2, 3, 1), - .gpiomux = { 0x68, 0x68, 0x61, 0x61 }, - .pll = PLL_28, - }, - - /* ---- card 0x78 ---------------------------------- */ - [BTTV_BOARD_CONTVFMI] = { - /* Javier Cendan Ares */ - /* bt878 TV + FM without subsystem ID */ - .name = "Conceptronic CONTVFMi", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x008007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 2 }, - .gpiomute = 3, - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - .has_radio = 1, - }, - [BTTV_BOARD_PICOLO_TETRA_CHIP] = { - /*Eric DEBIEF */ - /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/ - /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/ - /*0x79 in bttv.h*/ - .name = "Euresys Picolo Tetra", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/ - .no_msp34xx = 1, - .no_tda7432 = 1, - /*878A input is always MUX0, see above.*/ - .muxsel = MUXSEL(2, 2, 2, 2), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .pll = PLL_28, - .needs_tvaudio = 0, - .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_SPIRIT_TV] = { - /* Spirit TV Tuner from http://spiritmodems.com.au */ - /* Stafford Goodsell */ - .name = "Spirit TV Tuner", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x0000000f, - .muxsel = MUXSEL(2, 1, 1), - .gpiomux = { 0x02, 0x00, 0x00, 0x00 }, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - }, - [BTTV_BOARD_AVDVBT_771] = { - /* Wolfram Joost */ - .name = "AVerMedia AVerTV DVB-T 771", - .video_inputs = 2, - .svhs = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .muxsel = MUXSEL(3, 3), - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .has_dvb = 1, - .no_gpioirq = 1, - .has_remote = 1, - }, - /* ---- card 0x7c ---------------------------------- */ - [BTTV_BOARD_AVDVBT_761] = { - /* Matt Jesson */ - /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */ - .name = "AverMedia AverTV DVB-T 761", - .video_inputs = 2, - .svhs = 1, - .muxsel = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */ - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .has_dvb = 1, - .no_gpioirq = 1, - .has_remote = 1, - }, - [BTTV_BOARD_MATRIX_VISIONSQ] = { - /* andre.schwarz@matrix-vision.de */ - .name = "MATRIX Vision Sigma-SQ", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x0, - .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3), - .muxsel_hook = sigmaSQ_muxsel, - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MATRIX_VISIONSLC] = { - /* andre.schwarz@matrix-vision.de */ - .name = "MATRIX Vision Sigma-SLC", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x0, - .muxsel = MUXSEL(2, 2, 2, 2), - .muxsel_hook = sigmaSLC_muxsel, - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - /* BTTV_BOARD_APAC_VIEWCOMP */ - [BTTV_BOARD_APAC_VIEWCOMP] = { - /* Attila Kondoros */ - /* bt878 TV + FM 0x00000000 subsystem ID */ - .name = "APAC Viewcomp 878(AMAX)", - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 0xFF, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 10, - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */ - .has_radio = 1, /* not every card has radio */ - }, - - /* ---- card 0x80 ---------------------------------- */ - [BTTV_BOARD_DVICO_DVBT_LITE] = { - /* Chris Pascoe */ - .name = "DViCO FusionHDTV DVB-T Lite", - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .no_video = 1, - .has_dvb = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VGEAR_MYVCD] = { - /* Steven */ - .name = "V-Gear MyVCD", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3f, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = {0x31, 0x31, 0x31, 0x31 }, - .gpiomute = 0x31, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .tuner_addr = ADDR_UNSET, - .has_radio = 0, - }, - [BTTV_BOARD_SUPER_TV] = { - /* Rick C */ - .name = "Super TV Tuner", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 0), - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .gpiomask = 0x008007, - .gpiomux = { 0, 0x000001,0,0 }, - .needs_tvaudio = 1, - .has_radio = 1, - }, - [BTTV_BOARD_TIBET_CS16] = { - /* Chris Fanning */ - .name = "Tibet Systems 'Progress DVR' CS16", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .muxsel_hook = tibetCS16_muxsel, - }, - [BTTV_BOARD_KODICOM_4400R] = { - /* Bill Brack */ - /* - * Note that, because of the card's wiring, the "master" - * BT878A chip (i.e. the one which controls the analog switch - * and must use this card type) is the 2nd one detected. The - * other 3 chips should use card type 0x85, whose description - * follows this one. There is a EEPROM on the card (which is - * connected to the I2C of one of those other chips), but is - * not currently handled. There is also a facility for a - * "monitor", which is also not currently implemented. - */ - .name = "Kodicom 4400R (master)", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - /* GPIO bits 0-9 used for analog switch: - * 00 - 03: camera selector - * 04 - 06: channel (controller) selector - * 07: data (1->on, 0->off) - * 08: strobe - * 09: reset - * bit 16 is input from sync separator for the channel - */ - .gpiomask = 0x0003ff, - .no_gpioirq = 1, - .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel_hook = kodicom4400r_muxsel, - }, - [BTTV_BOARD_KODICOM_4400R_SL] = { - /* Bill Brack */ - /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the - * one which controls the analog switch, and must use the card type) - * is the 2nd one detected. The other 3 chips should use this card - * type - */ - .name = "Kodicom 4400R (slave)", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0x010000, - .no_gpioirq = 1, - .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel_hook = kodicom4400r_muxsel, - }, - /* ---- card 0x86---------------------------------- */ - [BTTV_BOARD_ADLINK_RTV24] = { - /* Michael Henson */ - /* Adlink RTV24 with special unlock codes */ - .name = "Adlink RTV24", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 0), - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - }, - /* ---- card 0x87---------------------------------- */ - [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = { - /* Michael Krufky */ - .name = "DViCO FusionHDTV 5 Lite", - .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */ - .tuner_addr = ADDR_UNSET, - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1), - .gpiomask = 0x00e00007, - .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, - .gpiomute = 0x00c00007, - .no_msp34xx = 1, - .no_tda7432 = 1, - .has_dvb = 1, - }, - /* ---- card 0x88---------------------------------- */ - [BTTV_BOARD_ACORP_Y878F] = { - /* Mauro Carvalho Chehab */ - .name = "Acorp Y878F", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x01fe00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 }, - .gpiomute = 0x002000, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_YMEC_TVF66T5_B_DFF, - .tuner_addr = 0xc1 >>1, - .has_radio = 1, - }, - /* ---- card 0x89 ---------------------------------- */ - [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = { - .name = "Conceptronic CTVFMi v2", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x001c0007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 2 }, - .gpiomute = 3, - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_TENA_9533_DI, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - .has_radio = 1, - }, - /* ---- card 0x8a ---------------------------------- */ - [BTTV_BOARD_PV_BT878P_2E] = { - .name = "Prolink Pixelview PV-BT878P+ (Rev.2E)", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 3, - .has_dig_in = 1, - .gpiomask = 0x01fe00, - .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */ - /* .digital_mode= DIGITAL_MODE_CAMERA, */ - .gpiomux = { 0x00400, 0x10400, 0x04400, 0x80000 }, - .gpiomute = 0x12400, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_LG_PAL_FM, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - }, - /* ---- card 0x8b ---------------------------------- */ - [BTTV_BOARD_PV_M4900] = { - /* Sérgio Fortier */ - .name = "Prolink PixelView PlayTV MPEG2 PV-M4900", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x21, 0x20, 0x24, 0x2c }, - .gpiomute = 0x29, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_YMEC_TVF_5533MF, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - .has_remote = 1, - }, - /* ---- card 0x8c ---------------------------------- */ - /* Has four Bt878 chips behind a PCI bridge, each chip has: - one external BNC composite input (mux 2) - three internal composite inputs (unknown muxes) - an 18-bit stereo A/D (CS5331A), which has: - one external stereo unblanced (RCA) audio connection - one (or 3?) internal stereo balanced (XLR) audio connection - input is selected via gpio to a 14052B mux - (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300) - gain is controlled via an X9221A chip on the I2C bus @0x28 - sample rate is controlled via gpio to an MK1413S - (mask=0x3, 32kHz=0x0, 44.1kHz=0x1, 48kHz=0x2, ??=0x3) - There is neither a tuner nor an svideo input. */ - [BTTV_BOARD_OSPREY440] = { - .name = "Osprey 440", - .video_inputs = 4, - /* .audio_inputs= 2, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 3, 0, 1), /* 3,0,1 are guesses */ - .gpiomask = 0x303, - .gpiomute = 0x000, /* int + 32kHz */ - .gpiomux = { 0, 0, 0x000, 0x100}, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - /* ---- card 0x8d ---------------------------------- */ - [BTTV_BOARD_ASOUND_SKYEYE] = { - .name = "Asound Skyeye PCTV", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 1, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - }, - /* ---- card 0x8e ---------------------------------- */ - [BTTV_BOARD_SABRENT_TVFM] = { - .name = "Sabrent TV-FM (bttv version)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x108007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 100000, 100002, 100002, 100000 }, - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .tuner_type = TUNER_TNF_5335MF, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - }, - /* ---- card 0x8f ---------------------------------- */ - [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = { - .name = "Hauppauge ImpactVCB (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x0f, /* old: 7 */ - .muxsel = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */ - .no_msp34xx = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MACHTV_MAGICTV] = { - /* Julian Calaby - * Slightly different from original MachTV definition (0x60) - - * FIXME: RegSpy says gpiomask should be "0x001c800f", but it - * stuffs up remote chip. Bug is a pin on the jaecs is not set - * properly (methinks) causing no keyup bits being set */ - - .name = "MagicTV", /* rebranded MachTV */ - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .tuner_type = TUNER_TEMIC_4009FR5_PAL, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - .has_remote = 1, - }, - [BTTV_BOARD_SSAI_SECURITY] = { - .name = "SSAI Security Video Interface", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(0, 1, 2, 3), - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_SSAI_ULTRASOUND] = { - .name = "SSAI Ultrasound Video Interface", - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .muxsel = MUXSEL(2, 0, 1, 3), - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - /* ---- card 0x94---------------------------------- */ - [BTTV_BOARD_DVICO_FUSIONHDTV_2] = { - .name = "DViCO FusionHDTV 2", - .tuner_type = TUNER_PHILIPS_FCV1236D, - .tuner_addr = ADDR_UNSET, - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1), - .gpiomask = 0x00e00007, - .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, - .gpiomute = 0x00c00007, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - /* ---- card 0x95---------------------------------- */ - [BTTV_BOARD_TYPHOON_TVTUNERPCI] = { - .name = "Typhoon TV-Tuner PCI (50684)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3014f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20001,0x10001, 0, 0 }, - .gpiomute = 10, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_GEOVISION_GV600] = { - /* emhn@usb.ve */ - .name = "Geovision GV-600", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x0, - .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), - .muxsel_hook = geovision_muxsel, - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_KOZUMI_KTV_01C] = { - /* Mauro Lacy - * Based on MagicTV and Conceptronic CONTVFMi */ - - .name = "Kozumi KTV-01C", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x008007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 2 }, /* CONTVFMi */ - .gpiomute = 3, /* CONTVFMi */ - .needs_tvaudio = 0, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */ - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - .has_remote = 1, - }, - [BTTV_BOARD_ENLTV_FM_2] = { - /* Encore TV Tuner Pro ENL TV-FM-2 - Mauro Carvalho Chehab IR disabled - bit 18/17 = 00 -> mute - 01 -> enable external audio input - 10 -> internal audio input (mono?) - 11 -> internal audio input - */ - .gpiomask = 0x060040, - .muxsel = MUXSEL(2, 3, 3), - .gpiomux = { 0x60000, 0x60000, 0x20000, 0x20000 }, - .gpiomute = 0, - .tuner_type = TUNER_TCL_MF02GIP_5N, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - .has_remote = 1, - }, - [BTTV_BOARD_VD012] = { - /* D.Heer@Phytec.de */ - .name = "PHYTEC VD-012 (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x00, - .muxsel = MUXSEL(0, 2, 3, 1), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD012_X1] = { - /* D.Heer@Phytec.de */ - .name = "PHYTEC VD-012-X1 (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 3, - .gpiomask = 0x00, - .muxsel = MUXSEL(2, 3, 1), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD012_X2] = { - /* D.Heer@Phytec.de */ - .name = "PHYTEC VD-012-X2 (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 3, - .gpiomask = 0x00, - .muxsel = MUXSEL(3, 2, 1), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .needs_tvaudio = 0, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_GEOVISION_GV800S] = { - /* Bruno Christo - * - * GeoVision GV-800(S) has 4 Conexant Fusion 878A: - * 1 audio input per BT878A = 4 audio inputs - * 4 video inputs per BT878A = 16 video inputs - * This is the first BT878A chip of the GV-800(S). It's the - * "master" chip and it controls the video inputs through an - * analog multiplexer (a CD22M3494) via some GPIO pins. The - * slaves should use card type 0x9e (following this one). - * There is a EEPROM on the card which is currently not handled. - * The audio input is not working yet. - */ - .name = "Geovision GV-800(S) (master)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0xf107f, - .no_gpioirq = 1, - .muxsel = MUXSEL(2, 2, 2, 2), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel_hook = gv800s_muxsel, - }, - [BTTV_BOARD_GEOVISION_GV800S_SL] = { - /* Bruno Christo - * - * GeoVision GV-800(S) has 4 Conexant Fusion 878A: - * 1 audio input per BT878A = 4 audio inputs - * 4 video inputs per BT878A = 16 video inputs - * The 3 other BT878A chips are "slave" chips of the GV-800(S) - * and should use this card type. - * The audio input is not working yet. - */ - .name = "Geovision GV-800(S) (slave)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0x00, - .no_gpioirq = 1, - .muxsel = MUXSEL(2, 2, 2, 2), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel_hook = gv800s_muxsel, - }, - [BTTV_BOARD_PV183] = { - .name = "ProVideo PV183", /* 0x9f */ - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3), - .gpiomux = { 0 }, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, -}; - -static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); - -/* ----------------------------------------------------------------------- */ - -static unsigned char eeprom_data[256]; - -/* - * identify card - */ -void __devinit bttv_idcard(struct bttv *btv) -{ - unsigned int gpiobits; - int i,type; - unsigned short tmp; - - /* read PCI subsystem ID */ - pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_ID, &tmp); - btv->cardid = tmp << 16; - pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_VENDOR_ID, &tmp); - btv->cardid |= tmp; - - if (0 != btv->cardid && 0xffffffff != btv->cardid) { - /* look for the card */ - for (type = -1, i = 0; cards[i].id != 0; i++) - if (cards[i].id == btv->cardid) - type = i; - - if (type != -1) { - /* found it */ - printk(KERN_INFO "bttv%d: detected: %s [card=%d], " - "PCI subsystem ID is %04x:%04x\n", - btv->c.nr,cards[type].name,cards[type].cardnr, - btv->cardid & 0xffff, - (btv->cardid >> 16) & 0xffff); - btv->c.type = cards[type].cardnr; - } else { - /* 404 */ - printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n", - btv->c.nr, btv->cardid & 0xffff, - (btv->cardid >> 16) & 0xffff); - printk(KERN_DEBUG "please mail id, board name and " - "the correct card= insmod option to linux-media@vger.kernel.org\n"); - } - } - - /* let the user override the autodetected type */ - if (card[btv->c.nr] < bttv_num_tvcards) - btv->c.type=card[btv->c.nr]; - - /* print which card config we are using */ - printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->c.nr, - bttv_tvcards[btv->c.type].name, btv->c.type, - card[btv->c.nr] < bttv_num_tvcards - ? "insmod option" : "autodetected"); - - /* overwrite gpio stuff ?? */ - if (UNSET == audioall && UNSET == audiomux[0]) - return; - - if (UNSET != audiomux[0]) { - gpiobits = 0; - for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { - bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; - gpiobits |= audiomux[i]; - } - } else { - gpiobits = audioall; - for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { - bttv_tvcards[btv->c.type].gpiomux[i] = audioall; - } - } - bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; - printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", - btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); - for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { - printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); - } - printk("\n"); -} - -/* - * (most) board specific initialisations goes here - */ - -/* Some Modular Technology cards have an eeprom, but no subsystem ID */ -static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) -{ - int type = -1; - - if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13)) - type = BTTV_BOARD_MODTEC_205; - else if (0 == strncmp(eeprom_data+20,"Picolo",7)) - type = BTTV_BOARD_EURESYS_PICOLO; - else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0) - type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */ - - if (-1 != type) { - btv->c.type = type; - printk("bttv%d: detected by eeprom: %s [card=%d]\n", - btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type); - } -} - -static void flyvideo_gpio(struct bttv *btv) -{ - int gpio, has_remote, has_radio, is_capture_only; - int is_lr90, has_tda9820_tda9821; - int tuner_type = UNSET, ttype; - - gpio_inout(0xffffff, 0); - udelay(8); /* without this we would see the 0x1800 mask */ - gpio = gpio_read(); - /* FIXME: must restore OUR_EN ??? */ - - /* all cards provide GPIO info, some have an additional eeprom - * LR50: GPIO coding can be found lower right CP1 .. CP9 - * CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1. - * GPIO14-12: n.c. - * LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878) - - * lowest 3 bytes are remote control codes (no handshake needed) - * xxxFFF: No remote control chip soldered - * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered - * Note: Some bits are Audio_Mask ! - */ - ttype = (gpio & 0x0f0000) >> 16; - switch (ttype) { - case 0x0: - tuner_type = 2; /* NTSC, e.g. TPI8NSR11P */ - break; - case 0x2: - tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */ - break; - case 0x4: - tuner_type = 5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ - break; - case 0x6: - tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */ - break; - case 0xC: - tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ - break; - default: - printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr); - break; - } - - has_remote = gpio & 0x800000; - has_radio = gpio & 0x400000; - /* unknown 0x200000; - * unknown2 0x100000; */ - is_capture_only = !(gpio & 0x008000); /* GPIO15 */ - has_tda9820_tda9821 = !(gpio & 0x004000); - is_lr90 = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */ - /* - * gpio & 0x001000 output bit for audio routing */ - - if (is_capture_only) - tuner_type = TUNER_ABSENT; /* No tuner present */ - - printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", - btv->c.nr, has_radio ? "yes" : "no ", - has_remote ? "yes" : "no ", tuner_type, gpio); - printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", - btv->c.nr, is_lr90 ? "yes" : "no ", - has_tda9820_tda9821 ? "yes" : "no ", - is_capture_only ? "yes" : "no "); - - if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */ - btv->tuner_type = tuner_type; - btv->has_radio = has_radio; - - /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 - * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 - * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ - if (has_tda9820_tda9821) - btv->audio_mode_gpio = lt9415_audio; - /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ -} - -static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, - 14,2,17,1, 4,1,4,3, 1,2,16,1, 4,4,4,4 }; -static int miro_fmtuner[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, - 1,1,1,1, 1,1,1,0, 0,0,0,0, 0,1,0,0 }; - -static void miro_pinnacle_gpio(struct bttv *btv) -{ - int id,msp,gpio; - char *info; - - gpio_inout(0xffffff, 0); - gpio = gpio_read(); - id = ((gpio>>10) & 63) -1; - msp = bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx"); - if (id < 32) { - btv->tuner_type = miro_tunermap[id]; - if (0 == (gpio & 0x20)) { - btv->has_radio = 1; - if (!miro_fmtuner[id]) { - btv->has_matchbox = 1; - btv->mbox_we = (1<<6); - btv->mbox_most = (1<<7); - btv->mbox_clk = (1<<8); - btv->mbox_data = (1<<9); - btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9); - } - } else { - btv->has_radio = 0; - } - if (-1 != msp) { - if (btv->c.type == BTTV_BOARD_MIRO) - btv->c.type = BTTV_BOARD_MIROPRO; - if (btv->c.type == BTTV_BOARD_PINNACLE) - btv->c.type = BTTV_BOARD_PINNACLEPRO; - } - printk(KERN_INFO - "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", - btv->c.nr, id+1, btv->tuner_type, - !btv->has_radio ? "no" : - (btv->has_matchbox ? "matchbox" : "fmtuner"), - (-1 == msp) ? "no" : "yes"); - } else { - /* new cards with microtune tuner */ - id = 63 - id; - btv->has_radio = 0; - switch (id) { - case 1: - info = "PAL / mono"; - btv->tda9887_conf = TDA9887_INTERCARRIER; - break; - case 2: - info = "PAL+SECAM / stereo"; - btv->has_radio = 1; - btv->tda9887_conf = TDA9887_QSS; - break; - case 3: - info = "NTSC / stereo"; - btv->has_radio = 1; - btv->tda9887_conf = TDA9887_QSS; - break; - case 4: - info = "PAL+SECAM / mono"; - btv->tda9887_conf = TDA9887_QSS; - break; - case 5: - info = "NTSC / mono"; - btv->tda9887_conf = TDA9887_INTERCARRIER; - break; - case 6: - info = "NTSC / stereo"; - btv->tda9887_conf = TDA9887_INTERCARRIER; - break; - case 7: - info = "PAL / stereo"; - btv->tda9887_conf = TDA9887_INTERCARRIER; - break; - default: - info = "oops: unknown card"; - break; - } - if (-1 != msp) - btv->c.type = BTTV_BOARD_PINNACLEPRO; - printk(KERN_INFO - "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", - btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); - btv->tuner_type = TUNER_MT2032; - } -} - -/* GPIO21 L: Buffer aktiv, H: Buffer inaktiv */ -#define LM1882_SYNC_DRIVE 0x200000L - -static void init_ids_eagle(struct bttv *btv) -{ - gpio_inout(0xffffff,0xFFFF37); - gpio_write(0x200020); - - /* flash strobe inverter ?! */ - gpio_write(0x200024); - - /* switch sync drive off */ - gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); - - /* set BT848 muxel to 2 */ - btaor((2)<<5, ~(2<<5), BT848_IFORM); -} - -/* Muxsel helper for the IDS Eagle. - * the eagles does not use the standard muxsel-bits but - * has its own multiplexer */ -static void eagle_muxsel(struct bttv *btv, unsigned int input) -{ - gpio_bits(3, input & 3); - - /* composite */ - /* set chroma ADC to sleep */ - btor(BT848_ADC_C_SLEEP, BT848_ADC); - /* set to composite video */ - btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); - btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); - - /* switch sync drive off */ - gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); -} - -static void gvc1100_muxsel(struct bttv *btv, unsigned int input) -{ - static const int masks[] = {0x30, 0x01, 0x12, 0x23}; - gpio_write(masks[input%4]); -} - -/* LMLBT4x initialization - to allow access to GPIO bits for sensors input and - alarms output - - GPIObit | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - assignment | TI | O3|INx| O2| O1|IN4|IN3|IN2|IN1| | | - - IN - sensor inputs, INx - sensor inputs and TI XORed together - O1,O2,O3 - alarm outputs (relays) - - OUT ENABLE 1 1 0 . 1 1 0 0 . 0 0 0 0 = 0x6C0 - -*/ - -static void init_lmlbt4x(struct bttv *btv) -{ - printk(KERN_DEBUG "LMLBT4x init\n"); - btwrite(0x000000, BT848_GPIO_REG_INP); - gpio_inout(0xffffff, 0x0006C0); - gpio_write(0x000000); -} - -static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input) -{ - unsigned int inmux = input % 8; - gpio_inout( 0xf, 0xf ); - gpio_bits( 0xf, inmux ); -} - -static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input) -{ - unsigned int inmux = input % 4; - gpio_inout( 3<<9, 3<<9 ); - gpio_bits( 3<<9, inmux<<9 ); -} - -static void geovision_muxsel(struct bttv *btv, unsigned int input) -{ - unsigned int inmux = input % 16; - gpio_inout(0xf, 0xf); - gpio_bits(0xf, inmux); -} - -/* ----------------------------------------------------------------------- */ - -static void bttv_reset_audio(struct bttv *btv) -{ - /* - * BT878A has a audio-reset register. - * 1. This register is an audio reset function but it is in - * function-0 (video capture) address space. - * 2. It is enough to do this once per power-up of the card. - * 3. There is a typo in the Conexant doc -- it is not at - * 0x5B, but at 0x058. (B is an odd-number, obviously a typo!). - * --//Shrikumar 030609 - */ - if (btv->id != 878) - return; - - if (bttv_debug) - printk("bttv%d: BT878A ARESET\n",btv->c.nr); - btwrite((1<<7), 0x058); - udelay(10); - btwrite( 0, 0x058); -} - -/* initialization part one -- before registering i2c bus */ -void __devinit bttv_init_card1(struct bttv *btv) -{ - switch (btv->c.type) { - case BTTV_BOARD_HAUPPAUGE: - case BTTV_BOARD_HAUPPAUGE878: - boot_msp34xx(btv,5); - break; - case BTTV_BOARD_VOODOOTV_200: - case BTTV_BOARD_VOODOOTV_FM: - boot_msp34xx(btv,20); - break; - case BTTV_BOARD_AVERMEDIA98: - boot_msp34xx(btv,11); - break; - case BTTV_BOARD_HAUPPAUGEPVR: - pvr_boot(btv); - break; - case BTTV_BOARD_TWINHAN_DST: - case BTTV_BOARD_AVDVBT_771: - case BTTV_BOARD_PINNACLESAT: - btv->use_i2c_hw = 1; - break; - case BTTV_BOARD_ADLINK_RTV24: - init_RTV24( btv ); - break; - - } - if (!bttv_tvcards[btv->c.type].has_dvb) - bttv_reset_audio(btv); -} - -/* initialization part two -- after registering i2c bus */ -void __devinit bttv_init_card2(struct bttv *btv) -{ - btv->tuner_type = UNSET; - - if (BTTV_BOARD_UNKNOWN == btv->c.type) { - bttv_readee(btv,eeprom_data,0xa0); - identify_by_eeprom(btv,eeprom_data); - } - - switch (btv->c.type) { - case BTTV_BOARD_MIRO: - case BTTV_BOARD_MIROPRO: - case BTTV_BOARD_PINNACLE: - case BTTV_BOARD_PINNACLEPRO: - /* miro/pinnacle */ - miro_pinnacle_gpio(btv); - break; - case BTTV_BOARD_FLYVIDEO_98: - case BTTV_BOARD_MAXI: - case BTTV_BOARD_LIFE_FLYKIT: - case BTTV_BOARD_FLYVIDEO: - case BTTV_BOARD_TYPHOON_TVIEW: - case BTTV_BOARD_CHRONOS_VS2: - case BTTV_BOARD_FLYVIDEO_98FM: - case BTTV_BOARD_FLYVIDEO2000: - case BTTV_BOARD_FLYVIDEO98EZ: - case BTTV_BOARD_CONFERENCETV: - case BTTV_BOARD_LIFETEC_9415: - flyvideo_gpio(btv); - break; - case BTTV_BOARD_HAUPPAUGE: - case BTTV_BOARD_HAUPPAUGE878: - case BTTV_BOARD_HAUPPAUGEPVR: - /* pick up some config infos from the eeprom */ - bttv_readee(btv,eeprom_data,0xa0); - hauppauge_eeprom(btv); - break; - case BTTV_BOARD_AVERMEDIA98: - case BTTV_BOARD_AVPHONE98: - bttv_readee(btv,eeprom_data,0xa0); - avermedia_eeprom(btv); - break; - case BTTV_BOARD_PXC200: - init_PXC200(btv); - break; - case BTTV_BOARD_PICOLO_TETRA_CHIP: - picolo_tetra_init(btv); - break; - case BTTV_BOARD_VHX: - btv->has_radio = 1; - btv->has_matchbox = 1; - btv->mbox_we = 0x20; - btv->mbox_most = 0; - btv->mbox_clk = 0x08; - btv->mbox_data = 0x10; - btv->mbox_mask = 0x38; - break; - case BTTV_BOARD_VOBIS_BOOSTAR: - case BTTV_BOARD_TERRATV: - terratec_active_radio_upgrade(btv); - break; - case BTTV_BOARD_MAGICTVIEW061: - if (btv->cardid == 0x3002144f) { - btv->has_radio=1; - printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr); - } - break; - case BTTV_BOARD_STB2: - if (btv->cardid == 0x3060121a) { - /* Fix up entry for 3DFX VoodooTV 100, - which is an OEM STB card variant. */ - btv->has_radio=0; - btv->tuner_type=TUNER_TEMIC_NTSC; - } - break; - case BTTV_BOARD_OSPREY1x0: - case BTTV_BOARD_OSPREY1x0_848: - case BTTV_BOARD_OSPREY101_848: - case BTTV_BOARD_OSPREY1x1: - case BTTV_BOARD_OSPREY1x1_SVID: - case BTTV_BOARD_OSPREY2xx: - case BTTV_BOARD_OSPREY2x0_SVID: - case BTTV_BOARD_OSPREY2x0: - case BTTV_BOARD_OSPREY440: - case BTTV_BOARD_OSPREY500: - case BTTV_BOARD_OSPREY540: - case BTTV_BOARD_OSPREY2000: - bttv_readee(btv,eeprom_data,0xa0); - osprey_eeprom(btv, eeprom_data); - break; - case BTTV_BOARD_IDS_EAGLE: - init_ids_eagle(btv); - break; - case BTTV_BOARD_MODTEC_205: - bttv_readee(btv,eeprom_data,0xa0); - modtec_eeprom(btv); - break; - case BTTV_BOARD_LMLBT4: - init_lmlbt4x(btv); - break; - case BTTV_BOARD_TIBET_CS16: - tibetCS16_init(btv); - break; - case BTTV_BOARD_KODICOM_4400R: - kodicom4400r_init(btv); - break; - case BTTV_BOARD_GEOVISION_GV800S: - gv800s_init(btv); - break; - } - - /* pll configuration */ - if (!(btv->id==848 && btv->revision==0x11)) { - /* defaults from card list */ - if (PLL_28 == bttv_tvcards[btv->c.type].pll) { - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - } - if (PLL_35 == bttv_tvcards[btv->c.type].pll) { - btv->pll.pll_ifreq=35468950; - btv->pll.pll_crystal=BT848_IFORM_XT1; - } - /* insmod options can override */ - switch (pll[btv->c.nr]) { - case 0: /* none */ - btv->pll.pll_crystal = 0; - btv->pll.pll_ifreq = 0; - btv->pll.pll_ofreq = 0; - break; - case 1: /* 28 MHz */ - case 28: - btv->pll.pll_ifreq = 28636363; - btv->pll.pll_ofreq = 0; - btv->pll.pll_crystal = BT848_IFORM_XT0; - break; - case 2: /* 35 MHz */ - case 35: - btv->pll.pll_ifreq = 35468950; - btv->pll.pll_ofreq = 0; - btv->pll.pll_crystal = BT848_IFORM_XT1; - break; - } - } - btv->pll.pll_current = -1; - - /* tuner configuration (from card list / autodetect / insmod option) */ - if (UNSET != bttv_tvcards[btv->c.type].tuner_type) - if (UNSET == btv->tuner_type) - btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; - if (UNSET != tuner[btv->c.nr]) - btv->tuner_type = tuner[btv->c.nr]; - - if (btv->tuner_type == TUNER_ABSENT) - printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr); - else if(btv->tuner_type == UNSET) - printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr); - else - printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr, - btv->tuner_type); - - if (autoload != UNSET) { - printk(KERN_WARNING "bttv%d: the autoload option is obsolete.\n", btv->c.nr); - printk(KERN_WARNING "bttv%d: use option msp3400, tda7432 or tvaudio to\n", btv->c.nr); - printk(KERN_WARNING "bttv%d: override which audio module should be used.\n", btv->c.nr); - } - - if (UNSET == btv->tuner_type) - btv->tuner_type = TUNER_ABSENT; - - btv->dig = bttv_tvcards[btv->c.type].has_dig_in ? - bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET; - btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ? - UNSET : bttv_tvcards[btv->c.type].svhs; - if (svhs[btv->c.nr] != UNSET) - btv->svhs = svhs[btv->c.nr]; - if (remote[btv->c.nr] != UNSET) - btv->has_remote = remote[btv->c.nr]; - - if (bttv_tvcards[btv->c.type].has_radio) - btv->has_radio = 1; - if (bttv_tvcards[btv->c.type].has_remote) - btv->has_remote = 1; - if (!bttv_tvcards[btv->c.type].no_gpioirq) - btv->gpioirq = 1; - if (bttv_tvcards[btv->c.type].volume_gpio) - btv->volume_gpio = bttv_tvcards[btv->c.type].volume_gpio; - if (bttv_tvcards[btv->c.type].audio_mode_gpio) - btv->audio_mode_gpio = bttv_tvcards[btv->c.type].audio_mode_gpio; - - if (btv->tuner_type == TUNER_ABSENT) - return; /* no tuner or related drivers to load */ - - if (btv->has_saa6588 || saa6588[btv->c.nr]) { - /* Probe for RDS receiver chip */ - static const unsigned short addrs[] = { - 0x20 >> 1, - 0x22 >> 1, - I2C_CLIENT_END - }; - struct v4l2_subdev *sd; - - sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "saa6588", 0, addrs); - btv->has_saa6588 = (sd != NULL); - } - - /* try to detect audio/fader chips */ - - /* First check if the user specified the audio chip via a module - option. */ - - switch (audiodev[btv->c.nr]) { - case -1: - return; /* do not load any audio module */ - - case 0: /* autodetect */ - break; - - case 1: { - /* The user specified that we should probe for msp3400 */ - static const unsigned short addrs[] = { - I2C_ADDR_MSP3400 >> 1, - I2C_ADDR_MSP3400_ALT >> 1, - I2C_CLIENT_END - }; - - btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "msp3400", 0, addrs); - if (btv->sd_msp34xx) - return; - goto no_audio; - } - - case 2: { - /* The user specified that we should probe for tda7432 */ - static const unsigned short addrs[] = { - I2C_ADDR_TDA7432 >> 1, - I2C_CLIENT_END - }; - - if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tda7432", 0, addrs)) - return; - goto no_audio; - } - - case 3: { - /* The user specified that we should probe for tvaudio */ - btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); - if (btv->sd_tvaudio) - return; - goto no_audio; - } - - default: - printk(KERN_WARNING "bttv%d: unknown audiodev value!\n", - btv->c.nr); - return; - } - - /* There were no overrides, so now we try to discover this through the - card definition */ - - /* probe for msp3400 first: this driver can detect whether or not - it really is a msp3400, so it will return NULL when the device - found is really something else (e.g. a tea6300). */ - if (!bttv_tvcards[btv->c.type].no_msp34xx) { - btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "msp3400", - 0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1)); - } else if (bttv_tvcards[btv->c.type].msp34xx_alt) { - btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "msp3400", - 0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1)); - } - - /* If we found a msp34xx, then we're done. */ - if (btv->sd_msp34xx) - return; - - /* it might also be a tda7432. */ - if (!bttv_tvcards[btv->c.type].no_tda7432) { - static const unsigned short addrs[] = { - I2C_ADDR_TDA7432 >> 1, - I2C_CLIENT_END - }; - - if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tda7432", 0, addrs)) - return; - } - - /* Now see if we can find one of the tvaudio devices. */ - btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); - if (btv->sd_tvaudio) - return; - -no_audio: - printk(KERN_WARNING "bttv%d: audio absent, no audio device found!\n", - btv->c.nr); -} - - -/* initialize the tuner */ -void __devinit bttv_init_tuner(struct bttv *btv) -{ - int addr = ADDR_UNSET; - - if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr) - addr = bttv_tvcards[btv->c.type].tuner_addr; - - if (btv->tuner_type != TUNER_ABSENT) { - struct tuner_setup tun_setup; - - /* Load tuner module before issuing tuner config call! */ - if (bttv_tvcards[btv->c.type].has_radio) - v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); - v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); - v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); - - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = btv->tuner_type; - tun_setup.addr = addr; - - if (bttv_tvcards[btv->c.type].has_radio) - tun_setup.mode_mask |= T_RADIO; - - bttv_call_all(btv, tuner, s_type_addr, &tun_setup); - } - - if (btv->tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &btv->tda9887_conf; - - bttv_call_all(btv, tuner, s_config, &tda9887_cfg); - } -} - -/* ----------------------------------------------------------------------- */ - -static void modtec_eeprom(struct bttv *btv) -{ - if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) { - btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I; - printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr,&eeprom_data[0x1e]); - } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) { - btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I; - printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr,&eeprom_data[0x1e]); - } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) { - btv->tuner_type=TUNER_PHILIPS_NTSC; - printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr,&eeprom_data[0x1e]); - } else { - printk("bttv%d: Modtec: Unknown TunerString: %s\n", - btv->c.nr,&eeprom_data[0x1e]); - } -} - -static void __devinit hauppauge_eeprom(struct bttv *btv) -{ - struct tveeprom tv; - - tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); - btv->tuner_type = tv.tuner_type; - btv->has_radio = tv.has_radio; - - printk("bttv%d: Hauppauge eeprom indicates model#%d\n", - btv->c.nr, tv.model); - - /* - * Some of the 878 boards have duplicate PCI IDs. Switch the board - * type based on model #. - */ - if(tv.model == 64900) { - printk("bttv%d: Switching board type from %s to %s\n", - btv->c.nr, - bttv_tvcards[btv->c.type].name, - bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name); - btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB; - } -} - -static int terratec_active_radio_upgrade(struct bttv *btv) -{ - int freq; - - btv->has_radio = 1; - btv->has_matchbox = 1; - btv->mbox_we = 0x10; - btv->mbox_most = 0x20; - btv->mbox_clk = 0x08; - btv->mbox_data = 0x04; - btv->mbox_mask = 0x3c; - - btv->mbox_iow = 1 << 8; - btv->mbox_ior = 1 << 9; - btv->mbox_csel = 1 << 10; - - freq=88000/62.5; - tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */ - if (0x1ed8 == tea5757_read(btv)) { - printk("bttv%d: Terratec Active Radio Upgrade found.\n", - btv->c.nr); - btv->has_radio = 1; - btv->has_saa6588 = 1; - btv->has_matchbox = 1; - } else { - btv->has_radio = 0; - btv->has_matchbox = 0; - } - return 0; -} - - -/* ----------------------------------------------------------------------- */ - -/* - * minimal bootstrap for the WinTV/PVR -- upload altera firmware. - * - * The hcwamc.rbf firmware file is on the Hauppauge driver CD. Have - * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be - * unpacked with unzip). - */ -#define PVR_GPIO_DELAY 10 - -#define BTTV_ALT_DATA 0x000001 -#define BTTV_ALT_DCLK 0x100000 -#define BTTV_ALT_NCONFIG 0x800000 - -static int __devinit pvr_altera_load(struct bttv *btv, const u8 *micro, - u32 microlen) -{ - u32 n; - u8 bits; - int i; - - gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG); - gpio_write(0); - udelay(PVR_GPIO_DELAY); - - gpio_write(BTTV_ALT_NCONFIG); - udelay(PVR_GPIO_DELAY); - - for (n = 0; n < microlen; n++) { - bits = micro[n]; - for (i = 0 ; i < 8 ; i++) { - gpio_bits(BTTV_ALT_DCLK,0); - if (bits & 0x01) - gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); - else - gpio_bits(BTTV_ALT_DATA,0); - gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); - bits >>= 1; - } - } - gpio_bits(BTTV_ALT_DCLK,0); - udelay(PVR_GPIO_DELAY); - - /* begin Altera init loop (Not necessary,but doesn't hurt) */ - for (i = 0 ; i < 30 ; i++) { - gpio_bits(BTTV_ALT_DCLK,0); - gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); - } - gpio_bits(BTTV_ALT_DCLK,0); - return 0; -} - -static int __devinit pvr_boot(struct bttv *btv) -{ - const struct firmware *fw_entry; - int rc; - - rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev); - if (rc != 0) { - printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n", - btv->c.nr); - return rc; - } - rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size); - printk(KERN_INFO "bttv%d: altera firmware upload %s\n", - btv->c.nr, (rc < 0) ? "failed" : "ok"); - release_firmware(fw_entry); - return rc; -} - -/* ----------------------------------------------------------------------- */ -/* some osprey specific stuff */ - -static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) -{ - int i; - u32 serial = 0; - int cardid = -1; - - /* This code will nevery actually get called in this case.... */ - if (btv->c.type == BTTV_BOARD_UNKNOWN) { - /* this might be an antique... check for MMAC label in eeprom */ - if (!strncmp(ee, "MMAC", 4)) { - u8 checksum = 0; - for (i = 0; i < 21; i++) - checksum += ee[i]; - if (checksum != ee[21]) - return; - cardid = BTTV_BOARD_OSPREY1x0_848; - for (i = 12; i < 21; i++) - serial *= 10, serial += ee[i] - '0'; - } - } else { - unsigned short type; - - for (i = 4*16; i < 8*16; i += 16) { - u16 checksum = ip_compute_csum(ee + i, 16); - - if ((checksum&0xff) + (checksum>>8) == 0xff) - break; - } - if (i >= 8*16) - return; - ee += i; - - /* found a valid descriptor */ - type = get_unaligned_be16((__be16 *)(ee+4)); - - switch(type) { - /* 848 based */ - case 0x0004: - cardid = BTTV_BOARD_OSPREY1x0_848; - break; - case 0x0005: - cardid = BTTV_BOARD_OSPREY101_848; - break; - - /* 878 based */ - case 0x0012: - case 0x0013: - cardid = BTTV_BOARD_OSPREY1x0; - break; - case 0x0014: - case 0x0015: - cardid = BTTV_BOARD_OSPREY1x1; - break; - case 0x0016: - case 0x0017: - case 0x0020: - cardid = BTTV_BOARD_OSPREY1x1_SVID; - break; - case 0x0018: - case 0x0019: - case 0x001E: - case 0x001F: - cardid = BTTV_BOARD_OSPREY2xx; - break; - case 0x001A: - case 0x001B: - cardid = BTTV_BOARD_OSPREY2x0_SVID; - break; - case 0x0040: - cardid = BTTV_BOARD_OSPREY500; - break; - case 0x0050: - case 0x0056: - cardid = BTTV_BOARD_OSPREY540; - /* bttv_osprey_540_init(btv); */ - break; - case 0x0060: - case 0x0070: - case 0x00A0: - cardid = BTTV_BOARD_OSPREY2x0; - /* enable output on select control lines */ - gpio_inout(0xffffff,0x000303); - break; - case 0x00D8: - cardid = BTTV_BOARD_OSPREY440; - break; - default: - /* unknown...leave generic, but get serial # */ - printk(KERN_INFO "bttv%d: " - "osprey eeprom: unknown card type 0x%04x\n", - btv->c.nr, type); - break; - } - serial = get_unaligned_be32((__be32 *)(ee+6)); - } - - printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n", - btv->c.nr, cardid, - cardid>0 ? bttv_tvcards[cardid].name : "Unknown", serial); - - if (cardid<0 || btv->c.type == cardid) - return; - - /* card type isn't set correctly */ - if (card[btv->c.nr] < bttv_num_tvcards) { - printk(KERN_WARNING "bttv%d: osprey eeprom: " - "Not overriding user specified card type\n", btv->c.nr); - } else { - printk(KERN_INFO "bttv%d: osprey eeprom: " - "Changing card type from %d to %d\n", btv->c.nr, - btv->c.type, cardid); - btv->c.type = cardid; - } -} - -/* ----------------------------------------------------------------------- */ -/* AVermedia specific stuff, from bktr_card.c */ - -static int tuner_0_table[] = { - TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL /* PAL-BG*/, - TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL /* PAL-I*/, - TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, - TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, - TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL, - TUNER_PHILIPS_FM1216ME_MK3 }; - -static int tuner_1_table[] = { - TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, - TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, - TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, - TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */ - TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL}; - -static void __devinit avermedia_eeprom(struct bttv *btv) -{ - int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0; - - tuner_make = (eeprom_data[0x41] & 0x7); - tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3; - tuner_format = (eeprom_data[0x42] & 0xf0) >> 4; - btv->has_remote = (eeprom_data[0x42] & 0x01); - - if (tuner_make == 0 || tuner_make == 2) - if (tuner_format <= 0x0a) - tuner_type = tuner_0_table[tuner_format]; - if (tuner_make == 1) - if (tuner_format <= 9) - tuner_type = tuner_1_table[tuner_format]; - - if (tuner_make == 4) - if (tuner_format == 0x09) - tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ - - printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=", - btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]); - if (tuner_type) { - btv->tuner_type = tuner_type; - printk(KERN_CONT "%d", tuner_type); - } else - printk(KERN_CONT "Unknown type"); - printk(KERN_CONT " radio:%s remote control:%s\n", - tuner_tv_fm ? "yes" : "no", - btv->has_remote ? "yes" : "no"); -} - -/* - * For Voodoo TV/FM and Voodoo 200. These cards' tuners use a TDA9880 - * analog demod, which is not I2C controlled like the newer and more common - * TDA9887 series. Instead is has two tri-state input pins, S0 and S1, - * that control the IF for the video and audio. Apparently, bttv GPIO - * 0x10000 is connected to S0. S0 low selects a 38.9 MHz VIF for B/G/D/K/I - * (i.e., PAL) while high selects 45.75 MHz for M/N (i.e., NTSC). - */ -u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits) -{ - - if (btv->audio == TVAUDIO_INPUT_TUNER) { - if (bttv_tvnorms[btv->tvnorm].v4l2_id & V4L2_STD_MN) - gpiobits |= 0x10000; - else - gpiobits &= ~0x10000; - } - - gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpiobits); - return gpiobits; -} - - -/* - * reset/enable the MSP on some Hauppauge cards - * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! - * - * Hauppauge: pin 5 - * Voodoo: pin 20 - */ -static void __devinit boot_msp34xx(struct bttv *btv, int pin) -{ - int mask = (1 << pin); - - gpio_inout(mask,mask); - gpio_bits(mask,0); - mdelay(2); - udelay(500); - gpio_bits(mask,mask); - - if (bttv_gpio) - bttv_gpio_tracking(btv,"msp34xx"); - if (bttv_verbose) - printk(KERN_INFO "bttv%d: Hauppauge/Voodoo msp34xx: reset line " - "init [%d]\n", btv->c.nr, pin); -} - -/* ----------------------------------------------------------------------- */ -/* Imagenation L-Model PXC200 Framegrabber */ -/* This is basically the same procedure as - * used by Alessandro Rubini in his pxc200 - * driver, but using BTTV functions */ - -static void __devinit init_PXC200(struct bttv *btv) -{ - static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x00 }; - unsigned int i; - int tmp; - u32 val; - - /* Initialise GPIO-connevted stuff */ - gpio_inout(0xffffff, (1<<13)); - gpio_write(0); - udelay(3); - gpio_write(1<<13); - /* GPIO inputs are pulled up, so no need to drive - * reset pin any longer */ - gpio_bits(0xffffff, 0); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pxc200"); - - /* we could/should try and reset/control the AD pots? but - right now we simply turned off the crushing. Without - this the AGC drifts drifts - remember the EN is reverse logic --> - setting BT848_ADC_AGC_EN disable the AGC - tboult@eecs.lehigh.edu - */ - - btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); - - /* Initialise MAX517 DAC */ - printk(KERN_INFO "Setting DAC reference voltage level ...\n"); - bttv_I2CWrite(btv,0x5E,0,0x80,1); - - /* Initialise 12C508 PIC */ - /* The I2CWrite and I2CRead commmands are actually to the - * same chips - but the R/W bit is included in the address - * argument so the numbers are different */ - - - printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); - - /* First of all, enable the clock line. This is used in the PXC200-F */ - val = btread(BT848_GPIO_DMA_CTL); - val |= BT848_GPIO_DMA_CTL_GPCLKMODE; - btwrite(val, BT848_GPIO_DMA_CTL); - - /* Then, push to 0 the reset pin long enough to reset the * - * device same as above for the reset line, but not the same - * value sent to the GPIO-connected stuff - * which one is the good one? */ - gpio_inout(0xffffff,(1<<2)); - gpio_write(0); - udelay(10); - gpio_write(1<<2); - - for (i = 0; i < ARRAY_SIZE(vals); i++) { - tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1); - if (tmp != -1) { - printk(KERN_INFO - "I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n", - vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL)); - } - } - - printk(KERN_INFO "PXC200 Initialised.\n"); -} - - - -/* ----------------------------------------------------------------------- */ -/* - * The Adlink RTV-24 (aka Angelo) has some special initialisation to unlock - * it. This apparently involves the following procedure for each 878 chip: - * - * 1) write 0x00C3FEFF to the GPIO_OUT_EN register - * - * 2) write to GPIO_DATA - * - 0x0E - * - sleep 1ms - * - 0x10 + 0x0E - * - sleep 10ms - * - 0x0E - * read from GPIO_DATA into buf (uint_32) - * - if ( data>>18 & 0x01 != 0) || ( buf>>19 & 0x01 != 1 ) - * error. ERROR_CPLD_Check_Failed stop. - * - * 3) write to GPIO_DATA - * - write 0x4400 + 0x0E - * - sleep 10ms - * - write 0x4410 + 0x0E - * - sleep 1ms - * - write 0x0E - * read from GPIO_DATA into buf (uint_32) - * - if ( buf>>18 & 0x01 ) || ( buf>>19 & 0x01 != 0 ) - * error. ERROR_CPLD_Check_Failed. - */ -/* ----------------------------------------------------------------------- */ -static void -init_RTV24 (struct bttv *btv) -{ - uint32_t dataRead = 0; - long watchdog_value = 0x0E; - - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation in progress ...\n", - btv->c.nr); - - btwrite (0x00c3feff, BT848_GPIO_OUT_EN); - - btwrite (0 + watchdog_value, BT848_GPIO_DATA); - msleep (1); - btwrite (0x10 + watchdog_value, BT848_GPIO_DATA); - msleep (10); - btwrite (0 + watchdog_value, BT848_GPIO_DATA); - - dataRead = btread (BT848_GPIO_DATA); - - if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) { - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n", - btv->c.nr, dataRead); - } - - btwrite (0x4400 + watchdog_value, BT848_GPIO_DATA); - msleep (10); - btwrite (0x4410 + watchdog_value, BT848_GPIO_DATA); - msleep (1); - btwrite (watchdog_value, BT848_GPIO_DATA); - msleep (1); - dataRead = btread (BT848_GPIO_DATA); - - if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) { - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n", - btv->c.nr, dataRead); - - return; - } - - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation complete.\n", btv->c.nr); -} - - - -/* ----------------------------------------------------------------------- */ -/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */ -/* - * Copyright (c) 1999 Csaba Halasz - * This code is placed under the terms of the GNU General Public License - * - * Brutally hacked by Dan Sheridan djs52 8/3/00 - */ - -static void bus_low(struct bttv *btv, int bit) -{ - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - - gpio_bits(bit,0); - udelay(5); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); - udelay(5); - } -} - -static void bus_high(struct bttv *btv, int bit) -{ - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - - gpio_bits(bit,bit); - udelay(5); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); - udelay(5); - } -} - -static int bus_in(struct bttv *btv, int bit) -{ - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - - gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); - udelay(5); - } - return gpio_read() & (bit); -} - -/* TEA5757 register bits */ -#define TEA_FREQ 0:14 -#define TEA_BUFFER 15:15 - -#define TEA_SIGNAL_STRENGTH 16:17 - -#define TEA_PORT1 18:18 -#define TEA_PORT0 19:19 - -#define TEA_BAND 20:21 -#define TEA_BAND_FM 0 -#define TEA_BAND_MW 1 -#define TEA_BAND_LW 2 -#define TEA_BAND_SW 3 - -#define TEA_MONO 22:22 -#define TEA_ALLOW_STEREO 0 -#define TEA_FORCE_MONO 1 - -#define TEA_SEARCH_DIRECTION 23:23 -#define TEA_SEARCH_DOWN 0 -#define TEA_SEARCH_UP 1 - -#define TEA_STATUS 24:24 -#define TEA_STATUS_TUNED 0 -#define TEA_STATUS_SEARCHING 1 - -/* Low-level stuff */ -static int tea5757_read(struct bttv *btv) -{ - unsigned long timeout; - int value = 0; - int i; - - /* better safe than sorry */ - gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - - if (bttv_gpio) - bttv_gpio_tracking(btv,"tea5757 read"); - - bus_low(btv,btv->mbox_we); - bus_low(btv,btv->mbox_clk); - - udelay(10); - timeout= jiffies + msecs_to_jiffies(1000); - - /* wait for DATA line to go low; error if it doesn't */ - while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) - schedule(); - if (bus_in(btv,btv->mbox_data)) { - printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->c.nr); - return -1; - } - - dprintk("bttv%d: tea5757:",btv->c.nr); - for (i = 0; i < 24; i++) { - udelay(5); - bus_high(btv,btv->mbox_clk); - udelay(5); - dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-'); - bus_low(btv,btv->mbox_clk); - value <<= 1; - value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */ - dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M'); - } - dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->c.nr, value); - return value; -} - -static int tea5757_write(struct bttv *btv, int value) -{ - int i; - int reg = value; - - gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - if (bttv_gpio) - bttv_gpio_tracking(btv,"tea5757 write"); - - dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); - bus_low(btv,btv->mbox_clk); - bus_high(btv,btv->mbox_we); - for (i = 0; i < 25; i++) { - if (reg & 0x1000000) - bus_high(btv,btv->mbox_data); - else - bus_low(btv,btv->mbox_data); - reg <<= 1; - bus_high(btv,btv->mbox_clk); - udelay(10); - bus_low(btv,btv->mbox_clk); - udelay(10); - } - bus_low(btv,btv->mbox_we); /* unmute !!! */ - return 0; -} - -void tea5757_set_freq(struct bttv *btv, unsigned short freq) -{ - dprintk("tea5757_set_freq %d\n",freq); - tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ -} - -/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] - * - * This is needed because rv605 don't use a normal multiplex, but a crosspoint - * switch instead (CD22M3494E). This IC can have multiple active connections - * between Xn (input) and Yn (output) pins. We need to clear any existing - * connection prior to establish a new one, pulsing the STROBE pin. - * - * The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin. - * GPIO pins are wired as: - * GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroller) - * GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroller) - * GPIO[7] - DATA (xpoint) - P1[7] (microcontroller) - * GPIO[8] - - P3[5] (microcontroller) - * GPIO[9] - RESET (xpoint) - P3[6] (microcontroller) - * GPIO[10] - STROBE (xpoint) - P3[7] (microcontroller) - * GPINTR - - P3[4] (microcontroller) - * - * The microcontroller is a 80C32 like. It should be possible to change xpoint - * configuration either directly (as we are doing) or using the microcontroller - * which is also wired to I2C interface. I have no further info on the - * microcontroller features, one would need to disassembly the firmware. - * note: the vendor refused to give any information on this product, all - * that stuff was found using a multimeter! :) - */ -static void rv605_muxsel(struct bttv *btv, unsigned int input) -{ - static const u8 muxgpio[] = { 0x3, 0x1, 0x2, 0x4, 0xf, 0x7, 0xe, 0x0, - 0xd, 0xb, 0xc, 0x6, 0x9, 0x5, 0x8, 0xa }; - - gpio_bits(0x07f, muxgpio[input]); - - /* reset all conections */ - gpio_bits(0x200,0x200); - mdelay(1); - gpio_bits(0x200,0x000); - mdelay(1); - - /* create a new connection */ - gpio_bits(0x480,0x480); - mdelay(1); - gpio_bits(0x480,0x080); - mdelay(1); -} - -/* Tibet Systems 'Progress DVR' CS16 muxsel helper [Chris Fanning] - * - * The CS16 (available on eBay cheap) is a PCI board with four Fusion - * 878A chips, a PCI bridge, an Atmel microcontroller, four sync separator - * chips, ten eight input analog multiplexors, a not chip and a few - * other components. - * - * 16 inputs on a secondary bracket are provided and can be selected - * from each of the four capture chips. Two of the eight input - * multiplexors are used to select from any of the 16 input signals. - * - * Unsupported hardware capabilities: - * . A video output monitor on the secondary bracket can be selected from - * one of the 878A chips. - * . Another passthrough but I haven't spent any time investigating it. - * . Digital I/O (logic level connected to GPIO) is available from an - * onboard header. - * - * The on chip input mux should always be set to 2. - * GPIO[16:19] - Video input selection - * GPIO[0:3] - Video output monitor select (only available from one 878A) - * GPIO[?:?] - Digital I/O. - * - * There is an ATMEL microcontroller with an 8031 core on board. I have not - * determined what function (if any) it provides. With the microcontroller - * and sync separator chips a guess is that it might have to do with video - * switching and maybe some digital I/O. - */ -static void tibetCS16_muxsel(struct bttv *btv, unsigned int input) -{ - /* video mux */ - gpio_bits(0x0f0000, input << 16); -} - -static void tibetCS16_init(struct bttv *btv) -{ - /* enable gpio bits, mask obtained via btSpy */ - gpio_inout(0xffffff, 0x0f7fff); - gpio_write(0x0f7fff); -} - -/* - * The following routines for the Kodicom-4400r get a little mind-twisting. - * There is a "master" controller and three "slave" controllers, together - * an analog switch which connects any of 16 cameras to any of the BT87A's. - * The analog switch is controlled by the "master", but the detection order - * of the four BT878A chips is in an order which I just don't understand. - * The "master" is actually the second controller to be detected. The - * logic on the board uses logical numbers for the 4 controllers, but - * those numbers are different from the detection sequence. When working - * with the analog switch, we need to "map" from the detection sequence - * over to the board's logical controller number. This mapping sequence - * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical - * unit 3, the second (which is the master) is logical unit 0, etc. - * We need to maintain the status of the analog switch (which of the 16 - * cameras is connected to which of the 4 controllers). Rather than - * add to the bttv structure for this, we use the data reserved for - * the mbox (unused for this card type). - */ - -/* - * First a routine to set the analog switch, which controls which camera - * is routed to which controller. The switch comprises an X-address - * (gpio bits 0-3, representing the camera, ranging from 0-15), and a - * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3). - * A data value (gpio bit 7) of '1' enables the switch, and '0' disables - * the switch. A STROBE bit (gpio bit 8) latches the data value into the - * specified address. The idea is to set the address and data, then bring - * STROBE high, and finally bring STROBE back to low. - */ -static void kodicom4400r_write(struct bttv *btv, - unsigned char xaddr, - unsigned char yaddr, - unsigned char data) { - unsigned int udata; - - udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf); - gpio_bits(0x1ff, udata); /* write ADDR and DAT */ - gpio_bits(0x1ff, udata | (1 << 8)); /* strobe high */ - gpio_bits(0x1ff, udata); /* strobe low */ -} - -/* - * Next the mux select. Both the "master" and "slave" 'cards' (controllers) - * use this routine. The routine finds the "master" for the card, maps - * the controller number from the detected position over to the logical - * number, writes the appropriate data to the analog switch, and housekeeps - * the local copy of the switch information. The parameter 'input' is the - * requested camera number (0 - 15). - */ -static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input) -{ - char *sw_status; - int xaddr, yaddr; - struct bttv *mctlr; - static unsigned char map[4] = {3, 0, 2, 1}; - - mctlr = master[btv->c.nr]; - if (mctlr == NULL) { /* ignore if master not yet detected */ - return; - } - yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */ - yaddr = map[yaddr]; - sw_status = (char *)(&mctlr->mbox_we); - xaddr = input & 0xf; - /* Check if the controller/camera pair has changed, else ignore */ - if (sw_status[yaddr] != xaddr) - { - /* "open" the old switch, "close" the new one, save the new */ - kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0); - sw_status[yaddr] = xaddr; - kodicom4400r_write(mctlr, xaddr, yaddr, 1); - } -} - -/* - * During initialisation, we need to reset the analog switch. We - * also preset the switch to map the 4 connectors on the card to the - * *user's* (see above description of kodicom4400r_muxsel) channels - * 0 through 3 - */ -static void kodicom4400r_init(struct bttv *btv) -{ - char *sw_status = (char *)(&btv->mbox_we); - int ix; - - gpio_inout(0x0003ff, 0x0003ff); - gpio_write(1 << 9); /* reset MUX */ - gpio_write(0); - /* Preset camera 0 to the 4 controllers */ - for (ix = 0; ix < 4; ix++) { - sw_status[ix] = ix; - kodicom4400r_write(btv, ix, ix, 1); - } - /* - * Since this is the "master", we need to set up the - * other three controller chips' pointers to this structure - * for later use in the muxsel routine. - */ - if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3)) - return; - master[btv->c.nr-1] = btv; - master[btv->c.nr] = btv; - master[btv->c.nr+1] = btv; - master[btv->c.nr+2] = btv; -} - -/* The Grandtec X-Guard framegrabber card uses two Dual 4-channel - * video multiplexers to provide up to 16 video inputs. These - * multiplexers are controlled by the lower 8 GPIO pins of the - * bt878. The multiplexers probably Pericom PI5V331Q or similar. - - * xxx0 is pin xxx of multiplexer U5, - * yyy1 is pin yyy of multiplexer U2 - */ -#define ENA0 0x01 -#define ENB0 0x02 -#define ENA1 0x04 -#define ENB1 0x08 - -#define IN10 0x10 -#define IN00 0x20 -#define IN11 0x40 -#define IN01 0x80 - -static void xguard_muxsel(struct bttv *btv, unsigned int input) -{ - static const int masks[] = { - ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10, - ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10, - ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11, - ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11, - }; - gpio_write(masks[input%16]); -} -static void picolo_tetra_init(struct bttv *btv) -{ - /*This is the video input redirection fonctionality : I DID NOT USED IT. */ - btwrite (0x08<<16,BT848_GPIO_DATA);/*GPIO[19] [==> 4053 B+C] set to 1 */ - btwrite (0x04<<16,BT848_GPIO_DATA);/*GPIO[18] [==> 4053 A] set to 1*/ -} -static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) -{ - - dprintk (KERN_DEBUG "bttv%d : picolo_tetra_muxsel => input = %d\n",btv->c.nr,input); - /*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/ - /*GPIO[20]&GPIO[21] used to choose the right input*/ - btwrite (input<<20,BT848_GPIO_DATA); - -} - -/* - * ivc120_muxsel [Added by Alan Garfield ] - * - * The IVC120G security card has 4 i2c controlled TDA8540 matrix - * swichers to provide 16 channels to MUX0. The TDA8540's have - * 4 independent outputs and as such the IVC120G also has the - * optional "Monitor Out" bus. This allows the card to be looking - * at one input while the monitor is looking at another. - * - * Since I've couldn't be bothered figuring out how to add an - * independant muxsel for the monitor bus, I've just set it to - * whatever the card is looking at. - * - * OUT0 of the TDA8540's is connected to MUX0 (0x03) - * OUT1 of the TDA8540's is connected to "Monitor Out" (0x0C) - * - * TDA8540_ALT3 IN0-3 = Channel 13 - 16 (0x03) - * TDA8540_ALT4 IN0-3 = Channel 1 - 4 (0x03) - * TDA8540_ALT5 IN0-3 = Channel 5 - 8 (0x03) - * TDA8540_ALT6 IN0-3 = Channel 9 - 12 (0x03) - * - */ - -/* All 7 possible sub-ids for the TDA8540 Matrix Switcher */ -#define I2C_TDA8540 0x90 -#define I2C_TDA8540_ALT1 0x92 -#define I2C_TDA8540_ALT2 0x94 -#define I2C_TDA8540_ALT3 0x96 -#define I2C_TDA8540_ALT4 0x98 -#define I2C_TDA8540_ALT5 0x9a -#define I2C_TDA8540_ALT6 0x9c - -static void ivc120_muxsel(struct bttv *btv, unsigned int input) -{ - /* Simple maths */ - int key = input % 4; - int matrix = input / 4; - - dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", - btv->c.nr, input, matrix, key); - - /* Handles the input selection on the TDA8540's */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00, - ((matrix == 3) ? (key | key << 2) : 0x00), 1); - bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00, - ((matrix == 0) ? (key | key << 2) : 0x00), 1); - bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x00, - ((matrix == 1) ? (key | key << 2) : 0x00), 1); - bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00, - ((matrix == 2) ? (key | key << 2) : 0x00), 1); - - /* Handles the output enables on the TDA8540's */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02, - ((matrix == 3) ? 0x03 : 0x00), 1); /* 13 - 16 */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02, - ((matrix == 0) ? 0x03 : 0x00), 1); /* 1-4 */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02, - ((matrix == 1) ? 0x03 : 0x00), 1); /* 5-8 */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02, - ((matrix == 2) ? 0x03 : 0x00), 1); /* 9-12 */ - - /* 878's MUX0 is already selected for input via muxsel values */ -} - - -/* PXC200 muxsel helper - * luke@syseng.anu.edu.au - * another transplant - * from Alessandro Rubini (rubini@linux.it) - * - * There are 4 kinds of cards: - * PXC200L which is bt848 - * PXC200F which is bt848 with PIC controlling mux - * PXC200AL which is bt878 - * PXC200AF which is bt878 with PIC controlling mux - */ -#define PX_CFG_PXC200F 0x01 -#define PX_FLAG_PXC200A 0x00001000 /* a pxc200A is bt-878 based */ -#define PX_I2C_PIC 0x0f -#define PX_PXC200A_CARDID 0x200a1295 -#define PX_I2C_CMD_CFG 0x00 - -static void PXC200_muxsel(struct bttv *btv, unsigned int input) -{ - int rc; - long mux; - int bitmask; - unsigned char buf[2]; - - /* Read PIC config to determine if this is a PXC200F */ - /* PX_I2C_CMD_CFG*/ - buf[0]=0; - buf[1]=0; - rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1); - if (rc) { - printk(KERN_DEBUG "bttv%d: PXC200_muxsel: pic cfg write failed:%d\n", btv->c.nr,rc); - /* not PXC ? do nothing */ - return; - } - - rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL); - if (!(rc & PX_CFG_PXC200F)) { - printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc); - return; - } - - - /* The multiplexer in the 200F is handled by the GPIO port */ - /* get correct mapping between inputs */ - /* mux = bttv_tvcards[btv->type].muxsel[input] & 3; */ - /* ** not needed!? */ - mux = input; - - /* make sure output pins are enabled */ - /* bitmask=0x30f; */ - bitmask=0x302; - /* check whether we have a PXC200A */ - if (btv->cardid == PX_PXC200A_CARDID) { - bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */ - bitmask |= 7<<4; /* the DAC */ - } - btwrite(bitmask, BT848_GPIO_OUT_EN); - - bitmask = btread(BT848_GPIO_DATA); - if (btv->cardid == PX_PXC200A_CARDID) - bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7); - else /* older device */ - bitmask = (bitmask & ~0x300) | ((mux & 3) << 8); - btwrite(bitmask,BT848_GPIO_DATA); - - /* - * Was "to be safe, set the bt848 to input 0" - * Actually, since it's ok at load time, better not messing - * with these bits (on PXC200AF you need to set mux 2 here) - * - * needed because bttv-driver sets mux before calling this function - */ - if (btv->cardid == PX_PXC200A_CARDID) - btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM); - else /* older device */ - btand(~BT848_IFORM_MUXSEL,BT848_IFORM); - - printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux); -} - -static void phytec_muxsel(struct bttv *btv, unsigned int input) -{ - unsigned int mux = input % 4; - - if (input == btv->svhs) - mux = 0; - - gpio_bits(0x3, mux); -} - -/* - * GeoVision GV-800(S) functions - * Bruno Christo -*/ - -/* This is a function to control the analog switch, which determines which - * camera is routed to which controller. The switch comprises an X-address - * (gpio bits 0-3, representing the camera, ranging from 0-15), and a - * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3). - * A data value (gpio bit 18) of '1' enables the switch, and '0' disables - * the switch. A STROBE bit (gpio bit 17) latches the data value into the - * specified address. There is also a chip select (gpio bit 16). - * The idea is to set the address and chip select together, bring - * STROBE high, write the data, and finally bring STROBE back to low. - */ -static void gv800s_write(struct bttv *btv, - unsigned char xaddr, - unsigned char yaddr, - unsigned char data) { - /* On the "master" 878A: - * GPIO bits 0-9 are used for the analog switch: - * 00 - 03: camera selector - * 04 - 06: 878A (controller) selector - * 16: cselect - * 17: strobe - * 18: data (1->on, 0->off) - * 19: reset - */ - const u32 ADDRESS = ((xaddr&0xf) | (yaddr&3)<<4); - const u32 CSELECT = 1<<16; - const u32 STROBE = 1<<17; - const u32 DATA = data<<18; - - gpio_bits(0x1007f, ADDRESS | CSELECT); /* write ADDRESS and CSELECT */ - gpio_bits(0x20000, STROBE); /* STROBE high */ - gpio_bits(0x40000, DATA); /* write DATA */ - gpio_bits(0x20000, ~STROBE); /* STROBE low */ -} - -/* - * GeoVision GV-800(S) muxsel - * - * Each of the 4 cards (controllers) use this function. - * The controller using this function selects the input through the GPIO pins - * of the "master" card. A pointer to this card is stored in master[btv->c.nr]. - * - * The parameter 'input' is the requested camera number (0-4) on the controller. - * The map array has the address of each input. Note that the addresses in the - * array are in the sequence the original GeoVision driver uses, that is, set - * every controller to input 0, then to input 1, 2, 3, repeat. This means that - * the physical "camera 1" connector corresponds to controller 0 input 0, - * "camera 2" corresponds to controller 1 input 0, and so on. - * - * After getting the input address, the function then writes the appropriate - * data to the analog switch, and housekeeps the local copy of the switch - * information. - */ -static void gv800s_muxsel(struct bttv *btv, unsigned int input) -{ - struct bttv *mctlr; - char *sw_status; - int xaddr, yaddr; - static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 }, - { 0x1, 0x5, 0xb, 0x7 }, - { 0x2, 0x8, 0xc, 0xe }, - { 0x3, 0x9, 0xd, 0xf } }; - input = input%4; - mctlr = master[btv->c.nr]; - if (mctlr == NULL) { - /* do nothing until the "master" is detected */ - return; - } - yaddr = (btv->c.nr - mctlr->c.nr) & 3; - sw_status = (char *)(&mctlr->mbox_we); - xaddr = map[yaddr][input] & 0xf; - - /* Check if the controller/camera pair has changed, ignore otherwise */ - if (sw_status[yaddr] != xaddr) { - /* disable the old switch, enable the new one and save status */ - gv800s_write(mctlr, sw_status[yaddr], yaddr, 0); - sw_status[yaddr] = xaddr; - gv800s_write(mctlr, xaddr, yaddr, 1); - } -} - -/* GeoVision GV-800(S) "master" chip init */ -static void gv800s_init(struct bttv *btv) -{ - char *sw_status = (char *)(&btv->mbox_we); - int ix; - - gpio_inout(0xf107f, 0xf107f); - gpio_write(1<<19); /* reset the analog MUX */ - gpio_write(0); - - /* Preset camera 0 to the 4 controllers */ - for (ix = 0; ix < 4; ix++) { - sw_status[ix] = ix; - gv800s_write(btv, ix, ix, 1); - } - - /* Inputs on the "master" controller need this brightness fix */ - bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1); - - if (btv->c.nr > BTTV_MAX-4) - return; - /* - * Store the "master" controller pointer in the master - * array for later use in the muxsel function. - */ - master[btv->c.nr] = btv; - master[btv->c.nr+1] = btv; - master[btv->c.nr+2] = btv; - master[btv->c.nr+3] = btv; -} - -/* ----------------------------------------------------------------------- */ -/* motherboard chipset specific stuff */ - -void __init bttv_check_chipset(void) -{ - int pcipci_fail = 0; - struct pci_dev *dev = NULL; - - if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) /* should check if target is AGP */ - pcipci_fail = 1; - if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF)) - triton1 = 1; - if (pci_pci_problems & PCIPCI_VSFX) - vsfx = 1; -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) - latency = 0x0A; -#endif - - - /* print warnings about any quirks found */ - if (triton1) - printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n"); - if (vsfx) - printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n"); - if (pcipci_fail) { - printk(KERN_INFO "bttv: bttv and your chipset may not work " - "together.\n"); - if (!no_overlay) { - printk(KERN_INFO "bttv: overlay will be disabled.\n"); - no_overlay = 1; - } else { - printk(KERN_INFO "bttv: overlay forced. Use this " - "option at your own risk.\n"); - } - } - if (UNSET != latency) - printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency); - while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82441, dev))) { - unsigned char b; - pci_read_config_byte(dev, 0x53, &b); - if (bttv_debug) - printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, " - "bufcon=0x%02x\n",b); - } -} - -int __devinit bttv_handle_chipset(struct bttv *btv) -{ - unsigned char command; - - if (!triton1 && !vsfx && UNSET == latency) - return 0; - - if (bttv_verbose) { - if (triton1) - printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->c.nr); - if (vsfx && btv->id >= 878) - printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->c.nr); - if (UNSET != latency) - printk(KERN_INFO "bttv%d: setting pci timer to %d\n", - btv->c.nr,latency); - } - - if (btv->id < 878) { - /* bt848 (mis)uses a bit in the irq mask for etbf */ - if (triton1) - btv->triton1 = BT848_INT_ETBF; - } else { - /* bt878 has a bit in the pci config space for it */ - pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command); - if (triton1) - command |= BT878_EN_TBFX; - if (vsfx) - command |= BT878_EN_VSFX; - pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command); - } - if (UNSET != latency) - pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency); - return 0; -} - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-driver.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-driver.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,4632 +0,0 @@ -/* - - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler - & Marcus Metzler - (c) 1999-2002 Gerd Knorr - - some v4l2 code lines are taken from Justin's bttv2 driver which is - (c) 2000 Justin Schoeman - - V4L1 removal from: - (c) 2005-2006 Nickolay V. Shmyrev - - Fixes to be fully V4L2 compliant by - (c) 2006 Mauro Carvalho Chehab - - Cropping and overscan support - Copyright (C) 2005, 2006 Michael H. Schimek - Sponsored by OPQ Systems AB - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bttvp.h" -#include -#include -#include -#include - -#include - -#include -#include - -#include - - -unsigned int bttv_num; /* number of Bt848s in use */ -struct bttv *bttvs[BTTV_MAX]; - -unsigned int bttv_debug; -unsigned int bttv_verbose = 1; -unsigned int bttv_gpio; - -/* config variables */ -#ifdef __BIG_ENDIAN -static unsigned int bigendian=1; -#else -static unsigned int bigendian; -#endif -static unsigned int radio[BTTV_MAX]; -static unsigned int irq_debug; -static unsigned int gbuffers = 8; -static unsigned int gbufsize = 0x208000; -static unsigned int reset_crop = 1; - -static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; -static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; -static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; -static int debug_latency; -static int disable_ir; - -static unsigned int fdsr; - -/* options */ -static unsigned int combfilter; -static unsigned int lumafilter; -static unsigned int automute = 1; -static unsigned int chroma_agc; -static unsigned int adc_crush = 1; -static unsigned int whitecrush_upper = 0xCF; -static unsigned int whitecrush_lower = 0x7F; -static unsigned int vcr_hack; -static unsigned int irq_iswitch; -static unsigned int uv_ratio = 50; -static unsigned int full_luma_range; -static unsigned int coring; - -/* API features (turn on/off stuff for testing) */ -static unsigned int v4l2 = 1; - -/* insmod args */ -module_param(bttv_verbose, int, 0644); -module_param(bttv_gpio, int, 0644); -module_param(bttv_debug, int, 0644); -module_param(irq_debug, int, 0644); -module_param(debug_latency, int, 0644); -module_param(disable_ir, int, 0444); - -module_param(fdsr, int, 0444); -module_param(gbuffers, int, 0444); -module_param(gbufsize, int, 0444); -module_param(reset_crop, int, 0444); - -module_param(v4l2, int, 0644); -module_param(bigendian, int, 0644); -module_param(irq_iswitch, int, 0644); -module_param(combfilter, int, 0444); -module_param(lumafilter, int, 0444); -module_param(automute, int, 0444); -module_param(chroma_agc, int, 0444); -module_param(adc_crush, int, 0444); -module_param(whitecrush_upper, int, 0444); -module_param(whitecrush_lower, int, 0444); -module_param(vcr_hack, int, 0444); -module_param(uv_ratio, int, 0444); -module_param(full_luma_range, int, 0444); -module_param(coring, int, 0444); - -module_param_array(radio, int, NULL, 0444); -module_param_array(video_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); - -MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)"); -MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian"); -MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)"); -MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)"); -MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)"); -MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)"); -MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); -MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8"); -MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000"); -MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default " - "is 1 (yes) for compatibility with older applications"); -MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)"); -MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)"); -MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)"); -MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207"); -MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127"); -MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); -MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler"); -MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50"); -MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)"); -MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)"); -MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); - -MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); -MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); -MODULE_LICENSE("GPL"); - -/* ----------------------------------------------------------------------- */ -/* sysfs */ - -static ssize_t show_card(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vfd = container_of(cd, struct video_device, dev); - struct bttv *btv = video_get_drvdata(vfd); - return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); -} -static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); - -/* ----------------------------------------------------------------------- */ -/* dvb auto-load setup */ -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - request_module("dvb-bt8xx"); -} - -static void request_modules(struct bttv *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} - -static void flush_request_modules(struct bttv *dev) -{ - flush_work_sync(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#define flush_request_modules(dev) -#endif /* CONFIG_MODULES */ - - -/* ----------------------------------------------------------------------- */ -/* static data */ - -/* special timing tables from conexant... */ -static u8 SRAM_Table[][60] = -{ - /* PAL digital input over GPIO[7:0] */ - { - 45, // 45 bytes following - 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16, - 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00, - 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00, - 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37, - 0x37,0x00,0xAF,0x21,0x00 - }, - /* NTSC digital input over GPIO[7:0] */ - { - 51, // 51 bytes following - 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06, - 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00, - 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07, - 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6, - 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21, - 0x00, - }, - // TGB_NTSC392 // quartzsight - // This table has been modified to be used for Fusion Rev D - { - 0x2A, // size of table = 42 - 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24, - 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10, - 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00, - 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3, - 0x20, 0x00 - } -}; - -/* minhdelayx1 first video pixel we can capture on a line and - hdelayx1 start of active video, both relative to rising edge of - /HRESET pulse (0H) in 1 / fCLKx1. - swidth width of active video and - totalwidth total line width, both in 1 / fCLKx1. - sqwidth total line width in square pixels. - vdelay start of active video in 2 * field lines relative to - trailing edge of /VRESET pulse (VDELAY register). - sheight height of active video in 2 * field lines. - videostart0 ITU-R frame line number of the line corresponding - to vdelay in the first field. */ -#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \ - vdelay, sheight, videostart0) \ - .cropcap.bounds.left = minhdelayx1, \ - /* * 2 because vertically we count field lines times two, */ \ - /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \ - .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \ - /* 4 is a safety margin at the end of the line. */ \ - .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \ - .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \ - .cropcap.defrect.left = hdelayx1, \ - .cropcap.defrect.top = (videostart0) * 2, \ - .cropcap.defrect.width = swidth, \ - .cropcap.defrect.height = sheight, \ - .cropcap.pixelaspect.numerator = totalwidth, \ - .cropcap.pixelaspect.denominator = sqwidth, - -const struct bttv_tvnorm bttv_tvnorms[] = { - /* PAL-BDGHI */ - /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ - /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */ - { - .v4l2_id = V4L2_STD_PAL, - .name = "PAL", - .Fsc = 35468950, - .swidth = 924, - .sheight = 576, - .totalwidth = 1135, - .adelay = 0x7f, - .bdelay = 0x72, - .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - .scaledtwidth = 1135, - .hdelayx1 = 186, - .hactivex1 = 924, - .vdelay = 0x20, - .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */ - .sram = 0, - /* ITU-R frame line number of the first VBI line - we can capture, of the first and second field. - The last line is determined by cropcap.bounds. */ - .vbistart = { 7, 320 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 186, - /* Should be (768 * 1135 + 944 / 2) / 944. - cropcap.defrect is used for image width - checks, so we keep the old value 924. */ - /* swidth */ 924, - /* totalwidth */ 1135, - /* sqwidth */ 944, - /* vdelay */ 0x20, - /* sheight */ 576, - /* videostart0 */ 23) - /* bt878 (and bt848?) can capture another - line below active video. */ - .cropcap.bounds.height = (576 + 2) + 0x20 - 2, - },{ - .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, - .name = "NTSC", - .Fsc = 28636363, - .swidth = 768, - .sheight = 480, - .totalwidth = 910, - .adelay = 0x68, - .bdelay = 0x5d, - .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0), - .scaledtwidth = 910, - .hdelayx1 = 128, - .hactivex1 = 910, - .vdelay = 0x1a, - .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */ - .sram = 1, - .vbistart = { 10, 273 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 128, - /* Should be (640 * 910 + 780 / 2) / 780? */ - /* swidth */ 768, - /* totalwidth */ 910, - /* sqwidth */ 780, - /* vdelay */ 0x1a, - /* sheight */ 480, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_SECAM, - .name = "SECAM", - .Fsc = 35468950, - .swidth = 924, - .sheight = 576, - .totalwidth = 1135, - .adelay = 0x7f, - .bdelay = 0xb0, - .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1), - .scaledtwidth = 1135, - .hdelayx1 = 186, - .hactivex1 = 922, - .vdelay = 0x20, - .vbipack = 255, - .sram = 0, /* like PAL, correct? */ - .vbistart = { 7, 320 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 186, - /* swidth */ 924, - /* totalwidth */ 1135, - /* sqwidth */ 944, - /* vdelay */ 0x20, - /* sheight */ 576, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_PAL_Nc, - .name = "PAL-Nc", - .Fsc = 28636363, - .swidth = 640, - .sheight = 576, - .totalwidth = 910, - .adelay = 0x68, - .bdelay = 0x5d, - .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), - .scaledtwidth = 780, - .hdelayx1 = 130, - .hactivex1 = 734, - .vdelay = 0x1a, - .vbipack = 144, - .sram = -1, - .vbistart = { 7, 320 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 130, - /* swidth */ (640 * 910 + 780 / 2) / 780, - /* totalwidth */ 910, - /* sqwidth */ 780, - /* vdelay */ 0x1a, - /* sheight */ 576, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_PAL_M, - .name = "PAL-M", - .Fsc = 28636363, - .swidth = 640, - .sheight = 480, - .totalwidth = 910, - .adelay = 0x68, - .bdelay = 0x5d, - .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0), - .scaledtwidth = 780, - .hdelayx1 = 135, - .hactivex1 = 754, - .vdelay = 0x1a, - .vbipack = 144, - .sram = -1, - .vbistart = { 10, 273 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 135, - /* swidth */ (640 * 910 + 780 / 2) / 780, - /* totalwidth */ 910, - /* sqwidth */ 780, - /* vdelay */ 0x1a, - /* sheight */ 480, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_PAL_N, - .name = "PAL-N", - .Fsc = 35468950, - .swidth = 768, - .sheight = 576, - .totalwidth = 1135, - .adelay = 0x7f, - .bdelay = 0x72, - .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1), - .scaledtwidth = 944, - .hdelayx1 = 186, - .hactivex1 = 922, - .vdelay = 0x20, - .vbipack = 144, - .sram = -1, - .vbistart = { 7, 320 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 186, - /* swidth */ (768 * 1135 + 944 / 2) / 944, - /* totalwidth */ 1135, - /* sqwidth */ 944, - /* vdelay */ 0x20, - /* sheight */ 576, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_NTSC_M_JP, - .name = "NTSC-JP", - .Fsc = 28636363, - .swidth = 640, - .sheight = 480, - .totalwidth = 910, - .adelay = 0x68, - .bdelay = 0x5d, - .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), - .scaledtwidth = 780, - .hdelayx1 = 135, - .hactivex1 = 754, - .vdelay = 0x16, - .vbipack = 144, - .sram = -1, - .vbistart = { 10, 273 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 135, - /* swidth */ (640 * 910 + 780 / 2) / 780, - /* totalwidth */ 910, - /* sqwidth */ 780, - /* vdelay */ 0x16, - /* sheight */ 480, - /* videostart0 */ 23) - },{ - /* that one hopefully works with the strange timing - * which video recorders produce when playing a NTSC - * tape on a PAL TV ... */ - .v4l2_id = V4L2_STD_PAL_60, - .name = "PAL-60", - .Fsc = 35468950, - .swidth = 924, - .sheight = 480, - .totalwidth = 1135, - .adelay = 0x7f, - .bdelay = 0x72, - .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - .scaledtwidth = 1135, - .hdelayx1 = 186, - .hactivex1 = 924, - .vdelay = 0x1a, - .vbipack = 255, - .vtotal = 524, - .sram = -1, - .vbistart = { 10, 273 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 186, - /* swidth */ 924, - /* totalwidth */ 1135, - /* sqwidth */ 944, - /* vdelay */ 0x1a, - /* sheight */ 480, - /* videostart0 */ 23) - } -}; -static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); - -/* ----------------------------------------------------------------------- */ -/* bttv format list - packed pixel formats must come first */ -static const struct bttv_format formats[] = { - { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .btformat = BT848_COLOR_FMT_Y8, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "8 bpp, dithered color", - .fourcc = V4L2_PIX_FMT_HI240, - .btformat = BT848_COLOR_FMT_RGB8, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, - },{ - .name = "15 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .btformat = BT848_COLOR_FMT_RGB15, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "15 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB555X, - .btformat = BT848_COLOR_FMT_RGB15, - .btswap = 0x03, /* byteswap */ - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "16 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB565, - .btformat = BT848_COLOR_FMT_RGB16, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "16 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB565X, - .btformat = BT848_COLOR_FMT_RGB16, - .btswap = 0x03, /* byteswap */ - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "24 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR24, - .btformat = BT848_COLOR_FMT_RGB24, - .depth = 24, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "32 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR32, - .btformat = BT848_COLOR_FMT_RGB32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "32 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB32, - .btformat = BT848_COLOR_FMT_RGB32, - .btswap = 0x0f, /* byte+word swap */ - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .btformat = BT848_COLOR_FMT_YUY2, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .btformat = BT848_COLOR_FMT_YUY2, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .btformat = BT848_COLOR_FMT_YUY2, - .btswap = 0x03, /* byteswap */ - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "4:2:2, planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV422P, - .btformat = BT848_COLOR_FMT_YCrCb422, - .depth = 16, - .flags = FORMAT_FLAGS_PLANAR, - .hshift = 1, - .vshift = 0, - },{ - .name = "4:2:0, planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV420, - .btformat = BT848_COLOR_FMT_YCrCb422, - .depth = 12, - .flags = FORMAT_FLAGS_PLANAR, - .hshift = 1, - .vshift = 1, - },{ - .name = "4:2:0, planar, Y-Cr-Cb", - .fourcc = V4L2_PIX_FMT_YVU420, - .btformat = BT848_COLOR_FMT_YCrCb422, - .depth = 12, - .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb, - .hshift = 1, - .vshift = 1, - },{ - .name = "4:1:1, planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV411P, - .btformat = BT848_COLOR_FMT_YCrCb411, - .depth = 12, - .flags = FORMAT_FLAGS_PLANAR, - .hshift = 2, - .vshift = 0, - },{ - .name = "4:1:0, planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV410, - .btformat = BT848_COLOR_FMT_YCrCb411, - .depth = 9, - .flags = FORMAT_FLAGS_PLANAR, - .hshift = 2, - .vshift = 2, - },{ - .name = "4:1:0, planar, Y-Cr-Cb", - .fourcc = V4L2_PIX_FMT_YVU410, - .btformat = BT848_COLOR_FMT_YCrCb411, - .depth = 9, - .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb, - .hshift = 2, - .vshift = 2, - },{ - .name = "raw scanlines", - .fourcc = -1, - .btformat = BT848_COLOR_FMT_RAW, - .depth = 8, - .flags = FORMAT_FLAGS_RAW, - } -}; -static const unsigned int FORMATS = ARRAY_SIZE(formats); - -/* ----------------------------------------------------------------------- */ - -#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4) -#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6) -#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8) -#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9) -#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11) - -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; -static const struct v4l2_queryctrl bttv_ctls[] = { - /* --- video --- */ - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 65535, - .step = 256, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 65535, - .step = 128, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 65535, - .step = 128, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 65535, - .step = 256, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - /* --- audio --- */ - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 65535, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_BALANCE, - .name = "Balance", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_BASS, - .name = "Bass", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_TREBLE, - .name = "Treble", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - /* --- private --- */ - { - .id = V4L2_CID_PRIVATE_CHROMA_AGC, - .name = "chroma agc", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_COMBFILTER, - .name = "combfilter", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_AUTOMUTE, - .name = "automute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_LUMAFILTER, - .name = "luma decimation filter", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_AGC_CRUSH, - .name = "agc crush", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_VCR_HACK, - .name = "vcr hack", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER, - .name = "whitecrush upper", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0xCF, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER, - .name = "whitecrush lower", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0x7F, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_UV_RATIO, - .name = "uv ratio", - .minimum = 0, - .maximum = 100, - .step = 1, - .default_value = 50, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, - .name = "full luma range", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_CORING, - .name = "coring", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - } - - - -}; - -static const struct v4l2_queryctrl *ctrl_by_id(int id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++) - if (bttv_ctls[i].id == id) - return bttv_ctls+i; - - return NULL; -} - -/* ----------------------------------------------------------------------- */ -/* resource management */ - -/* - RESOURCE_ allocated by freed by - - VIDEO_READ bttv_read 1) bttv_read 2) - - VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF - VIDIOC_QBUF 1) bttv_release - VIDIOCMCAPTURE 1) - - OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off - VIDIOC_OVERLAY on VIDIOC_OVERLAY off - 3) bttv_release - - VBI VIDIOC_STREAMON VIDIOC_STREAMOFF - VIDIOC_QBUF 1) bttv_release - bttv_read, bttv_poll 1) 4) - - 1) The resource must be allocated when we enter buffer prepare functions - and remain allocated while buffers are in the DMA queue. - 2) This is a single frame read. - 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when - RESOURCE_OVERLAY is allocated. - 4) This is a continuous read, implies VIDIOC_STREAMON. - - Note this driver permits video input and standard changes regardless if - resources are allocated. -*/ - -#define VBI_RESOURCES (RESOURCE_VBI) -#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \ - RESOURCE_VIDEO_STREAM | \ - RESOURCE_OVERLAY) - -static -int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) -{ - int xbits; /* mutual exclusive resources */ - - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - xbits = bit; - if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM)) - xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM; - - /* is it free? */ - if (btv->resources & xbits) { - /* no, someone else uses it */ - goto fail; - } - - if ((bit & VIDEO_RESOURCES) - && 0 == (btv->resources & VIDEO_RESOURCES)) { - /* Do crop - use current, don't - use default parameters. */ - __s32 top = btv->crop[!!fh->do_crop].rect.top; - - if (btv->vbi_end > top) - goto fail; - - /* We cannot capture the same line as video and VBI data. - Claim scan lines crop[].rect.top to bottom. */ - btv->crop_start = top; - } else if (bit & VBI_RESOURCES) { - __s32 end = fh->vbi_fmt.end; - - if (end > btv->crop_start) - goto fail; - - /* Claim scan lines above fh->vbi_fmt.end. */ - btv->vbi_end = end; - } - - /* it's free, grab it */ - fh->resources |= bit; - btv->resources |= bit; - return 1; - - fail: - return 0; -} - -static -int check_btres(struct bttv_fh *fh, int bit) -{ - return (fh->resources & bit); -} - -static -int locked_btres(struct bttv *btv, int bit) -{ - return (btv->resources & bit); -} - -/* Call with btv->lock down. */ -static void -disclaim_vbi_lines(struct bttv *btv) -{ - btv->vbi_end = 0; -} - -/* Call with btv->lock down. */ -static void -disclaim_video_lines(struct bttv *btv) -{ - const struct bttv_tvnorm *tvnorm; - u8 crop; - - tvnorm = &bttv_tvnorms[btv->tvnorm]; - btv->crop_start = tvnorm->cropcap.bounds.top - + tvnorm->cropcap.bounds.height; - - /* VBI capturing ends at VDELAY, start of video capturing, no - matter how many lines the VBI RISC program expects. When video - capturing is off, it shall no longer "preempt" VBI capturing, - so we set VDELAY to maximum. */ - crop = btread(BT848_E_CROP) | 0xc0; - btwrite(crop, BT848_E_CROP); - btwrite(0xfe, BT848_E_VDELAY_LO); - btwrite(crop, BT848_O_CROP); - btwrite(0xfe, BT848_O_VDELAY_LO); -} - -static -void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) -{ - if ((fh->resources & bits) != bits) { - /* trying to free ressources not allocated by us ... */ - printk("bttv: BUG! (btres)\n"); - } - fh->resources &= ~bits; - btv->resources &= ~bits; - - bits = btv->resources; - - if (0 == (bits & VIDEO_RESOURCES)) - disclaim_video_lines(btv); - - if (0 == (bits & VBI_RESOURCES)) - disclaim_vbi_lines(btv); -} - -/* ----------------------------------------------------------------------- */ -/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */ - -/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C - PLL_X = Reference pre-divider (0=1, 1=2) - PLL_C = Post divider (0=6, 1=4) - PLL_I = Integer input - PLL_F = Fractional input - - F_input = 28.636363 MHz: - PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0 -*/ - -static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout) -{ - unsigned char fl, fh, fi; - - /* prevent overflows */ - fin/=4; - fout/=4; - - fout*=12; - fi=fout/fin; - - fout=(fout%fin)*256; - fh=fout/fin; - - fout=(fout%fin)*256; - fl=fout/fin; - - btwrite(fl, BT848_PLL_F_LO); - btwrite(fh, BT848_PLL_F_HI); - btwrite(fi|BT848_PLL_X, BT848_PLL_XCI); -} - -static void set_pll(struct bttv *btv) -{ - int i; - - if (!btv->pll.pll_crystal) - return; - - if (btv->pll.pll_ofreq == btv->pll.pll_current) { - dprintk("bttv%d: PLL: no change required\n",btv->c.nr); - return; - } - - if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) { - /* no PLL needed */ - if (btv->pll.pll_current == 0) - return; - bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n", - btv->c.nr,btv->pll.pll_ifreq); - btwrite(0x00,BT848_TGCTRL); - btwrite(0x00,BT848_PLL_XCI); - btv->pll.pll_current = 0; - return; - } - - bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr, - btv->pll.pll_ifreq, btv->pll.pll_ofreq); - set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); - - for (i=0; i<10; i++) { - /* Let other people run while the PLL stabilizes */ - bttv_printk("."); - msleep(10); - - if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) { - btwrite(0,BT848_DSTATUS); - } else { - btwrite(0x08,BT848_TGCTRL); - btv->pll.pll_current = btv->pll.pll_ofreq; - bttv_printk(" ok\n"); - return; - } - } - btv->pll.pll_current = -1; - bttv_printk("failed\n"); - return; -} - -/* used to switch between the bt848's analog/digital video capture modes */ -static void bt848A_set_timing(struct bttv *btv) -{ - int i, len; - int table_idx = bttv_tvnorms[btv->tvnorm].sram; - int fsc = bttv_tvnorms[btv->tvnorm].Fsc; - - if (btv->input == btv->dig) { - dprintk("bttv%d: load digital timing table (table_idx=%d)\n", - btv->c.nr,table_idx); - - /* timing change...reset timing generator address */ - btwrite(0x00, BT848_TGCTRL); - btwrite(0x02, BT848_TGCTRL); - btwrite(0x00, BT848_TGCTRL); - - len=SRAM_Table[table_idx][0]; - for(i = 1; i <= len; i++) - btwrite(SRAM_Table[table_idx][i],BT848_TGLB); - btv->pll.pll_ofreq = 27000000; - - set_pll(btv); - btwrite(0x11, BT848_TGCTRL); - btwrite(0x41, BT848_DVSIF); - } else { - btv->pll.pll_ofreq = fsc; - set_pll(btv); - btwrite(0x0, BT848_DVSIF); - } -} - -/* ----------------------------------------------------------------------- */ - -static void bt848_bright(struct bttv *btv, int bright) -{ - int value; - - // printk("bttv: set bright: %d\n",bright); // DEBUG - btv->bright = bright; - - /* We want -128 to 127 we get 0-65535 */ - value = (bright >> 8) - 128; - btwrite(value & 0xff, BT848_BRIGHT); -} - -static void bt848_hue(struct bttv *btv, int hue) -{ - int value; - - btv->hue = hue; - - /* -128 to 127 */ - value = (hue >> 8) - 128; - btwrite(value & 0xff, BT848_HUE); -} - -static void bt848_contrast(struct bttv *btv, int cont) -{ - int value,hibit; - - btv->contrast = cont; - - /* 0-511 */ - value = (cont >> 7); - hibit = (value >> 6) & 4; - btwrite(value & 0xff, BT848_CONTRAST_LO); - btaor(hibit, ~4, BT848_E_CONTROL); - btaor(hibit, ~4, BT848_O_CONTROL); -} - -static void bt848_sat(struct bttv *btv, int color) -{ - int val_u,val_v,hibits; - - btv->saturation = color; - - /* 0-511 for the color */ - val_u = ((color * btv->opt_uv_ratio) / 50) >> 7; - val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254; - hibits = (val_u >> 7) & 2; - hibits |= (val_v >> 8) & 1; - btwrite(val_u & 0xff, BT848_SAT_U_LO); - btwrite(val_v & 0xff, BT848_SAT_V_LO); - btaor(hibits, ~3, BT848_E_CONTROL); - btaor(hibits, ~3, BT848_O_CONTROL); -} - -/* ----------------------------------------------------------------------- */ - -static int -video_mux(struct bttv *btv, unsigned int input) -{ - int mux,mask2; - - if (input >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - - /* needed by RemoteVideo MX */ - mask2 = bttv_tvcards[btv->c.type].gpiomask2; - if (mask2) - gpio_inout(mask2,mask2); - - if (input == btv->svhs) { - btor(BT848_CONTROL_COMP, BT848_E_CONTROL); - btor(BT848_CONTROL_COMP, BT848_O_CONTROL); - } else { - btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); - btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); - } - mux = bttv_muxsel(btv, input); - btaor(mux<<5, ~(3<<5), BT848_IFORM); - dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n", - btv->c.nr,input,mux); - - /* card specific hook */ - if(bttv_tvcards[btv->c.type].muxsel_hook) - bttv_tvcards[btv->c.type].muxsel_hook (btv, input); - return 0; -} - -static char *audio_modes[] = { - "audio: tuner", "audio: radio", "audio: extern", - "audio: intern", "audio: mute" -}; - -static int -audio_mux(struct bttv *btv, int input, int mute) -{ - int gpio_val, signal; - struct v4l2_control ctrl; - - gpio_inout(bttv_tvcards[btv->c.type].gpiomask, - bttv_tvcards[btv->c.type].gpiomask); - signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC; - - btv->mute = mute; - btv->audio = input; - - /* automute */ - mute = mute || (btv->opt_automute && !signal && !btv->radio_user); - - if (mute) - gpio_val = bttv_tvcards[btv->c.type].gpiomute; - else - gpio_val = bttv_tvcards[btv->c.type].gpiomux[input]; - - switch (btv->c.type) { - case BTTV_BOARD_VOODOOTV_FM: - case BTTV_BOARD_VOODOOTV_200: - gpio_val = bttv_tda9880_setnorm(btv, gpio_val); - break; - - default: - gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val); - } - - if (bttv_gpio) - bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]); - if (in_interrupt()) - return 0; - - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = btv->mute; - bttv_call_all(btv, core, s_ctrl, &ctrl); - if (btv->sd_msp34xx) { - u32 in; - - /* Note: the inputs tuner/radio/extern/intern are translated - to msp routings. This assumes common behavior for all msp3400 - based TV cards. When this assumption fails, then the - specific MSP routing must be added to the card table. - For now this is sufficient. */ - switch (input) { - case TVAUDIO_INPUT_RADIO: - in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; - case TVAUDIO_INPUT_EXTERN: - in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; - case TVAUDIO_INPUT_INTERN: - /* Yes, this is the same input as for RADIO. I doubt - if this is ever used. The only board with an INTERN - input is the BTTV_BOARD_AVERMEDIA98. I wonder how - that was tested. My guess is that the whole INTERN - input does not work. */ - in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; - case TVAUDIO_INPUT_TUNER: - default: - /* This is the only card that uses TUNER2, and afaik, - is the only difference between the VOODOOTV_FM - and VOODOOTV_200 */ - if (btv->c.type == BTTV_BOARD_VOODOOTV_200) - in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \ - MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER); - else - in = MSP_INPUT_DEFAULT; - break; - } - v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing, - in, MSP_OUTPUT_DEFAULT, 0); - } - if (btv->sd_tvaudio) { - v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, - input, 0, 0); - } - return 0; -} - -static inline int -audio_mute(struct bttv *btv, int mute) -{ - return audio_mux(btv, btv->audio, mute); -} - -static inline int -audio_input(struct bttv *btv, int input) -{ - return audio_mux(btv, input, btv->mute); -} - -static void -bttv_crop_calc_limits(struct bttv_crop *c) -{ - /* Scale factor min. 1:1, max. 16:1. Min. image size - 48 x 32. Scaled width must be a multiple of 4. */ - - if (1) { - /* For bug compatibility with VIDIOCGCAP and image - size checks in earlier driver versions. */ - c->min_scaled_width = 48; - c->min_scaled_height = 32; - } else { - c->min_scaled_width = - (max(48, c->rect.width >> 4) + 3) & ~3; - c->min_scaled_height = - max(32, c->rect.height >> 4); - } - - c->max_scaled_width = c->rect.width & ~3; - c->max_scaled_height = c->rect.height; -} - -static void -bttv_crop_reset(struct bttv_crop *c, unsigned int norm) -{ - c->rect = bttv_tvnorms[norm].cropcap.defrect; - bttv_crop_calc_limits(c); -} - -/* Call with btv->lock down. */ -static int -set_tvnorm(struct bttv *btv, unsigned int norm) -{ - const struct bttv_tvnorm *tvnorm; - v4l2_std_id id; - - BUG_ON(norm >= BTTV_TVNORMS); - BUG_ON(btv->tvnorm >= BTTV_TVNORMS); - - tvnorm = &bttv_tvnorms[norm]; - - if (memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap, - sizeof (tvnorm->cropcap))) { - bttv_crop_reset(&btv->crop[0], norm); - btv->crop[1] = btv->crop[0]; /* current = default */ - - if (0 == (btv->resources & VIDEO_RESOURCES)) { - btv->crop_start = tvnorm->cropcap.bounds.top - + tvnorm->cropcap.bounds.height; - } - } - - btv->tvnorm = norm; - - btwrite(tvnorm->adelay, BT848_ADELAY); - btwrite(tvnorm->bdelay, BT848_BDELAY); - btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), - BT848_IFORM); - btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE); - btwrite(1, BT848_VBI_PACK_DEL); - bt848A_set_timing(btv); - - switch (btv->c.type) { - case BTTV_BOARD_VOODOOTV_FM: - case BTTV_BOARD_VOODOOTV_200: - bttv_tda9880_setnorm(btv, gpio_read()); - break; - } - id = tvnorm->v4l2_id; - bttv_call_all(btv, core, s_std, id); - - return 0; -} - -/* Call with btv->lock down. */ -static void -set_input(struct bttv *btv, unsigned int input, unsigned int norm) -{ - unsigned long flags; - - btv->input = input; - if (irq_iswitch) { - spin_lock_irqsave(&btv->s_lock,flags); - if (btv->curr.frame_irq) { - /* active capture -> delayed input switch */ - btv->new_input = input; - } else { - video_mux(btv,input); - } - spin_unlock_irqrestore(&btv->s_lock,flags); - } else { - video_mux(btv,input); - } - audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ? - TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN); - set_tvnorm(btv, norm); -} - -static void init_irqreg(struct bttv *btv) -{ - /* clear status */ - btwrite(0xfffffUL, BT848_INT_STAT); - - if (bttv_tvcards[btv->c.type].no_video) { - /* i2c only */ - btwrite(BT848_INT_I2CDONE, - BT848_INT_MASK); - } else { - /* full video */ - btwrite((btv->triton1) | - (btv->gpioirq ? BT848_INT_GPINT : 0) | - BT848_INT_SCERR | - (fdsr ? BT848_INT_FDSR : 0) | - BT848_INT_RISCI | BT848_INT_OCERR | - BT848_INT_FMTCHG|BT848_INT_HLOCK| - BT848_INT_I2CDONE, - BT848_INT_MASK); - } -} - -static void init_bt848(struct bttv *btv) -{ - int val; - - if (bttv_tvcards[btv->c.type].no_video) { - /* very basic init only */ - init_irqreg(btv); - return; - } - - btwrite(0x00, BT848_CAP_CTL); - btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); - btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM); - - /* set planar and packed mode trigger points and */ - /* set rising edge of inverted GPINTR pin as irq trigger */ - btwrite(BT848_GPIO_DMA_CTL_PKTP_32| - BT848_GPIO_DMA_CTL_PLTP1_16| - BT848_GPIO_DMA_CTL_PLTP23_16| - BT848_GPIO_DMA_CTL_GPINTC| - BT848_GPIO_DMA_CTL_GPINTI, - BT848_GPIO_DMA_CTL); - - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); - - btwrite(0x20, BT848_E_VSCALE_HI); - btwrite(0x20, BT848_O_VSCALE_HI); - btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); - - btwrite(whitecrush_upper, BT848_WC_UP); - btwrite(whitecrush_lower, BT848_WC_DOWN); - - if (btv->opt_lumafilter) { - btwrite(0, BT848_E_CONTROL); - btwrite(0, BT848_O_CONTROL); - } else { - btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); - } - - bt848_bright(btv, btv->bright); - bt848_hue(btv, btv->hue); - bt848_contrast(btv, btv->contrast); - bt848_sat(btv, btv->saturation); - - /* interrupt */ - init_irqreg(btv); -} - -static void bttv_reinit_bt848(struct bttv *btv) -{ - unsigned long flags; - - if (bttv_verbose) - printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr); - spin_lock_irqsave(&btv->s_lock,flags); - btv->errors=0; - bttv_set_dma(btv,0); - spin_unlock_irqrestore(&btv->s_lock,flags); - - init_bt848(btv); - btv->pll.pll_current = -1; - set_input(btv, btv->input, btv->tvnorm); -} - -static int bttv_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = btv->bright; - break; - case V4L2_CID_HUE: - c->value = btv->hue; - break; - case V4L2_CID_CONTRAST: - c->value = btv->contrast; - break; - case V4L2_CID_SATURATION: - c->value = btv->saturation; - break; - - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_all(btv, core, g_ctrl, c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - c->value = btv->opt_chroma_agc; - break; - case V4L2_CID_PRIVATE_COMBFILTER: - c->value = btv->opt_combfilter; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - c->value = btv->opt_lumafilter; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - c->value = btv->opt_automute; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - c->value = btv->opt_adc_crush; - break; - case V4L2_CID_PRIVATE_VCR_HACK: - c->value = btv->opt_vcr_hack; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - c->value = btv->opt_whitecrush_upper; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - c->value = btv->opt_whitecrush_lower; - break; - case V4L2_CID_PRIVATE_UV_RATIO: - c->value = btv->opt_uv_ratio; - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - c->value = btv->opt_full_luma_range; - break; - case V4L2_CID_PRIVATE_CORING: - c->value = btv->opt_coring; - break; - default: - return -EINVAL; - } - return 0; -} - -static int bttv_s_ctrl(struct file *file, void *f, - struct v4l2_control *c) -{ - int err; - int val; - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (0 != err) - return err; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - bt848_bright(btv, c->value); - break; - case V4L2_CID_HUE: - bt848_hue(btv, c->value); - break; - case V4L2_CID_CONTRAST: - bt848_contrast(btv, c->value); - break; - case V4L2_CID_SATURATION: - bt848_sat(btv, c->value); - break; - case V4L2_CID_AUDIO_MUTE: - audio_mute(btv, c->value); - /* fall through */ - case V4L2_CID_AUDIO_VOLUME: - if (btv->volume_gpio) - btv->volume_gpio(btv, c->value); - - bttv_call_all(btv, core, s_ctrl, c); - break; - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_all(btv, core, s_ctrl, c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - btv->opt_chroma_agc = c->value; - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); - break; - case V4L2_CID_PRIVATE_COMBFILTER: - btv->opt_combfilter = c->value; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - btv->opt_lumafilter = c->value; - if (btv->opt_lumafilter) { - btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); - btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); - } else { - btor(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btor(BT848_CONTROL_LDEC, BT848_O_CONTROL); - } - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - btv->opt_automute = c->value; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - btv->opt_adc_crush = c->value; - btwrite(BT848_ADC_RESERVED | - (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); - break; - case V4L2_CID_PRIVATE_VCR_HACK: - btv->opt_vcr_hack = c->value; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - btv->opt_whitecrush_upper = c->value; - btwrite(c->value, BT848_WC_UP); - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - btv->opt_whitecrush_lower = c->value; - btwrite(c->value, BT848_WC_DOWN); - break; - case V4L2_CID_PRIVATE_UV_RATIO: - btv->opt_uv_ratio = c->value; - bt848_sat(btv, btv->saturation); - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - btv->opt_full_luma_range = c->value; - btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); - break; - case V4L2_CID_PRIVATE_CORING: - btv->opt_coring = c->value; - btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); - break; - default: - return -EINVAL; - } - return 0; -} - -/* ----------------------------------------------------------------------- */ - -void bttv_gpio_tracking(struct bttv *btv, char *comment) -{ - unsigned int outbits, data; - outbits = btread(BT848_GPIO_OUT_EN); - data = btread(BT848_GPIO_DATA); - printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", - btv->c.nr,outbits,data & outbits, data & ~outbits, comment); -} - -static void bttv_field_count(struct bttv *btv) -{ - int need_count = 0; - - if (btv->users) - need_count++; - - if (need_count) { - /* start field counter */ - btor(BT848_INT_VSYNC,BT848_INT_MASK); - } else { - /* stop field counter */ - btand(~BT848_INT_VSYNC,BT848_INT_MASK); - btv->field_count = 0; - } -} - -static const struct bttv_format* -format_by_fourcc(int fourcc) -{ - unsigned int i; - - for (i = 0; i < FORMATS; i++) { - if (-1 == formats[i].fourcc) - continue; - if (formats[i].fourcc == fourcc) - return formats+i; - } - return NULL; -} - -/* ----------------------------------------------------------------------- */ -/* misc helpers */ - -static int -bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, - struct bttv_buffer *new) -{ - struct bttv_buffer *old; - unsigned long flags; - int retval = 0; - - dprintk("switch_overlay: enter [new=%p]\n",new); - if (new) - new->vb.state = VIDEOBUF_DONE; - spin_lock_irqsave(&btv->s_lock,flags); - old = btv->screen; - btv->screen = new; - btv->loop_irq |= 1; - bttv_set_dma(btv, 0x03); - spin_unlock_irqrestore(&btv->s_lock,flags); - if (NULL != old) { - dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state); - bttv_dma_free(&fh->cap,btv, old); - kfree(old); - } - if (NULL == new) - free_btres_lock(btv,fh,RESOURCE_OVERLAY); - dprintk("switch_overlay: done\n"); - return retval; -} - -/* ----------------------------------------------------------------------- */ -/* video4linux (1) interface */ - -static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, - struct bttv_buffer *buf, - const struct bttv_format *fmt, - unsigned int width, unsigned int height, - enum v4l2_field field) -{ - struct bttv_fh *fh = q->priv_data; - int redo_dma_risc = 0; - struct bttv_crop c; - int norm; - int rc; - - /* check settings */ - if (NULL == fmt) - return -EINVAL; - if (fmt->btformat == BT848_COLOR_FMT_RAW) { - width = RAW_BPL; - height = RAW_LINES*2; - if (width*height > buf->vb.bsize) - return -EINVAL; - buf->vb.size = buf->vb.bsize; - - /* Make sure tvnorm and vbi_end remain consistent - until we're done. */ - - norm = btv->tvnorm; - - /* In this mode capturing always starts at defrect.top - (default VDELAY), ignoring cropping parameters. */ - if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) { - return -EINVAL; - } - - c.rect = bttv_tvnorms[norm].cropcap.defrect; - } else { - norm = btv->tvnorm; - c = btv->crop[!!fh->do_crop]; - - if (width < c.min_scaled_width || - width > c.max_scaled_width || - height < c.min_scaled_height) - return -EINVAL; - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - /* btv->crop counts frame lines. Max. scale - factor is 16:1 for frames, 8:1 for fields. */ - if (height * 2 > c.max_scaled_height) - return -EINVAL; - break; - - default: - if (height > c.max_scaled_height) - return -EINVAL; - break; - } - - buf->vb.size = (width * height * fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - } - - /* alloc + fill struct bttv_buffer (if changed) */ - if (buf->vb.width != width || buf->vb.height != height || - buf->vb.field != field || - buf->tvnorm != norm || buf->fmt != fmt || - buf->crop.top != c.rect.top || - buf->crop.left != c.rect.left || - buf->crop.width != c.rect.width || - buf->crop.height != c.rect.height) { - buf->vb.width = width; - buf->vb.height = height; - buf->vb.field = field; - buf->tvnorm = norm; - buf->fmt = fmt; - buf->crop = c.rect; - redo_dma_risc = 1; - } - - /* alloc risc memory */ - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - redo_dma_risc = 1; - if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf))) - goto fail; - } - - if (redo_dma_risc) - if (0 != (rc = bttv_buffer_risc(btv,buf))) - goto fail; - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - bttv_dma_free(q,btv,buf); - return rc; -} - -static int -buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct bttv_fh *fh = q->priv_data; - - *size = fh->fmt->depth*fh->width*fh->height >> 3; - if (0 == *count) - *count = gbuffers; - if (*size * *count > gbuffers * gbufsize) - *count = (gbuffers * gbufsize) / *size; - return 0; -} - -static int -buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - struct bttv_fh *fh = q->priv_data; - - return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt, - fh->width, fh->height, field); -} - -static void -buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue,&btv->capture); - if (!btv->curr.frame_irq) { - btv->loop_irq |= 1; - bttv_set_dma(btv, 0x03); - } -} - -static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - struct bttv_fh *fh = q->priv_data; - - bttv_dma_free(q,fh->btv,buf); -} - -static struct videobuf_queue_ops bttv_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - unsigned int i; - int err; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (err) - goto err; - - for (i = 0; i < BTTV_TVNORMS; i++) - if (*id & bttv_tvnorms[i].v4l2_id) - break; - if (i == BTTV_TVNORMS) { - err = -EINVAL; - goto err; - } - - set_tvnorm(btv, i); - -err: - - return err; -} - -static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) - *id = V4L2_STD_625_50; - else - *id = V4L2_STD_525_60; - return 0; -} - -static int bttv_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int rc = 0; - - if (i->index >= bttv_tvcards[btv->c.type].video_inputs) { - rc = -EINVAL; - goto err; - } - - i->type = V4L2_INPUT_TYPE_CAMERA; - i->audioset = 1; - - if (btv->tuner_type != TUNER_ABSENT && i->index == 0) { - sprintf(i->name, "Television"); - i->type = V4L2_INPUT_TYPE_TUNER; - i->tuner = 0; - } else if (i->index == btv->svhs) { - sprintf(i->name, "S-Video"); - } else { - sprintf(i->name, "Composite%d", i->index); - } - - if (i->index == btv->input) { - __u32 dstatus = btread(BT848_DSTATUS); - if (0 == (dstatus & BT848_DSTATUS_PRES)) - i->status |= V4L2_IN_ST_NO_SIGNAL; - if (0 == (dstatus & BT848_DSTATUS_HLOC)) - i->status |= V4L2_IN_ST_NO_H_LOCK; - } - - i->std = BTTV_NORMS; - -err: - - return rc; -} - -static int bttv_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - *i = btv->input; - - return 0; -} - -static int bttv_s_input(struct file *file, void *priv, unsigned int i) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - int err; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (unlikely(err)) - goto err; - - if (i > bttv_tvcards[btv->c.type].video_inputs) { - err = -EINVAL; - goto err; - } - - set_input(btv, i, btv->tvnorm); - -err: - return 0; -} - -static int bttv_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int err; - - if (unlikely(0 != t->index)) - return -EINVAL; - - if (unlikely(btv->tuner_type == TUNER_ABSENT)) { - err = -EINVAL; - goto err; - } - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (unlikely(err)) - goto err; - - bttv_call_all(btv, tuner, s_tuner, t); - - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 1); - -err: - - return 0; -} - -static int bttv_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = btv->freq; - - return 0; -} - -static int bttv_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int err; - - if (unlikely(f->tuner != 0)) - return -EINVAL; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (unlikely(err)) - goto err; - - if (unlikely(f->type != (btv->radio_user - ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) { - err = -EINVAL; - goto err; - } - btv->freq = f->frequency; - bttv_call_all(btv, tuner, s_frequency, f); - if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv, btv->freq); -err: - - return 0; -} - -static int bttv_log_status(struct file *file, void *f) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n", - btv->c.nr, btv->c.nr); - bttv_call_all(btv, core, log_status); - printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n", - btv->c.nr, btv->c.nr); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int bttv_g_register(struct file *file, void *f, - struct v4l2_dbg_register *reg) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - - /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - reg->val = btread(reg->reg); - reg->size = 1; - - return 0; -} - -static int bttv_s_register(struct file *file, void *f, - struct v4l2_dbg_register *reg) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - - /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - btwrite(reg->val, reg->reg); - - return 0; -} -#endif - -/* Given cropping boundaries b and the scaled width and height of a - single field or frame, which must not exceed hardware limits, this - function adjusts the cropping parameters c. */ -static void -bttv_crop_adjust (struct bttv_crop * c, - const struct v4l2_rect * b, - __s32 width, - __s32 height, - enum v4l2_field field) -{ - __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field); - __s32 max_left; - __s32 max_top; - - if (width < c->min_scaled_width) { - /* Max. hor. scale factor 16:1. */ - c->rect.width = width * 16; - } else if (width > c->max_scaled_width) { - /* Min. hor. scale factor 1:1. */ - c->rect.width = width; - - max_left = b->left + b->width - width; - max_left = min(max_left, (__s32) MAX_HDELAY); - if (c->rect.left > max_left) - c->rect.left = max_left; - } - - if (height < c->min_scaled_height) { - /* Max. vert. scale factor 16:1, single fields 8:1. */ - c->rect.height = height * 16; - } else if (frame_height > c->max_scaled_height) { - /* Min. vert. scale factor 1:1. - Top and height count field lines times two. */ - c->rect.height = (frame_height + 1) & ~1; - - max_top = b->top + b->height - c->rect.height; - if (c->rect.top > max_top) - c->rect.top = max_top; - } - - bttv_crop_calc_limits(c); -} - -/* Returns an error if scaling to a frame or single field with the given - width and height is not possible with the current cropping parameters - and width aligned according to width_mask. If adjust_size is TRUE the - function may adjust the width and/or height instead, rounding width - to (width + width_bias) & width_mask. If adjust_crop is TRUE it may - also adjust the current cropping parameters to get closer to the - desired image size. */ -static int -limit_scaled_size_lock (struct bttv_fh * fh, - __s32 * width, - __s32 * height, - enum v4l2_field field, - unsigned int width_mask, - unsigned int width_bias, - int adjust_size, - int adjust_crop) -{ - struct bttv *btv = fh->btv; - const struct v4l2_rect *b; - struct bttv_crop *c; - __s32 min_width; - __s32 min_height; - __s32 max_width; - __s32 max_height; - int rc; - - BUG_ON((int) width_mask >= 0 || - width_bias >= (unsigned int) -width_mask); - - /* Make sure tvnorm, vbi_end and the current cropping parameters - remain consistent until we're done. */ - - b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; - - /* Do crop - use current, don't - use default parameters. */ - c = &btv->crop[!!fh->do_crop]; - - if (fh->do_crop - && adjust_size - && adjust_crop - && !locked_btres(btv, VIDEO_RESOURCES)) { - min_width = 48; - min_height = 32; - - /* We cannot scale up. When the scaled image is larger - than crop.rect we adjust the crop.rect as required - by the V4L2 spec, hence cropcap.bounds are our limit. */ - max_width = min(b->width, (__s32) MAX_HACTIVE); - max_height = b->height; - - /* We cannot capture the same line as video and VBI data. - Note btv->vbi_end is really a minimum, see - bttv_vbi_try_fmt(). */ - if (btv->vbi_end > b->top) { - max_height -= btv->vbi_end - b->top; - rc = -EBUSY; - if (min_height > max_height) - goto fail; - } - } else { - rc = -EBUSY; - if (btv->vbi_end > c->rect.top) - goto fail; - - min_width = c->min_scaled_width; - min_height = c->min_scaled_height; - max_width = c->max_scaled_width; - max_height = c->max_scaled_height; - - adjust_crop = 0; - } - - min_width = (min_width - width_mask - 1) & width_mask; - max_width = max_width & width_mask; - - /* Max. scale factor is 16:1 for frames, 8:1 for fields. */ - min_height = min_height; - /* Min. scale factor is 1:1. */ - max_height >>= !V4L2_FIELD_HAS_BOTH(field); - - if (adjust_size) { - *width = clamp(*width, min_width, max_width); - *height = clamp(*height, min_height, max_height); - - /* Round after clamping to avoid overflow. */ - *width = (*width + width_bias) & width_mask; - - if (adjust_crop) { - bttv_crop_adjust(c, b, *width, *height, field); - - if (btv->vbi_end > c->rect.top) { - /* Move the crop window out of the way. */ - c->rect.top = btv->vbi_end; - } - } - } else { - rc = -EINVAL; - if (*width < min_width || - *height < min_height || - *width > max_width || - *height > max_height || - 0 != (*width & ~width_mask)) - goto fail; - } - - rc = 0; /* success */ - - fail: - - return rc; -} - -/* Returns an error if the given overlay window dimensions are not - possible with the current cropping parameters. If adjust_size is - TRUE the function may adjust the window width and/or height - instead, however it always rounds the horizontal position and - width as btcx_align() does. If adjust_crop is TRUE the function - may also adjust the current cropping parameters to get closer - to the desired window size. */ -static int -verify_window_lock (struct bttv_fh * fh, - struct v4l2_window * win, - int adjust_size, - int adjust_crop) -{ - enum v4l2_field field; - unsigned int width_mask; - int rc; - - if (win->w.width < 48 || win->w.height < 32) - return -EINVAL; - if (win->clipcount > 2048) - return -EINVAL; - - field = win->field; - - if (V4L2_FIELD_ANY == field) { - __s32 height2; - - height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1; - field = (win->w.height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - /* 4-byte alignment. */ - if (NULL == fh->ovfmt) - return -EINVAL; - width_mask = ~0; - switch (fh->ovfmt->depth) { - case 8: - case 24: - width_mask = ~3; - break; - case 16: - width_mask = ~1; - break; - case 32: - break; - default: - BUG(); - } - - win->w.width -= win->w.left & ~width_mask; - win->w.left = (win->w.left - width_mask - 1) & width_mask; - - rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height, - field, width_mask, - /* width_bias: round down */ 0, - adjust_size, adjust_crop); - if (0 != rc) - return rc; - - win->field = field; - return 0; -} - -static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, - struct v4l2_window *win, int fixup) -{ - struct v4l2_clip *clips = NULL; - int n,size,retval = 0; - - if (NULL == fh->ovfmt) - return -EINVAL; - if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; - retval = verify_window_lock(fh, win, - /* adjust_size */ fixup, - /* adjust_crop */ fixup); - if (0 != retval) - return retval; - - /* copy clips -- luckily v4l1 + v4l2 are binary - compatible here ...*/ - n = win->clipcount; - size = sizeof(*clips)*(n+4); - clips = kmalloc(size,GFP_KERNEL); - if (NULL == clips) - return -ENOMEM; - if (n > 0) { - if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) { - kfree(clips); - return -EFAULT; - } - } - - /* clip against screen */ - if (NULL != btv->fbuf.base) - n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height, - &win->w, clips, n); - btcx_sort_clips(clips,n); - - /* 4-byte alignments */ - switch (fh->ovfmt->depth) { - case 8: - case 24: - btcx_align(&win->w, clips, n, 3); - break; - case 16: - btcx_align(&win->w, clips, n, 1); - break; - case 32: - /* no alignment fixups needed */ - break; - default: - BUG(); - } - - kfree(fh->ov.clips); - fh->ov.clips = clips; - fh->ov.nclips = n; - - fh->ov.w = win->w; - fh->ov.field = win->field; - fh->ov.setup_ok = 1; - - btv->init.ov.w.width = win->w.width; - btv->init.ov.w.height = win->w.height; - btv->init.ov.field = win->field; - - /* update overlay if needed */ - retval = 0; - if (check_btres(fh, RESOURCE_OVERLAY)) { - struct bttv_buffer *new; - - new = videobuf_sg_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - retval = bttv_switch_overlay(btv,fh,new); - } - return retval; -} - -/* ----------------------------------------------------------------------- */ - -static struct videobuf_queue* bttv_queue(struct bttv_fh *fh) -{ - struct videobuf_queue* q = NULL; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - q = &fh->cap; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - q = &fh->vbi; - break; - default: - BUG(); - } - return q; -} - -static int bttv_resource(struct bttv_fh *fh) -{ - int res = 0; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - res = RESOURCE_VIDEO_STREAM; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - res = RESOURCE_VBI; - break; - default: - BUG(); - } - return res; -} - -static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type) -{ - struct videobuf_queue *q = bttv_queue(fh); - int res = bttv_resource(fh); - - if (check_btres(fh,res)) - return -EBUSY; - if (videobuf_queue_is_busy(q)) - return -EBUSY; - fh->type = type; - return 0; -} - -static void -pix_format_set_size (struct v4l2_pix_format * f, - const struct bttv_format * fmt, - unsigned int width, - unsigned int height) -{ - f->width = width; - f->height = height; - - if (fmt->flags & FORMAT_FLAGS_PLANAR) { - f->bytesperline = width; /* Y plane */ - f->sizeimage = (width * height * fmt->depth) >> 3; - } else { - f->bytesperline = (width * fmt->depth) >> 3; - f->sizeimage = height * f->bytesperline; - } -} - -static int bttv_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - - pix_format_set_size(&f->fmt.pix, fh->fmt, - fh->width, fh->height); - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - - return 0; -} - -static int bttv_g_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - - f->fmt.win.w = fh->ov.w; - f->fmt.win.field = fh->ov.field; - - return 0; -} - -static int bttv_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - const struct bttv_format *fmt; - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - enum v4l2_field field; - __s32 width, height; - int rc; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - - if (V4L2_FIELD_ANY == field) { - __s32 height2; - - height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - field = (f->fmt.pix.height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - - if (V4L2_FIELD_SEQ_BT == field) - field = V4L2_FIELD_SEQ_TB; - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - case V4L2_FIELD_INTERLACED: - break; - case V4L2_FIELD_SEQ_TB: - if (fmt->flags & FORMAT_FLAGS_PLANAR) - return -EINVAL; - break; - default: - return -EINVAL; - } - - width = f->fmt.pix.width; - height = f->fmt.pix.height; - - rc = limit_scaled_size_lock(fh, &width, &height, field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, - /* adjust_size */ 1, - /* adjust_crop */ 0); - if (0 != rc) - return rc; - - /* update data for the application */ - f->fmt.pix.field = field; - pix_format_set_size(&f->fmt.pix, fmt, width, height); - - return 0; -} - -static int bttv_try_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - - return verify_window_lock(fh, &f->fmt.win, - /* adjust_size */ 1, - /* adjust_crop */ 0); -} - -static int bttv_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - int retval; - const struct bttv_format *fmt; - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - __s32 width, height; - enum v4l2_field field; - - retval = bttv_switch_type(fh, f->type); - if (0 != retval) - return retval; - - retval = bttv_try_fmt_vid_cap(file, priv, f); - if (0 != retval) - return retval; - - width = f->fmt.pix.width; - height = f->fmt.pix.height; - field = f->fmt.pix.field; - - retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, - /* adjust_size */ 1, - /* adjust_crop */ 1); - if (0 != retval) - return retval; - - f->fmt.pix.field = field; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - - /* update our state informations */ - fh->fmt = fmt; - fh->cap.field = f->fmt.pix.field; - fh->cap.last = V4L2_FIELD_NONE; - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - btv->init.fmt = fmt; - btv->init.width = f->fmt.pix.width; - btv->init.height = f->fmt.pix.height; - - return 0; -} - -static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - - return setup_window_lock(fh, btv, &f->fmt.win, 1); -} - -static int bttv_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (0 == v4l2) - return -EINVAL; - - strlcpy(cap->driver, "bttv", sizeof(cap->driver)); - strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - if (no_overlay <= 0) - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - - /* - * No need to lock here: those vars are initialized during board - * probe and remains untouched during the rest of the driver lifecycle - */ - if (btv->has_saa6588) - cap->capabilities |= V4L2_CAP_RDS_CAPTURE; - if (btv->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; -} - -static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) -{ - int index = -1, i; - - for (i = 0; i < FORMATS; i++) { - if (formats[i].fourcc != -1) - index++; - if ((unsigned int)index == f->index) - break; - } - if (FORMATS == i) - return -EINVAL; - - f->pixelformat = formats[i].fourcc; - strlcpy(f->description, formats[i].name, sizeof(f->description)); - - return i; -} - -static int bttv_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - int rc = bttv_enum_fmt_cap_ovr(f); - - if (rc < 0) - return rc; - - return 0; -} - -static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - int rc; - - if (no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - - rc = bttv_enum_fmt_cap_ovr(f); - - if (rc < 0) - return rc; - - if (!(formats[rc].flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; - - return 0; -} - -static int bttv_g_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - *fb = btv->fbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - if (fh->ovfmt) - fb->fmt.pixelformat = fh->ovfmt->fourcc; - return 0; -} - -static int bttv_overlay(struct file *file, void *f, unsigned int on) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - struct bttv_buffer *new; - int retval = 0; - - if (on) { - /* verify args */ - if (unlikely(!btv->fbuf.base)) { - return -EINVAL; - } - if (unlikely(!fh->ov.setup_ok)) { - dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr); - retval = -EINVAL; - } - if (retval) - return retval; - } - - if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY)) - return -EBUSY; - - if (on) { - fh->ov.tvnorm = btv->tvnorm; - new = videobuf_sg_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - } else { - new = NULL; - } - - /* switch over */ - retval = bttv_switch_overlay(btv, fh, new); - return retval; -} - -static int bttv_s_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct bttv_format *fmt; - int retval; - - if (!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; - if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; - - retval = -EINVAL; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - __s32 width = fb->fmt.width; - __s32 height = fb->fmt.height; - - retval = limit_scaled_size_lock(fh, &width, &height, - V4L2_FIELD_INTERLACED, - /* width_mask */ ~3, - /* width_bias */ 2, - /* adjust_size */ 0, - /* adjust_crop */ 0); - if (0 != retval) - return retval; - } - - /* ok, accept it */ - btv->fbuf.base = fb->base; - btv->fbuf.fmt.width = fb->fmt.width; - btv->fbuf.fmt.height = fb->fmt.height; - if (0 != fb->fmt.bytesperline) - btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; - else - btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; - - retval = 0; - fh->ovfmt = fmt; - btv->init.ovfmt = fmt; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - fh->ov.w.left = 0; - fh->ov.w.top = 0; - fh->ov.w.width = fb->fmt.width; - fh->ov.w.height = fb->fmt.height; - btv->init.ov.w.width = fb->fmt.width; - btv->init.ov.w.height = fb->fmt.height; - kfree(fh->ov.clips); - fh->ov.clips = NULL; - fh->ov.nclips = 0; - - if (check_btres(fh, RESOURCE_OVERLAY)) { - struct bttv_buffer *new; - - new = videobuf_sg_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - retval = bttv_switch_overlay(btv, fh, new); - } - } - return retval; -} - -static int bttv_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct bttv_fh *fh = priv; - return videobuf_reqbufs(bttv_queue(fh), p); -} - -static int bttv_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct bttv_fh *fh = priv; - return videobuf_querybuf(bttv_queue(fh), b); -} - -static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int res = bttv_resource(fh); - - if (!check_alloc_btres_lock(btv, fh, res)) - return -EBUSY; - - return videobuf_qbuf(bttv_queue(fh), b); -} - -static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct bttv_fh *fh = priv; - return videobuf_dqbuf(bttv_queue(fh), b, - file->f_flags & O_NONBLOCK); -} - -static int bttv_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int res = bttv_resource(fh); - - if (!check_alloc_btres_lock(btv, fh, res)) - return -EBUSY; - return videobuf_streamon(bttv_queue(fh)); -} - - -static int bttv_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int retval; - int res = bttv_resource(fh); - - - retval = videobuf_streamoff(bttv_queue(fh)); - if (retval < 0) - return retval; - free_btres_lock(btv, fh, res); - return 0; -} - -static int bttv_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - const struct v4l2_queryctrl *ctrl; - - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - - if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) - *c = no_ctl; - else { - ctrl = ctrl_by_id(c->id); - - *c = (NULL != ctrl) ? *ctrl : no_ctl; - } - - return 0; -} - -static int bttv_g_parm(struct file *file, void *f, - struct v4l2_streamparm *parm) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id, - &parm->parm.capture.timeperframe); - - return 0; -} - -static int bttv_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (btv->tuner_type == TUNER_ABSENT) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - t->rxsubchans = V4L2_TUNER_SUB_MONO; - bttv_call_all(btv, tuner, g_tuner, t); - strcpy(t->name, "Television"); - t->capability = V4L2_TUNER_CAP_NORM; - t->type = V4L2_TUNER_ANALOG_TV; - if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) - t->signal = 0xffff; - - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 0); - - return 0; -} - -static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - *p = v4l2_prio_max(&btv->prio); - - return 0; -} - -static int bttv_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - int rc; - - rc = v4l2_prio_change(&btv->prio, &fh->prio, prio); - - return rc; -} - -static int bttv_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - - *cap = bttv_tvnorms[btv->tvnorm].cropcap; - - return 0; -} - -static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - - /* No fh->do_crop = 1; because btv->crop[1] may be - inconsistent with fh->width or fh->height and apps - do not expect a change here. */ - - crop->c = btv->crop[!!fh->do_crop].rect; - - return 0; -} - -static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct v4l2_rect *b; - int retval; - struct bttv_crop c; - __s32 b_left; - __s32 b_top; - __s32 b_right; - __s32 b_bottom; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - - /* Make sure tvnorm, vbi_end and the current cropping - parameters remain consistent until we're done. Note - read() may change vbi_end in check_alloc_btres_lock(). */ - retval = v4l2_prio_check(&btv->prio, fh->prio); - if (0 != retval) { - return retval; - } - - retval = -EBUSY; - - if (locked_btres(fh->btv, VIDEO_RESOURCES)) { - return retval; - } - - b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; - - b_left = b->left; - b_right = b_left + b->width; - b_bottom = b->top + b->height; - - b_top = max(b->top, btv->vbi_end); - if (b_top + 32 >= b_bottom) { - return retval; - } - - /* Min. scaled size 48 x 32. */ - c.rect.left = clamp(crop->c.left, b_left, b_right - 48); - c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); - - c.rect.width = clamp(crop->c.width, - 48, b_right - c.rect.left); - - c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); - /* Top and height must be a multiple of two. */ - c.rect.top = (c.rect.top + 1) & ~1; - - c.rect.height = clamp(crop->c.height, - 32, b_bottom - c.rect.top); - c.rect.height = (c.rect.height + 1) & ~1; - - bttv_crop_calc_limits(&c); - - btv->crop[1] = c; - - fh->do_crop = 1; - - if (fh->width < c.min_scaled_width) { - fh->width = c.min_scaled_width; - btv->init.width = c.min_scaled_width; - } else if (fh->width > c.max_scaled_width) { - fh->width = c.max_scaled_width; - btv->init.width = c.max_scaled_width; - } - - if (fh->height < c.min_scaled_height) { - fh->height = c.min_scaled_height; - btv->init.height = c.min_scaled_height; - } else if (fh->height > c.max_scaled_height) { - fh->height = c.max_scaled_height; - btv->init.height = c.max_scaled_height; - } - - return 0; -} - -static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name, "audio"); - return 0; -} - -static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - return 0; -} - -static ssize_t bttv_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct bttv_fh *fh = file->private_data; - int retval = 0; - - if (fh->btv->errors) - bttv_reinit_bt848(fh->btv); - dprintk("bttv%d: read count=%d type=%s\n", - fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]); - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) { - /* VIDEO_READ in use by another fh, - or VIDEO_STREAM by any fh. */ - return -EBUSY; - } - retval = videobuf_read_one(&fh->cap, data, count, ppos, - file->f_flags & O_NONBLOCK); - free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI)) - return -EBUSY; - retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - break; - default: - BUG(); - } - return retval; -} - -static unsigned int bttv_poll(struct file *file, poll_table *wait) -{ - struct bttv_fh *fh = file->private_data; - struct bttv_buffer *buf; - enum v4l2_field field; - unsigned int rc = POLLERR; - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbi, wait); - } - - if (check_btres(fh,RESOURCE_VIDEO_STREAM)) { - /* streaming capture */ - if (list_empty(&fh->cap.stream)) - goto err; - buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream); - } else { - /* read() capture */ - if (NULL == fh->cap.read_buf) { - /* need to capture a new frame */ - if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) - goto err; - fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize); - if (NULL == fh->cap.read_buf) - goto err; - fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR; - field = videobuf_next_field(&fh->cap); - if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) { - kfree (fh->cap.read_buf); - fh->cap.read_buf = NULL; - goto err; - } - fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); - fh->cap.read_off = 0; - } - buf = (struct bttv_buffer*)fh->cap.read_buf; - } - - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; -err: - return rc; -} - -static int bttv_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct bttv *btv = video_drvdata(file); - struct bttv_fh *fh; - enum v4l2_buf_type type = 0; - - dprintk(KERN_DEBUG "bttv: open dev=%s\n", video_device_node_name(vdev)); - - if (vdev->vfl_type == VFL_TYPE_GRABBER) { - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } else if (vdev->vfl_type == VFL_TYPE_VBI) { - type = V4L2_BUF_TYPE_VBI_CAPTURE; - } else { - WARN_ON(1); - return -ENODEV; - } - - dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", - btv->c.nr,v4l2_type_names[type]); - - /* allocate per filehandle data */ - fh = kmalloc(sizeof(*fh), GFP_KERNEL); - if (unlikely(!fh)) - return -ENOMEM; - file->private_data = fh; - - *fh = btv->init; - - fh->type = type; - fh->ov.setup_ok = 0; - - v4l2_prio_open(&btv->prio, &fh->prio); - - videobuf_queue_sg_init(&fh->cap, &bttv_video_qops, - &btv->c.pci->dev, &btv->s_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct bttv_buffer), - fh, &btv->lock); - videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops, - &btv->c.pci->dev, &btv->s_lock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct bttv_buffer), - fh, &btv->lock); - set_tvnorm(btv,btv->tvnorm); - set_input(btv, btv->input, btv->tvnorm); - - btv->users++; - - /* The V4L2 spec requires one global set of cropping parameters - which only change on request. These are stored in btv->crop[1]. - However for compatibility with V4L apps and cropping unaware - V4L2 apps we now reset the cropping parameters as seen through - this fh, which is to say VIDIOC_G_CROP and scaling limit checks - will use btv->crop[0], the default cropping parameters for the - current video standard, and VIDIOC_S_FMT will not implicitely - change the cropping parameters until VIDIOC_S_CROP has been - called. */ - fh->do_crop = !reset_crop; /* module parameter */ - - /* Likewise there should be one global set of VBI capture - parameters, but for compatibility with V4L apps and earlier - driver versions each fh has its own parameters. */ - bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm); - - bttv_field_count(btv); - return 0; -} - -static int bttv_release(struct file *file) -{ - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - - /* turn off overlay */ - if (check_btres(fh, RESOURCE_OVERLAY)) - bttv_switch_overlay(btv,fh,NULL); - - /* stop video capture */ - if (check_btres(fh, RESOURCE_VIDEO_STREAM)) { - videobuf_streamoff(&fh->cap); - free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM); - } - if (fh->cap.read_buf) { - buffer_release(&fh->cap,fh->cap.read_buf); - kfree(fh->cap.read_buf); - } - if (check_btres(fh, RESOURCE_VIDEO_READ)) { - free_btres_lock(btv, fh, RESOURCE_VIDEO_READ); - } - - /* stop vbi capture */ - if (check_btres(fh, RESOURCE_VBI)) { - videobuf_stop(&fh->vbi); - free_btres_lock(btv,fh,RESOURCE_VBI); - } - - /* free stuff */ - - videobuf_mmap_free(&fh->cap); - videobuf_mmap_free(&fh->vbi); - v4l2_prio_close(&btv->prio, fh->prio); - file->private_data = NULL; - kfree(fh); - - btv->users--; - bttv_field_count(btv); - - if (!btv->users) - audio_mute(btv, 1); - - return 0; -} - -static int -bttv_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct bttv_fh *fh = file->private_data; - - dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n", - fh->btv->c.nr, v4l2_type_names[fh->type], - vma->vm_start, vma->vm_end - vma->vm_start); - return videobuf_mmap_mapper(bttv_queue(fh),vma); -} - -static const struct v4l2_file_operations bttv_fops = -{ - .owner = THIS_MODULE, - .open = bttv_open, - .release = bttv_release, - .unlocked_ioctl = video_ioctl2, - .read = bttv_read, - .mmap = bttv_mmap, - .poll = bttv_poll, -}; - -static const struct v4l2_ioctl_ops bttv_ioctl_ops = { - .vidioc_querycap = bttv_querycap, - .vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = bttv_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = bttv_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_overlay = bttv_enum_fmt_vid_overlay, - .vidioc_g_fmt_vid_overlay = bttv_g_fmt_vid_overlay, - .vidioc_try_fmt_vid_overlay = bttv_try_fmt_vid_overlay, - .vidioc_s_fmt_vid_overlay = bttv_s_fmt_vid_overlay, - .vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap, - .vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap, - .vidioc_g_audio = bttv_g_audio, - .vidioc_s_audio = bttv_s_audio, - .vidioc_cropcap = bttv_cropcap, - .vidioc_reqbufs = bttv_reqbufs, - .vidioc_querybuf = bttv_querybuf, - .vidioc_qbuf = bttv_qbuf, - .vidioc_dqbuf = bttv_dqbuf, - .vidioc_s_std = bttv_s_std, - .vidioc_enum_input = bttv_enum_input, - .vidioc_g_input = bttv_g_input, - .vidioc_s_input = bttv_s_input, - .vidioc_queryctrl = bttv_queryctrl, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, - .vidioc_streamon = bttv_streamon, - .vidioc_streamoff = bttv_streamoff, - .vidioc_g_tuner = bttv_g_tuner, - .vidioc_s_tuner = bttv_s_tuner, - .vidioc_g_crop = bttv_g_crop, - .vidioc_s_crop = bttv_s_crop, - .vidioc_g_fbuf = bttv_g_fbuf, - .vidioc_s_fbuf = bttv_s_fbuf, - .vidioc_overlay = bttv_overlay, - .vidioc_g_priority = bttv_g_priority, - .vidioc_s_priority = bttv_s_priority, - .vidioc_g_parm = bttv_g_parm, - .vidioc_g_frequency = bttv_g_frequency, - .vidioc_s_frequency = bttv_s_frequency, - .vidioc_log_status = bttv_log_status, - .vidioc_querystd = bttv_querystd, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = bttv_g_register, - .vidioc_s_register = bttv_s_register, -#endif -}; - -static struct video_device bttv_video_template = { - .fops = &bttv_fops, - .ioctl_ops = &bttv_ioctl_ops, - .tvnorms = BTTV_NORMS, - .current_norm = V4L2_STD_PAL, -}; - -/* ----------------------------------------------------------------------- */ -/* radio interface */ - -static int radio_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct bttv *btv = video_drvdata(file); - struct bttv_fh *fh; - - dprintk("bttv: open dev=%s\n", video_device_node_name(vdev)); - - dprintk("bttv%d: open called (radio)\n",btv->c.nr); - - /* allocate per filehandle data */ - fh = kmalloc(sizeof(*fh), GFP_KERNEL); - if (unlikely(!fh)) - return -ENOMEM; - file->private_data = fh; - *fh = btv->init; - - v4l2_prio_open(&btv->prio, &fh->prio); - - btv->radio_user++; - - bttv_call_all(btv, tuner, s_radio); - audio_input(btv,TVAUDIO_INPUT_RADIO); - - return 0; -} - -static int radio_release(struct file *file) -{ - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - struct saa6588_command cmd; - - v4l2_prio_close(&btv->prio, fh->prio); - file->private_data = NULL; - kfree(fh); - - btv->radio_user--; - - bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd); - - return 0; -} - -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - strcpy(cap->driver, "bttv"); - strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (btv->tuner_type == TUNER_ABSENT) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - bttv_call_all(btv, tuner, g_tuner, t); - - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 0); - - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name, "Radio"); - - return 0; -} - -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (0 != t->index) - return -EINVAL; - - bttv_call_all(btv, tuner, g_tuner, t); - return 0; -} - -static int radio_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - return 0; -} - -static int radio_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (unlikely(i)) - return -EINVAL; - - return 0; -} - -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - return 0; -} - -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctl; - - return 0; -} - -static int radio_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static ssize_t radio_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - struct saa6588_command cmd; - cmd.block_count = count/3; - cmd.buffer = data; - cmd.instance = file; - cmd.result = -ENODEV; - - bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd); - - return cmd.result; -} - -static unsigned int radio_poll(struct file *file, poll_table *wait) -{ - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - struct saa6588_command cmd; - cmd.instance = file; - cmd.event_list = wait; - cmd.result = -ENODEV; - bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd); - - return cmd.result; -} - -static const struct v4l2_file_operations radio_fops = -{ - .owner = THIS_MODULE, - .open = radio_open, - .read = radio_read, - .release = radio_release, - .unlocked_ioctl = video_ioctl2, - .poll = radio_poll, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_s_std = radio_s_std, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_input = radio_g_input, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, - .vidioc_g_frequency = bttv_g_frequency, - .vidioc_s_frequency = bttv_s_frequency, -}; - -static struct video_device radio_template = { - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, -}; - -/* ----------------------------------------------------------------------- */ -/* some debug code */ - -static int bttv_risc_decode(u32 risc) -{ - static char *instr[16] = { - [ BT848_RISC_WRITE >> 28 ] = "write", - [ BT848_RISC_SKIP >> 28 ] = "skip", - [ BT848_RISC_WRITEC >> 28 ] = "writec", - [ BT848_RISC_JUMP >> 28 ] = "jump", - [ BT848_RISC_SYNC >> 28 ] = "sync", - [ BT848_RISC_WRITE123 >> 28 ] = "write123", - [ BT848_RISC_SKIP123 >> 28 ] = "skip123", - [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23", - }; - static int incr[16] = { - [ BT848_RISC_WRITE >> 28 ] = 2, - [ BT848_RISC_JUMP >> 28 ] = 2, - [ BT848_RISC_SYNC >> 28 ] = 2, - [ BT848_RISC_WRITE123 >> 28 ] = 5, - [ BT848_RISC_SKIP123 >> 28 ] = 2, - [ BT848_RISC_WRITE1S23 >> 28 ] = 3, - }; - static char *bits[] = { - "be0", "be1", "be2", "be3/resync", - "set0", "set1", "set2", "set3", - "clr0", "clr1", "clr2", "clr3", - "irq", "res", "eol", "sol", - }; - int i; - - printk("0x%08x [ %s", risc, - instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); - for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) - if (risc & (1 << (i + 12))) - printk(" %s",bits[i]); - printk(" count=%d ]\n", risc & 0xfff); - return incr[risc >> 28] ? incr[risc >> 28] : 1; -} - -static void bttv_risc_disasm(struct bttv *btv, - struct btcx_riscmem *risc) -{ - unsigned int i,j,n; - - printk("%s: risc disasm: %p [dma=0x%08lx]\n", - btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma); - for (i = 0; i < (risc->size >> 2); i += n) { - printk("%s: 0x%lx: ", btv->c.v4l2_dev.name, - (unsigned long)(risc->dma + (i<<2))); - n = bttv_risc_decode(le32_to_cpu(risc->cpu[i])); - for (j = 1; j < n; j++) - printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n", - btv->c.v4l2_dev.name, (unsigned long)(risc->dma + ((i+j)<<2)), - risc->cpu[i+j], j); - if (0 == risc->cpu[i]) - break; - } -} - -static void bttv_print_riscaddr(struct bttv *btv) -{ - printk(" main: %08Lx\n", - (unsigned long long)btv->main.dma); - printk(" vbi : o=%08Lx e=%08Lx\n", - btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, - btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); - printk(" cap : o=%08Lx e=%08Lx\n", - btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, - btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); - printk(" scr : o=%08Lx e=%08Lx\n", - btv->screen ? (unsigned long long)btv->screen->top.dma : 0, - btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); - bttv_risc_disasm(btv, &btv->main); -} - -/* ----------------------------------------------------------------------- */ -/* irq handler */ - -static char *irq_name[] = { - "FMTCHG", // format change detected (525 vs. 625) - "VSYNC", // vertical sync (new field) - "HSYNC", // horizontal sync - "OFLOW", // chroma/luma AGC overflow - "HLOCK", // horizontal lock changed - "VPRES", // video presence changed - "6", "7", - "I2CDONE", // hw irc operation finished - "GPINT", // gpio port triggered irq - "10", - "RISCI", // risc instruction triggered irq - "FBUS", // pixel data fifo dropped data (high pci bus latencies) - "FTRGT", // pixel data fifo overrun - "FDSR", // fifo data stream resyncronisation - "PPERR", // parity error (data transfer) - "RIPERR", // parity error (read risc instructions) - "PABORT", // pci abort - "OCERR", // risc instruction error - "SCERR", // syncronisation error -}; - -static void bttv_print_irqbits(u32 print, u32 mark) -{ - unsigned int i; - - printk("bits:"); - for (i = 0; i < ARRAY_SIZE(irq_name); i++) { - if (print & (1 << i)) - printk(" %s",irq_name[i]); - if (mark & (1 << i)) - printk("*"); - } -} - -static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc) -{ - printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", - btv->c.nr, - (unsigned long)btv->main.dma, - (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]), - (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]), - (unsigned long)rc); - - if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) { - printk("bttv%d: Oh, there (temporarely?) is no input signal. " - "Ok, then this is harmless, don't worry ;)\n", - btv->c.nr); - return; - } - printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n", - btv->c.nr); - printk("bttv%d: Lets try to catch the culpit red-handed ...\n", - btv->c.nr); - dump_stack(); -} - -static int -bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set) -{ - struct bttv_buffer *item; - - memset(set,0,sizeof(*set)); - - /* capture request ? */ - if (!list_empty(&btv->capture)) { - set->frame_irq = 1; - item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); - if (V4L2_FIELD_HAS_TOP(item->vb.field)) - set->top = item; - if (V4L2_FIELD_HAS_BOTTOM(item->vb.field)) - set->bottom = item; - - /* capture request for other field ? */ - if (!V4L2_FIELD_HAS_BOTH(item->vb.field) && - (item->vb.queue.next != &btv->capture)) { - item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue); - /* Mike Isely - Only check - * and set up the bottom field in the logic - * below. Don't ever do the top field. This - * of course means that if we set up the - * bottom field in the above code that we'll - * actually skip a field. But that's OK. - * Having processed only a single buffer this - * time, then the next time around the first - * available buffer should be for a top field. - * That will then cause us here to set up a - * top then a bottom field in the normal way. - * The alternative to this understanding is - * that we set up the second available buffer - * as a top field, but that's out of order - * since this driver always processes the top - * field first - the effect will be the two - * buffers being returned in the wrong order, - * with the second buffer also being delayed - * by one field time (owing to the fifo nature - * of videobuf). Worse still, we'll be stuck - * doing fields out of order now every time - * until something else causes a field to be - * dropped. By effectively forcing a field to - * drop this way then we always get back into - * sync within a single frame time. (Out of - * order fields can screw up deinterlacing - * algorithms.) */ - if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) { - if (NULL == set->bottom && - V4L2_FIELD_BOTTOM == item->vb.field) { - set->bottom = item; - } - if (NULL != set->top && NULL != set->bottom) - set->top_irq = 2; - } - } - } - - /* screen overlay ? */ - if (NULL != btv->screen) { - if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) { - if (NULL == set->top && NULL == set->bottom) { - set->top = btv->screen; - set->bottom = btv->screen; - } - } else { - if (V4L2_FIELD_TOP == btv->screen->vb.field && - NULL == set->top) { - set->top = btv->screen; - } - if (V4L2_FIELD_BOTTOM == btv->screen->vb.field && - NULL == set->bottom) { - set->bottom = btv->screen; - } - } - } - - dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n", - btv->c.nr,set->top, set->bottom, - btv->screen,set->frame_irq,set->top_irq); - return 0; -} - -static void -bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, - struct bttv_buffer_set *curr, unsigned int state) -{ - struct timeval ts; - - do_gettimeofday(&ts); - - if (wakeup->top == wakeup->bottom) { - if (NULL != wakeup->top && curr->top != wakeup->top) { - if (irq_debug > 1) - printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top); - wakeup->top->vb.ts = ts; - wakeup->top->vb.field_count = btv->field_count; - wakeup->top->vb.state = state; - wake_up(&wakeup->top->vb.done); - } - } else { - if (NULL != wakeup->top && curr->top != wakeup->top) { - if (irq_debug > 1) - printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top); - wakeup->top->vb.ts = ts; - wakeup->top->vb.field_count = btv->field_count; - wakeup->top->vb.state = state; - wake_up(&wakeup->top->vb.done); - } - if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) { - if (irq_debug > 1) - printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom); - wakeup->bottom->vb.ts = ts; - wakeup->bottom->vb.field_count = btv->field_count; - wakeup->bottom->vb.state = state; - wake_up(&wakeup->bottom->vb.done); - } - } -} - -static void -bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup, - unsigned int state) -{ - struct timeval ts; - - if (NULL == wakeup) - return; - - do_gettimeofday(&ts); - wakeup->vb.ts = ts; - wakeup->vb.field_count = btv->field_count; - wakeup->vb.state = state; - wake_up(&wakeup->vb.done); -} - -static void bttv_irq_timeout(unsigned long data) -{ - struct bttv *btv = (struct bttv *)data; - struct bttv_buffer_set old,new; - struct bttv_buffer *ovbi; - struct bttv_buffer *item; - unsigned long flags; - - if (bttv_verbose) { - printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ", - btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total, - btread(BT848_RISC_COUNT)); - bttv_print_irqbits(btread(BT848_INT_STAT),0); - printk("\n"); - } - - spin_lock_irqsave(&btv->s_lock,flags); - - /* deactivate stuff */ - memset(&new,0,sizeof(new)); - old = btv->curr; - ovbi = btv->cvbi; - btv->curr = new; - btv->cvbi = NULL; - btv->loop_irq = 0; - bttv_buffer_activate_video(btv, &new); - bttv_buffer_activate_vbi(btv, NULL); - bttv_set_dma(btv, 0); - - /* wake up */ - bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR); - bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR); - - /* cancel all outstanding capture / vbi requests */ - while (!list_empty(&btv->capture)) { - item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); - list_del(&item->vb.queue); - item->vb.state = VIDEOBUF_ERROR; - wake_up(&item->vb.done); - } - while (!list_empty(&btv->vcapture)) { - item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); - list_del(&item->vb.queue); - item->vb.state = VIDEOBUF_ERROR; - wake_up(&item->vb.done); - } - - btv->errors++; - spin_unlock_irqrestore(&btv->s_lock,flags); -} - -static void -bttv_irq_wakeup_top(struct bttv *btv) -{ - struct bttv_buffer *wakeup = btv->curr.top; - - if (NULL == wakeup) - return; - - spin_lock(&btv->s_lock); - btv->curr.top_irq = 0; - btv->curr.top = NULL; - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); - - do_gettimeofday(&wakeup->vb.ts); - wakeup->vb.field_count = btv->field_count; - wakeup->vb.state = VIDEOBUF_DONE; - wake_up(&wakeup->vb.done); - spin_unlock(&btv->s_lock); -} - -static inline int is_active(struct btcx_riscmem *risc, u32 rc) -{ - if (rc < risc->dma) - return 0; - if (rc > risc->dma + risc->size) - return 0; - return 1; -} - -static void -bttv_irq_switch_video(struct bttv *btv) -{ - struct bttv_buffer_set new; - struct bttv_buffer_set old; - dma_addr_t rc; - - spin_lock(&btv->s_lock); - - /* new buffer set */ - bttv_irq_next_video(btv, &new); - rc = btread(BT848_RISC_COUNT); - if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) || - (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) { - btv->framedrop++; - if (debug_latency) - bttv_irq_debug_low_latency(btv, rc); - spin_unlock(&btv->s_lock); - return; - } - - /* switch over */ - old = btv->curr; - btv->curr = new; - btv->loop_irq &= ~1; - bttv_buffer_activate_video(btv, &new); - bttv_set_dma(btv, 0); - - /* switch input */ - if (UNSET != btv->new_input) { - video_mux(btv,btv->new_input); - btv->new_input = UNSET; - } - - /* wake up finished buffers */ - bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE); - spin_unlock(&btv->s_lock); -} - -static void -bttv_irq_switch_vbi(struct bttv *btv) -{ - struct bttv_buffer *new = NULL; - struct bttv_buffer *old; - u32 rc; - - spin_lock(&btv->s_lock); - - if (!list_empty(&btv->vcapture)) - new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); - old = btv->cvbi; - - rc = btread(BT848_RISC_COUNT); - if (NULL != old && (is_active(&old->top, rc) || - is_active(&old->bottom, rc))) { - btv->framedrop++; - if (debug_latency) - bttv_irq_debug_low_latency(btv, rc); - spin_unlock(&btv->s_lock); - return; - } - - /* switch */ - btv->cvbi = new; - btv->loop_irq &= ~4; - bttv_buffer_activate_vbi(btv, new); - bttv_set_dma(btv, 0); - - bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE); - spin_unlock(&btv->s_lock); -} - -static irqreturn_t bttv_irq(int irq, void *dev_id) -{ - u32 stat,astat; - u32 dstat; - int count; - struct bttv *btv; - int handled = 0; - - btv=(struct bttv *)dev_id; - - count=0; - while (1) { - /* get/clear interrupt status bits */ - stat=btread(BT848_INT_STAT); - astat=stat&btread(BT848_INT_MASK); - if (!astat) - break; - handled = 1; - btwrite(stat,BT848_INT_STAT); - - /* get device status bits */ - dstat=btread(BT848_DSTATUS); - - if (irq_debug) { - printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d " - "riscs=%x, riscc=%08x, ", - btv->c.nr, count, btv->field_count, - stat>>28, btread(BT848_RISC_COUNT)); - bttv_print_irqbits(stat,astat); - if (stat & BT848_INT_HLOCK) - printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC) - ? "yes" : "no"); - if (stat & BT848_INT_VPRES) - printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES) - ? "yes" : "no"); - if (stat & BT848_INT_FMTCHG) - printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML) - ? "625" : "525"); - printk("\n"); - } - - if (astat&BT848_INT_VSYNC) - btv->field_count++; - - if ((astat & BT848_INT_GPINT) && btv->remote) { - bttv_input_irq(btv); - } - - if (astat & BT848_INT_I2CDONE) { - btv->i2c_done = stat; - wake_up(&btv->i2c_queue); - } - - if ((astat & BT848_INT_RISCI) && (stat & (4<<28))) - bttv_irq_switch_vbi(btv); - - if ((astat & BT848_INT_RISCI) && (stat & (2<<28))) - bttv_irq_wakeup_top(btv); - - if ((astat & BT848_INT_RISCI) && (stat & (1<<28))) - bttv_irq_switch_video(btv); - - if ((astat & BT848_INT_HLOCK) && btv->opt_automute) - audio_mute(btv, btv->mute); /* trigger automute */ - - if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) { - printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr, - (astat & BT848_INT_SCERR) ? "SCERR" : "", - (astat & BT848_INT_OCERR) ? "OCERR" : "", - btread(BT848_RISC_COUNT)); - bttv_print_irqbits(stat,astat); - printk("\n"); - if (bttv_debug) - bttv_print_riscaddr(btv); - } - if (fdsr && astat & BT848_INT_FDSR) { - printk(KERN_INFO "bttv%d: FDSR @ %08x\n", - btv->c.nr,btread(BT848_RISC_COUNT)); - if (bttv_debug) - bttv_print_riscaddr(btv); - } - - count++; - if (count > 4) { - - if (count > 8 || !(astat & BT848_INT_GPINT)) { - btwrite(0, BT848_INT_MASK); - - printk(KERN_ERR - "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr); - } else { - printk(KERN_ERR - "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr); - - btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT), - BT848_INT_MASK); - }; - - bttv_print_irqbits(stat,astat); - - printk("]\n"); - } - } - btv->irq_total++; - if (handled) - btv->irq_me++; - return IRQ_RETVAL(handled); -} - - -/* ----------------------------------------------------------------------- */ -/* initialitation */ - -static struct video_device *vdev_init(struct bttv *btv, - const struct video_device *template, - const char *type_name) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->v4l2_dev = &btv->c.v4l2_dev; - vfd->release = video_device_release; - vfd->debug = bttv_debug; - video_set_drvdata(vfd, btv); - snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", - btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", - type_name, bttv_tvcards[btv->c.type].name); - return vfd; -} - -static void bttv_unregister_video(struct bttv *btv) -{ - if (btv->video_dev) { - if (video_is_registered(btv->video_dev)) - video_unregister_device(btv->video_dev); - else - video_device_release(btv->video_dev); - btv->video_dev = NULL; - } - if (btv->vbi_dev) { - if (video_is_registered(btv->vbi_dev)) - video_unregister_device(btv->vbi_dev); - else - video_device_release(btv->vbi_dev); - btv->vbi_dev = NULL; - } - if (btv->radio_dev) { - if (video_is_registered(btv->radio_dev)) - video_unregister_device(btv->radio_dev); - else - video_device_release(btv->radio_dev); - btv->radio_dev = NULL; - } -} - -/* register video4linux devices */ -static int __devinit bttv_register_video(struct bttv *btv) -{ - if (no_overlay > 0) - printk("bttv: Overlay support disabled.\n"); - - /* video */ - btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); - - if (NULL == btv->video_dev) - goto err; - if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, - video_nr[btv->c.nr]) < 0) - goto err; - printk(KERN_INFO "bttv%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->video_dev)); - if (device_create_file(&btv->video_dev->dev, - &dev_attr_card)<0) { - printk(KERN_ERR "bttv%d: device_create_file 'card' " - "failed\n", btv->c.nr); - goto err; - } - - /* vbi */ - btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi"); - - if (NULL == btv->vbi_dev) - goto err; - if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, - vbi_nr[btv->c.nr]) < 0) - goto err; - printk(KERN_INFO "bttv%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->vbi_dev)); - - if (!btv->has_radio) - return 0; - /* radio */ - btv->radio_dev = vdev_init(btv, &radio_template, "radio"); - if (NULL == btv->radio_dev) - goto err; - if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, - radio_nr[btv->c.nr]) < 0) - goto err; - printk(KERN_INFO "bttv%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->radio_dev)); - - /* all done */ - return 0; - - err: - bttv_unregister_video(btv); - return -1; -} - - -/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ -/* response on cards with no firmware is not enabled by OF */ -static void pci_set_command(struct pci_dev *dev) -{ -#if defined(__powerpc__) - unsigned int cmd; - - pci_read_config_dword(dev, PCI_COMMAND, &cmd); - cmd = (cmd | PCI_COMMAND_MEMORY ); - pci_write_config_dword(dev, PCI_COMMAND, cmd); -#endif -} - -static int __devinit bttv_probe(struct pci_dev *dev, - const struct pci_device_id *pci_id) -{ - int result; - unsigned char lat; - struct bttv *btv; - - if (bttv_num == BTTV_MAX) - return -ENOMEM; - printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); - bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL); - if (btv == NULL) { - printk(KERN_ERR "bttv: out of memory.\n"); - return -ENOMEM; - } - btv->c.nr = bttv_num; - snprintf(btv->c.v4l2_dev.name, sizeof(btv->c.v4l2_dev.name), - "bttv%d", btv->c.nr); - - /* initialize structs / fill in defaults */ - mutex_init(&btv->lock); - spin_lock_init(&btv->s_lock); - spin_lock_init(&btv->gpio_lock); - init_waitqueue_head(&btv->i2c_queue); - INIT_LIST_HEAD(&btv->c.subs); - INIT_LIST_HEAD(&btv->capture); - INIT_LIST_HEAD(&btv->vcapture); - v4l2_prio_init(&btv->prio); - - init_timer(&btv->timeout); - btv->timeout.function = bttv_irq_timeout; - btv->timeout.data = (unsigned long)btv; - - btv->i2c_rc = -1; - btv->tuner_type = UNSET; - btv->new_input = UNSET; - btv->has_radio=radio[btv->c.nr]; - - /* pci stuff (init, get irq/mmio, ... */ - btv->c.pci = dev; - btv->id = dev->device; - if (pci_enable_device(dev)) { - printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->c.nr); - return -EIO; - } - if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "bttv%d: No suitable DMA available.\n", - btv->c.nr); - return -EIO; - } - if (!request_mem_region(pci_resource_start(dev,0), - pci_resource_len(dev,0), - btv->c.v4l2_dev.name)) { - printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n", - btv->c.nr, - (unsigned long long)pci_resource_start(dev,0)); - return -EBUSY; - } - pci_set_master(dev); - pci_set_command(dev); - - result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev); - if (result < 0) { - printk(KERN_WARNING "bttv%d: v4l2_device_register() failed\n", btv->c.nr); - goto fail0; - } - - pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ", - bttv_num,btv->id, btv->revision, pci_name(dev)); - printk("irq: %d, latency: %d, mmio: 0x%llx\n", - btv->c.pci->irq, lat, - (unsigned long long)pci_resource_start(dev,0)); - schedule(); - - btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000); - if (NULL == btv->bt848_mmio) { - printk("bttv%d: ioremap() failed\n", btv->c.nr); - result = -EIO; - goto fail1; - } - - /* identify card */ - bttv_idcard(btv); - - /* disable irqs, register irq handler */ - btwrite(0, BT848_INT_MASK); - result = request_irq(btv->c.pci->irq, bttv_irq, - IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv); - if (result < 0) { - printk(KERN_ERR "bttv%d: can't get IRQ %d\n", - bttv_num,btv->c.pci->irq); - goto fail1; - } - - if (0 != bttv_handle_chipset(btv)) { - result = -EIO; - goto fail2; - } - - /* init options from insmod args */ - btv->opt_combfilter = combfilter; - btv->opt_lumafilter = lumafilter; - btv->opt_automute = automute; - btv->opt_chroma_agc = chroma_agc; - btv->opt_adc_crush = adc_crush; - btv->opt_vcr_hack = vcr_hack; - btv->opt_whitecrush_upper = whitecrush_upper; - btv->opt_whitecrush_lower = whitecrush_lower; - btv->opt_uv_ratio = uv_ratio; - btv->opt_full_luma_range = full_luma_range; - btv->opt_coring = coring; - - /* fill struct bttv with some useful defaults */ - btv->init.btv = btv; - btv->init.ov.w.width = 320; - btv->init.ov.w.height = 240; - btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - btv->init.width = 320; - btv->init.height = 240; - btv->input = 0; - - /* initialize hardware */ - if (bttv_gpio) - bttv_gpio_tracking(btv,"pre-init"); - - bttv_risc_init_main(btv); - init_bt848(btv); - - /* gpio */ - btwrite(0x00, BT848_GPIO_REG_INP); - btwrite(0x00, BT848_GPIO_OUT_EN); - if (bttv_verbose) - bttv_gpio_tracking(btv,"init"); - - /* needs to be done before i2c is registered */ - bttv_init_card1(btv); - - /* register i2c + gpio */ - init_bttv_i2c(btv); - - /* some card-specific stuff (needs working i2c) */ - bttv_init_card2(btv); - bttv_init_tuner(btv); - init_irqreg(btv); - - /* register video4linux + input */ - if (!bttv_tvcards[btv->c.type].no_video) { - bttv_register_video(btv); - bt848_bright(btv,32768); - bt848_contrast(btv,32768); - bt848_hue(btv,32768); - bt848_sat(btv,32768); - audio_mute(btv, 1); - set_input(btv, 0, btv->tvnorm); - bttv_crop_reset(&btv->crop[0], btv->tvnorm); - btv->crop[1] = btv->crop[0]; /* current = default */ - disclaim_vbi_lines(btv); - disclaim_video_lines(btv); - } - - /* add subdevices and autoload dvb-bt8xx if needed */ - if (bttv_tvcards[btv->c.type].has_dvb) { - bttv_sub_add_device(&btv->c, "dvb"); - request_modules(btv); - } - - if (!disable_ir) { - init_bttv_i2c_ir(btv); - bttv_input_init(btv); - } - - /* everything is fine */ - bttv_num++; - return 0; - -fail2: - free_irq(btv->c.pci->irq,btv); - -fail1: - v4l2_device_unregister(&btv->c.v4l2_dev); - -fail0: - if (btv->bt848_mmio) - iounmap(btv->bt848_mmio); - release_mem_region(pci_resource_start(btv->c.pci,0), - pci_resource_len(btv->c.pci,0)); - return result; -} - -static void __devexit bttv_remove(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct bttv *btv = to_bttv(v4l2_dev); - - if (bttv_verbose) - printk("bttv%d: unloading\n",btv->c.nr); - - if (bttv_tvcards[btv->c.type].has_dvb) - flush_request_modules(btv); - - /* shutdown everything (DMA+IRQs) */ - btand(~15, BT848_GPIO_DMA_CTL); - btwrite(0, BT848_INT_MASK); - btwrite(~0x0, BT848_INT_STAT); - btwrite(0x0, BT848_GPIO_OUT_EN); - if (bttv_gpio) - bttv_gpio_tracking(btv,"cleanup"); - - /* tell gpio modules we are leaving ... */ - btv->shutdown=1; - bttv_input_fini(btv); - bttv_sub_del_devices(&btv->c); - - /* unregister i2c_bus + input */ - fini_bttv_i2c(btv); - - /* unregister video4linux */ - bttv_unregister_video(btv); - - /* free allocated memory */ - btcx_riscmem_free(btv->c.pci,&btv->main); - - /* free ressources */ - free_irq(btv->c.pci->irq,btv); - iounmap(btv->bt848_mmio); - release_mem_region(pci_resource_start(btv->c.pci,0), - pci_resource_len(btv->c.pci,0)); - - v4l2_device_unregister(&btv->c.v4l2_dev); - bttvs[btv->c.nr] = NULL; - kfree(btv); - - return; -} - -#ifdef CONFIG_PM -static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct bttv *btv = to_bttv(v4l2_dev); - struct bttv_buffer_set idle; - unsigned long flags; - - dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event); - - /* stop dma + irqs */ - spin_lock_irqsave(&btv->s_lock,flags); - memset(&idle, 0, sizeof(idle)); - btv->state.video = btv->curr; - btv->state.vbi = btv->cvbi; - btv->state.loop_irq = btv->loop_irq; - btv->curr = idle; - btv->loop_irq = 0; - bttv_buffer_activate_video(btv, &idle); - bttv_buffer_activate_vbi(btv, NULL); - bttv_set_dma(btv, 0); - btwrite(0, BT848_INT_MASK); - spin_unlock_irqrestore(&btv->s_lock,flags); - - /* save bt878 state */ - btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN); - btv->state.gpio_data = gpio_read(); - - /* save pci state */ - pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { - pci_disable_device(pci_dev); - btv->state.disabled = 1; - } - return 0; -} - -static int bttv_resume(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct bttv *btv = to_bttv(v4l2_dev); - unsigned long flags; - int err; - - dprintk("bttv%d: resume\n", btv->c.nr); - - /* restore pci state */ - if (btv->state.disabled) { - err=pci_enable_device(pci_dev); - if (err) { - printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->c.nr); - return err; - } - btv->state.disabled = 0; - } - err=pci_set_power_state(pci_dev, PCI_D0); - if (err) { - pci_disable_device(pci_dev); - printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->c.nr); - btv->state.disabled = 1; - return err; - } - - pci_restore_state(pci_dev); - - /* restore bt878 state */ - bttv_reinit_bt848(btv); - gpio_inout(0xffffff, btv->state.gpio_enable); - gpio_write(btv->state.gpio_data); - - /* restart dma */ - spin_lock_irqsave(&btv->s_lock,flags); - btv->curr = btv->state.video; - btv->cvbi = btv->state.vbi; - btv->loop_irq = btv->state.loop_irq; - bttv_buffer_activate_video(btv, &btv->curr); - bttv_buffer_activate_vbi(btv, btv->cvbi); - bttv_set_dma(btv, 0); - spin_unlock_irqrestore(&btv->s_lock,flags); - return 0; -} -#endif - -static struct pci_device_id bttv_pci_tbl[] = { - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); - -static struct pci_driver bttv_pci_driver = { - .name = "bttv", - .id_table = bttv_pci_tbl, - .probe = bttv_probe, - .remove = __devexit_p(bttv_remove), -#ifdef CONFIG_PM - .suspend = bttv_suspend, - .resume = bttv_resume, -#endif -}; - -static int __init bttv_init_module(void) -{ - int ret; - - bttv_num = 0; - - printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", - (BTTV_VERSION_CODE >> 16) & 0xff, - (BTTV_VERSION_CODE >> 8) & 0xff, - BTTV_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) - gbuffers = 2; - if (gbufsize > BTTV_MAX_FBUF) - gbufsize = BTTV_MAX_FBUF; - gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; - if (bttv_verbose) - printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n", - gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT); - - bttv_check_chipset(); - - ret = bus_register(&bttv_sub_bus_type); - if (ret < 0) { - printk(KERN_WARNING "bttv: bus_register error: %d\n", ret); - return ret; - } - ret = pci_register_driver(&bttv_pci_driver); - if (ret < 0) - bus_unregister(&bttv_sub_bus_type); - - return ret; -} - -static void __exit bttv_cleanup_module(void) -{ - pci_unregister_driver(&bttv_pci_driver); - bus_unregister(&bttv_sub_bus_type); -} - -module_init(bttv_init_module); -module_exit(bttv_cleanup_module); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-gpio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-gpio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-gpio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-gpio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -/* - - bttv-gpio.c -- gpio sub drivers - - sysfs-based sub driver interface for bttv - mainly intented for gpio access - - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999-2003 Gerd Knorr - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include - -#include "bttvp.h" - -/* ----------------------------------------------------------------------- */ -/* internal: the bttv "bus" */ - -static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv) -{ - struct bttv_sub_driver *sub = to_bttv_sub_drv(drv); - int len = strlen(sub->wanted); - - if (0 == strncmp(dev_name(dev), sub->wanted, len)) - return 1; - return 0; -} - -static int bttv_sub_probe(struct device *dev) -{ - struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); - struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); - - return sub->probe ? sub->probe(sdev) : -ENODEV; -} - -static int bttv_sub_remove(struct device *dev) -{ - struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); - struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); - - if (sub->remove) - sub->remove(sdev); - return 0; -} - -struct bus_type bttv_sub_bus_type = { - .name = "bttv-sub", - .match = &bttv_sub_bus_match, - .probe = bttv_sub_probe, - .remove = bttv_sub_remove, -}; - -static void release_sub_device(struct device *dev) -{ - struct bttv_sub_device *sub = to_bttv_sub_dev(dev); - kfree(sub); -} - -int bttv_sub_add_device(struct bttv_core *core, char *name) -{ - struct bttv_sub_device *sub; - int err; - - sub = kzalloc(sizeof(*sub),GFP_KERNEL); - if (NULL == sub) - return -ENOMEM; - - sub->core = core; - sub->dev.parent = &core->pci->dev; - sub->dev.bus = &bttv_sub_bus_type; - sub->dev.release = release_sub_device; - dev_set_name(&sub->dev, "%s%d", name, core->nr); - - err = device_register(&sub->dev); - if (0 != err) { - kfree(sub); - return err; - } - printk("bttv%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); - list_add_tail(&sub->list,&core->subs); - return 0; -} - -int bttv_sub_del_devices(struct bttv_core *core) -{ - struct bttv_sub_device *sub, *save; - - list_for_each_entry_safe(sub, save, &core->subs, list) { - list_del(&sub->list); - device_unregister(&sub->dev); - } - return 0; -} - -/* ----------------------------------------------------------------------- */ -/* external: sub-driver register/unregister */ - -int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted) -{ - sub->drv.bus = &bttv_sub_bus_type; - snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted); - return driver_register(&sub->drv); -} -EXPORT_SYMBOL(bttv_sub_register); - -int bttv_sub_unregister(struct bttv_sub_driver *sub) -{ - driver_unregister(&sub->drv); - return 0; -} -EXPORT_SYMBOL(bttv_sub_unregister); - -/* ----------------------------------------------------------------------- */ -/* external: gpio access functions */ - -void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) -{ - struct bttv *btv = container_of(core, struct bttv, c); - unsigned long flags; - u32 data; - - spin_lock_irqsave(&btv->gpio_lock,flags); - data = btread(BT848_GPIO_OUT_EN); - data = data & ~mask; - data = data | (mask & outbits); - btwrite(data,BT848_GPIO_OUT_EN); - spin_unlock_irqrestore(&btv->gpio_lock,flags); -} - -u32 bttv_gpio_read(struct bttv_core *core) -{ - struct bttv *btv = container_of(core, struct bttv, c); - u32 value; - - value = btread(BT848_GPIO_DATA); - return value; -} - -void bttv_gpio_write(struct bttv_core *core, u32 value) -{ - struct bttv *btv = container_of(core, struct bttv, c); - - btwrite(value,BT848_GPIO_DATA); -} - -void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) -{ - struct bttv *btv = container_of(core, struct bttv, c); - unsigned long flags; - u32 data; - - spin_lock_irqsave(&btv->gpio_lock,flags); - data = btread(BT848_GPIO_DATA); - data = data & ~mask; - data = data | (mask & bits); - btwrite(data,BT848_GPIO_DATA); - spin_unlock_irqrestore(&btv->gpio_lock,flags); -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,376 +0,0 @@ -/* - * - * bttv - Bt848 frame grabber driver - * - * card ID's and external interfaces of the bttv driver - * basically stuff needed by other drivers (i2c, lirc, ...) - * and is supported not to change much over time. - * - * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) - * (c) 1999,2000 Gerd Knorr - * - */ - -#ifndef _BTTV_H_ -#define _BTTV_H_ - -#include -#include -#include -#include -#include - -/* ---------------------------------------------------------- */ -/* exported by bttv-cards.c */ - -#define BTTV_BOARD_UNKNOWN 0x00 -#define BTTV_BOARD_MIRO 0x01 -#define BTTV_BOARD_HAUPPAUGE 0x02 -#define BTTV_BOARD_STB 0x03 -#define BTTV_BOARD_INTEL 0x04 -#define BTTV_BOARD_DIAMOND 0x05 -#define BTTV_BOARD_AVERMEDIA 0x06 -#define BTTV_BOARD_MATRIX_VISION 0x07 -#define BTTV_BOARD_FLYVIDEO 0x08 -#define BTTV_BOARD_TURBOTV 0x09 -#define BTTV_BOARD_HAUPPAUGE878 0x0a -#define BTTV_BOARD_MIROPRO 0x0b -#define BTTV_BOARD_ADSTECH_TV 0x0c -#define BTTV_BOARD_AVERMEDIA98 0x0d -#define BTTV_BOARD_VHX 0x0e -#define BTTV_BOARD_ZOLTRIX 0x0f -#define BTTV_BOARD_PIXVIEWPLAYTV 0x10 -#define BTTV_BOARD_WINVIEW_601 0x11 -#define BTTV_BOARD_AVEC_INTERCAP 0x12 -#define BTTV_BOARD_LIFE_FLYKIT 0x13 -#define BTTV_BOARD_CEI_RAFFLES 0x14 -#define BTTV_BOARD_CONFERENCETV 0x15 -#define BTTV_BOARD_PHOEBE_TVMAS 0x16 -#define BTTV_BOARD_MODTEC_205 0x17 -#define BTTV_BOARD_MAGICTVIEW061 0x18 -#define BTTV_BOARD_VOBIS_BOOSTAR 0x19 -#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a -#define BTTV_BOARD_MAXI 0x1b -#define BTTV_BOARD_TERRATV 0x1c -#define BTTV_BOARD_PXC200 0x1d -#define BTTV_BOARD_FLYVIDEO_98 0x1e -#define BTTV_BOARD_IPROTV 0x1f -#define BTTV_BOARD_INTEL_C_S_PCI 0x20 -#define BTTV_BOARD_TERRATVALUE 0x21 -#define BTTV_BOARD_WINFAST2000 0x22 -#define BTTV_BOARD_CHRONOS_VS2 0x23 -#define BTTV_BOARD_TYPHOON_TVIEW 0x24 -#define BTTV_BOARD_PXELVWPLTVPRO 0x25 -#define BTTV_BOARD_MAGICTVIEW063 0x26 -#define BTTV_BOARD_PINNACLE 0x27 -#define BTTV_BOARD_STB2 0x28 -#define BTTV_BOARD_AVPHONE98 0x29 -#define BTTV_BOARD_PV951 0x2a -#define BTTV_BOARD_ONAIR_TV 0x2b -#define BTTV_BOARD_SIGMA_TVII_FM 0x2c -#define BTTV_BOARD_MATRIX_VISION2 0x2d -#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e -#define BTTV_BOARD_TERRATVRADIO 0x2f -#define BTTV_BOARD_DYNALINK 0x30 -#define BTTV_BOARD_GVBCTV3PCI 0x31 -#define BTTV_BOARD_PXELVWPLTVPAK 0x32 -#define BTTV_BOARD_EAGLE 0x33 -#define BTTV_BOARD_PINNACLEPRO 0x34 -#define BTTV_BOARD_TVIEW_RDS_FM 0x35 -#define BTTV_BOARD_LIFETEC_9415 0x36 -#define BTTV_BOARD_BESTBUY_EASYTV 0x37 -#define BTTV_BOARD_FLYVIDEO_98FM 0x38 -#define BTTV_BOARD_GRANDTEC 0x39 -#define BTTV_BOARD_ASKEY_CPH060 0x3a -#define BTTV_BOARD_ASKEY_CPH03X 0x3b -#define BTTV_BOARD_MM100PCTV 0x3c -#define BTTV_BOARD_GMV1 0x3d -#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e -#define BTTV_BOARD_ATI_TVWONDER 0x3f -#define BTTV_BOARD_ATI_TVWONDERVE 0x40 -#define BTTV_BOARD_FLYVIDEO2000 0x41 -#define BTTV_BOARD_TERRATVALUER 0x42 -#define BTTV_BOARD_GVBCTV4PCI 0x43 -#define BTTV_BOARD_VOODOOTV_FM 0x44 -#define BTTV_BOARD_AIMMS 0x45 -#define BTTV_BOARD_PV_BT878P_PLUS 0x46 -#define BTTV_BOARD_FLYVIDEO98EZ 0x47 -#define BTTV_BOARD_PV_BT878P_9B 0x48 -#define BTTV_BOARD_SENSORAY311 0x49 -#define BTTV_BOARD_RV605 0x4a -#define BTTV_BOARD_POWERCLR_MTV878 0x4b -#define BTTV_BOARD_WINDVR 0x4c -#define BTTV_BOARD_GRANDTEC_MULTI 0x4d -#define BTTV_BOARD_KWORLD 0x4e -#define BTTV_BOARD_DSP_TCVIDEO 0x4f -#define BTTV_BOARD_HAUPPAUGEPVR 0x50 -#define BTTV_BOARD_GVBCTV5PCI 0x51 -#define BTTV_BOARD_OSPREY1x0 0x52 -#define BTTV_BOARD_OSPREY1x0_848 0x53 -#define BTTV_BOARD_OSPREY101_848 0x54 -#define BTTV_BOARD_OSPREY1x1 0x55 -#define BTTV_BOARD_OSPREY1x1_SVID 0x56 -#define BTTV_BOARD_OSPREY2xx 0x57 -#define BTTV_BOARD_OSPREY2x0_SVID 0x58 -#define BTTV_BOARD_OSPREY2x0 0x59 -#define BTTV_BOARD_OSPREY500 0x5a -#define BTTV_BOARD_OSPREY540 0x5b -#define BTTV_BOARD_OSPREY2000 0x5c -#define BTTV_BOARD_IDS_EAGLE 0x5d -#define BTTV_BOARD_PINNACLESAT 0x5e -#define BTTV_BOARD_FORMAC_PROTV 0x5f -#define BTTV_BOARD_MACHTV 0x60 -#define BTTV_BOARD_EURESYS_PICOLO 0x61 -#define BTTV_BOARD_PV150 0x62 -#define BTTV_BOARD_AD_TVK503 0x63 -#define BTTV_BOARD_HERCULES_SM_TV 0x64 -#define BTTV_BOARD_PACETV 0x65 -#define BTTV_BOARD_IVC200 0x66 -#define BTTV_BOARD_XGUARD 0x67 -#define BTTV_BOARD_NEBULA_DIGITV 0x68 -#define BTTV_BOARD_PV143 0x69 -#define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a -#define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b -#define BTTV_BOARD_VD009_MINIDIN 0x6c -#define BTTV_BOARD_VD009_COMBI 0x6d -#define BTTV_BOARD_IVC100 0x6e -#define BTTV_BOARD_IVC120 0x6f -#define BTTV_BOARD_PC_HDTV 0x70 -#define BTTV_BOARD_TWINHAN_DST 0x71 -#define BTTV_BOARD_WINFASTVC100 0x72 -#define BTTV_BOARD_TEV560 0x73 -#define BTTV_BOARD_SIMUS_GVC1100 0x74 -#define BTTV_BOARD_NGSTV_PLUS 0x75 -#define BTTV_BOARD_LMLBT4 0x76 -#define BTTV_BOARD_TEKRAM_M205 0x77 -#define BTTV_BOARD_CONTVFMI 0x78 -#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 -#define BTTV_BOARD_SPIRIT_TV 0x7a -#define BTTV_BOARD_AVDVBT_771 0x7b -#define BTTV_BOARD_AVDVBT_761 0x7c -#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d -#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e -#define BTTV_BOARD_APAC_VIEWCOMP 0x7f -#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 -#define BTTV_BOARD_VGEAR_MYVCD 0x81 -#define BTTV_BOARD_SUPER_TV 0x82 -#define BTTV_BOARD_TIBET_CS16 0x83 -#define BTTV_BOARD_KODICOM_4400R 0x84 -#define BTTV_BOARD_KODICOM_4400R_SL 0x85 -#define BTTV_BOARD_ADLINK_RTV24 0x86 -#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 -#define BTTV_BOARD_ACORP_Y878F 0x88 -#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 -#define BTTV_BOARD_PV_BT878P_2E 0x8a -#define BTTV_BOARD_PV_M4900 0x8b -#define BTTV_BOARD_OSPREY440 0x8c -#define BTTV_BOARD_ASOUND_SKYEYE 0x8d -#define BTTV_BOARD_SABRENT_TVFM 0x8e -#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f -#define BTTV_BOARD_MACHTV_MAGICTV 0x90 -#define BTTV_BOARD_SSAI_SECURITY 0x91 -#define BTTV_BOARD_SSAI_ULTRASOUND 0x92 -#define BTTV_BOARD_VOODOOTV_200 0x93 -#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 -#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 -#define BTTV_BOARD_GEOVISION_GV600 0x96 -#define BTTV_BOARD_KOZUMI_KTV_01C 0x97 -#define BTTV_BOARD_ENLTV_FM_2 0x98 -#define BTTV_BOARD_VD012 0x99 -#define BTTV_BOARD_VD012_X1 0x9a -#define BTTV_BOARD_VD012_X2 0x9b -#define BTTV_BOARD_IVCE8784 0x9c -#define BTTV_BOARD_GEOVISION_GV800S 0x9d -#define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e -#define BTTV_BOARD_PV183 0x9f - - -/* more card-specific defines */ -#define PT2254_L_CHANNEL 0x10 -#define PT2254_R_CHANNEL 0x08 -#define PT2254_DBS_IN_2 0x400 -#define PT2254_DBS_IN_10 0x20000 -#define WINVIEW_PT2254_CLK 0x40 -#define WINVIEW_PT2254_DATA 0x20 -#define WINVIEW_PT2254_STROBE 0x80 - -struct bttv_core { - /* device structs */ - struct v4l2_device v4l2_dev; - struct pci_dev *pci; - struct i2c_adapter i2c_adap; - struct list_head subs; /* struct bttv_sub_device */ - - /* device config */ - unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ - unsigned int type; /* card type (pointer into tvcards[]) */ -}; - -struct bttv; - -struct tvcard { - char *name; - void (*volume_gpio)(struct bttv *btv, __u16 volume); - void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); - void (*muxsel_hook)(struct bttv *btv, unsigned int input); - - /* MUX bits for each input, two bits per input starting with the LSB */ - u32 muxsel; /* Use MUXSEL() to set */ - - u32 gpiomask; - u32 gpiomux[4]; /* Tuner, Radio, external, internal */ - u32 gpiomute; /* GPIO mute setting */ - u32 gpiomask2; /* GPIO MUX mask */ - - unsigned int tuner_type; - u8 tuner_addr; - u8 video_inputs; /* Number of inputs */ - unsigned int svhs:4; /* Which input is s-video */ -#define NO_SVHS 15 - unsigned int pll:2; -#define PLL_NONE 0 -#define PLL_28 1 -#define PLL_35 2 - - /* i2c audio flags */ - unsigned int no_msp34xx:1; - unsigned int no_tda7432:1; - unsigned int needs_tvaudio:1; - unsigned int msp34xx_alt:1; - /* Note: currently no card definition needs to mark the presence - of a RDS saa6588 chip. If this is ever needed, then add a new - 'has_saa6588' bit here. */ - - unsigned int no_video:1; /* video pci function is unused */ - unsigned int has_dvb:1; - unsigned int has_remote:1; - unsigned int has_radio:1; - unsigned int has_dig_in:1; /* Has digital input (always last input) */ - unsigned int no_gpioirq:1; -}; - -extern struct tvcard bttv_tvcards[]; - -/* - * This bit of cpp voodoo is used to create a macro with a variable number of - * arguments (1 to 16). It will pack each argument into a word two bits at a - * time. It can't be a function because it needs to be compile time constant to - * initialize structures. Since each argument must fit in two bits, it's ok - * that they are changed to octal. One should not use hex number, macros, or - * anything else with this macro. Just use plain integers from 0 to 3. - */ -#define _MUXSELf(a) 0##a << 30 -#define _MUXSELe(a, b...) 0##a << 28 | _MUXSELf(b) -#define _MUXSELd(a, b...) 0##a << 26 | _MUXSELe(b) -#define _MUXSELc(a, b...) 0##a << 24 | _MUXSELd(b) -#define _MUXSELb(a, b...) 0##a << 22 | _MUXSELc(b) -#define _MUXSELa(a, b...) 0##a << 20 | _MUXSELb(b) -#define _MUXSEL9(a, b...) 0##a << 18 | _MUXSELa(b) -#define _MUXSEL8(a, b...) 0##a << 16 | _MUXSEL9(b) -#define _MUXSEL7(a, b...) 0##a << 14 | _MUXSEL8(b) -#define _MUXSEL6(a, b...) 0##a << 12 | _MUXSEL7(b) -#define _MUXSEL5(a, b...) 0##a << 10 | _MUXSEL6(b) -#define _MUXSEL4(a, b...) 0##a << 8 | _MUXSEL5(b) -#define _MUXSEL3(a, b...) 0##a << 6 | _MUXSEL4(b) -#define _MUXSEL2(a, b...) 0##a << 4 | _MUXSEL3(b) -#define _MUXSEL1(a, b...) 0##a << 2 | _MUXSEL2(b) -#define MUXSEL(a, b...) (a | _MUXSEL1(b)) - -/* identification / initialization of the card */ -extern void bttv_idcard(struct bttv *btv); -extern void bttv_init_card1(struct bttv *btv); -extern void bttv_init_card2(struct bttv *btv); -extern void bttv_init_tuner(struct bttv *btv); - -/* card-specific funtions */ -extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); -extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits); - -/* extra tweaks for some chipsets */ -extern void bttv_check_chipset(void); -extern int bttv_handle_chipset(struct bttv *btv); - -/* ---------------------------------------------------------- */ -/* exported by bttv-if.c */ - -/* this obsolete -- please use the sysfs-based - interface below for new code */ - -extern struct pci_dev* bttv_get_pcidev(unsigned int card); - -/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: - data | (current_GPOE_value & ~mask) - returns negative value if error occurred -*/ -extern int bttv_gpio_enable(unsigned int card, - unsigned long mask, unsigned long data); - -/* fills data with GPDATA register contents - returns negative value if error occurred -*/ -extern int bttv_read_gpio(unsigned int card, unsigned long *data); - -/* sets GPDATA register to new value: - (data & mask) | (current_GPDATA_value & ~mask) - returns negative value if error occurred -*/ -extern int bttv_write_gpio(unsigned int card, - unsigned long mask, unsigned long data); - - - - -/* ---------------------------------------------------------- */ -/* sysfs/driver-moded based gpio access interface */ - -struct bttv_sub_device { - struct device dev; - struct bttv_core *core; - struct list_head list; -}; -#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) - -struct bttv_sub_driver { - struct device_driver drv; - char wanted[20]; - int (*probe)(struct bttv_sub_device *sub); - void (*remove)(struct bttv_sub_device *sub); -}; -#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) - -int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); -int bttv_sub_unregister(struct bttv_sub_driver *drv); - -/* gpio access functions */ -void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); -u32 bttv_gpio_read(struct bttv_core *core); -void bttv_gpio_write(struct bttv_core *core, u32 value); -void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); - -#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) -#define gpio_read() bttv_gpio_read(&btv->c) -#define gpio_write(value) bttv_gpio_write(&btv->c, value) -#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) - - -/* ---------------------------------------------------------- */ -/* i2c */ - -#define bttv_call_all(btv, o, f, args...) \ - v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args) - -extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); -extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, - unsigned char b2, int both); -extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); - -extern int bttv_input_init(struct bttv *dev); -extern void bttv_input_fini(struct bttv *dev); -extern void bttv_input_irq(struct bttv *dev); - -#endif /* _BTTV_H_ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-i2c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,391 +0,0 @@ -/* - - bttv-i2c.c -- all the i2c code is here - - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999-2003 Gerd Knorr - - (c) 2005 Mauro Carvalho Chehab - - Multituner support and i2c address binding - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include - -#include "bttvp.h" -#include -#include -#include - -static int i2c_debug; -static int i2c_hw; -static int i2c_scan; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "configure i2c debug level"); -module_param(i2c_hw, int, 0444); -MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, " - "instead of software bitbang"); -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); - -static unsigned int i2c_udelay = 5; -module_param(i2c_udelay, int, 0444); -MODULE_PARM_DESC(i2c_udelay,"soft i2c delay at insmod time, in usecs " - "(should be 5 or higher). Lower value means higher bus speed."); - -/* ----------------------------------------------------------------------- */ -/* I2C functions - bitbanging adapter (software i2c) */ - -static void bttv_bit_setscl(void *data, int state) -{ - struct bttv *btv = (struct bttv*)data; - - if (state) - btv->i2c_state |= 0x02; - else - btv->i2c_state &= ~0x02; - btwrite(btv->i2c_state, BT848_I2C); - btread(BT848_I2C); -} - -static void bttv_bit_setsda(void *data, int state) -{ - struct bttv *btv = (struct bttv*)data; - - if (state) - btv->i2c_state |= 0x01; - else - btv->i2c_state &= ~0x01; - btwrite(btv->i2c_state, BT848_I2C); - btread(BT848_I2C); -} - -static int bttv_bit_getscl(void *data) -{ - struct bttv *btv = (struct bttv*)data; - int state; - - state = btread(BT848_I2C) & 0x02 ? 1 : 0; - return state; -} - -static int bttv_bit_getsda(void *data) -{ - struct bttv *btv = (struct bttv*)data; - int state; - - state = btread(BT848_I2C) & 0x01; - return state; -} - -static struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = { - .setsda = bttv_bit_setsda, - .setscl = bttv_bit_setscl, - .getsda = bttv_bit_getsda, - .getscl = bttv_bit_getscl, - .udelay = 16, - .timeout = 200, -}; - -/* ----------------------------------------------------------------------- */ -/* I2C functions - hardware i2c */ - -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static int -bttv_i2c_wait_done(struct bttv *btv) -{ - int rc = 0; - - /* timeout */ - if (wait_event_interruptible_timeout(btv->i2c_queue, - btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS) - rc = -EIO; - - if (btv->i2c_done & BT848_INT_RACK) - rc = 1; - btv->i2c_done = 0; - return rc; -} - -#define I2C_HW (BT878_I2C_MODE | BT848_I2C_SYNC |\ - BT848_I2C_SCL | BT848_I2C_SDA) - -static int -bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) -{ - u32 xmit; - int retval,cnt; - - /* sanity checks */ - if (0 == msg->len) - return -EINVAL; - - /* start, address + first byte */ - xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW; - if (msg->len > 1 || !last) - xmit |= BT878_I2C_NOSTOP; - btwrite(xmit, BT848_I2C); - retval = bttv_i2c_wait_done(btv); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - if (i2c_debug) { - printk(" addr << 1, msg->buf[0]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); - } - - for (cnt = 1; cnt < msg->len; cnt++ ) { - /* following bytes */ - xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART; - if (cnt < msg->len-1 || !last) - xmit |= BT878_I2C_NOSTOP; - btwrite(xmit, BT848_I2C); - retval = bttv_i2c_wait_done(btv); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - if (i2c_debug) { - printk(" %02x", msg->buf[cnt]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); - } - } - return msg->len; - - eio: - retval = -EIO; - err: - if (i2c_debug) - printk(" ERR: %d\n",retval); - return retval; -} - -static int -bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) -{ - u32 xmit; - u32 cnt; - int retval; - - for(cnt = 0; cnt < msg->len; cnt++) { - xmit = (msg->addr << 25) | (1 << 24) | I2C_HW; - if (cnt < msg->len-1) - xmit |= BT848_I2C_W3B; - if (cnt < msg->len-1 || !last) - xmit |= BT878_I2C_NOSTOP; - if (cnt) - xmit |= BT878_I2C_NOSTART; - btwrite(xmit, BT848_I2C); - retval = bttv_i2c_wait_done(btv); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff; - if (i2c_debug) { - if (!(xmit & BT878_I2C_NOSTART)) - printk(" addr << 1) +1); - printk(" =%02x", msg->buf[cnt]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); - } - } - return msg->len; - - eio: - retval = -EIO; - err: - if (i2c_debug) - printk(" ERR: %d\n",retval); - return retval; -} - -static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) -{ - struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap); - struct bttv *btv = to_bttv(v4l2_dev); - int retval = 0; - int i; - - if (i2c_debug) - printk("bt-i2c:"); - btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); - for (i = 0 ; i < num; i++) { - if (msgs[i].flags & I2C_M_RD) { - /* read */ - retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num); - if (retval < 0) - goto err; - } else { - /* write */ - retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num); - if (retval < 0) - goto err; - } - } - return num; - - err: - return retval; -} - -static const struct i2c_algorithm bttv_algo = { - .master_xfer = bttv_i2c_xfer, - .functionality = functionality, -}; - -/* ----------------------------------------------------------------------- */ -/* I2C functions - common stuff */ - -/* read I2C */ -int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) -{ - unsigned char buffer = 0; - - if (0 != btv->i2c_rc) - return -1; - if (bttv_verbose && NULL != probe_for) - printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", - btv->c.nr,probe_for,addr); - btv->i2c_client.addr = addr >> 1; - if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { - if (NULL != probe_for) { - if (bttv_verbose) - printk("not found\n"); - } else - printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", - btv->c.nr,addr); - return -1; - } - if (bttv_verbose && NULL != probe_for) - printk("found\n"); - return buffer; -} - -/* write I2C */ -int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, - unsigned char b2, int both) -{ - unsigned char buffer[2]; - int bytes = both ? 2 : 1; - - if (0 != btv->i2c_rc) - return -1; - btv->i2c_client.addr = addr >> 1; - buffer[0] = b1; - buffer[1] = b2; - if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) - return -1; - return 0; -} - -/* read EEPROM content */ -void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) -{ - memset(eedata, 0, 256); - if (0 != btv->i2c_rc) - return; - btv->i2c_client.addr = addr >> 1; - tveeprom_read(&btv->i2c_client, eedata, 256); -} - -static char *i2c_devs[128] = { - [ 0x1c >> 1 ] = "lgdt330x", - [ 0x30 >> 1 ] = "IR (hauppauge)", - [ 0x80 >> 1 ] = "msp34xx", - [ 0x86 >> 1 ] = "tda9887", - [ 0xa0 >> 1 ] = "eeprom", - [ 0xc0 >> 1 ] = "tuner (analog)", - [ 0xc2 >> 1 ] = "tuner (analog)", -}; - -static void do_i2c_scan(char *name, struct i2c_client *c) -{ - unsigned char buf; - int i,rc; - - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - c->addr = i; - rc = i2c_master_recv(c,&buf,0); - if (rc < 0) - continue; - printk("%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); - } -} - -/* init + register i2c algo-bit adapter */ -int __devinit init_bttv_i2c(struct bttv *btv) -{ - strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE); - - if (i2c_hw) - btv->use_i2c_hw = 1; - if (btv->use_i2c_hw) { - /* bt878 */ - strlcpy(btv->c.i2c_adap.name, "bt878", - sizeof(btv->c.i2c_adap.name)); - btv->c.i2c_adap.algo = &bttv_algo; - } else { - /* bt848 */ - /* Prevents usage of invalid delay values */ - if (i2c_udelay<5) - i2c_udelay=5; - - strlcpy(btv->c.i2c_adap.name, "bttv", - sizeof(btv->c.i2c_adap.name)); - memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template, - sizeof(bttv_i2c_algo_bit_template)); - btv->i2c_algo.udelay = i2c_udelay; - btv->i2c_algo.data = btv; - btv->c.i2c_adap.algo_data = &btv->i2c_algo; - } - btv->c.i2c_adap.owner = THIS_MODULE; - - btv->c.i2c_adap.dev.parent = &btv->c.pci->dev; - snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name), - "bt%d #%d [%s]", btv->id, btv->c.nr, - btv->use_i2c_hw ? "hw" : "sw"); - - i2c_set_adapdata(&btv->c.i2c_adap, &btv->c.v4l2_dev); - btv->i2c_client.adapter = &btv->c.i2c_adap; - - - if (btv->use_i2c_hw) { - btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap); - } else { - bttv_bit_setscl(btv,1); - bttv_bit_setsda(btv,1); - btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap); - } - if (0 == btv->i2c_rc && i2c_scan) - do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client); - - return btv->i2c_rc; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-if.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-if.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-if.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-if.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -/* - - bttv-if.c -- old gpio interface to other kernel modules - don't use in new code, will go away in 2.7 - have a look at bttv-gpio.c instead. - - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999-2003 Gerd Knorr - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include - -#include "bttvp.h" - -EXPORT_SYMBOL(bttv_get_pcidev); -EXPORT_SYMBOL(bttv_gpio_enable); -EXPORT_SYMBOL(bttv_read_gpio); -EXPORT_SYMBOL(bttv_write_gpio); - -/* ----------------------------------------------------------------------- */ -/* Exported functions - for other modules which want to access the */ -/* gpio ports (IR for example) */ -/* see bttv.h for comments */ - -struct pci_dev* bttv_get_pcidev(unsigned int card) -{ - if (card >= bttv_num) - return NULL; - if (!bttvs[card]) - return NULL; - - return bttvs[card]->c.pci; -} - - -int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return -EINVAL; - } - - btv = bttvs[card]; - if (!btv) - return -ENODEV; - - gpio_inout(mask,data); - if (bttv_gpio) - bttv_gpio_tracking(btv,"extern enable"); - return 0; -} - -int bttv_read_gpio(unsigned int card, unsigned long *data) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return -EINVAL; - } - - btv = bttvs[card]; - if (!btv) - return -ENODEV; - - if(btv->shutdown) { - return -ENODEV; - } - -/* prior setting BT848_GPIO_REG_INP is (probably) not needed - because we set direct input on init */ - *data = gpio_read(); - return 0; -} - -int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return -EINVAL; - } - - btv = bttvs[card]; - if (!btv) - return -ENODEV; - -/* prior setting BT848_GPIO_REG_INP is (probably) not needed - because direct input is set on init */ - gpio_bits(mask,data); - if (bttv_gpio) - bttv_gpio_tracking(btv,"extern write"); - return 0; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-input.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-input.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,588 +0,0 @@ -/* - * - * Copyright (c) 2003 Gerd Knorr - * Copyright (c) 2003 Pavel Machek - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "bttvp.h" - - -static int ir_debug; -module_param(ir_debug, int, 0644); - -static int ir_rc5_remote_gap = 885; -module_param(ir_rc5_remote_gap, int, 0644); - -#undef dprintk -#define dprintk(arg...) do { \ - if (ir_debug >= 1) \ - printk(arg); \ -} while (0) - -#define DEVNAME "bttv-input" - -#define MODULE_NAME "bttv" - -/* ---------------------------------------------------------------------- */ - -static void ir_handle_key(struct bttv *btv) -{ - struct bttv_ir *ir = btv->remote; - u32 gpio,data; - - /* read gpio value */ - gpio = bttv_gpio_read(&btv->c); - if (ir->polling) { - if (ir->last_gpio == gpio) - return; - ir->last_gpio = gpio; - } - - /* extract data */ - data = ir_extract_bits(gpio, ir->mask_keycode); - dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n", - gpio, data, - ir->polling ? "poll" : "irq", - (gpio & ir->mask_keydown) ? " down" : "", - (gpio & ir->mask_keyup) ? " up" : ""); - - if ((ir->mask_keydown && (gpio & ir->mask_keydown)) || - (ir->mask_keyup && !(gpio & ir->mask_keyup))) { - rc_keydown_notimeout(ir->dev, data, 0); - } else { - /* HACK: Probably, ir->mask_keydown is missing - for this board */ - if (btv->c.type == BTTV_BOARD_WINFAST2000) - rc_keydown_notimeout(ir->dev, data, 0); - - rc_keyup(ir->dev); - } -} - -static void ir_enltv_handle_key(struct bttv *btv) -{ - struct bttv_ir *ir = btv->remote; - u32 gpio, data, keyup; - - /* read gpio value */ - gpio = bttv_gpio_read(&btv->c); - - /* extract data */ - data = ir_extract_bits(gpio, ir->mask_keycode); - - /* Check if it is keyup */ - keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; - - if ((ir->last_gpio & 0x7f) != data) { - dprintk(KERN_INFO DEVNAME ": gpio=0x%x code=%d | %s\n", - gpio, data, - (gpio & ir->mask_keyup) ? " up" : "up/down"); - - rc_keydown_notimeout(ir->dev, data, 0); - if (keyup) - rc_keyup(ir->dev); - } else { - if ((ir->last_gpio & 1 << 31) == keyup) - return; - - dprintk(KERN_INFO DEVNAME ":(cnt) gpio=0x%x code=%d | %s\n", - gpio, data, - (gpio & ir->mask_keyup) ? " up" : "down"); - - if (keyup) - rc_keyup(ir->dev); - else - rc_keydown_notimeout(ir->dev, data, 0); - } - - ir->last_gpio = data | keyup; -} - -static int bttv_rc5_irq(struct bttv *btv); - -void bttv_input_irq(struct bttv *btv) -{ - struct bttv_ir *ir = btv->remote; - - if (ir->rc5_gpio) - bttv_rc5_irq(btv); - else if (!ir->polling) - ir_handle_key(btv); -} - -static void bttv_input_timer(unsigned long data) -{ - struct bttv *btv = (struct bttv*)data; - struct bttv_ir *ir = btv->remote; - - if (btv->c.type == BTTV_BOARD_ENLTV_FM_2) - ir_enltv_handle_key(btv); - else - ir_handle_key(btv); - mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); -} - -/* - * FIXME: Nebula digi uses the legacy way to decode RC5, instead of relying - * on the rc-core way. As we need to be sure that both IRQ transitions are - * properly triggered, Better to touch it only with this hardware for - * testing. - */ - -#define RC5_START(x) (((x) >> 12) & 3) -#define RC5_TOGGLE(x) (((x) >> 11) & 1) -#define RC5_ADDR(x) (((x) >> 6) & 31) -#define RC5_INSTR(x) ((x) & 63) - -/* decode raw bit pattern to RC5 code */ -static u32 bttv_rc5_decode(unsigned int code) -{ - unsigned int org_code = code; - unsigned int pair; - unsigned int rc5 = 0; - int i; - - for (i = 0; i < 14; ++i) { - pair = code & 0x3; - code >>= 2; - - rc5 <<= 1; - switch (pair) { - case 0: - case 2: - break; - case 1: - rc5 |= 1; - break; - case 3: - dprintk(KERN_INFO DEVNAME ":rc5_decode(%x) bad code\n", - org_code); - return 0; - } - } - dprintk(KERN_INFO DEVNAME ":" - "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " - "instr=%x\n", rc5, org_code, RC5_START(rc5), - RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); - return rc5; -} - -static void bttv_rc5_timer_end(unsigned long data) -{ - struct bttv_ir *ir = (struct bttv_ir *)data; - struct timeval tv; - u32 gap; - u32 rc5 = 0; - - /* get time */ - do_gettimeofday(&tv); - - /* avoid overflow with gap >1s */ - if (tv.tv_sec - ir->base_time.tv_sec > 1) { - gap = 200000; - } else { - gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + - tv.tv_usec - ir->base_time.tv_usec; - } - - /* signal we're ready to start a new code */ - ir->active = false; - - /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */ - if (gap < 28000) { - dprintk(KERN_INFO DEVNAME ": spurious timer_end\n"); - return; - } - - if (ir->last_bit < 20) { - /* ignore spurious codes (caused by light/other remotes) */ - dprintk(KERN_INFO DEVNAME ": short code: %x\n", ir->code); - } else { - ir->code = (ir->code << ir->shift_by) | 1; - rc5 = bttv_rc5_decode(ir->code); - - /* two start bits? */ - if (RC5_START(rc5) != ir->start) { - printk(KERN_INFO DEVNAME ":" - " rc5 start bits invalid: %u\n", RC5_START(rc5)); - - /* right address? */ - } else if (RC5_ADDR(rc5) == ir->addr) { - u32 toggle = RC5_TOGGLE(rc5); - u32 instr = RC5_INSTR(rc5); - - /* Good code */ - rc_keydown(ir->dev, instr, toggle); - dprintk(KERN_INFO DEVNAME ":" - " instruction %x, toggle %x\n", - instr, toggle); - } - } -} - -static int bttv_rc5_irq(struct bttv *btv) -{ - struct bttv_ir *ir = btv->remote; - struct timeval tv; - u32 gpio; - u32 gap; - unsigned long current_jiffies; - - /* read gpio port */ - gpio = bttv_gpio_read(&btv->c); - - /* get time of bit */ - current_jiffies = jiffies; - do_gettimeofday(&tv); - - /* avoid overflow with gap >1s */ - if (tv.tv_sec - ir->base_time.tv_sec > 1) { - gap = 200000; - } else { - gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + - tv.tv_usec - ir->base_time.tv_usec; - } - - dprintk(KERN_INFO DEVNAME ": RC5 IRQ: gap %d us for %s\n", - gap, (gpio & 0x20) ? "mark" : "space"); - - /* remote IRQ? */ - if (!(gpio & 0x20)) - return 0; - - /* active code => add bit */ - if (ir->active) { - /* only if in the code (otherwise spurious IRQ or timer - late) */ - if (ir->last_bit < 28) { - ir->last_bit = (gap - ir_rc5_remote_gap / 2) / - ir_rc5_remote_gap; - ir->code |= 1 << ir->last_bit; - } - /* starting new code */ - } else { - ir->active = true; - ir->code = 0; - ir->base_time = tv; - ir->last_bit = 0; - - mod_timer(&ir->timer, current_jiffies + msecs_to_jiffies(30)); - } - - /* toggle GPIO pin 4 to reset the irq */ - bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); - bttv_gpio_write(&btv->c, gpio | (1 << 4)); - return 1; -} - -/* ---------------------------------------------------------------------- */ - -static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir) -{ - if (ir->polling) { - setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv); - ir->timer.expires = jiffies + msecs_to_jiffies(1000); - add_timer(&ir->timer); - } else if (ir->rc5_gpio) { - /* set timer_end for code completion */ - setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir); - ir->shift_by = 1; - ir->start = 3; - ir->addr = 0x0; - ir->rc5_remote_gap = ir_rc5_remote_gap; - } -} - -static void bttv_ir_stop(struct bttv *btv) -{ - if (btv->remote->polling) - del_timer_sync(&btv->remote->timer); - - if (btv->remote->rc5_gpio) { - u32 gpio; - - del_timer_sync(&btv->remote->timer); - - gpio = bttv_gpio_read(&btv->c); - bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); - } -} - -/* - * Get_key functions used by I2C remotes - */ - -static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char b; - - /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk(KERN_INFO DEVNAME ": read error\n"); - return -EIO; - } - - /* ignore 0xaa */ - if (b==0xaa) - return 0; - dprintk(KERN_INFO DEVNAME ": key %02x\n", b); - - /* - * NOTE: - * lirc_i2c maps the pv951 code as: - * addr = 0x61D6 - * cmd = bit_reverse (b) - * So, it seems that this device uses NEC extended - * I decided to not fix the table, due to two reasons: - * 1) Without the actual device, this is only a guess; - * 2) As the addr is not reported via I2C, nor can be changed, - * the device is bound to the vendor-provided RC. - */ - - *ir_key = b; - *ir_raw = b; - return 1; -} - -/* Instantiate the I2C IR receiver device, if present */ -void __devinit init_bttv_i2c_ir(struct bttv *btv) -{ - const unsigned short addr_list[] = { - 0x1a, 0x18, 0x64, 0x30, 0x71, - I2C_CLIENT_END - }; - struct i2c_board_info info; - - if (0 != btv->i2c_rc) - return; - - memset(&info, 0, sizeof(struct i2c_board_info)); - memset(&btv->init_data, 0, sizeof(btv->init_data)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - - switch (btv->c.type) { - case BTTV_BOARD_PV951: - btv->init_data.name = "PV951"; - btv->init_data.get_key = get_key_pv951; - btv->init_data.ir_codes = RC_MAP_PV951; - info.addr = 0x4b; - break; - default: - /* - * The external IR receiver is at i2c address 0x34 (0x35 for - * reads). Future Hauppauge cards will have an internal - * receiver at 0x30 (0x31 for reads). In theory, both can be - * fitted, and Hauppauge suggest an external overrides an - * internal. - * That's why we probe 0x1a (~0x34) first. CB - */ - - i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); - return; - } - - if (btv->init_data.name) - info.platform_data = &btv->init_data; - i2c_new_device(&btv->c.i2c_adap, &info); - - return; -} - -int __devexit fini_bttv_i2c(struct bttv *btv) -{ - if (0 != btv->i2c_rc) - return 0; - - return i2c_del_adapter(&btv->c.i2c_adap); -} - -int bttv_input_init(struct bttv *btv) -{ - struct bttv_ir *ir; - char *ir_codes = NULL; - struct rc_dev *rc; - int err = -ENOMEM; - - if (!btv->has_remote) - return -ENODEV; - - ir = kzalloc(sizeof(*ir),GFP_KERNEL); - rc = rc_allocate_device(); - if (!ir || !rc) - goto err_out_free; - - /* detect & configure */ - switch (btv->c.type) { - case BTTV_BOARD_AVERMEDIA: - case BTTV_BOARD_AVPHONE98: - case BTTV_BOARD_AVERMEDIA98: - ir_codes = RC_MAP_AVERMEDIA; - ir->mask_keycode = 0xf88000; - ir->mask_keydown = 0x010000; - ir->polling = 50; // ms - break; - - case BTTV_BOARD_AVDVBT_761: - case BTTV_BOARD_AVDVBT_771: - ir_codes = RC_MAP_AVERMEDIA_DVBT; - ir->mask_keycode = 0x0f00c0; - ir->mask_keydown = 0x000020; - ir->polling = 50; // ms - break; - - case BTTV_BOARD_PXELVWPLTVPAK: - ir_codes = RC_MAP_PIXELVIEW; - ir->mask_keycode = 0x003e00; - ir->mask_keyup = 0x010000; - ir->polling = 50; // ms - break; - case BTTV_BOARD_PV_M4900: - case BTTV_BOARD_PV_BT878P_9B: - case BTTV_BOARD_PV_BT878P_PLUS: - ir_codes = RC_MAP_PIXELVIEW; - ir->mask_keycode = 0x001f00; - ir->mask_keyup = 0x008000; - ir->polling = 50; // ms - break; - - case BTTV_BOARD_WINFAST2000: - ir_codes = RC_MAP_WINFAST; - ir->mask_keycode = 0x1f8; - break; - case BTTV_BOARD_MAGICTVIEW061: - case BTTV_BOARD_MAGICTVIEW063: - ir_codes = RC_MAP_WINFAST; - ir->mask_keycode = 0x0008e000; - ir->mask_keydown = 0x00200000; - break; - case BTTV_BOARD_APAC_VIEWCOMP: - ir_codes = RC_MAP_APAC_VIEWCOMP; - ir->mask_keycode = 0x001f00; - ir->mask_keyup = 0x008000; - ir->polling = 50; // ms - break; - case BTTV_BOARD_ASKEY_CPH03X: - case BTTV_BOARD_CONCEPTRONIC_CTVFMI2: - case BTTV_BOARD_CONTVFMI: - ir_codes = RC_MAP_PIXELVIEW; - ir->mask_keycode = 0x001F00; - ir->mask_keyup = 0x006000; - ir->polling = 50; // ms - break; - case BTTV_BOARD_NEBULA_DIGITV: - ir_codes = RC_MAP_NEBULA; - ir->rc5_gpio = true; - break; - case BTTV_BOARD_MACHTV_MAGICTV: - ir_codes = RC_MAP_APAC_VIEWCOMP; - ir->mask_keycode = 0x001F00; - ir->mask_keyup = 0x004000; - ir->polling = 50; /* ms */ - break; - case BTTV_BOARD_KOZUMI_KTV_01C: - ir_codes = RC_MAP_PCTV_SEDNA; - ir->mask_keycode = 0x001f00; - ir->mask_keyup = 0x006000; - ir->polling = 50; /* ms */ - break; - case BTTV_BOARD_ENLTV_FM_2: - ir_codes = RC_MAP_ENCORE_ENLTV2; - ir->mask_keycode = 0x00fd00; - ir->mask_keyup = 0x000080; - ir->polling = 1; /* ms */ - ir->last_gpio = ir_extract_bits(bttv_gpio_read(&btv->c), - ir->mask_keycode); - break; - } - if (NULL == ir_codes) { - dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type); - err = -ENODEV; - goto err_out_free; - } - - if (ir->rc5_gpio) { - u32 gpio; - /* enable remote irq */ - bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4); - gpio = bttv_gpio_read(&btv->c); - bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); - bttv_gpio_write(&btv->c, gpio | (1 << 4)); - } else { - /* init hardware-specific stuff */ - bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0); - } - - /* init input device */ - ir->dev = rc; - - snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", - btv->c.type); - snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", - pci_name(btv->c.pci)); - - rc->input_name = ir->name; - rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_PCI; - rc->input_id.version = 1; - if (btv->c.pci->subsystem_vendor) { - rc->input_id.vendor = btv->c.pci->subsystem_vendor; - rc->input_id.product = btv->c.pci->subsystem_device; - } else { - rc->input_id.vendor = btv->c.pci->vendor; - rc->input_id.product = btv->c.pci->device; - } - rc->dev.parent = &btv->c.pci->dev; - rc->map_name = ir_codes; - rc->driver_name = MODULE_NAME; - - btv->remote = ir; - bttv_ir_start(btv, ir); - - /* all done */ - err = rc_register_device(rc); - if (err) - goto err_out_stop; - - return 0; - - err_out_stop: - bttv_ir_stop(btv); - btv->remote = NULL; - err_out_free: - rc_free_device(rc); - kfree(ir); - return err; -} - -void bttv_input_fini(struct bttv *btv) -{ - if (btv->remote == NULL) - return; - - bttv_ir_stop(btv); - rc_unregister_device(btv->remote->dev); - kfree(btv->remote); - btv->remote = NULL; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttvp.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttvp.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttvp.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttvp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,525 +0,0 @@ -/* - - bttv - Bt848 frame grabber driver - - bttv's *private* header file -- nobody other than bttv itself - should ever include this file. - - (c) 2000-2002 Gerd Knorr - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _BTTVP_H_ -#define _BTTVP_H_ - -#include -#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,18) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bt848.h" -#include "bttv.h" -#include "btcx-risc.h" - -#ifdef __KERNEL__ - -#define FORMAT_FLAGS_DITHER 0x01 -#define FORMAT_FLAGS_PACKED 0x02 -#define FORMAT_FLAGS_PLANAR 0x04 -#define FORMAT_FLAGS_RAW 0x08 -#define FORMAT_FLAGS_CrCb 0x10 - -#define RISC_SLOT_O_VBI 4 -#define RISC_SLOT_O_FIELD 6 -#define RISC_SLOT_E_VBI 10 -#define RISC_SLOT_E_FIELD 12 -#define RISC_SLOT_LOOP 14 - -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO_STREAM 2 -#define RESOURCE_VBI 4 -#define RESOURCE_VIDEO_READ 8 - -#define RAW_LINES 640 -#define RAW_BPL 1024 - -#define UNSET (-1U) - -/* Min. value in VDELAY register. */ -#define MIN_VDELAY 2 -/* Even to get Cb first, odd for Cr. */ -#define MAX_HDELAY (0x3FF & -2) -/* Limits scaled width, which must be a multiple of 4. */ -#define MAX_HACTIVE (0x3FF & -4) - -#define BTTV_NORMS (\ - V4L2_STD_PAL | V4L2_STD_PAL_N | \ - V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ - V4L2_STD_NTSC | V4L2_STD_PAL_M | \ - V4L2_STD_PAL_60) -/* ---------------------------------------------------------- */ - -struct bttv_tvnorm { - int v4l2_id; - char *name; - u32 Fsc; - u16 swidth, sheight; /* scaled standard width, height */ - u16 totalwidth; - u8 adelay, bdelay, iform; - u32 scaledtwidth; - u16 hdelayx1, hactivex1; - u16 vdelay; - u8 vbipack; - u16 vtotal; - int sram; - /* ITU-R frame line number of the first VBI line we can - capture, of the first and second field. The last possible line - is determined by cropcap.bounds. */ - u16 vbistart[2]; - /* Horizontally this counts fCLKx1 samples following the leading - edge of the horizontal sync pulse, vertically ITU-R frame line - numbers of the first field times two (2, 4, 6, ... 524 or 624). */ - struct v4l2_cropcap cropcap; -}; -extern const struct bttv_tvnorm bttv_tvnorms[]; - -struct bttv_format { - char *name; - int fourcc; /* video4linux 2 */ - int btformat; /* BT848_COLOR_FMT_* */ - int btswap; /* BT848_COLOR_CTL_* */ - int depth; /* bit/pixel */ - int flags; - int hshift,vshift; /* for planar modes */ -}; - -struct bttv_ir { - struct rc_dev *dev; - struct timer_list timer; - - char name[32]; - char phys[32]; - - /* Usual gpio signalling */ - u32 mask_keycode; - u32 mask_keydown; - u32 mask_keyup; - u32 polling; - u32 last_gpio; - int shift_by; - int start; // What should RC5_START() be - int addr; // What RC5_ADDR() should be. - int rc5_remote_gap; - - /* RC5 gpio */ - bool rc5_gpio; /* Is RC5 legacy GPIO enabled? */ - u32 last_bit; /* last raw bit seen */ - u32 code; /* raw code under construction */ - struct timeval base_time; /* time of last seen code */ - bool active; /* building raw code */ -}; - - -/* ---------------------------------------------------------- */ - -struct bttv_geometry { - u8 vtc,crop,comb; - u16 width,hscale,hdelay; - u16 sheight,vscale,vdelay,vtotal; -}; - -struct bttv_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* bttv specific */ - const struct bttv_format *fmt; - unsigned int tvnorm; - int btformat; - int btswap; - struct bttv_geometry geo; - struct btcx_riscmem top; - struct btcx_riscmem bottom; - struct v4l2_rect crop; - unsigned int vbi_skip[2]; - unsigned int vbi_count[2]; -}; - -struct bttv_buffer_set { - struct bttv_buffer *top; /* top field buffer */ - struct bttv_buffer *bottom; /* bottom field buffer */ - unsigned int top_irq; - unsigned int frame_irq; -}; - -struct bttv_overlay { - unsigned int tvnorm; - struct v4l2_rect w; - enum v4l2_field field; - struct v4l2_clip *clips; - int nclips; - int setup_ok; -}; - -struct bttv_vbi_fmt { - struct v4l2_vbi_format fmt; - - /* fmt.start[] and count[] refer to this video standard. */ - const struct bttv_tvnorm *tvnorm; - - /* Earliest possible start of video capturing with this - v4l2_vbi_format, in struct bttv_crop.rect units. */ - __s32 end; -}; - -/* bttv-vbi.c */ -void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm); - -struct bttv_crop { - /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */ - struct v4l2_rect rect; - - /* Scaled image size limits with this crop rect. Divide - max_height, but not min_height, by two when capturing - single fields. See also bttv_crop_reset() and - bttv_crop_adjust() in bttv-driver.c. */ - __s32 min_scaled_width; - __s32 min_scaled_height; - __s32 max_scaled_width; - __s32 max_scaled_height; -}; - -struct bttv_fh { - struct bttv *btv; - int resources; -#ifdef VIDIOC_G_PRIORITY - enum v4l2_priority prio; -#endif - enum v4l2_buf_type type; - - /* video capture */ - struct videobuf_queue cap; - const struct bttv_format *fmt; - int width; - int height; - - /* video overlay */ - const struct bttv_format *ovfmt; - struct bttv_overlay ov; - - /* Application called VIDIOC_S_CROP. */ - int do_crop; - - /* vbi capture */ - struct videobuf_queue vbi; - /* Current VBI capture window as seen through this fh (cannot - be global for compatibility with earlier drivers). Protected - by struct bttv.lock and struct bttv_fh.vbi.lock. */ - struct bttv_vbi_fmt vbi_fmt; -}; - -/* ---------------------------------------------------------- */ -/* bttv-risc.c */ - -/* risc code generators - capture */ -int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int offset, unsigned int bpl, - unsigned int pitch, unsigned int skip_lines, - unsigned int store_lines); - -/* control dma register + risc main loop */ -void bttv_set_dma(struct bttv *btv, int override); -int bttv_risc_init_main(struct bttv *btv); -int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, - int irqflags); - -/* capture buffer handling */ -int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); -int bttv_buffer_activate_video(struct bttv *btv, - struct bttv_buffer_set *set); -int bttv_buffer_activate_vbi(struct bttv *btv, - struct bttv_buffer *vbi); -void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, - struct bttv_buffer *buf); - -/* overlay handling */ -int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, - const struct bttv_format *fmt, - struct bttv_buffer *buf); - - -/* ---------------------------------------------------------- */ -/* bttv-vbi.c */ - -int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); -int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); -int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); - -extern struct videobuf_queue_ops bttv_vbi_qops; - -/* ---------------------------------------------------------- */ -/* bttv-gpio.c */ - -extern struct bus_type bttv_sub_bus_type; -int bttv_sub_add_device(struct bttv_core *core, char *name); -int bttv_sub_del_devices(struct bttv_core *core); - -/* ---------------------------------------------------------- */ -/* bttv-cards.c */ - -extern int no_overlay; - -/* ---------------------------------------------------------- */ -/* bttv-input.c */ - -extern void init_bttv_i2c_ir(struct bttv *btv); -extern int fini_bttv_i2c(struct bttv *btv); - -/* ---------------------------------------------------------- */ -/* bttv-driver.c */ - -/* insmod options */ -extern unsigned int bttv_verbose; -extern unsigned int bttv_debug; -extern unsigned int bttv_gpio; -extern void bttv_gpio_tracking(struct bttv *btv, char *comment); -extern int init_bttv_i2c(struct bttv *btv); - -#define bttv_printk if (bttv_verbose) printk -#define dprintk if (bttv_debug >= 1) printk -#define d2printk if (bttv_debug >= 2) printk - -#define BTTV_MAX_FBUF 0x208000 -#define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ -#define BTTV_FREE_IDLE msecs_to_jiffies(1000) /* one second */ - - -struct bttv_pll_info { - unsigned int pll_ifreq; /* PLL input frequency */ - unsigned int pll_ofreq; /* PLL output frequency */ - unsigned int pll_crystal; /* Crystal used for input */ - unsigned int pll_current; /* Currently programmed ofreq */ -}; - -/* for gpio-connected remote control */ -struct bttv_input { - struct input_dev *dev; - char name[32]; - char phys[32]; - u32 mask_keycode; - u32 mask_keydown; -}; - -struct bttv_suspend_state { - u32 gpio_enable; - u32 gpio_data; - int disabled; - int loop_irq; - struct bttv_buffer_set video; - struct bttv_buffer *vbi; -}; - -struct bttv { - struct bttv_core c; - - /* pci device config */ - unsigned short id; - unsigned char revision; - unsigned char __iomem *bt848_mmio; /* pointer to mmio */ - - /* card configuration info */ - unsigned int cardid; /* pci subsystem id (bt878 based ones) */ - unsigned int tuner_type; /* tuner chip type */ - unsigned int tda9887_conf; - unsigned int svhs, dig; - unsigned int has_saa6588:1; - struct bttv_pll_info pll; - int triton1; - int gpioirq; - - int use_i2c_hw; - - /* old gpio interface */ - int shutdown; - - void (*volume_gpio)(struct bttv *btv, __u16 volume); - void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); - - /* new gpio interface */ - spinlock_t gpio_lock; - - /* i2c layer */ - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - int i2c_state, i2c_rc; - int i2c_done; - wait_queue_head_t i2c_queue; - struct v4l2_subdev *sd_msp34xx; - struct v4l2_subdev *sd_tvaudio; - - /* video4linux (1) */ - struct video_device *video_dev; - struct video_device *radio_dev; - struct video_device *vbi_dev; - - /* infrared remote */ - int has_remote; - struct bttv_ir *remote; - - /* I2C remote data */ - struct IR_i2c_init_data init_data; - - /* locking */ - spinlock_t s_lock; - struct mutex lock; - int resources; -#ifdef VIDIOC_G_PRIORITY - struct v4l2_prio_state prio; -#endif - - /* video state */ - unsigned int input; - unsigned int audio; - unsigned int mute; - unsigned long freq; - unsigned int tvnorm; - int hue, contrast, bright, saturation; - struct v4l2_framebuffer fbuf; - unsigned int field_count; - - /* various options */ - int opt_combfilter; - int opt_lumafilter; - int opt_automute; - int opt_chroma_agc; - int opt_adc_crush; - int opt_vcr_hack; - int opt_whitecrush_upper; - int opt_whitecrush_lower; - int opt_uv_ratio; - int opt_full_luma_range; - int opt_coring; - - /* radio data/state */ - int has_radio; - int radio_user; - - /* miro/pinnacle + Aimslab VHX - philips matchbox (tea5757 radio tuner) support */ - int has_matchbox; - int mbox_we; - int mbox_data; - int mbox_clk; - int mbox_most; - int mbox_mask; - - /* ISA stuff (Terratec Active Radio Upgrade) */ - int mbox_ior; - int mbox_iow; - int mbox_csel; - - /* risc memory management data - - must acquire s_lock before changing these - - only the irq handler is supported to touch top + bottom + vcurr */ - struct btcx_riscmem main; - struct bttv_buffer *screen; /* overlay */ - struct list_head capture; /* video capture queue */ - struct list_head vcapture; /* vbi capture queue */ - struct bttv_buffer_set curr; /* active buffers */ - struct bttv_buffer *cvbi; /* active vbi buffer */ - int loop_irq; - int new_input; - - unsigned long cap_ctl; - unsigned long dma_on; - struct timer_list timeout; - struct bttv_suspend_state state; - - /* stats */ - unsigned int errors; - unsigned int framedrop; - unsigned int irq_total; - unsigned int irq_me; - - unsigned int users; - struct bttv_fh init; - - /* used to make dvb-bt8xx autoloadable */ - struct work_struct request_module_wk; - - /* Default (0) and current (1) video capturing and overlay - cropping parameters in bttv_tvnorm.cropcap units. Protected - by bttv.lock. */ - struct bttv_crop crop[2]; - - /* Earliest possible start of video capturing in - bttv_tvnorm.cropcap line units. Set by check_alloc_btres() - and free_btres(). Protected by bttv.lock. */ - __s32 vbi_end; - - /* Latest possible end of VBI capturing (= crop[x].rect.top when - VIDEO_RESOURCES are locked). Set by check_alloc_btres() - and free_btres(). Protected by bttv.lock. */ - __s32 crop_start; -}; - -static inline struct bttv *to_bttv(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct bttv, c.v4l2_dev); -} - -/* our devices */ -#define BTTV_MAX 32 -extern unsigned int bttv_num; -extern struct bttv *bttvs[BTTV_MAX]; - -static inline unsigned int bttv_muxsel(const struct bttv *btv, - unsigned int input) -{ - return (bttv_tvcards[btv->c.type].muxsel >> (input * 2)) & 3; -} - -#endif - -#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) -#define btread(adr) readl(btv->bt848_mmio+(adr)) - -#define btand(dat,adr) btwrite((dat) & btread(adr), adr) -#define btor(dat,adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) - -#endif /* _BTTVP_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-risc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-risc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-risc.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-risc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,910 +0,0 @@ -/* - - bttv-risc.c -- interfaces to other kernel modules - - bttv risc code handling - - memory management - - generation - - (c) 2000-2003 Gerd Knorr - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttvp.h" - -#define VCR_HACK_LINES 4 - -/* ---------------------------------------------------------- */ -/* risc code generators */ - -int -bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int offset, unsigned int bpl, - unsigned int padding, unsigned int skip_lines, - unsigned int store_lines) -{ - u32 instructions,line,todo; - struct scatterlist *sg; - __le32 *rp; - int rc; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + sync + jump (all 2 dwords). padding - can cause next bpl to start close to a page border. First DMA - region may be smaller than PAGE_SIZE */ - instructions = skip_lines * 4; - instructions += (1 + ((bpl + padding) * store_lines) - / PAGE_SIZE + store_lines) * 8; - instructions += 2 * 8; - if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0) - return rc; - - /* sync instruction */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(rp++) = cpu_to_le32(0); - - while (skip_lines-- > 0) { - *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL | - BT848_RISC_EOL | bpl); - } - - /* scan lines */ - sg = sglist; - for (line = 0; line < store_lines; line++) { - if ((btv->opt_vcr_hack) && - (line >= (store_lines - VCR_HACK_LINES))) - continue; - while (offset && offset >= sg_dma_len(sg)) { - offset -= sg_dma_len(sg); - sg++; - } - if (bpl <= sg_dma_len(sg)-offset) { - /* fits into current chunk */ - *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| - BT848_RISC_EOL|bpl); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); - offset+=bpl; - } else { - /* scanline needs to be splitted */ - todo = bpl; - *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| - (sg_dma_len(sg)-offset)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); - todo -= (sg_dma_len(sg)-offset); - offset = 0; - sg++; - while (todo > sg_dma_len(sg)) { - *(rp++)=cpu_to_le32(BT848_RISC_WRITE| - sg_dma_len(sg)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); - todo -= sg_dma_len(sg); - sg++; - } - *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL| - todo); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); - offset += todo; - } - offset += padding; - } - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - return 0; -} - -static int -bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int yoffset, unsigned int ybpl, - unsigned int ypadding, unsigned int ylines, - unsigned int uoffset, unsigned int voffset, - unsigned int hshift, unsigned int vshift, - unsigned int cpadding) -{ - unsigned int instructions,line,todo,ylen,chroma; - __le32 *rp; - u32 ri; - struct scatterlist *ysg; - struct scatterlist *usg; - struct scatterlist *vsg; - int topfield = (0 == yoffset); - int rc; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line (5 dwords) - plus sync + jump (2 dwords) */ - instructions = ((3 + (ybpl + ypadding) * ylines * 2) - / PAGE_SIZE) + ylines; - instructions += 2; - if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0) - return rc; - - /* sync instruction */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); - *(rp++) = cpu_to_le32(0); - - /* scan lines */ - ysg = sglist; - usg = sglist; - vsg = sglist; - for (line = 0; line < ylines; line++) { - if ((btv->opt_vcr_hack) && - (line >= (ylines - VCR_HACK_LINES))) - continue; - switch (vshift) { - case 0: - chroma = 1; - break; - case 1: - if (topfield) - chroma = ((line & 1) == 0); - else - chroma = ((line & 1) == 1); - break; - case 2: - if (topfield) - chroma = ((line & 3) == 0); - else - chroma = ((line & 3) == 2); - break; - default: - chroma = 0; - break; - } - - for (todo = ybpl; todo > 0; todo -= ylen) { - /* go to next sg entry if needed */ - while (yoffset && yoffset >= sg_dma_len(ysg)) { - yoffset -= sg_dma_len(ysg); - ysg++; - } - while (uoffset && uoffset >= sg_dma_len(usg)) { - uoffset -= sg_dma_len(usg); - usg++; - } - while (voffset && voffset >= sg_dma_len(vsg)) { - voffset -= sg_dma_len(vsg); - vsg++; - } - - /* calculate max number of bytes we can write */ - ylen = todo; - if (yoffset + ylen > sg_dma_len(ysg)) - ylen = sg_dma_len(ysg) - yoffset; - if (chroma) { - if (uoffset + (ylen>>hshift) > sg_dma_len(usg)) - ylen = (sg_dma_len(usg) - uoffset) << hshift; - if (voffset + (ylen>>hshift) > sg_dma_len(vsg)) - ylen = (sg_dma_len(vsg) - voffset) << hshift; - ri = BT848_RISC_WRITE123; - } else { - ri = BT848_RISC_WRITE1S23; - } - if (ybpl == todo) - ri |= BT848_RISC_SOL; - if (ylen == todo) - ri |= BT848_RISC_EOL; - - /* write risc instruction */ - *(rp++)=cpu_to_le32(ri | ylen); - *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) | - (ylen >> hshift)); - *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset); - yoffset += ylen; - if (chroma) { - *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset); - uoffset += ylen >> hshift; - *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset); - voffset += ylen >> hshift; - } - } - yoffset += ypadding; - if (chroma) { - uoffset += cpadding; - voffset += cpadding; - } - } - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - return 0; -} - -static int -bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, - const struct bttv_format *fmt, struct bttv_overlay *ov, - int skip_even, int skip_odd) -{ - int dwords, rc, line, maxy, start, end; - unsigned skip, nskips; - struct btcx_skiplist *skips; - __le32 *rp; - u32 ri,ra; - u32 addr; - - /* skip list for window clipping */ - if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL))) - return -ENOMEM; - - /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions - + sync + jump (all 2 dwords) */ - dwords = (3 * ov->nclips + 2) * - ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height); - dwords += 4; - if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) { - kfree(skips); - return rc; - } - - /* sync instruction */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(rp++) = cpu_to_le32(0); - - addr = (unsigned long)btv->fbuf.base; - addr += btv->fbuf.fmt.bytesperline * ov->w.top; - addr += (fmt->depth >> 3) * ov->w.left; - - /* scan lines */ - for (maxy = -1, line = 0; line < ov->w.height; - line++, addr += btv->fbuf.fmt.bytesperline) { - if ((btv->opt_vcr_hack) && - (line >= (ov->w.height - VCR_HACK_LINES))) - continue; - if ((line%2) == 0 && skip_even) - continue; - if ((line%2) == 1 && skip_odd) - continue; - - /* calculate clipping */ - if (line > maxy) - btcx_calc_skips(line, ov->w.width, &maxy, - skips, &nskips, ov->clips, ov->nclips); - - /* write out risc code */ - for (start = 0, skip = 0; start < ov->w.width; start = end) { - if (skip >= nskips) { - ri = BT848_RISC_WRITE; - end = ov->w.width; - } else if (start < skips[skip].start) { - ri = BT848_RISC_WRITE; - end = skips[skip].start; - } else { - ri = BT848_RISC_SKIP; - end = skips[skip].end; - skip++; - } - if (BT848_RISC_WRITE == ri) - ra = addr + (fmt->depth>>3)*start; - else - ra = 0; - - if (0 == start) - ri |= BT848_RISC_SOL; - if (ov->w.width == end) - ri |= BT848_RISC_EOL; - ri |= (fmt->depth>>3) * (end-start); - - *(rp++)=cpu_to_le32(ri); - if (0 != ra) - *(rp++)=cpu_to_le32(ra); - } - } - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - kfree(skips); - return 0; -} - -/* ---------------------------------------------------------- */ - -static void -bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo, - int width, int height, int interleaved, - const struct bttv_tvnorm *tvnorm) -{ - u32 xsf, sr; - int vdelay; - - int swidth = tvnorm->swidth; - int totalwidth = tvnorm->totalwidth; - int scaledtwidth = tvnorm->scaledtwidth; - - if (btv->input == btv->dig) { - swidth = 720; - totalwidth = 858; - scaledtwidth = 858; - } - - vdelay = tvnorm->vdelay; - - xsf = (width*scaledtwidth)/swidth; - geo->hscale = ((totalwidth*4096UL)/xsf-4096); - geo->hdelay = tvnorm->hdelayx1; - geo->hdelay = (geo->hdelay*width)/swidth; - geo->hdelay &= 0x3fe; - sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512; - geo->vscale = (0x10000UL-sr) & 0x1fff; - geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) | - ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0); - geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0; - geo->vdelay = vdelay; - geo->width = width; - geo->sheight = tvnorm->sheight; - geo->vtotal = tvnorm->vtotal; - - if (btv->opt_combfilter) { - geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); - geo->comb = (width < 769) ? 1 : 0; - } else { - geo->vtc = 0; - geo->comb = 0; - } -} - -static void -bttv_calc_geo (struct bttv * btv, - struct bttv_geometry * geo, - unsigned int width, - unsigned int height, - int both_fields, - const struct bttv_tvnorm * tvnorm, - const struct v4l2_rect * crop) -{ - unsigned int c_width; - unsigned int c_height; - u32 sr; - - if ((crop->left == tvnorm->cropcap.defrect.left - && crop->top == tvnorm->cropcap.defrect.top - && crop->width == tvnorm->cropcap.defrect.width - && crop->height == tvnorm->cropcap.defrect.height - && width <= tvnorm->swidth /* see PAL-Nc et al */) - || btv->input == btv->dig) { - bttv_calc_geo_old(btv, geo, width, height, - both_fields, tvnorm); - return; - } - - /* For bug compatibility the image size checks permit scale - factors > 16. See bttv_crop_calc_limits(). */ - c_width = min((unsigned int) crop->width, width * 16); - c_height = min((unsigned int) crop->height, height * 16); - - geo->width = width; - geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096; - /* Even to store Cb first, odd for Cr. */ - geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1; - - geo->sheight = c_height; - geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY; - sr = c_height >> !both_fields; - sr = (sr * 512U + (height >> 1)) / height - 512; - geo->vscale = (0x10000UL - sr) & 0x1fff; - geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0; - geo->vtotal = tvnorm->vtotal; - - geo->crop = (((geo->width >> 8) & 0x03) | - ((geo->hdelay >> 6) & 0x0c) | - ((geo->sheight >> 4) & 0x30) | - ((geo->vdelay >> 2) & 0xc0)); - - if (btv->opt_combfilter) { - geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); - geo->comb = (width < 769) ? 1 : 0; - } else { - geo->vtc = 0; - geo->comb = 0; - } -} - -static void -bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd) -{ - int off = odd ? 0x80 : 0x00; - - if (geo->comb) - btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); - else - btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); - - btwrite(geo->vtc, BT848_E_VTC+off); - btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off); - btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off); - btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); - btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off); - btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off); - btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off); - btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off); - btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off); - btwrite(geo->crop, BT848_E_CROP+off); - btwrite(geo->vtotal>>8, BT848_VTOTAL_HI); - btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO); -} - -/* ---------------------------------------------------------- */ -/* risc group / risc main loop / dma management */ - -void -bttv_set_dma(struct bttv *btv, int override) -{ - unsigned long cmd; - int capctl; - - btv->cap_ctl = 0; - if (NULL != btv->curr.top) btv->cap_ctl |= 0x02; - if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01; - if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c; - - capctl = 0; - capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */ - capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */ - capctl |= override; - - d2printk(KERN_DEBUG - "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n", - btv->c.nr,capctl,btv->loop_irq, - btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, - btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, - btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0, - btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); - - cmd = BT848_RISC_JUMP; - if (btv->loop_irq) { - cmd |= BT848_RISC_IRQ; - cmd |= (btv->loop_irq & 0x0f) << 16; - cmd |= (~btv->loop_irq & 0x0f) << 20; - } - if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) { - mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT); - } else { - del_timer(&btv->timeout); - } - btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd); - - btaor(capctl, ~0x0f, BT848_CAP_CTL); - if (capctl) { - if (btv->dma_on) - return; - btwrite(btv->main.dma, BT848_RISC_STRT_ADD); - btor(3, BT848_GPIO_DMA_CTL); - btv->dma_on = 1; - } else { - if (!btv->dma_on) - return; - btand(~3, BT848_GPIO_DMA_CTL); - btv->dma_on = 0; - } - return; -} - -int -bttv_risc_init_main(struct bttv *btv) -{ - int rc; - - if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0) - return rc; - dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n", - btv->c.nr,(unsigned long long)btv->main.dma); - - btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | - BT848_FIFO_STATUS_VRE); - btv->main.cpu[1] = cpu_to_le32(0); - btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2)); - - /* top field */ - btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2)); - btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2)); - - btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | - BT848_FIFO_STATUS_VRO); - btv->main.cpu[9] = cpu_to_le32(0); - - /* bottom field */ - btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2)); - btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2)); - - /* jump back to top field */ - btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2)); - - return 0; -} - -int -bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, - int irqflags) -{ - unsigned long cmd; - unsigned long next = btv->main.dma + ((slot+2) << 2); - - if (NULL == risc) { - d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n", - btv->c.nr,risc,slot); - btv->main.cpu[slot+1] = cpu_to_le32(next); - } else { - d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n", - btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags); - cmd = BT848_RISC_JUMP; - if (irqflags) { - cmd |= BT848_RISC_IRQ; - cmd |= (irqflags & 0x0f) << 16; - cmd |= (~irqflags & 0x0f) << 20; - } - risc->jmp[0] = cpu_to_le32(cmd); - risc->jmp[1] = cpu_to_le32(next); - btv->main.cpu[slot+1] = cpu_to_le32(risc->dma); - } - return 0; -} - -void -bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf) -{ - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(btv->c.pci,&buf->bottom); - btcx_riscmem_free(btv->c.pci,&buf->top); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -int -bttv_buffer_activate_vbi(struct bttv *btv, - struct bttv_buffer *vbi) -{ - struct btcx_riscmem *top; - struct btcx_riscmem *bottom; - int top_irq_flags; - int bottom_irq_flags; - - top = NULL; - bottom = NULL; - top_irq_flags = 0; - bottom_irq_flags = 0; - - if (vbi) { - unsigned int crop, vdelay; - - vbi->vb.state = VIDEOBUF_ACTIVE; - list_del(&vbi->vb.queue); - - /* VDELAY is start of video, end of VBI capturing. */ - crop = btread(BT848_E_CROP); - vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2); - - if (vbi->geo.vdelay > vdelay) { - vdelay = vbi->geo.vdelay & 0xfe; - crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0); - - btwrite(vdelay, BT848_E_VDELAY_LO); - btwrite(crop, BT848_E_CROP); - btwrite(vdelay, BT848_O_VDELAY_LO); - btwrite(crop, BT848_O_CROP); - } - - if (vbi->vbi_count[0] > 0) { - top = &vbi->top; - top_irq_flags = 4; - } - - if (vbi->vbi_count[1] > 0) { - top_irq_flags = 0; - bottom = &vbi->bottom; - bottom_irq_flags = 4; - } - } - - bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags); - bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags); - - return 0; -} - -int -bttv_buffer_activate_video(struct bttv *btv, - struct bttv_buffer_set *set) -{ - /* video capture */ - if (NULL != set->top && NULL != set->bottom) { - if (set->top == set->bottom) { - set->top->vb.state = VIDEOBUF_ACTIVE; - if (set->top->vb.queue.next) - list_del(&set->top->vb.queue); - } else { - set->top->vb.state = VIDEOBUF_ACTIVE; - set->bottom->vb.state = VIDEOBUF_ACTIVE; - if (set->top->vb.queue.next) - list_del(&set->top->vb.queue); - if (set->bottom->vb.queue.next) - list_del(&set->bottom->vb.queue); - } - bttv_apply_geo(btv, &set->top->geo, 1); - bttv_apply_geo(btv, &set->bottom->geo,0); - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, - set->top_irq); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, - set->frame_irq); - btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f), - ~0xff, BT848_COLOR_FMT); - btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), - ~0x0f, BT848_COLOR_CTL); - } else if (NULL != set->top) { - set->top->vb.state = VIDEOBUF_ACTIVE; - if (set->top->vb.queue.next) - list_del(&set->top->vb.queue); - bttv_apply_geo(btv, &set->top->geo,1); - bttv_apply_geo(btv, &set->top->geo,0); - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, - set->frame_irq); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); - btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); - btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); - } else if (NULL != set->bottom) { - set->bottom->vb.state = VIDEOBUF_ACTIVE; - if (set->bottom->vb.queue.next) - list_del(&set->bottom->vb.queue); - bttv_apply_geo(btv, &set->bottom->geo,1); - bttv_apply_geo(btv, &set->bottom->geo,0); - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, - set->frame_irq); - btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT); - btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); - } else { - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); - } - return 0; -} - -/* ---------------------------------------------------------- */ - -/* calculate geometry, build risc code */ -int -bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) -{ - const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - dprintk(KERN_DEBUG - "bttv%d: buffer field: %s format: %s size: %dx%d\n", - btv->c.nr, v4l2_field_names[buf->vb.field], - buf->fmt->name, buf->vb.width, buf->vb.height); - - /* packed pixel modes */ - if (buf->fmt->flags & FORMAT_FLAGS_PACKED) { - int bpl = (buf->fmt->depth >> 3) * buf->vb.width; - int bpf = bpl * (buf->vb.height >> 1); - - bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height, - V4L2_FIELD_HAS_BOTH(buf->vb.field), - tvnorm,&buf->crop); - - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - bttv_risc_packed(btv,&buf->top,dma->sglist, - /* offset */ 0,bpl, - /* padding */ 0,/* skip_lines */ 0, - buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - bttv_risc_packed(btv,&buf->bottom,dma->sglist, - 0,bpl,0,0,buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - bttv_risc_packed(btv,&buf->top,dma->sglist, - 0,bpl,bpl,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,dma->sglist, - bpl,bpl,bpl,0,buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - bttv_risc_packed(btv,&buf->top,dma->sglist, - 0,bpl,0,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,dma->sglist, - bpf,bpl,0,0,buf->vb.height >> 1); - break; - default: - BUG(); - } - } - - /* planar modes */ - if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) { - int uoffset, voffset; - int ypadding, cpadding, lines; - - /* calculate chroma offsets */ - uoffset = buf->vb.width * buf->vb.height; - voffset = buf->vb.width * buf->vb.height; - if (buf->fmt->flags & FORMAT_FLAGS_CrCb) { - /* Y-Cr-Cb plane order */ - uoffset >>= buf->fmt->hshift; - uoffset >>= buf->fmt->vshift; - uoffset += voffset; - } else { - /* Y-Cb-Cr plane order */ - voffset >>= buf->fmt->hshift; - voffset >>= buf->fmt->vshift; - voffset += uoffset; - } - - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,/* both_fields */ 0, - tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->top, dma->sglist, - 0,buf->vb.width,0,buf->vb.height, - uoffset,voffset,buf->fmt->hshift, - buf->fmt->vshift,0); - break; - case V4L2_FIELD_BOTTOM: - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,0, - tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->bottom, dma->sglist, - 0,buf->vb.width,0,buf->vb.height, - uoffset,voffset,buf->fmt->hshift, - buf->fmt->vshift,0); - break; - case V4L2_FIELD_INTERLACED: - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,1, - tvnorm,&buf->crop); - lines = buf->vb.height >> 1; - ypadding = buf->vb.width; - cpadding = buf->vb.width >> buf->fmt->hshift; - bttv_risc_planar(btv,&buf->top, - dma->sglist, - 0,buf->vb.width,ypadding,lines, - uoffset,voffset, - buf->fmt->hshift, - buf->fmt->vshift, - cpadding); - bttv_risc_planar(btv,&buf->bottom, - dma->sglist, - ypadding,buf->vb.width,ypadding,lines, - uoffset+cpadding, - voffset+cpadding, - buf->fmt->hshift, - buf->fmt->vshift, - cpadding); - break; - case V4L2_FIELD_SEQ_TB: - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,1, - tvnorm,&buf->crop); - lines = buf->vb.height >> 1; - ypadding = buf->vb.width; - cpadding = buf->vb.width >> buf->fmt->hshift; - bttv_risc_planar(btv,&buf->top, - dma->sglist, - 0,buf->vb.width,0,lines, - uoffset >> 1, - voffset >> 1, - buf->fmt->hshift, - buf->fmt->vshift, - 0); - bttv_risc_planar(btv,&buf->bottom, - dma->sglist, - lines * ypadding,buf->vb.width,0,lines, - lines * ypadding + (uoffset >> 1), - lines * ypadding + (voffset >> 1), - buf->fmt->hshift, - buf->fmt->vshift, - 0); - break; - default: - BUG(); - } - } - - /* raw data */ - if (buf->fmt->flags & FORMAT_FLAGS_RAW) { - /* build risc code */ - buf->vb.field = V4L2_FIELD_SEQ_TB; - bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, - 1,tvnorm,&buf->crop); - bttv_risc_packed(btv, &buf->top, dma->sglist, - /* offset */ 0, RAW_BPL, /* padding */ 0, - /* skip_lines */ 0, RAW_LINES); - bttv_risc_packed(btv, &buf->bottom, dma->sglist, - buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); - } - - /* copy format info */ - buf->btformat = buf->fmt->btformat; - buf->btswap = buf->fmt->btswap; - return 0; -} - -/* ---------------------------------------------------------- */ - -/* calculate geometry, build risc code */ -int -bttv_overlay_risc(struct bttv *btv, - struct bttv_overlay *ov, - const struct bttv_format *fmt, - struct bttv_buffer *buf) -{ - /* check interleave, bottom+top fields */ - dprintk(KERN_DEBUG - "bttv%d: overlay fields: %s format: %s size: %dx%d\n", - btv->c.nr, v4l2_field_names[buf->vb.field], - fmt->name,ov->w.width,ov->w.height); - - /* calculate geometry */ - bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, - V4L2_FIELD_HAS_BOTH(ov->field), - &bttv_tvnorms[ov->tvnorm],&buf->crop); - - /* build risc code */ - switch (ov->field) { - case V4L2_FIELD_TOP: - bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0); - break; - case V4L2_FIELD_BOTTOM: - bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0); - break; - case V4L2_FIELD_INTERLACED: - bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1); - bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0); - break; - default: - BUG(); - } - - /* copy format info */ - buf->btformat = fmt->btformat; - buf->btswap = fmt->btswap; - buf->vb.field = ov->field; - return 0; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-vbi.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/bttv-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,454 +0,0 @@ -/* - - bttv - Bt848 frame grabber driver - vbi interface - - (c) 2002 Gerd Knorr - - Copyright (C) 2005, 2006 Michael H. Schimek - Sponsored by OPQ Systems AB - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "bttvp.h" - -/* Offset from line sync pulse leading edge (0H) to start of VBI capture, - in fCLKx2 pixels. According to the datasheet, VBI capture starts - VBI_HDELAY fCLKx1 pixels from the tailing edgeof /HRESET, and /HRESET - is 64 fCLKx1 pixels wide. VBI_HDELAY is set to 0, so this should be - (64 + 0) * 2 = 128 fCLKx2 pixels. But it's not! The datasheet is - Just Plain Wrong. The real value appears to be different for - different revisions of the bt8x8 chips, and to be affected by the - horizontal scaling factor. Experimentally, the value is measured - to be about 244. */ -#define VBI_OFFSET 244 - -/* 2048 for compatibility with earlier driver versions. The driver - really stores 1024 + tvnorm->vbipack * 4 samples per line in the - buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI - is 0x1FF DWORDs) and VBI read()s store a frame counter in the last - four bytes of the VBI image. */ -#define VBI_BPL 2048 - -/* Compatibility. */ -#define VBI_DEFLINES 16 - -static unsigned int vbibufs = 4; -static unsigned int vbi_debug; - -module_param(vbibufs, int, 0444); -module_param(vbi_debug, int, 0644); -MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4"); -MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)"); - -#ifdef dprintk -# undef dprintk -#endif -#define dprintk(fmt, arg...) if (vbi_debug) \ - printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg) - -#define IMAGE_SIZE(fmt) \ - (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line) - -/* ----------------------------------------------------------------------- */ -/* vbi risc code + mm */ - -static int vbi_buffer_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) -{ - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - - if (0 == *count) - *count = vbibufs; - - *size = IMAGE_SIZE(&fh->vbi_fmt.fmt); - - dprintk("setup: samples=%u start=%d,%d count=%u,%u\n", - fh->vbi_fmt.fmt.samples_per_line, - fh->vbi_fmt.fmt.start[0], - fh->vbi_fmt.fmt.start[1], - fh->vbi_fmt.fmt.count[0], - fh->vbi_fmt.fmt.count[1]); - - return 0; -} - -static int vbi_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - const struct bttv_tvnorm *tvnorm; - unsigned int skip_lines0, skip_lines1, min_vdelay; - int redo_dma_risc; - int rc; - - buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt); - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - tvnorm = fh->vbi_fmt.tvnorm; - - /* There's no VBI_VDELAY register, RISC must skip the lines - we don't want. With default parameters we skip zero lines - as earlier driver versions did. The driver permits video - standard changes while capturing, so we use vbi_fmt.tvnorm - instead of btv->tvnorm to skip zero lines after video - standard changes as well. */ - - skip_lines0 = 0; - skip_lines1 = 0; - - if (fh->vbi_fmt.fmt.count[0] > 0) - skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0] - - tvnorm->vbistart[0])); - if (fh->vbi_fmt.fmt.count[1] > 0) - skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1] - - tvnorm->vbistart[1])); - - redo_dma_risc = 0; - - if (buf->vbi_skip[0] != skip_lines0 || - buf->vbi_skip[1] != skip_lines1 || - buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] || - buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) { - buf->vbi_skip[0] = skip_lines0; - buf->vbi_skip[1] = skip_lines1; - buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0]; - buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1]; - redo_dma_risc = 1; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - redo_dma_risc = 1; - if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) - goto fail; - } - - if (redo_dma_risc) { - unsigned int bpl, padding, offset; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - bpl = 2044; /* max. vbipack */ - padding = VBI_BPL - bpl; - - if (fh->vbi_fmt.fmt.count[0] > 0) { - rc = bttv_risc_packed(btv, &buf->top, - dma->sglist, - /* offset */ 0, bpl, - padding, skip_lines0, - fh->vbi_fmt.fmt.count[0]); - if (0 != rc) - goto fail; - } - - if (fh->vbi_fmt.fmt.count[1] > 0) { - offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL; - - rc = bttv_risc_packed(btv, &buf->bottom, - dma->sglist, - offset, bpl, - padding, skip_lines1, - fh->vbi_fmt.fmt.count[1]); - if (0 != rc) - goto fail; - } - } - - /* VBI capturing ends at VDELAY, start of video capturing, - no matter where the RISC program ends. VDELAY minimum is 2, - bounds.top is the corresponding first field line number - times two. VDELAY counts half field lines. */ - min_vdelay = MIN_VDELAY; - if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top) - min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top; - - /* For bttv_buffer_activate_vbi(). */ - buf->geo.vdelay = min_vdelay; - - buf->vb.state = VIDEOBUF_PREPARED; - buf->vb.field = field; - dprintk("buf prepare %p: top=%p bottom=%p field=%s\n", - vb, &buf->top, &buf->bottom, - v4l2_field_names[buf->vb.field]); - return 0; - - fail: - bttv_dma_free(q,btv,buf); - return rc; -} - -static void -vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - - dprintk("queue %p\n",vb); - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue,&btv->vcapture); - if (NULL == btv->cvbi) { - fh->btv->loop_irq |= 4; - bttv_set_dma(btv,0x0c); - } -} - -static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - - dprintk("free %p\n",vb); - bttv_dma_free(q,fh->btv,buf); -} - -struct videobuf_queue_ops bttv_vbi_qops = { - .buf_setup = vbi_buffer_setup, - .buf_prepare = vbi_buffer_prepare, - .buf_queue = vbi_buffer_queue, - .buf_release = vbi_buffer_release, -}; - -/* ----------------------------------------------------------------------- */ - -static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, - __s32 crop_start) -{ - __s32 min_start, max_start, max_end, f2_offset; - unsigned int i; - - /* For compatibility with earlier driver versions we must pretend - the VBI and video capture window may overlap. In reality RISC - magic aborts VBI capturing at the first line of video capturing, - leaving the rest of the buffer unchanged, usually all zero. - VBI capturing must always start before video capturing. >> 1 - because cropping counts field lines times two. */ - min_start = tvnorm->vbistart[0]; - max_start = (crop_start >> 1) - 1; - max_end = (tvnorm->cropcap.bounds.top - + tvnorm->cropcap.bounds.height) >> 1; - - if (min_start > max_start) - return -EBUSY; - - BUG_ON(max_start >= max_end); - - f->sampling_rate = tvnorm->Fsc; - f->samples_per_line = VBI_BPL; - f->sample_format = V4L2_PIX_FMT_GREY; - f->offset = VBI_OFFSET; - - f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0]; - - for (i = 0; i < 2; ++i) { - if (0 == f->count[i]) { - /* No data from this field. We leave f->start[i] - alone because VIDIOCSVBIFMT is w/o and EINVALs - when a driver does not support exactly the - requested parameters. */ - } else { - s64 start, count; - - start = clamp(f->start[i], min_start, max_start); - /* s64 to prevent overflow. */ - count = (s64) f->start[i] + f->count[i] - start; - f->start[i] = start; - f->count[i] = clamp(count, (s64) 1, - max_end - start); - } - - min_start += f2_offset; - max_start += f2_offset; - max_end += f2_offset; - } - - if (0 == (f->count[0] | f->count[1])) { - /* As in earlier driver versions. */ - f->start[0] = tvnorm->vbistart[0]; - f->start[1] = tvnorm->vbistart[1]; - f->count[0] = 1; - f->count[1] = 1; - } - - f->flags = 0; - - f->reserved[0] = 0; - f->reserved[1] = 0; - - return 0; -} - -int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct bttv_tvnorm *tvnorm; - __s32 crop_start; - - mutex_lock(&btv->lock); - - tvnorm = &bttv_tvnorms[btv->tvnorm]; - crop_start = btv->crop_start; - - mutex_unlock(&btv->lock); - - return try_fmt(&frt->fmt.vbi, tvnorm, crop_start); -} - - -int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct bttv_tvnorm *tvnorm; - __s32 start1, end; - int rc; - - mutex_lock(&btv->lock); - - rc = -EBUSY; - if (fh->resources & RESOURCE_VBI) - goto fail; - - tvnorm = &bttv_tvnorms[btv->tvnorm]; - - rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start); - if (0 != rc) - goto fail; - - start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] + - tvnorm->vbistart[0]; - - /* First possible line of video capturing. Should be - max(f->start[0] + f->count[0], start1 + f->count[1]) * 2 - when capturing both fields. But for compatibility we must - pretend the VBI and video capture window may overlap, - so end = start + 1, the lowest possible value, times two - because vbi_fmt.end counts field lines times two. */ - end = max(frt->fmt.vbi.start[0], start1) * 2 + 2; - - mutex_lock(&fh->vbi.vb_lock); - - fh->vbi_fmt.fmt = frt->fmt.vbi; - fh->vbi_fmt.tvnorm = tvnorm; - fh->vbi_fmt.end = end; - - mutex_unlock(&fh->vbi.vb_lock); - - rc = 0; - - fail: - mutex_unlock(&btv->lock); - - return rc; -} - - -int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) -{ - struct bttv_fh *fh = f; - const struct bttv_tvnorm *tvnorm; - - frt->fmt.vbi = fh->vbi_fmt.fmt; - - tvnorm = &bttv_tvnorms[fh->btv->tvnorm]; - - if (tvnorm != fh->vbi_fmt.tvnorm) { - __s32 max_end; - unsigned int i; - - /* As in vbi_buffer_prepare() this imitates the - behaviour of earlier driver versions after video - standard changes, with default parameters anyway. */ - - max_end = (tvnorm->cropcap.bounds.top - + tvnorm->cropcap.bounds.height) >> 1; - - frt->fmt.vbi.sampling_rate = tvnorm->Fsc; - - for (i = 0; i < 2; ++i) { - __s32 new_start; - - new_start = frt->fmt.vbi.start[i] - + tvnorm->vbistart[i] - - fh->vbi_fmt.tvnorm->vbistart[i]; - - frt->fmt.vbi.start[i] = min(new_start, max_end - 1); - frt->fmt.vbi.count[i] = - min((__s32) frt->fmt.vbi.count[i], - max_end - frt->fmt.vbi.start[i]); - - max_end += tvnorm->vbistart[1] - - tvnorm->vbistart[0]; - } - } - return 0; -} - -void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm) -{ - const struct bttv_tvnorm *tvnorm; - unsigned int real_samples_per_line; - unsigned int real_count; - - tvnorm = &bttv_tvnorms[norm]; - - f->fmt.sampling_rate = tvnorm->Fsc; - f->fmt.samples_per_line = VBI_BPL; - f->fmt.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.offset = VBI_OFFSET; - f->fmt.start[0] = tvnorm->vbistart[0]; - f->fmt.start[1] = tvnorm->vbistart[1]; - f->fmt.count[0] = VBI_DEFLINES; - f->fmt.count[1] = VBI_DEFLINES; - f->fmt.flags = 0; - f->fmt.reserved[0] = 0; - f->fmt.reserved[1] = 0; - - /* For compatibility the buffer size must be 2 * VBI_DEFLINES * - VBI_BPL regardless of the current video standard. */ - real_samples_per_line = 1024 + tvnorm->vbipack * 4; - real_count = ((tvnorm->cropcap.defrect.top >> 1) - - tvnorm->vbistart[0]); - - BUG_ON(real_samples_per_line > VBI_BPL); - BUG_ON(real_count > VBI_DEFLINES); - - f->tvnorm = tvnorm; - - /* See bttv_vbi_fmt_set(). */ - f->end = tvnorm->vbistart[0] * 2 + 2; -} - -/* ----------------------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -config VIDEO_BT848 - tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 - select I2C_ALGOBIT - select VIDEO_BTCX - select VIDEOBUF_DMA_SG - depends on RC_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO - ---help--- - Support for BT848 based frame grabber/overlay boards. This includes - the Miro, Hauppauge and STB boards. Please read the material in - for more information. - - To compile this driver as a module, choose M here: the - module will be called bttv. - -config VIDEO_BT848_DVB - bool "DVB/ATSC Support for bt878 based TV cards" - depends on VIDEO_BT848 && DVB_CORE - select DVB_BT8XX - ---help--- - This adds support for DVB/ATSC cards based on the BT878 chip. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bt8xx/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -# -# Makefile for the video capture/playback device drivers. -# - -bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ - bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ - bttv-input.o bttv-audio-hook.o - -obj-$(CONFIG_VIDEO_BT848) += bttv.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/btcx-risc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/btcx-risc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/btcx-risc.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/btcx-risc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,260 +0,0 @@ -/* - - btcx-risc.c - - bt848/bt878/cx2388x risc code generator. - - (c) 2000-03 Gerd Knorr [SuSE Labs] - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "btcx-risc.h" - -MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers"); -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)"); - -/* ---------------------------------------------------------- */ -/* allocate/free risc memory */ - -static int memcnt; - -void btcx_riscmem_free(struct pci_dev *pci, - struct btcx_riscmem *risc) -{ - if (NULL == risc->cpu) - return; - if (debug) { - memcnt--; - printk("btcx: riscmem free [%d] dma=%lx\n", - memcnt, (unsigned long)risc->dma); - } - pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); - memset(risc,0,sizeof(*risc)); -} - -int btcx_riscmem_alloc(struct pci_dev *pci, - struct btcx_riscmem *risc, - unsigned int size) -{ - __le32 *cpu; - dma_addr_t dma = 0; - - if (NULL != risc->cpu && risc->size < size) - btcx_riscmem_free(pci,risc); - if (NULL == risc->cpu) { - cpu = pci_alloc_consistent(pci, size, &dma); - if (NULL == cpu) - return -ENOMEM; - risc->cpu = cpu; - risc->dma = dma; - risc->size = size; - if (debug) { - memcnt++; - printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", - memcnt, (unsigned long)dma, cpu, size); - } - } - memset(risc->cpu,0,risc->size); - return 0; -} - -/* ---------------------------------------------------------- */ -/* screen overlay helpers */ - -int -btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, - struct v4l2_clip *clips, unsigned int n) -{ - if (win->left < 0) { - /* left */ - clips[n].c.left = 0; - clips[n].c.top = 0; - clips[n].c.width = -win->left; - clips[n].c.height = win->height; - n++; - } - if (win->left + win->width > swidth) { - /* right */ - clips[n].c.left = swidth - win->left; - clips[n].c.top = 0; - clips[n].c.width = win->width - clips[n].c.left; - clips[n].c.height = win->height; - n++; - } - if (win->top < 0) { - /* top */ - clips[n].c.left = 0; - clips[n].c.top = 0; - clips[n].c.width = win->width; - clips[n].c.height = -win->top; - n++; - } - if (win->top + win->height > sheight) { - /* bottom */ - clips[n].c.left = 0; - clips[n].c.top = sheight - win->top; - clips[n].c.width = win->width; - clips[n].c.height = win->height - clips[n].c.top; - n++; - } - return n; -} - -int -btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask) -{ - s32 nx,nw,dx; - unsigned int i; - - /* fixup window */ - nx = (win->left + mask) & ~mask; - nw = (win->width) & ~mask; - if (nx + nw > win->left + win->width) - nw -= mask+1; - dx = nx - win->left; - win->left = nx; - win->width = nw; - if (debug) - printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n", - win->width, win->height, win->left, win->top, dx); - - /* fixup clips */ - for (i = 0; i < n; i++) { - nx = (clips[i].c.left-dx) & ~mask; - nw = (clips[i].c.width) & ~mask; - if (nx + nw < clips[i].c.left-dx + clips[i].c.width) - nw += mask+1; - clips[i].c.left = nx; - clips[i].c.width = nw; - if (debug) - printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n", - clips[i].c.width, clips[i].c.height, - clips[i].c.left, clips[i].c.top); - } - return 0; -} - -void -btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) -{ - struct v4l2_clip swap; - int i,j,n; - - if (nclips < 2) - return; - for (i = nclips-2; i >= 0; i--) { - for (n = 0, j = 0; j <= i; j++) { - if (clips[j].c.left > clips[j+1].c.left) { - swap = clips[j]; - clips[j] = clips[j+1]; - clips[j+1] = swap; - n++; - } - } - if (0 == n) - break; - } -} - -void -btcx_calc_skips(int line, int width, int *maxy, - struct btcx_skiplist *skips, unsigned int *nskips, - const struct v4l2_clip *clips, unsigned int nclips) -{ - unsigned int clip,skip; - int end, maxline; - - skip=0; - maxline = 9999; - for (clip = 0; clip < nclips; clip++) { - - /* sanity checks */ - if (clips[clip].c.left + clips[clip].c.width <= 0) - continue; - if (clips[clip].c.left > (signed)width) - break; - - /* vertical range */ - if (line > clips[clip].c.top+clips[clip].c.height-1) - continue; - if (line < clips[clip].c.top) { - if (maxline > clips[clip].c.top-1) - maxline = clips[clip].c.top-1; - continue; - } - if (maxline > clips[clip].c.top+clips[clip].c.height-1) - maxline = clips[clip].c.top+clips[clip].c.height-1; - - /* horizontal range */ - if (0 == skip || clips[clip].c.left > skips[skip-1].end) { - /* new one */ - skips[skip].start = clips[clip].c.left; - if (skips[skip].start < 0) - skips[skip].start = 0; - skips[skip].end = clips[clip].c.left + clips[clip].c.width; - if (skips[skip].end > width) - skips[skip].end = width; - skip++; - } else { - /* overlaps -- expand last one */ - end = clips[clip].c.left + clips[clip].c.width; - if (skips[skip-1].end < end) - skips[skip-1].end = end; - if (skips[skip-1].end > width) - skips[skip-1].end = width; - } - } - *nskips = skip; - *maxy = maxline; - - if (debug) { - printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline); - for (skip = 0; skip < *nskips; skip++) { - printk(" %d-%d",skips[skip].start,skips[skip].end); - } - printk("\n"); - } -} - -/* ---------------------------------------------------------- */ - -EXPORT_SYMBOL(btcx_riscmem_alloc); -EXPORT_SYMBOL(btcx_riscmem_free); - -EXPORT_SYMBOL(btcx_screen_clips); -EXPORT_SYMBOL(btcx_align); -EXPORT_SYMBOL(btcx_sort_clips); -EXPORT_SYMBOL(btcx_calc_skips); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/btcx-risc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/btcx-risc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/btcx-risc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/btcx-risc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - */ -struct btcx_riscmem { - unsigned int size; - __le32 *cpu; - __le32 *jmp; - dma_addr_t dma; -}; - -struct btcx_skiplist { - int start; - int end; -}; - -int btcx_riscmem_alloc(struct pci_dev *pci, - struct btcx_riscmem *risc, - unsigned int size); -void btcx_riscmem_free(struct pci_dev *pci, - struct btcx_riscmem *risc); - -int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, - struct v4l2_clip *clips, unsigned int n); -int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, - unsigned int n, int mask); -void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); -void btcx_calc_skips(int line, int width, int *maxy, - struct btcx_skiplist *skips, unsigned int *nskips, - const struct v4l2_clip *clips, unsigned int nclips); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bw-qcam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bw-qcam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bw-qcam.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/bw-qcam.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1094 +0,0 @@ -/* - * QuickCam Driver For Video4Linux. - * - * Video4Linux conversion work by Alan Cox. - * Parport compatibility by Phil Blundell. - * Busy loop avoidance by Mark Cooke. - * - * Module parameters: - * - * maxpoll=<1 - 5000> - * - * When polling the QuickCam for a response, busy-wait for a - * maximum of this many loops. The default of 250 gives little - * impact on interactive response. - * - * NOTE: If this parameter is set too high, the processor - * will busy wait until this loop times out, and then - * slowly poll for a further 5 seconds before failing - * the transaction. You have been warned. - * - * yieldlines=<1 - 250> - * - * When acquiring a frame from the camera, the data gathering - * loop will yield back to the scheduler after completing - * this many lines. The default of 4 provides a trade-off - * between increased frame acquisition time and impact on - * interactive response. - */ - -/* qcam-lib.c -- Library for programming with the Connectix QuickCam. - * See the included documentation for usage instructions and details - * of the protocol involved. */ - - -/* Version 0.5, August 4, 1996 */ -/* Version 0.7, August 27, 1996 */ -/* Version 0.9, November 17, 1996 */ - - -/****************************************************************** - -Copyright (C) 1996 by Scott Laird - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -******************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* One from column A... */ -#define QC_NOTSET 0 -#define QC_UNIDIR 1 -#define QC_BIDIR 2 -#define QC_SERIAL 3 - -/* ... and one from column B */ -#define QC_ANY 0x00 -#define QC_FORCE_UNIDIR 0x10 -#define QC_FORCE_BIDIR 0x20 -#define QC_FORCE_SERIAL 0x30 -/* in the port_mode member */ - -#define QC_MODE_MASK 0x07 -#define QC_FORCE_MASK 0x70 - -#define MAX_HEIGHT 243 -#define MAX_WIDTH 336 - -/* Bit fields for status flags */ -#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ - -struct qcam { - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct pardevice *pdev; - struct parport *pport; - struct mutex lock; - int width, height; - int bpp; - int mode; - int contrast, brightness, whitebal; - int port_mode; - int transfer_scale; - int top, left; - int status; - unsigned int saved_bits; - unsigned long in_use; -}; - -static unsigned int maxpoll = 250; /* Maximum busy-loop count for qcam I/O */ -static unsigned int yieldlines = 4; /* Yield after this many during capture */ -static int video_nr = -1; -static unsigned int force_init; /* Whether to probe aggressively */ - -module_param(maxpoll, int, 0); -module_param(yieldlines, int, 0); -module_param(video_nr, int, 0); - -/* Set force_init=1 to avoid detection by polling status register and - * immediately attempt to initialize qcam */ -module_param(force_init, int, 0); - -#define MAX_CAMS 4 -static struct qcam *qcams[MAX_CAMS]; -static unsigned int num_cams; - -static inline int read_lpstatus(struct qcam *q) -{ - return parport_read_status(q->pport); -} - -static inline int read_lpdata(struct qcam *q) -{ - return parport_read_data(q->pport); -} - -static inline void write_lpdata(struct qcam *q, int d) -{ - parport_write_data(q->pport, d); -} - -static void write_lpcontrol(struct qcam *q, int d) -{ - if (d & 0x20) { - /* Set bidirectional mode to reverse (data in) */ - parport_data_reverse(q->pport); - } else { - /* Set bidirectional mode to forward (data out) */ - parport_data_forward(q->pport); - } - - /* Now issue the regular port command, but strip out the - * direction flag */ - d &= ~0x20; - parport_write_control(q->pport, d); -} - - -/* qc_waithand busy-waits for a handshake signal from the QuickCam. - * Almost all communication with the camera requires handshaking. */ - -static int qc_waithand(struct qcam *q, int val) -{ - int status; - int runs = 0; - - if (val) { - while (!((status = read_lpstatus(q)) & 8)) { - /* 1000 is enough spins on the I/O for all normal - cases, at that point we start to poll slowly - until the camera wakes up. However, we are - busy blocked until the camera responds, so - setting it lower is much better for interactive - response. */ - - if (runs++ > maxpoll) - msleep_interruptible(5); - if (runs > (maxpoll + 1000)) /* 5 seconds */ - return -1; - } - } else { - while (((status = read_lpstatus(q)) & 8)) { - /* 1000 is enough spins on the I/O for all normal - cases, at that point we start to poll slowly - until the camera wakes up. However, we are - busy blocked until the camera responds, so - setting it lower is much better for interactive - response. */ - - if (runs++ > maxpoll) - msleep_interruptible(5); - if (runs++ > (maxpoll + 1000)) /* 5 seconds */ - return -1; - } - } - - return status; -} - -/* Waithand2 is used when the qcam is in bidirectional mode, and the - * handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1 - * (bit 3 of status register). It also returns the last value read, - * since this data is useful. */ - -static unsigned int qc_waithand2(struct qcam *q, int val) -{ - unsigned int status; - int runs = 0; - - do { - status = read_lpdata(q); - /* 1000 is enough spins on the I/O for all normal - cases, at that point we start to poll slowly - until the camera wakes up. However, we are - busy blocked until the camera responds, so - setting it lower is much better for interactive - response. */ - - if (runs++ > maxpoll) - msleep_interruptible(5); - if (runs++ > (maxpoll + 1000)) /* 5 seconds */ - return 0; - } while ((status & 1) != val); - - return status; -} - -/* qc_command is probably a bit of a misnomer -- it's used to send - * bytes *to* the camera. Generally, these bytes are either commands - * or arguments to commands, so the name fits, but it still bugs me a - * bit. See the documentation for a list of commands. */ - -static int qc_command(struct qcam *q, int command) -{ - int n1, n2; - int cmd; - - write_lpdata(q, command); - write_lpcontrol(q, 6); - - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} - -static int qc_readparam(struct qcam *q) -{ - int n1, n2; - int cmd; - - write_lpcontrol(q, 6); - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} - - -/* Try to detect a QuickCam. It appears to flash the upper 4 bits of - the status register at 5-10 Hz. This is only used in the autoprobe - code. Be aware that this isn't the way Connectix detects the - camera (they send a reset and try to handshake), but this should be - almost completely safe, while their method screws up my printer if - I plug it in before the camera. */ - -static int qc_detect(struct qcam *q) -{ - int reg, lastreg; - int count = 0; - int i; - - if (force_init) - return 1; - - lastreg = reg = read_lpstatus(q) & 0xf0; - - for (i = 0; i < 500; i++) { - reg = read_lpstatus(q) & 0xf0; - if (reg != lastreg) - count++; - lastreg = reg; - mdelay(2); - } - - -#if 0 - /* Force camera detection during testing. Sometimes the camera - won't be flashing these bits. Possibly unloading the module - in the middle of a grab? Or some timeout condition? - I've seen this parameter as low as 19 on my 450Mhz box - mpc */ - printk(KERN_DEBUG "Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count); - return 1; -#endif - - /* Be (even more) liberal in what you accept... */ - - if (count > 20 && count < 400) { - return 1; /* found */ - } else { - printk(KERN_ERR "No Quickcam found on port %s\n", - q->pport->name); - printk(KERN_DEBUG "Quickcam detection counter: %u\n", count); - return 0; /* not found */ - } -} - -/* Decide which scan mode to use. There's no real requirement that - * the scanmode match the resolution in q->height and q-> width -- the - * camera takes the picture at the resolution specified in the - * "scanmode" and then returns the image at the resolution specified - * with the resolution commands. If the scan is bigger than the - * requested resolution, the upper-left hand corner of the scan is - * returned. If the scan is smaller, then the rest of the image - * returned contains garbage. */ - -static int qc_setscanmode(struct qcam *q) -{ - int old_mode = q->mode; - - switch (q->transfer_scale) { - case 1: - q->mode = 0; - break; - case 2: - q->mode = 4; - break; - case 4: - q->mode = 8; - break; - } - - switch (q->bpp) { - case 4: - break; - case 6: - q->mode += 2; - break; - } - - switch (q->port_mode & QC_MODE_MASK) { - case QC_BIDIR: - q->mode += 1; - break; - case QC_NOTSET: - case QC_UNIDIR: - break; - } - - if (q->mode != old_mode) - q->status |= QC_PARAM_CHANGE; - - return 0; -} - - -/* Reset the QuickCam. This uses the same sequence the Windows - * QuickPic program uses. Someone with a bi-directional port should - * check that bi-directional mode is detected right, and then - * implement bi-directional mode in qc_readbyte(). */ - -static void qc_reset(struct qcam *q) -{ - switch (q->port_mode & QC_FORCE_MASK) { - case QC_FORCE_UNIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - break; - - case QC_FORCE_BIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - break; - - case QC_ANY: - write_lpcontrol(q, 0x20); - write_lpdata(q, 0x75); - - if (read_lpdata(q) != 0x75) - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - else - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - break; - } - - write_lpcontrol(q, 0xb); - udelay(250); - write_lpcontrol(q, 0xe); - qc_setscanmode(q); /* in case port_mode changed */ -} - - - -/* Reset the QuickCam and program for brightness, contrast, - * white-balance, and resolution. */ - -static void qc_set(struct qcam *q) -{ - int val; - int val2; - - qc_reset(q); - - /* Set the brightness. Yes, this is repetitive, but it works. - * Shorter versions seem to fail subtly. Feel free to try :-). */ - /* I think the problem was in qc_command, not here -- bls */ - - qc_command(q, 0xb); - qc_command(q, q->brightness); - - val = q->height / q->transfer_scale; - qc_command(q, 0x11); - qc_command(q, val); - if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) { - /* The normal "transfers per line" calculation doesn't seem to work - as expected here (and yet it works fine in qc_scan). No idea - why this case is the odd man out. Fortunately, Laird's original - working version gives me a good way to guess at working values. - -- bls */ - val = q->width; - val2 = q->transfer_scale * 4; - } else { - val = q->width * q->bpp; - val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * - q->transfer_scale; - } - val = DIV_ROUND_UP(val, val2); - qc_command(q, 0x13); - qc_command(q, val); - - /* Setting top and left -- bls */ - qc_command(q, 0xd); - qc_command(q, q->top); - qc_command(q, 0xf); - qc_command(q, q->left / 2); - - qc_command(q, 0x19); - qc_command(q, q->contrast); - qc_command(q, 0x1f); - qc_command(q, q->whitebal); - - /* Clear flag that we must update the grabbing parameters on the camera - before we grab the next frame */ - q->status &= (~QC_PARAM_CHANGE); -} - -/* Qc_readbytes reads some bytes from the QC and puts them in - the supplied buffer. It returns the number of bytes read, - or -1 on error. */ - -static inline int qc_readbytes(struct qcam *q, char buffer[]) -{ - int ret = 1; - unsigned int hi, lo; - unsigned int hi2, lo2; - static int state; - - if (buffer == NULL) { - state = 0; - return 0; - } - - switch (q->port_mode & QC_MODE_MASK) { - case QC_BIDIR: /* Bi-directional Port */ - write_lpcontrol(q, 0x26); - lo = (qc_waithand2(q, 1) >> 1); - hi = (read_lpstatus(q) >> 3) & 0x1f; - write_lpcontrol(q, 0x2e); - lo2 = (qc_waithand2(q, 0) >> 1); - hi2 = (read_lpstatus(q) >> 3) & 0x1f; - switch (q->bpp) { - case 4: - buffer[0] = lo & 0xf; - buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3); - buffer[2] = (hi & 0x1e) >> 1; - buffer[3] = lo2 & 0xf; - buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3); - buffer[5] = (hi2 & 0x1e) >> 1; - ret = 6; - break; - case 6: - buffer[0] = lo & 0x3f; - buffer[1] = ((lo & 0x40) >> 6) | (hi << 1); - buffer[2] = lo2 & 0x3f; - buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1); - ret = 4; - break; - } - break; - - case QC_UNIDIR: /* Unidirectional Port */ - write_lpcontrol(q, 6); - lo = (qc_waithand(q, 1) & 0xf0) >> 4; - write_lpcontrol(q, 0xe); - hi = (qc_waithand(q, 0) & 0xf0) >> 4; - - switch (q->bpp) { - case 4: - buffer[0] = lo; - buffer[1] = hi; - ret = 2; - break; - case 6: - switch (state) { - case 0: - buffer[0] = (lo << 2) | ((hi & 0xc) >> 2); - q->saved_bits = (hi & 3) << 4; - state = 1; - ret = 1; - break; - case 1: - buffer[0] = lo | q->saved_bits; - q->saved_bits = hi << 2; - state = 2; - ret = 1; - break; - case 2: - buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits; - buffer[1] = ((lo & 3) << 4) | hi; - state = 0; - ret = 2; - break; - } - break; - } - break; - } - return ret; -} - -/* requests a scan from the camera. It sends the correct instructions - * to the camera and then reads back the correct number of bytes. In - * previous versions of this routine the return structure contained - * the raw output from the camera, and there was a 'qc_convertscan' - * function that converted that to a useful format. In version 0.3 I - * rolled qc_convertscan into qc_scan and now I only return the - * converted scan. The format is just an one-dimensional array of - * characters, one for each pixel, with 0=black up to n=white, where - * n=2^(bit depth)-1. Ask me for more details if you don't understand - * this. */ - -static long qc_capture(struct qcam *q, char __user *buf, unsigned long len) -{ - int i, j, k, yield; - int bytes; - int linestotrans, transperline; - int divisor; - int pixels_per_line; - int pixels_read = 0; - int got = 0; - char buffer[6]; - int shift = 8 - q->bpp; - char invert; - - if (q->mode == -1) - return -ENXIO; - - qc_command(q, 0x7); - qc_command(q, q->mode); - - if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { - write_lpcontrol(q, 0x2e); /* turn port around */ - write_lpcontrol(q, 0x26); - qc_waithand(q, 1); - write_lpcontrol(q, 0x2e); - qc_waithand(q, 0); - } - - /* strange -- should be 15:63 below, but 4bpp is odd */ - invert = (q->bpp == 4) ? 16 : 63; - - linestotrans = q->height / q->transfer_scale; - pixels_per_line = q->width / q->transfer_scale; - transperline = q->width * q->bpp; - divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * - q->transfer_scale; - transperline = DIV_ROUND_UP(transperline, divisor); - - for (i = 0, yield = yieldlines; i < linestotrans; i++) { - for (pixels_read = j = 0; j < transperline; j++) { - bytes = qc_readbytes(q, buffer); - for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) { - int o; - if (buffer[k] == 0 && invert == 16) { - /* 4bpp is odd (again) -- inverter is 16, not 15, but output - must be 0-15 -- bls */ - buffer[k] = 16; - } - o = i * pixels_per_line + pixels_read + k; - if (o < len) { - got++; - put_user((invert - buffer[k]) << shift, buf + o); - } - } - pixels_read += bytes; - } - qc_readbytes(q, NULL); /* reset state machine */ - - /* Grabbing an entire frame from the quickcam is a lengthy - process. We don't (usually) want to busy-block the - processor for the entire frame. yieldlines is a module - parameter. If we yield every line, the minimum frame - time will be 240 / 200 = 1.2 seconds. The compile-time - default is to yield every 4 lines. */ - if (i >= yield) { - msleep_interruptible(5); - yield = i + yieldlines; - } - } - - if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { - write_lpcontrol(q, 2); - write_lpcontrol(q, 6); - udelay(3); - write_lpcontrol(q, 0xe); - } - if (got < len) - return got; - return len; -} - -/* - * Video4linux interfacing - */ - -static int qcam_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct qcam *qcam = video_drvdata(file); - - strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card)); - strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); - vcap->version = KERNEL_VERSION(0, 0, 2); - vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - return 0; -} - -static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - if (vin->index > 0) - return -EINVAL; - strlcpy(vin->name, "Camera", sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = 0; - vin->status = 0; - return 0; -} - -static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) -{ - *inp = 0; - return 0; -} - -static int qcam_s_input(struct file *file, void *fh, unsigned int inp) -{ - return (inp > 0) ? -EINVAL : 0; -} - -static int qcam_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192); - case V4L2_CID_GAMMA: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105); - } - return -EINVAL; -} - -static int qcam_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct qcam *qcam = video_drvdata(file); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = qcam->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = qcam->contrast; - break; - case V4L2_CID_GAMMA: - ctrl->value = qcam->whitebal; - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static int qcam_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct qcam *qcam = video_drvdata(file); - int ret = 0; - - mutex_lock(&qcam->lock); - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - qcam->brightness = ctrl->value; - break; - case V4L2_CID_CONTRAST: - qcam->contrast = ctrl->value; - break; - case V4L2_CID_GAMMA: - qcam->whitebal = ctrl->value; - break; - default: - ret = -EINVAL; - break; - } - if (ret == 0) { - qc_setscanmode(qcam); - qcam->status |= QC_PARAM_CHANGE; - } - mutex_unlock(&qcam->lock); - return ret; -} - -static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct qcam *qcam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = qcam->width / qcam->transfer_scale; - pix->height = qcam->height / qcam->transfer_scale; - pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = qcam->width; - pix->sizeimage = qcam->width * qcam->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->height <= 60 || pix->width <= 80) { - pix->height = 60; - pix->width = 80; - } else if (pix->height <= 120 || pix->width <= 160) { - pix->height = 120; - pix->width = 160; - } else { - pix->height = 240; - pix->width = 320; - } - if (pix->pixelformat != V4L2_PIX_FMT_Y4 && - pix->pixelformat != V4L2_PIX_FMT_Y6) - pix->pixelformat = V4L2_PIX_FMT_Y4; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = pix->width; - pix->sizeimage = pix->width * pix->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct qcam *qcam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = qcam_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - qcam->width = 320; - qcam->height = 240; - if (pix->height == 60) - qcam->transfer_scale = 4; - else if (pix->height == 120) - qcam->transfer_scale = 2; - else - qcam->transfer_scale = 1; - if (pix->pixelformat == V4L2_PIX_FMT_Y6) - qcam->bpp = 6; - else - qcam->bpp = 4; - - mutex_lock(&qcam->lock); - qc_setscanmode(qcam); - /* We must update the camera before we grab. We could - just have changed the grab size */ - qcam->status |= QC_PARAM_CHANGE; - mutex_unlock(&qcam->lock); - return 0; -} - -static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "4-Bit Monochrome", V4L2_PIX_FMT_Y4, - { 0, 0, 0, 0 } - }, - { 0, 0, 0, - "6-Bit Monochrome", V4L2_PIX_FMT_Y6, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 1) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -static ssize_t qcam_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct qcam *qcam = video_drvdata(file); - int len; - parport_claim_or_block(qcam->pdev); - - mutex_lock(&qcam->lock); - - qc_reset(qcam); - - /* Update the camera parameters if we need to */ - if (qcam->status & QC_PARAM_CHANGE) - qc_set(qcam); - - len = qc_capture(qcam, buf, count); - - mutex_unlock(&qcam->lock); - - parport_release(qcam->pdev); - return len; -} - -static const struct v4l2_file_operations qcam_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - .read = qcam_read, -}; - -static const struct v4l2_ioctl_ops qcam_ioctl_ops = { - .vidioc_querycap = qcam_querycap, - .vidioc_g_input = qcam_g_input, - .vidioc_s_input = qcam_s_input, - .vidioc_enum_input = qcam_enum_input, - .vidioc_queryctrl = qcam_queryctrl, - .vidioc_g_ctrl = qcam_g_ctrl, - .vidioc_s_ctrl = qcam_s_ctrl, - .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, -}; - -/* Initialize the QuickCam driver control structure. This is where - * defaults are set for people who don't have a config file.*/ - -static struct qcam *qcam_init(struct parport *port) -{ - struct qcam *qcam; - struct v4l2_device *v4l2_dev; - - qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL); - if (qcam == NULL) - return NULL; - - v4l2_dev = &qcam->v4l2_dev; - strlcpy(v4l2_dev->name, "bw-qcam", sizeof(v4l2_dev->name)); - - if (v4l2_device_register(NULL, v4l2_dev) < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return NULL; - } - - qcam->pport = port; - qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, - NULL, 0, NULL); - if (qcam->pdev == NULL) { - v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); - kfree(qcam); - return NULL; - } - - strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name)); - qcam->vdev.v4l2_dev = v4l2_dev; - qcam->vdev.fops = &qcam_fops; - qcam->vdev.ioctl_ops = &qcam_ioctl_ops; - qcam->vdev.release = video_device_release_empty; - video_set_drvdata(&qcam->vdev, qcam); - - mutex_init(&qcam->lock); - - qcam->port_mode = (QC_ANY | QC_NOTSET); - qcam->width = 320; - qcam->height = 240; - qcam->bpp = 4; - qcam->transfer_scale = 2; - qcam->contrast = 192; - qcam->brightness = 180; - qcam->whitebal = 105; - qcam->top = 1; - qcam->left = 14; - qcam->mode = -1; - qcam->status = QC_PARAM_CHANGE; - return qcam; -} - -static int qc_calibrate(struct qcam *q) -{ - /* - * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 - * The white balance is an individual value for each - * quickcam. - */ - - int value; - int count = 0; - - qc_command(q, 27); /* AutoAdjustOffset */ - qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ - - /* GetOffset (33) will read 255 until autocalibration */ - /* is finished. After that, a value of 1-254 will be */ - /* returned. */ - - do { - qc_command(q, 33); - value = qc_readparam(q); - mdelay(1); - schedule(); - count++; - } while (value == 0xff && count < 2048); - - q->whitebal = value; - return value; -} - -static int init_bwqcam(struct parport *port) -{ - struct qcam *qcam; - - if (num_cams == MAX_CAMS) { - printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); - return -ENOSPC; - } - - qcam = qcam_init(port); - if (qcam == NULL) - return -ENODEV; - - parport_claim_or_block(qcam->pdev); - - qc_reset(qcam); - - if (qc_detect(qcam) == 0) { - parport_release(qcam->pdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - qc_calibrate(qcam); - - parport_release(qcam->pdev); - - v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name); - - if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - - qcams[num_cams++] = qcam; - - return 0; -} - -static void close_bwqcam(struct qcam *qcam) -{ - video_unregister_device(&qcam->vdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); -} - -/* The parport parameter controls which parports will be scanned. - * Scanning all parports causes some printers to print a garbage page. - * -- March 14, 1999 Billy Donahue */ -#ifdef MODULE -static char *parport[MAX_CAMS] = { NULL, }; -module_param_array(parport, charp, NULL, 0); -#endif - -static int accept_bwqcam(struct parport *port) -{ -#ifdef MODULE - int n; - - if (parport[0] && strncmp(parport[0], "auto", 4) != 0) { - /* user gave parport parameters */ - for (n = 0; n < MAX_CAMS && parport[n]; n++) { - char *ep; - unsigned long r; - r = simple_strtoul(parport[n], &ep, 0); - if (ep == parport[n]) { - printk(KERN_ERR - "bw-qcam: bad port specifier \"%s\"\n", - parport[n]); - continue; - } - if (r == port->number) - return 1; - } - return 0; - } -#endif - return 1; -} - -static void bwqcam_attach(struct parport *port) -{ - if (accept_bwqcam(port)) - init_bwqcam(port); -} - -static void bwqcam_detach(struct parport *port) -{ - int i; - for (i = 0; i < num_cams; i++) { - struct qcam *qcam = qcams[i]; - if (qcam && qcam->pdev->port == port) { - qcams[i] = NULL; - close_bwqcam(qcam); - } - } -} - -static struct parport_driver bwqcam_driver = { - .name = "bw-qcam", - .attach = bwqcam_attach, - .detach = bwqcam_detach, -}; - -static void __exit exit_bw_qcams(void) -{ - parport_unregister_driver(&bwqcam_driver); -} - -static int __init init_bw_qcams(void) -{ -#ifdef MODULE - /* Do some sanity checks on the module parameters. */ - if (maxpoll > 5000) { - printk(KERN_INFO "Connectix Quickcam max-poll was above 5000. Using 5000.\n"); - maxpoll = 5000; - } - - if (yieldlines < 1) { - printk(KERN_INFO "Connectix Quickcam yieldlines was less than 1. Using 1.\n"); - yieldlines = 1; - } -#endif - return parport_register_driver(&bwqcam_driver); -} - -module_init(init_bw_qcams); -module_exit(exit_bw_qcams); - -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cafe_ccic.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cafe_ccic.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cafe_ccic.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cafe_ccic.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2267 +0,0 @@ -/* - * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe" - * multifunction chip. Currently works with the Omnivision OV7670 - * sensor. - * - * The data sheet for this device can be found at: - * http://www.marvell.com/products/pc_connectivity/88alp01/ - * - * Copyright 2006 One Laptop Per Child Association, Inc. - * Copyright 2006-7 Jonathan Corbet - * - * Written by Jonathan Corbet, corbet@lwn.net. - * - * v4l2_device/v4l2_subdev conversion by: - * Copyright (C) 2009 Hans Verkuil - * - * Note: this conversion is untested! Please contact the linux-media - * mailinglist if you can test this, together with the test results. - * - * This file may be distributed under the terms of the GNU General - * Public License, version 2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "ov7670.h" -#include "cafe_ccic-regs.h" - -#define CAFE_VERSION 0x000002 - - -/* - * Parameters. - */ -MODULE_AUTHOR("Jonathan Corbet "); -MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("Video"); - -/* - * Internal DMA buffer management. Since the controller cannot do S/G I/O, - * we must have physically contiguous buffers to bring frames into. - * These parameters control how many buffers we use, whether we - * allocate them at load time (better chance of success, but nails down - * memory) or when somebody tries to use the camera (riskier), and, - * for load-time allocation, how big they should be. - * - * The controller can cycle through three buffers. We could use - * more by flipping pointers around, but it probably makes little - * sense. - */ - -#define MAX_DMA_BUFS 3 -static int alloc_bufs_at_read; -module_param(alloc_bufs_at_read, bool, 0444); -MODULE_PARM_DESC(alloc_bufs_at_read, - "Non-zero value causes DMA buffers to be allocated when the " - "video capture device is read, rather than at module load " - "time. This saves memory, but decreases the chances of " - "successfully getting those buffers."); - -static int n_dma_bufs = 3; -module_param(n_dma_bufs, uint, 0644); -MODULE_PARM_DESC(n_dma_bufs, - "The number of DMA buffers to allocate. Can be either two " - "(saves memory, makes timing tighter) or three."); - -static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2; /* Worst case */ -module_param(dma_buf_size, uint, 0444); -MODULE_PARM_DESC(dma_buf_size, - "The size of the allocated DMA buffers. If actual operating " - "parameters require larger buffers, an attempt to reallocate " - "will be made."); - -static int min_buffers = 1; -module_param(min_buffers, uint, 0644); -MODULE_PARM_DESC(min_buffers, - "The minimum number of streaming I/O buffers we are willing " - "to work with."); - -static int max_buffers = 10; -module_param(max_buffers, uint, 0644); -MODULE_PARM_DESC(max_buffers, - "The maximum number of streaming I/O buffers an application " - "will be allowed to allocate. These buffers are big and live " - "in vmalloc space."); - -static int flip; -module_param(flip, bool, 0444); -MODULE_PARM_DESC(flip, - "If set, the sensor will be instructed to flip the image " - "vertically."); - - -enum cafe_state { - S_NOTREADY, /* Not yet initialized */ - S_IDLE, /* Just hanging around */ - S_FLAKED, /* Some sort of problem */ - S_SINGLEREAD, /* In read() */ - S_SPECREAD, /* Speculative read (for future read()) */ - S_STREAMING /* Streaming data */ -}; - -/* - * Tracking of streaming I/O buffers. - */ -struct cafe_sio_buffer { - struct list_head list; - struct v4l2_buffer v4lbuf; - char *buffer; /* Where it lives in kernel space */ - int mapcount; - struct cafe_camera *cam; -}; - -/* - * A description of one of our devices. - * Locking: controlled by s_mutex. Certain fields, however, require - * the dev_lock spinlock; they are marked as such by comments. - * dev_lock is also required for access to device registers. - */ -struct cafe_camera -{ - struct v4l2_device v4l2_dev; - enum cafe_state state; - unsigned long flags; /* Buffer status, mainly (dev_lock) */ - int users; /* How many open FDs */ - struct file *owner; /* Who has data access (v4l2) */ - - /* - * Subsystem structures. - */ - struct pci_dev *pdev; - struct video_device vdev; - struct i2c_adapter i2c_adapter; - struct v4l2_subdev *sensor; - unsigned short sensor_addr; - - unsigned char __iomem *regs; - struct list_head dev_list; /* link to other devices */ - - /* DMA buffers */ - unsigned int nbufs; /* How many are alloc'd */ - int next_buf; /* Next to consume (dev_lock) */ - unsigned int dma_buf_size; /* allocated size */ - void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ - dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */ - unsigned int specframes; /* Unconsumed spec frames (dev_lock) */ - unsigned int sequence; /* Frame sequence number */ - unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */ - - /* Streaming buffers */ - unsigned int n_sbufs; /* How many we have */ - struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */ - struct list_head sb_avail; /* Available for data (we own) (dev_lock) */ - struct list_head sb_full; /* With data (user space owns) (dev_lock) */ - struct tasklet_struct s_tasklet; - - /* Current operating parameters */ - u32 sensor_type; /* Currently ov7670 only */ - struct v4l2_pix_format pix_format; - enum v4l2_mbus_pixelcode mbus_code; - - /* Locks */ - struct mutex s_mutex; /* Access to this structure */ - spinlock_t dev_lock; /* Access to device */ - - /* Misc */ - wait_queue_head_t smbus_wait; /* Waiting on i2c events */ - wait_queue_head_t iowait; /* Waiting on frame data */ -}; - -/* - * Status flags. Always manipulated with bit operations. - */ -#define CF_BUF0_VALID 0 /* Buffers valid - first three */ -#define CF_BUF1_VALID 1 -#define CF_BUF2_VALID 2 -#define CF_DMA_ACTIVE 3 /* A frame is incoming */ -#define CF_CONFIG_NEEDED 4 /* Must configure hardware */ - -#define sensor_call(cam, o, f, args...) \ - v4l2_subdev_call(cam->sensor, o, f, ##args) - -static inline struct cafe_camera *to_cam(struct v4l2_device *dev) -{ - return container_of(dev, struct cafe_camera, v4l2_dev); -} - -static struct cafe_format_struct { - __u8 *desc; - __u32 pixelformat; - int bpp; /* Bytes per pixel */ - enum v4l2_mbus_pixelcode mbus_code; -} cafe_formats[] = { - { - .desc = "YUYV 4:2:2", - .pixelformat = V4L2_PIX_FMT_YUYV, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, - .bpp = 2, - }, - { - .desc = "RGB 444", - .pixelformat = V4L2_PIX_FMT_RGB444, - .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, - .bpp = 2, - }, - { - .desc = "RGB 565", - .pixelformat = V4L2_PIX_FMT_RGB565, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, - .bpp = 2, - }, - { - .desc = "Raw RGB Bayer", - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8, - .bpp = 1 - }, -}; -#define N_CAFE_FMTS ARRAY_SIZE(cafe_formats) - -static struct cafe_format_struct *cafe_find_format(u32 pixelformat) -{ - unsigned i; - - for (i = 0; i < N_CAFE_FMTS; i++) - if (cafe_formats[i].pixelformat == pixelformat) - return cafe_formats + i; - /* Not found? Then return the first format. */ - return cafe_formats; -} - -/* - * Start over with DMA buffers - dev_lock needed. - */ -static void cafe_reset_buffers(struct cafe_camera *cam) -{ - int i; - - cam->next_buf = -1; - for (i = 0; i < cam->nbufs; i++) - clear_bit(i, &cam->flags); - cam->specframes = 0; -} - -static inline int cafe_needs_config(struct cafe_camera *cam) -{ - return test_bit(CF_CONFIG_NEEDED, &cam->flags); -} - -static void cafe_set_config_needed(struct cafe_camera *cam, int needed) -{ - if (needed) - set_bit(CF_CONFIG_NEEDED, &cam->flags); - else - clear_bit(CF_CONFIG_NEEDED, &cam->flags); -} - - - - -/* - * Debugging and related. - */ -#define cam_err(cam, fmt, arg...) \ - dev_err(&(cam)->pdev->dev, fmt, ##arg); -#define cam_warn(cam, fmt, arg...) \ - dev_warn(&(cam)->pdev->dev, fmt, ##arg); -#define cam_dbg(cam, fmt, arg...) \ - dev_dbg(&(cam)->pdev->dev, fmt, ##arg); - - -/* ---------------------------------------------------------------------*/ - -/* - * Device register I/O - */ -static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg, - unsigned int val) -{ - iowrite32(val, cam->regs + reg); -} - -static inline unsigned int cafe_reg_read(struct cafe_camera *cam, - unsigned int reg) -{ - return ioread32(cam->regs + reg); -} - - -static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg, - unsigned int val, unsigned int mask) -{ - unsigned int v = cafe_reg_read(cam, reg); - - v = (v & ~mask) | (val & mask); - cafe_reg_write(cam, reg, v); -} - -static inline void cafe_reg_clear_bit(struct cafe_camera *cam, - unsigned int reg, unsigned int val) -{ - cafe_reg_write_mask(cam, reg, 0, val); -} - -static inline void cafe_reg_set_bit(struct cafe_camera *cam, - unsigned int reg, unsigned int val) -{ - cafe_reg_write_mask(cam, reg, val, val); -} - - - -/* -------------------------------------------------------------------- */ -/* - * The I2C/SMBUS interface to the camera itself starts here. The - * controller handles SMBUS itself, presenting a relatively simple register - * interface; all we have to do is to tell it where to route the data. - */ -#define CAFE_SMBUS_TIMEOUT (HZ) /* generous */ - -static int cafe_smbus_write_done(struct cafe_camera *cam) -{ - unsigned long flags; - int c1; - - /* - * We must delay after the interrupt, or the controller gets confused - * and never does give us good status. Fortunately, we don't do this - * often. - */ - udelay(20); - spin_lock_irqsave(&cam->dev_lock, flags); - c1 = cafe_reg_read(cam, REG_TWSIC1); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT; -} - -static int cafe_smbus_write_data(struct cafe_camera *cam, - u16 addr, u8 command, u8 value) -{ - unsigned int rval; - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); - rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ - /* - * Marvell sez set clkdiv to all 1's for now. - */ - rval |= TWSIC0_CLKDIV; - cafe_reg_write(cam, REG_TWSIC0, rval); - (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ - rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); - cafe_reg_write(cam, REG_TWSIC1, rval); - spin_unlock_irqrestore(&cam->dev_lock, flags); - - /* Unfortunately, reading TWSIC1 too soon after sending a command - * causes the device to die. - * Use a busy-wait because we often send a large quantity of small - * commands at-once; using msleep() would cause a lot of context - * switches which take longer than 2ms, resulting in a noticable - * boot-time and capture-start delays. - */ - mdelay(2); - - /* - * Another sad fact is that sometimes, commands silently complete but - * cafe_smbus_write_done() never becomes aware of this. - * This happens at random and appears to possible occur with any - * command. - * We don't understand why this is. We work around this issue - * with the timeout in the wait below, assuming that all commands - * complete within the timeout. - */ - wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam), - CAFE_SMBUS_TIMEOUT); - - spin_lock_irqsave(&cam->dev_lock, flags); - rval = cafe_reg_read(cam, REG_TWSIC1); - spin_unlock_irqrestore(&cam->dev_lock, flags); - - if (rval & TWSIC1_WSTAT) { - cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr, - command, value); - return -EIO; - } - if (rval & TWSIC1_ERROR) { - cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr, - command, value); - return -EIO; - } - return 0; -} - - - -static int cafe_smbus_read_done(struct cafe_camera *cam) -{ - unsigned long flags; - int c1; - - /* - * We must delay after the interrupt, or the controller gets confused - * and never does give us good status. Fortunately, we don't do this - * often. - */ - udelay(20); - spin_lock_irqsave(&cam->dev_lock, flags); - c1 = cafe_reg_read(cam, REG_TWSIC1); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return c1 & (TWSIC1_RVALID|TWSIC1_ERROR); -} - - - -static int cafe_smbus_read_data(struct cafe_camera *cam, - u16 addr, u8 command, u8 *value) -{ - unsigned int rval; - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); - rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ - /* - * Marvel sez set clkdiv to all 1's for now. - */ - rval |= TWSIC0_CLKDIV; - cafe_reg_write(cam, REG_TWSIC0, rval); - (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ - rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); - cafe_reg_write(cam, REG_TWSIC1, rval); - spin_unlock_irqrestore(&cam->dev_lock, flags); - - wait_event_timeout(cam->smbus_wait, - cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT); - spin_lock_irqsave(&cam->dev_lock, flags); - rval = cafe_reg_read(cam, REG_TWSIC1); - spin_unlock_irqrestore(&cam->dev_lock, flags); - - if (rval & TWSIC1_ERROR) { - cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command); - return -EIO; - } - if (! (rval & TWSIC1_RVALID)) { - cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr, - command); - return -EIO; - } - *value = rval & 0xff; - return 0; -} - -/* - * Perform a transfer over SMBUS. This thing is called under - * the i2c bus lock, so we shouldn't race with ourselves... - */ -static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, - unsigned short flags, char rw, u8 command, - int size, union i2c_smbus_data *data) -{ - struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); - struct cafe_camera *cam = to_cam(v4l2_dev); - int ret = -EINVAL; - - /* - * This interface would appear to only do byte data ops. OK - * it can do word too, but the cam chip has no use for that. - */ - if (size != I2C_SMBUS_BYTE_DATA) { - cam_err(cam, "funky xfer size %d\n", size); - return -EINVAL; - } - - if (rw == I2C_SMBUS_WRITE) - ret = cafe_smbus_write_data(cam, addr, command, data->byte); - else if (rw == I2C_SMBUS_READ) - ret = cafe_smbus_read_data(cam, addr, command, &data->byte); - return ret; -} - - -static void cafe_smbus_enable_irq(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - -static u32 cafe_smbus_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_READ_BYTE_DATA | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA; -} - -static struct i2c_algorithm cafe_smbus_algo = { - .smbus_xfer = cafe_smbus_xfer, - .functionality = cafe_smbus_func -}; - -/* Somebody is on the bus */ -static void cafe_ctlr_stop_dma(struct cafe_camera *cam); -static void cafe_ctlr_power_down(struct cafe_camera *cam); - -static int cafe_smbus_setup(struct cafe_camera *cam) -{ - struct i2c_adapter *adap = &cam->i2c_adapter; - int ret; - - cafe_smbus_enable_irq(cam); - adap->owner = THIS_MODULE; - adap->algo = &cafe_smbus_algo; - strcpy(adap->name, "cafe_ccic"); - adap->dev.parent = &cam->pdev->dev; - i2c_set_adapdata(adap, &cam->v4l2_dev); - ret = i2c_add_adapter(adap); - if (ret) - printk(KERN_ERR "Unable to register cafe i2c adapter\n"); - return ret; -} - -static void cafe_smbus_shutdown(struct cafe_camera *cam) -{ - i2c_del_adapter(&cam->i2c_adapter); -} - - -/* ------------------------------------------------------------------- */ -/* - * Deal with the controller. - */ - -/* - * Do everything we think we need to have the interface operating - * according to the desired format. - */ -static void cafe_ctlr_dma(struct cafe_camera *cam) -{ - /* - * Store the first two Y buffers (we aren't supporting - * planar formats for now, so no UV bufs). Then either - * set the third if it exists, or tell the controller - * to just use two. - */ - cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]); - cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]); - if (cam->nbufs > 2) { - cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]); - cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); - } - else - cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); - cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */ -} - -static void cafe_ctlr_image(struct cafe_camera *cam) -{ - int imgsz; - struct v4l2_pix_format *fmt = &cam->pix_format; - - imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | - (fmt->bytesperline & IMGSZ_H_MASK); - cafe_reg_write(cam, REG_IMGSIZE, imgsz); - cafe_reg_write(cam, REG_IMGOFFSET, 0); - /* YPITCH just drops the last two bits */ - cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline, - IMGP_YP_MASK); - /* - * Tell the controller about the image format we are using. - */ - switch (cam->pix_format.pixelformat) { - case V4L2_PIX_FMT_YUYV: - cafe_reg_write_mask(cam, REG_CTRL0, - C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV, - C0_DF_MASK); - break; - - case V4L2_PIX_FMT_RGB444: - cafe_reg_write_mask(cam, REG_CTRL0, - C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB, - C0_DF_MASK); - /* Alpha value? */ - break; - - case V4L2_PIX_FMT_RGB565: - cafe_reg_write_mask(cam, REG_CTRL0, - C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR, - C0_DF_MASK); - break; - - default: - cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat); - break; - } - /* - * Make sure it knows we want to use hsync/vsync. - */ - cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, - C0_SIFM_MASK); -} - - -/* - * Configure the controller for operation; caller holds the - * device mutex. - */ -static int cafe_ctlr_configure(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_ctlr_dma(cam); - cafe_ctlr_image(cam); - cafe_set_config_needed(cam, 0); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return 0; -} - -static void cafe_ctlr_irq_enable(struct cafe_camera *cam) -{ - /* - * Clear any pending interrupts, since we do not - * expect to have I/O active prior to enabling. - */ - cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); - cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS); -} - -static void cafe_ctlr_irq_disable(struct cafe_camera *cam) -{ - cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); -} - -/* - * Make the controller start grabbing images. Everything must - * be set up before doing this. - */ -static void cafe_ctlr_start(struct cafe_camera *cam) -{ - /* set_bit performs a read, so no other barrier should be - needed here */ - cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE); -} - -static void cafe_ctlr_stop(struct cafe_camera *cam) -{ - cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); -} - -static void cafe_ctlr_init(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - /* - * Added magic to bring up the hardware on the B-Test board - */ - cafe_reg_write(cam, 0x3038, 0x8); - cafe_reg_write(cam, 0x315c, 0x80008); - /* - * Go through the dance needed to wake the device up. - * Note that these registers are global and shared - * with the NAND and SD devices. Interaction between the - * three still needs to be examined. - */ - cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ - cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); - cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); - /* - * Here we must wait a bit for the controller to come around. - */ - spin_unlock_irqrestore(&cam->dev_lock, flags); - msleep(5); - spin_lock_irqsave(&cam->dev_lock, flags); - - cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); - cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); - /* - * Make sure it's not powered down. - */ - cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); - /* - * Turn off the enable bit. It sure should be off anyway, - * but it's good to be sure. - */ - cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); - /* - * Mask all interrupts. - */ - cafe_reg_write(cam, REG_IRQMASK, 0); - /* - * Clock the sensor appropriately. Controller clock should - * be 48MHz, sensor "typical" value is half that. - */ - cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - - -/* - * Stop the controller, and don't return until we're really sure that no - * further DMA is going on. - */ -static void cafe_ctlr_stop_dma(struct cafe_camera *cam) -{ - unsigned long flags; - - /* - * Theory: stop the camera controller (whether it is operating - * or not). Delay briefly just in case we race with the SOF - * interrupt, then wait until no DMA is active. - */ - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_ctlr_stop(cam); - spin_unlock_irqrestore(&cam->dev_lock, flags); - mdelay(1); - wait_event_timeout(cam->iowait, - !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ); - if (test_bit(CF_DMA_ACTIVE, &cam->flags)) - cam_err(cam, "Timeout waiting for DMA to end\n"); - /* This would be bad news - what now? */ - spin_lock_irqsave(&cam->dev_lock, flags); - cam->state = S_IDLE; - cafe_ctlr_irq_disable(cam); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - -/* - * Power up and down. - */ -static void cafe_ctlr_power_up(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); - /* - * Part one of the sensor dance: turn the global - * GPIO signal on. - */ - cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); - cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL); - /* - * Put the sensor into operational mode (assumes OLPC-style - * wiring). Control 0 is reset - set to 1 to operate. - * Control 1 is power down, set to 0 to operate. - */ - cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ -/* mdelay(1); */ /* Marvell says 1ms will do it */ - cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); -/* mdelay(1); */ /* Enough? */ - spin_unlock_irqrestore(&cam->dev_lock, flags); - msleep(5); /* Just to be sure */ -} - -static void cafe_ctlr_power_down(struct cafe_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); - cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); - cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT); - cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - -/* -------------------------------------------------------------------- */ -/* - * Communications with the sensor. - */ - -static int __cafe_cam_reset(struct cafe_camera *cam) -{ - return sensor_call(cam, core, reset, 0); -} - -/* - * We have found the sensor on the i2c. Let's try to have a - * conversation. - */ -static int cafe_cam_init(struct cafe_camera *cam) -{ - struct v4l2_dbg_chip_ident chip; - int ret; - - mutex_lock(&cam->s_mutex); - if (cam->state != S_NOTREADY) - cam_warn(cam, "Cam init with device in funky state %d", - cam->state); - ret = __cafe_cam_reset(cam); - if (ret) - goto out; - chip.ident = V4L2_IDENT_NONE; - chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR; - chip.match.addr = cam->sensor_addr; - ret = sensor_call(cam, core, g_chip_ident, &chip); - if (ret) - goto out; - cam->sensor_type = chip.ident; - if (cam->sensor_type != V4L2_IDENT_OV7670) { - cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type); - ret = -EINVAL; - goto out; - } -/* Get/set parameters? */ - ret = 0; - cam->state = S_IDLE; - out: - cafe_ctlr_power_down(cam); - mutex_unlock(&cam->s_mutex); - return ret; -} - -/* - * Configure the sensor to match the parameters we have. Caller should - * hold s_mutex - */ -static int cafe_cam_set_flip(struct cafe_camera *cam) -{ - struct v4l2_control ctrl; - - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_VFLIP; - ctrl.value = flip; - return sensor_call(cam, core, s_ctrl, &ctrl); -} - - -static int cafe_cam_configure(struct cafe_camera *cam) -{ - struct v4l2_mbus_framefmt mbus_fmt; - int ret; - - v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code); - ret = sensor_call(cam, core, init, 0); - if (ret == 0) - ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); - /* - * OV7670 does weird things if flip is set *before* format... - */ - ret += cafe_cam_set_flip(cam); - return ret; -} - -/* -------------------------------------------------------------------- */ -/* - * DMA buffer management. These functions need s_mutex held. - */ - -/* FIXME: this is inefficient as hell, since dma_alloc_coherent just - * does a get_free_pages() call, and we waste a good chunk of an orderN - * allocation. Should try to allocate the whole set in one chunk. - */ -static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime) -{ - int i; - - cafe_set_config_needed(cam, 1); - if (loadtime) - cam->dma_buf_size = dma_buf_size; - else - cam->dma_buf_size = cam->pix_format.sizeimage; - if (n_dma_bufs > 3) - n_dma_bufs = 3; - - cam->nbufs = 0; - for (i = 0; i < n_dma_bufs; i++) { - cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev, - cam->dma_buf_size, cam->dma_handles + i, - GFP_KERNEL); - if (cam->dma_bufs[i] == NULL) { - cam_warn(cam, "Failed to allocate DMA buffer\n"); - break; - } - /* For debug, remove eventually */ - memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size); - (cam->nbufs)++; - } - - switch (cam->nbufs) { - case 1: - dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, - cam->dma_bufs[0], cam->dma_handles[0]); - cam->nbufs = 0; - case 0: - cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); - return -ENOMEM; - - case 2: - if (n_dma_bufs > 2) - cam_warn(cam, "Will limp along with only 2 buffers\n"); - break; - } - return 0; -} - -static void cafe_free_dma_bufs(struct cafe_camera *cam) -{ - int i; - - for (i = 0; i < cam->nbufs; i++) { - dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, - cam->dma_bufs[i], cam->dma_handles[i]); - cam->dma_bufs[i] = NULL; - } - cam->nbufs = 0; -} - - - - - -/* ----------------------------------------------------------------------- */ -/* - * Here starts the V4L2 interface code. - */ - -/* - * Read an image from the device. - */ -static ssize_t cafe_deliver_buffer(struct cafe_camera *cam, - char __user *buffer, size_t len, loff_t *pos) -{ - int bufno; - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - if (cam->next_buf < 0) { - cam_err(cam, "deliver_buffer: No next buffer\n"); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return -EIO; - } - bufno = cam->next_buf; - clear_bit(bufno, &cam->flags); - if (++(cam->next_buf) >= cam->nbufs) - cam->next_buf = 0; - if (! test_bit(cam->next_buf, &cam->flags)) - cam->next_buf = -1; - cam->specframes = 0; - spin_unlock_irqrestore(&cam->dev_lock, flags); - - if (len > cam->pix_format.sizeimage) - len = cam->pix_format.sizeimage; - if (copy_to_user(buffer, cam->dma_bufs[bufno], len)) - return -EFAULT; - (*pos) += len; - return len; -} - -/* - * Get everything ready, and start grabbing frames. - */ -static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state) -{ - int ret; - unsigned long flags; - - /* - * Configuration. If we still don't have DMA buffers, - * make one last, desperate attempt. - */ - if (cam->nbufs == 0) - if (cafe_alloc_dma_bufs(cam, 0)) - return -ENOMEM; - - if (cafe_needs_config(cam)) { - cafe_cam_configure(cam); - ret = cafe_ctlr_configure(cam); - if (ret) - return ret; - } - - /* - * Turn it loose. - */ - spin_lock_irqsave(&cam->dev_lock, flags); - cafe_reset_buffers(cam); - cafe_ctlr_irq_enable(cam); - cam->state = state; - cafe_ctlr_start(cam); - spin_unlock_irqrestore(&cam->dev_lock, flags); - return 0; -} - - -static ssize_t cafe_v4l_read(struct file *filp, - char __user *buffer, size_t len, loff_t *pos) -{ - struct cafe_camera *cam = filp->private_data; - int ret = 0; - - /* - * Perhaps we're in speculative read mode and already - * have data? - */ - mutex_lock(&cam->s_mutex); - if (cam->state == S_SPECREAD) { - if (cam->next_buf >= 0) { - ret = cafe_deliver_buffer(cam, buffer, len, pos); - if (ret != 0) - goto out_unlock; - } - } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) { - ret = -EIO; - goto out_unlock; - } else if (cam->state != S_IDLE) { - ret = -EBUSY; - goto out_unlock; - } - - /* - * v4l2: multiple processes can open the device, but only - * one gets to grab data from it. - */ - if (cam->owner && cam->owner != filp) { - ret = -EBUSY; - goto out_unlock; - } - cam->owner = filp; - - /* - * Do setup if need be. - */ - if (cam->state != S_SPECREAD) { - ret = cafe_read_setup(cam, S_SINGLEREAD); - if (ret) - goto out_unlock; - } - /* - * Wait for something to happen. This should probably - * be interruptible (FIXME). - */ - wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ); - if (cam->next_buf < 0) { - cam_err(cam, "read() operation timed out\n"); - cafe_ctlr_stop_dma(cam); - ret = -EIO; - goto out_unlock; - } - /* - * Give them their data and we should be done. - */ - ret = cafe_deliver_buffer(cam, buffer, len, pos); - - out_unlock: - mutex_unlock(&cam->s_mutex); - return ret; -} - - - - - - - - -/* - * Streaming I/O support. - */ - - - -static int cafe_vidioc_streamon(struct file *filp, void *priv, - enum v4l2_buf_type type) -{ - struct cafe_camera *cam = filp->private_data; - int ret = -EINVAL; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - goto out; - mutex_lock(&cam->s_mutex); - if (cam->state != S_IDLE || cam->n_sbufs == 0) - goto out_unlock; - - cam->sequence = 0; - ret = cafe_read_setup(cam, S_STREAMING); - - out_unlock: - mutex_unlock(&cam->s_mutex); - out: - return ret; -} - - -static int cafe_vidioc_streamoff(struct file *filp, void *priv, - enum v4l2_buf_type type) -{ - struct cafe_camera *cam = filp->private_data; - int ret = -EINVAL; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - goto out; - mutex_lock(&cam->s_mutex); - if (cam->state != S_STREAMING) - goto out_unlock; - - cafe_ctlr_stop_dma(cam); - ret = 0; - - out_unlock: - mutex_unlock(&cam->s_mutex); - out: - return ret; -} - - - -static int cafe_setup_siobuf(struct cafe_camera *cam, int index) -{ - struct cafe_sio_buffer *buf = cam->sb_bufs + index; - - INIT_LIST_HEAD(&buf->list); - buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage); - buf->buffer = vmalloc_user(buf->v4lbuf.length); - if (buf->buffer == NULL) - return -ENOMEM; - buf->mapcount = 0; - buf->cam = cam; - - buf->v4lbuf.index = index; - buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->v4lbuf.field = V4L2_FIELD_NONE; - buf->v4lbuf.memory = V4L2_MEMORY_MMAP; - /* - * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg - * just uses the length times the index, but the spec warns - * against doing just that - vma merging problems. So we - * leave a gap between each pair of buffers. - */ - buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; - return 0; -} - -static int cafe_free_sio_buffers(struct cafe_camera *cam) -{ - int i; - - /* - * If any buffers are mapped, we cannot free them at all. - */ - for (i = 0; i < cam->n_sbufs; i++) - if (cam->sb_bufs[i].mapcount > 0) - return -EBUSY; - /* - * OK, let's do it. - */ - for (i = 0; i < cam->n_sbufs; i++) - vfree(cam->sb_bufs[i].buffer); - cam->n_sbufs = 0; - kfree(cam->sb_bufs); - cam->sb_bufs = NULL; - INIT_LIST_HEAD(&cam->sb_avail); - INIT_LIST_HEAD(&cam->sb_full); - return 0; -} - - - -static int cafe_vidioc_reqbufs(struct file *filp, void *priv, - struct v4l2_requestbuffers *req) -{ - struct cafe_camera *cam = filp->private_data; - int ret = 0; /* Silence warning */ - - /* - * Make sure it's something we can do. User pointers could be - * implemented without great pain, but that's not been done yet. - */ - if (req->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - /* - * If they ask for zero buffers, they really want us to stop streaming - * (if it's happening) and free everything. Should we check owner? - */ - mutex_lock(&cam->s_mutex); - if (req->count == 0) { - if (cam->state == S_STREAMING) - cafe_ctlr_stop_dma(cam); - ret = cafe_free_sio_buffers (cam); - goto out; - } - /* - * Device needs to be idle and working. We *could* try to do the - * right thing in S_SPECREAD by shutting things down, but it - * probably doesn't matter. - */ - if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) { - ret = -EBUSY; - goto out; - } - cam->owner = filp; - - if (req->count < min_buffers) - req->count = min_buffers; - else if (req->count > max_buffers) - req->count = max_buffers; - if (cam->n_sbufs > 0) { - ret = cafe_free_sio_buffers(cam); - if (ret) - goto out; - } - - cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer), - GFP_KERNEL); - if (cam->sb_bufs == NULL) { - ret = -ENOMEM; - goto out; - } - for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) { - ret = cafe_setup_siobuf(cam, cam->n_sbufs); - if (ret) - break; - } - - if (cam->n_sbufs == 0) /* no luck at all - ret already set */ - kfree(cam->sb_bufs); - req->count = cam->n_sbufs; /* In case of partial success */ - - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int cafe_vidioc_querybuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct cafe_camera *cam = filp->private_data; - int ret = -EINVAL; - - mutex_lock(&cam->s_mutex); - if (buf->index >= cam->n_sbufs) - goto out; - *buf = cam->sb_bufs[buf->index].v4lbuf; - ret = 0; - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - -static int cafe_vidioc_qbuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct cafe_camera *cam = filp->private_data; - struct cafe_sio_buffer *sbuf; - int ret = -EINVAL; - unsigned long flags; - - mutex_lock(&cam->s_mutex); - if (buf->index >= cam->n_sbufs) - goto out; - sbuf = cam->sb_bufs + buf->index; - if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) { - ret = 0; /* Already queued?? */ - goto out; - } - if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) { - /* Spec doesn't say anything, seems appropriate tho */ - ret = -EBUSY; - goto out; - } - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; - spin_lock_irqsave(&cam->dev_lock, flags); - list_add(&sbuf->list, &cam->sb_avail); - spin_unlock_irqrestore(&cam->dev_lock, flags); - ret = 0; - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - -static int cafe_vidioc_dqbuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct cafe_camera *cam = filp->private_data; - struct cafe_sio_buffer *sbuf; - int ret = -EINVAL; - unsigned long flags; - - mutex_lock(&cam->s_mutex); - if (cam->state != S_STREAMING) - goto out_unlock; - if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto out_unlock; - } - - while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) { - mutex_unlock(&cam->s_mutex); - if (wait_event_interruptible(cam->iowait, - !list_empty(&cam->sb_full))) { - ret = -ERESTARTSYS; - goto out; - } - mutex_lock(&cam->s_mutex); - } - - if (cam->state != S_STREAMING) - ret = -EINTR; - else { - spin_lock_irqsave(&cam->dev_lock, flags); - /* Should probably recheck !list_empty() here */ - sbuf = list_entry(cam->sb_full.next, - struct cafe_sio_buffer, list); - list_del_init(&sbuf->list); - spin_unlock_irqrestore(&cam->dev_lock, flags); - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; - *buf = sbuf->v4lbuf; - ret = 0; - } - - out_unlock: - mutex_unlock(&cam->s_mutex); - out: - return ret; -} - - - -static void cafe_v4l_vm_open(struct vm_area_struct *vma) -{ - struct cafe_sio_buffer *sbuf = vma->vm_private_data; - /* - * Locking: done under mmap_sem, so we don't need to - * go back to the camera lock here. - */ - sbuf->mapcount++; -} - - -static void cafe_v4l_vm_close(struct vm_area_struct *vma) -{ - struct cafe_sio_buffer *sbuf = vma->vm_private_data; - - mutex_lock(&sbuf->cam->s_mutex); - sbuf->mapcount--; - /* Docs say we should stop I/O too... */ - if (sbuf->mapcount == 0) - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; - mutex_unlock(&sbuf->cam->s_mutex); -} - -static const struct vm_operations_struct cafe_v4l_vm_ops = { - .open = cafe_v4l_vm_open, - .close = cafe_v4l_vm_close -}; - - -static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct cafe_camera *cam = filp->private_data; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int ret = -EINVAL; - int i; - struct cafe_sio_buffer *sbuf = NULL; - - if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) - return -EINVAL; - /* - * Find the buffer they are looking for. - */ - mutex_lock(&cam->s_mutex); - for (i = 0; i < cam->n_sbufs; i++) - if (cam->sb_bufs[i].v4lbuf.m.offset == offset) { - sbuf = cam->sb_bufs + i; - break; - } - if (sbuf == NULL) - goto out; - - ret = remap_vmalloc_range(vma, sbuf->buffer, 0); - if (ret) - goto out; - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_private_data = sbuf; - vma->vm_ops = &cafe_v4l_vm_ops; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; - cafe_v4l_vm_open(vma); - ret = 0; - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - - - -static int cafe_v4l_open(struct file *filp) -{ - struct cafe_camera *cam = video_drvdata(filp); - - filp->private_data = cam; - - mutex_lock(&cam->s_mutex); - if (cam->users == 0) { - cafe_ctlr_power_up(cam); - __cafe_cam_reset(cam); - cafe_set_config_needed(cam, 1); - /* FIXME make sure this is complete */ - } - (cam->users)++; - mutex_unlock(&cam->s_mutex); - return 0; -} - - -static int cafe_v4l_release(struct file *filp) -{ - struct cafe_camera *cam = filp->private_data; - - mutex_lock(&cam->s_mutex); - (cam->users)--; - if (filp == cam->owner) { - cafe_ctlr_stop_dma(cam); - cafe_free_sio_buffers(cam); - cam->owner = NULL; - } - if (cam->users == 0) { - cafe_ctlr_power_down(cam); - if (alloc_bufs_at_read) - cafe_free_dma_bufs(cam); - } - mutex_unlock(&cam->s_mutex); - return 0; -} - - - -static unsigned int cafe_v4l_poll(struct file *filp, - struct poll_table_struct *pt) -{ - struct cafe_camera *cam = filp->private_data; - - poll_wait(filp, &cam->iowait, pt); - if (cam->next_buf >= 0) - return POLLIN | POLLRDNORM; - return 0; -} - - - -static int cafe_vidioc_queryctrl(struct file *filp, void *priv, - struct v4l2_queryctrl *qc) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, core, queryctrl, qc); - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int cafe_vidioc_g_ctrl(struct file *filp, void *priv, - struct v4l2_control *ctrl) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, core, g_ctrl, ctrl); - mutex_unlock(&cam->s_mutex); - return ret; -} - - -static int cafe_vidioc_s_ctrl(struct file *filp, void *priv, - struct v4l2_control *ctrl) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, core, s_ctrl, ctrl); - mutex_unlock(&cam->s_mutex); - return ret; -} - - - - - -static int cafe_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strcpy(cap->driver, "cafe_ccic"); - strcpy(cap->card, "cafe_ccic"); - cap->version = CAFE_VERSION; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - return 0; -} - - -/* - * The default format we use until somebody says otherwise. - */ -static const struct v4l2_pix_format cafe_def_pix_format = { - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .pixelformat = V4L2_PIX_FMT_YUYV, - .field = V4L2_FIELD_NONE, - .bytesperline = VGA_WIDTH*2, - .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, -}; - -static const enum v4l2_mbus_pixelcode cafe_def_mbus_code = - V4L2_MBUS_FMT_YUYV8_2X8; - -static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_fmtdesc *fmt) -{ - if (fmt->index >= N_CAFE_FMTS) - return -EINVAL; - strlcpy(fmt->description, cafe_formats[fmt->index].desc, - sizeof(fmt->description)); - fmt->pixelformat = cafe_formats[fmt->index].pixelformat; - return 0; -} - -static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_format *fmt) -{ - struct cafe_camera *cam = priv; - struct cafe_format_struct *f; - struct v4l2_pix_format *pix = &fmt->fmt.pix; - struct v4l2_mbus_framefmt mbus_fmt; - int ret; - - f = cafe_find_format(pix->pixelformat); - pix->pixelformat = f->pixelformat; - v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code); - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); - mutex_unlock(&cam->s_mutex); - v4l2_fill_pix_format(pix, &mbus_fmt); - pix->bytesperline = pix->width * f->bpp; - pix->sizeimage = pix->height * pix->bytesperline; - return ret; -} - -static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_format *fmt) -{ - struct cafe_camera *cam = priv; - struct cafe_format_struct *f; - int ret; - - /* - * Can't do anything if the device is not idle - * Also can't if there are streaming buffers in place. - */ - if (cam->state != S_IDLE || cam->n_sbufs > 0) - return -EBUSY; - - f = cafe_find_format(fmt->fmt.pix.pixelformat); - - /* - * See if the formatting works in principle. - */ - ret = cafe_vidioc_try_fmt_vid_cap(filp, priv, fmt); - if (ret) - return ret; - /* - * Now we start to change things for real, so let's do it - * under lock. - */ - mutex_lock(&cam->s_mutex); - cam->pix_format = fmt->fmt.pix; - cam->mbus_code = f->mbus_code; - - /* - * Make sure we have appropriate DMA buffers. - */ - ret = -ENOMEM; - if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage) - cafe_free_dma_bufs(cam); - if (cam->nbufs == 0) { - if (cafe_alloc_dma_bufs(cam, 0)) - goto out; - } - /* - * It looks like this might work, so let's program the sensor. - */ - ret = cafe_cam_configure(cam); - if (! ret) - ret = cafe_ctlr_configure(cam); - out: - mutex_unlock(&cam->s_mutex); - return ret; -} - -/* - * Return our stored notion of how the camera is/should be configured. - * The V4l2 spec wants us to be smarter, and actually get this from - * the camera (and not mess with it at open time). Someday. - */ -static int cafe_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_format *f) -{ - struct cafe_camera *cam = priv; - - f->fmt.pix = cam->pix_format; - return 0; -} - -/* - * We only have one input - the sensor - so minimize the nonsense here. - */ -static int cafe_vidioc_enum_input(struct file *filp, void *priv, - struct v4l2_input *input) -{ - if (input->index != 0) - return -EINVAL; - - input->type = V4L2_INPUT_TYPE_CAMERA; - input->std = V4L2_STD_ALL; /* Not sure what should go here */ - strcpy(input->name, "Camera"); - return 0; -} - -static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -/* from vivi.c */ -static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) -{ - return 0; -} - -/* - * G/S_PARM. Most of this is done by the sensor, but we are - * the level which controls the number of read buffers. - */ -static int cafe_vidioc_g_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, g_parm, parms); - mutex_unlock(&cam->s_mutex); - parms->parm.capture.readbuffers = n_dma_bufs; - return ret; -} - -static int cafe_vidioc_s_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, s_parm, parms); - mutex_unlock(&cam->s_mutex); - parms->parm.capture.readbuffers = n_dma_bufs; - return ret; -} - -static int cafe_vidioc_g_chip_ident(struct file *file, void *priv, - struct v4l2_dbg_chip_ident *chip) -{ - struct cafe_camera *cam = priv; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (v4l2_chip_match_host(&chip->match)) { - chip->ident = V4L2_IDENT_CAFE; - return 0; - } - return sensor_call(cam, core, g_chip_ident, chip); -} - -static int cafe_vidioc_enum_framesizes(struct file *filp, void *priv, - struct v4l2_frmsizeenum *sizes) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, enum_framesizes, sizes); - mutex_unlock(&cam->s_mutex); - return ret; -} - -static int cafe_vidioc_enum_frameintervals(struct file *filp, void *priv, - struct v4l2_frmivalenum *interval) -{ - struct cafe_camera *cam = priv; - int ret; - - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, enum_frameintervals, interval); - mutex_unlock(&cam->s_mutex); - return ret; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cafe_vidioc_g_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct cafe_camera *cam = priv; - - if (v4l2_chip_match_host(®->match)) { - reg->val = cafe_reg_read(cam, reg->reg); - reg->size = 4; - return 0; - } - return sensor_call(cam, core, g_register, reg); -} - -static int cafe_vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct cafe_camera *cam = priv; - - if (v4l2_chip_match_host(®->match)) { - cafe_reg_write(cam, reg->reg, reg->val); - return 0; - } - return sensor_call(cam, core, s_register, reg); -} -#endif - -/* - * This template device holds all of those v4l2 methods; we - * clone it for specific real devices. - */ - -static const struct v4l2_file_operations cafe_v4l_fops = { - .owner = THIS_MODULE, - .open = cafe_v4l_open, - .release = cafe_v4l_release, - .read = cafe_v4l_read, - .poll = cafe_v4l_poll, - .mmap = cafe_v4l_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { - .vidioc_querycap = cafe_vidioc_querycap, - .vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cafe_vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = cafe_vidioc_g_fmt_vid_cap, - .vidioc_enum_input = cafe_vidioc_enum_input, - .vidioc_g_input = cafe_vidioc_g_input, - .vidioc_s_input = cafe_vidioc_s_input, - .vidioc_s_std = cafe_vidioc_s_std, - .vidioc_reqbufs = cafe_vidioc_reqbufs, - .vidioc_querybuf = cafe_vidioc_querybuf, - .vidioc_qbuf = cafe_vidioc_qbuf, - .vidioc_dqbuf = cafe_vidioc_dqbuf, - .vidioc_streamon = cafe_vidioc_streamon, - .vidioc_streamoff = cafe_vidioc_streamoff, - .vidioc_queryctrl = cafe_vidioc_queryctrl, - .vidioc_g_ctrl = cafe_vidioc_g_ctrl, - .vidioc_s_ctrl = cafe_vidioc_s_ctrl, - .vidioc_g_parm = cafe_vidioc_g_parm, - .vidioc_s_parm = cafe_vidioc_s_parm, - .vidioc_enum_framesizes = cafe_vidioc_enum_framesizes, - .vidioc_enum_frameintervals = cafe_vidioc_enum_frameintervals, - .vidioc_g_chip_ident = cafe_vidioc_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = cafe_vidioc_g_register, - .vidioc_s_register = cafe_vidioc_s_register, -#endif -}; - -static struct video_device cafe_v4l_template = { - .name = "cafe", - .tvnorms = V4L2_STD_NTSC_M, - .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ - - .fops = &cafe_v4l_fops, - .ioctl_ops = &cafe_v4l_ioctl_ops, - .release = video_device_release_empty, -}; - - -/* ---------------------------------------------------------------------- */ -/* - * Interrupt handler stuff - */ - - - -static void cafe_frame_tasklet(unsigned long data) -{ - struct cafe_camera *cam = (struct cafe_camera *) data; - int i; - unsigned long flags; - struct cafe_sio_buffer *sbuf; - - spin_lock_irqsave(&cam->dev_lock, flags); - for (i = 0; i < cam->nbufs; i++) { - int bufno = cam->next_buf; - if (bufno < 0) { /* "will never happen" */ - cam_err(cam, "No valid bufs in tasklet!\n"); - break; - } - if (++(cam->next_buf) >= cam->nbufs) - cam->next_buf = 0; - if (! test_bit(bufno, &cam->flags)) - continue; - if (list_empty(&cam->sb_avail)) - break; /* Leave it valid, hope for better later */ - clear_bit(bufno, &cam->flags); - sbuf = list_entry(cam->sb_avail.next, - struct cafe_sio_buffer, list); - /* - * Drop the lock during the big copy. This *should* be safe... - */ - spin_unlock_irqrestore(&cam->dev_lock, flags); - memcpy(sbuf->buffer, cam->dma_bufs[bufno], - cam->pix_format.sizeimage); - sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; - sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; - spin_lock_irqsave(&cam->dev_lock, flags); - list_move_tail(&sbuf->list, &cam->sb_full); - } - if (! list_empty(&cam->sb_full)) - wake_up(&cam->iowait); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - - - -static void cafe_frame_complete(struct cafe_camera *cam, int frame) -{ - /* - * Basic frame housekeeping. - */ - if (test_bit(frame, &cam->flags) && printk_ratelimit()) - cam_err(cam, "Frame overrun on %d, frames lost\n", frame); - set_bit(frame, &cam->flags); - clear_bit(CF_DMA_ACTIVE, &cam->flags); - if (cam->next_buf < 0) - cam->next_buf = frame; - cam->buf_seq[frame] = ++(cam->sequence); - - switch (cam->state) { - /* - * If in single read mode, try going speculative. - */ - case S_SINGLEREAD: - cam->state = S_SPECREAD; - cam->specframes = 0; - wake_up(&cam->iowait); - break; - - /* - * If we are already doing speculative reads, and nobody is - * reading them, just stop. - */ - case S_SPECREAD: - if (++(cam->specframes) >= cam->nbufs) { - cafe_ctlr_stop(cam); - cafe_ctlr_irq_disable(cam); - cam->state = S_IDLE; - } - wake_up(&cam->iowait); - break; - /* - * For the streaming case, we defer the real work to the - * camera tasklet. - * - * FIXME: if the application is not consuming the buffers, - * we should eventually put things on hold and restart in - * vidioc_dqbuf(). - */ - case S_STREAMING: - tasklet_schedule(&cam->s_tasklet); - break; - - default: - cam_err(cam, "Frame interrupt in non-operational state\n"); - break; - } -} - - - - -static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs) -{ - unsigned int frame; - - cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */ - /* - * Handle any frame completions. There really should - * not be more than one of these, or we have fallen - * far behind. - */ - for (frame = 0; frame < cam->nbufs; frame++) - if (irqs & (IRQ_EOF0 << frame)) - cafe_frame_complete(cam, frame); - /* - * If a frame starts, note that we have DMA active. This - * code assumes that we won't get multiple frame interrupts - * at once; may want to rethink that. - */ - if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) - set_bit(CF_DMA_ACTIVE, &cam->flags); -} - - - -static irqreturn_t cafe_irq(int irq, void *data) -{ - struct cafe_camera *cam = data; - unsigned int irqs; - - spin_lock(&cam->dev_lock); - irqs = cafe_reg_read(cam, REG_IRQSTAT); - if ((irqs & ALLIRQS) == 0) { - spin_unlock(&cam->dev_lock); - return IRQ_NONE; - } - if (irqs & FRAMEIRQS) - cafe_frame_irq(cam, irqs); - if (irqs & TWSIIRQS) { - cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS); - wake_up(&cam->smbus_wait); - } - spin_unlock(&cam->dev_lock); - return IRQ_HANDLED; -} - - -/* -------------------------------------------------------------------------- */ -/* - * PCI interface stuff. - */ - -static const struct dmi_system_id olpc_xo1_dmi[] = { - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "OLPC"), - DMI_MATCH(DMI_PRODUCT_NAME, "XO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "1"), - }, - }, - { } -}; - -static int cafe_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - int ret; - struct cafe_camera *cam; - struct ov7670_config sensor_cfg = { - /* This controller only does SMBUS */ - .use_smbus = true, - - /* - * Exclude QCIF mode, because it only captures a tiny portion - * of the sensor FOV - */ - .min_width = 320, - .min_height = 240, - }; - struct i2c_board_info ov7670_info = { - .type = "ov7670", - .addr = 0x42, - .platform_data = &sensor_cfg, - }; - - /* - * Start putting together one of our big camera structures. - */ - ret = -ENOMEM; - cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL); - if (cam == NULL) - goto out; - ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev); - if (ret) - goto out_free; - - mutex_init(&cam->s_mutex); - spin_lock_init(&cam->dev_lock); - cam->state = S_NOTREADY; - cafe_set_config_needed(cam, 1); - init_waitqueue_head(&cam->smbus_wait); - init_waitqueue_head(&cam->iowait); - cam->pdev = pdev; - cam->pix_format = cafe_def_pix_format; - cam->mbus_code = cafe_def_mbus_code; - INIT_LIST_HEAD(&cam->dev_list); - INIT_LIST_HEAD(&cam->sb_avail); - INIT_LIST_HEAD(&cam->sb_full); - tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam); - /* - * Get set up on the PCI bus. - */ - ret = pci_enable_device(pdev); - if (ret) - goto out_unreg; - pci_set_master(pdev); - - ret = -EIO; - cam->regs = pci_iomap(pdev, 0, 0); - if (! cam->regs) { - printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n"); - goto out_unreg; - } - ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam); - if (ret) - goto out_iounmap; - /* - * Initialize the controller and leave it powered up. It will - * stay that way until the sensor driver shows up. - */ - cafe_ctlr_init(cam); - cafe_ctlr_power_up(cam); - /* - * Set up I2C/SMBUS communications. We have to drop the mutex here - * because the sensor could attach in this call chain, leading to - * unsightly deadlocks. - */ - ret = cafe_smbus_setup(cam); - if (ret) - goto out_freeirq; - - /* Apply XO-1 clock speed */ - if (dmi_check_system(olpc_xo1_dmi)) - sensor_cfg.clock_speed = 45; - - cam->sensor_addr = ov7670_info.addr; - cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, &cam->i2c_adapter, - &ov7670_info, NULL); - if (cam->sensor == NULL) { - ret = -ENODEV; - goto out_smbus; - } - - ret = cafe_cam_init(cam); - if (ret) - goto out_smbus; - - /* - * Get the v4l2 setup done. - */ - mutex_lock(&cam->s_mutex); - cam->vdev = cafe_v4l_template; - cam->vdev.debug = 0; -/* cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/ - cam->vdev.v4l2_dev = &cam->v4l2_dev; - ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); - if (ret) - goto out_unlock; - video_set_drvdata(&cam->vdev, cam); - - /* - * If so requested, try to get our DMA buffers now. - */ - if (!alloc_bufs_at_read) { - if (cafe_alloc_dma_bufs(cam, 1)) - cam_warn(cam, "Unable to alloc DMA buffers at load" - " will try again later."); - } - - mutex_unlock(&cam->s_mutex); - return 0; - -out_unlock: - mutex_unlock(&cam->s_mutex); -out_smbus: - cafe_smbus_shutdown(cam); -out_freeirq: - cafe_ctlr_power_down(cam); - free_irq(pdev->irq, cam); -out_iounmap: - pci_iounmap(pdev, cam->regs); -out_free: - v4l2_device_unregister(&cam->v4l2_dev); -out_unreg: - kfree(cam); -out: - return ret; -} - - -/* - * Shut down an initialized device - */ -static void cafe_shutdown(struct cafe_camera *cam) -{ -/* FIXME: Make sure we take care of everything here */ - if (cam->n_sbufs > 0) - /* What if they are still mapped? Shouldn't be, but... */ - cafe_free_sio_buffers(cam); - cafe_ctlr_stop_dma(cam); - cafe_ctlr_power_down(cam); - cafe_smbus_shutdown(cam); - cafe_free_dma_bufs(cam); - free_irq(cam->pdev->irq, cam); - pci_iounmap(cam->pdev, cam->regs); - video_unregister_device(&cam->vdev); -} - - -static void cafe_pci_remove(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct cafe_camera *cam = to_cam(v4l2_dev); - - if (cam == NULL) { - printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev); - return; - } - mutex_lock(&cam->s_mutex); - if (cam->users > 0) - cam_warn(cam, "Removing a device with users!\n"); - cafe_shutdown(cam); - v4l2_device_unregister(&cam->v4l2_dev); - kfree(cam); -/* No unlock - it no longer exists */ -} - - -#ifdef CONFIG_PM -/* - * Basic power management. - */ -static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct cafe_camera *cam = to_cam(v4l2_dev); - int ret; - enum cafe_state cstate; - - ret = pci_save_state(pdev); - if (ret) - return ret; - cstate = cam->state; /* HACK - stop_dma sets to idle */ - cafe_ctlr_stop_dma(cam); - cafe_ctlr_power_down(cam); - pci_disable_device(pdev); - cam->state = cstate; - return 0; -} - - -static int cafe_pci_resume(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct cafe_camera *cam = to_cam(v4l2_dev); - int ret = 0; - - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - - if (ret) { - cam_warn(cam, "Unable to re-enable device on resume!\n"); - return ret; - } - cafe_ctlr_init(cam); - - mutex_lock(&cam->s_mutex); - if (cam->users > 0) { - cafe_ctlr_power_up(cam); - __cafe_cam_reset(cam); - } else { - cafe_ctlr_power_down(cam); - } - mutex_unlock(&cam->s_mutex); - - set_bit(CF_CONFIG_NEEDED, &cam->flags); - if (cam->state == S_SPECREAD) - cam->state = S_IDLE; /* Don't bother restarting */ - else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING) - ret = cafe_read_setup(cam, cam->state); - return ret; -} - -#endif /* CONFIG_PM */ - - -static struct pci_device_id cafe_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, - PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, cafe_ids); - -static struct pci_driver cafe_pci_driver = { - .name = "cafe1000-ccic", - .id_table = cafe_ids, - .probe = cafe_pci_probe, - .remove = cafe_pci_remove, -#ifdef CONFIG_PM - .suspend = cafe_pci_suspend, - .resume = cafe_pci_resume, -#endif -}; - - - - -static int __init cafe_init(void) -{ - int ret; - - printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n", - CAFE_VERSION); - ret = pci_register_driver(&cafe_pci_driver); - if (ret) { - printk(KERN_ERR "Unable to register cafe_ccic driver\n"); - goto out; - } - ret = 0; - - out: - return ret; -} - - -static void __exit cafe_exit(void) -{ - pci_unregister_driver(&cafe_pci_driver); -} - -module_init(cafe_init); -module_exit(cafe_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cafe_ccic-regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cafe_ccic-regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cafe_ccic-regs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cafe_ccic-regs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,166 +0,0 @@ -/* - * Register definitions for the m88alp01 camera interface. Offsets in bytes - * as given in the spec. - * - * Copyright 2006 One Laptop Per Child Association, Inc. - * - * Written by Jonathan Corbet, corbet@lwn.net. - * - * This file may be distributed under the terms of the GNU General - * Public License, version 2. - */ -#define REG_Y0BAR 0x00 -#define REG_Y1BAR 0x04 -#define REG_Y2BAR 0x08 -/* ... */ - -#define REG_IMGPITCH 0x24 /* Image pitch register */ -#define IMGP_YP_SHFT 2 /* Y pitch params */ -#define IMGP_YP_MASK 0x00003ffc /* Y pitch field */ -#define IMGP_UVP_SHFT 18 /* UV pitch (planar) */ -#define IMGP_UVP_MASK 0x3ffc0000 -#define REG_IRQSTATRAW 0x28 /* RAW IRQ Status */ -#define IRQ_EOF0 0x00000001 /* End of frame 0 */ -#define IRQ_EOF1 0x00000002 /* End of frame 1 */ -#define IRQ_EOF2 0x00000004 /* End of frame 2 */ -#define IRQ_SOF0 0x00000008 /* Start of frame 0 */ -#define IRQ_SOF1 0x00000010 /* Start of frame 1 */ -#define IRQ_SOF2 0x00000020 /* Start of frame 2 */ -#define IRQ_OVERFLOW 0x00000040 /* FIFO overflow */ -#define IRQ_TWSIW 0x00010000 /* TWSI (smbus) write */ -#define IRQ_TWSIR 0x00020000 /* TWSI read */ -#define IRQ_TWSIE 0x00040000 /* TWSI error */ -#define TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE) -#define FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2) -#define ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW) -#define REG_IRQMASK 0x2c /* IRQ mask - same bits as IRQSTAT */ -#define REG_IRQSTAT 0x30 /* IRQ status / clear */ - -#define REG_IMGSIZE 0x34 /* Image size */ -#define IMGSZ_V_MASK 0x1fff0000 -#define IMGSZ_V_SHIFT 16 -#define IMGSZ_H_MASK 0x00003fff -#define REG_IMGOFFSET 0x38 /* IMage offset */ - -#define REG_CTRL0 0x3c /* Control 0 */ -#define C0_ENABLE 0x00000001 /* Makes the whole thing go */ - -/* Mask for all the format bits */ -#define C0_DF_MASK 0x00fffffc /* Bits 2-23 */ - -/* RGB ordering */ -#define C0_RGB4_RGBX 0x00000000 -#define C0_RGB4_XRGB 0x00000004 -#define C0_RGB4_BGRX 0x00000008 -#define C0_RGB4_XBGR 0x0000000c -#define C0_RGB5_RGGB 0x00000000 -#define C0_RGB5_GRBG 0x00000004 -#define C0_RGB5_GBRG 0x00000008 -#define C0_RGB5_BGGR 0x0000000c - -/* Spec has two fields for DIN and DOUT, but they must match, so - combine them here. */ -#define C0_DF_YUV 0x00000000 /* Data is YUV */ -#define C0_DF_RGB 0x000000a0 /* ... RGB */ -#define C0_DF_BAYER 0x00000140 /* ... Bayer */ -/* 8-8-8 must be missing from the below - ask */ -#define C0_RGBF_565 0x00000000 -#define C0_RGBF_444 0x00000800 -#define C0_RGB_BGR 0x00001000 /* Blue comes first */ -#define C0_YUV_PLANAR 0x00000000 /* YUV 422 planar format */ -#define C0_YUV_PACKED 0x00008000 /* YUV 422 packed */ -#define C0_YUV_420PL 0x0000a000 /* YUV 420 planar */ -/* Think that 420 packed must be 111 - ask */ -#define C0_YUVE_YUYV 0x00000000 /* Y1CbY0Cr */ -#define C0_YUVE_YVYU 0x00010000 /* Y1CrY0Cb */ -#define C0_YUVE_VYUY 0x00020000 /* CrY1CbY0 */ -#define C0_YUVE_UYVY 0x00030000 /* CbY1CrY0 */ -#define C0_YUVE_XYUV 0x00000000 /* 420: .YUV */ -#define C0_YUVE_XYVU 0x00010000 /* 420: .YVU */ -#define C0_YUVE_XUVY 0x00020000 /* 420: .UVY */ -#define C0_YUVE_XVUY 0x00030000 /* 420: .VUY */ -/* Bayer bits 18,19 if needed */ -#define C0_HPOL_LOW 0x01000000 /* HSYNC polarity active low */ -#define C0_VPOL_LOW 0x02000000 /* VSYNC polarity active low */ -#define C0_VCLK_LOW 0x04000000 /* VCLK on falling edge */ -#define C0_DOWNSCALE 0x08000000 /* Enable downscaler */ -#define C0_SIFM_MASK 0xc0000000 /* SIF mode bits */ -#define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */ -#define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */ - - -#define REG_CTRL1 0x40 /* Control 1 */ -#define C1_444ALPHA 0x00f00000 /* Alpha field in RGB444 */ -#define C1_ALPHA_SHFT 20 -#define C1_DMAB32 0x00000000 /* 32-byte DMA burst */ -#define C1_DMAB16 0x02000000 /* 16-byte DMA burst */ -#define C1_DMAB64 0x04000000 /* 64-byte DMA burst */ -#define C1_DMAB_MASK 0x06000000 -#define C1_TWOBUFS 0x08000000 /* Use only two DMA buffers */ -#define C1_PWRDWN 0x10000000 /* Power down */ - -#define REG_CLKCTRL 0x88 /* Clock control */ -#define CLK_DIV_MASK 0x0000ffff /* Upper bits RW "reserved" */ - -#define REG_GPR 0xb4 /* General purpose register. This - controls inputs to the power and reset - pins on the OV7670 used with OLPC; - other deployments could differ. */ -#define GPR_C1EN 0x00000020 /* Pad 1 (power down) enable */ -#define GPR_C0EN 0x00000010 /* Pad 0 (reset) enable */ -#define GPR_C1 0x00000002 /* Control 1 value */ -/* - * Control 0 is wired to reset on OLPC machines. For ov7x sensors, - * it is active low, for 0v6x, instead, it's active high. What - * fun. - */ -#define GPR_C0 0x00000001 /* Control 0 value */ - -#define REG_TWSIC0 0xb8 /* TWSI (smbus) control 0 */ -#define TWSIC0_EN 0x00000001 /* TWSI enable */ -#define TWSIC0_MODE 0x00000002 /* 1 = 16-bit, 0 = 8-bit */ -#define TWSIC0_SID 0x000003fc /* Slave ID */ -#define TWSIC0_SID_SHIFT 2 -#define TWSIC0_CLKDIV 0x0007fc00 /* Clock divider */ -#define TWSIC0_MASKACK 0x00400000 /* Mask ack from sensor */ -#define TWSIC0_OVMAGIC 0x00800000 /* Make it work on OV sensors */ - -#define REG_TWSIC1 0xbc /* TWSI control 1 */ -#define TWSIC1_DATA 0x0000ffff /* Data to/from camchip */ -#define TWSIC1_ADDR 0x00ff0000 /* Address (register) */ -#define TWSIC1_ADDR_SHIFT 16 -#define TWSIC1_READ 0x01000000 /* Set for read op */ -#define TWSIC1_WSTAT 0x02000000 /* Write status */ -#define TWSIC1_RVALID 0x04000000 /* Read data valid */ -#define TWSIC1_ERROR 0x08000000 /* Something screwed up */ - - -#define REG_UBAR 0xc4 /* Upper base address register */ - -/* - * Here's the weird global control registers which are said to live - * way up here. - */ -#define REG_GL_CSR 0x3004 /* Control/status register */ -#define GCSR_SRS 0x00000001 /* SW Reset set */ -#define GCSR_SRC 0x00000002 /* SW Reset clear */ -#define GCSR_MRS 0x00000004 /* Master reset set */ -#define GCSR_MRC 0x00000008 /* HW Reset clear */ -#define GCSR_CCIC_EN 0x00004000 /* CCIC Clock enable */ -#define REG_GL_IMASK 0x300c /* Interrupt mask register */ -#define GIMSK_CCIC_EN 0x00000004 /* CCIC Interrupt enable */ - -#define REG_GL_FCR 0x3038 /* GPIO functional control register */ -#define GFCR_GPIO_ON 0x08 /* Camera GPIO enabled */ -#define REG_GL_GPIOR 0x315c /* GPIO register */ -#define GGPIO_OUT 0x80000 /* GPIO output */ -#define GGPIO_VAL 0x00008 /* Output pin value */ - -#define REG_LEN REG_GL_IMASK + 4 - - -/* - * Useful stuff that probably belongs somewhere global. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2493 +0,0 @@ -/**************************************************************************** - * - * Filename: cpia2_core.c - * - * Copyright 2001, STMicrolectronics, Inc. - * Contact: steve.miller@st.com - * - * Description: - * This is a USB driver for CPia2 based video cameras. - * The infrastructure of this driver is based on the cpia usb driver by - * Jochen Scharrlach and Johannes Erdfeldt. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Stripped of 2.4 stuff ready for main kernel submit by - * Alan Cox - * - ****************************************************************************/ - -#include "cpia2.h" - -#include -#include -#include -#include - -/* #define _CPIA2_DEBUG_ */ - -#ifdef _CPIA2_DEBUG_ - -static const char *block_name[] = { - "System", - "VC", - "VP", - "IDATA" -}; -#endif - -static unsigned int debugs_on; /* default 0 - DEBUG_REG */ - - -/****************************************************************************** - * - * Forward Declarations - * - *****************************************************************************/ -static int apply_vp_patch(struct camera_data *cam); -static int set_default_user_mode(struct camera_data *cam); -static int set_vw_size(struct camera_data *cam, int size); -static int configure_sensor(struct camera_data *cam, - int reqwidth, int reqheight); -static int config_sensor_410(struct camera_data *cam, - int reqwidth, int reqheight); -static int config_sensor_500(struct camera_data *cam, - int reqwidth, int reqheight); -static int set_all_properties(struct camera_data *cam); -static void get_color_params(struct camera_data *cam); -static void wake_system(struct camera_data *cam); -static void set_lowlight_boost(struct camera_data *cam); -static void reset_camera_struct(struct camera_data *cam); -static int cpia2_set_high_power(struct camera_data *cam); - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - return ret; -} - -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - /* Round it off to PAGE_SIZE */ - size = PAGE_ALIGN(size); - - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - - while ((long)size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - return mem; -} - -static void rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - size = PAGE_ALIGN(size); - - adr = (unsigned long) mem; - while ((long)size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - -/****************************************************************************** - * - * cpia2_do_command - * - * Send an arbitrary command to the camera. For commands that read from - * the camera, copy the buffers into the proper param structures. - *****************************************************************************/ -int cpia2_do_command(struct camera_data *cam, - u32 command, u8 direction, u8 param) -{ - int retval = 0; - struct cpia2_command cmd; - unsigned int device = cam->params.pnp_id.device_type; - - cmd.command = command; - cmd.reg_count = 2; /* default */ - cmd.direction = direction; - - /*** - * Set up the command. - ***/ - switch (command) { - case CPIA2_CMD_GET_VERSION: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.start = CPIA2_SYSTEM_DEVICE_HI; - break; - case CPIA2_CMD_GET_PNP_ID: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 8; - cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI; - break; - case CPIA2_CMD_GET_ASIC_TYPE: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.start = CPIA2_VC_ASIC_ID; - break; - case CPIA2_CMD_GET_SENSOR: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.start = CPIA2_VP_SENSOR_FLAGS; - break; - case CPIA2_CMD_GET_VP_DEVICE: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.start = CPIA2_VP_DEVICEH; - break; - case CPIA2_CMD_SET_VP_BRIGHTNESS: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_VP_BRIGHTNESS: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP4_EXPOSURE_TARGET; - else - cmd.start = CPIA2_VP5_EXPOSURE_TARGET; - break; - case CPIA2_CMD_SET_CONTRAST: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_CONTRAST: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_YRANGE; - break; - case CPIA2_CMD_SET_VP_SATURATION: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_VP_SATURATION: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP_SATURATION; - else - cmd.start = CPIA2_VP5_MCUVSATURATION; - break; - case CPIA2_CMD_SET_VP_GPIO_DATA: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_VP_GPIO_DATA: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_GPIO_DATA; - break; - case CPIA2_CMD_SET_VP_GPIO_DIRECTION: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_VP_GPIO_DIRECTION: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_GPIO_DIRECTION; - break; - case CPIA2_CMD_SET_VC_MP_GPIO_DATA: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_VC_MP_GPIO_DATA: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_MP_DATA; - break; - case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_MP_DIR; - break; - case CPIA2_CMD_ENABLE_PACKET_CTRL: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL; - cmd.reg_count = 1; - cmd.buffer.block_data[0] = param; - break; - case CPIA2_CMD_SET_FLICKER_MODES: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_FLICKER_MODES: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_FLICKER_MODES; - break; - case CPIA2_CMD_RESET_FIFO: /* clear fifo and enable stream block */ - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.reg_count = 2; - cmd.start = 0; - cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL; - cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC | - CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT; - cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL; - cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC | - CPIA2_VC_ST_CTRL_DST_USB | - CPIA2_VC_ST_CTRL_EOF_DETECT | - CPIA2_VC_ST_CTRL_FIFO_ENABLE; - break; - case CPIA2_CMD_SET_HI_POWER: - cmd.req_mode = - CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM; - cmd.reg_count = 2; - cmd.buffer.registers[0].index = - CPIA2_SYSTEM_SYSTEM_CONTROL; - cmd.buffer.registers[1].index = - CPIA2_SYSTEM_SYSTEM_CONTROL; - cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR; - cmd.buffer.registers[1].value = - CPIA2_SYSTEM_CONTROL_HIGH_POWER; - break; - case CPIA2_CMD_SET_LOW_POWER: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 1; - cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; - cmd.buffer.block_data[0] = 0; - break; - case CPIA2_CMD_CLEAR_V2W_ERR: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 1; - cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; - cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR; - break; - case CPIA2_CMD_SET_USER_MODE: /* Then fall through */ - cmd.buffer.block_data[0] = param; - case CPIA2_CMD_GET_USER_MODE: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP4_USER_MODE; - else - cmd.start = CPIA2_VP5_USER_MODE; - break; - case CPIA2_CMD_FRAMERATE_REQ: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP4_FRAMERATE_REQUEST; - else - cmd.start = CPIA2_VP5_FRAMERATE_REQUEST; - cmd.buffer.block_data[0] = param; - break; - case CPIA2_CMD_SET_WAKEUP: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_WAKEUP: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_WAKEUP; - break; - case CPIA2_CMD_SET_PW_CONTROL: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_PW_CONTROL: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_PW_CTRL; - break; - case CPIA2_CMD_GET_VP_SYSTEM_STATE: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_SYSTEMSTATE; - break; - case CPIA2_CMD_SET_SYSTEM_CTRL: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_SYSTEM_CTRL: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 1; - cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; - break; - case CPIA2_CMD_SET_VP_SYSTEM_CTRL: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_VP_SYSTEM_CTRL: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_SYSTEMCTRL; - break; - case CPIA2_CMD_SET_VP_EXP_MODES: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_VP_EXP_MODES: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_EXPOSURE_MODES; - break; - case CPIA2_CMD_SET_DEVICE_CONFIG: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_DEVICE_CONFIG: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_DEVICE_CONFIG; - break; - case CPIA2_CMD_SET_SERIAL_ADDR: - cmd.buffer.block_data[0] = param; - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 1; - cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR; - break; - case CPIA2_CMD_SET_SENSOR_CR1: - cmd.buffer.block_data[0] = param; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_SENSOR_CR1; - break; - case CPIA2_CMD_SET_VC_CONTROL: - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_VC_CONTROL: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_VC_CTRL; - break; - case CPIA2_CMD_SET_TARGET_KB: - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB; - cmd.buffer.registers[0].value = param; - break; - case CPIA2_CMD_SET_DEF_JPEG_OPT: - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.reg_count = 4; - cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT; - cmd.buffer.registers[0].value = - CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE; - cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE; - cmd.buffer.registers[1].value = 20; - cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD; - cmd.buffer.registers[2].value = 2; - cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT; - cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT; - break; - case CPIA2_CMD_REHASH_VP4: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_REHASH_VALUES; - cmd.buffer.block_data[0] = param; - break; - case CPIA2_CMD_SET_USER_EFFECTS: /* Note: Be careful with this as - this register can also affect - flicker modes */ - cmd.buffer.block_data[0] = param; /* Then fall through */ - case CPIA2_CMD_GET_USER_EFFECTS: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP4_USER_EFFECTS; - else - cmd.start = CPIA2_VP5_USER_EFFECTS; - break; - default: - LOG("DoCommand received invalid command\n"); - return -EINVAL; - } - - retval = cpia2_send_command(cam, &cmd); - if (retval) { - return retval; - } - - /*** - * Now copy any results from a read into the appropriate param struct. - ***/ - switch (command) { - case CPIA2_CMD_GET_VERSION: - cam->params.version.firmware_revision_hi = - cmd.buffer.block_data[0]; - cam->params.version.firmware_revision_lo = - cmd.buffer.block_data[1]; - break; - case CPIA2_CMD_GET_PNP_ID: - cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) | - cmd.buffer.block_data[1]; - cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) | - cmd.buffer.block_data[3]; - cam->params.pnp_id.device_revision = - (cmd.buffer.block_data[4] << 8) | - cmd.buffer.block_data[5]; - if (cam->params.pnp_id.vendor == 0x553) { - if (cam->params.pnp_id.product == 0x100) { - cam->params.pnp_id.device_type = DEVICE_STV_672; - } else if (cam->params.pnp_id.product == 0x140 || - cam->params.pnp_id.product == 0x151) { - cam->params.pnp_id.device_type = DEVICE_STV_676; - } - } - break; - case CPIA2_CMD_GET_ASIC_TYPE: - cam->params.version.asic_id = cmd.buffer.block_data[0]; - cam->params.version.asic_rev = cmd.buffer.block_data[1]; - break; - case CPIA2_CMD_GET_SENSOR: - cam->params.version.sensor_flags = cmd.buffer.block_data[0]; - cam->params.version.sensor_rev = cmd.buffer.block_data[1]; - break; - case CPIA2_CMD_GET_VP_DEVICE: - cam->params.version.vp_device_hi = cmd.buffer.block_data[0]; - cam->params.version.vp_device_lo = cmd.buffer.block_data[1]; - break; - case CPIA2_CMD_GET_VP_BRIGHTNESS: - cam->params.color_params.brightness = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_CONTRAST: - cam->params.color_params.contrast = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_SATURATION: - cam->params.color_params.saturation = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_GPIO_DATA: - cam->params.vp_params.gpio_data = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_GPIO_DIRECTION: - cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION: - cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VC_MP_GPIO_DATA: - cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_FLICKER_MODES: - cam->params.flicker_control.cam_register = - cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_WAKEUP: - cam->params.vc_params.wakeup = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_PW_CONTROL: - cam->params.vc_params.pw_control = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_SYSTEM_CTRL: - cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_SYSTEM_STATE: - cam->params.vp_params.system_state = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_SYSTEM_CTRL: - cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_EXP_MODES: - cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_DEVICE_CONFIG: - cam->params.vp_params.device_config = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VC_CONTROL: - cam->params.vc_params.vc_control = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_USER_MODE: - cam->params.vp_params.video_mode = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_USER_EFFECTS: - cam->params.vp_params.user_effects = cmd.buffer.block_data[0]; - break; - default: - break; - } - return retval; -} - -/****************************************************************************** - * - * cpia2_send_command - * - *****************************************************************************/ - -#define DIR(cmd) ((cmd->direction == TRANSFER_WRITE) ? "Write" : "Read") -#define BINDEX(cmd) (cmd->req_mode & 0x03) - -int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd) -{ - u8 count; - u8 start; - u8 *buffer; - int retval; - - switch (cmd->req_mode & 0x0c) { - case CAMERAACCESS_TYPE_RANDOM: - count = cmd->reg_count * sizeof(struct cpia2_register); - start = 0; - buffer = (u8 *) & cmd->buffer; - if (debugs_on & DEBUG_REG) - DBG("%s Random: Register block %s\n", DIR(cmd), - block_name[BINDEX(cmd)]); - break; - case CAMERAACCESS_TYPE_BLOCK: - count = cmd->reg_count; - start = cmd->start; - buffer = cmd->buffer.block_data; - if (debugs_on & DEBUG_REG) - DBG("%s Block: Register block %s\n", DIR(cmd), - block_name[BINDEX(cmd)]); - break; - case CAMERAACCESS_TYPE_MASK: - count = cmd->reg_count * sizeof(struct cpia2_reg_mask); - start = 0; - buffer = (u8 *) & cmd->buffer; - if (debugs_on & DEBUG_REG) - DBG("%s Mask: Register block %s\n", DIR(cmd), - block_name[BINDEX(cmd)]); - break; - case CAMERAACCESS_TYPE_REPEAT: /* For patch blocks only */ - count = cmd->reg_count; - start = cmd->start; - buffer = cmd->buffer.block_data; - if (debugs_on & DEBUG_REG) - DBG("%s Repeat: Register block %s\n", DIR(cmd), - block_name[BINDEX(cmd)]); - break; - default: - LOG("%s: invalid request mode\n",__func__); - return -EINVAL; - } - - retval = cpia2_usb_transfer_cmd(cam, - buffer, - cmd->req_mode, - start, count, cmd->direction); -#ifdef _CPIA2_DEBUG_ - if (debugs_on & DEBUG_REG) { - int i; - for (i = 0; i < cmd->reg_count; i++) { - if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK) - KINFO("%s Block: [0x%02X] = 0x%02X\n", - DIR(cmd), start + i, buffer[i]); - if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM) - KINFO("%s Random: [0x%02X] = 0x%02X\n", - DIR(cmd), cmd->buffer.registers[i].index, - cmd->buffer.registers[i].value); - } - } -#endif - - return retval; -}; - -/************* - * Functions to implement camera functionality - *************/ -/****************************************************************************** - * - * cpia2_get_version_info - * - *****************************************************************************/ -static void cpia2_get_version_info(struct camera_data *cam) -{ - cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0); -} - -/****************************************************************************** - * - * cpia2_reset_camera - * - * Called at least during the open process, sets up initial params. - *****************************************************************************/ -int cpia2_reset_camera(struct camera_data *cam) -{ - u8 tmp_reg; - int retval = 0; - int i; - struct cpia2_command cmd; - - /*** - * VC setup - ***/ - retval = configure_sensor(cam, - cam->params.roi.width, - cam->params.roi.height); - if (retval < 0) { - ERR("Couldn't configure sensor, error=%d\n", retval); - return retval; - } - - /* Clear FIFO and route/enable stream block */ - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.direction = TRANSFER_WRITE; - cmd.reg_count = 2; - cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL; - cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC | - CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT; - cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL; - cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC | - CPIA2_VC_ST_CTRL_DST_USB | - CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE; - - cpia2_send_command(cam, &cmd); - - cpia2_set_high_power(cam); - - if (cam->params.pnp_id.device_type == DEVICE_STV_672) { - /* Enable button notification */ - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM; - cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL; - cmd.buffer.registers[0].value = - CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX; - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - } - - schedule_timeout_interruptible(msecs_to_jiffies(100)); - - if (cam->params.pnp_id.device_type == DEVICE_STV_672) - retval = apply_vp_patch(cam); - - /* wait for vp to go to sleep */ - schedule_timeout_interruptible(msecs_to_jiffies(100)); - - /*** - * If this is a 676, apply VP5 fixes before we start streaming - ***/ - if (cam->params.pnp_id.device_type == DEVICE_STV_676) { - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; - - /* The following writes improve the picture */ - cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL; - cmd.buffer.registers[0].value = 0; /* reduce from the default - * rec 601 pedestal of 16 */ - cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE; - cmd.buffer.registers[1].value = 0x92; /* increase from 100% to - * (256/256 - 31) to fill - * available range */ - cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING; - cmd.buffer.registers[2].value = 0xFF; /* Increase from the - * default rec 601 ceiling - * of 240 */ - cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION; - cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec - * 601 100% level (128) - * to 145-192 */ - cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP; - cmd.buffer.registers[4].value = 0x80; /* Inhibit the - * anti-flicker */ - - /* The following 4 writes are a fix to allow QVGA to work at 30 fps */ - cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H; - cmd.buffer.registers[5].value = 0x01; - cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L; - cmd.buffer.registers[6].value = 0xE3; - cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA; - cmd.buffer.registers[7].value = 0x02; - cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA; - cmd.buffer.registers[8].value = 0xFC; - - cmd.direction = TRANSFER_WRITE; - cmd.reg_count = 9; - - cpia2_send_command(cam, &cmd); - } - - /* Activate all settings and start the data stream */ - /* Set user mode */ - set_default_user_mode(cam); - - /* Give VP time to wake up */ - schedule_timeout_interruptible(msecs_to_jiffies(100)); - - set_all_properties(cam); - - cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0); - DBG("After SetAllProperties(cam), user mode is 0x%0X\n", - cam->params.vp_params.video_mode); - - /*** - * Set audio regulator off. This and the code to set the compresison - * state are too complex to form a CPIA2_CMD_, and seem to be somewhat - * intertwined. This stuff came straight from the windows driver. - ***/ - /* Turn AutoExposure off in VP and enable the serial bridge to the sensor */ - cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0); - tmp_reg = cam->params.vp_params.system_ctrl; - cmd.buffer.registers[0].value = tmp_reg & - (tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF)); - - cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0); - cmd.buffer.registers[1].value = cam->params.vp_params.device_config | - CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE; - cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL; - cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG; - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; - cmd.reg_count = 2; - cmd.direction = TRANSFER_WRITE; - cmd.start = 0; - cpia2_send_command(cam, &cmd); - - /* Set the correct I2C address in the CPiA-2 system register */ - cpia2_do_command(cam, - CPIA2_CMD_SET_SERIAL_ADDR, - TRANSFER_WRITE, - CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR); - - /* Now have sensor access - set bit to turn the audio regulator off */ - cpia2_do_command(cam, - CPIA2_CMD_SET_SENSOR_CR1, - TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR); - - /* Set the correct I2C address in the CPiA-2 system register */ - if (cam->params.pnp_id.device_type == DEVICE_STV_672) - cpia2_do_command(cam, - CPIA2_CMD_SET_SERIAL_ADDR, - TRANSFER_WRITE, - CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88 - else - cpia2_do_command(cam, - CPIA2_CMD_SET_SERIAL_ADDR, - TRANSFER_WRITE, - CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a - - /* increase signal drive strength */ - if (cam->params.pnp_id.device_type == DEVICE_STV_676) - cpia2_do_command(cam, - CPIA2_CMD_SET_VP_EXP_MODES, - TRANSFER_WRITE, - CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP); - - /* Start autoexposure */ - cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0); - cmd.buffer.registers[0].value = cam->params.vp_params.device_config & - (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF); - - cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0); - cmd.buffer.registers[1].value = - cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL; - - cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG; - cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL; - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; - cmd.reg_count = 2; - cmd.direction = TRANSFER_WRITE; - - cpia2_send_command(cam, &cmd); - - /* Set compression state */ - cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0); - if (cam->params.compression.inhibit_htables) { - tmp_reg = cam->params.vc_params.vc_control | - CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES; - } else { - tmp_reg = cam->params.vc_params.vc_control & - ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES; - } - cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg); - - /* Set target size (kb) on vc */ - cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB, - TRANSFER_WRITE, cam->params.vc_params.target_kb); - - /* Wiggle VC Reset */ - /*** - * First read and wait a bit. - ***/ - for (i = 0; i < 50; i++) { - cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL, - TRANSFER_READ, 0); - } - - tmp_reg = cam->params.vc_params.pw_control; - tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N; - - cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg); - - tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N; - cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg); - - cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0); - - cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0); - DBG("After VC RESET, user mode is 0x%0X\n", - cam->params.vp_params.video_mode); - - return retval; -} - -/****************************************************************************** - * - * cpia2_set_high_power - * - *****************************************************************************/ -static int cpia2_set_high_power(struct camera_data *cam) -{ - int i; - for (i = 0; i <= 50; i++) { - /* Read system status */ - cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0); - - /* If there is an error, clear it */ - if(cam->params.camera_state.system_ctrl & - CPIA2_SYSTEM_CONTROL_V2W_ERR) - cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR, - TRANSFER_WRITE, 0); - - /* Try to set high power mode */ - cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, - TRANSFER_WRITE, 1); - - /* Try to read something in VP to check if everything is awake */ - cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE, - TRANSFER_READ, 0); - if (cam->params.vp_params.system_state & - CPIA2_VP_SYSTEMSTATE_HK_ALIVE) { - break; - } else if (i == 50) { - cam->params.camera_state.power_mode = LO_POWER_MODE; - ERR("Camera did not wake up\n"); - return -EIO; - } - } - - DBG("System now in high power state\n"); - cam->params.camera_state.power_mode = HI_POWER_MODE; - return 0; -} - -/****************************************************************************** - * - * cpia2_set_low_power - * - *****************************************************************************/ -int cpia2_set_low_power(struct camera_data *cam) -{ - cam->params.camera_state.power_mode = LO_POWER_MODE; - cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0); - return 0; -} - -/****************************************************************************** - * - * apply_vp_patch - * - *****************************************************************************/ -static int cpia2_send_onebyte_command(struct camera_data *cam, - struct cpia2_command *cmd, - u8 start, u8 datum) -{ - cmd->buffer.block_data[0] = datum; - cmd->start = start; - cmd->reg_count = 1; - return cpia2_send_command(cam, cmd); -} - -static int apply_vp_patch(struct camera_data *cam) -{ - const struct firmware *fw; - const char fw_name[] = "cpia2/stv0672_vp4.bin"; - int i, ret; - struct cpia2_command cmd; - - ret = request_firmware(&fw, fw_name, &cam->dev->dev); - if (ret) { - printk(KERN_ERR "cpia2: failed to load VP patch \"%s\"\n", - fw_name); - return ret; - } - - cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP; - cmd.direction = TRANSFER_WRITE; - - /* First send the start address... */ - cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */ - cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */ - - /* ... followed by the data payload */ - for (i = 2; i < fw->size; i += 64) { - cmd.start = 0x0C; /* Data */ - cmd.reg_count = min_t(int, 64, fw->size - i); - memcpy(cmd.buffer.block_data, &fw->data[i], cmd.reg_count); - cpia2_send_command(cam, &cmd); - } - - /* Next send the start address... */ - cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */ - cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */ - - /* ... followed by the 'goto' command */ - cpia2_send_onebyte_command(cam, &cmd, 0x0D, 1); - - release_firmware(fw); - return 0; -} - -/****************************************************************************** - * - * set_default_user_mode - * - *****************************************************************************/ -static int set_default_user_mode(struct camera_data *cam) -{ - unsigned char user_mode; - unsigned char frame_rate; - int width = cam->params.roi.width; - int height = cam->params.roi.height; - - switch (cam->params.version.sensor_flags) { - case CPIA2_VP_SENSOR_FLAGS_404: - case CPIA2_VP_SENSOR_FLAGS_407: - case CPIA2_VP_SENSOR_FLAGS_409: - case CPIA2_VP_SENSOR_FLAGS_410: - if ((width > STV_IMAGE_QCIF_COLS) - || (height > STV_IMAGE_QCIF_ROWS)) { - user_mode = CPIA2_VP_USER_MODE_CIF; - } else { - user_mode = CPIA2_VP_USER_MODE_QCIFDS; - } - frame_rate = CPIA2_VP_FRAMERATE_30; - break; - case CPIA2_VP_SENSOR_FLAGS_500: - if ((width > STV_IMAGE_CIF_COLS) - || (height > STV_IMAGE_CIF_ROWS)) { - user_mode = CPIA2_VP_USER_MODE_VGA; - } else { - user_mode = CPIA2_VP_USER_MODE_QVGADS; - } - if (cam->params.pnp_id.device_type == DEVICE_STV_672) - frame_rate = CPIA2_VP_FRAMERATE_15; - else - frame_rate = CPIA2_VP_FRAMERATE_30; - break; - default: - LOG("%s: Invalid sensor flag value 0x%0X\n",__func__, - cam->params.version.sensor_flags); - return -EINVAL; - } - - DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n", - cam->params.version.sensor_flags, user_mode, frame_rate); - cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE, - user_mode); - if(cam->params.vp_params.frame_rate > 0 && - frame_rate > cam->params.vp_params.frame_rate) - frame_rate = cam->params.vp_params.frame_rate; - - cpia2_set_fps(cam, frame_rate); - -// if (cam->params.pnp_id.device_type == DEVICE_STV_676) -// cpia2_do_command(cam, -// CPIA2_CMD_SET_VP_SYSTEM_CTRL, -// TRANSFER_WRITE, -// CPIA2_VP_SYSTEMCTRL_HK_CONTROL | -// CPIA2_VP_SYSTEMCTRL_POWER_CONTROL); - - return 0; -} - -/****************************************************************************** - * - * cpia2_match_video_size - * - * return the best match, where 'best' is as always - * the largest that is not bigger than what is requested. - *****************************************************************************/ -int cpia2_match_video_size(int width, int height) -{ - if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS) - return VIDEOSIZE_VGA; - - if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS) - return VIDEOSIZE_CIF; - - if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS) - return VIDEOSIZE_QVGA; - - if (width >= 288 && height >= 216) - return VIDEOSIZE_288_216; - - if (width >= 256 && height >= 192) - return VIDEOSIZE_256_192; - - if (width >= 224 && height >= 168) - return VIDEOSIZE_224_168; - - if (width >= 192 && height >= 144) - return VIDEOSIZE_192_144; - - if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS) - return VIDEOSIZE_QCIF; - - return -1; -} - -/****************************************************************************** - * - * SetVideoSize - * - *****************************************************************************/ -static int set_vw_size(struct camera_data *cam, int size) -{ - int retval = 0; - - cam->params.vp_params.video_size = size; - - switch (size) { - case VIDEOSIZE_VGA: - DBG("Setting size to VGA\n"); - cam->params.roi.width = STV_IMAGE_VGA_COLS; - cam->params.roi.height = STV_IMAGE_VGA_ROWS; - cam->width = STV_IMAGE_VGA_COLS; - cam->height = STV_IMAGE_VGA_ROWS; - break; - case VIDEOSIZE_CIF: - DBG("Setting size to CIF\n"); - cam->params.roi.width = STV_IMAGE_CIF_COLS; - cam->params.roi.height = STV_IMAGE_CIF_ROWS; - cam->width = STV_IMAGE_CIF_COLS; - cam->height = STV_IMAGE_CIF_ROWS; - break; - case VIDEOSIZE_QVGA: - DBG("Setting size to QVGA\n"); - cam->params.roi.width = STV_IMAGE_QVGA_COLS; - cam->params.roi.height = STV_IMAGE_QVGA_ROWS; - cam->width = STV_IMAGE_QVGA_COLS; - cam->height = STV_IMAGE_QVGA_ROWS; - break; - case VIDEOSIZE_288_216: - cam->params.roi.width = 288; - cam->params.roi.height = 216; - cam->width = 288; - cam->height = 216; - break; - case VIDEOSIZE_256_192: - cam->width = 256; - cam->height = 192; - cam->params.roi.width = 256; - cam->params.roi.height = 192; - break; - case VIDEOSIZE_224_168: - cam->width = 224; - cam->height = 168; - cam->params.roi.width = 224; - cam->params.roi.height = 168; - break; - case VIDEOSIZE_192_144: - cam->width = 192; - cam->height = 144; - cam->params.roi.width = 192; - cam->params.roi.height = 144; - break; - case VIDEOSIZE_QCIF: - DBG("Setting size to QCIF\n"); - cam->params.roi.width = STV_IMAGE_QCIF_COLS; - cam->params.roi.height = STV_IMAGE_QCIF_ROWS; - cam->width = STV_IMAGE_QCIF_COLS; - cam->height = STV_IMAGE_QCIF_ROWS; - break; - default: - retval = -EINVAL; - } - return retval; -} - -/****************************************************************************** - * - * configure_sensor - * - *****************************************************************************/ -static int configure_sensor(struct camera_data *cam, - int req_width, int req_height) -{ - int retval; - - switch (cam->params.version.sensor_flags) { - case CPIA2_VP_SENSOR_FLAGS_404: - case CPIA2_VP_SENSOR_FLAGS_407: - case CPIA2_VP_SENSOR_FLAGS_409: - case CPIA2_VP_SENSOR_FLAGS_410: - retval = config_sensor_410(cam, req_width, req_height); - break; - case CPIA2_VP_SENSOR_FLAGS_500: - retval = config_sensor_500(cam, req_width, req_height); - break; - default: - return -EINVAL; - } - - return retval; -} - -/****************************************************************************** - * - * config_sensor_410 - * - *****************************************************************************/ -static int config_sensor_410(struct camera_data *cam, - int req_width, int req_height) -{ - struct cpia2_command cmd; - int i = 0; - int image_size; - int image_type; - int width = req_width; - int height = req_height; - - /*** - * Make sure size doesn't exceed CIF. - ***/ - if (width > STV_IMAGE_CIF_COLS) - width = STV_IMAGE_CIF_COLS; - if (height > STV_IMAGE_CIF_ROWS) - height = STV_IMAGE_CIF_ROWS; - - image_size = cpia2_match_video_size(width, height); - - DBG("Config 410: width = %d, height = %d\n", width, height); - DBG("Image size returned is %d\n", image_size); - if (image_size >= 0) { - set_vw_size(cam, image_size); - width = cam->params.roi.width; - height = cam->params.roi.height; - - DBG("After set_vw_size(), width = %d, height = %d\n", - width, height); - if (width <= 176 && height <= 144) { - DBG("image type = VIDEOSIZE_QCIF\n"); - image_type = VIDEOSIZE_QCIF; - } - else if (width <= 320 && height <= 240) { - DBG("image type = VIDEOSIZE_QVGA\n"); - image_type = VIDEOSIZE_QVGA; - } - else { - DBG("image type = VIDEOSIZE_CIF\n"); - image_type = VIDEOSIZE_CIF; - } - } else { - ERR("ConfigSensor410 failed\n"); - return -EINVAL; - } - - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.direction = TRANSFER_WRITE; - - /* VC Format */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT; - if (image_type == VIDEOSIZE_CIF) { - cmd.buffer.registers[i++].value = - (u8) (CPIA2_VC_VC_FORMAT_UFIRST | - CPIA2_VC_VC_FORMAT_SHORTLINE); - } else { - cmd.buffer.registers[i++].value = - (u8) CPIA2_VC_VC_FORMAT_UFIRST; - } - - /* VC Clocks */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS; - if (image_type == VIDEOSIZE_QCIF) { - if (cam->params.pnp_id.device_type == DEVICE_STV_672) { - cmd.buffer.registers[i++].value= - (u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 | - CPIA2_VC_VC_672_CLOCKS_SCALING | - CPIA2_VC_VC_CLOCKS_LOGDIV2); - DBG("VC_Clocks (0xc4) should be B\n"); - } - else { - cmd.buffer.registers[i++].value= - (u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 | - CPIA2_VC_VC_CLOCKS_LOGDIV2); - } - } else { - if (cam->params.pnp_id.device_type == DEVICE_STV_672) { - cmd.buffer.registers[i++].value = - (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 | - CPIA2_VC_VC_CLOCKS_LOGDIV0); - } - else { - cmd.buffer.registers[i++].value = - (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 | - CPIA2_VC_VC_676_CLOCKS_SCALING | - CPIA2_VC_VC_CLOCKS_LOGDIV0); - } - } - DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value); - - /* Input reqWidth from VC */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = - (u8) (STV_IMAGE_QCIF_COLS / 4); - else - cmd.buffer.registers[i++].value = - (u8) (STV_IMAGE_CIF_COLS / 4); - - /* Timings */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 0; - else - cmd.buffer.registers[i++].value = (u8) 1; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 208; - else - cmd.buffer.registers[i++].value = (u8) 160; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 0; - else - cmd.buffer.registers[i++].value = (u8) 1; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 160; - else - cmd.buffer.registers[i++].value = (u8) 64; - - /* Output Image Size */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE; - cmd.buffer.registers[i++].value = cam->params.roi.width / 4; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE; - cmd.buffer.registers[i++].value = cam->params.roi.height / 4; - - /* Cropping */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2); - else - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2); - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2); - else - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2); - - /* Scaling registers (defaults) */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN; - cmd.buffer.registers[i++].value = (u8) 31; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN; - cmd.buffer.registers[i++].value = (u8) 31; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT; - cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */ - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT; - cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */ - - cmd.reg_count = i; - - cpia2_send_command(cam, &cmd); - - return i; -} - - -/****************************************************************************** - * - * config_sensor_500(cam) - * - *****************************************************************************/ -static int config_sensor_500(struct camera_data *cam, - int req_width, int req_height) -{ - struct cpia2_command cmd; - int i = 0; - int image_size = VIDEOSIZE_CIF; - int image_type = VIDEOSIZE_VGA; - int width = req_width; - int height = req_height; - unsigned int device = cam->params.pnp_id.device_type; - - image_size = cpia2_match_video_size(width, height); - - if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS) - image_type = VIDEOSIZE_VGA; - else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS) - image_type = VIDEOSIZE_CIF; - else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS) - image_type = VIDEOSIZE_QVGA; - else - image_type = VIDEOSIZE_QCIF; - - if (image_size >= 0) { - set_vw_size(cam, image_size); - width = cam->params.roi.width; - height = cam->params.roi.height; - } else { - ERR("ConfigSensor500 failed\n"); - return -EINVAL; - } - - DBG("image_size = %d, width = %d, height = %d, type = %d\n", - image_size, width, height, image_type); - - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.direction = TRANSFER_WRITE; - i = 0; - - /* VC Format */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT; - cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING; - i++; - - /* VC Clocks */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS; - if (device == DEVICE_STV_672) { - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i].value = - (u8)CPIA2_VC_VC_CLOCKS_LOGDIV1; - else - cmd.buffer.registers[i].value = - (u8)(CPIA2_VC_VC_672_CLOCKS_SCALING | - CPIA2_VC_VC_CLOCKS_LOGDIV3); - } else { - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i].value = - (u8)CPIA2_VC_VC_CLOCKS_LOGDIV0; - else - cmd.buffer.registers[i].value = - (u8)(CPIA2_VC_VC_676_CLOCKS_SCALING | - CPIA2_VC_VC_CLOCKS_LOGDIV2); - } - i++; - - DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value); - - /* Input width from VP */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i].value = - (u8) (STV_IMAGE_VGA_COLS / 4); - else - cmd.buffer.registers[i].value = - (u8) (STV_IMAGE_QVGA_COLS / 4); - i++; - DBG("Input width = %d\n", cmd.buffer.registers[i-1].value); - - /* Timings */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = (u8) 2; - else - cmd.buffer.registers[i++].value = (u8) 1; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = (u8) 250; - else if (image_type == VIDEOSIZE_QVGA) - cmd.buffer.registers[i++].value = (u8) 125; - else - cmd.buffer.registers[i++].value = (u8) 160; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = (u8) 2; - else - cmd.buffer.registers[i++].value = (u8) 1; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = (u8) 12; - else if (image_type == VIDEOSIZE_QVGA) - cmd.buffer.registers[i++].value = (u8) 64; - else - cmd.buffer.registers[i++].value = (u8) 6; - - /* Output Image Size */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS / 4; - else - cmd.buffer.registers[i++].value = width / 4; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS / 4; - else - cmd.buffer.registers[i++].value = height / 4; - - /* Cropping */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2); - else if (image_type == VIDEOSIZE_QVGA) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2); - else if (image_type == VIDEOSIZE_CIF) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2); - else /*if (image_type == VIDEOSIZE_QCIF)*/ - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2); - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2); - else if (image_type == VIDEOSIZE_QVGA) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2); - else if (image_type == VIDEOSIZE_CIF) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2); - else /*if (image_type == VIDEOSIZE_QCIF)*/ - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2); - - /* Scaling registers (defaults) */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 36; - else - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 32; - else - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 26; - else - cmd.buffer.registers[i++].value = (u8) 31; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 21; - else - cmd.buffer.registers[i++].value = (u8) 31; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 0x2B; /* 2/11 */ - else - cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */ - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 0x13; /* 1/3 */ - else - cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */ - - cmd.reg_count = i; - - cpia2_send_command(cam, &cmd); - - return i; -} - - -/****************************************************************************** - * - * setallproperties - * - * This sets all user changeable properties to the values in cam->params. - *****************************************************************************/ -static int set_all_properties(struct camera_data *cam) -{ - /** - * Don't set target_kb here, it will be set later. - * framerate and user_mode were already set (set_default_user_mode). - **/ - - cpia2_set_color_params(cam); - - cpia2_usb_change_streaming_alternate(cam, - cam->params.camera_state.stream_mode); - - cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, - cam->params.vp_params.user_effects); - - cpia2_set_flicker_mode(cam, - cam->params.flicker_control.flicker_mode_req); - - cpia2_do_command(cam, - CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, - TRANSFER_WRITE, cam->params.vp_params.gpio_direction); - cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE, - cam->params.vp_params.gpio_data); - - wake_system(cam); - - set_lowlight_boost(cam); - - return 0; -} - -/****************************************************************************** - * - * cpia2_save_camera_state - * - *****************************************************************************/ -void cpia2_save_camera_state(struct camera_data *cam) -{ - get_color_params(cam); - cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ, - 0); - cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0); - /* Don't get framerate or target_kb. Trust the values we already have */ -} - -/****************************************************************************** - * - * get_color_params - * - *****************************************************************************/ -static void get_color_params(struct camera_data *cam) -{ - cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, TRANSFER_READ, 0); -} - -/****************************************************************************** - * - * cpia2_set_color_params - * - *****************************************************************************/ -void cpia2_set_color_params(struct camera_data *cam) -{ - DBG("Setting color params\n"); - cpia2_set_brightness(cam, cam->params.color_params.brightness); - cpia2_set_contrast(cam, cam->params.color_params.contrast); - cpia2_set_saturation(cam, cam->params.color_params.saturation); -} - -/****************************************************************************** - * - * cpia2_set_flicker_mode - * - *****************************************************************************/ -int cpia2_set_flicker_mode(struct camera_data *cam, int mode) -{ - unsigned char cam_reg; - int err = 0; - - if(cam->params.pnp_id.device_type != DEVICE_STV_672) - return -EINVAL; - - /* Set the appropriate bits in FLICKER_MODES, preserving the rest */ - if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, - TRANSFER_READ, 0))) - return err; - cam_reg = cam->params.flicker_control.cam_register; - - switch(mode) { - case NEVER_FLICKER: - cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; - cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ; - break; - case FLICKER_60: - cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; - cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ; - break; - case FLICKER_50: - cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; - cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ; - break; - default: - return -EINVAL; - } - - if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES, - TRANSFER_WRITE, cam_reg))) - return err; - - /* Set the appropriate bits in EXP_MODES, preserving the rest */ - if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES, - TRANSFER_READ, 0))) - return err; - cam_reg = cam->params.vp_params.exposure_modes; - - if (mode == NEVER_FLICKER) { - cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER; - } else { - cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER; - } - - if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES, - TRANSFER_WRITE, cam_reg))) - return err; - - if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, - TRANSFER_WRITE, 1))) - return err; - - switch(mode) { - case NEVER_FLICKER: - cam->params.flicker_control.flicker_mode_req = mode; - break; - case FLICKER_60: - cam->params.flicker_control.flicker_mode_req = mode; - cam->params.flicker_control.mains_frequency = 60; - break; - case FLICKER_50: - cam->params.flicker_control.flicker_mode_req = mode; - cam->params.flicker_control.mains_frequency = 50; - break; - default: - err = -EINVAL; - } - - return err; -} - -/****************************************************************************** - * - * cpia2_set_property_flip - * - *****************************************************************************/ -void cpia2_set_property_flip(struct camera_data *cam, int prop_val) -{ - unsigned char cam_reg; - - cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); - cam_reg = cam->params.vp_params.user_effects; - - if (prop_val) - { - cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP; - } - else - { - cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP; - } - cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, - cam_reg); -} - -/****************************************************************************** - * - * cpia2_set_property_mirror - * - *****************************************************************************/ -void cpia2_set_property_mirror(struct camera_data *cam, int prop_val) -{ - unsigned char cam_reg; - - cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); - cam_reg = cam->params.vp_params.user_effects; - - if (prop_val) - { - cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR; - } - else - { - cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR; - } - cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, - cam_reg); -} - -/****************************************************************************** - * - * set_target_kb - * - * The new Target KB is set in cam->params.vc_params.target_kb and - * activates on reset. - *****************************************************************************/ - -int cpia2_set_target_kb(struct camera_data *cam, unsigned char value) -{ - DBG("Requested target_kb = %d\n", value); - if (value != cam->params.vc_params.target_kb) { - - cpia2_usb_stream_pause(cam); - - /* reset camera for new target_kb */ - cam->params.vc_params.target_kb = value; - cpia2_reset_camera(cam); - - cpia2_usb_stream_resume(cam); - } - - return 0; -} - -/****************************************************************************** - * - * cpia2_set_gpio - * - *****************************************************************************/ -int cpia2_set_gpio(struct camera_data *cam, unsigned char setting) -{ - int ret; - - /* Set the microport direction (register 0x90, should be defined - * already) to 1 (user output), and set the microport data (0x91) to - * the value in the ioctl argument. - */ - - ret = cpia2_do_command(cam, - CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, - CPIA2_VC_MP_DIR_OUTPUT, - 255); - if (ret < 0) - return ret; - cam->params.vp_params.gpio_direction = 255; - - ret = cpia2_do_command(cam, - CPIA2_CMD_SET_VC_MP_GPIO_DATA, - CPIA2_VC_MP_DIR_OUTPUT, - setting); - if (ret < 0) - return ret; - cam->params.vp_params.gpio_data = setting; - - return 0; -} - -/****************************************************************************** - * - * cpia2_set_fps - * - *****************************************************************************/ -int cpia2_set_fps(struct camera_data *cam, int framerate) -{ - int retval; - - switch(framerate) { - case CPIA2_VP_FRAMERATE_30: - case CPIA2_VP_FRAMERATE_25: - if(cam->params.pnp_id.device_type == DEVICE_STV_672 && - cam->params.version.sensor_flags == - CPIA2_VP_SENSOR_FLAGS_500) { - return -EINVAL; - } - /* Fall through */ - case CPIA2_VP_FRAMERATE_15: - case CPIA2_VP_FRAMERATE_12_5: - case CPIA2_VP_FRAMERATE_7_5: - case CPIA2_VP_FRAMERATE_6_25: - break; - default: - return -EINVAL; - } - - if (cam->params.pnp_id.device_type == DEVICE_STV_672 && - framerate == CPIA2_VP_FRAMERATE_15) - framerate = 0; /* Work around bug in VP4 */ - - retval = cpia2_do_command(cam, - CPIA2_CMD_FRAMERATE_REQ, - TRANSFER_WRITE, - framerate); - - if(retval == 0) - cam->params.vp_params.frame_rate = framerate; - - return retval; -} - -/****************************************************************************** - * - * cpia2_set_brightness - * - *****************************************************************************/ -void cpia2_set_brightness(struct camera_data *cam, unsigned char value) -{ - /*** - * Don't let the register be set to zero - bug in VP4 - flash of full - * brightness - ***/ - if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0) - value++; - DBG("Setting brightness to %d (0x%0x)\n", value, value); - cpia2_do_command(cam,CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE,value); -} - -/****************************************************************************** - * - * cpia2_set_contrast - * - *****************************************************************************/ -void cpia2_set_contrast(struct camera_data *cam, unsigned char value) -{ - DBG("Setting contrast to %d (0x%0x)\n", value, value); - cam->params.color_params.contrast = value; - cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value); -} - -/****************************************************************************** - * - * cpia2_set_saturation - * - *****************************************************************************/ -void cpia2_set_saturation(struct camera_data *cam, unsigned char value) -{ - DBG("Setting saturation to %d (0x%0x)\n", value, value); - cam->params.color_params.saturation = value; - cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value); -} - -/****************************************************************************** - * - * wake_system - * - *****************************************************************************/ -static void wake_system(struct camera_data *cam) -{ - cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0); -} - -/****************************************************************************** - * - * set_lowlight_boost - * - * Valid for STV500 sensor only - *****************************************************************************/ -static void set_lowlight_boost(struct camera_data *cam) -{ - struct cpia2_command cmd; - - if (cam->params.pnp_id.device_type != DEVICE_STV_672 || - cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500) - return; - - cmd.direction = TRANSFER_WRITE; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 3; - cmd.start = CPIA2_VP_RAM_ADDR_H; - - cmd.buffer.block_data[0] = 0; /* High byte of address to write to */ - cmd.buffer.block_data[1] = 0x59; /* Low byte of address to write to */ - cmd.buffer.block_data[2] = 0; /* High byte of data to write */ - - cpia2_send_command(cam, &cmd); - - if (cam->params.vp_params.lowlight_boost) { - cmd.buffer.block_data[0] = 0x02; /* Low byte data to write */ - } else { - cmd.buffer.block_data[0] = 0x06; - } - cmd.start = CPIA2_VP_RAM_DATA; - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - - /* Rehash the VP4 values */ - cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1); -} - -/****************************************************************************** - * - * cpia2_set_format - * - * Assumes that new size is already set in param struct. - *****************************************************************************/ -void cpia2_set_format(struct camera_data *cam) -{ - cam->flush = true; - - cpia2_usb_stream_pause(cam); - - /* reset camera to new size */ - cpia2_set_low_power(cam); - cpia2_reset_camera(cam); - cam->flush = false; - - cpia2_dbg_dump_registers(cam); - - cpia2_usb_stream_resume(cam); -} - -/****************************************************************************** - * - * cpia2_dbg_dump_registers - * - *****************************************************************************/ -void cpia2_dbg_dump_registers(struct camera_data *cam) -{ -#ifdef _CPIA2_DEBUG_ - struct cpia2_command cmd; - - if (!(debugs_on & DEBUG_DUMP_REGS)) - return; - - cmd.direction = TRANSFER_READ; - - /* Start with bank 0 (SYSTEM) */ - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 3; - cmd.start = 0; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "System Device Hi = 0x%X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "System Device Lo = 0x%X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "System_system control = 0x%X\n", - cmd.buffer.block_data[2]); - - /* Bank 1 (VC) */ - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 4; - cmd.start = 0x80; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "ASIC_ID = 0x%X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "ASIC_REV = 0x%X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "PW_CONTRL = 0x%X\n", - cmd.buffer.block_data[2]); - printk(KERN_DEBUG "WAKEUP = 0x%X\n", - cmd.buffer.block_data[3]); - - cmd.start = 0xA0; /* ST_CTRL */ - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "Stream ctrl = 0x%X\n", - cmd.buffer.block_data[0]); - - cmd.start = 0xA4; /* Stream status */ - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "Stream status = 0x%X\n", - cmd.buffer.block_data[0]); - - cmd.start = 0xA8; /* USB status */ - cmd.reg_count = 3; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "USB_CTRL = 0x%X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "USB_STRM = 0x%X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "USB_STATUS = 0x%X\n", - cmd.buffer.block_data[2]); - - cmd.start = 0xAF; /* USB settings */ - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "USB settings = 0x%X\n", - cmd.buffer.block_data[0]); - - cmd.start = 0xC0; /* VC stuff */ - cmd.reg_count = 26; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VC Control = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VC Format = 0x%0X\n", - cmd.buffer.block_data[3]); - printk(KERN_DEBUG "VC Clocks = 0x%0X\n", - cmd.buffer.block_data[4]); - printk(KERN_DEBUG "VC IHSize = 0x%0X\n", - cmd.buffer.block_data[5]); - printk(KERN_DEBUG "VC Xlim Hi = 0x%0X\n", - cmd.buffer.block_data[6]); - printk(KERN_DEBUG "VC XLim Lo = 0x%0X\n", - cmd.buffer.block_data[7]); - printk(KERN_DEBUG "VC YLim Hi = 0x%0X\n", - cmd.buffer.block_data[8]); - printk(KERN_DEBUG "VC YLim Lo = 0x%0X\n", - cmd.buffer.block_data[9]); - printk(KERN_DEBUG "VC OHSize = 0x%0X\n", - cmd.buffer.block_data[10]); - printk(KERN_DEBUG "VC OVSize = 0x%0X\n", - cmd.buffer.block_data[11]); - printk(KERN_DEBUG "VC HCrop = 0x%0X\n", - cmd.buffer.block_data[12]); - printk(KERN_DEBUG "VC VCrop = 0x%0X\n", - cmd.buffer.block_data[13]); - printk(KERN_DEBUG "VC HPhase = 0x%0X\n", - cmd.buffer.block_data[14]); - printk(KERN_DEBUG "VC VPhase = 0x%0X\n", - cmd.buffer.block_data[15]); - printk(KERN_DEBUG "VC HIspan = 0x%0X\n", - cmd.buffer.block_data[16]); - printk(KERN_DEBUG "VC VIspan = 0x%0X\n", - cmd.buffer.block_data[17]); - printk(KERN_DEBUG "VC HiCrop = 0x%0X\n", - cmd.buffer.block_data[18]); - printk(KERN_DEBUG "VC ViCrop = 0x%0X\n", - cmd.buffer.block_data[19]); - printk(KERN_DEBUG "VC HiFract = 0x%0X\n", - cmd.buffer.block_data[20]); - printk(KERN_DEBUG "VC ViFract = 0x%0X\n", - cmd.buffer.block_data[21]); - printk(KERN_DEBUG "VC JPeg Opt = 0x%0X\n", - cmd.buffer.block_data[22]); - printk(KERN_DEBUG "VC Creep Per = 0x%0X\n", - cmd.buffer.block_data[23]); - printk(KERN_DEBUG "VC User Sq. = 0x%0X\n", - cmd.buffer.block_data[24]); - printk(KERN_DEBUG "VC Target KB = 0x%0X\n", - cmd.buffer.block_data[25]); - - /*** VP ***/ - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 14; - cmd.start = 0; - cpia2_send_command(cam, &cmd); - - printk(KERN_DEBUG "VP Dev Hi = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VP Dev Lo = 0x%0X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "VP Sys State = 0x%0X\n", - cmd.buffer.block_data[2]); - printk(KERN_DEBUG "VP Sys Ctrl = 0x%0X\n", - cmd.buffer.block_data[3]); - printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n", - cmd.buffer.block_data[5]); - printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n", - cmd.buffer.block_data[6]); - printk(KERN_DEBUG "VP Dev Config = 0x%0X\n", - cmd.buffer.block_data[7]); - printk(KERN_DEBUG "VP GPIO_DIR = 0x%0X\n", - cmd.buffer.block_data[8]); - printk(KERN_DEBUG "VP GPIO_DATA = 0x%0X\n", - cmd.buffer.block_data[9]); - printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n", - cmd.buffer.block_data[10]); - printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n", - cmd.buffer.block_data[11]); - printk(KERN_DEBUG "VP RAM Data = 0x%0X\n", - cmd.buffer.block_data[12]); - printk(KERN_DEBUG "Do Call = 0x%0X\n", - cmd.buffer.block_data[13]); - - if (cam->params.pnp_id.device_type == DEVICE_STV_672) { - cmd.reg_count = 9; - cmd.start = 0x0E; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n", - cmd.buffer.block_data[2]); - printk(KERN_DEBUG "VP Framerate = 0x%0X\n", - cmd.buffer.block_data[3]); - printk(KERN_DEBUG "VP UserEffect = 0x%0X\n", - cmd.buffer.block_data[4]); - printk(KERN_DEBUG "VP White Bal = 0x%0X\n", - cmd.buffer.block_data[5]); - printk(KERN_DEBUG "VP WB thresh = 0x%0X\n", - cmd.buffer.block_data[6]); - printk(KERN_DEBUG "VP Exp Modes = 0x%0X\n", - cmd.buffer.block_data[7]); - printk(KERN_DEBUG "VP Exp Target = 0x%0X\n", - cmd.buffer.block_data[8]); - - cmd.reg_count = 1; - cmd.start = 0x1B; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n", - cmd.buffer.block_data[0]); - } else { - cmd.reg_count = 8 ; - cmd.start = 0x0E; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n", - cmd.buffer.block_data[5]); - printk(KERN_DEBUG "VP Framerate = 0x%0X\n", - cmd.buffer.block_data[6]); - printk(KERN_DEBUG "VP UserEffect = 0x%0X\n", - cmd.buffer.block_data[7]); - - cmd.reg_count = 1; - cmd.start = CPIA2_VP5_EXPOSURE_TARGET; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n", - cmd.buffer.block_data[0]); - - cmd.reg_count = 4; - cmd.start = 0x3A; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP5 MY Black = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n", - cmd.buffer.block_data[2]); - printk(KERN_DEBUG "VP5 MCUV Sat = 0x%0X\n", - cmd.buffer.block_data[3]); - } -#endif -} - -/****************************************************************************** - * - * reset_camera_struct - * - * Sets all values to the defaults - *****************************************************************************/ -static void reset_camera_struct(struct camera_data *cam) -{ - /*** - * The following parameter values are the defaults from the register map. - ***/ - cam->params.color_params.brightness = DEFAULT_BRIGHTNESS; - cam->params.color_params.contrast = DEFAULT_CONTRAST; - cam->params.color_params.saturation = DEFAULT_SATURATION; - cam->params.vp_params.lowlight_boost = 0; - - /* FlickerModes */ - cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER; - cam->params.flicker_control.mains_frequency = 60; - - /* jpeg params */ - cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT; - cam->params.compression.creep_period = 2; - cam->params.compression.user_squeeze = 20; - cam->params.compression.inhibit_htables = false; - - /* gpio params */ - cam->params.vp_params.gpio_direction = 0; /* write, the default safe mode */ - cam->params.vp_params.gpio_data = 0; - - /* Target kb params */ - cam->params.vc_params.target_kb = DEFAULT_TARGET_KB; - - /*** - * Set Sensor FPS as fast as possible. - ***/ - if(cam->params.pnp_id.device_type == DEVICE_STV_672) { - if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) - cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15; - else - cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30; - } else { - cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30; - } - - /*** - * Set default video mode as large as possible : - * for vga sensor set to vga, for cif sensor set to CIF. - ***/ - if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) { - cam->sensor_type = CPIA2_SENSOR_500; - cam->video_size = VIDEOSIZE_VGA; - cam->params.roi.width = STV_IMAGE_VGA_COLS; - cam->params.roi.height = STV_IMAGE_VGA_ROWS; - } else { - cam->sensor_type = CPIA2_SENSOR_410; - cam->video_size = VIDEOSIZE_CIF; - cam->params.roi.width = STV_IMAGE_CIF_COLS; - cam->params.roi.height = STV_IMAGE_CIF_ROWS; - } - - cam->width = cam->params.roi.width; - cam->height = cam->params.roi.height; -} - -/****************************************************************************** - * - * cpia2_init_camera_struct - * - * Initializes camera struct, does not call reset to fill in defaults. - *****************************************************************************/ -struct camera_data *cpia2_init_camera_struct(void) -{ - struct camera_data *cam; - - cam = kzalloc(sizeof(*cam), GFP_KERNEL); - - if (!cam) { - ERR("couldn't kmalloc cpia2 struct\n"); - return NULL; - } - - - cam->present = 1; - mutex_init(&cam->v4l2_lock); - init_waitqueue_head(&cam->wq_stream); - - return cam; -} - -/****************************************************************************** - * - * cpia2_init_camera - * - * Initializes camera. - *****************************************************************************/ -int cpia2_init_camera(struct camera_data *cam) -{ - DBG("Start\n"); - - cam->mmapped = false; - - /* Get sensor and asic types before reset. */ - cpia2_set_high_power(cam); - cpia2_get_version_info(cam); - if (cam->params.version.asic_id != CPIA2_ASIC_672) { - ERR("Device IO error (asicID has incorrect value of 0x%X\n", - cam->params.version.asic_id); - return -ENODEV; - } - - /* Set GPIO direction and data to a safe state. */ - cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, - TRANSFER_WRITE, 0); - cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, - TRANSFER_WRITE, 0); - - /* resetting struct requires version info for sensor and asic types */ - reset_camera_struct(cam); - - cpia2_set_low_power(cam); - - DBG("End\n"); - - return 0; -} - -/****************************************************************************** - * - * cpia2_allocate_buffers - * - *****************************************************************************/ -int cpia2_allocate_buffers(struct camera_data *cam) -{ - int i; - - if(!cam->buffers) { - u32 size = cam->num_frames*sizeof(struct framebuf); - cam->buffers = kmalloc(size, GFP_KERNEL); - if(!cam->buffers) { - ERR("couldn't kmalloc frame buffer structures\n"); - return -ENOMEM; - } - } - - if(!cam->frame_buffer) { - cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames); - if (!cam->frame_buffer) { - ERR("couldn't vmalloc frame buffer data area\n"); - kfree(cam->buffers); - cam->buffers = NULL; - return -ENOMEM; - } - } - - for(i=0; inum_frames-1; ++i) { - cam->buffers[i].next = &cam->buffers[i+1]; - cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size; - cam->buffers[i].status = FRAME_EMPTY; - cam->buffers[i].length = 0; - cam->buffers[i].max_length = 0; - cam->buffers[i].num = i; - } - cam->buffers[i].next = cam->buffers; - cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size; - cam->buffers[i].status = FRAME_EMPTY; - cam->buffers[i].length = 0; - cam->buffers[i].max_length = 0; - cam->buffers[i].num = i; - cam->curbuff = cam->buffers; - cam->workbuff = cam->curbuff->next; - DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff, - cam->workbuff); - return 0; -} - -/****************************************************************************** - * - * cpia2_free_buffers - * - *****************************************************************************/ -void cpia2_free_buffers(struct camera_data *cam) -{ - if(cam->buffers) { - kfree(cam->buffers); - cam->buffers = NULL; - } - if(cam->frame_buffer) { - rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames); - cam->frame_buffer = NULL; - } -} - -/****************************************************************************** - * - * cpia2_read - * - *****************************************************************************/ -long cpia2_read(struct camera_data *cam, - char __user *buf, unsigned long count, int noblock) -{ - struct framebuf *frame; - - if (!count) - return 0; - - if (!buf) { - ERR("%s: buffer NULL\n",__func__); - return -EINVAL; - } - - if (!cam) { - ERR("%s: Internal error, camera_data NULL!\n",__func__); - return -EINVAL; - } - - if (!cam->present) { - LOG("%s: camera removed\n",__func__); - return 0; /* EOF */ - } - - if (!cam->streaming) { - /* Start streaming */ - cpia2_usb_stream_start(cam, - cam->params.camera_state.stream_mode); - } - - /* Copy cam->curbuff in case it changes while we're processing */ - frame = cam->curbuff; - if (noblock && frame->status != FRAME_READY) { - return -EAGAIN; - } - - if (frame->status != FRAME_READY) { - mutex_unlock(&cam->v4l2_lock); - wait_event_interruptible(cam->wq_stream, - !cam->present || - (frame = cam->curbuff)->status == FRAME_READY); - mutex_lock(&cam->v4l2_lock); - if (signal_pending(current)) - return -ERESTARTSYS; - if (!cam->present) - return 0; - } - - /* copy data to user space */ - if (frame->length > count) - return -EFAULT; - if (copy_to_user(buf, frame->data, frame->length)) - return -EFAULT; - - count = frame->length; - - frame->status = FRAME_EMPTY; - - return count; -} - -/****************************************************************************** - * - * cpia2_poll - * - *****************************************************************************/ -unsigned int cpia2_poll(struct camera_data *cam, struct file *filp, - poll_table *wait) -{ - unsigned int status=0; - - if (!cam) { - ERR("%s: Internal error, camera_data not found!\n",__func__); - return POLLERR; - } - - if (!cam->present) - return POLLHUP; - - if(!cam->streaming) { - /* Start streaming */ - cpia2_usb_stream_start(cam, - cam->params.camera_state.stream_mode); - } - - poll_wait(filp, &cam->wq_stream, wait); - - if(!cam->present) - status = POLLHUP; - else if(cam->curbuff->status == FRAME_READY) - status = POLLIN | POLLRDNORM; - - return status; -} - -/****************************************************************************** - * - * cpia2_remap_buffer - * - *****************************************************************************/ -int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma) -{ - const char *adr = (const char *)vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long start = (unsigned long) adr; - unsigned long page, pos; - - if (!cam) - return -ENODEV; - - DBG("mmap offset:%ld size:%ld\n", start_offset, size); - - if (!cam->present) - return -ENODEV; - - if (size > cam->frame_size*cam->num_frames || - (start_offset % cam->frame_size) != 0 || - (start_offset+size > cam->frame_size*cam->num_frames)) - return -EINVAL; - - pos = ((unsigned long) (cam->frame_buffer)) + start_offset; - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - cam->mmapped = true; - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2dev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2dev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2dev.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2dev.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/**************************************************************************** - * - * Filename: cpia2dev.h - * - * Copyright 2001, STMicrolectronics, Inc. - * - * Contact: steve.miller@st.com - * - * Description: - * This file provides definitions for applications wanting to use the - * cpia2 driver beyond the generic v4l capabilities. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ****************************************************************************/ - -#ifndef CPIA2_DEV_HEADER -#define CPIA2_DEV_HEADER - -#include - -/*** - * The following defines are ioctl numbers based on video4linux private ioctls, - * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int - * args - */ -#define CPIA2_IOC_SET_GPIO _IOW('v', BASE_VIDIOC_PRIVATE + 17, __u32) - -/* V4L2 driver specific controls */ -#define CPIA2_CID_TARGET_KB (V4L2_CID_PRIVATE_BASE+0) -#define CPIA2_CID_GPIO (V4L2_CID_PRIVATE_BASE+1) -#define CPIA2_CID_FLICKER_MODE (V4L2_CID_PRIVATE_BASE+2) -#define CPIA2_CID_FRAMERATE (V4L2_CID_PRIVATE_BASE+3) -#define CPIA2_CID_USB_ALT (V4L2_CID_PRIVATE_BASE+4) -#define CPIA2_CID_LIGHTS (V4L2_CID_PRIVATE_BASE+5) -#define CPIA2_CID_RESET_CAMERA (V4L2_CID_PRIVATE_BASE+6) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,494 +0,0 @@ -/**************************************************************************** - * - * Filename: cpia2.h - * - * Copyright 2001, STMicrolectronics, Inc. - * - * Contact: steve.miller@st.com - * - * Description: - * This is a USB driver for CPiA2 based video cameras. - * - * This driver is modelled on the cpia usb driver by - * Jochen Scharrlach and Johannes Erdfeldt. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ****************************************************************************/ - -#ifndef __CPIA2_H__ -#define __CPIA2_H__ - -#include -#include -#include -#include -#include - -#include "cpia2dev.h" -#include "cpia2_registers.h" - -/* define for verbose debug output */ -//#define _CPIA2_DEBUG_ - -#define CPIA2_MAJ_VER 3 -#define CPIA2_MIN_VER 0 -#define CPIA2_PATCH_VER 0 - -/*** - * Image defines - ***/ - -/* Misc constants */ -#define ALLOW_CORRUPT 0 /* Causes collater to discard checksum */ - -/* USB Transfer mode */ -#define XFER_ISOC 0 -#define XFER_BULK 1 - -/* USB Alternates */ -#define USBIF_CMDONLY 0 -#define USBIF_BULK 1 -#define USBIF_ISO_1 2 /* 128 bytes/ms */ -#define USBIF_ISO_2 3 /* 384 bytes/ms */ -#define USBIF_ISO_3 4 /* 640 bytes/ms */ -#define USBIF_ISO_4 5 /* 768 bytes/ms */ -#define USBIF_ISO_5 6 /* 896 bytes/ms */ -#define USBIF_ISO_6 7 /* 1023 bytes/ms */ - -/* Flicker Modes */ -#define NEVER_FLICKER 0 -#define ANTI_FLICKER_ON 1 -#define FLICKER_60 60 -#define FLICKER_50 50 - -/* Debug flags */ -#define DEBUG_NONE 0 -#define DEBUG_REG 0x00000001 -#define DEBUG_DUMP_PATCH 0x00000002 -#define DEBUG_DUMP_REGS 0x00000004 - -/*** - * Video frame sizes - ***/ -enum { - VIDEOSIZE_VGA = 0, /* 640x480 */ - VIDEOSIZE_CIF, /* 352x288 */ - VIDEOSIZE_QVGA, /* 320x240 */ - VIDEOSIZE_QCIF, /* 176x144 */ - VIDEOSIZE_288_216, - VIDEOSIZE_256_192, - VIDEOSIZE_224_168, - VIDEOSIZE_192_144, -}; - -#define STV_IMAGE_CIF_ROWS 288 -#define STV_IMAGE_CIF_COLS 352 - -#define STV_IMAGE_QCIF_ROWS 144 -#define STV_IMAGE_QCIF_COLS 176 - -#define STV_IMAGE_VGA_ROWS 480 -#define STV_IMAGE_VGA_COLS 640 - -#define STV_IMAGE_QVGA_ROWS 240 -#define STV_IMAGE_QVGA_COLS 320 - -#define JPEG_MARKER_COM (1<<6) /* Comment segment */ - -/*** - * Enums - ***/ -/* Sensor types available with cpia2 asics */ -enum sensors { - CPIA2_SENSOR_410, - CPIA2_SENSOR_500 -}; - -/* Asic types available in the CPiA2 architecture */ -#define CPIA2_ASIC_672 0x67 - -/* Device types (stv672, stv676, etc) */ -#define DEVICE_STV_672 0x0001 -#define DEVICE_STV_676 0x0002 - -enum frame_status { - FRAME_EMPTY, - FRAME_READING, /* In the process of being grabbed into */ - FRAME_READY, /* Ready to be read */ - FRAME_ERROR, -}; - -/*** - * Register access (for USB request byte) - ***/ -enum { - CAMERAACCESS_SYSTEM = 0, - CAMERAACCESS_VC, - CAMERAACCESS_VP, - CAMERAACCESS_IDATA -}; - -#define CAMERAACCESS_TYPE_BLOCK 0x00 -#define CAMERAACCESS_TYPE_RANDOM 0x04 -#define CAMERAACCESS_TYPE_MASK 0x08 -#define CAMERAACCESS_TYPE_REPEAT 0x0C - -#define TRANSFER_READ 0 -#define TRANSFER_WRITE 1 - -#define DEFAULT_ALT USBIF_ISO_6 -#define DEFAULT_BRIGHTNESS 0x46 -#define DEFAULT_CONTRAST 0x93 -#define DEFAULT_SATURATION 0x7f -#define DEFAULT_TARGET_KB 0x30 - -/* Power state */ -#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER -#define LO_POWER_MODE CPIA2_SYSTEM_CONTROL_LOW_POWER - - -/******** - * Commands - *******/ -enum { - CPIA2_CMD_NONE = 0, - CPIA2_CMD_GET_VERSION, - CPIA2_CMD_GET_PNP_ID, - CPIA2_CMD_GET_ASIC_TYPE, - CPIA2_CMD_GET_SENSOR, - CPIA2_CMD_GET_VP_DEVICE, - CPIA2_CMD_GET_VP_BRIGHTNESS, - CPIA2_CMD_SET_VP_BRIGHTNESS, - CPIA2_CMD_GET_CONTRAST, - CPIA2_CMD_SET_CONTRAST, - CPIA2_CMD_GET_VP_SATURATION, - CPIA2_CMD_SET_VP_SATURATION, - CPIA2_CMD_GET_VP_GPIO_DIRECTION, - CPIA2_CMD_SET_VP_GPIO_DIRECTION, - CPIA2_CMD_GET_VP_GPIO_DATA, - CPIA2_CMD_SET_VP_GPIO_DATA, - CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, - CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, - CPIA2_CMD_GET_VC_MP_GPIO_DATA, - CPIA2_CMD_SET_VC_MP_GPIO_DATA, - CPIA2_CMD_ENABLE_PACKET_CTRL, - CPIA2_CMD_GET_FLICKER_MODES, - CPIA2_CMD_SET_FLICKER_MODES, - CPIA2_CMD_RESET_FIFO, /* clear fifo and enable stream block */ - CPIA2_CMD_SET_HI_POWER, - CPIA2_CMD_SET_LOW_POWER, - CPIA2_CMD_CLEAR_V2W_ERR, - CPIA2_CMD_SET_USER_MODE, - CPIA2_CMD_GET_USER_MODE, - CPIA2_CMD_FRAMERATE_REQ, - CPIA2_CMD_SET_COMPRESSION_STATE, - CPIA2_CMD_GET_WAKEUP, - CPIA2_CMD_SET_WAKEUP, - CPIA2_CMD_GET_PW_CONTROL, - CPIA2_CMD_SET_PW_CONTROL, - CPIA2_CMD_GET_SYSTEM_CTRL, - CPIA2_CMD_SET_SYSTEM_CTRL, - CPIA2_CMD_GET_VP_SYSTEM_STATE, - CPIA2_CMD_GET_VP_SYSTEM_CTRL, - CPIA2_CMD_SET_VP_SYSTEM_CTRL, - CPIA2_CMD_GET_VP_EXP_MODES, - CPIA2_CMD_SET_VP_EXP_MODES, - CPIA2_CMD_GET_DEVICE_CONFIG, - CPIA2_CMD_SET_DEVICE_CONFIG, - CPIA2_CMD_SET_SERIAL_ADDR, - CPIA2_CMD_SET_SENSOR_CR1, - CPIA2_CMD_GET_VC_CONTROL, - CPIA2_CMD_SET_VC_CONTROL, - CPIA2_CMD_SET_TARGET_KB, - CPIA2_CMD_SET_DEF_JPEG_OPT, - CPIA2_CMD_REHASH_VP4, - CPIA2_CMD_GET_USER_EFFECTS, - CPIA2_CMD_SET_USER_EFFECTS -}; - -enum user_cmd { - COMMAND_NONE = 0x00000001, - COMMAND_SET_FPS = 0x00000002, - COMMAND_SET_COLOR_PARAMS = 0x00000004, - COMMAND_GET_COLOR_PARAMS = 0x00000008, - COMMAND_SET_FORMAT = 0x00000010, /* size, etc */ - COMMAND_SET_FLICKER = 0x00000020 -}; - -/*** - * Some defines specific to the 676 chip - ***/ -#define CAMACC_CIF 0x01 -#define CAMACC_VGA 0x02 -#define CAMACC_QCIF 0x04 -#define CAMACC_QVGA 0x08 - - -struct cpia2_register { - u8 index; - u8 value; -}; - -struct cpia2_reg_mask { - u8 index; - u8 and_mask; - u8 or_mask; - u8 fill; -}; - -struct cpia2_command { - u32 command; - u8 req_mode; /* (Block or random) | registerBank */ - u8 reg_count; - u8 direction; - u8 start; - union reg_types { - struct cpia2_register registers[32]; - struct cpia2_reg_mask masks[16]; - u8 block_data[64]; - u8 *patch_data; /* points to function defined block */ - } buffer; -}; - -struct camera_params { - struct { - u8 firmware_revision_hi; /* For system register set (bank 0) */ - u8 firmware_revision_lo; - u8 asic_id; /* Video Compressor set (bank 1) */ - u8 asic_rev; - u8 vp_device_hi; /* Video Processor set (bank 2) */ - u8 vp_device_lo; - u8 sensor_flags; - u8 sensor_rev; - } version; - - struct { - u32 device_type; /* enumerated from vendor/product ids. - * Currently, either STV_672 or STV_676 */ - u16 vendor; - u16 product; - u16 device_revision; - } pnp_id; - - struct { - u8 brightness; /* CPIA2_VP_EXPOSURE_TARGET */ - u8 contrast; /* Note: this is CPIA2_VP_YRANGE */ - u8 saturation; /* CPIA2_VP_SATURATION */ - } color_params; - - struct { - u8 cam_register; - u8 flicker_mode_req; /* 1 if flicker on, else never flicker */ - int mains_frequency; - } flicker_control; - - struct { - u8 jpeg_options; - u8 creep_period; - u8 user_squeeze; - u8 inhibit_htables; - } compression; - - struct { - u8 ohsize; /* output image size */ - u8 ovsize; - u8 hcrop; /* cropping start_pos/4 */ - u8 vcrop; - u8 hphase; /* scaling registers */ - u8 vphase; - u8 hispan; - u8 vispan; - u8 hicrop; - u8 vicrop; - u8 hifraction; - u8 vifraction; - } image_size; - - struct { - int width; /* actual window width */ - int height; /* actual window height */ - } roi; - - struct { - u8 video_mode; - u8 frame_rate; - u8 video_size; /* Not a register, just a convenience for cropped sizes */ - u8 gpio_direction; - u8 gpio_data; - u8 system_ctrl; - u8 system_state; - u8 lowlight_boost; /* Bool: 0 = off, 1 = on */ - u8 device_config; - u8 exposure_modes; - u8 user_effects; - } vp_params; - - struct { - u8 pw_control; - u8 wakeup; - u8 vc_control; - u8 vc_mp_direction; - u8 vc_mp_data; - u8 target_kb; - } vc_params; - - struct { - u8 power_mode; - u8 system_ctrl; - u8 stream_mode; /* This is the current alternate for usb drivers */ - u8 allow_corrupt; - } camera_state; -}; - -#define NUM_SBUF 2 - -struct cpia2_sbuf { - char *data; - struct urb *urb; -}; - -struct framebuf { - struct timeval timestamp; - unsigned long seq; - int num; - int length; - int max_length; - volatile enum frame_status status; - u8 *data; - struct framebuf *next; -}; - -struct cpia2_fh { - enum v4l2_priority prio; - u8 mmapped; -}; - -struct camera_data { - /* locks */ - struct mutex v4l2_lock; /* serialize file operations */ - struct v4l2_prio_state prio; - - /* camera status */ - volatile int present; /* Is the camera still present? */ - int open_count; /* # of process that have camera open */ - int first_image_seen; - u8 mains_freq; /* for flicker control */ - enum sensors sensor_type; - u8 flush; - u8 mmapped; - int streaming; /* 0 = no, 1 = yes */ - int xfer_mode; /* XFER_BULK or XFER_ISOC */ - struct camera_params params; /* camera settings */ - - /* v4l */ - int video_size; /* VIDEO_SIZE_ */ - struct video_device *vdev; /* v4l videodev */ - u32 width; - u32 height; /* Its size */ - __u32 pixelformat; /* Format fourcc */ - - /* USB */ - struct usb_device *dev; - unsigned char iface; - unsigned int cur_alt; - unsigned int old_alt; - struct cpia2_sbuf sbuf[NUM_SBUF]; /* Double buffering */ - - wait_queue_head_t wq_stream; - - /* Buffering */ - u32 frame_size; - int num_frames; - unsigned long frame_count; - u8 *frame_buffer; /* frame buffer data */ - struct framebuf *buffers; - struct framebuf * volatile curbuff; - struct framebuf *workbuff; - - /* MJPEG Extension */ - int APPn; /* Number of APP segment to be written, must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ -}; - -/* v4l */ -int cpia2_register_camera(struct camera_data *cam); -void cpia2_unregister_camera(struct camera_data *cam); - -/* core */ -int cpia2_reset_camera(struct camera_data *cam); -int cpia2_set_low_power(struct camera_data *cam); -void cpia2_dbg_dump_registers(struct camera_data *cam); -int cpia2_match_video_size(int width, int height); -void cpia2_set_camera_state(struct camera_data *cam); -void cpia2_save_camera_state(struct camera_data *cam); -void cpia2_set_color_params(struct camera_data *cam); -void cpia2_set_brightness(struct camera_data *cam, unsigned char value); -void cpia2_set_contrast(struct camera_data *cam, unsigned char value); -void cpia2_set_saturation(struct camera_data *cam, unsigned char value); -int cpia2_set_flicker_mode(struct camera_data *cam, int mode); -void cpia2_set_format(struct camera_data *cam); -int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd); -int cpia2_do_command(struct camera_data *cam, - unsigned int command, - unsigned char direction, unsigned char param); -struct camera_data *cpia2_init_camera_struct(void); -int cpia2_init_camera(struct camera_data *cam); -int cpia2_allocate_buffers(struct camera_data *cam); -void cpia2_free_buffers(struct camera_data *cam); -long cpia2_read(struct camera_data *cam, - char __user *buf, unsigned long count, int noblock); -unsigned int cpia2_poll(struct camera_data *cam, - struct file *filp, poll_table *wait); -int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma); -void cpia2_set_property_flip(struct camera_data *cam, int prop_val); -void cpia2_set_property_mirror(struct camera_data *cam, int prop_val); -int cpia2_set_target_kb(struct camera_data *cam, unsigned char value); -int cpia2_set_gpio(struct camera_data *cam, unsigned char setting); -int cpia2_set_fps(struct camera_data *cam, int framerate); - -/* usb */ -int cpia2_usb_init(void); -void cpia2_usb_cleanup(void); -int cpia2_usb_transfer_cmd(struct camera_data *cam, void *registers, - u8 request, u8 start, u8 count, u8 direction); -int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate); -int cpia2_usb_stream_stop(struct camera_data *cam); -int cpia2_usb_stream_pause(struct camera_data *cam); -int cpia2_usb_stream_resume(struct camera_data *cam); -int cpia2_usb_change_streaming_alternate(struct camera_data *cam, - unsigned int alt); - - -/* ----------------------- debug functions ---------------------- */ -#ifdef _CPIA2_DEBUG_ -#define ALOG(lev, fmt, args...) printk(lev "%s:%d %s(): " fmt, __FILE__, __LINE__, __func__, ## args) -#define LOG(fmt, args...) ALOG(KERN_INFO, fmt, ## args) -#define ERR(fmt, args...) ALOG(KERN_ERR, fmt, ## args) -#define DBG(fmt, args...) ALOG(KERN_DEBUG, fmt, ## args) -#else -#define ALOG(fmt,args...) printk(fmt,##args) -#define LOG(fmt,args...) ALOG(KERN_INFO "cpia2: "fmt,##args) -#define ERR(fmt,args...) ALOG(KERN_ERR "cpia2: "fmt,##args) -#define DBG(fmn,args...) do {} while(0) -#endif -/* No function or lineno, for shorter lines */ -#define KINFO(fmt, args...) printk(KERN_INFO fmt,##args) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_registers.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_registers.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_registers.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_registers.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,476 +0,0 @@ -/**************************************************************************** - * - * Filename: cpia2registers.h - * - * Copyright 2001, STMicrolectronics, Inc. - * - * Description: - * Definitions for the CPia2 register set - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ****************************************************************************/ - -#ifndef CPIA2_REGISTER_HEADER -#define CPIA2_REGISTER_HEADER - -/*** - * System register set (Bank 0) - ***/ -#define CPIA2_SYSTEM_DEVICE_HI 0x00 -#define CPIA2_SYSTEM_DEVICE_LO 0x01 - -#define CPIA2_SYSTEM_SYSTEM_CONTROL 0x02 -#define CPIA2_SYSTEM_CONTROL_LOW_POWER 0x00 -#define CPIA2_SYSTEM_CONTROL_HIGH_POWER 0x01 -#define CPIA2_SYSTEM_CONTROL_SUSPEND 0x02 -#define CPIA2_SYSTEM_CONTROL_V2W_ERR 0x10 -#define CPIA2_SYSTEM_CONTROL_RB_ERR 0x10 -#define CPIA2_SYSTEM_CONTROL_CLEAR_ERR 0x80 - -#define CPIA2_SYSTEM_INT_PACKET_CTRL 0x04 -#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX 0x01 -#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_EOF 0x02 -#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_INT1 0x04 - -#define CPIA2_SYSTEM_CACHE_CTRL 0x05 -#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_RESET 0x01 -#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_FLUSH 0x02 - -#define CPIA2_SYSTEM_SERIAL_CTRL 0x06 -#define CPIA2_SYSTEM_SERIAL_CTRL_NULL_CMD 0x00 -#define CPIA2_SYSTEM_SERIAL_CTRL_START_CMD 0x01 -#define CPIA2_SYSTEM_SERIAL_CTRL_STOP_CMD 0x02 -#define CPIA2_SYSTEM_SERIAL_CTRL_WRITE_CMD 0x03 -#define CPIA2_SYSTEM_SERIAL_CTRL_READ_ACK_CMD 0x04 -#define CPIA2_SYSTEM_SERIAL_CTRL_READ_NACK_CMD 0x05 - -#define CPIA2_SYSTEM_SERIAL_DATA 0x07 - -#define CPIA2_SYSTEM_VP_SERIAL_ADDR 0x08 - -/*** - * I2C addresses for various devices in CPiA2 - ***/ -#define CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR 0x20 -#define CPIA2_SYSTEM_VP_SERIAL_ADDR_VP 0x88 -#define CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP 0x8A - -#define CPIA2_SYSTEM_SPARE_REG1 0x09 -#define CPIA2_SYSTEM_SPARE_REG2 0x0A -#define CPIA2_SYSTEM_SPARE_REG3 0x0B - -#define CPIA2_SYSTEM_MC_PORT_0 0x0C -#define CPIA2_SYSTEM_MC_PORT_1 0x0D -#define CPIA2_SYSTEM_MC_PORT_2 0x0E -#define CPIA2_SYSTEM_MC_PORT_3 0x0F - -#define CPIA2_SYSTEM_STATUS_PKT 0x20 -#define CPIA2_SYSTEM_STATUS_PKT_END 0x27 - -#define CPIA2_SYSTEM_DESCRIP_VID_HI 0x30 -#define CPIA2_SYSTEM_DESCRIP_VID_LO 0x31 -#define CPIA2_SYSTEM_DESCRIP_PID_HI 0x32 -#define CPIA2_SYSTEM_DESCRIP_PID_LO 0x33 - -#define CPIA2_SYSTEM_FW_VERSION_HI 0x34 -#define CPIA2_SYSTEM_FW_VERSION_LO 0x35 - -#define CPIA2_SYSTEM_CACHE_START_INDEX 0x80 -#define CPIA2_SYSTEM_CACHE_MAX_WRITES 0x10 - -/*** - * VC register set (Bank 1) - ***/ -#define CPIA2_VC_ASIC_ID 0x80 - -#define CPIA2_VC_ASIC_REV 0x81 - -#define CPIA2_VC_PW_CTRL 0x82 -#define CPIA2_VC_PW_CTRL_COLDSTART 0x01 -#define CPIA2_VC_PW_CTRL_CP_CLK_EN 0x02 -#define CPIA2_VC_PW_CTRL_VP_RESET_N 0x04 -#define CPIA2_VC_PW_CTRL_VC_CLK_EN 0x08 -#define CPIA2_VC_PW_CTRL_VC_RESET_N 0x10 -#define CPIA2_VC_PW_CTRL_GOTO_SUSPEND 0x20 -#define CPIA2_VC_PW_CTRL_UDC_SUSPEND 0x40 -#define CPIA2_VC_PW_CTRL_PWR_DOWN 0x80 - -#define CPIA2_VC_WAKEUP 0x83 -#define CPIA2_VC_WAKEUP_SW_ENABLE 0x01 -#define CPIA2_VC_WAKEUP_XX_ENABLE 0x02 -#define CPIA2_VC_WAKEUP_SW_ATWAKEUP 0x04 -#define CPIA2_VC_WAKEUP_XX_ATWAKEUP 0x08 - -#define CPIA2_VC_CLOCK_CTRL 0x84 -#define CPIA2_VC_CLOCK_CTRL_TESTUP72 0x01 - -#define CPIA2_VC_INT_ENABLE 0x88 -#define CPIA2_VC_INT_ENABLE_XX_IE 0x01 -#define CPIA2_VC_INT_ENABLE_SW_IE 0x02 -#define CPIA2_VC_INT_ENABLE_VC_IE 0x04 -#define CPIA2_VC_INT_ENABLE_USBDATA_IE 0x08 -#define CPIA2_VC_INT_ENABLE_USBSETUP_IE 0x10 -#define CPIA2_VC_INT_ENABLE_USBCFG_IE 0x20 - -#define CPIA2_VC_INT_FLAG 0x89 -#define CPIA2_VC_INT_ENABLE_XX_FLAG 0x01 -#define CPIA2_VC_INT_ENABLE_SW_FLAG 0x02 -#define CPIA2_VC_INT_ENABLE_VC_FLAG 0x04 -#define CPIA2_VC_INT_ENABLE_USBDATA_FLAG 0x08 -#define CPIA2_VC_INT_ENABLE_USBSETUP_FLAG 0x10 -#define CPIA2_VC_INT_ENABLE_USBCFG_FLAG 0x20 -#define CPIA2_VC_INT_ENABLE_SET_RESET_BIT 0x80 - -#define CPIA2_VC_INT_STATE 0x8A -#define CPIA2_VC_INT_STATE_XX_STATE 0x01 -#define CPIA2_VC_INT_STATE_SW_STATE 0x02 - -#define CPIA2_VC_MP_DIR 0x90 -#define CPIA2_VC_MP_DIR_INPUT 0x00 -#define CPIA2_VC_MP_DIR_OUTPUT 0x01 - -#define CPIA2_VC_MP_DATA 0x91 - -#define CPIA2_VC_DP_CTRL 0x98 -#define CPIA2_VC_DP_CTRL_MODE_0 0x00 -#define CPIA2_VC_DP_CTRL_MODE_A 0x01 -#define CPIA2_VC_DP_CTRL_MODE_B 0x02 -#define CPIA2_VC_DP_CTRL_MODE_C 0x03 -#define CPIA2_VC_DP_CTRL_FAKE_FST 0x04 - -#define CPIA2_VC_AD_CTRL 0x99 -#define CPIA2_VC_AD_CTRL_SRC_0 0x00 -#define CPIA2_VC_AD_CTRL_SRC_DIGI_A 0x01 -#define CPIA2_VC_AD_CTRL_SRC_REG 0x02 -#define CPIA2_VC_AD_CTRL_DST_USB 0x00 -#define CPIA2_VC_AD_CTRL_DST_REG 0x04 - -#define CPIA2_VC_AD_TEST_IN 0x9B - -#define CPIA2_VC_AD_TEST_OUT 0x9C - -#define CPIA2_VC_AD_STATUS 0x9D -#define CPIA2_VC_AD_STATUS_EMPTY 0x01 -#define CPIA2_VC_AD_STATUS_FULL 0x02 - -#define CPIA2_VC_DP_DATA 0x9E - -#define CPIA2_VC_ST_CTRL 0xA0 -#define CPIA2_VC_ST_CTRL_SRC_VC 0x00 -#define CPIA2_VC_ST_CTRL_SRC_DP 0x01 -#define CPIA2_VC_ST_CTRL_SRC_REG 0x02 - -#define CPIA2_VC_ST_CTRL_RAW_SELECT 0x04 - -#define CPIA2_VC_ST_CTRL_DST_USB 0x00 -#define CPIA2_VC_ST_CTRL_DST_DP 0x08 -#define CPIA2_VC_ST_CTRL_DST_REG 0x10 - -#define CPIA2_VC_ST_CTRL_FIFO_ENABLE 0x20 -#define CPIA2_VC_ST_CTRL_EOF_DETECT 0x40 - -#define CPIA2_VC_ST_TEST 0xA1 -#define CPIA2_VC_ST_TEST_MODE_MANUAL 0x00 -#define CPIA2_VC_ST_TEST_MODE_INCREMENT 0x02 - -#define CPIA2_VC_ST_TEST_AUTO_FILL 0x08 - -#define CPIA2_VC_ST_TEST_REPEAT_FIFO 0x10 - -#define CPIA2_VC_ST_TEST_IN 0xA2 - -#define CPIA2_VC_ST_TEST_OUT 0xA3 - -#define CPIA2_VC_ST_STATUS 0xA4 -#define CPIA2_VC_ST_STATUS_EMPTY 0x01 -#define CPIA2_VC_ST_STATUS_FULL 0x02 - -#define CPIA2_VC_ST_FRAME_DETECT_1 0xA5 - -#define CPIA2_VC_ST_FRAME_DETECT_2 0xA6 - -#define CPIA2_VC_USB_CTRL 0xA8 -#define CPIA2_VC_USB_CTRL_CMD_STALLED 0x01 -#define CPIA2_VC_USB_CTRL_CMD_READY 0x02 -#define CPIA2_VC_USB_CTRL_CMD_STATUS 0x04 -#define CPIA2_VC_USB_CTRL_CMD_STATUS_DIR 0x08 -#define CPIA2_VC_USB_CTRL_CMD_NO_CLASH 0x10 -#define CPIA2_VC_USB_CTRL_CMD_MICRO_ACCESS 0x80 - -#define CPIA2_VC_USB_STRM 0xA9 -#define CPIA2_VC_USB_STRM_ISO_ENABLE 0x01 -#define CPIA2_VC_USB_STRM_BLK_ENABLE 0x02 -#define CPIA2_VC_USB_STRM_INT_ENABLE 0x04 -#define CPIA2_VC_USB_STRM_AUD_ENABLE 0x08 - -#define CPIA2_VC_USB_STATUS 0xAA -#define CPIA2_VC_USB_STATUS_CMD_IN_PROGRESS 0x01 -#define CPIA2_VC_USB_STATUS_CMD_STATUS_STALL 0x02 -#define CPIA2_VC_USB_STATUS_CMD_HANDSHAKE 0x04 -#define CPIA2_VC_USB_STATUS_CMD_OVERRIDE 0x08 -#define CPIA2_VC_USB_STATUS_CMD_FIFO_BUSY 0x10 -#define CPIA2_VC_USB_STATUS_BULK_REPEAT_TXN 0x20 -#define CPIA2_VC_USB_STATUS_CONFIG_DONE 0x40 -#define CPIA2_VC_USB_STATUS_USB_SUSPEND 0x80 - -#define CPIA2_VC_USB_CMDW 0xAB - -#define CPIA2_VC_USB_DATARW 0xAC - -#define CPIA2_VC_USB_INFO 0xAD - -#define CPIA2_VC_USB_CONFIG 0xAE - -#define CPIA2_VC_USB_SETTINGS 0xAF -#define CPIA2_VC_USB_SETTINGS_CONFIG_MASK 0x03 -#define CPIA2_VC_USB_SETTINGS_INTERFACE_MASK 0x0C -#define CPIA2_VC_USB_SETTINGS_ALTERNATE_MASK 0x70 - -#define CPIA2_VC_USB_ISOLIM 0xB0 - -#define CPIA2_VC_USB_ISOFAILS 0xB1 - -#define CPIA2_VC_USB_ISOMAXPKTHI 0xB2 - -#define CPIA2_VC_USB_ISOMAXPKTLO 0xB3 - -#define CPIA2_VC_V2W_CTRL 0xB8 -#define CPIA2_VC_V2W_SELECT 0x01 - -#define CPIA2_VC_V2W_SCL 0xB9 - -#define CPIA2_VC_V2W_SDA 0xBA - -#define CPIA2_VC_VC_CTRL 0xC0 -#define CPIA2_VC_VC_CTRL_RUN 0x01 -#define CPIA2_VC_VC_CTRL_SINGLESHOT 0x02 -#define CPIA2_VC_VC_CTRL_IDLING 0x04 -#define CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES 0x10 -#define CPIA2_VC_VC_CTRL_INHIBIT_Q_TABLES 0x20 -#define CPIA2_VC_VC_CTRL_INHIBIT_PRIVATE 0x40 - -#define CPIA2_VC_VC_RESTART_IVAL_HI 0xC1 - -#define CPIA2_VC_VC_RESTART_IVAL_LO 0xC2 - -#define CPIA2_VC_VC_FORMAT 0xC3 -#define CPIA2_VC_VC_FORMAT_UFIRST 0x01 -#define CPIA2_VC_VC_FORMAT_MONO 0x02 -#define CPIA2_VC_VC_FORMAT_DECIMATING 0x04 -#define CPIA2_VC_VC_FORMAT_SHORTLINE 0x08 -#define CPIA2_VC_VC_FORMAT_SELFTEST 0x10 - -#define CPIA2_VC_VC_CLOCKS 0xC4 -#define CPIA2_VC_VC_CLOCKS_CLKDIV_MASK 0x03 -#define CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 0x04 -#define CPIA2_VC_VC_672_CLOCKS_SCALING 0x08 -#define CPIA2_VC_VC_CLOCKS_LOGDIV0 0x00 -#define CPIA2_VC_VC_CLOCKS_LOGDIV1 0x01 -#define CPIA2_VC_VC_CLOCKS_LOGDIV2 0x02 -#define CPIA2_VC_VC_CLOCKS_LOGDIV3 0x03 -#define CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 0x08 -#define CPIA2_VC_VC_676_CLOCKS_SCALING 0x10 - -#define CPIA2_VC_VC_IHSIZE_LO 0xC5 - -#define CPIA2_VC_VC_XLIM_HI 0xC6 - -#define CPIA2_VC_VC_XLIM_LO 0xC7 - -#define CPIA2_VC_VC_YLIM_HI 0xC8 - -#define CPIA2_VC_VC_YLIM_LO 0xC9 - -#define CPIA2_VC_VC_OHSIZE 0xCA - -#define CPIA2_VC_VC_OVSIZE 0xCB - -#define CPIA2_VC_VC_HCROP 0xCC - -#define CPIA2_VC_VC_VCROP 0xCD - -#define CPIA2_VC_VC_HPHASE 0xCE - -#define CPIA2_VC_VC_VPHASE 0xCF - -#define CPIA2_VC_VC_HISPAN 0xD0 - -#define CPIA2_VC_VC_VISPAN 0xD1 - -#define CPIA2_VC_VC_HICROP 0xD2 - -#define CPIA2_VC_VC_VICROP 0xD3 - -#define CPIA2_VC_VC_HFRACT 0xD4 -#define CPIA2_VC_VC_HFRACT_DEN_MASK 0x0F -#define CPIA2_VC_VC_HFRACT_NUM_MASK 0xF0 - -#define CPIA2_VC_VC_VFRACT 0xD5 -#define CPIA2_VC_VC_VFRACT_DEN_MASK 0x0F -#define CPIA2_VC_VC_VFRACT_NUM_MASK 0xF0 - -#define CPIA2_VC_VC_JPEG_OPT 0xD6 -#define CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE 0x01 -#define CPIA2_VC_VC_JPEG_OPT_NO_DC_AUTO_SQUEEZE 0x02 -#define CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE 0x04 -#define CPIA2_VC_VC_JPEG_OPT_DEFAULT (CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE|\ - CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE) - - -#define CPIA2_VC_VC_CREEP_PERIOD 0xD7 -#define CPIA2_VC_VC_USER_SQUEEZE 0xD8 -#define CPIA2_VC_VC_TARGET_KB 0xD9 - -#define CPIA2_VC_VC_AUTO_SQUEEZE 0xE6 - - -/*** - * VP register set (Bank 2) - ***/ -#define CPIA2_VP_DEVICEH 0 -#define CPIA2_VP_DEVICEL 1 - -#define CPIA2_VP_SYSTEMSTATE 0x02 -#define CPIA2_VP_SYSTEMSTATE_HK_ALIVE 0x01 - -#define CPIA2_VP_SYSTEMCTRL 0x03 -#define CPIA2_VP_SYSTEMCTRL_REQ_CLEAR_ERROR 0x80 -#define CPIA2_VP_SYSTEMCTRL_POWER_DOWN_PLL 0x20 -#define CPIA2_VP_SYSTEMCTRL_REQ_SUSPEND_STATE 0x10 -#define CPIA2_VP_SYSTEMCTRL_REQ_SERIAL_WAKEUP 0x08 -#define CPIA2_VP_SYSTEMCTRL_REQ_AUTOLOAD 0x04 -#define CPIA2_VP_SYSTEMCTRL_HK_CONTROL 0x02 -#define CPIA2_VP_SYSTEMCTRL_POWER_CONTROL 0x01 - -#define CPIA2_VP_SENSOR_FLAGS 0x05 -#define CPIA2_VP_SENSOR_FLAGS_404 0x01 -#define CPIA2_VP_SENSOR_FLAGS_407 0x02 -#define CPIA2_VP_SENSOR_FLAGS_409 0x04 -#define CPIA2_VP_SENSOR_FLAGS_410 0x08 -#define CPIA2_VP_SENSOR_FLAGS_500 0x10 - -#define CPIA2_VP_SENSOR_REV 0x06 - -#define CPIA2_VP_DEVICE_CONFIG 0x07 -#define CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE 0x01 - -#define CPIA2_VP_GPIO_DIRECTION 0x08 -#define CPIA2_VP_GPIO_READ 0xFF -#define CPIA2_VP_GPIO_WRITE 0x00 - -#define CPIA2_VP_GPIO_DATA 0x09 - -#define CPIA2_VP_RAM_ADDR_H 0x0A -#define CPIA2_VP_RAM_ADDR_L 0x0B -#define CPIA2_VP_RAM_DATA 0x0C - -#define CPIA2_VP_PATCH_REV 0x0F - -#define CPIA2_VP4_USER_MODE 0x10 -#define CPIA2_VP5_USER_MODE 0x13 -#define CPIA2_VP_USER_MODE_CIF 0x01 -#define CPIA2_VP_USER_MODE_QCIFDS 0x02 -#define CPIA2_VP_USER_MODE_QCIFPTC 0x04 -#define CPIA2_VP_USER_MODE_QVGADS 0x08 -#define CPIA2_VP_USER_MODE_QVGAPTC 0x10 -#define CPIA2_VP_USER_MODE_VGA 0x20 - -#define CPIA2_VP4_FRAMERATE_REQUEST 0x11 -#define CPIA2_VP5_FRAMERATE_REQUEST 0x14 -#define CPIA2_VP_FRAMERATE_60 0x80 -#define CPIA2_VP_FRAMERATE_50 0x40 -#define CPIA2_VP_FRAMERATE_30 0x20 -#define CPIA2_VP_FRAMERATE_25 0x10 -#define CPIA2_VP_FRAMERATE_15 0x08 -#define CPIA2_VP_FRAMERATE_12_5 0x04 -#define CPIA2_VP_FRAMERATE_7_5 0x02 -#define CPIA2_VP_FRAMERATE_6_25 0x01 - -#define CPIA2_VP4_USER_EFFECTS 0x12 -#define CPIA2_VP5_USER_EFFECTS 0x15 -#define CPIA2_VP_USER_EFFECTS_COLBARS 0x01 -#define CPIA2_VP_USER_EFFECTS_COLBARS_GRAD 0x02 -#define CPIA2_VP_USER_EFFECTS_MIRROR 0x04 -#define CPIA2_VP_USER_EFFECTS_FLIP 0x40 // VP5 only - -/* NOTE: CPIA2_VP_EXPOSURE_MODES shares the same register as VP5 User - * Effects */ -#define CPIA2_VP_EXPOSURE_MODES 0x15 -#define CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER 0x20 -#define CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP 0x10 - -#define CPIA2_VP4_EXPOSURE_TARGET 0x16 // VP4 -#define CPIA2_VP5_EXPOSURE_TARGET 0x20 // VP5 - -#define CPIA2_VP_FLICKER_MODES 0x1B -#define CPIA2_VP_FLICKER_MODES_50HZ 0x80 -#define CPIA2_VP_FLICKER_MODES_CUSTOM_FLT_FFREQ 0x40 -#define CPIA2_VP_FLICKER_MODES_NEVER_FLICKER 0x20 -#define CPIA2_VP_FLICKER_MODES_INHIBIT_RUB 0x10 -#define CPIA2_VP_FLICKER_MODES_ADJUST_LINE_FREQ 0x08 -#define CPIA2_VP_FLICKER_MODES_CUSTOM_INT_FFREQ 0x04 - -#define CPIA2_VP_UMISC 0x1D -#define CPIA2_VP_UMISC_FORCE_MONO 0x80 -#define CPIA2_VP_UMISC_FORCE_ID_MASK 0x40 -#define CPIA2_VP_UMISC_INHIBIT_AUTO_FGS 0x20 -#define CPIA2_VP_UMISC_INHIBIT_AUTO_DIMS 0x08 -#define CPIA2_VP_UMISC_OPT_FOR_SENSOR_DS 0x04 -#define CPIA2_VP_UMISC_INHIBIT_AUTO_MODE_INT 0x02 - -#define CPIA2_VP5_ANTIFLKRSETUP 0x22 //34 - -#define CPIA2_VP_INTERPOLATION 0x24 -#define CPIA2_VP_INTERPOLATION_EVEN_FIRST 0x40 -#define CPIA2_VP_INTERPOLATION_HJOG 0x20 -#define CPIA2_VP_INTERPOLATION_VJOG 0x10 - -#define CPIA2_VP_GAMMA 0x25 -#define CPIA2_VP_DEFAULT_GAMMA 0x10 - -#define CPIA2_VP_YRANGE 0x26 - -#define CPIA2_VP_SATURATION 0x27 - -#define CPIA2_VP5_MYBLACK_LEVEL 0x3A //58 -#define CPIA2_VP5_MCYRANGE 0x3B //59 -#define CPIA2_VP5_MYCEILING 0x3C //60 -#define CPIA2_VP5_MCUVSATURATION 0x3D //61 - - -#define CPIA2_VP_REHASH_VALUES 0x60 - - -/*** - * Common sensor registers - ***/ -#define CPIA2_SENSOR_DEVICE_H 0x00 -#define CPIA2_SENSOR_DEVICE_L 0x01 - -#define CPIA2_SENSOR_DATA_FORMAT 0x16 -#define CPIA2_SENSOR_DATA_FORMAT_HMIRROR 0x08 -#define CPIA2_SENSOR_DATA_FORMAT_VMIRROR 0x10 - -#define CPIA2_SENSOR_CR1 0x76 -#define CPIA2_SENSOR_CR1_STAND_BY 0x01 -#define CPIA2_SENSOR_CR1_DOWN_RAMP_GEN 0x02 -#define CPIA2_SENSOR_CR1_DOWN_COLUMN_ADC 0x04 -#define CPIA2_SENSOR_CR1_DOWN_CAB_REGULATOR 0x08 -#define CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR 0x10 -#define CPIA2_SENSOR_CR1_DOWN_VRT_AMP 0x20 -#define CPIA2_SENSOR_CR1_DOWN_BAND_GAP 0x40 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_usb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_usb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_usb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_usb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,914 +0,0 @@ -/**************************************************************************** - * - * Filename: cpia2_usb.c - * - * Copyright 2001, STMicrolectronics, Inc. - * Contact: steve.miller@st.com - * - * Description: - * This is a USB driver for CPia2 based video cameras. - * The infrastructure of this driver is based on the cpia usb driver by - * Jochen Scharrlach and Johannes Erdfeldt. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Stripped of 2.4 stuff ready for main kernel submit by - * Alan Cox - ****************************************************************************/ - -#include -#include -#include - -#include "cpia2.h" - -static int frame_sizes[] = { - 0, // USBIF_CMDONLY - 0, // USBIF_BULK - 128, // USBIF_ISO_1 - 384, // USBIF_ISO_2 - 640, // USBIF_ISO_3 - 768, // USBIF_ISO_4 - 896, // USBIF_ISO_5 - 1023, // USBIF_ISO_6 -}; - -#define FRAMES_PER_DESC 10 -#define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt] - -static void process_frame(struct camera_data *cam); -static void cpia2_usb_complete(struct urb *urb); -static int cpia2_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void cpia2_usb_disconnect(struct usb_interface *intf); - -static void free_sbufs(struct camera_data *cam); -static void add_APPn(struct camera_data *cam); -static void add_COM(struct camera_data *cam); -static int submit_urbs(struct camera_data *cam); -static int set_alternate(struct camera_data *cam, unsigned int alt); -static int configure_transfer_mode(struct camera_data *cam, unsigned int alt); - -static struct usb_device_id cpia2_id_table[] = { - {USB_DEVICE(0x0553, 0x0100)}, - {USB_DEVICE(0x0553, 0x0140)}, - {USB_DEVICE(0x0553, 0x0151)}, /* STV0676 */ - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, cpia2_id_table); - -static struct usb_driver cpia2_driver = { - .name = "cpia2", - .probe = cpia2_usb_probe, - .disconnect = cpia2_usb_disconnect, - .id_table = cpia2_id_table -}; - - -/****************************************************************************** - * - * process_frame - * - *****************************************************************************/ -static void process_frame(struct camera_data *cam) -{ - static int frame_count; - - unsigned char *inbuff = cam->workbuff->data; - - DBG("Processing frame #%d, current:%d\n", - cam->workbuff->num, cam->curbuff->num); - - if(cam->workbuff->length > cam->workbuff->max_length) - cam->workbuff->max_length = cam->workbuff->length; - - if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) { - frame_count++; - } else { - cam->workbuff->status = FRAME_ERROR; - DBG("Start of frame not found\n"); - return; - } - - /*** - * Now the output buffer should have a JPEG image in it. - ***/ - if(!cam->first_image_seen) { - /* Always skip the first image after streaming - * starts. It is almost certainly corrupt. */ - cam->first_image_seen = 1; - cam->workbuff->status = FRAME_EMPTY; - return; - } - if (cam->workbuff->length > 3) { - if(cam->mmapped && - cam->workbuff->length < cam->workbuff->max_length) { - /* No junk in the buffers */ - memset(cam->workbuff->data+cam->workbuff->length, - 0, cam->workbuff->max_length- - cam->workbuff->length); - } - cam->workbuff->max_length = cam->workbuff->length; - cam->workbuff->status = FRAME_READY; - - if(!cam->mmapped && cam->num_frames > 2) { - /* During normal reading, the most recent - * frame will be read. If the current frame - * hasn't started reading yet, it will never - * be read, so mark it empty. If the buffer is - * mmapped, or we have few buffers, we need to - * wait for the user to free the buffer. - * - * NOTE: This is not entirely foolproof with 3 - * buffers, but it would take an EXTREMELY - * overloaded system to cause problems (possible - * image data corruption). Basically, it would - * need to take more time to execute cpia2_read - * than it would for the camera to send - * cam->num_frames-2 frames before problems - * could occur. - */ - cam->curbuff->status = FRAME_EMPTY; - } - cam->curbuff = cam->workbuff; - cam->workbuff = cam->workbuff->next; - DBG("Changed buffers, work:%d, current:%d\n", - cam->workbuff->num, cam->curbuff->num); - return; - } else { - DBG("Not enough data for an image.\n"); - } - - cam->workbuff->status = FRAME_ERROR; - return; -} - -/****************************************************************************** - * - * add_APPn - * - * Adds a user specified APPn record - *****************************************************************************/ -static void add_APPn(struct camera_data *cam) -{ - if(cam->APP_len > 0) { - cam->workbuff->data[cam->workbuff->length++] = 0xFF; - cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn; - cam->workbuff->data[cam->workbuff->length++] = 0; - cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2; - memcpy(cam->workbuff->data+cam->workbuff->length, - cam->APP_data, cam->APP_len); - cam->workbuff->length += cam->APP_len; - } -} - -/****************************************************************************** - * - * add_COM - * - * Adds a user specified COM record - *****************************************************************************/ -static void add_COM(struct camera_data *cam) -{ - if(cam->COM_len > 0) { - cam->workbuff->data[cam->workbuff->length++] = 0xFF; - cam->workbuff->data[cam->workbuff->length++] = 0xFE; - cam->workbuff->data[cam->workbuff->length++] = 0; - cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2; - memcpy(cam->workbuff->data+cam->workbuff->length, - cam->COM_data, cam->COM_len); - cam->workbuff->length += cam->COM_len; - } -} - -/****************************************************************************** - * - * cpia2_usb_complete - * - * callback when incoming packet is received - *****************************************************************************/ -static void cpia2_usb_complete(struct urb *urb) -{ - int i; - unsigned char *cdata; - static int frame_ready = false; - struct camera_data *cam = (struct camera_data *) urb->context; - - if (urb->status!=0) { - if (!(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN)) - { - DBG("urb->status = %d!\n", urb->status); - } - DBG("Stopping streaming\n"); - return; - } - - if (!cam->streaming || !cam->present || cam->open_count == 0) { - LOG("Will now stop the streaming: streaming = %d, " - "present=%d, open_count=%d\n", - cam->streaming, cam->present, cam->open_count); - return; - } - - /*** - * Packet collater - ***/ - //DBG("Collating %d packets\n", urb->number_of_packets); - for (i = 0; i < urb->number_of_packets; i++) { - u16 checksum, iso_checksum; - int j; - int n = urb->iso_frame_desc[i].actual_length; - int st = urb->iso_frame_desc[i].status; - - if(cam->workbuff->status == FRAME_READY) { - struct framebuf *ptr; - /* Try to find an available buffer */ - DBG("workbuff full, searching\n"); - for (ptr = cam->workbuff->next; - ptr != cam->workbuff; - ptr = ptr->next) - { - if (ptr->status == FRAME_EMPTY) { - ptr->status = FRAME_READING; - ptr->length = 0; - break; - } - } - if (ptr == cam->workbuff) - break; /* No READING or EMPTY buffers left */ - - cam->workbuff = ptr; - } - - if (cam->workbuff->status == FRAME_EMPTY || - cam->workbuff->status == FRAME_ERROR) { - cam->workbuff->status = FRAME_READING; - cam->workbuff->length = 0; - } - - //DBG(" Packet %d length = %d, status = %d\n", i, n, st); - cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - if (st) { - LOG("cpia2 data error: [%d] len=%d, status = %d\n", - i, n, st); - if(!ALLOW_CORRUPT) - cam->workbuff->status = FRAME_ERROR; - continue; - } - - if(n<=2) - continue; - - checksum = 0; - for(j=0; jworkbuff->status = FRAME_ERROR; - continue; - } - } - n -= 2; - - if(cam->workbuff->status != FRAME_READING) { - if((0xFF == cdata[0] && 0xD8 == cdata[1]) || - (0xD8 == cdata[0] && 0xFF == cdata[1] && - 0 != cdata[2])) { - /* frame is skipped, but increment total - * frame count anyway */ - cam->frame_count++; - } - DBG("workbuff not reading, status=%d\n", - cam->workbuff->status); - continue; - } - - if (cam->frame_size < cam->workbuff->length + n) { - ERR("buffer overflow! length: %d, n: %d\n", - cam->workbuff->length, n); - cam->workbuff->status = FRAME_ERROR; - if(cam->workbuff->length > cam->workbuff->max_length) - cam->workbuff->max_length = - cam->workbuff->length; - continue; - } - - if (cam->workbuff->length == 0) { - int data_offset; - if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) { - data_offset = 1; - } else if((0xFF == cdata[0]) && (0xD8 == cdata[1]) - && (0xFF == cdata[2])) { - data_offset = 2; - } else { - DBG("Ignoring packet, not beginning!\n"); - continue; - } - DBG("Start of frame pattern found\n"); - do_gettimeofday(&cam->workbuff->timestamp); - cam->workbuff->seq = cam->frame_count++; - cam->workbuff->data[0] = 0xFF; - cam->workbuff->data[1] = 0xD8; - cam->workbuff->length = 2; - add_APPn(cam); - add_COM(cam); - memcpy(cam->workbuff->data+cam->workbuff->length, - cdata+data_offset, n-data_offset); - cam->workbuff->length += n-data_offset; - } else if (cam->workbuff->length > 0) { - memcpy(cam->workbuff->data + cam->workbuff->length, - cdata, n); - cam->workbuff->length += n; - } - - if ((cam->workbuff->length >= 3) && - (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) && - (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) && - (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) { - frame_ready = true; - cam->workbuff->data[cam->workbuff->length - 1] = 0; - cam->workbuff->length -= 1; - } else if ((cam->workbuff->length >= 2) && - (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) && - (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) { - frame_ready = true; - } - - if (frame_ready) { - DBG("Workbuff image size = %d\n",cam->workbuff->length); - process_frame(cam); - - frame_ready = false; - - if (waitqueue_active(&cam->wq_stream)) - wake_up_interruptible(&cam->wq_stream); - } - } - - if(cam->streaming) { - /* resubmit */ - urb->dev = cam->dev; - if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) - ERR("%s: usb_submit_urb ret %d!\n", __func__, i); - } -} - -/****************************************************************************** - * - * configure_transfer_mode - * - *****************************************************************************/ -static int configure_transfer_mode(struct camera_data *cam, unsigned int alt) -{ - static unsigned char iso_regs[8][4] = { - {0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00}, - {0xB9, 0x00, 0x00, 0x7E}, - {0xB9, 0x00, 0x01, 0x7E}, - {0xB9, 0x00, 0x02, 0x7E}, - {0xB9, 0x00, 0x02, 0xFE}, - {0xB9, 0x00, 0x03, 0x7E}, - {0xB9, 0x00, 0x03, 0xFD} - }; - struct cpia2_command cmd; - unsigned char reg; - - if(!cam->present) - return -ENODEV; - - /*** - * Write the isoc registers according to the alternate selected - ***/ - cmd.direction = TRANSFER_WRITE; - cmd.buffer.block_data[0] = iso_regs[alt][0]; - cmd.buffer.block_data[1] = iso_regs[alt][1]; - cmd.buffer.block_data[2] = iso_regs[alt][2]; - cmd.buffer.block_data[3] = iso_regs[alt][3]; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.start = CPIA2_VC_USB_ISOLIM; - cmd.reg_count = 4; - cpia2_send_command(cam, &cmd); - - /*** - * Enable relevant streams before starting polling. - * First read USB Stream Config Register. - ***/ - cmd.direction = TRANSFER_READ; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.start = CPIA2_VC_USB_STRM; - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - reg = cmd.buffer.block_data[0]; - - /* Clear iso, bulk, and int */ - reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE | - CPIA2_VC_USB_STRM_ISO_ENABLE | - CPIA2_VC_USB_STRM_INT_ENABLE); - - if (alt == USBIF_BULK) { - DBG("Enabling bulk xfer\n"); - reg |= CPIA2_VC_USB_STRM_BLK_ENABLE; /* Enable Bulk */ - cam->xfer_mode = XFER_BULK; - } else if (alt >= USBIF_ISO_1) { - DBG("Enabling ISOC xfer\n"); - reg |= CPIA2_VC_USB_STRM_ISO_ENABLE; - cam->xfer_mode = XFER_ISOC; - } - - cmd.buffer.block_data[0] = reg; - cmd.direction = TRANSFER_WRITE; - cmd.start = CPIA2_VC_USB_STRM; - cmd.reg_count = 1; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cpia2_send_command(cam, &cmd); - - return 0; -} - -/****************************************************************************** - * - * cpia2_usb_change_streaming_alternate - * - *****************************************************************************/ -int cpia2_usb_change_streaming_alternate(struct camera_data *cam, - unsigned int alt) -{ - int ret = 0; - - if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6) - return -EINVAL; - - if(alt == cam->params.camera_state.stream_mode) - return 0; - - cpia2_usb_stream_pause(cam); - - configure_transfer_mode(cam, alt); - - cam->params.camera_state.stream_mode = alt; - - /* Reset the camera to prevent image quality degradation */ - cpia2_reset_camera(cam); - - cpia2_usb_stream_resume(cam); - - return ret; -} - -/****************************************************************************** - * - * set_alternate - * - *****************************************************************************/ -static int set_alternate(struct camera_data *cam, unsigned int alt) -{ - int ret = 0; - - if(alt == cam->cur_alt) - return 0; - - if (cam->cur_alt != USBIF_CMDONLY) { - DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY); - ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY); - if (ret != 0) - return ret; - } - if (alt != USBIF_CMDONLY) { - DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt); - ret = usb_set_interface(cam->dev, cam->iface, alt); - if (ret != 0) - return ret; - } - - cam->old_alt = cam->cur_alt; - cam->cur_alt = alt; - - return ret; -} - -/****************************************************************************** - * - * free_sbufs - * - * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL - * are assumed to be allocated. Non-NULL .urb members are also assumed to be - * submitted (and must therefore be killed before they are freed). - *****************************************************************************/ -static void free_sbufs(struct camera_data *cam) -{ - int i; - - for (i = 0; i < NUM_SBUF; i++) { - if(cam->sbuf[i].urb) { - usb_kill_urb(cam->sbuf[i].urb); - usb_free_urb(cam->sbuf[i].urb); - cam->sbuf[i].urb = NULL; - } - if(cam->sbuf[i].data) { - kfree(cam->sbuf[i].data); - cam->sbuf[i].data = NULL; - } - } -} - -/******* -* Convenience functions -*******/ -/**************************************************************************** - * - * write_packet - * - ***************************************************************************/ -static int write_packet(struct usb_device *udev, - u8 request, u8 * registers, u16 start, size_t size) -{ - if (!registers || size <= 0) - return -EINVAL; - - return usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - start, /* value */ - 0, /* index */ - registers, /* buffer */ - size, - HZ); -} - -/**************************************************************************** - * - * read_packet - * - ***************************************************************************/ -static int read_packet(struct usb_device *udev, - u8 request, u8 * registers, u16 start, size_t size) -{ - if (!registers || size <= 0) - return -EINVAL; - - return usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - request, - USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE, - start, /* value */ - 0, /* index */ - registers, /* buffer */ - size, - HZ); -} - -/****************************************************************************** - * - * cpia2_usb_transfer_cmd - * - *****************************************************************************/ -int cpia2_usb_transfer_cmd(struct camera_data *cam, - void *registers, - u8 request, u8 start, u8 count, u8 direction) -{ - int err = 0; - struct usb_device *udev = cam->dev; - - if (!udev) { - ERR("%s: Internal driver error: udev is NULL\n", __func__); - return -EINVAL; - } - - if (!registers) { - ERR("%s: Internal driver error: register array is NULL\n", __func__); - return -EINVAL; - } - - if (direction == TRANSFER_READ) { - err = read_packet(udev, request, (u8 *)registers, start, count); - if (err > 0) - err = 0; - } else if (direction == TRANSFER_WRITE) { - err =write_packet(udev, request, (u8 *)registers, start, count); - if (err < 0) { - LOG("Control message failed, err val = %d\n", err); - LOG("Message: request = 0x%0X, start = 0x%0X\n", - request, start); - LOG("Message: count = %d, register[0] = 0x%0X\n", - count, ((unsigned char *) registers)[0]); - } else - err=0; - } else { - LOG("Unexpected first byte of direction: %d\n", - direction); - return -EINVAL; - } - - if(err != 0) - LOG("Unexpected error: %d\n", err); - return err; -} - - -/****************************************************************************** - * - * submit_urbs - * - *****************************************************************************/ -static int submit_urbs(struct camera_data *cam) -{ - struct urb *urb; - int fx, err, i, j; - - for(i=0; isbuf[i].data) - continue; - cam->sbuf[i].data = - kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); - if (!cam->sbuf[i].data) { - while (--i >= 0) { - kfree(cam->sbuf[i].data); - cam->sbuf[i].data = NULL; - } - return -ENOMEM; - } - } - - /* We double buffer the Isoc lists, and also know the polling - * interval is every frame (1 == (1 << (bInterval -1))). - */ - for(i=0; isbuf[i].urb) { - continue; - } - urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); - if (!urb) { - ERR("%s: usb_alloc_urb error!\n", __func__); - for (j = 0; j < i; j++) - usb_free_urb(cam->sbuf[j].urb); - return -ENOMEM; - } - - cam->sbuf[i].urb = urb; - urb->dev = cam->dev; - urb->context = cam; - urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = cam->sbuf[i].data; - urb->complete = cpia2_usb_complete; - urb->number_of_packets = FRAMES_PER_DESC; - urb->interval = 1; - urb->transfer_buffer_length = - FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; - - for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = - FRAME_SIZE_PER_DESC * fx; - urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; - } - } - - - /* Queue the ISO urbs, and resubmit in the completion handler */ - for(i=0; isbuf[i].urb, GFP_KERNEL); - if (err) { - ERR("usb_submit_urb[%d]() = %d\n", i, err); - return err; - } - } - - return 0; -} - -/****************************************************************************** - * - * cpia2_usb_stream_start - * - *****************************************************************************/ -int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate) -{ - int ret; - int old_alt; - - if(cam->streaming) - return 0; - - if (cam->flush) { - int i; - DBG("Flushing buffers\n"); - for(i=0; inum_frames; ++i) { - cam->buffers[i].status = FRAME_EMPTY; - cam->buffers[i].length = 0; - } - cam->curbuff = &cam->buffers[0]; - cam->workbuff = cam->curbuff->next; - cam->flush = false; - } - - old_alt = cam->params.camera_state.stream_mode; - cam->params.camera_state.stream_mode = 0; - ret = cpia2_usb_change_streaming_alternate(cam, alternate); - if (ret < 0) { - int ret2; - ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret); - cam->params.camera_state.stream_mode = old_alt; - ret2 = set_alternate(cam, USBIF_CMDONLY); - if (ret2 < 0) { - ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already " - "failed. Then tried to call " - "set_alternate(USBIF_CMDONLY) = %d.\n", - alternate, ret, ret2); - } - } else { - cam->frame_count = 0; - cam->streaming = 1; - ret = cpia2_usb_stream_resume(cam); - } - return ret; -} - -/****************************************************************************** - * - * cpia2_usb_stream_pause - * - *****************************************************************************/ -int cpia2_usb_stream_pause(struct camera_data *cam) -{ - int ret = 0; - if(cam->streaming) { - ret = set_alternate(cam, USBIF_CMDONLY); - free_sbufs(cam); - } - return ret; -} - -/****************************************************************************** - * - * cpia2_usb_stream_resume - * - *****************************************************************************/ -int cpia2_usb_stream_resume(struct camera_data *cam) -{ - int ret = 0; - if(cam->streaming) { - cam->first_image_seen = 0; - ret = set_alternate(cam, cam->params.camera_state.stream_mode); - if(ret == 0) { - ret = submit_urbs(cam); - } - } - return ret; -} - -/****************************************************************************** - * - * cpia2_usb_stream_stop - * - *****************************************************************************/ -int cpia2_usb_stream_stop(struct camera_data *cam) -{ - int ret; - ret = cpia2_usb_stream_pause(cam); - cam->streaming = 0; - configure_transfer_mode(cam, 0); - return ret; -} - -/****************************************************************************** - * - * cpia2_usb_probe - * - * Probe and initialize. - *****************************************************************************/ -static int cpia2_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_interface_descriptor *interface; - struct camera_data *cam; - int ret; - - /* A multi-config CPiA2 camera? */ - if (udev->descriptor.bNumConfigurations != 1) - return -ENODEV; - interface = &intf->cur_altsetting->desc; - - /* If we get to this point, we found a CPiA2 camera */ - LOG("CPiA2 USB camera found\n"); - - if((cam = cpia2_init_camera_struct()) == NULL) - return -ENOMEM; - - cam->dev = udev; - cam->iface = interface->bInterfaceNumber; - - ret = set_alternate(cam, USBIF_CMDONLY); - if (ret < 0) { - ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret); - kfree(cam); - return ret; - } - - if ((ret = cpia2_register_camera(cam)) < 0) { - ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret); - kfree(cam); - return ret; - } - - - if((ret = cpia2_init_camera(cam)) < 0) { - ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret); - cpia2_unregister_camera(cam); - kfree(cam); - return ret; - } - LOG(" CPiA Version: %d.%02d (%d.%d)\n", - cam->params.version.firmware_revision_hi, - cam->params.version.firmware_revision_lo, - cam->params.version.asic_id, - cam->params.version.asic_rev); - LOG(" CPiA PnP-ID: %04x:%04x:%04x\n", - cam->params.pnp_id.vendor, - cam->params.pnp_id.product, - cam->params.pnp_id.device_revision); - LOG(" SensorID: %d.(version %d)\n", - cam->params.version.sensor_flags, - cam->params.version.sensor_rev); - - usb_set_intfdata(intf, cam); - - return 0; -} - -/****************************************************************************** - * - * cpia2_disconnect - * - *****************************************************************************/ -static void cpia2_usb_disconnect(struct usb_interface *intf) -{ - struct camera_data *cam = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - cam->present = 0; - - DBG("Stopping stream\n"); - cpia2_usb_stream_stop(cam); - - DBG("Unregistering camera\n"); - cpia2_unregister_camera(cam); - - if(cam->buffers) { - DBG("Wakeup waiting processes\n"); - cam->curbuff->status = FRAME_READY; - cam->curbuff->length = 0; - if (waitqueue_active(&cam->wq_stream)) - wake_up_interruptible(&cam->wq_stream); - } - - DBG("Releasing interface\n"); - usb_driver_release_interface(&cpia2_driver, intf); - - if (cam->open_count == 0) { - DBG("Freeing camera structure\n"); - kfree(cam); - } - - LOG("CPiA2 camera disconnected.\n"); -} - - -/****************************************************************************** - * - * usb_cpia2_init - * - *****************************************************************************/ -int cpia2_usb_init(void) -{ - return usb_register(&cpia2_driver); -} - -/****************************************************************************** - * - * usb_cpia_cleanup - * - *****************************************************************************/ -void cpia2_usb_cleanup(void) -{ - schedule_timeout(2 * HZ); - usb_deregister(&cpia2_driver); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_v4l.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_v4l.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_v4l.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/cpia2_v4l.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1582 +0,0 @@ -/**************************************************************************** - * - * Filename: cpia2_v4l.c - * - * Copyright 2001, STMicrolectronics, Inc. - * Contact: steve.miller@st.com - * Copyright 2001,2005, Scott J. Bertin - * - * Description: - * This is a USB driver for CPia2 based video cameras. - * The infrastructure of this driver is based on the cpia usb driver by - * Jochen Scharrlach and Johannes Erdfeldt. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Stripped of 2.4 stuff ready for main kernel submit by - * Alan Cox - ****************************************************************************/ - -#include - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpia2.h" -#include "cpia2dev.h" - -static int video_nr = -1; -module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); - -static int buffer_size = 68*1024; -module_param(buffer_size, int, 0); -MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); - -static int num_buffers = 3; -module_param(num_buffers, int, 0); -MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" - __stringify(VIDEO_MAX_FRAME) ", default 3)"); - -static int alternate = DEFAULT_ALT; -module_param(alternate, int, 0); -MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-" - __stringify(USBIF_ISO_6) ", default " - __stringify(DEFAULT_ALT) ")"); - -static int flicker_freq = 60; -module_param(flicker_freq, int, 0); -MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" __stringify(50) "or" - __stringify(60) ", default " - __stringify(60) ")"); - -static int flicker_mode = NEVER_FLICKER; -module_param(flicker_mode, int, 0); -MODULE_PARM_DESC(flicker_mode, - "Flicker supression (" __stringify(NEVER_FLICKER) "or" - __stringify(ANTI_FLICKER_ON) ", default " - __stringify(NEVER_FLICKER) ")"); - -MODULE_AUTHOR("Steve Miller (STMicroelectronics) "); -MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); -MODULE_SUPPORTED_DEVICE("video"); -MODULE_LICENSE("GPL"); - -#define ABOUT "V4L-Driver for Vision CPiA2 based cameras" - -struct control_menu_info { - int value; - char name[32]; -}; - -static struct control_menu_info framerate_controls[] = -{ - { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" }, - { CPIA2_VP_FRAMERATE_7_5, "7.5 fps" }, - { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" }, - { CPIA2_VP_FRAMERATE_15, "15 fps" }, - { CPIA2_VP_FRAMERATE_25, "25 fps" }, - { CPIA2_VP_FRAMERATE_30, "30 fps" }, -}; -#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls)) - -static struct control_menu_info flicker_controls[] = -{ - { NEVER_FLICKER, "Off" }, - { FLICKER_50, "50 Hz" }, - { FLICKER_60, "60 Hz" }, -}; -#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls)) - -static struct control_menu_info lights_controls[] = -{ - { 0, "Off" }, - { 64, "Top" }, - { 128, "Bottom" }, - { 192, "Both" }, -}; -#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls)) -#define GPIO_LIGHTS_MASK 192 - -static struct v4l2_queryctrl controls[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = DEFAULT_BRIGHTNESS, - }, - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = DEFAULT_CONTRAST, - }, - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = DEFAULT_SATURATION, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = CPIA2_CID_TARGET_KB, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Target KB", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = DEFAULT_TARGET_KB, - }, - { - .id = CPIA2_CID_GPIO, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "GPIO", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0, - }, - { - .id = CPIA2_CID_FLICKER_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Flicker Reduction", - .minimum = 0, - .maximum = NUM_FLICKER_CONTROLS-1, - .step = 1, - .default_value = 0, - }, - { - .id = CPIA2_CID_FRAMERATE, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Framerate", - .minimum = 0, - .maximum = NUM_FRAMERATE_CONTROLS-1, - .step = 1, - .default_value = NUM_FRAMERATE_CONTROLS-1, - }, - { - .id = CPIA2_CID_USB_ALT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "USB Alternate", - .minimum = USBIF_ISO_1, - .maximum = USBIF_ISO_6, - .step = 1, - .default_value = DEFAULT_ALT, - }, - { - .id = CPIA2_CID_LIGHTS, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Lights", - .minimum = 0, - .maximum = NUM_LIGHTS_CONTROLS-1, - .step = 1, - .default_value = 0, - }, - { - .id = CPIA2_CID_RESET_CAMERA, - .type = V4L2_CTRL_TYPE_BUTTON, - .name = "Reset Camera", - .minimum = 0, - .maximum = 0, - .step = 0, - .default_value = 0, - }, -}; -#define NUM_CONTROLS (ARRAY_SIZE(controls)) - - -/****************************************************************************** - * - * cpia2_open - * - *****************************************************************************/ -static int cpia2_open(struct file *file) -{ - struct camera_data *cam = video_drvdata(file); - struct cpia2_fh *fh; - - if (!cam) { - ERR("Internal error, camera_data not found!\n"); - return -ENODEV; - } - - if (!cam->present) - return -ENODEV; - - if (cam->open_count == 0) { - if (cpia2_allocate_buffers(cam)) - return -ENOMEM; - - /* reset the camera */ - if (cpia2_reset_camera(cam) < 0) - return -EIO; - - cam->APP_len = 0; - cam->COM_len = 0; - } - - fh = kmalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) - return -ENOMEM; - file->private_data = fh; - fh->prio = V4L2_PRIORITY_UNSET; - v4l2_prio_open(&cam->prio, &fh->prio); - fh->mmapped = 0; - - ++cam->open_count; - - cpia2_dbg_dump_registers(cam); - return 0; -} - -/****************************************************************************** - * - * cpia2_close - * - *****************************************************************************/ -static int cpia2_close(struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct camera_data *cam = video_get_drvdata(dev); - struct cpia2_fh *fh = file->private_data; - - if (cam->present && - (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) { - cpia2_usb_stream_stop(cam); - - if (cam->open_count == 1) { - /* save camera state for later open */ - cpia2_save_camera_state(cam); - - cpia2_set_low_power(cam); - cpia2_free_buffers(cam); - } - } - - if (fh->mmapped) - cam->mmapped = 0; - v4l2_prio_close(&cam->prio, fh->prio); - file->private_data = NULL; - kfree(fh); - - if (--cam->open_count == 0) { - cpia2_free_buffers(cam); - if (!cam->present) { - video_unregister_device(dev); - kfree(cam); - return 0; - } - } - - return 0; -} - -/****************************************************************************** - * - * cpia2_v4l_read - * - *****************************************************************************/ -static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, - loff_t *off) -{ - struct camera_data *cam = video_drvdata(file); - int noblock = file->f_flags&O_NONBLOCK; - - struct cpia2_fh *fh = file->private_data; - - if(!cam) - return -EINVAL; - - /* Priority check */ - if(fh->prio != V4L2_PRIORITY_RECORD) { - return -EBUSY; - } - - return cpia2_read(cam, buf, count, noblock); -} - - -/****************************************************************************** - * - * cpia2_v4l_poll - * - *****************************************************************************/ -static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) -{ - struct camera_data *cam = video_drvdata(filp); - struct cpia2_fh *fh = filp->private_data; - - if(!cam) - return POLLERR; - - /* Priority check */ - if(fh->prio != V4L2_PRIORITY_RECORD) { - return POLLERR; - } - - return cpia2_poll(cam, filp, wait); -} - - -static int sync(struct camera_data *cam, int frame_nr) -{ - struct framebuf *frame = &cam->buffers[frame_nr]; - - while (1) { - if (frame->status == FRAME_READY) - return 0; - - if (!cam->streaming) { - frame->status = FRAME_READY; - frame->length = 0; - return 0; - } - - mutex_unlock(&cam->v4l2_lock); - wait_event_interruptible(cam->wq_stream, - !cam->streaming || - frame->status == FRAME_READY); - mutex_lock(&cam->v4l2_lock); - if (signal_pending(current)) - return -ERESTARTSYS; - if(!cam->present) - return -ENOTTY; - } -} - -/****************************************************************************** - * - * ioctl_set_gpio - * - *****************************************************************************/ - -static long cpia2_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) -{ - struct camera_data *cam = video_drvdata(file); - __u32 gpio_val; - - if (cmd != CPIA2_CID_GPIO) - return -EINVAL; - - gpio_val = *(__u32*) arg; - - if (gpio_val &~ 0xFFU) - return -EINVAL; - - return cpia2_set_gpio(cam, (unsigned char)gpio_val); -} - -/****************************************************************************** - * - * ioctl_querycap - * - * V4L2 device capabilities - * - *****************************************************************************/ - -static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc) -{ - struct camera_data *cam = video_drvdata(file); - - strcpy(vc->driver, "cpia2"); - - if (cam->params.pnp_id.product == 0x151) - strcpy(vc->card, "QX5 Microscope"); - else - strcpy(vc->card, "CPiA2 Camera"); - switch (cam->params.pnp_id.device_type) { - case DEVICE_STV_672: - strcat(vc->card, " (672/"); - break; - case DEVICE_STV_676: - strcat(vc->card, " (676/"); - break; - default: - strcat(vc->card, " (???/"); - break; - } - switch (cam->params.version.sensor_flags) { - case CPIA2_VP_SENSOR_FLAGS_404: - strcat(vc->card, "404)"); - break; - case CPIA2_VP_SENSOR_FLAGS_407: - strcat(vc->card, "407)"); - break; - case CPIA2_VP_SENSOR_FLAGS_409: - strcat(vc->card, "409)"); - break; - case CPIA2_VP_SENSOR_FLAGS_410: - strcat(vc->card, "410)"); - break; - case CPIA2_VP_SENSOR_FLAGS_500: - strcat(vc->card, "500)"); - break; - default: - strcat(vc->card, "???)"); - break; - } - - if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) - memset(vc->bus_info,0, sizeof(vc->bus_info)); - - vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER, - CPIA2_PATCH_VER); - - vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - return 0; -} - -/****************************************************************************** - * - * ioctl_input - * - * V4L2 input get/set/enumerate - * - *****************************************************************************/ - -static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - if (i->index) - return -EINVAL; - strcpy(i->name, "Camera"); - i->type = V4L2_INPUT_TYPE_CAMERA; - return 0; -} - -static int cpia2_g_input(struct file *file, void *fh, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int cpia2_s_input(struct file *file, void *fh, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -/****************************************************************************** - * - * ioctl_enum_fmt - * - * V4L2 format enumerate - * - *****************************************************************************/ - -static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - int index = f->index; - - if (index < 0 || index > 1) - return -EINVAL; - - memset(f, 0, sizeof(*f)); - f->index = index; - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->flags = V4L2_FMT_FLAG_COMPRESSED; - switch(index) { - case 0: - strcpy(f->description, "MJPEG"); - f->pixelformat = V4L2_PIX_FMT_MJPEG; - break; - case 1: - strcpy(f->description, "JPEG"); - f->pixelformat = V4L2_PIX_FMT_JPEG; - break; - default: - return -EINVAL; - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_try_fmt - * - * V4L2 format try - * - *****************************************************************************/ - -static int cpia2_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct camera_data *cam = video_drvdata(file); - - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && - f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = cam->frame_size; - f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - f->fmt.pix.priv = 0; - - switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { - case VIDEOSIZE_VGA: - f->fmt.pix.width = 640; - f->fmt.pix.height = 480; - break; - case VIDEOSIZE_CIF: - f->fmt.pix.width = 352; - f->fmt.pix.height = 288; - break; - case VIDEOSIZE_QVGA: - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - break; - case VIDEOSIZE_288_216: - f->fmt.pix.width = 288; - f->fmt.pix.height = 216; - break; - case VIDEOSIZE_256_192: - f->fmt.pix.width = 256; - f->fmt.pix.height = 192; - break; - case VIDEOSIZE_224_168: - f->fmt.pix.width = 224; - f->fmt.pix.height = 168; - break; - case VIDEOSIZE_192_144: - f->fmt.pix.width = 192; - f->fmt.pix.height = 144; - break; - case VIDEOSIZE_QCIF: - default: - f->fmt.pix.width = 176; - f->fmt.pix.height = 144; - break; - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_set_fmt - * - * V4L2 format set - * - *****************************************************************************/ - -static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh, - struct v4l2_format *f) -{ - struct camera_data *cam = video_drvdata(file); - struct cpia2_fh *fh = _fh; - int err, frame; - - err = v4l2_prio_check(&cam->prio, fh->prio); - if (err) - return err; - err = cpia2_try_fmt_vid_cap(file, _fh, f); - if(err != 0) - return err; - - /* Ensure that only this process can change the format. */ - err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); - if(err != 0) { - return err; - } - - cam->pixelformat = f->fmt.pix.pixelformat; - - /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle - * the missing Huffman table properly. */ - cam->params.compression.inhibit_htables = 0; - /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ - - /* we set the video window to something smaller or equal to what - * is requested by the user??? - */ - DBG("Requested width = %d, height = %d\n", - f->fmt.pix.width, f->fmt.pix.height); - if (f->fmt.pix.width != cam->width || - f->fmt.pix.height != cam->height) { - cam->width = f->fmt.pix.width; - cam->height = f->fmt.pix.height; - cam->params.roi.width = f->fmt.pix.width; - cam->params.roi.height = f->fmt.pix.height; - cpia2_set_format(cam); - } - - for (frame = 0; frame < cam->num_frames; ++frame) { - if (cam->buffers[frame].status == FRAME_READING) - if ((err = sync(cam, frame)) < 0) - return err; - - cam->buffers[frame].status = FRAME_EMPTY; - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_get_fmt - * - * V4L2 format get - * - *****************************************************************************/ - -static int cpia2_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct camera_data *cam = video_drvdata(file); - - f->fmt.pix.width = cam->width; - f->fmt.pix.height = cam->height; - f->fmt.pix.pixelformat = cam->pixelformat; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = cam->frame_size; - f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - f->fmt.pix.priv = 0; - - return 0; -} - -/****************************************************************************** - * - * ioctl_cropcap - * - * V4L2 query cropping capabilities - * NOTE: cropping is currently disabled - * - *****************************************************************************/ - -static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c) -{ - struct camera_data *cam = video_drvdata(file); - - if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - c->bounds.left = 0; - c->bounds.top = 0; - c->bounds.width = cam->width; - c->bounds.height = cam->height; - c->defrect.left = 0; - c->defrect.top = 0; - c->defrect.width = cam->width; - c->defrect.height = cam->height; - c->pixelaspect.numerator = 1; - c->pixelaspect.denominator = 1; - - return 0; -} - -/****************************************************************************** - * - * ioctl_queryctrl - * - * V4L2 query possible control variables - * - *****************************************************************************/ - -static int cpia2_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) -{ - struct camera_data *cam = video_drvdata(file); - int i; - - for(i=0; iid == controls[i].id) { - memcpy(c, controls+i, sizeof(*c)); - break; - } - } - - if(i == NUM_CONTROLS) - return -EINVAL; - - /* Some devices have additional limitations */ - switch(c->id) { - case V4L2_CID_BRIGHTNESS: - /*** - * Don't let the register be set to zero - bug in VP4 - * flash of full brightness - ***/ - if (cam->params.pnp_id.device_type == DEVICE_STV_672) - c->minimum = 1; - break; - case V4L2_CID_VFLIP: - // VP5 Only - if(cam->params.pnp_id.device_type == DEVICE_STV_672) - c->flags |= V4L2_CTRL_FLAG_DISABLED; - break; - case CPIA2_CID_FRAMERATE: - if(cam->params.pnp_id.device_type == DEVICE_STV_672 && - cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ - // Maximum 15fps - for(i=0; imaximum; ++i) { - if(framerate_controls[i].value == - CPIA2_VP_FRAMERATE_15) { - c->maximum = i; - c->default_value = i; - } - } - } - break; - case CPIA2_CID_FLICKER_MODE: - // Flicker control only valid for 672. - if(cam->params.pnp_id.device_type != DEVICE_STV_672) - c->flags |= V4L2_CTRL_FLAG_DISABLED; - break; - case CPIA2_CID_LIGHTS: - // Light control only valid for the QX5 Microscope. - if(cam->params.pnp_id.product != 0x151) - c->flags |= V4L2_CTRL_FLAG_DISABLED; - break; - default: - break; - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_querymenu - * - * V4L2 query possible control variables - * - *****************************************************************************/ - -static int cpia2_querymenu(struct file *file, void *fh, struct v4l2_querymenu *m) -{ - struct camera_data *cam = video_drvdata(file); - - switch(m->id) { - case CPIA2_CID_FLICKER_MODE: - if (m->index >= NUM_FLICKER_CONTROLS) - return -EINVAL; - - strcpy(m->name, flicker_controls[m->index].name); - break; - case CPIA2_CID_FRAMERATE: - { - int maximum = NUM_FRAMERATE_CONTROLS - 1; - if(cam->params.pnp_id.device_type == DEVICE_STV_672 && - cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ - // Maximum 15fps - int i; - for(i=0; iindex > maximum) - return -EINVAL; - - strcpy(m->name, framerate_controls[m->index].name); - break; - } - case CPIA2_CID_LIGHTS: - if (m->index >= NUM_LIGHTS_CONTROLS) - return -EINVAL; - - strcpy(m->name, lights_controls[m->index].name); - break; - default: - return -EINVAL; - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_g_ctrl - * - * V4L2 get the value of a control variable - * - *****************************************************************************/ - -static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) -{ - struct camera_data *cam = video_drvdata(file); - - switch(c->id) { - case V4L2_CID_BRIGHTNESS: - cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, - TRANSFER_READ, 0); - c->value = cam->params.color_params.brightness; - break; - case V4L2_CID_CONTRAST: - cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, - TRANSFER_READ, 0); - c->value = cam->params.color_params.contrast; - break; - case V4L2_CID_SATURATION: - cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, - TRANSFER_READ, 0); - c->value = cam->params.color_params.saturation; - break; - case V4L2_CID_HFLIP: - cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, - TRANSFER_READ, 0); - c->value = (cam->params.vp_params.user_effects & - CPIA2_VP_USER_EFFECTS_MIRROR) != 0; - break; - case V4L2_CID_VFLIP: - cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, - TRANSFER_READ, 0); - c->value = (cam->params.vp_params.user_effects & - CPIA2_VP_USER_EFFECTS_FLIP) != 0; - break; - case CPIA2_CID_TARGET_KB: - c->value = cam->params.vc_params.target_kb; - break; - case CPIA2_CID_GPIO: - cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, - TRANSFER_READ, 0); - c->value = cam->params.vp_params.gpio_data; - break; - case CPIA2_CID_FLICKER_MODE: - { - int i, mode; - cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, - TRANSFER_READ, 0); - if(cam->params.flicker_control.cam_register & - CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) { - mode = NEVER_FLICKER; - } else { - if(cam->params.flicker_control.cam_register & - CPIA2_VP_FLICKER_MODES_50HZ) { - mode = FLICKER_50; - } else { - mode = FLICKER_60; - } - } - for(i=0; ivalue = i; - break; - } - } - if(i == NUM_FLICKER_CONTROLS) - return -EINVAL; - break; - } - case CPIA2_CID_FRAMERATE: - { - int maximum = NUM_FRAMERATE_CONTROLS - 1; - int i; - for(i=0; i<= maximum; i++) { - if(cam->params.vp_params.frame_rate == - framerate_controls[i].value) - break; - } - if(i > maximum) - return -EINVAL; - c->value = i; - break; - } - case CPIA2_CID_USB_ALT: - c->value = cam->params.camera_state.stream_mode; - break; - case CPIA2_CID_LIGHTS: - { - int i; - cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, - TRANSFER_READ, 0); - for(i=0; iparams.vp_params.gpio_data&GPIO_LIGHTS_MASK) == - lights_controls[i].value) { - break; - } - } - if(i == NUM_LIGHTS_CONTROLS) - return -EINVAL; - c->value = i; - break; - } - case CPIA2_CID_RESET_CAMERA: - return -EINVAL; - default: - return -EINVAL; - } - - DBG("Get control id:%d, value:%d\n", c->id, c->value); - - return 0; -} - -/****************************************************************************** - * - * ioctl_s_ctrl - * - * V4L2 set the value of a control variable - * - *****************************************************************************/ - -static int cpia2_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) -{ - struct camera_data *cam = video_drvdata(file); - int i; - int retval = 0; - - DBG("Set control id:%d, value:%d\n", c->id, c->value); - - /* Check that the value is in range */ - for(i=0; iid == controls[i].id) { - if(c->value < controls[i].minimum || - c->value > controls[i].maximum) { - return -EINVAL; - } - break; - } - } - if(i == NUM_CONTROLS) - return -EINVAL; - - switch(c->id) { - case V4L2_CID_BRIGHTNESS: - cpia2_set_brightness(cam, c->value); - break; - case V4L2_CID_CONTRAST: - cpia2_set_contrast(cam, c->value); - break; - case V4L2_CID_SATURATION: - cpia2_set_saturation(cam, c->value); - break; - case V4L2_CID_HFLIP: - cpia2_set_property_mirror(cam, c->value); - break; - case V4L2_CID_VFLIP: - cpia2_set_property_flip(cam, c->value); - break; - case CPIA2_CID_TARGET_KB: - retval = cpia2_set_target_kb(cam, c->value); - break; - case CPIA2_CID_GPIO: - retval = cpia2_set_gpio(cam, c->value); - break; - case CPIA2_CID_FLICKER_MODE: - retval = cpia2_set_flicker_mode(cam, - flicker_controls[c->value].value); - break; - case CPIA2_CID_FRAMERATE: - retval = cpia2_set_fps(cam, framerate_controls[c->value].value); - break; - case CPIA2_CID_USB_ALT: - retval = cpia2_usb_change_streaming_alternate(cam, c->value); - break; - case CPIA2_CID_LIGHTS: - retval = cpia2_set_gpio(cam, lights_controls[c->value].value); - break; - case CPIA2_CID_RESET_CAMERA: - cpia2_usb_stream_pause(cam); - cpia2_reset_camera(cam); - cpia2_usb_stream_resume(cam); - break; - default: - retval = -EINVAL; - } - - return retval; -} - -/****************************************************************************** - * - * ioctl_g_jpegcomp - * - * V4L2 get the JPEG compression parameters - * - *****************************************************************************/ - -static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) -{ - struct camera_data *cam = video_drvdata(file); - - memset(parms, 0, sizeof(*parms)); - - parms->quality = 80; // TODO: Can this be made meaningful? - - parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; - if(!cam->params.compression.inhibit_htables) { - parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; - } - - parms->APPn = cam->APPn; - parms->APP_len = cam->APP_len; - if(cam->APP_len > 0) { - memcpy(parms->APP_data, cam->APP_data, cam->APP_len); - parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; - } - - parms->COM_len = cam->COM_len; - if(cam->COM_len > 0) { - memcpy(parms->COM_data, cam->COM_data, cam->COM_len); - parms->jpeg_markers |= JPEG_MARKER_COM; - } - - DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", - parms->APP_len, parms->COM_len); - - return 0; -} - -/****************************************************************************** - * - * ioctl_s_jpegcomp - * - * V4L2 set the JPEG compression parameters - * NOTE: quality and some jpeg_markers are ignored. - * - *****************************************************************************/ - -static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) -{ - struct camera_data *cam = video_drvdata(file); - - DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", - parms->APP_len, parms->COM_len); - - cam->params.compression.inhibit_htables = - !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); - - if(parms->APP_len != 0) { - if(parms->APP_len > 0 && - parms->APP_len <= sizeof(cam->APP_data) && - parms->APPn >= 0 && parms->APPn <= 15) { - cam->APPn = parms->APPn; - cam->APP_len = parms->APP_len; - memcpy(cam->APP_data, parms->APP_data, parms->APP_len); - } else { - LOG("Bad APPn Params n=%d len=%d\n", - parms->APPn, parms->APP_len); - return -EINVAL; - } - } else { - cam->APP_len = 0; - } - - if(parms->COM_len != 0) { - if(parms->COM_len > 0 && - parms->COM_len <= sizeof(cam->COM_data)) { - cam->COM_len = parms->COM_len; - memcpy(cam->COM_data, parms->COM_data, parms->COM_len); - } else { - LOG("Bad COM_len=%d\n", parms->COM_len); - return -EINVAL; - } - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_reqbufs - * - * V4L2 Initiate memory mapping. - * NOTE: The user's request is ignored. For now the buffers are fixed. - * - *****************************************************************************/ - -static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) -{ - struct camera_data *cam = video_drvdata(file); - - if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - req->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); - req->count = cam->num_frames; - memset(&req->reserved, 0, sizeof(req->reserved)); - - return 0; -} - -/****************************************************************************** - * - * ioctl_querybuf - * - * V4L2 Query memory buffer status. - * - *****************************************************************************/ - -static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct camera_data *cam = video_drvdata(file); - - if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->index > cam->num_frames) - return -EINVAL; - - buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; - buf->length = cam->frame_size; - - buf->memory = V4L2_MEMORY_MMAP; - - if(cam->mmapped) - buf->flags = V4L2_BUF_FLAG_MAPPED; - else - buf->flags = 0; - - switch (cam->buffers[buf->index].status) { - case FRAME_EMPTY: - case FRAME_ERROR: - case FRAME_READING: - buf->bytesused = 0; - buf->flags = V4L2_BUF_FLAG_QUEUED; - break; - case FRAME_READY: - buf->bytesused = cam->buffers[buf->index].length; - buf->timestamp = cam->buffers[buf->index].timestamp; - buf->sequence = cam->buffers[buf->index].seq; - buf->flags = V4L2_BUF_FLAG_DONE; - break; - } - - DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", - buf->index, buf->m.offset, buf->flags, buf->sequence, - buf->bytesused); - - return 0; -} - -/****************************************************************************** - * - * ioctl_qbuf - * - * V4L2 User is freeing buffer - * - *****************************************************************************/ - -static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct camera_data *cam = video_drvdata(file); - - if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->memory != V4L2_MEMORY_MMAP || - buf->index > cam->num_frames) - return -EINVAL; - - DBG("QBUF #%d\n", buf->index); - - if(cam->buffers[buf->index].status == FRAME_READY) - cam->buffers[buf->index].status = FRAME_EMPTY; - - return 0; -} - -/****************************************************************************** - * - * find_earliest_filled_buffer - * - * Helper for ioctl_dqbuf. Find the next ready buffer. - * - *****************************************************************************/ - -static int find_earliest_filled_buffer(struct camera_data *cam) -{ - int i; - int found = -1; - for (i=0; inum_frames; i++) { - if(cam->buffers[i].status == FRAME_READY) { - if(found < 0) { - found = i; - } else { - /* find which buffer is earlier */ - struct timeval *tv1, *tv2; - tv1 = &cam->buffers[i].timestamp; - tv2 = &cam->buffers[found].timestamp; - if(tv1->tv_sec < tv2->tv_sec || - (tv1->tv_sec == tv2->tv_sec && - tv1->tv_usec < tv2->tv_usec)) - found = i; - } - } - } - return found; -} - -/****************************************************************************** - * - * ioctl_dqbuf - * - * V4L2 User is asking for a filled buffer. - * - *****************************************************************************/ - -static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct camera_data *cam = video_drvdata(file); - int frame; - - if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - frame = find_earliest_filled_buffer(cam); - - if(frame < 0 && file->f_flags&O_NONBLOCK) - return -EAGAIN; - - if(frame < 0) { - /* Wait for a frame to become available */ - struct framebuf *cb=cam->curbuff; - mutex_unlock(&cam->v4l2_lock); - wait_event_interruptible(cam->wq_stream, - !cam->present || - (cb=cam->curbuff)->status == FRAME_READY); - mutex_lock(&cam->v4l2_lock); - if (signal_pending(current)) - return -ERESTARTSYS; - if(!cam->present) - return -ENOTTY; - frame = cb->num; - } - - - buf->index = frame; - buf->bytesused = cam->buffers[buf->index].length; - buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; - buf->field = V4L2_FIELD_NONE; - buf->timestamp = cam->buffers[buf->index].timestamp; - buf->sequence = cam->buffers[buf->index].seq; - buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; - buf->length = cam->frame_size; - buf->input = 0; - buf->reserved = 0; - memset(&buf->timecode, 0, sizeof(buf->timecode)); - - DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, - cam->buffers[buf->index].status, buf->sequence, buf->bytesused); - - return 0; -} - -static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p) -{ - struct cpia2_fh *fh = _fh; - - *p = fh->prio; - return 0; -} - -static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio) -{ - struct camera_data *cam = video_drvdata(file); - struct cpia2_fh *fh = fh; - - if (cam->streaming && prio != fh->prio && - fh->prio == V4L2_PRIORITY_RECORD) - /* Can't drop record priority while streaming */ - return -EBUSY; - - if (prio == V4L2_PRIORITY_RECORD && prio != fh->prio && - v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) - /* Only one program can record at a time */ - return -EBUSY; - return v4l2_prio_change(&cam->prio, &fh->prio, prio); -} - -static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) -{ - struct camera_data *cam = video_drvdata(file); - - DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); - if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (!cam->streaming) - return cpia2_usb_stream_start(cam, - cam->params.camera_state.stream_mode); - return -EINVAL; -} - -static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) -{ - struct camera_data *cam = video_drvdata(file); - - DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); - if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cam->streaming) - return cpia2_usb_stream_stop(cam); - return -EINVAL; -} - -/****************************************************************************** - * - * cpia2_mmap - * - *****************************************************************************/ -static int cpia2_mmap(struct file *file, struct vm_area_struct *area) -{ - struct camera_data *cam = video_drvdata(file); - int retval; - - /* Priority check */ - struct cpia2_fh *fh = file->private_data; - if(fh->prio != V4L2_PRIORITY_RECORD) { - return -EBUSY; - } - - retval = cpia2_remap_buffer(cam, area); - - if(!retval) - fh->mmapped = 1; - return retval; -} - -/****************************************************************************** - * - * reset_camera_struct_v4l - * - * Sets all values to the defaults - *****************************************************************************/ -static void reset_camera_struct_v4l(struct camera_data *cam) -{ - cam->width = cam->params.roi.width; - cam->height = cam->params.roi.height; - - cam->frame_size = buffer_size; - cam->num_frames = num_buffers; - - /* FlickerModes */ - cam->params.flicker_control.flicker_mode_req = flicker_mode; - cam->params.flicker_control.mains_frequency = flicker_freq; - - /* streamMode */ - cam->params.camera_state.stream_mode = alternate; - - cam->pixelformat = V4L2_PIX_FMT_JPEG; - v4l2_prio_init(&cam->prio); -} - -static const struct v4l2_ioctl_ops cpia2_ioctl_ops = { - .vidioc_querycap = cpia2_querycap, - .vidioc_enum_input = cpia2_enum_input, - .vidioc_g_input = cpia2_g_input, - .vidioc_s_input = cpia2_s_input, - .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap, - .vidioc_queryctrl = cpia2_queryctrl, - .vidioc_querymenu = cpia2_querymenu, - .vidioc_g_ctrl = cpia2_g_ctrl, - .vidioc_s_ctrl = cpia2_s_ctrl, - .vidioc_g_jpegcomp = cpia2_g_jpegcomp, - .vidioc_s_jpegcomp = cpia2_s_jpegcomp, - .vidioc_cropcap = cpia2_cropcap, - .vidioc_reqbufs = cpia2_reqbufs, - .vidioc_querybuf = cpia2_querybuf, - .vidioc_qbuf = cpia2_qbuf, - .vidioc_dqbuf = cpia2_dqbuf, - .vidioc_streamon = cpia2_streamon, - .vidioc_streamoff = cpia2_streamoff, - .vidioc_g_priority = cpia2_g_priority, - .vidioc_s_priority = cpia2_s_priority, - .vidioc_default = cpia2_default, -}; - -/*** - * The v4l video device structure initialized for this device - ***/ -static const struct v4l2_file_operations cpia2_fops = { - .owner = THIS_MODULE, - .open = cpia2_open, - .release = cpia2_close, - .read = cpia2_v4l_read, - .poll = cpia2_v4l_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = cpia2_mmap, -}; - -static struct video_device cpia2_template = { - /* I could not find any place for the old .initialize initializer?? */ - .name = "CPiA2 Camera", - .fops = &cpia2_fops, - .ioctl_ops = &cpia2_ioctl_ops, - .release = video_device_release, -}; - -/****************************************************************************** - * - * cpia2_register_camera - * - *****************************************************************************/ -int cpia2_register_camera(struct camera_data *cam) -{ - cam->vdev = video_device_alloc(); - if(!cam->vdev) - return -ENOMEM; - - memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template)); - video_set_drvdata(cam->vdev, cam); - cam->vdev->lock = &cam->v4l2_lock; - - reset_camera_struct_v4l(cam); - - /* register v4l device */ - if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - ERR("video_register_device failed\n"); - video_device_release(cam->vdev); - return -ENODEV; - } - - return 0; -} - -/****************************************************************************** - * - * cpia2_unregister_camera - * - *****************************************************************************/ -void cpia2_unregister_camera(struct camera_data *cam) -{ - if (!cam->open_count) { - video_unregister_device(cam->vdev); - } else { - LOG("%s removed while open, deferring " - "video_unregister_device\n", - video_device_node_name(cam->vdev)); - } -} - -/****************************************************************************** - * - * check_parameters - * - * Make sure that all user-supplied parameters are sensible - *****************************************************************************/ -static void __init check_parameters(void) -{ - if(buffer_size < PAGE_SIZE) { - buffer_size = PAGE_SIZE; - LOG("buffer_size too small, setting to %d\n", buffer_size); - } else if(buffer_size > 1024*1024) { - /* arbitrary upper limiit */ - buffer_size = 1024*1024; - LOG("buffer_size ridiculously large, setting to %d\n", - buffer_size); - } else { - buffer_size += PAGE_SIZE-1; - buffer_size &= ~(PAGE_SIZE-1); - } - - if(num_buffers < 1) { - num_buffers = 1; - LOG("num_buffers too small, setting to %d\n", num_buffers); - } else if(num_buffers > VIDEO_MAX_FRAME) { - num_buffers = VIDEO_MAX_FRAME; - LOG("num_buffers too large, setting to %d\n", num_buffers); - } - - if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { - alternate = DEFAULT_ALT; - LOG("alternate specified is invalid, using %d\n", alternate); - } - - if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) { - flicker_mode = NEVER_FLICKER; - LOG("Flicker mode specified is invalid, using %d\n", - flicker_mode); - } - - if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) { - flicker_freq = FLICKER_60; - LOG("Flicker mode specified is invalid, using %d\n", - flicker_freq); - } - - if(video_nr < -1 || video_nr > 64) { - video_nr = -1; - LOG("invalid video_nr specified, must be -1 to 64\n"); - } - - DBG("Using %d buffers, each %d bytes, alternate=%d\n", - num_buffers, buffer_size, alternate); -} - -/************ Module Stuff ***************/ - - -/****************************************************************************** - * - * cpia2_init/module_init - * - *****************************************************************************/ -static int __init cpia2_init(void) -{ - LOG("%s v%d.%d.%d\n", - ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); - check_parameters(); - cpia2_usb_init(); - return 0; -} - - -/****************************************************************************** - * - * cpia2_exit/module_exit - * - *****************************************************************************/ -static void __exit cpia2_exit(void) -{ - cpia2_usb_cleanup(); - schedule_timeout(2 * HZ); -} - -module_init(cpia2_init); -module_exit(cpia2_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -config VIDEO_CPIA2 - tristate "CPiA2 Video For Linux" - depends on VIDEO_DEV && USB && VIDEO_V4L2 - ---help--- - This is the video4linux driver for cameras based on Vision's CPiA2 - (Colour Processor Interface ASIC), such as the Digital Blue QX5 - Microscope. If you have one of these cameras, say Y here - - This driver is also available as a module (cpia2). diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cpia2/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -cpia2-objs := cpia2_v4l.o cpia2_usb.o cpia2_core.o - -obj-$(CONFIG_VIDEO_CPIA2) += cpia2.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/c-qcam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/c-qcam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/c-qcam.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/c-qcam.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,891 +0,0 @@ -/* - * Video4Linux Colour QuickCam driver - * Copyright 1997-2000 Philip Blundell - * - * Module parameters: - * - * parport=auto -- probe all parports (default) - * parport=0 -- parport0 becomes qcam1 - * parport=2,0,1 -- parports 2,0,1 are tried in that order - * - * probe=0 -- do no probing, assume camera is present - * probe=1 -- use IEEE-1284 autoprobe data only (default) - * probe=2 -- probe aggressively for cameras - * - * force_rgb=1 -- force data format to RGB (default is BGR) - * - * The parport parameter controls which parports will be scanned. - * Scanning all parports causes some printers to print a garbage page. - * -- March 14, 1999 Billy Donahue - * - * Fixed data format to BGR, added force_rgb parameter. Added missing - * parport_unregister_driver() on module removal. - * -- May 28, 2000 Claudio Matsuoka - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct qcam { - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct pardevice *pdev; - struct parport *pport; - int width, height; - int ccd_width, ccd_height; - int mode; - int contrast, brightness, whitebal; - int top, left; - unsigned int bidirectional; - struct mutex lock; -}; - -/* cameras maximum */ -#define MAX_CAMS 4 - -/* The three possible QuickCam modes */ -#define QC_MILLIONS 0x18 -#define QC_BILLIONS 0x10 -#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */ - -/* The three possible decimations */ -#define QC_DECIMATION_1 0 -#define QC_DECIMATION_2 2 -#define QC_DECIMATION_4 4 - -#define BANNER "Colour QuickCam for Video4Linux v0.06" - -static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; -static int probe = 2; -static int force_rgb; -static int video_nr = -1; - -/* FIXME: parport=auto would never have worked, surely? --RR */ -MODULE_PARM_DESC(parport, "parport= for port detection method\n" - "probe=<0|1|2> for camera detection method\n" - "force_rgb=<0|1> for RGB data format (default BGR)"); -module_param_array(parport, int, NULL, 0); -module_param(probe, int, 0); -module_param(force_rgb, bool, 0); -module_param(video_nr, int, 0); - -static struct qcam *qcams[MAX_CAMS]; -static unsigned int num_cams; - -static inline void qcam_set_ack(struct qcam *qcam, unsigned int i) -{ - /* note: the QC specs refer to the PCAck pin by voltage, not - software level. PC ports have builtin inverters. */ - parport_frob_control(qcam->pport, 8, i ? 8 : 0); -} - -static inline unsigned int qcam_ready1(struct qcam *qcam) -{ - return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0; -} - -static inline unsigned int qcam_ready2(struct qcam *qcam) -{ - return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0; -} - -static unsigned int qcam_await_ready1(struct qcam *qcam, int value) -{ - struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; - unsigned long oldjiffies = jiffies; - unsigned int i; - - for (oldjiffies = jiffies; - time_before(jiffies, oldjiffies + msecs_to_jiffies(40));) - if (qcam_ready1(qcam) == value) - return 0; - - /* If the camera didn't respond within 1/25 second, poll slowly - for a while. */ - for (i = 0; i < 50; i++) { - if (qcam_ready1(qcam) == value) - return 0; - msleep_interruptible(100); - } - - /* Probably somebody pulled the plug out. Not much we can do. */ - v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value, - parport_read_status(qcam->pport), - parport_read_control(qcam->pport)); - return 1; -} - -static unsigned int qcam_await_ready2(struct qcam *qcam, int value) -{ - struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; - unsigned long oldjiffies = jiffies; - unsigned int i; - - for (oldjiffies = jiffies; - time_before(jiffies, oldjiffies + msecs_to_jiffies(40));) - if (qcam_ready2(qcam) == value) - return 0; - - /* If the camera didn't respond within 1/25 second, poll slowly - for a while. */ - for (i = 0; i < 50; i++) { - if (qcam_ready2(qcam) == value) - return 0; - msleep_interruptible(100); - } - - /* Probably somebody pulled the plug out. Not much we can do. */ - v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value, - parport_read_status(qcam->pport), - parport_read_control(qcam->pport), - parport_read_data(qcam->pport)); - return 1; -} - -static int qcam_read_data(struct qcam *qcam) -{ - unsigned int idata; - - qcam_set_ack(qcam, 0); - if (qcam_await_ready1(qcam, 1)) - return -1; - idata = parport_read_status(qcam->pport) & 0xf0; - qcam_set_ack(qcam, 1); - if (qcam_await_ready1(qcam, 0)) - return -1; - idata |= parport_read_status(qcam->pport) >> 4; - return idata; -} - -static int qcam_write_data(struct qcam *qcam, unsigned int data) -{ - struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; - unsigned int idata; - - parport_write_data(qcam->pport, data); - idata = qcam_read_data(qcam); - if (data != idata) { - v4l2_warn(v4l2_dev, "sent %x but received %x\n", data, - idata); - return 1; - } - return 0; -} - -static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data) -{ - if (qcam_write_data(qcam, cmd)) - return -1; - if (qcam_write_data(qcam, data)) - return -1; - return 0; -} - -static inline int qcam_get(struct qcam *qcam, unsigned int cmd) -{ - if (qcam_write_data(qcam, cmd)) - return -1; - return qcam_read_data(qcam); -} - -static int qc_detect(struct qcam *qcam) -{ - unsigned int stat, ostat, i, count = 0; - - /* The probe routine below is not very reliable. The IEEE-1284 - probe takes precedence. */ - /* XXX Currently parport provides no way to distinguish between - "the IEEE probe was not done" and "the probe was done, but - no device was found". Fix this one day. */ - if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA - && qcam->pport->probe_info[0].model - && !strcmp(qcam->pdev->port->probe_info[0].model, - "Color QuickCam 2.0")) { - printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n"); - return 1; - } - - if (probe < 2) - return 0; - - parport_write_control(qcam->pport, 0xc); - - /* look for a heartbeat */ - ostat = stat = parport_read_status(qcam->pport); - for (i = 0; i < 250; i++) { - mdelay(1); - stat = parport_read_status(qcam->pport); - if (ostat != stat) { - if (++count >= 3) - return 1; - ostat = stat; - } - } - - /* Reset the camera and try again */ - parport_write_control(qcam->pport, 0xc); - parport_write_control(qcam->pport, 0x8); - mdelay(1); - parport_write_control(qcam->pport, 0xc); - mdelay(1); - count = 0; - - ostat = stat = parport_read_status(qcam->pport); - for (i = 0; i < 250; i++) { - mdelay(1); - stat = parport_read_status(qcam->pport); - if (ostat != stat) { - if (++count >= 3) - return 1; - ostat = stat; - } - } - - /* no (or flatline) camera, give up */ - return 0; -} - -static void qc_reset(struct qcam *qcam) -{ - parport_write_control(qcam->pport, 0xc); - parport_write_control(qcam->pport, 0x8); - mdelay(1); - parport_write_control(qcam->pport, 0xc); - mdelay(1); -} - -/* Reset the QuickCam and program for brightness, contrast, - * white-balance, and resolution. */ - -static void qc_setup(struct qcam *qcam) -{ - qc_reset(qcam); - - /* Set the brightness. */ - qcam_set(qcam, 11, qcam->brightness); - - /* Set the height and width. These refer to the actual - CCD area *before* applying the selected decimation. */ - qcam_set(qcam, 17, qcam->ccd_height); - qcam_set(qcam, 19, qcam->ccd_width / 2); - - /* Set top and left. */ - qcam_set(qcam, 0xd, qcam->top); - qcam_set(qcam, 0xf, qcam->left); - - /* Set contrast and white balance. */ - qcam_set(qcam, 0x19, qcam->contrast); - qcam_set(qcam, 0x1f, qcam->whitebal); - - /* Set the speed. */ - qcam_set(qcam, 45, 2); -} - -/* Read some bytes from the camera and put them in the buffer. - nbytes should be a multiple of 3, because bidirectional mode gives - us three bytes at a time. */ - -static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes) -{ - unsigned int bytes = 0; - - qcam_set_ack(qcam, 0); - if (qcam->bidirectional) { - /* It's a bidirectional port */ - while (bytes < nbytes) { - unsigned int lo1, hi1, lo2, hi2; - unsigned char r, g, b; - - if (qcam_await_ready2(qcam, 1)) - return bytes; - lo1 = parport_read_data(qcam->pport) >> 1; - hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(qcam, 1); - if (qcam_await_ready2(qcam, 0)) - return bytes; - lo2 = parport_read_data(qcam->pport) >> 1; - hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(qcam, 0); - r = lo1 | ((hi1 & 1) << 7); - g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1); - b = lo2 | ((hi2 & 1) << 7); - if (force_rgb) { - buf[bytes++] = r; - buf[bytes++] = g; - buf[bytes++] = b; - } else { - buf[bytes++] = b; - buf[bytes++] = g; - buf[bytes++] = r; - } - } - } else { - /* It's a unidirectional port */ - int i = 0, n = bytes; - unsigned char rgb[3]; - - while (bytes < nbytes) { - unsigned int hi, lo; - - if (qcam_await_ready1(qcam, 1)) - return bytes; - hi = (parport_read_status(qcam->pport) & 0xf0); - qcam_set_ack(qcam, 1); - if (qcam_await_ready1(qcam, 0)) - return bytes; - lo = (parport_read_status(qcam->pport) & 0xf0); - qcam_set_ack(qcam, 0); - /* flip some bits */ - rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; - if (i >= 2) { -get_fragment: - if (force_rgb) { - buf[n++] = rgb[0]; - buf[n++] = rgb[1]; - buf[n++] = rgb[2]; - } else { - buf[n++] = rgb[2]; - buf[n++] = rgb[1]; - buf[n++] = rgb[0]; - } - } - } - if (i) { - i = 0; - goto get_fragment; - } - } - return bytes; -} - -#define BUFSZ 150 - -static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len) -{ - struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; - unsigned lines, pixelsperline, bitsperxfer; - unsigned int is_bi_dir = qcam->bidirectional; - size_t wantlen, outptr = 0; - char tmpbuf[BUFSZ]; - - if (!access_ok(VERIFY_WRITE, buf, len)) - return -EFAULT; - - /* Wait for camera to become ready */ - for (;;) { - int i = qcam_get(qcam, 41); - - if (i == -1) { - qc_setup(qcam); - return -EIO; - } - if ((i & 0x80) == 0) - break; - schedule(); - } - - if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1)) - return -EIO; - - lines = qcam->height; - pixelsperline = qcam->width; - bitsperxfer = (is_bi_dir) ? 24 : 8; - - if (is_bi_dir) { - /* Turn the port around */ - parport_data_reverse(qcam->pport); - mdelay(3); - qcam_set_ack(qcam, 0); - if (qcam_await_ready1(qcam, 1)) { - qc_setup(qcam); - return -EIO; - } - qcam_set_ack(qcam, 1); - if (qcam_await_ready1(qcam, 0)) { - qc_setup(qcam); - return -EIO; - } - } - - wantlen = lines * pixelsperline * 24 / 8; - - while (wantlen) { - size_t t, s; - - s = (wantlen > BUFSZ) ? BUFSZ : wantlen; - t = qcam_read_bytes(qcam, tmpbuf, s); - if (outptr < len) { - size_t sz = len - outptr; - - if (sz > t) - sz = t; - if (__copy_to_user(buf + outptr, tmpbuf, sz)) - break; - outptr += sz; - } - wantlen -= t; - if (t < s) - break; - cond_resched(); - } - - len = outptr; - - if (wantlen) { - v4l2_err(v4l2_dev, "short read.\n"); - if (is_bi_dir) - parport_data_forward(qcam->pport); - qc_setup(qcam); - return len; - } - - if (is_bi_dir) { - int l; - - do { - l = qcam_read_bytes(qcam, tmpbuf, 3); - cond_resched(); - } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); - if (force_rgb) { - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - v4l2_err(v4l2_dev, "bad EOF\n"); - } else { - if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - v4l2_err(v4l2_dev, "bad EOF\n"); - } - qcam_set_ack(qcam, 0); - if (qcam_await_ready1(qcam, 1)) { - v4l2_err(v4l2_dev, "no ack after EOF\n"); - parport_data_forward(qcam->pport); - qc_setup(qcam); - return len; - } - parport_data_forward(qcam->pport); - mdelay(3); - qcam_set_ack(qcam, 1); - if (qcam_await_ready1(qcam, 0)) { - v4l2_err(v4l2_dev, "no ack to port turnaround\n"); - qc_setup(qcam); - return len; - } - } else { - int l; - - do { - l = qcam_read_bytes(qcam, tmpbuf, 1); - cond_resched(); - } while (l && tmpbuf[0] == 0x7e); - l = qcam_read_bytes(qcam, tmpbuf + 1, 2); - if (force_rgb) { - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - v4l2_err(v4l2_dev, "bad EOF\n"); - } else { - if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - v4l2_err(v4l2_dev, "bad EOF\n"); - } - } - - qcam_write_data(qcam, 0); - return len; -} - -/* - * Video4linux interfacing - */ - -static int qcam_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct qcam *qcam = video_drvdata(file); - - strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card)); - strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); - vcap->version = KERNEL_VERSION(0, 0, 3); - vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - return 0; -} - -static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - if (vin->index > 0) - return -EINVAL; - strlcpy(vin->name, "Camera", sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = 0; - vin->status = 0; - return 0; -} - -static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) -{ - *inp = 0; - return 0; -} - -static int qcam_s_input(struct file *file, void *fh, unsigned int inp) -{ - return (inp > 0) ? -EINVAL : 0; -} - -static int qcam_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192); - case V4L2_CID_GAMMA: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); - } - return -EINVAL; -} - -static int qcam_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct qcam *qcam = video_drvdata(file); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = qcam->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = qcam->contrast; - break; - case V4L2_CID_GAMMA: - ctrl->value = qcam->whitebal; - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static int qcam_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct qcam *qcam = video_drvdata(file); - int ret = 0; - - mutex_lock(&qcam->lock); - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - qcam->brightness = ctrl->value; - break; - case V4L2_CID_CONTRAST: - qcam->contrast = ctrl->value; - break; - case V4L2_CID_GAMMA: - qcam->whitebal = ctrl->value; - break; - default: - ret = -EINVAL; - break; - } - if (ret == 0) { - parport_claim_or_block(qcam->pdev); - qc_setup(qcam); - parport_release(qcam->pdev); - } - mutex_unlock(&qcam->lock); - return ret; -} - -static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct qcam *qcam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = qcam->width; - pix->height = qcam->height; - pix->pixelformat = V4L2_PIX_FMT_RGB24; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 3 * qcam->width; - pix->sizeimage = 3 * qcam->width * qcam->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->height < 60 || pix->width < 80) { - pix->height = 60; - pix->width = 80; - } else if (pix->height < 120 || pix->width < 160) { - pix->height = 120; - pix->width = 160; - } else { - pix->height = 240; - pix->width = 320; - } - pix->pixelformat = V4L2_PIX_FMT_RGB24; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 3 * pix->width; - pix->sizeimage = 3 * pix->width * pix->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct qcam *qcam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = qcam_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - switch (pix->height) { - case 60: - qcam->mode = QC_DECIMATION_4; - break; - case 120: - qcam->mode = QC_DECIMATION_2; - break; - default: - qcam->mode = QC_DECIMATION_1; - break; - } - - mutex_lock(&qcam->lock); - qcam->mode |= QC_MILLIONS; - qcam->height = pix->height; - qcam->width = pix->width; - parport_claim_or_block(qcam->pdev); - qc_setup(qcam); - parport_release(qcam->pdev); - mutex_unlock(&qcam->lock); - return 0; -} - -static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "RGB 8:8:8", V4L2_PIX_FMT_RGB24, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 0) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -static ssize_t qcam_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct qcam *qcam = video_drvdata(file); - int len; - - mutex_lock(&qcam->lock); - parport_claim_or_block(qcam->pdev); - /* Probably should have a semaphore against multiple users */ - len = qc_capture(qcam, buf, count); - parport_release(qcam->pdev); - mutex_unlock(&qcam->lock); - return len; -} - -static const struct v4l2_file_operations qcam_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - .read = qcam_read, -}; - -static const struct v4l2_ioctl_ops qcam_ioctl_ops = { - .vidioc_querycap = qcam_querycap, - .vidioc_g_input = qcam_g_input, - .vidioc_s_input = qcam_s_input, - .vidioc_enum_input = qcam_enum_input, - .vidioc_queryctrl = qcam_queryctrl, - .vidioc_g_ctrl = qcam_g_ctrl, - .vidioc_s_ctrl = qcam_s_ctrl, - .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, -}; - -/* Initialize the QuickCam driver control structure. */ - -static struct qcam *qcam_init(struct parport *port) -{ - struct qcam *qcam; - struct v4l2_device *v4l2_dev; - - qcam = kzalloc(sizeof(*qcam), GFP_KERNEL); - if (qcam == NULL) - return NULL; - - v4l2_dev = &qcam->v4l2_dev; - strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name)); - - if (v4l2_device_register(NULL, v4l2_dev) < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return NULL; - } - - qcam->pport = port; - qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL, - NULL, 0, NULL); - - qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; - - if (qcam->pdev == NULL) { - v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); - kfree(qcam); - return NULL; - } - - strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name)); - qcam->vdev.v4l2_dev = v4l2_dev; - qcam->vdev.fops = &qcam_fops; - qcam->vdev.ioctl_ops = &qcam_ioctl_ops; - qcam->vdev.release = video_device_release_empty; - video_set_drvdata(&qcam->vdev, qcam); - - mutex_init(&qcam->lock); - qcam->width = qcam->ccd_width = 320; - qcam->height = qcam->ccd_height = 240; - qcam->mode = QC_MILLIONS | QC_DECIMATION_1; - qcam->contrast = 192; - qcam->brightness = 240; - qcam->whitebal = 128; - qcam->top = 1; - qcam->left = 14; - return qcam; -} - -static int init_cqcam(struct parport *port) -{ - struct qcam *qcam; - struct v4l2_device *v4l2_dev; - - if (parport[0] != -1) { - /* The user gave specific instructions */ - int i, found = 0; - - for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) { - if (parport[0] == port->number) - found = 1; - } - if (!found) - return -ENODEV; - } - - if (num_cams == MAX_CAMS) - return -ENOSPC; - - qcam = qcam_init(port); - if (qcam == NULL) - return -ENODEV; - - v4l2_dev = &qcam->v4l2_dev; - - parport_claim_or_block(qcam->pdev); - - qc_reset(qcam); - - if (probe && qc_detect(qcam) == 0) { - parport_release(qcam->pdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - - qc_setup(qcam); - - parport_release(qcam->pdev); - - if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n", - qcam->pport->name); - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - - v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n", - video_device_node_name(&qcam->vdev), qcam->pport->name); - - qcams[num_cams++] = qcam; - - return 0; -} - -static void close_cqcam(struct qcam *qcam) -{ - video_unregister_device(&qcam->vdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); -} - -static void cq_attach(struct parport *port) -{ - init_cqcam(port); -} - -static void cq_detach(struct parport *port) -{ - /* Write this some day. */ -} - -static struct parport_driver cqcam_driver = { - .name = "cqcam", - .attach = cq_attach, - .detach = cq_detach, -}; - -static int __init cqcam_init(void) -{ - printk(KERN_INFO BANNER "\n"); - - return parport_register_driver(&cqcam_driver); -} - -static void __exit cqcam_cleanup(void) -{ - unsigned int i; - - for (i = 0; i < num_cams; i++) - close_cqcam(qcams[i]); - - parport_unregister_driver(&cqcam_driver); -} - -MODULE_AUTHOR("Philip Blundell "); -MODULE_DESCRIPTION(BANNER); -MODULE_LICENSE("GPL"); - -module_init(cqcam_init); -module_exit(cqcam_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs5345.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs5345.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs5345.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs5345.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,263 +0,0 @@ -/* - * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC"); -MODULE_AUTHOR("Hans Verkuil"); -MODULE_LICENSE("GPL"); - -static int debug; - -module_param(debug, bool, 0644); - -MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On"); - -struct cs5345_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; -}; - -static inline struct cs5345_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct cs5345_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct cs5345_state, hdl)->sd; -} - -/* ----------------------------------------------------------------------- */ - -static inline int cs5345_write(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_write_byte_data(client, reg, value); -} - -static inline int cs5345_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_read_byte_data(client, reg); -} - -static int cs5345_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - if ((input & 0xf) > 6) { - v4l2_err(sd, "Invalid input %d.\n", input); - return -EINVAL; - } - cs5345_write(sd, 0x09, input & 0xf); - cs5345_write(sd, 0x05, input & 0xf0); - return 0; -} - -static int cs5345_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - cs5345_write(sd, 0x04, ctrl->val ? 0x80 : 0); - return 0; - case V4L2_CID_AUDIO_VOLUME: - cs5345_write(sd, 0x07, ((u8)ctrl->val) & 0x3f); - cs5345_write(sd, 0x08, ((u8)ctrl->val) & 0x3f); - return 0; - } - return -EINVAL; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->size = 1; - reg->val = cs5345_read(sd, reg->reg & 0x1f); - return 0; -} - -static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - cs5345_write(sd, reg->reg & 0x1f, reg->val & 0xff); - return 0; -} -#endif - -static int cs5345_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_CS5345, 0); -} - -static int cs5345_log_status(struct v4l2_subdev *sd) -{ - u8 v = cs5345_read(sd, 0x09) & 7; - u8 m = cs5345_read(sd, 0x04); - int vol = cs5345_read(sd, 0x08) & 0x3f; - - v4l2_info(sd, "Input: %d%s\n", v, - (m & 0x80) ? " (muted)" : ""); - if (vol >= 32) - vol = vol - 64; - v4l2_info(sd, "Volume: %d dB\n", vol); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops cs5345_ctrl_ops = { - .s_ctrl = cs5345_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops cs5345_core_ops = { - .log_status = cs5345_log_status, - .g_chip_ident = cs5345_g_chip_ident, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = cs5345_g_register, - .s_register = cs5345_s_register, -#endif -}; - -static const struct v4l2_subdev_audio_ops cs5345_audio_ops = { - .s_routing = cs5345_s_routing, -}; - -static const struct v4l2_subdev_ops cs5345_ops = { - .core = &cs5345_core_ops, - .audio = &cs5345_audio_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int cs5345_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct cs5345_state *state; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kzalloc(sizeof(struct cs5345_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &cs5345_ops); - - v4l2_ctrl_handler_init(&state->hdl, 2); - v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, -24, 24, 1, 0); - sd->ctrl_handler = &state->hdl; - if (state->hdl.error) { - int err = state->hdl.error; - - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return err; - } - /* set volume/mute */ - v4l2_ctrl_handler_setup(&state->hdl); - - cs5345_write(sd, 0x02, 0x00); - cs5345_write(sd, 0x04, 0x01); - cs5345_write(sd, 0x09, 0x01); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int cs5345_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct cs5345_state *state = to_state(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id cs5345_id[] = { - { "cs5345", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, cs5345_id); - -static struct i2c_driver cs5345_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "cs5345", - }, - .probe = cs5345_probe, - .remove = cs5345_remove, - .id_table = cs5345_id, -}; - -static __init int init_cs5345(void) -{ - return i2c_add_driver(&cs5345_driver); -} - -static __exit void exit_cs5345(void) -{ - i2c_del_driver(&cs5345_driver); -} - -module_init(init_cs5345); -module_exit(exit_cs5345); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs53l32a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs53l32a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs53l32a.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs53l32a.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,262 +0,0 @@ -/* - * cs53l32a (Adaptec AVC-2010 and AVC-2410) i2c ivtv driver. - * Copyright (C) 2005 Martin Vaughan - * - * Audio source switching for Adaptec AVC-2410 added by Trev Jackson - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); -MODULE_AUTHOR("Martin Vaughan"); -MODULE_LICENSE("GPL"); - -static int debug; - -module_param(debug, bool, 0644); - -MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On"); - - -struct cs53l32a_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; -}; - -static inline struct cs53l32a_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct cs53l32a_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct cs53l32a_state, hdl)->sd; -} - -/* ----------------------------------------------------------------------- */ - -static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_read_byte_data(client, reg); -} - -static int cs53l32a_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - /* There are 2 physical inputs, but the second input can be - placed in two modes, the first mode bypasses the PGA (gain), - the second goes through the PGA. Hence there are three - possible inputs to choose from. */ - if (input > 2) { - v4l2_err(sd, "Invalid input %d.\n", input); - return -EINVAL; - } - cs53l32a_write(sd, 0x01, 0x01 + (input << 4)); - return 0; -} - -static int cs53l32a_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - cs53l32a_write(sd, 0x03, ctrl->val ? 0xf0 : 0x30); - return 0; - case V4L2_CID_AUDIO_VOLUME: - cs53l32a_write(sd, 0x04, (u8)ctrl->val); - cs53l32a_write(sd, 0x05, (u8)ctrl->val); - return 0; - } - return -EINVAL; -} - -static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, - chip, V4L2_IDENT_CS53l32A, 0); -} - -static int cs53l32a_log_status(struct v4l2_subdev *sd) -{ - struct cs53l32a_state *state = to_state(sd); - u8 v = cs53l32a_read(sd, 0x01); - - v4l2_info(sd, "Input: %d\n", (v >> 4) & 3); - v4l2_ctrl_handler_log_status(&state->hdl, sd->name); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops cs53l32a_ctrl_ops = { - .s_ctrl = cs53l32a_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops cs53l32a_core_ops = { - .log_status = cs53l32a_log_status, - .g_chip_ident = cs53l32a_g_chip_ident, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - -static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = { - .s_routing = cs53l32a_s_routing, -}; - -static const struct v4l2_subdev_ops cs53l32a_ops = { - .core = &cs53l32a_core_ops, - .audio = &cs53l32a_audio_ops, -}; - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ - -/* - * Generic i2c probe - * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' - */ - -static int cs53l32a_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct cs53l32a_state *state; - struct v4l2_subdev *sd; - int i; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - if (!id) - strlcpy(client->name, "cs53l32a", sizeof(client->name)); - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kzalloc(sizeof(struct cs53l32a_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops); - - for (i = 1; i <= 7; i++) { - u8 v = cs53l32a_read(sd, i); - - v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v); - } - - v4l2_ctrl_handler_init(&state->hdl, 2); - v4l2_ctrl_new_std(&state->hdl, &cs53l32a_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, -96, 12, 1, 0); - v4l2_ctrl_new_std(&state->hdl, &cs53l32a_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - sd->ctrl_handler = &state->hdl; - if (state->hdl.error) { - int err = state->hdl.error; - - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return err; - } - - /* Set cs53l32a internal register for Adaptec 2010/2410 setup */ - - cs53l32a_write(sd, 0x01, 0x21); - cs53l32a_write(sd, 0x02, 0x29); - cs53l32a_write(sd, 0x03, 0x30); - cs53l32a_write(sd, 0x04, 0x00); - cs53l32a_write(sd, 0x05, 0x00); - cs53l32a_write(sd, 0x06, 0x00); - cs53l32a_write(sd, 0x07, 0x00); - - /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */ - - for (i = 1; i <= 7; i++) { - u8 v = cs53l32a_read(sd, i); - - v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v); - } - return 0; -} - -static int cs53l32a_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct cs53l32a_state *state = to_state(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return 0; -} - -static const struct i2c_device_id cs53l32a_id[] = { - { "cs53l32a", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, cs53l32a_id); - -static struct i2c_driver cs53l32a_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "cs53l32a", - }, - .probe = cs53l32a_probe, - .remove = cs53l32a_remove, - .id_table = cs53l32a_id, -}; - -static __init int init_cs53l32a(void) -{ - return i2c_add_driver(&cs53l32a_driver); -} - -static __exit void exit_cs53l32a(void) -{ - i2c_del_driver(&cs53l32a_driver); -} - -module_init(init_cs53l32a); -module_exit(exit_cs53l32a); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs8420.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs8420.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs8420.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cs8420.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* cs8420.h - cs8420 initializations - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ -#ifndef __CS8420_H__ -#define __CS8420_H__ - -/* Initialization Sequence */ - -static __u8 init8420[] = { - 1, 0x01, 2, 0x02, 3, 0x00, 4, 0x46, - 5, 0x24, 6, 0x84, 18, 0x18, 19, 0x13, -}; - -#define INIT8420LEN (sizeof(init8420)/2) - -static __u8 mode8420pro[] = { /* professional output mode */ - 32, 0xa1, 33, 0x00, 34, 0x00, 35, 0x00, - 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, - 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, - 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, - 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, - 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, -}; -#define MODE8420LEN (sizeof(mode8420pro)/2) - -static __u8 mode8420con[] = { /* consumer output mode */ - 32, 0x20, 33, 0x00, 34, 0x00, 35, 0x48, - 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, - 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, - 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, - 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, - 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/* - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -struct snd_card; - -struct snd_cx18_card { - struct v4l2_device *v4l2_dev; - struct snd_card *sc; - unsigned int capture_transfer_done; - unsigned int hwptr_done_capture; - struct snd_pcm_substream *capture_pcm_substream; - spinlock_t slock; -}; - -extern int cx18_alsa_debug; - -/* - * File operations that manipulate the encoder or video or audio subdevices - * need to be serialized. Use the same lock we use for v4l2 file ops. - */ -static inline void snd_cx18_lock(struct snd_cx18_card *cxsc) -{ - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - mutex_lock(&cx->serialize_lock); -} - -static inline void snd_cx18_unlock(struct snd_cx18_card *cxsc) -{ - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - mutex_unlock(&cx->serialize_lock); -} - -#define CX18_ALSA_DBGFLG_WARN (1 << 0) -#define CX18_ALSA_DBGFLG_WARN (1 << 0) -#define CX18_ALSA_DBGFLG_INFO (1 << 1) - -#define CX18_ALSA_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & cx18_alsa_debug) \ - printk(KERN_INFO "%s-alsa: " type ": " fmt, \ - v4l2_dev->name , ## args); \ - } while (0) - -#define CX18_ALSA_DEBUG_WARN(fmt, args...) \ - CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_WARN, "warning", fmt , ## args) - -#define CX18_ALSA_DEBUG_INFO(fmt, args...) \ - CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_INFO, "info", fmt , ## args) - -#define CX18_ALSA_ERR(fmt, args...) \ - printk(KERN_ERR "%s-alsa: " fmt, v4l2_dev->name , ## args) - -#define CX18_ALSA_WARN(fmt, args...) \ - printk(KERN_WARNING "%s-alsa: " fmt, v4l2_dev->name , ## args) - -#define CX18_ALSA_INFO(fmt, args...) \ - printk(KERN_INFO "%s-alsa: " fmt, v4l2_dev->name , ## args) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-main.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-main.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-main.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-main.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,293 +0,0 @@ -/* - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls - * Copyright (C) 2009 Devin Heitmueller - * - * Portions of this work were sponsored by ONELAN Limited. - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "cx18-driver.h" -#include "cx18-version.h" -#include "cx18-alsa.h" -#include "cx18-alsa-mixer.h" -#include "cx18-alsa-pcm.h" - -int cx18_alsa_debug; - -#define CX18_DEBUG_ALSA_INFO(fmt, arg...) \ - do { \ - if (cx18_alsa_debug & 2) \ - printk(KERN_INFO "%s: " fmt, "cx18-alsa", ## arg); \ - } while (0); - -module_param_named(debug, cx18_alsa_debug, int, 0644); -MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: 0\n" - "\t\t\t 1/0x0001: warning\n" - "\t\t\t 2/0x0002: info\n"); - -MODULE_AUTHOR("Andy Walls"); -MODULE_DESCRIPTION("CX23418 ALSA Interface"); -MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); -MODULE_LICENSE("GPL"); - - -static inline -struct snd_cx18_card *to_snd_cx18_card(struct v4l2_device *v4l2_dev) -{ - return to_cx18(v4l2_dev)->alsa; -} - -static inline -struct snd_cx18_card *p_to_snd_cx18_card(struct v4l2_device **v4l2_dev) -{ - return container_of(v4l2_dev, struct snd_cx18_card, v4l2_dev); -} - -static void snd_cx18_card_free(struct snd_cx18_card *cxsc) -{ - if (cxsc == NULL) - return; - - if (cxsc->v4l2_dev != NULL) - to_cx18(cxsc->v4l2_dev)->alsa = NULL; - - /* FIXME - take any other stopping actions needed */ - - kfree(cxsc); -} - -static void snd_cx18_card_private_free(struct snd_card *sc) -{ - if (sc == NULL) - return; - snd_cx18_card_free(sc->private_data); - sc->private_data = NULL; - sc->private_free = NULL; -} - -static int snd_cx18_card_create(struct v4l2_device *v4l2_dev, - struct snd_card *sc, - struct snd_cx18_card **cxsc) -{ - *cxsc = kzalloc(sizeof(struct snd_cx18_card), GFP_KERNEL); - if (*cxsc == NULL) - return -ENOMEM; - - (*cxsc)->v4l2_dev = v4l2_dev; - (*cxsc)->sc = sc; - - sc->private_data = *cxsc; - sc->private_free = snd_cx18_card_private_free; - - return 0; -} - -static int snd_cx18_card_set_names(struct snd_cx18_card *cxsc) -{ - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct snd_card *sc = cxsc->sc; - - /* sc->driver is used by alsa-lib's configurator: simple, unique */ - strlcpy(sc->driver, "CX23418", sizeof(sc->driver)); - - /* sc->shortname is a symlink in /proc/asound: CX18-M -> cardN */ - snprintf(sc->shortname, sizeof(sc->shortname), "CX18-%d", - cx->instance); - - /* sc->longname is read from /proc/asound/cards */ - snprintf(sc->longname, sizeof(sc->longname), - "CX23418 #%d %s TV/FM Radio/Line-In Capture", - cx->instance, cx->card_name); - - return 0; -} - -static int snd_cx18_init(struct v4l2_device *v4l2_dev) -{ - struct cx18 *cx = to_cx18(v4l2_dev); - struct snd_card *sc = NULL; - struct snd_cx18_card *cxsc; - int ret; - - /* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */ - - /* (1) Check and increment the device index */ - /* This is a no-op for us. We'll use the cx->instance */ - - /* (2) Create a card instance */ - ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */ - SNDRV_DEFAULT_STR1, /* xid from end of shortname*/ - THIS_MODULE, 0, &sc); - if (ret) { - CX18_ALSA_ERR("%s: snd_card_create() failed with err %d\n", - __func__, ret); - goto err_exit; - } - - /* (3) Create a main component */ - ret = snd_cx18_card_create(v4l2_dev, sc, &cxsc); - if (ret) { - CX18_ALSA_ERR("%s: snd_cx18_card_create() failed with err %d\n", - __func__, ret); - goto err_exit_free; - } - - /* (4) Set the driver ID and name strings */ - snd_cx18_card_set_names(cxsc); - - - ret = snd_cx18_pcm_create(cxsc); - if (ret) { - CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n", - __func__, ret); - goto err_exit_free; - } - /* FIXME - proc files */ - - /* (7) Set the driver data and return 0 */ - /* We do this out of normal order for PCI drivers to avoid races */ - cx->alsa = cxsc; - - /* (6) Register the card instance */ - ret = snd_card_register(sc); - if (ret) { - cx->alsa = NULL; - CX18_ALSA_ERR("%s: snd_card_register() failed with err %d\n", - __func__, ret); - goto err_exit_free; - } - - return 0; - -err_exit_free: - if (sc != NULL) - snd_card_free(sc); -err_exit: - return ret; -} - -int cx18_alsa_load(struct cx18 *cx) -{ - struct v4l2_device *v4l2_dev = &cx->v4l2_dev; - struct cx18_stream *s; - - if (v4l2_dev == NULL) { - printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n", - __func__); - return 0; - } - - cx = to_cx18(v4l2_dev); - if (cx == NULL) { - printk(KERN_ERR "cx18-alsa cx is NULL\n"); - return 0; - } - - s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; - if (s->video_dev == NULL) { - CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - " - "skipping\n", __func__); - return 0; - } - - if (cx->alsa != NULL) { - CX18_ALSA_ERR("%s: struct snd_cx18_card * already exists\n", - __func__); - return 0; - } - - if (snd_cx18_init(v4l2_dev)) { - CX18_ALSA_ERR("%s: failed to create struct snd_cx18_card\n", - __func__); - } else { - CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance " - "\n", __func__); - } - return 0; -} - -static int __init cx18_alsa_init(void) -{ - printk(KERN_INFO "cx18-alsa: module loading...\n"); - cx18_ext_init = &cx18_alsa_load; - return 0; -} - -static void __exit snd_cx18_exit(struct snd_cx18_card *cxsc) -{ - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - - /* FIXME - pointer checks & shutdown cxsc */ - - snd_card_free(cxsc->sc); - cx->alsa = NULL; -} - -static int __exit cx18_alsa_exit_callback(struct device *dev, void *data) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); - struct snd_cx18_card *cxsc; - - if (v4l2_dev == NULL) { - printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n", - __func__); - return 0; - } - - cxsc = to_snd_cx18_card(v4l2_dev); - if (cxsc == NULL) { - CX18_ALSA_WARN("%s: struct snd_cx18_card * is NULL\n", - __func__); - return 0; - } - - snd_cx18_exit(cxsc); - return 0; -} - -static void __exit cx18_alsa_exit(void) -{ - struct device_driver *drv; - int ret; - - printk(KERN_INFO "cx18-alsa: module unloading...\n"); - - drv = driver_find("cx18", &pci_bus_type); - ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback); - put_driver(drv); - - cx18_ext_init = NULL; - printk(KERN_INFO "cx18-alsa: module unload complete\n"); -} - -module_init(cx18_alsa_init); -module_exit(cx18_alsa_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-mixer.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-mixer.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-mixer.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-mixer.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "cx18-alsa.h" -#include "cx18-driver.h" - -/* - * Note the cx18-av-core volume scale is funny, due to the alignment of the - * scale with another chip's range: - * - * v4l2_control value /512 indicated dB actual dB reg 0x8d4 - * 0x0000 - 0x01ff 0 -119 -96 228 - * 0x0200 - 0x02ff 1 -118 -96 228 - * ... - * 0x2c00 - 0x2dff 22 -97 -96 228 - * 0x2e00 - 0x2fff 23 -96 -96 228 - * 0x3000 - 0x31ff 24 -95 -95 226 - * ... - * 0xee00 - 0xefff 119 0 0 36 - * ... - * 0xfe00 - 0xffff 127 +8 +8 20 - */ -static inline int dB_to_cx18_av_vol(int dB) -{ - if (dB < -96) - dB = -96; - else if (dB > 8) - dB = 8; - return (dB + 119) << 9; -} - -static inline int cx18_av_vol_to_dB(int v) -{ - if (v < (23 << 9)) - v = (23 << 9); - else if (v > (127 << 9)) - v = (127 << 9); - return (v >> 9) - 119; -} - -static int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - /* We're already translating values, just keep this control in dB */ - uinfo->value.integer.min = -96; - uinfo->value.integer.max = 8; - uinfo->value.integer.step = 1; - return 0; -} - -static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - - snd_cx18_lock(cxsc); - ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl); - snd_cx18_unlock(cxsc); - - if (!ret) - uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value); - return ret; -} - -static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - - snd_cx18_lock(cxsc); - - /* Fetch current state */ - ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl); - - if (ret || - (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { - - /* Set, if needed */ - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - ret = v4l2_subdev_call(cx->sd_av, core, s_ctrl, &vctrl); - if (!ret) - ret = 1; /* Indicate control was changed w/o error */ - } - snd_cx18_unlock(cxsc); - - return ret; -} - - -/* This is a bit of overkill, the slider is already in dB internally */ -static DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0); - -static struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog TV Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = snd_cx18_mixer_tv_volume_info, - .get = snd_cx18_mixer_tv_volume_get, - .put = snd_cx18_mixer_tv_volume_put, - .tlv.p = snd_cx18_mixer_tv_vol_db_scale -}; - -/* FIXME - add mute switch and balance, bass, treble sliders: - V4L2_CID_AUDIO_MUTE - - V4L2_CID_AUDIO_BALANCE - - V4L2_CID_AUDIO_BASS - V4L2_CID_AUDIO_TREBLE -*/ - -/* FIXME - add stereo, lang1, lang2, mono menu */ -/* FIXME - add CS5345 I2S volume for HVR-1600 */ - -int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc) -{ - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct snd_card *sc = cxsc->sc; - int ret; - - strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername)); - - ret = snd_ctl_add(sc, snd_ctl_new1(snd_cx18_mixer_tv_vol, cxsc)); - if (ret) { - CX18_ALSA_WARN("%s: failed to add %s control, err %d\n", - __func__, snd_cx18_mixer_tv_vol.name, ret); - } - return ret; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-mixer.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-mixer.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-mixer.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-mixer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-pcm.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-pcm.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-pcm.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-pcm.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,360 +0,0 @@ -/* - * ALSA PCM device for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls - * Copyright (C) 2009 Devin Heitmueller - * - * Portions of this work were sponsored by ONELAN Limited. - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include - -#include - -#include -#include - -#include "cx18-driver.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-fileops.h" -#include "cx18-alsa.h" - -static unsigned int pcm_debug; -module_param(pcm_debug, int, 0644); -MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); - -#define dprintk(fmt, arg...) do { \ - if (pcm_debug) \ - printk(KERN_INFO "cx18-alsa-pcm %s: " fmt, \ - __func__, ##arg); \ - } while (0) - -static struct snd_pcm_hardware snd_cx18_hw_capture = { - .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID, - - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_48000, - - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ - .period_bytes_min = 64, /* 12544/2, */ - .period_bytes_max = 12544, - .periods_min = 2, - .periods_max = 98, /* 12544, */ -}; - -void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data, - size_t num_bytes) -{ - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - unsigned int oldptr; - unsigned int stride; - int period_elapsed = 0; - int length; - - dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc, - pcm_data, num_bytes); - - substream = cxsc->capture_pcm_substream; - if (substream == NULL) { - dprintk("substream was NULL\n"); - return; - } - - runtime = substream->runtime; - if (runtime == NULL) { - dprintk("runtime was NULL\n"); - return; - } - - stride = runtime->frame_bits >> 3; - if (stride == 0) { - dprintk("stride is zero\n"); - return; - } - - length = num_bytes / stride; - if (length == 0) { - dprintk("%s: length was zero\n", __func__); - return; - } - - if (runtime->dma_area == NULL) { - dprintk("dma area was NULL - ignoring\n"); - return; - } - - oldptr = cxsc->hwptr_done_capture; - if (oldptr + length >= runtime->buffer_size) { - unsigned int cnt = - runtime->buffer_size - oldptr; - memcpy(runtime->dma_area + oldptr * stride, pcm_data, - cnt * stride); - memcpy(runtime->dma_area, pcm_data + cnt * stride, - length * stride - cnt * stride); - } else { - memcpy(runtime->dma_area + oldptr * stride, pcm_data, - length * stride); - } - snd_pcm_stream_lock(substream); - - cxsc->hwptr_done_capture += length; - if (cxsc->hwptr_done_capture >= - runtime->buffer_size) - cxsc->hwptr_done_capture -= - runtime->buffer_size; - - cxsc->capture_transfer_done += length; - if (cxsc->capture_transfer_done >= - runtime->period_size) { - cxsc->capture_transfer_done -= - runtime->period_size; - period_elapsed = 1; - } - - snd_pcm_stream_unlock(substream); - - if (period_elapsed) - snd_pcm_period_elapsed(substream); -} - -static int snd_cx18_pcm_capture_open(struct snd_pcm_substream *substream) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct cx18 *cx = to_cx18(v4l2_dev); - struct cx18_stream *s; - struct cx18_open_id item; - int ret; - - /* Instruct the cx18 to start sending packets */ - snd_cx18_lock(cxsc); - s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; - - item.cx = cx; - item.type = s->type; - item.open_id = cx->open_id++; - - /* See if the stream is available */ - if (cx18_claim_stream(&item, item.type)) { - /* No, it's already in use */ - snd_cx18_unlock(cxsc); - return -EBUSY; - } - - if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || - test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { - /* We're already streaming. No additional action required */ - snd_cx18_unlock(cxsc); - return 0; - } - - - runtime->hw = snd_cx18_hw_capture; - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - cxsc->capture_pcm_substream = substream; - runtime->private_data = cx; - - cx->pcm_announce_callback = cx18_alsa_announce_pcm_data; - - /* Not currently streaming, so start it up */ - set_bit(CX18_F_S_STREAMING, &s->s_flags); - ret = cx18_start_v4l2_encode_stream(s); - snd_cx18_unlock(cxsc); - - return 0; -} - -static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct cx18 *cx = to_cx18(v4l2_dev); - struct cx18_stream *s; - int ret; - - /* Instruct the cx18 to stop sending packets */ - snd_cx18_lock(cxsc); - s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; - ret = cx18_stop_v4l2_encode_stream(s, 0); - clear_bit(CX18_F_S_STREAMING, &s->s_flags); - - cx18_release_stream(s); - - cx->pcm_announce_callback = NULL; - snd_cx18_unlock(cxsc); - - return 0; -} - -static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - int ret; - - snd_cx18_lock(cxsc); - ret = snd_pcm_lib_ioctl(substream, cmd, arg); - snd_cx18_unlock(cxsc); - return ret; -} - - -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, - size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - dprintk("Allocating vbuffer\n"); - if (runtime->dma_area) { - if (runtime->dma_bytes > size) - return 0; - - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc(size); - if (!runtime->dma_area) - return -ENOMEM; - - runtime->dma_bytes = size; - - return 0; -} - -static int snd_cx18_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - int ret; - - dprintk("%s called\n", __func__); - - ret = snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(params)); - return 0; -} - -static int snd_cx18_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - unsigned long flags; - - spin_lock_irqsave(&cxsc->slock, flags); - if (substream->runtime->dma_area) { - dprintk("freeing pcm capture region\n"); - vfree(substream->runtime->dma_area); - substream->runtime->dma_area = NULL; - } - spin_unlock_irqrestore(&cxsc->slock, flags); - - return 0; -} - -static int snd_cx18_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - - cxsc->hwptr_done_capture = 0; - cxsc->capture_transfer_done = 0; - - return 0; -} - -static int snd_cx18_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - return 0; -} - -static -snd_pcm_uframes_t snd_cx18_pcm_pointer(struct snd_pcm_substream *substream) -{ - unsigned long flags; - snd_pcm_uframes_t hwptr_done; - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - - spin_lock_irqsave(&cxsc->slock, flags); - hwptr_done = cxsc->hwptr_done_capture; - spin_unlock_irqrestore(&cxsc->slock, flags); - - return hwptr_done; -} - -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - - return vmalloc_to_page(pageptr); -} - -static struct snd_pcm_ops snd_cx18_pcm_capture_ops = { - .open = snd_cx18_pcm_capture_open, - .close = snd_cx18_pcm_capture_close, - .ioctl = snd_cx18_pcm_ioctl, - .hw_params = snd_cx18_pcm_hw_params, - .hw_free = snd_cx18_pcm_hw_free, - .prepare = snd_cx18_pcm_prepare, - .trigger = snd_cx18_pcm_trigger, - .pointer = snd_cx18_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, -}; - -int snd_cx18_pcm_create(struct snd_cx18_card *cxsc) -{ - struct snd_pcm *sp; - struct snd_card *sc = cxsc->sc; - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct cx18 *cx = to_cx18(v4l2_dev); - int ret; - - ret = snd_pcm_new(sc, "CX23418 PCM", - 0, /* PCM device 0, the only one for this card */ - 0, /* 0 playback substreams */ - 1, /* 1 capture substream */ - &sp); - if (ret) { - CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n", - __func__, ret); - goto err_exit; - } - - spin_lock_init(&cxsc->slock); - - snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE, - &snd_cx18_pcm_capture_ops); - sp->info_flags = 0; - sp->private_data = cxsc; - strlcpy(sp->name, cx->card_name, sizeof(sp->name)); - - return 0; - -err_exit: - return ret; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-pcm.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-pcm.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-pcm.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-alsa-pcm.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* - * ALSA PCM device for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -int __init snd_cx18_pcm_create(struct snd_cx18_card *cxsc); - -/* Used by cx18-mailbox to announce the PCM data to the module */ -void cx18_alsa_announce_pcm_data(struct snd_cx18_card *card, u8 *pcm_data, - size_t num_bytes); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-audio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-audio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/* - * cx18 audio-related functions - * - * Derived from ivtv-audio.c - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-cards.h" -#include "cx18-audio.h" - -#define CX18_AUDIO_ENABLE 0xc72014 -#define CX18_AI1_MUX_MASK 0x30 -#define CX18_AI1_MUX_I2S1 0x00 -#define CX18_AI1_MUX_I2S2 0x10 -#define CX18_AI1_MUX_843_I2S 0x20 - -/* Selects the audio input and output according to the current - settings. */ -int cx18_audio_set_io(struct cx18 *cx) -{ - const struct cx18_card_audio_input *in; - u32 u, v; - int err; - - /* Determine which input to use */ - if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) - in = &cx->card->radio_input; - else - in = &cx->card->audio_inputs[cx->audio_input]; - - /* handle muxer chips */ - v4l2_subdev_call(cx->sd_extmux, audio, s_routing, - (u32) in->muxer_input, 0, 0); - - err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl, - audio, s_routing, in->audio_input, 0, 0); - if (err) - return err; - - /* FIXME - this internal mux should be abstracted to a subdev */ - u = cx18_read_reg(cx, CX18_AUDIO_ENABLE); - v = u & ~CX18_AI1_MUX_MASK; - switch (in->audio_input) { - case CX18_AV_AUDIO_SERIAL1: - v |= CX18_AI1_MUX_I2S1; - break; - case CX18_AV_AUDIO_SERIAL2: - v |= CX18_AI1_MUX_I2S2; - break; - default: - v |= CX18_AI1_MUX_843_I2S; - break; - } - if (v == u) { - /* force a toggle of some AI1 MUX control bits */ - u &= ~CX18_AI1_MUX_MASK; - switch (in->audio_input) { - case CX18_AV_AUDIO_SERIAL1: - u |= CX18_AI1_MUX_843_I2S; - break; - case CX18_AV_AUDIO_SERIAL2: - u |= CX18_AI1_MUX_843_I2S; - break; - default: - u |= CX18_AI1_MUX_I2S1; - break; - } - cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE, - u, CX18_AI1_MUX_MASK); - } - cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, - v, CX18_AI1_MUX_MASK); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-audio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-audio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-audio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-audio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -/* - * cx18 audio-related functions - * - * Derived from ivtv-audio.c - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -int cx18_audio_set_io(struct cx18 *cx); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-audio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-audio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,471 +0,0 @@ -/* - * cx18 ADEC audio functions - * - * Derived from cx25840-audio.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "cx18-driver.h" - -static int set_audclk_freq(struct cx18 *cx, u32 freq) -{ - struct cx18_av_state *state = &cx->av_state; - - if (freq != 32000 && freq != 44100 && freq != 48000) - return -EINVAL; - - /* - * The PLL parameters are based on the external crystal frequency that - * would ideally be: - * - * NTSC Color subcarrier freq * 8 = - * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz - * - * The accidents of history and rationale that explain from where this - * combination of magic numbers originate can be found in: - * - * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in - * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80 - * - * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the - * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83 - * - * As Mike Bradley has rightly pointed out, it's not the exact crystal - * frequency that matters, only that all parts of the driver and - * firmware are using the same value (close to the ideal value). - * - * Since I have a strong suspicion that, if the firmware ever assumes a - * crystal value at all, it will assume 28.636360 MHz, the crystal - * freq used in calculations in this driver will be: - * - * xtal_freq = 28.636360 MHz - * - * an error of less than 0.13 ppm which is way, way better than any off - * the shelf crystal will have for accuracy anyway. - * - * Below I aim to run the PLLs' VCOs near 400 MHz to minimze error. - * - * Many thanks to Jeff Campbell and Mike Bradley for their extensive - * investigation, experimentation, testing, and suggested solutions of - * of audio/video sync problems with SVideo and CVBS captures. - */ - - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - switch (freq) { - case 32000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20 - */ - cx18_av_write4(cx, 0x108, 0x200d040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x176740c */ - /* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0176740c); - - /* src3/4/6_ctl */ - /* 0x1.f77f = (4 * xtal/8*2/455) / 32000 */ - cx18_av_write4(cx, 0x900, 0x0801f77f); - cx18_av_write4(cx, 0x904, 0x0801f77f); - cx18_av_write4(cx, 0x90c, 0x0801f77f); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */ - cx18_av_write(cx, 0x127, 0x60); - - /* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */ - cx18_av_write4(cx, 0x12c, 0x11202fff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = - * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa00d2ef8); - break; - - case 44100: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x18 - */ - cx18_av_write4(cx, 0x108, 0x180e040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x062a1f2 */ - /* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0062a1f2); - - /* src3/4/6_ctl */ - /* 0x1.6d59 = (4 * xtal/8*2/455) / 44100 */ - cx18_av_write4(cx, 0x900, 0x08016d59); - cx18_av_write4(cx, 0x904, 0x08016d59); - cx18_av_write4(cx, 0x90c, 0x08016d59); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x18 */ - cx18_av_write(cx, 0x127, 0x58); - - /* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */ - cx18_av_write4(cx, 0x12c, 0x112092ff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = - * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa01d4bf8); - break; - - case 48000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x16 - */ - cx18_av_write4(cx, 0x108, 0x160e040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x05227ad */ - /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x005227ad); - - /* src3/4/6_ctl */ - /* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */ - cx18_av_write4(cx, 0x900, 0x08014faa); - cx18_av_write4(cx, 0x904, 0x08014faa); - cx18_av_write4(cx, 0x90c, 0x08014faa); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ - cx18_av_write(cx, 0x127, 0x56); - - /* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */ - cx18_av_write4(cx, 0x12c, 0x11205fff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x1193f8 = 143999.000 * 8 = - * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa01193f8); - break; - } - } else { - switch (freq) { - case 32000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x30 - */ - cx18_av_write4(cx, 0x108, 0x300d040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x176740c */ - /* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0176740c); - - /* src1_ctl */ - /* 0x1.0000 = 32000/32000 */ - cx18_av_write4(cx, 0x8f8, 0x08010000); - - /* src3/4/6_ctl */ - /* 0x2.0000 = 2 * (32000/32000) */ - cx18_av_write4(cx, 0x900, 0x08020000); - cx18_av_write4(cx, 0x904, 0x08020000); - cx18_av_write4(cx, 0x90c, 0x08020000); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */ - cx18_av_write(cx, 0x127, 0x70); - - /* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */ - cx18_av_write4(cx, 0x12c, 0x11201fff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = - * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa00d2ef8); - break; - - case 44100: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x24 - */ - cx18_av_write4(cx, 0x108, 0x240e040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x062a1f2 */ - /* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0062a1f2); - - /* src1_ctl */ - /* 0x1.60cd = 44100/32000 */ - cx18_av_write4(cx, 0x8f8, 0x080160cd); - - /* src3/4/6_ctl */ - /* 0x1.7385 = 2 * (32000/44100) */ - cx18_av_write4(cx, 0x900, 0x08017385); - cx18_av_write4(cx, 0x904, 0x08017385); - cx18_av_write4(cx, 0x90c, 0x08017385); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x24 */ - cx18_av_write(cx, 0x127, 0x64); - - /* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */ - cx18_av_write4(cx, 0x12c, 0x112061ff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = - * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa01d4bf8); - break; - - case 48000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20 - */ - cx18_av_write4(cx, 0x108, 0x200d040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x176740c */ - /* xtal * 0xd.bb3a060/0x20 = 48000 * 256: 393 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0176740c); - - /* src1_ctl */ - /* 0x1.8000 = 48000/32000 */ - cx18_av_write4(cx, 0x8f8, 0x08018000); - - /* src3/4/6_ctl */ - /* 0x1.5555 = 2 * (32000/48000) */ - cx18_av_write4(cx, 0x900, 0x08015555); - cx18_av_write4(cx, 0x904, 0x08015555); - cx18_av_write4(cx, 0x90c, 0x08015555); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */ - cx18_av_write(cx, 0x127, 0x60); - - /* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */ - cx18_av_write4(cx, 0x12c, 0x11203fff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x1193f8 = 143999.000 * 8 = - * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa01193f8); - break; - } - } - - state->audclk_freq = freq; - - return 0; -} - -void cx18_av_audio_set_path(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - u8 v; - - /* stop microcontroller */ - v = cx18_av_read(cx, 0x803) & ~0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - - /* assert soft reset */ - v = cx18_av_read(cx, 0x810) | 0x01; - cx18_av_write_expect(cx, 0x810, v, v, 0x0f); - - /* Mute everything to prevent the PFFT! */ - cx18_av_write(cx, 0x8d3, 0x1f); - - if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) { - /* Set Path1 to Serial Audio Input */ - cx18_av_write4(cx, 0x8d0, 0x01011012); - - /* The microcontroller should not be started for the - * non-tuner inputs: autodetection is specific for - * TV audio. */ - } else { - /* Set Path1 to Analog Demod Main Channel */ - cx18_av_write4(cx, 0x8d0, 0x1f063870); - } - - set_audclk_freq(cx, state->audclk_freq); - - /* deassert soft reset */ - v = cx18_av_read(cx, 0x810) & ~0x01; - cx18_av_write_expect(cx, 0x810, v, v, 0x0f); - - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - /* When the microcontroller detects the - * audio format, it will unmute the lines */ - v = cx18_av_read(cx, 0x803) | 0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - } -} - -static void set_volume(struct cx18 *cx, int volume) -{ - /* First convert the volume to msp3400 values (0-127) */ - int vol = volume >> 9; - /* now scale it up to cx18_av values - * -114dB to -96dB maps to 0 - * this should be 19, but in my testing that was 4dB too loud */ - if (vol <= 23) - vol = 0; - else - vol -= 23; - - /* PATH1_VOLUME */ - cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); -} - -static void set_bass(struct cx18 *cx, int bass) -{ - /* PATH1_EQ_BASS_VOL */ - cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); -} - -static void set_treble(struct cx18 *cx, int treble) -{ - /* PATH1_EQ_TREBLE_VOL */ - cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); -} - -static void set_balance(struct cx18 *cx, int balance) -{ - int bal = balance >> 8; - if (bal > 0x80) { - /* PATH1_BAL_LEFT */ - cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80); - /* PATH1_BAL_LEVEL */ - cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f); - } else { - /* PATH1_BAL_LEFT */ - cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00); - /* PATH1_BAL_LEVEL */ - cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal); - } -} - -static void set_mute(struct cx18 *cx, int mute) -{ - struct cx18_av_state *state = &cx->av_state; - u8 v; - - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - /* Must turn off microcontroller in order to mute sound. - * Not sure if this is the best method, but it does work. - * If the microcontroller is running, then it will undo any - * changes to the mute register. */ - v = cx18_av_read(cx, 0x803); - if (mute) { - /* disable microcontroller */ - v &= ~0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - cx18_av_write(cx, 0x8d3, 0x1f); - } else { - /* enable microcontroller */ - v |= 0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - } - } else { - /* SRC1_MUTE_EN */ - cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00); - } -} - -int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - int retval; - u8 v; - - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - v = cx18_av_read(cx, 0x803) & ~0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - cx18_av_write(cx, 0x8d3, 0x1f); - } - v = cx18_av_read(cx, 0x810) | 0x1; - cx18_av_write_expect(cx, 0x810, v, v, 0x0f); - - retval = set_audclk_freq(cx, freq); - - v = cx18_av_read(cx, 0x810) & ~0x1; - cx18_av_write_expect(cx, 0x810, v, v, 0x0f); - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - v = cx18_av_read(cx, 0x803) | 0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - } - return retval; -} - -static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct cx18 *cx = v4l2_get_subdevdata(sd); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - set_volume(cx, ctrl->val); - break; - case V4L2_CID_AUDIO_BASS: - set_bass(cx, ctrl->val); - break; - case V4L2_CID_AUDIO_TREBLE: - set_treble(cx, ctrl->val); - break; - case V4L2_CID_AUDIO_BALANCE: - set_balance(cx, ctrl->val); - break; - case V4L2_CID_AUDIO_MUTE: - set_mute(cx, ctrl->val); - break; - default: - return -EINVAL; - } - return 0; -} - -const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = { - .s_ctrl = cx18_av_audio_s_ctrl, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1401 +0,0 @@ -/* - * cx18 ADEC audio functions - * - * Derived from cx25840-core.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-cards.h" - -int cx18_av_write(struct cx18 *cx, u16 addr, u8 value) -{ - u32 reg = 0xc40000 + (addr & ~3); - u32 mask = 0xff; - int shift = (addr & 3) * 8; - u32 x = cx18_read_reg(cx, reg); - - x = (x & ~(mask << shift)) | ((u32)value << shift); - cx18_write_reg(cx, x, reg); - return 0; -} - -int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask) -{ - u32 reg = 0xc40000 + (addr & ~3); - int shift = (addr & 3) * 8; - u32 x = cx18_read_reg(cx, reg); - - x = (x & ~((u32)0xff << shift)) | ((u32)value << shift); - cx18_write_reg_expect(cx, x, reg, - ((u32)eval << shift), ((u32)mask << shift)); - return 0; -} - -int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) -{ - cx18_write_reg(cx, value, 0xc40000 + addr); - return 0; -} - -int -cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, u32 mask) -{ - cx18_write_reg_expect(cx, value, 0xc40000 + addr, eval, mask); - return 0; -} - -int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value) -{ - cx18_write_reg_noretry(cx, value, 0xc40000 + addr); - return 0; -} - -u8 cx18_av_read(struct cx18 *cx, u16 addr) -{ - u32 x = cx18_read_reg(cx, 0xc40000 + (addr & ~3)); - int shift = (addr & 3) * 8; - - return (x >> shift) & 0xff; -} - -u32 cx18_av_read4(struct cx18 *cx, u16 addr) -{ - return cx18_read_reg(cx, 0xc40000 + addr); -} - -int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask, - u8 or_value) -{ - return cx18_av_write(cx, addr, - (cx18_av_read(cx, addr) & and_mask) | - or_value); -} - -int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, - u32 or_value) -{ - return cx18_av_write4(cx, addr, - (cx18_av_read4(cx, addr) & and_mask) | - or_value); -} - -static void cx18_av_init(struct cx18 *cx) -{ - /* - * The crystal freq used in calculations in this driver will be - * 28.636360 MHz. - * Aim to run the PLLs' VCOs near 400 MHz to minimze errors. - */ - - /* - * VDCLK Integer = 0x0f, Post Divider = 0x04 - * AIMCLK Integer = 0x0e, Post Divider = 0x16 - */ - cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f); - - /* VDCLK Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */ - cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe); - - /* AIMCLK Fraction = 0x05227ad */ - /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/ - cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ - cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56); -} - -static void cx18_av_initialize(struct v4l2_subdev *sd) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - int default_volume; - u32 v; - - cx18_av_loadfw(cx); - /* Stop 8051 code execution */ - cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x03000000, - 0x03000000, 0x13000000); - - /* initallize the PLL by toggling sleep bit */ - v = cx18_av_read4(cx, CXADEC_HOST_REG1); - /* enable sleep mode - register appears to be read only... */ - cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v | 1, v, 0xfffe); - /* disable sleep mode */ - cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v & 0xfffe, - v & 0xfffe, 0xffff); - - /* initialize DLLs */ - v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF; - /* disable FLD */ - cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v); - /* enable FLD */ - cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100); - - v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF; - /* disable FLD */ - cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v); - /* enable FLD */ - cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100); - - /* set analog bias currents. Set Vreg to 1.20V. */ - cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802); - - v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1; - /* enable TUNE_FIL_RST */ - cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, v, v, 0x03009F0F); - /* disable TUNE_FIL_RST */ - cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, - v & 0xFFFFFFFE, v & 0xFFFFFFFE, 0x03009F0F); - - /* enable 656 output */ - cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00); - - /* video output drive strength */ - cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2); - - /* reset video */ - cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000); - cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0); - - /* - * Disable Video Auto-config of the Analog Front End and Video PLL. - * - * Since we only use BT.656 pixel mode, which works for both 525 and 625 - * line systems, it's just easier for us to set registers - * 0x102 (CXADEC_CHIP_CTRL), 0x104-0x106 (CXADEC_AFE_CTRL), - * 0x108-0x109 (CXADEC_PLL_CTRL1), and 0x10c-0x10f (CXADEC_VID_PLL_FRAC) - * ourselves, than to run around cleaning up after the auto-config. - * - * (Note: my CX23418 chip doesn't seem to let the ACFG_DIS bit - * get set to 1, but OTOH, it doesn't seem to do AFE and VID PLL - * autoconfig either.) - * - * As a default, also turn off Dual mode for ADC2 and set ADC2 to CH3. - */ - cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000); - - /* Setup the Video and and Aux/Audio PLLs */ - cx18_av_init(cx); - - /* set video to auto-detect */ - /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ - /* set the comb notch = 1 */ - cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800); - - /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */ - /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */ - cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000); - - /* Set VGA_TRACK_RANGE to 0x20 */ - cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000); - - /* - * Initial VBI setup - * VIP-1.1, 10 bit mode, enable Raw, disable sliced, - * don't clamp raw samples when codes are in use, 1 byte user D-words, - * IDID0 has line #, RP code V bit transition on VBLANK, data during - * blanking intervals - */ - cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4013252e); - - /* Set the video input. - The setting in MODE_CTRL gets lost when we do the above setup */ - /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */ - /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */ - - /* - * Analog Front End (AFE) - * Default to luma on ch1/ADC1, chroma on ch2/ADC2, SIF on ch3/ADC2 - * bypass_ch[1-3] use filter - * droop_comp_ch[1-3] disable - * clamp_en_ch[1-3] disable - * aud_in_sel ADC2 - * luma_in_sel ADC1 - * chroma_in_sel ADC2 - * clamp_sel_ch[2-3] midcode - * clamp_sel_ch1 video decoder - * vga_sel_ch3 audio decoder - * vga_sel_ch[1-2] video decoder - * half_bw_ch[1-3] disable - * +12db_ch[1-3] disable - */ - cx18_av_and_or4(cx, CXADEC_AFE_CTRL, 0xFF000000, 0x00005D00); - -/* if(dwEnable && dw3DCombAvailable) { */ -/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */ -/* } else { */ -/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ -/* } */ - cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); - default_volume = cx18_av_read(cx, 0x8d4); - /* - * Enforce the legacy volume scale mapping limits to avoid - * -ERANGE errors when initializing the volume control - */ - if (default_volume > 228) { - /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ - default_volume = 228; - cx18_av_write(cx, 0x8d4, 228); - } else if (default_volume < 20) { - /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ - default_volume = 20; - cx18_av_write(cx, 0x8d4, 20); - } - default_volume = (((228 - default_volume) >> 1) + 23) << 9; - state->volume->cur.val = state->volume->default_value = default_volume; - v4l2_ctrl_handler_setup(&state->hdl); -} - -static int cx18_av_reset(struct v4l2_subdev *sd, u32 val) -{ - cx18_av_initialize(sd); - return 0; -} - -static int cx18_av_load_fw(struct v4l2_subdev *sd) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - - if (!state->is_initialized) { - /* initialize on first use */ - state->is_initialized = 1; - cx18_av_initialize(sd); - } - return 0; -} - -void cx18_av_std_setup(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd = &state->sd; - v4l2_std_id std = state->std; - - /* - * Video ADC crystal clock to pixel clock SRC decimation ratio - * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b - */ - const int src_decimation = 0x21f; - - int hblank, hactive, burst, vblank, vactive, sc; - int vblank656; - int luma_lpf, uv_lpf, comb; - u32 pll_int, pll_frac, pll_post; - - /* datasheet startup, step 8d */ - if (std & ~V4L2_STD_NTSC) - cx18_av_write(cx, 0x49f, 0x11); - else - cx18_av_write(cx, 0x49f, 0x14); - - /* - * Note: At the end of a field, there are 3 sets of half line duration - * (double horizontal rate) pulses: - * - * 5 (625) or 6 (525) half-lines to blank for the vertical retrace - * 5 (625) or 6 (525) vertical sync pulses of half line duration - * 5 (625) or 6 (525) half-lines of equalization pulses - */ - if (std & V4L2_STD_625_50) { - /* - * The following relationships of half line counts should hold: - * 625 = vblank656 + vactive - * 10 = vblank656 - vblank = vsync pulses + equalization pulses - * - * vblank656: half lines after line 625/mid-313 of blanked video - * vblank: half lines, after line 5/317, of blanked video - * vactive: half lines of active video + - * 5 half lines after the end of active video - * - * As far as I can tell: - * vblank656 starts counting from the falling edge of the first - * vsync pulse (start of line 1 or mid-313) - * vblank starts counting from the after the 5 vsync pulses and - * 5 or 4 equalization pulses (start of line 6 or 318) - * - * For 625 line systems the driver will extract VBI information - * from lines 6-23 and lines 318-335 (but the slicer can only - * handle 17 lines, not the 18 in the vblank region). - * In addition, we need vblank656 and vblank to be one whole - * line longer, to cover line 24 and 336, so the SAV/EAV RP - * codes get generated such that the encoder can actually - * extract line 23 & 335 (WSS). We'll lose 1 line in each field - * at the top of the screen. - * - * It appears the 5 half lines that happen after active - * video must be included in vactive (579 instead of 574), - * otherwise the colors get badly displayed in various regions - * of the screen. I guess the chroma comb filter gets confused - * without them (at least when a PVR-350 is the PAL source). - */ - vblank656 = 48; /* lines 1 - 24 & 313 - 336 */ - vblank = 38; /* lines 6 - 24 & 318 - 336 */ - vactive = 579; /* lines 24 - 313 & 337 - 626 */ - - /* - * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is - * is 864 pixels = 720 active + 144 blanking. ITU-R BT.601 - * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after - * the end of active video to start a horizontal line, so that - * leaves 132 pixels of hblank to ignore. - */ - hblank = 132; - hactive = 720; - - /* - * Burst gate delay (for 625 line systems) - * Hsync leading edge to color burst rise = 5.6 us - * Color burst width = 2.25 us - * Gate width = 4 pixel clocks - * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks - */ - burst = 93; - luma_lpf = 2; - if (std & V4L2_STD_PAL) { - uv_lpf = 1; - comb = 0x20; - /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ - sc = 688700; - } else if (std == V4L2_STD_PAL_Nc) { - uv_lpf = 1; - comb = 0x20; - /* sc = 3582056.25 * src_decimation/28636360 * 2^13 */ - sc = 556422; - } else { /* SECAM */ - uv_lpf = 0; - comb = 0; - /* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */ - /* sc = 4328130 * src_decimation/28636360 * 2^13 */ - sc = 672314; - } - } else { - /* - * The following relationships of half line counts should hold: - * 525 = prevsync + vblank656 + vactive - * 12 = vblank656 - vblank = vsync pulses + equalization pulses - * - * prevsync: 6 half-lines before the vsync pulses - * vblank656: half lines, after line 3/mid-266, of blanked video - * vblank: half lines, after line 9/272, of blanked video - * vactive: half lines of active video - * - * As far as I can tell: - * vblank656 starts counting from the falling edge of the first - * vsync pulse (start of line 4 or mid-266) - * vblank starts counting from the after the 6 vsync pulses and - * 6 or 5 equalization pulses (start of line 10 or 272) - * - * For 525 line systems the driver will extract VBI information - * from lines 10-21 and lines 273-284. - */ - vblank656 = 38; /* lines 4 - 22 & 266 - 284 */ - vblank = 26; /* lines 10 - 22 & 272 - 284 */ - vactive = 481; /* lines 23 - 263 & 285 - 525 */ - - /* - * For a 13.5 Mpps clock and 15,734.26 Hz line rate, a line is - * is 858 pixels = 720 active + 138 blanking. The Hsync leading - * edge should happen 1.2 us * 13.5 Mpps ~= 16 pixels after the - * end of active video, leaving 122 pixels of hblank to ignore - * before active video starts. - */ - hactive = 720; - hblank = 122; - luma_lpf = 1; - uv_lpf = 1; - - /* - * Burst gate delay (for 525 line systems) - * Hsync leading edge to color burst rise = 5.3 us - * Color burst width = 2.5 us - * Gate width = 4 pixel clocks - * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks - */ - if (std == V4L2_STD_PAL_60) { - burst = 90; - luma_lpf = 2; - comb = 0x20; - /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ - sc = 688700; - } else if (std == V4L2_STD_PAL_M) { - /* The 97 needs to be verified against PAL-M timings */ - burst = 97; - comb = 0x20; - /* sc = 3575611.49 * src_decimation/28636360 * 2^13 */ - sc = 555421; - } else { - burst = 90; - comb = 0x66; - /* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */ - sc = 556032; - } - } - - /* DEBUG: Displays configured PLL frequency */ - pll_int = cx18_av_read(cx, 0x108); - pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff; - pll_post = cx18_av_read(cx, 0x109); - CX18_DEBUG_INFO_DEV(sd, "PLL regs = int: %u, frac: %u, post: %u\n", - pll_int, pll_frac, pll_post); - - if (pll_post) { - int fsc, pll; - u64 tmp; - - pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25; - pll /= pll_post; - CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n", - pll / 1000000, pll % 1000000); - CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n", - pll / 8000000, (pll / 8) % 1000000); - - CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio " - "= %d.%03d\n", src_decimation / 256, - ((src_decimation % 256) * 1000) / 256); - - tmp = 28636360 * (u64) sc; - do_div(tmp, src_decimation); - fsc = tmp >> 13; - CX18_DEBUG_INFO_DEV(sd, - "Chroma sub-carrier initial freq = %d.%06d " - "MHz\n", fsc / 1000000, fsc % 1000000); - - CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, " - "vactive %i, vblank656 %i, src_dec %i, " - "burst 0x%02x, luma_lpf %i, uv_lpf %i, " - "comb 0x%02x, sc 0x%06x\n", - hblank, hactive, vblank, vactive, vblank656, - src_decimation, burst, luma_lpf, uv_lpf, - comb, sc); - } - - /* Sets horizontal blanking delay and active lines */ - cx18_av_write(cx, 0x470, hblank); - cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) | - (hactive << 4))); - cx18_av_write(cx, 0x472, hactive >> 4); - - /* Sets burst gate delay */ - cx18_av_write(cx, 0x473, burst); - - /* Sets vertical blanking delay and active duration */ - cx18_av_write(cx, 0x474, vblank); - cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) | - (vactive << 4))); - cx18_av_write(cx, 0x476, vactive >> 4); - cx18_av_write(cx, 0x477, vblank656); - - /* Sets src decimation rate */ - cx18_av_write(cx, 0x478, 0xff & src_decimation); - cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8)); - - /* Sets Luma and UV Low pass filters */ - cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); - - /* Enables comb filters */ - cx18_av_write(cx, 0x47b, comb); - - /* Sets SC Step*/ - cx18_av_write(cx, 0x47c, sc); - cx18_av_write(cx, 0x47d, 0xff & sc >> 8); - cx18_av_write(cx, 0x47e, 0xff & sc >> 16); - - if (std & V4L2_STD_625_50) { - state->slicer_line_delay = 1; - state->slicer_line_offset = (6 + state->slicer_line_delay - 2); - } else { - state->slicer_line_delay = 0; - state->slicer_line_offset = (10 + state->slicer_line_delay - 2); - } - cx18_av_write(cx, 0x47f, state->slicer_line_delay); -} - -static void input_change(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - v4l2_std_id std = state->std; - u8 v; - - /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ - cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); - cx18_av_and_or(cx, 0x401, ~0x60, 0); - cx18_av_and_or(cx, 0x401, ~0x60, 0x60); - - if (std & V4L2_STD_525_60) { - if (std == V4L2_STD_NTSC_M_JP) { - /* Japan uses EIAJ audio standard */ - cx18_av_write_expect(cx, 0x808, 0xf7, 0xf7, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x02, 0x02, 0x3f); - } else if (std == V4L2_STD_NTSC_M_KR) { - /* South Korea uses A2 audio standard */ - cx18_av_write_expect(cx, 0x808, 0xf8, 0xf8, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); - } else { - /* Others use the BTSC audio standard */ - cx18_av_write_expect(cx, 0x808, 0xf6, 0xf6, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x01, 0x01, 0x3f); - } - } else if (std & V4L2_STD_PAL) { - /* Follow tuner change procedure for PAL */ - cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); - } else if (std & V4L2_STD_SECAM) { - /* Select autodetect for SECAM */ - cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); - } - - v = cx18_av_read(cx, 0x803); - if (v & 0x10) { - /* restart audio decoder microcontroller */ - v &= ~0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - v |= 0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - } -} - -static int cx18_av_s_frequency(struct v4l2_subdev *sd, - struct v4l2_frequency *freq) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - input_change(cx); - return 0; -} - -static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, - enum cx18_av_audio_input aud_input) -{ - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd = &state->sd; - - enum analog_signal_type { - NONE, CVBS, Y, C, SIF, Pb, Pr - } ch[3] = {NONE, NONE, NONE}; - - u8 afe_mux_cfg; - u8 adc2_cfg; - u8 input_mode; - u32 afe_cfg; - int i; - - CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n", - vid_input, aud_input); - - if (vid_input >= CX18_AV_COMPOSITE1 && - vid_input <= CX18_AV_COMPOSITE8) { - afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1); - ch[0] = CVBS; - input_mode = 0x0; - } else if (vid_input >= CX18_AV_COMPONENT_LUMA1) { - int luma = vid_input & 0xf000; - int r_chroma = vid_input & 0xf0000; - int b_chroma = vid_input & 0xf00000; - - if ((vid_input & ~0xfff000) || - luma < CX18_AV_COMPONENT_LUMA1 || - luma > CX18_AV_COMPONENT_LUMA8 || - r_chroma < CX18_AV_COMPONENT_R_CHROMA4 || - r_chroma > CX18_AV_COMPONENT_R_CHROMA6 || - b_chroma < CX18_AV_COMPONENT_B_CHROMA7 || - b_chroma > CX18_AV_COMPONENT_B_CHROMA8) { - CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n", - vid_input); - return -EINVAL; - } - afe_mux_cfg = (luma - CX18_AV_COMPONENT_LUMA1) >> 12; - ch[0] = Y; - afe_mux_cfg |= (r_chroma - CX18_AV_COMPONENT_R_CHROMA4) >> 12; - ch[1] = Pr; - afe_mux_cfg |= (b_chroma - CX18_AV_COMPONENT_B_CHROMA7) >> 14; - ch[2] = Pb; - input_mode = 0x6; - } else { - int luma = vid_input & 0xf0; - int chroma = vid_input & 0xf00; - - if ((vid_input & ~0xff0) || - luma < CX18_AV_SVIDEO_LUMA1 || - luma > CX18_AV_SVIDEO_LUMA8 || - chroma < CX18_AV_SVIDEO_CHROMA4 || - chroma > CX18_AV_SVIDEO_CHROMA8) { - CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n", - vid_input); - return -EINVAL; - } - afe_mux_cfg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4); - ch[0] = Y; - if (chroma >= CX18_AV_SVIDEO_CHROMA7) { - afe_mux_cfg &= 0x3f; - afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2; - ch[2] = C; - } else { - afe_mux_cfg &= 0xcf; - afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4; - ch[1] = C; - } - input_mode = 0x2; - } - - switch (aud_input) { - case CX18_AV_AUDIO_SERIAL1: - case CX18_AV_AUDIO_SERIAL2: - /* do nothing, use serial audio input */ - break; - case CX18_AV_AUDIO4: - afe_mux_cfg &= ~0x30; - ch[1] = SIF; - break; - case CX18_AV_AUDIO5: - afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x10; - ch[1] = SIF; - break; - case CX18_AV_AUDIO6: - afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x20; - ch[1] = SIF; - break; - case CX18_AV_AUDIO7: - afe_mux_cfg &= ~0xc0; - ch[2] = SIF; - break; - case CX18_AV_AUDIO8: - afe_mux_cfg = (afe_mux_cfg & ~0xc0) | 0x40; - ch[2] = SIF; - break; - - default: - CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n", - aud_input); - return -EINVAL; - } - - /* Set up analog front end multiplexers */ - cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7); - /* Set INPUT_MODE to Composite, S-Video, or Component */ - cx18_av_and_or(cx, 0x401, ~0x6, input_mode); - - /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ - adc2_cfg = cx18_av_read(cx, 0x102); - if (ch[2] == NONE) - adc2_cfg &= ~0x2; /* No sig on CH3, set ADC2 to CH2 for input */ - else - adc2_cfg |= 0x2; /* Signal on CH3, set ADC2 to CH3 for input */ - - /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ - if (ch[1] != NONE && ch[2] != NONE) - adc2_cfg |= 0x4; /* Set dual mode */ - else - adc2_cfg &= ~0x4; /* Clear dual mode */ - cx18_av_write_expect(cx, 0x102, adc2_cfg, adc2_cfg, 0x17); - - /* Configure the analog front end */ - afe_cfg = cx18_av_read4(cx, CXADEC_AFE_CTRL); - afe_cfg &= 0xff000000; - afe_cfg |= 0x00005000; /* CHROMA_IN, AUD_IN: ADC2; LUMA_IN: ADC1 */ - if (ch[1] != NONE && ch[2] != NONE) - afe_cfg |= 0x00000030; /* half_bw_ch[2-3] since in dual mode */ - - for (i = 0; i < 3; i++) { - switch (ch[i]) { - default: - case NONE: - /* CLAMP_SEL = Fixed to midcode clamp level */ - afe_cfg |= (0x00000200 << i); - break; - case CVBS: - case Y: - if (i > 0) - afe_cfg |= 0x00002000; /* LUMA_IN_SEL: ADC2 */ - break; - case C: - case Pb: - case Pr: - /* CLAMP_SEL = Fixed to midcode clamp level */ - afe_cfg |= (0x00000200 << i); - if (i == 0 && ch[i] == C) - afe_cfg &= ~0x00001000; /* CHROMA_IN_SEL ADC1 */ - break; - case SIF: - /* - * VGA_GAIN_SEL = Audio Decoder - * CLAMP_SEL = Fixed to midcode clamp level - */ - afe_cfg |= (0x00000240 << i); - if (i == 0) - afe_cfg &= ~0x00004000; /* AUD_IN_SEL ADC1 */ - break; - } - } - - cx18_av_write4(cx, CXADEC_AFE_CTRL, afe_cfg); - - state->vid_input = vid_input; - state->aud_input = aud_input; - cx18_av_audio_set_path(cx); - input_change(cx); - return 0; -} - -static int cx18_av_s_video_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - return set_input(cx, input, state->aud_input); -} - -static int cx18_av_s_audio_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - return set_input(cx, state->vid_input, input); -} - -static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - u8 vpres; - u8 mode; - int val = 0; - - if (state->radio) - return 0; - - vpres = cx18_av_read(cx, 0x40e) & 0x20; - vt->signal = vpres ? 0xffff : 0x0; - - vt->capability |= - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - - mode = cx18_av_read(cx, 0x804); - - /* get rxsubchans and audmode */ - if ((mode & 0xf) == 1) - val |= V4L2_TUNER_SUB_STEREO; - else - val |= V4L2_TUNER_SUB_MONO; - - if (mode == 2 || mode == 4) - val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - - if (mode & 0x10) - val |= V4L2_TUNER_SUB_SAP; - - vt->rxsubchans = val; - vt->audmode = state->audmode; - return 0; -} - -static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - u8 v; - - if (state->radio) - return 0; - - v = cx18_av_read(cx, 0x809); - v &= ~0xf; - - switch (vt->audmode) { - case V4L2_TUNER_MODE_MONO: - /* mono -> mono - stereo -> mono - bilingual -> lang1 */ - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1: - /* mono -> mono - stereo -> stereo - bilingual -> lang1 */ - v |= 0x4; - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang1/lang2 */ - v |= 0x7; - break; - case V4L2_TUNER_MODE_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang2 */ - v |= 0x1; - break; - default: - return -EINVAL; - } - cx18_av_write_expect(cx, 0x809, v, v, 0xff); - state->audmode = vt->audmode; - return 0; -} - -static int cx18_av_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - - u8 fmt = 0; /* zero is autodetect */ - u8 pal_m = 0; - - if (state->radio == 0 && state->std == norm) - return 0; - - state->radio = 0; - state->std = norm; - - /* First tests should be against specific std */ - if (state->std == V4L2_STD_NTSC_M_JP) { - fmt = 0x2; - } else if (state->std == V4L2_STD_NTSC_443) { - fmt = 0x3; - } else if (state->std == V4L2_STD_PAL_M) { - pal_m = 1; - fmt = 0x5; - } else if (state->std == V4L2_STD_PAL_N) { - fmt = 0x6; - } else if (state->std == V4L2_STD_PAL_Nc) { - fmt = 0x7; - } else if (state->std == V4L2_STD_PAL_60) { - fmt = 0x8; - } else { - /* Then, test against generic ones */ - if (state->std & V4L2_STD_NTSC) - fmt = 0x1; - else if (state->std & V4L2_STD_PAL) - fmt = 0x4; - else if (state->std & V4L2_STD_SECAM) - fmt = 0xc; - } - - CX18_DEBUG_INFO_DEV(sd, "changing video std to fmt %i\n", fmt); - - /* Follow step 9 of section 3.16 in the cx18_av datasheet. - Without this PAL may display a vertical ghosting effect. - This happens for example with the Yuan MPC622. */ - if (fmt >= 4 && fmt < 8) { - /* Set format to NTSC-M */ - cx18_av_and_or(cx, 0x400, ~0xf, 1); - /* Turn off LCOMB */ - cx18_av_and_or(cx, 0x47b, ~6, 0); - } - cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20); - cx18_av_and_or(cx, 0x403, ~0x3, pal_m); - cx18_av_std_setup(cx); - input_change(cx); - return 0; -} - -static int cx18_av_s_radio(struct v4l2_subdev *sd) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - state->radio = 1; - return 0; -} - -static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct cx18 *cx = v4l2_get_subdevdata(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - cx18_av_write(cx, 0x414, ctrl->val - 128); - break; - - case V4L2_CID_CONTRAST: - cx18_av_write(cx, 0x415, ctrl->val << 1); - break; - - case V4L2_CID_SATURATION: - cx18_av_write(cx, 0x420, ctrl->val << 1); - cx18_av_write(cx, 0x421, ctrl->val << 1); - break; - - case V4L2_CID_HUE: - cx18_av_write(cx, 0x422, ctrl->val); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - int HSC, VSC, Vsrc, Hsrc, filter, Vlines; - int is_50Hz = !(state->std & V4L2_STD_525_60); - - if (fmt->code != V4L2_MBUS_FMT_FIXED) - return -EINVAL; - - fmt->field = V4L2_FIELD_INTERLACED; - fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - - Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; - Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; - - Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; - Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; - - /* - * This adjustment reflects the excess of vactive, set in - * cx18_av_std_setup(), above standard values: - * - * 480 + 1 for 60 Hz systems - * 576 + 3 for 50 Hz systems - */ - Vlines = fmt->height + (is_50Hz ? 3 : 1); - - /* - * Invalid height and width scaling requests are: - * 1. width less than 1/16 of the source width - * 2. width greater than the source width - * 3. height less than 1/8 of the source height - * 4. height greater than the source height - */ - if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || - (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { - CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n", - fmt->width, fmt->height); - return -ERANGE; - } - - HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); - VSC &= 0x1fff; - - if (fmt->width >= 385) - filter = 0; - else if (fmt->width > 192) - filter = 1; - else if (fmt->width > 96) - filter = 2; - else - filter = 3; - - CX18_DEBUG_INFO_DEV(sd, - "decoder set size %dx%d -> scale %ux%u\n", - fmt->width, fmt->height, HSC, VSC); - - /* HSCALE=HSC */ - cx18_av_write(cx, 0x418, HSC & 0xff); - cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); - cx18_av_write(cx, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx18_av_write(cx, 0x41c, VSC & 0xff); - cx18_av_write(cx, 0x41d, VSC >> 8); - /* VS_INTRLACE=1 VFILT=filter */ - cx18_av_write(cx, 0x41e, 0x8 | filter); - return 0; -} - -static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - CX18_DEBUG_INFO_DEV(sd, "%s output\n", enable ? "enable" : "disable"); - if (enable) { - cx18_av_write(cx, 0x115, 0x8c); - cx18_av_write(cx, 0x116, 0x07); - } else { - cx18_av_write(cx, 0x115, 0x00); - cx18_av_write(cx, 0x116, 0x00); - } - return 0; -} - -static void log_video_status(struct cx18 *cx) -{ - static const char *const fmt_strs[] = { - "0x0", - "NTSC-M", "NTSC-J", "NTSC-4.43", - "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", - "0x9", "0xA", "0xB", - "SECAM", - "0xD", "0xE", "0xF" - }; - - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd = &state->sd; - u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf; - u8 gen_stat1 = cx18_av_read(cx, 0x40d); - u8 gen_stat2 = cx18_av_read(cx, 0x40e); - int vid_input = state->vid_input; - - CX18_INFO_DEV(sd, "Video signal: %spresent\n", - (gen_stat2 & 0x20) ? "" : "not "); - CX18_INFO_DEV(sd, "Detected format: %s\n", - fmt_strs[gen_stat1 & 0xf]); - - CX18_INFO_DEV(sd, "Specified standard: %s\n", - vidfmt_sel ? fmt_strs[vidfmt_sel] - : "automatic detection"); - - if (vid_input >= CX18_AV_COMPOSITE1 && - vid_input <= CX18_AV_COMPOSITE8) { - CX18_INFO_DEV(sd, "Specified video input: Composite %d\n", - vid_input - CX18_AV_COMPOSITE1 + 1); - } else { - CX18_INFO_DEV(sd, "Specified video input: " - "S-Video (Luma In%d, Chroma In%d)\n", - (vid_input & 0xf0) >> 4, - (vid_input & 0xf00) >> 8); - } - - CX18_INFO_DEV(sd, "Specified audioclock freq: %d Hz\n", - state->audclk_freq); -} - -static void log_audio_status(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd = &state->sd; - u8 download_ctl = cx18_av_read(cx, 0x803); - u8 mod_det_stat0 = cx18_av_read(cx, 0x804); - u8 mod_det_stat1 = cx18_av_read(cx, 0x805); - u8 audio_config = cx18_av_read(cx, 0x808); - u8 pref_mode = cx18_av_read(cx, 0x809); - u8 afc0 = cx18_av_read(cx, 0x80b); - u8 mute_ctl = cx18_av_read(cx, 0x8d3); - int aud_input = state->aud_input; - char *p; - - switch (mod_det_stat0) { - case 0x00: p = "mono"; break; - case 0x01: p = "stereo"; break; - case 0x02: p = "dual"; break; - case 0x04: p = "tri"; break; - case 0x10: p = "mono with SAP"; break; - case 0x11: p = "stereo with SAP"; break; - case 0x12: p = "dual with SAP"; break; - case 0x14: p = "tri with SAP"; break; - case 0xfe: p = "forced mode"; break; - default: p = "not defined"; break; - } - CX18_INFO_DEV(sd, "Detected audio mode: %s\n", p); - - switch (mod_det_stat1) { - case 0x00: p = "not defined"; break; - case 0x01: p = "EIAJ"; break; - case 0x02: p = "A2-M"; break; - case 0x03: p = "A2-BG"; break; - case 0x04: p = "A2-DK1"; break; - case 0x05: p = "A2-DK2"; break; - case 0x06: p = "A2-DK3"; break; - case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x08: p = "AM-L"; break; - case 0x09: p = "NICAM-BG"; break; - case 0x0a: p = "NICAM-DK"; break; - case 0x0b: p = "NICAM-I"; break; - case 0x0c: p = "NICAM-L"; break; - case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; - case 0x0e: p = "IF FM Radio"; break; - case 0x0f: p = "BTSC"; break; - case 0x10: p = "detected chrominance"; break; - case 0xfd: p = "unknown audio standard"; break; - case 0xfe: p = "forced audio standard"; break; - case 0xff: p = "no detected audio standard"; break; - default: p = "not defined"; break; - } - CX18_INFO_DEV(sd, "Detected audio standard: %s\n", p); - CX18_INFO_DEV(sd, "Audio muted: %s\n", - (mute_ctl & 0x2) ? "yes" : "no"); - CX18_INFO_DEV(sd, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? "running" : "stopped"); - - switch (audio_config >> 4) { - case 0x00: p = "undefined"; break; - case 0x01: p = "BTSC"; break; - case 0x02: p = "EIAJ"; break; - case 0x03: p = "A2-M"; break; - case 0x04: p = "A2-BG"; break; - case 0x05: p = "A2-DK1"; break; - case 0x06: p = "A2-DK2"; break; - case 0x07: p = "A2-DK3"; break; - case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x09: p = "AM-L"; break; - case 0x0a: p = "NICAM-BG"; break; - case 0x0b: p = "NICAM-DK"; break; - case 0x0c: p = "NICAM-I"; break; - case 0x0d: p = "NICAM-L"; break; - case 0x0e: p = "FM radio"; break; - case 0x0f: p = "automatic detection"; break; - default: p = "undefined"; break; - } - CX18_INFO_DEV(sd, "Configured audio standard: %s\n", p); - - if ((audio_config >> 4) < 0xF) { - switch (audio_config & 0xF) { - case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; - case 0x01: p = "MONO2 (LANGUAGE B)"; break; - case 0x02: p = "MONO3 (STEREO forced MONO)"; break; - case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; - case 0x04: p = "STEREO"; break; - case 0x05: p = "DUAL1 (AC)"; break; - case 0x06: p = "DUAL2 (BC)"; break; - case 0x07: p = "DUAL3 (AB)"; break; - default: p = "undefined"; - } - CX18_INFO_DEV(sd, "Configured audio mode: %s\n", p); - } else { - switch (audio_config & 0xF) { - case 0x00: p = "BG"; break; - case 0x01: p = "DK1"; break; - case 0x02: p = "DK2"; break; - case 0x03: p = "DK3"; break; - case 0x04: p = "I"; break; - case 0x05: p = "L"; break; - case 0x06: p = "BTSC"; break; - case 0x07: p = "EIAJ"; break; - case 0x08: p = "A2-M"; break; - case 0x09: p = "FM Radio (4.5 MHz)"; break; - case 0x0a: p = "FM Radio (5.5 MHz)"; break; - case 0x0b: p = "S-Video"; break; - case 0x0f: p = "automatic standard and mode detection"; break; - default: p = "undefined"; break; - } - CX18_INFO_DEV(sd, "Configured audio system: %s\n", p); - } - - if (aud_input) - CX18_INFO_DEV(sd, "Specified audio input: Tuner (In%d)\n", - aud_input); - else - CX18_INFO_DEV(sd, "Specified audio input: External\n"); - - switch (pref_mode & 0xf) { - case 0: p = "mono/language A"; break; - case 1: p = "language B"; break; - case 2: p = "language C"; break; - case 3: p = "analog fallback"; break; - case 4: p = "stereo"; break; - case 5: p = "language AC"; break; - case 6: p = "language BC"; break; - case 7: p = "language AB"; break; - default: p = "undefined"; break; - } - CX18_INFO_DEV(sd, "Preferred audio mode: %s\n", p); - - if ((audio_config & 0xf) == 0xf) { - switch ((afc0 >> 3) & 0x1) { - case 0: p = "system DK"; break; - case 1: p = "system L"; break; - } - CX18_INFO_DEV(sd, "Selected 65 MHz format: %s\n", p); - - switch (afc0 & 0x7) { - case 0: p = "Chroma"; break; - case 1: p = "BTSC"; break; - case 2: p = "EIAJ"; break; - case 3: p = "A2-M"; break; - case 4: p = "autodetect"; break; - default: p = "undefined"; break; - } - CX18_INFO_DEV(sd, "Selected 45 MHz format: %s\n", p); - } -} - -static int cx18_av_log_status(struct v4l2_subdev *sd) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - log_video_status(cx); - log_audio_status(cx); - return 0; -} - -static inline int cx18_av_dbg_match(const struct v4l2_dbg_match *match) -{ - return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 1; -} - -static int cx18_av_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - - if (cx18_av_dbg_match(&chip->match)) { - chip->ident = state->id; - chip->revision = state->rev; - } - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx18_av_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - if (!cx18_av_dbg_match(®->match)) - return -EINVAL; - if ((reg->reg & 0x3) != 0) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->size = 4; - reg->val = cx18_av_read4(cx, reg->reg & 0x00000ffc); - return 0; -} - -static int cx18_av_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - if (!cx18_av_dbg_match(®->match)) - return -EINVAL; - if ((reg->reg & 0x3) != 0) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - cx18_av_write4(cx, reg->reg & 0x00000ffc, reg->val); - return 0; -} -#endif - -static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = { - .s_ctrl = cx18_av_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops cx18_av_general_ops = { - .g_chip_ident = cx18_av_g_chip_ident, - .log_status = cx18_av_log_status, - .load_fw = cx18_av_load_fw, - .reset = cx18_av_reset, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = cx18_av_s_std, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = cx18_av_g_register, - .s_register = cx18_av_s_register, -#endif -}; - -static const struct v4l2_subdev_tuner_ops cx18_av_tuner_ops = { - .s_radio = cx18_av_s_radio, - .s_frequency = cx18_av_s_frequency, - .g_tuner = cx18_av_g_tuner, - .s_tuner = cx18_av_s_tuner, -}; - -static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = { - .s_clock_freq = cx18_av_s_clock_freq, - .s_routing = cx18_av_s_audio_routing, -}; - -static const struct v4l2_subdev_video_ops cx18_av_video_ops = { - .s_routing = cx18_av_s_video_routing, - .s_stream = cx18_av_s_stream, - .s_mbus_fmt = cx18_av_s_mbus_fmt, -}; - -static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = { - .decode_vbi_line = cx18_av_decode_vbi_line, - .g_sliced_fmt = cx18_av_g_sliced_fmt, - .s_sliced_fmt = cx18_av_s_sliced_fmt, - .s_raw_fmt = cx18_av_s_raw_fmt, -}; - -static const struct v4l2_subdev_ops cx18_av_ops = { - .core = &cx18_av_general_ops, - .tuner = &cx18_av_tuner_ops, - .audio = &cx18_av_audio_ops, - .video = &cx18_av_video_ops, - .vbi = &cx18_av_vbi_ops, -}; - -int cx18_av_probe(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd; - int err; - - state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff; - state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO) - ? V4L2_IDENT_CX23418_843 : V4L2_IDENT_UNKNOWN; - - state->vid_input = CX18_AV_COMPOSITE7; - state->aud_input = CX18_AV_AUDIO8; - state->audclk_freq = 48000; - state->audmode = V4L2_TUNER_MODE_LANG1; - state->slicer_line_delay = 0; - state->slicer_line_offset = (10 + state->slicer_line_delay - 2); - - sd = &state->sd; - v4l2_subdev_init(sd, &cx18_av_ops); - v4l2_set_subdevdata(sd, cx); - snprintf(sd->name, sizeof(sd->name), - "%s %03x", cx->v4l2_dev.name, (state->rev >> 4)); - sd->grp_id = CX18_HW_418_AV; - v4l2_ctrl_handler_init(&state->hdl, 9); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, - V4L2_CID_CONTRAST, 0, 127, 1, 64); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, - V4L2_CID_SATURATION, 0, 127, 1, 64); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - - state->volume = v4l2_ctrl_new_std(&state->hdl, - &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, - 0, 65535, 65535 / 100, 0); - v4l2_ctrl_new_std(&state->hdl, - &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, - 0, 1, 1, 0); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, - 0, 65535, 65535 / 100, 32768); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, - V4L2_CID_AUDIO_BASS, - 0, 65535, 65535 / 100, 32768); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, - V4L2_CID_AUDIO_TREBLE, - 0, 65535, 65535 / 100, 32768); - sd->ctrl_handler = &state->hdl; - if (state->hdl.error) { - int err = state->hdl.error; - - v4l2_ctrl_handler_free(&state->hdl); - return err; - } - err = v4l2_device_register_subdev(&cx->v4l2_dev, sd); - if (err) - v4l2_ctrl_handler_free(&state->hdl); - else - cx18_av_init(cx); - return err; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-core.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-core.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,391 +0,0 @@ -/* - * cx18 ADEC header - * - * Derived from cx25840-core.h - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef _CX18_AV_CORE_H_ -#define _CX18_AV_CORE_H_ - -#include -#include - -struct cx18; - -enum cx18_av_video_input { - /* Composite video inputs In1-In8 */ - CX18_AV_COMPOSITE1 = 1, - CX18_AV_COMPOSITE2, - CX18_AV_COMPOSITE3, - CX18_AV_COMPOSITE4, - CX18_AV_COMPOSITE5, - CX18_AV_COMPOSITE6, - CX18_AV_COMPOSITE7, - CX18_AV_COMPOSITE8, - - /* S-Video inputs consist of one luma input (In1-In8) ORed with one - chroma input (In5-In8) */ - CX18_AV_SVIDEO_LUMA1 = 0x10, - CX18_AV_SVIDEO_LUMA2 = 0x20, - CX18_AV_SVIDEO_LUMA3 = 0x30, - CX18_AV_SVIDEO_LUMA4 = 0x40, - CX18_AV_SVIDEO_LUMA5 = 0x50, - CX18_AV_SVIDEO_LUMA6 = 0x60, - CX18_AV_SVIDEO_LUMA7 = 0x70, - CX18_AV_SVIDEO_LUMA8 = 0x80, - CX18_AV_SVIDEO_CHROMA4 = 0x400, - CX18_AV_SVIDEO_CHROMA5 = 0x500, - CX18_AV_SVIDEO_CHROMA6 = 0x600, - CX18_AV_SVIDEO_CHROMA7 = 0x700, - CX18_AV_SVIDEO_CHROMA8 = 0x800, - - /* S-Video aliases for common luma/chroma combinations */ - CX18_AV_SVIDEO1 = 0x510, - CX18_AV_SVIDEO2 = 0x620, - CX18_AV_SVIDEO3 = 0x730, - CX18_AV_SVIDEO4 = 0x840, - - /* Component Video inputs consist of one luma input (In1-In8) ORed - with a red chroma (In4-In6) and blue chroma input (In7-In8) */ - CX18_AV_COMPONENT_LUMA1 = 0x1000, - CX18_AV_COMPONENT_LUMA2 = 0x2000, - CX18_AV_COMPONENT_LUMA3 = 0x3000, - CX18_AV_COMPONENT_LUMA4 = 0x4000, - CX18_AV_COMPONENT_LUMA5 = 0x5000, - CX18_AV_COMPONENT_LUMA6 = 0x6000, - CX18_AV_COMPONENT_LUMA7 = 0x7000, - CX18_AV_COMPONENT_LUMA8 = 0x8000, - CX18_AV_COMPONENT_R_CHROMA4 = 0x40000, - CX18_AV_COMPONENT_R_CHROMA5 = 0x50000, - CX18_AV_COMPONENT_R_CHROMA6 = 0x60000, - CX18_AV_COMPONENT_B_CHROMA7 = 0x700000, - CX18_AV_COMPONENT_B_CHROMA8 = 0x800000, - - /* Component Video aliases for common combinations */ - CX18_AV_COMPONENT1 = 0x861000, -}; - -enum cx18_av_audio_input { - /* Audio inputs: serial or In4-In8 */ - CX18_AV_AUDIO_SERIAL1, - CX18_AV_AUDIO_SERIAL2, - CX18_AV_AUDIO4 = 4, - CX18_AV_AUDIO5, - CX18_AV_AUDIO6, - CX18_AV_AUDIO7, - CX18_AV_AUDIO8, -}; - -struct cx18_av_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - struct v4l2_ctrl *volume; - int radio; - v4l2_std_id std; - enum cx18_av_video_input vid_input; - enum cx18_av_audio_input aud_input; - u32 audclk_freq; - int audmode; - u32 id; - u32 rev; - int is_initialized; - - /* - * The VBI slicer starts operating and counting lines, begining at - * slicer line count of 1, at D lines after the deassertion of VRESET. - * This staring field line, S, is 6 (& 319) or 10 (& 273) for 625 or 525 - * line systems respectively. Sliced ancillary data captured on VBI - * slicer line M is inserted after the VBI slicer is done with line M, - * when VBI slicer line count is N = M+1. Thus when the VBI slicer - * reports a VBI slicer line number with ancillary data, the IDID0 byte - * indicates VBI slicer line N. The actual field line that the captured - * data comes from is - * - * L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2). - * - * L is the line in the field, not frame, from which the VBI data came. - * N is the line reported by the slicer in the ancillary data. - * D is the slicer_line_delay value programmed into register 0x47f. - * S is 6 for 625 line systems or 10 for 525 line systems - * (S+D-2) is the slicer_line_offset used to convert slicer reported - * line counts to actual field lines. - */ - int slicer_line_delay; - int slicer_line_offset; -}; - - -/* Registers */ -#define CXADEC_CHIP_TYPE_TIGER 0x837 -#define CXADEC_CHIP_TYPE_MAKO 0x843 - -#define CXADEC_HOST_REG1 0x000 -#define CXADEC_HOST_REG2 0x001 - -#define CXADEC_CHIP_CTRL 0x100 -#define CXADEC_AFE_CTRL 0x104 -#define CXADEC_PLL_CTRL1 0x108 -#define CXADEC_VID_PLL_FRAC 0x10C -#define CXADEC_AUX_PLL_FRAC 0x110 -#define CXADEC_PIN_CTRL1 0x114 -#define CXADEC_PIN_CTRL2 0x118 -#define CXADEC_PIN_CFG1 0x11C -#define CXADEC_PIN_CFG2 0x120 - -#define CXADEC_PIN_CFG3 0x124 -#define CXADEC_I2S_MCLK 0x127 - -#define CXADEC_AUD_LOCK1 0x128 -#define CXADEC_AUD_LOCK2 0x12C -#define CXADEC_POWER_CTRL 0x130 -#define CXADEC_AFE_DIAG_CTRL1 0x134 -#define CXADEC_AFE_DIAG_CTRL2 0x138 -#define CXADEC_AFE_DIAG_CTRL3 0x13C -#define CXADEC_PLL_DIAG_CTRL 0x140 -#define CXADEC_TEST_CTRL1 0x144 -#define CXADEC_TEST_CTRL2 0x148 -#define CXADEC_BIST_STAT 0x14C -#define CXADEC_DLL1_DIAG_CTRL 0x158 -#define CXADEC_DLL2_DIAG_CTRL 0x15C - -/* IR registers */ -#define CXADEC_IR_CTRL_REG 0x200 -#define CXADEC_IR_TXCLK_REG 0x204 -#define CXADEC_IR_RXCLK_REG 0x208 -#define CXADEC_IR_CDUTY_REG 0x20C -#define CXADEC_IR_STAT_REG 0x210 -#define CXADEC_IR_IRQEN_REG 0x214 -#define CXADEC_IR_FILTER_REG 0x218 -#define CXADEC_IR_FIFO_REG 0x21C - -/* Video Registers */ -#define CXADEC_MODE_CTRL 0x400 -#define CXADEC_OUT_CTRL1 0x404 -#define CXADEC_OUT_CTRL2 0x408 -#define CXADEC_GEN_STAT 0x40C -#define CXADEC_INT_STAT_MASK 0x410 -#define CXADEC_LUMA_CTRL 0x414 - -#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414 -#define CXADEC_CONTRAST_CTRL_BYTE 0x415 -#define CXADEC_LUMA_CTRL_BYTE_3 0x416 - -#define CXADEC_HSCALE_CTRL 0x418 -#define CXADEC_VSCALE_CTRL 0x41C - -#define CXADEC_CHROMA_CTRL 0x420 - -#define CXADEC_USAT_CTRL_BYTE 0x420 -#define CXADEC_VSAT_CTRL_BYTE 0x421 -#define CXADEC_HUE_CTRL_BYTE 0x422 - -#define CXADEC_VBI_LINE_CTRL1 0x424 -#define CXADEC_VBI_LINE_CTRL2 0x428 -#define CXADEC_VBI_LINE_CTRL3 0x42C -#define CXADEC_VBI_LINE_CTRL4 0x430 -#define CXADEC_VBI_LINE_CTRL5 0x434 -#define CXADEC_VBI_FC_CFG 0x438 -#define CXADEC_VBI_MISC_CFG1 0x43C -#define CXADEC_VBI_MISC_CFG2 0x440 -#define CXADEC_VBI_PAY1 0x444 -#define CXADEC_VBI_PAY2 0x448 -#define CXADEC_VBI_CUST1_CFG1 0x44C -#define CXADEC_VBI_CUST1_CFG2 0x450 -#define CXADEC_VBI_CUST1_CFG3 0x454 -#define CXADEC_VBI_CUST2_CFG1 0x458 -#define CXADEC_VBI_CUST2_CFG2 0x45C -#define CXADEC_VBI_CUST2_CFG3 0x460 -#define CXADEC_VBI_CUST3_CFG1 0x464 -#define CXADEC_VBI_CUST3_CFG2 0x468 -#define CXADEC_VBI_CUST3_CFG3 0x46C -#define CXADEC_HORIZ_TIM_CTRL 0x470 -#define CXADEC_VERT_TIM_CTRL 0x474 -#define CXADEC_SRC_COMB_CFG 0x478 -#define CXADEC_CHROMA_VBIOFF_CFG 0x47C -#define CXADEC_FIELD_COUNT 0x480 -#define CXADEC_MISC_TIM_CTRL 0x484 -#define CXADEC_DFE_CTRL1 0x488 -#define CXADEC_DFE_CTRL2 0x48C -#define CXADEC_DFE_CTRL3 0x490 -#define CXADEC_PLL_CTRL2 0x494 -#define CXADEC_HTL_CTRL 0x498 -#define CXADEC_COMB_CTRL 0x49C -#define CXADEC_CRUSH_CTRL 0x4A0 -#define CXADEC_SOFT_RST_CTRL 0x4A4 -#define CXADEC_MV_DT_CTRL2 0x4A8 -#define CXADEC_MV_DT_CTRL3 0x4AC -#define CXADEC_MISC_DIAG_CTRL 0x4B8 - -#define CXADEC_DL_CTL 0x800 -#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */ -#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */ -#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */ -#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */ - -#define CXADEC_STD_DET_STATUS 0x804 - -#define CXADEC_STD_DET_CTL 0x808 -#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */ -#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */ - -#define CXADEC_DW8051_INT 0x80C -#define CXADEC_GENERAL_CTL 0x810 -#define CXADEC_AAGC_CTL 0x814 -#define CXADEC_IF_SRC_CTL 0x818 -#define CXADEC_ANLOG_DEMOD_CTL 0x81C -#define CXADEC_ROT_FREQ_CTL 0x820 -#define CXADEC_FM1_CTL 0x824 -#define CXADEC_PDF_CTL 0x828 -#define CXADEC_DFT1_CTL1 0x82C -#define CXADEC_DFT1_CTL2 0x830 -#define CXADEC_DFT_STATUS 0x834 -#define CXADEC_DFT2_CTL1 0x838 -#define CXADEC_DFT2_CTL2 0x83C -#define CXADEC_DFT2_STATUS 0x840 -#define CXADEC_DFT3_CTL1 0x844 -#define CXADEC_DFT3_CTL2 0x848 -#define CXADEC_DFT3_STATUS 0x84C -#define CXADEC_DFT4_CTL1 0x850 -#define CXADEC_DFT4_CTL2 0x854 -#define CXADEC_DFT4_STATUS 0x858 -#define CXADEC_AM_MTS_DET 0x85C -#define CXADEC_ANALOG_MUX_CTL 0x860 -#define CXADEC_DIG_PLL_CTL1 0x864 -#define CXADEC_DIG_PLL_CTL2 0x868 -#define CXADEC_DIG_PLL_CTL3 0x86C -#define CXADEC_DIG_PLL_CTL4 0x870 -#define CXADEC_DIG_PLL_CTL5 0x874 -#define CXADEC_DEEMPH_GAIN_CTL 0x878 -#define CXADEC_DEEMPH_COEF1 0x87C -#define CXADEC_DEEMPH_COEF2 0x880 -#define CXADEC_DBX1_CTL1 0x884 -#define CXADEC_DBX1_CTL2 0x888 -#define CXADEC_DBX1_STATUS 0x88C -#define CXADEC_DBX2_CTL1 0x890 -#define CXADEC_DBX2_CTL2 0x894 -#define CXADEC_DBX2_STATUS 0x898 -#define CXADEC_AM_FM_DIFF 0x89C - -/* NICAM registers go here */ -#define CXADEC_NICAM_STATUS 0x8C8 -#define CXADEC_DEMATRIX_CTL 0x8CC - -#define CXADEC_PATH1_CTL1 0x8D0 -#define CXADEC_PATH1_VOL_CTL 0x8D4 -#define CXADEC_PATH1_EQ_CTL 0x8D8 -#define CXADEC_PATH1_SC_CTL 0x8DC - -#define CXADEC_PATH2_CTL1 0x8E0 -#define CXADEC_PATH2_VOL_CTL 0x8E4 -#define CXADEC_PATH2_EQ_CTL 0x8E8 -#define CXADEC_PATH2_SC_CTL 0x8EC - -#define CXADEC_SRC_CTL 0x8F0 -#define CXADEC_SRC_LF_COEF 0x8F4 -#define CXADEC_SRC1_CTL 0x8F8 -#define CXADEC_SRC2_CTL 0x8FC -#define CXADEC_SRC3_CTL 0x900 -#define CXADEC_SRC4_CTL 0x904 -#define CXADEC_SRC5_CTL 0x908 -#define CXADEC_SRC6_CTL 0x90C - -#define CXADEC_BASEBAND_OUT_SEL 0x910 -#define CXADEC_I2S_IN_CTL 0x914 -#define CXADEC_I2S_OUT_CTL 0x918 -#define CXADEC_AC97_CTL 0x91C -#define CXADEC_QAM_PDF 0x920 -#define CXADEC_QAM_CONST_DEC 0x924 -#define CXADEC_QAM_ROTATOR_FREQ 0x948 - -/* Bit definitions / settings used in Mako Audio */ -#define CXADEC_PREF_MODE_MONO_LANGA 0 -#define CXADEC_PREF_MODE_MONO_LANGB 1 -#define CXADEC_PREF_MODE_MONO_LANGC 2 -#define CXADEC_PREF_MODE_FALLBACK 3 -#define CXADEC_PREF_MODE_STEREO 4 -#define CXADEC_PREF_MODE_DUAL_LANG_AC 5 -#define CXADEC_PREF_MODE_DUAL_LANG_BC 6 -#define CXADEC_PREF_MODE_DUAL_LANG_AB 7 - - -#define CXADEC_DETECT_STEREO 1 -#define CXADEC_DETECT_DUAL 2 -#define CXADEC_DETECT_TRI 4 -#define CXADEC_DETECT_SAP 0x10 -#define CXADEC_DETECT_NO_SIGNAL 0xFF - -#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */ -#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */ -#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2 -#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3 -#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */ -#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */ -#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6 -#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7 -#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */ -#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */ -#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */ - -static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct cx18_av_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd; -} - -/* ----------------------------------------------------------------------- */ -/* cx18_av-core.c */ -int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); -int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); -int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value); -int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask); -int cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, - u32 mask); -u8 cx18_av_read(struct cx18 *cx, u16 addr); -u32 cx18_av_read4(struct cx18 *cx, u16 addr); -int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); -int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); -void cx18_av_std_setup(struct cx18 *cx); - -int cx18_av_probe(struct cx18 *cx); - -/* ----------------------------------------------------------------------- */ -/* cx18_av-firmware.c */ -int cx18_av_loadfw(struct cx18 *cx); - -/* ----------------------------------------------------------------------- */ -/* cx18_av-audio.c */ -int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq); -void cx18_av_audio_set_path(struct cx18 *cx); -extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops; - -/* ----------------------------------------------------------------------- */ -/* cx18_av-vbi.c */ -int cx18_av_decode_vbi_line(struct v4l2_subdev *sd, - struct v4l2_decode_vbi_line *vbi); -int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt); -int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); -int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-firmware.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-firmware.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,223 +0,0 @@ -/* - * cx18 ADEC firmware functions - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include - -#define CX18_AUDIO_ENABLE 0xc72014 -#define CX18_AI1_MUX_MASK 0x30 -#define CX18_AI1_MUX_I2S1 0x00 -#define CX18_AI1_MUX_I2S2 0x10 -#define CX18_AI1_MUX_843_I2S 0x20 -#define CX18_AI1_MUX_INVALID 0x30 - -#define FWFILE "v4l-cx23418-dig.fw" - -static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw) -{ - struct v4l2_subdev *sd = &cx->av_state.sd; - int ret = 0; - const u8 *data; - u32 size; - int addr; - u32 expected, dl_control; - - /* Ensure we put the 8051 in reset and enable firmware upload mode */ - dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); - do { - dl_control &= 0x00ffffff; - dl_control |= 0x0f000000; - cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control); - dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); - } while ((dl_control & 0xff000000) != 0x0f000000); - - /* Read and auto increment until at address 0x0000 */ - while (dl_control & 0x3fff) - dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); - - data = fw->data; - size = fw->size; - for (addr = 0; addr < size; addr++) { - dl_control &= 0xffff3fff; /* ignore top 2 bits of address */ - expected = 0x0f000000 | ((u32)data[addr] << 16) | addr; - if (expected != dl_control) { - CX18_ERR_DEV(sd, "verification of %s firmware load " - "failed: expected %#010x got %#010x\n", - FWFILE, expected, dl_control); - ret = -EIO; - break; - } - dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); - } - if (ret == 0) - CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n", - FWFILE, size); - return ret; -} - -int cx18_av_loadfw(struct cx18 *cx) -{ - struct v4l2_subdev *sd = &cx->av_state.sd; - const struct firmware *fw = NULL; - u32 size; - u32 u, v; - const u8 *ptr; - int i; - int retries1 = 0; - - if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) { - CX18_ERR_DEV(sd, "unable to open firmware %s\n", FWFILE); - return -EINVAL; - } - - /* The firmware load often has byte errors, so allow for several - retries, both at byte level and at the firmware load level. */ - while (retries1 < 5) { - cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000, - 0x00008430, 0xffffffff); /* cx25843 */ - cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff); - - /* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */ - cx18_av_write4_expect(cx, 0x8100, 0x00010000, - 0x00008430, 0xffffffff); /* cx25843 */ - - /* Put the 8051 in reset and enable firmware upload */ - cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000); - - ptr = fw->data; - size = fw->size; - - for (i = 0; i < size; i++) { - u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16); - u32 value = 0; - int retries2; - int unrec_err = 0; - - for (retries2 = 0; retries2 < CX18_MAX_MMIO_WR_RETRIES; - retries2++) { - cx18_av_write4_noretry(cx, CXADEC_DL_CTL, - dl_control); - udelay(10); - value = cx18_av_read4(cx, CXADEC_DL_CTL); - if (value == dl_control) - break; - /* Check if we can correct the byte by changing - the address. We can only write the lower - address byte of the address. */ - if ((value & 0x3F00) != (dl_control & 0x3F00)) { - unrec_err = 1; - break; - } - } - if (unrec_err || retries2 >= CX18_MAX_MMIO_WR_RETRIES) - break; - } - if (i == size) - break; - retries1++; - } - if (retries1 >= 5) { - CX18_ERR_DEV(sd, "unable to load firmware %s\n", FWFILE); - release_firmware(fw); - return -EIO; - } - - cx18_av_write4_expect(cx, CXADEC_DL_CTL, - 0x03000000 | fw->size, 0x03000000, 0x13000000); - - CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size); - - if (cx18_av_verifyfw(cx, fw) == 0) - cx18_av_write4_expect(cx, CXADEC_DL_CTL, - 0x13000000 | fw->size, 0x13000000, 0x13000000); - - /* Output to the 416 */ - cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000); - - /* Audio input control 1 set to Sony mode */ - /* Audio output input 2 is 0 for slave operation input */ - /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ - /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge - after WS transition for first bit of audio word. */ - cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0); - - /* Audio output control 1 is set to Sony mode */ - /* Audio output control 2 is set to 1 for master mode */ - /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ - /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge - after WS transition for first bit of audio word. */ - /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT - are generated) */ - cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0); - - /* set alt I2s master clock to /0x16 and enable alt divider i2s - passthrough */ - cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687); - - cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6, - 0x3F00FFFF); - /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */ - - /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */ - /* Register 0x09CC is defined by the Merlin firmware, and doesn't - have a name in the spec. */ - cx18_av_write4(cx, 0x09CC, 1); - - v = cx18_read_reg(cx, CX18_AUDIO_ENABLE); - /* If bit 11 is 1, clear bit 10 */ - if (v & 0x800) - cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE, - 0, 0x400); - - /* Toggle the AI1 MUX */ - v = cx18_read_reg(cx, CX18_AUDIO_ENABLE); - u = v & CX18_AI1_MUX_MASK; - v &= ~CX18_AI1_MUX_MASK; - if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) { - /* Switch to I2S1 */ - v |= CX18_AI1_MUX_I2S1; - cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, - v, CX18_AI1_MUX_MASK); - /* Switch back to the A/V decoder core I2S output */ - v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S; - } else { - /* Switch to the A/V decoder core I2S output */ - v |= CX18_AI1_MUX_843_I2S; - cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, - v, CX18_AI1_MUX_MASK); - /* Switch back to I2S1 or I2S2 */ - v = (v & ~CX18_AI1_MUX_MASK) | u; - } - cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, - v, CX18_AI1_MUX_MASK); - - /* Enable WW auto audio standard detection */ - v = cx18_av_read4(cx, CXADEC_STD_DET_CTL); - v |= 0xFF; /* Auto by default */ - v |= 0x400; /* Stereo by default */ - v |= 0x14000000; - cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF); - - release_firmware(fw); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-vbi.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-av-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,311 +0,0 @@ -/* - * cx18 ADEC VBI functions - * - * Derived from cx25840-vbi.c - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - - -#include "cx18-driver.h" - -/* - * For sliced VBI output, we set up to use VIP-1.1, 8-bit mode, - * NN counts 1 byte Dwords, an IDID with the VBI line # in it. - * Thus, according to the VIP-2 Spec, our VBI ancillary data lines - * (should!) look like: - * 4 byte EAV code: 0xff 0x00 0x00 0xRP - * unknown number of possible idle bytes - * 3 byte Anc data preamble: 0x00 0xff 0xff - * 1 byte data identifier: ne010iii (parity bits, 010, DID bits) - * 1 byte secondary data id: nessssss (parity bits, SDID bits) - * 1 byte data word count: necccccc (parity bits, NN Dword count) - * 2 byte Internal DID: VBI-line-# 0x80 - * NN data bytes - * 1 byte checksum - * Fill bytes needed to fil out to 4*NN bytes of payload - * - * The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, & - * in the vertical blanking interval are: - * 0xb0 (Task 0 VerticalBlank HorizontalBlank 0 0 0 0) - * 0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0) - * - * Since the V bit is only allowed to toggle in the EAV RP code, just - * before the first active region line and for active lines, they are: - * 0x90 (Task 0 0 HorizontalBlank 0 0 0 0) - * 0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0) - * - * The user application DID bytes we care about are: - * 0x91 (1 0 010 0 !ActiveLine AncDataPresent) - * 0x55 (0 1 010 2ndField !ActiveLine AncDataPresent) - * - */ -static const u8 sliced_vbi_did[2] = { 0x91, 0x55 }; - -struct vbi_anc_data { - /* u8 eav[4]; */ - /* u8 idle[]; Variable number of idle bytes */ - u8 preamble[3]; - u8 did; - u8 sdid; - u8 data_count; - u8 idid[2]; - u8 payload[1]; /* data_count of payload */ - /* u8 checksum; */ - /* u8 fill[]; Variable number of fill bytes */ -}; - -static int odd_parity(u8 c) -{ - c ^= (c >> 4); - c ^= (c >> 2); - c ^= (c >> 1); - - return c & 1; -} - -static int decode_vps(u8 *dst, u8 *p) -{ - static const u8 biphase_tbl[] = { - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, - 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, - 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, - 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, - 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, - 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, - 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, - 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, - 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, - 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, - 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, - 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, - 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, - 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, - 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, - 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, - 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, - 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, - 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, - 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, - 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, - 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - }; - - u8 c, err = 0; - int i; - - for (i = 0; i < 2 * 13; i += 2) { - err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; - c = (biphase_tbl[p[i + 1]] & 0xf) | - ((biphase_tbl[p[i]] & 0xf) << 4); - dst[i / 2] = c; - } - - return err & 0xf0; -} - -int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - static const u16 lcr2vbi[] = { - 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ - 0, V4L2_SLICED_WSS_625, 0, /* 4 */ - V4L2_SLICED_CAPTION_525, /* 6 */ - 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ - 0, 0, 0, 0 - }; - int is_pal = !(state->std & V4L2_STD_525_60); - int i; - - memset(svbi, 0, sizeof(*svbi)); - /* we're done if raw VBI is active */ - if ((cx18_av_read(cx, 0x404) & 0x10) == 0) - return 0; - - if (is_pal) { - for (i = 7; i <= 23; i++) { - u8 v = cx18_av_read(cx, 0x424 + i - 7); - - svbi->service_lines[0][i] = lcr2vbi[v >> 4]; - svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; - svbi->service_set |= svbi->service_lines[0][i] | - svbi->service_lines[1][i]; - } - } else { - for (i = 10; i <= 21; i++) { - u8 v = cx18_av_read(cx, 0x424 + i - 10); - - svbi->service_lines[0][i] = lcr2vbi[v >> 4]; - svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; - svbi->service_set |= svbi->service_lines[0][i] | - svbi->service_lines[1][i]; - } - } - return 0; -} - -int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - - /* Setup standard */ - cx18_av_std_setup(cx); - - /* VBI Offset */ - cx18_av_write(cx, 0x47f, state->slicer_line_delay); - cx18_av_write(cx, 0x404, 0x2e); - return 0; -} - -int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - int is_pal = !(state->std & V4L2_STD_525_60); - int i, x; - u8 lcr[24]; - - for (x = 0; x <= 23; x++) - lcr[x] = 0x00; - - /* Setup standard */ - cx18_av_std_setup(cx); - - /* Sliced VBI */ - cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */ - cx18_av_write(cx, 0x406, 0x13); - cx18_av_write(cx, 0x47f, state->slicer_line_delay); - - /* Force impossible lines to 0 */ - if (is_pal) { - for (i = 0; i <= 6; i++) - svbi->service_lines[0][i] = - svbi->service_lines[1][i] = 0; - } else { - for (i = 0; i <= 9; i++) - svbi->service_lines[0][i] = - svbi->service_lines[1][i] = 0; - - for (i = 22; i <= 23; i++) - svbi->service_lines[0][i] = - svbi->service_lines[1][i] = 0; - } - - /* Build register values for requested service lines */ - for (i = 7; i <= 23; i++) { - for (x = 0; x <= 1; x++) { - switch (svbi->service_lines[1-x][i]) { - case V4L2_SLICED_TELETEXT_B: - lcr[i] |= 1 << (4 * x); - break; - case V4L2_SLICED_WSS_625: - lcr[i] |= 4 << (4 * x); - break; - case V4L2_SLICED_CAPTION_525: - lcr[i] |= 6 << (4 * x); - break; - case V4L2_SLICED_VPS: - lcr[i] |= 9 << (4 * x); - break; - } - } - } - - if (is_pal) { - for (x = 1, i = 0x424; i <= 0x434; i++, x++) - cx18_av_write(cx, i, lcr[6 + x]); - } else { - for (x = 1, i = 0x424; i <= 0x430; i++, x++) - cx18_av_write(cx, i, lcr[9 + x]); - for (i = 0x431; i <= 0x434; i++) - cx18_av_write(cx, i, 0); - } - - cx18_av_write(cx, 0x43c, 0x16); - /* Should match vblank set in cx18_av_std_setup() */ - cx18_av_write(cx, 0x474, is_pal ? 38 : 26); - return 0; -} - -int cx18_av_decode_vbi_line(struct v4l2_subdev *sd, - struct v4l2_decode_vbi_line *vbi) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - struct vbi_anc_data *anc = (struct vbi_anc_data *)vbi->p; - u8 *p; - int did, sdid, l, err = 0; - - /* - * Check for the ancillary data header for sliced VBI - */ - if (anc->preamble[0] || - anc->preamble[1] != 0xff || anc->preamble[2] != 0xff || - (anc->did != sliced_vbi_did[0] && - anc->did != sliced_vbi_did[1])) { - vbi->line = vbi->type = 0; - return 0; - } - - did = anc->did; - sdid = anc->sdid & 0xf; - l = anc->idid[0] & 0x3f; - l += state->slicer_line_offset; - p = anc->payload; - - /* Decode the SDID set by the slicer */ - switch (sdid) { - case 1: - sdid = V4L2_SLICED_TELETEXT_B; - break; - case 4: - sdid = V4L2_SLICED_WSS_625; - break; - case 6: - sdid = V4L2_SLICED_CAPTION_525; - err = !odd_parity(p[0]) || !odd_parity(p[1]); - break; - case 9: - sdid = V4L2_SLICED_VPS; - if (decode_vps(p, p) != 0) - err = 1; - break; - default: - sdid = 0; - err = 1; - break; - } - - vbi->type = err ? 0 : sdid; - vbi->line = err ? 0 : l; - vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]); - vbi->p = p; - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-cards.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,628 +0,0 @@ -/* - * cx18 functions to query card hardware - * - * Derived from ivtv-cards.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-cards.h" -#include "cx18-av-core.h" -#include "cx18-i2c.h" -#include - -#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM) - -/********************** card configuration *******************************/ - -/* usual i2c tuner addresses to probe */ -static struct cx18_card_tuner_i2c cx18_i2c_std = { - .radio = { I2C_CLIENT_END }, - .demod = { 0x43, I2C_CLIENT_END }, - .tv = { 0x61, 0x60, I2C_CLIENT_END }, -}; - -/* Please add new PCI IDs to: http://pci-ids.ucw.cz/ - This keeps the PCI ID database up to date. Note that the entries - must be added under vendor 0x4444 (Conexant) as subsystem IDs. - New vendor IDs should still be added to the vendor ID list. */ - -/* Hauppauge HVR-1600 cards */ - -/* Note: for Hauppauge cards the tveeprom information is used instead - of PCI IDs */ -static const struct cx18_card cx18_card_hvr1600_esmt = { - .type = CX18_CARD_HVR_1600_ESMT, - .name = "Hauppauge HVR-1600", - .comment = "Simultaneous Digital and Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_CS5345, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL | - CX18_HW_Z8F0811_IR_HAUP, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, - { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, - { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, - { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, - .ddr = { - /* ESMT M13S128324A-5B memory */ - .chip_config = 0x003, - .refresh = 0x30c, - .timing1 = 0x44220e82, - .timing2 = 0x08, - .tune_lane = 0, - .initial_emrs = 0, - }, - .gpio_init.initial_value = 0x3001, - .gpio_init.direction = 0x3001, - .gpio_i2c_slave_reset = { - .active_lo_mask = 0x3001, - .msecs_asserted = 10, - .msecs_recovery = 40, - .ir_reset_mask = 0x0001, - }, - .i2c = &cx18_i2c_std, -}; - -static const struct cx18_card cx18_card_hvr1600_s5h1411 = { - .type = CX18_CARD_HVR_1600_S5H1411, - .name = "Hauppauge HVR-1600", - .comment = "Simultaneous Digital and Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_CS5345, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL | - CX18_HW_Z8F0811_IR_HAUP, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, - { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, - { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, - { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, - .ddr = { - /* ESMT M13S128324A-5B memory */ - .chip_config = 0x003, - .refresh = 0x30c, - .timing1 = 0x44220e82, - .timing2 = 0x08, - .tune_lane = 0, - .initial_emrs = 0, - }, - .gpio_init.initial_value = 0x3001, - .gpio_init.direction = 0x3001, - .gpio_i2c_slave_reset = { - .active_lo_mask = 0x3001, - .msecs_asserted = 10, - .msecs_recovery = 40, - .ir_reset_mask = 0x0001, - }, - .i2c = &cx18_i2c_std, -}; - -static const struct cx18_card cx18_card_hvr1600_samsung = { - .type = CX18_CARD_HVR_1600_SAMSUNG, - .name = "Hauppauge HVR-1600 (Preproduction)", - .comment = "Simultaneous Digital and Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_CS5345, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL | - CX18_HW_Z8F0811_IR_HAUP, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, - { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, - { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, - { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, - .ddr = { - /* Samsung K4D263238G-VC33 memory */ - .chip_config = 0x003, - .refresh = 0x30c, - .timing1 = 0x23230b73, - .timing2 = 0x08, - .tune_lane = 0, - .initial_emrs = 2, - }, - .gpio_init.initial_value = 0x3001, - .gpio_init.direction = 0x3001, - .gpio_i2c_slave_reset = { - .active_lo_mask = 0x3001, - .msecs_asserted = 10, - .msecs_recovery = 40, - .ir_reset_mask = 0x0001, - }, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Compro VideoMate H900: note that this card is analog only! */ - -static const struct cx18_card_pci_info cx18_pci_h900[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_h900 = { - .type = CX18_CARD_COMPRO_H900, - .name = "Compro VideoMate H900", - .comment = "Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL1, 0 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL1, 0 }, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .ddr = { - /* EtronTech EM6A9160TS-5G memory */ - .chip_config = 0x50003, - .refresh = 0x753, - .timing1 = 0x24330e84, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 0, - }, - .xceive_pin = 15, - .pci_list = cx18_pci_h900, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPC718: not working at the moment! */ - -static const struct cx18_card_pci_info cx18_pci_mpc718[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_mpc718 = { - .type = CX18_CARD_YUAN_MPC718, - .name = "Yuan MPC718 MiniPCI DVB-T/Analog", - .comment = "Experimenters needed for device to work well.\n" - "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - { CX18_CARD_INPUT_SVIDEO2, 2, - CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, - }, - .tuners = { - /* XC3028 tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - /* FIXME - the FM radio is just a guess and driver doesn't use SIF */ - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, - .ddr = { - /* Hynix HY5DU283222B DDR RAM */ - .chip_config = 0x303, - .refresh = 0x3bd, - .timing1 = 0x36320966, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 2, - }, - .gpio_init.initial_value = 0x1, - .gpio_init.direction = 0x3, - /* FIXME - these GPIO's are just guesses */ - .gpio_audio_input = { .mask = 0x3, - .tuner = 0x1, - .linein = 0x3, - .radio = 0x1 }, - .xceive_pin = 0, - .pci_list = cx18_pci_mpc718, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* GoTView PCI */ - -static const struct cx18_card_pci_info cx18_pci_gotview_dvd3[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_GOTVIEW, 0x3343 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_gotview_dvd3 = { - .type = CX18_CARD_GOTVIEW_PCI_DVD3, - .name = "GoTView PCI DVD3 Hybrid", - .comment = "Experimenters needed for device to work well.\n" - "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - { CX18_CARD_INPUT_SVIDEO2, 2, - CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, - }, - .tuners = { - /* XC3028 tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - /* FIXME - the FM radio is just a guess and driver doesn't use SIF */ - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, - .ddr = { - /* Hynix HY5DU283222B DDR RAM */ - .chip_config = 0x303, - .refresh = 0x3bd, - .timing1 = 0x36320966, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 2, - }, - .gpio_init.initial_value = 0x1, - .gpio_init.direction = 0x3, - - .gpio_audio_input = { .mask = 0x3, - .tuner = 0x1, - .linein = 0x2, - .radio = 0x1 }, - .xceive_pin = 0, - .pci_list = cx18_pci_gotview_dvd3, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Conexant Raptor PAL/SECAM: note that this card is analog only! */ - -static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_cnxt_raptor_pal = { - .type = CX18_CARD_CNXT_RAPTOR_PAL, - .name = "Conexant Raptor PAL/SECAM", - .comment = "Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - { CX18_CARD_INPUT_SVIDEO2, 2, - CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, - }, - .tuners = { - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 }, - .ddr = { - /* MT 46V16M16 memory */ - .chip_config = 0x50306, - .refresh = 0x753, - .timing1 = 0x33220953, - .timing2 = 0x09, - .tune_lane = 0, - .initial_emrs = 0, - }, - .gpio_init.initial_value = 0x1002, - .gpio_init.direction = 0xf002, - .gpio_audio_input = { .mask = 0xf002, - .tuner = 0x1002, /* LED D1 Tuner AF */ - .linein = 0x2000, /* LED D2 Line In 1 */ - .radio = 0x4002 }, /* LED D3 Tuner AF */ - .pci_list = cx18_pci_cnxt_raptor_pal, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Toshiba Qosmio laptop internal DVB-T/Analog Hybrid Tuner */ - -static const struct cx18_card_pci_info cx18_pci_toshiba_qosmio_dvbt[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_TOSHIBA, 0x0110 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = { - .type = CX18_CARD_TOSHIBA_QOSMIO_DVBT, - .name = "Toshiba Qosmio DVB-T/Analog", - .comment = "Experimenters and photos needed for device to work well.\n" - "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE6 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - }, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .ddr = { - .chip_config = 0x202, - .refresh = 0x3bb, - .timing1 = 0x33320a63, - .timing2 = 0x0a, - .tune_lane = 0, - .initial_emrs = 0x42, - }, - .xceive_pin = 15, - .pci_list = cx18_pci_toshiba_qosmio_dvbt, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Leadtek WinFast PVR2100 */ - -static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100 */ - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_leadtek_pvr2100 = { - .type = CX18_CARD_LEADTEK_PVR2100, - .name = "Leadtek WinFast PVR2100", - .comment = "Experimenters and photos needed for device to work well.\n" - "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX | - CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - }, - .tuners = { - /* XC2028 tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, - .ddr = { - /* Pointer to proper DDR config values provided by Terry Wu */ - .chip_config = 0x303, - .refresh = 0x3bb, - .timing1 = 0x24220e83, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 0x2, - }, - .gpio_init.initial_value = 0x6, - .gpio_init.direction = 0x7, - .gpio_audio_input = { .mask = 0x7, - .tuner = 0x6, .linein = 0x2, .radio = 0x2 }, - .xceive_pin = 1, - .pci_list = cx18_pci_leadtek_pvr2100, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Leadtek WinFast DVR3100 H */ - -static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */ - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_leadtek_dvr3100h = { - .type = CX18_CARD_LEADTEK_DVR3100H, - .name = "Leadtek WinFast DVR3100 H", - .comment = "Simultaneous DVB-T and Analog capture supported,\n" - "\texcept when capturing Analog from the antenna input.\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX | - CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - }, - .tuners = { - /* XC3028 tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, - .ddr = { - /* Pointer to proper DDR config values provided by Terry Wu */ - .chip_config = 0x303, - .refresh = 0x3bb, - .timing1 = 0x24220e83, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 0x2, - }, - .gpio_init.initial_value = 0x6, - .gpio_init.direction = 0x7, - .gpio_audio_input = { .mask = 0x7, - .tuner = 0x6, .linein = 0x2, .radio = 0x2 }, - .xceive_pin = 1, - .pci_list = cx18_pci_leadtek_dvr3100h, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -static const struct cx18_card *cx18_card_list[] = { - &cx18_card_hvr1600_esmt, - &cx18_card_hvr1600_samsung, - &cx18_card_h900, - &cx18_card_mpc718, - &cx18_card_cnxt_raptor_pal, - &cx18_card_toshiba_qosmio_dvbt, - &cx18_card_leadtek_pvr2100, - &cx18_card_leadtek_dvr3100h, - &cx18_card_gotview_dvd3, - &cx18_card_hvr1600_s5h1411 -}; - -const struct cx18_card *cx18_get_card(u16 index) -{ - if (index >= ARRAY_SIZE(cx18_card_list)) - return NULL; - return cx18_card_list[index]; -} - -int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input) -{ - const struct cx18_card_video_input *card_input = - cx->card->video_inputs + index; - static const char * const input_strs[] = { - "Tuner 1", - "S-Video 1", - "S-Video 2", - "Composite 1", - "Composite 2", - "Component 1" - }; - - if (index >= cx->nof_inputs) - return -EINVAL; - input->index = index; - strlcpy(input->name, input_strs[card_input->video_type - 1], - sizeof(input->name)); - input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ? - V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); - input->audioset = (1 << cx->nof_audio_inputs) - 1; - input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? - cx->tuner_std : V4L2_STD_ALL; - return 0; -} - -int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio) -{ - const struct cx18_card_audio_input *aud_input = - cx->card->audio_inputs + index; - static const char * const input_strs[] = { - "Tuner 1", - "Line In 1", - "Line In 2" - }; - - memset(audio, 0, sizeof(*audio)); - if (index >= cx->nof_audio_inputs) - return -EINVAL; - strlcpy(audio->name, input_strs[aud_input->audio_type - 1], - sizeof(audio->name)); - audio->index = index; - audio->capability = V4L2_AUDCAP_STEREO; - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-cards.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-cards.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-cards.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-cards.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -/* - * cx18 functions to query card hardware - * - * Derived from ivtv-cards.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -/* hardware flags */ -#define CX18_HW_TUNER (1 << 0) -#define CX18_HW_TVEEPROM (1 << 1) -#define CX18_HW_CS5345 (1 << 2) -#define CX18_HW_DVB (1 << 3) -#define CX18_HW_418_AV (1 << 4) -#define CX18_HW_GPIO_MUX (1 << 5) -#define CX18_HW_GPIO_RESET_CTRL (1 << 6) -#define CX18_HW_Z8F0811_IR_TX_HAUP (1 << 7) -#define CX18_HW_Z8F0811_IR_RX_HAUP (1 << 8) -#define CX18_HW_Z8F0811_IR_HAUP (CX18_HW_Z8F0811_IR_RX_HAUP | \ - CX18_HW_Z8F0811_IR_TX_HAUP) - -#define CX18_HW_IR_ANY (CX18_HW_Z8F0811_IR_RX_HAUP | \ - CX18_HW_Z8F0811_IR_TX_HAUP) - -/* video inputs */ -#define CX18_CARD_INPUT_VID_TUNER 1 -#define CX18_CARD_INPUT_SVIDEO1 2 -#define CX18_CARD_INPUT_SVIDEO2 3 -#define CX18_CARD_INPUT_COMPOSITE1 4 -#define CX18_CARD_INPUT_COMPOSITE2 5 -#define CX18_CARD_INPUT_COMPONENT1 6 - -/* audio inputs */ -#define CX18_CARD_INPUT_AUD_TUNER 1 -#define CX18_CARD_INPUT_LINE_IN1 2 -#define CX18_CARD_INPUT_LINE_IN2 3 - -#define CX18_CARD_MAX_VIDEO_INPUTS 6 -#define CX18_CARD_MAX_AUDIO_INPUTS 3 -#define CX18_CARD_MAX_TUNERS 2 - -/* V4L2 capability aliases */ -#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \ - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) - -struct cx18_card_video_input { - u8 video_type; /* video input type */ - u8 audio_index; /* index in cx18_card_audio_input array */ - u32 video_input; /* hardware video input */ -}; - -struct cx18_card_audio_input { - u8 audio_type; /* audio input type */ - u32 audio_input; /* hardware audio input */ - u16 muxer_input; /* hardware muxer input for boards with a - multiplexer chip */ -}; - -struct cx18_card_pci_info { - u16 device; - u16 subsystem_vendor; - u16 subsystem_device; -}; - -/* GPIO definitions */ - -/* The mask is the set of bits used by the operation */ - -struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */ - u32 direction; /* DIR setting. Leave to 0 if no init is needed */ - u32 initial_value; -}; - -struct cx18_gpio_i2c_slave_reset { - u32 active_lo_mask; /* GPIO outputs that reset i2c chips when low */ - u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */ - int msecs_asserted; /* time period reset must remain asserted */ - int msecs_recovery; /* time after deassert for chips to be ready */ - u32 ir_reset_mask; /* GPIO to reset the Zilog Z8F0811 IR contoller */ -}; - -struct cx18_gpio_audio_input { /* select tuner/line in input */ - u32 mask; /* leave to 0 if not supported */ - u32 tuner; - u32 linein; - u32 radio; -}; - -struct cx18_card_tuner { - v4l2_std_id std; /* standard for which the tuner is suitable */ - int tuner; /* tuner ID (from tuner.h) */ -}; - -struct cx18_card_tuner_i2c { - unsigned short radio[2];/* radio tuner i2c address to probe */ - unsigned short demod[2];/* demodulator i2c address to probe */ - unsigned short tv[4]; /* tv tuner i2c addresses to probe */ -}; - -struct cx18_ddr { /* DDR config data */ - u32 chip_config; - u32 refresh; - u32 timing1; - u32 timing2; - u32 tune_lane; - u32 initial_emrs; -}; - -/* for card information/parameters */ -struct cx18_card { - int type; - char *name; - char *comment; - u32 v4l2_capabilities; - u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only - 1 dev allowed currently) */ - u32 hw_muxer; /* hardware used to multiplex audio input */ - u32 hw_all; /* all hardware used by the board */ - struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS]; - struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS]; - struct cx18_card_audio_input radio_input; - - /* GPIO card-specific settings */ - u8 xceive_pin; /* XCeive tuner GPIO reset pin */ - struct cx18_gpio_init gpio_init; - struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset; - struct cx18_gpio_audio_input gpio_audio_input; - - struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS]; - struct cx18_card_tuner_i2c *i2c; - - struct cx18_ddr ddr; - - /* list of device and subsystem vendor/devices that - correspond to this card type. */ - const struct cx18_card_pci_info *pci_list; -}; - -int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input); -int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input); -const struct cx18_card *cx18_get_card(u16 index); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-controls.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-controls.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-controls.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-controls.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -/* - * cx18 ioctl control functions - * - * Derived from ivtv-controls.c - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 -#include - -#include "cx18-driver.h" -#include "cx18-cards.h" -#include "cx18-ioctl.h" -#include "cx18-audio.h" -#include "cx18-mailbox.h" -#include "cx18-controls.h" - -static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) -{ - struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - int type = cxhdl->stream_type->val; - - if (atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV || - !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS || - type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD || - type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) { - /* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */ - cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE; - CX18_DEBUG_INFO("disabled insertion of sliced VBI data into " - "the MPEG stream\n"); - return 0; - } - - /* Allocate sliced VBI buffers if needed. */ - if (cx->vbi.sliced_mpeg_data[0] == NULL) { - int i; - - for (i = 0; i < CX18_VBI_FRAMES; i++) { - cx->vbi.sliced_mpeg_data[i] = - kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL); - if (cx->vbi.sliced_mpeg_data[i] == NULL) { - while (--i >= 0) { - kfree(cx->vbi.sliced_mpeg_data[i]); - cx->vbi.sliced_mpeg_data[i] = NULL; - } - cx->vbi.insert_mpeg = - V4L2_MPEG_STREAM_VBI_FMT_NONE; - CX18_WARN("Unable to allocate buffers for " - "sliced VBI data insertion\n"); - return -ENOMEM; - } - } - } - - cx->vbi.insert_mpeg = fmt; - CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS," - "when sliced VBI is enabled\n"); - - /* - * If our current settings have no lines set for capture, store a valid, - * default set of service lines to capture, in our current settings. - */ - if (cx18_get_service_set(cx->vbi.sliced_in) == 0) { - if (cx->is_60hz) - cx->vbi.sliced_in->service_set = - V4L2_SLICED_CAPTION_525; - else - cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; - cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz); - } - return 0; -} - -static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) -{ - struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; - - /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = V4L2_MBUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); - return 0; -} - -static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) -{ - static const u32 freqs[3] = { 44100, 48000, 32000 }; - struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (idx < ARRAY_SIZE(freqs)) - cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); - return 0; -} - -static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) -{ - struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - - cx->dualwatch_stereo_mode = val; - return 0; -} - -struct cx2341x_handler_ops cx18_cxhdl_ops = { - .s_audio_mode = cx18_s_audio_mode, - .s_audio_sampling_freq = cx18_s_audio_sampling_freq, - .s_video_encoding = cx18_s_video_encoding, - .s_stream_vbi_fmt = cx18_s_stream_vbi_fmt, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-controls.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-controls.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-controls.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-controls.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -/* - * cx18 ioctl control functions - * - * Derived from ivtv-controls.h - * - * Copyright (C) 2007 Hans Verkuil - - * 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, or - * (at your option) any later version. - - * 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 - */ - -extern struct cx2341x_handler_ops cx18_cxhdl_ops; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-driver.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-driver.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1335 +0,0 @@ -/* - * cx18 driver initialization and card probing - * - * Derived from ivtv-driver.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-version.h" -#include "cx18-cards.h" -#include "cx18-i2c.h" -#include "cx18-irq.h" -#include "cx18-gpio.h" -#include "cx18-firmware.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-av-core.h" -#include "cx18-scb.h" -#include "cx18-mailbox.h" -#include "cx18-ioctl.h" -#include "cx18-controls.h" -#include "tuner-xc2028.h" - -#include - -/* If you have already X v4l cards, then set this to X. This way - the device numbers stay matched. Example: you have a WinTV card - without radio and a Compro H900 with. Normally this would give a - video1 device together with a radio0 device for the Compro. By - setting this to 1 you ensure that radio0 is now also radio1. */ -int cx18_first_minor; - -/* Callback for registering extensions */ -int (*cx18_ext_init)(struct cx18 *); -EXPORT_SYMBOL(cx18_ext_init); - -/* add your revision and whatnot here */ -static struct pci_device_id cx18_pci_tbl[] __devinitdata = { - {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, cx18_pci_tbl); - -static atomic_t cx18_instance = ATOMIC_INIT(0); - -/* Parameter declarations */ -static int cardtype[CX18_MAX_CARDS]; -static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static unsigned cardtype_c = 1; -static unsigned tuner_c = 1; -static unsigned radio_c = 1; -static char pal[] = "--"; -static char secam[] = "--"; -static char ntsc[] = "-"; - -/* Buffers */ -static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS; -static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; -static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS; -static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS; -static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS; -static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; - -static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE; -static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE; -static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE; -static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE; -static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE; - -static int enc_ts_bufs = -1; -static int enc_mpg_bufs = -1; -static int enc_idx_bufs = CX18_MAX_FW_MDLS_PER_STREAM; -static int enc_yuv_bufs = -1; -static int enc_vbi_bufs = -1; -static int enc_pcm_bufs = -1; - - -static int cx18_pci_latency = 1; - -static int mmio_ndelay; -static int retry_mmio = 1; - -int cx18_debug; - -module_param_array(tuner, int, &tuner_c, 0644); -module_param_array(radio, bool, &radio_c, 0644); -module_param_array(cardtype, int, &cardtype_c, 0644); -module_param_string(pal, pal, sizeof(pal), 0644); -module_param_string(secam, secam, sizeof(secam), 0644); -module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); -module_param_named(debug, cx18_debug, int, 0644); -module_param(mmio_ndelay, int, 0644); -module_param(retry_mmio, int, 0644); -module_param(cx18_pci_latency, int, 0644); -module_param(cx18_first_minor, int, 0644); - -module_param(enc_ts_buffers, int, 0644); -module_param(enc_mpg_buffers, int, 0644); -module_param(enc_idx_buffers, int, 0644); -module_param(enc_yuv_buffers, int, 0644); -module_param(enc_vbi_buffers, int, 0644); -module_param(enc_pcm_buffers, int, 0644); - -module_param(enc_ts_bufsize, int, 0644); -module_param(enc_mpg_bufsize, int, 0644); -module_param(enc_idx_bufsize, int, 0644); -module_param(enc_yuv_bufsize, int, 0644); -module_param(enc_pcm_bufsize, int, 0644); - -module_param(enc_ts_bufs, int, 0644); -module_param(enc_mpg_bufs, int, 0644); -module_param(enc_idx_bufs, int, 0644); -module_param(enc_yuv_bufs, int, 0644); -module_param(enc_vbi_bufs, int, 0644); -module_param(enc_pcm_bufs, int, 0644); - -MODULE_PARM_DESC(tuner, "Tuner type selection,\n" - "\t\t\tsee tuner.h for values"); -MODULE_PARM_DESC(radio, - "Enable or disable the radio. Use only if autodetection\n" - "\t\t\tfails. 0 = disable, 1 = enable"); -MODULE_PARM_DESC(cardtype, - "Only use this option if your card is not detected properly.\n" - "\t\tSpecify card type:\n" - "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n" - "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n" - "\t\t\t 3 = Compro VideoMate H900\n" - "\t\t\t 4 = Yuan MPC718\n" - "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" - "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n" - "\t\t\t 7 = Leadtek WinFast PVR2100\n" - "\t\t\t 8 = Leadtek WinFast DVR3100 H\n" - "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n" - "\t\t\t 10 = Hauppauge HVR 1600 (S5H1411)\n" - "\t\t\t 0 = Autodetect (default)\n" - "\t\t\t-1 = Ignore this card\n\t\t"); -MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); -MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); -MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); -MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: 0\n" - "\t\t\t 1/0x0001: warning\n" - "\t\t\t 2/0x0002: info\n" - "\t\t\t 4/0x0004: mailbox\n" - "\t\t\t 8/0x0008: dma\n" - "\t\t\t 16/0x0010: ioctl\n" - "\t\t\t 32/0x0020: file\n" - "\t\t\t 64/0x0040: i2c\n" - "\t\t\t128/0x0080: irq\n" - "\t\t\t256/0x0100: high volume\n"); -MODULE_PARM_DESC(cx18_pci_latency, - "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" - "\t\t\tDefault: Yes"); -MODULE_PARM_DESC(retry_mmio, - "(Deprecated) MMIO writes are now always checked and retried\n" - "\t\t\tEffectively: 1 [Yes]"); -MODULE_PARM_DESC(mmio_ndelay, - "(Deprecated) MMIO accesses are now never purposely delayed\n" - "\t\t\tEffectively: 0 ns"); -MODULE_PARM_DESC(enc_ts_buffers, - "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS)); -MODULE_PARM_DESC(enc_ts_bufsize, - "Size of an encoder TS buffer (kB)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE)); -MODULE_PARM_DESC(enc_ts_bufs, - "Number of encoder TS buffers\n" - "\t\t\tDefault is computed from other enc_ts_* parameters"); -MODULE_PARM_DESC(enc_mpg_buffers, - "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); -MODULE_PARM_DESC(enc_mpg_bufsize, - "Size of an encoder MPG buffer (kB)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE)); -MODULE_PARM_DESC(enc_mpg_bufs, - "Number of encoder MPG buffers\n" - "\t\t\tDefault is computed from other enc_mpg_* parameters"); -MODULE_PARM_DESC(enc_idx_buffers, - "(Deprecated) Encoder IDX buffer memory (MB)\n" - "\t\t\tIgnored, except 0 disables IDX buffer allocations\n" - "\t\t\tDefault: 1 [Enabled]"); -MODULE_PARM_DESC(enc_idx_bufsize, - "Size of an encoder IDX buffer (kB)\n" - "\t\t\tAllowed values are multiples of 1.5 kB rounded up\n" - "\t\t\t(multiples of size required for 64 index entries)\n" - "\t\t\tDefault: 2"); -MODULE_PARM_DESC(enc_idx_bufs, - "Number of encoder IDX buffers\n" - "\t\t\tDefault: " __stringify(CX18_MAX_FW_MDLS_PER_STREAM)); -MODULE_PARM_DESC(enc_yuv_buffers, - "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); -MODULE_PARM_DESC(enc_yuv_bufsize, - "Size of an encoder YUV buffer (kB)\n" - "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n" - "\t\t\t(multiples of size required for 32 screen lines)\n" - "\t\t\tDefault: 102"); -MODULE_PARM_DESC(enc_yuv_bufs, - "Number of encoder YUV buffers\n" - "\t\t\tDefault is computed from other enc_yuv_* parameters"); -MODULE_PARM_DESC(enc_vbi_buffers, - "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); -MODULE_PARM_DESC(enc_vbi_bufs, - "Number of encoder VBI buffers\n" - "\t\t\tDefault is computed from enc_vbi_buffers"); -MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); -MODULE_PARM_DESC(enc_pcm_bufsize, - "Size of an encoder PCM buffer (kB)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE)); -MODULE_PARM_DESC(enc_pcm_bufs, - "Number of encoder PCM buffers\n" - "\t\t\tDefault is computed from other enc_pcm_* parameters"); - -MODULE_PARM_DESC(cx18_first_minor, - "Set device node number assigned to first card"); - -MODULE_AUTHOR("Hans Verkuil"); -MODULE_DESCRIPTION("CX23418 driver"); -MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); -MODULE_LICENSE("GPL"); - - -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - struct cx18 *dev = container_of(work, struct cx18, request_module_wk); - - /* Make sure cx18-alsa module is loaded */ - request_module("cx18-alsa"); - - /* Initialize cx18-alsa for this instance of the cx18 device */ - if (cx18_ext_init != NULL) - cx18_ext_init(dev); -} - -static void request_modules(struct cx18 *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} - -static void flush_request_modules(struct cx18 *dev) -{ - flush_work_sync(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#define flush_request_modules(dev) -#endif /* CONFIG_MODULES */ - -/* Generic utility functions */ -int cx18_msleep_timeout(unsigned int msecs, int intr) -{ - long int timeout = msecs_to_jiffies(msecs); - int sig; - - do { - set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - timeout = schedule_timeout(timeout); - sig = intr ? signal_pending(current) : 0; - } while (!sig && timeout); - return sig; -} - -/* Release ioremapped memory */ -static void cx18_iounmap(struct cx18 *cx) -{ - if (cx == NULL) - return; - - /* Release io memory */ - if (cx->enc_mem != NULL) { - CX18_DEBUG_INFO("releasing enc_mem\n"); - iounmap(cx->enc_mem); - cx->enc_mem = NULL; - } -} - -static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len) -{ - int i; - - CX18_INFO("eeprom dump:\n"); - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - CX18_INFO("eeprom %02x:", i); - printk(KERN_CONT " %02x", eedata[i]); - if (15 == (i % 16)) - printk(KERN_CONT "\n"); - } -} - -/* Hauppauge card? get values from tveeprom */ -void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) -{ - struct i2c_client c; - u8 eedata[256]; - - memset(&c, 0, sizeof(c)); - strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name)); - c.adapter = &cx->i2c_adap[0]; - c.addr = 0xA0 >> 1; - - memset(tv, 0, sizeof(*tv)); - if (tveeprom_read(&c, eedata, sizeof(eedata))) - return; - - switch (cx->card->type) { - case CX18_CARD_HVR_1600_ESMT: - case CX18_CARD_HVR_1600_SAMSUNG: - case CX18_CARD_HVR_1600_S5H1411: - tveeprom_hauppauge_analog(&c, tv, eedata); - break; - case CX18_CARD_YUAN_MPC718: - case CX18_CARD_GOTVIEW_PCI_DVD3: - tv->model = 0x718; - cx18_eeprom_dump(cx, eedata, sizeof(eedata)); - CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n", - eedata[2], eedata[1], eedata[4], eedata[3]); - break; - default: - tv->model = 0xffffffff; - cx18_eeprom_dump(cx, eedata, sizeof(eedata)); - break; - } -} - -static void cx18_process_eeprom(struct cx18 *cx) -{ - struct tveeprom tv; - - cx18_read_eeprom(cx, &tv); - - /* Many thanks to Steven Toth from Hauppauge for providing the - model numbers */ - /* Note: the Samsung memory models cannot be reliably determined - from the model number. Use the cardtype module option if you - have one of these preproduction models. */ - switch (tv.model) { - case 74301: /* Retail models */ - case 74321: - case 74351: /* OEM models */ - case 74361: - /* Digital side is s5h1411/tda18271 */ - cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411); - break; - case 74021: /* Retail models */ - case 74031: - case 74041: - case 74141: - case 74541: /* OEM models */ - case 74551: - case 74591: - case 74651: - case 74691: - case 74751: - case 74891: - /* Digital side is s5h1409/mxl5005s */ - cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); - break; - case 0x718: - return; - case 0xffffffff: - CX18_INFO("Unknown EEPROM encoding\n"); - return; - case 0: - CX18_ERR("Invalid EEPROM\n"); - return; - default: - CX18_ERR("Unknown model %d, defaulting to original HVR-1600 " - "(cardtype=1)\n", tv.model); - cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); - break; - } - - cx->v4l2_cap = cx->card->v4l2_capabilities; - cx->card_name = cx->card->name; - cx->card_i2c = cx->card->i2c; - - CX18_INFO("Autodetected %s\n", cx->card_name); - - if (tv.tuner_type == TUNER_ABSENT) - CX18_ERR("tveeprom cannot autodetect tuner!\n"); - - if (cx->options.tuner == -1) - cx->options.tuner = tv.tuner_type; - if (cx->options.radio == -1) - cx->options.radio = (tv.has_radio != 0); - - if (cx->std != 0) - /* user specified tuner standard */ - return; - - /* autodetect tuner standard */ - if (tv.tuner_formats & V4L2_STD_PAL) { - CX18_DEBUG_INFO("PAL tuner detected\n"); - cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; - } else if (tv.tuner_formats & V4L2_STD_NTSC) { - CX18_DEBUG_INFO("NTSC tuner detected\n"); - cx->std |= V4L2_STD_NTSC_M; - } else if (tv.tuner_formats & V4L2_STD_SECAM) { - CX18_DEBUG_INFO("SECAM tuner detected\n"); - cx->std |= V4L2_STD_SECAM_L; - } else { - CX18_INFO("No tuner detected, default to NTSC-M\n"); - cx->std |= V4L2_STD_NTSC_M; - } -} - -static v4l2_std_id cx18_parse_std(struct cx18 *cx) -{ - switch (pal[0]) { - case '6': - return V4L2_STD_PAL_60; - case 'b': - case 'B': - case 'g': - case 'G': - return V4L2_STD_PAL_BG; - case 'h': - case 'H': - return V4L2_STD_PAL_H; - case 'n': - case 'N': - if (pal[1] == 'c' || pal[1] == 'C') - return V4L2_STD_PAL_Nc; - return V4L2_STD_PAL_N; - case 'i': - case 'I': - return V4L2_STD_PAL_I; - case 'd': - case 'D': - case 'k': - case 'K': - return V4L2_STD_PAL_DK; - case 'M': - case 'm': - return V4L2_STD_PAL_M; - case '-': - break; - default: - CX18_WARN("pal= argument not recognised\n"); - return 0; - } - - switch (secam[0]) { - case 'b': - case 'B': - case 'g': - case 'G': - case 'h': - case 'H': - return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; - case 'd': - case 'D': - case 'k': - case 'K': - return V4L2_STD_SECAM_DK; - case 'l': - case 'L': - if (secam[1] == 'C' || secam[1] == 'c') - return V4L2_STD_SECAM_LC; - return V4L2_STD_SECAM_L; - case '-': - break; - default: - CX18_WARN("secam= argument not recognised\n"); - return 0; - } - - switch (ntsc[0]) { - case 'm': - case 'M': - return V4L2_STD_NTSC_M; - case 'j': - case 'J': - return V4L2_STD_NTSC_M_JP; - case 'k': - case 'K': - return V4L2_STD_NTSC_M_KR; - case '-': - break; - default: - CX18_WARN("ntsc= argument not recognised\n"); - return 0; - } - - /* no match found */ - return 0; -} - -static void cx18_process_options(struct cx18 *cx) -{ - int i, j; - - cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */ - - cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */ - - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */ - - /* Ensure stream_buffers & stream_buf_size are valid */ - for (i = 0; i < CX18_MAX_STREAMS; i++) { - if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */ - cx->options.megabytes[i] <= 0 || /* User said 0 MB total */ - cx->stream_buf_size[i] <= 0) { /* User said buf size 0 */ - cx->options.megabytes[i] = 0; - cx->stream_buffers[i] = 0; - cx->stream_buf_size[i] = 0; - continue; - } - /* - * YUV is a special case where the stream_buf_size needs to be - * an integral multiple of 33.75 kB (storage for 32 screens - * lines to maintain alignment in case of lost buffers). - * - * IDX is a special case where the stream_buf_size should be - * an integral multiple of 1.5 kB (storage for 64 index entries - * to maintain alignment in case of lost buffers). - * - */ - if (i == CX18_ENC_STREAM_TYPE_YUV) { - cx->stream_buf_size[i] *= 1024; - cx->stream_buf_size[i] -= - (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE); - - if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE) - cx->stream_buf_size[i] = - CX18_UNIT_ENC_YUV_BUFSIZE; - } else if (i == CX18_ENC_STREAM_TYPE_IDX) { - cx->stream_buf_size[i] *= 1024; - cx->stream_buf_size[i] -= - (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE); - - if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE) - cx->stream_buf_size[i] = - CX18_UNIT_ENC_IDX_BUFSIZE; - } - /* - * YUV and IDX are special cases where the stream_buf_size is - * now in bytes. - * VBI is a special case where the stream_buf_size is fixed - * and already in bytes - */ - if (i == CX18_ENC_STREAM_TYPE_VBI || - i == CX18_ENC_STREAM_TYPE_YUV || - i == CX18_ENC_STREAM_TYPE_IDX) { - if (cx->stream_buffers[i] < 0) { - cx->stream_buffers[i] = - cx->options.megabytes[i] * 1024 * 1024 - / cx->stream_buf_size[i]; - } else { - /* N.B. This might round down to 0 */ - cx->options.megabytes[i] = - cx->stream_buffers[i] - * cx->stream_buf_size[i]/(1024 * 1024); - } - } else { - /* All other streams have stream_buf_size in kB here */ - if (cx->stream_buffers[i] < 0) { - cx->stream_buffers[i] = - cx->options.megabytes[i] * 1024 - / cx->stream_buf_size[i]; - } else { - /* N.B. This might round down to 0 */ - cx->options.megabytes[i] = - cx->stream_buffers[i] - * cx->stream_buf_size[i] / 1024; - } - /* convert from kB to bytes */ - cx->stream_buf_size[i] *= 1024; - } - CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, " - "%d bytes\n", i, cx->options.megabytes[i], - cx->stream_buffers[i], cx->stream_buf_size[i]); - } - - cx->options.cardtype = cardtype[cx->instance]; - cx->options.tuner = tuner[cx->instance]; - cx->options.radio = radio[cx->instance]; - - cx->std = cx18_parse_std(cx); - if (cx->options.cardtype == -1) { - CX18_INFO("Ignore card\n"); - return; - } - cx->card = cx18_get_card(cx->options.cardtype - 1); - if (cx->card) - CX18_INFO("User specified %s card\n", cx->card->name); - else if (cx->options.cardtype != 0) - CX18_ERR("Unknown user specified type, trying to autodetect card\n"); - if (cx->card == NULL) { - if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { - cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); - CX18_INFO("Autodetected Hauppauge card\n"); - } - } - if (cx->card == NULL) { - for (i = 0; (cx->card = cx18_get_card(i)); i++) { - if (cx->card->pci_list == NULL) - continue; - for (j = 0; cx->card->pci_list[j].device; j++) { - if (cx->pci_dev->device != - cx->card->pci_list[j].device) - continue; - if (cx->pci_dev->subsystem_vendor != - cx->card->pci_list[j].subsystem_vendor) - continue; - if (cx->pci_dev->subsystem_device != - cx->card->pci_list[j].subsystem_device) - continue; - CX18_INFO("Autodetected %s card\n", cx->card->name); - goto done; - } - } - } -done: - - if (cx->card == NULL) { - cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); - CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", - cx->pci_dev->vendor, cx->pci_dev->device); - CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n", - cx->pci_dev->subsystem_vendor, - cx->pci_dev->subsystem_device); - CX18_ERR("Defaulting to %s card\n", cx->card->name); - CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); - CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); - CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n"); - } - cx->v4l2_cap = cx->card->v4l2_capabilities; - cx->card_name = cx->card->name; - cx->card_i2c = cx->card->i2c; -} - -static int __devinit cx18_create_in_workq(struct cx18 *cx) -{ - snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", - cx->v4l2_dev.name); - cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0); - if (cx->in_work_queue == NULL) { - CX18_ERR("Unable to create incoming mailbox handler thread\n"); - return -ENOMEM; - } - return 0; -} - -static void __devinit cx18_init_in_work_orders(struct cx18 *cx) -{ - int i; - for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { - cx->in_work_order[i].cx = cx; - cx->in_work_order[i].str = cx->epu_debug_str; - INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler); - } -} - -/* Precondition: the cx18 structure has been memset to 0. Only - the dev and instance fields have been filled in. - No assumptions on the card type may be made here (see cx18_init_struct2 - for that). - */ -static int __devinit cx18_init_struct1(struct cx18 *cx) -{ - int ret; - - cx->base_addr = pci_resource_start(cx->pci_dev, 0); - - mutex_init(&cx->serialize_lock); - mutex_init(&cx->gpio_lock); - mutex_init(&cx->epu2apu_mb_lock); - mutex_init(&cx->epu2cpu_mb_lock); - - ret = cx18_create_in_workq(cx); - if (ret) - return ret; - - cx18_init_in_work_orders(cx); - - /* start counting open_id at 1 */ - cx->open_id = 1; - - /* Initial settings */ - cx->cxhdl.port = CX2341X_PORT_MEMORY; - cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; - cx->cxhdl.ops = &cx18_cxhdl_ops; - cx->cxhdl.func = cx18_api_func; - cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; - ret = cx2341x_handler_init(&cx->cxhdl, 50); - if (ret) - return ret; - cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl; - - cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val; - cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val; - cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val | - (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) | - (cx->cxhdl.video_median_filter_type->cur.val << 2); - - init_waitqueue_head(&cx->cap_w); - init_waitqueue_head(&cx->mb_apu_waitq); - init_waitqueue_head(&cx->mb_cpu_waitq); - init_waitqueue_head(&cx->dma_waitq); - - /* VBI */ - cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; - cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; - - /* IVTV style VBI insertion into MPEG streams */ - INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list); - INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list); - INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list); - list_add(&cx->vbi.sliced_mpeg_buf.list, - &cx->vbi.sliced_mpeg_mdl.buf_list); - return 0; -} - -/* Second initialization part. Here the card type has been - autodetected. */ -static void __devinit cx18_init_struct2(struct cx18 *cx) -{ - int i; - - for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++) - if (cx->card->video_inputs[i].video_type == 0) - break; - cx->nof_inputs = i; - for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++) - if (cx->card->audio_inputs[i].audio_type == 0) - break; - cx->nof_audio_inputs = i; - - /* Find tuner input */ - for (i = 0; i < cx->nof_inputs; i++) { - if (cx->card->video_inputs[i].video_type == - CX18_CARD_INPUT_VID_TUNER) - break; - } - if (i == cx->nof_inputs) - i = 0; - cx->active_input = i; - cx->audio_input = cx->card->video_inputs[i].audio_index; -} - -static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - u16 cmd; - unsigned char pci_latency; - - CX18_DEBUG_INFO("Enabling pci device\n"); - - if (pci_enable_device(pci_dev)) { - CX18_ERR("Can't enable device %d!\n", cx->instance); - return -EIO; - } - if (pci_set_dma_mask(pci_dev, 0xffffffff)) { - CX18_ERR("No suitable DMA available, card %d\n", cx->instance); - return -EIO; - } - if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) { - CX18_ERR("Cannot request encoder memory region, card %d\n", - cx->instance); - return -EIO; - } - - /* Enable bus mastering and memory mapped IO for the CX23418 */ - pci_read_config_word(pci_dev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - pci_write_config_word(pci_dev, PCI_COMMAND, cmd); - - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); - - if (pci_latency < 64 && cx18_pci_latency) { - CX18_INFO("Unreasonably low latency timer, " - "setting to 64 (was %d)\n", pci_latency); - pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); - } - - CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, " - "irq: %d, latency: %d, memory: 0x%lx\n", - cx->pci_dev->device, cx->card_rev, pci_dev->bus->number, - PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), - cx->pci_dev->irq, pci_latency, (unsigned long)cx->base_addr); - - return 0; -} - -static void cx18_init_subdevs(struct cx18 *cx) -{ - u32 hw = cx->card->hw_all; - u32 device; - int i; - - for (i = 0, device = 1; i < 32; i++, device <<= 1) { - - if (!(device & hw)) - continue; - - switch (device) { - case CX18_HW_DVB: - case CX18_HW_TVEEPROM: - /* These subordinate devices do not use probing */ - cx->hw_flags |= device; - break; - case CX18_HW_418_AV: - /* The A/V decoder gets probed earlier to set PLLs */ - /* Just note that the card uses it (i.e. has analog) */ - cx->hw_flags |= device; - break; - case CX18_HW_GPIO_RESET_CTRL: - /* - * The Reset Controller gets probed and added to - * hw_flags earlier for i2c adapter/bus initialization - */ - break; - case CX18_HW_GPIO_MUX: - if (cx18_gpio_register(cx, device) == 0) - cx->hw_flags |= device; - break; - default: - if (cx18_i2c_register(cx, i) == 0) - cx->hw_flags |= device; - break; - } - } - - if (cx->hw_flags & CX18_HW_418_AV) - cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV); - - if (cx->card->hw_muxer != 0) - cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer); -} - -static int __devinit cx18_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - int retval = 0; - int i; - u32 devtype; - struct cx18 *cx; - - /* FIXME - module parameter arrays constrain max instances */ - i = atomic_inc_return(&cx18_instance) - 1; - if (i >= CX18_MAX_CARDS) { - printk(KERN_ERR "cx18: cannot manage card %d, driver has a " - "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1); - return -ENOMEM; - } - - cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); - if (cx == NULL) { - printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n", - i); - return -ENOMEM; - } - cx->pci_dev = pci_dev; - cx->instance = i; - - retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev); - if (retval) { - printk(KERN_ERR "cx18: v4l2_device_register of card %d failed" - "\n", cx->instance); - kfree(cx); - return retval; - } - snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d", - cx->instance); - CX18_INFO("Initializing card %d\n", cx->instance); - - cx18_process_options(cx); - if (cx->options.cardtype == -1) { - retval = -ENODEV; - goto err; - } - - retval = cx18_init_struct1(cx); - if (retval) - goto err; - - CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); - - /* PCI Device Setup */ - retval = cx18_setup_pci(cx, pci_dev, pci_id); - if (retval != 0) - goto free_workqueues; - - /* map io memory */ - CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", - cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); - cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, - CX18_MEM_SIZE); - if (!cx->enc_mem) { - CX18_ERR("ioremap failed. Can't get a window into CX23418 " - "memory and register space\n"); - CX18_ERR("Each capture card with a CX23418 needs 64 MB of " - "vmalloc address space for the window\n"); - CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); - CX18_ERR("Use the vmalloc= kernel command line option to set " - "VmallocTotal to a larger value\n"); - retval = -ENOMEM; - goto free_mem; - } - cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; - devtype = cx18_read_reg(cx, 0xC72028); - switch (devtype & 0xff000000) { - case 0xff000000: - CX18_INFO("cx23418 revision %08x (A)\n", devtype); - break; - case 0x01000000: - CX18_INFO("cx23418 revision %08x (B)\n", devtype); - break; - default: - CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); - break; - } - - cx18_init_power(cx, 1); - cx18_init_memory(cx); - - cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); - cx18_init_scb(cx); - - cx18_gpio_init(cx); - - /* Initialize integrated A/V decoder early to set PLLs, just in case */ - retval = cx18_av_probe(cx); - if (retval) { - CX18_ERR("Could not register A/V decoder subdevice\n"); - goto free_map; - } - - /* Initialize GPIO Reset Controller to do chip resets during i2c init */ - if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) { - if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0) - CX18_WARN("Could not register GPIO reset controller" - "subdevice; proceeding anyway.\n"); - else - cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL; - } - - /* active i2c */ - CX18_DEBUG_INFO("activating i2c...\n"); - retval = init_cx18_i2c(cx); - if (retval) { - CX18_ERR("Could not initialize i2c\n"); - goto free_map; - } - - if (cx->card->hw_all & CX18_HW_TVEEPROM) { - /* Based on the model number the cardtype may be changed. - The PCI IDs are not always reliable. */ - cx18_process_eeprom(cx); - } - if (cx->card->comment) - CX18_INFO("%s", cx->card->comment); - if (cx->card->v4l2_capabilities == 0) { - retval = -ENODEV; - goto free_i2c; - } - cx18_init_memory(cx); - cx18_init_scb(cx); - - /* Register IRQ */ - retval = request_irq(cx->pci_dev->irq, cx18_irq_handler, - IRQF_SHARED | IRQF_DISABLED, - cx->v4l2_dev.name, (void *)cx); - if (retval) { - CX18_ERR("Failed to register irq %d\n", retval); - goto free_i2c; - } - - if (cx->std == 0) - cx->std = V4L2_STD_NTSC_M; - - if (cx->options.tuner == -1) { - for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { - if ((cx->std & cx->card->tuners[i].std) == 0) - continue; - cx->options.tuner = cx->card->tuners[i].tuner; - break; - } - } - /* if no tuner was found, then pick the first tuner in the card list */ - if (cx->options.tuner == -1 && cx->card->tuners[0].std) { - cx->std = cx->card->tuners[0].std; - if (cx->std & V4L2_STD_PAL) - cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; - else if (cx->std & V4L2_STD_NTSC) - cx->std = V4L2_STD_NTSC_M; - else if (cx->std & V4L2_STD_SECAM) - cx->std = V4L2_STD_SECAM_L; - cx->options.tuner = cx->card->tuners[0].tuner; - } - if (cx->options.radio == -1) - cx->options.radio = (cx->card->radio_input.audio_type != 0); - - /* The card is now fully identified, continue with card-specific - initialization. */ - cx18_init_struct2(cx); - - cx18_init_subdevs(cx); - - if (cx->std & V4L2_STD_525_60) - cx->is_60hz = 1; - else - cx->is_50hz = 1; - - cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz); - - if (cx->options.radio > 0) - cx->v4l2_cap |= V4L2_CAP_RADIO; - - if (cx->options.tuner > -1) { - struct tuner_setup setup; - - setup.addr = ADDR_UNSET; - setup.type = cx->options.tuner; - setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ - setup.tuner_callback = (setup.type == TUNER_XC2028) ? - cx18_reset_tuner_gpio : NULL; - cx18_call_all(cx, tuner, s_type_addr, &setup); - if (setup.type == TUNER_XC2028) { - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - }; - struct v4l2_priv_tun_config cfg = { - .tuner = cx->options.tuner, - .priv = &ctrl, - }; - cx18_call_all(cx, tuner, s_config, &cfg); - } - } - - /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) - are not. */ - cx->tuner_std = cx->std; - - retval = cx18_streams_setup(cx); - if (retval) { - CX18_ERR("Error %d setting up streams\n", retval); - goto free_irq; - } - retval = cx18_streams_register(cx); - if (retval) { - CX18_ERR("Error %d registering devices\n", retval); - goto free_streams; - } - - CX18_INFO("Initialized card: %s\n", cx->card_name); - - /* Load cx18 submodules (cx18-alsa) */ - request_modules(cx); - return 0; - -free_streams: - cx18_streams_cleanup(cx, 1); -free_irq: - free_irq(cx->pci_dev->irq, (void *)cx); -free_i2c: - exit_cx18_i2c(cx); -free_map: - cx18_iounmap(cx); -free_mem: - release_mem_region(cx->base_addr, CX18_MEM_SIZE); -free_workqueues: - destroy_workqueue(cx->in_work_queue); -err: - if (retval == 0) - retval = -ENODEV; - CX18_ERR("Error %d on initialization\n", retval); - - v4l2_device_unregister(&cx->v4l2_dev); - kfree(cx); - return retval; -} - -int cx18_init_on_first_open(struct cx18 *cx) -{ - int video_input; - int fw_retry_count = 3; - struct v4l2_frequency vf; - struct cx18_open_id fh; - - fh.cx = cx; - - if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) - return -ENXIO; - - if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) - return 0; - - while (--fw_retry_count > 0) { - /* load firmware */ - if (cx18_firmware_init(cx) == 0) - break; - if (fw_retry_count > 1) - CX18_WARN("Retry loading firmware\n"); - } - - if (fw_retry_count == 0) { - set_bit(CX18_F_I_FAILED, &cx->i_flags); - return -ENXIO; - } - set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); - - /* - * Init the firmware twice to work around a silicon bug - * with the digital TS. - * - * The second firmware load requires us to normalize the APU state, - * or the audio for the first analog capture will be badly incorrect. - * - * I can't seem to call APU_RESETAI and have it succeed without the - * APU capturing audio, so we start and stop it here to do the reset - */ - - /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ - cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); - cx18_vapi(cx, CX18_APU_RESETAI, 0); - cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); - - fw_retry_count = 3; - while (--fw_retry_count > 0) { - /* load firmware */ - if (cx18_firmware_init(cx) == 0) - break; - if (fw_retry_count > 1) - CX18_WARN("Retry loading firmware\n"); - } - - if (fw_retry_count == 0) { - set_bit(CX18_F_I_FAILED, &cx->i_flags); - return -ENXIO; - } - - /* - * The second firmware load requires us to normalize the APU state, - * or the audio for the first analog capture will be badly incorrect. - * - * I can't seem to call APU_RESETAI and have it succeed without the - * APU capturing audio, so we start and stop it here to do the reset - */ - - /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ - cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); - cx18_vapi(cx, CX18_APU_RESETAI, 0); - cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); - - /* Init the A/V decoder, if it hasn't been already */ - v4l2_subdev_call(cx->sd_av, core, load_fw); - - vf.tuner = 0; - vf.type = V4L2_TUNER_ANALOG_TV; - vf.frequency = 6400; /* the tuner 'baseline' frequency */ - - /* Set initial frequency. For PAL/SECAM broadcasts no - 'default' channel exists AFAIK. */ - if (cx->std == V4L2_STD_NTSC_M_JP) - vf.frequency = 1460; /* ch. 1 91250*16/1000 */ - else if (cx->std & V4L2_STD_NTSC_M) - vf.frequency = 1076; /* ch. 4 67250*16/1000 */ - - video_input = cx->active_input; - cx->active_input++; /* Force update of input */ - cx18_s_input(NULL, &fh, video_input); - - /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code - in one place. */ - cx->std++; /* Force full standard initialization */ - cx18_s_std(NULL, &fh, &cx->tuner_std); - cx18_s_frequency(NULL, &fh, &vf); - return 0; -} - -static void cx18_cancel_in_work_orders(struct cx18 *cx) -{ - int i; - for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) - cancel_work_sync(&cx->in_work_order[i].work); -} - -static void cx18_cancel_out_work_orders(struct cx18 *cx) -{ - int i; - for (i = 0; i < CX18_MAX_STREAMS; i++) - if (&cx->streams[i].video_dev != NULL) - cancel_work_sync(&cx->streams[i].out_work_order); -} - -static void cx18_remove(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct cx18 *cx = to_cx18(v4l2_dev); - int i; - - CX18_DEBUG_INFO("Removing Card\n"); - - flush_request_modules(cx); - - /* Stop all captures */ - CX18_DEBUG_INFO("Stopping all streams\n"); - if (atomic_read(&cx->tot_capturing) > 0) - cx18_stop_all_captures(cx); - - /* Stop interrupts that cause incoming work to be queued */ - cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); - - /* Incoming work can cause outgoing work, so clean up incoming first */ - cx18_cancel_in_work_orders(cx); - cx18_cancel_out_work_orders(cx); - - /* Stop ack interrupts that may have been needed for work to finish */ - cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); - - cx18_halt_firmware(cx); - - destroy_workqueue(cx->in_work_queue); - - cx18_streams_cleanup(cx, 1); - - exit_cx18_i2c(cx); - - free_irq(cx->pci_dev->irq, (void *)cx); - - cx18_iounmap(cx); - - release_mem_region(cx->base_addr, CX18_MEM_SIZE); - - pci_disable_device(cx->pci_dev); - - if (cx->vbi.sliced_mpeg_data[0] != NULL) - for (i = 0; i < CX18_VBI_FRAMES; i++) - kfree(cx->vbi.sliced_mpeg_data[i]); - - v4l2_ctrl_handler_free(&cx->av_state.hdl); - - CX18_INFO("Removed %s\n", cx->card_name); - - v4l2_device_unregister(v4l2_dev); - kfree(cx); -} - - -/* define a pci_driver for card detection */ -static struct pci_driver cx18_pci_driver = { - .name = "cx18", - .id_table = cx18_pci_tbl, - .probe = cx18_probe, - .remove = cx18_remove, -}; - -static int __init module_start(void) -{ - printk(KERN_INFO "cx18: Start initialization, version %s\n", - CX18_VERSION); - - /* Validate parameters */ - if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) { - printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n", - CX18_MAX_CARDS - 1); - return -1; - } - - if (cx18_debug < 0 || cx18_debug > 511) { - cx18_debug = 0; - printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n"); - } - - if (pci_register_driver(&cx18_pci_driver)) { - printk(KERN_ERR "cx18: Error detecting PCI card\n"); - return -ENODEV; - } - printk(KERN_INFO "cx18: End initialization\n"); - return 0; -} - -static void __exit module_cleanup(void) -{ - pci_unregister_driver(&cx18_pci_driver); -} - -module_init(module_start); -module_exit(module_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-driver.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-driver.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-driver.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-driver.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,711 +0,0 @@ -/* - * cx18 driver internal defines and structures - * - * Derived from ivtv-driver.h - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#ifndef CX18_DRIVER_H -#define CX18_DRIVER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "cx18-mailbox.h" -#include "cx18-av-core.h" -#include "cx23418.h" - -/* DVB */ -#include "demux.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "dvbdev.h" - -#ifndef CONFIG_PCI -# error "This driver requires kernel PCI support." -#endif - -#define CX18_MEM_OFFSET 0x00000000 -#define CX18_MEM_SIZE 0x04000000 -#define CX18_REG_OFFSET 0x02000000 - -/* Maximum cx18 driver instances. */ -#define CX18_MAX_CARDS 32 - -/* Supported cards */ -#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */ -#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */ -#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */ -#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ -#define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */ -#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/ -#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */ -#define CX18_CARD_LEADTEK_DVR3100H 7 /* Leadtek WinFast DVR3100 H */ -#define CX18_CARD_GOTVIEW_PCI_DVD3 8 /* GoTView PCI DVD3 Hybrid */ -#define CX18_CARD_HVR_1600_S5H1411 9 /* Hauppauge HVR 1600 s5h1411/tda18271*/ -#define CX18_CARD_LAST 9 - -#define CX18_ENC_STREAM_TYPE_MPG 0 -#define CX18_ENC_STREAM_TYPE_TS 1 -#define CX18_ENC_STREAM_TYPE_YUV 2 -#define CX18_ENC_STREAM_TYPE_VBI 3 -#define CX18_ENC_STREAM_TYPE_PCM 4 -#define CX18_ENC_STREAM_TYPE_IDX 5 -#define CX18_ENC_STREAM_TYPE_RAD 6 -#define CX18_MAX_STREAMS 7 - -/* system vendor and device IDs */ -#define PCI_VENDOR_ID_CX 0x14f1 -#define PCI_DEVICE_ID_CX23418 0x5b7a - -/* subsystem vendor ID */ -#define CX18_PCI_ID_HAUPPAUGE 0x0070 -#define CX18_PCI_ID_COMPRO 0x185b -#define CX18_PCI_ID_YUAN 0x12ab -#define CX18_PCI_ID_CONEXANT 0x14f1 -#define CX18_PCI_ID_TOSHIBA 0x1179 -#define CX18_PCI_ID_LEADTEK 0x107D -#define CX18_PCI_ID_GOTVIEW 0x5854 - -/* ======================================================================== */ -/* ========================== START USER SETTABLE DMA VARIABLES =========== */ -/* ======================================================================== */ - -/* DMA Buffers, Default size in MB allocated */ -#define CX18_DEFAULT_ENC_TS_BUFFERS 1 -#define CX18_DEFAULT_ENC_MPG_BUFFERS 2 -#define CX18_DEFAULT_ENC_IDX_BUFFERS 1 -#define CX18_DEFAULT_ENC_YUV_BUFFERS 2 -#define CX18_DEFAULT_ENC_VBI_BUFFERS 1 -#define CX18_DEFAULT_ENC_PCM_BUFFERS 1 - -/* Maximum firmware DMA buffers per stream */ -#define CX18_MAX_FW_MDLS_PER_STREAM 63 - -/* YUV buffer sizes in bytes to ensure integer # of frames per buffer */ -#define CX18_UNIT_ENC_YUV_BUFSIZE (720 * 32 * 3 / 2) /* bytes */ -#define CX18_625_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 576/32) -#define CX18_525_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 480/32) - -/* IDX buffer size should be a multiple of the index entry size from the chip */ -struct cx18_enc_idx_entry { - __le32 length; - __le32 offset_low; - __le32 offset_high; - __le32 flags; - __le32 pts_low; - __le32 pts_high; -} __attribute__ ((packed)); -#define CX18_UNIT_ENC_IDX_BUFSIZE \ - (sizeof(struct cx18_enc_idx_entry) * V4L2_ENC_IDX_ENTRIES) - -/* DMA buffer, default size in kB allocated */ -#define CX18_DEFAULT_ENC_TS_BUFSIZE 32 -#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32 -#define CX18_DEFAULT_ENC_IDX_BUFSIZE (CX18_UNIT_ENC_IDX_BUFSIZE * 1 / 1024 + 1) -#define CX18_DEFAULT_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 3 / 1024 + 1) -#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4 - -/* i2c stuff */ -#define I2C_CLIENTS_MAX 16 - -/* debugging */ - -/* Flag to turn on high volume debugging */ -#define CX18_DBGFLG_WARN (1 << 0) -#define CX18_DBGFLG_INFO (1 << 1) -#define CX18_DBGFLG_API (1 << 2) -#define CX18_DBGFLG_DMA (1 << 3) -#define CX18_DBGFLG_IOCTL (1 << 4) -#define CX18_DBGFLG_FILE (1 << 5) -#define CX18_DBGFLG_I2C (1 << 6) -#define CX18_DBGFLG_IRQ (1 << 7) -/* Flag to turn on high volume debugging */ -#define CX18_DBGFLG_HIGHVOL (1 << 8) - -/* NOTE: extra space before comma in 'fmt , ## args' is required for - gcc-2.95, otherwise it won't compile. */ -#define CX18_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & cx18_debug) \ - v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \ - } while (0) -#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args) -#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args) -#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args) -#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args) -#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args) -#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args) -#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args) - -#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \ - do { \ - if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \ - v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \ - } while (0) -#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args) -#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args) -#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args) -#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args) -#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args) -#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args) -#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args) - -/* Standard kernel messages */ -#define CX18_ERR(fmt, args...) v4l2_err(&cx->v4l2_dev, fmt , ## args) -#define CX18_WARN(fmt, args...) v4l2_warn(&cx->v4l2_dev, fmt , ## args) -#define CX18_INFO(fmt, args...) v4l2_info(&cx->v4l2_dev, fmt , ## args) - -/* Messages for internal subdevs to use */ -#define CX18_DEBUG_DEV(x, dev, type, fmt, args...) \ - do { \ - if ((x) & cx18_debug) \ - v4l2_info(dev, " " type ": " fmt , ## args); \ - } while (0) -#define CX18_DEBUG_WARN_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args) -#define CX18_DEBUG_INFO_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args) -#define CX18_DEBUG_API_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args) -#define CX18_DEBUG_DMA_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args) -#define CX18_DEBUG_IOCTL_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args) -#define CX18_DEBUG_FILE_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args) -#define CX18_DEBUG_I2C_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args) -#define CX18_DEBUG_IRQ_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args) - -#define CX18_DEBUG_HIGH_VOL_DEV(x, dev, type, fmt, args...) \ - do { \ - if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \ - v4l2_info(dev, " " type ": " fmt , ## args); \ - } while (0) -#define CX18_DEBUG_HI_WARN_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args) -#define CX18_DEBUG_HI_INFO_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args) -#define CX18_DEBUG_HI_API_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args) -#define CX18_DEBUG_HI_DMA_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args) -#define CX18_DEBUG_HI_IOCTL_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args) -#define CX18_DEBUG_HI_FILE_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args) -#define CX18_DEBUG_HI_I2C_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args) -#define CX18_DEBUG_HI_IRQ_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args) - -#define CX18_ERR_DEV(dev, fmt, args...) v4l2_err(dev, fmt , ## args) -#define CX18_WARN_DEV(dev, fmt, args...) v4l2_warn(dev, fmt , ## args) -#define CX18_INFO_DEV(dev, fmt, args...) v4l2_info(dev, fmt , ## args) - -extern int cx18_debug; - -struct cx18_options { - int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */ - int cardtype; /* force card type on load */ - int tuner; /* set tuner on load */ - int radio; /* enable/disable radio */ -}; - -/* per-mdl bit flags */ -#define CX18_F_M_NEED_SWAP 0 /* mdl buffer data must be endianess swapped */ - -/* per-stream, s_flags */ -#define CX18_F_S_CLAIMED 3 /* this stream is claimed */ -#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ -#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ -#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */ -#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ -#define CX18_F_S_STOPPING 9 /* telling the fw to stop capturing */ - -/* per-cx18, i_flags */ -#define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */ -#define CX18_F_I_EOS 4 /* End of encoder stream */ -#define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */ -#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ -#define CX18_F_I_INITED 21 /* set after first open */ -#define CX18_F_I_FAILED 22 /* set if first open failed */ - -/* These are the VBI types as they appear in the embedded VBI private packets. */ -#define CX18_SLICED_TYPE_TELETEXT_B (1) -#define CX18_SLICED_TYPE_CAPTION_525 (4) -#define CX18_SLICED_TYPE_WSS_625 (5) -#define CX18_SLICED_TYPE_VPS (7) - -/** - * list_entry_is_past_end - check if a previous loop cursor is off list end - * @pos: the type * previously used as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Check if the entry's list_head is the head of the list, thus it's not a - * real entry but was the loop cursor that walked past the end - */ -#define list_entry_is_past_end(pos, head, member) \ - (&pos->member == (head)) - -struct cx18_buffer { - struct list_head list; - dma_addr_t dma_handle; - char *buf; - - u32 bytesused; - u32 readpos; -}; - -struct cx18_mdl { - struct list_head list; - u32 id; /* index into cx->scb->cpu_mdl[] of 1st cx18_mdl_ent */ - - unsigned int skipped; - unsigned long m_flags; - - struct list_head buf_list; - struct cx18_buffer *curr_buf; /* current buffer in list for reading */ - - u32 bytesused; - u32 readpos; -}; - -struct cx18_queue { - struct list_head list; - atomic_t depth; - u32 bytesused; - spinlock_t lock; -}; - -struct cx18_stream; /* forward reference */ - -struct cx18_dvb { - struct cx18_stream *stream; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - struct dmxdev dmxdev; - struct dvb_adapter dvb_adapter; - struct dvb_demux demux; - struct dvb_frontend *fe; - struct dvb_net dvbnet; - int enabled; - int feeding; - struct mutex feedlock; -}; - -struct cx18; /* forward reference */ -struct cx18_scb; /* forward reference */ - - -#define CX18_MAX_MDL_ACKS 2 -#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7) -/* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */ - -#define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1 -#define CX18_F_EWO_MB_STALE_WHILE_PROC 0x2 -#define CX18_F_EWO_MB_STALE \ - (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC) - -struct cx18_in_work_order { - struct work_struct work; - atomic_t pending; - struct cx18 *cx; - unsigned long flags; - int rpu; - struct cx18_mailbox mb; - struct cx18_mdl_ack mdl_ack[CX18_MAX_MDL_ACKS]; - char *str; -}; - -#define CX18_INVALID_TASK_HANDLE 0xffffffff - -struct cx18_stream { - /* These first five fields are always set, even if the stream - is not actually created. */ - struct video_device *video_dev; /* NULL when stream not created */ - struct cx18_dvb *dvb; /* DVB / Digital Transport */ - struct cx18 *cx; /* for ease of use */ - const char *name; /* name of the stream */ - int type; /* stream type */ - u32 handle; /* task handle */ - unsigned int mdl_base_idx; - - u32 id; - unsigned long s_flags; /* status flags, see above */ - int dma; /* can be PCI_DMA_TODEVICE, - PCI_DMA_FROMDEVICE or - PCI_DMA_NONE */ - wait_queue_head_t waitq; - - /* Buffers */ - struct list_head buf_pool; /* buffers not attached to an MDL */ - u32 buffers; /* total buffers owned by this stream */ - u32 buf_size; /* size in bytes of a single buffer */ - - /* MDL sizes - all stream MDLs are the same size */ - u32 bufs_per_mdl; - u32 mdl_size; /* total bytes in all buffers in a mdl */ - - /* MDL Queues */ - struct cx18_queue q_free; /* free - in rotation, not committed */ - struct cx18_queue q_busy; /* busy - in use by firmware */ - struct cx18_queue q_full; /* full - data for user apps */ - struct cx18_queue q_idle; /* idle - not in rotation */ - - struct work_struct out_work_order; -}; - -struct cx18_open_id { - struct v4l2_fh fh; - u32 open_id; - int type; - struct cx18 *cx; -}; - -static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) -{ - return container_of(fh, struct cx18_open_id, fh); -} - -static inline struct cx18_open_id *file2id(struct file *file) -{ - return fh2id(file->private_data); -} - -/* forward declaration of struct defined in cx18-cards.h */ -struct cx18_card; - -/* - * A note about "sliced" VBI data as implemented in this driver: - * - * Currently we collect the sliced VBI in the form of Ancillary Data - * packets, inserted by the AV core decoder/digitizer/slicer in the - * horizontal blanking region of the VBI lines, in "raw" mode as far as - * the Encoder is concerned. We don't ever tell the Encoder itself - * to provide sliced VBI. (AV Core: sliced mode - Encoder: raw mode) - * - * We then process the ancillary data ourselves to send the sliced data - * to the user application directly or build up MPEG-2 private stream 1 - * packets to splice into (only!) MPEG-2 PS streams for the user app. - * - * (That's how ivtv essentially does it.) - * - * The Encoder should be able to extract certain sliced VBI data for - * us and provide it in a separate stream or splice it into any type of - * MPEG PS or TS stream, but this isn't implemented yet. - */ - -/* - * Number of "raw" VBI samples per horizontal line we tell the Encoder to - * grab from the decoder/digitizer/slicer output for raw or sliced VBI. - * It depends on the pixel clock and the horiz rate: - * - * (1/Fh)*(2*Fp) = Samples/line - * = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples - * - * Sliced VBI data is sent as ancillary data during horizontal blanking - * Raw VBI is sent as active video samples during vertcal blanking - * - * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line - * length of 720 pixels @ 4:2:2 sampling. Thus... - * - * For systems that use a 15.734 kHz horizontal rate, such as - * NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have: - * - * (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line = - * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples - * - * For systems that use a 15.625 kHz horizontal rate, such as - * PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have: - * - * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line = - * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples - */ -static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */ -static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */ -static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */ - -#define CX18_VBI_FRAMES 32 - -struct vbi_info { - /* Current state of v4l2 VBI settings for this device */ - struct v4l2_format in; - struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */ - u32 count; /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */ - u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */ - - u32 frame; /* Count of VBI buffers/frames received from Encoder */ - - /* - * Vars for creation and insertion of MPEG Private Stream 1 packets - * of sliced VBI data into an MPEG PS - */ - - /* Boolean: create and insert Private Stream 1 packets into the PS */ - int insert_mpeg; - - /* - * Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. - * Used in cx18-vbi.c only for collecting sliced data, and as a source - * during conversion of sliced VBI data into MPEG Priv Stream 1 packets. - * We don't need to save state here, but the array may have been a bit - * too big (2304 bytes) to alloc from the stack. - */ - struct v4l2_sliced_vbi_data sliced_data[36]; - - /* - * A ring buffer of driver-generated MPEG-2 PS - * Program Pack/Private Stream 1 packets for sliced VBI data insertion - * into the MPEG PS stream. - * - * In each sliced_mpeg_data[] buffer is: - * 16 byte MPEG-2 PS Program Pack Header - * 16 byte MPEG-2 Private Stream 1 PES Header - * 4 byte magic number: "itv0" or "ITV0" - * 4 byte first field line mask, if "itv0" - * 4 byte second field line mask, if "itv0" - * 36 lines, if "ITV0"; or <36 lines, if "itv0"; of sliced VBI data - * - * Each line in the payload is - * 1 byte line header derived from the SDID (WSS, CC, VPS, etc.) - * 42 bytes of line data - * - * That's a maximum 1552 bytes of payload in the Private Stream 1 packet - * which is the payload size a PVR-350 (CX23415) MPEG decoder will - * accept for VBI data. So, including the headers, it's a maximum 1584 - * bytes total. - */ -#define CX18_SLICED_MPEG_DATA_MAXSZ 1584 - /* copy_vbi_buf() needs 8 temp bytes on the end for the worst case */ -#define CX18_SLICED_MPEG_DATA_BUFSZ (CX18_SLICED_MPEG_DATA_MAXSZ+8) - u8 *sliced_mpeg_data[CX18_VBI_FRAMES]; - u32 sliced_mpeg_size[CX18_VBI_FRAMES]; - - /* Count of Program Pack/Program Stream 1 packets inserted into PS */ - u32 inserted_frame; - - /* - * A dummy driver stream transfer mdl & buffer with a copy of the next - * sliced_mpeg_data[] buffer for output to userland apps. - * Only used in cx18-fileops.c, but its state needs to persist at times. - */ - struct cx18_mdl sliced_mpeg_mdl; - struct cx18_buffer sliced_mpeg_buf; -}; - -/* Per cx23418, per I2C bus private algo callback data */ -struct cx18_i2c_algo_callback_data { - struct cx18 *cx; - int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */ -}; - -#define CX18_MAX_MMIO_WR_RETRIES 10 - -/* Struct to hold info about cx18 cards */ -struct cx18 { - int instance; - struct pci_dev *pci_dev; - struct v4l2_device v4l2_dev; - struct v4l2_subdev *sd_av; /* A/V decoder/digitizer sub-device */ - struct v4l2_subdev *sd_extmux; /* External multiplexer sub-dev */ - - const struct cx18_card *card; /* card information */ - const char *card_name; /* full name of the card */ - const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ - u8 is_50hz; - u8 is_60hz; - u8 nof_inputs; /* number of video inputs */ - u8 nof_audio_inputs; /* number of audio inputs */ - u32 v4l2_cap; /* V4L2 capabilities of card */ - u32 hw_flags; /* Hardware description of the board */ - unsigned int free_mdl_idx; - struct cx18_scb __iomem *scb; /* pointer to SCB */ - struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ - struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ - - struct cx18_av_state av_state; - - /* codec settings */ - struct cx2341x_handler cxhdl; - u32 filter_mode; - u32 temporal_strength; - u32 spatial_strength; - - /* dualwatch */ - unsigned long dualwatch_jiffies; - u32 dualwatch_stereo_mode; - - struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ - struct cx18_options options; /* User options */ - int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */ - int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ - struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ - struct snd_cx18_card *alsa; /* ALSA interface for PCM capture stream */ - void (*pcm_announce_callback)(struct snd_cx18_card *card, u8 *pcm_data, - size_t num_bytes); - - unsigned long i_flags; /* global cx18 flags */ - atomic_t ana_capturing; /* count number of active analog capture streams */ - atomic_t tot_capturing; /* total count number of active capture streams */ - int search_pack_header; - - int open_id; /* incremented each time an open occurs, used as - unique ID. Starts at 1, so 0 can be used as - uninitialized value in the stream->id. */ - - u32 base_addr; - - u8 card_rev; - void __iomem *enc_mem, *reg_mem; - - struct vbi_info vbi; - - u64 mpg_data_received; - u64 vbi_data_inserted; - - wait_queue_head_t mb_apu_waitq; - wait_queue_head_t mb_cpu_waitq; - wait_queue_head_t cap_w; - /* when the current DMA is finished this queue is woken up */ - wait_queue_head_t dma_waitq; - - u32 sw1_irq_mask; - u32 sw2_irq_mask; - u32 hw2_irq_mask; - - struct workqueue_struct *in_work_queue; - char in_workq_name[11]; /* "cx18-NN-in" */ - struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; - char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ - - /* i2c */ - struct i2c_adapter i2c_adap[2]; - struct i2c_algo_bit_data i2c_algo[2]; - struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; - - struct IR_i2c_init_data ir_i2c_init_data; - - /* gpio */ - u32 gpio_dir; - u32 gpio_val; - struct mutex gpio_lock; - struct v4l2_subdev sd_gpiomux; - struct v4l2_subdev sd_resetctrl; - - /* v4l2 and User settings */ - - /* codec settings */ - u32 audio_input; - u32 active_input; - v4l2_std_id std; - v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ - - /* Used for cx18-alsa module loading */ - struct work_struct request_module_wk; -}; - -static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct cx18, v4l2_dev); -} - -/* cx18 extensions to be loaded */ -extern int (*cx18_ext_init)(struct cx18 *); - -/* Globals */ -extern int cx18_first_minor; - -/*==============Prototypes==================*/ - -/* Return non-zero if a signal is pending */ -int cx18_msleep_timeout(unsigned int msecs, int intr); - -/* Read Hauppauge eeprom */ -struct tveeprom; /* forward reference */ -void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv); - -/* First-open initialization: load firmware, etc. */ -int cx18_init_on_first_open(struct cx18 *cx); - -/* Test if the current VBI mode is raw (1) or sliced (0) */ -static inline int cx18_raw_vbi(const struct cx18 *cx) -{ - return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE; -} - -/* Call the specified callback for all subdevs with a grp_id bit matching the - * mask in hw (if 0, then match them all). Ignore any errors. */ -#define cx18_call_hw(cx, hw, o, f, args...) \ - do { \ - struct v4l2_subdev *__sd; \ - __v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd, \ - !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ - } while (0) - -#define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args) - -/* Call the specified callback for all subdevs with a grp_id bit matching the - * mask in hw (if 0, then match them all). If the callback returns an error - * other than 0 or -ENOIOCTLCMD, then return with that error code. */ -#define cx18_call_hw_err(cx, hw, o, f, args...) \ -({ \ - struct v4l2_subdev *__sd; \ - __v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev, \ - __sd, !(hw) || (__sd->grp_id & (hw)), o, f, \ - ##args); \ -}) - -#define cx18_call_all_err(cx, o, f, args...) \ - cx18_call_hw_err(cx, 0, o, f , ##args) - -#endif /* CX18_DRIVER_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-dvb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,605 +0,0 @@ -/* - * cx18 functions for DVB support - * - * Copyright (c) 2008 Steven Toth - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx18-version.h" -#include "cx18-dvb.h" -#include "cx18-io.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-cards.h" -#include "cx18-gpio.h" -#include "s5h1409.h" -#include "mxl5005s.h" -#include "s5h1411.h" -#include "tda18271.h" -#include "zl10353.h" - -#include -#include "mt352.h" -#include "mt352_priv.h" -#include "tuner-xc2028.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 -#define CX18_CLOCK_ENABLE2 0xc71024 -#define CX18_DMUX_CLK_MASK 0x0080 - -/* - * CX18_CARD_HVR_1600_ESMT - * CX18_CARD_HVR_1600_SAMSUNG - */ - -static struct mxl5005s_config hauppauge_hvr1600_tuner = { - .i2c_address = 0xC6 >> 1, - .if_freq = IF_FREQ_5380000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_C_H, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .qam_gain = 0x02, - .AgcMasterByte = 0x00, -}; - -static struct s5h1409_config hauppauge_hvr1600_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, - .hvr1600_opt = S5H1409_HVR1600_OPTIMIZE -}; - -/* - * CX18_CARD_HVR_1600_S5H1411 - */ -static struct s5h1411_config hcw_s5h1411_config = { - .output_mode = S5H1411_SERIAL_OUTPUT, - .gpio = S5H1411_GPIO_OFF, - .vsb_if = S5H1411_IF_44000, - .qam_if = S5H1411_IF_4000, - .inversion = S5H1411_INVERSION_ON, - .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct tda18271_std_map hauppauge_tda18271_std_map = { - .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, - .if_lvl = 6, .rfagc_top = 0x37 }, - .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, - .if_lvl = 6, .rfagc_top = 0x37 }, -}; - -static struct tda18271_config hauppauge_tda18271_config = { - .std_map = &hauppauge_tda18271_std_map, - .gate = TDA18271_GATE_DIGITAL, - .output_opt = TDA18271_OUTPUT_LT_OFF, -}; - -/* - * CX18_CARD_LEADTEK_DVR3100H - */ -/* Information/confirmation of proper config values provided by Terry Wu */ -static struct zl10353_config leadtek_dvr3100h_demod = { - .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ - .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ - .parallel_ts = 1, /* Not a serial TS */ - .no_tuner = 1, /* XC3028 is not behind the gate */ - .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ -}; - -/* - * CX18_CARD_YUAN_MPC718 - */ -/* - * Due to - * - * 1. an absence of information on how to prgram the MT352 - * 2. the Linux mt352 module pushing MT352 initialzation off onto us here - * - * We have to use an init sequence that *you* must extract from the Windows - * driver (yuanrap.sys) and which we load as a firmware. - * - * If someone can provide me with a Zarlink MT352 (Intel CE6352?) Design Manual - * with chip programming details, then I can remove this annoyance. - */ -static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream, - const struct firmware **fw) -{ - struct cx18 *cx = stream->cx; - const char *fn = "dvb-cx18-mpc718-mt352.fw"; - int ret; - - ret = request_firmware(fw, fn, &cx->pci_dev->dev); - if (ret) - CX18_ERR("Unable to open firmware file %s\n", fn); - else { - size_t sz = (*fw)->size; - if (sz < 2 || sz > 64 || (sz % 2) != 0) { - CX18_ERR("Firmware %s has a bad size: %lu bytes\n", - fn, (unsigned long) sz); - ret = -EILSEQ; - release_firmware(*fw); - *fw = NULL; - } - } - - if (ret) { - CX18_ERR("The MPC718 board variant with the MT352 DVB-T" - "demodualtor will not work without it\n"); - CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware " - "mpc718' if you need the firmware\n"); - } - return ret; -} - -static int yuan_mpc718_mt352_init(struct dvb_frontend *fe) -{ - struct cx18_dvb *dvb = container_of(fe->dvb, - struct cx18_dvb, dvb_adapter); - struct cx18_stream *stream = dvb->stream; - const struct firmware *fw = NULL; - int ret; - int i; - u8 buf[3]; - - ret = yuan_mpc718_mt352_reqfw(stream, &fw); - if (ret) - return ret; - - /* Loop through all the register-value pairs in the firmware file */ - for (i = 0; i < fw->size; i += 2) { - buf[0] = fw->data[i]; - /* Intercept a few registers we want to set ourselves */ - switch (buf[0]) { - case TRL_NOMINAL_RATE_0: - /* Set our custom OFDM bandwidth in the case below */ - break; - case TRL_NOMINAL_RATE_1: - /* 6 MHz: 64/7 * 6/8 / 20.48 * 2^16 = 0x55b6.db6 */ - /* 7 MHz: 64/7 * 7/8 / 20.48 * 2^16 = 0x6400 */ - /* 8 MHz: 64/7 * 8/8 / 20.48 * 2^16 = 0x7249.249 */ - buf[1] = 0x72; - buf[2] = 0x49; - mt352_write(fe, buf, 3); - break; - case INPUT_FREQ_0: - /* Set our custom IF in the case below */ - break; - case INPUT_FREQ_1: - /* 4.56 MHz IF: (20.48 - 4.56)/20.48 * 2^14 = 0x31c0 */ - buf[1] = 0x31; - buf[2] = 0xc0; - mt352_write(fe, buf, 3); - break; - default: - /* Pass through the register-value pair from the fw */ - buf[1] = fw->data[i+1]; - mt352_write(fe, buf, 2); - break; - } - } - - buf[0] = (u8) TUNER_GO; - buf[1] = 0x01; /* Go */ - mt352_write(fe, buf, 2); - release_firmware(fw); - return 0; -} - -static struct mt352_config yuan_mpc718_mt352_demod = { - .demod_address = 0x1e >> 1, - .adc_clock = 20480, /* 20.480 MHz */ - .if2 = 4560, /* 4.560 MHz */ - .no_tuner = 1, /* XC3028 is not behind the gate */ - .demod_init = yuan_mpc718_mt352_init, -}; - -static struct zl10353_config yuan_mpc718_zl10353_demod = { - .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ - .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ - .parallel_ts = 1, /* Not a serial TS */ - .no_tuner = 1, /* XC3028 is not behind the gate */ - .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ -}; - -static struct zl10353_config gotview_dvd3_zl10353_demod = { - .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ - .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ - .parallel_ts = 1, /* Not a serial TS */ - .no_tuner = 1, /* XC3028 is not behind the gate */ - .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ -}; - -static int dvb_register(struct cx18_stream *stream); - -/* Kernel DVB framework calls this when the feed needs to start. - * The CX18 framework should enable the transport DMA handling - * and queue processing. - */ -static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct cx18_stream *stream = (struct cx18_stream *) demux->priv; - struct cx18 *cx; - int ret; - u32 v; - - if (!stream) - return -EINVAL; - - cx = stream->cx; - CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n", - feed->pid, feed->index); - - mutex_lock(&cx->serialize_lock); - ret = cx18_init_on_first_open(cx); - mutex_unlock(&cx->serialize_lock); - if (ret) { - CX18_ERR("Failed to initialize firmware starting DVB feed\n"); - return ret; - } - ret = -EINVAL; - - switch (cx->card->type) { - case CX18_CARD_HVR_1600_ESMT: - case CX18_CARD_HVR_1600_SAMSUNG: - case CX18_CARD_HVR_1600_S5H1411: - v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL); - v |= 0x00400000; /* Serial Mode */ - v |= 0x00002000; /* Data Length - Byte */ - v |= 0x00010000; /* Error - Polarity */ - v |= 0x00020000; /* Error - Passthru */ - v |= 0x000c0000; /* Error - Ignore */ - cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL); - break; - - case CX18_CARD_LEADTEK_DVR3100H: - case CX18_CARD_YUAN_MPC718: - case CX18_CARD_GOTVIEW_PCI_DVD3: - default: - /* Assumption - Parallel transport - Signalling - * undefined or default. - */ - break; - } - - if (!demux->dmx.frontend) - return -EINVAL; - - mutex_lock(&stream->dvb->feedlock); - if (stream->dvb->feeding++ == 0) { - CX18_DEBUG_INFO("Starting Transport DMA\n"); - mutex_lock(&cx->serialize_lock); - set_bit(CX18_F_S_STREAMING, &stream->s_flags); - ret = cx18_start_v4l2_encode_stream(stream); - if (ret < 0) { - CX18_DEBUG_INFO("Failed to start Transport DMA\n"); - stream->dvb->feeding--; - if (stream->dvb->feeding == 0) - clear_bit(CX18_F_S_STREAMING, &stream->s_flags); - } - mutex_unlock(&cx->serialize_lock); - } else - ret = 0; - mutex_unlock(&stream->dvb->feedlock); - - return ret; -} - -/* Kernel DVB framework calls this when the feed needs to stop. */ -static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct cx18_stream *stream = (struct cx18_stream *)demux->priv; - struct cx18 *cx; - int ret = -EINVAL; - - if (stream) { - cx = stream->cx; - CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n", - feed->pid, feed->index); - - mutex_lock(&stream->dvb->feedlock); - if (--stream->dvb->feeding == 0) { - CX18_DEBUG_INFO("Stopping Transport DMA\n"); - mutex_lock(&cx->serialize_lock); - ret = cx18_stop_v4l2_encode_stream(stream, 0); - mutex_unlock(&cx->serialize_lock); - } else - ret = 0; - mutex_unlock(&stream->dvb->feedlock); - } - - return ret; -} - -int cx18_dvb_register(struct cx18_stream *stream) -{ - struct cx18 *cx = stream->cx; - struct cx18_dvb *dvb = stream->dvb; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - int ret; - - if (!dvb) - return -EINVAL; - - dvb->enabled = 0; - dvb->stream = stream; - - ret = dvb_register_adapter(&dvb->dvb_adapter, - CX18_DRIVER_NAME, - THIS_MODULE, &cx->pci_dev->dev, adapter_nr); - if (ret < 0) - goto err_out; - - dvb_adapter = &dvb->dvb_adapter; - - dvbdemux = &dvb->demux; - - dvbdemux->priv = (void *)stream; - - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = cx18_dvb_start_feed; - dvbdemux->stop_feed = cx18_dvb_stop_feed; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); - ret = dvb_dmx_init(dvbdemux); - if (ret < 0) - goto err_dvb_unregister_adapter; - - dmx = &dvbdemux->dmx; - - dvb->hw_frontend.source = DMX_FRONTEND_0; - dvb->mem_frontend.source = DMX_MEMORY_FE; - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = dmx; - - ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter); - if (ret < 0) - goto err_dvb_dmx_release; - - ret = dmx->add_frontend(dmx, &dvb->hw_frontend); - if (ret < 0) - goto err_dvb_dmxdev_release; - - ret = dmx->add_frontend(dmx, &dvb->mem_frontend); - if (ret < 0) - goto err_remove_hw_frontend; - - ret = dmx->connect_frontend(dmx, &dvb->hw_frontend); - if (ret < 0) - goto err_remove_mem_frontend; - - ret = dvb_register(stream); - if (ret < 0) - goto err_disconnect_frontend; - - dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); - - CX18_INFO("DVB Frontend registered\n"); - CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n", - stream->dvb->dvb_adapter.num, stream->name, - stream->buffers, stream->buf_size/1024, - (stream->buf_size * 100 / 1024) % 100); - - mutex_init(&dvb->feedlock); - dvb->enabled = 1; - return ret; - -err_disconnect_frontend: - dmx->disconnect_frontend(dmx); -err_remove_mem_frontend: - dmx->remove_frontend(dmx, &dvb->mem_frontend); -err_remove_hw_frontend: - dmx->remove_frontend(dmx, &dvb->hw_frontend); -err_dvb_dmxdev_release: - dvb_dmxdev_release(&dvb->dmxdev); -err_dvb_dmx_release: - dvb_dmx_release(dvbdemux); -err_dvb_unregister_adapter: - dvb_unregister_adapter(dvb_adapter); -err_out: - return ret; -} - -void cx18_dvb_unregister(struct cx18_stream *stream) -{ - struct cx18 *cx = stream->cx; - struct cx18_dvb *dvb = stream->dvb; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - - CX18_INFO("unregister DVB\n"); - - if (dvb == NULL || !dvb->enabled) - return; - - dvb_adapter = &dvb->dvb_adapter; - dvbdemux = &dvb->demux; - dmx = &dvbdemux->dmx; - - dmx->close(dmx); - dvb_net_release(&dvb->dvbnet); - dmx->remove_frontend(dmx, &dvb->mem_frontend); - dmx->remove_frontend(dmx, &dvb->hw_frontend); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(dvbdemux); - dvb_unregister_frontend(dvb->fe); - dvb_frontend_detach(dvb->fe); - dvb_unregister_adapter(dvb_adapter); -} - -/* All the DVB attach calls go here, this function get's modified - * for each new card. cx18_dvb_start_feed() will also need changes. - */ -static int dvb_register(struct cx18_stream *stream) -{ - struct cx18_dvb *dvb = stream->dvb; - struct cx18 *cx = stream->cx; - int ret = 0; - - switch (cx->card->type) { - case CX18_CARD_HVR_1600_ESMT: - case CX18_CARD_HVR_1600_SAMSUNG: - dvb->fe = dvb_attach(s5h1409_attach, - &hauppauge_hvr1600_config, - &cx->i2c_adap[0]); - if (dvb->fe != NULL) { - dvb_attach(mxl5005s_attach, dvb->fe, - &cx->i2c_adap[0], - &hauppauge_hvr1600_tuner); - ret = 0; - } - break; - case CX18_CARD_HVR_1600_S5H1411: - dvb->fe = dvb_attach(s5h1411_attach, - &hcw_s5h1411_config, - &cx->i2c_adap[0]); - if (dvb->fe != NULL) - dvb_attach(tda18271_attach, dvb->fe, - 0x60, &cx->i2c_adap[0], - &hauppauge_tda18271_config); - break; - case CX18_CARD_LEADTEK_DVR3100H: - dvb->fe = dvb_attach(zl10353_attach, - &leadtek_dvr3100h_demod, - &cx->i2c_adap[1]); - if (dvb->fe != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &cx->i2c_adap[1], - .i2c_addr = 0xc2 >> 1, - .ctrl = NULL, - }; - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - .type = XC2028_AUTO, - }; - - fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctrl); - } - break; - case CX18_CARD_YUAN_MPC718: - /* - * TODO - * Apparently, these cards also could instead have a - * DiBcom demod supported by one of the db7000 drivers - */ - dvb->fe = dvb_attach(mt352_attach, - &yuan_mpc718_mt352_demod, - &cx->i2c_adap[1]); - if (dvb->fe == NULL) - dvb->fe = dvb_attach(zl10353_attach, - &yuan_mpc718_zl10353_demod, - &cx->i2c_adap[1]); - if (dvb->fe != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &cx->i2c_adap[1], - .i2c_addr = 0xc2 >> 1, - .ctrl = NULL, - }; - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - .type = XC2028_AUTO, - }; - - fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctrl); - } - break; - case CX18_CARD_GOTVIEW_PCI_DVD3: - dvb->fe = dvb_attach(zl10353_attach, - &gotview_dvd3_zl10353_demod, - &cx->i2c_adap[1]); - if (dvb->fe != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &cx->i2c_adap[1], - .i2c_addr = 0xc2 >> 1, - .ctrl = NULL, - }; - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - .type = XC2028_AUTO, - }; - - fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctrl); - } - break; - default: - /* No Digital Tv Support */ - break; - } - - if (dvb->fe == NULL) { - CX18_ERR("frontend initialization failed\n"); - return -1; - } - - dvb->fe->callback = cx18_reset_tuner_gpio; - - ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe); - if (ret < 0) { - if (dvb->fe->ops.release) - dvb->fe->ops.release(dvb->fe); - return ret; - } - - /* - * The firmware seems to enable the TS DMUX clock - * under various circumstances. However, since we know we - * might use it, let's just turn it on ourselves here. - */ - cx18_write_reg_expect(cx, - (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK, - CX18_CLOCK_ENABLE2, - CX18_DMUX_CLK_MASK, - (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK); - - return ret; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-dvb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-dvb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-dvb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-dvb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -/* - * cx18 functions for DVB support - * - * Copyright (c) 2008 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx18-driver.h" - -int cx18_dvb_register(struct cx18_stream *stream); -void cx18_dvb_unregister(struct cx18_stream *stream); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-fileops.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-fileops.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-fileops.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-fileops.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,826 +0,0 @@ -/* - * cx18 file operation functions - * - * Derived from ivtv-fileops.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-fileops.h" -#include "cx18-i2c.h" -#include "cx18-queue.h" -#include "cx18-vbi.h" -#include "cx18-audio.h" -#include "cx18-mailbox.h" -#include "cx18-scb.h" -#include "cx18-streams.h" -#include "cx18-controls.h" -#include "cx18-ioctl.h" -#include "cx18-cards.h" - -/* This function tries to claim the stream for a specific file descriptor. - If no one else is using this stream then the stream is claimed and - associated VBI and IDX streams are also automatically claimed. - Possible error returns: -EBUSY if someone else has claimed - the stream or 0 on success. */ -int cx18_claim_stream(struct cx18_open_id *id, int type) -{ - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[type]; - struct cx18_stream *s_assoc; - - /* Nothing should ever try to directly claim the IDX stream */ - if (type == CX18_ENC_STREAM_TYPE_IDX) { - CX18_WARN("MPEG Index stream cannot be claimed " - "directly, but something tried.\n"); - return -EINVAL; - } - - if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) { - /* someone already claimed this stream */ - if (s->id == id->open_id) { - /* yes, this file descriptor did. So that's OK. */ - return 0; - } - if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) { - /* VBI is handled already internally, now also assign - the file descriptor to this stream for external - reading of the stream. */ - s->id = id->open_id; - CX18_DEBUG_INFO("Start Read VBI\n"); - return 0; - } - /* someone else is using this stream already */ - CX18_DEBUG_INFO("Stream %d is busy\n", type); - return -EBUSY; - } - s->id = id->open_id; - - /* - * CX18_ENC_STREAM_TYPE_MPG needs to claim: - * CX18_ENC_STREAM_TYPE_VBI, if VBI insertion is on for sliced VBI, or - * CX18_ENC_STREAM_TYPE_IDX, if VBI insertion is off for sliced VBI - * (We don't yet fix up MPEG Index entries for our inserted packets). - * - * For all other streams we're done. - */ - if (type != CX18_ENC_STREAM_TYPE_MPG) - return 0; - - s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) - s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - else if (!cx18_stream_enabled(s_assoc)) - return 0; - - set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); - - /* mark that it is used internally */ - set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags); - return 0; -} -EXPORT_SYMBOL(cx18_claim_stream); - -/* This function releases a previously claimed stream. It will take into - account associated VBI streams. */ -void cx18_release_stream(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - struct cx18_stream *s_assoc; - - s->id = -1; - if (s->type == CX18_ENC_STREAM_TYPE_IDX) { - /* - * The IDX stream is only used internally, and can - * only be indirectly unclaimed by unclaiming the MPG stream. - */ - return; - } - - if (s->type == CX18_ENC_STREAM_TYPE_VBI && - test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { - /* this stream is still in use internally */ - return; - } - if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) { - CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name); - return; - } - - cx18_flush_queues(s); - - /* - * CX18_ENC_STREAM_TYPE_MPG needs to release the - * CX18_ENC_STREAM_TYPE_VBI and/or CX18_ENC_STREAM_TYPE_IDX streams. - * - * For all other streams we're done. - */ - if (s->type != CX18_ENC_STREAM_TYPE_MPG) - return; - - /* Unclaim the associated MPEG Index stream */ - s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { - clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); - cx18_flush_queues(s_assoc); - } - - /* Unclaim the associated VBI stream */ - s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { - if (s_assoc->id == -1) { - /* - * The VBI stream is not still claimed by a file - * descriptor, so completely unclaim it. - */ - clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); - cx18_flush_queues(s_assoc); - } - } -} -EXPORT_SYMBOL(cx18_release_stream); - -static void cx18_dualwatch(struct cx18 *cx) -{ - struct v4l2_tuner vt; - u32 new_stereo_mode; - const u32 dual = 0x0200; - - new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); - memset(&vt, 0, sizeof(vt)); - cx18_call_all(cx, tuner, g_tuner, &vt); - if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && - (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) - new_stereo_mode = dual; - - if (new_stereo_mode == cx->dualwatch_stereo_mode) - return; - - CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", - cx->dualwatch_stereo_mode, new_stereo_mode); - if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode)) - CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); -} - - -static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block, - int *err) -{ - struct cx18 *cx = s->cx; - struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - struct cx18_mdl *mdl; - DEFINE_WAIT(wait); - - *err = 0; - while (1) { - if (s->type == CX18_ENC_STREAM_TYPE_MPG) { - /* Process pending program updates and VBI data */ - if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { - cx->dualwatch_jiffies = jiffies; - cx18_dualwatch(cx); - } - if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && - !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { - while ((mdl = cx18_dequeue(s_vbi, - &s_vbi->q_full))) { - /* byteswap and process VBI data */ - cx18_process_vbi_data(cx, mdl, - s_vbi->type); - cx18_stream_put_mdl_fw(s_vbi, mdl); - } - } - mdl = &cx->vbi.sliced_mpeg_mdl; - if (mdl->readpos != mdl->bytesused) - return mdl; - } - - /* do we have new data? */ - mdl = cx18_dequeue(s, &s->q_full); - if (mdl) { - if (!test_and_clear_bit(CX18_F_M_NEED_SWAP, - &mdl->m_flags)) - return mdl; - if (s->type == CX18_ENC_STREAM_TYPE_MPG) - /* byteswap MPG data */ - cx18_mdl_swap(mdl); - else { - /* byteswap and process VBI data */ - cx18_process_vbi_data(cx, mdl, s->type); - } - return mdl; - } - - /* return if end of stream */ - if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) { - CX18_DEBUG_INFO("EOS %s\n", s->name); - return NULL; - } - - /* return if file was opened with O_NONBLOCK */ - if (non_block) { - *err = -EAGAIN; - return NULL; - } - - /* wait for more data to arrive */ - prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); - /* New buffers might have become available before we were added - to the waitqueue */ - if (!atomic_read(&s->q_full.depth)) - schedule(); - finish_wait(&s->waitq, &wait); - if (signal_pending(current)) { - /* return if a signal was received */ - CX18_DEBUG_INFO("User stopped %s\n", s->name); - *err = -EINTR; - return NULL; - } - } -} - -static void cx18_setup_sliced_vbi_mdl(struct cx18 *cx) -{ - struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl; - struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf; - int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; - - buf->buf = cx->vbi.sliced_mpeg_data[idx]; - buf->bytesused = cx->vbi.sliced_mpeg_size[idx]; - buf->readpos = 0; - - mdl->curr_buf = NULL; - mdl->bytesused = cx->vbi.sliced_mpeg_size[idx]; - mdl->readpos = 0; -} - -static size_t cx18_copy_buf_to_user(struct cx18_stream *s, - struct cx18_buffer *buf, char __user *ubuf, size_t ucount, bool *stop) -{ - struct cx18 *cx = s->cx; - size_t len = buf->bytesused - buf->readpos; - - *stop = false; - if (len > ucount) - len = ucount; - if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && - !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) { - /* - * Try to find a good splice point in the PS, just before - * an MPEG-2 Program Pack start code, and provide only - * up to that point to the user, so it's easy to insert VBI data - * the next time around. - * - * This will not work for an MPEG-2 TS and has only been - * verified by analysis to work for an MPEG-2 PS. Helen Buus - * pointed out this works for the CX23416 MPEG-2 DVD compatible - * stream, and research indicates both the MPEG 2 SVCD and DVD - * stream types use an MPEG-2 PS container. - */ - /* - * An MPEG-2 Program Stream (PS) is a series of - * MPEG-2 Program Packs terminated by an - * MPEG Program End Code after the last Program Pack. - * A Program Pack may hold a PS System Header packet and any - * number of Program Elementary Stream (PES) Packets - */ - const char *start = buf->buf + buf->readpos; - const char *p = start + 1; - const u8 *q; - u8 ch = cx->search_pack_header ? 0xba : 0xe0; - int stuffing, i; - - while (start + len > p) { - /* Scan for a 0 to find a potential MPEG-2 start code */ - q = memchr(p, 0, start + len - p); - if (q == NULL) - break; - p = q + 1; - /* - * Keep looking if not a - * MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba - * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0 - */ - if ((char *)q + 15 >= buf->buf + buf->bytesused || - q[1] != 0 || q[2] != 1 || q[3] != ch) - continue; - - /* If expecting the primary video PES */ - if (!cx->search_pack_header) { - /* Continue if it couldn't be a PES packet */ - if ((q[6] & 0xc0) != 0x80) - continue; - /* Check if a PTS or PTS & DTS follow */ - if (((q[7] & 0xc0) == 0x80 && /* PTS only */ - (q[9] & 0xf0) == 0x20) || /* PTS only */ - ((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */ - (q[9] & 0xf0) == 0x30)) { /* DTS follows */ - /* Assume we found the video PES hdr */ - ch = 0xba; /* next want a Program Pack*/ - cx->search_pack_header = 1; - p = q + 9; /* Skip this video PES hdr */ - } - continue; - } - - /* We may have found a Program Pack start code */ - - /* Get the count of stuffing bytes & verify them */ - stuffing = q[13] & 7; - /* all stuffing bytes must be 0xff */ - for (i = 0; i < stuffing; i++) - if (q[14 + i] != 0xff) - break; - if (i == stuffing && /* right number of stuffing bytes*/ - (q[4] & 0xc4) == 0x44 && /* marker check */ - (q[12] & 3) == 3 && /* marker check */ - q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */ - q[15 + stuffing] == 0 && - q[16 + stuffing] == 1) { - /* We declare we actually found a Program Pack*/ - cx->search_pack_header = 0; /* expect vid PES */ - len = (char *)q - start; - cx18_setup_sliced_vbi_mdl(cx); - *stop = true; - break; - } - } - } - if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { - CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n", - len, s->name); - return -EFAULT; - } - buf->readpos += len; - if (s->type == CX18_ENC_STREAM_TYPE_MPG && - buf != &cx->vbi.sliced_mpeg_buf) - cx->mpg_data_received += len; - return len; -} - -static size_t cx18_copy_mdl_to_user(struct cx18_stream *s, - struct cx18_mdl *mdl, char __user *ubuf, size_t ucount) -{ - size_t tot_written = 0; - int rc; - bool stop = false; - - if (mdl->curr_buf == NULL) - mdl->curr_buf = list_first_entry(&mdl->buf_list, - struct cx18_buffer, list); - - if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { - /* - * For some reason we've exhausted the buffers, but the MDL - * object still said some data was unread. - * Fix that and bail out. - */ - mdl->readpos = mdl->bytesused; - return 0; - } - - list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { - - if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) - continue; - - rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written, - ucount - tot_written, &stop); - if (rc < 0) - return rc; - mdl->readpos += rc; - tot_written += rc; - - if (stop || /* Forced stopping point for VBI insertion */ - tot_written >= ucount || /* Reader request statisfied */ - mdl->curr_buf->readpos < mdl->curr_buf->bytesused || - mdl->readpos >= mdl->bytesused) /* MDL buffers drained */ - break; - } - return tot_written; -} - -static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, - size_t tot_count, int non_block) -{ - struct cx18 *cx = s->cx; - size_t tot_written = 0; - int single_frame = 0; - - if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) { - /* shouldn't happen */ - CX18_DEBUG_WARN("Stream %s not initialized before read\n", - s->name); - return -EIO; - } - - /* Each VBI buffer is one frame, the v4l2 API says that for VBI the - frames should arrive one-by-one, so make sure we never output more - than one VBI frame at a time */ - if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx)) - single_frame = 1; - - for (;;) { - struct cx18_mdl *mdl; - int rc; - - mdl = cx18_get_mdl(s, non_block, &rc); - /* if there is no data available... */ - if (mdl == NULL) { - /* if we got data, then return that regardless */ - if (tot_written) - break; - /* EOS condition */ - if (rc == 0) { - clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); - clear_bit(CX18_F_S_APPL_IO, &s->s_flags); - cx18_release_stream(s); - } - /* set errno */ - return rc; - } - - rc = cx18_copy_mdl_to_user(s, mdl, ubuf + tot_written, - tot_count - tot_written); - - if (mdl != &cx->vbi.sliced_mpeg_mdl) { - if (mdl->readpos == mdl->bytesused) - cx18_stream_put_mdl_fw(s, mdl); - else - cx18_push(s, mdl, &s->q_full); - } else if (mdl->readpos == mdl->bytesused) { - int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; - - cx->vbi.sliced_mpeg_size[idx] = 0; - cx->vbi.inserted_frame++; - cx->vbi_data_inserted += mdl->bytesused; - } - if (rc < 0) - return rc; - tot_written += rc; - - if (tot_written == tot_count || single_frame) - break; - } - return tot_written; -} - -static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, - size_t count, loff_t *pos, int non_block) -{ - ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0; - struct cx18 *cx = s->cx; - - CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); - if (rc > 0) - pos += rc; - return rc; -} - -int cx18_start_capture(struct cx18_open_id *id) -{ - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - struct cx18_stream *s_vbi; - struct cx18_stream *s_idx; - - if (s->type == CX18_ENC_STREAM_TYPE_RAD) { - /* you cannot read from these stream types. */ - return -EPERM; - } - - /* Try to claim this stream. */ - if (cx18_claim_stream(id, s->type)) - return -EBUSY; - - /* If capture is already in progress, then we also have to - do nothing extra. */ - if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || - test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { - set_bit(CX18_F_S_APPL_IO, &s->s_flags); - return 0; - } - - /* Start associated VBI or IDX stream capture if required */ - s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - if (s->type == CX18_ENC_STREAM_TYPE_MPG) { - /* - * The VBI and IDX streams should have been claimed - * automatically, if for internal use, when the MPG stream was - * claimed. We only need to start these streams capturing. - */ - if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) && - !test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { - if (cx18_start_v4l2_encode_stream(s_idx)) { - CX18_DEBUG_WARN("IDX capture start failed\n"); - clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); - goto start_failed; - } - CX18_DEBUG_INFO("IDX capture started\n"); - } - if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && - !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { - if (cx18_start_v4l2_encode_stream(s_vbi)) { - CX18_DEBUG_WARN("VBI capture start failed\n"); - clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); - goto start_failed; - } - CX18_DEBUG_INFO("VBI insertion started\n"); - } - } - - /* Tell the card to start capturing */ - if (!cx18_start_v4l2_encode_stream(s)) { - /* We're done */ - set_bit(CX18_F_S_APPL_IO, &s->s_flags); - /* Resume a possibly paused encoder */ - if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) - cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle); - return 0; - } - -start_failed: - CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); - - /* - * The associated VBI and IDX streams for internal use are released - * automatically when the MPG stream is released. We only need to stop - * the associated stream. - */ - if (s->type == CX18_ENC_STREAM_TYPE_MPG) { - /* Stop the IDX stream which is always for internal use */ - if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { - cx18_stop_v4l2_encode_stream(s_idx, 0); - clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); - } - /* Stop the VBI stream, if only running for internal use */ - if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && - !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { - cx18_stop_v4l2_encode_stream(s_vbi, 0); - clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); - } - } - clear_bit(CX18_F_S_STREAMING, &s->s_flags); - cx18_release_stream(s); /* Also releases associated streams */ - return -EIO; -} - -ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t *pos) -{ - struct cx18_open_id *id = file2id(filp); - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - int rc; - - CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); - - mutex_lock(&cx->serialize_lock); - rc = cx18_start_capture(id); - mutex_unlock(&cx->serialize_lock); - if (rc) - return rc; - return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); -} - -unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) -{ - struct cx18_open_id *id = file2id(filp); - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); - - /* Start a capture if there is none */ - if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { - int rc; - - mutex_lock(&cx->serialize_lock); - rc = cx18_start_capture(id); - mutex_unlock(&cx->serialize_lock); - if (rc) { - CX18_DEBUG_INFO("Could not start capture for %s (%d)\n", - s->name, rc); - return POLLERR; - } - CX18_DEBUG_FILE("Encoder poll started capture\n"); - } - - /* add stream's waitq to the poll list */ - CX18_DEBUG_HI_FILE("Encoder poll\n"); - poll_wait(filp, &s->waitq, wait); - - if (atomic_read(&s->q_full.depth)) - return POLLIN | POLLRDNORM; - if (eof) - return POLLHUP; - return 0; -} - -void cx18_stop_capture(struct cx18_open_id *id, int gop_end) -{ - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - - CX18_DEBUG_IOCTL("close() of %s\n", s->name); - - /* 'Unclaim' this stream */ - - /* Stop capturing */ - if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { - CX18_DEBUG_INFO("close stopping capture\n"); - if (id->type == CX18_ENC_STREAM_TYPE_MPG) { - /* Stop internal use associated VBI and IDX streams */ - if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && - !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { - CX18_DEBUG_INFO("close stopping embedded VBI " - "capture\n"); - cx18_stop_v4l2_encode_stream(s_vbi, 0); - } - if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { - CX18_DEBUG_INFO("close stopping IDX capture\n"); - cx18_stop_v4l2_encode_stream(s_idx, 0); - } - } - if (id->type == CX18_ENC_STREAM_TYPE_VBI && - test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) - /* Also used internally, don't stop capturing */ - s->id = -1; - else - cx18_stop_v4l2_encode_stream(s, gop_end); - } - if (!gop_end) { - clear_bit(CX18_F_S_APPL_IO, &s->s_flags); - clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); - cx18_release_stream(s); - } -} - -int cx18_v4l2_close(struct file *filp) -{ - struct v4l2_fh *fh = filp->private_data; - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - CX18_DEBUG_IOCTL("close() of %s\n", s->name); - - v4l2_fh_del(fh); - v4l2_fh_exit(fh); - - /* Easy case first: this stream was never claimed by us */ - if (s->id != id->open_id) { - kfree(id); - return 0; - } - - /* 'Unclaim' this stream */ - - /* Stop radio */ - mutex_lock(&cx->serialize_lock); - if (id->type == CX18_ENC_STREAM_TYPE_RAD) { - /* Closing radio device, return to TV mode */ - cx18_mute(cx); - /* Mark that the radio is no longer in use */ - clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); - /* Switch tuner to TV */ - cx18_call_all(cx, core, s_std, cx->std); - /* Select correct audio input (i.e. TV tuner or Line in) */ - cx18_audio_set_io(cx); - if (atomic_read(&cx->ana_capturing) > 0) { - /* Undo video mute */ - cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, - (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) | - (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8))); - } - /* Done! Unmute and continue. */ - cx18_unmute(cx); - cx18_release_stream(s); - } else { - cx18_stop_capture(id, 0); - } - kfree(id); - mutex_unlock(&cx->serialize_lock); - return 0; -} - -static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) -{ - struct cx18 *cx = s->cx; - struct cx18_open_id *item; - - CX18_DEBUG_FILE("open %s\n", s->name); - - /* Allocate memory */ - item = kzalloc(sizeof(struct cx18_open_id), GFP_KERNEL); - if (NULL == item) { - CX18_DEBUG_WARN("nomem on v4l2 open\n"); - return -ENOMEM; - } - v4l2_fh_init(&item->fh, s->video_dev); - - item->cx = cx; - item->type = s->type; - - item->open_id = cx->open_id++; - filp->private_data = &item->fh; - - if (item->type == CX18_ENC_STREAM_TYPE_RAD) { - /* Try to claim this stream */ - if (cx18_claim_stream(item, item->type)) { - /* No, it's already in use */ - v4l2_fh_exit(&item->fh); - kfree(item); - return -EBUSY; - } - - if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { - if (atomic_read(&cx->ana_capturing) > 0) { - /* switching to radio while capture is - in progress is not polite */ - cx18_release_stream(s); - v4l2_fh_exit(&item->fh); - kfree(item); - return -EBUSY; - } - } - - /* Mark that the radio is being used. */ - set_bit(CX18_F_I_RADIO_USER, &cx->i_flags); - /* We have the radio */ - cx18_mute(cx); - /* Switch tuner to radio */ - cx18_call_all(cx, tuner, s_radio); - /* Select the correct audio input (i.e. radio tuner) */ - cx18_audio_set_io(cx); - /* Done! Unmute and continue. */ - cx18_unmute(cx); - } - v4l2_fh_add(&item->fh); - return 0; -} - -int cx18_v4l2_open(struct file *filp) -{ - int res; - struct video_device *video_dev = video_devdata(filp); - struct cx18_stream *s = video_get_drvdata(video_dev); - struct cx18 *cx = s->cx; - - mutex_lock(&cx->serialize_lock); - if (cx18_init_on_first_open(cx)) { - CX18_ERR("Failed to initialize on %s\n", - video_device_node_name(video_dev)); - mutex_unlock(&cx->serialize_lock); - return -ENXIO; - } - res = cx18_serialized_open(s, filp); - mutex_unlock(&cx->serialize_lock); - return res; -} - -void cx18_mute(struct cx18 *cx) -{ - u32 h; - if (atomic_read(&cx->ana_capturing)) { - h = cx18_find_handle(cx); - if (h != CX18_INVALID_TASK_HANDLE) - cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1); - else - CX18_ERR("Can't find valid task handle for mute\n"); - } - CX18_DEBUG_INFO("Mute\n"); -} - -void cx18_unmute(struct cx18 *cx) -{ - u32 h; - if (atomic_read(&cx->ana_capturing)) { - h = cx18_find_handle(cx); - if (h != CX18_INVALID_TASK_HANDLE) { - cx18_msleep_timeout(100, 0); - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12); - cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0); - } else - CX18_ERR("Can't find valid task handle for unmute\n"); - } - CX18_DEBUG_INFO("Unmute\n"); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-fileops.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-fileops.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-fileops.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-fileops.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - * cx18 file operation functions - * - * Derived from ivtv-fileops.h - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -/* Testing/Debugging */ -int cx18_v4l2_open(struct file *filp); -ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t *pos); -ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count, - loff_t *pos); -int cx18_v4l2_close(struct file *filp); -unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait); -int cx18_start_capture(struct cx18_open_id *id); -void cx18_stop_capture(struct cx18_open_id *id, int gop_end); -void cx18_mute(struct cx18 *cx); -void cx18_unmute(struct cx18 *cx); - -/* Shared with cx18-alsa module */ -int cx18_claim_stream(struct cx18_open_id *id, int type); -void cx18_release_stream(struct cx18_stream *s); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-firmware.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-firmware.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,448 +0,0 @@ -/* - * cx18 firmware functions - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-scb.h" -#include "cx18-irq.h" -#include "cx18-firmware.h" -#include "cx18-cards.h" -#include - -#define CX18_PROC_SOFT_RESET 0xc70010 -#define CX18_DDR_SOFT_RESET 0xc70014 -#define CX18_CLOCK_SELECT1 0xc71000 -#define CX18_CLOCK_SELECT2 0xc71004 -#define CX18_HALF_CLOCK_SELECT1 0xc71008 -#define CX18_HALF_CLOCK_SELECT2 0xc7100C -#define CX18_CLOCK_POLARITY1 0xc71010 -#define CX18_CLOCK_POLARITY2 0xc71014 -#define CX18_ADD_DELAY_ENABLE1 0xc71018 -#define CX18_ADD_DELAY_ENABLE2 0xc7101C -#define CX18_CLOCK_ENABLE1 0xc71020 -#define CX18_CLOCK_ENABLE2 0xc71024 - -#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 - -#define CX18_FAST_CLOCK_PLL_INT 0xc78000 -#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004 -#define CX18_FAST_CLOCK_PLL_POST 0xc78008 -#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C -#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010 - -#define CX18_SLOW_CLOCK_PLL_INT 0xc78014 -#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018 -#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C -#define CX18_MPEG_CLOCK_PLL_INT 0xc78040 -#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044 -#define CX18_MPEG_CLOCK_PLL_POST 0xc78048 -#define CX18_PLL_POWER_DOWN 0xc78088 -#define CX18_SW1_INT_STATUS 0xc73104 -#define CX18_SW1_INT_ENABLE_PCI 0xc7311C -#define CX18_SW2_INT_SET 0xc73140 -#define CX18_SW2_INT_STATUS 0xc73144 -#define CX18_ADEC_CONTROL 0xc78120 - -#define CX18_DDR_REQUEST_ENABLE 0xc80000 -#define CX18_DDR_CHIP_CONFIG 0xc80004 -#define CX18_DDR_REFRESH 0xc80008 -#define CX18_DDR_TIMING1 0xc8000C -#define CX18_DDR_TIMING2 0xc80010 -#define CX18_DDR_POWER_REG 0xc8001C - -#define CX18_DDR_TUNE_LANE 0xc80048 -#define CX18_DDR_INITIAL_EMRS 0xc80054 -#define CX18_DDR_MB_PER_ROW_7 0xc8009C -#define CX18_DDR_BASE_63_ADDR 0xc804FC - -#define CX18_WMB_CLIENT02 0xc90108 -#define CX18_WMB_CLIENT05 0xc90114 -#define CX18_WMB_CLIENT06 0xc90118 -#define CX18_WMB_CLIENT07 0xc9011C -#define CX18_WMB_CLIENT08 0xc90120 -#define CX18_WMB_CLIENT09 0xc90124 -#define CX18_WMB_CLIENT10 0xc90128 -#define CX18_WMB_CLIENT11 0xc9012C -#define CX18_WMB_CLIENT12 0xc90130 -#define CX18_WMB_CLIENT13 0xc90134 -#define CX18_WMB_CLIENT14 0xc90138 - -#define CX18_DSP0_INTERRUPT_MASK 0xd0004C - -#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ -#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ - -struct cx18_apu_rom_seghdr { - u32 sync1; - u32 sync2; - u32 addr; - u32 size; -}; - -static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) -{ - const struct firmware *fw = NULL; - int i, j; - unsigned size; - u32 __iomem *dst = (u32 __iomem *)mem; - const u32 *src; - - if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { - CX18_ERR("Unable to open firmware %s\n", fn); - CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); - return -ENOMEM; - } - - src = (const u32 *)fw->data; - - for (i = 0; i < fw->size; i += 4096) { - cx18_setup_page(cx, i); - for (j = i; j < fw->size && j < i + 4096; j += 4) { - /* no need for endianness conversion on the ppc */ - cx18_raw_writel(cx, *src, dst); - if (cx18_raw_readl(cx, dst) != *src) { - CX18_ERR("Mismatch at offset %x\n", i); - release_firmware(fw); - cx18_setup_page(cx, 0); - return -EIO; - } - dst++; - src++; - } - } - if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); - size = fw->size; - release_firmware(fw); - cx18_setup_page(cx, SCB_OFFSET); - return size; -} - -static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, - u32 *entry_addr) -{ - const struct firmware *fw = NULL; - int i, j; - unsigned size; - const u32 *src; - struct cx18_apu_rom_seghdr seghdr; - const u8 *vers; - u32 offset = 0; - u32 apu_version = 0; - int sz; - - if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { - CX18_ERR("unable to open firmware %s\n", fn); - CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); - cx18_setup_page(cx, 0); - return -ENOMEM; - } - - *entry_addr = 0; - src = (const u32 *)fw->data; - vers = fw->data + sizeof(seghdr); - sz = fw->size; - - apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; - while (offset + sizeof(seghdr) < fw->size) { - /* TODO: byteswapping */ - memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); - offset += sizeof(seghdr); - if (seghdr.sync1 != APU_ROM_SYNC1 || - seghdr.sync2 != APU_ROM_SYNC2) { - offset += seghdr.size; - continue; - } - CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, - seghdr.addr + seghdr.size - 1); - if (*entry_addr == 0) - *entry_addr = seghdr.addr; - if (offset + seghdr.size > sz) - break; - for (i = 0; i < seghdr.size; i += 4096) { - cx18_setup_page(cx, seghdr.addr + i); - for (j = i; j < seghdr.size && j < i + 4096; j += 4) { - /* no need for endianness conversion on the ppc */ - cx18_raw_writel(cx, src[(offset + j) / 4], - dst + seghdr.addr + j); - if (cx18_raw_readl(cx, dst + seghdr.addr + j) - != src[(offset + j) / 4]) { - CX18_ERR("Mismatch at offset %x\n", - offset + j); - release_firmware(fw); - cx18_setup_page(cx, 0); - return -EIO; - } - } - } - offset += seghdr.size; - } - if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", - fn, apu_version, fw->size); - size = fw->size; - release_firmware(fw); - cx18_setup_page(cx, 0); - return size; -} - -void cx18_halt_firmware(struct cx18 *cx) -{ - CX18_DEBUG_INFO("Preparing for firmware halt.\n"); - cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, - 0x0000000F, 0x000F000F); - cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL, - 0x00000002, 0x00020002); -} - -void cx18_init_power(struct cx18 *cx, int lowpwr) -{ - /* power-down Spare and AOM PLLs */ - /* power-up fast, slow and mpeg PLLs */ - cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN); - - /* ADEC out of sleep */ - cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL, - 0x00000000, 0x00020002); - - /* - * The PLL parameters are based on the external crystal frequency that - * would ideally be: - * - * NTSC Color subcarrier freq * 8 = - * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz - * - * The accidents of history and rationale that explain from where this - * combination of magic numbers originate can be found in: - * - * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in - * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80 - * - * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the - * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83 - * - * As Mike Bradley has rightly pointed out, it's not the exact crystal - * frequency that matters, only that all parts of the driver and - * firmware are using the same value (close to the ideal value). - * - * Since I have a strong suspicion that, if the firmware ever assumes a - * crystal value at all, it will assume 28.636360 MHz, the crystal - * freq used in calculations in this driver will be: - * - * xtal_freq = 28.636360 MHz - * - * an error of less than 0.13 ppm which is way, way better than any off - * the shelf crystal will have for accuracy anyway. - * - * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors. - * - * Many thanks to Jeff Campbell and Mike Bradley for their extensive - * investigation, experimentation, testing, and suggested solutions of - * of audio/video sync problems with SVideo and CVBS captures. - */ - - /* the fast clock is at 200/245 MHz */ - /* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/ - /* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/ - cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); - cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7, - CX18_FAST_CLOCK_PLL_FRAC); - - cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST); - cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE); - cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH); - - /* set slow clock to 125/120 MHz */ - /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */ - /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */ - cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT); - cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F, - CX18_SLOW_CLOCK_PLL_FRAC); - cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST); - - /* mpeg clock pll 54MHz */ - /* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */ - cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT); - cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC); - cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST); - - /* Defaults */ - /* APU = SC or SC/2 = 125/62.5 */ - /* EPU = SC = 125 */ - /* DDR = FC = 180 */ - /* ENC = SC = 125 */ - /* AI1 = SC = 125 */ - /* VIM2 = disabled */ - /* PCI = FC/2 = 90 */ - /* AI2 = disabled */ - /* DEMUX = disabled */ - /* AO = SC/2 = 62.5 */ - /* SER = 54MHz */ - /* VFC = disabled */ - /* USB = disabled */ - - if (lowpwr) { - cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1, - 0x00000020, 0xFFFFFFFF); - cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2, - 0x00000004, 0xFFFFFFFF); - } else { - /* This doesn't explicitly set every clock select */ - cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1, - 0x00000004, 0x00060006); - cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2, - 0x00000006, 0x00060006); - } - - cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1, - 0x00000002, 0xFFFFFFFF); - cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2, - 0x00000104, 0xFFFFFFFF); - cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1, - 0x00009026, 0xFFFFFFFF); - cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2, - 0x00003105, 0xFFFFFFFF); -} - -void cx18_init_memory(struct cx18 *cx) -{ - cx18_msleep_timeout(10, 0); - cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET, - 0x00000000, 0x00010001); - cx18_msleep_timeout(10, 0); - - cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG); - - cx18_msleep_timeout(10, 0); - - cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH); - cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1); - cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2); - - cx18_msleep_timeout(10, 0); - - /* Initialize DQS pad time */ - cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE); - cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS); - - cx18_msleep_timeout(10, 0); - - cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET, - 0x00000000, 0x00020002); - cx18_msleep_timeout(10, 0); - - /* use power-down mode when idle */ - cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG); - - cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN, - 0x00000001, 0x00010001); - - cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7); - cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR); - - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02); /* AO */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09); /* AI2 */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05); /* VIM1 */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06); /* AI1 */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07); /* 3D comb */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10); /* ME */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12); /* ENC */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13); /* PK */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11); /* RC */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14); /* AVO */ -} - -int cx18_firmware_init(struct cx18 *cx) -{ - u32 fw_entry_addr; - int sz, retries; - u32 api_args[MAX_MB_ARGUMENTS]; - - /* Allow chip to control CLKRUN */ - cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK); - - /* Stop the firmware */ - cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, - 0x0000000F, 0x000F000F); - - cx18_msleep_timeout(1, 0); - - /* If the CPU is still running */ - if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) { - CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__); - return -EIO; - } - - cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); - cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); - - sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx); - if (sz <= 0) - return sz; - - /* The SCB & IPC area *must* be correct before starting the firmwares */ - cx18_init_scb(cx); - - fw_entry_addr = 0; - sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx, - &fw_entry_addr); - if (sz <= 0) - return sz; - - /* Start the CPU. The CPU will take care of the APU for us. */ - cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET, - 0x00000000, 0x00080008); - - /* Wait up to 500 ms for the APU to come out of reset */ - for (retries = 0; - retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1; - retries++) - cx18_msleep_timeout(10, 0); - - cx18_msleep_timeout(200, 0); - - if (retries == 50 && - (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) { - CX18_ERR("Could not start the CPU\n"); - return -EIO; - } - - /* - * The CPU had once before set up to receive an interrupt for it's - * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an - * interrupt when it sends us an ack, but by the time we process it, - * that flag in the SW2 status register has been cleared by the CPU - * firmware. We'll prevent that not so useful condition from happening - * by clearing the CPU's interrupt enables for Ack IRQ's we want to - * process. - */ - cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); - - /* Try a benign command to see if the CPU is alive and well */ - sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0); - if (sz < 0) - return sz; - - /* initialize GPIO */ - cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-firmware.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-firmware.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-firmware.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-firmware.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -/* - * cx18 firmware functions - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -int cx18_firmware_init(struct cx18 *cx); -void cx18_halt_firmware(struct cx18 *cx); -void cx18_init_memory(struct cx18 *cx); -void cx18_init_power(struct cx18 *cx, int lowpwr); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-gpio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-gpio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-gpio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-gpio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,347 +0,0 @@ -/* - * cx18 gpio functions - * - * Derived from ivtv-gpio.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-cards.h" -#include "cx18-gpio.h" -#include "tuner-xc2028.h" - -/********************* GPIO stuffs *********************/ - -/* GPIO registers */ -#define CX18_REG_GPIO_IN 0xc72010 -#define CX18_REG_GPIO_OUT1 0xc78100 -#define CX18_REG_GPIO_DIR1 0xc78108 -#define CX18_REG_GPIO_OUT2 0xc78104 -#define CX18_REG_GPIO_DIR2 0xc7810c - -/* - * HVR-1600 GPIO pins, courtesy of Hauppauge: - * - * gpio0: zilog ir process reset pin - * gpio1: zilog programming pin (you should never use this) - * gpio12: cx24227 reset pin - * gpio13: cs5345 reset pin -*/ - -/* - * File scope utility functions - */ -static void gpio_write(struct cx18 *cx) -{ - u32 dir_lo = cx->gpio_dir & 0xffff; - u32 val_lo = cx->gpio_val & 0xffff; - u32 dir_hi = cx->gpio_dir >> 16; - u32 val_hi = cx->gpio_val >> 16; - - cx18_write_reg_expect(cx, dir_lo << 16, - CX18_REG_GPIO_DIR1, ~dir_lo, dir_lo); - cx18_write_reg_expect(cx, (dir_lo << 16) | val_lo, - CX18_REG_GPIO_OUT1, val_lo, dir_lo); - cx18_write_reg_expect(cx, dir_hi << 16, - CX18_REG_GPIO_DIR2, ~dir_hi, dir_hi); - cx18_write_reg_expect(cx, (dir_hi << 16) | val_hi, - CX18_REG_GPIO_OUT2, val_hi, dir_hi); -} - -static void gpio_update(struct cx18 *cx, u32 mask, u32 data) -{ - if (mask == 0) - return; - - mutex_lock(&cx->gpio_lock); - cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask); - gpio_write(cx); - mutex_unlock(&cx->gpio_lock); -} - -static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi, - unsigned int assert_msecs, - unsigned int recovery_msecs) -{ - u32 mask; - - mask = active_lo | active_hi; - if (mask == 0) - return; - - /* - * Assuming that active_hi and active_lo are a subsets of the bits in - * gpio_dir. Also assumes that active_lo and active_hi don't overlap - * in any bit position - */ - - /* Assert */ - gpio_update(cx, mask, ~active_lo); - schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs)); - - /* Deassert */ - gpio_update(cx, mask, ~active_hi); - schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs)); -} - -/* - * GPIO Multiplexer - logical device - */ -static int gpiomux_log_status(struct v4l2_subdev *sd) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - mutex_lock(&cx->gpio_lock); - CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n", - cx->gpio_dir, cx->gpio_val); - mutex_unlock(&cx->gpio_lock); - return 0; -} - -static int gpiomux_s_radio(struct v4l2_subdev *sd) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - /* - * FIXME - work out the cx->active/audio_input mess - this is - * intended to handle the switch to radio mode and set the - * audio routing, but we need to update the state in cx - */ - gpio_update(cx, cx->card->gpio_audio_input.mask, - cx->card->gpio_audio_input.radio); - return 0; -} - -static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - u32 data; - - switch (cx->card->audio_inputs[cx->audio_input].muxer_input) { - case 1: - data = cx->card->gpio_audio_input.linein; - break; - case 0: - data = cx->card->gpio_audio_input.tuner; - break; - default: - /* - * FIXME - work out the cx->active/audio_input mess - this is - * intended to handle the switch from radio mode and set the - * audio routing, but we need to update the state in cx - */ - data = cx->card->gpio_audio_input.tuner; - break; - } - gpio_update(cx, cx->card->gpio_audio_input.mask, data); - return 0; -} - -static int gpiomux_s_audio_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - u32 data; - - switch (input) { - case 0: - data = cx->card->gpio_audio_input.tuner; - break; - case 1: - data = cx->card->gpio_audio_input.linein; - break; - case 2: - data = cx->card->gpio_audio_input.radio; - break; - default: - return -EINVAL; - } - gpio_update(cx, cx->card->gpio_audio_input.mask, data); - return 0; -} - -static const struct v4l2_subdev_core_ops gpiomux_core_ops = { - .log_status = gpiomux_log_status, - .s_std = gpiomux_s_std, -}; - -static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = { - .s_radio = gpiomux_s_radio, -}; - -static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = { - .s_routing = gpiomux_s_audio_routing, -}; - -static const struct v4l2_subdev_ops gpiomux_ops = { - .core = &gpiomux_core_ops, - .tuner = &gpiomux_tuner_ops, - .audio = &gpiomux_audio_ops, -}; - -/* - * GPIO Reset Controller - logical device - */ -static int resetctrl_log_status(struct v4l2_subdev *sd) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - mutex_lock(&cx->gpio_lock); - CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n", - cx->gpio_dir, cx->gpio_val); - mutex_unlock(&cx->gpio_lock); - return 0; -} - -static int resetctrl_reset(struct v4l2_subdev *sd, u32 val) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - const struct cx18_gpio_i2c_slave_reset *p; - - p = &cx->card->gpio_i2c_slave_reset; - switch (val) { - case CX18_GPIO_RESET_I2C: - gpio_reset_seq(cx, p->active_lo_mask, p->active_hi_mask, - p->msecs_asserted, p->msecs_recovery); - break; - case CX18_GPIO_RESET_Z8F0811: - /* - * Assert timing for the Z8F0811 on HVR-1600 boards: - * 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to - * initiate - * 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock - * cycles (6,601,085 nanoseconds ~= 7 milliseconds) - * 3. DBG pin must be high before chip exits reset for normal - * operation. DBG is open drain and hopefully pulled high - * since we don't normally drive it (GPIO 1?) for the - * HVR-1600 - * 4. Z8F0811 won't exit reset until RESET is deasserted - * 5. Zilog comes out of reset, loads reset vector address and - * executes from there. Required recovery delay unknown. - */ - gpio_reset_seq(cx, p->ir_reset_mask, 0, - p->msecs_asserted, p->msecs_recovery); - break; - case CX18_GPIO_RESET_XC2028: - if (cx->card->tuners[0].tuner == TUNER_XC2028) - gpio_reset_seq(cx, (1 << cx->card->xceive_pin), 0, - 1, 1); - break; - } - return 0; -} - -static const struct v4l2_subdev_core_ops resetctrl_core_ops = { - .log_status = resetctrl_log_status, - .reset = resetctrl_reset, -}; - -static const struct v4l2_subdev_ops resetctrl_ops = { - .core = &resetctrl_core_ops, -}; - -/* - * External entry points - */ -void cx18_gpio_init(struct cx18 *cx) -{ - mutex_lock(&cx->gpio_lock); - cx->gpio_dir = cx->card->gpio_init.direction; - cx->gpio_val = cx->card->gpio_init.initial_value; - - if (cx->card->tuners[0].tuner == TUNER_XC2028) { - cx->gpio_dir |= 1 << cx->card->xceive_pin; - cx->gpio_val |= 1 << cx->card->xceive_pin; - } - - if (cx->gpio_dir == 0) { - mutex_unlock(&cx->gpio_lock); - return; - } - - CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n", - cx18_read_reg(cx, CX18_REG_GPIO_DIR1), - cx18_read_reg(cx, CX18_REG_GPIO_DIR2), - cx18_read_reg(cx, CX18_REG_GPIO_OUT1), - cx18_read_reg(cx, CX18_REG_GPIO_OUT2)); - - gpio_write(cx); - mutex_unlock(&cx->gpio_lock); -} - -int cx18_gpio_register(struct cx18 *cx, u32 hw) -{ - struct v4l2_subdev *sd; - const struct v4l2_subdev_ops *ops; - char *str; - - switch (hw) { - case CX18_HW_GPIO_MUX: - sd = &cx->sd_gpiomux; - ops = &gpiomux_ops; - str = "gpio-mux"; - break; - case CX18_HW_GPIO_RESET_CTRL: - sd = &cx->sd_resetctrl; - ops = &resetctrl_ops; - str = "gpio-reset-ctrl"; - break; - default: - return -EINVAL; - } - - v4l2_subdev_init(sd, ops); - v4l2_set_subdevdata(sd, cx); - snprintf(sd->name, sizeof(sd->name), "%s %s", cx->v4l2_dev.name, str); - sd->grp_id = hw; - return v4l2_device_register_subdev(&cx->v4l2_dev, sd); -} - -void cx18_reset_ir_gpio(void *data) -{ - struct cx18 *cx = to_cx18((struct v4l2_device *)data); - - if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0) - return; - - CX18_DEBUG_INFO("Resetting IR microcontroller\n"); - - v4l2_subdev_call(&cx->sd_resetctrl, - core, reset, CX18_GPIO_RESET_Z8F0811); -} -EXPORT_SYMBOL(cx18_reset_ir_gpio); -/* This symbol is exported for use by lirc_pvr150 for the IR-blaster */ - -/* Xceive tuner reset function */ -int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value) -{ - struct i2c_algo_bit_data *algo = dev; - struct cx18_i2c_algo_callback_data *cb_data = algo->data; - struct cx18 *cx = cb_data->cx; - - if (cmd != XC2028_TUNER_RESET || - cx->card->tuners[0].tuner != TUNER_XC2028) - return 0; - - CX18_DEBUG_INFO("Resetting XCeive tuner\n"); - return v4l2_subdev_call(&cx->sd_resetctrl, - core, reset, CX18_GPIO_RESET_XC2028); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-gpio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-gpio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-gpio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-gpio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - * cx18 gpio functions - * - * Derived from ivtv-gpio.h - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -void cx18_gpio_init(struct cx18 *cx); -int cx18_gpio_register(struct cx18 *cx, u32 hw); - -enum cx18_gpio_reset_type { - CX18_GPIO_RESET_I2C = 0, - CX18_GPIO_RESET_Z8F0811 = 1, - CX18_GPIO_RESET_XC2028 = 2, -}; - -void cx18_reset_ir_gpio(void *data); -int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-i2c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,330 +0,0 @@ -/* - * cx18 I2C functions - * - * Derived from ivtv-i2c.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-cards.h" -#include "cx18-gpio.h" -#include "cx18-i2c.h" -#include "cx18-irq.h" - -#define CX18_REG_I2C_1_WR 0xf15000 -#define CX18_REG_I2C_1_RD 0xf15008 -#define CX18_REG_I2C_2_WR 0xf25100 -#define CX18_REG_I2C_2_RD 0xf25108 - -#define SETSCL_BIT 0x0001 -#define SETSDL_BIT 0x0002 -#define GETSCL_BIT 0x0004 -#define GETSDL_BIT 0x0008 - -#define CX18_CS5345_I2C_ADDR 0x4c -#define CX18_Z8F0811_IR_TX_I2C_ADDR 0x70 -#define CX18_Z8F0811_IR_RX_I2C_ADDR 0x71 - -/* This array should match the CX18_HW_ defines */ -static const u8 hw_addrs[] = { - 0, /* CX18_HW_TUNER */ - 0, /* CX18_HW_TVEEPROM */ - CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */ - 0, /* CX18_HW_DVB */ - 0, /* CX18_HW_418_AV */ - 0, /* CX18_HW_GPIO_MUX */ - 0, /* CX18_HW_GPIO_RESET_CTRL */ - CX18_Z8F0811_IR_TX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_TX_HAUP */ - CX18_Z8F0811_IR_RX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_RX_HAUP */ -}; - -/* This array should match the CX18_HW_ defines */ -/* This might well become a card-specific array */ -static const u8 hw_bus[] = { - 1, /* CX18_HW_TUNER */ - 0, /* CX18_HW_TVEEPROM */ - 0, /* CX18_HW_CS5345 */ - 0, /* CX18_HW_DVB */ - 0, /* CX18_HW_418_AV */ - 0, /* CX18_HW_GPIO_MUX */ - 0, /* CX18_HW_GPIO_RESET_CTRL */ - 0, /* CX18_HW_Z8F0811_IR_TX_HAUP */ - 0, /* CX18_HW_Z8F0811_IR_RX_HAUP */ -}; - -/* This array should match the CX18_HW_ defines */ -static const char * const hw_devicenames[] = { - "tuner", - "tveeprom", - "cs5345", - "cx23418_DTV", - "cx23418_AV", - "gpio_mux", - "gpio_reset_ctrl", - "ir_tx_z8f0811_haup", - "ir_rx_z8f0811_haup", -}; - -static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw, - const char *type, u8 addr) -{ - struct i2c_board_info info; - struct IR_i2c_init_data *init_data = &cx->ir_i2c_init_data; - unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, type, I2C_NAME_SIZE); - - /* Our default information for ir-kbd-i2c.c to use */ - switch (hw) { - case CX18_HW_Z8F0811_IR_RX_HAUP: - init_data->ir_codes = RC_MAP_HAUPPAUGE; - init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; - init_data->name = cx->card_name; - info.platform_data = init_data; - break; - } - - return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? - -1 : 0; -} - -int cx18_i2c_register(struct cx18 *cx, unsigned idx) -{ - struct v4l2_subdev *sd; - int bus = hw_bus[idx]; - struct i2c_adapter *adap = &cx->i2c_adap[bus]; - const char *type = hw_devicenames[idx]; - u32 hw = 1 << idx; - - if (idx >= ARRAY_SIZE(hw_addrs)) - return -1; - - if (hw == CX18_HW_TUNER) { - /* special tuner group handling */ - sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, - adap, type, 0, cx->card_i2c->radio); - if (sd != NULL) - sd->grp_id = hw; - sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, - adap, type, 0, cx->card_i2c->demod); - if (sd != NULL) - sd->grp_id = hw; - sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, - adap, type, 0, cx->card_i2c->tv); - if (sd != NULL) - sd->grp_id = hw; - return sd != NULL ? 0 : -1; - } - - if (hw & CX18_HW_IR_ANY) - return cx18_i2c_new_ir(cx, adap, hw, type, hw_addrs[idx]); - - /* Is it not an I2C device or one we do not wish to register? */ - if (!hw_addrs[idx]) - return -1; - - /* It's an I2C device other than an analog tuner or IR chip */ - sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx], - NULL); - if (sd != NULL) - sd->grp_id = hw; - return sd != NULL ? 0 : -1; -} - -/* Find the first member of the subdev group id in hw */ -struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw) -{ - struct v4l2_subdev *result = NULL; - struct v4l2_subdev *sd; - - spin_lock(&cx->v4l2_dev.lock); - v4l2_device_for_each_subdev(sd, &cx->v4l2_dev) { - if (sd->grp_id == hw) { - result = sd; - break; - } - } - spin_unlock(&cx->v4l2_dev.lock); - return result; -} - -static void cx18_setscl(void *data, int state) -{ - struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; - int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; - u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; - u32 r = cx18_read_reg(cx, addr); - - if (state) - cx18_write_reg(cx, r | SETSCL_BIT, addr); - else - cx18_write_reg(cx, r & ~SETSCL_BIT, addr); -} - -static void cx18_setsda(void *data, int state) -{ - struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; - int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; - u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; - u32 r = cx18_read_reg(cx, addr); - - if (state) - cx18_write_reg(cx, r | SETSDL_BIT, addr); - else - cx18_write_reg(cx, r & ~SETSDL_BIT, addr); -} - -static int cx18_getscl(void *data) -{ - struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; - int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; - u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; - - return cx18_read_reg(cx, addr) & GETSCL_BIT; -} - -static int cx18_getsda(void *data) -{ - struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; - int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; - u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; - - return cx18_read_reg(cx, addr) & GETSDL_BIT; -} - -/* template for i2c-bit-algo */ -static struct i2c_adapter cx18_i2c_adap_template = { - .name = "cx18 i2c driver", - .algo = NULL, /* set by i2c-algo-bit */ - .algo_data = NULL, /* filled from template */ - .owner = THIS_MODULE, -}; - -#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */ -#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */ - -static struct i2c_algo_bit_data cx18_i2c_algo_template = { - .setsda = cx18_setsda, - .setscl = cx18_setscl, - .getsda = cx18_getsda, - .getscl = cx18_getscl, - .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/ - .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ -}; - -/* init + register i2c algo-bit adapter */ -int init_cx18_i2c(struct cx18 *cx) -{ - int i, err; - CX18_DEBUG_I2C("i2c init\n"); - - for (i = 0; i < 2; i++) { - /* Setup algorithm for adapter */ - memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template, - sizeof(struct i2c_algo_bit_data)); - cx->i2c_algo_cb_data[i].cx = cx; - cx->i2c_algo_cb_data[i].bus_index = i; - cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i]; - - /* Setup adapter */ - memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, - sizeof(struct i2c_adapter)); - cx->i2c_adap[i].algo_data = &cx->i2c_algo[i]; - sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name), - " #%d-%d", cx->instance, i); - i2c_set_adapdata(&cx->i2c_adap[i], &cx->v4l2_dev); - cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev; - } - - if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) { - /* Reset/Unreset I2C hardware block */ - /* Clock select 220MHz */ - cx18_write_reg_expect(cx, 0x10000000, 0xc71004, - 0x00000000, 0x10001000); - /* Clock Enable */ - cx18_write_reg_expect(cx, 0x10001000, 0xc71024, - 0x00001000, 0x10001000); - } - /* courtesy of Steven Toth */ - cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); - mdelay(10); - cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0); - mdelay(10); - cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); - mdelay(10); - - /* Set to edge-triggered intrs. */ - cx18_write_reg(cx, 0x00c00000, 0xc730c8); - /* Clear any stale intrs */ - cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS, - ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT); - - /* Hw I2C1 Clock Freq ~100kHz */ - cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR); - cx18_setscl(&cx->i2c_algo_cb_data[0], 1); - cx18_setsda(&cx->i2c_algo_cb_data[0], 1); - - /* Hw I2C2 Clock Freq ~100kHz */ - cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR); - cx18_setscl(&cx->i2c_algo_cb_data[1], 1); - cx18_setsda(&cx->i2c_algo_cb_data[1], 1); - - cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, - core, reset, (u32) CX18_GPIO_RESET_I2C); - - err = i2c_bit_add_bus(&cx->i2c_adap[0]); - if (err) - goto err; - err = i2c_bit_add_bus(&cx->i2c_adap[1]); - if (err) - goto err_del_bus_0; - return 0; - - err_del_bus_0: - i2c_del_adapter(&cx->i2c_adap[0]); - err: - return err; -} - -void exit_cx18_i2c(struct cx18 *cx) -{ - int i; - CX18_DEBUG_I2C("i2c exit\n"); - cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4, - CX18_REG_I2C_1_WR); - cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4, - CX18_REG_I2C_2_WR); - - for (i = 0; i < 2; i++) { - i2c_del_adapter(&cx->i2c_adap[i]); - } -} - -/* - Hauppauge HVR1600 should have: - 32 cx24227 - 98 unknown - a0 eeprom - c2 tuner - e? zilog ir - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-i2c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-i2c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* - * cx18 I2C functions - * - * Derived from ivtv-i2c.h - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -int cx18_i2c_register(struct cx18 *cx, unsigned idx); -struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw); - -/* init + register i2c algo-bit adapter */ -int init_cx18_i2c(struct cx18 *cx); -void exit_cx18_i2c(struct cx18 *cx); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-io.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-io.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-io.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-io.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/* - * cx18 driver PCI memory mapped IO access routines - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-irq.h" - -void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count) -{ - u8 __iomem *dst = addr; - u16 val2 = val | (val << 8); - u32 val4 = val2 | (val2 << 16); - - /* Align writes on the CX23418's addresses */ - if ((count > 0) && ((unsigned long)dst & 1)) { - cx18_writeb(cx, (u8) val, dst); - count--; - dst++; - } - if ((count > 1) && ((unsigned long)dst & 2)) { - cx18_writew(cx, val2, dst); - count -= 2; - dst += 2; - } - while (count > 3) { - cx18_writel(cx, val4, dst); - count -= 4; - dst += 4; - } - if (count > 1) { - cx18_writew(cx, val2, dst); - count -= 2; - dst += 2; - } - if (count > 0) - cx18_writeb(cx, (u8) val, dst); -} - -void cx18_sw1_irq_enable(struct cx18 *cx, u32 val) -{ - cx18_write_reg_expect(cx, val, SW1_INT_STATUS, ~val, val); - cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | val; - cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI); -} - -void cx18_sw1_irq_disable(struct cx18 *cx, u32 val) -{ - cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) & ~val; - cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI); -} - -void cx18_sw2_irq_enable(struct cx18 *cx, u32 val) -{ - cx18_write_reg_expect(cx, val, SW2_INT_STATUS, ~val, val); - cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | val; - cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI); -} - -void cx18_sw2_irq_disable(struct cx18 *cx, u32 val) -{ - cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) & ~val; - cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI); -} - -void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val) -{ - u32 r; - r = cx18_read_reg(cx, SW2_INT_ENABLE_CPU); - cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_CPU); -} - -void cx18_setup_page(struct cx18 *cx, u32 addr) -{ - u32 val; - val = cx18_read_reg(cx, 0xD000F8); - val = (val & ~0x1f00) | ((addr >> 17) & 0x1f00); - cx18_write_reg(cx, val, 0xD000F8); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-ioctl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-ioctl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-ioctl.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-ioctl.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1089 +0,0 @@ -/* - * cx18 ioctl system call - * - * Derived from ivtv-ioctl.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-version.h" -#include "cx18-mailbox.h" -#include "cx18-i2c.h" -#include "cx18-queue.h" -#include "cx18-fileops.h" -#include "cx18-vbi.h" -#include "cx18-audio.h" -#include "cx18-video.h" -#include "cx18-streams.h" -#include "cx18-ioctl.h" -#include "cx18-gpio.h" -#include "cx18-controls.h" -#include "cx18-cards.h" -#include "cx18-av-core.h" -#include -#include - -u16 cx18_service2vbi(int type) -{ - switch (type) { - case V4L2_SLICED_TELETEXT_B: - return CX18_SLICED_TYPE_TELETEXT_B; - case V4L2_SLICED_CAPTION_525: - return CX18_SLICED_TYPE_CAPTION_525; - case V4L2_SLICED_WSS_625: - return CX18_SLICED_TYPE_WSS_625; - case V4L2_SLICED_VPS: - return CX18_SLICED_TYPE_VPS; - default: - return 0; - } -} - -/* Check if VBI services are allowed on the (field, line) for the video std */ -static int valid_service_line(int field, int line, int is_pal) -{ - return (is_pal && line >= 6 && - ((field == 0 && line <= 23) || (field == 1 && line <= 22))) || - (!is_pal && line >= 10 && line < 22); -} - -/* - * For a (field, line, std) and inbound potential set of services for that line, - * return the first valid service of those passed in the incoming set for that - * line in priority order: - * CC, VPS, or WSS over TELETEXT for well known lines - * TELETEXT, before VPS, before CC, before WSS, for other lines - */ -static u16 select_service_from_set(int field, int line, u16 set, int is_pal) -{ - u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); - int i; - - set = set & valid_set; - if (set == 0 || !valid_service_line(field, line, is_pal)) - return 0; - if (!is_pal) { - if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) - return V4L2_SLICED_CAPTION_525; - } else { - if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) - return V4L2_SLICED_VPS; - if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) - return V4L2_SLICED_WSS_625; - if (line == 23) - return 0; - } - for (i = 0; i < 32; i++) { - if ((1 << i) & set) - return 1 << i; - } - return 0; -} - -/* - * Expand the service_set of *fmt into valid service_lines for the std, - * and clear the passed in fmt->service_set - */ -void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) -{ - u16 set = fmt->service_set; - int f, l; - - fmt->service_set = 0; - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) - fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); - } -} - -/* - * Sanitize the service_lines in *fmt per the video std, and return 1 - * if any service_line is left as valid after santization - */ -static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) -{ - int f, l; - u16 set = 0; - - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); - set |= fmt->service_lines[f][l]; - } - } - return set != 0; -} - -/* Compute the service_set from the assumed valid service_lines of *fmt */ -u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) -{ - int f, l; - u16 set = 0; - - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) - set |= fmt->service_lines[f][l]; - } - return set; -} - -static int cx18_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - pixfmt->width = cx->cxhdl.width; - pixfmt->height = cx->cxhdl.height; - pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - pixfmt->field = V4L2_FIELD_INTERLACED; - pixfmt->priv = 0; - if (id->type == CX18_ENC_STREAM_TYPE_YUV) { - pixfmt->pixelformat = V4L2_PIX_FMT_HM12; - /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */ - pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; - pixfmt->bytesperline = 720; - } else { - pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; - pixfmt->sizeimage = 128 * 1024; - pixfmt->bytesperline = 0; - } - return 0; -} - -static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; - - vbifmt->sampling_rate = 27000000; - vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */ - vbifmt->samples_per_line = vbi_active_samples - 4; - vbifmt->sample_format = V4L2_PIX_FMT_GREY; - vbifmt->start[0] = cx->vbi.start[0]; - vbifmt->start[1] = cx->vbi.start[1]; - vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count; - vbifmt->flags = 0; - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - return 0; -} - -static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - /* sane, V4L2 spec compliant, defaults */ - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); - vbifmt->service_set = 0; - - /* - * Fetch the configured service_lines and total service_set from the - * digitizer/slicer. Note, cx18_av_vbi() wipes the passed in - * fmt->fmt.sliced under valid calling conditions - */ - if (v4l2_subdev_call(cx->sd_av, vbi, g_sliced_fmt, &fmt->fmt.sliced)) - return -EINVAL; - - /* Ensure V4L2 spec compliant output */ - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - vbifmt->service_set = cx18_get_service_set(vbifmt); - return 0; -} - -static int cx18_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; - int min_h = 2; - - w = min(w, 720); - w = max(w, 2); - if (id->type == CX18_ENC_STREAM_TYPE_YUV) { - /* YUV height must be a multiple of 32 */ - h &= ~0x1f; - min_h = 32; - } - h = min(h, cx->is_50hz ? 576 : 480); - h = max(h, min_h); - - cx18_g_fmt_vid_cap(file, fh, fmt); - fmt->fmt.pix.width = w; - fmt->fmt.pix.height = h; - return 0; -} - -static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - return cx18_g_fmt_vbi_cap(file, fh, fmt); -} - -static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - - /* If given a service set, expand it validly & clear passed in set */ - if (vbifmt->service_set) - cx18_expand_service_set(vbifmt, cx->is_50hz); - /* Sanitize the service_lines, and compute the new set if any valid */ - if (check_service_set(vbifmt, cx->is_50hz)) - vbifmt->service_set = cx18_get_service_set(vbifmt); - return 0; -} - -static int cx18_s_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - struct v4l2_mbus_framefmt mbus_fmt; - int ret; - int w, h; - - ret = cx18_try_fmt_vid_cap(file, fh, fmt); - if (ret) - return ret; - w = fmt->fmt.pix.width; - h = fmt->fmt.pix.height; - - if (cx->cxhdl.width == w && cx->cxhdl.height == h) - return 0; - - if (atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - mbus_fmt.width = cx->cxhdl.width = w; - mbus_fmt.height = cx->cxhdl.height = h; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); - return cx18_g_fmt_vid_cap(file, fh, fmt); -} - -static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - int ret; - - /* - * Changing the Encoder's Raw VBI parameters won't have any effect - * if any analog capture is ongoing - */ - if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - /* - * Set the digitizer registers for raw active VBI. - * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid - * calling conditions - */ - ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi); - if (ret) - return ret; - - /* Store our new v4l2 (non-)sliced VBI state */ - cx->vbi.sliced_in->service_set = 0; - cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; - - return cx18_g_fmt_vbi_cap(file, fh, fmt); -} - -static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - int ret; - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - cx18_try_fmt_sliced_vbi_cap(file, fh, fmt); - - /* - * Changing the Encoder's Raw VBI parameters won't have any effect - * if any analog capture is ongoing - */ - if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - /* - * Set the service_lines requested in the digitizer/slicer registers. - * Note, cx18_av_vbi() wipes some "impossible" service lines in the - * passed in fmt->fmt.sliced under valid calling conditions - */ - ret = v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &fmt->fmt.sliced); - if (ret) - return ret; - /* Store our current v4l2 sliced VBI settings */ - cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); - return 0; -} - -static int cx18_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) -{ - struct cx18 *cx = fh2id(fh)->cx; - int err = 0; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - switch (chip->match.type) { - case V4L2_CHIP_MATCH_HOST: - switch (chip->match.addr) { - case 0: - chip->ident = V4L2_IDENT_CX23418; - chip->revision = cx18_read_reg(cx, 0xC72028); - break; - case 1: - /* - * The A/V decoder is always present, but in the rare - * case that the card doesn't have analog, we don't - * use it. We find it w/o using the cx->sd_av pointer - */ - cx18_call_hw(cx, CX18_HW_418_AV, - core, g_chip_ident, chip); - break; - default: - /* - * Could return ident = V4L2_IDENT_UNKNOWN if we had - * other host chips at higher addresses, but we don't - */ - err = -EINVAL; /* per V4L2 spec */ - break; - } - break; - case V4L2_CHIP_MATCH_I2C_DRIVER: - /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */ - cx18_call_all(cx, core, g_chip_ident, chip); - break; - case V4L2_CHIP_MATCH_I2C_ADDR: - /* - * We could return V4L2_IDENT_UNKNOWN, but we don't do the work - * to look if a chip is at the address with no driver. That's a - * dangerous thing to do with EEPROMs anyway. - */ - cx18_call_all(cx, core, g_chip_ident, chip); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) -{ - struct v4l2_dbg_register *regs = arg; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) - return -EINVAL; - - regs->size = 4; - if (cmd == VIDIOC_DBG_S_REGISTER) - cx18_write_enc(cx, regs->val, regs->reg); - else - regs->val = cx18_read_enc(cx, regs->reg); - return 0; -} - -static int cx18_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (v4l2_chip_match_host(®->match)) - return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); - /* FIXME - errors shouldn't be ignored */ - cx18_call_all(cx, core, g_register, reg); - return 0; -} - -static int cx18_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (v4l2_chip_match_host(®->match)) - return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); - /* FIXME - errors shouldn't be ignored */ - cx18_call_all(cx, core, s_register, reg); - return 0; -} -#endif - -static int cx18_querycap(struct file *file, void *fh, - struct v4l2_capability *vcap) -{ - struct cx18 *cx = fh2id(fh)->cx; - - strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); - strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); - snprintf(vcap->bus_info, sizeof(vcap->bus_info), - "PCI:%s", pci_name(cx->pci_dev)); - vcap->version = CX18_DRIVER_VERSION; /* version */ - vcap->capabilities = cx->v4l2_cap; /* capabilities */ - return 0; -} - -static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) -{ - struct cx18 *cx = fh2id(fh)->cx; - - return cx18_get_audio_input(cx, vin->index, vin); -} - -static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) -{ - struct cx18 *cx = fh2id(fh)->cx; - - vin->index = cx->audio_input; - return cx18_get_audio_input(cx, vin->index, vin); -} - -static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (vout->index >= cx->nof_audio_inputs) - return -EINVAL; - cx->audio_input = vout->index; - cx18_audio_set_io(cx); - return 0; -} - -static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - struct cx18 *cx = fh2id(fh)->cx; - - /* set it to defaults from our table */ - return cx18_get_input(cx, vin->index, vin); -} - -static int cx18_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cropcap) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = cx->is_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; - cropcap->defrect = cropcap->bounds; - return 0; -} - -static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n"); - return -EINVAL; -} - -static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n"); - return -EINVAL; -} - -static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, - "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } - }, - { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, - "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } - } - }; - - if (fmt->index > 1) - return -EINVAL; - *fmt = formats[fmt->index]; - return 0; -} - -static int cx18_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct cx18 *cx = fh2id(fh)->cx; - - *i = cx->active_input; - return 0; -} - -int cx18_s_input(struct file *file, void *fh, unsigned int inp) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (inp >= cx->nof_inputs) - return -EINVAL; - - if (inp == cx->active_input) { - CX18_DEBUG_INFO("Input unchanged\n"); - return 0; - } - - CX18_DEBUG_INFO("Changing input from %d to %d\n", - cx->active_input, inp); - - cx->active_input = inp; - /* Set the audio input to whatever is appropriate for the input type. */ - cx->audio_input = cx->card->video_inputs[inp].audio_index; - - /* prevent others from messing with the streams until - we're finished changing inputs. */ - cx18_mute(cx); - cx18_video_set_io(cx); - cx18_audio_set_io(cx); - cx18_unmute(cx); - return 0; -} - -static int cx18_g_frequency(struct file *file, void *fh, - struct v4l2_frequency *vf) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (vf->tuner != 0) - return -EINVAL; - - cx18_call_all(cx, tuner, g_frequency, vf); - return 0; -} - -int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (vf->tuner != 0) - return -EINVAL; - - cx18_mute(cx); - CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); - cx18_call_all(cx, tuner, s_frequency, vf); - cx18_unmute(cx); - return 0; -} - -static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) -{ - struct cx18 *cx = fh2id(fh)->cx; - - *std = cx->std; - return 0; -} - -int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if ((*std & V4L2_STD_ALL) == 0) - return -EINVAL; - - if (*std == cx->std) - return 0; - - if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || - atomic_read(&cx->ana_capturing) > 0) { - /* Switching standard would turn off the radio or mess - with already running streams, prevent that by - returning EBUSY. */ - return -EBUSY; - } - - cx->std = *std; - cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; - cx->is_50hz = !cx->is_60hz; - cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz); - cx->cxhdl.width = 720; - cx->cxhdl.height = cx->is_50hz ? 576 : 480; - cx->vbi.count = cx->is_50hz ? 18 : 12; - cx->vbi.start[0] = cx->is_50hz ? 6 : 10; - cx->vbi.start[1] = cx->is_50hz ? 318 : 273; - CX18_DEBUG_INFO("Switching standard to %llx.\n", - (unsigned long long) cx->std); - - /* Tuner */ - cx18_call_all(cx, core, s_std, cx->std); - return 0; -} - -static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (vt->index != 0) - return -EINVAL; - - cx18_call_all(cx, tuner, s_tuner, vt); - return 0; -} - -static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (vt->index != 0) - return -EINVAL; - - cx18_call_all(cx, tuner, g_tuner, vt); - - if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { - strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_RADIO; - } else { - strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_ANALOG_TV; - } - - return 0; -} - -static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_sliced_vbi_cap *cap) -{ - struct cx18 *cx = fh2id(fh)->cx; - int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; - int f, l; - - if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - - cap->service_set = 0; - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - if (valid_service_line(f, l, cx->is_50hz)) { - /* - * We can find all v4l2 supported vbi services - * for the standard, on a valid line for the std - */ - cap->service_lines[f][l] = set; - cap->service_set |= set; - } else - cap->service_lines[f][l] = 0; - } - } - for (f = 0; f < 3; f++) - cap->reserved[f] = 0; - return 0; -} - -static int _cx18_process_idx_data(struct cx18_buffer *buf, - struct v4l2_enc_idx *idx) -{ - int consumed, remaining; - struct v4l2_enc_idx_entry *e_idx; - struct cx18_enc_idx_entry *e_buf; - - /* Frame type lookup: 1=I, 2=P, 4=B */ - const int mapping[8] = { - -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, - -1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1 - }; - - /* - * Assumption here is that a buf holds an integral number of - * struct cx18_enc_idx_entry objects and is properly aligned. - * This is enforced by the module options on IDX buffer sizes. - */ - remaining = buf->bytesused - buf->readpos; - consumed = 0; - e_idx = &idx->entry[idx->entries]; - e_buf = (struct cx18_enc_idx_entry *) &buf->buf[buf->readpos]; - - while (remaining >= sizeof(struct cx18_enc_idx_entry) && - idx->entries < V4L2_ENC_IDX_ENTRIES) { - - e_idx->offset = (((u64) le32_to_cpu(e_buf->offset_high)) << 32) - | le32_to_cpu(e_buf->offset_low); - - e_idx->pts = (((u64) (le32_to_cpu(e_buf->pts_high) & 1)) << 32) - | le32_to_cpu(e_buf->pts_low); - - e_idx->length = le32_to_cpu(e_buf->length); - - e_idx->flags = mapping[le32_to_cpu(e_buf->flags) & 0x7]; - - e_idx->reserved[0] = 0; - e_idx->reserved[1] = 0; - - idx->entries++; - e_idx = &idx->entry[idx->entries]; - e_buf++; - - remaining -= sizeof(struct cx18_enc_idx_entry); - consumed += sizeof(struct cx18_enc_idx_entry); - } - - /* Swallow any partial entries at the end, if there are any */ - if (remaining > 0 && remaining < sizeof(struct cx18_enc_idx_entry)) - consumed += remaining; - - buf->readpos += consumed; - return consumed; -} - -static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl, - struct v4l2_enc_idx *idx) -{ - if (s->type != CX18_ENC_STREAM_TYPE_IDX) - return -EINVAL; - - if (mdl->curr_buf == NULL) - mdl->curr_buf = list_first_entry(&mdl->buf_list, - struct cx18_buffer, list); - - if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { - /* - * For some reason we've exhausted the buffers, but the MDL - * object still said some data was unread. - * Fix that and bail out. - */ - mdl->readpos = mdl->bytesused; - return 0; - } - - list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { - - /* Skip any empty buffers in the MDL */ - if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) - continue; - - mdl->readpos += _cx18_process_idx_data(mdl->curr_buf, idx); - - /* exit when MDL drained or request satisfied */ - if (idx->entries >= V4L2_ENC_IDX_ENTRIES || - mdl->curr_buf->readpos < mdl->curr_buf->bytesused || - mdl->readpos >= mdl->bytesused) - break; - } - return 0; -} - -static int cx18_g_enc_index(struct file *file, void *fh, - struct v4l2_enc_idx *idx) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - s32 tmp; - struct cx18_mdl *mdl; - - if (!cx18_stream_enabled(s)) /* Module options inhibited IDX stream */ - return -EINVAL; - - /* Compute the best case number of entries we can buffer */ - tmp = s->buffers - - s->bufs_per_mdl * CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN; - if (tmp <= 0) - tmp = 1; - tmp = tmp * s->buf_size / sizeof(struct cx18_enc_idx_entry); - - /* Fill out the header of the return structure */ - idx->entries = 0; - idx->entries_cap = tmp; - memset(idx->reserved, 0, sizeof(idx->reserved)); - - /* Pull IDX MDLs and buffers from q_full and populate the entries */ - do { - mdl = cx18_dequeue(s, &s->q_full); - if (mdl == NULL) /* No more IDX data right now */ - break; - - /* Extract the Index entry data from the MDL and buffers */ - cx18_process_idx_data(s, mdl, idx); - if (mdl->readpos < mdl->bytesused) { - /* We finished with data remaining, push the MDL back */ - cx18_push(s, mdl, &s->q_full); - break; - } - - /* We drained this MDL, schedule it to go to the firmware */ - cx18_enqueue(s, mdl, &s->q_free); - - } while (idx->entries < V4L2_ENC_IDX_ENTRIES); - - /* Tell the work handler to send free IDX MDLs to the firmware */ - cx18_stream_load_fw_queue(s); - return 0; -} - -static int cx18_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *enc) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - u32 h; - - switch (enc->cmd) { - case V4L2_ENC_CMD_START: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); - enc->flags = 0; - return cx18_start_capture(id); - - case V4L2_ENC_CMD_STOP: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - cx18_stop_capture(id, - enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); - break; - - case V4L2_ENC_CMD_PAUSE: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); - enc->flags = 0; - if (!atomic_read(&cx->ana_capturing)) - return -EPERM; - if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) - return 0; - h = cx18_find_handle(cx); - if (h == CX18_INVALID_TASK_HANDLE) { - CX18_ERR("Can't find valid task handle for " - "V4L2_ENC_CMD_PAUSE\n"); - return -EBADFD; - } - cx18_mute(cx); - cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h); - break; - - case V4L2_ENC_CMD_RESUME: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); - enc->flags = 0; - if (!atomic_read(&cx->ana_capturing)) - return -EPERM; - if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) - return 0; - h = cx18_find_handle(cx); - if (h == CX18_INVALID_TASK_HANDLE) { - CX18_ERR("Can't find valid task handle for " - "V4L2_ENC_CMD_RESUME\n"); - return -EBADFD; - } - cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h); - cx18_unmute(cx); - break; - - default: - CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); - return -EINVAL; - } - return 0; -} - -static int cx18_try_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *enc) -{ - struct cx18 *cx = fh2id(fh)->cx; - - switch (enc->cmd) { - case V4L2_ENC_CMD_START: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); - enc->flags = 0; - break; - - case V4L2_ENC_CMD_STOP: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - break; - - case V4L2_ENC_CMD_PAUSE: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); - enc->flags = 0; - break; - - case V4L2_ENC_CMD_RESUME: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); - enc->flags = 0; - break; - - default: - CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); - return -EINVAL; - } - return 0; -} - -static int cx18_log_status(struct file *file, void *fh) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct v4l2_input vidin; - struct v4l2_audio audin; - int i; - - CX18_INFO("================= START STATUS CARD #%d " - "=================\n", cx->instance); - CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name); - if (cx->hw_flags & CX18_HW_TVEEPROM) { - struct tveeprom tv; - - cx18_read_eeprom(cx, &tv); - } - cx18_call_all(cx, core, log_status); - cx18_get_input(cx, cx->active_input, &vidin); - cx18_get_audio_input(cx, cx->audio_input, &audin); - CX18_INFO("Video Input: %s\n", vidin.name); - CX18_INFO("Audio Input: %s\n", audin.name); - mutex_lock(&cx->gpio_lock); - CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n", - cx->gpio_dir, cx->gpio_val); - mutex_unlock(&cx->gpio_lock); - CX18_INFO("Tuner: %s\n", - test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV"); - v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name); - CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); - for (i = 0; i < CX18_MAX_STREAMS; i++) { - struct cx18_stream *s = &cx->streams[i]; - - if (s->video_dev == NULL || s->buffers == 0) - continue; - CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", - s->name, s->s_flags, - atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100 - / s->buffers, - (s->buffers * s->buf_size) / 1024, s->buffers); - } - CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", - (long long)cx->mpg_data_received, - (long long)cx->vbi_data_inserted); - CX18_INFO("================== END STATUS CARD #%d " - "==================\n", cx->instance); - return 0; -} - -static long cx18_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) -{ - struct cx18 *cx = fh2id(fh)->cx; - - switch (cmd) { - case VIDIOC_INT_RESET: { - u32 val = *(u32 *)arg; - - if ((val == 0) || (val & 0x01)) - cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset, - (u32) CX18_GPIO_RESET_Z8F0811); - break; - } - - default: - return -EINVAL; - } - return 0; -} - -long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct video_device *vfd = video_devdata(filp); - struct cx18_open_id *id = file2id(filp); - struct cx18 *cx = id->cx; - long res; - - mutex_lock(&cx->serialize_lock); - - if (cx18_debug & CX18_DBGFLG_IOCTL) - vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; - res = video_ioctl2(filp, cmd, arg); - vfd->debug = 0; - mutex_unlock(&cx->serialize_lock); - return res; -} - -static const struct v4l2_ioctl_ops cx18_ioctl_ops = { - .vidioc_querycap = cx18_querycap, - .vidioc_s_audio = cx18_s_audio, - .vidioc_g_audio = cx18_g_audio, - .vidioc_enumaudio = cx18_enumaudio, - .vidioc_enum_input = cx18_enum_input, - .vidioc_cropcap = cx18_cropcap, - .vidioc_s_crop = cx18_s_crop, - .vidioc_g_crop = cx18_g_crop, - .vidioc_g_input = cx18_g_input, - .vidioc_s_input = cx18_s_input, - .vidioc_g_frequency = cx18_g_frequency, - .vidioc_s_frequency = cx18_s_frequency, - .vidioc_s_tuner = cx18_s_tuner, - .vidioc_g_tuner = cx18_g_tuner, - .vidioc_g_enc_index = cx18_g_enc_index, - .vidioc_g_std = cx18_g_std, - .vidioc_s_std = cx18_s_std, - .vidioc_log_status = cx18_log_status, - .vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap, - .vidioc_encoder_cmd = cx18_encoder_cmd, - .vidioc_try_encoder_cmd = cx18_try_encoder_cmd, - .vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap, - .vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap, - .vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap, - .vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap, - .vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap, - .vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap, - .vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap, - .vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap, - .vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap, - .vidioc_g_chip_ident = cx18_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = cx18_g_register, - .vidioc_s_register = cx18_s_register, -#endif - .vidioc_default = cx18_default, -}; - -void cx18_set_funcs(struct video_device *vdev) -{ - vdev->ioctl_ops = &cx18_ioctl_ops; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-ioctl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-ioctl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-ioctl.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-ioctl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - * cx18 ioctl system call - * - * Derived from ivtv-ioctl.h - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -u16 cx18_service2vbi(int type); -void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); -u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); -void cx18_set_funcs(struct video_device *vdev); -int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); -int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); -int cx18_s_input(struct file *file, void *fh, unsigned int inp); -long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-io.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-io.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-io.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-io.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -/* - * cx18 driver PCI memory mapped IO access routines - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#ifndef CX18_IO_H -#define CX18_IO_H - -#include "cx18-driver.h" - -/* - * Readback and retry of MMIO access for reliability: - * The concept was suggested by Steve Toth . - * The implmentation is the fault of Andy Walls . - * - * *write* functions are implied to retry the mmio unless suffixed with _noretry - * *read* functions never retry the mmio (it never helps to do so) - */ - -/* Non byteswapping memory mapped IO */ -static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr) -{ - return __raw_readl(addr); -} - -static inline -void cx18_raw_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) -{ - __raw_writel(val, addr); -} - -static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr) -{ - int i; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_raw_writel_noretry(cx, val, addr); - if (val == cx18_raw_readl(cx, addr)) - break; - } -} - -/* Normal memory mapped IO */ -static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr) -{ - return readl(addr); -} - -static inline -void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) -{ - writel(val, addr); -} - -static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr) -{ - int i; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_writel_noretry(cx, val, addr); - if (val == cx18_readl(cx, addr)) - break; - } -} - -static inline -void cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr, - u32 eval, u32 mask) -{ - int i; - u32 r; - eval &= mask; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_writel_noretry(cx, val, addr); - r = cx18_readl(cx, addr); - if (r == 0xffffffff && eval != 0xffffffff) - continue; - if (eval == (r & mask)) - break; - } -} - -static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr) -{ - return readw(addr); -} - -static inline -void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr) -{ - writew(val, addr); -} - -static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr) -{ - int i; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_writew_noretry(cx, val, addr); - if (val == cx18_readw(cx, addr)) - break; - } -} - -static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr) -{ - return readb(addr); -} - -static inline -void cx18_writeb_noretry(struct cx18 *cx, u8 val, void __iomem *addr) -{ - writeb(val, addr); -} - -static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr) -{ - int i; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_writeb_noretry(cx, val, addr); - if (val == cx18_readb(cx, addr)) - break; - } -} - -static inline -void cx18_memcpy_fromio(struct cx18 *cx, void *to, - const void __iomem *from, unsigned int len) -{ - memcpy_fromio(to, from, len); -} - -void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count); - - -/* Access "register" region of CX23418 memory mapped I/O */ -static inline void cx18_write_reg_noretry(struct cx18 *cx, u32 val, u32 reg) -{ - cx18_writel_noretry(cx, val, cx->reg_mem + reg); -} - -static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg) -{ - cx18_writel(cx, val, cx->reg_mem + reg); -} - -static inline void cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg, - u32 eval, u32 mask) -{ - cx18_writel_expect(cx, val, cx->reg_mem + reg, eval, mask); -} - -static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg) -{ - return cx18_readl(cx, cx->reg_mem + reg); -} - - -/* Access "encoder memory" region of CX23418 memory mapped I/O */ -static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr) -{ - cx18_writel(cx, val, cx->enc_mem + addr); -} - -static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr) -{ - return cx18_readl(cx, cx->enc_mem + addr); -} - -void cx18_sw1_irq_enable(struct cx18 *cx, u32 val); -void cx18_sw1_irq_disable(struct cx18 *cx, u32 val); -void cx18_sw2_irq_enable(struct cx18 *cx, u32 val); -void cx18_sw2_irq_disable(struct cx18 *cx, u32 val); -void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val); -void cx18_setup_page(struct cx18 *cx, u32 addr); - -#endif /* CX18_IO_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-irq.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-irq.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-irq.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-irq.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/* - * cx18 interrupt handling - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-irq.h" -#include "cx18-mailbox.h" -#include "cx18-scb.h" - -static void xpu_ack(struct cx18 *cx, u32 sw2) -{ - if (sw2 & IRQ_CPU_TO_EPU_ACK) - wake_up(&cx->mb_cpu_waitq); - if (sw2 & IRQ_APU_TO_EPU_ACK) - wake_up(&cx->mb_apu_waitq); -} - -static void epu_cmd(struct cx18 *cx, u32 sw1) -{ - if (sw1 & IRQ_CPU_TO_EPU) - cx18_api_epu_cmd_irq(cx, CPU); - if (sw1 & IRQ_APU_TO_EPU) - cx18_api_epu_cmd_irq(cx, APU); -} - -irqreturn_t cx18_irq_handler(int irq, void *dev_id) -{ - struct cx18 *cx = (struct cx18 *)dev_id; - u32 sw1, sw2, hw2; - - sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & cx->sw1_irq_mask; - sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & cx->sw2_irq_mask; - hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & cx->hw2_irq_mask; - - if (sw1) - cx18_write_reg_expect(cx, sw1, SW1_INT_STATUS, ~sw1, sw1); - if (sw2) - cx18_write_reg_expect(cx, sw2, SW2_INT_STATUS, ~sw2, sw2); - if (hw2) - cx18_write_reg_expect(cx, hw2, HW2_INT_CLR_STATUS, ~hw2, hw2); - - if (sw1 || sw2 || hw2) - CX18_DEBUG_HI_IRQ("received interrupts " - "SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); - - /* - * SW1 responses have to happen first. The sending XPU times out the - * incoming mailboxes on us rather rapidly. - */ - if (sw1) - epu_cmd(cx, sw1); - - /* To do: interrupt-based I2C handling - if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) { - } - */ - - if (sw2) - xpu_ack(cx, sw2); - - return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-irq.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-irq.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-irq.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-irq.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - * cx18 interrupt handling - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#define HW2_I2C1_INT (1 << 22) -#define HW2_I2C2_INT (1 << 23) -#define HW2_INT_CLR_STATUS 0xc730c4 -#define HW2_INT_MASK5_PCI 0xc730e4 -#define SW1_INT_SET 0xc73100 -#define SW1_INT_STATUS 0xc73104 -#define SW1_INT_ENABLE_PCI 0xc7311c -#define SW2_INT_SET 0xc73140 -#define SW2_INT_STATUS 0xc73144 -#define SW2_INT_ENABLE_CPU 0xc73158 -#define SW2_INT_ENABLE_PCI 0xc7315c - -irqreturn_t cx18_irq_handler(int irq, void *dev_id); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-mailbox.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-mailbox.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-mailbox.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-mailbox.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,811 +0,0 @@ -/* - * cx18 mailbox functions - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-scb.h" -#include "cx18-irq.h" -#include "cx18-mailbox.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-alsa-pcm.h" /* FIXME make configurable */ - -static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" }; - -#define API_FAST (1 << 2) /* Short timeout */ -#define API_SLOW (1 << 3) /* Additional 300ms timeout */ - -struct cx18_api_info { - u32 cmd; - u8 flags; /* Flags, see above */ - u8 rpu; /* Processing unit */ - const char *name; /* The name of the command */ -}; - -#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x } - -static const struct cx18_api_info api_info[] = { - /* MPEG encoder API */ - API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), - API_ENTRY(CPU, CX18_EPU_DEBUG, 0), - API_ENTRY(CPU, CX18_CREATE_TASK, 0), - API_ENTRY(CPU, CX18_DESTROY_TASK, 0), - API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW), - API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW), - API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0), - API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0), - API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), - API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0), - API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0), - API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0), - API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0), - API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0), - API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0), - API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0), - API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0), - API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW), - API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0), - API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0), - API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0), - API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0), - API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0), - API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0), - API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0), - API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0), - API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), - API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), - API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), - API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), - API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), - API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), - API_ENTRY(APU, CX18_APU_START, 0), - API_ENTRY(APU, CX18_APU_STOP, 0), - API_ENTRY(APU, CX18_APU_RESETAI, 0), - API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0), - API_ENTRY(0, 0, 0), -}; - -static const struct cx18_api_info *find_api_info(u32 cmd) -{ - int i; - - for (i = 0; api_info[i].cmd; i++) - if (api_info[i].cmd == cmd) - return &api_info[i]; - return NULL; -} - -/* Call with buf of n*11+1 bytes */ -static char *u32arr2hex(u32 data[], int n, char *buf) -{ - char *p; - int i; - - for (i = 0, p = buf; i < n; i++, p += 11) { - /* kernel snprintf() appends '\0' always */ - snprintf(p, 12, " %#010x", data[i]); - } - *p = '\0'; - return buf; -} - -static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) -{ - char argstr[MAX_MB_ARGUMENTS*11+1]; - - if (!(cx18_debug & CX18_DBGFLG_API)) - return; - - CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s" - "\n", name, mb->request, mb->ack, mb->cmd, mb->error, - u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr)); -} - - -/* - * Functions that run in a work_queue work handling context - */ - -static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - if (s->dvb == NULL || !s->dvb->enabled || mdl->bytesused == 0) - return; - - /* We ignore mdl and buf readpos accounting here - it doesn't matter */ - - /* The likely case */ - if (list_is_singular(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, - list); - if (buf->bytesused) - dvb_dmx_swfilter(&s->dvb->demux, - buf->buf, buf->bytesused); - return; - } - - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - dvb_dmx_swfilter(&s->dvb->demux, buf->buf, buf->bytesused); - } -} - - -static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - if (mdl->bytesused == 0) - return; - - /* We ignore mdl and buf readpos accounting here - it doesn't matter */ - - /* The likely case */ - if (list_is_singular(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, - list); - if (buf->bytesused) - cx->pcm_announce_callback(cx->alsa, buf->buf, - buf->bytesused); - return; - } - - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - cx->pcm_announce_callback(cx->alsa, buf->buf, buf->bytesused); - } -} - -static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) -{ - u32 handle, mdl_ack_count, id; - struct cx18_mailbox *mb; - struct cx18_mdl_ack *mdl_ack; - struct cx18_stream *s; - struct cx18_mdl *mdl; - int i; - - mb = &order->mb; - handle = mb->args[0]; - s = cx18_handle_to_stream(cx, handle); - - if (s == NULL) { - CX18_WARN("Got DMA done notification for unknown/inactive" - " handle %d, %s mailbox seq no %d\n", handle, - (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ? - "stale" : "good", mb->request); - return; - } - - mdl_ack_count = mb->args[2]; - mdl_ack = order->mdl_ack; - for (i = 0; i < mdl_ack_count; i++, mdl_ack++) { - id = mdl_ack->id; - /* - * Simple integrity check for processing a stale (and possibly - * inconsistent mailbox): make sure the MDL id is in the - * valid range for the stream. - * - * We go through the trouble of dealing with stale mailboxes - * because most of the time, the mailbox data is still valid and - * unchanged (and in practice the firmware ping-pongs the - * two mdl_ack buffers so mdl_acks are not stale). - * - * There are occasions when we get a half changed mailbox, - * which this check catches for a handle & id mismatch. If the - * handle and id do correspond, the worst case is that we - * completely lost the old MDL, but pick up the new MDL - * early (but the new mdl_ack is guaranteed to be good in this - * case as the firmware wouldn't point us to a new mdl_ack until - * it's filled in). - * - * cx18_queue_get_mdl() will detect the lost MDLs - * and send them back to q_free for fw rotation eventually. - */ - if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && - !(id >= s->mdl_base_idx && - id < (s->mdl_base_idx + s->buffers))) { - CX18_WARN("Fell behind! Ignoring stale mailbox with " - " inconsistent data. Lost MDL for mailbox " - "seq no %d\n", mb->request); - break; - } - mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used); - - CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id); - if (mdl == NULL) { - CX18_WARN("Could not find MDL %d for stream %s\n", - id, s->name); - continue; - } - - CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", - s->name, mdl->bytesused); - - if (s->type == CX18_ENC_STREAM_TYPE_TS) { - cx18_mdl_send_to_dvb(s, mdl); - cx18_enqueue(s, mdl, &s->q_free); - } else if (s->type == CX18_ENC_STREAM_TYPE_PCM) { - /* Pass the data to cx18-alsa */ - if (cx->pcm_announce_callback != NULL) { - cx18_mdl_send_to_alsa(cx, s, mdl); - cx18_enqueue(s, mdl, &s->q_free); - } else { - cx18_enqueue(s, mdl, &s->q_full); - } - } else { - cx18_enqueue(s, mdl, &s->q_full); - if (s->type == CX18_ENC_STREAM_TYPE_IDX) - cx18_stream_rotate_idx_mdls(cx); - } - } - /* Put as many MDLs as possible back into fw use */ - cx18_stream_load_fw_queue(s); - - wake_up(&cx->dma_waitq); - if (s->id != -1) - wake_up(&s->waitq); -} - -static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order) -{ - char *p; - char *str = order->str; - - CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str); - p = strchr(str, '.'); - if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) - CX18_INFO("FW version: %s\n", p - 1); -} - -static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order) -{ - switch (order->rpu) { - case CPU: - { - switch (order->mb.cmd) { - case CX18_EPU_DMA_DONE: - epu_dma_done(cx, order); - break; - case CX18_EPU_DEBUG: - epu_debug(cx, order); - break; - default: - CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - } - break; - } - case APU: - CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - default: - break; - } -} - -static -void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order) -{ - atomic_set(&order->pending, 0); -} - -void cx18_in_work_handler(struct work_struct *work) -{ - struct cx18_in_work_order *order = - container_of(work, struct cx18_in_work_order, work); - struct cx18 *cx = order->cx; - epu_cmd(cx, order); - free_in_work_order(cx, order); -} - - -/* - * Functions that run in an interrupt handling context - */ - -static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - struct cx18_mailbox __iomem *ack_mb; - u32 ack_irq, req; - - switch (order->rpu) { - case APU: - ack_irq = IRQ_EPU_TO_APU_ACK; - ack_mb = &cx->scb->apu2epu_mb; - break; - case CPU: - ack_irq = IRQ_EPU_TO_CPU_ACK; - ack_mb = &cx->scb->cpu2epu_mb; - break; - default: - CX18_WARN("Unhandled RPU (%d) for command %x ack\n", - order->rpu, order->mb.cmd); - return; - } - - req = order->mb.request; - /* Don't ack if the RPU has gotten impatient and timed us out */ - if (req != cx18_readl(cx, &ack_mb->request) || - req == cx18_readl(cx, &ack_mb->ack)) { - CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " - "incoming %s to EPU mailbox (sequence no. %u) " - "while processing\n", - rpu_str[order->rpu], rpu_str[order->rpu], req); - order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC; - return; - } - cx18_writel(cx, req, &ack_mb->ack); - cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq); - return; -} - -static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - u32 handle, mdl_ack_offset, mdl_ack_count; - struct cx18_mailbox *mb; - - mb = &order->mb; - handle = mb->args[0]; - mdl_ack_offset = mb->args[1]; - mdl_ack_count = mb->args[2]; - - if (handle == CX18_INVALID_TASK_HANDLE || - mdl_ack_count == 0 || mdl_ack_count > CX18_MAX_MDL_ACKS) { - if ((order->flags & CX18_F_EWO_MB_STALE) == 0) - mb_ack_irq(cx, order); - return -1; - } - - cx18_memcpy_fromio(cx, order->mdl_ack, cx->enc_mem + mdl_ack_offset, - sizeof(struct cx18_mdl_ack) * mdl_ack_count); - - if ((order->flags & CX18_F_EWO_MB_STALE) == 0) - mb_ack_irq(cx, order); - return 1; -} - -static -int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - u32 str_offset; - char *str = order->str; - - str[0] = '\0'; - str_offset = order->mb.args[1]; - if (str_offset) { - cx18_setup_page(cx, str_offset); - cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252); - str[252] = '\0'; - cx18_setup_page(cx, SCB_OFFSET); - } - - if ((order->flags & CX18_F_EWO_MB_STALE) == 0) - mb_ack_irq(cx, order); - - return str_offset ? 1 : 0; -} - -static inline -int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - int ret = -1; - - switch (order->rpu) { - case CPU: - { - switch (order->mb.cmd) { - case CX18_EPU_DMA_DONE: - ret = epu_dma_done_irq(cx, order); - break; - case CX18_EPU_DEBUG: - ret = epu_debug_irq(cx, order); - break; - default: - CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - } - break; - } - case APU: - CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - default: - break; - } - return ret; -} - -static inline -struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx) -{ - int i; - struct cx18_in_work_order *order = NULL; - - for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { - /* - * We only need "pending" atomic to inspect its contents, - * and need not do a check and set because: - * 1. Any work handler thread only clears "pending" and only - * on one, particular work order at a time, per handler thread. - * 2. "pending" is only set here, and we're serialized because - * we're called in an IRQ handler context. - */ - if (atomic_read(&cx->in_work_order[i].pending) == 0) { - order = &cx->in_work_order[i]; - atomic_set(&order->pending, 1); - break; - } - } - return order; -} - -void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) -{ - struct cx18_mailbox __iomem *mb; - struct cx18_mailbox *order_mb; - struct cx18_in_work_order *order; - int submit; - - switch (rpu) { - case CPU: - mb = &cx->scb->cpu2epu_mb; - break; - case APU: - mb = &cx->scb->apu2epu_mb; - break; - default: - return; - } - - order = alloc_in_work_order_irq(cx); - if (order == NULL) { - CX18_WARN("Unable to find blank work order form to schedule " - "incoming mailbox command processing\n"); - return; - } - - order->flags = 0; - order->rpu = rpu; - order_mb = &order->mb; - - /* mb->cmd and mb->args[0] through mb->args[2] */ - cx18_memcpy_fromio(cx, &order_mb->cmd, &mb->cmd, 4 * sizeof(u32)); - /* mb->request and mb->ack. N.B. we want to read mb->ack last */ - cx18_memcpy_fromio(cx, &order_mb->request, &mb->request, - 2 * sizeof(u32)); - - if (order_mb->request == order_mb->ack) { - CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " - "incoming %s to EPU mailbox (sequence no. %u)" - "\n", - rpu_str[rpu], rpu_str[rpu], order_mb->request); - if (cx18_debug & CX18_DBGFLG_WARN) - dump_mb(cx, order_mb, "incoming"); - order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT; - } - - /* - * Individual EPU command processing is responsible for ack-ing - * a non-stale mailbox as soon as possible - */ - submit = epu_cmd_irq(cx, order); - if (submit > 0) { - queue_work(cx->in_work_queue, &order->work); - } -} - - -/* - * Functions called from a non-interrupt, non work_queue context - */ - -static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) -{ - const struct cx18_api_info *info = find_api_info(cmd); - u32 state, irq, req, ack, err; - struct cx18_mailbox __iomem *mb; - u32 __iomem *xpu_state; - wait_queue_head_t *waitq; - struct mutex *mb_lock; - unsigned long int t0, timeout, ret; - int i; - char argstr[MAX_MB_ARGUMENTS*11+1]; - DEFINE_WAIT(w); - - if (info == NULL) { - CX18_WARN("unknown cmd %x\n", cmd); - return -EINVAL; - } - - if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */ - if (cmd == CX18_CPU_DE_SET_MDL) { - if (cx18_debug & CX18_DBGFLG_HIGHVOL) - CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n", - info->name, cmd, - u32arr2hex(data, args, argstr)); - } else - CX18_DEBUG_API("%s\tcmd %#010x args%s\n", - info->name, cmd, - u32arr2hex(data, args, argstr)); - } - - switch (info->rpu) { - case APU: - waitq = &cx->mb_apu_waitq; - mb_lock = &cx->epu2apu_mb_lock; - irq = IRQ_EPU_TO_APU; - mb = &cx->scb->epu2apu_mb; - xpu_state = &cx->scb->apu_state; - break; - case CPU: - waitq = &cx->mb_cpu_waitq; - mb_lock = &cx->epu2cpu_mb_lock; - irq = IRQ_EPU_TO_CPU; - mb = &cx->scb->epu2cpu_mb; - xpu_state = &cx->scb->cpu_state; - break; - default: - CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); - return -EINVAL; - } - - mutex_lock(mb_lock); - /* - * Wait for an in-use mailbox to complete - * - * If the XPU is responding with Ack's, the mailbox shouldn't be in - * a busy state, since we serialize access to it on our end. - * - * If the wait for ack after sending a previous command was interrupted - * by a signal, we may get here and find a busy mailbox. After waiting, - * mark it "not busy" from our end, if the XPU hasn't ack'ed it still. - */ - state = cx18_readl(cx, xpu_state); - req = cx18_readl(cx, &mb->request); - timeout = msecs_to_jiffies(10); - ret = wait_event_timeout(*waitq, - (ack = cx18_readl(cx, &mb->ack)) == req, - timeout); - if (req != ack) { - /* waited long enough, make the mbox "not busy" from our end */ - cx18_writel(cx, req, &mb->ack); - CX18_ERR("mbox was found stuck busy when setting up for %s; " - "clearing busy and trying to proceed\n", info->name); - } else if (ret != timeout) - CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n", - jiffies_to_msecs(timeout-ret)); - - /* Build the outgoing mailbox */ - req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1; - - cx18_writel(cx, cmd, &mb->cmd); - for (i = 0; i < args; i++) - cx18_writel(cx, data[i], &mb->args[i]); - cx18_writel(cx, 0, &mb->error); - cx18_writel(cx, req, &mb->request); - cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ - - /* - * Notify the XPU and wait for it to send an Ack back - */ - timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20); - - CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", - irq, info->name); - - /* So we don't miss the wakeup, prepare to wait before notifying fw */ - prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE); - cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); - - t0 = jiffies; - ack = cx18_readl(cx, &mb->ack); - if (ack != req) { - schedule_timeout(timeout); - ret = jiffies - t0; - ack = cx18_readl(cx, &mb->ack); - } else { - ret = jiffies - t0; - } - - finish_wait(waitq, &w); - - if (req != ack) { - mutex_unlock(mb_lock); - if (ret >= timeout) { - /* Timed out */ - CX18_DEBUG_WARN("sending %s timed out waiting %d msecs " - "for RPU acknowledgement\n", - info->name, jiffies_to_msecs(ret)); - } else { - CX18_DEBUG_WARN("woken up before mailbox ack was ready " - "after submitting %s to RPU. only " - "waited %d msecs on req %u but awakened" - " with unmatched ack %u\n", - info->name, - jiffies_to_msecs(ret), - req, ack); - } - return -EINVAL; - } - - if (ret >= timeout) - CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment " - "sending %s; timed out waiting %d msecs\n", - info->name, jiffies_to_msecs(ret)); - else - CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", - jiffies_to_msecs(ret), info->name); - - /* Collect data returned by the XPU */ - for (i = 0; i < MAX_MB_ARGUMENTS; i++) - data[i] = cx18_readl(cx, &mb->args[i]); - err = cx18_readl(cx, &mb->error); - mutex_unlock(mb_lock); - - /* - * Wait for XPU to perform extra actions for the caller in some cases. - * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all MDLs - * back in a burst shortly thereafter - */ - if (info->flags & API_SLOW) - cx18_msleep_timeout(300, 0); - - if (err) - CX18_DEBUG_API("mailbox error %08x for command %s\n", err, - info->name); - return err ? -EIO : 0; -} - -int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) -{ - return cx18_api_call(cx, cmd, args, data); -} - -static int cx18_set_filter_param(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - u32 mode; - int ret; - - mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0); - ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, - s->handle, 1, mode, cx->spatial_strength); - mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0); - ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, - s->handle, 0, mode, cx->temporal_strength); - ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, - s->handle, 2, cx->filter_mode >> 2, 0); - return ret; -} - -int cx18_api_func(void *priv, u32 cmd, int in, int out, - u32 data[CX2341X_MBOX_MAX_DATA]) -{ - struct cx18_stream *s = priv; - struct cx18 *cx = s->cx; - - switch (cmd) { - case CX2341X_ENC_SET_OUTPUT_PORT: - return 0; - case CX2341X_ENC_SET_FRAME_RATE: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6, - s->handle, 0, 0, 0, 0, data[0]); - case CX2341X_ENC_SET_FRAME_SIZE: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3, - s->handle, data[1], data[0]); - case CX2341X_ENC_SET_STREAM_TYPE: - return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2, - s->handle, data[0]); - case CX2341X_ENC_SET_ASPECT_RATIO: - return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2, - s->handle, data[0]); - - case CX2341X_ENC_SET_GOP_PROPERTIES: - return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3, - s->handle, data[0], data[1]); - case CX2341X_ENC_SET_GOP_CLOSURE: - return 0; - case CX2341X_ENC_SET_AUDIO_PROPERTIES: - return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, - s->handle, data[0]); - case CX2341X_ENC_MUTE_AUDIO: - return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, - s->handle, data[0]); - case CX2341X_ENC_SET_BIT_RATE: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5, - s->handle, data[0], data[1], data[2], data[3]); - case CX2341X_ENC_MUTE_VIDEO: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, - s->handle, data[0]); - case CX2341X_ENC_SET_FRAME_DROP_RATE: - return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2, - s->handle, data[0]); - case CX2341X_ENC_MISC: - return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4, - s->handle, data[0], data[1], data[2]); - case CX2341X_ENC_SET_DNR_FILTER_MODE: - cx->filter_mode = (data[0] & 3) | (data[1] << 2); - return cx18_set_filter_param(s); - case CX2341X_ENC_SET_DNR_FILTER_PROPS: - cx->spatial_strength = data[0]; - cx->temporal_strength = data[1]; - return cx18_set_filter_param(s); - case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: - return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3, - s->handle, data[0], data[1]); - case CX2341X_ENC_SET_CORING_LEVELS: - return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5, - s->handle, data[0], data[1], data[2], data[3]); - } - CX18_WARN("Unknown cmd %x\n", cmd); - return 0; -} - -int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], - u32 cmd, int args, ...) -{ - va_list ap; - int i; - - va_start(ap, args); - for (i = 0; i < args; i++) - data[i] = va_arg(ap, u32); - va_end(ap); - return cx18_api(cx, cmd, args, data); -} - -int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...) -{ - u32 data[MAX_MB_ARGUMENTS]; - va_list ap; - int i; - - if (cx == NULL) { - CX18_ERR("cx == NULL (cmd=%x)\n", cmd); - return 0; - } - if (args > MAX_MB_ARGUMENTS) { - CX18_ERR("args too big (cmd=%x)\n", cmd); - args = MAX_MB_ARGUMENTS; - } - va_start(ap, args); - for (i = 0; i < args; i++) - data[i] = va_arg(ap, u32); - va_end(ap); - return cx18_api(cx, cmd, args, data); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-mailbox.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-mailbox.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-mailbox.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-mailbox.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* - * cx18 mailbox functions - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#ifndef _CX18_MAILBOX_H_ -#define _CX18_MAILBOX_H_ - -/* mailbox max args */ -#define MAX_MB_ARGUMENTS 6 -/* compatibility, should be same as the define in cx2341x.h */ -#define CX2341X_MBOX_MAX_DATA 16 - -#define MB_RESERVED_HANDLE_0 0 -#define MB_RESERVED_HANDLE_1 0xFFFFFFFF - -#define APU 0 -#define CPU 1 -#define EPU 2 -#define HPU 3 - -struct cx18; - -/* - * This structure is used by CPU to provide completed MDL & buffers information. - * Its structure is dictated by the layout of the SCB, required by the - * firmware, but its definition needs to be here, instead of in cx18-scb.h, - * for mailbox work order scheduling - */ -struct cx18_mdl_ack { - u32 id; /* ID of a completed MDL */ - u32 data_used; /* Total data filled in the MDL with 'id' */ -}; - -/* The cx18_mailbox struct is the mailbox structure which is used for passing - messages between processors */ -struct cx18_mailbox { - /* The sender sets a handle in 'request' after he fills the command. The - 'request' should be different than 'ack'. The sender, also, generates - an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the - receiver. */ - u32 request; - /* The receiver detects a new command when 'req' is different than 'ack'. - He sets 'ack' to the same value as 'req' to clear the command. He, also, - generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU - is the receiver. */ - u32 ack; - u32 reserved[6]; - /* 'cmd' identifies the command. The list of these commands are in - cx23418.h */ - u32 cmd; - /* Each command can have up to 6 arguments */ - u32 args[MAX_MB_ARGUMENTS]; - /* The return code can be one of the codes in the file cx23418.h. If the - command is completed successfuly, the error will be ERR_SYS_SUCCESS. - If it is pending, the code is ERR_SYS_PENDING. If it failed, the error - code would indicate the task from which the error originated and will - be one of the errors in cx23418.h. In that case, the following - applies ((error & 0xff) != 0). - If the command is pending, the return will be passed in a MB from the - receiver to the sender. 'req' will be returned in args[0] */ - u32 error; -}; - -struct cx18_stream; - -int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); -int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, - int args, ...); -int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); -int cx18_api_func(void *priv, u32 cmd, int in, int out, - u32 data[CX2341X_MBOX_MAX_DATA]); - -void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu); - -void cx18_in_work_handler(struct work_struct *work); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-queue.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-queue.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-queue.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-queue.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,443 +0,0 @@ -/* - * cx18 buffer queues - * - * Derived from ivtv-queue.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-scb.h" -#include "cx18-io.h" - -void cx18_buf_swap(struct cx18_buffer *buf) -{ - int i; - - for (i = 0; i < buf->bytesused; i += 4) - swab32s((u32 *)(buf->buf + i)); -} - -void _cx18_mdl_swap(struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - cx18_buf_swap(buf); - } -} - -void cx18_queue_init(struct cx18_queue *q) -{ - INIT_LIST_HEAD(&q->list); - atomic_set(&q->depth, 0); - q->bytesused = 0; -} - -struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, - struct cx18_queue *q, int to_front) -{ - /* clear the mdl if it is not to be enqueued to the full queue */ - if (q != &s->q_full) { - mdl->bytesused = 0; - mdl->readpos = 0; - mdl->m_flags = 0; - mdl->skipped = 0; - mdl->curr_buf = NULL; - } - - /* q_busy is restricted to a max buffer count imposed by firmware */ - if (q == &s->q_busy && - atomic_read(&q->depth) >= CX18_MAX_FW_MDLS_PER_STREAM) - q = &s->q_free; - - spin_lock(&q->lock); - - if (to_front) - list_add(&mdl->list, &q->list); /* LIFO */ - else - list_add_tail(&mdl->list, &q->list); /* FIFO */ - q->bytesused += mdl->bytesused - mdl->readpos; - atomic_inc(&q->depth); - - spin_unlock(&q->lock); - return q; -} - -struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) -{ - struct cx18_mdl *mdl = NULL; - - spin_lock(&q->lock); - if (!list_empty(&q->list)) { - mdl = list_first_entry(&q->list, struct cx18_mdl, list); - list_del_init(&mdl->list); - q->bytesused -= mdl->bytesused - mdl->readpos; - mdl->skipped = 0; - atomic_dec(&q->depth); - } - spin_unlock(&q->lock); - return mdl; -} - -static void _cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - u32 buf_size = s->buf_size; - u32 bytesused = mdl->bytesused; - - list_for_each_entry(buf, &mdl->buf_list, list) { - buf->readpos = 0; - if (bytesused >= buf_size) { - buf->bytesused = buf_size; - bytesused -= buf_size; - } else { - buf->bytesused = bytesused; - bytesused = 0; - } - cx18_buf_sync_for_cpu(s, buf); - } -} - -static inline void cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - if (list_is_singular(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, - list); - buf->bytesused = mdl->bytesused; - buf->readpos = 0; - cx18_buf_sync_for_cpu(s, buf); - } else { - _cx18_mdl_update_bufs_for_cpu(s, mdl); - } -} - -struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, - u32 bytesused) -{ - struct cx18 *cx = s->cx; - struct cx18_mdl *mdl; - struct cx18_mdl *tmp; - struct cx18_mdl *ret = NULL; - LIST_HEAD(sweep_up); - - /* - * We don't have to acquire multiple q locks here, because we are - * serialized by the single threaded work handler. - * MDLs from the firmware will thus remain in order as - * they are moved from q_busy to q_full or to the dvb ring buffer. - */ - spin_lock(&s->q_busy.lock); - list_for_each_entry_safe(mdl, tmp, &s->q_busy.list, list) { - /* - * We should find what the firmware told us is done, - * right at the front of the queue. If we don't, we likely have - * missed an mdl done message from the firmware. - * Once we skip an mdl repeatedly, relative to the size of - * q_busy, we have high confidence we've missed it. - */ - if (mdl->id != id) { - mdl->skipped++; - if (mdl->skipped >= atomic_read(&s->q_busy.depth)-1) { - /* mdl must have fallen out of rotation */ - CX18_WARN("Skipped %s, MDL %d, %d " - "times - it must have dropped out of " - "rotation\n", s->name, mdl->id, - mdl->skipped); - /* Sweep it up to put it back into rotation */ - list_move_tail(&mdl->list, &sweep_up); - atomic_dec(&s->q_busy.depth); - } - continue; - } - /* - * We pull the desired mdl off of the queue here. Something - * will have to put it back on a queue later. - */ - list_del_init(&mdl->list); - atomic_dec(&s->q_busy.depth); - ret = mdl; - break; - } - spin_unlock(&s->q_busy.lock); - - /* - * We found the mdl for which we were looking. Get it ready for - * the caller to put on q_full or in the dvb ring buffer. - */ - if (ret != NULL) { - ret->bytesused = bytesused; - ret->skipped = 0; - /* 0'ed readpos, m_flags & curr_buf when mdl went on q_busy */ - cx18_mdl_update_bufs_for_cpu(s, ret); - if (s->type != CX18_ENC_STREAM_TYPE_TS) - set_bit(CX18_F_M_NEED_SWAP, &ret->m_flags); - } - - /* Put any mdls the firmware is ignoring back into normal rotation */ - list_for_each_entry_safe(mdl, tmp, &sweep_up, list) { - list_del_init(&mdl->list); - cx18_enqueue(s, mdl, &s->q_free); - } - return ret; -} - -/* Move all mdls of a queue, while flushing the mdl */ -static void cx18_queue_flush(struct cx18_stream *s, - struct cx18_queue *q_src, struct cx18_queue *q_dst) -{ - struct cx18_mdl *mdl; - - /* It only makes sense to flush to q_free or q_idle */ - if (q_src == q_dst || q_dst == &s->q_full || q_dst == &s->q_busy) - return; - - spin_lock(&q_src->lock); - spin_lock(&q_dst->lock); - while (!list_empty(&q_src->list)) { - mdl = list_first_entry(&q_src->list, struct cx18_mdl, list); - list_move_tail(&mdl->list, &q_dst->list); - mdl->bytesused = 0; - mdl->readpos = 0; - mdl->m_flags = 0; - mdl->skipped = 0; - mdl->curr_buf = NULL; - atomic_inc(&q_dst->depth); - } - cx18_queue_init(q_src); - spin_unlock(&q_src->lock); - spin_unlock(&q_dst->lock); -} - -void cx18_flush_queues(struct cx18_stream *s) -{ - cx18_queue_flush(s, &s->q_busy, &s->q_free); - cx18_queue_flush(s, &s->q_full, &s->q_free); -} - -/* - * Note, s->buf_pool is not protected by a lock, - * the stream better not have *anything* going on when calling this - */ -void cx18_unload_queues(struct cx18_stream *s) -{ - struct cx18_queue *q_idle = &s->q_idle; - struct cx18_mdl *mdl; - struct cx18_buffer *buf; - - /* Move all MDLS to q_idle */ - cx18_queue_flush(s, &s->q_busy, q_idle); - cx18_queue_flush(s, &s->q_full, q_idle); - cx18_queue_flush(s, &s->q_free, q_idle); - - /* Reset MDL id's and move all buffers back to the stream's buf_pool */ - spin_lock(&q_idle->lock); - list_for_each_entry(mdl, &q_idle->list, list) { - while (!list_empty(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, - struct cx18_buffer, list); - list_move_tail(&buf->list, &s->buf_pool); - buf->bytesused = 0; - buf->readpos = 0; - } - mdl->id = s->mdl_base_idx; /* reset id to a "safe" value */ - /* all other mdl fields were cleared by cx18_queue_flush() */ - } - spin_unlock(&q_idle->lock); -} - -/* - * Note, s->buf_pool is not protected by a lock, - * the stream better not have *anything* going on when calling this - */ -void cx18_load_queues(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - struct cx18_mdl *mdl; - struct cx18_buffer *buf; - int mdl_id; - int i; - u32 partial_buf_size; - - /* - * Attach buffers to MDLs, give the MDLs ids, and add MDLs to q_free - * Excess MDLs are left on q_idle - * Excess buffers are left in buf_pool and/or on an MDL in q_idle - */ - mdl_id = s->mdl_base_idx; - for (mdl = cx18_dequeue(s, &s->q_idle), i = s->bufs_per_mdl; - mdl != NULL && i == s->bufs_per_mdl; - mdl = cx18_dequeue(s, &s->q_idle)) { - - mdl->id = mdl_id; - - for (i = 0; i < s->bufs_per_mdl; i++) { - if (list_empty(&s->buf_pool)) - break; - - buf = list_first_entry(&s->buf_pool, struct cx18_buffer, - list); - list_move_tail(&buf->list, &mdl->buf_list); - - /* update the firmware's MDL array with this buffer */ - cx18_writel(cx, buf->dma_handle, - &cx->scb->cpu_mdl[mdl_id + i].paddr); - cx18_writel(cx, s->buf_size, - &cx->scb->cpu_mdl[mdl_id + i].length); - } - - if (i == s->bufs_per_mdl) { - /* - * The encoder doesn't honor s->mdl_size. So in the - * case of a non-integral number of buffers to meet - * mdl_size, we lie about the size of the last buffer - * in the MDL to get the encoder to really only send - * us mdl_size bytes per MDL transfer. - */ - partial_buf_size = s->mdl_size % s->buf_size; - if (partial_buf_size) { - cx18_writel(cx, partial_buf_size, - &cx->scb->cpu_mdl[mdl_id + i - 1].length); - } - cx18_enqueue(s, mdl, &s->q_free); - } else { - /* Not enough buffers for this MDL; we won't use it */ - cx18_push(s, mdl, &s->q_idle); - } - mdl_id += i; - } -} - -void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl) -{ - int dma = s->dma; - u32 buf_size = s->buf_size; - struct pci_dev *pci_dev = s->cx->pci_dev; - struct cx18_buffer *buf; - - list_for_each_entry(buf, &mdl->buf_list, list) - pci_dma_sync_single_for_device(pci_dev, buf->dma_handle, - buf_size, dma); -} - -int cx18_stream_alloc(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - int i; - - if (s->buffers == 0) - return 0; - - CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers " - "(%d.%02d kB total)\n", - s->name, s->buffers, s->buf_size, - s->buffers * s->buf_size / 1024, - (s->buffers * s->buf_size * 100 / 1024) % 100); - - if (((char __iomem *)&cx->scb->cpu_mdl[cx->free_mdl_idx + s->buffers] - - (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) { - unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE - - ((char __iomem *)cx->scb->cpu_mdl)); - - CX18_ERR("Too many buffers, cannot fit in SCB area\n"); - CX18_ERR("Max buffers = %zd\n", - bufsz / sizeof(struct cx18_mdl_ent)); - return -ENOMEM; - } - - s->mdl_base_idx = cx->free_mdl_idx; - - /* allocate stream buffers and MDLs */ - for (i = 0; i < s->buffers; i++) { - struct cx18_mdl *mdl; - struct cx18_buffer *buf; - - /* 1 MDL per buffer to handle the worst & also default case */ - mdl = kzalloc(sizeof(struct cx18_mdl), GFP_KERNEL|__GFP_NOWARN); - if (mdl == NULL) - break; - - buf = kzalloc(sizeof(struct cx18_buffer), - GFP_KERNEL|__GFP_NOWARN); - if (buf == NULL) { - kfree(mdl); - break; - } - - buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN); - if (buf->buf == NULL) { - kfree(mdl); - kfree(buf); - break; - } - - INIT_LIST_HEAD(&mdl->list); - INIT_LIST_HEAD(&mdl->buf_list); - mdl->id = s->mdl_base_idx; /* a somewhat safe value */ - cx18_enqueue(s, mdl, &s->q_idle); - - INIT_LIST_HEAD(&buf->list); - buf->dma_handle = pci_map_single(s->cx->pci_dev, - buf->buf, s->buf_size, s->dma); - cx18_buf_sync_for_cpu(s, buf); - list_add_tail(&buf->list, &s->buf_pool); - } - if (i == s->buffers) { - cx->free_mdl_idx += s->buffers; - return 0; - } - CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name); - cx18_stream_free(s); - return -ENOMEM; -} - -void cx18_stream_free(struct cx18_stream *s) -{ - struct cx18_mdl *mdl; - struct cx18_buffer *buf; - struct cx18 *cx = s->cx; - - CX18_DEBUG_INFO("Deallocating buffers for %s stream\n", s->name); - - /* move all buffers to buf_pool and all MDLs to q_idle */ - cx18_unload_queues(s); - - /* empty q_idle */ - while ((mdl = cx18_dequeue(s, &s->q_idle))) - kfree(mdl); - - /* empty buf_pool */ - while (!list_empty(&s->buf_pool)) { - buf = list_first_entry(&s->buf_pool, struct cx18_buffer, list); - list_del_init(&buf->list); - - pci_unmap_single(s->cx->pci_dev, buf->dma_handle, - s->buf_size, s->dma); - kfree(buf->buf); - kfree(buf); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-queue.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-queue.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-queue.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-queue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -/* - * cx18 buffer queues - * - * Derived from ivtv-queue.h - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#define CX18_DMA_UNMAPPED ((u32) -1) - -/* cx18_buffer utility functions */ - -static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, - struct cx18_buffer *buf) -{ - pci_dma_sync_single_for_cpu(s->cx->pci_dev, buf->dma_handle, - s->buf_size, s->dma); -} - -static inline void cx18_buf_sync_for_device(struct cx18_stream *s, - struct cx18_buffer *buf) -{ - pci_dma_sync_single_for_device(s->cx->pci_dev, buf->dma_handle, - s->buf_size, s->dma); -} - -void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl); - -static inline void cx18_mdl_sync_for_device(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - if (list_is_singular(&mdl->buf_list)) - cx18_buf_sync_for_device(s, list_first_entry(&mdl->buf_list, - struct cx18_buffer, - list)); - else - _cx18_mdl_sync_for_device(s, mdl); -} - -void cx18_buf_swap(struct cx18_buffer *buf); -void _cx18_mdl_swap(struct cx18_mdl *mdl); - -static inline void cx18_mdl_swap(struct cx18_mdl *mdl) -{ - if (list_is_singular(&mdl->buf_list)) - cx18_buf_swap(list_first_entry(&mdl->buf_list, - struct cx18_buffer, list)); - else - _cx18_mdl_swap(mdl); -} - -/* cx18_queue utility functions */ -struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, - struct cx18_queue *q, int to_front); - -static inline -struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, - struct cx18_queue *q) -{ - return _cx18_enqueue(s, mdl, q, 0); /* FIFO */ -} - -static inline -struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_mdl *mdl, - struct cx18_queue *q) -{ - return _cx18_enqueue(s, mdl, q, 1); /* LIFO */ -} - -void cx18_queue_init(struct cx18_queue *q); -struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); -struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, - u32 bytesused); -void cx18_flush_queues(struct cx18_stream *s); - -/* queue MDL reconfiguration helpers */ -void cx18_unload_queues(struct cx18_stream *s); -void cx18_load_queues(struct cx18_stream *s); - -/* cx18_stream utility functions */ -int cx18_stream_alloc(struct cx18_stream *s); -void cx18_stream_free(struct cx18_stream *s); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-scb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-scb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-scb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-scb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -/* - * cx18 System Control Block initialization - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-scb.h" - -void cx18_init_scb(struct cx18 *cx) -{ - cx18_setup_page(cx, SCB_OFFSET); - cx18_memset_io(cx, cx->scb, 0, 0x10000); - - cx18_writel(cx, IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq); - cx18_writel(cx, IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack); - cx18_writel(cx, IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq); - cx18_writel(cx, IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack); - cx18_writel(cx, IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq); - cx18_writel(cx, IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack); - cx18_writel(cx, IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq); - cx18_writel(cx, IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack); - - cx18_writel(cx, IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq); - cx18_writel(cx, IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack); - cx18_writel(cx, IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq); - cx18_writel(cx, IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack); - cx18_writel(cx, IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq); - cx18_writel(cx, IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack); - cx18_writel(cx, IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq); - cx18_writel(cx, IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack); - - cx18_writel(cx, IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq); - cx18_writel(cx, IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack); - cx18_writel(cx, IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq); - cx18_writel(cx, IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack); - cx18_writel(cx, IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq); - cx18_writel(cx, IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack); - cx18_writel(cx, IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq); - cx18_writel(cx, IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack); - - cx18_writel(cx, IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq); - cx18_writel(cx, IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack); - cx18_writel(cx, IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq); - cx18_writel(cx, IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack); - cx18_writel(cx, IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq); - cx18_writel(cx, IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack); - cx18_writel(cx, IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq); - cx18_writel(cx, IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack); - - cx18_writel(cx, IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq); - cx18_writel(cx, IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack); - cx18_writel(cx, IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq); - cx18_writel(cx, IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack); - cx18_writel(cx, IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq); - cx18_writel(cx, IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack); - cx18_writel(cx, IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq); - cx18_writel(cx, IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack); - - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb), - &cx->scb->apu2cpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb), - &cx->scb->hpu2cpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb), - &cx->scb->ppu2cpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb), - &cx->scb->epu2cpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb), - &cx->scb->cpu2apu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb), - &cx->scb->hpu2apu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb), - &cx->scb->ppu2apu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb), - &cx->scb->epu2apu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb), - &cx->scb->cpu2hpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb), - &cx->scb->apu2hpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb), - &cx->scb->ppu2hpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb), - &cx->scb->epu2hpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb), - &cx->scb->cpu2ppu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb), - &cx->scb->apu2ppu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb), - &cx->scb->hpu2ppu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb), - &cx->scb->epu2ppu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb), - &cx->scb->cpu2epu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb), - &cx->scb->apu2epu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb), - &cx->scb->hpu2epu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb), - &cx->scb->ppu2epu_mb_offset); - - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state), - &cx->scb->ipc_offset); - - cx18_writel(cx, 1, &cx->scb->epu_state); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-scb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-scb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-scb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-scb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,280 +0,0 @@ -/* - * cx18 System Control Block initialization - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#ifndef CX18_SCB_H -#define CX18_SCB_H - -#include "cx18-mailbox.h" - -/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts - are in the SW1 register. */ - -#define IRQ_APU_TO_CPU 0x00000001 -#define IRQ_CPU_TO_APU_ACK 0x00000001 -#define IRQ_HPU_TO_CPU 0x00000002 -#define IRQ_CPU_TO_HPU_ACK 0x00000002 -#define IRQ_PPU_TO_CPU 0x00000004 -#define IRQ_CPU_TO_PPU_ACK 0x00000004 -#define IRQ_EPU_TO_CPU 0x00000008 -#define IRQ_CPU_TO_EPU_ACK 0x00000008 - -#define IRQ_CPU_TO_APU 0x00000010 -#define IRQ_APU_TO_CPU_ACK 0x00000010 -#define IRQ_HPU_TO_APU 0x00000020 -#define IRQ_APU_TO_HPU_ACK 0x00000020 -#define IRQ_PPU_TO_APU 0x00000040 -#define IRQ_APU_TO_PPU_ACK 0x00000040 -#define IRQ_EPU_TO_APU 0x00000080 -#define IRQ_APU_TO_EPU_ACK 0x00000080 - -#define IRQ_CPU_TO_HPU 0x00000100 -#define IRQ_HPU_TO_CPU_ACK 0x00000100 -#define IRQ_APU_TO_HPU 0x00000200 -#define IRQ_HPU_TO_APU_ACK 0x00000200 -#define IRQ_PPU_TO_HPU 0x00000400 -#define IRQ_HPU_TO_PPU_ACK 0x00000400 -#define IRQ_EPU_TO_HPU 0x00000800 -#define IRQ_HPU_TO_EPU_ACK 0x00000800 - -#define IRQ_CPU_TO_PPU 0x00001000 -#define IRQ_PPU_TO_CPU_ACK 0x00001000 -#define IRQ_APU_TO_PPU 0x00002000 -#define IRQ_PPU_TO_APU_ACK 0x00002000 -#define IRQ_HPU_TO_PPU 0x00004000 -#define IRQ_PPU_TO_HPU_ACK 0x00004000 -#define IRQ_EPU_TO_PPU 0x00008000 -#define IRQ_PPU_TO_EPU_ACK 0x00008000 - -#define IRQ_CPU_TO_EPU 0x00010000 -#define IRQ_EPU_TO_CPU_ACK 0x00010000 -#define IRQ_APU_TO_EPU 0x00020000 -#define IRQ_EPU_TO_APU_ACK 0x00020000 -#define IRQ_HPU_TO_EPU 0x00040000 -#define IRQ_EPU_TO_HPU_ACK 0x00040000 -#define IRQ_PPU_TO_EPU 0x00080000 -#define IRQ_EPU_TO_PPU_ACK 0x00080000 - -#define SCB_OFFSET 0xDC0000 - -/* If Firmware uses fixed memory map, it shall not allocate the area - between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */ -#define SCB_RESERVED_SIZE 0x10000 - - -/* This structure is used by EPU to provide memory descriptors in its memory */ -struct cx18_mdl_ent { - u32 paddr; /* Physical address of a buffer segment */ - u32 length; /* Length of the buffer segment */ -}; - -struct cx18_scb { - /* These fields form the System Control Block which is used at boot time - for localizing the IPC data as well as the code positions for all - processors. The offsets are from the start of this struct. */ - - /* Offset where to find the Inter-Processor Communication data */ - u32 ipc_offset; - u32 reserved01[7]; - /* Offset where to find the start of the CPU code */ - u32 cpu_code_offset; - u32 reserved02[3]; - /* Offset where to find the start of the APU code */ - u32 apu_code_offset; - u32 reserved03[3]; - /* Offset where to find the start of the HPU code */ - u32 hpu_code_offset; - u32 reserved04[3]; - /* Offset where to find the start of the PPU code */ - u32 ppu_code_offset; - u32 reserved05[3]; - - /* These fields form Inter-Processor Communication data which is used - by all processors to locate the information needed for communicating - with other processors */ - - /* Fields for CPU: */ - - /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */ - u32 cpu_state; - u32 reserved1[7]; - /* Offset to the mailbox used for sending commands from APU to CPU */ - u32 apu2cpu_mb_offset; - /* Value to write to register SW1 register set (0xC7003100) after the - command is ready */ - u32 apu2cpu_irq; - /* Value to write to register SW2 register set (0xC7003140) after the - command is cleared */ - u32 cpu2apu_irq_ack; - u32 reserved2[13]; - - u32 hpu2cpu_mb_offset; - u32 hpu2cpu_irq; - u32 cpu2hpu_irq_ack; - u32 reserved3[13]; - - u32 ppu2cpu_mb_offset; - u32 ppu2cpu_irq; - u32 cpu2ppu_irq_ack; - u32 reserved4[13]; - - u32 epu2cpu_mb_offset; - u32 epu2cpu_irq; - u32 cpu2epu_irq_ack; - u32 reserved5[13]; - u32 reserved6[8]; - - /* Fields for APU: */ - - u32 apu_state; - u32 reserved11[7]; - u32 cpu2apu_mb_offset; - u32 cpu2apu_irq; - u32 apu2cpu_irq_ack; - u32 reserved12[13]; - - u32 hpu2apu_mb_offset; - u32 hpu2apu_irq; - u32 apu2hpu_irq_ack; - u32 reserved13[13]; - - u32 ppu2apu_mb_offset; - u32 ppu2apu_irq; - u32 apu2ppu_irq_ack; - u32 reserved14[13]; - - u32 epu2apu_mb_offset; - u32 epu2apu_irq; - u32 apu2epu_irq_ack; - u32 reserved15[13]; - u32 reserved16[8]; - - /* Fields for HPU: */ - - u32 hpu_state; - u32 reserved21[7]; - u32 cpu2hpu_mb_offset; - u32 cpu2hpu_irq; - u32 hpu2cpu_irq_ack; - u32 reserved22[13]; - - u32 apu2hpu_mb_offset; - u32 apu2hpu_irq; - u32 hpu2apu_irq_ack; - u32 reserved23[13]; - - u32 ppu2hpu_mb_offset; - u32 ppu2hpu_irq; - u32 hpu2ppu_irq_ack; - u32 reserved24[13]; - - u32 epu2hpu_mb_offset; - u32 epu2hpu_irq; - u32 hpu2epu_irq_ack; - u32 reserved25[13]; - u32 reserved26[8]; - - /* Fields for PPU: */ - - u32 ppu_state; - u32 reserved31[7]; - u32 cpu2ppu_mb_offset; - u32 cpu2ppu_irq; - u32 ppu2cpu_irq_ack; - u32 reserved32[13]; - - u32 apu2ppu_mb_offset; - u32 apu2ppu_irq; - u32 ppu2apu_irq_ack; - u32 reserved33[13]; - - u32 hpu2ppu_mb_offset; - u32 hpu2ppu_irq; - u32 ppu2hpu_irq_ack; - u32 reserved34[13]; - - u32 epu2ppu_mb_offset; - u32 epu2ppu_irq; - u32 ppu2epu_irq_ack; - u32 reserved35[13]; - u32 reserved36[8]; - - /* Fields for EPU: */ - - u32 epu_state; - u32 reserved41[7]; - u32 cpu2epu_mb_offset; - u32 cpu2epu_irq; - u32 epu2cpu_irq_ack; - u32 reserved42[13]; - - u32 apu2epu_mb_offset; - u32 apu2epu_irq; - u32 epu2apu_irq_ack; - u32 reserved43[13]; - - u32 hpu2epu_mb_offset; - u32 hpu2epu_irq; - u32 epu2hpu_irq_ack; - u32 reserved44[13]; - - u32 ppu2epu_mb_offset; - u32 ppu2epu_irq; - u32 epu2ppu_irq_ack; - u32 reserved45[13]; - u32 reserved46[8]; - - u32 semaphores[8]; /* Semaphores */ - - u32 reserved50[32]; /* Reserved for future use */ - - struct cx18_mailbox apu2cpu_mb; - struct cx18_mailbox hpu2cpu_mb; - struct cx18_mailbox ppu2cpu_mb; - struct cx18_mailbox epu2cpu_mb; - - struct cx18_mailbox cpu2apu_mb; - struct cx18_mailbox hpu2apu_mb; - struct cx18_mailbox ppu2apu_mb; - struct cx18_mailbox epu2apu_mb; - - struct cx18_mailbox cpu2hpu_mb; - struct cx18_mailbox apu2hpu_mb; - struct cx18_mailbox ppu2hpu_mb; - struct cx18_mailbox epu2hpu_mb; - - struct cx18_mailbox cpu2ppu_mb; - struct cx18_mailbox apu2ppu_mb; - struct cx18_mailbox hpu2ppu_mb; - struct cx18_mailbox epu2ppu_mb; - - struct cx18_mailbox cpu2epu_mb; - struct cx18_mailbox apu2epu_mb; - struct cx18_mailbox hpu2epu_mb; - struct cx18_mailbox ppu2epu_mb; - - struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS]; - struct cx18_mdl_ent cpu_mdl[1]; -}; - -void cx18_init_scb(struct cx18 *cx); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-streams.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-streams.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-streams.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-streams.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,867 +0,0 @@ -/* - * cx18 init/start/stop/exit stream functions - * - * Derived from ivtv-streams.c - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-fileops.h" -#include "cx18-mailbox.h" -#include "cx18-i2c.h" -#include "cx18-queue.h" -#include "cx18-ioctl.h" -#include "cx18-streams.h" -#include "cx18-cards.h" -#include "cx18-scb.h" -#include "cx18-dvb.h" - -#define CX18_DSP0_INTERRUPT_MASK 0xd0004C - -static struct v4l2_file_operations cx18_v4l2_enc_fops = { - .owner = THIS_MODULE, - .read = cx18_v4l2_read, - .open = cx18_v4l2_open, - /* FIXME change to video_ioctl2 if serialization lock can be removed */ - .unlocked_ioctl = cx18_v4l2_ioctl, - .release = cx18_v4l2_close, - .poll = cx18_v4l2_enc_poll, -}; - -/* offset from 0 to register ts v4l2 minors on */ -#define CX18_V4L2_ENC_TS_OFFSET 16 -/* offset from 0 to register pcm v4l2 minors on */ -#define CX18_V4L2_ENC_PCM_OFFSET 24 -/* offset from 0 to register yuv v4l2 minors on */ -#define CX18_V4L2_ENC_YUV_OFFSET 32 - -static struct { - const char *name; - int vfl_type; - int num_offset; - int dma; - enum v4l2_buf_type buf_type; -} cx18_stream_info[] = { - { /* CX18_ENC_STREAM_TYPE_MPG */ - "encoder MPEG", - VFL_TYPE_GRABBER, 0, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_TS */ - "TS", - VFL_TYPE_GRABBER, -1, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_YUV */ - "encoder YUV", - VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_VBI */ - "encoder VBI", - VFL_TYPE_VBI, 0, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_PCM */ - "encoder PCM audio", - VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE, - }, - { /* CX18_ENC_STREAM_TYPE_IDX */ - "encoder IDX", - VFL_TYPE_GRABBER, -1, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_RAD */ - "encoder radio", - VFL_TYPE_RADIO, 0, - PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE, - }, -}; - -static void cx18_stream_init(struct cx18 *cx, int type) -{ - struct cx18_stream *s = &cx->streams[type]; - struct video_device *video_dev = s->video_dev; - - /* we need to keep video_dev, so restore it afterwards */ - memset(s, 0, sizeof(*s)); - s->video_dev = video_dev; - - /* initialize cx18_stream fields */ - s->dvb = NULL; - s->cx = cx; - s->type = type; - s->name = cx18_stream_info[type].name; - s->handle = CX18_INVALID_TASK_HANDLE; - - s->dma = cx18_stream_info[type].dma; - s->buffers = cx->stream_buffers[type]; - s->buf_size = cx->stream_buf_size[type]; - INIT_LIST_HEAD(&s->buf_pool); - s->bufs_per_mdl = 1; - s->mdl_size = s->buf_size * s->bufs_per_mdl; - - init_waitqueue_head(&s->waitq); - s->id = -1; - spin_lock_init(&s->q_free.lock); - cx18_queue_init(&s->q_free); - spin_lock_init(&s->q_busy.lock); - cx18_queue_init(&s->q_busy); - spin_lock_init(&s->q_full.lock); - cx18_queue_init(&s->q_full); - spin_lock_init(&s->q_idle.lock); - cx18_queue_init(&s->q_idle); - - INIT_WORK(&s->out_work_order, cx18_out_work_handler); -} - -static int cx18_prep_dev(struct cx18 *cx, int type) -{ - struct cx18_stream *s = &cx->streams[type]; - u32 cap = cx->v4l2_cap; - int num_offset = cx18_stream_info[type].num_offset; - int num = cx->instance + cx18_first_minor + num_offset; - - /* - * These five fields are always initialized. - * For analog capture related streams, if video_dev == NULL then the - * stream is not in use. - * For the TS stream, if dvb == NULL then the stream is not in use. - * In those cases no other fields but these four can be used. - */ - s->video_dev = NULL; - s->dvb = NULL; - s->cx = cx; - s->type = type; - s->name = cx18_stream_info[type].name; - - /* Check whether the radio is supported */ - if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO)) - return 0; - - /* Check whether VBI is supported */ - if (type == CX18_ENC_STREAM_TYPE_VBI && - !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) - return 0; - - /* User explicitly selected 0 buffers for these streams, so don't - create them. */ - if (cx18_stream_info[type].dma != PCI_DMA_NONE && - cx->stream_buffers[type] == 0) { - CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); - return 0; - } - - cx18_stream_init(cx, type); - - /* Allocate the cx18_dvb struct only for the TS on cards with DTV */ - if (type == CX18_ENC_STREAM_TYPE_TS) { - if (cx->card->hw_all & CX18_HW_DVB) { - s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL); - if (s->dvb == NULL) { - CX18_ERR("Couldn't allocate cx18_dvb structure" - " for %s\n", s->name); - return -ENOMEM; - } - } else { - /* Don't need buffers for the TS, if there is no DVB */ - s->buffers = 0; - } - } - - if (num_offset == -1) - return 0; - - /* allocate and initialize the v4l2 video device structure */ - s->video_dev = video_device_alloc(); - if (s->video_dev == NULL) { - CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", - s->name); - return -ENOMEM; - } - - snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s", - cx->v4l2_dev.name, s->name); - - s->video_dev->num = num; - s->video_dev->v4l2_dev = &cx->v4l2_dev; - s->video_dev->fops = &cx18_v4l2_enc_fops; - s->video_dev->release = video_device_release; - s->video_dev->tvnorms = V4L2_STD_ALL; - set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags); - cx18_set_funcs(s->video_dev); - return 0; -} - -/* Initialize v4l2 variables and register v4l2 devices */ -int cx18_streams_setup(struct cx18 *cx) -{ - int type, ret; - - /* Setup V4L2 Devices */ - for (type = 0; type < CX18_MAX_STREAMS; type++) { - /* Prepare device */ - ret = cx18_prep_dev(cx, type); - if (ret < 0) - break; - - /* Allocate Stream */ - ret = cx18_stream_alloc(&cx->streams[type]); - if (ret < 0) - break; - } - if (type == CX18_MAX_STREAMS) - return 0; - - /* One or more streams could not be initialized. Clean 'em all up. */ - cx18_streams_cleanup(cx, 0); - return ret; -} - -static int cx18_reg_dev(struct cx18 *cx, int type) -{ - struct cx18_stream *s = &cx->streams[type]; - int vfl_type = cx18_stream_info[type].vfl_type; - const char *name; - int num, ret; - - if (type == CX18_ENC_STREAM_TYPE_TS && s->dvb != NULL) { - ret = cx18_dvb_register(s); - if (ret < 0) { - CX18_ERR("DVB failed to register\n"); - return ret; - } - } - - if (s->video_dev == NULL) - return 0; - - num = s->video_dev->num; - /* card number + user defined offset + device offset */ - if (type != CX18_ENC_STREAM_TYPE_MPG) { - struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; - - if (s_mpg->video_dev) - num = s_mpg->video_dev->num - + cx18_stream_info[type].num_offset; - } - video_set_drvdata(s->video_dev, s); - - /* Register device. First try the desired minor, then any free one. */ - ret = video_register_device_no_warn(s->video_dev, vfl_type, num); - if (ret < 0) { - CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", - s->name, num); - video_device_release(s->video_dev); - s->video_dev = NULL; - return ret; - } - - name = video_device_node_name(s->video_dev); - - switch (vfl_type) { - case VFL_TYPE_GRABBER: - CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n", - name, s->name, cx->stream_buffers[type], - cx->stream_buf_size[type] / 1024, - (cx->stream_buf_size[type] * 100 / 1024) % 100); - break; - - case VFL_TYPE_RADIO: - CX18_INFO("Registered device %s for %s\n", name, s->name); - break; - - case VFL_TYPE_VBI: - if (cx->stream_buffers[type]) - CX18_INFO("Registered device %s for %s " - "(%d x %d bytes)\n", - name, s->name, cx->stream_buffers[type], - cx->stream_buf_size[type]); - else - CX18_INFO("Registered device %s for %s\n", - name, s->name); - break; - } - - return 0; -} - -/* Register v4l2 devices */ -int cx18_streams_register(struct cx18 *cx) -{ - int type; - int err; - int ret = 0; - - /* Register V4L2 devices */ - for (type = 0; type < CX18_MAX_STREAMS; type++) { - err = cx18_reg_dev(cx, type); - if (err && ret == 0) - ret = err; - } - - if (ret == 0) - return 0; - - /* One or more streams could not be initialized. Clean 'em all up. */ - cx18_streams_cleanup(cx, 1); - return ret; -} - -/* Unregister v4l2 devices */ -void cx18_streams_cleanup(struct cx18 *cx, int unregister) -{ - struct video_device *vdev; - int type; - - /* Teardown all streams */ - for (type = 0; type < CX18_MAX_STREAMS; type++) { - - /* The TS has a cx18_dvb structure, not a video_device */ - if (type == CX18_ENC_STREAM_TYPE_TS) { - if (cx->streams[type].dvb != NULL) { - if (unregister) - cx18_dvb_unregister(&cx->streams[type]); - kfree(cx->streams[type].dvb); - cx->streams[type].dvb = NULL; - cx18_stream_free(&cx->streams[type]); - } - continue; - } - - /* No struct video_device, but can have buffers allocated */ - if (type == CX18_ENC_STREAM_TYPE_IDX) { - if (cx->stream_buffers[type] != 0) { - cx->stream_buffers[type] = 0; - cx18_stream_free(&cx->streams[type]); - } - continue; - } - - /* If struct video_device exists, can have buffers allocated */ - vdev = cx->streams[type].video_dev; - - cx->streams[type].video_dev = NULL; - if (vdev == NULL) - continue; - - cx18_stream_free(&cx->streams[type]); - - /* Unregister or release device */ - if (unregister) - video_unregister_device(vdev); - else - video_device_release(vdev); - } -} - -static void cx18_vbi_setup(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - int raw = cx18_raw_vbi(cx); - u32 data[CX2341X_MBOX_MAX_DATA]; - int lines; - - if (cx->is_60hz) { - cx->vbi.count = 12; - cx->vbi.start[0] = 10; - cx->vbi.start[1] = 273; - } else { /* PAL/SECAM */ - cx->vbi.count = 18; - cx->vbi.start[0] = 6; - cx->vbi.start[1] = 318; - } - - /* setup VBI registers */ - if (raw) - v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &cx->vbi.in.fmt.vbi); - else - v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &cx->vbi.in.fmt.sliced); - - /* - * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw - * VBI when the first analog capture channel starts, as once it starts - * (e.g. MPEG), we can't effect any change in the Encoder Raw VBI setup - * (i.e. for the VBI capture channels). We also send it for each - * analog capture channel anyway just to make sure we get the proper - * behavior - */ - if (raw) { - lines = cx->vbi.count * 2; - } else { - /* - * For 525/60 systems, according to the VIP 2 & BT.656 std: - * The EAV RP code's Field bit toggles on line 4, a few lines - * after the Vertcal Blank bit has already toggled. - * Tell the encoder to capture 21-4+1=18 lines per field, - * since we want lines 10 through 21. - * - * For 625/50 systems, according to the VIP 2 & BT.656 std: - * The EAV RP code's Field bit toggles on line 1, a few lines - * after the Vertcal Blank bit has already toggled. - * (We've actually set the digitizer so that the Field bit - * toggles on line 2.) Tell the encoder to capture 23-2+1=22 - * lines per field, since we want lines 6 through 23. - */ - lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2; - } - - data[0] = s->handle; - /* Lines per field */ - data[1] = (lines / 2) | ((lines / 2) << 16); - /* bytes per line */ - data[2] = (raw ? vbi_active_samples - : (cx->is_60hz ? vbi_hblank_samples_60Hz - : vbi_hblank_samples_50Hz)); - /* Every X number of frames a VBI interrupt arrives - (frames as in 25 or 30 fps) */ - data[3] = 1; - /* - * Set the SAV/EAV RP codes to look for as start/stop points - * when in VIP-1.1 mode - */ - if (raw) { - /* - * Start codes for beginning of "active" line in vertical blank - * 0x20 ( VerticalBlank ) - * 0x60 ( EvenField VerticalBlank ) - */ - data[4] = 0x20602060; - /* - * End codes for end of "active" raw lines and regular lines - * 0x30 ( VerticalBlank HorizontalBlank) - * 0x70 ( EvenField VerticalBlank HorizontalBlank) - * 0x90 (Task HorizontalBlank) - * 0xd0 (Task EvenField HorizontalBlank) - */ - data[5] = 0x307090d0; - } else { - /* - * End codes for active video, we want data in the hblank region - * 0xb0 (Task 0 VerticalBlank HorizontalBlank) - * 0xf0 (Task EvenField VerticalBlank HorizontalBlank) - * - * Since the V bit is only allowed to toggle in the EAV RP code, - * just before the first active region line, these two - * are problematic: - * 0x90 (Task HorizontalBlank) - * 0xd0 (Task EvenField HorizontalBlank) - * - * We have set the digitzer such that we don't have to worry - * about these problem codes. - */ - data[4] = 0xB0F0B0F0; - /* - * Start codes for beginning of active line in vertical blank - * 0xa0 (Task VerticalBlank ) - * 0xe0 (Task EvenField VerticalBlank ) - */ - data[5] = 0xA0E0A0E0; - } - - CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n", - data[0], data[1], data[2], data[3], data[4], data[5]); - - cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); -} - -void cx18_stream_rotate_idx_mdls(struct cx18 *cx) -{ - struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - struct cx18_mdl *mdl; - - if (!cx18_stream_enabled(s)) - return; - - /* Return if the firmware is not running low on MDLs */ - if ((atomic_read(&s->q_free.depth) + atomic_read(&s->q_busy.depth)) >= - CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN) - return; - - /* Return if there are no MDLs to rotate back to the firmware */ - if (atomic_read(&s->q_full.depth) < 2) - return; - - /* - * Take the oldest IDX MDL still holding data, and discard its index - * entries by scheduling the MDL to go back to the firmware - */ - mdl = cx18_dequeue(s, &s->q_full); - if (mdl != NULL) - cx18_enqueue(s, mdl, &s->q_free); -} - -static -struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18 *cx = s->cx; - struct cx18_queue *q; - - /* Don't give it to the firmware, if we're not running a capture */ - if (s->handle == CX18_INVALID_TASK_HANDLE || - test_bit(CX18_F_S_STOPPING, &s->s_flags) || - !test_bit(CX18_F_S_STREAMING, &s->s_flags)) - return cx18_enqueue(s, mdl, &s->q_free); - - q = cx18_enqueue(s, mdl, &s->q_busy); - if (q != &s->q_busy) - return q; /* The firmware has the max MDLs it can handle */ - - cx18_mdl_sync_for_device(s, mdl); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem, - s->bufs_per_mdl, mdl->id, s->mdl_size); - return q; -} - -static -void _cx18_stream_load_fw_queue(struct cx18_stream *s) -{ - struct cx18_queue *q; - struct cx18_mdl *mdl; - - if (atomic_read(&s->q_free.depth) == 0 || - atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM) - return; - - /* Move from q_free to q_busy notifying the firmware, until the limit */ - do { - mdl = cx18_dequeue(s, &s->q_free); - if (mdl == NULL) - break; - q = _cx18_stream_put_mdl_fw(s, mdl); - } while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM - && q == &s->q_busy); -} - -void cx18_out_work_handler(struct work_struct *work) -{ - struct cx18_stream *s = - container_of(work, struct cx18_stream, out_work_order); - - _cx18_stream_load_fw_queue(s); -} - -static void cx18_stream_configure_mdls(struct cx18_stream *s) -{ - cx18_unload_queues(s); - - switch (s->type) { - case CX18_ENC_STREAM_TYPE_YUV: - /* - * Height should be a multiple of 32 lines. - * Set the MDL size to the exact size needed for one frame. - * Use enough buffers per MDL to cover the MDL size - */ - s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; - s->bufs_per_mdl = s->mdl_size / s->buf_size; - if (s->mdl_size % s->buf_size) - s->bufs_per_mdl++; - break; - case CX18_ENC_STREAM_TYPE_VBI: - s->bufs_per_mdl = 1; - if (cx18_raw_vbi(s->cx)) { - s->mdl_size = (s->cx->is_60hz ? 12 : 18) - * 2 * vbi_active_samples; - } else { - /* - * See comment in cx18_vbi_setup() below about the - * extra lines we capture in sliced VBI mode due to - * the lines on which EAV RP codes toggle. - */ - s->mdl_size = s->cx->is_60hz - ? (21 - 4 + 1) * 2 * vbi_hblank_samples_60Hz - : (23 - 2 + 1) * 2 * vbi_hblank_samples_50Hz; - } - break; - default: - s->bufs_per_mdl = 1; - s->mdl_size = s->buf_size * s->bufs_per_mdl; - break; - } - - cx18_load_queues(s); -} - -int cx18_start_v4l2_encode_stream(struct cx18_stream *s) -{ - u32 data[MAX_MB_ARGUMENTS]; - struct cx18 *cx = s->cx; - int captype = 0; - struct cx18_stream *s_idx; - - if (!cx18_stream_enabled(s)) - return -EINVAL; - - CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); - - switch (s->type) { - case CX18_ENC_STREAM_TYPE_MPG: - captype = CAPTURE_CHANNEL_TYPE_MPEG; - cx->mpg_data_received = cx->vbi_data_inserted = 0; - cx->dualwatch_jiffies = jiffies; - cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); - cx->search_pack_header = 0; - break; - - case CX18_ENC_STREAM_TYPE_IDX: - captype = CAPTURE_CHANNEL_TYPE_INDEX; - break; - case CX18_ENC_STREAM_TYPE_TS: - captype = CAPTURE_CHANNEL_TYPE_TS; - break; - case CX18_ENC_STREAM_TYPE_YUV: - captype = CAPTURE_CHANNEL_TYPE_YUV; - break; - case CX18_ENC_STREAM_TYPE_PCM: - captype = CAPTURE_CHANNEL_TYPE_PCM; - break; - case CX18_ENC_STREAM_TYPE_VBI: -#ifdef CX18_ENCODER_PARSES_SLICED - captype = cx18_raw_vbi(cx) ? - CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; -#else - /* - * Currently we set things up so that Sliced VBI from the - * digitizer is handled as Raw VBI by the encoder - */ - captype = CAPTURE_CHANNEL_TYPE_VBI; -#endif - cx->vbi.frame = 0; - cx->vbi.inserted_frame = 0; - memset(cx->vbi.sliced_mpeg_size, - 0, sizeof(cx->vbi.sliced_mpeg_size)); - break; - default: - return -EINVAL; - } - - /* Clear Streamoff flags in case left from last capture */ - clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); - - cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); - s->handle = data[0]; - cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); - - /* - * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and - * set up all the parameters, as it is not obvious which parameters the - * firmware shares across capture channel types and which it does not. - * - * Some of the cx18_vapi() calls below apply to only certain capture - * channel types. We're hoping there's no harm in calling most of them - * anyway, as long as the values are all consistent. Setting some - * shared parameters will have no effect once an analog capture channel - * has started streaming. - */ - if (captype != CAPTURE_CHANNEL_TYPE_TS) { - cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); - - /* - * Audio related reset according to - * Documentation/video4linux/cx2341x/fw-encoder-api.txt - */ - if (atomic_read(&cx->ana_capturing) == 0) - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, - s->handle, 12); - - /* - * Number of lines for Field 1 & Field 2 according to - * Documentation/video4linux/cx2341x/fw-encoder-api.txt - * Field 1 is 312 for 625 line systems in BT.656 - * Field 2 is 313 for 625 line systems in BT.656 - */ - cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, - s->handle, 312, 313); - - if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) - cx18_vbi_setup(s); - - /* - * Select to receive I, P, and B frame index entries, if the - * index stream is enabled. Otherwise disable index entry - * generation. - */ - s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2, - s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); - - /* Call out to the common CX2341x API setup for user controls */ - cx->cxhdl.priv = s; - cx2341x_handler_setup(&cx->cxhdl); - - /* - * When starting a capture and we're set for radio, - * ensure the video is muted, despite the user control. - */ - if (!cx->cxhdl.video_mute && - test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) - cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, - (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); - } - - if (atomic_read(&cx->tot_capturing) == 0) { - cx2341x_handler_set_busy(&cx->cxhdl, 1); - clear_bit(CX18_F_I_EOS, &cx->i_flags); - cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); - } - - cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, - (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, - (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); - - /* Init all the cpu_mdls for this stream */ - cx18_stream_configure_mdls(s); - _cx18_stream_load_fw_queue(s); - - /* begin_capture */ - if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { - CX18_DEBUG_WARN("Error starting capture!\n"); - /* Ensure we're really not capturing before releasing MDLs */ - set_bit(CX18_F_S_STOPPING, &s->s_flags); - if (s->type == CX18_ENC_STREAM_TYPE_MPG) - cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); - else - cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); - clear_bit(CX18_F_S_STREAMING, &s->s_flags); - /* FIXME - CX18_F_S_STREAMOFF as well? */ - cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); - cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); - s->handle = CX18_INVALID_TASK_HANDLE; - clear_bit(CX18_F_S_STOPPING, &s->s_flags); - if (atomic_read(&cx->tot_capturing) == 0) { - set_bit(CX18_F_I_EOS, &cx->i_flags); - cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); - } - return -EINVAL; - } - - /* you're live! sit back and await interrupts :) */ - if (captype != CAPTURE_CHANNEL_TYPE_TS) - atomic_inc(&cx->ana_capturing); - atomic_inc(&cx->tot_capturing); - return 0; -} -EXPORT_SYMBOL(cx18_start_v4l2_encode_stream); - -void cx18_stop_all_captures(struct cx18 *cx) -{ - int i; - - for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) { - struct cx18_stream *s = &cx->streams[i]; - - if (!cx18_stream_enabled(s)) - continue; - if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) - cx18_stop_v4l2_encode_stream(s, 0); - } -} - -int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) -{ - struct cx18 *cx = s->cx; - unsigned long then; - - if (!cx18_stream_enabled(s)) - return -EINVAL; - - /* This function assumes that you are allowed to stop the capture - and that we are actually capturing */ - - CX18_DEBUG_INFO("Stop Capture\n"); - - if (atomic_read(&cx->tot_capturing) == 0) - return 0; - - set_bit(CX18_F_S_STOPPING, &s->s_flags); - if (s->type == CX18_ENC_STREAM_TYPE_MPG) - cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); - else - cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); - - then = jiffies; - - if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) { - CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); - } - - if (s->type != CX18_ENC_STREAM_TYPE_TS) - atomic_dec(&cx->ana_capturing); - atomic_dec(&cx->tot_capturing); - - /* Clear capture and no-read bits */ - clear_bit(CX18_F_S_STREAMING, &s->s_flags); - - /* Tell the CX23418 it can't use our buffers anymore */ - cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); - - cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); - s->handle = CX18_INVALID_TASK_HANDLE; - clear_bit(CX18_F_S_STOPPING, &s->s_flags); - - if (atomic_read(&cx->tot_capturing) > 0) - return 0; - - cx2341x_handler_set_busy(&cx->cxhdl, 0); - cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); - wake_up(&s->waitq); - - return 0; -} -EXPORT_SYMBOL(cx18_stop_v4l2_encode_stream); - -u32 cx18_find_handle(struct cx18 *cx) -{ - int i; - - /* find first available handle to be used for global settings */ - for (i = 0; i < CX18_MAX_STREAMS; i++) { - struct cx18_stream *s = &cx->streams[i]; - - if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) - return s->handle; - } - return CX18_INVALID_TASK_HANDLE; -} - -struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle) -{ - int i; - struct cx18_stream *s; - - if (handle == CX18_INVALID_TASK_HANDLE) - return NULL; - - for (i = 0; i < CX18_MAX_STREAMS; i++) { - s = &cx->streams[i]; - if (s->handle != handle) - continue; - if (cx18_stream_enabled(s)) - return s; - } - return NULL; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-streams.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-streams.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-streams.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-streams.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* - * cx18 init/start/stop/exit stream functions - * - * Derived from ivtv-streams.h - * - * Copyright (C) 2007 Hans Verkuil - * Copyright (C) 2008 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -u32 cx18_find_handle(struct cx18 *cx); -struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle); -int cx18_streams_setup(struct cx18 *cx); -int cx18_streams_register(struct cx18 *cx); -void cx18_streams_cleanup(struct cx18 *cx, int unregister); - -#define CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN (3) -void cx18_stream_rotate_idx_mdls(struct cx18 *cx); - -static inline bool cx18_stream_enabled(struct cx18_stream *s) -{ - return s->video_dev || - (s->dvb && s->dvb->enabled) || - (s->type == CX18_ENC_STREAM_TYPE_IDX && - s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0); -} - -/* Related to submission of mdls to firmware */ -static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) -{ - schedule_work(&s->out_work_order); -} - -static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - /* Put mdl on q_free; the out work handler will move mdl(s) to q_busy */ - cx18_enqueue(s, mdl, &s->q_free); - cx18_stream_load_fw_queue(s); -} - -void cx18_out_work_handler(struct work_struct *work); - -/* Capture related */ -int cx18_start_v4l2_encode_stream(struct cx18_stream *s); -int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); - -void cx18_stop_all_captures(struct cx18 *cx); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-vbi.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,277 +0,0 @@ -/* - * cx18 Vertical Blank Interval support functions - * - * Derived from ivtv-vbi.c - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-vbi.h" -#include "cx18-ioctl.h" -#include "cx18-queue.h" - -/* - * Raster Reference/Protection (RP) bytes, used in Start/End Active - * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start - * of VBI sample or VBI ancilliary data regions in the digitial ratser line. - * - * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0 - */ -static const u8 raw_vbi_sav_rp[2] = { 0x20, 0x60 }; /* __V_, _FV_ */ -static const u8 sliced_vbi_eav_rp[2] = { 0xb0, 0xf0 }; /* T_VH, TFVH */ - -static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) -{ - int line = 0; - int i; - u32 linemask[2] = { 0, 0 }; - unsigned short size; - static const u8 mpeg_hdr_data[] = { - /* MPEG-2 Program Pack */ - 0x00, 0x00, 0x01, 0xba, /* Prog Pack start code */ - 0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */ - 0x01, 0xd1, 0xd3, /* Mux Rate, markers */ - 0xfa, 0xff, 0xff, /* Res, Suff cnt, Stuff */ - /* MPEG-2 Private Stream 1 PES Packet */ - 0x00, 0x00, 0x01, 0xbd, /* Priv Stream 1 start */ - 0x00, 0x1a, /* length */ - 0x84, 0x80, 0x07, /* flags, hdr data len */ - 0x21, 0x00, 0x5d, 0x63, 0xa7, /* PTS, markers */ - 0xff, 0xff /* stuffing */ - }; - const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ - int idx = cx->vbi.frame % CX18_VBI_FRAMES; - u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0]; - - for (i = 0; i < lines; i++) { - struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i; - int f, l; - - if (sdata->id == 0) - continue; - - l = sdata->line - 6; - f = sdata->field; - if (f) - l += 18; - if (l < 32) - linemask[0] |= (1 << l); - else - linemask[1] |= (1 << (l - 32)); - dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id); - memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42); - line++; - } - memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); - if (line == 36) { - /* All lines are used, so there is no space for the linemask - (the max size of the VBI data is 36 * 43 + 4 bytes). - So in this case we use the magic number 'ITV0'. */ - memcpy(dst + sd, "ITV0", 4); - memcpy(dst + sd + 4, dst + sd + 12, line * 43); - size = 4 + ((43 * line + 3) & ~3); - } else { - memcpy(dst + sd, "itv0", 4); - cpu_to_le32s(&linemask[0]); - cpu_to_le32s(&linemask[1]); - memcpy(dst + sd + 4, &linemask[0], 8); - size = 12 + ((43 * line + 3) & ~3); - } - dst[4+16] = (size + 10) >> 8; - dst[5+16] = (size + 10) & 0xff; - dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); - dst[10+16] = (pts_stamp >> 22) & 0xff; - dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); - dst[12+16] = (pts_stamp >> 7) & 0xff; - dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); - cx->vbi.sliced_mpeg_size[idx] = sd + size; -} - -/* Compress raw VBI format, removes leading SAV codes and surplus space - after the frame. Returns new compressed size. */ -/* FIXME - this function ignores the input size. */ -static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size) -{ - u32 line_size = vbi_active_samples; - u32 lines = cx->vbi.count * 2; - u8 *q = buf; - u8 *p; - int i; - - /* Skip the header */ - buf += hdr_size; - - for (i = 0; i < lines; i++) { - p = buf + i * line_size; - - /* Look for SAV code */ - if (p[0] != 0xff || p[1] || p[2] || - (p[3] != raw_vbi_sav_rp[0] && - p[3] != raw_vbi_sav_rp[1])) - break; - if (i == lines - 1) { - /* last line is hdr_size bytes short - extrapolate it */ - memcpy(q, p + 4, line_size - 4 - hdr_size); - q += line_size - 4 - hdr_size; - p += line_size - hdr_size - 1; - memset(q, (int) *p, hdr_size); - } else { - memcpy(q, p + 4, line_size - 4); - q += line_size - 4; - } - } - return lines * (line_size - 4); -} - -static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size, - const u32 hdr_size) -{ - struct v4l2_decode_vbi_line vbi; - int i; - u32 line = 0; - u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz - : vbi_hblank_samples_50Hz; - - /* find the first valid line */ - for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) { - if (buf[0] == 0xff && !buf[1] && !buf[2] && - (buf[3] == sliced_vbi_eav_rp[0] || - buf[3] == sliced_vbi_eav_rp[1])) - break; - } - - /* - * The last line is short by hdr_size bytes, but for the remaining - * checks against size, we pretend that it is not, by counting the - * header bytes we knowingly skipped - */ - size -= (i - hdr_size); - if (size < line_size) - return line; - - for (i = 0; i < size / line_size; i++) { - u8 *p = buf + i * line_size; - - /* Look for EAV code */ - if (p[0] != 0xff || p[1] || p[2] || - (p[3] != sliced_vbi_eav_rp[0] && - p[3] != sliced_vbi_eav_rp[1])) - continue; - vbi.p = p + 4; - v4l2_subdev_call(cx->sd_av, vbi, decode_vbi_line, &vbi); - if (vbi.type) { - cx->vbi.sliced_data[line].id = vbi.type; - cx->vbi.sliced_data[line].field = vbi.is_second_field; - cx->vbi.sliced_data[line].line = vbi.line; - memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42); - line++; - } - } - return line; -} - -static void _cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf) -{ - /* - * The CX23418 provides a 12 byte header in its raw VBI buffers to us: - * 0x3fffffff [4 bytes of something] [4 byte presentation time stamp] - */ - struct vbi_data_hdr { - __be32 magic; - __be32 unknown; - __be32 pts; - } *hdr = (struct vbi_data_hdr *) buf->buf; - - u8 *p = (u8 *) buf->buf; - u32 size = buf->bytesused; - u32 pts; - int lines; - - /* - * The CX23418 sends us data that is 32 bit little-endian swapped, - * but we want the raw VBI bytes in the order they were in the raster - * line. This has a side effect of making the header big endian - */ - cx18_buf_swap(buf); - - /* Raw VBI data */ - if (cx18_raw_vbi(cx)) { - - size = buf->bytesused = - compress_raw_buf(cx, p, size, sizeof(struct vbi_data_hdr)); - - /* - * Hack needed for compatibility with old VBI software. - * Write the frame # at the last 4 bytes of the frame - */ - p += size - 4; - memcpy(p, &cx->vbi.frame, 4); - cx->vbi.frame++; - return; - } - - /* Sliced VBI data with data insertion */ - - pts = (be32_to_cpu(hdr->magic) == 0x3fffffff) ? be32_to_cpu(hdr->pts) - : 0; - - lines = compress_sliced_buf(cx, p, size, sizeof(struct vbi_data_hdr)); - - /* always return at least one empty line */ - if (lines == 0) { - cx->vbi.sliced_data[0].id = 0; - cx->vbi.sliced_data[0].line = 0; - cx->vbi.sliced_data[0].field = 0; - lines = 1; - } - buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]); - memcpy(p, &cx->vbi.sliced_data[0], size); - - if (cx->vbi.insert_mpeg) - copy_vbi_data(cx, lines, pts); - cx->vbi.frame++; -} - -void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, - int streamtype) -{ - struct cx18_buffer *buf; - u32 orig_used; - - if (streamtype != CX18_ENC_STREAM_TYPE_VBI) - return; - - /* - * Big assumption here: - * Every buffer hooked to the MDL's buf_list is a complete VBI frame - * that ends at the end of the buffer. - * - * To assume anything else would make the code in this file - * more complex, or require extra memcpy()'s to make the - * buffers satisfy the above assumption. It's just simpler to set - * up the encoder buffer transfers to make the assumption true. - */ - list_for_each_entry(buf, &mdl->buf_list, list) { - orig_used = buf->bytesused; - if (orig_used == 0) - break; - _cx18_process_vbi_data(cx, buf); - mdl->bytesused -= (orig_used - buf->bytesused); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-vbi.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-vbi.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-vbi.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-vbi.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -/* - * cx18 Vertical Blank Interval support functions - * - * Derived from ivtv-vbi.h - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, - int streamtype); -int cx18_used_line(struct cx18 *cx, int line, int field); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-version.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-version.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-version.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-version.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - * cx18 driver version information - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#ifndef CX18_VERSION_H -#define CX18_VERSION_H - -#define CX18_DRIVER_NAME "cx18" -#define CX18_DRIVER_VERSION_MAJOR 1 -#define CX18_DRIVER_VERSION_MINOR 4 -#define CX18_DRIVER_VERSION_PATCHLEVEL 0 - -#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) -#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ - CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-video.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/* - * cx18 video interface functions - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 "cx18-driver.h" -#include "cx18-video.h" -#include "cx18-cards.h" - -void cx18_video_set_io(struct cx18 *cx) -{ - int inp = cx->active_input; - - v4l2_subdev_call(cx->sd_av, video, s_routing, - cx->card->video_inputs[inp].video_input, 0, 0); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-video.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-video.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-video.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx18-video.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -/* - * cx18 video interface functions - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -void cx18_video_set_io(struct cx18 *cx); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx23418.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx23418.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx23418.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/cx23418.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,486 +0,0 @@ -/* - * cx18 header containing common defines. - * - * Copyright (C) 2007 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#ifndef CX23418_H -#define CX23418_H - -#include - -#define MGR_CMD_MASK 0x40000000 -/* The MSB of the command code indicates that this is the completion of a - command */ -#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000) - -/* Description: This command creates a new instance of a certain task - IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is - the processor on which the task YYY will be created - OUT[0] - Task handle. This handle is passed along with commands to - dispatch to the right instance of the task - ReturnCode - One of the ERR_SYS_... */ -#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001) - -/* Description: This command destroys an instance of a task - IN[0] - Task handle. Hanlde of the task to destroy - ReturnCode - One of the ERR_SYS_... */ -#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002) - -/* All commands for CPU have the following mask set */ -#define CPU_CMD_MASK 0x20000000 -#define CPU_CMD_MASK_DEBUG (CPU_CMD_MASK | 0x00000000) -#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000) -#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000) -#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000) - -#define EPU_CMD_MASK 0x02000000 -#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000) -#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000) - -#define APU_CMD_MASK 0x10000000 -#define APU_CMD_MASK_ACK (APU_CMD_MASK | 0x80000000) - -#define CX18_APU_ENCODING_METHOD_MPEG (0 << 28) -#define CX18_APU_ENCODING_METHOD_AC3 (1 << 28) - -/* Description: Command APU to start audio - IN[0] - audio parameters (same as CX18_CPU_SET_AUDIO_PARAMETERS?) - IN[1] - caller buffer address, or 0 - ReturnCode - ??? */ -#define CX18_APU_START (APU_CMD_MASK | 0x01) - -/* Description: Command APU to stop audio - IN[0] - encoding method to stop - ReturnCode - ??? */ -#define CX18_APU_STOP (APU_CMD_MASK | 0x02) - -/* Description: Command APU to reset the AI - ReturnCode - ??? */ -#define CX18_APU_RESETAI (APU_CMD_MASK | 0x05) - -/* Description: This command indicates that a Memory Descriptor List has been - filled with the requested channel type - IN[0] - Task handle. Handle of the task - IN[1] - Offset of the MDL_ACK from the beginning of the local DDR. - IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1] - ReturnCode - One of the ERR_DE_... */ -#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001) - -/* Something interesting happened - IN[0] - A value to log - IN[1] - An offset of a string in the MiniMe memory; - 0/zero/NULL means "I have nothing to say" */ -#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003) - -/* Reads memory/registers (32-bit) - IN[0] - Address - OUT[1] - Value */ -#define CX18_CPU_DEBUG_PEEK32 (CPU_CMD_MASK_DEBUG | 0x0003) - -/* Description: This command starts streaming with the set channel type - IN[0] - Task handle. Handle of the task to start - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002) - -/* Description: This command stops streaming with the set channel type - IN[0] - Task handle. Handle of the task to stop - IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only) - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003) - -/* Description: This command pauses streaming with the set channel type - IN[0] - Task handle. Handle of the task to pause - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007) - -/* Description: This command resumes streaming with the set channel type - IN[0] - Task handle. Handle of the task to resume - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008) - -#define CAPTURE_CHANNEL_TYPE_NONE 0 -#define CAPTURE_CHANNEL_TYPE_MPEG 1 -#define CAPTURE_CHANNEL_TYPE_INDEX 2 -#define CAPTURE_CHANNEL_TYPE_YUV 3 -#define CAPTURE_CHANNEL_TYPE_PCM 4 -#define CAPTURE_CHANNEL_TYPE_VBI 5 -#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6 -#define CAPTURE_CHANNEL_TYPE_TS 7 -#define CAPTURE_CHANNEL_TYPE_MAX 15 - -/* Description: This command sets the channel type. This can only be done - when stopped. - IN[0] - Task handle. Handle of the task to start - IN[1] - Channel Type. See Below. - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1) - -/* Description: Set stream output type - IN[0] - task handle. Handle of the task to start - IN[1] - type - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012) - -/* Description: Set video input resolution and frame rate - IN[0] - task handle - IN[1] - reserved - IN[2] - reserved - IN[3] - reserved - IN[4] - reserved - IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004) - -/* Description: Set video frame rate - IN[0] - task handle. Handle of the task to start - IN[1] - video bit rate mode - IN[2] - video average rate - IN[3] - video peak rate - IN[4] - system mux rate - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005) - -/* Description: Set video output resolution - IN[0] - task handle - IN[1] - horizontal size - IN[2] - vertical size - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006) - -/* Description: This command set filter parameters - IN[0] - Task handle. Handle of the task - IN[1] - type, 0 - temporal, 1 - spatial, 2 - median - IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic - median: 0 = disable, 1 = horizontal, 2 = vertical, - 3 = horizontal/vertical, 4 = diagonal - IN[3] - strength, temporal 0 - 31, spatial 0 - 15 - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009) - -/* Description: This command set spatial filter type - IN[0] - Task handle. - IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only, - 3 = 2D H/V separable, 4 = 2D symmetric non-separable - IN[2] - chroma type: 0 - disable, 1 = 1D horizontal - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C) - -/* Description: This command set coring levels for median filter - IN[0] - Task handle. - IN[1] - luma_high - IN[2] - luma_low - IN[3] - chroma_high - IN[4] - chroma_low - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E) - -/* Description: This command set the picture type mask for index file - IN[0] - Task handle (ignored by firmware) - IN[1] - 0 = disable index file output - 1 = output I picture - 2 = P picture - 4 = B picture - other = illegal */ -#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010) - -/* Description: Set audio parameters - IN[0] - task handle. Handle of the task to start - IN[1] - audio parameter - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011) - -/* Description: Set video mute - IN[0] - task handle. Handle of the task to start - IN[1] - bit31-24: muteYvalue - bit23-16: muteUvalue - bit15-8: muteVvalue - bit0: 1:mute, 0: unmute - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013) - -/* Description: Set audio mute - IN[0] - task handle. Handle of the task to start - IN[1] - mute/unmute - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014) - -/* Description: Set stream output type - IN[0] - task handle. Handle of the task to start - IN[1] - subType - SET_INITIAL_SCR 1 - SET_QUALITY_MODE 2 - SET_VIM_PROTECT_MODE 3 - SET_PTS_CORRECTION 4 - SET_USB_FLUSH_MODE 5 - SET_MERAQPAR_ENABLE 6 - SET_NAV_PACK_INSERTION 7 - SET_SCENE_CHANGE_ENABLE 8 - IN[2] - parameter 1 - IN[3] - parameter 2 - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015) - -/* Description: Set raw VBI parameters - IN[0] - Task handle - IN[1] - No. of input lines per field: - bit[15:0]: field 1, - bit[31:16]: field 2 - IN[2] - No. of input bytes per line - IN[3] - No. of output frames per transfer - IN[4] - start code - IN[5] - stop code - ReturnCode */ -#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016) - -/* Description: Set capture line No. - IN[0] - task handle. Handle of the task to start - IN[1] - height1 - IN[2] - height2 - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017) - -/* Description: Set copyright - IN[0] - task handle. Handle of the task to start - IN[1] - copyright - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018) - -/* Description: Set audio PID - IN[0] - task handle. Handle of the task to start - IN[1] - PID - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019) - -/* Description: Set video PID - IN[0] - task handle. Handle of the task to start - IN[1] - PID - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A) - -/* Description: Set Vertical Crop Line - IN[0] - task handle. Handle of the task to start - IN[1] - Line - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B) - -/* Description: Set COP structure - IN[0] - task handle. Handle of the task to start - IN[1] - M - IN[2] - N - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C) - -/* Description: Set Scene Change Detection - IN[0] - task handle. Handle of the task to start - IN[1] - scene change - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D) - -/* Description: Set Aspect Ratio - IN[0] - task handle. Handle of the task to start - IN[1] - AspectRatio - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E) - -/* Description: Set Skip Input Frame - IN[0] - task handle. Handle of the task to start - IN[1] - skip input frames - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F) - -/* Description: Set sliced VBI parameters - - Note This API will only apply to MPEG and Sliced VBI Channels - IN[0] - Task handle - IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext - IN[2] - start / stop line - bit[15:0] start line number - bit[31:16] stop line number - IN[3] - number of output frames per interrupt - IN[4] - VBI insertion mode - bit 0: output user data, 1 - enable - bit 1: output private stream, 1 - enable - bit 2: mux option, 0 - in GOP, 1 - in picture - bit[7:0] private stream ID - IN[5] - insertion period while mux option is in picture - ReturnCode - VBI data offset */ -#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020) - -/* Description: Set the user data place holder - IN[0] - type of data (0 for user) - IN[1] - Stuffing period - IN[2] - ID data size in word (less than 10) - IN[3] - Pointer to ID buffer */ -#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021) - - -/* Description: - In[0] Task Handle - return parameter: - Out[0] Reserved - Out[1] Video PTS bit[32:2] of last output video frame. - Out[2] Video PTS bit[ 1:0] of last output video frame. - Out[3] Hardware Video PTS counter bit[31:0], - these bits get incremented on every 90kHz clock tick. - Out[4] Hardware Video PTS counter bit32, - these bits get incremented on every 90kHz clock tick. - ReturnCode */ -#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) - -/* Below is the list of commands related to the data exchange */ -#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) - -/* Description: This command provides the physical base address of the local - DDR as viewed by EPU - IN[0] - Physical offset where EPU has the local DDR mapped - ReturnCode - One of the ERR_DE_... */ -#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001) - -/* Description: This command provides the offsets in the device memory where - the 2 cx18_mdl_ack blocks reside - IN[0] - Task handle. Handle of the task to start - IN[1] - Offset of the first cx18_mdl_ack from the beginning of the - local DDR. - IN[2] - Offset of the second cx18_mdl_ack from the beginning of the - local DDR. - ReturnCode - One of the ERR_DE_... */ -#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002) - -/* Description: This command provides the offset to a Memory Descriptor List - IN[0] - Task handle. Handle of the task to start - IN[1] - Offset of the MDL from the beginning of the local DDR. - IN[2] - Number of cx18_mdl_ent structures in the array pointed to by IN[1] - IN[3] - Buffer ID - IN[4] - Total buffer length - ReturnCode - One of the ERR_DE_... */ -#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005) - -/* Description: This command requests return of all current Memory - Descriptor Lists to the driver - IN[0] - Task handle. Handle of the task to start - ReturnCode - One of the ERR_DE_... */ -#define CX18_CPU_DE_RELEASE_MDL (CPU_CMD_MASK_DE | 0x0006) - -/* Description: This command signals the cpu that the dat buffer has been - consumed and ready for re-use. - IN[0] - Task handle. Handle of the task - IN[1] - Offset of the data block from the beginning of the local DDR. - IN[2] - Number of bytes in the data block - ReturnCode - One of the ERR_DE_... */ -/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */ - -/* No Error / Success */ -#define CNXT_OK 0x000000 - -/* Received unknown command */ -#define CXERR_UNK_CMD 0x000001 - -/* First parameter in the command is invalid */ -#define CXERR_INVALID_PARAM1 0x000002 - -/* Second parameter in the command is invalid */ -#define CXERR_INVALID_PARAM2 0x000003 - -/* Device interface is not open/found */ -#define CXERR_DEV_NOT_FOUND 0x000004 - -/* Requested function is not implemented/available */ -#define CXERR_NOTSUPPORTED 0x000005 - -/* Invalid pointer is provided */ -#define CXERR_BADPTR 0x000006 - -/* Unable to allocate memory */ -#define CXERR_NOMEM 0x000007 - -/* Object/Link not found */ -#define CXERR_LINK 0x000008 - -/* Device busy, command cannot be executed */ -#define CXERR_BUSY 0x000009 - -/* File/device/handle is not open. */ -#define CXERR_NOT_OPEN 0x00000A - -/* Value is out of range */ -#define CXERR_OUTOFRANGE 0x00000B - -/* Buffer overflow */ -#define CXERR_OVERFLOW 0x00000C - -/* Version mismatch */ -#define CXERR_BADVER 0x00000D - -/* Operation timed out */ -#define CXERR_TIMEOUT 0x00000E - -/* Operation aborted */ -#define CXERR_ABORT 0x00000F - -/* Specified I2C device not found for read/write */ -#define CXERR_I2CDEV_NOTFOUND 0x000010 - -/* Error in I2C data xfer (but I2C device is present) */ -#define CXERR_I2CDEV_XFERERR 0x000011 - -/* Chanel changing component not ready */ -#define CXERR_CHANNELNOTREADY 0x000012 - -/* PPU (Presensation/Decoder) mail box is corrupted */ -#define CXERR_PPU_MB_CORRUPT 0x000013 - -/* CPU (Capture/Encoder) mail box is corrupted */ -#define CXERR_CPU_MB_CORRUPT 0x000014 - -/* APU (Audio) mail box is corrupted */ -#define CXERR_APU_MB_CORRUPT 0x000015 - -/* Unable to open file for reading */ -#define CXERR_FILE_OPEN_READ 0x000016 - -/* Unable to open file for writing */ -#define CXERR_FILE_OPEN_WRITE 0x000017 - -/* Unable to find the I2C section specified */ -#define CXERR_I2C_BADSECTION 0x000018 - -/* Error in I2C data xfer (but I2C device is present) */ -#define CXERR_I2CDEV_DATALOW 0x000019 - -/* Error in I2C data xfer (but I2C device is present) */ -#define CXERR_I2CDEV_CLOCKLOW 0x00001A - -/* No Interrupt received from HW (for I2C access) */ -#define CXERR_NO_HW_I2C_INTR 0x00001B - -/* RPU is not ready to accept commands! */ -#define CXERR_RPU_NOT_READY 0x00001C - -/* RPU is not ready to accept commands! */ -#define CXERR_RPU_NO_ACK 0x00001D - -/* The are no buffers ready. Try again soon! */ -#define CXERR_NODATA_AGAIN 0x00001E - -/* The stream is stopping. Function not allowed now! */ -#define CXERR_STOPPING_STATUS 0x00001F - -/* Trying to access hardware when the power is turned OFF */ -#define CXERR_DEVPOWER_OFF 0x000020 - -#endif /* CX23418_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -config VIDEO_CX18 - tristate "Conexant cx23418 MPEG encoder support" - depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL - select I2C_ALGOBIT - depends on RC_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_CX2341X - select VIDEO_CS5345 - select DVB_S5H1409 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - ---help--- - This is a video4linux driver for Conexant cx23418 based - PCI combo video recorder devices. - - This is used in devices such as the Hauppauge HVR-1600 - cards. - - To compile this driver as a module, choose M here: the - module will be called cx18. - -config VIDEO_CX18_ALSA - tristate "Conexant 23418 DMA audio support" - depends on VIDEO_CX18 && SND && EXPERIMENTAL - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio on - Conexant 23418 based TV cards using ALSA. - - To compile this driver as a module, choose M here: the - module will be called cx18-alsa. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx18/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \ - cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \ - cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \ - cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \ - cx18-dvb.o cx18-io.o -cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o - -obj-$(CONFIG_VIDEO_CX18) += cx18.o -obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/common/tuners diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-417.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-417.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-417.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-417.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2192 +0,0 @@ -/* - * - * Support for a cx23417 mpeg encoder via cx231xx host port. - * - * (c) 2004 Jelle Foks - * (c) 2004 Gerd Knorr - * (c) 2008 Steven Toth - * - CX23885/7/8 support - * - * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx231xx.h" -/*#include "cx23885-ioctl.h"*/ - -#define CX231xx_FIRM_IMAGE_SIZE 376836 -#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" - -/* for polaris ITVC */ -#define ITVC_WRITE_DIR 0x03FDFC00 -#define ITVC_READ_DIR 0x0001FC00 - -#define MCI_MEMORY_DATA_BYTE0 0x00 -#define MCI_MEMORY_DATA_BYTE1 0x08 -#define MCI_MEMORY_DATA_BYTE2 0x10 -#define MCI_MEMORY_DATA_BYTE3 0x18 - -#define MCI_MEMORY_ADDRESS_BYTE2 0x20 -#define MCI_MEMORY_ADDRESS_BYTE1 0x28 -#define MCI_MEMORY_ADDRESS_BYTE0 0x30 - -#define MCI_REGISTER_DATA_BYTE0 0x40 -#define MCI_REGISTER_DATA_BYTE1 0x48 -#define MCI_REGISTER_DATA_BYTE2 0x50 -#define MCI_REGISTER_DATA_BYTE3 0x58 - -#define MCI_REGISTER_ADDRESS_BYTE0 0x60 -#define MCI_REGISTER_ADDRESS_BYTE1 0x68 - -#define MCI_REGISTER_MODE 0x70 - -/* Read and write modes for polaris ITVC */ -#define MCI_MODE_REGISTER_READ 0x000 -#define MCI_MODE_REGISTER_WRITE 0x100 -#define MCI_MODE_MEMORY_READ 0x000 -#define MCI_MODE_MEMORY_WRITE 0x4000 - -static unsigned int mpegbufs = 8; -module_param(mpegbufs, int, 0644); -MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32"); -static unsigned int mpeglines = 128; -module_param(mpeglines, int, 0644); -MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32"); -static unsigned int mpeglinesize = 512; -module_param(mpeglinesize, int, 0644); -MODULE_PARM_DESC(mpeglinesize, - "number of bytes in each line of an MPEG buffer, range 512-1024"); - -static unsigned int v4l_debug = 1; -module_param(v4l_debug, int, 0644); -MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages"); -struct cx231xx_dmaqueue *dma_qq; -#define dprintk(level, fmt, arg...)\ - do { if (v4l_debug >= level) \ - printk(KERN_INFO "%s: " fmt, \ - (dev) ? dev->name : "cx231xx[?]", ## arg); \ - } while (0) - -static struct cx231xx_tvnorm cx231xx_tvnorms[] = { - { - .name = "NTSC-M", - .id = V4L2_STD_NTSC_M, - }, { - .name = "NTSC-JP", - .id = V4L2_STD_NTSC_M_JP, - }, { - .name = "PAL-BG", - .id = V4L2_STD_PAL_BG, - }, { - .name = "PAL-DK", - .id = V4L2_STD_PAL_DK, - }, { - .name = "PAL-I", - .id = V4L2_STD_PAL_I, - }, { - .name = "PAL-M", - .id = V4L2_STD_PAL_M, - }, { - .name = "PAL-N", - .id = V4L2_STD_PAL_N, - }, { - .name = "PAL-Nc", - .id = V4L2_STD_PAL_Nc, - }, { - .name = "PAL-60", - .id = V4L2_STD_PAL_60, - }, { - .name = "SECAM-L", - .id = V4L2_STD_SECAM_L, - }, { - .name = "SECAM-DK", - .id = V4L2_STD_SECAM_DK, - } -}; - -/* ------------------------------------------------------------------ */ -enum cx231xx_capture_type { - CX231xx_MPEG_CAPTURE, - CX231xx_RAW_CAPTURE, - CX231xx_RAW_PASSTHRU_CAPTURE -}; -enum cx231xx_capture_bits { - CX231xx_RAW_BITS_NONE = 0x00, - CX231xx_RAW_BITS_YUV_CAPTURE = 0x01, - CX231xx_RAW_BITS_PCM_CAPTURE = 0x02, - CX231xx_RAW_BITS_VBI_CAPTURE = 0x04, - CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08, - CX231xx_RAW_BITS_TO_HOST_CAPTURE = 0x10 -}; -enum cx231xx_capture_end { - CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */ - CX231xx_END_NOW, /* stop immediately, no irq */ -}; -enum cx231xx_framerate { - CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */ - CX231xx_FRAMERATE_PAL_25 /* PAL: 25fps */ -}; -enum cx231xx_stream_port { - CX231xx_OUTPUT_PORT_MEMORY, - CX231xx_OUTPUT_PORT_STREAMING, - CX231xx_OUTPUT_PORT_SERIAL -}; -enum cx231xx_data_xfer_status { - CX231xx_MORE_BUFFERS_FOLLOW, - CX231xx_LAST_BUFFER, -}; -enum cx231xx_picture_mask { - CX231xx_PICTURE_MASK_NONE, - CX231xx_PICTURE_MASK_I_FRAMES, - CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3, - CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7, -}; -enum cx231xx_vbi_mode_bits { - CX231xx_VBI_BITS_SLICED, - CX231xx_VBI_BITS_RAW, -}; -enum cx231xx_vbi_insertion_bits { - CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, - CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, - CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1, - CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, - CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, -}; -enum cx231xx_dma_unit { - CX231xx_DMA_BYTES, - CX231xx_DMA_FRAMES, -}; -enum cx231xx_dma_transfer_status_bits { - CX231xx_DMA_TRANSFER_BITS_DONE = 0x01, - CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04, - CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10, -}; -enum cx231xx_pause { - CX231xx_PAUSE_ENCODING, - CX231xx_RESUME_ENCODING, -}; -enum cx231xx_copyright { - CX231xx_COPYRIGHT_OFF, - CX231xx_COPYRIGHT_ON, -}; -enum cx231xx_notification_type { - CX231xx_NOTIFICATION_REFRESH, -}; -enum cx231xx_notification_status { - CX231xx_NOTIFICATION_OFF, - CX231xx_NOTIFICATION_ON, -}; -enum cx231xx_notification_mailbox { - CX231xx_NOTIFICATION_NO_MAILBOX = -1, -}; -enum cx231xx_field1_lines { - CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */ - CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */ - CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */ -}; -enum cx231xx_field2_lines { - CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */ - CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */ - CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */ -}; -enum cx231xx_custom_data_type { - CX231xx_CUSTOM_EXTENSION_USR_DATA, - CX231xx_CUSTOM_PRIVATE_PACKET, -}; -enum cx231xx_mute { - CX231xx_UNMUTE, - CX231xx_MUTE, -}; -enum cx231xx_mute_video_mask { - CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00, - CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000, - CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000, -}; -enum cx231xx_mute_video_shift { - CX231xx_MUTE_VIDEO_V_SHIFT = 8, - CX231xx_MUTE_VIDEO_U_SHIFT = 16, - CX231xx_MUTE_VIDEO_Y_SHIFT = 24, -}; - -/* defines below are from ivtv-driver.h */ -#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF - -/* Firmware API commands */ -#define IVTV_API_STD_TIMEOUT 500 - -/* Registers */ -/* IVTV_REG_OFFSET */ -#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) -#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) -#define IVTV_REG_SPU (0x9050) -#define IVTV_REG_HW_BLOCKS (0x9054) -#define IVTV_REG_VPU (0x9058) -#define IVTV_REG_APU (0xA064) - -/* - * Bit definitions for MC417_RWD and MC417_OEN registers - * - * bits 31-16 - *+-----------+ - *| Reserved | - *|+-----------+ - *| bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 - *|+-------+-------+-------+-------+-------+-------+-------+-------+ - *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0| - *|+-------+-------+-------+-------+-------+-------+-------+-------+ - *| bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 - *|+-------+-------+-------+-------+-------+-------+-------+-------+ - *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0| - *|+-------+-------+-------+-------+-------+-------+-------+-------+ - */ -#define MC417_MIWR 0x8000 -#define MC417_MIRD 0x4000 -#define MC417_MICS 0x2000 -#define MC417_MIRDY 0x1000 -#define MC417_MIADDR 0x0F00 -#define MC417_MIDATA 0x00FF - - -/* Bit definitions for MC417_CTL register **** - *bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0 - *+--------+-------------+--------+--------------+------------+ - *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN| - *+--------+-------------+--------+--------------+------------+ - */ -#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030) -#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006) -#define MC417_UART_GPIO_EN 0x00000001 - -/* Values for speed control */ -#define MC417_SPD_CTL_SLOW 0x1 -#define MC417_SPD_CTL_MEDIUM 0x0 -#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */ - -/* Values for GPIO select */ -#define MC417_GPIO_SEL_GPIO3 0x3 -#define MC417_GPIO_SEL_GPIO2 0x2 -#define MC417_GPIO_SEL_GPIO1 0x1 -#define MC417_GPIO_SEL_GPIO0 0x0 - - -#define CX23417_GPIO_MASK 0xFC0003FF -static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value) -{ - int status = 0; - u32 _gpio_direction = 0; - - _gpio_direction = _gpio_direction & CX23417_GPIO_MASK; - _gpio_direction = _gpio_direction|gpio_direction; - status = cx231xx_send_gpio_cmd(dev, _gpio_direction, - (u8 *)&value, 4, 0, 0); - return status; -} -static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue) -{ - int status = 0; - u32 _gpio_direction = 0; - - _gpio_direction = _gpio_direction & CX23417_GPIO_MASK; - _gpio_direction = _gpio_direction|gpio_direction; - - status = cx231xx_send_gpio_cmd(dev, _gpio_direction, - (u8 *)pValue, 4, 0, 1); - return status; -} - -static int waitForMciComplete(struct cx231xx *dev) -{ - u32 gpio; - u32 gpio_driection = 0; - u8 count = 0; - getITVCReg(dev, gpio_driection, &gpio); - - while (!(gpio&0x020000)) { - msleep(10); - - getITVCReg(dev, gpio_driection, &gpio); - - if (count++ > 100) { - dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio); - return -1; - } - } - return 0; -} - -static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value) -{ - u32 temp; - int status = 0; - - temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8); - temp = temp<<10; - status = setITVCReg(dev, ITVC_WRITE_DIR, temp); - if (status < 0) - return status; - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write data byte 1;*/ - temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write data byte 2;*/ - temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write data byte 3;*/ - temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write address byte 0;*/ - temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write address byte 1;*/ - temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*Write that the mode is write.*/ - temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE; - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - return waitForMciComplete(dev); -} - -static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value) -{ - /*write address byte 0;*/ - u32 temp; - u32 return_value = 0; - int ret = 0; - - temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8); - temp = temp << 10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write address byte 1;*/ - temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00); - temp = temp << 10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write that the mode is read;*/ - temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ; - temp = temp << 10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*wait for the MIRDY line to be asserted , - signalling that the read is done;*/ - ret = waitForMciComplete(dev); - - /*switch the DATA- GPIO to input mode;*/ - - /*Read data byte 0;*/ - temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp & 0x03FC0000) >> 18); - setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); - - /* Read data byte 1;*/ - temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - - return_value |= ((temp & 0x03FC0000) >> 10); - setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); - - /*Read data byte 2;*/ - temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp & 0x03FC0000) >> 2); - setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); - - /*Read data byte 3;*/ - temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp & 0x03FC0000) << 6); - setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); - - *value = return_value; - - - return ret; -} - -static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value) -{ - /*write data byte 0;*/ - - u32 temp; - int ret = 0; - - temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8); - temp = temp << 10; - ret = setITVCReg(dev, ITVC_WRITE_DIR, temp); - if (ret < 0) - return ret; - temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write data byte 1;*/ - temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00); - temp = temp << 10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write data byte 2;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write data byte 3;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /* write address byte 2;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE | - ((address & 0x003F0000)>>8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /* write address byte 1;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /* write address byte 0;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*wait for MIRDY line;*/ - waitForMciComplete(dev); - - return 0; -} - -static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value) -{ - u32 temp = 0; - u32 return_value = 0; - int ret = 0; - - /*write address byte 2;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ | - ((address & 0x003F0000)>>8); - temp = temp<<10; - ret = setITVCReg(dev, ITVC_WRITE_DIR, temp); - if (ret < 0) - return ret; - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write address byte 1*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*write address byte 0*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); - - /*Wait for MIRDY line*/ - ret = waitForMciComplete(dev); - - - /*Read data byte 3;*/ - temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp&0x03FC0000)<<6); - setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); - - /*Read data byte 2;*/ - temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp&0x03FC0000)>>2); - setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); - - /* Read data byte 1;*/ - temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp&0x03FC0000)>>10); - setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); - - /*Read data byte 0;*/ - temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp&0x03FC0000)>>18); - setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); - - *value = return_value; - return ret; -} - -/* ------------------------------------------------------------------ */ - -/* MPEG encoder API */ -static char *cmd_to_str(int cmd) -{ - switch (cmd) { - case CX2341X_ENC_PING_FW: - return "PING_FW"; - case CX2341X_ENC_START_CAPTURE: - return "START_CAPTURE"; - case CX2341X_ENC_STOP_CAPTURE: - return "STOP_CAPTURE"; - case CX2341X_ENC_SET_AUDIO_ID: - return "SET_AUDIO_ID"; - case CX2341X_ENC_SET_VIDEO_ID: - return "SET_VIDEO_ID"; - case CX2341X_ENC_SET_PCR_ID: - return "SET_PCR_PID"; - case CX2341X_ENC_SET_FRAME_RATE: - return "SET_FRAME_RATE"; - case CX2341X_ENC_SET_FRAME_SIZE: - return "SET_FRAME_SIZE"; - case CX2341X_ENC_SET_BIT_RATE: - return "SET_BIT_RATE"; - case CX2341X_ENC_SET_GOP_PROPERTIES: - return "SET_GOP_PROPERTIES"; - case CX2341X_ENC_SET_ASPECT_RATIO: - return "SET_ASPECT_RATIO"; - case CX2341X_ENC_SET_DNR_FILTER_MODE: - return "SET_DNR_FILTER_PROPS"; - case CX2341X_ENC_SET_DNR_FILTER_PROPS: - return "SET_DNR_FILTER_PROPS"; - case CX2341X_ENC_SET_CORING_LEVELS: - return "SET_CORING_LEVELS"; - case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: - return "SET_SPATIAL_FILTER_TYPE"; - case CX2341X_ENC_SET_VBI_LINE: - return "SET_VBI_LINE"; - case CX2341X_ENC_SET_STREAM_TYPE: - return "SET_STREAM_TYPE"; - case CX2341X_ENC_SET_OUTPUT_PORT: - return "SET_OUTPUT_PORT"; - case CX2341X_ENC_SET_AUDIO_PROPERTIES: - return "SET_AUDIO_PROPERTIES"; - case CX2341X_ENC_HALT_FW: - return "HALT_FW"; - case CX2341X_ENC_GET_VERSION: - return "GET_VERSION"; - case CX2341X_ENC_SET_GOP_CLOSURE: - return "SET_GOP_CLOSURE"; - case CX2341X_ENC_GET_SEQ_END: - return "GET_SEQ_END"; - case CX2341X_ENC_SET_PGM_INDEX_INFO: - return "SET_PGM_INDEX_INFO"; - case CX2341X_ENC_SET_VBI_CONFIG: - return "SET_VBI_CONFIG"; - case CX2341X_ENC_SET_DMA_BLOCK_SIZE: - return "SET_DMA_BLOCK_SIZE"; - case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10: - return "GET_PREV_DMA_INFO_MB_10"; - case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9: - return "GET_PREV_DMA_INFO_MB_9"; - case CX2341X_ENC_SCHED_DMA_TO_HOST: - return "SCHED_DMA_TO_HOST"; - case CX2341X_ENC_INITIALIZE_INPUT: - return "INITIALIZE_INPUT"; - case CX2341X_ENC_SET_FRAME_DROP_RATE: - return "SET_FRAME_DROP_RATE"; - case CX2341X_ENC_PAUSE_ENCODER: - return "PAUSE_ENCODER"; - case CX2341X_ENC_REFRESH_INPUT: - return "REFRESH_INPUT"; - case CX2341X_ENC_SET_COPYRIGHT: - return "SET_COPYRIGHT"; - case CX2341X_ENC_SET_EVENT_NOTIFICATION: - return "SET_EVENT_NOTIFICATION"; - case CX2341X_ENC_SET_NUM_VSYNC_LINES: - return "SET_NUM_VSYNC_LINES"; - case CX2341X_ENC_SET_PLACEHOLDER: - return "SET_PLACEHOLDER"; - case CX2341X_ENC_MUTE_VIDEO: - return "MUTE_VIDEO"; - case CX2341X_ENC_MUTE_AUDIO: - return "MUTE_AUDIO"; - case CX2341X_ENC_MISC: - return "MISC"; - default: - return "UNKNOWN"; - } -} - -static int cx231xx_mbox_func(void *priv, - u32 command, - int in, - int out, - u32 data[CX2341X_MBOX_MAX_DATA]) -{ - struct cx231xx *dev = priv; - unsigned long timeout; - u32 value, flag, retval = 0; - int i; - - dprintk(3, "%s: command(0x%X) = %s\n", __func__, command, - cmd_to_str(command)); - - /* this may not be 100% safe if we can't read any memory location - without side effects */ - mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value); - if (value != 0x12345678) { - dprintk(3, - "Firmware and/or mailbox pointer not initialized " - "or corrupted, signature = 0x%x, cmd = %s\n", value, - cmd_to_str(command)); - return -1; - } - - /* This read looks at 32 bits, but flag is only 8 bits. - * Seems we also bail if CMD or TIMEOUT bytes are set??? - */ - mc417_memory_read(dev, dev->cx23417_mailbox, &flag); - if (flag) { - dprintk(3, "ERROR: Mailbox appears to be in use " - "(%x), cmd = %s\n", flag, cmd_to_str(command)); - return -1; - } - - flag |= 1; /* tell 'em we're working on it */ - mc417_memory_write(dev, dev->cx23417_mailbox, flag); - - /* write command + args + fill remaining with zeros */ - /* command code */ - mc417_memory_write(dev, dev->cx23417_mailbox + 1, command); - mc417_memory_write(dev, dev->cx23417_mailbox + 3, - IVTV_API_STD_TIMEOUT); /* timeout */ - for (i = 0; i < in; i++) { - mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]); - dprintk(3, "API Input %d = %d\n", i, data[i]); - } - for (; i < CX2341X_MBOX_MAX_DATA; i++) - mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0); - - flag |= 3; /* tell 'em we're done writing */ - mc417_memory_write(dev, dev->cx23417_mailbox, flag); - - /* wait for firmware to handle the API command */ - timeout = jiffies + msecs_to_jiffies(10); - for (;;) { - mc417_memory_read(dev, dev->cx23417_mailbox, &flag); - if (0 != (flag & 4)) - break; - if (time_after(jiffies, timeout)) { - dprintk(3, "ERROR: API Mailbox timeout\n"); - return -1; - } - udelay(10); - } - - /* read output values */ - for (i = 0; i < out; i++) { - mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i); - dprintk(3, "API Output %d = %d\n", i, data[i]); - } - - mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval); - dprintk(3, "API result = %d\n", retval); - - flag = 0; - mc417_memory_write(dev, dev->cx23417_mailbox, flag); - - return retval; -} - -/* We don't need to call the API often, so using just one - * mailbox will probably suffice - */ -static int cx231xx_api_cmd(struct cx231xx *dev, - u32 command, - u32 inputcnt, - u32 outputcnt, - ...) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - va_list vargs; - int i, err; - - dprintk(3, "%s() cmds = 0x%08x\n", __func__, command); - - va_start(vargs, outputcnt); - for (i = 0; i < inputcnt; i++) - data[i] = va_arg(vargs, int); - - err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data); - for (i = 0; i < outputcnt; i++) { - int *vptr = va_arg(vargs, int *); - *vptr = data[i]; - } - va_end(vargs); - - return err; -} - -static int cx231xx_find_mailbox(struct cx231xx *dev) -{ - u32 signature[4] = { - 0x12345678, 0x34567812, 0x56781234, 0x78123456 - }; - int signaturecnt = 0; - u32 value; - int i; - int ret = 0; - - dprintk(2, "%s()\n", __func__); - - for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/ - ret = mc417_memory_read(dev, i, &value); - if (ret < 0) - return ret; - if (value == signature[signaturecnt]) - signaturecnt++; - else - signaturecnt = 0; - if (4 == signaturecnt) { - dprintk(1, "Mailbox signature found at 0x%x\n", i+1); - return i+1; - } - } - dprintk(3, "Mailbox signature values not found!\n"); - return -1; -} - -static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value, - u32 *p_fw_image) -{ - - u32 temp = 0; - int i = 0; - - temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8); - temp = temp<<10; - *p_fw_image = temp; - p_fw_image++; - temp = temp|((0x05)<<10); - *p_fw_image = temp; - p_fw_image++; - - /*write data byte 1;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00); - temp = temp<<10; - *p_fw_image = temp; - p_fw_image++; - temp = temp|((0x05)<<10); - *p_fw_image = temp; - p_fw_image++; - - /*write data byte 2;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8); - temp = temp<<10; - *p_fw_image = temp; - p_fw_image++; - temp = temp|((0x05)<<10); - *p_fw_image = temp; - p_fw_image++; - - /*write data byte 3;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16); - temp = temp<<10; - *p_fw_image = temp; - p_fw_image++; - temp = temp|((0x05)<<10); - *p_fw_image = temp; - p_fw_image++; - - /* write address byte 2;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE | - ((address & 0x003F0000)>>8); - temp = temp<<10; - *p_fw_image = temp; - p_fw_image++; - temp = temp|((0x05)<<10); - *p_fw_image = temp; - p_fw_image++; - - /* write address byte 1;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); - temp = temp<<10; - *p_fw_image = temp; - p_fw_image++; - temp = temp|((0x05)<<10); - *p_fw_image = temp; - p_fw_image++; - - /* write address byte 0;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8); - temp = temp<<10; - *p_fw_image = temp; - p_fw_image++; - temp = temp|((0x05)<<10); - *p_fw_image = temp; - p_fw_image++; - - for (i = 0; i < 6; i++) { - *p_fw_image = 0xFFFFFFFF; - p_fw_image++; - } -} - - -static int cx231xx_load_firmware(struct cx231xx *dev) -{ - static const unsigned char magic[8] = { - 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa - }; - const struct firmware *firmware; - int i, retval = 0; - u32 value = 0; - u32 gpio_output = 0; - /*u32 checksum = 0;*/ - /*u32 *dataptr;*/ - u32 transfer_size = 0; - u32 fw_data = 0; - u32 address = 0; - /*u32 current_fw[800];*/ - u32 *p_current_fw, *p_fw; - u32 *p_fw_data; - int frame = 0; - u16 _buffer_size = 4096; - u8 *p_buffer; - - p_current_fw = vmalloc(1884180 * 4); - p_fw = p_current_fw; - if (p_current_fw == NULL) { - dprintk(2, "FAIL!!!\n"); - return -1; - } - - p_buffer = vmalloc(4096); - if (p_buffer == NULL) { - dprintk(2, "FAIL!!!\n"); - return -1; - } - - dprintk(2, "%s()\n", __func__); - - /* Save GPIO settings before reset of APU */ - retval |= mc417_memory_read(dev, 0x9020, &gpio_output); - retval |= mc417_memory_read(dev, 0x900C, &value); - - retval = mc417_register_write(dev, - IVTV_REG_VPU, 0xFFFFFFED); - retval |= mc417_register_write(dev, - IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); - retval |= mc417_register_write(dev, - IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800); - retval |= mc417_register_write(dev, - IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); - retval |= mc417_register_write(dev, - IVTV_REG_APU, 0); - - if (retval != 0) { - printk(KERN_ERR "%s: Error with mc417_register_write\n", - __func__); - return -1; - } - - retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME, - &dev->udev->dev); - - if (retval != 0) { - printk(KERN_ERR - "ERROR: Hotplug firmware request failed (%s).\n", - CX231xx_FIRM_IMAGE_NAME); - printk(KERN_ERR "Please fix your hotplug setup, the board will " - "not work without firmware loaded!\n"); - return -1; - } - - if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) { - printk(KERN_ERR "ERROR: Firmware size mismatch " - "(have %zd, expected %d)\n", - firmware->size, CX231xx_FIRM_IMAGE_SIZE); - release_firmware(firmware); - return -1; - } - - if (0 != memcmp(firmware->data, magic, 8)) { - printk(KERN_ERR - "ERROR: Firmware magic mismatch, wrong file?\n"); - release_firmware(firmware); - return -1; - } - - initGPIO(dev); - - /* transfer to the chip */ - dprintk(2, "Loading firmware to GPIO...\n"); - p_fw_data = (u32 *)firmware->data; - dprintk(2, "firmware->size=%zd\n", firmware->size); - for (transfer_size = 0; transfer_size < firmware->size; - transfer_size += 4) { - fw_data = *p_fw_data; - - mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw); - address = address + 1; - p_current_fw += 20; - p_fw_data += 1; - } - - /*download the firmware by ep5-out*/ - - for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size); - frame++) { - for (i = 0; i < _buffer_size; i++) { - *(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF); - i++; - *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8); - i++; - *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16); - i++; - *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24); - } - cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size); - } - - p_current_fw = p_fw; - vfree(p_current_fw); - p_current_fw = NULL; - uninitGPIO(dev); - release_firmware(firmware); - dprintk(1, "Firmware upload successful.\n"); - - retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS, - IVTV_CMD_HW_BLOCKS_RST); - if (retval < 0) { - printk(KERN_ERR "%s: Error with mc417_register_write\n", - __func__); - return retval; - } - /* F/W power up disturbs the GPIOs, restore state */ - retval |= mc417_register_write(dev, 0x9020, gpio_output); - retval |= mc417_register_write(dev, 0x900C, value); - - retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); - retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); - - if (retval < 0) { - printk(KERN_ERR "%s: Error with mc417_register_write\n", - __func__); - return retval; - } - return 0; -} - -static void cx231xx_417_check_encoder(struct cx231xx *dev) -{ - u32 status, seq; - - status = 0; - seq = 0; - cx231xx_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq); - dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq); -} - -static void cx231xx_codec_settings(struct cx231xx *dev) -{ - dprintk(1, "%s()\n", __func__); - - /* assign frame size */ - cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, - dev->ts1.height, dev->ts1.width); - - dev->mpeg_params.width = dev->ts1.width; - dev->mpeg_params.height = dev->ts1.height; - - cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params); - - cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); - cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); -} - -static int cx231xx_initialize_codec(struct cx231xx *dev) -{ - int version; - int retval; - u32 i, data[7]; - u32 val = 0; - - dprintk(1, "%s()\n", __func__); - cx231xx_disable656(dev); - retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ - if (retval < 0) { - dprintk(2, "%s() PING OK\n", __func__); - retval = cx231xx_load_firmware(dev); - if (retval < 0) { - printk(KERN_ERR "%s() f/w load failed\n", __func__); - return retval; - } - retval = cx231xx_find_mailbox(dev); - if (retval < 0) { - printk(KERN_ERR "%s() mailbox < 0, error\n", - __func__); - return -1; - } - dev->cx23417_mailbox = retval; - retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); - if (retval < 0) { - printk(KERN_ERR - "ERROR: cx23417 firmware ping failed!\n"); - return -1; - } - retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, - &version); - if (retval < 0) { - printk(KERN_ERR "ERROR: cx23417 firmware get encoder :" - "version failed!\n"); - return -1; - } - dprintk(1, "cx23417 firmware version is 0x%08x\n", version); - msleep(200); - } - - for (i = 0; i < 1; i++) { - retval = mc417_register_read(dev, 0x20f8, &val); - dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n", - val); - if (retval < 0) - return retval; - } - - cx231xx_enable656(dev); - /* stop mpeg capture */ - cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, - 3, 0, 1, 3, 4); - - cx231xx_codec_settings(dev); - msleep(60); - -/* cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, - CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115); - cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, - CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0); -*/ - /* Setup to capture VBI */ - data[0] = 0x0001BD00; - data[1] = 1; /* frames per interrupt */ - data[2] = 4; /* total bufs */ - data[3] = 0x91559155; /* start codes */ - data[4] = 0x206080C0; /* stop codes */ - data[5] = 6; /* lines */ - data[6] = 64; /* BPL */ -/* - cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1], - data[2], data[3], data[4], data[5], data[6]); - - for (i = 2; i <= 24; i++) { - int valid; - - valid = ((i >= 19) && (i <= 21)); - cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i, - valid, 0 , 0, 0); - cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, - i | 0x80000000, valid, 0, 0, 0); - } -*/ -/* cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE); - msleep(60); -*/ - /* initialize the video input */ - retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); - if (retval < 0) - return retval; - msleep(60); - - /* Enable VIP style pixel invalidation so we work with scaled mode */ - mc417_memory_write(dev, 2120, 0x00000080); - - /* start capturing to the host interface */ - retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, - CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE); - if (retval < 0) - return retval; - msleep(10); - - for (i = 0; i < 1; i++) { - mc417_register_read(dev, 0x20f8, &val); - dprintk(3, "***VIM Capture Lines =%d ***\n", val); - } - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int bb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) -{ - struct cx231xx_fh *fh = q->priv_data; - - fh->dev->ts1.ts_packet_size = mpeglinesize; - fh->dev->ts1.ts_packet_count = mpeglines; - - *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; - *count = mpegbufs; - - return 0; -} -static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) -{ - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - unsigned long flags = 0; - - if (in_interrupt()) - BUG(); - - spin_lock_irqsave(&dev->video_mode.slock, flags); - if (dev->USE_ISO) { - if (dev->video_mode.isoc_ctl.buf == buf) - dev->video_mode.isoc_ctl.buf = NULL; - } else { - if (dev->video_mode.bulk_ctl.buf == buf) - dev->video_mode.bulk_ctl.buf = NULL; - } - spin_unlock_irqrestore(&dev->video_mode.slock, flags); - videobuf_waiton(vq, &buf->vb, 0, 0); - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb, - struct cx231xx_dmaqueue *dma_q) -{ - void *vbuf; - struct cx231xx_buffer *buf; - u32 tail_data = 0; - char *p_data; - - if (dma_q->mpeg_buffer_done == 0) { - if (list_empty(&dma_q->active)) - return; - - buf = list_entry(dma_q->active.next, - struct cx231xx_buffer, vb.queue); - dev->video_mode.isoc_ctl.buf = buf; - dma_q->mpeg_buffer_done = 1; - } - /* Fill buffer */ - buf = dev->video_mode.isoc_ctl.buf; - vbuf = videobuf_to_vmalloc(&buf->vb); - - if ((dma_q->mpeg_buffer_completed+len) < - mpeglines*mpeglinesize) { - if (dma_q->add_ps_package_head == - CX231XX_NEED_ADD_PS_PACKAGE_HEAD) { - memcpy(vbuf+dma_q->mpeg_buffer_completed, - dma_q->ps_head, 3); - dma_q->mpeg_buffer_completed = - dma_q->mpeg_buffer_completed + 3; - dma_q->add_ps_package_head = - CX231XX_NONEED_PS_PACKAGE_HEAD; - } - memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len); - dma_q->mpeg_buffer_completed = - dma_q->mpeg_buffer_completed + len; - } else { - dma_q->mpeg_buffer_done = 0; - - tail_data = - mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed; - memcpy(vbuf+dma_q->mpeg_buffer_completed, - data, tail_data); - - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - dma_q->mpeg_buffer_completed = 0; - - if (len - tail_data > 0) { - p_data = data + tail_data; - dma_q->left_data_count = len - tail_data; - memcpy(dma_q->p_left_data, - p_data, len - tail_data); - } - - } - - return; -} - -static void buffer_filled(char *data, int len, struct urb *urb, - struct cx231xx_dmaqueue *dma_q) -{ - void *vbuf; - struct cx231xx_buffer *buf; - - if (list_empty(&dma_q->active)) - return; - - - buf = list_entry(dma_q->active.next, - struct cx231xx_buffer, vb.queue); - - - /* Fill buffer */ - vbuf = videobuf_to_vmalloc(&buf->vb); - memcpy(vbuf, data, len); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - - return; -} -static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) -{ - struct cx231xx_dmaqueue *dma_q = urb->context; - unsigned char *p_buffer; - u32 buffer_size = 0; - u32 i = 0; - - for (i = 0; i < urb->number_of_packets; i++) { - if (dma_q->left_data_count > 0) { - buffer_copy(dev, dma_q->p_left_data, - dma_q->left_data_count, urb, dma_q); - dma_q->mpeg_buffer_completed = dma_q->left_data_count; - dma_q->left_data_count = 0; - } - - p_buffer = urb->transfer_buffer + - urb->iso_frame_desc[i].offset; - buffer_size = urb->iso_frame_desc[i].actual_length; - - if (buffer_size > 0) - buffer_copy(dev, p_buffer, buffer_size, urb, dma_q); - } - - return 0; -} -static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) -{ - - /*char *outp;*/ - /*struct cx231xx_buffer *buf;*/ - struct cx231xx_dmaqueue *dma_q = urb->context; - unsigned char *p_buffer, *buffer; - u32 buffer_size = 0; - - p_buffer = urb->transfer_buffer; - buffer_size = urb->actual_length; - - buffer = kmalloc(buffer_size, GFP_ATOMIC); - - memcpy(buffer, dma_q->ps_head, 3); - memcpy(buffer+3, p_buffer, buffer_size-3); - memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3); - - p_buffer = buffer; - buffer_filled(p_buffer, buffer_size, urb, dma_q); - - kfree(buffer); - return 0; -} - -static int bb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct cx231xx_fh *fh = q->priv_data; - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx *dev = fh->dev; - int rc = 0, urb_init = 0; - int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; - - dma_qq = &dev->video_mode.vidq; - - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - buf->vb.width = fh->dev->ts1.ts_packet_size; - buf->vb.height = fh->dev->ts1.ts_packet_count; - buf->vb.size = size; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(q, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - if (dev->USE_ISO) { - if (!dev->video_mode.isoc_ctl.num_bufs) - urb_init = 1; - } else { - if (!dev->video_mode.bulk_ctl.num_bufs) - urb_init = 1; - } - /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n", - urb_init, dev->video_mode.max_pkt_size);*/ - dev->mode_tv = 1; - - if (urb_init) { - rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); - rc = cx231xx_unmute_audio(dev); - if (dev->USE_ISO) { - cx231xx_set_alt_setting(dev, INDEX_TS1, 4); - rc = cx231xx_init_isoc(dev, mpeglines, - mpegbufs, - dev->ts1_mode.max_pkt_size, - cx231xx_isoc_copy); - } else { - cx231xx_set_alt_setting(dev, INDEX_TS1, 0); - rc = cx231xx_init_bulk(dev, mpeglines, - mpegbufs, - dev->ts1_mode.max_pkt_size, - cx231xx_bulk_copy); - } - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(q, buf); - return rc; -} - -static void bb_buf_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx231xx_fh *fh = q->priv_data; - - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx *dev = fh->dev; - struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); - -} - -static void bb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - /*struct cx231xx_fh *fh = q->priv_data;*/ - /*struct cx231xx *dev = (struct cx231xx *)fh->dev;*/ - - free_buffer(q, buf); -} - -static struct videobuf_queue_ops cx231xx_qops = { - .buf_setup = bb_buf_setup, - .buf_prepare = bb_buf_prepare, - .buf_queue = bb_buf_queue, - .buf_release = bb_buf_release, -}; - -/* ------------------------------------------------------------------ */ - -static const u32 *ctrl_classes[] = { - cx2341x_mpeg_ctrls, - NULL -}; - -static int cx231xx_queryctrl(struct cx231xx *dev, - struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - - /* MPEG V4L2 controls */ - if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - - return 0; -} - -static int cx231xx_querymenu(struct cx231xx *dev, - struct v4l2_querymenu *qmenu) -{ - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - cx231xx_queryctrl(dev, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); -} - -static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - - *norm = dev->encodernorm.id; - return 0; -} -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++) - if (*id & cx231xx_tvnorms[i].id) - break; - if (i == ARRAY_SIZE(cx231xx_tvnorms)) - return -EINVAL; - dev->encodernorm = cx231xx_tvnorms[i]; - - if (dev->encodernorm.id & 0xb000) { - dprintk(3, "encodernorm set to NTSC\n"); - dev->norm = V4L2_STD_NTSC; - dev->ts1.height = 480; - dev->mpeg_params.is_50hz = 0; - } else { - dprintk(3, "encodernorm set to PAL\n"); - dev->norm = V4L2_STD_PAL_B; - dev->ts1.height = 576; - dev->mpeg_params.is_50hz = 1; - } - call_all(dev, core, s_std, dev->norm); - /* do mode control overrides */ - cx231xx_do_mode_ctrl_overrides(dev); - - dprintk(3, "exit vidioc_s_std() i=0x%x\n", i); - return 0; -} -static int vidioc_g_audio(struct file *file, void *fh, - struct v4l2_audio *a) -{ - struct v4l2_audio *vin = a; - - int ret = -EINVAL; - if (vin->index > 0) - return ret; - strncpy(vin->name, "VideoGrabber Audio", 14); - vin->capability = V4L2_AUDCAP_STEREO; -return 0; -} -static int vidioc_enumaudio(struct file *file, void *fh, - struct v4l2_audio *a) -{ - struct v4l2_audio *vin = a; - - int ret = -EINVAL; - - if (vin->index > 0) - return ret; - strncpy(vin->name, "VideoGrabber Audio", 14); - vin->capability = V4L2_AUDCAP_STEREO; - - -return 0; -} -static const char *iname[] = { - [CX231XX_VMUX_COMPOSITE1] = "Composite1", - [CX231XX_VMUX_SVIDEO] = "S-Video", - [CX231XX_VMUX_TELEVISION] = "Television", - [CX231XX_VMUX_CABLE] = "Cable TV", - [CX231XX_VMUX_DVB] = "DVB", - [CX231XX_VMUX_DEBUG] = "for debug only", -}; -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - struct cx231xx_input *input; - int n; - dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index); - - if (i->index >= 4) - return -EINVAL; - - - input = &cx231xx_boards[dev->model].input[i->index]; - - if (input->type == 0) - return -EINVAL; - - /* FIXME - * strcpy(i->name, input->name); */ - - n = i->index; - strcpy(i->name, iname[INPUT(n)->type]); - - if (input->type == CX231XX_VMUX_TELEVISION || - input->type == CX231XX_VMUX_CABLE) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - - dprintk(3, "enter vidioc_s_input() i=%d\n", i); - - mutex_lock(&dev->lock); - - video_mux(dev, i); - - mutex_unlock(&dev->lock); - - if (i >= 4) - return -EINVAL; - dev->input = i; - dprintk(3, "exit vidioc_s_input()\n"); - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - - - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - dprintk(3, "enter vidioc_s_ctrl()\n"); - /* Update the A/V core */ - call_all(dev, core, s_ctrl, ctl); - dprintk(3, "exit vidioc_s_ctrl()\n"); - return 0; -} -static struct v4l2_capability pvr_capability = { - .driver = "cx231xx", - .card = "VideoGrabber", - .bus_info = "usb", - .version = 1, - .capabilities = (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | - V4L2_CAP_STREAMING | V4L2_CAP_READWRITE), - .reserved = {0, 0, 0, 0} -}; -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - - - - memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - - if (f->index != 0) - return -EINVAL; - - strlcpy(f->description, "MPEG", sizeof(f->description)); - f->pixelformat = V4L2_PIX_FMT_MPEG; - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - dprintk(3, "enter vidioc_g_fmt_vid_cap()\n"); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.colorspace = 0; - f->fmt.pix.width = dev->ts1.width; - f->fmt.pix.height = dev->ts1.height; - f->fmt.pix.field = fh->vidq.field; - dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->vidq.field); - dprintk(3, "exit vidioc_g_fmt_vid_cap()\n"); - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - dprintk(3, "enter vidioc_try_fmt_vid_cap()\n"); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.colorspace = 0; - dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->vidq.field); - dprintk(3, "exit vidioc_try_fmt_vid_cap()\n"); - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx231xx_fh *fh = file->private_data; - - return videobuf_reqbufs(&fh->vidq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx231xx_fh *fh = file->private_data; - - return videobuf_querybuf(&fh->vidq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx231xx_fh *fh = file->private_data; - - return videobuf_qbuf(&fh->vidq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx231xx_fh *fh = priv; - - return videobuf_dqbuf(&fh->vidq, b, file->f_flags & O_NONBLOCK); -} - - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx231xx_fh *fh = file->private_data; - - struct cx231xx *dev = fh->dev; - int rc = 0; - dprintk(3, "enter vidioc_streamon()\n"); - cx231xx_set_alt_setting(dev, INDEX_TS1, 0); - rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); - if (dev->USE_ISO) - rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, - CX231XX_NUM_BUFS, - dev->video_mode.max_pkt_size, - cx231xx_isoc_copy); - else { - rc = cx231xx_init_bulk(dev, 320, - 5, - dev->ts1_mode.max_pkt_size, - cx231xx_bulk_copy); - } - dprintk(3, "exit vidioc_streamon()\n"); - return videobuf_streamon(&fh->vidq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx231xx_fh *fh = file->private_data; - - return videobuf_streamoff(&fh->vidq); -} - -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - dprintk(3, "enter vidioc_g_ext_ctrls()\n"); - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - dprintk(3, "exit vidioc_g_ext_ctrls()\n"); - return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); -} - -static int vidioc_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - dprintk(3, "enter vidioc_s_ext_ctrls()\n"); - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - if (err == 0) { - err = cx2341x_update(dev, cx231xx_mbox_func, - &dev->mpeg_params, &p); - dev->mpeg_params = p; - } - - return err; - - -return 0; -} - -static int vidioc_try_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - dprintk(3, "enter vidioc_try_ext_ctrls()\n"); - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err); - return err; -} - -static int vidioc_log_status(struct file *file, void *priv) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - char name[32 + 2]; - - snprintf(name, sizeof(name), "%s/2", dev->name); - dprintk(3, - "%s/2: ============ START LOG STATUS ============\n", - dev->name); - call_all(dev, core, log_status); - cx2341x_log_status(&dev->mpeg_params, name); - dprintk(3, - "%s/2: ============= END LOG STATUS =============\n", - dev->name); - return 0; -} - -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *a) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - dprintk(3, "enter vidioc_querymenu()\n"); - dprintk(3, "exit vidioc_querymenu()\n"); - return cx231xx_querymenu(dev, a); -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - dprintk(3, "enter vidioc_queryctrl()\n"); - dprintk(3, "exit vidioc_queryctrl()\n"); - return cx231xx_queryctrl(dev, c); -} - -static int mpeg_open(struct file *file) -{ - int minor = video_devdata(file)->minor; - struct cx231xx *h, *dev = NULL; - /*struct list_head *list;*/ - struct cx231xx_fh *fh; - /*u32 value = 0;*/ - - dprintk(2, "%s()\n", __func__); - - list_for_each_entry(h, &cx231xx_devlist, devlist) { - if (h->v4l_device->minor == minor) - dev = h; - } - - if (dev == NULL) - return -ENODEV; - - mutex_lock(&dev->lock); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) { - mutex_unlock(&dev->lock); - return -ENOMEM; - } - - file->private_data = fh; - fh->dev = dev; - - - videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops, - NULL, &dev->video_mode.slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, - sizeof(struct cx231xx_buffer), fh, NULL); -/* - videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops, - &dev->udev->dev, &dev->ts1.slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx231xx_buffer), - fh, NULL); -*/ - - - cx231xx_set_alt_setting(dev, INDEX_VANC, 1); - cx231xx_set_gpio_value(dev, 2, 0); - - cx231xx_initialize_codec(dev); - - mutex_unlock(&dev->lock); - cx231xx_start_TS1(dev); - - return 0; -} - -static int mpeg_release(struct file *file) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - - dprintk(3, "mpeg_release()! dev=0x%p\n", dev); - - if (!dev) { - dprintk(3, "abort!!!\n"); - return 0; - } - - mutex_lock(&dev->lock); - - cx231xx_stop_TS1(dev); - - /* do this before setting alternate! */ - if (dev->USE_ISO) - cx231xx_uninit_isoc(dev); - else - cx231xx_uninit_bulk(dev); - cx231xx_set_mode(dev, CX231XX_SUSPEND); - - cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX231xx_END_NOW, CX231xx_MPEG_CAPTURE, - CX231xx_RAW_BITS_NONE); - - /* FIXME: Review this crap */ - /* Shut device down on last close */ - if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { - if (atomic_dec_return(&dev->v4l_reader_count) == 0) { - /* stop mpeg capture */ - - msleep(500); - cx231xx_417_check_encoder(dev); - - } - } - - if (fh->vidq.streaming) - videobuf_streamoff(&fh->vidq); - if (fh->vidq.reading) - videobuf_read_stop(&fh->vidq); - - videobuf_mmap_free(&fh->vidq); - file->private_data = NULL; - kfree(fh); - mutex_unlock(&dev->lock); - return 0; -} - -static ssize_t mpeg_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - - - /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ - /* Start mpeg encoder on first read. */ - if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { - if (atomic_inc_return(&dev->v4l_reader_count) == 1) { - if (cx231xx_initialize_codec(dev) < 0) - return -EINVAL; - } - } - - return videobuf_read_stream(&fh->vidq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static unsigned int mpeg_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx231xx_fh *fh = file->private_data; - /*struct cx231xx *dev = fh->dev;*/ - - /*dprintk(2, "%s\n", __func__);*/ - - return videobuf_poll_stream(file, &fh->vidq, wait); -} - -static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - - dprintk(2, "%s()\n", __func__); - - return videobuf_mmap_mapper(&fh->vidq, vma); -} - -static struct v4l2_file_operations mpeg_fops = { - .owner = THIS_MODULE, - .open = mpeg_open, - .release = mpeg_release, - .read = mpeg_read, - .poll = mpeg_poll, - .mmap = mpeg_mmap, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { - .vidioc_s_std = vidioc_s_std, - .vidioc_g_std = vidioc_g_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_enumaudio = vidioc_enumaudio, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, - .vidioc_log_status = vidioc_log_status, - .vidioc_querymenu = vidioc_querymenu, - .vidioc_queryctrl = vidioc_queryctrl, -/* .vidioc_g_chip_ident = cx231xx_g_chip_ident,*/ -#ifdef CONFIG_VIDEO_ADV_DEBUG -/* .vidioc_g_register = cx231xx_g_register,*/ -/* .vidioc_s_register = cx231xx_s_register,*/ -#endif -}; - -static struct video_device cx231xx_mpeg_template = { - .name = "cx231xx", - .fops = &mpeg_fops, - .ioctl_ops = &mpeg_ioctl_ops, - .minor = -1, - .tvnorms = CX231xx_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; - -void cx231xx_417_unregister(struct cx231xx *dev) -{ - dprintk(1, "%s()\n", __func__); - dprintk(3, "%s()\n", __func__); - - if (dev->v4l_device) { - if (-1 != dev->v4l_device->minor) - video_unregister_device(dev->v4l_device); - else - video_device_release(dev->v4l_device); - dev->v4l_device = NULL; - } -} - -static struct video_device *cx231xx_video_dev_alloc( - struct cx231xx *dev, - struct usb_device *usbdev, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - - dprintk(1, "%s()\n", __func__); - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->minor = -1; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, - type, cx231xx_boards[dev->model].name); - - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; - - return vfd; - -} - -int cx231xx_417_register(struct cx231xx *dev) -{ - /* FIXME: Port1 hardcoded here */ - int err = -ENODEV; - struct cx231xx_tsport *tsport = &dev->ts1; - - dprintk(1, "%s()\n", __func__); - - /* Set default TV standard */ - dev->encodernorm = cx231xx_tvnorms[0]; - - if (dev->encodernorm.id & V4L2_STD_525_60) - tsport->height = 480; - else - tsport->height = 576; - - tsport->width = 720; - cx2341x_fill_defaults(&dev->mpeg_params); - dev->norm = V4L2_STD_NTSC; - - dev->mpeg_params.port = CX2341X_PORT_SERIAL; - - /* Allocate and initialize V4L video device */ - dev->v4l_device = cx231xx_video_dev_alloc(dev, - dev->udev, &cx231xx_mpeg_template, "mpeg"); - err = video_register_device(dev->v4l_device, - VFL_TYPE_GRABBER, -1); - if (err < 0) { - dprintk(3, "%s: can't register mpeg device\n", dev->name); - return err; - } - - dprintk(3, "%s: registered device video%d [mpeg]\n", - dev->name, dev->v4l_device->num); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-audio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-audio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,756 +0,0 @@ -/* - * Conexant Cx231xx audio extension - * - * Copyright (C) 2008 - * Based on em28xx driver - * - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cx231xx.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); - -#define dprintk(fmt, arg...) do { \ - if (debug) \ - printk(KERN_INFO "cx231xx-audio %s: " fmt, \ - __func__, ##arg); \ - } while (0) - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; - -static int cx231xx_isoc_audio_deinit(struct cx231xx *dev) -{ - int i; - - dprintk("Stopping isoc\n"); - - for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { - if (dev->adev.urb[i]) { - if (!irqs_disabled()) - usb_kill_urb(dev->adev.urb[i]); - else - usb_unlink_urb(dev->adev.urb[i]); - - usb_free_urb(dev->adev.urb[i]); - dev->adev.urb[i] = NULL; - - kfree(dev->adev.transfer_buffer[i]); - dev->adev.transfer_buffer[i] = NULL; - } - } - - return 0; -} - -static int cx231xx_bulk_audio_deinit(struct cx231xx *dev) -{ - int i; - - dprintk("Stopping bulk\n"); - - for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { - if (dev->adev.urb[i]) { - if (!irqs_disabled()) - usb_kill_urb(dev->adev.urb[i]); - else - usb_unlink_urb(dev->adev.urb[i]); - - usb_free_urb(dev->adev.urb[i]); - dev->adev.urb[i] = NULL; - - kfree(dev->adev.transfer_buffer[i]); - dev->adev.transfer_buffer[i] = NULL; - } - } - - return 0; -} - -static void cx231xx_audio_isocirq(struct urb *urb) -{ - struct cx231xx *dev = urb->context; - int i; - unsigned int oldptr; - int period_elapsed = 0; - int status; - unsigned char *cp; - unsigned int stride; - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - dprintk("urb completition error %d.\n", urb->status); - break; - } - - if (atomic_read(&dev->stream_started) == 0) - return; - - if (dev->adev.capture_pcm_substream) { - substream = dev->adev.capture_pcm_substream; - runtime = substream->runtime; - stride = runtime->frame_bits >> 3; - - for (i = 0; i < urb->number_of_packets; i++) { - int length = urb->iso_frame_desc[i].actual_length / - stride; - cp = (unsigned char *)urb->transfer_buffer + - urb->iso_frame_desc[i].offset; - - if (!length) - continue; - - oldptr = dev->adev.hwptr_done_capture; - if (oldptr + length >= runtime->buffer_size) { - unsigned int cnt; - - cnt = runtime->buffer_size - oldptr; - memcpy(runtime->dma_area + oldptr * stride, cp, - cnt * stride); - memcpy(runtime->dma_area, cp + cnt * stride, - length * stride - cnt * stride); - } else { - memcpy(runtime->dma_area + oldptr * stride, cp, - length * stride); - } - - snd_pcm_stream_lock(substream); - - dev->adev.hwptr_done_capture += length; - if (dev->adev.hwptr_done_capture >= - runtime->buffer_size) - dev->adev.hwptr_done_capture -= - runtime->buffer_size; - - dev->adev.capture_transfer_done += length; - if (dev->adev.capture_transfer_done >= - runtime->period_size) { - dev->adev.capture_transfer_done -= - runtime->period_size; - period_elapsed = 1; - } - snd_pcm_stream_unlock(substream); - } - if (period_elapsed) - snd_pcm_period_elapsed(substream); - } - urb->status = 0; - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - cx231xx_errdev("resubmit of audio urb failed (error=%i)\n", - status); - } - return; -} - -static void cx231xx_audio_bulkirq(struct urb *urb) -{ - struct cx231xx *dev = urb->context; - unsigned int oldptr; - int period_elapsed = 0; - int status; - unsigned char *cp; - unsigned int stride; - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - dprintk("urb completition error %d.\n", urb->status); - break; - } - - if (atomic_read(&dev->stream_started) == 0) - return; - - if (dev->adev.capture_pcm_substream) { - substream = dev->adev.capture_pcm_substream; - runtime = substream->runtime; - stride = runtime->frame_bits >> 3; - - if (1) { - int length = urb->actual_length / - stride; - cp = (unsigned char *)urb->transfer_buffer; - - oldptr = dev->adev.hwptr_done_capture; - if (oldptr + length >= runtime->buffer_size) { - unsigned int cnt; - - cnt = runtime->buffer_size - oldptr; - memcpy(runtime->dma_area + oldptr * stride, cp, - cnt * stride); - memcpy(runtime->dma_area, cp + cnt * stride, - length * stride - cnt * stride); - } else { - memcpy(runtime->dma_area + oldptr * stride, cp, - length * stride); - } - - snd_pcm_stream_lock(substream); - - dev->adev.hwptr_done_capture += length; - if (dev->adev.hwptr_done_capture >= - runtime->buffer_size) - dev->adev.hwptr_done_capture -= - runtime->buffer_size; - - dev->adev.capture_transfer_done += length; - if (dev->adev.capture_transfer_done >= - runtime->period_size) { - dev->adev.capture_transfer_done -= - runtime->period_size; - period_elapsed = 1; - } - snd_pcm_stream_unlock(substream); - } - if (period_elapsed) - snd_pcm_period_elapsed(substream); - } - urb->status = 0; - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - cx231xx_errdev("resubmit of audio urb failed (error=%i)\n", - status); - } - return; -} - -static int cx231xx_init_audio_isoc(struct cx231xx *dev) -{ - int i, errCode; - int sb_size; - - cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__); - - sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; - - for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { - struct urb *urb; - int j, k; - - dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); - if (!dev->adev.transfer_buffer[i]) - return -ENOMEM; - - memset(dev->adev.transfer_buffer[i], 0x80, sb_size); - urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC); - if (!urb) { - cx231xx_errdev("usb_alloc_urb failed!\n"); - for (j = 0; j < i; j++) { - usb_free_urb(dev->adev.urb[j]); - kfree(dev->adev.transfer_buffer[j]); - } - return -ENOMEM; - } - - urb->dev = dev->udev; - urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, - dev->adev.end_point_addr); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->adev.transfer_buffer[i]; - urb->interval = 1; - urb->complete = cx231xx_audio_isocirq; - urb->number_of_packets = CX231XX_ISO_NUM_AUDIO_PACKETS; - urb->transfer_buffer_length = sb_size; - - for (j = k = 0; j < CX231XX_ISO_NUM_AUDIO_PACKETS; - j++, k += dev->adev.max_pkt_size) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = dev->adev.max_pkt_size; - } - dev->adev.urb[i] = urb; - } - - for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { - errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); - if (errCode < 0) { - cx231xx_isoc_audio_deinit(dev); - return errCode; - } - } - - return errCode; -} - -static int cx231xx_init_audio_bulk(struct cx231xx *dev) -{ - int i, errCode; - int sb_size; - - cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__); - - sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; - - for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { - struct urb *urb; - int j; - - dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); - if (!dev->adev.transfer_buffer[i]) - return -ENOMEM; - - memset(dev->adev.transfer_buffer[i], 0x80, sb_size); - urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); - if (!urb) { - cx231xx_errdev("usb_alloc_urb failed!\n"); - for (j = 0; j < i; j++) { - usb_free_urb(dev->adev.urb[j]); - kfree(dev->adev.transfer_buffer[j]); - } - return -ENOMEM; - } - - urb->dev = dev->udev; - urb->context = dev; - urb->pipe = usb_rcvbulkpipe(dev->udev, - dev->adev.end_point_addr); - urb->transfer_flags = 0; - urb->transfer_buffer = dev->adev.transfer_buffer[i]; - urb->complete = cx231xx_audio_bulkirq; - urb->transfer_buffer_length = sb_size; - - dev->adev.urb[i] = urb; - - } - - for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { - errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); - if (errCode < 0) { - cx231xx_bulk_audio_deinit(dev); - return errCode; - } - } - - return errCode; -} - -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, - size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - dprintk("Allocating vbuffer\n"); - if (runtime->dma_area) { - if (runtime->dma_bytes > size) - return 0; - - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc(size); - if (!runtime->dma_area) - return -ENOMEM; - - runtime->dma_bytes = size; - - return 0; -} - -static struct snd_pcm_hardware snd_cx231xx_hw_capture = { - .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID, - - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, - - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ - .period_bytes_min = 64, /* 12544/2, */ - .period_bytes_max = 12544, - .periods_min = 2, - .periods_max = 98, /* 12544, */ -}; - -static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream) -{ - struct cx231xx *dev = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int ret = 0; - - dprintk("opening device and trying to acquire exclusive lock\n"); - - if (!dev) { - cx231xx_errdev("BUG: cx231xx can't find device struct." - " Can't proceed with open\n"); - return -ENODEV; - } - - /* Sets volume, mute, etc */ - dev->mute = 0; - - /* set alternate setting for audio interface */ - /* 1 - 48000 samples per sec */ - mutex_lock(&dev->lock); - if (dev->USE_ISO) - ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1); - else - ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); - mutex_unlock(&dev->lock); - if (ret < 0) { - cx231xx_errdev("failed to set alternate setting !\n"); - - return ret; - } - - runtime->hw = snd_cx231xx_hw_capture; - - mutex_lock(&dev->lock); - /* inform hardware to start streaming */ - ret = cx231xx_capture_start(dev, 1, Audio); - - dev->adev.users++; - mutex_unlock(&dev->lock); - - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - dev->adev.capture_pcm_substream = substream; - runtime->private_data = dev; - - return 0; -} - -static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) -{ - int ret; - struct cx231xx *dev = snd_pcm_substream_chip(substream); - - dprintk("closing device\n"); - - /* inform hardware to stop streaming */ - mutex_lock(&dev->lock); - ret = cx231xx_capture_start(dev, 0, Audio); - - /* set alternate setting for audio interface */ - /* 1 - 48000 samples per sec */ - ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); - if (ret < 0) { - cx231xx_errdev("failed to set alternate setting !\n"); - - mutex_unlock(&dev->lock); - return ret; - } - - dev->mute = 1; - dev->adev.users--; - mutex_unlock(&dev->lock); - - if (dev->adev.users == 0 && dev->adev.shutdown == 1) { - dprintk("audio users: %d\n", dev->adev.users); - dprintk("disabling audio stream!\n"); - dev->adev.shutdown = 0; - dprintk("released lock\n"); - if (atomic_read(&dev->stream_started) > 0) { - atomic_set(&dev->stream_started, 0); - schedule_work(&dev->wq_trigger); - } - } - return 0; -} - -static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - unsigned int channels, rate, format; - int ret; - - dprintk("Setting capture parameters\n"); - - ret = snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - format = params_format(hw_params); - rate = params_rate(hw_params); - channels = params_channels(hw_params); - - /* TODO: set up cx231xx audio chip to deliver the correct audio format, - current default is 48000hz multiplexed => 96000hz mono - which shouldn't matter since analogue TV only supports mono */ - return 0; -} - -static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream) -{ - struct cx231xx *dev = snd_pcm_substream_chip(substream); - - dprintk("Stop capture, if needed\n"); - - if (atomic_read(&dev->stream_started) > 0) { - atomic_set(&dev->stream_started, 0); - schedule_work(&dev->wq_trigger); - } - - return 0; -} - -static int snd_cx231xx_prepare(struct snd_pcm_substream *substream) -{ - struct cx231xx *dev = snd_pcm_substream_chip(substream); - - dev->adev.hwptr_done_capture = 0; - dev->adev.capture_transfer_done = 0; - - return 0; -} - -static void audio_trigger(struct work_struct *work) -{ - struct cx231xx *dev = container_of(work, struct cx231xx, wq_trigger); - - if (atomic_read(&dev->stream_started)) { - dprintk("starting capture"); - if (is_fw_load(dev) == 0) - cx25840_call(dev, core, load_fw); - if (dev->USE_ISO) - cx231xx_init_audio_isoc(dev); - else - cx231xx_init_audio_bulk(dev); - } else { - dprintk("stopping capture"); - cx231xx_isoc_audio_deinit(dev); - } -} - -static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct cx231xx *dev = snd_pcm_substream_chip(substream); - int retval; - - spin_lock(&dev->adev.slock); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - atomic_set(&dev->stream_started, 1); - break; - case SNDRV_PCM_TRIGGER_STOP: - atomic_set(&dev->stream_started, 0); - break; - default: - retval = -EINVAL; - } - spin_unlock(&dev->adev.slock); - - schedule_work(&dev->wq_trigger); - - return 0; -} - -static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream - *substream) -{ - struct cx231xx *dev; - unsigned long flags; - snd_pcm_uframes_t hwptr_done; - - dev = snd_pcm_substream_chip(substream); - - spin_lock_irqsave(&dev->adev.slock, flags); - hwptr_done = dev->adev.hwptr_done_capture; - spin_unlock_irqrestore(&dev->adev.slock, flags); - - return hwptr_done; -} - -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - - return vmalloc_to_page(pageptr); -} - -static struct snd_pcm_ops snd_cx231xx_pcm_capture = { - .open = snd_cx231xx_capture_open, - .close = snd_cx231xx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_cx231xx_hw_capture_params, - .hw_free = snd_cx231xx_hw_capture_free, - .prepare = snd_cx231xx_prepare, - .trigger = snd_cx231xx_capture_trigger, - .pointer = snd_cx231xx_capture_pointer, - .page = snd_pcm_get_vmalloc_page, -}; - -static int cx231xx_audio_init(struct cx231xx *dev) -{ - struct cx231xx_audio *adev = &dev->adev; - struct snd_pcm *pcm; - struct snd_card *card; - static int devnr; - int err; - struct usb_interface *uif; - int i, isoc_pipe = 0; - - if (dev->has_alsa_audio != 1) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module or - doesn't have analog audio support at all) */ - return 0; - } - - cx231xx_info("cx231xx-audio.c: probing for cx231xx " - "non standard usbaudio\n"); - - err = snd_card_create(index[devnr], "Cx231xx Audio", THIS_MODULE, - 0, &card); - if (err < 0) - return err; - - spin_lock_init(&adev->slock); - err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm); - if (err < 0) { - snd_card_free(card); - return err; - } - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_cx231xx_pcm_capture); - pcm->info_flags = 0; - pcm->private_data = dev; - strcpy(pcm->name, "Conexant cx231xx Capture"); - snd_card_set_dev(card, &dev->udev->dev); - strcpy(card->driver, "Cx231xx-Audio"); - strcpy(card->shortname, "Cx231xx Audio"); - strcpy(card->longname, "Conexant cx231xx Audio"); - - INIT_WORK(&dev->wq_trigger, audio_trigger); - - err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } - adev->sndcard = card; - adev->udev = dev->udev; - - /* compute alternate max packet sizes for Audio */ - uif = - dev->udev->actconfig->interface[dev->current_pcb_config. - hs_config_info[0].interface_info. - audio_index + 1]; - - adev->end_point_addr = - le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc. - bEndpointAddress); - - adev->num_alt = uif->num_altsetting; - cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", - adev->end_point_addr, adev->num_alt); - adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL); - - if (adev->alt_max_pkt_size == NULL) { - cx231xx_errdev("out of memory!\n"); - return -ENOMEM; - } - - for (i = 0; i < adev->num_alt; i++) { - u16 tmp = - le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc. - wMaxPacketSize); - adev->alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - cx231xx_info("Alternate setting %i, max size= %i\n", i, - adev->alt_max_pkt_size[i]); - } - - return 0; -} - -static int cx231xx_audio_fini(struct cx231xx *dev) -{ - if (dev == NULL) - return 0; - - if (dev->has_alsa_audio != 1) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module or - doesn't have analog audio support at all) */ - return 0; - } - - if (dev->adev.sndcard) { - snd_card_free(dev->adev.sndcard); - kfree(dev->adev.alt_max_pkt_size); - dev->adev.sndcard = NULL; - } - - return 0; -} - -static struct cx231xx_ops audio_ops = { - .id = CX231XX_AUDIO, - .name = "Cx231xx Audio Extension", - .init = cx231xx_audio_init, - .fini = cx231xx_audio_fini, -}; - -static int __init cx231xx_alsa_register(void) -{ - return cx231xx_register_extension(&audio_ops); -} - -static void __exit cx231xx_alsa_unregister(void) -{ - cx231xx_unregister_extension(&audio_ops); -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Srinivasa Deevi "); -MODULE_DESCRIPTION("Cx231xx Audio driver"); - -module_init(cx231xx_alsa_register); -module_exit(cx231xx_alsa_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-avcore.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-avcore.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-avcore.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-avcore.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3119 +0,0 @@ -/* - cx231xx_avcore.c - driver for Conexant Cx23100/101/102 - USB video capture devices - - Copyright (C) 2008 - - This program contains the specific code to control the avdecoder chip and - other related usb control functions for cx231xx based chipset. - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "cx231xx.h" -#include "cx231xx-dif.h" - -#define TUNER_MODE_FM_RADIO 0 -/****************************************************************************** - -: BLOCK ARRANGEMENT :- - I2S block ----------------------| - [I2S audio] | - | - Analog Front End --> Direct IF -|-> Cx25840 --> Audio - [video & audio] | [Audio] - | - |-> Cx25840 --> Video - [Video] - -*******************************************************************************/ -/****************************************************************************** - * VERVE REGISTER * - * * - ******************************************************************************/ -static int verve_write_byte(struct cx231xx *dev, u8 saddr, u8 data) -{ - return cx231xx_write_i2c_data(dev, VERVE_I2C_ADDRESS, - saddr, 1, data, 1); -} - -static int verve_read_byte(struct cx231xx *dev, u8 saddr, u8 *data) -{ - int status; - u32 temp = 0; - - status = cx231xx_read_i2c_data(dev, VERVE_I2C_ADDRESS, - saddr, 1, &temp, 1); - *data = (u8) temp; - return status; -} -void initGPIO(struct cx231xx *dev) -{ - u32 _gpio_direction = 0; - u32 value = 0; - u8 val = 0; - - _gpio_direction = _gpio_direction & 0xFC0003FF; - _gpio_direction = _gpio_direction | 0x03FDFC00; - cx231xx_send_gpio_cmd(dev, _gpio_direction, (u8 *)&value, 4, 0, 0); - - verve_read_byte(dev, 0x07, &val); - cx231xx_info(" verve_read_byte address0x07=0x%x\n", val); - verve_write_byte(dev, 0x07, 0xF4); - verve_read_byte(dev, 0x07, &val); - cx231xx_info(" verve_read_byte address0x07=0x%x\n", val); - - cx231xx_capture_start(dev, 1, 2); - - cx231xx_mode_register(dev, EP_MODE_SET, 0x0500FE00); - cx231xx_mode_register(dev, GBULK_BIT_EN, 0xFFFDFFFF); - -} -void uninitGPIO(struct cx231xx *dev) -{ - u8 value[4] = { 0, 0, 0, 0 }; - - cx231xx_capture_start(dev, 0, 2); - verve_write_byte(dev, 0x07, 0x14); - cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - 0x68, value, 4); -} - -/****************************************************************************** - * A F E - B L O C K C O N T R O L functions * - * [ANALOG FRONT END] * - ******************************************************************************/ -static int afe_write_byte(struct cx231xx *dev, u16 saddr, u8 data) -{ - return cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS, - saddr, 2, data, 1); -} - -static int afe_read_byte(struct cx231xx *dev, u16 saddr, u8 *data) -{ - int status; - u32 temp = 0; - - status = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS, - saddr, 2, &temp, 1); - *data = (u8) temp; - return status; -} - -int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count) -{ - int status = 0; - u8 temp = 0; - u8 afe_power_status = 0; - int i = 0; - - /* super block initialize */ - temp = (u8) (ref_count & 0xff); - status = afe_write_byte(dev, SUP_BLK_TUNE2, temp); - if (status < 0) - return status; - - status = afe_read_byte(dev, SUP_BLK_TUNE2, &afe_power_status); - if (status < 0) - return status; - - temp = (u8) ((ref_count & 0x300) >> 8); - temp |= 0x40; - status = afe_write_byte(dev, SUP_BLK_TUNE1, temp); - if (status < 0) - return status; - - status = afe_write_byte(dev, SUP_BLK_PLL2, 0x0f); - if (status < 0) - return status; - - /* enable pll */ - while (afe_power_status != 0x18) { - status = afe_write_byte(dev, SUP_BLK_PWRDN, 0x18); - if (status < 0) { - cx231xx_info( - ": Init Super Block failed in send cmd\n"); - break; - } - - status = afe_read_byte(dev, SUP_BLK_PWRDN, &afe_power_status); - afe_power_status &= 0xff; - if (status < 0) { - cx231xx_info( - ": Init Super Block failed in receive cmd\n"); - break; - } - i++; - if (i == 10) { - cx231xx_info( - ": Init Super Block force break in loop !!!!\n"); - status = -1; - break; - } - } - - if (status < 0) - return status; - - /* start tuning filter */ - status = afe_write_byte(dev, SUP_BLK_TUNE3, 0x40); - if (status < 0) - return status; - - msleep(5); - - /* exit tuning */ - status = afe_write_byte(dev, SUP_BLK_TUNE3, 0x00); - - return status; -} - -int cx231xx_afe_init_channels(struct cx231xx *dev) -{ - int status = 0; - - /* power up all 3 channels, clear pd_buffer */ - status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, 0x00); - status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, 0x00); - status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, 0x00); - - /* Enable quantizer calibration */ - status = afe_write_byte(dev, ADC_COM_QUANT, 0x02); - - /* channel initialize, force modulator (fb) reset */ - status = afe_write_byte(dev, ADC_FB_FRCRST_CH1, 0x17); - status = afe_write_byte(dev, ADC_FB_FRCRST_CH2, 0x17); - status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, 0x17); - - /* start quantilizer calibration */ - status = afe_write_byte(dev, ADC_CAL_ATEST_CH1, 0x10); - status = afe_write_byte(dev, ADC_CAL_ATEST_CH2, 0x10); - status = afe_write_byte(dev, ADC_CAL_ATEST_CH3, 0x10); - msleep(5); - - /* exit modulator (fb) reset */ - status = afe_write_byte(dev, ADC_FB_FRCRST_CH1, 0x07); - status = afe_write_byte(dev, ADC_FB_FRCRST_CH2, 0x07); - status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, 0x07); - - /* enable the pre_clamp in each channel for single-ended input */ - status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH1, 0xf0); - status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH2, 0xf0); - status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, 0xf0); - - /* use diode instead of resistor, so set term_en to 0, res_en to 0 */ - status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8, - ADC_QGAIN_RES_TRM_CH1, 3, 7, 0x00); - status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8, - ADC_QGAIN_RES_TRM_CH2, 3, 7, 0x00); - status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8, - ADC_QGAIN_RES_TRM_CH3, 3, 7, 0x00); - - /* dynamic element matching off */ - status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH1, 0x03); - status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH2, 0x03); - status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, 0x03); - - return status; -} - -int cx231xx_afe_setup_AFE_for_baseband(struct cx231xx *dev) -{ - u8 c_value = 0; - int status = 0; - - status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH2, &c_value); - c_value &= (~(0x50)); - status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, c_value); - - return status; -} - -/* - The Analog Front End in Cx231xx has 3 channels. These - channels are used to share between different inputs - like tuner, s-video and composite inputs. - - channel 1 ----- pin 1 to pin4(in reg is 1-4) - channel 2 ----- pin 5 to pin8(in reg is 5-8) - channel 3 ----- pin 9 to pin 12(in reg is 9-11) -*/ -int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux) -{ - u8 ch1_setting = (u8) input_mux; - u8 ch2_setting = (u8) (input_mux >> 8); - u8 ch3_setting = (u8) (input_mux >> 16); - int status = 0; - u8 value = 0; - - if (ch1_setting != 0) { - status = afe_read_byte(dev, ADC_INPUT_CH1, &value); - value &= ~INPUT_SEL_MASK; - value |= (ch1_setting - 1) << 4; - value &= 0xff; - status = afe_write_byte(dev, ADC_INPUT_CH1, value); - } - - if (ch2_setting != 0) { - status = afe_read_byte(dev, ADC_INPUT_CH2, &value); - value &= ~INPUT_SEL_MASK; - value |= (ch2_setting - 1) << 4; - value &= 0xff; - status = afe_write_byte(dev, ADC_INPUT_CH2, value); - } - - /* For ch3_setting, the value to put in the register is - 7 less than the input number */ - if (ch3_setting != 0) { - status = afe_read_byte(dev, ADC_INPUT_CH3, &value); - value &= ~INPUT_SEL_MASK; - value |= (ch3_setting - 1) << 4; - value &= 0xff; - status = afe_write_byte(dev, ADC_INPUT_CH3, value); - } - - return status; -} - -int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode) -{ - int status = 0; - - /* - * FIXME: We need to implement the AFE code for LOW IF and for HI IF. - * Currently, only baseband works. - */ - - switch (mode) { - case AFE_MODE_LOW_IF: - cx231xx_Setup_AFE_for_LowIF(dev); - break; - case AFE_MODE_BASEBAND: - status = cx231xx_afe_setup_AFE_for_baseband(dev); - break; - case AFE_MODE_EU_HI_IF: - /* SetupAFEforEuHiIF(); */ - break; - case AFE_MODE_US_HI_IF: - /* SetupAFEforUsHiIF(); */ - break; - case AFE_MODE_JAPAN_HI_IF: - /* SetupAFEforJapanHiIF(); */ - break; - } - - if ((mode != dev->afe_mode) && - (dev->video_input == CX231XX_VMUX_TELEVISION)) - status = cx231xx_afe_adjust_ref_count(dev, - CX231XX_VMUX_TELEVISION); - - dev->afe_mode = mode; - - return status; -} - -int cx231xx_afe_update_power_control(struct cx231xx *dev, - enum AV_MODE avmode) -{ - u8 afe_power_status = 0; - int status = 0; - - switch (dev->model) { - case CX231XX_BOARD_CNXT_CARRAERA: - case CX231XX_BOARD_CNXT_RDE_250: - case CX231XX_BOARD_CNXT_SHELBY: - case CX231XX_BOARD_CNXT_RDU_250: - case CX231XX_BOARD_CNXT_RDE_253S: - case CX231XX_BOARD_CNXT_RDU_253S: - case CX231XX_BOARD_CNXT_VIDEO_GRABBER: - case CX231XX_BOARD_HAUPPAUGE_EXETER: - case CX231XX_BOARD_HAUPPAUGE_USBLIVE2: - case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: - if (avmode == POLARIS_AVMODE_ANALOGT_TV) { - while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | - FLD_PWRDN_ENABLE_PLL)) { - status = afe_write_byte(dev, SUP_BLK_PWRDN, - FLD_PWRDN_TUNING_BIAS | - FLD_PWRDN_ENABLE_PLL); - status |= afe_read_byte(dev, SUP_BLK_PWRDN, - &afe_power_status); - if (status < 0) - break; - } - - status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, - 0x00); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, - 0x00); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, - 0x00); - } else if (avmode == POLARIS_AVMODE_DIGITAL) { - status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, - 0x70); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, - 0x70); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, - 0x70); - - status |= afe_read_byte(dev, SUP_BLK_PWRDN, - &afe_power_status); - afe_power_status |= FLD_PWRDN_PD_BANDGAP | - FLD_PWRDN_PD_BIAS | - FLD_PWRDN_PD_TUNECK; - status |= afe_write_byte(dev, SUP_BLK_PWRDN, - afe_power_status); - } else if (avmode == POLARIS_AVMODE_ENXTERNAL_AV) { - while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | - FLD_PWRDN_ENABLE_PLL)) { - status = afe_write_byte(dev, SUP_BLK_PWRDN, - FLD_PWRDN_TUNING_BIAS | - FLD_PWRDN_ENABLE_PLL); - status |= afe_read_byte(dev, SUP_BLK_PWRDN, - &afe_power_status); - if (status < 0) - break; - } - - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, - 0x00); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, - 0x00); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, - 0x00); - } else { - cx231xx_info("Invalid AV mode input\n"); - status = -1; - } - break; - default: - if (avmode == POLARIS_AVMODE_ANALOGT_TV) { - while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | - FLD_PWRDN_ENABLE_PLL)) { - status = afe_write_byte(dev, SUP_BLK_PWRDN, - FLD_PWRDN_TUNING_BIAS | - FLD_PWRDN_ENABLE_PLL); - status |= afe_read_byte(dev, SUP_BLK_PWRDN, - &afe_power_status); - if (status < 0) - break; - } - - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, - 0x40); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, - 0x40); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, - 0x00); - } else if (avmode == POLARIS_AVMODE_DIGITAL) { - status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, - 0x70); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, - 0x70); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, - 0x70); - - status |= afe_read_byte(dev, SUP_BLK_PWRDN, - &afe_power_status); - afe_power_status |= FLD_PWRDN_PD_BANDGAP | - FLD_PWRDN_PD_BIAS | - FLD_PWRDN_PD_TUNECK; - status |= afe_write_byte(dev, SUP_BLK_PWRDN, - afe_power_status); - } else if (avmode == POLARIS_AVMODE_ENXTERNAL_AV) { - while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | - FLD_PWRDN_ENABLE_PLL)) { - status = afe_write_byte(dev, SUP_BLK_PWRDN, - FLD_PWRDN_TUNING_BIAS | - FLD_PWRDN_ENABLE_PLL); - status |= afe_read_byte(dev, SUP_BLK_PWRDN, - &afe_power_status); - if (status < 0) - break; - } - - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, - 0x00); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, - 0x00); - status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, - 0x40); - } else { - cx231xx_info("Invalid AV mode input\n"); - status = -1; - } - } /* switch */ - - return status; -} - -int cx231xx_afe_adjust_ref_count(struct cx231xx *dev, u32 video_input) -{ - u8 input_mode = 0; - u8 ntf_mode = 0; - int status = 0; - - dev->video_input = video_input; - - if (video_input == CX231XX_VMUX_TELEVISION) { - status = afe_read_byte(dev, ADC_INPUT_CH3, &input_mode); - status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, - &ntf_mode); - } else { - status = afe_read_byte(dev, ADC_INPUT_CH1, &input_mode); - status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH1, - &ntf_mode); - } - - input_mode = (ntf_mode & 0x3) | ((input_mode & 0x6) << 1); - - switch (input_mode) { - case SINGLE_ENDED: - dev->afe_ref_count = 0x23C; - break; - case LOW_IF: - dev->afe_ref_count = 0x24C; - break; - case EU_IF: - dev->afe_ref_count = 0x258; - break; - case US_IF: - dev->afe_ref_count = 0x260; - break; - default: - break; - } - - status = cx231xx_afe_init_super_block(dev, dev->afe_ref_count); - - return status; -} - -/****************************************************************************** - * V I D E O / A U D I O D E C O D E R C O N T R O L functions * - ******************************************************************************/ -static int vid_blk_write_byte(struct cx231xx *dev, u16 saddr, u8 data) -{ - return cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS, - saddr, 2, data, 1); -} - -static int vid_blk_read_byte(struct cx231xx *dev, u16 saddr, u8 *data) -{ - int status; - u32 temp = 0; - - status = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, - saddr, 2, &temp, 1); - *data = (u8) temp; - return status; -} - -static int vid_blk_write_word(struct cx231xx *dev, u16 saddr, u32 data) -{ - return cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS, - saddr, 2, data, 4); -} - -static int vid_blk_read_word(struct cx231xx *dev, u16 saddr, u32 *data) -{ - return cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, - saddr, 2, data, 4); -} -int cx231xx_check_fw(struct cx231xx *dev) -{ - u8 temp = 0; - int status = 0; - status = vid_blk_read_byte(dev, DL_CTL_ADDRESS_LOW, &temp); - if (status < 0) - return status; - else - return temp; - -} - -int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input) -{ - int status = 0; - - switch (INPUT(input)->type) { - case CX231XX_VMUX_COMPOSITE1: - case CX231XX_VMUX_SVIDEO: - if ((dev->current_pcb_config.type == USB_BUS_POWER) && - (dev->power_mode != POLARIS_AVMODE_ENXTERNAL_AV)) { - /* External AV */ - status = cx231xx_set_power_mode(dev, - POLARIS_AVMODE_ENXTERNAL_AV); - if (status < 0) { - cx231xx_errdev("%s: set_power_mode : Failed to" - " set Power - errCode [%d]!\n", - __func__, status); - return status; - } - } - status = cx231xx_set_decoder_video_input(dev, - INPUT(input)->type, - INPUT(input)->vmux); - break; - case CX231XX_VMUX_TELEVISION: - case CX231XX_VMUX_CABLE: - if ((dev->current_pcb_config.type == USB_BUS_POWER) && - (dev->power_mode != POLARIS_AVMODE_ANALOGT_TV)) { - /* Tuner */ - status = cx231xx_set_power_mode(dev, - POLARIS_AVMODE_ANALOGT_TV); - if (status < 0) { - cx231xx_errdev("%s: set_power_mode:Failed" - " to set Power - errCode [%d]!\n", - __func__, status); - return status; - } - } - if (dev->tuner_type == TUNER_NXP_TDA18271) - status = cx231xx_set_decoder_video_input(dev, - CX231XX_VMUX_TELEVISION, - INPUT(input)->vmux); - else - status = cx231xx_set_decoder_video_input(dev, - CX231XX_VMUX_COMPOSITE1, - INPUT(input)->vmux); - - break; - default: - cx231xx_errdev("%s: set_power_mode : Unknown Input %d !\n", - __func__, INPUT(input)->type); - break; - } - - /* save the selection */ - dev->video_input = input; - - return status; -} - -int cx231xx_set_decoder_video_input(struct cx231xx *dev, - u8 pin_type, u8 input) -{ - int status = 0; - u32 value = 0; - - if (pin_type != dev->video_input) { - status = cx231xx_afe_adjust_ref_count(dev, pin_type); - if (status < 0) { - cx231xx_errdev("%s: adjust_ref_count :Failed to set" - "AFE input mux - errCode [%d]!\n", - __func__, status); - return status; - } - } - - /* call afe block to set video inputs */ - status = cx231xx_afe_set_input_mux(dev, input); - if (status < 0) { - cx231xx_errdev("%s: set_input_mux :Failed to set" - " AFE input mux - errCode [%d]!\n", - __func__, status); - return status; - } - - switch (pin_type) { - case CX231XX_VMUX_COMPOSITE1: - status = vid_blk_read_word(dev, AFE_CTRL, &value); - value |= (0 << 13) | (1 << 4); - value &= ~(1 << 5); - - /* set [24:23] [22:15] to 0 */ - value &= (~(0x1ff8000)); - /* set FUNC_MODE[24:23] = 2 IF_MOD[22:15] = 0 */ - value |= 0x1000000; - status = vid_blk_write_word(dev, AFE_CTRL, value); - - status = vid_blk_read_word(dev, OUT_CTRL1, &value); - value |= (1 << 7); - status = vid_blk_write_word(dev, OUT_CTRL1, value); - - /* Set output mode */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - OUT_CTRL1, - FLD_OUT_MODE, - dev->board.output_mode); - - /* Tell DIF object to go to baseband mode */ - status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND); - if (status < 0) { - cx231xx_errdev("%s: cx231xx_dif set to By pass" - " mode- errCode [%d]!\n", - __func__, status); - return status; - } - - /* Read the DFE_CTRL1 register */ - status = vid_blk_read_word(dev, DFE_CTRL1, &value); - - /* enable the VBI_GATE_EN */ - value |= FLD_VBI_GATE_EN; - - /* Enable the auto-VGA enable */ - value |= FLD_VGA_AUTO_EN; - - /* Write it back */ - status = vid_blk_write_word(dev, DFE_CTRL1, value); - - /* Disable auto config of registers */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - MODE_CTRL, FLD_ACFG_DIS, - cx231xx_set_field(FLD_ACFG_DIS, 1)); - - /* Set CVBS input mode */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - MODE_CTRL, FLD_INPUT_MODE, - cx231xx_set_field(FLD_INPUT_MODE, INPUT_MODE_CVBS_0)); - break; - case CX231XX_VMUX_SVIDEO: - /* Disable the use of DIF */ - - status = vid_blk_read_word(dev, AFE_CTRL, &value); - - /* set [24:23] [22:15] to 0 */ - value &= (~(0x1ff8000)); - /* set FUNC_MODE[24:23] = 2 - IF_MOD[22:15] = 0 DCR_BYP_CH2[4:4] = 1; */ - value |= 0x1000010; - status = vid_blk_write_word(dev, AFE_CTRL, value); - - /* Tell DIF object to go to baseband mode */ - status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND); - if (status < 0) { - cx231xx_errdev("%s: cx231xx_dif set to By pass" - " mode- errCode [%d]!\n", - __func__, status); - return status; - } - - /* Read the DFE_CTRL1 register */ - status = vid_blk_read_word(dev, DFE_CTRL1, &value); - - /* enable the VBI_GATE_EN */ - value |= FLD_VBI_GATE_EN; - - /* Enable the auto-VGA enable */ - value |= FLD_VGA_AUTO_EN; - - /* Write it back */ - status = vid_blk_write_word(dev, DFE_CTRL1, value); - - /* Disable auto config of registers */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - MODE_CTRL, FLD_ACFG_DIS, - cx231xx_set_field(FLD_ACFG_DIS, 1)); - - /* Set YC input mode */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - MODE_CTRL, - FLD_INPUT_MODE, - cx231xx_set_field(FLD_INPUT_MODE, INPUT_MODE_YC_1)); - - /* Chroma to ADC2 */ - status = vid_blk_read_word(dev, AFE_CTRL, &value); - value |= FLD_CHROMA_IN_SEL; /* set the chroma in select */ - - /* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8) - This sets them to use video - rather than audio. Only one of the two will be in use. */ - value &= ~(FLD_VGA_SEL_CH2 | FLD_VGA_SEL_CH3); - - status = vid_blk_write_word(dev, AFE_CTRL, value); - - status = cx231xx_afe_set_mode(dev, AFE_MODE_BASEBAND); - break; - case CX231XX_VMUX_TELEVISION: - case CX231XX_VMUX_CABLE: - default: - /* TODO: Test if this is also needed for xc2028/xc3028 */ - if (dev->board.tuner_type == TUNER_XC5000) { - /* Disable the use of DIF */ - - status = vid_blk_read_word(dev, AFE_CTRL, &value); - value |= (0 << 13) | (1 << 4); - value &= ~(1 << 5); - - /* set [24:23] [22:15] to 0 */ - value &= (~(0x1FF8000)); - /* set FUNC_MODE[24:23] = 2 IF_MOD[22:15] = 0 */ - value |= 0x1000000; - status = vid_blk_write_word(dev, AFE_CTRL, value); - - status = vid_blk_read_word(dev, OUT_CTRL1, &value); - value |= (1 << 7); - status = vid_blk_write_word(dev, OUT_CTRL1, value); - - /* Set output mode */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - OUT_CTRL1, FLD_OUT_MODE, - dev->board.output_mode); - - /* Tell DIF object to go to baseband mode */ - status = cx231xx_dif_set_standard(dev, - DIF_USE_BASEBAND); - if (status < 0) { - cx231xx_errdev("%s: cx231xx_dif set to By pass" - " mode- errCode [%d]!\n", - __func__, status); - return status; - } - - /* Read the DFE_CTRL1 register */ - status = vid_blk_read_word(dev, DFE_CTRL1, &value); - - /* enable the VBI_GATE_EN */ - value |= FLD_VBI_GATE_EN; - - /* Enable the auto-VGA enable */ - value |= FLD_VGA_AUTO_EN; - - /* Write it back */ - status = vid_blk_write_word(dev, DFE_CTRL1, value); - - /* Disable auto config of registers */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - MODE_CTRL, FLD_ACFG_DIS, - cx231xx_set_field(FLD_ACFG_DIS, 1)); - - /* Set CVBS input mode */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - MODE_CTRL, FLD_INPUT_MODE, - cx231xx_set_field(FLD_INPUT_MODE, - INPUT_MODE_CVBS_0)); - } else { - /* Enable the DIF for the tuner */ - - /* Reinitialize the DIF */ - status = cx231xx_dif_set_standard(dev, dev->norm); - if (status < 0) { - cx231xx_errdev("%s: cx231xx_dif set to By pass" - " mode- errCode [%d]!\n", - __func__, status); - return status; - } - - /* Make sure bypass is cleared */ - status = vid_blk_read_word(dev, DIF_MISC_CTRL, &value); - - /* Clear the bypass bit */ - value &= ~FLD_DIF_DIF_BYPASS; - - /* Enable the use of the DIF block */ - status = vid_blk_write_word(dev, DIF_MISC_CTRL, value); - - /* Read the DFE_CTRL1 register */ - status = vid_blk_read_word(dev, DFE_CTRL1, &value); - - /* Disable the VBI_GATE_EN */ - value &= ~FLD_VBI_GATE_EN; - - /* Enable the auto-VGA enable, AGC, and - set the skip count to 2 */ - value |= FLD_VGA_AUTO_EN | FLD_AGC_AUTO_EN | 0x00200000; - - /* Write it back */ - status = vid_blk_write_word(dev, DFE_CTRL1, value); - - /* Wait until AGC locks up */ - msleep(1); - - /* Disable the auto-VGA enable AGC */ - value &= ~(FLD_VGA_AUTO_EN); - - /* Write it back */ - status = vid_blk_write_word(dev, DFE_CTRL1, value); - - /* Enable Polaris B0 AGC output */ - status = vid_blk_read_word(dev, PIN_CTRL, &value); - value |= (FLD_OEF_AGC_RF) | - (FLD_OEF_AGC_IFVGA) | - (FLD_OEF_AGC_IF); - status = vid_blk_write_word(dev, PIN_CTRL, value); - - /* Set output mode */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - OUT_CTRL1, FLD_OUT_MODE, - dev->board.output_mode); - - /* Disable auto config of registers */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - MODE_CTRL, FLD_ACFG_DIS, - cx231xx_set_field(FLD_ACFG_DIS, 1)); - - /* Set CVBS input mode */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - MODE_CTRL, FLD_INPUT_MODE, - cx231xx_set_field(FLD_INPUT_MODE, - INPUT_MODE_CVBS_0)); - - /* Set some bits in AFE_CTRL so that channel 2 or 3 - * is ready to receive audio */ - /* Clear clamp for channels 2 and 3 (bit 16-17) */ - /* Clear droop comp (bit 19-20) */ - /* Set VGA_SEL (for audio control) (bit 7-8) */ - status = vid_blk_read_word(dev, AFE_CTRL, &value); - - /*Set Func mode:01-DIF 10-baseband 11-YUV*/ - value &= (~(FLD_FUNC_MODE)); - value |= 0x800000; - - value |= FLD_VGA_SEL_CH3 | FLD_VGA_SEL_CH2; - - status = vid_blk_write_word(dev, AFE_CTRL, value); - - if (dev->tuner_type == TUNER_NXP_TDA18271) { - status = vid_blk_read_word(dev, PIN_CTRL, - &value); - status = vid_blk_write_word(dev, PIN_CTRL, - (value & 0xFFFFFFEF)); - } - - break; - - } - break; - } - - /* Set raw VBI mode */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - OUT_CTRL1, FLD_VBIHACTRAW_EN, - cx231xx_set_field(FLD_VBIHACTRAW_EN, 1)); - - status = vid_blk_read_word(dev, OUT_CTRL1, &value); - if (value & 0x02) { - value |= (1 << 19); - status = vid_blk_write_word(dev, OUT_CTRL1, value); - } - - return status; -} - -void cx231xx_enable656(struct cx231xx *dev) -{ - u8 temp = 0; - int status; - /*enable TS1 data[0:7] as output to export 656*/ - - status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0xFF); - - /*enable TS1 clock as output to export 656*/ - - status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp); - temp = temp|0x04; - - status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp); - -} -EXPORT_SYMBOL_GPL(cx231xx_enable656); - -void cx231xx_disable656(struct cx231xx *dev) -{ - u8 temp = 0; - int status; - - - status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0x00); - - status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp); - temp = temp&0xFB; - - status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp); -} -EXPORT_SYMBOL_GPL(cx231xx_disable656); - -/* - * Handle any video-mode specific overrides that are different - * on a per video standards basis after touching the MODE_CTRL - * register which resets many values for autodetect - */ -int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev) -{ - int status = 0; - - cx231xx_info("do_mode_ctrl_overrides : 0x%x\n", - (unsigned int)dev->norm); - - /* Change the DFE_CTRL3 bp_percent to fix flagging */ - status = vid_blk_write_word(dev, DFE_CTRL3, 0xCD3F0280); - - if (dev->norm & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) { - cx231xx_info("do_mode_ctrl_overrides NTSC\n"); - - /* Move the close caption lines out of active video, - adjust the active video start point */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - VERT_TIM_CTRL, - FLD_VBLANK_CNT, 0x18); - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - VERT_TIM_CTRL, - FLD_VACTIVE_CNT, - 0x1E7000); - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - VERT_TIM_CTRL, - FLD_V656BLANK_CNT, - 0x1C000000); - - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - HORIZ_TIM_CTRL, - FLD_HBLANK_CNT, - cx231xx_set_field - (FLD_HBLANK_CNT, 0x79)); - - } else if (dev->norm & V4L2_STD_SECAM) { - cx231xx_info("do_mode_ctrl_overrides SECAM\n"); - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - VERT_TIM_CTRL, - FLD_VBLANK_CNT, 0x20); - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - VERT_TIM_CTRL, - FLD_VACTIVE_CNT, - cx231xx_set_field - (FLD_VACTIVE_CNT, - 0x244)); - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - VERT_TIM_CTRL, - FLD_V656BLANK_CNT, - cx231xx_set_field - (FLD_V656BLANK_CNT, - 0x24)); - /* Adjust the active video horizontal start point */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - HORIZ_TIM_CTRL, - FLD_HBLANK_CNT, - cx231xx_set_field - (FLD_HBLANK_CNT, 0x85)); - } else { - cx231xx_info("do_mode_ctrl_overrides PAL\n"); - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - VERT_TIM_CTRL, - FLD_VBLANK_CNT, 0x20); - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - VERT_TIM_CTRL, - FLD_VACTIVE_CNT, - cx231xx_set_field - (FLD_VACTIVE_CNT, - 0x244)); - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - VERT_TIM_CTRL, - FLD_V656BLANK_CNT, - cx231xx_set_field - (FLD_V656BLANK_CNT, - 0x24)); - /* Adjust the active video horizontal start point */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - HORIZ_TIM_CTRL, - FLD_HBLANK_CNT, - cx231xx_set_field - (FLD_HBLANK_CNT, 0x85)); - - } - - return status; -} - -int cx231xx_unmute_audio(struct cx231xx *dev) -{ - return vid_blk_write_byte(dev, PATH1_VOL_CTL, 0x24); -} -EXPORT_SYMBOL_GPL(cx231xx_unmute_audio); - -int stopAudioFirmware(struct cx231xx *dev) -{ - return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x03); -} - -int restartAudioFirmware(struct cx231xx *dev) -{ - return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x13); -} - -int cx231xx_set_audio_input(struct cx231xx *dev, u8 input) -{ - int status = 0; - enum AUDIO_INPUT ainput = AUDIO_INPUT_LINE; - - switch (INPUT(input)->amux) { - case CX231XX_AMUX_VIDEO: - ainput = AUDIO_INPUT_TUNER_TV; - break; - case CX231XX_AMUX_LINE_IN: - status = cx231xx_i2s_blk_set_audio_input(dev, input); - ainput = AUDIO_INPUT_LINE; - break; - default: - break; - } - - status = cx231xx_set_audio_decoder_input(dev, ainput); - - return status; -} - -int cx231xx_set_audio_decoder_input(struct cx231xx *dev, - enum AUDIO_INPUT audio_input) -{ - u32 dwval; - int status; - u8 gen_ctrl; - u32 value = 0; - - /* Put it in soft reset */ - status = vid_blk_read_byte(dev, GENERAL_CTL, &gen_ctrl); - gen_ctrl |= 1; - status = vid_blk_write_byte(dev, GENERAL_CTL, gen_ctrl); - - switch (audio_input) { - case AUDIO_INPUT_LINE: - /* setup AUD_IO control from Merlin paralle output */ - value = cx231xx_set_field(FLD_AUD_CHAN1_SRC, - AUD_CHAN_SRC_PARALLEL); - status = vid_blk_write_word(dev, AUD_IO_CTRL, value); - - /* setup input to Merlin, SRC2 connect to AC97 - bypass upsample-by-2, slave mode, sony mode, left justify - adr 091c, dat 01000000 */ - status = vid_blk_read_word(dev, AC97_CTL, &dwval); - - status = vid_blk_write_word(dev, AC97_CTL, - (dwval | FLD_AC97_UP2X_BYPASS)); - - /* select the parallel1 and SRC3 */ - status = vid_blk_write_word(dev, BAND_OUT_SEL, - cx231xx_set_field(FLD_SRC3_IN_SEL, 0x0) | - cx231xx_set_field(FLD_SRC3_CLK_SEL, 0x0) | - cx231xx_set_field(FLD_PARALLEL1_SRC_SEL, 0x0)); - - /* unmute all, AC97 in, independence mode - adr 08d0, data 0x00063073 */ - status = vid_blk_write_word(dev, DL_CTL, 0x3000001); - status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063073); - - /* set AVC maximum threshold, adr 08d4, dat ffff0024 */ - status = vid_blk_read_word(dev, PATH1_VOL_CTL, &dwval); - status = vid_blk_write_word(dev, PATH1_VOL_CTL, - (dwval | FLD_PATH1_AVC_THRESHOLD)); - - /* set SC maximum threshold, adr 08ec, dat ffffb3a3 */ - status = vid_blk_read_word(dev, PATH1_SC_CTL, &dwval); - status = vid_blk_write_word(dev, PATH1_SC_CTL, - (dwval | FLD_PATH1_SC_THRESHOLD)); - break; - - case AUDIO_INPUT_TUNER_TV: - default: - status = stopAudioFirmware(dev); - /* Setup SRC sources and clocks */ - status = vid_blk_write_word(dev, BAND_OUT_SEL, - cx231xx_set_field(FLD_SRC6_IN_SEL, 0x00) | - cx231xx_set_field(FLD_SRC6_CLK_SEL, 0x01) | - cx231xx_set_field(FLD_SRC5_IN_SEL, 0x00) | - cx231xx_set_field(FLD_SRC5_CLK_SEL, 0x02) | - cx231xx_set_field(FLD_SRC4_IN_SEL, 0x02) | - cx231xx_set_field(FLD_SRC4_CLK_SEL, 0x03) | - cx231xx_set_field(FLD_SRC3_IN_SEL, 0x00) | - cx231xx_set_field(FLD_SRC3_CLK_SEL, 0x00) | - cx231xx_set_field(FLD_BASEBAND_BYPASS_CTL, 0x00) | - cx231xx_set_field(FLD_AC97_SRC_SEL, 0x03) | - cx231xx_set_field(FLD_I2S_SRC_SEL, 0x00) | - cx231xx_set_field(FLD_PARALLEL2_SRC_SEL, 0x02) | - cx231xx_set_field(FLD_PARALLEL1_SRC_SEL, 0x01)); - - /* Setup the AUD_IO control */ - status = vid_blk_write_word(dev, AUD_IO_CTRL, - cx231xx_set_field(FLD_I2S_PORT_DIR, 0x00) | - cx231xx_set_field(FLD_I2S_OUT_SRC, 0x00) | - cx231xx_set_field(FLD_AUD_CHAN3_SRC, 0x00) | - cx231xx_set_field(FLD_AUD_CHAN2_SRC, 0x00) | - cx231xx_set_field(FLD_AUD_CHAN1_SRC, 0x03)); - - status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F063870); - - /* setAudioStandard(_audio_standard); */ - status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063870); - - status = restartAudioFirmware(dev); - - switch (dev->board.tuner_type) { - case TUNER_XC5000: - /* SIF passthrough at 28.6363 MHz sample rate */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - CHIP_CTRL, - FLD_SIF_EN, - cx231xx_set_field(FLD_SIF_EN, 1)); - break; - case TUNER_NXP_TDA18271: - /* Normal mode: SIF passthrough at 14.32 MHz */ - status = cx231xx_read_modify_write_i2c_dword(dev, - VID_BLK_I2C_ADDRESS, - CHIP_CTRL, - FLD_SIF_EN, - cx231xx_set_field(FLD_SIF_EN, 0)); - break; - default: - /* This is just a casual suggestion to people adding - new boards in case they use a tuner type we don't - currently know about */ - printk(KERN_INFO "Unknown tuner type configuring SIF"); - break; - } - break; - - case AUDIO_INPUT_TUNER_FM: - /* use SIF for FM radio - setupFM(); - setAudioStandard(_audio_standard); - */ - break; - - case AUDIO_INPUT_MUTE: - status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F011012); - break; - } - - /* Take it out of soft reset */ - status = vid_blk_read_byte(dev, GENERAL_CTL, &gen_ctrl); - gen_ctrl &= ~1; - status = vid_blk_write_byte(dev, GENERAL_CTL, gen_ctrl); - - return status; -} - -/****************************************************************************** - * C H I P Specific C O N T R O L functions * - ******************************************************************************/ -int cx231xx_init_ctrl_pin_status(struct cx231xx *dev) -{ - u32 value; - int status = 0; - - status = vid_blk_read_word(dev, PIN_CTRL, &value); - value |= (~dev->board.ctl_pin_status_mask); - status = vid_blk_write_word(dev, PIN_CTRL, value); - - return status; -} - -int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev, - u8 analog_or_digital) -{ - int status = 0; - - /* first set the direction to output */ - status = cx231xx_set_gpio_direction(dev, - dev->board. - agc_analog_digital_select_gpio, 1); - - /* 0 - demod ; 1 - Analog mode */ - status = cx231xx_set_gpio_value(dev, - dev->board.agc_analog_digital_select_gpio, - analog_or_digital); - - return status; -} - -int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3) -{ - u8 value[4] = { 0, 0, 0, 0 }; - int status = 0; - bool current_is_port_3; - - if (dev->board.dont_use_port_3) - is_port_3 = false; - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, - PWR_CTL_EN, value, 4); - if (status < 0) - return status; - - current_is_port_3 = value[0] & I2C_DEMOD_EN ? true : false; - - /* Just return, if already using the right port */ - if (current_is_port_3 == is_port_3) - return 0; - - if (is_port_3) - value[0] |= I2C_DEMOD_EN; - else - value[0] &= ~I2C_DEMOD_EN; - - cx231xx_info("Changing the i2c master port to %d\n", - is_port_3 ? 3 : 1); - - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - - return status; - -} -EXPORT_SYMBOL_GPL(cx231xx_enable_i2c_port_3); - -void update_HH_register_after_set_DIF(struct cx231xx *dev) -{ -/* - u8 status = 0; - u32 value = 0; - - vid_blk_write_word(dev, PIN_CTRL, 0xA0FFF82F); - vid_blk_write_word(dev, DIF_MISC_CTRL, 0x0A203F11); - vid_blk_write_word(dev, DIF_SRC_PHASE_INC, 0x1BEFBF06); - - status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); - vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390); - status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); -*/ -} - -void cx231xx_dump_HH_reg(struct cx231xx *dev) -{ - u8 status = 0; - u32 value = 0; - u16 i = 0; - - value = 0x45005390; - status = vid_blk_write_word(dev, 0x104, value); - - for (i = 0x100; i < 0x140; i++) { - status = vid_blk_read_word(dev, i, &value); - cx231xx_info("reg0x%x=0x%x\n", i, value); - i = i+3; - } - - for (i = 0x300; i < 0x400; i++) { - status = vid_blk_read_word(dev, i, &value); - cx231xx_info("reg0x%x=0x%x\n", i, value); - i = i+3; - } - - for (i = 0x400; i < 0x440; i++) { - status = vid_blk_read_word(dev, i, &value); - cx231xx_info("reg0x%x=0x%x\n", i, value); - i = i+3; - } - - status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); - cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); - vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390); - status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); - cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); -} - -void cx231xx_dump_SC_reg(struct cx231xx *dev) -{ - u8 value[4] = { 0, 0, 0, 0 }; - int status = 0; - cx231xx_info("cx231xx_dump_SC_reg %s!\n", __TIME__); - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", BOARD_CFG_STAT, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS_MODE_REG, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_CFG_REG, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_LENGTH_REG, value[0], - value[1], value[2], value[3]); - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_CFG_REG, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_LENGTH_REG, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", EP_MODE_SET, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN1, value[0], - value[1], value[2], value[3]); - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN2, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN3, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK0, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK1, value[0], - value[1], value[2], value[3]); - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK2, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_GAIN, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_CAR_REG, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG1, value[0], - value[1], value[2], value[3]); - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG2, value[0], - value[1], value[2], value[3]); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, - value, 4); - cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, value[0], - value[1], value[2], value[3]); - - -} - -void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev) - -{ - u8 status = 0; - u8 value = 0; - - - - status = afe_read_byte(dev, ADC_STATUS2_CH3, &value); - value = (value & 0xFE)|0x01; - status = afe_write_byte(dev, ADC_STATUS2_CH3, value); - - status = afe_read_byte(dev, ADC_STATUS2_CH3, &value); - value = (value & 0xFE)|0x00; - status = afe_write_byte(dev, ADC_STATUS2_CH3, value); - - -/* - config colibri to lo-if mode - - FIXME: ntf_mode = 2'b00 by default. But set 0x1 would reduce - the diff IF input by half, - - for low-if agc defect -*/ - - status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, &value); - value = (value & 0xFC)|0x00; - status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, value); - - status = afe_read_byte(dev, ADC_INPUT_CH3, &value); - value = (value & 0xF9)|0x02; - status = afe_write_byte(dev, ADC_INPUT_CH3, value); - - status = afe_read_byte(dev, ADC_FB_FRCRST_CH3, &value); - value = (value & 0xFB)|0x04; - status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, value); - - status = afe_read_byte(dev, ADC_DCSERVO_DEM_CH3, &value); - value = (value & 0xFC)|0x03; - status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, value); - - status = afe_read_byte(dev, ADC_CTRL_DAC1_CH3, &value); - value = (value & 0xFB)|0x04; - status = afe_write_byte(dev, ADC_CTRL_DAC1_CH3, value); - - status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value); - value = (value & 0xF8)|0x06; - status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value); - - status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value); - value = (value & 0x8F)|0x40; - status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value); - - status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH3, &value); - value = (value & 0xDF)|0x20; - status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, value); -} - -void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq, - u8 spectral_invert, u32 mode) -{ - u32 colibri_carrier_offset = 0; - u8 status = 0; - u32 func_mode = 0x01; /* Device has a DIF if this function is called */ - u32 standard = 0; - u8 value[4] = { 0, 0, 0, 0 }; - - cx231xx_info("Enter cx231xx_set_Colibri_For_LowIF()\n"); - value[0] = (u8) 0x6F; - value[1] = (u8) 0x6F; - value[2] = (u8) 0x6F; - value[3] = (u8) 0x6F; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - - /*Set colibri for low IF*/ - status = cx231xx_afe_set_mode(dev, AFE_MODE_LOW_IF); - - /* Set C2HH for low IF operation.*/ - standard = dev->norm; - status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode, - func_mode, standard); - - /* Get colibri offsets.*/ - colibri_carrier_offset = cx231xx_Get_Colibri_CarrierOffset(mode, - standard); - - cx231xx_info("colibri_carrier_offset=%d, standard=0x%x\n", - colibri_carrier_offset, standard); - - /* Set the band Pass filter for DIF*/ - cx231xx_set_DIF_bandpass(dev, (if_freq+colibri_carrier_offset), - spectral_invert, mode); -} - -u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd) -{ - u32 colibri_carrier_offset = 0; - - if (mode == TUNER_MODE_FM_RADIO) { - colibri_carrier_offset = 1100000; - } else if (standerd & (V4L2_STD_MN | V4L2_STD_NTSC_M_JP)) { - colibri_carrier_offset = 4832000; /*4.83MHz */ - } else if (standerd & (V4L2_STD_PAL_B | V4L2_STD_PAL_G)) { - colibri_carrier_offset = 2700000; /*2.70MHz */ - } else if (standerd & (V4L2_STD_PAL_D | V4L2_STD_PAL_I - | V4L2_STD_SECAM)) { - colibri_carrier_offset = 2100000; /*2.10MHz */ - } - - return colibri_carrier_offset; -} - -void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq, - u8 spectral_invert, u32 mode) -{ - unsigned long pll_freq_word; - int status = 0; - u32 dif_misc_ctrl_value = 0; - u64 pll_freq_u64 = 0; - u32 i = 0; - - cx231xx_info("if_freq=%d;spectral_invert=0x%x;mode=0x%x\n", - if_freq, spectral_invert, mode); - - - if (mode == TUNER_MODE_FM_RADIO) { - pll_freq_word = 0x905A1CAC; - status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word); - - } else /*KSPROPERTY_TUNER_MODE_TV*/{ - /* Calculate the PLL frequency word based on the adjusted if_freq*/ - pll_freq_word = if_freq; - pll_freq_u64 = (u64)pll_freq_word << 28L; - do_div(pll_freq_u64, 50000000); - pll_freq_word = (u32)pll_freq_u64; - /*pll_freq_word = 0x3463497;*/ - status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word); - - if (spectral_invert) { - if_freq -= 400000; - /* Enable Spectral Invert*/ - status = vid_blk_read_word(dev, DIF_MISC_CTRL, - &dif_misc_ctrl_value); - dif_misc_ctrl_value = dif_misc_ctrl_value | 0x00200000; - status = vid_blk_write_word(dev, DIF_MISC_CTRL, - dif_misc_ctrl_value); - } else { - if_freq += 400000; - /* Disable Spectral Invert*/ - status = vid_blk_read_word(dev, DIF_MISC_CTRL, - &dif_misc_ctrl_value); - dif_misc_ctrl_value = dif_misc_ctrl_value & 0xFFDFFFFF; - status = vid_blk_write_word(dev, DIF_MISC_CTRL, - dif_misc_ctrl_value); - } - - if_freq = (if_freq/100000)*100000; - - if (if_freq < 3000000) - if_freq = 3000000; - - if (if_freq > 16000000) - if_freq = 16000000; - } - - cx231xx_info("Enter IF=%zd\n", - sizeof(Dif_set_array)/sizeof(struct dif_settings)); - for (i = 0; i < sizeof(Dif_set_array)/sizeof(struct dif_settings); i++) { - if (Dif_set_array[i].if_freq == if_freq) { - status = vid_blk_write_word(dev, - Dif_set_array[i].register_address, Dif_set_array[i].value); - } - } -} - -/****************************************************************************** - * D I F - B L O C K C O N T R O L functions * - ******************************************************************************/ -int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode, - u32 function_mode, u32 standard) -{ - int status = 0; - - - if (mode == V4L2_TUNER_RADIO) { - /* C2HH */ - /* lo if big signal */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1); - /* FUNC_MODE = DIF */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 23, 24, function_mode); - /* IF_MODE */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xFF); - /* no inv */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1); - } else if (standard != DIF_USE_BASEBAND) { - if (standard & V4L2_STD_MN) { - /* lo if big signal */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1); - /* FUNC_MODE = DIF */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 23, 24, - function_mode); - /* IF_MODE */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xb); - /* no inv */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1); - /* 0x124, AUD_CHAN1_SRC = 0x3 */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AUD_IO_CTRL, 0, 31, 0x00000003); - } else if ((standard == V4L2_STD_PAL_I) | - (standard & V4L2_STD_PAL_D) | - (standard & V4L2_STD_SECAM)) { - /* C2HH setup */ - /* lo if big signal */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1); - /* FUNC_MODE = DIF */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 23, 24, - function_mode); - /* IF_MODE */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xF); - /* no inv */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1); - } else { - /* default PAL BG */ - /* C2HH setup */ - /* lo if big signal */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1); - /* FUNC_MODE = DIF */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 23, 24, - function_mode); - /* IF_MODE */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xE); - /* no inv */ - status = cx231xx_reg_mask_write(dev, - VID_BLK_I2C_ADDRESS, 32, - AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1); - } - } - - return status; -} - -int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard) -{ - int status = 0; - u32 dif_misc_ctrl_value = 0; - u32 func_mode = 0; - - cx231xx_info("%s: setStandard to %x\n", __func__, standard); - - status = vid_blk_read_word(dev, DIF_MISC_CTRL, &dif_misc_ctrl_value); - if (standard != DIF_USE_BASEBAND) - dev->norm = standard; - - switch (dev->model) { - case CX231XX_BOARD_CNXT_CARRAERA: - case CX231XX_BOARD_CNXT_RDE_250: - case CX231XX_BOARD_CNXT_SHELBY: - case CX231XX_BOARD_CNXT_RDU_250: - case CX231XX_BOARD_CNXT_VIDEO_GRABBER: - case CX231XX_BOARD_HAUPPAUGE_EXETER: - func_mode = 0x03; - break; - case CX231XX_BOARD_CNXT_RDE_253S: - case CX231XX_BOARD_CNXT_RDU_253S: - func_mode = 0x01; - break; - default: - func_mode = 0x01; - } - - status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode, - func_mode, standard); - - if (standard == DIF_USE_BASEBAND) { /* base band */ - /* There is a different SRC_PHASE_INC value - for baseband vs. DIF */ - status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, 0xDF7DF83); - status = vid_blk_read_word(dev, DIF_MISC_CTRL, - &dif_misc_ctrl_value); - dif_misc_ctrl_value |= FLD_DIF_DIF_BYPASS; - status = vid_blk_write_word(dev, DIF_MISC_CTRL, - dif_misc_ctrl_value); - } else if (standard & V4L2_STD_PAL_D) { - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL, 0, 31, 0x6503bc0c); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL1, 0, 31, 0xbd038c85); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL2, 0, 31, 0x1db4640a); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL3, 0, 31, 0x00008800); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_REF, 0, 31, 0x444C1380); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_IF, 0, 31, 0xDA302600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_INT, 0, 31, 0xDA261700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_RF, 0, 31, 0xDA262600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_INT_CURRENT, 0, 31, - 0x26001700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_RF_CURRENT, 0, 31, - 0x00002660); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VIDEO_AGC_CTRL, 0, 31, - 0x72500800); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VID_AUD_OVERRIDE, 0, 31, - 0x27000100); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AV_SEP_CTRL, 0, 31, 0x3F3934EA); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_COMP_FLT_CTRL, 0, 31, - 0x00000000); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_PHASE_INC, 0, 31, - 0x1befbf06); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_GAIN_CONTROL, 0, 31, - 0x000035e8); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_RPT_VARIANCE, 0, 31, 0x00000000); - /* Save the Spec Inversion value */ - dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; - dif_misc_ctrl_value |= 0x3a023F11; - } else if (standard & V4L2_STD_PAL_I) { - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL, 0, 31, 0x6503bc0c); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL1, 0, 31, 0xbd038c85); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL2, 0, 31, 0x1db4640a); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL3, 0, 31, 0x00008800); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_REF, 0, 31, 0x444C1380); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_IF, 0, 31, 0xDA302600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_INT, 0, 31, 0xDA261700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_RF, 0, 31, 0xDA262600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_INT_CURRENT, 0, 31, - 0x26001700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_RF_CURRENT, 0, 31, - 0x00002660); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VIDEO_AGC_CTRL, 0, 31, - 0x72500800); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VID_AUD_OVERRIDE, 0, 31, - 0x27000100); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AV_SEP_CTRL, 0, 31, 0x5F39A934); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_COMP_FLT_CTRL, 0, 31, - 0x00000000); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_PHASE_INC, 0, 31, - 0x1befbf06); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_GAIN_CONTROL, 0, 31, - 0x000035e8); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_RPT_VARIANCE, 0, 31, 0x00000000); - /* Save the Spec Inversion value */ - dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; - dif_misc_ctrl_value |= 0x3a033F11; - } else if (standard & V4L2_STD_PAL_M) { - /* improved Low Frequency Phase Noise */ - status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0xFF01FF0C); - status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xbd038c85); - status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1db4640a); - status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800); - status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C1380); - status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT, - 0x26001700); - status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT, - 0x00002660); - status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL, - 0x72500800); - status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE, - 0x27000100); - status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, 0x012c405d); - status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL, - 0x009f50c1); - status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, - 0x1befbf06); - status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL, - 0x000035e8); - status = vid_blk_write_word(dev, DIF_SOFT_RST_CTRL_REVB, - 0x00000000); - /* Save the Spec Inversion value */ - dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; - dif_misc_ctrl_value |= 0x3A0A3F10; - } else if (standard & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) { - /* improved Low Frequency Phase Noise */ - status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0xFF01FF0C); - status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xbd038c85); - status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1db4640a); - status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800); - status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C1380); - status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT, - 0x26001700); - status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT, - 0x00002660); - status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL, - 0x72500800); - status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE, - 0x27000100); - status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, - 0x012c405d); - status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL, - 0x009f50c1); - status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, - 0x1befbf06); - status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL, - 0x000035e8); - status = vid_blk_write_word(dev, DIF_SOFT_RST_CTRL_REVB, - 0x00000000); - /* Save the Spec Inversion value */ - dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; - dif_misc_ctrl_value = 0x3A093F10; - } else if (standard & - (V4L2_STD_SECAM_B | V4L2_STD_SECAM_D | V4L2_STD_SECAM_G | - V4L2_STD_SECAM_K | V4L2_STD_SECAM_K1)) { - - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL, 0, 31, 0x6503bc0c); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL1, 0, 31, 0xbd038c85); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL2, 0, 31, 0x1db4640a); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL3, 0, 31, 0x00008800); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_REF, 0, 31, 0x888C0380); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_IF, 0, 31, 0xe0262600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_INT, 0, 31, 0xc2171700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_RF, 0, 31, 0xc2262600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_INT_CURRENT, 0, 31, - 0x26001700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_RF_CURRENT, 0, 31, - 0x00002660); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VID_AUD_OVERRIDE, 0, 31, - 0x27000100); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AV_SEP_CTRL, 0, 31, 0x3F3530ec); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_COMP_FLT_CTRL, 0, 31, - 0x00000000); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_PHASE_INC, 0, 31, - 0x1befbf06); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_GAIN_CONTROL, 0, 31, - 0x000035e8); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_RPT_VARIANCE, 0, 31, 0x00000000); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VIDEO_AGC_CTRL, 0, 31, - 0xf4000000); - - /* Save the Spec Inversion value */ - dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; - dif_misc_ctrl_value |= 0x3a023F11; - } else if (standard & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) { - /* Is it SECAM_L1? */ - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL, 0, 31, 0x6503bc0c); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL1, 0, 31, 0xbd038c85); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL2, 0, 31, 0x1db4640a); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL3, 0, 31, 0x00008800); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_REF, 0, 31, 0x888C0380); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_IF, 0, 31, 0xe0262600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_INT, 0, 31, 0xc2171700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_RF, 0, 31, 0xc2262600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_INT_CURRENT, 0, 31, - 0x26001700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_RF_CURRENT, 0, 31, - 0x00002660); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VID_AUD_OVERRIDE, 0, 31, - 0x27000100); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AV_SEP_CTRL, 0, 31, 0x3F3530ec); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_COMP_FLT_CTRL, 0, 31, - 0x00000000); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_PHASE_INC, 0, 31, - 0x1befbf06); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_GAIN_CONTROL, 0, 31, - 0x000035e8); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_RPT_VARIANCE, 0, 31, 0x00000000); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VIDEO_AGC_CTRL, 0, 31, - 0xf2560000); - - /* Save the Spec Inversion value */ - dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; - dif_misc_ctrl_value |= 0x3a023F11; - - } else if (standard & V4L2_STD_NTSC_M) { - /* V4L2_STD_NTSC_M (75 IRE Setup) Or - V4L2_STD_NTSC_M_JP (Japan, 0 IRE Setup) */ - - /* For NTSC the centre frequency of video coming out of - sidewinder is around 7.1MHz or 3.6MHz depending on the - spectral inversion. so for a non spectrally inverted channel - the pll freq word is 0x03420c49 - */ - - status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0x6503BC0C); - status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xBD038C85); - status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1DB4640A); - status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800); - status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C0380); - status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT, - 0x26001700); - status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT, - 0x00002660); - status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL, - 0x04000800); - status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE, - 0x27000100); - status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, 0x01296e1f); - - status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL, - 0x009f50c1); - status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, - 0x1befbf06); - status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL, - 0x000035e8); - - status = vid_blk_write_word(dev, DIF_AGC_CTRL_IF, 0xC2262600); - status = vid_blk_write_word(dev, DIF_AGC_CTRL_INT, - 0xC2262600); - status = vid_blk_write_word(dev, DIF_AGC_CTRL_RF, 0xC2262600); - - /* Save the Spec Inversion value */ - dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; - dif_misc_ctrl_value |= 0x3a003F10; - } else { - /* default PAL BG */ - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL, 0, 31, 0x6503bc0c); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL1, 0, 31, 0xbd038c85); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL2, 0, 31, 0x1db4640a); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_PLL_CTRL3, 0, 31, 0x00008800); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_REF, 0, 31, 0x444C1380); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_IF, 0, 31, 0xDA302600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_INT, 0, 31, 0xDA261700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_CTRL_RF, 0, 31, 0xDA262600); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_IF_INT_CURRENT, 0, 31, - 0x26001700); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AGC_RF_CURRENT, 0, 31, - 0x00002660); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VIDEO_AGC_CTRL, 0, 31, - 0x72500800); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_VID_AUD_OVERRIDE, 0, 31, - 0x27000100); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_AV_SEP_CTRL, 0, 31, 0x3F3530EC); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_COMP_FLT_CTRL, 0, 31, - 0x00A653A8); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_PHASE_INC, 0, 31, - 0x1befbf06); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_SRC_GAIN_CONTROL, 0, 31, - 0x000035e8); - status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, - DIF_RPT_VARIANCE, 0, 31, 0x00000000); - /* Save the Spec Inversion value */ - dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; - dif_misc_ctrl_value |= 0x3a013F11; - } - - /* The AGC values should be the same for all standards, - AUD_SRC_SEL[19] should always be disabled */ - dif_misc_ctrl_value &= ~FLD_DIF_AUD_SRC_SEL; - - /* It is still possible to get Set Standard calls even when we - are in FM mode. - This is done to override the value for FM. */ - if (dev->active_mode == V4L2_TUNER_RADIO) - dif_misc_ctrl_value = 0x7a080000; - - /* Write the calculated value for misc ontrol register */ - status = vid_blk_write_word(dev, DIF_MISC_CTRL, dif_misc_ctrl_value); - - return status; -} - -int cx231xx_tuner_pre_channel_change(struct cx231xx *dev) -{ - int status = 0; - u32 dwval; - - /* Set the RF and IF k_agc values to 3 */ - status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval); - dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF); - dwval |= 0x33000000; - - status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval); - - return status; -} - -int cx231xx_tuner_post_channel_change(struct cx231xx *dev) -{ - int status = 0; - u32 dwval; - cx231xx_info("cx231xx_tuner_post_channel_change dev->tuner_type =0%d\n", - dev->tuner_type); - /* Set the RF and IF k_agc values to 4 for PAL/NTSC and 8 for - * SECAM L/B/D standards */ - status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval); - dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF); - - if (dev->norm & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_B | - V4L2_STD_SECAM_D)) { - if (dev->tuner_type == TUNER_NXP_TDA18271) { - dwval &= ~FLD_DIF_IF_REF; - dwval |= 0x88000300; - } else - dwval |= 0x88000000; - } else { - if (dev->tuner_type == TUNER_NXP_TDA18271) { - dwval &= ~FLD_DIF_IF_REF; - dwval |= 0xCC000300; - } else - dwval |= 0x44000000; - } - - status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval); - - return status; -} - -/****************************************************************************** - * I 2 S - B L O C K C O N T R O L functions * - ******************************************************************************/ -int cx231xx_i2s_blk_initialize(struct cx231xx *dev) -{ - int status = 0; - u32 value; - - status = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, - CH_PWR_CTRL1, 1, &value, 1); - /* enables clock to delta-sigma and decimation filter */ - value |= 0x80; - status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, - CH_PWR_CTRL1, 1, value, 1); - /* power up all channel */ - status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, - CH_PWR_CTRL2, 1, 0x00, 1); - - return status; -} - -int cx231xx_i2s_blk_update_power_control(struct cx231xx *dev, - enum AV_MODE avmode) -{ - int status = 0; - u32 value = 0; - - if (avmode != POLARIS_AVMODE_ENXTERNAL_AV) { - status = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, - CH_PWR_CTRL2, 1, &value, 1); - value |= 0xfe; - status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, - CH_PWR_CTRL2, 1, value, 1); - } else { - status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, - CH_PWR_CTRL2, 1, 0x00, 1); - } - - return status; -} - -/* set i2s_blk for audio input types */ -int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input) -{ - int status = 0; - - switch (audio_input) { - case CX231XX_AMUX_LINE_IN: - status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, - CH_PWR_CTRL2, 1, 0x00, 1); - status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, - CH_PWR_CTRL1, 1, 0x80, 1); - break; - case CX231XX_AMUX_VIDEO: - default: - break; - } - - dev->ctl_ainput = audio_input; - - return status; -} - -/****************************************************************************** - * P O W E R C O N T R O L functions * - ******************************************************************************/ -int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode) -{ - u8 value[4] = { 0, 0, 0, 0 }; - u32 tmp = 0; - int status = 0; - - if (dev->power_mode != mode) - dev->power_mode = mode; - else { - cx231xx_info(" setPowerMode::mode = %d, No Change req.\n", - mode); - return 0; - } - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value, - 4); - if (status < 0) - return status; - - tmp = *((u32 *) value); - - switch (mode) { - case POLARIS_AVMODE_ENXTERNAL_AV: - - tmp &= (~PWR_MODE_MASK); - - tmp |= PWR_AV_EN; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - - tmp |= PWR_ISO_EN; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = - cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN, - value, 4); - msleep(PWR_SLEEP_INTERVAL); - - tmp |= POLARIS_AVMODE_ENXTERNAL_AV; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - - /* reset state of xceive tuner */ - dev->xc_fw_load_done = 0; - break; - - case POLARIS_AVMODE_ANALOGT_TV: - - tmp |= PWR_DEMOD_EN; - tmp |= (I2C_DEMOD_EN); - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - - if (!(tmp & PWR_TUNER_EN)) { - tmp |= (PWR_TUNER_EN); - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - } - - if (!(tmp & PWR_AV_EN)) { - tmp |= PWR_AV_EN; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - } - if (!(tmp & PWR_ISO_EN)) { - tmp |= PWR_ISO_EN; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - } - - if (!(tmp & POLARIS_AVMODE_ANALOGT_TV)) { - tmp |= POLARIS_AVMODE_ANALOGT_TV; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - } - - if (dev->board.tuner_type != TUNER_ABSENT) { - /* Enable tuner */ - cx231xx_enable_i2c_port_3(dev, true); - - /* reset the Tuner */ - if (dev->board.tuner_gpio) - cx231xx_gpio_set(dev, dev->board.tuner_gpio); - - if (dev->cx231xx_reset_analog_tuner) - dev->cx231xx_reset_analog_tuner(dev); - } - - break; - - case POLARIS_AVMODE_DIGITAL: - if (!(tmp & PWR_TUNER_EN)) { - tmp |= (PWR_TUNER_EN); - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - } - if (!(tmp & PWR_AV_EN)) { - tmp |= PWR_AV_EN; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - } - if (!(tmp & PWR_ISO_EN)) { - tmp |= PWR_ISO_EN; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - } - - tmp &= (~PWR_AV_MODE); - tmp |= POLARIS_AVMODE_DIGITAL | I2C_DEMOD_EN; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - - if (!(tmp & PWR_DEMOD_EN)) { - tmp |= PWR_DEMOD_EN; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - } - - if (dev->board.tuner_type != TUNER_ABSENT) { - /* - * Enable tuner - * Hauppauge Exeter seems to need to do something different! - */ - if (dev->model == CX231XX_BOARD_HAUPPAUGE_EXETER) - cx231xx_enable_i2c_port_3(dev, false); - else - cx231xx_enable_i2c_port_3(dev, true); - - /* reset the Tuner */ - if (dev->board.tuner_gpio) - cx231xx_gpio_set(dev, dev->board.tuner_gpio); - - if (dev->cx231xx_reset_analog_tuner) - dev->cx231xx_reset_analog_tuner(dev); - } - break; - - default: - break; - } - - msleep(PWR_SLEEP_INTERVAL); - - /* For power saving, only enable Pwr_resetout_n - when digital TV is selected. */ - if (mode == POLARIS_AVMODE_DIGITAL) { - tmp |= PWR_RESETOUT_EN; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(PWR_SLEEP_INTERVAL); - } - - /* update power control for afe */ - status = cx231xx_afe_update_power_control(dev, mode); - - /* update power control for i2s_blk */ - status = cx231xx_i2s_blk_update_power_control(dev, mode); - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value, - 4); - - return status; -} - -int cx231xx_power_suspend(struct cx231xx *dev) -{ - u8 value[4] = { 0, 0, 0, 0 }; - u32 tmp = 0; - int status = 0; - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, - value, 4); - if (status > 0) - return status; - - tmp = *((u32 *) value); - tmp &= (~PWR_MODE_MASK); - - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN, - value, 4); - - return status; -} - -/****************************************************************************** - * S T R E A M C O N T R O L functions * - ******************************************************************************/ -int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask) -{ - u8 value[4] = { 0x0, 0x0, 0x0, 0x0 }; - u32 tmp = 0; - int status = 0; - - cx231xx_info("cx231xx_start_stream():: ep_mask = %x\n", ep_mask); - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET, - value, 4); - if (status < 0) - return status; - - tmp = *((u32 *) value); - tmp |= ep_mask; - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, EP_MODE_SET, - value, 4); - - return status; -} - -int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask) -{ - u8 value[4] = { 0x0, 0x0, 0x0, 0x0 }; - u32 tmp = 0; - int status = 0; - - cx231xx_info("cx231xx_stop_stream():: ep_mask = %x\n", ep_mask); - status = - cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET, value, 4); - if (status < 0) - return status; - - tmp = *((u32 *) value); - tmp &= (~ep_mask); - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, EP_MODE_SET, - value, 4); - - return status; -} - -int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type) -{ - int status = 0; - u32 value = 0; - u8 val[4] = { 0, 0, 0, 0 }; - - if (dev->udev->speed == USB_SPEED_HIGH) { - switch (media_type) { - case 81: /* audio */ - cx231xx_info("%s: Audio enter HANC\n", __func__); - status = - cx231xx_mode_register(dev, TS_MODE_REG, 0x9300); - break; - - case 2: /* vbi */ - cx231xx_info("%s: set vanc registers\n", __func__); - status = cx231xx_mode_register(dev, TS_MODE_REG, 0x300); - break; - - case 3: /* sliced cc */ - cx231xx_info("%s: set hanc registers\n", __func__); - status = - cx231xx_mode_register(dev, TS_MODE_REG, 0x1300); - break; - - case 0: /* video */ - cx231xx_info("%s: set video registers\n", __func__); - status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100); - break; - - case 4: /* ts1 */ - cx231xx_info("%s: set ts1 registers", __func__); - - if (dev->board.has_417) { - cx231xx_info(" MPEG\n"); - value &= 0xFFFFFFFC; - value |= 0x3; - - status = cx231xx_mode_register(dev, TS_MODE_REG, value); - - val[0] = 0x04; - val[1] = 0xA3; - val[2] = 0x3B; - val[3] = 0x00; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - TS1_CFG_REG, val, 4); - - val[0] = 0x00; - val[1] = 0x08; - val[2] = 0x00; - val[3] = 0x08; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - TS1_LENGTH_REG, val, 4); - - } else { - cx231xx_info(" BDA\n"); - status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101); - status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x010); - } - break; - - case 6: /* ts1 parallel mode */ - cx231xx_info("%s: set ts1 parrallel mode registers\n", - __func__); - status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100); - status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400); - break; - } - } else { - status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101); - } - - return status; -} - -int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type) -{ - int rc = -1; - u32 ep_mask = -1; - struct pcb_config *pcb_config; - - /* get EP for media type */ - pcb_config = (struct pcb_config *)&dev->current_pcb_config; - - if (pcb_config->config_num == 1) { - switch (media_type) { - case 0: /* Video */ - ep_mask = ENABLE_EP4; /* ep4 [00:1000] */ - break; - case 1: /* Audio */ - ep_mask = ENABLE_EP3; /* ep3 [00:0100] */ - break; - case 2: /* Vbi */ - ep_mask = ENABLE_EP5; /* ep5 [01:0000] */ - break; - case 3: /* Sliced_cc */ - ep_mask = ENABLE_EP6; /* ep6 [10:0000] */ - break; - case 4: /* ts1 */ - case 6: /* ts1 parallel mode */ - ep_mask = ENABLE_EP1; /* ep1 [00:0001] */ - break; - case 5: /* ts2 */ - ep_mask = ENABLE_EP2; /* ep2 [00:0010] */ - break; - } - - } else if (pcb_config->config_num > 1) { - switch (media_type) { - case 0: /* Video */ - ep_mask = ENABLE_EP4; /* ep4 [00:1000] */ - break; - case 1: /* Audio */ - ep_mask = ENABLE_EP3; /* ep3 [00:0100] */ - break; - case 2: /* Vbi */ - ep_mask = ENABLE_EP5; /* ep5 [01:0000] */ - break; - case 3: /* Sliced_cc */ - ep_mask = ENABLE_EP6; /* ep6 [10:0000] */ - break; - case 4: /* ts1 */ - case 6: /* ts1 parallel mode */ - ep_mask = ENABLE_EP1; /* ep1 [00:0001] */ - break; - case 5: /* ts2 */ - ep_mask = ENABLE_EP2; /* ep2 [00:0010] */ - break; - } - - } - - if (start) { - rc = cx231xx_initialize_stream_xfer(dev, media_type); - - if (rc < 0) - return rc; - - /* enable video capture */ - if (ep_mask > 0) - rc = cx231xx_start_stream(dev, ep_mask); - } else { - /* disable video capture */ - if (ep_mask > 0) - rc = cx231xx_stop_stream(dev, ep_mask); - } - - if (dev->mode == CX231XX_ANALOG_MODE) - ;/* do any in Analog mode */ - else - ;/* do any in digital mode */ - - return rc; -} -EXPORT_SYMBOL_GPL(cx231xx_capture_start); - -/***************************************************************************** -* G P I O B I T control functions * -******************************************************************************/ -int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val) -{ - int status = 0; - - status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 0); - - return status; -} - -int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val) -{ - int status = 0; - - status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 1); - - return status; -} - -/* -* cx231xx_set_gpio_direction -* Sets the direction of the GPIO pin to input or output -* -* Parameters : -* pin_number : The GPIO Pin number to program the direction for -* from 0 to 31 -* pin_value : The Direction of the GPIO Pin under reference. -* 0 = Input direction -* 1 = Output direction -*/ -int cx231xx_set_gpio_direction(struct cx231xx *dev, - int pin_number, int pin_value) -{ - int status = 0; - u32 value = 0; - - /* Check for valid pin_number - if 32 , bail out */ - if (pin_number >= 32) - return -EINVAL; - - /* input */ - if (pin_value == 0) - value = dev->gpio_dir & (~(1 << pin_number)); /* clear */ - else - value = dev->gpio_dir | (1 << pin_number); - - status = cx231xx_set_gpio_bit(dev, value, (u8 *) &dev->gpio_val); - - /* cache the value for future */ - dev->gpio_dir = value; - - return status; -} - -/* -* cx231xx_set_gpio_value -* Sets the value of the GPIO pin to Logic high or low. The Pin under -* reference should ALREADY BE SET IN OUTPUT MODE !!!!!!!!! -* -* Parameters : -* pin_number : The GPIO Pin number to program the direction for -* pin_value : The value of the GPIO Pin under reference. -* 0 = set it to 0 -* 1 = set it to 1 -*/ -int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value) -{ - int status = 0; - u32 value = 0; - - /* Check for valid pin_number - if 0xFF , bail out */ - if (pin_number >= 32) - return -EINVAL; - - /* first do a sanity check - if the Pin is not output, make it output */ - if ((dev->gpio_dir & (1 << pin_number)) == 0x00) { - /* It was in input mode */ - value = dev->gpio_dir | (1 << pin_number); - dev->gpio_dir = value; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *) &dev->gpio_val); - value = 0; - } - - if (pin_value == 0) - value = dev->gpio_val & (~(1 << pin_number)); - else - value = dev->gpio_val | (1 << pin_number); - - /* store the value */ - dev->gpio_val = value; - - /* toggle bit0 of GP_IO */ - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - return status; -} - -/***************************************************************************** -* G P I O I2C related functions * -******************************************************************************/ -int cx231xx_gpio_i2c_start(struct cx231xx *dev) -{ - int status = 0; - - /* set SCL to output 1 ; set SDA to output 1 */ - dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio; - dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; - dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - dev->gpio_val |= 1 << dev->board.tuner_sda_gpio; - - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - if (status < 0) - return -EINVAL; - - /* set SCL to output 1; set SDA to output 0 */ - dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - if (status < 0) - return -EINVAL; - - /* set SCL to output 0; set SDA to output 0 */ - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - if (status < 0) - return -EINVAL; - - return status; -} - -int cx231xx_gpio_i2c_end(struct cx231xx *dev) -{ - int status = 0; - - /* set SCL to output 0; set SDA to output 0 */ - dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio; - dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; - - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - if (status < 0) - return -EINVAL; - - /* set SCL to output 1; set SDA to output 0 */ - dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - if (status < 0) - return -EINVAL; - - /* set SCL to input ,release SCL cable control - set SDA to input ,release SDA cable control */ - dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio); - dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); - - status = - cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - if (status < 0) - return -EINVAL; - - return status; -} - -int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data) -{ - int status = 0; - u8 i; - - /* set SCL to output ; set SDA to output */ - dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio; - dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; - - for (i = 0; i < 8; i++) { - if (((data << i) & 0x80) == 0) { - /* set SCL to output 0; set SDA to output 0 */ - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - - /* set SCL to output 1; set SDA to output 0 */ - dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - - /* set SCL to output 0; set SDA to output 0 */ - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - } else { - /* set SCL to output 0; set SDA to output 1 */ - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - dev->gpio_val |= 1 << dev->board.tuner_sda_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - - /* set SCL to output 1; set SDA to output 1 */ - dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - - /* set SCL to output 0; set SDA to output 1 */ - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - } - } - return status; -} - -int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf) -{ - u8 value = 0; - int status = 0; - u32 gpio_logic_value = 0; - u8 i; - - /* read byte */ - for (i = 0; i < 8; i++) { /* send write I2c addr */ - - /* set SCL to output 0; set SDA to input */ - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - - /* set SCL to output 1; set SDA to input */ - dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - - /* get SDA data bit */ - gpio_logic_value = dev->gpio_val; - status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - if ((dev->gpio_val & (1 << dev->board.tuner_sda_gpio)) != 0) - value |= (1 << (8 - i - 1)); - - dev->gpio_val = gpio_logic_value; - } - - /* set SCL to output 0,finish the read latest SCL signal. - !!!set SDA to input, never to modify SDA direction at - the same times */ - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - /* store the value */ - *buf = value & 0xff; - - return status; -} - -int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev) -{ - int status = 0; - u32 gpio_logic_value = 0; - int nCnt = 10; - int nInit = nCnt; - - /* clock stretch; set SCL to input; set SDA to input; - get SCL value till SCL = 1 */ - dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); - dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio); - - gpio_logic_value = dev->gpio_val; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - do { - msleep(2); - status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); - nCnt--; - } while (((dev->gpio_val & - (1 << dev->board.tuner_scl_gpio)) == 0) && - (nCnt > 0)); - - if (nCnt == 0) - cx231xx_info("No ACK after %d msec -GPIO I2C failed!", - nInit * 10); - - /* - * readAck - * through clock stretch, slave has given a SCL signal, - * so the SDA data can be directly read. - */ - status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - if ((dev->gpio_val & 1 << dev->board.tuner_sda_gpio) == 0) { - dev->gpio_val = gpio_logic_value; - dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - status = 0; - } else { - dev->gpio_val = gpio_logic_value; - dev->gpio_val |= (1 << dev->board.tuner_sda_gpio); - } - - /* read SDA end, set the SCL to output 0, after this operation, - SDA direction can be changed. */ - dev->gpio_val = gpio_logic_value; - dev->gpio_dir |= (1 << dev->board.tuner_scl_gpio); - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - return status; -} - -int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev) -{ - int status = 0; - - /* set SDA to ouput */ - dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - /* set SCL = 0 (output); set SDA = 0 (output) */ - dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - /* set SCL = 1 (output); set SDA = 0 (output) */ - dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - /* set SCL = 0 (output); set SDA = 0 (output) */ - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - /* set SDA to input,and then the slave will read data from SDA. */ - dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - return status; -} - -int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev) -{ - int status = 0; - - /* set scl to output ; set sda to input */ - dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio; - dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - /* set scl to output 0; set sda to input */ - dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - /* set scl to output 1; set sda to input */ - dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); - - return status; -} - -/***************************************************************************** -* G P I O I2C related functions * -******************************************************************************/ -/* cx231xx_gpio_i2c_read - * Function to read data from gpio based I2C interface - */ -int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len) -{ - int status = 0; - int i = 0; - - /* get the lock */ - mutex_lock(&dev->gpio_i2c_lock); - - /* start */ - status = cx231xx_gpio_i2c_start(dev); - - /* write dev_addr */ - status = cx231xx_gpio_i2c_write_byte(dev, (dev_addr << 1) + 1); - - /* readAck */ - status = cx231xx_gpio_i2c_read_ack(dev); - - /* read data */ - for (i = 0; i < len; i++) { - /* read data */ - buf[i] = 0; - status = cx231xx_gpio_i2c_read_byte(dev, &buf[i]); - - if ((i + 1) != len) { - /* only do write ack if we more length */ - status = cx231xx_gpio_i2c_write_ack(dev); - } - } - - /* write NAK - inform reads are complete */ - status = cx231xx_gpio_i2c_write_nak(dev); - - /* write end */ - status = cx231xx_gpio_i2c_end(dev); - - /* release the lock */ - mutex_unlock(&dev->gpio_i2c_lock); - - return status; -} - -/* cx231xx_gpio_i2c_write - * Function to write data to gpio based I2C interface - */ -int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len) -{ - int status = 0; - int i = 0; - - /* get the lock */ - mutex_lock(&dev->gpio_i2c_lock); - - /* start */ - status = cx231xx_gpio_i2c_start(dev); - - /* write dev_addr */ - status = cx231xx_gpio_i2c_write_byte(dev, dev_addr << 1); - - /* read Ack */ - status = cx231xx_gpio_i2c_read_ack(dev); - - for (i = 0; i < len; i++) { - /* Write data */ - status = cx231xx_gpio_i2c_write_byte(dev, buf[i]); - - /* read Ack */ - status = cx231xx_gpio_i2c_read_ack(dev); - } - - /* write End */ - status = cx231xx_gpio_i2c_end(dev); - - /* release the lock */ - mutex_unlock(&dev->gpio_i2c_lock); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-cards.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1265 +0,0 @@ -/* - cx231xx-cards.c - driver for Conexant Cx23100/101/102 - USB video capture devices - - Copyright (C) 2008 - Based on em28xx driver - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "dvb-usb-ids.h" -#include "xc5000.h" -#include "tda18271.h" - -#include "cx231xx.h" - -static int tuner = -1; -module_param(tuner, int, 0444); -MODULE_PARM_DESC(tuner, "tuner type"); - -static int transfer_mode = 1; -module_param(transfer_mode, int, 0444); -MODULE_PARM_DESC(transfer_mode, "transfer mode (1-ISO or 0-BULK)"); - -static unsigned int disable_ir; -module_param(disable_ir, int, 0444); -MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); - -/* Bitmask marking allocated devices from 0 to CX231XX_MAXBOARDS */ -static unsigned long cx231xx_devused; - -/* - * Reset sequences for analog/digital modes - */ - -static struct cx231xx_reg_seq RDE250_XCV_TUNER[] = { - {0x03, 0x01, 10}, - {0x03, 0x00, 30}, - {0x03, 0x01, 10}, - {-1, -1, -1}, -}; - -/* - * Board definitions - */ -struct cx231xx_board cx231xx_boards[] = { - [CX231XX_BOARD_UNKNOWN] = { - .name = "Unknown CX231xx video grabber", - .tuner_type = TUNER_ABSENT, - .input = {{ - .type = CX231XX_VMUX_TELEVISION, - .vmux = CX231XX_VIN_3_1, - .amux = CX231XX_AMUX_VIDEO, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } - }, - }, - [CX231XX_BOARD_CNXT_CARRAERA] = { - .name = "Conexant Hybrid TV - CARRAERA", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x61, - .tuner_gpio = RDE250_XCV_TUNER, - .tuner_sif_gpio = 0x05, - .tuner_scl_gpio = 0x1a, - .tuner_sda_gpio = 0x1b, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x0c, - .gpio_pin_status_mask = 0x4001000, - .tuner_i2c_master = 1, - .demod_i2c_master = 2, - .has_dvb = 1, - .demod_addr = 0x02, - .norm = V4L2_STD_PAL, - - .input = {{ - .type = CX231XX_VMUX_TELEVISION, - .vmux = CX231XX_VIN_3_1, - .amux = CX231XX_AMUX_VIDEO, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } - }, - }, - [CX231XX_BOARD_CNXT_SHELBY] = { - .name = "Conexant Hybrid TV - SHELBY", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x61, - .tuner_gpio = RDE250_XCV_TUNER, - .tuner_sif_gpio = 0x05, - .tuner_scl_gpio = 0x1a, - .tuner_sda_gpio = 0x1b, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x0c, - .gpio_pin_status_mask = 0x4001000, - .tuner_i2c_master = 1, - .demod_i2c_master = 2, - .has_dvb = 1, - .demod_addr = 0x32, - .norm = V4L2_STD_NTSC, - - .input = {{ - .type = CX231XX_VMUX_TELEVISION, - .vmux = CX231XX_VIN_3_1, - .amux = CX231XX_AMUX_VIDEO, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } - }, - }, - [CX231XX_BOARD_CNXT_RDE_253S] = { - .name = "Conexant Hybrid TV - RDE253S", - .tuner_type = TUNER_NXP_TDA18271, - .tuner_addr = 0x60, - .tuner_gpio = RDE250_XCV_TUNER, - .tuner_sif_gpio = 0x05, - .tuner_scl_gpio = 0x1a, - .tuner_sda_gpio = 0x1b, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x1c, - .gpio_pin_status_mask = 0x4001000, - .tuner_i2c_master = 1, - .demod_i2c_master = 2, - .has_dvb = 1, - .demod_addr = 0x02, - .norm = V4L2_STD_PAL, - - .input = {{ - .type = CX231XX_VMUX_TELEVISION, - .vmux = CX231XX_VIN_3_1, - .amux = CX231XX_AMUX_VIDEO, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } - }, - }, - - [CX231XX_BOARD_CNXT_RDU_253S] = { - .name = "Conexant Hybrid TV - RDU253S", - .tuner_type = TUNER_NXP_TDA18271, - .tuner_addr = 0x60, - .tuner_gpio = RDE250_XCV_TUNER, - .tuner_sif_gpio = 0x05, - .tuner_scl_gpio = 0x1a, - .tuner_sda_gpio = 0x1b, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x1c, - .gpio_pin_status_mask = 0x4001000, - .tuner_i2c_master = 1, - .demod_i2c_master = 2, - .has_dvb = 1, - .demod_addr = 0x02, - .norm = V4L2_STD_PAL, - - .input = {{ - .type = CX231XX_VMUX_TELEVISION, - .vmux = CX231XX_VIN_3_1, - .amux = CX231XX_AMUX_VIDEO, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } - }, - }, - [CX231XX_BOARD_CNXT_VIDEO_GRABBER] = { - .name = "Conexant VIDEO GRABBER", - .tuner_type = TUNER_ABSENT, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x1c, - .gpio_pin_status_mask = 0x4001000, - .norm = V4L2_STD_PAL, - .no_alt_vanc = 1, - .external_av = 1, - .has_417 = 1, - - .input = {{ - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } - }, - }, - [CX231XX_BOARD_CNXT_RDE_250] = { - .name = "Conexant Hybrid TV - rde 250", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x61, - .tuner_gpio = RDE250_XCV_TUNER, - .tuner_sif_gpio = 0x05, - .tuner_scl_gpio = 0x1a, - .tuner_sda_gpio = 0x1b, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x0c, - .gpio_pin_status_mask = 0x4001000, - .tuner_i2c_master = 1, - .demod_i2c_master = 2, - .has_dvb = 1, - .demod_addr = 0x02, - .norm = V4L2_STD_PAL, - - .input = {{ - .type = CX231XX_VMUX_TELEVISION, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_VIDEO, - .gpio = NULL, - } - }, - }, - [CX231XX_BOARD_CNXT_RDU_250] = { - .name = "Conexant Hybrid TV - RDU 250", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x61, - .tuner_gpio = RDE250_XCV_TUNER, - .tuner_sif_gpio = 0x05, - .tuner_scl_gpio = 0x1a, - .tuner_sda_gpio = 0x1b, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x0c, - .gpio_pin_status_mask = 0x4001000, - .tuner_i2c_master = 1, - .demod_i2c_master = 2, - .has_dvb = 1, - .demod_addr = 0x32, - .norm = V4L2_STD_NTSC, - - .input = {{ - .type = CX231XX_VMUX_TELEVISION, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_VIDEO, - .gpio = NULL, - } - }, - }, - [CX231XX_BOARD_HAUPPAUGE_EXETER] = { - .name = "Hauppauge EXETER", - .tuner_type = TUNER_NXP_TDA18271, - .tuner_addr = 0x60, - .tuner_gpio = RDE250_XCV_TUNER, - .tuner_sif_gpio = 0x05, - .tuner_scl_gpio = 0x1a, - .tuner_sda_gpio = 0x1b, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x0c, - .gpio_pin_status_mask = 0x4001000, - .tuner_i2c_master = 1, - .demod_i2c_master = 2, - .has_dvb = 1, - .demod_addr = 0x0e, - .norm = V4L2_STD_NTSC, - - .input = {{ - .type = CX231XX_VMUX_TELEVISION, - .vmux = CX231XX_VIN_3_1, - .amux = CX231XX_AMUX_VIDEO, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } }, - }, - [CX231XX_BOARD_HAUPPAUGE_USBLIVE2] = { - .name = "Hauppauge USB Live 2", - .tuner_type = TUNER_ABSENT, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x0c, - .gpio_pin_status_mask = 0x4001000, - .norm = V4L2_STD_NTSC, - .no_alt_vanc = 1, - .external_av = 1, - .input = {{ - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } }, - }, - [CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = { - .name = "Pixelview PlayTV USB Hybrid", - .tuner_type = TUNER_NXP_TDA18271, - .tuner_addr = 0x60, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x00, /* According with PV cxPolaris.inf file */ - .tuner_sif_gpio = -1, - .tuner_scl_gpio = -1, - .tuner_sda_gpio = -1, - .gpio_pin_status_mask = 0x4001000, - .tuner_i2c_master = 2, - .demod_i2c_master = 1, - .ir_i2c_master = 2, - .rc_map_name = RC_MAP_PIXELVIEW_002T, - .has_dvb = 1, - .demod_addr = 0x10, - .norm = V4L2_STD_PAL_M, - .input = {{ - .type = CX231XX_VMUX_TELEVISION, - .vmux = CX231XX_VIN_3_1, - .amux = CX231XX_AMUX_VIDEO, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } }, - }, - [CX231XX_BOARD_PV_XCAPTURE_USB] = { - .name = "Pixelview Xcapture USB", - .tuner_type = TUNER_ABSENT, - .decoder = CX231XX_AVDECODER, - .output_mode = OUT_MODE_VIP11, - .demod_xfer_mode = 0, - .ctl_pin_status_mask = 0xFFFFFFC4, - .agc_analog_digital_select_gpio = 0x0c, - .gpio_pin_status_mask = 0x4001000, - .norm = V4L2_STD_NTSC, - .no_alt_vanc = 1, - .external_av = 1, - .dont_use_port_3 = 1, - - .input = {{ - .type = CX231XX_VMUX_COMPOSITE1, - .vmux = CX231XX_VIN_2_1, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - }, { - .type = CX231XX_VMUX_SVIDEO, - .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, - .amux = CX231XX_AMUX_LINE_IN, - .gpio = NULL, - } - }, - }, -}; -const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); - -/* table of devices that work with this driver */ -struct usb_device_id cx231xx_id_table[] = { - {USB_DEVICE(0x0572, 0x5A3C), - .driver_info = CX231XX_BOARD_UNKNOWN}, - {USB_DEVICE(0x0572, 0x58A2), - .driver_info = CX231XX_BOARD_CNXT_CARRAERA}, - {USB_DEVICE(0x0572, 0x58A1), - .driver_info = CX231XX_BOARD_CNXT_SHELBY}, - {USB_DEVICE(0x0572, 0x58A4), - .driver_info = CX231XX_BOARD_CNXT_RDE_253S}, - {USB_DEVICE(0x0572, 0x58A5), - .driver_info = CX231XX_BOARD_CNXT_RDU_253S}, - {USB_DEVICE(0x0572, 0x58A6), - .driver_info = CX231XX_BOARD_CNXT_VIDEO_GRABBER}, - {USB_DEVICE(0x0572, 0x589E), - .driver_info = CX231XX_BOARD_CNXT_RDE_250}, - {USB_DEVICE(0x0572, 0x58A0), - .driver_info = CX231XX_BOARD_CNXT_RDU_250}, - {USB_DEVICE(0x2040, 0xb120), - .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, - {USB_DEVICE(0x2040, 0xb140), - .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, - {USB_DEVICE(0x2040, 0xc200), - .driver_info = CX231XX_BOARD_HAUPPAUGE_USBLIVE2}, - {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000, 0x4001), - .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID}, - {USB_DEVICE(USB_VID_PIXELVIEW, 0x5014), - .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, - {}, -}; - -MODULE_DEVICE_TABLE(usb, cx231xx_id_table); - -/* cx231xx_tuner_callback - * will be used to reset XC5000 tuner using GPIO pin - */ - -int cx231xx_tuner_callback(void *ptr, int component, int command, int arg) -{ - int rc = 0; - struct cx231xx *dev = ptr; - - if (dev->tuner_type == TUNER_XC5000) { - if (command == XC5000_TUNER_RESET) { - cx231xx_info - ("Tuner CB: RESET: cmd %d : tuner type %d \n", - command, dev->tuner_type); - cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, - 1); - msleep(10); - cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, - 0); - msleep(330); - cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, - 1); - msleep(10); - } - } else if (dev->tuner_type == TUNER_NXP_TDA18271) { - switch (command) { - case TDA18271_CALLBACK_CMD_AGC_ENABLE: - if (dev->model == CX231XX_BOARD_PV_PLAYTV_USB_HYBRID) - rc = cx231xx_set_agc_analog_digital_mux_select(dev, arg); - break; - default: - rc = -EINVAL; - break; - } - } - return rc; -} -EXPORT_SYMBOL_GPL(cx231xx_tuner_callback); - -void cx231xx_reset_out(struct cx231xx *dev) -{ - cx231xx_set_gpio_value(dev, CX23417_RESET, 1); - msleep(200); - cx231xx_set_gpio_value(dev, CX23417_RESET, 0); - msleep(200); - cx231xx_set_gpio_value(dev, CX23417_RESET, 1); -} -void cx231xx_enable_OSC(struct cx231xx *dev) -{ - cx231xx_set_gpio_value(dev, CX23417_OSC_EN, 1); -} -void cx231xx_sleep_s5h1432(struct cx231xx *dev) -{ - cx231xx_set_gpio_value(dev, SLEEP_S5H1432, 0); -} - -static inline void cx231xx_set_model(struct cx231xx *dev) -{ - memcpy(&dev->board, &cx231xx_boards[dev->model], sizeof(dev->board)); -} - -/* Since cx231xx_pre_card_setup() requires a proper dev->model, - * this won't work for boards with generic PCI IDs - */ -void cx231xx_pre_card_setup(struct cx231xx *dev) -{ - - cx231xx_set_model(dev); - - cx231xx_info("Identified as %s (card=%d)\n", - dev->board.name, dev->model); - - /* set the direction for GPIO pins */ - if (dev->board.tuner_gpio) { - cx231xx_set_gpio_direction(dev, dev->board.tuner_gpio->bit, 1); - cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, 1); - } - if (dev->board.tuner_sif_gpio >= 0) - cx231xx_set_gpio_direction(dev, dev->board.tuner_sif_gpio, 1); - - /* request some modules if any required */ - - /* set the mode to Analog mode initially */ - cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); - - /* Unlock device */ - /* cx231xx_set_mode(dev, CX231XX_SUSPEND); */ - -} - -static void cx231xx_config_tuner(struct cx231xx *dev) -{ - struct tuner_setup tun_setup; - struct v4l2_frequency f; - - if (dev->tuner_type == TUNER_ABSENT) - return; - - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - tun_setup.tuner_callback = cx231xx_tuner_callback; - - tuner_call(dev, tuner, s_type_addr, &tun_setup); - -#if 0 - if (tun_setup.type == TUNER_XC5000) { - static struct xc2028_ctrl ctrl = { - .fname = XC5000_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = 0; - }; - struct v4l2_priv_tun_config cfg = { - .tuner = dev->tuner_type, - .priv = &ctrl, - }; - tuner_call(dev, tuner, s_config, &cfg); - } -#endif - /* configure tuner */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 9076; /* just a magic number */ - dev->ctl_freq = f.frequency; - call_all(dev, tuner, s_frequency, &f); - -} - -void cx231xx_card_setup(struct cx231xx *dev) -{ - - cx231xx_set_model(dev); - - dev->tuner_type = cx231xx_boards[dev->model].tuner_type; - if (cx231xx_boards[dev->model].tuner_addr) - dev->tuner_addr = cx231xx_boards[dev->model].tuner_addr; - - /* request some modules */ - if (dev->board.decoder == CX231XX_AVDECODER) { - dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_bus[0].i2c_adap, - "cx25840", 0x88 >> 1, NULL); - if (dev->sd_cx25840 == NULL) - cx231xx_info("cx25840 subdev registration failure\n"); - cx25840_call(dev, core, load_fw); - - } - - /* Initialize the tuner */ - if (dev->board.tuner_type != TUNER_ABSENT) { - dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, - "tuner", - dev->tuner_addr, NULL); - if (dev->sd_tuner == NULL) - cx231xx_info("tuner subdev registration failure\n"); - else - cx231xx_config_tuner(dev); - } -} - -/* - * cx231xx_config() - * inits registers with sane defaults - */ -int cx231xx_config(struct cx231xx *dev) -{ - /* TBD need to add cx231xx specific code */ - dev->mute = 1; /* maybe not the right place... */ - dev->volume = 0x1f; - - return 0; -} - -/* - * cx231xx_config_i2c() - * configure i2c attached devices - */ -void cx231xx_config_i2c(struct cx231xx *dev) -{ - /* u32 input = INPUT(dev->video_input)->vmux; */ - - call_all(dev, video, s_stream, 1); -} - -/* - * cx231xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -void cx231xx_release_resources(struct cx231xx *dev) -{ - cx231xx_release_analog_resources(dev); - - cx231xx_remove_from_devlist(dev); - - /* Release I2C buses */ - cx231xx_dev_uninit(dev); - - cx231xx_ir_exit(dev); - - usb_put_dev(dev->udev); - - /* Mark device as unused */ - cx231xx_devused &= ~(1 << dev->devno); -} - -/* - * cx231xx_init_dev() - * allocates and inits the device structs, registers i2c bus and v4l device - */ -static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev, - int minor) -{ - struct cx231xx *dev = *devhandle; - int retval = -ENOMEM; - int errCode; - unsigned int maxh, maxw; - - dev->udev = udev; - mutex_init(&dev->lock); - mutex_init(&dev->ctrl_urb_lock); - mutex_init(&dev->gpio_i2c_lock); - mutex_init(&dev->i2c_lock); - - spin_lock_init(&dev->video_mode.slock); - spin_lock_init(&dev->vbi_mode.slock); - spin_lock_init(&dev->sliced_cc_mode.slock); - - init_waitqueue_head(&dev->open); - init_waitqueue_head(&dev->wait_frame); - init_waitqueue_head(&dev->wait_stream); - - dev->cx231xx_read_ctrl_reg = cx231xx_read_ctrl_reg; - dev->cx231xx_write_ctrl_reg = cx231xx_write_ctrl_reg; - dev->cx231xx_send_usb_command = cx231xx_send_usb_command; - dev->cx231xx_gpio_i2c_read = cx231xx_gpio_i2c_read; - dev->cx231xx_gpio_i2c_write = cx231xx_gpio_i2c_write; - - /* Query cx231xx to find what pcb config it is related to */ - initialize_cx231xx(dev); - - /*To workaround error number=-71 on EP0 for VideoGrabber, - need set alt here.*/ - if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER || - dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) { - cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3); - cx231xx_set_alt_setting(dev, INDEX_VANC, 1); - } - /* Cx231xx pre card setup */ - cx231xx_pre_card_setup(dev); - - errCode = cx231xx_config(dev); - if (errCode) { - cx231xx_errdev("error configuring device\n"); - return -ENOMEM; - } - - /* set default norm */ - dev->norm = dev->board.norm; - - /* register i2c bus */ - errCode = cx231xx_dev_init(dev); - if (errCode < 0) { - cx231xx_dev_uninit(dev); - cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* Do board specific init */ - cx231xx_card_setup(dev); - - /* configure the device */ - cx231xx_config_i2c(dev); - - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); - - /* set default image size */ - dev->width = maxw; - dev->height = maxh; - dev->interlaced = 0; - dev->video_input = 0; - - errCode = cx231xx_config(dev); - if (errCode < 0) { - cx231xx_errdev("%s: cx231xx_config - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->video_mode.vidq.active); - INIT_LIST_HEAD(&dev->video_mode.vidq.queued); - - /* init vbi dma queues */ - INIT_LIST_HEAD(&dev->vbi_mode.vidq.active); - INIT_LIST_HEAD(&dev->vbi_mode.vidq.queued); - - /* Reset other chips required if they are tied up with GPIO pins */ - cx231xx_add_into_devlist(dev); - - if (dev->board.has_417) { - printk(KERN_INFO "attach 417 %d\n", dev->model); - if (cx231xx_417_register(dev) < 0) { - printk(KERN_ERR - "%s() Failed to register 417 on VID_B\n", - __func__); - } - } - - retval = cx231xx_register_analog_devices(dev); - if (retval < 0) { - cx231xx_release_resources(dev); - return retval; - } - - cx231xx_ir_init(dev); - - cx231xx_init_extension(dev); - - return 0; -} - -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - struct cx231xx *dev = container_of(work, - struct cx231xx, request_module_wk); - - if (dev->has_alsa_audio) - request_module("cx231xx-alsa"); - - if (dev->board.has_dvb) - request_module("cx231xx-dvb"); - -} - -static void request_modules(struct cx231xx *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} - -static void flush_request_modules(struct cx231xx *dev) -{ - flush_work_sync(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#define flush_request_modules(dev) -#endif /* CONFIG_MODULES */ - -/* - * cx231xx_usb_probe() - * checks for supported devices - */ -static int cx231xx_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev; - struct usb_interface *uif; - struct cx231xx *dev = NULL; - int retval = -ENODEV; - int nr = 0, ifnum; - int i, isoc_pipe = 0; - char *speed; - char descr[255] = ""; - struct usb_interface *lif = NULL; - struct usb_interface_assoc_descriptor *assoc_desc; - - udev = usb_get_dev(interface_to_usbdev(interface)); - ifnum = interface->altsetting[0].desc.bInterfaceNumber; - - /* - * Interface number 0 - IR interface (handled by mceusb driver) - * Interface number 1 - AV interface (handled by this driver) - */ - if (ifnum != 1) - return -ENODEV; - - /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); - cx231xx_devused |= 1 << nr; - - if (nr >= CX231XX_MAXBOARDS) { - cx231xx_err(DRIVER_NAME - ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS); - cx231xx_devused &= ~(1 << nr); - return -ENOMEM; - } - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - cx231xx_err(DRIVER_NAME ": out of memory!\n"); - cx231xx_devused &= ~(1 << nr); - return -ENOMEM; - } - - snprintf(dev->name, 29, "cx231xx #%d", nr); - dev->devno = nr; - dev->model = id->driver_info; - dev->video_mode.alt = -1; - - dev->interface_count++; - /* reset gpio dir and value */ - dev->gpio_dir = 0; - dev->gpio_val = 0; - dev->xc_fw_load_done = 0; - dev->has_alsa_audio = 1; - dev->power_mode = -1; - atomic_set(&dev->devlist_count, 0); - - /* 0 - vbi ; 1 -sliced cc mode */ - dev->vbi_or_sliced_cc_mode = 0; - - /* get maximum no.of IAD interfaces */ - assoc_desc = udev->actconfig->intf_assoc[0]; - dev->max_iad_interface_count = assoc_desc->bInterfaceCount; - - /* init CIR module TBD */ - - /* store the current interface */ - lif = interface; - - /*mode_tv: digital=1 or analog=0*/ - dev->mode_tv = 0; - - dev->USE_ISO = transfer_mode; - - switch (udev->speed) { - case USB_SPEED_LOW: - speed = "1.5"; - break; - case USB_SPEED_UNKNOWN: - case USB_SPEED_FULL: - speed = "12"; - break; - case USB_SPEED_HIGH: - speed = "480"; - break; - default: - speed = "unknown"; - } - - if (udev->manufacturer) - strlcpy(descr, udev->manufacturer, sizeof(descr)); - - if (udev->product) { - if (*descr) - strlcat(descr, " ", sizeof(descr)); - strlcat(descr, udev->product, sizeof(descr)); - } - if (*descr) - strlcat(descr, " ", sizeof(descr)); - - cx231xx_info("New device %s@ %s Mbps " - "(%04x:%04x) with %d interfaces\n", - descr, - speed, - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - dev->max_iad_interface_count); - - /* store the interface 0 back */ - lif = udev->actconfig->interface[0]; - - /* increment interface count */ - dev->interface_count++; - - /* get device number */ - nr = dev->devno; - - assoc_desc = udev->actconfig->intf_assoc[0]; - if (assoc_desc->bFirstInterface != ifnum) { - cx231xx_err(DRIVER_NAME ": Not found " - "matching IAD interface\n"); - return -ENODEV; - } - - cx231xx_info("registering interface %d\n", ifnum); - - /* save our data pointer in this interface device */ - usb_set_intfdata(lif, dev); - - /* - * AV device initialization - only done at the last interface - */ - - /* Create v4l2 device */ - retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); - if (retval) { - cx231xx_errdev("v4l2_device_register failed\n"); - cx231xx_devused &= ~(1 << nr); - kfree(dev); - dev = NULL; - return -EIO; - } - /* allocate device struct */ - retval = cx231xx_init_dev(&dev, udev, nr); - if (retval) { - cx231xx_devused &= ~(1 << dev->devno); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - usb_set_intfdata(lif, NULL); - - return retval; - } - - /* compute alternate max packet sizes for video */ - uif = udev->actconfig->interface[dev->current_pcb_config. - hs_config_info[0].interface_info.video_index + 1]; - - dev->video_mode.end_point_addr = le16_to_cpu(uif->altsetting[0]. - endpoint[isoc_pipe].desc.bEndpointAddress); - - dev->video_mode.num_alt = uif->num_altsetting; - cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", - dev->video_mode.end_point_addr, - dev->video_mode.num_alt); - dev->video_mode.alt_max_pkt_size = - kmalloc(32 * dev->video_mode.num_alt, GFP_KERNEL); - - if (dev->video_mode.alt_max_pkt_size == NULL) { - cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - return -ENOMEM; - } - - for (i = 0; i < dev->video_mode.num_alt; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. - desc.wMaxPacketSize); - dev->video_mode.alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - cx231xx_info("Alternate setting %i, max size= %i\n", i, - dev->video_mode.alt_max_pkt_size[i]); - } - - /* compute alternate max packet sizes for vbi */ - uif = udev->actconfig->interface[dev->current_pcb_config. - hs_config_info[0].interface_info. - vanc_index + 1]; - - dev->vbi_mode.end_point_addr = - le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc. - bEndpointAddress); - - dev->vbi_mode.num_alt = uif->num_altsetting; - cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", - dev->vbi_mode.end_point_addr, - dev->vbi_mode.num_alt); - dev->vbi_mode.alt_max_pkt_size = - kmalloc(32 * dev->vbi_mode.num_alt, GFP_KERNEL); - - if (dev->vbi_mode.alt_max_pkt_size == NULL) { - cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - return -ENOMEM; - } - - for (i = 0; i < dev->vbi_mode.num_alt; i++) { - u16 tmp = - le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. - desc.wMaxPacketSize); - dev->vbi_mode.alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - cx231xx_info("Alternate setting %i, max size= %i\n", i, - dev->vbi_mode.alt_max_pkt_size[i]); - } - - /* compute alternate max packet sizes for sliced CC */ - uif = udev->actconfig->interface[dev->current_pcb_config. - hs_config_info[0].interface_info. - hanc_index + 1]; - - dev->sliced_cc_mode.end_point_addr = - le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc. - bEndpointAddress); - - dev->sliced_cc_mode.num_alt = uif->num_altsetting; - cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", - dev->sliced_cc_mode.end_point_addr, - dev->sliced_cc_mode.num_alt); - dev->sliced_cc_mode.alt_max_pkt_size = - kmalloc(32 * dev->sliced_cc_mode.num_alt, GFP_KERNEL); - - if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) { - cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - return -ENOMEM; - } - - for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. - desc.wMaxPacketSize); - dev->sliced_cc_mode.alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - cx231xx_info("Alternate setting %i, max size= %i\n", i, - dev->sliced_cc_mode.alt_max_pkt_size[i]); - } - - if (dev->current_pcb_config.ts1_source != 0xff) { - /* compute alternate max packet sizes for TS1 */ - uif = udev->actconfig->interface[dev->current_pcb_config. - hs_config_info[0]. - interface_info. - ts1_index + 1]; - - dev->ts1_mode.end_point_addr = - le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe]. - desc.bEndpointAddress); - - dev->ts1_mode.num_alt = uif->num_altsetting; - cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", - dev->ts1_mode.end_point_addr, - dev->ts1_mode.num_alt); - dev->ts1_mode.alt_max_pkt_size = - kmalloc(32 * dev->ts1_mode.num_alt, GFP_KERNEL); - - if (dev->ts1_mode.alt_max_pkt_size == NULL) { - cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - return -ENOMEM; - } - - for (i = 0; i < dev->ts1_mode.num_alt; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i]. - endpoint[isoc_pipe].desc. - wMaxPacketSize); - dev->ts1_mode.alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - cx231xx_info("Alternate setting %i, max size= %i\n", i, - dev->ts1_mode.alt_max_pkt_size[i]); - } - } - - if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) { - cx231xx_enable_OSC(dev); - cx231xx_reset_out(dev); - cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3); - } - - if (dev->model == CX231XX_BOARD_CNXT_RDE_253S) - cx231xx_sleep_s5h1432(dev); - - /* load other modules required */ - request_modules(dev); - - return 0; -} - -/* - * cx231xx_usb_disconnect() - * called when the device gets diconencted - * video device will be unregistered on v4l2_close in case it is still open - */ -static void cx231xx_usb_disconnect(struct usb_interface *interface) -{ - struct cx231xx *dev; - - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - if (!dev) - return; - - if (!dev->udev) - return; - - flush_request_modules(dev); - - /* delete v4l2 device */ - v4l2_device_unregister(&dev->v4l2_dev); - - /* wait until all current v4l2 io is finished then deallocate - resources */ - mutex_lock(&dev->lock); - - wake_up_interruptible_all(&dev->open); - - if (dev->users) { - cx231xx_warn - ("device %s is open! Deregistration and memory " - "deallocation are deferred on close.\n", - video_device_node_name(dev->vdev)); - - dev->state |= DEV_MISCONFIGURED; - if (dev->USE_ISO) - cx231xx_uninit_isoc(dev); - else - cx231xx_uninit_bulk(dev); - dev->state |= DEV_DISCONNECTED; - wake_up_interruptible(&dev->wait_frame); - wake_up_interruptible(&dev->wait_stream); - } else { - dev->state |= DEV_DISCONNECTED; - cx231xx_release_resources(dev); - } - - cx231xx_close_extension(dev); - - mutex_unlock(&dev->lock); - - if (!dev->users) { - kfree(dev->video_mode.alt_max_pkt_size); - kfree(dev->vbi_mode.alt_max_pkt_size); - kfree(dev->sliced_cc_mode.alt_max_pkt_size); - kfree(dev->ts1_mode.alt_max_pkt_size); - kfree(dev); - dev = NULL; - } -} - -static struct usb_driver cx231xx_usb_driver = { - .name = "cx231xx", - .probe = cx231xx_usb_probe, - .disconnect = cx231xx_usb_disconnect, - .id_table = cx231xx_id_table, -}; - -static int __init cx231xx_module_init(void) -{ - int result; - - printk(KERN_INFO DRIVER_NAME " v4l2 driver loaded.\n"); - - /* register this driver with the USB subsystem */ - result = usb_register(&cx231xx_usb_driver); - if (result) - cx231xx_err(DRIVER_NAME - " usb_register failed. Error number %d.\n", result); - - return result; -} - -static void __exit cx231xx_module_exit(void) -{ - /* deregister this driver with the USB subsystem */ - usb_deregister(&cx231xx_usb_driver); -} - -module_init(cx231xx_module_init); -module_exit(cx231xx_module_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,495 +0,0 @@ -/* - cx231xx_conf-reg.h - driver for Conexant Cx23100/101/102 USB - video capture devices - - Copyright (C) 2008 - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _POLARIS_REG_H_ -#define _POLARIS_REG_H_ - -#define BOARD_CFG_STAT 0x0 -#define TS_MODE_REG 0x4 -#define TS1_CFG_REG 0x8 -#define TS1_LENGTH_REG 0xc -#define TS2_CFG_REG 0x10 -#define TS2_LENGTH_REG 0x14 -#define EP_MODE_SET 0x18 -#define CIR_PWR_PTN1 0x1c -#define CIR_PWR_PTN2 0x20 -#define CIR_PWR_PTN3 0x24 -#define CIR_PWR_MASK0 0x28 -#define CIR_PWR_MASK1 0x2c -#define CIR_PWR_MASK2 0x30 -#define CIR_GAIN 0x34 -#define CIR_CAR_REG 0x38 -#define CIR_OT_CFG1 0x40 -#define CIR_OT_CFG2 0x44 -#define GBULK_BIT_EN 0x68 -#define PWR_CTL_EN 0x74 - -/* Polaris Endpoints capture mask for register EP_MODE_SET */ -#define ENABLE_EP1 0x01 /* Bit[0]=1 */ -#define ENABLE_EP2 0x02 /* Bit[1]=1 */ -#define ENABLE_EP3 0x04 /* Bit[2]=1 */ -#define ENABLE_EP4 0x08 /* Bit[3]=1 */ -#define ENABLE_EP5 0x10 /* Bit[4]=1 */ -#define ENABLE_EP6 0x20 /* Bit[5]=1 */ - -/* Bit definition for register PWR_CTL_EN */ -#define PWR_MODE_MASK 0x17f -#define PWR_AV_EN 0x08 /* bit3 */ -#define PWR_ISO_EN 0x40 /* bit6 */ -#define PWR_AV_MODE 0x30 /* bit4,5 */ -#define PWR_TUNER_EN 0x04 /* bit2 */ -#define PWR_DEMOD_EN 0x02 /* bit1 */ -#define I2C_DEMOD_EN 0x01 /* bit0 */ -#define PWR_RESETOUT_EN 0x100 /* bit8 */ - -enum AV_MODE{ - POLARIS_AVMODE_DEFAULT = 0, - POLARIS_AVMODE_DIGITAL = 0x10, - POLARIS_AVMODE_ANALOGT_TV = 0x20, - POLARIS_AVMODE_ENXTERNAL_AV = 0x30, - -}; - -/* Colibri Registers */ - -#define SINGLE_ENDED 0x0 -#define LOW_IF 0x4 -#define EU_IF 0x9 -#define US_IF 0xa - -#define SUP_BLK_TUNE1 0x00 -#define SUP_BLK_TUNE2 0x01 -#define SUP_BLK_TUNE3 0x02 -#define SUP_BLK_XTAL 0x03 -#define SUP_BLK_PLL1 0x04 -#define SUP_BLK_PLL2 0x05 -#define SUP_BLK_PLL3 0x06 -#define SUP_BLK_REF 0x07 -#define SUP_BLK_PWRDN 0x08 -#define SUP_BLK_TESTPAD 0x09 -#define ADC_COM_INT5_STAB_REF 0x0a -#define ADC_COM_QUANT 0x0b -#define ADC_COM_BIAS1 0x0c -#define ADC_COM_BIAS2 0x0d -#define ADC_COM_BIAS3 0x0e -#define TESTBUS_CTRL 0x12 - -#define FLD_PWRDN_TUNING_BIAS 0x10 -#define FLD_PWRDN_ENABLE_PLL 0x08 -#define FLD_PWRDN_PD_BANDGAP 0x04 -#define FLD_PWRDN_PD_BIAS 0x02 -#define FLD_PWRDN_PD_TUNECK 0x01 - - -#define ADC_STATUS_CH1 0x20 -#define ADC_STATUS_CH2 0x40 -#define ADC_STATUS_CH3 0x60 - -#define ADC_STATUS2_CH1 0x21 -#define ADC_STATUS2_CH2 0x41 -#define ADC_STATUS2_CH3 0x61 - -#define ADC_CAL_ATEST_CH1 0x22 -#define ADC_CAL_ATEST_CH2 0x42 -#define ADC_CAL_ATEST_CH3 0x62 - -#define ADC_PWRDN_CLAMP_CH1 0x23 -#define ADC_PWRDN_CLAMP_CH2 0x43 -#define ADC_PWRDN_CLAMP_CH3 0x63 - -#define ADC_CTRL_DAC23_CH1 0x24 -#define ADC_CTRL_DAC23_CH2 0x44 -#define ADC_CTRL_DAC23_CH3 0x64 - -#define ADC_CTRL_DAC1_CH1 0x25 -#define ADC_CTRL_DAC1_CH2 0x45 -#define ADC_CTRL_DAC1_CH3 0x65 - -#define ADC_DCSERVO_DEM_CH1 0x26 -#define ADC_DCSERVO_DEM_CH2 0x46 -#define ADC_DCSERVO_DEM_CH3 0x66 - -#define ADC_FB_FRCRST_CH1 0x27 -#define ADC_FB_FRCRST_CH2 0x47 -#define ADC_FB_FRCRST_CH3 0x67 - -#define ADC_INPUT_CH1 0x28 -#define ADC_INPUT_CH2 0x48 -#define ADC_INPUT_CH3 0x68 -#define INPUT_SEL_MASK 0x30 /* [5:4] in_sel */ - -#define ADC_NTF_PRECLMP_EN_CH1 0x29 -#define ADC_NTF_PRECLMP_EN_CH2 0x49 -#define ADC_NTF_PRECLMP_EN_CH3 0x69 - -#define ADC_QGAIN_RES_TRM_CH1 0x2a -#define ADC_QGAIN_RES_TRM_CH2 0x4a -#define ADC_QGAIN_RES_TRM_CH3 0x6a - -#define ADC_SOC_PRECLMP_TERM_CH1 0x2b -#define ADC_SOC_PRECLMP_TERM_CH2 0x4b -#define ADC_SOC_PRECLMP_TERM_CH3 0x6b - -#define TESTBUS_CTRL_CH1 0x32 -#define TESTBUS_CTRL_CH2 0x52 -#define TESTBUS_CTRL_CH3 0x72 - -/****************************************************************************** - * DIF registers * - ******************************************************************************/ -#define DIRECT_IF_REVB_BASE 0x00300 - -/*****************************************************************************/ -#define DIF_PLL_FREQ_WORD (DIRECT_IF_REVB_BASE + 0x00000000) -/*****************************************************************************/ -#define FLD_DIF_PLL_LOCK 0x80000000 -/* Reserved [30:29] */ -#define FLD_DIF_PLL_FREE_RUN 0x10000000 -#define FLD_DIF_PLL_FREQ 0x0fffffff - -/*****************************************************************************/ -#define DIF_PLL_CTRL (DIRECT_IF_REVB_BASE + 0x00000004) -/*****************************************************************************/ -#define FLD_DIF_KD_PD 0xff000000 -/* Reserved [23:20] */ -#define FLD_DIF_KDS_PD 0x000f0000 -#define FLD_DIF_KI_PD 0x0000ff00 -/* Reserved [7:4] */ -#define FLD_DIF_KIS_PD 0x0000000f - -/*****************************************************************************/ -#define DIF_PLL_CTRL1 (DIRECT_IF_REVB_BASE + 0x00000008) -/*****************************************************************************/ -#define FLD_DIF_KD_FD 0xff000000 -/* Reserved [23:20] */ -#define FLD_DIF_KDS_FD 0x000f0000 -#define FLD_DIF_KI_FD 0x0000ff00 -#define FLD_DIF_SIG_PROP_SZ 0x000000f0 -#define FLD_DIF_KIS_FD 0x0000000f - -/*****************************************************************************/ -#define DIF_PLL_CTRL2 (DIRECT_IF_REVB_BASE + 0x0000000c) -/*****************************************************************************/ -#define FLD_DIF_PLL_AGC_REF 0xfff00000 -#define FLD_DIF_PLL_AGC_KI 0x000f0000 -/* Reserved [15] */ -#define FLD_DIF_FREQ_LIMIT 0x00007000 -#define FLD_DIF_K_FD 0x00000f00 -#define FLD_DIF_DOWNSMPL_FD 0x000000ff - -/*****************************************************************************/ -#define DIF_PLL_CTRL3 (DIRECT_IF_REVB_BASE + 0x00000010) -/*****************************************************************************/ -/* Reserved [31:16] */ -#define FLD_DIF_PLL_AGC_EN 0x00008000 -/* Reserved [14:12] */ -#define FLD_DIF_PLL_MAN_GAIN 0x00000fff - -/*****************************************************************************/ -#define DIF_AGC_IF_REF (DIRECT_IF_REVB_BASE + 0x00000014) -/*****************************************************************************/ -#define FLD_DIF_K_AGC_RF 0xf0000000 -#define FLD_DIF_K_AGC_IF 0x0f000000 -#define FLD_DIF_K_AGC_INT 0x00f00000 -/* Reserved [19:12] */ -#define FLD_DIF_IF_REF 0x00000fff - -/*****************************************************************************/ -#define DIF_AGC_CTRL_IF (DIRECT_IF_REVB_BASE + 0x00000018) -/*****************************************************************************/ -#define FLD_DIF_IF_MAX 0xff000000 -#define FLD_DIF_IF_MIN 0x00ff0000 -#define FLD_DIF_IF_AGC 0x0000ffff - -/*****************************************************************************/ -#define DIF_AGC_CTRL_INT (DIRECT_IF_REVB_BASE + 0x0000001c) -/*****************************************************************************/ -#define FLD_DIF_INT_MAX 0xff000000 -#define FLD_DIF_INT_MIN 0x00ff0000 -#define FLD_DIF_INT_AGC 0x0000ffff - -/*****************************************************************************/ -#define DIF_AGC_CTRL_RF (DIRECT_IF_REVB_BASE + 0x00000020) -/*****************************************************************************/ -#define FLD_DIF_RF_MAX 0xff000000 -#define FLD_DIF_RF_MIN 0x00ff0000 -#define FLD_DIF_RF_AGC 0x0000ffff - -/*****************************************************************************/ -#define DIF_AGC_IF_INT_CURRENT (DIRECT_IF_REVB_BASE + 0x00000024) -/*****************************************************************************/ -#define FLD_DIF_IF_AGC_IN 0xffff0000 -#define FLD_DIF_INT_AGC_IN 0x0000ffff - -/*****************************************************************************/ -#define DIF_AGC_RF_CURRENT (DIRECT_IF_REVB_BASE + 0x00000028) -/*****************************************************************************/ -/* Reserved [31:16] */ -#define FLD_DIF_RF_AGC_IN 0x0000ffff - -/*****************************************************************************/ -#define DIF_VIDEO_AGC_CTRL (DIRECT_IF_REVB_BASE + 0x0000002c) -/*****************************************************************************/ -#define FLD_DIF_AFD 0xc0000000 -#define FLD_DIF_K_VID_AGC 0x30000000 -#define FLD_DIF_LINE_LENGTH 0x0fff0000 -#define FLD_DIF_AGC_GAIN 0x0000ffff - -/*****************************************************************************/ -#define DIF_VID_AUD_OVERRIDE (DIRECT_IF_REVB_BASE + 0x00000030) -/*****************************************************************************/ -#define FLD_DIF_AUDIO_AGC_OVERRIDE 0x80000000 -/* Reserved [30:30] */ -#define FLD_DIF_AUDIO_MAN_GAIN 0x3f000000 -/* Reserved [23:17] */ -#define FLD_DIF_VID_AGC_OVERRIDE 0x00010000 -#define FLD_DIF_VID_MAN_GAIN 0x0000ffff - -/*****************************************************************************/ -#define DIF_AV_SEP_CTRL (DIRECT_IF_REVB_BASE + 0x00000034) -/*****************************************************************************/ -#define FLD_DIF_LPF_FREQ 0xc0000000 -#define FLD_DIF_AV_PHASE_INC 0x3f000000 -#define FLD_DIF_AUDIO_FREQ 0x00ffffff - -/*****************************************************************************/ -#define DIF_COMP_FLT_CTRL (DIRECT_IF_REVB_BASE + 0x00000038) -/*****************************************************************************/ -/* Reserved [31:24] */ -#define FLD_DIF_IIR23_R2 0x00ff0000 -#define FLD_DIF_IIR23_R1 0x0000ff00 -#define FLD_DIF_IIR1_R1 0x000000ff - -/*****************************************************************************/ -#define DIF_MISC_CTRL (DIRECT_IF_REVB_BASE + 0x0000003c) -/*****************************************************************************/ -#define FLD_DIF_DIF_BYPASS 0x80000000 -#define FLD_DIF_FM_NYQ_GAIN 0x40000000 -#define FLD_DIF_RF_AGC_ENA 0x20000000 -#define FLD_DIF_INT_AGC_ENA 0x10000000 -#define FLD_DIF_IF_AGC_ENA 0x08000000 -#define FLD_DIF_FORCE_RF_IF_LOCK 0x04000000 -#define FLD_DIF_VIDEO_AGC_ENA 0x02000000 -#define FLD_DIF_RF_AGC_INV 0x01000000 -#define FLD_DIF_INT_AGC_INV 0x00800000 -#define FLD_DIF_IF_AGC_INV 0x00400000 -#define FLD_DIF_SPEC_INV 0x00200000 -#define FLD_DIF_AUD_FULL_BW 0x00100000 -#define FLD_DIF_AUD_SRC_SEL 0x00080000 -/* Reserved [18] */ -#define FLD_DIF_IF_FREQ 0x00030000 -/* Reserved [15:14] */ -#define FLD_DIF_TIP_OFFSET 0x00003f00 -/* Reserved [7:5] */ -#define FLD_DIF_DITHER_ENA 0x00000010 -/* Reserved [3:1] */ -#define FLD_DIF_RF_IF_LOCK 0x00000001 - -/*****************************************************************************/ -#define DIF_SRC_PHASE_INC (DIRECT_IF_REVB_BASE + 0x00000040) -/*****************************************************************************/ -/* Reserved [31:29] */ -#define FLD_DIF_PHASE_INC 0x1fffffff - -/*****************************************************************************/ -#define DIF_SRC_GAIN_CONTROL (DIRECT_IF_REVB_BASE + 0x00000044) -/*****************************************************************************/ -/* Reserved [31:16] */ -#define FLD_DIF_SRC_KI 0x0000ff00 -#define FLD_DIF_SRC_KD 0x000000ff - -/*****************************************************************************/ -#define DIF_BPF_COEFF01 (DIRECT_IF_REVB_BASE + 0x00000048) -/*****************************************************************************/ -/* Reserved [31:19] */ -#define FLD_DIF_BPF_COEFF_0 0x00070000 -/* Reserved [15:4] */ -#define FLD_DIF_BPF_COEFF_1 0x0000000f - -/*****************************************************************************/ -#define DIF_BPF_COEFF23 (DIRECT_IF_REVB_BASE + 0x0000004c) -/*****************************************************************************/ -/* Reserved [31:22] */ -#define FLD_DIF_BPF_COEFF_2 0x003f0000 -/* Reserved [15:7] */ -#define FLD_DIF_BPF_COEFF_3 0x0000007f - -/*****************************************************************************/ -#define DIF_BPF_COEFF45 (DIRECT_IF_REVB_BASE + 0x00000050) -/*****************************************************************************/ -/* Reserved [31:24] */ -#define FLD_DIF_BPF_COEFF_4 0x00ff0000 -/* Reserved [15:8] */ -#define FLD_DIF_BPF_COEFF_5 0x000000ff - -/*****************************************************************************/ -#define DIF_BPF_COEFF67 (DIRECT_IF_REVB_BASE + 0x00000054) -/*****************************************************************************/ -/* Reserved [31:25] */ -#define FLD_DIF_BPF_COEFF_6 0x01ff0000 -/* Reserved [15:9] */ -#define FLD_DIF_BPF_COEFF_7 0x000001ff - -/*****************************************************************************/ -#define DIF_BPF_COEFF89 (DIRECT_IF_REVB_BASE + 0x00000058) -/*****************************************************************************/ -/* Reserved [31:26] */ -#define FLD_DIF_BPF_COEFF_8 0x03ff0000 -/* Reserved [15:10] */ -#define FLD_DIF_BPF_COEFF_9 0x000003ff - -/*****************************************************************************/ -#define DIF_BPF_COEFF1011 (DIRECT_IF_REVB_BASE + 0x0000005c) -/*****************************************************************************/ -/* Reserved [31:27] */ -#define FLD_DIF_BPF_COEFF_10 0x07ff0000 -/* Reserved [15:11] */ -#define FLD_DIF_BPF_COEFF_11 0x000007ff - -/*****************************************************************************/ -#define DIF_BPF_COEFF1213 (DIRECT_IF_REVB_BASE + 0x00000060) -/*****************************************************************************/ -/* Reserved [31:27] */ -#define FLD_DIF_BPF_COEFF_12 0x07ff0000 -/* Reserved [15:12] */ -#define FLD_DIF_BPF_COEFF_13 0x00000fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF1415 (DIRECT_IF_REVB_BASE + 0x00000064) -/*****************************************************************************/ -/* Reserved [31:28] */ -#define FLD_DIF_BPF_COEFF_14 0x0fff0000 -/* Reserved [15:12] */ -#define FLD_DIF_BPF_COEFF_15 0x00000fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF1617 (DIRECT_IF_REVB_BASE + 0x00000068) -/*****************************************************************************/ -/* Reserved [31:29] */ -#define FLD_DIF_BPF_COEFF_16 0x1fff0000 -/* Reserved [15:13] */ -#define FLD_DIF_BPF_COEFF_17 0x00001fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF1819 (DIRECT_IF_REVB_BASE + 0x0000006c) -/*****************************************************************************/ -/* Reserved [31:29] */ -#define FLD_DIF_BPF_COEFF_18 0x1fff0000 -/* Reserved [15:13] */ -#define FLD_DIF_BPF_COEFF_19 0x00001fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF2021 (DIRECT_IF_REVB_BASE + 0x00000070) -/*****************************************************************************/ -/* Reserved [31:29] */ -#define FLD_DIF_BPF_COEFF_20 0x1fff0000 -/* Reserved [15:14] */ -#define FLD_DIF_BPF_COEFF_21 0x00003fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF2223 (DIRECT_IF_REVB_BASE + 0x00000074) -/*****************************************************************************/ -/* Reserved [31:30] */ -#define FLD_DIF_BPF_COEFF_22 0x3fff0000 -/* Reserved [15:14] */ -#define FLD_DIF_BPF_COEFF_23 0x00003fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF2425 (DIRECT_IF_REVB_BASE + 0x00000078) -/*****************************************************************************/ -/* Reserved [31:30] */ -#define FLD_DIF_BPF_COEFF_24 0x3fff0000 -/* Reserved [15:14] */ -#define FLD_DIF_BPF_COEFF_25 0x00003fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF2627 (DIRECT_IF_REVB_BASE + 0x0000007c) -/*****************************************************************************/ -/* Reserved [31:30] */ -#define FLD_DIF_BPF_COEFF_26 0x3fff0000 -/* Reserved [15:14] */ -#define FLD_DIF_BPF_COEFF_27 0x00003fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF2829 (DIRECT_IF_REVB_BASE + 0x00000080) -/*****************************************************************************/ -/* Reserved [31:30] */ -#define FLD_DIF_BPF_COEFF_28 0x3fff0000 -/* Reserved [15:14] */ -#define FLD_DIF_BPF_COEFF_29 0x00003fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF3031 (DIRECT_IF_REVB_BASE + 0x00000084) -/*****************************************************************************/ -/* Reserved [31:30] */ -#define FLD_DIF_BPF_COEFF_30 0x3fff0000 -/* Reserved [15:14] */ -#define FLD_DIF_BPF_COEFF_31 0x00003fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF3233 (DIRECT_IF_REVB_BASE + 0x00000088) -/*****************************************************************************/ -/* Reserved [31:30] */ -#define FLD_DIF_BPF_COEFF_32 0x3fff0000 -/* Reserved [15:14] */ -#define FLD_DIF_BPF_COEFF_33 0x00003fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF3435 (DIRECT_IF_REVB_BASE + 0x0000008c) -/*****************************************************************************/ -/* Reserved [31:30] */ -#define FLD_DIF_BPF_COEFF_34 0x3fff0000 -/* Reserved [15:14] */ -#define FLD_DIF_BPF_COEFF_35 0x00003fff - -/*****************************************************************************/ -#define DIF_BPF_COEFF36 (DIRECT_IF_REVB_BASE + 0x00000090) -/*****************************************************************************/ -/* Reserved [31:30] */ -#define FLD_DIF_BPF_COEFF_36 0x3fff0000 -/* Reserved [15:0] */ - -/*****************************************************************************/ -#define DIF_RPT_VARIANCE (DIRECT_IF_REVB_BASE + 0x00000094) -/*****************************************************************************/ -/* Reserved [31:20] */ -#define FLD_DIF_RPT_VARIANCE 0x000fffff - -/*****************************************************************************/ -#define DIF_SOFT_RST_CTRL_REVB (DIRECT_IF_REVB_BASE + 0x00000098) -/*****************************************************************************/ -/* Reserved [31:8] */ -#define FLD_DIF_DIF_SOFT_RST 0x00000080 -#define FLD_DIF_DIF_REG_RST_MSK 0x00000040 -#define FLD_DIF_AGC_RST_MSK 0x00000020 -#define FLD_DIF_CMP_RST_MSK 0x00000010 -#define FLD_DIF_AVS_RST_MSK 0x00000008 -#define FLD_DIF_NYQ_RST_MSK 0x00000004 -#define FLD_DIF_DIF_SRC_RST_MSK 0x00000002 -#define FLD_DIF_PLL_RST_MSK 0x00000001 - -/*****************************************************************************/ -#define DIF_PLL_FREQ_ERR (DIRECT_IF_REVB_BASE + 0x0000009c) -/*****************************************************************************/ -/* Reserved [31:25] */ -#define FLD_DIF_CTL_IP 0x01ffffff - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-core.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1735 +0,0 @@ -/* - cx231xx-core.c - driver for Conexant Cx23100/101/102 - USB video capture devices - - Copyright (C) 2008 - Based on em28xx driver - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx231xx.h" -#include "cx231xx-reg.h" - -/* #define ENABLE_DEBUG_ISOC_FRAMES */ - -static unsigned int core_debug; -module_param(core_debug, int, 0644); -MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); - -#define cx231xx_coredbg(fmt, arg...) do {\ - if (core_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -static unsigned int reg_debug; -module_param(reg_debug, int, 0644); -MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); - -static int alt = CX231XX_PINOUT; -module_param(alt, int, 0644); -MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); - -#define cx231xx_isocdbg(fmt, arg...) do {\ - if (core_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -/***************************************************************** -* Device control list functions * -******************************************************************/ - -LIST_HEAD(cx231xx_devlist); -static DEFINE_MUTEX(cx231xx_devlist_mutex); - -/* - * cx231xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -void cx231xx_remove_from_devlist(struct cx231xx *dev) -{ - if (dev == NULL) - return; - if (dev->udev == NULL) - return; - - if (atomic_read(&dev->devlist_count) > 0) { - mutex_lock(&cx231xx_devlist_mutex); - list_del(&dev->devlist); - atomic_dec(&dev->devlist_count); - mutex_unlock(&cx231xx_devlist_mutex); - } -}; - -void cx231xx_add_into_devlist(struct cx231xx *dev) -{ - mutex_lock(&cx231xx_devlist_mutex); - list_add_tail(&dev->devlist, &cx231xx_devlist); - atomic_inc(&dev->devlist_count); - mutex_unlock(&cx231xx_devlist_mutex); -}; - -static LIST_HEAD(cx231xx_extension_devlist); - -int cx231xx_register_extension(struct cx231xx_ops *ops) -{ - struct cx231xx *dev = NULL; - - mutex_lock(&cx231xx_devlist_mutex); - list_add_tail(&ops->next, &cx231xx_extension_devlist); - list_for_each_entry(dev, &cx231xx_devlist, devlist) - ops->init(dev); - - printk(KERN_INFO DRIVER_NAME ": %s initialized\n", ops->name); - mutex_unlock(&cx231xx_devlist_mutex); - return 0; -} -EXPORT_SYMBOL(cx231xx_register_extension); - -void cx231xx_unregister_extension(struct cx231xx_ops *ops) -{ - struct cx231xx *dev = NULL; - - mutex_lock(&cx231xx_devlist_mutex); - list_for_each_entry(dev, &cx231xx_devlist, devlist) - ops->fini(dev); - - - printk(KERN_INFO DRIVER_NAME ": %s removed\n", ops->name); - list_del(&ops->next); - mutex_unlock(&cx231xx_devlist_mutex); -} -EXPORT_SYMBOL(cx231xx_unregister_extension); - -void cx231xx_init_extension(struct cx231xx *dev) -{ - struct cx231xx_ops *ops = NULL; - - mutex_lock(&cx231xx_devlist_mutex); - if (!list_empty(&cx231xx_extension_devlist)) { - list_for_each_entry(ops, &cx231xx_extension_devlist, next) { - if (ops->init) - ops->init(dev); - } - } - mutex_unlock(&cx231xx_devlist_mutex); -} - -void cx231xx_close_extension(struct cx231xx *dev) -{ - struct cx231xx_ops *ops = NULL; - - mutex_lock(&cx231xx_devlist_mutex); - if (!list_empty(&cx231xx_extension_devlist)) { - list_for_each_entry(ops, &cx231xx_extension_devlist, next) { - if (ops->fini) - ops->fini(dev); - } - } - mutex_unlock(&cx231xx_devlist_mutex); -} - -/**************************************************************** -* U S B related functions * -*****************************************************************/ -int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus, - struct cx231xx_i2c_xfer_data *req_data) -{ - int status = 0; - struct cx231xx *dev = i2c_bus->dev; - struct VENDOR_REQUEST_IN ven_req; - - u8 saddr_len = 0; - u8 _i2c_period = 0; - u8 _i2c_nostop = 0; - u8 _i2c_reserve = 0; - - /* Get the I2C period, nostop and reserve parameters */ - _i2c_period = i2c_bus->i2c_period; - _i2c_nostop = i2c_bus->i2c_nostop; - _i2c_reserve = i2c_bus->i2c_reserve; - - saddr_len = req_data->saddr_len; - - /* Set wValue */ - if (saddr_len == 1) /* need check saddr_len == 0 */ - ven_req.wValue = - req_data-> - dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 | - _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6; - else - ven_req.wValue = - req_data-> - dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 | - _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6; - - /* set channel number */ - if (req_data->direction & I2C_M_RD) { - /* channel number, for read,spec required channel_num +4 */ - ven_req.bRequest = i2c_bus->nr + 4; - } else - ven_req.bRequest = i2c_bus->nr; /* channel number, */ - - /* set index value */ - switch (saddr_len) { - case 0: - ven_req.wIndex = 0; /* need check */ - break; - case 1: - ven_req.wIndex = (req_data->saddr_dat & 0xff); - break; - case 2: - ven_req.wIndex = req_data->saddr_dat; - break; - } - - /* set wLength value */ - ven_req.wLength = req_data->buf_size; - - /* set bData value */ - ven_req.bData = 0; - - /* set the direction */ - if (req_data->direction) { - ven_req.direction = USB_DIR_IN; - memset(req_data->p_buffer, 0x00, ven_req.wLength); - } else - ven_req.direction = USB_DIR_OUT; - - /* set the buffer for read / write */ - ven_req.pBuff = req_data->p_buffer; - - - /* call common vendor command request */ - status = cx231xx_send_vendor_cmd(dev, &ven_req); - if (status < 0) { - cx231xx_info - ("UsbInterface::sendCommand, failed with status -%d\n", - status); - } - - return status; -} -EXPORT_SYMBOL_GPL(cx231xx_send_usb_command); - -/* - * Sends/Receives URB control messages, assuring to use a kalloced buffer - * for all operations (dev->urb_buf), to avoid using stacked buffers, as - * they aren't safe for usage with USB, due to DMA restrictions. - * Also implements the debug code for control URB's. - */ -static int __usb_control_msg(struct cx231xx *dev, unsigned int pipe, - __u8 request, __u8 requesttype, __u16 value, __u16 index, - void *data, __u16 size, int timeout) -{ - int rc, i; - - if (reg_debug) { - printk(KERN_DEBUG "%s: (pipe 0x%08x): " - "%s: %02x %02x %02x %02x %02x %02x %02x %02x ", - dev->name, - pipe, - (requesttype & USB_DIR_IN) ? "IN" : "OUT", - requesttype, - request, - value & 0xff, value >> 8, - index & 0xff, index >> 8, - size & 0xff, size >> 8); - if (!(requesttype & USB_DIR_IN)) { - printk(KERN_CONT ">>>"); - for (i = 0; i < size; i++) - printk(KERN_CONT " %02x", - ((unsigned char *)data)[i]); - } - } - - /* Do the real call to usb_control_msg */ - mutex_lock(&dev->ctrl_urb_lock); - if (!(requesttype & USB_DIR_IN) && size) - memcpy(dev->urb_buf, data, size); - rc = usb_control_msg(dev->udev, pipe, request, requesttype, value, - index, dev->urb_buf, size, timeout); - if ((requesttype & USB_DIR_IN) && size) - memcpy(data, dev->urb_buf, size); - mutex_unlock(&dev->ctrl_urb_lock); - - if (reg_debug) { - if (unlikely(rc < 0)) { - printk(KERN_CONT "FAILED!\n"); - return rc; - } - - if ((requesttype & USB_DIR_IN)) { - printk(KERN_CONT "<<<"); - for (i = 0; i < size; i++) - printk(KERN_CONT " %02x", - ((unsigned char *)data)[i]); - } - printk(KERN_CONT "\n"); - } - - return rc; -} - - -/* - * cx231xx_read_ctrl_reg() - * reads data from the usb device specifying bRequest and wValue - */ -int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, - char *buf, int len) -{ - u8 val = 0; - int ret; - int pipe = usb_rcvctrlpipe(dev->udev, 0); - - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - - if (len > URB_MAX_CTRL_SIZE) - return -EINVAL; - - switch (len) { - case 1: - val = ENABLE_ONE_BYTE; - break; - case 2: - val = ENABLE_TWE_BYTE; - break; - case 3: - val = ENABLE_THREE_BYTE; - break; - case 4: - val = ENABLE_FOUR_BYTE; - break; - default: - val = 0xFF; /* invalid option */ - } - - if (val == 0xFF) - return -EINVAL; - - ret = __usb_control_msg(dev, pipe, req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - val, reg, buf, len, HZ); - return ret; -} - -int cx231xx_send_vendor_cmd(struct cx231xx *dev, - struct VENDOR_REQUEST_IN *ven_req) -{ - int ret; - int pipe = 0; - int unsend_size = 0; - u8 *pdata; - - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - - if ((ven_req->wLength > URB_MAX_CTRL_SIZE)) - return -EINVAL; - - if (ven_req->direction) - pipe = usb_rcvctrlpipe(dev->udev, 0); - else - pipe = usb_sndctrlpipe(dev->udev, 0); - - /* - * If the cx23102 read more than 4 bytes with i2c bus, - * need chop to 4 byte per request - */ - if ((ven_req->wLength > 4) && ((ven_req->bRequest == 0x4) || - (ven_req->bRequest == 0x5) || - (ven_req->bRequest == 0x6))) { - unsend_size = 0; - pdata = ven_req->pBuff; - - - unsend_size = ven_req->wLength; - - /* the first package */ - ven_req->wValue = ven_req->wValue & 0xFFFB; - ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x2; - ret = __usb_control_msg(dev, pipe, ven_req->bRequest, - ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - ven_req->wValue, ven_req->wIndex, pdata, - 0x0004, HZ); - unsend_size = unsend_size - 4; - - /* the middle package */ - ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x42; - while (unsend_size - 4 > 0) { - pdata = pdata + 4; - ret = __usb_control_msg(dev, pipe, - ven_req->bRequest, - ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - ven_req->wValue, ven_req->wIndex, pdata, - 0x0004, HZ); - unsend_size = unsend_size - 4; - } - - /* the last package */ - ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x40; - pdata = pdata + 4; - ret = __usb_control_msg(dev, pipe, ven_req->bRequest, - ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - ven_req->wValue, ven_req->wIndex, pdata, - unsend_size, HZ); - } else { - ret = __usb_control_msg(dev, pipe, ven_req->bRequest, - ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - ven_req->wValue, ven_req->wIndex, - ven_req->pBuff, ven_req->wLength, HZ); - } - - return ret; -} - -/* - * cx231xx_write_ctrl_reg() - * sends data to the usb device, specifying bRequest - */ -int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, char *buf, - int len) -{ - u8 val = 0; - int ret; - int pipe = usb_sndctrlpipe(dev->udev, 0); - - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - - if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) - return -EINVAL; - - switch (len) { - case 1: - val = ENABLE_ONE_BYTE; - break; - case 2: - val = ENABLE_TWE_BYTE; - break; - case 3: - val = ENABLE_THREE_BYTE; - break; - case 4: - val = ENABLE_FOUR_BYTE; - break; - default: - val = 0xFF; /* invalid option */ - } - - if (val == 0xFF) - return -EINVAL; - - if (reg_debug) { - int byte; - - cx231xx_isocdbg("(pipe 0x%08x): " - "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", - pipe, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - req, 0, val, reg & 0xff, - reg >> 8, len & 0xff, len >> 8); - - for (byte = 0; byte < len; byte++) - cx231xx_isocdbg(" %02x", (unsigned char)buf[byte]); - cx231xx_isocdbg("\n"); - } - - ret = __usb_control_msg(dev, pipe, req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - val, reg, buf, len, HZ); - - return ret; -} - -/**************************************************************** -* USB Alternate Setting functions * -*****************************************************************/ - -int cx231xx_set_video_alternate(struct cx231xx *dev) -{ - int errCode, prev_alt = dev->video_mode.alt; - unsigned int min_pkt_size = dev->width * 2 + 4; - u32 usb_interface_index = 0; - - /* When image size is bigger than a certain value, - the frame size should be increased, otherwise, only - green screen will be received. - */ - if (dev->width * 2 * dev->height > 720 * 240 * 2) - min_pkt_size *= 2; - - if (dev->width > 360) { - /* resolutions: 720,704,640 */ - dev->video_mode.alt = 3; - } else if (dev->width > 180) { - /* resolutions: 360,352,320,240 */ - dev->video_mode.alt = 2; - } else if (dev->width > 0) { - /* resolutions: 180,176,160,128,88 */ - dev->video_mode.alt = 1; - } else { - /* Change to alt0 BULK to release USB bandwidth */ - dev->video_mode.alt = 0; - } - - if (dev->USE_ISO == 0) - dev->video_mode.alt = 0; - - cx231xx_coredbg("dev->video_mode.alt= %d\n", dev->video_mode.alt); - - /* Get the correct video interface Index */ - usb_interface_index = - dev->current_pcb_config.hs_config_info[0].interface_info. - video_index + 1; - - if (dev->video_mode.alt != prev_alt) { - cx231xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", - min_pkt_size, dev->video_mode.alt); - - if (dev->video_mode.alt_max_pkt_size != NULL) - dev->video_mode.max_pkt_size = - dev->video_mode.alt_max_pkt_size[dev->video_mode.alt]; - cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", - dev->video_mode.alt, - dev->video_mode.max_pkt_size); - errCode = - usb_set_interface(dev->udev, usb_interface_index, - dev->video_mode.alt); - if (errCode < 0) { - cx231xx_errdev - ("cannot change alt number to %d (error=%i)\n", - dev->video_mode.alt, errCode); - return errCode; - } - } - return 0; -} - -int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt) -{ - int status = 0; - u32 usb_interface_index = 0; - u32 max_pkt_size = 0; - - switch (index) { - case INDEX_TS1: - usb_interface_index = - dev->current_pcb_config.hs_config_info[0].interface_info. - ts1_index + 1; - dev->ts1_mode.alt = alt; - if (dev->ts1_mode.alt_max_pkt_size != NULL) - max_pkt_size = dev->ts1_mode.max_pkt_size = - dev->ts1_mode.alt_max_pkt_size[dev->ts1_mode.alt]; - break; - case INDEX_TS2: - usb_interface_index = - dev->current_pcb_config.hs_config_info[0].interface_info. - ts2_index + 1; - break; - case INDEX_AUDIO: - usb_interface_index = - dev->current_pcb_config.hs_config_info[0].interface_info. - audio_index + 1; - dev->adev.alt = alt; - if (dev->adev.alt_max_pkt_size != NULL) - max_pkt_size = dev->adev.max_pkt_size = - dev->adev.alt_max_pkt_size[dev->adev.alt]; - break; - case INDEX_VIDEO: - usb_interface_index = - dev->current_pcb_config.hs_config_info[0].interface_info. - video_index + 1; - dev->video_mode.alt = alt; - if (dev->video_mode.alt_max_pkt_size != NULL) - max_pkt_size = dev->video_mode.max_pkt_size = - dev->video_mode.alt_max_pkt_size[dev->video_mode. - alt]; - break; - case INDEX_VANC: - if (dev->board.no_alt_vanc) - return 0; - usb_interface_index = - dev->current_pcb_config.hs_config_info[0].interface_info. - vanc_index + 1; - dev->vbi_mode.alt = alt; - if (dev->vbi_mode.alt_max_pkt_size != NULL) - max_pkt_size = dev->vbi_mode.max_pkt_size = - dev->vbi_mode.alt_max_pkt_size[dev->vbi_mode.alt]; - break; - case INDEX_HANC: - usb_interface_index = - dev->current_pcb_config.hs_config_info[0].interface_info. - hanc_index + 1; - dev->sliced_cc_mode.alt = alt; - if (dev->sliced_cc_mode.alt_max_pkt_size != NULL) - max_pkt_size = dev->sliced_cc_mode.max_pkt_size = - dev->sliced_cc_mode.alt_max_pkt_size[dev-> - sliced_cc_mode. - alt]; - break; - default: - break; - } - - if (alt > 0 && max_pkt_size == 0) { - cx231xx_errdev - ("can't change interface %d alt no. to %d: Max. Pkt size = 0\n", - usb_interface_index, alt); - /*To workaround error number=-71 on EP0 for videograbber, - need add following codes.*/ - if (dev->board.no_alt_vanc) - return -1; - } - - cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u," - "Interface = %d\n", alt, max_pkt_size, - usb_interface_index); - - if (usb_interface_index > 0) { - status = usb_set_interface(dev->udev, usb_interface_index, alt); - if (status < 0) { - cx231xx_errdev - ("can't change interface %d alt no. to %d (err=%i)\n", - usb_interface_index, alt, status); - return status; - } - } - - return status; -} -EXPORT_SYMBOL_GPL(cx231xx_set_alt_setting); - -int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio) -{ - int rc = 0; - - if (!gpio) - return rc; - - /* Send GPIO reset sequences specified at board entry */ - while (gpio->sleep >= 0) { - rc = cx231xx_set_gpio_value(dev, gpio->bit, gpio->val); - if (rc < 0) - return rc; - - if (gpio->sleep > 0) - msleep(gpio->sleep); - - gpio++; - } - return rc; -} - -int cx231xx_demod_reset(struct cx231xx *dev) -{ - - u8 status = 0; - u8 value[4] = { 0, 0, 0, 0 }; - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, - value, 4); - - cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, - value[0], value[1], value[2], value[3]); - - cx231xx_coredbg("Enter cx231xx_demod_reset()\n"); - - value[1] = (u8) 0x3; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(10); - - value[1] = (u8) 0x0; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(10); - - value[1] = (u8) 0x3; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - PWR_CTL_EN, value, 4); - msleep(10); - - - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, - value, 4); - - cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, - value[0], value[1], value[2], value[3]); - - return status; -} -EXPORT_SYMBOL_GPL(cx231xx_demod_reset); -int is_fw_load(struct cx231xx *dev) -{ - return cx231xx_check_fw(dev); -} -EXPORT_SYMBOL_GPL(is_fw_load); - -int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode) -{ - int errCode = 0; - - if (dev->mode == set_mode) - return 0; - - if (set_mode == CX231XX_SUSPEND) { - /* Set the chip in power saving mode */ - dev->mode = set_mode; - } - - /* Resource is locked */ - if (dev->mode != CX231XX_SUSPEND) - return -EINVAL; - - dev->mode = set_mode; - - if (dev->mode == CX231XX_DIGITAL_MODE)/* Set Digital power mode */ { - /* set AGC mode to Digital */ - switch (dev->model) { - case CX231XX_BOARD_CNXT_CARRAERA: - case CX231XX_BOARD_CNXT_RDE_250: - case CX231XX_BOARD_CNXT_SHELBY: - case CX231XX_BOARD_CNXT_RDU_250: - errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); - break; - case CX231XX_BOARD_CNXT_RDE_253S: - case CX231XX_BOARD_CNXT_RDU_253S: - errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1); - break; - case CX231XX_BOARD_HAUPPAUGE_EXETER: - errCode = cx231xx_set_power_mode(dev, - POLARIS_AVMODE_DIGITAL); - break; - default: - break; - } - } else/* Set Analog Power mode */ { - /* set AGC mode to Analog */ - switch (dev->model) { - case CX231XX_BOARD_CNXT_CARRAERA: - case CX231XX_BOARD_CNXT_RDE_250: - case CX231XX_BOARD_CNXT_SHELBY: - case CX231XX_BOARD_CNXT_RDU_250: - errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1); - break; - case CX231XX_BOARD_CNXT_RDE_253S: - case CX231XX_BOARD_CNXT_RDU_253S: - case CX231XX_BOARD_HAUPPAUGE_EXETER: - case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: - errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); - break; - default: - break; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(cx231xx_set_mode); - -int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size) -{ - int errCode = 0; - int actlen, ret = -ENOMEM; - u32 *buffer; - -buffer = kzalloc(4096, GFP_KERNEL); - if (buffer == NULL) { - cx231xx_info("out of mem\n"); - return -ENOMEM; - } - memcpy(&buffer[0], firmware, 4096); - - ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5), - buffer, 4096, &actlen, 2000); - - if (ret) - cx231xx_info("bulk message failed: %d (%d/%d)", ret, - size, actlen); - else { - errCode = actlen != size ? -1 : 0; - } -kfree(buffer); - return 0; -} - -/***************************************************************** -* URB Streaming functions * -******************************************************************/ - -/* - * IRQ callback, called by URB callback - */ -static void cx231xx_isoc_irq_callback(struct urb *urb) -{ - struct cx231xx_dmaqueue *dma_q = urb->context; - struct cx231xx_video_mode *vmode = - container_of(dma_q, struct cx231xx_video_mode, vidq); - struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode); - int rc, i; - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - cx231xx_isocdbg("urb completition error %d.\n", urb->status); - break; - } - - /* Copy data from URB */ - spin_lock(&dev->video_mode.slock); - rc = dev->video_mode.isoc_ctl.isoc_copy(dev, urb); - spin_unlock(&dev->video_mode.slock); - - /* Reset urb buffers */ - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - urb->status = 0; - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) { - cx231xx_isocdbg("urb resubmit failed (error=%i)\n", - urb->status); - } -} -/***************************************************************** -* URB Streaming functions * -******************************************************************/ - -/* - * IRQ callback, called by URB callback - */ -static void cx231xx_bulk_irq_callback(struct urb *urb) -{ - struct cx231xx_dmaqueue *dma_q = urb->context; - struct cx231xx_video_mode *vmode = - container_of(dma_q, struct cx231xx_video_mode, vidq); - struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode); - int rc; - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - cx231xx_isocdbg("urb completition error %d.\n", urb->status); - break; - } - - /* Copy data from URB */ - spin_lock(&dev->video_mode.slock); - rc = dev->video_mode.bulk_ctl.bulk_copy(dev, urb); - spin_unlock(&dev->video_mode.slock); - - /* Reset urb buffers */ - urb->status = 0; - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) { - cx231xx_isocdbg("urb resubmit failed (error=%i)\n", - urb->status); - } -} -/* - * Stop and Deallocate URBs - */ -void cx231xx_uninit_isoc(struct cx231xx *dev) -{ - struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; - struct urb *urb; - int i; - - cx231xx_isocdbg("cx231xx: called cx231xx_uninit_isoc\n"); - - dev->video_mode.isoc_ctl.nfields = -1; - for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) { - urb = dev->video_mode.isoc_ctl.urb[i]; - if (urb) { - if (!irqs_disabled()) - usb_kill_urb(urb); - else - usb_unlink_urb(urb); - - if (dev->video_mode.isoc_ctl.transfer_buffer[i]) { - usb_free_coherent(dev->udev, - urb->transfer_buffer_length, - dev->video_mode.isoc_ctl. - transfer_buffer[i], - urb->transfer_dma); - } - usb_free_urb(urb); - dev->video_mode.isoc_ctl.urb[i] = NULL; - } - dev->video_mode.isoc_ctl.transfer_buffer[i] = NULL; - } - - kfree(dev->video_mode.isoc_ctl.urb); - kfree(dev->video_mode.isoc_ctl.transfer_buffer); - kfree(dma_q->p_left_data); - - dev->video_mode.isoc_ctl.urb = NULL; - dev->video_mode.isoc_ctl.transfer_buffer = NULL; - dev->video_mode.isoc_ctl.num_bufs = 0; - dma_q->p_left_data = NULL; - - if (dev->mode_tv == 0) - cx231xx_capture_start(dev, 0, Raw_Video); - else - cx231xx_capture_start(dev, 0, TS1_serial_mode); - - -} -EXPORT_SYMBOL_GPL(cx231xx_uninit_isoc); - -/* - * Stop and Deallocate URBs - */ -void cx231xx_uninit_bulk(struct cx231xx *dev) -{ - struct urb *urb; - int i; - - cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n"); - - dev->video_mode.bulk_ctl.nfields = -1; - for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) { - urb = dev->video_mode.bulk_ctl.urb[i]; - if (urb) { - if (!irqs_disabled()) - usb_kill_urb(urb); - else - usb_unlink_urb(urb); - - if (dev->video_mode.bulk_ctl.transfer_buffer[i]) { - usb_free_coherent(dev->udev, - urb->transfer_buffer_length, - dev->video_mode.isoc_ctl. - transfer_buffer[i], - urb->transfer_dma); - } - usb_free_urb(urb); - dev->video_mode.bulk_ctl.urb[i] = NULL; - } - dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL; - } - - kfree(dev->video_mode.bulk_ctl.urb); - kfree(dev->video_mode.bulk_ctl.transfer_buffer); - - dev->video_mode.bulk_ctl.urb = NULL; - dev->video_mode.bulk_ctl.transfer_buffer = NULL; - dev->video_mode.bulk_ctl.num_bufs = 0; - - if (dev->mode_tv == 0) - cx231xx_capture_start(dev, 0, Raw_Video); - else - cx231xx_capture_start(dev, 0, TS1_serial_mode); - - -} -EXPORT_SYMBOL_GPL(cx231xx_uninit_bulk); - -/* - * Allocate URBs and start IRQ - */ -int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*isoc_copy) (struct cx231xx *dev, struct urb *urb)) -{ - struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; - int i; - int sb_size, pipe; - struct urb *urb; - int j, k; - int rc; - - /* De-allocates all pending stuff */ - cx231xx_uninit_isoc(dev); - - dma_q->p_left_data = kzalloc(4096, GFP_KERNEL); - if (dma_q->p_left_data == NULL) { - cx231xx_info("out of mem\n"); - return -ENOMEM; - } - - - - dev->video_mode.isoc_ctl.isoc_copy = isoc_copy; - dev->video_mode.isoc_ctl.num_bufs = num_bufs; - dma_q->pos = 0; - dma_q->is_partial_line = 0; - dma_q->last_sav = 0; - dma_q->current_field = -1; - dma_q->field1_done = 0; - dma_q->lines_per_field = dev->height / 2; - dma_q->bytes_left_in_line = dev->width << 1; - dma_q->lines_completed = 0; - dma_q->mpeg_buffer_done = 0; - dma_q->left_data_count = 0; - dma_q->mpeg_buffer_completed = 0; - dma_q->add_ps_package_head = CX231XX_NEED_ADD_PS_PACKAGE_HEAD; - dma_q->ps_head[0] = 0x00; - dma_q->ps_head[1] = 0x00; - dma_q->ps_head[2] = 0x01; - dma_q->ps_head[3] = 0xBA; - for (i = 0; i < 8; i++) - dma_q->partial_buf[i] = 0; - - dev->video_mode.isoc_ctl.urb = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); - if (!dev->video_mode.isoc_ctl.urb) { - cx231xx_errdev("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - - dev->video_mode.isoc_ctl.transfer_buffer = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); - if (!dev->video_mode.isoc_ctl.transfer_buffer) { - cx231xx_errdev("cannot allocate memory for usbtransfer\n"); - kfree(dev->video_mode.isoc_ctl.urb); - return -ENOMEM; - } - - dev->video_mode.isoc_ctl.max_pkt_size = max_pkt_size; - dev->video_mode.isoc_ctl.buf = NULL; - - sb_size = max_packets * dev->video_mode.isoc_ctl.max_pkt_size; - - if (dev->mode_tv == 1) - dev->video_mode.end_point_addr = 0x81; - else - dev->video_mode.end_point_addr = 0x84; - - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) { - urb = usb_alloc_urb(max_packets, GFP_KERNEL); - if (!urb) { - cx231xx_err("cannot alloc isoc_ctl.urb %i\n", i); - cx231xx_uninit_isoc(dev); - return -ENOMEM; - } - dev->video_mode.isoc_ctl.urb[i] = urb; - - dev->video_mode.isoc_ctl.transfer_buffer[i] = - usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, - &urb->transfer_dma); - if (!dev->video_mode.isoc_ctl.transfer_buffer[i]) { - cx231xx_err("unable to allocate %i bytes for transfer" - " buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); - cx231xx_uninit_isoc(dev); - return -ENOMEM; - } - memset(dev->video_mode.isoc_ctl.transfer_buffer[i], 0, sb_size); - - pipe = - usb_rcvisocpipe(dev->udev, dev->video_mode.end_point_addr); - - usb_fill_int_urb(urb, dev->udev, pipe, - dev->video_mode.isoc_ctl.transfer_buffer[i], - sb_size, cx231xx_isoc_irq_callback, dma_q, 1); - - urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP; - - k = 0; - for (j = 0; j < max_packets; j++) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - dev->video_mode.isoc_ctl.max_pkt_size; - k += dev->video_mode.isoc_ctl.max_pkt_size; - } - } - - init_waitqueue_head(&dma_q->wq); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) { - rc = usb_submit_urb(dev->video_mode.isoc_ctl.urb[i], - GFP_ATOMIC); - if (rc) { - cx231xx_err("submit of urb %i failed (error=%i)\n", i, - rc); - cx231xx_uninit_isoc(dev); - return rc; - } - } - - if (dev->mode_tv == 0) - cx231xx_capture_start(dev, 1, Raw_Video); - else - cx231xx_capture_start(dev, 1, TS1_serial_mode); - - return 0; -} -EXPORT_SYMBOL_GPL(cx231xx_init_isoc); - -/* - * Allocate URBs and start IRQ - */ -int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*bulk_copy) (struct cx231xx *dev, struct urb *urb)) -{ - struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; - int i; - int sb_size, pipe; - struct urb *urb; - int rc; - - dev->video_input = dev->video_input > 2 ? 2 : dev->video_input; - - cx231xx_coredbg("Setting Video mux to %d\n", dev->video_input); - - video_mux(dev, dev->video_input); - - /* De-allocates all pending stuff */ - cx231xx_uninit_bulk(dev); - - dev->video_mode.bulk_ctl.bulk_copy = bulk_copy; - dev->video_mode.bulk_ctl.num_bufs = num_bufs; - dma_q->pos = 0; - dma_q->is_partial_line = 0; - dma_q->last_sav = 0; - dma_q->current_field = -1; - dma_q->field1_done = 0; - dma_q->lines_per_field = dev->height / 2; - dma_q->bytes_left_in_line = dev->width << 1; - dma_q->lines_completed = 0; - dma_q->mpeg_buffer_done = 0; - dma_q->left_data_count = 0; - dma_q->mpeg_buffer_completed = 0; - dma_q->ps_head[0] = 0x00; - dma_q->ps_head[1] = 0x00; - dma_q->ps_head[2] = 0x01; - dma_q->ps_head[3] = 0xBA; - for (i = 0; i < 8; i++) - dma_q->partial_buf[i] = 0; - - dev->video_mode.bulk_ctl.urb = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); - if (!dev->video_mode.bulk_ctl.urb) { - cx231xx_errdev("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - - dev->video_mode.bulk_ctl.transfer_buffer = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); - if (!dev->video_mode.bulk_ctl.transfer_buffer) { - cx231xx_errdev("cannot allocate memory for usbtransfer\n"); - kfree(dev->video_mode.bulk_ctl.urb); - return -ENOMEM; - } - - dev->video_mode.bulk_ctl.max_pkt_size = max_pkt_size; - dev->video_mode.bulk_ctl.buf = NULL; - - sb_size = max_packets * dev->video_mode.bulk_ctl.max_pkt_size; - - if (dev->mode_tv == 1) - dev->video_mode.end_point_addr = 0x81; - else - dev->video_mode.end_point_addr = 0x84; - - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i); - cx231xx_uninit_bulk(dev); - return -ENOMEM; - } - dev->video_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = 0; - - dev->video_mode.bulk_ctl.transfer_buffer[i] = - usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, - &urb->transfer_dma); - if (!dev->video_mode.bulk_ctl.transfer_buffer[i]) { - cx231xx_err("unable to allocate %i bytes for transfer" - " buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); - cx231xx_uninit_bulk(dev); - return -ENOMEM; - } - memset(dev->video_mode.bulk_ctl.transfer_buffer[i], 0, sb_size); - - pipe = usb_rcvbulkpipe(dev->udev, - dev->video_mode.end_point_addr); - usb_fill_bulk_urb(urb, dev->udev, pipe, - dev->video_mode.bulk_ctl.transfer_buffer[i], - sb_size, cx231xx_bulk_irq_callback, dma_q); - } - - init_waitqueue_head(&dma_q->wq); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) { - rc = usb_submit_urb(dev->video_mode.bulk_ctl.urb[i], - GFP_ATOMIC); - if (rc) { - cx231xx_err("submit of urb %i failed (error=%i)\n", i, - rc); - cx231xx_uninit_bulk(dev); - return rc; - } - } - - if (dev->mode_tv == 0) - cx231xx_capture_start(dev, 1, Raw_Video); - else - cx231xx_capture_start(dev, 1, TS1_serial_mode); - - return 0; -} -EXPORT_SYMBOL_GPL(cx231xx_init_bulk); -void cx231xx_stop_TS1(struct cx231xx *dev) -{ - int status = 0; - u8 val[4] = { 0, 0, 0, 0 }; - - val[0] = 0x00; - val[1] = 0x03; - val[2] = 0x00; - val[3] = 0x00; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - TS_MODE_REG, val, 4); - - val[0] = 0x00; - val[1] = 0x70; - val[2] = 0x04; - val[3] = 0x00; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - TS1_CFG_REG, val, 4); -} -/* EXPORT_SYMBOL_GPL(cx231xx_stop_TS1); */ -void cx231xx_start_TS1(struct cx231xx *dev) -{ - int status = 0; - u8 val[4] = { 0, 0, 0, 0 }; - - val[0] = 0x03; - val[1] = 0x03; - val[2] = 0x00; - val[3] = 0x00; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - TS_MODE_REG, val, 4); - - val[0] = 0x04; - val[1] = 0xA3; - val[2] = 0x3B; - val[3] = 0x00; - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, - TS1_CFG_REG, val, 4); -} -/* EXPORT_SYMBOL_GPL(cx231xx_start_TS1); */ -/***************************************************************** -* Device Init/UnInit functions * -******************************************************************/ -int cx231xx_dev_init(struct cx231xx *dev) -{ - int errCode = 0; - - /* Initialize I2C bus */ - - /* External Master 1 Bus */ - dev->i2c_bus[0].nr = 0; - dev->i2c_bus[0].dev = dev; - dev->i2c_bus[0].i2c_period = I2C_SPEED_100K; /* 100 KHz */ - dev->i2c_bus[0].i2c_nostop = 0; - dev->i2c_bus[0].i2c_reserve = 0; - - /* External Master 2 Bus */ - dev->i2c_bus[1].nr = 1; - dev->i2c_bus[1].dev = dev; - dev->i2c_bus[1].i2c_period = I2C_SPEED_100K; /* 100 KHz */ - dev->i2c_bus[1].i2c_nostop = 0; - dev->i2c_bus[1].i2c_reserve = 0; - - /* Internal Master 3 Bus */ - dev->i2c_bus[2].nr = 2; - dev->i2c_bus[2].dev = dev; - dev->i2c_bus[2].i2c_period = I2C_SPEED_100K; /* 100kHz */ - dev->i2c_bus[2].i2c_nostop = 0; - dev->i2c_bus[2].i2c_reserve = 0; - - /* register I2C buses */ - cx231xx_i2c_register(&dev->i2c_bus[0]); - cx231xx_i2c_register(&dev->i2c_bus[1]); - cx231xx_i2c_register(&dev->i2c_bus[2]); - - /* init hardware */ - /* Note : with out calling set power mode function, - afe can not be set up correctly */ - if (dev->board.external_av) { - errCode = cx231xx_set_power_mode(dev, - POLARIS_AVMODE_ENXTERNAL_AV); - if (errCode < 0) { - cx231xx_errdev - ("%s: Failed to set Power - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - } else { - errCode = cx231xx_set_power_mode(dev, - POLARIS_AVMODE_ANALOGT_TV); - if (errCode < 0) { - cx231xx_errdev - ("%s: Failed to set Power - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - } - - /* reset the Tuner, if it is a Xceive tuner */ - if ((dev->board.tuner_type == TUNER_XC5000) || - (dev->board.tuner_type == TUNER_XC2028)) - cx231xx_gpio_set(dev, dev->board.tuner_gpio); - - /* initialize Colibri block */ - errCode = cx231xx_afe_init_super_block(dev, 0x23c); - if (errCode < 0) { - cx231xx_errdev - ("%s: cx231xx_afe init super block - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - errCode = cx231xx_afe_init_channels(dev); - if (errCode < 0) { - cx231xx_errdev - ("%s: cx231xx_afe init channels - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* Set DIF in By pass mode */ - errCode = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND); - if (errCode < 0) { - cx231xx_errdev - ("%s: cx231xx_dif set to By pass mode - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* I2S block related functions */ - errCode = cx231xx_i2s_blk_initialize(dev); - if (errCode < 0) { - cx231xx_errdev - ("%s: cx231xx_i2s block initialize - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* init control pins */ - errCode = cx231xx_init_ctrl_pin_status(dev); - if (errCode < 0) { - cx231xx_errdev("%s: cx231xx_init ctrl pins - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* set AGC mode to Analog */ - switch (dev->model) { - case CX231XX_BOARD_CNXT_CARRAERA: - case CX231XX_BOARD_CNXT_RDE_250: - case CX231XX_BOARD_CNXT_SHELBY: - case CX231XX_BOARD_CNXT_RDU_250: - errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1); - break; - case CX231XX_BOARD_CNXT_RDE_253S: - case CX231XX_BOARD_CNXT_RDU_253S: - case CX231XX_BOARD_HAUPPAUGE_EXETER: - case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: - errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); - break; - default: - break; - } - if (errCode < 0) { - cx231xx_errdev - ("%s: cx231xx_AGC mode to Analog - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* set all alternate settings to zero initially */ - cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0); - cx231xx_set_alt_setting(dev, INDEX_VANC, 0); - cx231xx_set_alt_setting(dev, INDEX_HANC, 0); - if (dev->board.has_dvb) - cx231xx_set_alt_setting(dev, INDEX_TS1, 0); - - /* set the I2C master port to 3 on channel 1 */ - errCode = cx231xx_enable_i2c_port_3(dev, true); - - return errCode; -} -EXPORT_SYMBOL_GPL(cx231xx_dev_init); - -void cx231xx_dev_uninit(struct cx231xx *dev) -{ - /* Un Initialize I2C bus */ - cx231xx_i2c_unregister(&dev->i2c_bus[2]); - cx231xx_i2c_unregister(&dev->i2c_bus[1]); - cx231xx_i2c_unregister(&dev->i2c_bus[0]); -} -EXPORT_SYMBOL_GPL(cx231xx_dev_uninit); - -/***************************************************************** -* G P I O related functions * -******************************************************************/ -int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val, - u8 len, u8 request, u8 direction) -{ - int status = 0; - struct VENDOR_REQUEST_IN ven_req; - - /* Set wValue */ - ven_req.wValue = (u16) (gpio_bit >> 16 & 0xffff); - - /* set request */ - if (!request) { - if (direction) - ven_req.bRequest = VRT_GET_GPIO; /* 0x8 gpio */ - else - ven_req.bRequest = VRT_SET_GPIO; /* 0x9 gpio */ - } else { - if (direction) - ven_req.bRequest = VRT_GET_GPIE; /* 0xa gpie */ - else - ven_req.bRequest = VRT_SET_GPIE; /* 0xb gpie */ - } - - /* set index value */ - ven_req.wIndex = (u16) (gpio_bit & 0xffff); - - /* set wLength value */ - ven_req.wLength = len; - - /* set bData value */ - ven_req.bData = 0; - - /* set the buffer for read / write */ - ven_req.pBuff = gpio_val; - - /* set the direction */ - if (direction) { - ven_req.direction = USB_DIR_IN; - memset(ven_req.pBuff, 0x00, ven_req.wLength); - } else - ven_req.direction = USB_DIR_OUT; - - - /* call common vendor command request */ - status = cx231xx_send_vendor_cmd(dev, &ven_req); - if (status < 0) { - cx231xx_info - ("UsbInterface::sendCommand, failed with status -%d\n", - status); - } - - return status; -} -EXPORT_SYMBOL_GPL(cx231xx_send_gpio_cmd); - -/***************************************************************** - * C O N T R O L - Register R E A D / W R I T E functions * - *****************************************************************/ -int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode) -{ - u8 value[4] = { 0x0, 0x0, 0x0, 0x0 }; - u32 tmp = 0; - int status = 0; - - status = - cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, address, value, 4); - if (status < 0) - return status; - - tmp = *((u32 *) value); - tmp |= mode; - - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - - status = - cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, address, value, 4); - - return status; -} - -/***************************************************************** - * I 2 C Internal C O N T R O L functions * - *****************************************************************/ -int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr, - u8 saddr_len, u32 *data, u8 data_len, int master) -{ - int status = 0; - struct cx231xx_i2c_xfer_data req_data; - u8 value[64] = "0"; - - if (saddr_len == 0) - saddr = 0; - else if (saddr_len == 1) - saddr &= 0xff; - - /* prepare xfer_data struct */ - req_data.dev_addr = dev_addr >> 1; - req_data.direction = I2C_M_RD; - req_data.saddr_len = saddr_len; - req_data.saddr_dat = saddr; - req_data.buf_size = data_len; - req_data.p_buffer = (u8 *) value; - - /* usb send command */ - if (master == 0) - status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], - &req_data); - else if (master == 1) - status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1], - &req_data); - else if (master == 2) - status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2], - &req_data); - - if (status >= 0) { - /* Copy the data read back to main buffer */ - if (data_len == 1) - *data = value[0]; - else if (data_len == 4) - *data = - value[0] | value[1] << 8 | value[2] << 16 | value[3] - << 24; - else if (data_len > 4) - *data = value[saddr]; - } - - return status; -} - -int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr, - u8 saddr_len, u32 data, u8 data_len, int master) -{ - int status = 0; - u8 value[4] = { 0, 0, 0, 0 }; - struct cx231xx_i2c_xfer_data req_data; - - value[0] = (u8) data; - value[1] = (u8) (data >> 8); - value[2] = (u8) (data >> 16); - value[3] = (u8) (data >> 24); - - if (saddr_len == 0) - saddr = 0; - else if (saddr_len == 1) - saddr &= 0xff; - - /* prepare xfer_data struct */ - req_data.dev_addr = dev_addr >> 1; - req_data.direction = 0; - req_data.saddr_len = saddr_len; - req_data.saddr_dat = saddr; - req_data.buf_size = data_len; - req_data.p_buffer = value; - - /* usb send command */ - if (master == 0) - status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], - &req_data); - else if (master == 1) - status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1], - &req_data); - else if (master == 2) - status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2], - &req_data); - - return status; -} - -int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr, - u8 saddr_len, u32 *data, u8 data_len) -{ - int status = 0; - struct cx231xx_i2c_xfer_data req_data; - u8 value[4] = { 0, 0, 0, 0 }; - - if (saddr_len == 0) - saddr = 0; - else if (saddr_len == 1) - saddr &= 0xff; - - /* prepare xfer_data struct */ - req_data.dev_addr = dev_addr >> 1; - req_data.direction = I2C_M_RD; - req_data.saddr_len = saddr_len; - req_data.saddr_dat = saddr; - req_data.buf_size = data_len; - req_data.p_buffer = (u8 *) value; - - /* usb send command */ - status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], &req_data); - - if (status >= 0) { - /* Copy the data read back to main buffer */ - if (data_len == 1) - *data = value[0]; - else - *data = - value[0] | value[1] << 8 | value[2] << 16 | value[3] - << 24; - } - - return status; -} - -int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr, - u8 saddr_len, u32 data, u8 data_len) -{ - int status = 0; - u8 value[4] = { 0, 0, 0, 0 }; - struct cx231xx_i2c_xfer_data req_data; - - value[0] = (u8) data; - value[1] = (u8) (data >> 8); - value[2] = (u8) (data >> 16); - value[3] = (u8) (data >> 24); - - if (saddr_len == 0) - saddr = 0; - else if (saddr_len == 1) - saddr &= 0xff; - - /* prepare xfer_data struct */ - req_data.dev_addr = dev_addr >> 1; - req_data.direction = 0; - req_data.saddr_len = saddr_len; - req_data.saddr_dat = saddr; - req_data.buf_size = data_len; - req_data.p_buffer = value; - - /* usb send command */ - status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], &req_data); - - return status; -} - -int cx231xx_reg_mask_write(struct cx231xx *dev, u8 dev_addr, u8 size, - u16 register_address, u8 bit_start, u8 bit_end, - u32 value) -{ - int status = 0; - u32 tmp; - u32 mask = 0; - int i; - - if (bit_start > (size - 1) || bit_end > (size - 1)) - return -1; - - if (size == 8) { - status = - cx231xx_read_i2c_data(dev, dev_addr, register_address, 2, - &tmp, 1); - } else { - status = - cx231xx_read_i2c_data(dev, dev_addr, register_address, 2, - &tmp, 4); - } - - if (status < 0) - return status; - - mask = 1 << bit_end; - for (i = bit_end; i > bit_start && i > 0; i--) - mask = mask + (1 << (i - 1)); - - value <<= bit_start; - - if (size == 8) { - tmp &= ~mask; - tmp |= value; - tmp &= 0xff; - status = - cx231xx_write_i2c_data(dev, dev_addr, register_address, 2, - tmp, 1); - } else { - tmp &= ~mask; - tmp |= value; - status = - cx231xx_write_i2c_data(dev, dev_addr, register_address, 2, - tmp, 4); - } - - return status; -} - -int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr, - u16 saddr, u32 mask, u32 value) -{ - u32 temp; - int status = 0; - - status = cx231xx_read_i2c_data(dev, dev_addr, saddr, 2, &temp, 4); - - if (status < 0) - return status; - - temp &= ~mask; - temp |= value; - - status = cx231xx_write_i2c_data(dev, dev_addr, saddr, 2, temp, 4); - - return status; -} - -u32 cx231xx_set_field(u32 field_mask, u32 data) -{ - u32 temp; - - for (temp = field_mask; (temp & 1) == 0; temp >>= 1) - data <<= 1; - - return data; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-dif.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-dif.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-dif.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-dif.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,3178 +0,0 @@ -/* - * cx231xx-dif.h - driver for Conexant Cx23100/101/102 USB video capture devices - * - * Copyright {C} 2009 - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _CX231XX_DIF_H -#define _CX231XX_DIF_H - -#include "cx231xx-reg.h" - -struct dif_settings{ - u32 if_freq; - u32 register_address; - u32 value; -}; - -static struct dif_settings Dif_set_array[] = { - -/*case 3000000:*/ -/* BEGIN - DIF BPF register values from 30_quant.dat*/ -{3000000, DIF_BPF_COEFF01, 0x00000002}, -{3000000, DIF_BPF_COEFF23, 0x00080012}, -{3000000, DIF_BPF_COEFF45, 0x001e0024}, -{3000000, DIF_BPF_COEFF67, 0x001bfff8}, -{3000000, DIF_BPF_COEFF89, 0xffb4ff50}, -{3000000, DIF_BPF_COEFF1011, 0xfed8fe68}, -{3000000, DIF_BPF_COEFF1213, 0xfe24fe34}, -{3000000, DIF_BPF_COEFF1415, 0xfebaffc7}, -{3000000, DIF_BPF_COEFF1617, 0x014d031f}, -{3000000, DIF_BPF_COEFF1819, 0x04f0065d}, -{3000000, DIF_BPF_COEFF2021, 0x07010688}, -{3000000, DIF_BPF_COEFF2223, 0x04c901d6}, -{3000000, DIF_BPF_COEFF2425, 0xfe00f9d3}, -{3000000, DIF_BPF_COEFF2627, 0xf600f342}, -{3000000, DIF_BPF_COEFF2829, 0xf235f337}, -{3000000, DIF_BPF_COEFF3031, 0xf64efb22}, -{3000000, DIF_BPF_COEFF3233, 0x0105070f}, -{3000000, DIF_BPF_COEFF3435, 0x0c460fce}, -{3000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 30_quant.dat*/ - - -/*case 3100000:*/ -/* BEGIN - DIF BPF register values from 31_quant.dat*/ -{3100000, DIF_BPF_COEFF01, 0x00000001}, -{3100000, DIF_BPF_COEFF23, 0x00070012}, -{3100000, DIF_BPF_COEFF45, 0x00220032}, -{3100000, DIF_BPF_COEFF67, 0x00370026}, -{3100000, DIF_BPF_COEFF89, 0xfff0ff91}, -{3100000, DIF_BPF_COEFF1011, 0xff0efe7c}, -{3100000, DIF_BPF_COEFF1213, 0xfe01fdcc}, -{3100000, DIF_BPF_COEFF1415, 0xfe0afedb}, -{3100000, DIF_BPF_COEFF1617, 0x00440224}, -{3100000, DIF_BPF_COEFF1819, 0x0434060c}, -{3100000, DIF_BPF_COEFF2021, 0x0738074e}, -{3100000, DIF_BPF_COEFF2223, 0x06090361}, -{3100000, DIF_BPF_COEFF2425, 0xff99fb39}, -{3100000, DIF_BPF_COEFF2627, 0xf6fef3b6}, -{3100000, DIF_BPF_COEFF2829, 0xf21af2a5}, -{3100000, DIF_BPF_COEFF3031, 0xf573fa33}, -{3100000, DIF_BPF_COEFF3233, 0x0034067d}, -{3100000, DIF_BPF_COEFF3435, 0x0bfb0fb9}, -{3100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 31_quant.dat*/ - - -/*case 3200000:*/ -/* BEGIN - DIF BPF register values from 32_quant.dat*/ -{3200000, DIF_BPF_COEFF01, 0x00000000}, -{3200000, DIF_BPF_COEFF23, 0x0004000e}, -{3200000, DIF_BPF_COEFF45, 0x00200038}, -{3200000, DIF_BPF_COEFF67, 0x004c004f}, -{3200000, DIF_BPF_COEFF89, 0x002fffdf}, -{3200000, DIF_BPF_COEFF1011, 0xff5cfeb6}, -{3200000, DIF_BPF_COEFF1213, 0xfe0dfd92}, -{3200000, DIF_BPF_COEFF1415, 0xfd7ffe03}, -{3200000, DIF_BPF_COEFF1617, 0xff36010a}, -{3200000, DIF_BPF_COEFF1819, 0x03410575}, -{3200000, DIF_BPF_COEFF2021, 0x072607d2}, -{3200000, DIF_BPF_COEFF2223, 0x071804d5}, -{3200000, DIF_BPF_COEFF2425, 0x0134fcb7}, -{3200000, DIF_BPF_COEFF2627, 0xf81ff451}, -{3200000, DIF_BPF_COEFF2829, 0xf223f22e}, -{3200000, DIF_BPF_COEFF3031, 0xf4a7f94b}, -{3200000, DIF_BPF_COEFF3233, 0xff6405e8}, -{3200000, DIF_BPF_COEFF3435, 0x0bae0fa4}, -{3200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 32_quant.dat*/ - - -/*case 3300000:*/ -/* BEGIN - DIF BPF register values from 33_quant.dat*/ -{3300000, DIF_BPF_COEFF01, 0x0000ffff}, -{3300000, DIF_BPF_COEFF23, 0x00000008}, -{3300000, DIF_BPF_COEFF45, 0x001a0036}, -{3300000, DIF_BPF_COEFF67, 0x0056006d}, -{3300000, DIF_BPF_COEFF89, 0x00670030}, -{3300000, DIF_BPF_COEFF1011, 0xffbdff10}, -{3300000, DIF_BPF_COEFF1213, 0xfe46fd8d}, -{3300000, DIF_BPF_COEFF1415, 0xfd25fd4f}, -{3300000, DIF_BPF_COEFF1617, 0xfe35ffe0}, -{3300000, DIF_BPF_COEFF1819, 0x0224049f}, -{3300000, DIF_BPF_COEFF2021, 0x06c9080e}, -{3300000, DIF_BPF_COEFF2223, 0x07ef0627}, -{3300000, DIF_BPF_COEFF2425, 0x02c9fe45}, -{3300000, DIF_BPF_COEFF2627, 0xf961f513}, -{3300000, DIF_BPF_COEFF2829, 0xf250f1d2}, -{3300000, DIF_BPF_COEFF3031, 0xf3ecf869}, -{3300000, DIF_BPF_COEFF3233, 0xfe930552}, -{3300000, DIF_BPF_COEFF3435, 0x0b5f0f8f}, -{3300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 33_quant.dat*/ - - -/*case 3400000:*/ -/* BEGIN - DIF BPF register values from 34_quant.dat*/ -{3400000, DIF_BPF_COEFF01, 0xfffffffe}, -{3400000, DIF_BPF_COEFF23, 0xfffd0001}, -{3400000, DIF_BPF_COEFF45, 0x000f002c}, -{3400000, DIF_BPF_COEFF67, 0x0054007d}, -{3400000, DIF_BPF_COEFF89, 0x0093007c}, -{3400000, DIF_BPF_COEFF1011, 0x0024ff82}, -{3400000, DIF_BPF_COEFF1213, 0xfea6fdbb}, -{3400000, DIF_BPF_COEFF1415, 0xfd03fcca}, -{3400000, DIF_BPF_COEFF1617, 0xfd51feb9}, -{3400000, DIF_BPF_COEFF1819, 0x00eb0392}, -{3400000, DIF_BPF_COEFF2021, 0x06270802}, -{3400000, DIF_BPF_COEFF2223, 0x08880750}, -{3400000, DIF_BPF_COEFF2425, 0x044dffdb}, -{3400000, DIF_BPF_COEFF2627, 0xfabdf5f8}, -{3400000, DIF_BPF_COEFF2829, 0xf2a0f193}, -{3400000, DIF_BPF_COEFF3031, 0xf342f78f}, -{3400000, DIF_BPF_COEFF3233, 0xfdc404b9}, -{3400000, DIF_BPF_COEFF3435, 0x0b0e0f78}, -{3400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 34_quant.dat*/ - - -/*case 3500000:*/ -/* BEGIN - DIF BPF register values from 35_quant.dat*/ -{3500000, DIF_BPF_COEFF01, 0xfffffffd}, -{3500000, DIF_BPF_COEFF23, 0xfffafff9}, -{3500000, DIF_BPF_COEFF45, 0x0002001b}, -{3500000, DIF_BPF_COEFF67, 0x0046007d}, -{3500000, DIF_BPF_COEFF89, 0x00ad00ba}, -{3500000, DIF_BPF_COEFF1011, 0x00870000}, -{3500000, DIF_BPF_COEFF1213, 0xff26fe1a}, -{3500000, DIF_BPF_COEFF1415, 0xfd1bfc7e}, -{3500000, DIF_BPF_COEFF1617, 0xfc99fda4}, -{3500000, DIF_BPF_COEFF1819, 0xffa5025c}, -{3500000, DIF_BPF_COEFF2021, 0x054507ad}, -{3500000, DIF_BPF_COEFF2223, 0x08dd0847}, -{3500000, DIF_BPF_COEFF2425, 0x05b80172}, -{3500000, DIF_BPF_COEFF2627, 0xfc2ef6ff}, -{3500000, DIF_BPF_COEFF2829, 0xf313f170}, -{3500000, DIF_BPF_COEFF3031, 0xf2abf6bd}, -{3500000, DIF_BPF_COEFF3233, 0xfcf6041f}, -{3500000, DIF_BPF_COEFF3435, 0x0abc0f61}, -{3500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 35_quant.dat*/ - - -/*case 3600000:*/ -/* BEGIN - DIF BPF register values from 36_quant.dat*/ -{3600000, DIF_BPF_COEFF01, 0xfffffffd}, -{3600000, DIF_BPF_COEFF23, 0xfff8fff3}, -{3600000, DIF_BPF_COEFF45, 0xfff50006}, -{3600000, DIF_BPF_COEFF67, 0x002f006c}, -{3600000, DIF_BPF_COEFF89, 0x00b200e3}, -{3600000, DIF_BPF_COEFF1011, 0x00dc007e}, -{3600000, DIF_BPF_COEFF1213, 0xffb9fea0}, -{3600000, DIF_BPF_COEFF1415, 0xfd6bfc71}, -{3600000, DIF_BPF_COEFF1617, 0xfc17fcb1}, -{3600000, DIF_BPF_COEFF1819, 0xfe65010b}, -{3600000, DIF_BPF_COEFF2021, 0x042d0713}, -{3600000, DIF_BPF_COEFF2223, 0x08ec0906}, -{3600000, DIF_BPF_COEFF2425, 0x07020302}, -{3600000, DIF_BPF_COEFF2627, 0xfdaff823}, -{3600000, DIF_BPF_COEFF2829, 0xf3a7f16a}, -{3600000, DIF_BPF_COEFF3031, 0xf228f5f5}, -{3600000, DIF_BPF_COEFF3233, 0xfc2a0384}, -{3600000, DIF_BPF_COEFF3435, 0x0a670f4a}, -{3600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 36_quant.dat*/ - - -/*case 3700000:*/ -/* BEGIN - DIF BPF register values from 37_quant.dat*/ -{3700000, DIF_BPF_COEFF01, 0x0000fffd}, -{3700000, DIF_BPF_COEFF23, 0xfff7ffef}, -{3700000, DIF_BPF_COEFF45, 0xffe9fff1}, -{3700000, DIF_BPF_COEFF67, 0x0010004d}, -{3700000, DIF_BPF_COEFF89, 0x00a100f2}, -{3700000, DIF_BPF_COEFF1011, 0x011a00f0}, -{3700000, DIF_BPF_COEFF1213, 0x0053ff44}, -{3700000, DIF_BPF_COEFF1415, 0xfdedfca2}, -{3700000, DIF_BPF_COEFF1617, 0xfbd3fbef}, -{3700000, DIF_BPF_COEFF1819, 0xfd39ffae}, -{3700000, DIF_BPF_COEFF2021, 0x02ea0638}, -{3700000, DIF_BPF_COEFF2223, 0x08b50987}, -{3700000, DIF_BPF_COEFF2425, 0x08230483}, -{3700000, DIF_BPF_COEFF2627, 0xff39f960}, -{3700000, DIF_BPF_COEFF2829, 0xf45bf180}, -{3700000, DIF_BPF_COEFF3031, 0xf1b8f537}, -{3700000, DIF_BPF_COEFF3233, 0xfb6102e7}, -{3700000, DIF_BPF_COEFF3435, 0x0a110f32}, -{3700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 37_quant.dat*/ - - -/*case 3800000:*/ -/* BEGIN - DIF BPF register values from 38_quant.dat*/ -{3800000, DIF_BPF_COEFF01, 0x0000fffe}, -{3800000, DIF_BPF_COEFF23, 0xfff9ffee}, -{3800000, DIF_BPF_COEFF45, 0xffe1ffdd}, -{3800000, DIF_BPF_COEFF67, 0xfff00024}, -{3800000, DIF_BPF_COEFF89, 0x007c00e5}, -{3800000, DIF_BPF_COEFF1011, 0x013a014a}, -{3800000, DIF_BPF_COEFF1213, 0x00e6fff8}, -{3800000, DIF_BPF_COEFF1415, 0xfe98fd0f}, -{3800000, DIF_BPF_COEFF1617, 0xfbd3fb67}, -{3800000, DIF_BPF_COEFF1819, 0xfc32fe54}, -{3800000, DIF_BPF_COEFF2021, 0x01880525}, -{3800000, DIF_BPF_COEFF2223, 0x083909c7}, -{3800000, DIF_BPF_COEFF2425, 0x091505ee}, -{3800000, DIF_BPF_COEFF2627, 0x00c7fab3}, -{3800000, DIF_BPF_COEFF2829, 0xf52df1b4}, -{3800000, DIF_BPF_COEFF3031, 0xf15df484}, -{3800000, DIF_BPF_COEFF3233, 0xfa9b0249}, -{3800000, DIF_BPF_COEFF3435, 0x09ba0f19}, -{3800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 38_quant.dat*/ - - -/*case 3900000:*/ -/* BEGIN - DIF BPF register values from 39_quant.dat*/ -{3900000, DIF_BPF_COEFF01, 0x00000000}, -{3900000, DIF_BPF_COEFF23, 0xfffbfff0}, -{3900000, DIF_BPF_COEFF45, 0xffdeffcf}, -{3900000, DIF_BPF_COEFF67, 0xffd1fff6}, -{3900000, DIF_BPF_COEFF89, 0x004800be}, -{3900000, DIF_BPF_COEFF1011, 0x01390184}, -{3900000, DIF_BPF_COEFF1213, 0x016300ac}, -{3900000, DIF_BPF_COEFF1415, 0xff5efdb1}, -{3900000, DIF_BPF_COEFF1617, 0xfc17fb23}, -{3900000, DIF_BPF_COEFF1819, 0xfb5cfd0d}, -{3900000, DIF_BPF_COEFF2021, 0x001703e4}, -{3900000, DIF_BPF_COEFF2223, 0x077b09c4}, -{3900000, DIF_BPF_COEFF2425, 0x09d2073c}, -{3900000, DIF_BPF_COEFF2627, 0x0251fc18}, -{3900000, DIF_BPF_COEFF2829, 0xf61cf203}, -{3900000, DIF_BPF_COEFF3031, 0xf118f3dc}, -{3900000, DIF_BPF_COEFF3233, 0xf9d801aa}, -{3900000, DIF_BPF_COEFF3435, 0x09600eff}, -{3900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 39_quant.dat*/ - - -/*case 4000000:*/ -/* BEGIN - DIF BPF register values from 40_quant.dat*/ -{4000000, DIF_BPF_COEFF01, 0x00000001}, -{4000000, DIF_BPF_COEFF23, 0xfffefff4}, -{4000000, DIF_BPF_COEFF45, 0xffe1ffc8}, -{4000000, DIF_BPF_COEFF67, 0xffbaffca}, -{4000000, DIF_BPF_COEFF89, 0x000b0082}, -{4000000, DIF_BPF_COEFF1011, 0x01170198}, -{4000000, DIF_BPF_COEFF1213, 0x01c10152}, -{4000000, DIF_BPF_COEFF1415, 0x0030fe7b}, -{4000000, DIF_BPF_COEFF1617, 0xfc99fb24}, -{4000000, DIF_BPF_COEFF1819, 0xfac3fbe9}, -{4000000, DIF_BPF_COEFF2021, 0xfea5027f}, -{4000000, DIF_BPF_COEFF2223, 0x0683097f}, -{4000000, DIF_BPF_COEFF2425, 0x0a560867}, -{4000000, DIF_BPF_COEFF2627, 0x03d2fd89}, -{4000000, DIF_BPF_COEFF2829, 0xf723f26f}, -{4000000, DIF_BPF_COEFF3031, 0xf0e8f341}, -{4000000, DIF_BPF_COEFF3233, 0xf919010a}, -{4000000, DIF_BPF_COEFF3435, 0x09060ee5}, -{4000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 40_quant.dat*/ - - -/*case 4100000:*/ -/* BEGIN - DIF BPF register values from 41_quant.dat*/ -{4100000, DIF_BPF_COEFF01, 0x00010002}, -{4100000, DIF_BPF_COEFF23, 0x0002fffb}, -{4100000, DIF_BPF_COEFF45, 0xffe8ffca}, -{4100000, DIF_BPF_COEFF67, 0xffacffa4}, -{4100000, DIF_BPF_COEFF89, 0xffcd0036}, -{4100000, DIF_BPF_COEFF1011, 0x00d70184}, -{4100000, DIF_BPF_COEFF1213, 0x01f601dc}, -{4100000, DIF_BPF_COEFF1415, 0x00ffff60}, -{4100000, DIF_BPF_COEFF1617, 0xfd51fb6d}, -{4100000, DIF_BPF_COEFF1819, 0xfa6efaf5}, -{4100000, DIF_BPF_COEFF2021, 0xfd410103}, -{4100000, DIF_BPF_COEFF2223, 0x055708f9}, -{4100000, DIF_BPF_COEFF2425, 0x0a9e0969}, -{4100000, DIF_BPF_COEFF2627, 0x0543ff02}, -{4100000, DIF_BPF_COEFF2829, 0xf842f2f5}, -{4100000, DIF_BPF_COEFF3031, 0xf0cef2b2}, -{4100000, DIF_BPF_COEFF3233, 0xf85e006b}, -{4100000, DIF_BPF_COEFF3435, 0x08aa0ecb}, -{4100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 41_quant.dat*/ - - -/*case 4200000:*/ -/* BEGIN - DIF BPF register values from 42_quant.dat*/ -{4200000, DIF_BPF_COEFF01, 0x00010003}, -{4200000, DIF_BPF_COEFF23, 0x00050003}, -{4200000, DIF_BPF_COEFF45, 0xfff3ffd3}, -{4200000, DIF_BPF_COEFF67, 0xffaaff8b}, -{4200000, DIF_BPF_COEFF89, 0xff95ffe5}, -{4200000, DIF_BPF_COEFF1011, 0x0080014a}, -{4200000, DIF_BPF_COEFF1213, 0x01fe023f}, -{4200000, DIF_BPF_COEFF1415, 0x01ba0050}, -{4200000, DIF_BPF_COEFF1617, 0xfe35fbf8}, -{4200000, DIF_BPF_COEFF1819, 0xfa62fa3b}, -{4200000, DIF_BPF_COEFF2021, 0xfbf9ff7e}, -{4200000, DIF_BPF_COEFF2223, 0x04010836}, -{4200000, DIF_BPF_COEFF2425, 0x0aa90a3d}, -{4200000, DIF_BPF_COEFF2627, 0x069f007f}, -{4200000, DIF_BPF_COEFF2829, 0xf975f395}, -{4200000, DIF_BPF_COEFF3031, 0xf0cbf231}, -{4200000, DIF_BPF_COEFF3233, 0xf7a9ffcb}, -{4200000, DIF_BPF_COEFF3435, 0x084c0eaf}, -{4200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 42_quant.dat*/ - - -/*case 4300000:*/ -/* BEGIN - DIF BPF register values from 43_quant.dat*/ -{4300000, DIF_BPF_COEFF01, 0x00010003}, -{4300000, DIF_BPF_COEFF23, 0x0008000a}, -{4300000, DIF_BPF_COEFF45, 0x0000ffe4}, -{4300000, DIF_BPF_COEFF67, 0xffb4ff81}, -{4300000, DIF_BPF_COEFF89, 0xff6aff96}, -{4300000, DIF_BPF_COEFF1011, 0x001c00f0}, -{4300000, DIF_BPF_COEFF1213, 0x01d70271}, -{4300000, DIF_BPF_COEFF1415, 0x0254013b}, -{4300000, DIF_BPF_COEFF1617, 0xff36fcbd}, -{4300000, DIF_BPF_COEFF1819, 0xfa9ff9c5}, -{4300000, DIF_BPF_COEFF2021, 0xfadbfdfe}, -{4300000, DIF_BPF_COEFF2223, 0x028c073b}, -{4300000, DIF_BPF_COEFF2425, 0x0a750adf}, -{4300000, DIF_BPF_COEFF2627, 0x07e101fa}, -{4300000, DIF_BPF_COEFF2829, 0xfab8f44e}, -{4300000, DIF_BPF_COEFF3031, 0xf0ddf1be}, -{4300000, DIF_BPF_COEFF3233, 0xf6f9ff2b}, -{4300000, DIF_BPF_COEFF3435, 0x07ed0e94}, -{4300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 43_quant.dat*/ - - -/*case 4400000:*/ -/* BEGIN - DIF BPF register values from 44_quant.dat*/ -{4400000, DIF_BPF_COEFF01, 0x00000003}, -{4400000, DIF_BPF_COEFF23, 0x0009000f}, -{4400000, DIF_BPF_COEFF45, 0x000efff8}, -{4400000, DIF_BPF_COEFF67, 0xffc9ff87}, -{4400000, DIF_BPF_COEFF89, 0xff52ff54}, -{4400000, DIF_BPF_COEFF1011, 0xffb5007e}, -{4400000, DIF_BPF_COEFF1213, 0x01860270}, -{4400000, DIF_BPF_COEFF1415, 0x02c00210}, -{4400000, DIF_BPF_COEFF1617, 0x0044fdb2}, -{4400000, DIF_BPF_COEFF1819, 0xfb22f997}, -{4400000, DIF_BPF_COEFF2021, 0xf9f2fc90}, -{4400000, DIF_BPF_COEFF2223, 0x0102060f}, -{4400000, DIF_BPF_COEFF2425, 0x0a050b4c}, -{4400000, DIF_BPF_COEFF2627, 0x0902036e}, -{4400000, DIF_BPF_COEFF2829, 0xfc0af51e}, -{4400000, DIF_BPF_COEFF3031, 0xf106f15a}, -{4400000, DIF_BPF_COEFF3233, 0xf64efe8b}, -{4400000, DIF_BPF_COEFF3435, 0x078d0e77}, -{4400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 44_quant.dat*/ - - -/*case 4500000:*/ -/* BEGIN - DIF BPF register values from 45_quant.dat*/ -{4500000, DIF_BPF_COEFF01, 0x00000002}, -{4500000, DIF_BPF_COEFF23, 0x00080012}, -{4500000, DIF_BPF_COEFF45, 0x0019000e}, -{4500000, DIF_BPF_COEFF67, 0xffe5ff9e}, -{4500000, DIF_BPF_COEFF89, 0xff4fff25}, -{4500000, DIF_BPF_COEFF1011, 0xff560000}, -{4500000, DIF_BPF_COEFF1213, 0x0112023b}, -{4500000, DIF_BPF_COEFF1415, 0x02f702c0}, -{4500000, DIF_BPF_COEFF1617, 0x014dfec8}, -{4500000, DIF_BPF_COEFF1819, 0xfbe5f9b3}, -{4500000, DIF_BPF_COEFF2021, 0xf947fb41}, -{4500000, DIF_BPF_COEFF2223, 0xff7004b9}, -{4500000, DIF_BPF_COEFF2425, 0x095a0b81}, -{4500000, DIF_BPF_COEFF2627, 0x0a0004d8}, -{4500000, DIF_BPF_COEFF2829, 0xfd65f603}, -{4500000, DIF_BPF_COEFF3031, 0xf144f104}, -{4500000, DIF_BPF_COEFF3233, 0xf5aafdec}, -{4500000, DIF_BPF_COEFF3435, 0x072b0e5a}, -{4500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 45_quant.dat*/ - - -/*case 4600000:*/ -/* BEGIN - DIF BPF register values from 46_quant.dat*/ -{4600000, DIF_BPF_COEFF01, 0x00000001}, -{4600000, DIF_BPF_COEFF23, 0x00060012}, -{4600000, DIF_BPF_COEFF45, 0x00200022}, -{4600000, DIF_BPF_COEFF67, 0x0005ffc1}, -{4600000, DIF_BPF_COEFF89, 0xff61ff10}, -{4600000, DIF_BPF_COEFF1011, 0xff09ff82}, -{4600000, DIF_BPF_COEFF1213, 0x008601d7}, -{4600000, DIF_BPF_COEFF1415, 0x02f50340}, -{4600000, DIF_BPF_COEFF1617, 0x0241fff0}, -{4600000, DIF_BPF_COEFF1819, 0xfcddfa19}, -{4600000, DIF_BPF_COEFF2021, 0xf8e2fa1e}, -{4600000, DIF_BPF_COEFF2223, 0xfde30343}, -{4600000, DIF_BPF_COEFF2425, 0x08790b7f}, -{4600000, DIF_BPF_COEFF2627, 0x0ad50631}, -{4600000, DIF_BPF_COEFF2829, 0xfec7f6fc}, -{4600000, DIF_BPF_COEFF3031, 0xf198f0bd}, -{4600000, DIF_BPF_COEFF3233, 0xf50dfd4e}, -{4600000, DIF_BPF_COEFF3435, 0x06c90e3d}, -{4600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 46_quant.dat*/ - - -/*case 4700000:*/ -/* BEGIN - DIF BPF register values from 47_quant.dat*/ -{4700000, DIF_BPF_COEFF01, 0x0000ffff}, -{4700000, DIF_BPF_COEFF23, 0x0003000f}, -{4700000, DIF_BPF_COEFF45, 0x00220030}, -{4700000, DIF_BPF_COEFF67, 0x0025ffed}, -{4700000, DIF_BPF_COEFF89, 0xff87ff15}, -{4700000, DIF_BPF_COEFF1011, 0xfed6ff10}, -{4700000, DIF_BPF_COEFF1213, 0xffed014c}, -{4700000, DIF_BPF_COEFF1415, 0x02b90386}, -{4700000, DIF_BPF_COEFF1617, 0x03110119}, -{4700000, DIF_BPF_COEFF1819, 0xfdfefac4}, -{4700000, DIF_BPF_COEFF2021, 0xf8c6f92f}, -{4700000, DIF_BPF_COEFF2223, 0xfc6701b7}, -{4700000, DIF_BPF_COEFF2425, 0x07670b44}, -{4700000, DIF_BPF_COEFF2627, 0x0b7e0776}, -{4700000, DIF_BPF_COEFF2829, 0x002df807}, -{4700000, DIF_BPF_COEFF3031, 0xf200f086}, -{4700000, DIF_BPF_COEFF3233, 0xf477fcb1}, -{4700000, DIF_BPF_COEFF3435, 0x06650e1e}, -{4700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 47_quant.dat*/ - - -/*case 4800000:*/ -/* BEGIN - DIF BPF register values from 48_quant.dat*/ -{4800000, DIF_BPF_COEFF01, 0xfffffffe}, -{4800000, DIF_BPF_COEFF23, 0xffff0009}, -{4800000, DIF_BPF_COEFF45, 0x001e0038}, -{4800000, DIF_BPF_COEFF67, 0x003f001b}, -{4800000, DIF_BPF_COEFF89, 0xffbcff36}, -{4800000, DIF_BPF_COEFF1011, 0xfec2feb6}, -{4800000, DIF_BPF_COEFF1213, 0xff5600a5}, -{4800000, DIF_BPF_COEFF1415, 0x0248038d}, -{4800000, DIF_BPF_COEFF1617, 0x03b00232}, -{4800000, DIF_BPF_COEFF1819, 0xff39fbab}, -{4800000, DIF_BPF_COEFF2021, 0xf8f4f87f}, -{4800000, DIF_BPF_COEFF2223, 0xfb060020}, -{4800000, DIF_BPF_COEFF2425, 0x062a0ad2}, -{4800000, DIF_BPF_COEFF2627, 0x0bf908a3}, -{4800000, DIF_BPF_COEFF2829, 0x0192f922}, -{4800000, DIF_BPF_COEFF3031, 0xf27df05e}, -{4800000, DIF_BPF_COEFF3233, 0xf3e8fc14}, -{4800000, DIF_BPF_COEFF3435, 0x06000e00}, -{4800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 48_quant.dat*/ - - -/*case 4900000:*/ -/* BEGIN - DIF BPF register values from 49_quant.dat*/ -{4900000, DIF_BPF_COEFF01, 0xfffffffd}, -{4900000, DIF_BPF_COEFF23, 0xfffc0002}, -{4900000, DIF_BPF_COEFF45, 0x00160037}, -{4900000, DIF_BPF_COEFF67, 0x00510046}, -{4900000, DIF_BPF_COEFF89, 0xfff9ff6d}, -{4900000, DIF_BPF_COEFF1011, 0xfed0fe7c}, -{4900000, DIF_BPF_COEFF1213, 0xfecefff0}, -{4900000, DIF_BPF_COEFF1415, 0x01aa0356}, -{4900000, DIF_BPF_COEFF1617, 0x0413032b}, -{4900000, DIF_BPF_COEFF1819, 0x007ffcc5}, -{4900000, DIF_BPF_COEFF2021, 0xf96cf812}, -{4900000, DIF_BPF_COEFF2223, 0xf9cefe87}, -{4900000, DIF_BPF_COEFF2425, 0x04c90a2c}, -{4900000, DIF_BPF_COEFF2627, 0x0c4309b4}, -{4900000, DIF_BPF_COEFF2829, 0x02f3fa4a}, -{4900000, DIF_BPF_COEFF3031, 0xf30ef046}, -{4900000, DIF_BPF_COEFF3233, 0xf361fb7a}, -{4900000, DIF_BPF_COEFF3435, 0x059b0de0}, -{4900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 49_quant.dat*/ - - -/*case 5000000:*/ -/* BEGIN - DIF BPF register values from 50_quant.dat*/ -{5000000, DIF_BPF_COEFF01, 0xfffffffd}, -{5000000, DIF_BPF_COEFF23, 0xfff9fffa}, -{5000000, DIF_BPF_COEFF45, 0x000a002d}, -{5000000, DIF_BPF_COEFF67, 0x00570067}, -{5000000, DIF_BPF_COEFF89, 0x0037ffb5}, -{5000000, DIF_BPF_COEFF1011, 0xfefffe68}, -{5000000, DIF_BPF_COEFF1213, 0xfe62ff3d}, -{5000000, DIF_BPF_COEFF1415, 0x00ec02e3}, -{5000000, DIF_BPF_COEFF1617, 0x043503f6}, -{5000000, DIF_BPF_COEFF1819, 0x01befe05}, -{5000000, DIF_BPF_COEFF2021, 0xfa27f7ee}, -{5000000, DIF_BPF_COEFF2223, 0xf8c6fcf8}, -{5000000, DIF_BPF_COEFF2425, 0x034c0954}, -{5000000, DIF_BPF_COEFF2627, 0x0c5c0aa4}, -{5000000, DIF_BPF_COEFF2829, 0x044cfb7e}, -{5000000, DIF_BPF_COEFF3031, 0xf3b1f03f}, -{5000000, DIF_BPF_COEFF3233, 0xf2e2fae1}, -{5000000, DIF_BPF_COEFF3435, 0x05340dc0}, -{5000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 50_quant.dat*/ - - -/*case 5100000:*/ -/* BEGIN - DIF BPF register values from 51_quant.dat*/ -{5100000, DIF_BPF_COEFF01, 0x0000fffd}, -{5100000, DIF_BPF_COEFF23, 0xfff8fff4}, -{5100000, DIF_BPF_COEFF45, 0xfffd001e}, -{5100000, DIF_BPF_COEFF67, 0x0051007b}, -{5100000, DIF_BPF_COEFF89, 0x006e0006}, -{5100000, DIF_BPF_COEFF1011, 0xff48fe7c}, -{5100000, DIF_BPF_COEFF1213, 0xfe1bfe9a}, -{5100000, DIF_BPF_COEFF1415, 0x001d023e}, -{5100000, DIF_BPF_COEFF1617, 0x04130488}, -{5100000, DIF_BPF_COEFF1819, 0x02e6ff5b}, -{5100000, DIF_BPF_COEFF2021, 0xfb1ef812}, -{5100000, DIF_BPF_COEFF2223, 0xf7f7fb7f}, -{5100000, DIF_BPF_COEFF2425, 0x01bc084e}, -{5100000, DIF_BPF_COEFF2627, 0x0c430b72}, -{5100000, DIF_BPF_COEFF2829, 0x059afcba}, -{5100000, DIF_BPF_COEFF3031, 0xf467f046}, -{5100000, DIF_BPF_COEFF3233, 0xf26cfa4a}, -{5100000, DIF_BPF_COEFF3435, 0x04cd0da0}, -{5100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 51_quant.dat*/ - - -/*case 5200000:*/ -/* BEGIN - DIF BPF register values from 52_quant.dat*/ -{5200000, DIF_BPF_COEFF01, 0x0000fffe}, -{5200000, DIF_BPF_COEFF23, 0xfff8ffef}, -{5200000, DIF_BPF_COEFF45, 0xfff00009}, -{5200000, DIF_BPF_COEFF67, 0x003f007f}, -{5200000, DIF_BPF_COEFF89, 0x00980056}, -{5200000, DIF_BPF_COEFF1011, 0xffa5feb6}, -{5200000, DIF_BPF_COEFF1213, 0xfe00fe15}, -{5200000, DIF_BPF_COEFF1415, 0xff4b0170}, -{5200000, DIF_BPF_COEFF1617, 0x03b004d7}, -{5200000, DIF_BPF_COEFF1819, 0x03e800b9}, -{5200000, DIF_BPF_COEFF2021, 0xfc48f87f}, -{5200000, DIF_BPF_COEFF2223, 0xf768fa23}, -{5200000, DIF_BPF_COEFF2425, 0x0022071f}, -{5200000, DIF_BPF_COEFF2627, 0x0bf90c1b}, -{5200000, DIF_BPF_COEFF2829, 0x06dafdfd}, -{5200000, DIF_BPF_COEFF3031, 0xf52df05e}, -{5200000, DIF_BPF_COEFF3233, 0xf1fef9b5}, -{5200000, DIF_BPF_COEFF3435, 0x04640d7f}, -{5200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 52_quant.dat*/ - - -/*case 5300000:*/ -/* BEGIN - DIF BPF register values from 53_quant.dat*/ -{5300000, DIF_BPF_COEFF01, 0x0000ffff}, -{5300000, DIF_BPF_COEFF23, 0xfff9ffee}, -{5300000, DIF_BPF_COEFF45, 0xffe6fff3}, -{5300000, DIF_BPF_COEFF67, 0x00250072}, -{5300000, DIF_BPF_COEFF89, 0x00af009c}, -{5300000, DIF_BPF_COEFF1011, 0x000cff10}, -{5300000, DIF_BPF_COEFF1213, 0xfe13fdb8}, -{5300000, DIF_BPF_COEFF1415, 0xfe870089}, -{5300000, DIF_BPF_COEFF1617, 0x031104e1}, -{5300000, DIF_BPF_COEFF1819, 0x04b8020f}, -{5300000, DIF_BPF_COEFF2021, 0xfd98f92f}, -{5300000, DIF_BPF_COEFF2223, 0xf71df8f0}, -{5300000, DIF_BPF_COEFF2425, 0xfe8805ce}, -{5300000, DIF_BPF_COEFF2627, 0x0b7e0c9c}, -{5300000, DIF_BPF_COEFF2829, 0x0808ff44}, -{5300000, DIF_BPF_COEFF3031, 0xf603f086}, -{5300000, DIF_BPF_COEFF3233, 0xf19af922}, -{5300000, DIF_BPF_COEFF3435, 0x03fb0d5e}, -{5300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 53_quant.dat*/ - - -/*case 5400000:*/ -/* BEGIN - DIF BPF register values from 54_quant.dat*/ -{5400000, DIF_BPF_COEFF01, 0x00000001}, -{5400000, DIF_BPF_COEFF23, 0xfffcffef}, -{5400000, DIF_BPF_COEFF45, 0xffe0ffe0}, -{5400000, DIF_BPF_COEFF67, 0x00050056}, -{5400000, DIF_BPF_COEFF89, 0x00b000d1}, -{5400000, DIF_BPF_COEFF1011, 0x0071ff82}, -{5400000, DIF_BPF_COEFF1213, 0xfe53fd8c}, -{5400000, DIF_BPF_COEFF1415, 0xfddfff99}, -{5400000, DIF_BPF_COEFF1617, 0x024104a3}, -{5400000, DIF_BPF_COEFF1819, 0x054a034d}, -{5400000, DIF_BPF_COEFF2021, 0xff01fa1e}, -{5400000, DIF_BPF_COEFF2223, 0xf717f7ed}, -{5400000, DIF_BPF_COEFF2425, 0xfcf50461}, -{5400000, DIF_BPF_COEFF2627, 0x0ad50cf4}, -{5400000, DIF_BPF_COEFF2829, 0x0921008d}, -{5400000, DIF_BPF_COEFF3031, 0xf6e7f0bd}, -{5400000, DIF_BPF_COEFF3233, 0xf13ff891}, -{5400000, DIF_BPF_COEFF3435, 0x03920d3b}, -{5400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 54_quant.dat*/ - - -/*case 5500000:*/ -/* BEGIN - DIF BPF register values from 55_quant.dat*/ -{5500000, DIF_BPF_COEFF01, 0x00010002}, -{5500000, DIF_BPF_COEFF23, 0xfffffff3}, -{5500000, DIF_BPF_COEFF45, 0xffdeffd1}, -{5500000, DIF_BPF_COEFF67, 0xffe5002f}, -{5500000, DIF_BPF_COEFF89, 0x009c00ed}, -{5500000, DIF_BPF_COEFF1011, 0x00cb0000}, -{5500000, DIF_BPF_COEFF1213, 0xfebafd94}, -{5500000, DIF_BPF_COEFF1415, 0xfd61feb0}, -{5500000, DIF_BPF_COEFF1617, 0x014d0422}, -{5500000, DIF_BPF_COEFF1819, 0x05970464}, -{5500000, DIF_BPF_COEFF2021, 0x0074fb41}, -{5500000, DIF_BPF_COEFF2223, 0xf759f721}, -{5500000, DIF_BPF_COEFF2425, 0xfb7502de}, -{5500000, DIF_BPF_COEFF2627, 0x0a000d21}, -{5500000, DIF_BPF_COEFF2829, 0x0a2201d4}, -{5500000, DIF_BPF_COEFF3031, 0xf7d9f104}, -{5500000, DIF_BPF_COEFF3233, 0xf0edf804}, -{5500000, DIF_BPF_COEFF3435, 0x03280d19}, -{5500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 55_quant.dat*/ - - -/*case 5600000:*/ -/* BEGIN - DIF BPF register values from 56_quant.dat*/ -{5600000, DIF_BPF_COEFF01, 0x00010003}, -{5600000, DIF_BPF_COEFF23, 0x0003fffa}, -{5600000, DIF_BPF_COEFF45, 0xffe3ffc9}, -{5600000, DIF_BPF_COEFF67, 0xffc90002}, -{5600000, DIF_BPF_COEFF89, 0x007500ef}, -{5600000, DIF_BPF_COEFF1011, 0x010e007e}, -{5600000, DIF_BPF_COEFF1213, 0xff3dfdcf}, -{5600000, DIF_BPF_COEFF1415, 0xfd16fddd}, -{5600000, DIF_BPF_COEFF1617, 0x00440365}, -{5600000, DIF_BPF_COEFF1819, 0x059b0548}, -{5600000, DIF_BPF_COEFF2021, 0x01e3fc90}, -{5600000, DIF_BPF_COEFF2223, 0xf7dff691}, -{5600000, DIF_BPF_COEFF2425, 0xfa0f014d}, -{5600000, DIF_BPF_COEFF2627, 0x09020d23}, -{5600000, DIF_BPF_COEFF2829, 0x0b0a0318}, -{5600000, DIF_BPF_COEFF3031, 0xf8d7f15a}, -{5600000, DIF_BPF_COEFF3233, 0xf0a5f779}, -{5600000, DIF_BPF_COEFF3435, 0x02bd0cf6}, -{5600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 56_quant.dat*/ - - -/*case 5700000:*/ -/* BEGIN - DIF BPF register values from 57_quant.dat*/ -{5700000, DIF_BPF_COEFF01, 0x00010003}, -{5700000, DIF_BPF_COEFF23, 0x00060001}, -{5700000, DIF_BPF_COEFF45, 0xffecffc9}, -{5700000, DIF_BPF_COEFF67, 0xffb4ffd4}, -{5700000, DIF_BPF_COEFF89, 0x004000d5}, -{5700000, DIF_BPF_COEFF1011, 0x013600f0}, -{5700000, DIF_BPF_COEFF1213, 0xffd3fe39}, -{5700000, DIF_BPF_COEFF1415, 0xfd04fd31}, -{5700000, DIF_BPF_COEFF1617, 0xff360277}, -{5700000, DIF_BPF_COEFF1819, 0x055605ef}, -{5700000, DIF_BPF_COEFF2021, 0x033efdfe}, -{5700000, DIF_BPF_COEFF2223, 0xf8a5f642}, -{5700000, DIF_BPF_COEFF2425, 0xf8cbffb6}, -{5700000, DIF_BPF_COEFF2627, 0x07e10cfb}, -{5700000, DIF_BPF_COEFF2829, 0x0bd50456}, -{5700000, DIF_BPF_COEFF3031, 0xf9dff1be}, -{5700000, DIF_BPF_COEFF3233, 0xf067f6f2}, -{5700000, DIF_BPF_COEFF3435, 0x02520cd2}, -{5700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 57_quant.dat*/ - - -/*case 5800000:*/ -/* BEGIN - DIF BPF register values from 58_quant.dat*/ -{5800000, DIF_BPF_COEFF01, 0x00000003}, -{5800000, DIF_BPF_COEFF23, 0x00080009}, -{5800000, DIF_BPF_COEFF45, 0xfff8ffd2}, -{5800000, DIF_BPF_COEFF67, 0xffaaffac}, -{5800000, DIF_BPF_COEFF89, 0x000200a3}, -{5800000, DIF_BPF_COEFF1011, 0x013c014a}, -{5800000, DIF_BPF_COEFF1213, 0x006dfec9}, -{5800000, DIF_BPF_COEFF1415, 0xfd2bfcb7}, -{5800000, DIF_BPF_COEFF1617, 0xfe350165}, -{5800000, DIF_BPF_COEFF1819, 0x04cb0651}, -{5800000, DIF_BPF_COEFF2021, 0x0477ff7e}, -{5800000, DIF_BPF_COEFF2223, 0xf9a5f635}, -{5800000, DIF_BPF_COEFF2425, 0xf7b1fe20}, -{5800000, DIF_BPF_COEFF2627, 0x069f0ca8}, -{5800000, DIF_BPF_COEFF2829, 0x0c81058b}, -{5800000, DIF_BPF_COEFF3031, 0xfaf0f231}, -{5800000, DIF_BPF_COEFF3233, 0xf033f66d}, -{5800000, DIF_BPF_COEFF3435, 0x01e60cae}, -{5800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 58_quant.dat*/ - - -/*case 5900000:*/ -/* BEGIN - DIF BPF register values from 59_quant.dat*/ -{5900000, DIF_BPF_COEFF01, 0x00000002}, -{5900000, DIF_BPF_COEFF23, 0x0009000e}, -{5900000, DIF_BPF_COEFF45, 0x0005ffe1}, -{5900000, DIF_BPF_COEFF67, 0xffacff90}, -{5900000, DIF_BPF_COEFF89, 0xffc5005f}, -{5900000, DIF_BPF_COEFF1011, 0x01210184}, -{5900000, DIF_BPF_COEFF1213, 0x00fcff72}, -{5900000, DIF_BPF_COEFF1415, 0xfd8afc77}, -{5900000, DIF_BPF_COEFF1617, 0xfd51003f}, -{5900000, DIF_BPF_COEFF1819, 0x04020669}, -{5900000, DIF_BPF_COEFF2021, 0x05830103}, -{5900000, DIF_BPF_COEFF2223, 0xfad7f66b}, -{5900000, DIF_BPF_COEFF2425, 0xf6c8fc93}, -{5900000, DIF_BPF_COEFF2627, 0x05430c2b}, -{5900000, DIF_BPF_COEFF2829, 0x0d0d06b5}, -{5900000, DIF_BPF_COEFF3031, 0xfc08f2b2}, -{5900000, DIF_BPF_COEFF3233, 0xf00af5ec}, -{5900000, DIF_BPF_COEFF3435, 0x017b0c89}, -{5900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 59_quant.dat*/ - - -/*case 6000000:*/ -/* BEGIN - DIF BPF register values from 60_quant.dat*/ -{6000000, DIF_BPF_COEFF01, 0x00000001}, -{6000000, DIF_BPF_COEFF23, 0x00070012}, -{6000000, DIF_BPF_COEFF45, 0x0012fff5}, -{6000000, DIF_BPF_COEFF67, 0xffbaff82}, -{6000000, DIF_BPF_COEFF89, 0xff8e000f}, -{6000000, DIF_BPF_COEFF1011, 0x00e80198}, -{6000000, DIF_BPF_COEFF1213, 0x01750028}, -{6000000, DIF_BPF_COEFF1415, 0xfe18fc75}, -{6000000, DIF_BPF_COEFF1617, 0xfc99ff15}, -{6000000, DIF_BPF_COEFF1819, 0x03050636}, -{6000000, DIF_BPF_COEFF2021, 0x0656027f}, -{6000000, DIF_BPF_COEFF2223, 0xfc32f6e2}, -{6000000, DIF_BPF_COEFF2425, 0xf614fb17}, -{6000000, DIF_BPF_COEFF2627, 0x03d20b87}, -{6000000, DIF_BPF_COEFF2829, 0x0d7707d2}, -{6000000, DIF_BPF_COEFF3031, 0xfd26f341}, -{6000000, DIF_BPF_COEFF3233, 0xefeaf56f}, -{6000000, DIF_BPF_COEFF3435, 0x010f0c64}, -{6000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 60_quant.dat*/ - - -/*case 6100000:*/ -/* BEGIN - DIF BPF register values from 61_quant.dat*/ -{6100000, DIF_BPF_COEFF01, 0xffff0000}, -{6100000, DIF_BPF_COEFF23, 0x00050012}, -{6100000, DIF_BPF_COEFF45, 0x001c000b}, -{6100000, DIF_BPF_COEFF67, 0xffd1ff84}, -{6100000, DIF_BPF_COEFF89, 0xff66ffbe}, -{6100000, DIF_BPF_COEFF1011, 0x00960184}, -{6100000, DIF_BPF_COEFF1213, 0x01cd00da}, -{6100000, DIF_BPF_COEFF1415, 0xfeccfcb2}, -{6100000, DIF_BPF_COEFF1617, 0xfc17fdf9}, -{6100000, DIF_BPF_COEFF1819, 0x01e005bc}, -{6100000, DIF_BPF_COEFF2021, 0x06e703e4}, -{6100000, DIF_BPF_COEFF2223, 0xfdabf798}, -{6100000, DIF_BPF_COEFF2425, 0xf599f9b3}, -{6100000, DIF_BPF_COEFF2627, 0x02510abd}, -{6100000, DIF_BPF_COEFF2829, 0x0dbf08df}, -{6100000, DIF_BPF_COEFF3031, 0xfe48f3dc}, -{6100000, DIF_BPF_COEFF3233, 0xefd5f4f6}, -{6100000, DIF_BPF_COEFF3435, 0x00a20c3e}, -{6100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 61_quant.dat*/ - - -/*case 6200000:*/ -/* BEGIN - DIF BPF register values from 62_quant.dat*/ -{6200000, DIF_BPF_COEFF01, 0xfffffffe}, -{6200000, DIF_BPF_COEFF23, 0x0002000f}, -{6200000, DIF_BPF_COEFF45, 0x0021001f}, -{6200000, DIF_BPF_COEFF67, 0xfff0ff97}, -{6200000, DIF_BPF_COEFF89, 0xff50ff74}, -{6200000, DIF_BPF_COEFF1011, 0x0034014a}, -{6200000, DIF_BPF_COEFF1213, 0x01fa0179}, -{6200000, DIF_BPF_COEFF1415, 0xff97fd2a}, -{6200000, DIF_BPF_COEFF1617, 0xfbd3fcfa}, -{6200000, DIF_BPF_COEFF1819, 0x00a304fe}, -{6200000, DIF_BPF_COEFF2021, 0x07310525}, -{6200000, DIF_BPF_COEFF2223, 0xff37f886}, -{6200000, DIF_BPF_COEFF2425, 0xf55cf86e}, -{6200000, DIF_BPF_COEFF2627, 0x00c709d0}, -{6200000, DIF_BPF_COEFF2829, 0x0de209db}, -{6200000, DIF_BPF_COEFF3031, 0xff6df484}, -{6200000, DIF_BPF_COEFF3233, 0xefcbf481}, -{6200000, DIF_BPF_COEFF3435, 0x00360c18}, -{6200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 62_quant.dat*/ - - -/*case 6300000:*/ -/* BEGIN - DIF BPF register values from 63_quant.dat*/ -{6300000, DIF_BPF_COEFF01, 0xfffffffd}, -{6300000, DIF_BPF_COEFF23, 0xfffe000a}, -{6300000, DIF_BPF_COEFF45, 0x0021002f}, -{6300000, DIF_BPF_COEFF67, 0x0010ffb8}, -{6300000, DIF_BPF_COEFF89, 0xff50ff3b}, -{6300000, DIF_BPF_COEFF1011, 0xffcc00f0}, -{6300000, DIF_BPF_COEFF1213, 0x01fa01fa}, -{6300000, DIF_BPF_COEFF1415, 0x0069fdd4}, -{6300000, DIF_BPF_COEFF1617, 0xfbd3fc26}, -{6300000, DIF_BPF_COEFF1819, 0xff5d0407}, -{6300000, DIF_BPF_COEFF2021, 0x07310638}, -{6300000, DIF_BPF_COEFF2223, 0x00c9f9a8}, -{6300000, DIF_BPF_COEFF2425, 0xf55cf74e}, -{6300000, DIF_BPF_COEFF2627, 0xff3908c3}, -{6300000, DIF_BPF_COEFF2829, 0x0de20ac3}, -{6300000, DIF_BPF_COEFF3031, 0x0093f537}, -{6300000, DIF_BPF_COEFF3233, 0xefcbf410}, -{6300000, DIF_BPF_COEFF3435, 0xffca0bf2}, -{6300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 63_quant.dat*/ - - -/*case 6400000:*/ -/* BEGIN - DIF BPF register values from 64_quant.dat*/ -{6400000, DIF_BPF_COEFF01, 0xfffffffd}, -{6400000, DIF_BPF_COEFF23, 0xfffb0003}, -{6400000, DIF_BPF_COEFF45, 0x001c0037}, -{6400000, DIF_BPF_COEFF67, 0x002fffe2}, -{6400000, DIF_BPF_COEFF89, 0xff66ff17}, -{6400000, DIF_BPF_COEFF1011, 0xff6a007e}, -{6400000, DIF_BPF_COEFF1213, 0x01cd0251}, -{6400000, DIF_BPF_COEFF1415, 0x0134fea5}, -{6400000, DIF_BPF_COEFF1617, 0xfc17fb8b}, -{6400000, DIF_BPF_COEFF1819, 0xfe2002e0}, -{6400000, DIF_BPF_COEFF2021, 0x06e70713}, -{6400000, DIF_BPF_COEFF2223, 0x0255faf5}, -{6400000, DIF_BPF_COEFF2425, 0xf599f658}, -{6400000, DIF_BPF_COEFF2627, 0xfdaf0799}, -{6400000, DIF_BPF_COEFF2829, 0x0dbf0b96}, -{6400000, DIF_BPF_COEFF3031, 0x01b8f5f5}, -{6400000, DIF_BPF_COEFF3233, 0xefd5f3a3}, -{6400000, DIF_BPF_COEFF3435, 0xff5e0bca}, -{6400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 64_quant.dat*/ - - -/*case 6500000:*/ -/* BEGIN - DIF BPF register values from 65_quant.dat*/ -{6500000, DIF_BPF_COEFF01, 0x0000fffd}, -{6500000, DIF_BPF_COEFF23, 0xfff9fffb}, -{6500000, DIF_BPF_COEFF45, 0x00120037}, -{6500000, DIF_BPF_COEFF67, 0x00460010}, -{6500000, DIF_BPF_COEFF89, 0xff8eff0f}, -{6500000, DIF_BPF_COEFF1011, 0xff180000}, -{6500000, DIF_BPF_COEFF1213, 0x01750276}, -{6500000, DIF_BPF_COEFF1415, 0x01e8ff8d}, -{6500000, DIF_BPF_COEFF1617, 0xfc99fb31}, -{6500000, DIF_BPF_COEFF1819, 0xfcfb0198}, -{6500000, DIF_BPF_COEFF2021, 0x065607ad}, -{6500000, DIF_BPF_COEFF2223, 0x03cefc64}, -{6500000, DIF_BPF_COEFF2425, 0xf614f592}, -{6500000, DIF_BPF_COEFF2627, 0xfc2e0656}, -{6500000, DIF_BPF_COEFF2829, 0x0d770c52}, -{6500000, DIF_BPF_COEFF3031, 0x02daf6bd}, -{6500000, DIF_BPF_COEFF3233, 0xefeaf33b}, -{6500000, DIF_BPF_COEFF3435, 0xfef10ba3}, -{6500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 65_quant.dat*/ - - -/*case 6600000:*/ -/* BEGIN - DIF BPF register values from 66_quant.dat*/ -{6600000, DIF_BPF_COEFF01, 0x0000fffe}, -{6600000, DIF_BPF_COEFF23, 0xfff7fff5}, -{6600000, DIF_BPF_COEFF45, 0x0005002f}, -{6600000, DIF_BPF_COEFF67, 0x0054003c}, -{6600000, DIF_BPF_COEFF89, 0xffc5ff22}, -{6600000, DIF_BPF_COEFF1011, 0xfedfff82}, -{6600000, DIF_BPF_COEFF1213, 0x00fc0267}, -{6600000, DIF_BPF_COEFF1415, 0x0276007e}, -{6600000, DIF_BPF_COEFF1617, 0xfd51fb1c}, -{6600000, DIF_BPF_COEFF1819, 0xfbfe003e}, -{6600000, DIF_BPF_COEFF2021, 0x05830802}, -{6600000, DIF_BPF_COEFF2223, 0x0529fdec}, -{6600000, DIF_BPF_COEFF2425, 0xf6c8f4fe}, -{6600000, DIF_BPF_COEFF2627, 0xfabd04ff}, -{6600000, DIF_BPF_COEFF2829, 0x0d0d0cf6}, -{6600000, DIF_BPF_COEFF3031, 0x03f8f78f}, -{6600000, DIF_BPF_COEFF3233, 0xf00af2d7}, -{6600000, DIF_BPF_COEFF3435, 0xfe850b7b}, -{6600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 66_quant.dat*/ - - -/*case 6700000:*/ -/* BEGIN - DIF BPF register values from 67_quant.dat*/ -{6700000, DIF_BPF_COEFF01, 0x0000ffff}, -{6700000, DIF_BPF_COEFF23, 0xfff8fff0}, -{6700000, DIF_BPF_COEFF45, 0xfff80020}, -{6700000, DIF_BPF_COEFF67, 0x00560060}, -{6700000, DIF_BPF_COEFF89, 0x0002ff4e}, -{6700000, DIF_BPF_COEFF1011, 0xfec4ff10}, -{6700000, DIF_BPF_COEFF1213, 0x006d0225}, -{6700000, DIF_BPF_COEFF1415, 0x02d50166}, -{6700000, DIF_BPF_COEFF1617, 0xfe35fb4e}, -{6700000, DIF_BPF_COEFF1819, 0xfb35fee1}, -{6700000, DIF_BPF_COEFF2021, 0x0477080e}, -{6700000, DIF_BPF_COEFF2223, 0x065bff82}, -{6700000, DIF_BPF_COEFF2425, 0xf7b1f4a0}, -{6700000, DIF_BPF_COEFF2627, 0xf9610397}, -{6700000, DIF_BPF_COEFF2829, 0x0c810d80}, -{6700000, DIF_BPF_COEFF3031, 0x0510f869}, -{6700000, DIF_BPF_COEFF3233, 0xf033f278}, -{6700000, DIF_BPF_COEFF3435, 0xfe1a0b52}, -{6700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 67_quant.dat*/ - - -/*case 6800000:*/ -/* BEGIN - DIF BPF register values from 68_quant.dat*/ -{6800000, DIF_BPF_COEFF01, 0x00010000}, -{6800000, DIF_BPF_COEFF23, 0xfffaffee}, -{6800000, DIF_BPF_COEFF45, 0xffec000c}, -{6800000, DIF_BPF_COEFF67, 0x004c0078}, -{6800000, DIF_BPF_COEFF89, 0x0040ff8e}, -{6800000, DIF_BPF_COEFF1011, 0xfecafeb6}, -{6800000, DIF_BPF_COEFF1213, 0xffd301b6}, -{6800000, DIF_BPF_COEFF1415, 0x02fc0235}, -{6800000, DIF_BPF_COEFF1617, 0xff36fbc5}, -{6800000, DIF_BPF_COEFF1819, 0xfaaafd90}, -{6800000, DIF_BPF_COEFF2021, 0x033e07d2}, -{6800000, DIF_BPF_COEFF2223, 0x075b011b}, -{6800000, DIF_BPF_COEFF2425, 0xf8cbf47a}, -{6800000, DIF_BPF_COEFF2627, 0xf81f0224}, -{6800000, DIF_BPF_COEFF2829, 0x0bd50def}, -{6800000, DIF_BPF_COEFF3031, 0x0621f94b}, -{6800000, DIF_BPF_COEFF3233, 0xf067f21e}, -{6800000, DIF_BPF_COEFF3435, 0xfdae0b29}, -{6800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 68_quant.dat*/ - - -/*case 6900000:*/ -/* BEGIN - DIF BPF register values from 69_quant.dat*/ -{6900000, DIF_BPF_COEFF01, 0x00010001}, -{6900000, DIF_BPF_COEFF23, 0xfffdffef}, -{6900000, DIF_BPF_COEFF45, 0xffe3fff6}, -{6900000, DIF_BPF_COEFF67, 0x0037007f}, -{6900000, DIF_BPF_COEFF89, 0x0075ffdc}, -{6900000, DIF_BPF_COEFF1011, 0xfef2fe7c}, -{6900000, DIF_BPF_COEFF1213, 0xff3d0122}, -{6900000, DIF_BPF_COEFF1415, 0x02ea02dd}, -{6900000, DIF_BPF_COEFF1617, 0x0044fc79}, -{6900000, DIF_BPF_COEFF1819, 0xfa65fc5d}, -{6900000, DIF_BPF_COEFF2021, 0x01e3074e}, -{6900000, DIF_BPF_COEFF2223, 0x082102ad}, -{6900000, DIF_BPF_COEFF2425, 0xfa0ff48c}, -{6900000, DIF_BPF_COEFF2627, 0xf6fe00a9}, -{6900000, DIF_BPF_COEFF2829, 0x0b0a0e43}, -{6900000, DIF_BPF_COEFF3031, 0x0729fa33}, -{6900000, DIF_BPF_COEFF3233, 0xf0a5f1c9}, -{6900000, DIF_BPF_COEFF3435, 0xfd430b00}, -{6900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 69_quant.dat*/ - - -/*case 7000000:*/ -/* BEGIN - DIF BPF register values from 70_quant.dat*/ -{7000000, DIF_BPF_COEFF01, 0x00010002}, -{7000000, DIF_BPF_COEFF23, 0x0001fff3}, -{7000000, DIF_BPF_COEFF45, 0xffdeffe2}, -{7000000, DIF_BPF_COEFF67, 0x001b0076}, -{7000000, DIF_BPF_COEFF89, 0x009c002d}, -{7000000, DIF_BPF_COEFF1011, 0xff35fe68}, -{7000000, DIF_BPF_COEFF1213, 0xfeba0076}, -{7000000, DIF_BPF_COEFF1415, 0x029f0352}, -{7000000, DIF_BPF_COEFF1617, 0x014dfd60}, -{7000000, DIF_BPF_COEFF1819, 0xfa69fb53}, -{7000000, DIF_BPF_COEFF2021, 0x00740688}, -{7000000, DIF_BPF_COEFF2223, 0x08a7042d}, -{7000000, DIF_BPF_COEFF2425, 0xfb75f4d6}, -{7000000, DIF_BPF_COEFF2627, 0xf600ff2d}, -{7000000, DIF_BPF_COEFF2829, 0x0a220e7a}, -{7000000, DIF_BPF_COEFF3031, 0x0827fb22}, -{7000000, DIF_BPF_COEFF3233, 0xf0edf17a}, -{7000000, DIF_BPF_COEFF3435, 0xfcd80ad6}, -{7000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 70_quant.dat*/ - - -/*case 7100000:*/ -/* BEGIN - DIF BPF register values from 71_quant.dat*/ -{7100000, DIF_BPF_COEFF01, 0x00000003}, -{7100000, DIF_BPF_COEFF23, 0x0004fff9}, -{7100000, DIF_BPF_COEFF45, 0xffe0ffd2}, -{7100000, DIF_BPF_COEFF67, 0xfffb005e}, -{7100000, DIF_BPF_COEFF89, 0x00b0007a}, -{7100000, DIF_BPF_COEFF1011, 0xff8ffe7c}, -{7100000, DIF_BPF_COEFF1213, 0xfe53ffc1}, -{7100000, DIF_BPF_COEFF1415, 0x0221038c}, -{7100000, DIF_BPF_COEFF1617, 0x0241fe6e}, -{7100000, DIF_BPF_COEFF1819, 0xfab6fa80}, -{7100000, DIF_BPF_COEFF2021, 0xff010587}, -{7100000, DIF_BPF_COEFF2223, 0x08e90590}, -{7100000, DIF_BPF_COEFF2425, 0xfcf5f556}, -{7100000, DIF_BPF_COEFF2627, 0xf52bfdb3}, -{7100000, DIF_BPF_COEFF2829, 0x09210e95}, -{7100000, DIF_BPF_COEFF3031, 0x0919fc15}, -{7100000, DIF_BPF_COEFF3233, 0xf13ff12f}, -{7100000, DIF_BPF_COEFF3435, 0xfc6e0aab}, -{7100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 71_quant.dat*/ - - -/*case 7200000:*/ -/* BEGIN - DIF BPF register values from 72_quant.dat*/ -{7200000, DIF_BPF_COEFF01, 0x00000003}, -{7200000, DIF_BPF_COEFF23, 0x00070000}, -{7200000, DIF_BPF_COEFF45, 0xffe6ffc9}, -{7200000, DIF_BPF_COEFF67, 0xffdb0039}, -{7200000, DIF_BPF_COEFF89, 0x00af00b8}, -{7200000, DIF_BPF_COEFF1011, 0xfff4feb6}, -{7200000, DIF_BPF_COEFF1213, 0xfe13ff10}, -{7200000, DIF_BPF_COEFF1415, 0x01790388}, -{7200000, DIF_BPF_COEFF1617, 0x0311ff92}, -{7200000, DIF_BPF_COEFF1819, 0xfb48f9ed}, -{7200000, DIF_BPF_COEFF2021, 0xfd980453}, -{7200000, DIF_BPF_COEFF2223, 0x08e306cd}, -{7200000, DIF_BPF_COEFF2425, 0xfe88f60a}, -{7200000, DIF_BPF_COEFF2627, 0xf482fc40}, -{7200000, DIF_BPF_COEFF2829, 0x08080e93}, -{7200000, DIF_BPF_COEFF3031, 0x09fdfd0c}, -{7200000, DIF_BPF_COEFF3233, 0xf19af0ea}, -{7200000, DIF_BPF_COEFF3435, 0xfc050a81}, -{7200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 72_quant.dat*/ - - -/*case 7300000:*/ -/* BEGIN - DIF BPF register values from 73_quant.dat*/ -{7300000, DIF_BPF_COEFF01, 0x00000002}, -{7300000, DIF_BPF_COEFF23, 0x00080008}, -{7300000, DIF_BPF_COEFF45, 0xfff0ffc9}, -{7300000, DIF_BPF_COEFF67, 0xffc1000d}, -{7300000, DIF_BPF_COEFF89, 0x009800e2}, -{7300000, DIF_BPF_COEFF1011, 0x005bff10}, -{7300000, DIF_BPF_COEFF1213, 0xfe00fe74}, -{7300000, DIF_BPF_COEFF1415, 0x00b50345}, -{7300000, DIF_BPF_COEFF1617, 0x03b000bc}, -{7300000, DIF_BPF_COEFF1819, 0xfc18f9a1}, -{7300000, DIF_BPF_COEFF2021, 0xfc4802f9}, -{7300000, DIF_BPF_COEFF2223, 0x089807dc}, -{7300000, DIF_BPF_COEFF2425, 0x0022f6f0}, -{7300000, DIF_BPF_COEFF2627, 0xf407fada}, -{7300000, DIF_BPF_COEFF2829, 0x06da0e74}, -{7300000, DIF_BPF_COEFF3031, 0x0ad3fe06}, -{7300000, DIF_BPF_COEFF3233, 0xf1fef0ab}, -{7300000, DIF_BPF_COEFF3435, 0xfb9c0a55}, -{7300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 73_quant.dat*/ - - -/*case 7400000:*/ -/* BEGIN - DIF BPF register values from 74_quant.dat*/ -{7400000, DIF_BPF_COEFF01, 0x00000001}, -{7400000, DIF_BPF_COEFF23, 0x0008000e}, -{7400000, DIF_BPF_COEFF45, 0xfffdffd0}, -{7400000, DIF_BPF_COEFF67, 0xffafffdf}, -{7400000, DIF_BPF_COEFF89, 0x006e00f2}, -{7400000, DIF_BPF_COEFF1011, 0x00b8ff82}, -{7400000, DIF_BPF_COEFF1213, 0xfe1bfdf8}, -{7400000, DIF_BPF_COEFF1415, 0xffe302c8}, -{7400000, DIF_BPF_COEFF1617, 0x041301dc}, -{7400000, DIF_BPF_COEFF1819, 0xfd1af99e}, -{7400000, DIF_BPF_COEFF2021, 0xfb1e0183}, -{7400000, DIF_BPF_COEFF2223, 0x080908b5}, -{7400000, DIF_BPF_COEFF2425, 0x01bcf801}, -{7400000, DIF_BPF_COEFF2627, 0xf3bdf985}, -{7400000, DIF_BPF_COEFF2829, 0x059a0e38}, -{7400000, DIF_BPF_COEFF3031, 0x0b99ff03}, -{7400000, DIF_BPF_COEFF3233, 0xf26cf071}, -{7400000, DIF_BPF_COEFF3435, 0xfb330a2a}, -{7400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 74_quant.dat*/ - - -/*case 7500000:*/ -/* BEGIN - DIF BPF register values from 75_quant.dat*/ -{7500000, DIF_BPF_COEFF01, 0xffff0000}, -{7500000, DIF_BPF_COEFF23, 0x00070011}, -{7500000, DIF_BPF_COEFF45, 0x000affdf}, -{7500000, DIF_BPF_COEFF67, 0xffa9ffb5}, -{7500000, DIF_BPF_COEFF89, 0x003700e6}, -{7500000, DIF_BPF_COEFF1011, 0x01010000}, -{7500000, DIF_BPF_COEFF1213, 0xfe62fda8}, -{7500000, DIF_BPF_COEFF1415, 0xff140219}, -{7500000, DIF_BPF_COEFF1617, 0x043502e1}, -{7500000, DIF_BPF_COEFF1819, 0xfe42f9e6}, -{7500000, DIF_BPF_COEFF2021, 0xfa270000}, -{7500000, DIF_BPF_COEFF2223, 0x073a0953}, -{7500000, DIF_BPF_COEFF2425, 0x034cf939}, -{7500000, DIF_BPF_COEFF2627, 0xf3a4f845}, -{7500000, DIF_BPF_COEFF2829, 0x044c0de1}, -{7500000, DIF_BPF_COEFF3031, 0x0c4f0000}, -{7500000, DIF_BPF_COEFF3233, 0xf2e2f03c}, -{7500000, DIF_BPF_COEFF3435, 0xfacc09fe}, -{7500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 75_quant.dat*/ - - -/*case 7600000:*/ -/* BEGIN - DIF BPF register values from 76_quant.dat*/ -{7600000, DIF_BPF_COEFF01, 0xffffffff}, -{7600000, DIF_BPF_COEFF23, 0x00040012}, -{7600000, DIF_BPF_COEFF45, 0x0016fff3}, -{7600000, DIF_BPF_COEFF67, 0xffafff95}, -{7600000, DIF_BPF_COEFF89, 0xfff900c0}, -{7600000, DIF_BPF_COEFF1011, 0x0130007e}, -{7600000, DIF_BPF_COEFF1213, 0xfecefd89}, -{7600000, DIF_BPF_COEFF1415, 0xfe560146}, -{7600000, DIF_BPF_COEFF1617, 0x041303bc}, -{7600000, DIF_BPF_COEFF1819, 0xff81fa76}, -{7600000, DIF_BPF_COEFF2021, 0xf96cfe7d}, -{7600000, DIF_BPF_COEFF2223, 0x063209b1}, -{7600000, DIF_BPF_COEFF2425, 0x04c9fa93}, -{7600000, DIF_BPF_COEFF2627, 0xf3bdf71e}, -{7600000, DIF_BPF_COEFF2829, 0x02f30d6e}, -{7600000, DIF_BPF_COEFF3031, 0x0cf200fd}, -{7600000, DIF_BPF_COEFF3233, 0xf361f00e}, -{7600000, DIF_BPF_COEFF3435, 0xfa6509d1}, -{7600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 76_quant.dat*/ - - -/*case 7700000:*/ -/* BEGIN - DIF BPF register values from 77_quant.dat*/ -{7700000, DIF_BPF_COEFF01, 0xfffffffe}, -{7700000, DIF_BPF_COEFF23, 0x00010010}, -{7700000, DIF_BPF_COEFF45, 0x001e0008}, -{7700000, DIF_BPF_COEFF67, 0xffc1ff84}, -{7700000, DIF_BPF_COEFF89, 0xffbc0084}, -{7700000, DIF_BPF_COEFF1011, 0x013e00f0}, -{7700000, DIF_BPF_COEFF1213, 0xff56fd9f}, -{7700000, DIF_BPF_COEFF1415, 0xfdb8005c}, -{7700000, DIF_BPF_COEFF1617, 0x03b00460}, -{7700000, DIF_BPF_COEFF1819, 0x00c7fb45}, -{7700000, DIF_BPF_COEFF2021, 0xf8f4fd07}, -{7700000, DIF_BPF_COEFF2223, 0x04fa09ce}, -{7700000, DIF_BPF_COEFF2425, 0x062afc07}, -{7700000, DIF_BPF_COEFF2627, 0xf407f614}, -{7700000, DIF_BPF_COEFF2829, 0x01920ce0}, -{7700000, DIF_BPF_COEFF3031, 0x0d8301fa}, -{7700000, DIF_BPF_COEFF3233, 0xf3e8efe5}, -{7700000, DIF_BPF_COEFF3435, 0xfa0009a4}, -{7700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 77_quant.dat*/ - - -/*case 7800000:*/ -/* BEGIN - DIF BPF register values from 78_quant.dat*/ -{7800000, DIF_BPF_COEFF01, 0x0000fffd}, -{7800000, DIF_BPF_COEFF23, 0xfffd000b}, -{7800000, DIF_BPF_COEFF45, 0x0022001d}, -{7800000, DIF_BPF_COEFF67, 0xffdbff82}, -{7800000, DIF_BPF_COEFF89, 0xff870039}, -{7800000, DIF_BPF_COEFF1011, 0x012a014a}, -{7800000, DIF_BPF_COEFF1213, 0xffedfde7}, -{7800000, DIF_BPF_COEFF1415, 0xfd47ff6b}, -{7800000, DIF_BPF_COEFF1617, 0x031104c6}, -{7800000, DIF_BPF_COEFF1819, 0x0202fc4c}, -{7800000, DIF_BPF_COEFF2021, 0xf8c6fbad}, -{7800000, DIF_BPF_COEFF2223, 0x039909a7}, -{7800000, DIF_BPF_COEFF2425, 0x0767fd8e}, -{7800000, DIF_BPF_COEFF2627, 0xf482f52b}, -{7800000, DIF_BPF_COEFF2829, 0x002d0c39}, -{7800000, DIF_BPF_COEFF3031, 0x0e0002f4}, -{7800000, DIF_BPF_COEFF3233, 0xf477efc2}, -{7800000, DIF_BPF_COEFF3435, 0xf99b0977}, -{7800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 78_quant.dat*/ - - -/*case 7900000:*/ -/* BEGIN - DIF BPF register values from 79_quant.dat*/ -{7900000, DIF_BPF_COEFF01, 0x0000fffd}, -{7900000, DIF_BPF_COEFF23, 0xfffa0004}, -{7900000, DIF_BPF_COEFF45, 0x0020002d}, -{7900000, DIF_BPF_COEFF67, 0xfffbff91}, -{7900000, DIF_BPF_COEFF89, 0xff61ffe8}, -{7900000, DIF_BPF_COEFF1011, 0x00f70184}, -{7900000, DIF_BPF_COEFF1213, 0x0086fe5c}, -{7900000, DIF_BPF_COEFF1415, 0xfd0bfe85}, -{7900000, DIF_BPF_COEFF1617, 0x024104e5}, -{7900000, DIF_BPF_COEFF1819, 0x0323fd7d}, -{7900000, DIF_BPF_COEFF2021, 0xf8e2fa79}, -{7900000, DIF_BPF_COEFF2223, 0x021d093f}, -{7900000, DIF_BPF_COEFF2425, 0x0879ff22}, -{7900000, DIF_BPF_COEFF2627, 0xf52bf465}, -{7900000, DIF_BPF_COEFF2829, 0xfec70b79}, -{7900000, DIF_BPF_COEFF3031, 0x0e6803eb}, -{7900000, DIF_BPF_COEFF3233, 0xf50defa5}, -{7900000, DIF_BPF_COEFF3435, 0xf937094a}, -{7900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 79_quant.dat*/ - - -/*case 8000000:*/ -/* BEGIN - DIF BPF register values from 80_quant.dat*/ -{8000000, DIF_BPF_COEFF01, 0x0000fffe}, -{8000000, DIF_BPF_COEFF23, 0xfff8fffd}, -{8000000, DIF_BPF_COEFF45, 0x00190036}, -{8000000, DIF_BPF_COEFF67, 0x001bffaf}, -{8000000, DIF_BPF_COEFF89, 0xff4fff99}, -{8000000, DIF_BPF_COEFF1011, 0x00aa0198}, -{8000000, DIF_BPF_COEFF1213, 0x0112fef3}, -{8000000, DIF_BPF_COEFF1415, 0xfd09fdb9}, -{8000000, DIF_BPF_COEFF1617, 0x014d04be}, -{8000000, DIF_BPF_COEFF1819, 0x041bfecc}, -{8000000, DIF_BPF_COEFF2021, 0xf947f978}, -{8000000, DIF_BPF_COEFF2223, 0x00900897}, -{8000000, DIF_BPF_COEFF2425, 0x095a00b9}, -{8000000, DIF_BPF_COEFF2627, 0xf600f3c5}, -{8000000, DIF_BPF_COEFF2829, 0xfd650aa3}, -{8000000, DIF_BPF_COEFF3031, 0x0ebc04de}, -{8000000, DIF_BPF_COEFF3233, 0xf5aaef8e}, -{8000000, DIF_BPF_COEFF3435, 0xf8d5091c}, -{8000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 80_quant.dat*/ - - -/*case 8100000:*/ -/* BEGIN - DIF BPF register values from 81_quant.dat*/ -{8100000, DIF_BPF_COEFF01, 0x0000ffff}, -{8100000, DIF_BPF_COEFF23, 0xfff7fff6}, -{8100000, DIF_BPF_COEFF45, 0x000e0038}, -{8100000, DIF_BPF_COEFF67, 0x0037ffd7}, -{8100000, DIF_BPF_COEFF89, 0xff52ff56}, -{8100000, DIF_BPF_COEFF1011, 0x004b0184}, -{8100000, DIF_BPF_COEFF1213, 0x0186ffa1}, -{8100000, DIF_BPF_COEFF1415, 0xfd40fd16}, -{8100000, DIF_BPF_COEFF1617, 0x00440452}, -{8100000, DIF_BPF_COEFF1819, 0x04de0029}, -{8100000, DIF_BPF_COEFF2021, 0xf9f2f8b2}, -{8100000, DIF_BPF_COEFF2223, 0xfefe07b5}, -{8100000, DIF_BPF_COEFF2425, 0x0a05024d}, -{8100000, DIF_BPF_COEFF2627, 0xf6fef34d}, -{8100000, DIF_BPF_COEFF2829, 0xfc0a09b8}, -{8100000, DIF_BPF_COEFF3031, 0x0efa05cd}, -{8100000, DIF_BPF_COEFF3233, 0xf64eef7d}, -{8100000, DIF_BPF_COEFF3435, 0xf87308ed}, -{8100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 81_quant.dat*/ - - -/*case 8200000:*/ -/* BEGIN - DIF BPF register values from 82_quant.dat*/ -{8200000, DIF_BPF_COEFF01, 0x00010000}, -{8200000, DIF_BPF_COEFF23, 0xfff8fff0}, -{8200000, DIF_BPF_COEFF45, 0x00000031}, -{8200000, DIF_BPF_COEFF67, 0x004c0005}, -{8200000, DIF_BPF_COEFF89, 0xff6aff27}, -{8200000, DIF_BPF_COEFF1011, 0xffe4014a}, -{8200000, DIF_BPF_COEFF1213, 0x01d70057}, -{8200000, DIF_BPF_COEFF1415, 0xfdacfca6}, -{8200000, DIF_BPF_COEFF1617, 0xff3603a7}, -{8200000, DIF_BPF_COEFF1819, 0x05610184}, -{8200000, DIF_BPF_COEFF2021, 0xfadbf82e}, -{8200000, DIF_BPF_COEFF2223, 0xfd74069f}, -{8200000, DIF_BPF_COEFF2425, 0x0a7503d6}, -{8200000, DIF_BPF_COEFF2627, 0xf81ff2ff}, -{8200000, DIF_BPF_COEFF2829, 0xfab808b9}, -{8200000, DIF_BPF_COEFF3031, 0x0f2306b5}, -{8200000, DIF_BPF_COEFF3233, 0xf6f9ef72}, -{8200000, DIF_BPF_COEFF3435, 0xf81308bf}, -{8200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 82_quant.dat*/ - - -/*case 8300000:*/ -/* BEGIN - DIF BPF register values from 83_quant.dat*/ -{8300000, DIF_BPF_COEFF01, 0x00010001}, -{8300000, DIF_BPF_COEFF23, 0xfffbffee}, -{8300000, DIF_BPF_COEFF45, 0xfff30022}, -{8300000, DIF_BPF_COEFF67, 0x00560032}, -{8300000, DIF_BPF_COEFF89, 0xff95ff10}, -{8300000, DIF_BPF_COEFF1011, 0xff8000f0}, -{8300000, DIF_BPF_COEFF1213, 0x01fe0106}, -{8300000, DIF_BPF_COEFF1415, 0xfe46fc71}, -{8300000, DIF_BPF_COEFF1617, 0xfe3502c7}, -{8300000, DIF_BPF_COEFF1819, 0x059e02ce}, -{8300000, DIF_BPF_COEFF2021, 0xfbf9f7f2}, -{8300000, DIF_BPF_COEFF2223, 0xfbff055b}, -{8300000, DIF_BPF_COEFF2425, 0x0aa9054c}, -{8300000, DIF_BPF_COEFF2627, 0xf961f2db}, -{8300000, DIF_BPF_COEFF2829, 0xf97507aa}, -{8300000, DIF_BPF_COEFF3031, 0x0f350797}, -{8300000, DIF_BPF_COEFF3233, 0xf7a9ef6d}, -{8300000, DIF_BPF_COEFF3435, 0xf7b40890}, -{8300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 83_quant.dat*/ - - -/*case 8400000:*/ -/* BEGIN - DIF BPF register values from 84_quant.dat*/ -{8400000, DIF_BPF_COEFF01, 0x00010002}, -{8400000, DIF_BPF_COEFF23, 0xfffeffee}, -{8400000, DIF_BPF_COEFF45, 0xffe8000f}, -{8400000, DIF_BPF_COEFF67, 0x00540058}, -{8400000, DIF_BPF_COEFF89, 0xffcdff14}, -{8400000, DIF_BPF_COEFF1011, 0xff29007e}, -{8400000, DIF_BPF_COEFF1213, 0x01f6019e}, -{8400000, DIF_BPF_COEFF1415, 0xff01fc7c}, -{8400000, DIF_BPF_COEFF1617, 0xfd5101bf}, -{8400000, DIF_BPF_COEFF1819, 0x059203f6}, -{8400000, DIF_BPF_COEFF2021, 0xfd41f7fe}, -{8400000, DIF_BPF_COEFF2223, 0xfaa903f3}, -{8400000, DIF_BPF_COEFF2425, 0x0a9e06a9}, -{8400000, DIF_BPF_COEFF2627, 0xfabdf2e2}, -{8400000, DIF_BPF_COEFF2829, 0xf842068b}, -{8400000, DIF_BPF_COEFF3031, 0x0f320871}, -{8400000, DIF_BPF_COEFF3233, 0xf85eef6e}, -{8400000, DIF_BPF_COEFF3435, 0xf7560860}, -{8400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 84_quant.dat*/ - - -/*case 8500000:*/ -/* BEGIN - DIF BPF register values from 85_quant.dat*/ -{8500000, DIF_BPF_COEFF01, 0x00000003}, -{8500000, DIF_BPF_COEFF23, 0x0002fff2}, -{8500000, DIF_BPF_COEFF45, 0xffe1fff9}, -{8500000, DIF_BPF_COEFF67, 0x00460073}, -{8500000, DIF_BPF_COEFF89, 0x000bff34}, -{8500000, DIF_BPF_COEFF1011, 0xfee90000}, -{8500000, DIF_BPF_COEFF1213, 0x01c10215}, -{8500000, DIF_BPF_COEFF1415, 0xffd0fcc5}, -{8500000, DIF_BPF_COEFF1617, 0xfc99009d}, -{8500000, DIF_BPF_COEFF1819, 0x053d04f1}, -{8500000, DIF_BPF_COEFF2021, 0xfea5f853}, -{8500000, DIF_BPF_COEFF2223, 0xf97d0270}, -{8500000, DIF_BPF_COEFF2425, 0x0a5607e4}, -{8500000, DIF_BPF_COEFF2627, 0xfc2ef314}, -{8500000, DIF_BPF_COEFF2829, 0xf723055f}, -{8500000, DIF_BPF_COEFF3031, 0x0f180943}, -{8500000, DIF_BPF_COEFF3233, 0xf919ef75}, -{8500000, DIF_BPF_COEFF3435, 0xf6fa0830}, -{8500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 85_quant.dat*/ - - -/*case 8600000:*/ -/* BEGIN - DIF BPF register values from 86_quant.dat*/ -{8600000, DIF_BPF_COEFF01, 0x00000003}, -{8600000, DIF_BPF_COEFF23, 0x0005fff8}, -{8600000, DIF_BPF_COEFF45, 0xffdeffe4}, -{8600000, DIF_BPF_COEFF67, 0x002f007f}, -{8600000, DIF_BPF_COEFF89, 0x0048ff6b}, -{8600000, DIF_BPF_COEFF1011, 0xfec7ff82}, -{8600000, DIF_BPF_COEFF1213, 0x0163025f}, -{8600000, DIF_BPF_COEFF1415, 0x00a2fd47}, -{8600000, DIF_BPF_COEFF1617, 0xfc17ff73}, -{8600000, DIF_BPF_COEFF1819, 0x04a405b2}, -{8600000, DIF_BPF_COEFF2021, 0x0017f8ed}, -{8600000, DIF_BPF_COEFF2223, 0xf88500dc}, -{8600000, DIF_BPF_COEFF2425, 0x09d208f9}, -{8600000, DIF_BPF_COEFF2627, 0xfdaff370}, -{8600000, DIF_BPF_COEFF2829, 0xf61c0429}, -{8600000, DIF_BPF_COEFF3031, 0x0ee80a0b}, -{8600000, DIF_BPF_COEFF3233, 0xf9d8ef82}, -{8600000, DIF_BPF_COEFF3435, 0xf6a00800}, -{8600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 86_quant.dat*/ - - -/*case 8700000:*/ -/* BEGIN - DIF BPF register values from 87_quant.dat*/ -{8700000, DIF_BPF_COEFF01, 0x00000003}, -{8700000, DIF_BPF_COEFF23, 0x0007ffff}, -{8700000, DIF_BPF_COEFF45, 0xffe1ffd4}, -{8700000, DIF_BPF_COEFF67, 0x0010007a}, -{8700000, DIF_BPF_COEFF89, 0x007cffb2}, -{8700000, DIF_BPF_COEFF1011, 0xfec6ff10}, -{8700000, DIF_BPF_COEFF1213, 0x00e60277}, -{8700000, DIF_BPF_COEFF1415, 0x0168fdf9}, -{8700000, DIF_BPF_COEFF1617, 0xfbd3fe50}, -{8700000, DIF_BPF_COEFF1819, 0x03ce0631}, -{8700000, DIF_BPF_COEFF2021, 0x0188f9c8}, -{8700000, DIF_BPF_COEFF2223, 0xf7c7ff43}, -{8700000, DIF_BPF_COEFF2425, 0x091509e3}, -{8700000, DIF_BPF_COEFF2627, 0xff39f3f6}, -{8700000, DIF_BPF_COEFF2829, 0xf52d02ea}, -{8700000, DIF_BPF_COEFF3031, 0x0ea30ac9}, -{8700000, DIF_BPF_COEFF3233, 0xfa9bef95}, -{8700000, DIF_BPF_COEFF3435, 0xf64607d0}, -{8700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 87_quant.dat*/ - - -/*case 8800000:*/ -/* BEGIN - DIF BPF register values from 88_quant.dat*/ -{8800000, DIF_BPF_COEFF01, 0x00000002}, -{8800000, DIF_BPF_COEFF23, 0x00090007}, -{8800000, DIF_BPF_COEFF45, 0xffe9ffca}, -{8800000, DIF_BPF_COEFF67, 0xfff00065}, -{8800000, DIF_BPF_COEFF89, 0x00a10003}, -{8800000, DIF_BPF_COEFF1011, 0xfee6feb6}, -{8800000, DIF_BPF_COEFF1213, 0x0053025b}, -{8800000, DIF_BPF_COEFF1415, 0x0213fed0}, -{8800000, DIF_BPF_COEFF1617, 0xfbd3fd46}, -{8800000, DIF_BPF_COEFF1819, 0x02c70668}, -{8800000, DIF_BPF_COEFF2021, 0x02eafadb}, -{8800000, DIF_BPF_COEFF2223, 0xf74bfdae}, -{8800000, DIF_BPF_COEFF2425, 0x08230a9c}, -{8800000, DIF_BPF_COEFF2627, 0x00c7f4a3}, -{8800000, DIF_BPF_COEFF2829, 0xf45b01a6}, -{8800000, DIF_BPF_COEFF3031, 0x0e480b7c}, -{8800000, DIF_BPF_COEFF3233, 0xfb61efae}, -{8800000, DIF_BPF_COEFF3435, 0xf5ef079f}, -{8800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 88_quant.dat*/ - - -/*case 8900000:*/ -/* BEGIN - DIF BPF register values from 89_quant.dat*/ -{8900000, DIF_BPF_COEFF01, 0xffff0000}, -{8900000, DIF_BPF_COEFF23, 0x0008000d}, -{8900000, DIF_BPF_COEFF45, 0xfff5ffc8}, -{8900000, DIF_BPF_COEFF67, 0xffd10043}, -{8900000, DIF_BPF_COEFF89, 0x00b20053}, -{8900000, DIF_BPF_COEFF1011, 0xff24fe7c}, -{8900000, DIF_BPF_COEFF1213, 0xffb9020c}, -{8900000, DIF_BPF_COEFF1415, 0x0295ffbb}, -{8900000, DIF_BPF_COEFF1617, 0xfc17fc64}, -{8900000, DIF_BPF_COEFF1819, 0x019b0654}, -{8900000, DIF_BPF_COEFF2021, 0x042dfc1c}, -{8900000, DIF_BPF_COEFF2223, 0xf714fc2a}, -{8900000, DIF_BPF_COEFF2425, 0x07020b21}, -{8900000, DIF_BPF_COEFF2627, 0x0251f575}, -{8900000, DIF_BPF_COEFF2829, 0xf3a7005e}, -{8900000, DIF_BPF_COEFF3031, 0x0dd80c24}, -{8900000, DIF_BPF_COEFF3233, 0xfc2aefcd}, -{8900000, DIF_BPF_COEFF3435, 0xf599076e}, -{8900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 89_quant.dat*/ - - -/*case 9000000:*/ -/* BEGIN - DIF BPF register values from 90_quant.dat*/ -{9000000, DIF_BPF_COEFF01, 0xffffffff}, -{9000000, DIF_BPF_COEFF23, 0x00060011}, -{9000000, DIF_BPF_COEFF45, 0x0002ffcf}, -{9000000, DIF_BPF_COEFF67, 0xffba0018}, -{9000000, DIF_BPF_COEFF89, 0x00ad009a}, -{9000000, DIF_BPF_COEFF1011, 0xff79fe68}, -{9000000, DIF_BPF_COEFF1213, 0xff260192}, -{9000000, DIF_BPF_COEFF1415, 0x02e500ab}, -{9000000, DIF_BPF_COEFF1617, 0xfc99fbb6}, -{9000000, DIF_BPF_COEFF1819, 0x005b05f7}, -{9000000, DIF_BPF_COEFF2021, 0x0545fd81}, -{9000000, DIF_BPF_COEFF2223, 0xf723fabf}, -{9000000, DIF_BPF_COEFF2425, 0x05b80b70}, -{9000000, DIF_BPF_COEFF2627, 0x03d2f669}, -{9000000, DIF_BPF_COEFF2829, 0xf313ff15}, -{9000000, DIF_BPF_COEFF3031, 0x0d550cbf}, -{9000000, DIF_BPF_COEFF3233, 0xfcf6eff2}, -{9000000, DIF_BPF_COEFF3435, 0xf544073d}, -{9000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 90_quant.dat*/ - - -/*case 9100000:*/ -/* BEGIN - DIF BPF register values from 91_quant.dat*/ -{9100000, DIF_BPF_COEFF01, 0xfffffffe}, -{9100000, DIF_BPF_COEFF23, 0x00030012}, -{9100000, DIF_BPF_COEFF45, 0x000fffdd}, -{9100000, DIF_BPF_COEFF67, 0xffacffea}, -{9100000, DIF_BPF_COEFF89, 0x009300cf}, -{9100000, DIF_BPF_COEFF1011, 0xffdcfe7c}, -{9100000, DIF_BPF_COEFF1213, 0xfea600f7}, -{9100000, DIF_BPF_COEFF1415, 0x02fd0190}, -{9100000, DIF_BPF_COEFF1617, 0xfd51fb46}, -{9100000, DIF_BPF_COEFF1819, 0xff150554}, -{9100000, DIF_BPF_COEFF2021, 0x0627fefd}, -{9100000, DIF_BPF_COEFF2223, 0xf778f978}, -{9100000, DIF_BPF_COEFF2425, 0x044d0b87}, -{9100000, DIF_BPF_COEFF2627, 0x0543f77d}, -{9100000, DIF_BPF_COEFF2829, 0xf2a0fdcf}, -{9100000, DIF_BPF_COEFF3031, 0x0cbe0d4e}, -{9100000, DIF_BPF_COEFF3233, 0xfdc4f01d}, -{9100000, DIF_BPF_COEFF3435, 0xf4f2070b}, -{9100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 91_quant.dat*/ - - -/*case 9200000:*/ -/* BEGIN - DIF BPF register values from 92_quant.dat*/ -{9200000, DIF_BPF_COEFF01, 0x0000fffd}, -{9200000, DIF_BPF_COEFF23, 0x00000010}, -{9200000, DIF_BPF_COEFF45, 0x001afff0}, -{9200000, DIF_BPF_COEFF67, 0xffaaffbf}, -{9200000, DIF_BPF_COEFF89, 0x006700ed}, -{9200000, DIF_BPF_COEFF1011, 0x0043feb6}, -{9200000, DIF_BPF_COEFF1213, 0xfe460047}, -{9200000, DIF_BPF_COEFF1415, 0x02db0258}, -{9200000, DIF_BPF_COEFF1617, 0xfe35fb1b}, -{9200000, DIF_BPF_COEFF1819, 0xfddc0473}, -{9200000, DIF_BPF_COEFF2021, 0x06c90082}, -{9200000, DIF_BPF_COEFF2223, 0xf811f85e}, -{9200000, DIF_BPF_COEFF2425, 0x02c90b66}, -{9200000, DIF_BPF_COEFF2627, 0x069ff8ad}, -{9200000, DIF_BPF_COEFF2829, 0xf250fc8d}, -{9200000, DIF_BPF_COEFF3031, 0x0c140dcf}, -{9200000, DIF_BPF_COEFF3233, 0xfe93f04d}, -{9200000, DIF_BPF_COEFF3435, 0xf4a106d9}, -{9200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 92_quant.dat*/ - - -/*case 9300000:*/ -/* BEGIN - DIF BPF register values from 93_quant.dat*/ -{9300000, DIF_BPF_COEFF01, 0x0000fffd}, -{9300000, DIF_BPF_COEFF23, 0xfffc000c}, -{9300000, DIF_BPF_COEFF45, 0x00200006}, -{9300000, DIF_BPF_COEFF67, 0xffb4ff9c}, -{9300000, DIF_BPF_COEFF89, 0x002f00ef}, -{9300000, DIF_BPF_COEFF1011, 0x00a4ff10}, -{9300000, DIF_BPF_COEFF1213, 0xfe0dff92}, -{9300000, DIF_BPF_COEFF1415, 0x028102f7}, -{9300000, DIF_BPF_COEFF1617, 0xff36fb37}, -{9300000, DIF_BPF_COEFF1819, 0xfcbf035e}, -{9300000, DIF_BPF_COEFF2021, 0x07260202}, -{9300000, DIF_BPF_COEFF2223, 0xf8e8f778}, -{9300000, DIF_BPF_COEFF2425, 0x01340b0d}, -{9300000, DIF_BPF_COEFF2627, 0x07e1f9f4}, -{9300000, DIF_BPF_COEFF2829, 0xf223fb51}, -{9300000, DIF_BPF_COEFF3031, 0x0b590e42}, -{9300000, DIF_BPF_COEFF3233, 0xff64f083}, -{9300000, DIF_BPF_COEFF3435, 0xf45206a7}, -{9300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 93_quant.dat*/ - - -/*case 9400000:*/ -/* BEGIN - DIF BPF register values from 94_quant.dat*/ -{9400000, DIF_BPF_COEFF01, 0x0000fffd}, -{9400000, DIF_BPF_COEFF23, 0xfff90005}, -{9400000, DIF_BPF_COEFF45, 0x0022001a}, -{9400000, DIF_BPF_COEFF67, 0xffc9ff86}, -{9400000, DIF_BPF_COEFF89, 0xfff000d7}, -{9400000, DIF_BPF_COEFF1011, 0x00f2ff82}, -{9400000, DIF_BPF_COEFF1213, 0xfe01fee5}, -{9400000, DIF_BPF_COEFF1415, 0x01f60362}, -{9400000, DIF_BPF_COEFF1617, 0x0044fb99}, -{9400000, DIF_BPF_COEFF1819, 0xfbcc0222}, -{9400000, DIF_BPF_COEFF2021, 0x07380370}, -{9400000, DIF_BPF_COEFF2223, 0xf9f7f6cc}, -{9400000, DIF_BPF_COEFF2425, 0xff990a7e}, -{9400000, DIF_BPF_COEFF2627, 0x0902fb50}, -{9400000, DIF_BPF_COEFF2829, 0xf21afa1f}, -{9400000, DIF_BPF_COEFF3031, 0x0a8d0ea6}, -{9400000, DIF_BPF_COEFF3233, 0x0034f0bf}, -{9400000, DIF_BPF_COEFF3435, 0xf4050675}, -{9400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 94_quant.dat*/ - - -/*case 9500000:*/ -/* BEGIN - DIF BPF register values from 95_quant.dat*/ -{9500000, DIF_BPF_COEFF01, 0x0000fffe}, -{9500000, DIF_BPF_COEFF23, 0xfff8fffe}, -{9500000, DIF_BPF_COEFF45, 0x001e002b}, -{9500000, DIF_BPF_COEFF67, 0xffe5ff81}, -{9500000, DIF_BPF_COEFF89, 0xffb400a5}, -{9500000, DIF_BPF_COEFF1011, 0x01280000}, -{9500000, DIF_BPF_COEFF1213, 0xfe24fe50}, -{9500000, DIF_BPF_COEFF1415, 0x01460390}, -{9500000, DIF_BPF_COEFF1617, 0x014dfc3a}, -{9500000, DIF_BPF_COEFF1819, 0xfb1000ce}, -{9500000, DIF_BPF_COEFF2021, 0x070104bf}, -{9500000, DIF_BPF_COEFF2223, 0xfb37f65f}, -{9500000, DIF_BPF_COEFF2425, 0xfe0009bc}, -{9500000, DIF_BPF_COEFF2627, 0x0a00fcbb}, -{9500000, DIF_BPF_COEFF2829, 0xf235f8f8}, -{9500000, DIF_BPF_COEFF3031, 0x09b20efc}, -{9500000, DIF_BPF_COEFF3233, 0x0105f101}, -{9500000, DIF_BPF_COEFF3435, 0xf3ba0642}, -{9500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 95_quant.dat*/ - - -/*case 9600000:*/ -/* BEGIN - DIF BPF register values from 96_quant.dat*/ -{9600000, DIF_BPF_COEFF01, 0x0001ffff}, -{9600000, DIF_BPF_COEFF23, 0xfff8fff7}, -{9600000, DIF_BPF_COEFF45, 0x00150036}, -{9600000, DIF_BPF_COEFF67, 0x0005ff8c}, -{9600000, DIF_BPF_COEFF89, 0xff810061}, -{9600000, DIF_BPF_COEFF1011, 0x013d007e}, -{9600000, DIF_BPF_COEFF1213, 0xfe71fddf}, -{9600000, DIF_BPF_COEFF1415, 0x007c0380}, -{9600000, DIF_BPF_COEFF1617, 0x0241fd13}, -{9600000, DIF_BPF_COEFF1819, 0xfa94ff70}, -{9600000, DIF_BPF_COEFF2021, 0x068005e2}, -{9600000, DIF_BPF_COEFF2223, 0xfc9bf633}, -{9600000, DIF_BPF_COEFF2425, 0xfc7308ca}, -{9600000, DIF_BPF_COEFF2627, 0x0ad5fe30}, -{9600000, DIF_BPF_COEFF2829, 0xf274f7e0}, -{9600000, DIF_BPF_COEFF3031, 0x08c90f43}, -{9600000, DIF_BPF_COEFF3233, 0x01d4f147}, -{9600000, DIF_BPF_COEFF3435, 0xf371060f}, -{9600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 96_quant.dat*/ - - -/*case 9700000:*/ -/* BEGIN - DIF BPF register values from 97_quant.dat*/ -{9700000, DIF_BPF_COEFF01, 0x00010001}, -{9700000, DIF_BPF_COEFF23, 0xfff9fff1}, -{9700000, DIF_BPF_COEFF45, 0x00090038}, -{9700000, DIF_BPF_COEFF67, 0x0025ffa7}, -{9700000, DIF_BPF_COEFF89, 0xff5e0012}, -{9700000, DIF_BPF_COEFF1011, 0x013200f0}, -{9700000, DIF_BPF_COEFF1213, 0xfee3fd9b}, -{9700000, DIF_BPF_COEFF1415, 0xffaa0331}, -{9700000, DIF_BPF_COEFF1617, 0x0311fe15}, -{9700000, DIF_BPF_COEFF1819, 0xfa60fe18}, -{9700000, DIF_BPF_COEFF2021, 0x05bd06d1}, -{9700000, DIF_BPF_COEFF2223, 0xfe1bf64a}, -{9700000, DIF_BPF_COEFF2425, 0xfafa07ae}, -{9700000, DIF_BPF_COEFF2627, 0x0b7effab}, -{9700000, DIF_BPF_COEFF2829, 0xf2d5f6d7}, -{9700000, DIF_BPF_COEFF3031, 0x07d30f7a}, -{9700000, DIF_BPF_COEFF3233, 0x02a3f194}, -{9700000, DIF_BPF_COEFF3435, 0xf32905dc}, -{9700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 97_quant.dat*/ - - -/*case 9800000:*/ -/* BEGIN - DIF BPF register values from 98_quant.dat*/ -{9800000, DIF_BPF_COEFF01, 0x00010002}, -{9800000, DIF_BPF_COEFF23, 0xfffcffee}, -{9800000, DIF_BPF_COEFF45, 0xfffb0032}, -{9800000, DIF_BPF_COEFF67, 0x003fffcd}, -{9800000, DIF_BPF_COEFF89, 0xff4effc1}, -{9800000, DIF_BPF_COEFF1011, 0x0106014a}, -{9800000, DIF_BPF_COEFF1213, 0xff6efd8a}, -{9800000, DIF_BPF_COEFF1415, 0xfedd02aa}, -{9800000, DIF_BPF_COEFF1617, 0x03b0ff34}, -{9800000, DIF_BPF_COEFF1819, 0xfa74fcd7}, -{9800000, DIF_BPF_COEFF2021, 0x04bf0781}, -{9800000, DIF_BPF_COEFF2223, 0xffaaf6a3}, -{9800000, DIF_BPF_COEFF2425, 0xf99e066b}, -{9800000, DIF_BPF_COEFF2627, 0x0bf90128}, -{9800000, DIF_BPF_COEFF2829, 0xf359f5e1}, -{9800000, DIF_BPF_COEFF3031, 0x06d20fa2}, -{9800000, DIF_BPF_COEFF3233, 0x0370f1e5}, -{9800000, DIF_BPF_COEFF3435, 0xf2e405a8}, -{9800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 98_quant.dat*/ - - -/*case 9900000:*/ -/* BEGIN - DIF BPF register values from 99_quant.dat*/ -{9900000, DIF_BPF_COEFF01, 0x00000003}, -{9900000, DIF_BPF_COEFF23, 0xffffffee}, -{9900000, DIF_BPF_COEFF45, 0xffef0024}, -{9900000, DIF_BPF_COEFF67, 0x0051fffa}, -{9900000, DIF_BPF_COEFF89, 0xff54ff77}, -{9900000, DIF_BPF_COEFF1011, 0x00be0184}, -{9900000, DIF_BPF_COEFF1213, 0x0006fdad}, -{9900000, DIF_BPF_COEFF1415, 0xfe2701f3}, -{9900000, DIF_BPF_COEFF1617, 0x0413005e}, -{9900000, DIF_BPF_COEFF1819, 0xfad1fbba}, -{9900000, DIF_BPF_COEFF2021, 0x039007ee}, -{9900000, DIF_BPF_COEFF2223, 0x013bf73d}, -{9900000, DIF_BPF_COEFF2425, 0xf868050a}, -{9900000, DIF_BPF_COEFF2627, 0x0c4302a1}, -{9900000, DIF_BPF_COEFF2829, 0xf3fdf4fe}, -{9900000, DIF_BPF_COEFF3031, 0x05c70fba}, -{9900000, DIF_BPF_COEFF3233, 0x043bf23c}, -{9900000, DIF_BPF_COEFF3435, 0xf2a10575}, -{9900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 99_quant.dat*/ - - -/*case 10000000:*/ -/* BEGIN - DIF BPF register values from 100_quant.dat*/ -{10000000, DIF_BPF_COEFF01, 0x00000003}, -{10000000, DIF_BPF_COEFF23, 0x0003fff1}, -{10000000, DIF_BPF_COEFF45, 0xffe50011}, -{10000000, DIF_BPF_COEFF67, 0x00570027}, -{10000000, DIF_BPF_COEFF89, 0xff70ff3c}, -{10000000, DIF_BPF_COEFF1011, 0x00620198}, -{10000000, DIF_BPF_COEFF1213, 0x009efe01}, -{10000000, DIF_BPF_COEFF1415, 0xfd95011a}, -{10000000, DIF_BPF_COEFF1617, 0x04350183}, -{10000000, DIF_BPF_COEFF1819, 0xfb71fad0}, -{10000000, DIF_BPF_COEFF2021, 0x023c0812}, -{10000000, DIF_BPF_COEFF2223, 0x02c3f811}, -{10000000, DIF_BPF_COEFF2425, 0xf75e0390}, -{10000000, DIF_BPF_COEFF2627, 0x0c5c0411}, -{10000000, DIF_BPF_COEFF2829, 0xf4c1f432}, -{10000000, DIF_BPF_COEFF3031, 0x04b30fc1}, -{10000000, DIF_BPF_COEFF3233, 0x0503f297}, -{10000000, DIF_BPF_COEFF3435, 0xf2610541}, -{10000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 100_quant.dat*/ - - -/*case 10100000:*/ -/* BEGIN - DIF BPF register values from 101_quant.dat*/ -{10100000, DIF_BPF_COEFF01, 0x00000003}, -{10100000, DIF_BPF_COEFF23, 0x0006fff7}, -{10100000, DIF_BPF_COEFF45, 0xffdffffc}, -{10100000, DIF_BPF_COEFF67, 0x00510050}, -{10100000, DIF_BPF_COEFF89, 0xff9dff18}, -{10100000, DIF_BPF_COEFF1011, 0xfffc0184}, -{10100000, DIF_BPF_COEFF1213, 0x0128fe80}, -{10100000, DIF_BPF_COEFF1415, 0xfd32002e}, -{10100000, DIF_BPF_COEFF1617, 0x04130292}, -{10100000, DIF_BPF_COEFF1819, 0xfc4dfa21}, -{10100000, DIF_BPF_COEFF2021, 0x00d107ee}, -{10100000, DIF_BPF_COEFF2223, 0x0435f91c}, -{10100000, DIF_BPF_COEFF2425, 0xf6850205}, -{10100000, DIF_BPF_COEFF2627, 0x0c430573}, -{10100000, DIF_BPF_COEFF2829, 0xf5a1f37d}, -{10100000, DIF_BPF_COEFF3031, 0x03990fba}, -{10100000, DIF_BPF_COEFF3233, 0x05c7f2f8}, -{10100000, DIF_BPF_COEFF3435, 0xf222050d}, -{10100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 101_quant.dat*/ - - -/*case 10200000:*/ -/* BEGIN - DIF BPF register values from 102_quant.dat*/ -{10200000, DIF_BPF_COEFF01, 0x00000002}, -{10200000, DIF_BPF_COEFF23, 0x0008fffe}, -{10200000, DIF_BPF_COEFF45, 0xffdfffe7}, -{10200000, DIF_BPF_COEFF67, 0x003f006e}, -{10200000, DIF_BPF_COEFF89, 0xffd6ff0f}, -{10200000, DIF_BPF_COEFF1011, 0xff96014a}, -{10200000, DIF_BPF_COEFF1213, 0x0197ff1f}, -{10200000, DIF_BPF_COEFF1415, 0xfd05ff3e}, -{10200000, DIF_BPF_COEFF1617, 0x03b0037c}, -{10200000, DIF_BPF_COEFF1819, 0xfd59f9b7}, -{10200000, DIF_BPF_COEFF2021, 0xff5d0781}, -{10200000, DIF_BPF_COEFF2223, 0x0585fa56}, -{10200000, DIF_BPF_COEFF2425, 0xf5e4006f}, -{10200000, DIF_BPF_COEFF2627, 0x0bf906c4}, -{10200000, DIF_BPF_COEFF2829, 0xf69df2e0}, -{10200000, DIF_BPF_COEFF3031, 0x02790fa2}, -{10200000, DIF_BPF_COEFF3233, 0x0688f35d}, -{10200000, DIF_BPF_COEFF3435, 0xf1e604d8}, -{10200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 102_quant.dat*/ - - -/*case 10300000:*/ -/* BEGIN - DIF BPF register values from 103_quant.dat*/ -{10300000, DIF_BPF_COEFF01, 0xffff0001}, -{10300000, DIF_BPF_COEFF23, 0x00090005}, -{10300000, DIF_BPF_COEFF45, 0xffe4ffd6}, -{10300000, DIF_BPF_COEFF67, 0x0025007e}, -{10300000, DIF_BPF_COEFF89, 0x0014ff20}, -{10300000, DIF_BPF_COEFF1011, 0xff3c00f0}, -{10300000, DIF_BPF_COEFF1213, 0x01e1ffd0}, -{10300000, DIF_BPF_COEFF1415, 0xfd12fe5c}, -{10300000, DIF_BPF_COEFF1617, 0x03110433}, -{10300000, DIF_BPF_COEFF1819, 0xfe88f996}, -{10300000, DIF_BPF_COEFF2021, 0xfdf106d1}, -{10300000, DIF_BPF_COEFF2223, 0x06aafbb7}, -{10300000, DIF_BPF_COEFF2425, 0xf57efed8}, -{10300000, DIF_BPF_COEFF2627, 0x0b7e07ff}, -{10300000, DIF_BPF_COEFF2829, 0xf7b0f25e}, -{10300000, DIF_BPF_COEFF3031, 0x01560f7a}, -{10300000, DIF_BPF_COEFF3233, 0x0745f3c7}, -{10300000, DIF_BPF_COEFF3435, 0xf1ac04a4}, -{10300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 103_quant.dat*/ - - -/*case 10400000:*/ -/* BEGIN - DIF BPF register values from 104_quant.dat*/ -{10400000, DIF_BPF_COEFF01, 0xffffffff}, -{10400000, DIF_BPF_COEFF23, 0x0008000c}, -{10400000, DIF_BPF_COEFF45, 0xffedffcb}, -{10400000, DIF_BPF_COEFF67, 0x0005007d}, -{10400000, DIF_BPF_COEFF89, 0x0050ff4c}, -{10400000, DIF_BPF_COEFF1011, 0xfef6007e}, -{10400000, DIF_BPF_COEFF1213, 0x01ff0086}, -{10400000, DIF_BPF_COEFF1415, 0xfd58fd97}, -{10400000, DIF_BPF_COEFF1617, 0x024104ad}, -{10400000, DIF_BPF_COEFF1819, 0xffcaf9c0}, -{10400000, DIF_BPF_COEFF2021, 0xfc9905e2}, -{10400000, DIF_BPF_COEFF2223, 0x079afd35}, -{10400000, DIF_BPF_COEFF2425, 0xf555fd46}, -{10400000, DIF_BPF_COEFF2627, 0x0ad50920}, -{10400000, DIF_BPF_COEFF2829, 0xf8d9f1f6}, -{10400000, DIF_BPF_COEFF3031, 0x00310f43}, -{10400000, DIF_BPF_COEFF3233, 0x07fdf435}, -{10400000, DIF_BPF_COEFF3435, 0xf174046f}, -{10400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 104_quant.dat*/ - - -/*case 10500000:*/ -/* BEGIN - DIF BPF register values from 105_quant.dat*/ -{10500000, DIF_BPF_COEFF01, 0xfffffffe}, -{10500000, DIF_BPF_COEFF23, 0x00050011}, -{10500000, DIF_BPF_COEFF45, 0xfffaffc8}, -{10500000, DIF_BPF_COEFF67, 0xffe5006b}, -{10500000, DIF_BPF_COEFF89, 0x0082ff8c}, -{10500000, DIF_BPF_COEFF1011, 0xfecc0000}, -{10500000, DIF_BPF_COEFF1213, 0x01f00130}, -{10500000, DIF_BPF_COEFF1415, 0xfdd2fcfc}, -{10500000, DIF_BPF_COEFF1617, 0x014d04e3}, -{10500000, DIF_BPF_COEFF1819, 0x010efa32}, -{10500000, DIF_BPF_COEFF2021, 0xfb6404bf}, -{10500000, DIF_BPF_COEFF2223, 0x084efec5}, -{10500000, DIF_BPF_COEFF2425, 0xf569fbc2}, -{10500000, DIF_BPF_COEFF2627, 0x0a000a23}, -{10500000, DIF_BPF_COEFF2829, 0xfa15f1ab}, -{10500000, DIF_BPF_COEFF3031, 0xff0b0efc}, -{10500000, DIF_BPF_COEFF3233, 0x08b0f4a7}, -{10500000, DIF_BPF_COEFF3435, 0xf13f043a}, -{10500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 105_quant.dat*/ - - -/*case 10600000:*/ -/* BEGIN - DIF BPF register values from 106_quant.dat*/ -{10600000, DIF_BPF_COEFF01, 0x0000fffd}, -{10600000, DIF_BPF_COEFF23, 0x00020012}, -{10600000, DIF_BPF_COEFF45, 0x0007ffcd}, -{10600000, DIF_BPF_COEFF67, 0xffc9004c}, -{10600000, DIF_BPF_COEFF89, 0x00a4ffd9}, -{10600000, DIF_BPF_COEFF1011, 0xfec3ff82}, -{10600000, DIF_BPF_COEFF1213, 0x01b401c1}, -{10600000, DIF_BPF_COEFF1415, 0xfe76fc97}, -{10600000, DIF_BPF_COEFF1617, 0x004404d2}, -{10600000, DIF_BPF_COEFF1819, 0x0245fae8}, -{10600000, DIF_BPF_COEFF2021, 0xfa5f0370}, -{10600000, DIF_BPF_COEFF2223, 0x08c1005f}, -{10600000, DIF_BPF_COEFF2425, 0xf5bcfa52}, -{10600000, DIF_BPF_COEFF2627, 0x09020b04}, -{10600000, DIF_BPF_COEFF2829, 0xfb60f17b}, -{10600000, DIF_BPF_COEFF3031, 0xfde70ea6}, -{10600000, DIF_BPF_COEFF3233, 0x095df51e}, -{10600000, DIF_BPF_COEFF3435, 0xf10c0405}, -{10600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 106_quant.dat*/ - - -/*case 10700000:*/ -/* BEGIN - DIF BPF register values from 107_quant.dat*/ -{10700000, DIF_BPF_COEFF01, 0x0000fffd}, -{10700000, DIF_BPF_COEFF23, 0xffff0011}, -{10700000, DIF_BPF_COEFF45, 0x0014ffdb}, -{10700000, DIF_BPF_COEFF67, 0xffb40023}, -{10700000, DIF_BPF_COEFF89, 0x00b2002a}, -{10700000, DIF_BPF_COEFF1011, 0xfedbff10}, -{10700000, DIF_BPF_COEFF1213, 0x0150022d}, -{10700000, DIF_BPF_COEFF1415, 0xff38fc6f}, -{10700000, DIF_BPF_COEFF1617, 0xff36047b}, -{10700000, DIF_BPF_COEFF1819, 0x035efbda}, -{10700000, DIF_BPF_COEFF2021, 0xf9940202}, -{10700000, DIF_BPF_COEFF2223, 0x08ee01f5}, -{10700000, DIF_BPF_COEFF2425, 0xf649f8fe}, -{10700000, DIF_BPF_COEFF2627, 0x07e10bc2}, -{10700000, DIF_BPF_COEFF2829, 0xfcb6f169}, -{10700000, DIF_BPF_COEFF3031, 0xfcc60e42}, -{10700000, DIF_BPF_COEFF3233, 0x0a04f599}, -{10700000, DIF_BPF_COEFF3435, 0xf0db03d0}, -{10700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 107_quant.dat*/ - - -/*case 10800000:*/ -/* BEGIN - DIF BPF register values from 108_quant.dat*/ -{10800000, DIF_BPF_COEFF01, 0x0000fffd}, -{10800000, DIF_BPF_COEFF23, 0xfffb000d}, -{10800000, DIF_BPF_COEFF45, 0x001dffed}, -{10800000, DIF_BPF_COEFF67, 0xffaafff5}, -{10800000, DIF_BPF_COEFF89, 0x00aa0077}, -{10800000, DIF_BPF_COEFF1011, 0xff13feb6}, -{10800000, DIF_BPF_COEFF1213, 0x00ce026b}, -{10800000, DIF_BPF_COEFF1415, 0x000afc85}, -{10800000, DIF_BPF_COEFF1617, 0xfe3503e3}, -{10800000, DIF_BPF_COEFF1819, 0x044cfcfb}, -{10800000, DIF_BPF_COEFF2021, 0xf90c0082}, -{10800000, DIF_BPF_COEFF2223, 0x08d5037f}, -{10800000, DIF_BPF_COEFF2425, 0xf710f7cc}, -{10800000, DIF_BPF_COEFF2627, 0x069f0c59}, -{10800000, DIF_BPF_COEFF2829, 0xfe16f173}, -{10800000, DIF_BPF_COEFF3031, 0xfbaa0dcf}, -{10800000, DIF_BPF_COEFF3233, 0x0aa5f617}, -{10800000, DIF_BPF_COEFF3435, 0xf0ad039b}, -{10800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 108_quant.dat*/ - - -/*case 10900000:*/ -/* BEGIN - DIF BPF register values from 109_quant.dat*/ -{10900000, DIF_BPF_COEFF01, 0x0000fffe}, -{10900000, DIF_BPF_COEFF23, 0xfff90006}, -{10900000, DIF_BPF_COEFF45, 0x00210003}, -{10900000, DIF_BPF_COEFF67, 0xffacffc8}, -{10900000, DIF_BPF_COEFF89, 0x008e00b6}, -{10900000, DIF_BPF_COEFF1011, 0xff63fe7c}, -{10900000, DIF_BPF_COEFF1213, 0x003a0275}, -{10900000, DIF_BPF_COEFF1415, 0x00dafcda}, -{10900000, DIF_BPF_COEFF1617, 0xfd510313}, -{10900000, DIF_BPF_COEFF1819, 0x0501fe40}, -{10900000, DIF_BPF_COEFF2021, 0xf8cbfefd}, -{10900000, DIF_BPF_COEFF2223, 0x087604f0}, -{10900000, DIF_BPF_COEFF2425, 0xf80af6c2}, -{10900000, DIF_BPF_COEFF2627, 0x05430cc8}, -{10900000, DIF_BPF_COEFF2829, 0xff7af19a}, -{10900000, DIF_BPF_COEFF3031, 0xfa940d4e}, -{10900000, DIF_BPF_COEFF3233, 0x0b3ff699}, -{10900000, DIF_BPF_COEFF3435, 0xf0810365}, -{10900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 109_quant.dat*/ - - -/*case 11000000:*/ -/* BEGIN - DIF BPF register values from 110_quant.dat*/ -{11000000, DIF_BPF_COEFF01, 0x0001ffff}, -{11000000, DIF_BPF_COEFF23, 0xfff8ffff}, -{11000000, DIF_BPF_COEFF45, 0x00210018}, -{11000000, DIF_BPF_COEFF67, 0xffbaffa3}, -{11000000, DIF_BPF_COEFF89, 0x006000e1}, -{11000000, DIF_BPF_COEFF1011, 0xffc4fe68}, -{11000000, DIF_BPF_COEFF1213, 0xffa0024b}, -{11000000, DIF_BPF_COEFF1415, 0x019afd66}, -{11000000, DIF_BPF_COEFF1617, 0xfc990216}, -{11000000, DIF_BPF_COEFF1819, 0x0575ff99}, -{11000000, DIF_BPF_COEFF2021, 0xf8d4fd81}, -{11000000, DIF_BPF_COEFF2223, 0x07d40640}, -{11000000, DIF_BPF_COEFF2425, 0xf932f5e6}, -{11000000, DIF_BPF_COEFF2627, 0x03d20d0d}, -{11000000, DIF_BPF_COEFF2829, 0x00dff1de}, -{11000000, DIF_BPF_COEFF3031, 0xf9860cbf}, -{11000000, DIF_BPF_COEFF3233, 0x0bd1f71e}, -{11000000, DIF_BPF_COEFF3435, 0xf058032f}, -{11000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 110_quant.dat*/ - - -/*case 11100000:*/ -/* BEGIN - DIF BPF register values from 111_quant.dat*/ -{11100000, DIF_BPF_COEFF01, 0x00010000}, -{11100000, DIF_BPF_COEFF23, 0xfff8fff8}, -{11100000, DIF_BPF_COEFF45, 0x001b0029}, -{11100000, DIF_BPF_COEFF67, 0xffd1ff8a}, -{11100000, DIF_BPF_COEFF89, 0x002600f2}, -{11100000, DIF_BPF_COEFF1011, 0x002cfe7c}, -{11100000, DIF_BPF_COEFF1213, 0xff0f01f0}, -{11100000, DIF_BPF_COEFF1415, 0x023bfe20}, -{11100000, DIF_BPF_COEFF1617, 0xfc1700fa}, -{11100000, DIF_BPF_COEFF1819, 0x05a200f7}, -{11100000, DIF_BPF_COEFF2021, 0xf927fc1c}, -{11100000, DIF_BPF_COEFF2223, 0x06f40765}, -{11100000, DIF_BPF_COEFF2425, 0xfa82f53b}, -{11100000, DIF_BPF_COEFF2627, 0x02510d27}, -{11100000, DIF_BPF_COEFF2829, 0x0243f23d}, -{11100000, DIF_BPF_COEFF3031, 0xf8810c24}, -{11100000, DIF_BPF_COEFF3233, 0x0c5cf7a7}, -{11100000, DIF_BPF_COEFF3435, 0xf03102fa}, -{11100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 111_quant.dat*/ - - -/*case 11200000:*/ -/* BEGIN - DIF BPF register values from 112_quant.dat*/ -{11200000, DIF_BPF_COEFF01, 0x00010002}, -{11200000, DIF_BPF_COEFF23, 0xfffafff2}, -{11200000, DIF_BPF_COEFF45, 0x00110035}, -{11200000, DIF_BPF_COEFF67, 0xfff0ff81}, -{11200000, DIF_BPF_COEFF89, 0xffe700e7}, -{11200000, DIF_BPF_COEFF1011, 0x008ffeb6}, -{11200000, DIF_BPF_COEFF1213, 0xfe94016d}, -{11200000, DIF_BPF_COEFF1415, 0x02b0fefb}, -{11200000, DIF_BPF_COEFF1617, 0xfbd3ffd1}, -{11200000, DIF_BPF_COEFF1819, 0x05850249}, -{11200000, DIF_BPF_COEFF2021, 0xf9c1fadb}, -{11200000, DIF_BPF_COEFF2223, 0x05de0858}, -{11200000, DIF_BPF_COEFF2425, 0xfbf2f4c4}, -{11200000, DIF_BPF_COEFF2627, 0x00c70d17}, -{11200000, DIF_BPF_COEFF2829, 0x03a0f2b8}, -{11200000, DIF_BPF_COEFF3031, 0xf7870b7c}, -{11200000, DIF_BPF_COEFF3233, 0x0cdff833}, -{11200000, DIF_BPF_COEFF3435, 0xf00d02c4}, -{11200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 112_quant.dat*/ - - -/*case 11300000:*/ -/* BEGIN - DIF BPF register values from 113_quant.dat*/ -{11300000, DIF_BPF_COEFF01, 0x00000003}, -{11300000, DIF_BPF_COEFF23, 0xfffdffee}, -{11300000, DIF_BPF_COEFF45, 0x00040038}, -{11300000, DIF_BPF_COEFF67, 0x0010ff88}, -{11300000, DIF_BPF_COEFF89, 0xffac00c2}, -{11300000, DIF_BPF_COEFF1011, 0x00e2ff10}, -{11300000, DIF_BPF_COEFF1213, 0xfe3900cb}, -{11300000, DIF_BPF_COEFF1415, 0x02f1ffe9}, -{11300000, DIF_BPF_COEFF1617, 0xfbd3feaa}, -{11300000, DIF_BPF_COEFF1819, 0x05210381}, -{11300000, DIF_BPF_COEFF2021, 0xfa9cf9c8}, -{11300000, DIF_BPF_COEFF2223, 0x04990912}, -{11300000, DIF_BPF_COEFF2425, 0xfd7af484}, -{11300000, DIF_BPF_COEFF2627, 0xff390cdb}, -{11300000, DIF_BPF_COEFF2829, 0x04f4f34d}, -{11300000, DIF_BPF_COEFF3031, 0xf69a0ac9}, -{11300000, DIF_BPF_COEFF3233, 0x0d5af8c1}, -{11300000, DIF_BPF_COEFF3435, 0xefec028e}, -{11300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 113_quant.dat*/ - - -/*case 11400000:*/ -/* BEGIN - DIF BPF register values from 114_quant.dat*/ -{11400000, DIF_BPF_COEFF01, 0x00000003}, -{11400000, DIF_BPF_COEFF23, 0x0000ffee}, -{11400000, DIF_BPF_COEFF45, 0xfff60033}, -{11400000, DIF_BPF_COEFF67, 0x002fff9f}, -{11400000, DIF_BPF_COEFF89, 0xff7b0087}, -{11400000, DIF_BPF_COEFF1011, 0x011eff82}, -{11400000, DIF_BPF_COEFF1213, 0xfe080018}, -{11400000, DIF_BPF_COEFF1415, 0x02f900d8}, -{11400000, DIF_BPF_COEFF1617, 0xfc17fd96}, -{11400000, DIF_BPF_COEFF1819, 0x04790490}, -{11400000, DIF_BPF_COEFF2021, 0xfbadf8ed}, -{11400000, DIF_BPF_COEFF2223, 0x032f098e}, -{11400000, DIF_BPF_COEFF2425, 0xff10f47d}, -{11400000, DIF_BPF_COEFF2627, 0xfdaf0c75}, -{11400000, DIF_BPF_COEFF2829, 0x063cf3fc}, -{11400000, DIF_BPF_COEFF3031, 0xf5ba0a0b}, -{11400000, DIF_BPF_COEFF3233, 0x0dccf952}, -{11400000, DIF_BPF_COEFF3435, 0xefcd0258}, -{11400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 114_quant.dat*/ - - -/*case 11500000:*/ -/* BEGIN - DIF BPF register values from 115_quant.dat*/ -{11500000, DIF_BPF_COEFF01, 0x00000003}, -{11500000, DIF_BPF_COEFF23, 0x0004fff1}, -{11500000, DIF_BPF_COEFF45, 0xffea0026}, -{11500000, DIF_BPF_COEFF67, 0x0046ffc3}, -{11500000, DIF_BPF_COEFF89, 0xff5a003c}, -{11500000, DIF_BPF_COEFF1011, 0x013b0000}, -{11500000, DIF_BPF_COEFF1213, 0xfe04ff63}, -{11500000, DIF_BPF_COEFF1415, 0x02c801b8}, -{11500000, DIF_BPF_COEFF1617, 0xfc99fca6}, -{11500000, DIF_BPF_COEFF1819, 0x0397056a}, -{11500000, DIF_BPF_COEFF2021, 0xfcecf853}, -{11500000, DIF_BPF_COEFF2223, 0x01ad09c9}, -{11500000, DIF_BPF_COEFF2425, 0x00acf4ad}, -{11500000, DIF_BPF_COEFF2627, 0xfc2e0be7}, -{11500000, DIF_BPF_COEFF2829, 0x0773f4c2}, -{11500000, DIF_BPF_COEFF3031, 0xf4e90943}, -{11500000, DIF_BPF_COEFF3233, 0x0e35f9e6}, -{11500000, DIF_BPF_COEFF3435, 0xefb10221}, -{11500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 115_quant.dat*/ - - -/*case 11600000:*/ -/* BEGIN - DIF BPF register values from 116_quant.dat*/ -{11600000, DIF_BPF_COEFF01, 0x00000002}, -{11600000, DIF_BPF_COEFF23, 0x0007fff6}, -{11600000, DIF_BPF_COEFF45, 0xffe20014}, -{11600000, DIF_BPF_COEFF67, 0x0054ffee}, -{11600000, DIF_BPF_COEFF89, 0xff4effeb}, -{11600000, DIF_BPF_COEFF1011, 0x0137007e}, -{11600000, DIF_BPF_COEFF1213, 0xfe2efebb}, -{11600000, DIF_BPF_COEFF1415, 0x0260027a}, -{11600000, DIF_BPF_COEFF1617, 0xfd51fbe6}, -{11600000, DIF_BPF_COEFF1819, 0x02870605}, -{11600000, DIF_BPF_COEFF2021, 0xfe4af7fe}, -{11600000, DIF_BPF_COEFF2223, 0x001d09c1}, -{11600000, DIF_BPF_COEFF2425, 0x0243f515}, -{11600000, DIF_BPF_COEFF2627, 0xfabd0b32}, -{11600000, DIF_BPF_COEFF2829, 0x0897f59e}, -{11600000, DIF_BPF_COEFF3031, 0xf4280871}, -{11600000, DIF_BPF_COEFF3233, 0x0e95fa7c}, -{11600000, DIF_BPF_COEFF3435, 0xef9701eb}, -{11600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 116_quant.dat*/ - - -/*case 11700000:*/ -/* BEGIN - DIF BPF register values from 117_quant.dat*/ -{11700000, DIF_BPF_COEFF01, 0xffff0001}, -{11700000, DIF_BPF_COEFF23, 0x0008fffd}, -{11700000, DIF_BPF_COEFF45, 0xffdeffff}, -{11700000, DIF_BPF_COEFF67, 0x0056001d}, -{11700000, DIF_BPF_COEFF89, 0xff57ff9c}, -{11700000, DIF_BPF_COEFF1011, 0x011300f0}, -{11700000, DIF_BPF_COEFF1213, 0xfe82fe2e}, -{11700000, DIF_BPF_COEFF1415, 0x01ca0310}, -{11700000, DIF_BPF_COEFF1617, 0xfe35fb62}, -{11700000, DIF_BPF_COEFF1819, 0x0155065a}, -{11700000, DIF_BPF_COEFF2021, 0xffbaf7f2}, -{11700000, DIF_BPF_COEFF2223, 0xfe8c0977}, -{11700000, DIF_BPF_COEFF2425, 0x03cef5b2}, -{11700000, DIF_BPF_COEFF2627, 0xf9610a58}, -{11700000, DIF_BPF_COEFF2829, 0x09a5f68f}, -{11700000, DIF_BPF_COEFF3031, 0xf3790797}, -{11700000, DIF_BPF_COEFF3233, 0x0eebfb14}, -{11700000, DIF_BPF_COEFF3435, 0xef8001b5}, -{11700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 117_quant.dat*/ - - -/*case 11800000:*/ -/* BEGIN - DIF BPF register values from 118_quant.dat*/ -{11800000, DIF_BPF_COEFF01, 0xffff0000}, -{11800000, DIF_BPF_COEFF23, 0x00080004}, -{11800000, DIF_BPF_COEFF45, 0xffe0ffe9}, -{11800000, DIF_BPF_COEFF67, 0x004c0047}, -{11800000, DIF_BPF_COEFF89, 0xff75ff58}, -{11800000, DIF_BPF_COEFF1011, 0x00d1014a}, -{11800000, DIF_BPF_COEFF1213, 0xfef9fdc8}, -{11800000, DIF_BPF_COEFF1415, 0x0111036f}, -{11800000, DIF_BPF_COEFF1617, 0xff36fb21}, -{11800000, DIF_BPF_COEFF1819, 0x00120665}, -{11800000, DIF_BPF_COEFF2021, 0x012df82e}, -{11800000, DIF_BPF_COEFF2223, 0xfd0708ec}, -{11800000, DIF_BPF_COEFF2425, 0x0542f682}, -{11800000, DIF_BPF_COEFF2627, 0xf81f095c}, -{11800000, DIF_BPF_COEFF2829, 0x0a9af792}, -{11800000, DIF_BPF_COEFF3031, 0xf2db06b5}, -{11800000, DIF_BPF_COEFF3233, 0x0f38fbad}, -{11800000, DIF_BPF_COEFF3435, 0xef6c017e}, -{11800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 118_quant.dat*/ - - -/*case 11900000:*/ -/* BEGIN - DIF BPF register values from 119_quant.dat*/ -{11900000, DIF_BPF_COEFF01, 0xffffffff}, -{11900000, DIF_BPF_COEFF23, 0x0007000b}, -{11900000, DIF_BPF_COEFF45, 0xffe7ffd8}, -{11900000, DIF_BPF_COEFF67, 0x00370068}, -{11900000, DIF_BPF_COEFF89, 0xffa4ff28}, -{11900000, DIF_BPF_COEFF1011, 0x00790184}, -{11900000, DIF_BPF_COEFF1213, 0xff87fd91}, -{11900000, DIF_BPF_COEFF1415, 0x00430392}, -{11900000, DIF_BPF_COEFF1617, 0x0044fb26}, -{11900000, DIF_BPF_COEFF1819, 0xfece0626}, -{11900000, DIF_BPF_COEFF2021, 0x0294f8b2}, -{11900000, DIF_BPF_COEFF2223, 0xfb990825}, -{11900000, DIF_BPF_COEFF2425, 0x0698f77f}, -{11900000, DIF_BPF_COEFF2627, 0xf6fe0842}, -{11900000, DIF_BPF_COEFF2829, 0x0b73f8a7}, -{11900000, DIF_BPF_COEFF3031, 0xf25105cd}, -{11900000, DIF_BPF_COEFF3233, 0x0f7bfc48}, -{11900000, DIF_BPF_COEFF3435, 0xef5a0148}, -{11900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 119_quant.dat*/ - - -/*case 12000000:*/ -/* BEGIN - DIF BPF register values from 120_quant.dat*/ -{12000000, DIF_BPF_COEFF01, 0x0000fffe}, -{12000000, DIF_BPF_COEFF23, 0x00050010}, -{12000000, DIF_BPF_COEFF45, 0xfff2ffcc}, -{12000000, DIF_BPF_COEFF67, 0x001b007b}, -{12000000, DIF_BPF_COEFF89, 0xffdfff10}, -{12000000, DIF_BPF_COEFF1011, 0x00140198}, -{12000000, DIF_BPF_COEFF1213, 0x0020fd8e}, -{12000000, DIF_BPF_COEFF1415, 0xff710375}, -{12000000, DIF_BPF_COEFF1617, 0x014dfb73}, -{12000000, DIF_BPF_COEFF1819, 0xfd9a059f}, -{12000000, DIF_BPF_COEFF2021, 0x03e0f978}, -{12000000, DIF_BPF_COEFF2223, 0xfa4e0726}, -{12000000, DIF_BPF_COEFF2425, 0x07c8f8a7}, -{12000000, DIF_BPF_COEFF2627, 0xf600070c}, -{12000000, DIF_BPF_COEFF2829, 0x0c2ff9c9}, -{12000000, DIF_BPF_COEFF3031, 0xf1db04de}, -{12000000, DIF_BPF_COEFF3233, 0x0fb4fce5}, -{12000000, DIF_BPF_COEFF3435, 0xef4b0111}, -{12000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 120_quant.dat*/ - - -/*case 12100000:*/ -/* BEGIN - DIF BPF register values from 121_quant.dat*/ -{12100000, DIF_BPF_COEFF01, 0x0000fffd}, -{12100000, DIF_BPF_COEFF23, 0x00010012}, -{12100000, DIF_BPF_COEFF45, 0xffffffc8}, -{12100000, DIF_BPF_COEFF67, 0xfffb007e}, -{12100000, DIF_BPF_COEFF89, 0x001dff14}, -{12100000, DIF_BPF_COEFF1011, 0xffad0184}, -{12100000, DIF_BPF_COEFF1213, 0x00b7fdbe}, -{12100000, DIF_BPF_COEFF1415, 0xfea9031b}, -{12100000, DIF_BPF_COEFF1617, 0x0241fc01}, -{12100000, DIF_BPF_COEFF1819, 0xfc8504d6}, -{12100000, DIF_BPF_COEFF2021, 0x0504fa79}, -{12100000, DIF_BPF_COEFF2223, 0xf93005f6}, -{12100000, DIF_BPF_COEFF2425, 0x08caf9f2}, -{12100000, DIF_BPF_COEFF2627, 0xf52b05c0}, -{12100000, DIF_BPF_COEFF2829, 0x0ccbfaf9}, -{12100000, DIF_BPF_COEFF3031, 0xf17903eb}, -{12100000, DIF_BPF_COEFF3233, 0x0fe3fd83}, -{12100000, DIF_BPF_COEFF3435, 0xef3f00db}, -{12100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 121_quant.dat*/ - - -/*case 12200000:*/ -/* BEGIN - DIF BPF register values from 122_quant.dat*/ -{12200000, DIF_BPF_COEFF01, 0x0000fffd}, -{12200000, DIF_BPF_COEFF23, 0xfffe0011}, -{12200000, DIF_BPF_COEFF45, 0x000cffcc}, -{12200000, DIF_BPF_COEFF67, 0xffdb0071}, -{12200000, DIF_BPF_COEFF89, 0x0058ff32}, -{12200000, DIF_BPF_COEFF1011, 0xff4f014a}, -{12200000, DIF_BPF_COEFF1213, 0x013cfe1f}, -{12200000, DIF_BPF_COEFF1415, 0xfdfb028a}, -{12200000, DIF_BPF_COEFF1617, 0x0311fcc9}, -{12200000, DIF_BPF_COEFF1819, 0xfb9d03d6}, -{12200000, DIF_BPF_COEFF2021, 0x05f4fbad}, -{12200000, DIF_BPF_COEFF2223, 0xf848049d}, -{12200000, DIF_BPF_COEFF2425, 0x0999fb5b}, -{12200000, DIF_BPF_COEFF2627, 0xf4820461}, -{12200000, DIF_BPF_COEFF2829, 0x0d46fc32}, -{12200000, DIF_BPF_COEFF3031, 0xf12d02f4}, -{12200000, DIF_BPF_COEFF3233, 0x1007fe21}, -{12200000, DIF_BPF_COEFF3435, 0xef3600a4}, -{12200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 122_quant.dat*/ - - -/*case 12300000:*/ -/* BEGIN - DIF BPF register values from 123_quant.dat*/ -{12300000, DIF_BPF_COEFF01, 0x0000fffe}, -{12300000, DIF_BPF_COEFF23, 0xfffa000e}, -{12300000, DIF_BPF_COEFF45, 0x0017ffd9}, -{12300000, DIF_BPF_COEFF67, 0xffc10055}, -{12300000, DIF_BPF_COEFF89, 0x0088ff68}, -{12300000, DIF_BPF_COEFF1011, 0xff0400f0}, -{12300000, DIF_BPF_COEFF1213, 0x01a6fea7}, -{12300000, DIF_BPF_COEFF1415, 0xfd7501cc}, -{12300000, DIF_BPF_COEFF1617, 0x03b0fdc0}, -{12300000, DIF_BPF_COEFF1819, 0xfaef02a8}, -{12300000, DIF_BPF_COEFF2021, 0x06a7fd07}, -{12300000, DIF_BPF_COEFF2223, 0xf79d0326}, -{12300000, DIF_BPF_COEFF2425, 0x0a31fcda}, -{12300000, DIF_BPF_COEFF2627, 0xf40702f3}, -{12300000, DIF_BPF_COEFF2829, 0x0d9ffd72}, -{12300000, DIF_BPF_COEFF3031, 0xf0f601fa}, -{12300000, DIF_BPF_COEFF3233, 0x1021fec0}, -{12300000, DIF_BPF_COEFF3435, 0xef2f006d}, -{12300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 123_quant.dat*/ - - -/*case 12400000:*/ -/* BEGIN - DIF BPF register values from 124_quant.dat*/ -{12400000, DIF_BPF_COEFF01, 0x0001ffff}, -{12400000, DIF_BPF_COEFF23, 0xfff80007}, -{12400000, DIF_BPF_COEFF45, 0x001fffeb}, -{12400000, DIF_BPF_COEFF67, 0xffaf002d}, -{12400000, DIF_BPF_COEFF89, 0x00a8ffb0}, -{12400000, DIF_BPF_COEFF1011, 0xfed3007e}, -{12400000, DIF_BPF_COEFF1213, 0x01e9ff4c}, -{12400000, DIF_BPF_COEFF1415, 0xfd2000ee}, -{12400000, DIF_BPF_COEFF1617, 0x0413fed8}, -{12400000, DIF_BPF_COEFF1819, 0xfa82015c}, -{12400000, DIF_BPF_COEFF2021, 0x0715fe7d}, -{12400000, DIF_BPF_COEFF2223, 0xf7340198}, -{12400000, DIF_BPF_COEFF2425, 0x0a8dfe69}, -{12400000, DIF_BPF_COEFF2627, 0xf3bd017c}, -{12400000, DIF_BPF_COEFF2829, 0x0dd5feb8}, -{12400000, DIF_BPF_COEFF3031, 0xf0d500fd}, -{12400000, DIF_BPF_COEFF3233, 0x1031ff60}, -{12400000, DIF_BPF_COEFF3435, 0xef2b0037}, -{12400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 124_quant.dat*/ - - -/*case 12500000:*/ -/* BEGIN - DIF BPF register values from 125_quant.dat*/ -{12500000, DIF_BPF_COEFF01, 0x00010000}, -{12500000, DIF_BPF_COEFF23, 0xfff70000}, -{12500000, DIF_BPF_COEFF45, 0x00220000}, -{12500000, DIF_BPF_COEFF67, 0xffa90000}, -{12500000, DIF_BPF_COEFF89, 0x00b30000}, -{12500000, DIF_BPF_COEFF1011, 0xfec20000}, -{12500000, DIF_BPF_COEFF1213, 0x02000000}, -{12500000, DIF_BPF_COEFF1415, 0xfd030000}, -{12500000, DIF_BPF_COEFF1617, 0x04350000}, -{12500000, DIF_BPF_COEFF1819, 0xfa5e0000}, -{12500000, DIF_BPF_COEFF2021, 0x073b0000}, -{12500000, DIF_BPF_COEFF2223, 0xf7110000}, -{12500000, DIF_BPF_COEFF2425, 0x0aac0000}, -{12500000, DIF_BPF_COEFF2627, 0xf3a40000}, -{12500000, DIF_BPF_COEFF2829, 0x0de70000}, -{12500000, DIF_BPF_COEFF3031, 0xf0c90000}, -{12500000, DIF_BPF_COEFF3233, 0x10360000}, -{12500000, DIF_BPF_COEFF3435, 0xef290000}, -{12500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 125_quant.dat*/ - - -/*case 12600000:*/ -/* BEGIN - DIF BPF register values from 126_quant.dat*/ -{12600000, DIF_BPF_COEFF01, 0x00010001}, -{12600000, DIF_BPF_COEFF23, 0xfff8fff9}, -{12600000, DIF_BPF_COEFF45, 0x001f0015}, -{12600000, DIF_BPF_COEFF67, 0xffafffd3}, -{12600000, DIF_BPF_COEFF89, 0x00a80050}, -{12600000, DIF_BPF_COEFF1011, 0xfed3ff82}, -{12600000, DIF_BPF_COEFF1213, 0x01e900b4}, -{12600000, DIF_BPF_COEFF1415, 0xfd20ff12}, -{12600000, DIF_BPF_COEFF1617, 0x04130128}, -{12600000, DIF_BPF_COEFF1819, 0xfa82fea4}, -{12600000, DIF_BPF_COEFF2021, 0x07150183}, -{12600000, DIF_BPF_COEFF2223, 0xf734fe68}, -{12600000, DIF_BPF_COEFF2425, 0x0a8d0197}, -{12600000, DIF_BPF_COEFF2627, 0xf3bdfe84}, -{12600000, DIF_BPF_COEFF2829, 0x0dd50148}, -{12600000, DIF_BPF_COEFF3031, 0xf0d5ff03}, -{12600000, DIF_BPF_COEFF3233, 0x103100a0}, -{12600000, DIF_BPF_COEFF3435, 0xef2bffc9}, -{12600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 126_quant.dat*/ - - -/*case 12700000:*/ -/* BEGIN - DIF BPF register values from 127_quant.dat*/ -{12700000, DIF_BPF_COEFF01, 0x00000002}, -{12700000, DIF_BPF_COEFF23, 0xfffafff2}, -{12700000, DIF_BPF_COEFF45, 0x00170027}, -{12700000, DIF_BPF_COEFF67, 0xffc1ffab}, -{12700000, DIF_BPF_COEFF89, 0x00880098}, -{12700000, DIF_BPF_COEFF1011, 0xff04ff10}, -{12700000, DIF_BPF_COEFF1213, 0x01a60159}, -{12700000, DIF_BPF_COEFF1415, 0xfd75fe34}, -{12700000, DIF_BPF_COEFF1617, 0x03b00240}, -{12700000, DIF_BPF_COEFF1819, 0xfaeffd58}, -{12700000, DIF_BPF_COEFF2021, 0x06a702f9}, -{12700000, DIF_BPF_COEFF2223, 0xf79dfcda}, -{12700000, DIF_BPF_COEFF2425, 0x0a310326}, -{12700000, DIF_BPF_COEFF2627, 0xf407fd0d}, -{12700000, DIF_BPF_COEFF2829, 0x0d9f028e}, -{12700000, DIF_BPF_COEFF3031, 0xf0f6fe06}, -{12700000, DIF_BPF_COEFF3233, 0x10210140}, -{12700000, DIF_BPF_COEFF3435, 0xef2fff93}, -{12700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 127_quant.dat*/ - - -/*case 12800000:*/ -/* BEGIN - DIF BPF register values from 128_quant.dat*/ -{12800000, DIF_BPF_COEFF01, 0x00000003}, -{12800000, DIF_BPF_COEFF23, 0xfffeffef}, -{12800000, DIF_BPF_COEFF45, 0x000c0034}, -{12800000, DIF_BPF_COEFF67, 0xffdbff8f}, -{12800000, DIF_BPF_COEFF89, 0x005800ce}, -{12800000, DIF_BPF_COEFF1011, 0xff4ffeb6}, -{12800000, DIF_BPF_COEFF1213, 0x013c01e1}, -{12800000, DIF_BPF_COEFF1415, 0xfdfbfd76}, -{12800000, DIF_BPF_COEFF1617, 0x03110337}, -{12800000, DIF_BPF_COEFF1819, 0xfb9dfc2a}, -{12800000, DIF_BPF_COEFF2021, 0x05f40453}, -{12800000, DIF_BPF_COEFF2223, 0xf848fb63}, -{12800000, DIF_BPF_COEFF2425, 0x099904a5}, -{12800000, DIF_BPF_COEFF2627, 0xf482fb9f}, -{12800000, DIF_BPF_COEFF2829, 0x0d4603ce}, -{12800000, DIF_BPF_COEFF3031, 0xf12dfd0c}, -{12800000, DIF_BPF_COEFF3233, 0x100701df}, -{12800000, DIF_BPF_COEFF3435, 0xef36ff5c}, -{12800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 128_quant.dat*/ - - -/*case 12900000:*/ -/* BEGIN - DIF BPF register values from 129_quant.dat*/ -{12900000, DIF_BPF_COEFF01, 0x00000003}, -{12900000, DIF_BPF_COEFF23, 0x0001ffee}, -{12900000, DIF_BPF_COEFF45, 0xffff0038}, -{12900000, DIF_BPF_COEFF67, 0xfffbff82}, -{12900000, DIF_BPF_COEFF89, 0x001d00ec}, -{12900000, DIF_BPF_COEFF1011, 0xffadfe7c}, -{12900000, DIF_BPF_COEFF1213, 0x00b70242}, -{12900000, DIF_BPF_COEFF1415, 0xfea9fce5}, -{12900000, DIF_BPF_COEFF1617, 0x024103ff}, -{12900000, DIF_BPF_COEFF1819, 0xfc85fb2a}, -{12900000, DIF_BPF_COEFF2021, 0x05040587}, -{12900000, DIF_BPF_COEFF2223, 0xf930fa0a}, -{12900000, DIF_BPF_COEFF2425, 0x08ca060e}, -{12900000, DIF_BPF_COEFF2627, 0xf52bfa40}, -{12900000, DIF_BPF_COEFF2829, 0x0ccb0507}, -{12900000, DIF_BPF_COEFF3031, 0xf179fc15}, -{12900000, DIF_BPF_COEFF3233, 0x0fe3027d}, -{12900000, DIF_BPF_COEFF3435, 0xef3fff25}, -{12900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 129_quant.dat*/ - - -/*case 113000000:*/ -/* BEGIN - DIF BPF register values from 130_quant.dat*/ -{13000000, DIF_BPF_COEFF01, 0x00000002}, -{13000000, DIF_BPF_COEFF23, 0x0005fff0}, -{13000000, DIF_BPF_COEFF45, 0xfff20034}, -{13000000, DIF_BPF_COEFF67, 0x001bff85}, -{13000000, DIF_BPF_COEFF89, 0xffdf00f0}, -{13000000, DIF_BPF_COEFF1011, 0x0014fe68}, -{13000000, DIF_BPF_COEFF1213, 0x00200272}, -{13000000, DIF_BPF_COEFF1415, 0xff71fc8b}, -{13000000, DIF_BPF_COEFF1617, 0x014d048d}, -{13000000, DIF_BPF_COEFF1819, 0xfd9afa61}, -{13000000, DIF_BPF_COEFF2021, 0x03e00688}, -{13000000, DIF_BPF_COEFF2223, 0xfa4ef8da}, -{13000000, DIF_BPF_COEFF2425, 0x07c80759}, -{13000000, DIF_BPF_COEFF2627, 0xf600f8f4}, -{13000000, DIF_BPF_COEFF2829, 0x0c2f0637}, -{13000000, DIF_BPF_COEFF3031, 0xf1dbfb22}, -{13000000, DIF_BPF_COEFF3233, 0x0fb4031b}, -{13000000, DIF_BPF_COEFF3435, 0xef4bfeef}, -{13000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 130_quant.dat*/ - - -/*case 13100000:*/ -/* BEGIN - DIF BPF register values from 131_quant.dat*/ -{13100000, DIF_BPF_COEFF01, 0xffff0001}, -{13100000, DIF_BPF_COEFF23, 0x0007fff5}, -{13100000, DIF_BPF_COEFF45, 0xffe70028}, -{13100000, DIF_BPF_COEFF67, 0x0037ff98}, -{13100000, DIF_BPF_COEFF89, 0xffa400d8}, -{13100000, DIF_BPF_COEFF1011, 0x0079fe7c}, -{13100000, DIF_BPF_COEFF1213, 0xff87026f}, -{13100000, DIF_BPF_COEFF1415, 0x0043fc6e}, -{13100000, DIF_BPF_COEFF1617, 0x004404da}, -{13100000, DIF_BPF_COEFF1819, 0xfecef9da}, -{13100000, DIF_BPF_COEFF2021, 0x0294074e}, -{13100000, DIF_BPF_COEFF2223, 0xfb99f7db}, -{13100000, DIF_BPF_COEFF2425, 0x06980881}, -{13100000, DIF_BPF_COEFF2627, 0xf6fef7be}, -{13100000, DIF_BPF_COEFF2829, 0x0b730759}, -{13100000, DIF_BPF_COEFF3031, 0xf251fa33}, -{13100000, DIF_BPF_COEFF3233, 0x0f7b03b8}, -{13100000, DIF_BPF_COEFF3435, 0xef5afeb8}, -{13100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 131_quant.dat*/ - - -/*case 13200000:*/ -/* BEGIN - DIF BPF register values from 132_quant.dat*/ -{13200000, DIF_BPF_COEFF01, 0xffff0000}, -{13200000, DIF_BPF_COEFF23, 0x0008fffc}, -{13200000, DIF_BPF_COEFF45, 0xffe00017}, -{13200000, DIF_BPF_COEFF67, 0x004cffb9}, -{13200000, DIF_BPF_COEFF89, 0xff7500a8}, -{13200000, DIF_BPF_COEFF1011, 0x00d1feb6}, -{13200000, DIF_BPF_COEFF1213, 0xfef90238}, -{13200000, DIF_BPF_COEFF1415, 0x0111fc91}, -{13200000, DIF_BPF_COEFF1617, 0xff3604df}, -{13200000, DIF_BPF_COEFF1819, 0x0012f99b}, -{13200000, DIF_BPF_COEFF2021, 0x012d07d2}, -{13200000, DIF_BPF_COEFF2223, 0xfd07f714}, -{13200000, DIF_BPF_COEFF2425, 0x0542097e}, -{13200000, DIF_BPF_COEFF2627, 0xf81ff6a4}, -{13200000, DIF_BPF_COEFF2829, 0x0a9a086e}, -{13200000, DIF_BPF_COEFF3031, 0xf2dbf94b}, -{13200000, DIF_BPF_COEFF3233, 0x0f380453}, -{13200000, DIF_BPF_COEFF3435, 0xef6cfe82}, -{13200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 132_quant.dat*/ - - -/*case 13300000:*/ -/* BEGIN - DIF BPF register values from 133_quant.dat*/ -{13300000, DIF_BPF_COEFF01, 0xffffffff}, -{13300000, DIF_BPF_COEFF23, 0x00080003}, -{13300000, DIF_BPF_COEFF45, 0xffde0001}, -{13300000, DIF_BPF_COEFF67, 0x0056ffe3}, -{13300000, DIF_BPF_COEFF89, 0xff570064}, -{13300000, DIF_BPF_COEFF1011, 0x0113ff10}, -{13300000, DIF_BPF_COEFF1213, 0xfe8201d2}, -{13300000, DIF_BPF_COEFF1415, 0x01cafcf0}, -{13300000, DIF_BPF_COEFF1617, 0xfe35049e}, -{13300000, DIF_BPF_COEFF1819, 0x0155f9a6}, -{13300000, DIF_BPF_COEFF2021, 0xffba080e}, -{13300000, DIF_BPF_COEFF2223, 0xfe8cf689}, -{13300000, DIF_BPF_COEFF2425, 0x03ce0a4e}, -{13300000, DIF_BPF_COEFF2627, 0xf961f5a8}, -{13300000, DIF_BPF_COEFF2829, 0x09a50971}, -{13300000, DIF_BPF_COEFF3031, 0xf379f869}, -{13300000, DIF_BPF_COEFF3233, 0x0eeb04ec}, -{13300000, DIF_BPF_COEFF3435, 0xef80fe4b}, -{13300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 133_quant.dat*/ - - -/*case 13400000:*/ -/* BEGIN - DIF BPF register values from 134_quant.dat*/ -{13400000, DIF_BPF_COEFF01, 0x0000fffe}, -{13400000, DIF_BPF_COEFF23, 0x0007000a}, -{13400000, DIF_BPF_COEFF45, 0xffe2ffec}, -{13400000, DIF_BPF_COEFF67, 0x00540012}, -{13400000, DIF_BPF_COEFF89, 0xff4e0015}, -{13400000, DIF_BPF_COEFF1011, 0x0137ff82}, -{13400000, DIF_BPF_COEFF1213, 0xfe2e0145}, -{13400000, DIF_BPF_COEFF1415, 0x0260fd86}, -{13400000, DIF_BPF_COEFF1617, 0xfd51041a}, -{13400000, DIF_BPF_COEFF1819, 0x0287f9fb}, -{13400000, DIF_BPF_COEFF2021, 0xfe4a0802}, -{13400000, DIF_BPF_COEFF2223, 0x001df63f}, -{13400000, DIF_BPF_COEFF2425, 0x02430aeb}, -{13400000, DIF_BPF_COEFF2627, 0xfabdf4ce}, -{13400000, DIF_BPF_COEFF2829, 0x08970a62}, -{13400000, DIF_BPF_COEFF3031, 0xf428f78f}, -{13400000, DIF_BPF_COEFF3233, 0x0e950584}, -{13400000, DIF_BPF_COEFF3435, 0xef97fe15}, -{13400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 134_quant.dat*/ - - -/*case 13500000:*/ -/* BEGIN - DIF BPF register values from 135_quant.dat*/ -{13500000, DIF_BPF_COEFF01, 0x0000fffd}, -{13500000, DIF_BPF_COEFF23, 0x0004000f}, -{13500000, DIF_BPF_COEFF45, 0xffeaffda}, -{13500000, DIF_BPF_COEFF67, 0x0046003d}, -{13500000, DIF_BPF_COEFF89, 0xff5affc4}, -{13500000, DIF_BPF_COEFF1011, 0x013b0000}, -{13500000, DIF_BPF_COEFF1213, 0xfe04009d}, -{13500000, DIF_BPF_COEFF1415, 0x02c8fe48}, -{13500000, DIF_BPF_COEFF1617, 0xfc99035a}, -{13500000, DIF_BPF_COEFF1819, 0x0397fa96}, -{13500000, DIF_BPF_COEFF2021, 0xfcec07ad}, -{13500000, DIF_BPF_COEFF2223, 0x01adf637}, -{13500000, DIF_BPF_COEFF2425, 0x00ac0b53}, -{13500000, DIF_BPF_COEFF2627, 0xfc2ef419}, -{13500000, DIF_BPF_COEFF2829, 0x07730b3e}, -{13500000, DIF_BPF_COEFF3031, 0xf4e9f6bd}, -{13500000, DIF_BPF_COEFF3233, 0x0e35061a}, -{13500000, DIF_BPF_COEFF3435, 0xefb1fddf}, -{13500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 135_quant.dat*/ - - -/*case 13600000:*/ -/* BEGIN - DIF BPF register values from 136_quant.dat*/ -{13600000, DIF_BPF_COEFF01, 0x0000fffd}, -{13600000, DIF_BPF_COEFF23, 0x00000012}, -{13600000, DIF_BPF_COEFF45, 0xfff6ffcd}, -{13600000, DIF_BPF_COEFF67, 0x002f0061}, -{13600000, DIF_BPF_COEFF89, 0xff7bff79}, -{13600000, DIF_BPF_COEFF1011, 0x011e007e}, -{13600000, DIF_BPF_COEFF1213, 0xfe08ffe8}, -{13600000, DIF_BPF_COEFF1415, 0x02f9ff28}, -{13600000, DIF_BPF_COEFF1617, 0xfc17026a}, -{13600000, DIF_BPF_COEFF1819, 0x0479fb70}, -{13600000, DIF_BPF_COEFF2021, 0xfbad0713}, -{13600000, DIF_BPF_COEFF2223, 0x032ff672}, -{13600000, DIF_BPF_COEFF2425, 0xff100b83}, -{13600000, DIF_BPF_COEFF2627, 0xfdaff38b}, -{13600000, DIF_BPF_COEFF2829, 0x063c0c04}, -{13600000, DIF_BPF_COEFF3031, 0xf5baf5f5}, -{13600000, DIF_BPF_COEFF3233, 0x0dcc06ae}, -{13600000, DIF_BPF_COEFF3435, 0xefcdfda8}, -{13600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 136_quant.dat*/ - - -/*case 13700000:*/ -/* BEGIN - DIF BPF register values from 137_quant.dat*/ -{13700000, DIF_BPF_COEFF01, 0x0000fffd}, -{13700000, DIF_BPF_COEFF23, 0xfffd0012}, -{13700000, DIF_BPF_COEFF45, 0x0004ffc8}, -{13700000, DIF_BPF_COEFF67, 0x00100078}, -{13700000, DIF_BPF_COEFF89, 0xffacff3e}, -{13700000, DIF_BPF_COEFF1011, 0x00e200f0}, -{13700000, DIF_BPF_COEFF1213, 0xfe39ff35}, -{13700000, DIF_BPF_COEFF1415, 0x02f10017}, -{13700000, DIF_BPF_COEFF1617, 0xfbd30156}, -{13700000, DIF_BPF_COEFF1819, 0x0521fc7f}, -{13700000, DIF_BPF_COEFF2021, 0xfa9c0638}, -{13700000, DIF_BPF_COEFF2223, 0x0499f6ee}, -{13700000, DIF_BPF_COEFF2425, 0xfd7a0b7c}, -{13700000, DIF_BPF_COEFF2627, 0xff39f325}, -{13700000, DIF_BPF_COEFF2829, 0x04f40cb3}, -{13700000, DIF_BPF_COEFF3031, 0xf69af537}, -{13700000, DIF_BPF_COEFF3233, 0x0d5a073f}, -{13700000, DIF_BPF_COEFF3435, 0xefecfd72}, -{13700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 137_quant.dat*/ - - -/*case 13800000:*/ -/* BEGIN - DIF BPF register values from 138_quant.dat*/ -{13800000, DIF_BPF_COEFF01, 0x0001fffe}, -{13800000, DIF_BPF_COEFF23, 0xfffa000e}, -{13800000, DIF_BPF_COEFF45, 0x0011ffcb}, -{13800000, DIF_BPF_COEFF67, 0xfff0007f}, -{13800000, DIF_BPF_COEFF89, 0xffe7ff19}, -{13800000, DIF_BPF_COEFF1011, 0x008f014a}, -{13800000, DIF_BPF_COEFF1213, 0xfe94fe93}, -{13800000, DIF_BPF_COEFF1415, 0x02b00105}, -{13800000, DIF_BPF_COEFF1617, 0xfbd3002f}, -{13800000, DIF_BPF_COEFF1819, 0x0585fdb7}, -{13800000, DIF_BPF_COEFF2021, 0xf9c10525}, -{13800000, DIF_BPF_COEFF2223, 0x05def7a8}, -{13800000, DIF_BPF_COEFF2425, 0xfbf20b3c}, -{13800000, DIF_BPF_COEFF2627, 0x00c7f2e9}, -{13800000, DIF_BPF_COEFF2829, 0x03a00d48}, -{13800000, DIF_BPF_COEFF3031, 0xf787f484}, -{13800000, DIF_BPF_COEFF3233, 0x0cdf07cd}, -{13800000, DIF_BPF_COEFF3435, 0xf00dfd3c}, -{13800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 138_quant.dat*/ - - -/*case 13900000:*/ -/* BEGIN - DIF BPF register values from 139_quant.dat*/ -{13900000, DIF_BPF_COEFF01, 0x00010000}, -{13900000, DIF_BPF_COEFF23, 0xfff80008}, -{13900000, DIF_BPF_COEFF45, 0x001bffd7}, -{13900000, DIF_BPF_COEFF67, 0xffd10076}, -{13900000, DIF_BPF_COEFF89, 0x0026ff0e}, -{13900000, DIF_BPF_COEFF1011, 0x002c0184}, -{13900000, DIF_BPF_COEFF1213, 0xff0ffe10}, -{13900000, DIF_BPF_COEFF1415, 0x023b01e0}, -{13900000, DIF_BPF_COEFF1617, 0xfc17ff06}, -{13900000, DIF_BPF_COEFF1819, 0x05a2ff09}, -{13900000, DIF_BPF_COEFF2021, 0xf92703e4}, -{13900000, DIF_BPF_COEFF2223, 0x06f4f89b}, -{13900000, DIF_BPF_COEFF2425, 0xfa820ac5}, -{13900000, DIF_BPF_COEFF2627, 0x0251f2d9}, -{13900000, DIF_BPF_COEFF2829, 0x02430dc3}, -{13900000, DIF_BPF_COEFF3031, 0xf881f3dc}, -{13900000, DIF_BPF_COEFF3233, 0x0c5c0859}, -{13900000, DIF_BPF_COEFF3435, 0xf031fd06}, -{13900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 139_quant.dat*/ - - -/*case 14000000:*/ -/* BEGIN - DIF BPF register values from 140_quant.dat*/ -{14000000, DIF_BPF_COEFF01, 0x00010001}, -{14000000, DIF_BPF_COEFF23, 0xfff80001}, -{14000000, DIF_BPF_COEFF45, 0x0021ffe8}, -{14000000, DIF_BPF_COEFF67, 0xffba005d}, -{14000000, DIF_BPF_COEFF89, 0x0060ff1f}, -{14000000, DIF_BPF_COEFF1011, 0xffc40198}, -{14000000, DIF_BPF_COEFF1213, 0xffa0fdb5}, -{14000000, DIF_BPF_COEFF1415, 0x019a029a}, -{14000000, DIF_BPF_COEFF1617, 0xfc99fdea}, -{14000000, DIF_BPF_COEFF1819, 0x05750067}, -{14000000, DIF_BPF_COEFF2021, 0xf8d4027f}, -{14000000, DIF_BPF_COEFF2223, 0x07d4f9c0}, -{14000000, DIF_BPF_COEFF2425, 0xf9320a1a}, -{14000000, DIF_BPF_COEFF2627, 0x03d2f2f3}, -{14000000, DIF_BPF_COEFF2829, 0x00df0e22}, -{14000000, DIF_BPF_COEFF3031, 0xf986f341}, -{14000000, DIF_BPF_COEFF3233, 0x0bd108e2}, -{14000000, DIF_BPF_COEFF3435, 0xf058fcd1}, -{14000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 140_quant.dat*/ - - -/*case 14100000:*/ -/* BEGIN - DIF BPF register values from 141_quant.dat*/ -{14100000, DIF_BPF_COEFF01, 0x00000002}, -{14100000, DIF_BPF_COEFF23, 0xfff9fffa}, -{14100000, DIF_BPF_COEFF45, 0x0021fffd}, -{14100000, DIF_BPF_COEFF67, 0xffac0038}, -{14100000, DIF_BPF_COEFF89, 0x008eff4a}, -{14100000, DIF_BPF_COEFF1011, 0xff630184}, -{14100000, DIF_BPF_COEFF1213, 0x003afd8b}, -{14100000, DIF_BPF_COEFF1415, 0x00da0326}, -{14100000, DIF_BPF_COEFF1617, 0xfd51fced}, -{14100000, DIF_BPF_COEFF1819, 0x050101c0}, -{14100000, DIF_BPF_COEFF2021, 0xf8cb0103}, -{14100000, DIF_BPF_COEFF2223, 0x0876fb10}, -{14100000, DIF_BPF_COEFF2425, 0xf80a093e}, -{14100000, DIF_BPF_COEFF2627, 0x0543f338}, -{14100000, DIF_BPF_COEFF2829, 0xff7a0e66}, -{14100000, DIF_BPF_COEFF3031, 0xfa94f2b2}, -{14100000, DIF_BPF_COEFF3233, 0x0b3f0967}, -{14100000, DIF_BPF_COEFF3435, 0xf081fc9b}, -{14100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 141_quant.dat*/ - - -/*case 14200000:*/ -/* BEGIN - DIF BPF register values from 142_quant.dat*/ -{14200000, DIF_BPF_COEFF01, 0x00000003}, -{14200000, DIF_BPF_COEFF23, 0xfffbfff3}, -{14200000, DIF_BPF_COEFF45, 0x001d0013}, -{14200000, DIF_BPF_COEFF67, 0xffaa000b}, -{14200000, DIF_BPF_COEFF89, 0x00aaff89}, -{14200000, DIF_BPF_COEFF1011, 0xff13014a}, -{14200000, DIF_BPF_COEFF1213, 0x00cefd95}, -{14200000, DIF_BPF_COEFF1415, 0x000a037b}, -{14200000, DIF_BPF_COEFF1617, 0xfe35fc1d}, -{14200000, DIF_BPF_COEFF1819, 0x044c0305}, -{14200000, DIF_BPF_COEFF2021, 0xf90cff7e}, -{14200000, DIF_BPF_COEFF2223, 0x08d5fc81}, -{14200000, DIF_BPF_COEFF2425, 0xf7100834}, -{14200000, DIF_BPF_COEFF2627, 0x069ff3a7}, -{14200000, DIF_BPF_COEFF2829, 0xfe160e8d}, -{14200000, DIF_BPF_COEFF3031, 0xfbaaf231}, -{14200000, DIF_BPF_COEFF3233, 0x0aa509e9}, -{14200000, DIF_BPF_COEFF3435, 0xf0adfc65}, -{14200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 142_quant.dat*/ - - -/*case 14300000:*/ -/* BEGIN - DIF BPF register values from 143_quant.dat*/ -{14300000, DIF_BPF_COEFF01, 0x00000003}, -{14300000, DIF_BPF_COEFF23, 0xffffffef}, -{14300000, DIF_BPF_COEFF45, 0x00140025}, -{14300000, DIF_BPF_COEFF67, 0xffb4ffdd}, -{14300000, DIF_BPF_COEFF89, 0x00b2ffd6}, -{14300000, DIF_BPF_COEFF1011, 0xfedb00f0}, -{14300000, DIF_BPF_COEFF1213, 0x0150fdd3}, -{14300000, DIF_BPF_COEFF1415, 0xff380391}, -{14300000, DIF_BPF_COEFF1617, 0xff36fb85}, -{14300000, DIF_BPF_COEFF1819, 0x035e0426}, -{14300000, DIF_BPF_COEFF2021, 0xf994fdfe}, -{14300000, DIF_BPF_COEFF2223, 0x08eefe0b}, -{14300000, DIF_BPF_COEFF2425, 0xf6490702}, -{14300000, DIF_BPF_COEFF2627, 0x07e1f43e}, -{14300000, DIF_BPF_COEFF2829, 0xfcb60e97}, -{14300000, DIF_BPF_COEFF3031, 0xfcc6f1be}, -{14300000, DIF_BPF_COEFF3233, 0x0a040a67}, -{14300000, DIF_BPF_COEFF3435, 0xf0dbfc30}, -{14300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 143_quant.dat*/ - - -/*case 14400000:*/ -/* BEGIN - DIF BPF register values from 144_quant.dat*/ -{14400000, DIF_BPF_COEFF01, 0x00000003}, -{14400000, DIF_BPF_COEFF23, 0x0002ffee}, -{14400000, DIF_BPF_COEFF45, 0x00070033}, -{14400000, DIF_BPF_COEFF67, 0xffc9ffb4}, -{14400000, DIF_BPF_COEFF89, 0x00a40027}, -{14400000, DIF_BPF_COEFF1011, 0xfec3007e}, -{14400000, DIF_BPF_COEFF1213, 0x01b4fe3f}, -{14400000, DIF_BPF_COEFF1415, 0xfe760369}, -{14400000, DIF_BPF_COEFF1617, 0x0044fb2e}, -{14400000, DIF_BPF_COEFF1819, 0x02450518}, -{14400000, DIF_BPF_COEFF2021, 0xfa5ffc90}, -{14400000, DIF_BPF_COEFF2223, 0x08c1ffa1}, -{14400000, DIF_BPF_COEFF2425, 0xf5bc05ae}, -{14400000, DIF_BPF_COEFF2627, 0x0902f4fc}, -{14400000, DIF_BPF_COEFF2829, 0xfb600e85}, -{14400000, DIF_BPF_COEFF3031, 0xfde7f15a}, -{14400000, DIF_BPF_COEFF3233, 0x095d0ae2}, -{14400000, DIF_BPF_COEFF3435, 0xf10cfbfb}, -{14400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 144_quant.dat*/ - - -/*case 14500000:*/ -/* BEGIN - DIF BPF register values from 145_quant.dat*/ -{14500000, DIF_BPF_COEFF01, 0xffff0002}, -{14500000, DIF_BPF_COEFF23, 0x0005ffef}, -{14500000, DIF_BPF_COEFF45, 0xfffa0038}, -{14500000, DIF_BPF_COEFF67, 0xffe5ff95}, -{14500000, DIF_BPF_COEFF89, 0x00820074}, -{14500000, DIF_BPF_COEFF1011, 0xfecc0000}, -{14500000, DIF_BPF_COEFF1213, 0x01f0fed0}, -{14500000, DIF_BPF_COEFF1415, 0xfdd20304}, -{14500000, DIF_BPF_COEFF1617, 0x014dfb1d}, -{14500000, DIF_BPF_COEFF1819, 0x010e05ce}, -{14500000, DIF_BPF_COEFF2021, 0xfb64fb41}, -{14500000, DIF_BPF_COEFF2223, 0x084e013b}, -{14500000, DIF_BPF_COEFF2425, 0xf569043e}, -{14500000, DIF_BPF_COEFF2627, 0x0a00f5dd}, -{14500000, DIF_BPF_COEFF2829, 0xfa150e55}, -{14500000, DIF_BPF_COEFF3031, 0xff0bf104}, -{14500000, DIF_BPF_COEFF3233, 0x08b00b59}, -{14500000, DIF_BPF_COEFF3435, 0xf13ffbc6}, -{14500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 145_quant.dat*/ - - -/*case 14600000:*/ -/* BEGIN - DIF BPF register values from 146_quant.dat*/ -{14600000, DIF_BPF_COEFF01, 0xffff0001}, -{14600000, DIF_BPF_COEFF23, 0x0008fff4}, -{14600000, DIF_BPF_COEFF45, 0xffed0035}, -{14600000, DIF_BPF_COEFF67, 0x0005ff83}, -{14600000, DIF_BPF_COEFF89, 0x005000b4}, -{14600000, DIF_BPF_COEFF1011, 0xfef6ff82}, -{14600000, DIF_BPF_COEFF1213, 0x01ffff7a}, -{14600000, DIF_BPF_COEFF1415, 0xfd580269}, -{14600000, DIF_BPF_COEFF1617, 0x0241fb53}, -{14600000, DIF_BPF_COEFF1819, 0xffca0640}, -{14600000, DIF_BPF_COEFF2021, 0xfc99fa1e}, -{14600000, DIF_BPF_COEFF2223, 0x079a02cb}, -{14600000, DIF_BPF_COEFF2425, 0xf55502ba}, -{14600000, DIF_BPF_COEFF2627, 0x0ad5f6e0}, -{14600000, DIF_BPF_COEFF2829, 0xf8d90e0a}, -{14600000, DIF_BPF_COEFF3031, 0x0031f0bd}, -{14600000, DIF_BPF_COEFF3233, 0x07fd0bcb}, -{14600000, DIF_BPF_COEFF3435, 0xf174fb91}, -{14600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 146_quant.dat*/ - - -/*case 14700000:*/ -/* BEGIN - DIF BPF register values from 147_quant.dat*/ -{14700000, DIF_BPF_COEFF01, 0xffffffff}, -{14700000, DIF_BPF_COEFF23, 0x0009fffb}, -{14700000, DIF_BPF_COEFF45, 0xffe4002a}, -{14700000, DIF_BPF_COEFF67, 0x0025ff82}, -{14700000, DIF_BPF_COEFF89, 0x001400e0}, -{14700000, DIF_BPF_COEFF1011, 0xff3cff10}, -{14700000, DIF_BPF_COEFF1213, 0x01e10030}, -{14700000, DIF_BPF_COEFF1415, 0xfd1201a4}, -{14700000, DIF_BPF_COEFF1617, 0x0311fbcd}, -{14700000, DIF_BPF_COEFF1819, 0xfe88066a}, -{14700000, DIF_BPF_COEFF2021, 0xfdf1f92f}, -{14700000, DIF_BPF_COEFF2223, 0x06aa0449}, -{14700000, DIF_BPF_COEFF2425, 0xf57e0128}, -{14700000, DIF_BPF_COEFF2627, 0x0b7ef801}, -{14700000, DIF_BPF_COEFF2829, 0xf7b00da2}, -{14700000, DIF_BPF_COEFF3031, 0x0156f086}, -{14700000, DIF_BPF_COEFF3233, 0x07450c39}, -{14700000, DIF_BPF_COEFF3435, 0xf1acfb5c}, -{14700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 147_quant.dat*/ - - -/*case 14800000:*/ -/* BEGIN - DIF BPF register values from 148_quant.dat*/ -{14800000, DIF_BPF_COEFF01, 0x0000fffe}, -{14800000, DIF_BPF_COEFF23, 0x00080002}, -{14800000, DIF_BPF_COEFF45, 0xffdf0019}, -{14800000, DIF_BPF_COEFF67, 0x003fff92}, -{14800000, DIF_BPF_COEFF89, 0xffd600f1}, -{14800000, DIF_BPF_COEFF1011, 0xff96feb6}, -{14800000, DIF_BPF_COEFF1213, 0x019700e1}, -{14800000, DIF_BPF_COEFF1415, 0xfd0500c2}, -{14800000, DIF_BPF_COEFF1617, 0x03b0fc84}, -{14800000, DIF_BPF_COEFF1819, 0xfd590649}, -{14800000, DIF_BPF_COEFF2021, 0xff5df87f}, -{14800000, DIF_BPF_COEFF2223, 0x058505aa}, -{14800000, DIF_BPF_COEFF2425, 0xf5e4ff91}, -{14800000, DIF_BPF_COEFF2627, 0x0bf9f93c}, -{14800000, DIF_BPF_COEFF2829, 0xf69d0d20}, -{14800000, DIF_BPF_COEFF3031, 0x0279f05e}, -{14800000, DIF_BPF_COEFF3233, 0x06880ca3}, -{14800000, DIF_BPF_COEFF3435, 0xf1e6fb28}, -{14800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 148_quant.dat*/ - - -/*case 14900000:*/ -/* BEGIN - DIF BPF register values from 149_quant.dat*/ -{14900000, DIF_BPF_COEFF01, 0x0000fffd}, -{14900000, DIF_BPF_COEFF23, 0x00060009}, -{14900000, DIF_BPF_COEFF45, 0xffdf0004}, -{14900000, DIF_BPF_COEFF67, 0x0051ffb0}, -{14900000, DIF_BPF_COEFF89, 0xff9d00e8}, -{14900000, DIF_BPF_COEFF1011, 0xfffcfe7c}, -{14900000, DIF_BPF_COEFF1213, 0x01280180}, -{14900000, DIF_BPF_COEFF1415, 0xfd32ffd2}, -{14900000, DIF_BPF_COEFF1617, 0x0413fd6e}, -{14900000, DIF_BPF_COEFF1819, 0xfc4d05df}, -{14900000, DIF_BPF_COEFF2021, 0x00d1f812}, -{14900000, DIF_BPF_COEFF2223, 0x043506e4}, -{14900000, DIF_BPF_COEFF2425, 0xf685fdfb}, -{14900000, DIF_BPF_COEFF2627, 0x0c43fa8d}, -{14900000, DIF_BPF_COEFF2829, 0xf5a10c83}, -{14900000, DIF_BPF_COEFF3031, 0x0399f046}, -{14900000, DIF_BPF_COEFF3233, 0x05c70d08}, -{14900000, DIF_BPF_COEFF3435, 0xf222faf3}, -{14900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 149_quant.dat*/ - - -/*case 15000000:*/ -/* BEGIN - DIF BPF register values from 150_quant.dat*/ -{15000000, DIF_BPF_COEFF01, 0x0000fffd}, -{15000000, DIF_BPF_COEFF23, 0x0003000f}, -{15000000, DIF_BPF_COEFF45, 0xffe5ffef}, -{15000000, DIF_BPF_COEFF67, 0x0057ffd9}, -{15000000, DIF_BPF_COEFF89, 0xff7000c4}, -{15000000, DIF_BPF_COEFF1011, 0x0062fe68}, -{15000000, DIF_BPF_COEFF1213, 0x009e01ff}, -{15000000, DIF_BPF_COEFF1415, 0xfd95fee6}, -{15000000, DIF_BPF_COEFF1617, 0x0435fe7d}, -{15000000, DIF_BPF_COEFF1819, 0xfb710530}, -{15000000, DIF_BPF_COEFF2021, 0x023cf7ee}, -{15000000, DIF_BPF_COEFF2223, 0x02c307ef}, -{15000000, DIF_BPF_COEFF2425, 0xf75efc70}, -{15000000, DIF_BPF_COEFF2627, 0x0c5cfbef}, -{15000000, DIF_BPF_COEFF2829, 0xf4c10bce}, -{15000000, DIF_BPF_COEFF3031, 0x04b3f03f}, -{15000000, DIF_BPF_COEFF3233, 0x05030d69}, -{15000000, DIF_BPF_COEFF3435, 0xf261fabf}, -{15000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 150_quant.dat*/ - - -/*case 15100000:*/ -/* BEGIN - DIF BPF register values from 151_quant.dat*/ -{15100000, DIF_BPF_COEFF01, 0x0000fffd}, -{15100000, DIF_BPF_COEFF23, 0xffff0012}, -{15100000, DIF_BPF_COEFF45, 0xffefffdc}, -{15100000, DIF_BPF_COEFF67, 0x00510006}, -{15100000, DIF_BPF_COEFF89, 0xff540089}, -{15100000, DIF_BPF_COEFF1011, 0x00befe7c}, -{15100000, DIF_BPF_COEFF1213, 0x00060253}, -{15100000, DIF_BPF_COEFF1415, 0xfe27fe0d}, -{15100000, DIF_BPF_COEFF1617, 0x0413ffa2}, -{15100000, DIF_BPF_COEFF1819, 0xfad10446}, -{15100000, DIF_BPF_COEFF2021, 0x0390f812}, -{15100000, DIF_BPF_COEFF2223, 0x013b08c3}, -{15100000, DIF_BPF_COEFF2425, 0xf868faf6}, -{15100000, DIF_BPF_COEFF2627, 0x0c43fd5f}, -{15100000, DIF_BPF_COEFF2829, 0xf3fd0b02}, -{15100000, DIF_BPF_COEFF3031, 0x05c7f046}, -{15100000, DIF_BPF_COEFF3233, 0x043b0dc4}, -{15100000, DIF_BPF_COEFF3435, 0xf2a1fa8b}, -{15100000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 151_quant.dat*/ - - -/*case 15200000:*/ -/* BEGIN - DIF BPF register values from 152_quant.dat*/ -{15200000, DIF_BPF_COEFF01, 0x0001fffe}, -{15200000, DIF_BPF_COEFF23, 0xfffc0012}, -{15200000, DIF_BPF_COEFF45, 0xfffbffce}, -{15200000, DIF_BPF_COEFF67, 0x003f0033}, -{15200000, DIF_BPF_COEFF89, 0xff4e003f}, -{15200000, DIF_BPF_COEFF1011, 0x0106feb6}, -{15200000, DIF_BPF_COEFF1213, 0xff6e0276}, -{15200000, DIF_BPF_COEFF1415, 0xfeddfd56}, -{15200000, DIF_BPF_COEFF1617, 0x03b000cc}, -{15200000, DIF_BPF_COEFF1819, 0xfa740329}, -{15200000, DIF_BPF_COEFF2021, 0x04bff87f}, -{15200000, DIF_BPF_COEFF2223, 0xffaa095d}, -{15200000, DIF_BPF_COEFF2425, 0xf99ef995}, -{15200000, DIF_BPF_COEFF2627, 0x0bf9fed8}, -{15200000, DIF_BPF_COEFF2829, 0xf3590a1f}, -{15200000, DIF_BPF_COEFF3031, 0x06d2f05e}, -{15200000, DIF_BPF_COEFF3233, 0x03700e1b}, -{15200000, DIF_BPF_COEFF3435, 0xf2e4fa58}, -{15200000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 152_quant.dat*/ - - -/*case 115300000:*/ -/* BEGIN - DIF BPF register values from 153_quant.dat*/ -{15300000, DIF_BPF_COEFF01, 0x0001ffff}, -{15300000, DIF_BPF_COEFF23, 0xfff9000f}, -{15300000, DIF_BPF_COEFF45, 0x0009ffc8}, -{15300000, DIF_BPF_COEFF67, 0x00250059}, -{15300000, DIF_BPF_COEFF89, 0xff5effee}, -{15300000, DIF_BPF_COEFF1011, 0x0132ff10}, -{15300000, DIF_BPF_COEFF1213, 0xfee30265}, -{15300000, DIF_BPF_COEFF1415, 0xffaafccf}, -{15300000, DIF_BPF_COEFF1617, 0x031101eb}, -{15300000, DIF_BPF_COEFF1819, 0xfa6001e8}, -{15300000, DIF_BPF_COEFF2021, 0x05bdf92f}, -{15300000, DIF_BPF_COEFF2223, 0xfe1b09b6}, -{15300000, DIF_BPF_COEFF2425, 0xfafaf852}, -{15300000, DIF_BPF_COEFF2627, 0x0b7e0055}, -{15300000, DIF_BPF_COEFF2829, 0xf2d50929}, -{15300000, DIF_BPF_COEFF3031, 0x07d3f086}, -{15300000, DIF_BPF_COEFF3233, 0x02a30e6c}, -{15300000, DIF_BPF_COEFF3435, 0xf329fa24}, -{15300000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 153_quant.dat*/ - - -/*case 115400000:*/ -/* BEGIN - DIF BPF register values from 154_quant.dat*/ -{15400000, DIF_BPF_COEFF01, 0x00010001}, -{15400000, DIF_BPF_COEFF23, 0xfff80009}, -{15400000, DIF_BPF_COEFF45, 0x0015ffca}, -{15400000, DIF_BPF_COEFF67, 0x00050074}, -{15400000, DIF_BPF_COEFF89, 0xff81ff9f}, -{15400000, DIF_BPF_COEFF1011, 0x013dff82}, -{15400000, DIF_BPF_COEFF1213, 0xfe710221}, -{15400000, DIF_BPF_COEFF1415, 0x007cfc80}, -{15400000, DIF_BPF_COEFF1617, 0x024102ed}, -{15400000, DIF_BPF_COEFF1819, 0xfa940090}, -{15400000, DIF_BPF_COEFF2021, 0x0680fa1e}, -{15400000, DIF_BPF_COEFF2223, 0xfc9b09cd}, -{15400000, DIF_BPF_COEFF2425, 0xfc73f736}, -{15400000, DIF_BPF_COEFF2627, 0x0ad501d0}, -{15400000, DIF_BPF_COEFF2829, 0xf2740820}, -{15400000, DIF_BPF_COEFF3031, 0x08c9f0bd}, -{15400000, DIF_BPF_COEFF3233, 0x01d40eb9}, -{15400000, DIF_BPF_COEFF3435, 0xf371f9f1}, -{15400000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 154_quant.dat*/ - - -/*case 115500000:*/ -/* BEGIN - DIF BPF register values from 155_quant.dat*/ -{15500000, DIF_BPF_COEFF01, 0x00000002}, -{15500000, DIF_BPF_COEFF23, 0xfff80002}, -{15500000, DIF_BPF_COEFF45, 0x001effd5}, -{15500000, DIF_BPF_COEFF67, 0xffe5007f}, -{15500000, DIF_BPF_COEFF89, 0xffb4ff5b}, -{15500000, DIF_BPF_COEFF1011, 0x01280000}, -{15500000, DIF_BPF_COEFF1213, 0xfe2401b0}, -{15500000, DIF_BPF_COEFF1415, 0x0146fc70}, -{15500000, DIF_BPF_COEFF1617, 0x014d03c6}, -{15500000, DIF_BPF_COEFF1819, 0xfb10ff32}, -{15500000, DIF_BPF_COEFF2021, 0x0701fb41}, -{15500000, DIF_BPF_COEFF2223, 0xfb3709a1}, -{15500000, DIF_BPF_COEFF2425, 0xfe00f644}, -{15500000, DIF_BPF_COEFF2627, 0x0a000345}, -{15500000, DIF_BPF_COEFF2829, 0xf2350708}, -{15500000, DIF_BPF_COEFF3031, 0x09b2f104}, -{15500000, DIF_BPF_COEFF3233, 0x01050eff}, -{15500000, DIF_BPF_COEFF3435, 0xf3baf9be}, -{15500000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 155_quant.dat*/ - - -/*case 115600000:*/ -/* BEGIN - DIF BPF register values from 156_quant.dat*/ -{15600000, DIF_BPF_COEFF01, 0x00000003}, -{15600000, DIF_BPF_COEFF23, 0xfff9fffb}, -{15600000, DIF_BPF_COEFF45, 0x0022ffe6}, -{15600000, DIF_BPF_COEFF67, 0xffc9007a}, -{15600000, DIF_BPF_COEFF89, 0xfff0ff29}, -{15600000, DIF_BPF_COEFF1011, 0x00f2007e}, -{15600000, DIF_BPF_COEFF1213, 0xfe01011b}, -{15600000, DIF_BPF_COEFF1415, 0x01f6fc9e}, -{15600000, DIF_BPF_COEFF1617, 0x00440467}, -{15600000, DIF_BPF_COEFF1819, 0xfbccfdde}, -{15600000, DIF_BPF_COEFF2021, 0x0738fc90}, -{15600000, DIF_BPF_COEFF2223, 0xf9f70934}, -{15600000, DIF_BPF_COEFF2425, 0xff99f582}, -{15600000, DIF_BPF_COEFF2627, 0x090204b0}, -{15600000, DIF_BPF_COEFF2829, 0xf21a05e1}, -{15600000, DIF_BPF_COEFF3031, 0x0a8df15a}, -{15600000, DIF_BPF_COEFF3233, 0x00340f41}, -{15600000, DIF_BPF_COEFF3435, 0xf405f98b}, -{15600000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 156_quant.dat*/ - - -/*case 115700000:*/ -/* BEGIN - DIF BPF register values from 157_quant.dat*/ -{15700000, DIF_BPF_COEFF01, 0x00000003}, -{15700000, DIF_BPF_COEFF23, 0xfffcfff4}, -{15700000, DIF_BPF_COEFF45, 0x0020fffa}, -{15700000, DIF_BPF_COEFF67, 0xffb40064}, -{15700000, DIF_BPF_COEFF89, 0x002fff11}, -{15700000, DIF_BPF_COEFF1011, 0x00a400f0}, -{15700000, DIF_BPF_COEFF1213, 0xfe0d006e}, -{15700000, DIF_BPF_COEFF1415, 0x0281fd09}, -{15700000, DIF_BPF_COEFF1617, 0xff3604c9}, -{15700000, DIF_BPF_COEFF1819, 0xfcbffca2}, -{15700000, DIF_BPF_COEFF2021, 0x0726fdfe}, -{15700000, DIF_BPF_COEFF2223, 0xf8e80888}, -{15700000, DIF_BPF_COEFF2425, 0x0134f4f3}, -{15700000, DIF_BPF_COEFF2627, 0x07e1060c}, -{15700000, DIF_BPF_COEFF2829, 0xf22304af}, -{15700000, DIF_BPF_COEFF3031, 0x0b59f1be}, -{15700000, DIF_BPF_COEFF3233, 0xff640f7d}, -{15700000, DIF_BPF_COEFF3435, 0xf452f959}, -{15700000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 157_quant.dat*/ - - -/*case 115800000:*/ -/* BEGIN - DIF BPF register values from 158_quant.dat*/ -{15800000, DIF_BPF_COEFF01, 0x00000003}, -{15800000, DIF_BPF_COEFF23, 0x0000fff0}, -{15800000, DIF_BPF_COEFF45, 0x001a0010}, -{15800000, DIF_BPF_COEFF67, 0xffaa0041}, -{15800000, DIF_BPF_COEFF89, 0x0067ff13}, -{15800000, DIF_BPF_COEFF1011, 0x0043014a}, -{15800000, DIF_BPF_COEFF1213, 0xfe46ffb9}, -{15800000, DIF_BPF_COEFF1415, 0x02dbfda8}, -{15800000, DIF_BPF_COEFF1617, 0xfe3504e5}, -{15800000, DIF_BPF_COEFF1819, 0xfddcfb8d}, -{15800000, DIF_BPF_COEFF2021, 0x06c9ff7e}, -{15800000, DIF_BPF_COEFF2223, 0xf81107a2}, -{15800000, DIF_BPF_COEFF2425, 0x02c9f49a}, -{15800000, DIF_BPF_COEFF2627, 0x069f0753}, -{15800000, DIF_BPF_COEFF2829, 0xf2500373}, -{15800000, DIF_BPF_COEFF3031, 0x0c14f231}, -{15800000, DIF_BPF_COEFF3233, 0xfe930fb3}, -{15800000, DIF_BPF_COEFF3435, 0xf4a1f927}, -{15800000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 158_quant.dat*/ - - -/*case 115900000:*/ -/* BEGIN - DIF BPF register values from 159_quant.dat*/ -{15900000, DIF_BPF_COEFF01, 0xffff0002}, -{15900000, DIF_BPF_COEFF23, 0x0003ffee}, -{15900000, DIF_BPF_COEFF45, 0x000f0023}, -{15900000, DIF_BPF_COEFF67, 0xffac0016}, -{15900000, DIF_BPF_COEFF89, 0x0093ff31}, -{15900000, DIF_BPF_COEFF1011, 0xffdc0184}, -{15900000, DIF_BPF_COEFF1213, 0xfea6ff09}, -{15900000, DIF_BPF_COEFF1415, 0x02fdfe70}, -{15900000, DIF_BPF_COEFF1617, 0xfd5104ba}, -{15900000, DIF_BPF_COEFF1819, 0xff15faac}, -{15900000, DIF_BPF_COEFF2021, 0x06270103}, -{15900000, DIF_BPF_COEFF2223, 0xf7780688}, -{15900000, DIF_BPF_COEFF2425, 0x044df479}, -{15900000, DIF_BPF_COEFF2627, 0x05430883}, -{15900000, DIF_BPF_COEFF2829, 0xf2a00231}, -{15900000, DIF_BPF_COEFF3031, 0x0cbef2b2}, -{15900000, DIF_BPF_COEFF3233, 0xfdc40fe3}, -{15900000, DIF_BPF_COEFF3435, 0xf4f2f8f5}, -{15900000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 159_quant.dat*/ - - -/*case 116000000:*/ -/* BEGIN - DIF BPF register values from 160_quant.dat*/ -{16000000, DIF_BPF_COEFF01, 0xffff0001}, -{16000000, DIF_BPF_COEFF23, 0x0006ffef}, -{16000000, DIF_BPF_COEFF45, 0x00020031}, -{16000000, DIF_BPF_COEFF67, 0xffbaffe8}, -{16000000, DIF_BPF_COEFF89, 0x00adff66}, -{16000000, DIF_BPF_COEFF1011, 0xff790198}, -{16000000, DIF_BPF_COEFF1213, 0xff26fe6e}, -{16000000, DIF_BPF_COEFF1415, 0x02e5ff55}, -{16000000, DIF_BPF_COEFF1617, 0xfc99044a}, -{16000000, DIF_BPF_COEFF1819, 0x005bfa09}, -{16000000, DIF_BPF_COEFF2021, 0x0545027f}, -{16000000, DIF_BPF_COEFF2223, 0xf7230541}, -{16000000, DIF_BPF_COEFF2425, 0x05b8f490}, -{16000000, DIF_BPF_COEFF2627, 0x03d20997}, -{16000000, DIF_BPF_COEFF2829, 0xf31300eb}, -{16000000, DIF_BPF_COEFF3031, 0x0d55f341}, -{16000000, DIF_BPF_COEFF3233, 0xfcf6100e}, -{16000000, DIF_BPF_COEFF3435, 0xf544f8c3}, -{16000000, DIF_BPF_COEFF36, 0x110d0000}, -/* END - DIF BPF register values from 160_quant.dat*/ -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-dvb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,795 +0,0 @@ -/* - DVB device driver for cx231xx - - Copyright (C) 2008 - Based on em28xx driver - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include - -#include "cx231xx.h" -#include -#include - -#include "xc5000.h" -#include "s5h1432.h" -#include "tda18271.h" -#include "s5h1411.h" -#include "lgdt3305.h" -#include "mb86a20s.h" - -MODULE_DESCRIPTION("driver for cx231xx based DVB cards"); -MODULE_AUTHOR("Srinivasa Deevi "); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages [dvb]"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk(level, fmt, arg...) do { \ -if (debug >= level) \ - printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ -} while (0) - -#define CX231XX_DVB_NUM_BUFS 5 -#define CX231XX_DVB_MAX_PACKETSIZE 564 -#define CX231XX_DVB_MAX_PACKETS 64 - -struct cx231xx_dvb { - struct dvb_frontend *frontend; - - /* feed count management */ - struct mutex lock; - int nfeeds; - - /* general boilerplate stuff */ - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net net; -}; - -static struct s5h1432_config dvico_s5h1432_config = { - .output_mode = S5H1432_SERIAL_OUTPUT, - .gpio = S5H1432_GPIO_ON, - .qam_if = S5H1432_IF_4000, - .vsb_if = S5H1432_IF_4000, - .inversion = S5H1432_INVERSION_OFF, - .status_mode = S5H1432_DEMODLOCKING, - .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = { - .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, - .dvbt_7 = { .if_freq = 4000, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, - .dvbt_8 = { .if_freq = 4000, .agc_mode = 3, .std = 6, - .if_lvl = 1, .rfagc_top = 0x37, }, -}; - -static struct tda18271_std_map mb86a20s_tda18271_config = { - .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, - .if_lvl = 7, .rfagc_top = 0x37, }, -}; - -static struct tda18271_config cnxt_rde253s_tunerconfig = { - .std_map = &cnxt_rde253s_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, -}; - -static struct s5h1411_config tda18271_s5h1411_config = { - .output_mode = S5H1411_SERIAL_OUTPUT, - .gpio = S5H1411_GPIO_OFF, - .vsb_if = S5H1411_IF_3250, - .qam_if = S5H1411_IF_4000, - .inversion = S5H1411_INVERSION_ON, - .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; -static struct s5h1411_config xc5000_s5h1411_config = { - .output_mode = S5H1411_SERIAL_OUTPUT, - .gpio = S5H1411_GPIO_OFF, - .vsb_if = S5H1411_IF_3250, - .qam_if = S5H1411_IF_3250, - .inversion = S5H1411_INVERSION_OFF, - .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct lgdt3305_config hcw_lgdt3305_config = { - .i2c_addr = 0x0e, - .mpeg_mode = LGDT3305_MPEG_SERIAL, - .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, - .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, - .deny_i2c_rptr = 1, - .spectral_inversion = 1, - .qam_if_khz = 4000, - .vsb_if_khz = 3250, -}; - -static struct tda18271_std_map hauppauge_tda18271_std_map = { - .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x58, }, - .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x58, }, -}; - -static struct tda18271_config hcw_tda18271_config = { - .std_map = &hauppauge_tda18271_std_map, - .gate = TDA18271_GATE_DIGITAL, -}; - -static const struct mb86a20s_config pv_mb86a20s_config = { - .demod_address = 0x10, - .is_serial = true, -}; - -static struct tda18271_config pv_tda18271_config = { - .std_map = &mb86a20s_tda18271_config, - .gate = TDA18271_GATE_DIGITAL, - .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, -}; - -static inline void print_err_status(struct cx231xx *dev, int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - dprintk(1, "URB status %d [%s].\n", status, errmsg); - } else { - dprintk(1, "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb) -{ - int i; - - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - if (urb->iso_frame_desc[i].status != -EPROTO) - continue; - } - - dvb_dmx_swfilter(&dev->dvb->demux, - urb->transfer_buffer + - urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - } - - return 0; -} - -static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb) -{ - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - /* Feed the transport payload into the kernel demux */ - dvb_dmx_swfilter(&dev->dvb->demux, - urb->transfer_buffer, urb->actual_length); - - return 0; -} - -static int start_streaming(struct cx231xx_dvb *dvb) -{ - int rc; - struct cx231xx *dev = dvb->adapter.priv; - - if (dev->USE_ISO) { - cx231xx_info("DVB transfer mode is ISO.\n"); - mutex_lock(&dev->i2c_lock); - cx231xx_enable_i2c_port_3(dev, false); - cx231xx_set_alt_setting(dev, INDEX_TS1, 4); - cx231xx_enable_i2c_port_3(dev, true); - mutex_unlock(&dev->i2c_lock); - rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); - if (rc < 0) - return rc; - dev->mode_tv = 1; - return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS, - CX231XX_DVB_NUM_BUFS, - dev->ts1_mode.max_pkt_size, - dvb_isoc_copy); - } else { - cx231xx_info("DVB transfer mode is BULK.\n"); - cx231xx_set_alt_setting(dev, INDEX_TS1, 0); - rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); - if (rc < 0) - return rc; - dev->mode_tv = 1; - return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS, - CX231XX_DVB_NUM_BUFS, - dev->ts1_mode.max_pkt_size, - dvb_bulk_copy); - } - -} - -static int stop_streaming(struct cx231xx_dvb *dvb) -{ - struct cx231xx *dev = dvb->adapter.priv; - - if (dev->USE_ISO) - cx231xx_uninit_isoc(dev); - else - cx231xx_uninit_bulk(dev); - - cx231xx_set_mode(dev, CX231XX_SUSPEND); - - return 0; -} - -static int start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct cx231xx_dvb *dvb = demux->priv; - int rc, ret; - - if (!demux->dmx.frontend) - return -EINVAL; - - mutex_lock(&dvb->lock); - dvb->nfeeds++; - rc = dvb->nfeeds; - - if (dvb->nfeeds == 1) { - ret = start_streaming(dvb); - if (ret < 0) - rc = ret; - } - - mutex_unlock(&dvb->lock); - return rc; -} - -static int stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct cx231xx_dvb *dvb = demux->priv; - int err = 0; - - mutex_lock(&dvb->lock); - dvb->nfeeds--; - - if (0 == dvb->nfeeds) - err = stop_streaming(dvb); - - mutex_unlock(&dvb->lock); - return err; -} - -/* ------------------------------------------------------------------ */ -static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct cx231xx *dev = fe->dvb->priv; - - if (acquire) - return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); - else - return cx231xx_set_mode(dev, CX231XX_SUSPEND); -} - -/* ------------------------------------------------------------------ */ - -static struct xc5000_config cnxt_rde250_tunerconfig = { - .i2c_address = 0x61, - .if_khz = 4000, -}; -static struct xc5000_config cnxt_rdu250_tunerconfig = { - .i2c_address = 0x61, - .if_khz = 3250, -}; - -/* ------------------------------------------------------------------ */ -#if 0 -static int attach_xc5000(u8 addr, struct cx231xx *dev) -{ - - struct dvb_frontend *fe; - struct xc5000_config cfg; - - memset(&cfg, 0, sizeof(cfg)); - cfg.i2c_adap = &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap; - cfg.i2c_addr = addr; - - if (!dev->dvb->frontend) { - printk(KERN_ERR "%s/2: dvb frontend not attached. " - "Can't attach xc5000\n", dev->name); - return -EINVAL; - } - - fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg); - if (!fe) { - printk(KERN_ERR "%s/2: xc5000 attach failed\n", dev->name); - dvb_frontend_detach(dev->dvb->frontend); - dev->dvb->frontend = NULL; - return -EINVAL; - } - - printk(KERN_INFO "%s/2: xc5000 attached\n", dev->name); - - return 0; -} -#endif - -int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) -{ - int status = 0; - - if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { - - struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; - - if (dops->set_analog_params != NULL) { - struct analog_parameters params; - - params.frequency = freq; - params.std = dev->norm; - params.mode = 0; /* 0- Air; 1 - cable */ - /*params.audmode = ; */ - - /* Set the analog parameters to set the frequency */ - dops->set_analog_params(dev->dvb->frontend, ¶ms); - } - - } - - return status; -} - -int cx231xx_reset_analog_tuner(struct cx231xx *dev) -{ - int status = 0; - - if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { - - struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; - - if (dops->init != NULL && !dev->xc_fw_load_done) { - - cx231xx_info("Reloading firmware for XC5000\n"); - status = dops->init(dev->dvb->frontend); - if (status == 0) { - dev->xc_fw_load_done = 1; - cx231xx_info - ("XC5000 firmware download completed\n"); - } else { - dev->xc_fw_load_done = 0; - cx231xx_info - ("XC5000 firmware download failed !!!\n"); - } - } - - } - - return status; -} - -/* ------------------------------------------------------------------ */ - -static int register_dvb(struct cx231xx_dvb *dvb, - struct module *module, - struct cx231xx *dev, struct device *device) -{ - int result; - - mutex_init(&dvb->lock); - - /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, - adapter_nr); - if (result < 0) { - printk(KERN_WARNING - "%s: dvb_register_adapter failed (errno = %d)\n", - dev->name, result); - goto fail_adapter; - } - - /* Ensure all frontends negotiate bus access */ - dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; - - dvb->adapter.priv = dev; - - /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (result < 0) { - printk(KERN_WARNING - "%s: dvb_register_frontend failed (errno = %d)\n", - dev->name, result); - goto fail_frontend; - } - - /* register demux stuff */ - dvb->demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dvb; - dvb->demux.filternum = 256; - dvb->demux.feednum = 256; - dvb->demux.start_feed = start_feed; - dvb->demux.stop_feed = stop_feed; - - result = dvb_dmx_init(&dvb->demux); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", - dev->name, result); - goto fail_dmx; - } - - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = &dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", - dev->name, result); - goto fail_dmxdev; - } - - dvb->fe_hw.source = DMX_FRONTEND_0; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING - "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", - dev->name, result); - goto fail_fe_hw; - } - - dvb->fe_mem.source = DMX_MEMORY_FE; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); - if (result < 0) { - printk(KERN_WARNING - "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", - dev->name, result); - goto fail_fe_mem; - } - - result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING - "%s: connect_frontend failed (errno = %d)\n", dev->name, - result); - goto fail_fe_conn; - } - - /* register network adapter */ - dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); - return 0; - -fail_fe_conn: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); -fail_fe_mem: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); -fail_fe_hw: - dvb_dmxdev_release(&dvb->dmxdev); -fail_dmxdev: - dvb_dmx_release(&dvb->demux); -fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -fail_adapter: - return result; -} - -static void unregister_dvb(struct cx231xx_dvb *dvb) -{ - dvb_net_release(&dvb->net); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -} - -static int dvb_init(struct cx231xx *dev) -{ - int result = 0; - struct cx231xx_dvb *dvb; - - if (!dev->board.has_dvb) { - /* This device does not support the extension */ - return 0; - } - - dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL); - - if (dvb == NULL) { - printk(KERN_INFO "cx231xx_dvb: memory allocation failed\n"); - return -ENOMEM; - } - dev->dvb = dvb; - dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq; - dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner; - - mutex_lock(&dev->lock); - cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); - cx231xx_demod_reset(dev); - /* init frontend */ - switch (dev->model) { - case CX231XX_BOARD_CNXT_CARRAERA: - case CX231XX_BOARD_CNXT_RDE_250: - - dev->dvb->frontend = dvb_attach(s5h1432_attach, - &dvico_s5h1432_config, - &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); - - if (dev->dvb->frontend == NULL) { - printk(DRIVER_NAME - ": Failed to attach s5h1432 front end\n"); - result = -EINVAL; - goto out_free; - } - - /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; - - if (!dvb_attach(xc5000_attach, dev->dvb->frontend, - &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, - &cnxt_rde250_tunerconfig)) { - result = -EINVAL; - goto out_free; - } - - break; - case CX231XX_BOARD_CNXT_SHELBY: - case CX231XX_BOARD_CNXT_RDU_250: - - dev->dvb->frontend = dvb_attach(s5h1411_attach, - &xc5000_s5h1411_config, - &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); - - if (dev->dvb->frontend == NULL) { - printk(DRIVER_NAME - ": Failed to attach s5h1411 front end\n"); - result = -EINVAL; - goto out_free; - } - - /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; - - if (!dvb_attach(xc5000_attach, dev->dvb->frontend, - &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, - &cnxt_rdu250_tunerconfig)) { - result = -EINVAL; - goto out_free; - } - break; - case CX231XX_BOARD_CNXT_RDE_253S: - - dev->dvb->frontend = dvb_attach(s5h1432_attach, - &dvico_s5h1432_config, - &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); - - if (dev->dvb->frontend == NULL) { - printk(DRIVER_NAME - ": Failed to attach s5h1432 front end\n"); - result = -EINVAL; - goto out_free; - } - - /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; - - if (!dvb_attach(tda18271_attach, dev->dvb->frontend, - 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, - &cnxt_rde253s_tunerconfig)) { - result = -EINVAL; - goto out_free; - } - break; - case CX231XX_BOARD_CNXT_RDU_253S: - - dev->dvb->frontend = dvb_attach(s5h1411_attach, - &tda18271_s5h1411_config, - &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); - - if (dev->dvb->frontend == NULL) { - printk(DRIVER_NAME - ": Failed to attach s5h1411 front end\n"); - result = -EINVAL; - goto out_free; - } - - /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; - - if (!dvb_attach(tda18271_attach, dev->dvb->frontend, - 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, - &cnxt_rde253s_tunerconfig)) { - result = -EINVAL; - goto out_free; - } - break; - case CX231XX_BOARD_HAUPPAUGE_EXETER: - - printk(KERN_INFO "%s: looking for tuner / demod on i2c bus: %d\n", - __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap)); - - dev->dvb->frontend = dvb_attach(lgdt3305_attach, - &hcw_lgdt3305_config, - &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap); - - if (dev->dvb->frontend == NULL) { - printk(DRIVER_NAME - ": Failed to attach LG3305 front end\n"); - result = -EINVAL; - goto out_free; - } - - /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; - - dvb_attach(tda18271_attach, dev->dvb->frontend, - 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, - &hcw_tda18271_config); - break; - - case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: - - printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n", - __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap)); - - dev->dvb->frontend = dvb_attach(mb86a20s_attach, - &pv_mb86a20s_config, - &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); - - if (dev->dvb->frontend == NULL) { - printk(DRIVER_NAME - ": Failed to attach mb86a20s demod\n"); - result = -EINVAL; - goto out_free; - } - - /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; - - dvb_attach(tda18271_attach, dev->dvb->frontend, - 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, - &pv_tda18271_config); - break; - - default: - printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" - " isn't supported yet\n", dev->name); - break; - } - if (NULL == dvb->frontend) { - printk(KERN_ERR - "%s/2: frontend initialization failed\n", dev->name); - result = -EINVAL; - goto out_free; - } - - /* register everything */ - result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); - - if (result < 0) - goto out_free; - - - printk(KERN_INFO "Successfully loaded cx231xx-dvb\n"); - -ret: - cx231xx_set_mode(dev, CX231XX_SUSPEND); - mutex_unlock(&dev->lock); - return result; - -out_free: - kfree(dvb); - dev->dvb = NULL; - goto ret; -} - -static int dvb_fini(struct cx231xx *dev) -{ - if (!dev->board.has_dvb) { - /* This device does not support the extension */ - return 0; - } - - if (dev->dvb) { - unregister_dvb(dev->dvb); - dev->dvb = NULL; - } - - return 0; -} - -static struct cx231xx_ops dvb_ops = { - .id = CX231XX_DVB, - .name = "Cx231xx dvb Extension", - .init = dvb_init, - .fini = dvb_fini, -}; - -static int __init cx231xx_dvb_register(void) -{ - return cx231xx_register_extension(&dvb_ops); -} - -static void __exit cx231xx_dvb_unregister(void) -{ - cx231xx_unregister_extension(&dvb_ops); -} - -module_init(cx231xx_dvb_register); -module_exit(cx231xx_dvb_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1011 +0,0 @@ -/* - cx231xx.h - driver for Conexant Cx23100/101/102 USB video capture devices - - Copyright (C) 2008 - Based on em28xx driver - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _CX231XX_H -#define _CX231XX_H - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include "cx231xx-reg.h" -#include "cx231xx-pcb-cfg.h" -#include "cx231xx-conf-reg.h" - -#define DRIVER_NAME "cx231xx" -#define PWR_SLEEP_INTERVAL 5 - -/* I2C addresses for control block in Cx231xx */ -#define AFE_DEVICE_ADDRESS 0x60 -#define I2S_BLK_DEVICE_ADDRESS 0x98 -#define VID_BLK_I2C_ADDRESS 0x88 -#define VERVE_I2C_ADDRESS 0x40 -#define DIF_USE_BASEBAND 0xFFFFFFFF - -/* Boards supported by driver */ -#define CX231XX_BOARD_UNKNOWN 0 -#define CX231XX_BOARD_CNXT_CARRAERA 1 -#define CX231XX_BOARD_CNXT_SHELBY 2 -#define CX231XX_BOARD_CNXT_RDE_253S 3 -#define CX231XX_BOARD_CNXT_RDU_253S 4 -#define CX231XX_BOARD_CNXT_VIDEO_GRABBER 5 -#define CX231XX_BOARD_CNXT_RDE_250 6 -#define CX231XX_BOARD_CNXT_RDU_250 7 -#define CX231XX_BOARD_HAUPPAUGE_EXETER 8 -#define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9 -#define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10 -#define CX231XX_BOARD_PV_XCAPTURE_USB 11 - -/* Limits minimum and default number of buffers */ -#define CX231XX_MIN_BUF 4 -#define CX231XX_DEF_BUF 12 -#define CX231XX_DEF_VBI_BUF 6 - -#define VBI_LINE_COUNT 17 -#define VBI_LINE_LENGTH 1440 - -/*Limits the max URB message size */ -#define URB_MAX_CTRL_SIZE 80 - -/* Params for validated field */ -#define CX231XX_BOARD_NOT_VALIDATED 1 -#define CX231XX_BOARD_VALIDATED 0 - -/* maximum number of cx231xx boards */ -#define CX231XX_MAXBOARDS 8 - -/* maximum number of frames that can be queued */ -#define CX231XX_NUM_FRAMES 5 - -/* number of buffers for isoc transfers */ -#define CX231XX_NUM_BUFS 8 - -/* number of packets for each buffer - windows requests only 40 packets .. so we better do the same - this is what I found out for all alternate numbers there! - */ -#define CX231XX_NUM_PACKETS 40 - -/* default alternate; 0 means choose the best */ -#define CX231XX_PINOUT 0 - -#define CX231XX_INTERLACED_DEFAULT 1 - -/* time to wait when stopping the isoc transfer */ -#define CX231XX_URB_TIMEOUT \ - msecs_to_jiffies(CX231XX_NUM_BUFS * CX231XX_NUM_PACKETS) - -#define CX231xx_NORMS (\ - V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \ - V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ - V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ - V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) -#define CX231xx_VERSION_CODE KERNEL_VERSION(0, 0, 2) - -#define SLEEP_S5H1432 30 -#define CX23417_OSC_EN 8 -#define CX23417_RESET 9 - -struct cx23417_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int flags; - u32 cxformat; -}; -enum cx231xx_mode { - CX231XX_SUSPEND, - CX231XX_ANALOG_MODE, - CX231XX_DIGITAL_MODE, -}; - -enum cx231xx_std_mode { - CX231XX_TV_AIR = 0, - CX231XX_TV_CABLE -}; - -enum cx231xx_stream_state { - STREAM_OFF, - STREAM_INTERRUPT, - STREAM_ON, -}; - -struct cx231xx; - -struct cx231xx_isoc_ctl { - /* max packet size of isoc transaction */ - int max_pkt_size; - - /* number of allocated urbs */ - int num_bufs; - - /* urb for isoc transfers */ - struct urb **urb; - - /* transfer buffers for isoc transfer */ - char **transfer_buffer; - - /* Last buffer command and region */ - u8 cmd; - int pos, size, pktsize; - - /* Last field: ODD or EVEN? */ - int field; - - /* Stores incomplete commands */ - u32 tmp_buf; - int tmp_buf_len; - - /* Stores already requested buffers */ - struct cx231xx_buffer *buf; - - /* Stores the number of received fields */ - int nfields; - - /* isoc urb callback */ - int (*isoc_copy) (struct cx231xx *dev, struct urb *urb); -}; - -struct cx231xx_bulk_ctl { - /* max packet size of bulk transaction */ - int max_pkt_size; - - /* number of allocated urbs */ - int num_bufs; - - /* urb for bulk transfers */ - struct urb **urb; - - /* transfer buffers for bulk transfer */ - char **transfer_buffer; - - /* Last buffer command and region */ - u8 cmd; - int pos, size, pktsize; - - /* Last field: ODD or EVEN? */ - int field; - - /* Stores incomplete commands */ - u32 tmp_buf; - int tmp_buf_len; - - /* Stores already requested buffers */ - struct cx231xx_buffer *buf; - - /* Stores the number of received fields */ - int nfields; - - /* bulk urb callback */ - int (*bulk_copy) (struct cx231xx *dev, struct urb *urb); -}; - -struct cx231xx_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int reg; -}; - -/* buffer for one video frame */ -struct cx231xx_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - struct list_head frame; - int top_field; - int receiving; -}; - -enum ps_package_head { - CX231XX_NEED_ADD_PS_PACKAGE_HEAD = 0, - CX231XX_NONEED_PS_PACKAGE_HEAD -}; - -struct cx231xx_dmaqueue { - struct list_head active; - struct list_head queued; - - wait_queue_head_t wq; - - /* Counters to control buffer fill */ - int pos; - u8 is_partial_line; - u8 partial_buf[8]; - u8 last_sav; - int current_field; - u32 bytes_left_in_line; - u32 lines_completed; - u8 field1_done; - u32 lines_per_field; - - /*Mpeg2 control buffer*/ - u8 *p_left_data; - u32 left_data_count; - u8 mpeg_buffer_done; - u32 mpeg_buffer_completed; - enum ps_package_head add_ps_package_head; - char ps_head[10]; -}; - -/* inputs */ - -#define MAX_CX231XX_INPUT 4 - -enum cx231xx_itype { - CX231XX_VMUX_COMPOSITE1 = 1, - CX231XX_VMUX_SVIDEO, - CX231XX_VMUX_TELEVISION, - CX231XX_VMUX_CABLE, - CX231XX_RADIO, - CX231XX_VMUX_DVB, - CX231XX_VMUX_DEBUG -}; - -enum cx231xx_v_input { - CX231XX_VIN_1_1 = 0x1, - CX231XX_VIN_2_1, - CX231XX_VIN_3_1, - CX231XX_VIN_4_1, - CX231XX_VIN_1_2 = 0x01, - CX231XX_VIN_2_2, - CX231XX_VIN_3_2, - CX231XX_VIN_1_3 = 0x1, - CX231XX_VIN_2_3, - CX231XX_VIN_3_3, -}; - -/* cx231xx has two audio inputs: tuner and line in */ -enum cx231xx_amux { - /* This is the only entry for cx231xx tuner input */ - CX231XX_AMUX_VIDEO, /* cx231xx tuner */ - CX231XX_AMUX_LINE_IN, /* Line In */ -}; - -struct cx231xx_reg_seq { - unsigned char bit; - unsigned char val; - int sleep; -}; - -struct cx231xx_input { - enum cx231xx_itype type; - unsigned int vmux; - enum cx231xx_amux amux; - struct cx231xx_reg_seq *gpio; -}; - -#define INPUT(nr) (&cx231xx_boards[dev->model].input[nr]) - -enum cx231xx_decoder { - CX231XX_NODECODER, - CX231XX_AVDECODER -}; - -enum CX231XX_I2C_MASTER_PORT { - I2C_0 = 0, - I2C_1 = 1, - I2C_2 = 2, - I2C_3 = 3 -}; - -struct cx231xx_board { - char *name; - int vchannels; - int tuner_type; - int tuner_addr; - v4l2_std_id norm; /* tv norm */ - - /* demod related */ - int demod_addr; - u8 demod_xfer_mode; /* 0 - Serial; 1 - parallel */ - - /* GPIO Pins */ - struct cx231xx_reg_seq *dvb_gpio; - struct cx231xx_reg_seq *suspend_gpio; - struct cx231xx_reg_seq *tuner_gpio; - /* Negative means don't use it */ - s8 tuner_sif_gpio; - s8 tuner_scl_gpio; - s8 tuner_sda_gpio; - - /* PIN ctrl */ - u32 ctl_pin_status_mask; - u8 agc_analog_digital_select_gpio; - u32 gpio_pin_status_mask; - - /* i2c masters */ - u8 tuner_i2c_master; - u8 demod_i2c_master; - u8 ir_i2c_master; - - /* for devices with I2C chips for IR */ - char *rc_map_name; - - unsigned int max_range_640_480:1; - unsigned int has_dvb:1; - unsigned int has_417:1; - unsigned int valid:1; - unsigned int no_alt_vanc:1; - unsigned int external_av:1; - unsigned int dont_use_port_3:1; - - unsigned char xclk, i2c_speed; - - enum cx231xx_decoder decoder; - int output_mode; - - struct cx231xx_input input[MAX_CX231XX_INPUT]; - struct cx231xx_input radio; - struct rc_map *ir_codes; -}; - -/* device states */ -enum cx231xx_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -enum AFE_MODE { - AFE_MODE_LOW_IF, - AFE_MODE_BASEBAND, - AFE_MODE_EU_HI_IF, - AFE_MODE_US_HI_IF, - AFE_MODE_JAPAN_HI_IF -}; - -enum AUDIO_INPUT { - AUDIO_INPUT_MUTE, - AUDIO_INPUT_LINE, - AUDIO_INPUT_TUNER_TV, - AUDIO_INPUT_SPDIF, - AUDIO_INPUT_TUNER_FM -}; - -#define CX231XX_AUDIO_BUFS 5 -#define CX231XX_NUM_AUDIO_PACKETS 16 -#define CX231XX_ISO_NUM_AUDIO_PACKETS 64 - -/* cx231xx extensions */ -#define CX231XX_AUDIO 0x10 -#define CX231XX_DVB 0x20 - -struct cx231xx_audio { - char name[50]; - char *transfer_buffer[CX231XX_AUDIO_BUFS]; - struct urb *urb[CX231XX_AUDIO_BUFS]; - struct usb_device *udev; - unsigned int capture_transfer_done; - struct snd_pcm_substream *capture_pcm_substream; - - unsigned int hwptr_done_capture; - struct snd_card *sndcard; - - int users, shutdown; - /* locks */ - spinlock_t slock; - - int alt; /* alternate */ - int max_pkt_size; /* max packet size of isoc transaction */ - int num_alt; /* Number of alternative settings */ - unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ - u16 end_point_addr; -}; - -struct cx231xx; - -struct cx231xx_fh { - struct cx231xx *dev; - unsigned int stream_on:1; /* Locks streams */ - int radio; - - struct videobuf_queue vb_vidq; - - enum v4l2_buf_type type; - - - -/*following is copyed from cx23885.h*/ - u32 resources; - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - - /* video capture */ - struct cx23417_fmt *fmt; - unsigned int width, height; - - /* vbi capture */ - struct videobuf_queue vidq; - struct videobuf_queue vbiq; - - /* MPEG Encoder specifics ONLY */ - - atomic_t v4l_reading; -}; - -/*****************************************************************/ -/* set/get i2c */ -/* 00--1Mb/s, 01-400kb/s, 10--100kb/s, 11--5Mb/s */ -#define I2C_SPEED_1M 0x0 -#define I2C_SPEED_400K 0x1 -#define I2C_SPEED_100K 0x2 -#define I2C_SPEED_5M 0x3 - -/* 0-- STOP transaction */ -#define I2C_STOP 0x0 -/* 1-- do not transmit STOP at end of transaction */ -#define I2C_NOSTOP 0x1 -/* 1--allow slave to insert clock wait states */ -#define I2C_SYNC 0x1 - -struct cx231xx_i2c { - struct cx231xx *dev; - - int nr; - - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - u32 i2c_rc; - - /* different settings for each bus */ - u8 i2c_period; - u8 i2c_nostop; - u8 i2c_reserve; -}; - -struct cx231xx_i2c_xfer_data { - u8 dev_addr; - u8 direction; /* 1 - IN, 0 - OUT */ - u8 saddr_len; /* sub address len */ - u16 saddr_dat; /* sub addr data */ - u8 buf_size; /* buffer size */ - u8 *p_buffer; /* pointer to the buffer */ -}; - -struct VENDOR_REQUEST_IN { - u8 bRequest; - u16 wValue; - u16 wIndex; - u16 wLength; - u8 direction; - u8 bData; - u8 *pBuff; -}; - -struct cx231xx_tvnorm { - char *name; - v4l2_std_id id; - u32 cxiformat; - u32 cxoformat; -}; - -struct cx231xx_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 mask; - u32 shift; -}; - -enum TRANSFER_TYPE { - Raw_Video = 0, - Audio, - Vbi, /* VANC */ - Sliced_cc, /* HANC */ - TS1_serial_mode, - TS2, - TS1_parallel_mode -} ; - -struct cx231xx_video_mode { - /* Isoc control struct */ - struct cx231xx_dmaqueue vidq; - struct cx231xx_isoc_ctl isoc_ctl; - struct cx231xx_bulk_ctl bulk_ctl; - /* locks */ - spinlock_t slock; - - /* usb transfer */ - int alt; /* alternate */ - int max_pkt_size; /* max packet size of isoc transaction */ - int num_alt; /* Number of alternative settings */ - unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ - u16 end_point_addr; -}; -/* -struct cx23885_dmaqueue { - struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; - u32 count; -}; -*/ -struct cx231xx_tsport { - struct cx231xx *dev; - - int nr; - int sram_chno; - - struct videobuf_dvb_frontends frontends; - - /* dma queues */ - - u32 ts_packet_size; - u32 ts_packet_count; - - int width; - int height; - - /* locks */ - spinlock_t slock; - - /* registers */ - u32 reg_gpcnt; - u32 reg_gpcnt_ctl; - u32 reg_dma_ctl; - u32 reg_lngth; - u32 reg_hw_sop_ctrl; - u32 reg_gen_ctrl; - u32 reg_bd_pkt_status; - u32 reg_sop_status; - u32 reg_fifo_ovfl_stat; - u32 reg_vld_misc; - u32 reg_ts_clk_en; - u32 reg_ts_int_msk; - u32 reg_ts_int_stat; - u32 reg_src_sel; - - /* Default register vals */ - int pci_irqmask; - u32 dma_ctl_val; - u32 ts_int_msk_val; - u32 gen_ctrl_val; - u32 ts_clk_en_val; - u32 src_sel_val; - u32 vld_misc_val; - u32 hw_sop_ctrl_val; - - /* Allow a single tsport to have multiple frontends */ - u32 num_frontends; - void *port_priv; -}; - -/* main device struct */ -struct cx231xx { - /* generic device properties */ - char name[30]; /* name (including minor) of the device */ - int model; /* index in the device_data struct */ - int devno; /* marks the number of this device */ - - struct cx231xx_board board; - - /* For I2C IR support */ - struct IR_i2c_init_data init_data; - - unsigned int stream_on:1; /* Locks streams */ - unsigned int vbi_stream_on:1; /* Locks streams for VBI */ - unsigned int has_audio_class:1; - unsigned int has_alsa_audio:1; - - struct cx231xx_fmt *format; - - struct v4l2_device v4l2_dev; - struct v4l2_subdev *sd_cx25840; - struct v4l2_subdev *sd_tuner; - - struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ - atomic_t stream_started; /* stream should be running if true */ - - struct list_head devlist; - - int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - - /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ - struct cx231xx_i2c i2c_bus[3]; - unsigned int xc_fw_load_done:1; - /* locks */ - struct mutex gpio_i2c_lock; - struct mutex i2c_lock; - - /* video for linux */ - int users; /* user count for exclusive use */ - struct video_device *vdev; /* video for linux device struct */ - v4l2_std_id norm; /* selected tv norm */ - int ctl_freq; /* selected frequency */ - unsigned int ctl_ainput; /* selected audio input */ - int mute; - int volume; - - /* frame properties */ - int width; /* current frame width */ - int height; /* current frame height */ - int interlaced; /* 1=interlace fileds, 0=just top fileds */ - - struct cx231xx_audio adev; - - /* states */ - enum cx231xx_dev_state state; - - struct work_struct request_module_wk; - - /* locks */ - struct mutex lock; - struct mutex ctrl_urb_lock; /* protects urb_buf */ - struct list_head inqueue, outqueue; - wait_queue_head_t open, wait_frame, wait_stream; - struct video_device *vbi_dev; - struct video_device *radio_dev; - - unsigned char eedata[256]; - - struct cx231xx_video_mode video_mode; - struct cx231xx_video_mode vbi_mode; - struct cx231xx_video_mode sliced_cc_mode; - struct cx231xx_video_mode ts1_mode; - - atomic_t devlist_count; - - struct usb_device *udev; /* the usb device */ - char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ - - /* helper funcs that call usb_control_msg */ - int (*cx231xx_read_ctrl_reg) (struct cx231xx *dev, u8 req, u16 reg, - char *buf, int len); - int (*cx231xx_write_ctrl_reg) (struct cx231xx *dev, u8 req, u16 reg, - char *buf, int len); - int (*cx231xx_send_usb_command) (struct cx231xx_i2c *i2c_bus, - struct cx231xx_i2c_xfer_data *req_data); - int (*cx231xx_gpio_i2c_read) (struct cx231xx *dev, u8 dev_addr, - u8 *buf, u8 len); - int (*cx231xx_gpio_i2c_write) (struct cx231xx *dev, u8 dev_addr, - u8 *buf, u8 len); - - int (*cx231xx_set_analog_freq) (struct cx231xx *dev, u32 freq); - int (*cx231xx_reset_analog_tuner) (struct cx231xx *dev); - - enum cx231xx_mode mode; - - struct cx231xx_dvb *dvb; - - /* Cx231xx supported PCB config's */ - struct pcb_config current_pcb_config; - u8 current_scenario_idx; - u8 interface_count; - u8 max_iad_interface_count; - - /* GPIO related register direction and values */ - u32 gpio_dir; - u32 gpio_val; - - /* Power Modes */ - int power_mode; - - /* afe parameters */ - enum AFE_MODE afe_mode; - u32 afe_ref_count; - - /* video related parameters */ - u32 video_input; - u32 active_mode; - u8 vbi_or_sliced_cc_mode; /* 0 - vbi ; 1 - sliced cc mode */ - enum cx231xx_std_mode std_mode; /* 0 - Air; 1 - cable */ - - /*mode: digital=1 or analog=0*/ - u8 mode_tv; - - u8 USE_ISO; - struct cx231xx_tvnorm encodernorm; - struct cx231xx_tsport ts1, ts2; - struct cx2341x_mpeg_params mpeg_params; - struct video_device *v4l_device; - atomic_t v4l_reader_count; - u32 freq; - unsigned int input; - u32 cx23417_mailbox; - u32 __iomem *lmmio; - u8 __iomem *bmmio; -}; - -extern struct list_head cx231xx_devlist; - -#define cx25840_call(cx231xx, o, f, args...) \ - v4l2_subdev_call(cx231xx->sd_cx25840, o, f, ##args) -#define tuner_call(cx231xx, o, f, args...) \ - v4l2_subdev_call(cx231xx->sd_tuner, o, f, ##args) -#define call_all(dev, o, f, args...) \ - v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args) - -struct cx231xx_ops { - struct list_head next; - char *name; - int id; - int (*init) (struct cx231xx *); - int (*fini) (struct cx231xx *); -}; - -/* call back functions in dvb module */ -int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq); -int cx231xx_reset_analog_tuner(struct cx231xx *dev); - -/* Provided by cx231xx-i2c.c */ -void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c); -int cx231xx_i2c_register(struct cx231xx_i2c *bus); -int cx231xx_i2c_unregister(struct cx231xx_i2c *bus); - -/* Internal block control functions */ -int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr, - u8 saddr_len, u32 *data, u8 data_len, int master); -int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr, - u8 saddr_len, u32 data, u8 data_len, int master); -int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, - u16 saddr, u8 saddr_len, u32 *data, u8 data_len); -int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr, - u16 saddr, u8 saddr_len, u32 data, u8 data_len); -int cx231xx_reg_mask_write(struct cx231xx *dev, u8 dev_addr, u8 size, - u16 register_address, u8 bit_start, u8 bit_end, - u32 value); -int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr, - u16 saddr, u32 mask, u32 value); -u32 cx231xx_set_field(u32 field_mask, u32 data); - -/*verve r/w*/ -void initGPIO(struct cx231xx *dev); -void uninitGPIO(struct cx231xx *dev); -/* afe related functions */ -int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count); -int cx231xx_afe_init_channels(struct cx231xx *dev); -int cx231xx_afe_setup_AFE_for_baseband(struct cx231xx *dev); -int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux); -int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode); -int cx231xx_afe_update_power_control(struct cx231xx *dev, - enum AV_MODE avmode); -int cx231xx_afe_adjust_ref_count(struct cx231xx *dev, u32 video_input); - -/* i2s block related functions */ -int cx231xx_i2s_blk_initialize(struct cx231xx *dev); -int cx231xx_i2s_blk_update_power_control(struct cx231xx *dev, - enum AV_MODE avmode); -int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input); - -/* DIF related functions */ -int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode, - u32 function_mode, u32 standard); -void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq, - u8 spectral_invert, u32 mode); -u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd); -void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq, - u8 spectral_invert, u32 mode); -void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev); -void reset_s5h1432_demod(struct cx231xx *dev); -void cx231xx_dump_HH_reg(struct cx231xx *dev); -void update_HH_register_after_set_DIF(struct cx231xx *dev); -void cx231xx_dump_SC_reg(struct cx231xx *dev); - - - -int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard); -int cx231xx_tuner_pre_channel_change(struct cx231xx *dev); -int cx231xx_tuner_post_channel_change(struct cx231xx *dev); - -/* video parser functions */ -u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, - u32 *p_bytes_used); -u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf, - u32 *p_bytes_used); -int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 *p_buffer, u32 bytes_to_copy); -void cx231xx_reset_video_buffer(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q); -u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q); -u32 cx231xx_copy_video_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 *p_line, u32 length, int field_number); -u32 cx231xx_get_video_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 sav_eav, u8 *p_buffer, u32 buffer_size); -void cx231xx_swab(u16 *from, u16 *to, u16 len); - -/* Provided by cx231xx-core.c */ - -u32 cx231xx_request_buffers(struct cx231xx *dev, u32 count); -void cx231xx_queue_unusedframes(struct cx231xx *dev); -void cx231xx_release_buffers(struct cx231xx *dev); - -/* read from control pipe */ -int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, - char *buf, int len); - -/* write to control pipe */ -int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, - char *buf, int len); -int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode); - -int cx231xx_send_vendor_cmd(struct cx231xx *dev, - struct VENDOR_REQUEST_IN *ven_req); -int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus, - struct cx231xx_i2c_xfer_data *req_data); - -/* Gpio related functions */ -int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val, - u8 len, u8 request, u8 direction); -int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val); -int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val); -int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value); -int cx231xx_set_gpio_direction(struct cx231xx *dev, int pin_number, - int pin_value); - -int cx231xx_gpio_i2c_start(struct cx231xx *dev); -int cx231xx_gpio_i2c_end(struct cx231xx *dev); -int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data); -int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf); -int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev); -int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev); -int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev); - -int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len); -int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len); - -/* audio related functions */ -int cx231xx_set_audio_decoder_input(struct cx231xx *dev, - enum AUDIO_INPUT audio_input); - -int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type); -int cx231xx_set_video_alternate(struct cx231xx *dev); -int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt); -int is_fw_load(struct cx231xx *dev); -int cx231xx_check_fw(struct cx231xx *dev); -int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*isoc_copy) (struct cx231xx *dev, - struct urb *urb)); -int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*bulk_copy) (struct cx231xx *dev, - struct urb *urb)); -void cx231xx_stop_TS1(struct cx231xx *dev); -void cx231xx_start_TS1(struct cx231xx *dev); -void cx231xx_uninit_isoc(struct cx231xx *dev); -void cx231xx_uninit_bulk(struct cx231xx *dev); -int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode); -int cx231xx_unmute_audio(struct cx231xx *dev); -int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size); -void cx231xx_disable656(struct cx231xx *dev); -void cx231xx_enable656(struct cx231xx *dev); -int cx231xx_demod_reset(struct cx231xx *dev); -int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio); - -/* Device list functions */ -void cx231xx_release_resources(struct cx231xx *dev); -void cx231xx_release_analog_resources(struct cx231xx *dev); -int cx231xx_register_analog_devices(struct cx231xx *dev); -void cx231xx_remove_from_devlist(struct cx231xx *dev); -void cx231xx_add_into_devlist(struct cx231xx *dev); -void cx231xx_init_extension(struct cx231xx *dev); -void cx231xx_close_extension(struct cx231xx *dev); - -/* hardware init functions */ -int cx231xx_dev_init(struct cx231xx *dev); -void cx231xx_dev_uninit(struct cx231xx *dev); -void cx231xx_config_i2c(struct cx231xx *dev); -int cx231xx_config(struct cx231xx *dev); - -/* Stream control functions */ -int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask); -int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask); - -int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type); - -/* Power control functions */ -int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode); -int cx231xx_power_suspend(struct cx231xx *dev); - -/* chip specific control functions */ -int cx231xx_init_ctrl_pin_status(struct cx231xx *dev); -int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev, - u8 analog_or_digital); -int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3); - -/* video audio decoder related functions */ -void video_mux(struct cx231xx *dev, int index); -int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input); -int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input); -int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev); -int cx231xx_set_audio_input(struct cx231xx *dev, u8 input); - -/* Provided by cx231xx-video.c */ -int cx231xx_register_extension(struct cx231xx_ops *dev); -void cx231xx_unregister_extension(struct cx231xx_ops *dev); -void cx231xx_init_extension(struct cx231xx *dev); -void cx231xx_close_extension(struct cx231xx *dev); - -/* Provided by cx231xx-cards.c */ -extern void cx231xx_pre_card_setup(struct cx231xx *dev); -extern void cx231xx_card_setup(struct cx231xx *dev); -extern struct cx231xx_board cx231xx_boards[]; -extern struct usb_device_id cx231xx_id_table[]; -extern const unsigned int cx231xx_bcount; -int cx231xx_tuner_callback(void *ptr, int component, int command, int arg); - -/* cx23885-417.c */ -extern int cx231xx_417_register(struct cx231xx *dev); -extern void cx231xx_417_unregister(struct cx231xx *dev); - -/* cx23885-input.c */ - -#if defined(CONFIG_VIDEO_CX231XX_RC) -int cx231xx_ir_init(struct cx231xx *dev); -void cx231xx_ir_exit(struct cx231xx *dev); -#else -#define cx231xx_ir_init(dev) (0) -#define cx231xx_ir_exit(dev) (0) -#endif - - -/* printk macros */ - -#define cx231xx_err(fmt, arg...) do {\ - printk(KERN_ERR fmt , ##arg); } while (0) - -#define cx231xx_errdev(fmt, arg...) do {\ - printk(KERN_ERR "%s: "fmt,\ - dev->name , ##arg); } while (0) - -#define cx231xx_info(fmt, arg...) do {\ - printk(KERN_INFO "%s: "fmt,\ - dev->name , ##arg); } while (0) -#define cx231xx_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s: "fmt,\ - dev->name , ##arg); } while (0) - -static inline unsigned int norm_maxw(struct cx231xx *dev) -{ - if (dev->board.max_range_640_480) - return 640; - else - return 720; -} - -static inline unsigned int norm_maxh(struct cx231xx *dev) -{ - if (dev->board.max_range_640_480) - return 480; - else - return (dev->norm & V4L2_STD_625_50) ? 576 : 480; -} -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-i2c.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,536 +0,0 @@ -/* - cx231xx-i2c.c - driver for Conexant Cx23100/101/102 USB video capture devices - - Copyright (C) 2008 - Based on em28xx driver - Based on Cx23885 driver - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "cx231xx.h" - -/* ----------------------------------------------------------- */ - -static unsigned int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -#define dprintk1(lvl, fmt, args...) \ -do { \ - if (i2c_debug >= lvl) { \ - printk(fmt, ##args); \ - } \ -} while (0) - -#define dprintk2(lvl, fmt, args...) \ -do { \ - if (i2c_debug >= lvl) { \ - printk(KERN_DEBUG "%s at %s: " fmt, \ - dev->name, __func__ , ##args); \ - } \ -} while (0) - -static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus, - const struct i2c_msg *msg, int tuner_type) -{ - if (bus->nr != dev->board.tuner_i2c_master) - return false; - - if (msg->addr != dev->board.tuner_addr) - return false; - - if (dev->tuner_type != tuner_type) - return false; - - return true; -} - -/* - * cx231xx_i2c_send_bytes() - */ -int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg) -{ - struct cx231xx_i2c *bus = i2c_adap->algo_data; - struct cx231xx *dev = bus->dev; - struct cx231xx_i2c_xfer_data req_data; - int status = 0; - u16 size = 0; - u8 loop = 0; - u8 saddr_len = 1; - u8 *buf_ptr = NULL; - u16 saddr = 0; - u8 need_gpio = 0; - - if (is_tuner(dev, bus, msg, TUNER_XC5000)) { - size = msg->len; - - if (size == 2) { /* register write sub addr */ - /* Just writing sub address will cause problem - * to XC5000. So ignore the request */ - return 0; - } else if (size == 4) { /* register write with sub addr */ - if (msg->len >= 2) - saddr = msg->buf[0] << 8 | msg->buf[1]; - else if (msg->len == 1) - saddr = msg->buf[0]; - - switch (saddr) { - case 0x0000: /* start tuner calibration mode */ - need_gpio = 1; - /* FW Loading is done */ - dev->xc_fw_load_done = 1; - break; - case 0x000D: /* Set signal source */ - case 0x0001: /* Set TV standard - Video */ - case 0x0002: /* Set TV standard - Audio */ - case 0x0003: /* Set RF Frequency */ - need_gpio = 1; - break; - default: - if (dev->xc_fw_load_done) - need_gpio = 1; - break; - } - - if (need_gpio) { - dprintk1(1, - "GPIO WRITE: addr 0x%x, len %d, saddr 0x%x\n", - msg->addr, msg->len, saddr); - - return dev->cx231xx_gpio_i2c_write(dev, - msg->addr, - msg->buf, - msg->len); - } - } - - /* special case for Xc5000 tuner case */ - saddr_len = 1; - - /* adjust the length to correct length */ - size -= saddr_len; - buf_ptr = (u8 *) (msg->buf + 1); - - do { - /* prepare xfer_data struct */ - req_data.dev_addr = msg->addr; - req_data.direction = msg->flags; - req_data.saddr_len = saddr_len; - req_data.saddr_dat = msg->buf[0]; - req_data.buf_size = size > 16 ? 16 : size; - req_data.p_buffer = (u8 *) (buf_ptr + loop * 16); - - bus->i2c_nostop = (size > 16) ? 1 : 0; - bus->i2c_reserve = (loop == 0) ? 0 : 1; - - /* usb send command */ - status = dev->cx231xx_send_usb_command(bus, &req_data); - loop++; - - if (size >= 16) - size -= 16; - else - size = 0; - - } while (size > 0); - - bus->i2c_nostop = 0; - bus->i2c_reserve = 0; - - } else { /* regular case */ - - /* prepare xfer_data struct */ - req_data.dev_addr = msg->addr; - req_data.direction = msg->flags; - req_data.saddr_len = 0; - req_data.saddr_dat = 0; - req_data.buf_size = msg->len; - req_data.p_buffer = msg->buf; - - /* usb send command */ - status = dev->cx231xx_send_usb_command(bus, &req_data); - } - - return status < 0 ? status : 0; -} - -/* - * cx231xx_i2c_recv_bytes() - * read a byte from the i2c device - */ -static int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg) -{ - struct cx231xx_i2c *bus = i2c_adap->algo_data; - struct cx231xx *dev = bus->dev; - struct cx231xx_i2c_xfer_data req_data; - int status = 0; - u16 saddr = 0; - u8 need_gpio = 0; - - if (is_tuner(dev, bus, msg, TUNER_XC5000)) { - if (msg->len == 2) - saddr = msg->buf[0] << 8 | msg->buf[1]; - else if (msg->len == 1) - saddr = msg->buf[0]; - - if (dev->xc_fw_load_done) { - - switch (saddr) { - case 0x0009: /* BUSY check */ - dprintk1(1, - "GPIO R E A D: Special case BUSY check \n"); - /*Try read BUSY register, just set it to zero*/ - msg->buf[0] = 0; - if (msg->len == 2) - msg->buf[1] = 0; - return 0; - case 0x0004: /* read Lock status */ - need_gpio = 1; - break; - - } - - if (need_gpio) { - /* this is a special case to handle Xceive tuner - clock stretch issue with gpio based I2C */ - - dprintk1(1, - "GPIO R E A D: addr 0x%x, len %d, saddr 0x%x\n", - msg->addr, msg->len, - msg->buf[0] << 8 | msg->buf[1]); - - status = - dev->cx231xx_gpio_i2c_write(dev, msg->addr, - msg->buf, - msg->len); - status = - dev->cx231xx_gpio_i2c_read(dev, msg->addr, - msg->buf, - msg->len); - return status; - } - } - - /* prepare xfer_data struct */ - req_data.dev_addr = msg->addr; - req_data.direction = msg->flags; - req_data.saddr_len = msg->len; - req_data.saddr_dat = msg->buf[0] << 8 | msg->buf[1]; - req_data.buf_size = msg->len; - req_data.p_buffer = msg->buf; - - /* usb send command */ - status = dev->cx231xx_send_usb_command(bus, &req_data); - - } else { - - /* prepare xfer_data struct */ - req_data.dev_addr = msg->addr; - req_data.direction = msg->flags; - req_data.saddr_len = 0; - req_data.saddr_dat = 0; - req_data.buf_size = msg->len; - req_data.p_buffer = msg->buf; - - /* usb send command */ - status = dev->cx231xx_send_usb_command(bus, &req_data); - } - - return status < 0 ? status : 0; -} - -/* - * cx231xx_i2c_recv_bytes_with_saddr() - * read a byte from the i2c device - */ -static int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg1, - const struct i2c_msg *msg2) -{ - struct cx231xx_i2c *bus = i2c_adap->algo_data; - struct cx231xx *dev = bus->dev; - struct cx231xx_i2c_xfer_data req_data; - int status = 0; - u16 saddr = 0; - u8 need_gpio = 0; - - if (msg1->len == 2) - saddr = msg1->buf[0] << 8 | msg1->buf[1]; - else if (msg1->len == 1) - saddr = msg1->buf[0]; - - if (is_tuner(dev, bus, msg2, TUNER_XC5000)) { - if ((msg2->len < 16)) { - - dprintk1(1, - "i2c_read: addr 0x%x, len %d, saddr 0x%x, len %d\n", - msg2->addr, msg2->len, saddr, msg1->len); - - switch (saddr) { - case 0x0008: /* read FW load status */ - need_gpio = 1; - break; - case 0x0004: /* read Lock status */ - need_gpio = 1; - break; - } - - if (need_gpio) { - status = - dev->cx231xx_gpio_i2c_write(dev, msg1->addr, - msg1->buf, - msg1->len); - status = - dev->cx231xx_gpio_i2c_read(dev, msg2->addr, - msg2->buf, - msg2->len); - return status; - } - } - } - - /* prepare xfer_data struct */ - req_data.dev_addr = msg2->addr; - req_data.direction = msg2->flags; - req_data.saddr_len = msg1->len; - req_data.saddr_dat = saddr; - req_data.buf_size = msg2->len; - req_data.p_buffer = msg2->buf; - - /* usb send command */ - status = dev->cx231xx_send_usb_command(bus, &req_data); - - return status < 0 ? status : 0; -} - -/* - * cx231xx_i2c_check_for_device() - * check if there is a i2c_device at the supplied address - */ -static int cx231xx_i2c_check_for_device(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg) -{ - struct cx231xx_i2c *bus = i2c_adap->algo_data; - struct cx231xx *dev = bus->dev; - struct cx231xx_i2c_xfer_data req_data; - int status = 0; - - /* prepare xfer_data struct */ - req_data.dev_addr = msg->addr; - req_data.direction = msg->flags; - req_data.saddr_len = 0; - req_data.saddr_dat = 0; - req_data.buf_size = 0; - req_data.p_buffer = NULL; - - /* usb send command */ - status = dev->cx231xx_send_usb_command(bus, &req_data); - - return status < 0 ? status : 0; -} - -/* - * cx231xx_i2c_xfer() - * the main i2c transfer function - */ -static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) -{ - struct cx231xx_i2c *bus = i2c_adap->algo_data; - struct cx231xx *dev = bus->dev; - int addr, rc, i, byte; - - if (num <= 0) - return 0; - mutex_lock(&dev->i2c_lock); - for (i = 0; i < num; i++) { - - addr = msgs[i].addr >> 1; - - dprintk2(2, "%s %s addr=%x len=%d:", - (msgs[i].flags & I2C_M_RD) ? "read" : "write", - i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); - if (!msgs[i].len) { - /* no len: check only for device presence */ - rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]); - if (rc < 0) { - dprintk2(2, " no device\n"); - mutex_unlock(&dev->i2c_lock); - return rc; - } - - } else if (msgs[i].flags & I2C_M_RD) { - /* read bytes */ - rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]); - if (i2c_debug >= 2) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } - } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && - msgs[i].addr == msgs[i + 1].addr - && (msgs[i].len <= 2) && (bus->nr < 3)) { - /* read bytes */ - rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap, - &msgs[i], - &msgs[i + 1]); - if (i2c_debug >= 2) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } - i++; - } else { - /* write bytes */ - if (i2c_debug >= 2) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } - rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]); - } - if (rc < 0) - goto err; - if (i2c_debug >= 2) - printk("\n"); - } - mutex_unlock(&dev->i2c_lock); - return num; -err: - dprintk2(2, " ERROR: %i\n", rc); - mutex_unlock(&dev->i2c_lock); - return rc; -} - -/* ----------------------------------------------------------- */ - -/* - * functionality() - */ -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; -} - -static struct i2c_algorithm cx231xx_algo = { - .master_xfer = cx231xx_i2c_xfer, - .functionality = functionality, -}; - -static struct i2c_adapter cx231xx_adap_template = { - .owner = THIS_MODULE, - .name = "cx231xx", - .algo = &cx231xx_algo, -}; - -static struct i2c_client cx231xx_client_template = { - .name = "cx231xx internal", -}; - -/* ----------------------------------------------------------- */ - -/* - * i2c_devs - * incomplete list of known devices - */ -static char *i2c_devs[128] = { - [0x60 >> 1] = "colibri", - [0x88 >> 1] = "hammerhead", - [0x8e >> 1] = "CIR", - [0x32 >> 1] = "GeminiIII", - [0x02 >> 1] = "Aquarius", - [0xa0 >> 1] = "eeprom", - [0xc0 >> 1] = "tuner", - [0xc2 >> 1] = "tuner", -}; - -/* - * cx231xx_do_i2c_scan() - * check i2c address range for devices - */ -void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c) -{ - unsigned char buf; - int i, rc; - - cx231xx_info(": Checking for I2C devices ..\n"); - for (i = 0; i < 128; i++) { - c->addr = i; - rc = i2c_master_recv(c, &buf, 0); - if (rc < 0) - continue; - cx231xx_info("%s: i2c scan: found device @ 0x%x [%s]\n", - dev->name, i << 1, - i2c_devs[i] ? i2c_devs[i] : "???"); - } - cx231xx_info(": Completed Checking for I2C devices.\n"); -} - -/* - * cx231xx_i2c_register() - * register i2c bus - */ -int cx231xx_i2c_register(struct cx231xx_i2c *bus) -{ - struct cx231xx *dev = bus->dev; - - BUG_ON(!dev->cx231xx_send_usb_command); - - memcpy(&bus->i2c_adap, &cx231xx_adap_template, sizeof(bus->i2c_adap)); - memcpy(&bus->i2c_algo, &cx231xx_algo, sizeof(bus->i2c_algo)); - memcpy(&bus->i2c_client, &cx231xx_client_template, - sizeof(bus->i2c_client)); - - bus->i2c_adap.dev.parent = &dev->udev->dev; - - strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); - - bus->i2c_algo.data = bus; - bus->i2c_adap.algo_data = bus; - i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); - i2c_add_adapter(&bus->i2c_adap); - - bus->i2c_client.adapter = &bus->i2c_adap; - - if (0 == bus->i2c_rc) { - if (i2c_scan) - cx231xx_do_i2c_scan(dev, &bus->i2c_client); - } else - cx231xx_warn("%s: i2c bus %d register FAILED\n", - dev->name, bus->nr); - - return bus->i2c_rc; -} - -/* - * cx231xx_i2c_unregister() - * unregister i2c_bus - */ -int cx231xx_i2c_unregister(struct cx231xx_i2c *bus) -{ - i2c_del_adapter(&bus->i2c_adap); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-input.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-input.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/* - * cx231xx IR glue driver - * - * Copyright (C) 2010 Mauro Carvalho Chehab - * - * Polaris (cx231xx) has its support for IR's with a design close to MCE. - * however, a few designs are using an external I2C chip for IR, instead - * of using the one provided by the chip. - * This driver provides support for those extra devices - * - * 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 version 2. - * - * 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. - */ - -#include "cx231xx.h" -#include -#include - -#define MODULE_NAME "cx231xx-input" - -static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key, - u32 *ir_raw) -{ - u8 cmd, scancode; - - dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__); - - /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &cmd, 1)) - return -EIO; - - /* it seems that 0xFE indicates that a button is still hold - down, while 0xff indicates that no button is hold - down. 0xfe sequences are sometimes interrupted by 0xFF */ - - if (cmd == 0xff) - return 0; - - scancode = - ((cmd & 0x01) ? 0x80 : 0) | - ((cmd & 0x02) ? 0x40 : 0) | - ((cmd & 0x04) ? 0x20 : 0) | - ((cmd & 0x08) ? 0x10 : 0) | - ((cmd & 0x10) ? 0x08 : 0) | - ((cmd & 0x20) ? 0x04 : 0) | - ((cmd & 0x40) ? 0x02 : 0) | - ((cmd & 0x80) ? 0x01 : 0); - - dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n", - cmd, scancode); - - *ir_key = scancode; - *ir_raw = scancode; - return 1; -} - -int cx231xx_ir_init(struct cx231xx *dev) -{ - struct i2c_board_info info; - u8 ir_i2c_bus; - - dev_dbg(&dev->udev->dev, "%s\n", __func__); - - /* Only initialize if a rc keycode map is defined */ - if (!cx231xx_boards[dev->model].rc_map_name) - return -ENODEV; - - request_module("ir-kbd-i2c"); - - memset(&info, 0, sizeof(struct i2c_board_info)); - memset(&dev->init_data, 0, sizeof(dev->init_data)); - dev->init_data.rc_dev = rc_allocate_device(); - if (!dev->init_data.rc_dev) - return -ENOMEM; - - dev->init_data.name = cx231xx_boards[dev->model].name; - - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - info.platform_data = &dev->init_data; - - /* - * Board-dependent values - * - * For now, there's just one type of hardware design using - * an i2c device. - */ - dev->init_data.get_key = get_key_isdbt; - dev->init_data.ir_codes = cx231xx_boards[dev->model].rc_map_name; - /* The i2c micro-controller only outputs the cmd part of NEC protocol */ - dev->init_data.rc_dev->scanmask = 0xff; - dev->init_data.rc_dev->driver_name = "cx231xx"; - dev->init_data.type = RC_TYPE_NEC; - info.addr = 0x30; - - /* Load and bind ir-kbd-i2c */ - ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master; - dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n", - ir_i2c_bus, info.addr); - i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info); - - return 0; -} - -void cx231xx_ir_exit(struct cx231xx *dev) -{ -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,795 +0,0 @@ -/* - cx231xx-pcb-config.c - driver for Conexant - Cx23100/101/102 USB video capture devices - - Copyright (C) 2008 - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx231xx.h" -#include "cx231xx-conf-reg.h" - -static unsigned int pcb_debug; -module_param(pcb_debug, int, 0644); -MODULE_PARM_DESC(pcb_debug, "enable pcb config debug messages [video]"); - -/******************************************************************************/ - -struct pcb_config cx231xx_Scenario[] = { - { - INDEX_SELFPOWER_DIGITAL_ONLY, /* index */ - USB_SELF_POWER, /* power_type */ - 0, /* speed , not decide yet */ - MOD_DIGITAL, /* mode */ - SOURCE_TS_BDA, /* ts1_source, digital tv only */ - NOT_SUPPORTED, /* ts2_source */ - NOT_SUPPORTED, /* analog source */ - - 0, /* digital_index */ - 0, /* analog index */ - 0, /* dif_index */ - 0, /* external_index */ - - 1, /* only one configuration */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - NOT_SUPPORTED, /* AUDIO */ - NOT_SUPPORTED, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - , - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - , - /* full-speed config */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - NOT_SUPPORTED, /* AUDIO */ - NOT_SUPPORTED, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - } - , - - { - INDEX_SELFPOWER_DUAL_DIGITAL, /* index */ - USB_SELF_POWER, /* power_type */ - 0, /* speed , not decide yet */ - MOD_DIGITAL, /* mode */ - SOURCE_TS_BDA, /* ts1_source, digital tv only */ - 0, /* ts2_source,need update from register */ - NOT_SUPPORTED, /* analog source */ - 0, /* digital_index */ - 0, /* analog index */ - 0, /* dif_index */ - 0, /* external_index */ - - 1, /* only one configuration */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - 2, /* TS2 index */ - NOT_SUPPORTED, /* AUDIO */ - NOT_SUPPORTED, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - , - /* full-speed */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - 2, /* TS2 index */ - NOT_SUPPORTED, /* AUDIO */ - NOT_SUPPORTED, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - } - , - - { - INDEX_SELFPOWER_ANALOG_ONLY, /* index */ - USB_SELF_POWER, /* power_type */ - 0, /* speed , not decide yet */ - MOD_ANALOG | MOD_DIF | MOD_EXTERNAL, /* mode ,analog tv only */ - NOT_SUPPORTED, /* ts1_source, NOT SUPPORT */ - NOT_SUPPORTED, /* ts2_source,NOT SUPPORT */ - 0, /* analog source, need update */ - - 0, /* digital_index */ - 0, /* analog index */ - 0, /* dif_index */ - 0, /* external_index */ - - 1, /* only one configuration */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - NOT_SUPPORTED, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - 1, /* AUDIO */ - 2, /* VIDEO */ - 3, /* VANC */ - 4, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - , - /* full-speed */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - NOT_SUPPORTED, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - 1, /* AUDIO */ - 2, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - } - , - - { - INDEX_SELFPOWER_DUAL, /* index */ - USB_SELF_POWER, /* power_type */ - 0, /* speed , not decide yet */ - /* mode ,analog tv and digital path */ - MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL, - 0, /* ts1_source,will update in register */ - NOT_SUPPORTED, /* ts2_source,NOT SUPPORT */ - 0, /* analog source need update */ - 0, /* digital_index */ - 0, /* analog index */ - 0, /* dif_index */ - 0, /* external_index */ - 1, /* only one configuration */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - 2, /* AUDIO */ - 3, /* VIDEO */ - 4, /* VANC */ - 5, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - , - /* full-speed */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - 2, /* AUDIO */ - 3, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - } - , - - { - INDEX_SELFPOWER_TRIPLE, /* index */ - USB_SELF_POWER, /* power_type */ - 0, /* speed , not decide yet */ - /* mode ,analog tv and digital path */ - MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL, - 0, /* ts1_source, update in register */ - 0, /* ts2_source,update in register */ - 0, /* analog source, need update */ - - 0, /* digital_index */ - 0, /* analog index */ - 0, /* dif_index */ - 0, /* external_index */ - 1, /* only one configuration */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - 2, /* TS2 index */ - 3, /* AUDIO */ - 4, /* VIDEO */ - 5, /* VANC */ - 6, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - , - /* full-speed */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - 2, /* TS2 index */ - 3, /* AUDIO */ - 4, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - } - , - - { - INDEX_SELFPOWER_COMPRESSOR, /* index */ - USB_SELF_POWER, /* power_type */ - 0, /* speed , not decide yet */ - /* mode ,analog tv AND DIGITAL path */ - MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL, - NOT_SUPPORTED, /* ts1_source, disable */ - SOURCE_TS_BDA, /* ts2_source */ - 0, /* analog source,need update */ - 0, /* digital_index */ - 0, /* analog index */ - 0, /* dif_index */ - 0, /* external_index */ - 1, /* only one configuration */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - NOT_SUPPORTED, /* ts1 index */ - 1, /* TS2 index */ - 2, /* AUDIO */ - 3, /* VIDEO */ - 4, /* VANC */ - 5, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - , - /* full-speed */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - NOT_SUPPORTED, /* ts1 index */ - 1, /* TS2 index */ - 2, /* AUDIO */ - 3, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - } - , - - { - INDEX_BUSPOWER_DIGITAL_ONLY, /* index */ - USB_BUS_POWER, /* power_type */ - 0, /* speed , not decide yet */ - MOD_DIGITAL, /* mode ,analog tv AND DIGITAL path */ - SOURCE_TS_BDA, /* ts1_source, disable */ - NOT_SUPPORTED, /* ts2_source */ - NOT_SUPPORTED, /* analog source */ - - 0, /* digital_index */ - 0, /* analog index */ - 0, /* dif_index */ - 0, /* external_index */ - - 1, /* only one configuration */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index = 2 */ - 1, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - NOT_SUPPORTED, /* AUDIO */ - NOT_SUPPORTED, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - , - /* full-speed */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index = 2 */ - 1, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - NOT_SUPPORTED, /* AUDIO */ - NOT_SUPPORTED, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - } - , - { - INDEX_BUSPOWER_ANALOG_ONLY, /* index */ - USB_BUS_POWER, /* power_type */ - 0, /* speed , not decide yet */ - MOD_ANALOG, /* mode ,analog tv AND DIGITAL path */ - NOT_SUPPORTED, /* ts1_source, disable */ - NOT_SUPPORTED, /* ts2_source */ - SOURCE_ANALOG, /* analog source--analog */ - 0, /* digital_index */ - 0, /* analog index */ - 0, /* dif_index */ - 0, /* external_index */ - 1, /* only one configuration */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - NOT_SUPPORTED, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - 1, /* AUDIO */ - 2, /* VIDEO */ - 3, /* VANC */ - 4, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - , - { /* full-speed */ - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - NOT_SUPPORTED, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - 1, /* AUDIO */ - 2, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - } - , - { - INDEX_BUSPOWER_DIF_ONLY, /* index */ - USB_BUS_POWER, /* power_type */ - 0, /* speed , not decide yet */ - /* mode ,analog tv AND DIGITAL path */ - MOD_DIF | MOD_ANALOG | MOD_DIGITAL | MOD_EXTERNAL, - SOURCE_TS_BDA, /* ts1_source, disable */ - NOT_SUPPORTED, /* ts2_source */ - SOURCE_DIF | SOURCE_ANALOG | SOURCE_EXTERNAL, /* analog source, dif */ - 0, /* digital_index */ - 0, /* analog index */ - 0, /* dif_index */ - 0, /* external_index */ - 1, /* only one configuration */ - { - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - 2, /* AUDIO */ - 3, /* VIDEO */ - 4, /* VANC */ - 5, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - , - { /* full speed */ - { - 0, /* config index */ - { - 0, /* interrupt ep index */ - 1, /* ts1 index */ - NOT_SUPPORTED, /* TS2 index */ - 2, /* AUDIO */ - 3, /* VIDEO */ - NOT_SUPPORTED, /* VANC */ - NOT_SUPPORTED, /* HANC */ - NOT_SUPPORTED /* ir_index */ - } - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - , - {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, - NOT_SUPPORTED} - } - } - } - , - -}; - -/*****************************************************************/ - -u32 initialize_cx231xx(struct cx231xx *dev) -{ - u32 config_info = 0; - struct pcb_config *p_pcb_info; - u8 usb_speed = 1; /* from register,1--HS, 0--FS */ - u8 data[4] = { 0, 0, 0, 0 }; - u32 ts1_source = 0; - u32 ts2_source = 0; - u32 analog_source = 0; - u8 _current_scenario_idx = 0xff; - - ts1_source = SOURCE_TS_BDA; - ts2_source = SOURCE_TS_BDA; - - /* read board config register to find out which - pcb config it is related to */ - cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4); - - config_info = *((u32 *) data); - usb_speed = (u8) (config_info & 0x1); - - /* Verify this device belongs to Bus power or Self power device */ - if (config_info & BUS_POWER) { /* bus-power */ - switch (config_info & BUSPOWER_MASK) { - case TS1_PORT | BUS_POWER: - cx231xx_Scenario[INDEX_BUSPOWER_DIGITAL_ONLY].speed = - usb_speed; - p_pcb_info = - &cx231xx_Scenario[INDEX_BUSPOWER_DIGITAL_ONLY]; - _current_scenario_idx = INDEX_BUSPOWER_DIGITAL_ONLY; - break; - case AVDEC_ENABLE | BUS_POWER: - cx231xx_Scenario[INDEX_BUSPOWER_ANALOG_ONLY].speed = - usb_speed; - p_pcb_info = - &cx231xx_Scenario[INDEX_BUSPOWER_ANALOG_ONLY]; - _current_scenario_idx = INDEX_BUSPOWER_ANALOG_ONLY; - break; - case AVDEC_ENABLE | BUS_POWER | TS1_PORT: - cx231xx_Scenario[INDEX_BUSPOWER_DIF_ONLY].speed = - usb_speed; - p_pcb_info = &cx231xx_Scenario[INDEX_BUSPOWER_DIF_ONLY]; - _current_scenario_idx = INDEX_BUSPOWER_DIF_ONLY; - break; - default: - cx231xx_info("bad config in buspower!!!!\n"); - cx231xx_info("config_info=%x\n", - (config_info & BUSPOWER_MASK)); - return 1; - } - } else { /* self-power */ - - switch (config_info & SELFPOWER_MASK) { - case TS1_PORT | SELF_POWER: - cx231xx_Scenario[INDEX_SELFPOWER_DIGITAL_ONLY].speed = - usb_speed; - p_pcb_info = - &cx231xx_Scenario[INDEX_SELFPOWER_DIGITAL_ONLY]; - _current_scenario_idx = INDEX_SELFPOWER_DIGITAL_ONLY; - break; - case TS1_TS2_PORT | SELF_POWER: - cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL].speed = - usb_speed; - cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL]. - ts2_source = ts2_source; - p_pcb_info = - &cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL]; - _current_scenario_idx = INDEX_SELFPOWER_DUAL_DIGITAL; - break; - case AVDEC_ENABLE | SELF_POWER: - cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY].speed = - usb_speed; - cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY]. - analog_source = analog_source; - p_pcb_info = - &cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY]; - _current_scenario_idx = INDEX_SELFPOWER_ANALOG_ONLY; - break; - case AVDEC_ENABLE | TS1_PORT | SELF_POWER: - cx231xx_Scenario[INDEX_SELFPOWER_DUAL].speed = - usb_speed; - cx231xx_Scenario[INDEX_SELFPOWER_DUAL].ts1_source = - ts1_source; - cx231xx_Scenario[INDEX_SELFPOWER_DUAL].analog_source = - analog_source; - p_pcb_info = &cx231xx_Scenario[INDEX_SELFPOWER_DUAL]; - _current_scenario_idx = INDEX_SELFPOWER_DUAL; - break; - case AVDEC_ENABLE | TS1_TS2_PORT | SELF_POWER: - cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].speed = - usb_speed; - cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].ts1_source = - ts1_source; - cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].ts2_source = - ts2_source; - cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].analog_source = - analog_source; - p_pcb_info = &cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE]; - _current_scenario_idx = INDEX_SELFPOWER_TRIPLE; - break; - case AVDEC_ENABLE | TS1VIP_TS2_PORT | SELF_POWER: - cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR].speed = - usb_speed; - cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR]. - analog_source = analog_source; - p_pcb_info = - &cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR]; - _current_scenario_idx = INDEX_SELFPOWER_COMPRESSOR; - break; - default: - cx231xx_info("bad senario!!!!!\n"); - cx231xx_info("config_info=%x\n", - (config_info & SELFPOWER_MASK)); - return 1; - } - } - - dev->current_scenario_idx = _current_scenario_idx; - - memcpy(&dev->current_pcb_config, p_pcb_info, - sizeof(struct pcb_config)); - - if (pcb_debug) { - cx231xx_info("SC(0x00) register = 0x%x\n", config_info); - cx231xx_info("scenario %d\n", - (dev->current_pcb_config.index) + 1); - cx231xx_info("type=%x\n", dev->current_pcb_config.type); - cx231xx_info("mode=%x\n", dev->current_pcb_config.mode); - cx231xx_info("speed=%x\n", dev->current_pcb_config.speed); - cx231xx_info("ts1_source=%x\n", - dev->current_pcb_config.ts1_source); - cx231xx_info("ts2_source=%x\n", - dev->current_pcb_config.ts2_source); - cx231xx_info("analog_source=%x\n", - dev->current_pcb_config.analog_source); - } - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,231 +0,0 @@ -/* - cx231xx-pcb-cfg.h - driver for Conexant - Cx23100/101/102 USB video capture devices - - Copyright (C) 2008 - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _PCB_CONFIG_H_ -#define _PCB_CONFIG_H_ - -#include -#include - -/*************************************************************************** - * Class Information * -***************************************************************************/ -#define CLASS_DEFAULT 0xFF - -enum VENDOR_REQUEST_TYPE { - /* Set/Get I2C */ - VRT_SET_I2C0 = 0x0, - VRT_SET_I2C1 = 0x1, - VRT_SET_I2C2 = 0x2, - VRT_GET_I2C0 = 0x4, - VRT_GET_I2C1 = 0x5, - VRT_GET_I2C2 = 0x6, - - /* Set/Get GPIO */ - VRT_SET_GPIO = 0x8, - VRT_GET_GPIO = 0x9, - - /* Set/Get GPIE */ - VRT_SET_GPIE = 0xA, - VRT_GET_GPIE = 0xB, - - /* Set/Get Register Control/Status */ - VRT_SET_REGISTER = 0xC, - VRT_GET_REGISTER = 0xD, - - /* Get Extended Compat ID Descriptor */ - VRT_GET_EXTCID_DESC = 0xFF, -}; - -enum BYTE_ENABLE_MASK { - ENABLE_ONE_BYTE = 0x1, - ENABLE_TWE_BYTE = 0x3, - ENABLE_THREE_BYTE = 0x7, - ENABLE_FOUR_BYTE = 0xF, -}; - -#define SPEED_MASK 0x1 -enum USB_SPEED{ - FULL_SPEED = 0x0, /* 0: full speed */ - HIGH_SPEED = 0x1 /* 1: high speed */ -}; - -enum _true_false{ - FALSE = 0, - TRUE = 1 -}; - -#define TS_MASK 0x6 -enum TS_PORT{ - NO_TS_PORT = 0x0, /* 2'b00: Neither port used. PCB not a Hybrid, - only offers Analog TV or Video */ - TS1_PORT = 0x4, /* 2'b10: TS1 Input (Hybrid mode : - Digital or External Analog/Compressed source) */ - TS1_TS2_PORT = 0x6, /* 2'b11: TS1 & TS2 Inputs - (Dual inputs from Digital and/or - External Analog/Compressed sources) */ - TS1_EXT_CLOCK = 0x6, /* 2'b11: TS1 & TS2 as selector - to external clock */ - TS1VIP_TS2_PORT = 0x2 /* 2'b01: TS1 used as 656/VIP Output, - TS2 Input (from Compressor) */ -}; - -#define EAVP_MASK 0x8 -enum EAV_PRESENT{ - NO_EXTERNAL_AV = 0x0, /* 0: No External A/V inputs - (no need for i2s blcok), - Analog Tuner must be present */ - EXTERNAL_AV = 0x8 /* 1: External A/V inputs - present (requires i2s blk) */ -}; - -#define ATM_MASK 0x30 -enum AT_MODE{ - DIF_TUNER = 0x30, /* 2'b11: IF Tuner (requires use of DIF) */ - BASEBAND_SOUND = 0x20, /* 2'b10: Baseband Composite & - Sound-IF Signals present */ - NO_TUNER = 0x10 /* 2'b0x: No Analog Tuner present */ -}; - -#define PWR_SEL_MASK 0x40 -enum POWE_TYPE{ - SELF_POWER = 0x0, /* 0: self power */ - BUS_POWER = 0x40 /* 1: bus power */ -}; - -enum USB_POWE_TYPE{ - USB_SELF_POWER = 0, - USB_BUS_POWER -}; - -#define BO_0_MASK 0x80 -enum AVDEC_STATUS{ - AVDEC_DISABLE = 0x0, /* 0: A/V Decoder Disabled */ - AVDEC_ENABLE = 0x80 /* 1: A/V Decoder Enabled */ -}; - -#define BO_1_MASK 0x100 - -#define BUSPOWER_MASK 0xC4 /* for Polaris spec 0.8 */ -#define SELFPOWER_MASK 0x86 - -/***************************************************************************/ -#define NOT_DECIDE_YET 0xFE -#define NOT_SUPPORTED 0xFF - -/*************************************************************************** - * for mod field use * -***************************************************************************/ -#define MOD_DIGITAL 0x1 -#define MOD_ANALOG 0x2 -#define MOD_DIF 0x4 -#define MOD_EXTERNAL 0x8 -#define CAP_ALL_MOD 0x0f - -/*************************************************************************** - * source define * -***************************************************************************/ -#define SOURCE_DIGITAL 0x1 -#define SOURCE_ANALOG 0x2 -#define SOURCE_DIF 0x4 -#define SOURCE_EXTERNAL 0x8 -#define SOURCE_TS_BDA 0x10 -#define SOURCE_TS_ENCODE 0x20 -#define SOURCE_TS_EXTERNAL 0x40 - -/*************************************************************************** - * interface information define * -***************************************************************************/ -struct INTERFACE_INFO { - u8 interrupt_index; - u8 ts1_index; - u8 ts2_index; - u8 audio_index; - u8 video_index; - u8 vanc_index; /* VBI */ - u8 hanc_index; /* Sliced CC */ - u8 ir_index; -}; - -enum INDEX_INTERFACE_INFO{ - INDEX_INTERRUPT = 0x0, - INDEX_TS1, - INDEX_TS2, - INDEX_AUDIO, - INDEX_VIDEO, - INDEX_VANC, - INDEX_HANC, - INDEX_IR, -}; - -/*************************************************************************** - * configuration information define * -***************************************************************************/ -struct CONFIG_INFO { - u8 config_index; - struct INTERFACE_INFO interface_info; -}; - -struct pcb_config { - u8 index; - u8 type; /* bus power or self power, - self power--0, bus_power--1 */ - u8 speed; /* usb speed, 2.0--1, 1.1--0 */ - u8 mode; /* digital , anlog, dif or external A/V */ - u32 ts1_source; /* three source -- BDA,External,encode */ - u32 ts2_source; - u32 analog_source; - u8 digital_index; /* bus-power used */ - u8 analog_index; /* bus-power used */ - u8 dif_index; /* bus-power used */ - u8 external_index; /* bus-power used */ - u8 config_num; /* current config num, 0,1,2, - for self-power, always 0 */ - struct CONFIG_INFO hs_config_info[3]; - struct CONFIG_INFO fs_config_info[3]; -}; - -enum INDEX_PCB_CONFIG{ - INDEX_SELFPOWER_DIGITAL_ONLY = 0x0, - INDEX_SELFPOWER_DUAL_DIGITAL, - INDEX_SELFPOWER_ANALOG_ONLY, - INDEX_SELFPOWER_DUAL, - INDEX_SELFPOWER_TRIPLE, - INDEX_SELFPOWER_COMPRESSOR, - INDEX_BUSPOWER_DIGITAL_ONLY, - INDEX_BUSPOWER_ANALOG_ONLY, - INDEX_BUSPOWER_DIF_ONLY, - INDEX_BUSPOWER_EXTERNAL_ONLY, - INDEX_BUSPOWER_EXTERNAL_ANALOG, - INDEX_BUSPOWER_EXTERNAL_DIF, - INDEX_BUSPOWER_EXTERNAL_DIGITAL, - INDEX_BUSPOWER_DIGITAL_ANALOG, - INDEX_BUSPOWER_DIGITAL_DIF, - INDEX_BUSPOWER_DIGITAL_ANALOG_EXTERNAL, - INDEX_BUSPOWER_DIGITAL_DIF_EXTERNAL, -}; - -/***************************************************************************/ -struct cx231xx; - -u32 initialize_cx231xx(struct cx231xx *p_dev); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1564 +0,0 @@ -/* - cx231xx-reg.h - driver for Conexant Cx23100/101/102 - USB video capture devices - - Copyright (C) 2008 - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _CX231XX_REG_H -#define _CX231XX_REG_H - -/***************************************************************************** - * VBI codes * -*****************************************************************************/ - -#define SAV_ACTIVE_VIDEO_FIELD1 0x80 -#define EAV_ACTIVE_VIDEO_FIELD1 0x90 - -#define SAV_ACTIVE_VIDEO_FIELD2 0xc0 -#define EAV_ACTIVE_VIDEO_FIELD2 0xd0 - -#define SAV_VBLANK_FIELD1 0xa0 -#define EAV_VBLANK_FIELD1 0xb0 - -#define SAV_VBLANK_FIELD2 0xe0 -#define EAV_VBLANK_FIELD2 0xf0 - -#define SAV_VBI_FIELD1 0x20 -#define EAV_VBI_FIELD1 0x30 - -#define SAV_VBI_FIELD2 0x60 -#define EAV_VBI_FIELD2 0x70 - -/*****************************************************************************/ -/* Audio ADC Registers */ -#define CH_PWR_CTRL1 0x0000000e -#define CH_PWR_CTRL2 0x0000000f -/*****************************************************************************/ - -#define HOST_REG1 0x000 -#define FLD_FORCE_CHIP_SEL 0x80 -#define FLD_AUTO_INC_DIS 0x20 -#define FLD_PREFETCH_EN 0x10 -/* Reserved [2:3] */ -#define FLD_DIGITAL_PWR_DN 0x02 -#define FLD_SLEEP 0x01 - -/*****************************************************************************/ -#define HOST_REG2 0x001 - -/*****************************************************************************/ -#define HOST_REG3 0x002 - -/*****************************************************************************/ -/* added for polaris */ -#define GPIO_PIN_CTL0 0x3 -#define GPIO_PIN_CTL1 0x4 -#define GPIO_PIN_CTL2 0x5 -#define GPIO_PIN_CTL3 0x6 -#define TS1_PIN_CTL0 0x7 -#define TS1_PIN_CTL1 0x8 -/*****************************************************************************/ - -#define FLD_CLK_IN_EN 0x80 -#define FLD_XTAL_CTRL 0x70 -#define FLD_BB_CLK_MODE 0x0C -#define FLD_REF_DIV_PLL 0x02 -#define FLD_REF_SEL_PLL1 0x01 - -/*****************************************************************************/ -#define CHIP_CTRL 0x100 -/* Reserved [27] */ -/* Reserved [31:21] */ -#define FLD_CHIP_ACFG_DIS 0x00100000 -/* Reserved [19] */ -#define FLD_DUAL_MODE_ADC2 0x00040000 -#define FLD_SIF_EN 0x00020000 -#define FLD_SOFT_RST 0x00010000 -#define FLD_DEVICE_ID 0x0000ffff - -/*****************************************************************************/ -#define AFE_CTRL 0x104 -#define AFE_CTRL_C2HH_SRC_CTRL 0x104 -#define FLD_DIF_OUT_SEL 0xc0000000 -#define FLD_AUX_PLL_CLK_ALT_SEL 0x3c000000 -#define FLD_UV_ORDER_MODE 0x02000000 -#define FLD_FUNC_MODE 0x01800000 -#define FLD_ROT1_PHASE_CTL 0x007f8000 -#define FLD_AUD_IN_SEL 0x00004000 -#define FLD_LUMA_IN_SEL 0x00002000 -#define FLD_CHROMA_IN_SEL 0x00001000 -/* reserve [11:10] */ -#define FLD_INV_SPEC_DIS 0x00000200 -#define FLD_VGA_SEL_CH3 0x00000100 -#define FLD_VGA_SEL_CH2 0x00000080 -#define FLD_VGA_SEL_CH1 0x00000040 -#define FLD_DCR_BYP_CH1 0x00000020 -#define FLD_DCR_BYP_CH2 0x00000010 -#define FLD_DCR_BYP_CH3 0x00000008 -#define FLD_EN_12DB_CH3 0x00000004 -#define FLD_EN_12DB_CH2 0x00000002 -#define FLD_EN_12DB_CH1 0x00000001 - -/* redefine in Cx231xx */ -/*****************************************************************************/ -#define DC_CTRL1 0x108 -/* reserve [31:30] */ -#define FLD_CLAMP_LVL_CH1 0x3fff8000 -#define FLD_CLAMP_LVL_CH2 0x00007fff -/*****************************************************************************/ - -/*****************************************************************************/ -#define DC_CTRL2 0x10c -/* reserve [31:28] */ -#define FLD_CLAMP_LVL_CH3 0x00fffe00 -#define FLD_CLAMP_WIND_LENTH 0x000001e0 -#define FLD_C2HH_SAT_MIN 0x0000001e -#define FLD_FLT_BYP_SEL 0x00000001 -/*****************************************************************************/ - -/*****************************************************************************/ -#define DC_CTRL3 0x110 -/* reserve [31:16] */ -#define FLD_ERR_GAIN_CTL 0x00070000 -#define FLD_LPF_MIN 0x0000ffff -/*****************************************************************************/ - -/*****************************************************************************/ -#define DC_CTRL4 0x114 -/* reserve [31:31] */ -#define FLD_INTG_CH1 0x7fffffff -/*****************************************************************************/ - -/*****************************************************************************/ -#define DC_CTRL5 0x118 -/* reserve [31:31] */ -#define FLD_INTG_CH2 0x7fffffff -/*****************************************************************************/ - -/*****************************************************************************/ -#define DC_CTRL6 0x11c -/* reserve [31:31] */ -#define FLD_INTG_CH3 0x7fffffff -/*****************************************************************************/ - -/*****************************************************************************/ -#define PIN_CTRL 0x120 -#define FLD_OEF_AGC_RF 0x00000001 -#define FLD_OEF_AGC_IFVGA 0x00000002 -#define FLD_OEF_AGC_IF 0x00000004 -#define FLD_REG_BO_PUD 0x80000000 -#define FLD_IR_IRQ_STAT 0x40000000 -#define FLD_AUD_IRQ_STAT 0x20000000 -#define FLD_VID_IRQ_STAT 0x10000000 -/* Reserved [27:26] */ -#define FLD_IRQ_N_OUT_EN 0x02000000 -#define FLD_IRQ_N_POLAR 0x01000000 -/* Reserved [23:6] */ -#define FLD_OE_AUX_PLL_CLK 0x00000020 -#define FLD_OE_I2S_BCLK 0x00000010 -#define FLD_OE_I2S_WCLK 0x00000008 -#define FLD_OE_AGC_IF 0x00000004 -#define FLD_OE_AGC_IFVGA 0x00000002 -#define FLD_OE_AGC_RF 0x00000001 - -/*****************************************************************************/ -#define AUD_IO_CTRL 0x124 -/* Reserved [31:8] */ -#define FLD_I2S_PORT_DIR 0x00000080 -#define FLD_I2S_OUT_SRC 0x00000040 -#define FLD_AUD_CHAN3_SRC 0x00000030 -#define FLD_AUD_CHAN2_SRC 0x0000000c -#define FLD_AUD_CHAN1_SRC 0x00000003 - -/*****************************************************************************/ -#define AUD_LOCK1 0x128 -#define FLD_AUD_LOCK_KI_SHIFT 0xc0000000 -#define FLD_AUD_LOCK_KD_SHIFT 0x30000000 -/* Reserved [27:25] */ -#define FLD_EN_AV_LOCK 0x01000000 -#define FLD_VID_COUNT 0x00ffffff - -/*****************************************************************************/ -#define AUD_LOCK2 0x12c -#define FLD_AUD_LOCK_KI_MULT 0xf0000000 -#define FLD_AUD_LOCK_KD_MULT 0x0F000000 -/* Reserved [23:22] */ -#define FLD_AUD_LOCK_FREQ_SHIFT 0x00300000 -#define FLD_AUD_COUNT 0x000fffff - -/*****************************************************************************/ -#define AFE_DIAG_CTRL1 0x134 -/* Reserved [31:16] */ -#define FLD_CUV_DLY_LENGTH 0x0000ff00 -#define FLD_YC_DLY_LENGTH 0x000000ff - -/*****************************************************************************/ -/* Poalris redefine */ -#define AFE_DIAG_CTRL3 0x138 -/* Reserved [31:26] */ -#define FLD_AUD_DUAL_FLAG_POL 0x02000000 -#define FLD_VID_DUAL_FLAG_POL 0x01000000 -/* Reserved [23:23] */ -#define FLD_COL_CLAMP_DIS_CH1 0x00400000 -#define FLD_COL_CLAMP_DIS_CH2 0x00200000 -#define FLD_COL_CLAMP_DIS_CH3 0x00100000 - -#define TEST_CTRL1 0x144 -/* Reserved [31:29] */ -#define FLD_LBIST_EN 0x10000000 -/* Reserved [27:10] */ -#define FLD_FI_BIST_INTR_R 0x0000200 -#define FLD_FI_BIST_INTR_L 0x0000100 -#define FLD_BIST_FAIL_AUD_PLL 0x0000080 -#define FLD_BIST_INTR_AUD_PLL 0x0000040 -#define FLD_BIST_FAIL_VID_PLL 0x0000020 -#define FLD_BIST_INTR_VID_PLL 0x0000010 -/* Reserved [3:1] */ -#define FLD_CIR_TEST_DIS 0x00000001 - -/*****************************************************************************/ -#define TEST_CTRL2 0x148 -#define FLD_TSXCLK_POL_CTL 0x80000000 -#define FLD_ISO_CTL_SEL 0x40000000 -#define FLD_ISO_CTL_EN 0x20000000 -#define FLD_BIST_DEBUGZ 0x10000000 -#define FLD_AUD_BIST_TEST_H 0x0f000000 -/* Reserved [23:22] */ -#define FLD_FLTRN_BIST_TEST_H 0x00020000 -#define FLD_VID_BIST_TEST_H 0x00010000 -/* Reserved [19:17] */ -#define FLD_BIST_TEST_H 0x00010000 -/* Reserved [15:13] */ -#define FLD_TAB_EN 0x00001000 -/* Reserved [11:0] */ - -/*****************************************************************************/ -#define BIST_STAT 0x14c -#define FLD_AUD_BIST_FAIL_H 0xfff00000 -#define FLD_FLTRN_BIST_FAIL_H 0x00180000 -#define FLD_VID_BIST_FAIL_H 0x00070000 -#define FLD_AUD_BIST_TST_DONE 0x0000fff0 -#define FLD_FLTRN_BIST_TST_DONE 0x00000008 -#define FLD_VID_BIST_TST_DONE 0x00000007 - -/*****************************************************************************/ -/* DirectIF registers definition have been moved to DIF_reg.h */ -/*****************************************************************************/ -#define MODE_CTRL 0x400 -#define FLD_AFD_PAL60_DIS 0x20000000 -#define FLD_AFD_FORCE_SECAM 0x10000000 -#define FLD_AFD_FORCE_PALNC 0x08000000 -#define FLD_AFD_FORCE_PAL 0x04000000 -#define FLD_AFD_PALM_SEL 0x03000000 -#define FLD_CKILL_MODE 0x00300000 -#define FLD_COMB_NOTCH_MODE 0x00c00000 /* bit[19:18] */ -#define FLD_CLR_LOCK_STAT 0x00020000 -#define FLD_FAST_LOCK_MD 0x00010000 -#define FLD_WCEN 0x00008000 -#define FLD_CAGCEN 0x00004000 -#define FLD_CKILLEN 0x00002000 -#define FLD_AUTO_SC_LOCK 0x00001000 -#define FLD_MAN_SC_FAST_LOCK 0x00000800 -#define FLD_INPUT_MODE 0x00000600 -#define FLD_AFD_ACQUIRE 0x00000100 -#define FLD_AFD_NTSC_SEL 0x00000080 -#define FLD_AFD_PAL_SEL 0x00000040 -#define FLD_ACFG_DIS 0x00000020 -#define FLD_SQ_PIXEL 0x00000010 -#define FLD_VID_FMT_SEL 0x0000000f - -/*****************************************************************************/ -#define OUT_CTRL1 0x404 -#define FLD_POLAR 0x7f000000 -/* Reserved [23] */ -#define FLD_RND_MODE 0x00600000 -#define FLD_VIPCLAMP_EN 0x00100000 -#define FLD_VIPBLANK_EN 0x00080000 -#define FLD_VIP_OPT_AL 0x00040000 -#define FLD_IDID0_SOURCE 0x00020000 -#define FLD_DCMODE 0x00010000 -#define FLD_CLK_GATING 0x0000c000 -#define FLD_CLK_INVERT 0x00002000 -#define FLD_HSFMT 0x00001000 -#define FLD_VALIDFMT 0x00000800 -#define FLD_ACTFMT 0x00000400 -#define FLD_SWAPRAW 0x00000200 -#define FLD_CLAMPRAW_EN 0x00000100 -#define FLD_BLUE_FIELD_EN 0x00000080 -#define FLD_BLUE_FIELD_ACT 0x00000040 -#define FLD_TASKBIT_VAL 0x00000020 -#define FLD_ANC_DATA_EN 0x00000010 -#define FLD_VBIHACTRAW_EN 0x00000008 -#define FLD_MODE10B 0x00000004 -#define FLD_OUT_MODE 0x00000003 - -/*****************************************************************************/ -#define OUT_CTRL2 0x408 -#define FLD_AUD_GRP 0xc0000000 -#define FLD_SAMPLE_RATE 0x30000000 -#define FLD_AUD_ANC_EN 0x08000000 -#define FLD_EN_C 0x04000000 -#define FLD_EN_B 0x02000000 -#define FLD_EN_A 0x01000000 -/* Reserved [23:20] */ -#define FLD_IDID1_LSB 0x000c0000 -#define FLD_IDID0_LSB 0x00030000 -#define FLD_IDID1_MSB 0x0000ff00 -#define FLD_IDID0_MSB 0x000000ff - -/*****************************************************************************/ -#define GEN_STAT 0x40c -#define FLD_VCR_DETECT 0x00800000 -#define FLD_SPECIAL_PLAY_N 0x00400000 -#define FLD_VPRES 0x00200000 -#define FLD_AGC_LOCK 0x00100000 -#define FLD_CSC_LOCK 0x00080000 -#define FLD_VLOCK 0x00040000 -#define FLD_SRC_LOCK 0x00020000 -#define FLD_HLOCK 0x00010000 -#define FLD_VSYNC_N 0x00008000 -#define FLD_SRC_FIFO_UFLOW 0x00004000 -#define FLD_SRC_FIFO_OFLOW 0x00002000 -#define FLD_FIELD 0x00001000 -#define FLD_AFD_FMT_STAT 0x00000f00 -#define FLD_MV_TYPE2_PAIR 0x00000080 -#define FLD_MV_T3CS 0x00000040 -#define FLD_MV_CS 0x00000020 -#define FLD_MV_PSP 0x00000010 -/* Reserved [3] */ -#define FLD_MV_CDAT 0x00000003 - -/*****************************************************************************/ -#define INT_STAT_MASK 0x410 -#define FLD_COMB_3D_FIFO_MSK 0x80000000 -#define FLD_WSS_DAT_AVAIL_MSK 0x40000000 -#define FLD_GS2_DAT_AVAIL_MSK 0x20000000 -#define FLD_GS1_DAT_AVAIL_MSK 0x10000000 -#define FLD_CC_DAT_AVAIL_MSK 0x08000000 -#define FLD_VPRES_CHANGE_MSK 0x04000000 -#define FLD_MV_CHANGE_MSK 0x02000000 -#define FLD_END_VBI_EVEN_MSK 0x01000000 -#define FLD_END_VBI_ODD_MSK 0x00800000 -#define FLD_FMT_CHANGE_MSK 0x00400000 -#define FLD_VSYNC_TRAIL_MSK 0x00200000 -#define FLD_HLOCK_CHANGE_MSK 0x00100000 -#define FLD_VLOCK_CHANGE_MSK 0x00080000 -#define FLD_CSC_LOCK_CHANGE_MSK 0x00040000 -#define FLD_SRC_FIFO_UFLOW_MSK 0x00020000 -#define FLD_SRC_FIFO_OFLOW_MSK 0x00010000 -#define FLD_COMB_3D_FIFO_STAT 0x00008000 -#define FLD_WSS_DAT_AVAIL_STAT 0x00004000 -#define FLD_GS2_DAT_AVAIL_STAT 0x00002000 -#define FLD_GS1_DAT_AVAIL_STAT 0x00001000 -#define FLD_CC_DAT_AVAIL_STAT 0x00000800 -#define FLD_VPRES_CHANGE_STAT 0x00000400 -#define FLD_MV_CHANGE_STAT 0x00000200 -#define FLD_END_VBI_EVEN_STAT 0x00000100 -#define FLD_END_VBI_ODD_STAT 0x00000080 -#define FLD_FMT_CHANGE_STAT 0x00000040 -#define FLD_VSYNC_TRAIL_STAT 0x00000020 -#define FLD_HLOCK_CHANGE_STAT 0x00000010 -#define FLD_VLOCK_CHANGE_STAT 0x00000008 -#define FLD_CSC_LOCK_CHANGE_STAT 0x00000004 -#define FLD_SRC_FIFO_UFLOW_STAT 0x00000002 -#define FLD_SRC_FIFO_OFLOW_STAT 0x00000001 - -/*****************************************************************************/ -#define LUMA_CTRL 0x414 -#define BRIGHTNESS_CTRL_BYTE 0x414 -#define CONTRAST_CTRL_BYTE 0x415 -#define LUMA_CTRL_BYTE_3 0x416 -#define FLD_LUMA_CORE_SEL 0x00c00000 -#define FLD_RANGE 0x00300000 -/* Reserved [19] */ -#define FLD_PEAK_EN 0x00040000 -#define FLD_PEAK_SEL 0x00030000 -#define FLD_CNTRST 0x0000ff00 -#define FLD_BRITE 0x000000ff - -/*****************************************************************************/ -#define HSCALE_CTRL 0x418 -#define FLD_HFILT 0x03000000 -#define FLD_HSCALE 0x00ffffff - -/*****************************************************************************/ -#define VSCALE_CTRL 0x41c -#define FLD_LINE_AVG_DIS 0x01000000 -/* Reserved [23:20] */ -#define FLD_VS_INTRLACE 0x00080000 -#define FLD_VFILT 0x00070000 -/* Reserved [15:13] */ -#define FLD_VSCALE 0x00001fff - -/*****************************************************************************/ -#define CHROMA_CTRL 0x420 -#define USAT_CTRL_BYTE 0x420 -#define VSAT_CTRL_BYTE 0x421 -#define HUE_CTRL_BYTE 0x422 -#define FLD_C_LPF_EN 0x20000000 -#define FLD_CHR_DELAY 0x1c000000 -#define FLD_C_CORE_SEL 0x03000000 -#define FLD_HUE 0x00ff0000 -#define FLD_VSAT 0x0000ff00 -#define FLD_USAT 0x000000ff - -/*****************************************************************************/ -#define VBI_LINE_CTRL1 0x424 -#define FLD_VBI_MD_LINE4 0xff000000 -#define FLD_VBI_MD_LINE3 0x00ff0000 -#define FLD_VBI_MD_LINE2 0x0000ff00 -#define FLD_VBI_MD_LINE1 0x000000ff - -/*****************************************************************************/ -#define VBI_LINE_CTRL2 0x428 -#define FLD_VBI_MD_LINE8 0xff000000 -#define FLD_VBI_MD_LINE7 0x00ff0000 -#define FLD_VBI_MD_LINE6 0x0000ff00 -#define FLD_VBI_MD_LINE5 0x000000ff - -/*****************************************************************************/ -#define VBI_LINE_CTRL3 0x42c -#define FLD_VBI_MD_LINE12 0xff000000 -#define FLD_VBI_MD_LINE11 0x00ff0000 -#define FLD_VBI_MD_LINE10 0x0000ff00 -#define FLD_VBI_MD_LINE9 0x000000ff - -/*****************************************************************************/ -#define VBI_LINE_CTRL4 0x430 -#define FLD_VBI_MD_LINE16 0xff000000 -#define FLD_VBI_MD_LINE15 0x00ff0000 -#define FLD_VBI_MD_LINE14 0x0000ff00 -#define FLD_VBI_MD_LINE13 0x000000ff - -/*****************************************************************************/ -#define VBI_LINE_CTRL5 0x434 -#define FLD_VBI_MD_LINE17 0x000000ff - -/*****************************************************************************/ -#define VBI_FC_CFG 0x438 -#define FLD_FC_ALT2 0xff000000 -#define FLD_FC_ALT1 0x00ff0000 -#define FLD_FC_ALT2_TYPE 0x0000f000 -#define FLD_FC_ALT1_TYPE 0x00000f00 -/* Reserved [7:1] */ -#define FLD_FC_SEARCH_MODE 0x00000001 - -/*****************************************************************************/ -#define VBI_MISC_CFG1 0x43c -#define FLD_TTX_PKTADRU 0xfff00000 -#define FLD_TTX_PKTADRL 0x000fff00 -/* Reserved [7:6] */ -#define FLD_MOJI_PACK_DIS 0x00000020 -#define FLD_VPS_DEC_DIS 0x00000010 -#define FLD_CRI_MARG_SCALE 0x0000000c -#define FLD_EDGE_RESYNC_EN 0x00000002 -#define FLD_ADAPT_SLICE_DIS 0x00000001 - -/*****************************************************************************/ -#define VBI_MISC_CFG2 0x440 -#define FLD_HAMMING_TYPE 0x0f000000 -/* Reserved [23:20] */ -#define FLD_WSS_FIFO_RST 0x00080000 -#define FLD_GS2_FIFO_RST 0x00040000 -#define FLD_GS1_FIFO_RST 0x00020000 -#define FLD_CC_FIFO_RST 0x00010000 -/* Reserved [15:12] */ -#define FLD_VBI3_SDID 0x00000f00 -#define FLD_VBI2_SDID 0x000000f0 -#define FLD_VBI1_SDID 0x0000000f - -/*****************************************************************************/ -#define VBI_PAY1 0x444 -#define FLD_GS1_FIFO_DAT 0xFF000000 -#define FLD_GS1_STAT 0x00FF0000 -#define FLD_CC_FIFO_DAT 0x0000FF00 -#define FLD_CC_STAT 0x000000FF - -/*****************************************************************************/ -#define VBI_PAY2 0x448 -#define FLD_WSS_FIFO_DAT 0xff000000 -#define FLD_WSS_STAT 0x00ff0000 -#define FLD_GS2_FIFO_DAT 0x0000ff00 -#define FLD_GS2_STAT 0x000000ff - -/*****************************************************************************/ -#define VBI_CUST1_CFG1 0x44c -/* Reserved [31] */ -#define FLD_VBI1_CRIWIN 0x7f000000 -#define FLD_VBI1_SLICE_DIST 0x00f00000 -#define FLD_VBI1_BITINC 0x000fff00 -#define FLD_VBI1_HDELAY 0x000000ff - -/*****************************************************************************/ -#define VBI_CUST1_CFG2 0x450 -#define FLD_VBI1_FC_LENGTH 0x1f000000 -#define FLD_VBI1_FRAME_CODE 0x00ffffff - -/*****************************************************************************/ -#define VBI_CUST1_CFG3 0x454 -#define FLD_VBI1_HAM_EN 0x80000000 -#define FLD_VBI1_FIFO_MODE 0x70000000 -#define FLD_VBI1_FORMAT_TYPE 0x0f000000 -#define FLD_VBI1_PAYLD_LENGTH 0x00ff0000 -#define FLD_VBI1_CRI_LENGTH 0x0000f000 -#define FLD_VBI1_CRI_MARGIN 0x00000f00 -#define FLD_VBI1_CRI_TIME 0x000000ff - -/*****************************************************************************/ -#define VBI_CUST2_CFG1 0x458 -/* Reserved [31] */ -#define FLD_VBI2_CRIWIN 0x7f000000 -#define FLD_VBI2_SLICE_DIST 0x00f00000 -#define FLD_VBI2_BITINC 0x000fff00 -#define FLD_VBI2_HDELAY 0x000000ff - -/*****************************************************************************/ -#define VBI_CUST2_CFG2 0x45c -#define FLD_VBI2_FC_LENGTH 0x1f000000 -#define FLD_VBI2_FRAME_CODE 0x00ffffff - -/*****************************************************************************/ -#define VBI_CUST2_CFG3 0x460 -#define FLD_VBI2_HAM_EN 0x80000000 -#define FLD_VBI2_FIFO_MODE 0x70000000 -#define FLD_VBI2_FORMAT_TYPE 0x0f000000 -#define FLD_VBI2_PAYLD_LENGTH 0x00ff0000 -#define FLD_VBI2_CRI_LENGTH 0x0000f000 -#define FLD_VBI2_CRI_MARGIN 0x00000f00 -#define FLD_VBI2_CRI_TIME 0x000000ff - -/*****************************************************************************/ -#define VBI_CUST3_CFG1 0x464 -/* Reserved [31] */ -#define FLD_VBI3_CRIWIN 0x7f000000 -#define FLD_VBI3_SLICE_DIST 0x00f00000 -#define FLD_VBI3_BITINC 0x000fff00 -#define FLD_VBI3_HDELAY 0x000000ff - -/*****************************************************************************/ -#define VBI_CUST3_CFG2 0x468 -#define FLD_VBI3_FC_LENGTH 0x1f000000 -#define FLD_VBI3_FRAME_CODE 0x00ffffff - -/*****************************************************************************/ -#define VBI_CUST3_CFG3 0x46c -#define FLD_VBI3_HAM_EN 0x80000000 -#define FLD_VBI3_FIFO_MODE 0x70000000 -#define FLD_VBI3_FORMAT_TYPE 0x0f000000 -#define FLD_VBI3_PAYLD_LENGTH 0x00ff0000 -#define FLD_VBI3_CRI_LENGTH 0x0000f000 -#define FLD_VBI3_CRI_MARGIN 0x00000f00 -#define FLD_VBI3_CRI_TIME 0x000000ff - -/*****************************************************************************/ -#define HORIZ_TIM_CTRL 0x470 -#define FLD_BGDEL_CNT 0xff000000 -/* Reserved [23:22] */ -#define FLD_HACTIVE_CNT 0x003ff000 -/* Reserved [11:10] */ -#define FLD_HBLANK_CNT 0x000003ff - -/*****************************************************************************/ -#define VERT_TIM_CTRL 0x474 -#define FLD_V656BLANK_CNT 0xff000000 -/* Reserved [23:22] */ -#define FLD_VACTIVE_CNT 0x003ff000 -/* Reserved [11:10] */ -#define FLD_VBLANK_CNT 0x000003ff - -/*****************************************************************************/ -#define SRC_COMB_CFG 0x478 -#define FLD_CCOMB_2LN_CHECK 0x80000000 -#define FLD_CCOMB_3LN_EN 0x40000000 -#define FLD_CCOMB_2LN_EN 0x20000000 -#define FLD_CCOMB_3D_EN 0x10000000 -/* Reserved [27] */ -#define FLD_LCOMB_3LN_EN 0x04000000 -#define FLD_LCOMB_2LN_EN 0x02000000 -#define FLD_LCOMB_3D_EN 0x01000000 -#define FLD_LUMA_LPF_SEL 0x00c00000 -#define FLD_UV_LPF_SEL 0x00300000 -#define FLD_BLEND_SLOPE 0x000f0000 -#define FLD_CCOMB_REDUCE_EN 0x00008000 -/* Reserved [14:10] */ -#define FLD_SRC_DECIM_RATIO 0x000003ff - -/*****************************************************************************/ -#define CHROMA_VBIOFF_CFG 0x47c -#define FLD_VBI_VOFFSET 0x1f000000 -/* Reserved [23:20] */ -#define FLD_SC_STEP 0x000fffff - -/*****************************************************************************/ -#define FIELD_COUNT 0x480 -#define FLD_FIELD_COUNT_FLD 0x000003ff - -/*****************************************************************************/ -#define MISC_TIM_CTRL 0x484 -#define FLD_DEBOUNCE_COUNT 0xc0000000 -#define FLD_VT_LINE_CNT_HYST 0x30000000 -/* Reserved [27] */ -#define FLD_AFD_STAT 0x07ff0000 -#define FLD_VPRES_VERT_EN 0x00008000 -/* Reserved [14:12] */ -#define FLD_HR32 0x00000800 -#define FLD_TDALGN 0x00000400 -#define FLD_TDFIELD 0x00000200 -/* Reserved [8:6] */ -#define FLD_TEMPDEC 0x0000003f - -/*****************************************************************************/ -#define DFE_CTRL1 0x488 -#define FLD_CLAMP_AUTO_EN 0x80000000 -#define FLD_AGC_AUTO_EN 0x40000000 -#define FLD_VGA_CRUSH_EN 0x20000000 -#define FLD_VGA_AUTO_EN 0x10000000 -#define FLD_VBI_GATE_EN 0x08000000 -#define FLD_CLAMP_LEVEL 0x07000000 -/* Reserved [23:22] */ -#define FLD_CLAMP_SKIP_CNT 0x00300000 -#define FLD_AGC_GAIN 0x000fff00 -/* Reserved [7:6] */ -#define FLD_VGA_GAIN 0x0000003f - -/*****************************************************************************/ -#define DFE_CTRL2 0x48c -#define FLD_VGA_ACQUIRE_RANGE 0x00ff0000 -#define FLD_VGA_TRACK_RANGE 0x0000ff00 -#define FLD_VGA_SYNC 0x000000ff - -/*****************************************************************************/ -#define DFE_CTRL3 0x490 -#define FLD_BP_PERCENT 0xff000000 -#define FLD_DFT_THRESHOLD 0x00ff0000 -/* Reserved [15:12] */ -#define FLD_SYNC_WIDTH_SEL 0x00000600 -#define FLD_BP_LOOP_GAIN 0x00000300 -#define FLD_SYNC_LOOP_GAIN 0x000000c0 -/* Reserved [5:4] */ -#define FLD_AGC_LOOP_GAIN 0x0000000c -#define FLD_DCC_LOOP_GAIN 0x00000003 - -/*****************************************************************************/ -#define PLL_CTRL 0x494 -#define FLD_PLL_KD 0xff000000 -#define FLD_PLL_KI 0x00ff0000 -#define FLD_PLL_MAX_OFFSET 0x0000ffff - -/*****************************************************************************/ -#define HTL_CTRL 0x498 -/* Reserved [31:24] */ -#define FLD_AUTO_LOCK_SPD 0x00080000 -#define FLD_MAN_FAST_LOCK 0x00040000 -#define FLD_HTL_15K_EN 0x00020000 -#define FLD_HTL_500K_EN 0x00010000 -#define FLD_HTL_KD 0x0000ff00 -#define FLD_HTL_KI 0x000000ff - -/*****************************************************************************/ -#define COMB_CTRL 0x49c -#define FLD_COMB_PHASE_LIMIT 0xff000000 -#define FLD_CCOMB_ERR_LIMIT 0x00ff0000 -#define FLD_LUMA_THRESHOLD 0x0000ff00 -#define FLD_LCOMB_ERR_LIMIT 0x000000ff - -/*****************************************************************************/ -#define CRUSH_CTRL 0x4a0 -#define FLD_WTW_EN 0x00400000 -#define FLD_CRUSH_FREQ 0x00200000 -#define FLD_MAJ_SEL_EN 0x00100000 -#define FLD_MAJ_SEL 0x000c0000 -/* Reserved [17:15] */ -#define FLD_SYNC_TIP_REDUCE 0x00007e00 -/* Reserved [8:6] */ -#define FLD_SYNC_TIP_INC 0x0000003f - -/*****************************************************************************/ -#define SOFT_RST_CTRL 0x4a4 -#define FLD_VD_SOFT_RST 0x00008000 -/* Reserved [14:12] */ -#define FLD_REG_RST_MSK 0x00000800 -#define FLD_VOF_RST_MSK 0x00000400 -#define FLD_MVDET_RST_MSK 0x00000200 -#define FLD_VBI_RST_MSK 0x00000100 -#define FLD_SCALE_RST_MSK 0x00000080 -#define FLD_CHROMA_RST_MSK 0x00000040 -#define FLD_LUMA_RST_MSK 0x00000020 -#define FLD_VTG_RST_MSK 0x00000010 -#define FLD_YCSEP_RST_MSK 0x00000008 -#define FLD_SRC_RST_MSK 0x00000004 -#define FLD_DFE_RST_MSK 0x00000002 -/* Reserved [0] */ - -/*****************************************************************************/ -#define MV_DT_CTRL1 0x4a8 -/* Reserved [31:29] */ -#define FLD_PSP_STOP_LINE 0x1f000000 -/* Reserved [23:21] */ -#define FLD_PSP_STRT_LINE 0x001f0000 -/* Reserved [15] */ -#define FLD_PSP_LLIMW 0x00007f00 -/* Reserved [7] */ -#define FLD_PSP_ULIMW 0x0000007f - -/*****************************************************************************/ -#define MV_DT_CTRL2 0x4aC -#define FLD_CS_STOPWIN 0xff000000 -#define FLD_CS_STRTWIN 0x00ff0000 -#define FLD_CS_WIDTH 0x0000ff00 -#define FLD_PSP_SPEC_VAL 0x000000ff - -/*****************************************************************************/ -#define MV_DT_CTRL3 0x4B0 -#define FLD_AUTO_RATE_DIS 0x80000000 -#define FLD_HLOCK_DIS 0x40000000 -#define FLD_SEL_FIELD_CNT 0x20000000 -#define FLD_CS_TYPE2_SEL 0x10000000 -#define FLD_CS_LINE_THRSH_SEL 0x08000000 -#define FLD_CS_ATHRESH_SEL 0x04000000 -#define FLD_PSP_SPEC_SEL 0x02000000 -#define FLD_PSP_LINES_SEL 0x01000000 -#define FLD_FIELD_CNT 0x00f00000 -#define FLD_CS_TYPE2_CNT 0x000fc000 -#define FLD_CS_LINE_CNT 0x00003f00 -#define FLD_CS_ATHRESH_LEV 0x000000ff - -/*****************************************************************************/ -#define CHIP_VERSION 0x4b4 -/* Cx231xx redefine */ -#define VERSION 0x4b4 -#define FLD_REV_ID 0x000000ff - -/*****************************************************************************/ -#define MISC_DIAG_CTRL 0x4b8 -/* Reserved [31:24] */ -#define FLD_SC_CONVERGE_THRESH 0x00ff0000 -#define FLD_CCOMB_ERR_LIMIT_3D 0x0000ff00 -#define FLD_LCOMB_ERR_LIMIT_3D 0x000000ff - -/*****************************************************************************/ -#define VBI_PASS_CTRL 0x4bc -#define FLD_VBI_PASS_MD 0x00200000 -#define FLD_VBI_SETUP_DIS 0x00100000 -#define FLD_PASS_LINE_CTRL 0x000fffff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define VCR_DET_CTRL 0x4c0 -#define FLD_EN_FIELD_PHASE_DET 0x80000000 -#define FLD_EN_HEAD_SW_DET 0x40000000 -#define FLD_FIELD_PHASE_LENGTH 0x01ff0000 -/* Reserved [29:25] */ -#define FLD_FIELD_PHASE_DELAY 0x0000ff00 -#define FLD_FIELD_PHASE_LIMIT 0x000000f0 -#define FLD_HEAD_SW_DET_LIMIT 0x0000000f - -/*****************************************************************************/ -#define DL_CTL 0x800 -#define DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */ -#define DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */ -#define DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */ -#define DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */ -/* Reserved [31:5] */ -#define FLD_START_8051 0x10000000 -#define FLD_DL_ENABLE 0x08000000 -#define FLD_DL_AUTO_INC 0x04000000 -#define FLD_DL_MAP 0x03000000 - -/*****************************************************************************/ -#define STD_DET_STATUS 0x804 -#define FLD_SPARE_STATUS1 0xff000000 -#define FLD_SPARE_STATUS0 0x00ff0000 -#define FLD_MOD_DET_STATUS1 0x0000ff00 -#define FLD_MOD_DET_STATUS0 0x000000ff - -/*****************************************************************************/ -#define AUD_BUILD_NUM 0x806 -#define AUD_VER_NUM 0x807 -#define STD_DET_CTL 0x808 -#define STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */ -#define STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */ -#define FLD_SPARE_CTL0 0xff000000 -#define FLD_DIS_DBX 0x00800000 -#define FLD_DIS_BTSC 0x00400000 -#define FLD_DIS_NICAM_A2 0x00200000 -#define FLD_VIDEO_PRESENT 0x00100000 -#define FLD_DW8051_VIDEO_FORMAT 0x000f0000 -#define FLD_PREF_DEC_MODE 0x0000ff00 -#define FLD_AUD_CONFIG 0x000000ff - -/*****************************************************************************/ -#define DW8051_INT 0x80c -#define FLD_VIDEO_PRESENT_CHANGE 0x80000000 -#define FLD_VIDEO_CHANGE 0x40000000 -#define FLD_RDS_READY 0x20000000 -#define FLD_AC97_INT 0x10000000 -#define FLD_NICAM_BIT_ERROR_TOO_HIGH 0x08000000 -#define FLD_NICAM_LOCK 0x04000000 -#define FLD_NICAM_UNLOCK 0x02000000 -#define FLD_DFT4_TH_CMP 0x01000000 -/* Reserved [23:22] */ -#define FLD_LOCK_IND_INT 0x00200000 -#define FLD_DFT3_TH_CMP 0x00100000 -#define FLD_DFT2_TH_CMP 0x00080000 -#define FLD_DFT1_TH_CMP 0x00040000 -#define FLD_FM2_DFT_TH_CMP 0x00020000 -#define FLD_FM1_DFT_TH_CMP 0x00010000 -#define FLD_VIDEO_PRESENT_EN 0x00008000 -#define FLD_VIDEO_CHANGE_EN 0x00004000 -#define FLD_RDS_READY_EN 0x00002000 -#define FLD_AC97_INT_EN 0x00001000 -#define FLD_NICAM_BIT_ERROR_TOO_HIGH_EN 0x00000800 -#define FLD_NICAM_LOCK_EN 0x00000400 -#define FLD_NICAM_UNLOCK_EN 0x00000200 -#define FLD_DFT4_TH_CMP_EN 0x00000100 -/* Reserved [7] */ -#define FLD_DW8051_INT6_CTL1 0x00000040 -#define FLD_DW8051_INT5_CTL1 0x00000020 -#define FLD_DW8051_INT4_CTL1 0x00000010 -#define FLD_DW8051_INT3_CTL1 0x00000008 -#define FLD_DW8051_INT2_CTL1 0x00000004 -#define FLD_DW8051_INT1_CTL1 0x00000002 -#define FLD_DW8051_INT0_CTL1 0x00000001 - -/*****************************************************************************/ -#define GENERAL_CTL 0x810 -#define FLD_RDS_INT 0x80000000 -#define FLD_NBER_INT 0x40000000 -#define FLD_NLL_INT 0x20000000 -#define FLD_IFL_INT 0x10000000 -#define FLD_FDL_INT 0x08000000 -#define FLD_AFC_INT 0x04000000 -#define FLD_AMC_INT 0x02000000 -#define FLD_AC97_INT_CTL 0x01000000 -#define FLD_RDS_INT_DIS 0x00800000 -#define FLD_NBER_INT_DIS 0x00400000 -#define FLD_NLL_INT_DIS 0x00200000 -#define FLD_IFL_INT_DIS 0x00100000 -#define FLD_FDL_INT_DIS 0x00080000 -#define FLD_FC_INT_DIS 0x00040000 -#define FLD_AMC_INT_DIS 0x00020000 -#define FLD_AC97_INT_DIS 0x00010000 -#define FLD_REV_NUM 0x0000ff00 -/* Reserved [7:5] */ -#define FLD_DBX_SOFT_RESET_REG 0x00000010 -#define FLD_AD_SOFT_RESET_REG 0x00000008 -#define FLD_SRC_SOFT_RESET_REG 0x00000004 -#define FLD_CDMOD_SOFT_RESET 0x00000002 -#define FLD_8051_SOFT_RESET 0x00000001 - -/*****************************************************************************/ -#define AAGC_CTL 0x814 -#define FLD_AFE_12DB_EN 0x80000000 -#define FLD_AAGC_DEFAULT_EN 0x40000000 -#define FLD_AAGC_DEFAULT 0x3f000000 -/* Reserved [23] */ -#define FLD_AAGC_GAIN 0x00600000 -#define FLD_AAGC_TH 0x001f0000 -/* Reserved [15:14] */ -#define FLD_AAGC_HYST2 0x00003f00 -/* Reserved [7:6] */ -#define FLD_AAGC_HYST1 0x0000003f - -/*****************************************************************************/ -#define IF_SRC_CTL 0x818 -#define FLD_DBX_BYPASS 0x80000000 -/* Reserved [30:25] */ -#define FLD_IF_SRC_MODE 0x01000000 -/* Reserved [23:18] */ -#define FLD_IF_SRC_PHASE_INC 0x0001ffff - -/*****************************************************************************/ -#define ANALOG_DEMOD_CTL 0x81c -#define FLD_ROT1_PHACC_PROG 0xffff0000 -/* Reserved [15] */ -#define FLD_FM1_DELAY_FIX 0x00007000 -#define FLD_PDF4_SHIFT 0x00000c00 -#define FLD_PDF3_SHIFT 0x00000300 -#define FLD_PDF2_SHIFT 0x000000c0 -#define FLD_PDF1_SHIFT 0x00000030 -#define FLD_FMBYPASS_MODE2 0x00000008 -#define FLD_FMBYPASS_MODE1 0x00000004 -#define FLD_NICAM_MODE 0x00000002 -#define FLD_BTSC_FMRADIO_MODE 0x00000001 - -/*****************************************************************************/ -#define ROT_FREQ_CTL 0x820 -#define FLD_ROT3_PHACC_PROG 0xffff0000 -#define FLD_ROT2_PHACC_PROG 0x0000ffff - -/*****************************************************************************/ -#define FM_CTL 0x824 -#define FLD_FM2_DC_FB_SHIFT 0xf0000000 -#define FLD_FM2_DC_INT_SHIFT 0x0f000000 -#define FLD_FM2_AFC_RESET 0x00800000 -#define FLD_FM2_DC_PASS_IN 0x00400000 -#define FLD_FM2_DAGC_SHIFT 0x00380000 -#define FLD_FM2_CORDIC_SHIFT 0x00070000 -#define FLD_FM1_DC_FB_SHIFT 0x0000f000 -#define FLD_FM1_DC_INT_SHIFT 0x00000f00 -#define FLD_FM1_AFC_RESET 0x00000080 -#define FLD_FM1_DC_PASS_IN 0x00000040 -#define FLD_FM1_DAGC_SHIFT 0x00000038 -#define FLD_FM1_CORDIC_SHIFT 0x00000007 - -/*****************************************************************************/ -#define LPF_PDF_CTL 0x828 -/* Reserved [31:30] */ -#define FLD_LPF32_SHIFT1 0x30000000 -#define FLD_LPF32_SHIFT2 0x0c000000 -#define FLD_LPF160_SHIFTA 0x03000000 -#define FLD_LPF160_SHIFTB 0x00c00000 -#define FLD_LPF160_SHIFTC 0x00300000 -#define FLD_LPF32_COEF_SEL2 0x000c0000 -#define FLD_LPF32_COEF_SEL1 0x00030000 -#define FLD_LPF160_COEF_SELC 0x0000c000 -#define FLD_LPF160_COEF_SELB 0x00003000 -#define FLD_LPF160_COEF_SELA 0x00000c00 -#define FLD_LPF160_IN_EN_REG 0x00000300 -#define FLD_PDF4_PDF_SEL 0x000000c0 -#define FLD_PDF3_PDF_SEL 0x00000030 -#define FLD_PDF2_PDF_SEL 0x0000000c -#define FLD_PDF1_PDF_SEL 0x00000003 - -/*****************************************************************************/ -#define DFT1_CTL1 0x82c -#define FLD_DFT1_DWELL 0xffff0000 -#define FLD_DFT1_FREQ 0x0000ffff - -/*****************************************************************************/ -#define DFT1_CTL2 0x830 -#define FLD_DFT1_THRESHOLD 0xffffff00 -#define FLD_DFT1_CMP_CTL 0x00000080 -#define FLD_DFT1_AVG 0x00000070 -/* Reserved [3:1] */ -#define FLD_DFT1_START 0x00000001 - -/*****************************************************************************/ -#define DFT1_STATUS 0x834 -#define FLD_DFT1_DONE 0x80000000 -#define FLD_DFT1_TH_CMP_STAT 0x40000000 -#define FLD_DFT1_RESULT 0x3fffffff - -/*****************************************************************************/ -#define DFT2_CTL1 0x838 -#define FLD_DFT2_DWELL 0xffff0000 -#define FLD_DFT2_FREQ 0x0000ffff - -/*****************************************************************************/ -#define DFT2_CTL2 0x83C -#define FLD_DFT2_THRESHOLD 0xffffff00 -#define FLD_DFT2_CMP_CTL 0x00000080 -#define FLD_DFT2_AVG 0x00000070 -/* Reserved [3:1] */ -#define FLD_DFT2_START 0x00000001 - -/*****************************************************************************/ -#define DFT2_STATUS 0x840 -#define FLD_DFT2_DONE 0x80000000 -#define FLD_DFT2_TH_CMP_STAT 0x40000000 -#define FLD_DFT2_RESULT 0x3fffffff - -/*****************************************************************************/ -#define DFT3_CTL1 0x844 -#define FLD_DFT3_DWELL 0xffff0000 -#define FLD_DFT3_FREQ 0x0000ffff - -/*****************************************************************************/ -#define DFT3_CTL2 0x848 -#define FLD_DFT3_THRESHOLD 0xffffff00 -#define FLD_DFT3_CMP_CTL 0x00000080 -#define FLD_DFT3_AVG 0x00000070 -/* Reserved [3:1] */ -#define FLD_DFT3_START 0x00000001 - -/*****************************************************************************/ -#define DFT3_STATUS 0x84c -#define FLD_DFT3_DONE 0x80000000 -#define FLD_DFT3_TH_CMP_STAT 0x40000000 -#define FLD_DFT3_RESULT 0x3fffffff - -/*****************************************************************************/ -#define DFT4_CTL1 0x850 -#define FLD_DFT4_DWELL 0xffff0000 -#define FLD_DFT4_FREQ 0x0000ffff - -/*****************************************************************************/ -#define DFT4_CTL2 0x854 -#define FLD_DFT4_THRESHOLD 0xffffff00 -#define FLD_DFT4_CMP_CTL 0x00000080 -#define FLD_DFT4_AVG 0x00000070 -/* Reserved [3:1] */ -#define FLD_DFT4_START 0x00000001 - -/*****************************************************************************/ -#define DFT4_STATUS 0x858 -#define FLD_DFT4_DONE 0x80000000 -#define FLD_DFT4_TH_CMP_STAT 0x40000000 -#define FLD_DFT4_RESULT 0x3fffffff - -/*****************************************************************************/ -#define AM_MTS_DET 0x85c -#define FLD_AM_MTS_MODE 0x80000000 -/* Reserved [30:26] */ -#define FLD_AM_SUB 0x02000000 -#define FLD_AM_GAIN_EN 0x01000000 -/* Reserved [23:16] */ -#define FLD_AMMTS_GAIN_SCALE 0x0000e000 -#define FLD_MTS_PDF_SHIFT 0x00001800 -#define FLD_AM_REG_GAIN 0x00000700 -#define FLD_AGC_REF 0x000000ff - -/*****************************************************************************/ -#define ANALOG_MUX_CTL 0x860 -/* Reserved [31:29] */ -#define FLD_MUX21_SEL 0x10000000 -#define FLD_MUX20_SEL 0x08000000 -#define FLD_MUX19_SEL 0x04000000 -#define FLD_MUX18_SEL 0x02000000 -#define FLD_MUX17_SEL 0x01000000 -#define FLD_MUX16_SEL 0x00800000 -#define FLD_MUX15_SEL 0x00400000 -#define FLD_MUX14_SEL 0x00300000 -#define FLD_MUX13_SEL 0x000C0000 -#define FLD_MUX12_SEL 0x00020000 -#define FLD_MUX11_SEL 0x00018000 -#define FLD_MUX10_SEL 0x00004000 -#define FLD_MUX9_SEL 0x00002000 -#define FLD_MUX8_SEL 0x00001000 -#define FLD_MUX7_SEL 0x00000800 -#define FLD_MUX6_SEL 0x00000600 -#define FLD_MUX5_SEL 0x00000100 -#define FLD_MUX4_SEL 0x000000c0 -#define FLD_MUX3_SEL 0x00000030 -#define FLD_MUX2_SEL 0x0000000c -#define FLD_MUX1_SEL 0x00000003 - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DPLL_CTRL1 0x864 -#define DIG_PLL_CTL1 0x864 - -#define FLD_PLL_STATUS 0x07000000 -#define FLD_BANDWIDTH_SELECT 0x00030000 -#define FLD_PLL_SHIFT_REG 0x00007000 -#define FLD_PHASE_SHIFT 0x000007ff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DPLL_CTRL2 0x868 -#define DIG_PLL_CTL2 0x868 -#define FLD_PLL_UNLOCK_THR 0xff000000 -#define FLD_PLL_LOCK_THR 0x00ff0000 -/* Reserved [15:8] */ -#define FLD_AM_PDF_SEL2 0x000000c0 -#define FLD_AM_PDF_SEL1 0x00000030 -#define FLD_DPLL_FSM_CTRL 0x0000000c -/* Reserved [1] */ -#define FLD_PLL_PILOT_DET 0x00000001 - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DPLL_CTRL3 0x86c -#define DIG_PLL_CTL3 0x86c -#define FLD_DISABLE_LOOP 0x01000000 -#define FLD_A1_DS1_SEL 0x000c0000 -#define FLD_A1_DS2_SEL 0x00030000 -#define FLD_A1_KI 0x0000ff00 -#define FLD_A1_KD 0x000000ff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DPLL_CTRL4 0x870 -#define DIG_PLL_CTL4 0x870 -#define FLD_A2_DS1_SEL 0x000c0000 -#define FLD_A2_DS2_SEL 0x00030000 -#define FLD_A2_KI 0x0000ff00 -#define FLD_A2_KD 0x000000ff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DPLL_CTRL5 0x874 -#define DIG_PLL_CTL5 0x874 -#define FLD_TRK_DS1_SEL 0x000c0000 -#define FLD_TRK_DS2_SEL 0x00030000 -#define FLD_TRK_KI 0x0000ff00 -#define FLD_TRK_KD 0x000000ff - -/*****************************************************************************/ -#define DEEMPH_GAIN_CTL 0x878 -#define FLD_DEEMPH2_GAIN 0xFFFF0000 -#define FLD_DEEMPH1_GAIN 0x0000FFFF - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DEEMPH_COEFF1 0x87c -#define DEEMPH_COEF1 0x87c -#define FLD_DEEMPH_B0 0xffff0000 -#define FLD_DEEMPH_A0 0x0000ffff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DEEMPH_COEFF2 0x880 -#define DEEMPH_COEF2 0x880 -#define FLD_DEEMPH_B1 0xFFFF0000 -#define FLD_DEEMPH_A1 0x0000FFFF - -/*****************************************************************************/ -#define DBX1_CTL1 0x884 -#define FLD_DBX1_WBE_GAIN 0xffff0000 -#define FLD_DBX1_IN_GAIN 0x0000ffff - -/*****************************************************************************/ -#define DBX1_CTL2 0x888 -#define FLD_DBX1_SE_BYPASS 0xffff0000 -#define FLD_DBX1_SE_GAIN 0x0000ffff - -/*****************************************************************************/ -#define DBX1_RMS_SE 0x88C -#define FLD_DBX1_RMS_WBE 0xffff0000 -#define FLD_DBX1_RMS_SE_FLD 0x0000ffff - -/*****************************************************************************/ -#define DBX2_CTL1 0x890 -#define FLD_DBX2_WBE_GAIN 0xffff0000 -#define FLD_DBX2_IN_GAIN 0x0000ffff - -/*****************************************************************************/ -#define DBX2_CTL2 0x894 -#define FLD_DBX2_SE_BYPASS 0xffff0000 -#define FLD_DBX2_SE_GAIN 0x0000ffff - -/*****************************************************************************/ -#define DBX2_RMS_SE 0x898 -#define FLD_DBX2_RMS_WBE 0xffff0000 -#define FLD_DBX2_RMS_SE_FLD 0x0000ffff - -/*****************************************************************************/ -#define AM_FM_DIFF 0x89c -/* Reserved [31] */ -#define FLD_FM_DIFF_OUT 0x7fff0000 -/* Reserved [15] */ -#define FLD_AM_DIFF_OUT 0x00007fff - -/*****************************************************************************/ -#define NICAM_FAW 0x8a0 -#define FLD_FAWDETWINEND 0xFc000000 -#define FLD_FAWDETWINSTR 0x03ff0000 -/* Reserved [15:12] */ -#define FLD_FAWDETTHRSHLD3 0x00000f00 -#define FLD_FAWDETTHRSHLD2 0x000000f0 -#define FLD_FAWDETTHRSHLD1 0x0000000f - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DEEMPH_GAIN 0x8a4 -#define NICAM_DEEMPHGAIN 0x8a4 -/* Reserved [31:18] */ -#define FLD_DEEMPHGAIN 0x0003ffff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DEEMPH_NUMER1 0x8a8 -#define NICAM_DEEMPHNUMER1 0x8a8 -/* Reserved [31:18] */ -#define FLD_DEEMPHNUMER1 0x0003ffff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DEEMPH_NUMER2 0x8ac -#define NICAM_DEEMPHNUMER2 0x8ac -/* Reserved [31:18] */ -#define FLD_DEEMPHNUMER2 0x0003ffff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DEEMPH_DENOM1 0x8b0 -#define NICAM_DEEMPHDENOM1 0x8b0 -/* Reserved [31:18] */ -#define FLD_DEEMPHDENOM1 0x0003ffff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define DEEMPH_DENOM2 0x8b4 -#define NICAM_DEEMPHDENOM2 0x8b4 -/* Reserved [31:18] */ -#define FLD_DEEMPHDENOM2 0x0003ffff - -/*****************************************************************************/ -#define NICAM_ERRLOG_CTL1 0x8B8 -/* Reserved [31:28] */ -#define FLD_ERRINTRPTTHSHLD1 0x0fff0000 -/* Reserved [15:12] */ -#define FLD_ERRLOGPERIOD 0x00000fff - -/*****************************************************************************/ -#define NICAM_ERRLOG_CTL2 0x8bc -/* Reserved [31:28] */ -#define FLD_ERRINTRPTTHSHLD3 0x0fff0000 -/* Reserved [15:12] */ -#define FLD_ERRINTRPTTHSHLD2 0x00000fff - -/*****************************************************************************/ -#define NICAM_ERRLOG_STS1 0x8c0 -/* Reserved [31:28] */ -#define FLD_ERRLOG2 0x0fff0000 -/* Reserved [15:12] */ -#define FLD_ERRLOG1 0x00000fff - -/*****************************************************************************/ -#define NICAM_ERRLOG_STS2 0x8c4 -/* Reserved [31:12] */ -#define FLD_ERRLOG3 0x00000fff - -/*****************************************************************************/ -#define NICAM_STATUS 0x8c8 -/* Reserved [31:20] */ -#define FLD_NICAM_CIB 0x000c0000 -#define FLD_NICAM_LOCK_STAT 0x00020000 -#define FLD_NICAM_MUTE 0x00010000 -#define FLD_NICAMADDIT_DATA 0x0000ffe0 -#define FLD_NICAMCNTRL 0x0000001f - -/*****************************************************************************/ -#define DEMATRIX_CTL 0x8cc -#define FLD_AC97_IN_SHIFT 0xf0000000 -#define FLD_I2S_IN_SHIFT 0x0f000000 -#define FLD_DEMATRIX_SEL_CTL 0x00ff0000 -/* Reserved [15:11] */ -#define FLD_DMTRX_BYPASS 0x00000400 -#define FLD_DEMATRIX_MODE 0x00000300 -/* Reserved [7:6] */ -#define FLD_PH_DBX_SEL 0x00000020 -#define FLD_PH_CH_SEL 0x00000010 -#define FLD_PHASE_FIX 0x0000000f - -/*****************************************************************************/ -#define PATH1_CTL1 0x8d0 -/* Reserved [31:29] */ -#define FLD_PATH1_MUTE_CTL 0x1f000000 -/* Reserved [23:22] */ -#define FLD_PATH1_AVC_CG 0x00300000 -#define FLD_PATH1_AVC_RT 0x000f0000 -#define FLD_PATH1_AVC_AT 0x0000f000 -#define FLD_PATH1_AVC_STEREO 0x00000800 -#define FLD_PATH1_AVC_CR 0x00000700 -#define FLD_PATH1_AVC_RMS_CON 0x000000f0 -#define FLD_PATH1_SEL_CTL 0x0000000f - -/*****************************************************************************/ -#define PATH1_VOL_CTL 0x8d4 -#define FLD_PATH1_AVC_THRESHOLD 0x7fff0000 -#define FLD_PATH1_BAL_LEFT 0x00008000 -#define FLD_PATH1_BAL_LEVEL 0x00007f00 -#define FLD_PATH1_VOLUME 0x000000ff - -/*****************************************************************************/ -#define PATH1_EQ_CTL 0x8d8 -/* Reserved [31:30] */ -#define FLD_PATH1_EQ_TREBLE_VOL 0x3f000000 -/* Reserved [23:22] */ -#define FLD_PATH1_EQ_MID_VOL 0x003f0000 -/* Reserved [15:14] */ -#define FLD_PATH1_EQ_BASS_VOL 0x00003f00 -/* Reserved [7:1] */ -#define FLD_PATH1_EQ_BAND_SEL 0x00000001 - -/*****************************************************************************/ -#define PATH1_SC_CTL 0x8dc -#define FLD_PATH1_SC_THRESHOLD 0x7fff0000 -#define FLD_PATH1_SC_RT 0x0000f000 -#define FLD_PATH1_SC_AT 0x00000f00 -#define FLD_PATH1_SC_STEREO 0x00000080 -#define FLD_PATH1_SC_CR 0x00000070 -#define FLD_PATH1_SC_RMS_CON 0x0000000f - -/*****************************************************************************/ -#define PATH2_CTL1 0x8e0 -/* Reserved [31:26] */ -#define FLD_PATH2_MUTE_CTL 0x03000000 -/* Reserved [23:22] */ -#define FLD_PATH2_AVC_CG 0x00300000 -#define FLD_PATH2_AVC_RT 0x000f0000 -#define FLD_PATH2_AVC_AT 0x0000f000 -#define FLD_PATH2_AVC_STEREO 0x00000800 -#define FLD_PATH2_AVC_CR 0x00000700 -#define FLD_PATH2_AVC_RMS_CON 0x000000f0 -#define FLD_PATH2_SEL_CTL 0x0000000f - -/*****************************************************************************/ -#define PATH2_VOL_CTL 0x8e4 -#define FLD_PATH2_AVC_THRESHOLD 0xffff0000 -#define FLD_PATH2_BAL_LEFT 0x00008000 -#define FLD_PATH2_BAL_LEVEL 0x00007f00 -#define FLD_PATH2_VOLUME 0x000000ff - -/*****************************************************************************/ -#define PATH2_EQ_CTL 0x8e8 -/* Reserved [31:30] */ -#define FLD_PATH2_EQ_TREBLE_VOL 0x3f000000 -/* Reserved [23:22] */ -#define FLD_PATH2_EQ_MID_VOL 0x003f0000 -/* Reserved [15:14] */ -#define FLD_PATH2_EQ_BASS_VOL 0x00003f00 -/* Reserved [7:1] */ -#define FLD_PATH2_EQ_BAND_SEL 0x00000001 - -/*****************************************************************************/ -#define PATH2_SC_CTL 0x8eC -#define FLD_PATH2_SC_THRESHOLD 0xffff0000 -#define FLD_PATH2_SC_RT 0x0000f000 -#define FLD_PATH2_SC_AT 0x00000f00 -#define FLD_PATH2_SC_STEREO 0x00000080 -#define FLD_PATH2_SC_CR 0x00000070 -#define FLD_PATH2_SC_RMS_CON 0x0000000f - -/*****************************************************************************/ -#define SRC_CTL 0x8f0 -#define FLD_SRC_STATUS 0xffffff00 -#define FLD_FIFO_LF_EN 0x000000fc -#define FLD_BYPASS_LI 0x00000002 -#define FLD_BYPASS_PF 0x00000001 - -/*****************************************************************************/ -#define SRC_LF_COEF 0x8f4 -#define FLD_LOOP_FILTER_COEF2 0xffff0000 -#define FLD_LOOP_FILTER_COEF1 0x0000ffff - -/*****************************************************************************/ -#define SRC1_CTL 0x8f8 -/* Reserved [31:28] */ -#define FLD_SRC1_FIFO_RD_TH 0x0f000000 -/* Reserved [23:18] */ -#define FLD_SRC1_PHASE_INC 0x0003ffff - -/*****************************************************************************/ -#define SRC2_CTL 0x8fc -/* Reserved [31:28] */ -#define FLD_SRC2_FIFO_RD_TH 0x0f000000 -/* Reserved [23:18] */ -#define FLD_SRC2_PHASE_INC 0x0003ffff - -/*****************************************************************************/ -#define SRC3_CTL 0x900 -/* Reserved [31:28] */ -#define FLD_SRC3_FIFO_RD_TH 0x0f000000 -/* Reserved [23:18] */ -#define FLD_SRC3_PHASE_INC 0x0003ffff - -/*****************************************************************************/ -#define SRC4_CTL 0x904 -/* Reserved [31:28] */ -#define FLD_SRC4_FIFO_RD_TH 0x0f000000 -/* Reserved [23:18] */ -#define FLD_SRC4_PHASE_INC 0x0003ffff - -/*****************************************************************************/ -#define SRC5_CTL 0x908 -/* Reserved [31:28] */ -#define FLD_SRC5_FIFO_RD_TH 0x0f000000 -/* Reserved [23:18] */ -#define FLD_SRC5_PHASE_INC 0x0003ffff - -/*****************************************************************************/ -#define SRC6_CTL 0x90c -/* Reserved [31:28] */ -#define FLD_SRC6_FIFO_RD_TH 0x0f000000 -/* Reserved [23:18] */ -#define FLD_SRC6_PHASE_INC 0x0003ffff - -/*****************************************************************************/ -#define BAND_OUT_SEL 0x910 -#define FLD_SRC6_IN_SEL 0xc0000000 -#define FLD_SRC6_CLK_SEL 0x30000000 -#define FLD_SRC5_IN_SEL 0x0c000000 -#define FLD_SRC5_CLK_SEL 0x03000000 -#define FLD_SRC4_IN_SEL 0x00c00000 -#define FLD_SRC4_CLK_SEL 0x00300000 -#define FLD_SRC3_IN_SEL 0x000c0000 -#define FLD_SRC3_CLK_SEL 0x00030000 -#define FLD_BASEBAND_BYPASS_CTL 0x0000ff00 -#define FLD_AC97_SRC_SEL 0x000000c0 -#define FLD_I2S_SRC_SEL 0x00000030 -#define FLD_PARALLEL2_SRC_SEL 0x0000000c -#define FLD_PARALLEL1_SRC_SEL 0x00000003 - -/*****************************************************************************/ -#define I2S_IN_CTL 0x914 -/* Reserved [31:11] */ -#define FLD_I2S_UP2X_BW20K 0x00000400 -#define FLD_I2S_UP2X_BYPASS 0x00000200 -#define FLD_I2S_IN_MASTER_MODE 0x00000100 -#define FLD_I2S_IN_SONY_MODE 0x00000080 -#define FLD_I2S_IN_RIGHT_JUST 0x00000040 -#define FLD_I2S_IN_WS_SEL 0x00000020 -#define FLD_I2S_IN_BCN_DEL 0x0000001f - -/*****************************************************************************/ -#define I2S_OUT_CTL 0x918 -/* Reserved [31:17] */ -#define FLD_I2S_OUT_SOFT_RESET_EN 0x00010000 -/* Reserved [15:9] */ -#define FLD_I2S_OUT_MASTER_MODE 0x00000100 -#define FLD_I2S_OUT_SONY_MODE 0x00000080 -#define FLD_I2S_OUT_RIGHT_JUST 0x00000040 -#define FLD_I2S_OUT_WS_SEL 0x00000020 -#define FLD_I2S_OUT_BCN_DEL 0x0000001f - -/*****************************************************************************/ -#define AC97_CTL 0x91c -/* Reserved [31:26] */ -#define FLD_AC97_UP2X_BW20K 0x02000000 -#define FLD_AC97_UP2X_BYPASS 0x01000000 -/* Reserved [23:17] */ -#define FLD_AC97_RST_ACL 0x00010000 -/* Reserved [15:9] */ -#define FLD_AC97_WAKE_UP_SYNC 0x00000100 -/* Reserved [7:1] */ -#define FLD_AC97_SHUTDOWN 0x00000001 - -/* Cx231xx redefine */ -#define QPSK_IAGC_CTL1 0x94c -#define QPSK_IAGC_CTL2 0x950 -#define QPSK_FEPR_FREQ 0x954 -#define QPSK_BTL_CTL1 0x958 -#define QPSK_BTL_CTL2 0x95c -#define QPSK_CTL_CTL1 0x960 -#define QPSK_CTL_CTL2 0x964 -#define QPSK_MF_FAGC_CTL 0x968 -#define QPSK_EQ_CTL 0x96c -#define QPSK_LOCK_CTL 0x970 - -/*****************************************************************************/ -#define FM1_DFT_CTL 0x9a8 -#define FLD_FM1_DFT_THRESHOLD 0xffff0000 -/* Reserved [15:8] */ -#define FLD_FM1_DFT_CMP_CTL 0x00000080 -#define FLD_FM1_DFT_AVG 0x00000070 -/* Reserved [3:1] */ -#define FLD_FM1_DFT_START 0x00000001 - -/*****************************************************************************/ -#define FM1_DFT_STATUS 0x9ac -#define FLD_FM1_DFT_DONE 0x80000000 -/* Reserved [30:19] */ -#define FLD_FM_DFT_TH_CMP 0x00040000 -#define FLD_FM1_DFT 0x0003ffff - -/*****************************************************************************/ -#define FM2_DFT_CTL 0x9b0 -#define FLD_FM2_DFT_THRESHOLD 0xffff0000 -/* Reserved [15:8] */ -#define FLD_FM2_DFT_CMP_CTL 0x00000080 -#define FLD_FM2_DFT_AVG 0x00000070 -/* Reserved [3:1] */ -#define FLD_FM2_DFT_START 0x00000001 - -/*****************************************************************************/ -#define FM2_DFT_STATUS 0x9b4 -#define FLD_FM2_DFT_DONE 0x80000000 -/* Reserved [30:19] */ -#define FLD_FM2_DFT_TH_CMP_STAT 0x00040000 -#define FLD_FM2_DFT 0x0003ffff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define AAGC_STATUS_REG 0x9b8 -#define AAGC_STATUS 0x9b8 -/* Reserved [31:27] */ -#define FLD_FM2_DAGC_OUT 0x07000000 -/* Reserved [23:19] */ -#define FLD_FM1_DAGC_OUT 0x00070000 -/* Reserved [15:6] */ -#define FLD_AFE_VGA_OUT 0x0000003f - -/*****************************************************************************/ -#define MTS_GAIN_STATUS 0x9bc -/* Reserved [31:14] */ -#define FLD_MTS_GAIN 0x00003fff - -#define RDS_OUT 0x9c0 -#define FLD_RDS_Q 0xffff0000 -#define FLD_RDS_I 0x0000ffff - -/*****************************************************************************/ -#define AUTOCONFIG_REG 0x9c4 -/* Reserved [31:4] */ -#define FLD_AUTOCONFIG_MODE 0x0000000f - -#define FM_AFC 0x9c8 -#define FLD_FM2_AFC 0xffff0000 -#define FLD_FM1_AFC 0x0000ffff - -/*****************************************************************************/ -/* Cx231xx redefine */ -#define NEW_SPARE 0x9cc -#define NEW_SPARE_REG 0x9cc - -/*****************************************************************************/ -#define DBX_ADJ 0x9d0 -/* Reserved [31:28] */ -#define FLD_DBX2_ADJ 0x0fff0000 -/* Reserved [15:12] */ -#define FLD_DBX1_ADJ 0x00000fff - -#define VID_FMT_AUTO 0 -#define VID_FMT_NTSC_M 1 -#define VID_FMT_NTSC_J 2 -#define VID_FMT_NTSC_443 3 -#define VID_FMT_PAL_BDGHI 4 -#define VID_FMT_PAL_M 5 -#define VID_FMT_PAL_N 6 -#define VID_FMT_PAL_NC 7 -#define VID_FMT_PAL_60 8 -#define VID_FMT_SECAM 12 -#define VID_FMT_SECAM_60 13 - -#define INPUT_MODE_CVBS_0 0 /* INPUT_MODE_VALUE(0) */ -#define INPUT_MODE_YC_1 1 /* INPUT_MODE_VALUE(1) */ -#define INPUT_MODE_YC2_2 2 /* INPUT_MODE_VALUE(2) */ -#define INPUT_MODE_YUV_3 3 /* INPUT_MODE_VALUE(3) */ - -#define LUMA_LPF_LOW_BANDPASS 0 /* 0.6Mhz LPF BW */ -#define LUMA_LPF_MEDIUM_BANDPASS 1 /* 1.0Mhz LPF BW */ -#define LUMA_LPF_HIGH_BANDPASS 2 /* 1.5Mhz LPF BW */ - -#define UV_LPF_LOW_BANDPASS 0 /* 0.6Mhz LPF BW */ -#define UV_LPF_MEDIUM_BANDPASS 1 /* 1.0Mhz LPF BW */ -#define UV_LPF_HIGH_BANDPASS 2 /* 1.5Mhz LPF BW */ - -#define TWO_TAP_FILT 0 -#define THREE_TAP_FILT 1 -#define FOUR_TAP_FILT 2 -#define FIVE_TAP_FILT 3 - -#define AUD_CHAN_SRC_PARALLEL 0 -#define AUD_CHAN_SRC_I2S_INPUT 1 -#define AUD_CHAN_SRC_FLATIRON 2 -#define AUD_CHAN_SRC_PARALLEL3 3 - -#define OUT_MODE_601 0 -#define OUT_MODE_656 1 -#define OUT_MODE_VIP11 2 -#define OUT_MODE_VIP20 3 - -#define PHASE_INC_49MHZ 0x0df22 -#define PHASE_INC_56MHZ 0x0fa5b -#define PHASE_INC_28MHZ 0x010000 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-vbi.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,714 +0,0 @@ -/* - cx231xx_vbi.c - driver for Conexant Cx23100/101/102 USB video capture devices - - Copyright (C) 2008 - Based on cx88 driver - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "cx231xx.h" -#include "cx231xx-vbi.h" - -static inline void print_err_status(struct cx231xx *dev, int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - cx231xx_err(DRIVER_NAME "URB status %d [%s].\n", status, - errmsg); - } else { - cx231xx_err(DRIVER_NAME "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -/* - * Controls the isoc copy of each urb packet - */ -static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb) -{ - struct cx231xx_buffer *buf; - struct cx231xx_dmaqueue *dma_q = urb->context; - int rc = 1; - unsigned char *p_buffer; - u32 bytes_parsed = 0, buffer_size = 0; - u8 sav_eav = 0; - - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - buf = dev->vbi_mode.bulk_ctl.buf; - - /* get buffer pointer and length */ - p_buffer = urb->transfer_buffer; - buffer_size = urb->actual_length; - - if (buffer_size > 0) { - bytes_parsed = 0; - - if (dma_q->is_partial_line) { - /* Handle the case where we were working on a partial - line */ - sav_eav = dma_q->last_sav; - } else { - /* Check for a SAV/EAV overlapping the - buffer boundary */ - - sav_eav = cx231xx_find_boundary_SAV_EAV(p_buffer, - dma_q->partial_buf, - &bytes_parsed); - } - - sav_eav &= 0xF0; - /* Get the first line if we have some portion of an SAV/EAV from - the last buffer or a partial line */ - if (sav_eav) { - bytes_parsed += cx231xx_get_vbi_line(dev, dma_q, - sav_eav, /* SAV/EAV */ - p_buffer + bytes_parsed, /* p_buffer */ - buffer_size - bytes_parsed); /* buffer size */ - } - - /* Now parse data that is completely in this buffer */ - dma_q->is_partial_line = 0; - - while (bytes_parsed < buffer_size) { - u32 bytes_used = 0; - - sav_eav = cx231xx_find_next_SAV_EAV( - p_buffer + bytes_parsed, /* p_buffer */ - buffer_size - bytes_parsed, /* buffer size */ - &bytes_used); /* bytes used to get SAV/EAV */ - - bytes_parsed += bytes_used; - - sav_eav &= 0xF0; - if (sav_eav && (bytes_parsed < buffer_size)) { - bytes_parsed += cx231xx_get_vbi_line(dev, - dma_q, sav_eav, /* SAV/EAV */ - p_buffer+bytes_parsed, /* p_buffer */ - buffer_size-bytes_parsed);/*buf size*/ - } - } - - /* Save the last four bytes of the buffer so we can - check the buffer boundary condition next time */ - memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4); - bytes_parsed = 0; - } - - return rc; -} - -/* ------------------------------------------------------------------ - Vbi buf operations - ------------------------------------------------------------------*/ - -static int -vbi_buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - u32 height = 0; - - height = ((dev->norm & V4L2_STD_625_50) ? - PAL_VBI_LINES : NTSC_VBI_LINES); - - *size = (dev->width * height * 2 * 2); - if (0 == *count) - *count = CX231XX_DEF_VBI_BUF; - - if (*count < CX231XX_MIN_BUF) - *count = CX231XX_MIN_BUF; - - return 0; -} - -/* This is called *without* dev->slock held; please keep it that way */ -static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) -{ - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - unsigned long flags = 0; - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->vbi_mode.slock, flags); - if (dev->vbi_mode.bulk_ctl.buf == buf) - dev->vbi_mode.bulk_ctl.buf = NULL; - spin_unlock_irqrestore(&dev->vbi_mode.slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx *dev = fh->dev; - int rc = 0, urb_init = 0; - u32 height = 0; - - height = ((dev->norm & V4L2_STD_625_50) ? - PAL_VBI_LINES : NTSC_VBI_LINES); - buf->vb.size = ((dev->width << 1) * height * 2); - - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - buf->vb.width = dev->width; - buf->vb.height = height; - buf->vb.field = field; - buf->vb.field = V4L2_FIELD_SEQ_TB; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - if (!dev->vbi_mode.bulk_ctl.num_bufs) - urb_init = 1; - - if (urb_init) { - rc = cx231xx_init_vbi_isoc(dev, CX231XX_NUM_VBI_PACKETS, - CX231XX_NUM_VBI_BUFS, - dev->vbi_mode.alt_max_pkt_size[0], - cx231xx_isoc_vbi_copy); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void -vbi_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); - -} - -static void vbi_buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - - - free_buffer(vq, buf); -} - -struct videobuf_queue_ops cx231xx_vbi_qops = { - .buf_setup = vbi_buffer_setup, - .buf_prepare = vbi_buffer_prepare, - .buf_queue = vbi_buffer_queue, - .buf_release = vbi_buffer_release, -}; - -/* ------------------------------------------------------------------ - URB control - ------------------------------------------------------------------*/ - -/* - * IRQ callback, called by URB callback - */ -static void cx231xx_irq_vbi_callback(struct urb *urb) -{ - struct cx231xx_dmaqueue *dma_q = urb->context; - struct cx231xx_video_mode *vmode = - container_of(dma_q, struct cx231xx_video_mode, vidq); - struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode); - int rc; - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - cx231xx_err(DRIVER_NAME "urb completition error %d.\n", - urb->status); - break; - } - - /* Copy data from URB */ - spin_lock(&dev->vbi_mode.slock); - rc = dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb); - spin_unlock(&dev->vbi_mode.slock); - - /* Reset status */ - urb->status = 0; - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) { - cx231xx_err(DRIVER_NAME "urb resubmit failed (error=%i)\n", - urb->status); - } -} - -/* - * Stop and Deallocate URBs - */ -void cx231xx_uninit_vbi_isoc(struct cx231xx *dev) -{ - struct urb *urb; - int i; - - cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_uninit_vbi_isoc\n"); - - dev->vbi_mode.bulk_ctl.nfields = -1; - for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { - urb = dev->vbi_mode.bulk_ctl.urb[i]; - if (urb) { - if (!irqs_disabled()) - usb_kill_urb(urb); - else - usb_unlink_urb(urb); - - if (dev->vbi_mode.bulk_ctl.transfer_buffer[i]) { - - kfree(dev->vbi_mode.bulk_ctl. - transfer_buffer[i]); - dev->vbi_mode.bulk_ctl.transfer_buffer[i] = - NULL; - } - usb_free_urb(urb); - dev->vbi_mode.bulk_ctl.urb[i] = NULL; - } - dev->vbi_mode.bulk_ctl.transfer_buffer[i] = NULL; - } - - kfree(dev->vbi_mode.bulk_ctl.urb); - kfree(dev->vbi_mode.bulk_ctl.transfer_buffer); - - dev->vbi_mode.bulk_ctl.urb = NULL; - dev->vbi_mode.bulk_ctl.transfer_buffer = NULL; - dev->vbi_mode.bulk_ctl.num_bufs = 0; - - cx231xx_capture_start(dev, 0, Vbi); -} -EXPORT_SYMBOL_GPL(cx231xx_uninit_vbi_isoc); - -/* - * Allocate URBs and start IRQ - */ -int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*bulk_copy) (struct cx231xx *dev, - struct urb *urb)) -{ - struct cx231xx_dmaqueue *dma_q = &dev->vbi_mode.vidq; - int i; - int sb_size, pipe; - struct urb *urb; - int rc; - - cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_prepare_isoc\n"); - - /* De-allocates all pending stuff */ - cx231xx_uninit_vbi_isoc(dev); - - /* clear if any halt */ - usb_clear_halt(dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->vbi_mode.end_point_addr)); - - dev->vbi_mode.bulk_ctl.bulk_copy = bulk_copy; - dev->vbi_mode.bulk_ctl.num_bufs = num_bufs; - dma_q->pos = 0; - dma_q->is_partial_line = 0; - dma_q->last_sav = 0; - dma_q->current_field = -1; - dma_q->bytes_left_in_line = dev->width << 1; - dma_q->lines_per_field = ((dev->norm & V4L2_STD_625_50) ? - PAL_VBI_LINES : NTSC_VBI_LINES); - dma_q->lines_completed = 0; - for (i = 0; i < 8; i++) - dma_q->partial_buf[i] = 0; - - dev->vbi_mode.bulk_ctl.urb = kzalloc(sizeof(void *) * num_bufs, - GFP_KERNEL); - if (!dev->vbi_mode.bulk_ctl.urb) { - cx231xx_errdev("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - - dev->vbi_mode.bulk_ctl.transfer_buffer = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); - if (!dev->vbi_mode.bulk_ctl.transfer_buffer) { - cx231xx_errdev("cannot allocate memory for usbtransfer\n"); - kfree(dev->vbi_mode.bulk_ctl.urb); - return -ENOMEM; - } - - dev->vbi_mode.bulk_ctl.max_pkt_size = max_pkt_size; - dev->vbi_mode.bulk_ctl.buf = NULL; - - sb_size = max_packets * dev->vbi_mode.bulk_ctl.max_pkt_size; - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - cx231xx_err(DRIVER_NAME - ": cannot alloc bulk_ctl.urb %i\n", i); - cx231xx_uninit_vbi_isoc(dev); - return -ENOMEM; - } - dev->vbi_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = 0; - - dev->vbi_mode.bulk_ctl.transfer_buffer[i] = - kzalloc(sb_size, GFP_KERNEL); - if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) { - cx231xx_err(DRIVER_NAME - ": unable to allocate %i bytes for transfer" - " buffer %i%s\n", sb_size, i, - in_interrupt() ? " while in int" : ""); - cx231xx_uninit_vbi_isoc(dev); - return -ENOMEM; - } - - pipe = usb_rcvbulkpipe(dev->udev, dev->vbi_mode.end_point_addr); - usb_fill_bulk_urb(urb, dev->udev, pipe, - dev->vbi_mode.bulk_ctl.transfer_buffer[i], - sb_size, cx231xx_irq_vbi_callback, dma_q); - } - - init_waitqueue_head(&dma_q->wq); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { - rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC); - if (rc) { - cx231xx_err(DRIVER_NAME - ": submit of urb %i failed (error=%i)\n", i, - rc); - cx231xx_uninit_vbi_isoc(dev); - return rc; - } - } - - cx231xx_capture_start(dev, 1, Vbi); - - return 0; -} -EXPORT_SYMBOL_GPL(cx231xx_init_vbi_isoc); - -u32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 sav_eav, u8 *p_buffer, u32 buffer_size) -{ - u32 bytes_copied = 0; - int current_field = -1; - - switch (sav_eav) { - - case SAV_VBI_FIELD1: - current_field = 1; - break; - - case SAV_VBI_FIELD2: - current_field = 2; - break; - default: - break; - } - - if (current_field < 0) - return bytes_copied; - - dma_q->last_sav = sav_eav; - - bytes_copied = - cx231xx_copy_vbi_line(dev, dma_q, p_buffer, buffer_size, - current_field); - - return bytes_copied; -} - -/* - * Announces that a buffer were filled and request the next - */ -static inline void vbi_buffer_filled(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q, - struct cx231xx_buffer *buf) -{ - /* Advice that buffer was filled */ - /* cx231xx_info(DRIVER_NAME "[%p/%d] wakeup\n", buf, buf->vb.i); */ - - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - - dev->vbi_mode.bulk_ctl.buf = NULL; - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 *p_line, u32 length, int field_number) -{ - u32 bytes_to_copy; - struct cx231xx_buffer *buf; - u32 _line_size = dev->width * 2; - - if (dma_q->current_field == -1) { - /* Just starting up */ - cx231xx_reset_vbi_buffer(dev, dma_q); - } - - if (dma_q->current_field != field_number) - dma_q->lines_completed = 0; - - /* get the buffer pointer */ - buf = dev->vbi_mode.bulk_ctl.buf; - - /* Remember the field number for next time */ - dma_q->current_field = field_number; - - bytes_to_copy = dma_q->bytes_left_in_line; - if (bytes_to_copy > length) - bytes_to_copy = length; - - if (dma_q->lines_completed >= dma_q->lines_per_field) { - dma_q->bytes_left_in_line -= bytes_to_copy; - dma_q->is_partial_line = - (dma_q->bytes_left_in_line == 0) ? 0 : 1; - return 0; - } - - dma_q->is_partial_line = 1; - - /* If we don't have a buffer, just return the number of bytes we would - have copied if we had a buffer. */ - if (!buf) { - dma_q->bytes_left_in_line -= bytes_to_copy; - dma_q->is_partial_line = - (dma_q->bytes_left_in_line == 0) ? 0 : 1; - return bytes_to_copy; - } - - /* copy the data to video buffer */ - cx231xx_do_vbi_copy(dev, dma_q, p_line, bytes_to_copy); - - dma_q->pos += bytes_to_copy; - dma_q->bytes_left_in_line -= bytes_to_copy; - - if (dma_q->bytes_left_in_line == 0) { - - dma_q->bytes_left_in_line = _line_size; - dma_q->lines_completed++; - dma_q->is_partial_line = 0; - - if (cx231xx_is_vbi_buffer_done(dev, dma_q) && buf) { - - vbi_buffer_filled(dev, dma_q, buf); - - dma_q->pos = 0; - dma_q->lines_completed = 0; - cx231xx_reset_vbi_buffer(dev, dma_q); - } - } - - return bytes_to_copy; -} - -/* - * video-buf generic routine to get the next available buffer - */ -static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q, - struct cx231xx_buffer **buf) -{ - struct cx231xx_video_mode *vmode = - container_of(dma_q, struct cx231xx_video_mode, vidq); - struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode); - char *outp; - - if (list_empty(&dma_q->active)) { - cx231xx_err(DRIVER_NAME ": No active queue to serve\n"); - dev->vbi_mode.bulk_ctl.buf = NULL; - *buf = NULL; - return; - } - - /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue); - - /* Cleans up buffer - Usefull for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - memset(outp, 0, (*buf)->vb.size); - - dev->vbi_mode.bulk_ctl.buf = *buf; - - return; -} - -void cx231xx_reset_vbi_buffer(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q) -{ - struct cx231xx_buffer *buf; - - buf = dev->vbi_mode.bulk_ctl.buf; - - if (buf == NULL) { - /* first try to get the buffer */ - get_next_vbi_buf(dma_q, &buf); - - dma_q->pos = 0; - dma_q->current_field = -1; - } - - dma_q->bytes_left_in_line = dev->width << 1; - dma_q->lines_completed = 0; -} - -int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 *p_buffer, u32 bytes_to_copy) -{ - u8 *p_out_buffer = NULL; - u32 current_line_bytes_copied = 0; - struct cx231xx_buffer *buf; - u32 _line_size = dev->width << 1; - void *startwrite; - int offset, lencopy; - - buf = dev->vbi_mode.bulk_ctl.buf; - - if (buf == NULL) - return -EINVAL; - - p_out_buffer = videobuf_to_vmalloc(&buf->vb); - - if (dma_q->bytes_left_in_line != _line_size) { - current_line_bytes_copied = - _line_size - dma_q->bytes_left_in_line; - } - - offset = (dma_q->lines_completed * _line_size) + - current_line_bytes_copied; - - if (dma_q->current_field == 2) { - /* Populate the second half of the frame */ - offset += (dev->width * 2 * dma_q->lines_per_field); - } - - /* prepare destination address */ - startwrite = p_out_buffer + offset; - - lencopy = dma_q->bytes_left_in_line > bytes_to_copy ? - bytes_to_copy : dma_q->bytes_left_in_line; - - memcpy(startwrite, p_buffer, lencopy); - - return 0; -} - -u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q) -{ - u32 height = 0; - - height = ((dev->norm & V4L2_STD_625_50) ? - PAL_VBI_LINES : NTSC_VBI_LINES); - if (dma_q->lines_completed == height && dma_q->current_field == 2) - return 1; - else - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-vbi.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-vbi.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-vbi.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-vbi.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -/* - cx231xx_vbi.h - driver for Conexant Cx23100/101/102 USB video capture devices - - Copyright (C) 2008 - Based on cx88 driver - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _CX231XX_VBI_H -#define _CX231XX_VBI_H - -extern struct videobuf_queue_ops cx231xx_vbi_qops; - -#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ -#define NTSC_VBI_END_LINE 21 -#define NTSC_VBI_LINES (NTSC_VBI_END_LINE-NTSC_VBI_START_LINE+1) - -#define PAL_VBI_START_LINE 6 -#define PAL_VBI_END_LINE 23 -#define PAL_VBI_LINES (PAL_VBI_END_LINE-PAL_VBI_START_LINE+1) - -#define VBI_STRIDE 1440 -#define VBI_SAMPLES_PER_LINE 1440 - -#define CX231XX_NUM_VBI_PACKETS 4 -#define CX231XX_NUM_VBI_BUFS 5 - -/* stream functions */ -int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*bulk_copy) (struct cx231xx *dev, - struct urb *urb)); - -void cx231xx_uninit_vbi_isoc(struct cx231xx *dev); - -/* vbi data copy functions */ -u32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 sav_eav, u8 *p_buffer, u32 buffer_size); - -u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 *p_line, u32 length, int field_number); - -void cx231xx_reset_vbi_buffer(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q); - -int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 *p_buffer, u32 bytes_to_copy); - -u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-video.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/cx231xx-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2658 +0,0 @@ -/* - cx231xx-video.c - driver for Conexant Cx23100/101/102 - USB video capture devices - - Copyright (C) 2008 - Based on em28xx driver - Based on cx23885 driver - Based on cx88 driver - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "cx231xx.h" -#include "cx231xx-vbi.h" - -#define CX231XX_VERSION_CODE KERNEL_VERSION(0, 0, 1) - -#define DRIVER_AUTHOR "Srinivasa Deevi " -#define DRIVER_DESC "Conexant cx231xx based USB video device driver" - -#define cx231xx_videodbg(fmt, arg...) do {\ - if (video_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -static unsigned int isoc_debug; -module_param(isoc_debug, int, 0644); -MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); - -#define cx231xx_isocdbg(fmt, arg...) \ -do {\ - if (isoc_debug) { \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); \ - } \ - } while (0) - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; - -module_param_array(card, int, NULL, 0444); -module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); - -MODULE_PARM_DESC(card, "card type"); -MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); - -static unsigned int video_debug; -module_param(video_debug, int, 0644); -MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); - -/* supported video standards */ -static struct cx231xx_fmt format[] = { - { - .name = "16bpp YUY2, 4:2:2, packed", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .reg = 0, - }, -}; - -/* supported controls */ -/* Common to all boards */ - -/* ------------------------------------------------------------------- */ - -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static struct cx231xx_ctrl cx231xx_ctls[] = { - /* --- video --- */ - { - .v = { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = LUMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - .v = { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = LUMA_CTRL, - .mask = 0xff00, - .shift = 8, - }, { - .v = { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = CHROMA_CTRL, - .mask = 0xff0000, - .shift = 16, - }, { - /* strictly, this only describes only U saturation. - * V saturation is handled specially through code. - */ - .v = { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = CHROMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - /* --- audio --- */ - .v = { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = PATH1_CTL1, - .mask = (0x1f << 24), - .shift = 24, - }, { - .v = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = PATH1_VOL_CTL, - .mask = 0xff, - .shift = 0, - } -}; -static const int CX231XX_CTLS = ARRAY_SIZE(cx231xx_ctls); - -static const u32 cx231xx_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, -#if 0 - V4L2_CID_AUDIO_BALANCE, -#endif - V4L2_CID_AUDIO_MUTE, - 0 -}; - -static const u32 *ctrl_classes[] = { - cx231xx_user_ctrls, - NULL -}; - -/* ------------------------------------------------------------------ - Video buffer and parser functions - ------------------------------------------------------------------*/ - -/* - * Announces that a buffer were filled and request the next - */ -static inline void buffer_filled(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q, - struct cx231xx_buffer *buf) -{ - /* Advice that buffer was filled */ - cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - - if (dev->USE_ISO) - dev->video_mode.isoc_ctl.buf = NULL; - else - dev->video_mode.bulk_ctl.buf = NULL; - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -static inline void print_err_status(struct cx231xx *dev, int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - cx231xx_isocdbg("URB status %d [%s].\n", status, errmsg); - } else { - cx231xx_isocdbg("URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -/* - * video-buf generic routine to get the next available buffer - */ -static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q, - struct cx231xx_buffer **buf) -{ - struct cx231xx_video_mode *vmode = - container_of(dma_q, struct cx231xx_video_mode, vidq); - struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode); - - char *outp; - - if (list_empty(&dma_q->active)) { - cx231xx_isocdbg("No active queue to serve\n"); - if (dev->USE_ISO) - dev->video_mode.isoc_ctl.buf = NULL; - else - dev->video_mode.bulk_ctl.buf = NULL; - *buf = NULL; - return; - } - - /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue); - - /* Cleans up buffer - Usefull for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - memset(outp, 0, (*buf)->vb.size); - - if (dev->USE_ISO) - dev->video_mode.isoc_ctl.buf = *buf; - else - dev->video_mode.bulk_ctl.buf = *buf; - - return; -} - -/* - * Controls the isoc copy of each urb packet - */ -static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) -{ - struct cx231xx_buffer *buf; - struct cx231xx_dmaqueue *dma_q = urb->context; - unsigned char *outp = NULL; - int i, rc = 1; - unsigned char *p_buffer; - u32 bytes_parsed = 0, buffer_size = 0; - u8 sav_eav = 0; - - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - buf = dev->video_mode.isoc_ctl.buf; - if (buf != NULL) - outp = videobuf_to_vmalloc(&buf->vb); - - for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - if (urb->iso_frame_desc[i].status != -EPROTO) - continue; - } - - if (urb->iso_frame_desc[i].actual_length <= 0) { - /* cx231xx_isocdbg("packet %d is empty",i); - spammy */ - continue; - } - if (urb->iso_frame_desc[i].actual_length > - dev->video_mode.max_pkt_size) { - cx231xx_isocdbg("packet bigger than packet size"); - continue; - } - - /* get buffer pointer and length */ - p_buffer = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - buffer_size = urb->iso_frame_desc[i].actual_length; - bytes_parsed = 0; - - if (dma_q->is_partial_line) { - /* Handle the case of a partial line */ - sav_eav = dma_q->last_sav; - } else { - /* Check for a SAV/EAV overlapping - the buffer boundary */ - sav_eav = - cx231xx_find_boundary_SAV_EAV(p_buffer, - dma_q->partial_buf, - &bytes_parsed); - } - - sav_eav &= 0xF0; - /* Get the first line if we have some portion of an SAV/EAV from - the last buffer or a partial line */ - if (sav_eav) { - bytes_parsed += cx231xx_get_video_line(dev, dma_q, - sav_eav, /* SAV/EAV */ - p_buffer + bytes_parsed, /* p_buffer */ - buffer_size - bytes_parsed);/* buf size */ - } - - /* Now parse data that is completely in this buffer */ - /* dma_q->is_partial_line = 0; */ - - while (bytes_parsed < buffer_size) { - u32 bytes_used = 0; - - sav_eav = cx231xx_find_next_SAV_EAV( - p_buffer + bytes_parsed, /* p_buffer */ - buffer_size - bytes_parsed, /* buf size */ - &bytes_used);/* bytes used to get SAV/EAV */ - - bytes_parsed += bytes_used; - - sav_eav &= 0xF0; - if (sav_eav && (bytes_parsed < buffer_size)) { - bytes_parsed += cx231xx_get_video_line(dev, - dma_q, sav_eav, /* SAV/EAV */ - p_buffer + bytes_parsed,/* p_buffer */ - buffer_size - bytes_parsed);/*buf size*/ - } - } - - /* Save the last four bytes of the buffer so we can check the - buffer boundary condition next time */ - memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4); - bytes_parsed = 0; - - } - return rc; -} - -static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) -{ - struct cx231xx_buffer *buf; - struct cx231xx_dmaqueue *dma_q = urb->context; - unsigned char *outp = NULL; - int rc = 1; - unsigned char *p_buffer; - u32 bytes_parsed = 0, buffer_size = 0; - u8 sav_eav = 0; - - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - buf = dev->video_mode.bulk_ctl.buf; - if (buf != NULL) - outp = videobuf_to_vmalloc(&buf->vb); - - if (1) { - - /* get buffer pointer and length */ - p_buffer = urb->transfer_buffer; - buffer_size = urb->actual_length; - bytes_parsed = 0; - - if (dma_q->is_partial_line) { - /* Handle the case of a partial line */ - sav_eav = dma_q->last_sav; - } else { - /* Check for a SAV/EAV overlapping - the buffer boundary */ - sav_eav = - cx231xx_find_boundary_SAV_EAV(p_buffer, - dma_q->partial_buf, - &bytes_parsed); - } - - sav_eav &= 0xF0; - /* Get the first line if we have some portion of an SAV/EAV from - the last buffer or a partial line */ - if (sav_eav) { - bytes_parsed += cx231xx_get_video_line(dev, dma_q, - sav_eav, /* SAV/EAV */ - p_buffer + bytes_parsed, /* p_buffer */ - buffer_size - bytes_parsed);/* buf size */ - } - - /* Now parse data that is completely in this buffer */ - /* dma_q->is_partial_line = 0; */ - - while (bytes_parsed < buffer_size) { - u32 bytes_used = 0; - - sav_eav = cx231xx_find_next_SAV_EAV( - p_buffer + bytes_parsed, /* p_buffer */ - buffer_size - bytes_parsed, /* buf size */ - &bytes_used);/* bytes used to get SAV/EAV */ - - bytes_parsed += bytes_used; - - sav_eav &= 0xF0; - if (sav_eav && (bytes_parsed < buffer_size)) { - bytes_parsed += cx231xx_get_video_line(dev, - dma_q, sav_eav, /* SAV/EAV */ - p_buffer + bytes_parsed,/* p_buffer */ - buffer_size - bytes_parsed);/*buf size*/ - } - } - - /* Save the last four bytes of the buffer so we can check the - buffer boundary condition next time */ - memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4); - bytes_parsed = 0; - - } - return rc; -} - - -u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf, - u32 *p_bytes_used) -{ - u32 bytes_used; - u8 boundary_bytes[8]; - u8 sav_eav = 0; - - *p_bytes_used = 0; - - /* Create an array of the last 4 bytes of the last buffer and the first - 4 bytes of the current buffer. */ - - memcpy(boundary_bytes, partial_buf, 4); - memcpy(boundary_bytes + 4, p_buffer, 4); - - /* Check for the SAV/EAV in the boundary buffer */ - sav_eav = cx231xx_find_next_SAV_EAV((u8 *)&boundary_bytes, 8, - &bytes_used); - - if (sav_eav) { - /* found a boundary SAV/EAV. Updates the bytes used to reflect - only those used in the new buffer */ - *p_bytes_used = bytes_used - 4; - } - - return sav_eav; -} - -u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, u32 *p_bytes_used) -{ - u32 i; - u8 sav_eav = 0; - - /* - * Don't search if the buffer size is less than 4. It causes a page - * fault since buffer_size - 4 evaluates to a large number in that - * case. - */ - if (buffer_size < 4) { - *p_bytes_used = buffer_size; - return 0; - } - - for (i = 0; i < (buffer_size - 3); i++) { - - if ((p_buffer[i] == 0xFF) && - (p_buffer[i + 1] == 0x00) && (p_buffer[i + 2] == 0x00)) { - - *p_bytes_used = i + 4; - sav_eav = p_buffer[i + 3]; - return sav_eav; - } - } - - *p_bytes_used = buffer_size; - return 0; -} - -u32 cx231xx_get_video_line(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q, u8 sav_eav, - u8 *p_buffer, u32 buffer_size) -{ - u32 bytes_copied = 0; - int current_field = -1; - - switch (sav_eav) { - case SAV_ACTIVE_VIDEO_FIELD1: - /* looking for skipped line which occurred in PAL 720x480 mode. - In this case, there will be no active data contained - between the SAV and EAV */ - if ((buffer_size > 3) && (p_buffer[0] == 0xFF) && - (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) && - ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) || - (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) || - (p_buffer[3] == EAV_VBLANK_FIELD1) || - (p_buffer[3] == EAV_VBLANK_FIELD2))) - return bytes_copied; - current_field = 1; - break; - - case SAV_ACTIVE_VIDEO_FIELD2: - /* looking for skipped line which occurred in PAL 720x480 mode. - In this case, there will be no active data contained between - the SAV and EAV */ - if ((buffer_size > 3) && (p_buffer[0] == 0xFF) && - (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) && - ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) || - (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) || - (p_buffer[3] == EAV_VBLANK_FIELD1) || - (p_buffer[3] == EAV_VBLANK_FIELD2))) - return bytes_copied; - current_field = 2; - break; - } - - dma_q->last_sav = sav_eav; - - bytes_copied = cx231xx_copy_video_line(dev, dma_q, p_buffer, - buffer_size, current_field); - - return bytes_copied; -} - -u32 cx231xx_copy_video_line(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q, u8 *p_line, - u32 length, int field_number) -{ - u32 bytes_to_copy; - struct cx231xx_buffer *buf; - u32 _line_size = dev->width * 2; - - if (dma_q->current_field != field_number) - cx231xx_reset_video_buffer(dev, dma_q); - - /* get the buffer pointer */ - if (dev->USE_ISO) - buf = dev->video_mode.isoc_ctl.buf; - else - buf = dev->video_mode.bulk_ctl.buf; - - /* Remember the field number for next time */ - dma_q->current_field = field_number; - - bytes_to_copy = dma_q->bytes_left_in_line; - if (bytes_to_copy > length) - bytes_to_copy = length; - - if (dma_q->lines_completed >= dma_q->lines_per_field) { - dma_q->bytes_left_in_line -= bytes_to_copy; - dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) ? - 0 : 1; - return 0; - } - - dma_q->is_partial_line = 1; - - /* If we don't have a buffer, just return the number of bytes we would - have copied if we had a buffer. */ - if (!buf) { - dma_q->bytes_left_in_line -= bytes_to_copy; - dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) - ? 0 : 1; - return bytes_to_copy; - } - - /* copy the data to video buffer */ - cx231xx_do_copy(dev, dma_q, p_line, bytes_to_copy); - - dma_q->pos += bytes_to_copy; - dma_q->bytes_left_in_line -= bytes_to_copy; - - if (dma_q->bytes_left_in_line == 0) { - dma_q->bytes_left_in_line = _line_size; - dma_q->lines_completed++; - dma_q->is_partial_line = 0; - - if (cx231xx_is_buffer_done(dev, dma_q) && buf) { - buffer_filled(dev, dma_q, buf); - - dma_q->pos = 0; - buf = NULL; - dma_q->lines_completed = 0; - } - } - - return bytes_to_copy; -} - -void cx231xx_reset_video_buffer(struct cx231xx *dev, - struct cx231xx_dmaqueue *dma_q) -{ - struct cx231xx_buffer *buf; - - /* handle the switch from field 1 to field 2 */ - if (dma_q->current_field == 1) { - if (dma_q->lines_completed >= dma_q->lines_per_field) - dma_q->field1_done = 1; - else - dma_q->field1_done = 0; - } - - if (dev->USE_ISO) - buf = dev->video_mode.isoc_ctl.buf; - else - buf = dev->video_mode.bulk_ctl.buf; - - if (buf == NULL) { - u8 *outp = NULL; - /* first try to get the buffer */ - get_next_buf(dma_q, &buf); - - if (buf) - outp = videobuf_to_vmalloc(&buf->vb); - - dma_q->pos = 0; - dma_q->field1_done = 0; - dma_q->current_field = -1; - } - - /* reset the counters */ - dma_q->bytes_left_in_line = dev->width << 1; - dma_q->lines_completed = 0; -} - -int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, - u8 *p_buffer, u32 bytes_to_copy) -{ - u8 *p_out_buffer = NULL; - u32 current_line_bytes_copied = 0; - struct cx231xx_buffer *buf; - u32 _line_size = dev->width << 1; - void *startwrite; - int offset, lencopy; - - if (dev->USE_ISO) - buf = dev->video_mode.isoc_ctl.buf; - else - buf = dev->video_mode.bulk_ctl.buf; - - if (buf == NULL) - return -1; - - p_out_buffer = videobuf_to_vmalloc(&buf->vb); - - current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line; - - /* Offset field 2 one line from the top of the buffer */ - offset = (dma_q->current_field == 1) ? 0 : _line_size; - - /* Offset for field 2 */ - startwrite = p_out_buffer + offset; - - /* lines already completed in the current field */ - startwrite += (dma_q->lines_completed * _line_size * 2); - - /* bytes already completed in the current line */ - startwrite += current_line_bytes_copied; - - lencopy = dma_q->bytes_left_in_line > bytes_to_copy ? - bytes_to_copy : dma_q->bytes_left_in_line; - - if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + buf->vb.size)) - return 0; - - /* The below copies the UYVY data straight into video buffer */ - cx231xx_swab((u16 *) p_buffer, (u16 *) startwrite, (u16) lencopy); - - return 0; -} - -void cx231xx_swab(u16 *from, u16 *to, u16 len) -{ - u16 i; - - if (len <= 0) - return; - - for (i = 0; i < len / 2; i++) - to[i] = (from[i] << 8) | (from[i] >> 8); -} - -u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q) -{ - u8 buffer_complete = 0; - - /* Dual field stream */ - buffer_complete = ((dma_q->current_field == 2) && - (dma_q->lines_completed >= dma_q->lines_per_field) && - dma_q->field1_done); - - return buffer_complete; -} - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ - -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) -{ - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - - *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3; - if (0 == *count) - *count = CX231XX_DEF_BUF; - - if (*count < CX231XX_MIN_BUF) - *count = CX231XX_MIN_BUF; - - return 0; -} - -/* This is called *without* dev->slock held; please keep it that way */ -static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) -{ - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - unsigned long flags = 0; - - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->video_mode.slock, flags); - if (dev->USE_ISO) { - if (dev->video_mode.isoc_ctl.buf == buf) - dev->video_mode.isoc_ctl.buf = NULL; - } else { - if (dev->video_mode.bulk_ctl.buf == buf) - dev->video_mode.bulk_ctl.buf = NULL; - } - spin_unlock_irqrestore(&dev->video_mode.slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx *dev = fh->dev; - int rc = 0, urb_init = 0; - - /* The only currently supported format is 16 bits/pixel */ - buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth - + 7) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - if (dev->USE_ISO) { - if (!dev->video_mode.isoc_ctl.num_bufs) - urb_init = 1; - } else { - if (!dev->video_mode.bulk_ctl.num_bufs) - urb_init = 1; - } - /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n", - urb_init, dev->video_mode.max_pkt_size);*/ - if (urb_init) { - dev->mode_tv = 0; - if (dev->USE_ISO) - rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, - CX231XX_NUM_BUFS, - dev->video_mode.max_pkt_size, - cx231xx_isoc_copy); - else - rc = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS, - CX231XX_NUM_BUFS, - dev->video_mode.max_pkt_size, - cx231xx_bulk_copy); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); - -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = (struct cx231xx *)fh->dev; - - cx231xx_isocdbg("cx231xx: called buffer_release\n"); - - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops cx231xx_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/********************* v4l2 interface **************************************/ - -void video_mux(struct cx231xx *dev, int index) -{ - dev->video_input = index; - dev->ctl_ainput = INPUT(index)->amux; - - cx231xx_set_video_input_mux(dev, index); - - cx25840_call(dev, video, s_routing, INPUT(index)->vmux, 0, 0); - - cx231xx_set_audio_input(dev, dev->ctl_ainput); - - cx231xx_info("video_mux : %d\n", index); - - /* do mode control overrides if required */ - cx231xx_do_mode_ctrl_overrides(dev); -} - -/* Usage lock check functions */ -static int res_get(struct cx231xx_fh *fh) -{ - struct cx231xx *dev = fh->dev; - int rc = 0; - - /* This instance already has stream_on */ - if (fh->stream_on) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (dev->stream_on) - return -EBUSY; - dev->stream_on = 1; - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (dev->vbi_stream_on) - return -EBUSY; - dev->vbi_stream_on = 1; - } else - return -EINVAL; - - fh->stream_on = 1; - - return rc; -} - -static int res_check(struct cx231xx_fh *fh) -{ - return fh->stream_on; -} - -static void res_free(struct cx231xx_fh *fh) -{ - struct cx231xx *dev = fh->dev; - - fh->stream_on = 0; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - dev->stream_on = 0; - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - dev->vbi_stream_on = 0; -} - -static int check_dev(struct cx231xx *dev) -{ - if (dev->state & DEV_DISCONNECTED) { - cx231xx_errdev("v4l2 ioctl: device not present\n"); - return -ENODEV; - } - - if (dev->state & DEV_MISCONFIGURED) { - cx231xx_errdev("v4l2 ioctl: device is misconfigured; " - "close and open it again\n"); - return -EIO; - } - return 0; -} - -/* ------------------------------------------------------------------ - IOCTL vidioc handling - ------------------------------------------------------------------*/ - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - f->fmt.pix.pixelformat = dev->format->fourcc; - f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - - f->fmt.pix.field = V4L2_FIELD_INTERLACED; - - return 0; -} - -static struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(format); i++) - if (format[i].fourcc == fourcc) - return &format[i]; - - return NULL; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - unsigned int width = f->fmt.pix.width; - unsigned int height = f->fmt.pix.height; - unsigned int maxw = norm_maxw(dev); - unsigned int maxh = norm_maxh(dev); - struct cx231xx_fmt *fmt; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (!fmt) { - cx231xx_videodbg("Fourcc format (%08x) invalid.\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - /* width must even because of the YUYV format - height must be even because of interlacing */ - v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0); - - f->fmt.pix.width = width; - f->fmt.pix.height = height; - f->fmt.pix.pixelformat = fmt->fourcc; - f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.field = V4L2_FIELD_INTERLACED; - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - struct cx231xx_fmt *fmt; - struct v4l2_mbus_framefmt mbus_fmt; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - vidioc_try_fmt_vid_cap(file, priv, f); - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (!fmt) - return -EINVAL; - - if (videobuf_queue_is_busy(&fh->vb_vidq)) { - cx231xx_errdev("%s queue busy\n", __func__); - return -EBUSY; - } - - if (dev->stream_on && !fh->stream_on) { - cx231xx_errdev("%s device in use by another fh\n", __func__); - return -EBUSY; - } - - /* set new image size */ - dev->width = f->fmt.pix.width; - dev->height = f->fmt.pix.height; - dev->format = fmt; - - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); - call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); - - return rc; -} - -static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - *id = dev->norm; - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - struct v4l2_mbus_framefmt mbus_fmt; - struct v4l2_format f; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm); - - dev->norm = *norm; - - /* Adjusts width/height, if needed */ - f.fmt.pix.width = dev->width; - f.fmt.pix.height = dev->height; - vidioc_try_fmt_vid_cap(file, priv, &f); - - call_all(dev, core, s_std, dev->norm); - - /* We need to reset basic properties in the decoder related to - resolution (since a standard change effects things like the number - of lines in VACT, etc) */ - v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED); - call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt); - - /* set new image size */ - dev->width = f.fmt.pix.width; - dev->height = f.fmt.pix.height; - - /* do mode control overrides */ - cx231xx_do_mode_ctrl_overrides(dev); - - return 0; -} - -static const char *iname[] = { - [CX231XX_VMUX_COMPOSITE1] = "Composite1", - [CX231XX_VMUX_SVIDEO] = "S-Video", - [CX231XX_VMUX_TELEVISION] = "Television", - [CX231XX_VMUX_CABLE] = "Cable TV", - [CX231XX_VMUX_DVB] = "DVB", - [CX231XX_VMUX_DEBUG] = "for debug only", -}; - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - unsigned int n; - - n = i->index; - if (n >= MAX_CX231XX_INPUT) - return -EINVAL; - if (0 == INPUT(n)->type) - return -EINVAL; - - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - - strcpy(i->name, iname[INPUT(n)->type]); - - if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) || - (CX231XX_VMUX_CABLE == INPUT(n)->type)) - i->type = V4L2_INPUT_TYPE_TUNER; - - i->std = dev->vdev->tvnorms; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - *i = dev->video_input; - - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - dev->mode_tv = 0; - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (i >= MAX_CX231XX_INPUT) - return -EINVAL; - if (0 == INPUT(i)->type) - return -EINVAL; - - video_mux(dev, i); - - if (INPUT(i)->type == CX231XX_VMUX_TELEVISION || - INPUT(i)->type == CX231XX_VMUX_CABLE) { - /* There's a tuner, so reset the standard and put it on the - last known frequency (since it was probably powered down - until now */ - call_all(dev, core, s_std, dev->norm); - } - - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - switch (a->index) { - case CX231XX_AMUX_VIDEO: - strcpy(a->name, "Television"); - break; - case CX231XX_AMUX_LINE_IN: - strcpy(a->name, "Line In"); - break; - default: - return -EINVAL; - } - - a->index = dev->ctl_ainput; - a->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int status = 0; - - /* Doesn't allow manual routing */ - if (a->index != dev->ctl_ainput) - return -EINVAL; - - dev->ctl_ainput = INPUT(a->index)->amux; - status = cx231xx_set_audio_input(dev, dev->ctl_ainput); - - return status; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int id = qc->id; - int i; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - qc->id = v4l2_ctrl_next(ctrl_classes, qc->id); - if (unlikely(qc->id == 0)) - return -EINVAL; - - memset(qc, 0, sizeof(*qc)); - - qc->id = id; - - if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1) - return -EINVAL; - - for (i = 0; i < CX231XX_CTLS; i++) - if (cx231xx_ctls[i].v.id == qc->id) - break; - - if (i == CX231XX_CTLS) { - *qc = no_ctl; - return 0; - } - *qc = cx231xx_ctls[i].v; - - call_all(dev, core, queryctrl, qc); - - if (qc->type) - return 0; - else - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - call_all(dev, core, g_ctrl, ctrl); - return rc; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - call_all(dev, core, s_ctrl, ctrl); - return rc; -} - -static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Tuner"); - - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - t->signal = 0xffff; /* LOCKED */ - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != t->index) - return -EINVAL; -#if 0 - call_all(dev, tuner, s_tuner, t); -#endif - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - - call_all(dev, tuner, g_frequency, f); - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - u32 if_frequency = 5400000; - - cx231xx_info("Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n", - f->frequency, f->type); - /*cx231xx_info("f->type: 1-radio 2-analogTV 3-digitalTV\n");*/ - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != f->tuner) - return -EINVAL; - - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; - - /* set pre channel change settings in DIF first */ - rc = cx231xx_tuner_pre_channel_change(dev); - - dev->ctl_freq = f->frequency; - call_all(dev, tuner, s_frequency, f); - - /* set post channel change settings in DIF first */ - rc = cx231xx_tuner_post_channel_change(dev); - - if (dev->tuner_type == TUNER_NXP_TDA18271) { - if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443)) - if_frequency = 5400000; /*5.4MHz */ - else if (dev->norm & V4L2_STD_B) - if_frequency = 6000000; /*6.0MHz */ - else if (dev->norm & (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK)) - if_frequency = 6900000; /*6.9MHz */ - else if (dev->norm & V4L2_STD_GH) - if_frequency = 7100000; /*7.1MHz */ - else if (dev->norm & V4L2_STD_PAL_I) - if_frequency = 7250000; /*7.25MHz */ - else if (dev->norm & V4L2_STD_SECAM_L) - if_frequency = 6900000; /*6.9MHz */ - else if (dev->norm & V4L2_STD_SECAM_LC) - if_frequency = 1250000; /*1.25MHz */ - - cx231xx_info("if_frequency is set to %d\n", if_frequency); - cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1); - - update_HH_register_after_set_DIF(dev); - } - - cx231xx_info("Set New FREQUENCY to %d\n", f->frequency); - - return rc; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG - -/* - -R, --list-registers=type=, - chip=[,min=,max=] - dump registers from to [VIDIOC_DBG_G_REGISTER] - -r, --set-register=type=, - chip=,reg=,val= - set the register [VIDIOC_DBG_S_REGISTER] - - if type == host, then is the hosts chip ID (default 0) - if type == i2cdrv (default), then is the I2C driver name or ID - if type == i2caddr, then is the 7-bit I2C address -*/ - -static int vidioc_g_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int ret = 0; - u8 value[4] = { 0, 0, 0, 0 }; - u32 data = 0; - - switch (reg->match.type) { - case V4L2_CHIP_MATCH_HOST: - switch (reg->match.addr) { - case 0: /* Cx231xx - internal registers */ - ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, - (u16)reg->reg, value, 4); - reg->val = value[0] | value[1] << 8 | - value[2] << 16 | value[3] << 24; - break; - case 1: /* AFE - read byte */ - ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS, - (u16)reg->reg, 2, &data, 1); - reg->val = le32_to_cpu(data & 0xff); - break; - case 14: /* AFE - read dword */ - ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS, - (u16)reg->reg, 2, &data, 4); - reg->val = le32_to_cpu(data); - break; - case 2: /* Video Block - read byte */ - ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, - (u16)reg->reg, 2, &data, 1); - reg->val = le32_to_cpu(data & 0xff); - break; - case 24: /* Video Block - read dword */ - ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, - (u16)reg->reg, 2, &data, 4); - reg->val = le32_to_cpu(data); - break; - case 3: /* I2S block - read byte */ - ret = cx231xx_read_i2c_data(dev, - I2S_BLK_DEVICE_ADDRESS, - (u16)reg->reg, 1, - &data, 1); - reg->val = le32_to_cpu(data & 0xff); - break; - case 34: /* I2S Block - read dword */ - ret = - cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, - (u16)reg->reg, 1, &data, 4); - reg->val = le32_to_cpu(data); - break; - } - return ret < 0 ? ret : 0; - - case V4L2_CHIP_MATCH_I2C_DRIVER: - call_all(dev, core, g_register, reg); - return 0; - case V4L2_CHIP_MATCH_I2C_ADDR:/*for register debug*/ - switch (reg->match.addr) { - case 0: /* Cx231xx - internal registers */ - ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, - (u16)reg->reg, value, 4); - reg->val = value[0] | value[1] << 8 | - value[2] << 16 | value[3] << 24; - - break; - case 0x600:/* AFE - read byte */ - ret = cx231xx_read_i2c_master(dev, AFE_DEVICE_ADDRESS, - (u16)reg->reg, 2, - &data, 1 , 0); - reg->val = le32_to_cpu(data & 0xff); - break; - - case 0x880:/* Video Block - read byte */ - if (reg->reg < 0x0b) { - ret = cx231xx_read_i2c_master(dev, - VID_BLK_I2C_ADDRESS, - (u16)reg->reg, 2, - &data, 1 , 0); - reg->val = le32_to_cpu(data & 0xff); - } else { - ret = cx231xx_read_i2c_master(dev, - VID_BLK_I2C_ADDRESS, - (u16)reg->reg, 2, - &data, 4 , 0); - reg->val = le32_to_cpu(data); - } - break; - case 0x980: - ret = cx231xx_read_i2c_master(dev, - I2S_BLK_DEVICE_ADDRESS, - (u16)reg->reg, 1, - &data, 1 , 0); - reg->val = le32_to_cpu(data & 0xff); - break; - case 0x400: - ret = - cx231xx_read_i2c_master(dev, 0x40, - (u16)reg->reg, 1, - &data, 1 , 0); - reg->val = le32_to_cpu(data & 0xff); - break; - case 0xc01: - ret = - cx231xx_read_i2c_master(dev, 0xc0, - (u16)reg->reg, 2, - &data, 38, 1); - reg->val = le32_to_cpu(data); - break; - case 0x022: - ret = - cx231xx_read_i2c_master(dev, 0x02, - (u16)reg->reg, 1, - &data, 1, 2); - reg->val = le32_to_cpu(data & 0xff); - break; - case 0x322: - ret = cx231xx_read_i2c_master(dev, - 0x32, - (u16)reg->reg, 1, - &data, 4 , 2); - reg->val = le32_to_cpu(data); - break; - case 0x342: - ret = cx231xx_read_i2c_master(dev, - 0x34, - (u16)reg->reg, 1, - &data, 4 , 2); - reg->val = le32_to_cpu(data); - break; - - default: - cx231xx_info("no match device address!!\n"); - break; - } - return ret < 0 ? ret : 0; - /*return -EINVAL;*/ - default: - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - } - - call_all(dev, core, g_register, reg); - - return ret; -} - -static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int ret = 0; - __le64 buf; - u32 value; - u8 data[4] = { 0, 0, 0, 0 }; - - buf = cpu_to_le64(reg->val); - - switch (reg->match.type) { - case V4L2_CHIP_MATCH_HOST: - { - value = (u32) buf & 0xffffffff; - - switch (reg->match.addr) { - case 0: /* cx231xx internal registers */ - data[0] = (u8) value; - data[1] = (u8) (value >> 8); - data[2] = (u8) (value >> 16); - data[3] = (u8) (value >> 24); - ret = cx231xx_write_ctrl_reg(dev, - VRT_SET_REGISTER, - (u16)reg->reg, data, - 4); - break; - case 1: /* AFE - read byte */ - ret = cx231xx_write_i2c_data(dev, - AFE_DEVICE_ADDRESS, - (u16)reg->reg, 2, - value, 1); - break; - case 14: /* AFE - read dword */ - ret = cx231xx_write_i2c_data(dev, - AFE_DEVICE_ADDRESS, - (u16)reg->reg, 2, - value, 4); - break; - case 2: /* Video Block - read byte */ - ret = - cx231xx_write_i2c_data(dev, - VID_BLK_I2C_ADDRESS, - (u16)reg->reg, 2, - value, 1); - break; - case 24: /* Video Block - read dword */ - ret = - cx231xx_write_i2c_data(dev, - VID_BLK_I2C_ADDRESS, - (u16)reg->reg, 2, - value, 4); - break; - case 3: /* I2S block - read byte */ - ret = - cx231xx_write_i2c_data(dev, - I2S_BLK_DEVICE_ADDRESS, - (u16)reg->reg, 1, - value, 1); - break; - case 34: /* I2S block - read dword */ - ret = - cx231xx_write_i2c_data(dev, - I2S_BLK_DEVICE_ADDRESS, - (u16)reg->reg, 1, - value, 4); - break; - } - } - return ret < 0 ? ret : 0; - case V4L2_CHIP_MATCH_I2C_ADDR: - { - value = (u32) buf & 0xffffffff; - - switch (reg->match.addr) { - case 0:/*cx231xx internal registers*/ - data[0] = (u8) value; - data[1] = (u8) (value >> 8); - data[2] = (u8) (value >> 16); - data[3] = (u8) (value >> 24); - ret = cx231xx_write_ctrl_reg(dev, - VRT_SET_REGISTER, - (u16)reg->reg, data, - 4); - break; - case 0x600:/* AFE - read byte */ - ret = cx231xx_write_i2c_master(dev, - AFE_DEVICE_ADDRESS, - (u16)reg->reg, 2, - value, 1 , 0); - break; - - case 0x880:/* Video Block - read byte */ - if (reg->reg < 0x0b) - cx231xx_write_i2c_master(dev, - VID_BLK_I2C_ADDRESS, - (u16)reg->reg, 2, - value, 1, 0); - else - cx231xx_write_i2c_master(dev, - VID_BLK_I2C_ADDRESS, - (u16)reg->reg, 2, - value, 4, 0); - break; - case 0x980: - ret = - cx231xx_write_i2c_master(dev, - I2S_BLK_DEVICE_ADDRESS, - (u16)reg->reg, 1, - value, 1, 0); - break; - case 0x400: - ret = - cx231xx_write_i2c_master(dev, - 0x40, - (u16)reg->reg, 1, - value, 1, 0); - break; - case 0xc01: - ret = - cx231xx_write_i2c_master(dev, - 0xc0, - (u16)reg->reg, 1, - value, 1, 1); - break; - - case 0x022: - ret = - cx231xx_write_i2c_master(dev, - 0x02, - (u16)reg->reg, 1, - value, 1, 2); - case 0x322: - ret = - cx231xx_write_i2c_master(dev, - 0x32, - (u16)reg->reg, 1, - value, 4, 2); - break; - - case 0x342: - ret = - cx231xx_write_i2c_master(dev, - 0x34, - (u16)reg->reg, 1, - value, 4, 2); - break; - default: - cx231xx_info("no match device address, " - "the value is %x\n", reg->match.addr); - break; - - } - - } - default: - break; - } - - call_all(dev, core, s_register, reg); - - return ret; -} -#endif - -static int vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cc) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - cc->bounds.left = 0; - cc->bounds.top = 0; - cc->bounds.width = dev->width; - cc->bounds.height = dev->height; - cc->defrect = cc->bounds; - cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ - cc->pixelaspect.denominator = 59; - - return 0; -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - rc = res_get(fh); - - if (likely(rc >= 0)) - rc = videobuf_streamon(&fh->vb_vidq); - - call_all(dev, video, s_stream, 1); - - return rc; -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - if (type != fh->type) - return -EINVAL; - - cx25840_call(dev, video, s_stream, 0); - - videobuf_streamoff(&fh->vb_vidq); - res_free(fh); - - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - strlcpy(cap->driver, "cx231xx", sizeof(cap->driver)); - strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - - cap->version = CX231XX_VERSION_CODE; - - cap->capabilities = V4L2_CAP_VBI_CAPTURE | -#if 0 - V4L2_CAP_SLICED_VBI_CAPTURE | -#endif - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (unlikely(f->index >= ARRAY_SIZE(format))) - return -EINVAL; - - strlcpy(f->description, format[f->index].name, sizeof(f->description)); - f->pixelformat = format[f->index].fourcc; - - return 0; -} - -/* Sliced VBI ioctls */ -static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - f->fmt.sliced.service_set = 0; - - call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced); - - if (f->fmt.sliced.service_set == 0) - rc = -EINVAL; - - return rc; -} - -static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced); - - if (f->fmt.sliced.service_set == 0) - return -EINVAL; - - return 0; -} - -/* RAW VBI ioctls */ - -static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - f->fmt.vbi.sampling_rate = 6750000 * 4; - f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; - f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 0; - f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ? - PAL_VBI_START_LINE : NTSC_VBI_START_LINE; - f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ? - PAL_VBI_LINES : NTSC_VBI_LINES; - f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ? - PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263; - f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; - - return 0; - -} - -static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - if (dev->vbi_stream_on && !fh->stream_on) { - cx231xx_errdev("%s device in use by another fh\n", __func__); - return -EBUSY; - } - - f->type = V4L2_BUF_TYPE_VBI_CAPTURE; - f->fmt.vbi.sampling_rate = 6750000 * 4; - f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; - f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 0; - f->fmt.vbi.flags = 0; - f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ? - PAL_VBI_START_LINE : NTSC_VBI_START_LINE; - f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ? - PAL_VBI_LINES : NTSC_VBI_LINES; - f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ? - PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263; - f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; - - return 0; - -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return videobuf_reqbufs(&fh->vb_vidq, rb); -} - -static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return videobuf_querybuf(&fh->vb_vidq, b); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return videobuf_qbuf(&fh->vb_vidq, b); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); -} - -/* ----------------------------------------------------------- */ -/* RADIO ESPECIFIC IOCTLS */ -/* ----------------------------------------------------------- */ - -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; - - strlcpy(cap->driver, "cx231xx", sizeof(cap->driver)); - strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - - cap->version = CX231XX_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; - - if (unlikely(t->index > 0)) - return -EINVAL; - - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - call_all(dev, tuner, s_tuner, t); - - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name, "Radio"); - return 0; -} - -static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; - - if (0 != t->index) - return -EINVAL; - - call_all(dev, tuner, s_tuner, t); - - return 0; -} - -static int radio_s_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input(struct file *file, void *fh, unsigned int i) -{ - return 0; -} - -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - int i; - - if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - for (i = 0; i < CX231XX_CTLS; i++) { - if (cx231xx_ctls[i].v.id == c->id) - break; - } - if (i == CX231XX_CTLS) - return -EINVAL; - *c = cx231xx_ctls[i].v; - } else - *c = no_ctl; - return 0; -} - -/* - * cx231xx_v4l2_open() - * inits the device and starts isoc transfer - */ -static int cx231xx_v4l2_open(struct file *filp) -{ - int errCode = 0, radio = 0; - struct video_device *vdev = video_devdata(filp); - struct cx231xx *dev = video_drvdata(filp); - struct cx231xx_fh *fh; - enum v4l2_buf_type fh_type = 0; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - } - - cx231xx_videodbg("open dev=%s type=%s users=%d\n", - video_device_node_name(vdev), v4l2_type_names[fh_type], - dev->users); - -#if 0 - errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); - if (errCode < 0) { - cx231xx_errdev - ("Device locked on digital mode. Can't open analog\n"); - return -EBUSY; - } -#endif - - fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL); - if (!fh) { - cx231xx_errdev("cx231xx-video.c: Out of memory?!\n"); - return -ENOMEM; - } - fh->dev = dev; - fh->radio = radio; - fh->type = fh_type; - filp->private_data = fh; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { - dev->width = norm_maxw(dev); - dev->height = norm_maxh(dev); - - /* Power up in Analog TV mode */ - if (dev->board.external_av) - cx231xx_set_power_mode(dev, - POLARIS_AVMODE_ENXTERNAL_AV); - else - cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV); - -#if 0 - cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); -#endif - - /* set video alternate setting */ - cx231xx_set_video_alternate(dev); - - /* Needed, since GPIO might have disabled power of - some i2c device */ - cx231xx_config_i2c(dev); - - /* device needs to be initialized before isoc transfer */ - dev->video_input = dev->video_input > 2 ? 2 : dev->video_input; - - } - if (fh->radio) { - cx231xx_videodbg("video_open: setting radio device\n"); - - /* cx231xx_start_radio(dev); */ - - call_all(dev, tuner, s_radio); - } - - dev->users++; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops, - NULL, &dev->video_mode.slock, - fh->type, V4L2_FIELD_INTERLACED, - sizeof(struct cx231xx_buffer), - fh, &dev->lock); - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - /* Set the required alternate setting VBI interface works in - Bulk mode only */ - cx231xx_set_alt_setting(dev, INDEX_VANC, 0); - - videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops, - NULL, &dev->vbi_mode.slock, - fh->type, V4L2_FIELD_SEQ_TB, - sizeof(struct cx231xx_buffer), - fh, &dev->lock); - } - - return errCode; -} - -/* - * cx231xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -void cx231xx_release_analog_resources(struct cx231xx *dev) -{ - - /*FIXME: I2C IR should be disconnected */ - - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - if (dev->vbi_dev) { - cx231xx_info("V4L2 device %s deregistered\n", - video_device_node_name(dev->vbi_dev)); - if (video_is_registered(dev->vbi_dev)) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->vdev) { - cx231xx_info("V4L2 device %s deregistered\n", - video_device_node_name(dev->vdev)); - - if (dev->board.has_417) - cx231xx_417_unregister(dev); - - if (video_is_registered(dev->vdev)) - video_unregister_device(dev->vdev); - else - video_device_release(dev->vdev); - dev->vdev = NULL; - } -} - -/* - * cx231xx_v4l2_close() - * stops streaming and deallocates all resources allocated by the v4l2 - * calls and ioctls - */ -static int cx231xx_v4l2_close(struct file *filp) -{ - struct cx231xx_fh *fh = filp->private_data; - struct cx231xx *dev = fh->dev; - - cx231xx_videodbg("users=%d\n", dev->users); - - cx231xx_videodbg("users=%d\n", dev->users); - if (res_check(fh)) - res_free(fh); - - /* - * To workaround error number=-71 on EP0 for VideoGrabber, - * need exclude following. - * FIXME: It is probably safe to remove most of these, as we're - * now avoiding the alternate setting for INDEX_VANC - */ - if (!dev->board.no_alt_vanc) - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - - /* the device is already disconnect, - free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - if (atomic_read(&dev->devlist_count) > 0) { - cx231xx_release_resources(dev); - kfree(dev); - dev = NULL; - return 0; - } - return 0; - } - - /* do this before setting alternate! */ - cx231xx_uninit_vbi_isoc(dev); - - /* set alternate 0 */ - if (!dev->vbi_or_sliced_cc_mode) - cx231xx_set_alt_setting(dev, INDEX_VANC, 0); - else - cx231xx_set_alt_setting(dev, INDEX_HANC, 0); - - kfree(fh); - dev->users--; - wake_up_interruptible_nr(&dev->open, 1); - return 0; - } - - if (dev->users == 1) { - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - - /* the device is already disconnect, - free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - cx231xx_release_resources(dev); - kfree(dev); - dev = NULL; - return 0; - } - - /* Save some power by putting tuner to sleep */ - call_all(dev, core, s_power, 0); - - /* do this before setting alternate! */ - if (dev->USE_ISO) - cx231xx_uninit_isoc(dev); - else - cx231xx_uninit_bulk(dev); - cx231xx_set_mode(dev, CX231XX_SUSPEND); - - /* set alternate 0 */ - cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0); - } - kfree(fh); - dev->users--; - wake_up_interruptible_nr(&dev->open, 1); - return 0; -} - -/* - * cx231xx_v4l2_read() - * will allocate buffers when called for the first time - */ -static ssize_t -cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t *pos) -{ - struct cx231xx_fh *fh = filp->private_data; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) || - (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) { - rc = res_get(fh); - - if (unlikely(rc < 0)) - return rc; - - return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - } - return 0; -} - -/* - * cx231xx_v4l2_poll() - * will allocate buffers when called for the first time - */ -static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait) -{ - struct cx231xx_fh *fh = filp->private_data; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - rc = res_get(fh); - - if (unlikely(rc < 0)) - return POLLERR; - - if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) || - (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) - return videobuf_poll_stream(filp, &fh->vb_vidq, wait); - else - return POLLERR; -} - -/* - * cx231xx_v4l2_mmap() - */ -static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct cx231xx_fh *fh = filp->private_data; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - rc = res_get(fh); - - if (unlikely(rc < 0)) - return rc; - - rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); - - cx231xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - - (unsigned long)vma->vm_start, rc); - - return rc; -} - -static const struct v4l2_file_operations cx231xx_v4l_fops = { - .owner = THIS_MODULE, - .open = cx231xx_v4l2_open, - .release = cx231xx_v4l2_close, - .read = cx231xx_v4l2_read, - .poll = cx231xx_v4l2_poll, - .mmap = cx231xx_v4l2_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, - .vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = vidioc_try_fmt_vbi_cap, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_cropcap = vidioc_cropcap, - .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, - .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_g_std = vidioc_g_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif -}; - -static struct video_device cx231xx_vbi_template; - -static const struct video_device cx231xx_video_template = { - .fops = &cx231xx_v4l_fops, - .release = video_device_release, - .ioctl_ops = &video_ioctl_ops, - .tvnorms = V4L2_STD_ALL, - .current_norm = V4L2_STD_PAL, -}; - -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = cx231xx_v4l2_open, - .release = cx231xx_v4l2_close, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif -}; - -static struct video_device cx231xx_radio_template = { - .name = "cx231xx-radio", - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, -}; - -/******************************** usb interface ******************************/ - -static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, - const struct video_device - *template, const char *type_name) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - - *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; - vfd->debug = video_debug; - vfd->lock = &dev->lock; - - snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); - - video_set_drvdata(vfd, dev); - return vfd; -} - -int cx231xx_register_analog_devices(struct cx231xx *dev) -{ - int ret; - - cx231xx_info("%s: v4l2 driver version %d.%d.%d\n", - dev->name, - (CX231XX_VERSION_CODE >> 16) & 0xff, - (CX231XX_VERSION_CODE >> 8) & 0xff, - CX231XX_VERSION_CODE & 0xff); - - /* set default norm */ - /*dev->norm = cx231xx_video_template.current_norm; */ - dev->width = norm_maxw(dev); - dev->height = norm_maxh(dev); - dev->interlaced = 0; - - /* Analog specific initialization */ - dev->format = &format[0]; - - /* Set the initial input */ - video_mux(dev, dev->video_input); - - /* Audio defaults */ - dev->mute = 1; - dev->volume = 0x1f; - - /* enable vbi capturing */ - /* write code here... */ - - /* allocate and fill video video_device struct */ - dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video"); - if (!dev->vdev) { - cx231xx_errdev("cannot allocate video_device.\n"); - return -ENODEV; - } - - /* register v4l2 video video_device */ - ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, - video_nr[dev->devno]); - if (ret) { - cx231xx_errdev("unable to register video device (error=%i).\n", - ret); - return ret; - } - - cx231xx_info("%s/0: registered device %s [v4l2]\n", - dev->name, video_device_node_name(dev->vdev)); - - /* Initialize VBI template */ - memcpy(&cx231xx_vbi_template, &cx231xx_video_template, - sizeof(cx231xx_vbi_template)); - strcpy(cx231xx_vbi_template.name, "cx231xx-vbi"); - - /* Allocate and fill vbi video_device struct */ - dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi"); - - /* register v4l2 vbi video_device */ - ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, - vbi_nr[dev->devno]); - if (ret < 0) { - cx231xx_errdev("unable to register vbi device\n"); - return ret; - } - - cx231xx_info("%s/0: registered device %s\n", - dev->name, video_device_node_name(dev->vbi_dev)); - - if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) { - dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template, - "radio"); - if (!dev->radio_dev) { - cx231xx_errdev("cannot allocate video_device.\n"); - return -ENODEV; - } - ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr[dev->devno]); - if (ret < 0) { - cx231xx_errdev("can't register radio device\n"); - return ret; - } - cx231xx_info("Registered radio device as %s\n", - video_device_node_name(dev->radio_dev)); - } - - cx231xx_info("V4L2 device registered as %s and %s\n", - video_device_node_name(dev->vdev), - video_device_node_name(dev->vbi_dev)); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -config VIDEO_CX231XX - tristate "Conexant cx231xx USB video capture support" - depends on VIDEO_DEV && I2C - select VIDEO_TUNER - select VIDEO_TVEEPROM - depends on RC_CORE - select VIDEOBUF_VMALLOC - select VIDEO_CX25840 - select VIDEO_CX2341X - - ---help--- - This is a video4linux driver for Conexant 231xx USB based TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx231xx - -config VIDEO_CX231XX_RC - bool "Conexant cx231xx Remote Controller additional support" - depends on RC_CORE - depends on VIDEO_CX231XX - default y - ---help--- - cx231xx hardware has a builtin RX/TX support. However, a few - designs opted to not use it, but, instead, some other hardware. - This module enables the usage of those other hardware, like the - ones used with ISDB-T boards. - - On most cases, all you need for IR is mceusb module. - -config VIDEO_CX231XX_ALSA - tristate "Conexant Cx231xx ALSA audio module" - depends on VIDEO_CX231XX && SND - select SND_PCM - - ---help--- - This is an ALSA driver for Cx231xx USB based TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx231xx-alsa - -config VIDEO_CX231XX_DVB - tristate "DVB/ATSC Support for Cx231xx based TV cards" - depends on VIDEO_CX231XX && DVB_CORE - select VIDEOBUF_DVB - select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_NXP18271 if !DVB_FE_CUSTOMISE - select DVB_MB86A20S if !DVB_FE_CUSTOMISE - - ---help--- - This adds support for DVB cards based on the - Conexant cx231xx chips. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx231xx/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -cx231xx-y += cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o -cx231xx-y += cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o -cx231xx-$(CONFIG_VIDEO_CX231XX_RC) += cx231xx-input.o - -cx231xx-alsa-objs := cx231xx-audio.o - -obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o -obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o -obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-usb - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx2341x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx2341x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx2341x.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx2341x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1726 +0,0 @@ -/* - * cx2341x - generic code for cx23415/6/8 based devices - * - * Copyright (C) 2006 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -MODULE_DESCRIPTION("cx23415/6/8 driver"); -MODULE_AUTHOR("Hans Verkuil"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -/********************** COMMON CODE *********************/ - -/* definitions for audio properties bits 29-28 */ -#define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0 -#define CX2341X_AUDIO_ENCODING_METHOD_AC3 1 -#define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2 - -static const char *cx2341x_get_name(u32 id) -{ - switch (id) { - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: - return "Spatial Filter Mode"; - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: - return "Spatial Filter"; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: - return "Spatial Luma Filter Type"; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: - return "Spatial Chroma Filter Type"; - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: - return "Temporal Filter Mode"; - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: - return "Temporal Filter"; - case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: - return "Median Filter Type"; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: - return "Median Luma Filter Maximum"; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: - return "Median Luma Filter Minimum"; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: - return "Median Chroma Filter Maximum"; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: - return "Median Chroma Filter Minimum"; - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - return "Insert Navigation Packets"; - } - return NULL; -} - -static const char **cx2341x_get_menu(u32 id) -{ - static const char *cx2341x_video_spatial_filter_mode_menu[] = { - "Manual", - "Auto", - NULL - }; - - static const char *cx2341x_video_luma_spatial_filter_type_menu[] = { - "Off", - "1D Horizontal", - "1D Vertical", - "2D H/V Separable", - "2D Symmetric non-separable", - NULL - }; - - static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = { - "Off", - "1D Horizontal", - NULL - }; - - static const char *cx2341x_video_temporal_filter_mode_menu[] = { - "Manual", - "Auto", - NULL - }; - - static const char *cx2341x_video_median_filter_type_menu[] = { - "Off", - "Horizontal", - "Vertical", - "Horizontal/Vertical", - "Diagonal", - NULL - }; - - switch (id) { - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: - return cx2341x_video_spatial_filter_mode_menu; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: - return cx2341x_video_luma_spatial_filter_type_menu; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: - return cx2341x_video_chroma_spatial_filter_type_menu; - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: - return cx2341x_video_temporal_filter_mode_menu; - case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: - return cx2341x_video_median_filter_type_menu; - } - return NULL; -} - -static void cx2341x_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, - s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags) -{ - *name = cx2341x_get_name(id); - *flags = 0; - - switch (id) { - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: - case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: - *type = V4L2_CTRL_TYPE_MENU; - *min = 0; - *step = 0; - break; - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - *type = V4L2_CTRL_TYPE_BOOLEAN; - *min = 0; - *max = *step = 1; - break; - default: - *type = V4L2_CTRL_TYPE_INTEGER; - break; - } - switch (id) { - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: - case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: - *flags |= V4L2_CTRL_FLAG_UPDATE; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: - *flags |= V4L2_CTRL_FLAG_SLIDER; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - *flags |= V4L2_CTRL_FLAG_READ_ONLY; - break; - } -} - - -/********************** OLD CODE *********************/ - -/* Must be sorted from low to high control ID! */ -const u32 cx2341x_mpeg_ctrls[] = { - V4L2_CID_MPEG_CLASS, - V4L2_CID_MPEG_STREAM_TYPE, - V4L2_CID_MPEG_STREAM_VBI_FMT, - V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, - V4L2_CID_MPEG_AUDIO_ENCODING, - V4L2_CID_MPEG_AUDIO_L2_BITRATE, - V4L2_CID_MPEG_AUDIO_MODE, - V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, - V4L2_CID_MPEG_AUDIO_EMPHASIS, - V4L2_CID_MPEG_AUDIO_CRC, - V4L2_CID_MPEG_AUDIO_MUTE, - V4L2_CID_MPEG_AUDIO_AC3_BITRATE, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_CID_MPEG_VIDEO_ASPECT, - V4L2_CID_MPEG_VIDEO_B_FRAMES, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, - V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, - V4L2_CID_MPEG_VIDEO_BITRATE, - V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, - V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, - V4L2_CID_MPEG_VIDEO_MUTE, - V4L2_CID_MPEG_VIDEO_MUTE_YUV, - V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, - V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, - V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, - V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, - V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, - V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, - 0 -}; -EXPORT_SYMBOL(cx2341x_mpeg_ctrls); - -static const struct cx2341x_mpeg_params default_params = { - /* misc */ - .capabilities = 0, - .port = CX2341X_PORT_MEMORY, - .width = 720, - .height = 480, - .is_50hz = 0, - - /* stream */ - .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, - .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, - .stream_insert_nav_packets = 0, - - /* audio */ - .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, - .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K, - .audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K, - .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO, - .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, - .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, - .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, - .audio_mute = 0, - - /* video */ - .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, - .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3, - .video_b_frames = 2, - .video_gop_size = 12, - .video_gop_closure = 1, - .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - .video_bitrate = 6000000, - .video_bitrate_peak = 8000000, - .video_temporal_decimation = 0, - .video_mute = 0, - .video_mute_yuv = 0x008080, /* YCbCr value for black */ - - /* encoding filters */ - .video_spatial_filter_mode = - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, - .video_spatial_filter = 0, - .video_luma_spatial_filter_type = - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_chroma_spatial_filter_type = - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_temporal_filter_mode = - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, - .video_temporal_filter = 8, - .video_median_filter_type = - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, - .video_luma_median_filter_top = 255, - .video_luma_median_filter_bottom = 0, - .video_chroma_median_filter_top = 255, - .video_chroma_median_filter_bottom = 0, -}; -/* Map the control ID to the correct field in the cx2341x_mpeg_params - struct. Return -EINVAL if the ID is unknown, else return 0. */ -static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params, - struct v4l2_ext_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - ctrl->value = params->audio_sampling_freq; - break; - case V4L2_CID_MPEG_AUDIO_ENCODING: - ctrl->value = params->audio_encoding; - break; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - ctrl->value = params->audio_l2_bitrate; - break; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - ctrl->value = params->audio_ac3_bitrate; - break; - case V4L2_CID_MPEG_AUDIO_MODE: - ctrl->value = params->audio_mode; - break; - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - ctrl->value = params->audio_mode_extension; - break; - case V4L2_CID_MPEG_AUDIO_EMPHASIS: - ctrl->value = params->audio_emphasis; - break; - case V4L2_CID_MPEG_AUDIO_CRC: - ctrl->value = params->audio_crc; - break; - case V4L2_CID_MPEG_AUDIO_MUTE: - ctrl->value = params->audio_mute; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - ctrl->value = params->video_encoding; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - ctrl->value = params->video_aspect; - break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - ctrl->value = params->video_b_frames; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - ctrl->value = params->video_gop_size; - break; - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - ctrl->value = params->video_gop_closure; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - ctrl->value = params->video_bitrate_mode; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - ctrl->value = params->video_bitrate; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - ctrl->value = params->video_bitrate_peak; - break; - case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: - ctrl->value = params->video_temporal_decimation; - break; - case V4L2_CID_MPEG_VIDEO_MUTE: - ctrl->value = params->video_mute; - break; - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: - ctrl->value = params->video_mute_yuv; - break; - case V4L2_CID_MPEG_STREAM_TYPE: - ctrl->value = params->stream_type; - break; - case V4L2_CID_MPEG_STREAM_VBI_FMT: - ctrl->value = params->stream_vbi_fmt; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: - ctrl->value = params->video_spatial_filter_mode; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: - ctrl->value = params->video_spatial_filter; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: - ctrl->value = params->video_luma_spatial_filter_type; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: - ctrl->value = params->video_chroma_spatial_filter_type; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: - ctrl->value = params->video_temporal_filter_mode; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: - ctrl->value = params->video_temporal_filter; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: - ctrl->value = params->video_median_filter_type; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: - ctrl->value = params->video_luma_median_filter_top; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: - ctrl->value = params->video_luma_median_filter_bottom; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: - ctrl->value = params->video_chroma_median_filter_top; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: - ctrl->value = params->video_chroma_median_filter_bottom; - break; - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - ctrl->value = params->stream_insert_nav_packets; - break; - default: - return -EINVAL; - } - return 0; -} - -/* Map the control ID to the correct field in the cx2341x_mpeg_params - struct. Return -EINVAL if the ID is unknown, else return 0. */ -static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, - struct v4l2_ext_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - if (busy) - return -EBUSY; - params->audio_sampling_freq = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_ENCODING: - if (busy) - return -EBUSY; - if (params->capabilities & CX2341X_CAP_HAS_AC3) - if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && - ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3) - return -ERANGE; - params->audio_encoding = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - if (busy) - return -EBUSY; - params->audio_l2_bitrate = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - if (busy) - return -EBUSY; - if (!(params->capabilities & CX2341X_CAP_HAS_AC3)) - return -EINVAL; - params->audio_ac3_bitrate = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_MODE: - params->audio_mode = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - params->audio_mode_extension = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_EMPHASIS: - params->audio_emphasis = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_CRC: - params->audio_crc = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_MUTE: - params->audio_mute = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - params->video_aspect = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: { - int b = ctrl->value + 1; - int gop = params->video_gop_size; - params->video_b_frames = ctrl->value; - params->video_gop_size = b * ((gop + b - 1) / b); - /* Max GOP size = 34 */ - while (params->video_gop_size > 34) - params->video_gop_size -= b; - break; - } - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: { - int b = params->video_b_frames + 1; - int gop = ctrl->value; - params->video_gop_size = b * ((gop + b - 1) / b); - /* Max GOP size = 34 */ - while (params->video_gop_size > 34) - params->video_gop_size -= b; - ctrl->value = params->video_gop_size; - break; - } - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - params->video_gop_closure = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - if (busy) - return -EBUSY; - /* MPEG-1 only allows CBR */ - if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 && - ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) - return -EINVAL; - params->video_bitrate_mode = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - if (busy) - return -EBUSY; - params->video_bitrate = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - if (busy) - return -EBUSY; - params->video_bitrate_peak = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: - params->video_temporal_decimation = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_MUTE: - params->video_mute = (ctrl->value != 0); - break; - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: - params->video_mute_yuv = ctrl->value; - break; - case V4L2_CID_MPEG_STREAM_TYPE: - if (busy) - return -EBUSY; - params->stream_type = ctrl->value; - params->video_encoding = - (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || - params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? - V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : - V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) - /* MPEG-1 implies CBR */ - params->video_bitrate_mode = - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; - break; - case V4L2_CID_MPEG_STREAM_VBI_FMT: - params->stream_vbi_fmt = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: - params->video_spatial_filter_mode = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: - params->video_spatial_filter = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: - params->video_luma_spatial_filter_type = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: - params->video_chroma_spatial_filter_type = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: - params->video_temporal_filter_mode = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: - params->video_temporal_filter = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: - params->video_median_filter_type = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: - params->video_luma_median_filter_top = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: - params->video_luma_median_filter_bottom = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: - params->video_chroma_median_filter_top = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: - params->video_chroma_median_filter_bottom = ctrl->value; - break; - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - params->stream_insert_nav_packets = ctrl->value; - break; - default: - return -EINVAL; - } - return 0; -} - -static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, - s32 min, s32 max, s32 step, s32 def) -{ - const char *name; - - switch (qctrl->id) { - /* MPEG controls */ - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: - case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - cx2341x_ctrl_fill(qctrl->id, &name, &qctrl->type, - &min, &max, &step, &def, &qctrl->flags); - qctrl->minimum = min; - qctrl->maximum = max; - qctrl->step = step; - qctrl->default_value = def; - qctrl->reserved[0] = qctrl->reserved[1] = 0; - strlcpy(qctrl->name, name, sizeof(qctrl->name)); - return 0; - - default: - return v4l2_ctrl_query_fill(qctrl, min, max, step, def); - } -} - -int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, - struct v4l2_queryctrl *qctrl) -{ - int err; - - switch (qctrl->id) { - case V4L2_CID_MPEG_CLASS: - return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); - case V4L2_CID_MPEG_STREAM_TYPE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_STREAM_TYPE_MPEG2_PS, - V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1, - V4L2_MPEG_STREAM_TYPE_MPEG2_PS); - - case V4L2_CID_MPEG_STREAM_VBI_FMT: - if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI) - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_STREAM_VBI_FMT_NONE, - V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1, - V4L2_MPEG_STREAM_VBI_FMT_NONE); - return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_STREAM_VBI_FMT_NONE, - V4L2_MPEG_STREAM_VBI_FMT_NONE, 1, - default_params.stream_vbi_fmt); - - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); - - case V4L2_CID_MPEG_AUDIO_ENCODING: - if (params->capabilities & CX2341X_CAP_HAS_AC3) { - /* - * The state of L2 & AC3 bitrate controls can change - * when this control changes, but v4l2_ctrl_query_fill() - * already sets V4L2_CTRL_FLAG_UPDATE for - * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here. - */ - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - V4L2_MPEG_AUDIO_ENCODING_AC3, 1, - default_params.audio_encoding); - } - - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, - default_params.audio_encoding); - - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - err = v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_L2_BITRATE_192K, - V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, - default_params.audio_l2_bitrate); - if (err) - return err; - if (params->capabilities & CX2341X_CAP_HAS_AC3 && - params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; - - case V4L2_CID_MPEG_AUDIO_MODE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_MODE_STEREO, - V4L2_MPEG_AUDIO_MODE_MONO, 1, - V4L2_MPEG_AUDIO_MODE_STEREO); - - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - err = v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); - if (err == 0 && - params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return err; - - case V4L2_CID_MPEG_AUDIO_EMPHASIS: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_EMPHASIS_NONE, - V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1, - V4L2_MPEG_AUDIO_EMPHASIS_NONE); - - case V4L2_CID_MPEG_AUDIO_CRC: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_CRC_NONE, - V4L2_MPEG_AUDIO_CRC_CRC16, 1, - V4L2_MPEG_AUDIO_CRC_NONE); - - case V4L2_CID_MPEG_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); - - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - err = v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_AC3_BITRATE_48K, - V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1, - default_params.audio_ac3_bitrate); - if (err) - return err; - if (params->capabilities & CX2341X_CAP_HAS_AC3) { - if (params->audio_encoding != - V4L2_MPEG_AUDIO_ENCODING_AC3) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - } else - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; - - case V4L2_CID_MPEG_VIDEO_ENCODING: - /* this setting is read-only for the cx2341x since the - V4L2_CID_MPEG_STREAM_TYPE really determines the - MPEG-1/2 setting */ - err = v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_VIDEO_ENCODING_MPEG_1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2); - if (err == 0) - qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - return err; - - case V4L2_CID_MPEG_VIDEO_ASPECT: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_VIDEO_ASPECT_1x1, - V4L2_MPEG_VIDEO_ASPECT_221x100, 1, - V4L2_MPEG_VIDEO_ASPECT_4x3); - - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2); - - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, - params->is_50hz ? 12 : 15); - - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); - - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - err = v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); - if (err == 0 && - params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return err; - - case V4L2_CID_MPEG_VIDEO_BITRATE: - return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000); - - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); - if (err == 0 && - params->video_bitrate_mode == - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return err; - - case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: - return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); - - case V4L2_CID_MPEG_VIDEO_MUTE: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); - - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */ - return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080); - - /* CX23415/6 specific */ - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: - return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, - default_params.video_spatial_filter_mode); - - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: - cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, - default_params.video_spatial_filter); - qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_spatial_filter_mode == - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; - - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: - cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, - 1, - default_params.video_luma_spatial_filter_type); - if (params->video_spatial_filter_mode == - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; - - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: - cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, - 1, - default_params.video_chroma_spatial_filter_type); - if (params->video_spatial_filter_mode == - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; - - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: - return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, - default_params.video_temporal_filter_mode); - - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: - cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, - default_params.video_temporal_filter); - qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_temporal_filter_mode == - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; - - case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: - return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, - default_params.video_median_filter_type); - - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: - cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, - default_params.video_luma_median_filter_top); - qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; - - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: - cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, - default_params.video_luma_median_filter_bottom); - qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; - - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: - cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, - default_params.video_chroma_median_filter_top); - qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; - - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: - cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, - default_params.video_chroma_median_filter_bottom); - qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; - - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, - default_params.stream_insert_nav_packets); - - default: - return -EINVAL; - - } -} -EXPORT_SYMBOL(cx2341x_ctrl_query); - -const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) -{ - static const char * const mpeg_stream_type_without_ts[] = { - "MPEG-2 Program Stream", - "", - "MPEG-1 System Stream", - "MPEG-2 DVD-compatible Stream", - "MPEG-1 VCD-compatible Stream", - "MPEG-2 SVCD-compatible Stream", - NULL - }; - - static const char *mpeg_stream_type_with_ts[] = { - "MPEG-2 Program Stream", - "MPEG-2 Transport Stream", - "MPEG-1 System Stream", - "MPEG-2 DVD-compatible Stream", - "MPEG-1 VCD-compatible Stream", - "MPEG-2 SVCD-compatible Stream", - NULL - }; - - static const char *mpeg_audio_encoding_l2_ac3[] = { - "", - "MPEG-1/2 Layer II", - "", - "", - "AC-3", - NULL - }; - - switch (id) { - case V4L2_CID_MPEG_STREAM_TYPE: - return (p->capabilities & CX2341X_CAP_HAS_TS) ? - mpeg_stream_type_with_ts : mpeg_stream_type_without_ts; - case V4L2_CID_MPEG_AUDIO_ENCODING: - return (p->capabilities & CX2341X_CAP_HAS_AC3) ? - mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id); - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: - return NULL; - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: - case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: - case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: - case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: - return cx2341x_get_menu(id); - default: - return v4l2_ctrl_get_menu(id); - } -} -EXPORT_SYMBOL(cx2341x_ctrl_get_menu); - -static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) -{ - params->audio_properties = - (params->audio_sampling_freq << 0) | - (params->audio_mode << 8) | - (params->audio_mode_extension << 10) | - (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) - ? 3 : params->audio_emphasis) << 12) | - (params->audio_crc << 14); - - if ((params->capabilities & CX2341X_CAP_HAS_AC3) && - params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) { - params->audio_properties |= - /* Not sure if this MPEG Layer II setting is required */ - ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | - (params->audio_ac3_bitrate << 4) | - (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); - } else { - /* Assuming MPEG Layer II */ - params->audio_properties |= - ((3 - params->audio_encoding) << 2) | - ((1 + params->audio_l2_bitrate) << 4); - } -} - -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, - struct v4l2_ext_controls *ctrls, unsigned int cmd) -{ - int err = 0; - int i; - - if (cmd == VIDIOC_G_EXT_CTRLS) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = cx2341x_get_ctrl(params, ctrl); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - } - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - struct v4l2_queryctrl qctrl; - const char * const *menu_items = NULL; - - qctrl.id = ctrl->id; - err = cx2341x_ctrl_query(params, &qctrl); - if (err) - break; - if (qctrl.type == V4L2_CTRL_TYPE_MENU) - menu_items = cx2341x_ctrl_get_menu(params, qctrl.id); - err = v4l2_ctrl_check(ctrl, &qctrl, menu_items); - if (err) - break; - err = cx2341x_set_ctrl(params, busy, ctrl); - if (err) - break; - } - if (err == 0 && - params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && - params->video_bitrate_peak < params->video_bitrate) { - err = -ERANGE; - ctrls->error_idx = ctrls->count; - } - if (err) - ctrls->error_idx = i; - else - cx2341x_calc_audio_properties(params); - return err; -} -EXPORT_SYMBOL(cx2341x_ext_ctrls); - -void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) -{ - *p = default_params; - cx2341x_calc_audio_properties(p); -} -EXPORT_SYMBOL(cx2341x_fill_defaults); - -static int cx2341x_api(void *priv, cx2341x_mbox_func func, - u32 cmd, int args, ...) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - va_list vargs; - int i; - - va_start(vargs, args); - - for (i = 0; i < args; i++) - data[i] = va_arg(vargs, int); - va_end(vargs); - return func(priv, cmd, args, 0, data); -} - -#define NEQ(field) (old->field != new->field) - -int cx2341x_update(void *priv, cx2341x_mbox_func func, - const struct cx2341x_mpeg_params *old, - const struct cx2341x_mpeg_params *new) -{ - static int mpeg_stream_type[] = { - 0, /* MPEG-2 PS */ - 1, /* MPEG-2 TS */ - 2, /* MPEG-1 SS */ - 14, /* DVD */ - 11, /* VCD */ - 12, /* SVCD */ - }; - - int err = 0; - int force = (old == NULL); - u16 temporal = new->video_temporal_filter; - - cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); - - if (force || NEQ(is_50hz)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, - new->is_50hz); - if (err) return err; - } - - if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) { - u16 w = new->width; - u16 h = new->height; - - if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { - w /= 2; - h /= 2; - } - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, - h, w); - if (err) return err; - } - if (force || NEQ(stream_type)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, - mpeg_stream_type[new->stream_type]); - if (err) return err; - } - if (force || NEQ(video_aspect)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, - 1 + new->video_aspect); - if (err) return err; - } - if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2, - new->video_gop_size, new->video_b_frames + 1); - if (err) return err; - } - if (force || NEQ(video_gop_closure)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, - new->video_gop_closure); - if (err) return err; - } - if (force || NEQ(audio_properties)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, - 1, new->audio_properties); - if (err) return err; - } - if (force || NEQ(audio_mute)) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, - new->audio_mute); - if (err) return err; - } - if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) || - NEQ(video_bitrate_peak)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5, - new->video_bitrate_mode, new->video_bitrate, - new->video_bitrate_peak / 400, 0, 0); - if (err) return err; - } - if (force || NEQ(video_spatial_filter_mode) || - NEQ(video_temporal_filter_mode) || - NEQ(video_median_filter_type)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, - 2, new->video_spatial_filter_mode | - (new->video_temporal_filter_mode << 1), - new->video_median_filter_type); - if (err) return err; - } - if (force || NEQ(video_luma_median_filter_bottom) || - NEQ(video_luma_median_filter_top) || - NEQ(video_chroma_median_filter_bottom) || - NEQ(video_chroma_median_filter_top)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4, - new->video_luma_median_filter_bottom, - new->video_luma_median_filter_top, - new->video_chroma_median_filter_bottom, - new->video_chroma_median_filter_top); - if (err) return err; - } - if (force || NEQ(video_luma_spatial_filter_type) || - NEQ(video_chroma_spatial_filter_type)) { - err = cx2341x_api(priv, func, - CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, - 2, new->video_luma_spatial_filter_type, - new->video_chroma_spatial_filter_type); - if (err) return err; - } - if (force || NEQ(video_spatial_filter) || - old->video_temporal_filter != temporal) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, - 2, new->video_spatial_filter, temporal); - if (err) return err; - } - if (force || NEQ(video_temporal_decimation)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, - 1, new->video_temporal_decimation); - if (err) return err; - } - if (force || NEQ(video_mute) || - (new->video_mute && NEQ(video_mute_yuv))) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, - new->video_mute | (new->video_mute_yuv << 8)); - if (err) return err; - } - if (force || NEQ(stream_insert_nav_packets)) { - err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, - 7, new->stream_insert_nav_packets); - if (err) return err; - } - return 0; -} -EXPORT_SYMBOL(cx2341x_update); - -static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id) -{ - const char * const *menu = cx2341x_ctrl_get_menu(p, id); - struct v4l2_ext_control ctrl; - - if (menu == NULL) - goto invalid; - ctrl.id = id; - if (cx2341x_get_ctrl(p, &ctrl)) - goto invalid; - while (ctrl.value-- && *menu) menu++; - if (*menu == NULL) - goto invalid; - return *menu; - -invalid: - return ""; -} - -void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) -{ - int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - - /* Stream */ - printk(KERN_INFO "%s: Stream: %s", - prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); - if (p->stream_insert_nav_packets) - printk(" (with navigation packets)"); - printk("\n"); - printk(KERN_INFO "%s: VBI Format: %s\n", - prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); - - /* Video */ - printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n", - prefix, - p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), - p->is_50hz ? 25 : 30, - (p->video_mute) ? " (muted)" : ""); - printk(KERN_INFO "%s: Video: %s, %s, %s, %d", - prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), - cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT), - cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), - p->video_bitrate); - if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) - printk(", Peak %d", p->video_bitrate_peak); - printk("\n"); - printk(KERN_INFO - "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", - prefix, - p->video_gop_size, p->video_b_frames, - p->video_gop_closure ? "" : "No "); - if (p->video_temporal_decimation) - printk(KERN_INFO "%s: Video: Temporal Decimation %d\n", - prefix, p->video_temporal_decimation); - - /* Audio */ - printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", - prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), - cx2341x_menu_item(p, - p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3 - ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE - : V4L2_CID_MPEG_AUDIO_L2_BITRATE), - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), - p->audio_mute ? " (muted)" : ""); - if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) - printk(", %s", cx2341x_menu_item(p, - V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); - printk(", %s, %s\n", - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS), - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); - - /* Encoding filters */ - printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n", - prefix, - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), - p->video_spatial_filter); - - printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", - prefix, - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), - p->video_temporal_filter); - printk(KERN_INFO - "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", - prefix, - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), - p->video_luma_median_filter_bottom, - p->video_luma_median_filter_top, - p->video_chroma_median_filter_bottom, - p->video_chroma_median_filter_top); -} -EXPORT_SYMBOL(cx2341x_log_status); - - - -/********************** NEW CODE *********************/ - -static inline struct cx2341x_handler *to_cxhdl(struct v4l2_ctrl *ctrl) -{ - return container_of(ctrl->handler, struct cx2341x_handler, hdl); -} - -static int cx2341x_hdl_api(struct cx2341x_handler *hdl, - u32 cmd, int args, ...) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - va_list vargs; - int i; - - va_start(vargs, args); - - for (i = 0; i < args; i++) - data[i] = va_arg(vargs, int); - va_end(vargs); - return hdl->func(hdl->priv, cmd, args, 0, data); -} - -/* ctrl->handler->lock is held, so it is safe to access cur.val */ -static inline int cx2341x_neq(struct v4l2_ctrl *ctrl) -{ - return ctrl && ctrl->val != ctrl->cur.val; -} - -static int cx2341x_try_ctrl(struct v4l2_ctrl *ctrl) -{ - struct cx2341x_handler *hdl = to_cxhdl(ctrl); - s32 val = ctrl->val; - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_B_FRAMES: { - /* video gop cluster */ - int b = val + 1; - int gop = hdl->video_gop_size->val; - - gop = b * ((gop + b - 1) / b); - - /* Max GOP size = 34 */ - while (gop > 34) - gop -= b; - hdl->video_gop_size->val = gop; - break; - } - - case V4L2_CID_MPEG_STREAM_TYPE: - /* stream type cluster */ - hdl->video_encoding->val = - (hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || - hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? - V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : - V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - if (hdl->video_encoding->val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) - /* MPEG-1 implies CBR */ - hdl->video_bitrate_mode->val = - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; - /* peak bitrate shall be >= normal bitrate */ - if (hdl->video_bitrate_mode->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && - hdl->video_bitrate_peak->val < hdl->video_bitrate->val) - hdl->video_bitrate_peak->val = hdl->video_bitrate->val; - break; - } - return 0; -} - -static int cx2341x_s_ctrl(struct v4l2_ctrl *ctrl) -{ - static const int mpeg_stream_type[] = { - 0, /* MPEG-2 PS */ - 1, /* MPEG-2 TS */ - 2, /* MPEG-1 SS */ - 14, /* DVD */ - 11, /* VCD */ - 12, /* SVCD */ - }; - struct cx2341x_handler *hdl = to_cxhdl(ctrl); - s32 val = ctrl->val; - u32 props; - int err; - - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_VBI_FMT: - if (hdl->ops && hdl->ops->s_stream_vbi_fmt) - return hdl->ops->s_stream_vbi_fmt(hdl, val); - return 0; - - case V4L2_CID_MPEG_VIDEO_ASPECT: - return cx2341x_hdl_api(hdl, - CX2341X_ENC_SET_ASPECT_RATIO, 1, val + 1); - - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_CLOSURE, 1, val); - - case V4L2_CID_MPEG_AUDIO_MUTE: - return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_AUDIO, 1, val); - - case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: - return cx2341x_hdl_api(hdl, - CX2341X_ENC_SET_FRAME_DROP_RATE, 1, val); - - case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: - return cx2341x_hdl_api(hdl, CX2341X_ENC_MISC, 2, 7, val); - - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - /* audio properties cluster */ - props = (hdl->audio_sampling_freq->val << 0) | - (hdl->audio_mode->val << 8) | - (hdl->audio_mode_extension->val << 10) | - (hdl->audio_crc->val << 14); - if (hdl->audio_emphasis->val == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) - props |= 3 << 12; - else - props |= hdl->audio_emphasis->val << 12; - - if (hdl->audio_encoding->val == V4L2_MPEG_AUDIO_ENCODING_AC3) { - props |= -#if 1 - /* Not sure if this MPEG Layer II setting is required */ - ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | -#endif - (hdl->audio_ac3_bitrate->val << 4) | - (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); - } else { - /* Assuming MPEG Layer II */ - props |= - ((3 - hdl->audio_encoding->val) << 2) | - ((1 + hdl->audio_l2_bitrate->val) << 4); - } - err = cx2341x_hdl_api(hdl, - CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, props); - if (err) - return err; - - hdl->audio_properties = props; - if (hdl->audio_ac3_bitrate) { - int is_ac3 = hdl->audio_encoding->val == - V4L2_MPEG_AUDIO_ENCODING_AC3; - - v4l2_ctrl_activate(hdl->audio_ac3_bitrate, is_ac3); - v4l2_ctrl_activate(hdl->audio_l2_bitrate, !is_ac3); - } - v4l2_ctrl_activate(hdl->audio_mode_extension, - hdl->audio_mode->val == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO); - if (cx2341x_neq(hdl->audio_sampling_freq) && - hdl->ops && hdl->ops->s_audio_sampling_freq) - return hdl->ops->s_audio_sampling_freq(hdl, hdl->audio_sampling_freq->val); - if (cx2341x_neq(hdl->audio_mode) && - hdl->ops && hdl->ops->s_audio_mode) - return hdl->ops->s_audio_mode(hdl, hdl->audio_mode->val); - return 0; - - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - /* video gop cluster */ - return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_PROPERTIES, 2, - hdl->video_gop_size->val, - hdl->video_b_frames->val + 1); - - case V4L2_CID_MPEG_STREAM_TYPE: - /* stream type cluster */ - err = cx2341x_hdl_api(hdl, - CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[val]); - if (err) - return err; - - err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_BIT_RATE, 5, - hdl->video_bitrate_mode->val, - hdl->video_bitrate->val, - hdl->video_bitrate_peak->val / 400, 0, 0); - if (err) - return err; - - v4l2_ctrl_activate(hdl->video_bitrate_mode, - hdl->video_encoding->val != V4L2_MPEG_VIDEO_ENCODING_MPEG_1); - v4l2_ctrl_activate(hdl->video_bitrate_peak, - hdl->video_bitrate_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); - if (cx2341x_neq(hdl->video_encoding) && - hdl->ops && hdl->ops->s_video_encoding) - return hdl->ops->s_video_encoding(hdl, hdl->video_encoding->val); - return 0; - - case V4L2_CID_MPEG_VIDEO_MUTE: - /* video mute cluster */ - return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_VIDEO, 1, - hdl->video_mute->val | - (hdl->video_mute_yuv->val << 8)); - - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: { - int active_filter; - - /* video filter mode */ - err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_MODE, 2, - hdl->video_spatial_filter_mode->val | - (hdl->video_temporal_filter_mode->val << 1), - hdl->video_median_filter_type->val); - if (err) - return err; - - active_filter = hdl->video_spatial_filter_mode->val != - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO; - v4l2_ctrl_activate(hdl->video_spatial_filter, active_filter); - v4l2_ctrl_activate(hdl->video_luma_spatial_filter_type, active_filter); - v4l2_ctrl_activate(hdl->video_chroma_spatial_filter_type, active_filter); - active_filter = hdl->video_temporal_filter_mode->val != - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO; - v4l2_ctrl_activate(hdl->video_temporal_filter, active_filter); - active_filter = hdl->video_median_filter_type->val != - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF; - v4l2_ctrl_activate(hdl->video_luma_median_filter_bottom, active_filter); - v4l2_ctrl_activate(hdl->video_luma_median_filter_top, active_filter); - v4l2_ctrl_activate(hdl->video_chroma_median_filter_bottom, active_filter); - v4l2_ctrl_activate(hdl->video_chroma_median_filter_top, active_filter); - return 0; - } - - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: - /* video filter type cluster */ - return cx2341x_hdl_api(hdl, - CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, - hdl->video_luma_spatial_filter_type->val, - hdl->video_chroma_spatial_filter_type->val); - - case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: - /* video filter cluster */ - return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2, - hdl->video_spatial_filter->val, - hdl->video_temporal_filter->val); - - case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: - /* video median cluster */ - return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_CORING_LEVELS, 4, - hdl->video_luma_median_filter_bottom->val, - hdl->video_luma_median_filter_top->val, - hdl->video_chroma_median_filter_bottom->val, - hdl->video_chroma_median_filter_top->val); - } - return -EINVAL; -} - -static const struct v4l2_ctrl_ops cx2341x_ops = { - .try_ctrl = cx2341x_try_ctrl, - .s_ctrl = cx2341x_s_ctrl, -}; - -static struct v4l2_ctrl *cx2341x_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, - u32 id, s32 min, s32 max, s32 step, s32 def) -{ - struct v4l2_ctrl_config cfg; - - cx2341x_ctrl_fill(id, &cfg.name, &cfg.type, &min, &max, &step, &def, &cfg.flags); - cfg.ops = &cx2341x_ops; - cfg.id = id; - cfg.min = min; - cfg.max = max; - cfg.def = def; - if (cfg.type == V4L2_CTRL_TYPE_MENU) { - cfg.step = 0; - cfg.menu_skip_mask = step; - cfg.qmenu = cx2341x_get_menu(id); - } else { - cfg.step = step; - cfg.menu_skip_mask = 0; - } - return v4l2_ctrl_new_custom(hdl, &cfg, NULL); -} - -static struct v4l2_ctrl *cx2341x_ctrl_new_std(struct v4l2_ctrl_handler *hdl, - u32 id, s32 min, s32 max, s32 step, s32 def) -{ - return v4l2_ctrl_new_std(hdl, &cx2341x_ops, id, min, max, step, def); -} - -static struct v4l2_ctrl *cx2341x_ctrl_new_menu(struct v4l2_ctrl_handler *hdl, - u32 id, s32 max, s32 mask, s32 def) -{ - return v4l2_ctrl_new_std_menu(hdl, &cx2341x_ops, id, max, mask, def); -} - -int cx2341x_handler_init(struct cx2341x_handler *cxhdl, - unsigned nr_of_controls_hint) -{ - struct v4l2_ctrl_handler *hdl = &cxhdl->hdl; - u32 caps = cxhdl->capabilities; - int has_sliced_vbi = caps & CX2341X_CAP_HAS_SLICED_VBI; - int has_ac3 = caps & CX2341X_CAP_HAS_AC3; - int has_ts = caps & CX2341X_CAP_HAS_TS; - - cxhdl->width = 720; - cxhdl->height = 480; - - v4l2_ctrl_handler_init(hdl, nr_of_controls_hint); - - /* Add controls in ascending control ID order for fastest - insertion time. */ - cxhdl->stream_type = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_STREAM_TYPE, - V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, has_ts ? 0 : 2, - V4L2_MPEG_STREAM_TYPE_MPEG2_PS); - cxhdl->stream_vbi_fmt = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_STREAM_VBI_FMT, - V4L2_MPEG_STREAM_VBI_FMT_IVTV, has_sliced_vbi ? 0 : 2, - V4L2_MPEG_STREAM_VBI_FMT_NONE); - cxhdl->audio_sampling_freq = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 0, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); - cxhdl->audio_encoding = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_AUDIO_ENCODING, - V4L2_MPEG_AUDIO_ENCODING_AC3, has_ac3 ? ~0x12 : ~0x2, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2); - cxhdl->audio_l2_bitrate = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_AUDIO_L2_BITRATE, - V4L2_MPEG_AUDIO_L2_BITRATE_384K, 0x1ff, - V4L2_MPEG_AUDIO_L2_BITRATE_224K); - cxhdl->audio_mode = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_AUDIO_MODE, - V4L2_MPEG_AUDIO_MODE_MONO, 0, - V4L2_MPEG_AUDIO_MODE_STEREO); - cxhdl->audio_mode_extension = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 0, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); - cxhdl->audio_emphasis = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_AUDIO_EMPHASIS, - V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 0, - V4L2_MPEG_AUDIO_EMPHASIS_NONE); - cxhdl->audio_crc = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_AUDIO_CRC, - V4L2_MPEG_AUDIO_CRC_CRC16, 0, - V4L2_MPEG_AUDIO_CRC_NONE); - - cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_AUDIO_MUTE, 0, 1, 1, 0); - if (has_ac3) - cxhdl->audio_ac3_bitrate = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_AUDIO_AC3_BITRATE, - V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 0x03, - V4L2_MPEG_AUDIO_AC3_BITRATE_224K); - cxhdl->video_encoding = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 0, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2); - cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_VIDEO_ASPECT, - V4L2_MPEG_VIDEO_ASPECT_221x100, 0, - V4L2_MPEG_VIDEO_ASPECT_4x3); - cxhdl->video_b_frames = cx2341x_ctrl_new_std(hdl, - V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 33, 1, 2); - cxhdl->video_gop_size = cx2341x_ctrl_new_std(hdl, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, - 1, 34, 1, cxhdl->is_50hz ? 12 : 15); - cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1); - cxhdl->video_bitrate_mode = cx2341x_ctrl_new_menu(hdl, - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); - cxhdl->video_bitrate = cx2341x_ctrl_new_std(hdl, - V4L2_CID_MPEG_VIDEO_BITRATE, - 0, 27000000, 1, 6000000); - cxhdl->video_bitrate_peak = cx2341x_ctrl_new_std(hdl, - V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, - 0, 27000000, 1, 8000000); - cx2341x_ctrl_new_std(hdl, - V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, 0, 255, 1, 0); - cxhdl->video_mute = cx2341x_ctrl_new_std(hdl, - V4L2_CID_MPEG_VIDEO_MUTE, 0, 1, 1, 0); - cxhdl->video_mute_yuv = cx2341x_ctrl_new_std(hdl, - V4L2_CID_MPEG_VIDEO_MUTE_YUV, 0, 0xffffff, 1, 0x008080); - - /* CX23415/6 specific */ - cxhdl->video_spatial_filter_mode = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 0, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); - cxhdl->video_spatial_filter = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, - 0, 15, 1, 0); - cxhdl->video_luma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, - 0, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR); - cxhdl->video_chroma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, - 0, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR); - cxhdl->video_temporal_filter_mode = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, - 0, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); - cxhdl->video_temporal_filter = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, - 0, 31, 1, 8); - cxhdl->video_median_filter_type = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, - 0, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); - cxhdl->video_luma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, - 0, 255, 1, 0); - cxhdl->video_luma_median_filter_top = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, - 0, 255, 1, 255); - cxhdl->video_chroma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, - 0, 255, 1, 0); - cxhdl->video_chroma_median_filter_top = cx2341x_ctrl_new_custom(hdl, - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, - 0, 255, 1, 255); - cx2341x_ctrl_new_custom(hdl, V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, - 0, 1, 1, 0); - - if (hdl->error) { - int err = hdl->error; - - v4l2_ctrl_handler_free(hdl); - return err; - } - - v4l2_ctrl_cluster(8, &cxhdl->audio_sampling_freq); - v4l2_ctrl_cluster(2, &cxhdl->video_b_frames); - v4l2_ctrl_cluster(5, &cxhdl->stream_type); - v4l2_ctrl_cluster(2, &cxhdl->video_mute); - v4l2_ctrl_cluster(3, &cxhdl->video_spatial_filter_mode); - v4l2_ctrl_cluster(2, &cxhdl->video_luma_spatial_filter_type); - v4l2_ctrl_cluster(2, &cxhdl->video_spatial_filter); - v4l2_ctrl_cluster(4, &cxhdl->video_luma_median_filter_top); - - return 0; -} -EXPORT_SYMBOL(cx2341x_handler_init); - -void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz) -{ - cxhdl->is_50hz = is_50hz; - cxhdl->video_gop_size->default_value = cxhdl->is_50hz ? 12 : 15; -} -EXPORT_SYMBOL(cx2341x_handler_set_50hz); - -int cx2341x_handler_setup(struct cx2341x_handler *cxhdl) -{ - int h = cxhdl->height; - int w = cxhdl->width; - int err; - - err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_OUTPUT_PORT, 2, cxhdl->port, 0); - if (err) - return err; - err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_RATE, 1, cxhdl->is_50hz); - if (err) - return err; - - if (v4l2_ctrl_g_ctrl(cxhdl->video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { - w /= 2; - h /= 2; - } - err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); - if (err) - return err; - return v4l2_ctrl_handler_setup(&cxhdl->hdl); -} -EXPORT_SYMBOL(cx2341x_handler_setup); - -void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy) -{ - v4l2_ctrl_grab(cxhdl->audio_sampling_freq, busy); - v4l2_ctrl_grab(cxhdl->audio_encoding, busy); - v4l2_ctrl_grab(cxhdl->audio_l2_bitrate, busy); - v4l2_ctrl_grab(cxhdl->audio_ac3_bitrate, busy); - v4l2_ctrl_grab(cxhdl->stream_vbi_fmt, busy); - v4l2_ctrl_grab(cxhdl->stream_type, busy); - v4l2_ctrl_grab(cxhdl->video_bitrate_mode, busy); - v4l2_ctrl_grab(cxhdl->video_bitrate, busy); - v4l2_ctrl_grab(cxhdl->video_bitrate_peak, busy); -} -EXPORT_SYMBOL(cx2341x_handler_set_busy); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/altera-ci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/altera-ci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/altera-ci.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/altera-ci.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,838 +0,0 @@ -/* - * altera-ci.c - * - * CI driver in conjunction with NetUp Dual DVB-T/C RF CI card - * - * Copyright (C) 2010,2011 NetUP Inc. - * Copyright (C) 2010,2011 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * currently cx23885 GPIO's used. - * GPIO-0 ~INT in - * GPIO-1 TMS out - * GPIO-2 ~reset chips out - * GPIO-3 to GPIO-10 data/addr for CA in/out - * GPIO-11 ~CS out - * GPIO-12 AD_RG out - * GPIO-13 ~WR out - * GPIO-14 ~RD out - * GPIO-15 ~RDY in - * GPIO-16 TCK out - * GPIO-17 TDO in - * GPIO-18 TDI out - */ -/* - * Bit definitions for MC417_RWD and MC417_OEN registers - * bits 31-16 - * +-----------+ - * | Reserved | - * +-----------+ - * bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | TDI | TDO | TCK | RDY# | #RD | #WR | AD_RG | #CS | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| - * +-------+-------+-------+-------+-------+-------+-------+-------+ - */ -#include -#include -#include -#include "altera-ci.h" -#include "dvb_ca_en50221.h" - -/* FPGA regs */ -#define NETUP_CI_INT_CTRL 0x00 -#define NETUP_CI_BUSCTRL2 0x01 -#define NETUP_CI_ADDR0 0x04 -#define NETUP_CI_ADDR1 0x05 -#define NETUP_CI_DATA 0x06 -#define NETUP_CI_BUSCTRL 0x07 -#define NETUP_CI_PID_ADDR0 0x08 -#define NETUP_CI_PID_ADDR1 0x09 -#define NETUP_CI_PID_DATA 0x0a -#define NETUP_CI_TSA_DIV 0x0c -#define NETUP_CI_TSB_DIV 0x0d -#define NETUP_CI_REVISION 0x0f - -/* const for ci op */ -#define NETUP_CI_FLG_CTL 1 -#define NETUP_CI_FLG_RD 1 -#define NETUP_CI_FLG_AD 1 - -static unsigned int ci_dbg; -module_param(ci_dbg, int, 0644); -MODULE_PARM_DESC(ci_dbg, "Enable CI debugging"); - -static unsigned int pid_dbg; -module_param(pid_dbg, int, 0644); -MODULE_PARM_DESC(pid_dbg, "Enable PID filtering debugging"); - -MODULE_DESCRIPTION("altera FPGA CI module"); -MODULE_AUTHOR("Igor M. Liplianin "); -MODULE_LICENSE("GPL"); - -#define ci_dbg_print(args...) \ - do { \ - if (ci_dbg) \ - printk(KERN_DEBUG args); \ - } while (0) - -#define pid_dbg_print(args...) \ - do { \ - if (pid_dbg) \ - printk(KERN_DEBUG args); \ - } while (0) - -struct altera_ci_state; -struct netup_hw_pid_filter; - -struct fpga_internal { - void *dev; - struct mutex fpga_mutex;/* two CI's on the same fpga */ - struct netup_hw_pid_filter *pid_filt[2]; - struct altera_ci_state *state[2]; - struct work_struct work; - int (*fpga_rw) (void *dev, int flag, int data, int rw); - int cis_used; - int filts_used; - int strt_wrk; -}; - -/* stores all private variables for communication with CI */ -struct altera_ci_state { - struct fpga_internal *internal; - struct dvb_ca_en50221 ca; - int status; - int nr; -}; - -/* stores all private variables for hardware pid filtering */ -struct netup_hw_pid_filter { - struct fpga_internal *internal; - struct dvb_demux *demux; - /* save old functions */ - int (*start_feed)(struct dvb_demux_feed *feed); - int (*stop_feed)(struct dvb_demux_feed *feed); - - int status; - int nr; -}; - -/* internal params node */ -struct fpga_inode { - /* pointer for internal params, one for each pair of CI's */ - struct fpga_internal *internal; - struct fpga_inode *next_inode; -}; - -/* first internal params */ -static struct fpga_inode *fpga_first_inode; - -/* find chip by dev */ -static struct fpga_inode *find_inode(void *dev) -{ - struct fpga_inode *temp_chip = fpga_first_inode; - - if (temp_chip == NULL) - return temp_chip; - - /* - Search for the last fpga CI chip or - find it by dev */ - while ((temp_chip != NULL) && - (temp_chip->internal->dev != dev)) - temp_chip = temp_chip->next_inode; - - return temp_chip; -} -/* check demux */ -static struct fpga_internal *check_filter(struct fpga_internal *temp_int, - void *demux_dev, int filt_nr) -{ - if (temp_int == NULL) - return NULL; - - if ((temp_int->pid_filt[filt_nr]) == NULL) - return NULL; - - if (temp_int->pid_filt[filt_nr]->demux == demux_dev) - return temp_int; - - return NULL; -} - -/* find chip by demux */ -static struct fpga_inode *find_dinode(void *demux_dev) -{ - struct fpga_inode *temp_chip = fpga_first_inode; - struct fpga_internal *temp_int; - - /* - * Search of the last fpga CI chip or - * find it by demux - */ - while (temp_chip != NULL) { - if (temp_chip->internal != NULL) { - temp_int = temp_chip->internal; - if (check_filter(temp_int, demux_dev, 0)) - break; - if (check_filter(temp_int, demux_dev, 1)) - break; - } - - temp_chip = temp_chip->next_inode; - } - - return temp_chip; -} - -/* deallocating chip */ -static void remove_inode(struct fpga_internal *internal) -{ - struct fpga_inode *prev_node = fpga_first_inode; - struct fpga_inode *del_node = find_inode(internal->dev); - - if (del_node != NULL) { - if (del_node == fpga_first_inode) { - fpga_first_inode = del_node->next_inode; - } else { - while (prev_node->next_inode != del_node) - prev_node = prev_node->next_inode; - - if (del_node->next_inode == NULL) - prev_node->next_inode = NULL; - else - prev_node->next_inode = - prev_node->next_inode->next_inode; - } - - kfree(del_node); - } -} - -/* allocating new chip */ -static struct fpga_inode *append_internal(struct fpga_internal *internal) -{ - struct fpga_inode *new_node = fpga_first_inode; - - if (new_node == NULL) { - new_node = kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); - fpga_first_inode = new_node; - } else { - while (new_node->next_inode != NULL) - new_node = new_node->next_inode; - - new_node->next_inode = - kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); - if (new_node->next_inode != NULL) - new_node = new_node->next_inode; - else - new_node = NULL; - } - - if (new_node != NULL) { - new_node->internal = internal; - new_node->next_inode = NULL; - } - - return new_node; -} - -static int netup_fpga_op_rw(struct fpga_internal *inter, int addr, - u8 val, u8 read) -{ - inter->fpga_rw(inter->dev, NETUP_CI_FLG_AD, addr, 0); - return inter->fpga_rw(inter->dev, 0, val, read); -} - -/* flag - mem/io, read - read/write */ -int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, - u8 flag, u8 read, int addr, u8 val) -{ - - struct altera_ci_state *state = en50221->data; - struct fpga_internal *inter = state->internal; - - u8 store; - int mem = 0; - - if (0 != slot) - return -EINVAL; - - mutex_lock(&inter->fpga_mutex); - - netup_fpga_op_rw(inter, NETUP_CI_ADDR0, ((addr << 1) & 0xfe), 0); - netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0); - store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); - - store &= 0x0f; - store |= ((state->nr << 7) | (flag << 6)); - - netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0); - mem = netup_fpga_op_rw(inter, NETUP_CI_DATA, val, read); - - mutex_unlock(&inter->fpga_mutex); - - ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__, - (read) ? "read" : "write", addr, - (flag == NETUP_CI_FLG_CTL) ? "ctl" : "mem", - (read) ? mem : val); - - return mem; -} - -int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, - int slot, int addr) -{ - return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0); -} - -int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, - int slot, int addr, u8 data) -{ - return altera_ci_op_cam(en50221, slot, 0, 0, addr, data); -} - -int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) -{ - return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, - NETUP_CI_FLG_RD, addr, 0); -} - -int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, - u8 addr, u8 data) -{ - return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data); -} - -int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) -{ - struct altera_ci_state *state = en50221->data; - struct fpga_internal *inter = state->internal; - /* reasonable timeout for CI reset is 10 seconds */ - unsigned long t_out = jiffies + msecs_to_jiffies(9999); - int ret; - - ci_dbg_print("%s\n", __func__); - - if (0 != slot) - return -EINVAL; - - mutex_lock(&inter->fpga_mutex); - - ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); - netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, - (ret & 0xcf) | (1 << (5 - state->nr)), 0); - - mutex_unlock(&inter->fpga_mutex); - - for (;;) { - mdelay(50); - - mutex_lock(&inter->fpga_mutex); - - ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, - 0, NETUP_CI_FLG_RD); - mutex_unlock(&inter->fpga_mutex); - - if ((ret & (1 << (5 - state->nr))) == 0) - break; - if (time_after(jiffies, t_out)) - break; - } - - - ci_dbg_print("%s: %d msecs\n", __func__, - jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out)); - - return 0; -} - -int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) -{ - /* not implemented */ - return 0; -} - -int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) -{ - struct altera_ci_state *state = en50221->data; - struct fpga_internal *inter = state->internal; - int ret; - - ci_dbg_print("%s\n", __func__); - - if (0 != slot) - return -EINVAL; - - mutex_lock(&inter->fpga_mutex); - - ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); - netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, - (ret & 0x0f) | (1 << (3 - state->nr)), 0); - - mutex_unlock(&inter->fpga_mutex); - - return 0; -} - -/* work handler */ -static void netup_read_ci_status(struct work_struct *work) -{ - struct fpga_internal *inter = - container_of(work, struct fpga_internal, work); - int ret; - - ci_dbg_print("%s\n", __func__); - - mutex_lock(&inter->fpga_mutex); - /* ack' irq */ - ret = netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0, NETUP_CI_FLG_RD); - ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); - - mutex_unlock(&inter->fpga_mutex); - - if (inter->state[1] != NULL) { - inter->state[1]->status = - ((ret & 1) == 0 ? - DVB_CA_EN50221_POLL_CAM_PRESENT | - DVB_CA_EN50221_POLL_CAM_READY : 0); - ci_dbg_print("%s: setting CI[1] status = 0x%x\n", - __func__, inter->state[1]->status); - }; - - if (inter->state[0] != NULL) { - inter->state[0]->status = - ((ret & 2) == 0 ? - DVB_CA_EN50221_POLL_CAM_PRESENT | - DVB_CA_EN50221_POLL_CAM_READY : 0); - ci_dbg_print("%s: setting CI[0] status = 0x%x\n", - __func__, inter->state[0]->status); - }; -} - -/* CI irq handler */ -int altera_ci_irq(void *dev) -{ - struct fpga_inode *temp_int = NULL; - struct fpga_internal *inter = NULL; - - ci_dbg_print("%s\n", __func__); - - if (dev != NULL) { - temp_int = find_inode(dev); - if (temp_int != NULL) { - inter = temp_int->internal; - schedule_work(&inter->work); - } - } - - return 1; -} -EXPORT_SYMBOL(altera_ci_irq); - -int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, - int open) -{ - struct altera_ci_state *state = en50221->data; - - if (0 != slot) - return -EINVAL; - - return state->status; -} - -void altera_hw_filt_release(void *main_dev, int filt_nr) -{ - struct fpga_inode *temp_int = find_inode(main_dev); - struct netup_hw_pid_filter *pid_filt = NULL; - - ci_dbg_print("%s\n", __func__); - - if (temp_int != NULL) { - pid_filt = temp_int->internal->pid_filt[filt_nr - 1]; - /* stored old feed controls */ - pid_filt->demux->start_feed = pid_filt->start_feed; - pid_filt->demux->stop_feed = pid_filt->stop_feed; - - if (((--(temp_int->internal->filts_used)) <= 0) && - ((temp_int->internal->cis_used) <= 0)) { - - ci_dbg_print("%s: Actually removing\n", __func__); - - remove_inode(temp_int->internal); - kfree(pid_filt->internal); - } - - kfree(pid_filt); - - } - -} -EXPORT_SYMBOL(altera_hw_filt_release); - -void altera_ci_release(void *dev, int ci_nr) -{ - struct fpga_inode *temp_int = find_inode(dev); - struct altera_ci_state *state = NULL; - - ci_dbg_print("%s\n", __func__); - - if (temp_int != NULL) { - state = temp_int->internal->state[ci_nr - 1]; - altera_hw_filt_release(dev, ci_nr); - - - if (((temp_int->internal->filts_used) <= 0) && - ((--(temp_int->internal->cis_used)) <= 0)) { - - ci_dbg_print("%s: Actually removing\n", __func__); - - remove_inode(temp_int->internal); - kfree(state->internal); - } - - if (state != NULL) { - if (state->ca.data != NULL) - dvb_ca_en50221_release(&state->ca); - - kfree(state); - } - } - -} -EXPORT_SYMBOL(altera_ci_release); - -static void altera_pid_control(struct netup_hw_pid_filter *pid_filt, - u16 pid, int onoff) -{ - struct fpga_internal *inter = pid_filt->internal; - u8 store = 0; - - /* pid 0-0x1f always enabled, don't touch them */ - if ((pid == 0x2000) || (pid < 0x20)) - return; - - mutex_lock(&inter->fpga_mutex); - - netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, (pid >> 3) & 0xff, 0); - netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, - ((pid >> 11) & 0x03) | (pid_filt->nr << 2), 0); - - store = netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 0, NETUP_CI_FLG_RD); - - if (onoff)/* 0 - on, 1 - off */ - store |= (1 << (pid & 7)); - else - store &= ~(1 << (pid & 7)); - - netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0); - - mutex_unlock(&inter->fpga_mutex); - - pid_dbg_print("%s: (%d) set pid: %5d 0x%04x '%s'\n", __func__, - pid_filt->nr, pid, pid, onoff ? "off" : "on"); -} - -static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt, - int filt_nr, int onoff) -{ - struct fpga_internal *inter = pid_filt->internal; - u8 store = 0; - int i; - - pid_dbg_print("%s: pid_filt->nr[%d] now %s\n", __func__, pid_filt->nr, - onoff ? "off" : "on"); - - if (onoff)/* 0 - on, 1 - off */ - store = 0xff;/* ignore pid */ - else - store = 0;/* enable pid */ - - mutex_lock(&inter->fpga_mutex); - - for (i = 0; i < 1024; i++) { - netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, i & 0xff, 0); - - netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, - ((i >> 8) & 0x03) | (pid_filt->nr << 2), 0); - /* pid 0-0x1f always enabled */ - netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, - (i > 3 ? store : 0), 0); - } - - mutex_unlock(&inter->fpga_mutex); -} - -int altera_pid_feed_control(void *demux_dev, int filt_nr, - struct dvb_demux_feed *feed, int onoff) -{ - struct fpga_inode *temp_int = find_dinode(demux_dev); - struct fpga_internal *inter = temp_int->internal; - struct netup_hw_pid_filter *pid_filt = inter->pid_filt[filt_nr - 1]; - - altera_pid_control(pid_filt, feed->pid, onoff ? 0 : 1); - /* call old feed proc's */ - if (onoff) - pid_filt->start_feed(feed); - else - pid_filt->stop_feed(feed); - - if (feed->pid == 0x2000) - altera_toggle_fullts_streaming(pid_filt, filt_nr, - onoff ? 0 : 1); - - return 0; -} -EXPORT_SYMBOL(altera_pid_feed_control); - -int altera_ci_start_feed(struct dvb_demux_feed *feed, int num) -{ - altera_pid_feed_control(feed->demux, num, feed, 1); - - return 0; -} - -int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num) -{ - altera_pid_feed_control(feed->demux, num, feed, 0); - - return 0; -} - -int altera_ci_start_feed_1(struct dvb_demux_feed *feed) -{ - return altera_ci_start_feed(feed, 1); -} - -int altera_ci_stop_feed_1(struct dvb_demux_feed *feed) -{ - return altera_ci_stop_feed(feed, 1); -} - -int altera_ci_start_feed_2(struct dvb_demux_feed *feed) -{ - return altera_ci_start_feed(feed, 2); -} - -int altera_ci_stop_feed_2(struct dvb_demux_feed *feed) -{ - return altera_ci_stop_feed(feed, 2); -} - -int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) -{ - struct netup_hw_pid_filter *pid_filt = NULL; - struct fpga_inode *temp_int = find_inode(config->dev); - struct fpga_internal *inter = NULL; - int ret = 0; - - pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL); - - ci_dbg_print("%s\n", __func__); - - if (!pid_filt) { - ret = -ENOMEM; - goto err; - } - - if (temp_int != NULL) { - inter = temp_int->internal; - (inter->filts_used)++; - ci_dbg_print("%s: Find Internal Structure!\n", __func__); - } else { - inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); - if (!inter) { - ret = -ENOMEM; - goto err; - } - - temp_int = append_internal(inter); - inter->filts_used = 1; - inter->dev = config->dev; - inter->fpga_rw = config->fpga_rw; - mutex_init(&inter->fpga_mutex); - inter->strt_wrk = 1; - ci_dbg_print("%s: Create New Internal Structure!\n", __func__); - } - - ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__, - pid_filt, hw_filt_nr - 1); - inter->pid_filt[hw_filt_nr - 1] = pid_filt; - pid_filt->demux = config->demux; - pid_filt->internal = inter; - pid_filt->nr = hw_filt_nr - 1; - /* store old feed controls */ - pid_filt->start_feed = config->demux->start_feed; - pid_filt->stop_feed = config->demux->stop_feed; - /* replace with new feed controls */ - if (hw_filt_nr == 1) { - pid_filt->demux->start_feed = altera_ci_start_feed_1; - pid_filt->demux->stop_feed = altera_ci_stop_feed_1; - } else if (hw_filt_nr == 2) { - pid_filt->demux->start_feed = altera_ci_start_feed_2; - pid_filt->demux->stop_feed = altera_ci_stop_feed_2; - } - - altera_toggle_fullts_streaming(pid_filt, 0, 1); - - return 0; -err: - ci_dbg_print("%s: Can't init hardware filter: Error %d\n", - __func__, ret); - - kfree(pid_filt); - - return ret; -} -EXPORT_SYMBOL(altera_hw_filt_init); - -int altera_ci_init(struct altera_ci_config *config, int ci_nr) -{ - struct altera_ci_state *state; - struct fpga_inode *temp_int = find_inode(config->dev); - struct fpga_internal *inter = NULL; - int ret = 0; - u8 store = 0; - - state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL); - - ci_dbg_print("%s\n", __func__); - - if (!state) { - ret = -ENOMEM; - goto err; - } - - if (temp_int != NULL) { - inter = temp_int->internal; - (inter->cis_used)++; - ci_dbg_print("%s: Find Internal Structure!\n", __func__); - } else { - inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); - if (!inter) { - ret = -ENOMEM; - goto err; - } - - temp_int = append_internal(inter); - inter->cis_used = 1; - inter->dev = config->dev; - inter->fpga_rw = config->fpga_rw; - mutex_init(&inter->fpga_mutex); - inter->strt_wrk = 1; - ci_dbg_print("%s: Create New Internal Structure!\n", __func__); - } - - ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__, - state, ci_nr - 1); - inter->state[ci_nr - 1] = state; - state->internal = inter; - state->nr = ci_nr - 1; - - state->ca.owner = THIS_MODULE; - state->ca.read_attribute_mem = altera_ci_read_attribute_mem; - state->ca.write_attribute_mem = altera_ci_write_attribute_mem; - state->ca.read_cam_control = altera_ci_read_cam_ctl; - state->ca.write_cam_control = altera_ci_write_cam_ctl; - state->ca.slot_reset = altera_ci_slot_reset; - state->ca.slot_shutdown = altera_ci_slot_shutdown; - state->ca.slot_ts_enable = altera_ci_slot_ts_ctl; - state->ca.poll_slot_status = altera_poll_ci_slot_status; - state->ca.data = state; - - ret = dvb_ca_en50221_init(config->adapter, - &state->ca, - /* flags */ 0, - /* n_slots */ 1); - if (0 != ret) - goto err; - - altera_hw_filt_init(config, ci_nr); - - if (inter->strt_wrk) { - INIT_WORK(&inter->work, netup_read_ci_status); - inter->strt_wrk = 0; - } - - ci_dbg_print("%s: CI initialized!\n", __func__); - - mutex_lock(&inter->fpga_mutex); - - /* Enable div */ - netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0); - netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0); - - /* enable TS out */ - store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); - store |= (3 << 4); - netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); - - ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD); - /* enable irq */ - netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0); - - mutex_unlock(&inter->fpga_mutex); - - ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret); - - schedule_work(&inter->work); - - return 0; -err: - ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret); - - kfree(state); - - return ret; -} -EXPORT_SYMBOL(altera_ci_init); - -int altera_ci_tuner_reset(void *dev, int ci_nr) -{ - struct fpga_inode *temp_int = find_inode(dev); - struct fpga_internal *inter = NULL; - u8 store; - - ci_dbg_print("%s\n", __func__); - - if (temp_int == NULL) - return -1; - - if (temp_int->internal == NULL) - return -1; - - inter = temp_int->internal; - - mutex_lock(&inter->fpga_mutex); - - store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); - store &= ~(4 << (2 - ci_nr)); - netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); - msleep(100); - store |= (4 << (2 - ci_nr)); - netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); - - mutex_unlock(&inter->fpga_mutex); - - return 0; -} -EXPORT_SYMBOL(altera_ci_tuner_reset); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/altera-ci.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/altera-ci.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/altera-ci.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/altera-ci.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -/* - * altera-ci.c - * - * CI driver in conjunction with NetUp Dual DVB-T/C RF CI card - * - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef __ALTERA_CI_H -#define __ALTERA_CI_H - -#define ALT_DATA 0x000000ff -#define ALT_TDI 0x00008000 -#define ALT_TDO 0x00004000 -#define ALT_TCK 0x00002000 -#define ALT_RDY 0x00001000 -#define ALT_RD 0x00000800 -#define ALT_WR 0x00000400 -#define ALT_AD_RG 0x00000200 -#define ALT_CS 0x00000100 - -struct altera_ci_config { - void *dev;/* main dev, for example cx23885_dev */ - void *adapter;/* for CI to connect to */ - struct dvb_demux *demux;/* for hardware PID filter to connect to */ - int (*fpga_rw) (void *dev, int ad_rg, int val, int rw); -}; - -#if defined(CONFIG_MEDIA_ALTERA_CI) || (defined(CONFIG_MEDIA_ALTERA_CI_MODULE) \ - && defined(MODULE)) - -extern int altera_ci_init(struct altera_ci_config *config, int ci_nr); -extern void altera_ci_release(void *dev, int ci_nr); -extern int altera_ci_irq(void *dev); -extern int altera_ci_tuner_reset(void *dev, int ci_nr); - -#else - -static inline int altera_ci_init(struct altera_ci_config *config, int ci_nr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} - -static inline void altera_ci_release(void *dev, int ci_nr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -} - -static inline int altera_ci_irq(void *dev) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} - -static inline int altera_ci_tuner_reset(void *dev, int ci_nr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} - -#endif -#if 0 -static inline int altera_hw_filt_init(struct altera_ci_config *config, - int hw_filt_nr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} - -static inline void altera_hw_filt_release(void *dev, int filt_nr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -} - -static inline int altera_pid_feed_control(void *dev, int filt_nr, - struct dvb_demux_feed *dvbdmxfeed, int onoff) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} - -#endif /* CONFIG_MEDIA_ALTERA_CI */ - -#endif /* __ALTERA_CI_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cimax2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cimax2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cimax2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cimax2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,536 +0,0 @@ -/* - * cimax2.c - * - * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card - * - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * Copyright (C) 2009 Abylay Ospan - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx23885.h" -#include "dvb_ca_en50221.h" -/**** Bit definitions for MC417_RWD and MC417_OEN registers *** - bits 31-16 -+-----------+ -| Reserved | -+-----------+ - bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 -+-------+-------+-------+-------+-------+-------+-------+-------+ -| WR# | RD# | | ACK# | ADHI | ADLO | CS1# | CS0# | -+-------+-------+-------+-------+-------+-------+-------+-------+ - bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 -+-------+-------+-------+-------+-------+-------+-------+-------+ -| DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| -+-------+-------+-------+-------+-------+-------+-------+-------+ -***/ -/* MC417 */ -#define NETUP_DATA 0x000000ff -#define NETUP_WR 0x00008000 -#define NETUP_RD 0x00004000 -#define NETUP_ACK 0x00001000 -#define NETUP_ADHI 0x00000800 -#define NETUP_ADLO 0x00000400 -#define NETUP_CS1 0x00000200 -#define NETUP_CS0 0x00000100 -#define NETUP_EN_ALL 0x00001000 -#define NETUP_CTRL_OFF (NETUP_CS1 | NETUP_CS0 | NETUP_WR | NETUP_RD) -#define NETUP_CI_CTL 0x04 -#define NETUP_CI_RD 1 - -#define NETUP_IRQ_DETAM 0x1 -#define NETUP_IRQ_IRQAM 0x4 - -static unsigned int ci_dbg; -module_param(ci_dbg, int, 0644); -MODULE_PARM_DESC(ci_dbg, "Enable CI debugging"); - -static unsigned int ci_irq_enable; -module_param(ci_irq_enable, int, 0644); -MODULE_PARM_DESC(ci_irq_enable, "Enable IRQ from CAM"); - -#define ci_dbg_print(args...) \ - do { \ - if (ci_dbg) \ - printk(KERN_DEBUG args); \ - } while (0) - -#define ci_irq_flags() (ci_irq_enable ? NETUP_IRQ_IRQAM : 0) - -/* stores all private variables for communication with CI */ -struct netup_ci_state { - struct dvb_ca_en50221 ca; - struct mutex ca_mutex; - struct i2c_adapter *i2c_adap; - u8 ci_i2c_addr; - int status; - struct work_struct work; - void *priv; - u8 current_irq_mode; - int current_ci_flag; - unsigned long next_status_checked_time; -}; - - -int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, - u8 *buf, int len) -{ - int ret; - struct i2c_msg msg[] = { - { - .addr = addr, - .flags = 0, - .buf = ®, - .len = 1 - }, { - .addr = addr, - .flags = I2C_M_RD, - .buf = buf, - .len = len - } - }; - - ret = i2c_transfer(i2c_adap, msg, 2); - - if (ret != 2) { - ci_dbg_print("%s: i2c read error, Reg = 0x%02x, Status = %d\n", - __func__, reg, ret); - - return -1; - } - - ci_dbg_print("%s: i2c read Addr=0x%04x, Reg = 0x%02x, data = %02x\n", - __func__, addr, reg, buf[0]); - - return 0; -} - -int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, - u8 *buf, int len) -{ - int ret; - u8 buffer[len + 1]; - - struct i2c_msg msg = { - .addr = addr, - .flags = 0, - .buf = &buffer[0], - .len = len + 1 - }; - - buffer[0] = reg; - memcpy(&buffer[1], buf, len); - - ret = i2c_transfer(i2c_adap, &msg, 1); - - if (ret != 1) { - ci_dbg_print("%s: i2c write error, Reg=[0x%02x], Status=%d\n", - __func__, reg, ret); - return -1; - } - - return 0; -} - -int netup_ci_get_mem(struct cx23885_dev *dev) -{ - int mem; - unsigned long timeout = jiffies + msecs_to_jiffies(1); - - for (;;) { - mem = cx_read(MC417_RWD); - if ((mem & NETUP_ACK) == 0) - break; - if (time_after(jiffies, timeout)) - break; - udelay(1); - } - - cx_set(MC417_RWD, NETUP_CTRL_OFF); - - return mem & 0xff; -} - -int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, - u8 flag, u8 read, int addr, u8 data) -{ - struct netup_ci_state *state = en50221->data; - struct cx23885_tsport *port = state->priv; - struct cx23885_dev *dev = port->dev; - - u8 store; - int mem; - int ret; - - if (0 != slot) - return -EINVAL; - - if (state->current_ci_flag != flag) { - ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &store, 1); - if (ret != 0) - return ret; - - store &= ~0x0c; - store |= flag; - - ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &store, 1); - if (ret != 0) - return ret; - }; - state->current_ci_flag = flag; - - mutex_lock(&dev->gpio_lock); - - /* write addr */ - cx_write(MC417_OEN, NETUP_EN_ALL); - cx_write(MC417_RWD, NETUP_CTRL_OFF | - NETUP_ADLO | (0xff & addr)); - cx_clear(MC417_RWD, NETUP_ADLO); - cx_write(MC417_RWD, NETUP_CTRL_OFF | - NETUP_ADHI | (0xff & (addr >> 8))); - cx_clear(MC417_RWD, NETUP_ADHI); - - if (read) { /* data in */ - cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA); - } else /* data out */ - cx_write(MC417_RWD, NETUP_CTRL_OFF | data); - - /* choose chip */ - cx_clear(MC417_RWD, - (state->ci_i2c_addr == 0x40) ? NETUP_CS0 : NETUP_CS1); - /* read/write */ - cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR); - mem = netup_ci_get_mem(dev); - - mutex_unlock(&dev->gpio_lock); - - if (!read) - if (mem < 0) - return -EREMOTEIO; - - ci_dbg_print("%s: %s: chipaddr=[0x%x] addr=[0x%02x], %s=%x\n", __func__, - (read) ? "read" : "write", state->ci_i2c_addr, addr, - (flag == NETUP_CI_CTL) ? "ctl" : "mem", - (read) ? mem : data); - - if (read) - return mem; - - return 0; -} - -int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, - int slot, int addr) -{ - return netup_ci_op_cam(en50221, slot, 0, NETUP_CI_RD, addr, 0); -} - -int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, - int slot, int addr, u8 data) -{ - return netup_ci_op_cam(en50221, slot, 0, 0, addr, data); -} - -int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) -{ - return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, - NETUP_CI_RD, addr, 0); -} - -int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, - u8 addr, u8 data) -{ - return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, 0, addr, data); -} - -int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) -{ - struct netup_ci_state *state = en50221->data; - u8 buf = 0x80; - int ret; - - if (0 != slot) - return -EINVAL; - - udelay(500); - ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &buf, 1); - - if (ret != 0) - return ret; - - udelay(500); - - buf = 0x00; - ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &buf, 1); - - msleep(1000); - dvb_ca_en50221_camready_irq(&state->ca, 0); - - return 0; - -} - -int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) -{ - /* not implemented */ - return 0; -} - -int netup_ci_set_irq(struct dvb_ca_en50221 *en50221, u8 irq_mode) -{ - struct netup_ci_state *state = en50221->data; - int ret; - - if (irq_mode == state->current_irq_mode) - return 0; - - ci_dbg_print("%s: chipaddr=[0x%x] setting ci IRQ to [0x%x] \n", - __func__, state->ci_i2c_addr, irq_mode); - ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, - 0x1b, &irq_mode, 1); - - if (ret != 0) - return ret; - - state->current_irq_mode = irq_mode; - - return 0; -} - -int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) -{ - struct netup_ci_state *state = en50221->data; - u8 buf; - - if (0 != slot) - return -EINVAL; - - netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &buf, 1); - buf |= 0x60; - - return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &buf, 1); -} - -/* work handler */ -static void netup_read_ci_status(struct work_struct *work) -{ - struct netup_ci_state *state = - container_of(work, struct netup_ci_state, work); - u8 buf[33]; - int ret; - - /* CAM module IRQ processing. fast operation */ - dvb_ca_en50221_frda_irq(&state->ca, 0); - - /* CAM module INSERT/REMOVE processing. slow operation because of i2c - * transfers */ - if (time_after(jiffies, state->next_status_checked_time) - || !state->status) { - ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &buf[0], 33); - - state->next_status_checked_time = jiffies - + msecs_to_jiffies(1000); - - if (ret != 0) - return; - - ci_dbg_print("%s: Slot Status Addr=[0x%04x], " - "Reg=[0x%02x], data=%02x, " - "TS config = %02x\n", __func__, - state->ci_i2c_addr, 0, buf[0], - buf[0]); - - - if (buf[0] & 1) - state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | - DVB_CA_EN50221_POLL_CAM_READY; - else - state->status = 0; - } -} - -/* CI irq handler */ -int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status) -{ - struct cx23885_tsport *port = NULL; - struct netup_ci_state *state = NULL; - - ci_dbg_print("%s:\n", __func__); - - if (0 == (pci_status & (PCI_MSK_GPIO0 | PCI_MSK_GPIO1))) - return 0; - - if (pci_status & PCI_MSK_GPIO0) { - port = &dev->ts1; - state = port->port_priv; - schedule_work(&state->work); - ci_dbg_print("%s: Wakeup CI0\n", __func__); - } - - if (pci_status & PCI_MSK_GPIO1) { - port = &dev->ts2; - state = port->port_priv; - schedule_work(&state->work); - ci_dbg_print("%s: Wakeup CI1\n", __func__); - } - - return 1; -} - -int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) -{ - struct netup_ci_state *state = en50221->data; - - if (0 != slot) - return -EINVAL; - - netup_ci_set_irq(en50221, open ? (NETUP_IRQ_DETAM | ci_irq_flags()) - : NETUP_IRQ_DETAM); - - return state->status; -} - -int netup_ci_init(struct cx23885_tsport *port) -{ - struct netup_ci_state *state; - u8 cimax_init[34] = { - 0x00, /* module A control*/ - 0x00, /* auto select mask high A */ - 0x00, /* auto select mask low A */ - 0x00, /* auto select pattern high A */ - 0x00, /* auto select pattern low A */ - 0x44, /* memory access time A */ - 0x00, /* invert input A */ - 0x00, /* RFU */ - 0x00, /* RFU */ - 0x00, /* module B control*/ - 0x00, /* auto select mask high B */ - 0x00, /* auto select mask low B */ - 0x00, /* auto select pattern high B */ - 0x00, /* auto select pattern low B */ - 0x44, /* memory access time B */ - 0x00, /* invert input B */ - 0x00, /* RFU */ - 0x00, /* RFU */ - 0x00, /* auto select mask high Ext */ - 0x00, /* auto select mask low Ext */ - 0x00, /* auto select pattern high Ext */ - 0x00, /* auto select pattern low Ext */ - 0x00, /* RFU */ - 0x02, /* destination - module A */ - 0x01, /* power on (use it like store place) */ - 0x00, /* RFU */ - 0x00, /* int status read only */ - ci_irq_flags() | NETUP_IRQ_DETAM, /* DETAM, IRQAM unmasked */ - 0x05, /* EXTINT=active-high, INT=push-pull */ - 0x00, /* USCG1 */ - 0x04, /* ack active low */ - 0x00, /* LOCK = 0 */ - 0x33, /* serial mode, rising in, rising out, MSB first*/ - 0x31, /* syncronization */ - }; - int ret; - - ci_dbg_print("%s\n", __func__); - state = kzalloc(sizeof(struct netup_ci_state), GFP_KERNEL); - if (!state) { - ci_dbg_print("%s: Unable create CI structure!\n", __func__); - ret = -ENOMEM; - goto err; - } - - port->port_priv = state; - - switch (port->nr) { - case 1: - state->ci_i2c_addr = 0x40; - break; - case 2: - state->ci_i2c_addr = 0x41; - break; - } - - state->i2c_adap = &port->dev->i2c_bus[0].i2c_adap; - state->ca.owner = THIS_MODULE; - state->ca.read_attribute_mem = netup_ci_read_attribute_mem; - state->ca.write_attribute_mem = netup_ci_write_attribute_mem; - state->ca.read_cam_control = netup_ci_read_cam_ctl; - state->ca.write_cam_control = netup_ci_write_cam_ctl; - state->ca.slot_reset = netup_ci_slot_reset; - state->ca.slot_shutdown = netup_ci_slot_shutdown; - state->ca.slot_ts_enable = netup_ci_slot_ts_ctl; - state->ca.poll_slot_status = netup_poll_ci_slot_status; - state->ca.data = state; - state->priv = port; - state->current_irq_mode = ci_irq_flags() | NETUP_IRQ_DETAM; - - ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &cimax_init[0], 34); - /* lock registers */ - ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, - 0x1f, &cimax_init[0x18], 1); - /* power on slots */ - ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, - 0x18, &cimax_init[0x18], 1); - - if (0 != ret) - goto err; - - ret = dvb_ca_en50221_init(&port->frontends.adapter, - &state->ca, - /* flags */ 0, - /* n_slots */ 1); - if (0 != ret) - goto err; - - INIT_WORK(&state->work, netup_read_ci_status); - schedule_work(&state->work); - - ci_dbg_print("%s: CI initialized!\n", __func__); - - return 0; -err: - ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret); - kfree(state); - return ret; -} - -void netup_ci_exit(struct cx23885_tsport *port) -{ - struct netup_ci_state *state; - - if (NULL == port) - return; - - state = (struct netup_ci_state *)port->port_priv; - if (NULL == state) - return; - - if (NULL == state->ca.data) - return; - - dvb_ca_en50221_release(&state->ca); - kfree(state); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cimax2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cimax2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cimax2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cimax2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * cimax2.h - * - * CIMax(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card - * - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * Copyright (C) 2009 Abylay Ospan - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef CIMAX2_H -#define CIMAX2_H -#include "dvb_ca_en50221.h" - -extern int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, - int slot, int addr); -extern int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, - int slot, int addr, u8 data); -extern int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, - int slot, u8 addr); -extern int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, - int slot, u8 addr, u8 data); -extern int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot); -extern int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot); -extern int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot); -extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status); -extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, - int slot, int open); -extern int netup_ci_init(struct cx23885_tsport *port); -extern void netup_ci_exit(struct cx23885_tsport *port); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-417.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-417.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-417.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-417.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1796 +0,0 @@ -/* - * - * Support for a cx23417 mpeg encoder via cx23885 host port. - * - * (c) 2004 Jelle Foks - * (c) 2004 Gerd Knorr - * (c) 2008 Steven Toth - * - CX23885/7/8 support - * - * Includes parts from the ivtv driver - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx23885.h" -#include "cx23885-ioctl.h" - -#define CX23885_FIRM_IMAGE_SIZE 376836 -#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" - -static unsigned int mpegbufs = 32; -module_param(mpegbufs, int, 0644); -MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32"); -static unsigned int mpeglines = 32; -module_param(mpeglines, int, 0644); -MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32"); -static unsigned int mpeglinesize = 512; -module_param(mpeglinesize, int, 0644); -MODULE_PARM_DESC(mpeglinesize, - "number of bytes in each line of an MPEG buffer, range 512-1024"); - -static unsigned int v4l_debug; -module_param(v4l_debug, int, 0644); -MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages"); - -#define dprintk(level, fmt, arg...)\ - do { if (v4l_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, \ - (dev) ? dev->name : "cx23885[?]", ## arg); \ - } while (0) - -static struct cx23885_tvnorm cx23885_tvnorms[] = { - { - .name = "NTSC-M", - .id = V4L2_STD_NTSC_M, - }, { - .name = "NTSC-JP", - .id = V4L2_STD_NTSC_M_JP, - }, { - .name = "PAL-BG", - .id = V4L2_STD_PAL_BG, - }, { - .name = "PAL-DK", - .id = V4L2_STD_PAL_DK, - }, { - .name = "PAL-I", - .id = V4L2_STD_PAL_I, - }, { - .name = "PAL-M", - .id = V4L2_STD_PAL_M, - }, { - .name = "PAL-N", - .id = V4L2_STD_PAL_N, - }, { - .name = "PAL-Nc", - .id = V4L2_STD_PAL_Nc, - }, { - .name = "PAL-60", - .id = V4L2_STD_PAL_60, - }, { - .name = "SECAM-L", - .id = V4L2_STD_SECAM_L, - }, { - .name = "SECAM-DK", - .id = V4L2_STD_SECAM_DK, - } -}; - -/* ------------------------------------------------------------------ */ -enum cx23885_capture_type { - CX23885_MPEG_CAPTURE, - CX23885_RAW_CAPTURE, - CX23885_RAW_PASSTHRU_CAPTURE -}; -enum cx23885_capture_bits { - CX23885_RAW_BITS_NONE = 0x00, - CX23885_RAW_BITS_YUV_CAPTURE = 0x01, - CX23885_RAW_BITS_PCM_CAPTURE = 0x02, - CX23885_RAW_BITS_VBI_CAPTURE = 0x04, - CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08, - CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10 -}; -enum cx23885_capture_end { - CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */ - CX23885_END_NOW, /* stop immediately, no irq */ -}; -enum cx23885_framerate { - CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */ - CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */ -}; -enum cx23885_stream_port { - CX23885_OUTPUT_PORT_MEMORY, - CX23885_OUTPUT_PORT_STREAMING, - CX23885_OUTPUT_PORT_SERIAL -}; -enum cx23885_data_xfer_status { - CX23885_MORE_BUFFERS_FOLLOW, - CX23885_LAST_BUFFER, -}; -enum cx23885_picture_mask { - CX23885_PICTURE_MASK_NONE, - CX23885_PICTURE_MASK_I_FRAMES, - CX23885_PICTURE_MASK_I_P_FRAMES = 0x3, - CX23885_PICTURE_MASK_ALL_FRAMES = 0x7, -}; -enum cx23885_vbi_mode_bits { - CX23885_VBI_BITS_SLICED, - CX23885_VBI_BITS_RAW, -}; -enum cx23885_vbi_insertion_bits { - CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, - CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, - CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1, - CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, - CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, -}; -enum cx23885_dma_unit { - CX23885_DMA_BYTES, - CX23885_DMA_FRAMES, -}; -enum cx23885_dma_transfer_status_bits { - CX23885_DMA_TRANSFER_BITS_DONE = 0x01, - CX23885_DMA_TRANSFER_BITS_ERROR = 0x04, - CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10, -}; -enum cx23885_pause { - CX23885_PAUSE_ENCODING, - CX23885_RESUME_ENCODING, -}; -enum cx23885_copyright { - CX23885_COPYRIGHT_OFF, - CX23885_COPYRIGHT_ON, -}; -enum cx23885_notification_type { - CX23885_NOTIFICATION_REFRESH, -}; -enum cx23885_notification_status { - CX23885_NOTIFICATION_OFF, - CX23885_NOTIFICATION_ON, -}; -enum cx23885_notification_mailbox { - CX23885_NOTIFICATION_NO_MAILBOX = -1, -}; -enum cx23885_field1_lines { - CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */ - CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */ - CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */ -}; -enum cx23885_field2_lines { - CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */ - CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */ - CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */ -}; -enum cx23885_custom_data_type { - CX23885_CUSTOM_EXTENSION_USR_DATA, - CX23885_CUSTOM_PRIVATE_PACKET, -}; -enum cx23885_mute { - CX23885_UNMUTE, - CX23885_MUTE, -}; -enum cx23885_mute_video_mask { - CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00, - CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000, - CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000, -}; -enum cx23885_mute_video_shift { - CX23885_MUTE_VIDEO_V_SHIFT = 8, - CX23885_MUTE_VIDEO_U_SHIFT = 16, - CX23885_MUTE_VIDEO_Y_SHIFT = 24, -}; - -/* defines below are from ivtv-driver.h */ -#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF - -/* Firmware API commands */ -#define IVTV_API_STD_TIMEOUT 500 - -/* Registers */ -/* IVTV_REG_OFFSET */ -#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) -#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) -#define IVTV_REG_SPU (0x9050) -#define IVTV_REG_HW_BLOCKS (0x9054) -#define IVTV_REG_VPU (0x9058) -#define IVTV_REG_APU (0xA064) - -/**** Bit definitions for MC417_RWD and MC417_OEN registers *** - bits 31-16 -+-----------+ -| Reserved | -+-----------+ - bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 -+-------+-------+-------+-------+-------+-------+-------+-------+ -| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0| -+-------+-------+-------+-------+-------+-------+-------+-------+ - bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 -+-------+-------+-------+-------+-------+-------+-------+-------+ -|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0| -+-------+-------+-------+-------+-------+-------+-------+-------+ -***/ -#define MC417_MIWR 0x8000 -#define MC417_MIRD 0x4000 -#define MC417_MICS 0x2000 -#define MC417_MIRDY 0x1000 -#define MC417_MIADDR 0x0F00 -#define MC417_MIDATA 0x00FF - -/* MIADDR* nibble definitions */ -#define MCI_MEMORY_DATA_BYTE0 0x000 -#define MCI_MEMORY_DATA_BYTE1 0x100 -#define MCI_MEMORY_DATA_BYTE2 0x200 -#define MCI_MEMORY_DATA_BYTE3 0x300 -#define MCI_MEMORY_ADDRESS_BYTE2 0x400 -#define MCI_MEMORY_ADDRESS_BYTE1 0x500 -#define MCI_MEMORY_ADDRESS_BYTE0 0x600 -#define MCI_REGISTER_DATA_BYTE0 0x800 -#define MCI_REGISTER_DATA_BYTE1 0x900 -#define MCI_REGISTER_DATA_BYTE2 0xA00 -#define MCI_REGISTER_DATA_BYTE3 0xB00 -#define MCI_REGISTER_ADDRESS_BYTE0 0xC00 -#define MCI_REGISTER_ADDRESS_BYTE1 0xD00 -#define MCI_REGISTER_MODE 0xE00 - -/* Read and write modes */ -#define MCI_MODE_REGISTER_READ 0 -#define MCI_MODE_REGISTER_WRITE 1 -#define MCI_MODE_MEMORY_READ 0 -#define MCI_MODE_MEMORY_WRITE 0x40 - -/*** Bit definitions for MC417_CTL register **** - bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0 -+--------+-------------+--------+--------------+------------+ -|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN| -+--------+-------------+--------+--------------+------------+ -***/ -#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030) -#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006) -#define MC417_UART_GPIO_EN 0x00000001 - -/* Values for speed control */ -#define MC417_SPD_CTL_SLOW 0x1 -#define MC417_SPD_CTL_MEDIUM 0x0 -#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */ - -/* Values for GPIO select */ -#define MC417_GPIO_SEL_GPIO3 0x3 -#define MC417_GPIO_SEL_GPIO2 0x2 -#define MC417_GPIO_SEL_GPIO1 0x1 -#define MC417_GPIO_SEL_GPIO0 0x0 - -void cx23885_mc417_init(struct cx23885_dev *dev) -{ - u32 regval; - - dprintk(2, "%s()\n", __func__); - - /* Configure MC417_CTL register to defaults. */ - regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) | - MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) | - MC417_UART_GPIO_EN; - cx_write(MC417_CTL, regval); - - /* Configure MC417_OEN to defaults. */ - regval = MC417_MIRDY; - cx_write(MC417_OEN, regval); - - /* Configure MC417_RWD to defaults. */ - regval = MC417_MIWR | MC417_MIRD | MC417_MICS; - cx_write(MC417_RWD, regval); -} - -static int mc417_wait_ready(struct cx23885_dev *dev) -{ - u32 mi_ready; - unsigned long timeout = jiffies + msecs_to_jiffies(1); - - for (;;) { - mi_ready = cx_read(MC417_RWD) & MC417_MIRDY; - if (mi_ready != 0) - return 0; - if (time_after(jiffies, timeout)) - return -1; - udelay(1); - } -} - -int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value) -{ - u32 regval; - - /* Enable MC417 GPIO outputs except for MC417_MIRDY, - * which is an input. - */ - cx_write(MC417_OEN, MC417_MIRDY); - - /* Write data byte 0 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 | - (value & 0x000000FF); - cx_write(MC417_RWD, regval); - - /* Transition CS/WR to effect write transaction across bus. */ - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write data byte 1 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 | - ((value >> 8) & 0x000000FF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write data byte 2 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 | - ((value >> 16) & 0x000000FF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write data byte 3 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 | - ((value >> 24) & 0x000000FF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write address byte 0 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | - (address & 0xFF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write address byte 1 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | - ((address >> 8) & 0xFF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Indicate that this is a write. */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | - MCI_MODE_REGISTER_WRITE; - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Wait for the trans to complete (MC417_MIRDY asserted). */ - return mc417_wait_ready(dev); -} - -int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value) -{ - int retval; - u32 regval; - u32 tempval; - u32 dataval; - - /* Enable MC417 GPIO outputs except for MC417_MIRDY, - * which is an input. - */ - cx_write(MC417_OEN, MC417_MIRDY); - - /* Write address byte 0 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | - ((address & 0x00FF)); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write address byte 1 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | - ((address >> 8) & 0xFF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Indicate that this is a register read. */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | - MCI_MODE_REGISTER_READ; - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Wait for the trans to complete (MC417_MIRDY asserted). */ - retval = mc417_wait_ready(dev); - - /* switch the DAT0-7 GPIO[10:3] to input mode */ - cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA); - - /* Read data byte 0 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; - cx_write(MC417_RWD, regval); - - /* Transition RD to effect read transaction across bus. - * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)? - * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its - * input only...) - */ - regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; - cx_write(MC417_RWD, regval); - - /* Collect byte */ - tempval = cx_read(MC417_RWD); - dataval = tempval & 0x000000FF; - - /* Bring CS and RD high. */ - regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; - cx_write(MC417_RWD, regval); - - /* Read data byte 1 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; - cx_write(MC417_RWD, regval); - regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; - cx_write(MC417_RWD, regval); - tempval = cx_read(MC417_RWD); - dataval |= ((tempval & 0x000000FF) << 8); - regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; - cx_write(MC417_RWD, regval); - - /* Read data byte 2 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; - cx_write(MC417_RWD, regval); - regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; - cx_write(MC417_RWD, regval); - tempval = cx_read(MC417_RWD); - dataval |= ((tempval & 0x000000FF) << 16); - regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; - cx_write(MC417_RWD, regval); - - /* Read data byte 3 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3; - cx_write(MC417_RWD, regval); - regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3; - cx_write(MC417_RWD, regval); - tempval = cx_read(MC417_RWD); - dataval |= ((tempval & 0x000000FF) << 24); - regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; - cx_write(MC417_RWD, regval); - - *value = dataval; - - return retval; -} - -int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value) -{ - u32 regval; - - /* Enable MC417 GPIO outputs except for MC417_MIRDY, - * which is an input. - */ - cx_write(MC417_OEN, MC417_MIRDY); - - /* Write data byte 0 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 | - (value & 0x000000FF); - cx_write(MC417_RWD, regval); - - /* Transition CS/WR to effect write transaction across bus. */ - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write data byte 1 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 | - ((value >> 8) & 0x000000FF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write data byte 2 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 | - ((value >> 16) & 0x000000FF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write data byte 3 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 | - ((value >> 24) & 0x000000FF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write address byte 2 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 | - MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write address byte 1 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 | - ((address >> 8) & 0xFF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write address byte 0 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 | - (address & 0xFF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Wait for the trans to complete (MC417_MIRDY asserted). */ - return mc417_wait_ready(dev); -} - -int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value) -{ - int retval; - u32 regval; - u32 tempval; - u32 dataval; - - /* Enable MC417 GPIO outputs except for MC417_MIRDY, - * which is an input. - */ - cx_write(MC417_OEN, MC417_MIRDY); - - /* Write address byte 2 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 | - MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write address byte 1 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 | - ((address >> 8) & 0xFF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Write address byte 0 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 | - (address & 0xFF); - cx_write(MC417_RWD, regval); - regval |= MC417_MICS | MC417_MIWR; - cx_write(MC417_RWD, regval); - - /* Wait for the trans to complete (MC417_MIRDY asserted). */ - retval = mc417_wait_ready(dev); - - /* switch the DAT0-7 GPIO[10:3] to input mode */ - cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA); - - /* Read data byte 3 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3; - cx_write(MC417_RWD, regval); - - /* Transition RD to effect read transaction across bus. */ - regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3; - cx_write(MC417_RWD, regval); - - /* Collect byte */ - tempval = cx_read(MC417_RWD); - dataval = ((tempval & 0x000000FF) << 24); - - /* Bring CS and RD high. */ - regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; - cx_write(MC417_RWD, regval); - - /* Read data byte 2 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2; - cx_write(MC417_RWD, regval); - regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2; - cx_write(MC417_RWD, regval); - tempval = cx_read(MC417_RWD); - dataval |= ((tempval & 0x000000FF) << 16); - regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; - cx_write(MC417_RWD, regval); - - /* Read data byte 1 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1; - cx_write(MC417_RWD, regval); - regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1; - cx_write(MC417_RWD, regval); - tempval = cx_read(MC417_RWD); - dataval |= ((tempval & 0x000000FF) << 8); - regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; - cx_write(MC417_RWD, regval); - - /* Read data byte 0 */ - regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0; - cx_write(MC417_RWD, regval); - regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0; - cx_write(MC417_RWD, regval); - tempval = cx_read(MC417_RWD); - dataval |= (tempval & 0x000000FF); - regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; - cx_write(MC417_RWD, regval); - - *value = dataval; - - return retval; -} - -void mc417_gpio_set(struct cx23885_dev *dev, u32 mask) -{ - u32 val; - - /* Set the gpio value */ - mc417_register_read(dev, 0x900C, &val); - val |= (mask & 0x000ffff); - mc417_register_write(dev, 0x900C, val); -} - -void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask) -{ - u32 val; - - /* Clear the gpio value */ - mc417_register_read(dev, 0x900C, &val); - val &= ~(mask & 0x0000ffff); - mc417_register_write(dev, 0x900C, val); -} - -void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) -{ - u32 val; - - /* Enable GPIO direction bits */ - mc417_register_read(dev, 0x9020, &val); - if (asoutput) - val |= (mask & 0x0000ffff); - else - val &= ~(mask & 0x0000ffff); - - mc417_register_write(dev, 0x9020, val); -} -/* ------------------------------------------------------------------ */ - -/* MPEG encoder API */ -static char *cmd_to_str(int cmd) -{ - switch (cmd) { - case CX2341X_ENC_PING_FW: - return "PING_FW"; - case CX2341X_ENC_START_CAPTURE: - return "START_CAPTURE"; - case CX2341X_ENC_STOP_CAPTURE: - return "STOP_CAPTURE"; - case CX2341X_ENC_SET_AUDIO_ID: - return "SET_AUDIO_ID"; - case CX2341X_ENC_SET_VIDEO_ID: - return "SET_VIDEO_ID"; - case CX2341X_ENC_SET_PCR_ID: - return "SET_PCR_ID"; - case CX2341X_ENC_SET_FRAME_RATE: - return "SET_FRAME_RATE"; - case CX2341X_ENC_SET_FRAME_SIZE: - return "SET_FRAME_SIZE"; - case CX2341X_ENC_SET_BIT_RATE: - return "SET_BIT_RATE"; - case CX2341X_ENC_SET_GOP_PROPERTIES: - return "SET_GOP_PROPERTIES"; - case CX2341X_ENC_SET_ASPECT_RATIO: - return "SET_ASPECT_RATIO"; - case CX2341X_ENC_SET_DNR_FILTER_MODE: - return "SET_DNR_FILTER_MODE"; - case CX2341X_ENC_SET_DNR_FILTER_PROPS: - return "SET_DNR_FILTER_PROPS"; - case CX2341X_ENC_SET_CORING_LEVELS: - return "SET_CORING_LEVELS"; - case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: - return "SET_SPATIAL_FILTER_TYPE"; - case CX2341X_ENC_SET_VBI_LINE: - return "SET_VBI_LINE"; - case CX2341X_ENC_SET_STREAM_TYPE: - return "SET_STREAM_TYPE"; - case CX2341X_ENC_SET_OUTPUT_PORT: - return "SET_OUTPUT_PORT"; - case CX2341X_ENC_SET_AUDIO_PROPERTIES: - return "SET_AUDIO_PROPERTIES"; - case CX2341X_ENC_HALT_FW: - return "HALT_FW"; - case CX2341X_ENC_GET_VERSION: - return "GET_VERSION"; - case CX2341X_ENC_SET_GOP_CLOSURE: - return "SET_GOP_CLOSURE"; - case CX2341X_ENC_GET_SEQ_END: - return "GET_SEQ_END"; - case CX2341X_ENC_SET_PGM_INDEX_INFO: - return "SET_PGM_INDEX_INFO"; - case CX2341X_ENC_SET_VBI_CONFIG: - return "SET_VBI_CONFIG"; - case CX2341X_ENC_SET_DMA_BLOCK_SIZE: - return "SET_DMA_BLOCK_SIZE"; - case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10: - return "GET_PREV_DMA_INFO_MB_10"; - case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9: - return "GET_PREV_DMA_INFO_MB_9"; - case CX2341X_ENC_SCHED_DMA_TO_HOST: - return "SCHED_DMA_TO_HOST"; - case CX2341X_ENC_INITIALIZE_INPUT: - return "INITIALIZE_INPUT"; - case CX2341X_ENC_SET_FRAME_DROP_RATE: - return "SET_FRAME_DROP_RATE"; - case CX2341X_ENC_PAUSE_ENCODER: - return "PAUSE_ENCODER"; - case CX2341X_ENC_REFRESH_INPUT: - return "REFRESH_INPUT"; - case CX2341X_ENC_SET_COPYRIGHT: - return "SET_COPYRIGHT"; - case CX2341X_ENC_SET_EVENT_NOTIFICATION: - return "SET_EVENT_NOTIFICATION"; - case CX2341X_ENC_SET_NUM_VSYNC_LINES: - return "SET_NUM_VSYNC_LINES"; - case CX2341X_ENC_SET_PLACEHOLDER: - return "SET_PLACEHOLDER"; - case CX2341X_ENC_MUTE_VIDEO: - return "MUTE_VIDEO"; - case CX2341X_ENC_MUTE_AUDIO: - return "MUTE_AUDIO"; - case CX2341X_ENC_MISC: - return "MISC"; - default: - return "UNKNOWN"; - } -} - -static int cx23885_mbox_func(void *priv, - u32 command, - int in, - int out, - u32 data[CX2341X_MBOX_MAX_DATA]) -{ - struct cx23885_dev *dev = priv; - unsigned long timeout; - u32 value, flag, retval = 0; - int i; - - dprintk(3, "%s: command(0x%X) = %s\n", __func__, command, - cmd_to_str(command)); - - /* this may not be 100% safe if we can't read any memory location - without side effects */ - mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value); - if (value != 0x12345678) { - printk(KERN_ERR - "Firmware and/or mailbox pointer not initialized " - "or corrupted, signature = 0x%x, cmd = %s\n", value, - cmd_to_str(command)); - return -1; - } - - /* This read looks at 32 bits, but flag is only 8 bits. - * Seems we also bail if CMD or TIMEOUT bytes are set??? - */ - mc417_memory_read(dev, dev->cx23417_mailbox, &flag); - if (flag) { - printk(KERN_ERR "ERROR: Mailbox appears to be in use " - "(%x), cmd = %s\n", flag, cmd_to_str(command)); - return -1; - } - - flag |= 1; /* tell 'em we're working on it */ - mc417_memory_write(dev, dev->cx23417_mailbox, flag); - - /* write command + args + fill remaining with zeros */ - /* command code */ - mc417_memory_write(dev, dev->cx23417_mailbox + 1, command); - mc417_memory_write(dev, dev->cx23417_mailbox + 3, - IVTV_API_STD_TIMEOUT); /* timeout */ - for (i = 0; i < in; i++) { - mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]); - dprintk(3, "API Input %d = %d\n", i, data[i]); - } - for (; i < CX2341X_MBOX_MAX_DATA; i++) - mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0); - - flag |= 3; /* tell 'em we're done writing */ - mc417_memory_write(dev, dev->cx23417_mailbox, flag); - - /* wait for firmware to handle the API command */ - timeout = jiffies + msecs_to_jiffies(10); - for (;;) { - mc417_memory_read(dev, dev->cx23417_mailbox, &flag); - if (0 != (flag & 4)) - break; - if (time_after(jiffies, timeout)) { - printk(KERN_ERR "ERROR: API Mailbox timeout\n"); - return -1; - } - udelay(10); - } - - /* read output values */ - for (i = 0; i < out; i++) { - mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i); - dprintk(3, "API Output %d = %d\n", i, data[i]); - } - - mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval); - dprintk(3, "API result = %d\n", retval); - - flag = 0; - mc417_memory_write(dev, dev->cx23417_mailbox, flag); - - return retval; -} - -/* We don't need to call the API often, so using just one - * mailbox will probably suffice - */ -static int cx23885_api_cmd(struct cx23885_dev *dev, - u32 command, - u32 inputcnt, - u32 outputcnt, - ...) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - va_list vargs; - int i, err; - - dprintk(3, "%s() cmds = 0x%08x\n", __func__, command); - - va_start(vargs, outputcnt); - for (i = 0; i < inputcnt; i++) - data[i] = va_arg(vargs, int); - - err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data); - for (i = 0; i < outputcnt; i++) { - int *vptr = va_arg(vargs, int *); - *vptr = data[i]; - } - va_end(vargs); - - return err; -} - -static int cx23885_find_mailbox(struct cx23885_dev *dev) -{ - u32 signature[4] = { - 0x12345678, 0x34567812, 0x56781234, 0x78123456 - }; - int signaturecnt = 0; - u32 value; - int i; - - dprintk(2, "%s()\n", __func__); - - for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) { - mc417_memory_read(dev, i, &value); - if (value == signature[signaturecnt]) - signaturecnt++; - else - signaturecnt = 0; - if (4 == signaturecnt) { - dprintk(1, "Mailbox signature found at 0x%x\n", i+1); - return i+1; - } - } - printk(KERN_ERR "Mailbox signature values not found!\n"); - return -1; -} - -static int cx23885_load_firmware(struct cx23885_dev *dev) -{ - static const unsigned char magic[8] = { - 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa - }; - const struct firmware *firmware; - int i, retval = 0; - u32 value = 0; - u32 gpio_output = 0; - u32 checksum = 0; - u32 *dataptr; - - dprintk(2, "%s()\n", __func__); - - /* Save GPIO settings before reset of APU */ - retval |= mc417_memory_read(dev, 0x9020, &gpio_output); - retval |= mc417_memory_read(dev, 0x900C, &value); - - retval = mc417_register_write(dev, - IVTV_REG_VPU, 0xFFFFFFED); - retval |= mc417_register_write(dev, - IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); - retval |= mc417_register_write(dev, - IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800); - retval |= mc417_register_write(dev, - IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); - retval |= mc417_register_write(dev, - IVTV_REG_APU, 0); - - if (retval != 0) { - printk(KERN_ERR "%s: Error with mc417_register_write\n", - __func__); - return -1; - } - - retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME, - &dev->pci->dev); - - if (retval != 0) { - printk(KERN_ERR - "ERROR: Hotplug firmware request failed (%s).\n", - CX23885_FIRM_IMAGE_NAME); - printk(KERN_ERR "Please fix your hotplug setup, the board will " - "not work without firmware loaded!\n"); - return -1; - } - - if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { - printk(KERN_ERR "ERROR: Firmware size mismatch " - "(have %zd, expected %d)\n", - firmware->size, CX23885_FIRM_IMAGE_SIZE); - release_firmware(firmware); - return -1; - } - - if (0 != memcmp(firmware->data, magic, 8)) { - printk(KERN_ERR - "ERROR: Firmware magic mismatch, wrong file?\n"); - release_firmware(firmware); - return -1; - } - - /* transfer to the chip */ - dprintk(2, "Loading firmware ...\n"); - dataptr = (u32 *)firmware->data; - for (i = 0; i < (firmware->size >> 2); i++) { - value = *dataptr; - checksum += ~value; - if (mc417_memory_write(dev, i, value) != 0) { - printk(KERN_ERR "ERROR: Loading firmware failed!\n"); - release_firmware(firmware); - return -1; - } - dataptr++; - } - - /* read back to verify with the checksum */ - dprintk(1, "Verifying firmware ...\n"); - for (i--; i >= 0; i--) { - if (mc417_memory_read(dev, i, &value) != 0) { - printk(KERN_ERR "ERROR: Reading firmware failed!\n"); - release_firmware(firmware); - return -1; - } - checksum -= ~value; - } - if (checksum) { - printk(KERN_ERR - "ERROR: Firmware load failed (checksum mismatch).\n"); - release_firmware(firmware); - return -1; - } - release_firmware(firmware); - dprintk(1, "Firmware upload successful.\n"); - - retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS, - IVTV_CMD_HW_BLOCKS_RST); - - /* F/W power up disturbs the GPIOs, restore state */ - retval |= mc417_register_write(dev, 0x9020, gpio_output); - retval |= mc417_register_write(dev, 0x900C, value); - - retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); - retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); - - if (retval < 0) - printk(KERN_ERR "%s: Error with mc417_register_write\n", - __func__); - return 0; -} - -void cx23885_417_check_encoder(struct cx23885_dev *dev) -{ - u32 status, seq; - - status = seq = 0; - cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq); - dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq); -} - -static void cx23885_codec_settings(struct cx23885_dev *dev) -{ - dprintk(1, "%s()\n", __func__); - - /* assign frame size */ - cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, - dev->ts1.height, dev->ts1.width); - - dev->mpeg_params.width = dev->ts1.width; - dev->mpeg_params.height = dev->ts1.height; - dev->mpeg_params.is_50hz = - (dev->encodernorm.id & V4L2_STD_625_50) != 0; - - cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params); - - cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); - cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); -} - -static int cx23885_initialize_codec(struct cx23885_dev *dev) -{ - int version; - int retval; - u32 i, data[7]; - - dprintk(1, "%s()\n", __func__); - - retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ - if (retval < 0) { - dprintk(2, "%s() PING OK\n", __func__); - retval = cx23885_load_firmware(dev); - if (retval < 0) { - printk(KERN_ERR "%s() f/w load failed\n", __func__); - return retval; - } - retval = cx23885_find_mailbox(dev); - if (retval < 0) { - printk(KERN_ERR "%s() mailbox < 0, error\n", - __func__); - return -1; - } - dev->cx23417_mailbox = retval; - retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); - if (retval < 0) { - printk(KERN_ERR - "ERROR: cx23417 firmware ping failed!\n"); - return -1; - } - retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, - &version); - if (retval < 0) { - printk(KERN_ERR "ERROR: cx23417 firmware get encoder :" - "version failed!\n"); - return -1; - } - dprintk(1, "cx23417 firmware version is 0x%08x\n", version); - msleep(200); - } - - cx23885_codec_settings(dev); - msleep(60); - - cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, - CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115); - cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, - CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0); - - /* Setup to capture VBI */ - data[0] = 0x0001BD00; - data[1] = 1; /* frames per interrupt */ - data[2] = 4; /* total bufs */ - data[3] = 0x91559155; /* start codes */ - data[4] = 0x206080C0; /* stop codes */ - data[5] = 6; /* lines */ - data[6] = 64; /* BPL */ - - cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1], - data[2], data[3], data[4], data[5], data[6]); - - for (i = 2; i <= 24; i++) { - int valid; - - valid = ((i >= 19) && (i <= 21)); - cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i, - valid, 0 , 0, 0); - cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, - i | 0x80000000, valid, 0, 0, 0); - } - - cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE); - msleep(60); - - /* initialize the video input */ - cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); - msleep(60); - - /* Enable VIP style pixel invalidation so we work with scaled mode */ - mc417_memory_write(dev, 2120, 0x00000080); - - /* start capturing to the host interface */ - cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, - CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); - msleep(10); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int bb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) -{ - struct cx23885_fh *fh = q->priv_data; - - fh->dev->ts1.ts_packet_size = mpeglinesize; - fh->dev->ts1.ts_packet_count = mpeglines; - - *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; - *count = mpegbufs; - - return 0; -} - -static int bb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct cx23885_fh *fh = q->priv_data; - return cx23885_buf_prepare(q, &fh->dev->ts1, - (struct cx23885_buffer *)vb, - field); -} - -static void bb_buf_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx23885_fh *fh = q->priv_data; - cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb); -} - -static void bb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - cx23885_free_buffer(q, (struct cx23885_buffer *)vb); -} - -static struct videobuf_queue_ops cx23885_qops = { - .buf_setup = bb_buf_setup, - .buf_prepare = bb_buf_prepare, - .buf_queue = bb_buf_queue, - .buf_release = bb_buf_release, -}; - -/* ------------------------------------------------------------------ */ - -static const u32 *ctrl_classes[] = { - cx2341x_mpeg_ctrls, - NULL -}; - -static int cx23885_queryctrl(struct cx23885_dev *dev, - struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - - /* MPEG V4L2 controls */ - if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - - return 0; -} - -static int cx23885_querymenu(struct cx23885_dev *dev, - struct v4l2_querymenu *qmenu) -{ - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - cx23885_queryctrl(dev, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) - if (*id & cx23885_tvnorms[i].id) - break; - if (i == ARRAY_SIZE(cx23885_tvnorms)) - return -EINVAL; - dev->encodernorm = cx23885_tvnorms[i]; - return 0; -} - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_input *input; - int n; - - if (i->index >= 4) - return -EINVAL; - - input = &cx23885_boards[dev->board].input[i->index]; - - if (input->type == 0) - return -EINVAL; - - /* FIXME - * strcpy(i->name, input->name); */ - strcpy(i->name, "unset"); - - if (input->type == CX23885_VMUX_TELEVISION || - input->type == CX23885_VMUX_CABLE) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - - for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++) - i->std |= cx23885_tvnorms[n].id; - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - *i = dev->input; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i >= 4) - return -EINVAL; - - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - if (UNSET == dev->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - strcpy(t->name, "Television"); - call_all(dev, tuner, g_tuner, t); - - dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type); - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - if (UNSET == dev->tuner_type) - return -EINVAL; - - /* Update the A/V core */ - call_all(dev, tuner, s_tuner, t); - - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - if (UNSET == dev->tuner_type) - return -EINVAL; - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = dev->freq; - - call_all(dev, tuner, g_frequency, f); - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX23885_END_NOW, CX23885_MPEG_CAPTURE, - CX23885_RAW_BITS_NONE); - - dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n", - dev->tuner_type); - dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n", - f->tuner, f->type); - if (UNSET == dev->tuner_type) - return -EINVAL; - if (f->tuner != 0) - return -EINVAL; - if (f->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - dev->freq = f->frequency; - - call_all(dev, tuner, s_frequency, f); - - cx23885_initialize_codec(dev); - - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - /* Update the A/V core */ - call_all(dev, core, s_ctrl, ctl); - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_tsport *tsport = &dev->ts1; - - strlcpy(cap->driver, dev->name, sizeof(cap->driver)); - strlcpy(cap->card, cx23885_boards[tsport->dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = CX23885_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - 0; - if (UNSET != dev->tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index != 0) - return -EINVAL; - - strlcpy(f->description, "MPEG", sizeof(f->description)); - f->pixelformat = V4L2_PIX_FMT_MPEG; - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.colorspace = 0; - f->fmt.pix.width = dev->ts1.width; - f->fmt.pix.height = dev->ts1.height; - f->fmt.pix.field = fh->mpegq.field; - dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->mpegq.field); - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.colorspace = 0; - dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->mpegq.field); - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.colorspace = 0; - dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", - f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_reqbufs(&fh->mpegq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_querybuf(&fh->mpegq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_qbuf(&fh->mpegq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx23885_fh *fh = priv; - - return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK); -} - - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_streamon(&fh->mpegq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_streamoff(&fh->mpegq); -} - -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); -} - -static int vidioc_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); - - if (err == 0) { - err = cx2341x_update(dev, cx23885_mbox_func, - &dev->mpeg_params, &p); - dev->mpeg_params = p; - } - return err; -} - -static int vidioc_try_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - return err; -} - -static int vidioc_log_status(struct file *file, void *priv) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - char name[32 + 2]; - - snprintf(name, sizeof(name), "%s/2", dev->name); - printk(KERN_INFO - "%s/2: ============ START LOG STATUS ============\n", - dev->name); - call_all(dev, core, log_status); - cx2341x_log_status(&dev->mpeg_params, name); - printk(KERN_INFO - "%s/2: ============= END LOG STATUS =============\n", - dev->name); - return 0; -} - -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *a) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - return cx23885_querymenu(dev, a); -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - return cx23885_queryctrl(dev, c); -} - -static int mpeg_open(struct file *file) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh; - - dprintk(2, "%s()\n", __func__); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) - return -ENOMEM; - - file->private_data = fh; - fh->dev = dev; - - videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops, - &dev->pci->dev, &dev->ts1.slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh, NULL); - return 0; -} - -static int mpeg_release(struct file *file) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - dprintk(2, "%s()\n", __func__); - - /* FIXME: Review this crap */ - /* Shut device down on last close */ - if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { - if (atomic_dec_return(&dev->v4l_reader_count) == 0) { - /* stop mpeg capture */ - cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX23885_END_NOW, CX23885_MPEG_CAPTURE, - CX23885_RAW_BITS_NONE); - - msleep(500); - cx23885_417_check_encoder(dev); - - cx23885_cancel_buffers(&fh->dev->ts1); - } - } - - if (fh->mpegq.streaming) - videobuf_streamoff(&fh->mpegq); - if (fh->mpegq.reading) - videobuf_read_stop(&fh->mpegq); - - videobuf_mmap_free(&fh->mpegq); - file->private_data = NULL; - kfree(fh); - - return 0; -} - -static ssize_t mpeg_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - dprintk(2, "%s()\n", __func__); - - /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ - /* Start mpeg encoder on first read. */ - if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { - if (atomic_inc_return(&dev->v4l_reader_count) == 1) { - if (cx23885_initialize_codec(dev) < 0) - return -EINVAL; - } - } - - return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static unsigned int mpeg_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - dprintk(2, "%s\n", __func__); - - return videobuf_poll_stream(file, &fh->mpegq, wait); -} - -static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - dprintk(2, "%s()\n", __func__); - - return videobuf_mmap_mapper(&fh->mpegq, vma); -} - -static struct v4l2_file_operations mpeg_fops = { - .owner = THIS_MODULE, - .open = mpeg_open, - .release = mpeg_release, - .read = mpeg_read, - .poll = mpeg_poll, - .mmap = mpeg_mmap, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, - .vidioc_log_status = vidioc_log_status, - .vidioc_querymenu = vidioc_querymenu, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_chip_ident = cx23885_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = cx23885_g_register, - .vidioc_s_register = cx23885_s_register, -#endif -}; - -static struct video_device cx23885_mpeg_template = { - .name = "cx23885", - .fops = &mpeg_fops, - .ioctl_ops = &mpeg_ioctl_ops, - .tvnorms = CX23885_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; - -void cx23885_417_unregister(struct cx23885_dev *dev) -{ - dprintk(1, "%s()\n", __func__); - - if (dev->v4l_device) { - if (video_is_registered(dev->v4l_device)) - video_unregister_device(dev->v4l_device); - else - video_device_release(dev->v4l_device); - dev->v4l_device = NULL; - } -} - -static struct video_device *cx23885_video_dev_alloc( - struct cx23885_tsport *tsport, - struct pci_dev *pci, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - struct cx23885_dev *dev = tsport->dev; - - dprintk(1, "%s()\n", __func__); - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, - type, cx23885_boards[tsport->dev->board].name); - vfd->parent = &pci->dev; - vfd->release = video_device_release; - return vfd; -} - -int cx23885_417_register(struct cx23885_dev *dev) -{ - /* FIXME: Port1 hardcoded here */ - int err = -ENODEV; - struct cx23885_tsport *tsport = &dev->ts1; - - dprintk(1, "%s()\n", __func__); - - if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER) - return err; - - /* Set default TV standard */ - dev->encodernorm = cx23885_tvnorms[0]; - - if (dev->encodernorm.id & V4L2_STD_525_60) - tsport->height = 480; - else - tsport->height = 576; - - tsport->width = 720; - cx2341x_fill_defaults(&dev->mpeg_params); - - dev->mpeg_params.port = CX2341X_PORT_SERIAL; - - /* Allocate and initialize V4L video device */ - dev->v4l_device = cx23885_video_dev_alloc(tsport, - dev->pci, &cx23885_mpeg_template, "mpeg"); - video_set_drvdata(dev->v4l_device, dev); - err = video_register_device(dev->v4l_device, - VFL_TYPE_GRABBER, -1); - if (err < 0) { - printk(KERN_INFO "%s: can't register mpeg device\n", dev->name); - return err; - } - - printk(KERN_INFO "%s: registered device %s [mpeg]\n", - dev->name, video_device_node_name(dev->v4l_device)); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-av.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-av.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-av.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-av.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * AV device support routines - non-input, non-vl42_subdev routines - * - * Copyright (C) 2010 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "cx23885.h" - -void cx23885_av_work_handler(struct work_struct *work) -{ - struct cx23885_dev *dev = - container_of(work, struct cx23885_dev, cx25840_work); - bool handled; - - v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine, - PCI_MSK_AV_CORE, &handled); - cx23885_irq_enable(dev, PCI_MSK_AV_CORE); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-av.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-av.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-av.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-av.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * AV device support routines - non-input, non-vl42_subdev routines - * - * Copyright (C) 2010 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef _CX23885_AV_H_ -#define _CX23885_AV_H_ -void cx23885_av_work_handler(struct work_struct *work); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-cards.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1407 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2006 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "cx23885.h" -#include "tuner-xc2028.h" -#include "netup-init.h" -#include "altera-ci.h" -#include "xc5000.h" -#include "cx23888-ir.h" - -static unsigned int enable_885_ir; -module_param(enable_885_ir, int, 0644); -MODULE_PARM_DESC(enable_885_ir, - "Enable integrated IR controller for supported\n" - "\t\t CX2388[57] boards that are wired for it:\n" - "\t\t\tHVR-1250 (reported safe)\n" - "\t\t\tTeVii S470 (reported unsafe)\n" - "\t\t This can cause an interrupt storm with some cards.\n" - "\t\t Default: 0 [Disabled]"); - -/* ------------------------------------------------------------------ */ -/* board config info */ - -struct cx23885_board cx23885_boards[] = { - [CX23885_BOARD_UNKNOWN] = { - .name = "UNKNOWN/GENERIC", - /* Ensure safe default for unknown boards */ - .clk_freq = 0, - .input = {{ - .type = CX23885_VMUX_COMPOSITE1, - .vmux = 0, - }, { - .type = CX23885_VMUX_COMPOSITE2, - .vmux = 1, - }, { - .type = CX23885_VMUX_COMPOSITE3, - .vmux = 2, - }, { - .type = CX23885_VMUX_COMPOSITE4, - .vmux = 3, - } }, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { - .name = "Hauppauge WinTV-HVR1800lp", - .portc = CX23885_MPEG_DVB, - .input = {{ - .type = CX23885_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xff00, - }, { - .type = CX23885_VMUX_DEBUG, - .vmux = 0, - .gpio0 = 0xff01, - }, { - .type = CX23885_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xff02, - }, { - .type = CX23885_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xff02, - } }, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1800] = { - .name = "Hauppauge WinTV-HVR1800", - .porta = CX23885_ANALOG_VIDEO, - .portb = CX23885_MPEG_ENCODER, - .portc = CX23885_MPEG_DVB, - .tuner_type = TUNER_PHILIPS_TDA8290, - .tuner_addr = 0x42, /* 0x84 >> 1 */ - .tuner_bus = 1, - .input = {{ - .type = CX23885_VMUX_TELEVISION, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN5_CH2 | - CX25840_VIN2_CH1, - .gpio0 = 0, - }, { - .type = CX23885_VMUX_COMPOSITE1, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN4_CH2 | - CX25840_VIN6_CH1, - .gpio0 = 0, - }, { - .type = CX23885_VMUX_SVIDEO, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN4_CH2 | - CX25840_VIN8_CH1 | - CX25840_SVIDEO_ON, - .gpio0 = 0, - } }, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1250] = { - .name = "Hauppauge WinTV-HVR1250", - .portc = CX23885_MPEG_DVB, - .input = {{ - .type = CX23885_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xff00, - }, { - .type = CX23885_VMUX_DEBUG, - .vmux = 0, - .gpio0 = 0xff01, - }, { - .type = CX23885_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xff02, - }, { - .type = CX23885_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xff02, - } }, - }, - [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { - .name = "DViCO FusionHDTV5 Express", - .portb = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = { - .name = "Hauppauge WinTV-HVR1500Q", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1500] = { - .name = "Hauppauge WinTV-HVR1500", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1200] = { - .name = "Hauppauge WinTV-HVR1200", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1700] = { - .name = "Hauppauge WinTV-HVR1700", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1400] = { - .name = "Hauppauge WinTV-HVR1400", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = { - .name = "DViCO FusionHDTV7 Dual Express", - .portb = CX23885_MPEG_DVB, - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = { - .name = "DViCO FusionHDTV DVB-T Dual Express", - .portb = CX23885_MPEG_DVB, - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = { - .name = "Leadtek Winfast PxDVR3200 H", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = { - .name = "Compro VideoMate E650F", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_TBS_6920] = { - .name = "TurboSight TBS 6920", - .portb = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_TEVII_S470] = { - .name = "TeVii S470", - .portb = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_DVBWORLD_2005] = { - .name = "DVBWorld DVB-S2 2005", - .portb = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = { - .ci_type = 1, - .name = "NetUP Dual DVB-S2 CI", - .portb = CX23885_MPEG_DVB, - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1270] = { - .name = "Hauppauge WinTV-HVR1270", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1275] = { - .name = "Hauppauge WinTV-HVR1275", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1255] = { - .name = "Hauppauge WinTV-HVR1255", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1210] = { - .name = "Hauppauge WinTV-HVR1210", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_MYGICA_X8506] = { - .name = "Mygica X8506 DMB-TH", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x61, - .tuner_bus = 1, - .porta = CX23885_ANALOG_VIDEO, - .portb = CX23885_MPEG_DVB, - .input = { - { - .type = CX23885_VMUX_TELEVISION, - .vmux = CX25840_COMPOSITE2, - }, - { - .type = CX23885_VMUX_COMPOSITE1, - .vmux = CX25840_COMPOSITE8, - }, - { - .type = CX23885_VMUX_SVIDEO, - .vmux = CX25840_SVIDEO_LUMA3 | - CX25840_SVIDEO_CHROMA4, - }, - { - .type = CX23885_VMUX_COMPONENT, - .vmux = CX25840_COMPONENT_ON | - CX25840_VIN1_CH1 | - CX25840_VIN6_CH2 | - CX25840_VIN7_CH3, - }, - }, - }, - [CX23885_BOARD_MAGICPRO_PROHDTVE2] = { - .name = "Magic-Pro ProHDTV Extreme 2", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x61, - .tuner_bus = 1, - .porta = CX23885_ANALOG_VIDEO, - .portb = CX23885_MPEG_DVB, - .input = { - { - .type = CX23885_VMUX_TELEVISION, - .vmux = CX25840_COMPOSITE2, - }, - { - .type = CX23885_VMUX_COMPOSITE1, - .vmux = CX25840_COMPOSITE8, - }, - { - .type = CX23885_VMUX_SVIDEO, - .vmux = CX25840_SVIDEO_LUMA3 | - CX25840_SVIDEO_CHROMA4, - }, - { - .type = CX23885_VMUX_COMPONENT, - .vmux = CX25840_COMPONENT_ON | - CX25840_VIN1_CH1 | - CX25840_VIN6_CH2 | - CX25840_VIN7_CH3, - }, - }, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1850] = { - .name = "Hauppauge WinTV-HVR1850", - .portb = CX23885_MPEG_ENCODER, - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_COMPRO_VIDEOMATE_E800] = { - .name = "Compro VideoMate E800", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1290] = { - .name = "Hauppauge WinTV-HVR1290", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_MYGICA_X8558PRO] = { - .name = "Mygica X8558 PRO DMB-TH", - .portb = CX23885_MPEG_DVB, - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_LEADTEK_WINFAST_PXTV1200] = { - .name = "LEADTEK WinFast PxTV1200", - .porta = CX23885_ANALOG_VIDEO, - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .tuner_bus = 1, - .input = {{ - .type = CX23885_VMUX_TELEVISION, - .vmux = CX25840_VIN2_CH1 | - CX25840_VIN5_CH2 | - CX25840_NONE0_CH3, - }, { - .type = CX23885_VMUX_COMPOSITE1, - .vmux = CX25840_COMPOSITE1, - }, { - .type = CX23885_VMUX_SVIDEO, - .vmux = CX25840_SVIDEO_LUMA3 | - CX25840_SVIDEO_CHROMA4, - }, { - .type = CX23885_VMUX_COMPONENT, - .vmux = CX25840_VIN7_CH1 | - CX25840_VIN6_CH2 | - CX25840_VIN8_CH3 | - CX25840_COMPONENT_ON, - } }, - }, - [CX23885_BOARD_GOTVIEW_X5_3D_HYBRID] = { - .name = "GoTView X5 3D Hybrid", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x64, - .tuner_bus = 1, - .porta = CX23885_ANALOG_VIDEO, - .portb = CX23885_MPEG_DVB, - .input = {{ - .type = CX23885_VMUX_TELEVISION, - .vmux = CX25840_VIN2_CH1 | - CX25840_VIN5_CH2, - .gpio0 = 0x02, - }, { - .type = CX23885_VMUX_COMPOSITE1, - .vmux = CX23885_VMUX_COMPOSITE1, - }, { - .type = CX23885_VMUX_SVIDEO, - .vmux = CX25840_SVIDEO_LUMA3 | - CX25840_SVIDEO_CHROMA4, - } }, - }, - [CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF] = { - .ci_type = 2, - .name = "NetUP Dual DVB-T/C-CI RF", - .porta = CX23885_ANALOG_VIDEO, - .portb = CX23885_MPEG_DVB, - .portc = CX23885_MPEG_DVB, - .num_fds_portb = 2, - .num_fds_portc = 2, - .tuner_type = TUNER_XC5000, - .tuner_addr = 0x64, - .input = { { - .type = CX23885_VMUX_TELEVISION, - .vmux = CX25840_COMPOSITE1, - } }, - }, -}; -const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); - -/* ------------------------------------------------------------------ */ -/* PCI subsystem IDs */ - -struct cx23885_subid cx23885_subids[] = { - { - .subvendor = 0x0070, - .subdevice = 0x3400, - .card = CX23885_BOARD_UNKNOWN, - }, { - .subvendor = 0x0070, - .subdevice = 0x7600, - .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp, - }, { - .subvendor = 0x0070, - .subdevice = 0x7800, - .card = CX23885_BOARD_HAUPPAUGE_HVR1800, - }, { - .subvendor = 0x0070, - .subdevice = 0x7801, - .card = CX23885_BOARD_HAUPPAUGE_HVR1800, - }, { - .subvendor = 0x0070, - .subdevice = 0x7809, - .card = CX23885_BOARD_HAUPPAUGE_HVR1800, - }, { - .subvendor = 0x0070, - .subdevice = 0x7911, - .card = CX23885_BOARD_HAUPPAUGE_HVR1250, - }, { - .subvendor = 0x18ac, - .subdevice = 0xd500, - .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, - }, { - .subvendor = 0x0070, - .subdevice = 0x7790, - .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, - }, { - .subvendor = 0x0070, - .subdevice = 0x7797, - .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, - }, { - .subvendor = 0x0070, - .subdevice = 0x7710, - .card = CX23885_BOARD_HAUPPAUGE_HVR1500, - }, { - .subvendor = 0x0070, - .subdevice = 0x7717, - .card = CX23885_BOARD_HAUPPAUGE_HVR1500, - }, { - .subvendor = 0x0070, - .subdevice = 0x71d1, - .card = CX23885_BOARD_HAUPPAUGE_HVR1200, - }, { - .subvendor = 0x0070, - .subdevice = 0x71d3, - .card = CX23885_BOARD_HAUPPAUGE_HVR1200, - }, { - .subvendor = 0x0070, - .subdevice = 0x8101, - .card = CX23885_BOARD_HAUPPAUGE_HVR1700, - }, { - .subvendor = 0x0070, - .subdevice = 0x8010, - .card = CX23885_BOARD_HAUPPAUGE_HVR1400, - }, { - .subvendor = 0x18ac, - .subdevice = 0xd618, - .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP, - }, { - .subvendor = 0x18ac, - .subdevice = 0xdb78, - .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP, - }, { - .subvendor = 0x107d, - .subdevice = 0x6681, - .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H, - }, { - .subvendor = 0x185b, - .subdevice = 0xe800, - .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F, - }, { - .subvendor = 0x6920, - .subdevice = 0x8888, - .card = CX23885_BOARD_TBS_6920, - }, { - .subvendor = 0xd470, - .subdevice = 0x9022, - .card = CX23885_BOARD_TEVII_S470, - }, { - .subvendor = 0x0001, - .subdevice = 0x2005, - .card = CX23885_BOARD_DVBWORLD_2005, - }, { - .subvendor = 0x1b55, - .subdevice = 0x2a2c, - .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI, - }, { - .subvendor = 0x0070, - .subdevice = 0x2211, - .card = CX23885_BOARD_HAUPPAUGE_HVR1270, - }, { - .subvendor = 0x0070, - .subdevice = 0x2215, - .card = CX23885_BOARD_HAUPPAUGE_HVR1275, - }, { - .subvendor = 0x0070, - .subdevice = 0x221d, - .card = CX23885_BOARD_HAUPPAUGE_HVR1275, - }, { - .subvendor = 0x0070, - .subdevice = 0x2251, - .card = CX23885_BOARD_HAUPPAUGE_HVR1255, - }, { - .subvendor = 0x0070, - .subdevice = 0x2259, - .card = CX23885_BOARD_HAUPPAUGE_HVR1255, - }, { - .subvendor = 0x0070, - .subdevice = 0x2291, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, - }, { - .subvendor = 0x0070, - .subdevice = 0x2295, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, - }, { - .subvendor = 0x0070, - .subdevice = 0x2299, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, - }, { - .subvendor = 0x0070, - .subdevice = 0x229d, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ - }, { - .subvendor = 0x0070, - .subdevice = 0x22f0, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, - }, { - .subvendor = 0x0070, - .subdevice = 0x22f1, - .card = CX23885_BOARD_HAUPPAUGE_HVR1255, - }, { - .subvendor = 0x0070, - .subdevice = 0x22f2, - .card = CX23885_BOARD_HAUPPAUGE_HVR1275, - }, { - .subvendor = 0x0070, - .subdevice = 0x22f3, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ - }, { - .subvendor = 0x0070, - .subdevice = 0x22f4, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, - }, { - .subvendor = 0x0070, - .subdevice = 0x22f5, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ - }, { - .subvendor = 0x14f1, - .subdevice = 0x8651, - .card = CX23885_BOARD_MYGICA_X8506, - }, { - .subvendor = 0x14f1, - .subdevice = 0x8657, - .card = CX23885_BOARD_MAGICPRO_PROHDTVE2, - }, { - .subvendor = 0x0070, - .subdevice = 0x8541, - .card = CX23885_BOARD_HAUPPAUGE_HVR1850, - }, { - .subvendor = 0x1858, - .subdevice = 0xe800, - .card = CX23885_BOARD_COMPRO_VIDEOMATE_E800, - }, { - .subvendor = 0x0070, - .subdevice = 0x8551, - .card = CX23885_BOARD_HAUPPAUGE_HVR1290, - }, { - .subvendor = 0x14f1, - .subdevice = 0x8578, - .card = CX23885_BOARD_MYGICA_X8558PRO, - }, { - .subvendor = 0x107d, - .subdevice = 0x6f22, - .card = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200, - }, { - .subvendor = 0x5654, - .subdevice = 0x2390, - .card = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID, - }, { - .subvendor = 0x1b55, - .subdevice = 0xe2e4, - .card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF, - }, -}; -const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); - -void cx23885_card_list(struct cx23885_dev *dev) -{ - int i; - - if (0 == dev->pci->subsystem_vendor && - 0 == dev->pci->subsystem_device) { - printk(KERN_INFO - "%s: Board has no valid PCIe Subsystem ID and can't\n" - "%s: be autodetected. Pass card= insmod option\n" - "%s: to workaround that. Redirect complaints to the\n" - "%s: vendor of the TV card. Best regards,\n" - "%s: -- tux\n", - dev->name, dev->name, dev->name, dev->name, dev->name); - } else { - printk(KERN_INFO - "%s: Your board isn't known (yet) to the driver.\n" - "%s: Try to pick one of the existing card configs via\n" - "%s: card= insmod option. Updating to the latest\n" - "%s: version might help as well.\n", - dev->name, dev->name, dev->name, dev->name); - } - printk(KERN_INFO "%s: Here is a list of valid choices for the card= insmod option:\n", - dev->name); - for (i = 0; i < cx23885_bcount; i++) - printk(KERN_INFO "%s: card=%d -> %s\n", - dev->name, i, cx23885_boards[i].name); -} - -static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) -{ - struct tveeprom tv; - - tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, - eeprom_data); - - /* Make sure we support the board model */ - switch (tv.model) { - case 22001: - /* WinTV-HVR1270 (PCIe, Retail, half height) - * ATSC/QAM and basic analog, IR Blast */ - case 22009: - /* WinTV-HVR1210 (PCIe, Retail, half height) - * DVB-T and basic analog, IR Blast */ - case 22011: - /* WinTV-HVR1270 (PCIe, Retail, half height) - * ATSC/QAM and basic analog, IR Recv */ - case 22019: - /* WinTV-HVR1210 (PCIe, Retail, half height) - * DVB-T and basic analog, IR Recv */ - case 22021: - /* WinTV-HVR1275 (PCIe, Retail, half height) - * ATSC/QAM and basic analog, IR Recv */ - case 22029: - /* WinTV-HVR1210 (PCIe, Retail, half height) - * DVB-T and basic analog, IR Recv */ - case 22101: - /* WinTV-HVR1270 (PCIe, Retail, full height) - * ATSC/QAM and basic analog, IR Blast */ - case 22109: - /* WinTV-HVR1210 (PCIe, Retail, full height) - * DVB-T and basic analog, IR Blast */ - case 22111: - /* WinTV-HVR1270 (PCIe, Retail, full height) - * ATSC/QAM and basic analog, IR Recv */ - case 22119: - /* WinTV-HVR1210 (PCIe, Retail, full height) - * DVB-T and basic analog, IR Recv */ - case 22121: - /* WinTV-HVR1275 (PCIe, Retail, full height) - * ATSC/QAM and basic analog, IR Recv */ - case 22129: - /* WinTV-HVR1210 (PCIe, Retail, full height) - * DVB-T and basic analog, IR Recv */ - case 71009: - /* WinTV-HVR1200 (PCIe, Retail, full height) - * DVB-T and basic analog */ - case 71359: - /* WinTV-HVR1200 (PCIe, OEM, half height) - * DVB-T and basic analog */ - case 71439: - /* WinTV-HVR1200 (PCIe, OEM, half height) - * DVB-T and basic analog */ - case 71449: - /* WinTV-HVR1200 (PCIe, OEM, full height) - * DVB-T and basic analog */ - case 71939: - /* WinTV-HVR1200 (PCIe, OEM, half height) - * DVB-T and basic analog */ - case 71949: - /* WinTV-HVR1200 (PCIe, OEM, full height) - * DVB-T and basic analog */ - case 71959: - /* WinTV-HVR1200 (PCIe, OEM, full height) - * DVB-T and basic analog */ - case 71979: - /* WinTV-HVR1200 (PCIe, OEM, half height) - * DVB-T and basic analog */ - case 71999: - /* WinTV-HVR1200 (PCIe, OEM, full height) - * DVB-T and basic analog */ - case 76601: - /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual - channel ATSC and MPEG2 HW Encoder */ - case 77001: - /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC - and Basic analog */ - case 77011: - /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC - and Basic analog */ - case 77041: - /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM - and Basic analog */ - case 77051: - /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM - and Basic analog */ - case 78011: - /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, - Dual channel ATSC and MPEG2 HW Encoder */ - case 78501: - /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, - Dual channel ATSC and MPEG2 HW Encoder */ - case 78521: - /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, - Dual channel ATSC and MPEG2 HW Encoder */ - case 78531: - /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, - Dual channel ATSC and MPEG2 HW Encoder */ - case 78631: - /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, - Dual channel ATSC and MPEG2 HW Encoder */ - case 79001: - /* WinTV-HVR1250 (PCIe, Retail, IR, full height, - ATSC and Basic analog */ - case 79101: - /* WinTV-HVR1250 (PCIe, Retail, IR, half height, - ATSC and Basic analog */ - case 79501: - /* WinTV-HVR1250 (PCIe, No IR, half height, - ATSC [at least] and Basic analog) */ - case 79561: - /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, - ATSC and Basic analog */ - case 79571: - /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, - ATSC and Basic analog */ - case 79671: - /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, - ATSC and Basic analog */ - case 80019: - /* WinTV-HVR1400 (Express Card, Retail, IR, - * DVB-T and Basic analog */ - case 81509: - /* WinTV-HVR1700 (PCIe, OEM, No IR, half height) - * DVB-T and MPEG2 HW Encoder */ - case 81519: - /* WinTV-HVR1700 (PCIe, OEM, No IR, full height) - * DVB-T and MPEG2 HW Encoder */ - break; - case 85021: - /* WinTV-HVR1850 (PCIe, Retail, 3.5mm in, IR, FM, - Dual channel ATSC and MPEG2 HW Encoder */ - break; - case 85721: - /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR, - Dual channel ATSC and Basic analog */ - break; - default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", - dev->name, tv.model); - break; - } - - printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", - dev->name, tv.model); -} - -int cx23885_tuner_callback(void *priv, int component, int command, int arg) -{ - struct cx23885_tsport *port = priv; - struct cx23885_dev *dev = port->dev; - u32 bitmask = 0; - - if (command == XC2028_RESET_CLK) - return 0; - - if (command != 0) { - printk(KERN_ERR "%s(): Unknown command 0x%x.\n", - __func__, command); - return -EINVAL; - } - - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1400: - case CX23885_BOARD_HAUPPAUGE_HVR1500: - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: - case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: - case CX23885_BOARD_COMPRO_VIDEOMATE_E800: - case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: - /* Tuner Reset Command */ - bitmask = 0x04; - break; - case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: - case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: - /* Two identical tuners on two different i2c buses, - * we need to reset the correct gpio. */ - if (port->nr == 1) - bitmask = 0x01; - else if (port->nr == 2) - bitmask = 0x04; - break; - case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: - /* Tuner Reset Command */ - bitmask = 0x02; - break; - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: - altera_ci_tuner_reset(dev, port->nr); - break; - } - - if (bitmask) { - /* Drive the tuner into reset and back out */ - cx_clear(GP0_IO, bitmask); - mdelay(200); - cx_set(GP0_IO, bitmask); - } - - return 0; -} - -void cx23885_gpio_setup(struct cx23885_dev *dev) -{ - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - /* GPIO-0 cx24227 demodulator reset */ - cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ - break; - case CX23885_BOARD_HAUPPAUGE_HVR1500: - /* GPIO-0 cx24227 demodulator */ - /* GPIO-2 xc3028 tuner */ - - /* Put the parts into reset */ - cx_set(GP0_IO, 0x00050000); - cx_clear(GP0_IO, 0x00000005); - msleep(5); - - /* Bring the parts out of reset */ - cx_set(GP0_IO, 0x00050005); - break; - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - /* GPIO-0 cx24227 demodulator reset */ - /* GPIO-2 xc5000 tuner reset */ - cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */ - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - /* GPIO-0 656_CLK */ - /* GPIO-1 656_D0 */ - /* GPIO-2 8295A Reset */ - /* GPIO-3-10 cx23417 data0-7 */ - /* GPIO-11-14 cx23417 addr0-3 */ - /* GPIO-15-18 cx23417 READY, CS, RD, WR */ - /* GPIO-19 IR_RX */ - - /* CX23417 GPIO's */ - /* EIO15 Zilog Reset */ - /* EIO14 S5H1409/CX24227 Reset */ - mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1); - - /* Put the demod into reset and protect the eeprom */ - mc417_gpio_clear(dev, GPIO_15 | GPIO_14); - mdelay(100); - - /* Bring the demod and blaster out of reset */ - mc417_gpio_set(dev, GPIO_15 | GPIO_14); - mdelay(100); - - /* Force the TDA8295A into reset and back */ - cx23885_gpio_enable(dev, GPIO_2, 1); - cx23885_gpio_set(dev, GPIO_2); - mdelay(20); - cx23885_gpio_clear(dev, GPIO_2); - mdelay(20); - cx23885_gpio_set(dev, GPIO_2); - mdelay(20); - break; - case CX23885_BOARD_HAUPPAUGE_HVR1200: - /* GPIO-0 tda10048 demodulator reset */ - /* GPIO-2 tda18271 tuner reset */ - - /* Put the parts into reset and back */ - cx_set(GP0_IO, 0x00050000); - mdelay(20); - cx_clear(GP0_IO, 0x00000005); - mdelay(20); - cx_set(GP0_IO, 0x00050005); - break; - case CX23885_BOARD_HAUPPAUGE_HVR1700: - /* GPIO-0 TDA10048 demodulator reset */ - /* GPIO-2 TDA8295A Reset */ - /* GPIO-3-10 cx23417 data0-7 */ - /* GPIO-11-14 cx23417 addr0-3 */ - /* GPIO-15-18 cx23417 READY, CS, RD, WR */ - - /* The following GPIO's are on the interna AVCore (cx25840) */ - /* GPIO-19 IR_RX */ - /* GPIO-20 IR_TX 416/DVBT Select */ - /* GPIO-21 IIS DAT */ - /* GPIO-22 IIS WCLK */ - /* GPIO-23 IIS BCLK */ - - /* Put the parts into reset and back */ - cx_set(GP0_IO, 0x00050000); - mdelay(20); - cx_clear(GP0_IO, 0x00000005); - mdelay(20); - cx_set(GP0_IO, 0x00050005); - break; - case CX23885_BOARD_HAUPPAUGE_HVR1400: - /* GPIO-0 Dibcom7000p demodulator reset */ - /* GPIO-2 xc3028L tuner reset */ - /* GPIO-13 LED */ - - /* Put the parts into reset and back */ - cx_set(GP0_IO, 0x00050000); - mdelay(20); - cx_clear(GP0_IO, 0x00000005); - mdelay(20); - cx_set(GP0_IO, 0x00050005); - break; - case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: - /* GPIO-0 xc5000 tuner reset i2c bus 0 */ - /* GPIO-1 s5h1409 demod reset i2c bus 0 */ - /* GPIO-2 xc5000 tuner reset i2c bus 1 */ - /* GPIO-3 s5h1409 demod reset i2c bus 0 */ - - /* Put the parts into reset and back */ - cx_set(GP0_IO, 0x000f0000); - mdelay(20); - cx_clear(GP0_IO, 0x0000000f); - mdelay(20); - cx_set(GP0_IO, 0x000f000f); - break; - case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: - /* GPIO-0 portb xc3028 reset */ - /* GPIO-1 portb zl10353 reset */ - /* GPIO-2 portc xc3028 reset */ - /* GPIO-3 portc zl10353 reset */ - - /* Put the parts into reset and back */ - cx_set(GP0_IO, 0x000f0000); - mdelay(20); - cx_clear(GP0_IO, 0x0000000f); - mdelay(20); - cx_set(GP0_IO, 0x000f000f); - break; - case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: - case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: - case CX23885_BOARD_COMPRO_VIDEOMATE_E800: - case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: - /* GPIO-2 xc3028 tuner reset */ - - /* The following GPIO's are on the internal AVCore (cx25840) */ - /* GPIO-? zl10353 demod reset */ - - /* Put the parts into reset and back */ - cx_set(GP0_IO, 0x00040000); - mdelay(20); - cx_clear(GP0_IO, 0x00000004); - mdelay(20); - cx_set(GP0_IO, 0x00040004); - break; - case CX23885_BOARD_TBS_6920: - cx_write(MC417_CTL, 0x00000036); - cx_write(MC417_OEN, 0x00001000); - cx_set(MC417_RWD, 0x00000002); - mdelay(200); - cx_clear(MC417_RWD, 0x00000800); - mdelay(200); - cx_set(MC417_RWD, 0x00000800); - mdelay(200); - break; - case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: - /* GPIO-0 INTA from CiMax1 - GPIO-1 INTB from CiMax2 - GPIO-2 reset chips - GPIO-3 to GPIO-10 data/addr for CA - GPIO-11 ~CS0 to CiMax1 - GPIO-12 ~CS1 to CiMax2 - GPIO-13 ADL0 load LSB addr - GPIO-14 ADL1 load MSB addr - GPIO-15 ~RDY from CiMax - GPIO-17 ~RD to CiMax - GPIO-18 ~WR to CiMax - */ - cx_set(GP0_IO, 0x00040000); /* GPIO as out */ - /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */ - cx_clear(GP0_IO, 0x00030004); - mdelay(100);/* reset delay */ - cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */ - cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */ - /* GPIO-15 IN as ~ACK, rest as OUT */ - cx_write(MC417_OEN, 0x00001000); - /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */ - cx_write(MC417_RWD, 0x0000c300); - /* enable irq */ - cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ - break; - case CX23885_BOARD_HAUPPAUGE_HVR1270: - case CX23885_BOARD_HAUPPAUGE_HVR1275: - case CX23885_BOARD_HAUPPAUGE_HVR1255: - case CX23885_BOARD_HAUPPAUGE_HVR1210: - /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */ - /* GPIO-6 I2C Gate which can isolate the demod from the bus */ - /* GPIO-9 Demod reset */ - - /* Put the parts into reset and back */ - cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1); - cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5); - cx23885_gpio_clear(dev, GPIO_9); - mdelay(20); - cx23885_gpio_set(dev, GPIO_9); - break; - case CX23885_BOARD_MYGICA_X8506: - case CX23885_BOARD_MAGICPRO_PROHDTVE2: - /* GPIO-0 (0)Analog / (1)Digital TV */ - /* GPIO-1 reset XC5000 */ - /* GPIO-2 reset LGS8GL5 / LGS8G75 */ - cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1); - cx23885_gpio_clear(dev, GPIO_1 | GPIO_2); - mdelay(100); - cx23885_gpio_set(dev, GPIO_0 | GPIO_1 | GPIO_2); - mdelay(100); - break; - case CX23885_BOARD_MYGICA_X8558PRO: - /* GPIO-0 reset first ATBM8830 */ - /* GPIO-1 reset second ATBM8830 */ - cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1); - cx23885_gpio_clear(dev, GPIO_0 | GPIO_1); - mdelay(100); - cx23885_gpio_set(dev, GPIO_0 | GPIO_1); - mdelay(100); - break; - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - /* GPIO-0 656_CLK */ - /* GPIO-1 656_D0 */ - /* GPIO-2 Wake# */ - /* GPIO-3-10 cx23417 data0-7 */ - /* GPIO-11-14 cx23417 addr0-3 */ - /* GPIO-15-18 cx23417 READY, CS, RD, WR */ - /* GPIO-19 IR_RX */ - /* GPIO-20 C_IR_TX */ - /* GPIO-21 I2S DAT */ - /* GPIO-22 I2S WCLK */ - /* GPIO-23 I2S BCLK */ - /* ALT GPIO: EXP GPIO LATCH */ - - /* CX23417 GPIO's */ - /* GPIO-14 S5H1411/CX24228 Reset */ - /* GPIO-13 EEPROM write protect */ - mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1); - - /* Put the demod into reset and protect the eeprom */ - mc417_gpio_clear(dev, GPIO_14 | GPIO_13); - mdelay(100); - - /* Bring the demod out of reset */ - mc417_gpio_set(dev, GPIO_14); - mdelay(100); - - /* CX24228 GPIO */ - /* Connected to IF / Mux */ - break; - case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: - cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ - break; - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: - /* GPIO-0 ~INT in - GPIO-1 TMS out - GPIO-2 ~reset chips out - GPIO-3 to GPIO-10 data/addr for CA in/out - GPIO-11 ~CS out - GPIO-12 ADDR out - GPIO-13 ~WR out - GPIO-14 ~RD out - GPIO-15 ~RDY in - GPIO-16 TCK out - GPIO-17 TDO in - GPIO-18 TDI out - */ - cx_set(GP0_IO, 0x00060000); /* GPIO-1,2 as out */ - /* GPIO-0 as INT, reset & TMS low */ - cx_clear(GP0_IO, 0x00010006); - mdelay(100);/* reset delay */ - cx_set(GP0_IO, 0x00000004); /* reset high */ - cx_write(MC417_CTL, 0x00000037);/* enable GPIO-3..18 pins */ - /* GPIO-17 is TDO in, GPIO-15 is ~RDY in, rest is out */ - cx_write(MC417_OEN, 0x00005000); - /* ~RD, ~WR high; ADDR low; ~CS high */ - cx_write(MC417_RWD, 0x00000d00); - /* enable irq */ - cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ - break; - } -} - -int cx23885_ir_init(struct cx23885_dev *dev) -{ - static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = { - { - .flags = V4L2_SUBDEV_IO_PIN_INPUT, - .pin = CX23885_PIN_IR_RX_GPIO19, - .function = CX23885_PAD_IR_RX, - .value = 0, - .strength = CX25840_PIN_DRIVE_MEDIUM, - }, { - .flags = V4L2_SUBDEV_IO_PIN_OUTPUT, - .pin = CX23885_PIN_IR_TX_GPIO20, - .function = CX23885_PAD_IR_TX, - .value = 0, - .strength = CX25840_PIN_DRIVE_MEDIUM, - } - }; - const size_t ir_rxtx_pin_cfg_count = ARRAY_SIZE(ir_rxtx_pin_cfg); - - static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = { - { - .flags = V4L2_SUBDEV_IO_PIN_INPUT, - .pin = CX23885_PIN_IR_RX_GPIO19, - .function = CX23885_PAD_IR_RX, - .value = 0, - .strength = CX25840_PIN_DRIVE_MEDIUM, - } - }; - const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg); - - struct v4l2_subdev_ir_parameters params; - int ret = 0; - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1500: - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - case CX23885_BOARD_HAUPPAUGE_HVR1800: - case CX23885_BOARD_HAUPPAUGE_HVR1200: - case CX23885_BOARD_HAUPPAUGE_HVR1400: - case CX23885_BOARD_HAUPPAUGE_HVR1270: - case CX23885_BOARD_HAUPPAUGE_HVR1275: - case CX23885_BOARD_HAUPPAUGE_HVR1255: - case CX23885_BOARD_HAUPPAUGE_HVR1210: - /* FIXME: Implement me */ - break; - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - ret = cx23888_ir_probe(dev); - if (ret) - break; - dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); - v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, - ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); - /* - * For these boards we need to invert the Tx output via the - * IR controller to have the LED off while idle - */ - v4l2_subdev_call(dev->sd_ir, ir, tx_g_parameters, ¶ms); - params.enable = false; - params.shutdown = false; - params.invert_level = true; - v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, ¶ms); - params.shutdown = true; - v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, ¶ms); - break; - case CX23885_BOARD_TEVII_S470: - if (!enable_885_ir) - break; - dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); - if (dev->sd_ir == NULL) { - ret = -ENODEV; - break; - } - v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, - ir_rx_pin_cfg_count, ir_rx_pin_cfg); - break; - case CX23885_BOARD_HAUPPAUGE_HVR1250: - if (!enable_885_ir) - break; - dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); - if (dev->sd_ir == NULL) { - ret = -ENODEV; - break; - } - v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, - ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); - break; - case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: - request_module("ir-kbd-i2c"); - break; - } - - return ret; -} - -void cx23885_ir_fini(struct cx23885_dev *dev) -{ - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - cx23885_irq_remove(dev, PCI_MSK_IR); - cx23888_ir_remove(dev); - dev->sd_ir = NULL; - break; - case CX23885_BOARD_TEVII_S470: - case CX23885_BOARD_HAUPPAUGE_HVR1250: - cx23885_irq_remove(dev, PCI_MSK_AV_CORE); - /* sd_ir is a duplicate pointer to the AV Core, just clear it */ - dev->sd_ir = NULL; - break; - } -} - -int netup_jtag_io(void *device, int tms, int tdi, int read_tdo) -{ - int data; - int tdo = 0; - struct cx23885_dev *dev = (struct cx23885_dev *)device; - /*TMS*/ - data = ((cx_read(GP0_IO)) & (~0x00000002)); - data |= (tms ? 0x00020002 : 0x00020000); - cx_write(GP0_IO, data); - - /*TDI*/ - data = ((cx_read(MC417_RWD)) & (~0x0000a000)); - data |= (tdi ? 0x00008000 : 0); - cx_write(MC417_RWD, data); - if (read_tdo) - tdo = (data & 0x00004000) ? 1 : 0; /*TDO*/ - - cx_write(MC417_RWD, data | 0x00002000); - udelay(1); - /*TCK*/ - cx_write(MC417_RWD, data); - - return tdo; -} - -void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) -{ - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - if (dev->sd_ir) - cx23885_irq_add_enable(dev, PCI_MSK_IR); - break; - case CX23885_BOARD_TEVII_S470: - case CX23885_BOARD_HAUPPAUGE_HVR1250: - if (dev->sd_ir) - cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE); - break; - } -} - -void cx23885_card_setup(struct cx23885_dev *dev) -{ - struct cx23885_tsport *ts1 = &dev->ts1; - struct cx23885_tsport *ts2 = &dev->ts2; - - static u8 eeprom[256]; - - if (dev->i2c_bus[0].i2c_rc == 0) { - dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, - eeprom, sizeof(eeprom)); - } - - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - if (dev->i2c_bus[0].i2c_rc == 0) { - if (eeprom[0x80] != 0x84) - hauppauge_eeprom(dev, eeprom+0xc0); - else - hauppauge_eeprom(dev, eeprom+0x80); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1500: - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - case CX23885_BOARD_HAUPPAUGE_HVR1400: - if (dev->i2c_bus[0].i2c_rc == 0) - hauppauge_eeprom(dev, eeprom+0x80); - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: - case CX23885_BOARD_HAUPPAUGE_HVR1200: - case CX23885_BOARD_HAUPPAUGE_HVR1700: - case CX23885_BOARD_HAUPPAUGE_HVR1270: - case CX23885_BOARD_HAUPPAUGE_HVR1275: - case CX23885_BOARD_HAUPPAUGE_HVR1255: - case CX23885_BOARD_HAUPPAUGE_HVR1210: - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - if (dev->i2c_bus[0].i2c_rc == 0) - hauppauge_eeprom(dev, eeprom+0xc0); - break; - } - - switch (dev->board) { - case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: - case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: - ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - /* break omitted intentionally */ - case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: - ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - /* Defaults for VID B - Analog encoder */ - /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */ - ts1->gen_ctrl_val = 0x10e; - ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - - /* APB_TSVALERR_POL (active low)*/ - ts1->vld_misc_val = 0x2000; - ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc); - - /* Defaults for VID C */ - ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - break; - case CX23885_BOARD_TBS_6920: - ts1->gen_ctrl_val = 0x4; /* Parallel */ - ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - break; - case CX23885_BOARD_TEVII_S470: - case CX23885_BOARD_DVBWORLD_2005: - ts1->gen_ctrl_val = 0x5; /* Parallel */ - ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - break; - case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: - ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - break; - case CX23885_BOARD_MYGICA_X8506: - case CX23885_BOARD_MAGICPRO_PROHDTVE2: - ts1->gen_ctrl_val = 0x5; /* Parallel */ - ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - break; - case CX23885_BOARD_MYGICA_X8558PRO: - ts1->gen_ctrl_val = 0x5; /* Parallel */ - ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - break; - case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1500: - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: - case CX23885_BOARD_HAUPPAUGE_HVR1200: - case CX23885_BOARD_HAUPPAUGE_HVR1700: - case CX23885_BOARD_HAUPPAUGE_HVR1400: - case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: - case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: - case CX23885_BOARD_HAUPPAUGE_HVR1270: - case CX23885_BOARD_HAUPPAUGE_HVR1275: - case CX23885_BOARD_HAUPPAUGE_HVR1255: - case CX23885_BOARD_HAUPPAUGE_HVR1210: - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_COMPRO_VIDEOMATE_E800: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: - default: - ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ - ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - } - - /* Certain boards support analog, or require the avcore to be - * loaded, ensure this happens. - */ - switch (dev->board) { - case CX23885_BOARD_TEVII_S470: - case CX23885_BOARD_HAUPPAUGE_HVR1250: - /* Currently only enabled for the integrated IR controller */ - if (!enable_885_ir) - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: - case CX23885_BOARD_HAUPPAUGE_HVR1700: - case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: - case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: - case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: - case CX23885_BOARD_COMPRO_VIDEOMATE_E800: - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_MYGICA_X8506: - case CX23885_BOARD_MAGICPRO_PROHDTVE2: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: - case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: - dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_bus[2].i2c_adap, - "cx25840", 0x88 >> 1, NULL); - if (dev->sd_cx25840) { - dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; - v4l2_subdev_call(dev->sd_cx25840, core, load_fw); - } - break; - } - - /* AUX-PLL 27MHz CLK */ - switch (dev->board) { - case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: - netup_initialize(dev); - break; - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { - int ret; - const struct firmware *fw; - const char *filename = "dvb-netup-altera-01.fw"; - char *action = "configure"; - struct altera_config netup_config = { - .dev = dev, - .action = action, - .jtag_io = netup_jtag_io, - }; - - netup_initialize(dev); - - ret = request_firmware(&fw, filename, &dev->pci->dev); - if (ret != 0) - printk(KERN_ERR "did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details " - "on firmware-problems.", filename); - else - altera_init(&netup_config, fw); - - break; - } - } -} - -/* ------------------------------------------------------------------ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2174 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2006 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx23885.h" -#include "cimax2.h" -#include "altera-ci.h" -#include "cx23888-ir.h" -#include "cx23885-ir.h" -#include "cx23885-av.h" -#include "cx23885-input.h" - -MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); -MODULE_AUTHOR("Steven Toth "); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); - -static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; -module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card, "card type"); - -#define dprintk(level, fmt, arg...)\ - do { if (debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) - -static unsigned int cx23885_devcount; - -#define NO_SYNC_LINE (-1U) - -/* FIXME, these allocations will change when - * analog arrives. The be reviewed. - * CX23887 Assumptions - * 1 line = 16 bytes of CDT - * cmds size = 80 - * cdt size = 16 * linesize - * iqsize = 64 - * maxlines = 6 - * - * Address Space: - * 0x00000000 0x00008fff FIFO clusters - * 0x00010000 0x000104af Channel Management Data Structures - * 0x000104b0 0x000104ff Free - * 0x00010500 0x000108bf 15 channels * iqsize - * 0x000108c0 0x000108ff Free - * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables - * 15 channels * (iqsize + (maxlines * linesize)) - * 0x00010ea0 0x00010xxx Free - */ - -static struct sram_channel cx23885_sram_channels[] = { - [SRAM_CH01] = { - .name = "VID A", - .cmds_start = 0x10000, - .ctrl_start = 0x10380, - .cdt = 0x104c0, - .fifo_start = 0x40, - .fifo_size = 0x2800, - .ptr1_reg = DMA1_PTR1, - .ptr2_reg = DMA1_PTR2, - .cnt1_reg = DMA1_CNT1, - .cnt2_reg = DMA1_CNT2, - }, - [SRAM_CH02] = { - .name = "ch2", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA2_PTR1, - .ptr2_reg = DMA2_PTR2, - .cnt1_reg = DMA2_CNT1, - .cnt2_reg = DMA2_CNT2, - }, - [SRAM_CH03] = { - .name = "TS1 B", - .cmds_start = 0x100A0, - .ctrl_start = 0x10400, - .cdt = 0x10580, - .fifo_start = 0x5000, - .fifo_size = 0x1000, - .ptr1_reg = DMA3_PTR1, - .ptr2_reg = DMA3_PTR2, - .cnt1_reg = DMA3_CNT1, - .cnt2_reg = DMA3_CNT2, - }, - [SRAM_CH04] = { - .name = "ch4", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA4_PTR1, - .ptr2_reg = DMA4_PTR2, - .cnt1_reg = DMA4_CNT1, - .cnt2_reg = DMA4_CNT2, - }, - [SRAM_CH05] = { - .name = "ch5", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA5_PTR1, - .ptr2_reg = DMA5_PTR2, - .cnt1_reg = DMA5_CNT1, - .cnt2_reg = DMA5_CNT2, - }, - [SRAM_CH06] = { - .name = "TS2 C", - .cmds_start = 0x10140, - .ctrl_start = 0x10440, - .cdt = 0x105e0, - .fifo_start = 0x6000, - .fifo_size = 0x1000, - .ptr1_reg = DMA5_PTR1, - .ptr2_reg = DMA5_PTR2, - .cnt1_reg = DMA5_CNT1, - .cnt2_reg = DMA5_CNT2, - }, - [SRAM_CH07] = { - .name = "ch7", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA6_PTR1, - .ptr2_reg = DMA6_PTR2, - .cnt1_reg = DMA6_CNT1, - .cnt2_reg = DMA6_CNT2, - }, - [SRAM_CH08] = { - .name = "ch8", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA7_PTR1, - .ptr2_reg = DMA7_PTR2, - .cnt1_reg = DMA7_CNT1, - .cnt2_reg = DMA7_CNT2, - }, - [SRAM_CH09] = { - .name = "ch9", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA8_PTR1, - .ptr2_reg = DMA8_PTR2, - .cnt1_reg = DMA8_CNT1, - .cnt2_reg = DMA8_CNT2, - }, -}; - -static struct sram_channel cx23887_sram_channels[] = { - [SRAM_CH01] = { - .name = "VID A", - .cmds_start = 0x10000, - .ctrl_start = 0x105b0, - .cdt = 0x107b0, - .fifo_start = 0x40, - .fifo_size = 0x2800, - .ptr1_reg = DMA1_PTR1, - .ptr2_reg = DMA1_PTR2, - .cnt1_reg = DMA1_CNT1, - .cnt2_reg = DMA1_CNT2, - }, - [SRAM_CH02] = { - .name = "ch2", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA2_PTR1, - .ptr2_reg = DMA2_PTR2, - .cnt1_reg = DMA2_CNT1, - .cnt2_reg = DMA2_CNT2, - }, - [SRAM_CH03] = { - .name = "TS1 B", - .cmds_start = 0x100A0, - .ctrl_start = 0x10630, - .cdt = 0x10870, - .fifo_start = 0x5000, - .fifo_size = 0x1000, - .ptr1_reg = DMA3_PTR1, - .ptr2_reg = DMA3_PTR2, - .cnt1_reg = DMA3_CNT1, - .cnt2_reg = DMA3_CNT2, - }, - [SRAM_CH04] = { - .name = "ch4", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA4_PTR1, - .ptr2_reg = DMA4_PTR2, - .cnt1_reg = DMA4_CNT1, - .cnt2_reg = DMA4_CNT2, - }, - [SRAM_CH05] = { - .name = "ch5", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA5_PTR1, - .ptr2_reg = DMA5_PTR2, - .cnt1_reg = DMA5_CNT1, - .cnt2_reg = DMA5_CNT2, - }, - [SRAM_CH06] = { - .name = "TS2 C", - .cmds_start = 0x10140, - .ctrl_start = 0x10670, - .cdt = 0x108d0, - .fifo_start = 0x6000, - .fifo_size = 0x1000, - .ptr1_reg = DMA5_PTR1, - .ptr2_reg = DMA5_PTR2, - .cnt1_reg = DMA5_CNT1, - .cnt2_reg = DMA5_CNT2, - }, - [SRAM_CH07] = { - .name = "ch7", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA6_PTR1, - .ptr2_reg = DMA6_PTR2, - .cnt1_reg = DMA6_CNT1, - .cnt2_reg = DMA6_CNT2, - }, - [SRAM_CH08] = { - .name = "ch8", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA7_PTR1, - .ptr2_reg = DMA7_PTR2, - .cnt1_reg = DMA7_CNT1, - .cnt2_reg = DMA7_CNT2, - }, - [SRAM_CH09] = { - .name = "ch9", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, - .ptr1_reg = DMA8_PTR1, - .ptr2_reg = DMA8_PTR2, - .cnt1_reg = DMA8_CNT1, - .cnt2_reg = DMA8_CNT2, - }, -}; - -void cx23885_irq_add(struct cx23885_dev *dev, u32 mask) -{ - unsigned long flags; - spin_lock_irqsave(&dev->pci_irqmask_lock, flags); - - dev->pci_irqmask |= mask; - - spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); -} - -void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask) -{ - unsigned long flags; - spin_lock_irqsave(&dev->pci_irqmask_lock, flags); - - dev->pci_irqmask |= mask; - cx_set(PCI_INT_MSK, mask); - - spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); -} - -void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask) -{ - u32 v; - unsigned long flags; - spin_lock_irqsave(&dev->pci_irqmask_lock, flags); - - v = mask & dev->pci_irqmask; - if (v) - cx_set(PCI_INT_MSK, v); - - spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); -} - -static inline void cx23885_irq_enable_all(struct cx23885_dev *dev) -{ - cx23885_irq_enable(dev, 0xffffffff); -} - -void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask) -{ - unsigned long flags; - spin_lock_irqsave(&dev->pci_irqmask_lock, flags); - - cx_clear(PCI_INT_MSK, mask); - - spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); -} - -static inline void cx23885_irq_disable_all(struct cx23885_dev *dev) -{ - cx23885_irq_disable(dev, 0xffffffff); -} - -void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask) -{ - unsigned long flags; - spin_lock_irqsave(&dev->pci_irqmask_lock, flags); - - dev->pci_irqmask &= ~mask; - cx_clear(PCI_INT_MSK, mask); - - spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); -} - -static u32 cx23885_irq_get_mask(struct cx23885_dev *dev) -{ - u32 v; - unsigned long flags; - spin_lock_irqsave(&dev->pci_irqmask_lock, flags); - - v = cx_read(PCI_INT_MSK); - - spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); - return v; -} - -static int cx23885_risc_decode(u32 risc) -{ - static char *instr[16] = { - [RISC_SYNC >> 28] = "sync", - [RISC_WRITE >> 28] = "write", - [RISC_WRITEC >> 28] = "writec", - [RISC_READ >> 28] = "read", - [RISC_READC >> 28] = "readc", - [RISC_JUMP >> 28] = "jump", - [RISC_SKIP >> 28] = "skip", - [RISC_WRITERM >> 28] = "writerm", - [RISC_WRITECM >> 28] = "writecm", - [RISC_WRITECR >> 28] = "writecr", - }; - static int incr[16] = { - [RISC_WRITE >> 28] = 3, - [RISC_JUMP >> 28] = 3, - [RISC_SKIP >> 28] = 1, - [RISC_SYNC >> 28] = 1, - [RISC_WRITERM >> 28] = 3, - [RISC_WRITECM >> 28] = 3, - [RISC_WRITECR >> 28] = 4, - }; - static char *bits[] = { - "12", "13", "14", "resync", - "cnt0", "cnt1", "18", "19", - "20", "21", "22", "23", - "irq1", "irq2", "eol", "sol", - }; - int i; - - printk("0x%08x [ %s", risc, - instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); - for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) - if (risc & (1 << (i + 12))) - printk(" %s", bits[i]); - printk(" count=%d ]\n", risc & 0xfff); - return incr[risc >> 28] ? incr[risc >> 28] : 1; -} - -void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - do_gettimeofday(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } - if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - if (bc != 1) - printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n", - __func__, bc); -} - -int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) -{ - unsigned int i, lines; - u32 cdt; - - if (ch->cmds_start == 0) { - dprintk(1, "%s() Erasing channel [%s]\n", __func__, - ch->name); - cx_write(ch->ptr1_reg, 0); - cx_write(ch->ptr2_reg, 0); - cx_write(ch->cnt2_reg, 0); - cx_write(ch->cnt1_reg, 0); - return 0; - } else { - dprintk(1, "%s() Configuring channel [%s]\n", __func__, - ch->name); - } - - bpl = (bpl + 7) & ~7; /* alignment */ - cdt = ch->cdt; - lines = ch->fifo_size / bpl; - if (lines > 6) - lines = 6; - BUG_ON(lines < 2); - - cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - cx_write(8 + 4, 8); - cx_write(8 + 8, 0); - - /* write CDT */ - for (i = 0; i < lines; i++) { - dprintk(2, "%s() 0x%08x <- 0x%08x\n", __func__, cdt + 16*i, - ch->fifo_start + bpl*i); - cx_write(cdt + 16*i, ch->fifo_start + bpl*i); - cx_write(cdt + 16*i + 4, 0); - cx_write(cdt + 16*i + 8, 0); - cx_write(cdt + 16*i + 12, 0); - } - - /* write CMDS */ - if (ch->jumponly) - cx_write(ch->cmds_start + 0, 8); - else - cx_write(ch->cmds_start + 0, risc); - cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ - cx_write(ch->cmds_start + 8, cdt); - cx_write(ch->cmds_start + 12, (lines*16) >> 3); - cx_write(ch->cmds_start + 16, ch->ctrl_start); - if (ch->jumponly) - cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); - else - cx_write(ch->cmds_start + 20, 64 >> 2); - for (i = 24; i < 80; i += 4) - cx_write(ch->cmds_start + i, 0); - - /* fill registers */ - cx_write(ch->ptr1_reg, ch->fifo_start); - cx_write(ch->ptr2_reg, cdt); - cx_write(ch->cnt2_reg, (lines*16) >> 3); - cx_write(ch->cnt1_reg, (bpl >> 3) - 1); - - dprintk(2, "[bridge %d] sram setup %s: bpl=%d lines=%d\n", - dev->bridge, - ch->name, - bpl, - lines); - - return 0; -} - -void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch) -{ - static char *name[] = { - "init risc lo", - "init risc hi", - "cdt base", - "cdt size", - "iq base", - "iq size", - "risc pc lo", - "risc pc hi", - "iq wr ptr", - "iq rd ptr", - "cdt current", - "pci target lo", - "pci target hi", - "line / byte", - }; - u32 risc; - unsigned int i, j, n; - - printk(KERN_WARNING "%s: %s - dma channel status dump\n", - dev->name, ch->name); - for (i = 0; i < ARRAY_SIZE(name); i++) - printk(KERN_WARNING "%s: cmds: %-15s: 0x%08x\n", - dev->name, name[i], - cx_read(ch->cmds_start + 4*i)); - - for (i = 0; i < 4; i++) { - risc = cx_read(ch->cmds_start + 4 * (i + 14)); - printk(KERN_WARNING "%s: risc%d: ", dev->name, i); - cx23885_risc_decode(risc); - } - for (i = 0; i < (64 >> 2); i += n) { - risc = cx_read(ch->ctrl_start + 4 * i); - /* No consideration for bits 63-32 */ - - printk(KERN_WARNING "%s: (0x%08x) iq %x: ", dev->name, - ch->ctrl_start + 4 * i, i); - n = cx23885_risc_decode(risc); - for (j = 1; j < n; j++) { - risc = cx_read(ch->ctrl_start + 4 * (i + j)); - printk(KERN_WARNING "%s: iq %x: 0x%08x [ arg #%d ]\n", - dev->name, i+j, risc, j); - } - } - - printk(KERN_WARNING "%s: fifo: 0x%08x -> 0x%x\n", - dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); - printk(KERN_WARNING "%s: ctrl: 0x%08x -> 0x%x\n", - dev->name, ch->ctrl_start, ch->ctrl_start + 6*16); - printk(KERN_WARNING "%s: ptr1_reg: 0x%08x\n", - dev->name, cx_read(ch->ptr1_reg)); - printk(KERN_WARNING "%s: ptr2_reg: 0x%08x\n", - dev->name, cx_read(ch->ptr2_reg)); - printk(KERN_WARNING "%s: cnt1_reg: 0x%08x\n", - dev->name, cx_read(ch->cnt1_reg)); - printk(KERN_WARNING "%s: cnt2_reg: 0x%08x\n", - dev->name, cx_read(ch->cnt2_reg)); -} - -static void cx23885_risc_disasm(struct cx23885_tsport *port, - struct btcx_riscmem *risc) -{ - struct cx23885_dev *dev = port->dev; - unsigned int i, j, n; - - printk(KERN_INFO "%s: risc disasm: %p [dma=0x%08lx]\n", - dev->name, risc->cpu, (unsigned long)risc->dma); - for (i = 0; i < (risc->size >> 2); i += n) { - printk(KERN_INFO "%s: %04d: ", dev->name, i); - n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i])); - for (j = 1; j < n; j++) - printk(KERN_INFO "%s: %04d: 0x%08x [ arg #%d ]\n", - dev->name, i + j, risc->cpu[i + j], j); - if (risc->cpu[i] == cpu_to_le32(RISC_JUMP)) - break; - } -} - -static void cx23885_shutdown(struct cx23885_dev *dev) -{ - /* disable RISC controller */ - cx_write(DEV_CNTRL2, 0); - - /* Disable all IR activity */ - cx_write(IR_CNTRL_REG, 0); - - /* Disable Video A/B activity */ - cx_write(VID_A_DMA_CTL, 0); - cx_write(VID_B_DMA_CTL, 0); - cx_write(VID_C_DMA_CTL, 0); - - /* Disable Audio activity */ - cx_write(AUD_INT_DMA_CTL, 0); - cx_write(AUD_EXT_DMA_CTL, 0); - - /* Disable Serial port */ - cx_write(UART_CTL, 0); - - /* Disable Interrupts */ - cx23885_irq_disable_all(dev); - cx_write(VID_A_INT_MSK, 0); - cx_write(VID_B_INT_MSK, 0); - cx_write(VID_C_INT_MSK, 0); - cx_write(AUDIO_INT_INT_MSK, 0); - cx_write(AUDIO_EXT_INT_MSK, 0); - -} - -static void cx23885_reset(struct cx23885_dev *dev) -{ - dprintk(1, "%s()\n", __func__); - - cx23885_shutdown(dev); - - cx_write(PCI_INT_STAT, 0xffffffff); - cx_write(VID_A_INT_STAT, 0xffffffff); - cx_write(VID_B_INT_STAT, 0xffffffff); - cx_write(VID_C_INT_STAT, 0xffffffff); - cx_write(AUDIO_INT_INT_STAT, 0xffffffff); - cx_write(AUDIO_EXT_INT_STAT, 0xffffffff); - cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); - cx_write(PAD_CTRL, 0x00500300); - - mdelay(100); - - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], - 720*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03], - 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06], - 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0); - - cx23885_gpio_setup(dev); -} - - -static int cx23885_pci_quirks(struct cx23885_dev *dev) -{ - dprintk(1, "%s()\n", __func__); - - /* The cx23885 bridge has a weird bug which causes NMI to be asserted - * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not - * occur on the cx23887 bridge. - */ - if (dev->bridge == CX23885_BRIDGE_885) - cx_clear(RDR_TLCTL0, 1 << 4); - - return 0; -} - -static int get_resources(struct cx23885_dev *dev) -{ - if (request_mem_region(pci_resource_start(dev->pci, 0), - pci_resource_len(dev->pci, 0), - dev->name)) - return 0; - - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", - dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); - - return -EBUSY; -} - -static void cx23885_timeout(unsigned long data); -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); - -static int cx23885_init_tsport(struct cx23885_dev *dev, - struct cx23885_tsport *port, int portno) -{ - dprintk(1, "%s(portno=%d)\n", __func__, portno); - - /* Transport bus init dma queue - Common settings */ - port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - port->vld_misc_val = 0x0; - port->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4); - - spin_lock_init(&port->slock); - port->dev = dev; - port->nr = portno; - - INIT_LIST_HEAD(&port->mpegq.active); - INIT_LIST_HEAD(&port->mpegq.queued); - port->mpegq.timeout.function = cx23885_timeout; - port->mpegq.timeout.data = (unsigned long)port; - init_timer(&port->mpegq.timeout); - - mutex_init(&port->frontends.lock); - INIT_LIST_HEAD(&port->frontends.felist); - port->frontends.active_fe_id = 0; - - /* This should be hardcoded allow a single frontend - * attachment to this tsport, keeping the -dvb.c - * code clean and safe. - */ - if (!port->num_frontends) - port->num_frontends = 1; - - switch (portno) { - case 1: - port->reg_gpcnt = VID_B_GPCNT; - port->reg_gpcnt_ctl = VID_B_GPCNT_CTL; - port->reg_dma_ctl = VID_B_DMA_CTL; - port->reg_lngth = VID_B_LNGTH; - port->reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; - port->reg_gen_ctrl = VID_B_GEN_CTL; - port->reg_bd_pkt_status = VID_B_BD_PKT_STATUS; - port->reg_sop_status = VID_B_SOP_STATUS; - port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; - port->reg_vld_misc = VID_B_VLD_MISC; - port->reg_ts_clk_en = VID_B_TS_CLK_EN; - port->reg_src_sel = VID_B_SRC_SEL; - port->reg_ts_int_msk = VID_B_INT_MSK; - port->reg_ts_int_stat = VID_B_INT_STAT; - port->sram_chno = SRAM_CH03; /* VID_B */ - port->pci_irqmask = 0x02; /* VID_B bit1 */ - break; - case 2: - port->reg_gpcnt = VID_C_GPCNT; - port->reg_gpcnt_ctl = VID_C_GPCNT_CTL; - port->reg_dma_ctl = VID_C_DMA_CTL; - port->reg_lngth = VID_C_LNGTH; - port->reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; - port->reg_gen_ctrl = VID_C_GEN_CTL; - port->reg_bd_pkt_status = VID_C_BD_PKT_STATUS; - port->reg_sop_status = VID_C_SOP_STATUS; - port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; - port->reg_vld_misc = VID_C_VLD_MISC; - port->reg_ts_clk_en = VID_C_TS_CLK_EN; - port->reg_src_sel = 0; - port->reg_ts_int_msk = VID_C_INT_MSK; - port->reg_ts_int_stat = VID_C_INT_STAT; - port->sram_chno = SRAM_CH06; /* VID_C */ - port->pci_irqmask = 0x04; /* VID_C bit2 */ - break; - default: - BUG(); - } - - cx23885_risc_stopper(dev->pci, &port->mpegq.stopper, - port->reg_dma_ctl, port->dma_ctl_val, 0x00); - - return 0; -} - -static void cx23885_dev_checkrevision(struct cx23885_dev *dev) -{ - switch (cx_read(RDR_CFG2) & 0xff) { - case 0x00: - /* cx23885 */ - dev->hwrevision = 0xa0; - break; - case 0x01: - /* CX23885-12Z */ - dev->hwrevision = 0xa1; - break; - case 0x02: - /* CX23885-13Z/14Z */ - dev->hwrevision = 0xb0; - break; - case 0x03: - if (dev->pci->device == 0x8880) { - /* CX23888-21Z/22Z */ - dev->hwrevision = 0xc0; - } else { - /* CX23885-14Z */ - dev->hwrevision = 0xa4; - } - break; - case 0x04: - if (dev->pci->device == 0x8880) { - /* CX23888-31Z */ - dev->hwrevision = 0xd0; - } else { - /* CX23885-15Z, CX23888-31Z */ - dev->hwrevision = 0xa5; - } - break; - case 0x0e: - /* CX23887-15Z */ - dev->hwrevision = 0xc0; - break; - case 0x0f: - /* CX23887-14Z */ - dev->hwrevision = 0xb1; - break; - default: - printk(KERN_ERR "%s() New hardware revision found 0x%x\n", - __func__, dev->hwrevision); - } - if (dev->hwrevision) - printk(KERN_INFO "%s() Hardware revision = 0x%02x\n", - __func__, dev->hwrevision); - else - printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n", - __func__, dev->hwrevision); -} - -/* Find the first v4l2_subdev member of the group id in hw */ -struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw) -{ - struct v4l2_subdev *result = NULL; - struct v4l2_subdev *sd; - - spin_lock(&dev->v4l2_dev.lock); - v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) { - if (sd->grp_id == hw) { - result = sd; - break; - } - } - spin_unlock(&dev->v4l2_dev.lock); - return result; -} - -static int cx23885_dev_setup(struct cx23885_dev *dev) -{ - int i; - - spin_lock_init(&dev->pci_irqmask_lock); - - mutex_init(&dev->lock); - mutex_init(&dev->gpio_lock); - - atomic_inc(&dev->refcount); - - dev->nr = cx23885_devcount++; - sprintf(dev->name, "cx23885[%d]", dev->nr); - - /* Configure the internal memory */ - if (dev->pci->device == 0x8880) { - /* Could be 887 or 888, assume a default */ - dev->bridge = CX23885_BRIDGE_887; - /* Apply a sensible clock frequency for the PCIe bridge */ - dev->clk_freq = 25000000; - dev->sram_channels = cx23887_sram_channels; - } else - if (dev->pci->device == 0x8852) { - dev->bridge = CX23885_BRIDGE_885; - /* Apply a sensible clock frequency for the PCIe bridge */ - dev->clk_freq = 28000000; - dev->sram_channels = cx23885_sram_channels; - } else - BUG(); - - dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", - __func__, dev->bridge); - - /* board config */ - dev->board = UNSET; - if (card[dev->nr] < cx23885_bcount) - dev->board = card[dev->nr]; - for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) - if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && - dev->pci->subsystem_device == cx23885_subids[i].subdevice) - dev->board = cx23885_subids[i].card; - if (UNSET == dev->board) { - dev->board = CX23885_BOARD_UNKNOWN; - cx23885_card_list(dev); - } - - /* If the user specific a clk freq override, apply it */ - if (cx23885_boards[dev->board].clk_freq > 0) - dev->clk_freq = cx23885_boards[dev->board].clk_freq; - - dev->pci_bus = dev->pci->bus->number; - dev->pci_slot = PCI_SLOT(dev->pci->devfn); - cx23885_irq_add(dev, 0x001f00); - - /* External Master 1 Bus */ - dev->i2c_bus[0].nr = 0; - dev->i2c_bus[0].dev = dev; - dev->i2c_bus[0].reg_stat = I2C1_STAT; - dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; - dev->i2c_bus[0].reg_addr = I2C1_ADDR; - dev->i2c_bus[0].reg_rdata = I2C1_RDATA; - dev->i2c_bus[0].reg_wdata = I2C1_WDATA; - dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */ - - /* External Master 2 Bus */ - dev->i2c_bus[1].nr = 1; - dev->i2c_bus[1].dev = dev; - dev->i2c_bus[1].reg_stat = I2C2_STAT; - dev->i2c_bus[1].reg_ctrl = I2C2_CTRL; - dev->i2c_bus[1].reg_addr = I2C2_ADDR; - dev->i2c_bus[1].reg_rdata = I2C2_RDATA; - dev->i2c_bus[1].reg_wdata = I2C2_WDATA; - dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */ - - /* Internal Master 3 Bus */ - dev->i2c_bus[2].nr = 2; - dev->i2c_bus[2].dev = dev; - dev->i2c_bus[2].reg_stat = I2C3_STAT; - dev->i2c_bus[2].reg_ctrl = I2C3_CTRL; - dev->i2c_bus[2].reg_addr = I2C3_ADDR; - dev->i2c_bus[2].reg_rdata = I2C3_RDATA; - dev->i2c_bus[2].reg_wdata = I2C3_WDATA; - dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ - - if ((cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) || - (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)) - cx23885_init_tsport(dev, &dev->ts1, 1); - - if ((cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) || - (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)) - cx23885_init_tsport(dev, &dev->ts2, 2); - - if (get_resources(dev) < 0) { - printk(KERN_ERR "CORE %s No more PCIe resources for " - "subsystem: %04x:%04x\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device); - - cx23885_devcount--; - return -ENODEV; - } - - /* PCIe stuff */ - dev->lmmio = ioremap(pci_resource_start(dev->pci, 0), - pci_resource_len(dev->pci, 0)); - - dev->bmmio = (u8 __iomem *)dev->lmmio; - - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, cx23885_boards[dev->board].name, - dev->board, card[dev->nr] == dev->board ? - "insmod option" : "autodetected"); - - cx23885_pci_quirks(dev); - - /* Assume some sensible defaults */ - dev->tuner_type = cx23885_boards[dev->board].tuner_type; - dev->tuner_addr = cx23885_boards[dev->board].tuner_addr; - dev->tuner_bus = cx23885_boards[dev->board].tuner_bus; - dev->radio_type = cx23885_boards[dev->board].radio_type; - dev->radio_addr = cx23885_boards[dev->board].radio_addr; - - dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x tuner_bus = %d\n", - __func__, dev->tuner_type, dev->tuner_addr, dev->tuner_bus); - dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n", - __func__, dev->radio_type, dev->radio_addr); - - /* The cx23417 encoder has GPIO's that need to be initialised - * before DVB, so that demodulators and tuners are out of - * reset before DVB uses them. - */ - if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) || - (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)) - cx23885_mc417_init(dev); - - /* init hardware */ - cx23885_reset(dev); - - cx23885_i2c_register(&dev->i2c_bus[0]); - cx23885_i2c_register(&dev->i2c_bus[1]); - cx23885_i2c_register(&dev->i2c_bus[2]); - cx23885_card_setup(dev); - call_all(dev, core, s_power, 0); - cx23885_ir_init(dev); - - if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { - if (cx23885_video_register(dev) < 0) { - printk(KERN_ERR "%s() Failed to register analog " - "video adapters on VID_A\n", __func__); - } - } - - if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { - if (cx23885_boards[dev->board].num_fds_portb) - dev->ts1.num_frontends = - cx23885_boards[dev->board].num_fds_portb; - if (cx23885_dvb_register(&dev->ts1) < 0) { - printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", - __func__); - } - } else - if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { - if (cx23885_417_register(dev) < 0) { - printk(KERN_ERR - "%s() Failed to register 417 on VID_B\n", - __func__); - } - } - - if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { - if (cx23885_boards[dev->board].num_fds_portc) - dev->ts2.num_frontends = - cx23885_boards[dev->board].num_fds_portc; - if (cx23885_dvb_register(&dev->ts2) < 0) { - printk(KERN_ERR - "%s() Failed to register dvb on VID_C\n", - __func__); - } - } else - if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) { - if (cx23885_417_register(dev) < 0) { - printk(KERN_ERR - "%s() Failed to register 417 on VID_C\n", - __func__); - } - } - - cx23885_dev_checkrevision(dev); - - /* disable MSI for NetUP cards, otherwise CI is not working */ - if (cx23885_boards[dev->board].ci_type > 0) - cx_clear(RDR_RDRCTL1, 1 << 8); - - return 0; -} - -static void cx23885_dev_unregister(struct cx23885_dev *dev) -{ - release_mem_region(pci_resource_start(dev->pci, 0), - pci_resource_len(dev->pci, 0)); - - if (!atomic_dec_and_test(&dev->refcount)) - return; - - if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) - cx23885_video_unregister(dev); - - if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) - cx23885_dvb_unregister(&dev->ts1); - - if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) - cx23885_417_unregister(dev); - - if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) - cx23885_dvb_unregister(&dev->ts2); - - if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) - cx23885_417_unregister(dev); - - cx23885_i2c_unregister(&dev->i2c_bus[2]); - cx23885_i2c_unregister(&dev->i2c_bus[1]); - cx23885_i2c_unregister(&dev->i2c_bus[0]); - - iounmap(dev->lmmio); -} - -static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, - unsigned int offset, u32 sync_line, - unsigned int bpl, unsigned int padding, - unsigned int lines) -{ - struct scatterlist *sg; - unsigned int line, todo; - - /* sync instruction */ - if (sync_line != NO_SYNC_LINE) - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - /* scan lines */ - sg = sglist; - for (line = 0; line < lines; line++) { - while (offset && offset >= sg_dma_len(sg)) { - offset -= sg_dma_len(sg); - sg++; - } - if (bpl <= sg_dma_len(sg)-offset) { - /* fits into current chunk */ - *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); - *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - offset += bpl; - } else { - /* scanline needs to be split */ - todo = bpl; - *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL| - (sg_dma_len(sg)-offset)); - *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - todo -= (sg_dma_len(sg)-offset); - offset = 0; - sg++; - while (todo > sg_dma_len(sg)) { - *(rp++) = cpu_to_le32(RISC_WRITE| - sg_dma_len(sg)); - *(rp++) = cpu_to_le32(sg_dma_address(sg)); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - todo -= sg_dma_len(sg); - sg++; - } - *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); - *(rp++) = cpu_to_le32(sg_dma_address(sg)); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - offset += todo; - } - offset += padding; - } - - return rp; -} - -int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int top_offset, - unsigned int bottom_offset, unsigned int bpl, - unsigned int padding, unsigned int lines) -{ - u32 instructions, fields; - __le32 *rp; - int rc; - - fields = 0; - if (UNSET != top_offset) - fields++; - if (UNSET != bottom_offset) - fields++; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Padding - can cause next bpl to start close to a page border. First DMA - region may be smaller than PAGE_SIZE */ - /* write and jump need and extra dword */ - instructions = fields * (1 + ((bpl + padding) * lines) - / PAGE_SIZE + lines); - instructions += 2; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - if (UNSET != top_offset) - rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); - if (UNSET != bottom_offset) - rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - return 0; -} - -static int cx23885_risc_databuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int bpl, - unsigned int lines) -{ - u32 instructions; - __le32 *rp; - int rc; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Here - there is no padding and no sync. First DMA region may be smaller - than PAGE_SIZE */ - /* Jump and write need an extra dword */ - instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; - instructions += 1; - - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - return 0; -} - -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) -{ - __le32 *rp; - int rc; - - rc = btcx_riscmem_alloc(pci, risc, 4*16); - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); - *(rp++) = cpu_to_le32(reg); - *(rp++) = cpu_to_le32(value); - *(rp++) = cpu_to_le32(mask); - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - return 0; -} - -void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - - BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) -{ - struct cx23885_dev *dev = port->dev; - - dprintk(1, "%s() Register Dump\n", __func__); - dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__, - cx_read(DEV_CNTRL2)); - dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__, - cx23885_irq_get_mask(dev)); - dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__, - cx_read(AUDIO_INT_INT_MSK)); - dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__, - cx_read(AUD_INT_DMA_CTL)); - dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __func__, - cx_read(AUDIO_EXT_INT_MSK)); - dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __func__, - cx_read(AUD_EXT_DMA_CTL)); - dprintk(1, "%s() PAD_CTRL 0x%08X\n", __func__, - cx_read(PAD_CTRL)); - dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __func__, - cx_read(ALT_PIN_OUT_SEL)); - dprintk(1, "%s() GPIO2 0x%08X\n", __func__, - cx_read(GPIO2)); - dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __func__, - port->reg_gpcnt, cx_read(port->reg_gpcnt)); - dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __func__, - port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); - dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__, - port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); - if (port->reg_src_sel) - dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__, - port->reg_src_sel, cx_read(port->reg_src_sel)); - dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__, - port->reg_lngth, cx_read(port->reg_lngth)); - dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__, - port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl)); - dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __func__, - port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl)); - dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __func__, - port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status)); - dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __func__, - port->reg_sop_status, cx_read(port->reg_sop_status)); - dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__, - port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat)); - dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __func__, - port->reg_vld_misc, cx_read(port->reg_vld_misc)); - dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __func__, - port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en)); - dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__, - port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); -} - -static int cx23885_start_dma(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, - struct cx23885_buffer *buf) -{ - struct cx23885_dev *dev = port->dev; - u32 reg; - - dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, - buf->vb.width, buf->vb.height, buf->vb.field); - - /* Stop the fifo and risc engine for this port */ - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - - /* setup fifo + format */ - cx23885_sram_channel_setup(dev, - &dev->sram_channels[port->sram_chno], - port->ts_packet_size, buf->risc.dma); - if (debug > 5) { - cx23885_sram_channel_dump(dev, - &dev->sram_channels[port->sram_chno]); - cx23885_risc_disasm(port, &buf->risc); - } - - /* write TS length to chip */ - cx_write(port->reg_lngth, buf->vb.width); - - if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && - (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { - printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n", - __func__, - cx23885_boards[dev->board].portb, - cx23885_boards[dev->board].portc); - return -EINVAL; - } - - if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) - cx23885_av_clk(dev, 0); - - udelay(100); - - /* If the port supports SRC SELECT, configure it */ - if (port->reg_src_sel) - cx_write(port->reg_src_sel, port->src_sel_val); - - cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val); - cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); - cx_write(port->reg_vld_misc, port->vld_misc_val); - cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); - udelay(100); - - /* NOTE: this is 2 (reserved) for portb, does it matter? */ - /* reset counter to zero */ - cx_write(port->reg_gpcnt_ctl, 3); - q->count = 1; - - /* Set VIDB pins to input */ - if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { - reg = cx_read(PAD_CTRL); - reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */ - cx_write(PAD_CTRL, reg); - } - - /* Set VIDC pins to input */ - if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { - reg = cx_read(PAD_CTRL); - reg &= ~0x4; /* Clear TS2_SOP_OE */ - cx_write(PAD_CTRL, reg); - } - - if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { - - reg = cx_read(PAD_CTRL); - reg = reg & ~0x1; /* Clear TS1_OE */ - - /* FIXME, bit 2 writing here is questionable */ - /* set TS1_SOP_OE and TS1_OE_HI */ - reg = reg | 0xa; - cx_write(PAD_CTRL, reg); - - /* FIXME and these two registers should be documented. */ - cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011); - cx_write(ALT_PIN_OUT_SEL, 0x10100045); - } - - switch (dev->bridge) { - case CX23885_BRIDGE_885: - case CX23885_BRIDGE_887: - case CX23885_BRIDGE_888: - /* enable irqs */ - dprintk(1, "%s() enabling TS int's and DMA\n", __func__); - cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); - cx_set(port->reg_dma_ctl, port->dma_ctl_val); - cx23885_irq_add(dev, port->pci_irqmask); - cx23885_irq_enable_all(dev); - break; - default: - BUG(); - } - - cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ - - if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) - cx23885_av_clk(dev, 1); - - if (debug > 4) - cx23885_tsport_reg_dump(port); - - return 0; -} - -static int cx23885_stop_dma(struct cx23885_tsport *port) -{ - struct cx23885_dev *dev = port->dev; - u32 reg; - - dprintk(1, "%s()\n", __func__); - - /* Stop interrupts and DMA */ - cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - - if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { - - reg = cx_read(PAD_CTRL); - - /* Set TS1_OE */ - reg = reg | 0x1; - - /* clear TS1_SOP_OE and TS1_OE_HI */ - reg = reg & ~0xa; - cx_write(PAD_CTRL, reg); - cx_write(port->reg_src_sel, 0); - cx_write(port->reg_gen_ctrl, 8); - - } - - if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) - cx23885_av_clk(dev, 0); - - return 0; -} - -int cx23885_restart_queue(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_buffer *buf; - - dprintk(5, "%s()\n", __func__); - if (list_empty(&q->active)) { - struct cx23885_buffer *prev; - prev = NULL; - - dprintk(5, "%s() queue is empty\n", __func__); - - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, - vb.queue); - if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_dma(port, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(5, "[%p/%d] restart_queue - f/active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(5, "[%p/%d] restart_queue - m/active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } - return 0; - } - - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_dma(port, q, buf); - list_for_each_entry(buf, &q->active, vb.queue) - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; -} - -/* ------------------------------------------------------------------ */ - -int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, - struct cx23885_buffer *buf, enum v4l2_field field) -{ - struct cx23885_dev *dev = port->dev; - int size = port->ts_packet_size * port->ts_packet_count; - int rc; - - dprintk(1, "%s: %p\n", __func__, buf); - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = port->ts_packet_size; - buf->vb.height = port->ts_packet_count; - buf->vb.size = size; - buf->vb.field = field /*V4L2_FIELD_TOP*/; - - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - cx23885_risc_databuffer(dev->pci, &buf->risc, - videobuf_to_dma(&buf->vb)->sglist, - buf->vb.width, buf->vb.height); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - cx23885_free_buffer(q, buf); - return rc; -} - -void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) -{ - struct cx23885_buffer *prev; - struct cx23885_dev *dev = port->dev; - struct cx23885_dmaqueue *cx88q = &port->mpegq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); - buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - - if (list_empty(&cx88q->active)) { - dprintk(1, "queue is empty - first active\n"); - list_add_tail(&buf->vb.queue, &cx88q->active); - cx23885_start_dma(port, cx88q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; - mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); - dprintk(1, "[%p/%d] %s - first active\n", - buf, buf->vb.i, __func__); - } else { - dprintk(1, "queue is not empty - append to active\n"); - prev = list_entry(cx88q->active.prev, struct cx23885_buffer, - vb.queue); - list_add_tail(&buf->vb.queue, &cx88q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ - dprintk(1, "[%p/%d] %s - append to active\n", - buf, buf->vb.i, __func__); - } -} - -/* ----------------------------------------------------------- */ - -static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, - int restart) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_dmaqueue *q = &port->mpegq; - struct cx23885_buffer *buf; - unsigned long flags; - - spin_lock_irqsave(&port->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", - buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); - } - if (restart) { - dprintk(1, "restarting queue\n"); - cx23885_restart_queue(port, q); - } - spin_unlock_irqrestore(&port->slock, flags); -} - -void cx23885_cancel_buffers(struct cx23885_tsport *port) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_dmaqueue *q = &port->mpegq; - - dprintk(1, "%s()\n", __func__); - del_timer_sync(&q->timeout); - cx23885_stop_dma(port); - do_cancel_buffers(port, "cancel", 0); -} - -static void cx23885_timeout(unsigned long data) -{ - struct cx23885_tsport *port = (struct cx23885_tsport *)data; - struct cx23885_dev *dev = port->dev; - - dprintk(1, "%s()\n", __func__); - - if (debug > 5) - cx23885_sram_channel_dump(dev, - &dev->sram_channels[port->sram_chno]); - - cx23885_stop_dma(port); - do_cancel_buffers(port, "timeout", 1); -} - -int cx23885_irq_417(struct cx23885_dev *dev, u32 status) -{ - /* FIXME: port1 assumption here. */ - struct cx23885_tsport *port = &dev->ts1; - int count = 0; - int handled = 0; - - if (status == 0) - return handled; - - count = cx_read(port->reg_gpcnt); - dprintk(7, "status: 0x%08x mask: 0x%08x count: 0x%x\n", - status, cx_read(port->reg_ts_int_msk), count); - - if ((status & VID_B_MSK_BAD_PKT) || - (status & VID_B_MSK_OPC_ERR) || - (status & VID_B_MSK_VBI_OPC_ERR) || - (status & VID_B_MSK_SYNC) || - (status & VID_B_MSK_VBI_SYNC) || - (status & VID_B_MSK_OF) || - (status & VID_B_MSK_VBI_OF)) { - printk(KERN_ERR "%s: V4L mpeg risc op code error, status " - "= 0x%x\n", dev->name, status); - if (status & VID_B_MSK_BAD_PKT) - dprintk(1, " VID_B_MSK_BAD_PKT\n"); - if (status & VID_B_MSK_OPC_ERR) - dprintk(1, " VID_B_MSK_OPC_ERR\n"); - if (status & VID_B_MSK_VBI_OPC_ERR) - dprintk(1, " VID_B_MSK_VBI_OPC_ERR\n"); - if (status & VID_B_MSK_SYNC) - dprintk(1, " VID_B_MSK_SYNC\n"); - if (status & VID_B_MSK_VBI_SYNC) - dprintk(1, " VID_B_MSK_VBI_SYNC\n"); - if (status & VID_B_MSK_OF) - dprintk(1, " VID_B_MSK_OF\n"); - if (status & VID_B_MSK_VBI_OF) - dprintk(1, " VID_B_MSK_VBI_OF\n"); - - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - cx23885_sram_channel_dump(dev, - &dev->sram_channels[port->sram_chno]); - cx23885_417_check_encoder(dev); - } else if (status & VID_B_MSK_RISCI1) { - dprintk(7, " VID_B_MSK_RISCI1\n"); - spin_lock(&port->slock); - cx23885_wakeup(port, &port->mpegq, count); - spin_unlock(&port->slock); - } else if (status & VID_B_MSK_RISCI2) { - dprintk(7, " VID_B_MSK_RISCI2\n"); - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - } - if (status) { - cx_write(port->reg_ts_int_stat, status); - handled = 1; - } - - return handled; -} - -static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) -{ - struct cx23885_dev *dev = port->dev; - int handled = 0; - u32 count; - - if ((status & VID_BC_MSK_OPC_ERR) || - (status & VID_BC_MSK_BAD_PKT) || - (status & VID_BC_MSK_SYNC) || - (status & VID_BC_MSK_OF)) { - - if (status & VID_BC_MSK_OPC_ERR) - dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", - VID_BC_MSK_OPC_ERR); - - if (status & VID_BC_MSK_BAD_PKT) - dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", - VID_BC_MSK_BAD_PKT); - - if (status & VID_BC_MSK_SYNC) - dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", - VID_BC_MSK_SYNC); - - if (status & VID_BC_MSK_OF) - dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", - VID_BC_MSK_OF); - - printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); - - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - cx23885_sram_channel_dump(dev, - &dev->sram_channels[port->sram_chno]); - - } else if (status & VID_BC_MSK_RISCI1) { - - dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1); - - spin_lock(&port->slock); - count = cx_read(port->reg_gpcnt); - cx23885_wakeup(port, &port->mpegq, count); - spin_unlock(&port->slock); - - } else if (status & VID_BC_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - - } - if (status) { - cx_write(port->reg_ts_int_stat, status); - handled = 1; - } - - return handled; -} - -static irqreturn_t cx23885_irq(int irq, void *dev_id) -{ - struct cx23885_dev *dev = dev_id; - struct cx23885_tsport *ts1 = &dev->ts1; - struct cx23885_tsport *ts2 = &dev->ts2; - u32 pci_status, pci_mask; - u32 vida_status, vida_mask; - u32 ts1_status, ts1_mask; - u32 ts2_status, ts2_mask; - int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; - bool subdev_handled; - - pci_status = cx_read(PCI_INT_STAT); - pci_mask = cx23885_irq_get_mask(dev); - vida_status = cx_read(VID_A_INT_STAT); - vida_mask = cx_read(VID_A_INT_MSK); - ts1_status = cx_read(VID_B_INT_STAT); - ts1_mask = cx_read(VID_B_INT_MSK); - ts2_status = cx_read(VID_C_INT_STAT); - ts2_mask = cx_read(VID_C_INT_MSK); - - if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0)) - goto out; - - vida_count = cx_read(VID_A_GPCNT); - ts1_count = cx_read(ts1->reg_gpcnt); - ts2_count = cx_read(ts2->reg_gpcnt); - dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", - pci_status, pci_mask); - dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n", - vida_status, vida_mask, vida_count); - dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", - ts1_status, ts1_mask, ts1_count); - dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", - ts2_status, ts2_mask, ts2_count); - - if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR | - PCI_MSK_AL_RD | PCI_MSK_AL_WR | PCI_MSK_APB_DMA | - PCI_MSK_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A | - PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT | - PCI_MSK_GPIO0 | PCI_MSK_GPIO1 | - PCI_MSK_AV_CORE | PCI_MSK_IR)) { - - if (pci_status & PCI_MSK_RISC_RD) - dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", - PCI_MSK_RISC_RD); - - if (pci_status & PCI_MSK_RISC_WR) - dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", - PCI_MSK_RISC_WR); - - if (pci_status & PCI_MSK_AL_RD) - dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", - PCI_MSK_AL_RD); - - if (pci_status & PCI_MSK_AL_WR) - dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", - PCI_MSK_AL_WR); - - if (pci_status & PCI_MSK_APB_DMA) - dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", - PCI_MSK_APB_DMA); - - if (pci_status & PCI_MSK_VID_C) - dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", - PCI_MSK_VID_C); - - if (pci_status & PCI_MSK_VID_B) - dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", - PCI_MSK_VID_B); - - if (pci_status & PCI_MSK_VID_A) - dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", - PCI_MSK_VID_A); - - if (pci_status & PCI_MSK_AUD_INT) - dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", - PCI_MSK_AUD_INT); - - if (pci_status & PCI_MSK_AUD_EXT) - dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", - PCI_MSK_AUD_EXT); - - if (pci_status & PCI_MSK_GPIO0) - dprintk(7, " (PCI_MSK_GPIO0 0x%08x)\n", - PCI_MSK_GPIO0); - - if (pci_status & PCI_MSK_GPIO1) - dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n", - PCI_MSK_GPIO1); - - if (pci_status & PCI_MSK_AV_CORE) - dprintk(7, " (PCI_MSK_AV_CORE 0x%08x)\n", - PCI_MSK_AV_CORE); - - if (pci_status & PCI_MSK_IR) - dprintk(7, " (PCI_MSK_IR 0x%08x)\n", - PCI_MSK_IR); - } - - if (cx23885_boards[dev->board].ci_type == 1 && - (pci_status & (PCI_MSK_GPIO1 | PCI_MSK_GPIO0))) - handled += netup_ci_slot_status(dev, pci_status); - - if (cx23885_boards[dev->board].ci_type == 2 && - (pci_status & PCI_MSK_GPIO0)) - handled += altera_ci_irq(dev); - - if (ts1_status) { - if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) - handled += cx23885_irq_ts(ts1, ts1_status); - else - if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) - handled += cx23885_irq_417(dev, ts1_status); - } - - if (ts2_status) { - if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) - handled += cx23885_irq_ts(ts2, ts2_status); - else - if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) - handled += cx23885_irq_417(dev, ts2_status); - } - - if (vida_status) - handled += cx23885_video_irq(dev, vida_status); - - if (pci_status & PCI_MSK_IR) { - subdev_handled = false; - v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine, - pci_status, &subdev_handled); - if (subdev_handled) - handled++; - } - - if ((pci_status & pci_mask) & PCI_MSK_AV_CORE) { - cx23885_irq_disable(dev, PCI_MSK_AV_CORE); - if (!schedule_work(&dev->cx25840_work)) - printk(KERN_ERR "%s: failed to set up deferred work for" - " AV Core/IR interrupt. Interrupt is disabled" - " and won't be re-enabled\n", dev->name); - handled++; - } - - if (handled) - cx_write(PCI_INT_STAT, pci_status); -out: - return IRQ_RETVAL(handled); -} - -static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd, - unsigned int notification, void *arg) -{ - struct cx23885_dev *dev; - - if (sd == NULL) - return; - - dev = to_cx23885(sd->v4l2_dev); - - switch (notification) { - case V4L2_SUBDEV_IR_RX_NOTIFY: /* Possibly called in an IRQ context */ - if (sd == dev->sd_ir) - cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg); - break; - case V4L2_SUBDEV_IR_TX_NOTIFY: /* Possibly called in an IRQ context */ - if (sd == dev->sd_ir) - cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg); - break; - } -} - -static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev) -{ - INIT_WORK(&dev->cx25840_work, cx23885_av_work_handler); - INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler); - INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler); - dev->v4l2_dev.notify = cx23885_v4l2_dev_notify; -} - -static inline int encoder_on_portb(struct cx23885_dev *dev) -{ - return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER; -} - -static inline int encoder_on_portc(struct cx23885_dev *dev) -{ - return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER; -} - -/* Mask represents 32 different GPIOs, GPIO's are split into multiple - * registers depending on the board configuration (and whether the - * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will - * be pushed into the correct hardware register, regardless of the - * physical location. Certain registers are shared so we sanity check - * and report errors if we think we're tampering with a GPIo that might - * be assigned to the encoder (and used for the host bus). - * - * GPIO 2 thru 0 - On the cx23885 bridge - * GPIO 18 thru 3 - On the cx23417 host bus interface - * GPIO 23 thru 19 - On the cx25840 a/v core - */ -void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask) -{ - if (mask & 0x7) - cx_set(GP0_IO, mask & 0x7); - - if (mask & 0x0007fff8) { - if (encoder_on_portb(dev) || encoder_on_portc(dev)) - printk(KERN_ERR - "%s: Setting GPIO on encoder ports\n", - dev->name); - cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3); - } - - /* TODO: 23-19 */ - if (mask & 0x00f80000) - printk(KERN_INFO "%s: Unsupported\n", dev->name); -} - -void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask) -{ - if (mask & 0x00000007) - cx_clear(GP0_IO, mask & 0x7); - - if (mask & 0x0007fff8) { - if (encoder_on_portb(dev) || encoder_on_portc(dev)) - printk(KERN_ERR - "%s: Clearing GPIO moving on encoder ports\n", - dev->name); - cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3); - } - - /* TODO: 23-19 */ - if (mask & 0x00f80000) - printk(KERN_INFO "%s: Unsupported\n", dev->name); -} - -u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask) -{ - if (mask & 0x00000007) - return (cx_read(GP0_IO) >> 8) & mask & 0x7; - - if (mask & 0x0007fff8) { - if (encoder_on_portb(dev) || encoder_on_portc(dev)) - printk(KERN_ERR - "%s: Reading GPIO moving on encoder ports\n", - dev->name); - return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3; - } - - /* TODO: 23-19 */ - if (mask & 0x00f80000) - printk(KERN_INFO "%s: Unsupported\n", dev->name); - - return 0; -} - -void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) -{ - if ((mask & 0x00000007) && asoutput) - cx_set(GP0_IO, (mask & 0x7) << 16); - else if ((mask & 0x00000007) && !asoutput) - cx_clear(GP0_IO, (mask & 0x7) << 16); - - if (mask & 0x0007fff8) { - if (encoder_on_portb(dev) || encoder_on_portc(dev)) - printk(KERN_ERR - "%s: Enabling GPIO on encoder ports\n", - dev->name); - } - - /* MC417_OEN is active low for output, write 1 for an input */ - if ((mask & 0x0007fff8) && asoutput) - cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3); - - else if ((mask & 0x0007fff8) && !asoutput) - cx_set(MC417_OEN, (mask & 0x7fff8) >> 3); - - /* TODO: 23-19 */ -} - -static int __devinit cx23885_initdev(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - struct cx23885_dev *dev; - int err; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (NULL == dev) - return -ENOMEM; - - err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); - if (err < 0) - goto fail_free; - - /* Prepare to handle notifications from subdevices */ - cx23885_v4l2_dev_notify_init(dev); - - /* pci init */ - dev->pci = pci_dev; - if (pci_enable_device(pci_dev)) { - err = -EIO; - goto fail_unreg; - } - - if (cx23885_dev_setup(dev) < 0) { - err = -EINVAL; - goto fail_unreg; - } - - /* print pci info */ - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->name, - pci_name(pci_dev), dev->pci_rev, pci_dev->irq, - dev->pci_lat, - (unsigned long long)pci_resource_start(pci_dev, 0)); - - pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev, 0xffffffff)) { - printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); - err = -EIO; - goto fail_irq; - } - - if (!pci_enable_msi(pci_dev)) - err = request_irq(pci_dev->irq, cx23885_irq, - IRQF_DISABLED, dev->name, dev); - else - err = request_irq(pci_dev->irq, cx23885_irq, - IRQF_SHARED | IRQF_DISABLED, dev->name, dev); - if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", - dev->name, pci_dev->irq); - goto fail_irq; - } - - switch (dev->board) { - case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: - cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0); - break; - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: - cx23885_irq_add_enable(dev, PCI_MSK_GPIO0); - break; - } - - /* - * The CX2388[58] IR controller can start firing interrupts when - * enabled, so these have to take place after the cx23885_irq() handler - * is hooked up by the call to request_irq() above. - */ - cx23885_ir_pci_int_enable(dev); - cx23885_input_init(dev); - - return 0; - -fail_irq: - cx23885_dev_unregister(dev); -fail_unreg: - v4l2_device_unregister(&dev->v4l2_dev); -fail_free: - kfree(dev); - return err; -} - -static void __devexit cx23885_finidev(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct cx23885_dev *dev = to_cx23885(v4l2_dev); - - cx23885_input_fini(dev); - cx23885_ir_fini(dev); - - cx23885_shutdown(dev); - - pci_disable_device(pci_dev); - - /* unregister stuff */ - free_irq(pci_dev->irq, dev); - pci_disable_msi(pci_dev); - - cx23885_dev_unregister(dev); - v4l2_device_unregister(v4l2_dev); - kfree(dev); -} - -static struct pci_device_id cx23885_pci_tbl[] = { - { - /* CX23885 */ - .vendor = 0x14f1, - .device = 0x8852, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { - /* CX23887 Rev 2 */ - .vendor = 0x14f1, - .device = 0x8880, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { - /* --- end of list --- */ - } -}; -MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl); - -static struct pci_driver cx23885_pci_driver = { - .name = "cx23885", - .id_table = cx23885_pci_tbl, - .probe = cx23885_initdev, - .remove = __devexit_p(cx23885_finidev), - /* TODO */ - .suspend = NULL, - .resume = NULL, -}; - -static int __init cx23885_init(void) -{ - printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", - (CX23885_VERSION_CODE >> 16) & 0xff, - (CX23885_VERSION_CODE >> 8) & 0xff, - CX23885_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return pci_register_driver(&cx23885_pci_driver); -} - -static void __exit cx23885_fini(void) -{ - pci_unregister_driver(&cx23885_pci_driver); -} - -module_init(cx23885_init); -module_exit(cx23885_fini); - -/* ----------------------------------------------------------- */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-dvb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1268 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2006 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "cx23885.h" -#include - -#include "dvb_ca_en50221.h" -#include "s5h1409.h" -#include "s5h1411.h" -#include "mt2131.h" -#include "tda8290.h" -#include "tda18271.h" -#include "lgdt330x.h" -#include "xc5000.h" -#include "max2165.h" -#include "tda10048.h" -#include "tuner-xc2028.h" -#include "tuner-simple.h" -#include "dib7000p.h" -#include "dibx000_common.h" -#include "zl10353.h" -#include "stv0900.h" -#include "stv0900_reg.h" -#include "stv6110.h" -#include "lnbh24.h" -#include "cx24116.h" -#include "cimax2.h" -#include "lgs8gxx.h" -#include "netup-eeprom.h" -#include "netup-init.h" -#include "lgdt3305.h" -#include "atbm8830.h" -#include "ds3000.h" -#include "cx23885-f300.h" -#include "altera-ci.h" -#include "stv0367.h" - -static unsigned int debug; - -#define dprintk(level, fmt, arg...)\ - do { if (debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) - -/* ------------------------------------------------------------------ */ - -static unsigned int alt_tuner; -module_param(alt_tuner, int, 0644); -MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -/* ------------------------------------------------------------------ */ - -static int dvb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) -{ - struct cx23885_tsport *port = q->priv_data; - - port->ts_packet_size = 188 * 4; - port->ts_packet_count = 32; - - *size = port->ts_packet_size * port->ts_packet_count; - *count = 32; - return 0; -} - -static int dvb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct cx23885_tsport *port = q->priv_data; - return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field); -} - -static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct cx23885_tsport *port = q->priv_data; - cx23885_buf_queue(port, (struct cx23885_buffer *)vb); -} - -static void dvb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - cx23885_free_buffer(q, (struct cx23885_buffer *)vb); -} - -static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) -{ - struct videobuf_dvb_frontends *f; - struct videobuf_dvb_frontend *fe; - - f = &port->frontends; - - if (f->gate <= 1) /* undefined or fe0 */ - fe = videobuf_dvb_get_frontend(f, 1); - else - fe = videobuf_dvb_get_frontend(f, f->gate); - - if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) - fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); -} - -static struct videobuf_queue_ops dvb_qops = { - .buf_setup = dvb_buf_setup, - .buf_prepare = dvb_buf_prepare, - .buf_queue = dvb_buf_queue, - .buf_release = dvb_buf_release, -}; - -static struct s5h1409_config hauppauge_generic_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct tda10048_config hauppauge_hvr1200_config = { - .demod_address = 0x10 >> 1, - .output_mode = TDA10048_SERIAL_OUTPUT, - .fwbulkwritelen = TDA10048_BULKWRITE_200, - .inversion = TDA10048_INVERSION_ON, - .dtv6_if_freq_khz = TDA10048_IF_3300, - .dtv7_if_freq_khz = TDA10048_IF_3800, - .dtv8_if_freq_khz = TDA10048_IF_4300, - .clk_freq_khz = TDA10048_CLK_16000, -}; - -static struct tda10048_config hauppauge_hvr1210_config = { - .demod_address = 0x10 >> 1, - .output_mode = TDA10048_SERIAL_OUTPUT, - .fwbulkwritelen = TDA10048_BULKWRITE_200, - .inversion = TDA10048_INVERSION_ON, - .dtv6_if_freq_khz = TDA10048_IF_3300, - .dtv7_if_freq_khz = TDA10048_IF_3500, - .dtv8_if_freq_khz = TDA10048_IF_4000, - .clk_freq_khz = TDA10048_CLK_16000, -}; - -static struct s5h1409_config hauppauge_ezqam_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_OFF, - .qam_if = 4000, - .inversion = S5H1409_INVERSION_ON, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct s5h1409_config hauppauge_hvr1800lp_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_OFF, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct s5h1409_config hauppauge_hvr1500_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_OFF, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct mt2131_config hauppauge_generic_tunerconfig = { - 0x61 -}; - -static struct lgdt330x_config fusionhdtv_5_express = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, - .serial_mpeg = 0x40, -}; - -static struct s5h1409_config hauppauge_hvr1500q_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct s5h1409_config dvico_s5h1409_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct s5h1411_config dvico_s5h1411_config = { - .output_mode = S5H1411_SERIAL_OUTPUT, - .gpio = S5H1411_GPIO_ON, - .qam_if = S5H1411_IF_44000, - .vsb_if = S5H1411_IF_44000, - .inversion = S5H1411_INVERSION_OFF, - .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct s5h1411_config hcw_s5h1411_config = { - .output_mode = S5H1411_SERIAL_OUTPUT, - .gpio = S5H1411_GPIO_OFF, - .vsb_if = S5H1411_IF_44000, - .qam_if = S5H1411_IF_4000, - .inversion = S5H1411_INVERSION_ON, - .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { - .i2c_address = 0x61, - .if_khz = 5380, -}; - -static struct xc5000_config dvico_xc5000_tunerconfig = { - .i2c_address = 0x64, - .if_khz = 5380, -}; - -static struct tda829x_config tda829x_no_probe = { - .probe_tuner = TDA829X_DONT_PROBE, -}; - -static struct tda18271_std_map hauppauge_tda18271_std_map = { - .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, - .if_lvl = 6, .rfagc_top = 0x37 }, - .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, - .if_lvl = 6, .rfagc_top = 0x37 }, -}; - -static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = { - .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, - .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, - .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6, - .if_lvl = 1, .rfagc_top = 0x37, }, -}; - -static struct tda18271_config hauppauge_tda18271_config = { - .std_map = &hauppauge_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, - .output_opt = TDA18271_OUTPUT_LT_OFF, -}; - -static struct tda18271_config hauppauge_hvr1200_tuner_config = { - .std_map = &hauppauge_hvr1200_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, - .output_opt = TDA18271_OUTPUT_LT_OFF, -}; - -static struct tda18271_config hauppauge_hvr1210_tuner_config = { - .gate = TDA18271_GATE_DIGITAL, - .output_opt = TDA18271_OUTPUT_LT_OFF, -}; - -static struct tda18271_std_map hauppauge_hvr127x_std_map = { - .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x58 }, - .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x58 }, -}; - -static struct tda18271_config hauppauge_hvr127x_config = { - .std_map = &hauppauge_hvr127x_std_map, - .output_opt = TDA18271_OUTPUT_LT_OFF, -}; - -static struct lgdt3305_config hauppauge_lgdt3305_config = { - .i2c_addr = 0x0e, - .mpeg_mode = LGDT3305_MPEG_SERIAL, - .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, - .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, - .deny_i2c_rptr = 1, - .spectral_inversion = 1, - .qam_if_khz = 4000, - .vsb_if_khz = 3250, -}; - -static struct dibx000_agc_config xc3028_agc_config = { - BAND_VHF | BAND_UHF, /* band_caps */ - - /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, - * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, - * P_agc_nb_est=2, P_agc_write=0 - */ - (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | - (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */ - - 712, /* inv_gain */ - 21, /* time_stabiliz */ - - 0, /* alpha_level */ - 118, /* thlock */ - - 0, /* wbd_inv */ - 2867, /* wbd_ref */ - 0, /* wbd_sel */ - 2, /* wbd_alpha */ - - 0, /* agc1_max */ - 0, /* agc1_min */ - 39718, /* agc2_max */ - 9930, /* agc2_min */ - 0, /* agc1_pt1 */ - 0, /* agc1_pt2 */ - 0, /* agc1_pt3 */ - 0, /* agc1_slope1 */ - 0, /* agc1_slope2 */ - 0, /* agc2_pt1 */ - 128, /* agc2_pt2 */ - 29, /* agc2_slope1 */ - 29, /* agc2_slope2 */ - - 17, /* alpha_mant */ - 27, /* alpha_exp */ - 23, /* beta_mant */ - 51, /* beta_exp */ - - 1, /* perform_agc_softsplit */ -}; - -/* PLL Configuration for COFDM BW_MHz = 8.000000 - * With external clock = 30.000000 */ -static struct dibx000_bandwidth_config xc3028_bw_config = { - 60000, /* internal */ - 30000, /* sampling */ - 1, /* pll_cfg: prediv */ - 8, /* pll_cfg: ratio */ - 3, /* pll_cfg: range */ - 1, /* pll_cfg: reset */ - 0, /* pll_cfg: bypass */ - 0, /* misc: refdiv */ - 0, /* misc: bypclk_div */ - 1, /* misc: IO_CLK_en_core */ - 1, /* misc: ADClkSrc */ - 0, /* misc: modulo */ - (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ - (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ - 20452225, /* timf */ - 30000000 /* xtal_hz */ -}; - -static struct dib7000p_config hauppauge_hvr1400_dib7000_config = { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 0, - .update_lna = NULL, - - .agc_config_count = 1, - .agc = &xc3028_agc_config, - .bw = &xc3028_bw_config, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - .agc_control = NULL, - .spur_protect = 0, - - .output_mode = OUTMODE_MPEG2_SERIAL, -}; - -static struct zl10353_config dvico_fusionhdtv_xc3028 = { - .demod_address = 0x0f, - .if2 = 45600, - .no_tuner = 1, - .disable_i2c_gate_ctrl = 1, -}; - -static struct stv0900_reg stv0900_ts_regs[] = { - { R0900_TSGENERAL, 0x00 }, - { R0900_P1_TSSPEED, 0x40 }, - { R0900_P2_TSSPEED, 0x40 }, - { R0900_P1_TSCFGM, 0xc0 }, - { R0900_P2_TSCFGM, 0xc0 }, - { R0900_P1_TSCFGH, 0xe0 }, - { R0900_P2_TSCFGH, 0xe0 }, - { R0900_P1_TSCFGL, 0x20 }, - { R0900_P2_TSCFGL, 0x20 }, - { 0xffff, 0xff }, /* terminate */ -}; - -static struct stv0900_config netup_stv0900_config = { - .demod_address = 0x68, - .demod_mode = 1, /* dual */ - .xtal = 8000000, - .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ - .diseqc_mode = 2,/* 2/3 PWM */ - .ts_config_regs = stv0900_ts_regs, - .tun1_maddress = 0,/* 0x60 */ - .tun2_maddress = 3,/* 0x63 */ - .tun1_adc = 1,/* 1 Vpp */ - .tun2_adc = 1,/* 1 Vpp */ -}; - -static struct stv6110_config netup_stv6110_tunerconfig_a = { - .i2c_address = 0x60, - .mclk = 16000000, - .clk_div = 1, - .gain = 8, /* +16 dB - maximum gain */ -}; - -static struct stv6110_config netup_stv6110_tunerconfig_b = { - .i2c_address = 0x63, - .mclk = 16000000, - .clk_div = 1, - .gain = 8, /* +16 dB - maximum gain */ -}; - -static struct cx24116_config tbs_cx24116_config = { - .demod_address = 0x55, -}; - -static struct ds3000_config tevii_ds3000_config = { - .demod_address = 0x68, -}; - -static struct cx24116_config dvbworld_cx24116_config = { - .demod_address = 0x05, -}; - -static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = { - .prod = LGS8GXX_PROD_LGS8GL5, - .demod_address = 0x19, - .serial_ts = 0, - .ts_clk_pol = 1, - .ts_clk_gated = 1, - .if_clk_freq = 30400, /* 30.4 MHz */ - .if_freq = 5380, /* 5.38 MHz */ - .if_neg_center = 1, - .ext_adc = 0, - .adc_signed = 0, - .if_neg_edge = 0, -}; - -static struct xc5000_config mygica_x8506_xc5000_config = { - .i2c_address = 0x61, - .if_khz = 5380, -}; - -static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct cx23885_tsport *port = fe->dvb->priv; - struct cx23885_dev *dev = port->dev; - - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1275: - switch (param->u.vsb.modulation) { - case VSB_8: - cx23885_gpio_clear(dev, GPIO_5); - break; - case QAM_64: - case QAM_256: - default: - cx23885_gpio_set(dev, GPIO_5); - break; - } - break; - case CX23885_BOARD_MYGICA_X8506: - case CX23885_BOARD_MAGICPRO_PROHDTVE2: - /* Select Digital TV */ - cx23885_gpio_set(dev, GPIO_0); - break; - } - return 0; -} - -static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe, - unsigned int cmd, void *parg, - unsigned int stage) -{ - int err = 0; - - switch (stage) { - case DVB_FE_IOCTL_PRE: - - switch (cmd) { - case FE_SET_FRONTEND: - err = cx23885_dvb_set_frontend(fe, - (struct dvb_frontend_parameters *) parg); - break; - } - break; - - case DVB_FE_IOCTL_POST: - /* no post-ioctl handling required */ - break; - } - return err; -}; - - -static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { - .prod = LGS8GXX_PROD_LGS8G75, - .demod_address = 0x19, - .serial_ts = 0, - .ts_clk_pol = 1, - .ts_clk_gated = 1, - .if_clk_freq = 30400, /* 30.4 MHz */ - .if_freq = 6500, /* 6.50 MHz */ - .if_neg_center = 1, - .ext_adc = 0, - .adc_signed = 1, - .adc_vpp = 2, /* 1.6 Vpp */ - .if_neg_edge = 1, -}; - -static struct xc5000_config magicpro_prohdtve2_xc5000_config = { - .i2c_address = 0x61, - .if_khz = 6500, -}; - -static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = { - .prod = ATBM8830_PROD_8830, - .demod_address = 0x44, - .serial_ts = 0, - .ts_sampling_edge = 1, - .ts_clk_gated = 0, - .osc_clk_freq = 30400, /* in kHz */ - .if_freq = 0, /* zero IF */ - .zif_swap_iq = 1, - .agc_min = 0x2E, - .agc_max = 0xFF, - .agc_hold_loop = 0, -}; - -static struct max2165_config mygic_x8558pro_max2165_cfg1 = { - .i2c_address = 0x60, - .osc_clk = 20 -}; - -static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = { - .prod = ATBM8830_PROD_8830, - .demod_address = 0x44, - .serial_ts = 1, - .ts_sampling_edge = 1, - .ts_clk_gated = 0, - .osc_clk_freq = 30400, /* in kHz */ - .if_freq = 0, /* zero IF */ - .zif_swap_iq = 1, - .agc_min = 0x2E, - .agc_max = 0xFF, - .agc_hold_loop = 0, -}; - -static struct max2165_config mygic_x8558pro_max2165_cfg2 = { - .i2c_address = 0x60, - .osc_clk = 20 -}; -static struct stv0367_config netup_stv0367_config[] = { - { - .demod_address = 0x1c, - .xtal = 27000000, - .if_khz = 4500, - .if_iq_mode = 0, - .ts_mode = 1, - .clk_pol = 0, - }, { - .demod_address = 0x1d, - .xtal = 27000000, - .if_khz = 4500, - .if_iq_mode = 0, - .ts_mode = 1, - .clk_pol = 0, - }, -}; - -static struct xc5000_config netup_xc5000_config[] = { - { - .i2c_address = 0x61, - .if_khz = 4500, - }, { - .i2c_address = 0x64, - .if_khz = 4500, - }, -}; - -int netup_altera_fpga_rw(void *device, int flag, int data, int read) -{ - struct cx23885_dev *dev = (struct cx23885_dev *)device; - unsigned long timeout = jiffies + msecs_to_jiffies(1); - uint32_t mem = 0; - - mem = cx_read(MC417_RWD); - if (read) - cx_set(MC417_OEN, ALT_DATA); - else { - cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */ - mem &= ~ALT_DATA; - mem |= (data & ALT_DATA); - } - - if (flag) - mem |= ALT_AD_RG; - else - mem &= ~ALT_AD_RG; - - mem &= ~ALT_CS; - if (read) - mem = (mem & ~ALT_RD) | ALT_WR; - else - mem = (mem & ~ALT_WR) | ALT_RD; - - cx_write(MC417_RWD, mem); /* start RW cycle */ - - for (;;) { - mem = cx_read(MC417_RWD); - if ((mem & ALT_RDY) == 0) - break; - if (time_after(jiffies, timeout)) - break; - udelay(1); - } - - cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); - if (read) - return mem & ALT_DATA; - - return 0; -}; - -static int dvb_register(struct cx23885_tsport *port) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; - struct videobuf_dvb_frontend *fe0, *fe1 = NULL; - int mfe_shared = 0; /* bus not shared by default */ - int ret; - - /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); - if (!fe0) - return -EINVAL; - - /* init struct videobuf_dvb */ - fe0->dvb.name = dev->name; - - /* multi-frontend gate control is undefined or defaults to fe0 */ - port->frontends.gate = 0; - - /* Sets the gate control callback to be used by i2c command calls */ - port->gate_ctrl = cx23885_dvb_gate_ctrl; - - /* init frontend */ - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_generic_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_generic_tunerconfig, 0); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1270: - case CX23885_BOARD_HAUPPAUGE_HVR1275: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(lgdt3305_attach, - &hauppauge_lgdt3305_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_bus[1].i2c_adap, - &hauppauge_hvr127x_config); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1255: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(s5h1411_attach, - &hcw_s5h1411_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_bus[1].i2c_adap, - &hauppauge_tda18271_config); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - i2c_bus = &dev->i2c_bus[0]; - switch (alt_tuner) { - case 1: - fe0->dvb.frontend = - dvb_attach(s5h1409_attach, - &hauppauge_ezqam_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(tda829x_attach, fe0->dvb.frontend, - &dev->i2c_bus[1].i2c_adap, 0x42, - &tda829x_no_probe); - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_bus[1].i2c_adap, - &hauppauge_tda18271_config); - } - break; - case 0: - default: - fe0->dvb.frontend = - dvb_attach(s5h1409_attach, - &hauppauge_generic_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) - dvb_attach(mt2131_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_generic_tunerconfig, 0); - break; - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800lp_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_generic_tunerconfig, 0); - } - break; - case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(lgdt330x_attach, - &fusionhdtv_5_express, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, 0x61, - TUNER_LG_TDVS_H06XF); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - i2c_bus = &dev->i2c_bus[1]; - fe0->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1500q_config, - &dev->i2c_bus[0].i2c_adap); - if (fe0->dvb.frontend != NULL) - dvb_attach(xc5000_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_hvr1500q_tunerconfig); - break; - case CX23885_BOARD_HAUPPAUGE_HVR1500: - i2c_bus = &dev->i2c_bus[1]; - fe0->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1500_config, - &dev->i2c_bus[0].i2c_adap); - if (fe0->dvb.frontend != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &i2c_bus->i2c_adap, - .i2c_addr = 0x61, - }; - static struct xc2028_ctrl ctl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_OREN538, - }; - - fe = dvb_attach(xc2028_attach, - fe0->dvb.frontend, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctl); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1200: - case CX23885_BOARD_HAUPPAUGE_HVR1700: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(tda10048_attach, - &hauppauge_hvr1200_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(tda829x_attach, fe0->dvb.frontend, - &dev->i2c_bus[1].i2c_adap, 0x42, - &tda829x_no_probe); - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_bus[1].i2c_adap, - &hauppauge_hvr1200_tuner_config); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1210: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(tda10048_attach, - &hauppauge_hvr1210_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_bus[1].i2c_adap, - &hauppauge_hvr1210_tuner_config); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1400: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(dib7000p_attach, - &i2c_bus->i2c_adap, - 0x12, &hauppauge_hvr1400_dib7000_config); - if (fe0->dvb.frontend != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &dev->i2c_bus[1].i2c_adap, - .i2c_addr = 0x64, - }; - static struct xc2028_ctrl ctl = { - .fname = XC3028L_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = 5000, - /* This is true for all demods with - v36 firmware? */ - .type = XC2028_D2633, - }; - - fe = dvb_attach(xc2028_attach, - fe0->dvb.frontend, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctl); - } - break; - case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: - i2c_bus = &dev->i2c_bus[port->nr - 1]; - - fe0->dvb.frontend = dvb_attach(s5h1409_attach, - &dvico_s5h1409_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend == NULL) - fe0->dvb.frontend = dvb_attach(s5h1411_attach, - &dvico_s5h1411_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) - dvb_attach(xc5000_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &dvico_xc5000_tunerconfig); - break; - case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: { - i2c_bus = &dev->i2c_bus[port->nr - 1]; - - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &dvico_fusionhdtv_xc3028, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &i2c_bus->i2c_adap, - .i2c_addr = 0x61, - }; - static struct xc2028_ctrl ctl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - }; - - fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, - &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctl); - } - break; - } - case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: - case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: - case CX23885_BOARD_COMPRO_VIDEOMATE_E800: - i2c_bus = &dev->i2c_bus[0]; - - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &dvico_fusionhdtv_xc3028, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &dev->i2c_bus[1].i2c_adap, - .i2c_addr = 0x61, - }; - static struct xc2028_ctrl ctl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - }; - - fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, - &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctl); - } - break; - case CX23885_BOARD_TBS_6920: - i2c_bus = &dev->i2c_bus[1]; - - fe0->dvb.frontend = dvb_attach(cx24116_attach, - &tbs_cx24116_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) - fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; - - break; - case CX23885_BOARD_TEVII_S470: - i2c_bus = &dev->i2c_bus[1]; - - fe0->dvb.frontend = dvb_attach(ds3000_attach, - &tevii_ds3000_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) - fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; - - break; - case CX23885_BOARD_DVBWORLD_2005: - i2c_bus = &dev->i2c_bus[1]; - - fe0->dvb.frontend = dvb_attach(cx24116_attach, - &dvbworld_cx24116_config, - &i2c_bus->i2c_adap); - break; - case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: - i2c_bus = &dev->i2c_bus[0]; - switch (port->nr) { - /* port B */ - case 1: - fe0->dvb.frontend = dvb_attach(stv0900_attach, - &netup_stv0900_config, - &i2c_bus->i2c_adap, 0); - if (fe0->dvb.frontend != NULL) { - if (dvb_attach(stv6110_attach, - fe0->dvb.frontend, - &netup_stv6110_tunerconfig_a, - &i2c_bus->i2c_adap)) { - if (!dvb_attach(lnbh24_attach, - fe0->dvb.frontend, - &i2c_bus->i2c_adap, - LNBH24_PCL | LNBH24_TTX, - LNBH24_TEN, 0x09)) - printk(KERN_ERR - "No LNBH24 found!\n"); - - } - } - break; - /* port C */ - case 2: - fe0->dvb.frontend = dvb_attach(stv0900_attach, - &netup_stv0900_config, - &i2c_bus->i2c_adap, 1); - if (fe0->dvb.frontend != NULL) { - if (dvb_attach(stv6110_attach, - fe0->dvb.frontend, - &netup_stv6110_tunerconfig_b, - &i2c_bus->i2c_adap)) { - if (!dvb_attach(lnbh24_attach, - fe0->dvb.frontend, - &i2c_bus->i2c_adap, - LNBH24_PCL | LNBH24_TTX, - LNBH24_TEN, 0x0a)) - printk(KERN_ERR - "No LNBH24 found!\n"); - - } - } - break; - } - break; - case CX23885_BOARD_MYGICA_X8506: - i2c_bus = &dev->i2c_bus[0]; - i2c_bus2 = &dev->i2c_bus[1]; - fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, - &mygica_x8506_lgs8gl5_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(xc5000_attach, - fe0->dvb.frontend, - &i2c_bus2->i2c_adap, - &mygica_x8506_xc5000_config); - } - break; - case CX23885_BOARD_MAGICPRO_PROHDTVE2: - i2c_bus = &dev->i2c_bus[0]; - i2c_bus2 = &dev->i2c_bus[1]; - fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, - &magicpro_prohdtve2_lgs8g75_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(xc5000_attach, - fe0->dvb.frontend, - &i2c_bus2->i2c_adap, - &magicpro_prohdtve2_xc5000_config); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(s5h1411_attach, - &hcw_s5h1411_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_bus[0].i2c_adap, - &hauppauge_tda18271_config); - break; - case CX23885_BOARD_MYGICA_X8558PRO: - switch (port->nr) { - /* port B */ - case 1: - i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(atbm8830_attach, - &mygica_x8558pro_atbm8830_cfg1, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(max2165_attach, - fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &mygic_x8558pro_max2165_cfg1); - } - break; - /* port C */ - case 2: - i2c_bus = &dev->i2c_bus[1]; - fe0->dvb.frontend = dvb_attach(atbm8830_attach, - &mygica_x8558pro_atbm8830_cfg2, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(max2165_attach, - fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &mygic_x8558pro_max2165_cfg2); - } - break; - } - break; - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: - i2c_bus = &dev->i2c_bus[0]; - mfe_shared = 1;/* MFE */ - port->frontends.gate = 0;/* not clear for me yet */ - /* ports B, C */ - /* MFE frontend 1 DVB-T */ - fe0->dvb.frontend = dvb_attach(stv0367ter_attach, - &netup_stv0367_config[port->nr - 1], - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (NULL == dvb_attach(xc5000_attach, - fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &netup_xc5000_config[port->nr - 1])) - goto frontend_detach; - /* load xc5000 firmware */ - fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend); - } - /* MFE frontend 2 */ - fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); - if (fe1 == NULL) - goto frontend_detach; - /* DVB-C init */ - fe1->dvb.frontend = dvb_attach(stv0367cab_attach, - &netup_stv0367_config[port->nr - 1], - &i2c_bus->i2c_adap); - if (fe1->dvb.frontend != NULL) { - fe1->dvb.frontend->id = 1; - if (NULL == dvb_attach(xc5000_attach, - fe1->dvb.frontend, - &i2c_bus->i2c_adap, - &netup_xc5000_config[port->nr - 1])) - goto frontend_detach; - } - break; - default: - printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " - " isn't supported yet\n", - dev->name); - break; - } - - if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) { - printk(KERN_ERR "%s: frontend initialization failed\n", - dev->name); - goto frontend_detach; - } - - /* define general-purpose callback pointer */ - fe0->dvb.frontend->callback = cx23885_tuner_callback; - if (fe1) - fe1->dvb.frontend->callback = cx23885_tuner_callback; -#if 0 - /* Ensure all frontends negotiate bus access */ - fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; - if (fe1) - fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; -#endif - - /* Put the analog decoder in standby to keep it quiet */ - call_all(dev, core, s_power, 0); - - if (fe0->dvb.frontend->ops.analog_ops.standby) - fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); - - /* register everything */ - ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, - &dev->pci->dev, adapter_nr, mfe_shared, - cx23885_dvb_fe_ioctl_override); - if (ret) - goto frontend_detach; - - /* init CI & MAC */ - switch (dev->board) { - case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: { - static struct netup_card_info cinfo; - - netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); - memcpy(port->frontends.adapter.proposed_mac, - cinfo.port[port->nr - 1].mac, 6); - printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", - port->nr, port->frontends.adapter.proposed_mac); - - netup_ci_init(port); - break; - } - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { - struct altera_ci_config netup_ci_cfg = { - .dev = dev,/* magic number to identify*/ - .adapter = &port->frontends.adapter,/* for CI */ - .demux = &fe0->dvb.demux,/* for hw pid filter */ - .fpga_rw = netup_altera_fpga_rw, - }; - - altera_ci_init(&netup_ci_cfg, port->nr); - break; - } - case CX23885_BOARD_TEVII_S470: { - u8 eeprom[256]; /* 24C02 i2c eeprom */ - - if (port->nr != 1) - break; - - /* Read entire EEPROM */ - dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); - printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0); - memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); - break; - } - } - - return ret; - -frontend_detach: - port->gate_ctrl = NULL; - videobuf_dvb_dealloc_frontends(&port->frontends); - return -EINVAL; -} - -int cx23885_dvb_register(struct cx23885_tsport *port) -{ - - struct videobuf_dvb_frontend *fe0; - struct cx23885_dev *dev = port->dev; - int err, i; - - /* Here we need to allocate the correct number of frontends, - * as reflected in the cards struct. The reality is that currently - * no cx23885 boards support this - yet. But, if we don't modify this - * code then the second frontend would never be allocated (later) - * and fail with error before the attach in dvb_register(). - * Without these changes we risk an OOPS later. The changes here - * are for safety, and should provide a good foundation for the - * future addition of any multi-frontend cx23885 based boards. - */ - printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, - port->num_frontends); - - for (i = 1; i <= port->num_frontends; i++) { - if (videobuf_dvb_alloc_frontend( - &port->frontends, i) == NULL) { - printk(KERN_ERR "%s() failed to alloc\n", __func__); - return -ENOMEM; - } - - fe0 = videobuf_dvb_get_frontend(&port->frontends, i); - if (!fe0) - err = -EINVAL; - - dprintk(1, "%s\n", __func__); - dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n", - dev->board, - dev->name, - dev->pci_bus, - dev->pci_slot); - - err = -ENODEV; - - /* dvb stuff */ - /* We have to init the queue for each frontend on a port. */ - printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, - &dev->pci->dev, &port->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, - sizeof(struct cx23885_buffer), port, NULL); - } - err = dvb_register(port); - if (err != 0) - printk(KERN_ERR "%s() dvb_register failed err = %d\n", - __func__, err); - - return err; -} - -int cx23885_dvb_unregister(struct cx23885_tsport *port) -{ - struct videobuf_dvb_frontend *fe0; - - /* FIXME: in an error condition where the we have - * an expected number of frontends (attach problem) - * then this might not clean up correctly, if 1 - * is invalid. - * This comment only applies to future boards IF they - * implement MFE support. - */ - fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); - if (fe0->dvb.frontend) - videobuf_dvb_unregister_bus(&port->frontends); - - switch (port->dev->board) { - case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: - netup_ci_exit(port); - break; - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: - altera_ci_release(port->dev, port->nr); - break; - } - - port->gate_ctrl = NULL; - - return 0; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-f300.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-f300.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-f300.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-f300.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,177 +0,0 @@ -/* - * Driver for Silicon Labs C8051F300 microcontroller. - * - * It is used for LNB power control in TeVii S470, - * TBS 6920 PCIe DVB-S2 cards. - * - * Microcontroller connected to cx23885 GPIO pins: - * GPIO0 - data - P0.3 F300 - * GPIO1 - reset - P0.2 F300 - * GPIO2 - clk - P0.1 F300 - * GPIO3 - busy - P0.0 F300 - * - * Copyright (C) 2009 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx23885.h" - -#define F300_DATA GPIO_0 -#define F300_RESET GPIO_1 -#define F300_CLK GPIO_2 -#define F300_BUSY GPIO_3 - -static void f300_set_line(struct cx23885_dev *dev, u32 line, u8 lvl) -{ - cx23885_gpio_enable(dev, line, 1); - if (lvl == 1) - cx23885_gpio_set(dev, line); - else - cx23885_gpio_clear(dev, line); -} - -static u8 f300_get_line(struct cx23885_dev *dev, u32 line) -{ - cx23885_gpio_enable(dev, line, 0); - - return cx23885_gpio_get(dev, line); -} - -static void f300_send_byte(struct cx23885_dev *dev, u8 dta) -{ - u8 i; - - for (i = 0; i < 8; i++) { - f300_set_line(dev, F300_CLK, 0); - udelay(30); - f300_set_line(dev, F300_DATA, (dta & 0x80) >> 7);/* msb first */ - udelay(30); - dta <<= 1; - f300_set_line(dev, F300_CLK, 1); - udelay(30); - } -} - -static u8 f300_get_byte(struct cx23885_dev *dev) -{ - u8 i, dta = 0; - - for (i = 0; i < 8; i++) { - f300_set_line(dev, F300_CLK, 0); - udelay(30); - dta <<= 1; - f300_set_line(dev, F300_CLK, 1); - udelay(30); - dta |= f300_get_line(dev, F300_DATA);/* msb first */ - - } - - return dta; -} - -static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf) -{ - struct cx23885_tsport *port = fe->dvb->priv; - struct cx23885_dev *dev = port->dev; - u8 i, temp, ret = 0; - - temp = buf[0]; - for (i = 0; i < buf[0]; i++) - temp += buf[i + 1]; - temp = (~temp + 1);/* get check sum */ - buf[1 + buf[0]] = temp; - - f300_set_line(dev, F300_RESET, 1); - f300_set_line(dev, F300_CLK, 1); - udelay(30); - f300_set_line(dev, F300_DATA, 1); - msleep(1); - - /* question: */ - f300_set_line(dev, F300_RESET, 0);/* begin to send data */ - msleep(1); - - f300_send_byte(dev, 0xe0);/* the slave address is 0xe0, write */ - msleep(1); - - temp = buf[0]; - temp += 2; - for (i = 0; i < temp; i++) - f300_send_byte(dev, buf[i]); - - f300_set_line(dev, F300_RESET, 1);/* sent data over */ - f300_set_line(dev, F300_DATA, 1); - - /* answer: */ - temp = 0; - for (i = 0; ((i < 8) & (temp == 0)); i++) { - msleep(1); - if (f300_get_line(dev, F300_BUSY) == 0) - temp = 1; - } - - if (i > 7) { - printk(KERN_ERR "%s: timeout, the slave no response\n", - __func__); - ret = 1; /* timeout, the slave no response */ - } else { /* the slave not busy, prepare for getting data */ - f300_set_line(dev, F300_RESET, 0);/*ready...*/ - msleep(1); - f300_send_byte(dev, 0xe1);/* 0xe1 is Read */ - msleep(1); - temp = f300_get_byte(dev);/*get the data length */ - if (temp > 14) - temp = 14; - - for (i = 0; i < (temp + 1); i++) - f300_get_byte(dev);/* get data to empty buffer */ - - f300_set_line(dev, F300_RESET, 1);/* received data over */ - f300_set_line(dev, F300_DATA, 1); - } - - return ret; -} - -int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - u8 buf[16]; - - buf[0] = 0x05; - buf[1] = 0x38;/* write port */ - buf[2] = 0x01;/* A port, lnb power */ - - switch (voltage) { - case SEC_VOLTAGE_13: - buf[3] = 0x01;/* power on */ - buf[4] = 0x02;/* B port, H/V */ - buf[5] = 0x00;/*13V v*/ - break; - case SEC_VOLTAGE_18: - buf[3] = 0x01; - buf[4] = 0x02; - buf[5] = 0x01;/* 18V h*/ - break; - case SEC_VOLTAGE_OFF: - buf[3] = 0x00;/* power off */ - buf[4] = 0x00; - buf[5] = 0x00; - break; - } - - return f300_xfer(fe, buf); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-f300.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-f300.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-f300.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-f300.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -extern int f300_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,583 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2006 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "btcx-risc.h" -#include "cx23885-reg.h" -#include "media/cx2341x.h" - -#include -#include - -#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 2) - -#define UNSET (-1U) - -#define CX23885_MAXBOARDS 8 - -/* Max number of inputs by card */ -#define MAX_CX23885_INPUT 8 -#define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 - -#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ - -#define CX23885_BOARD_NOAUTO UNSET -#define CX23885_BOARD_UNKNOWN 0 -#define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 -#define CX23885_BOARD_HAUPPAUGE_HVR1800 2 -#define CX23885_BOARD_HAUPPAUGE_HVR1250 3 -#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 -#define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 -#define CX23885_BOARD_HAUPPAUGE_HVR1500 6 -#define CX23885_BOARD_HAUPPAUGE_HVR1200 7 -#define CX23885_BOARD_HAUPPAUGE_HVR1700 8 -#define CX23885_BOARD_HAUPPAUGE_HVR1400 9 -#define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10 -#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11 -#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12 -#define CX23885_BOARD_COMPRO_VIDEOMATE_E650F 13 -#define CX23885_BOARD_TBS_6920 14 -#define CX23885_BOARD_TEVII_S470 15 -#define CX23885_BOARD_DVBWORLD_2005 16 -#define CX23885_BOARD_NETUP_DUAL_DVBS2_CI 17 -#define CX23885_BOARD_HAUPPAUGE_HVR1270 18 -#define CX23885_BOARD_HAUPPAUGE_HVR1275 19 -#define CX23885_BOARD_HAUPPAUGE_HVR1255 20 -#define CX23885_BOARD_HAUPPAUGE_HVR1210 21 -#define CX23885_BOARD_MYGICA_X8506 22 -#define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 -#define CX23885_BOARD_HAUPPAUGE_HVR1850 24 -#define CX23885_BOARD_COMPRO_VIDEOMATE_E800 25 -#define CX23885_BOARD_HAUPPAUGE_HVR1290 26 -#define CX23885_BOARD_MYGICA_X8558PRO 27 -#define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28 -#define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29 -#define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 - -#define GPIO_0 0x00000001 -#define GPIO_1 0x00000002 -#define GPIO_2 0x00000004 -#define GPIO_3 0x00000008 -#define GPIO_4 0x00000010 -#define GPIO_5 0x00000020 -#define GPIO_6 0x00000040 -#define GPIO_7 0x00000080 -#define GPIO_8 0x00000100 -#define GPIO_9 0x00000200 -#define GPIO_10 0x00000400 -#define GPIO_11 0x00000800 -#define GPIO_12 0x00001000 -#define GPIO_13 0x00002000 -#define GPIO_14 0x00004000 -#define GPIO_15 0x00008000 - -/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ -#define CX23885_NORMS (\ - V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \ - V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ - V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ - V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) - -struct cx23885_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int flags; - u32 cxformat; -}; - -struct cx23885_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 mask; - u32 shift; -}; - -struct cx23885_tvnorm { - char *name; - v4l2_std_id id; - u32 cxiformat; - u32 cxoformat; -}; - -struct cx23885_fh { - struct cx23885_dev *dev; - enum v4l2_buf_type type; - int radio; - u32 resources; - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - - /* video capture */ - struct cx23885_fmt *fmt; - unsigned int width, height; - - /* vbi capture */ - struct videobuf_queue vidq; - struct videobuf_queue vbiq; - - /* MPEG Encoder specifics ONLY */ - struct videobuf_queue mpegq; - atomic_t v4l_reading; -}; - -enum cx23885_itype { - CX23885_VMUX_COMPOSITE1 = 1, - CX23885_VMUX_COMPOSITE2, - CX23885_VMUX_COMPOSITE3, - CX23885_VMUX_COMPOSITE4, - CX23885_VMUX_SVIDEO, - CX23885_VMUX_COMPONENT, - CX23885_VMUX_TELEVISION, - CX23885_VMUX_CABLE, - CX23885_VMUX_DVB, - CX23885_VMUX_DEBUG, - CX23885_RADIO, -}; - -enum cx23885_src_sel_type { - CX23885_SRC_SEL_EXT_656_VIDEO = 0, - CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO -}; - -/* buffer for one video frame */ -struct cx23885_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* cx23885 specific */ - unsigned int bpl; - struct btcx_riscmem risc; - struct cx23885_fmt *fmt; - u32 count; -}; - -struct cx23885_input { - enum cx23885_itype type; - unsigned int vmux; - u32 gpio0, gpio1, gpio2, gpio3; -}; - -typedef enum { - CX23885_MPEG_UNDEFINED = 0, - CX23885_MPEG_DVB, - CX23885_ANALOG_VIDEO, - CX23885_MPEG_ENCODER, -} port_t; - -struct cx23885_board { - char *name; - port_t porta, portb, portc; - int num_fds_portb, num_fds_portc; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - unsigned int tuner_bus; - - /* Vendors can and do run the PCIe bridge at different - * clock rates, driven physically by crystals on the PCBs. - * The core has to accomodate this. This allows the user - * to add new boards with new frequencys. The value is - * expressed in Hz. - * - * The core framework will default this value based on - * current designs, but it can vary. - */ - u32 clk_freq; - struct cx23885_input input[MAX_CX23885_INPUT]; - int ci_type; /* for NetUP */ -}; - -struct cx23885_subid { - u16 subvendor; - u16 subdevice; - u32 card; -}; - -struct cx23885_i2c { - struct cx23885_dev *dev; - - int nr; - - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - u32 i2c_rc; - - /* 885 registers used for raw addess */ - u32 i2c_period; - u32 reg_ctrl; - u32 reg_stat; - u32 reg_addr; - u32 reg_rdata; - u32 reg_wdata; -}; - -struct cx23885_dmaqueue { - struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; - u32 count; -}; - -struct cx23885_tsport { - struct cx23885_dev *dev; - - int nr; - int sram_chno; - - struct videobuf_dvb_frontends frontends; - - /* dma queues */ - struct cx23885_dmaqueue mpegq; - u32 ts_packet_size; - u32 ts_packet_count; - - int width; - int height; - - spinlock_t slock; - - /* registers */ - u32 reg_gpcnt; - u32 reg_gpcnt_ctl; - u32 reg_dma_ctl; - u32 reg_lngth; - u32 reg_hw_sop_ctrl; - u32 reg_gen_ctrl; - u32 reg_bd_pkt_status; - u32 reg_sop_status; - u32 reg_fifo_ovfl_stat; - u32 reg_vld_misc; - u32 reg_ts_clk_en; - u32 reg_ts_int_msk; - u32 reg_ts_int_stat; - u32 reg_src_sel; - - /* Default register vals */ - int pci_irqmask; - u32 dma_ctl_val; - u32 ts_int_msk_val; - u32 gen_ctrl_val; - u32 ts_clk_en_val; - u32 src_sel_val; - u32 vld_misc_val; - u32 hw_sop_ctrl_val; - - /* Allow a single tsport to have multiple frontends */ - u32 num_frontends; - void (*gate_ctrl)(struct cx23885_tsport *port, int open); - void *port_priv; -}; - -struct cx23885_kernel_ir { - struct cx23885_dev *cx; - char *name; - char *phys; - - struct rc_dev *rc; -}; - -struct cx23885_dev { - atomic_t refcount; - struct v4l2_device v4l2_dev; - - /* pci stuff */ - struct pci_dev *pci; - unsigned char pci_rev, pci_lat; - int pci_bus, pci_slot; - u32 __iomem *lmmio; - u8 __iomem *bmmio; - int pci_irqmask; - spinlock_t pci_irqmask_lock; /* protects mask reg too */ - int hwrevision; - - /* This valud is board specific and is used to configure the - * AV core so we see nice clean and stable video and audio. */ - u32 clk_freq; - - /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ - struct cx23885_i2c i2c_bus[3]; - - int nr; - struct mutex lock; - struct mutex gpio_lock; - - /* board details */ - unsigned int board; - char name[32]; - - struct cx23885_tsport ts1, ts2; - - /* sram configuration */ - struct sram_channel *sram_channels; - - enum { - CX23885_BRIDGE_UNDEFINED = 0, - CX23885_BRIDGE_885 = 885, - CX23885_BRIDGE_887 = 887, - CX23885_BRIDGE_888 = 888, - } bridge; - - /* Analog video */ - u32 resources; - unsigned int input; - u32 tvaudio; - v4l2_std_id tvnorm; - unsigned int tuner_type; - unsigned char tuner_addr; - unsigned int tuner_bus; - unsigned int radio_type; - unsigned char radio_addr; - unsigned int has_radio; - struct v4l2_subdev *sd_cx25840; - struct work_struct cx25840_work; - - /* Infrared */ - struct v4l2_subdev *sd_ir; - struct work_struct ir_rx_work; - unsigned long ir_rx_notifications; - struct work_struct ir_tx_work; - unsigned long ir_tx_notifications; - - struct cx23885_kernel_ir *kernel_ir; - atomic_t ir_input_stopping; - - /* V4l */ - u32 freq; - struct video_device *video_dev; - struct video_device *vbi_dev; - struct video_device *radio_dev; - - struct cx23885_dmaqueue vidq; - struct cx23885_dmaqueue vbiq; - spinlock_t slock; - - /* MPEG Encoder ONLY settings */ - u32 cx23417_mailbox; - struct cx2341x_mpeg_params mpeg_params; - struct video_device *v4l_device; - atomic_t v4l_reader_count; - struct cx23885_tvnorm encodernorm; - -}; - -static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct cx23885_dev, v4l2_dev); -} - -#define call_all(dev, o, f, args...) \ - v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) - -#define CX23885_HW_888_IR (1 << 0) -#define CX23885_HW_AV_CORE (1 << 1) - -#define call_hw(dev, grpid, o, f, args...) \ - v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args) - -extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw); - -#define SRAM_CH01 0 /* Video A */ -#define SRAM_CH02 1 /* VBI A */ -#define SRAM_CH03 2 /* Video B */ -#define SRAM_CH04 3 /* Transport via B */ -#define SRAM_CH05 4 /* VBI B */ -#define SRAM_CH06 5 /* Video C */ -#define SRAM_CH07 6 /* Transport via C */ -#define SRAM_CH08 7 /* Audio Internal A */ -#define SRAM_CH09 8 /* Audio Internal B */ -#define SRAM_CH10 9 /* Audio External */ -#define SRAM_CH11 10 /* COMB_3D_N */ -#define SRAM_CH12 11 /* Comb 3D N1 */ -#define SRAM_CH13 12 /* Comb 3D N2 */ -#define SRAM_CH14 13 /* MOE Vid */ -#define SRAM_CH15 14 /* MOE RSLT */ - -struct sram_channel { - char *name; - u32 cmds_start; - u32 ctrl_start; - u32 cdt; - u32 fifo_start; - u32 fifo_size; - u32 ptr1_reg; - u32 ptr2_reg; - u32 cnt1_reg; - u32 cnt2_reg; - u32 jumponly; -}; - -/* ----------------------------------------------------------- */ - -#define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) -#define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) - -#define cx_andor(reg, mask, value) \ - writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ - ((value) & (mask)), dev->lmmio+((reg)>>2)) - -#define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) -#define cx_clear(reg, bit) cx_andor((reg), (bit), 0) - -/* ----------------------------------------------------------- */ -/* cx23885-core.c */ - -extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc); - -extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch); - -extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); - -extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int top_offset, unsigned int bottom_offset, - unsigned int bpl, unsigned int padding, unsigned int lines); - -void cx23885_cancel_buffers(struct cx23885_tsport *port); - -extern int cx23885_restart_queue(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q); - -extern void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count); - -extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); -extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); -extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask); -extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, - int asoutput); - -extern void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask); -extern void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask); -extern void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask); -extern void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask); - -/* ----------------------------------------------------------- */ -/* cx23885-cards.c */ -extern struct cx23885_board cx23885_boards[]; -extern const unsigned int cx23885_bcount; - -extern struct cx23885_subid cx23885_subids[]; -extern const unsigned int cx23885_idcount; - -extern int cx23885_tuner_callback(void *priv, int component, - int command, int arg); -extern void cx23885_card_list(struct cx23885_dev *dev); -extern int cx23885_ir_init(struct cx23885_dev *dev); -extern void cx23885_ir_pci_int_enable(struct cx23885_dev *dev); -extern void cx23885_ir_fini(struct cx23885_dev *dev); -extern void cx23885_gpio_setup(struct cx23885_dev *dev); -extern void cx23885_card_setup(struct cx23885_dev *dev); -extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); - -extern int cx23885_dvb_register(struct cx23885_tsport *port); -extern int cx23885_dvb_unregister(struct cx23885_tsport *port); - -extern int cx23885_buf_prepare(struct videobuf_queue *q, - struct cx23885_tsport *port, - struct cx23885_buffer *buf, - enum v4l2_field field); -extern void cx23885_buf_queue(struct cx23885_tsport *port, - struct cx23885_buffer *buf); -extern void cx23885_free_buffer(struct videobuf_queue *q, - struct cx23885_buffer *buf); - -/* ----------------------------------------------------------- */ -/* cx23885-video.c */ -/* Video */ -extern int cx23885_video_register(struct cx23885_dev *dev); -extern void cx23885_video_unregister(struct cx23885_dev *dev); -extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); - -/* ----------------------------------------------------------- */ -/* cx23885-vbi.c */ -extern int cx23885_vbi_fmt(struct file *file, void *priv, - struct v4l2_format *f); -extern void cx23885_vbi_timeout(unsigned long data); -extern struct videobuf_queue_ops cx23885_vbi_qops; - -/* cx23885-i2c.c */ -extern int cx23885_i2c_register(struct cx23885_i2c *bus); -extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); -extern void cx23885_av_clk(struct cx23885_dev *dev, int enable); - -/* ----------------------------------------------------------- */ -/* cx23885-417.c */ -extern int cx23885_417_register(struct cx23885_dev *dev); -extern void cx23885_417_unregister(struct cx23885_dev *dev); -extern int cx23885_irq_417(struct cx23885_dev *dev, u32 status); -extern void cx23885_417_check_encoder(struct cx23885_dev *dev); -extern void cx23885_mc417_init(struct cx23885_dev *dev); -extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value); -extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value); -extern int mc417_register_read(struct cx23885_dev *dev, - u16 address, u32 *value); -extern int mc417_register_write(struct cx23885_dev *dev, - u16 address, u32 value); -extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask); -extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask); -extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput); - - -/* ----------------------------------------------------------- */ -/* tv norms */ - -static inline unsigned int norm_maxw(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; -} - -static inline unsigned int norm_maxh(v4l2_std_id norm) -{ - return (norm & V4L2_STD_625_50) ? 576 : 480; -} - -static inline unsigned int norm_swidth(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,401 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2006 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "cx23885.h" - -#include - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -static unsigned int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); - -#define dprintk(level, fmt, arg...)\ - do { if (i2c_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) - -#define I2C_WAIT_DELAY 32 -#define I2C_WAIT_RETRY 64 - -#define I2C_EXTEND (1 << 3) -#define I2C_NOSTOP (1 << 4) - -static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) -{ - struct cx23885_i2c *bus = i2c_adap->algo_data; - struct cx23885_dev *dev = bus->dev; - return cx_read(bus->reg_stat) & 0x01; -} - -static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) -{ - struct cx23885_i2c *bus = i2c_adap->algo_data; - struct cx23885_dev *dev = bus->dev; - return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; -} - -static int i2c_wait_done(struct i2c_adapter *i2c_adap) -{ - int count; - - for (count = 0; count < I2C_WAIT_RETRY; count++) { - if (!i2c_is_busy(i2c_adap)) - break; - udelay(I2C_WAIT_DELAY); - } - - if (I2C_WAIT_RETRY == count) - return 0; - - return 1; -} - -static int i2c_sendbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int joined_rlen) -{ - struct cx23885_i2c *bus = i2c_adap->algo_data; - struct cx23885_dev *dev = bus->dev; - u32 wdata, addr, ctrl; - int retval, cnt; - - if (joined_rlen) - dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__, - msg->len, joined_rlen); - else - dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len); - - /* Deal with i2c probe functions with zero payload */ - if (msg->len == 0) { - cx_write(bus->reg_addr, msg->addr << 25); - cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); - if (!i2c_wait_done(i2c_adap)) - return -EIO; - if (!i2c_slave_did_ack(i2c_adap)) - return -ENXIO; - - dprintk(1, "%s() returns 0\n", __func__); - return 0; - } - - - /* dev, reg + first byte */ - addr = (msg->addr << 25) | msg->buf[0]; - wdata = msg->buf[0]; - ctrl = bus->i2c_period | (1 << 12) | (1 << 2); - - if (msg->len > 1) - ctrl |= I2C_NOSTOP | I2C_EXTEND; - else if (joined_rlen) - ctrl |= I2C_NOSTOP; - - cx_write(bus->reg_addr, addr); - cx_write(bus->reg_wdata, wdata); - cx_write(bus->reg_ctrl, ctrl); - - if (!i2c_wait_done(i2c_adap)) - goto eio; - if (i2c_debug) { - printk(" addr << 1, msg->buf[0]); - if (!(ctrl & I2C_NOSTOP)) - printk(" >\n"); - } - - for (cnt = 1; cnt < msg->len; cnt++) { - /* following bytes */ - wdata = msg->buf[cnt]; - ctrl = bus->i2c_period | (1 << 12) | (1 << 2); - - if (cnt < msg->len - 1) - ctrl |= I2C_NOSTOP | I2C_EXTEND; - else if (joined_rlen) - ctrl |= I2C_NOSTOP; - - cx_write(bus->reg_addr, addr); - cx_write(bus->reg_wdata, wdata); - cx_write(bus->reg_ctrl, ctrl); - - if (!i2c_wait_done(i2c_adap)) - goto eio; - if (i2c_debug) { - dprintk(1, " %02x", msg->buf[cnt]); - if (!(ctrl & I2C_NOSTOP)) - dprintk(1, " >\n"); - } - } - return msg->len; - - eio: - retval = -EIO; - if (i2c_debug) - printk(KERN_ERR " ERR: %d\n", retval); - return retval; -} - -static int i2c_readbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int joined) -{ - struct cx23885_i2c *bus = i2c_adap->algo_data; - struct cx23885_dev *dev = bus->dev; - u32 ctrl, cnt; - int retval; - - - if (i2c_debug && !joined) - dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len); - - /* Deal with i2c probe functions with zero payload */ - if (msg->len == 0) { - cx_write(bus->reg_addr, msg->addr << 25); - cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); - if (!i2c_wait_done(i2c_adap)) - return -EIO; - if (!i2c_slave_did_ack(i2c_adap)) - return -ENXIO; - - - dprintk(1, "%s() returns 0\n", __func__); - return 0; - } - - if (i2c_debug) { - if (joined) - dprintk(1, " R"); - else - dprintk(1, " addr << 1) + 1); - } - - for (cnt = 0; cnt < msg->len; cnt++) { - - ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; - - if (cnt < msg->len - 1) - ctrl |= I2C_NOSTOP | I2C_EXTEND; - - cx_write(bus->reg_addr, msg->addr << 25); - cx_write(bus->reg_ctrl, ctrl); - - if (!i2c_wait_done(i2c_adap)) - goto eio; - msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; - if (i2c_debug) { - dprintk(1, " %02x", msg->buf[cnt]); - if (!(ctrl & I2C_NOSTOP)) - dprintk(1, " >\n"); - } - } - return msg->len; - - eio: - retval = -EIO; - if (i2c_debug) - printk(KERN_ERR " ERR: %d\n", retval); - return retval; -} - -static int i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, int num) -{ - struct cx23885_i2c *bus = i2c_adap->algo_data; - struct cx23885_dev *dev = bus->dev; - int i, retval = 0; - - dprintk(1, "%s(num = %d)\n", __func__, num); - - for (i = 0 ; i < num; i++) { - dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n", - __func__, num, msgs[i].addr, msgs[i].len); - if (msgs[i].flags & I2C_M_RD) { - /* read */ - retval = i2c_readbytes(i2c_adap, &msgs[i], 0); - } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && - msgs[i].addr == msgs[i + 1].addr) { - /* write then read from same address */ - retval = i2c_sendbytes(i2c_adap, &msgs[i], - msgs[i + 1].len); - if (retval < 0) - goto err; - i++; - retval = i2c_readbytes(i2c_adap, &msgs[i], 1); - } else { - /* write */ - retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); - } - if (retval < 0) - goto err; - } - return num; - - err: - return retval; -} - -static u32 cx23885_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; -} - -static struct i2c_algorithm cx23885_i2c_algo_template = { - .master_xfer = i2c_xfer, - .functionality = cx23885_functionality, -}; - -/* ----------------------------------------------------------------------- */ - -static struct i2c_adapter cx23885_i2c_adap_template = { - .name = "cx23885", - .owner = THIS_MODULE, - .algo = &cx23885_i2c_algo_template, -}; - -static struct i2c_client cx23885_i2c_client_template = { - .name = "cx23885 internal", -}; - -static char *i2c_devs[128] = { - [0x10 >> 1] = "tda10048", - [0x12 >> 1] = "dib7000pc", - [0x1c >> 1] = "lgdt3303", - [0x86 >> 1] = "tda9887", - [0x32 >> 1] = "cx24227", - [0x88 >> 1] = "cx25837", - [0x84 >> 1] = "tda8295", - [0xa0 >> 1] = "eeprom", - [0xc0 >> 1] = "tuner/mt2131/tda8275", - [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028", - [0xc8 >> 1] = "tuner/xc3028L", -}; - -static void do_i2c_scan(char *name, struct i2c_client *c) -{ - unsigned char buf; - int i, rc; - - for (i = 0; i < 128; i++) { - c->addr = i; - rc = i2c_master_recv(c, &buf, 0); - if (rc < 0) - continue; - printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); - } -} - -/* init + register i2c algo-bit adapter */ -int cx23885_i2c_register(struct cx23885_i2c *bus) -{ - struct cx23885_dev *dev = bus->dev; - - dprintk(1, "%s(bus = %d)\n", __func__, bus->nr); - - memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, - sizeof(bus->i2c_adap)); - memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, - sizeof(bus->i2c_algo)); - memcpy(&bus->i2c_client, &cx23885_i2c_client_template, - sizeof(bus->i2c_client)); - - bus->i2c_adap.dev.parent = &dev->pci->dev; - - strlcpy(bus->i2c_adap.name, bus->dev->name, - sizeof(bus->i2c_adap.name)); - - bus->i2c_algo.data = bus; - bus->i2c_adap.algo_data = bus; - i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); - i2c_add_adapter(&bus->i2c_adap); - - bus->i2c_client.adapter = &bus->i2c_adap; - - if (0 == bus->i2c_rc) { - dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr); - if (i2c_scan) { - printk(KERN_INFO "%s: scan bus %d:\n", - dev->name, bus->nr); - do_i2c_scan(dev->name, &bus->i2c_client); - } - } else - printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", - dev->name, bus->nr); - - /* Instantiate the IR receiver device, if present */ - if (0 == bus->i2c_rc) { - struct i2c_board_info info; - const unsigned short addr_list[] = { - 0x6b, I2C_CLIENT_END - }; - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - /* Use quick read command for probe, some IR chips don't - * support writes */ - i2c_new_probed_device(&bus->i2c_adap, &info, addr_list, - i2c_probe_func_quick_read); - } - - return bus->i2c_rc; -} - -int cx23885_i2c_unregister(struct cx23885_i2c *bus) -{ - i2c_del_adapter(&bus->i2c_adap); - return 0; -} - -void cx23885_av_clk(struct cx23885_dev *dev, int enable) -{ - /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ - char buffer[3]; - struct i2c_msg msg; - dprintk(1, "%s(enabled = %d)\n", __func__, enable); - - /* Register 0x144 */ - buffer[0] = 0x01; - buffer[1] = 0x44; - if (enable == 1) - buffer[2] = 0x05; - else - buffer[2] = 0x00; - - msg.addr = 0x44; - msg.flags = I2C_M_TEN; - msg.len = 3; - msg.buf = buffer; - - i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); -} - -/* ----------------------------------------------------------------------- */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-input.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-input.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,350 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * Infrared remote control input device - * - * Most of this file is - * - * Copyright (C) 2009 Andy Walls - * - * However, the cx23885_input_{init,fini} functions contained herein are - * derived from Linux kernel files linux/media/video/.../...-input.c marked as: - * - * Copyright (C) 2008 - * Copyright (C) 2005 Ludovico Cavedon - * Markus Rechberger - * Mauro Carvalho Chehab - * Sascha Sommer - * Copyright (C) 2004, 2005 Chris Pascoe - * Copyright (C) 2003, 2004 Gerd Knorr - * Copyright (C) 2003 Pavel Machek - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include -#include -#include - -#include "cx23885.h" - -#define MODULE_NAME "cx23885" - -static void cx23885_input_process_measurements(struct cx23885_dev *dev, - bool overrun) -{ - struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir; - - ssize_t num; - int count, i; - bool handle = false; - struct ir_raw_event ir_core_event[64]; - - do { - num = 0; - v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event, - sizeof(ir_core_event), &num); - - count = num / sizeof(struct ir_raw_event); - - for (i = 0; i < count; i++) { - ir_raw_event_store(kernel_ir->rc, - &ir_core_event[i]); - handle = true; - } - } while (num != 0); - - if (overrun) - ir_raw_event_reset(kernel_ir->rc); - else if (handle) - ir_raw_event_handle(kernel_ir->rc); -} - -void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) -{ - struct v4l2_subdev_ir_parameters params; - int overrun, data_available; - - if (dev->sd_ir == NULL || events == 0) - return; - - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - case CX23885_BOARD_TEVII_S470: - case CX23885_BOARD_HAUPPAUGE_HVR1250: - /* - * The only boards we handle right now. However other boards - * using the CX2388x integrated IR controller should be similar - */ - break; - default: - return; - } - - overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN | - V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN); - - data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED | - V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ); - - if (overrun) { - /* If there was a FIFO overrun, stop the device */ - v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); - params.enable = false; - /* Mitigate race with cx23885_input_ir_stop() */ - params.shutdown = atomic_read(&dev->ir_input_stopping); - v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); - } - - if (data_available) - cx23885_input_process_measurements(dev, overrun); - - if (overrun) { - /* If there was a FIFO overrun, clear & restart the device */ - params.enable = true; - /* Mitigate race with cx23885_input_ir_stop() */ - params.shutdown = atomic_read(&dev->ir_input_stopping); - v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); - } -} - -static int cx23885_input_ir_start(struct cx23885_dev *dev) -{ - struct v4l2_subdev_ir_parameters params; - - if (dev->sd_ir == NULL) - return -ENODEV; - - atomic_set(&dev->ir_input_stopping, 0); - - v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - case CX23885_BOARD_HAUPPAUGE_HVR1250: - /* - * The IR controller on this board only returns pulse widths. - * Any other mode setting will fail to set up the device. - */ - params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; - params.enable = true; - params.interrupt_enable = true; - params.shutdown = false; - - /* Setup for baseband compatible with both RC-5 and RC-6A */ - params.modulation = false; - /* RC-5: 2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/ - /* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/ - params.max_pulse_width = 3333333; /* ns */ - /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ - /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ - params.noise_filter_min_width = 333333; /* ns */ - /* - * This board has inverted receive sense: - * mark is received as low logic level; - * falling edges are detected as rising edges; etc. - */ - params.invert_level = true; - break; - case CX23885_BOARD_TEVII_S470: - /* - * The IR controller on this board only returns pulse widths. - * Any other mode setting will fail to set up the device. - */ - params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; - params.enable = true; - params.interrupt_enable = true; - params.shutdown = false; - - /* Setup for a standard NEC protocol */ - params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */ - params.carrier_range_lower = 33000; /* Hz */ - params.carrier_range_upper = 43000; /* Hz */ - params.duty_cycle = 33; /* percent, 33 percent for NEC */ - - /* - * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units - * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns - */ - params.max_pulse_width = 12378022; /* ns */ - - /* - * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit - * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns - */ - params.noise_filter_min_width = 351648; /* ns */ - - params.modulation = false; - params.invert_level = true; - break; - } - v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); - return 0; -} - -static int cx23885_input_ir_open(struct rc_dev *rc) -{ - struct cx23885_kernel_ir *kernel_ir = rc->priv; - - if (kernel_ir->cx == NULL) - return -ENODEV; - - return cx23885_input_ir_start(kernel_ir->cx); -} - -static void cx23885_input_ir_stop(struct cx23885_dev *dev) -{ - struct v4l2_subdev_ir_parameters params; - - if (dev->sd_ir == NULL) - return; - - /* - * Stop the sd_ir subdevice from generating notifications and - * scheduling work. - * It is shutdown this way in order to mitigate a race with - * cx23885_input_rx_work_handler() in the overrun case, which could - * re-enable the subdevice. - */ - atomic_set(&dev->ir_input_stopping, 1); - v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); - while (params.shutdown == false) { - params.enable = false; - params.interrupt_enable = false; - params.shutdown = true; - v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); - v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); - } -} - -static void cx23885_input_ir_close(struct rc_dev *rc) -{ - struct cx23885_kernel_ir *kernel_ir = rc->priv; - - if (kernel_ir->cx != NULL) - cx23885_input_ir_stop(kernel_ir->cx); -} - -int cx23885_input_init(struct cx23885_dev *dev) -{ - struct cx23885_kernel_ir *kernel_ir; - struct rc_dev *rc; - char *rc_map; - enum rc_driver_type driver_type; - unsigned long allowed_protos; - - int ret; - - /* - * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't - * encapsulated in a v4l2_subdev, then I'm not going to deal with it. - */ - if (dev->sd_ir == NULL) - return -ENODEV; - - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: - case CX23885_BOARD_HAUPPAUGE_HVR1250: - /* Integrated CX2388[58] IR controller */ - driver_type = RC_DRIVER_IR_RAW; - allowed_protos = RC_TYPE_ALL; - /* The grey Hauppauge RC-5 remote */ - rc_map = RC_MAP_HAUPPAUGE; - break; - case CX23885_BOARD_TEVII_S470: - /* Integrated CX23885 IR controller */ - driver_type = RC_DRIVER_IR_RAW; - allowed_protos = RC_TYPE_ALL; - /* A guess at the remote */ - rc_map = RC_MAP_TEVII_NEC; - break; - default: - return -ENODEV; - } - - /* cx23885 board instance kernel IR state */ - kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL); - if (kernel_ir == NULL) - return -ENOMEM; - - kernel_ir->cx = dev; - kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)", - cx23885_boards[dev->board].name); - kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0", - pci_name(dev->pci)); - - /* input device */ - rc = rc_allocate_device(); - if (!rc) { - ret = -ENOMEM; - goto err_out_free; - } - - kernel_ir->rc = rc; - rc->input_name = kernel_ir->name; - rc->input_phys = kernel_ir->phys; - rc->input_id.bustype = BUS_PCI; - rc->input_id.version = 1; - if (dev->pci->subsystem_vendor) { - rc->input_id.vendor = dev->pci->subsystem_vendor; - rc->input_id.product = dev->pci->subsystem_device; - } else { - rc->input_id.vendor = dev->pci->vendor; - rc->input_id.product = dev->pci->device; - } - rc->dev.parent = &dev->pci->dev; - rc->driver_type = driver_type; - rc->allowed_protos = allowed_protos; - rc->priv = kernel_ir; - rc->open = cx23885_input_ir_open; - rc->close = cx23885_input_ir_close; - rc->map_name = rc_map; - rc->driver_name = MODULE_NAME; - - /* Go */ - dev->kernel_ir = kernel_ir; - ret = rc_register_device(rc); - if (ret) - goto err_out_stop; - - return 0; - -err_out_stop: - cx23885_input_ir_stop(dev); - dev->kernel_ir = NULL; - rc_free_device(rc); -err_out_free: - kfree(kernel_ir->phys); - kfree(kernel_ir->name); - kfree(kernel_ir); - return ret; -} - -void cx23885_input_fini(struct cx23885_dev *dev) -{ - /* Always stop the IR hardware from generating interrupts */ - cx23885_input_ir_stop(dev); - - if (dev->kernel_ir == NULL) - return; - rc_unregister_device(dev->kernel_ir->rc); - kfree(dev->kernel_ir->phys); - kfree(dev->kernel_ir->name); - kfree(dev->kernel_ir); - dev->kernel_ir = NULL; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-input.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-input.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-input.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-input.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * Infrared remote control input device - * - * Copyright (C) 2009 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef _CX23885_INPUT_H_ -#define _CX23885_INPUT_H_ -int cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events); - -int cx23885_input_init(struct cx23885_dev *dev); -void cx23885_input_fini(struct cx23885_dev *dev); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ioctl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ioctl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ioctl.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ioctl.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,208 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * Various common ioctl() support functions - * - * Copyright (c) 2009 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx23885.h" -#include - -int cx23885_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; - int err = 0; - u8 rev; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - switch (chip->match.type) { - case V4L2_CHIP_MATCH_HOST: - switch (chip->match.addr) { - case 0: - rev = cx_read(RDR_CFG2) & 0xff; - switch (dev->pci->device) { - case 0x8852: - /* rev 0x04 could be '885 or '888. Pick '888. */ - if (rev == 0x04) - chip->ident = V4L2_IDENT_CX23888; - else - chip->ident = V4L2_IDENT_CX23885; - break; - case 0x8880: - if (rev == 0x0e || rev == 0x0f) - chip->ident = V4L2_IDENT_CX23887; - else - chip->ident = V4L2_IDENT_CX23888; - break; - default: - chip->ident = V4L2_IDENT_UNKNOWN; - break; - } - chip->revision = (dev->pci->device << 16) | (rev << 8) | - (dev->hwrevision & 0xff); - break; - case 1: - if (dev->v4l_device != NULL) { - chip->ident = V4L2_IDENT_CX23417; - chip->revision = 0; - } - break; - case 2: - /* - * The integrated IR controller on the CX23888 is - * host chip 2. It may not be used/initialized or sd_ir - * may be pointing at the cx25840 subdevice for the - * IR controller on the CX23885. Thus we find it - * without using the dev->sd_ir pointer. - */ - call_hw(dev, CX23885_HW_888_IR, core, g_chip_ident, - chip); - break; - default: - err = -EINVAL; /* per V4L2 spec */ - break; - } - break; - case V4L2_CHIP_MATCH_I2C_DRIVER: - /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */ - call_all(dev, core, g_chip_ident, chip); - break; - case V4L2_CHIP_MATCH_I2C_ADDR: - /* - * We could return V4L2_IDENT_UNKNOWN, but we don't do the work - * to look if a chip is at the address with no driver. That's a - * dangerous thing to do with EEPROMs anyway. - */ - call_all(dev, core, g_chip_ident, chip); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx23885_g_host_register(struct cx23885_dev *dev, - struct v4l2_dbg_register *reg) -{ - if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) - return -EINVAL; - - reg->size = 4; - reg->val = cx_read(reg->reg); - return 0; -} - -static int cx23417_g_register(struct cx23885_dev *dev, - struct v4l2_dbg_register *reg) -{ - u32 value; - - if (dev->v4l_device == NULL) - return -EINVAL; - - if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) - return -EINVAL; - - if (mc417_register_read(dev, (u16) reg->reg, &value)) - return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ - - reg->size = 4; - reg->val = value; - return 0; -} - -int cx23885_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (reg->match.type == V4L2_CHIP_MATCH_HOST) { - switch (reg->match.addr) { - case 0: - return cx23885_g_host_register(dev, reg); - case 1: - return cx23417_g_register(dev, reg); - default: - break; - } - } - - /* FIXME - any error returns should not be ignored */ - call_all(dev, core, g_register, reg); - return 0; -} - -static int cx23885_s_host_register(struct cx23885_dev *dev, - struct v4l2_dbg_register *reg) -{ - if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) - return -EINVAL; - - reg->size = 4; - cx_write(reg->reg, reg->val); - return 0; -} - -static int cx23417_s_register(struct cx23885_dev *dev, - struct v4l2_dbg_register *reg) -{ - if (dev->v4l_device == NULL) - return -EINVAL; - - if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) - return -EINVAL; - - if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val)) - return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ - - reg->size = 4; - return 0; -} - -int cx23885_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (reg->match.type == V4L2_CHIP_MATCH_HOST) { - switch (reg->match.addr) { - case 0: - return cx23885_s_host_register(dev, reg); - case 1: - return cx23417_s_register(dev, reg); - default: - break; - } - } - - /* FIXME - any error returns should not be ignored */ - call_all(dev, core, s_register, reg); - return 0; -} -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ioctl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ioctl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ioctl.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ioctl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * Various common ioctl() support functions - * - * Copyright (c) 2009 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _CX23885_IOCTL_H_ -#define _CX23885_IOCTL_H_ - -int cx23885_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip); - -#ifdef CONFIG_VIDEO_ADV_DEBUG -int cx23885_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg); - - -int cx23885_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg); - -#endif -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ir.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * Infrared device support routines - non-input, non-vl42_subdev routines - * - * Copyright (C) 2009 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include - -#include "cx23885.h" -#include "cx23885-input.h" - -#define CX23885_IR_RX_FIFO_SERVICE_REQ 0 -#define CX23885_IR_RX_END_OF_RX_DETECTED 1 -#define CX23885_IR_RX_HW_FIFO_OVERRUN 2 -#define CX23885_IR_RX_SW_FIFO_OVERRUN 3 - -#define CX23885_IR_TX_FIFO_SERVICE_REQ 0 - - -void cx23885_ir_rx_work_handler(struct work_struct *work) -{ - struct cx23885_dev *dev = - container_of(work, struct cx23885_dev, ir_rx_work); - u32 events = 0; - unsigned long *notifications = &dev->ir_rx_notifications; - - if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications)) - events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; - if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications)) - events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; - if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications)) - events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; - if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications)) - events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; - - if (events == 0) - return; - - if (dev->kernel_ir) - cx23885_input_rx_work_handler(dev, events); -} - -void cx23885_ir_tx_work_handler(struct work_struct *work) -{ - struct cx23885_dev *dev = - container_of(work, struct cx23885_dev, ir_tx_work); - u32 events = 0; - unsigned long *notifications = &dev->ir_tx_notifications; - - if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications)) - events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; - - if (events == 0) - return; - -} - -/* Possibly called in an IRQ context */ -void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) -{ - struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); - unsigned long *notifications = &dev->ir_rx_notifications; - - if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ) - set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications); - if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED) - set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications); - if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN) - set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications); - if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN) - set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications); - - /* - * For the integrated AV core, we are already in a workqueue context. - * For the CX23888 integrated IR, we are in an interrupt context. - */ - if (sd == dev->sd_cx25840) - cx23885_ir_rx_work_handler(&dev->ir_rx_work); - else - schedule_work(&dev->ir_rx_work); -} - -/* Possibly called in an IRQ context */ -void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) -{ - struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); - unsigned long *notifications = &dev->ir_tx_notifications; - - if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ) - set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications); - - /* - * For the integrated AV core, we are already in a workqueue context. - * For the CX23888 integrated IR, we are in an interrupt context. - */ - if (sd == dev->sd_cx25840) - cx23885_ir_tx_work_handler(&dev->ir_tx_work); - else - schedule_work(&dev->ir_tx_work); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ir.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-ir.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * Infrared device support routines - non-input, non-vl42_subdev routines - * - * Copyright (C) 2009 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef _CX23885_IR_H_ -#define _CX23885_IR_H_ -void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events); -void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events); - -void cx23885_ir_rx_work_handler(struct work_struct *work); -void cx23885_ir_tx_work_handler(struct work_struct *work); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,449 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2006 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _CX23885_REG_H_ -#define _CX23885_REG_H_ - -/* -Address Map -0x00000000 -> 0x00009000 TX SRAM (Fifos) -0x00010000 -> 0x00013c00 RX SRAM CMDS + CDT - -EACH CMDS struct is 0x80 bytes long - -DMAx_PTR1 = 0x03040 address of first cluster -DMAx_PTR2 = 0x10600 address of the CDT -DMAx_CNT1 = cluster size in (bytes >> 4) -1 -DMAx_CNT2 = total cdt size for all entries >> 3 - -Cluster Descriptor entry = 4 DWORDS - DWORD 0 -> ptr to cluster - DWORD 1 Reserved - DWORD 2 Reserved - DWORD 3 Reserved - -Channel manager Data Structure entry = 20 DWORD - 0 IntialProgramCounterLow - 1 IntialProgramCounterHigh - 2 ClusterDescriptorTableBase - 3 ClusterDescriptorTableSize - 4 InstructionQueueBase - 5 InstructionQueueSize -... Reserved - 19 Reserved -*/ - -/* Risc Instructions */ -#define RISC_CNT_INC 0x00010000 -#define RISC_CNT_RESET 0x00030000 -#define RISC_IRQ1 0x01000000 -#define RISC_IRQ2 0x02000000 -#define RISC_EOL 0x04000000 -#define RISC_SOL 0x08000000 -#define RISC_WRITE 0x10000000 -#define RISC_SKIP 0x20000000 -#define RISC_JUMP 0x70000000 -#define RISC_SYNC 0x80000000 -#define RISC_RESYNC 0x80008000 -#define RISC_READ 0x90000000 -#define RISC_WRITERM 0xB0000000 -#define RISC_WRITECM 0xC0000000 -#define RISC_WRITECR 0xD0000000 -#define RISC_WRITEC 0x50000000 -#define RISC_READC 0xA0000000 - - -/* Audio and Video Core */ -#define HOST_REG1 0x00000000 -#define HOST_REG2 0x00000001 -#define HOST_REG3 0x00000002 - -/* Chip Configuration Registers */ -#define CHIP_CTRL 0x00000100 -#define AFE_CTRL 0x00000104 -#define VID_PLL_INT_POST 0x00000108 -#define VID_PLL_FRAC 0x0000010C -#define AUX_PLL_INT_POST 0x00000110 -#define AUX_PLL_FRAC 0x00000114 -#define SYS_PLL_INT_POST 0x00000118 -#define SYS_PLL_FRAC 0x0000011C -#define PIN_CTRL 0x00000120 -#define AUD_IO_CTRL 0x00000124 -#define AUD_LOCK1 0x00000128 -#define AUD_LOCK2 0x0000012C -#define POWER_CTRL 0x00000130 -#define AFE_DIAG_CTRL1 0x00000134 -#define AFE_DIAG_CTRL3 0x0000013C -#define PLL_DIAG_CTRL 0x00000140 -#define AFE_CLK_OUT_CTRL 0x00000144 -#define DLL1_DIAG_CTRL 0x0000015C - -/* GPIO[23:19] Output Enable */ -#define GPIO2_OUT_EN_REG 0x00000160 -/* GPIO[23:19] Data Registers */ -#define GPIO2 0x00000164 - -#define IFADC_CTRL 0x00000180 - -/* Infrared Remote Registers */ -#define IR_CNTRL_REG 0x00000200 -#define IR_TXCLK_REG 0x00000204 -#define IR_RXCLK_REG 0x00000208 -#define IR_CDUTY_REG 0x0000020C -#define IR_STAT_REG 0x00000210 -#define IR_IRQEN_REG 0x00000214 -#define IR_FILTR_REG 0x00000218 -#define IR_FIFO_REG 0x0000023C - -/* Video Decoder Registers */ -#define MODE_CTRL 0x00000400 -#define OUT_CTRL1 0x00000404 -#define OUT_CTRL2 0x00000408 -#define GEN_STAT 0x0000040C -#define INT_STAT_MASK 0x00000410 -#define LUMA_CTRL 0x00000414 -#define HSCALE_CTRL 0x00000418 -#define VSCALE_CTRL 0x0000041C -#define CHROMA_CTRL 0x00000420 -#define VBI_LINE_CTRL1 0x00000424 -#define VBI_LINE_CTRL2 0x00000428 -#define VBI_LINE_CTRL3 0x0000042C -#define VBI_LINE_CTRL4 0x00000430 -#define VBI_LINE_CTRL5 0x00000434 -#define VBI_FC_CFG 0x00000438 -#define VBI_MISC_CFG1 0x0000043C -#define VBI_MISC_CFG2 0x00000440 -#define VBI_PAY1 0x00000444 -#define VBI_PAY2 0x00000448 -#define VBI_CUST1_CFG1 0x0000044C -#define VBI_CUST1_CFG2 0x00000450 -#define VBI_CUST1_CFG3 0x00000454 -#define VBI_CUST2_CFG1 0x00000458 -#define VBI_CUST2_CFG2 0x0000045C -#define VBI_CUST2_CFG3 0x00000460 -#define VBI_CUST3_CFG1 0x00000464 -#define VBI_CUST3_CFG2 0x00000468 -#define VBI_CUST3_CFG3 0x0000046C -#define HORIZ_TIM_CTRL 0x00000470 -#define VERT_TIM_CTRL 0x00000474 -#define SRC_COMB_CFG 0x00000478 -#define CHROMA_VBIOFF_CFG 0x0000047C -#define FIELD_COUNT 0x00000480 -#define MISC_TIM_CTRL 0x00000484 -#define DFE_CTRL1 0x00000488 -#define DFE_CTRL2 0x0000048C -#define DFE_CTRL3 0x00000490 -#define PLL_CTRL 0x00000494 -#define HTL_CTRL 0x00000498 -#define COMB_CTRL 0x0000049C -#define CRUSH_CTRL 0x000004A0 -#define SOFT_RST_CTRL 0x000004A4 -#define CX885_VERSION 0x000004B4 -#define VBI_PASS_CTRL 0x000004BC - -/* Audio Decoder Registers */ -/* 8051 Configuration */ -#define DL_CTL 0x00000800 -#define STD_DET_STATUS 0x00000804 -#define STD_DET_CTL 0x00000808 -#define DW8051_INT 0x0000080C -#define GENERAL_CTL 0x00000810 -#define AAGC_CTL 0x00000814 -#define DEMATRIX_CTL 0x000008CC -#define PATH1_CTL1 0x000008D0 -#define PATH1_VOL_CTL 0x000008D4 -#define PATH1_EQ_CTL 0x000008D8 -#define PATH1_SC_CTL 0x000008DC -#define PATH2_CTL1 0x000008E0 -#define PATH2_VOL_CTL 0x000008E4 -#define PATH2_EQ_CTL 0x000008E8 -#define PATH2_SC_CTL 0x000008EC - -/* Sample Rate Converter */ -#define SRC_CTL 0x000008F0 -#define SRC_LF_COEF 0x000008F4 -#define SRC1_CTL 0x000008F8 -#define SRC2_CTL 0x000008FC -#define SRC3_CTL 0x00000900 -#define SRC4_CTL 0x00000904 -#define SRC5_CTL 0x00000908 -#define SRC6_CTL 0x0000090C -#define BAND_OUT_SEL 0x00000910 -#define I2S_N_CTL 0x00000914 -#define I2S_OUT_CTL 0x00000918 -#define AUTOCONFIG_REG 0x000009C4 - -/* Audio ADC Registers */ -#define DSM_CTRL1 0x00000000 -#define DSM_CTRL2 0x00000001 -#define CHP_EN_CTRL 0x00000002 -#define CHP_CLK_CTRL1 0x00000004 -#define CHP_CLK_CTRL2 0x00000005 -#define BG_REF_CTRL 0x00000006 -#define SD2_SW_CTRL1 0x00000008 -#define SD2_SW_CTRL2 0x00000009 -#define SD2_BIAS_CTRL 0x0000000A -#define AMP_BIAS_CTRL 0x0000000C -#define CH_PWR_CTRL1 0x0000000E -#define CH_PWR_CTRL2 0x0000000F -#define DSM_STATUS1 0x00000010 -#define DSM_STATUS2 0x00000011 -#define DIG_CTL1 0x00000012 -#define DIG_CTL2 0x00000013 -#define I2S_TX_CFG 0x0000001A - -#define DEV_CNTRL2 0x00040000 - -#define PCI_MSK_IR (1 << 28) -#define PCI_MSK_AV_CORE (1 << 27) -#define PCI_MSK_GPIO1 (1 << 24) -#define PCI_MSK_GPIO0 (1 << 23) -#define PCI_MSK_APB_DMA (1 << 12) -#define PCI_MSK_AL_WR (1 << 11) -#define PCI_MSK_AL_RD (1 << 10) -#define PCI_MSK_RISC_WR (1 << 9) -#define PCI_MSK_RISC_RD (1 << 8) -#define PCI_MSK_AUD_EXT (1 << 4) -#define PCI_MSK_AUD_INT (1 << 3) -#define PCI_MSK_VID_C (1 << 2) -#define PCI_MSK_VID_B (1 << 1) -#define PCI_MSK_VID_A 1 -#define PCI_INT_MSK 0x00040010 - -#define PCI_INT_STAT 0x00040014 -#define PCI_INT_MSTAT 0x00040018 - -#define VID_A_INT_MSK 0x00040020 -#define VID_A_INT_STAT 0x00040024 -#define VID_A_INT_MSTAT 0x00040028 -#define VID_A_INT_SSTAT 0x0004002C - -#define VID_B_INT_MSK 0x00040030 -#define VID_B_MSK_BAD_PKT (1 << 20) -#define VID_B_MSK_VBI_OPC_ERR (1 << 17) -#define VID_B_MSK_OPC_ERR (1 << 16) -#define VID_B_MSK_VBI_SYNC (1 << 13) -#define VID_B_MSK_SYNC (1 << 12) -#define VID_B_MSK_VBI_OF (1 << 9) -#define VID_B_MSK_OF (1 << 8) -#define VID_B_MSK_VBI_RISCI2 (1 << 5) -#define VID_B_MSK_RISCI2 (1 << 4) -#define VID_B_MSK_VBI_RISCI1 (1 << 1) -#define VID_B_MSK_RISCI1 1 -#define VID_B_INT_STAT 0x00040034 -#define VID_B_INT_MSTAT 0x00040038 -#define VID_B_INT_SSTAT 0x0004003C - -#define VID_B_MSK_BAD_PKT (1 << 20) -#define VID_B_MSK_OPC_ERR (1 << 16) -#define VID_B_MSK_SYNC (1 << 12) -#define VID_B_MSK_OF (1 << 8) -#define VID_B_MSK_RISCI2 (1 << 4) -#define VID_B_MSK_RISCI1 1 - -#define VID_C_MSK_BAD_PKT (1 << 20) -#define VID_C_MSK_OPC_ERR (1 << 16) -#define VID_C_MSK_SYNC (1 << 12) -#define VID_C_MSK_OF (1 << 8) -#define VID_C_MSK_RISCI2 (1 << 4) -#define VID_C_MSK_RISCI1 1 - -/* A superset for testing purposes */ -#define VID_BC_MSK_BAD_PKT (1 << 20) -#define VID_BC_MSK_OPC_ERR (1 << 16) -#define VID_BC_MSK_SYNC (1 << 12) -#define VID_BC_MSK_OF (1 << 8) -#define VID_BC_MSK_RISCI2 (1 << 4) -#define VID_BC_MSK_RISCI1 1 - -#define VID_C_INT_MSK 0x00040040 -#define VID_C_INT_STAT 0x00040044 -#define VID_C_INT_MSTAT 0x00040048 -#define VID_C_INT_SSTAT 0x0004004C - -#define AUDIO_INT_INT_MSK 0x00040050 -#define AUDIO_INT_INT_STAT 0x00040054 -#define AUDIO_INT_INT_MSTAT 0x00040058 -#define AUDIO_INT_INT_SSTAT 0x0004005C - -#define AUDIO_EXT_INT_MSK 0x00040060 -#define AUDIO_EXT_INT_STAT 0x00040064 -#define AUDIO_EXT_INT_MSTAT 0x00040068 -#define AUDIO_EXT_INT_SSTAT 0x0004006C - -#define RDR_CFG0 0x00050000 -#define RDR_CFG1 0x00050004 -#define RDR_CFG2 0x00050008 -#define RDR_RDRCTL1 0x0005030c -#define RDR_TLCTL0 0x00050318 - -/* APB DMAC Current Buffer Pointer */ -#define DMA1_PTR1 0x00100000 -#define DMA2_PTR1 0x00100004 -#define DMA3_PTR1 0x00100008 -#define DMA4_PTR1 0x0010000C -#define DMA5_PTR1 0x00100010 -#define DMA6_PTR1 0x00100014 -#define DMA7_PTR1 0x00100018 -#define DMA8_PTR1 0x0010001C - -/* APB DMAC Current Table Pointer */ -#define DMA1_PTR2 0x00100040 -#define DMA2_PTR2 0x00100044 -#define DMA3_PTR2 0x00100048 -#define DMA4_PTR2 0x0010004C -#define DMA5_PTR2 0x00100050 -#define DMA6_PTR2 0x00100054 -#define DMA7_PTR2 0x00100058 -#define DMA8_PTR2 0x0010005C - -/* APB DMAC Buffer Limit */ -#define DMA1_CNT1 0x00100080 -#define DMA2_CNT1 0x00100084 -#define DMA3_CNT1 0x00100088 -#define DMA4_CNT1 0x0010008C -#define DMA5_CNT1 0x00100090 -#define DMA6_CNT1 0x00100094 -#define DMA7_CNT1 0x00100098 -#define DMA8_CNT1 0x0010009C - -/* APB DMAC Table Size */ -#define DMA1_CNT2 0x001000C0 -#define DMA2_CNT2 0x001000C4 -#define DMA3_CNT2 0x001000C8 -#define DMA4_CNT2 0x001000CC -#define DMA5_CNT2 0x001000D0 -#define DMA6_CNT2 0x001000D4 -#define DMA7_CNT2 0x001000D8 -#define DMA8_CNT2 0x001000DC - -/* Timer Counters */ -#define TM_CNT_LDW 0x00110000 -#define TM_CNT_UW 0x00110004 -#define TM_LMT_LDW 0x00110008 -#define TM_LMT_UW 0x0011000C - -/* GPIO */ -#define GP0_IO 0x00110010 -#define GPIO_ISM 0x00110014 -#define SOFT_RESET 0x0011001C - -/* GPIO (417 Microsoftcontroller) RW Data */ -#define MC417_RWD 0x00110020 - -/* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ -#define MC417_OEN 0x00110024 -#define MC417_CTL 0x00110028 -#define ALT_PIN_OUT_SEL 0x0011002C -#define CLK_DELAY 0x00110048 -#define PAD_CTRL 0x0011004C - -/* Video A Interface */ -#define VID_A_GPCNT 0x00130020 -#define VBI_A_GPCNT 0x00130024 -#define VID_A_GPCNT_CTL 0x00130030 -#define VBI_A_GPCNT_CTL 0x00130034 -#define VID_A_DMA_CTL 0x00130040 -#define VID_A_VIP_CTRL 0x00130080 -#define VID_A_PIXEL_FRMT 0x00130084 -#define VID_A_VBI_CTRL 0x00130088 - -/* Video B Interface */ -#define VID_B_DMA 0x00130100 -#define VBI_B_DMA 0x00130108 -#define VID_B_GPCNT 0x00130120 -#define VBI_B_GPCNT 0x00130124 -#define VID_B_GPCNT_CTL 0x00130134 -#define VBI_B_GPCNT_CTL 0x00130138 -#define VID_B_DMA_CTL 0x00130140 -#define VID_B_SRC_SEL 0x00130144 -#define VID_B_LNGTH 0x00130150 -#define VID_B_HW_SOP_CTL 0x00130154 -#define VID_B_GEN_CTL 0x00130158 -#define VID_B_BD_PKT_STATUS 0x0013015C -#define VID_B_SOP_STATUS 0x00130160 -#define VID_B_FIFO_OVFL_STAT 0x00130164 -#define VID_B_VLD_MISC 0x00130168 -#define VID_B_TS_CLK_EN 0x0013016C -#define VID_B_VIP_CTRL 0x00130180 -#define VID_B_PIXEL_FRMT 0x00130184 - -/* Video C Interface */ -#define VID_C_GPCNT 0x00130220 -#define VID_C_GPCNT_CTL 0x00130230 -#define VBI_C_GPCNT_CTL 0x00130234 -#define VID_C_DMA_CTL 0x00130240 -#define VID_C_LNGTH 0x00130250 -#define VID_C_HW_SOP_CTL 0x00130254 -#define VID_C_GEN_CTL 0x00130258 -#define VID_C_BD_PKT_STATUS 0x0013025C -#define VID_C_SOP_STATUS 0x00130260 -#define VID_C_FIFO_OVFL_STAT 0x00130264 -#define VID_C_VLD_MISC 0x00130268 -#define VID_C_TS_CLK_EN 0x0013026C - -/* Internal Audio Interface */ -#define AUD_INT_A_GPCNT 0x00140020 -#define AUD_INT_B_GPCNT 0x00140024 -#define AUD_INT_A_GPCNT_CTL 0x00140030 -#define AUD_INT_B_GPCNT_CTL 0x00140034 -#define AUD_INT_DMA_CTL 0x00140040 -#define AUD_INT_A_LNGTH 0x00140050 -#define AUD_INT_B_LNGTH 0x00140054 -#define AUD_INT_A_MODE 0x00140058 -#define AUD_INT_B_MODE 0x0014005C - -/* External Audio Interface */ -#define AUD_EXT_DMA 0x00140100 -#define AUD_EXT_GPCNT 0x00140120 -#define AUD_EXT_GPCNT_CTL 0x00140130 -#define AUD_EXT_DMA_CTL 0x00140140 -#define AUD_EXT_LNGTH 0x00140150 -#define AUD_EXT_A_MODE 0x00140158 - -/* I2C Bus 1 */ -#define I2C1_ADDR 0x00180000 -#define I2C1_WDATA 0x00180004 -#define I2C1_CTRL 0x00180008 -#define I2C1_RDATA 0x0018000C -#define I2C1_STAT 0x00180010 - -/* I2C Bus 2 */ -#define I2C2_ADDR 0x00190000 -#define I2C2_WDATA 0x00190004 -#define I2C2_CTRL 0x00190008 -#define I2C2_RDATA 0x0019000C -#define I2C2_STAT 0x00190010 - -/* I2C Bus 3 */ -#define I2C3_ADDR 0x001A0000 -#define I2C3_WDATA 0x001A0004 -#define I2C3_CTRL 0x001A0008 -#define I2C3_RDATA 0x001A000C -#define I2C3_STAT 0x001A0010 - -/* UART */ -#define UART_CTL 0x001B0000 -#define UART_BRD 0x001B0004 -#define UART_ISR 0x001B000C -#define UART_CNT 0x001B0010 - -#endif /* _CX23885_REG_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-vbi.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,247 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2007 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "cx23885.h" - -static unsigned int vbibufs = 4; -module_param(vbibufs, int, 0644); -MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); - -static unsigned int vbi_debug; -module_param(vbi_debug, int, 0644); -MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); - -#define dprintk(level, fmt, arg...)\ - do { if (vbi_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) - -/* ------------------------------------------------------------------ */ - -int cx23885_vbi_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (dev->tvnorm & V4L2_STD_525_60) { - /* ntsc */ - f->fmt.vbi.sampling_rate = 28636363; - f->fmt.vbi.start[0] = 10; - f->fmt.vbi.start[1] = 273; - - } else if (dev->tvnorm & V4L2_STD_625_50) { - /* pal */ - f->fmt.vbi.sampling_rate = 35468950; - f->fmt.vbi.start[0] = 7 - 1; - f->fmt.vbi.start[1] = 319 - 1; - } - return 0; -} - -static int cx23885_start_vbi_dma(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q, - struct cx23885_buffer *buf) -{ - /* setup fifo + format */ - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], - buf->vb.width, buf->risc.dma); - - /* reset counter */ - q->count = 1; - - /* enable irqs */ - cx23885_irq_add_enable(dev, 0x01); - cx_set(VID_A_INT_MSK, 0x000022); - - /* start dma */ - cx_set(DEV_CNTRL2, (1<<5)); - cx_set(VID_A_DMA_CTL, 0x00000022); - - return 0; -} - - -static int cx23885_restart_vbi_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) -{ - struct cx23885_buffer *buf; - struct list_head *item; - - if (list_empty(&q->active)) - return 0; - - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_vbi_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; -} - -void cx23885_vbi_timeout(unsigned long data) -{ - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vbiq; - struct cx23885_buffer *buf; - unsigned long flags; - - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]); - - cx_clear(VID_A_DMA_CTL, 0x22); - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, - buf, buf->vb.i, (unsigned long)buf->risc.dma); - } - cx23885_restart_vbi_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} - -/* ------------------------------------------------------------------ */ -#define VBI_LINE_LENGTH 2048 -#define VBI_LINE_COUNT 17 - -static int -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 == *count) - *count = vbibufs; - if (*count < 2) - *count = 2; - if (*count > 32) - *count = 32; - return 0; -} - -static int -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - unsigned int size; - int rc; - - size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = VBI_LINE_LENGTH; - buf->vb.height = VBI_LINE_COUNT; - buf->vb.size = size; - buf->vb.field = V4L2_FIELD_SEQ_TB; - - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->vb.width * buf->vb.height, - buf->vb.width, 0, - buf->vb.height); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - cx23885_free_buffer(q, buf); - return rc; -} - -static void -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); - struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_dmaqueue *q = &dev->vbiq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - - if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_vbi_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] vbi_queue - first active\n", - buf, buf->vb.i); - - } else { - prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ - dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - } -} - -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); - - cx23885_free_buffer(q, buf); -} - -struct videobuf_queue_ops cx23885_vbi_qops = { - .buf_setup = vbi_setup, - .buf_prepare = vbi_prepare, - .buf_queue = vbi_queue, - .buf_release = vbi_release, -}; - -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23885-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1534 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2007 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx23885.h" -#include -#include -#include "cx23885-ioctl.h" -#include "tuner-xc2028.h" - -MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); -MODULE_AUTHOR("Steven Toth "); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------------ */ - -static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; - -module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); - -MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); - -static unsigned int video_debug; -module_param(video_debug, int, 0644); -MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); - -static unsigned int irq_debug; -module_param(irq_debug, int, 0644); -MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); - -static unsigned int vid_limit = 16; -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); - -#define dprintk(level, fmt, arg...)\ - do { if (video_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) - -/* ------------------------------------------------------------------- */ -/* static data */ - -#define FORMAT_FLAGS_PACKED 0x01 - -static struct cx23885_fmt formats[] = { - { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB555X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB565, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB565X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "24 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR24, - .depth = 24, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, -}; - -static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(formats); i++) - if (formats[i].fourcc == fourcc) - return formats+i; - - printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc); - return NULL; -} - -/* ------------------------------------------------------------------- */ - -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static struct cx23885_ctrl cx23885_ctls[] = { - /* --- video --- */ - { - .v = { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = LUMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - .v = { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = LUMA_CTRL, - .mask = 0xff00, - .shift = 8, - }, { - .v = { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = CHROMA_CTRL, - .mask = 0xff0000, - .shift = 16, - }, { - /* strictly, this only describes only U saturation. - * V saturation is handled specially through code. - */ - .v = { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = CHROMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - /* --- audio --- */ - .v = { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = PATH1_CTL1, - .mask = (0x1f << 24), - .shift = 24, - }, { - .v = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = PATH1_VOL_CTL, - .mask = 0xff, - .shift = 0, - } -}; -static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); - -/* Must be sorted from low to high control ID! */ -static const u32 cx23885_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_MUTE, - 0 -}; - -static const u32 *ctrl_classes[] = { - cx23885_user_ctrls, - NULL -}; - -static void cx23885_video_wakeup(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q, u32 count) -{ - struct cx23885_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - do_gettimeofday(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } - if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - if (bc != 1) - printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", - __func__, bc); -} - -static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) -{ - dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", - __func__, - (unsigned int)norm, - v4l2_norm_to_name(norm)); - - dev->tvnorm = norm; - - call_all(dev, core, s_std, norm); - - return 0; -} - -static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, - struct pci_dev *pci, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - dprintk(1, "%s()\n", __func__); - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - dev->name, type, cx23885_boards[dev->board].name); - video_set_drvdata(vfd, dev); - return vfd; -} - -static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || - qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX23885_CTLS; i++) - if (cx23885_ctls[i].v.id == qctrl->id) - break; - if (i == CX23885_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx23885_ctls[i].v; - return 0; -} - -/* ------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bit) -{ - dprintk(1, "%s()\n", __func__); - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources & bit) { - /* no, someone else uses it */ - mutex_unlock(&dev->lock); - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(1, "res: get %d\n", bit); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_check(struct cx23885_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct cx23885_dev *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bits) -{ - BUG_ON((fh->resources & bits) != bits); - dprintk(1, "%s()\n", __func__); - - mutex_lock(&dev->lock); - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk(1, "res: put %d\n", bits); - mutex_unlock(&dev->lock); -} - -static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) -{ - dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", - __func__, - input, INPUT(input)->vmux, - INPUT(input)->gpio0, INPUT(input)->gpio1, - INPUT(input)->gpio2, INPUT(input)->gpio3); - dev->input = input; - - if (dev->board == CX23885_BOARD_MYGICA_X8506 || - dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) { - /* Select Analog TV */ - if (INPUT(input)->type == CX23885_VMUX_TELEVISION) - cx23885_gpio_clear(dev, GPIO_0); - } - - /* Tell the internal A/V decoder */ - v4l2_subdev_call(dev->sd_cx25840, video, s_routing, - INPUT(input)->vmux, 0, 0); - - return 0; -} - -/* ------------------------------------------------------------------ */ -static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, - unsigned int height, enum v4l2_field field) -{ - dprintk(1, "%s()\n", __func__); - return 0; -} - -static int cx23885_start_video_dma(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q, - struct cx23885_buffer *buf) -{ - dprintk(1, "%s()\n", __func__); - - /* setup fifo + format */ - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], - buf->bpl, buf->risc.dma); - cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); - - /* reset counter */ - cx_write(VID_A_GPCNT_CTL, 3); - q->count = 1; - - /* enable irq */ - cx23885_irq_add_enable(dev, 0x01); - cx_set(VID_A_INT_MSK, 0x000011); - - /* start dma */ - cx_set(DEV_CNTRL2, (1<<5)); - cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ - - return 0; -} - - -static int cx23885_restart_video_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) -{ - struct cx23885_buffer *buf, *prev; - struct list_head *item; - dprintk(1, "%s()\n", __func__); - - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_video_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, - vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, - vb.queue); - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] restart_queue - first active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ - dprintk(2, "[%p/%d] restart_queue - move to active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } -} - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct cx23885_fh *fh = q->priv_data; - - *size = fh->fmt->depth*fh->width*fh->height >> 3; - if (0 == *count) - *count = 32; - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; - return 0; -} - -static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); - int rc, init_buffer = 0; - u32 line0_offset, line1_offset; - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) - return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - init_buffer = 1; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - } - - if (init_buffer) { - buf->bpl = buf->vb.width * buf->fmt->depth >> 3; - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) { - /* cx25840 transmits NTSC bottom field first */ - dprintk(1, "%s() Creating NTSC risc\n", - __func__); - line0_offset = buf->bpl; - line1_offset = 0; - } else { - /* All other formats are top field first */ - dprintk(1, "%s() Creating PAL/SECAM risc\n", - __func__); - line0_offset = 0; - line1_offset = buf->bpl; - } - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, line0_offset, - line1_offset, - buf->bpl, buf->bpl, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, - buf->vb.height >> 1); - break; - default: - BUG(); - } - } - dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, - fh->width, fh->height, fh->fmt->depth, fh->fmt->name, - (unsigned long)buf->risc.dma); - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - cx23885_free_buffer(q, buf); - return rc; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_dmaqueue *q = &dev->vidq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", - buf, buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] buffer_queue - first active\n", - buf, buf->vb.i); - - } else { - prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - - } else { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", - buf, buf->vb.i); - } - } -} - -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - - cx23885_free_buffer(q, buf); -} - -static struct videobuf_queue_ops cx23885_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -static struct videobuf_queue *get_queue(struct cx23885_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &fh->vidq; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return &fh->vbiq; - default: - BUG(); - return NULL; - } -} - -static int get_resource(struct cx23885_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return RESOURCE_VBI; - default: - BUG(); - return 0; - } -} - -static int video_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh; - enum v4l2_buf_type type = 0; - int radio = 0; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - } - - dprintk(1, "open dev=%s radio=%d type=%s\n", - video_device_node_name(vdev), radio, v4l2_type_names[type]); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - fh->type = type; - fh->width = 320; - fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - - videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh, NULL); - - dprintk(1, "post videobuf_queue_init()\n"); - - return 0; -} - -static ssize_t video_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct cx23885_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - return videobuf_read_one(&fh->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (!res_get(fh->dev, fh, RESOURCE_VBI)) - return -EBUSY; - return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - default: - BUG(); - return 0; - } -} - -static unsigned int video_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_buffer *buf; - unsigned int rc = POLLERR; - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - if (!res_get(fh->dev, fh, RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbiq, wait); - } - - mutex_lock(&fh->vidq.vb_lock); - if (res_check(fh, RESOURCE_VIDEO)) { - /* streaming capture */ - if (list_empty(&fh->vidq.stream)) - goto done; - buf = list_entry(fh->vidq.stream.next, - struct cx23885_buffer, vb.stream); - } else { - /* read() capture */ - buf = (struct cx23885_buffer *)fh->vidq.read_buf; - if (NULL == buf) - goto done; - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; -done: - mutex_unlock(&fh->vidq.vb_lock); - return rc; -} - -static int video_release(struct file *file) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - /* turn off overlay */ - if (res_check(fh, RESOURCE_OVERLAY)) { - /* FIXME */ - res_free(dev, fh, RESOURCE_OVERLAY); - } - - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_queue_cancel(&fh->vidq); - res_free(dev, fh, RESOURCE_VIDEO); - } - if (fh->vidq.read_buf) { - buffer_release(&fh->vidq, fh->vidq.read_buf); - kfree(fh->vidq.read_buf); - } - - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - if (fh->vbiq.streaming) - videobuf_streamoff(&fh->vbiq); - if (fh->vbiq.reading) - videobuf_read_stop(&fh->vbiq); - res_free(dev, fh, RESOURCE_VBI); - } - - videobuf_mmap_free(&fh->vidq); - file->private_data = NULL; - kfree(fh); - - /* We are not putting the tuner to sleep here on exit, because - * we want to use the mpeg encoder in another session to capture - * tuner video. Closing this will result in no video to the encoder. - */ - - return 0; -} - -static int video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_mmap_mapper(get_queue(fh), vma); -} - -/* ------------------------------------------------------------------ */ -/* VIDEO CTRL IOCTLS */ - -static int cx23885_get_control(struct cx23885_dev *dev, - struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); - call_all(dev, core, g_ctrl, ctl); - return 0; -} - -static int cx23885_set_control(struct cx23885_dev *dev, - struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" - " (disabled - no action)\n", __func__); - return 0; -} - -static void init_controls(struct cx23885_dev *dev) -{ - struct v4l2_control ctrl; - int i; - - for (i = 0; i < CX23885_CTLS; i++) { - ctrl.id = cx23885_ctls[i].v.id; - ctrl.value = cx23885_ctls[i].v.default_value; - - cx23885_set_control(dev, &ctrl); - } -} - -/* ------------------------------------------------------------------ */ -/* VIDEO IOCTLS */ - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - struct cx23885_fmt *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - maxw = norm_maxw(dev->tvnorm); - maxh = norm_maxh(dev->tvnorm); - - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - f->fmt.pix.field = field; - v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, - &f->fmt.pix.height, 32, maxh, 0, 0); - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - struct v4l2_mbus_framefmt mbus_fmt; - int err; - - dprintk(2, "%s()\n", __func__); - err = vidioc_try_fmt_vid_cap(file, priv, f); - - if (0 != err) - return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->vidq.field = f->fmt.pix.field; - dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, - fh->width, fh->height, fh->vidq.field); - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); - call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - strcpy(cap->driver, "cx23885"); - strlcpy(cap->card, cx23885_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->version = CX23885_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VBI_CAPTURE; - if (UNSET != dev->tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (unlikely(f->index >= ARRAY_SIZE(formats))) - return -EINVAL; - - strlcpy(f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx23885_fh *fh = priv; - return videobuf_reqbufs(get_queue(fh), p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = priv; - return videobuf_querybuf(get_queue(fh), p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = priv; - return videobuf_qbuf(get_queue(fh), p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = priv; - return videobuf_dqbuf(get_queue(fh), p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - dprintk(1, "%s()\n", __func__); - - if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) - return -EINVAL; - if (unlikely(i != fh->type)) - return -EINVAL; - - if (unlikely(!res_get(dev, fh, get_resource(fh)))) - return -EBUSY; - return videobuf_streamon(get_queue(fh)); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - int err, res; - dprintk(1, "%s()\n", __func__); - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (i != fh->type) - return -EINVAL; - - res = get_resource(fh); - err = videobuf_streamoff(get_queue(fh)); - if (err < 0) - return err; - res_free(dev, fh, res); - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - dprintk(1, "%s()\n", __func__); - - mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, *tvnorms); - mutex_unlock(&dev->lock); - - return 0; -} - -static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) -{ - static const char *iname[] = { - [CX23885_VMUX_COMPOSITE1] = "Composite1", - [CX23885_VMUX_COMPOSITE2] = "Composite2", - [CX23885_VMUX_COMPOSITE3] = "Composite3", - [CX23885_VMUX_COMPOSITE4] = "Composite4", - [CX23885_VMUX_SVIDEO] = "S-Video", - [CX23885_VMUX_COMPONENT] = "Component", - [CX23885_VMUX_TELEVISION] = "Television", - [CX23885_VMUX_CABLE] = "Cable TV", - [CX23885_VMUX_DVB] = "DVB", - [CX23885_VMUX_DEBUG] = "for debug only", - }; - unsigned int n; - dprintk(1, "%s()\n", __func__); - - n = i->index; - if (n >= 4) - return -EINVAL; - - if (0 == INPUT(n)->type) - return -EINVAL; - - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, iname[INPUT(n)->type]); - if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || - (CX23885_VMUX_CABLE == INPUT(n)->type)) { - i->type = V4L2_INPUT_TYPE_TUNER; - i->std = CX23885_NORMS; - } - return 0; -} - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - dprintk(1, "%s()\n", __func__); - return cx23885_enum_input(dev, i); -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - *i = dev->input; - dprintk(1, "%s() returns %d\n", __func__, *i); - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - dprintk(1, "%s(%d)\n", __func__, i); - - if (i >= 4) { - dprintk(1, "%s() -EINVAL\n", __func__); - return -EINVAL; - } - - mutex_lock(&dev->lock); - cx23885_video_mux(dev, i); - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_log_status(struct file *file, void *priv) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - printk(KERN_INFO - "%s/0: ============ START LOG STATUS ============\n", - dev->name); - call_all(dev, core, log_status); - printk(KERN_INFO - "%s/0: ============= END LOG STATUS =============\n", - dev->name); - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx23885_ctrl_query(qctrl); -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_get_control(dev, ctl); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_set_control(dev, ctl); -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - t->signal = 0xffff ; /* LOCKED */ - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - if (UNSET == dev->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - - /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->freq; - - call_all(dev, tuner, g_frequency, f); - - return 0; -} - -static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) -{ - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (unlikely(f->tuner != 0)) - return -EINVAL; - - mutex_lock(&dev->lock); - dev->freq = f->frequency; - - call_all(dev, tuner, s_frequency, f); - - /* When changing channels it is required to reset TVAUDIO */ - msleep(10); - - mutex_unlock(&dev->lock); - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; - - return - cx23885_set_freq(dev, f); -} - -/* ----------------------------------------------------------- */ - -static void cx23885_vid_timeout(unsigned long data) -{ - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vidq; - struct cx23885_buffer *buf; - unsigned long flags; - - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); - - cx_clear(VID_A_DMA_CTL, 0x11); - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", - dev->name, buf, buf->vb.i, - (unsigned long)buf->risc.dma); - } - cx23885_restart_video_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} - -int cx23885_video_irq(struct cx23885_dev *dev, u32 status) -{ - u32 mask, count; - int handled = 0; - - mask = cx_read(VID_A_INT_MSK); - if (0 == (status & mask)) - return handled; - cx_write(VID_A_INT_STAT, status); - - dprintk(2, "%s() status = 0x%08x\n", __func__, status); - /* risc op code error */ - if (status & (1 << 16)) { - printk(KERN_WARNING "%s/0: video risc op code error\n", - dev->name); - cx_clear(VID_A_DMA_CTL, 0x11); - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); - } - - /* risc1 y */ - if (status & 0x01) { - spin_lock(&dev->slock); - count = cx_read(VID_A_GPCNT); - cx23885_video_wakeup(dev, &dev->vidq, count); - spin_unlock(&dev->slock); - handled++; - } - /* risc2 y */ - if (status & 0x10) { - dprintk(2, "stopper video\n"); - spin_lock(&dev->slock); - cx23885_restart_video_queue(dev, &dev->vidq); - spin_unlock(&dev->slock); - handled++; - } - - return handled; -} - -/* ----------------------------------------------------------- */ -/* exported stuff */ - -static const struct v4l2_file_operations video_fops = { - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = video_mmap, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, - .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, - .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_g_chip_ident = cx23885_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = cx23885_g_register, - .vidioc_s_register = cx23885_s_register, -#endif -}; - -static struct video_device cx23885_vbi_template; -static struct video_device cx23885_video_template = { - .name = "cx23885-video", - .fops = &video_fops, - .ioctl_ops = &video_ioctl_ops, - .tvnorms = CX23885_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; - -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .ioctl = video_ioctl2, -}; - - -void cx23885_video_unregister(struct cx23885_dev *dev) -{ - dprintk(1, "%s()\n", __func__); - cx23885_irq_remove(dev, 0x01); - - if (dev->video_dev) { - if (video_is_registered(dev->video_dev)) - video_unregister_device(dev->video_dev); - else - video_device_release(dev->video_dev); - dev->video_dev = NULL; - - btcx_riscmem_free(dev->pci, &dev->vidq.stopper); - } -} - -int cx23885_video_register(struct cx23885_dev *dev) -{ - int err; - - dprintk(1, "%s()\n", __func__); - spin_lock_init(&dev->slock); - - /* Initialize VBI template */ - memcpy(&cx23885_vbi_template, &cx23885_video_template, - sizeof(cx23885_vbi_template)); - strcpy(cx23885_vbi_template.name, "cx23885-vbi"); - - dev->tvnorm = cx23885_video_template.current_norm; - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - dev->vidq.timeout.function = cx23885_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, - VID_A_DMA_CTL, 0x11, 0x00); - - /* Don't enable VBI yet */ - - cx23885_irq_add_enable(dev, 0x01); - - if ((TUNER_ABSENT != dev->tuner_type) && - ((dev->tuner_bus == 0) || (dev->tuner_bus == 1))) { - struct v4l2_subdev *sd = NULL; - - if (dev->tuner_addr) - sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_bus[dev->tuner_bus].i2c_adap, - "tuner", dev->tuner_addr, NULL); - else - sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_bus[dev->tuner_bus].i2c_adap, - "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV)); - if (sd) { - struct tuner_setup tun_setup; - - memset(&tun_setup, 0, sizeof(tun_setup)); - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = v4l2_i2c_subdev_addr(sd); - tun_setup.tuner_callback = cx23885_tuner_callback; - - v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup); - - if (dev->board == CX23885_BOARD_LEADTEK_WINFAST_PXTV1200) { - struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64 - }; - struct v4l2_priv_tun_config cfg = { - .tuner = dev->tuner_type, - .priv = &ctrl - }; - v4l2_subdev_call(sd, tuner, s_config, &cfg); - } - } - } - - - /* register v4l devices */ - dev->video_dev = cx23885_vdev_init(dev, dev->pci, - &cx23885_video_template, "video"); - err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, - video_nr[dev->nr]); - if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - goto fail_unreg; - } - printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", - dev->name, video_device_node_name(dev->video_dev)); - /* initial device configuration */ - mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, dev->tvnorm); - init_controls(dev); - cx23885_video_mux(dev, 0); - mutex_unlock(&dev->lock); - - return 0; - -fail_unreg: - cx23885_video_unregister(dev); - return err; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23888-ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23888-ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23888-ir.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23888-ir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1269 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * CX23888 Integrated Consumer Infrared Controller - * - * Copyright (C) 2009 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include -#include - -#include -#include -#include - -#include "cx23885.h" - -static unsigned int ir_888_debug; -module_param(ir_888_debug, int, 0644); -MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]"); - -#define CX23888_IR_REG_BASE 0x170000 -/* - * These CX23888 register offsets have a straightforward one to one mapping - * to the CX23885 register offsets of 0x200 through 0x218 - */ -#define CX23888_IR_CNTRL_REG 0x170000 -#define CNTRL_WIN_3_3 0x00000000 -#define CNTRL_WIN_4_3 0x00000001 -#define CNTRL_WIN_3_4 0x00000002 -#define CNTRL_WIN_4_4 0x00000003 -#define CNTRL_WIN 0x00000003 -#define CNTRL_EDG_NONE 0x00000000 -#define CNTRL_EDG_FALL 0x00000004 -#define CNTRL_EDG_RISE 0x00000008 -#define CNTRL_EDG_BOTH 0x0000000C -#define CNTRL_EDG 0x0000000C -#define CNTRL_DMD 0x00000010 -#define CNTRL_MOD 0x00000020 -#define CNTRL_RFE 0x00000040 -#define CNTRL_TFE 0x00000080 -#define CNTRL_RXE 0x00000100 -#define CNTRL_TXE 0x00000200 -#define CNTRL_RIC 0x00000400 -#define CNTRL_TIC 0x00000800 -#define CNTRL_CPL 0x00001000 -#define CNTRL_LBM 0x00002000 -#define CNTRL_R 0x00004000 -/* CX23888 specific control flag */ -#define CNTRL_IVO 0x00008000 - -#define CX23888_IR_TXCLK_REG 0x170004 -#define TXCLK_TCD 0x0000FFFF - -#define CX23888_IR_RXCLK_REG 0x170008 -#define RXCLK_RCD 0x0000FFFF - -#define CX23888_IR_CDUTY_REG 0x17000C -#define CDUTY_CDC 0x0000000F - -#define CX23888_IR_STATS_REG 0x170010 -#define STATS_RTO 0x00000001 -#define STATS_ROR 0x00000002 -#define STATS_RBY 0x00000004 -#define STATS_TBY 0x00000008 -#define STATS_RSR 0x00000010 -#define STATS_TSR 0x00000020 - -#define CX23888_IR_IRQEN_REG 0x170014 -#define IRQEN_RTE 0x00000001 -#define IRQEN_ROE 0x00000002 -#define IRQEN_RSE 0x00000010 -#define IRQEN_TSE 0x00000020 - -#define CX23888_IR_FILTR_REG 0x170018 -#define FILTR_LPF 0x0000FFFF - -/* This register doesn't follow the pattern; it's 0x23C on a CX23885 */ -#define CX23888_IR_FIFO_REG 0x170040 -#define FIFO_RXTX 0x0000FFFF -#define FIFO_RXTX_LVL 0x00010000 -#define FIFO_RXTX_RTO 0x0001FFFF -#define FIFO_RX_NDV 0x00020000 -#define FIFO_RX_DEPTH 8 -#define FIFO_TX_DEPTH 8 - -/* CX23888 unique registers */ -#define CX23888_IR_SEEDP_REG 0x17001C -#define CX23888_IR_TIMOL_REG 0x170020 -#define CX23888_IR_WAKE0_REG 0x170024 -#define CX23888_IR_WAKE1_REG 0x170028 -#define CX23888_IR_WAKE2_REG 0x17002C -#define CX23888_IR_MASK0_REG 0x170030 -#define CX23888_IR_MASK1_REG 0x170034 -#define CX23888_IR_MAKS2_REG 0x170038 -#define CX23888_IR_DPIPG_REG 0x17003C -#define CX23888_IR_LEARN_REG 0x170044 - -#define CX23888_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */ -#define CX23888_IR_REFCLK_FREQ (CX23888_VIDCLK_FREQ / 2) - -/* - * We use this union internally for convenience, but callers to tx_write - * and rx_read will be expecting records of type struct ir_raw_event. - * Always ensure the size of this union is dictated by struct ir_raw_event. - */ -union cx23888_ir_fifo_rec { - u32 hw_fifo_data; - struct ir_raw_event ir_core_data; -}; - -#define CX23888_IR_RX_KFIFO_SIZE (256 * sizeof(union cx23888_ir_fifo_rec)) -#define CX23888_IR_TX_KFIFO_SIZE (256 * sizeof(union cx23888_ir_fifo_rec)) - -struct cx23888_ir_state { - struct v4l2_subdev sd; - struct cx23885_dev *dev; - u32 id; - u32 rev; - - struct v4l2_subdev_ir_parameters rx_params; - struct mutex rx_params_lock; - atomic_t rxclk_divider; - atomic_t rx_invert; - - struct kfifo rx_kfifo; - spinlock_t rx_kfifo_lock; - - struct v4l2_subdev_ir_parameters tx_params; - struct mutex tx_params_lock; - atomic_t txclk_divider; -}; - -static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd) -{ - return v4l2_get_subdevdata(sd); -} - -/* - * IR register block read and write functions - */ -static -inline int cx23888_ir_write4(struct cx23885_dev *dev, u32 addr, u32 value) -{ - cx_write(addr, value); - return 0; -} - -static inline u32 cx23888_ir_read4(struct cx23885_dev *dev, u32 addr) -{ - return cx_read(addr); -} - -static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr, - u32 and_mask, u32 or_value) -{ - cx_andor(addr, ~and_mask, or_value); - return 0; -} - -/* - * Rx and Tx Clock Divider register computations - * - * Note the largest clock divider value of 0xffff corresponds to: - * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns - * which fits in 21 bits, so we'll use unsigned int for time arguments. - */ -static inline u16 count_to_clock_divider(unsigned int d) -{ - if (d > RXCLK_RCD + 1) - d = RXCLK_RCD; - else if (d < 2) - d = 1; - else - d--; - return (u16) d; -} - -static inline u16 ns_to_clock_divider(unsigned int ns) -{ - return count_to_clock_divider( - DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000)); -} - -static inline unsigned int clock_divider_to_ns(unsigned int divider) -{ - /* Period of the Rx or Tx clock in ns */ - return DIV_ROUND_CLOSEST((divider + 1) * 1000, - CX23888_IR_REFCLK_FREQ / 1000000); -} - -static inline u16 carrier_freq_to_clock_divider(unsigned int freq) -{ - return count_to_clock_divider( - DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * 16)); -} - -static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) -{ - return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16); -} - -static inline u16 freq_to_clock_divider(unsigned int freq, - unsigned int rollovers) -{ - return count_to_clock_divider( - DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * rollovers)); -} - -static inline unsigned int clock_divider_to_freq(unsigned int divider, - unsigned int rollovers) -{ - return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, - (divider + 1) * rollovers); -} - -/* - * Low Pass Filter register calculations - * - * Note the largest count value of 0xffff corresponds to: - * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns - * which fits in 21 bits, so we'll use unsigned int for time arguments. - */ -static inline u16 count_to_lpf_count(unsigned int d) -{ - if (d > FILTR_LPF) - d = FILTR_LPF; - else if (d < 4) - d = 0; - return (u16) d; -} - -static inline u16 ns_to_lpf_count(unsigned int ns) -{ - return count_to_lpf_count( - DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000)); -} - -static inline unsigned int lpf_count_to_ns(unsigned int count) -{ - /* Duration of the Low Pass Filter rejection window in ns */ - return DIV_ROUND_CLOSEST(count * 1000, - CX23888_IR_REFCLK_FREQ / 1000000); -} - -static inline unsigned int lpf_count_to_us(unsigned int count) -{ - /* Duration of the Low Pass Filter rejection window in us */ - return DIV_ROUND_CLOSEST(count, CX23888_IR_REFCLK_FREQ / 1000000); -} - -/* - * FIFO register pulse width count compuations - */ -static u32 clock_divider_to_resolution(u16 divider) -{ - /* - * Resolution is the duration of 1 tick of the readable portion of - * of the pulse width counter as read from the FIFO. The two lsb's are - * not readable, hence the << 2. This function returns ns. - */ - return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, - CX23888_IR_REFCLK_FREQ / 1000000); -} - -static u64 pulse_width_count_to_ns(u16 count, u16 divider) -{ - u64 n; - u32 rem; - - /* - * The 2 lsb's of the pulse width timer count are not readable, hence - * the (count << 2) | 0x3 - */ - n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */ - rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */ - if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2) - n++; - return n; -} - -static unsigned int pulse_width_count_to_us(u16 count, u16 divider) -{ - u64 n; - u32 rem; - - /* - * The 2 lsb's of the pulse width timer count are not readable, hence - * the (count << 2) | 0x3 - */ - n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */ - rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => us */ - if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2) - n++; - return (unsigned int) n; -} - -/* - * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts - * - * The total pulse clock count is an 18 bit pulse width timer count as the most - * significant part and (up to) 16 bit clock divider count as a modulus. - * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse - * width timer count's least significant bit. - */ -static u64 ns_to_pulse_clocks(u32 ns) -{ - u64 clocks; - u32 rem; - clocks = CX23888_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */ - rem = do_div(clocks, 1000); /* /1000 = cycles */ - if (rem >= 1000 / 2) - clocks++; - return clocks; -} - -static u16 pulse_clocks_to_clock_divider(u64 count) -{ - u32 rem; - - rem = do_div(count, (FIFO_RXTX << 2) | 0x3); - - /* net result needs to be rounded down and decremented by 1 */ - if (count > RXCLK_RCD + 1) - count = RXCLK_RCD; - else if (count < 2) - count = 1; - else - count--; - return (u16) count; -} - -/* - * IR Control Register helpers - */ -enum tx_fifo_watermark { - TX_FIFO_HALF_EMPTY = 0, - TX_FIFO_EMPTY = CNTRL_TIC, -}; - -enum rx_fifo_watermark { - RX_FIFO_HALF_FULL = 0, - RX_FIFO_NOT_EMPTY = CNTRL_RIC, -}; - -static inline void control_tx_irq_watermark(struct cx23885_dev *dev, - enum tx_fifo_watermark level) -{ - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_TIC, level); -} - -static inline void control_rx_irq_watermark(struct cx23885_dev *dev, - enum rx_fifo_watermark level) -{ - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_RIC, level); -} - -static inline void control_tx_enable(struct cx23885_dev *dev, bool enable) -{ - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE), - enable ? (CNTRL_TXE | CNTRL_TFE) : 0); -} - -static inline void control_rx_enable(struct cx23885_dev *dev, bool enable) -{ - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE), - enable ? (CNTRL_RXE | CNTRL_RFE) : 0); -} - -static inline void control_tx_modulation_enable(struct cx23885_dev *dev, - bool enable) -{ - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_MOD, - enable ? CNTRL_MOD : 0); -} - -static inline void control_rx_demodulation_enable(struct cx23885_dev *dev, - bool enable) -{ - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_DMD, - enable ? CNTRL_DMD : 0); -} - -static inline void control_rx_s_edge_detection(struct cx23885_dev *dev, - u32 edge_types) -{ - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_EDG_BOTH, - edge_types & CNTRL_EDG_BOTH); -} - -static void control_rx_s_carrier_window(struct cx23885_dev *dev, - unsigned int carrier, - unsigned int *carrier_range_low, - unsigned int *carrier_range_high) -{ - u32 v; - unsigned int c16 = carrier * 16; - - if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) { - v = CNTRL_WIN_3_4; - *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4); - } else { - v = CNTRL_WIN_3_3; - *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3); - } - - if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { - v |= CNTRL_WIN_4_3; - *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); - } else { - v |= CNTRL_WIN_3_3; - *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); - } - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_WIN, v); -} - -static inline void control_tx_polarity_invert(struct cx23885_dev *dev, - bool invert) -{ - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_CPL, - invert ? CNTRL_CPL : 0); -} - -static inline void control_tx_level_invert(struct cx23885_dev *dev, - bool invert) -{ - cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_IVO, - invert ? CNTRL_IVO : 0); -} - -/* - * IR Rx & Tx Clock Register helpers - */ -static unsigned int txclk_tx_s_carrier(struct cx23885_dev *dev, - unsigned int freq, - u16 *divider) -{ - *divider = carrier_freq_to_clock_divider(freq); - cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); - return clock_divider_to_carrier_freq(*divider); -} - -static unsigned int rxclk_rx_s_carrier(struct cx23885_dev *dev, - unsigned int freq, - u16 *divider) -{ - *divider = carrier_freq_to_clock_divider(freq); - cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); - return clock_divider_to_carrier_freq(*divider); -} - -static u32 txclk_tx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, - u16 *divider) -{ - u64 pulse_clocks; - - if (ns > IR_MAX_DURATION) - ns = IR_MAX_DURATION; - pulse_clocks = ns_to_pulse_clocks(ns); - *divider = pulse_clocks_to_clock_divider(pulse_clocks); - cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); - return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); -} - -static u32 rxclk_rx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, - u16 *divider) -{ - u64 pulse_clocks; - - if (ns > IR_MAX_DURATION) - ns = IR_MAX_DURATION; - pulse_clocks = ns_to_pulse_clocks(ns); - *divider = pulse_clocks_to_clock_divider(pulse_clocks); - cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); - return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); -} - -/* - * IR Tx Carrier Duty Cycle register helpers - */ -static unsigned int cduty_tx_s_duty_cycle(struct cx23885_dev *dev, - unsigned int duty_cycle) -{ - u32 n; - n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */ - if (n != 0) - n--; - if (n > 15) - n = 15; - cx23888_ir_write4(dev, CX23888_IR_CDUTY_REG, n); - return DIV_ROUND_CLOSEST((n + 1) * 100, 16); -} - -/* - * IR Filter Register helpers - */ -static u32 filter_rx_s_min_width(struct cx23885_dev *dev, u32 min_width_ns) -{ - u32 count = ns_to_lpf_count(min_width_ns); - cx23888_ir_write4(dev, CX23888_IR_FILTR_REG, count); - return lpf_count_to_ns(count); -} - -/* - * IR IRQ Enable Register helpers - */ -static inline void irqenable_rx(struct cx23885_dev *dev, u32 mask) -{ - mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE); - cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, - ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask); -} - -static inline void irqenable_tx(struct cx23885_dev *dev, u32 mask) -{ - mask &= IRQEN_TSE; - cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, ~IRQEN_TSE, mask); -} - -/* - * V4L2 Subdevice IR Ops - */ -static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, - bool *handled) -{ - struct cx23888_ir_state *state = to_state(sd); - struct cx23885_dev *dev = state->dev; - unsigned long flags; - - u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); - u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); - u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); - - union cx23888_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; - unsigned int i, j, k; - u32 events, v; - int tsr, rsr, rto, ror, tse, rse, rte, roe, kror; - - tsr = stats & STATS_TSR; /* Tx FIFO Service Request */ - rsr = stats & STATS_RSR; /* Rx FIFO Service Request */ - rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */ - ror = stats & STATS_ROR; /* Rx FIFO Over Run */ - - tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ - rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ - rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ - roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ - - *handled = false; - v4l2_dbg(2, ir_888_debug, sd, "IRQ Status: %s %s %s %s %s %s\n", - tsr ? "tsr" : " ", rsr ? "rsr" : " ", - rto ? "rto" : " ", ror ? "ror" : " ", - stats & STATS_TBY ? "tby" : " ", - stats & STATS_RBY ? "rby" : " "); - - v4l2_dbg(2, ir_888_debug, sd, "IRQ Enables: %s %s %s %s\n", - tse ? "tse" : " ", rse ? "rse" : " ", - rte ? "rte" : " ", roe ? "roe" : " "); - - /* - * Transmitter interrupt service - */ - if (tse && tsr) { - /* - * TODO: - * Check the watermark threshold setting - * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo - * Push the data to the hardware FIFO. - * If there was nothing more to send in the tx_kfifo, disable - * the TSR IRQ and notify the v4l2_device. - * If there was something in the tx_kfifo, check the tx_kfifo - * level and notify the v4l2_device, if it is low. - */ - /* For now, inhibit TSR interrupt until Tx is implemented */ - irqenable_tx(dev, 0); - events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; - v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events); - *handled = true; - } - - /* - * Receiver interrupt service - */ - kror = 0; - if ((rse && rsr) || (rte && rto)) { - /* - * Receive data on RSR to clear the STATS_RSR. - * Receive data on RTO, since we may not have yet hit the RSR - * watermark when we receive the RTO. - */ - for (i = 0, v = FIFO_RX_NDV; - (v & FIFO_RX_NDV) && !kror; i = 0) { - for (j = 0; - (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) { - v = cx23888_ir_read4(dev, CX23888_IR_FIFO_REG); - rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV; - i++; - } - if (i == 0) - break; - j = i * sizeof(union cx23888_ir_fifo_rec); - k = kfifo_in_locked(&state->rx_kfifo, - (unsigned char *) rx_data, j, - &state->rx_kfifo_lock); - if (k != j) - kror++; /* rx_kfifo over run */ - } - *handled = true; - } - - events = 0; - v = 0; - if (kror) { - events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; - v4l2_err(sd, "IR receiver software FIFO overrun\n"); - } - if (roe && ror) { - /* - * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear - * the Rx FIFO Over Run status (STATS_ROR) - */ - v |= CNTRL_RFE; - events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; - v4l2_err(sd, "IR receiver hardware FIFO overrun\n"); - } - if (rte && rto) { - /* - * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear - * the Rx Pulse Width Timer Time Out (STATS_RTO) - */ - v |= CNTRL_RXE; - events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; - } - if (v) { - /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ - cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl & ~v); - cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl); - *handled = true; - } - - spin_lock_irqsave(&state->rx_kfifo_lock, flags); - if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) - events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; - spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); - - if (events) - v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); - return 0; -} - -/* Receiver */ -static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, - ssize_t *num) -{ - struct cx23888_ir_state *state = to_state(sd); - bool invert = (bool) atomic_read(&state->rx_invert); - u16 divider = (u16) atomic_read(&state->rxclk_divider); - - unsigned int i, n; - union cx23888_ir_fifo_rec *p; - unsigned u, v; - - n = count / sizeof(union cx23888_ir_fifo_rec) - * sizeof(union cx23888_ir_fifo_rec); - if (n == 0) { - *num = 0; - return 0; - } - - n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock); - - n /= sizeof(union cx23888_ir_fifo_rec); - *num = n * sizeof(union cx23888_ir_fifo_rec); - - for (p = (union cx23888_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) { - - if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { - /* Assume RTO was because of no IR light input */ - u = 0; - v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); - } else { - u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; - if (invert) - u = u ? 0 : 1; - } - - v = (unsigned) pulse_width_count_to_ns( - (u16) (p->hw_fifo_data & FIFO_RXTX), divider); - if (v > IR_MAX_DURATION) - v = IR_MAX_DURATION; - - init_ir_raw_event(&p->ir_core_data); - p->ir_core_data.pulse = u; - p->ir_core_data.duration = v; - - v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s\n", - v, u ? "mark" : "space"); - } - return 0; -} - -static int cx23888_ir_rx_g_parameters(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *p) -{ - struct cx23888_ir_state *state = to_state(sd); - mutex_lock(&state->rx_params_lock); - memcpy(p, &state->rx_params, sizeof(struct v4l2_subdev_ir_parameters)); - mutex_unlock(&state->rx_params_lock); - return 0; -} - -static int cx23888_ir_rx_shutdown(struct v4l2_subdev *sd) -{ - struct cx23888_ir_state *state = to_state(sd); - struct cx23885_dev *dev = state->dev; - - mutex_lock(&state->rx_params_lock); - - /* Disable or slow down all IR Rx circuits and counters */ - irqenable_rx(dev, 0); - control_rx_enable(dev, false); - control_rx_demodulation_enable(dev, false); - control_rx_s_edge_detection(dev, CNTRL_EDG_NONE); - filter_rx_s_min_width(dev, 0); - cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, RXCLK_RCD); - - state->rx_params.shutdown = true; - - mutex_unlock(&state->rx_params_lock); - return 0; -} - -static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *p) -{ - struct cx23888_ir_state *state = to_state(sd); - struct cx23885_dev *dev = state->dev; - struct v4l2_subdev_ir_parameters *o = &state->rx_params; - u16 rxclk_divider; - - if (p->shutdown) - return cx23888_ir_rx_shutdown(sd); - - if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) - return -ENOSYS; - - mutex_lock(&state->rx_params_lock); - - o->shutdown = p->shutdown; - - o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; - - o->bytes_per_data_element = p->bytes_per_data_element - = sizeof(union cx23888_ir_fifo_rec); - - /* Before we tweak the hardware, we have to disable the receiver */ - irqenable_rx(dev, 0); - control_rx_enable(dev, false); - - control_rx_demodulation_enable(dev, p->modulation); - o->modulation = p->modulation; - - if (p->modulation) { - p->carrier_freq = rxclk_rx_s_carrier(dev, p->carrier_freq, - &rxclk_divider); - - o->carrier_freq = p->carrier_freq; - - o->duty_cycle = p->duty_cycle = 50; - - control_rx_s_carrier_window(dev, p->carrier_freq, - &p->carrier_range_lower, - &p->carrier_range_upper); - o->carrier_range_lower = p->carrier_range_lower; - o->carrier_range_upper = p->carrier_range_upper; - - p->max_pulse_width = - (u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider); - } else { - p->max_pulse_width = - rxclk_rx_s_max_pulse_width(dev, p->max_pulse_width, - &rxclk_divider); - } - o->max_pulse_width = p->max_pulse_width; - atomic_set(&state->rxclk_divider, rxclk_divider); - - p->noise_filter_min_width = - filter_rx_s_min_width(dev, p->noise_filter_min_width); - o->noise_filter_min_width = p->noise_filter_min_width; - - p->resolution = clock_divider_to_resolution(rxclk_divider); - o->resolution = p->resolution; - - /* FIXME - make this dependent on resolution for better performance */ - control_rx_irq_watermark(dev, RX_FIFO_HALF_FULL); - - control_rx_s_edge_detection(dev, CNTRL_EDG_BOTH); - - o->invert_level = p->invert_level; - atomic_set(&state->rx_invert, p->invert_level); - - o->interrupt_enable = p->interrupt_enable; - o->enable = p->enable; - if (p->enable) { - unsigned long flags; - - spin_lock_irqsave(&state->rx_kfifo_lock, flags); - kfifo_reset(&state->rx_kfifo); - /* reset tx_fifo too if there is one... */ - spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); - if (p->interrupt_enable) - irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); - control_rx_enable(dev, p->enable); - } - - mutex_unlock(&state->rx_params_lock); - return 0; -} - -/* Transmitter */ -static int cx23888_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count, - ssize_t *num) -{ - struct cx23888_ir_state *state = to_state(sd); - struct cx23885_dev *dev = state->dev; - /* For now enable the Tx FIFO Service interrupt & pretend we did work */ - irqenable_tx(dev, IRQEN_TSE); - *num = count; - return 0; -} - -static int cx23888_ir_tx_g_parameters(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *p) -{ - struct cx23888_ir_state *state = to_state(sd); - mutex_lock(&state->tx_params_lock); - memcpy(p, &state->tx_params, sizeof(struct v4l2_subdev_ir_parameters)); - mutex_unlock(&state->tx_params_lock); - return 0; -} - -static int cx23888_ir_tx_shutdown(struct v4l2_subdev *sd) -{ - struct cx23888_ir_state *state = to_state(sd); - struct cx23885_dev *dev = state->dev; - - mutex_lock(&state->tx_params_lock); - - /* Disable or slow down all IR Tx circuits and counters */ - irqenable_tx(dev, 0); - control_tx_enable(dev, false); - control_tx_modulation_enable(dev, false); - cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, TXCLK_TCD); - - state->tx_params.shutdown = true; - - mutex_unlock(&state->tx_params_lock); - return 0; -} - -static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *p) -{ - struct cx23888_ir_state *state = to_state(sd); - struct cx23885_dev *dev = state->dev; - struct v4l2_subdev_ir_parameters *o = &state->tx_params; - u16 txclk_divider; - - if (p->shutdown) - return cx23888_ir_tx_shutdown(sd); - - if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) - return -ENOSYS; - - mutex_lock(&state->tx_params_lock); - - o->shutdown = p->shutdown; - - o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; - - o->bytes_per_data_element = p->bytes_per_data_element - = sizeof(union cx23888_ir_fifo_rec); - - /* Before we tweak the hardware, we have to disable the transmitter */ - irqenable_tx(dev, 0); - control_tx_enable(dev, false); - - control_tx_modulation_enable(dev, p->modulation); - o->modulation = p->modulation; - - if (p->modulation) { - p->carrier_freq = txclk_tx_s_carrier(dev, p->carrier_freq, - &txclk_divider); - o->carrier_freq = p->carrier_freq; - - p->duty_cycle = cduty_tx_s_duty_cycle(dev, p->duty_cycle); - o->duty_cycle = p->duty_cycle; - - p->max_pulse_width = - (u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider); - } else { - p->max_pulse_width = - txclk_tx_s_max_pulse_width(dev, p->max_pulse_width, - &txclk_divider); - } - o->max_pulse_width = p->max_pulse_width; - atomic_set(&state->txclk_divider, txclk_divider); - - p->resolution = clock_divider_to_resolution(txclk_divider); - o->resolution = p->resolution; - - /* FIXME - make this dependent on resolution for better performance */ - control_tx_irq_watermark(dev, TX_FIFO_HALF_EMPTY); - - control_tx_polarity_invert(dev, p->invert_carrier_sense); - o->invert_carrier_sense = p->invert_carrier_sense; - - control_tx_level_invert(dev, p->invert_level); - o->invert_level = p->invert_level; - - o->interrupt_enable = p->interrupt_enable; - o->enable = p->enable; - if (p->enable) { - if (p->interrupt_enable) - irqenable_tx(dev, IRQEN_TSE); - control_tx_enable(dev, p->enable); - } - - mutex_unlock(&state->tx_params_lock); - return 0; -} - - -/* - * V4L2 Subdevice Core Ops - */ -static int cx23888_ir_log_status(struct v4l2_subdev *sd) -{ - struct cx23888_ir_state *state = to_state(sd); - struct cx23885_dev *dev = state->dev; - char *s; - int i, j; - - u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); - u32 txclk = cx23888_ir_read4(dev, CX23888_IR_TXCLK_REG) & TXCLK_TCD; - u32 rxclk = cx23888_ir_read4(dev, CX23888_IR_RXCLK_REG) & RXCLK_RCD; - u32 cduty = cx23888_ir_read4(dev, CX23888_IR_CDUTY_REG) & CDUTY_CDC; - u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); - u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); - u32 filtr = cx23888_ir_read4(dev, CX23888_IR_FILTR_REG) & FILTR_LPF; - - v4l2_info(sd, "IR Receiver:\n"); - v4l2_info(sd, "\tEnabled: %s\n", - cntrl & CNTRL_RXE ? "yes" : "no"); - v4l2_info(sd, "\tDemodulation from a carrier: %s\n", - cntrl & CNTRL_DMD ? "enabled" : "disabled"); - v4l2_info(sd, "\tFIFO: %s\n", - cntrl & CNTRL_RFE ? "enabled" : "disabled"); - switch (cntrl & CNTRL_EDG) { - case CNTRL_EDG_NONE: - s = "disabled"; - break; - case CNTRL_EDG_FALL: - s = "falling edge"; - break; - case CNTRL_EDG_RISE: - s = "rising edge"; - break; - case CNTRL_EDG_BOTH: - s = "rising & falling edges"; - break; - default: - s = "??? edge"; - break; - } - v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s); - v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n", - cntrl & CNTRL_R ? "not loaded" : "overflow marker"); - v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", - cntrl & CNTRL_RIC ? "not empty" : "half full or greater"); - v4l2_info(sd, "\tLoopback mode: %s\n", - cntrl & CNTRL_LBM ? "loopback active" : "normal receive"); - if (cntrl & CNTRL_DMD) { - v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n", - clock_divider_to_carrier_freq(rxclk)); - switch (cntrl & CNTRL_WIN) { - case CNTRL_WIN_3_3: - i = 3; - j = 3; - break; - case CNTRL_WIN_4_3: - i = 4; - j = 3; - break; - case CNTRL_WIN_3_4: - i = 3; - j = 4; - break; - case CNTRL_WIN_4_4: - i = 4; - j = 4; - break; - default: - i = 0; - j = 0; - break; - } - v4l2_info(sd, "\tNext carrier edge window: 16 clocks " - "-%1d/+%1d, %u to %u Hz\n", i, j, - clock_divider_to_freq(rxclk, 16 + j), - clock_divider_to_freq(rxclk, 16 - i)); - } - v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n", - pulse_width_count_to_us(FIFO_RXTX, rxclk), - pulse_width_count_to_ns(FIFO_RXTX, rxclk)); - v4l2_info(sd, "\tLow pass filter: %s\n", - filtr ? "enabled" : "disabled"); - if (filtr) - v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " - "%u ns\n", - lpf_count_to_us(filtr), - lpf_count_to_ns(filtr)); - v4l2_info(sd, "\tPulse width timer timed-out: %s\n", - stats & STATS_RTO ? "yes" : "no"); - v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", - irqen & IRQEN_RTE ? "enabled" : "disabled"); - v4l2_info(sd, "\tFIFO overrun: %s\n", - stats & STATS_ROR ? "yes" : "no"); - v4l2_info(sd, "\tFIFO overrun interrupt: %s\n", - irqen & IRQEN_ROE ? "enabled" : "disabled"); - v4l2_info(sd, "\tBusy: %s\n", - stats & STATS_RBY ? "yes" : "no"); - v4l2_info(sd, "\tFIFO service requested: %s\n", - stats & STATS_RSR ? "yes" : "no"); - v4l2_info(sd, "\tFIFO service request interrupt: %s\n", - irqen & IRQEN_RSE ? "enabled" : "disabled"); - - v4l2_info(sd, "IR Transmitter:\n"); - v4l2_info(sd, "\tEnabled: %s\n", - cntrl & CNTRL_TXE ? "yes" : "no"); - v4l2_info(sd, "\tModulation onto a carrier: %s\n", - cntrl & CNTRL_MOD ? "enabled" : "disabled"); - v4l2_info(sd, "\tFIFO: %s\n", - cntrl & CNTRL_TFE ? "enabled" : "disabled"); - v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", - cntrl & CNTRL_TIC ? "not empty" : "half full or less"); - v4l2_info(sd, "\tOutput pin level inversion %s\n", - cntrl & CNTRL_IVO ? "yes" : "no"); - v4l2_info(sd, "\tCarrier polarity: %s\n", - cntrl & CNTRL_CPL ? "space:burst mark:noburst" - : "space:noburst mark:burst"); - if (cntrl & CNTRL_MOD) { - v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n", - clock_divider_to_carrier_freq(txclk)); - v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n", - cduty + 1); - } - v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n", - pulse_width_count_to_us(FIFO_RXTX, txclk), - pulse_width_count_to_ns(FIFO_RXTX, txclk)); - v4l2_info(sd, "\tBusy: %s\n", - stats & STATS_TBY ? "yes" : "no"); - v4l2_info(sd, "\tFIFO service requested: %s\n", - stats & STATS_TSR ? "yes" : "no"); - v4l2_info(sd, "\tFIFO service request interrupt: %s\n", - irqen & IRQEN_TSE ? "enabled" : "disabled"); - - return 0; -} - -static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match) -{ - return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2; -} - -static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct cx23888_ir_state *state = to_state(sd); - - if (cx23888_ir_dbg_match(&chip->match)) { - chip->ident = state->id; - chip->revision = state->rev; - } - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx23888_ir_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct cx23888_ir_state *state = to_state(sd); - u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; - - if (!cx23888_ir_dbg_match(®->match)) - return -EINVAL; - if ((addr & 0x3) != 0) - return -EINVAL; - if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->size = 4; - reg->val = cx23888_ir_read4(state->dev, addr); - return 0; -} - -static int cx23888_ir_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct cx23888_ir_state *state = to_state(sd); - u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; - - if (!cx23888_ir_dbg_match(®->match)) - return -EINVAL; - if ((addr & 0x3) != 0) - return -EINVAL; - if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - cx23888_ir_write4(state->dev, addr, reg->val); - return 0; -} -#endif - -static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = { - .g_chip_ident = cx23888_ir_g_chip_ident, - .log_status = cx23888_ir_log_status, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = cx23888_ir_g_register, - .s_register = cx23888_ir_s_register, -#endif - .interrupt_service_routine = cx23888_ir_irq_handler, -}; - -static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = { - .rx_read = cx23888_ir_rx_read, - .rx_g_parameters = cx23888_ir_rx_g_parameters, - .rx_s_parameters = cx23888_ir_rx_s_parameters, - - .tx_write = cx23888_ir_tx_write, - .tx_g_parameters = cx23888_ir_tx_g_parameters, - .tx_s_parameters = cx23888_ir_tx_s_parameters, -}; - -static const struct v4l2_subdev_ops cx23888_ir_controller_ops = { - .core = &cx23888_ir_core_ops, - .ir = &cx23888_ir_ir_ops, -}; - -static const struct v4l2_subdev_ir_parameters default_rx_params = { - .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec), - .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, - - .enable = false, - .interrupt_enable = false, - .shutdown = true, - - .modulation = true, - .carrier_freq = 36000, /* 36 kHz - RC-5, RC-6, and RC-6A carrier */ - - /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ - /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ - .noise_filter_min_width = 333333, /* ns */ - .carrier_range_lower = 35000, - .carrier_range_upper = 37000, - .invert_level = false, -}; - -static const struct v4l2_subdev_ir_parameters default_tx_params = { - .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec), - .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, - - .enable = false, - .interrupt_enable = false, - .shutdown = true, - - .modulation = true, - .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ - .duty_cycle = 25, /* 25 % - RC-5 carrier */ - .invert_level = false, - .invert_carrier_sense = false, -}; - -int cx23888_ir_probe(struct cx23885_dev *dev) -{ - struct cx23888_ir_state *state; - struct v4l2_subdev *sd; - struct v4l2_subdev_ir_parameters default_params; - int ret; - - state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - - spin_lock_init(&state->rx_kfifo_lock); - if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL)) - return -ENOMEM; - - state->dev = dev; - state->id = V4L2_IDENT_CX23888_IR; - state->rev = 0; - sd = &state->sd; - - v4l2_subdev_init(sd, &cx23888_ir_controller_ops); - v4l2_set_subdevdata(sd, state); - /* FIXME - fix the formatting of dev->v4l2_dev.name and use it */ - snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name); - sd->grp_id = CX23885_HW_888_IR; - - ret = v4l2_device_register_subdev(&dev->v4l2_dev, sd); - if (ret == 0) { - /* - * Ensure no interrupts arrive from '888 specific conditions, - * since we ignore them in this driver to have commonality with - * similar IR controller cores. - */ - cx23888_ir_write4(dev, CX23888_IR_IRQEN_REG, 0); - - mutex_init(&state->rx_params_lock); - memcpy(&default_params, &default_rx_params, - sizeof(struct v4l2_subdev_ir_parameters)); - v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); - - mutex_init(&state->tx_params_lock); - memcpy(&default_params, &default_tx_params, - sizeof(struct v4l2_subdev_ir_parameters)); - v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); - } else { - kfifo_free(&state->rx_kfifo); - } - return ret; -} - -int cx23888_ir_remove(struct cx23885_dev *dev) -{ - struct v4l2_subdev *sd; - struct cx23888_ir_state *state; - - sd = cx23885_find_hw(dev, CX23885_HW_888_IR); - if (sd == NULL) - return -ENODEV; - - cx23888_ir_rx_shutdown(sd); - cx23888_ir_tx_shutdown(sd); - - state = to_state(sd); - v4l2_device_unregister_subdev(sd); - kfifo_free(&state->rx_kfifo); - kfree(state); - /* Nothing more to free() as state held the actual v4l2_subdev object */ - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23888-ir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23888-ir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23888-ir.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/cx23888-ir.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -/* - * Driver for the Conexant CX23885/7/8 PCIe bridge - * - * CX23888 Integrated Consumer Infrared Controller - * - * Copyright (C) 2009 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef _CX23888_IR_H_ -#define _CX23888_IR_H_ -int cx23888_ir_probe(struct cx23885_dev *dev); -int cx23888_ir_remove(struct cx23885_dev *dev); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -config VIDEO_CX23885 - tristate "Conexant cx23885 (2388x successor) support" - depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND - select SND_PCM - select I2C_ALGOBIT - select VIDEO_BTCX - select VIDEO_TUNER - select VIDEO_TVEEPROM - depends on RC_CORE - select VIDEOBUF_DVB - select VIDEOBUF_DMA_SG - select VIDEO_CX25840 - select VIDEO_CX2341X - select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select DVB_S5H1409 if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TDA10048 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV6110 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE - select DVB_DS3000 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE - ---help--- - This is a video4linux driver for Conexant 23885 based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx23885 - -config MEDIA_ALTERA_CI - tristate "Altera FPGA based CI module" - depends on VIDEO_CX23885 && DVB_CORE - select STAPL_ALTERA - ---help--- - An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. - - To compile this driver as a module, choose M here: the - module will be called altera-ci diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \ - cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \ - cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \ - cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \ - cx23885-f300.o - -obj-$(CONFIG_VIDEO_CX23885) += cx23885.o -obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends - -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-eeprom.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-eeprom.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-eeprom.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-eeprom.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ - -/* - * netup-eeprom.c - * - * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card - * - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Abylay Ospan - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -# -#include "cx23885.h" -#include "netup-eeprom.h" - -#define EEPROM_I2C_ADDR 0x50 - -int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr) -{ - int ret; - unsigned char buf[2]; - - /* Read from EEPROM */ - struct i2c_msg msg[] = { - { - .addr = EEPROM_I2C_ADDR, - .flags = 0, - .buf = &buf[0], - .len = 1 - }, { - .addr = EEPROM_I2C_ADDR, - .flags = I2C_M_RD, - .buf = &buf[1], - .len = 1 - } - - }; - - buf[0] = addr; - buf[1] = 0x0; - - ret = i2c_transfer(i2c_adap, msg, 2); - - if (ret != 2) { - printk(KERN_ERR "eeprom i2c read error, status=%d\n", ret); - return -1; - } - - return buf[1]; -}; - -int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data) -{ - int ret; - unsigned char bufw[2]; - - /* Write into EEPROM */ - struct i2c_msg msg[] = { - { - .addr = EEPROM_I2C_ADDR, - .flags = 0, - .buf = &bufw[0], - .len = 2 - } - }; - - bufw[0] = addr; - bufw[1] = data; - - ret = i2c_transfer(i2c_adap, msg, 1); - - if (ret != 1) { - printk(KERN_ERR "eeprom i2c write error, status=%d\n", ret); - return -1; - } - - mdelay(10); /* prophylactic delay, datasheet write cycle time = 5 ms */ - return 0; -}; - -void netup_get_card_info(struct i2c_adapter *i2c_adap, - struct netup_card_info *cinfo) -{ - int i, j; - - cinfo->rev = netup_eeprom_read(i2c_adap, 63); - - for (i = 64, j = 0; i < 70; i++, j++) - cinfo->port[0].mac[j] = netup_eeprom_read(i2c_adap, i); - - for (i = 70, j = 0; i < 76; i++, j++) - cinfo->port[1].mac[j] = netup_eeprom_read(i2c_adap, i); -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-eeprom.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-eeprom.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-eeprom.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-eeprom.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * netup-eeprom.h - * - * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card - * - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Abylay Ospan - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef NETUP_EEPROM_H -#define NETUP_EEPROM_H - -struct netup_port_info { - u8 mac[6];/* card MAC address */ -}; - -struct netup_card_info { - struct netup_port_info port[2];/* ports - 1,2 */ - u8 rev;/* card revision */ -}; - -extern int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr); -extern int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data); -extern void netup_get_card_info(struct i2c_adapter *i2c_adap, - struct netup_card_info *cinfo); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-init.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-init.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-init.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-init.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -/* - * netup-init.c - * - * NetUP Dual DVB-S2 CI driver - * - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * Copyright (C) 2009 Abylay Ospan - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx23885.h" - -static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val) -{ - int ret; - u8 buf[3]; - struct i2c_msg msg = { - .addr = 0x88 >> 1, - .flags = 0, - .buf = buf, - .len = 3 - }; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - buf[2] = val; - - ret = i2c_transfer(i2c, &msg, 1); - - if (ret != 1) - printk(KERN_ERR "%s: i2c write error!\n", __func__); -} - -static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val) -{ - int ret; - u8 buf[6]; - struct i2c_msg msg = { - .addr = 0x88 >> 1, - .flags = 0, - .buf = buf, - .len = 6 - }; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - buf[2] = val & 0xff; - buf[3] = (val >> 8) & 0xff; - buf[4] = (val >> 16) & 0xff; - buf[5] = val >> 24; - - ret = i2c_transfer(i2c, &msg, 1); - - if (ret != 1) - printk(KERN_ERR "%s: i2c write error!\n", __func__); -} - -static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg) -{ - int ret; - u8 buf[2]; - struct i2c_msg msg = { - .addr = 0x88 >> 1, - .flags = 0, - .buf = buf, - .len = 2 - }; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; - - ret = i2c_transfer(i2c, &msg, 1); - - if (ret != 1) - printk(KERN_ERR "%s: i2c write error!\n", __func__); - - msg.flags = I2C_M_RD; - msg.len = 1; - - ret = i2c_transfer(i2c, &msg, 1); - - if (ret != 1) - printk(KERN_ERR "%s: i2c read error!\n", __func__); - - return buf[0]; -} - -static void i2c_av_and_or(struct i2c_adapter *i2c, u16 reg, unsigned and_mask, - u8 or_value) -{ - i2c_av_write(i2c, reg, (i2c_av_read(i2c, reg) & and_mask) | or_value); -} -/* set 27MHz on AUX_CLK */ -void netup_initialize(struct cx23885_dev *dev) -{ - struct cx23885_i2c *i2c_bus = &dev->i2c_bus[2]; - struct i2c_adapter *i2c = &i2c_bus->i2c_adap; - - /* Stop microcontroller */ - i2c_av_and_or(i2c, 0x803, ~0x10, 0x00); - - /* Aux PLL frac for 27 MHz */ - i2c_av_write4(i2c, 0x114, 0xea0eb3); - - /* Aux PLL int for 27 MHz */ - i2c_av_write4(i2c, 0x110, 0x090319); - - /* start microcontroller */ - i2c_av_and_or(i2c, 0x803, ~0x10, 0x10); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-init.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-init.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-init.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx23885/netup-init.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -/* - * netup-init.h - * - * NetUP Dual DVB-S2 CI driver - * - * Copyright (C) 2009 NetUP Inc. - * Copyright (C) 2009 Igor M. Liplianin - * Copyright (C) 2009 Abylay Ospan - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -extern void netup_initialize(struct cx23885_dev *dev); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-audio.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-audio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,571 +0,0 @@ -/* cx25840 audio functions - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#include -#include -#include -#include - -#include "cx25840-core.h" - -/* - * Note: The PLL and SRC parameters are based on a reference frequency that - * would ideally be: - * - * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz - * - * However, it's not the exact reference frequency that matters, only that the - * firmware and modules that comprise the driver for a particular board all - * use the same value (close to the ideal value). - * - * Comments below will note which reference frequency is assumed for various - * parameters. They will usually be one of - * - * ref_freq = 28.636360 MHz - * or - * ref_freq = 28.636363 MHz - */ - -static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - - if (state->aud_input != CX25840_AUDIO_SERIAL) { - switch (freq) { - case 32000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10 - */ - cx25840_write4(client, 0x108, 0x1006040f); - - /* - * VID_PLL Fraction (register 0x10c) = 0x2be2fe - * 28636360 * 0xf.15f17f0/4 = 108 MHz - * 432 MHz pre-postdivide - */ - - /* - * AUX_PLL Fraction = 0x1bb39ee - * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384 - * 196.6 MHz pre-postdivide - * FIXME < 200 MHz is out of specified valid range - * FIXME 28636363 ref_freq doesn't match VID PLL ref - */ - cx25840_write4(client, 0x110, 0x01bb39ee); - - /* - * SA_MCLK_SEL = 1 - * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider - */ - cx25840_write(client, 0x127, 0x50); - - if (is_cx2583x(state)) - break; - - /* src3/4/6_ctl */ - /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */ - cx25840_write4(client, 0x900, 0x0801f77f); - cx25840_write4(client, 0x904, 0x0801f77f); - cx25840_write4(client, 0x90c, 0x0801f77f); - break; - - case 44100: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10 - */ - cx25840_write4(client, 0x108, 0x1009040f); - - /* - * VID_PLL Fraction (register 0x10c) = 0x2be2fe - * 28636360 * 0xf.15f17f0/4 = 108 MHz - * 432 MHz pre-postdivide - */ - - /* - * AUX_PLL Fraction = 0x0ec6bd6 - * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384 - * 271 MHz pre-postdivide - * FIXME 28636363 ref_freq doesn't match VID PLL ref - */ - cx25840_write4(client, 0x110, 0x00ec6bd6); - - /* - * SA_MCLK_SEL = 1 - * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider - */ - cx25840_write(client, 0x127, 0x50); - - if (is_cx2583x(state)) - break; - - /* src3/4/6_ctl */ - /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */ - cx25840_write4(client, 0x900, 0x08016d59); - cx25840_write4(client, 0x904, 0x08016d59); - cx25840_write4(client, 0x90c, 0x08016d59); - break; - - case 48000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10 - */ - cx25840_write4(client, 0x108, 0x100a040f); - - /* - * VID_PLL Fraction (register 0x10c) = 0x2be2fe - * 28636360 * 0xf.15f17f0/4 = 108 MHz - * 432 MHz pre-postdivide - */ - - /* - * AUX_PLL Fraction = 0x098d6e5 - * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384 - * 295 MHz pre-postdivide - * FIXME 28636363 ref_freq doesn't match VID PLL ref - */ - cx25840_write4(client, 0x110, 0x0098d6e5); - - /* - * SA_MCLK_SEL = 1 - * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider - */ - cx25840_write(client, 0x127, 0x50); - - if (is_cx2583x(state)) - break; - - /* src3/4/6_ctl */ - /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ - cx25840_write4(client, 0x900, 0x08014faa); - cx25840_write4(client, 0x904, 0x08014faa); - cx25840_write4(client, 0x90c, 0x08014faa); - break; - } - } else { - switch (freq) { - case 32000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e - */ - cx25840_write4(client, 0x108, 0x1e08040f); - - /* - * VID_PLL Fraction (register 0x10c) = 0x2be2fe - * 28636360 * 0xf.15f17f0/4 = 108 MHz - * 432 MHz pre-postdivide - */ - - /* - * AUX_PLL Fraction = 0x12a0869 - * 28636363 * 0x8.9504348/0x1e = 32000 * 256 - * 246 MHz pre-postdivide - * FIXME 28636363 ref_freq doesn't match VID PLL ref - */ - cx25840_write4(client, 0x110, 0x012a0869); - - /* - * SA_MCLK_SEL = 1 - * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider - */ - cx25840_write(client, 0x127, 0x54); - - if (is_cx2583x(state)) - break; - - /* src1_ctl */ - /* 0x1.0000 = 32000/32000 */ - cx25840_write4(client, 0x8f8, 0x08010000); - - /* src3/4/6_ctl */ - /* 0x2.0000 = 2 * (32000/32000) */ - cx25840_write4(client, 0x900, 0x08020000); - cx25840_write4(client, 0x904, 0x08020000); - cx25840_write4(client, 0x90c, 0x08020000); - break; - - case 44100: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18 - */ - cx25840_write4(client, 0x108, 0x1809040f); - - /* - * VID_PLL Fraction (register 0x10c) = 0x2be2fe - * 28636360 * 0xf.15f17f0/4 = 108 MHz - * 432 MHz pre-postdivide - */ - - /* - * AUX_PLL Fraction = 0x0ec6bd6 - * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256 - * 271 MHz pre-postdivide - * FIXME 28636363 ref_freq doesn't match VID PLL ref - */ - cx25840_write4(client, 0x110, 0x00ec6bd6); - - /* - * SA_MCLK_SEL = 1 - * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider - */ - cx25840_write(client, 0x127, 0x50); - - if (is_cx2583x(state)) - break; - - /* src1_ctl */ - /* 0x1.60cd = 44100/32000 */ - cx25840_write4(client, 0x8f8, 0x080160cd); - - /* src3/4/6_ctl */ - /* 0x1.7385 = 2 * (32000/44100) */ - cx25840_write4(client, 0x900, 0x08017385); - cx25840_write4(client, 0x904, 0x08017385); - cx25840_write4(client, 0x90c, 0x08017385); - break; - - case 48000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18 - */ - cx25840_write4(client, 0x108, 0x180a040f); - - /* - * VID_PLL Fraction (register 0x10c) = 0x2be2fe - * 28636360 * 0xf.15f17f0/4 = 108 MHz - * 432 MHz pre-postdivide - */ - - /* - * AUX_PLL Fraction = 0x098d6e5 - * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256 - * 295 MHz pre-postdivide - * FIXME 28636363 ref_freq doesn't match VID PLL ref - */ - cx25840_write4(client, 0x110, 0x0098d6e5); - - /* - * SA_MCLK_SEL = 1 - * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider - */ - cx25840_write(client, 0x127, 0x50); - - if (is_cx2583x(state)) - break; - - /* src1_ctl */ - /* 0x1.8000 = 48000/32000 */ - cx25840_write4(client, 0x8f8, 0x08018000); - - /* src3/4/6_ctl */ - /* 0x1.5555 = 2 * (32000/48000) */ - cx25840_write4(client, 0x900, 0x08015555); - cx25840_write4(client, 0x904, 0x08015555); - cx25840_write4(client, 0x90c, 0x08015555); - break; - } - } - - state->audclk_freq = freq; - - return 0; -} - -static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq) -{ - return cx25840_set_audclk_freq(client, freq); -} - -static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - - if (state->aud_input != CX25840_AUDIO_SERIAL) { - switch (freq) { - case 32000: - case 44100: - case 48000: - /* We don't have register values - * so avoid destroying registers. */ - /* FIXME return -EINVAL; */ - break; - } - } else { - switch (freq) { - case 32000: - case 44100: - /* We don't have register values - * so avoid destroying registers. */ - /* FIXME return -EINVAL; */ - break; - - case 48000: - /* src1_ctl */ - /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */ - cx25840_write4(client, 0x8f8, 0x0801867c); - - /* src3/4/6_ctl */ - /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ - cx25840_write4(client, 0x900, 0x08014faa); - cx25840_write4(client, 0x904, 0x08014faa); - cx25840_write4(client, 0x90c, 0x08014faa); - break; - } - } - - state->audclk_freq = freq; - - return 0; -} - -static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - - if (state->aud_input != CX25840_AUDIO_SERIAL) { - switch (freq) { - case 32000: - /* src3/4/6_ctl */ - /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */ - cx25840_write4(client, 0x900, 0x0801f77f); - cx25840_write4(client, 0x904, 0x0801f77f); - cx25840_write4(client, 0x90c, 0x0801f77f); - break; - - case 44100: - /* src3/4/6_ctl */ - /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */ - cx25840_write4(client, 0x900, 0x08016d59); - cx25840_write4(client, 0x904, 0x08016d59); - cx25840_write4(client, 0x90c, 0x08016d59); - break; - - case 48000: - /* src3/4/6_ctl */ - /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ - cx25840_write4(client, 0x900, 0x08014faa); - cx25840_write4(client, 0x904, 0x08014faa); - cx25840_write4(client, 0x90c, 0x08014faa); - break; - } - } else { - switch (freq) { - /* FIXME These cases make different assumptions about audclk */ - case 32000: - /* src1_ctl */ - /* 0x1.0000 = 32000/32000 */ - cx25840_write4(client, 0x8f8, 0x08010000); - - /* src3/4/6_ctl */ - /* 0x2.0000 = 2 * (32000/32000) */ - cx25840_write4(client, 0x900, 0x08020000); - cx25840_write4(client, 0x904, 0x08020000); - cx25840_write4(client, 0x90c, 0x08020000); - break; - - case 44100: - /* src1_ctl */ - /* 0x1.60cd = 44100/32000 */ - cx25840_write4(client, 0x8f8, 0x080160cd); - - /* src3/4/6_ctl */ - /* 0x1.7385 = 2 * (32000/44100) */ - cx25840_write4(client, 0x900, 0x08017385); - cx25840_write4(client, 0x904, 0x08017385); - cx25840_write4(client, 0x90c, 0x08017385); - break; - - case 48000: - /* src1_ctl */ - /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */ - cx25840_write4(client, 0x8f8, 0x0801867c); - - /* src3/4/6_ctl */ - /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ - cx25840_write4(client, 0x900, 0x08014faa); - cx25840_write4(client, 0x904, 0x08014faa); - cx25840_write4(client, 0x90c, 0x08014faa); - break; - } - } - - state->audclk_freq = freq; - - return 0; -} - -static int set_audclk_freq(struct i2c_client *client, u32 freq) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - - if (freq != 32000 && freq != 44100 && freq != 48000) - return -EINVAL; - - if (is_cx231xx(state)) - return cx231xx_set_audclk_freq(client, freq); - - if (is_cx2388x(state)) - return cx23885_set_audclk_freq(client, freq); - - if (is_cx2583x(state)) - return cx25836_set_audclk_freq(client, freq); - - return cx25840_set_audclk_freq(client, freq); -} - -void cx25840_audio_set_path(struct i2c_client *client) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - - if (!is_cx2583x(state)) { - /* assert soft reset */ - cx25840_and_or(client, 0x810, ~0x1, 0x01); - - /* stop microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0); - - /* Mute everything to prevent the PFFT! */ - cx25840_write(client, 0x8d3, 0x1f); - - if (state->aud_input == CX25840_AUDIO_SERIAL) { - /* Set Path1 to Serial Audio Input */ - cx25840_write4(client, 0x8d0, 0x01011012); - - /* The microcontroller should not be started for the - * non-tuner inputs: autodetection is specific for - * TV audio. */ - } else { - /* Set Path1 to Analog Demod Main Channel */ - cx25840_write4(client, 0x8d0, 0x1f063870); - } - } - - set_audclk_freq(client, state->audclk_freq); - - if (!is_cx2583x(state)) { - if (state->aud_input != CX25840_AUDIO_SERIAL) { - /* When the microcontroller detects the - * audio format, it will unmute the lines */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } - - /* deassert soft reset */ - cx25840_and_or(client, 0x810, ~0x1, 0x00); - - /* Ensure the controller is running when we exit */ - if (is_cx2388x(state) || is_cx231xx(state)) - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } -} - -static void set_volume(struct i2c_client *client, int volume) -{ - int vol; - - /* Convert the volume to msp3400 values (0-127) */ - vol = volume >> 9; - - /* now scale it up to cx25840 values - * -114dB to -96dB maps to 0 - * this should be 19, but in my testing that was 4dB too loud */ - if (vol <= 23) { - vol = 0; - } else { - vol -= 23; - } - - /* PATH1_VOLUME */ - cx25840_write(client, 0x8d4, 228 - (vol * 2)); -} - -static void set_balance(struct i2c_client *client, int balance) -{ - int bal = balance >> 8; - if (bal > 0x80) { - /* PATH1_BAL_LEFT */ - cx25840_and_or(client, 0x8d5, 0x7f, 0x80); - /* PATH1_BAL_LEVEL */ - cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f); - } else { - /* PATH1_BAL_LEFT */ - cx25840_and_or(client, 0x8d5, 0x7f, 0x00); - /* PATH1_BAL_LEVEL */ - cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal); - } -} - -int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct cx25840_state *state = to_state(sd); - int retval; - - if (!is_cx2583x(state)) - cx25840_and_or(client, 0x810, ~0x1, 1); - if (state->aud_input != CX25840_AUDIO_SERIAL) { - cx25840_and_or(client, 0x803, ~0x10, 0); - cx25840_write(client, 0x8d3, 0x1f); - } - retval = set_audclk_freq(client, freq); - if (state->aud_input != CX25840_AUDIO_SERIAL) - cx25840_and_or(client, 0x803, ~0x10, 0x10); - if (!is_cx2583x(state)) - cx25840_and_or(client, 0x810, ~0x1, 0); - return retval; -} - -static int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - if (state->mute->val) - set_volume(client, 0); - else - set_volume(client, state->volume->val); - break; - case V4L2_CID_AUDIO_BASS: - /* PATH1_EQ_BASS_VOL */ - cx25840_and_or(client, 0x8d9, ~0x3f, - 48 - (ctrl->val * 48 / 0xffff)); - break; - case V4L2_CID_AUDIO_TREBLE: - /* PATH1_EQ_TREBLE_VOL */ - cx25840_and_or(client, 0x8db, ~0x3f, - 48 - (ctrl->val * 48 / 0xffff)); - break; - case V4L2_CID_AUDIO_BALANCE: - set_balance(client, ctrl->val); - break; - default: - return -EINVAL; - } - return 0; -} - -const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops = { - .s_ctrl = cx25840_audio_s_ctrl, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2071 +0,0 @@ -/* cx25840 - Conexant CX25840 audio/video decoder driver - * - * Copyright (C) 2004 Ulf Eklund - * - * Based on the saa7115 driver and on the first verison of Chris Kennedy's - * cx25840 driver. - * - * Changes by Tyler Trafford - * - cleanup/rewrite for V4L2 API (2005) - * - * VBI support by Hans Verkuil . - * - * NTSC sliced VBI support by Christopher Neufeld - * with additional fixes by Hans Verkuil . - * - * CX23885 support by Steven Toth . - * - * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are - * Copyright (C) 2010 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx25840-core.h" - -MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver"); -MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford"); -MODULE_LICENSE("GPL"); - -#define CX25840_VID_INT_STAT_REG 0x410 -#define CX25840_VID_INT_STAT_BITS 0x0000ffff -#define CX25840_VID_INT_MASK_BITS 0xffff0000 -#define CX25840_VID_INT_MASK_SHFT 16 -#define CX25840_VID_INT_MASK_REG 0x412 - -#define CX23885_AUD_MC_INT_MASK_REG 0x80c -#define CX23885_AUD_MC_INT_STAT_BITS 0xffff0000 -#define CX23885_AUD_MC_INT_CTRL_BITS 0x0000ffff -#define CX23885_AUD_MC_INT_STAT_SHFT 16 - -#define CX25840_AUD_INT_CTRL_REG 0x812 -#define CX25840_AUD_INT_STAT_REG 0x813 - -#define CX23885_PIN_CTRL_IRQ_REG 0x123 -#define CX23885_PIN_CTRL_IRQ_IR_STAT 0x40 -#define CX23885_PIN_CTRL_IRQ_AUD_STAT 0x20 -#define CX23885_PIN_CTRL_IRQ_VID_STAT 0x10 - -#define CX25840_IR_STATS_REG 0x210 -#define CX25840_IR_IRQEN_REG 0x214 - -static int cx25840_debug; - -module_param_named(debug,cx25840_debug, int, 0644); - -MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); - - -/* ----------------------------------------------------------------------- */ - -int cx25840_write(struct i2c_client *client, u16 addr, u8 value) -{ - u8 buffer[3]; - buffer[0] = addr >> 8; - buffer[1] = addr & 0xff; - buffer[2] = value; - return i2c_master_send(client, buffer, 3); -} - -int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) -{ - u8 buffer[6]; - buffer[0] = addr >> 8; - buffer[1] = addr & 0xff; - buffer[2] = value & 0xff; - buffer[3] = (value >> 8) & 0xff; - buffer[4] = (value >> 16) & 0xff; - buffer[5] = value >> 24; - return i2c_master_send(client, buffer, 6); -} - -u8 cx25840_read(struct i2c_client * client, u16 addr) -{ - struct i2c_msg msgs[2]; - u8 tx_buf[2], rx_buf[1]; - - /* Write register address */ - tx_buf[0] = addr >> 8; - tx_buf[1] = addr & 0xff; - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = 2; - msgs[0].buf = (char *) tx_buf; - - /* Read data from register */ - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = 1; - msgs[1].buf = (char *) rx_buf; - - if (i2c_transfer(client->adapter, msgs, 2) < 2) - return 0; - - return rx_buf[0]; -} - -u32 cx25840_read4(struct i2c_client * client, u16 addr) -{ - struct i2c_msg msgs[2]; - u8 tx_buf[2], rx_buf[4]; - - /* Write register address */ - tx_buf[0] = addr >> 8; - tx_buf[1] = addr & 0xff; - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = 2; - msgs[0].buf = (char *) tx_buf; - - /* Read data from registers */ - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = 4; - msgs[1].buf = (char *) rx_buf; - - if (i2c_transfer(client->adapter, msgs, 2) < 2) - return 0; - - return (rx_buf[3] << 24) | (rx_buf[2] << 16) | (rx_buf[1] << 8) | - rx_buf[0]; -} - -int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, - u8 or_value) -{ - return cx25840_write(client, addr, - (cx25840_read(client, addr) & and_mask) | - or_value); -} - -int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, - u32 or_value) -{ - return cx25840_write4(client, addr, - (cx25840_read4(client, addr) & and_mask) | - or_value); -} - -/* ----------------------------------------------------------------------- */ - -static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, - enum cx25840_audio_input aud_input); - -/* ----------------------------------------------------------------------- */ - -static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, - struct v4l2_subdev_io_pin_config *p) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int i; - u32 pin_ctrl; - u8 gpio_oe, gpio_data, strength; - - pin_ctrl = cx25840_read4(client, 0x120); - gpio_oe = cx25840_read(client, 0x160); - gpio_data = cx25840_read(client, 0x164); - - for (i = 0; i < n; i++) { - strength = p[i].strength; - if (strength > CX25840_PIN_DRIVE_FAST) - strength = CX25840_PIN_DRIVE_FAST; - - switch (p[i].pin) { - case CX23885_PIN_IRQ_N_GPIO16: - if (p[i].function != CX23885_PAD_IRQ_N) { - /* GPIO16 */ - pin_ctrl &= ~(0x1 << 25); - } else { - /* IRQ_N */ - if (p[i].flags & - (V4L2_SUBDEV_IO_PIN_DISABLE | - V4L2_SUBDEV_IO_PIN_INPUT)) { - pin_ctrl &= ~(0x1 << 25); - } else { - pin_ctrl |= (0x1 << 25); - } - if (p[i].flags & - V4L2_SUBDEV_IO_PIN_ACTIVE_LOW) { - pin_ctrl &= ~(0x1 << 24); - } else { - pin_ctrl |= (0x1 << 24); - } - } - break; - case CX23885_PIN_IR_RX_GPIO19: - if (p[i].function != CX23885_PAD_GPIO19) { - /* IR_RX */ - gpio_oe |= (0x1 << 0); - pin_ctrl &= ~(0x3 << 18); - pin_ctrl |= (strength << 18); - } else { - /* GPIO19 */ - gpio_oe &= ~(0x1 << 0); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { - gpio_data &= ~(0x1 << 0); - gpio_data |= ((p[i].value & 0x1) << 0); - } - pin_ctrl &= ~(0x3 << 12); - pin_ctrl |= (strength << 12); - } - break; - case CX23885_PIN_IR_TX_GPIO20: - if (p[i].function != CX23885_PAD_GPIO20) { - /* IR_TX */ - gpio_oe |= (0x1 << 1); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_DISABLE) - pin_ctrl &= ~(0x1 << 10); - else - pin_ctrl |= (0x1 << 10); - pin_ctrl &= ~(0x3 << 18); - pin_ctrl |= (strength << 18); - } else { - /* GPIO20 */ - gpio_oe &= ~(0x1 << 1); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { - gpio_data &= ~(0x1 << 1); - gpio_data |= ((p[i].value & 0x1) << 1); - } - pin_ctrl &= ~(0x3 << 12); - pin_ctrl |= (strength << 12); - } - break; - case CX23885_PIN_I2S_SDAT_GPIO21: - if (p[i].function != CX23885_PAD_GPIO21) { - /* I2S_SDAT */ - /* TODO: Input or Output config */ - gpio_oe |= (0x1 << 2); - pin_ctrl &= ~(0x3 << 22); - pin_ctrl |= (strength << 22); - } else { - /* GPIO21 */ - gpio_oe &= ~(0x1 << 2); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { - gpio_data &= ~(0x1 << 2); - gpio_data |= ((p[i].value & 0x1) << 2); - } - pin_ctrl &= ~(0x3 << 12); - pin_ctrl |= (strength << 12); - } - break; - case CX23885_PIN_I2S_WCLK_GPIO22: - if (p[i].function != CX23885_PAD_GPIO22) { - /* I2S_WCLK */ - /* TODO: Input or Output config */ - gpio_oe |= (0x1 << 3); - pin_ctrl &= ~(0x3 << 22); - pin_ctrl |= (strength << 22); - } else { - /* GPIO22 */ - gpio_oe &= ~(0x1 << 3); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { - gpio_data &= ~(0x1 << 3); - gpio_data |= ((p[i].value & 0x1) << 3); - } - pin_ctrl &= ~(0x3 << 12); - pin_ctrl |= (strength << 12); - } - break; - case CX23885_PIN_I2S_BCLK_GPIO23: - if (p[i].function != CX23885_PAD_GPIO23) { - /* I2S_BCLK */ - /* TODO: Input or Output config */ - gpio_oe |= (0x1 << 4); - pin_ctrl &= ~(0x3 << 22); - pin_ctrl |= (strength << 22); - } else { - /* GPIO23 */ - gpio_oe &= ~(0x1 << 4); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { - gpio_data &= ~(0x1 << 4); - gpio_data |= ((p[i].value & 0x1) << 4); - } - pin_ctrl &= ~(0x3 << 12); - pin_ctrl |= (strength << 12); - } - break; - } - } - - cx25840_write(client, 0x164, gpio_data); - cx25840_write(client, 0x160, gpio_oe); - cx25840_write4(client, 0x120, pin_ctrl); - return 0; -} - -static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n, - struct v4l2_subdev_io_pin_config *pincfg) -{ - struct cx25840_state *state = to_state(sd); - - if (is_cx2388x(state)) - return cx23885_s_io_pin_config(sd, n, pincfg); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static void init_dll1(struct i2c_client *client) -{ - /* This is the Hauppauge sequence used to - * initialize the Delay Lock Loop 1 (ADC DLL). */ - cx25840_write(client, 0x159, 0x23); - cx25840_write(client, 0x15a, 0x87); - cx25840_write(client, 0x15b, 0x06); - udelay(10); - cx25840_write(client, 0x159, 0xe1); - udelay(10); - cx25840_write(client, 0x15a, 0x86); - cx25840_write(client, 0x159, 0xe0); - cx25840_write(client, 0x159, 0xe1); - cx25840_write(client, 0x15b, 0x10); -} - -static void init_dll2(struct i2c_client *client) -{ - /* This is the Hauppauge sequence used to - * initialize the Delay Lock Loop 2 (ADC DLL). */ - cx25840_write(client, 0x15d, 0xe3); - cx25840_write(client, 0x15e, 0x86); - cx25840_write(client, 0x15f, 0x06); - udelay(10); - cx25840_write(client, 0x15d, 0xe1); - cx25840_write(client, 0x15d, 0xe0); - cx25840_write(client, 0x15d, 0xe1); -} - -static void cx25836_initialize(struct i2c_client *client) -{ - /* reset configuration is described on page 3-77 of the CX25836 datasheet */ - /* 2. */ - cx25840_and_or(client, 0x000, ~0x01, 0x01); - cx25840_and_or(client, 0x000, ~0x01, 0x00); - /* 3a. */ - cx25840_and_or(client, 0x15a, ~0x70, 0x00); - /* 3b. */ - cx25840_and_or(client, 0x15b, ~0x1e, 0x06); - /* 3c. */ - cx25840_and_or(client, 0x159, ~0x02, 0x02); - /* 3d. */ - udelay(10); - /* 3e. */ - cx25840_and_or(client, 0x159, ~0x02, 0x00); - /* 3f. */ - cx25840_and_or(client, 0x159, ~0xc0, 0xc0); - /* 3g. */ - cx25840_and_or(client, 0x159, ~0x01, 0x00); - cx25840_and_or(client, 0x159, ~0x01, 0x01); - /* 3h. */ - cx25840_and_or(client, 0x15b, ~0x1e, 0x10); -} - -static void cx25840_work_handler(struct work_struct *work) -{ - struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); - cx25840_loadfw(state->c); - wake_up(&state->fw_wait); -} - -static void cx25840_initialize(struct i2c_client *client) -{ - DEFINE_WAIT(wait); - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - struct workqueue_struct *q; - - /* datasheet startup in numbered steps, refer to page 3-77 */ - /* 2. */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - /* The default of this register should be 4, but I get 0 instead. - * Set this register to 4 manually. */ - cx25840_write(client, 0x000, 0x04); - /* 3. */ - init_dll1(client); - init_dll2(client); - cx25840_write(client, 0x136, 0x0a); - /* 4. */ - cx25840_write(client, 0x13c, 0x01); - cx25840_write(client, 0x13c, 0x00); - /* 5. */ - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ - INIT_WORK(&state->fw_work, cx25840_work_handler); - init_waitqueue_head(&state->fw_wait); - q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); - - /* 6. */ - cx25840_write(client, 0x115, 0x8c); - cx25840_write(client, 0x116, 0x07); - cx25840_write(client, 0x118, 0x02); - /* 7. */ - cx25840_write(client, 0x4a5, 0x80); - cx25840_write(client, 0x4a5, 0x00); - cx25840_write(client, 0x402, 0x00); - /* 8. */ - cx25840_and_or(client, 0x401, ~0x18, 0); - cx25840_and_or(client, 0x4a2, ~0x10, 0x10); - /* steps 8c and 8d are done in change_input() */ - /* 10. */ - cx25840_write(client, 0x8d3, 0x1f); - cx25840_write(client, 0x8e3, 0x03); - - cx25840_std_setup(client); - - /* trial and error says these are needed to get audio */ - cx25840_write(client, 0x914, 0xa0); - cx25840_write(client, 0x918, 0xa0); - cx25840_write(client, 0x919, 0x01); - - /* stereo prefered */ - cx25840_write(client, 0x809, 0x04); - /* AC97 shift */ - cx25840_write(client, 0x8cf, 0x0f); - - /* (re)set input */ - set_input(client, state->vid_input, state->aud_input); - - /* start microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); -} - -static void cx23885_initialize(struct i2c_client *client) -{ - DEFINE_WAIT(wait); - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - struct workqueue_struct *q; - - /* - * Come out of digital power down - * The CX23888, at least, needs this, otherwise registers aside from - * 0x0-0x2 can't be read or written. - */ - cx25840_write(client, 0x000, 0); - - /* Internal Reset */ - cx25840_and_or(client, 0x102, ~0x01, 0x01); - cx25840_and_or(client, 0x102, ~0x01, 0x00); - - /* Stop microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - - /* DIF in reset? */ - cx25840_write(client, 0x398, 0); - - /* - * Trust the default xtal, no division - * '885: 28.636363... MHz - * '887: 25.000000 MHz - * '888: 50.000000 MHz - */ - cx25840_write(client, 0x2, 0x76); - - /* Power up all the PLL's and DLL */ - cx25840_write(client, 0x1, 0x40); - - /* Sys PLL */ - switch (state->id) { - case V4L2_IDENT_CX23888_AV: - /* - * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz - * 572.73 MHz before post divide - */ - cx25840_write4(client, 0x11c, 0x00e8ba26); - cx25840_write4(client, 0x118, 0x0000040b); - break; - case V4L2_IDENT_CX23887_AV: - /* - * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz - * 572.73 MHz before post divide - */ - cx25840_write4(client, 0x11c, 0x01d1744c); - cx25840_write4(client, 0x118, 0x00000416); - break; - case V4L2_IDENT_CX23885_AV: - default: - /* - * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz - * 572.73 MHz before post divide - */ - cx25840_write4(client, 0x11c, 0x00000000); - cx25840_write4(client, 0x118, 0x00000414); - break; - } - - /* Disable DIF bypass */ - cx25840_write4(client, 0x33c, 0x00000001); - - /* DIF Src phase inc */ - cx25840_write4(client, 0x340, 0x0df7df83); - - /* - * Vid PLL - * Setup for a BT.656 pixel clock of 13.5 Mpixels/second - * - * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz - * 432.0 MHz before post divide - */ - cx25840_write4(client, 0x10c, 0x002be2c9); - cx25840_write4(client, 0x108, 0x0000040f); - - /* Luma */ - cx25840_write4(client, 0x414, 0x00107d12); - - /* Chroma */ - cx25840_write4(client, 0x420, 0x3d008282); - - /* - * Aux PLL - * Initial setup for audio sample clock: - * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz - * Intial I2S output/master clock(?): - * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz - */ - switch (state->id) { - case V4L2_IDENT_CX23888_AV: - /* - * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz - * 368.64 MHz before post divide - * 122.88 MHz / 0xa = 12.288 MHz - */ - cx25840_write4(client, 0x114, 0x00bedfa4); - cx25840_write4(client, 0x110, 0x000a0307); - break; - case V4L2_IDENT_CX23887_AV: - /* - * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz - * 368.64 MHz before post divide - * 122.88 MHz / 0xa = 12.288 MHz - */ - cx25840_write4(client, 0x114, 0x017dbf48); - cx25840_write4(client, 0x110, 0x000a030e); - break; - case V4L2_IDENT_CX23885_AV: - default: - /* - * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz - * 368.64 MHz before post divide - * 122.88 MHz / 0xa = 12.288 MHz - */ - cx25840_write4(client, 0x114, 0x01bf0c9e); - cx25840_write4(client, 0x110, 0x000a030c); - break; - }; - - /* ADC2 input select */ - cx25840_write(client, 0x102, 0x10); - - /* VIN1 & VIN5 */ - cx25840_write(client, 0x103, 0x11); - - /* Enable format auto detect */ - cx25840_write(client, 0x400, 0); - /* Fast subchroma lock */ - /* White crush, Chroma AGC & Chroma Killer enabled */ - cx25840_write(client, 0x401, 0xe8); - - /* Select AFE clock pad output source */ - cx25840_write(client, 0x144, 0x05); - - /* Drive GPIO2 direction and values for HVR1700 - * where an onboard mux selects the output of demodulator - * vs the 417. Failure to set this results in no DTV. - * It's safe to set this across all Hauppauge boards - * currently, regardless of the board type. - */ - cx25840_write(client, 0x160, 0x1d); - cx25840_write(client, 0x164, 0x00); - - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ - INIT_WORK(&state->fw_work, cx25840_work_handler); - init_waitqueue_head(&state->fw_wait); - q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); - - cx25840_std_setup(client); - - /* (re)set input */ - set_input(client, state->vid_input, state->aud_input); - - /* start microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); - - /* Disable and clear video interrupts - we don't use them */ - cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff); - - /* Disable and clear audio interrupts - we don't use them */ - cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff); - cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff); -} - -/* ----------------------------------------------------------------------- */ - -static void cx231xx_initialize(struct i2c_client *client) -{ - DEFINE_WAIT(wait); - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - struct workqueue_struct *q; - - /* Internal Reset */ - cx25840_and_or(client, 0x102, ~0x01, 0x01); - cx25840_and_or(client, 0x102, ~0x01, 0x00); - - /* Stop microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - - /* DIF in reset? */ - cx25840_write(client, 0x398, 0); - - /* Trust the default xtal, no division */ - /* This changes for the cx23888 products */ - cx25840_write(client, 0x2, 0x76); - - /* Bring down the regulator for AUX clk */ - cx25840_write(client, 0x1, 0x40); - - /* Disable DIF bypass */ - cx25840_write4(client, 0x33c, 0x00000001); - - /* DIF Src phase inc */ - cx25840_write4(client, 0x340, 0x0df7df83); - - /* Luma */ - cx25840_write4(client, 0x414, 0x00107d12); - - /* Chroma */ - cx25840_write4(client, 0x420, 0x3d008282); - - /* ADC2 input select */ - cx25840_write(client, 0x102, 0x10); - - /* VIN1 & VIN5 */ - cx25840_write(client, 0x103, 0x11); - - /* Enable format auto detect */ - cx25840_write(client, 0x400, 0); - /* Fast subchroma lock */ - /* White crush, Chroma AGC & Chroma Killer enabled */ - cx25840_write(client, 0x401, 0xe8); - - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ - INIT_WORK(&state->fw_work, cx25840_work_handler); - init_waitqueue_head(&state->fw_wait); - q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); - - cx25840_std_setup(client); - - /* (re)set input */ - set_input(client, state->vid_input, state->aud_input); - - /* start microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); -} - -/* ----------------------------------------------------------------------- */ - -void cx25840_std_setup(struct i2c_client *client) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - v4l2_std_id std = state->std; - int hblank, hactive, burst, vblank, vactive, sc; - int vblank656, src_decimation; - int luma_lpf, uv_lpf, comb; - u32 pll_int, pll_frac, pll_post; - - /* datasheet startup, step 8d */ - if (std & ~V4L2_STD_NTSC) - cx25840_write(client, 0x49f, 0x11); - else - cx25840_write(client, 0x49f, 0x14); - - if (std & V4L2_STD_625_50) { - hblank = 132; - hactive = 720; - burst = 93; - vblank = 36; - vactive = 580; - vblank656 = 40; - src_decimation = 0x21f; - luma_lpf = 2; - - if (std & V4L2_STD_SECAM) { - uv_lpf = 0; - comb = 0; - sc = 0x0a425f; - } else if (std == V4L2_STD_PAL_Nc) { - uv_lpf = 1; - comb = 0x20; - sc = 556453; - } else { - uv_lpf = 1; - comb = 0x20; - sc = 688739; - } - } else { - hactive = 720; - hblank = 122; - vactive = 487; - luma_lpf = 1; - uv_lpf = 1; - - src_decimation = 0x21f; - if (std == V4L2_STD_PAL_60) { - vblank = 26; - vblank656 = 26; - burst = 0x5b; - luma_lpf = 2; - comb = 0x20; - sc = 688739; - } else if (std == V4L2_STD_PAL_M) { - vblank = 20; - vblank656 = 24; - burst = 0x61; - comb = 0x20; - sc = 555452; - } else { - vblank = 26; - vblank656 = 26; - burst = 0x5b; - comb = 0x66; - sc = 556063; - } - } - - /* DEBUG: Displays configured PLL frequency */ - if (!is_cx231xx(state)) { - pll_int = cx25840_read(client, 0x108); - pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; - pll_post = cx25840_read(client, 0x109); - v4l_dbg(1, cx25840_debug, client, - "PLL regs = int: %u, frac: %u, post: %u\n", - pll_int, pll_frac, pll_post); - - if (pll_post) { - int fin, fsc; - int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L; - - pll /= pll_post; - v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n", - pll / 1000000, pll % 1000000); - v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n", - pll / 8000000, (pll / 8) % 1000000); - - fin = ((u64)src_decimation * pll) >> 12; - v4l_dbg(1, cx25840_debug, client, - "ADC Sampling freq = %d.%06d MHz\n", - fin / 1000000, fin % 1000000); - - fsc = (((u64)sc) * pll) >> 24L; - v4l_dbg(1, cx25840_debug, client, - "Chroma sub-carrier freq = %d.%06d MHz\n", - fsc / 1000000, fsc % 1000000); - - v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " - "vblank %i, vactive %i, vblank656 %i, src_dec %i, " - "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, " - "sc 0x%06x\n", - hblank, hactive, vblank, vactive, vblank656, - src_decimation, burst, luma_lpf, uv_lpf, comb, sc); - } - } - - /* Sets horizontal blanking delay and active lines */ - cx25840_write(client, 0x470, hblank); - cx25840_write(client, 0x471, - 0xff & (((hblank >> 8) & 0x3) | (hactive << 4))); - cx25840_write(client, 0x472, hactive >> 4); - - /* Sets burst gate delay */ - cx25840_write(client, 0x473, burst); - - /* Sets vertical blanking delay and active duration */ - cx25840_write(client, 0x474, vblank); - cx25840_write(client, 0x475, - 0xff & (((vblank >> 8) & 0x3) | (vactive << 4))); - cx25840_write(client, 0x476, vactive >> 4); - cx25840_write(client, 0x477, vblank656); - - /* Sets src decimation rate */ - cx25840_write(client, 0x478, 0xff & src_decimation); - cx25840_write(client, 0x479, 0xff & (src_decimation >> 8)); - - /* Sets Luma and UV Low pass filters */ - cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); - - /* Enables comb filters */ - cx25840_write(client, 0x47b, comb); - - /* Sets SC Step*/ - cx25840_write(client, 0x47c, sc); - cx25840_write(client, 0x47d, 0xff & sc >> 8); - cx25840_write(client, 0x47e, 0xff & sc >> 16); - - /* Sets VBI parameters */ - if (std & V4L2_STD_625_50) { - cx25840_write(client, 0x47f, 0x01); - state->vbi_line_offset = 5; - } else { - cx25840_write(client, 0x47f, 0x00); - state->vbi_line_offset = 8; - } -} - -/* ----------------------------------------------------------------------- */ - -static void input_change(struct i2c_client *client) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - v4l2_std_id std = state->std; - - /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */ - if (std & V4L2_STD_SECAM) { - cx25840_write(client, 0x402, 0); - } - else { - cx25840_write(client, 0x402, 0x04); - cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); - } - cx25840_and_or(client, 0x401, ~0x60, 0); - cx25840_and_or(client, 0x401, ~0x60, 0x60); - - /* Don't write into audio registers on cx2583x chips */ - if (is_cx2583x(state)) - return; - - cx25840_and_or(client, 0x810, ~0x01, 1); - - if (state->radio) { - cx25840_write(client, 0x808, 0xf9); - cx25840_write(client, 0x80b, 0x00); - } - else if (std & V4L2_STD_525_60) { - /* Certain Hauppauge PVR150 models have a hardware bug - that causes audio to drop out. For these models the - audio standard must be set explicitly. - To be precise: it affects cards with tuner models - 85, 99 and 112 (model numbers from tveeprom). */ - int hw_fix = state->pvr150_workaround; - - if (std == V4L2_STD_NTSC_M_JP) { - /* Japan uses EIAJ audio standard */ - cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7); - } else if (std == V4L2_STD_NTSC_M_KR) { - /* South Korea uses A2 audio standard */ - cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8); - } else { - /* Others use the BTSC audio standard */ - cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6); - } - cx25840_write(client, 0x80b, 0x00); - } else if (std & V4L2_STD_PAL) { - /* Autodetect audio standard and audio system */ - cx25840_write(client, 0x808, 0xff); - /* Since system PAL-L is pretty much non-existant and - not used by any public broadcast network, force - 6.5 MHz carrier to be interpreted as System DK, - this avoids DK audio detection instability */ - cx25840_write(client, 0x80b, 0x00); - } else if (std & V4L2_STD_SECAM) { - /* Autodetect audio standard and audio system */ - cx25840_write(client, 0x808, 0xff); - /* If only one of SECAM-DK / SECAM-L is required, then force - 6.5MHz carrier, else autodetect it */ - if ((std & V4L2_STD_SECAM_DK) && - !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { - /* 6.5 MHz carrier to be interpreted as System DK */ - cx25840_write(client, 0x80b, 0x00); - } else if (!(std & V4L2_STD_SECAM_DK) && - (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { - /* 6.5 MHz carrier to be interpreted as System L */ - cx25840_write(client, 0x80b, 0x08); - } else { - /* 6.5 MHz carrier to be autodetected */ - cx25840_write(client, 0x80b, 0x10); - } - } - - cx25840_and_or(client, 0x810, ~0x01, 0); -} - -static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, - enum cx25840_audio_input aud_input) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && - vid_input <= CX25840_COMPOSITE8); - u8 is_component = (vid_input & CX25840_COMPONENT_ON) == - CX25840_COMPONENT_ON; - int luma = vid_input & 0xf0; - int chroma = vid_input & 0xf00; - u8 reg; - - v4l_dbg(1, cx25840_debug, client, - "decoder set video input %d, audio input %d\n", - vid_input, aud_input); - - if (vid_input >= CX25840_VIN1_CH1) { - v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", - vid_input); - reg = vid_input & 0xff; - is_composite = !is_component && - ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON); - - v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", - reg, is_composite); - } else if (is_composite) { - reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); - } else { - if ((vid_input & ~0xff0) || - luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 || - chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { - v4l_err(client, "0x%04x is not a valid video input!\n", - vid_input); - return -EINVAL; - } - reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); - if (chroma >= CX25840_SVIDEO_CHROMA7) { - reg &= 0x3f; - reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2; - } else { - reg &= 0xcf; - reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4; - } - } - - /* The caller has previously prepared the correct routing - * configuration in reg (for the cx23885) so we have no - * need to attempt to flip bits for earlier av decoders. - */ - if (!is_cx2388x(state) && !is_cx231xx(state)) { - switch (aud_input) { - case CX25840_AUDIO_SERIAL: - /* do nothing, use serial audio input */ - break; - case CX25840_AUDIO4: reg &= ~0x30; break; - case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; - case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; - case CX25840_AUDIO7: reg &= ~0xc0; break; - case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; - - default: - v4l_err(client, "0x%04x is not a valid audio input!\n", - aud_input); - return -EINVAL; - } - } - - cx25840_write(client, 0x103, reg); - - /* Set INPUT_MODE to Composite, S-Video or Component */ - if (is_component) - cx25840_and_or(client, 0x401, ~0x6, 0x6); - else - cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); - - if (!is_cx2388x(state) && !is_cx231xx(state)) { - /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ - cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); - /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ - if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) - cx25840_and_or(client, 0x102, ~0x4, 4); - else - cx25840_and_or(client, 0x102, ~0x4, 0); - } else { - /* Set DUAL_MODE_ADC2 to 1 if component*/ - cx25840_and_or(client, 0x102, ~0x4, is_component ? 0x4 : 0x0); - if (is_composite) { - /* ADC2 input select channel 2 */ - cx25840_and_or(client, 0x102, ~0x2, 0); - } else if (!is_component) { - /* S-Video */ - if (chroma >= CX25840_SVIDEO_CHROMA7) { - /* ADC2 input select channel 3 */ - cx25840_and_or(client, 0x102, ~0x2, 2); - } else { - /* ADC2 input select channel 2 */ - cx25840_and_or(client, 0x102, ~0x2, 0); - } - } - } - - state->vid_input = vid_input; - state->aud_input = aud_input; - cx25840_audio_set_path(client); - input_change(client); - - if (is_cx2388x(state)) { - /* Audio channel 1 src : Parallel 1 */ - cx25840_write(client, 0x124, 0x03); - - /* Select AFE clock pad output source */ - cx25840_write(client, 0x144, 0x05); - - /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ - cx25840_write(client, 0x914, 0xa0); - - /* I2S_OUT_CTL: - * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 - * I2S_OUT_MASTER_MODE = Master - */ - cx25840_write(client, 0x918, 0xa0); - cx25840_write(client, 0x919, 0x01); - } else if (is_cx231xx(state)) { - /* Audio channel 1 src : Parallel 1 */ - cx25840_write(client, 0x124, 0x03); - - /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ - cx25840_write(client, 0x914, 0xa0); - - /* I2S_OUT_CTL: - * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 - * I2S_OUT_MASTER_MODE = Master - */ - cx25840_write(client, 0x918, 0xa0); - cx25840_write(client, 0x919, 0x01); - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int set_v4lstd(struct i2c_client *client) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - u8 fmt = 0; /* zero is autodetect */ - u8 pal_m = 0; - - /* First tests should be against specific std */ - if (state->std == V4L2_STD_NTSC_M_JP) { - fmt = 0x2; - } else if (state->std == V4L2_STD_NTSC_443) { - fmt = 0x3; - } else if (state->std == V4L2_STD_PAL_M) { - pal_m = 1; - fmt = 0x5; - } else if (state->std == V4L2_STD_PAL_N) { - fmt = 0x6; - } else if (state->std == V4L2_STD_PAL_Nc) { - fmt = 0x7; - } else if (state->std == V4L2_STD_PAL_60) { - fmt = 0x8; - } else { - /* Then, test against generic ones */ - if (state->std & V4L2_STD_NTSC) - fmt = 0x1; - else if (state->std & V4L2_STD_PAL) - fmt = 0x4; - else if (state->std & V4L2_STD_SECAM) - fmt = 0xc; - } - - v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt); - - /* Follow step 9 of section 3.16 in the cx25840 datasheet. - Without this PAL may display a vertical ghosting effect. - This happens for example with the Yuan MPC622. */ - if (fmt >= 4 && fmt < 8) { - /* Set format to NTSC-M */ - cx25840_and_or(client, 0x400, ~0xf, 1); - /* Turn off LCOMB */ - cx25840_and_or(client, 0x47b, ~6, 0); - } - cx25840_and_or(client, 0x400, ~0xf, fmt); - cx25840_and_or(client, 0x403, ~0x3, pal_m); - cx25840_std_setup(client); - if (!is_cx2583x(state)) - input_change(client); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - cx25840_write(client, 0x414, ctrl->val - 128); - break; - - case V4L2_CID_CONTRAST: - cx25840_write(client, 0x415, ctrl->val << 1); - break; - - case V4L2_CID_SATURATION: - cx25840_write(client, 0x420, ctrl->val << 1); - cx25840_write(client, 0x421, ctrl->val << 1); - break; - - case V4L2_CID_HUE: - cx25840_write(client, 0x422, ctrl->val); - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int HSC, VSC, Vsrc, Hsrc, filter, Vlines; - int is_50Hz = !(state->std & V4L2_STD_525_60); - - if (fmt->code != V4L2_MBUS_FMT_FIXED) - return -EINVAL; - - fmt->field = V4L2_FIELD_INTERLACED; - fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - - Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; - Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; - - Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; - Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; - - Vlines = fmt->height + (is_50Hz ? 4 : 7); - - if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || - (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { - v4l_err(client, "%dx%d is not a valid size!\n", - fmt->width, fmt->height); - return -ERANGE; - } - - HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); - VSC &= 0x1fff; - - if (fmt->width >= 385) - filter = 0; - else if (fmt->width > 192) - filter = 1; - else if (fmt->width > 96) - filter = 2; - else - filter = 3; - - v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", - fmt->width, fmt->height, HSC, VSC); - - /* HSCALE=HSC */ - cx25840_write(client, 0x418, HSC & 0xff); - cx25840_write(client, 0x419, (HSC >> 8) & 0xff); - cx25840_write(client, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx25840_write(client, 0x41c, VSC & 0xff); - cx25840_write(client, 0x41d, VSC >> 8); - /* VS_INTRLACE=1 VFILT=filter */ - cx25840_write(client, 0x41e, 0x8 | filter); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static void log_video_status(struct i2c_client *client) -{ - static const char *const fmt_strs[] = { - "0x0", - "NTSC-M", "NTSC-J", "NTSC-4.43", - "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", - "0x9", "0xA", "0xB", - "SECAM", - "0xD", "0xE", "0xF" - }; - - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; - u8 gen_stat1 = cx25840_read(client, 0x40d); - u8 gen_stat2 = cx25840_read(client, 0x40e); - int vid_input = state->vid_input; - - v4l_info(client, "Video signal: %spresent\n", - (gen_stat2 & 0x20) ? "" : "not "); - v4l_info(client, "Detected format: %s\n", - fmt_strs[gen_stat1 & 0xf]); - - v4l_info(client, "Specified standard: %s\n", - vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); - - if (vid_input >= CX25840_COMPOSITE1 && - vid_input <= CX25840_COMPOSITE8) { - v4l_info(client, "Specified video input: Composite %d\n", - vid_input - CX25840_COMPOSITE1 + 1); - } else { - v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", - (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); - } - - v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); -} - -/* ----------------------------------------------------------------------- */ - -static void log_audio_status(struct i2c_client *client) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - u8 download_ctl = cx25840_read(client, 0x803); - u8 mod_det_stat0 = cx25840_read(client, 0x804); - u8 mod_det_stat1 = cx25840_read(client, 0x805); - u8 audio_config = cx25840_read(client, 0x808); - u8 pref_mode = cx25840_read(client, 0x809); - u8 afc0 = cx25840_read(client, 0x80b); - u8 mute_ctl = cx25840_read(client, 0x8d3); - int aud_input = state->aud_input; - char *p; - - switch (mod_det_stat0) { - case 0x00: p = "mono"; break; - case 0x01: p = "stereo"; break; - case 0x02: p = "dual"; break; - case 0x04: p = "tri"; break; - case 0x10: p = "mono with SAP"; break; - case 0x11: p = "stereo with SAP"; break; - case 0x12: p = "dual with SAP"; break; - case 0x14: p = "tri with SAP"; break; - case 0xfe: p = "forced mode"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio mode: %s\n", p); - - switch (mod_det_stat1) { - case 0x00: p = "not defined"; break; - case 0x01: p = "EIAJ"; break; - case 0x02: p = "A2-M"; break; - case 0x03: p = "A2-BG"; break; - case 0x04: p = "A2-DK1"; break; - case 0x05: p = "A2-DK2"; break; - case 0x06: p = "A2-DK3"; break; - case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x08: p = "AM-L"; break; - case 0x09: p = "NICAM-BG"; break; - case 0x0a: p = "NICAM-DK"; break; - case 0x0b: p = "NICAM-I"; break; - case 0x0c: p = "NICAM-L"; break; - case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; - case 0x0e: p = "IF FM Radio"; break; - case 0x0f: p = "BTSC"; break; - case 0x10: p = "high-deviation FM"; break; - case 0x11: p = "very high-deviation FM"; break; - case 0xfd: p = "unknown audio standard"; break; - case 0xfe: p = "forced audio standard"; break; - case 0xff: p = "no detected audio standard"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio standard: %s\n", p); - v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? - ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); - - switch (audio_config >> 4) { - case 0x00: p = "undefined"; break; - case 0x01: p = "BTSC"; break; - case 0x02: p = "EIAJ"; break; - case 0x03: p = "A2-M"; break; - case 0x04: p = "A2-BG"; break; - case 0x05: p = "A2-DK1"; break; - case 0x06: p = "A2-DK2"; break; - case 0x07: p = "A2-DK3"; break; - case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x09: p = "AM-L"; break; - case 0x0a: p = "NICAM-BG"; break; - case 0x0b: p = "NICAM-DK"; break; - case 0x0c: p = "NICAM-I"; break; - case 0x0d: p = "NICAM-L"; break; - case 0x0e: p = "FM radio"; break; - case 0x0f: p = "automatic detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio standard: %s\n", p); - - if ((audio_config >> 4) < 0xF) { - switch (audio_config & 0xF) { - case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; - case 0x01: p = "MONO2 (LANGUAGE B)"; break; - case 0x02: p = "MONO3 (STEREO forced MONO)"; break; - case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; - case 0x04: p = "STEREO"; break; - case 0x05: p = "DUAL1 (AB)"; break; - case 0x06: p = "DUAL2 (AC) (FM)"; break; - case 0x07: p = "DUAL3 (BC) (FM)"; break; - case 0x08: p = "DUAL4 (AC) (AM)"; break; - case 0x09: p = "DUAL5 (BC) (AM)"; break; - case 0x0a: p = "SAP"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio mode: %s\n", p); - } else { - switch (audio_config & 0xF) { - case 0x00: p = "BG"; break; - case 0x01: p = "DK1"; break; - case 0x02: p = "DK2"; break; - case 0x03: p = "DK3"; break; - case 0x04: p = "I"; break; - case 0x05: p = "L"; break; - case 0x06: p = "BTSC"; break; - case 0x07: p = "EIAJ"; break; - case 0x08: p = "A2-M"; break; - case 0x09: p = "FM Radio"; break; - case 0x0f: p = "automatic standard and mode detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio system: %s\n", p); - } - - if (aud_input) { - v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); - } else { - v4l_info(client, "Specified audio input: External\n"); - } - - switch (pref_mode & 0xf) { - case 0: p = "mono/language A"; break; - case 1: p = "language B"; break; - case 2: p = "language C"; break; - case 3: p = "analog fallback"; break; - case 4: p = "stereo"; break; - case 5: p = "language AC"; break; - case 6: p = "language BC"; break; - case 7: p = "language AB"; break; - default: p = "undefined"; - } - v4l_info(client, "Preferred audio mode: %s\n", p); - - if ((audio_config & 0xf) == 0xf) { - switch ((afc0 >> 3) & 0x3) { - case 0: p = "system DK"; break; - case 1: p = "system L"; break; - case 2: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 65 MHz format: %s\n", p); - - switch (afc0 & 0x7) { - case 0: p = "chroma"; break; - case 1: p = "BTSC"; break; - case 2: p = "EIAJ"; break; - case 3: p = "A2-M"; break; - case 4: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 45 MHz format: %s\n", p); - } -} - -/* ----------------------------------------------------------------------- */ - -/* This load_fw operation must be called to load the driver's firmware. - Without this the audio standard detection will fail and you will - only get mono. - - Since loading the firmware is often problematic when the driver is - compiled into the kernel I recommend postponing calling this function - until the first open of the video device. Another reason for - postponing it is that loading this firmware takes a long time (seconds) - due to the slow i2c bus speed. So it will speed up the boot process if - you can avoid loading the fw as long as the video device isn't used. */ -static int cx25840_load_fw(struct v4l2_subdev *sd) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!state->is_initialized) { - /* initialize and load firmware */ - state->is_initialized = 1; - if (is_cx2583x(state)) - cx25836_initialize(client); - else if (is_cx2388x(state)) - cx23885_initialize(client); - else if (is_cx231xx(state)) - cx231xx_initialize(client); - else - cx25840_initialize(client); - } - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->size = 1; - reg->val = cx25840_read(client, reg->reg & 0x0fff); - return 0; -} - -static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff); - return 0; -} -#endif - -static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 v; - - if (is_cx2583x(state) || is_cx2388x(state) || is_cx231xx(state)) - return 0; - - v4l_dbg(1, cx25840_debug, client, "%s audio output\n", - enable ? "enable" : "disable"); - - if (enable) { - v = cx25840_read(client, 0x115) | 0x80; - cx25840_write(client, 0x115, v); - v = cx25840_read(client, 0x116) | 0x03; - cx25840_write(client, 0x116, v); - } else { - v = cx25840_read(client, 0x115) & ~(0x80); - cx25840_write(client, 0x115, v); - v = cx25840_read(client, 0x116) & ~(0x03); - cx25840_write(client, 0x116, v); - } - return 0; -} - -static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 v; - - v4l_dbg(1, cx25840_debug, client, "%s video output\n", - enable ? "enable" : "disable"); - if (enable) { - if (is_cx2388x(state) || is_cx231xx(state)) { - v = cx25840_read(client, 0x421) | 0x0b; - cx25840_write(client, 0x421, v); - } else { - v = cx25840_read(client, 0x115) | 0x0c; - cx25840_write(client, 0x115, v); - v = cx25840_read(client, 0x116) | 0x04; - cx25840_write(client, 0x116, v); - } - } else { - if (is_cx2388x(state) || is_cx231xx(state)) { - v = cx25840_read(client, 0x421) & ~(0x0b); - cx25840_write(client, 0x421, v); - } else { - v = cx25840_read(client, 0x115) & ~(0x0c); - cx25840_write(client, 0x115, v); - v = cx25840_read(client, 0x116) & ~(0x04); - cx25840_write(client, 0x116, v); - } - } - return 0; -} - -static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (state->radio == 0 && state->std == std) - return 0; - state->radio = 0; - state->std = std; - return set_v4lstd(client); -} - -static int cx25840_s_radio(struct v4l2_subdev *sd) -{ - struct cx25840_state *state = to_state(sd); - - state->radio = 1; - return 0; -} - -static int cx25840_s_video_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return set_input(client, input, state->aud_input); -} - -static int cx25840_s_audio_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return set_input(client, state->vid_input, input); -} - -static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - input_change(client); - return 0; -} - -static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 vpres = cx25840_read(client, 0x40e) & 0x20; - u8 mode; - int val = 0; - - if (state->radio) - return 0; - - vt->signal = vpres ? 0xffff : 0x0; - if (is_cx2583x(state)) - return 0; - - vt->capability |= - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - - mode = cx25840_read(client, 0x804); - - /* get rxsubchans and audmode */ - if ((mode & 0xf) == 1) - val |= V4L2_TUNER_SUB_STEREO; - else - val |= V4L2_TUNER_SUB_MONO; - - if (mode == 2 || mode == 4) - val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - - if (mode & 0x10) - val |= V4L2_TUNER_SUB_SAP; - - vt->rxsubchans = val; - vt->audmode = state->audmode; - return 0; -} - -static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (state->radio || is_cx2583x(state)) - return 0; - - switch (vt->audmode) { - case V4L2_TUNER_MODE_MONO: - /* mono -> mono - stereo -> mono - bilingual -> lang1 */ - cx25840_and_or(client, 0x809, ~0xf, 0x00); - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1: - /* mono -> mono - stereo -> stereo - bilingual -> lang1 */ - cx25840_and_or(client, 0x809, ~0xf, 0x04); - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang1/lang2 */ - cx25840_and_or(client, 0x809, ~0xf, 0x07); - break; - case V4L2_TUNER_MODE_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang2 */ - cx25840_and_or(client, 0x809, ~0xf, 0x01); - break; - default: - return -EINVAL; - } - state->audmode = vt->audmode; - return 0; -} - -static int cx25840_reset(struct v4l2_subdev *sd, u32 val) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (is_cx2583x(state)) - cx25836_initialize(client); - else if (is_cx2388x(state)) - cx23885_initialize(client); - else if (is_cx231xx(state)) - cx231xx_initialize(client); - else - cx25840_initialize(client); - return 0; -} - -static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev); -} - -static int cx25840_log_status(struct v4l2_subdev *sd) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - log_video_status(client); - if (!is_cx2583x(state)) - log_audio_status(client); - cx25840_ir_log_status(sd); - v4l2_ctrl_handler_log_status(&state->hdl, sd->name); - return 0; -} - -static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status, - bool *handled) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *c = v4l2_get_subdevdata(sd); - u8 irq_stat, aud_stat, aud_en, ir_stat, ir_en; - u32 vid_stat, aud_mc_stat; - bool block_handled; - int ret = 0; - - irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG); - v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (entry): %s %s %s\n", - irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ", - irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ", - irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " "); - - if ((is_cx23885(state) || is_cx23887(state))) { - ir_stat = cx25840_read(c, CX25840_IR_STATS_REG); - ir_en = cx25840_read(c, CX25840_IR_IRQEN_REG); - v4l_dbg(2, cx25840_debug, c, - "AV Core ir IRQ status: %#04x disables: %#04x\n", - ir_stat, ir_en); - if (irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT) { - block_handled = false; - ret = cx25840_ir_irq_handler(sd, - status, &block_handled); - if (block_handled) - *handled = true; - } - } - - aud_stat = cx25840_read(c, CX25840_AUD_INT_STAT_REG); - aud_en = cx25840_read(c, CX25840_AUD_INT_CTRL_REG); - v4l_dbg(2, cx25840_debug, c, - "AV Core audio IRQ status: %#04x disables: %#04x\n", - aud_stat, aud_en); - aud_mc_stat = cx25840_read4(c, CX23885_AUD_MC_INT_MASK_REG); - v4l_dbg(2, cx25840_debug, c, - "AV Core audio MC IRQ status: %#06x enables: %#06x\n", - aud_mc_stat >> CX23885_AUD_MC_INT_STAT_SHFT, - aud_mc_stat & CX23885_AUD_MC_INT_CTRL_BITS); - if (irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT) { - if (aud_stat) { - cx25840_write(c, CX25840_AUD_INT_STAT_REG, aud_stat); - *handled = true; - } - } - - vid_stat = cx25840_read4(c, CX25840_VID_INT_STAT_REG); - v4l_dbg(2, cx25840_debug, c, - "AV Core video IRQ status: %#06x disables: %#06x\n", - vid_stat & CX25840_VID_INT_STAT_BITS, - vid_stat >> CX25840_VID_INT_MASK_SHFT); - if (irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT) { - if (vid_stat & CX25840_VID_INT_STAT_BITS) { - cx25840_write4(c, CX25840_VID_INT_STAT_REG, vid_stat); - *handled = true; - } - } - - irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG); - v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (exit): %s %s %s\n", - irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ", - irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ", - irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " "); - - return ret; -} - -static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status, - bool *handled) -{ - struct cx25840_state *state = to_state(sd); - - *handled = false; - - /* Only support the CX2388[578] AV Core for now */ - if (is_cx2388x(state)) - return cx23885_irq_handler(sd, status, handled); - - return -ENODEV; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops cx25840_ctrl_ops = { - .s_ctrl = cx25840_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops cx25840_core_ops = { - .log_status = cx25840_log_status, - .g_chip_ident = cx25840_g_chip_ident, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = cx25840_s_std, - .reset = cx25840_reset, - .load_fw = cx25840_load_fw, - .s_io_pin_config = common_s_io_pin_config, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = cx25840_g_register, - .s_register = cx25840_s_register, -#endif - .interrupt_service_routine = cx25840_irq_handler, -}; - -static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { - .s_frequency = cx25840_s_frequency, - .s_radio = cx25840_s_radio, - .g_tuner = cx25840_g_tuner, - .s_tuner = cx25840_s_tuner, -}; - -static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { - .s_clock_freq = cx25840_s_clock_freq, - .s_routing = cx25840_s_audio_routing, - .s_stream = cx25840_s_audio_stream, -}; - -static const struct v4l2_subdev_video_ops cx25840_video_ops = { - .s_routing = cx25840_s_video_routing, - .s_mbus_fmt = cx25840_s_mbus_fmt, - .s_stream = cx25840_s_stream, -}; - -static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = { - .decode_vbi_line = cx25840_decode_vbi_line, - .s_raw_fmt = cx25840_s_raw_fmt, - .s_sliced_fmt = cx25840_s_sliced_fmt, - .g_sliced_fmt = cx25840_g_sliced_fmt, -}; - -static const struct v4l2_subdev_ops cx25840_ops = { - .core = &cx25840_core_ops, - .tuner = &cx25840_tuner_ops, - .audio = &cx25840_audio_ops, - .video = &cx25840_video_ops, - .vbi = &cx25840_vbi_ops, - .ir = &cx25840_ir_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static u32 get_cx2388x_ident(struct i2c_client *client) -{ - u32 ret; - - /* Come out of digital power down */ - cx25840_write(client, 0x000, 0); - - /* Detecting whether the part is cx23885/7/8 is more - * difficult than it needs to be. No ID register. Instead we - * probe certain registers indicated in the datasheets to look - * for specific defaults that differ between the silicon designs. */ - - /* It's either 885/7 if the IR Tx Clk Divider register exists */ - if (cx25840_read4(client, 0x204) & 0xffff) { - /* CX23885 returns bogus repetitive byte values for the DIF, - * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */ - ret = cx25840_read4(client, 0x300); - if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) { - /* No DIF */ - ret = V4L2_IDENT_CX23885_AV; - } else { - /* CX23887 has a broken DIF, but the registers - * appear valid (but unsed), good enough to detect. */ - ret = V4L2_IDENT_CX23887_AV; - } - } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { - /* DIF PLL Freq Word reg exists; chip must be a CX23888 */ - ret = V4L2_IDENT_CX23888_AV; - } else { - v4l_err(client, "Unable to detect h/w, assuming cx23887\n"); - ret = V4L2_IDENT_CX23887_AV; - } - - /* Back into digital power down */ - cx25840_write(client, 0x000, 2); - return ret; -} - -static int cx25840_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct cx25840_state *state; - struct v4l2_subdev *sd; - int default_volume; - u32 id = V4L2_IDENT_NONE; - u16 device_id; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); - - device_id = cx25840_read(client, 0x101) << 8; - device_id |= cx25840_read(client, 0x100); - v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); - - /* The high byte of the device ID should be - * 0x83 for the cx2583x and 0x84 for the cx2584x */ - if ((device_id & 0xff00) == 0x8300) { - id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; - } else if ((device_id & 0xff00) == 0x8400) { - id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); - } else if (device_id == 0x0000) { - id = get_cx2388x_ident(client); - } else if ((device_id & 0xfff0) == 0x5A30) { - /* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */ - id = V4L2_IDENT_CX2310X_AV; - } else if ((device_id & 0xff) == (device_id >> 8)) { - v4l_err(client, - "likely a confused/unresponsive cx2388[578] A/V decoder" - " found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - v4l_err(client, "A method to reset it from the cx25840 driver" - " software is not known at this time\n"); - return -ENODEV; - } else { - v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); - return -ENODEV; - } - - state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &cx25840_ops); - - switch (id) { - case V4L2_IDENT_CX23885_AV: - v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - break; - case V4L2_IDENT_CX23887_AV: - v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - break; - case V4L2_IDENT_CX23888_AV: - v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - break; - case V4L2_IDENT_CX2310X_AV: - v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n", - device_id, client->addr << 1, client->adapter->name); - break; - case V4L2_IDENT_CX25840: - case V4L2_IDENT_CX25841: - case V4L2_IDENT_CX25842: - case V4L2_IDENT_CX25843: - /* Note: revision '(device_id & 0x0f) == 2' was never built. The - marking skips from 0x1 == 22 to 0x3 == 23. */ - v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", - (device_id & 0xfff0) >> 4, - (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 - : (device_id & 0x0f), - client->addr << 1, client->adapter->name); - break; - case V4L2_IDENT_CX25836: - case V4L2_IDENT_CX25837: - default: - v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n", - (device_id & 0xfff0) >> 4, device_id & 0x0f, - client->addr << 1, client->adapter->name); - break; - } - - state->c = client; - state->vid_input = CX25840_COMPOSITE7; - state->aud_input = CX25840_AUDIO8; - state->audclk_freq = 48000; - state->audmode = V4L2_TUNER_MODE_LANG1; - state->vbi_line_offset = 8; - state->id = id; - state->rev = device_id; - v4l2_ctrl_handler_init(&state->hdl, 9); - v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_CONTRAST, 0, 127, 1, 64); - v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_SATURATION, 0, 127, 1, 64); - v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - if (!is_cx2583x(state)) { - default_volume = cx25840_read(client, 0x8d4); - /* - * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume - * scale mapping limits to avoid -ERANGE errors when - * initializing the volume control - */ - if (default_volume > 228) { - /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ - default_volume = 228; - cx25840_write(client, 0x8d4, 228); - } - else if (default_volume < 20) { - /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ - default_volume = 20; - cx25840_write(client, 0x8d4, 20); - } - default_volume = (((228 - default_volume) >> 1) + 23) << 9; - - state->volume = v4l2_ctrl_new_std(&state->hdl, - &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, - 0, 65535, 65535 / 100, default_volume); - state->mute = v4l2_ctrl_new_std(&state->hdl, - &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, - 0, 1, 1, 0); - v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, - 0, 65535, 65535 / 100, 32768); - v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, - V4L2_CID_AUDIO_BASS, - 0, 65535, 65535 / 100, 32768); - v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, - V4L2_CID_AUDIO_TREBLE, - 0, 65535, 65535 / 100, 32768); - } - sd->ctrl_handler = &state->hdl; - if (state->hdl.error) { - int err = state->hdl.error; - - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return err; - } - if (!is_cx2583x(state)) - v4l2_ctrl_cluster(2, &state->volume); - v4l2_ctrl_handler_setup(&state->hdl); - - if (client->dev.platform_data) { - struct cx25840_platform_data *pdata = client->dev.platform_data; - - state->pvr150_workaround = pdata->pvr150_workaround; - } - - cx25840_ir_probe(sd); - return 0; -} - -static int cx25840_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct cx25840_state *state = to_state(sd); - - cx25840_ir_remove(sd); - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return 0; -} - -static const struct i2c_device_id cx25840_id[] = { - { "cx25840", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, cx25840_id); - -static struct i2c_driver cx25840_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "cx25840", - }, - .probe = cx25840_probe, - .remove = cx25840_remove, - .id_table = cx25840_id, -}; - -static __init int init_cx25840(void) -{ - return i2c_add_driver(&cx25840_driver); -} - -static __exit void exit_cx25840(void) -{ - i2c_del_driver(&cx25840_driver); -} - -module_init(init_cx25840); -module_exit(exit_cx25840); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-core.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-core.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,137 +0,0 @@ -/* cx25840 internal API header - * - * Copyright (C) 2003-2004 Chris Kennedy - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _CX25840_CORE_H_ -#define _CX25840_CORE_H_ - - -#include -#include -#include -#include -#include - -struct cx25840_ir_state; - -struct cx25840_state { - struct i2c_client *c; - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - struct { - /* volume cluster */ - struct v4l2_ctrl *volume; - struct v4l2_ctrl *mute; - }; - int pvr150_workaround; - int radio; - v4l2_std_id std; - enum cx25840_video_input vid_input; - enum cx25840_audio_input aud_input; - u32 audclk_freq; - int audmode; - int vbi_line_offset; - u32 id; - u32 rev; - int is_initialized; - wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ - struct work_struct fw_work; /* work entry for fw load */ - struct cx25840_ir_state *ir_state; -}; - -static inline struct cx25840_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct cx25840_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct cx25840_state, hdl)->sd; -} - -static inline bool is_cx2583x(struct cx25840_state *state) -{ - return state->id == V4L2_IDENT_CX25836 || - state->id == V4L2_IDENT_CX25837; -} - -static inline bool is_cx231xx(struct cx25840_state *state) -{ - return state->id == V4L2_IDENT_CX2310X_AV; -} - -static inline bool is_cx2388x(struct cx25840_state *state) -{ - return state->id == V4L2_IDENT_CX23885_AV || - state->id == V4L2_IDENT_CX23887_AV || - state->id == V4L2_IDENT_CX23888_AV; -} - -static inline bool is_cx23885(struct cx25840_state *state) -{ - return state->id == V4L2_IDENT_CX23885_AV; -} - -static inline bool is_cx23887(struct cx25840_state *state) -{ - return state->id == V4L2_IDENT_CX23887_AV; -} - -static inline bool is_cx23888(struct cx25840_state *state) -{ - return state->id == V4L2_IDENT_CX23888_AV; -} - -/* ----------------------------------------------------------------------- */ -/* cx25850-core.c */ -int cx25840_write(struct i2c_client *client, u16 addr, u8 value); -int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); -u8 cx25840_read(struct i2c_client *client, u16 addr); -u32 cx25840_read4(struct i2c_client *client, u16 addr); -int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value); -int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, - u32 or_value); -void cx25840_std_setup(struct i2c_client *client); - -/* ----------------------------------------------------------------------- */ -/* cx25850-firmware.c */ -int cx25840_loadfw(struct i2c_client *client); - -/* ----------------------------------------------------------------------- */ -/* cx25850-audio.c */ -void cx25840_audio_set_path(struct i2c_client *client); -int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq); - -extern const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops; - -/* ----------------------------------------------------------------------- */ -/* cx25850-vbi.c */ -int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt); -int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); -int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); -int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi); - -/* ----------------------------------------------------------------------- */ -/* cx25850-ir.c */ -extern const struct v4l2_subdev_ir_ops cx25840_ir_ops; -int cx25840_ir_log_status(struct v4l2_subdev *sd); -int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled); -int cx25840_ir_probe(struct v4l2_subdev *sd); -int cx25840_ir_remove(struct v4l2_subdev *sd); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-firmware.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-firmware.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,166 +0,0 @@ -/* cx25840 firmware functions - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include - -#include "cx25840-core.h" - -/* - * Mike Isely - The FWSEND parameter controls the - * size of the firmware chunks sent down the I2C bus to the chip. - * Previously this had been set to 1024 but unfortunately some I2C - * implementations can't transfer data in such big gulps. - * Specifically, the pvrusb2 driver has a hard limit of around 60 - * bytes, due to the encapsulation there of I2C traffic into USB - * messages. So we have to significantly reduce this parameter. - */ -#define FWSEND 48 - -#define FWDEV(x) &((x)->dev) - -static char *firmware = ""; - -module_param(firmware, charp, 0444); - -MODULE_PARM_DESC(firmware, "Firmware image to load"); - -static void start_fw_load(struct i2c_client *client) -{ - /* DL_ADDR_LB=0 DL_ADDR_HB=0 */ - cx25840_write(client, 0x800, 0x00); - cx25840_write(client, 0x801, 0x00); - // DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1 - cx25840_write(client, 0x803, 0x0b); - /* AUTO_INC_DIS=1 */ - cx25840_write(client, 0x000, 0x20); -} - -static void end_fw_load(struct i2c_client *client) -{ - /* AUTO_INC_DIS=0 */ - cx25840_write(client, 0x000, 0x00); - /* DL_ENABLE=0 */ - cx25840_write(client, 0x803, 0x03); -} - -static const char *get_fw_name(struct i2c_client *client) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - - if (firmware[0]) - return firmware; - if (is_cx2388x(state)) - return "v4l-cx23885-avcore-01.fw"; - if (is_cx231xx(state)) - return "v4l-cx231xx-avcore-01.fw"; - return "v4l-cx25840.fw"; -} - -static int check_fw_load(struct i2c_client *client, int size) -{ - /* DL_ADDR_HB DL_ADDR_LB */ - int s = cx25840_read(client, 0x801) << 8; - s |= cx25840_read(client, 0x800); - - if (size != s) { - v4l_err(client, "firmware %s load failed\n", - get_fw_name(client)); - return -EINVAL; - } - - v4l_info(client, "loaded %s firmware (%d bytes)\n", - get_fw_name(client), size); - return 0; -} - -static int fw_write(struct i2c_client *client, const u8 *data, int size) -{ - if (i2c_master_send(client, data, size) < size) { - v4l_err(client, "firmware load i2c failure\n"); - return -ENOSYS; - } - - return 0; -} - -int cx25840_loadfw(struct i2c_client *client) -{ - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - const struct firmware *fw = NULL; - u8 buffer[FWSEND]; - const u8 *ptr; - const char *fwname = get_fw_name(client); - int size, retval; - int MAX_BUF_SIZE = FWSEND; - u32 gpio_oe = 0, gpio_da = 0; - - if (is_cx2388x(state)) { - /* Preserve the GPIO OE and output bits */ - gpio_oe = cx25840_read(client, 0x160); - gpio_da = cx25840_read(client, 0x164); - } - - if (is_cx231xx(state) && MAX_BUF_SIZE > 16) { - v4l_err(client, " Firmware download size changed to 16 bytes max length\n"); - MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */ - } - - if (request_firmware(&fw, fwname, FWDEV(client)) != 0) { - v4l_err(client, "unable to open firmware %s\n", fwname); - return -EINVAL; - } - - start_fw_load(client); - - buffer[0] = 0x08; - buffer[1] = 0x02; - - size = fw->size; - ptr = fw->data; - while (size > 0) { - int len = min(MAX_BUF_SIZE - 2, size); - - memcpy(buffer + 2, ptr, len); - - retval = fw_write(client, buffer, len + 2); - - if (retval < 0) { - release_firmware(fw); - return retval; - } - - size -= len; - ptr += len; - } - - end_fw_load(client); - - size = fw->size; - release_firmware(fw); - - if (is_cx2388x(state)) { - /* Restore GPIO configuration after f/w load */ - cx25840_write(client, 0x160, gpio_oe); - cx25840_write(client, 0x164, gpio_da); - } - - return check_fw_load(client, size); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-ir.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-ir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1280 +0,0 @@ -/* - * Driver for the Conexant CX2584x Audio/Video decoder chip and related cores - * - * Integrated Consumer Infrared Controller - * - * Copyright (C) 2010 Andy Walls - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include -#include -#include -#include - -#include "cx25840-core.h" - -static unsigned int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages"); - -#define CX25840_IR_REG_BASE 0x200 - -#define CX25840_IR_CNTRL_REG 0x200 -#define CNTRL_WIN_3_3 0x00000000 -#define CNTRL_WIN_4_3 0x00000001 -#define CNTRL_WIN_3_4 0x00000002 -#define CNTRL_WIN_4_4 0x00000003 -#define CNTRL_WIN 0x00000003 -#define CNTRL_EDG_NONE 0x00000000 -#define CNTRL_EDG_FALL 0x00000004 -#define CNTRL_EDG_RISE 0x00000008 -#define CNTRL_EDG_BOTH 0x0000000C -#define CNTRL_EDG 0x0000000C -#define CNTRL_DMD 0x00000010 -#define CNTRL_MOD 0x00000020 -#define CNTRL_RFE 0x00000040 -#define CNTRL_TFE 0x00000080 -#define CNTRL_RXE 0x00000100 -#define CNTRL_TXE 0x00000200 -#define CNTRL_RIC 0x00000400 -#define CNTRL_TIC 0x00000800 -#define CNTRL_CPL 0x00001000 -#define CNTRL_LBM 0x00002000 -#define CNTRL_R 0x00004000 - -#define CX25840_IR_TXCLK_REG 0x204 -#define TXCLK_TCD 0x0000FFFF - -#define CX25840_IR_RXCLK_REG 0x208 -#define RXCLK_RCD 0x0000FFFF - -#define CX25840_IR_CDUTY_REG 0x20C -#define CDUTY_CDC 0x0000000F - -#define CX25840_IR_STATS_REG 0x210 -#define STATS_RTO 0x00000001 -#define STATS_ROR 0x00000002 -#define STATS_RBY 0x00000004 -#define STATS_TBY 0x00000008 -#define STATS_RSR 0x00000010 -#define STATS_TSR 0x00000020 - -#define CX25840_IR_IRQEN_REG 0x214 -#define IRQEN_RTE 0x00000001 -#define IRQEN_ROE 0x00000002 -#define IRQEN_RSE 0x00000010 -#define IRQEN_TSE 0x00000020 -#define IRQEN_MSK 0x00000033 - -#define CX25840_IR_FILTR_REG 0x218 -#define FILTR_LPF 0x0000FFFF - -#define CX25840_IR_FIFO_REG 0x23C -#define FIFO_RXTX 0x0000FFFF -#define FIFO_RXTX_LVL 0x00010000 -#define FIFO_RXTX_RTO 0x0001FFFF -#define FIFO_RX_NDV 0x00020000 -#define FIFO_RX_DEPTH 8 -#define FIFO_TX_DEPTH 8 - -#define CX25840_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */ -#define CX25840_IR_REFCLK_FREQ (CX25840_VIDCLK_FREQ / 2) - -/* - * We use this union internally for convenience, but callers to tx_write - * and rx_read will be expecting records of type struct ir_raw_event. - * Always ensure the size of this union is dictated by struct ir_raw_event. - */ -union cx25840_ir_fifo_rec { - u32 hw_fifo_data; - struct ir_raw_event ir_core_data; -}; - -#define CX25840_IR_RX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec)) -#define CX25840_IR_TX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec)) - -struct cx25840_ir_state { - struct i2c_client *c; - - struct v4l2_subdev_ir_parameters rx_params; - struct mutex rx_params_lock; /* protects Rx parameter settings cache */ - atomic_t rxclk_divider; - atomic_t rx_invert; - - struct kfifo rx_kfifo; - spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */ - - struct v4l2_subdev_ir_parameters tx_params; - struct mutex tx_params_lock; /* protects Tx parameter settings cache */ - atomic_t txclk_divider; -}; - -static inline struct cx25840_ir_state *to_ir_state(struct v4l2_subdev *sd) -{ - struct cx25840_state *state = to_state(sd); - return state ? state->ir_state : NULL; -} - - -/* - * Rx and Tx Clock Divider register computations - * - * Note the largest clock divider value of 0xffff corresponds to: - * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns - * which fits in 21 bits, so we'll use unsigned int for time arguments. - */ -static inline u16 count_to_clock_divider(unsigned int d) -{ - if (d > RXCLK_RCD + 1) - d = RXCLK_RCD; - else if (d < 2) - d = 1; - else - d--; - return (u16) d; -} - -static inline u16 ns_to_clock_divider(unsigned int ns) -{ - return count_to_clock_divider( - DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000)); -} - -static inline unsigned int clock_divider_to_ns(unsigned int divider) -{ - /* Period of the Rx or Tx clock in ns */ - return DIV_ROUND_CLOSEST((divider + 1) * 1000, - CX25840_IR_REFCLK_FREQ / 1000000); -} - -static inline u16 carrier_freq_to_clock_divider(unsigned int freq) -{ - return count_to_clock_divider( - DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * 16)); -} - -static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) -{ - return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, (divider + 1) * 16); -} - -static inline u16 freq_to_clock_divider(unsigned int freq, - unsigned int rollovers) -{ - return count_to_clock_divider( - DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * rollovers)); -} - -static inline unsigned int clock_divider_to_freq(unsigned int divider, - unsigned int rollovers) -{ - return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, - (divider + 1) * rollovers); -} - -/* - * Low Pass Filter register calculations - * - * Note the largest count value of 0xffff corresponds to: - * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns - * which fits in 21 bits, so we'll use unsigned int for time arguments. - */ -static inline u16 count_to_lpf_count(unsigned int d) -{ - if (d > FILTR_LPF) - d = FILTR_LPF; - else if (d < 4) - d = 0; - return (u16) d; -} - -static inline u16 ns_to_lpf_count(unsigned int ns) -{ - return count_to_lpf_count( - DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000)); -} - -static inline unsigned int lpf_count_to_ns(unsigned int count) -{ - /* Duration of the Low Pass Filter rejection window in ns */ - return DIV_ROUND_CLOSEST(count * 1000, - CX25840_IR_REFCLK_FREQ / 1000000); -} - -static inline unsigned int lpf_count_to_us(unsigned int count) -{ - /* Duration of the Low Pass Filter rejection window in us */ - return DIV_ROUND_CLOSEST(count, CX25840_IR_REFCLK_FREQ / 1000000); -} - -/* - * FIFO register pulse width count compuations - */ -static u32 clock_divider_to_resolution(u16 divider) -{ - /* - * Resolution is the duration of 1 tick of the readable portion of - * of the pulse width counter as read from the FIFO. The two lsb's are - * not readable, hence the << 2. This function returns ns. - */ - return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, - CX25840_IR_REFCLK_FREQ / 1000000); -} - -static u64 pulse_width_count_to_ns(u16 count, u16 divider) -{ - u64 n; - u32 rem; - - /* - * The 2 lsb's of the pulse width timer count are not readable, hence - * the (count << 2) | 0x3 - */ - n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */ - rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */ - if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2) - n++; - return n; -} - -#if 0 -/* Keep as we will need this for Transmit functionality */ -static u16 ns_to_pulse_width_count(u32 ns, u16 divider) -{ - u64 n; - u32 d; - u32 rem; - - /* - * The 2 lsb's of the pulse width timer count are not accessible, hence - * the (1 << 2) - */ - n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */ - d = (1 << 2) * ((u32) divider + 1) * 1000; /* millicycles/count */ - rem = do_div(n, d); - if (rem >= d / 2) - n++; - - if (n > FIFO_RXTX) - n = FIFO_RXTX; - else if (n == 0) - n = 1; - return (u16) n; -} - -#endif -static unsigned int pulse_width_count_to_us(u16 count, u16 divider) -{ - u64 n; - u32 rem; - - /* - * The 2 lsb's of the pulse width timer count are not readable, hence - * the (count << 2) | 0x3 - */ - n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */ - rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => us */ - if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2) - n++; - return (unsigned int) n; -} - -/* - * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts - * - * The total pulse clock count is an 18 bit pulse width timer count as the most - * significant part and (up to) 16 bit clock divider count as a modulus. - * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse - * width timer count's least significant bit. - */ -static u64 ns_to_pulse_clocks(u32 ns) -{ - u64 clocks; - u32 rem; - clocks = CX25840_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */ - rem = do_div(clocks, 1000); /* /1000 = cycles */ - if (rem >= 1000 / 2) - clocks++; - return clocks; -} - -static u16 pulse_clocks_to_clock_divider(u64 count) -{ - u32 rem; - - rem = do_div(count, (FIFO_RXTX << 2) | 0x3); - - /* net result needs to be rounded down and decremented by 1 */ - if (count > RXCLK_RCD + 1) - count = RXCLK_RCD; - else if (count < 2) - count = 1; - else - count--; - return (u16) count; -} - -/* - * IR Control Register helpers - */ -enum tx_fifo_watermark { - TX_FIFO_HALF_EMPTY = 0, - TX_FIFO_EMPTY = CNTRL_TIC, -}; - -enum rx_fifo_watermark { - RX_FIFO_HALF_FULL = 0, - RX_FIFO_NOT_EMPTY = CNTRL_RIC, -}; - -static inline void control_tx_irq_watermark(struct i2c_client *c, - enum tx_fifo_watermark level) -{ - cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_TIC, level); -} - -static inline void control_rx_irq_watermark(struct i2c_client *c, - enum rx_fifo_watermark level) -{ - cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_RIC, level); -} - -static inline void control_tx_enable(struct i2c_client *c, bool enable) -{ - cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE), - enable ? (CNTRL_TXE | CNTRL_TFE) : 0); -} - -static inline void control_rx_enable(struct i2c_client *c, bool enable) -{ - cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE), - enable ? (CNTRL_RXE | CNTRL_RFE) : 0); -} - -static inline void control_tx_modulation_enable(struct i2c_client *c, - bool enable) -{ - cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_MOD, - enable ? CNTRL_MOD : 0); -} - -static inline void control_rx_demodulation_enable(struct i2c_client *c, - bool enable) -{ - cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_DMD, - enable ? CNTRL_DMD : 0); -} - -static inline void control_rx_s_edge_detection(struct i2c_client *c, - u32 edge_types) -{ - cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_EDG_BOTH, - edge_types & CNTRL_EDG_BOTH); -} - -static void control_rx_s_carrier_window(struct i2c_client *c, - unsigned int carrier, - unsigned int *carrier_range_low, - unsigned int *carrier_range_high) -{ - u32 v; - unsigned int c16 = carrier * 16; - - if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) { - v = CNTRL_WIN_3_4; - *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4); - } else { - v = CNTRL_WIN_3_3; - *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3); - } - - if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { - v |= CNTRL_WIN_4_3; - *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); - } else { - v |= CNTRL_WIN_3_3; - *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); - } - cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_WIN, v); -} - -static inline void control_tx_polarity_invert(struct i2c_client *c, - bool invert) -{ - cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_CPL, - invert ? CNTRL_CPL : 0); -} - -/* - * IR Rx & Tx Clock Register helpers - */ -static unsigned int txclk_tx_s_carrier(struct i2c_client *c, - unsigned int freq, - u16 *divider) -{ - *divider = carrier_freq_to_clock_divider(freq); - cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider); - return clock_divider_to_carrier_freq(*divider); -} - -static unsigned int rxclk_rx_s_carrier(struct i2c_client *c, - unsigned int freq, - u16 *divider) -{ - *divider = carrier_freq_to_clock_divider(freq); - cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider); - return clock_divider_to_carrier_freq(*divider); -} - -static u32 txclk_tx_s_max_pulse_width(struct i2c_client *c, u32 ns, - u16 *divider) -{ - u64 pulse_clocks; - - if (ns > IR_MAX_DURATION) - ns = IR_MAX_DURATION; - pulse_clocks = ns_to_pulse_clocks(ns); - *divider = pulse_clocks_to_clock_divider(pulse_clocks); - cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider); - return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); -} - -static u32 rxclk_rx_s_max_pulse_width(struct i2c_client *c, u32 ns, - u16 *divider) -{ - u64 pulse_clocks; - - if (ns > IR_MAX_DURATION) - ns = IR_MAX_DURATION; - pulse_clocks = ns_to_pulse_clocks(ns); - *divider = pulse_clocks_to_clock_divider(pulse_clocks); - cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider); - return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); -} - -/* - * IR Tx Carrier Duty Cycle register helpers - */ -static unsigned int cduty_tx_s_duty_cycle(struct i2c_client *c, - unsigned int duty_cycle) -{ - u32 n; - n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */ - if (n != 0) - n--; - if (n > 15) - n = 15; - cx25840_write4(c, CX25840_IR_CDUTY_REG, n); - return DIV_ROUND_CLOSEST((n + 1) * 100, 16); -} - -/* - * IR Filter Register helpers - */ -static u32 filter_rx_s_min_width(struct i2c_client *c, u32 min_width_ns) -{ - u32 count = ns_to_lpf_count(min_width_ns); - cx25840_write4(c, CX25840_IR_FILTR_REG, count); - return lpf_count_to_ns(count); -} - -/* - * IR IRQ Enable Register helpers - */ -static inline void irqenable_rx(struct v4l2_subdev *sd, u32 mask) -{ - struct cx25840_state *state = to_state(sd); - - if (is_cx23885(state) || is_cx23887(state)) - mask ^= IRQEN_MSK; - mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE); - cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, - ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask); -} - -static inline void irqenable_tx(struct v4l2_subdev *sd, u32 mask) -{ - struct cx25840_state *state = to_state(sd); - - if (is_cx23885(state) || is_cx23887(state)) - mask ^= IRQEN_MSK; - mask &= IRQEN_TSE; - cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, ~IRQEN_TSE, mask); -} - -/* - * V4L2 Subdevice IR Ops - */ -int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled) -{ - struct cx25840_state *state = to_state(sd); - struct cx25840_ir_state *ir_state = to_ir_state(sd); - struct i2c_client *c = NULL; - unsigned long flags; - - union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; - unsigned int i, j, k; - u32 events, v; - int tsr, rsr, rto, ror, tse, rse, rte, roe, kror; - u32 cntrl, irqen, stats; - - *handled = false; - if (ir_state == NULL) - return -ENODEV; - - c = ir_state->c; - - /* Only support the IR controller for the CX2388[57] AV Core for now */ - if (!(is_cx23885(state) || is_cx23887(state))) - return -ENODEV; - - cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG); - irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG); - if (is_cx23885(state) || is_cx23887(state)) - irqen ^= IRQEN_MSK; - stats = cx25840_read4(c, CX25840_IR_STATS_REG); - - tsr = stats & STATS_TSR; /* Tx FIFO Service Request */ - rsr = stats & STATS_RSR; /* Rx FIFO Service Request */ - rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */ - ror = stats & STATS_ROR; /* Rx FIFO Over Run */ - - tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ - rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ - rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ - roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ - - v4l2_dbg(2, ir_debug, sd, "IR IRQ Status: %s %s %s %s %s %s\n", - tsr ? "tsr" : " ", rsr ? "rsr" : " ", - rto ? "rto" : " ", ror ? "ror" : " ", - stats & STATS_TBY ? "tby" : " ", - stats & STATS_RBY ? "rby" : " "); - - v4l2_dbg(2, ir_debug, sd, "IR IRQ Enables: %s %s %s %s\n", - tse ? "tse" : " ", rse ? "rse" : " ", - rte ? "rte" : " ", roe ? "roe" : " "); - - /* - * Transmitter interrupt service - */ - if (tse && tsr) { - /* - * TODO: - * Check the watermark threshold setting - * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo - * Push the data to the hardware FIFO. - * If there was nothing more to send in the tx_kfifo, disable - * the TSR IRQ and notify the v4l2_device. - * If there was something in the tx_kfifo, check the tx_kfifo - * level and notify the v4l2_device, if it is low. - */ - /* For now, inhibit TSR interrupt until Tx is implemented */ - irqenable_tx(sd, 0); - events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; - v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events); - *handled = true; - } - - /* - * Receiver interrupt service - */ - kror = 0; - if ((rse && rsr) || (rte && rto)) { - /* - * Receive data on RSR to clear the STATS_RSR. - * Receive data on RTO, since we may not have yet hit the RSR - * watermark when we receive the RTO. - */ - for (i = 0, v = FIFO_RX_NDV; - (v & FIFO_RX_NDV) && !kror; i = 0) { - for (j = 0; - (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) { - v = cx25840_read4(c, CX25840_IR_FIFO_REG); - rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV; - i++; - } - if (i == 0) - break; - j = i * sizeof(union cx25840_ir_fifo_rec); - k = kfifo_in_locked(&ir_state->rx_kfifo, - (unsigned char *) rx_data, j, - &ir_state->rx_kfifo_lock); - if (k != j) - kror++; /* rx_kfifo over run */ - } - *handled = true; - } - - events = 0; - v = 0; - if (kror) { - events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; - v4l2_err(sd, "IR receiver software FIFO overrun\n"); - } - if (roe && ror) { - /* - * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear - * the Rx FIFO Over Run status (STATS_ROR) - */ - v |= CNTRL_RFE; - events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; - v4l2_err(sd, "IR receiver hardware FIFO overrun\n"); - } - if (rte && rto) { - /* - * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear - * the Rx Pulse Width Timer Time Out (STATS_RTO) - */ - v |= CNTRL_RXE; - events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; - } - if (v) { - /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ - cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl & ~v); - cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl); - *handled = true; - } - spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); - if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) - events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; - spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); - - if (events) - v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); - return 0; -} - -/* Receiver */ -static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, - ssize_t *num) -{ - struct cx25840_ir_state *ir_state = to_ir_state(sd); - bool invert; - u16 divider; - unsigned int i, n; - union cx25840_ir_fifo_rec *p; - unsigned u, v; - - if (ir_state == NULL) - return -ENODEV; - - invert = (bool) atomic_read(&ir_state->rx_invert); - divider = (u16) atomic_read(&ir_state->rxclk_divider); - - n = count / sizeof(union cx25840_ir_fifo_rec) - * sizeof(union cx25840_ir_fifo_rec); - if (n == 0) { - *num = 0; - return 0; - } - - n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n, - &ir_state->rx_kfifo_lock); - - n /= sizeof(union cx25840_ir_fifo_rec); - *num = n * sizeof(union cx25840_ir_fifo_rec); - - for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) { - - if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { - /* Assume RTO was because of no IR light input */ - u = 0; - v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n"); - } else { - u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; - if (invert) - u = u ? 0 : 1; - } - - v = (unsigned) pulse_width_count_to_ns( - (u16) (p->hw_fifo_data & FIFO_RXTX), divider); - if (v > IR_MAX_DURATION) - v = IR_MAX_DURATION; - - init_ir_raw_event(&p->ir_core_data); - p->ir_core_data.pulse = u; - p->ir_core_data.duration = v; - - v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s\n", - v, u ? "mark" : "space"); - } - return 0; -} - -static int cx25840_ir_rx_g_parameters(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *p) -{ - struct cx25840_ir_state *ir_state = to_ir_state(sd); - - if (ir_state == NULL) - return -ENODEV; - - mutex_lock(&ir_state->rx_params_lock); - memcpy(p, &ir_state->rx_params, - sizeof(struct v4l2_subdev_ir_parameters)); - mutex_unlock(&ir_state->rx_params_lock); - return 0; -} - -static int cx25840_ir_rx_shutdown(struct v4l2_subdev *sd) -{ - struct cx25840_ir_state *ir_state = to_ir_state(sd); - struct i2c_client *c; - - if (ir_state == NULL) - return -ENODEV; - - c = ir_state->c; - mutex_lock(&ir_state->rx_params_lock); - - /* Disable or slow down all IR Rx circuits and counters */ - irqenable_rx(sd, 0); - control_rx_enable(c, false); - control_rx_demodulation_enable(c, false); - control_rx_s_edge_detection(c, CNTRL_EDG_NONE); - filter_rx_s_min_width(c, 0); - cx25840_write4(c, CX25840_IR_RXCLK_REG, RXCLK_RCD); - - ir_state->rx_params.shutdown = true; - - mutex_unlock(&ir_state->rx_params_lock); - return 0; -} - -static int cx25840_ir_rx_s_parameters(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *p) -{ - struct cx25840_ir_state *ir_state = to_ir_state(sd); - struct i2c_client *c; - struct v4l2_subdev_ir_parameters *o; - u16 rxclk_divider; - - if (ir_state == NULL) - return -ENODEV; - - if (p->shutdown) - return cx25840_ir_rx_shutdown(sd); - - if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) - return -ENOSYS; - - c = ir_state->c; - o = &ir_state->rx_params; - - mutex_lock(&ir_state->rx_params_lock); - - o->shutdown = p->shutdown; - - p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; - o->mode = p->mode; - - p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec); - o->bytes_per_data_element = p->bytes_per_data_element; - - /* Before we tweak the hardware, we have to disable the receiver */ - irqenable_rx(sd, 0); - control_rx_enable(c, false); - - control_rx_demodulation_enable(c, p->modulation); - o->modulation = p->modulation; - - if (p->modulation) { - p->carrier_freq = rxclk_rx_s_carrier(c, p->carrier_freq, - &rxclk_divider); - - o->carrier_freq = p->carrier_freq; - - p->duty_cycle = 50; - o->duty_cycle = p->duty_cycle; - - control_rx_s_carrier_window(c, p->carrier_freq, - &p->carrier_range_lower, - &p->carrier_range_upper); - o->carrier_range_lower = p->carrier_range_lower; - o->carrier_range_upper = p->carrier_range_upper; - - p->max_pulse_width = - (u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider); - } else { - p->max_pulse_width = - rxclk_rx_s_max_pulse_width(c, p->max_pulse_width, - &rxclk_divider); - } - o->max_pulse_width = p->max_pulse_width; - atomic_set(&ir_state->rxclk_divider, rxclk_divider); - - p->noise_filter_min_width = - filter_rx_s_min_width(c, p->noise_filter_min_width); - o->noise_filter_min_width = p->noise_filter_min_width; - - p->resolution = clock_divider_to_resolution(rxclk_divider); - o->resolution = p->resolution; - - /* FIXME - make this dependent on resolution for better performance */ - control_rx_irq_watermark(c, RX_FIFO_HALF_FULL); - - control_rx_s_edge_detection(c, CNTRL_EDG_BOTH); - - o->invert_level = p->invert_level; - atomic_set(&ir_state->rx_invert, p->invert_level); - - o->interrupt_enable = p->interrupt_enable; - o->enable = p->enable; - if (p->enable) { - unsigned long flags; - - spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); - kfifo_reset(&ir_state->rx_kfifo); - spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); - if (p->interrupt_enable) - irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); - control_rx_enable(c, p->enable); - } - - mutex_unlock(&ir_state->rx_params_lock); - return 0; -} - -/* Transmitter */ -static int cx25840_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count, - ssize_t *num) -{ - struct cx25840_ir_state *ir_state = to_ir_state(sd); - struct i2c_client *c; - - if (ir_state == NULL) - return -ENODEV; - - c = ir_state->c; -#if 0 - /* - * FIXME - the code below is an incomplete and untested sketch of what - * may need to be done. The critical part is to get 4 (or 8) pulses - * from the tx_kfifo, or converted from ns to the proper units from the - * input, and push them off to the hardware Tx FIFO right away, if the - * HW TX fifo needs service. The rest can be pushed to the tx_kfifo in - * a less critical timeframe. Also watch out for overruning the - * tx_kfifo - don't let it happen and let the caller know not all his - * pulses were written. - */ - u32 *ns_pulse = (u32 *) buf; - unsigned int n; - u32 fifo_pulse[FIFO_TX_DEPTH]; - u32 mark; - - /* Compute how much we can fit in the tx kfifo */ - n = CX25840_IR_TX_KFIFO_SIZE - kfifo_len(ir_state->tx_kfifo); - n = min(n, (unsigned int) count); - n /= sizeof(u32); - - /* FIXME - turn on Tx Fifo service interrupt - * check hardware fifo level, and other stuff - */ - for (i = 0; i < n; ) { - for (j = 0; j < FIFO_TX_DEPTH / 2 && i < n; j++) { - mark = ns_pulse[i] & LEVEL_MASK; - fifo_pulse[j] = ns_to_pulse_width_count( - ns_pulse[i] & - ~LEVEL_MASK, - ir_state->txclk_divider); - if (mark) - fifo_pulse[j] &= FIFO_RXTX_LVL; - i++; - } - kfifo_put(ir_state->tx_kfifo, (u8 *) fifo_pulse, - j * sizeof(u32)); - } - *num = n * sizeof(u32); -#else - /* For now enable the Tx FIFO Service interrupt & pretend we did work */ - irqenable_tx(sd, IRQEN_TSE); - *num = count; -#endif - return 0; -} - -static int cx25840_ir_tx_g_parameters(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *p) -{ - struct cx25840_ir_state *ir_state = to_ir_state(sd); - - if (ir_state == NULL) - return -ENODEV; - - mutex_lock(&ir_state->tx_params_lock); - memcpy(p, &ir_state->tx_params, - sizeof(struct v4l2_subdev_ir_parameters)); - mutex_unlock(&ir_state->tx_params_lock); - return 0; -} - -static int cx25840_ir_tx_shutdown(struct v4l2_subdev *sd) -{ - struct cx25840_ir_state *ir_state = to_ir_state(sd); - struct i2c_client *c; - - if (ir_state == NULL) - return -ENODEV; - - c = ir_state->c; - mutex_lock(&ir_state->tx_params_lock); - - /* Disable or slow down all IR Tx circuits and counters */ - irqenable_tx(sd, 0); - control_tx_enable(c, false); - control_tx_modulation_enable(c, false); - cx25840_write4(c, CX25840_IR_TXCLK_REG, TXCLK_TCD); - - ir_state->tx_params.shutdown = true; - - mutex_unlock(&ir_state->tx_params_lock); - return 0; -} - -static int cx25840_ir_tx_s_parameters(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *p) -{ - struct cx25840_ir_state *ir_state = to_ir_state(sd); - struct i2c_client *c; - struct v4l2_subdev_ir_parameters *o; - u16 txclk_divider; - - if (ir_state == NULL) - return -ENODEV; - - if (p->shutdown) - return cx25840_ir_tx_shutdown(sd); - - if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) - return -ENOSYS; - - c = ir_state->c; - o = &ir_state->tx_params; - mutex_lock(&ir_state->tx_params_lock); - - o->shutdown = p->shutdown; - - p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; - o->mode = p->mode; - - p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec); - o->bytes_per_data_element = p->bytes_per_data_element; - - /* Before we tweak the hardware, we have to disable the transmitter */ - irqenable_tx(sd, 0); - control_tx_enable(c, false); - - control_tx_modulation_enable(c, p->modulation); - o->modulation = p->modulation; - - if (p->modulation) { - p->carrier_freq = txclk_tx_s_carrier(c, p->carrier_freq, - &txclk_divider); - o->carrier_freq = p->carrier_freq; - - p->duty_cycle = cduty_tx_s_duty_cycle(c, p->duty_cycle); - o->duty_cycle = p->duty_cycle; - - p->max_pulse_width = - (u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider); - } else { - p->max_pulse_width = - txclk_tx_s_max_pulse_width(c, p->max_pulse_width, - &txclk_divider); - } - o->max_pulse_width = p->max_pulse_width; - atomic_set(&ir_state->txclk_divider, txclk_divider); - - p->resolution = clock_divider_to_resolution(txclk_divider); - o->resolution = p->resolution; - - /* FIXME - make this dependent on resolution for better performance */ - control_tx_irq_watermark(c, TX_FIFO_HALF_EMPTY); - - control_tx_polarity_invert(c, p->invert_carrier_sense); - o->invert_carrier_sense = p->invert_carrier_sense; - - /* - * FIXME: we don't have hardware help for IO pin level inversion - * here like we have on the CX23888. - * Act on this with some mix of logical inversion of data levels, - * carrier polarity, and carrier duty cycle. - */ - o->invert_level = p->invert_level; - - o->interrupt_enable = p->interrupt_enable; - o->enable = p->enable; - if (p->enable) { - /* reset tx_fifo here */ - if (p->interrupt_enable) - irqenable_tx(sd, IRQEN_TSE); - control_tx_enable(c, p->enable); - } - - mutex_unlock(&ir_state->tx_params_lock); - return 0; -} - - -/* - * V4L2 Subdevice Core Ops support - */ -int cx25840_ir_log_status(struct v4l2_subdev *sd) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *c = state->c; - char *s; - int i, j; - u32 cntrl, txclk, rxclk, cduty, stats, irqen, filtr; - - /* The CX23888 chip doesn't have an IR controller on the A/V core */ - if (is_cx23888(state)) - return 0; - - cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG); - txclk = cx25840_read4(c, CX25840_IR_TXCLK_REG) & TXCLK_TCD; - rxclk = cx25840_read4(c, CX25840_IR_RXCLK_REG) & RXCLK_RCD; - cduty = cx25840_read4(c, CX25840_IR_CDUTY_REG) & CDUTY_CDC; - stats = cx25840_read4(c, CX25840_IR_STATS_REG); - irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG); - if (is_cx23885(state) || is_cx23887(state)) - irqen ^= IRQEN_MSK; - filtr = cx25840_read4(c, CX25840_IR_FILTR_REG) & FILTR_LPF; - - v4l2_info(sd, "IR Receiver:\n"); - v4l2_info(sd, "\tEnabled: %s\n", - cntrl & CNTRL_RXE ? "yes" : "no"); - v4l2_info(sd, "\tDemodulation from a carrier: %s\n", - cntrl & CNTRL_DMD ? "enabled" : "disabled"); - v4l2_info(sd, "\tFIFO: %s\n", - cntrl & CNTRL_RFE ? "enabled" : "disabled"); - switch (cntrl & CNTRL_EDG) { - case CNTRL_EDG_NONE: - s = "disabled"; - break; - case CNTRL_EDG_FALL: - s = "falling edge"; - break; - case CNTRL_EDG_RISE: - s = "rising edge"; - break; - case CNTRL_EDG_BOTH: - s = "rising & falling edges"; - break; - default: - s = "??? edge"; - break; - } - v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s); - v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n", - cntrl & CNTRL_R ? "not loaded" : "overflow marker"); - v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", - cntrl & CNTRL_RIC ? "not empty" : "half full or greater"); - v4l2_info(sd, "\tLoopback mode: %s\n", - cntrl & CNTRL_LBM ? "loopback active" : "normal receive"); - if (cntrl & CNTRL_DMD) { - v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n", - clock_divider_to_carrier_freq(rxclk)); - switch (cntrl & CNTRL_WIN) { - case CNTRL_WIN_3_3: - i = 3; - j = 3; - break; - case CNTRL_WIN_4_3: - i = 4; - j = 3; - break; - case CNTRL_WIN_3_4: - i = 3; - j = 4; - break; - case CNTRL_WIN_4_4: - i = 4; - j = 4; - break; - default: - i = 0; - j = 0; - break; - } - v4l2_info(sd, "\tNext carrier edge window: 16 clocks " - "-%1d/+%1d, %u to %u Hz\n", i, j, - clock_divider_to_freq(rxclk, 16 + j), - clock_divider_to_freq(rxclk, 16 - i)); - } - v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n", - pulse_width_count_to_us(FIFO_RXTX, rxclk), - pulse_width_count_to_ns(FIFO_RXTX, rxclk)); - v4l2_info(sd, "\tLow pass filter: %s\n", - filtr ? "enabled" : "disabled"); - if (filtr) - v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " - "%u ns\n", - lpf_count_to_us(filtr), - lpf_count_to_ns(filtr)); - v4l2_info(sd, "\tPulse width timer timed-out: %s\n", - stats & STATS_RTO ? "yes" : "no"); - v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", - irqen & IRQEN_RTE ? "enabled" : "disabled"); - v4l2_info(sd, "\tFIFO overrun: %s\n", - stats & STATS_ROR ? "yes" : "no"); - v4l2_info(sd, "\tFIFO overrun interrupt: %s\n", - irqen & IRQEN_ROE ? "enabled" : "disabled"); - v4l2_info(sd, "\tBusy: %s\n", - stats & STATS_RBY ? "yes" : "no"); - v4l2_info(sd, "\tFIFO service requested: %s\n", - stats & STATS_RSR ? "yes" : "no"); - v4l2_info(sd, "\tFIFO service request interrupt: %s\n", - irqen & IRQEN_RSE ? "enabled" : "disabled"); - - v4l2_info(sd, "IR Transmitter:\n"); - v4l2_info(sd, "\tEnabled: %s\n", - cntrl & CNTRL_TXE ? "yes" : "no"); - v4l2_info(sd, "\tModulation onto a carrier: %s\n", - cntrl & CNTRL_MOD ? "enabled" : "disabled"); - v4l2_info(sd, "\tFIFO: %s\n", - cntrl & CNTRL_TFE ? "enabled" : "disabled"); - v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", - cntrl & CNTRL_TIC ? "not empty" : "half full or less"); - v4l2_info(sd, "\tCarrier polarity: %s\n", - cntrl & CNTRL_CPL ? "space:burst mark:noburst" - : "space:noburst mark:burst"); - if (cntrl & CNTRL_MOD) { - v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n", - clock_divider_to_carrier_freq(txclk)); - v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n", - cduty + 1); - } - v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n", - pulse_width_count_to_us(FIFO_RXTX, txclk), - pulse_width_count_to_ns(FIFO_RXTX, txclk)); - v4l2_info(sd, "\tBusy: %s\n", - stats & STATS_TBY ? "yes" : "no"); - v4l2_info(sd, "\tFIFO service requested: %s\n", - stats & STATS_TSR ? "yes" : "no"); - v4l2_info(sd, "\tFIFO service request interrupt: %s\n", - irqen & IRQEN_TSE ? "enabled" : "disabled"); - - return 0; -} - - -const struct v4l2_subdev_ir_ops cx25840_ir_ops = { - .rx_read = cx25840_ir_rx_read, - .rx_g_parameters = cx25840_ir_rx_g_parameters, - .rx_s_parameters = cx25840_ir_rx_s_parameters, - - .tx_write = cx25840_ir_tx_write, - .tx_g_parameters = cx25840_ir_tx_g_parameters, - .tx_s_parameters = cx25840_ir_tx_s_parameters, -}; - - -static const struct v4l2_subdev_ir_parameters default_rx_params = { - .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec), - .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, - - .enable = false, - .interrupt_enable = false, - .shutdown = true, - - .modulation = true, - .carrier_freq = 36000, /* 36 kHz - RC-5, and RC-6 carrier */ - - /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ - /* RC-6: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ - .noise_filter_min_width = 333333, /* ns */ - .carrier_range_lower = 35000, - .carrier_range_upper = 37000, - .invert_level = false, -}; - -static const struct v4l2_subdev_ir_parameters default_tx_params = { - .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec), - .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, - - .enable = false, - .interrupt_enable = false, - .shutdown = true, - - .modulation = true, - .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ - .duty_cycle = 25, /* 25 % - RC-5 carrier */ - .invert_level = false, - .invert_carrier_sense = false, -}; - -int cx25840_ir_probe(struct v4l2_subdev *sd) -{ - struct cx25840_state *state = to_state(sd); - struct cx25840_ir_state *ir_state; - struct v4l2_subdev_ir_parameters default_params; - - /* Only init the IR controller for the CX2388[57] AV Core for now */ - if (!(is_cx23885(state) || is_cx23887(state))) - return 0; - - ir_state = kzalloc(sizeof(struct cx25840_ir_state), GFP_KERNEL); - if (ir_state == NULL) - return -ENOMEM; - - spin_lock_init(&ir_state->rx_kfifo_lock); - if (kfifo_alloc(&ir_state->rx_kfifo, - CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) { - kfree(ir_state); - return -ENOMEM; - } - - ir_state->c = state->c; - state->ir_state = ir_state; - - /* Ensure no interrupts arrive yet */ - if (is_cx23885(state) || is_cx23887(state)) - cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, IRQEN_MSK); - else - cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0); - - mutex_init(&ir_state->rx_params_lock); - memcpy(&default_params, &default_rx_params, - sizeof(struct v4l2_subdev_ir_parameters)); - v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); - - mutex_init(&ir_state->tx_params_lock); - memcpy(&default_params, &default_tx_params, - sizeof(struct v4l2_subdev_ir_parameters)); - v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); - - return 0; -} - -int cx25840_ir_remove(struct v4l2_subdev *sd) -{ - struct cx25840_state *state = to_state(sd); - struct cx25840_ir_state *ir_state = to_ir_state(sd); - - if (ir_state == NULL) - return -ENODEV; - - cx25840_ir_rx_shutdown(sd); - cx25840_ir_tx_shutdown(sd); - - kfifo_free(&ir_state->rx_kfifo); - kfree(ir_state); - state->ir_state = NULL; - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-vbi.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/cx25840-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,256 +0,0 @@ -/* cx25840 VBI functions - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#include -#include -#include -#include - -#include "cx25840-core.h" - -static int odd_parity(u8 c) -{ - c ^= (c >> 4); - c ^= (c >> 2); - c ^= (c >> 1); - - return c & 1; -} - -static int decode_vps(u8 * dst, u8 * p) -{ - static const u8 biphase_tbl[] = { - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, - 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, - 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, - 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, - 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, - 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, - 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, - 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, - 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, - 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, - 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, - 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, - 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, - 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, - 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, - 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, - 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, - 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, - 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, - 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, - 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, - 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - }; - - u8 c, err = 0; - int i; - - for (i = 0; i < 2 * 13; i += 2) { - err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; - c = (biphase_tbl[p[i + 1]] & 0xf) | - ((biphase_tbl[p[i]] & 0xf) << 4); - dst[i / 2] = c; - } - - return err & 0xf0; -} - -int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct cx25840_state *state = to_state(sd); - static const u16 lcr2vbi[] = { - 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ - 0, V4L2_SLICED_WSS_625, 0, /* 4 */ - V4L2_SLICED_CAPTION_525, /* 6 */ - 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ - 0, 0, 0, 0 - }; - int is_pal = !(state->std & V4L2_STD_525_60); - int i; - - memset(svbi, 0, sizeof(*svbi)); - /* we're done if raw VBI is active */ - if ((cx25840_read(client, 0x404) & 0x10) == 0) - return 0; - - if (is_pal) { - for (i = 7; i <= 23; i++) { - u8 v = cx25840_read(client, 0x424 + i - 7); - - svbi->service_lines[0][i] = lcr2vbi[v >> 4]; - svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; - svbi->service_set |= svbi->service_lines[0][i] | - svbi->service_lines[1][i]; - } - } else { - for (i = 10; i <= 21; i++) { - u8 v = cx25840_read(client, 0x424 + i - 10); - - svbi->service_lines[0][i] = lcr2vbi[v >> 4]; - svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; - svbi->service_set |= svbi->service_lines[0][i] | - svbi->service_lines[1][i]; - } - } - return 0; -} - -int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct cx25840_state *state = to_state(sd); - int is_pal = !(state->std & V4L2_STD_525_60); - int vbi_offset = is_pal ? 1 : 0; - - /* Setup standard */ - cx25840_std_setup(client); - - /* VBI Offset */ - cx25840_write(client, 0x47f, vbi_offset); - cx25840_write(client, 0x404, 0x2e); - return 0; -} - -int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct cx25840_state *state = to_state(sd); - int is_pal = !(state->std & V4L2_STD_525_60); - int vbi_offset = is_pal ? 1 : 0; - int i, x; - u8 lcr[24]; - - for (x = 0; x <= 23; x++) - lcr[x] = 0x00; - - /* Setup standard */ - cx25840_std_setup(client); - - /* Sliced VBI */ - cx25840_write(client, 0x404, 0x32); /* Ancillary data */ - cx25840_write(client, 0x406, 0x13); - cx25840_write(client, 0x47f, vbi_offset); - - if (is_pal) { - for (i = 0; i <= 6; i++) - svbi->service_lines[0][i] = - svbi->service_lines[1][i] = 0; - } else { - for (i = 0; i <= 9; i++) - svbi->service_lines[0][i] = - svbi->service_lines[1][i] = 0; - - for (i = 22; i <= 23; i++) - svbi->service_lines[0][i] = - svbi->service_lines[1][i] = 0; - } - - for (i = 7; i <= 23; i++) { - for (x = 0; x <= 1; x++) { - switch (svbi->service_lines[1-x][i]) { - case V4L2_SLICED_TELETEXT_B: - lcr[i] |= 1 << (4 * x); - break; - case V4L2_SLICED_WSS_625: - lcr[i] |= 4 << (4 * x); - break; - case V4L2_SLICED_CAPTION_525: - lcr[i] |= 6 << (4 * x); - break; - case V4L2_SLICED_VPS: - lcr[i] |= 9 << (4 * x); - break; - } - } - } - - if (is_pal) { - for (x = 1, i = 0x424; i <= 0x434; i++, x++) - cx25840_write(client, i, lcr[6 + x]); - } else { - for (x = 1, i = 0x424; i <= 0x430; i++, x++) - cx25840_write(client, i, lcr[9 + x]); - for (i = 0x431; i <= 0x434; i++) - cx25840_write(client, i, 0); - } - - cx25840_write(client, 0x43c, 0x16); - cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22); - return 0; -} - -int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi) -{ - struct cx25840_state *state = to_state(sd); - u8 *p = vbi->p; - int id1, id2, l, err = 0; - - if (p[0] || p[1] != 0xff || p[2] != 0xff || - (p[3] != 0x55 && p[3] != 0x91)) { - vbi->line = vbi->type = 0; - return 0; - } - - p += 4; - id1 = p[-1]; - id2 = p[0] & 0xf; - l = p[2] & 0x3f; - l += state->vbi_line_offset; - p += 4; - - switch (id2) { - case 1: - id2 = V4L2_SLICED_TELETEXT_B; - break; - case 4: - id2 = V4L2_SLICED_WSS_625; - break; - case 6: - id2 = V4L2_SLICED_CAPTION_525; - err = !odd_parity(p[0]) || !odd_parity(p[1]); - break; - case 9: - id2 = V4L2_SLICED_VPS; - if (decode_vps(p, p) != 0) - err = 1; - break; - default: - id2 = 0; - err = 1; - break; - } - - vbi->type = err ? 0 : id2; - vbi->line = err ? 0 : l; - vbi->is_second_field = err ? 0 : (id1 == 0x55); - vbi->p = p; - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -config VIDEO_CX25840 - tristate "Conexant CX2584x audio/video decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Conexant CX2584x audio/video decoders. - - To compile this driver as a module, choose M here: the - module will be called cx25840 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx25840/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ - cx25840-vbi.o cx25840-ir.o - -obj-$(CONFIG_VIDEO_CX25840) += cx25840.o - -EXTRA_CFLAGS += -Idrivers/media/video diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-alsa.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-alsa.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-alsa.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-alsa.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1003 +0,0 @@ -/* - * - * Support for audio capture - * PCI function #1 of the cx2388x. - * - * (c) 2007 Trent Piepho - * (c) 2005,2006 Ricardo Cerqueira - * (c) 2005 Mauro Carvalho Chehab - * Based on a dummy cx88 module by Gerd Knorr - * Based on dummy.c by Jaroslav Kysela - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx88.h" -#include "cx88-reg.h" - -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg) - -#define dprintk_core(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg) - -/**************************************************************************** - Data type declarations - Can be moded to a header file later - ****************************************************************************/ - -struct cx88_audio_buffer { - unsigned int bpl; - struct btcx_riscmem risc; - struct videobuf_dmabuf dma; -}; - -struct cx88_audio_dev { - struct cx88_core *core; - struct cx88_dmaqueue q; - - /* pci i/o */ - struct pci_dev *pci; - - /* audio controls */ - int irq; - - struct snd_card *card; - - spinlock_t reg_lock; - atomic_t count; - - unsigned int dma_size; - unsigned int period_size; - unsigned int num_periods; - - struct videobuf_dmabuf *dma_risc; - - struct cx88_audio_buffer *buf; - - struct snd_pcm_substream *substream; -}; -typedef struct cx88_audio_dev snd_cx88_card_t; - - - -/**************************************************************************** - Module global static vars - ****************************************************************************/ - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; - -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled."); - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s)."); - - -/**************************************************************************** - Module macros - ****************************************************************************/ - -MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards"); -MODULE_AUTHOR("Ricardo Cerqueira"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Conexant,23881}," - "{{Conexant,23882}," - "{{Conexant,23883}"); -static unsigned int debug; -module_param(debug,int,0644); -MODULE_PARM_DESC(debug,"enable debug messages"); - -/**************************************************************************** - Module specific funtions - ****************************************************************************/ - -/* - * BOARD Specific: Sets audio DMA - */ - -static int _cx88_start_audio_dma(snd_cx88_card_t *chip) -{ - struct cx88_audio_buffer *buf = chip->buf; - struct cx88_core *core=chip->core; - const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25]; - - /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ - cx_clear(MO_AUD_DMACNTRL, 0x11); - - /* setup fifo + format - out channel */ - cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma); - - /* sets bpl size */ - cx_write(MO_AUDD_LNGTH, buf->bpl); - - /* reset counter */ - cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); - atomic_set(&chip->count, 0); - - dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d " - "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, - chip->num_periods, buf->bpl * chip->num_periods); - - /* Enables corresponding bits at AUD_INT_STAT */ - cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | - AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); - - /* Clean any pending interrupt bits already set */ - cx_write(MO_AUD_INTSTAT, ~0); - - /* enable audio irqs */ - cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); - - /* start dma */ - cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */ - cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */ - - if (debug) - cx88_sram_channel_dump(chip->core, audio_ch); - - return 0; -} - -/* - * BOARD Specific: Resets audio DMA - */ -static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) -{ - struct cx88_core *core=chip->core; - dprintk(1, "Stopping audio DMA\n"); - - /* stop dma */ - cx_clear(MO_AUD_DMACNTRL, 0x11); - - /* disable irqs */ - cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); - cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | - AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); - - if (debug) - cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); - - return 0; -} - -#define MAX_IRQ_LOOP 50 - -/* - * BOARD Specific: IRQ dma bits - */ -static const char *cx88_aud_irqs[32] = { - "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */ - NULL, /* reserved */ - "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */ - NULL, /* reserved */ - "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ - NULL, /* reserved */ - "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ - NULL, /* reserved */ - "opc_err", "par_err", "rip_err", /* 16-18 */ - "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ -}; - -/* - * BOARD Specific: Threats IRQ audio specific calls - */ -static void cx8801_aud_irq(snd_cx88_card_t *chip) -{ - struct cx88_core *core = chip->core; - u32 status, mask; - - status = cx_read(MO_AUD_INTSTAT); - mask = cx_read(MO_AUD_INTMSK); - if (0 == (status & mask)) - return; - cx_write(MO_AUD_INTSTAT, status); - if (debug > 1 || (status & mask & ~0xff)) - cx88_print_irqbits(core->name, "irq aud", - cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), - status, mask); - /* risc op code error */ - if (status & AUD_INT_OPC_ERR) { - printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name); - cx_clear(MO_AUD_DMACNTRL, 0x11); - cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); - } - if (status & AUD_INT_DN_SYNC) { - dprintk(1, "Downstream sync error\n"); - cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); - return; - } - /* risc1 downstream */ - if (status & AUD_INT_DN_RISCI1) { - atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT)); - snd_pcm_period_elapsed(chip->substream); - } - /* FIXME: Any other status should deserve a special handling? */ -} - -/* - * BOARD Specific: Handles IRQ calls - */ -static irqreturn_t cx8801_irq(int irq, void *dev_id) -{ - snd_cx88_card_t *chip = dev_id; - struct cx88_core *core = chip->core; - u32 status; - int loop, handled = 0; - - for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & - (core->pci_irqmask | PCI_INT_AUDINT); - if (0 == status) - goto out; - dprintk(3, "cx8801_irq loop %d/%d, status %x\n", - loop, MAX_IRQ_LOOP, status); - handled = 1; - cx_write(MO_PCI_INTSTAT, status); - - if (status & core->pci_irqmask) - cx88_core_irq(core, status); - if (status & PCI_INT_AUDINT) - cx8801_aud_irq(chip); - } - - if (MAX_IRQ_LOOP == loop) { - printk(KERN_ERR - "%s/1: IRQ loop detected, disabling interrupts\n", - core->name); - cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); - } - - out: - return IRQ_RETVAL(handled); -} - - -static int dsp_buffer_free(snd_cx88_card_t *chip) -{ - BUG_ON(!chip->dma_size); - - dprintk(2,"Freeing buffer\n"); - videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); - videobuf_dma_free(chip->dma_risc); - btcx_riscmem_free(chip->pci,&chip->buf->risc); - kfree(chip->buf); - - chip->dma_risc = NULL; - chip->dma_size = 0; - - return 0; -} - -/**************************************************************************** - ALSA PCM Interface - ****************************************************************************/ - -/* - * Digital hardware definition - */ -#define DEFAULT_FIFO_SIZE 4096 -static const struct snd_pcm_hardware snd_cx88_digital_hw = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - /* Analog audio output will be full of clicks and pops if there - are not exactly four lines in the SRAM FIFO buffer. */ - .period_bytes_min = DEFAULT_FIFO_SIZE/4, - .period_bytes_max = DEFAULT_FIFO_SIZE/4, - .periods_min = 1, - .periods_max = 1024, - .buffer_bytes_max = (1024*1024), -}; - -/* - * audio pcm capture open callback - */ -static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) -{ - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - if (!chip) { - printk(KERN_ERR "BUG: cx88 can't find device struct." - " Can't proceed with open\n"); - return -ENODEV; - } - - err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) - goto _error; - - chip->substream = substream; - - runtime->hw = snd_cx88_digital_hw; - - if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) { - unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4; - bpl &= ~7; /* must be multiple of 8 */ - runtime->hw.period_bytes_min = bpl; - runtime->hw.period_bytes_max = bpl; - } - - return 0; -_error: - dprintk(1,"Error opening PCM!\n"); - return err; -} - -/* - * audio close callback - */ -static int snd_cx88_close(struct snd_pcm_substream *substream) -{ - return 0; -} - -/* - * hw_params callback - */ -static int snd_cx88_hw_params(struct snd_pcm_substream * substream, - struct snd_pcm_hw_params * hw_params) -{ - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); - struct videobuf_dmabuf *dma; - - struct cx88_audio_buffer *buf; - int ret; - - if (substream->runtime->dma_area) { - dsp_buffer_free(chip); - substream->runtime->dma_area = NULL; - } - - chip->period_size = params_period_bytes(hw_params); - chip->num_periods = params_periods(hw_params); - chip->dma_size = chip->period_size * params_periods(hw_params); - - BUG_ON(!chip->dma_size); - BUG_ON(chip->num_periods & (chip->num_periods-1)); - - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (NULL == buf) - return -ENOMEM; - - buf->bpl = chip->period_size; - - dma = &buf->dma; - videobuf_dma_init(dma); - ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, - (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); - if (ret < 0) - goto error; - - ret = videobuf_dma_map(&chip->pci->dev, dma); - if (ret < 0) - goto error; - - ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist, - chip->period_size, chip->num_periods, 1); - if (ret < 0) - goto error; - - /* Loop back to start of program */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - - chip->buf = buf; - chip->dma_risc = dma; - - substream->runtime->dma_area = chip->dma_risc->vaddr; - substream->runtime->dma_bytes = chip->dma_size; - substream->runtime->dma_addr = 0; - return 0; - -error: - kfree(buf); - return ret; -} - -/* - * hw free callback - */ -static int snd_cx88_hw_free(struct snd_pcm_substream * substream) -{ - - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); - - if (substream->runtime->dma_area) { - dsp_buffer_free(chip); - substream->runtime->dma_area = NULL; - } - - return 0; -} - -/* - * prepare callback - */ -static int snd_cx88_prepare(struct snd_pcm_substream *substream) -{ - return 0; -} - -/* - * trigger callback - */ -static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd) -{ - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); - int err; - - /* Local interrupts are already disabled by ALSA */ - spin_lock(&chip->reg_lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - err=_cx88_start_audio_dma(chip); - break; - case SNDRV_PCM_TRIGGER_STOP: - err=_cx88_stop_audio_dma(chip); - break; - default: - err=-EINVAL; - break; - } - - spin_unlock(&chip->reg_lock); - - return err; -} - -/* - * pointer callback - */ -static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) -{ - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - u16 count; - - count = atomic_read(&chip->count); - -// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__, -// count, new, count & (runtime->periods-1), -// runtime->period_size * (count & (runtime->periods-1))); - return runtime->period_size * (count & (runtime->periods-1)); -} - -/* - * page callback (needed for mmap) - */ -static struct page *snd_cx88_page(struct snd_pcm_substream *substream, - unsigned long offset) -{ - void *pageptr = substream->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -/* - * operators - */ -static struct snd_pcm_ops snd_cx88_pcm_ops = { - .open = snd_cx88_pcm_open, - .close = snd_cx88_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_cx88_hw_params, - .hw_free = snd_cx88_hw_free, - .prepare = snd_cx88_prepare, - .trigger = snd_cx88_card_trigger, - .pointer = snd_cx88_pointer, - .page = snd_cx88_page, -}; - -/* - * create a PCM device - */ -static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name) -{ - int err; - struct snd_pcm *pcm; - - err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); - if (err < 0) - return err; - pcm->private_data = chip; - strcpy(pcm->name, name); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops); - - return 0; -} - -/**************************************************************************** - CONTROL INTERFACE - ****************************************************************************/ -static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 2; - info->value.integer.min = 0; - info->value.integer.max = 0x3f; - - return 0; -} - -static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core=chip->core; - int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f), - bal = cx_read(AUD_BAL_CTL); - - value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol; - vol -= (bal & 0x3f); - value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol; - - return 0; -} - -static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core = chip->core; - struct v4l2_control client_ctl; - int left = value->value.integer.value[0]; - int right = value->value.integer.value[1]; - int v, b; - - memset(&client_ctl, 0, sizeof(client_ctl)); - - /* Pass volume & balance onto any WM8775 */ - if (left >= right) { - v = left << 10; - b = left ? (0x8000 * right) / left : 0x8000; - } else { - v = right << 10; - b = right ? 0xffff - (0x8000 * left) / right : 0x8000; - } - client_ctl.value = v; - client_ctl.id = V4L2_CID_AUDIO_VOLUME; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - - client_ctl.value = b; - client_ctl.id = V4L2_CID_AUDIO_BALANCE; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); -} - -/* OK - TODO: test it */ -static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core=chip->core; - int left, right, v, b; - int changed = 0; - u32 old; - - if (core->board.audio_chip == V4L2_IDENT_WM8775) - snd_cx88_wm8775_volume_put(kcontrol, value); - - left = value->value.integer.value[0] & 0x3f; - right = value->value.integer.value[1] & 0x3f; - b = right - left; - if (b < 0) { - v = 0x3f - left; - b = (-b) | 0x40; - } else { - v = 0x3f - right; - } - /* Do we really know this will always be called with IRQs on? */ - spin_lock_irq(&chip->reg_lock); - old = cx_read(AUD_VOL_CTL); - if (v != (old & 0x3f)) { - cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v); - changed = 1; - } - if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) { - cx_write(AUD_BAL_CTL, b); - changed = 1; - } - spin_unlock_irq(&chip->reg_lock); - - return changed; -} - -static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0); - -static const struct snd_kcontrol_new snd_cx88_volume = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .name = "Analog-TV Volume", - .info = snd_cx88_volume_info, - .get = snd_cx88_volume_get, - .put = snd_cx88_volume_put, - .tlv.p = snd_cx88_db_scale, -}; - -static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core = chip->core; - u32 bit = kcontrol->private_value; - - value->value.integer.value[0] = !(cx_read(AUD_VOL_CTL) & bit); - return 0; -} - -static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core = chip->core; - u32 bit = kcontrol->private_value; - int ret = 0; - u32 vol; - - spin_lock_irq(&chip->reg_lock); - vol = cx_read(AUD_VOL_CTL); - if (value->value.integer.value[0] != !(vol & bit)) { - vol ^= bit; - cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol); - /* Pass mute onto any WM8775 */ - if ((core->board.audio_chip == V4L2_IDENT_WM8775) && - ((1<<6) == bit)) { - struct v4l2_control client_ctl; - - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.value = 0 != (vol & bit); - client_ctl.id = V4L2_CID_AUDIO_MUTE; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - } - ret = 1; - } - spin_unlock_irq(&chip->reg_lock); - return ret; -} - -static const struct snd_kcontrol_new snd_cx88_dac_switch = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Audio-Out Switch", - .info = snd_ctl_boolean_mono_info, - .get = snd_cx88_switch_get, - .put = snd_cx88_switch_put, - .private_value = (1<<8), -}; - -static const struct snd_kcontrol_new snd_cx88_source_switch = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog-TV Switch", - .info = snd_ctl_boolean_mono_info, - .get = snd_cx88_switch_get, - .put = snd_cx88_switch_put, - .private_value = (1<<6), -}; - -static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core = chip->core; - struct v4l2_control client_ctl; - - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; - call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl); - value->value.integer.value[0] = client_ctl.value ? 1 : 0; - - return 0; -} - -static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core = chip->core; - struct v4l2_control client_ctl; - - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.value = 0 != value->value.integer.value[0]; - client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - - return 0; -} - -static struct snd_kcontrol_new snd_cx88_alc_switch = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line-In ALC Switch", - .info = snd_ctl_boolean_mono_info, - .get = snd_cx88_alc_get, - .put = snd_cx88_alc_put, -}; - -/**************************************************************************** - Basic Flow for Sound Devices - ****************************************************************************/ - -/* - * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio - * Only boards with eeprom and byte 1 at eeprom=1 have it - */ - -static const struct pci_device_id const cx88_audio_pci_tbl[] __devinitdata = { - {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {0, } -}; -MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl); - -/* - * Chip-specific destructor - */ - -static int snd_cx88_free(snd_cx88_card_t *chip) -{ - - if (chip->irq >= 0) - free_irq(chip->irq, chip); - - cx88_core_put(chip->core,chip->pci); - - pci_disable_device(chip->pci); - return 0; -} - -/* - * Component Destructor - */ -static void snd_cx88_dev_free(struct snd_card * card) -{ - snd_cx88_card_t *chip = card->private_data; - - snd_cx88_free(chip); -} - - -/* - * Alsa Constructor - Component probe - */ - -static int devno; -static int __devinit snd_cx88_create(struct snd_card *card, - struct pci_dev *pci, - snd_cx88_card_t **rchip, - struct cx88_core **core_ptr) -{ - snd_cx88_card_t *chip; - struct cx88_core *core; - int err; - unsigned char pci_lat; - - *rchip = NULL; - - err = pci_enable_device(pci); - if (err < 0) - return err; - - pci_set_master(pci); - - chip = card->private_data; - - core = cx88_core_get(pci); - if (NULL == core) { - err = -EINVAL; - return err; - } - - if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) { - dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); - err = -EIO; - cx88_core_put(core, pci); - return err; - } - - - /* pci init */ - chip->card = card; - chip->pci = pci; - chip->irq = -1; - spin_lock_init(&chip->reg_lock); - - chip->core = core; - - /* get irq */ - err = request_irq(chip->pci->irq, cx8801_irq, - IRQF_SHARED | IRQF_DISABLED, chip->core->name, chip); - if (err < 0) { - dprintk(0, "%s: can't get IRQ %d\n", - chip->core->name, chip->pci->irq); - return err; - } - - /* print pci info */ - pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat); - - dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", core->name, devno, - pci_name(pci), pci->revision, pci->irq, - pci_lat, (unsigned long long)pci_resource_start(pci,0)); - - chip->irq = pci->irq; - synchronize_irq(chip->irq); - - snd_card_set_dev(card, &pci->dev); - - *rchip = chip; - *core_ptr = core; - - return 0; -} - -static int __devinit cx88_audio_initdev(struct pci_dev *pci, - const struct pci_device_id *pci_id) -{ - struct snd_card *card; - snd_cx88_card_t *chip; - struct cx88_core *core = NULL; - int err; - - if (devno >= SNDRV_CARDS) - return (-ENODEV); - - if (!enable[devno]) { - ++devno; - return (-ENOENT); - } - - err = snd_card_create(index[devno], id[devno], THIS_MODULE, - sizeof(snd_cx88_card_t), &card); - if (err < 0) - return err; - - card->private_free = snd_cx88_dev_free; - - err = snd_cx88_create(card, pci, &chip, &core); - if (err < 0) - goto error; - - err = snd_cx88_pcm(chip, 0, "CX88 Digital"); - if (err < 0) - goto error; - - err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_volume, chip)); - if (err < 0) - goto error; - err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_dac_switch, chip)); - if (err < 0) - goto error; - err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_source_switch, chip)); - if (err < 0) - goto error; - - /* If there's a wm8775 then add a Line-In ALC switch */ - if (core->board.audio_chip == V4L2_IDENT_WM8775) - snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip)); - - strcpy (card->driver, "CX88x"); - sprintf(card->shortname, "Conexant CX%x", pci->device); - sprintf(card->longname, "%s at %#llx", - card->shortname,(unsigned long long)pci_resource_start(pci, 0)); - strcpy (card->mixername, "CX88"); - - dprintk (0, "%s/%i: ALSA support for cx2388x boards\n", - card->driver,devno); - - err = snd_card_register(card); - if (err < 0) - goto error; - pci_set_drvdata(pci,card); - - devno++; - return 0; - -error: - snd_card_free(card); - return err; -} -/* - * ALSA destructor - */ -static void __devexit cx88_audio_finidev(struct pci_dev *pci) -{ - struct cx88_audio_dev *card = pci_get_drvdata(pci); - - snd_card_free((void *)card); - - pci_set_drvdata(pci, NULL); - - devno--; -} - -/* - * PCI driver definition - */ - -static struct pci_driver cx88_audio_pci_driver = { - .name = "cx88_audio", - .id_table = cx88_audio_pci_tbl, - .probe = cx88_audio_initdev, - .remove = __devexit_p(cx88_audio_finidev), -}; - -/**************************************************************************** - LINUX MODULE INIT - ****************************************************************************/ - -/* - * module init - */ -static int __init cx88_audio_init(void) -{ - printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return pci_register_driver(&cx88_audio_pci_driver); -} - -/* - * module remove - */ -static void __exit cx88_audio_fini(void) -{ - pci_unregister_driver(&cx88_audio_pci_driver); -} - -module_init(cx88_audio_init); -module_exit(cx88_audio_fini); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-blackbird.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-blackbird.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-blackbird.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-blackbird.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1396 +0,0 @@ -/* - * - * Support for a cx23416 mpeg encoder via cx2388x host port. - * "blackbird" reference design. - * - * (c) 2004 Jelle Foks - * (c) 2004 Gerd Knorr - * - * (c) 2005-2006 Mauro Carvalho Chehab - * - video_ioctl2 conversion - * - * Includes parts from the ivtv driver - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx88.h" - -MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); -MODULE_AUTHOR("Jelle Foks , Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -static unsigned int mpegbufs = 32; -module_param(mpegbufs,int,0644); -MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32"); - -static unsigned int debug; -module_param(debug,int,0644); -MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); - -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg) - - -/* ------------------------------------------------------------------ */ - -#define BLACKBIRD_FIRM_IMAGE_SIZE 376836 - -/* defines below are from ivtv-driver.h */ - -#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF - -/* Firmware API commands */ -#define IVTV_API_STD_TIMEOUT 500 - -enum blackbird_capture_type { - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_CAPTURE, - BLACKBIRD_RAW_PASSTHRU_CAPTURE -}; -enum blackbird_capture_bits { - BLACKBIRD_RAW_BITS_NONE = 0x00, - BLACKBIRD_RAW_BITS_YUV_CAPTURE = 0x01, - BLACKBIRD_RAW_BITS_PCM_CAPTURE = 0x02, - BLACKBIRD_RAW_BITS_VBI_CAPTURE = 0x04, - BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08, - BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE = 0x10 -}; -enum blackbird_capture_end { - BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */ - BLACKBIRD_END_NOW, /* stop immediately, no irq */ -}; -enum blackbird_framerate { - BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */ - BLACKBIRD_FRAMERATE_PAL_25 /* PAL: 25fps */ -}; -enum blackbird_stream_port { - BLACKBIRD_OUTPUT_PORT_MEMORY, - BLACKBIRD_OUTPUT_PORT_STREAMING, - BLACKBIRD_OUTPUT_PORT_SERIAL -}; -enum blackbird_data_xfer_status { - BLACKBIRD_MORE_BUFFERS_FOLLOW, - BLACKBIRD_LAST_BUFFER, -}; -enum blackbird_picture_mask { - BLACKBIRD_PICTURE_MASK_NONE, - BLACKBIRD_PICTURE_MASK_I_FRAMES, - BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3, - BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7, -}; -enum blackbird_vbi_mode_bits { - BLACKBIRD_VBI_BITS_SLICED, - BLACKBIRD_VBI_BITS_RAW, -}; -enum blackbird_vbi_insertion_bits { - BLACKBIRD_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, - BLACKBIRD_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, - BLACKBIRD_VBI_BITS_SEPARATE_STREAM = 0x2 << 1, - BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, - BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, -}; -enum blackbird_dma_unit { - BLACKBIRD_DMA_BYTES, - BLACKBIRD_DMA_FRAMES, -}; -enum blackbird_dma_transfer_status_bits { - BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01, - BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04, - BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10, -}; -enum blackbird_pause { - BLACKBIRD_PAUSE_ENCODING, - BLACKBIRD_RESUME_ENCODING, -}; -enum blackbird_copyright { - BLACKBIRD_COPYRIGHT_OFF, - BLACKBIRD_COPYRIGHT_ON, -}; -enum blackbird_notification_type { - BLACKBIRD_NOTIFICATION_REFRESH, -}; -enum blackbird_notification_status { - BLACKBIRD_NOTIFICATION_OFF, - BLACKBIRD_NOTIFICATION_ON, -}; -enum blackbird_notification_mailbox { - BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1, -}; -enum blackbird_field1_lines { - BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */ - BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */ - BLACKBIRD_FIELD1_MICRONAS = 0x0105, /* 261 */ -}; -enum blackbird_field2_lines { - BLACKBIRD_FIELD2_SAA7114 = 0x00EF, /* 239 */ - BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */ - BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */ -}; -enum blackbird_custom_data_type { - BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, - BLACKBIRD_CUSTOM_PRIVATE_PACKET, -}; -enum blackbird_mute { - BLACKBIRD_UNMUTE, - BLACKBIRD_MUTE, -}; -enum blackbird_mute_video_mask { - BLACKBIRD_MUTE_VIDEO_V_MASK = 0x0000FF00, - BLACKBIRD_MUTE_VIDEO_U_MASK = 0x00FF0000, - BLACKBIRD_MUTE_VIDEO_Y_MASK = 0xFF000000, -}; -enum blackbird_mute_video_shift { - BLACKBIRD_MUTE_VIDEO_V_SHIFT = 8, - BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16, - BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24, -}; - -/* Registers */ -#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/) -#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/) -#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/) -#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/) -#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/) -#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/) - -/* ------------------------------------------------------------------ */ - -static void host_setup(struct cx88_core *core) -{ - /* toggle reset of the host */ - cx_write(MO_GPHST_SOFT_RST, 1); - udelay(100); - cx_write(MO_GPHST_SOFT_RST, 0); - udelay(100); - - /* host port setup */ - cx_write(MO_GPHST_WSC, 0x44444444U); - cx_write(MO_GPHST_XFR, 0); - cx_write(MO_GPHST_WDTH, 15); - cx_write(MO_GPHST_HDSHK, 0); - cx_write(MO_GPHST_MUX16, 0x44448888U); - cx_write(MO_GPHST_MODE, 0); -} - -/* ------------------------------------------------------------------ */ - -#define P1_MDATA0 0x390000 -#define P1_MDATA1 0x390001 -#define P1_MDATA2 0x390002 -#define P1_MDATA3 0x390003 -#define P1_MADDR2 0x390004 -#define P1_MADDR1 0x390005 -#define P1_MADDR0 0x390006 -#define P1_RDATA0 0x390008 -#define P1_RDATA1 0x390009 -#define P1_RDATA2 0x39000A -#define P1_RDATA3 0x39000B -#define P1_RADDR0 0x39000C -#define P1_RADDR1 0x39000D -#define P1_RRDWR 0x39000E - -static int wait_ready_gpio0_bit1(struct cx88_core *core, u32 state) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(1); - u32 gpio0,need; - - need = state ? 2 : 0; - for (;;) { - gpio0 = cx_read(MO_GP0_IO) & 2; - if (need == gpio0) - return 0; - if (time_after(jiffies,timeout)) - return -1; - udelay(1); - } -} - -static int memory_write(struct cx88_core *core, u32 address, u32 value) -{ - /* Warning: address is dword address (4 bytes) */ - cx_writeb(P1_MDATA0, (unsigned int)value); - cx_writeb(P1_MDATA1, (unsigned int)(value >> 8)); - cx_writeb(P1_MDATA2, (unsigned int)(value >> 16)); - cx_writeb(P1_MDATA3, (unsigned int)(value >> 24)); - cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) | 0x40); - cx_writeb(P1_MADDR1, (unsigned int)(address >> 8)); - cx_writeb(P1_MADDR0, (unsigned int)address); - cx_read(P1_MDATA0); - cx_read(P1_MADDR0); - - return wait_ready_gpio0_bit1(core,1); -} - -static int memory_read(struct cx88_core *core, u32 address, u32 *value) -{ - int retval; - u32 val; - - /* Warning: address is dword address (4 bytes) */ - cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) & ~0xC0); - cx_writeb(P1_MADDR1, (unsigned int)(address >> 8)); - cx_writeb(P1_MADDR0, (unsigned int)address); - cx_read(P1_MADDR0); - - retval = wait_ready_gpio0_bit1(core,1); - - cx_writeb(P1_MDATA3, 0); - val = (unsigned char)cx_read(P1_MDATA3) << 24; - cx_writeb(P1_MDATA2, 0); - val |= (unsigned char)cx_read(P1_MDATA2) << 16; - cx_writeb(P1_MDATA1, 0); - val |= (unsigned char)cx_read(P1_MDATA1) << 8; - cx_writeb(P1_MDATA0, 0); - val |= (unsigned char)cx_read(P1_MDATA0); - - *value = val; - return retval; -} - -static int register_write(struct cx88_core *core, u32 address, u32 value) -{ - cx_writeb(P1_RDATA0, (unsigned int)value); - cx_writeb(P1_RDATA1, (unsigned int)(value >> 8)); - cx_writeb(P1_RDATA2, (unsigned int)(value >> 16)); - cx_writeb(P1_RDATA3, (unsigned int)(value >> 24)); - cx_writeb(P1_RADDR0, (unsigned int)address); - cx_writeb(P1_RADDR1, (unsigned int)(address >> 8)); - cx_writeb(P1_RRDWR, 1); - cx_read(P1_RDATA0); - cx_read(P1_RADDR0); - - return wait_ready_gpio0_bit1(core,1); -} - - -static int register_read(struct cx88_core *core, u32 address, u32 *value) -{ - int retval; - u32 val; - - cx_writeb(P1_RADDR0, (unsigned int)address); - cx_writeb(P1_RADDR1, (unsigned int)(address >> 8)); - cx_writeb(P1_RRDWR, 0); - cx_read(P1_RADDR0); - - retval = wait_ready_gpio0_bit1(core,1); - val = (unsigned char)cx_read(P1_RDATA0); - val |= (unsigned char)cx_read(P1_RDATA1) << 8; - val |= (unsigned char)cx_read(P1_RDATA2) << 16; - val |= (unsigned char)cx_read(P1_RDATA3) << 24; - - *value = val; - return retval; -} - -/* ------------------------------------------------------------------ */ - -static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) -{ - struct cx8802_dev *dev = priv; - unsigned long timeout; - u32 value, flag, retval; - int i; - - dprintk(1,"%s: 0x%X\n", __func__, command); - - /* this may not be 100% safe if we can't read any memory location - without side effects */ - memory_read(dev->core, dev->mailbox - 4, &value); - if (value != 0x12345678) { - dprintk(0, "Firmware and/or mailbox pointer not initialized or corrupted\n"); - return -1; - } - - memory_read(dev->core, dev->mailbox, &flag); - if (flag) { - dprintk(0, "ERROR: Mailbox appears to be in use (%x)\n", flag); - return -1; - } - - flag |= 1; /* tell 'em we're working on it */ - memory_write(dev->core, dev->mailbox, flag); - - /* write command + args + fill remaining with zeros */ - memory_write(dev->core, dev->mailbox + 1, command); /* command code */ - memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */ - for (i = 0; i < in; i++) { - memory_write(dev->core, dev->mailbox + 4 + i, data[i]); - dprintk(1, "API Input %d = %d\n", i, data[i]); - } - for (; i < CX2341X_MBOX_MAX_DATA; i++) - memory_write(dev->core, dev->mailbox + 4 + i, 0); - - flag |= 3; /* tell 'em we're done writing */ - memory_write(dev->core, dev->mailbox, flag); - - /* wait for firmware to handle the API command */ - timeout = jiffies + msecs_to_jiffies(10); - for (;;) { - memory_read(dev->core, dev->mailbox, &flag); - if (0 != (flag & 4)) - break; - if (time_after(jiffies,timeout)) { - dprintk(0, "ERROR: API Mailbox timeout\n"); - return -1; - } - udelay(10); - } - - /* read output values */ - for (i = 0; i < out; i++) { - memory_read(dev->core, dev->mailbox + 4 + i, data + i); - dprintk(1, "API Output %d = %d\n", i, data[i]); - } - - memory_read(dev->core, dev->mailbox + 2, &retval); - dprintk(1, "API result = %d\n",retval); - - flag = 0; - memory_write(dev->core, dev->mailbox, flag); - return retval; -} -/* ------------------------------------------------------------------ */ - -/* We don't need to call the API often, so using just one mailbox will probably suffice */ -static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command, - u32 inputcnt, u32 outputcnt, ...) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - va_list vargs; - int i, err; - - va_start(vargs, outputcnt); - - for (i = 0; i < inputcnt; i++) { - data[i] = va_arg(vargs, int); - } - err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data); - for (i = 0; i < outputcnt; i++) { - int *vptr = va_arg(vargs, int *); - *vptr = data[i]; - } - va_end(vargs); - return err; -} - -static int blackbird_find_mailbox(struct cx8802_dev *dev) -{ - u32 signature[4]={0x12345678, 0x34567812, 0x56781234, 0x78123456}; - int signaturecnt=0; - u32 value; - int i; - - for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) { - memory_read(dev->core, i, &value); - if (value == signature[signaturecnt]) - signaturecnt++; - else - signaturecnt = 0; - if (4 == signaturecnt) { - dprintk(1, "Mailbox signature found\n"); - return i+1; - } - } - dprintk(0, "Mailbox signature values not found!\n"); - return -1; -} - -static int blackbird_load_firmware(struct cx8802_dev *dev) -{ - static const unsigned char magic[8] = { - 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa - }; - const struct firmware *firmware; - int i, retval = 0; - u32 value = 0; - u32 checksum = 0; - u32 *dataptr; - - retval = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED); - retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); - retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640); - retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); - msleep(1); - retval |= register_write(dev->core, IVTV_REG_APU, 0); - - if (retval < 0) - dprintk(0, "Error with register_write\n"); - - retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME, - &dev->pci->dev); - - - if (retval != 0) { - dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n", - CX2341X_FIRM_ENC_FILENAME); - dprintk(0, "Please fix your hotplug setup, the board will " - "not work without firmware loaded!\n"); - return -1; - } - - if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) { - dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n", - firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE); - release_firmware(firmware); - return -1; - } - - if (0 != memcmp(firmware->data, magic, 8)) { - dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n"); - release_firmware(firmware); - return -1; - } - - /* transfer to the chip */ - dprintk(1,"Loading firmware ...\n"); - dataptr = (u32*)firmware->data; - for (i = 0; i < (firmware->size >> 2); i++) { - value = *dataptr; - checksum += ~value; - memory_write(dev->core, i, value); - dataptr++; - } - - /* read back to verify with the checksum */ - for (i--; i >= 0; i--) { - memory_read(dev->core, i, &value); - checksum -= ~value; - } - if (checksum) { - dprintk(0, "ERROR: Firmware load failed (checksum mismatch).\n"); - release_firmware(firmware); - return -1; - } - release_firmware(firmware); - dprintk(0, "Firmware upload successful.\n"); - - retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); - retval |= register_read(dev->core, IVTV_REG_SPU, &value); - retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE); - msleep(1); - - retval |= register_read(dev->core, IVTV_REG_VPU, &value); - retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8); - - if (retval < 0) - dprintk(0, "Error with register_write\n"); - return 0; -} - -/** - Settings used by the windows tv app for PVR2000: -================================================================================================================= -Profile | Codec | Resolution | CBR/VBR | Video Qlty | V. Bitrate | Frmrate | Audio Codec | A. Bitrate | A. Mode ------------------------------------------------------------------------------------------------------------------ -MPEG-1 | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 2000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -MPEG-2 | MPEG2 | 720x576PAL | VBR | 600 :Good | 4000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -VCD | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 1150 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -DVD | MPEG2 | 720x576PAL | VBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -================================================================================================================= -*DB: "DirectBurn" -*/ - -static void blackbird_codec_settings(struct cx8802_dev *dev) -{ - /* assign frame size */ - blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, - dev->height, dev->width); - - dev->params.width = dev->width; - dev->params.height = dev->height; - dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0; - - cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params); -} - -static int blackbird_initialize_codec(struct cx8802_dev *dev) -{ - struct cx88_core *core = dev->core; - int version; - int retval; - - dprintk(1,"Initialize codec\n"); - retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ - if (retval < 0) { - - dev->mpeg_active = 0; - - /* ping was not successful, reset and upload firmware */ - cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */ - cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */ - retval = blackbird_load_firmware(dev); - if (retval < 0) - return retval; - - retval = blackbird_find_mailbox(dev); - if (retval < 0) - return -1; - - dev->mailbox = retval; - - retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ - if (retval < 0) { - dprintk(0, "ERROR: Firmware ping failed!\n"); - return -1; - } - - retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version); - if (retval < 0) { - dprintk(0, "ERROR: Firmware get encoder version failed!\n"); - return -1; - } - dprintk(0, "Firmware version is 0x%08x\n", version); - } - - cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */ - cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */ - cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */ - cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */ - - blackbird_codec_settings(dev); - - blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, - BLACKBIRD_FIELD1_SAA7115, - BLACKBIRD_FIELD2_SAA7115 - ); - - blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, - BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - - return 0; -} - -static int blackbird_start_codec(struct file *file, void *priv) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx88_core *core = dev->core; - /* start capturing to the host interface */ - u32 reg; - - int i; - int lastchange = -1; - int lastval = 0; - - for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) { - reg = cx_read(AUD_STATUS); - - dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg); - if ((reg & 0x0F) != lastval) { - lastval = reg & 0x0F; - lastchange = i; - } - msleep(100); - } - - /* unmute audio source */ - cx_clear(AUD_VOL_CTL, (1 << 6)); - - blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0); - - /* initialize the video input */ - blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); - - /* start capturing to the host interface */ - blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_BITS_NONE - ); - - dev->mpeg_active = 1; - return 0; -} - -static int blackbird_stop_codec(struct cx8802_dev *dev) -{ - blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - BLACKBIRD_END_NOW, - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_BITS_NONE - ); - - dev->mpeg_active = 0; - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int bb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) -{ - struct cx8802_fh *fh = q->priv_data; - - fh->dev->ts_packet_size = 188 * 4; /* was: 512 */ - fh->dev->ts_packet_count = mpegbufs; /* was: 100 */ - - *size = fh->dev->ts_packet_size * fh->dev->ts_packet_count; - *count = fh->dev->ts_packet_count; - return 0; -} - -static int -bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx8802_fh *fh = q->priv_data; - return cx8802_buf_prepare(q, fh->dev, (struct cx88_buffer*)vb, field); -} - -static void -bb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct cx8802_fh *fh = q->priv_data; - cx8802_buf_queue(fh->dev, (struct cx88_buffer*)vb); -} - -static void -bb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - cx88_free_buffer(q, (struct cx88_buffer*)vb); -} - -static struct videobuf_queue_ops blackbird_qops = { - .buf_setup = bb_buf_setup, - .buf_prepare = bb_buf_prepare, - .buf_queue = bb_buf_queue, - .buf_release = bb_buf_release, -}; - -/* ------------------------------------------------------------------ */ - -static const u32 *ctrl_classes[] = { - cx88_user_ctrls, - cx2341x_mpeg_ctrls, - NULL -}; - -static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - - /* Standard V4L2 controls */ - if (cx8800_ctrl_query(dev->core, qctrl) == 0) - return 0; - - /* MPEG V4L2 controls */ - if (cx2341x_ctrl_query(&dev->params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; -} - -/* ------------------------------------------------------------------ */ -/* IOCTL Handlers */ - -static int vidioc_querymenu (struct file *file, void *priv, - struct v4l2_querymenu *qmenu) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - blackbird_queryctrl(dev, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(&dev->params, qmenu->id)); -} - -static int vidioc_querycap (struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx88_core *core = dev->core; - - strcpy(cap->driver, "cx88_blackbird"); - strlcpy(cap->card, core->board.name, sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - if (UNSET != core->board.tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index != 0) - return -EINVAL; - - strlcpy(f->description, "MPEG", sizeof(f->description)); - f->pixelformat = V4L2_PIX_FMT_MPEG; - return 0; -} - -static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx8802_fh *fh = priv; - struct cx8802_dev *dev = fh->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */ - f->fmt.pix.colorspace = 0; - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - f->fmt.pix.field = fh->mpegq.field; - dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", - dev->width, dev->height, fh->mpegq.field ); - return 0; -} - -static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx8802_fh *fh = priv; - struct cx8802_dev *dev = fh->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; - f->fmt.pix.colorspace = 0; - dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", - dev->width, dev->height, fh->mpegq.field ); - return 0; -} - -static int vidioc_s_fmt_vid_cap (struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx8802_fh *fh = priv; - struct cx8802_dev *dev = fh->dev; - struct cx88_core *core = dev->core; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; - f->fmt.pix.colorspace = 0; - dev->width = f->fmt.pix.width; - dev->height = f->fmt.pix.height; - fh->mpegq.field = f->fmt.pix.field; - cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); - blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, - f->fmt.pix.height, f->fmt.pix.width); - dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", - f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field ); - return 0; -} - -static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) -{ - struct cx8802_fh *fh = priv; - return (videobuf_reqbufs(&fh->mpegq, p)); -} - -static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx8802_fh *fh = priv; - return (videobuf_querybuf(&fh->mpegq, p)); -} - -static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx8802_fh *fh = priv; - return (videobuf_qbuf(&fh->mpegq, p)); -} - -static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx8802_fh *fh = priv; - return (videobuf_dqbuf(&fh->mpegq, p, - file->f_flags & O_NONBLOCK)); -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx8802_fh *fh = priv; - return videobuf_streamon(&fh->mpegq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx8802_fh *fh = priv; - return videobuf_streamoff(&fh->mpegq); -} - -static int vidioc_g_ext_ctrls (struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS); -} - -static int vidioc_s_ext_ctrls (struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - if (dev->mpeg_active) - blackbird_stop_codec(dev); - - p = dev->params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); - if (!err) { - err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); - dev->params = p; - } - return err; -} - -static int vidioc_try_ext_ctrls (struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - p = dev->params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - - return err; -} - -static int vidioc_s_frequency (struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx8802_fh *fh = priv; - struct cx8802_dev *dev = fh->dev; - struct cx88_core *core = dev->core; - - if (dev->mpeg_active) - blackbird_stop_codec(dev); - - cx88_set_freq (core,f); - blackbird_initialize_codec(dev); - cx88_set_scale(dev->core, dev->width, dev->height, - fh->mpegq.field); - return 0; -} - -static int vidioc_log_status (struct file *file, void *priv) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx88_core *core = dev->core; - char name[32 + 2]; - - snprintf(name, sizeof(name), "%s/2", core->name); - printk("%s/2: ============ START LOG STATUS ============\n", - core->name); - call_all(core, core, log_status); - cx2341x_log_status(&dev->params, name); - printk("%s/2: ============= END LOG STATUS =============\n", - core->name); - return 0; -} - -static int vidioc_queryctrl (struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - - if (blackbird_queryctrl(dev, qctrl) == 0) - return 0; - - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx8800_ctrl_query(dev->core, qctrl); -} - -static int vidioc_enum_input (struct file *file, void *priv, - struct v4l2_input *i) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - return cx88_enum_input (core,i); -} - -static int vidioc_g_ctrl (struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - return - cx88_get_control(core,ctl); -} - -static int vidioc_s_ctrl (struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - return - cx88_set_control(core,ctl); -} - -static int vidioc_g_frequency (struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx8802_fh *fh = priv; - struct cx88_core *core = fh->dev->core; - - if (unlikely(UNSET == core->board.tuner_type)) - return -EINVAL; - - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = core->freq; - call_all(core, tuner, g_frequency, f); - - return 0; -} - -static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - - *i = core->input; - return 0; -} - -static int vidioc_s_input (struct file *file, void *priv, unsigned int i) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - - if (i >= 4) - return -EINVAL; - - mutex_lock(&core->lock); - cx88_newstation(core); - cx88_video_mux(core,i); - mutex_unlock(&core->lock); - return 0; -} - -static int vidioc_g_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - u32 reg; - - if (unlikely(UNSET == core->board.tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - - cx88_get_stereo(core ,t); - reg = cx_read(MO_DEVICE_STATUS); - t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; - return 0; -} - -static int vidioc_s_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - - if (UNSET == core->board.tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - cx88_set_stereo(core, t->audmode, 1); - return 0; -} - -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - - mutex_lock(&core->lock); - cx88_set_tvnorm(core,*id); - mutex_unlock(&core->lock); - return 0; -} - -/* FIXME: cx88_ioctl_hook not implemented */ - -static int mpeg_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct cx8802_dev *dev = video_drvdata(file); - struct cx8802_fh *fh; - struct cx8802_driver *drv = NULL; - int err; - - dprintk( 1, "%s\n", __func__); - - mutex_lock(&dev->core->lock); - - /* Make sure we can acquire the hardware */ - drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); - if (drv) { - err = drv->request_acquire(drv); - if(err != 0) { - dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err); - mutex_unlock(&dev->core->lock); - return err; - } - } - - if (!atomic_read(&dev->core->mpeg_users) && blackbird_initialize_codec(dev) < 0) { - if (drv) - drv->request_release(drv); - mutex_unlock(&dev->core->lock); - return -EINVAL; - } - dprintk(1, "open dev=%s\n", video_device_node_name(vdev)); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) { - if (drv) - drv->request_release(drv); - mutex_unlock(&dev->core->lock); - return -ENOMEM; - } - file->private_data = fh; - fh->dev = dev; - - videobuf_queue_sg_init(&fh->mpegq, &blackbird_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx88_buffer), - fh, NULL); - - /* FIXME: locking against other video device */ - cx88_set_scale(dev->core, dev->width, dev->height, - fh->mpegq.field); - - atomic_inc(&dev->core->mpeg_users); - mutex_unlock(&dev->core->lock); - return 0; -} - -static int mpeg_release(struct file *file) -{ - struct cx8802_fh *fh = file->private_data; - struct cx8802_dev *dev = fh->dev; - struct cx8802_driver *drv = NULL; - - if (dev->mpeg_active && atomic_read(&dev->core->mpeg_users) == 1) - blackbird_stop_codec(dev); - - cx8802_cancel_buffers(fh->dev); - /* stop mpeg capture */ - videobuf_stop(&fh->mpegq); - - videobuf_mmap_free(&fh->mpegq); - - mutex_lock(&dev->core->lock); - file->private_data = NULL; - kfree(fh); - mutex_unlock(&dev->core->lock); - - /* Make sure we release the hardware */ - drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); - if (drv) - drv->request_release(drv); - - atomic_dec(&dev->core->mpeg_users); - - return 0; -} - -static ssize_t -mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct cx8802_fh *fh = file->private_data; - struct cx8802_dev *dev = fh->dev; - - if (!dev->mpeg_active) - blackbird_start_codec(file, fh); - - return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static unsigned int -mpeg_poll(struct file *file, struct poll_table_struct *wait) -{ - struct cx8802_fh *fh = file->private_data; - struct cx8802_dev *dev = fh->dev; - - if (!dev->mpeg_active) - blackbird_start_codec(file, fh); - - return videobuf_poll_stream(file, &fh->mpegq, wait); -} - -static int -mpeg_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct cx8802_fh *fh = file->private_data; - - return videobuf_mmap_mapper(&fh->mpegq, vma); -} - -static const struct v4l2_file_operations mpeg_fops = -{ - .owner = THIS_MODULE, - .open = mpeg_open, - .release = mpeg_release, - .read = mpeg_read, - .poll = mpeg_poll, - .mmap = mpeg_mmap, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { - .vidioc_querymenu = vidioc_querymenu, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_s_std = vidioc_s_std, -}; - -static struct video_device cx8802_mpeg_template = { - .name = "cx8802", - .fops = &mpeg_fops, - .ioctl_ops = &mpeg_ioctl_ops, - .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; - -/* ------------------------------------------------------------------ */ - -/* The CX8802 MPEG API will call this when we can use the hardware */ -static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv) -{ - struct cx88_core *core = drv->core; - int err = 0; - - switch (core->boardnr) { - case CX88_BOARD_HAUPPAUGE_HVR1300: - /* By default, core setup will leave the cx22702 out of reset, on the bus. - * We left the hardware on power up with the cx22702 active. - * We're being given access to re-arrange the GPIOs. - * Take the bus off the cx22702 and put the cx23416 on it. - */ - /* Toggle reset on cx22702 leaving i2c active */ - cx_set(MO_GP0_IO, 0x00000080); - udelay(1000); - cx_clear(MO_GP0_IO, 0x00000080); - udelay(50); - cx_set(MO_GP0_IO, 0x00000080); - udelay(1000); - /* tri-state the cx22702 pins */ - cx_set(MO_GP0_IO, 0x00000004); - udelay(1000); - break; - default: - err = -ENODEV; - } - return err; -} - -/* The CX8802 MPEG API will call this when we need to release the hardware */ -static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) -{ - struct cx88_core *core = drv->core; - int err = 0; - - switch (core->boardnr) { - case CX88_BOARD_HAUPPAUGE_HVR1300: - /* Exit leaving the cx23416 on the bus */ - break; - default: - err = -ENODEV; - } - return err; -} - -static void blackbird_unregister_video(struct cx8802_dev *dev) -{ - if (dev->mpeg_dev) { - if (video_is_registered(dev->mpeg_dev)) - video_unregister_device(dev->mpeg_dev); - else - video_device_release(dev->mpeg_dev); - dev->mpeg_dev = NULL; - } -} - -static int blackbird_register_video(struct cx8802_dev *dev) -{ - int err; - - dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci, - &cx8802_mpeg_template,"mpeg"); - video_set_drvdata(dev->mpeg_dev, dev); - err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1); - if (err < 0) { - printk(KERN_INFO "%s/2: can't register mpeg device\n", - dev->core->name); - return err; - } - printk(KERN_INFO "%s/2: registered device %s [mpeg]\n", - dev->core->name, video_device_node_name(dev->mpeg_dev)); - return 0; -} - -/* ----------------------------------------------------------- */ - -static int cx8802_blackbird_probe(struct cx8802_driver *drv) -{ - struct cx88_core *core = drv->core; - struct cx8802_dev *dev = core->dvbdev; - int err; - - dprintk( 1, "%s\n", __func__); - dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", - core->boardnr, - core->name, - core->pci_bus, - core->pci_slot); - - err = -ENODEV; - if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD)) - goto fail_core; - - dev->width = 720; - dev->height = 576; - cx2341x_fill_defaults(&dev->params); - dev->params.port = CX2341X_PORT_STREAMING; - - cx8802_mpeg_template.current_norm = core->tvnorm; - - if (core->tvnorm & V4L2_STD_525_60) { - dev->height = 480; - } else { - dev->height = 576; - } - - /* blackbird stuff */ - printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n", - core->name); - host_setup(dev->core); - - blackbird_initialize_codec(dev); - blackbird_register_video(dev); - - /* initial device configuration: needed ? */ - mutex_lock(&dev->core->lock); -// init_controls(core); - cx88_set_tvnorm(core,core->tvnorm); - cx88_video_mux(core,0); - mutex_unlock(&dev->core->lock); - - return 0; - - fail_core: - return err; -} - -static int cx8802_blackbird_remove(struct cx8802_driver *drv) -{ - /* blackbird */ - blackbird_unregister_video(drv->core->dvbdev); - - return 0; -} - -static struct cx8802_driver cx8802_blackbird_driver = { - .type_id = CX88_MPEG_BLACKBIRD, - .hw_access = CX8802_DRVCTL_SHARED, - .probe = cx8802_blackbird_probe, - .remove = cx8802_blackbird_remove, - .advise_acquire = cx8802_blackbird_advise_acquire, - .advise_release = cx8802_blackbird_advise_release, -}; - -static int __init blackbird_init(void) -{ - printk(KERN_INFO "cx2388x blackbird driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return cx8802_register_driver(&cx8802_blackbird_driver); -} - -static void __exit blackbird_fini(void) -{ - cx8802_unregister_driver(&cx8802_blackbird_driver); -} - -module_init(blackbird_init); -module_exit(blackbird_fini); - -module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [video]"); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-cards.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3563 +0,0 @@ -/* - * - * device driver for Conexant 2388x based TV cards - * card-specific stuff. - * - * (c) 2003 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "cx88.h" -#include "tea5767.h" - -static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; - -module_param_array(tuner, int, NULL, 0444); -module_param_array(radio, int, NULL, 0444); -module_param_array(card, int, NULL, 0444); - -MODULE_PARM_DESC(tuner,"tuner type"); -MODULE_PARM_DESC(radio,"radio tuner type"); -MODULE_PARM_DESC(card,"card type"); - -static unsigned int latency = UNSET; -module_param(latency,int,0444); -MODULE_PARM_DESC(latency,"pci latency timer"); - -static int disable_ir; -module_param(disable_ir, int, 0444); -MODULE_PARM_DESC(disable_ir, "Disable IR support"); - -#define info_printk(core, fmt, arg...) \ - printk(KERN_INFO "%s: " fmt, core->name , ## arg) - -#define warn_printk(core, fmt, arg...) \ - printk(KERN_WARNING "%s: " fmt, core->name , ## arg) - -#define err_printk(core, fmt, arg...) \ - printk(KERN_ERR "%s: " fmt, core->name , ## arg) - - -/* ------------------------------------------------------------------ */ -/* board config info */ - -/* If radio_type !=UNSET, radio_addr should be specified - */ - -static const struct cx88_board cx88_boards[] = { - [CX88_BOARD_UNKNOWN] = { - .name = "UNKNOWN/GENERIC", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 0, - },{ - .type = CX88_VMUX_COMPOSITE2, - .vmux = 1, - },{ - .type = CX88_VMUX_COMPOSITE3, - .vmux = 2, - },{ - .type = CX88_VMUX_COMPOSITE4, - .vmux = 3, - }}, - }, - [CX88_BOARD_HAUPPAUGE] = { - .name = "Hauppauge WinTV 34xxx models", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xff00, // internal decoder - },{ - .type = CX88_VMUX_DEBUG, - .vmux = 0, - .gpio0 = 0xff01, // mono from tuner chip - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xff02, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xff02, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0xff01, - }, - }, - [CX88_BOARD_GDI] = { - .name = "GDI Black Gold", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - }}, - }, - [CX88_BOARD_PIXELVIEW] = { - .name = "PixelView", - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xff00, // internal decoder - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0xff10, - }, - }, - [CX88_BOARD_ATI_WONDER_PRO] = { - .name = "ATI TV Wonder Pro", - .tuner_type = TUNER_PHILIPS_4IN1, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x03ff, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x03fe, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x03fe, - }}, - }, - [CX88_BOARD_WINFAST2000XP_EXPERT] = { - .name = "Leadtek Winfast 2000XP Expert", - .tuner_type = TUNER_PHILIPS_4IN1, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00F5e700, - .gpio1 = 0x00003004, - .gpio2 = 0x00F5e700, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00F5c700, - .gpio1 = 0x00003004, - .gpio2 = 0x00F5c700, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x00F5c700, - .gpio1 = 0x00003004, - .gpio2 = 0x00F5c700, - .gpio3 = 0x02000000, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x00F5d700, - .gpio1 = 0x00003004, - .gpio2 = 0x00F5d700, - .gpio3 = 0x02000000, - }, - }, - [CX88_BOARD_AVERTV_STUDIO_303] = { - .name = "AverTV Studio 303 (M126)", - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio1 = 0xe09f, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio1 = 0xe05f, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio1 = 0xe05f, - }}, - .radio = { - .gpio1 = 0xe0df, - .type = CX88_RADIO, - }, - }, - [CX88_BOARD_MSI_TVANYWHERE_MASTER] = { - // added gpio values thanks to Michal - // values for PAL from DScaler - .name = "MSI TV-@nywhere Master", - .tuner_type = TUNER_MT2032, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x000040bf, - .gpio1 = 0x000080c0, - .gpio2 = 0x0000ff40, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x000040bf, - .gpio1 = 0x000080c0, - .gpio2 = 0x0000ff40, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x000040bf, - .gpio1 = 0x000080c0, - .gpio2 = 0x0000ff40, - }}, - .radio = { - .type = CX88_RADIO, - .vmux = 3, - .gpio0 = 0x000040bf, - .gpio1 = 0x000080c0, - .gpio2 = 0x0000ff20, - }, - }, - [CX88_BOARD_WINFAST_DV2000] = { - .name = "Leadtek Winfast DV2000", - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0035e700, - .gpio1 = 0x00003004, - .gpio2 = 0x0035e700, - .gpio3 = 0x02000000, - },{ - - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0035c700, - .gpio1 = 0x00003004, - .gpio2 = 0x0035c700, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0035c700, - .gpio1 = 0x0035c700, - .gpio2 = 0x02000000, - .gpio3 = 0x02000000, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x0035d700, - .gpio1 = 0x00007004, - .gpio2 = 0x0035d700, - .gpio3 = 0x02000000, - }, - }, - [CX88_BOARD_LEADTEK_PVR2000] = { - // gpio values for PAL version from regspy by DScaler - .name = "Leadtek PVR 2000", - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0000bde2, - .audioroute = 1, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0000bde6, - .audioroute = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0000bde6, - .audioroute = 1, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x0000bd62, - .audioroute = 1, - }, - .mpeg = CX88_MPEG_BLACKBIRD, - }, - [CX88_BOARD_IODATA_GVVCP3PCI] = { - .name = "IODATA GV-VCP3/PCI", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 0, - },{ - .type = CX88_VMUX_COMPOSITE2, - .vmux = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - }}, - }, - [CX88_BOARD_PROLINK_PLAYTVPVR] = { - .name = "Prolink PlayTV PVR", - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xbff0, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xbff3, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xbff3, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0xbff0, - }, - }, - [CX88_BOARD_ASUS_PVR_416] = { - .name = "ASUS PVR-416", - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0000fde6, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? - .audioroute = 1, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x0000fde2, - }, - .mpeg = CX88_MPEG_BLACKBIRD, - }, - [CX88_BOARD_MSI_TVANYWHERE] = { - .name = "MSI TV-@nywhere", - .tuner_type = TUNER_MT2032, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00000fbf, - .gpio2 = 0x0000fc08, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00000fbf, - .gpio2 = 0x0000fc68, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x00000fbf, - .gpio2 = 0x0000fc68, - }}, - }, - [CX88_BOARD_KWORLD_DVB_T] = { - .name = "KWorld/VStream XPert DVB-T", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0700, - .gpio2 = 0x0101, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0700, - .gpio2 = 0x0101, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = { - .name = "DViCO FusionHDTV DVB-T1", - .tuner_type = TUNER_ABSENT, /* No analog tuner */ - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x000027df, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x000027df, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_KWORLD_LTV883] = { - .name = "KWorld LTV883RF", - .tuner_type = TUNER_TNF_8831BGFF, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x07f8, - },{ - .type = CX88_VMUX_DEBUG, - .vmux = 0, - .gpio0 = 0x07f9, // mono from tuner chip - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x000007fa, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x000007fa, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x000007f8, - }, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = { - .name = "DViCO FusionHDTV 3 Gold-Q", - .tuner_type = TUNER_MICROTUNE_4042FI5, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - /* - GPIO[0] resets DT3302 DTV receiver - 0 - reset asserted - 1 - normal operation - GPIO[1] mutes analog audio output connector - 0 - enable selected source - 1 - mute - GPIO[2] selects source for analog audio output connector - 0 - analog audio input connector on tab - 1 - analog DAC output from CX23881 chip - GPIO[3] selects RF input connector on tuner module - 0 - RF connector labeled CABLE - 1 - RF connector labeled ANT - GPIO[4] selects high RF for QAM256 mode - 0 - normal RF - 1 - high RF - */ - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0f0d, - },{ - .type = CX88_VMUX_CABLE, - .vmux = 0, - .gpio0 = 0x0f05, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0f00, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0f00, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_HAUPPAUGE_DVB_T1] = { - .name = "Hauppauge Nova-T DVB-T", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_CONEXANT_DVB_T1] = { - .name = "Conexant DVB-T reference design", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_PROVIDEO_PV259] = { - .name = "Provideo PV259", - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .audioroute = 1, - }}, - .mpeg = CX88_MPEG_BLACKBIRD, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = { - .name = "DViCO FusionHDTV DVB-T Plus", - .tuner_type = TUNER_ABSENT, /* No analog tuner */ - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x000027df, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x000027df, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_DNTV_LIVE_DVB_T] = { - .name = "digitalnow DNTV Live! DVB-T", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00000700, - .gpio2 = 0x00000101, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x00000700, - .gpio2 = 0x00000101, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_PCHDTV_HD3000] = { - .name = "pcHDTV HD3000 HDTV", - .tuner_type = TUNER_THOMSON_DTT761X, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - /* GPIO[2] = audio source for analog audio out connector - * 0 = analog audio input connector - * 1 = CX88 audio DACs - * - * GPIO[7] = input to CX88's audio/chroma ADC - * 0 = FM 10.7 MHz IF - * 1 = Sound 4.5 MHz IF - * - * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively - * - * GPIO[16] = Remote control input - */ - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00008484, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00008400, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x00008400, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x00008404, - }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_HAUPPAUGE_ROSLYN] = { - // entry added by Kaustubh D. Bhalerao - // GPIO values obtained from regspy, courtesy Sean Covel - .name = "Hauppauge WinTV 28xxx (Roslyn) models", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xed1a, - .gpio2 = 0x00ff, - },{ - .type = CX88_VMUX_DEBUG, - .vmux = 0, - .gpio0 = 0xff01, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xff02, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xed92, - .gpio2 = 0x00ff, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0xed96, - .gpio2 = 0x00ff, - }, - .mpeg = CX88_MPEG_BLACKBIRD, - }, - [CX88_BOARD_DIGITALLOGIC_MEC] = { - .name = "Digital-Logic MICROSPACE Entertainment Center (MEC)", - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00009d80, - .audioroute = 1, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00009d76, - .audioroute = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x00009d76, - .audioroute = 1, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x00009d00, - .audioroute = 1, - }, - .mpeg = CX88_MPEG_BLACKBIRD, - }, - [CX88_BOARD_IODATA_GVBCTV7E] = { - .name = "IODATA GV/BCTV7E", - .tuner_type = TUNER_PHILIPS_FQ1286, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 1, - .gpio1 = 0x0000e03f, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 2, - .gpio1 = 0x0000e07f, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 3, - .gpio1 = 0x0000e07f, - }} - }, - [CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = { - .name = "PixelView PlayTV Ultra Pro (Stereo)", - /* May be also TUNER_YMEC_TVF_5533MF for NTSC/M or PAL/M */ - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - /* Some variants use a tda9874 and so need the tvaudio module. */ - .audio_chip = V4L2_IDENT_TVAUDIO, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xbf61, /* internal decoder */ - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xbf63, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xbf63, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0xbf60, - }, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = { - .name = "DViCO FusionHDTV 3 Gold-T", - .tuner_type = TUNER_THOMSON_DTT761X, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x97ed, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x97e9, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x97e9, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_ADSTECH_DVB_T_PCI] = { - .name = "ADS Tech Instant TV DVB-T PCI", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0700, - .gpio2 = 0x0101, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0700, - .gpio2 = 0x0101, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = { - .name = "TerraTec Cinergy 1400 DVB-T", - .tuner_type = TUNER_ABSENT, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 2, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = { - .name = "DViCO FusionHDTV 5 Gold", - .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H062F */ - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x87fd, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x87f9, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x87f9, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = { - .name = "AverMedia UltraTV Media Center PCI 550", - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 0, - .gpio0 = 0x0000cd73, - .audioroute = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 1, - .gpio0 = 0x0000cd73, - .audioroute = 1, - },{ - .type = CX88_VMUX_TELEVISION, - .vmux = 3, - .gpio0 = 0x0000cdb3, - .audioroute = 1, - }}, - .radio = { - .type = CX88_RADIO, - .vmux = 2, - .gpio0 = 0x0000cdf3, - .audioroute = 1, - }, - .mpeg = CX88_MPEG_BLACKBIRD, - }, - [CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = { - /* Alexander Wold */ - .name = "Kworld V-Stream Xpert DVD", - .tuner_type = UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x03000000, - .gpio1 = 0x01000000, - .gpio2 = 0x02000000, - .gpio3 = 0x00100000, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x03000000, - .gpio1 = 0x01000000, - .gpio2 = 0x02000000, - .gpio3 = 0x00100000, - }}, - }, - [CX88_BOARD_ATI_HDTVWONDER] = { - .name = "ATI HDTV Wonder", - .tuner_type = TUNER_PHILIPS_TUV1236D, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00000ff7, - .gpio1 = 0x000000ff, - .gpio2 = 0x00000001, - .gpio3 = 0x00000000, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00000ffe, - .gpio1 = 0x000000ff, - .gpio2 = 0x00000001, - .gpio3 = 0x00000000, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x00000ffe, - .gpio1 = 0x000000ff, - .gpio2 = 0x00000001, - .gpio3 = 0x00000000, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_WINFAST_DTV1000] = { - .name = "WinFast DTV1000-T", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_AVERTV_303] = { - .name = "AVerTV 303 (M126)", - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00ff, - .gpio1 = 0xe09f, - .gpio2 = 0x0010, - .gpio3 = 0x0000, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00ff, - .gpio1 = 0xe05f, - .gpio2 = 0x0010, - .gpio3 = 0x0000, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x00ff, - .gpio1 = 0xe05f, - .gpio2 = 0x0010, - .gpio3 = 0x0000, - }}, - }, - [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = { - .name = "Hauppauge Nova-S-Plus DVB-S", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .audio_chip = V4L2_IDENT_WM8775, - .i2sinputcntl = 2, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - /* 2: Line-In */ - .audioroute = 2, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - /* 2: Line-In */ - .audioroute = 2, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - /* 2: Line-In */ - .audioroute = 2, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = { - .name = "Hauppauge Nova-SE2 DVB-S", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_KWORLD_DVBS_100] = { - .name = "KWorld DVB-S 100", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .audio_chip = V4L2_IDENT_WM8775, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - /* 2: Line-In */ - .audioroute = 2, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - /* 2: Line-In */ - .audioroute = 2, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - /* 2: Line-In */ - .audioroute = 2, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_HAUPPAUGE_HVR1100] = { - .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - }}, - /* fixme: Add radio support */ - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_HAUPPAUGE_HVR1100LP] = { - .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - }}, - /* fixme: Add radio support */ - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_DNTV_LIVE_DVB_T_PRO] = { - .name = "digitalnow DNTV Live! DVB-T Pro", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xf80808, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xf80808, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xf80808, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0xf80808, - }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_KWORLD_DVB_T_CX22702] = { - /* Kworld V-stream Xpert DVB-T with Thomson tuner */ - /* DTT 7579 Conexant CX22702-19 Conexant CX2388x */ - /* Manenti Marco */ - .name = "KWorld/VStream XPert DVB-T with cx22702", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0700, - .gpio2 = 0x0101, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0700, - .gpio2 = 0x0101, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = { - .name = "DViCO FusionHDTV DVB-T Dual Digital", - .tuner_type = TUNER_ABSENT, /* No analog tuner */ - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x000067df, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x000067df, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = { - .name = "KWorld HardwareMpegTV XPert", - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x3de2, - .gpio2 = 0x00ff, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x3de6, - .audioroute = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x3de6, - .audioroute = 1, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x3de6, - .gpio2 = 0x00ff, - }, - .mpeg = CX88_MPEG_BLACKBIRD, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = { - .name = "DViCO FusionHDTV DVB-T Hybrid", - .tuner_type = TUNER_THOMSON_FE6600, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0000a75f, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0000a75b, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0000a75b, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_PCHDTV_HD5500] = { - .name = "pcHDTV HD5500 HDTV", - .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */ - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x87fd, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x87f9, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x87f9, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_KWORLD_MCE200_DELUXE] = { - /* FIXME: tested TV input only, disabled composite, - svideo and radio until they can be tested also. */ - .name = "Kworld MCE 200 Deluxe", - .tuner_type = TUNER_TENA_9533_DI, - .radio_type = UNSET, - .tda9887_conf = TDA9887_PRESENT, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0000BDE6 - }}, - .mpeg = CX88_MPEG_BLACKBIRD, - }, - [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = { - /* FIXME: SVideo, Composite and FM inputs are untested */ - .name = "PixelView PlayTV P7000", - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x5da6, - }}, - .mpeg = CX88_MPEG_BLACKBIRD, - }, - [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = { - .name = "NPG Tech Real TV FM Top 10", - .tuner_type = TUNER_TNF_5335MF, /* Actually a TNF9535 */ - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0788, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x078b, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x078b, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x074a, - }, - }, - [CX88_BOARD_WINFAST_DTV2000H] = { - .name = "WinFast DTV2000 H", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00017304, - .gpio1 = 0x00008203, - .gpio2 = 0x00017304, - .gpio3 = 0x02000000, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0001d701, - .gpio1 = 0x0000b207, - .gpio2 = 0x0001d701, - .gpio3 = 0x02000000, - }, { - .type = CX88_VMUX_COMPOSITE2, - .vmux = 2, - .gpio0 = 0x0001d503, - .gpio1 = 0x0000b207, - .gpio2 = 0x0001d503, - .gpio3 = 0x02000000, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 3, - .gpio0 = 0x0001d701, - .gpio1 = 0x0000b207, - .gpio2 = 0x0001d701, - .gpio3 = 0x02000000, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x00015702, - .gpio1 = 0x0000f207, - .gpio2 = 0x00015702, - .gpio3 = 0x02000000, - }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_WINFAST_DTV2000H_J] = { - .name = "WinFast DTV2000 H rev. J", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00017300, - .gpio1 = 0x00008207, - .gpio2 = 0x00000000, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00018300, - .gpio1 = 0x0000f207, - .gpio2 = 0x00017304, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00018301, - .gpio1 = 0x0000f207, - .gpio2 = 0x00017304, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x00018301, - .gpio1 = 0x0000f207, - .gpio2 = 0x00017304, - .gpio3 = 0x02000000, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x00015702, - .gpio1 = 0x0000f207, - .gpio2 = 0x00015702, - .gpio3 = 0x02000000, - }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_GENIATECH_DVBS] = { - .name = "Geniatech DVB-S", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_HAUPPAUGE_HVR3000] = { - .name = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .audio_chip = V4L2_IDENT_WM8775, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x84bf, - /* 1: TV Audio / FM Mono */ - .audioroute = 1, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x84bf, - /* 2: Line-In */ - .audioroute = 2, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x84bf, - /* 2: Line-In */ - .audioroute = 2, - }}, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x84bf, - /* 4: FM Stereo (untested) */ - .audioroute = 8, - }, - .mpeg = CX88_MPEG_DVB, - .num_frontends = 2, - }, - [CX88_BOARD_NORWOOD_MICRO] = { - .name = "Norwood Micro TV Tuner", - .tuner_type = TUNER_TNF_5335MF, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0709, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x070b, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x070b, - }}, - }, - [CX88_BOARD_TE_DTV_250_OEM_SWANN] = { - .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x003fffff, - .gpio1 = 0x00e00000, - .gpio2 = 0x003fffff, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x003fffff, - .gpio1 = 0x00e00000, - .gpio2 = 0x003fffff, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x003fffff, - .gpio1 = 0x00e00000, - .gpio2 = 0x003fffff, - .gpio3 = 0x02000000, - }}, - }, - [CX88_BOARD_HAUPPAUGE_HVR1300] = { - .name = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .audio_chip = V4L2_IDENT_WM8775, - /* - * gpio0 as reported by Mike Crash - */ - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xef88, - /* 1: TV Audio / FM Mono */ - .audioroute = 1, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xef88, - /* 2: Line-In */ - .audioroute = 2, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xef88, - /* 2: Line-In */ - .audioroute = 2, - }}, - .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0xef88, - /* 4: FM Stereo (untested) */ - .audioroute = 8, - }, - }, - [CX88_BOARD_SAMSUNG_SMT_7020] = { - .name = "Samsung SMT 7020 DVB-S", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = { { - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_ADSTECH_PTV_390] = { - .name = "ADS Tech Instant Video PCI", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DEBUG, - .vmux = 3, - .gpio0 = 0x04ff, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x07fa, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x07fa, - }}, - }, - [CX88_BOARD_PINNACLE_PCTV_HD_800i] = { - .name = "Pinnacle PCTV HD 800i", - .tuner_type = TUNER_XC5000, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x04fb, - .gpio1 = 0x10ff, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x04fb, - .gpio1 = 0x10ef, - .audioroute = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x04fb, - .gpio1 = 0x10ef, - .audioroute = 1, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = { - .name = "DViCO FusionHDTV 5 PCI nano", - /* xc3008 tuner, digital only for now */ - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x000027df, /* Unconfirmed */ - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x000027df, /* Unconfirmed */ - .audioroute = 1, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x000027df, /* Unconfirmed */ - .audioroute = 1, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_PINNACLE_HYBRID_PCTV] = { - .name = "Pinnacle Hybrid PCTV", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .radio_type = TUNER_XC2028, - .radio_addr = 0x61, - .input = { { - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x004ff, - .gpio1 = 0x010ff, - .gpio2 = 0x00001, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x004fb, - .gpio1 = 0x010ef, - .audioroute = 1, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x004fb, - .gpio1 = 0x010ef, - .audioroute = 1, - } }, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x004ff, - .gpio1 = 0x010ff, - .gpio2 = 0x0ff, - }, - .mpeg = CX88_MPEG_DVB, - }, - /* Terry Wu */ - /* TV Audio : set GPIO 2, 18, 19 value to 0, 1, 0 */ - /* FM Audio : set GPIO 2, 18, 19 value to 0, 0, 0 */ - /* Line-in Audio : set GPIO 2, 18, 19 value to 0, 1, 1 */ - /* Mute Audio : set GPIO 2 value to 1 */ - [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = { - .name = "Leadtek TV2000 XP Global", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .radio_type = TUNER_XC2028, - .radio_addr = 0x61, - .input = { { - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0400, /* pin 2 = 0 */ - .gpio1 = 0x0000, - .gpio2 = 0x0C04, /* pin 18 = 1, pin 19 = 0 */ - .gpio3 = 0x0000, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0400, /* pin 2 = 0 */ - .gpio1 = 0x0000, - .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ - .gpio3 = 0x0000, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0400, /* pin 2 = 0 */ - .gpio1 = 0x0000, - .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ - .gpio3 = 0x0000, - } }, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x0400, /* pin 2 = 0 */ - .gpio1 = 0x0000, - .gpio2 = 0x0C00, /* pin 18 = 0, pin 19 = 0 */ - .gpio3 = 0x0000, - }, - }, - [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = { - .name = "PowerColor RA330", /* Long names may confuse LIRC. */ - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .input = { { - .type = CX88_VMUX_DEBUG, - .vmux = 3, /* Due to the way the cx88 driver is written, */ - .gpio0 = 0x00ff, /* there is no way to deactivate audio pass- */ - .gpio1 = 0xf39d, /* through without this entry. Furthermore, if */ - .gpio3 = 0x0000, /* the TV mux entry is first, you get audio */ - }, { /* from the tuner on boot for a little while. */ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00ff, - .gpio1 = 0xf35d, - .gpio3 = 0x0000, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00ff, - .gpio1 = 0xf37d, - .gpio3 = 0x0000, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x000ff, - .gpio1 = 0x0f37d, - .gpio3 = 0x00000, - } }, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x000ff, - .gpio1 = 0x0f35d, - .gpio3 = 0x00000, - }, - }, - [CX88_BOARD_GENIATECH_X8000_MT] = { - /* Also PowerColor Real Angel 330 and Geniatech X800 OEM */ - .name = "Geniatech X8000-MT DVBT", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .input = { { - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x00000000, - .gpio1 = 0x00e3e341, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x00000000, - .gpio1 = 0x00e3e361, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x00000000, - .gpio1 = 0x00e3e361, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, - } }, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x00000000, - .gpio1 = 0x00e3e341, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, - }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO] = { - .name = "DViCO FusionHDTV DVB-T PRO", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .radio_type = UNSET, - .radio_addr = ADDR_UNSET, - .input = { { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x000067df, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x000067df, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD] = { - .name = "DViCO FusionHDTV 7 Gold", - .tuner_type = TUNER_XC5000, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x10df, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x16d9, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x16d9, - }}, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_PROLINK_PV_8000GT] = { - .name = "Prolink Pixelview MPEG 8000GT", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .input = { { - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0ff, - .gpio2 = 0x0cfb, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio2 = 0x0cfb, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio2 = 0x0cfb, - } }, - .radio = { - .type = CX88_RADIO, - .gpio2 = 0x0cfb, - }, - }, - [CX88_BOARD_PROLINK_PV_GLOBAL_XTREME] = { - .name = "Prolink Pixelview Global Extreme", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .input = { { - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x04fb, - .gpio1 = 0x04080, - .gpio2 = 0x0cf7, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x04fb, - .gpio1 = 0x04080, - .gpio2 = 0x0cfb, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x04fb, - .gpio1 = 0x04080, - .gpio2 = 0x0cfb, - } }, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x04ff, - .gpio1 = 0x04080, - .gpio2 = 0x0cf7, - }, - }, - /* Both radio, analog and ATSC work with this board. - However, for analog to work, s5h1409 gate should be open, - otherwise, tuner-xc3028 won't be detected. - A proper fix require using the newer i2c methods to add - tuner-xc3028 without doing an i2c probe. - */ - [CX88_BOARD_KWORLD_ATSC_120] = { - .name = "Kworld PlusTV HD PCI 120 (ATSC 120)", - .tuner_type = TUNER_XC2028, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = { { - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x000000ff, - .gpio1 = 0x0000f35d, - .gpio2 = 0x00000000, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x000000ff, - .gpio1 = 0x0000f37e, - .gpio2 = 0x00000000, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x000000ff, - .gpio1 = 0x0000f37e, - .gpio2 = 0x00000000, - } }, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x000000ff, - .gpio1 = 0x0000f35d, - .gpio2 = 0x00000000, - }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_HAUPPAUGE_HVR4000] = { - .name = "Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .audio_chip = V4L2_IDENT_WM8775, - /* - * GPIO0 (WINTV2000) - * - * Analogue SAT DVB-T - * Antenna 0xc4bf 0xc4bb - * Composite 0xc4bf 0xc4bb - * S-Video 0xc4bf 0xc4bb - * Composite1 0xc4ff 0xc4fb - * S-Video1 0xc4ff 0xc4fb - * - * BIT VALUE FUNCTION GP{x}_IO - * 0 1 I:? - * 1 1 I:? - * 2 1 O:MPEG PORT 0=DVB-T 1=DVB-S - * 3 1 I:? - * 4 1 I:? - * 5 1 I:? - * 6 0 O:INPUT SELECTOR 0=INTERNAL 1=EXPANSION - * 7 1 O:DVB-T DEMOD RESET LOW - * - * BIT VALUE FUNCTION GP{x}_OE - * 8 0 I - * 9 0 I - * a 1 O - * b 0 I - * c 0 I - * d 0 I - * e 1 O - * f 1 O - * - * WM8775 ADC - * - * 1: TV Audio / FM Mono - * 2: Line-In - * 3: Line-In Expansion - * 4: FM Stereo - */ - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xc4bf, - /* 1: TV Audio / FM Mono */ - .audioroute = 1, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xc4bf, - /* 2: Line-In */ - .audioroute = 2, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xc4bf, - /* 2: Line-In */ - .audioroute = 2, - } }, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0xc4bf, - /* 4: FM Stereo */ - .audioroute = 8, - }, - .mpeg = CX88_MPEG_DVB, - .num_frontends = 2, - }, - [CX88_BOARD_HAUPPAUGE_HVR4000LITE] = { - .name = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_TEVII_S420] = { - .name = "TeVii S420 DVB-S", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_TEVII_S460] = { - .name = "TeVii S460 DVB-S/S2", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_TEVII_S464] = { - .name = "TeVii S464 DVB-S/S2", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_OMICOM_SS4_PCI] = { - .name = "Omicom SS4 DVB-S/S2 PCI", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_TBS_8910] = { - .name = "TBS 8910 DVB-S", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_TBS_8920] = { - .name = "TBS 8920 DVB-S/S2", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - .gpio0 = 0x8080, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_PROF_6200] = { - .name = "Prof 6200 DVB-S", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_PROF_7300] = { - .name = "PROF 7300 DVB-S/S2", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_SATTRADE_ST4200] = { - .name = "SATTRADE ST4200 DVB-S/S2", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII] = { - .name = "Terratec Cinergy HT PCI MKII", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .radio_type = TUNER_XC2028, - .radio_addr = 0x61, - .input = { { - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x004ff, - .gpio1 = 0x010ff, - .gpio2 = 0x00001, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x004fb, - .gpio1 = 0x010ef, - .audioroute = 1, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x004fb, - .gpio1 = 0x010ef, - .audioroute = 1, - } }, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x004ff, - .gpio1 = 0x010ff, - .gpio2 = 0x0ff, - }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_HAUPPAUGE_IRONLY] = { - .name = "Hauppauge WinTV-IR Only", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - }, - [CX88_BOARD_WINFAST_DTV1800H] = { - .name = "Leadtek WinFast DTV1800 Hybrid", - .tuner_type = TUNER_XC2028, - .radio_type = TUNER_XC2028, - .tuner_addr = 0x61, - .radio_addr = 0x61, - /* - * GPIO setting - * - * 2: mute (0=off,1=on) - * 12: tuner reset pin - * 13: audio source (0=tuner audio,1=line in) - * 14: FM (0=on,1=off ???) - */ - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x0400, /* pin 2 = 0 */ - .gpio1 = 0x6040, /* pin 13 = 0, pin 14 = 1 */ - .gpio2 = 0x0000, - }, { - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x0400, /* pin 2 = 0 */ - .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ - .gpio2 = 0x0000, - }, { - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x0400, /* pin 2 = 0 */ - .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ - .gpio2 = 0x0000, - } }, - .radio = { - .type = CX88_RADIO, - .gpio0 = 0x0400, /* pin 2 = 0 */ - .gpio1 = 0x6000, /* pin 13 = 0, pin 14 = 0 */ - .gpio2 = 0x0000, - }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_PROF_7301] = { - .name = "Prof 7301 DVB-S/S2", - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = { { - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, - [CX88_BOARD_TWINHAN_VP1027_DVBS] = { - .name = "Twinhan VP-1027 DVB-S", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_DVB, - .vmux = 0, - } }, - .mpeg = CX88_MPEG_DVB, - }, -}; - -/* ------------------------------------------------------------------ */ -/* PCI subsystem IDs */ - -static const struct cx88_subid cx88_subids[] = { - { - .subvendor = 0x0070, - .subdevice = 0x3400, - .card = CX88_BOARD_HAUPPAUGE, - },{ - .subvendor = 0x0070, - .subdevice = 0x3401, - .card = CX88_BOARD_HAUPPAUGE, - },{ - .subvendor = 0x14c7, - .subdevice = 0x0106, - .card = CX88_BOARD_GDI, - },{ - .subvendor = 0x14c7, - .subdevice = 0x0107, /* with mpeg encoder */ - .card = CX88_BOARD_GDI, - },{ - .subvendor = PCI_VENDOR_ID_ATI, - .subdevice = 0x00f8, - .card = CX88_BOARD_ATI_WONDER_PRO, - }, { - .subvendor = PCI_VENDOR_ID_ATI, - .subdevice = 0x00f9, - .card = CX88_BOARD_ATI_WONDER_PRO, - }, { - .subvendor = 0x107d, - .subdevice = 0x6611, - .card = CX88_BOARD_WINFAST2000XP_EXPERT, - },{ - .subvendor = 0x107d, - .subdevice = 0x6613, /* NTSC */ - .card = CX88_BOARD_WINFAST2000XP_EXPERT, - },{ - .subvendor = 0x107d, - .subdevice = 0x6620, - .card = CX88_BOARD_WINFAST_DV2000, - },{ - .subvendor = 0x107d, - .subdevice = 0x663b, - .card = CX88_BOARD_LEADTEK_PVR2000, - },{ - .subvendor = 0x107d, - .subdevice = 0x663c, - .card = CX88_BOARD_LEADTEK_PVR2000, - },{ - .subvendor = 0x1461, - .subdevice = 0x000b, - .card = CX88_BOARD_AVERTV_STUDIO_303, - },{ - .subvendor = 0x1462, - .subdevice = 0x8606, - .card = CX88_BOARD_MSI_TVANYWHERE_MASTER, - },{ - .subvendor = 0x10fc, - .subdevice = 0xd003, - .card = CX88_BOARD_IODATA_GVVCP3PCI, - },{ - .subvendor = 0x1043, - .subdevice = 0x4823, /* with mpeg encoder */ - .card = CX88_BOARD_ASUS_PVR_416, - },{ - .subvendor = 0x17de, - .subdevice = 0x08a6, - .card = CX88_BOARD_KWORLD_DVB_T, - },{ - .subvendor = 0x18ac, - .subdevice = 0xd810, - .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, - },{ - .subvendor = 0x18ac, - .subdevice = 0xd820, - .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T, - },{ - .subvendor = 0x18ac, - .subdevice = 0xdb00, - .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1, - },{ - .subvendor = 0x0070, - .subdevice = 0x9002, - .card = CX88_BOARD_HAUPPAUGE_DVB_T1, - },{ - .subvendor = 0x14f1, - .subdevice = 0x0187, - .card = CX88_BOARD_CONEXANT_DVB_T1, - },{ - .subvendor = 0x1540, - .subdevice = 0x2580, - .card = CX88_BOARD_PROVIDEO_PV259, - },{ - .subvendor = 0x18ac, - .subdevice = 0xdb10, - .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, - },{ - .subvendor = 0x1554, - .subdevice = 0x4811, - .card = CX88_BOARD_PIXELVIEW, - },{ - .subvendor = 0x7063, - .subdevice = 0x3000, /* HD-3000 card */ - .card = CX88_BOARD_PCHDTV_HD3000, - },{ - .subvendor = 0x17de, - .subdevice = 0xa8a6, - .card = CX88_BOARD_DNTV_LIVE_DVB_T, - },{ - .subvendor = 0x0070, - .subdevice = 0x2801, - .card = CX88_BOARD_HAUPPAUGE_ROSLYN, - },{ - .subvendor = 0x14f1, - .subdevice = 0x0342, - .card = CX88_BOARD_DIGITALLOGIC_MEC, - },{ - .subvendor = 0x10fc, - .subdevice = 0xd035, - .card = CX88_BOARD_IODATA_GVBCTV7E, - },{ - .subvendor = 0x1421, - .subdevice = 0x0334, - .card = CX88_BOARD_ADSTECH_DVB_T_PCI, - },{ - .subvendor = 0x153b, - .subdevice = 0x1166, - .card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1, - },{ - .subvendor = 0x18ac, - .subdevice = 0xd500, - .card = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD, - },{ - .subvendor = 0x1461, - .subdevice = 0x8011, - .card = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550, - },{ - .subvendor = PCI_VENDOR_ID_ATI, - .subdevice = 0xa101, - .card = CX88_BOARD_ATI_HDTVWONDER, - },{ - .subvendor = 0x107d, - .subdevice = 0x665f, - .card = CX88_BOARD_WINFAST_DTV1000, - },{ - .subvendor = 0x1461, - .subdevice = 0x000a, - .card = CX88_BOARD_AVERTV_303, - },{ - .subvendor = 0x0070, - .subdevice = 0x9200, - .card = CX88_BOARD_HAUPPAUGE_NOVASE2_S1, - },{ - .subvendor = 0x0070, - .subdevice = 0x9201, - .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, - },{ - .subvendor = 0x0070, - .subdevice = 0x9202, - .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, - },{ - .subvendor = 0x17de, - .subdevice = 0x08b2, - .card = CX88_BOARD_KWORLD_DVBS_100, - },{ - .subvendor = 0x0070, - .subdevice = 0x9400, - .card = CX88_BOARD_HAUPPAUGE_HVR1100, - },{ - .subvendor = 0x0070, - .subdevice = 0x9402, - .card = CX88_BOARD_HAUPPAUGE_HVR1100, - },{ - .subvendor = 0x0070, - .subdevice = 0x9800, - .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, - },{ - .subvendor = 0x0070, - .subdevice = 0x9802, - .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, - },{ - .subvendor = 0x0070, - .subdevice = 0x9001, - .card = CX88_BOARD_HAUPPAUGE_DVB_T1, - },{ - .subvendor = 0x1822, - .subdevice = 0x0025, - .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, - },{ - .subvendor = 0x17de, - .subdevice = 0x08a1, - .card = CX88_BOARD_KWORLD_DVB_T_CX22702, - },{ - .subvendor = 0x18ac, - .subdevice = 0xdb50, - .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL, - },{ - .subvendor = 0x18ac, - .subdevice = 0xdb54, - .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL, - /* Re-branded DViCO: DigitalNow DVB-T Dual */ - },{ - .subvendor = 0x18ac, - .subdevice = 0xdb11, - .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, - /* Re-branded DViCO: UltraView DVB-T Plus */ - }, { - .subvendor = 0x18ac, - .subdevice = 0xdb30, - .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO, - }, { - .subvendor = 0x17de, - .subdevice = 0x0840, - .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, - },{ - .subvendor = 0x1421, - .subdevice = 0x0305, - .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, - },{ - .subvendor = 0x18ac, - .subdevice = 0xdb40, - .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, - },{ - .subvendor = 0x18ac, - .subdevice = 0xdb44, - .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, - },{ - .subvendor = 0x7063, - .subdevice = 0x5500, - .card = CX88_BOARD_PCHDTV_HD5500, - },{ - .subvendor = 0x17de, - .subdevice = 0x0841, - .card = CX88_BOARD_KWORLD_MCE200_DELUXE, - },{ - .subvendor = 0x1822, - .subdevice = 0x0019, - .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, - },{ - .subvendor = 0x1554, - .subdevice = 0x4813, - .card = CX88_BOARD_PIXELVIEW_PLAYTV_P7000, - },{ - .subvendor = 0x14f1, - .subdevice = 0x0842, - .card = CX88_BOARD_NPGTECH_REALTV_TOP10FM, - },{ - .subvendor = 0x107d, - .subdevice = 0x665e, - .card = CX88_BOARD_WINFAST_DTV2000H, - },{ - .subvendor = 0x107d, - .subdevice = 0x6f2b, - .card = CX88_BOARD_WINFAST_DTV2000H_J, - },{ - .subvendor = 0x18ac, - .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */ - .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, - },{ - .subvendor = 0x14f1, - .subdevice = 0x0084, - .card = CX88_BOARD_GENIATECH_DVBS, - },{ - .subvendor = 0x0070, - .subdevice = 0x1404, - .card = CX88_BOARD_HAUPPAUGE_HVR3000, - }, { - .subvendor = 0x18ac, - .subdevice = 0xdc00, - .card = CX88_BOARD_SAMSUNG_SMT_7020, - }, { - .subvendor = 0x18ac, - .subdevice = 0xdccd, - .card = CX88_BOARD_SAMSUNG_SMT_7020, - },{ - .subvendor = 0x1461, - .subdevice = 0xc111, /* AverMedia M150-D */ - /* This board is known to work with the ASUS PVR416 config */ - .card = CX88_BOARD_ASUS_PVR_416, - },{ - .subvendor = 0xc180, - .subdevice = 0xc980, - .card = CX88_BOARD_TE_DTV_250_OEM_SWANN, - },{ - .subvendor = 0x0070, - .subdevice = 0x9600, - .card = CX88_BOARD_HAUPPAUGE_HVR1300, - },{ - .subvendor = 0x0070, - .subdevice = 0x9601, - .card = CX88_BOARD_HAUPPAUGE_HVR1300, - },{ - .subvendor = 0x0070, - .subdevice = 0x9602, - .card = CX88_BOARD_HAUPPAUGE_HVR1300, - },{ - .subvendor = 0x107d, - .subdevice = 0x6632, - .card = CX88_BOARD_LEADTEK_PVR2000, - },{ - .subvendor = 0x12ab, - .subdevice = 0x2300, /* Club3D Zap TV2100 */ - .card = CX88_BOARD_KWORLD_DVB_T_CX22702, - },{ - .subvendor = 0x0070, - .subdevice = 0x9000, - .card = CX88_BOARD_HAUPPAUGE_DVB_T1, - },{ - .subvendor = 0x0070, - .subdevice = 0x1400, - .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ - .subvendor = 0x0070, - .subdevice = 0x1401, - .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ - .subvendor = 0x0070, - .subdevice = 0x1402, - .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ - .subvendor = 0x1421, - .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */ - .card = CX88_BOARD_KWORLD_DVBS_100, - },{ - .subvendor = 0x1421, - .subdevice = 0x0390, - .card = CX88_BOARD_ADSTECH_PTV_390, - },{ - .subvendor = 0x11bd, - .subdevice = 0x0051, - .card = CX88_BOARD_PINNACLE_PCTV_HD_800i, - }, { - .subvendor = 0x18ac, - .subdevice = 0xd530, - .card = CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO, - }, { - .subvendor = 0x12ab, - .subdevice = 0x1788, - .card = CX88_BOARD_PINNACLE_HYBRID_PCTV, - }, { - .subvendor = 0x14f1, - .subdevice = 0xea3d, - .card = CX88_BOARD_POWERCOLOR_REAL_ANGEL, - }, { - .subvendor = 0x107d, - .subdevice = 0x6f18, - .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, - }, { - .subvendor = 0x14f1, - .subdevice = 0x8852, - .card = CX88_BOARD_GENIATECH_X8000_MT, - }, { - .subvendor = 0x18ac, - .subdevice = 0xd610, - .card = CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD, - }, { - .subvendor = 0x1554, - .subdevice = 0x4935, - .card = CX88_BOARD_PROLINK_PV_8000GT, - }, { - .subvendor = 0x1554, - .subdevice = 0x4976, - .card = CX88_BOARD_PROLINK_PV_GLOBAL_XTREME, - }, { - .subvendor = 0x17de, - .subdevice = 0x08c1, - .card = CX88_BOARD_KWORLD_ATSC_120, - }, { - .subvendor = 0x0070, - .subdevice = 0x6900, - .card = CX88_BOARD_HAUPPAUGE_HVR4000, - }, { - .subvendor = 0x0070, - .subdevice = 0x6904, - .card = CX88_BOARD_HAUPPAUGE_HVR4000, - }, { - .subvendor = 0x0070, - .subdevice = 0x6902, - .card = CX88_BOARD_HAUPPAUGE_HVR4000, - }, { - .subvendor = 0x0070, - .subdevice = 0x6905, - .card = CX88_BOARD_HAUPPAUGE_HVR4000LITE, - }, { - .subvendor = 0x0070, - .subdevice = 0x6906, - .card = CX88_BOARD_HAUPPAUGE_HVR4000LITE, - }, { - .subvendor = 0xd420, - .subdevice = 0x9022, - .card = CX88_BOARD_TEVII_S420, - }, { - .subvendor = 0xd460, - .subdevice = 0x9022, - .card = CX88_BOARD_TEVII_S460, - }, { - .subvendor = 0xd464, - .subdevice = 0x9022, - .card = CX88_BOARD_TEVII_S464, - }, { - .subvendor = 0xA044, - .subdevice = 0x2011, - .card = CX88_BOARD_OMICOM_SS4_PCI, - }, { - .subvendor = 0x8910, - .subdevice = 0x8888, - .card = CX88_BOARD_TBS_8910, - }, { - .subvendor = 0x8920, - .subdevice = 0x8888, - .card = CX88_BOARD_TBS_8920, - }, { - .subvendor = 0xb022, - .subdevice = 0x3022, - .card = CX88_BOARD_PROF_6200, - }, { - .subvendor = 0xB033, - .subdevice = 0x3033, - .card = CX88_BOARD_PROF_7300, - }, { - .subvendor = 0xb200, - .subdevice = 0x4200, - .card = CX88_BOARD_SATTRADE_ST4200, - }, { - .subvendor = 0x153b, - .subdevice = 0x1177, - .card = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII, - }, { - .subvendor = 0x0070, - .subdevice = 0x9290, - .card = CX88_BOARD_HAUPPAUGE_IRONLY, - }, { - .subvendor = 0x107d, - .subdevice = 0x6654, - .card = CX88_BOARD_WINFAST_DTV1800H, - }, { - /* PVR2000 PAL Model [107d:6630] */ - .subvendor = 0x107d, - .subdevice = 0x6630, - .card = CX88_BOARD_LEADTEK_PVR2000, - }, { - /* PVR2000 PAL Model [107d:6638] */ - .subvendor = 0x107d, - .subdevice = 0x6638, - .card = CX88_BOARD_LEADTEK_PVR2000, - }, { - /* PVR2000 NTSC Model [107d:6631] */ - .subvendor = 0x107d, - .subdevice = 0x6631, - .card = CX88_BOARD_LEADTEK_PVR2000, - }, { - /* PVR2000 NTSC Model [107d:6637] */ - .subvendor = 0x107d, - .subdevice = 0x6637, - .card = CX88_BOARD_LEADTEK_PVR2000, - }, { - /* PVR2000 NTSC Model [107d:663d] */ - .subvendor = 0x107d, - .subdevice = 0x663d, - .card = CX88_BOARD_LEADTEK_PVR2000, - }, { - /* DV2000 NTSC Model [107d:6621] */ - .subvendor = 0x107d, - .subdevice = 0x6621, - .card = CX88_BOARD_WINFAST_DV2000, - }, { - /* TV2000 XP Global [107d:6618] */ - .subvendor = 0x107d, - .subdevice = 0x6618, - .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, - }, { - .subvendor = 0xb034, - .subdevice = 0x3034, - .card = CX88_BOARD_PROF_7301, - }, { - .subvendor = 0x1822, - .subdevice = 0x0023, - .card = CX88_BOARD_TWINHAN_VP1027_DVBS, - }, -}; - -/* ----------------------------------------------------------------------- */ -/* some leadtek specific stuff */ - -static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) -{ - if (eeprom_data[4] != 0x7d || - eeprom_data[5] != 0x10 || - eeprom_data[7] != 0x66) { - warn_printk(core, "Leadtek eeprom invalid.\n"); - return; - } - - /* Terry Wu */ - switch (eeprom_data[6]) { - case 0x13: /* SSID 6613 for TV2000 XP Expert NTSC Model */ - case 0x21: /* SSID 6621 for DV2000 NTSC Model */ - case 0x31: /* SSID 6631 for PVR2000 NTSC Model */ - case 0x37: /* SSID 6637 for PVR2000 NTSC Model */ - case 0x3d: /* SSID 6637 for PVR2000 NTSC Model */ - core->board.tuner_type = TUNER_PHILIPS_FM1236_MK3; - break; - default: - core->board.tuner_type = TUNER_PHILIPS_FM1216ME_MK3; - break; - } - - info_printk(core, "Leadtek Winfast 2000XP Expert config: " - "tuner=%d, eeprom[0]=0x%02x\n", - core->board.tuner_type, eeprom_data[0]); -} - -static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) -{ - struct tveeprom tv; - - tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); - core->board.tuner_type = tv.tuner_type; - core->tuner_formats = tv.tuner_formats; - core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; - - /* Make sure we support the board model */ - switch (tv.model) - { - case 14009: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */ - case 14019: /* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */ - case 14029: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */ - case 14109: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - low profile) */ - case 14129: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge - LP) */ - case 14559: /* WinTV-HVR3000 (OEM, no IR, b/panel video, 3.5mm audio in) */ - case 14569: /* WinTV-HVR3000 (OEM, no IR, no back panel video) */ - case 14659: /* WinTV-HVR3000 (OEM, no IR, b/panel video, RCA audio in - Low profile) */ - case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */ - case 28552: /* WinTV-PVR 'Roslyn' (No IR) */ - case 34519: /* WinTV-PCI-FM */ - case 69009: - /* WinTV-HVR4000 (DVBS/S2/T, Video and IR, back panel inputs) */ - case 69100: /* WinTV-HVR4000LITE (DVBS/S2, IR) */ - case 69500: /* WinTV-HVR4000LITE (DVBS/S2, No IR) */ - case 69559: - /* WinTV-HVR4000 (DVBS/S2/T, Video no IR, back panel inputs) */ - case 69569: /* WinTV-HVR4000 (DVBS/S2/T, Video no IR) */ - case 90002: /* Nova-T-PCI (9002) */ - case 92001: /* Nova-S-Plus (Video and IR) */ - case 92002: /* Nova-S-Plus (Video and IR) */ - case 90003: /* Nova-T-PCI (9002 No RF out) */ - case 90500: /* Nova-T-PCI (oem) */ - case 90501: /* Nova-T-PCI (oem/IR) */ - case 92000: /* Nova-SE2 (OEM, No Video or IR) */ - case 92900: /* WinTV-IROnly (No analog or digital Video inputs) */ - case 94009: /* WinTV-HVR1100 (Video and IR Retail) */ - case 94501: /* WinTV-HVR1100 (Video and IR OEM) */ - case 96009: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX) */ - case 96019: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX/TX) */ - case 96559: /* WinTV-HVR1300 (PAL Video, MPEG Video no IR) */ - case 96569: /* WinTV-HVR1300 () */ - case 96659: /* WinTV-HVR1300 () */ - case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */ - /* known */ - break; - case CX88_BOARD_SAMSUNG_SMT_7020: - cx_set(MO_GP0_IO, 0x008989FF); - break; - default: - warn_printk(core, "warning: unknown hauppauge model #%d\n", - tv.model); - break; - } - - info_printk(core, "hauppauge eeprom: model=%d\n", tv.model); -} - -/* ----------------------------------------------------------------------- */ -/* some GDI (was: Modular Technology) specific stuff */ - -static const struct { - int id; - int fm; - const char *name; -} gdi_tuner[] = { - [ 0x01 ] = { .id = TUNER_ABSENT, - .name = "NTSC_M" }, - [ 0x02 ] = { .id = TUNER_ABSENT, - .name = "PAL_B" }, - [ 0x03 ] = { .id = TUNER_ABSENT, - .name = "PAL_I" }, - [ 0x04 ] = { .id = TUNER_ABSENT, - .name = "PAL_D" }, - [ 0x05 ] = { .id = TUNER_ABSENT, - .name = "SECAM" }, - - [ 0x10 ] = { .id = TUNER_ABSENT, - .fm = 1, - .name = "TEMIC_4049" }, - [ 0x11 ] = { .id = TUNER_TEMIC_4136FY5, - .name = "TEMIC_4136" }, - [ 0x12 ] = { .id = TUNER_ABSENT, - .name = "TEMIC_4146" }, - - [ 0x20 ] = { .id = TUNER_PHILIPS_FQ1216ME, - .fm = 1, - .name = "PHILIPS_FQ1216_MK3" }, - [ 0x21 ] = { .id = TUNER_ABSENT, .fm = 1, - .name = "PHILIPS_FQ1236_MK3" }, - [ 0x22 ] = { .id = TUNER_ABSENT, - .name = "PHILIPS_FI1236_MK3" }, - [ 0x23 ] = { .id = TUNER_ABSENT, - .name = "PHILIPS_FI1216_MK3" }, -}; - -static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) -{ - const char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner)) - ? gdi_tuner[eeprom_data[0x0d]].name : NULL; - - info_printk(core, "GDI: tuner=%s\n", name ? name : "unknown"); - if (NULL == name) - return; - core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id; - core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ? - CX88_RADIO : 0; -} - -/* ------------------------------------------------------------------- */ -/* some Divco specific stuff */ -static int cx88_dvico_xc2028_callback(struct cx88_core *core, - int command, int arg) -{ - switch (command) { - case XC2028_TUNER_RESET: - switch (core->boardnr) { - case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: - /* GPIO-4 xc3028 tuner */ - - cx_set(MO_GP0_IO, 0x00001000); - cx_clear(MO_GP0_IO, 0x00000010); - msleep(100); - cx_set(MO_GP0_IO, 0x00000010); - msleep(100); - break; - default: - cx_write(MO_GP0_IO, 0x101000); - mdelay(5); - cx_set(MO_GP0_IO, 0x101010); - } - break; - default: - return -EINVAL; - } - - return 0; -} - - -/* ----------------------------------------------------------------------- */ -/* some Geniatech specific stuff */ - -static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core, - int command, int mode) -{ - switch (command) { - case XC2028_TUNER_RESET: - switch (INPUT(core->input).type) { - case CX88_RADIO: - break; - case CX88_VMUX_DVB: - cx_write(MO_GP1_IO, 0x030302); - mdelay(50); - break; - default: - cx_write(MO_GP1_IO, 0x030301); - mdelay(50); - } - cx_write(MO_GP1_IO, 0x101010); - mdelay(50); - cx_write(MO_GP1_IO, 0x101000); - mdelay(50); - cx_write(MO_GP1_IO, 0x101010); - mdelay(50); - return 0; - } - return -EINVAL; -} - -static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core, - int command, int arg) -{ - switch (command) { - case XC2028_TUNER_RESET: - /* GPIO 12 (xc3028 tuner reset) */ - cx_set(MO_GP1_IO, 0x1010); - mdelay(50); - cx_clear(MO_GP1_IO, 0x10); - mdelay(50); - cx_set(MO_GP1_IO, 0x10); - mdelay(50); - return 0; - } - return -EINVAL; -} - -/* ------------------------------------------------------------------- */ -/* some Divco specific stuff */ -static int cx88_pv_8000gt_callback(struct cx88_core *core, - int command, int arg) -{ - switch (command) { - case XC2028_TUNER_RESET: - cx_write(MO_GP2_IO, 0xcf7); - mdelay(50); - cx_write(MO_GP2_IO, 0xef5); - mdelay(50); - cx_write(MO_GP2_IO, 0xcf7); - break; - default: - return -EINVAL; - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ -/* some DViCO specific stuff */ - -static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) -{ - struct i2c_msg msg = { .addr = 0x45, .flags = 0 }; - int i, err; - static u8 init_bufs[13][5] = { - { 0x10, 0x00, 0x20, 0x01, 0x03 }, - { 0x10, 0x10, 0x01, 0x00, 0x21 }, - { 0x10, 0x10, 0x10, 0x00, 0xCA }, - { 0x10, 0x10, 0x12, 0x00, 0x08 }, - { 0x10, 0x10, 0x13, 0x00, 0x0A }, - { 0x10, 0x10, 0x16, 0x01, 0xC0 }, - { 0x10, 0x10, 0x22, 0x01, 0x3D }, - { 0x10, 0x10, 0x73, 0x01, 0x2E }, - { 0x10, 0x10, 0x72, 0x00, 0xC5 }, - { 0x10, 0x10, 0x71, 0x01, 0x97 }, - { 0x10, 0x10, 0x70, 0x00, 0x0F }, - { 0x10, 0x10, 0xB0, 0x00, 0x01 }, - { 0x03, 0x0C }, - }; - - for (i = 0; i < ARRAY_SIZE(init_bufs); i++) { - msg.buf = init_bufs[i]; - msg.len = (i != 12 ? 5 : 2); - err = i2c_transfer(&core->i2c_adap, &msg, 1); - if (err != 1) { - warn_printk(core, "dvico_fusionhdtv_hybrid_init buf %d " - "failed (err = %d)!\n", i, err); - return; - } - } -} - -static int cx88_xc2028_tuner_callback(struct cx88_core *core, - int command, int arg) -{ - /* Board-specific callbacks */ - switch (core->boardnr) { - case CX88_BOARD_POWERCOLOR_REAL_ANGEL: - case CX88_BOARD_GENIATECH_X8000_MT: - case CX88_BOARD_KWORLD_ATSC_120: - return cx88_xc3028_geniatech_tuner_callback(core, - command, arg); - case CX88_BOARD_PROLINK_PV_8000GT: - case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: - return cx88_pv_8000gt_callback(core, command, arg); - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: - case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: - return cx88_dvico_xc2028_callback(core, command, arg); - case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: - case CX88_BOARD_WINFAST_DTV1800H: - return cx88_xc3028_winfast1800h_callback(core, command, arg); - } - - switch (command) { - case XC2028_TUNER_RESET: - switch (INPUT(core->input).type) { - case CX88_RADIO: - info_printk(core, "setting GPIO to radio!\n"); - cx_write(MO_GP0_IO, 0x4ff); - mdelay(250); - cx_write(MO_GP2_IO, 0xff); - mdelay(250); - break; - case CX88_VMUX_DVB: /* Digital TV*/ - default: /* Analog TV */ - info_printk(core, "setting GPIO to TV!\n"); - break; - } - cx_write(MO_GP1_IO, 0x101010); - mdelay(250); - cx_write(MO_GP1_IO, 0x101000); - mdelay(250); - cx_write(MO_GP1_IO, 0x101010); - mdelay(250); - return 0; - } - return -EINVAL; -} - -/* ----------------------------------------------------------------------- */ -/* Tuner callback function. Currently only needed for the Pinnacle * - * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * - * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ - -static int cx88_xc5000_tuner_callback(struct cx88_core *core, - int command, int arg) -{ - switch (core->boardnr) { - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - if (command == 0) { /* This is the reset command from xc5000 */ - - /* djh - According to the engineer at PCTV Systems, - the xc5000 reset pin is supposed to be on GPIO12. - However, despite three nights of effort, pulling - that GPIO low didn't reset the xc5000. While - pulling MO_SRST_IO low does reset the xc5000, this - also resets in the s5h1409 being reset as well. - This causes tuning to always fail since the internal - state of the s5h1409 does not match the driver's - state. Given that the only two conditions in which - the driver performs a reset is during firmware load - and powering down the chip, I am taking out the - reset. We know that the chip is being reset - when the cx88 comes online, and not being able to - do power management for this board is worse than - not having any tuning at all. */ - return 0; - } else { - err_printk(core, "xc5000: unknown tuner " - "callback command.\n"); - return -EINVAL; - } - break; - case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: - if (command == 0) { /* This is the reset command from xc5000 */ - cx_clear(MO_GP0_IO, 0x00000010); - msleep(10); - cx_set(MO_GP0_IO, 0x00000010); - return 0; - } else { - printk(KERN_ERR - "xc5000: unknown tuner callback command.\n"); - return -EINVAL; - } - break; - } - return 0; /* Should never be here */ -} - -int cx88_tuner_callback(void *priv, int component, int command, int arg) -{ - struct i2c_algo_bit_data *i2c_algo = priv; - struct cx88_core *core; - - if (!i2c_algo) { - printk(KERN_ERR "cx88: Error - i2c private data undefined.\n"); - return -EINVAL; - } - - core = i2c_algo->data; - - if (!core) { - printk(KERN_ERR "cx88: Error - device struct undefined.\n"); - return -EINVAL; - } - - if (component != DVB_FRONTEND_COMPONENT_TUNER) - return -EINVAL; - - switch (core->board.tuner_type) { - case TUNER_XC2028: - info_printk(core, "Calling XC2028/3028 callback\n"); - return cx88_xc2028_tuner_callback(core, command, arg); - case TUNER_XC5000: - info_printk(core, "Calling XC5000 callback\n"); - return cx88_xc5000_tuner_callback(core, command, arg); - } - err_printk(core, "Error: Calling callback for tuner %d\n", - core->board.tuner_type); - return -EINVAL; -} -EXPORT_SYMBOL(cx88_tuner_callback); - -/* ----------------------------------------------------------------------- */ - -static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) -{ - int i; - - if (0 == pci->subsystem_vendor && - 0 == pci->subsystem_device) { - printk(KERN_ERR - "%s: Your board has no valid PCI Subsystem ID and thus can't\n" - "%s: be autodetected. Please pass card= insmod option to\n" - "%s: workaround that. Redirect complaints to the vendor of\n" - "%s: the TV card. Best regards,\n" - "%s: -- tux\n", - core->name,core->name,core->name,core->name,core->name); - } else { - printk(KERN_ERR - "%s: Your board isn't known (yet) to the driver. You can\n" - "%s: try to pick one of the existing card configs via\n" - "%s: card= insmod option. Updating to the latest\n" - "%s: version might help as well.\n", - core->name,core->name,core->name,core->name); - } - err_printk(core, "Here is a list of valid choices for the card= " - "insmod option:\n"); - for (i = 0; i < ARRAY_SIZE(cx88_boards); i++) - printk(KERN_ERR "%s: card=%d -> %s\n", - core->name, i, cx88_boards[i].name); -} - -static void cx88_card_setup_pre_i2c(struct cx88_core *core) -{ - switch (core->boardnr) { - case CX88_BOARD_HAUPPAUGE_HVR1300: - /* - * Bring the 702 demod up before i2c scanning/attach or devices are hidden - * We leave here with the 702 on the bus - * - * "reset the IR receiver on GPIO[3]" - * Reported by Mike Crash - */ - cx_write(MO_GP0_IO, 0x0000ef88); - udelay(1000); - cx_clear(MO_GP0_IO, 0x00000088); - udelay(50); - cx_set(MO_GP0_IO, 0x00000088); /* 702 out of reset */ - udelay(1000); - break; - - case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: - case CX88_BOARD_PROLINK_PV_8000GT: - cx_write(MO_GP2_IO, 0xcf7); - mdelay(50); - cx_write(MO_GP2_IO, 0xef5); - mdelay(50); - cx_write(MO_GP2_IO, 0xcf7); - msleep(10); - break; - - case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: - /* Enable the xc5000 tuner */ - cx_set(MO_GP0_IO, 0x00001010); - break; - - case CX88_BOARD_HAUPPAUGE_HVR3000: - case CX88_BOARD_HAUPPAUGE_HVR4000: - /* Init GPIO */ - cx_write(MO_GP0_IO, core->board.input[0].gpio0); - udelay(1000); - cx_clear(MO_GP0_IO, 0x00000080); - udelay(50); - cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */ - udelay(1000); - break; - - case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: - case CX88_BOARD_WINFAST_DTV1800H: - /* GPIO 12 (xc3028 tuner reset) */ - cx_set(MO_GP1_IO, 0x1010); - mdelay(50); - cx_clear(MO_GP1_IO, 0x10); - mdelay(50); - cx_set(MO_GP1_IO, 0x10); - mdelay(50); - break; - - case CX88_BOARD_TWINHAN_VP1027_DVBS: - cx_write(MO_GP0_IO, 0x00003230); - cx_write(MO_GP0_IO, 0x00003210); - msleep(1); - cx_write(MO_GP0_IO, 0x00001230); - break; - } -} - -/* - * Sets board-dependent xc3028 configuration - */ -void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl) -{ - memset(ctl, 0, sizeof(*ctl)); - - ctl->fname = XC2028_DEFAULT_FIRMWARE; - ctl->max_len = 64; - - switch (core->boardnr) { - case CX88_BOARD_POWERCOLOR_REAL_ANGEL: - /* Now works with firmware version 2.7 */ - if (core->i2c_algo.udelay < 16) - core->i2c_algo.udelay = 16; - break; - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: - case CX88_BOARD_WINFAST_DTV1800H: - ctl->demod = XC3028_FE_ZARLINK456; - break; - case CX88_BOARD_KWORLD_ATSC_120: - case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: - ctl->demod = XC3028_FE_OREN538; - break; - case CX88_BOARD_GENIATECH_X8000_MT: - /* FIXME: For this board, the xc3028 never recovers after being - powered down (the reset GPIO probably is not set properly). - We don't have access to the hardware so we cannot determine - which GPIO is used for xc3028, so just disable power xc3028 - power management for now */ - ctl->disable_power_mgmt = 1; - break; - case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: - case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: - case CX88_BOARD_PROLINK_PV_8000GT: - /* - * Those boards uses non-MTS firmware - */ - break; - case CX88_BOARD_PINNACLE_HYBRID_PCTV: - case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII: - ctl->demod = XC3028_FE_ZARLINK456; - ctl->mts = 1; - break; - default: - ctl->demod = XC3028_FE_OREN538; - ctl->mts = 1; - } -} -EXPORT_SYMBOL_GPL(cx88_setup_xc3028); - -static void cx88_card_setup(struct cx88_core *core) -{ - static u8 eeprom[256]; - struct tuner_setup tun_setup; - unsigned int mode_mask = T_RADIO | T_ANALOG_TV; - - memset(&tun_setup, 0, sizeof(tun_setup)); - - if (0 == core->i2c_rc) { - core->i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom)); - } - - switch (core->boardnr) { - case CX88_BOARD_HAUPPAUGE: - case CX88_BOARD_HAUPPAUGE_ROSLYN: - if (0 == core->i2c_rc) - hauppauge_eeprom(core, eeprom+8); - break; - case CX88_BOARD_GDI: - if (0 == core->i2c_rc) - gdi_eeprom(core, eeprom); - break; - case CX88_BOARD_LEADTEK_PVR2000: - case CX88_BOARD_WINFAST_DV2000: - case CX88_BOARD_WINFAST2000XP_EXPERT: - if (0 == core->i2c_rc) - leadtek_eeprom(core, eeprom); - break; - case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: - case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: - case CX88_BOARD_HAUPPAUGE_DVB_T1: - case CX88_BOARD_HAUPPAUGE_HVR1100: - case CX88_BOARD_HAUPPAUGE_HVR1100LP: - case CX88_BOARD_HAUPPAUGE_HVR3000: - case CX88_BOARD_HAUPPAUGE_HVR1300: - case CX88_BOARD_HAUPPAUGE_HVR4000: - case CX88_BOARD_HAUPPAUGE_HVR4000LITE: - case CX88_BOARD_HAUPPAUGE_IRONLY: - if (0 == core->i2c_rc) - hauppauge_eeprom(core, eeprom); - break; - case CX88_BOARD_KWORLD_DVBS_100: - cx_write(MO_GP0_IO, 0x000007f8); - cx_write(MO_GP1_IO, 0x00000001); - break; - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: - /* GPIO0:0 is hooked to demod reset */ - /* GPIO0:4 is hooked to xc3028 reset */ - cx_write(MO_GP0_IO, 0x00111100); - msleep(1); - cx_write(MO_GP0_IO, 0x00111111); - break; - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: - /* GPIO0:6 is hooked to FX2 reset pin */ - cx_set(MO_GP0_IO, 0x00004040); - cx_clear(MO_GP0_IO, 0x00000040); - msleep(1000); - cx_set(MO_GP0_IO, 0x00004040); - /* FALLTHROUGH */ - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: - /* GPIO0:0 is hooked to mt352 reset pin */ - cx_set(MO_GP0_IO, 0x00000101); - cx_clear(MO_GP0_IO, 0x00000001); - msleep(1); - cx_set(MO_GP0_IO, 0x00000101); - if (0 == core->i2c_rc && - core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) - dvico_fusionhdtv_hybrid_init(core); - break; - case CX88_BOARD_KWORLD_DVB_T: - case CX88_BOARD_DNTV_LIVE_DVB_T: - cx_set(MO_GP0_IO, 0x00000707); - cx_set(MO_GP2_IO, 0x00000101); - cx_clear(MO_GP2_IO, 0x00000001); - msleep(1); - cx_clear(MO_GP0_IO, 0x00000007); - cx_set(MO_GP2_IO, 0x00000101); - break; - case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: - cx_write(MO_GP0_IO, 0x00080808); - break; - case CX88_BOARD_ATI_HDTVWONDER: - if (0 == core->i2c_rc) { - /* enable tuner */ - int i; - static const u8 buffer [][2] = { - {0x10,0x12}, - {0x13,0x04}, - {0x16,0x00}, - {0x14,0x04}, - {0x17,0x00} - }; - core->i2c_client.addr = 0x0a; - - for (i = 0; i < ARRAY_SIZE(buffer); i++) - if (2 != i2c_master_send(&core->i2c_client, - buffer[i],2)) - warn_printk(core, "Unable to enable " - "tuner(%i).\n", i); - } - break; - case CX88_BOARD_MSI_TVANYWHERE_MASTER: - { - struct v4l2_priv_tun_config tea5767_cfg; - struct tea5767_ctrl ctl; - - memset(&ctl, 0, sizeof(ctl)); - - ctl.high_cut = 1; - ctl.st_noise = 1; - ctl.deemph_75 = 1; - ctl.xtal_freq = TEA5767_HIGH_LO_13MHz; - - tea5767_cfg.tuner = TUNER_TEA5767; - tea5767_cfg.priv = &ctl; - - call_all(core, tuner, s_config, &tea5767_cfg); - break; - } - case CX88_BOARD_TEVII_S420: - case CX88_BOARD_TEVII_S460: - case CX88_BOARD_TEVII_S464: - case CX88_BOARD_OMICOM_SS4_PCI: - case CX88_BOARD_TBS_8910: - case CX88_BOARD_TBS_8920: - case CX88_BOARD_PROF_6200: - case CX88_BOARD_PROF_7300: - case CX88_BOARD_PROF_7301: - case CX88_BOARD_SATTRADE_ST4200: - cx_write(MO_GP0_IO, 0x8000); - msleep(100); - cx_write(MO_SRST_IO, 0); - msleep(10); - cx_write(MO_GP0_IO, 0x8080); - msleep(100); - cx_write(MO_SRST_IO, 1); - msleep(100); - break; - } /*end switch() */ - - - /* Setup tuners */ - if ((core->board.radio_type != UNSET)) { - tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->board.radio_type; - tun_setup.addr = core->board.radio_addr; - tun_setup.tuner_callback = cx88_tuner_callback; - call_all(core, tuner, s_type_addr, &tun_setup); - mode_mask &= ~T_RADIO; - } - - if (core->board.tuner_type != TUNER_ABSENT) { - tun_setup.mode_mask = mode_mask; - tun_setup.type = core->board.tuner_type; - tun_setup.addr = core->board.tuner_addr; - tun_setup.tuner_callback = cx88_tuner_callback; - - call_all(core, tuner, s_type_addr, &tun_setup); - } - - if (core->board.tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &core->board.tda9887_conf; - - call_all(core, tuner, s_config, &tda9887_cfg); - } - - if (core->board.tuner_type == TUNER_XC2028) { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - /* Fills device-dependent initialization parameters */ - cx88_setup_xc3028(core, &ctl); - - /* Sends parameters to xc2028/3028 tuner */ - memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - info_printk(core, "Asking xc2028/3028 to load firmware %s\n", - ctl.fname); - call_all(core, tuner, s_config, &xc2028_cfg); - } - call_all(core, core, s_power, 0); -} - -/* ------------------------------------------------------------------ */ - -static int cx88_pci_quirks(const char *name, struct pci_dev *pci) -{ - unsigned int lat = UNSET; - u8 ctrl = 0; - u8 value; - - /* check pci quirks */ - if (pci_pci_problems & PCIPCI_TRITON) { - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_NATOMA) { - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_VIAETBF) { - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_VSFX) { - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", - name); - ctrl |= CX88X_EN_VSFX; - } -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", - name); - lat = 0x0A; - } -#endif - - /* check insmod options */ - if (UNSET != latency) - lat = latency; - - /* apply stuff */ - if (ctrl) { - pci_read_config_byte(pci, CX88X_DEVCTRL, &value); - value |= ctrl; - pci_write_config_byte(pci, CX88X_DEVCTRL, value); - } - if (UNSET != lat) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", - name, latency); - pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); - } - return 0; -} - -int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci) -{ - if (request_mem_region(pci_resource_start(pci,0), - pci_resource_len(pci,0), - core->name)) - return 0; - printk(KERN_ERR - "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", - core->name, PCI_FUNC(pci->devfn), - (unsigned long long)pci_resource_start(pci, 0), - pci->subsystem_vendor, pci->subsystem_device); - return -EBUSY; -} - -/* Allocate and initialize the cx88 core struct. One should hold the - * devlist mutex before calling this. */ -struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) -{ - struct cx88_core *core; - int i; - - core = kzalloc(sizeof(*core), GFP_KERNEL); - if (core == NULL) - return NULL; - - atomic_inc(&core->refcount); - core->pci_bus = pci->bus->number; - core->pci_slot = PCI_SLOT(pci->devfn); - core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT | - PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT | - PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT; - mutex_init(&core->lock); - - core->nr = nr; - sprintf(core->name, "cx88[%d]", core->nr); - - strcpy(core->v4l2_dev.name, core->name); - if (v4l2_device_register(NULL, &core->v4l2_dev)) { - kfree(core); - return NULL; - } - - if (0 != cx88_get_resources(core, pci)) { - v4l2_device_unregister(&core->v4l2_dev); - kfree(core); - return NULL; - } - - /* PCI stuff */ - cx88_pci_quirks(core->name, pci); - core->lmmio = ioremap(pci_resource_start(pci, 0), - pci_resource_len(pci, 0)); - core->bmmio = (u8 __iomem *)core->lmmio; - - if (core->lmmio == NULL) { - kfree(core); - return NULL; - } - - /* board config */ - core->boardnr = UNSET; - if (card[core->nr] < ARRAY_SIZE(cx88_boards)) - core->boardnr = card[core->nr]; - for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++) - if (pci->subsystem_vendor == cx88_subids[i].subvendor && - pci->subsystem_device == cx88_subids[i].subdevice) - core->boardnr = cx88_subids[i].card; - if (UNSET == core->boardnr) { - core->boardnr = CX88_BOARD_UNKNOWN; - cx88_card_list(core, pci); - } - - memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); - - if (!core->board.num_frontends && (core->board.mpeg & CX88_MPEG_DVB)) - core->board.num_frontends = 1; - - info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n", - pci->subsystem_vendor, pci->subsystem_device, core->board.name, - core->boardnr, card[core->nr] == core->boardnr ? - "insmod option" : "autodetected", - core->board.num_frontends); - - if (tuner[core->nr] != UNSET) - core->board.tuner_type = tuner[core->nr]; - if (radio[core->nr] != UNSET) - core->board.radio_type = radio[core->nr]; - - info_printk(core, "TV tuner type %d, Radio tuner type %d\n", - core->board.tuner_type, core->board.radio_type); - - /* init hardware */ - cx88_reset(core); - cx88_card_setup_pre_i2c(core); - cx88_i2c_init(core, pci); - - /* load tuner module, if needed */ - if (TUNER_ABSENT != core->board.tuner_type) { - /* Ignore 0x6b and 0x6f on cx88 boards. - * FusionHDTV5 RT Gold has an ir receiver at 0x6b - * and an RTC at 0x6f which can get corrupted if probed. */ - static const unsigned short tv_addrs[] = { - 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6c, 0x6d, 0x6e, - I2C_CLIENT_END - }; - int has_demod = (core->board.tda9887_conf & TDA9887_PRESENT); - - /* I don't trust the radio_type as is stored in the card - definitions, so we just probe for it. - The radio_type is sometimes missing, or set to UNSET but - later code configures a tea5767. - */ - v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); - if (has_demod) - v4l2_i2c_new_subdev(&core->v4l2_dev, - &core->i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); - if (core->board.tuner_addr == ADDR_UNSET) { - v4l2_i2c_new_subdev(&core->v4l2_dev, - &core->i2c_adap, "tuner", - 0, has_demod ? tv_addrs + 4 : tv_addrs); - } else { - v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - "tuner", core->board.tuner_addr, NULL); - } - } - - cx88_card_setup(core); - if (!disable_ir) { - cx88_i2c_init_ir(core); - cx88_ir_init(core, pci); - } - - return core; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1126 +0,0 @@ -/* - * - * device driver for Conexant 2388x based TV cards - * driver core - * - * (c) 2003 Gerd Knorr [SuSE Labs] - * - * (c) 2005-2006 Mauro Carvalho Chehab - * - Multituner support - * - video_ioctl2 conversion - * - PAL/M fixes - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx88.h" -#include -#include - -MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------------ */ - -static unsigned int core_debug; -module_param(core_debug,int,0644); -MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); - -static unsigned int nicam; -module_param(nicam,int,0644); -MODULE_PARM_DESC(nicam,"tv audio is nicam"); - -static unsigned int nocomb; -module_param(nocomb,int,0644); -MODULE_PARM_DESC(nocomb,"disable comb filter"); - -#define dprintk(level,fmt, arg...) if (core_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) - -static unsigned int cx88_devcount; -static LIST_HEAD(cx88_devlist); -static DEFINE_MUTEX(devlist); - -#define NO_SYNC_LINE (-1U) - -/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be - generated _after_ lpi lines are transferred. */ -static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist, - unsigned int offset, u32 sync_line, - unsigned int bpl, unsigned int padding, - unsigned int lines, unsigned int lpi) -{ - struct scatterlist *sg; - unsigned int line,todo,sol; - - /* sync instruction */ - if (sync_line != NO_SYNC_LINE) - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - /* scan lines */ - sg = sglist; - for (line = 0; line < lines; line++) { - while (offset && offset >= sg_dma_len(sg)) { - offset -= sg_dma_len(sg); - sg++; - } - if (lpi && line>0 && !(line % lpi)) - sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; - else - sol = RISC_SOL; - if (bpl <= sg_dma_len(sg)-offset) { - /* fits into current chunk */ - *(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); - offset+=bpl; - } else { - /* scanline needs to be split */ - todo = bpl; - *(rp++)=cpu_to_le32(RISC_WRITE|sol| - (sg_dma_len(sg)-offset)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); - todo -= (sg_dma_len(sg)-offset); - offset = 0; - sg++; - while (todo > sg_dma_len(sg)) { - *(rp++)=cpu_to_le32(RISC_WRITE| - sg_dma_len(sg)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); - todo -= sg_dma_len(sg); - sg++; - } - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); - offset += todo; - } - offset += padding; - } - - return rp; -} - -int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int top_offset, unsigned int bottom_offset, - unsigned int bpl, unsigned int padding, unsigned int lines) -{ - u32 instructions,fields; - __le32 *rp; - int rc; - - fields = 0; - if (UNSET != top_offset) - fields++; - if (UNSET != bottom_offset) - fields++; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Padding - can cause next bpl to start close to a page border. First DMA - region may be smaller than PAGE_SIZE */ - instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; - if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - if (UNSET != top_offset) - rp = cx88_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines, 0); - if (UNSET != bottom_offset) - rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines, 0); - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); - return 0; -} - -int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int bpl, - unsigned int lines, unsigned int lpi) -{ - u32 instructions; - __le32 *rp; - int rc; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Here - there is no padding and no sync. First DMA region may be smaller - than PAGE_SIZE */ - instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; - instructions += 1; - if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi); - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); - return 0; -} - -int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) -{ - __le32 *rp; - int rc; - - if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM); - *(rp++) = cpu_to_le32(reg); - *(rp++) = cpu_to_le32(value); - *(rp++) = cpu_to_le32(mask); - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - return 0; -} - -void -cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) -{ - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -/* ------------------------------------------------------------------ */ -/* our SRAM memory layout */ - -/* we are going to put all thr risc programs into host memory, so we - * can use the whole SDRAM for the DMA fifos. To simplify things, we - * use a static memory layout. That surely will waste memory in case - * we don't use all DMA channels at the same time (which will be the - * case most of the time). But that still gives us enough FIFO space - * to be able to deal with insane long pci latencies ... - * - * FIFO space allocations: - * channel 21 (y video) - 10.0k - * channel 22 (u video) - 2.0k - * channel 23 (v video) - 2.0k - * channel 24 (vbi) - 4.0k - * channels 25+26 (audio) - 4.0k - * channel 28 (mpeg) - 4.0k - * channel 27 (audio rds)- 3.0k - * TOTAL = 29.0k - * - * Every channel has 160 bytes control data (64 bytes instruction - * queue and 6 CDT entries), which is close to 2k total. - * - * Address layout: - * 0x0000 - 0x03ff CMDs / reserved - * 0x0400 - 0x0bff instruction queues + CDs - * 0x0c00 - FIFOs - */ - -const struct sram_channel const cx88_sram_channels[] = { - [SRAM_CH21] = { - .name = "video y / packed", - .cmds_start = 0x180040, - .ctrl_start = 0x180400, - .cdt = 0x180400 + 64, - .fifo_start = 0x180c00, - .fifo_size = 0x002800, - .ptr1_reg = MO_DMA21_PTR1, - .ptr2_reg = MO_DMA21_PTR2, - .cnt1_reg = MO_DMA21_CNT1, - .cnt2_reg = MO_DMA21_CNT2, - }, - [SRAM_CH22] = { - .name = "video u", - .cmds_start = 0x180080, - .ctrl_start = 0x1804a0, - .cdt = 0x1804a0 + 64, - .fifo_start = 0x183400, - .fifo_size = 0x000800, - .ptr1_reg = MO_DMA22_PTR1, - .ptr2_reg = MO_DMA22_PTR2, - .cnt1_reg = MO_DMA22_CNT1, - .cnt2_reg = MO_DMA22_CNT2, - }, - [SRAM_CH23] = { - .name = "video v", - .cmds_start = 0x1800c0, - .ctrl_start = 0x180540, - .cdt = 0x180540 + 64, - .fifo_start = 0x183c00, - .fifo_size = 0x000800, - .ptr1_reg = MO_DMA23_PTR1, - .ptr2_reg = MO_DMA23_PTR2, - .cnt1_reg = MO_DMA23_CNT1, - .cnt2_reg = MO_DMA23_CNT2, - }, - [SRAM_CH24] = { - .name = "vbi", - .cmds_start = 0x180100, - .ctrl_start = 0x1805e0, - .cdt = 0x1805e0 + 64, - .fifo_start = 0x184400, - .fifo_size = 0x001000, - .ptr1_reg = MO_DMA24_PTR1, - .ptr2_reg = MO_DMA24_PTR2, - .cnt1_reg = MO_DMA24_CNT1, - .cnt2_reg = MO_DMA24_CNT2, - }, - [SRAM_CH25] = { - .name = "audio from", - .cmds_start = 0x180140, - .ctrl_start = 0x180680, - .cdt = 0x180680 + 64, - .fifo_start = 0x185400, - .fifo_size = 0x001000, - .ptr1_reg = MO_DMA25_PTR1, - .ptr2_reg = MO_DMA25_PTR2, - .cnt1_reg = MO_DMA25_CNT1, - .cnt2_reg = MO_DMA25_CNT2, - }, - [SRAM_CH26] = { - .name = "audio to", - .cmds_start = 0x180180, - .ctrl_start = 0x180720, - .cdt = 0x180680 + 64, /* same as audio IN */ - .fifo_start = 0x185400, /* same as audio IN */ - .fifo_size = 0x001000, /* same as audio IN */ - .ptr1_reg = MO_DMA26_PTR1, - .ptr2_reg = MO_DMA26_PTR2, - .cnt1_reg = MO_DMA26_CNT1, - .cnt2_reg = MO_DMA26_CNT2, - }, - [SRAM_CH28] = { - .name = "mpeg", - .cmds_start = 0x180200, - .ctrl_start = 0x1807C0, - .cdt = 0x1807C0 + 64, - .fifo_start = 0x186400, - .fifo_size = 0x001000, - .ptr1_reg = MO_DMA28_PTR1, - .ptr2_reg = MO_DMA28_PTR2, - .cnt1_reg = MO_DMA28_CNT1, - .cnt2_reg = MO_DMA28_CNT2, - }, - [SRAM_CH27] = { - .name = "audio rds", - .cmds_start = 0x1801C0, - .ctrl_start = 0x180860, - .cdt = 0x180860 + 64, - .fifo_start = 0x187400, - .fifo_size = 0x000C00, - .ptr1_reg = MO_DMA27_PTR1, - .ptr2_reg = MO_DMA27_PTR2, - .cnt1_reg = MO_DMA27_CNT1, - .cnt2_reg = MO_DMA27_CNT2, - }, -}; - -int cx88_sram_channel_setup(struct cx88_core *core, - const struct sram_channel *ch, - unsigned int bpl, u32 risc) -{ - unsigned int i,lines; - u32 cdt; - - bpl = (bpl + 7) & ~7; /* alignment */ - cdt = ch->cdt; - lines = ch->fifo_size / bpl; - if (lines > 6) - lines = 6; - BUG_ON(lines < 2); - - /* write CDT */ - for (i = 0; i < lines; i++) - cx_write(cdt + 16*i, ch->fifo_start + bpl*i); - - /* write CMDS */ - cx_write(ch->cmds_start + 0, risc); - cx_write(ch->cmds_start + 4, cdt); - cx_write(ch->cmds_start + 8, (lines*16) >> 3); - cx_write(ch->cmds_start + 12, ch->ctrl_start); - cx_write(ch->cmds_start + 16, 64 >> 2); - for (i = 20; i < 64; i += 4) - cx_write(ch->cmds_start + i, 0); - - /* fill registers */ - cx_write(ch->ptr1_reg, ch->fifo_start); - cx_write(ch->ptr2_reg, cdt); - cx_write(ch->cnt1_reg, (bpl >> 3) -1); - cx_write(ch->cnt2_reg, (lines*16) >> 3); - - dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines); - return 0; -} - -/* ------------------------------------------------------------------ */ -/* debug helper code */ - -static int cx88_risc_decode(u32 risc) -{ - static const char * const instr[16] = { - [ RISC_SYNC >> 28 ] = "sync", - [ RISC_WRITE >> 28 ] = "write", - [ RISC_WRITEC >> 28 ] = "writec", - [ RISC_READ >> 28 ] = "read", - [ RISC_READC >> 28 ] = "readc", - [ RISC_JUMP >> 28 ] = "jump", - [ RISC_SKIP >> 28 ] = "skip", - [ RISC_WRITERM >> 28 ] = "writerm", - [ RISC_WRITECM >> 28 ] = "writecm", - [ RISC_WRITECR >> 28 ] = "writecr", - }; - static int const incr[16] = { - [ RISC_WRITE >> 28 ] = 2, - [ RISC_JUMP >> 28 ] = 2, - [ RISC_WRITERM >> 28 ] = 3, - [ RISC_WRITECM >> 28 ] = 3, - [ RISC_WRITECR >> 28 ] = 4, - }; - static const char * const bits[] = { - "12", "13", "14", "resync", - "cnt0", "cnt1", "18", "19", - "20", "21", "22", "23", - "irq1", "irq2", "eol", "sol", - }; - int i; - - printk("0x%08x [ %s", risc, - instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); - for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) - if (risc & (1 << (i + 12))) - printk(" %s",bits[i]); - printk(" count=%d ]\n", risc & 0xfff); - return incr[risc >> 28] ? incr[risc >> 28] : 1; -} - - -void cx88_sram_channel_dump(struct cx88_core *core, - const struct sram_channel *ch) -{ - static const char * const name[] = { - "initial risc", - "cdt base", - "cdt size", - "iq base", - "iq size", - "risc pc", - "iq wr ptr", - "iq rd ptr", - "cdt current", - "pci target", - "line / byte", - }; - u32 risc; - unsigned int i,j,n; - - printk("%s: %s - dma channel status dump\n", - core->name,ch->name); - for (i = 0; i < ARRAY_SIZE(name); i++) - printk("%s: cmds: %-12s: 0x%08x\n", - core->name,name[i], - cx_read(ch->cmds_start + 4*i)); - for (n = 1, i = 0; i < 4; i++) { - risc = cx_read(ch->cmds_start + 4 * (i+11)); - printk("%s: risc%d: ", core->name, i); - if (--n) - printk("0x%08x [ arg #%d ]\n", risc, n); - else - n = cx88_risc_decode(risc); - } - for (i = 0; i < 16; i += n) { - risc = cx_read(ch->ctrl_start + 4 * i); - printk("%s: iq %x: ", core->name, i); - n = cx88_risc_decode(risc); - for (j = 1; j < n; j++) { - risc = cx_read(ch->ctrl_start + 4 * (i+j)); - printk("%s: iq %x: 0x%08x [ arg #%d ]\n", - core->name, i+j, risc, j); - } - } - - printk("%s: fifo: 0x%08x -> 0x%x\n", - core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); - printk("%s: ctrl: 0x%08x -> 0x%x\n", - core->name, ch->ctrl_start, ch->ctrl_start+6*16); - printk("%s: ptr1_reg: 0x%08x\n", - core->name,cx_read(ch->ptr1_reg)); - printk("%s: ptr2_reg: 0x%08x\n", - core->name,cx_read(ch->ptr2_reg)); - printk("%s: cnt1_reg: 0x%08x\n", - core->name,cx_read(ch->cnt1_reg)); - printk("%s: cnt2_reg: 0x%08x\n", - core->name,cx_read(ch->cnt2_reg)); -} - -static const char *cx88_pci_irqs[32] = { - "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1", - "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err", - "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err", - "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1" -}; - -void cx88_print_irqbits(const char *name, const char *tag, const char *strings[], - int len, u32 bits, u32 mask) -{ - unsigned int i; - - printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits); - for (i = 0; i < len; i++) { - if (!(bits & (1 << i))) - continue; - if (strings[i]) - printk(" %s", strings[i]); - else - printk(" %d", i); - if (!(mask & (1 << i))) - continue; - printk("*"); - } - printk("\n"); -} - -/* ------------------------------------------------------------------ */ - -int cx88_core_irq(struct cx88_core *core, u32 status) -{ - int handled = 0; - - if (status & PCI_INT_IR_SMPINT) { - cx88_ir_irq(core); - handled++; - } - if (!handled) - cx88_print_irqbits(core->name, "irq pci", - cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs), - status, core->pci_irqmask); - return handled; -} - -void cx88_wakeup(struct cx88_core *core, - struct cx88_dmaqueue *q, u32 count) -{ - struct cx88_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx88_buffer, vb.queue); - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - do_gettimeofday(&buf->vb.ts); - dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } - if (list_empty(&q->active)) { - del_timer(&q->timeout); - } else { - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - } - if (bc != 1) - dprintk(2, "%s: %d buffers handled (should be 1)\n", - __func__, bc); -} - -void cx88_shutdown(struct cx88_core *core) -{ - /* disable RISC controller + IRQs */ - cx_write(MO_DEV_CNTRL2, 0); - - /* stop dma transfers */ - cx_write(MO_VID_DMACNTRL, 0x0); - cx_write(MO_AUD_DMACNTRL, 0x0); - cx_write(MO_TS_DMACNTRL, 0x0); - cx_write(MO_VIP_DMACNTRL, 0x0); - cx_write(MO_GPHST_DMACNTRL, 0x0); - - /* stop interrupts */ - cx_write(MO_PCI_INTMSK, 0x0); - cx_write(MO_VID_INTMSK, 0x0); - cx_write(MO_AUD_INTMSK, 0x0); - cx_write(MO_TS_INTMSK, 0x0); - cx_write(MO_VIP_INTMSK, 0x0); - cx_write(MO_GPHST_INTMSK, 0x0); - - /* stop capturing */ - cx_write(VID_CAPTURE_CONTROL, 0); -} - -int cx88_reset(struct cx88_core *core) -{ - dprintk(1,"%s\n",__func__); - cx88_shutdown(core); - - /* clear irq status */ - cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int - cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int - cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int - - /* wait a bit */ - msleep(100); - - /* init sram */ - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0); - - /* misc init ... */ - cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable - (1 << 12) | // agc gain - (1 << 11) | // adaptibe agc - (0 << 10) | // chroma agc - (0 << 9) | // ckillen - (7))); - - /* setup image format */ - cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000); - - /* setup FIFO Thresholds */ - cx_write(MO_PDMA_STHRSH, 0x0807); - cx_write(MO_PDMA_DTHRSH, 0x0807); - - /* fixes flashing of image */ - cx_write(MO_AGC_SYNC_TIP1, 0x0380000F); - cx_write(MO_AGC_BACK_VBI, 0x00E00555); - - cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int - cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int - cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int - - /* Reset on-board parts */ - cx_write(MO_SRST_IO, 0); - msleep(10); - cx_write(MO_SRST_IO, 1); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static unsigned int inline norm_swidth(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; -} - -static unsigned int inline norm_hdelay(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186; -} - -static unsigned int inline norm_vdelay(v4l2_std_id norm) -{ - return (norm & V4L2_STD_625_50) ? 0x24 : 0x18; -} - -static unsigned int inline norm_fsc8(v4l2_std_id norm) -{ - if (norm & V4L2_STD_PAL_M) - return 28604892; // 3.575611 MHz - - if (norm & (V4L2_STD_PAL_Nc)) - return 28656448; // 3.582056 MHz - - if (norm & V4L2_STD_NTSC) // All NTSC/M and variants - return 28636360; // 3.57954545 MHz +/- 10 Hz - - /* SECAM have also different sub carrier for chroma, - but step_db and step_dr, at cx88_set_tvnorm already handles that. - - The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N - */ - - return 35468950; // 4.43361875 MHz +/- 5 Hz -} - -static unsigned int inline norm_htotal(v4l2_std_id norm) -{ - - unsigned int fsc4=norm_fsc8(norm)/2; - - /* returns 4*FSC / vtotal / frames per seconds */ - return (norm & V4L2_STD_625_50) ? - ((fsc4+312)/625+12)/25 : - ((fsc4+262)/525*1001+15000)/30000; -} - -static unsigned int inline norm_vbipack(v4l2_std_id norm) -{ - return (norm & V4L2_STD_625_50) ? 511 : 400; -} - -int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height, - enum v4l2_field field) -{ - unsigned int swidth = norm_swidth(core->tvnorm); - unsigned int sheight = norm_maxh(core->tvnorm); - u32 value; - - dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height, - V4L2_FIELD_HAS_TOP(field) ? "T" : "", - V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", - v4l2_norm_to_name(core->tvnorm)); - if (!V4L2_FIELD_HAS_BOTH(field)) - height *= 2; - - // recalc H delay and scale registers - value = (width * norm_hdelay(core->tvnorm)) / swidth; - value &= 0x3fe; - cx_write(MO_HDELAY_EVEN, value); - cx_write(MO_HDELAY_ODD, value); - dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth); - - value = (swidth * 4096 / width) - 4096; - cx_write(MO_HSCALE_EVEN, value); - cx_write(MO_HSCALE_ODD, value); - dprintk(1,"set_scale: hscale 0x%04x\n", value); - - cx_write(MO_HACTIVE_EVEN, width); - cx_write(MO_HACTIVE_ODD, width); - dprintk(1,"set_scale: hactive 0x%04x\n", width); - - // recalc V scale Register (delay is constant) - cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm)); - cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm)); - dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm)); - - value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff; - cx_write(MO_VSCALE_EVEN, value); - cx_write(MO_VSCALE_ODD, value); - dprintk(1,"set_scale: vscale 0x%04x\n", value); - - cx_write(MO_VACTIVE_EVEN, sheight); - cx_write(MO_VACTIVE_ODD, sheight); - dprintk(1,"set_scale: vactive 0x%04x\n", sheight); - - // setup filters - value = 0; - value |= (1 << 19); // CFILT (default) - if (core->tvnorm & V4L2_STD_SECAM) { - value |= (1 << 15); - value |= (1 << 16); - } - if (INPUT(core->input).type == CX88_VMUX_SVIDEO) - value |= (1 << 13) | (1 << 5); - if (V4L2_FIELD_INTERLACED == field) - value |= (1 << 3); // VINT (interlaced vertical scaling) - if (width < 385) - value |= (1 << 0); // 3-tap interpolation - if (width < 193) - value |= (1 << 1); // 5-tap interpolation - if (nocomb) - value |= (3 << 5); // disable comb filter - - cx_write(MO_FILTER_EVEN, value); - cx_write(MO_FILTER_ODD, value); - dprintk(1,"set_scale: filter 0x%04x\n", value); - - return 0; -} - -static const u32 xtal = 28636363; - -static int set_pll(struct cx88_core *core, int prescale, u32 ofreq) -{ - static const u32 pre[] = { 0, 0, 0, 3, 2, 1 }; - u64 pll; - u32 reg; - int i; - - if (prescale < 2) - prescale = 2; - if (prescale > 5) - prescale = 5; - - pll = ofreq * 8 * prescale * (u64)(1 << 20); - do_div(pll,xtal); - reg = (pll & 0x3ffffff) | (pre[prescale] << 26); - if (((reg >> 20) & 0x3f) < 14) { - printk("%s/0: pll out of range\n",core->name); - return -1; - } - - dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n", - reg, cx_read(MO_PLL_REG), ofreq); - cx_write(MO_PLL_REG, reg); - for (i = 0; i < 100; i++) { - reg = cx_read(MO_DEVICE_STATUS); - if (reg & (1<<2)) { - dprintk(1,"pll locked [pre=%d,ofreq=%d]\n", - prescale,ofreq); - return 0; - } - dprintk(1,"pll not locked yet, waiting ...\n"); - msleep(10); - } - dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq); - return -1; -} - -int cx88_start_audio_dma(struct cx88_core *core) -{ - /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */ - int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4; - - int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES; - - /* If downstream RISC is enabled, bail out; ALSA is managing DMA */ - if (cx_read(MO_AUD_DMACNTRL) & 0x10) - return 0; - - /* setup fifo + format */ - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], - rds_bpl, 0); - - cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */ - cx_write(MO_AUDR_LNGTH, rds_bpl); /* fifo bpl size */ - - /* enable Up, Down and Audio RDS fifo */ - cx_write(MO_AUD_DMACNTRL, 0x0007); - - return 0; -} - -int cx88_stop_audio_dma(struct cx88_core *core) -{ - /* If downstream RISC is enabled, bail out; ALSA is managing DMA */ - if (cx_read(MO_AUD_DMACNTRL) & 0x10) - return 0; - - /* stop dma */ - cx_write(MO_AUD_DMACNTRL, 0x0000); - - return 0; -} - -static int set_tvaudio(struct cx88_core *core) -{ - v4l2_std_id norm = core->tvnorm; - - if (CX88_VMUX_TELEVISION != INPUT(core->input).type && - CX88_VMUX_CABLE != INPUT(core->input).type) - return 0; - - if (V4L2_STD_PAL_BG & norm) { - core->tvaudio = WW_BG; - - } else if (V4L2_STD_PAL_DK & norm) { - core->tvaudio = WW_DK; - - } else if (V4L2_STD_PAL_I & norm) { - core->tvaudio = WW_I; - - } else if (V4L2_STD_SECAM_L & norm) { - core->tvaudio = WW_L; - - } else if ((V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H) & norm) { - core->tvaudio = WW_BG; - - } else if (V4L2_STD_SECAM_DK & norm) { - core->tvaudio = WW_DK; - - } else if ((V4L2_STD_NTSC_M & norm) || - (V4L2_STD_PAL_M & norm)) { - core->tvaudio = WW_BTSC; - - } else if (V4L2_STD_NTSC_M_JP & norm) { - core->tvaudio = WW_EIAJ; - - } else { - printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n", - core->name, v4l2_norm_to_name(core->tvnorm)); - core->tvaudio = WW_NONE; - return 0; - } - - cx_andor(MO_AFECFG_IO, 0x1f, 0x0); - cx88_set_tvaudio(core); - /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */ - -/* - This should be needed only on cx88-alsa. It seems that some cx88 chips have - bugs and does require DMA enabled for it to work. - */ - cx88_start_audio_dma(core); - return 0; -} - - - -int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) -{ - u32 fsc8; - u32 adc_clock; - u32 vdec_clock; - u32 step_db,step_dr; - u64 tmp64; - u32 bdelay,agcdelay,htotal; - u32 cxiformat, cxoformat; - - core->tvnorm = norm; - fsc8 = norm_fsc8(norm); - adc_clock = xtal; - vdec_clock = fsc8; - step_db = fsc8; - step_dr = fsc8; - - if (norm & V4L2_STD_NTSC_M_JP) { - cxiformat = VideoFormatNTSCJapan; - cxoformat = 0x181f0008; - } else if (norm & V4L2_STD_NTSC_443) { - cxiformat = VideoFormatNTSC443; - cxoformat = 0x181f0008; - } else if (norm & V4L2_STD_PAL_M) { - cxiformat = VideoFormatPALM; - cxoformat = 0x1c1f0008; - } else if (norm & V4L2_STD_PAL_N) { - cxiformat = VideoFormatPALN; - cxoformat = 0x1c1f0008; - } else if (norm & V4L2_STD_PAL_Nc) { - cxiformat = VideoFormatPALNC; - cxoformat = 0x1c1f0008; - } else if (norm & V4L2_STD_PAL_60) { - cxiformat = VideoFormatPAL60; - cxoformat = 0x181f0008; - } else if (norm & V4L2_STD_NTSC) { - cxiformat = VideoFormatNTSC; - cxoformat = 0x181f0008; - } else if (norm & V4L2_STD_SECAM) { - step_db = 4250000 * 8; - step_dr = 4406250 * 8; - - cxiformat = VideoFormatSECAM; - cxoformat = 0x181f0008; - } else { /* PAL */ - cxiformat = VideoFormatPAL; - cxoformat = 0x181f0008; - } - - dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n", - v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock, - step_db, step_dr); - set_pll(core,2,vdec_clock); - - dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n", - cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f); - /* Chroma AGC must be disabled if SECAM is used, we enable it - by default on PAL and NTSC */ - cx_andor(MO_INPUT_FORMAT, 0x40f, - norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400); - - // FIXME: as-is from DScaler - dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n", - cxoformat, cx_read(MO_OUTPUT_FORMAT)); - cx_write(MO_OUTPUT_FORMAT, cxoformat); - - // MO_SCONV_REG = adc clock / video dec clock * 2^17 - tmp64 = adc_clock * (u64)(1 << 17); - do_div(tmp64, vdec_clock); - dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n", - (u32)tmp64, cx_read(MO_SCONV_REG)); - cx_write(MO_SCONV_REG, (u32)tmp64); - - // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22 - tmp64 = step_db * (u64)(1 << 22); - do_div(tmp64, vdec_clock); - dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n", - (u32)tmp64, cx_read(MO_SUB_STEP)); - cx_write(MO_SUB_STEP, (u32)tmp64); - - // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22 - tmp64 = step_dr * (u64)(1 << 22); - do_div(tmp64, vdec_clock); - dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n", - (u32)tmp64, cx_read(MO_SUB_STEP_DR)); - cx_write(MO_SUB_STEP_DR, (u32)tmp64); - - // bdelay + agcdelay - bdelay = vdec_clock * 65 / 20000000 + 21; - agcdelay = vdec_clock * 68 / 20000000 + 15; - dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n", - (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay); - cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay); - - // htotal - tmp64 = norm_htotal(norm) * (u64)vdec_clock; - do_div(tmp64, fsc8); - htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11); - dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n", - htotal, cx_read(MO_HTOTAL), (u32)tmp64); - cx_write(MO_HTOTAL, htotal); - - // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes - // the effective vbi offset ~244 samples, the same as the Bt8x8 - cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm)); - - // this is needed as well to set all tvnorm parameter - cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED); - - // audio - set_tvaudio(core); - - // tell i2c chips - call_all(core, core, s_std, norm); - - // done - return 0; -} - -/* ------------------------------------------------------------------ */ - -struct video_device *cx88_vdev_init(struct cx88_core *core, - struct pci_dev *pci, - const struct video_device *template_, - const char *type) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template_; - vfd->v4l2_dev = &core->v4l2_dev; - vfd->parent = &pci->dev; - vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - core->name, type, core->board.name); - return vfd; -} - -struct cx88_core* cx88_core_get(struct pci_dev *pci) -{ - struct cx88_core *core; - - mutex_lock(&devlist); - list_for_each_entry(core, &cx88_devlist, devlist) { - if (pci->bus->number != core->pci_bus) - continue; - if (PCI_SLOT(pci->devfn) != core->pci_slot) - continue; - - if (0 != cx88_get_resources(core, pci)) { - mutex_unlock(&devlist); - return NULL; - } - atomic_inc(&core->refcount); - mutex_unlock(&devlist); - return core; - } - - core = cx88_core_create(pci, cx88_devcount); - if (NULL != core) { - cx88_devcount++; - list_add_tail(&core->devlist, &cx88_devlist); - } - - mutex_unlock(&devlist); - return core; -} - -void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) -{ - release_mem_region(pci_resource_start(pci,0), - pci_resource_len(pci,0)); - - if (!atomic_dec_and_test(&core->refcount)) - return; - - mutex_lock(&devlist); - cx88_ir_fini(core); - if (0 == core->i2c_rc) { - if (core->i2c_rtc) - i2c_unregister_device(core->i2c_rtc); - i2c_del_adapter(&core->i2c_adap); - } - list_del(&core->devlist); - iounmap(core->lmmio); - cx88_devcount--; - mutex_unlock(&devlist); - v4l2_device_unregister(&core->v4l2_dev); - kfree(core); -} - -/* ------------------------------------------------------------------ */ - -EXPORT_SYMBOL(cx88_print_irqbits); - -EXPORT_SYMBOL(cx88_core_irq); -EXPORT_SYMBOL(cx88_wakeup); -EXPORT_SYMBOL(cx88_reset); -EXPORT_SYMBOL(cx88_shutdown); - -EXPORT_SYMBOL(cx88_risc_buffer); -EXPORT_SYMBOL(cx88_risc_databuffer); -EXPORT_SYMBOL(cx88_risc_stopper); -EXPORT_SYMBOL(cx88_free_buffer); - -EXPORT_SYMBOL(cx88_sram_channels); -EXPORT_SYMBOL(cx88_sram_channel_setup); -EXPORT_SYMBOL(cx88_sram_channel_dump); - -EXPORT_SYMBOL(cx88_set_tvnorm); -EXPORT_SYMBOL(cx88_set_scale); - -EXPORT_SYMBOL(cx88_vdev_init); -EXPORT_SYMBOL(cx88_core_get); -EXPORT_SYMBOL(cx88_core_put); - -EXPORT_SYMBOL(cx88_ir_start); -EXPORT_SYMBOL(cx88_ir_stop); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-dsp.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-dsp.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-dsp.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-dsp.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,322 +0,0 @@ -/* - * - * Stereo and SAP detection for cx88 - * - * Copyright (c) 2009 Marton Balint - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "cx88.h" -#include "cx88-reg.h" - -#define INT_PI ((s32)(3.141592653589 * 32768.0)) - -#define compat_remainder(a, b) \ - ((float)(((s32)((a)*100))%((s32)((b)*100)))/100.0) - -#define baseband_freq(carrier, srate, tone) ((s32)( \ - (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI)) - -/* We calculate the baseband frequencies of the carrier and the pilot tones - * based on the the sampling rate of the audio rds fifo. */ - -#define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0) -#define FREQ_A2_DUAL baseband_freq(54687.5, 2689.36, 274.1) -#define FREQ_A2_STEREO baseband_freq(54687.5, 2689.36, 117.5) - -/* The frequencies below are from the reference driver. They probably need - * further adjustments, because they are not tested at all. You may even need - * to play a bit with the registers of the chip to select the proper signal - * for the input of the audio rds fifo, and measure it's sampling rate to - * calculate the proper baseband frequencies... */ - -#define FREQ_A2M_CARRIER ((s32)(2.114516 * 32768.0)) -#define FREQ_A2M_DUAL ((s32)(2.754916 * 32768.0)) -#define FREQ_A2M_STEREO ((s32)(2.462326 * 32768.0)) - -#define FREQ_EIAJ_CARRIER ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ -#define FREQ_EIAJ_DUAL ((s32)(2.562118 * 32768.0)) -#define FREQ_EIAJ_STEREO ((s32)(2.601053 * 32768.0)) - -#define FREQ_BTSC_DUAL ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ -#define FREQ_BTSC_DUAL_REF ((s32)(1.374446 * 32768.0)) /* 7pi/16 */ - -#define FREQ_BTSC_SAP ((s32)(2.471532 * 32768.0)) -#define FREQ_BTSC_SAP_REF ((s32)(1.730072 * 32768.0)) - -/* The spectrum of the signal should be empty between these frequencies. */ -#define FREQ_NOISE_START ((s32)(0.100000 * 32768.0)) -#define FREQ_NOISE_END ((s32)(1.200000 * 32768.0)) - -static unsigned int dsp_debug; -module_param(dsp_debug, int, 0644); -MODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages"); - -#define dprintk(level, fmt, arg...) if (dsp_debug >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) - -static s32 int_cos(u32 x) -{ - u32 t2, t4, t6, t8; - s32 ret; - u16 period = x / INT_PI; - if (period % 2) - return -int_cos(x - INT_PI); - x = x % INT_PI; - if (x > INT_PI/2) - return -int_cos(INT_PI/2 - (x % (INT_PI/2))); - /* Now x is between 0 and INT_PI/2. - * To calculate cos(x) we use it's Taylor polinom. */ - t2 = x*x/32768/2; - t4 = t2*x/32768*x/32768/3/4; - t6 = t4*x/32768*x/32768/5/6; - t8 = t6*x/32768*x/32768/7/8; - ret = 32768-t2+t4-t6+t8; - return ret; -} - -static u32 int_goertzel(s16 x[], u32 N, u32 freq) -{ - /* We use the Goertzel algorithm to determine the power of the - * given frequency in the signal */ - s32 s_prev = 0; - s32 s_prev2 = 0; - s32 coeff = 2*int_cos(freq); - u32 i; - - u64 tmp; - u32 divisor; - - for (i = 0; i < N; i++) { - s32 s = x[i] + ((s64)coeff*s_prev/32768) - s_prev2; - s_prev2 = s_prev; - s_prev = s; - } - - tmp = (s64)s_prev2 * s_prev2 + (s64)s_prev * s_prev - - (s64)coeff * s_prev2 * s_prev / 32768; - - /* XXX: N must be low enough so that N*N fits in s32. - * Else we need two divisions. */ - divisor = N * N; - do_div(tmp, divisor); - - return (u32) tmp; -} - -static u32 freq_magnitude(s16 x[], u32 N, u32 freq) -{ - u32 sum = int_goertzel(x, N, freq); - return (u32)int_sqrt(sum); -} - -static u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end) -{ - int i; - u32 sum = 0; - u32 freq_step; - int samples = 5; - - if (N > 192) { - /* The last 192 samples are enough for noise detection */ - x += (N-192); - N = 192; - } - - freq_step = (freq_end - freq_start) / (samples - 1); - - for (i = 0; i < samples; i++) { - sum += int_goertzel(x, N, freq_start); - freq_start += freq_step; - } - - return (u32)int_sqrt(sum / samples); -} - -static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) -{ - s32 carrier, stereo, dual, noise; - s32 carrier_freq, stereo_freq, dual_freq; - s32 ret; - - switch (core->tvaudio) { - case WW_BG: - case WW_DK: - carrier_freq = FREQ_A2_CARRIER; - stereo_freq = FREQ_A2_STEREO; - dual_freq = FREQ_A2_DUAL; - break; - case WW_M: - carrier_freq = FREQ_A2M_CARRIER; - stereo_freq = FREQ_A2M_STEREO; - dual_freq = FREQ_A2M_DUAL; - break; - case WW_EIAJ: - carrier_freq = FREQ_EIAJ_CARRIER; - stereo_freq = FREQ_EIAJ_STEREO; - dual_freq = FREQ_EIAJ_DUAL; - break; - default: - printk(KERN_WARNING "%s/0: unsupported audio mode %d for %s\n", - core->name, core->tvaudio, __func__); - return UNSET; - } - - carrier = freq_magnitude(x, N, carrier_freq); - stereo = freq_magnitude(x, N, stereo_freq); - dual = freq_magnitude(x, N, dual_freq); - noise = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END); - - dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, " - "noise=%d\n", carrier, stereo, dual, noise); - - if (stereo > dual) - ret = V4L2_TUNER_SUB_STEREO; - else - ret = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - - if (core->tvaudio == WW_EIAJ) { - /* EIAJ checks may need adjustments */ - if ((carrier > max(stereo, dual)*2) && - (carrier < max(stereo, dual)*6) && - (carrier > 20 && carrier < 200) && - (max(stereo, dual) > min(stereo, dual))) { - /* For EIAJ the carrier is always present, - so we probably don't need noise detection */ - return ret; - } - } else { - if ((carrier > max(stereo, dual)*2) && - (carrier < max(stereo, dual)*8) && - (carrier > 20 && carrier < 200) && - (noise < 10) && - (max(stereo, dual) > min(stereo, dual)*2)) { - return ret; - } - } - return V4L2_TUNER_SUB_MONO; -} - -static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N) -{ - s32 sap_ref = freq_magnitude(x, N, FREQ_BTSC_SAP_REF); - s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP); - s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF); - s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL); - dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d" - "\n", dual_ref, dual, sap_ref, sap); - /* FIXME: Currently not supported */ - return UNSET; -} - -static s16 *read_rds_samples(struct cx88_core *core, u32 *N) -{ - const struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27]; - s16 *samples; - - unsigned int i; - unsigned int bpl = srch->fifo_size/AUD_RDS_LINES; - unsigned int spl = bpl/4; - unsigned int sample_count = spl*(AUD_RDS_LINES-1); - - u32 current_address = cx_read(srch->ptr1_reg); - u32 offset = (current_address - srch->fifo_start + bpl); - - dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), " - "sample_count=%d, aud_intstat=%08x\n", current_address, - current_address - srch->fifo_start, sample_count, - cx_read(MO_AUD_INTSTAT)); - - samples = kmalloc(sizeof(s16)*sample_count, GFP_KERNEL); - if (!samples) - return NULL; - - *N = sample_count; - - for (i = 0; i < sample_count; i++) { - offset = offset % (AUD_RDS_LINES*bpl); - samples[i] = cx_read(srch->fifo_start + offset); - offset += 4; - } - - if (dsp_debug >= 2) { - dprintk(2, "RDS samples dump: "); - for (i = 0; i < sample_count; i++) - printk("%hd ", samples[i]); - printk(".\n"); - } - - return samples; -} - -s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core) -{ - s16 *samples; - u32 N = 0; - s32 ret = UNSET; - - /* If audio RDS fifo is disabled, we can't read the samples */ - if (!(cx_read(MO_AUD_DMACNTRL) & 0x04)) - return ret; - if (!(cx_read(AUD_CTL) & EN_FMRADIO_EN_RDS)) - return ret; - - /* Wait at least 500 ms after an audio standard change */ - if (time_before(jiffies, core->last_change + msecs_to_jiffies(500))) - return ret; - - samples = read_rds_samples(core, &N); - - if (!samples) - return ret; - - switch (core->tvaudio) { - case WW_BG: - case WW_DK: - case WW_EIAJ: - case WW_M: - ret = detect_a2_a2m_eiaj(core, samples, N); - break; - case WW_BTSC: - ret = detect_btsc(core, samples, N); - break; - case WW_NONE: - case WW_I: - case WW_L: - case WW_I2SPT: - case WW_FM: - case WW_I2SADC: - break; - } - - kfree(samples); - - if (UNSET != ret) - dprintk(1, "stereo/sap detection result:%s%s%s\n", - (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "", - (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", - (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : ""); - - return ret; -} -EXPORT_SYMBOL(cx88_dsp_detect_stereo_sap); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-dvb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1717 +0,0 @@ -/* - * - * device driver for Conexant 2388x based TV cards - * MPEG Transport Stream (DVB) routines - * - * (c) 2004, 2005 Chris Pascoe - * (c) 2004 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "cx88.h" -#include "dvb-pll.h" -#include - -#include "mt352.h" -#include "mt352_priv.h" -#include "cx88-vp3054-i2c.h" -#include "zl10353.h" -#include "cx22702.h" -#include "or51132.h" -#include "lgdt330x.h" -#include "s5h1409.h" -#include "xc5000.h" -#include "nxt200x.h" -#include "cx24123.h" -#include "isl6421.h" -#include "tuner-simple.h" -#include "tda9887.h" -#include "s5h1411.h" -#include "stv0299.h" -#include "z0194a.h" -#include "stv0288.h" -#include "stb6000.h" -#include "cx24116.h" -#include "stv0900.h" -#include "stb6100.h" -#include "stb6100_proc.h" -#include "mb86a16.h" -#include "ds3000.h" - -MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); -MODULE_AUTHOR("Chris Pascoe "); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [dvb]"); - -static unsigned int dvb_buf_tscnt = 32; -module_param(dvb_buf_tscnt, int, 0644); -MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg) - -/* ------------------------------------------------------------------ */ - -static int dvb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) -{ - struct cx8802_dev *dev = q->priv_data; - - dev->ts_packet_size = 188 * 4; - dev->ts_packet_count = dvb_buf_tscnt; - - *size = dev->ts_packet_size * dev->ts_packet_count; - *count = dvb_buf_tscnt; - return 0; -} - -static int dvb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct cx8802_dev *dev = q->priv_data; - return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field); -} - -static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct cx8802_dev *dev = q->priv_data; - cx8802_buf_queue(dev, (struct cx88_buffer*)vb); -} - -static void dvb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - cx88_free_buffer(q, (struct cx88_buffer*)vb); -} - -static const struct videobuf_queue_ops dvb_qops = { - .buf_setup = dvb_buf_setup, - .buf_prepare = dvb_buf_prepare, - .buf_queue = dvb_buf_queue, - .buf_release = dvb_buf_release, -}; - -/* ------------------------------------------------------------------ */ - -static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) -{ - struct cx8802_dev *dev= fe->dvb->priv; - struct cx8802_driver *drv = NULL; - int ret = 0; - int fe_id; - - fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe); - if (!fe_id) { - printk(KERN_ERR "%s() No frontend found\n", __func__); - return -EINVAL; - } - - drv = cx8802_get_driver(dev, CX88_MPEG_DVB); - if (drv) { - if (acquire){ - dev->frontends.active_fe_id = fe_id; - ret = drv->request_acquire(drv); - } else { - ret = drv->request_release(drv); - dev->frontends.active_fe_id = 0; - } - } - - return ret; -} - -static void cx88_dvb_gate_ctrl(struct cx88_core *core, int open) -{ - struct videobuf_dvb_frontends *f; - struct videobuf_dvb_frontend *fe; - - if (!core->dvbdev) - return; - - f = &core->dvbdev->frontends; - - if (!f) - return; - - if (f->gate <= 1) /* undefined or fe0 */ - fe = videobuf_dvb_get_frontend(f, 1); - else - fe = videobuf_dvb_get_frontend(f, f->gate); - - if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) - fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); -} - -/* ------------------------------------------------------------------ */ - -static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe) -{ - static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 }; - static const u8 reset [] = { RESET, 0x80 }; - static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static const u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; - static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; - static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - return 0; -} - -static int dvico_dual_demod_init(struct dvb_frontend *fe) -{ - static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 }; - static const u8 reset [] = { RESET, 0x80 }; - static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static const u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; - static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; - static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - - return 0; -} - -static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe) -{ - static const u8 clock_config [] = { 0x89, 0x38, 0x39 }; - static const u8 reset [] = { 0x50, 0x80 }; - static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static const u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, - 0x00, 0xFF, 0x00, 0x40, 0x40 }; - static const u8 dntv_extra[] = { 0xB5, 0x7A }; - static const u8 capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(2000); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - udelay(2000); - mt352_write(fe, dntv_extra, sizeof(dntv_extra)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - - return 0; -} - -static const struct mt352_config dvico_fusionhdtv = { - .demod_address = 0x0f, - .demod_init = dvico_fusionhdtv_demod_init, -}; - -static const struct mt352_config dntv_live_dvbt_config = { - .demod_address = 0x0f, - .demod_init = dntv_live_dvbt_demod_init, -}; - -static const struct mt352_config dvico_fusionhdtv_dual = { - .demod_address = 0x0f, - .demod_init = dvico_dual_demod_init, -}; - -static const struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, - .if2 = 45600, -}; - -static struct mb86a16_config twinhan_vp1027 = { - .demod_address = 0x08, -}; - -#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) -static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe) -{ - static const u8 clock_config [] = { 0x89, 0x38, 0x38 }; - static const u8 reset [] = { 0x50, 0x80 }; - static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static const u8 agc_cfg [] = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF, - 0x00, 0xFF, 0x00, 0x40, 0x40 }; - static const u8 dntv_extra[] = { 0xB5, 0x7A }; - static const u8 capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(2000); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - udelay(2000); - mt352_write(fe, dntv_extra, sizeof(dntv_extra)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - - return 0; -} - -static const struct mt352_config dntv_live_dvbt_pro_config = { - .demod_address = 0x0f, - .no_tuner = 1, - .demod_init = dntv_live_dvbt_pro_demod_init, -}; -#endif - -static const struct zl10353_config dvico_fusionhdtv_hybrid = { - .demod_address = 0x0f, - .no_tuner = 1, -}; - -static const struct zl10353_config dvico_fusionhdtv_xc3028 = { - .demod_address = 0x0f, - .if2 = 45600, - .no_tuner = 1, -}; - -static const struct mt352_config dvico_fusionhdtv_mt352_xc3028 = { - .demod_address = 0x0f, - .if2 = 4560, - .no_tuner = 1, - .demod_init = dvico_fusionhdtv_demod_init, -}; - -static const struct zl10353_config dvico_fusionhdtv_plus_v1_1 = { - .demod_address = 0x0f, -}; - -static const struct cx22702_config connexant_refboard_config = { - .demod_address = 0x43, - .output_mode = CX22702_SERIAL_OUTPUT, -}; - -static const struct cx22702_config hauppauge_hvr_config = { - .demod_address = 0x63, - .output_mode = CX22702_SERIAL_OUTPUT, -}; - -static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) -{ - struct cx8802_dev *dev= fe->dvb->priv; - dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; - return 0; -} - -static const struct or51132_config pchdtv_hd3000 = { - .demod_address = 0x15, - .set_ts_params = or51132_set_ts_param, -}; - -static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index) -{ - struct cx8802_dev *dev= fe->dvb->priv; - struct cx88_core *core = dev->core; - - dprintk(1, "%s: index = %d\n", __func__, index); - if (index == 0) - cx_clear(MO_GP0_IO, 8); - else - cx_set(MO_GP0_IO, 8); - return 0; -} - -static int lgdt330x_set_ts_param(struct dvb_frontend* fe, int is_punctured) -{ - struct cx8802_dev *dev= fe->dvb->priv; - if (is_punctured) - dev->ts_gen_cntrl |= 0x04; - else - dev->ts_gen_cntrl &= ~0x04; - return 0; -} - -static struct lgdt330x_config fusionhdtv_3_gold = { - .demod_address = 0x0e, - .demod_chip = LGDT3302, - .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */ - .set_ts_params = lgdt330x_set_ts_param, -}; - -static const struct lgdt330x_config fusionhdtv_5_gold = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, - .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ - .set_ts_params = lgdt330x_set_ts_param, -}; - -static const struct lgdt330x_config pchdtv_hd5500 = { - .demod_address = 0x59, - .demod_chip = LGDT3303, - .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ - .set_ts_params = lgdt330x_set_ts_param, -}; - -static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured) -{ - struct cx8802_dev *dev= fe->dvb->priv; - dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; - return 0; -} - -static const struct nxt200x_config ati_hdtvwonder = { - .demod_address = 0x0a, - .set_ts_params = nxt200x_set_ts_param, -}; - -static int cx24123_set_ts_param(struct dvb_frontend* fe, - int is_punctured) -{ - struct cx8802_dev *dev= fe->dvb->priv; - dev->ts_gen_cntrl = 0x02; - return 0; -} - -static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, - fe_sec_voltage_t voltage) -{ - struct cx8802_dev *dev= fe->dvb->priv; - struct cx88_core *core = dev->core; - - if (voltage == SEC_VOLTAGE_OFF) - cx_write(MO_GP0_IO, 0x000006fb); - else - cx_write(MO_GP0_IO, 0x000006f9); - - if (core->prev_set_voltage) - return core->prev_set_voltage(fe, voltage); - return 0; -} - -static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct cx8802_dev *dev= fe->dvb->priv; - struct cx88_core *core = dev->core; - - if (voltage == SEC_VOLTAGE_OFF) { - dprintk(1,"LNB Voltage OFF\n"); - cx_write(MO_GP0_IO, 0x0000efff); - } - - if (core->prev_set_voltage) - return core->prev_set_voltage(fe, voltage); - return 0; -} - -static int tevii_dvbs_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct cx8802_dev *dev= fe->dvb->priv; - struct cx88_core *core = dev->core; - - cx_set(MO_GP0_IO, 0x6040); - switch (voltage) { - case SEC_VOLTAGE_13: - cx_clear(MO_GP0_IO, 0x20); - break; - case SEC_VOLTAGE_18: - cx_set(MO_GP0_IO, 0x20); - break; - case SEC_VOLTAGE_OFF: - cx_clear(MO_GP0_IO, 0x20); - break; - } - - if (core->prev_set_voltage) - return core->prev_set_voltage(fe, voltage); - return 0; -} - -static int vp1027_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct cx8802_dev *dev = fe->dvb->priv; - struct cx88_core *core = dev->core; - - switch (voltage) { - case SEC_VOLTAGE_13: - dprintk(1, "LNB SEC Voltage=13\n"); - cx_write(MO_GP0_IO, 0x00001220); - break; - case SEC_VOLTAGE_18: - dprintk(1, "LNB SEC Voltage=18\n"); - cx_write(MO_GP0_IO, 0x00001222); - break; - case SEC_VOLTAGE_OFF: - dprintk(1, "LNB Voltage OFF\n"); - cx_write(MO_GP0_IO, 0x00001230); - break; - } - - if (core->prev_set_voltage) - return core->prev_set_voltage(fe, voltage); - return 0; -} - -static const struct cx24123_config geniatech_dvbs_config = { - .demod_address = 0x55, - .set_ts_params = cx24123_set_ts_param, -}; - -static const struct cx24123_config hauppauge_novas_config = { - .demod_address = 0x55, - .set_ts_params = cx24123_set_ts_param, -}; - -static const struct cx24123_config kworld_dvbs_100_config = { - .demod_address = 0x15, - .set_ts_params = cx24123_set_ts_param, - .lnb_polarity = 1, -}; - -static const struct s5h1409_config pinnacle_pctv_hd_800i_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_PARALLEL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, -}; - -static const struct s5h1409_config dvico_hdtv5_pci_nano_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_OFF, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static const struct s5h1409_config kworld_atsc_120_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_OFF, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { - .i2c_address = 0x64, - .if_khz = 5380, -}; - -static const struct zl10353_config cx88_pinnacle_hybrid_pctv = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, - .if2 = 45600, -}; - -static const struct zl10353_config cx88_geniatech_x8000_mt = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, - .disable_i2c_gate_ctrl = 1, -}; - -static const struct s5h1411_config dvico_fusionhdtv7_config = { - .output_mode = S5H1411_SERIAL_OUTPUT, - .gpio = S5H1411_GPIO_ON, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, - .qam_if = S5H1411_IF_44000, - .vsb_if = S5H1411_IF_44000, - .inversion = S5H1411_INVERSION_OFF, - .status_mode = S5H1411_DEMODLOCKING -}; - -static const struct xc5000_config dvico_fusionhdtv7_tuner_config = { - .i2c_address = 0xc2 >> 1, - .if_khz = 5380, -}; - -static int attach_xc3028(u8 addr, struct cx8802_dev *dev) -{ - struct dvb_frontend *fe; - struct videobuf_dvb_frontend *fe0 = NULL; - struct xc2028_ctrl ctl; - struct xc2028_config cfg = { - .i2c_adap = &dev->core->i2c_adap, - .i2c_addr = addr, - .ctrl = &ctl, - }; - - /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); - if (!fe0) - return -EINVAL; - - if (!fe0->dvb.frontend) { - printk(KERN_ERR "%s/2: dvb frontend not attached. " - "Can't attach xc3028\n", - dev->core->name); - return -EINVAL; - } - - /* - * Some xc3028 devices may be hidden by an I2C gate. This is known - * to happen with some s5h1409-based devices. - * Now that I2C gate is open, sets up xc3028 configuration - */ - cx88_setup_xc3028(dev->core, &ctl); - - fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); - if (!fe) { - printk(KERN_ERR "%s/2: xc3028 attach failed\n", - dev->core->name); - dvb_frontend_detach(fe0->dvb.frontend); - dvb_unregister_frontend(fe0->dvb.frontend); - fe0->dvb.frontend = NULL; - return -EINVAL; - } - - printk(KERN_INFO "%s/2: xc3028 attached\n", - dev->core->name); - - return 0; -} - -static int cx24116_set_ts_param(struct dvb_frontend *fe, - int is_punctured) -{ - struct cx8802_dev *dev = fe->dvb->priv; - dev->ts_gen_cntrl = 0x2; - - return 0; -} - -static int stv0900_set_ts_param(struct dvb_frontend *fe, - int is_punctured) -{ - struct cx8802_dev *dev = fe->dvb->priv; - dev->ts_gen_cntrl = 0; - - return 0; -} - -static int cx24116_reset_device(struct dvb_frontend *fe) -{ - struct cx8802_dev *dev = fe->dvb->priv; - struct cx88_core *core = dev->core; - - /* Reset the part */ - /* Put the cx24116 into reset */ - cx_write(MO_SRST_IO, 0); - msleep(10); - /* Take the cx24116 out of reset */ - cx_write(MO_SRST_IO, 1); - msleep(10); - - return 0; -} - -static const struct cx24116_config hauppauge_hvr4000_config = { - .demod_address = 0x05, - .set_ts_params = cx24116_set_ts_param, - .reset_device = cx24116_reset_device, -}; - -static const struct cx24116_config tevii_s460_config = { - .demod_address = 0x55, - .set_ts_params = cx24116_set_ts_param, - .reset_device = cx24116_reset_device, -}; - -static int ds3000_set_ts_param(struct dvb_frontend *fe, - int is_punctured) -{ - struct cx8802_dev *dev = fe->dvb->priv; - dev->ts_gen_cntrl = 4; - - return 0; -} - -static struct ds3000_config tevii_ds3000_config = { - .demod_address = 0x68, - .set_ts_params = ds3000_set_ts_param, -}; - -static const struct stv0900_config prof_7301_stv0900_config = { - .demod_address = 0x6a, -/* demod_mode = 0,*/ - .xtal = 27000000, - .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ - .diseqc_mode = 2,/* 2/3 PWM */ - .tun1_maddress = 0,/* 0x60 */ - .tun1_adc = 0,/* 2 Vpp */ - .path1_mode = 3, - .set_ts_params = stv0900_set_ts_param, -}; - -static const struct stb6100_config prof_7301_stb6100_config = { - .tuner_address = 0x60, - .refclock = 27000000, -}; - -static const struct stv0299_config tevii_tuner_sharp_config = { - .demod_address = 0x68, - .inittab = sharp_z0194a_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = 1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a_set_symbol_rate, - .set_ts_params = cx24116_set_ts_param, -}; - -static const struct stv0288_config tevii_tuner_earda_config = { - .demod_address = 0x68, - .min_delay_ms = 100, - .set_ts_params = cx24116_set_ts_param, -}; - -static int cx8802_alloc_frontends(struct cx8802_dev *dev) -{ - struct cx88_core *core = dev->core; - struct videobuf_dvb_frontend *fe = NULL; - int i; - - mutex_init(&dev->frontends.lock); - INIT_LIST_HEAD(&dev->frontends.felist); - - if (!core->board.num_frontends) - return -ENODEV; - - printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, - core->board.num_frontends); - for (i = 1; i <= core->board.num_frontends; i++) { - fe = videobuf_dvb_alloc_frontend(&dev->frontends, i); - if (!fe) { - printk(KERN_ERR "%s() failed to alloc\n", __func__); - videobuf_dvb_dealloc_frontends(&dev->frontends); - return -ENOMEM; - } - } - return 0; -} - - - -static const u8 samsung_smt_7020_inittab[] = { - 0x01, 0x15, - 0x02, 0x00, - 0x03, 0x00, - 0x04, 0x7D, - 0x05, 0x0F, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0x60, - - 0x0A, 0xC2, - 0x0B, 0x00, - 0x0C, 0x01, - 0x0D, 0x81, - 0x0E, 0x44, - 0x0F, 0x09, - 0x10, 0x3C, - 0x11, 0x84, - 0x12, 0xDA, - 0x13, 0x99, - 0x14, 0x8D, - 0x15, 0xCE, - 0x16, 0xE8, - 0x17, 0x43, - 0x18, 0x1C, - 0x19, 0x1B, - 0x1A, 0x1D, - - 0x1C, 0x12, - 0x1D, 0x00, - 0x1E, 0x00, - 0x1F, 0x00, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - - 0x28, 0x02, - 0x29, 0x28, - 0x2A, 0x14, - 0x2B, 0x0F, - 0x2C, 0x09, - 0x2D, 0x05, - - 0x31, 0x1F, - 0x32, 0x19, - 0x33, 0xFC, - 0x34, 0x13, - 0xff, 0xff, -}; - - -static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct cx8802_dev *dev = fe->dvb->priv; - u8 buf[4]; - u32 div; - struct i2c_msg msg = { - .addr = 0x61, - .flags = 0, - .buf = buf, - .len = sizeof(buf) }; - - div = params->frequency / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x84; /* 0xC4 */ - buf[3] = 0x00; - - if (params->frequency < 1500000) - buf[3] |= 0x10; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(&dev->core->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static int samsung_smt_7020_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t tone) -{ - struct cx8802_dev *dev = fe->dvb->priv; - struct cx88_core *core = dev->core; - - cx_set(MO_GP0_IO, 0x0800); - - switch (tone) { - case SEC_TONE_ON: - cx_set(MO_GP0_IO, 0x08); - break; - case SEC_TONE_OFF: - cx_clear(MO_GP0_IO, 0x08); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct cx8802_dev *dev = fe->dvb->priv; - struct cx88_core *core = dev->core; - - u8 data; - struct i2c_msg msg = { - .addr = 8, - .flags = 0, - .buf = &data, - .len = sizeof(data) }; - - cx_set(MO_GP0_IO, 0x8000); - - switch (voltage) { - case SEC_VOLTAGE_OFF: - break; - case SEC_VOLTAGE_13: - data = ISL6421_EN1 | ISL6421_LLC1; - cx_clear(MO_GP0_IO, 0x80); - break; - case SEC_VOLTAGE_18: - data = ISL6421_EN1 | ISL6421_LLC1 | ISL6421_VSEL1; - cx_clear(MO_GP0_IO, 0x80); - break; - default: - return -EINVAL; - }; - - return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO; -} - -static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { - aclk = 0xb7; - bclk = 0x47; - } else if (srate < 3000000) { - aclk = 0xb7; - bclk = 0x4b; - } else if (srate < 7000000) { - aclk = 0xb7; - bclk = 0x4f; - } else if (srate < 14000000) { - aclk = 0xb7; - bclk = 0x53; - } else if (srate < 30000000) { - aclk = 0xb6; - bclk = 0x53; - } else if (srate < 45000000) { - aclk = 0xb4; - bclk = 0x51; - } - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, ratio & 0xf0); - - return 0; -} - - -static const struct stv0299_config samsung_stv0299_config = { - .demod_address = 0x68, - .inittab = samsung_smt_7020_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_LK, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate, -}; - -static int dvb_register(struct cx8802_dev *dev) -{ - struct cx88_core *core = dev->core; - struct videobuf_dvb_frontend *fe0, *fe1 = NULL; - int mfe_shared = 0; /* bus not shared by default */ - - if (0 != core->i2c_rc) { - printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); - goto frontend_detach; - } - - /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); - if (!fe0) - goto frontend_detach; - - /* multi-frontend gate control is undefined or defaults to fe0 */ - dev->frontends.gate = 0; - - /* Sets the gate control callback to be used by i2c command calls */ - core->gate_ctrl = cx88_dvb_gate_ctrl; - - /* init frontend(s) */ - switch (core->boardnr) { - case CX88_BOARD_HAUPPAUGE_DVB_T1: - fe0->dvb.frontend = dvb_attach(cx22702_attach, - &connexant_refboard_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, - 0x61, &core->i2c_adap, - DVB_PLL_THOMSON_DTT759X)) - goto frontend_detach; - } - break; - case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: - case CX88_BOARD_CONEXANT_DVB_T1: - case CX88_BOARD_KWORLD_DVB_T_CX22702: - case CX88_BOARD_WINFAST_DTV1000: - fe0->dvb.frontend = dvb_attach(cx22702_attach, - &connexant_refboard_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, - 0x60, &core->i2c_adap, - DVB_PLL_THOMSON_DTT7579)) - goto frontend_detach; - } - break; - case CX88_BOARD_WINFAST_DTV2000H: - case CX88_BOARD_WINFAST_DTV2000H_J: - case CX88_BOARD_HAUPPAUGE_HVR1100: - case CX88_BOARD_HAUPPAUGE_HVR1100LP: - case CX88_BOARD_HAUPPAUGE_HVR1300: - fe0->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3)) - goto frontend_detach; - } - break; - case CX88_BOARD_HAUPPAUGE_HVR3000: - /* MFE frontend 1 */ - mfe_shared = 1; - dev->frontends.gate = 2; - /* DVB-S init */ - fe0->dvb.frontend = dvb_attach(cx24123_attach, - &hauppauge_novas_config, - &dev->core->i2c_adap); - if (fe0->dvb.frontend) { - if (!dvb_attach(isl6421_attach, - fe0->dvb.frontend, - &dev->core->i2c_adap, - 0x08, ISL6421_DCL, 0x00)) - goto frontend_detach; - } - /* MFE frontend 2 */ - fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); - if (!fe1) - goto frontend_detach; - /* DVB-T init */ - fe1->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr_config, - &dev->core->i2c_adap); - if (fe1->dvb.frontend) { - fe1->dvb.frontend->id = 1; - if (!dvb_attach(simple_tuner_attach, - fe1->dvb.frontend, - &dev->core->i2c_adap, - 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) - goto frontend_detach; - } - break; - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: - fe0->dvb.frontend = dvb_attach(mt352_attach, - &dvico_fusionhdtv, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, - 0x60, NULL, DVB_PLL_THOMSON_DTT7579)) - goto frontend_detach; - break; - } - /* ZL10353 replaces MT352 on later cards */ - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &dvico_fusionhdtv_plus_v1_1, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, - 0x60, NULL, DVB_PLL_THOMSON_DTT7579)) - goto frontend_detach; - } - break; - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: - /* The tin box says DEE1601, but it seems to be DTT7579 - * compatible, with a slightly different MT352 AGC gain. */ - fe0->dvb.frontend = dvb_attach(mt352_attach, - &dvico_fusionhdtv_dual, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, - 0x61, NULL, DVB_PLL_THOMSON_DTT7579)) - goto frontend_detach; - break; - } - /* ZL10353 replaces MT352 on later cards */ - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &dvico_fusionhdtv_plus_v1_1, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, - 0x61, NULL, DVB_PLL_THOMSON_DTT7579)) - goto frontend_detach; - } - break; - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: - fe0->dvb.frontend = dvb_attach(mt352_attach, - &dvico_fusionhdtv, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, - 0x61, NULL, DVB_PLL_LG_Z201)) - goto frontend_detach; - } - break; - case CX88_BOARD_KWORLD_DVB_T: - case CX88_BOARD_DNTV_LIVE_DVB_T: - case CX88_BOARD_ADSTECH_DVB_T_PCI: - fe0->dvb.frontend = dvb_attach(mt352_attach, - &dntv_live_dvbt_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, - 0x61, NULL, DVB_PLL_UNKNOWN_1)) - goto frontend_detach; - } - break; - case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: -#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) - /* MT352 is on a secondary I2C bus made from some GPIO lines */ - fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config, - &dev->vp3054->adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3)) - goto frontend_detach; - } -#else - printk(KERN_ERR "%s/2: built without vp3054 support\n", - core->name); -#endif - break; - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &dvico_fusionhdtv_hybrid, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_THOMSON_FE6600)) - goto frontend_detach; - } - break; - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &dvico_fusionhdtv_xc3028, - &core->i2c_adap); - if (fe0->dvb.frontend == NULL) - fe0->dvb.frontend = dvb_attach(mt352_attach, - &dvico_fusionhdtv_mt352_xc3028, - &core->i2c_adap); - /* - * On this board, the demod provides the I2C bus pullup. - * We must not permit gate_ctrl to be performed, or - * the xc3028 cannot communicate on the bus. - */ - if (fe0->dvb.frontend) - fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; - if (attach_xc3028(0x61, dev) < 0) - goto frontend_detach; - break; - case CX88_BOARD_PCHDTV_HD3000: - fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_THOMSON_DTT761X)) - goto frontend_detach; - } - break; - case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: - dev->ts_gen_cntrl = 0x08; - - /* Do a hardware reset of chip before using it. */ - cx_clear(MO_GP0_IO, 1); - mdelay(100); - cx_set(MO_GP0_IO, 1); - mdelay(200); - - /* Select RF connector callback */ - fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set; - fe0->dvb.frontend = dvb_attach(lgdt330x_attach, - &fusionhdtv_3_gold, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_MICROTUNE_4042FI5)) - goto frontend_detach; - } - break; - case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: - dev->ts_gen_cntrl = 0x08; - - /* Do a hardware reset of chip before using it. */ - cx_clear(MO_GP0_IO, 1); - mdelay(100); - cx_set(MO_GP0_IO, 9); - mdelay(200); - fe0->dvb.frontend = dvb_attach(lgdt330x_attach, - &fusionhdtv_3_gold, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_THOMSON_DTT761X)) - goto frontend_detach; - } - break; - case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: - dev->ts_gen_cntrl = 0x08; - - /* Do a hardware reset of chip before using it. */ - cx_clear(MO_GP0_IO, 1); - mdelay(100); - cx_set(MO_GP0_IO, 1); - mdelay(200); - fe0->dvb.frontend = dvb_attach(lgdt330x_attach, - &fusionhdtv_5_gold, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_LG_TDVS_H06XF)) - goto frontend_detach; - if (!dvb_attach(tda9887_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x43)) - goto frontend_detach; - } - break; - case CX88_BOARD_PCHDTV_HD5500: - dev->ts_gen_cntrl = 0x08; - - /* Do a hardware reset of chip before using it. */ - cx_clear(MO_GP0_IO, 1); - mdelay(100); - cx_set(MO_GP0_IO, 1); - mdelay(200); - fe0->dvb.frontend = dvb_attach(lgdt330x_attach, - &pchdtv_hd5500, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_LG_TDVS_H06XF)) - goto frontend_detach; - if (!dvb_attach(tda9887_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x43)) - goto frontend_detach; - } - break; - case CX88_BOARD_ATI_HDTVWONDER: - fe0->dvb.frontend = dvb_attach(nxt200x_attach, - &ati_hdtvwonder, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_PHILIPS_TUV1236D)) - goto frontend_detach; - } - break; - case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: - case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: - fe0->dvb.frontend = dvb_attach(cx24123_attach, - &hauppauge_novas_config, - &core->i2c_adap); - if (fe0->dvb.frontend) { - if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) - goto frontend_detach; - } - break; - case CX88_BOARD_KWORLD_DVBS_100: - fe0->dvb.frontend = dvb_attach(cx24123_attach, - &kworld_dvbs_100_config, - &core->i2c_adap); - if (fe0->dvb.frontend) { - core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; - fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage; - } - break; - case CX88_BOARD_GENIATECH_DVBS: - fe0->dvb.frontend = dvb_attach(cx24123_attach, - &geniatech_dvbs_config, - &core->i2c_adap); - if (fe0->dvb.frontend) { - core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; - fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; - } - break; - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - fe0->dvb.frontend = dvb_attach(s5h1409_attach, - &pinnacle_pctv_hd_800i_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(xc5000_attach, fe0->dvb.frontend, - &core->i2c_adap, - &pinnacle_pctv_hd_800i_tuner_config)) - goto frontend_detach; - } - break; - case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: - fe0->dvb.frontend = dvb_attach(s5h1409_attach, - &dvico_hdtv5_pci_nano_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &core->i2c_adap, - .i2c_addr = 0x61, - }; - static struct xc2028_ctrl ctl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .scode_table = XC3028_FE_OREN538, - }; - - fe = dvb_attach(xc2028_attach, - fe0->dvb.frontend, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctl); - } - break; - case CX88_BOARD_PINNACLE_HYBRID_PCTV: - case CX88_BOARD_WINFAST_DTV1800H: - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &cx88_pinnacle_hybrid_pctv, - &core->i2c_adap); - if (fe0->dvb.frontend) { - fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; - if (attach_xc3028(0x61, dev) < 0) - goto frontend_detach; - } - break; - case CX88_BOARD_GENIATECH_X8000_MT: - dev->ts_gen_cntrl = 0x00; - - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &cx88_geniatech_x8000_mt, - &core->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) - goto frontend_detach; - break; - case CX88_BOARD_KWORLD_ATSC_120: - fe0->dvb.frontend = dvb_attach(s5h1409_attach, - &kworld_atsc_120_config, - &core->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) - goto frontend_detach; - break; - case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: - fe0->dvb.frontend = dvb_attach(s5h1411_attach, - &dvico_fusionhdtv7_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(xc5000_attach, fe0->dvb.frontend, - &core->i2c_adap, - &dvico_fusionhdtv7_tuner_config)) - goto frontend_detach; - } - break; - case CX88_BOARD_HAUPPAUGE_HVR4000: - /* MFE frontend 1 */ - mfe_shared = 1; - dev->frontends.gate = 2; - /* DVB-S/S2 Init */ - fe0->dvb.frontend = dvb_attach(cx24116_attach, - &hauppauge_hvr4000_config, - &dev->core->i2c_adap); - if (fe0->dvb.frontend) { - if (!dvb_attach(isl6421_attach, - fe0->dvb.frontend, - &dev->core->i2c_adap, - 0x08, ISL6421_DCL, 0x00)) - goto frontend_detach; - } - /* MFE frontend 2 */ - fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); - if (!fe1) - goto frontend_detach; - /* DVB-T Init */ - fe1->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr_config, - &dev->core->i2c_adap); - if (fe1->dvb.frontend) { - fe1->dvb.frontend->id = 1; - if (!dvb_attach(simple_tuner_attach, - fe1->dvb.frontend, - &dev->core->i2c_adap, - 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) - goto frontend_detach; - } - break; - case CX88_BOARD_HAUPPAUGE_HVR4000LITE: - fe0->dvb.frontend = dvb_attach(cx24116_attach, - &hauppauge_hvr4000_config, - &dev->core->i2c_adap); - if (fe0->dvb.frontend) { - if (!dvb_attach(isl6421_attach, - fe0->dvb.frontend, - &dev->core->i2c_adap, - 0x08, ISL6421_DCL, 0x00)) - goto frontend_detach; - } - break; - case CX88_BOARD_PROF_6200: - case CX88_BOARD_TBS_8910: - case CX88_BOARD_TEVII_S420: - fe0->dvb.frontend = dvb_attach(stv0299_attach, - &tevii_tuner_sharp_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, - &core->i2c_adap, DVB_PLL_OPERA1)) - goto frontend_detach; - core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; - fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; - - } else { - fe0->dvb.frontend = dvb_attach(stv0288_attach, - &tevii_tuner_earda_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61, - &core->i2c_adap)) - goto frontend_detach; - core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; - fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; - } - } - break; - case CX88_BOARD_TEVII_S460: - fe0->dvb.frontend = dvb_attach(cx24116_attach, - &tevii_s460_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) - fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; - break; - case CX88_BOARD_TEVII_S464: - fe0->dvb.frontend = dvb_attach(ds3000_attach, - &tevii_ds3000_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) - fe0->dvb.frontend->ops.set_voltage = - tevii_dvbs_set_voltage; - break; - case CX88_BOARD_OMICOM_SS4_PCI: - case CX88_BOARD_TBS_8920: - case CX88_BOARD_PROF_7300: - case CX88_BOARD_SATTRADE_ST4200: - fe0->dvb.frontend = dvb_attach(cx24116_attach, - &hauppauge_hvr4000_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) - fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; - break; - case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII: - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &cx88_terratec_cinergy_ht_pci_mkii_config, - &core->i2c_adap); - if (fe0->dvb.frontend) { - fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; - if (attach_xc3028(0x61, dev) < 0) - goto frontend_detach; - } - break; - case CX88_BOARD_PROF_7301:{ - struct dvb_tuner_ops *tuner_ops = NULL; - - fe0->dvb.frontend = dvb_attach(stv0900_attach, - &prof_7301_stv0900_config, - &core->i2c_adap, 0); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(stb6100_attach, fe0->dvb.frontend, - &prof_7301_stb6100_config, - &core->i2c_adap)) - goto frontend_detach; - - tuner_ops = &fe0->dvb.frontend->ops.tuner_ops; - tuner_ops->set_frequency = stb6100_set_freq; - tuner_ops->get_frequency = stb6100_get_freq; - tuner_ops->set_bandwidth = stb6100_set_bandw; - tuner_ops->get_bandwidth = stb6100_get_bandw; - - core->prev_set_voltage = - fe0->dvb.frontend->ops.set_voltage; - fe0->dvb.frontend->ops.set_voltage = - tevii_dvbs_set_voltage; - } - break; - } - case CX88_BOARD_SAMSUNG_SMT_7020: - dev->ts_gen_cntrl = 0x08; - - cx_set(MO_GP0_IO, 0x0101); - - cx_clear(MO_GP0_IO, 0x01); - mdelay(100); - cx_set(MO_GP0_IO, 0x01); - mdelay(200); - - fe0->dvb.frontend = dvb_attach(stv0299_attach, - &samsung_stv0299_config, - &dev->core->i2c_adap); - if (fe0->dvb.frontend) { - fe0->dvb.frontend->ops.tuner_ops.set_params = - samsung_smt_7020_tuner_set_params; - fe0->dvb.frontend->tuner_priv = - &dev->core->i2c_adap; - fe0->dvb.frontend->ops.set_voltage = - samsung_smt_7020_set_voltage; - fe0->dvb.frontend->ops.set_tone = - samsung_smt_7020_set_tone; - } - - break; - case CX88_BOARD_TWINHAN_VP1027_DVBS: - dev->ts_gen_cntrl = 0x00; - fe0->dvb.frontend = dvb_attach(mb86a16_attach, - &twinhan_vp1027, - &core->i2c_adap); - if (fe0->dvb.frontend) { - core->prev_set_voltage = - fe0->dvb.frontend->ops.set_voltage; - fe0->dvb.frontend->ops.set_voltage = - vp1027_set_voltage; - } - break; - - default: - printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", - core->name); - break; - } - - if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) { - printk(KERN_ERR - "%s/2: frontend initialization failed\n", - core->name); - goto frontend_detach; - } - /* define general-purpose callback pointer */ - fe0->dvb.frontend->callback = cx88_tuner_callback; - - /* Ensure all frontends negotiate bus access */ - fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; - if (fe1) - fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; - - /* Put the analog decoder in standby to keep it quiet */ - call_all(core, core, s_power, 0); - - /* register everything */ - return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, - &dev->pci->dev, adapter_nr, mfe_shared, NULL); - -frontend_detach: - core->gate_ctrl = NULL; - videobuf_dvb_dealloc_frontends(&dev->frontends); - return -EINVAL; -} - -/* ----------------------------------------------------------- */ - -/* CX8802 MPEG -> mini driver - We have been given the hardware */ -static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) -{ - struct cx88_core *core = drv->core; - int err = 0; - dprintk( 1, "%s\n", __func__); - - switch (core->boardnr) { - case CX88_BOARD_HAUPPAUGE_HVR1300: - /* We arrive here with either the cx23416 or the cx22702 - * on the bus. Take the bus from the cx23416 and enable the - * cx22702 demod - */ - /* Toggle reset on cx22702 leaving i2c active */ - cx_set(MO_GP0_IO, 0x00000080); - udelay(1000); - cx_clear(MO_GP0_IO, 0x00000080); - udelay(50); - cx_set(MO_GP0_IO, 0x00000080); - udelay(1000); - /* enable the cx22702 pins */ - cx_clear(MO_GP0_IO, 0x00000004); - udelay(1000); - break; - - case CX88_BOARD_HAUPPAUGE_HVR3000: - case CX88_BOARD_HAUPPAUGE_HVR4000: - /* Toggle reset on cx22702 leaving i2c active */ - cx_set(MO_GP0_IO, 0x00000080); - udelay(1000); - cx_clear(MO_GP0_IO, 0x00000080); - udelay(50); - cx_set(MO_GP0_IO, 0x00000080); - udelay(1000); - switch (core->dvbdev->frontends.active_fe_id) { - case 1: /* DVB-S/S2 Enabled */ - /* tri-state the cx22702 pins */ - cx_set(MO_GP0_IO, 0x00000004); - /* Take the cx24116/cx24123 out of reset */ - cx_write(MO_SRST_IO, 1); - core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */ - break; - case 2: /* DVB-T Enabled */ - /* Put the cx24116/cx24123 into reset */ - cx_write(MO_SRST_IO, 0); - /* enable the cx22702 pins */ - cx_clear(MO_GP0_IO, 0x00000004); - core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */ - break; - } - udelay(1000); - break; - - default: - err = -ENODEV; - } - return err; -} - -/* CX8802 MPEG -> mini driver - We no longer have the hardware */ -static int cx8802_dvb_advise_release(struct cx8802_driver *drv) -{ - struct cx88_core *core = drv->core; - int err = 0; - dprintk( 1, "%s\n", __func__); - - switch (core->boardnr) { - case CX88_BOARD_HAUPPAUGE_HVR1300: - /* Do Nothing, leave the cx22702 on the bus. */ - break; - case CX88_BOARD_HAUPPAUGE_HVR3000: - case CX88_BOARD_HAUPPAUGE_HVR4000: - break; - default: - err = -ENODEV; - } - return err; -} - -static int cx8802_dvb_probe(struct cx8802_driver *drv) -{ - struct cx88_core *core = drv->core; - struct cx8802_dev *dev = drv->core->dvbdev; - int err; - struct videobuf_dvb_frontend *fe; - int i; - - dprintk( 1, "%s\n", __func__); - dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", - core->boardnr, - core->name, - core->pci_bus, - core->pci_slot); - - err = -ENODEV; - if (!(core->board.mpeg & CX88_MPEG_DVB)) - goto fail_core; - - /* If vp3054 isn't enabled, a stub will just return 0 */ - err = vp3054_i2c_probe(dev); - if (0 != err) - goto fail_core; - - /* dvb stuff */ - printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); - dev->ts_gen_cntrl = 0x0c; - - err = cx8802_alloc_frontends(dev); - if (err) - goto fail_core; - - err = -ENODEV; - for (i = 1; i <= core->board.num_frontends; i++) { - fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i); - if (fe == NULL) { - printk(KERN_ERR "%s() failed to get frontend(%d)\n", - __func__, i); - goto fail_probe; - } - videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_TOP, - sizeof(struct cx88_buffer), - dev, NULL); - /* init struct videobuf_dvb */ - fe->dvb.name = dev->core->name; - } - - err = dvb_register(dev); - if (err) - /* frontends/adapter de-allocated in dvb_register */ - printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n", - core->name, err); - return err; -fail_probe: - videobuf_dvb_dealloc_frontends(&core->dvbdev->frontends); -fail_core: - return err; -} - -static int cx8802_dvb_remove(struct cx8802_driver *drv) -{ - struct cx88_core *core = drv->core; - struct cx8802_dev *dev = drv->core->dvbdev; - - dprintk( 1, "%s\n", __func__); - - videobuf_dvb_unregister_bus(&dev->frontends); - - vp3054_i2c_remove(dev); - - core->gate_ctrl = NULL; - - return 0; -} - -static struct cx8802_driver cx8802_dvb_driver = { - .type_id = CX88_MPEG_DVB, - .hw_access = CX8802_DRVCTL_SHARED, - .probe = cx8802_dvb_probe, - .remove = cx8802_dvb_remove, - .advise_acquire = cx8802_dvb_advise_acquire, - .advise_release = cx8802_dvb_advise_release, -}; - -static int __init dvb_init(void) -{ - printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return cx8802_register_driver(&cx8802_dvb_driver); -} - -static void __exit dvb_fini(void) -{ - cx8802_unregister_driver(&cx8802_dvb_driver); -} - -module_init(dvb_init); -module_exit(dvb_fini); - -/* - * Local variables: - * c-basic-offset: 8 - * compile-command: "make DVB=1" - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,722 +0,0 @@ -/* - * - * v4l2 device driver for cx2388x based TV cards - * - * (c) 2003,04 Gerd Knorr [SUSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "btcx-risc.h" -#include "cx88-reg.h" -#include "tuner-xc2028.h" - -#include -#include -#define CX88_VERSION_CODE KERNEL_VERSION(0, 0, 8) - -#define UNSET (-1U) - -#define CX88_MAXBOARDS 8 - -/* Max number of inputs by card */ -#define MAX_CX88_INPUT 8 - -/* ----------------------------------------------------------- */ -/* defines and enums */ - -/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM/LC */ -#define CX88_NORMS (V4L2_STD_ALL \ - & ~V4L2_STD_PAL_H \ - & ~V4L2_STD_NTSC_M_KR \ - & ~V4L2_STD_SECAM_LC) - -#define FORMAT_FLAGS_PACKED 0x01 -#define FORMAT_FLAGS_PLANAR 0x02 - -#define VBI_LINE_COUNT 17 -#define VBI_LINE_LENGTH 2048 - -#define AUD_RDS_LINES 4 - -/* need "shadow" registers for some write-only ones ... */ -#define SHADOW_AUD_VOL_CTL 1 -#define SHADOW_AUD_BAL_CTL 2 -#define SHADOW_MAX 3 - -/* FM Radio deemphasis type */ -enum cx88_deemph_type { - FM_NO_DEEMPH = 0, - FM_DEEMPH_50, - FM_DEEMPH_75 -}; - -enum cx88_board_type { - CX88_BOARD_NONE = 0, - CX88_MPEG_DVB, - CX88_MPEG_BLACKBIRD -}; - -enum cx8802_board_access { - CX8802_DRVCTL_SHARED = 1, - CX8802_DRVCTL_EXCLUSIVE = 2, -}; - -/* ----------------------------------------------------------- */ -/* tv norms */ - -static unsigned int inline norm_maxw(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; -} - - -static unsigned int inline norm_maxh(v4l2_std_id norm) -{ - return (norm & V4L2_STD_625_50) ? 576 : 480; -} - -/* ----------------------------------------------------------- */ -/* static data */ - -struct cx8800_fmt { - const char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int flags; - u32 cxformat; -}; - -struct cx88_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 sreg; - u32 mask; - u32 shift; -}; - -/* ----------------------------------------------------------- */ -/* SRAM memory management data (see cx88-core.c) */ - -#define SRAM_CH21 0 /* video */ -#define SRAM_CH22 1 -#define SRAM_CH23 2 -#define SRAM_CH24 3 /* vbi */ -#define SRAM_CH25 4 /* audio */ -#define SRAM_CH26 5 -#define SRAM_CH28 6 /* mpeg */ -#define SRAM_CH27 7 /* audio rds */ -/* more */ - -struct sram_channel { - const char *name; - u32 cmds_start; - u32 ctrl_start; - u32 cdt; - u32 fifo_start; - u32 fifo_size; - u32 ptr1_reg; - u32 ptr2_reg; - u32 cnt1_reg; - u32 cnt2_reg; -}; -extern const struct sram_channel const cx88_sram_channels[]; - -/* ----------------------------------------------------------- */ -/* card configuration */ - -#define CX88_BOARD_NOAUTO UNSET -#define CX88_BOARD_UNKNOWN 0 -#define CX88_BOARD_HAUPPAUGE 1 -#define CX88_BOARD_GDI 2 -#define CX88_BOARD_PIXELVIEW 3 -#define CX88_BOARD_ATI_WONDER_PRO 4 -#define CX88_BOARD_WINFAST2000XP_EXPERT 5 -#define CX88_BOARD_AVERTV_STUDIO_303 6 -#define CX88_BOARD_MSI_TVANYWHERE_MASTER 7 -#define CX88_BOARD_WINFAST_DV2000 8 -#define CX88_BOARD_LEADTEK_PVR2000 9 -#define CX88_BOARD_IODATA_GVVCP3PCI 10 -#define CX88_BOARD_PROLINK_PLAYTVPVR 11 -#define CX88_BOARD_ASUS_PVR_416 12 -#define CX88_BOARD_MSI_TVANYWHERE 13 -#define CX88_BOARD_KWORLD_DVB_T 14 -#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15 -#define CX88_BOARD_KWORLD_LTV883 16 -#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q 17 -#define CX88_BOARD_HAUPPAUGE_DVB_T1 18 -#define CX88_BOARD_CONEXANT_DVB_T1 19 -#define CX88_BOARD_PROVIDEO_PV259 20 -#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21 -#define CX88_BOARD_PCHDTV_HD3000 22 -#define CX88_BOARD_DNTV_LIVE_DVB_T 23 -#define CX88_BOARD_HAUPPAUGE_ROSLYN 24 -#define CX88_BOARD_DIGITALLOGIC_MEC 25 -#define CX88_BOARD_IODATA_GVBCTV7E 26 -#define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27 -#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T 28 -#define CX88_BOARD_ADSTECH_DVB_T_PCI 29 -#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30 -#define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31 -#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32 -#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33 -#define CX88_BOARD_ATI_HDTVWONDER 34 -#define CX88_BOARD_WINFAST_DTV1000 35 -#define CX88_BOARD_AVERTV_303 36 -#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37 -#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38 -#define CX88_BOARD_KWORLD_DVBS_100 39 -#define CX88_BOARD_HAUPPAUGE_HVR1100 40 -#define CX88_BOARD_HAUPPAUGE_HVR1100LP 41 -#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42 -#define CX88_BOARD_KWORLD_DVB_T_CX22702 43 -#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44 -#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45 -#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46 -#define CX88_BOARD_PCHDTV_HD5500 47 -#define CX88_BOARD_KWORLD_MCE200_DELUXE 48 -#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000 49 -#define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50 -#define CX88_BOARD_WINFAST_DTV2000H 51 -#define CX88_BOARD_GENIATECH_DVBS 52 -#define CX88_BOARD_HAUPPAUGE_HVR3000 53 -#define CX88_BOARD_NORWOOD_MICRO 54 -#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55 -#define CX88_BOARD_HAUPPAUGE_HVR1300 56 -#define CX88_BOARD_ADSTECH_PTV_390 57 -#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58 -#define CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO 59 -#define CX88_BOARD_PINNACLE_HYBRID_PCTV 60 -#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL 61 -#define CX88_BOARD_POWERCOLOR_REAL_ANGEL 62 -#define CX88_BOARD_GENIATECH_X8000_MT 63 -#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO 64 -#define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65 -#define CX88_BOARD_PROLINK_PV_8000GT 66 -#define CX88_BOARD_KWORLD_ATSC_120 67 -#define CX88_BOARD_HAUPPAUGE_HVR4000 68 -#define CX88_BOARD_HAUPPAUGE_HVR4000LITE 69 -#define CX88_BOARD_TEVII_S460 70 -#define CX88_BOARD_OMICOM_SS4_PCI 71 -#define CX88_BOARD_TBS_8920 72 -#define CX88_BOARD_TEVII_S420 73 -#define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74 -#define CX88_BOARD_PROF_7300 75 -#define CX88_BOARD_SATTRADE_ST4200 76 -#define CX88_BOARD_TBS_8910 77 -#define CX88_BOARD_PROF_6200 78 -#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79 -#define CX88_BOARD_HAUPPAUGE_IRONLY 80 -#define CX88_BOARD_WINFAST_DTV1800H 81 -#define CX88_BOARD_WINFAST_DTV2000H_J 82 -#define CX88_BOARD_PROF_7301 83 -#define CX88_BOARD_SAMSUNG_SMT_7020 84 -#define CX88_BOARD_TWINHAN_VP1027_DVBS 85 -#define CX88_BOARD_TEVII_S464 86 - -enum cx88_itype { - CX88_VMUX_COMPOSITE1 = 1, - CX88_VMUX_COMPOSITE2, - CX88_VMUX_COMPOSITE3, - CX88_VMUX_COMPOSITE4, - CX88_VMUX_SVIDEO, - CX88_VMUX_TELEVISION, - CX88_VMUX_CABLE, - CX88_VMUX_DVB, - CX88_VMUX_DEBUG, - CX88_RADIO, -}; - -struct cx88_input { - enum cx88_itype type; - u32 gpio0, gpio1, gpio2, gpio3; - unsigned int vmux:2; - unsigned int audioroute:4; -}; - -struct cx88_board { - const char *name; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - int tda9887_conf; - struct cx88_input input[MAX_CX88_INPUT]; - struct cx88_input radio; - enum cx88_board_type mpeg; - unsigned int audio_chip; - int num_frontends; - - /* Used for I2S devices */ - int i2sinputcntl; -}; - -struct cx88_subid { - u16 subvendor; - u16 subdevice; - u32 card; -}; - -enum cx88_tvaudio { - WW_NONE = 1, - WW_BTSC, - WW_BG, - WW_DK, - WW_I, - WW_L, - WW_EIAJ, - WW_I2SPT, - WW_FM, - WW_I2SADC, - WW_M -}; - -#define INPUT(nr) (core->board.input[nr]) - -/* ----------------------------------------------------------- */ -/* device / file handle status */ - -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 - -#define BUFFER_TIMEOUT msecs_to_jiffies(2000) - -/* buffer for one video frame */ -struct cx88_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* cx88 specific */ - unsigned int bpl; - struct btcx_riscmem risc; - const struct cx8800_fmt *fmt; - u32 count; -}; - -struct cx88_dmaqueue { - struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; - u32 count; -}; - -struct cx88_core { - struct list_head devlist; - atomic_t refcount; - - /* board name */ - int nr; - char name[32]; - - /* pci stuff */ - int pci_bus; - int pci_slot; - u32 __iomem *lmmio; - u8 __iomem *bmmio; - u32 shadow[SHADOW_MAX]; - int pci_irqmask; - - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - u32 i2c_state, i2c_rc; - - /* config info -- analog */ - struct v4l2_device v4l2_dev; - struct i2c_client *i2c_rtc; - unsigned int boardnr; - struct cx88_board board; - - /* Supported V4L _STD_ tuner formats */ - unsigned int tuner_formats; - - /* config info -- dvb */ -#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) - int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); -#endif - void (*gate_ctrl)(struct cx88_core *core, int open); - - /* state info */ - struct task_struct *kthread; - v4l2_std_id tvnorm; - enum cx88_tvaudio tvaudio; - u32 audiomode_manual; - u32 audiomode_current; - u32 input; - u32 astat; - u32 use_nicam; - unsigned long last_change; - - /* IR remote control state */ - struct cx88_IR *ir; - - /* I2C remote data */ - struct IR_i2c_init_data init_data; - struct wm8775_platform_data wm8775_data; - - struct mutex lock; - /* various v4l controls */ - u32 freq; - atomic_t users; - atomic_t mpeg_users; - - /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ - struct cx8802_dev *dvbdev; - enum cx88_board_type active_type_id; - int active_ref; - int active_fe_id; -}; - -static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct cx88_core, v4l2_dev); -} - -#define WM8775_GID (1 << 0) - -#define call_hw(core, grpid, o, f, args...) \ - do { \ - if (!core->i2c_rc) { \ - if (core->gate_ctrl) \ - core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ - if (core->gate_ctrl) \ - core->gate_ctrl(core, 0); \ - } \ - } while (0) - -#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) - -struct cx8800_dev; -struct cx8802_dev; - -/* ----------------------------------------------------------- */ -/* function 0: video stuff */ - -struct cx8800_fh { - struct cx8800_dev *dev; - enum v4l2_buf_type type; - int radio; - unsigned int resources; - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - - /* video capture */ - const struct cx8800_fmt *fmt; - unsigned int width,height; - struct videobuf_queue vidq; - - /* vbi capture */ - struct videobuf_queue vbiq; -}; - -struct cx8800_suspend_state { - int disabled; -}; - -struct cx8800_dev { - struct cx88_core *core; - spinlock_t slock; - - /* various device info */ - unsigned int resources; - struct video_device *video_dev; - struct video_device *vbi_dev; - struct video_device *radio_dev; - - /* pci i/o */ - struct pci_dev *pci; - unsigned char pci_rev,pci_lat; - - - /* capture queues */ - struct cx88_dmaqueue vidq; - struct cx88_dmaqueue vbiq; - - /* various v4l controls */ - - /* other global state info */ - struct cx8800_suspend_state state; -}; - -/* ----------------------------------------------------------- */ -/* function 1: audio/alsa stuff */ -/* =============> moved to cx88-alsa.c <====================== */ - - -/* ----------------------------------------------------------- */ -/* function 2: mpeg stuff */ - -struct cx8802_fh { - struct cx8802_dev *dev; - struct videobuf_queue mpegq; -}; - -struct cx8802_suspend_state { - int disabled; -}; - -struct cx8802_driver { - struct cx88_core *core; - - /* List of drivers attached to device */ - struct list_head drvlist; - - /* Type of driver and access required */ - enum cx88_board_type type_id; - enum cx8802_board_access hw_access; - - /* MPEG 8802 internal only */ - int (*suspend)(struct pci_dev *pci_dev, pm_message_t state); - int (*resume)(struct pci_dev *pci_dev); - - /* MPEG 8802 -> mini driver - Driver probe and configuration */ - int (*probe)(struct cx8802_driver *drv); - int (*remove)(struct cx8802_driver *drv); - - /* MPEG 8802 -> mini driver - Access for hardware control */ - int (*advise_acquire)(struct cx8802_driver *drv); - int (*advise_release)(struct cx8802_driver *drv); - - /* MPEG 8802 <- mini driver - Access for hardware control */ - int (*request_acquire)(struct cx8802_driver *drv); - int (*request_release)(struct cx8802_driver *drv); -}; - -struct cx8802_dev { - struct cx88_core *core; - spinlock_t slock; - - /* pci i/o */ - struct pci_dev *pci; - unsigned char pci_rev,pci_lat; - - /* dma queues */ - struct cx88_dmaqueue mpegq; - u32 ts_packet_size; - u32 ts_packet_count; - - /* other global state info */ - struct cx8802_suspend_state state; - - /* for blackbird only */ - struct list_head devlist; -#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \ - defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE) - struct video_device *mpeg_dev; - u32 mailbox; - int width; - int height; - unsigned char mpeg_active; /* nonzero if mpeg encoder is active */ - - /* mpeg params */ - struct cx2341x_mpeg_params params; -#endif - -#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) - /* for dvb only */ - struct videobuf_dvb_frontends frontends; -#endif - -#if defined(CONFIG_VIDEO_CX88_VP3054) || \ - defined(CONFIG_VIDEO_CX88_VP3054_MODULE) - /* For VP3045 secondary I2C bus support */ - struct vp3054_i2c_state *vp3054; -#endif - /* for switching modulation types */ - unsigned char ts_gen_cntrl; - - /* List of attached drivers */ - struct list_head drvlist; - struct work_struct request_module_wk; -}; - -/* ----------------------------------------------------------- */ - -#define cx_read(reg) readl(core->lmmio + ((reg)>>2)) -#define cx_write(reg,value) writel((value), core->lmmio + ((reg)>>2)) -#define cx_writeb(reg,value) writeb((value), core->bmmio + (reg)) - -#define cx_andor(reg,mask,value) \ - writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\ - ((value) & (mask)), core->lmmio+((reg)>>2)) -#define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) -#define cx_clear(reg,bit) cx_andor((reg),(bit),0) - -#define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); } - -/* shadow registers */ -#define cx_sread(sreg) (core->shadow[sreg]) -#define cx_swrite(sreg,reg,value) \ - (core->shadow[sreg] = value, \ - writel(core->shadow[sreg], core->lmmio + ((reg)>>2))) -#define cx_sandor(sreg,reg,mask,value) \ - (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \ - writel(core->shadow[sreg], core->lmmio + ((reg)>>2))) - -/* ----------------------------------------------------------- */ -/* cx88-core.c */ - -extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[], - int len, u32 bits, u32 mask); - -extern int cx88_core_irq(struct cx88_core *core, u32 status); -extern void cx88_wakeup(struct cx88_core *core, - struct cx88_dmaqueue *q, u32 count); -extern void cx88_shutdown(struct cx88_core *core); -extern int cx88_reset(struct cx88_core *core); - -extern int -cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int top_offset, unsigned int bottom_offset, - unsigned int bpl, unsigned int padding, unsigned int lines); -extern int -cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int bpl, - unsigned int lines, unsigned int lpi); -extern int -cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); -extern void -cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf); - -extern void cx88_risc_disasm(struct cx88_core *core, - struct btcx_riscmem *risc); -extern int cx88_sram_channel_setup(struct cx88_core *core, - const struct sram_channel *ch, - unsigned int bpl, u32 risc); -extern void cx88_sram_channel_dump(struct cx88_core *core, - const struct sram_channel *ch); - -extern int cx88_set_scale(struct cx88_core *core, unsigned int width, - unsigned int height, enum v4l2_field field); -extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm); - -extern struct video_device *cx88_vdev_init(struct cx88_core *core, - struct pci_dev *pci, - const struct video_device *template_, - const char *type); -extern struct cx88_core* cx88_core_get(struct pci_dev *pci); -extern void cx88_core_put(struct cx88_core *core, - struct pci_dev *pci); - -extern int cx88_start_audio_dma(struct cx88_core *core); -extern int cx88_stop_audio_dma(struct cx88_core *core); - - -/* ----------------------------------------------------------- */ -/* cx88-vbi.c */ - -/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */ -int cx8800_vbi_fmt (struct file *file, void *priv, - struct v4l2_format *f); - -/* -int cx8800_start_vbi_dma(struct cx8800_dev *dev, - struct cx88_dmaqueue *q, - struct cx88_buffer *buf); -*/ -int cx8800_stop_vbi_dma(struct cx8800_dev *dev); -int cx8800_restart_vbi_queue(struct cx8800_dev *dev, - struct cx88_dmaqueue *q); -void cx8800_vbi_timeout(unsigned long data); - -extern const struct videobuf_queue_ops cx8800_vbi_qops; - -/* ----------------------------------------------------------- */ -/* cx88-i2c.c */ - -extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci); - - -/* ----------------------------------------------------------- */ -/* cx88-cards.c */ - -extern int cx88_tuner_callback(void *dev, int component, int command, int arg); -extern int cx88_get_resources(const struct cx88_core *core, - struct pci_dev *pci); -extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); -extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl); - -/* ----------------------------------------------------------- */ -/* cx88-tvaudio.c */ - -void cx88_set_tvaudio(struct cx88_core *core); -void cx88_newstation(struct cx88_core *core); -void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); -void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); -int cx88_audio_thread(void *data); - -int cx8802_register_driver(struct cx8802_driver *drv); -int cx8802_unregister_driver(struct cx8802_driver *drv); -struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); - -/* ----------------------------------------------------------- */ -/* cx88-dsp.c */ - -s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core); - -/* ----------------------------------------------------------- */ -/* cx88-input.c */ - -int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci); -int cx88_ir_fini(struct cx88_core *core); -void cx88_ir_irq(struct cx88_core *core); -int cx88_ir_start(struct cx88_core *core); -void cx88_ir_stop(struct cx88_core *core); -extern void cx88_i2c_init_ir(struct cx88_core *core); - -/* ----------------------------------------------------------- */ -/* cx88-mpeg.c */ - -int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev, - struct cx88_buffer *buf, enum v4l2_field field); -void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf); -void cx8802_cancel_buffers(struct cx8802_dev *dev); - -/* ----------------------------------------------------------- */ -/* cx88-video.c*/ -extern const u32 cx88_user_ctrls[]; -extern int cx8800_ctrl_query(struct cx88_core *core, - struct v4l2_queryctrl *qctrl); -int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i); -int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f); -int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl); -int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl); -int cx88_video_mux(struct cx88_core *core, unsigned int input); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,184 +0,0 @@ - -/* - - cx88-i2c.c -- all the i2c code is here - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 2002 Yurij Sysoev - (c) 1999-2003 Gerd Knorr - - (c) 2005 Mauro Carvalho Chehab - - Multituner support and i2c address binding - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include - -#include - -#include "cx88.h" -#include - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); - -static unsigned int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); - -static unsigned int i2c_udelay = 5; -module_param(i2c_udelay, int, 0644); -MODULE_PARM_DESC(i2c_udelay,"i2c delay at insmod time, in usecs " - "(should be 5 or higher). Lower value means higher bus speed."); - -#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) - -/* ----------------------------------------------------------------------- */ - -static void cx8800_bit_setscl(void *data, int state) -{ - struct cx88_core *core = data; - - if (state) - core->i2c_state |= 0x02; - else - core->i2c_state &= ~0x02; - cx_write(MO_I2C, core->i2c_state); - cx_read(MO_I2C); -} - -static void cx8800_bit_setsda(void *data, int state) -{ - struct cx88_core *core = data; - - if (state) - core->i2c_state |= 0x01; - else - core->i2c_state &= ~0x01; - cx_write(MO_I2C, core->i2c_state); - cx_read(MO_I2C); -} - -static int cx8800_bit_getscl(void *data) -{ - struct cx88_core *core = data; - u32 state; - - state = cx_read(MO_I2C); - return state & 0x02 ? 1 : 0; -} - -static int cx8800_bit_getsda(void *data) -{ - struct cx88_core *core = data; - u32 state; - - state = cx_read(MO_I2C); - return state & 0x01; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_algo_bit_data cx8800_i2c_algo_template = { - .setsda = cx8800_bit_setsda, - .setscl = cx8800_bit_setscl, - .getsda = cx8800_bit_getsda, - .getscl = cx8800_bit_getscl, - .udelay = 16, - .timeout = 200, -}; - -/* ----------------------------------------------------------------------- */ - -static const char * const i2c_devs[128] = { - [ 0x1c >> 1 ] = "lgdt330x", - [ 0x86 >> 1 ] = "tda9887/cx22702", - [ 0xa0 >> 1 ] = "eeprom", - [ 0xc0 >> 1 ] = "tuner (analog)", - [ 0xc2 >> 1 ] = "tuner (analog/dvb)", - [ 0xc8 >> 1 ] = "xc5000", -}; - -static void do_i2c_scan(const char *name, struct i2c_client *c) -{ - unsigned char buf; - int i,rc; - - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - c->addr = i; - rc = i2c_master_recv(c,&buf,0); - if (rc < 0) - continue; - printk("%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); - } -} - -/* init + register i2c algo-bit adapter */ -int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) -{ - /* Prevents usage of invalid delay values */ - if (i2c_udelay<5) - i2c_udelay=5; - - memcpy(&core->i2c_algo, &cx8800_i2c_algo_template, - sizeof(core->i2c_algo)); - - - core->i2c_adap.dev.parent = &pci->dev; - strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name)); - core->i2c_adap.owner = THIS_MODULE; - core->i2c_algo.udelay = i2c_udelay; - core->i2c_algo.data = core; - i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev); - core->i2c_adap.algo_data = &core->i2c_algo; - core->i2c_client.adapter = &core->i2c_adap; - strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE); - - cx8800_bit_setscl(core,1); - cx8800_bit_setsda(core,1); - - core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap); - if (0 == core->i2c_rc) { - static u8 tuner_data[] = - { 0x0b, 0xdc, 0x86, 0x52 }; - static struct i2c_msg tuner_msg = - { .flags = 0, .addr = 0xc2 >> 1, .buf = tuner_data, .len = 4 }; - - dprintk(1, "i2c register ok\n"); - switch( core->boardnr ) { - case CX88_BOARD_HAUPPAUGE_HVR1300: - case CX88_BOARD_HAUPPAUGE_HVR3000: - case CX88_BOARD_HAUPPAUGE_HVR4000: - printk("%s: i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n", - core->name); - i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1); - break; - default: - break; - } - if (i2c_scan) - do_i2c_scan(core->name,&core->i2c_client); - } else - printk("%s: i2c register FAILED\n", core->name); - - return core->i2c_rc; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-input.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-input.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,627 +0,0 @@ -/* - * - * Device driver for GPIO attached remote control interfaces - * on Conexant 2388x based TV/DVB cards. - * - * Copyright (c) 2003 Pavel Machek - * Copyright (c) 2004 Gerd Knorr - * Copyright (c) 2004, 2005 Chris Pascoe - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include - -#include "cx88.h" -#include - -#define MODULE_NAME "cx88xx" - -/* ---------------------------------------------------------------------- */ - -struct cx88_IR { - struct cx88_core *core; - struct rc_dev *dev; - - int users; - - char name[32]; - char phys[32]; - - /* sample from gpio pin 16 */ - u32 sampling; - - /* poll external decoder */ - int polling; - struct hrtimer timer; - u32 gpio_addr; - u32 last_gpio; - u32 mask_keycode; - u32 mask_keydown; - u32 mask_keyup; -}; - -static unsigned ir_samplerate = 4; -module_param(ir_samplerate, uint, 0444); -MODULE_PARM_DESC(ir_samplerate, "IR samplerate in kHz, 1 - 20, default 4"); - -static int ir_debug; -module_param(ir_debug, int, 0644); /* debug level [IR] */ -MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); - -#define ir_dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg) - -#define dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "cx88 IR: " fmt , ##arg) - -/* ---------------------------------------------------------------------- */ - -static void cx88_ir_handle_key(struct cx88_IR *ir) -{ - struct cx88_core *core = ir->core; - u32 gpio, data, auxgpio; - - /* read gpio value */ - gpio = cx_read(ir->gpio_addr); - switch (core->boardnr) { - case CX88_BOARD_NPGTECH_REALTV_TOP10FM: - /* This board apparently uses a combination of 2 GPIO - to represent the keys. Additionally, the second GPIO - can be used for parity. - - Example: - - for key "5" - gpio = 0x758, auxgpio = 0xe5 or 0xf5 - for key "Power" - gpio = 0x758, auxgpio = 0xed or 0xfd - */ - - auxgpio = cx_read(MO_GP1_IO); - /* Take out the parity part */ - gpio=(gpio & 0x7fd) + (auxgpio & 0xef); - break; - case CX88_BOARD_WINFAST_DTV1000: - case CX88_BOARD_WINFAST_DTV1800H: - case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: - gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); - auxgpio = gpio; - break; - default: - auxgpio = gpio; - } - if (ir->polling) { - if (ir->last_gpio == auxgpio) - return; - ir->last_gpio = auxgpio; - } - - /* extract data */ - data = ir_extract_bits(gpio, ir->mask_keycode); - ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n", - gpio, data, - ir->polling ? "poll" : "irq", - (gpio & ir->mask_keydown) ? " down" : "", - (gpio & ir->mask_keyup) ? " up" : ""); - - if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) { - u32 gpio_key = cx_read(MO_GP0_IO); - - data = (data << 4) | ((gpio_key & 0xf0) >> 4); - - rc_keydown(ir->dev, data, 0); - - } else if (ir->mask_keydown) { - /* bit set on keydown */ - if (gpio & ir->mask_keydown) - rc_keydown_notimeout(ir->dev, data, 0); - else - rc_keyup(ir->dev); - - } else if (ir->mask_keyup) { - /* bit cleared on keydown */ - if (0 == (gpio & ir->mask_keyup)) - rc_keydown_notimeout(ir->dev, data, 0); - else - rc_keyup(ir->dev); - - } else { - /* can't distinguish keydown/up :-/ */ - rc_keydown_notimeout(ir->dev, data, 0); - rc_keyup(ir->dev); - } -} - -static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer) -{ - unsigned long missed; - struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer); - - cx88_ir_handle_key(ir); - missed = hrtimer_forward_now(&ir->timer, - ktime_set(0, ir->polling * 1000000)); - if (missed > 1) - ir_dprintk("Missed ticks %ld\n", missed - 1); - - return HRTIMER_RESTART; -} - -static int __cx88_ir_start(void *priv) -{ - struct cx88_core *core = priv; - struct cx88_IR *ir; - - if (!core || !core->ir) - return -EINVAL; - - ir = core->ir; - - if (ir->polling) { - hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ir->timer.function = cx88_ir_work; - hrtimer_start(&ir->timer, - ktime_set(0, ir->polling * 1000000), - HRTIMER_MODE_REL); - } - if (ir->sampling) { - core->pci_irqmask |= PCI_INT_IR_SMPINT; - cx_write(MO_DDS_IO, 0x33F286 * ir_samplerate); /* samplerate */ - cx_write(MO_DDSCFG_IO, 0x5); /* enable */ - } - return 0; -} - -static void __cx88_ir_stop(void *priv) -{ - struct cx88_core *core = priv; - struct cx88_IR *ir; - - if (!core || !core->ir) - return; - - ir = core->ir; - if (ir->sampling) { - cx_write(MO_DDSCFG_IO, 0x0); - core->pci_irqmask &= ~PCI_INT_IR_SMPINT; - } - - if (ir->polling) - hrtimer_cancel(&ir->timer); -} - -int cx88_ir_start(struct cx88_core *core) -{ - if (core->ir->users) - return __cx88_ir_start(core); - - return 0; -} - -void cx88_ir_stop(struct cx88_core *core) -{ - if (core->ir->users) - __cx88_ir_stop(core); -} - -static int cx88_ir_open(struct rc_dev *rc) -{ - struct cx88_core *core = rc->priv; - - core->ir->users++; - return __cx88_ir_start(core); -} - -static void cx88_ir_close(struct rc_dev *rc) -{ - struct cx88_core *core = rc->priv; - - core->ir->users--; - if (!core->ir->users) - __cx88_ir_stop(core); -} - -/* ---------------------------------------------------------------------- */ - -int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) -{ - struct cx88_IR *ir; - struct rc_dev *dev; - char *ir_codes = NULL; - u64 rc_type = RC_TYPE_OTHER; - int err = -ENOMEM; - u32 hardware_mask = 0; /* For devices with a hardware mask, when - * used with a full-code IR table - */ - - ir = kzalloc(sizeof(*ir), GFP_KERNEL); - dev = rc_allocate_device(); - if (!ir || !dev) - goto err_out_free; - - ir->dev = dev; - - /* detect & configure */ - switch (core->boardnr) { - case CX88_BOARD_DNTV_LIVE_DVB_T: - case CX88_BOARD_KWORLD_DVB_T: - case CX88_BOARD_KWORLD_DVB_T_CX22702: - ir_codes = RC_MAP_DNTV_LIVE_DVB_T; - ir->gpio_addr = MO_GP1_IO; - ir->mask_keycode = 0x1f; - ir->mask_keyup = 0x60; - ir->polling = 50; /* ms */ - break; - case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: - ir_codes = RC_MAP_CINERGY_1400; - ir->sampling = 0xeb04; /* address */ - break; - case CX88_BOARD_HAUPPAUGE: - case CX88_BOARD_HAUPPAUGE_DVB_T1: - case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: - case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: - case CX88_BOARD_HAUPPAUGE_HVR1100: - case CX88_BOARD_HAUPPAUGE_HVR3000: - case CX88_BOARD_HAUPPAUGE_HVR4000: - case CX88_BOARD_HAUPPAUGE_HVR4000LITE: - case CX88_BOARD_PCHDTV_HD3000: - case CX88_BOARD_PCHDTV_HD5500: - case CX88_BOARD_HAUPPAUGE_IRONLY: - ir_codes = RC_MAP_HAUPPAUGE; - ir->sampling = 1; - break; - case CX88_BOARD_WINFAST_DTV2000H: - case CX88_BOARD_WINFAST_DTV2000H_J: - case CX88_BOARD_WINFAST_DTV1800H: - ir_codes = RC_MAP_WINFAST; - ir->gpio_addr = MO_GP0_IO; - ir->mask_keycode = 0x8f8; - ir->mask_keyup = 0x100; - ir->polling = 50; /* ms */ - break; - case CX88_BOARD_WINFAST2000XP_EXPERT: - case CX88_BOARD_WINFAST_DTV1000: - case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: - ir_codes = RC_MAP_WINFAST; - ir->gpio_addr = MO_GP0_IO; - ir->mask_keycode = 0x8f8; - ir->mask_keyup = 0x100; - ir->polling = 1; /* ms */ - break; - case CX88_BOARD_IODATA_GVBCTV7E: - ir_codes = RC_MAP_IODATA_BCTV7E; - ir->gpio_addr = MO_GP0_IO; - ir->mask_keycode = 0xfd; - ir->mask_keydown = 0x02; - ir->polling = 5; /* ms */ - break; - case CX88_BOARD_PROLINK_PLAYTVPVR: - case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO: - /* - * It seems that this hardware is paired with NEC extended - * address 0x866b. So, unfortunately, its usage with other - * IR's with different address won't work. Still, there are - * other IR's from the same manufacturer that works, like the - * 002-T mini RC, provided with newer PV hardware - */ - ir_codes = RC_MAP_PIXELVIEW_MK12; - ir->gpio_addr = MO_GP1_IO; - ir->mask_keyup = 0x80; - ir->polling = 10; /* ms */ - hardware_mask = 0x3f; /* Hardware returns only 6 bits from command part */ - break; - case CX88_BOARD_PROLINK_PV_8000GT: - case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: - ir_codes = RC_MAP_PIXELVIEW_NEW; - ir->gpio_addr = MO_GP1_IO; - ir->mask_keycode = 0x3f; - ir->mask_keyup = 0x80; - ir->polling = 1; /* ms */ - break; - case CX88_BOARD_KWORLD_LTV883: - ir_codes = RC_MAP_PIXELVIEW; - ir->gpio_addr = MO_GP1_IO; - ir->mask_keycode = 0x1f; - ir->mask_keyup = 0x60; - ir->polling = 1; /* ms */ - break; - case CX88_BOARD_ADSTECH_DVB_T_PCI: - ir_codes = RC_MAP_ADSTECH_DVB_T_PCI; - ir->gpio_addr = MO_GP1_IO; - ir->mask_keycode = 0xbf; - ir->mask_keyup = 0x40; - ir->polling = 50; /* ms */ - break; - case CX88_BOARD_MSI_TVANYWHERE_MASTER: - ir_codes = RC_MAP_MSI_TVANYWHERE; - ir->gpio_addr = MO_GP1_IO; - ir->mask_keycode = 0x1f; - ir->mask_keyup = 0x40; - ir->polling = 1; /* ms */ - break; - case CX88_BOARD_AVERTV_303: - case CX88_BOARD_AVERTV_STUDIO_303: - ir_codes = RC_MAP_AVERTV_303; - ir->gpio_addr = MO_GP2_IO; - ir->mask_keycode = 0xfb; - ir->mask_keydown = 0x02; - ir->polling = 50; /* ms */ - break; - case CX88_BOARD_OMICOM_SS4_PCI: - case CX88_BOARD_SATTRADE_ST4200: - case CX88_BOARD_TBS_8920: - case CX88_BOARD_TBS_8910: - case CX88_BOARD_PROF_7300: - case CX88_BOARD_PROF_7301: - case CX88_BOARD_PROF_6200: - ir_codes = RC_MAP_TBS_NEC; - ir->sampling = 0xff00; /* address */ - break; - case CX88_BOARD_TEVII_S464: - case CX88_BOARD_TEVII_S460: - case CX88_BOARD_TEVII_S420: - ir_codes = RC_MAP_TEVII_NEC; - ir->sampling = 0xff00; /* address */ - break; - case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: - ir_codes = RC_MAP_DNTV_LIVE_DVBT_PRO; - ir->sampling = 0xff00; /* address */ - break; - case CX88_BOARD_NORWOOD_MICRO: - ir_codes = RC_MAP_NORWOOD; - ir->gpio_addr = MO_GP1_IO; - ir->mask_keycode = 0x0e; - ir->mask_keyup = 0x80; - ir->polling = 50; /* ms */ - break; - case CX88_BOARD_NPGTECH_REALTV_TOP10FM: - ir_codes = RC_MAP_NPGTECH; - ir->gpio_addr = MO_GP0_IO; - ir->mask_keycode = 0xfa; - ir->polling = 50; /* ms */ - break; - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - ir_codes = RC_MAP_PINNACLE_PCTV_HD; - ir->sampling = 1; - break; - case CX88_BOARD_POWERCOLOR_REAL_ANGEL: - ir_codes = RC_MAP_POWERCOLOR_REAL_ANGEL; - ir->gpio_addr = MO_GP2_IO; - ir->mask_keycode = 0x7e; - ir->polling = 100; /* ms */ - break; - case CX88_BOARD_TWINHAN_VP1027_DVBS: - ir_codes = RC_MAP_TWINHAN_VP1027_DVBS; - rc_type = RC_TYPE_NEC; - ir->sampling = 0xff00; /* address */ - break; - } - - if (!ir_codes) { - err = -ENODEV; - goto err_out_free; - } - - /* - * The usage of mask_keycode were very convenient, due to several - * reasons. Among others, the scancode tables were using the scancode - * as the index elements. So, the less bits it was used, the smaller - * the table were stored. After the input changes, the better is to use - * the full scancodes, since it allows replacing the IR remote by - * another one. Unfortunately, there are still some hardware, like - * Pixelview Ultra Pro, where only part of the scancode is sent via - * GPIO. So, there's no way to get the full scancode. Due to that, - * hardware_mask were introduced here: it represents those hardware - * that has such limits. - */ - if (hardware_mask && !ir->mask_keycode) - ir->mask_keycode = hardware_mask; - - /* init input device */ - snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); - snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); - - dev->input_name = ir->name; - dev->input_phys = ir->phys; - dev->input_id.bustype = BUS_PCI; - dev->input_id.version = 1; - if (pci->subsystem_vendor) { - dev->input_id.vendor = pci->subsystem_vendor; - dev->input_id.product = pci->subsystem_device; - } else { - dev->input_id.vendor = pci->vendor; - dev->input_id.product = pci->device; - } - dev->dev.parent = &pci->dev; - dev->map_name = ir_codes; - dev->driver_name = MODULE_NAME; - dev->priv = core; - dev->open = cx88_ir_open; - dev->close = cx88_ir_close; - dev->scanmask = hardware_mask; - - if (ir->sampling) { - dev->driver_type = RC_DRIVER_IR_RAW; - dev->timeout = 10 * 1000 * 1000; /* 10 ms */ - } else { - dev->driver_type = RC_DRIVER_SCANCODE; - dev->allowed_protos = rc_type; - } - - ir->core = core; - core->ir = ir; - - /* all done */ - err = rc_register_device(dev); - if (err) - goto err_out_free; - - return 0; - -err_out_free: - rc_free_device(dev); - core->ir = NULL; - kfree(ir); - return err; -} - -int cx88_ir_fini(struct cx88_core *core) -{ - struct cx88_IR *ir = core->ir; - - /* skip detach on non attached boards */ - if (NULL == ir) - return 0; - - cx88_ir_stop(core); - rc_unregister_device(ir->dev); - kfree(ir); - - /* done */ - core->ir = NULL; - return 0; -} - -/* ---------------------------------------------------------------------- */ - -void cx88_ir_irq(struct cx88_core *core) -{ - struct cx88_IR *ir = core->ir; - u32 samples; - unsigned todo, bits; - struct ir_raw_event ev; - - if (!ir || !ir->sampling) - return; - - /* - * Samples are stored in a 32 bit register, oldest sample in - * the msb. A set bit represents space and an unset bit - * represents a pulse. - */ - samples = cx_read(MO_SAMPLE_IO); - - if (samples == 0xff && ir->dev->idle) - return; - - init_ir_raw_event(&ev); - for (todo = 32; todo > 0; todo -= bits) { - ev.pulse = samples & 0x80000000 ? false : true; - bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples)); - ev.duration = (bits * NSEC_PER_SEC) / (1000 * ir_samplerate); - ir_raw_event_store_with_filter(ir->dev, &ev); - samples <<= bits; - } - ir_raw_event_handle(ir->dev); -} - -static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - int flags, code; - - /* poll IR chip */ - flags = i2c_smbus_read_byte_data(ir->c, 0x10); - if (flags < 0) { - dprintk("read error\n"); - return 0; - } - /* key pressed ? */ - if (0 == (flags & 0x80)) - return 0; - - /* read actual key code */ - code = i2c_smbus_read_byte_data(ir->c, 0x00); - if (code < 0) { - dprintk("read error\n"); - return 0; - } - - dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", - code & 0xff, flags & 0xff); - - *ir_key = code & 0xff; - *ir_raw = code; - return 1; -} - -void cx88_i2c_init_ir(struct cx88_core *core) -{ - struct i2c_board_info info; - const unsigned short default_addr_list[] = { - 0x18, 0x6b, 0x71, - I2C_CLIENT_END - }; - const unsigned short pvr2000_addr_list[] = { - 0x18, 0x1a, - I2C_CLIENT_END - }; - const unsigned short *addr_list = default_addr_list; - const unsigned short *addrp; - /* Instantiate the IR receiver device, if present */ - if (0 != core->i2c_rc) - return; - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - - switch (core->boardnr) { - case CX88_BOARD_LEADTEK_PVR2000: - addr_list = pvr2000_addr_list; - core->init_data.name = "cx88 Leadtek PVR 2000 remote"; - core->init_data.type = RC_TYPE_UNKNOWN; - core->init_data.get_key = get_key_pvr2000; - core->init_data.ir_codes = RC_MAP_EMPTY; - break; - } - - /* - * We can't call i2c_new_probed_device() because it uses - * quick writes for probing and at least some RC receiver - * devices only reply to reads. - * Also, Hauppauge XVR needs to be specified, as address 0x71 - * conflicts with another remote type used with saa7134 - */ - for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) { - info.platform_data = NULL; - memset(&core->init_data, 0, sizeof(core->init_data)); - - if (*addrp == 0x71) { - /* Hauppauge XVR */ - core->init_data.name = "cx88 Hauppauge XVR remote"; - core->init_data.ir_codes = RC_MAP_HAUPPAUGE; - core->init_data.type = RC_TYPE_RC5; - core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - - info.platform_data = &core->init_data; - } - if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0, - I2C_SMBUS_READ, 0, - I2C_SMBUS_QUICK, NULL) >= 0) { - info.addr = *addrp; - i2c_new_device(&core->i2c_adap, &info); - break; - } - } -} - -/* ---------------------------------------------------------------------- */ - -MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe"); -MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-mpeg.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-mpeg.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-mpeg.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-mpeg.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,912 +0,0 @@ -/* - * - * Support for the mpeg transport stream transfers - * PCI function #2 of the cx2388x. - * - * (c) 2004 Jelle Foks - * (c) 2004 Chris Pascoe - * (c) 2004 Gerd Knorr - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "cx88.h" - -/* ------------------------------------------------------------------ */ - -MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards"); -MODULE_AUTHOR("Jelle Foks "); -MODULE_AUTHOR("Chris Pascoe "); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug,int,0644); -MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); - -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg) - -#define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) - -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk); - - if (dev->core->board.mpeg & CX88_MPEG_DVB) - request_module("cx88-dvb"); - if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD) - request_module("cx88-blackbird"); -} - -static void request_modules(struct cx8802_dev *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} - -static void flush_request_modules(struct cx8802_dev *dev) -{ - flush_work_sync(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#define flush_request_modules(dev) -#endif /* CONFIG_MODULES */ - - -static LIST_HEAD(cx8802_devlist); -/* ------------------------------------------------------------------ */ - -static int cx8802_start_dma(struct cx8802_dev *dev, - struct cx88_dmaqueue *q, - struct cx88_buffer *buf) -{ - struct cx88_core *core = dev->core; - - dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n", - buf->vb.width, buf->vb.height, buf->vb.field); - - /* setup fifo + format */ - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], - dev->ts_packet_size, buf->risc.dma); - - /* write TS length to chip */ - cx_write(MO_TS_LNGTH, buf->vb.width); - - /* FIXME: this needs a review. - * also: move to cx88-blackbird + cx88-dvb source files? */ - - dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id); - - if ( (core->active_type_id == CX88_MPEG_DVB) && - (core->board.mpeg & CX88_MPEG_DVB) ) { - - dprintk( 1, "cx8802_start_dma doing .dvb\n"); - /* negedge driven & software reset */ - cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); - udelay(100); - cx_write(MO_PINMUX_IO, 0x00); - cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01); - switch (core->boardnr) { - case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: - case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: - case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: - case CX88_BOARD_PCHDTV_HD5500: - cx_write(TS_SOP_STAT, 1<<13); - break; - case CX88_BOARD_SAMSUNG_SMT_7020: - cx_write(TS_SOP_STAT, 0x00); - break; - case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: - case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: - cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ - udelay(100); - break; - case CX88_BOARD_HAUPPAUGE_HVR1300: - /* Enable MPEG parallel IO and video signal pins */ - cx_write(MO_PINMUX_IO, 0x88); - cx_write(TS_SOP_STAT, 0); - cx_write(TS_VALERR_CNTRL, 0); - break; - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - /* Enable MPEG parallel IO and video signal pins */ - cx_write(MO_PINMUX_IO, 0x88); - cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4)); - dev->ts_gen_cntrl = 5; - cx_write(TS_SOP_STAT, 0); - cx_write(TS_VALERR_CNTRL, 0); - udelay(100); - break; - default: - cx_write(TS_SOP_STAT, 0x00); - break; - } - cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); - udelay(100); - } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && - (core->board.mpeg & CX88_MPEG_BLACKBIRD) ) { - dprintk( 1, "cx8802_start_dma doing .blackbird\n"); - cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ - - cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ - udelay(100); - - cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */ - cx_write(TS_VALERR_CNTRL, 0x2000); - - cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ - udelay(100); - } else { - printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __func__, - core->board.mpeg ); - return -EINVAL; - } - - /* reset counter */ - cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET); - q->count = 1; - - /* enable irqs */ - dprintk( 1, "setting the interrupt mask\n" ); - cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT); - cx_set(MO_TS_INTMSK, 0x1f0011); - - /* start dma */ - cx_set(MO_DEV_CNTRL2, (1<<5)); - cx_set(MO_TS_DMACNTRL, 0x11); - return 0; -} - -static int cx8802_stop_dma(struct cx8802_dev *dev) -{ - struct cx88_core *core = dev->core; - dprintk( 1, "cx8802_stop_dma\n" ); - - /* stop dma */ - cx_clear(MO_TS_DMACNTRL, 0x11); - - /* disable irqs */ - cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT); - cx_clear(MO_TS_INTMSK, 0x1f0011); - - /* Reset the controller */ - cx_write(TS_GEN_CNTRL, 0xcd); - return 0; -} - -static int cx8802_restart_queue(struct cx8802_dev *dev, - struct cx88_dmaqueue *q) -{ - struct cx88_buffer *buf; - - dprintk( 1, "cx8802_restart_queue\n" ); - if (list_empty(&q->active)) - { - struct cx88_buffer *prev; - prev = NULL; - - dprintk(1, "cx8802_restart_queue: queue is empty\n" ); - - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); - if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - cx8802_start_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(1,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(1,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); - } else { - return 0; - } - prev = buf; - } - return 0; - } - - buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx8802_start_dma(dev, q, buf); - list_for_each_entry(buf, &q->active, vb.queue) - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; -} - -/* ------------------------------------------------------------------ */ - -int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, - struct cx88_buffer *buf, enum v4l2_field field) -{ - int size = dev->ts_packet_size * dev->ts_packet_count; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - int rc; - - dprintk(1, "%s: %p\n", __func__, buf); - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = dev->ts_packet_size; - buf->vb.height = dev->ts_packet_count; - buf->vb.size = size; - buf->vb.field = field /*V4L2_FIELD_TOP*/; - - if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) - goto fail; - cx88_risc_databuffer(dev->pci, &buf->risc, - dma->sglist, - buf->vb.width, buf->vb.height, 0); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - cx88_free_buffer(q,buf); - return rc; -} - -void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) -{ - struct cx88_buffer *prev; - struct cx88_dmaqueue *cx88q = &dev->mpegq; - - dprintk( 1, "cx8802_buf_queue\n" ); - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); - - if (list_empty(&cx88q->active)) { - dprintk( 1, "queue is empty - first active\n" ); - list_add_tail(&buf->vb.queue,&cx88q->active); - cx8802_start_dma(dev, cx88q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; - mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(1,"[%p/%d] %s - first active\n", - buf, buf->vb.i, __func__); - - } else { - dprintk( 1, "queue is not empty - append to active\n" ); - prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue); - list_add_tail(&buf->vb.queue,&cx88q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk( 1, "[%p/%d] %s - append to active\n", - buf, buf->vb.i, __func__); - } -} - -/* ----------------------------------------------------------- */ - -static void do_cancel_buffers(struct cx8802_dev *dev, const char *reason, int restart) -{ - struct cx88_dmaqueue *q = &dev->mpegq; - struct cx88_buffer *buf; - unsigned long flags; - - spin_lock_irqsave(&dev->slock,flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", - buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); - } - if (restart) - { - dprintk(1, "restarting queue\n" ); - cx8802_restart_queue(dev,q); - } - spin_unlock_irqrestore(&dev->slock,flags); -} - -void cx8802_cancel_buffers(struct cx8802_dev *dev) -{ - struct cx88_dmaqueue *q = &dev->mpegq; - - dprintk( 1, "cx8802_cancel_buffers" ); - del_timer_sync(&q->timeout); - cx8802_stop_dma(dev); - do_cancel_buffers(dev,"cancel",0); -} - -static void cx8802_timeout(unsigned long data) -{ - struct cx8802_dev *dev = (struct cx8802_dev*)data; - - dprintk(1, "%s\n",__func__); - - if (debug) - cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]); - cx8802_stop_dma(dev); - do_cancel_buffers(dev,"timeout",1); -} - -static const char * cx88_mpeg_irqs[32] = { - "ts_risci1", NULL, NULL, NULL, - "ts_risci2", NULL, NULL, NULL, - "ts_oflow", NULL, NULL, NULL, - "ts_sync", NULL, NULL, NULL, - "opc_err", "par_err", "rip_err", "pci_abort", - "ts_err?", -}; - -static void cx8802_mpeg_irq(struct cx8802_dev *dev) -{ - struct cx88_core *core = dev->core; - u32 status, mask, count; - - dprintk( 1, "cx8802_mpeg_irq\n" ); - status = cx_read(MO_TS_INTSTAT); - mask = cx_read(MO_TS_INTMSK); - if (0 == (status & mask)) - return; - - cx_write(MO_TS_INTSTAT, status); - - if (debug || (status & mask & ~0xff)) - cx88_print_irqbits(core->name, "irq mpeg ", - cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs), - status, mask); - - /* risc op code error */ - if (status & (1 << 16)) { - printk(KERN_WARNING "%s: mpeg risc op code error\n",core->name); - cx_clear(MO_TS_DMACNTRL, 0x11); - cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]); - } - - /* risc1 y */ - if (status & 0x01) { - dprintk( 1, "wake up\n" ); - spin_lock(&dev->slock); - count = cx_read(MO_TS_GPCNT); - cx88_wakeup(dev->core, &dev->mpegq, count); - spin_unlock(&dev->slock); - } - - /* risc2 y */ - if (status & 0x10) { - spin_lock(&dev->slock); - cx8802_restart_queue(dev,&dev->mpegq); - spin_unlock(&dev->slock); - } - - /* other general errors */ - if (status & 0x1f0100) { - dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 ); - spin_lock(&dev->slock); - cx8802_stop_dma(dev); - cx8802_restart_queue(dev,&dev->mpegq); - spin_unlock(&dev->slock); - } -} - -#define MAX_IRQ_LOOP 10 - -static irqreturn_t cx8802_irq(int irq, void *dev_id) -{ - struct cx8802_dev *dev = dev_id; - struct cx88_core *core = dev->core; - u32 status; - int loop, handled = 0; - - for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & - (core->pci_irqmask | PCI_INT_TSINT); - if (0 == status) - goto out; - dprintk( 1, "cx8802_irq\n" ); - dprintk( 1, " loop: %d/%d\n", loop, MAX_IRQ_LOOP ); - dprintk( 1, " status: %d\n", status ); - handled = 1; - cx_write(MO_PCI_INTSTAT, status); - - if (status & core->pci_irqmask) - cx88_core_irq(core,status); - if (status & PCI_INT_TSINT) - cx8802_mpeg_irq(dev); - }; - if (MAX_IRQ_LOOP == loop) { - dprintk( 0, "clearing mask\n" ); - printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", - core->name); - cx_write(MO_PCI_INTMSK,0); - } - - out: - return IRQ_RETVAL(handled); -} - -static int cx8802_init_common(struct cx8802_dev *dev) -{ - struct cx88_core *core = dev->core; - int err; - - /* pci init */ - if (pci_enable_device(dev->pci)) - return -EIO; - pci_set_master(dev->pci); - if (!pci_dma_supported(dev->pci,DMA_BIT_MASK(32))) { - printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name); - return -EIO; - } - - pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev); - pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->core->name, - pci_name(dev->pci), dev->pci_rev, dev->pci->irq, - dev->pci_lat,(unsigned long long)pci_resource_start(dev->pci,0)); - - /* initialize driver struct */ - spin_lock_init(&dev->slock); - - /* init dma queue */ - INIT_LIST_HEAD(&dev->mpegq.active); - INIT_LIST_HEAD(&dev->mpegq.queued); - dev->mpegq.timeout.function = cx8802_timeout; - dev->mpegq.timeout.data = (unsigned long)dev; - init_timer(&dev->mpegq.timeout); - cx88_risc_stopper(dev->pci,&dev->mpegq.stopper, - MO_TS_DMACNTRL,0x11,0x00); - - /* get irq */ - err = request_irq(dev->pci->irq, cx8802_irq, - IRQF_SHARED | IRQF_DISABLED, dev->core->name, dev); - if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", - dev->core->name, dev->pci->irq); - return err; - } - cx_set(MO_PCI_INTMSK, core->pci_irqmask); - - /* everything worked */ - pci_set_drvdata(dev->pci,dev); - return 0; -} - -static void cx8802_fini_common(struct cx8802_dev *dev) -{ - dprintk( 2, "cx8802_fini_common\n" ); - cx8802_stop_dma(dev); - pci_disable_device(dev->pci); - - /* unregister stuff */ - free_irq(dev->pci->irq, dev); - pci_set_drvdata(dev->pci, NULL); - - /* free memory */ - btcx_riscmem_free(dev->pci,&dev->mpegq.stopper); -} - -/* ----------------------------------------------------------- */ - -static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) -{ - struct cx8802_dev *dev = pci_get_drvdata(pci_dev); - struct cx88_core *core = dev->core; - - /* stop mpeg dma */ - spin_lock(&dev->slock); - if (!list_empty(&dev->mpegq.active)) { - dprintk( 2, "suspend\n" ); - printk("%s: suspend mpeg\n", core->name); - cx8802_stop_dma(dev); - del_timer(&dev->mpegq.timeout); - } - spin_unlock(&dev->slock); - - /* FIXME -- shutdown device */ - cx88_shutdown(dev->core); - - pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { - pci_disable_device(pci_dev); - dev->state.disabled = 1; - } - return 0; -} - -static int cx8802_resume_common(struct pci_dev *pci_dev) -{ - struct cx8802_dev *dev = pci_get_drvdata(pci_dev); - struct cx88_core *core = dev->core; - int err; - - if (dev->state.disabled) { - err=pci_enable_device(pci_dev); - if (err) { - printk(KERN_ERR "%s: can't enable device\n", - dev->core->name); - return err; - } - dev->state.disabled = 0; - } - err=pci_set_power_state(pci_dev, PCI_D0); - if (err) { - printk(KERN_ERR "%s: can't enable device\n", - dev->core->name); - pci_disable_device(pci_dev); - dev->state.disabled = 1; - - return err; - } - pci_restore_state(pci_dev); - - /* FIXME: re-initialize hardware */ - cx88_reset(dev->core); - - /* restart video+vbi capture */ - spin_lock(&dev->slock); - if (!list_empty(&dev->mpegq.active)) { - printk("%s: resume mpeg\n", core->name); - cx8802_restart_queue(dev,&dev->mpegq); - } - spin_unlock(&dev->slock); - - return 0; -} - -struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) -{ - struct cx8802_driver *d; - - list_for_each_entry(d, &dev->drvlist, drvlist) - if (d->type_id == btype) - return d; - - return NULL; -} - -/* Driver asked for hardware access. */ -static int cx8802_request_acquire(struct cx8802_driver *drv) -{ - struct cx88_core *core = drv->core; - unsigned int i; - - /* Fail a request for hardware if the device is busy. */ - if (core->active_type_id != CX88_BOARD_NONE && - core->active_type_id != drv->type_id) - return -EBUSY; - - core->input = 0; - for (i = 0; - i < (sizeof(core->board.input) / sizeof(struct cx88_input)); - i++) { - if (core->board.input[i].type == CX88_VMUX_DVB) { - core->input = i; - break; - } - } - - if (drv->advise_acquire) - { - mutex_lock(&drv->core->lock); - core->active_ref++; - if (core->active_type_id == CX88_BOARD_NONE) { - core->active_type_id = drv->type_id; - drv->advise_acquire(drv); - } - mutex_unlock(&drv->core->lock); - - mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); - } - - return 0; -} - -/* Driver asked to release hardware. */ -static int cx8802_request_release(struct cx8802_driver *drv) -{ - struct cx88_core *core = drv->core; - - mutex_lock(&drv->core->lock); - if (drv->advise_release && --core->active_ref == 0) - { - drv->advise_release(drv); - core->active_type_id = CX88_BOARD_NONE; - mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); - } - mutex_unlock(&drv->core->lock); - - return 0; -} - -static int cx8802_check_driver(struct cx8802_driver *drv) -{ - if (drv == NULL) - return -ENODEV; - - if ((drv->type_id != CX88_MPEG_DVB) && - (drv->type_id != CX88_MPEG_BLACKBIRD)) - return -EINVAL; - - if ((drv->hw_access != CX8802_DRVCTL_SHARED) && - (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE)) - return -EINVAL; - - if ((drv->probe == NULL) || - (drv->remove == NULL) || - (drv->advise_acquire == NULL) || - (drv->advise_release == NULL)) - return -EINVAL; - - return 0; -} - -int cx8802_register_driver(struct cx8802_driver *drv) -{ - struct cx8802_dev *dev; - struct cx8802_driver *driver; - int err, i = 0; - - printk(KERN_INFO - "cx88/2: registering cx8802 driver, type: %s access: %s\n", - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", - drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); - - if ((err = cx8802_check_driver(drv)) != 0) { - printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n"); - return err; - } - - list_for_each_entry(dev, &cx8802_devlist, devlist) { - printk(KERN_INFO - "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", - dev->core->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, dev->core->board.name, - dev->core->boardnr); - - /* Bring up a new struct for each driver instance */ - driver = kzalloc(sizeof(*drv),GFP_KERNEL); - if (driver == NULL) - return -ENOMEM; - - /* Snapshot of the driver registration data */ - drv->core = dev->core; - drv->suspend = cx8802_suspend_common; - drv->resume = cx8802_resume_common; - drv->request_acquire = cx8802_request_acquire; - drv->request_release = cx8802_request_release; - memcpy(driver, drv, sizeof(*driver)); - - err = drv->probe(driver); - if (err == 0) { - i++; - mutex_lock(&drv->core->lock); - list_add_tail(&driver->drvlist, &dev->drvlist); - mutex_unlock(&drv->core->lock); - } else { - printk(KERN_ERR - "%s/2: cx8802 probe failed, err = %d\n", - dev->core->name, err); - } - - } - - return i ? 0 : -ENODEV; -} - -int cx8802_unregister_driver(struct cx8802_driver *drv) -{ - struct cx8802_dev *dev; - struct cx8802_driver *d, *dtmp; - int err = 0; - - printk(KERN_INFO - "cx88/2: unregistering cx8802 driver, type: %s access: %s\n", - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", - drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); - - list_for_each_entry(dev, &cx8802_devlist, devlist) { - printk(KERN_INFO - "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", - dev->core->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, dev->core->board.name, - dev->core->boardnr); - - list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) { - /* only unregister the correct driver type */ - if (d->type_id != drv->type_id) - continue; - - err = d->remove(d); - if (err == 0) { - mutex_lock(&drv->core->lock); - list_del(&d->drvlist); - mutex_unlock(&drv->core->lock); - kfree(d); - } else - printk(KERN_ERR "%s/2: cx8802 driver remove " - "failed (%d)\n", dev->core->name, err); - } - - } - - return err; -} - -/* ----------------------------------------------------------- */ -static int __devinit cx8802_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - struct cx8802_dev *dev; - struct cx88_core *core; - int err; - - /* general setup */ - core = cx88_core_get(pci_dev); - if (NULL == core) - return -EINVAL; - - printk("%s/2: cx2388x 8802 Driver Manager\n", core->name); - - err = -ENODEV; - if (!core->board.mpeg) - goto fail_core; - - err = -ENOMEM; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) - goto fail_core; - dev->pci = pci_dev; - dev->core = core; - - /* Maintain a reference so cx88-video can query the 8802 device. */ - core->dvbdev = dev; - - err = cx8802_init_common(dev); - if (err != 0) - goto fail_free; - - INIT_LIST_HEAD(&dev->drvlist); - list_add_tail(&dev->devlist,&cx8802_devlist); - - /* now autoload cx88-dvb or cx88-blackbird */ - request_modules(dev); - return 0; - - fail_free: - kfree(dev); - fail_core: - core->dvbdev = NULL; - cx88_core_put(core,pci_dev); - return err; -} - -static void __devexit cx8802_remove(struct pci_dev *pci_dev) -{ - struct cx8802_dev *dev; - - dev = pci_get_drvdata(pci_dev); - - dprintk( 1, "%s\n", __func__); - - flush_request_modules(dev); - - if (!list_empty(&dev->drvlist)) { - struct cx8802_driver *drv, *tmp; - int err; - - printk(KERN_WARNING "%s/2: Trying to remove cx8802 driver " - "while cx8802 sub-drivers still loaded?!\n", - dev->core->name); - - list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) { - err = drv->remove(drv); - if (err == 0) { - mutex_lock(&drv->core->lock); - list_del(&drv->drvlist); - mutex_unlock(&drv->core->lock); - } else - printk(KERN_ERR "%s/2: cx8802 driver remove " - "failed (%d)\n", dev->core->name, err); - kfree(drv); - } - } - - /* Destroy any 8802 reference. */ - dev->core->dvbdev = NULL; - - /* common */ - cx8802_fini_common(dev); - cx88_core_put(dev->core,dev->pci); - kfree(dev); -} - -static const struct pci_device_id cx8802_pci_tbl[] = { - { - .vendor = 0x14f1, - .device = 0x8802, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - },{ - /* --- end of list --- */ - } -}; -MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); - -static struct pci_driver cx8802_pci_driver = { - .name = "cx88-mpeg driver manager", - .id_table = cx8802_pci_tbl, - .probe = cx8802_probe, - .remove = __devexit_p(cx8802_remove), -}; - -static int __init cx8802_init(void) -{ - printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return pci_register_driver(&cx8802_pci_driver); -} - -static void __exit cx8802_fini(void) -{ - pci_unregister_driver(&cx8802_pci_driver); -} - -module_init(cx8802_init); -module_exit(cx8802_fini); -EXPORT_SYMBOL(cx8802_buf_prepare); -EXPORT_SYMBOL(cx8802_buf_queue); -EXPORT_SYMBOL(cx8802_cancel_buffers); - -EXPORT_SYMBOL(cx8802_register_driver); -EXPORT_SYMBOL(cx8802_unregister_driver); -EXPORT_SYMBOL(cx8802_get_driver); -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,836 +0,0 @@ -/* - - cx88x-hw.h - CX2388x register offsets - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - 2001 Michael Eskin - 2002 Yurij Sysoev - 2003 Gerd Knorr - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _CX88_REG_H_ -#define _CX88_REG_H_ - -/* ---------------------------------------------------------------------- */ -/* PCI IDs and config space */ - -#ifndef PCI_VENDOR_ID_CONEXANT -# define PCI_VENDOR_ID_CONEXANT 0x14F1 -#endif -#ifndef PCI_DEVICE_ID_CX2300_VID -# define PCI_DEVICE_ID_CX2300_VID 0x8800 -#endif - -#define CX88X_DEVCTRL 0x40 -#define CX88X_EN_TBFX 0x02 -#define CX88X_EN_VSFX 0x04 - -/* ---------------------------------------------------------------------- */ -/* PCI controller registers */ - -/* Command and Status Register */ -#define F0_CMD_STAT_MM 0x2f0004 -#define F1_CMD_STAT_MM 0x2f0104 -#define F2_CMD_STAT_MM 0x2f0204 -#define F3_CMD_STAT_MM 0x2f0304 -#define F4_CMD_STAT_MM 0x2f0404 - -/* Device Control #1 */ -#define F0_DEV_CNTRL1_MM 0x2f0040 -#define F1_DEV_CNTRL1_MM 0x2f0140 -#define F2_DEV_CNTRL1_MM 0x2f0240 -#define F3_DEV_CNTRL1_MM 0x2f0340 -#define F4_DEV_CNTRL1_MM 0x2f0440 - -/* Device Control #1 */ -#define F0_BAR0_MM 0x2f0010 -#define F1_BAR0_MM 0x2f0110 -#define F2_BAR0_MM 0x2f0210 -#define F3_BAR0_MM 0x2f0310 -#define F4_BAR0_MM 0x2f0410 - -/* ---------------------------------------------------------------------- */ -/* DMA Controller registers */ - -#define MO_PDMA_STHRSH 0x200000 // Source threshold -#define MO_PDMA_STADRS 0x200004 // Source target address -#define MO_PDMA_SIADRS 0x200008 // Source internal address -#define MO_PDMA_SCNTRL 0x20000C // Source control -#define MO_PDMA_DTHRSH 0x200010 // Destination threshold -#define MO_PDMA_DTADRS 0x200014 // Destination target address -#define MO_PDMA_DIADRS 0x200018 // Destination internal address -#define MO_PDMA_DCNTRL 0x20001C // Destination control -#define MO_LD_SSID 0x200030 // Load subsystem ID -#define MO_DEV_CNTRL2 0x200034 // Device control -#define MO_PCI_INTMSK 0x200040 // PCI interrupt mask -#define MO_PCI_INTSTAT 0x200044 // PCI interrupt status -#define MO_PCI_INTMSTAT 0x200048 // PCI interrupt masked status -#define MO_VID_INTMSK 0x200050 // Video interrupt mask -#define MO_VID_INTSTAT 0x200054 // Video interrupt status -#define MO_VID_INTMSTAT 0x200058 // Video interrupt masked status -#define MO_VID_INTSSTAT 0x20005C // Video interrupt set status -#define MO_AUD_INTMSK 0x200060 // Audio interrupt mask -#define MO_AUD_INTSTAT 0x200064 // Audio interrupt status -#define MO_AUD_INTMSTAT 0x200068 // Audio interrupt masked status -#define MO_AUD_INTSSTAT 0x20006C // Audio interrupt set status -#define MO_TS_INTMSK 0x200070 // Transport stream interrupt mask -#define MO_TS_INTSTAT 0x200074 // Transport stream interrupt status -#define MO_TS_INTMSTAT 0x200078 // Transport stream interrupt mask status -#define MO_TS_INTSSTAT 0x20007C // Transport stream interrupt set status -#define MO_VIP_INTMSK 0x200080 // VIP interrupt mask -#define MO_VIP_INTSTAT 0x200084 // VIP interrupt status -#define MO_VIP_INTMSTAT 0x200088 // VIP interrupt masked status -#define MO_VIP_INTSSTAT 0x20008C // VIP interrupt set status -#define MO_GPHST_INTMSK 0x200090 // Host interrupt mask -#define MO_GPHST_INTSTAT 0x200094 // Host interrupt status -#define MO_GPHST_INTMSTAT 0x200098 // Host interrupt masked status -#define MO_GPHST_INTSSTAT 0x20009C // Host interrupt set status - -// DMA Channels 1-6 belong to SPIPE -#define MO_DMA7_PTR1 0x300018 // {24}RW* DMA Current Ptr : Ch#7 -#define MO_DMA8_PTR1 0x30001C // {24}RW* DMA Current Ptr : Ch#8 - -// DMA Channels 9-20 belong to SPIPE -#define MO_DMA21_PTR1 0x300080 // {24}R0* DMA Current Ptr : Ch#21 -#define MO_DMA22_PTR1 0x300084 // {24}R0* DMA Current Ptr : Ch#22 -#define MO_DMA23_PTR1 0x300088 // {24}R0* DMA Current Ptr : Ch#23 -#define MO_DMA24_PTR1 0x30008C // {24}R0* DMA Current Ptr : Ch#24 -#define MO_DMA25_PTR1 0x300090 // {24}R0* DMA Current Ptr : Ch#25 -#define MO_DMA26_PTR1 0x300094 // {24}R0* DMA Current Ptr : Ch#26 -#define MO_DMA27_PTR1 0x300098 // {24}R0* DMA Current Ptr : Ch#27 -#define MO_DMA28_PTR1 0x30009C // {24}R0* DMA Current Ptr : Ch#28 -#define MO_DMA29_PTR1 0x3000A0 // {24}R0* DMA Current Ptr : Ch#29 -#define MO_DMA30_PTR1 0x3000A4 // {24}R0* DMA Current Ptr : Ch#30 -#define MO_DMA31_PTR1 0x3000A8 // {24}R0* DMA Current Ptr : Ch#31 -#define MO_DMA32_PTR1 0x3000AC // {24}R0* DMA Current Ptr : Ch#32 - -#define MO_DMA21_PTR2 0x3000C0 // {24}RW* DMA Tab Ptr : Ch#21 -#define MO_DMA22_PTR2 0x3000C4 // {24}RW* DMA Tab Ptr : Ch#22 -#define MO_DMA23_PTR2 0x3000C8 // {24}RW* DMA Tab Ptr : Ch#23 -#define MO_DMA24_PTR2 0x3000CC // {24}RW* DMA Tab Ptr : Ch#24 -#define MO_DMA25_PTR2 0x3000D0 // {24}RW* DMA Tab Ptr : Ch#25 -#define MO_DMA26_PTR2 0x3000D4 // {24}RW* DMA Tab Ptr : Ch#26 -#define MO_DMA27_PTR2 0x3000D8 // {24}RW* DMA Tab Ptr : Ch#27 -#define MO_DMA28_PTR2 0x3000DC // {24}RW* DMA Tab Ptr : Ch#28 -#define MO_DMA29_PTR2 0x3000E0 // {24}RW* DMA Tab Ptr : Ch#29 -#define MO_DMA30_PTR2 0x3000E4 // {24}RW* DMA Tab Ptr : Ch#30 -#define MO_DMA31_PTR2 0x3000E8 // {24}RW* DMA Tab Ptr : Ch#31 -#define MO_DMA32_PTR2 0x3000EC // {24}RW* DMA Tab Ptr : Ch#32 - -#define MO_DMA21_CNT1 0x300100 // {11}RW* DMA Buffer Size : Ch#21 -#define MO_DMA22_CNT1 0x300104 // {11}RW* DMA Buffer Size : Ch#22 -#define MO_DMA23_CNT1 0x300108 // {11}RW* DMA Buffer Size : Ch#23 -#define MO_DMA24_CNT1 0x30010C // {11}RW* DMA Buffer Size : Ch#24 -#define MO_DMA25_CNT1 0x300110 // {11}RW* DMA Buffer Size : Ch#25 -#define MO_DMA26_CNT1 0x300114 // {11}RW* DMA Buffer Size : Ch#26 -#define MO_DMA27_CNT1 0x300118 // {11}RW* DMA Buffer Size : Ch#27 -#define MO_DMA28_CNT1 0x30011C // {11}RW* DMA Buffer Size : Ch#28 -#define MO_DMA29_CNT1 0x300120 // {11}RW* DMA Buffer Size : Ch#29 -#define MO_DMA30_CNT1 0x300124 // {11}RW* DMA Buffer Size : Ch#30 -#define MO_DMA31_CNT1 0x300128 // {11}RW* DMA Buffer Size : Ch#31 -#define MO_DMA32_CNT1 0x30012C // {11}RW* DMA Buffer Size : Ch#32 - -#define MO_DMA21_CNT2 0x300140 // {11}RW* DMA Table Size : Ch#21 -#define MO_DMA22_CNT2 0x300144 // {11}RW* DMA Table Size : Ch#22 -#define MO_DMA23_CNT2 0x300148 // {11}RW* DMA Table Size : Ch#23 -#define MO_DMA24_CNT2 0x30014C // {11}RW* DMA Table Size : Ch#24 -#define MO_DMA25_CNT2 0x300150 // {11}RW* DMA Table Size : Ch#25 -#define MO_DMA26_CNT2 0x300154 // {11}RW* DMA Table Size : Ch#26 -#define MO_DMA27_CNT2 0x300158 // {11}RW* DMA Table Size : Ch#27 -#define MO_DMA28_CNT2 0x30015C // {11}RW* DMA Table Size : Ch#28 -#define MO_DMA29_CNT2 0x300160 // {11}RW* DMA Table Size : Ch#29 -#define MO_DMA30_CNT2 0x300164 // {11}RW* DMA Table Size : Ch#30 -#define MO_DMA31_CNT2 0x300168 // {11}RW* DMA Table Size : Ch#31 -#define MO_DMA32_CNT2 0x30016C // {11}RW* DMA Table Size : Ch#32 - - -/* ---------------------------------------------------------------------- */ -/* Video registers */ - -#define MO_VIDY_DMA 0x310000 // {64}RWp Video Y -#define MO_VIDU_DMA 0x310008 // {64}RWp Video U -#define MO_VIDV_DMA 0x310010 // {64}RWp Video V -#define MO_VBI_DMA 0x310018 // {64}RWp VBI (Vertical blanking interval) - -#define MO_DEVICE_STATUS 0x310100 -#define MO_INPUT_FORMAT 0x310104 -#define MO_AGC_BURST 0x31010c -#define MO_CONTR_BRIGHT 0x310110 -#define MO_UV_SATURATION 0x310114 -#define MO_HUE 0x310118 -#define MO_HTOTAL 0x310120 -#define MO_HDELAY_EVEN 0x310124 -#define MO_HDELAY_ODD 0x310128 -#define MO_VDELAY_ODD 0x31012c -#define MO_VDELAY_EVEN 0x310130 -#define MO_HACTIVE_EVEN 0x31013c -#define MO_HACTIVE_ODD 0x310140 -#define MO_VACTIVE_EVEN 0x310144 -#define MO_VACTIVE_ODD 0x310148 -#define MO_HSCALE_EVEN 0x31014c -#define MO_HSCALE_ODD 0x310150 -#define MO_VSCALE_EVEN 0x310154 -#define MO_FILTER_EVEN 0x31015c -#define MO_VSCALE_ODD 0x310158 -#define MO_FILTER_ODD 0x310160 -#define MO_OUTPUT_FORMAT 0x310164 - -#define MO_PLL_REG 0x310168 // PLL register -#define MO_PLL_ADJ_CTRL 0x31016c // PLL adjust control register -#define MO_SCONV_REG 0x310170 // sample rate conversion register -#define MO_SCONV_FIFO 0x310174 // sample rate conversion fifo -#define MO_SUB_STEP 0x310178 // subcarrier step size -#define MO_SUB_STEP_DR 0x31017c // subcarrier step size for DR line - -#define MO_CAPTURE_CTRL 0x310180 // capture control -#define MO_COLOR_CTRL 0x310184 -#define MO_VBI_PACKET 0x310188 // vbi packet size / delay -#define MO_FIELD_COUNT 0x310190 // field counter -#define MO_VIP_CONFIG 0x310194 -#define MO_VBOS_CONTROL 0x3101a8 - -#define MO_AGC_BACK_VBI 0x310200 -#define MO_AGC_SYNC_TIP1 0x310208 - -#define MO_VIDY_GPCNT 0x31C020 // {16}RO Video Y general purpose counter -#define MO_VIDU_GPCNT 0x31C024 // {16}RO Video U general purpose counter -#define MO_VIDV_GPCNT 0x31C028 // {16}RO Video V general purpose counter -#define MO_VBI_GPCNT 0x31C02C // {16}RO VBI general purpose counter -#define MO_VIDY_GPCNTRL 0x31C030 // {2}WO Video Y general purpose control -#define MO_VIDU_GPCNTRL 0x31C034 // {2}WO Video U general purpose control -#define MO_VIDV_GPCNTRL 0x31C038 // {2}WO Video V general purpose control -#define MO_VBI_GPCNTRL 0x31C03C // {2}WO VBI general purpose counter -#define MO_VID_DMACNTRL 0x31C040 // {8}RW Video DMA control -#define MO_VID_XFR_STAT 0x31C044 // {1}RO Video transfer status - - -/* ---------------------------------------------------------------------- */ -/* audio registers */ - -#define MO_AUDD_DMA 0x320000 // {64}RWp Audio downstream -#define MO_AUDU_DMA 0x320008 // {64}RWp Audio upstream -#define MO_AUDR_DMA 0x320010 // {64}RWp Audio RDS (downstream) -#define MO_AUDD_GPCNT 0x32C020 // {16}RO Audio down general purpose counter -#define MO_AUDU_GPCNT 0x32C024 // {16}RO Audio up general purpose counter -#define MO_AUDR_GPCNT 0x32C028 // {16}RO Audio RDS general purpose counter -#define MO_AUDD_GPCNTRL 0x32C030 // {2}WO Audio down general purpose control -#define MO_AUDU_GPCNTRL 0x32C034 // {2}WO Audio up general purpose control -#define MO_AUDR_GPCNTRL 0x32C038 // {2}WO Audio RDS general purpose control -#define MO_AUD_DMACNTRL 0x32C040 // {6}RW Audio DMA control -#define MO_AUD_XFR_STAT 0x32C044 // {1}RO Audio transfer status -#define MO_AUDD_LNGTH 0x32C048 // {12}RW Audio down line length -#define MO_AUDR_LNGTH 0x32C04C // {12}RW Audio RDS line length - -#define AUD_INIT 0x320100 -#define AUD_INIT_LD 0x320104 -#define AUD_SOFT_RESET 0x320108 -#define AUD_I2SINPUTCNTL 0x320120 -#define AUD_BAUDRATE 0x320124 -#define AUD_I2SOUTPUTCNTL 0x320128 -#define AAGC_HYST 0x320134 -#define AAGC_GAIN 0x320138 -#define AAGC_DEF 0x32013c -#define AUD_IIR1_0_SEL 0x320150 -#define AUD_IIR1_0_SHIFT 0x320154 -#define AUD_IIR1_1_SEL 0x320158 -#define AUD_IIR1_1_SHIFT 0x32015c -#define AUD_IIR1_2_SEL 0x320160 -#define AUD_IIR1_2_SHIFT 0x320164 -#define AUD_IIR1_3_SEL 0x320168 -#define AUD_IIR1_3_SHIFT 0x32016c -#define AUD_IIR1_4_SEL 0x320170 -#define AUD_IIR1_4_SHIFT 0x32017c -#define AUD_IIR1_5_SEL 0x320180 -#define AUD_IIR1_5_SHIFT 0x320184 -#define AUD_IIR2_0_SEL 0x320190 -#define AUD_IIR2_0_SHIFT 0x320194 -#define AUD_IIR2_1_SEL 0x320198 -#define AUD_IIR2_1_SHIFT 0x32019c -#define AUD_IIR2_2_SEL 0x3201a0 -#define AUD_IIR2_2_SHIFT 0x3201a4 -#define AUD_IIR2_3_SEL 0x3201a8 -#define AUD_IIR2_3_SHIFT 0x3201ac -#define AUD_IIR3_0_SEL 0x3201c0 -#define AUD_IIR3_0_SHIFT 0x3201c4 -#define AUD_IIR3_1_SEL 0x3201c8 -#define AUD_IIR3_1_SHIFT 0x3201cc -#define AUD_IIR3_2_SEL 0x3201d0 -#define AUD_IIR3_2_SHIFT 0x3201d4 -#define AUD_IIR4_0_SEL 0x3201e0 -#define AUD_IIR4_0_SHIFT 0x3201e4 -#define AUD_IIR4_1_SEL 0x3201e8 -#define AUD_IIR4_1_SHIFT 0x3201ec -#define AUD_IIR4_2_SEL 0x3201f0 -#define AUD_IIR4_2_SHIFT 0x3201f4 -#define AUD_IIR4_0_CA0 0x320200 -#define AUD_IIR4_0_CA1 0x320204 -#define AUD_IIR4_0_CA2 0x320208 -#define AUD_IIR4_0_CB0 0x32020c -#define AUD_IIR4_0_CB1 0x320210 -#define AUD_IIR4_1_CA0 0x320214 -#define AUD_IIR4_1_CA1 0x320218 -#define AUD_IIR4_1_CA2 0x32021c -#define AUD_IIR4_1_CB0 0x320220 -#define AUD_IIR4_1_CB1 0x320224 -#define AUD_IIR4_2_CA0 0x320228 -#define AUD_IIR4_2_CA1 0x32022c -#define AUD_IIR4_2_CA2 0x320230 -#define AUD_IIR4_2_CB0 0x320234 -#define AUD_IIR4_2_CB1 0x320238 -#define AUD_HP_MD_IIR4_1 0x320250 -#define AUD_HP_PROG_IIR4_1 0x320254 -#define AUD_FM_MODE_ENABLE 0x320258 -#define AUD_POLY0_DDS_CONSTANT 0x320270 -#define AUD_DN0_FREQ 0x320274 -#define AUD_DN1_FREQ 0x320278 -#define AUD_DN1_FREQ_SHIFT 0x32027c -#define AUD_DN1_AFC 0x320280 -#define AUD_DN1_SRC_SEL 0x320284 -#define AUD_DN1_SHFT 0x320288 -#define AUD_DN2_FREQ 0x32028c -#define AUD_DN2_FREQ_SHIFT 0x320290 -#define AUD_DN2_AFC 0x320294 -#define AUD_DN2_SRC_SEL 0x320298 -#define AUD_DN2_SHFT 0x32029c -#define AUD_CRDC0_SRC_SEL 0x320300 -#define AUD_CRDC0_SHIFT 0x320304 -#define AUD_CORDIC_SHIFT_0 0x320308 -#define AUD_CRDC1_SRC_SEL 0x32030c -#define AUD_CRDC1_SHIFT 0x320310 -#define AUD_CORDIC_SHIFT_1 0x320314 -#define AUD_DCOC_0_SRC 0x320320 -#define AUD_DCOC0_SHIFT 0x320324 -#define AUD_DCOC_0_SHIFT_IN0 0x320328 -#define AUD_DCOC_0_SHIFT_IN1 0x32032c -#define AUD_DCOC_1_SRC 0x320330 -#define AUD_DCOC1_SHIFT 0x320334 -#define AUD_DCOC_1_SHIFT_IN0 0x320338 -#define AUD_DCOC_1_SHIFT_IN1 0x32033c -#define AUD_DCOC_2_SRC 0x320340 -#define AUD_DCOC2_SHIFT 0x320344 -#define AUD_DCOC_2_SHIFT_IN0 0x320348 -#define AUD_DCOC_2_SHIFT_IN1 0x32034c -#define AUD_DCOC_PASS_IN 0x320350 -#define AUD_PDET_SRC 0x320370 -#define AUD_PDET_SHIFT 0x320374 -#define AUD_PILOT_BQD_1_K0 0x320380 -#define AUD_PILOT_BQD_1_K1 0x320384 -#define AUD_PILOT_BQD_1_K2 0x320388 -#define AUD_PILOT_BQD_1_K3 0x32038c -#define AUD_PILOT_BQD_1_K4 0x320390 -#define AUD_PILOT_BQD_2_K0 0x320394 -#define AUD_PILOT_BQD_2_K1 0x320398 -#define AUD_PILOT_BQD_2_K2 0x32039c -#define AUD_PILOT_BQD_2_K3 0x3203a0 -#define AUD_PILOT_BQD_2_K4 0x3203a4 -#define AUD_THR_FR 0x3203c0 -#define AUD_X_PROG 0x3203c4 -#define AUD_Y_PROG 0x3203c8 -#define AUD_HARMONIC_MULT 0x3203cc -#define AUD_C1_UP_THR 0x3203d0 -#define AUD_C1_LO_THR 0x3203d4 -#define AUD_C2_UP_THR 0x3203d8 -#define AUD_C2_LO_THR 0x3203dc -#define AUD_PLL_EN 0x320400 -#define AUD_PLL_SRC 0x320404 -#define AUD_PLL_SHIFT 0x320408 -#define AUD_PLL_IF_SEL 0x32040c -#define AUD_PLL_IF_SHIFT 0x320410 -#define AUD_BIQUAD_PLL_K0 0x320414 -#define AUD_BIQUAD_PLL_K1 0x320418 -#define AUD_BIQUAD_PLL_K2 0x32041c -#define AUD_BIQUAD_PLL_K3 0x320420 -#define AUD_BIQUAD_PLL_K4 0x320424 -#define AUD_DEEMPH0_SRC_SEL 0x320440 -#define AUD_DEEMPH0_SHIFT 0x320444 -#define AUD_DEEMPH0_G0 0x320448 -#define AUD_DEEMPH0_A0 0x32044c -#define AUD_DEEMPH0_B0 0x320450 -#define AUD_DEEMPH0_A1 0x320454 -#define AUD_DEEMPH0_B1 0x320458 -#define AUD_DEEMPH1_SRC_SEL 0x32045c -#define AUD_DEEMPH1_SHIFT 0x320460 -#define AUD_DEEMPH1_G0 0x320464 -#define AUD_DEEMPH1_A0 0x320468 -#define AUD_DEEMPH1_B0 0x32046c -#define AUD_DEEMPH1_A1 0x320470 -#define AUD_DEEMPH1_B1 0x320474 -#define AUD_OUT0_SEL 0x320490 -#define AUD_OUT0_SHIFT 0x320494 -#define AUD_OUT1_SEL 0x320498 -#define AUD_OUT1_SHIFT 0x32049c -#define AUD_RDSI_SEL 0x3204a0 -#define AUD_RDSI_SHIFT 0x3204a4 -#define AUD_RDSQ_SEL 0x3204a8 -#define AUD_RDSQ_SHIFT 0x3204ac -#define AUD_DBX_IN_GAIN 0x320500 -#define AUD_DBX_WBE_GAIN 0x320504 -#define AUD_DBX_SE_GAIN 0x320508 -#define AUD_DBX_RMS_WBE 0x32050c -#define AUD_DBX_RMS_SE 0x320510 -#define AUD_DBX_SE_BYPASS 0x320514 -#define AUD_FAWDETCTL 0x320530 -#define AUD_FAWDETWINCTL 0x320534 -#define AUD_DEEMPHGAIN_R 0x320538 -#define AUD_DEEMPHNUMER1_R 0x32053c -#define AUD_DEEMPHNUMER2_R 0x320540 -#define AUD_DEEMPHDENOM1_R 0x320544 -#define AUD_DEEMPHDENOM2_R 0x320548 -#define AUD_ERRLOGPERIOD_R 0x32054c -#define AUD_ERRINTRPTTHSHLD1_R 0x320550 -#define AUD_ERRINTRPTTHSHLD2_R 0x320554 -#define AUD_ERRINTRPTTHSHLD3_R 0x320558 -#define AUD_NICAM_STATUS1 0x32055c -#define AUD_NICAM_STATUS2 0x320560 -#define AUD_ERRLOG1 0x320564 -#define AUD_ERRLOG2 0x320568 -#define AUD_ERRLOG3 0x32056c -#define AUD_DAC_BYPASS_L 0x320580 -#define AUD_DAC_BYPASS_R 0x320584 -#define AUD_DAC_BYPASS_CTL 0x320588 -#define AUD_CTL 0x32058c -#define AUD_STATUS 0x320590 -#define AUD_VOL_CTL 0x320594 -#define AUD_BAL_CTL 0x320598 -#define AUD_START_TIMER 0x3205b0 -#define AUD_MODE_CHG_TIMER 0x3205b4 -#define AUD_POLYPH80SCALEFAC 0x3205b8 -#define AUD_DMD_RA_DDS 0x3205bc -#define AUD_I2S_RA_DDS 0x3205c0 -#define AUD_RATE_THRES_DMD 0x3205d0 -#define AUD_RATE_THRES_I2S 0x3205d4 -#define AUD_RATE_ADJ1 0x3205d8 -#define AUD_RATE_ADJ2 0x3205dc -#define AUD_RATE_ADJ3 0x3205e0 -#define AUD_RATE_ADJ4 0x3205e4 -#define AUD_RATE_ADJ5 0x3205e8 -#define AUD_APB_IN_RATE_ADJ 0x3205ec -#define AUD_I2SCNTL 0x3205ec -#define AUD_PHASE_FIX_CTL 0x3205f0 -#define AUD_PLL_PRESCALE 0x320600 -#define AUD_PLL_DDS 0x320604 -#define AUD_PLL_INT 0x320608 -#define AUD_PLL_FRAC 0x32060c -#define AUD_PLL_JTAG 0x320620 -#define AUD_PLL_SPMP 0x320624 -#define AUD_AFE_12DB_EN 0x320628 - -// Audio QAM Register Addresses -#define AUD_PDF_DDS_CNST_BYTE2 0x320d01 -#define AUD_PDF_DDS_CNST_BYTE1 0x320d02 -#define AUD_PDF_DDS_CNST_BYTE0 0x320d03 -#define AUD_PHACC_FREQ_8MSB 0x320d2a -#define AUD_PHACC_FREQ_8LSB 0x320d2b -#define AUD_QAM_MODE 0x320d04 - - -/* ---------------------------------------------------------------------- */ -/* transport stream registers */ - -#define MO_TS_DMA 0x330000 // {64}RWp Transport stream downstream -#define MO_TS_GPCNT 0x33C020 // {16}RO TS general purpose counter -#define MO_TS_GPCNTRL 0x33C030 // {2}WO TS general purpose control -#define MO_TS_DMACNTRL 0x33C040 // {6}RW TS DMA control -#define MO_TS_XFR_STAT 0x33C044 // {1}RO TS transfer status -#define MO_TS_LNGTH 0x33C048 // {12}RW TS line length - -#define TS_HW_SOP_CNTRL 0x33C04C -#define TS_GEN_CNTRL 0x33C050 -#define TS_BD_PKT_STAT 0x33C054 -#define TS_SOP_STAT 0x33C058 -#define TS_FIFO_OVFL_STAT 0x33C05C -#define TS_VALERR_CNTRL 0x33C060 - - -/* ---------------------------------------------------------------------- */ -/* VIP registers */ - -#define MO_VIPD_DMA 0x340000 // {64}RWp VIP downstream -#define MO_VIPU_DMA 0x340008 // {64}RWp VIP upstream -#define MO_VIPD_GPCNT 0x34C020 // {16}RO VIP down general purpose counter -#define MO_VIPU_GPCNT 0x34C024 // {16}RO VIP up general purpose counter -#define MO_VIPD_GPCNTRL 0x34C030 // {2}WO VIP down general purpose control -#define MO_VIPU_GPCNTRL 0x34C034 // {2}WO VIP up general purpose control -#define MO_VIP_DMACNTRL 0x34C040 // {6}RW VIP DMA control -#define MO_VIP_XFR_STAT 0x34C044 // {1}RO VIP transfer status -#define MO_VIP_CFG 0x340048 // VIP configuration -#define MO_VIPU_CNTRL 0x34004C // VIP upstream control #1 -#define MO_VIPD_CNTRL 0x340050 // VIP downstream control #2 -#define MO_VIPD_LNGTH 0x340054 // VIP downstream line length -#define MO_VIP_BRSTLN 0x340058 // VIP burst length -#define MO_VIP_INTCNTRL 0x34C05C // VIP Interrupt Control -#define MO_VIP_XFTERM 0x340060 // VIP transfer terminate - - -/* ---------------------------------------------------------------------- */ -/* misc registers */ - -#define MO_M2M_DMA 0x350000 // {64}RWp Mem2Mem DMA Bfr -#define MO_GP0_IO 0x350010 // {32}RW* GPIOoutput enablesdata I/O -#define MO_GP1_IO 0x350014 // {32}RW* GPIOoutput enablesdata I/O -#define MO_GP2_IO 0x350018 // {32}RW* GPIOoutput enablesdata I/O -#define MO_GP3_IO 0x35001C // {32}RW* GPIO Mode/Ctrloutput enables -#define MO_GPIO 0x350020 // {32}RW* GPIO I2C Ctrldata I/O -#define MO_GPOE 0x350024 // {32}RW GPIO I2C Ctrloutput enables -#define MO_GP_ISM 0x350028 // {16}WO GPIO Intr Sens/Pol - -#define MO_PLL_B 0x35C008 // {32}RW* PLL Control for ASB bus clks -#define MO_M2M_CNT 0x35C024 // {32}RW Mem2Mem DMA Cnt -#define MO_M2M_XSUM 0x35C028 // {32}RO M2M XOR-Checksum -#define MO_CRC 0x35C02C // {16}RW CRC16 init/result -#define MO_CRC_D 0x35C030 // {32}WO CRC16 new data in -#define MO_TM_CNT_LDW 0x35C034 // {32}RO Timer : Counter low dword -#define MO_TM_CNT_UW 0x35C038 // {16}RO Timer : Counter high word -#define MO_TM_LMT_LDW 0x35C03C // {32}RW Timer : Limit low dword -#define MO_TM_LMT_UW 0x35C040 // {32}RW Timer : Limit high word -#define MO_PINMUX_IO 0x35C044 // {8}RW Pin Mux Control -#define MO_TSTSEL_IO 0x35C048 // {2}RW Pin Mux Control -#define MO_AFECFG_IO 0x35C04C // AFE configuration reg -#define MO_DDS_IO 0x35C050 // DDS Increment reg -#define MO_DDSCFG_IO 0x35C054 // DDS Configuration reg -#define MO_SAMPLE_IO 0x35C058 // IRIn sample reg -#define MO_SRST_IO 0x35C05C // Output system reset reg - -#define MO_INT1_MSK 0x35C060 // DMA RISC interrupt mask -#define MO_INT1_STAT 0x35C064 // DMA RISC interrupt status -#define MO_INT1_MSTAT 0x35C068 // DMA RISC interrupt masked status - - -/* ---------------------------------------------------------------------- */ -/* i2c bus registers */ - -#define MO_I2C 0x368000 // I2C data/control -#define MO_I2C_DIV (0xf<<4) -#define MO_I2C_SYNC (1<<3) -#define MO_I2C_W3B (1<<2) -#define MO_I2C_SCL (1<<1) -#define MO_I2C_SDA (1<<0) - - -/* ---------------------------------------------------------------------- */ -/* general purpose host registers */ -/* FIXME: tyops? s/0x35/0x38/ ?? */ - -#define MO_GPHSTD_DMA 0x350000 // {64}RWp Host downstream -#define MO_GPHSTU_DMA 0x350008 // {64}RWp Host upstream -#define MO_GPHSTU_CNTRL 0x380048 // Host upstream control #1 -#define MO_GPHSTD_CNTRL 0x38004C // Host downstream control #2 -#define MO_GPHSTD_LNGTH 0x380050 // Host downstream line length -#define MO_GPHST_WSC 0x380054 // Host wait state control -#define MO_GPHST_XFR 0x380058 // Host transfer control -#define MO_GPHST_WDTH 0x38005C // Host interface width -#define MO_GPHST_HDSHK 0x380060 // Host peripheral handshake -#define MO_GPHST_MUX16 0x380064 // Host muxed 16-bit transfer parameters -#define MO_GPHST_MODE 0x380068 // Host mode select - -#define MO_GPHSTD_GPCNT 0x35C020 // Host down general purpose counter -#define MO_GPHSTU_GPCNT 0x35C024 // Host up general purpose counter -#define MO_GPHSTD_GPCNTRL 0x38C030 // Host down general purpose control -#define MO_GPHSTU_GPCNTRL 0x38C034 // Host up general purpose control -#define MO_GPHST_DMACNTRL 0x38C040 // Host DMA control -#define MO_GPHST_XFR_STAT 0x38C044 // Host transfer status -#define MO_GPHST_SOFT_RST 0x38C06C // Host software reset - - -/* ---------------------------------------------------------------------- */ -/* RISC instructions */ - -#define RISC_SYNC 0x80000000 -#define RISC_SYNC_ODD 0x80000000 -#define RISC_SYNC_EVEN 0x80000200 -#define RISC_RESYNC 0x80008000 -#define RISC_RESYNC_ODD 0x80008000 -#define RISC_RESYNC_EVEN 0x80008200 -#define RISC_WRITE 0x10000000 -#define RISC_WRITEC 0x50000000 -#define RISC_READ 0x90000000 -#define RISC_READC 0xA0000000 -#define RISC_JUMP 0x70000000 -#define RISC_SKIP 0x20000000 -#define RISC_WRITERM 0xB0000000 -#define RISC_WRITECM 0xC0000000 -#define RISC_WRITECR 0xD0000000 -#define RISC_IMM 0x00000001 - -#define RISC_SOL 0x08000000 -#define RISC_EOL 0x04000000 - -#define RISC_IRQ2 0x02000000 -#define RISC_IRQ1 0x01000000 - -#define RISC_CNT_NONE 0x00000000 -#define RISC_CNT_INC 0x00010000 -#define RISC_CNT_RSVR 0x00020000 -#define RISC_CNT_RESET 0x00030000 -#define RISC_JMP_SRP 0x01 - - -/* ---------------------------------------------------------------------- */ -/* various constants */ - -// DMA -/* Interrupt mask/status */ -#define PCI_INT_VIDINT (1 << 0) -#define PCI_INT_AUDINT (1 << 1) -#define PCI_INT_TSINT (1 << 2) -#define PCI_INT_VIPINT (1 << 3) -#define PCI_INT_HSTINT (1 << 4) -#define PCI_INT_TM1INT (1 << 5) -#define PCI_INT_SRCDMAINT (1 << 6) -#define PCI_INT_DSTDMAINT (1 << 7) -#define PCI_INT_RISC_RD_BERRINT (1 << 10) -#define PCI_INT_RISC_WR_BERRINT (1 << 11) -#define PCI_INT_BRDG_BERRINT (1 << 12) -#define PCI_INT_SRC_DMA_BERRINT (1 << 13) -#define PCI_INT_DST_DMA_BERRINT (1 << 14) -#define PCI_INT_IPB_DMA_BERRINT (1 << 15) -#define PCI_INT_I2CDONE (1 << 16) -#define PCI_INT_I2CRACK (1 << 17) -#define PCI_INT_IR_SMPINT (1 << 18) -#define PCI_INT_GPIO_INT0 (1 << 19) -#define PCI_INT_GPIO_INT1 (1 << 20) - -#define SEL_BTSC 0x01 -#define SEL_EIAJ 0x02 -#define SEL_A2 0x04 -#define SEL_SAP 0x08 -#define SEL_NICAM 0x10 -#define SEL_FMRADIO 0x20 - -// AUD_CTL -#define AUD_INT_DN_RISCI1 (1 << 0) -#define AUD_INT_UP_RISCI1 (1 << 1) -#define AUD_INT_RDS_DN_RISCI1 (1 << 2) -#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ -#define AUD_INT_UP_RISCI2 (1 << 5) -#define AUD_INT_RDS_DN_RISCI2 (1 << 6) -#define AUD_INT_DN_SYNC (1 << 12) -#define AUD_INT_UP_SYNC (1 << 13) -#define AUD_INT_RDS_DN_SYNC (1 << 14) -#define AUD_INT_OPC_ERR (1 << 16) -#define AUD_INT_BER_IRQ (1 << 20) -#define AUD_INT_MCHG_IRQ (1 << 21) - -#define EN_BTSC_FORCE_MONO 0 -#define EN_BTSC_FORCE_STEREO 1 -#define EN_BTSC_FORCE_SAP 2 -#define EN_BTSC_AUTO_STEREO 3 -#define EN_BTSC_AUTO_SAP 4 - -#define EN_A2_FORCE_MONO1 8 -#define EN_A2_FORCE_MONO2 9 -#define EN_A2_FORCE_STEREO 10 -#define EN_A2_AUTO_MONO2 11 -#define EN_A2_AUTO_STEREO 12 - -#define EN_EIAJ_FORCE_MONO1 16 -#define EN_EIAJ_FORCE_MONO2 17 -#define EN_EIAJ_FORCE_STEREO 18 -#define EN_EIAJ_AUTO_MONO2 19 -#define EN_EIAJ_AUTO_STEREO 20 - -#define EN_NICAM_FORCE_MONO1 32 -#define EN_NICAM_FORCE_MONO2 33 -#define EN_NICAM_FORCE_STEREO 34 -#define EN_NICAM_AUTO_MONO2 35 -#define EN_NICAM_AUTO_STEREO 36 - -#define EN_FMRADIO_FORCE_MONO 24 -#define EN_FMRADIO_FORCE_STEREO 25 -#define EN_FMRADIO_AUTO_STEREO 26 - -#define EN_NICAM_AUTO_FALLBACK 0x00000040 -#define EN_FMRADIO_EN_RDS 0x00000200 -#define EN_NICAM_TRY_AGAIN_BIT 0x00000400 -#define EN_DAC_ENABLE 0x00001000 -#define EN_I2SOUT_ENABLE 0x00002000 -#define EN_I2SIN_STR2DAC 0x00004000 -#define EN_I2SIN_ENABLE 0x00008000 - -#define EN_DMTRX_SUMDIFF (0 << 7) -#define EN_DMTRX_SUMR (1 << 7) -#define EN_DMTRX_LR (2 << 7) -#define EN_DMTRX_MONO (3 << 7) -#define EN_DMTRX_BYPASS (1 << 11) - -// Video -#define VID_CAPTURE_CONTROL 0x310180 - -#define CX23880_CAP_CTL_CAPTURE_VBI_ODD (1<<3) -#define CX23880_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) -#define CX23880_CAP_CTL_CAPTURE_ODD (1<<1) -#define CX23880_CAP_CTL_CAPTURE_EVEN (1<<0) - -#define VideoInputMux0 0x0 -#define VideoInputMux1 0x1 -#define VideoInputMux2 0x2 -#define VideoInputMux3 0x3 -#define VideoInputTuner 0x0 -#define VideoInputComposite 0x1 -#define VideoInputSVideo 0x2 -#define VideoInputOther 0x3 - -#define Xtal0 0x1 -#define Xtal1 0x2 -#define XtalAuto 0x3 - -#define VideoFormatAuto 0x0 -#define VideoFormatNTSC 0x1 -#define VideoFormatNTSCJapan 0x2 -#define VideoFormatNTSC443 0x3 -#define VideoFormatPAL 0x4 -#define VideoFormatPALB 0x4 -#define VideoFormatPALD 0x4 -#define VideoFormatPALG 0x4 -#define VideoFormatPALH 0x4 -#define VideoFormatPALI 0x4 -#define VideoFormatPALBDGHI 0x4 -#define VideoFormatPALM 0x5 -#define VideoFormatPALN 0x6 -#define VideoFormatPALNC 0x7 -#define VideoFormatPAL60 0x8 -#define VideoFormatSECAM 0x9 - -#define VideoFormatAuto27MHz 0x10 -#define VideoFormatNTSC27MHz 0x11 -#define VideoFormatNTSCJapan27MHz 0x12 -#define VideoFormatNTSC44327MHz 0x13 -#define VideoFormatPAL27MHz 0x14 -#define VideoFormatPALB27MHz 0x14 -#define VideoFormatPALD27MHz 0x14 -#define VideoFormatPALG27MHz 0x14 -#define VideoFormatPALH27MHz 0x14 -#define VideoFormatPALI27MHz 0x14 -#define VideoFormatPALBDGHI27MHz 0x14 -#define VideoFormatPALM27MHz 0x15 -#define VideoFormatPALN27MHz 0x16 -#define VideoFormatPALNC27MHz 0x17 -#define VideoFormatPAL6027MHz 0x18 -#define VideoFormatSECAM27MHz 0x19 - -#define NominalUSECAM 0x87 -#define NominalVSECAM 0x85 -#define NominalUNTSC 0xFE -#define NominalVNTSC 0xB4 - -#define NominalContrast 0xD8 - -#define HFilterAutoFormat 0x0 -#define HFilterCIF 0x1 -#define HFilterQCIF 0x2 -#define HFilterICON 0x3 - -#define VFilter2TapInterpolate 0 -#define VFilter3TapInterpolate 1 -#define VFilter4TapInterpolate 2 -#define VFilter5TapInterpolate 3 -#define VFilter2TapNoInterpolate 4 -#define VFilter3TapNoInterpolate 5 -#define VFilter4TapNoInterpolate 6 -#define VFilter5TapNoInterpolate 7 - -#define ColorFormatRGB32 0x0000 -#define ColorFormatRGB24 0x0011 -#define ColorFormatRGB16 0x0022 -#define ColorFormatRGB15 0x0033 -#define ColorFormatYUY2 0x0044 -#define ColorFormatBTYUV 0x0055 -#define ColorFormatY8 0x0066 -#define ColorFormatRGB8 0x0077 -#define ColorFormatPL422 0x0088 -#define ColorFormatPL411 0x0099 -#define ColorFormatYUV12 0x00AA -#define ColorFormatYUV9 0x00BB -#define ColorFormatRAW 0x00EE -#define ColorFormatBSWAP 0x0300 -#define ColorFormatWSWAP 0x0c00 -#define ColorFormatEvenMask 0x050f -#define ColorFormatOddMask 0x0af0 -#define ColorFormatGamma 0x1000 - -#define Interlaced 0x1 -#define NonInterlaced 0x0 - -#define FieldEven 0x1 -#define FieldOdd 0x0 - -#define TGReadWriteMode 0x0 -#define TGEnableMode 0x1 - -#define DV_CbAlign 0x0 -#define DV_Y0Align 0x1 -#define DV_CrAlign 0x2 -#define DV_Y1Align 0x3 - -#define DVF_Analog 0x0 -#define DVF_CCIR656 0x1 -#define DVF_ByteStream 0x2 -#define DVF_ExtVSYNC 0x4 -#define DVF_ExtField 0x5 - -#define CHANNEL_VID_Y 0x1 -#define CHANNEL_VID_U 0x2 -#define CHANNEL_VID_V 0x3 -#define CHANNEL_VID_VBI 0x4 -#define CHANNEL_AUD_DN 0x5 -#define CHANNEL_AUD_UP 0x6 -#define CHANNEL_AUD_RDS_DN 0x7 -#define CHANNEL_MPEG_DN 0x8 -#define CHANNEL_VIP_DN 0x9 -#define CHANNEL_VIP_UP 0xA -#define CHANNEL_HOST_DN 0xB -#define CHANNEL_HOST_UP 0xC -#define CHANNEL_FIRST 0x1 -#define CHANNEL_LAST 0xC - -#define GP_COUNT_CONTROL_NONE 0x0 -#define GP_COUNT_CONTROL_INC 0x1 -#define GP_COUNT_CONTROL_RESERVED 0x2 -#define GP_COUNT_CONTROL_RESET 0x3 - -#define PLL_PRESCALE_BY_2 2 -#define PLL_PRESCALE_BY_3 3 -#define PLL_PRESCALE_BY_4 4 -#define PLL_PRESCALE_BY_5 5 - -#define HLNotchFilter4xFsc 0 -#define HLNotchFilterSquare 1 -#define HLNotchFilter135NTSC 2 -#define HLNotchFilter135PAL 3 - -#define NTSC_8x_SUB_CARRIER 28.63636E6 -#define PAL_8x_SUB_CARRIER 35.46895E6 - -// Default analog settings -#define DEFAULT_HUE_NTSC 0x00 -#define DEFAULT_BRIGHTNESS_NTSC 0x00 -#define DEFAULT_CONTRAST_NTSC 0x39 -#define DEFAULT_SAT_U_NTSC 0x7F -#define DEFAULT_SAT_V_NTSC 0x5A - -typedef enum -{ - SOURCE_TUNER = 0, - SOURCE_COMPOSITE, - SOURCE_SVIDEO, - SOURCE_OTHER1, - SOURCE_OTHER2, - SOURCE_COMPVIASVIDEO, - SOURCE_CCIR656 -} VIDEOSOURCETYPE; - -#endif /* _CX88_REG_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-tvaudio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-tvaudio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-tvaudio.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-tvaudio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1059 +0,0 @@ -/* - - cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver - - (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version] - (c) 2002 Yurij Sysoev - (c) 2003 Gerd Knorr - - ----------------------------------------------------------------------- - - Lot of voodoo here. Even the data sheet doesn't help to - understand what is going on here, the documentation for the audio - part of the cx2388x chip is *very* bad. - - Some of this comes from party done linux driver sources I got from - [undocumented]. - - Some comes from the dscaler sources, one of the dscaler driver guy works - for Conexant ... - - ----------------------------------------------------------------------- - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx88.h" - -static unsigned int audio_debug; -module_param(audio_debug, int, 0644); -MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]"); - -static unsigned int always_analog; -module_param(always_analog,int,0644); -MODULE_PARM_DESC(always_analog,"force analog audio out"); - -static unsigned int radio_deemphasis; -module_param(radio_deemphasis,int,0644); -MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, " - "0=None, 1=50us (elsewhere), 2=75us (USA)"); - -#define dprintk(fmt, arg...) if (audio_debug) \ - printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) - -/* ----------------------------------------------------------- */ - -static const char * const aud_ctl_names[64] = { - [EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO", - [EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO", - [EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP", - [EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO", - [EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP", - [EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1", - [EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2", - [EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO", - [EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2", - [EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO", - [EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1", - [EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2", - [EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO", - [EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2", - [EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO", - [EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1", - [EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2", - [EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO", - [EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2", - [EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO", - [EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO", - [EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO", - [EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO", -}; - -struct rlist { - u32 reg; - u32 val; -}; - -static void set_audio_registers(struct cx88_core *core, const struct rlist *l) -{ - int i; - - for (i = 0; l[i].reg; i++) { - switch (l[i].reg) { - case AUD_PDF_DDS_CNST_BYTE2: - case AUD_PDF_DDS_CNST_BYTE1: - case AUD_PDF_DDS_CNST_BYTE0: - case AUD_QAM_MODE: - case AUD_PHACC_FREQ_8MSB: - case AUD_PHACC_FREQ_8LSB: - cx_writeb(l[i].reg, l[i].val); - break; - default: - cx_write(l[i].reg, l[i].val); - break; - } - } -} - -static void set_audio_start(struct cx88_core *core, u32 mode) -{ - /* mute */ - cx_write(AUD_VOL_CTL, (1 << 6)); - - /* start programming */ - cx_write(AUD_INIT, mode); - cx_write(AUD_INIT_LD, 0x0001); - cx_write(AUD_SOFT_RESET, 0x0001); -} - -static void set_audio_finish(struct cx88_core *core, u32 ctl) -{ - u32 volume; - - /* restart dma; This avoids buzz in NICAM and is good in others */ - cx88_stop_audio_dma(core); - cx_write(AUD_RATE_THRES_DMD, 0x000000C0); - cx88_start_audio_dma(core); - - if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { - cx_write(AUD_I2SINPUTCNTL, 4); - cx_write(AUD_BAUDRATE, 1); - /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ - cx_set(AUD_CTL, EN_I2SOUT_ENABLE); - cx_write(AUD_I2SOUTPUTCNTL, 1); - cx_write(AUD_I2SCNTL, 0); - /* cx_write(AUD_APB_IN_RATE_ADJ, 0); */ - } - if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) { - ctl |= EN_DAC_ENABLE; - cx_write(AUD_CTL, ctl); - } - - /* finish programming */ - cx_write(AUD_SOFT_RESET, 0x0000); - - /* unmute */ - volume = cx_sread(SHADOW_AUD_VOL_CTL); - cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume); - - core->last_change = jiffies; -} - -/* ----------------------------------------------------------- */ - -static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap, - u32 mode) -{ - static const struct rlist btsc[] = { - {AUD_AFE_12DB_EN, 0x00000001}, - {AUD_OUT1_SEL, 0x00000013}, - {AUD_OUT1_SHIFT, 0x00000000}, - {AUD_POLY0_DDS_CONSTANT, 0x0012010c}, - {AUD_DMD_RA_DDS, 0x00c3e7aa}, - {AUD_DBX_IN_GAIN, 0x00004734}, - {AUD_DBX_WBE_GAIN, 0x00004640}, - {AUD_DBX_SE_GAIN, 0x00008d31}, - {AUD_DCOC_0_SRC, 0x0000001a}, - {AUD_IIR1_4_SEL, 0x00000021}, - {AUD_DCOC_PASS_IN, 0x00000003}, - {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, - {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, - {AUD_DN0_FREQ, 0x0000283b}, - {AUD_DN2_SRC_SEL, 0x00000008}, - {AUD_DN2_FREQ, 0x00003000}, - {AUD_DN2_AFC, 0x00000002}, - {AUD_DN2_SHFT, 0x00000000}, - {AUD_IIR2_2_SEL, 0x00000020}, - {AUD_IIR2_2_SHIFT, 0x00000000}, - {AUD_IIR2_3_SEL, 0x0000001f}, - {AUD_IIR2_3_SHIFT, 0x00000000}, - {AUD_CRDC1_SRC_SEL, 0x000003ce}, - {AUD_CRDC1_SHIFT, 0x00000000}, - {AUD_CORDIC_SHIFT_1, 0x00000007}, - {AUD_DCOC_1_SRC, 0x0000001b}, - {AUD_DCOC1_SHIFT, 0x00000000}, - {AUD_RDSI_SEL, 0x00000008}, - {AUD_RDSQ_SEL, 0x00000008}, - {AUD_RDSI_SHIFT, 0x00000000}, - {AUD_RDSQ_SHIFT, 0x00000000}, - {AUD_POLYPH80SCALEFAC, 0x00000003}, - { /* end of list */ }, - }; - static const struct rlist btsc_sap[] = { - {AUD_AFE_12DB_EN, 0x00000001}, - {AUD_DBX_IN_GAIN, 0x00007200}, - {AUD_DBX_WBE_GAIN, 0x00006200}, - {AUD_DBX_SE_GAIN, 0x00006200}, - {AUD_IIR1_1_SEL, 0x00000000}, - {AUD_IIR1_3_SEL, 0x00000001}, - {AUD_DN1_SRC_SEL, 0x00000007}, - {AUD_IIR1_4_SHIFT, 0x00000006}, - {AUD_IIR2_1_SHIFT, 0x00000000}, - {AUD_IIR2_2_SHIFT, 0x00000000}, - {AUD_IIR3_0_SHIFT, 0x00000000}, - {AUD_IIR3_1_SHIFT, 0x00000000}, - {AUD_IIR3_0_SEL, 0x0000000d}, - {AUD_IIR3_1_SEL, 0x0000000e}, - {AUD_DEEMPH1_SRC_SEL, 0x00000014}, - {AUD_DEEMPH1_SHIFT, 0x00000000}, - {AUD_DEEMPH1_G0, 0x00004000}, - {AUD_DEEMPH1_A0, 0x00000000}, - {AUD_DEEMPH1_B0, 0x00000000}, - {AUD_DEEMPH1_A1, 0x00000000}, - {AUD_DEEMPH1_B1, 0x00000000}, - {AUD_OUT0_SEL, 0x0000003f}, - {AUD_OUT1_SEL, 0x0000003f}, - {AUD_DN1_AFC, 0x00000002}, - {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, - {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, - {AUD_IIR1_0_SEL, 0x0000001d}, - {AUD_IIR1_2_SEL, 0x0000001e}, - {AUD_IIR2_1_SEL, 0x00000002}, - {AUD_IIR2_2_SEL, 0x00000004}, - {AUD_IIR3_2_SEL, 0x0000000f}, - {AUD_DCOC2_SHIFT, 0x00000001}, - {AUD_IIR3_2_SHIFT, 0x00000001}, - {AUD_DEEMPH0_SRC_SEL, 0x00000014}, - {AUD_CORDIC_SHIFT_1, 0x00000006}, - {AUD_POLY0_DDS_CONSTANT, 0x000e4db2}, - {AUD_DMD_RA_DDS, 0x00f696e6}, - {AUD_IIR2_3_SEL, 0x00000025}, - {AUD_IIR1_4_SEL, 0x00000021}, - {AUD_DN1_FREQ, 0x0000c965}, - {AUD_DCOC_PASS_IN, 0x00000003}, - {AUD_DCOC_0_SRC, 0x0000001a}, - {AUD_DCOC_1_SRC, 0x0000001b}, - {AUD_DCOC1_SHIFT, 0x00000000}, - {AUD_RDSI_SEL, 0x00000009}, - {AUD_RDSQ_SEL, 0x00000009}, - {AUD_RDSI_SHIFT, 0x00000000}, - {AUD_RDSQ_SHIFT, 0x00000000}, - {AUD_POLYPH80SCALEFAC, 0x00000003}, - { /* end of list */ }, - }; - - mode |= EN_FMRADIO_EN_RDS; - - if (sap) { - dprintk("%s SAP (status: unknown)\n", __func__); - set_audio_start(core, SEL_SAP); - set_audio_registers(core, btsc_sap); - set_audio_finish(core, mode); - } else { - dprintk("%s (status: known-good)\n", __func__); - set_audio_start(core, SEL_BTSC); - set_audio_registers(core, btsc); - set_audio_finish(core, mode); - } -} - -static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode) -{ - static const struct rlist nicam_l[] = { - {AUD_AFE_12DB_EN, 0x00000001}, - {AUD_RATE_ADJ1, 0x00000060}, - {AUD_RATE_ADJ2, 0x000000F9}, - {AUD_RATE_ADJ3, 0x000001CC}, - {AUD_RATE_ADJ4, 0x000002B3}, - {AUD_RATE_ADJ5, 0x00000726}, - {AUD_DEEMPHDENOM1_R, 0x0000F3D0}, - {AUD_DEEMPHDENOM2_R, 0x00000000}, - {AUD_ERRLOGPERIOD_R, 0x00000064}, - {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF}, - {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F}, - {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F}, - {AUD_POLYPH80SCALEFAC, 0x00000003}, - {AUD_DMD_RA_DDS, 0x00C00000}, - {AUD_PLL_INT, 0x0000001E}, - {AUD_PLL_DDS, 0x00000000}, - {AUD_PLL_FRAC, 0x0000E542}, - {AUD_START_TIMER, 0x00000000}, - {AUD_DEEMPHNUMER1_R, 0x000353DE}, - {AUD_DEEMPHNUMER2_R, 0x000001B1}, - {AUD_PDF_DDS_CNST_BYTE2, 0x06}, - {AUD_PDF_DDS_CNST_BYTE1, 0x82}, - {AUD_PDF_DDS_CNST_BYTE0, 0x12}, - {AUD_QAM_MODE, 0x05}, - {AUD_PHACC_FREQ_8MSB, 0x34}, - {AUD_PHACC_FREQ_8LSB, 0x4C}, - {AUD_DEEMPHGAIN_R, 0x00006680}, - {AUD_RATE_THRES_DMD, 0x000000C0}, - { /* end of list */ }, - }; - - static const struct rlist nicam_bgdki_common[] = { - {AUD_AFE_12DB_EN, 0x00000001}, - {AUD_RATE_ADJ1, 0x00000010}, - {AUD_RATE_ADJ2, 0x00000040}, - {AUD_RATE_ADJ3, 0x00000100}, - {AUD_RATE_ADJ4, 0x00000400}, - {AUD_RATE_ADJ5, 0x00001000}, - {AUD_ERRLOGPERIOD_R, 0x00000fff}, - {AUD_ERRINTRPTTHSHLD1_R, 0x000003ff}, - {AUD_ERRINTRPTTHSHLD2_R, 0x000000ff}, - {AUD_ERRINTRPTTHSHLD3_R, 0x0000003f}, - {AUD_POLYPH80SCALEFAC, 0x00000003}, - {AUD_DEEMPHGAIN_R, 0x000023c2}, - {AUD_DEEMPHNUMER1_R, 0x0002a7bc}, - {AUD_DEEMPHNUMER2_R, 0x0003023e}, - {AUD_DEEMPHDENOM1_R, 0x0000f3d0}, - {AUD_DEEMPHDENOM2_R, 0x00000000}, - {AUD_PDF_DDS_CNST_BYTE2, 0x06}, - {AUD_PDF_DDS_CNST_BYTE1, 0x82}, - {AUD_QAM_MODE, 0x05}, - { /* end of list */ }, - }; - - static const struct rlist nicam_i[] = { - {AUD_PDF_DDS_CNST_BYTE0, 0x12}, - {AUD_PHACC_FREQ_8MSB, 0x3a}, - {AUD_PHACC_FREQ_8LSB, 0x93}, - { /* end of list */ }, - }; - - static const struct rlist nicam_default[] = { - {AUD_PDF_DDS_CNST_BYTE0, 0x16}, - {AUD_PHACC_FREQ_8MSB, 0x34}, - {AUD_PHACC_FREQ_8LSB, 0x4c}, - { /* end of list */ }, - }; - - set_audio_start(core,SEL_NICAM); - switch (core->tvaudio) { - case WW_L: - dprintk("%s SECAM-L NICAM (status: devel)\n", __func__); - set_audio_registers(core, nicam_l); - break; - case WW_I: - dprintk("%s PAL-I NICAM (status: known-good)\n", __func__); - set_audio_registers(core, nicam_bgdki_common); - set_audio_registers(core, nicam_i); - break; - case WW_NONE: - case WW_BTSC: - case WW_BG: - case WW_DK: - case WW_EIAJ: - case WW_I2SPT: - case WW_FM: - case WW_I2SADC: - case WW_M: - dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__); - set_audio_registers(core, nicam_bgdki_common); - set_audio_registers(core, nicam_default); - break; - }; - - mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS; - set_audio_finish(core, mode); -} - -static void set_audio_standard_A2(struct cx88_core *core, u32 mode) -{ - static const struct rlist a2_bgdk_common[] = { - {AUD_ERRLOGPERIOD_R, 0x00000064}, - {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, - {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, - {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, - {AUD_PDF_DDS_CNST_BYTE2, 0x06}, - {AUD_PDF_DDS_CNST_BYTE1, 0x82}, - {AUD_PDF_DDS_CNST_BYTE0, 0x12}, - {AUD_QAM_MODE, 0x05}, - {AUD_PHACC_FREQ_8MSB, 0x34}, - {AUD_PHACC_FREQ_8LSB, 0x4c}, - {AUD_RATE_ADJ1, 0x00000100}, - {AUD_RATE_ADJ2, 0x00000200}, - {AUD_RATE_ADJ3, 0x00000300}, - {AUD_RATE_ADJ4, 0x00000400}, - {AUD_RATE_ADJ5, 0x00000500}, - {AUD_THR_FR, 0x00000000}, - {AAGC_HYST, 0x0000001a}, - {AUD_PILOT_BQD_1_K0, 0x0000755b}, - {AUD_PILOT_BQD_1_K1, 0x00551340}, - {AUD_PILOT_BQD_1_K2, 0x006d30be}, - {AUD_PILOT_BQD_1_K3, 0xffd394af}, - {AUD_PILOT_BQD_1_K4, 0x00400000}, - {AUD_PILOT_BQD_2_K0, 0x00040000}, - {AUD_PILOT_BQD_2_K1, 0x002a4841}, - {AUD_PILOT_BQD_2_K2, 0x00400000}, - {AUD_PILOT_BQD_2_K3, 0x00000000}, - {AUD_PILOT_BQD_2_K4, 0x00000000}, - {AUD_MODE_CHG_TIMER, 0x00000040}, - {AUD_AFE_12DB_EN, 0x00000001}, - {AUD_CORDIC_SHIFT_0, 0x00000007}, - {AUD_CORDIC_SHIFT_1, 0x00000007}, - {AUD_DEEMPH0_G0, 0x00000380}, - {AUD_DEEMPH1_G0, 0x00000380}, - {AUD_DCOC_0_SRC, 0x0000001a}, - {AUD_DCOC0_SHIFT, 0x00000000}, - {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, - {AUD_DCOC_PASS_IN, 0x00000003}, - {AUD_IIR3_0_SEL, 0x00000021}, - {AUD_DN2_AFC, 0x00000002}, - {AUD_DCOC_1_SRC, 0x0000001b}, - {AUD_DCOC1_SHIFT, 0x00000000}, - {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, - {AUD_IIR3_1_SEL, 0x00000023}, - {AUD_RDSI_SEL, 0x00000017}, - {AUD_RDSI_SHIFT, 0x00000000}, - {AUD_RDSQ_SEL, 0x00000017}, - {AUD_RDSQ_SHIFT, 0x00000000}, - {AUD_PLL_INT, 0x0000001e}, - {AUD_PLL_DDS, 0x00000000}, - {AUD_PLL_FRAC, 0x0000e542}, - {AUD_POLYPH80SCALEFAC, 0x00000001}, - {AUD_START_TIMER, 0x00000000}, - { /* end of list */ }, - }; - - static const struct rlist a2_bg[] = { - {AUD_DMD_RA_DDS, 0x002a4f2f}, - {AUD_C1_UP_THR, 0x00007000}, - {AUD_C1_LO_THR, 0x00005400}, - {AUD_C2_UP_THR, 0x00005400}, - {AUD_C2_LO_THR, 0x00003000}, - { /* end of list */ }, - }; - - static const struct rlist a2_dk[] = { - {AUD_DMD_RA_DDS, 0x002a4f2f}, - {AUD_C1_UP_THR, 0x00007000}, - {AUD_C1_LO_THR, 0x00005400}, - {AUD_C2_UP_THR, 0x00005400}, - {AUD_C2_LO_THR, 0x00003000}, - {AUD_DN0_FREQ, 0x00003a1c}, - {AUD_DN2_FREQ, 0x0000d2e0}, - { /* end of list */ }, - }; - - static const struct rlist a1_i[] = { - {AUD_ERRLOGPERIOD_R, 0x00000064}, - {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, - {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, - {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, - {AUD_PDF_DDS_CNST_BYTE2, 0x06}, - {AUD_PDF_DDS_CNST_BYTE1, 0x82}, - {AUD_PDF_DDS_CNST_BYTE0, 0x12}, - {AUD_QAM_MODE, 0x05}, - {AUD_PHACC_FREQ_8MSB, 0x3a}, - {AUD_PHACC_FREQ_8LSB, 0x93}, - {AUD_DMD_RA_DDS, 0x002a4f2f}, - {AUD_PLL_INT, 0x0000001e}, - {AUD_PLL_DDS, 0x00000004}, - {AUD_PLL_FRAC, 0x0000e542}, - {AUD_RATE_ADJ1, 0x00000100}, - {AUD_RATE_ADJ2, 0x00000200}, - {AUD_RATE_ADJ3, 0x00000300}, - {AUD_RATE_ADJ4, 0x00000400}, - {AUD_RATE_ADJ5, 0x00000500}, - {AUD_THR_FR, 0x00000000}, - {AUD_PILOT_BQD_1_K0, 0x0000755b}, - {AUD_PILOT_BQD_1_K1, 0x00551340}, - {AUD_PILOT_BQD_1_K2, 0x006d30be}, - {AUD_PILOT_BQD_1_K3, 0xffd394af}, - {AUD_PILOT_BQD_1_K4, 0x00400000}, - {AUD_PILOT_BQD_2_K0, 0x00040000}, - {AUD_PILOT_BQD_2_K1, 0x002a4841}, - {AUD_PILOT_BQD_2_K2, 0x00400000}, - {AUD_PILOT_BQD_2_K3, 0x00000000}, - {AUD_PILOT_BQD_2_K4, 0x00000000}, - {AUD_MODE_CHG_TIMER, 0x00000060}, - {AUD_AFE_12DB_EN, 0x00000001}, - {AAGC_HYST, 0x0000000a}, - {AUD_CORDIC_SHIFT_0, 0x00000007}, - {AUD_CORDIC_SHIFT_1, 0x00000007}, - {AUD_C1_UP_THR, 0x00007000}, - {AUD_C1_LO_THR, 0x00005400}, - {AUD_C2_UP_THR, 0x00005400}, - {AUD_C2_LO_THR, 0x00003000}, - {AUD_DCOC_0_SRC, 0x0000001a}, - {AUD_DCOC0_SHIFT, 0x00000000}, - {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, - {AUD_DCOC_PASS_IN, 0x00000003}, - {AUD_IIR3_0_SEL, 0x00000021}, - {AUD_DN2_AFC, 0x00000002}, - {AUD_DCOC_1_SRC, 0x0000001b}, - {AUD_DCOC1_SHIFT, 0x00000000}, - {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, - {AUD_IIR3_1_SEL, 0x00000023}, - {AUD_DN0_FREQ, 0x000035a3}, - {AUD_DN2_FREQ, 0x000029c7}, - {AUD_CRDC0_SRC_SEL, 0x00000511}, - {AUD_IIR1_0_SEL, 0x00000001}, - {AUD_IIR1_1_SEL, 0x00000000}, - {AUD_IIR3_2_SEL, 0x00000003}, - {AUD_IIR3_2_SHIFT, 0x00000000}, - {AUD_IIR3_0_SEL, 0x00000002}, - {AUD_IIR2_0_SEL, 0x00000021}, - {AUD_IIR2_0_SHIFT, 0x00000002}, - {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, - {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, - {AUD_POLYPH80SCALEFAC, 0x00000001}, - {AUD_START_TIMER, 0x00000000}, - { /* end of list */ }, - }; - - static const struct rlist am_l[] = { - {AUD_ERRLOGPERIOD_R, 0x00000064}, - {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF}, - {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F}, - {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F}, - {AUD_PDF_DDS_CNST_BYTE2, 0x48}, - {AUD_PDF_DDS_CNST_BYTE1, 0x3D}, - {AUD_QAM_MODE, 0x00}, - {AUD_PDF_DDS_CNST_BYTE0, 0xf5}, - {AUD_PHACC_FREQ_8MSB, 0x3a}, - {AUD_PHACC_FREQ_8LSB, 0x4a}, - {AUD_DEEMPHGAIN_R, 0x00006680}, - {AUD_DEEMPHNUMER1_R, 0x000353DE}, - {AUD_DEEMPHNUMER2_R, 0x000001B1}, - {AUD_DEEMPHDENOM1_R, 0x0000F3D0}, - {AUD_DEEMPHDENOM2_R, 0x00000000}, - {AUD_FM_MODE_ENABLE, 0x00000007}, - {AUD_POLYPH80SCALEFAC, 0x00000003}, - {AUD_AFE_12DB_EN, 0x00000001}, - {AAGC_GAIN, 0x00000000}, - {AAGC_HYST, 0x00000018}, - {AAGC_DEF, 0x00000020}, - {AUD_DN0_FREQ, 0x00000000}, - {AUD_POLY0_DDS_CONSTANT, 0x000E4DB2}, - {AUD_DCOC_0_SRC, 0x00000021}, - {AUD_IIR1_0_SEL, 0x00000000}, - {AUD_IIR1_0_SHIFT, 0x00000007}, - {AUD_IIR1_1_SEL, 0x00000002}, - {AUD_IIR1_1_SHIFT, 0x00000000}, - {AUD_DCOC_1_SRC, 0x00000003}, - {AUD_DCOC1_SHIFT, 0x00000000}, - {AUD_DCOC_PASS_IN, 0x00000000}, - {AUD_IIR1_2_SEL, 0x00000023}, - {AUD_IIR1_2_SHIFT, 0x00000000}, - {AUD_IIR1_3_SEL, 0x00000004}, - {AUD_IIR1_3_SHIFT, 0x00000007}, - {AUD_IIR1_4_SEL, 0x00000005}, - {AUD_IIR1_4_SHIFT, 0x00000007}, - {AUD_IIR3_0_SEL, 0x00000007}, - {AUD_IIR3_0_SHIFT, 0x00000000}, - {AUD_DEEMPH0_SRC_SEL, 0x00000011}, - {AUD_DEEMPH0_SHIFT, 0x00000000}, - {AUD_DEEMPH0_G0, 0x00007000}, - {AUD_DEEMPH0_A0, 0x00000000}, - {AUD_DEEMPH0_B0, 0x00000000}, - {AUD_DEEMPH0_A1, 0x00000000}, - {AUD_DEEMPH0_B1, 0x00000000}, - {AUD_DEEMPH1_SRC_SEL, 0x00000011}, - {AUD_DEEMPH1_SHIFT, 0x00000000}, - {AUD_DEEMPH1_G0, 0x00007000}, - {AUD_DEEMPH1_A0, 0x00000000}, - {AUD_DEEMPH1_B0, 0x00000000}, - {AUD_DEEMPH1_A1, 0x00000000}, - {AUD_DEEMPH1_B1, 0x00000000}, - {AUD_OUT0_SEL, 0x0000003F}, - {AUD_OUT1_SEL, 0x0000003F}, - {AUD_DMD_RA_DDS, 0x00F5C285}, - {AUD_PLL_INT, 0x0000001E}, - {AUD_PLL_DDS, 0x00000000}, - {AUD_PLL_FRAC, 0x0000E542}, - {AUD_RATE_ADJ1, 0x00000100}, - {AUD_RATE_ADJ2, 0x00000200}, - {AUD_RATE_ADJ3, 0x00000300}, - {AUD_RATE_ADJ4, 0x00000400}, - {AUD_RATE_ADJ5, 0x00000500}, - {AUD_RATE_THRES_DMD, 0x000000C0}, - { /* end of list */ }, - }; - - static const struct rlist a2_deemph50[] = { - {AUD_DEEMPH0_G0, 0x00000380}, - {AUD_DEEMPH1_G0, 0x00000380}, - {AUD_DEEMPHGAIN_R, 0x000011e1}, - {AUD_DEEMPHNUMER1_R, 0x0002a7bc}, - {AUD_DEEMPHNUMER2_R, 0x0003023c}, - { /* end of list */ }, - }; - - set_audio_start(core, SEL_A2); - switch (core->tvaudio) { - case WW_BG: - dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__); - set_audio_registers(core, a2_bgdk_common); - set_audio_registers(core, a2_bg); - set_audio_registers(core, a2_deemph50); - break; - case WW_DK: - dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__); - set_audio_registers(core, a2_bgdk_common); - set_audio_registers(core, a2_dk); - set_audio_registers(core, a2_deemph50); - break; - case WW_I: - dprintk("%s PAL-I A1 (status: known-good)\n", __func__); - set_audio_registers(core, a1_i); - set_audio_registers(core, a2_deemph50); - break; - case WW_L: - dprintk("%s AM-L (status: devel)\n", __func__); - set_audio_registers(core, am_l); - break; - case WW_NONE: - case WW_BTSC: - case WW_EIAJ: - case WW_I2SPT: - case WW_FM: - case WW_I2SADC: - case WW_M: - dprintk("%s Warning: wrong value\n", __func__); - return; - break; - }; - - mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; - set_audio_finish(core, mode); -} - -static void set_audio_standard_EIAJ(struct cx88_core *core) -{ - static const struct rlist eiaj[] = { - /* TODO: eiaj register settings are not there yet ... */ - - { /* end of list */ }, - }; - dprintk("%s (status: unknown)\n", __func__); - - set_audio_start(core, SEL_EIAJ); - set_audio_registers(core, eiaj); - set_audio_finish(core, EN_EIAJ_AUTO_STEREO); -} - -static void set_audio_standard_FM(struct cx88_core *core, - enum cx88_deemph_type deemph) -{ - static const struct rlist fm_deemph_50[] = { - {AUD_DEEMPH0_G0, 0x0C45}, - {AUD_DEEMPH0_A0, 0x6262}, - {AUD_DEEMPH0_B0, 0x1C29}, - {AUD_DEEMPH0_A1, 0x3FC66}, - {AUD_DEEMPH0_B1, 0x399A}, - - {AUD_DEEMPH1_G0, 0x0D80}, - {AUD_DEEMPH1_A0, 0x6262}, - {AUD_DEEMPH1_B0, 0x1C29}, - {AUD_DEEMPH1_A1, 0x3FC66}, - {AUD_DEEMPH1_B1, 0x399A}, - - {AUD_POLYPH80SCALEFAC, 0x0003}, - { /* end of list */ }, - }; - static const struct rlist fm_deemph_75[] = { - {AUD_DEEMPH0_G0, 0x091B}, - {AUD_DEEMPH0_A0, 0x6B68}, - {AUD_DEEMPH0_B0, 0x11EC}, - {AUD_DEEMPH0_A1, 0x3FC66}, - {AUD_DEEMPH0_B1, 0x399A}, - - {AUD_DEEMPH1_G0, 0x0AA0}, - {AUD_DEEMPH1_A0, 0x6B68}, - {AUD_DEEMPH1_B0, 0x11EC}, - {AUD_DEEMPH1_A1, 0x3FC66}, - {AUD_DEEMPH1_B1, 0x399A}, - - {AUD_POLYPH80SCALEFAC, 0x0003}, - { /* end of list */ }, - }; - - /* It is enough to leave default values? */ - /* No, it's not! The deemphasis registers are reset to the 75us - * values by default. Analyzing the spectrum of the decoded audio - * reveals that "no deemphasis" is the same as 75 us, while the 50 us - * setting results in less deemphasis. */ - static const struct rlist fm_no_deemph[] = { - - {AUD_POLYPH80SCALEFAC, 0x0003}, - { /* end of list */ }, - }; - - dprintk("%s (status: unknown)\n", __func__); - set_audio_start(core, SEL_FMRADIO); - - switch (deemph) { - default: - case FM_NO_DEEMPH: - set_audio_registers(core, fm_no_deemph); - break; - - case FM_DEEMPH_50: - set_audio_registers(core, fm_deemph_50); - break; - - case FM_DEEMPH_75: - set_audio_registers(core, fm_deemph_75); - break; - } - - set_audio_finish(core, EN_FMRADIO_AUTO_STEREO); -} - -/* ----------------------------------------------------------- */ - -static int cx88_detect_nicam(struct cx88_core *core) -{ - int i, j = 0; - - dprintk("start nicam autodetect.\n"); - - for (i = 0; i < 6; i++) { - /* if bit1=1 then nicam is detected */ - j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1); - - if (j == 1) { - dprintk("nicam is detected.\n"); - return 1; - } - - /* wait a little bit for next reading status */ - msleep(10); - } - - dprintk("nicam is not detected.\n"); - return 0; -} - -void cx88_set_tvaudio(struct cx88_core *core) -{ - switch (core->tvaudio) { - case WW_BTSC: - set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); - break; - case WW_BG: - case WW_DK: - case WW_M: - case WW_I: - case WW_L: - /* prepare all dsp registers */ - set_audio_standard_A2(core, EN_A2_FORCE_MONO1); - - /* set nicam mode - otherwise - AUD_NICAM_STATUS2 contains wrong values */ - set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO); - if (0 == cx88_detect_nicam(core)) { - /* fall back to fm / am mono */ - set_audio_standard_A2(core, EN_A2_FORCE_MONO1); - core->audiomode_current = V4L2_TUNER_MODE_MONO; - core->use_nicam = 0; - } else { - core->use_nicam = 1; - } - break; - case WW_EIAJ: - set_audio_standard_EIAJ(core); - break; - case WW_FM: - set_audio_standard_FM(core, radio_deemphasis); - break; - case WW_I2SADC: - set_audio_start(core, 0x01); - /* - * Slave/Philips/Autobaud - * NB on Nova-S bit1 NPhilipsSony appears to be inverted: - * 0= Sony, 1=Philips - */ - cx_write(AUD_I2SINPUTCNTL, core->board.i2sinputcntl); - /* Switch to "I2S ADC mode" */ - cx_write(AUD_I2SCNTL, 0x1); - set_audio_finish(core, EN_I2SIN_ENABLE); - break; - case WW_NONE: - case WW_I2SPT: - printk("%s/0: unknown tv audio mode [%d]\n", - core->name, core->tvaudio); - break; - } - return; -} - -void cx88_newstation(struct cx88_core *core) -{ - core->audiomode_manual = UNSET; - core->last_change = jiffies; -} - -void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) -{ - static const char * const m[] = { "stereo", "dual mono", "mono", "sap" }; - static const char * const p[] = { "no pilot", "pilot c1", "pilot c2", "?" }; - u32 reg, mode, pilot; - - reg = cx_read(AUD_STATUS); - mode = reg & 0x03; - pilot = (reg >> 2) & 0x03; - - if (core->astat != reg) - dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n", - reg, m[mode], p[pilot], - aud_ctl_names[cx_read(AUD_CTL) & 63]); - core->astat = reg; - - t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - t->rxsubchans = UNSET; - t->audmode = V4L2_TUNER_MODE_MONO; - - switch (mode) { - case 0: - t->audmode = V4L2_TUNER_MODE_STEREO; - break; - case 1: - t->audmode = V4L2_TUNER_MODE_LANG2; - break; - case 2: - t->audmode = V4L2_TUNER_MODE_MONO; - break; - case 3: - t->audmode = V4L2_TUNER_MODE_SAP; - break; - } - - switch (core->tvaudio) { - case WW_BTSC: - case WW_BG: - case WW_DK: - case WW_M: - case WW_EIAJ: - if (!core->use_nicam) { - t->rxsubchans = cx88_dsp_detect_stereo_sap(core); - break; - } - break; - case WW_NONE: - case WW_I: - case WW_L: - case WW_I2SPT: - case WW_FM: - case WW_I2SADC: - /* nothing */ - break; - } - - /* If software stereo detection is not supported... */ - if (UNSET == t->rxsubchans) { - t->rxsubchans = V4L2_TUNER_SUB_MONO; - /* If the hardware itself detected stereo, also return - stereo as an available subchannel */ - if (V4L2_TUNER_MODE_STEREO == t->audmode) - t->rxsubchans |= V4L2_TUNER_SUB_STEREO; - } - return; -} - -void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) -{ - u32 ctl = UNSET; - u32 mask = UNSET; - - if (manual) { - core->audiomode_manual = mode; - } else { - if (UNSET != core->audiomode_manual) - return; - } - core->audiomode_current = mode; - - switch (core->tvaudio) { - case WW_BTSC: - switch (mode) { - case V4L2_TUNER_MODE_MONO: - set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_MONO); - break; - case V4L2_TUNER_MODE_LANG1: - set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); - break; - case V4L2_TUNER_MODE_LANG2: - set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP); - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO); - break; - } - break; - case WW_BG: - case WW_DK: - case WW_M: - case WW_I: - case WW_L: - if (1 == core->use_nicam) { - switch (mode) { - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - set_audio_standard_NICAM(core, - EN_NICAM_FORCE_MONO1); - break; - case V4L2_TUNER_MODE_LANG2: - set_audio_standard_NICAM(core, - EN_NICAM_FORCE_MONO2); - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - set_audio_standard_NICAM(core, - EN_NICAM_FORCE_STEREO); - break; - } - } else { - if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) { - /* fall back to fm / am mono */ - set_audio_standard_A2(core, EN_A2_FORCE_MONO1); - } else { - /* TODO: Add A2 autodection */ - mask = 0x3f; - switch (mode) { - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - ctl = EN_A2_FORCE_MONO1; - break; - case V4L2_TUNER_MODE_LANG2: - ctl = EN_A2_FORCE_MONO2; - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - ctl = EN_A2_FORCE_STEREO; - break; - } - } - } - break; - case WW_FM: - switch (mode) { - case V4L2_TUNER_MODE_MONO: - ctl = EN_FMRADIO_FORCE_MONO; - mask = 0x3f; - break; - case V4L2_TUNER_MODE_STEREO: - ctl = EN_FMRADIO_AUTO_STEREO; - mask = 0x3f; - break; - } - break; - case WW_I2SADC: - case WW_NONE: - case WW_EIAJ: - case WW_I2SPT: - /* DO NOTHING */ - break; - } - - if (UNSET != ctl) { - dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x " - "[status=0x%x,ctl=0x%x,vol=0x%x]\n", - mask, ctl, cx_read(AUD_STATUS), - cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL)); - cx_andor(AUD_CTL, mask, ctl); - } - return; -} - -int cx88_audio_thread(void *data) -{ - struct cx88_core *core = data; - struct v4l2_tuner t; - u32 mode = 0; - - dprintk("cx88: tvaudio thread started\n"); - set_freezable(); - for (;;) { - msleep_interruptible(1000); - if (kthread_should_stop()) - break; - try_to_freeze(); - - switch (core->tvaudio) { - case WW_BG: - case WW_DK: - case WW_M: - case WW_I: - case WW_L: - if (core->use_nicam) - goto hw_autodetect; - - /* just monitor the audio status for now ... */ - memset(&t, 0, sizeof(t)); - cx88_get_stereo(core, &t); - - if (UNSET != core->audiomode_manual) - /* manually set, don't do anything. */ - continue; - - /* monitor signal and set stereo if available */ - if (t.rxsubchans & V4L2_TUNER_SUB_STEREO) - mode = V4L2_TUNER_MODE_STEREO; - else - mode = V4L2_TUNER_MODE_MONO; - if (mode == core->audiomode_current) - continue; - /* automatically switch to best available mode */ - cx88_set_stereo(core, mode, 0); - break; - case WW_NONE: - case WW_BTSC: - case WW_EIAJ: - case WW_I2SPT: - case WW_FM: - case WW_I2SADC: -hw_autodetect: - /* stereo autodetection is supported by hardware so - we don't need to do it manually. Do nothing. */ - break; - } - } - - dprintk("cx88: tvaudio thread exiting\n"); - return 0; -} - -/* ----------------------------------------------------------- */ - -EXPORT_SYMBOL(cx88_set_tvaudio); -EXPORT_SYMBOL(cx88_newstation); -EXPORT_SYMBOL(cx88_set_stereo); -EXPORT_SYMBOL(cx88_get_stereo); -EXPORT_SYMBOL(cx88_audio_thread); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vbi.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -/* - */ -#include -#include -#include - -#include "cx88.h" - -static unsigned int vbibufs = 4; -module_param(vbibufs,int,0644); -MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); - -static unsigned int vbi_debug; -module_param(vbi_debug,int,0644); -MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); - -#define dprintk(level,fmt, arg...) if (vbi_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg) - -/* ------------------------------------------------------------------ */ - -int cx8800_vbi_fmt (struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx8800_fh *fh = priv; - struct cx8800_dev *dev = fh->dev; - - f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; - f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 244; - f->fmt.vbi.count[0] = VBI_LINE_COUNT; - f->fmt.vbi.count[1] = VBI_LINE_COUNT; - - if (dev->core->tvnorm & V4L2_STD_525_60) { - /* ntsc */ - f->fmt.vbi.sampling_rate = 28636363; - f->fmt.vbi.start[0] = 10; - f->fmt.vbi.start[1] = 273; - - } else if (dev->core->tvnorm & V4L2_STD_625_50) { - /* pal */ - f->fmt.vbi.sampling_rate = 35468950; - f->fmt.vbi.start[0] = 7 -1; - f->fmt.vbi.start[1] = 319 -1; - } - return 0; -} - -static int cx8800_start_vbi_dma(struct cx8800_dev *dev, - struct cx88_dmaqueue *q, - struct cx88_buffer *buf) -{ - struct cx88_core *core = dev->core; - - /* setup fifo + format */ - cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24], - buf->vb.width, buf->risc.dma); - - cx_write(MO_VBOS_CONTROL, ( (1 << 18) | // comb filter delay fixup - (1 << 15) | // enable vbi capture - (1 << 11) )); - - /* reset counter */ - cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET); - q->count = 1; - - /* enable irqs */ - cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); - cx_set(MO_VID_INTMSK, 0x0f0088); - - /* enable capture */ - cx_set(VID_CAPTURE_CONTROL,0x18); - - /* start dma */ - cx_set(MO_DEV_CNTRL2, (1<<5)); - cx_set(MO_VID_DMACNTRL, 0x88); - - return 0; -} - -int cx8800_stop_vbi_dma(struct cx8800_dev *dev) -{ - struct cx88_core *core = dev->core; - - /* stop dma */ - cx_clear(MO_VID_DMACNTRL, 0x88); - - /* disable capture */ - cx_clear(VID_CAPTURE_CONTROL,0x18); - - /* disable irqs */ - cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); - cx_clear(MO_VID_INTMSK, 0x0f0088); - return 0; -} - -int cx8800_restart_vbi_queue(struct cx8800_dev *dev, - struct cx88_dmaqueue *q) -{ - struct cx88_buffer *buf; - - if (list_empty(&q->active)) - return 0; - - buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx8800_start_vbi_dma(dev, q, buf); - list_for_each_entry(buf, &q->active, vb.queue) - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; -} - -void cx8800_vbi_timeout(unsigned long data) -{ - struct cx8800_dev *dev = (struct cx8800_dev*)data; - struct cx88_core *core = dev->core; - struct cx88_dmaqueue *q = &dev->vbiq; - struct cx88_buffer *buf; - unsigned long flags; - - cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH24]); - - cx_clear(MO_VID_DMACNTRL, 0x88); - cx_clear(VID_CAPTURE_CONTROL, 0x18); - - spin_lock_irqsave(&dev->slock,flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name, - buf, buf->vb.i, (unsigned long)buf->risc.dma); - } - cx8800_restart_vbi_queue(dev,q); - spin_unlock_irqrestore(&dev->slock,flags); -} - -/* ------------------------------------------------------------------ */ - -static int -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 == *count) - *count = vbibufs; - if (*count < 2) - *count = 2; - if (*count > 32) - *count = 32; - return 0; -} - -static int -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx8800_fh *fh = q->priv_data; - struct cx8800_dev *dev = fh->dev; - struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); - unsigned int size; - int rc; - - size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - buf->vb.width = VBI_LINE_LENGTH; - buf->vb.height = VBI_LINE_COUNT; - buf->vb.size = size; - buf->vb.field = V4L2_FIELD_SEQ_TB; - - if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) - goto fail; - cx88_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->vb.width * buf->vb.height, - buf->vb.width, 0, - buf->vb.height); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - cx88_free_buffer(q,buf); - return rc; -} - -static void -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); - struct cx88_buffer *prev; - struct cx8800_fh *fh = vq->priv_data; - struct cx8800_dev *dev = fh->dev; - struct cx88_dmaqueue *q = &dev->vbiq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - - if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue,&q->active); - cx8800_start_vbi_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2,"[%p/%d] vbi_queue - first active\n", - buf, buf->vb.i); - - } else { - prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(2,"[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - } -} - -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); - - cx88_free_buffer(q,buf); -} - -const struct videobuf_queue_ops cx8800_vbi_qops = { - .buf_setup = vbi_setup, - .buf_prepare = vbi_prepare, - .buf_queue = vbi_queue, - .buf_release = vbi_release, -}; - -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2166 +0,0 @@ -/* - * - * device driver for Conexant 2388x based TV cards - * video4linux video interface - * - * (c) 2003-04 Gerd Knorr [SuSE Labs] - * - * (c) 2005-2006 Mauro Carvalho Chehab - * - Multituner support - * - video_ioctl2 conversion - * - PAL/M fixes - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx88.h" -#include -#include -#include - -MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------------ */ - -static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; - -module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); - -MODULE_PARM_DESC(video_nr,"video device numbers"); -MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); -MODULE_PARM_DESC(radio_nr,"radio device numbers"); - -static unsigned int video_debug; -module_param(video_debug,int,0644); -MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); - -static unsigned int irq_debug; -module_param(irq_debug,int,0644); -MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); - -static unsigned int vid_limit = 16; -module_param(vid_limit,int,0644); -MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); - -#define dprintk(level,fmt, arg...) if (video_debug >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) - -/* ------------------------------------------------------------------- */ -/* static data */ - -static const struct cx8800_fmt formats[] = { - { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .cxformat = ColorFormatY8, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "15 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .cxformat = ColorFormatRGB15, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "15 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB555X, - .cxformat = ColorFormatRGB15 | ColorFormatBSWAP, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "16 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB565, - .cxformat = ColorFormatRGB16, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "16 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB565X, - .cxformat = ColorFormatRGB16 | ColorFormatBSWAP, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "24 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR24, - .cxformat = ColorFormatRGB24, - .depth = 24, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "32 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR32, - .cxformat = ColorFormatRGB32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "32 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB32, - .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .cxformat = ColorFormatYUY2, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .cxformat = ColorFormatYUY2 | ColorFormatBSWAP, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, -}; - -static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(formats); i++) - if (formats[i].fourcc == fourcc) - return formats+i; - return NULL; -} - -/* ------------------------------------------------------------------- */ - -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static const struct cx88_ctrl cx8800_ctls[] = { - /* --- video --- */ - { - .v = { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = MO_CONTR_BRIGHT, - .mask = 0x00ff, - .shift = 0, - },{ - .v = { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = MO_CONTR_BRIGHT, - .mask = 0xff00, - .shift = 8, - },{ - .v = { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = MO_HUE, - .mask = 0x00ff, - .shift = 0, - },{ - /* strictly, this only describes only U saturation. - * V saturation is handled specially through code. - */ - .v = { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = MO_UV_SATURATION, - .mask = 0x00ff, - .shift = 0, - },{ - .v = { - .id = V4L2_CID_CHROMA_AGC, - .name = "Chroma AGC", - .minimum = 0, - .maximum = 1, - .default_value = 0x1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = MO_INPUT_FORMAT, - .mask = 1 << 10, - .shift = 10, - }, { - .v = { - .id = V4L2_CID_COLOR_KILLER, - .name = "Color killer", - .minimum = 0, - .maximum = 1, - .default_value = 0x1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = MO_INPUT_FORMAT, - .mask = 1 << 9, - .shift = 9, - }, { - /* --- audio --- */ - .v = { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = AUD_VOL_CTL, - .sreg = SHADOW_AUD_VOL_CTL, - .mask = (1 << 6), - .shift = 6, - },{ - .v = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = AUD_VOL_CTL, - .sreg = SHADOW_AUD_VOL_CTL, - .mask = 0x3f, - .shift = 0, - },{ - .v = { - .id = V4L2_CID_AUDIO_BALANCE, - .name = "Balance", - .minimum = 0, - .maximum = 0x7f, - .step = 1, - .default_value = 0x40, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = AUD_BAL_CTL, - .sreg = SHADOW_AUD_BAL_CTL, - .mask = 0x7f, - .shift = 0, - } -}; -enum { CX8800_CTLS = ARRAY_SIZE(cx8800_ctls) }; - -/* Must be sorted from low to high control ID! */ -const u32 cx88_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_BALANCE, - V4L2_CID_AUDIO_MUTE, - V4L2_CID_CHROMA_AGC, - V4L2_CID_COLOR_KILLER, - 0 -}; -EXPORT_SYMBOL(cx88_user_ctrls); - -static const u32 * const ctrl_classes[] = { - cx88_user_ctrls, - NULL -}; - -int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || - qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX8800_CTLS; i++) - if (cx8800_ctls[i].v.id == qctrl->id) - break; - if (i == CX8800_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx8800_ctls[i].v; - /* Report chroma AGC as inactive when SECAM is selected */ - if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC && - core->tvnorm & V4L2_STD_SECAM) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - - return 0; -} -EXPORT_SYMBOL(cx8800_ctrl_query); - -/* ------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit) -{ - struct cx88_core *core = dev->core; - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - mutex_lock(&core->lock); - if (dev->resources & bit) { - /* no, someone else uses it */ - mutex_unlock(&core->lock); - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(1,"res: get %d\n",bit); - mutex_unlock(&core->lock); - return 1; -} - -static -int res_check(struct cx8800_fh *fh, unsigned int bit) -{ - return (fh->resources & bit); -} - -static -int res_locked(struct cx8800_dev *dev, unsigned int bit) -{ - return (dev->resources & bit); -} - -static -void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits) -{ - struct cx88_core *core = dev->core; - BUG_ON((fh->resources & bits) != bits); - - mutex_lock(&core->lock); - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk(1,"res: put %d\n",bits); - mutex_unlock(&core->lock); -} - -/* ------------------------------------------------------------------ */ - -int cx88_video_mux(struct cx88_core *core, unsigned int input) -{ - /* struct cx88_core *core = dev->core; */ - - dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", - input, INPUT(input).vmux, - INPUT(input).gpio0,INPUT(input).gpio1, - INPUT(input).gpio2,INPUT(input).gpio3); - core->input = input; - cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14); - cx_write(MO_GP3_IO, INPUT(input).gpio3); - cx_write(MO_GP0_IO, INPUT(input).gpio0); - cx_write(MO_GP1_IO, INPUT(input).gpio1); - cx_write(MO_GP2_IO, INPUT(input).gpio2); - - switch (INPUT(input).type) { - case CX88_VMUX_SVIDEO: - cx_set(MO_AFECFG_IO, 0x00000001); - cx_set(MO_INPUT_FORMAT, 0x00010010); - cx_set(MO_FILTER_EVEN, 0x00002020); - cx_set(MO_FILTER_ODD, 0x00002020); - break; - default: - cx_clear(MO_AFECFG_IO, 0x00000001); - cx_clear(MO_INPUT_FORMAT, 0x00010010); - cx_clear(MO_FILTER_EVEN, 0x00002020); - cx_clear(MO_FILTER_ODD, 0x00002020); - break; - } - - /* if there are audioroutes defined, we have an external - ADC to deal with audio */ - if (INPUT(input).audioroute) { - /* The wm8775 module has the "2" route hardwired into - the initialization. Some boards may use different - routes for different inputs. HVR-1300 surely does */ - if (core->board.audio_chip && - core->board.audio_chip == V4L2_IDENT_WM8775) { - call_all(core, audio, s_routing, - INPUT(input).audioroute, 0, 0); - } - /* cx2388's C-ADC is connected to the tuner only. - When used with S-Video, that ADC is busy dealing with - chroma, so an external must be used for baseband audio */ - if (INPUT(input).type != CX88_VMUX_TELEVISION && - INPUT(input).type != CX88_VMUX_CABLE) { - /* "I2S ADC mode" */ - core->tvaudio = WW_I2SADC; - cx88_set_tvaudio(core); - } else { - /* Normal mode */ - cx_write(AUD_I2SCNTL, 0x0); - cx_clear(AUD_CTL, EN_I2SIN_ENABLE); - } - } - - return 0; -} -EXPORT_SYMBOL(cx88_video_mux); - -/* ------------------------------------------------------------------ */ - -static int start_video_dma(struct cx8800_dev *dev, - struct cx88_dmaqueue *q, - struct cx88_buffer *buf) -{ - struct cx88_core *core = dev->core; - - /* setup fifo + format */ - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], - buf->bpl, buf->risc.dma); - cx88_set_scale(core, buf->vb.width, buf->vb.height, buf->vb.field); - cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma); - - /* reset counter */ - cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET); - q->count = 1; - - /* enable irqs */ - cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); - - /* Enables corresponding bits at PCI_INT_STAT: - bits 0 to 4: video, audio, transport stream, VIP, Host - bit 7: timer - bits 8 and 9: DMA complete for: SRC, DST - bits 10 and 11: BERR signal asserted for RISC: RD, WR - bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB - */ - cx_set(MO_VID_INTMSK, 0x0f0011); - - /* enable capture */ - cx_set(VID_CAPTURE_CONTROL,0x06); - - /* start dma */ - cx_set(MO_DEV_CNTRL2, (1<<5)); - cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */ - - return 0; -} - -#ifdef CONFIG_PM -static int stop_video_dma(struct cx8800_dev *dev) -{ - struct cx88_core *core = dev->core; - - /* stop dma */ - cx_clear(MO_VID_DMACNTRL, 0x11); - - /* disable capture */ - cx_clear(VID_CAPTURE_CONTROL,0x06); - - /* disable irqs */ - cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); - cx_clear(MO_VID_INTMSK, 0x0f0011); - return 0; -} -#endif - -static int restart_video_queue(struct cx8800_dev *dev, - struct cx88_dmaqueue *q) -{ - struct cx88_core *core = dev->core; - struct cx88_buffer *buf, *prev; - - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - start_video_dma(dev, q, buf); - list_for_each_entry(buf, &q->active, vb.queue) - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(2,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); - } else { - return 0; - } - prev = buf; - } -} - -/* ------------------------------------------------------------------ */ - -static int -buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct cx8800_fh *fh = q->priv_data; - - *size = fh->fmt->depth*fh->width*fh->height >> 3; - if (0 == *count) - *count = 32; - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; - return 0; -} - -static int -buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx8800_fh *fh = q->priv_data; - struct cx8800_dev *dev = fh->dev; - struct cx88_core *core = dev->core; - struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - int rc, init_buffer = 0; - - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) - return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - init_buffer = 1; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) - goto fail; - } - - if (init_buffer) { - buf->bpl = buf->vb.width * buf->fmt->depth >> 3; - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx88_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx88_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - cx88_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, buf->bpl, - buf->bpl, buf->bpl, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx88_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx88_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, - buf->vb.height >> 1); - break; - default: - BUG(); - } - } - dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, - fh->width, fh->height, fh->fmt->depth, fh->fmt->name, - (unsigned long)buf->risc.dma); - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - cx88_free_buffer(q,buf); - return rc; -} - -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); - struct cx88_buffer *prev; - struct cx8800_fh *fh = vq->priv_data; - struct cx8800_dev *dev = fh->dev; - struct cx88_core *core = dev->core; - struct cx88_dmaqueue *q = &dev->vidq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2,"[%p/%d] buffer_queue - append to queued\n", - buf, buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue,&q->active); - start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2,"[%p/%d] buffer_queue - first active\n", - buf, buf->vb.i); - - } else { - prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); - if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(2,"[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - - } else { - list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2,"[%p/%d] buffer_queue - first queued\n", - buf, buf->vb.i); - } - } -} - -static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); - - cx88_free_buffer(q,buf); -} - -static const struct videobuf_queue_ops cx8800_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ */ - - -/* ------------------------------------------------------------------ */ - -static struct videobuf_queue* get_queue(struct cx8800_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &fh->vidq; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return &fh->vbiq; - default: - BUG(); - return NULL; - } -} - -static int get_ressource(struct cx8800_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return RESOURCE_VBI; - default: - BUG(); - return 0; - } -} - -static int video_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct cx8800_dev *dev = video_drvdata(file); - struct cx88_core *core = dev->core; - struct cx8800_fh *fh; - enum v4l2_buf_type type = 0; - int radio = 0; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - } - - dprintk(1, "open dev=%s radio=%d type=%s\n", - video_device_node_name(vdev), radio, v4l2_type_names[type]); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (unlikely(!fh)) - return -ENOMEM; - - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - fh->type = type; - fh->width = 320; - fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - - mutex_lock(&core->lock); - - videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx88_buffer), - fh, NULL); - videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct cx88_buffer), - fh, NULL); - - if (fh->radio) { - dprintk(1,"video_open: setting radio device\n"); - cx_write(MO_GP3_IO, core->board.radio.gpio3); - cx_write(MO_GP0_IO, core->board.radio.gpio0); - cx_write(MO_GP1_IO, core->board.radio.gpio1); - cx_write(MO_GP2_IO, core->board.radio.gpio2); - if (core->board.radio.audioroute) { - if(core->board.audio_chip && - core->board.audio_chip == V4L2_IDENT_WM8775) { - call_all(core, audio, s_routing, - core->board.radio.audioroute, 0, 0); - } - /* "I2S ADC mode" */ - core->tvaudio = WW_I2SADC; - cx88_set_tvaudio(core); - } else { - /* FM Mode */ - core->tvaudio = WW_FM; - cx88_set_tvaudio(core); - cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); - } - call_all(core, tuner, s_radio); - } - - atomic_inc(&core->users); - mutex_unlock(&core->lock); - - return 0; -} - -static ssize_t -video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct cx8800_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (res_locked(fh->dev,RESOURCE_VIDEO)) - return -EBUSY; - return videobuf_read_one(&fh->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (!res_get(fh->dev,fh,RESOURCE_VBI)) - return -EBUSY; - return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - default: - BUG(); - return 0; - } -} - -static unsigned int -video_poll(struct file *file, struct poll_table_struct *wait) -{ - struct cx8800_fh *fh = file->private_data; - struct cx88_buffer *buf; - unsigned int rc = POLLERR; - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - if (!res_get(fh->dev,fh,RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbiq, wait); - } - - mutex_lock(&fh->vidq.vb_lock); - if (res_check(fh,RESOURCE_VIDEO)) { - /* streaming capture */ - if (list_empty(&fh->vidq.stream)) - goto done; - buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream); - } else { - /* read() capture */ - buf = (struct cx88_buffer*)fh->vidq.read_buf; - if (NULL == buf) - goto done; - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; -done: - mutex_unlock(&fh->vidq.vb_lock); - return rc; -} - -static int video_release(struct file *file) -{ - struct cx8800_fh *fh = file->private_data; - struct cx8800_dev *dev = fh->dev; - - /* turn off overlay */ - if (res_check(fh, RESOURCE_OVERLAY)) { - /* FIXME */ - res_free(dev,fh,RESOURCE_OVERLAY); - } - - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_queue_cancel(&fh->vidq); - res_free(dev,fh,RESOURCE_VIDEO); - } - if (fh->vidq.read_buf) { - buffer_release(&fh->vidq,fh->vidq.read_buf); - kfree(fh->vidq.read_buf); - } - - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - videobuf_stop(&fh->vbiq); - res_free(dev,fh,RESOURCE_VBI); - } - - videobuf_mmap_free(&fh->vidq); - videobuf_mmap_free(&fh->vbiq); - - mutex_lock(&dev->core->lock); - file->private_data = NULL; - kfree(fh); - - if(atomic_dec_and_test(&dev->core->users)) - call_all(dev->core, core, s_power, 0); - mutex_unlock(&dev->core->lock); - - return 0; -} - -static int -video_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct cx8800_fh *fh = file->private_data; - - return videobuf_mmap_mapper(get_queue(fh), vma); -} - -/* ------------------------------------------------------------------ */ -/* VIDEO CTRL IOCTLS */ - -int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl) -{ - const struct cx88_ctrl *c = NULL; - u32 value; - int i; - - for (i = 0; i < CX8800_CTLS; i++) - if (cx8800_ctls[i].v.id == ctl->id) - c = &cx8800_ctls[i]; - if (unlikely(NULL == c)) - return -EINVAL; - - value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); - switch (ctl->id) { - case V4L2_CID_AUDIO_BALANCE: - ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) - : (0x7f - (value & 0x7f)); - break; - case V4L2_CID_AUDIO_VOLUME: - ctl->value = 0x3f - (value & 0x3f); - break; - default: - ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; - break; - } - dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctl->id, c->v.name, ctl->value, c->reg, - value,c->mask, c->sreg ? " [shadowed]" : ""); - return 0; -} -EXPORT_SYMBOL(cx88_get_control); - -int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) -{ - const struct cx88_ctrl *c = NULL; - u32 value,mask; - int i; - - for (i = 0; i < CX8800_CTLS; i++) { - if (cx8800_ctls[i].v.id == ctl->id) { - c = &cx8800_ctls[i]; - } - } - if (unlikely(NULL == c)) - return -EINVAL; - - if (ctl->value < c->v.minimum) - ctl->value = c->v.minimum; - if (ctl->value > c->v.maximum) - ctl->value = c->v.maximum; - - /* Pass changes onto any WM8775 */ - if (core->board.audio_chip == V4L2_IDENT_WM8775) { - struct v4l2_control client_ctl; - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.id = ctl->id; - - switch (ctl->id) { - case V4L2_CID_AUDIO_MUTE: - client_ctl.value = ctl->value; - break; - case V4L2_CID_AUDIO_VOLUME: - client_ctl.value = (ctl->value) ? - (0x90 + ctl->value) << 8 : 0; - break; - case V4L2_CID_AUDIO_BALANCE: - client_ctl.value = ctl->value << 9; - break; - default: - client_ctl.id = 0; - break; - } - if (client_ctl.id) - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - } - - mask=c->mask; - switch (ctl->id) { - case V4L2_CID_AUDIO_BALANCE: - value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); - break; - case V4L2_CID_AUDIO_VOLUME: - value = 0x3f - (ctl->value & 0x3f); - break; - case V4L2_CID_SATURATION: - /* special v_sat handling */ - - value = ((ctl->value - c->off) << c->shift) & c->mask; - - if (core->tvnorm & V4L2_STD_SECAM) { - /* For SECAM, both U and V sat should be equal */ - value=value<<8|value; - } else { - /* Keeps U Saturation proportional to V Sat */ - value=(value*0x5a)/0x7f<<8|value; - } - mask=0xffff; - break; - case V4L2_CID_CHROMA_AGC: - /* Do not allow chroma AGC to be enabled for SECAM */ - value = ((ctl->value - c->off) << c->shift) & c->mask; - if (core->tvnorm & V4L2_STD_SECAM && value) - return -EINVAL; - break; - default: - value = ((ctl->value - c->off) << c->shift) & c->mask; - break; - } - dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctl->id, c->v.name, ctl->value, c->reg, value, - mask, c->sreg ? " [shadowed]" : ""); - if (c->sreg) { - cx_sandor(c->sreg, c->reg, mask, value); - } else { - cx_andor(c->reg, mask, value); - } - return 0; -} -EXPORT_SYMBOL(cx88_set_control); - -static void init_controls(struct cx88_core *core) -{ - struct v4l2_control ctrl; - int i; - - for (i = 0; i < CX8800_CTLS; i++) { - ctrl.id=cx8800_ctls[i].v.id; - ctrl.value=cx8800_ctls[i].v.default_value; - - cx88_set_control(core, &ctrl); - } -} - -/* ------------------------------------------------------------------ */ -/* VIDEO IOCTLS */ - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx8800_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - const struct cx8800_fmt *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - maxw = norm_maxw(core->tvnorm); - maxh = norm_maxh(core->tvnorm); - - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - f->fmt.pix.field = field; - v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, - &f->fmt.pix.height, 32, maxh, 0, 0); - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx8800_fh *fh = priv; - int err = vidioc_try_fmt_vid_cap (file,priv,f); - - if (0 != err) - return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->vidq.field = f->fmt.pix.field; - return 0; -} - -static int vidioc_querycap (struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; - struct cx88_core *core = dev->core; - - strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, core->board.name, sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VBI_CAPTURE; - if (UNSET != core->board.tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (unlikely(f->index >= ARRAY_SIZE(formats))) - return -EINVAL; - - strlcpy(f->description,formats[f->index].name,sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; - - return 0; -} - -static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) -{ - struct cx8800_fh *fh = priv; - return (videobuf_reqbufs(get_queue(fh), p)); -} - -static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx8800_fh *fh = priv; - return (videobuf_querybuf(get_queue(fh), p)); -} - -static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx8800_fh *fh = priv; - return (videobuf_qbuf(get_queue(fh), p)); -} - -static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx8800_fh *fh = priv; - return (videobuf_dqbuf(get_queue(fh), p, - file->f_flags & O_NONBLOCK)); -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx8800_fh *fh = priv; - struct cx8800_dev *dev = fh->dev; - - /* We should remember that this driver also supports teletext, */ - /* so we have to test if the v4l2_buf_type is VBI capture data. */ - if (unlikely((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))) - return -EINVAL; - - if (unlikely(i != fh->type)) - return -EINVAL; - - if (unlikely(!res_get(dev,fh,get_ressource(fh)))) - return -EBUSY; - return videobuf_streamon(get_queue(fh)); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx8800_fh *fh = priv; - struct cx8800_dev *dev = fh->dev; - int err, res; - - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - if (i != fh->type) - return -EINVAL; - - res = get_ressource(fh); - err = videobuf_streamoff(get_queue(fh)); - if (err < 0) - return err; - res_free(dev,fh,res); - return 0; -} - -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - - mutex_lock(&core->lock); - cx88_set_tvnorm(core,*tvnorms); - mutex_unlock(&core->lock); - - return 0; -} - -/* only one input in this sample driver */ -int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) -{ - static const char * const iname[] = { - [ CX88_VMUX_COMPOSITE1 ] = "Composite1", - [ CX88_VMUX_COMPOSITE2 ] = "Composite2", - [ CX88_VMUX_COMPOSITE3 ] = "Composite3", - [ CX88_VMUX_COMPOSITE4 ] = "Composite4", - [ CX88_VMUX_SVIDEO ] = "S-Video", - [ CX88_VMUX_TELEVISION ] = "Television", - [ CX88_VMUX_CABLE ] = "Cable TV", - [ CX88_VMUX_DVB ] = "DVB", - [ CX88_VMUX_DEBUG ] = "for debug only", - }; - unsigned int n = i->index; - - if (n >= 4) - return -EINVAL; - if (0 == INPUT(n).type) - return -EINVAL; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,iname[INPUT(n).type]); - if ((CX88_VMUX_TELEVISION == INPUT(n).type) || - (CX88_VMUX_CABLE == INPUT(n).type)) { - i->type = V4L2_INPUT_TYPE_TUNER; - i->std = CX88_NORMS; - } - return 0; -} -EXPORT_SYMBOL(cx88_enum_input); - -static int vidioc_enum_input (struct file *file, void *priv, - struct v4l2_input *i) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - return cx88_enum_input (core,i); -} - -static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - - *i = core->input; - return 0; -} - -static int vidioc_s_input (struct file *file, void *priv, unsigned int i) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - - if (i >= 4) - return -EINVAL; - - mutex_lock(&core->lock); - cx88_newstation(core); - cx88_video_mux(core,i); - mutex_unlock(&core->lock); - return 0; -} - - - -static int vidioc_queryctrl (struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx8800_ctrl_query(core, qctrl); -} - -static int vidioc_g_ctrl (struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - return - cx88_get_control(core,ctl); -} - -static int vidioc_s_ctrl (struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - return - cx88_set_control(core,ctl); -} - -static int vidioc_g_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - u32 reg; - - if (unlikely(UNSET == core->board.tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - - cx88_get_stereo(core ,t); - reg = cx_read(MO_DEVICE_STATUS); - t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; - return 0; -} - -static int vidioc_s_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - - if (UNSET == core->board.tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - cx88_set_stereo(core, t->audmode, 1); - return 0; -} - -static int vidioc_g_frequency (struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx8800_fh *fh = priv; - struct cx88_core *core = fh->dev->core; - - if (unlikely(UNSET == core->board.tuner_type)) - return -EINVAL; - - /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = core->freq; - - call_all(core, tuner, g_frequency, f); - - return 0; -} - -int cx88_set_freq (struct cx88_core *core, - struct v4l2_frequency *f) -{ - if (unlikely(UNSET == core->board.tuner_type)) - return -EINVAL; - if (unlikely(f->tuner != 0)) - return -EINVAL; - - mutex_lock(&core->lock); - core->freq = f->frequency; - cx88_newstation(core); - call_all(core, tuner, s_frequency, f); - - /* When changing channels it is required to reset TVAUDIO */ - msleep (10); - cx88_set_tvaudio(core); - - mutex_unlock(&core->lock); - - return 0; -} -EXPORT_SYMBOL(cx88_set_freq); - -static int vidioc_s_frequency (struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx8800_fh *fh = priv; - struct cx88_core *core = fh->dev->core; - - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; - - return - cx88_set_freq (core,f); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register (struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - /* cx2388x has a 24-bit register space */ - reg->val = cx_read(reg->reg & 0xffffff); - reg->size = 4; - return 0; -} - -static int vidioc_s_register (struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - cx_write(reg->reg & 0xffffff, reg->val); - return 0; -} -#endif - -/* ----------------------------------------------------------- */ -/* RADIO ESPECIFIC IOCTLS */ -/* ----------------------------------------------------------- */ - -static int radio_querycap (struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; - struct cx88_core *core = dev->core; - - strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, core->board.name, sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); - cap->version = CX88_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int radio_g_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - - if (unlikely(t->index > 0)) - return -EINVAL; - - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - call_all(core, tuner, g_tuner, t); - return 0; -} - -static int radio_enum_input (struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - strcpy(i->name,"Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name,"Radio"); - return 0; -} - -/* FIXME: Should add a standard for radio */ - -static int radio_s_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - - if (0 != t->index) - return -EINVAL; - - call_all(core, tuner, s_tuner, t); - - return 0; -} - -static int radio_s_audio (struct file *file, void *fh, - struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input (struct file *file, void *fh, unsigned int i) -{ - return 0; -} - -static int radio_queryctrl (struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - int i; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE || - c->id == V4L2_CID_AUDIO_VOLUME || - c->id == V4L2_CID_AUDIO_BALANCE) { - for (i = 0; i < CX8800_CTLS; i++) { - if (cx8800_ctls[i].v.id == c->id) - break; - } - if (i == CX8800_CTLS) - return -EINVAL; - *c = cx8800_ctls[i].v; - } else - *c = no_ctl; - return 0; -} - -/* ----------------------------------------------------------- */ - -static void cx8800_vid_timeout(unsigned long data) -{ - struct cx8800_dev *dev = (struct cx8800_dev*)data; - struct cx88_core *core = dev->core; - struct cx88_dmaqueue *q = &dev->vidq; - struct cx88_buffer *buf; - unsigned long flags; - - cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); - - cx_clear(MO_VID_DMACNTRL, 0x11); - cx_clear(VID_CAPTURE_CONTROL, 0x06); - - spin_lock_irqsave(&dev->slock,flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, - buf, buf->vb.i, (unsigned long)buf->risc.dma); - } - restart_video_queue(dev,q); - spin_unlock_irqrestore(&dev->slock,flags); -} - -static const char *cx88_vid_irqs[32] = { - "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", - "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", - "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", - "y_sync", "u_sync", "v_sync", "vbi_sync", - "opc_err", "par_err", "rip_err", "pci_abort", -}; - -static void cx8800_vid_irq(struct cx8800_dev *dev) -{ - struct cx88_core *core = dev->core; - u32 status, mask, count; - - status = cx_read(MO_VID_INTSTAT); - mask = cx_read(MO_VID_INTMSK); - if (0 == (status & mask)) - return; - cx_write(MO_VID_INTSTAT, status); - if (irq_debug || (status & mask & ~0xff)) - cx88_print_irqbits(core->name, "irq vid", - cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), - status, mask); - - /* risc op code error */ - if (status & (1 << 16)) { - printk(KERN_WARNING "%s/0: video risc op code error\n",core->name); - cx_clear(MO_VID_DMACNTRL, 0x11); - cx_clear(VID_CAPTURE_CONTROL, 0x06); - cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); - } - - /* risc1 y */ - if (status & 0x01) { - spin_lock(&dev->slock); - count = cx_read(MO_VIDY_GPCNT); - cx88_wakeup(core, &dev->vidq, count); - spin_unlock(&dev->slock); - } - - /* risc1 vbi */ - if (status & 0x08) { - spin_lock(&dev->slock); - count = cx_read(MO_VBI_GPCNT); - cx88_wakeup(core, &dev->vbiq, count); - spin_unlock(&dev->slock); - } - - /* risc2 y */ - if (status & 0x10) { - dprintk(2,"stopper video\n"); - spin_lock(&dev->slock); - restart_video_queue(dev,&dev->vidq); - spin_unlock(&dev->slock); - } - - /* risc2 vbi */ - if (status & 0x80) { - dprintk(2,"stopper vbi\n"); - spin_lock(&dev->slock); - cx8800_restart_vbi_queue(dev,&dev->vbiq); - spin_unlock(&dev->slock); - } -} - -static irqreturn_t cx8800_irq(int irq, void *dev_id) -{ - struct cx8800_dev *dev = dev_id; - struct cx88_core *core = dev->core; - u32 status; - int loop, handled = 0; - - for (loop = 0; loop < 10; loop++) { - status = cx_read(MO_PCI_INTSTAT) & - (core->pci_irqmask | PCI_INT_VIDINT); - if (0 == status) - goto out; - cx_write(MO_PCI_INTSTAT, status); - handled = 1; - - if (status & core->pci_irqmask) - cx88_core_irq(core,status); - if (status & PCI_INT_VIDINT) - cx8800_vid_irq(dev); - }; - if (10 == loop) { - printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", - core->name); - cx_write(MO_PCI_INTMSK,0); - } - - out: - return IRQ_RETVAL(handled); -} - -/* ----------------------------------------------------------- */ -/* exported stuff */ - -static const struct v4l2_file_operations video_fops = -{ - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = video_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, - .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, - .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif -}; - -static struct video_device cx8800_vbi_template; - -static const struct video_device cx8800_video_template = { - .name = "cx8800-video", - .fops = &video_fops, - .ioctl_ops = &video_ioctl_ops, - .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; - -static const struct v4l2_file_operations radio_fops = -{ - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif -}; - -static const struct video_device cx8800_radio_template = { - .name = "cx8800-radio", - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, -}; - -/* ----------------------------------------------------------- */ - -static void cx8800_unregister_video(struct cx8800_dev *dev) -{ - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - if (dev->vbi_dev) { - if (video_is_registered(dev->vbi_dev)) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->video_dev) { - if (video_is_registered(dev->video_dev)) - video_unregister_device(dev->video_dev); - else - video_device_release(dev->video_dev); - dev->video_dev = NULL; - } -} - -static int __devinit cx8800_initdev(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - struct cx8800_dev *dev; - struct cx88_core *core; - - int err; - - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) - return -ENOMEM; - - /* pci init */ - dev->pci = pci_dev; - if (pci_enable_device(pci_dev)) { - err = -EIO; - goto fail_free; - } - core = cx88_core_get(dev->pci); - if (NULL == core) { - err = -EINVAL; - goto fail_free; - } - dev->core = core; - - /* print pci info */ - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", core->name, - pci_name(pci_dev), dev->pci_rev, pci_dev->irq, - dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); - - pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev,DMA_BIT_MASK(32))) { - printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); - err = -EIO; - goto fail_core; - } - - /* Initialize VBI template */ - memcpy( &cx8800_vbi_template, &cx8800_video_template, - sizeof(cx8800_vbi_template) ); - strcpy(cx8800_vbi_template.name,"cx8800-vbi"); - - /* initialize driver struct */ - spin_lock_init(&dev->slock); - core->tvnorm = cx8800_video_template.current_norm; - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - dev->vidq.timeout.function = cx8800_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); - cx88_risc_stopper(dev->pci,&dev->vidq.stopper, - MO_VID_DMACNTRL,0x11,0x00); - - /* init vbi dma queues */ - INIT_LIST_HEAD(&dev->vbiq.active); - INIT_LIST_HEAD(&dev->vbiq.queued); - dev->vbiq.timeout.function = cx8800_vbi_timeout; - dev->vbiq.timeout.data = (unsigned long)dev; - init_timer(&dev->vbiq.timeout); - cx88_risc_stopper(dev->pci,&dev->vbiq.stopper, - MO_VID_DMACNTRL,0x88,0x00); - - /* get irq */ - err = request_irq(pci_dev->irq, cx8800_irq, - IRQF_SHARED | IRQF_DISABLED, core->name, dev); - if (err < 0) { - printk(KERN_ERR "%s/0: can't get IRQ %d\n", - core->name,pci_dev->irq); - goto fail_core; - } - cx_set(MO_PCI_INTMSK, core->pci_irqmask); - - /* load and configure helper modules */ - - if (core->board.audio_chip == V4L2_IDENT_WM8775) { - struct i2c_board_info wm8775_info = { - .type = "wm8775", - .addr = 0x36 >> 1, - .platform_data = &core->wm8775_data, - }; - struct v4l2_subdev *sd; - - if (core->boardnr == CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1) - core->wm8775_data.is_nova_s = true; - else - core->wm8775_data.is_nova_s = false; - - sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap, - &wm8775_info, NULL); - if (sd != NULL) - sd->grp_id = WM8775_GID; - } - - if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { - /* This probes for a tda9874 as is used on some - Pixelview Ultra boards. */ - v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - "tvaudio", 0, I2C_ADDRS(0xb0 >> 1)); - } - - switch (core->boardnr) { - case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: - case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: { - static const struct i2c_board_info rtc_info = { - I2C_BOARD_INFO("isl1208", 0x6f) - }; - - request_module("rtc-isl1208"); - core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info); - } - /* break intentionally omitted */ - case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: - request_module("ir-kbd-i2c"); - } - - /* Sets device info at pci_dev */ - pci_set_drvdata(pci_dev, dev); - - /* initial device configuration */ - mutex_lock(&core->lock); - cx88_set_tvnorm(core, core->tvnorm); - init_controls(core); - cx88_video_mux(core, 0); - - /* register v4l devices */ - dev->video_dev = cx88_vdev_init(core,dev->pci, - &cx8800_video_template,"video"); - video_set_drvdata(dev->video_dev, dev); - err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, - video_nr[core->nr]); - if (err < 0) { - printk(KERN_ERR "%s/0: can't register video device\n", - core->name); - goto fail_unreg; - } - printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", - core->name, video_device_node_name(dev->video_dev)); - - dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); - video_set_drvdata(dev->vbi_dev, dev); - err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, - vbi_nr[core->nr]); - if (err < 0) { - printk(KERN_ERR "%s/0: can't register vbi device\n", - core->name); - goto fail_unreg; - } - printk(KERN_INFO "%s/0: registered device %s\n", - core->name, video_device_node_name(dev->vbi_dev)); - - if (core->board.radio.type == CX88_RADIO) { - dev->radio_dev = cx88_vdev_init(core,dev->pci, - &cx8800_radio_template,"radio"); - video_set_drvdata(dev->radio_dev, dev); - err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, - radio_nr[core->nr]); - if (err < 0) { - printk(KERN_ERR "%s/0: can't register radio device\n", - core->name); - goto fail_unreg; - } - printk(KERN_INFO "%s/0: registered device %s\n", - core->name, video_device_node_name(dev->radio_dev)); - } - - /* start tvaudio thread */ - if (core->board.tuner_type != TUNER_ABSENT) { - core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); - if (IS_ERR(core->kthread)) { - err = PTR_ERR(core->kthread); - printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n", - core->name, err); - } - } - mutex_unlock(&core->lock); - - return 0; - -fail_unreg: - cx8800_unregister_video(dev); - free_irq(pci_dev->irq, dev); - mutex_unlock(&core->lock); -fail_core: - cx88_core_put(core,dev->pci); -fail_free: - kfree(dev); - return err; -} - -static void __devexit cx8800_finidev(struct pci_dev *pci_dev) -{ - struct cx8800_dev *dev = pci_get_drvdata(pci_dev); - struct cx88_core *core = dev->core; - - /* stop thread */ - if (core->kthread) { - kthread_stop(core->kthread); - core->kthread = NULL; - } - - if (core->ir) - cx88_ir_stop(core); - - cx88_shutdown(core); /* FIXME */ - pci_disable_device(pci_dev); - - /* unregister stuff */ - - free_irq(pci_dev->irq, dev); - cx8800_unregister_video(dev); - pci_set_drvdata(pci_dev, NULL); - - /* free memory */ - btcx_riscmem_free(dev->pci,&dev->vidq.stopper); - cx88_core_put(core,dev->pci); - kfree(dev); -} - -#ifdef CONFIG_PM -static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) -{ - struct cx8800_dev *dev = pci_get_drvdata(pci_dev); - struct cx88_core *core = dev->core; - - /* stop video+vbi capture */ - spin_lock(&dev->slock); - if (!list_empty(&dev->vidq.active)) { - printk("%s/0: suspend video\n", core->name); - stop_video_dma(dev); - del_timer(&dev->vidq.timeout); - } - if (!list_empty(&dev->vbiq.active)) { - printk("%s/0: suspend vbi\n", core->name); - cx8800_stop_vbi_dma(dev); - del_timer(&dev->vbiq.timeout); - } - spin_unlock(&dev->slock); - - if (core->ir) - cx88_ir_stop(core); - /* FIXME -- shutdown device */ - cx88_shutdown(core); - - pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { - pci_disable_device(pci_dev); - dev->state.disabled = 1; - } - return 0; -} - -static int cx8800_resume(struct pci_dev *pci_dev) -{ - struct cx8800_dev *dev = pci_get_drvdata(pci_dev); - struct cx88_core *core = dev->core; - int err; - - if (dev->state.disabled) { - err=pci_enable_device(pci_dev); - if (err) { - printk(KERN_ERR "%s/0: can't enable device\n", - core->name); - return err; - } - - dev->state.disabled = 0; - } - err= pci_set_power_state(pci_dev, PCI_D0); - if (err) { - printk(KERN_ERR "%s/0: can't set power state\n", core->name); - pci_disable_device(pci_dev); - dev->state.disabled = 1; - - return err; - } - pci_restore_state(pci_dev); - - /* FIXME: re-initialize hardware */ - cx88_reset(core); - if (core->ir) - cx88_ir_start(core); - - cx_set(MO_PCI_INTMSK, core->pci_irqmask); - - /* restart video+vbi capture */ - spin_lock(&dev->slock); - if (!list_empty(&dev->vidq.active)) { - printk("%s/0: resume video\n", core->name); - restart_video_queue(dev,&dev->vidq); - } - if (!list_empty(&dev->vbiq.active)) { - printk("%s/0: resume vbi\n", core->name); - cx8800_restart_vbi_queue(dev,&dev->vbiq); - } - spin_unlock(&dev->slock); - - return 0; -} -#endif - -/* ----------------------------------------------------------- */ - -static const struct pci_device_id cx8800_pci_tbl[] = { - { - .vendor = 0x14f1, - .device = 0x8800, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - },{ - /* --- end of list --- */ - } -}; -MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl); - -static struct pci_driver cx8800_pci_driver = { - .name = "cx8800", - .id_table = cx8800_pci_tbl, - .probe = cx8800_initdev, - .remove = __devexit_p(cx8800_finidev), -#ifdef CONFIG_PM - .suspend = cx8800_suspend, - .resume = cx8800_resume, -#endif -}; - -static int __init cx8800_init(void) -{ - printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return pci_register_driver(&cx8800_pci_driver); -} - -static void __exit cx8800_fini(void) -{ - pci_unregister_driver(&cx8800_pci_driver); -} - -module_init(cx8800_init); -module_exit(cx8800_fini); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -/* - - cx88-vp3054-i2c.c -- support for the secondary I2C bus of the - DNTV Live! DVB-T Pro (VP-3054), wired as: - GPIO[0] -> SCL, GPIO[1] -> SDA - - (c) 2005 Chris Pascoe - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include - -#include - -#include "cx88.h" -#include "cx88-vp3054-i2c.h" - -MODULE_DESCRIPTION("driver for cx2388x VP3054 design"); -MODULE_AUTHOR("Chris Pascoe "); -MODULE_LICENSE("GPL"); - -/* ----------------------------------------------------------------------- */ - -static void vp3054_bit_setscl(void *data, int state) -{ - struct cx8802_dev *dev = data; - struct cx88_core *core = dev->core; - struct vp3054_i2c_state *vp3054_i2c = dev->vp3054; - - if (state) { - vp3054_i2c->state |= 0x0001; /* SCL high */ - vp3054_i2c->state &= ~0x0100; /* external pullup */ - } else { - vp3054_i2c->state &= ~0x0001; /* SCL low */ - vp3054_i2c->state |= 0x0100; /* drive pin */ - } - cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state); - cx_read(MO_GP0_IO); -} - -static void vp3054_bit_setsda(void *data, int state) -{ - struct cx8802_dev *dev = data; - struct cx88_core *core = dev->core; - struct vp3054_i2c_state *vp3054_i2c = dev->vp3054; - - if (state) { - vp3054_i2c->state |= 0x0002; /* SDA high */ - vp3054_i2c->state &= ~0x0200; /* tristate pin */ - } else { - vp3054_i2c->state &= ~0x0002; /* SDA low */ - vp3054_i2c->state |= 0x0200; /* drive pin */ - } - cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state); - cx_read(MO_GP0_IO); -} - -static int vp3054_bit_getscl(void *data) -{ - struct cx8802_dev *dev = data; - struct cx88_core *core = dev->core; - u32 state; - - state = cx_read(MO_GP0_IO); - return (state & 0x01) ? 1 : 0; -} - -static int vp3054_bit_getsda(void *data) -{ - struct cx8802_dev *dev = data; - struct cx88_core *core = dev->core; - u32 state; - - state = cx_read(MO_GP0_IO); - return (state & 0x02) ? 1 : 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_algo_bit_data vp3054_i2c_algo_template = { - .setsda = vp3054_bit_setsda, - .setscl = vp3054_bit_setscl, - .getsda = vp3054_bit_getsda, - .getscl = vp3054_bit_getscl, - .udelay = 16, - .timeout = 200, -}; - -/* ----------------------------------------------------------------------- */ - -int vp3054_i2c_probe(struct cx8802_dev *dev) -{ - struct cx88_core *core = dev->core; - struct vp3054_i2c_state *vp3054_i2c; - int rc; - - if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) - return 0; - - vp3054_i2c = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL); - if (vp3054_i2c == NULL) - return -ENOMEM; - dev->vp3054 = vp3054_i2c; - - memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template, - sizeof(vp3054_i2c->algo)); - - vp3054_i2c->adap.dev.parent = &dev->pci->dev; - strlcpy(vp3054_i2c->adap.name, core->name, - sizeof(vp3054_i2c->adap.name)); - vp3054_i2c->adap.owner = THIS_MODULE; - vp3054_i2c->algo.data = dev; - i2c_set_adapdata(&vp3054_i2c->adap, dev); - vp3054_i2c->adap.algo_data = &vp3054_i2c->algo; - - vp3054_bit_setscl(dev,1); - vp3054_bit_setsda(dev,1); - - rc = i2c_bit_add_bus(&vp3054_i2c->adap); - if (0 != rc) { - printk("%s: vp3054_i2c register FAILED\n", core->name); - - kfree(dev->vp3054); - dev->vp3054 = NULL; - } - - return rc; -} - -void vp3054_i2c_remove(struct cx8802_dev *dev) -{ - struct vp3054_i2c_state *vp3054_i2c = dev->vp3054; - - if (vp3054_i2c == NULL || - dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) - return; - - i2c_del_adapter(&vp3054_i2c->adap); - kfree(vp3054_i2c); -} - -EXPORT_SYMBOL(vp3054_i2c_probe); -EXPORT_SYMBOL(vp3054_i2c_remove); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vp3054-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vp3054-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vp3054-i2c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/cx88-vp3054-i2c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* - - cx88-vp3054-i2c.h -- support for the secondary I2C bus of the - DNTV Live! DVB-T Pro (VP-3054), wired as: - GPIO[0] -> SCL, GPIO[1] -> SDA - - (c) 2005 Chris Pascoe - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/* ----------------------------------------------------------------------- */ -struct vp3054_i2c_state { - struct i2c_adapter adap; - struct i2c_algo_bit_data algo; - u32 state; -}; - -/* ----------------------------------------------------------------------- */ -#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) -int vp3054_i2c_probe(struct cx8802_dev *dev); -void vp3054_i2c_remove(struct cx8802_dev *dev); -#else -static inline int vp3054_i2c_probe(struct cx8802_dev *dev) -{ return 0; } -static inline void vp3054_i2c_remove(struct cx8802_dev *dev) -{ } -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -config VIDEO_CX88 - tristate "Conexant 2388x (bt878 successor) support" - depends on VIDEO_DEV && PCI && I2C && RC_CORE - select I2C_ALGOBIT - select VIDEO_BTCX - select VIDEOBUF_DMA_SG - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO - ---help--- - This is a video4linux driver for Conexant 2388x based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx8800 - -config VIDEO_CX88_ALSA - tristate "Conexant 2388x DMA audio support" - depends on VIDEO_CX88 && SND - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio on - Conexant 2388x based TV cards using ALSA. - - It only works with boards with function 01 enabled. - To check if your board supports, use lspci -n. - If supported, you should see 14f1:8801 or 14f1:8811 - PCI device. - - To compile this driver as a module, choose M here: the - module will be called cx88-alsa. - -config VIDEO_CX88_BLACKBIRD - tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" - depends on VIDEO_CX88 - select VIDEO_CX2341X - ---help--- - This adds support for MPEG encoder cards based on the - Blackbird reference design, using the Conexant 2388x - and 23416 chips. - - To compile this driver as a module, choose M here: the - module will be called cx88-blackbird. - -config VIDEO_CX88_DVB - tristate "DVB/ATSC Support for cx2388x based TV cards" - depends on VIDEO_CX88 && DVB_CORE - select VIDEOBUF_DVB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_OR51132 if !DVB_FE_CUSTOMISE - select DVB_CX22702 if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_NXT200X if !DVB_FE_CUSTOMISE - select DVB_CX24123 if !DVB_FE_CUSTOMISE - select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_STV0288 if !DVB_FE_CUSTOMISE - select DVB_STB6000 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - ---help--- - This adds support for DVB/ATSC cards based on the - Conexant 2388x chip. - - To compile this driver as a module, choose M here: the - module will be called cx88-dvb. - -config VIDEO_CX88_MPEG - tristate - depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD - default y - -config VIDEO_CX88_VP3054 - tristate "VP-3054 Secondary I2C Bus Support" - default m - depends on VIDEO_CX88_DVB && DVB_MT352 - ---help--- - This adds DVB-T support for cards based on the - Conexant 2388x chip and the MT352 demodulator, - which also require support for the VP-3054 - Secondary I2C bus, such at DNTV Live! DVB-T Pro. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/cx88/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \ - cx88-dsp.o cx88-input.o -cx8800-objs := cx88-video.o cx88-vbi.o -cx8802-objs := cx88-mpeg.o - -obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o -obj-$(CONFIG_VIDEO_CX88_MPEG) += cx8802.o -obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o -obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o -obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o -obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/ccdc_hw_device.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/ccdc_hw_device.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/ccdc_hw_device.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/ccdc_hw_device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * ccdc device API - */ -#ifndef _CCDC_HW_DEVICE_H -#define _CCDC_HW_DEVICE_H - -#ifdef __KERNEL__ -#include -#include -#include -#include - -/* - * ccdc hw operations - */ -struct ccdc_hw_ops { - /* Pointer to initialize function to initialize ccdc device */ - int (*open) (struct device *dev); - /* Pointer to deinitialize function */ - int (*close) (struct device *dev); - /* set ccdc base address */ - void (*set_ccdc_base)(void *base, int size); - /* Pointer to function to enable or disable ccdc */ - void (*enable) (int en); - /* reset sbl. only for 6446 */ - void (*reset) (void); - /* enable output to sdram */ - void (*enable_out_to_sdram) (int en); - /* Pointer to function to set hw parameters */ - int (*set_hw_if_params) (struct vpfe_hw_if_param *param); - /* get interface parameters */ - int (*get_hw_if_params) (struct vpfe_hw_if_param *param); - /* - * Pointer to function to set parameters. Used - * for implementing VPFE_S_CCDC_PARAMS - */ - int (*set_params) (void *params); - /* - * Pointer to function to get parameter. Used - * for implementing VPFE_G_CCDC_PARAMS - */ - int (*get_params) (void *params); - /* Pointer to function to configure ccdc */ - int (*configure) (void); - - /* Pointer to function to set buffer type */ - int (*set_buftype) (enum ccdc_buftype buf_type); - /* Pointer to function to get buffer type */ - enum ccdc_buftype (*get_buftype) (void); - /* Pointer to function to set frame format */ - int (*set_frame_format) (enum ccdc_frmfmt frm_fmt); - /* Pointer to function to get frame format */ - enum ccdc_frmfmt (*get_frame_format) (void); - /* enumerate hw pix formats */ - int (*enum_pix)(u32 *hw_pix, int i); - /* Pointer to function to set buffer type */ - u32 (*get_pixel_format) (void); - /* Pointer to function to get pixel format. */ - int (*set_pixel_format) (u32 pixfmt); - /* Pointer to function to set image window */ - int (*set_image_window) (struct v4l2_rect *win); - /* Pointer to function to set image window */ - void (*get_image_window) (struct v4l2_rect *win); - /* Pointer to function to get line length */ - unsigned int (*get_line_length) (void); - - /* Query CCDC control IDs */ - int (*queryctrl)(struct v4l2_queryctrl *qctrl); - /* Set CCDC control */ - int (*set_control)(struct v4l2_control *ctrl); - /* Get CCDC control */ - int (*get_control)(struct v4l2_control *ctrl); - - /* Pointer to function to set frame buffer address */ - void (*setfbaddr) (unsigned long addr); - /* Pointer to function to get field id */ - int (*getfid) (void); -}; - -struct ccdc_hw_device { - /* ccdc device name */ - char name[32]; - /* module owner */ - struct module *owner; - /* hw ops */ - struct ccdc_hw_ops hw_ops; -}; - -/* Used by CCDC module to register & unregister with vpfe capture driver */ -int vpfe_register_ccdc_device(struct ccdc_hw_device *dev); -void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev); - -#endif -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm355_ccdc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm355_ccdc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm355_ccdc.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm355_ccdc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1082 +0,0 @@ -/* - * Copyright (C) 2005-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * CCDC hardware module for DM355 - * ------------------------------ - * - * This module is for configuring DM355 CCD controller of VPFE to capture - * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules - * such as Defect Pixel Correction, Color Space Conversion etc to - * pre-process the Bayer RGB data, before writing it to SDRAM. This - * module also allows application to configure individual - * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. - * To do so, application include dm355_ccdc.h and vpfe_capture.h header - * files. The setparams() API is called by vpfe_capture driver - * to configure module parameters - * - * TODO: 1) Raw bayer parameter settings and bayer capture - * 2) Split module parameter structure to module specific ioctl structs - * 3) add support for lense shading correction - * 4) investigate if enum used for user space type definition - * to be replaced by #defines or integer - */ -#include -#include -#include -#include -#include - -#include -#include - -#include "dm355_ccdc_regs.h" -#include "ccdc_hw_device.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CCDC Driver for DM355"); -MODULE_AUTHOR("Texas Instruments"); - -static struct ccdc_oper_config { - struct device *dev; - /* CCDC interface type */ - enum vpfe_hw_if_type if_type; - /* Raw Bayer configuration */ - struct ccdc_params_raw bayer; - /* YCbCr configuration */ - struct ccdc_params_ycbcr ycbcr; - /* Master clock */ - struct clk *mclk; - /* slave clock */ - struct clk *sclk; - /* ccdc base address */ - void __iomem *base_addr; -} ccdc_cfg = { - /* Raw configurations */ - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = 256, - .gb_g = 256, - .gr_cy = 256, - .b_mg = 256 - }, - .config_params = { - .datasft = 2, - .mfilt1 = CCDC_NO_MEDIAN_FILTER1, - .mfilt2 = CCDC_NO_MEDIAN_FILTER2, - .alaw = { - .gama_wd = 2, - }, - .blk_clamp = { - .sample_pixel = 1, - .dc_sub = 25 - }, - .col_pat_field0 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED - }, - .col_pat_field1 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED - }, - }, - }, - /* YCbCr configuration */ - .ycbcr = { - .win = CCDC_WIN_PAL, - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED - }, -}; - - -/* Raw Bayer formats */ -static u32 ccdc_raw_bayer_pix_formats[] = - {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static u32 ccdc_raw_yuv_pix_formats[] = - {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(ccdc_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, ccdc_cfg.base_addr + offset); -} - -static void ccdc_enable(int en) -{ - unsigned int temp; - temp = regr(SYNCEN); - temp &= (~CCDC_SYNCEN_VDHDEN_MASK); - temp |= (en & CCDC_SYNCEN_VDHDEN_MASK); - regw(temp, SYNCEN); -} - -static void ccdc_enable_output_to_sdram(int en) -{ - unsigned int temp; - temp = regr(SYNCEN); - temp &= (~(CCDC_SYNCEN_WEN_MASK)); - temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK); - regw(temp, SYNCEN); -} - -static void ccdc_config_gain_offset(void) -{ - /* configure gain */ - regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); - regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); - regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); - regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); - /* configure offset */ - regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); -} - -/* - * ccdc_restore_defaults() - * This function restore power on defaults in the ccdc registers - */ -static int ccdc_restore_defaults(void) -{ - int i; - - dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); - /* set all registers to zero */ - for (i = 0; i <= CCDC_REG_LAST; i += 4) - regw(0, i); - - /* now override the values with power on defaults in registers */ - regw(MODESET_DEFAULT, MODESET); - /* no culling support */ - regw(CULH_DEFAULT, CULH); - regw(CULV_DEFAULT, CULV); - /* Set default Gain and Offset */ - ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; - ccdc_config_gain_offset(); - regw(OUTCLIP_DEFAULT, OUTCLIP); - regw(LSCCFG2_DEFAULT, LSCCFG2); - /* select ccdc input */ - if (vpss_select_ccdc_source(VPSS_CCDCIN)) { - dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); - return -EFAULT; - } - /* select ccdc clock */ - if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { - dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); - return -EFAULT; - } - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); - return 0; -} - -static int ccdc_open(struct device *device) -{ - return ccdc_restore_defaults(); -} - -static int ccdc_close(struct device *device) -{ - /* disable clock */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 0); - /* do nothing for now */ - return 0; -} -/* - * ccdc_setwin() - * This function will configure the window size to - * be capture in CCDC reg. - */ -static void ccdc_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, int ppc) -{ - int horz_start, horz_nr_pixels; - int vert_start, vert_nr_lines; - int mid_img = 0; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); - - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; - - /* Writing the horizontal info into the registers */ - regw(horz_start, SPH); - regw(horz_nr_pixels, NPH); - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* Since first line doesn't have any data */ - vert_start += 1; - /* configure VDINT0 and VDINT1 */ - regw(vert_start, VDINT0); - } else { - /* Since first line doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* configure VDINT0 and VDINT1 */ - mid_img = vert_start + (image_win->height / 2); - regw(vert_start, VDINT0); - regw(mid_img, VDINT1); - } - regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0); - regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); - regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); -} - -static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) -{ - if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT || - ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) { - dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n"); - return -EINVAL; - } - - if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 || - ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) { - dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n"); - return -EINVAL; - } - - if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 || - ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) { - dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n"); - return -EINVAL; - } - - if ((ccdcparam->med_filt_thres < 0) || - (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { - dev_dbg(ccdc_cfg.dev, - "Invalid value of median filter thresold\n"); - return -EINVAL; - } - - if (ccdcparam->data_sz < CCDC_DATA_16BITS || - ccdcparam->data_sz > CCDC_DATA_8BITS) { - dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n"); - return -EINVAL; - } - - if (ccdcparam->alaw.enable) { - if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || - ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { - dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); - return -EINVAL; - } - } - - if (ccdcparam->blk_clamp.b_clamp_enable) { - if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS || - ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) { - dev_dbg(ccdc_cfg.dev, - "Invalid value of sample pixel\n"); - return -EINVAL; - } - if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES || - ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) { - dev_dbg(ccdc_cfg.dev, - "Invalid value of sample lines\n"); - return -EINVAL; - } - } - return 0; -} - -/* Parameter operations */ -static int ccdc_set_params(void __user *params) -{ - struct ccdc_config_params_raw ccdc_raw_params; - int x; - - /* only raw module parameters can be set through the IOCTL */ - if (ccdc_cfg.if_type != VPFE_RAW_BAYER) - return -EINVAL; - - x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); - if (x) { - dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc" - "params, %d\n", x); - return -EFAULT; - } - - if (!validate_ccdc_param(&ccdc_raw_params)) { - memcpy(&ccdc_cfg.bayer.config_params, - &ccdc_raw_params, - sizeof(ccdc_raw_params)); - return 0; - } - return -EINVAL; -} - -/* This function will configure CCDC for YCbCr video capture */ -static void ccdc_config_ycbcr(void) -{ - struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; - u32 temp; - - /* first set the CCDC power on defaults values in all registers */ - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); - ccdc_restore_defaults(); - - /* configure pixel format & video frame format */ - temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) << - CCDC_INPUT_MODE_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << - CCDC_FRM_FMT_SHIFT)); - - /* setup BT.656 sync mode */ - if (params->bt656_enable) { - regw(CCDC_REC656IF_BT656_EN, REC656IF); - /* - * configure the FID, VD, HD pin polarity fld,hd pol positive, - * vd negative, 8-bit pack mode - */ - temp |= CCDC_VD_POL_NEGATIVE; - } else { /* y/c external sync mode */ - temp |= (((params->fid_pol & CCDC_FID_POL_MASK) << - CCDC_FID_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << - CCDC_HD_POL_SHIFT) | - ((params->vd_pol & CCDC_VD_POL_MASK) << - CCDC_VD_POL_SHIFT)); - } - - /* pack the data to 8-bit */ - temp |= CCDC_DATA_PACK_ENABLE; - - regw(temp, MODESET); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 2); - - /* configure the order of y cb cr in SD-RAM */ - temp = (params->pix_order << CCDC_Y8POS_SHIFT); - temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC; - regw(temp, CCDCFG); - - /* - * configure the horizontal line offset. This is done by rounding up - * width to a multiple of 16 pixels and multiply by two to account for - * y:cb:cr 4:2:2 data - */ - regw(((params->win.width * 2 + 31) >> 5), HSIZE); - - /* configure the memory line offset */ - if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { - /* two fields are interleaved in memory */ - regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); - } - - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); -} - -/* - * ccdc_config_black_clamp() - * configure parameters for Optical Black Clamp - */ -static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) -{ - u32 val; - - if (!bclamp->b_clamp_enable) { - /* configure DCSub */ - regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB); - regw(0x0000, CLAMP); - return; - } - /* Enable the Black clamping, set sample lines and pixels */ - val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) | - ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << - CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE; - regw(val, CLAMP); - - /* If Black clamping is enable then make dcsub 0 */ - val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK) - << CCDC_NUM_LINE_CALC_SHIFT; - regw(val, DCSUB); -} - -/* - * ccdc_config_black_compense() - * configure parameters for Black Compensation - */ -static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) -{ - u32 val; - - val = (bcomp->b & CCDC_BLK_COMP_MASK) | - ((bcomp->gb & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GB_COMP_SHIFT); - regw(val, BLKCMP1); - - val = ((bcomp->gr & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GR_COMP_SHIFT) | - ((bcomp->r & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_R_COMP_SHIFT); - regw(val, BLKCMP0); -} - -/* - * ccdc_write_dfc_entry() - * write an entry in the dfc table. - */ -int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) -{ -/* TODO This is to be re-visited and adjusted */ -#define DFC_WRITE_WAIT_COUNT 1000 - u32 val, count = DFC_WRITE_WAIT_COUNT; - - regw(dfc->dft_corr_vert[index], DFCMEM0); - regw(dfc->dft_corr_horz[index], DFCMEM1); - regw(dfc->dft_corr_sub1[index], DFCMEM2); - regw(dfc->dft_corr_sub2[index], DFCMEM3); - regw(dfc->dft_corr_sub3[index], DFCMEM4); - /* set WR bit to write */ - val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK; - regw(val, DFCMEMCTL); - - /* - * Assume, it is very short. If we get an error, we need to - * adjust this value - */ - while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK) - count--; - /* - * TODO We expect the count to be non-zero to be successful. Adjust - * the count if write requires more time - */ - - if (count) { - dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); - return -1; - } - return 0; -} - -/* - * ccdc_config_vdfc() - * configure parameters for Vertical Defect Correction - */ -static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc) -{ - u32 val; - int i; - - /* Configure General Defect Correction. The table used is from IPIPE */ - val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; - - /* Configure Vertical Defect Correction if needed */ - if (!dfc->ver_dft_en) { - /* Enable only General Defect Correction */ - regw(val, DFCCTL); - return 0; - } - - if (dfc->table_size > CCDC_DFT_TABLE_SIZE) - return -EINVAL; - - val |= CCDC_DFCCTL_VDFC_DISABLE; - val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << - CCDC_DFCCTL_VDFCSL_SHIFT; - val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << - CCDC_DFCCTL_VDFCUDA_SHIFT; - val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << - CCDC_DFCCTL_VDFLSFT_SHIFT; - regw(val , DFCCTL); - - /* clear address ptr to offset 0 */ - val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT; - - /* write defect table entries */ - for (i = 0; i < dfc->table_size; i++) { - /* increment address for non zero index */ - if (i != 0) - val = CCDC_DFCMEMCTL_INC_ADDR; - regw(val, DFCMEMCTL); - if (ccdc_write_dfc_entry(i, dfc) < 0) - return -EFAULT; - } - - /* update saturation level and enable dfc */ - regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); - val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK << - CCDC_DFCCTL_VDFCEN_SHIFT); - regw(val, DFCCTL); - return 0; -} - -/* - * ccdc_config_csc() - * configure parameters for color space conversion - * Each register CSCM0-7 has two values in S8Q5 format. - */ -static void ccdc_config_csc(struct ccdc_csc *csc) -{ - u32 val1, val2; - int i; - - if (!csc->enable) - return; - - /* Enable the CSC sub-module */ - regw(CCDC_CSC_ENABLE, CSCCTL); - - /* Converting the co-eff as per the format of the register */ - for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = (csc->coeff[i].integer & - CCDC_CSC_COEF_INTEG_MASK) - << CCDC_CSC_COEF_INTEG_SHIFT; - /* - * convert decimal part to binary. Use 2 decimal - * precision, user values range from .00 - 0.99 - */ - val1 |= (((csc->coeff[i].decimal & - CCDC_CSC_COEF_DECIMAL_MASK) * - CCDC_CSC_DEC_MAX) / 100); - } else { - - /* CSCM - MSB */ - val2 = (csc->coeff[i].integer & - CCDC_CSC_COEF_INTEG_MASK) - << CCDC_CSC_COEF_INTEG_SHIFT; - val2 |= (((csc->coeff[i].decimal & - CCDC_CSC_COEF_DECIMAL_MASK) * - CCDC_CSC_DEC_MAX) / 100); - val2 <<= CCDC_CSCM_MSB_SHIFT; - val2 |= val1; - regw(val2, (CSCM0 + ((i - 1) << 1))); - } - } -} - -/* - * ccdc_config_color_patterns() - * configure parameters for color patterns - */ -static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, - struct ccdc_col_pat *pat1) -{ - u32 val; - - val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) | - (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) | - (pat1->elop << 12) | (pat1->elep << 14)); - regw(val, COLPTN); -} - -/* This function will configure CCDC for Raw mode image capture */ -static int ccdc_config_raw(void) -{ - struct ccdc_params_raw *params = &ccdc_cfg.bayer; - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int val; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); - - /* restore power on defaults to register */ - ccdc_restore_defaults(); - - /* CCDCFG register: - * set CCD Not to swap input since input is RAW data - * set FID detection function to Latch at V-Sync - * set WENLOG - ccdc valid area to AND - * set TRGSEL to WENBIT - * set EXTRG to DISABLE - * disable latching function on VSYNC - shadowed registers - */ - regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | - CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | - CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); - - /* - * Set VDHD direction to input, input type to raw input - * normal data polarity, do not use external WEN - */ - val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL | - CCDC_EXWEN_DISABLE); - - /* - * Configure the vertical sync polarity (MODESET.VDPOL), horizontal - * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL), - * frame format(progressive or interlace), & pixel format (Input mode) - */ - val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | - ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | - ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT)); - - /* set pack for alaw compression */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - val |= CCDC_DATA_PACK_ENABLE; - - /* Configure for LPF */ - if (config_params->lpf_enable) - val |= (config_params->lpf_enable & CCDC_LPF_MASK) << - CCDC_LPF_SHIFT; - - /* Configure the data shift */ - val |= (config_params->datasft & CCDC_DATASFT_MASK) << - CCDC_DATASFT_SHIFT; - regw(val , MODESET); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); - - /* Configure the Median Filter threshold */ - regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); - - /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */ - val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT | - CCDC_CFA_MOSAIC; - - /* Enable and configure aLaw register if needed */ - if (config_params->alaw.enable) { - val |= (CCDC_ALAW_ENABLE | - ((config_params->alaw.gama_wd & - CCDC_ALAW_GAMA_WD_MASK) << - CCDC_GAMMAWD_INPUT_SHIFT)); - } - - /* Configure Median filter1 & filter2 */ - val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) | - (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); - - regw(val, GAMMAWD); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 1); - - /* Optical Clamp Averaging */ - ccdc_config_black_clamp(&config_params->blk_clamp); - - /* Black level compensation */ - ccdc_config_black_compense(&config_params->blk_comp); - - /* Vertical Defect Correction if needed */ - if (ccdc_config_vdfc(&config_params->vertical_dft) < 0) - return -EFAULT; - - /* color space conversion */ - ccdc_config_csc(&config_params->csc); - - /* color pattern */ - ccdc_config_color_patterns(&config_params->col_pat_field0, - &config_params->col_pat_field1); - - /* Configure the Gain & offset control */ - ccdc_config_gain_offset(); - - dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); - - /* Configure DATAOFST register */ - val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << - CCDC_DATAOFST_H_SHIFT; - val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) << - CCDC_DATAOFST_V_SHIFT; - regw(val, DATAOFST); - - /* configuring HSIZE register */ - val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) << - CCDC_HSIZE_FLIP_SHIFT; - - /* If pack 8 is enable then 1 pixel will take 1 byte */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) { - val |= (((params->win.width) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK; - - /* adjust to multiple of 32 */ - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", - (((params->win.width) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK); - } else { - /* else one pixel will take 2 byte */ - val |= (((params->win.width * 2) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK; - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", - (((params->win.width * 2) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK); - } - regw(val, HSIZE); - - /* Configure SDOFST register */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_enable) { - /* For interlace inverse mode */ - regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_INTERLACE_INVERSE); - } else { - /* For interlace non inverse mode */ - regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_INTERLACE_NORMAL); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - if (params->image_invert_enable) { - /* For progessive inverse mode */ - regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_PROGRESSIVE_INVERSE); - } else { - /* For progessive non inverse mode */ - regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_PROGRESSIVE_NORMAL); - } - } - dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); - return 0; -} - -static int ccdc_configure(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_config_raw(); - else - ccdc_config_ycbcr(); - return 0; -} - -static int ccdc_set_buftype(enum ccdc_buftype buf_type) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.buf_type = buf_type; - else - ccdc_cfg.ycbcr.buf_type = buf_type; - return 0; -} -static enum ccdc_buftype ccdc_get_buftype(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.buf_type; - return ccdc_cfg.ycbcr.buf_type; -} - -static int ccdc_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { - *pix = ccdc_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { - *pix = ccdc_raw_yuv_pix_formats[i]; - ret = 0; - } - } - return ret; -} - -static int ccdc_set_pixel_format(u32 pixfmt) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - if (pixfmt == V4L2_PIX_FMT_SBGGR8) - alaw->enable = 1; - else if (pixfmt != V4L2_PIX_FMT_SBGGR16) - return -EINVAL; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - } - return 0; -} -static u32 ccdc_get_pixel_format(void) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - u32 pixfmt; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - if (alaw->enable) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} -static int ccdc_set_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.win = *win; - else - ccdc_cfg.ycbcr.win = *win; - return 0; -} - -static void ccdc_get_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - *win = ccdc_cfg.bayer.win; - else - *win = ccdc_cfg.ycbcr.win; -} - -static unsigned int ccdc_get_line_length(void) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int len; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if ((config_params->alaw.enable) || - (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_cfg.bayer.win.width; - else - len = ccdc_cfg.bayer.win.width * 2; - } else - len = ccdc_cfg.ycbcr.win.width * 2; - return ALIGN(len, 32); -} - -static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.frm_fmt = frm_fmt; - else - ccdc_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} - -static enum ccdc_frmfmt ccdc_get_frame_format(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.frm_fmt; - else - return ccdc_cfg.ycbcr.frm_fmt; -} - -static int ccdc_getfid(void) -{ - return (regr(MODESET) >> 15) & 1; -} - -/* misc operations */ -static inline void ccdc_setfbaddr(unsigned long addr) -{ - regw((addr >> 21) & 0x007f, STADRH); - regw((addr >> 5) & 0x0ffff, STADRL); -} - -static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - ccdc_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_YCBCR_SYNC_16: - case VPFE_YCBCR_SYNC_8: - ccdc_cfg.ycbcr.vd_pol = params->vdpol; - ccdc_cfg.ycbcr.hd_pol = params->hdpol; - break; - default: - /* TODO add support for raw bayer here */ - return -EINVAL; - } - return 0; -} - -static struct ccdc_hw_device ccdc_hw_dev = { - .name = "DM355 CCDC", - .owner = THIS_MODULE, - .hw_ops = { - .open = ccdc_open, - .close = ccdc_close, - .enable = ccdc_enable, - .enable_out_to_sdram = ccdc_enable_output_to_sdram, - .set_hw_if_params = ccdc_set_hw_if_params, - .set_params = ccdc_set_params, - .configure = ccdc_configure, - .set_buftype = ccdc_set_buftype, - .get_buftype = ccdc_get_buftype, - .enum_pix = ccdc_enum_pix, - .set_pixel_format = ccdc_set_pixel_format, - .get_pixel_format = ccdc_get_pixel_format, - .set_frame_format = ccdc_set_frame_format, - .get_frame_format = ccdc_get_frame_format, - .set_image_window = ccdc_set_image_window, - .get_image_window = ccdc_get_image_window, - .get_line_length = ccdc_get_line_length, - .setfbaddr = ccdc_setfbaddr, - .getfid = ccdc_getfid, - }, -}; - -static int __init dm355_ccdc_probe(struct platform_device *pdev) -{ - void (*setup_pinmux)(void); - struct resource *res; - int status = 0; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&ccdc_hw_dev); - if (status < 0) - return status; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - status = -ENODEV; - goto fail_nores; - } - - res = request_mem_region(res->start, resource_size(res), res->name); - if (!res) { - status = -EBUSY; - goto fail_nores; - } - - ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); - if (!ccdc_cfg.base_addr) { - status = -ENOMEM; - goto fail_nomem; - } - - /* Get and enable Master clock */ - ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); - if (IS_ERR(ccdc_cfg.mclk)) { - status = PTR_ERR(ccdc_cfg.mclk); - goto fail_nomap; - } - if (clk_enable(ccdc_cfg.mclk)) { - status = -ENODEV; - goto fail_mclk; - } - - /* Get and enable Slave clock */ - ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); - if (IS_ERR(ccdc_cfg.sclk)) { - status = PTR_ERR(ccdc_cfg.sclk); - goto fail_mclk; - } - if (clk_enable(ccdc_cfg.sclk)) { - status = -ENODEV; - goto fail_sclk; - } - - /* Platform data holds setup_pinmux function ptr */ - if (NULL == pdev->dev.platform_data) { - status = -ENODEV; - goto fail_sclk; - } - setup_pinmux = pdev->dev.platform_data; - /* - * setup Mux configuration for ccdc which may be different for - * different SoCs using this CCDC - */ - setup_pinmux(); - ccdc_cfg.dev = &pdev->dev; - printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); - return 0; -fail_sclk: - clk_put(ccdc_cfg.sclk); -fail_mclk: - clk_put(ccdc_cfg.mclk); -fail_nomap: - iounmap(ccdc_cfg.base_addr); -fail_nomem: - release_mem_region(res->start, resource_size(res)); -fail_nores: - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return status; -} - -static int dm355_ccdc_remove(struct platform_device *pdev) -{ - struct resource *res; - - clk_put(ccdc_cfg.mclk); - clk_put(ccdc_cfg.sclk); - iounmap(ccdc_cfg.base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return 0; -} - -static struct platform_driver dm355_ccdc_driver = { - .driver = { - .name = "dm355_ccdc", - .owner = THIS_MODULE, - }, - .remove = __devexit_p(dm355_ccdc_remove), - .probe = dm355_ccdc_probe, -}; - -static int __init dm355_ccdc_init(void) -{ - return platform_driver_register(&dm355_ccdc_driver); -} - -static void __exit dm355_ccdc_exit(void) -{ - platform_driver_unregister(&dm355_ccdc_driver); -} - -module_init(dm355_ccdc_init); -module_exit(dm355_ccdc_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm355_ccdc_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm355_ccdc_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm355_ccdc_regs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm355_ccdc_regs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,310 +0,0 @@ -/* - * Copyright (C) 2005-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - */ -#ifndef _DM355_CCDC_REGS_H -#define _DM355_CCDC_REGS_H - -/**************************************************************************\ -* Register OFFSET Definitions -\**************************************************************************/ -#define SYNCEN 0x00 -#define MODESET 0x04 -#define HDWIDTH 0x08 -#define VDWIDTH 0x0c -#define PPLN 0x10 -#define LPFR 0x14 -#define SPH 0x18 -#define NPH 0x1c -#define SLV0 0x20 -#define SLV1 0x24 -#define NLV 0x28 -#define CULH 0x2c -#define CULV 0x30 -#define HSIZE 0x34 -#define SDOFST 0x38 -#define STADRH 0x3c -#define STADRL 0x40 -#define CLAMP 0x44 -#define DCSUB 0x48 -#define COLPTN 0x4c -#define BLKCMP0 0x50 -#define BLKCMP1 0x54 -#define MEDFILT 0x58 -#define RYEGAIN 0x5c -#define GRCYGAIN 0x60 -#define GBGGAIN 0x64 -#define BMGGAIN 0x68 -#define OFFSET 0x6c -#define OUTCLIP 0x70 -#define VDINT0 0x74 -#define VDINT1 0x78 -#define RSV0 0x7c -#define GAMMAWD 0x80 -#define REC656IF 0x84 -#define CCDCFG 0x88 -#define FMTCFG 0x8c -#define FMTPLEN 0x90 -#define FMTSPH 0x94 -#define FMTLNH 0x98 -#define FMTSLV 0x9c -#define FMTLNV 0xa0 -#define FMTRLEN 0xa4 -#define FMTHCNT 0xa8 -#define FMT_ADDR_PTR_B 0xac -#define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i * 4)) -#define FMTPGM_VF0 0xcc -#define FMTPGM_VF1 0xd0 -#define FMTPGM_AP0 0xd4 -#define FMTPGM_AP1 0xd8 -#define FMTPGM_AP2 0xdc -#define FMTPGM_AP3 0xe0 -#define FMTPGM_AP4 0xe4 -#define FMTPGM_AP5 0xe8 -#define FMTPGM_AP6 0xec -#define FMTPGM_AP7 0xf0 -#define LSCCFG1 0xf4 -#define LSCCFG2 0xf8 -#define LSCH0 0xfc -#define LSCV0 0x100 -#define LSCKH 0x104 -#define LSCKV 0x108 -#define LSCMEMCTL 0x10c -#define LSCMEMD 0x110 -#define LSCMEMQ 0x114 -#define DFCCTL 0x118 -#define DFCVSAT 0x11c -#define DFCMEMCTL 0x120 -#define DFCMEM0 0x124 -#define DFCMEM1 0x128 -#define DFCMEM2 0x12c -#define DFCMEM3 0x130 -#define DFCMEM4 0x134 -#define CSCCTL 0x138 -#define CSCM0 0x13c -#define CSCM1 0x140 -#define CSCM2 0x144 -#define CSCM3 0x148 -#define CSCM4 0x14c -#define CSCM5 0x150 -#define CSCM6 0x154 -#define CSCM7 0x158 -#define DATAOFST 0x15c -#define CCDC_REG_LAST DATAOFST -/************************************************************** -* Define for various register bit mask and shifts for CCDC -* -**************************************************************/ -#define CCDC_RAW_IP_MODE 0 -#define CCDC_VDHDOUT_INPUT 0 -#define CCDC_YCINSWP_RAW (0 << 4) -#define CCDC_EXWEN_DISABLE 0 -#define CCDC_DATAPOL_NORMAL 0 -#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0 -#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6) -#define CCDC_CCDCFG_WENLOG_AND 0 -#define CCDC_CCDCFG_TRGSEL_WEN 0 -#define CCDC_CCDCFG_EXTRG_DISABLE 0 -#define CCDC_CFA_MOSAIC 0 -#define CCDC_Y8POS_SHIFT 11 - -#define CCDC_VDC_DFCVSAT_MASK 0x3fff -#define CCDC_DATAOFST_MASK 0x0ff -#define CCDC_DATAOFST_H_SHIFT 0 -#define CCDC_DATAOFST_V_SHIFT 8 -#define CCDC_GAMMAWD_CFA_MASK 1 -#define CCDC_GAMMAWD_CFA_SHIFT 5 -#define CCDC_GAMMAWD_INPUT_SHIFT 2 -#define CCDC_FID_POL_MASK 1 -#define CCDC_FID_POL_SHIFT 4 -#define CCDC_HD_POL_MASK 1 -#define CCDC_HD_POL_SHIFT 3 -#define CCDC_VD_POL_MASK 1 -#define CCDC_VD_POL_SHIFT 2 -#define CCDC_VD_POL_NEGATIVE (1 << 2) -#define CCDC_FRM_FMT_MASK 1 -#define CCDC_FRM_FMT_SHIFT 7 -#define CCDC_DATA_SZ_MASK 7 -#define CCDC_DATA_SZ_SHIFT 8 -#define CCDC_VDHDOUT_MASK 1 -#define CCDC_VDHDOUT_SHIFT 0 -#define CCDC_EXWEN_MASK 1 -#define CCDC_EXWEN_SHIFT 5 -#define CCDC_INPUT_MODE_MASK 3 -#define CCDC_INPUT_MODE_SHIFT 12 -#define CCDC_PIX_FMT_MASK 3 -#define CCDC_PIX_FMT_SHIFT 12 -#define CCDC_DATAPOL_MASK 1 -#define CCDC_DATAPOL_SHIFT 6 -#define CCDC_WEN_ENABLE (1 << 1) -#define CCDC_VDHDEN_ENABLE (1 << 16) -#define CCDC_LPF_ENABLE (1 << 14) -#define CCDC_ALAW_ENABLE 1 -#define CCDC_ALAW_GAMA_WD_MASK 7 -#define CCDC_REC656IF_BT656_EN 3 - -#define CCDC_FMTCFG_FMTMODE_MASK 3 -#define CCDC_FMTCFG_FMTMODE_SHIFT 1 -#define CCDC_FMTCFG_LNUM_MASK 3 -#define CCDC_FMTCFG_LNUM_SHIFT 4 -#define CCDC_FMTCFG_ADDRINC_MASK 7 -#define CCDC_FMTCFG_ADDRINC_SHIFT 8 - -#define CCDC_CCDCFG_FIDMD_SHIFT 6 -#define CCDC_CCDCFG_WENLOG_SHIFT 8 -#define CCDC_CCDCFG_TRGSEL_SHIFT 9 -#define CCDC_CCDCFG_EXTRG_SHIFT 10 -#define CCDC_CCDCFG_MSBINVI_SHIFT 13 - -#define CCDC_HSIZE_FLIP_SHIFT 12 -#define CCDC_HSIZE_FLIP_MASK 1 -#define CCDC_HSIZE_VAL_MASK 0xFFF -#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 -#define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D -#define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D -#define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000 -#define CCDC_SDOFST_PROGRESSIVE_NORMAL 0 -#define CCDC_START_PX_HOR_MASK 0x7FFF -#define CCDC_NUM_PX_HOR_MASK 0x7FFF -#define CCDC_START_VER_ONE_MASK 0x7FFF -#define CCDC_START_VER_TWO_MASK 0x7FFF -#define CCDC_NUM_LINES_VER 0x7FFF - -#define CCDC_BLK_CLAMP_ENABLE (1 << 15) -#define CCDC_BLK_SGAIN_MASK 0x1F -#define CCDC_BLK_ST_PXL_MASK 0x1FFF -#define CCDC_BLK_SAMPLE_LN_MASK 3 -#define CCDC_BLK_SAMPLE_LN_SHIFT 13 - -#define CCDC_NUM_LINE_CALC_MASK 3 -#define CCDC_NUM_LINE_CALC_SHIFT 14 - -#define CCDC_BLK_DC_SUB_MASK 0x3FFF -#define CCDC_BLK_COMP_MASK 0xFF -#define CCDC_BLK_COMP_GB_COMP_SHIFT 8 -#define CCDC_BLK_COMP_GR_COMP_SHIFT 0 -#define CCDC_BLK_COMP_R_COMP_SHIFT 8 -#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) -#define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15) -#define CCDC_FPC_ENABLE (1 << 15) -#define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE (1 << 11) -#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 -#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_SHIFT 16 -#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF -#define CCDC_VP_OUT_VERT_NUM_SHIFT 17 -#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF -#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 -#define CCDC_VP_OUT_HORZ_ST_MASK 0xF - -#define CCDC_CSC_COEF_INTEG_MASK 7 -#define CCDC_CSC_COEF_DECIMAL_MASK 0x1f -#define CCDC_CSC_COEF_INTEG_SHIFT 5 -#define CCDC_CSCM_MSB_SHIFT 8 -#define CCDC_CSC_ENABLE 1 -#define CCDC_CSC_DEC_MAX 32 - -#define CCDC_MFILT1_SHIFT 10 -#define CCDC_MFILT2_SHIFT 8 -#define CCDC_MED_FILT_THRESH 0x3FFF -#define CCDC_LPF_MASK 1 -#define CCDC_LPF_SHIFT 14 -#define CCDC_OFFSET_MASK 0x3FF -#define CCDC_DATASFT_MASK 7 -#define CCDC_DATASFT_SHIFT 8 - -#define CCDC_DF_ENABLE 1 - -#define CCDC_FMTPLEN_P0_MASK 0xF -#define CCDC_FMTPLEN_P1_MASK 0xF -#define CCDC_FMTPLEN_P2_MASK 7 -#define CCDC_FMTPLEN_P3_MASK 7 -#define CCDC_FMTPLEN_P0_SHIFT 0 -#define CCDC_FMTPLEN_P1_SHIFT 4 -#define CCDC_FMTPLEN_P2_SHIFT 8 -#define CCDC_FMTPLEN_P3_SHIFT 12 - -#define CCDC_FMTSPH_MASK 0x1FFF -#define CCDC_FMTLNH_MASK 0x1FFF -#define CCDC_FMTSLV_MASK 0x1FFF -#define CCDC_FMTLNV_MASK 0x7FFF -#define CCDC_FMTRLEN_MASK 0x1FFF -#define CCDC_FMTHCNT_MASK 0x1FFF - -#define CCDC_ADP_INIT_MASK 0x1FFF -#define CCDC_ADP_LINE_SHIFT 13 -#define CCDC_ADP_LINE_MASK 3 -#define CCDC_FMTPGN_APTR_MASK 7 - -#define CCDC_DFCCTL_GDFCEN_MASK 1 -#define CCDC_DFCCTL_VDFCEN_MASK 1 -#define CCDC_DFCCTL_VDFC_DISABLE (0 << 4) -#define CCDC_DFCCTL_VDFCEN_SHIFT 4 -#define CCDC_DFCCTL_VDFCSL_MASK 3 -#define CCDC_DFCCTL_VDFCSL_SHIFT 5 -#define CCDC_DFCCTL_VDFCUDA_MASK 1 -#define CCDC_DFCCTL_VDFCUDA_SHIFT 7 -#define CCDC_DFCCTL_VDFLSFT_MASK 3 -#define CCDC_DFCCTL_VDFLSFT_SHIFT 8 -#define CCDC_DFCMEMCTL_DFCMARST_MASK 1 -#define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2 -#define CCDC_DFCMEMCTL_DFCMWR_MASK 1 -#define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0 -#define CCDC_DFCMEMCTL_INC_ADDR (0 << 2) - -#define CCDC_LSCCFG_GFTSF_MASK 7 -#define CCDC_LSCCFG_GFTSF_SHIFT 1 -#define CCDC_LSCCFG_GFTINV_MASK 0xf -#define CCDC_LSCCFG_GFTINV_SHIFT 4 -#define CCDC_LSC_GFTABLE_SEL_MASK 3 -#define CCDC_LSC_GFTABLE_EPEL_SHIFT 8 -#define CCDC_LSC_GFTABLE_OPEL_SHIFT 10 -#define CCDC_LSC_GFTABLE_EPOL_SHIFT 12 -#define CCDC_LSC_GFTABLE_OPOL_SHIFT 14 -#define CCDC_LSC_GFMODE_MASK 3 -#define CCDC_LSC_GFMODE_SHIFT 4 -#define CCDC_LSC_DISABLE 0 -#define CCDC_LSC_ENABLE 1 -#define CCDC_LSC_TABLE1_SLC 0 -#define CCDC_LSC_TABLE2_SLC 1 -#define CCDC_LSC_TABLE3_SLC 2 -#define CCDC_LSC_MEMADDR_RESET (1 << 2) -#define CCDC_LSC_MEMADDR_INCR (0 << 2) -#define CCDC_LSC_FRAC_MASK_T1 0xFF -#define CCDC_LSC_INT_MASK 3 -#define CCDC_LSC_FRAC_MASK 0x3FFF -#define CCDC_LSC_CENTRE_MASK 0x3FFF -#define CCDC_LSC_COEF_MASK 0xff -#define CCDC_LSC_COEFL_SHIFT 0 -#define CCDC_LSC_COEFU_SHIFT 8 -#define CCDC_GAIN_MASK 0x7FF -#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0) -#define CCDC_SYNCEN_WEN_MASK (1 << 1) -#define CCDC_SYNCEN_WEN_SHIFT 1 - -/* Power on Defaults in hardware */ -#define MODESET_DEFAULT 0x200 -#define CULH_DEFAULT 0xFFFF -#define CULV_DEFAULT 0xFF -#define GAIN_DEFAULT 256 -#define OUTCLIP_DEFAULT 0x3FFF -#define LSCCFG2_DEFAULT 0xE - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm644x_ccdc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm644x_ccdc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm644x_ccdc.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm644x_ccdc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1091 +0,0 @@ -/* - * Copyright (C) 2006-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * CCDC hardware module for DM6446 - * ------------------------------ - * - * This module is for configuring CCD controller of DM6446 VPFE to capture - * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules - * such as Defect Pixel Correction, Color Space Conversion etc to - * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This - * module also allows application to configure individual - * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. - * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header - * files. The setparams() API is called by vpfe_capture driver - * to configure module parameters. This file is named DM644x so that other - * variants such DM6443 may be supported using the same module. - * - * TODO: Test Raw bayer parameter settings and bayer capture - * Split module parameter structure to module specific ioctl structs - * investigate if enum used for user space type definition - * to be replaced by #defines or integer - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "dm644x_ccdc_regs.h" -#include "ccdc_hw_device.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CCDC Driver for DM6446"); -MODULE_AUTHOR("Texas Instruments"); - -static struct ccdc_oper_config { - struct device *dev; - /* CCDC interface type */ - enum vpfe_hw_if_type if_type; - /* Raw Bayer configuration */ - struct ccdc_params_raw bayer; - /* YCbCr configuration */ - struct ccdc_params_ycbcr ycbcr; - /* Master clock */ - struct clk *mclk; - /* slave clock */ - struct clk *sclk; - /* ccdc base address */ - void __iomem *base_addr; -} ccdc_cfg = { - /* Raw configurations */ - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .config_params = { - .data_sz = CCDC_DATA_10BITS, - }, - }, - .ycbcr = { - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .win = CCDC_WIN_PAL, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED - }, -}; - -#define CCDC_MAX_RAW_YUV_FORMATS 2 - -/* Raw Bayer formats */ -static u32 ccdc_raw_bayer_pix_formats[] = - {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static u32 ccdc_raw_yuv_pix_formats[] = - {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* CCDC Save/Restore context */ -static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)]; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(ccdc_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, ccdc_cfg.base_addr + offset); -} - -static void ccdc_enable(int flag) -{ - regw(flag, CCDC_PCR); -} - -static void ccdc_enable_vport(int flag) -{ - if (flag) - /* enable video port */ - regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG); - else - regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG); -} - -/* - * ccdc_setwin() - * This function will configure the window size - * to be capture in CCDC reg - */ -void ccdc_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, - int ppc) -{ - int horz_start, horz_nr_pixels; - int vert_start, vert_nr_lines; - int val = 0, mid_img = 0; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; - regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels, - CCDC_HORZ_INFO); - - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* Since first line doesn't have any data */ - vert_start += 1; - /* configure VDINT0 */ - val = (vert_start << CCDC_VDINT_VDINT0_SHIFT); - regw(val, CCDC_VDINT); - - } else { - /* Since first line doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* - * configure VDINT0 and VDINT1. VDINT1 will be at half - * of image height - */ - mid_img = vert_start + (image_win->height / 2); - val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) | - (mid_img & CCDC_VDINT_VDINT1_MASK); - regw(val, CCDC_VDINT); - - } - regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, - CCDC_VERT_START); - regw(vert_nr_lines, CCDC_VERT_LINES); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); -} - -static void ccdc_readregs(void) -{ - unsigned int val = 0; - - val = regr(CCDC_ALAW); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val); - val = regr(CCDC_CLAMP); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val); - val = regr(CCDC_DCSUB); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val); - val = regr(CCDC_BLKCMP); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val); - val = regr(CCDC_FPC_ADDR); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val); - val = regr(CCDC_FPC); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val); - val = regr(CCDC_FMTCFG); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val); - val = regr(CCDC_COLPTN); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val); - val = regr(CCDC_FMT_HORZ); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val); - val = regr(CCDC_FMT_VERT); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val); - val = regr(CCDC_HSIZE_OFF); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val); - val = regr(CCDC_SDOFST); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val); - val = regr(CCDC_VP_OUT); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val); - val = regr(CCDC_SYN_MODE); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val); - val = regr(CCDC_HORZ_INFO); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val); - val = regr(CCDC_VERT_START); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val); - val = regr(CCDC_VERT_LINES); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val); -} - -static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) -{ - if (ccdcparam->alaw.enable) { - if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) || - (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) || - (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { - dev_dbg(ccdc_cfg.dev, "\nInvalid data line select"); - return -1; - } - } - return 0; -} - -static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int *fpc_virtaddr = NULL; - unsigned int *fpc_physaddr = NULL; - - memcpy(config_params, raw_params, sizeof(*raw_params)); - /* - * allocate memory for fault pixel table and copy the user - * values to the table - */ - if (!config_params->fault_pxl.enable) - return 0; - - fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr; - fpc_virtaddr = (unsigned int *)phys_to_virt( - (unsigned long)fpc_physaddr); - /* - * Allocate memory for FPC table if current - * FPC table buffer is not big enough to - * accomodate FPC Number requested - */ - if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) { - if (fpc_physaddr != NULL) { - free_pages((unsigned long)fpc_physaddr, - get_order - (config_params->fault_pxl.fp_num * - FP_NUM_BYTES)); - } - - /* Allocate memory for FPC table */ - fpc_virtaddr = - (unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA, - get_order(raw_params-> - fault_pxl.fp_num * - FP_NUM_BYTES)); - - if (fpc_virtaddr == NULL) { - dev_dbg(ccdc_cfg.dev, - "\nUnable to allocate memory for FPC"); - return -EFAULT; - } - fpc_physaddr = - (unsigned int *)virt_to_phys((void *)fpc_virtaddr); - } - - /* Copy number of fault pixels and FPC table */ - config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num; - if (copy_from_user(fpc_virtaddr, - (void __user *)raw_params->fault_pxl.fpc_table_addr, - config_params->fault_pxl.fp_num * FP_NUM_BYTES)) { - dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed"); - return -EFAULT; - } - config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr; - return 0; -} - -static int ccdc_close(struct device *dev) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL; - - fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr; - - if (fpc_physaddr != NULL) { - fpc_virtaddr = (unsigned int *) - phys_to_virt((unsigned long)fpc_physaddr); - free_pages((unsigned long)fpc_virtaddr, - get_order(config_params->fault_pxl.fp_num * - FP_NUM_BYTES)); - } - return 0; -} - -/* - * ccdc_restore_defaults() - * This function will write defaults to all CCDC registers - */ -static void ccdc_restore_defaults(void) -{ - int i; - - /* disable CCDC */ - ccdc_enable(0); - /* set all registers to default value */ - for (i = 4; i <= 0x94; i += 4) - regw(0, i); - regw(CCDC_NO_CULLING, CCDC_CULLING); - regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW); -} - -static int ccdc_open(struct device *device) -{ - ccdc_restore_defaults(); - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_enable_vport(1); - return 0; -} - -static void ccdc_sbl_reset(void) -{ - vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O); -} - -/* Parameter operations */ -static int ccdc_set_params(void __user *params) -{ - struct ccdc_config_params_raw ccdc_raw_params; - int x; - - if (ccdc_cfg.if_type != VPFE_RAW_BAYER) - return -EINVAL; - - x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); - if (x) { - dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying" - "ccdc params, %d\n", x); - return -EFAULT; - } - - if (!validate_ccdc_param(&ccdc_raw_params)) { - if (!ccdc_update_raw_params(&ccdc_raw_params)) - return 0; - } - return -EINVAL; -} - -/* - * ccdc_config_ycbcr() - * This function will configure CCDC for YCbCr video capture - */ -void ccdc_config_ycbcr(void) -{ - struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; - u32 syn_mode; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); - /* - * first restore the CCDC registers to default values - * This is important since we assume default values to be set in - * a lot of registers that we didn't touch - */ - ccdc_restore_defaults(); - - /* - * configure pixel format, frame format, configure video frame - * format, enable output to SDRAM, enable internal timing generator - * and 8bit pack mode - */ - syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) << - CCDC_SYN_MODE_INPMOD_SHIFT) | - ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) << - CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE | - CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE); - - /* setup BT.656 sync mode */ - if (params->bt656_enable) { - regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF); - - /* - * configure the FID, VD, HD pin polarity, - * fld,hd pol positive, vd negative, 8-bit data - */ - syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE; - if (ccdc_cfg.if_type == VPFE_BT656_10BIT) - syn_mode |= CCDC_SYN_MODE_10BITS; - else - syn_mode |= CCDC_SYN_MODE_8BITS; - } else { - /* y/c external sync mode */ - syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) << - CCDC_FID_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << - CCDC_HD_POL_SHIFT) | - ((params->vd_pol & CCDC_VD_POL_MASK) << - CCDC_VD_POL_SHIFT)); - } - regw(syn_mode, CCDC_SYN_MODE); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 2); - - /* - * configure the order of y cb cr in SDRAM, and disable latch - * internal register on vsync - */ - if (ccdc_cfg.if_type == VPFE_BT656_10BIT) - regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | - CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT, - CCDC_CCDCFG); - else - regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | - CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); - - /* - * configure the horizontal line offset. This should be a - * on 32 byte bondary. So clear LSB 5 bits - */ - regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); - - /* configure the memory line offset */ - if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) - /* two fields are interleaved in memory */ - regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); - - ccdc_sbl_reset(); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); -} - -static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) -{ - u32 val; - - if (!bclamp->enable) { - /* configure DCSub */ - val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; - regw(val, CCDC_DCSUB); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val); - regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n"); - return; - } - /* - * Configure gain, Start pixel, No of line to be avg, - * No of pixel/line to be avg, & Enable the Black clamping - */ - val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) | - ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) << - CCDC_BLK_ST_PXL_SHIFT) | - ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) << - CCDC_BLK_SAMPLE_LINE_SHIFT) | - ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << - CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); - regw(val, CCDC_CLAMP); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val); - /* If Black clamping is enable then make dcsub 0 */ - regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n"); -} - -static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) -{ - u32 val; - - val = ((bcomp->b & CCDC_BLK_COMP_MASK) | - ((bcomp->gb & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GB_COMP_SHIFT) | - ((bcomp->gr & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GR_COMP_SHIFT) | - ((bcomp->r & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_R_COMP_SHIFT)); - regw(val, CCDC_BLKCMP); -} - -static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) -{ - u32 val; - - /* Initially disable FPC */ - val = CCDC_FPC_DISABLE; - regw(val, CCDC_FPC); - - if (!fpc->enable) - return; - - /* Configure Fault pixel if needed */ - regw(fpc->fpc_table_addr, CCDC_FPC_ADDR); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n", - (fpc->fpc_table_addr)); - /* Write the FPC params with FPC disable */ - val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK; - regw(val, CCDC_FPC); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); - /* read the FPC register */ - val = regr(CCDC_FPC) | CCDC_FPC_ENABLE; - regw(val, CCDC_FPC); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); -} - -/* - * ccdc_config_raw() - * This function will configure CCDC for Raw capture mode - */ -void ccdc_config_raw(void) -{ - struct ccdc_params_raw *params = &ccdc_cfg.bayer; - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int syn_mode = 0; - unsigned int val; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); - - /* Reset CCDC */ - ccdc_restore_defaults(); - - /* Disable latching function registers on VSYNC */ - regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); - - /* - * Configure the vertical sync polarity(SYN_MODE.VDPOL), - * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity - * (SYN_MODE.FLDPOL), frame format(progressive or interlace), - * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output - * SDRAM, enable internal timing generator - */ - syn_mode = - (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | - ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | - ((config_params->data_sz & CCDC_DATA_SZ_MASK) << - CCDC_DATA_SZ_SHIFT) | - ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) | - CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE); - - /* Enable and configure aLaw register if needed */ - if (config_params->alaw.enable) { - val = ((config_params->alaw.gama_wd & - CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE); - regw(val, CCDC_ALAW); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); - } - - /* Configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW); - - /* Configure Black Clamp */ - ccdc_config_black_clamp(&config_params->blk_clamp); - - /* Configure Black level compensation */ - ccdc_config_black_compense(&config_params->blk_comp); - - /* Configure Fault Pixel Correction */ - ccdc_config_fpc(&config_params->fault_pxl); - - /* If data size is 8 bit then pack the data */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - syn_mode |= CCDC_DATA_PACK_ENABLE; - -#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE - /* enable video port */ - val = CCDC_ENABLE_VIDEO_PORT; -#else - /* disable video port */ - val = CCDC_DISABLE_VIDEO_PORT; -#endif - - if (config_params->data_sz == CCDC_DATA_8BITS) - val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK) - << CCDC_FMTCFG_VPIN_SHIFT; - else - val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK) - << CCDC_FMTCFG_VPIN_SHIFT; - /* Write value in FMTCFG */ - regw(val, CCDC_FMTCFG); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val); - /* Configure the color pattern according to mt9t001 sensor */ - regw(CCDC_COLPTN_VAL, CCDC_COLPTN); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); - /* - * Configure Data formatter(Video port) pixel selection - * (FMT_HORZ, FMT_VERT) - */ - val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) << - CCDC_FMT_HORZ_FMTSPH_SHIFT) | - (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); - regw(val, CCDC_FMT_HORZ); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val); - val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK) - << CCDC_FMT_VERT_FMTSLV_SHIFT; - if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) - val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK; - else - val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK; - - dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n", - params->win.height); - regw(val, CCDC_FMT_VERT); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val); - - dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)..."); - - /* - * Configure Horizontal offset register. If pack 8 is enabled then - * 1 pixel will take 1 byte - */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) & - CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF); - else - /* else one pixel will take 2 byte */ - regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) + - CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK, - CCDC_HSIZE_OFF); - - /* Set value for SDOFST */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_enable) { - /* For intelace inverse mode */ - regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n"); - } - - else { - /* For intelace non inverse mode */ - regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n"); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n"); - } - - /* - * Configure video port pixel selection (VPOUT) - * Here -1 is to make the height value less than FMT_VERT.FMTLNV - */ - if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) - val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) - << CCDC_VP_OUT_VERT_NUM_SHIFT; - else - val = - ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) - - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) << - CCDC_VP_OUT_VERT_NUM_SHIFT; - - val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK) - << CCDC_VP_OUT_HORZ_NUM_SHIFT; - val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK; - regw(val, CCDC_VP_OUT); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val); - regw(syn_mode, CCDC_SYN_MODE); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); - - ccdc_sbl_reset(); - dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); - ccdc_readregs(); -} - -static int ccdc_configure(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_config_raw(); - else - ccdc_config_ycbcr(); - return 0; -} - -static int ccdc_set_buftype(enum ccdc_buftype buf_type) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.buf_type = buf_type; - else - ccdc_cfg.ycbcr.buf_type = buf_type; - return 0; -} - -static enum ccdc_buftype ccdc_get_buftype(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.buf_type; - return ccdc_cfg.ycbcr.buf_type; -} - -static int ccdc_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { - *pix = ccdc_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { - *pix = ccdc_raw_yuv_pix_formats[i]; - ret = 0; - } - } - return ret; -} - -static int ccdc_set_pixel_format(u32 pixfmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - if (pixfmt == V4L2_PIX_FMT_SBGGR8) - ccdc_cfg.bayer.config_params.alaw.enable = 1; - else if (pixfmt != V4L2_PIX_FMT_SBGGR16) - return -EINVAL; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - } - return 0; -} - -static u32 ccdc_get_pixel_format(void) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - u32 pixfmt; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - if (alaw->enable) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} - -static int ccdc_set_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.win = *win; - else - ccdc_cfg.ycbcr.win = *win; - return 0; -} - -static void ccdc_get_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - *win = ccdc_cfg.bayer.win; - else - *win = ccdc_cfg.ycbcr.win; -} - -static unsigned int ccdc_get_line_length(void) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int len; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if ((config_params->alaw.enable) || - (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_cfg.bayer.win.width; - else - len = ccdc_cfg.bayer.win.width * 2; - } else - len = ccdc_cfg.ycbcr.win.width * 2; - return ALIGN(len, 32); -} - -static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.frm_fmt = frm_fmt; - else - ccdc_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} - -static enum ccdc_frmfmt ccdc_get_frame_format(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.frm_fmt; - else - return ccdc_cfg.ycbcr.frm_fmt; -} - -static int ccdc_getfid(void) -{ - return (regr(CCDC_SYN_MODE) >> 15) & 1; -} - -/* misc operations */ -static inline void ccdc_setfbaddr(unsigned long addr) -{ - regw(addr & 0xffffffe0, CCDC_SDR_ADDR); -} - -static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - ccdc_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_YCBCR_SYNC_16: - case VPFE_YCBCR_SYNC_8: - case VPFE_BT656_10BIT: - ccdc_cfg.ycbcr.vd_pol = params->vdpol; - ccdc_cfg.ycbcr.hd_pol = params->hdpol; - break; - default: - /* TODO add support for raw bayer here */ - return -EINVAL; - } - return 0; -} - -static void ccdc_save_context(void) -{ - ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR); - ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE); - ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID); - ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES); - ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO); - ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START); - ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES); - ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING); - ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF); - ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST); - ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR); - ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP); - ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB); - ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN); - ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP); - ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC); - ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR); - ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT); - ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW); - ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF); - ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG); - ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG); - ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ); - ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT); - ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0); - ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1); - ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2); - ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3); - ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4); - ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5); - ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6); - ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7); - ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0); - ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1); - ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0); - ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1); - ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT); -} - -static void ccdc_restore_context(void) -{ - regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE); - regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID); - regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES); - regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO); - regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START); - regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES); - regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING); - regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF); - regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST); - regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR); - regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP); - regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB); - regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN); - regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP); - regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC); - regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR); - regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT); - regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW); - regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF); - regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG); - regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG); - regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ); - regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT); - regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0); - regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1); - regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2); - regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3); - regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4); - regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5); - regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6); - regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7); - regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0); - regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1); - regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0); - regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1); - regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); - regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); -} -static struct ccdc_hw_device ccdc_hw_dev = { - .name = "DM6446 CCDC", - .owner = THIS_MODULE, - .hw_ops = { - .open = ccdc_open, - .close = ccdc_close, - .reset = ccdc_sbl_reset, - .enable = ccdc_enable, - .set_hw_if_params = ccdc_set_hw_if_params, - .set_params = ccdc_set_params, - .configure = ccdc_configure, - .set_buftype = ccdc_set_buftype, - .get_buftype = ccdc_get_buftype, - .enum_pix = ccdc_enum_pix, - .set_pixel_format = ccdc_set_pixel_format, - .get_pixel_format = ccdc_get_pixel_format, - .set_frame_format = ccdc_set_frame_format, - .get_frame_format = ccdc_get_frame_format, - .set_image_window = ccdc_set_image_window, - .get_image_window = ccdc_get_image_window, - .get_line_length = ccdc_get_line_length, - .setfbaddr = ccdc_setfbaddr, - .getfid = ccdc_getfid, - }, -}; - -static int __init dm644x_ccdc_probe(struct platform_device *pdev) -{ - struct resource *res; - int status = 0; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&ccdc_hw_dev); - if (status < 0) - return status; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - status = -ENODEV; - goto fail_nores; - } - - res = request_mem_region(res->start, resource_size(res), res->name); - if (!res) { - status = -EBUSY; - goto fail_nores; - } - - ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); - if (!ccdc_cfg.base_addr) { - status = -ENOMEM; - goto fail_nomem; - } - - /* Get and enable Master clock */ - ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); - if (IS_ERR(ccdc_cfg.mclk)) { - status = PTR_ERR(ccdc_cfg.mclk); - goto fail_nomap; - } - if (clk_enable(ccdc_cfg.mclk)) { - status = -ENODEV; - goto fail_mclk; - } - - /* Get and enable Slave clock */ - ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); - if (IS_ERR(ccdc_cfg.sclk)) { - status = PTR_ERR(ccdc_cfg.sclk); - goto fail_mclk; - } - if (clk_enable(ccdc_cfg.sclk)) { - status = -ENODEV; - goto fail_sclk; - } - ccdc_cfg.dev = &pdev->dev; - printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); - return 0; -fail_sclk: - clk_put(ccdc_cfg.sclk); -fail_mclk: - clk_put(ccdc_cfg.mclk); -fail_nomap: - iounmap(ccdc_cfg.base_addr); -fail_nomem: - release_mem_region(res->start, resource_size(res)); -fail_nores: - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return status; -} - -static int dm644x_ccdc_remove(struct platform_device *pdev) -{ - struct resource *res; - - clk_put(ccdc_cfg.mclk); - clk_put(ccdc_cfg.sclk); - iounmap(ccdc_cfg.base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return 0; -} - -static int dm644x_ccdc_suspend(struct device *dev) -{ - /* Save CCDC context */ - ccdc_save_context(); - /* Disable CCDC */ - ccdc_enable(0); - /* Disable both master and slave clock */ - clk_disable(ccdc_cfg.mclk); - clk_disable(ccdc_cfg.sclk); - - return 0; -} - -static int dm644x_ccdc_resume(struct device *dev) -{ - /* Enable both master and slave clock */ - clk_enable(ccdc_cfg.mclk); - clk_enable(ccdc_cfg.sclk); - /* Restore CCDC context */ - ccdc_restore_context(); - - return 0; -} - -static const struct dev_pm_ops dm644x_ccdc_pm_ops = { - .suspend = dm644x_ccdc_suspend, - .resume = dm644x_ccdc_resume, -}; - -static struct platform_driver dm644x_ccdc_driver = { - .driver = { - .name = "dm644x_ccdc", - .owner = THIS_MODULE, - .pm = &dm644x_ccdc_pm_ops, - }, - .remove = __devexit_p(dm644x_ccdc_remove), - .probe = dm644x_ccdc_probe, -}; - -static int __init dm644x_ccdc_init(void) -{ - return platform_driver_register(&dm644x_ccdc_driver); -} - -static void __exit dm644x_ccdc_exit(void) -{ - platform_driver_unregister(&dm644x_ccdc_driver); -} - -module_init(dm644x_ccdc_init); -module_exit(dm644x_ccdc_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm644x_ccdc_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm644x_ccdc_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm644x_ccdc_regs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/dm644x_ccdc_regs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2006-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - */ -#ifndef _DM644X_CCDC_REGS_H -#define _DM644X_CCDC_REGS_H - -/**************************************************************************\ -* Register OFFSET Definitions -\**************************************************************************/ -#define CCDC_PID 0x0 -#define CCDC_PCR 0x4 -#define CCDC_SYN_MODE 0x8 -#define CCDC_HD_VD_WID 0xc -#define CCDC_PIX_LINES 0x10 -#define CCDC_HORZ_INFO 0x14 -#define CCDC_VERT_START 0x18 -#define CCDC_VERT_LINES 0x1c -#define CCDC_CULLING 0x20 -#define CCDC_HSIZE_OFF 0x24 -#define CCDC_SDOFST 0x28 -#define CCDC_SDR_ADDR 0x2c -#define CCDC_CLAMP 0x30 -#define CCDC_DCSUB 0x34 -#define CCDC_COLPTN 0x38 -#define CCDC_BLKCMP 0x3c -#define CCDC_FPC 0x40 -#define CCDC_FPC_ADDR 0x44 -#define CCDC_VDINT 0x48 -#define CCDC_ALAW 0x4c -#define CCDC_REC656IF 0x50 -#define CCDC_CCDCFG 0x54 -#define CCDC_FMTCFG 0x58 -#define CCDC_FMT_HORZ 0x5c -#define CCDC_FMT_VERT 0x60 -#define CCDC_FMT_ADDR0 0x64 -#define CCDC_FMT_ADDR1 0x68 -#define CCDC_FMT_ADDR2 0x6c -#define CCDC_FMT_ADDR3 0x70 -#define CCDC_FMT_ADDR4 0x74 -#define CCDC_FMT_ADDR5 0x78 -#define CCDC_FMT_ADDR6 0x7c -#define CCDC_FMT_ADDR7 0x80 -#define CCDC_PRGEVEN_0 0x84 -#define CCDC_PRGEVEN_1 0x88 -#define CCDC_PRGODD_0 0x8c -#define CCDC_PRGODD_1 0x90 -#define CCDC_VP_OUT 0x94 -#define CCDC_REG_END 0x98 - -/*************************************************************** -* Define for various register bit mask and shifts for CCDC -****************************************************************/ -#define CCDC_FID_POL_MASK 1 -#define CCDC_FID_POL_SHIFT 4 -#define CCDC_HD_POL_MASK 1 -#define CCDC_HD_POL_SHIFT 3 -#define CCDC_VD_POL_MASK 1 -#define CCDC_VD_POL_SHIFT 2 -#define CCDC_HSIZE_OFF_MASK 0xffffffe0 -#define CCDC_32BYTE_ALIGN_VAL 31 -#define CCDC_FRM_FMT_MASK 0x1 -#define CCDC_FRM_FMT_SHIFT 7 -#define CCDC_DATA_SZ_MASK 7 -#define CCDC_DATA_SZ_SHIFT 8 -#define CCDC_PIX_FMT_MASK 3 -#define CCDC_PIX_FMT_SHIFT 12 -#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF -#define CCDC_WEN_ENABLE (1 << 17) -#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF -#define CCDC_VDHDEN_ENABLE (1 << 16) -#define CCDC_LPF_ENABLE (1 << 14) -#define CCDC_ALAW_ENABLE (1 << 3) -#define CCDC_ALAW_GAMA_WD_MASK 7 -#define CCDC_BLK_CLAMP_ENABLE (1 << 31) -#define CCDC_BLK_SGAIN_MASK 0x1F -#define CCDC_BLK_ST_PXL_MASK 0x7FFF -#define CCDC_BLK_ST_PXL_SHIFT 10 -#define CCDC_BLK_SAMPLE_LN_MASK 7 -#define CCDC_BLK_SAMPLE_LN_SHIFT 28 -#define CCDC_BLK_SAMPLE_LINE_MASK 7 -#define CCDC_BLK_SAMPLE_LINE_SHIFT 25 -#define CCDC_BLK_DC_SUB_MASK 0x03FFF -#define CCDC_BLK_COMP_MASK 0xFF -#define CCDC_BLK_COMP_GB_COMP_SHIFT 8 -#define CCDC_BLK_COMP_GR_COMP_SHIFT 16 -#define CCDC_BLK_COMP_R_COMP_SHIFT 24 -#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) -#define CCDC_FPC_ENABLE (1 << 15) -#define CCDC_FPC_DISABLE 0 -#define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE (1 << 11) -#define CCDC_FMTCFG_VPIN_MASK 7 -#define CCDC_FMTCFG_VPIN_SHIFT 12 -#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 -#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_SHIFT 16 -#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF -#define CCDC_VP_OUT_VERT_NUM_SHIFT 17 -#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF -#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 -#define CCDC_VP_OUT_HORZ_ST_MASK 0xF -#define CCDC_HORZ_INFO_SPH_SHIFT 16 -#define CCDC_VERT_START_SLV0_SHIFT 16 -#define CCDC_VDINT_VDINT0_SHIFT 16 -#define CCDC_VDINT_VDINT1_MASK 0xFFFF -#define CCDC_PPC_RAW 1 -#define CCDC_DCSUB_DEFAULT_VAL 0 -#define CCDC_CLAMP_DEFAULT_VAL 0 -#define CCDC_ENABLE_VIDEO_PORT 0x8000 -#define CCDC_DISABLE_VIDEO_PORT 0 -#define CCDC_COLPTN_VAL 0xBB11BB11 -#define CCDC_TWO_BYTES_PER_PIXEL 2 -#define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D -#define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249 -#define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000 -#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0 -#define CCDC_INTERLACED_HEIGHT_SHIFT 1 -#define CCDC_SYN_MODE_INPMOD_SHIFT 12 -#define CCDC_SYN_MODE_INPMOD_MASK 3 -#define CCDC_SYN_MODE_8BITS (7 << 8) -#define CCDC_SYN_MODE_10BITS (6 << 8) -#define CCDC_SYN_MODE_11BITS (5 << 8) -#define CCDC_SYN_MODE_12BITS (4 << 8) -#define CCDC_SYN_MODE_13BITS (3 << 8) -#define CCDC_SYN_MODE_14BITS (2 << 8) -#define CCDC_SYN_MODE_15BITS (1 << 8) -#define CCDC_SYN_MODE_16BITS (0 << 8) -#define CCDC_SYN_FLDMODE_MASK 1 -#define CCDC_SYN_FLDMODE_SHIFT 7 -#define CCDC_REC656IF_BT656_EN 3 -#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2) -#define CCDC_CCDCFG_Y8POS_SHIFT 11 -#define CCDC_CCDCFG_BW656_10BIT (1 << 5) -#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 -#define CCDC_NO_CULLING 0xffff00ff -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/isif.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/isif.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/isif.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/isif.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1172 +0,0 @@ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * Image Sensor Interface (ISIF) driver - * - * This driver is for configuring the ISIF IP available on DM365 or any other - * TI SoCs. This is used for capturing yuv or bayer video or image data - * from a decoder or sensor. This IP is similar to the CCDC IP on DM355 - * and DM6446, but with enhanced or additional ip blocks. The driver - * configures the ISIF upon commands from the vpfe bridge driver through - * ccdc_hw_device interface. - * - * TODO: 1) Raw bayer parameter settings and bayer capture - * 2) Add support for control ioctl - */ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "isif_regs.h" -#include "ccdc_hw_device.h" - -/* Defaults for module configuration parameters */ -static struct isif_config_params_raw isif_config_defaults = { - .linearize = { - .en = 0, - .corr_shft = ISIF_NO_SHIFT, - .scale_fact = {1, 0}, - }, - .df_csc = { - .df_or_csc = 0, - .csc = { - .en = 0, - }, - }, - .dfc = { - .en = 0, - }, - .bclamp = { - .en = 0, - }, - .gain_offset = { - .gain = { - .r_ye = {1, 0}, - .gr_cy = {1, 0}, - .gb_g = {1, 0}, - .b_mg = {1, 0}, - }, - }, - .culling = { - .hcpat_odd = 0xff, - .hcpat_even = 0xff, - .vcpat = 0xff, - }, - .compress = { - .alg = ISIF_ALAW, - }, -}; - -/* ISIF operation configuration */ -static struct isif_oper_config { - struct device *dev; - enum vpfe_hw_if_type if_type; - struct isif_ycbcr_config ycbcr; - struct isif_params_raw bayer; - enum isif_data_pack data_pack; - /* Master clock */ - struct clk *mclk; - /* ISIF base address */ - void __iomem *base_addr; - /* ISIF Linear Table 0 */ - void __iomem *linear_tbl0_addr; - /* ISIF Linear Table 1 */ - void __iomem *linear_tbl1_addr; -} isif_cfg = { - .ycbcr = { - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .win = ISIF_WIN_NTSC, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, - }, - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = ISIF_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = {1, 0}, - .gr_cy = {1, 0}, - .gb_g = {1, 0}, - .b_mg = {1, 0}, - }, - .cfa_pat = ISIF_CFA_PAT_MOSAIC, - .data_msb = ISIF_BIT_MSB_11, - .config_params = { - .data_shift = ISIF_NO_SHIFT, - .col_pat_field0 = { - .olop = ISIF_GREEN_BLUE, - .olep = ISIF_BLUE, - .elop = ISIF_RED, - .elep = ISIF_GREEN_RED, - }, - .col_pat_field1 = { - .olop = ISIF_GREEN_BLUE, - .olep = ISIF_BLUE, - .elop = ISIF_RED, - .elep = ISIF_GREEN_RED, - }, - .test_pat_gen = 0, - }, - }, - .data_pack = ISIF_DATA_PACK8, -}; - -/* Raw Bayer formats */ -static const u32 isif_raw_bayer_pix_formats[] = { - V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static const u32 isif_raw_yuv_pix_formats[] = { - V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(isif_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, isif_cfg.base_addr + offset); -} - -/* reg_modify() - read, modify and write register */ -static inline u32 reg_modify(u32 mask, u32 val, u32 offset) -{ - u32 new_val = (regr(offset) & ~mask) | (val & mask); - - regw(new_val, offset); - return new_val; -} - -static inline void regw_lin_tbl(u32 val, u32 offset, int i) -{ - if (!i) - __raw_writel(val, isif_cfg.linear_tbl0_addr + offset); - else - __raw_writel(val, isif_cfg.linear_tbl1_addr + offset); -} - -static void isif_disable_all_modules(void) -{ - /* disable BC */ - regw(0, CLAMPCFG); - /* disable vdfc */ - regw(0, DFCCTL); - /* disable CSC */ - regw(0, CSCCTL); - /* disable linearization */ - regw(0, LINCFG0); - /* disable other modules here as they are supported */ -} - -static void isif_enable(int en) -{ - if (!en) { - /* Before disable isif, disable all ISIF modules */ - isif_disable_all_modules(); - /* - * wait for next VD. Assume lowest scan rate is 12 Hz. So - * 100 msec delay is good enough - */ - msleep(100); - } - reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN); -} - -static void isif_enable_output_to_sdram(int en) -{ - reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); -} - -static void isif_config_culling(struct isif_cul *cul) -{ - u32 val; - - /* Horizontal pattern */ - val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd; - regw(val, CULH); - - /* vertical pattern */ - regw(cul->vcpat, CULV); - - /* LPF */ - reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT, - cul->en_lpf << ISIF_LPF_SHIFT, MODESET); -} - -static void isif_config_gain_offset(void) -{ - struct isif_gain_offsets_adj *gain_off_p = - &isif_cfg.bayer.config_params.gain_offset; - u32 val; - - val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) | - (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) | - (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) | - (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) | - (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) | - (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT); - - reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); - - val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.r_ye.decimal; - regw(val, CRGAIN); - - val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.gr_cy.decimal; - regw(val, CGRGAIN); - - val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.gb_g.decimal; - regw(val, CGBGAIN); - - val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.b_mg.decimal; - regw(val, CBGAIN); - - regw(gain_off_p->offset, COFSTA); -} - -static void isif_restore_defaults(void) -{ - enum vpss_ccdc_source_sel source = VPSS_CCDCIN; - - dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults..."); - isif_cfg.bayer.config_params = isif_config_defaults; - /* Enable clock to ISIF, IPIPEIF and BL */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 1); - vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); - vpss_enable_clock(VPSS_BL_CLOCK, 1); - /* Set default offset and gain */ - isif_config_gain_offset(); - vpss_select_ccdc_source(source); - dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults..."); -} - -static int isif_open(struct device *device) -{ - isif_restore_defaults(); - return 0; -} - -/* This function will configure the window size to be capture in ISIF reg */ -static void isif_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, int ppc) -{ - int horz_start, horz_nr_pixels; - int vert_start, vert_nr_lines; - int mid_img = 0; - - dev_dbg(isif_cfg.dev, "\nStarting isif_setwin..."); - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; - - /* Writing the horizontal info into the registers */ - regw(horz_start & START_PX_HOR_MASK, SPH); - regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - } else { - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* configure VDINT0 and VDINT1 */ - mid_img = vert_start + (image_win->height / 2); - regw(mid_img, VDINT1); - } - - regw(0, VDINT0); - regw(vert_start & START_VER_ONE_MASK, SLV0); - regw(vert_start & START_VER_TWO_MASK, SLV1); - regw(vert_nr_lines & NUM_LINES_VER, LNV); -} - -static void isif_config_bclamp(struct isif_black_clamp *bc) -{ - u32 val; - - /* - * DC Offset is always added to image data irrespective of bc enable - * status - */ - regw(bc->dc_offset, CLDCOFST); - - if (bc->en) { - val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; - - /* Enable BC and horizontal clamp caculation paramaters */ - val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); - - regw(val, CLAMPCFG); - - if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) { - /* - * Window count for calculation - * Base window selection - * pixel limit - * Horizontal size of window - * vertical size of the window - * Horizontal start position of the window - * Vertical start position of the window - */ - val = bc->horz.win_count_calc | - ((!!bc->horz.base_win_sel_calc) << - ISIF_HORZ_BC_WIN_SEL_SHIFT) | - ((!!bc->horz.clamp_pix_limit) << - ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | - (bc->horz.win_h_sz_calc << - ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | - (bc->horz.win_v_sz_calc << - ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); - regw(val, CLHWIN0); - - regw(bc->horz.win_start_h_calc, CLHWIN1); - regw(bc->horz.win_start_v_calc, CLHWIN2); - } - - /* vertical clamp caculation paramaters */ - - /* Reset clamp value sel for previous line */ - val |= - (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) | - (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT); - regw(val, CLVWIN0); - - /* Optical Black horizontal start position */ - regw(bc->vert.ob_start_h, CLVWIN1); - /* Optical Black vertical start position */ - regw(bc->vert.ob_start_v, CLVWIN2); - /* Optical Black vertical size for calculation */ - regw(bc->vert.ob_v_sz_calc, CLVWIN3); - /* Vertical start position for BC subtraction */ - regw(bc->vert_start_sub, CLSV); - } -} - -static void isif_config_linearization(struct isif_linearize *linearize) -{ - u32 val, i; - - if (!linearize->en) { - regw(0, LINCFG0); - return; - } - - /* shift value for correction & enable linearization (set lsb) */ - val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1; - regw(val, LINCFG0); - - /* Scale factor */ - val = ((!!linearize->scale_fact.integer) << - ISIF_LIN_SCALE_FACT_INTEG_SHIFT) | - linearize->scale_fact.decimal; - regw(val, LINCFG1); - - for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) { - if (i % 2) - regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1); - else - regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0); - } -} - -static int isif_config_dfc(struct isif_dfc *vdfc) -{ - /* initialize retries to loop for max ~ 250 usec */ - u32 val, count, retries = loops_per_jiffy / (4000/HZ); - int i; - - if (!vdfc->en) - return 0; - - /* Correction mode */ - val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT); - - /* Correct whole line or partial */ - if (vdfc->corr_whole_line) - val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; - - /* level shift value */ - val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT; - - regw(val, DFCCTL); - - /* Defect saturation level */ - regw(vdfc->def_sat_level, VDFSATLV); - - regw(vdfc->table[0].pos_vert, DFCMEM0); - regw(vdfc->table[0].pos_horz, DFCMEM1); - if (vdfc->corr_mode == ISIF_VDFC_NORMAL || - vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - regw(vdfc->table[0].level_at_pos, DFCMEM2); - regw(vdfc->table[0].level_up_pixels, DFCMEM3); - regw(vdfc->table[0].level_low_pixels, DFCMEM4); - } - - /* set DFCMARST and set DFCMWR */ - val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1; - regw(val, DFCMEMCTL); - - count = retries; - while (count && (regr(DFCMEMCTL) & 0x1)) - count--; - - if (!count) { - dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n"); - return -1; - } - - for (i = 1; i < vdfc->num_vdefects; i++) { - regw(vdfc->table[i].pos_vert, DFCMEM0); - regw(vdfc->table[i].pos_horz, DFCMEM1); - if (vdfc->corr_mode == ISIF_VDFC_NORMAL || - vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - regw(vdfc->table[i].level_at_pos, DFCMEM2); - regw(vdfc->table[i].level_up_pixels, DFCMEM3); - regw(vdfc->table[i].level_low_pixels, DFCMEM4); - } - val = regr(DFCMEMCTL); - /* clear DFCMARST and set DFCMWR */ - val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); - val |= 1; - regw(val, DFCMEMCTL); - - count = retries; - while (count && (regr(DFCMEMCTL) & 0x1)) - count--; - - if (!count) { - dev_err(isif_cfg.dev, - "defect table write timeout !!!\n"); - return -1; - } - } - if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) { - /* Extra cycle needed */ - regw(0, DFCMEM0); - regw(0x1FFF, DFCMEM1); - regw(1, DFCMEMCTL); - } - - /* enable VDFC */ - reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT), - DFCCTL); - return 0; -} - -static void isif_config_csc(struct isif_df_csc *df_csc) -{ - u32 val1 = 0, val2 = 0, i; - - if (!df_csc->csc.en) { - regw(0, CSCCTL); - return; - } - for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = (df_csc->csc.coeff[i].integer << - ISIF_CSC_COEF_INTEG_SHIFT) | - df_csc->csc.coeff[i].decimal; - } else { - - /* CSCM - MSB */ - val2 = (df_csc->csc.coeff[i].integer << - ISIF_CSC_COEF_INTEG_SHIFT) | - df_csc->csc.coeff[i].decimal; - val2 <<= ISIF_CSCM_MSB_SHIFT; - val2 |= val1; - regw(val2, (CSCM0 + ((i - 1) << 1))); - } - } - - /* program the active area */ - regw(df_csc->start_pix, FMTSPH); - /* - * one extra pixel as required for CSC. Actually number of - * pixel - 1 should be configured in this register. So we - * need to subtract 1 before writing to FMTSPH, but we will - * not do this since csc requires one extra pixel - */ - regw(df_csc->num_pixels, FMTLNH); - regw(df_csc->start_line, FMTSLV); - /* - * one extra line as required for CSC. See reason documented for - * num_pixels - */ - regw(df_csc->num_lines, FMTLNV); - - /* Enable CSC */ - regw(1, CSCCTL); -} - -static int isif_config_raw(void) -{ - struct isif_params_raw *params = &isif_cfg.bayer; - struct isif_config_params_raw *module_params = - &isif_cfg.bayer.config_params; - struct vpss_pg_frame_size frame_size; - struct vpss_sync_pol sync; - u32 val; - - dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n"); - - /* - * Configure CCDCFG register:- - * Set CCD Not to swap input since input is RAW data - * Set FID detection function to Latch at V-Sync - * Set WENLOG - isif valid area - * Set TRGSEL - * Set EXTRG - * Packed to 8 or 16 bits - */ - - val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | - ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | - ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack; - - dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val); - regw(val, CCDCFG); - - /* - * Configure the vertical sync polarity(MODESET.VDPOL) - * Configure the horizontal sync polarity (MODESET.HDPOL) - * Configure frame id polarity (MODESET.FLDPOL) - * Configure data polarity - * Configure External WEN Selection - * Configure frame format(progressive or interlace) - * Configure pixel format (Input mode) - * Configure the data shift - */ - - val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) | - (params->hd_pol << ISIF_HD_POL_SHIFT) | - (params->fid_pol << ISIF_FID_POL_SHIFT) | - (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) | - (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) | - (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | - (params->pix_fmt << ISIF_INPUT_SHIFT) | - (params->config_params.data_shift << ISIF_DATASFT_SHIFT); - - regw(val, MODESET); - dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val); - - /* - * Configure GAMMAWD register - * CFA pattern setting - */ - val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT; - - /* Gamma msb */ - if (module_params->compress.alg == ISIF_ALAW) - val |= ISIF_ALAW_ENABLE; - - val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT); - regw(val, CGAMMAWD); - - /* Configure DPCM compression settings */ - if (module_params->compress.alg == ISIF_DPCM) { - val = BIT(ISIF_DPCM_EN_SHIFT) | - (module_params->compress.pred << - ISIF_DPCM_PREDICTOR_SHIFT); - } - - regw(val, MISC); - - /* Configure Gain & Offset */ - isif_config_gain_offset(); - - /* Configure Color pattern */ - val = (params->config_params.col_pat_field0.olop) | - (params->config_params.col_pat_field0.olep << 2) | - (params->config_params.col_pat_field0.elop << 4) | - (params->config_params.col_pat_field0.elep << 6) | - (params->config_params.col_pat_field1.olop << 8) | - (params->config_params.col_pat_field1.olep << 10) | - (params->config_params.col_pat_field1.elop << 12) | - (params->config_params.col_pat_field1.elep << 14); - regw(val, CCOLP); - dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val); - - /* Configure HSIZE register */ - val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT; - - /* calculate line offset in 32 bytes based on pack value */ - if (isif_cfg.data_pack == ISIF_PACK_8BIT) - val |= ((params->win.width + 31) >> 5); - else if (isif_cfg.data_pack == ISIF_PACK_12BIT) - val |= (((params->win.width + - (params->win.width >> 2)) + 31) >> 5); - else - val |= (((params->win.width * 2) + 31) >> 5); - regw(val, HSIZE); - - /* Configure SDOFST register */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_en) { - /* For interlace inverse mode */ - regw(0x4B6D, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n"); - } else { - /* For interlace non inverse mode */ - regw(0x0B6D, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n"); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - if (params->image_invert_en) { - /* For progressive inverse mode */ - regw(0x4000, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n"); - } else { - /* For progressive non inverse mode */ - regw(0x0000, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n"); - } - } - - /* Configure video window */ - isif_setwin(¶ms->win, params->frm_fmt, 1); - - /* Configure Black Clamp */ - isif_config_bclamp(&module_params->bclamp); - - /* Configure Vertical Defection Pixel Correction */ - if (isif_config_dfc(&module_params->dfc) < 0) - return -EFAULT; - - if (!module_params->df_csc.df_or_csc) - /* Configure Color Space Conversion */ - isif_config_csc(&module_params->df_csc); - - isif_config_linearization(&module_params->linearize); - - /* Configure Culling */ - isif_config_culling(&module_params->culling); - - /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */ - regw(module_params->horz_offset, DATAHOFST); - regw(module_params->vert_offset, DATAVOFST); - - /* Setup test pattern if enabled */ - if (params->config_params.test_pat_gen) { - /* Use the HD/VD pol settings from user */ - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - frame_size.hlpfr = isif_cfg.bayer.win.width; - frame_size.pplen = isif_cfg.bayer.win.height; - dm365_vpss_set_pg_frame_size(frame_size); - vpss_select_ccdc_source(VPSS_PGLPBK); - } - - dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n"); - return 0; -} - -static int isif_set_buftype(enum ccdc_buftype buf_type) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - isif_cfg.bayer.buf_type = buf_type; - else - isif_cfg.ycbcr.buf_type = buf_type; - - return 0; - -} -static enum ccdc_buftype isif_get_buftype(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_cfg.bayer.buf_type; - - return isif_cfg.ycbcr.buf_type; -} - -static int isif_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) { - *pix = isif_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) { - *pix = isif_raw_yuv_pix_formats[i]; - ret = 0; - } - } - - return ret; -} - -static int isif_set_pixel_format(unsigned int pixfmt) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (pixfmt == V4L2_PIX_FMT_SBGGR8) { - if ((isif_cfg.bayer.config_params.compress.alg != - ISIF_ALAW) && - (isif_cfg.bayer.config_params.compress.alg != - ISIF_DPCM)) { - dev_dbg(isif_cfg.dev, - "Either configure A-Law or DPCM\n"); - return -EINVAL; - } - isif_cfg.data_pack = ISIF_PACK_8BIT; - } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { - isif_cfg.bayer.config_params.compress.alg = - ISIF_NO_COMPRESSION; - isif_cfg.data_pack = ISIF_PACK_16BIT; - } else - return -EINVAL; - isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - isif_cfg.data_pack = ISIF_PACK_8BIT; - } - return 0; -} - -static u32 isif_get_pixel_format(void) -{ - u32 pixfmt; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) - if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW || - isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} - -static int isif_set_image_window(struct v4l2_rect *win) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - isif_cfg.bayer.win.top = win->top; - isif_cfg.bayer.win.left = win->left; - isif_cfg.bayer.win.width = win->width; - isif_cfg.bayer.win.height = win->height; - } else { - isif_cfg.ycbcr.win.top = win->top; - isif_cfg.ycbcr.win.left = win->left; - isif_cfg.ycbcr.win.width = win->width; - isif_cfg.ycbcr.win.height = win->height; - } - return 0; -} - -static void isif_get_image_window(struct v4l2_rect *win) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - *win = isif_cfg.bayer.win; - else - *win = isif_cfg.ycbcr.win; -} - -static unsigned int isif_get_line_length(void) -{ - unsigned int len; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (isif_cfg.data_pack == ISIF_PACK_8BIT) - len = ((isif_cfg.bayer.win.width)); - else if (isif_cfg.data_pack == ISIF_PACK_12BIT) - len = (((isif_cfg.bayer.win.width * 2) + - (isif_cfg.bayer.win.width >> 2))); - else - len = (((isif_cfg.bayer.win.width * 2))); - } else - len = (((isif_cfg.ycbcr.win.width * 2))); - return ALIGN(len, 32); -} - -static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - isif_cfg.bayer.frm_fmt = frm_fmt; - else - isif_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} -static enum ccdc_frmfmt isif_get_frame_format(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_cfg.bayer.frm_fmt; - return isif_cfg.ycbcr.frm_fmt; -} - -static int isif_getfid(void) -{ - return (regr(MODESET) >> 15) & 0x1; -} - -/* misc operations */ -static void isif_setfbaddr(unsigned long addr) -{ - regw((addr >> 21) & 0x07ff, CADU); - regw((addr >> 5) & 0x0ffff, CADL); -} - -static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - isif_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_BT656_10BIT: - case VPFE_YCBCR_SYNC_8: - isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - break; - case VPFE_BT1120: - case VPFE_YCBCR_SYNC_16: - isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - break; - case VPFE_RAW_BAYER: - isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - break; - default: - dev_dbg(isif_cfg.dev, "Invalid interface type\n"); - return -EINVAL; - } - - return 0; -} - -/* This function will configure ISIF for YCbCr parameters. */ -static int isif_config_ycbcr(void) -{ - struct isif_ycbcr_config *params = &isif_cfg.ycbcr; - struct vpss_pg_frame_size frame_size; - u32 modeset = 0, ccdcfg = 0; - struct vpss_sync_pol sync; - - dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); - - /* configure pixel format or input mode */ - modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) | - (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | - (params->fid_pol << ISIF_FID_POL_SHIFT) | - (params->hd_pol << ISIF_HD_POL_SHIFT) | - (params->vd_pol << ISIF_VD_POL_SHIFT); - - /* pack the data to 8-bit ISIFCFG */ - switch (isif_cfg.if_type) { - case VPFE_BT656: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT); - regw(3, REC656IF); - ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR; - break; - case VPFE_BT656_10BIT: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* setup BT.656, embedded sync */ - regw(3, REC656IF); - /* enable 10 bit mode in ccdcfg */ - ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR | - ISIF_BW656_ENABLE; - break; - case VPFE_BT1120: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - regw(3, REC656IF); - break; - - case VPFE_YCBCR_SYNC_8: - ccdcfg |= ISIF_DATA_PACK8; - ccdcfg |= ISIF_YCINSWP_YCBCR; - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - case VPFE_YCBCR_SYNC_16: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - default: - /* should never come here */ - dev_dbg(isif_cfg.dev, "Invalid interface type\n"); - return -EINVAL; - } - - regw(modeset, MODESET); - - /* Set up pix order */ - ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT; - - regw(ccdcfg, CCDCFG); - - /* configure video window */ - if ((isif_cfg.if_type == VPFE_BT1120) || - (isif_cfg.if_type == VPFE_YCBCR_SYNC_16)) - isif_setwin(¶ms->win, params->frm_fmt, 1); - else - isif_setwin(¶ms->win, params->frm_fmt, 2); - - /* - * configure the horizontal line offset - * this is done by rounding up width to a multiple of 16 pixels - * and multiply by two to account for y:cb:cr 4:2:2 data - */ - regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE); - - /* configure the memory line offset */ - if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) && - (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) - /* two fields are interleaved in memory */ - regw(0x00000249, SDOFST); - - /* Setup test pattern if enabled */ - if (isif_cfg.bayer.config_params.test_pat_gen) { - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - dm365_vpss_set_pg_frame_size(frame_size); - } - return 0; -} - -static int isif_configure(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_config_raw(); - return isif_config_ycbcr(); -} - -static int isif_close(struct device *device) -{ - /* copy defaults to module params */ - isif_cfg.bayer.config_params = isif_config_defaults; - return 0; -} - -static struct ccdc_hw_device isif_hw_dev = { - .name = "ISIF", - .owner = THIS_MODULE, - .hw_ops = { - .open = isif_open, - .close = isif_close, - .enable = isif_enable, - .enable_out_to_sdram = isif_enable_output_to_sdram, - .set_hw_if_params = isif_set_hw_if_params, - .configure = isif_configure, - .set_buftype = isif_set_buftype, - .get_buftype = isif_get_buftype, - .enum_pix = isif_enum_pix, - .set_pixel_format = isif_set_pixel_format, - .get_pixel_format = isif_get_pixel_format, - .set_frame_format = isif_set_frame_format, - .get_frame_format = isif_get_frame_format, - .set_image_window = isif_set_image_window, - .get_image_window = isif_get_image_window, - .get_line_length = isif_get_line_length, - .setfbaddr = isif_setfbaddr, - .getfid = isif_getfid, - }, -}; - -static int __init isif_probe(struct platform_device *pdev) -{ - void (*setup_pinmux)(void); - struct resource *res; - void *__iomem addr; - int status = 0, i; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&isif_hw_dev); - if (status < 0) - return status; - - /* Get and enable Master clock */ - isif_cfg.mclk = clk_get(&pdev->dev, "master"); - if (IS_ERR(isif_cfg.mclk)) { - status = PTR_ERR(isif_cfg.mclk); - goto fail_mclk; - } - if (clk_enable(isif_cfg.mclk)) { - status = -ENODEV; - goto fail_mclk; - } - - /* Platform data holds setup_pinmux function ptr */ - if (NULL == pdev->dev.platform_data) { - status = -ENODEV; - goto fail_mclk; - } - setup_pinmux = pdev->dev.platform_data; - /* - * setup Mux configuration for ccdc which may be different for - * different SoCs using this CCDC - */ - setup_pinmux(); - - i = 0; - /* Get the ISIF base address, linearization table0 and table1 addr. */ - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (!res) { - status = -ENODEV; - goto fail_nobase_res; - } - res = request_mem_region(res->start, resource_size(res), - res->name); - if (!res) { - status = -EBUSY; - goto fail_nobase_res; - } - addr = ioremap_nocache(res->start, resource_size(res)); - if (!addr) { - status = -ENOMEM; - goto fail_base_iomap; - } - switch (i) { - case 0: - /* ISIF base address */ - isif_cfg.base_addr = addr; - break; - case 1: - /* ISIF linear tbl0 address */ - isif_cfg.linear_tbl0_addr = addr; - break; - default: - /* ISIF linear tbl0 address */ - isif_cfg.linear_tbl1_addr = addr; - break; - } - i++; - } - isif_cfg.dev = &pdev->dev; - - printk(KERN_NOTICE "%s is registered with vpfe.\n", - isif_hw_dev.name); - return 0; -fail_base_iomap: - release_mem_region(res->start, resource_size(res)); - i--; -fail_nobase_res: - if (isif_cfg.base_addr) - iounmap(isif_cfg.base_addr); - if (isif_cfg.linear_tbl0_addr) - iounmap(isif_cfg.linear_tbl0_addr); - - while (i >= 0) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - release_mem_region(res->start, resource_size(res)); - i--; - } -fail_mclk: - clk_put(isif_cfg.mclk); - vpfe_unregister_ccdc_device(&isif_hw_dev); - return status; -} - -static int isif_remove(struct platform_device *pdev) -{ - struct resource *res; - int i = 0; - - iounmap(isif_cfg.base_addr); - iounmap(isif_cfg.linear_tbl0_addr); - iounmap(isif_cfg.linear_tbl1_addr); - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (res) - release_mem_region(res->start, resource_size(res)); - i++; - } - vpfe_unregister_ccdc_device(&isif_hw_dev); - return 0; -} - -static struct platform_driver isif_driver = { - .driver = { - .name = "isif", - .owner = THIS_MODULE, - }, - .remove = __devexit_p(isif_remove), - .probe = isif_probe, -}; - -static int __init isif_init(void) -{ - return platform_driver_register(&isif_driver); -} - -static void isif_exit(void) -{ - platform_driver_unregister(&isif_driver); -} - -module_init(isif_init); -module_exit(isif_exit); - -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/isif_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/isif_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/isif_regs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/isif_regs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,269 +0,0 @@ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - */ -#ifndef _ISIF_REGS_H -#define _ISIF_REGS_H - -/* ISIF registers relative offsets */ -#define SYNCEN 0x00 -#define MODESET 0x04 -#define HDW 0x08 -#define VDW 0x0c -#define PPLN 0x10 -#define LPFR 0x14 -#define SPH 0x18 -#define LNH 0x1c -#define SLV0 0x20 -#define SLV1 0x24 -#define LNV 0x28 -#define CULH 0x2c -#define CULV 0x30 -#define HSIZE 0x34 -#define SDOFST 0x38 -#define CADU 0x3c -#define CADL 0x40 -#define LINCFG0 0x44 -#define LINCFG1 0x48 -#define CCOLP 0x4c -#define CRGAIN 0x50 -#define CGRGAIN 0x54 -#define CGBGAIN 0x58 -#define CBGAIN 0x5c -#define COFSTA 0x60 -#define FLSHCFG0 0x64 -#define FLSHCFG1 0x68 -#define FLSHCFG2 0x6c -#define VDINT0 0x70 -#define VDINT1 0x74 -#define VDINT2 0x78 -#define MISC 0x7c -#define CGAMMAWD 0x80 -#define REC656IF 0x84 -#define CCDCFG 0x88 -/***************************************************** -* Defect Correction registers -*****************************************************/ -#define DFCCTL 0x8c -#define VDFSATLV 0x90 -#define DFCMEMCTL 0x94 -#define DFCMEM0 0x98 -#define DFCMEM1 0x9c -#define DFCMEM2 0xa0 -#define DFCMEM3 0xa4 -#define DFCMEM4 0xa8 -/**************************************************** -* Black Clamp registers -****************************************************/ -#define CLAMPCFG 0xac -#define CLDCOFST 0xb0 -#define CLSV 0xb4 -#define CLHWIN0 0xb8 -#define CLHWIN1 0xbc -#define CLHWIN2 0xc0 -#define CLVRV 0xc4 -#define CLVWIN0 0xc8 -#define CLVWIN1 0xcc -#define CLVWIN2 0xd0 -#define CLVWIN3 0xd4 -/**************************************************** -* Lense Shading Correction -****************************************************/ -#define DATAHOFST 0xd8 -#define DATAVOFST 0xdc -#define LSCHVAL 0xe0 -#define LSCVVAL 0xe4 -#define TWODLSCCFG 0xe8 -#define TWODLSCOFST 0xec -#define TWODLSCINI 0xf0 -#define TWODLSCGRBU 0xf4 -#define TWODLSCGRBL 0xf8 -#define TWODLSCGROF 0xfc -#define TWODLSCORBU 0x100 -#define TWODLSCORBL 0x104 -#define TWODLSCOROF 0x108 -#define TWODLSCIRQEN 0x10c -#define TWODLSCIRQST 0x110 -/**************************************************** -* Data formatter -****************************************************/ -#define FMTCFG 0x114 -#define FMTPLEN 0x118 -#define FMTSPH 0x11c -#define FMTLNH 0x120 -#define FMTSLV 0x124 -#define FMTLNV 0x128 -#define FMTRLEN 0x12c -#define FMTHCNT 0x130 -#define FMTAPTR_BASE 0x134 -/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ -#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) -#define FMTPGMVF0 0x174 -#define FMTPGMVF1 0x178 -#define FMTPGMAPU0 0x17c -#define FMTPGMAPU1 0x180 -#define FMTPGMAPS0 0x184 -#define FMTPGMAPS1 0x188 -#define FMTPGMAPS2 0x18c -#define FMTPGMAPS3 0x190 -#define FMTPGMAPS4 0x194 -#define FMTPGMAPS5 0x198 -#define FMTPGMAPS6 0x19c -#define FMTPGMAPS7 0x1a0 -/************************************************ -* Color Space Converter -************************************************/ -#define CSCCTL 0x1a4 -#define CSCM0 0x1a8 -#define CSCM1 0x1ac -#define CSCM2 0x1b0 -#define CSCM3 0x1b4 -#define CSCM4 0x1b8 -#define CSCM5 0x1bc -#define CSCM6 0x1c0 -#define CSCM7 0x1c4 -#define OBWIN0 0x1c8 -#define OBWIN1 0x1cc -#define OBWIN2 0x1d0 -#define OBWIN3 0x1d4 -#define OBVAL0 0x1d8 -#define OBVAL1 0x1dc -#define OBVAL2 0x1e0 -#define OBVAL3 0x1e4 -#define OBVAL4 0x1e8 -#define OBVAL5 0x1ec -#define OBVAL6 0x1f0 -#define OBVAL7 0x1f4 -#define CLKCTL 0x1f8 - -/* Masks & Shifts below */ -#define START_PX_HOR_MASK 0x7FFF -#define NUM_PX_HOR_MASK 0x7FFF -#define START_VER_ONE_MASK 0x7FFF -#define START_VER_TWO_MASK 0x7FFF -#define NUM_LINES_VER 0x7FFF - -/* gain - offset masks */ -#define GAIN_INTEGER_SHIFT 9 -#define OFFSET_MASK 0xFFF -#define GAIN_SDRAM_EN_SHIFT 12 -#define GAIN_IPIPE_EN_SHIFT 13 -#define GAIN_H3A_EN_SHIFT 14 -#define OFST_SDRAM_EN_SHIFT 8 -#define OFST_IPIPE_EN_SHIFT 9 -#define OFST_H3A_EN_SHIFT 10 -#define GAIN_OFFSET_EN_MASK 0x7700 - -/* Culling */ -#define CULL_PAT_EVEN_LINE_SHIFT 8 - -/* CCDCFG register */ -#define ISIF_YCINSWP_RAW (0x00 << 4) -#define ISIF_YCINSWP_YCBCR (0x01 << 4) -#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) -#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) -#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) -#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) -#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) -#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) -#define ISIF_DATA_PACK_MASK 3 -#define ISIF_DATA_PACK16 0 -#define ISIF_DATA_PACK12 1 -#define ISIF_DATA_PACK8 2 -#define ISIF_PIX_ORDER_SHIFT 11 -#define ISIF_BW656_ENABLE (0x01 << 5) - -/* MODESET registers */ -#define ISIF_VDHDOUT_INPUT (0x00 << 0) -#define ISIF_INPUT_SHIFT 12 -#define ISIF_RAW_INPUT_MODE 0 -#define ISIF_FID_POL_SHIFT 4 -#define ISIF_HD_POL_SHIFT 3 -#define ISIF_VD_POL_SHIFT 2 -#define ISIF_DATAPOL_NORMAL 0 -#define ISIF_DATAPOL_SHIFT 6 -#define ISIF_EXWEN_DISABLE 0 -#define ISIF_EXWEN_SHIFT 5 -#define ISIF_FRM_FMT_SHIFT 7 -#define ISIF_DATASFT_SHIFT 8 -#define ISIF_LPF_SHIFT 14 -#define ISIF_LPF_MASK 1 - -/* GAMMAWD registers */ -#define ISIF_ALAW_GAMA_WD_MASK 0xF -#define ISIF_ALAW_GAMA_WD_SHIFT 1 -#define ISIF_ALAW_ENABLE 1 -#define ISIF_GAMMAWD_CFA_SHIFT 5 - -/* HSIZE registers */ -#define ISIF_HSIZE_FLIP_MASK 1 -#define ISIF_HSIZE_FLIP_SHIFT 12 - -/* MISC registers */ -#define ISIF_DPCM_EN_SHIFT 12 -#define ISIF_DPCM_PREDICTOR_SHIFT 13 - -/* Black clamp related */ -#define ISIF_BC_MODE_COLOR_SHIFT 4 -#define ISIF_HORZ_BC_MODE_SHIFT 1 -#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 -#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 -#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 -#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 -#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 -#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 - -/* VDFC registers */ -#define ISIF_VDFC_EN_SHIFT 4 -#define ISIF_VDFC_CORR_MOD_SHIFT 5 -#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 -#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 -#define ISIF_VDFC_POS_MASK 0x1FFF -#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 - -/* CSC registers */ -#define ISIF_CSC_COEF_INTEG_MASK 7 -#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f -#define ISIF_CSC_COEF_INTEG_SHIFT 5 -#define ISIF_CSCM_MSB_SHIFT 8 -#define ISIF_DF_CSC_SPH_MASK 0x1FFF -#define ISIF_DF_CSC_LNH_MASK 0x1FFF -#define ISIF_DF_CSC_SLV_MASK 0x1FFF -#define ISIF_DF_CSC_LNV_MASK 0x1FFF -#define ISIF_DF_NUMLINES 0x7FFF -#define ISIF_DF_NUMPIX 0x1FFF - -/* Offsets for LSC/DFC/Gain */ -#define ISIF_DATA_H_OFFSET_MASK 0x1FFF -#define ISIF_DATA_V_OFFSET_MASK 0x1FFF - -/* Linearization */ -#define ISIF_LIN_CORRSFT_SHIFT 4 -#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 - - -/* Pattern registers */ -#define ISIF_PG_EN (1 << 3) -#define ISIF_SEL_PG_SRC (3 << 4) -#define ISIF_PG_VD_POL_SHIFT 0 -#define ISIF_PG_HD_POL_SHIFT 1 - -/*random other junk*/ -#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) -#define ISIF_SYNCEN_WEN_MASK (1 << 1) -#define ISIF_SYNCEN_WEN_SHIFT 1 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -config DISPLAY_DAVINCI_DM646X_EVM - tristate "DM646x EVM Video Display" - depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM - select VIDEOBUF_DMA_CONTIG - select VIDEO_DAVINCI_VPIF - select VIDEO_ADV7343 - select VIDEO_THS7303 - help - Support for DM6467 based display device. - - To compile this driver as a module, choose M here: the - module will be called vpif_display. - -config CAPTURE_DAVINCI_DM646X_EVM - tristate "DM646x EVM Video Capture" - depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM - select VIDEOBUF_DMA_CONTIG - select VIDEO_DAVINCI_VPIF - help - Support for DM6467 based capture device. - - To compile this driver as a module, choose M here: the - module will be called vpif_capture. - -config VIDEO_DAVINCI_VPIF - tristate "DaVinci VPIF Driver" - depends on DISPLAY_DAVINCI_DM646X_EVM - help - Support for DaVinci VPIF Driver. - - To compile this driver as a module, choose M here: the - module will be called vpif. - -config VIDEO_VPSS_SYSTEM - tristate "VPSS System module driver" - depends on ARCH_DAVINCI - help - Support for vpss system module for video driver - -config VIDEO_VPFE_CAPTURE - tristate "VPFE Video Capture Driver" - depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3) - select VIDEOBUF_DMA_CONTIG - help - Support for DMx/AMx VPFE based frame grabber. This is the - common V4L2 module for following DMx/AMx SoCs from Texas - Instruments:- DM6446, DM365, DM355 & AM3517/05. - - To compile this driver as a module, choose M here: the - module will be called vpfe-capture. - -config VIDEO_DM6446_CCDC - tristate "DM6446 CCDC HW module" - depends on VIDEO_VPFE_CAPTURE - select VIDEO_VPSS_SYSTEM - default y - help - Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from slave decoders. - - To compile this driver as a module, choose M here: the - module will be called vpfe. - -config VIDEO_DM355_CCDC - tristate "DM355 CCDC HW module" - depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE - select VIDEO_VPSS_SYSTEM - default y - help - Enables DM355 CCD hw module. DM355 CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from a slave decoders - - To compile this driver as a module, choose M here: the - module will be called vpfe. - -config VIDEO_ISIF - tristate "ISIF HW module" - depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE - select VIDEO_VPSS_SYSTEM - default y - help - Enables ISIF hw module. This is the hardware module for - configuring ISIF in VPFE to capture Raw Bayer RGB data from - a image sensor or YUV data from a YUV source. - - To compile this driver as a module, choose M here: the - module will be called vpfe. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -# -# Makefile for the davinci video device drivers. -# - -# VPIF -obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o - -#DM646x EVM Display driver -obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o -#DM646x EVM Capture driver -obj-$(CONFIG_CAPTURE_DAVINCI_DM646X_EVM) += vpif_capture.o - -# Capture: DM6446 and DM355 -obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o -obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o -obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o -obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o -obj-$(CONFIG_VIDEO_ISIF) += isif.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpfe_capture.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpfe_capture.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpfe_capture.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpfe_capture.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2095 +0,0 @@ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * Driver name : VPFE Capture driver - * VPFE Capture driver allows applications to capture and stream video - * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as - * TVP5146 or Raw Bayer RGB image data from an image sensor - * such as Microns' MT9T001, MT9T031 etc. - * - * These SoCs have, in common, a Video Processing Subsystem (VPSS) that - * consists of a Video Processing Front End (VPFE) for capturing - * video/raw image data and Video Processing Back End (VPBE) for displaying - * YUV data through an in-built analog encoder or Digital LCD port. This - * driver is for capture through VPFE. A typical EVM using these SoCs have - * following high level configuration. - * - * - * decoder(TVP5146/ YUV/ - * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) - * data input | | - * V | - * SDRAM | - * V - * Image Processor - * | - * V - * SDRAM - * The data flow happens from a decoder connected to the VPFE over a - * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface - * and to the input of VPFE through an optional MUX (if more inputs are - * to be interfaced on the EVM). The input data is first passed through - * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC - * does very little or no processing on YUV data and does pre-process Raw - * Bayer RGB data through modules such as Defect Pixel Correction (DFC) - * Color Space Conversion (CSC), data gain/offset etc. After this, data - * can be written to SDRAM or can be connected to the image processing - * block such as IPIPE (on DM355 only). - * - * Features supported - * - MMAP IO - * - Capture using TVP5146 over BT.656 - * - support for interfacing decoders using sub device model - * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV - * data capture to SDRAM. - * TODO list - * - Support multiple REQBUF after open - * - Support for de-allocating buffers through REQBUF - * - Support for Raw Bayer RGB capture - * - Support for chaining Image Processor - * - Support for static allocation of buffers - * - Support for USERPTR IO - * - Support for STREAMON before QBUF - * - Support for control ioctls - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "ccdc_hw_device.h" - -static int debug; -static u32 numbuffers = 3; -static u32 bufsize = (720 * 576 * 2); - -module_param(numbuffers, uint, S_IRUGO); -module_param(bufsize, uint, S_IRUGO); -module_param(debug, int, 0644); - -MODULE_PARM_DESC(numbuffers, "buffer count (default:3)"); -MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)"); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); - -/* standard information */ -struct vpfe_standard { - v4l2_std_id std_id; - unsigned int width; - unsigned int height; - struct v4l2_fract pixelaspect; - /* 0 - progressive, 1 - interlaced */ - int frame_format; -}; - -/* ccdc configuration */ -struct ccdc_config { - /* This make sure vpfe is probed and ready to go */ - int vpfe_probed; - /* name of ccdc device */ - char name[32]; -}; - -/* data structures */ -static struct vpfe_config_params config_params = { - .min_numbuffers = 3, - .numbuffers = 3, - .min_bufsize = 720 * 480 * 2, - .device_bufsize = 720 * 576 * 2, -}; - -/* ccdc device registered */ -static struct ccdc_hw_device *ccdc_dev; -/* lock for accessing ccdc information */ -static DEFINE_MUTEX(ccdc_lock); -/* ccdc configuration */ -static struct ccdc_config *ccdc_cfg; - -const struct vpfe_standard vpfe_standards[] = { - {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, - {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, -}; - -/* Used when raw Bayer image from ccdc is directly captured to SDRAM */ -static const struct vpfe_pixel_format vpfe_pix_fmts[] = { - { - .fmtdesc = { - .index = 0, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb 8bit A-Law compr.", - .pixelformat = V4L2_PIX_FMT_SBGGR8, - }, - .bpp = 1, - }, - { - .fmtdesc = { - .index = 1, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb - 16bit", - .pixelformat = V4L2_PIX_FMT_SBGGR16, - }, - .bpp = 2, - }, - { - .fmtdesc = { - .index = 2, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb 8bit DPCM compr.", - .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, - }, - .bpp = 1, - }, - { - .fmtdesc = { - .index = 3, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "YCbCr 4:2:2 Interleaved UYVY", - .pixelformat = V4L2_PIX_FMT_UYVY, - }, - .bpp = 2, - }, - { - .fmtdesc = { - .index = 4, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "YCbCr 4:2:2 Interleaved YUYV", - .pixelformat = V4L2_PIX_FMT_YUYV, - }, - .bpp = 2, - }, - { - .fmtdesc = { - .index = 5, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Y/CbCr 4:2:0 - Semi planar", - .pixelformat = V4L2_PIX_FMT_NV12, - }, - .bpp = 1, - }, -}; - -/* - * vpfe_lookup_pix_format() - * lookup an entry in the vpfe pix format table based on pix_format - */ -static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { - if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat) - return &vpfe_pix_fmts[i]; - } - return NULL; -} - -/* - * vpfe_register_ccdc_device. CCDC module calls this to - * register with vpfe capture - */ -int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) -{ - int ret = 0; - printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); - - BUG_ON(!dev->hw_ops.open); - BUG_ON(!dev->hw_ops.enable); - BUG_ON(!dev->hw_ops.set_hw_if_params); - BUG_ON(!dev->hw_ops.configure); - BUG_ON(!dev->hw_ops.set_buftype); - BUG_ON(!dev->hw_ops.get_buftype); - BUG_ON(!dev->hw_ops.enum_pix); - BUG_ON(!dev->hw_ops.set_frame_format); - BUG_ON(!dev->hw_ops.get_frame_format); - BUG_ON(!dev->hw_ops.get_pixel_format); - BUG_ON(!dev->hw_ops.set_pixel_format); - BUG_ON(!dev->hw_ops.set_image_window); - BUG_ON(!dev->hw_ops.get_image_window); - BUG_ON(!dev->hw_ops.get_line_length); - BUG_ON(!dev->hw_ops.getfid); - - mutex_lock(&ccdc_lock); - if (NULL == ccdc_cfg) { - /* - * TODO. Will this ever happen? if so, we need to fix it. - * Proabably we need to add the request to a linked list and - * walk through it during vpfe probe - */ - printk(KERN_ERR "vpfe capture not initialized\n"); - ret = -EFAULT; - goto unlock; - } - - if (strcmp(dev->name, ccdc_cfg->name)) { - /* ignore this ccdc */ - ret = -EINVAL; - goto unlock; - } - - if (ccdc_dev) { - printk(KERN_ERR "ccdc already registered\n"); - ret = -EINVAL; - goto unlock; - } - - ccdc_dev = dev; -unlock: - mutex_unlock(&ccdc_lock); - return ret; -} -EXPORT_SYMBOL(vpfe_register_ccdc_device); - -/* - * vpfe_unregister_ccdc_device. CCDC module calls this to - * unregister with vpfe capture - */ -void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) -{ - if (NULL == dev) { - printk(KERN_ERR "invalid ccdc device ptr\n"); - return; - } - - printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n", - dev->name); - - if (strcmp(dev->name, ccdc_cfg->name)) { - /* ignore this ccdc */ - return; - } - - mutex_lock(&ccdc_lock); - ccdc_dev = NULL; - mutex_unlock(&ccdc_lock); - return; -} -EXPORT_SYMBOL(vpfe_unregister_ccdc_device); - -/* - * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings - */ -static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev, - struct v4l2_format *f) -{ - struct v4l2_rect image_win; - enum ccdc_buftype buf_type; - enum ccdc_frmfmt frm_fmt; - - memset(f, 0, sizeof(*f)); - f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ccdc_dev->hw_ops.get_image_window(&image_win); - f->fmt.pix.width = image_win.width; - f->fmt.pix.height = image_win.height; - f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height; - buf_type = ccdc_dev->hw_ops.get_buftype(); - f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format(); - frm_fmt = ccdc_dev->hw_ops.get_frame_format(); - if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE) - f->fmt.pix.field = V4L2_FIELD_NONE; - else if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) - f->fmt.pix.field = V4L2_FIELD_INTERLACED; - else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED) - f->fmt.pix.field = V4L2_FIELD_SEQ_TB; - else { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n"); - return -EINVAL; - } - } else { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n"); - return -EINVAL; - } - return 0; -} - -/* - * vpfe_config_ccdc_image_format() - * For a pix format, configure ccdc to setup the capture - */ -static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; - int ret = 0; - - if (ccdc_dev->hw_ops.set_pixel_format( - vpfe_dev->fmt.fmt.pix.pixelformat) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "couldn't set pix format in ccdc\n"); - return -EINVAL; - } - /* configure the image window */ - ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop); - - switch (vpfe_dev->fmt.fmt.pix.field) { - case V4L2_FIELD_INTERLACED: - /* do nothing, since it is default */ - ret = ccdc_dev->hw_ops.set_buftype( - CCDC_BUFTYPE_FLD_INTERLEAVED); - break; - case V4L2_FIELD_NONE: - frm_fmt = CCDC_FRMFMT_PROGRESSIVE; - /* buffer type only applicable for interlaced scan */ - break; - case V4L2_FIELD_SEQ_TB: - ret = ccdc_dev->hw_ops.set_buftype( - CCDC_BUFTYPE_FLD_SEPARATED); - break; - default: - return -EINVAL; - } - - /* set the frame format */ - if (!ret) - ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt); - return ret; -} -/* - * vpfe_config_image_format() - * For a given standard, this functions sets up the default - * pix format & crop values in the vpfe device and ccdc. It first - * starts with defaults based values from the standard table. - * It then checks if sub device support g_mbus_fmt and then override the - * values based on that.Sets crop values to match with scan resolution - * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the - * values in ccdc - */ -static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, - const v4l2_std_id *std_id) -{ - struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; - struct v4l2_mbus_framefmt mbus_fmt; - struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix; - int i, ret = 0; - - for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { - if (vpfe_standards[i].std_id & *std_id) { - vpfe_dev->std_info.active_pixels = - vpfe_standards[i].width; - vpfe_dev->std_info.active_lines = - vpfe_standards[i].height; - vpfe_dev->std_info.frame_format = - vpfe_standards[i].frame_format; - vpfe_dev->std_index = i; - break; - } - } - - if (i == ARRAY_SIZE(vpfe_standards)) { - v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n"); - return -EINVAL; - } - - vpfe_dev->crop.top = 0; - vpfe_dev->crop.left = 0; - vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels; - vpfe_dev->crop.height = vpfe_dev->std_info.active_lines; - pix->width = vpfe_dev->crop.width; - pix->height = vpfe_dev->crop.height; - - /* first field and frame format based on standard frame format */ - if (vpfe_dev->std_info.frame_format) { - pix->field = V4L2_FIELD_INTERLACED; - /* assume V4L2_PIX_FMT_UYVY as default */ - pix->pixelformat = V4L2_PIX_FMT_UYVY; - v4l2_fill_mbus_format(&mbus_fmt, pix, - V4L2_MBUS_FMT_YUYV10_2X10); - } else { - pix->field = V4L2_FIELD_NONE; - /* assume V4L2_PIX_FMT_SBGGR8 */ - pix->pixelformat = V4L2_PIX_FMT_SBGGR8; - v4l2_fill_mbus_format(&mbus_fmt, pix, - V4L2_MBUS_FMT_SBGGR8_1X8); - } - - /* if sub device supports g_mbus_fmt, override the defaults */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt); - - if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&vpfe_dev->v4l2_dev, - "error in getting g_mbus_fmt from sub device\n"); - return ret; - } - v4l2_fill_pix_format(pix, &mbus_fmt); - pix->bytesperline = pix->width * 2; - pix->sizeimage = pix->bytesperline * pix->height; - - /* Sets the values in CCDC */ - ret = vpfe_config_ccdc_image_format(vpfe_dev); - if (ret) - return ret; - - /* Update the values of sizeimage and bytesperline */ - if (!ret) { - pix->bytesperline = ccdc_dev->hw_ops.get_line_length(); - pix->sizeimage = pix->bytesperline * pix->height; - } - return ret; -} - -static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) -{ - int ret = 0; - - /* set first input of current subdevice as the current input */ - vpfe_dev->current_input = 0; - - /* set default standard */ - vpfe_dev->std_index = 0; - - /* Configure the default format information */ - ret = vpfe_config_image_format(vpfe_dev, - &vpfe_standards[vpfe_dev->std_index].std_id); - if (ret) - return ret; - - /* now open the ccdc device to initialize it */ - mutex_lock(&ccdc_lock); - if (NULL == ccdc_dev) { - v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n"); - ret = -ENODEV; - goto unlock; - } - - if (!try_module_get(ccdc_dev->owner)) { - v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n"); - ret = -ENODEV; - goto unlock; - } - ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev); - if (!ret) - vpfe_dev->initialized = 1; - - /* Clear all VPFE/CCDC interrupts */ - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(-1); - -unlock: - mutex_unlock(&ccdc_lock); - return ret; -} - -/* - * vpfe_open : It creates object of file handle structure and - * stores it in private_data member of filepointer - */ -static int vpfe_open(struct file *file) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n"); - - if (!vpfe_dev->cfg->num_subdevs) { - v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n"); - return -ENODEV; - } - - /* Allocate memory for the file handle object */ - fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL); - if (NULL == fh) { - v4l2_err(&vpfe_dev->v4l2_dev, - "unable to allocate memory for file handle object\n"); - return -ENOMEM; - } - /* store pointer to fh in private_data member of file */ - file->private_data = fh; - fh->vpfe_dev = vpfe_dev; - mutex_lock(&vpfe_dev->lock); - /* If decoder is not initialized. initialize it */ - if (!vpfe_dev->initialized) { - if (vpfe_initialize_device(vpfe_dev)) { - mutex_unlock(&vpfe_dev->lock); - return -ENODEV; - } - } - /* Increment device usrs counter */ - vpfe_dev->usrs++; - /* Set io_allowed member to false */ - fh->io_allowed = 0; - /* Initialize priority of this instance to default priority */ - fh->prio = V4L2_PRIORITY_UNSET; - v4l2_prio_open(&vpfe_dev->prio, &fh->prio); - mutex_unlock(&vpfe_dev->lock); - return 0; -} - -static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev) -{ - unsigned long addr; - - vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vpfe_dev->next_frm->queue); - vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE; - addr = videobuf_to_dma_contig(vpfe_dev->next_frm); - - ccdc_dev->hw_ops.setfbaddr(addr); -} - -static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev) -{ - unsigned long addr; - - addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); - addr += vpfe_dev->field_off; - ccdc_dev->hw_ops.setfbaddr(addr); -} - -static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev) -{ - struct timeval timevalue; - - do_gettimeofday(&timevalue); - vpfe_dev->cur_frm->ts = timevalue; - vpfe_dev->cur_frm->state = VIDEOBUF_DONE; - vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage; - wake_up_interruptible(&vpfe_dev->cur_frm->done); - vpfe_dev->cur_frm = vpfe_dev->next_frm; -} - -/* ISR for VINT0*/ -static irqreturn_t vpfe_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - enum v4l2_field field; - int fid; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n"); - field = vpfe_dev->fmt.fmt.pix.field; - - /* if streaming not started, don't do anything */ - if (!vpfe_dev->started) - goto clear_intr; - - /* only for 6446 this will be applicable */ - if (NULL != ccdc_dev->hw_ops.reset) - ccdc_dev->hw_ops.reset(); - - if (field == V4L2_FIELD_NONE) { - /* handle progressive frame capture */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "frame format is progressive...\n"); - if (vpfe_dev->cur_frm != vpfe_dev->next_frm) - vpfe_process_buffer_complete(vpfe_dev); - goto clear_intr; - } - - /* interlaced or TB capture check which field we are in hardware */ - fid = ccdc_dev->hw_ops.getfid(); - - /* switch the software maintained field id */ - vpfe_dev->field_id ^= 1; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n", - fid, vpfe_dev->field_id); - if (fid == vpfe_dev->field_id) { - /* we are in-sync here,continue */ - if (fid == 0) { - /* - * One frame is just being captured. If the next frame - * is available, release the current frame and move on - */ - if (vpfe_dev->cur_frm != vpfe_dev->next_frm) - vpfe_process_buffer_complete(vpfe_dev); - /* - * based on whether the two fields are stored - * interleavely or separately in memory, reconfigure - * the CCDC memory address - */ - if (field == V4L2_FIELD_SEQ_TB) { - vpfe_schedule_bottom_field(vpfe_dev); - } - goto clear_intr; - } - /* - * if one field is just being captured configure - * the next frame get the next frame from the empty - * queue if no frame is available hold on to the - * current buffer - */ - spin_lock(&vpfe_dev->dma_queue_lock); - if (!list_empty(&vpfe_dev->dma_queue) && - vpfe_dev->cur_frm == vpfe_dev->next_frm) - vpfe_schedule_next_buffer(vpfe_dev); - spin_unlock(&vpfe_dev->dma_queue_lock); - } else if (fid == 0) { - /* - * out of sync. Recover from any hardware out-of-sync. - * May loose one frame - */ - vpfe_dev->field_id = fid; - } -clear_intr: - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - - return IRQ_HANDLED; -} - -/* vdint1_isr - isr handler for VINT1 interrupt */ -static irqreturn_t vdint1_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n"); - - /* if streaming not started, don't do anything */ - if (!vpfe_dev->started) { - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - return IRQ_HANDLED; - } - - spin_lock(&vpfe_dev->dma_queue_lock); - if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) && - !list_empty(&vpfe_dev->dma_queue) && - vpfe_dev->cur_frm == vpfe_dev->next_frm) - vpfe_schedule_next_buffer(vpfe_dev); - spin_unlock(&vpfe_dev->dma_queue_lock); - - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - - return IRQ_HANDLED; -} - -static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frame_format; - - frame_format = ccdc_dev->hw_ops.get_frame_format(); - if (frame_format == CCDC_FRMFMT_PROGRESSIVE) - free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); -} - -static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frame_format; - - frame_format = ccdc_dev->hw_ops.get_frame_format(); - if (frame_format == CCDC_FRMFMT_PROGRESSIVE) { - return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr, - IRQF_DISABLED, "vpfe_capture1", - vpfe_dev); - } - return 0; -} - -/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */ -static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev) -{ - vpfe_dev->started = 0; - ccdc_dev->hw_ops.enable(0); - if (ccdc_dev->hw_ops.enable_out_to_sdram) - ccdc_dev->hw_ops.enable_out_to_sdram(0); -} - -/* - * vpfe_release : This function deletes buffer queue, frees the - * buffers and the vpfe file handle - */ -static int vpfe_release(struct file *file) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); - - /* Get the device lock */ - mutex_lock(&vpfe_dev->lock); - /* if this instance is doing IO */ - if (fh->io_allowed) { - if (vpfe_dev->started) { - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, - video, s_stream, 0); - if (ret && (ret != -ENOIOCTLCMD)) - v4l2_err(&vpfe_dev->v4l2_dev, - "stream off failed in subdev\n"); - vpfe_stop_ccdc_capture(vpfe_dev); - vpfe_detach_irq(vpfe_dev); - videobuf_streamoff(&vpfe_dev->buffer_queue); - } - vpfe_dev->io_usrs = 0; - vpfe_dev->numbuffers = config_params.numbuffers; - } - - /* Decrement device usrs counter */ - vpfe_dev->usrs--; - /* Close the priority */ - v4l2_prio_close(&vpfe_dev->prio, fh->prio); - /* If this is the last file handle */ - if (!vpfe_dev->usrs) { - vpfe_dev->initialized = 0; - if (ccdc_dev->hw_ops.close) - ccdc_dev->hw_ops.close(vpfe_dev->pdev); - module_put(ccdc_dev->owner); - } - mutex_unlock(&vpfe_dev->lock); - file->private_data = NULL; - /* Free memory allocated to file handle object */ - kfree(fh); - return 0; -} - -/* - * vpfe_mmap : It is used to map kernel space buffers - * into user spaces - */ -static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) -{ - /* Get the device object and file handle object */ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); - - return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma); -} - -/* - * vpfe_poll: It is used for select/poll system call - */ -static unsigned int vpfe_poll(struct file *file, poll_table *wait) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); - - if (vpfe_dev->started) - return videobuf_poll_stream(file, - &vpfe_dev->buffer_queue, wait); - return 0; -} - -/* vpfe capture driver file operations */ -static const struct v4l2_file_operations vpfe_fops = { - .owner = THIS_MODULE, - .open = vpfe_open, - .release = vpfe_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vpfe_mmap, - .poll = vpfe_poll -}; - -/* - * vpfe_check_format() - * This function adjust the input pixel format as per hardware - * capabilities and update the same in pixfmt. - * Following algorithm used :- - * - * If given pixformat is not in the vpfe list of pix formats or not - * supported by the hardware, current value of pixformat in the device - * is used - * If given field is not supported, then current field is used. If field - * is different from current, then it is matched with that from sub device. - * Minimum height is 2 lines for interlaced or tb field and 1 line for - * progressive. Maximum height is clamped to active active lines of scan - * Minimum width is 32 bytes in memory and width is clamped to active - * pixels of scan. - * bytesperline is a multiple of 32. - */ -static const struct vpfe_pixel_format * - vpfe_check_format(struct vpfe_device *vpfe_dev, - struct v4l2_pix_format *pixfmt) -{ - u32 min_height = 1, min_width = 32, max_width, max_height; - const struct vpfe_pixel_format *vpfe_pix_fmt; - u32 pix; - int temp, found; - - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - if (NULL == vpfe_pix_fmt) { - /* - * use current pixel format in the vpfe device. We - * will find this pix format in the table - */ - pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - } - - /* check if hw supports it */ - temp = 0; - found = 0; - while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { - if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) { - found = 1; - break; - } - temp++; - } - - if (!found) { - /* use current pixel format */ - pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; - /* - * Since this is currently used in the vpfe device, we - * will find this pix format in the table - */ - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - } - - /* check what field format is supported */ - if (pixfmt->field == V4L2_FIELD_ANY) { - /* if field is any, use current value as default */ - pixfmt->field = vpfe_dev->fmt.fmt.pix.field; - } - - /* - * if field is not same as current field in the vpfe device - * try matching the field with the sub device field - */ - if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) { - /* - * If field value is not in the supported fields, use current - * field used in the device as default - */ - switch (pixfmt->field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_SEQ_TB: - /* if sub device is supporting progressive, use that */ - if (!vpfe_dev->std_info.frame_format) - pixfmt->field = V4L2_FIELD_NONE; - break; - case V4L2_FIELD_NONE: - if (vpfe_dev->std_info.frame_format) - pixfmt->field = V4L2_FIELD_INTERLACED; - break; - - default: - /* use current field as default */ - pixfmt->field = vpfe_dev->fmt.fmt.pix.field; - break; - } - } - - /* Now adjust image resolutions supported */ - if (pixfmt->field == V4L2_FIELD_INTERLACED || - pixfmt->field == V4L2_FIELD_SEQ_TB) - min_height = 2; - - max_width = vpfe_dev->std_info.active_pixels; - max_height = vpfe_dev->std_info.active_lines; - min_width /= vpfe_pix_fmt->bpp; - - v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n", - pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp); - - pixfmt->width = clamp((pixfmt->width), min_width, max_width); - pixfmt->height = clamp((pixfmt->height), min_height, max_height); - - /* If interlaced, adjust height to be a multiple of 2 */ - if (pixfmt->field == V4L2_FIELD_INTERLACED) - pixfmt->height &= (~1); - /* - * recalculate bytesperline and sizeimage since width - * and height might have changed - */ - pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31) - & ~31); - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) - pixfmt->sizeimage = - pixfmt->bytesperline * pixfmt->height + - ((pixfmt->bytesperline * pixfmt->height) >> 1); - else - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - - v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height =" - " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", - pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp, - pixfmt->bytesperline, pixfmt->sizeimage); - return vpfe_pix_fmt; -} - -static int vpfe_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); - - cap->version = VPFE_CAPTURE_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); - strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); - strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); - return 0; -} - -static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n"); - /* Fill in the information about format */ - *fmt = vpfe_dev->fmt; - return ret; -} - -static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmt; - int temp_index; - u32 pix; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); - - if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0) - return -EINVAL; - - /* Fill in the information about format */ - pix_fmt = vpfe_lookup_pix_format(pix); - if (NULL != pix_fmt) { - temp_index = fmt->index; - *fmt = pix_fmt->fmtdesc; - fmt->index = temp_index; - return 0; - } - return -EINVAL; -} - -static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmts; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); - - /* If streaming is started, return error */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); - return -EBUSY; - } - - /* Check for valid frame format */ - pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix); - - if (NULL == pix_fmts) - return -EINVAL; - - /* store the pixel format in the device object */ - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - /* First detach any IRQ if currently attached */ - vpfe_detach_irq(vpfe_dev); - vpfe_dev->fmt = *fmt; - /* set image capture parameters in the ccdc */ - ret = vpfe_config_ccdc_image_format(vpfe_dev); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmts; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n"); - - pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix); - if (NULL == pix_fmts) - return -EINVAL; - return 0; -} - -/* - * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a - * given app input index - */ -static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev, - int *subdev_index, - int *subdev_input_index, - int app_input_index) -{ - struct vpfe_config *cfg = vpfe_dev->cfg; - struct vpfe_subdev_info *sdinfo; - int i, j = 0; - - for (i = 0; i < cfg->num_subdevs; i++) { - sdinfo = &cfg->sub_devs[i]; - if (app_input_index < (j + sdinfo->num_inputs)) { - *subdev_index = i; - *subdev_input_index = app_input_index - j; - return 0; - } - j += sdinfo->num_inputs; - } - return -EINVAL; -} - -/* - * vpfe_get_app_input - Get app input index for a given subdev input index - * driver stores the input index of the current sub device and translate it - * when application request the current input - */ -static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev, - int *app_input_index) -{ - struct vpfe_config *cfg = vpfe_dev->cfg; - struct vpfe_subdev_info *sdinfo; - int i, j = 0; - - for (i = 0; i < cfg->num_subdevs; i++) { - sdinfo = &cfg->sub_devs[i]; - if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) { - if (vpfe_dev->current_input >= sdinfo->num_inputs) - return -1; - *app_input_index = j + vpfe_dev->current_input; - return 0; - } - j += sdinfo->num_inputs; - } - return -EINVAL; -} - -static int vpfe_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int subdev, index ; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); - - if (vpfe_get_subdev_input_index(vpfe_dev, - &subdev, - &index, - inp->index) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "input information not found" - " for the subdev\n"); - return -EINVAL; - } - sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; - memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input)); - return 0; -} - -static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); - - return vpfe_get_app_input_index(vpfe_dev, index); -} - - -static int vpfe_s_input(struct file *file, void *priv, unsigned int index) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int subdev_index, inp_index; - struct vpfe_route *route; - u32 input = 0, output = 0; - int ret = -EINVAL; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - /* - * If streaming is started return device busy - * error - */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); - ret = -EBUSY; - goto unlock_out; - } - - if (vpfe_get_subdev_input_index(vpfe_dev, - &subdev_index, - &inp_index, - index) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n"); - goto unlock_out; - } - - sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; - route = &sdinfo->routes[inp_index]; - if (route && sdinfo->can_route) { - input = route->input; - output = route->output; - } - - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_routing, input, output, 0); - - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, - "vpfe_doioctl:error in setting input in decoder\n"); - ret = -EINVAL; - goto unlock_out; - } - vpfe_dev->current_subdev = sdinfo; - vpfe_dev->current_input = index; - vpfe_dev->std_index = 0; - - /* set the bus/interface parameter for the sub device in ccdc */ - ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params); - if (ret) - goto unlock_out; - - /* set the default image parameters in the device */ - ret = vpfe_config_image_format(vpfe_dev, - &vpfe_standards[vpfe_dev->std_index].std_id); -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - sdinfo = vpfe_dev->current_subdev; - if (ret) - return ret; - /* Call querystd function of decoder device */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, querystd, std_id); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); - - /* Call decoder driver function to set the standard */ - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - sdinfo = vpfe_dev->current_subdev; - /* If streaming is started, return device busy error */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); - ret = -EBUSY; - goto unlock_out; - } - - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, s_std, *std_id); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); - goto unlock_out; - } - ret = vpfe_config_image_format(vpfe_dev, std_id); - -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); - - *std_id = vpfe_standards[vpfe_dev->std_index].std_id; - return 0; -} -/* - * Videobuf operations - */ -static int vpfe_videobuf_setup(struct videobuf_queue *vq, - unsigned int *count, - unsigned int *size) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n"); - *size = vpfe_dev->fmt.fmt.pix.sizeimage; - if (vpfe_dev->memory == V4L2_MEMORY_MMAP && - vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize) - *size = config_params.device_bufsize; - - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "count=%d, size=%d\n", *count, *size); - return 0; -} - -static int vpfe_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long addr; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); - - /* If buffer is not initialized, initialize it */ - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = vpfe_dev->fmt.fmt.pix.width; - vb->height = vpfe_dev->fmt.fmt.pix.height; - vb->size = vpfe_dev->fmt.fmt.pix.sizeimage; - vb->field = field; - - ret = videobuf_iolock(vq, vb, NULL); - if (ret < 0) - return ret; - - addr = videobuf_to_dma_contig(vb); - /* Make sure user addresses are aligned to 32 bytes */ - if (!ALIGN(addr, 32)) - return -EINVAL; - - vb->state = VIDEOBUF_PREPARED; - } - return 0; -} - -static void vpfe_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - /* Get the file handle object and device object */ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n"); - - /* add the buffer to the DMA queue */ - spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); - list_add_tail(&vb->queue, &vpfe_dev->dma_queue); - spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); - - /* Change state of the buffer */ - vb->state = VIDEOBUF_QUEUED; -} - -static void vpfe_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n"); - - /* - * We need to flush the buffer from the dma queue since - * they are de-allocated - */ - spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); - INIT_LIST_HEAD(&vpfe_dev->dma_queue); - spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static struct videobuf_queue_ops vpfe_videobuf_qops = { - .buf_setup = vpfe_videobuf_setup, - .buf_prepare = vpfe_videobuf_prepare, - .buf_queue = vpfe_videobuf_queue, - .buf_release = vpfe_videobuf_release, -}; - -/* - * vpfe_reqbufs. currently support REQBUF only once opening - * the device. - */ -static int vpfe_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req_buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - if (vpfe_dev->io_usrs != 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); - ret = -EBUSY; - goto unlock_out; - } - - vpfe_dev->memory = req_buf->memory; - videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue, - &vpfe_videobuf_qops, - vpfe_dev->pdev, - &vpfe_dev->irqlock, - req_buf->type, - vpfe_dev->fmt.fmt.pix.field, - sizeof(struct videobuf_buffer), - fh, NULL); - - fh->io_allowed = 1; - vpfe_dev->io_usrs = 1; - INIT_LIST_HEAD(&vpfe_dev->dma_queue); - ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf); -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - if (vpfe_dev->memory != V4L2_MEMORY_MMAP) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); - return -EINVAL; - } - /* Call videobuf_querybuf to get information */ - return videobuf_querybuf(&vpfe_dev->buffer_queue, buf); -} - -static int vpfe_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* - * If this file handle is not allowed to do IO, - * return error - */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - return videobuf_qbuf(&vpfe_dev->buffer_queue, p); -} - -static int vpfe_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - return videobuf_dqbuf(&vpfe_dev->buffer_queue, - buf, file->f_flags & O_NONBLOCK); -} - -static int vpfe_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - - sdinfo = vpfe_dev->current_subdev; - - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, queryctrl, qctrl); - -} - -static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - - sdinfo = vpfe_dev->current_subdev; - - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, g_ctrl, ctrl); -} - -static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - - sdinfo = vpfe_dev->current_subdev; - - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, s_ctrl, ctrl); -} - -/* - * vpfe_calculate_offsets : This function calculates buffers offset - * for top and bottom field - */ -static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev) -{ - struct v4l2_rect image_win; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n"); - - ccdc_dev->hw_ops.get_image_window(&image_win); - vpfe_dev->field_off = image_win.height * image_win.width; -} - -/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */ -static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev) -{ - ccdc_dev->hw_ops.enable(1); - if (ccdc_dev->hw_ops.enable_out_to_sdram) - ccdc_dev->hw_ops.enable_out_to_sdram(1); - vpfe_dev->started = 1; -} - -/* - * vpfe_streamon. Assume the DMA queue is not empty. - * application is expected to call QBUF before calling - * this ioctl. If not, driver returns error - */ -static int vpfe_streamon(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - unsigned long addr; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If file handle is not allowed IO, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_stream, 1); - - if (ret && (ret != -ENOIOCTLCMD)) { - v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n"); - return -EINVAL; - } - - /* If buffer queue is empty, return error */ - if (list_empty(&vpfe_dev->buffer_queue.stream)) { - v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); - return -EIO; - } - - /* Call videobuf_streamon to start streaming * in videobuf */ - ret = videobuf_streamon(&vpfe_dev->buffer_queue); - if (ret) - return ret; - - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - goto streamoff; - /* Get the next frame from the buffer queue */ - vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, - struct videobuf_buffer, queue); - vpfe_dev->cur_frm = vpfe_dev->next_frm; - /* Remove buffer from the buffer queue */ - list_del(&vpfe_dev->cur_frm->queue); - /* Mark state of the current frame to active */ - vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE; - /* Initialize field_id and started member */ - vpfe_dev->field_id = 0; - addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); - - /* Calculate field offset */ - vpfe_calculate_offsets(vpfe_dev); - - if (vpfe_attach_irq(vpfe_dev) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error in attaching interrupt handle\n"); - ret = -EFAULT; - goto unlock_out; - } - if (ccdc_dev->hw_ops.configure() < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error in configuring ccdc\n"); - ret = -EINVAL; - goto unlock_out; - } - ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr)); - vpfe_start_ccdc_capture(vpfe_dev); - mutex_unlock(&vpfe_dev->lock); - return ret; -unlock_out: - mutex_unlock(&vpfe_dev->lock); -streamoff: - ret = videobuf_streamoff(&vpfe_dev->buffer_queue); - return ret; -} - -static int vpfe_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If io is allowed for this file handle, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - /* If streaming is not started, return error */ - if (!vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "device started\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - vpfe_stop_ccdc_capture(vpfe_dev); - vpfe_detach_irq(vpfe_dev); - - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_stream, 0); - - if (ret && (ret != -ENOIOCTLCMD)) - v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n"); - ret = videobuf_streamoff(&vpfe_dev->buffer_queue); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *crop) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n"); - - if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards)) - return -EINVAL; - - memset(crop, 0, sizeof(struct v4l2_cropcap)); - crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - crop->bounds.width = crop->defrect.width = - vpfe_standards[vpfe_dev->std_index].width; - crop->bounds.height = crop->defrect.height = - vpfe_standards[vpfe_dev->std_index].height; - crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect; - return 0; -} - -static int vpfe_g_crop(struct file *file, void *priv, - struct v4l2_crop *crop) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n"); - - crop->c = vpfe_dev->crop; - return 0; -} - -static int vpfe_s_crop(struct file *file, void *priv, - struct v4l2_crop *crop) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); - - if (vpfe_dev->started) { - /* make sure streaming is not started */ - v4l2_err(&vpfe_dev->v4l2_dev, - "Cannot change crop when streaming is ON\n"); - return -EBUSY; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - if (crop->c.top < 0 || crop->c.left < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "doesn't support negative values for top & left\n"); - ret = -EINVAL; - goto unlock_out; - } - - /* adjust the width to 16 pixel boundry */ - crop->c.width = ((crop->c.width + 15) & ~0xf); - - /* make sure parameters are valid */ - if ((crop->c.left + crop->c.width > - vpfe_dev->std_info.active_pixels) || - (crop->c.top + crop->c.height > - vpfe_dev->std_info.active_lines)) { - v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); - ret = -EINVAL; - goto unlock_out; - } - ccdc_dev->hw_ops.set_image_window(&crop->c); - vpfe_dev->fmt.fmt.pix.width = crop->c.width; - vpfe_dev->fmt.fmt.pix.height = crop->c.height; - vpfe_dev->fmt.fmt.pix.bytesperline = - ccdc_dev->hw_ops.get_line_length(); - vpfe_dev->fmt.fmt.pix.sizeimage = - vpfe_dev->fmt.fmt.pix.bytesperline * - vpfe_dev->fmt.fmt.pix.height; - vpfe_dev->crop = crop->c; -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - - -static long vpfe_param_handler(struct file *file, void *priv, - bool valid_prio, int cmd, void *param) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - int ret = 0; - - v4l2_dbg(2, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n"); - - if (vpfe_dev->started) { - /* only allowed if streaming is not started */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "device already started\n"); - return -EBUSY; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - switch (cmd) { - case VPFE_CMD_S_CCDC_RAW_PARAMS: - v4l2_warn(&vpfe_dev->v4l2_dev, - "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n"); - if (ccdc_dev->hw_ops.set_params) { - ret = ccdc_dev->hw_ops.set_params(param); - if (ret) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "Error setting parameters in CCDC\n"); - goto unlock_out; - } - if (vpfe_get_ccdc_image_format(vpfe_dev, - &vpfe_dev->fmt) < 0) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "Invalid image format at CCDC\n"); - goto unlock_out; - } - } else { - ret = -EINVAL; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n"); - } - break; - default: - ret = -EINVAL; - } -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - - -/* vpfe capture ioctl operations */ -static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { - .vidioc_querycap = vpfe_querycap, - .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap, - .vidioc_enum_input = vpfe_enum_input, - .vidioc_g_input = vpfe_g_input, - .vidioc_s_input = vpfe_s_input, - .vidioc_querystd = vpfe_querystd, - .vidioc_s_std = vpfe_s_std, - .vidioc_g_std = vpfe_g_std, - .vidioc_queryctrl = vpfe_queryctrl, - .vidioc_g_ctrl = vpfe_g_ctrl, - .vidioc_s_ctrl = vpfe_s_ctrl, - .vidioc_reqbufs = vpfe_reqbufs, - .vidioc_querybuf = vpfe_querybuf, - .vidioc_qbuf = vpfe_qbuf, - .vidioc_dqbuf = vpfe_dqbuf, - .vidioc_streamon = vpfe_streamon, - .vidioc_streamoff = vpfe_streamoff, - .vidioc_cropcap = vpfe_cropcap, - .vidioc_g_crop = vpfe_g_crop, - .vidioc_s_crop = vpfe_s_crop, - .vidioc_default = vpfe_param_handler, -}; - -static struct vpfe_device *vpfe_initialize(void) -{ - struct vpfe_device *vpfe_dev; - - /* Default number of buffers should be 3 */ - if ((numbuffers > 0) && - (numbuffers < config_params.min_numbuffers)) - numbuffers = config_params.min_numbuffers; - - /* - * Set buffer size to min buffers size if invalid buffer size is - * given - */ - if (bufsize < config_params.min_bufsize) - bufsize = config_params.min_bufsize; - - config_params.numbuffers = numbuffers; - - if (numbuffers) - config_params.device_bufsize = bufsize; - - /* Allocate memory for device objects */ - vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); - - return vpfe_dev; -} - -/* - * vpfe_probe : This function creates device entries by register - * itself to the V4L2 driver and initializes fields of each - * device objects - */ -static __init int vpfe_probe(struct platform_device *pdev) -{ - struct vpfe_subdev_info *sdinfo; - struct vpfe_config *vpfe_cfg; - struct resource *res1; - struct vpfe_device *vpfe_dev; - struct i2c_adapter *i2c_adap; - struct video_device *vfd; - int ret = -ENOMEM, i, j; - int num_subdevs = 0; - - /* Get the pointer to the device object */ - vpfe_dev = vpfe_initialize(); - - if (!vpfe_dev) { - v4l2_err(pdev->dev.driver, - "Failed to allocate memory for vpfe_dev\n"); - return ret; - } - - vpfe_dev->pdev = &pdev->dev; - - if (NULL == pdev->dev.platform_data) { - v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); - ret = -ENODEV; - goto probe_free_dev_mem; - } - - vpfe_cfg = pdev->dev.platform_data; - vpfe_dev->cfg = vpfe_cfg; - if (NULL == vpfe_cfg->ccdc || - NULL == vpfe_cfg->card_name || - NULL == vpfe_cfg->sub_devs) { - v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - - /* Allocate memory for ccdc configuration */ - ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); - if (NULL == ccdc_cfg) { - v4l2_err(pdev->dev.driver, - "Memory allocation failed for ccdc_cfg\n"); - goto probe_free_lock; - } - - mutex_lock(&ccdc_lock); - - strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); - /* Get VINT0 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT0\n"); - ret = -ENODEV; - goto probe_free_ccdc_cfg_mem; - } - vpfe_dev->ccdc_irq0 = res1->start; - - /* Get VINT1 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT1\n"); - ret = -ENODEV; - goto probe_free_ccdc_cfg_mem; - } - vpfe_dev->ccdc_irq1 = res1->start; - - ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED, - "vpfe_capture0", vpfe_dev); - - if (0 != ret) { - v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); - goto probe_free_ccdc_cfg_mem; - } - - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (NULL == vfd) { - ret = -ENOMEM; - v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); - goto probe_out_release_irq; - } - - /* Initialize field of video device */ - vfd->release = video_device_release; - vfd->fops = &vpfe_fops; - vfd->ioctl_ops = &vpfe_ioctl_ops; - vfd->tvnorms = 0; - vfd->current_norm = V4L2_STD_PAL; - vfd->v4l2_dev = &vpfe_dev->v4l2_dev; - snprintf(vfd->name, sizeof(vfd->name), - "%s_V%d.%d.%d", - CAPTURE_DRV_NAME, - (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, - (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, - (VPFE_CAPTURE_VERSION_CODE) & 0xff); - /* Set video_dev to the video device */ - vpfe_dev->video_dev = vfd; - - ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register v4l2 device.\n"); - goto probe_out_video_release; - } - v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); - spin_lock_init(&vpfe_dev->irqlock); - spin_lock_init(&vpfe_dev->dma_queue_lock); - mutex_init(&vpfe_dev->lock); - - /* Initialize field of the device objects */ - vpfe_dev->numbuffers = config_params.numbuffers; - - /* Initialize prio member of device object */ - v4l2_prio_init(&vpfe_dev->prio); - /* register video device */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "trying to register vpfe device.\n"); - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "video_dev=%x\n", (int)&vpfe_dev->video_dev); - vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = video_register_device(vpfe_dev->video_dev, - VFL_TYPE_GRABBER, -1); - - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register video device.\n"); - goto probe_out_v4l2_unregister; - } - - v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n"); - /* set the driver data in platform device */ - platform_set_drvdata(pdev, vpfe_dev); - /* set driver private data */ - video_set_drvdata(vpfe_dev->video_dev, vpfe_dev); - i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); - num_subdevs = vpfe_cfg->num_subdevs; - vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, - GFP_KERNEL); - if (NULL == vpfe_dev->sd) { - v4l2_err(&vpfe_dev->v4l2_dev, - "unable to allocate memory for subdevice pointers\n"); - ret = -ENOMEM; - goto probe_out_video_unregister; - } - - for (i = 0; i < num_subdevs; i++) { - struct v4l2_input *inps; - - sdinfo = &vpfe_cfg->sub_devs[i]; - - /* Load up the subdevice */ - vpfe_dev->sd[i] = - v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, - i2c_adap, - &sdinfo->board_info, - NULL); - if (vpfe_dev->sd[i]) { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - sdinfo->name); - vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; - /* update tvnorms from the sub devices */ - for (j = 0; j < sdinfo->num_inputs; j++) { - inps = &sdinfo->inputs[j]; - vfd->tvnorms |= inps->std; - } - } else { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s register fails\n", - sdinfo->name); - goto probe_sd_out; - } - } - - /* set first sub device as current one */ - vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; - - /* We have at least one sub device to work with */ - mutex_unlock(&ccdc_lock); - return 0; - -probe_sd_out: - kfree(vpfe_dev->sd); -probe_out_video_unregister: - video_unregister_device(vpfe_dev->video_dev); -probe_out_v4l2_unregister: - v4l2_device_unregister(&vpfe_dev->v4l2_dev); -probe_out_video_release: - if (!video_is_registered(vpfe_dev->video_dev)) - video_device_release(vpfe_dev->video_dev); -probe_out_release_irq: - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); -probe_free_ccdc_cfg_mem: - kfree(ccdc_cfg); -probe_free_lock: - mutex_unlock(&ccdc_lock); -probe_free_dev_mem: - kfree(vpfe_dev); - return ret; -} - -/* - * vpfe_remove : It un-register device from V4L2 driver - */ -static int __devexit vpfe_remove(struct platform_device *pdev) -{ - struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); - - v4l2_info(pdev->dev.driver, "vpfe_remove\n"); - - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - kfree(vpfe_dev->sd); - v4l2_device_unregister(&vpfe_dev->v4l2_dev); - video_unregister_device(vpfe_dev->video_dev); - kfree(vpfe_dev); - kfree(ccdc_cfg); - return 0; -} - -static int vpfe_suspend(struct device *dev) -{ - return 0; -} - -static int vpfe_resume(struct device *dev) -{ - return 0; -} - -static const struct dev_pm_ops vpfe_dev_pm_ops = { - .suspend = vpfe_suspend, - .resume = vpfe_resume, -}; - -static struct platform_driver vpfe_driver = { - .driver = { - .name = CAPTURE_DRV_NAME, - .owner = THIS_MODULE, - .pm = &vpfe_dev_pm_ops, - }, - .probe = vpfe_probe, - .remove = __devexit_p(vpfe_remove), -}; - -static __init int vpfe_init(void) -{ - printk(KERN_NOTICE "vpfe_init\n"); - /* Register driver to the kernel */ - return platform_driver_register(&vpfe_driver); -} - -/* - * vpfe_cleanup : This function un-registers device driver - */ -static void vpfe_cleanup(void) -{ - platform_driver_unregister(&vpfe_driver); -} - -module_init(vpfe_init); -module_exit(vpfe_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,473 +0,0 @@ -/* - * vpif - DM646x Video Port Interface driver - * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) - * that receiveing video byte stream and two channels(2, 3) for video output. - * The hardware supports SDTV, HDTV formats, raw data capture. - * Currently, the driver supports NTSC and PAL standards. - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "vpif.h" - -MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver"); -MODULE_LICENSE("GPL"); - -#define VPIF_CH0_MAX_MODES (22) -#define VPIF_CH1_MAX_MODES (02) -#define VPIF_CH2_MAX_MODES (15) -#define VPIF_CH3_MAX_MODES (02) - -static resource_size_t res_len; -static struct resource *res; -spinlock_t vpif_lock; - -void __iomem *vpif_base; - -/** - * ch_params: video standard configuration parameters for vpif - * The table must include all presets from supported subdevices. - */ -const struct vpif_channel_config_params ch_params[] = { - /* HDTV formats */ - { - .name = "480p59_94", - .width = 720, - .height = 480, - .frm_fmt = 1, - .ycmux_mode = 0, - .eav2sav = 138-8, - .sav2eav = 720, - .l1 = 1, - .l3 = 43, - .l5 = 523, - .vsize = 525, - .capture_format = 0, - .vbi_supported = 0, - .hd_sd = 1, - .dv_preset = V4L2_DV_480P59_94, - }, - { - .name = "576p50", - .width = 720, - .height = 576, - .frm_fmt = 1, - .ycmux_mode = 0, - .eav2sav = 144-8, - .sav2eav = 720, - .l1 = 1, - .l3 = 45, - .l5 = 621, - .vsize = 625, - .capture_format = 0, - .vbi_supported = 0, - .hd_sd = 1, - .dv_preset = V4L2_DV_576P50, - }, - { - .name = "720p50", - .width = 1280, - .height = 720, - .frm_fmt = 1, - .ycmux_mode = 0, - .eav2sav = 700-8, - .sav2eav = 1280, - .l1 = 1, - .l3 = 26, - .l5 = 746, - .vsize = 750, - .capture_format = 0, - .vbi_supported = 0, - .hd_sd = 1, - .dv_preset = V4L2_DV_720P50, - }, - { - .name = "720p60", - .width = 1280, - .height = 720, - .frm_fmt = 1, - .ycmux_mode = 0, - .eav2sav = 370 - 8, - .sav2eav = 1280, - .l1 = 1, - .l3 = 26, - .l5 = 746, - .vsize = 750, - .capture_format = 0, - .vbi_supported = 0, - .hd_sd = 1, - .dv_preset = V4L2_DV_720P60, - }, - { - .name = "1080I50", - .width = 1920, - .height = 1080, - .frm_fmt = 0, - .ycmux_mode = 0, - .eav2sav = 720 - 8, - .sav2eav = 1920, - .l1 = 1, - .l3 = 21, - .l5 = 561, - .l7 = 563, - .l9 = 584, - .l11 = 1124, - .vsize = 1125, - .capture_format = 0, - .vbi_supported = 0, - .hd_sd = 1, - .dv_preset = V4L2_DV_1080I50, - }, - { - .name = "1080I60", - .width = 1920, - .height = 1080, - .frm_fmt = 0, - .ycmux_mode = 0, - .eav2sav = 280 - 8, - .sav2eav = 1920, - .l1 = 1, - .l3 = 21, - .l5 = 561, - .l7 = 563, - .l9 = 584, - .l11 = 1124, - .vsize = 1125, - .capture_format = 0, - .vbi_supported = 0, - .hd_sd = 1, - .dv_preset = V4L2_DV_1080I60, - }, - { - .name = "1080p60", - .width = 1920, - .height = 1080, - .frm_fmt = 1, - .ycmux_mode = 0, - .eav2sav = 280 - 8, - .sav2eav = 1920, - .l1 = 1, - .l3 = 42, - .l5 = 1122, - .vsize = 1125, - .capture_format = 0, - .vbi_supported = 0, - .hd_sd = 1, - .dv_preset = V4L2_DV_1080P60, - }, - - /* SDTV formats */ - { - .name = "NTSC_M", - .width = 720, - .height = 480, - .frm_fmt = 0, - .ycmux_mode = 1, - .eav2sav = 268, - .sav2eav = 1440, - .l1 = 1, - .l3 = 23, - .l5 = 263, - .l7 = 266, - .l9 = 286, - .l11 = 525, - .vsize = 525, - .capture_format = 0, - .vbi_supported = 1, - .hd_sd = 0, - .stdid = V4L2_STD_525_60, - }, - { - .name = "PAL_BDGHIK", - .width = 720, - .height = 576, - .frm_fmt = 0, - .ycmux_mode = 1, - .eav2sav = 280, - .sav2eav = 1440, - .l1 = 1, - .l3 = 23, - .l5 = 311, - .l7 = 313, - .l9 = 336, - .l11 = 624, - .vsize = 625, - .capture_format = 0, - .vbi_supported = 1, - .hd_sd = 0, - .stdid = V4L2_STD_625_50, - }, -}; - -const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params); - -static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) -{ - if (val) - vpif_set_bit(reg, bit); - else - vpif_clr_bit(reg, bit); -} - -/* This structure is used to keep track of VPIF size register's offsets */ -struct vpif_registers { - u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl; - u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt; - u32 vanc1_size, width_mask, len_mask; - u8 max_modes; -}; - -static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = { - /* Channel0 */ - { - VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01, - VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL, - VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, - VPIF_CH0_MAX_MODES, - }, - /* Channel1 */ - { - VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01, - VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL, - VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, - VPIF_CH1_MAX_MODES, - }, - /* Channel2 */ - { - VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01, - VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL, - VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE, - VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF, - VPIF_CH2_MAX_MODES - }, - /* Channel3 */ - { - VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01, - VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL, - VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE, - VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF, - VPIF_CH3_MAX_MODES - }, -}; - -/* vpif_set_mode_info: - * This function is used to set horizontal and vertical config parameters - * As per the standard in the channel, configure the values of L1, L3, - * L5, L7 L9, L11 in VPIF Register , also write width and height - */ -static void vpif_set_mode_info(const struct vpif_channel_config_params *config, - u8 channel_id, u8 config_channel_id) -{ - u32 value; - - value = (config->eav2sav & vpifregs[config_channel_id].width_mask); - value <<= VPIF_CH_LEN_SHIFT; - value |= (config->sav2eav & vpifregs[config_channel_id].width_mask); - regw(value, vpifregs[channel_id].h_cfg); - - value = (config->l1 & vpifregs[config_channel_id].len_mask); - value <<= VPIF_CH_LEN_SHIFT; - value |= (config->l3 & vpifregs[config_channel_id].len_mask); - regw(value, vpifregs[channel_id].v_cfg_00); - - value = (config->l5 & vpifregs[config_channel_id].len_mask); - value <<= VPIF_CH_LEN_SHIFT; - value |= (config->l7 & vpifregs[config_channel_id].len_mask); - regw(value, vpifregs[channel_id].v_cfg_01); - - value = (config->l9 & vpifregs[config_channel_id].len_mask); - value <<= VPIF_CH_LEN_SHIFT; - value |= (config->l11 & vpifregs[config_channel_id].len_mask); - regw(value, vpifregs[channel_id].v_cfg_02); - - value = (config->vsize & vpifregs[config_channel_id].len_mask); - regw(value, vpifregs[channel_id].v_cfg); -} - -/* config_vpif_params - * Function to set the parameters of a channel - * Mainly modifies the channel ciontrol register - * It sets frame format, yc mux mode - */ -static void config_vpif_params(struct vpif_params *vpifparams, - u8 channel_id, u8 found) -{ - const struct vpif_channel_config_params *config = &vpifparams->std_info; - u32 value, ch_nip, reg; - u8 start, end; - int i; - - start = channel_id; - end = channel_id + found; - - for (i = start; i < end; i++) { - reg = vpifregs[i].ch_ctrl; - if (channel_id < 2) - ch_nip = VPIF_CAPTURE_CH_NIP; - else - ch_nip = VPIF_DISPLAY_CH_NIP; - - vpif_wr_bit(reg, ch_nip, config->frm_fmt); - vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode); - vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, - vpifparams->video_params.storage_mode); - - /* Set raster scanning SDR Format */ - vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT); - vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format); - - if (channel_id > 1) /* Set the Pixel enable bit */ - vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT); - else if (config->capture_format) { - /* Set the polarity of various pins */ - vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, - vpifparams->iface.fid_pol); - vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, - vpifparams->iface.vd_pol); - vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, - vpifparams->iface.hd_pol); - - value = regr(reg); - /* Set data width */ - value &= ((~(unsigned int)(0x3)) << - VPIF_CH_DATA_WIDTH_BIT); - value |= ((vpifparams->params.data_sz) << - VPIF_CH_DATA_WIDTH_BIT); - regw(value, reg); - } - - /* Write the pitch in the driver */ - regw((vpifparams->video_params.hpitch), - vpifregs[i].line_offset); - } -} - -/* vpif_set_video_params - * This function is used to set video parameters in VPIF register - */ -int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id) -{ - const struct vpif_channel_config_params *config = &vpifparams->std_info; - int found = 1; - - vpif_set_mode_info(config, channel_id, channel_id); - if (!config->ycmux_mode) { - /* YC are on separate channels (HDTV formats) */ - vpif_set_mode_info(config, channel_id + 1, channel_id); - found = 2; - } - - config_vpif_params(vpifparams, channel_id, found); - - regw(0x80, VPIF_REQ_SIZE); - regw(0x01, VPIF_EMULATION_CTRL); - - return found; -} -EXPORT_SYMBOL(vpif_set_video_params); - -void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, - u8 channel_id) -{ - u32 value; - - value = 0x3F8 & (vbiparams->hstart0); - value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16); - regw(value, vpifregs[channel_id].vanc0_strt); - - value = 0x3F8 & (vbiparams->hstart1); - value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16); - regw(value, vpifregs[channel_id].vanc1_strt); - - value = 0x3F8 & (vbiparams->hsize0); - value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16); - regw(value, vpifregs[channel_id].vanc0_size); - - value = 0x3F8 & (vbiparams->hsize1); - value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16); - regw(value, vpifregs[channel_id].vanc1_size); - -} -EXPORT_SYMBOL(vpif_set_vbi_display_params); - -int vpif_channel_getfid(u8 channel_id) -{ - return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK) - >> VPIF_CH_FID_SHIFT; -} -EXPORT_SYMBOL(vpif_channel_getfid); - -static int __init vpif_probe(struct platform_device *pdev) -{ - int status = 0; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENOENT; - - res_len = res->end - res->start + 1; - - res = request_mem_region(res->start, res_len, res->name); - if (!res) - return -EBUSY; - - vpif_base = ioremap(res->start, res_len); - if (!vpif_base) { - status = -EBUSY; - goto fail; - } - - spin_lock_init(&vpif_lock); - dev_info(&pdev->dev, "vpif probe success\n"); - return 0; - -fail: - release_mem_region(res->start, res_len); - return status; -} - -static int __devexit vpif_remove(struct platform_device *pdev) -{ - iounmap(vpif_base); - release_mem_region(res->start, res_len); - return 0; -} - -static struct platform_driver vpif_driver = { - .driver = { - .name = "vpif", - .owner = THIS_MODULE, - }, - .remove = __devexit_p(vpif_remove), - .probe = vpif_probe, -}; - -static void vpif_exit(void) -{ - platform_driver_unregister(&vpif_driver); -} - -static int __init vpif_init(void) -{ - return platform_driver_register(&vpif_driver); -} -subsys_initcall(vpif_init); -module_exit(vpif_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_capture.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_capture.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_capture.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_capture.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2415 +0,0 @@ -/* - * Copyright (C) 2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * TODO : add support for VBI & HBI data service - * add static buffer allocation - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vpif_capture.h" -#include "vpif.h" - -MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver"); -MODULE_LICENSE("GPL"); - -#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) -#define vpif_dbg(level, debug, fmt, arg...) \ - v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) - -static int debug = 1; -static u32 ch0_numbuffers = 3; -static u32 ch1_numbuffers = 3; -static u32 ch0_bufsize = 1920 * 1080 * 2; -static u32 ch1_bufsize = 720 * 576 * 2; - -module_param(debug, int, 0644); -module_param(ch0_numbuffers, uint, S_IRUGO); -module_param(ch1_numbuffers, uint, S_IRUGO); -module_param(ch0_bufsize, uint, S_IRUGO); -module_param(ch1_bufsize, uint, S_IRUGO); - -MODULE_PARM_DESC(debug, "Debug level 0-1"); -MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)"); -MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)"); -MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)"); -MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)"); - -static struct vpif_config_params config_params = { - .min_numbuffers = 3, - .numbuffers[0] = 3, - .numbuffers[1] = 3, - .min_bufsize[0] = 720 * 480 * 2, - .min_bufsize[1] = 720 * 480 * 2, - .channel_bufsize[0] = 1920 * 1080 * 2, - .channel_bufsize[1] = 720 * 576 * 2, -}; - -/* global variables */ -static struct vpif_device vpif_obj = { {NULL} }; -static struct device *vpif_dev; - -/** - * vpif_uservirt_to_phys : translate user/virtual address to phy address - * @virtp: user/virtual address - * - * This inline function is used to convert user space virtual address to - * physical address. - */ -static inline u32 vpif_uservirt_to_phys(u32 virtp) -{ - unsigned long physp = 0; - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - - vma = find_vma(mm, virtp); - - /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) - physp = virt_to_phys((void *)virtp); - else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) - /** - * this will catch, kernel-allocated, mmaped-to-usermode - * addresses - */ - physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); - else { - /* otherwise, use get_user_pages() for general userland pages */ - int res, nr_pages = 1; - struct page *pages; - - down_read(¤t->mm->mmap_sem); - - res = get_user_pages(current, current->mm, - virtp, nr_pages, 1, 0, &pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (res == nr_pages) - physp = __pa(page_address(&pages[0]) + - (virtp & ~PAGE_MASK)); - else { - vpif_err("get_user_pages failed\n"); - return 0; - } - } - return physp; -} - -/** - * buffer_prepare : callback function for buffer prepare - * @q : buffer queue ptr - * @vb: ptr to video buffer - * @field: field info - * - * This is the callback function for buffer prepare when videobuf_qbuf() - * function is called. The buffer is prepared and user space virtual address - * or user address is converted into physical address - */ -static int vpif_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - unsigned long addr; - - - vpif_dbg(2, debug, "vpif_buffer_prepare\n"); - - common = &ch->common[VPIF_VIDEO_INDEX]; - - /* If buffer is not initialized, initialize it */ - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = common->width; - vb->height = common->height; - vb->size = vb->width * vb->height; - vb->field = field; - } - vb->state = VIDEOBUF_PREPARED; - /** - * if user pointer memory mechanism is used, get the physical - * address of the buffer - */ - if (V4L2_MEMORY_USERPTR == common->memory) { - if (0 == vb->baddr) { - vpif_dbg(1, debug, "buffer address is 0\n"); - return -EINVAL; - - } - vb->boff = vpif_uservirt_to_phys(vb->baddr); - if (!IS_ALIGNED(vb->boff, 8)) - goto exit; - } - - addr = vb->boff; - if (q->streaming) { - if (!IS_ALIGNED((addr + common->ytop_off), 8) || - !IS_ALIGNED((addr + common->ybtm_off), 8) || - !IS_ALIGNED((addr + common->ctop_off), 8) || - !IS_ALIGNED((addr + common->cbtm_off), 8)) - goto exit; - } - return 0; -exit: - vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n"); - return -EINVAL; -} - -/** - * vpif_buffer_setup : Callback function for buffer setup. - * @q: buffer queue ptr - * @count: number of buffers - * @size: size of the buffer - * - * This callback function is called when reqbuf() is called to adjust - * the buffer count and buffer size - */ -static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - - common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_buffer_setup\n"); - - /* If memory type is not mmap, return */ - if (V4L2_MEMORY_MMAP != common->memory) - return 0; - - /* Calculate the size of the buffer */ - *size = config_params.channel_bufsize[ch->channel_id]; - - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; - return 0; -} - -/** - * vpif_buffer_queue : Callback function to add buffer to DMA queue - * @q: ptr to videobuf_queue - * @vb: ptr to videobuf_buffer - */ -static void vpif_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - - common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_buffer_queue\n"); - - /* add the buffer to the DMA queue */ - list_add_tail(&vb->queue, &common->dma_queue); - /* Change state of the buffer */ - vb->state = VIDEOBUF_QUEUED; -} - -/** - * vpif_buffer_release : Callback function to free buffer - * @q: buffer queue ptr - * @vb: ptr to video buffer - * - * This function is called from the videobuf layer to free memory - * allocated to the buffers - */ -static void vpif_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - - common = &ch->common[VPIF_VIDEO_INDEX]; - - videobuf_dma_contig_free(q, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static struct videobuf_queue_ops video_qops = { - .buf_setup = vpif_buffer_setup, - .buf_prepare = vpif_buffer_prepare, - .buf_queue = vpif_buffer_queue, - .buf_release = vpif_buffer_release, -}; - -static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = - { {1, 1} }; - -/** - * vpif_process_buffer_complete: process a completed buffer - * @common: ptr to common channel object - * - * This function time stamp the buffer and mark it as DONE. It also - * wake up any process waiting on the QUEUE and set the next buffer - * as current - */ -static void vpif_process_buffer_complete(struct common_obj *common) -{ - do_gettimeofday(&common->cur_frm->ts); - common->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&common->cur_frm->done); - /* Make curFrm pointing to nextFrm */ - common->cur_frm = common->next_frm; -} - -/** - * vpif_schedule_next_buffer: set next buffer address for capture - * @common : ptr to common channel object - * - * This function will get next buffer from the dma queue and - * set the buffer address in the vpif register for capture. - * the buffer is marked active - */ -static void vpif_schedule_next_buffer(struct common_obj *common) -{ - unsigned long addr = 0; - - common->next_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - /* Remove that buffer from the buffer queue */ - list_del(&common->next_frm->queue); - common->next_frm->state = VIDEOBUF_ACTIVE; - if (V4L2_MEMORY_USERPTR == common->memory) - addr = common->next_frm->boff; - else - addr = videobuf_to_dma_contig(common->next_frm); - - /* Set top and bottom field addresses in VPIF registers */ - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); -} - -/** - * vpif_channel_isr : ISR handler for vpif capture - * @irq: irq number - * @dev_id: dev_id ptr - * - * It changes status of the captured buffer, takes next buffer from the queue - * and sets its address in VPIF registers - */ -static irqreturn_t vpif_channel_isr(int irq, void *dev_id) -{ - struct vpif_device *dev = &vpif_obj; - struct common_obj *common; - struct channel_obj *ch; - enum v4l2_field field; - int channel_id = 0; - int fid = -1, i; - - channel_id = *(int *)(dev_id); - ch = dev->dev[channel_id]; - - field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; - - for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) { - common = &ch->common[i]; - /* skip If streaming is not started in this channel */ - if (0 == common->started) - continue; - - /* Check the field format */ - if (1 == ch->vpifparams.std_info.frm_fmt) { - /* Progressive mode */ - if (list_empty(&common->dma_queue)) - continue; - - if (!channel_first_int[i][channel_id]) - vpif_process_buffer_complete(common); - - channel_first_int[i][channel_id] = 0; - - vpif_schedule_next_buffer(common); - - - channel_first_int[i][channel_id] = 0; - } else { - /** - * Interlaced mode. If it is first interrupt, ignore - * it - */ - if (channel_first_int[i][channel_id]) { - channel_first_int[i][channel_id] = 0; - continue; - } - if (0 == i) { - ch->field_id ^= 1; - /* Get field id from VPIF registers */ - fid = vpif_channel_getfid(ch->channel_id); - if (fid != ch->field_id) { - /** - * If field id does not match stored - * field id, make them in sync - */ - if (0 == fid) - ch->field_id = fid; - return IRQ_HANDLED; - } - } - /* device field id and local field id are in sync */ - if (0 == fid) { - /* this is even field */ - if (common->cur_frm == common->next_frm) - continue; - - /* mark the current buffer as done */ - vpif_process_buffer_complete(common); - } else if (1 == fid) { - /* odd field */ - if (list_empty(&common->dma_queue) || - (common->cur_frm != common->next_frm)) - continue; - - vpif_schedule_next_buffer(common); - } - } - } - return IRQ_HANDLED; -} - -/** - * vpif_update_std_info() - update standard related info - * @ch: ptr to channel object - * - * For a given standard selected by application, update values - * in the device data structures - */ -static int vpif_update_std_info(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct vpif_params *vpifparams = &ch->vpifparams; - const struct vpif_channel_config_params *config; - struct vpif_channel_config_params *std_info = &vpifparams->std_info; - struct video_obj *vid_ch = &ch->video; - int index; - - vpif_dbg(2, debug, "vpif_update_std_info\n"); - - for (index = 0; index < vpif_ch_params_count; index++) { - config = &ch_params[index]; - if (config->hd_sd == 0) { - vpif_dbg(2, debug, "SD format\n"); - if (config->stdid & vid_ch->stdid) { - memcpy(std_info, config, sizeof(*config)); - break; - } - } else { - vpif_dbg(2, debug, "HD format\n"); - if (config->dv_preset == vid_ch->dv_preset) { - memcpy(std_info, config, sizeof(*config)); - break; - } - } - } - - /* standard not found */ - if (index == vpif_ch_params_count) - return -EINVAL; - - common->fmt.fmt.pix.width = std_info->width; - common->width = std_info->width; - common->fmt.fmt.pix.height = std_info->height; - common->height = std_info->height; - common->fmt.fmt.pix.bytesperline = std_info->width; - vpifparams->video_params.hpitch = std_info->width; - vpifparams->video_params.storage_mode = std_info->frm_fmt; - - return 0; -} - -/** - * vpif_calculate_offsets : This function calculates buffers offsets - * @ch : ptr to channel object - * - * This function calculates buffer offsets for Y and C in the top and - * bottom field - */ -static void vpif_calculate_offsets(struct channel_obj *ch) -{ - unsigned int hpitch, vpitch, sizeimage; - struct video_obj *vid_ch = &(ch->video); - struct vpif_params *vpifparams = &ch->vpifparams; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - enum v4l2_field field = common->fmt.fmt.pix.field; - - vpif_dbg(2, debug, "vpif_calculate_offsets\n"); - - if (V4L2_FIELD_ANY == field) { - if (vpifparams->std_info.frm_fmt) - vid_ch->buf_field = V4L2_FIELD_NONE; - else - vid_ch->buf_field = V4L2_FIELD_INTERLACED; - } else - vid_ch->buf_field = common->fmt.fmt.pix.field; - - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = common->fmt.fmt.pix.sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; - - hpitch = common->fmt.fmt.pix.bytesperline; - vpitch = sizeimage / (hpitch * 2); - - if ((V4L2_FIELD_NONE == vid_ch->buf_field) || - (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { - /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ - common->ytop_off = 0; - common->ybtm_off = hpitch; - common->ctop_off = sizeimage / 2; - common->cbtm_off = sizeimage / 2 + hpitch; - } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { - /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ - common->ytop_off = 0; - common->ybtm_off = sizeimage / 4; - common->ctop_off = sizeimage / 2; - common->cbtm_off = common->ctop_off + sizeimage / 4; - } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { - /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ - common->ybtm_off = 0; - common->ytop_off = sizeimage / 4; - common->cbtm_off = sizeimage / 2; - common->ctop_off = common->cbtm_off + sizeimage / 4; - } - if ((V4L2_FIELD_NONE == vid_ch->buf_field) || - (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) - vpifparams->video_params.storage_mode = 1; - else - vpifparams->video_params.storage_mode = 0; - - if (1 == vpifparams->std_info.frm_fmt) - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline; - else { - if ((field == V4L2_FIELD_ANY) - || (field == V4L2_FIELD_INTERLACED)) - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline * 2; - else - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline; - } - - ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid; -} - -/** - * vpif_config_format: configure default frame format in the device - * ch : ptr to channel object - */ -static void vpif_config_format(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_config_format\n"); - - common->fmt.fmt.pix.field = V4L2_FIELD_ANY; - if (config_params.numbuffers[ch->channel_id] == 0) - common->memory = V4L2_MEMORY_USERPTR; - else - common->memory = V4L2_MEMORY_MMAP; - - common->fmt.fmt.pix.sizeimage - = config_params.channel_bufsize[ch->channel_id]; - - if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) - common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; - else - common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; - common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -} - -/** - * vpif_get_default_field() - Get default field type based on interface - * @vpif_params - ptr to vpif params - */ -static inline enum v4l2_field vpif_get_default_field( - struct vpif_interface *iface) -{ - return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE : - V4L2_FIELD_INTERLACED; -} - -/** - * vpif_check_format() - check given pixel format for compatibility - * @ch - channel ptr - * @pixfmt - Given pixel format - * @update - update the values as per hardware requirement - * - * Check the application pixel format for S_FMT and update the input - * values as per hardware limits for TRY_FMT. The default pixel and - * field format is selected based on interface type. - */ -static int vpif_check_format(struct channel_obj *ch, - struct v4l2_pix_format *pixfmt, - int update) -{ - struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); - struct vpif_params *vpif_params = &ch->vpifparams; - enum v4l2_field field = pixfmt->field; - u32 sizeimage, hpitch, vpitch; - int ret = -EINVAL; - - vpif_dbg(2, debug, "vpif_check_format\n"); - /** - * first check for the pixel format. If if_type is Raw bayer, - * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only - * V4L2_PIX_FMT_YUV422P is supported - */ - if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) { - if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) { - if (!update) { - vpif_dbg(2, debug, "invalid pix format\n"); - goto exit; - } - pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8; - } - } else { - if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) { - if (!update) { - vpif_dbg(2, debug, "invalid pixel format\n"); - goto exit; - } - pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P; - } - } - - if (!(VPIF_VALID_FIELD(field))) { - if (!update) { - vpif_dbg(2, debug, "invalid field format\n"); - goto exit; - } - /** - * By default use FIELD_NONE for RAW Bayer capture - * and FIELD_INTERLACED for other interfaces - */ - field = vpif_get_default_field(&vpif_params->iface); - } else if (field == V4L2_FIELD_ANY) - /* unsupported field. Use default */ - field = vpif_get_default_field(&vpif_params->iface); - - /* validate the hpitch */ - hpitch = pixfmt->bytesperline; - if (hpitch < vpif_params->std_info.width) { - if (!update) { - vpif_dbg(2, debug, "invalid hpitch\n"); - goto exit; - } - hpitch = vpif_params->std_info.width; - } - - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = pixfmt->sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; - - vpitch = sizeimage / (hpitch * 2); - - /* validate the vpitch */ - if (vpitch < vpif_params->std_info.height) { - if (!update) { - vpif_dbg(2, debug, "Invalid vpitch\n"); - goto exit; - } - vpitch = vpif_params->std_info.height; - } - - /* Check for 8 byte alignment */ - if (!ALIGN(hpitch, 8)) { - if (!update) { - vpif_dbg(2, debug, "invalid pitch alignment\n"); - goto exit; - } - /* adjust to next 8 byte boundary */ - hpitch = (((hpitch + 7) / 8) * 8); - } - /* if update is set, modify the bytesperline and sizeimage */ - if (update) { - pixfmt->bytesperline = hpitch; - pixfmt->sizeimage = hpitch * vpitch * 2; - } - /** - * Image width and height is always based on current standard width and - * height - */ - pixfmt->width = common->fmt.fmt.pix.width; - pixfmt->height = common->fmt.fmt.pix.height; - return 0; -exit: - return ret; -} - -/** - * vpif_config_addr() - function to configure buffer address in vpif - * @ch - channel ptr - * @muxmode - channel mux mode - */ -static void vpif_config_addr(struct channel_obj *ch, int muxmode) -{ - struct common_obj *common; - - vpif_dbg(2, debug, "vpif_config_addr\n"); - - common = &(ch->common[VPIF_VIDEO_INDEX]); - - if (VPIF_CHANNEL1_VIDEO == ch->channel_id) - common->set_addr = ch1_set_videobuf_addr; - else if (2 == muxmode) - common->set_addr = ch0_set_videobuf_addr_yc_nmux; - else - common->set_addr = ch0_set_videobuf_addr; -} - -/** - * vpfe_mmap : It is used to map kernel space buffers into user spaces - * @filep: file pointer - * @vma: ptr to vm_area_struct - */ -static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) -{ - /* Get the channel object and file handle object */ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); - - vpif_dbg(2, debug, "vpif_mmap\n"); - - return videobuf_mmap_mapper(&common->buffer_queue, vma); -} - -/** - * vpif_poll: It is used for select/poll system call - * @filep: file pointer - * @wait: poll table to wait - */ -static unsigned int vpif_poll(struct file *filep, poll_table * wait) -{ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *channel = fh->channel; - struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]); - - vpif_dbg(2, debug, "vpif_poll\n"); - - if (common->started) - return videobuf_poll_stream(filep, &common->buffer_queue, wait); - return 0; -} - -/** - * vpif_open : vpif open handler - * @filep: file ptr - * - * It creates object of file handle structure and stores it in private_data - * member of filepointer - */ -static int vpif_open(struct file *filep) -{ - struct vpif_capture_config *config = vpif_dev->platform_data; - struct video_device *vdev = video_devdata(filep); - struct common_obj *common; - struct video_obj *vid_ch; - struct channel_obj *ch; - struct vpif_fh *fh; - int i; - - vpif_dbg(2, debug, "vpif_open\n"); - - ch = video_get_drvdata(vdev); - - vid_ch = &ch->video; - common = &ch->common[VPIF_VIDEO_INDEX]; - - if (NULL == ch->curr_subdev_info) { - /** - * search through the sub device to see a registered - * sub device and make it as current sub device - */ - for (i = 0; i < config->subdev_count; i++) { - if (vpif_obj.sd[i]) { - /* the sub device is registered */ - ch->curr_subdev_info = &config->subdev_info[i]; - /* make first input as the current input */ - vid_ch->input_idx = 0; - break; - } - } - if (i == config->subdev_count) { - vpif_err("No sub device registered\n"); - return -ENOENT; - } - } - - /* Allocate memory for the file handle object */ - fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); - if (NULL == fh) { - vpif_err("unable to allocate memory for file handle object\n"); - return -ENOMEM; - } - - /* store pointer to fh in private_data member of filep */ - filep->private_data = fh; - fh->channel = ch; - fh->initialized = 0; - /* If decoder is not initialized. initialize it */ - if (!ch->initialized) { - fh->initialized = 1; - ch->initialized = 1; - memset(&(ch->vpifparams), 0, sizeof(struct vpif_params)); - } - /* Increment channel usrs counter */ - ch->usrs++; - /* Set io_allowed member to false */ - fh->io_allowed[VPIF_VIDEO_INDEX] = 0; - /* Initialize priority of this instance to default priority */ - fh->prio = V4L2_PRIORITY_UNSET; - v4l2_prio_open(&ch->prio, &fh->prio); - return 0; -} - -/** - * vpif_release : function to clean up file close - * @filep: file pointer - * - * This function deletes buffer queue, frees the buffers and the vpfe file - * handle - */ -static int vpif_release(struct file *filep) -{ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - - vpif_dbg(2, debug, "vpif_release\n"); - - common = &ch->common[VPIF_VIDEO_INDEX]; - - /* if this instance is doing IO */ - if (fh->io_allowed[VPIF_VIDEO_INDEX]) { - /* Reset io_usrs member of channel object */ - common->io_usrs = 0; - /* Disable channel as per its device type and channel id */ - if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { - enable_channel0(0); - channel0_intr_enable(0); - } - if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || - (2 == common->started)) { - enable_channel1(0); - channel1_intr_enable(0); - } - common->started = 0; - /* Free buffers allocated */ - videobuf_queue_cancel(&common->buffer_queue); - videobuf_mmap_free(&common->buffer_queue); - } - - /* Decrement channel usrs counter */ - ch->usrs--; - - /* Close the priority */ - v4l2_prio_close(&ch->prio, fh->prio); - - if (fh->initialized) - ch->initialized = 0; - - filep->private_data = NULL; - kfree(fh); - return 0; -} - -/** - * vpif_reqbufs() - request buffer handler - * @file: file ptr - * @priv: file handle - * @reqbuf: request buffer structure ptr - */ -static int vpif_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbuf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - u8 index = 0; - - vpif_dbg(2, debug, "vpif_reqbufs\n"); - - /** - * This file handle has not initialized the channel, - * It is not allowed to do settings - */ - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) - || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - } - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type) - return -EINVAL; - - index = VPIF_VIDEO_INDEX; - - common = &ch->common[index]; - - if (0 != common->io_usrs) - return -EBUSY; - - /* Initialize videobuf queue as per the buffer type */ - videobuf_queue_dma_contig_init(&common->buffer_queue, - &video_qops, NULL, - &common->irqlock, - reqbuf->type, - common->fmt.fmt.pix.field, - sizeof(struct videobuf_buffer), fh, - &common->lock); - - /* Set io allowed member of file handle to TRUE */ - fh->io_allowed[index] = 1; - /* Increment io usrs member of channel object to 1 */ - common->io_usrs = 1; - /* Store type of memory requested in channel object */ - common->memory = reqbuf->memory; - INIT_LIST_HEAD(&common->dma_queue); - - /* Allocate buffers */ - return videobuf_reqbufs(&common->buffer_queue, reqbuf); -} - -/** - * vpif_querybuf() - query buffer handler - * @file: file ptr - * @priv: file handle - * @buf: v4l2 buffer structure ptr - */ -static int vpif_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_querybuf\n"); - - if (common->fmt.type != buf->type) - return -EINVAL; - - if (common->memory != V4L2_MEMORY_MMAP) { - vpif_dbg(1, debug, "Invalid memory\n"); - return -EINVAL; - } - - return videobuf_querybuf(&common->buffer_queue, buf); -} - -/** - * vpif_qbuf() - query buffer handler - * @file: file ptr - * @priv: file handle - * @buf: v4l2 buffer structure ptr - */ -static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct v4l2_buffer tbuf = *buf; - struct videobuf_buffer *buf1; - unsigned long addr = 0; - unsigned long flags; - int ret = 0; - - vpif_dbg(2, debug, "vpif_qbuf\n"); - - if (common->fmt.type != tbuf.type) { - vpif_err("invalid buffer type\n"); - return -EINVAL; - } - - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh io not allowed \n"); - return -EACCES; - } - - if (!(list_empty(&common->dma_queue)) || - (common->cur_frm != common->next_frm) || - !common->started || - (common->started && (0 == ch->field_id))) - return videobuf_qbuf(&common->buffer_queue, buf); - - /* bufferqueue is empty store buffer address in VPIF registers */ - mutex_lock(&common->buffer_queue.vb_lock); - buf1 = common->buffer_queue.bufs[tbuf.index]; - - if ((buf1->state == VIDEOBUF_QUEUED) || - (buf1->state == VIDEOBUF_ACTIVE)) { - vpif_err("invalid state\n"); - goto qbuf_exit; - } - - switch (buf1->memory) { - case V4L2_MEMORY_MMAP: - if (buf1->baddr == 0) - goto qbuf_exit; - break; - - case V4L2_MEMORY_USERPTR: - if (tbuf.length < buf1->bsize) - goto qbuf_exit; - - if ((VIDEOBUF_NEEDS_INIT != buf1->state) - && (buf1->baddr != tbuf.m.userptr)) { - vpif_buffer_release(&common->buffer_queue, buf1); - buf1->baddr = tbuf.m.userptr; - } - break; - - default: - goto qbuf_exit; - } - - local_irq_save(flags); - ret = vpif_buffer_prepare(&common->buffer_queue, buf1, - common->buffer_queue.field); - if (ret < 0) { - local_irq_restore(flags); - goto qbuf_exit; - } - - buf1->state = VIDEOBUF_ACTIVE; - - if (V4L2_MEMORY_USERPTR == common->memory) - addr = buf1->boff; - else - addr = videobuf_to_dma_contig(buf1); - - common->next_frm = buf1; - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); - - local_irq_restore(flags); - list_add_tail(&buf1->stream, &common->buffer_queue.stream); - mutex_unlock(&common->buffer_queue.vb_lock); - return 0; - -qbuf_exit: - mutex_unlock(&common->buffer_queue.vb_lock); - return -EINVAL; -} - -/** - * vpif_dqbuf() - query buffer handler - * @file: file ptr - * @priv: file handle - * @buf: v4l2 buffer structure ptr - */ -static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_dqbuf\n"); - - return videobuf_dqbuf(&common->buffer_queue, buf, - file->f_flags & O_NONBLOCK); -} - -/** - * vpif_streamon() - streamon handler - * @file: file ptr - * @priv: file handle - * @buftype: v4l2 buffer type - */ -static int vpif_streamon(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - - struct vpif_capture_config *config = vpif_dev->platform_data; - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; - struct vpif_params *vpif; - unsigned long addr = 0; - int ret = 0; - - vpif_dbg(2, debug, "vpif_streamon\n"); - - vpif = &ch->vpifparams; - - if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - vpif_dbg(1, debug, "buffer type not supported\n"); - return -EINVAL; - } - - /* If file handle is not allowed IO, return error */ - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_dbg(1, debug, "io not allowed\n"); - return -EACCES; - } - - /* If Streaming is already started, return error */ - if (common->started) { - vpif_dbg(1, debug, "channel->started\n"); - return -EBUSY; - } - - if ((ch->channel_id == VPIF_CHANNEL0_VIDEO && - oth_ch->common[VPIF_VIDEO_INDEX].started && - vpif->std_info.ycmux_mode == 0) || - ((ch->channel_id == VPIF_CHANNEL1_VIDEO) && - (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { - vpif_dbg(1, debug, "other channel is being used\n"); - return -EBUSY; - } - - ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0); - if (ret) - return ret; - - /* Enable streamon on the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 1); - - if (ret && (ret != -ENOIOCTLCMD)) { - vpif_dbg(1, debug, "stream on failed in subdev\n"); - return ret; - } - - /* Call videobuf_streamon to start streaming in videobuf */ - ret = videobuf_streamon(&common->buffer_queue); - if (ret) { - vpif_dbg(1, debug, "videobuf_streamon\n"); - return ret; - } - - /* If buffer queue is empty, return error */ - if (list_empty(&common->dma_queue)) { - vpif_dbg(1, debug, "buffer queue is empty\n"); - ret = -EIO; - goto exit; - } - - /* Get the next frame from the buffer queue */ - common->cur_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - common->next_frm = common->cur_frm; - - /* Remove buffer from the buffer queue */ - list_del(&common->cur_frm->queue); - /* Mark state of the current frame to active */ - common->cur_frm->state = VIDEOBUF_ACTIVE; - /* Initialize field_id and started member */ - ch->field_id = 0; - common->started = 1; - - if (V4L2_MEMORY_USERPTR == common->memory) - addr = common->cur_frm->boff; - else - addr = videobuf_to_dma_contig(common->cur_frm); - - /* Calculate the offset for Y and C data in the buffer */ - vpif_calculate_offsets(ch); - - if ((vpif->std_info.frm_fmt && - ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && - (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || - (!vpif->std_info.frm_fmt && - (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { - vpif_dbg(1, debug, "conflict in field format and std format\n"); - ret = -EINVAL; - goto exit; - } - - /* configure 1 or 2 channel mode */ - ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set vpif channel mode\n"); - goto exit; - } - - /* Call vpif_set_params function to set the parameters and addresses */ - ret = vpif_set_video_params(vpif, ch->channel_id); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set video params\n"); - goto exit; - } - - common->started = ret; - vpif_config_addr(ch, ret); - - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); - - /** - * Set interrupt for both the fields in VPIF Register enable channel in - * VPIF register - */ - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { - channel0_intr_assert(); - channel0_intr_enable(1); - enable_channel0(1); - } - if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || - (common->started == 2)) { - channel1_intr_assert(); - channel1_intr_enable(1); - enable_channel1(1); - } - channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; - return ret; - -exit: - videobuf_streamoff(&common->buffer_queue); - return ret; -} - -/** - * vpif_streamoff() - streamoff handler - * @file: file ptr - * @priv: file handle - * @buftype: v4l2 buffer type - */ -static int vpif_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret; - - vpif_dbg(2, debug, "vpif_streamoff\n"); - - if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - vpif_dbg(1, debug, "buffer type not supported\n"); - return -EINVAL; - } - - /* If io is allowed for this file handle, return error */ - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_dbg(1, debug, "io not allowed\n"); - return -EACCES; - } - - /* If streaming is not started, return error */ - if (!common->started) { - vpif_dbg(1, debug, "channel->started\n"); - return -EINVAL; - } - - /* disable channel */ - if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { - enable_channel0(0); - channel0_intr_enable(0); - } else { - enable_channel1(0); - channel1_intr_enable(0); - } - - common->started = 0; - - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 0); - - if (ret && (ret != -ENOIOCTLCMD)) - vpif_dbg(1, debug, "stream off failed in subdev\n"); - - return videobuf_streamoff(&common->buffer_queue); -} - -/** - * vpif_map_sub_device_to_input() - Maps sub device to input - * @ch - ptr to channel - * @config - ptr to capture configuration - * @input_index - Given input index from application - * @sub_device_index - index into sd table - * - * lookup the sub device information for a given input index. - * we report all the inputs to application. inputs table also - * has sub device name for the each input - */ -static struct vpif_subdev_info *vpif_map_sub_device_to_input( - struct channel_obj *ch, - struct vpif_capture_config *vpif_cfg, - int input_index, - int *sub_device_index) -{ - struct vpif_capture_chan_config *chan_cfg; - struct vpif_subdev_info *subdev_info = NULL; - const char *subdev_name = NULL; - int i; - - vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); - - chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; - - /** - * search through the inputs to find the sub device supporting - * the input - */ - for (i = 0; i < chan_cfg->input_count; i++) { - /* For each sub device, loop through input */ - if (i == input_index) { - subdev_name = chan_cfg->inputs[i].subdev_name; - break; - } - } - - /* if reached maximum. return null */ - if (i == chan_cfg->input_count || (NULL == subdev_name)) - return subdev_info; - - /* loop through the sub device list to get the sub device info */ - for (i = 0; i < vpif_cfg->subdev_count; i++) { - subdev_info = &vpif_cfg->subdev_info[i]; - if (!strcmp(subdev_info->name, subdev_name)) - break; - } - - if (i == vpif_cfg->subdev_count) - return subdev_info; - - /* check if the sub device is registered */ - if (NULL == vpif_obj.sd[i]) - return NULL; - - *sub_device_index = i; - return subdev_info; -} - -/** - * vpif_querystd() - querystd handler - * @file: file ptr - * @priv: file handle - * @std_id: ptr to std id - * - * This function is called to detect standard at the selected input - */ -static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - int ret = 0; - - vpif_dbg(2, debug, "vpif_querystd\n"); - - /* Call querystd function of decoder device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - querystd, std_id); - if (ret < 0) - vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); - - return ret; -} - -/** - * vpif_g_std() - get STD handler - * @file: file ptr - * @priv: file handle - * @std_id: ptr to std id - */ -static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - vpif_dbg(2, debug, "vpif_g_std\n"); - - *std = ch->video.stdid; - return 0; -} - -/** - * vpif_s_std() - set STD handler - * @file: file ptr - * @priv: file handle - * @std_id: ptr to std id - */ -static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - vpif_dbg(2, debug, "vpif_s_std\n"); - - if (common->started) { - vpif_err("streaming in progress\n"); - return -EBUSY; - } - - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || - (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - } - - ret = v4l2_prio_check(&ch->prio, fh->prio); - if (0 != ret) - return ret; - - fh->initialized = 1; - - /* Call encoder subdevice function to set the standard */ - ch->video.stdid = *std_id; - ch->video.dv_preset = V4L2_DV_INVALID; - memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); - - /* Get the information about the standard */ - if (vpif_update_std_info(ch)) { - vpif_err("Error getting the standard info\n"); - return -EINVAL; - } - - /* Configure the default format information */ - vpif_config_format(ch); - - /* set standard in the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - s_std, *std_id); - if (ret < 0) - vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); - return ret; -} - -/** - * vpif_enum_input() - ENUMINPUT handler - * @file: file ptr - * @priv: file handle - * @input: ptr to input structure - */ -static int vpif_enum_input(struct file *file, void *priv, - struct v4l2_input *input) -{ - - struct vpif_capture_config *config = vpif_dev->platform_data; - struct vpif_capture_chan_config *chan_cfg; - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - chan_cfg = &config->chan_config[ch->channel_id]; - - if (input->index >= chan_cfg->input_count) { - vpif_dbg(1, debug, "Invalid input index\n"); - return -EINVAL; - } - - memcpy(input, &chan_cfg->inputs[input->index].input, - sizeof(*input)); - return 0; -} - -/** - * vpif_g_input() - Get INPUT handler - * @file: file ptr - * @priv: file handle - * @index: ptr to input index - */ -static int vpif_g_input(struct file *file, void *priv, unsigned int *index) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - *index = vid_ch->input_idx; - - return 0; -} - -/** - * vpif_s_input() - Set INPUT handler - * @file: file ptr - * @priv: file handle - * @index: input index - */ -static int vpif_s_input(struct file *file, void *priv, unsigned int index) -{ - struct vpif_capture_config *config = vpif_dev->platform_data; - struct vpif_capture_chan_config *chan_cfg; - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct video_obj *vid_ch = &ch->video; - struct vpif_subdev_info *subdev_info; - int ret = 0, sd_index = 0; - u32 input = 0, output = 0; - - chan_cfg = &config->chan_config[ch->channel_id]; - - if (common->started) { - vpif_err("Streaming in progress\n"); - return -EBUSY; - } - - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || - (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - } - - ret = v4l2_prio_check(&ch->prio, fh->prio); - if (0 != ret) - return ret; - - fh->initialized = 1; - subdev_info = vpif_map_sub_device_to_input(ch, config, index, - &sd_index); - if (NULL == subdev_info) { - vpif_dbg(1, debug, - "couldn't lookup sub device for the input index\n"); - return -EINVAL; - } - - /* first setup input path from sub device to vpif */ - if (config->setup_input_path) { - ret = config->setup_input_path(ch->channel_id, - subdev_info->name); - if (ret < 0) { - vpif_dbg(1, debug, "couldn't setup input path for the" - " sub device %s, for input index %d\n", - subdev_info->name, index); - return ret; - } - } - - if (subdev_info->can_route) { - input = subdev_info->input; - output = subdev_info->output; - ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, - input, output, 0); - if (ret < 0) { - vpif_dbg(1, debug, "Failed to set input\n"); - return ret; - } - } - vid_ch->input_idx = index; - ch->curr_subdev_info = subdev_info; - ch->curr_sd_index = sd_index; - /* copy interface parameters to vpif */ - ch->vpifparams.iface = subdev_info->vpif_if; - - /* update tvnorms from the sub device input info */ - ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; - return ret; -} - -/** - * vpif_enum_fmt_vid_cap() - ENUM_FMT handler - * @file: file ptr - * @priv: file handle - * @index: input index - */ -static int vpif_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - if (fmt->index != 0) { - vpif_dbg(1, debug, "Invalid format index\n"); - return -EINVAL; - } - - /* Fill in the information about format */ - if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) { - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb"); - fmt->pixelformat = V4L2_PIX_FMT_SBGGR8; - } else { - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); - fmt->pixelformat = V4L2_PIX_FMT_YUV422P; - } - return 0; -} - -/** - * vpif_try_fmt_vid_cap() - TRY_FMT handler - * @file: file ptr - * @priv: file handle - * @fmt: ptr to v4l2 format structure - */ -static int vpif_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - return vpif_check_format(ch, pixfmt, 1); -} - - -/** - * vpif_g_fmt_vid_cap() - Set INPUT handler - * @file: file ptr - * @priv: file handle - * @fmt: ptr to v4l2 format structure - */ -static int vpif_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - /* Check the validity of the buffer type */ - if (common->fmt.type != fmt->type) - return -EINVAL; - - /* Fill in the information about format */ - *fmt = common->fmt; - return 0; -} - -/** - * vpif_s_fmt_vid_cap() - Set FMT handler - * @file: file ptr - * @priv: file handle - * @fmt: ptr to v4l2 format structure - */ -static int vpif_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct v4l2_pix_format *pixfmt; - int ret = 0; - - vpif_dbg(2, debug, "%s\n", __func__); - - /* If streaming is started, return error */ - if (common->started) { - vpif_dbg(1, debug, "Streaming is started\n"); - return -EBUSY; - } - - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || - (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - } - - ret = v4l2_prio_check(&ch->prio, fh->prio); - if (0 != ret) - return ret; - - fh->initialized = 1; - - pixfmt = &fmt->fmt.pix; - /* Check for valid field format */ - ret = vpif_check_format(ch, pixfmt, 0); - - if (ret) - return ret; - /* store the format in the channel object */ - common->fmt = *fmt; - return 0; -} - -/** - * vpif_querycap() - QUERYCAP handler - * @file: file ptr - * @priv: file handle - * @cap: ptr to v4l2_capability structure - */ -static int vpif_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpif_capture_config *config = vpif_dev->platform_data; - - cap->version = VPIF_CAPTURE_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); - strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); - strlcpy(cap->card, config->card_name, sizeof(cap->card)); - - return 0; -} - -/** - * vpif_g_priority() - get priority handler - * @file: file ptr - * @priv: file handle - * @prio: ptr to v4l2_priority structure - */ -static int vpif_g_priority(struct file *file, void *priv, - enum v4l2_priority *prio) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - *prio = v4l2_prio_max(&ch->prio); - - return 0; -} - -/** - * vpif_s_priority() - set priority handler - * @file: file ptr - * @priv: file handle - * @prio: ptr to v4l2_priority structure - */ -static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - return v4l2_prio_change(&ch->prio, &fh->prio, p); -} - -/** - * vpif_cropcap() - cropcap handler - * @file: file ptr - * @priv: file handle - * @crop: ptr to v4l2_cropcap structure - */ -static int vpif_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *crop) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type) - return -EINVAL; - - crop->bounds.left = 0; - crop->bounds.top = 0; - crop->bounds.height = common->height; - crop->bounds.width = common->width; - crop->defrect = crop->bounds; - return 0; -} - -/** - * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler - * @file: file ptr - * @priv: file handle - * @preset: input preset - */ -static int vpif_enum_dv_presets(struct file *file, void *priv, - struct v4l2_dv_enum_preset *preset) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, enum_dv_presets, preset); -} - -/** - * vpif_query_dv_presets() - QUERY_DV_PRESET handler - * @file: file ptr - * @priv: file handle - * @preset: input preset - */ -static int vpif_query_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *preset) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, query_dv_preset, preset); -} -/** - * vpif_s_dv_presets() - S_DV_PRESETS handler - * @file: file ptr - * @priv: file handle - * @preset: input preset - */ -static int vpif_s_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *preset) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - if (common->started) { - vpif_dbg(1, debug, "streaming in progress\n"); - return -EBUSY; - } - - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || - (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - } - - ret = v4l2_prio_check(&ch->prio, fh->prio); - if (ret) - return ret; - - fh->initialized = 1; - - /* Call encoder subdevice function to set the standard */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - ch->video.dv_preset = preset->preset; - ch->video.stdid = V4L2_STD_UNKNOWN; - memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); - - /* Get the information about the standard */ - if (vpif_update_std_info(ch)) { - vpif_dbg(1, debug, "Error getting the standard info\n"); - ret = -EINVAL; - } else { - /* Configure the default format information */ - vpif_config_format(ch); - - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, s_dv_preset, preset); - } - - mutex_unlock(&common->lock); - - return ret; -} -/** - * vpif_g_dv_presets() - G_DV_PRESETS handler - * @file: file ptr - * @priv: file handle - * @preset: input preset - */ -static int vpif_g_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *preset) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - preset->preset = ch->video.dv_preset; - - return 0; -} - -/** - * vpif_s_dv_timings() - S_DV_TIMINGS handler - * @file: file ptr - * @priv: file handle - * @timings: digital video timings - */ -static int vpif_s_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct vpif_params *vpifparams = &ch->vpifparams; - struct vpif_channel_config_params *std_info = &vpifparams->std_info; - struct video_obj *vid_ch = &ch->video; - struct v4l2_bt_timings *bt = &vid_ch->bt_timings; - int ret; - - if (timings->type != V4L2_DV_BT_656_1120) { - vpif_dbg(2, debug, "Timing type not defined\n"); - return -EINVAL; - } - - /* Configure subdevice timings, if any */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, s_dv_timings, timings); - if (ret == -ENOIOCTLCMD) { - vpif_dbg(2, debug, "Custom DV timings not supported by " - "subdevice\n"); - return -EINVAL; - } - if (ret < 0) { - vpif_dbg(2, debug, "Error setting custom DV timings\n"); - return ret; - } - - if (!(timings->bt.width && timings->bt.height && - (timings->bt.hbackporch || - timings->bt.hfrontporch || - timings->bt.hsync) && - timings->bt.vfrontporch && - (timings->bt.vbackporch || - timings->bt.vsync))) { - vpif_dbg(2, debug, "Timings for width, height, " - "horizontal back porch, horizontal sync, " - "horizontal front porch, vertical back porch, " - "vertical sync and vertical back porch " - "must be defined\n"); - return -EINVAL; - } - - *bt = timings->bt; - - /* Configure video port timings */ - - std_info->eav2sav = bt->hbackporch + bt->hfrontporch + - bt->hsync - 8; - std_info->sav2eav = bt->width; - - std_info->l1 = 1; - std_info->l3 = bt->vsync + bt->vbackporch + 1; - - if (bt->interlaced) { - if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) { - std_info->vsize = bt->height * 2 + - bt->vfrontporch + bt->vsync + bt->vbackporch + - bt->il_vfrontporch + bt->il_vsync + - bt->il_vbackporch; - std_info->l5 = std_info->vsize/2 - - (bt->vfrontporch - 1); - std_info->l7 = std_info->vsize/2 + 1; - std_info->l9 = std_info->l7 + bt->il_vsync + - bt->il_vbackporch + 1; - std_info->l11 = std_info->vsize - - (bt->il_vfrontporch - 1); - } else { - vpif_dbg(2, debug, "Required timing values for " - "interlaced BT format missing\n"); - return -EINVAL; - } - } else { - std_info->vsize = bt->height + bt->vfrontporch + - bt->vsync + bt->vbackporch; - std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); - } - strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME); - std_info->width = bt->width; - std_info->height = bt->height; - std_info->frm_fmt = bt->interlaced ? 0 : 1; - std_info->ycmux_mode = 0; - std_info->capture_format = 0; - std_info->vbi_supported = 0; - std_info->hd_sd = 1; - std_info->stdid = 0; - std_info->dv_preset = V4L2_DV_INVALID; - - vid_ch->stdid = 0; - vid_ch->dv_preset = V4L2_DV_INVALID; - return 0; -} - -/** - * vpif_g_dv_timings() - G_DV_TIMINGS handler - * @file: file ptr - * @priv: file handle - * @timings: digital video timings - */ -static int vpif_g_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - struct v4l2_bt_timings *bt = &vid_ch->bt_timings; - - timings->bt = *bt; - - return 0; -} - -/* - * vpif_g_chip_ident() - Identify the chip - * @file: file ptr - * @priv: file handle - * @chip: chip identity - * - * Returns zero or -EINVAL if read operations fails. - */ -static int vpif_g_chip_ident(struct file *file, void *priv, - struct v4l2_dbg_chip_ident *chip) -{ - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && - chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) { - vpif_dbg(2, debug, "match_type is invalid.\n"); - return -EINVAL; - } - - return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core, - g_chip_ident, chip); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -/* - * vpif_dbg_g_register() - Read register - * @file: file ptr - * @priv: file handle - * @reg: register to be read - * - * Debugging only - * Returns zero or -EINVAL if read operations fails. - */ -static int vpif_dbg_g_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg){ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - g_register, reg); -} - -/* - * vpif_dbg_s_register() - Write to register - * @file: file ptr - * @priv: file handle - * @reg: register to be modified - * - * Debugging only - * Returns zero or -EINVAL if write operations fails. - */ -static int vpif_dbg_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg){ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - s_register, reg); -} -#endif - -/* - * vpif_log_status() - Status information - * @file: file ptr - * @priv: file handle - * - * Returns zero. - */ -static int vpif_log_status(struct file *filep, void *priv) -{ - /* status for sub devices */ - v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status); - - return 0; -} - -/* vpif capture ioctl operations */ -static const struct v4l2_ioctl_ops vpif_ioctl_ops = { - .vidioc_querycap = vpif_querycap, - .vidioc_g_priority = vpif_g_priority, - .vidioc_s_priority = vpif_s_priority, - .vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap, - .vidioc_enum_input = vpif_enum_input, - .vidioc_s_input = vpif_s_input, - .vidioc_g_input = vpif_g_input, - .vidioc_reqbufs = vpif_reqbufs, - .vidioc_querybuf = vpif_querybuf, - .vidioc_querystd = vpif_querystd, - .vidioc_s_std = vpif_s_std, - .vidioc_g_std = vpif_g_std, - .vidioc_qbuf = vpif_qbuf, - .vidioc_dqbuf = vpif_dqbuf, - .vidioc_streamon = vpif_streamon, - .vidioc_streamoff = vpif_streamoff, - .vidioc_cropcap = vpif_cropcap, - .vidioc_enum_dv_presets = vpif_enum_dv_presets, - .vidioc_s_dv_preset = vpif_s_dv_preset, - .vidioc_g_dv_preset = vpif_g_dv_preset, - .vidioc_query_dv_preset = vpif_query_dv_preset, - .vidioc_s_dv_timings = vpif_s_dv_timings, - .vidioc_g_dv_timings = vpif_g_dv_timings, - .vidioc_g_chip_ident = vpif_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vpif_dbg_g_register, - .vidioc_s_register = vpif_dbg_s_register, -#endif - .vidioc_log_status = vpif_log_status, -}; - -/* vpif file operations */ -static struct v4l2_file_operations vpif_fops = { - .owner = THIS_MODULE, - .open = vpif_open, - .release = vpif_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vpif_mmap, - .poll = vpif_poll -}; - -/* vpif video template */ -static struct video_device vpif_video_template = { - .name = "vpif", - .fops = &vpif_fops, - .minor = -1, - .ioctl_ops = &vpif_ioctl_ops, -}; - -/** - * initialize_vpif() - Initialize vpif data structures - * - * Allocate memory for data structures and initialize them - */ -static int initialize_vpif(void) -{ - int err = 0, i, j; - int free_channel_objects_index; - - /* Default number of buffers should be 3 */ - if ((ch0_numbuffers > 0) && - (ch0_numbuffers < config_params.min_numbuffers)) - ch0_numbuffers = config_params.min_numbuffers; - if ((ch1_numbuffers > 0) && - (ch1_numbuffers < config_params.min_numbuffers)) - ch1_numbuffers = config_params.min_numbuffers; - - /* Set buffer size to min buffers size if it is invalid */ - if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]) - ch0_bufsize = - config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]; - if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]) - ch1_bufsize = - config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]; - - config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers; - config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers; - if (ch0_numbuffers) { - config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO] - = ch0_bufsize; - } - if (ch1_numbuffers) { - config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO] - = ch1_bufsize; - } - - /* Allocate memory for six channel objects */ - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { - vpif_obj.dev[i] = - kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL); - /* If memory allocation fails, return error */ - if (!vpif_obj.dev[i]) { - free_channel_objects_index = i; - err = -ENOMEM; - goto vpif_init_free_channel_objects; - } - } - return 0; - -vpif_init_free_channel_objects: - for (j = 0; j < free_channel_objects_index; j++) - kfree(vpif_obj.dev[j]); - return err; -} - -/** - * vpif_probe : This function probes the vpif capture driver - * @pdev: platform device pointer - * - * This creates device entries by register itself to the V4L2 driver and - * initializes fields of each channel objects - */ -static __init int vpif_probe(struct platform_device *pdev) -{ - struct vpif_subdev_info *subdevdata; - struct vpif_capture_config *config; - int i, j, k, m, q, err; - struct i2c_adapter *i2c_adap; - struct channel_obj *ch; - struct common_obj *common; - struct video_device *vfd; - struct resource *res; - int subdev_count; - - vpif_dev = &pdev->dev; - - err = initialize_vpif(); - if (err) { - v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); - return err; - } - - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { - for (i = res->start; i <= res->end; i++) { - if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, - "DM646x_Capture", - (void *)(&vpif_obj.dev[k]->channel_id))) { - err = -EBUSY; - i--; - goto vpif_int_err; - } - } - k++; - } - - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (NULL == vfd) { - for (j = 0; j < i; j++) { - ch = vpif_obj.dev[j]; - video_device_release(ch->video_dev); - } - err = -ENOMEM; - goto vpif_dev_alloc_err; - } - - /* Initialize field of video device */ - *vfd = vpif_video_template; - vfd->v4l2_dev = &vpif_obj.v4l2_dev; - vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFCapture_DRIVER_V%d.%d.%d", - (VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff, - (VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff, - (VPIF_CAPTURE_VERSION_CODE) & 0xff); - /* Set video_dev to the video device */ - ch->video_dev = vfd; - } - - for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { - ch = vpif_obj.dev[j]; - ch->channel_id = j; - common = &(ch->common[VPIF_VIDEO_INDEX]); - spin_lock_init(&common->irqlock); - mutex_init(&common->lock); - ch->video_dev->lock = &common->lock; - /* Initialize prio member of channel object */ - v4l2_prio_init(&ch->prio); - err = video_register_device(ch->video_dev, - VFL_TYPE_GRABBER, (j ? 1 : 0)); - if (err) - goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - - } - - i2c_adap = i2c_get_adapter(1); - config = pdev->dev.platform_data; - - subdev_count = config->subdev_count; - vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, - GFP_KERNEL); - if (vpif_obj.sd == NULL) { - vpif_err("unable to allocate memory for subdevice pointers\n"); - err = -ENOMEM; - goto probe_out; - } - - err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); - if (err) { - v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); - goto probe_subdev_out; - } - - for (i = 0; i < subdev_count; i++) { - subdevdata = &config->subdev_info[i]; - vpif_obj.sd[i] = - v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, - i2c_adap, - &subdevdata->board_info, - NULL); - - if (!vpif_obj.sd[i]) { - vpif_err("Error registering v4l2 subdevice\n"); - goto probe_subdev_out; - } - v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n", - subdevdata->name); - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; - } - - v4l2_info(&vpif_obj.v4l2_dev, - "DM646x VPIF capture driver initialized\n"); - return 0; - -probe_subdev_out: - /* free sub devices memory */ - kfree(vpif_obj.sd); - - j = VPIF_CAPTURE_MAX_DEVICES; -probe_out: - v4l2_device_unregister(&vpif_obj.v4l2_dev); - for (k = 0; k < j; k++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[k]; - /* Unregister video device */ - video_unregister_device(ch->video_dev); - } - -vpif_dev_alloc_err: - k = VPIF_CAPTURE_MAX_DEVICES-1; - res = platform_get_resource(pdev, IORESOURCE_IRQ, k); - i = res->end; - -vpif_int_err: - for (q = k; q >= 0; q--) { - for (m = i; m >= (int)res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); - if (res) - i = res->end; - } - return err; -} - -/** - * vpif_remove() - driver remove handler - * @device: ptr to platform device structure - * - * The vidoe device is unregistered - */ -static int vpif_remove(struct platform_device *device) -{ - int i; - struct channel_obj *ch; - - v4l2_device_unregister(&vpif_obj.v4l2_dev); - - /* un-register device */ - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - /* Unregister video device */ - video_unregister_device(ch->video_dev); - } - return 0; -} - -/** - * vpif_suspend: vpif device suspend - * - * TODO: Add suspend code here - */ -static int -vpif_suspend(struct device *dev) -{ - return -1; -} - -/** - * vpif_resume: vpif device suspend - * - * TODO: Add resume code here - */ -static int -vpif_resume(struct device *dev) -{ - return -1; -} - -static const struct dev_pm_ops vpif_dev_pm_ops = { - .suspend = vpif_suspend, - .resume = vpif_resume, -}; - -static __refdata struct platform_driver vpif_driver = { - .driver = { - .name = "vpif_capture", - .owner = THIS_MODULE, - .pm = &vpif_dev_pm_ops, - }, - .probe = vpif_probe, - .remove = vpif_remove, -}; - -/** - * vpif_init: initialize the vpif driver - * - * This function registers device and driver to the kernel, requests irq - * handler and allocates memory - * for channel objects - */ -static __init int vpif_init(void) -{ - return platform_driver_register(&vpif_driver); -} - -/** - * vpif_cleanup : This function clean up the vpif capture resources - * - * This will un-registers device and driver to the kernel, frees - * requested irq handler and de-allocates memory allocated for channel - * objects. - */ -static void vpif_cleanup(void) -{ - struct platform_device *pdev; - struct resource *res; - int irq_num; - int i = 0; - - pdev = container_of(vpif_dev, struct platform_device, dev); - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { - for (irq_num = res->start; irq_num <= res->end; irq_num++) - free_irq(irq_num, - (void *)(&vpif_obj.dev[i]->channel_id)); - i++; - } - - platform_driver_unregister(&vpif_driver); - - kfree(vpif_obj.sd); - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) - kfree(vpif_obj.dev[i]); -} - -/* Function for module initialization and cleanup */ -module_init(vpif_init); -module_exit(vpif_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_capture.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_capture.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_capture.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_capture.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#ifndef VPIF_CAPTURE_H -#define VPIF_CAPTURE_H - -#ifdef __KERNEL__ - -/* Header files */ -#include -#include -#include -#include -#include -#include -#include - -#include "vpif.h" - -/* Macros */ -#define VPIF_MAJOR_RELEASE 0 -#define VPIF_MINOR_RELEASE 0 -#define VPIF_BUILD 1 -#define VPIF_CAPTURE_VERSION_CODE ((VPIF_MAJOR_RELEASE << 16) | \ - (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) - -#define VPIF_VALID_FIELD(field) (((V4L2_FIELD_ANY == field) || \ - (V4L2_FIELD_NONE == field)) || \ - (((V4L2_FIELD_INTERLACED == field) || \ - (V4L2_FIELD_SEQ_TB == field)) || \ - (V4L2_FIELD_SEQ_BT == field))) - -#define VPIF_CAPTURE_MAX_DEVICES 2 -#define VPIF_VIDEO_INDEX 0 -#define VPIF_NUMBER_OF_OBJECTS 1 - -/* Enumerated data type to give id to each device per channel */ -enum vpif_channel_id { - VPIF_CHANNEL0_VIDEO = 0, - VPIF_CHANNEL1_VIDEO, -}; - -struct video_obj { - enum v4l2_field buf_field; - /* Currently selected or default standard */ - v4l2_std_id stdid; - u32 dv_preset; - struct v4l2_bt_timings bt_timings; - /* This is to track the last input that is passed to application */ - u32 input_idx; -}; - -struct common_obj { - /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *cur_frm; - /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *next_frm; - /* - * This field keeps track of type of buffer exchange mechanism - * user has selected - */ - enum v4l2_memory memory; - /* Used to store pixel format */ - struct v4l2_format fmt; - /* Buffer queue used in video-buf */ - struct videobuf_queue buffer_queue; - /* Queue of filled frames */ - struct list_head dma_queue; - /* Used in video-buf */ - spinlock_t irqlock; - /* lock used to access this structure */ - struct mutex lock; - /* number of users performing IO */ - u32 io_usrs; - /* Indicates whether streaming started */ - u8 started; - /* Function pointer to set the addresses */ - void (*set_addr) (unsigned long, unsigned long, unsigned long, - unsigned long); - /* offset where Y top starts from the starting of the buffer */ - u32 ytop_off; - /* offset where Y bottom starts from the starting of the buffer */ - u32 ybtm_off; - /* offset where C top starts from the starting of the buffer */ - u32 ctop_off; - /* offset where C bottom starts from the starting of the buffer */ - u32 cbtm_off; - /* Indicates width of the image data */ - u32 width; - /* Indicates height of the image data */ - u32 height; -}; - -struct channel_obj { - /* Identifies video device for this channel */ - struct video_device *video_dev; - /* Used to keep track of state of the priority */ - struct v4l2_prio_state prio; - /* number of open instances of the channel */ - int usrs; - /* Indicates id of the field which is being displayed */ - u32 field_id; - /* flag to indicate whether decoder is initialized */ - u8 initialized; - /* Identifies channel */ - enum vpif_channel_id channel_id; - /* index into sd table */ - int curr_sd_index; - /* ptr to current sub device information */ - struct vpif_subdev_info *curr_subdev_info; - /* vpif configuration params */ - struct vpif_params vpifparams; - /* common object array */ - struct common_obj common[VPIF_NUMBER_OF_OBJECTS]; - /* video object */ - struct video_obj video; -}; - -/* File handle structure */ -struct vpif_fh { - /* pointer to channel object for opened device */ - struct channel_obj *channel; - /* Indicates whether this file handle is doing IO */ - u8 io_allowed[VPIF_NUMBER_OF_OBJECTS]; - /* Used to keep track priority of this instance */ - enum v4l2_priority prio; - /* Used to indicate channel is initialize or not */ - u8 initialized; -}; - -struct vpif_device { - struct v4l2_device v4l2_dev; - struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS]; - struct v4l2_subdev **sd; -}; - -struct vpif_config_params { - u8 min_numbuffers; - u8 numbuffers[VPIF_CAPTURE_NUM_CHANNELS]; - s8 device_type; - u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; - u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; - u8 default_device[VPIF_CAPTURE_NUM_CHANNELS]; - u8 max_device_type; -}; -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; -}; -#endif /* End of __KERNEL__ */ -#endif /* VPIF_CAPTURE_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_display.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_display.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_display.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_display.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1917 +0,0 @@ -/* - * vpif-display - VPIF display driver - * Display driver for TI DaVinci VPIF - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include - -#include "vpif_display.h" -#include "vpif.h" - -MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); -MODULE_LICENSE("GPL"); - -#define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) - -#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) -#define vpif_dbg(level, debug, fmt, arg...) \ - v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) - -static int debug = 1; -static u32 ch2_numbuffers = 3; -static u32 ch3_numbuffers = 3; -static u32 ch2_bufsize = 1920 * 1080 * 2; -static u32 ch3_bufsize = 720 * 576 * 2; - -module_param(debug, int, 0644); -module_param(ch2_numbuffers, uint, S_IRUGO); -module_param(ch3_numbuffers, uint, S_IRUGO); -module_param(ch2_bufsize, uint, S_IRUGO); -module_param(ch3_bufsize, uint, S_IRUGO); - -MODULE_PARM_DESC(debug, "Debug level 0-1"); -MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)"); -MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)"); -MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)"); -MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)"); - -static struct vpif_config_params config_params = { - .min_numbuffers = 3, - .numbuffers[0] = 3, - .numbuffers[1] = 3, - .min_bufsize[0] = 720 * 480 * 2, - .min_bufsize[1] = 720 * 480 * 2, - .channel_bufsize[0] = 1920 * 1080 * 2, - .channel_bufsize[1] = 720 * 576 * 2, -}; - -static struct vpif_device vpif_obj = { {NULL} }; -static struct device *vpif_dev; - -/* - * vpif_uservirt_to_phys: This function is used to convert user - * space virtual address to physical address. - */ -static u32 vpif_uservirt_to_phys(u32 virtp) -{ - struct mm_struct *mm = current->mm; - unsigned long physp = 0; - struct vm_area_struct *vma; - - vma = find_vma(mm, virtp); - - /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) { - physp = virt_to_phys((void *)virtp); - } else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) { - /* this will catch, kernel-allocated, mmaped-to-usermode addr */ - physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); - } else { - /* otherwise, use get_user_pages() for general userland pages */ - int res, nr_pages = 1; - struct page *pages; - down_read(¤t->mm->mmap_sem); - - res = get_user_pages(current, current->mm, - virtp, nr_pages, 1, 0, &pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (res == nr_pages) { - physp = __pa(page_address(&pages[0]) + - (virtp & ~PAGE_MASK)); - } else { - vpif_err("get_user_pages failed\n"); - return 0; - } - } - - return physp; -} - -/* - * buffer_prepare: This is the callback function called from videobuf_qbuf() - * function the buffer is prepared and user space virtual address is converted - * into physical address - */ -static int vpif_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct vpif_fh *fh = q->priv_data; - struct common_obj *common; - unsigned long addr; - - common = &fh->channel->common[VPIF_VIDEO_INDEX]; - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = common->width; - vb->height = common->height; - vb->size = vb->width * vb->height; - vb->field = field; - } - vb->state = VIDEOBUF_PREPARED; - - /* if user pointer memory mechanism is used, get the physical - * address of the buffer */ - if (V4L2_MEMORY_USERPTR == common->memory) { - if (!vb->baddr) { - vpif_err("buffer_address is 0\n"); - return -EINVAL; - } - - vb->boff = vpif_uservirt_to_phys(vb->baddr); - if (!ISALIGNED(vb->boff)) - goto buf_align_exit; - } - - addr = vb->boff; - if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) { - if (!ISALIGNED(addr + common->ytop_off) || - !ISALIGNED(addr + common->ybtm_off) || - !ISALIGNED(addr + common->ctop_off) || - !ISALIGNED(addr + common->cbtm_off)) - goto buf_align_exit; - } - return 0; - -buf_align_exit: - vpif_err("buffer offset not aligned to 8 bytes\n"); - return -EINVAL; -} - -/* - * vpif_buffer_setup: This function allocates memory for the buffers - */ -static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (V4L2_MEMORY_MMAP != common->memory) - return 0; - - *size = config_params.channel_bufsize[ch->channel_id]; - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; - - return 0; -} - -/* - * vpif_buffer_queue: This function adds the buffer to DMA queue - */ -static void vpif_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct vpif_fh *fh = q->priv_data; - struct common_obj *common; - - common = &fh->channel->common[VPIF_VIDEO_INDEX]; - - /* add the buffer to the DMA queue */ - list_add_tail(&vb->queue, &common->dma_queue); - vb->state = VIDEOBUF_QUEUED; -} - -/* - * vpif_buffer_release: This function is called from the videobuf layer to - * free memory allocated to the buffers - */ -static void vpif_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - unsigned int buf_size = 0; - - common = &ch->common[VPIF_VIDEO_INDEX]; - - videobuf_dma_contig_free(q, vb); - vb->state = VIDEOBUF_NEEDS_INIT; - - if (V4L2_MEMORY_MMAP != common->memory) - return; - - buf_size = config_params.channel_bufsize[ch->channel_id]; -} - -static struct videobuf_queue_ops video_qops = { - .buf_setup = vpif_buffer_setup, - .buf_prepare = vpif_buffer_prepare, - .buf_queue = vpif_buffer_queue, - .buf_release = vpif_buffer_release, -}; -static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} }; - -static void process_progressive_mode(struct common_obj *common) -{ - unsigned long addr = 0; - - /* Get the next buffer from buffer queue */ - common->next_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - /* Remove that buffer from the buffer queue */ - list_del(&common->next_frm->queue); - /* Mark status of the buffer as active */ - common->next_frm->state = VIDEOBUF_ACTIVE; - - /* Set top and bottom field addrs in VPIF registers */ - addr = videobuf_to_dma_contig(common->next_frm); - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); -} - -static void process_interlaced_mode(int fid, struct common_obj *common) -{ - /* device field id and local field id are in sync */ - /* If this is even field */ - if (0 == fid) { - if (common->cur_frm == common->next_frm) - return; - - /* one frame is displayed If next frame is - * available, release cur_frm and move on */ - /* Copy frame display time */ - do_gettimeofday(&common->cur_frm->ts); - /* Change status of the cur_frm */ - common->cur_frm->state = VIDEOBUF_DONE; - /* unlock semaphore on cur_frm */ - wake_up_interruptible(&common->cur_frm->done); - /* Make cur_frm pointing to next_frm */ - common->cur_frm = common->next_frm; - - } else if (1 == fid) { /* odd field */ - if (list_empty(&common->dma_queue) - || (common->cur_frm != common->next_frm)) { - return; - } - /* one field is displayed configure the next - * frame if it is available else hold on current - * frame */ - /* Get next from the buffer queue */ - process_progressive_mode(common); - - } -} - -/* - * vpif_channel_isr: It changes status of the displayed buffer, takes next - * buffer from the queue and sets its address in VPIF registers - */ -static irqreturn_t vpif_channel_isr(int irq, void *dev_id) -{ - struct vpif_device *dev = &vpif_obj; - struct channel_obj *ch; - struct common_obj *common; - enum v4l2_field field; - int fid = -1, i; - int channel_id = 0; - - channel_id = *(int *)(dev_id); - ch = dev->dev[channel_id]; - field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; - for (i = 0; i < VPIF_NUMOBJECTS; i++) { - common = &ch->common[i]; - /* If streaming is started in this channel */ - if (0 == common->started) - continue; - - if (1 == ch->vpifparams.std_info.frm_fmt) { - if (list_empty(&common->dma_queue)) - continue; - - /* Progressive mode */ - if (!channel_first_int[i][channel_id]) { - /* Mark status of the cur_frm to - * done and unlock semaphore on it */ - do_gettimeofday(&common->cur_frm->ts); - common->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&common->cur_frm->done); - /* Make cur_frm pointing to next_frm */ - common->cur_frm = common->next_frm; - } - - channel_first_int[i][channel_id] = 0; - process_progressive_mode(common); - } else { - /* Interlaced mode */ - /* If it is first interrupt, ignore it */ - - if (channel_first_int[i][channel_id]) { - channel_first_int[i][channel_id] = 0; - continue; - } - - if (0 == i) { - ch->field_id ^= 1; - /* Get field id from VPIF registers */ - fid = vpif_channel_getfid(ch->channel_id + 2); - /* If fid does not match with stored field id */ - if (fid != ch->field_id) { - /* Make them in sync */ - if (0 == fid) - ch->field_id = fid; - - return IRQ_HANDLED; - } - } - process_interlaced_mode(fid, common); - } - } - - return IRQ_HANDLED; -} - -static int vpif_update_std_info(struct channel_obj *ch) -{ - struct video_obj *vid_ch = &ch->video; - struct vpif_params *vpifparams = &ch->vpifparams; - struct vpif_channel_config_params *std_info = &vpifparams->std_info; - const struct vpif_channel_config_params *config; - - int i; - - for (i = 0; i < vpif_ch_params_count; i++) { - config = &ch_params[i]; - if (config->hd_sd == 0) { - vpif_dbg(2, debug, "SD format\n"); - if (config->stdid & vid_ch->stdid) { - memcpy(std_info, config, sizeof(*config)); - break; - } - } else { - vpif_dbg(2, debug, "HD format\n"); - if (config->dv_preset == vid_ch->dv_preset) { - memcpy(std_info, config, sizeof(*config)); - break; - } - } - } - - if (i == vpif_ch_params_count) { - vpif_dbg(1, debug, "Format not found\n"); - return -EINVAL; - } - - return 0; -} - -static int vpif_update_resolution(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct video_obj *vid_ch = &ch->video; - struct vpif_params *vpifparams = &ch->vpifparams; - struct vpif_channel_config_params *std_info = &vpifparams->std_info; - - if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height) - return -EINVAL; - - if (vid_ch->stdid || vid_ch->dv_preset) { - if (vpif_update_std_info(ch)) - return -EINVAL; - } - - common->fmt.fmt.pix.width = std_info->width; - common->fmt.fmt.pix.height = std_info->height; - vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n", - common->fmt.fmt.pix.width, common->fmt.fmt.pix.height); - - /* Set height and width paramateres */ - common->height = std_info->height; - common->width = std_info->width; - - return 0; -} - -/* - * vpif_calculate_offsets: This function calculates buffers offset for Y and C - * in the top and bottom field - */ -static void vpif_calculate_offsets(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct vpif_params *vpifparams = &ch->vpifparams; - enum v4l2_field field = common->fmt.fmt.pix.field; - struct video_obj *vid_ch = &ch->video; - unsigned int hpitch, vpitch, sizeimage; - - if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) { - if (ch->vpifparams.std_info.frm_fmt) - vid_ch->buf_field = V4L2_FIELD_NONE; - else - vid_ch->buf_field = V4L2_FIELD_INTERLACED; - } else { - vid_ch->buf_field = common->fmt.fmt.pix.field; - } - - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = common->fmt.fmt.pix.sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; - - hpitch = common->fmt.fmt.pix.bytesperline; - vpitch = sizeimage / (hpitch * 2); - if ((V4L2_FIELD_NONE == vid_ch->buf_field) || - (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { - common->ytop_off = 0; - common->ybtm_off = hpitch; - common->ctop_off = sizeimage / 2; - common->cbtm_off = sizeimage / 2 + hpitch; - } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { - common->ytop_off = 0; - common->ybtm_off = sizeimage / 4; - common->ctop_off = sizeimage / 2; - common->cbtm_off = common->ctop_off + sizeimage / 4; - } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { - common->ybtm_off = 0; - common->ytop_off = sizeimage / 4; - common->cbtm_off = sizeimage / 2; - common->ctop_off = common->cbtm_off + sizeimage / 4; - } - - if ((V4L2_FIELD_NONE == vid_ch->buf_field) || - (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { - vpifparams->video_params.storage_mode = 1; - } else { - vpifparams->video_params.storage_mode = 0; - } - - if (ch->vpifparams.std_info.frm_fmt == 1) { - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline; - } else { - if ((field == V4L2_FIELD_ANY) || - (field == V4L2_FIELD_INTERLACED)) - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline * 2; - else - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline; - } - - ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid; -} - -static void vpif_config_format(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - common->fmt.fmt.pix.field = V4L2_FIELD_ANY; - if (config_params.numbuffers[ch->channel_id] == 0) - common->memory = V4L2_MEMORY_USERPTR; - else - common->memory = V4L2_MEMORY_MMAP; - - common->fmt.fmt.pix.sizeimage = - config_params.channel_bufsize[ch->channel_id]; - common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; - common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; -} - -static int vpif_check_format(struct channel_obj *ch, - struct v4l2_pix_format *pixfmt) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - enum v4l2_field field = pixfmt->field; - u32 sizeimage, hpitch, vpitch; - - if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) - goto invalid_fmt_exit; - - if (!(VPIF_VALID_FIELD(field))) - goto invalid_fmt_exit; - - if (pixfmt->bytesperline <= 0) - goto invalid_pitch_exit; - - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = pixfmt->sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; - - if (vpif_update_resolution(ch)) - return -EINVAL; - - hpitch = pixfmt->bytesperline; - vpitch = sizeimage / (hpitch * 2); - - /* Check for valid value of pitch */ - if ((hpitch < ch->vpifparams.std_info.width) || - (vpitch < ch->vpifparams.std_info.height)) - goto invalid_pitch_exit; - - /* Check for 8 byte alignment */ - if (!ISALIGNED(hpitch)) { - vpif_err("invalid pitch alignment\n"); - return -EINVAL; - } - pixfmt->width = common->fmt.fmt.pix.width; - pixfmt->height = common->fmt.fmt.pix.height; - - return 0; - -invalid_fmt_exit: - vpif_err("invalid field format\n"); - return -EINVAL; - -invalid_pitch_exit: - vpif_err("invalid pitch\n"); - return -EINVAL; -} - -static void vpif_config_addr(struct channel_obj *ch, int muxmode) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (VPIF_CHANNEL3_VIDEO == ch->channel_id) { - common->set_addr = ch3_set_videobuf_addr; - } else { - if (2 == muxmode) - common->set_addr = ch2_set_videobuf_addr_yc_nmux; - else - common->set_addr = ch2_set_videobuf_addr; - } -} - -/* - * vpif_mmap: It is used to map kernel space buffers into user spaces - */ -static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) -{ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); - - vpif_dbg(2, debug, "vpif_mmap\n"); - - return videobuf_mmap_mapper(&common->buffer_queue, vma); -} - -/* - * vpif_poll: It is used for select/poll system call - */ -static unsigned int vpif_poll(struct file *filep, poll_table *wait) -{ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (common->started) - return videobuf_poll_stream(filep, &common->buffer_queue, wait); - - return 0; -} - -/* - * vpif_open: It creates object of file handle structure and stores it in - * private_data member of filepointer - */ -static int vpif_open(struct file *filep) -{ - struct video_device *vdev = video_devdata(filep); - struct channel_obj *ch = NULL; - struct vpif_fh *fh = NULL; - - ch = video_get_drvdata(vdev); - /* Allocate memory for the file handle object */ - fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); - if (fh == NULL) { - vpif_err("unable to allocate memory for file handle object\n"); - return -ENOMEM; - } - - /* store pointer to fh in private_data member of filep */ - filep->private_data = fh; - fh->channel = ch; - fh->initialized = 0; - if (!ch->initialized) { - fh->initialized = 1; - ch->initialized = 1; - memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); - } - - /* Increment channel usrs counter */ - atomic_inc(&ch->usrs); - /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */ - fh->io_allowed[VPIF_VIDEO_INDEX] = 0; - /* Initialize priority of this instance to default priority */ - fh->prio = V4L2_PRIORITY_UNSET; - v4l2_prio_open(&ch->prio, &fh->prio); - - return 0; -} - -/* - * vpif_release: This function deletes buffer queue, frees the buffers and - * the vpif file handle - */ -static int vpif_release(struct file *filep) -{ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - /* if this instance is doing IO */ - if (fh->io_allowed[VPIF_VIDEO_INDEX]) { - /* Reset io_usrs member of channel object */ - common->io_usrs = 0; - /* Disable channel */ - if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - enable_channel2(0); - channel2_intr_enable(0); - } - if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || - (2 == common->started)) { - enable_channel3(0); - channel3_intr_enable(0); - } - common->started = 0; - /* Free buffers allocated */ - videobuf_queue_cancel(&common->buffer_queue); - videobuf_mmap_free(&common->buffer_queue); - common->numbuffers = - config_params.numbuffers[ch->channel_id]; - } - - /* Decrement channel usrs counter */ - atomic_dec(&ch->usrs); - /* If this file handle has initialize encoder device, reset it */ - if (fh->initialized) - ch->initialized = 0; - - /* Close the priority */ - v4l2_prio_close(&ch->prio, fh->prio); - filep->private_data = NULL; - fh->initialized = 0; - kfree(fh); - - return 0; -} - -/* functions implementing ioctls */ -/** - * vpif_querycap() - QUERYCAP handler - * @file: file ptr - * @priv: file handle - * @cap: ptr to v4l2_capability structure - */ -static int vpif_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpif_display_config *config = vpif_dev->platform_data; - - cap->version = VPIF_DISPLAY_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); - strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); - strlcpy(cap->card, config->card_name, sizeof(cap->card)); - - return 0; -} - -static int vpif_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - if (fmt->index != 0) { - vpif_err("Invalid format index\n"); - return -EINVAL; - } - - /* Fill in the information about format */ - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); - fmt->pixelformat = V4L2_PIX_FMT_YUV422P; - - return 0; -} - -static int vpif_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - /* Check the validity of the buffer type */ - if (common->fmt.type != fmt->type) - return -EINVAL; - - if (vpif_update_resolution(ch)) - return -EINVAL; - *fmt = common->fmt; - return 0; -} - -static int vpif_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct v4l2_pix_format *pixfmt; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) - || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - - /* Check for the priority */ - ret = v4l2_prio_check(&ch->prio, fh->prio); - if (0 != ret) - return ret; - fh->initialized = 1; - } - - if (common->started) { - vpif_dbg(1, debug, "Streaming in progress\n"); - return -EBUSY; - } - - pixfmt = &fmt->fmt.pix; - /* Check for valid field format */ - ret = vpif_check_format(ch, pixfmt); - if (ret) - return ret; - - /* store the pix format in the channel object */ - common->fmt.fmt.pix = *pixfmt; - /* store the format in the channel object */ - common->fmt = *fmt; - return 0; -} - -static int vpif_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - int ret = 0; - - ret = vpif_check_format(ch, pixfmt); - if (ret) { - *pixfmt = common->fmt.fmt.pix; - pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2; - } - - return ret; -} - -static int vpif_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbuf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - enum v4l2_field field; - u8 index = 0; - - /* This file handle has not initialized the channel, - It is not allowed to do settings */ - if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) - || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_err("Channel Busy\n"); - return -EBUSY; - } - } - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type) - return -EINVAL; - - index = VPIF_VIDEO_INDEX; - - common = &ch->common[index]; - - if (common->fmt.type != reqbuf->type) - return -EINVAL; - - if (0 != common->io_usrs) - return -EBUSY; - - if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY) - field = V4L2_FIELD_INTERLACED; - else - field = common->fmt.fmt.pix.field; - } else { - field = V4L2_VBI_INTERLACED; - } - - /* Initialize videobuf queue as per the buffer type */ - videobuf_queue_dma_contig_init(&common->buffer_queue, - &video_qops, NULL, - &common->irqlock, - reqbuf->type, field, - sizeof(struct videobuf_buffer), fh, - &common->lock); - - /* Set io allowed member of file handle to TRUE */ - fh->io_allowed[index] = 1; - /* Increment io usrs member of channel object to 1 */ - common->io_usrs = 1; - /* Store type of memory requested in channel object */ - common->memory = reqbuf->memory; - INIT_LIST_HEAD(&common->dma_queue); - - /* Allocate buffers */ - return videobuf_reqbufs(&common->buffer_queue, reqbuf); -} - -static int vpif_querybuf(struct file *file, void *priv, - struct v4l2_buffer *tbuf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (common->fmt.type != tbuf->type) - return -EINVAL; - - return videobuf_querybuf(&common->buffer_queue, tbuf); -} - -static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct v4l2_buffer tbuf = *buf; - struct videobuf_buffer *buf1; - unsigned long addr = 0; - unsigned long flags; - int ret = 0; - - if (common->fmt.type != tbuf.type) - return -EINVAL; - - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh->io_allowed\n"); - return -EACCES; - } - - if (!(list_empty(&common->dma_queue)) || - (common->cur_frm != common->next_frm) || - !(common->started) || - (common->started && (0 == ch->field_id))) - return videobuf_qbuf(&common->buffer_queue, buf); - - /* bufferqueue is empty store buffer address in VPIF registers */ - mutex_lock(&common->buffer_queue.vb_lock); - buf1 = common->buffer_queue.bufs[tbuf.index]; - if (buf1->memory != tbuf.memory) { - vpif_err("invalid buffer type\n"); - goto qbuf_exit; - } - - if ((buf1->state == VIDEOBUF_QUEUED) || - (buf1->state == VIDEOBUF_ACTIVE)) { - vpif_err("invalid state\n"); - goto qbuf_exit; - } - - switch (buf1->memory) { - case V4L2_MEMORY_MMAP: - if (buf1->baddr == 0) - goto qbuf_exit; - break; - - case V4L2_MEMORY_USERPTR: - if (tbuf.length < buf1->bsize) - goto qbuf_exit; - - if ((VIDEOBUF_NEEDS_INIT != buf1->state) - && (buf1->baddr != tbuf.m.userptr)) { - vpif_buffer_release(&common->buffer_queue, buf1); - buf1->baddr = tbuf.m.userptr; - } - break; - - default: - goto qbuf_exit; - } - - local_irq_save(flags); - ret = vpif_buffer_prepare(&common->buffer_queue, buf1, - common->buffer_queue.field); - if (ret < 0) { - local_irq_restore(flags); - goto qbuf_exit; - } - - buf1->state = VIDEOBUF_ACTIVE; - addr = buf1->boff; - common->next_frm = buf1; - if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { - common->set_addr((addr + common->ytop_off), - (addr + common->ybtm_off), - (addr + common->ctop_off), - (addr + common->cbtm_off)); - } - - local_irq_restore(flags); - list_add_tail(&buf1->stream, &common->buffer_queue.stream); - mutex_unlock(&common->buffer_queue.vb_lock); - return 0; - -qbuf_exit: - mutex_unlock(&common->buffer_queue.vb_lock); - return -EINVAL; -} - -static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - if (!(*std_id & DM646X_V4L2_STD)) - return -EINVAL; - - if (common->started) { - vpif_err("streaming in progress\n"); - return -EBUSY; - } - - /* Call encoder subdevice function to set the standard */ - ch->video.stdid = *std_id; - ch->video.dv_preset = V4L2_DV_INVALID; - memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); - - /* Get the information about the standard */ - if (vpif_update_resolution(ch)) - return -EINVAL; - - if ((ch->vpifparams.std_info.width * - ch->vpifparams.std_info.height * 2) > - config_params.channel_bufsize[ch->channel_id]) { - vpif_err("invalid std for this size\n"); - return -EINVAL; - } - - common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width; - /* Configure the default format information */ - vpif_config_format(ch); - - ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, - s_std_output, *std_id); - if (ret < 0) { - vpif_err("Failed to set output standard\n"); - return ret; - } - - ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core, - s_std, *std_id); - if (ret < 0) - vpif_err("Failed to set standard for sub devices\n"); - return ret; -} - -static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - *std = ch->video.stdid; - return 0; -} - -static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - return videobuf_dqbuf(&common->buffer_queue, p, - (file->f_flags & O_NONBLOCK)); -} - -static int vpif_streamon(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; - struct vpif_params *vpif = &ch->vpifparams; - struct vpif_display_config *vpif_config_data = - vpif_dev->platform_data; - unsigned long addr = 0; - int ret = 0; - - if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - vpif_err("buffer type not supported\n"); - return -EINVAL; - } - - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh->io_allowed\n"); - return -EACCES; - } - - /* If Streaming is already started, return error */ - if (common->started) { - vpif_err("channel->started\n"); - return -EBUSY; - } - - if ((ch->channel_id == VPIF_CHANNEL2_VIDEO - && oth_ch->common[VPIF_VIDEO_INDEX].started && - ch->vpifparams.std_info.ycmux_mode == 0) - || ((ch->channel_id == VPIF_CHANNEL3_VIDEO) - && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { - vpif_err("other channel is using\n"); - return -EBUSY; - } - - ret = vpif_check_format(ch, &common->fmt.fmt.pix); - if (ret < 0) - return ret; - - /* Call videobuf_streamon to start streaming in videobuf */ - ret = videobuf_streamon(&common->buffer_queue); - if (ret < 0) { - vpif_err("videobuf_streamon\n"); - return ret; - } - - /* If buffer queue is empty, return error */ - if (list_empty(&common->dma_queue)) { - vpif_err("buffer queue is empty\n"); - return -EIO; - } - - /* Get the next frame from the buffer queue */ - common->next_frm = common->cur_frm = - list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - - list_del(&common->cur_frm->queue); - /* Mark state of the current frame to active */ - common->cur_frm->state = VIDEOBUF_ACTIVE; - - /* Initialize field_id and started member */ - ch->field_id = 0; - common->started = 1; - if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - addr = common->cur_frm->boff; - /* Calculate the offset for Y and C data in the buffer */ - vpif_calculate_offsets(ch); - - if ((ch->vpifparams.std_info.frm_fmt && - ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) - && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) - || (!ch->vpifparams.std_info.frm_fmt - && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { - vpif_err("conflict in field format and std format\n"); - return -EINVAL; - } - - /* clock settings */ - ret = - vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, - ch->vpifparams.std_info.hd_sd); - if (ret < 0) { - vpif_err("can't set clock\n"); - return ret; - } - - /* set the parameters and addresses */ - ret = vpif_set_video_params(vpif, ch->channel_id + 2); - if (ret < 0) - return ret; - - common->started = ret; - vpif_config_addr(ch, ret); - common->set_addr((addr + common->ytop_off), - (addr + common->ybtm_off), - (addr + common->ctop_off), - (addr + common->cbtm_off)); - - /* Set interrupt for both the fields in VPIF - Register enable channel in VPIF register */ - if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - channel2_intr_assert(); - channel2_intr_enable(1); - enable_channel2(1); - } - - if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) - || (common->started == 2)) { - channel3_intr_assert(); - channel3_intr_enable(1); - enable_channel3(1); - } - channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; - } - return ret; -} - -static int vpif_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - vpif_err("buffer type not supported\n"); - return -EINVAL; - } - - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh->io_allowed\n"); - return -EACCES; - } - - if (!common->started) { - vpif_err("channel->started\n"); - return -EINVAL; - } - - if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - /* disable channel */ - if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - enable_channel2(0); - channel2_intr_enable(0); - } - if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || - (2 == common->started)) { - enable_channel3(0); - channel3_intr_enable(0); - } - } - - common->started = 0; - return videobuf_streamoff(&common->buffer_queue); -} - -static int vpif_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *crop) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type) - return -EINVAL; - - crop->bounds.left = crop->bounds.top = 0; - crop->defrect.left = crop->defrect.top = 0; - crop->defrect.height = crop->bounds.height = common->height; - crop->defrect.width = crop->bounds.width = common->width; - - return 0; -} - -static int vpif_enum_output(struct file *file, void *fh, - struct v4l2_output *output) -{ - - struct vpif_display_config *config = vpif_dev->platform_data; - - if (output->index >= config->output_count) { - vpif_dbg(1, debug, "Invalid output index\n"); - return -EINVAL; - } - - strcpy(output->name, config->output[output->index]); - output->type = V4L2_OUTPUT_TYPE_ANALOG; - output->std = DM646X_V4L2_STD; - - return 0; -} - -static int vpif_s_output(struct file *file, void *priv, unsigned int i) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - if (common->started) { - vpif_err("Streaming in progress\n"); - return -EBUSY; - } - - ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, - s_routing, 0, i, 0); - - if (ret < 0) - vpif_err("Failed to set output standard\n"); - - vid_ch->output_id = i; - return ret; -} - -static int vpif_g_output(struct file *file, void *priv, unsigned int *i) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - *i = vid_ch->output_id; - - return 0; -} - -static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - *p = v4l2_prio_max(&ch->prio); - - return 0; -} - -static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - return v4l2_prio_change(&ch->prio, &fh->prio, p); -} - -/** - * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler - * @file: file ptr - * @priv: file handle - * @preset: input preset - */ -static int vpif_enum_dv_presets(struct file *file, void *priv, - struct v4l2_dv_enum_preset *preset) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], - video, enum_dv_presets, preset); -} - -/** - * vpif_s_dv_presets() - S_DV_PRESETS handler - * @file: file ptr - * @priv: file handle - * @preset: input preset - */ -static int vpif_s_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *preset) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct video_obj *vid_ch = &ch->video; - int ret = 0; - - if (common->started) { - vpif_dbg(1, debug, "streaming in progress\n"); - return -EBUSY; - } - - ret = v4l2_prio_check(&ch->prio, fh->prio); - if (ret != 0) - return ret; - - fh->initialized = 1; - - /* Call encoder subdevice function to set the standard */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - ch->video.dv_preset = preset->preset; - ch->video.stdid = V4L2_STD_UNKNOWN; - memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); - - /* Get the information about the standard */ - if (vpif_update_resolution(ch)) { - ret = -EINVAL; - } else { - /* Configure the default format information */ - vpif_config_format(ch); - - ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], - video, s_dv_preset, preset); - } - - mutex_unlock(&common->lock); - - return ret; -} -/** - * vpif_g_dv_presets() - G_DV_PRESETS handler - * @file: file ptr - * @priv: file handle - * @preset: input preset - */ -static int vpif_g_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *preset) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - preset->preset = ch->video.dv_preset; - - return 0; -} -/** - * vpif_s_dv_timings() - S_DV_TIMINGS handler - * @file: file ptr - * @priv: file handle - * @timings: digital video timings - */ -static int vpif_s_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct vpif_params *vpifparams = &ch->vpifparams; - struct vpif_channel_config_params *std_info = &vpifparams->std_info; - struct video_obj *vid_ch = &ch->video; - struct v4l2_bt_timings *bt = &vid_ch->bt_timings; - int ret; - - if (timings->type != V4L2_DV_BT_656_1120) { - vpif_dbg(2, debug, "Timing type not defined\n"); - return -EINVAL; - } - - /* Configure subdevice timings, if any */ - ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], - video, s_dv_timings, timings); - if (ret == -ENOIOCTLCMD) { - vpif_dbg(2, debug, "Custom DV timings not supported by " - "subdevice\n"); - return -EINVAL; - } - if (ret < 0) { - vpif_dbg(2, debug, "Error setting custom DV timings\n"); - return ret; - } - - if (!(timings->bt.width && timings->bt.height && - (timings->bt.hbackporch || - timings->bt.hfrontporch || - timings->bt.hsync) && - timings->bt.vfrontporch && - (timings->bt.vbackporch || - timings->bt.vsync))) { - vpif_dbg(2, debug, "Timings for width, height, " - "horizontal back porch, horizontal sync, " - "horizontal front porch, vertical back porch, " - "vertical sync and vertical back porch " - "must be defined\n"); - return -EINVAL; - } - - *bt = timings->bt; - - /* Configure video port timings */ - - std_info->eav2sav = bt->hbackporch + bt->hfrontporch + - bt->hsync - 8; - std_info->sav2eav = bt->width; - - std_info->l1 = 1; - std_info->l3 = bt->vsync + bt->vbackporch + 1; - - if (bt->interlaced) { - if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) { - std_info->vsize = bt->height * 2 + - bt->vfrontporch + bt->vsync + bt->vbackporch + - bt->il_vfrontporch + bt->il_vsync + - bt->il_vbackporch; - std_info->l5 = std_info->vsize/2 - - (bt->vfrontporch - 1); - std_info->l7 = std_info->vsize/2 + 1; - std_info->l9 = std_info->l7 + bt->il_vsync + - bt->il_vbackporch + 1; - std_info->l11 = std_info->vsize - - (bt->il_vfrontporch - 1); - } else { - vpif_dbg(2, debug, "Required timing values for " - "interlaced BT format missing\n"); - return -EINVAL; - } - } else { - std_info->vsize = bt->height + bt->vfrontporch + - bt->vsync + bt->vbackporch; - std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); - } - strncpy(std_info->name, "Custom timings BT656/1120", - VPIF_MAX_NAME); - std_info->width = bt->width; - std_info->height = bt->height; - std_info->frm_fmt = bt->interlaced ? 0 : 1; - std_info->ycmux_mode = 0; - std_info->capture_format = 0; - std_info->vbi_supported = 0; - std_info->hd_sd = 1; - std_info->stdid = 0; - std_info->dv_preset = V4L2_DV_INVALID; - - vid_ch->stdid = 0; - vid_ch->dv_preset = V4L2_DV_INVALID; - - return 0; -} - -/** - * vpif_g_dv_timings() - G_DV_TIMINGS handler - * @file: file ptr - * @priv: file handle - * @timings: digital video timings - */ -static int vpif_g_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - struct v4l2_bt_timings *bt = &vid_ch->bt_timings; - - timings->bt = *bt; - - return 0; -} - -/* - * vpif_g_chip_ident() - Identify the chip - * @file: file ptr - * @priv: file handle - * @chip: chip identity - * - * Returns zero or -EINVAL if read operations fails. - */ -static int vpif_g_chip_ident(struct file *file, void *priv, - struct v4l2_dbg_chip_ident *chip) -{ - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && - chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) { - vpif_dbg(2, debug, "match_type is invalid.\n"); - return -EINVAL; - } - - return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core, - g_chip_ident, chip); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -/* - * vpif_dbg_g_register() - Read register - * @file: file ptr - * @priv: file handle - * @reg: register to be read - * - * Debugging only - * Returns zero or -EINVAL if read operations fails. - */ -static int vpif_dbg_g_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg){ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, - g_register, reg); -} - -/* - * vpif_dbg_s_register() - Write to register - * @file: file ptr - * @priv: file handle - * @reg: register to be modified - * - * Debugging only - * Returns zero or -EINVAL if write operations fails. - */ -static int vpif_dbg_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg){ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, - s_register, reg); -} -#endif - -/* - * vpif_log_status() - Status information - * @file: file ptr - * @priv: file handle - * - * Returns zero. - */ -static int vpif_log_status(struct file *filep, void *priv) -{ - /* status for sub devices */ - v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status); - - return 0; -} - -/* vpif display ioctl operations */ -static const struct v4l2_ioctl_ops vpif_ioctl_ops = { - .vidioc_querycap = vpif_querycap, - .vidioc_g_priority = vpif_g_priority, - .vidioc_s_priority = vpif_s_priority, - .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out, - .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out, - .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out, - .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out, - .vidioc_reqbufs = vpif_reqbufs, - .vidioc_querybuf = vpif_querybuf, - .vidioc_qbuf = vpif_qbuf, - .vidioc_dqbuf = vpif_dqbuf, - .vidioc_streamon = vpif_streamon, - .vidioc_streamoff = vpif_streamoff, - .vidioc_s_std = vpif_s_std, - .vidioc_g_std = vpif_g_std, - .vidioc_enum_output = vpif_enum_output, - .vidioc_s_output = vpif_s_output, - .vidioc_g_output = vpif_g_output, - .vidioc_cropcap = vpif_cropcap, - .vidioc_enum_dv_presets = vpif_enum_dv_presets, - .vidioc_s_dv_preset = vpif_s_dv_preset, - .vidioc_g_dv_preset = vpif_g_dv_preset, - .vidioc_s_dv_timings = vpif_s_dv_timings, - .vidioc_g_dv_timings = vpif_g_dv_timings, - .vidioc_g_chip_ident = vpif_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vpif_dbg_g_register, - .vidioc_s_register = vpif_dbg_s_register, -#endif - .vidioc_log_status = vpif_log_status, -}; - -static const struct v4l2_file_operations vpif_fops = { - .owner = THIS_MODULE, - .open = vpif_open, - .release = vpif_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vpif_mmap, - .poll = vpif_poll -}; - -static struct video_device vpif_video_template = { - .name = "vpif", - .fops = &vpif_fops, - .ioctl_ops = &vpif_ioctl_ops, - .tvnorms = DM646X_V4L2_STD, - .current_norm = V4L2_STD_625_50, - -}; - -/*Configure the channels, buffer sizei, request irq */ -static int initialize_vpif(void) -{ - int free_channel_objects_index; - int free_buffer_channel_index; - int free_buffer_index; - int err = 0, i, j; - - /* Default number of buffers should be 3 */ - if ((ch2_numbuffers > 0) && - (ch2_numbuffers < config_params.min_numbuffers)) - ch2_numbuffers = config_params.min_numbuffers; - if ((ch3_numbuffers > 0) && - (ch3_numbuffers < config_params.min_numbuffers)) - ch3_numbuffers = config_params.min_numbuffers; - - /* Set buffer size to min buffers size if invalid buffer size is - * given */ - if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]) - ch2_bufsize = - config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]; - if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]) - ch3_bufsize = - config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]; - - config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers; - - if (ch2_numbuffers) { - config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] = - ch2_bufsize; - } - config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers; - - if (ch3_numbuffers) { - config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] = - ch3_bufsize; - } - - /* Allocate memory for six channel objects */ - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - vpif_obj.dev[i] = - kzalloc(sizeof(struct channel_obj), GFP_KERNEL); - /* If memory allocation fails, return error */ - if (!vpif_obj.dev[i]) { - free_channel_objects_index = i; - err = -ENOMEM; - goto vpif_init_free_channel_objects; - } - } - - free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES; - free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS; - free_buffer_index = config_params.numbuffers[i - 1]; - - return 0; - -vpif_init_free_channel_objects: - for (j = 0; j < free_channel_objects_index; j++) - kfree(vpif_obj.dev[j]); - return err; -} - -/* - * vpif_probe: This function creates device entries by register itself to the - * V4L2 driver and initializes fields of each channel objects - */ -static __init int vpif_probe(struct platform_device *pdev) -{ - struct vpif_subdev_info *subdevdata; - struct vpif_display_config *config; - int i, j = 0, k, q, m, err = 0; - struct i2c_adapter *i2c_adap; - struct common_obj *common; - struct channel_obj *ch; - struct video_device *vfd; - struct resource *res; - int subdev_count; - - vpif_dev = &pdev->dev; - - err = initialize_vpif(); - - if (err) { - v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); - return err; - } - - err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); - if (err) { - v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); - return err; - } - - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { - for (i = res->start; i <= res->end; i++) { - if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, - "DM646x_Display", - (void *)(&vpif_obj.dev[k]->channel_id))) { - err = -EBUSY; - goto vpif_int_err; - } - } - k++; - } - - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (vfd == NULL) { - for (j = 0; j < i; j++) { - ch = vpif_obj.dev[j]; - video_device_release(ch->video_dev); - } - err = -ENOMEM; - goto vpif_int_err; - } - - /* Initialize field of video device */ - *vfd = vpif_video_template; - vfd->v4l2_dev = &vpif_obj.v4l2_dev; - vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d", - (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff, - (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff, - (VPIF_DISPLAY_VERSION_CODE) & 0xff); - - /* Set video_dev to the video device */ - ch->video_dev = vfd; - } - - for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { - ch = vpif_obj.dev[j]; - /* Initialize field of the channel objects */ - atomic_set(&ch->usrs, 0); - for (k = 0; k < VPIF_NUMOBJECTS; k++) { - ch->common[k].numbuffers = 0; - common = &ch->common[k]; - common->io_usrs = 0; - common->started = 0; - spin_lock_init(&common->irqlock); - mutex_init(&common->lock); - common->numbuffers = 0; - common->set_addr = NULL; - common->ytop_off = common->ybtm_off = 0; - common->ctop_off = common->cbtm_off = 0; - common->cur_frm = common->next_frm = NULL; - memset(&common->fmt, 0, sizeof(common->fmt)); - common->numbuffers = config_params.numbuffers[k]; - - } - ch->initialized = 0; - ch->channel_id = j; - if (j < 2) - ch->common[VPIF_VIDEO_INDEX].numbuffers = - config_params.numbuffers[ch->channel_id]; - else - ch->common[VPIF_VIDEO_INDEX].numbuffers = 0; - - memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); - - /* Initialize prio member of channel object */ - v4l2_prio_init(&ch->prio); - ch->common[VPIF_VIDEO_INDEX].fmt.type = - V4L2_BUF_TYPE_VIDEO_OUTPUT; - ch->video_dev->lock = &common->lock; - - /* register video device */ - vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", - (int)ch, (int)&ch->video_dev); - - err = video_register_device(ch->video_dev, - VFL_TYPE_GRABBER, (j ? 3 : 2)); - if (err < 0) - goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - } - - i2c_adap = i2c_get_adapter(1); - config = pdev->dev.platform_data; - subdev_count = config->subdev_count; - subdevdata = config->subdevinfo; - vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, - GFP_KERNEL); - if (vpif_obj.sd == NULL) { - vpif_err("unable to allocate memory for subdevice pointers\n"); - err = -ENOMEM; - goto probe_out; - } - - for (i = 0; i < subdev_count; i++) { - vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, - i2c_adap, - &subdevdata[i].board_info, - NULL); - if (!vpif_obj.sd[i]) { - vpif_err("Error registering v4l2 subdevice\n"); - goto probe_subdev_out; - } - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; - } - - v4l2_info(&vpif_obj.v4l2_dev, - "DM646x VPIF display driver initialized\n"); - return 0; - -probe_subdev_out: - kfree(vpif_obj.sd); -probe_out: - for (k = 0; k < j; k++) { - ch = vpif_obj.dev[k]; - video_unregister_device(ch->video_dev); - video_device_release(ch->video_dev); - ch->video_dev = NULL; - } -vpif_int_err: - v4l2_device_unregister(&vpif_obj.v4l2_dev); - vpif_err("VPIF IRQ request failed\n"); - for (q = k; k >= 0; k--) { - for (m = i; m >= res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id)); - res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1); - m = res->end; - } - - return err; -} - -/* - * vpif_remove: It un-register channels from V4L2 driver - */ -static int vpif_remove(struct platform_device *device) -{ - struct channel_obj *ch; - int i; - - v4l2_device_unregister(&vpif_obj.v4l2_dev); - - /* un-register device */ - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - /* Unregister video device */ - video_unregister_device(ch->video_dev); - - ch->video_dev = NULL; - } - - return 0; -} - -static __refdata struct platform_driver vpif_driver = { - .driver = { - .name = "vpif_display", - .owner = THIS_MODULE, - }, - .probe = vpif_probe, - .remove = vpif_remove, -}; - -static __init int vpif_init(void) -{ - return platform_driver_register(&vpif_driver); -} - -/* - * vpif_cleanup: This function un-registers device and driver to the kernel, - * frees requested irq handler and de-allocates memory allocated for channel - * objects. - */ -static void vpif_cleanup(void) -{ - struct platform_device *pdev; - struct resource *res; - int irq_num; - int i = 0; - - pdev = container_of(vpif_dev, struct platform_device, dev); - - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { - for (irq_num = res->start; irq_num <= res->end; irq_num++) - free_irq(irq_num, - (void *)(&vpif_obj.dev[i]->channel_id)); - i++; - } - - platform_driver_unregister(&vpif_driver); - kfree(vpif_obj.sd); - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) - kfree(vpif_obj.dev[i]); -} - -module_init(vpif_init); -module_exit(vpif_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_display.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_display.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_display.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif_display.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,177 +0,0 @@ -/* - * DM646x display header file - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef DAVINCIHD_DISPLAY_H -#define DAVINCIHD_DISPLAY_H - -/* Header files */ -#include -#include -#include -#include -#include -#include - -#include "vpif.h" - -/* Macros */ -#define VPIF_MAJOR_RELEASE (0) -#define VPIF_MINOR_RELEASE (0) -#define VPIF_BUILD (1) - -#define VPIF_DISPLAY_VERSION_CODE \ - ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) - -#define VPIF_VALID_FIELD(field) \ - (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \ - (((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \ - (V4L2_FIELD_SEQ_BT == field))) - -#define VPIF_DISPLAY_MAX_DEVICES (2) -#define VPIF_SLICED_BUF_SIZE (256) -#define VPIF_SLICED_MAX_SERVICES (3) -#define VPIF_VIDEO_INDEX (0) -#define VPIF_VBI_INDEX (1) -#define VPIF_HBI_INDEX (2) - -/* Setting it to 1 as HBI/VBI support yet to be added , else 3*/ -#define VPIF_NUMOBJECTS (1) - -/* Macros */ -#define ISALIGNED(a) (0 == ((a) & 7)) - -/* enumerated data types */ -/* Enumerated data type to give id to each device per channel */ -enum vpif_channel_id { - VPIF_CHANNEL2_VIDEO = 0, /* Channel2 Video */ - VPIF_CHANNEL3_VIDEO, /* Channel3 Video */ -}; - -/* structures */ - -struct video_obj { - enum v4l2_field buf_field; - u32 latest_only; /* indicate whether to return - * most recent displayed frame only */ - v4l2_std_id stdid; /* Currently selected or default - * standard */ - u32 dv_preset; - struct v4l2_bt_timings bt_timings; - u32 output_id; /* Current output id */ -}; - -struct vbi_obj { - int num_services; - struct vpif_vbi_params vbiparams; /* vpif parameters for the raw - * vbi data */ -}; - -struct common_obj { - /* Buffer specific parameters */ - u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for - * storing frames */ - u32 numbuffers; /* number of buffers */ - struct videobuf_buffer *cur_frm; /* Pointer pointing to current - * videobuf_buffer */ - struct videobuf_buffer *next_frm; /* Pointer pointing to next - * videobuf_buffer */ - enum v4l2_memory memory; /* This field keeps track of - * type of buffer exchange - * method user has selected */ - struct v4l2_format fmt; /* Used to store the format */ - struct videobuf_queue buffer_queue; /* Buffer queue used in - * video-buf */ - struct list_head dma_queue; /* Queue of filled frames */ - spinlock_t irqlock; /* Used in video-buf */ - - /* channel specific parameters */ - struct mutex lock; /* lock used to access this - * structure */ - u32 io_usrs; /* number of users performing - * IO */ - u8 started; /* Indicates whether streaming - * started */ - u32 ytop_off; /* offset of Y top from the - * starting of the buffer */ - u32 ybtm_off; /* offset of Y bottom from the - * starting of the buffer */ - u32 ctop_off; /* offset of C top from the - * starting of the buffer */ - u32 cbtm_off; /* offset of C bottom from the - * starting of the buffer */ - /* Function pointer to set the addresses */ - void (*set_addr) (unsigned long, unsigned long, - unsigned long, unsigned long); - u32 height; - u32 width; -}; - -struct channel_obj { - /* V4l2 specific parameters */ - struct video_device *video_dev; /* Identifies video device for - * this channel */ - struct v4l2_prio_state prio; /* Used to keep track of state of - * the priority */ - atomic_t usrs; /* number of open instances of - * the channel */ - u32 field_id; /* Indicates id of the field - * which is being displayed */ - u8 initialized; /* flag to indicate whether - * encoder is initialized */ - - enum vpif_channel_id channel_id;/* Identifies channel */ - struct vpif_params vpifparams; - struct common_obj common[VPIF_NUMOBJECTS]; - struct video_obj video; - struct vbi_obj vbi; -}; - -/* File handle structure */ -struct vpif_fh { - struct channel_obj *channel; /* pointer to channel object for - * opened device */ - u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle - * is doing IO */ - enum v4l2_priority prio; /* Used to keep track priority of - * this instance */ - u8 initialized; /* Used to keep track of whether this - * file handle has initialized - * channel or not */ -}; - -/* vpif device structure */ -struct vpif_device { - struct v4l2_device v4l2_dev; - struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS]; - struct v4l2_subdev **sd; - -}; - -struct vpif_config_params { - u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; - u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; - u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS]; - u8 min_numbuffers; -}; - -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; - u16 enc_service_id; - u8 bytestowrite; -}; - -#endif /* DAVINCIHD_DISPLAY_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpif.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,644 +0,0 @@ -/* - * VPIF header file - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef VPIF_H -#define VPIF_H - -#include -#include -#include -#include - -/* Maximum channel allowed */ -#define VPIF_NUM_CHANNELS (4) -#define VPIF_CAPTURE_NUM_CHANNELS (2) -#define VPIF_DISPLAY_NUM_CHANNELS (2) - -/* Macros to read/write registers */ -extern void __iomem *vpif_base; -extern spinlock_t vpif_lock; - -#define regr(reg) readl((reg) + vpif_base) -#define regw(value, reg) writel(value, (reg + vpif_base)) - -/* Register Address Offsets */ -#define VPIF_PID (0x0000) -#define VPIF_CH0_CTRL (0x0004) -#define VPIF_CH1_CTRL (0x0008) -#define VPIF_CH2_CTRL (0x000C) -#define VPIF_CH3_CTRL (0x0010) - -#define VPIF_INTEN (0x0020) -#define VPIF_INTEN_SET (0x0024) -#define VPIF_INTEN_CLR (0x0028) -#define VPIF_STATUS (0x002C) -#define VPIF_STATUS_CLR (0x0030) -#define VPIF_EMULATION_CTRL (0x0034) -#define VPIF_REQ_SIZE (0x0038) - -#define VPIF_CH0_TOP_STRT_ADD_LUMA (0x0040) -#define VPIF_CH0_BTM_STRT_ADD_LUMA (0x0044) -#define VPIF_CH0_TOP_STRT_ADD_CHROMA (0x0048) -#define VPIF_CH0_BTM_STRT_ADD_CHROMA (0x004c) -#define VPIF_CH0_TOP_STRT_ADD_HANC (0x0050) -#define VPIF_CH0_BTM_STRT_ADD_HANC (0x0054) -#define VPIF_CH0_TOP_STRT_ADD_VANC (0x0058) -#define VPIF_CH0_BTM_STRT_ADD_VANC (0x005c) -#define VPIF_CH0_SP_CFG (0x0060) -#define VPIF_CH0_IMG_ADD_OFST (0x0064) -#define VPIF_CH0_HANC_ADD_OFST (0x0068) -#define VPIF_CH0_H_CFG (0x006c) -#define VPIF_CH0_V_CFG_00 (0x0070) -#define VPIF_CH0_V_CFG_01 (0x0074) -#define VPIF_CH0_V_CFG_02 (0x0078) -#define VPIF_CH0_V_CFG_03 (0x007c) - -#define VPIF_CH1_TOP_STRT_ADD_LUMA (0x0080) -#define VPIF_CH1_BTM_STRT_ADD_LUMA (0x0084) -#define VPIF_CH1_TOP_STRT_ADD_CHROMA (0x0088) -#define VPIF_CH1_BTM_STRT_ADD_CHROMA (0x008c) -#define VPIF_CH1_TOP_STRT_ADD_HANC (0x0090) -#define VPIF_CH1_BTM_STRT_ADD_HANC (0x0094) -#define VPIF_CH1_TOP_STRT_ADD_VANC (0x0098) -#define VPIF_CH1_BTM_STRT_ADD_VANC (0x009c) -#define VPIF_CH1_SP_CFG (0x00a0) -#define VPIF_CH1_IMG_ADD_OFST (0x00a4) -#define VPIF_CH1_HANC_ADD_OFST (0x00a8) -#define VPIF_CH1_H_CFG (0x00ac) -#define VPIF_CH1_V_CFG_00 (0x00b0) -#define VPIF_CH1_V_CFG_01 (0x00b4) -#define VPIF_CH1_V_CFG_02 (0x00b8) -#define VPIF_CH1_V_CFG_03 (0x00bc) - -#define VPIF_CH2_TOP_STRT_ADD_LUMA (0x00c0) -#define VPIF_CH2_BTM_STRT_ADD_LUMA (0x00c4) -#define VPIF_CH2_TOP_STRT_ADD_CHROMA (0x00c8) -#define VPIF_CH2_BTM_STRT_ADD_CHROMA (0x00cc) -#define VPIF_CH2_TOP_STRT_ADD_HANC (0x00d0) -#define VPIF_CH2_BTM_STRT_ADD_HANC (0x00d4) -#define VPIF_CH2_TOP_STRT_ADD_VANC (0x00d8) -#define VPIF_CH2_BTM_STRT_ADD_VANC (0x00dc) -#define VPIF_CH2_SP_CFG (0x00e0) -#define VPIF_CH2_IMG_ADD_OFST (0x00e4) -#define VPIF_CH2_HANC_ADD_OFST (0x00e8) -#define VPIF_CH2_H_CFG (0x00ec) -#define VPIF_CH2_V_CFG_00 (0x00f0) -#define VPIF_CH2_V_CFG_01 (0x00f4) -#define VPIF_CH2_V_CFG_02 (0x00f8) -#define VPIF_CH2_V_CFG_03 (0x00fc) -#define VPIF_CH2_HANC0_STRT (0x0100) -#define VPIF_CH2_HANC0_SIZE (0x0104) -#define VPIF_CH2_HANC1_STRT (0x0108) -#define VPIF_CH2_HANC1_SIZE (0x010c) -#define VPIF_CH2_VANC0_STRT (0x0110) -#define VPIF_CH2_VANC0_SIZE (0x0114) -#define VPIF_CH2_VANC1_STRT (0x0118) -#define VPIF_CH2_VANC1_SIZE (0x011c) - -#define VPIF_CH3_TOP_STRT_ADD_LUMA (0x0140) -#define VPIF_CH3_BTM_STRT_ADD_LUMA (0x0144) -#define VPIF_CH3_TOP_STRT_ADD_CHROMA (0x0148) -#define VPIF_CH3_BTM_STRT_ADD_CHROMA (0x014c) -#define VPIF_CH3_TOP_STRT_ADD_HANC (0x0150) -#define VPIF_CH3_BTM_STRT_ADD_HANC (0x0154) -#define VPIF_CH3_TOP_STRT_ADD_VANC (0x0158) -#define VPIF_CH3_BTM_STRT_ADD_VANC (0x015c) -#define VPIF_CH3_SP_CFG (0x0160) -#define VPIF_CH3_IMG_ADD_OFST (0x0164) -#define VPIF_CH3_HANC_ADD_OFST (0x0168) -#define VPIF_CH3_H_CFG (0x016c) -#define VPIF_CH3_V_CFG_00 (0x0170) -#define VPIF_CH3_V_CFG_01 (0x0174) -#define VPIF_CH3_V_CFG_02 (0x0178) -#define VPIF_CH3_V_CFG_03 (0x017c) -#define VPIF_CH3_HANC0_STRT (0x0180) -#define VPIF_CH3_HANC0_SIZE (0x0184) -#define VPIF_CH3_HANC1_STRT (0x0188) -#define VPIF_CH3_HANC1_SIZE (0x018c) -#define VPIF_CH3_VANC0_STRT (0x0190) -#define VPIF_CH3_VANC0_SIZE (0x0194) -#define VPIF_CH3_VANC1_STRT (0x0198) -#define VPIF_CH3_VANC1_SIZE (0x019c) - -#define VPIF_IODFT_CTRL (0x01c0) - -/* Functions for bit Manipulation */ -static inline void vpif_set_bit(u32 reg, u32 bit) -{ - regw((regr(reg)) | (0x01 << bit), reg); -} - -static inline void vpif_clr_bit(u32 reg, u32 bit) -{ - regw(((regr(reg)) & ~(0x01 << bit)), reg); -} - -/* Macro for Generating mask */ -#ifdef GENERATE_MASK -#undef GENERATE_MASK -#endif - -#define GENERATE_MASK(bits, pos) \ - ((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos) - -/* Bit positions in the channel control registers */ -#define VPIF_CH_DATA_MODE_BIT (2) -#define VPIF_CH_YC_MUX_BIT (3) -#define VPIF_CH_SDR_FMT_BIT (4) -#define VPIF_CH_HANC_EN_BIT (8) -#define VPIF_CH_VANC_EN_BIT (9) - -#define VPIF_CAPTURE_CH_NIP (10) -#define VPIF_DISPLAY_CH_NIP (11) - -#define VPIF_DISPLAY_PIX_EN_BIT (10) - -#define VPIF_CH_INPUT_FIELD_FRAME_BIT (12) - -#define VPIF_CH_FID_POLARITY_BIT (15) -#define VPIF_CH_V_VALID_POLARITY_BIT (14) -#define VPIF_CH_H_VALID_POLARITY_BIT (13) -#define VPIF_CH_DATA_WIDTH_BIT (28) - -#define VPIF_CH_CLK_EDGE_CTRL_BIT (31) - -/* Mask various length */ -#define VPIF_CH_EAVSAV_MASK GENERATE_MASK(13, 0) -#define VPIF_CH_LEN_MASK GENERATE_MASK(12, 0) -#define VPIF_CH_WIDTH_MASK GENERATE_MASK(13, 0) -#define VPIF_CH_LEN_SHIFT (16) - -/* VPIF masks for registers */ -#define VPIF_REQ_SIZE_MASK (0x1ff) - -/* bit posotion of interrupt vpif_ch_intr register */ -#define VPIF_INTEN_FRAME_CH0 (0x00000001) -#define VPIF_INTEN_FRAME_CH1 (0x00000002) -#define VPIF_INTEN_FRAME_CH2 (0x00000004) -#define VPIF_INTEN_FRAME_CH3 (0x00000008) - -/* bit position of clock and channel enable in vpif_chn_ctrl register */ - -#define VPIF_CH0_CLK_EN (0x00000002) -#define VPIF_CH0_EN (0x00000001) -#define VPIF_CH1_CLK_EN (0x00000002) -#define VPIF_CH1_EN (0x00000001) -#define VPIF_CH2_CLK_EN (0x00000002) -#define VPIF_CH2_EN (0x00000001) -#define VPIF_CH3_CLK_EN (0x00000002) -#define VPIF_CH3_EN (0x00000001) -#define VPIF_CH_CLK_EN (0x00000002) -#define VPIF_CH_EN (0x00000001) - -#define VPIF_INT_TOP (0x00) -#define VPIF_INT_BOTTOM (0x01) -#define VPIF_INT_BOTH (0x02) - -#define VPIF_CH0_INT_CTRL_SHIFT (6) -#define VPIF_CH1_INT_CTRL_SHIFT (6) -#define VPIF_CH2_INT_CTRL_SHIFT (6) -#define VPIF_CH3_INT_CTRL_SHIFT (6) -#define VPIF_CH_INT_CTRL_SHIFT (6) - -/* enabled interrupt on both the fields on vpid_ch0_ctrl register */ -#define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\ - (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL)) - -/* enabled interrupt on both the fields on vpid_ch1_ctrl register */ -#define channel1_intr_assert() (regw((regr(VPIF_CH1_CTRL)|\ - (VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL)) - -/* enabled interrupt on both the fields on vpid_ch0_ctrl register */ -#define channel2_intr_assert() (regw((regr(VPIF_CH2_CTRL)|\ - (VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL)) - -/* enabled interrupt on both the fields on vpid_ch1_ctrl register */ -#define channel3_intr_assert() (regw((regr(VPIF_CH3_CTRL)|\ - (VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL)) - -#define VPIF_CH_FID_MASK (0x20) -#define VPIF_CH_FID_SHIFT (5) - -#define VPIF_NTSC_VBI_START_FIELD0 (1) -#define VPIF_NTSC_VBI_START_FIELD1 (263) -#define VPIF_PAL_VBI_START_FIELD0 (624) -#define VPIF_PAL_VBI_START_FIELD1 (311) - -#define VPIF_NTSC_HBI_START_FIELD0 (1) -#define VPIF_NTSC_HBI_START_FIELD1 (263) -#define VPIF_PAL_HBI_START_FIELD0 (624) -#define VPIF_PAL_HBI_START_FIELD1 (311) - -#define VPIF_NTSC_VBI_COUNT_FIELD0 (20) -#define VPIF_NTSC_VBI_COUNT_FIELD1 (19) -#define VPIF_PAL_VBI_COUNT_FIELD0 (24) -#define VPIF_PAL_VBI_COUNT_FIELD1 (25) - -#define VPIF_NTSC_HBI_COUNT_FIELD0 (263) -#define VPIF_NTSC_HBI_COUNT_FIELD1 (262) -#define VPIF_PAL_HBI_COUNT_FIELD0 (312) -#define VPIF_PAL_HBI_COUNT_FIELD1 (313) - -#define VPIF_NTSC_VBI_SAMPLES_PER_LINE (720) -#define VPIF_PAL_VBI_SAMPLES_PER_LINE (720) -#define VPIF_NTSC_HBI_SAMPLES_PER_LINE (268) -#define VPIF_PAL_HBI_SAMPLES_PER_LINE (280) - -#define VPIF_CH_VANC_EN (0x20) -#define VPIF_DMA_REQ_SIZE (0x080) -#define VPIF_EMULATION_DISABLE (0x01) - -extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS]; - -/* inline function to enable/disable channel0 */ -static inline void enable_channel0(int enable) -{ - if (enable) - regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL); - else - regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL); -} - -/* inline function to enable/disable channel1 */ -static inline void enable_channel1(int enable) -{ - if (enable) - regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL); - else - regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL); -} - -/* inline function to enable interrupt for channel0 */ -static inline void channel0_intr_enable(int enable) -{ - unsigned long flags; - - spin_lock_irqsave(&vpif_lock, flags); - - if (enable) { - regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); - - regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), - VPIF_INTEN_SET); - } else { - regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), - VPIF_INTEN_SET); - } - spin_unlock_irqrestore(&vpif_lock, flags); -} - -/* inline function to enable interrupt for channel1 */ -static inline void channel1_intr_enable(int enable) -{ - unsigned long flags; - - spin_lock_irqsave(&vpif_lock, flags); - - if (enable) { - regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); - - regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), - VPIF_INTEN_SET); - } else { - regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), - VPIF_INTEN_SET); - } - spin_unlock_irqrestore(&vpif_lock, flags); -} - -/* inline function to set buffer addresses in case of Y/C non mux mode */ -static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); -} - -/* inline function to set buffer addresses in VPIF registers for video data */ -static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA); -} - -static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - - regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); -} - -static inline void ch0_set_vbi_addr(unsigned long top_vbi, - unsigned long btm_vbi, unsigned long a, unsigned long b) -{ - regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC); - regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC); -} - -static inline void ch0_set_hbi_addr(unsigned long top_vbi, - unsigned long btm_vbi, unsigned long a, unsigned long b) -{ - regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC); - regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC); -} - -static inline void ch1_set_vbi_addr(unsigned long top_vbi, - unsigned long btm_vbi, unsigned long a, unsigned long b) -{ - regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC); - regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC); -} - -static inline void ch1_set_hbi_addr(unsigned long top_vbi, - unsigned long btm_vbi, unsigned long a, unsigned long b) -{ - regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC); - regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC); -} - -/* Inline function to enable raw vbi in the given channel */ -static inline void disable_raw_feature(u8 channel_id, u8 index) -{ - u32 ctrl_reg; - if (0 == channel_id) - ctrl_reg = VPIF_CH0_CTRL; - else - ctrl_reg = VPIF_CH1_CTRL; - - if (1 == index) - vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); - else - vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); -} - -static inline void enable_raw_feature(u8 channel_id, u8 index) -{ - u32 ctrl_reg; - if (0 == channel_id) - ctrl_reg = VPIF_CH0_CTRL; - else - ctrl_reg = VPIF_CH1_CTRL; - - if (1 == index) - vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); - else - vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); -} - -/* inline function to enable/disable channel2 */ -static inline void enable_channel2(int enable) -{ - if (enable) { - regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); - regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL); - } else { - regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); - regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL); - } -} - -/* inline function to enable/disable channel3 */ -static inline void enable_channel3(int enable) -{ - if (enable) { - regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); - regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL); - } else { - regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); - regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL); - } -} - -/* inline function to enable interrupt for channel2 */ -static inline void channel2_intr_enable(int enable) -{ - unsigned long flags; - - spin_lock_irqsave(&vpif_lock, flags); - - if (enable) { - regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); - regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), - VPIF_INTEN_SET); - } else { - regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), - VPIF_INTEN_SET); - } - spin_unlock_irqrestore(&vpif_lock, flags); -} - -/* inline function to enable interrupt for channel3 */ -static inline void channel3_intr_enable(int enable) -{ - unsigned long flags; - - spin_lock_irqsave(&vpif_lock, flags); - - if (enable) { - regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); - - regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), - VPIF_INTEN_SET); - } else { - regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), - VPIF_INTEN_SET); - } - spin_unlock_irqrestore(&vpif_lock, flags); -} - -/* inline function to enable raw vbi data for channel2 */ -static inline void channel2_raw_enable(int enable, u8 index) -{ - u32 mask; - - if (1 == index) - mask = VPIF_CH_VANC_EN_BIT; - else - mask = VPIF_CH_HANC_EN_BIT; - - if (enable) - vpif_set_bit(VPIF_CH2_CTRL, mask); - else - vpif_clr_bit(VPIF_CH2_CTRL, mask); -} - -/* inline function to enable raw vbi data for channel3*/ -static inline void channel3_raw_enable(int enable, u8 index) -{ - u32 mask; - - if (1 == index) - mask = VPIF_CH_VANC_EN_BIT; - else - mask = VPIF_CH_HANC_EN_BIT; - - if (enable) - vpif_set_bit(VPIF_CH3_CTRL, mask); - else - vpif_clr_bit(VPIF_CH3_CTRL, mask); -} - -/* inline function to set buffer addresses in case of Y/C non mux mode */ -static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); -} - -/* inline function to set buffer addresses in VPIF registers for video data */ -static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA); -} - -static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); -} - -/* inline function to set buffer addresses in VPIF registers for vbi data */ -static inline void ch2_set_vbi_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC); - regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC); -} - -static inline void ch3_set_vbi_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC); - regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC); -} - -#define VPIF_MAX_NAME (30) - -/* This structure will store size parameters as per the mode selected by user */ -struct vpif_channel_config_params { - char name[VPIF_MAX_NAME]; /* Name of the mode */ - u16 width; /* Indicates width of the image */ - u16 height; /* Indicates height of the image */ - u8 frm_fmt; /* Interlaced (0) or progressive (1) */ - u8 ycmux_mode; /* This mode requires one (0) or two (1) - channels */ - u16 eav2sav; /* length of eav 2 sav */ - u16 sav2eav; /* length of sav 2 eav */ - u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */ - u16 vsize; /* Vertical size of the image */ - u8 capture_format; /* Indicates whether capture format - * is in BT or in CCD/CMOS */ - u8 vbi_supported; /* Indicates whether this mode - * supports capturing vbi or not */ - u8 hd_sd; /* HDTV (1) or SDTV (0) format */ - v4l2_std_id stdid; /* SDTV format */ - u32 dv_preset; /* HDTV format */ -}; - -extern const unsigned int vpif_ch_params_count; -extern const struct vpif_channel_config_params ch_params[]; - -struct vpif_video_params; -struct vpif_params; -struct vpif_vbi_params; - -int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id); -void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, - u8 channel_id); -int vpif_channel_getfid(u8 channel_id); - -enum data_size { - _8BITS = 0, - _10BITS, - _12BITS, -}; - -/* Structure for vpif parameters for raw vbi data */ -struct vpif_vbi_params { - __u32 hstart0; /* Horizontal start of raw vbi data for first field */ - __u32 vstart0; /* Vertical start of raw vbi data for first field */ - __u32 hsize0; /* Horizontal size of raw vbi data for first field */ - __u32 vsize0; /* Vertical size of raw vbi data for first field */ - __u32 hstart1; /* Horizontal start of raw vbi data for second field */ - __u32 vstart1; /* Vertical start of raw vbi data for second field */ - __u32 hsize1; /* Horizontal size of raw vbi data for second field */ - __u32 vsize1; /* Vertical size of raw vbi data for second field */ -}; - -/* structure for vpif parameters */ -struct vpif_video_params { - __u8 storage_mode; /* Indicates field or frame mode */ - unsigned long hpitch; - v4l2_std_id stdid; -}; - -struct vpif_params { - struct vpif_interface iface; - struct vpif_video_params video_params; - struct vpif_channel_config_params std_info; - union param { - struct vpif_vbi_params vbi_params; - enum data_size data_sz; - } params; -}; - -#endif /* End of #ifndef VPIF_H */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpss.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpss.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpss.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/davinci/vpss.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2009 Texas Instruments. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * common vpss system module platform driver for all video drivers. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("VPSS Driver"); -MODULE_AUTHOR("Texas Instruments"); - -/* DM644x defines */ -#define DM644X_SBL_PCR_VPSS (4) - -#define DM355_VPSSBL_INTSEL 0x10 -#define DM355_VPSSBL_EVTSEL 0x14 -/* vpss BL register offsets */ -#define DM355_VPSSBL_CCDCMUX 0x1c -/* vpss CLK register offsets */ -#define DM355_VPSSCLK_CLKCTRL 0x04 -/* masks and shifts */ -#define VPSS_HSSISEL_SHIFT 4 -/* - * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4, - * IPIPE_INT1_SDR - vpss_int5 - */ -#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10 -/* VENCINT - vpss_int8 */ -#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4 - -#define DM365_ISP5_PCCR 0x04 -#define DM365_ISP5_INTSEL1 0x10 -#define DM365_ISP5_INTSEL2 0x14 -#define DM365_ISP5_INTSEL3 0x18 -#define DM365_ISP5_CCDCMUX 0x20 -#define DM365_ISP5_PG_FRAME_SIZE 0x28 -#define DM365_VPBE_CLK_CTRL 0x00 -/* - * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1, - * AF - vpss_int3 - */ -#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100 -/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */ -#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f -/* VENC - vpss_int8 */ -#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015 - -/* masks and shifts for DM365*/ -#define DM365_CCDC_PG_VD_POL_SHIFT 0 -#define DM365_CCDC_PG_HD_POL_SHIFT 1 - -#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4)) -#define CCD_SRC_SEL_SHIFT 4 - -/* Different SoC platforms supported by this driver */ -enum vpss_platform_type { - DM644X, - DM355, - DM365, -}; - -/* - * vpss operations. Depends on platform. Not all functions are available - * on all platforms. The api, first check if a functio is available before - * invoking it. In the probe, the function ptrs are initialized based on - * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. - */ -struct vpss_hw_ops { - /* enable clock */ - int (*enable_clock)(enum vpss_clock_sel clock_sel, int en); - /* select input to ccdc */ - void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel); - /* clear wbl overflow bit */ - int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel); -}; - -/* vpss configuration */ -struct vpss_oper_config { - __iomem void *vpss_regs_base0; - __iomem void *vpss_regs_base1; - enum vpss_platform_type platform; - spinlock_t vpss_lock; - struct vpss_hw_ops hw_ops; -}; - -static struct vpss_oper_config oper_cfg; - -/* register access routines */ -static inline u32 bl_regr(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base0 + offset); -} - -static inline void bl_regw(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); -} - -static inline u32 vpss_regr(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base1 + offset); -} - -static inline void vpss_regw(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base1 + offset); -} - -/* For DM365 only */ -static inline u32 isp5_read(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base0 + offset); -} - -/* For DM365 only */ -static inline void isp5_write(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); -} - -static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK; - - /* if we are using pattern generator, enable it */ - if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG) - temp |= 0x08; - - temp |= (src_sel << CCD_SRC_SEL_SHIFT); - isp5_write(temp, DM365_ISP5_CCDCMUX); -} - -static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX); -} - -int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - if (!oper_cfg.hw_ops.select_ccdc_source) - return -EINVAL; - - oper_cfg.hw_ops.select_ccdc_source(src_sel); - return 0; -} -EXPORT_SYMBOL(vpss_select_ccdc_source); - -static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) -{ - u32 mask = 1, val; - - if (wbl_sel < VPSS_PCR_AEW_WBL_0 || - wbl_sel > VPSS_PCR_CCDC_WBL_O) - return -EINVAL; - - /* writing a 0 clear the overflow */ - mask = ~(mask << wbl_sel); - val = bl_regr(DM644X_SBL_PCR_VPSS) & mask; - bl_regw(val, DM644X_SBL_PCR_VPSS); - return 0; -} - -int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) -{ - if (!oper_cfg.hw_ops.clear_wbl_overflow) - return -EINVAL; - - return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); -} -EXPORT_SYMBOL(vpss_clear_wbl_overflow); - -/* - * dm355_enable_clock - Enable VPSS Clock - * @clock_sel: CLock to be enabled/disabled - * @en: enable/disable flag - * - * This is called to enable or disable a vpss clock - */ -static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - unsigned long flags; - u32 utemp, mask = 0x1, shift = 0; - - switch (clock_sel) { - case VPSS_VPBE_CLOCK: - /* nothing since lsb */ - break; - case VPSS_VENC_CLOCK_SEL: - shift = 2; - break; - case VPSS_CFALD_CLOCK: - shift = 3; - break; - case VPSS_H3A_CLOCK: - shift = 4; - break; - case VPSS_IPIPE_CLOCK: - shift = 5; - break; - case VPSS_CCDC_CLOCK: - shift = 6; - break; - default: - printk(KERN_ERR "dm355_enable_clock:" - " Invalid selector: %d\n", clock_sel); - return -EINVAL; - } - - spin_lock_irqsave(&oper_cfg.vpss_lock, flags); - utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL); - if (!en) - utemp &= ~(mask << shift); - else - utemp |= (mask << shift); - - vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL); - spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); - return 0; -} - -static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - unsigned long flags; - u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR; - u32 (*read)(u32 offset) = isp5_read; - void(*write)(u32 val, u32 offset) = isp5_write; - - switch (clock_sel) { - case VPSS_BL_CLOCK: - break; - case VPSS_CCDC_CLOCK: - shift = 1; - break; - case VPSS_H3A_CLOCK: - shift = 2; - break; - case VPSS_RSZ_CLOCK: - shift = 3; - break; - case VPSS_IPIPE_CLOCK: - shift = 4; - break; - case VPSS_IPIPEIF_CLOCK: - shift = 5; - break; - case VPSS_PCLK_INTERNAL: - shift = 6; - break; - case VPSS_PSYNC_CLOCK_SEL: - shift = 7; - break; - case VPSS_VPBE_CLOCK: - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_VENC_CLOCK_SEL: - shift = 2; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_LDC_CLOCK: - shift = 3; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_FDIF_CLOCK: - shift = 4; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_OSD_CLOCK_SEL: - shift = 6; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_LDC_CLOCK_SEL: - shift = 7; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - default: - printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n", - clock_sel); - return -1; - } - - spin_lock_irqsave(&oper_cfg.vpss_lock, flags); - utemp = read(offset); - if (!en) { - mask = ~mask; - utemp &= (mask << shift); - } else - utemp |= (mask << shift); - - write(utemp, offset); - spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); - - return 0; -} - -int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - if (!oper_cfg.hw_ops.enable_clock) - return -EINVAL; - - return oper_cfg.hw_ops.enable_clock(clock_sel, en); -} -EXPORT_SYMBOL(vpss_enable_clock); - -void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync) -{ - int val = 0; - val = isp5_read(DM365_ISP5_CCDCMUX); - - val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT); - val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT); - - isp5_write(val, DM365_ISP5_CCDCMUX); -} -EXPORT_SYMBOL(dm365_vpss_set_sync_pol); - -void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) -{ - int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16; - - current_reg |= (frame_size.pplen - 1); - isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE); -} -EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); - -static int __init vpss_probe(struct platform_device *pdev) -{ - struct resource *r1, *r2; - char *platform_name; - int status; - - if (!pdev->dev.platform_data) { - dev_err(&pdev->dev, "no platform data\n"); - return -ENOENT; - } - - platform_name = pdev->dev.platform_data; - if (!strcmp(platform_name, "dm355_vpss")) - oper_cfg.platform = DM355; - else if (!strcmp(platform_name, "dm365_vpss")) - oper_cfg.platform = DM365; - else if (!strcmp(platform_name, "dm644x_vpss")) - oper_cfg.platform = DM644X; - else { - dev_err(&pdev->dev, "vpss driver not supported on" - " this platform\n"); - return -ENODEV; - } - - dev_info(&pdev->dev, "%s vpss probed\n", platform_name); - r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r1) - return -ENOENT; - - r1 = request_mem_region(r1->start, resource_size(r1), r1->name); - if (!r1) - return -EBUSY; - - oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1)); - if (!oper_cfg.vpss_regs_base0) { - status = -EBUSY; - goto fail1; - } - - if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { - r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!r2) { - status = -ENOENT; - goto fail2; - } - r2 = request_mem_region(r2->start, resource_size(r2), r2->name); - if (!r2) { - status = -EBUSY; - goto fail2; - } - - oper_cfg.vpss_regs_base1 = ioremap(r2->start, - resource_size(r2)); - if (!oper_cfg.vpss_regs_base1) { - status = -EBUSY; - goto fail3; - } - } - - if (oper_cfg.platform == DM355) { - oper_cfg.hw_ops.enable_clock = dm355_enable_clock; - oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; - /* Setup vpss interrupts */ - bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL); - bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL); - } else if (oper_cfg.platform == DM365) { - oper_cfg.hw_ops.enable_clock = dm365_enable_clock; - oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source; - /* Setup vpss interrupts */ - isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1); - isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2); - isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3); - } else - oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; - - spin_lock_init(&oper_cfg.vpss_lock); - dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); - return 0; - -fail3: - release_mem_region(r2->start, resource_size(r2)); -fail2: - iounmap(oper_cfg.vpss_regs_base0); -fail1: - release_mem_region(r1->start, resource_size(r1)); - return status; -} - -static int __devexit vpss_remove(struct platform_device *pdev) -{ - struct resource *res; - - iounmap(oper_cfg.vpss_regs_base0); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { - iounmap(oper_cfg.vpss_regs_base1); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - release_mem_region(res->start, resource_size(res)); - } - return 0; -} - -static struct platform_driver vpss_driver = { - .driver = { - .name = "vpss", - .owner = THIS_MODULE, - }, - .remove = __devexit_p(vpss_remove), - .probe = vpss_probe, -}; - -static void vpss_exit(void) -{ - platform_driver_unregister(&vpss_driver); -} - -static int __init vpss_init(void) -{ - return platform_driver_register(&vpss_driver); -} -subsys_initcall(vpss_init); -module_exit(vpss_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-audio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-audio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,545 +0,0 @@ -/* - * Empiatech em28x1 audio extension - * - * Copyright (C) 2006 Markus Rechberger - * - * Copyright (C) 2007 Mauro Carvalho Chehab - * - Port to work with the in-kernel driver - * - Several cleanups - * - * This driver is based on my previous au600 usb pstn audio driver - * and inherits all the copyrights - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "em28xx.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); - -#define dprintk(fmt, arg...) do { \ - if (debug) \ - printk(KERN_INFO "em28xx-audio %s: " fmt, \ - __func__, ##arg); \ - } while (0) - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; - -static int em28xx_deinit_isoc_audio(struct em28xx *dev) -{ - int i; - - dprintk("Stopping isoc\n"); - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - if (!irqs_disabled()) - usb_kill_urb(dev->adev.urb[i]); - else - usb_unlink_urb(dev->adev.urb[i]); - - usb_free_urb(dev->adev.urb[i]); - dev->adev.urb[i] = NULL; - - kfree(dev->adev.transfer_buffer[i]); - dev->adev.transfer_buffer[i] = NULL; - } - - return 0; -} - -static void em28xx_audio_isocirq(struct urb *urb) -{ - struct em28xx *dev = urb->context; - int i; - unsigned int oldptr; - int period_elapsed = 0; - int status; - unsigned char *cp; - unsigned int stride; - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - dprintk("urb completition error %d.\n", urb->status); - break; - } - - if (atomic_read(&dev->stream_started) == 0) - return; - - if (dev->adev.capture_pcm_substream) { - substream = dev->adev.capture_pcm_substream; - runtime = substream->runtime; - stride = runtime->frame_bits >> 3; - - for (i = 0; i < urb->number_of_packets; i++) { - int length = - urb->iso_frame_desc[i].actual_length / stride; - cp = (unsigned char *)urb->transfer_buffer + - urb->iso_frame_desc[i].offset; - - if (!length) - continue; - - oldptr = dev->adev.hwptr_done_capture; - if (oldptr + length >= runtime->buffer_size) { - unsigned int cnt = - runtime->buffer_size - oldptr; - memcpy(runtime->dma_area + oldptr * stride, cp, - cnt * stride); - memcpy(runtime->dma_area, cp + cnt * stride, - length * stride - cnt * stride); - } else { - memcpy(runtime->dma_area + oldptr * stride, cp, - length * stride); - } - - snd_pcm_stream_lock(substream); - - dev->adev.hwptr_done_capture += length; - if (dev->adev.hwptr_done_capture >= - runtime->buffer_size) - dev->adev.hwptr_done_capture -= - runtime->buffer_size; - - dev->adev.capture_transfer_done += length; - if (dev->adev.capture_transfer_done >= - runtime->period_size) { - dev->adev.capture_transfer_done -= - runtime->period_size; - period_elapsed = 1; - } - - snd_pcm_stream_unlock(substream); - } - if (period_elapsed) - snd_pcm_period_elapsed(substream); - } - urb->status = 0; - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - em28xx_errdev("resubmit of audio urb failed (error=%i)\n", - status); - } - return; -} - -static int em28xx_init_audio_isoc(struct em28xx *dev) -{ - int i, errCode; - const int sb_size = EM28XX_NUM_AUDIO_PACKETS * - EM28XX_AUDIO_MAX_PACKET_SIZE; - - dprintk("Starting isoc transfers\n"); - - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - struct urb *urb; - int j, k; - - dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); - if (!dev->adev.transfer_buffer[i]) - return -ENOMEM; - - memset(dev->adev.transfer_buffer[i], 0x80, sb_size); - urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); - if (!urb) { - em28xx_errdev("usb_alloc_urb failed!\n"); - for (j = 0; j < i; j++) { - usb_free_urb(dev->adev.urb[j]); - kfree(dev->adev.transfer_buffer[j]); - } - return -ENOMEM; - } - - urb->dev = dev->udev; - urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->adev.transfer_buffer[i]; - urb->interval = 1; - urb->complete = em28xx_audio_isocirq; - urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; - urb->transfer_buffer_length = sb_size; - - for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS; - j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - EM28XX_AUDIO_MAX_PACKET_SIZE; - } - dev->adev.urb[i] = urb; - } - - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); - if (errCode) { - em28xx_deinit_isoc_audio(dev); - return errCode; - } - } - - return 0; -} - -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, - size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - dprintk("Allocating vbuffer\n"); - if (runtime->dma_area) { - if (runtime->dma_bytes > size) - return 0; - - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc(size); - if (!runtime->dma_area) - return -ENOMEM; - - runtime->dma_bytes = size; - - return 0; -} - -static struct snd_pcm_hardware snd_em28xx_hw_capture = { - .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID, - - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, - - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ - .period_bytes_min = 64, /* 12544/2, */ - .period_bytes_max = 12544, - .periods_min = 2, - .periods_max = 98, /* 12544, */ -}; - -static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int ret = 0; - - dprintk("opening device and trying to acquire exclusive lock\n"); - - if (!dev) { - em28xx_err("BUG: em28xx can't find device struct." - " Can't proceed with open\n"); - return -ENODEV; - } - - /* Sets volume, mute, etc */ - - dev->mute = 0; - mutex_lock(&dev->lock); - ret = em28xx_audio_analog_set(dev); - if (ret < 0) - goto err; - - runtime->hw = snd_em28xx_hw_capture; - if (dev->alt == 0 && dev->adev.users == 0) { - int errCode; - dev->alt = 7; - dprintk("changing alternate number to 7\n"); - errCode = usb_set_interface(dev->udev, 0, 7); - } - - dev->adev.users++; - mutex_unlock(&dev->lock); - - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - dev->adev.capture_pcm_substream = substream; - runtime->private_data = dev; - - return 0; -err: - mutex_unlock(&dev->lock); - - em28xx_err("Error while configuring em28xx mixer\n"); - return ret; -} - -static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - - dprintk("closing device\n"); - - dev->mute = 1; - mutex_lock(&dev->lock); - dev->adev.users--; - if (atomic_read(&dev->stream_started) > 0) { - atomic_set(&dev->stream_started, 0); - schedule_work(&dev->wq_trigger); - } - - em28xx_audio_analog_set(dev); - if (substream->runtime->dma_area) { - dprintk("freeing\n"); - vfree(substream->runtime->dma_area); - substream->runtime->dma_area = NULL; - } - mutex_unlock(&dev->lock); - - return 0; -} - -static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - unsigned int channels, rate, format; - int ret; - - dprintk("Setting capture parameters\n"); - - ret = snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - format = params_format(hw_params); - rate = params_rate(hw_params); - channels = params_channels(hw_params); - - /* TODO: set up em28xx audio chip to deliver the correct audio format, - current default is 48000hz multiplexed => 96000hz mono - which shouldn't matter since analogue TV only supports mono */ - return 0; -} - -static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - - dprintk("Stop capture, if needed\n"); - - if (atomic_read(&dev->stream_started) > 0) { - atomic_set(&dev->stream_started, 0); - schedule_work(&dev->wq_trigger); - } - - return 0; -} - -static int snd_em28xx_prepare(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - - dev->adev.hwptr_done_capture = 0; - dev->adev.capture_transfer_done = 0; - - return 0; -} - -static void audio_trigger(struct work_struct *work) -{ - struct em28xx *dev = container_of(work, struct em28xx, wq_trigger); - - if (atomic_read(&dev->stream_started)) { - dprintk("starting capture"); - em28xx_init_audio_isoc(dev); - } else { - dprintk("stopping capture"); - em28xx_deinit_isoc_audio(dev); - } -} - -static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - int retval; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - atomic_set(&dev->stream_started, 1); - break; - case SNDRV_PCM_TRIGGER_STOP: - atomic_set(&dev->stream_started, 1); - break; - default: - retval = -EINVAL; - } - schedule_work(&dev->wq_trigger); - return 0; -} - -static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream - *substream) -{ - unsigned long flags; - struct em28xx *dev; - snd_pcm_uframes_t hwptr_done; - - dev = snd_pcm_substream_chip(substream); - spin_lock_irqsave(&dev->adev.slock, flags); - hwptr_done = dev->adev.hwptr_done_capture; - spin_unlock_irqrestore(&dev->adev.slock, flags); - - return hwptr_done; -} - -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - - return vmalloc_to_page(pageptr); -} - -static struct snd_pcm_ops snd_em28xx_pcm_capture = { - .open = snd_em28xx_capture_open, - .close = snd_em28xx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_em28xx_hw_capture_params, - .hw_free = snd_em28xx_hw_capture_free, - .prepare = snd_em28xx_prepare, - .trigger = snd_em28xx_capture_trigger, - .pointer = snd_em28xx_capture_pointer, - .page = snd_pcm_get_vmalloc_page, -}; - -static int em28xx_audio_init(struct em28xx *dev) -{ - struct em28xx_audio *adev = &dev->adev; - struct snd_pcm *pcm; - struct snd_card *card; - static int devnr; - int err; - - if (dev->has_alsa_audio != 1) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module or - doesn't have analog audio support at all) */ - return 0; - } - - printk(KERN_INFO "em28xx-audio.c: probing for em28x1 " - "non standard usbaudio\n"); - printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " - "Rechberger\n"); - - err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0, - &card); - if (err < 0) - return err; - - spin_lock_init(&adev->slock); - err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); - if (err < 0) { - snd_card_free(card); - return err; - } - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); - pcm->info_flags = 0; - pcm->private_data = dev; - strcpy(pcm->name, "Empia 28xx Capture"); - - snd_card_set_dev(card, &dev->udev->dev); - strcpy(card->driver, "Em28xx-Audio"); - strcpy(card->shortname, "Em28xx Audio"); - strcpy(card->longname, "Empia Em28xx Audio"); - - INIT_WORK(&dev->wq_trigger, audio_trigger); - - err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } - adev->sndcard = card; - adev->udev = dev->udev; - - return 0; -} - -static int em28xx_audio_fini(struct em28xx *dev) -{ - if (dev == NULL) - return 0; - - if (dev->has_alsa_audio != 1) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module or - doesn't have analog audio support at all) */ - return 0; - } - - if (dev->adev.sndcard) { - snd_card_free(dev->adev.sndcard); - dev->adev.sndcard = NULL; - } - - return 0; -} - -static struct em28xx_ops audio_ops = { - .id = EM28XX_AUDIO, - .name = "Em28xx Audio Extension", - .init = em28xx_audio_init, - .fini = em28xx_audio_fini, -}; - -static int __init em28xx_alsa_register(void) -{ - return em28xx_register_extension(&audio_ops); -} - -static void __exit em28xx_alsa_unregister(void) -{ - em28xx_unregister_extension(&audio_ops); -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Markus Rechberger "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_DESCRIPTION("Em28xx Audio driver"); - -module_init(em28xx_alsa_register); -module_exit(em28xx_alsa_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-cards.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3195 +0,0 @@ -/* - em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "em28xx.h" - -#define DRIVER_NAME "em28xx" - -static int tuner = -1; -module_param(tuner, int, 0444); -MODULE_PARM_DESC(tuner, "tuner type"); - -static unsigned int disable_ir; -module_param(disable_ir, int, 0444); -MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); - -static unsigned int disable_usb_speed_check; -module_param(disable_usb_speed_check, int, 0444); -MODULE_PARM_DESC(disable_usb_speed_check, - "override min bandwidth requirement of 480M bps"); - -static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card, "card type"); - -/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ -static unsigned long em28xx_devused; - -struct em28xx_hash_table { - unsigned long hash; - unsigned int model; - unsigned int tuner; -}; - -/* - * Reset sequences for analog/digital modes - */ - -/* Reset for the most [analog] boards */ -static struct em28xx_reg_seq default_analog[] = { - {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Reset for the most [digital] boards */ -static struct em28xx_reg_seq default_digital[] = { - {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Board Hauppauge WinTV HVR 900 analog */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { - {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10}, - {0x05, 0xff, 0x10, 10}, - { -1, -1, -1, -1}, -}; - -/* Board Hauppauge WinTV HVR 900 digital */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { - {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10}, - {EM2880_R04_GPO, 0x04, 0x0f, 10}, - {EM2880_R04_GPO, 0x0c, 0x0f, 10}, - { -1, -1, -1, -1}, -}; - -/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ -static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { - {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ - -/* Board - EM2870 Kworld 355u - Analog - No input analog */ - -/* Board - EM2882 Kworld 315U digital */ -static struct em28xx_reg_seq em2882_kworld_315u_digital[] = { - {EM28XX_R08_GPIO, 0xff, 0xff, 10}, - {EM28XX_R08_GPIO, 0xfe, 0xff, 10}, - {EM2880_R04_GPO, 0x04, 0xff, 10}, - {EM2880_R04_GPO, 0x0c, 0xff, 10}, - {EM28XX_R08_GPIO, 0x7e, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { - {EM2880_R04_GPO, 0x08, 0xff, 10}, - {EM2880_R04_GPO, 0x0c, 0xff, 10}, - {EM2880_R04_GPO, 0x08, 0xff, 10}, - {EM2880_R04_GPO, 0x0c, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq kworld_330u_analog[] = { - {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, - {EM2880_R04_GPO, 0x00, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq kworld_330u_digital[] = { - {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, - {EM2880_R04_GPO, 0x08, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -/* Evga inDtube - GPIO0 - Enable digital power (s5h1409) - low to enable - GPIO1 - Enable analog power (tvp5150/emp202) - low to enable - GPIO4 - xc3028 reset - GOP3 - s5h1409 reset - */ -static struct em28xx_reg_seq evga_indtube_analog[] = { - {EM28XX_R08_GPIO, 0x79, 0xff, 60}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq evga_indtube_digital[] = { - {EM28XX_R08_GPIO, 0x7a, 0xff, 1}, - {EM2880_R04_GPO, 0x04, 0xff, 10}, - {EM2880_R04_GPO, 0x0c, 0xff, 1}, - { -1, -1, -1, -1}, -}; - -/* - * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map: - * EM_GPIO_0 - currently unknown - * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on) - * EM_GPIO_2 - currently unknown - * EM_GPIO_3 - currently unknown - * EM_GPIO_4 - TDA18271HD/C1 tuner (1 = active, 0 = in reset) - * EM_GPIO_5 - LGDT3304 ATSC/QAM demod (1 = active, 0 = in reset) - * EM_GPIO_6 - currently unknown - * EM_GPIO_7 - currently unknown - */ -static struct em28xx_reg_seq kworld_a340_digital[] = { - {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Pinnacle Hybrid Pro eb1a:2881 */ -static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = { - {EM28XX_R08_GPIO, 0xfd, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = { - {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, - {EM2880_R04_GPO, 0x04, 0xff, 100},/* zl10353 reset */ - {EM2880_R04_GPO, 0x0c, 0xff, 1}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = { - {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, - {EM2880_R04_GPO, 0x00, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { - {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, - {EM2880_R04_GPO, 0x08, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -/* eb1a:2868 Reddo DVB-C USB TV Box - GPIO4 - CU1216L NIM - Other GPIOs seems to be don't care. */ -static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { - {EM28XX_R08_GPIO, 0xfe, 0xff, 10}, - {EM28XX_R08_GPIO, 0xde, 0xff, 10}, - {EM28XX_R08_GPIO, 0xfe, 0xff, 10}, - {EM28XX_R08_GPIO, 0xff, 0xff, 10}, - {EM28XX_R08_GPIO, 0x7f, 0xff, 10}, - {EM28XX_R08_GPIO, 0x6f, 0xff, 10}, - {EM28XX_R08_GPIO, 0xff, 0xff, 10}, - {-1, -1, -1, -1}, -}; - -/* Callback for the most boards */ -static struct em28xx_reg_seq default_tuner_gpio[] = { - {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, - {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10}, - {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Mute/unmute */ -static struct em28xx_reg_seq compro_unmute_tv_gpio[] = { - {EM28XX_R08_GPIO, 5, 7, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq compro_unmute_svid_gpio[] = { - {EM28XX_R08_GPIO, 4, 7, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq compro_mute_gpio[] = { - {EM28XX_R08_GPIO, 6, 7, 10}, - { -1, -1, -1, -1}, -}; - -/* Terratec AV350 */ -static struct em28xx_reg_seq terratec_av350_mute_gpio[] = { - {EM28XX_R08_GPIO, 0xff, 0x7f, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { - {EM28XX_R08_GPIO, 0xff, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq silvercrest_reg_seq[] = { - {EM28XX_R08_GPIO, 0xff, 0xff, 10}, - {EM28XX_R08_GPIO, 0x01, 0xf7, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq vc211a_enable[] = { - {EM28XX_R08_GPIO, 0xff, 0x07, 10}, - {EM28XX_R08_GPIO, 0xff, 0x0f, 10}, - {EM28XX_R08_GPIO, 0xff, 0x0b, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq dikom_dk300_digital[] = { - {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, - {EM2880_R04_GPO, 0x08, 0xff, 10}, - { -1, -1, -1, -1}, -}; - - -/* Reset for the most [digital] boards */ -static struct em28xx_reg_seq leadership_digital[] = { - {EM2874_R80_GPIO, 0x70, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -static struct em28xx_reg_seq leadership_reset[] = { - {EM2874_R80_GPIO, 0xf0, 0xff, 10}, - {EM2874_R80_GPIO, 0xb0, 0xff, 10}, - {EM2874_R80_GPIO, 0xf0, 0xff, 10}, - { -1, -1, -1, -1}, -}; - - -/* - * Board definitions - */ -struct em28xx_board em28xx_boards[] = { - [EM2750_BOARD_UNKNOWN] = { - .name = "EM2710/EM2750/EM2751 webcam grabber", - .xclk = EM28XX_XCLK_FREQUENCY_20MHZ, - .tuner_type = TUNER_ABSENT, - .is_webcam = 1, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = silvercrest_reg_seq, - } }, - }, - [EM2800_BOARD_UNKNOWN] = { - .name = "Unknown EM2800 video grabber", - .is_em2800 = 1, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .tuner_type = TUNER_ABSENT, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_UNKNOWN] = { - .name = "Unknown EM2750/28xx video grabber", - .tuner_type = TUNER_ABSENT, - .is_webcam = 1, /* To enable sensor probe */ - }, - [EM2750_BOARD_DLCW_130] = { - /* Beijing Huaqi Information Digital Technology Co., Ltd */ - .name = "Huaqi DLCW-130", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .xclk = EM28XX_XCLK_FREQUENCY_48MHZ, - .tuner_type = TUNER_ABSENT, - .is_webcam = 1, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = EM28XX_AMUX_VIDEO, - } }, - }, - [EM2820_BOARD_KWORLD_PVRTV2800RF] = { - .name = "Kworld PVR TV 2800 RF", - .tuner_type = TUNER_TEMIC_PAL, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_GADMEI_TVR200] = { - .name = "Gadmei TVR200", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_TERRATEC_CINERGY_250] = { - .name = "Terratec Cinergy 250 USB", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .has_ir_i2c = 1, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_PINNACLE_USB_2] = { - .name = "Pinnacle PCTV USB 2", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .has_ir_i2c = 1, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = { - .name = "Hauppauge WinTV USB 2", - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .decoder = EM28XX_TVP5150, - .has_msp34xx = 1, - .has_ir_i2c = 1, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = MSP_INPUT_DEFAULT, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), - } }, - }, - [EM2820_BOARD_DLINK_USB_TV] = { - .name = "D-Link DUB-T210 TV Tuner", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_HERCULES_SMART_TV_USB2] = { - .name = "Hercules Smart TV USB 2.0", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = { - .name = "Pinnacle PCTV USB 2 (Philips FM1216ME)", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_GADMEI_UTV310] = { - .name = "Gadmei UTV310", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_TNF_5335MF, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = { - .name = "Leadtek Winfast USB II Deluxe", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .has_ir_i2c = 1, - .tvaudio_addr = 0x58, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT2_ACTIVE | - TDA9887_QSS, - .decoder = EM28XX_SAA711X, - .adecoder = EM28XX_TVAUDIO, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE4, - .amux = EM28XX_AMUX_AUX, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE5, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - .radio = { - .type = EM28XX_RADIO, - .amux = EM28XX_AMUX_AUX, - } - }, - [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { - .name = "Videology 20K14XUSB USB2.0", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, - .is_webcam = 1, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = EM28XX_AMUX_VIDEO, - } }, - }, - [EM2820_BOARD_SILVERCREST_WEBCAM] = { - .name = "Silvercrest Webcam 1.3mpix", - .tuner_type = TUNER_ABSENT, - .is_webcam = 1, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = silvercrest_reg_seq, - } }, - }, - [EM2821_BOARD_SUPERCOMP_USB_2] = { - .name = "Supercomp USB 2.0 TV", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2821_BOARD_USBGEAR_VD204] = { - .name = "Usbgear VD204v9", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, /* Capture only device */ - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2860_BOARD_NETGMBH_CAM] = { - /* Beijing Huaqi Information Digital Technology Co., Ltd */ - .name = "NetGMBH Cam", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, - .is_webcam = 1, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = EM28XX_AMUX_VIDEO, - } }, - }, - [EM2860_BOARD_TYPHOON_DVD_MAKER] = { - .name = "Typhoon DVD Maker", - .decoder = EM28XX_SAA711X, - .tuner_type = TUNER_ABSENT, /* Capture only device */ - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2860_BOARD_GADMEI_UTV330] = { - .name = "Gadmei UTV330", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_TNF_5335MF, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2861_BOARD_GADMEI_UTV330PLUS] = { - .name = "Gadmei UTV330+", - .tuner_type = TUNER_TNF_5335MF, - .tda9887_conf = TDA9887_PRESENT, - .ir_codes = RC_MAP_GADMEI_RM008Z, - .decoder = EM28XX_SAA711X, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2860_BOARD_TERRATEC_HYBRID_XS] = { - .name = "Terratec Cinergy A Hybrid XS", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2861_BOARD_KWORLD_PVRTV_300U] = { - .name = "KWorld PVRTV 300U", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = { - .name = "Yakumo MovieMixer", - .tuner_type = TUNER_ABSENT, /* Capture only device */ - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2860_BOARD_TVP5150_REFERENCE_DESIGN] = { - .name = "EM2860/TVP5150 Reference Design", - .tuner_type = TUNER_ABSENT, /* Capture only device */ - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2861_BOARD_PLEXTOR_PX_TV100U] = { - .name = "Plextor ConvertX PX-TV100U", - .tuner_type = TUNER_TNF_5335MF, - .xclk = EM28XX_XCLK_I2S_MSB_TIMING | - EM28XX_XCLK_FREQUENCY_12MHZ, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_TVP5150, - .has_msp34xx = 1, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = pinnacle_hybrid_pro_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = pinnacle_hybrid_pro_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = pinnacle_hybrid_pro_analog, - } }, - }, - - /* Those boards with em2870 are DVB Only*/ - - [EM2870_BOARD_TERRATEC_XS] = { - .name = "Terratec Cinergy T XS", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - }, - [EM2870_BOARD_TERRATEC_XS_MT2060] = { - .name = "Terratec Cinergy T XS (MT2060)", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, /* MT2060 */ - }, - [EM2870_BOARD_KWORLD_350U] = { - .name = "Kworld 350 U DVB-T", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - }, - [EM2870_BOARD_KWORLD_355U] = { - .name = "Kworld 355 U DVB-T", - .valid = EM28XX_BOARD_NOT_VALIDATED, - }, - [EM2870_BOARD_PINNACLE_PCTV_DVB] = { - .name = "Pinnacle PCTV DVB-T", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, /* MT2060 */ - /* djh - I have serious doubts this is right... */ - .xclk = EM28XX_XCLK_IR_RC5_MODE | - EM28XX_XCLK_FREQUENCY_10MHZ, - }, - [EM2870_BOARD_COMPRO_VIDEOMATE] = { - .name = "Compro, VideoMate U3", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, /* MT2060 */ - }, - - [EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = { - .name = "Terratec Hybrid XS Secam", - .has_msp34xx = 1, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .has_dvb = 1, - .dvb_gpio = terratec_cinergy_USB_XS_FR_digital, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = terratec_cinergy_USB_XS_FR_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = terratec_cinergy_USB_XS_FR_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = terratec_cinergy_USB_XS_FR_analog, - } }, - }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { - .name = "Hauppauge WinTV HVR 900", - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .mts_firmware = 1, - .has_dvb = 1, - .dvb_gpio = hauppauge_wintv_hvr_900_digital, - .ir_codes = RC_MAP_HAUPPAUGE, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = { - .name = "Hauppauge WinTV HVR 900 (R2)", - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .mts_firmware = 1, - .ir_codes = RC_MAP_HAUPPAUGE, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850] = { - .name = "Hauppauge WinTV HVR 850", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .mts_firmware = 1, - .has_dvb = 1, - .dvb_gpio = hauppauge_wintv_hvr_900_digital, - .ir_codes = RC_MAP_HAUPPAUGE, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { - .name = "Hauppauge WinTV HVR 950", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .mts_firmware = 1, - .has_dvb = 1, - .dvb_gpio = hauppauge_wintv_hvr_900_digital, - .ir_codes = RC_MAP_HAUPPAUGE, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { - .name = "Pinnacle PCTV HD Pro Stick", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .mts_firmware = 1, - .has_dvb = 1, - .dvb_gpio = hauppauge_wintv_hvr_900_digital, - .ir_codes = RC_MAP_PINNACLE_PCTV_HD, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { - .name = "AMD ATI TV Wonder HD 600", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .mts_firmware = 1, - .has_dvb = 1, - .dvb_gpio = hauppauge_wintv_hvr_900_digital, - .ir_codes = RC_MAP_ATI_TV_WONDER_HD_600, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2880_BOARD_TERRATEC_HYBRID_XS] = { - .name = "Terratec Hybrid XS", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .has_dvb = 1, - .dvb_gpio = default_digital, - .ir_codes = RC_MAP_TERRATEC_CINERGY_XS, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */ - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = default_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, - } }, - }, - /* maybe there's a reason behind it why Terratec sells the Hybrid XS - as Prodigy XS with a different PID, let's keep it separated for now - maybe we'll need it lateron */ - [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { - .name = "Terratec Prodigy XS", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2820_BOARD_MSI_VOX_USB_2] = { - .name = "MSI VOX USB 2.0", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .max_range_640_480 = 1, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE4, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2800_BOARD_TERRATEC_CINERGY_200] = { - .name = "Terratec Cinergy 200 USB", - .is_em2800 = 1, - .has_ir_i2c = 1, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2800_BOARD_GRABBEEX_USB2800] = { - .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder", - .is_em2800 = 1, - .decoder = EM28XX_SAA711X, - .tuner_type = TUNER_ABSENT, /* capture only board */ - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2800_BOARD_VC211A] = { - .name = "Actionmaster/LinXcel/Digitus VC211A", - .is_em2800 = 1, - .tuner_type = TUNER_ABSENT, /* Capture-only board */ - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = vc211a_enable, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = vc211a_enable, - } }, - }, - [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { - .name = "Leadtek Winfast USB II", - .is_em2800 = 1, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2800_BOARD_KWORLD_USB2800] = { - .name = "Kworld USB2800", - .is_em2800 = 1, - .tuner_type = TUNER_PHILIPS_FCV1236D, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_PINNACLE_DVC_90] = { - .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker " - "/ Kworld DVD Maker 2", - .tuner_type = TUNER_ABSENT, /* capture only board */ - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2800_BOARD_VGEAR_POCKETTV] = { - .name = "V-Gear PocketTV", - .is_em2800 = 1, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2] = { - .name = "Pixelview PlayTV Box 4 USB 2.0", - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_YMEC_TVF_5533MF, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - .aout = EM28XX_AOUT_MONO | /* I2S */ - EM28XX_AOUT_MASTER, /* Line out pin */ - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { - .name = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0", - .has_snapshot_button = 1, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_YMEC_TVF_5533MF, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - .aout = EM28XX_AOUT_MONO | /* I2S */ - EM28XX_AOUT_MASTER, /* Line out pin */ - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = { - .name = "EM2860/SAA711X Reference Design", - .has_snapshot_button = 1, - .tuner_type = TUNER_ABSENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - } }, - }, - - [EM2874_LEADERSHIP_ISDBT] = { - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | - EM28XX_I2C_FREQ_100_KHZ, - .xclk = EM28XX_XCLK_FREQUENCY_10MHZ, - .name = "EM2874 Leadership ISDBT", - .tuner_type = TUNER_ABSENT, - .tuner_gpio = leadership_reset, - .dvb_gpio = leadership_digital, - .has_dvb = 1, - }, - - [EM2880_BOARD_MSI_DIGIVOX_AD] = { - .name = "MSI DigiVox A/D", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = em2880_msi_digivox_ad_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = em2880_msi_digivox_ad_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = em2880_msi_digivox_ad_analog, - } }, - }, - [EM2880_BOARD_MSI_DIGIVOX_AD_II] = { - .name = "MSI DigiVox A/D II", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = em2880_msi_digivox_ad_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = em2880_msi_digivox_ad_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = em2880_msi_digivox_ad_analog, - } }, - }, - [EM2880_BOARD_KWORLD_DVB_305U] = { - .name = "KWorld DVB-T 305U", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2880_BOARD_KWORLD_DVB_310U] = { - .name = "KWorld DVB-T 310U", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .has_dvb = 1, - .dvb_gpio = default_digital, - .mts_firmware = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = default_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, - }, { /* S-video has not been tested yet */ - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, - } }, - }, - [EM2882_BOARD_KWORLD_ATSC_315U] = { - .name = "KWorld ATSC 315U HDTV TV Box", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_THOMSON_DTT761X, - .tuner_gpio = em2882_kworld_315u_tuner_gpio, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA711X, - .has_dvb = 1, - .dvb_gpio = em2882_kworld_315u_digital, - .ir_codes = RC_MAP_KWORLD_315U, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE, - /* Analog mode - still not ready */ - /*.input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_VIDEO, - .gpio = em2882_kworld_315u_analog, - .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = em2882_kworld_315u_analog1, - .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = em2882_kworld_315u_analog1, - .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, - } }, */ - }, - [EM2880_BOARD_EMPIRE_DUAL_TV] = { - .name = "Empire dual TV", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .has_dvb = 1, - .dvb_gpio = default_digital, - .mts_firmware = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = default_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, - } }, - }, - [EM2881_BOARD_DNT_DA2_HYBRID] = { - .name = "DNT DA2 Hybrid", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = default_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, - } }, - }, - [EM2881_BOARD_PINNACLE_HYBRID_PRO] = { - .name = "Pinnacle Hybrid Pro", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .has_dvb = 1, - .dvb_gpio = pinnacle_hybrid_pro_digital, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = pinnacle_hybrid_pro_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = pinnacle_hybrid_pro_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = pinnacle_hybrid_pro_analog, - } }, - }, - [EM2882_BOARD_PINNACLE_HYBRID_PRO] = { - .name = "Pinnacle Hybrid Pro (2)", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .mts_firmware = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2882_BOARD_KWORLD_VS_DVBT] = { - .name = "Kworld VS-DVB-T 323UR", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .mts_firmware = 1, - .has_dvb = 1, - .dvb_gpio = kworld_330u_digital, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */ - .ir_codes = RC_MAP_KWORLD_315U, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2882_BOARD_TERRATEC_HYBRID_XS] = { - .name = "Terratec Cinnergy Hybrid T USB XS (em2882)", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .mts_firmware = 1, - .decoder = EM28XX_TVP5150, - .has_dvb = 1, - .dvb_gpio = hauppauge_wintv_hvr_900_digital, - .ir_codes = RC_MAP_TERRATEC_CINERGY_XS, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, - } }, - }, - [EM2882_BOARD_DIKOM_DK300] = { - .name = "Dikom DK300", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .mts_firmware = 1, - .has_dvb = 1, - .dvb_gpio = dikom_dk300_digital, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = default_analog, - } }, - }, - [EM2883_BOARD_KWORLD_HYBRID_330U] = { - .name = "Kworld PlusTV HD Hybrid 330", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .mts_firmware = 1, - .has_dvb = 1, - .dvb_gpio = kworld_330u_digital, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | - EM28XX_I2C_EEPROM_ON_BOARD | - EM28XX_I2C_EEPROM_KEY_VALID, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = kworld_330u_analog, - .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = kworld_330u_analog, - .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = kworld_330u_analog, - } }, - }, - [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { - .name = "Compro VideoMate ForYou/Stereo", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tvaudio_addr = 0xb0, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_TVP5150, - .adecoder = EM28XX_TVAUDIO, - .mute_gpio = compro_mute_gpio, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = compro_unmute_tv_gpio, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = compro_unmute_svid_gpio, - } }, - }, - [EM2860_BOARD_KAIOMY_TVNPC_U2] = { - .name = "Kaiomy TVnPC U2", - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .tuner_addr = 0x61, - .mts_firmware = 1, - .decoder = EM28XX_TVP5150, - .tuner_gpio = default_tuner_gpio, - .ir_codes = RC_MAP_KAIOMY, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - } }, - .radio = { - .type = EM28XX_RADIO, - .amux = EM28XX_AMUX_LINE_IN, - } - }, - [EM2860_BOARD_EASYCAP] = { - .name = "Easy Cap Capture DC-60", - .vchannels = 2, - .tuner_type = TUNER_ABSENT, - .decoder = EM28XX_SAA711X, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2820_BOARD_IODATA_GVMVP_SZ] = { - .name = "IO-DATA GV-MVP/SZ", - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tuner_gpio = default_tuner_gpio, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - }, { /* Composite has not been tested yet */ - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_VIDEO, - }, { /* S-video has not been tested yet */ - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_VIDEO, - } }, - }, - [EM2860_BOARD_TERRATEC_GRABBY] = { - .name = "Terratec Grabby", - .vchannels = 2, - .tuner_type = TUNER_ABSENT, - .decoder = EM28XX_SAA711X, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2860_BOARD_TERRATEC_AV350] = { - .name = "Terratec AV350", - .vchannels = 2, - .tuner_type = TUNER_ABSENT, - .decoder = EM28XX_TVP5150, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, - .mute_gpio = terratec_av350_mute_gpio, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AUDIO_SRC_LINE, - .gpio = terratec_av350_unmute_gpio, - - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AUDIO_SRC_LINE, - .gpio = terratec_av350_unmute_gpio, - } }, - }, - - [EM2860_BOARD_ELGATO_VIDEO_CAPTURE] = { - .name = "Elgato Video Capture", - .decoder = EM28XX_SAA711X, - .tuner_type = TUNER_ABSENT, /* Capture only device */ - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - - [EM2882_BOARD_EVGA_INDTUBE] = { - .name = "Evga inDtube", - .tuner_type = TUNER_XC2028, - .tuner_gpio = default_tuner_gpio, - .decoder = EM28XX_TVP5150, - .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */ - .mts_firmware = 1, - .has_dvb = 1, - .dvb_gpio = evga_indtube_digital, - .ir_codes = RC_MAP_EVGA_INDTUBE, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_VIDEO, - .gpio = evga_indtube_analog, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = evga_indtube_analog, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - .gpio = evga_indtube_analog, - } }, - }, - /* eb1a:2868 Empia EM2870 + Philips CU1216L NIM (Philips TDA10023 + - Infineon TUA6034) */ - [EM2870_BOARD_REDDO_DVB_C_USB_BOX] = { - .name = "Reddo DVB-C USB TV Box", - .tuner_type = TUNER_ABSENT, - .tuner_gpio = reddo_dvb_c_usb_box, - .has_dvb = 1, - }, - /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold - * initially as the KWorld PlusTV 340U, then as the UB435-Q. - * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */ - [EM2870_BOARD_KWORLD_A340] = { - .name = "KWorld PlusTV 340U or UB435-Q (ATSC)", - .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */ - .has_dvb = 1, - .dvb_gpio = kworld_a340_digital, - .tuner_gpio = default_tuner_gpio, - }, -}; -const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); - -/* table of devices that work with this driver */ -struct usb_device_id em28xx_id_table[] = { - { USB_DEVICE(0xeb1a, 0x2750), - .driver_info = EM2750_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2751), - .driver_info = EM2750_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2800), - .driver_info = EM2800_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2710), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2820), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2821), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2860), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2861), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2862), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2863), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2870), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2881), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2883), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2868), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2875), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0xe300), - .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U }, - { USB_DEVICE(0xeb1a, 0xe303), - .driver_info = EM2860_BOARD_KAIOMY_TVNPC_U2 }, - { USB_DEVICE(0xeb1a, 0xe305), - .driver_info = EM2880_BOARD_KWORLD_DVB_305U }, - { USB_DEVICE(0xeb1a, 0xe310), - .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD }, - { USB_DEVICE(0xeb1a, 0xa313), - .driver_info = EM2882_BOARD_KWORLD_ATSC_315U }, - { USB_DEVICE(0xeb1a, 0xa316), - .driver_info = EM2883_BOARD_KWORLD_HYBRID_330U }, - { USB_DEVICE(0xeb1a, 0xe320), - .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD_II }, - { USB_DEVICE(0xeb1a, 0xe323), - .driver_info = EM2882_BOARD_KWORLD_VS_DVBT }, - { USB_DEVICE(0xeb1a, 0xe350), - .driver_info = EM2870_BOARD_KWORLD_350U }, - { USB_DEVICE(0xeb1a, 0xe355), - .driver_info = EM2870_BOARD_KWORLD_355U }, - { USB_DEVICE(0xeb1a, 0x2801), - .driver_info = EM2800_BOARD_GRABBEEX_USB2800 }, - { USB_DEVICE(0xeb1a, 0xe357), - .driver_info = EM2870_BOARD_KWORLD_355U }, - { USB_DEVICE(0x1b80, 0xe302), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */ - { USB_DEVICE(0x1b80, 0xe304), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kworld DVD Maker 2 */ - { USB_DEVICE(0x0ccd, 0x0036), - .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, - { USB_DEVICE(0x0ccd, 0x004c), - .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS_FR }, - { USB_DEVICE(0x0ccd, 0x004f), - .driver_info = EM2860_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x005e), - .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x0042), - .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x0043), - .driver_info = EM2870_BOARD_TERRATEC_XS }, - { USB_DEVICE(0x0ccd, 0x0047), - .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, - { USB_DEVICE(0x0ccd, 0x0084), - .driver_info = EM2860_BOARD_TERRATEC_AV350 }, - { USB_DEVICE(0x0ccd, 0x0096), - .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, - { USB_DEVICE(0x0fd9, 0x0033), - .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, - { USB_DEVICE(0x185b, 0x2870), - .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, - { USB_DEVICE(0x185b, 0x2041), - .driver_info = EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU }, - { USB_DEVICE(0x2040, 0x4200), - .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2040, 0x4201), - .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2040, 0x6500), - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, - { USB_DEVICE(0x2040, 0x6502), - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 }, - { USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */ - .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */ - .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */ - .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x2040, 0x651f), - .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, - { USB_DEVICE(0x0438, 0xb002), - .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, - { USB_DEVICE(0x2001, 0xf112), - .driver_info = EM2820_BOARD_DLINK_USB_TV }, - { USB_DEVICE(0x2304, 0x0207), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2304, 0x0208), - .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, - { USB_DEVICE(0x2304, 0x021a), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2304, 0x0226), - .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO }, - { USB_DEVICE(0x2304, 0x0227), - .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, - { USB_DEVICE(0x0413, 0x6023), - .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, - { USB_DEVICE(0x093b, 0xa005), - .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U }, - { USB_DEVICE(0x04bb, 0x0515), - .driver_info = EM2820_BOARD_IODATA_GVMVP_SZ }, - { USB_DEVICE(0xeb1a, 0x50a6), - .driver_info = EM2860_BOARD_GADMEI_UTV330 }, - { USB_DEVICE(0x1b80, 0xa340), - .driver_info = EM2870_BOARD_KWORLD_A340 }, - { }, -}; -MODULE_DEVICE_TABLE(usb, em28xx_id_table); - -/* - * EEPROM hash table for devices with generic USB IDs - */ -static struct em28xx_hash_table em28xx_eeprom_hash[] = { - /* P/N: SA 60002070465 Tuner: TVF7533-MF */ - {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, - {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF}, - {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028}, - {0x166a0441, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028}, - {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028}, - {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028}, - {0x63f653bd, EM2870_BOARD_REDDO_DVB_C_USB_BOX, TUNER_ABSENT}, - {0x4e913442, EM2882_BOARD_DIKOM_DK300, TUNER_XC2028}, -}; - -/* I2C devicelist hash table for devices with generic USB IDs */ -static struct em28xx_hash_table em28xx_i2c_hash[] = { - {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, - {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, - {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT}, - {0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT}, - {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC}, - {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF}, - {0x6b800080, EM2874_LEADERSHIP_ISDBT, TUNER_ABSENT}, -}; - -/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ -static unsigned short saa711x_addrs[] = { - 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ - 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ - I2C_CLIENT_END }; - -static unsigned short tvp5150_addrs[] = { - 0xb8 >> 1, - 0xba >> 1, - I2C_CLIENT_END -}; - -static unsigned short msp3400_addrs[] = { - 0x80 >> 1, - 0x88 >> 1, - I2C_CLIENT_END -}; - -int em28xx_tuner_callback(void *ptr, int component, int command, int arg) -{ - int rc = 0; - struct em28xx *dev = ptr; - - if (dev->tuner_type != TUNER_XC2028) - return 0; - - if (command != XC2028_TUNER_RESET) - return 0; - - rc = em28xx_gpio_set(dev, dev->board.tuner_gpio); - - return rc; -} -EXPORT_SYMBOL_GPL(em28xx_tuner_callback); - -static inline void em28xx_set_model(struct em28xx *dev) -{ - memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board)); - - /* Those are the default values for the majority of boards - Use those values if not specified otherwise at boards entry - */ - if (!dev->board.xclk) - dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE | - EM28XX_XCLK_FREQUENCY_12MHZ; - - if (!dev->board.i2c_speed) - dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | - EM28XX_I2C_FREQ_100_KHZ; -} - - -/* FIXME: Should be replaced by a proper mt9m111 driver */ -static int em28xx_initialize_mt9m111(struct em28xx *dev) -{ - int i; - unsigned char regs[][3] = { - { 0x0d, 0x00, 0x01, }, /* reset and use defaults */ - { 0x0d, 0x00, 0x00, }, - { 0x0a, 0x00, 0x21, }, - { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */ - }; - - for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client, ®s[i][0], 3); - - return 0; -} - - -/* FIXME: Should be replaced by a proper mt9m001 driver */ -static int em28xx_initialize_mt9m001(struct em28xx *dev) -{ - int i; - unsigned char regs[][3] = { - { 0x0d, 0x00, 0x01, }, - { 0x0d, 0x00, 0x00, }, - { 0x04, 0x05, 0x00, }, /* hres = 1280 */ - { 0x03, 0x04, 0x00, }, /* vres = 1024 */ - { 0x20, 0x11, 0x00, }, - { 0x06, 0x00, 0x10, }, - { 0x2b, 0x00, 0x24, }, - { 0x2e, 0x00, 0x24, }, - { 0x35, 0x00, 0x24, }, - { 0x2d, 0x00, 0x20, }, - { 0x2c, 0x00, 0x20, }, - { 0x09, 0x0a, 0xd4, }, - { 0x35, 0x00, 0x57, }, - }; - - for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client, ®s[i][0], 3); - - return 0; -} - -/* HINT method: webcam I2C chips - * - * This method works for webcams with Micron sensors - */ -static int em28xx_hint_sensor(struct em28xx *dev) -{ - int rc; - char *sensor_name; - unsigned char cmd; - __be16 version_be; - u16 version; - - /* Micron sensor detection */ - dev->i2c_client.addr = 0xba >> 1; - cmd = 0; - i2c_master_send(&dev->i2c_client, &cmd, 1); - rc = i2c_master_recv(&dev->i2c_client, (char *)&version_be, 2); - if (rc != 2) - return -EINVAL; - - version = be16_to_cpu(version_be); - switch (version) { - case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */ - case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ - dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; - em28xx_set_model(dev); - - sensor_name = "mt9v011"; - dev->em28xx_sensor = EM28XX_MT9V011; - dev->sensor_xres = 640; - dev->sensor_yres = 480; - /* - * FIXME: mt9v011 uses I2S speed as xtal clk - at least with - * the Silvercrest cam I have here for testing - for higher - * resolutions, a high clock cause horizontal artifacts, so we - * need to use a lower xclk frequency. - * Yet, it would be possible to adjust xclk depending on the - * desired resolution, since this affects directly the - * frame rate. - */ - dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; - dev->sensor_xtal = 4300000; - - /* probably means GRGB 16 bit bayer */ - dev->vinmode = 0x0d; - dev->vinctl = 0x00; - - break; - - case 0x143a: /* MT9M111 as found in the ECS G200 */ - dev->model = EM2750_BOARD_UNKNOWN; - em28xx_set_model(dev); - - sensor_name = "mt9m111"; - dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; - dev->em28xx_sensor = EM28XX_MT9M111; - em28xx_initialize_mt9m111(dev); - dev->sensor_xres = 640; - dev->sensor_yres = 512; - - dev->vinmode = 0x0a; - dev->vinctl = 0x00; - - break; - - case 0x8431: - dev->model = EM2750_BOARD_UNKNOWN; - em28xx_set_model(dev); - - sensor_name = "mt9m001"; - dev->em28xx_sensor = EM28XX_MT9M001; - em28xx_initialize_mt9m001(dev); - dev->sensor_xres = 1280; - dev->sensor_yres = 1024; - - /* probably means BGGR 16 bit bayer */ - dev->vinmode = 0x0c; - dev->vinctl = 0x00; - - break; - default: - printk("Unknown Micron Sensor 0x%04x\n", version); - return -EINVAL; - } - - /* Setup webcam defaults */ - em28xx_pre_card_setup(dev); - - em28xx_errdev("Sensor is %s, using model %s entry.\n", - sensor_name, em28xx_boards[dev->model].name); - - return 0; -} - -/* Since em28xx_pre_card_setup() requires a proper dev->model, - * this won't work for boards with generic PCI IDs - */ -void em28xx_pre_card_setup(struct em28xx *dev) -{ - /* Set the initial XCLK and I2C clock values based on the board - definition */ - em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f); - em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); - msleep(50); - - /* request some modules */ - switch (dev->model) { - case EM2861_BOARD_PLEXTOR_PX_TV100U: - /* Sets the msp34xx I2S speed */ - dev->i2s_speed = 2048000; - break; - case EM2861_BOARD_KWORLD_PVRTV_300U: - case EM2880_BOARD_KWORLD_DVB_305U: - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x6d); - msleep(10); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x7d); - msleep(10); - break; - case EM2870_BOARD_COMPRO_VIDEOMATE: - /* TODO: someone can do some cleanup here... - not everything's needed */ - em28xx_write_reg(dev, EM2880_R04_GPO, 0x00); - msleep(10); - em28xx_write_reg(dev, EM2880_R04_GPO, 0x01); - msleep(10); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); - mdelay(70); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc); - mdelay(70); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xdc); - mdelay(70); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc); - mdelay(70); - break; - case EM2870_BOARD_TERRATEC_XS_MT2060: - /* this device needs some gpio writes to get the DVB-T - demod work */ - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); - mdelay(70); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde); - mdelay(70); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); - mdelay(70); - break; - case EM2870_BOARD_PINNACLE_PCTV_DVB: - /* this device needs some gpio writes to get the - DVB-T demod work */ - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); - mdelay(70); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde); - mdelay(70); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); - mdelay(70); - break; - case EM2820_BOARD_GADMEI_UTV310: - case EM2820_BOARD_MSI_VOX_USB_2: - /* enables audio for that devices */ - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); - break; - - case EM2882_BOARD_KWORLD_ATSC_315U: - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); - msleep(10); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); - msleep(10); - em28xx_write_reg(dev, EM2880_R04_GPO, 0x00); - msleep(10); - em28xx_write_reg(dev, EM2880_R04_GPO, 0x08); - msleep(10); - break; - - case EM2860_BOARD_KAIOMY_TVNPC_U2: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - em28xx_write_regs(dev, 0x0d, "\x42", 1); - em28xx_write_regs(dev, 0x08, "\xfd", 1); - msleep(10); - em28xx_write_regs(dev, 0x08, "\xff", 1); - msleep(10); - em28xx_write_regs(dev, 0x08, "\x7f", 1); - msleep(10); - em28xx_write_regs(dev, 0x08, "\x6b", 1); - - break; - case EM2860_BOARD_EASYCAP: - em28xx_write_regs(dev, 0x08, "\xf8", 1); - break; - - case EM2820_BOARD_IODATA_GVMVP_SZ: - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); - msleep(70); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); - msleep(10); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); - msleep(70); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); - msleep(70); - break; - } - - em28xx_gpio_set(dev, dev->board.tuner_gpio); - em28xx_set_mode(dev, EM28XX_ANALOG_MODE); - - /* Unlock device */ - em28xx_set_mode(dev, EM28XX_SUSPEND); -} - -static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) -{ - memset(ctl, 0, sizeof(*ctl)); - - ctl->fname = XC2028_DEFAULT_FIRMWARE; - ctl->max_len = 64; - ctl->mts = em28xx_boards[dev->model].mts_firmware; - - switch (dev->model) { - case EM2880_BOARD_EMPIRE_DUAL_TV: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2882_BOARD_TERRATEC_HYBRID_XS: - ctl->demod = XC3028_FE_ZARLINK456; - break; - case EM2880_BOARD_TERRATEC_HYBRID_XS: - case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: - case EM2881_BOARD_PINNACLE_HYBRID_PRO: - ctl->demod = XC3028_FE_ZARLINK456; - break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - /* djh - Not sure which demod we need here */ - ctl->demod = XC3028_FE_DEFAULT; - break; - case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: - ctl->demod = XC3028_FE_DEFAULT; - ctl->fname = XC3028L_DEFAULT_FIRMWARE; - break; - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: - /* FIXME: Better to specify the needed IF */ - ctl->demod = XC3028_FE_DEFAULT; - break; - case EM2883_BOARD_KWORLD_HYBRID_330U: - case EM2882_BOARD_DIKOM_DK300: - case EM2882_BOARD_KWORLD_VS_DVBT: - ctl->demod = XC3028_FE_CHINA; - ctl->fname = XC2028_DEFAULT_FIRMWARE; - break; - case EM2882_BOARD_EVGA_INDTUBE: - ctl->demod = XC3028_FE_CHINA; - ctl->fname = XC3028L_DEFAULT_FIRMWARE; - break; - default: - ctl->demod = XC3028_FE_OREN538; - } -} - -static void em28xx_tuner_setup(struct em28xx *dev) -{ - struct tuner_setup tun_setup; - struct v4l2_frequency f; - - if (dev->tuner_type == TUNER_ABSENT) - return; - - memset(&tun_setup, 0, sizeof(tun_setup)); - - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.tuner_callback = em28xx_tuner_callback; - - if (dev->board.radio.type) { - tun_setup.type = dev->board.radio.type; - tun_setup.addr = dev->board.radio_addr; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); - } - - if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); - } - - if (dev->tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg); - } - - if (dev->tuner_type == TUNER_XC2028) { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); - memset(&ctl, 0, sizeof(ctl)); - - em28xx_setup_xc3028(dev, &ctl); - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg); - } - - /* configure tuner */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 9076; /* just a magic number */ - dev->ctl_freq = f.frequency; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); -} - -static int em28xx_hint_board(struct em28xx *dev) -{ - int i; - - /* HINT method: EEPROM - * - * This method works only for boards with eeprom. - * Uses a hash of all eeprom bytes. The hash should be - * unique for a vendor/tuner pair. - * There are a high chance that tuners for different - * video standards produce different hashes. - */ - for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) { - if (dev->hash == em28xx_eeprom_hash[i].hash) { - dev->model = em28xx_eeprom_hash[i].model; - dev->tuner_type = em28xx_eeprom_hash[i].tuner; - - em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, " - "based on eeprom hash.\n"); - em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, " - "please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List " - " \n"); - em28xx_errdev("Board detected as %s\n", - em28xx_boards[dev->model].name); - - return 0; - } - } - - /* HINT method: I2C attached devices - * - * This method works for all boards. - * Uses a hash of i2c scanned devices. - * Devices with the same i2c attached chips will - * be considered equal. - * This method is less precise than the eeprom one. - */ - - /* user did not request i2c scanning => do it now */ - if (!dev->i2c_hash) - em28xx_do_i2c_scan(dev); - - for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) { - if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { - dev->model = em28xx_i2c_hash[i].model; - dev->tuner_type = em28xx_i2c_hash[i].tuner; - em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, " - "based on i2c devicelist hash.\n"); - em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, " - "please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List " - " \n"); - em28xx_errdev("Board detected as %s\n", - em28xx_boards[dev->model].name); - - return 0; - } - } - - em28xx_errdev("Your board has no unique USB ID and thus need a " - "hint to be detected.\n"); - em28xx_errdev("You may try to use card= insmod option to " - "workaround that.\n"); - em28xx_errdev("Please send an email with this log to:\n"); - em28xx_errdev("\tV4L Mailing List \n"); - em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); - em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); - - em28xx_errdev("Here is a list of valid choices for the card=" - " insmod option:\n"); - for (i = 0; i < em28xx_bcount; i++) { - em28xx_errdev(" card=%d -> %s\n", - i, em28xx_boards[i].name); - } - return -1; -} - -/* ----------------------------------------------------------------------- */ -void em28xx_register_i2c_ir(struct em28xx *dev) -{ - /* Leadtek winfast tv USBII deluxe can find a non working IR-device */ - /* at address 0x18, so if that address is needed for another board in */ - /* the future, please put it after 0x1f. */ - struct i2c_board_info info; - const unsigned short addr_list[] = { - 0x1f, 0x30, 0x47, I2C_CLIENT_END - }; - - if (disable_ir) - return; - - memset(&info, 0, sizeof(struct i2c_board_info)); - memset(&dev->init_data, 0, sizeof(dev->init_data)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - - /* detect & configure */ - switch (dev->model) { - case EM2800_BOARD_TERRATEC_CINERGY_200: - case EM2820_BOARD_TERRATEC_CINERGY_250: - dev->init_data.ir_codes = RC_MAP_EM_TERRATEC; - dev->init_data.get_key = em28xx_get_key_terratec; - dev->init_data.name = "i2c IR (EM28XX Terratec)"; - break; - case EM2820_BOARD_PINNACLE_USB_2: - dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY; - dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey; - dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; - break; - case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - dev->init_data.ir_codes = RC_MAP_HAUPPAUGE; - dev->init_data.get_key = em28xx_get_key_em_haup; - dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; - break; - case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE: - dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE; - dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe; - dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)"; - break; - } - - if (dev->init_data.name) - info.platform_data = &dev->init_data; - i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL); -} - -void em28xx_card_setup(struct em28xx *dev) -{ - /* - * If the device can be a webcam, seek for a sensor. - * If sensor is not found, then it isn't a webcam. - */ - if (dev->board.is_webcam) { - if (em28xx_hint_sensor(dev) < 0) - dev->board.is_webcam = 0; - else - dev->progressive = 1; - } - - if (!dev->board.is_webcam) { - switch (dev->model) { - case EM2820_BOARD_UNKNOWN: - case EM2800_BOARD_UNKNOWN: - /* - * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD. - * - * This occurs because they share identical USB vendor and - * product IDs. - * - * What we do here is look up the EEPROM hash of the K-WORLD - * and if it is found then we decide that we do not have - * a DIGIVOX and reset the device to the K-WORLD instead. - * - * This solution is only valid if they do not share eeprom - * hash identities which has not been determined as yet. - */ - if (em28xx_hint_board(dev) < 0) - em28xx_errdev("Board not discovered\n"); - else { - em28xx_set_model(dev); - em28xx_pre_card_setup(dev); - } - break; - default: - em28xx_set_model(dev); - } - } - - em28xx_info("Identified as %s (card=%d)\n", - dev->board.name, dev->model); - - dev->tuner_type = em28xx_boards[dev->model].tuner_type; - if (em28xx_boards[dev->model].tuner_addr) - dev->tuner_addr = em28xx_boards[dev->model].tuner_addr; - - if (em28xx_boards[dev->model].tda9887_conf) - dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; - - /* request some modules */ - switch (dev->model) { - case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - { - struct tveeprom tv; -#if defined(CONFIG_MODULES) && defined(MODULE) - request_module("tveeprom"); -#endif - /* Call first TVeeprom */ - - dev->i2c_client.addr = 0xa0 >> 1; - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); - - dev->tuner_type = tv.tuner_type; - - if (tv.audio_processor == V4L2_IDENT_MSPX4XX) { - dev->i2s_speed = 2048000; - dev->board.has_msp34xx = 1; - } - break; - } - case EM2882_BOARD_KWORLD_ATSC_315U: - em28xx_write_reg(dev, 0x0d, 0x42); - msleep(10); - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); - msleep(10); - break; - case EM2820_BOARD_KWORLD_PVRTV2800RF: - /* GPIO enables sound on KWORLD PVR TV 2800RF */ - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9); - break; - case EM2820_BOARD_UNKNOWN: - case EM2800_BOARD_UNKNOWN: - /* - * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD. - * - * This occurs because they share identical USB vendor and - * product IDs. - * - * What we do here is look up the EEPROM hash of the K-WORLD - * and if it is found then we decide that we do not have - * a DIGIVOX and reset the device to the K-WORLD instead. - * - * This solution is only valid if they do not share eeprom - * hash identities which has not been determined as yet. - */ - case EM2880_BOARD_MSI_DIGIVOX_AD: - if (!em28xx_hint_board(dev)) - em28xx_set_model(dev); - - /* In cases where we had to use a board hint, the call to - em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, - so make the call now so the analog GPIOs are set properly - before probing the i2c bus. */ - em28xx_gpio_set(dev, dev->board.tuner_gpio); - em28xx_set_mode(dev, EM28XX_ANALOG_MODE); - break; - -/* - * The Dikom DK300 is detected as an Kworld VS-DVB-T 323UR. - * - * This occurs because they share identical USB vendor and - * product IDs. - * - * What we do here is look up the EEPROM hash of the Dikom - * and if it is found then we decide that we do not have - * a Kworld and reset the device to the Dikom instead. - * - * This solution is only valid if they do not share eeprom - * hash identities which has not been determined as yet. - */ - case EM2882_BOARD_KWORLD_VS_DVBT: - if (!em28xx_hint_board(dev)) - em28xx_set_model(dev); - - /* In cases where we had to use a board hint, the call to - em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, - so make the call now so the analog GPIOs are set properly - before probing the i2c bus. */ - em28xx_gpio_set(dev, dev->board.tuner_gpio); - em28xx_set_mode(dev, EM28XX_ANALOG_MODE); - break; - } - -#if defined(CONFIG_MODULES) && defined(MODULE) - if (dev->board.has_ir_i2c && !disable_ir) - request_module("ir-kbd-i2c"); -#endif - if (dev->board.has_snapshot_button) - em28xx_register_snapshot_button(dev); - - if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) { - em28xx_errdev("\n\n"); - em28xx_errdev("The support for this board weren't " - "valid yet.\n"); - em28xx_errdev("Please send a report of having this working\n"); - em28xx_errdev("not to V4L mailing list (and/or to other " - "addresses)\n\n"); - } - - /* Allow override tuner type by a module parameter */ - if (tuner >= 0) - dev->tuner_type = tuner; - - /* request some modules */ - if (dev->board.has_msp34xx) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "msp3400", 0, msp3400_addrs); - - if (dev->board.decoder == EM28XX_SAA711X) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "saa7115_auto", 0, saa711x_addrs); - - if (dev->board.decoder == EM28XX_TVP5150) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tvp5150", 0, tvp5150_addrs); - - if (dev->em28xx_sensor == EM28XX_MT9V011) { - struct mt9v011_platform_data pdata; - struct i2c_board_info mt9v011_info = { - .type = "mt9v011", - .addr = 0xba >> 1, - .platform_data = &pdata, - }; - struct v4l2_subdev *sd; - - pdata.xtal = dev->sensor_xtal; - sd = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap, - &mt9v011_info, NULL); - } - - - if (dev->board.adecoder == EM28XX_TVAUDIO) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tvaudio", dev->board.tvaudio_addr, NULL); - - if (dev->board.tuner_type != TUNER_ABSENT) { - int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); - - if (dev->board.radio.type) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tuner", dev->board.radio_addr, NULL); - - if (has_demod) - v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); - if (dev->tuner_addr == 0) { - enum v4l2_i2c_tuner_type type = - has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; - struct v4l2_subdev *sd; - - sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(type)); - - if (sd) - dev->tuner_addr = v4l2_i2c_subdev_addr(sd); - } else { - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tuner", dev->tuner_addr, NULL); - } - } - - em28xx_tuner_setup(dev); - - if(!disable_ir) - em28xx_ir_init(dev); -} - - -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - struct em28xx *dev = container_of(work, - struct em28xx, request_module_wk); - - if (dev->has_audio_class) - request_module("snd-usb-audio"); - else if (dev->has_alsa_audio) - request_module("em28xx-alsa"); - - if (dev->board.has_dvb) - request_module("em28xx-dvb"); -} - -static void request_modules(struct em28xx *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} - -static void flush_request_modules(struct em28xx *dev) -{ - flush_work_sync(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#define flush_request_modules(dev) -#endif /* CONFIG_MODULES */ - -/* - * em28xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -void em28xx_release_resources(struct em28xx *dev) -{ - if (dev->sbutton_input_dev) - em28xx_deregister_snapshot_button(dev); - - if (dev->ir) - em28xx_ir_fini(dev); - - /*FIXME: I2C IR should be disconnected */ - - em28xx_release_analog_resources(dev); - - em28xx_remove_from_devlist(dev); - - em28xx_i2c_unregister(dev); - - v4l2_device_unregister(&dev->v4l2_dev); - - usb_put_dev(dev->udev); - - /* Mark device as unused */ - em28xx_devused &= ~(1 << dev->devno); -}; - -/* - * em28xx_init_dev() - * allocates and inits the device structs, registers i2c bus and v4l device - */ -static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, - struct usb_interface *interface, - int minor) -{ - struct em28xx *dev = *devhandle; - int retval; - int errCode; - - dev->udev = udev; - mutex_init(&dev->ctrl_urb_lock); - spin_lock_init(&dev->slock); - init_waitqueue_head(&dev->open); - init_waitqueue_head(&dev->wait_frame); - init_waitqueue_head(&dev->wait_stream); - - dev->em28xx_write_regs = em28xx_write_regs; - dev->em28xx_read_reg = em28xx_read_reg; - dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; - dev->em28xx_write_regs_req = em28xx_write_regs_req; - dev->em28xx_read_reg_req = em28xx_read_reg_req; - dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800; - - em28xx_set_model(dev); - - /* Set the default GPO/GPIO for legacy devices */ - dev->reg_gpo_num = EM2880_R04_GPO; - dev->reg_gpio_num = EM28XX_R08_GPIO; - - dev->wait_after_write = 5; - - /* Based on the Chip ID, set the device configuration */ - retval = em28xx_read_reg(dev, EM28XX_R0A_CHIPID); - if (retval > 0) { - dev->chip_id = retval; - - switch (dev->chip_id) { - case CHIP_ID_EM2800: - em28xx_info("chip ID is em2800\n"); - break; - case CHIP_ID_EM2710: - em28xx_info("chip ID is em2710\n"); - break; - case CHIP_ID_EM2750: - em28xx_info("chip ID is em2750\n"); - break; - case CHIP_ID_EM2820: - em28xx_info("chip ID is em2820 (or em2710)\n"); - break; - case CHIP_ID_EM2840: - em28xx_info("chip ID is em2840\n"); - break; - case CHIP_ID_EM2860: - em28xx_info("chip ID is em2860\n"); - break; - case CHIP_ID_EM2870: - em28xx_info("chip ID is em2870\n"); - dev->wait_after_write = 0; - break; - case CHIP_ID_EM2874: - em28xx_info("chip ID is em2874\n"); - dev->reg_gpio_num = EM2874_R80_GPIO; - dev->wait_after_write = 0; - break; - case CHIP_ID_EM2883: - em28xx_info("chip ID is em2882/em2883\n"); - dev->wait_after_write = 0; - break; - default: - em28xx_info("em28xx chip ID = %d\n", dev->chip_id); - } - } - - /* Prepopulate cached GPO register content */ - retval = em28xx_read_reg(dev, dev->reg_gpo_num); - if (retval >= 0) - dev->reg_gpo = retval; - - em28xx_pre_card_setup(dev); - - if (!dev->board.is_em2800) { - /* Resets I2C speed */ - em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); - if (retval < 0) { - em28xx_errdev("%s: em28xx_write_regs_req failed!" - " retval [%d]\n", - __func__, retval); - return retval; - } - } - - retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); - if (retval < 0) { - em28xx_errdev("Call to v4l2_device_register() failed!\n"); - return retval; - } - - /* register i2c bus */ - errCode = em28xx_i2c_register(dev); - if (errCode < 0) { - v4l2_device_unregister(&dev->v4l2_dev); - em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* - * Default format, used for tvp5150 or saa711x output formats - */ - dev->vinmode = 0x10; - dev->vinctl = EM28XX_VINCTRL_INTERLACED | - EM28XX_VINCTRL_CCIR656_ENABLE; - - /* Do board specific init and eeprom reading */ - em28xx_card_setup(dev); - - /* Configure audio */ - errCode = em28xx_audio_setup(dev); - if (errCode < 0) { - v4l2_device_unregister(&dev->v4l2_dev); - em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n", - __func__, errCode); - } - - /* wake i2c devices */ - em28xx_wake_i2c(dev); - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - INIT_LIST_HEAD(&dev->vbiq.active); - INIT_LIST_HEAD(&dev->vbiq.queued); - - if (dev->board.has_msp34xx) { - /* Send a reset to other chips via gpio */ - errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_write_regs_req - " - "msp34xx(1) failed! errCode [%d]\n", - __func__, errCode); - return errCode; - } - msleep(3); - - errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_write_regs_req - " - "msp34xx(2) failed! errCode [%d]\n", - __func__, errCode); - return errCode; - } - msleep(3); - } - - em28xx_add_into_devlist(dev); - - retval = em28xx_register_analog_devices(dev); - if (retval < 0) { - em28xx_release_resources(dev); - goto fail_reg_devices; - } - - em28xx_init_extension(dev); - - /* Save some power by putting tuner to sleep */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); - - return 0; - -fail_reg_devices: - return retval; -} - -/* - * em28xx_usb_probe() - * checks for supported devices - */ -static int em28xx_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - const struct usb_endpoint_descriptor *endpoint; - struct usb_device *udev; - struct usb_interface *uif; - struct em28xx *dev = NULL; - int retval; - int i, nr, ifnum, isoc_pipe; - char *speed; - char descr[255] = ""; - - udev = usb_get_dev(interface_to_usbdev(interface)); - ifnum = interface->altsetting[0].desc.bInterfaceNumber; - - /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); - em28xx_devused |= 1<altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - em28xx_err(DRIVER_NAME " audio device (%04x:%04x): " - "interface %i, class %i\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - - em28xx_devused &= ~(1<cur_altsetting->endpoint[0].desc; - - /* check if the device has the iso in endpoint at the correct place */ - if (usb_endpoint_xfer_isoc(endpoint) - && - (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) { - /* It's a newer em2874/em2875 device */ - isoc_pipe = 0; - } else { - int check_interface = 1; - isoc_pipe = 1; - endpoint = &interface->cur_altsetting->endpoint[1].desc; - if (!usb_endpoint_xfer_isoc(endpoint)) - check_interface = 0; - - if (usb_endpoint_dir_out(endpoint)) - check_interface = 0; - - if (!check_interface) { - em28xx_err(DRIVER_NAME " video device (%04x:%04x): " - "interface %i, class %i found.\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - - em28xx_err(DRIVER_NAME " This is an anciliary " - "interface not used by the driver\n"); - - em28xx_devused &= ~(1<speed) { - case USB_SPEED_LOW: - speed = "1.5"; - break; - case USB_SPEED_UNKNOWN: - case USB_SPEED_FULL: - speed = "12"; - break; - case USB_SPEED_HIGH: - speed = "480"; - break; - default: - speed = "unknown"; - } - - if (udev->manufacturer) - strlcpy(descr, udev->manufacturer, sizeof(descr)); - - if (udev->product) { - if (*descr) - strlcat(descr, " ", sizeof(descr)); - strlcat(descr, udev->product, sizeof(descr)); - } - if (*descr) - strlcat(descr, " ", sizeof(descr)); - - printk(DRIVER_NAME ": New device %s@ %s Mbps " - "(%04x:%04x, interface %d, class %d)\n", - descr, - speed, - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting->desc.bInterfaceNumber); - - /* - * Make sure we have 480 Mbps of bandwidth, otherwise things like - * video stream wouldn't likely work, since 12 Mbps is generally - * not enough even for most Digital TV streams. - */ - if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - printk(DRIVER_NAME ": Device initialization failed.\n"); - printk(DRIVER_NAME ": Device must be connected to a high-speed" - " USB 2.0 port.\n"); - em28xx_devused &= ~(1<= EM28XX_MAXBOARDS) { - printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", - EM28XX_MAXBOARDS); - em28xx_devused &= ~(1<name, 29, "em28xx #%d", nr); - dev->devno = nr; - dev->model = id->driver_info; - dev->alt = -1; - - /* Checks if audio is provided by some interface */ - for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { - uif = udev->config->interface[i]; - if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - dev->has_audio_class = 1; - break; - } - } - - /* compute alternate max packet sizes */ - uif = udev->actconfig->interface[0]; - - dev->num_alt = uif->num_altsetting; - dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); - - if (dev->alt_max_pkt_size == NULL) { - em28xx_errdev("out of memory!\n"); - em28xx_devused &= ~(1<num_alt ; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); - dev->alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - } - - if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) - dev->model = card[nr]; - - /* allocate device struct */ - mutex_init(&dev->lock); - mutex_lock(&dev->lock); - retval = em28xx_init_dev(&dev, udev, interface, nr); - if (retval) { - em28xx_devused &= ~(1<devno); - mutex_unlock(&dev->lock); - kfree(dev); - goto err; - } - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - request_modules(dev); - - /* Should be the last thing to do, to avoid newer udev's to - open the device before fully initializing it - */ - mutex_unlock(&dev->lock); - - return 0; - -err: - return retval; -} - -/* - * em28xx_usb_disconnect() - * called when the device gets diconencted - * video device will be unregistered on v4l2_close in case it is still open - */ -static void em28xx_usb_disconnect(struct usb_interface *interface) -{ - struct em28xx *dev; - - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - if (!dev) - return; - - em28xx_info("disconnecting %s\n", dev->vdev->name); - - flush_request_modules(dev); - - /* wait until all current v4l2 io is finished then deallocate - resources */ - mutex_lock(&dev->lock); - - wake_up_interruptible_all(&dev->open); - - v4l2_device_disconnect(&dev->v4l2_dev); - - if (dev->users) { - em28xx_warn - ("device %s is open! Deregistration and memory " - "deallocation are deferred on close.\n", - video_device_node_name(dev->vdev)); - - dev->state |= DEV_MISCONFIGURED; - em28xx_uninit_isoc(dev); - dev->state |= DEV_DISCONNECTED; - wake_up_interruptible(&dev->wait_frame); - wake_up_interruptible(&dev->wait_stream); - } else { - dev->state |= DEV_DISCONNECTED; - em28xx_release_resources(dev); - } - - em28xx_close_extension(dev); - - mutex_unlock(&dev->lock); - - if (!dev->users) { - kfree(dev->alt_max_pkt_size); - kfree(dev); - } -} - -static struct usb_driver em28xx_usb_driver = { - .name = "em28xx", - .probe = em28xx_usb_probe, - .disconnect = em28xx_usb_disconnect, - .id_table = em28xx_id_table, -}; - -static int __init em28xx_module_init(void) -{ - int result; - - /* register this driver with the USB subsystem */ - result = usb_register(&em28xx_usb_driver); - if (result) - em28xx_err(DRIVER_NAME - " usb_register failed. Error number %d.\n", result); - - printk(KERN_INFO DRIVER_NAME " driver loaded\n"); - - return result; -} - -static void __exit em28xx_module_exit(void) -{ - /* deregister this driver with the USB subsystem */ - usb_deregister(&em28xx_usb_driver); -} - -module_init(em28xx_module_init); -module_exit(em28xx_module_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1237 +0,0 @@ -/* - em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "em28xx.h" - -/* #define ENABLE_DEBUG_ISOC_FRAMES */ - -static unsigned int core_debug; -module_param(core_debug, int, 0644); -MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); - -#define em28xx_coredbg(fmt, arg...) do {\ - if (core_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -static unsigned int reg_debug; -module_param(reg_debug, int, 0644); -MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); - -#define em28xx_regdbg(fmt, arg...) do {\ - if (reg_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -static int alt; -module_param(alt, int, 0644); -MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); - -static unsigned int disable_vbi; -module_param(disable_vbi, int, 0644); -MODULE_PARM_DESC(disable_vbi, "disable vbi support"); - -/* FIXME */ -#define em28xx_isocdbg(fmt, arg...) do {\ - if (core_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -/* - * em28xx_read_reg_req() - * reads data from the usb device specifying bRequest - */ -int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, - char *buf, int len) -{ - int ret; - int pipe = usb_rcvctrlpipe(dev->udev, 0); - - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - - if (len > URB_MAX_CTRL_SIZE) - return -EINVAL; - - if (reg_debug) { - printk(KERN_DEBUG "(pipe 0x%08x): " - "IN: %02x %02x %02x %02x %02x %02x %02x %02x ", - pipe, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - req, 0, 0, - reg & 0xff, reg >> 8, - len & 0xff, len >> 8); - } - - mutex_lock(&dev->ctrl_urb_lock); - ret = usb_control_msg(dev->udev, pipe, req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, dev->urb_buf, len, HZ); - if (ret < 0) { - if (reg_debug) - printk(" failed!\n"); - mutex_unlock(&dev->ctrl_urb_lock); - return ret; - } - - if (len) - memcpy(buf, dev->urb_buf, len); - - mutex_unlock(&dev->ctrl_urb_lock); - - if (reg_debug) { - int byte; - - printk("<<<"); - for (byte = 0; byte < len; byte++) - printk(" %02x", (unsigned char)buf[byte]); - printk("\n"); - } - - return ret; -} - -/* - * em28xx_read_reg_req() - * reads data from the usb device specifying bRequest - */ -int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg) -{ - int ret; - u8 val; - - ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1); - if (ret < 0) - return ret; - - return val; -} - -int em28xx_read_reg(struct em28xx *dev, u16 reg) -{ - return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg); -} - -/* - * em28xx_write_regs_req() - * sends data to the usb device, specifying bRequest - */ -int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, - int len) -{ - int ret; - int pipe = usb_sndctrlpipe(dev->udev, 0); - - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - - if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) - return -EINVAL; - - if (reg_debug) { - int byte; - - printk(KERN_DEBUG "(pipe 0x%08x): " - "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", - pipe, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - req, 0, 0, - reg & 0xff, reg >> 8, - len & 0xff, len >> 8); - - for (byte = 0; byte < len; byte++) - printk(" %02x", (unsigned char)buf[byte]); - printk("\n"); - } - - mutex_lock(&dev->ctrl_urb_lock); - memcpy(dev->urb_buf, buf, len); - ret = usb_control_msg(dev->udev, pipe, req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, dev->urb_buf, len, HZ); - mutex_unlock(&dev->ctrl_urb_lock); - - if (dev->wait_after_write) - msleep(dev->wait_after_write); - - return ret; -} - -int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len) -{ - int rc; - - rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len); - - /* Stores GPO/GPIO values at the cache, if changed - Only write values should be stored, since input on a GPIO - register will return the input bits. - Not sure what happens on reading GPO register. - */ - if (rc >= 0) { - if (reg == dev->reg_gpo_num) - dev->reg_gpo = buf[0]; - else if (reg == dev->reg_gpio_num) - dev->reg_gpio = buf[0]; - } - - return rc; -} - -/* Write a single register */ -int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val) -{ - return em28xx_write_regs(dev, reg, &val, 1); -} - -/* - * em28xx_write_reg_bits() - * sets only some bits (specified by bitmask) of a register, by first reading - * the actual value - */ -int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, - u8 bitmask) -{ - int oldval; - u8 newval; - - /* Uses cache for gpo/gpio registers */ - if (reg == dev->reg_gpo_num) - oldval = dev->reg_gpo; - else if (reg == dev->reg_gpio_num) - oldval = dev->reg_gpio; - else - oldval = em28xx_read_reg(dev, reg); - - if (oldval < 0) - return oldval; - - newval = (((u8) oldval) & ~bitmask) | (val & bitmask); - - return em28xx_write_regs(dev, reg, &newval, 1); -} - -/* - * em28xx_is_ac97_ready() - * Checks if ac97 is ready - */ -static int em28xx_is_ac97_ready(struct em28xx *dev) -{ - int ret, i; - - /* Wait up to 50 ms for AC97 command to complete */ - for (i = 0; i < 10; i++, msleep(5)) { - ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); - if (ret < 0) - return ret; - - if (!(ret & 0x01)) - return 0; - } - - em28xx_warn("AC97 command still being executed: not handled properly!\n"); - return -EBUSY; -} - -/* - * em28xx_read_ac97() - * write a 16 bit value to the specified AC97 address (LSB first!) - */ -int em28xx_read_ac97(struct em28xx *dev, u8 reg) -{ - int ret; - u8 addr = (reg & 0x7f) | 0x80; - u16 val; - - ret = em28xx_is_ac97_ready(dev); - if (ret < 0) - return ret; - - ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1); - if (ret < 0) - return ret; - - ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB, - (u8 *)&val, sizeof(val)); - - if (ret < 0) - return ret; - return le16_to_cpu(val); -} - -/* - * em28xx_write_ac97() - * write a 16 bit value to the specified AC97 address (LSB first!) - */ -int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val) -{ - int ret; - u8 addr = reg & 0x7f; - __le16 value; - - value = cpu_to_le16(val); - - ret = em28xx_is_ac97_ready(dev); - if (ret < 0) - return ret; - - ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2); - if (ret < 0) - return ret; - - ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1); - if (ret < 0) - return ret; - - return 0; -} - -struct em28xx_vol_table { - enum em28xx_amux mux; - u8 reg; -}; - -static struct em28xx_vol_table inputs[] = { - { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL }, - { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL }, - { EM28XX_AMUX_PHONE, AC97_PHONE_VOL }, - { EM28XX_AMUX_MIC, AC97_MIC_VOL }, - { EM28XX_AMUX_CD, AC97_CD_VOL }, - { EM28XX_AMUX_AUX, AC97_AUX_VOL }, - { EM28XX_AMUX_PCM_OUT, AC97_PCM_OUT_VOL }, -}; - -static int set_ac97_input(struct em28xx *dev) -{ - int ret, i; - enum em28xx_amux amux = dev->ctl_ainput; - - /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that - em28xx should point to LINE IN, while AC97 should use VIDEO - */ - if (amux == EM28XX_AMUX_VIDEO2) - amux = EM28XX_AMUX_VIDEO; - - /* Mute all entres but the one that were selected */ - for (i = 0; i < ARRAY_SIZE(inputs); i++) { - if (amux == inputs[i].mux) - ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808); - else - ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000); - - if (ret < 0) - em28xx_warn("couldn't setup AC97 register %d\n", - inputs[i].reg); - } - return 0; -} - -static int em28xx_set_audio_source(struct em28xx *dev) -{ - int ret; - u8 input; - - if (dev->board.is_em2800) { - if (dev->ctl_ainput == EM28XX_AMUX_VIDEO) - input = EM2800_AUDIO_SRC_TUNER; - else - input = EM2800_AUDIO_SRC_LINE; - - ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1); - if (ret < 0) - return ret; - } - - if (dev->board.has_msp34xx) - input = EM28XX_AUDIO_SRC_TUNER; - else { - switch (dev->ctl_ainput) { - case EM28XX_AMUX_VIDEO: - input = EM28XX_AUDIO_SRC_TUNER; - break; - default: - input = EM28XX_AUDIO_SRC_LINE; - break; - } - } - - if (dev->board.mute_gpio && dev->mute) - em28xx_gpio_set(dev, dev->board.mute_gpio); - else - em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio); - - ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0); - if (ret < 0) - return ret; - msleep(5); - - switch (dev->audio_mode.ac97) { - case EM28XX_NO_AC97: - break; - default: - ret = set_ac97_input(dev); - } - - return ret; -} - -static const struct em28xx_vol_table outputs[] = { - { EM28XX_AOUT_MASTER, AC97_MASTER_VOL }, - { EM28XX_AOUT_LINE, AC97_LINE_LEVEL_VOL }, - { EM28XX_AOUT_MONO, AC97_MASTER_MONO_VOL }, - { EM28XX_AOUT_LFE, AC97_LFE_MASTER_VOL }, - { EM28XX_AOUT_SURR, AC97_SURR_MASTER_VOL }, -}; - -int em28xx_audio_analog_set(struct em28xx *dev) -{ - int ret, i; - u8 xclk; - - if (!dev->audio_mode.has_audio) - return 0; - - /* It is assumed that all devices use master volume for output. - It would be possible to use also line output. - */ - if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { - /* Mute all outputs */ - for (i = 0; i < ARRAY_SIZE(outputs); i++) { - ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000); - if (ret < 0) - em28xx_warn("couldn't setup AC97 register %d\n", - outputs[i].reg); - } - } - - xclk = dev->board.xclk & 0x7f; - if (!dev->mute) - xclk |= EM28XX_XCLK_AUDIO_UNMUTE; - - ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk); - if (ret < 0) - return ret; - msleep(10); - - /* Selects the proper audio input */ - ret = em28xx_set_audio_source(dev); - - /* Sets volume */ - if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { - int vol; - - em28xx_write_ac97(dev, AC97_POWER_DOWN_CTRL, 0x4200); - em28xx_write_ac97(dev, AC97_EXT_AUD_CTRL, 0x0031); - em28xx_write_ac97(dev, AC97_PCM_IN_SRATE, 0xbb80); - - /* LSB: left channel - both channels with the same level */ - vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8); - - /* Mute device, if needed */ - if (dev->mute) - vol |= 0x8000; - - /* Sets volume */ - for (i = 0; i < ARRAY_SIZE(outputs); i++) { - if (dev->ctl_aoutput & outputs[i].mux) - ret = em28xx_write_ac97(dev, outputs[i].reg, - vol); - if (ret < 0) - em28xx_warn("couldn't setup AC97 register %d\n", - outputs[i].reg); - } - - if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) { - int sel = ac97_return_record_select(dev->ctl_aoutput); - - /* Use the same input for both left and right - channels */ - sel |= (sel << 8); - - em28xx_write_ac97(dev, AC97_RECORD_SELECT, sel); - } - } - - return ret; -} -EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); - -int em28xx_audio_setup(struct em28xx *dev) -{ - int vid1, vid2, feat, cfg; - u32 vid; - - if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874) { - /* Digital only device - don't load any alsa module */ - dev->audio_mode.has_audio = 0; - dev->has_audio_class = 0; - dev->has_alsa_audio = 0; - return 0; - } - - /* If device doesn't support Usb Audio Class, use vendor class */ - if (!dev->has_audio_class) - dev->has_alsa_audio = 1; - - dev->audio_mode.has_audio = 1; - - /* See how this device is configured */ - cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); - em28xx_info("Config register raw data: 0x%02x\n", cfg); - if (cfg < 0) { - /* Register read error? */ - cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ - } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) { - /* The device doesn't have vendor audio at all */ - dev->has_alsa_audio = 0; - dev->audio_mode.has_audio = 0; - return 0; - } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == - EM28XX_CHIPCFG_I2S_3_SAMPRATES) { - em28xx_info("I2S Audio (3 sample rates)\n"); - dev->audio_mode.i2s_3rates = 1; - } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == - EM28XX_CHIPCFG_I2S_5_SAMPRATES) { - em28xx_info("I2S Audio (5 sample rates)\n"); - dev->audio_mode.i2s_5rates = 1; - } - - if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) { - /* Skip the code that does AC97 vendor detection */ - dev->audio_mode.ac97 = EM28XX_NO_AC97; - goto init_audio; - } - - dev->audio_mode.ac97 = EM28XX_AC97_OTHER; - - vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1); - if (vid1 < 0) { - /* - * Device likely doesn't support AC97 - * Note: (some) em2800 devices without eeprom reports 0x91 on - * CHIPCFG register, even not having an AC97 chip - */ - em28xx_warn("AC97 chip type couldn't be determined\n"); - dev->audio_mode.ac97 = EM28XX_NO_AC97; - dev->has_alsa_audio = 0; - dev->audio_mode.has_audio = 0; - goto init_audio; - } - - vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2); - if (vid2 < 0) - goto init_audio; - - vid = vid1 << 16 | vid2; - - dev->audio_mode.ac97_vendor_id = vid; - em28xx_warn("AC97 vendor ID = 0x%08x\n", vid); - - feat = em28xx_read_ac97(dev, AC97_RESET); - if (feat < 0) - goto init_audio; - - dev->audio_mode.ac97_feat = feat; - em28xx_warn("AC97 features = 0x%04x\n", feat); - - /* Try to identify what audio processor we have */ - if ((vid == 0xffffffff) && (feat == 0x6a90)) - dev->audio_mode.ac97 = EM28XX_AC97_EM202; - else if ((vid >> 8) == 0x838476) - dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL; - -init_audio: - /* Reports detected AC97 processor */ - switch (dev->audio_mode.ac97) { - case EM28XX_NO_AC97: - em28xx_info("No AC97 audio processor\n"); - break; - case EM28XX_AC97_EM202: - em28xx_info("Empia 202 AC97 audio processor detected\n"); - break; - case EM28XX_AC97_SIGMATEL: - em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n", - dev->audio_mode.ac97_vendor_id & 0xff); - break; - case EM28XX_AC97_OTHER: - em28xx_warn("Unknown AC97 audio processor detected!\n"); - break; - default: - break; - } - - return em28xx_audio_analog_set(dev); -} -EXPORT_SYMBOL_GPL(em28xx_audio_setup); - -int em28xx_colorlevels_set_default(struct em28xx *dev) -{ - em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10); /* contrast */ - em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00); /* brightness */ - em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */ - em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00); - em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00); - em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00); - - em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); - em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); - em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20); - em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20); - em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00); - em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00); - return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00); -} - -int em28xx_capture_start(struct em28xx *dev, int start) -{ - int rc; - - if (dev->chip_id == CHIP_ID_EM2874) { - /* The Transport Stream Enable Register moved in em2874 */ - if (!start) { - rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, - 0x00, - EM2874_TS1_CAPTURE_ENABLE); - return rc; - } - - /* Enable Transport Stream */ - rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, - EM2874_TS1_CAPTURE_ENABLE, - EM2874_TS1_CAPTURE_ENABLE); - return rc; - } - - - /* FIXME: which is the best order? */ - /* video registers are sampled by VREF */ - rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, - start ? 0x10 : 0x00, 0x10); - if (rc < 0) - return rc; - - if (!start) { - /* disable video capture */ - rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27); - return rc; - } - - if (dev->board.is_webcam) - rc = em28xx_write_reg(dev, 0x13, 0x0c); - - /* enable video capture */ - rc = em28xx_write_reg(dev, 0x48, 0x00); - - if (dev->mode == EM28XX_ANALOG_MODE) - rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); - else - rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); - - msleep(6); - - return rc; -} - -int em28xx_vbi_supported(struct em28xx *dev) -{ - /* Modprobe option to manually disable */ - if (disable_vbi == 1) - return 0; - - if (dev->chip_id == CHIP_ID_EM2860 || - dev->chip_id == CHIP_ID_EM2883) - return 1; - - /* Version of em28xx that does not support VBI */ - return 0; -} - -int em28xx_set_outfmt(struct em28xx *dev) -{ - int ret; - u8 vinctrl; - - ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, - dev->format->reg | 0x20, 0xff); - if (ret < 0) - return ret; - - ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode); - if (ret < 0) - return ret; - - vinctrl = dev->vinctl; - if (em28xx_vbi_supported(dev) == 1) { - vinctrl |= EM28XX_VINCTRL_VBI_RAW; - em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); - em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4); - em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height); - if (dev->norm & V4L2_STD_525_60) { - /* NTSC */ - em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); - } else if (dev->norm & V4L2_STD_625_50) { - /* PAL */ - em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07); - } - } - - return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); -} - -static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, - u8 ymin, u8 ymax) -{ - em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", - xmin, ymin, xmax, ymax); - - em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); - em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); - em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); - return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); -} - -static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, - u16 width, u16 height) -{ - u8 cwidth = width; - u8 cheight = height; - u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01); - - em28xx_coredbg("em28xx Area Set: (%d,%d)\n", - (width | (overflow & 2) << 7), - (height | (overflow & 1) << 8)); - - em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); - em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); - em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); - em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); - return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); -} - -static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) -{ - u8 mode; - /* the em2800 scaler only supports scaling down to 50% */ - - if (dev->board.is_em2800) { - mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); - } else { - u8 buf[2]; - - buf[0] = h; - buf[1] = h >> 8; - em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); - - buf[0] = v; - buf[1] = v >> 8; - em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); - /* it seems that both H and V scalers must be active - to work correctly */ - mode = (h || v) ? 0x30 : 0x00; - } - return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30); -} - -/* FIXME: this only function read values from dev */ -int em28xx_resolution_set(struct em28xx *dev) -{ - int width, height; - width = norm_maxw(dev); - height = norm_maxh(dev); - - /* Properly setup VBI */ - dev->vbi_width = 720; - if (dev->norm & V4L2_STD_525_60) - dev->vbi_height = 12; - else - dev->vbi_height = 18; - - if (!dev->progressive) - height >>= norm_maxh(dev); - - em28xx_set_outfmt(dev); - - - em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); - - /* If we don't set the start position to 2 in VBI mode, we end up - with line 20/21 being YUYV encoded instead of being in 8-bit - greyscale. The core of the issue is that line 21 (and line 23 for - PAL WSS) are inside of active video region, and as a result they - get the pixelformatting associated with that area. So by cropping - it out, we end up with the same format as the rest of the VBI - region */ - if (em28xx_vbi_supported(dev) == 1) - em28xx_capture_area_set(dev, 0, 2, width >> 2, height >> 2); - else - em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); - - return em28xx_scaler_set(dev, dev->hscale, dev->vscale); -} - -int em28xx_set_alternate(struct em28xx *dev) -{ - int errCode, prev_alt = dev->alt; - int i; - unsigned int min_pkt_size = dev->width * 2 + 4; - - /* - * alt = 0 is used only for control messages, so, only values - * greater than 0 can be used for streaming. - */ - if (alt && alt < dev->num_alt) { - em28xx_coredbg("alternate forced to %d\n", dev->alt); - dev->alt = alt; - goto set_alt; - } - - /* When image size is bigger than a certain value, - the frame size should be increased, otherwise, only - green screen will be received. - */ - if (dev->width * 2 * dev->height > 720 * 240 * 2) - min_pkt_size *= 2; - - for (i = 0; i < dev->num_alt; i++) { - /* stop when the selected alt setting offers enough bandwidth */ - if (dev->alt_max_pkt_size[i] >= min_pkt_size) { - dev->alt = i; - break; - /* otherwise make sure that we end up with the maximum bandwidth - because the min_pkt_size equation might be wrong... - */ - } else if (dev->alt_max_pkt_size[i] > - dev->alt_max_pkt_size[dev->alt]) - dev->alt = i; - } - -set_alt: - if (dev->alt != prev_alt) { - em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", - min_pkt_size, dev->alt); - dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt]; - em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", - dev->alt, dev->max_pkt_size); - errCode = usb_set_interface(dev->udev, 0, dev->alt); - if (errCode < 0) { - em28xx_errdev("cannot change alternate number to %d (error=%i)\n", - dev->alt, errCode); - return errCode; - } - } - return 0; -} - -int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) -{ - int rc = 0; - - if (!gpio) - return rc; - - if (dev->mode != EM28XX_SUSPEND) { - em28xx_write_reg(dev, 0x48, 0x00); - if (dev->mode == EM28XX_ANALOG_MODE) - em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); - else - em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); - msleep(6); - } - - /* Send GPIO reset sequences specified at board entry */ - while (gpio->sleep >= 0) { - if (gpio->reg >= 0) { - rc = em28xx_write_reg_bits(dev, - gpio->reg, - gpio->val, - gpio->mask); - if (rc < 0) - return rc; - } - if (gpio->sleep > 0) - msleep(gpio->sleep); - - gpio++; - } - return rc; -} - -int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode) -{ - if (dev->mode == set_mode) - return 0; - - if (set_mode == EM28XX_SUSPEND) { - dev->mode = set_mode; - - /* FIXME: add suspend support for ac97 */ - - return em28xx_gpio_set(dev, dev->board.suspend_gpio); - } - - dev->mode = set_mode; - - if (dev->mode == EM28XX_DIGITAL_MODE) - return em28xx_gpio_set(dev, dev->board.dvb_gpio); - else - return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio); -} -EXPORT_SYMBOL_GPL(em28xx_set_mode); - -/* ------------------------------------------------------------------ - URB control - ------------------------------------------------------------------*/ - -/* - * IRQ callback, called by URB callback - */ -static void em28xx_irq_callback(struct urb *urb) -{ - struct em28xx *dev = urb->context; - int rc, i; - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - em28xx_isocdbg("urb completition error %d.\n", urb->status); - break; - } - - /* Copy data from URB */ - spin_lock(&dev->slock); - rc = dev->isoc_ctl.isoc_copy(dev, urb); - spin_unlock(&dev->slock); - - /* Reset urb buffers */ - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - urb->status = 0; - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) { - em28xx_isocdbg("urb resubmit failed (error=%i)\n", - urb->status); - } -} - -/* - * Stop and Deallocate URBs - */ -void em28xx_uninit_isoc(struct em28xx *dev) -{ - struct urb *urb; - int i; - - em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n"); - - dev->isoc_ctl.nfields = -1; - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = dev->isoc_ctl.urb[i]; - if (urb) { - if (!irqs_disabled()) - usb_kill_urb(urb); - else - usb_unlink_urb(urb); - - if (dev->isoc_ctl.transfer_buffer[i]) { - usb_free_coherent(dev->udev, - urb->transfer_buffer_length, - dev->isoc_ctl.transfer_buffer[i], - urb->transfer_dma); - } - usb_free_urb(urb); - dev->isoc_ctl.urb[i] = NULL; - } - dev->isoc_ctl.transfer_buffer[i] = NULL; - } - - kfree(dev->isoc_ctl.urb); - kfree(dev->isoc_ctl.transfer_buffer); - - dev->isoc_ctl.urb = NULL; - dev->isoc_ctl.transfer_buffer = NULL; - dev->isoc_ctl.num_bufs = 0; - - em28xx_capture_start(dev, 0); -} -EXPORT_SYMBOL_GPL(em28xx_uninit_isoc); - -/* - * Allocate URBs and start IRQ - */ -int em28xx_init_isoc(struct em28xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) -{ - struct em28xx_dmaqueue *dma_q = &dev->vidq; - struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; - int i; - int sb_size, pipe; - struct urb *urb; - int j, k; - int rc; - - em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n"); - - /* De-allocates all pending stuff */ - em28xx_uninit_isoc(dev); - - dev->isoc_ctl.isoc_copy = isoc_copy; - dev->isoc_ctl.num_bufs = num_bufs; - - dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); - if (!dev->isoc_ctl.urb) { - em28xx_errdev("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - - dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); - if (!dev->isoc_ctl.transfer_buffer) { - em28xx_errdev("cannot allocate memory for usb transfer\n"); - kfree(dev->isoc_ctl.urb); - return -ENOMEM; - } - - dev->isoc_ctl.max_pkt_size = max_pkt_size; - dev->isoc_ctl.vid_buf = NULL; - dev->isoc_ctl.vbi_buf = NULL; - - sb_size = max_packets * dev->isoc_ctl.max_pkt_size; - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = usb_alloc_urb(max_packets, GFP_KERNEL); - if (!urb) { - em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); - em28xx_uninit_isoc(dev); - return -ENOMEM; - } - dev->isoc_ctl.urb[i] = urb; - - dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, - sb_size, GFP_KERNEL, &urb->transfer_dma); - if (!dev->isoc_ctl.transfer_buffer[i]) { - em28xx_err("unable to allocate %i bytes for transfer" - " buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); - em28xx_uninit_isoc(dev); - return -ENOMEM; - } - memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); - - /* FIXME: this is a hack - should be - 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' - should also be using 'desc.bInterval' - */ - pipe = usb_rcvisocpipe(dev->udev, - dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84); - - usb_fill_int_urb(urb, dev->udev, pipe, - dev->isoc_ctl.transfer_buffer[i], sb_size, - em28xx_irq_callback, dev, 1); - - urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - - k = 0; - for (j = 0; j < max_packets; j++) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - dev->isoc_ctl.max_pkt_size; - k += dev->isoc_ctl.max_pkt_size; - } - } - - init_waitqueue_head(&dma_q->wq); - init_waitqueue_head(&vbi_dma_q->wq); - - em28xx_capture_start(dev, 1); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); - if (rc) { - em28xx_err("submit of urb %i failed (error=%i)\n", i, - rc); - em28xx_uninit_isoc(dev); - return rc; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(em28xx_init_isoc); - -/* Determine the packet size for the DVB stream for the given device - (underlying value programmed into the eeprom) */ -int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) -{ - unsigned int chip_cfg2; - unsigned int packet_size = 564; - - if (dev->chip_id == CHIP_ID_EM2874) { - /* FIXME - for now assume 564 like it was before, but the - em2874 code should be added to return the proper value... */ - packet_size = 564; - } else { - /* TS max packet size stored in bits 1-0 of R01 */ - chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); - switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) { - case EM28XX_CHIPCFG2_TS_PACKETSIZE_188: - packet_size = 188; - break; - case EM28XX_CHIPCFG2_TS_PACKETSIZE_376: - packet_size = 376; - break; - case EM28XX_CHIPCFG2_TS_PACKETSIZE_564: - packet_size = 564; - break; - case EM28XX_CHIPCFG2_TS_PACKETSIZE_752: - packet_size = 752; - break; - } - } - - em28xx_coredbg("dvb max packet size=%d\n", packet_size); - return packet_size; -} -EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize); - -/* - * em28xx_wake_i2c() - * configure i2c attached devices - */ -void em28xx_wake_i2c(struct em28xx *dev) -{ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, - INPUT(dev->ctl_input)->vmux, 0, 0); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); -} - -/* - * Device control list - */ - -static LIST_HEAD(em28xx_devlist); -static DEFINE_MUTEX(em28xx_devlist_mutex); - -/* - * em28xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -void em28xx_remove_from_devlist(struct em28xx *dev) -{ - mutex_lock(&em28xx_devlist_mutex); - list_del(&dev->devlist); - mutex_unlock(&em28xx_devlist_mutex); -}; - -void em28xx_add_into_devlist(struct em28xx *dev) -{ - mutex_lock(&em28xx_devlist_mutex); - list_add_tail(&dev->devlist, &em28xx_devlist); - mutex_unlock(&em28xx_devlist_mutex); -}; - -/* - * Extension interface - */ - -static LIST_HEAD(em28xx_extension_devlist); - -int em28xx_register_extension(struct em28xx_ops *ops) -{ - struct em28xx *dev = NULL; - - mutex_lock(&em28xx_devlist_mutex); - list_add_tail(&ops->next, &em28xx_extension_devlist); - list_for_each_entry(dev, &em28xx_devlist, devlist) { - ops->init(dev); - } - printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); - mutex_unlock(&em28xx_devlist_mutex); - return 0; -} -EXPORT_SYMBOL(em28xx_register_extension); - -void em28xx_unregister_extension(struct em28xx_ops *ops) -{ - struct em28xx *dev = NULL; - - mutex_lock(&em28xx_devlist_mutex); - list_for_each_entry(dev, &em28xx_devlist, devlist) { - ops->fini(dev); - } - printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); - list_del(&ops->next); - mutex_unlock(&em28xx_devlist_mutex); -} -EXPORT_SYMBOL(em28xx_unregister_extension); - -void em28xx_init_extension(struct em28xx *dev) -{ - struct em28xx_ops *ops = NULL; - - mutex_lock(&em28xx_devlist_mutex); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->init) - ops->init(dev); - } - } - mutex_unlock(&em28xx_devlist_mutex); -} - -void em28xx_close_extension(struct em28xx *dev) -{ - struct em28xx_ops *ops = NULL; - - mutex_lock(&em28xx_devlist_mutex); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->fini) - ops->fini(dev); - } - } - mutex_unlock(&em28xx_devlist_mutex); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-dvb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,689 +0,0 @@ -/* - DVB device driver for em28xx - - (c) 2008 Mauro Carvalho Chehab - - (c) 2008 Devin Heitmueller - - Fixes for the driver to properly work with HVR-950 - - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick - - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600 - - (c) 2008 Aidan Thornton - - Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: - (c) 2004, 2005 Chris Pascoe - (c) 2004 Gerd Knorr [SuSE Labs] - - 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. - */ - -#include -#include -#include - -#include "em28xx.h" -#include -#include -#include -#include "tuner-simple.h" - -#include "lgdt330x.h" -#include "lgdt3305.h" -#include "zl10353.h" -#include "s5h1409.h" -#include "mt352.h" -#include "mt352_priv.h" /* FIXME */ -#include "tda1002x.h" -#include "tda18271.h" -#include "s921.h" - -MODULE_DESCRIPTION("driver for em28xx based DVB cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages [dvb]"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk(level, fmt, arg...) do { \ -if (debug >= level) \ - printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ -} while (0) - -#define EM28XX_DVB_NUM_BUFS 5 -#define EM28XX_DVB_MAX_PACKETS 64 - -struct em28xx_dvb { - struct dvb_frontend *frontend; - - /* feed count management */ - struct mutex lock; - int nfeeds; - - /* general boilerplate stuff */ - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net net; -}; - - -static inline void print_err_status(struct em28xx *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - dprintk(1, "URB status %d [%s].\n", status, errmsg); - } else { - dprintk(1, "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) -{ - int i; - - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - if (urb->iso_frame_desc[i].status != -EPROTO) - continue; - } - - dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer + - urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - } - - return 0; -} - -static int start_streaming(struct em28xx_dvb *dvb) -{ - int rc; - struct em28xx *dev = dvb->adapter.priv; - int max_dvb_packet_size; - - usb_set_interface(dev->udev, 0, 1); - rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); - if (rc < 0) - return rc; - - max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev); - - return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, - EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, - dvb_isoc_copy); -} - -static int stop_streaming(struct em28xx_dvb *dvb) -{ - struct em28xx *dev = dvb->adapter.priv; - - em28xx_uninit_isoc(dev); - - em28xx_set_mode(dev, EM28XX_SUSPEND); - - return 0; -} - -static int start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct em28xx_dvb *dvb = demux->priv; - int rc, ret; - - if (!demux->dmx.frontend) - return -EINVAL; - - mutex_lock(&dvb->lock); - dvb->nfeeds++; - rc = dvb->nfeeds; - - if (dvb->nfeeds == 1) { - ret = start_streaming(dvb); - if (ret < 0) - rc = ret; - } - - mutex_unlock(&dvb->lock); - return rc; -} - -static int stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct em28xx_dvb *dvb = demux->priv; - int err = 0; - - mutex_lock(&dvb->lock); - dvb->nfeeds--; - - if (0 == dvb->nfeeds) - err = stop_streaming(dvb); - - mutex_unlock(&dvb->lock); - return err; -} - - - -/* ------------------------------------------------------------------ */ -static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct em28xx *dev = fe->dvb->priv; - - if (acquire) - return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); - else - return em28xx_set_mode(dev, EM28XX_SUSPEND); -} - -/* ------------------------------------------------------------------ */ - -static struct lgdt330x_config em2880_lgdt3303_dev = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, -}; - -static struct lgdt3305_config em2870_lgdt3304_dev = { - .i2c_addr = 0x0e, - .demod_chip = LGDT3304, - .spectral_inversion = 1, - .deny_i2c_rptr = 1, - .mpeg_mode = LGDT3305_MPEG_PARALLEL, - .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, - .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, - .vsb_if_khz = 3250, - .qam_if_khz = 4000, -}; - -static struct s921_config sharp_isdbt = { - .demod_address = 0x30 >> 1 -}; - -static struct zl10353_config em28xx_zl10353_with_xc3028 = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, - .parallel_ts = 1, - .if2 = 45600, -}; - -static struct s5h1409_config em28xx_s5h1409_with_xc3028 = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_PARALLEL_OUTPUT, - .gpio = S5H1409_GPIO_OFF, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK -}; - -static struct tda18271_std_map kworld_a340_std_map = { - .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 0, - .if_lvl = 1, .rfagc_top = 0x37, }, - .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 1, - .if_lvl = 1, .rfagc_top = 0x37, }, -}; - -static struct tda18271_config kworld_a340_config = { - .std_map = &kworld_a340_std_map, -}; - -static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, - .disable_i2c_gate_ctrl = 1, - .parallel_ts = 1, - .if2 = 45600, -}; - -#ifdef EM28XX_DRX397XD_SUPPORT -/* [TODO] djh - not sure yet what the device config needs to contain */ -static struct drx397xD_config em28xx_drx397xD_with_xc3028 = { - .demod_address = (0xe0 >> 1), -}; -#endif - -static int mt352_terratec_xs_init(struct dvb_frontend *fe) -{ - /* Values extracted from a USB trace of the Terratec Windows driver */ - static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x2c }; - static u8 reset[] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0xa0 }; - static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 }; - static u8 rs_err_cfg[] = { RS_ERR_PER_1, 0x00, 0x4d }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - static u8 trl_nom_cfg[] = { TRL_NOMINAL_RATE_1, 0x64, 0x00 }; - static u8 tps_given_cfg[] = { TPS_GIVEN_1, 0x40, 0x80, 0x50 }; - static u8 tuner_go[] = { TUNER_GO, 0x01}; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg)); - mt352_write(fe, rs_err_cfg, sizeof(rs_err_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - mt352_write(fe, trl_nom_cfg, sizeof(trl_nom_cfg)); - mt352_write(fe, tps_given_cfg, sizeof(tps_given_cfg)); - mt352_write(fe, tuner_go, sizeof(tuner_go)); - return 0; -} - -static struct mt352_config terratec_xs_mt352_cfg = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, - .if2 = 45600, - .demod_init = mt352_terratec_xs_init, -}; - -static struct tda10023_config em28xx_tda10023_config = { - .demod_address = 0x0c, - .invert = 1, -}; - -/* ------------------------------------------------------------------ */ - -static int attach_xc3028(u8 addr, struct em28xx *dev) -{ - struct dvb_frontend *fe; - struct xc2028_config cfg; - - memset(&cfg, 0, sizeof(cfg)); - cfg.i2c_adap = &dev->i2c_adap; - cfg.i2c_addr = addr; - - if (!dev->dvb->frontend) { - em28xx_errdev("/2: dvb frontend not attached. " - "Can't attach xc3028\n"); - return -EINVAL; - } - - fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg); - if (!fe) { - em28xx_errdev("/2: xc3028 attach failed\n"); - dvb_frontend_detach(dev->dvb->frontend); - dev->dvb->frontend = NULL; - return -EINVAL; - } - - em28xx_info("%s/2: xc3028 attached\n", dev->name); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int register_dvb(struct em28xx_dvb *dvb, - struct module *module, - struct em28xx *dev, - struct device *device) -{ - int result; - - mutex_init(&dvb->lock); - - /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, - adapter_nr); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", - dev->name, result); - goto fail_adapter; - } - - /* Ensure all frontends negotiate bus access */ - dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; - - dvb->adapter.priv = dev; - - /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", - dev->name, result); - goto fail_frontend; - } - - /* register demux stuff */ - dvb->demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dvb; - dvb->demux.filternum = 256; - dvb->demux.feednum = 256; - dvb->demux.start_feed = start_feed; - dvb->demux.stop_feed = stop_feed; - - result = dvb_dmx_init(&dvb->demux); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", - dev->name, result); - goto fail_dmx; - } - - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = &dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", - dev->name, result); - goto fail_dmxdev; - } - - dvb->fe_hw.source = DMX_FRONTEND_0; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", - dev->name, result); - goto fail_fe_hw; - } - - dvb->fe_mem.source = DMX_MEMORY_FE; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", - dev->name, result); - goto fail_fe_mem; - } - - result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", - dev->name, result); - goto fail_fe_conn; - } - - /* register network adapter */ - dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); - return 0; - -fail_fe_conn: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); -fail_fe_mem: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); -fail_fe_hw: - dvb_dmxdev_release(&dvb->dmxdev); -fail_dmxdev: - dvb_dmx_release(&dvb->demux); -fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -fail_adapter: - return result; -} - -static void unregister_dvb(struct em28xx_dvb *dvb) -{ - dvb_net_release(&dvb->net); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -} - - -static int dvb_init(struct em28xx *dev) -{ - int result = 0; - struct em28xx_dvb *dvb; - - if (!dev->board.has_dvb) { - /* This device does not support the extension */ - printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n"); - return 0; - } - - dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); - - if (dvb == NULL) { - em28xx_info("em28xx_dvb: memory allocation failed\n"); - return -ENOMEM; - } - dev->dvb = dvb; - - mutex_lock(&dev->lock); - em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); - /* init frontend */ - switch (dev->model) { - case EM2874_LEADERSHIP_ISDBT: - dvb->frontend = dvb_attach(s921_attach, - &sharp_isdbt, &dev->i2c_adap); - - if (!dvb->frontend) { - result = -EINVAL; - goto out_free; - } - - break; - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: - case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: - dvb->frontend = dvb_attach(lgdt330x_attach, - &em2880_lgdt3303_dev, - &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; - case EM2880_BOARD_KWORLD_DVB_310U: - dvb->frontend = dvb_attach(zl10353_attach, - &em28xx_zl10353_with_xc3028, - &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2882_BOARD_TERRATEC_HYBRID_XS: - case EM2880_BOARD_EMPIRE_DUAL_TV: - dvb->frontend = dvb_attach(zl10353_attach, - &em28xx_zl10353_xc3028_no_i2c_gate, - &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; - case EM2880_BOARD_TERRATEC_HYBRID_XS: - case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: - case EM2881_BOARD_PINNACLE_HYBRID_PRO: - case EM2882_BOARD_DIKOM_DK300: - case EM2882_BOARD_KWORLD_VS_DVBT: - dvb->frontend = dvb_attach(zl10353_attach, - &em28xx_zl10353_xc3028_no_i2c_gate, - &dev->i2c_adap); - if (dvb->frontend == NULL) { - /* This board could have either a zl10353 or a mt352. - If the chip id isn't for zl10353, try mt352 */ - dvb->frontend = dvb_attach(mt352_attach, - &terratec_xs_mt352_cfg, - &dev->i2c_adap); - } - - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; - case EM2883_BOARD_KWORLD_HYBRID_330U: - case EM2882_BOARD_EVGA_INDTUBE: - dvb->frontend = dvb_attach(s5h1409_attach, - &em28xx_s5h1409_with_xc3028, - &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; - case EM2882_BOARD_KWORLD_ATSC_315U: - dvb->frontend = dvb_attach(lgdt330x_attach, - &em2880_lgdt3303_dev, - &dev->i2c_adap); - if (dvb->frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dvb->frontend, - &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) { - result = -EINVAL; - goto out_free; - } - } - break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: -#ifdef EM28XX_DRX397XD_SUPPORT - /* We don't have the config structure properly populated, so - this is commented out for now */ - dvb->frontend = dvb_attach(drx397xD_attach, - &em28xx_drx397xD_with_xc3028, - &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; -#endif - case EM2870_BOARD_REDDO_DVB_C_USB_BOX: - /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ - dvb->frontend = dvb_attach(tda10023_attach, - &em28xx_tda10023_config, - &dev->i2c_adap, 0x48); - if (dvb->frontend) { - if (!dvb_attach(simple_tuner_attach, dvb->frontend, - &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) { - result = -EINVAL; - goto out_free; - } - } - break; - case EM2870_BOARD_KWORLD_A340: - dvb->frontend = dvb_attach(lgdt3305_attach, - &em2870_lgdt3304_dev, - &dev->i2c_adap); - if (dvb->frontend != NULL) - dvb_attach(tda18271_attach, dvb->frontend, 0x60, - &dev->i2c_adap, &kworld_a340_config); - break; - default: - em28xx_errdev("/2: The frontend of your DVB/ATSC card" - " isn't supported yet\n"); - break; - } - if (NULL == dvb->frontend) { - em28xx_errdev("/2: frontend initialization failed\n"); - result = -EINVAL; - goto out_free; - } - /* define general-purpose callback pointer */ - dvb->frontend->callback = em28xx_tuner_callback; - - /* register everything */ - result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); - - if (result < 0) - goto out_free; - - em28xx_info("Successfully loaded em28xx-dvb\n"); -ret: - em28xx_set_mode(dev, EM28XX_SUSPEND); - mutex_unlock(&dev->lock); - return result; - -out_free: - kfree(dvb); - dev->dvb = NULL; - goto ret; -} - -static int dvb_fini(struct em28xx *dev) -{ - if (!dev->board.has_dvb) { - /* This device does not support the extension */ - return 0; - } - - if (dev->dvb) { - unregister_dvb(dev->dvb); - kfree(dev->dvb); - dev->dvb = NULL; - } - - return 0; -} - -static struct em28xx_ops dvb_ops = { - .id = EM28XX_DVB, - .name = "Em28xx dvb Extension", - .init = dvb_init, - .fini = dvb_fini, -}; - -static int __init em28xx_dvb_register(void) -{ - return em28xx_register_extension(&dvb_ops); -} - -static void __exit em28xx_dvb_unregister(void) -{ - em28xx_unregister_extension(&dvb_ops); -} - -module_init(em28xx_dvb_register); -module_exit(em28xx_dvb_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,824 +0,0 @@ -/* - em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Markus Rechberger - Ludovico Cavedon - Mauro Carvalho Chehab - - Based on the em2800 driver from Sascha Sommer - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _EM28XX_H -#define _EM28XX_H - -#include -#include -#include -#include - -#include -#include -#include -#include -#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) -#include -#endif -#include "tuner-xc2028.h" -#include "em28xx-reg.h" - -/* Boards supported by driver */ -#define EM2800_BOARD_UNKNOWN 0 -#define EM2820_BOARD_UNKNOWN 1 -#define EM2820_BOARD_TERRATEC_CINERGY_250 2 -#define EM2820_BOARD_PINNACLE_USB_2 3 -#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 -#define EM2820_BOARD_MSI_VOX_USB_2 5 -#define EM2800_BOARD_TERRATEC_CINERGY_200 6 -#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 -#define EM2800_BOARD_KWORLD_USB2800 8 -#define EM2820_BOARD_PINNACLE_DVC_90 9 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 -#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 -#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 -#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 -#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 -#define EM2800_BOARD_VGEAR_POCKETTV 15 -#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16 -#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 -#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19 -#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 -#define EM2800_BOARD_GRABBEEX_USB2800 21 -#define EM2750_BOARD_UNKNOWN 22 -#define EM2750_BOARD_DLCW_130 23 -#define EM2820_BOARD_DLINK_USB_TV 24 -#define EM2820_BOARD_GADMEI_UTV310 25 -#define EM2820_BOARD_HERCULES_SMART_TV_USB2 26 -#define EM2820_BOARD_PINNACLE_USB_2_FM1216ME 27 -#define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28 -#define EM2860_BOARD_TVP5150_REFERENCE_DESIGN 29 -#define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30 -#define EM2821_BOARD_USBGEAR_VD204 31 -#define EM2821_BOARD_SUPERCOMP_USB_2 32 -#define EM2860_BOARD_ELGATO_VIDEO_CAPTURE 33 -#define EM2860_BOARD_TERRATEC_HYBRID_XS 34 -#define EM2860_BOARD_TYPHOON_DVD_MAKER 35 -#define EM2860_BOARD_NETGMBH_CAM 36 -#define EM2860_BOARD_GADMEI_UTV330 37 -#define EM2861_BOARD_YAKUMO_MOVIE_MIXER 38 -#define EM2861_BOARD_KWORLD_PVRTV_300U 39 -#define EM2861_BOARD_PLEXTOR_PX_TV100U 40 -#define EM2870_BOARD_KWORLD_350U 41 -#define EM2870_BOARD_KWORLD_355U 42 -#define EM2870_BOARD_TERRATEC_XS 43 -#define EM2870_BOARD_TERRATEC_XS_MT2060 44 -#define EM2870_BOARD_PINNACLE_PCTV_DVB 45 -#define EM2870_BOARD_COMPRO_VIDEOMATE 46 -#define EM2880_BOARD_KWORLD_DVB_305U 47 -#define EM2880_BOARD_KWORLD_DVB_310U 48 -#define EM2880_BOARD_MSI_DIGIVOX_AD 49 -#define EM2880_BOARD_MSI_DIGIVOX_AD_II 50 -#define EM2880_BOARD_TERRATEC_HYBRID_XS_FR 51 -#define EM2881_BOARD_DNT_DA2_HYBRID 52 -#define EM2881_BOARD_PINNACLE_HYBRID_PRO 53 -#define EM2882_BOARD_KWORLD_VS_DVBT 54 -#define EM2882_BOARD_TERRATEC_HYBRID_XS 55 -#define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 -#define EM2883_BOARD_KWORLD_HYBRID_330U 57 -#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 -#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 -#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61 -#define EM2820_BOARD_GADMEI_TVR200 62 -#define EM2860_BOARD_KAIOMY_TVNPC_U2 63 -#define EM2860_BOARD_EASYCAP 64 -#define EM2820_BOARD_IODATA_GVMVP_SZ 65 -#define EM2880_BOARD_EMPIRE_DUAL_TV 66 -#define EM2860_BOARD_TERRATEC_GRABBY 67 -#define EM2860_BOARD_TERRATEC_AV350 68 -#define EM2882_BOARD_KWORLD_ATSC_315U 69 -#define EM2882_BOARD_EVGA_INDTUBE 70 -#define EM2820_BOARD_SILVERCREST_WEBCAM 71 -#define EM2861_BOARD_GADMEI_UTV330PLUS 72 -#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73 -#define EM2800_BOARD_VC211A 74 -#define EM2882_BOARD_DIKOM_DK300 75 -#define EM2870_BOARD_KWORLD_A340 76 -#define EM2874_LEADERSHIP_ISDBT 77 - - -/* Limits minimum and default number of buffers */ -#define EM28XX_MIN_BUF 4 -#define EM28XX_DEF_BUF 8 - -/*Limits the max URB message size */ -#define URB_MAX_CTRL_SIZE 80 - -/* Params for validated field */ -#define EM28XX_BOARD_NOT_VALIDATED 1 -#define EM28XX_BOARD_VALIDATED 0 - -/* Params for em28xx_cmd() audio */ -#define EM28XX_START_AUDIO 1 -#define EM28XX_STOP_AUDIO 0 - -/* maximum number of em28xx boards */ -#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ - -/* maximum number of frames that can be queued */ -#define EM28XX_NUM_FRAMES 5 -/* number of frames that get used for v4l2_read() */ -#define EM28XX_NUM_READ_FRAMES 2 - -/* number of buffers for isoc transfers */ -#define EM28XX_NUM_BUFS 5 - -/* number of packets for each buffer - windows requests only 64 packets .. so we better do the same - this is what I found out for all alternate numbers there! - */ -#define EM28XX_NUM_PACKETS 64 - -#define EM28XX_INTERLACED_DEFAULT 1 - -/* -#define (use usbview if you want to get the other alternate number infos) -#define -#define alternate number 2 -#define Endpoint Address: 82 - Direction: in - Attribute: 1 - Type: Isoc - Max Packet Size: 1448 - Interval: 125us - - alternate number 7 - - Endpoint Address: 82 - Direction: in - Attribute: 1 - Type: Isoc - Max Packet Size: 3072 - Interval: 125us -*/ - -/* time to wait when stopping the isoc transfer */ -#define EM28XX_URB_TIMEOUT \ - msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS) - -/* time in msecs to wait for i2c writes to finish */ -#define EM2800_I2C_WRITE_TIMEOUT 20 - -enum em28xx_mode { - EM28XX_SUSPEND, - EM28XX_ANALOG_MODE, - EM28XX_DIGITAL_MODE, -}; - - -struct em28xx; - -struct em28xx_usb_isoc_ctl { - /* max packet size of isoc transaction */ - int max_pkt_size; - - /* number of allocated urbs */ - int num_bufs; - - /* urb for isoc transfers */ - struct urb **urb; - - /* transfer buffers for isoc transfer */ - char **transfer_buffer; - - /* Last buffer command and region */ - u8 cmd; - int pos, size, pktsize; - - /* Last field: ODD or EVEN? */ - int field; - - /* Stores incomplete commands */ - u32 tmp_buf; - int tmp_buf_len; - - /* Stores already requested buffers */ - struct em28xx_buffer *vid_buf; - struct em28xx_buffer *vbi_buf; - - /* Stores the number of received fields */ - int nfields; - - /* isoc urb callback */ - int (*isoc_copy) (struct em28xx *dev, struct urb *urb); - -}; - -/* Struct to enumberate video formats */ -struct em28xx_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int reg; -}; - -/* buffer for one video frame */ -struct em28xx_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - struct list_head frame; - int top_field; - int receiving; -}; - -struct em28xx_dmaqueue { - struct list_head active; - struct list_head queued; - - wait_queue_head_t wq; - - /* Counters to control buffer fill */ - int pos; -}; - -/* io methods */ -enum em28xx_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -/* inputs */ - -#define MAX_EM28XX_INPUT 4 -enum enum28xx_itype { - EM28XX_VMUX_COMPOSITE1 = 1, - EM28XX_VMUX_COMPOSITE2, - EM28XX_VMUX_COMPOSITE3, - EM28XX_VMUX_COMPOSITE4, - EM28XX_VMUX_SVIDEO, - EM28XX_VMUX_TELEVISION, - EM28XX_VMUX_CABLE, - EM28XX_VMUX_DVB, - EM28XX_VMUX_DEBUG, - EM28XX_RADIO, -}; - -enum em28xx_ac97_mode { - EM28XX_NO_AC97 = 0, - EM28XX_AC97_EM202, - EM28XX_AC97_SIGMATEL, - EM28XX_AC97_OTHER, -}; - -struct em28xx_audio_mode { - enum em28xx_ac97_mode ac97; - - u16 ac97_feat; - u32 ac97_vendor_id; - - unsigned int has_audio:1; - - unsigned int i2s_3rates:1; - unsigned int i2s_5rates:1; -}; - -/* em28xx has two audio inputs: tuner and line in. - However, on most devices, an auxiliary AC97 codec device is used. - The AC97 device may have several different inputs and outputs, - depending on their model. So, it is possible to use AC97 mixer to - address more than two different entries. - */ -enum em28xx_amux { - /* This is the only entry for em28xx tuner input */ - EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */ - - EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */ - - /* Some less-common mixer setups */ - EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */ - EM28XX_AMUX_PHONE, - EM28XX_AMUX_MIC, - EM28XX_AMUX_CD, - EM28XX_AMUX_AUX, - EM28XX_AMUX_PCM_OUT, -}; - -enum em28xx_aout { - /* AC97 outputs */ - EM28XX_AOUT_MASTER = 1 << 0, - EM28XX_AOUT_LINE = 1 << 1, - EM28XX_AOUT_MONO = 1 << 2, - EM28XX_AOUT_LFE = 1 << 3, - EM28XX_AOUT_SURR = 1 << 4, - - /* PCM IN Mixer - used by AC97_RECORD_SELECT register */ - EM28XX_AOUT_PCM_IN = 1 << 7, - - /* Bits 10-8 are used to indicate the PCM IN record select */ - EM28XX_AOUT_PCM_MIC_PCM = 0 << 8, - EM28XX_AOUT_PCM_CD = 1 << 8, - EM28XX_AOUT_PCM_VIDEO = 2 << 8, - EM28XX_AOUT_PCM_AUX = 3 << 8, - EM28XX_AOUT_PCM_LINE = 4 << 8, - EM28XX_AOUT_PCM_STEREO = 5 << 8, - EM28XX_AOUT_PCM_MONO = 6 << 8, - EM28XX_AOUT_PCM_PHONE = 7 << 8, -}; - -static inline int ac97_return_record_select(int a_out) -{ - return (a_out & 0x700) >> 8; -} - -struct em28xx_reg_seq { - int reg; - unsigned char val, mask; - int sleep; -}; - -struct em28xx_input { - enum enum28xx_itype type; - unsigned int vmux; - enum em28xx_amux amux; - enum em28xx_aout aout; - struct em28xx_reg_seq *gpio; -}; - -#define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) - -enum em28xx_decoder { - EM28XX_NODECODER = 0, - EM28XX_TVP5150, - EM28XX_SAA711X, -}; - -enum em28xx_sensor { - EM28XX_NOSENSOR = 0, - EM28XX_MT9V011, - EM28XX_MT9M001, - EM28XX_MT9M111, -}; - -enum em28xx_adecoder { - EM28XX_NOADECODER = 0, - EM28XX_TVAUDIO, -}; - -struct em28xx_board { - char *name; - int vchannels; - int tuner_type; - int tuner_addr; - - /* i2c flags */ - unsigned int tda9887_conf; - - /* GPIO sequences */ - struct em28xx_reg_seq *dvb_gpio; - struct em28xx_reg_seq *suspend_gpio; - struct em28xx_reg_seq *tuner_gpio; - struct em28xx_reg_seq *mute_gpio; - - unsigned int is_em2800:1; - unsigned int has_msp34xx:1; - unsigned int mts_firmware:1; - unsigned int max_range_640_480:1; - unsigned int has_dvb:1; - unsigned int has_snapshot_button:1; - unsigned int is_webcam:1; - unsigned int valid:1; - unsigned int has_ir_i2c:1; - - unsigned char xclk, i2c_speed; - unsigned char radio_addr; - unsigned short tvaudio_addr; - - enum em28xx_decoder decoder; - enum em28xx_adecoder adecoder; - - struct em28xx_input input[MAX_EM28XX_INPUT]; - struct em28xx_input radio; - char *ir_codes; -}; - -struct em28xx_eeprom { - u32 id; /* 0x9567eb1a */ - u16 vendor_ID; - u16 product_ID; - - u16 chip_conf; - - u16 board_conf; - - u16 string1, string2, string3; - - u8 string_idx_table; -}; - -/* device states */ -enum em28xx_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -#define EM28XX_AUDIO_BUFS 5 -#define EM28XX_NUM_AUDIO_PACKETS 64 -#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */ -#define EM28XX_CAPTURE_STREAM_EN 1 - -/* em28xx extensions */ -#define EM28XX_AUDIO 0x10 -#define EM28XX_DVB 0x20 - -/* em28xx resource types (used for res_get/res_lock etc */ -#define EM28XX_RESOURCE_VIDEO 0x01 -#define EM28XX_RESOURCE_VBI 0x02 - -struct em28xx_audio { - char name[50]; - char *transfer_buffer[EM28XX_AUDIO_BUFS]; - struct urb *urb[EM28XX_AUDIO_BUFS]; - struct usb_device *udev; - unsigned int capture_transfer_done; - struct snd_pcm_substream *capture_pcm_substream; - - unsigned int hwptr_done_capture; - struct snd_card *sndcard; - - int users; - spinlock_t slock; -}; - -struct em28xx; - -struct em28xx_fh { - struct em28xx *dev; - int radio; - unsigned int resources; - - struct videobuf_queue vb_vidq; - struct videobuf_queue vb_vbiq; - - enum v4l2_buf_type type; -}; - -/* main device struct */ -struct em28xx { - /* generic device properties */ - char name[30]; /* name (including minor) of the device */ - int model; /* index in the device_data struct */ - int devno; /* marks the number of this device */ - enum em28xx_chip_id chip_id; - - struct v4l2_device v4l2_dev; - struct em28xx_board board; - - /* Webcam specific fields */ - enum em28xx_sensor em28xx_sensor; - int sensor_xres, sensor_yres; - int sensor_xtal; - - /* Allows progressive (e. g. non-interlaced) mode */ - int progressive; - - /* Vinmode/Vinctl used at the driver */ - int vinmode, vinctl; - - unsigned int has_audio_class:1; - unsigned int has_alsa_audio:1; - - /* Controls audio streaming */ - struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ - atomic_t stream_started; /* stream should be running if true */ - - struct em28xx_fmt *format; - - struct em28xx_IR *ir; - - /* Some older em28xx chips needs a waiting time after writing */ - unsigned int wait_after_write; - - struct list_head devlist; - - u32 i2s_speed; /* I2S speed for audio digital stream */ - - struct em28xx_audio_mode audio_mode; - - int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - int tda9887_conf; - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; - /* video for linux */ - int users; /* user count for exclusive use */ - struct video_device *vdev; /* video for linux device struct */ - v4l2_std_id norm; /* selected tv norm */ - int ctl_freq; /* selected frequency */ - unsigned int ctl_input; /* selected input */ - unsigned int ctl_ainput;/* selected audio input */ - unsigned int ctl_aoutput;/* selected audio output */ - int mute; - int volume; - /* frame properties */ - int width; /* current frame width */ - int height; /* current frame height */ - unsigned hscale; /* horizontal scale factor (see datasheet) */ - unsigned vscale; /* vertical scale factor (see datasheet) */ - int interlaced; /* 1=interlace fileds, 0=just top fileds */ - unsigned int video_bytesread; /* Number of bytes read */ - - unsigned long hash; /* eeprom hash - for boards with generic ID */ - unsigned long i2c_hash; /* i2c devicelist hash - - for boards with generic ID */ - - struct em28xx_audio adev; - - /* states */ - enum em28xx_dev_state state; - enum em28xx_io_method io; - - /* vbi related state tracking */ - int capture_type; - int vbi_read; - unsigned char cur_field; - unsigned int vbi_width; - unsigned int vbi_height; /* lines per field */ - - struct work_struct request_module_wk; - - /* locks */ - struct mutex lock; - struct mutex ctrl_urb_lock; /* protects urb_buf */ - /* spinlock_t queue_lock; */ - struct list_head inqueue, outqueue; - wait_queue_head_t open, wait_frame, wait_stream; - struct video_device *vbi_dev; - struct video_device *radio_dev; - - /* resources in use */ - unsigned int resources; - - unsigned char eedata[256]; - - /* Isoc control struct */ - struct em28xx_dmaqueue vidq; - struct em28xx_dmaqueue vbiq; - struct em28xx_usb_isoc_ctl isoc_ctl; - spinlock_t slock; - - /* usb transfer */ - struct usb_device *udev; /* the usb device */ - int alt; /* alternate */ - int max_pkt_size; /* max packet size of isoc transaction */ - int num_alt; /* Number of alternative settings */ - unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ - struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ - char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc - transfer */ - char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ - - /* helper funcs that call usb_control_msg */ - int (*em28xx_write_regs) (struct em28xx *dev, u16 reg, - char *buf, int len); - int (*em28xx_read_reg) (struct em28xx *dev, u16 reg); - int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg, - char *buf, int len); - int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg, - char *buf, int len); - int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg); - - enum em28xx_mode mode; - - /* register numbers for GPO/GPIO registers */ - u16 reg_gpo_num, reg_gpio_num; - - /* Caches GPO and GPIO registers */ - unsigned char reg_gpo, reg_gpio; - - /* Snapshot button */ - char snapshot_button_path[30]; /* path of the input dev */ - struct input_dev *sbutton_input_dev; - struct delayed_work sbutton_query_work; - - struct em28xx_dvb *dvb; - - /* I2C keyboard data */ - struct IR_i2c_init_data init_data; -}; - -struct em28xx_ops { - struct list_head next; - char *name; - int id; - int (*init)(struct em28xx *); - int (*fini)(struct em28xx *); -}; - -/* Provided by em28xx-i2c.c */ -void em28xx_do_i2c_scan(struct em28xx *dev); -int em28xx_i2c_register(struct em28xx *dev); -int em28xx_i2c_unregister(struct em28xx *dev); - -/* Provided by em28xx-core.c */ - -u32 em28xx_request_buffers(struct em28xx *dev, u32 count); -void em28xx_queue_unusedframes(struct em28xx *dev); -void em28xx_release_buffers(struct em28xx *dev); - -int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, - char *buf, int len); -int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg); -int em28xx_read_reg(struct em28xx *dev, u16 reg); -int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, - int len); -int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); -int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); -int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, - u8 bitmask); - -int em28xx_read_ac97(struct em28xx *dev, u8 reg); -int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); - -int em28xx_audio_analog_set(struct em28xx *dev); -int em28xx_audio_setup(struct em28xx *dev); - -int em28xx_colorlevels_set_default(struct em28xx *dev); -int em28xx_capture_start(struct em28xx *dev, int start); -int em28xx_vbi_supported(struct em28xx *dev); -int em28xx_set_outfmt(struct em28xx *dev); -int em28xx_resolution_set(struct em28xx *dev); -int em28xx_set_alternate(struct em28xx *dev); -int em28xx_init_isoc(struct em28xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*isoc_copy) (struct em28xx *dev, struct urb *urb)); -void em28xx_uninit_isoc(struct em28xx *dev); -int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); -int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); -int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); -void em28xx_wake_i2c(struct em28xx *dev); -void em28xx_remove_from_devlist(struct em28xx *dev); -void em28xx_add_into_devlist(struct em28xx *dev); -int em28xx_register_extension(struct em28xx_ops *dev); -void em28xx_unregister_extension(struct em28xx_ops *dev); -void em28xx_init_extension(struct em28xx *dev); -void em28xx_close_extension(struct em28xx *dev); - -/* Provided by em28xx-video.c */ -int em28xx_register_analog_devices(struct em28xx *dev); -void em28xx_release_analog_resources(struct em28xx *dev); - -/* Provided by em28xx-cards.c */ -extern int em2800_variant_detect(struct usb_device *udev, int model); -extern void em28xx_pre_card_setup(struct em28xx *dev); -extern void em28xx_card_setup(struct em28xx *dev); -extern struct em28xx_board em28xx_boards[]; -extern struct usb_device_id em28xx_id_table[]; -extern const unsigned int em28xx_bcount; -void em28xx_register_i2c_ir(struct em28xx *dev); -int em28xx_tuner_callback(void *ptr, int component, int command, int arg); -void em28xx_release_resources(struct em28xx *dev); - -/* Provided by em28xx-input.c */ -int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); -int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); -int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, - u32 *ir_raw); -int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key, - u32 *ir_raw); -void em28xx_register_snapshot_button(struct em28xx *dev); -void em28xx_deregister_snapshot_button(struct em28xx *dev); - -int em28xx_ir_init(struct em28xx *dev); -int em28xx_ir_fini(struct em28xx *dev); - -/* Provided by em28xx-vbi.c */ -extern struct videobuf_queue_ops em28xx_vbi_qops; - -/* printk macros */ - -#define em28xx_err(fmt, arg...) do {\ - printk(KERN_ERR fmt , ##arg); } while (0) - -#define em28xx_errdev(fmt, arg...) do {\ - printk(KERN_ERR "%s: "fmt,\ - dev->name , ##arg); } while (0) - -#define em28xx_info(fmt, arg...) do {\ - printk(KERN_INFO "%s: "fmt,\ - dev->name , ##arg); } while (0) -#define em28xx_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s: "fmt,\ - dev->name , ##arg); } while (0) - -static inline int em28xx_compression_disable(struct em28xx *dev) -{ - /* side effect of disabling scaler and mixer */ - return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00); -} - -static inline int em28xx_contrast_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f; -} - -static inline int em28xx_brightness_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R21_YOFFSET); -} - -static inline int em28xx_saturation_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f; -} - -static inline int em28xx_u_balance_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R23_UOFFSET); -} - -static inline int em28xx_v_balance_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R24_VOFFSET); -} - -static inline int em28xx_gamma_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f; -} - -static inline int em28xx_contrast_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1); -} - -static inline int em28xx_brightness_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1); -} - -static inline int em28xx_saturation_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1); -} - -static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1); -} - -static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1); -} - -static inline int em28xx_gamma_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1); -} - -/*FIXME: maxw should be dependent of alt mode */ -static inline unsigned int norm_maxw(struct em28xx *dev) -{ - if (dev->board.is_webcam) - return dev->sensor_xres; - - if (dev->board.max_range_640_480 || dev->board.is_em2800) - return 640; - - return 720; -} - -static inline unsigned int norm_maxh(struct em28xx *dev) -{ - if (dev->board.is_webcam) - return dev->sensor_yres; - - if (dev->board.max_range_640_480) - return 480; - - return (dev->norm & V4L2_STD_625_50) ? 576 : 480; -} -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-i2c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,569 +0,0 @@ -/* - em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "em28xx.h" -#include "tuner-xc2028.h" -#include -#include - -/* ----------------------------------------------------------- */ - -static unsigned int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - - -#define dprintk1(lvl, fmt, args...) \ -do { \ - if (i2c_debug >= lvl) { \ - printk(fmt, ##args); \ - } \ -} while (0) - -#define dprintk2(lvl, fmt, args...) \ -do { \ - if (i2c_debug >= lvl) { \ - printk(KERN_DEBUG "%s at %s: " fmt, \ - dev->name, __func__ , ##args); \ - } \ -} while (0) - -/* - * em2800_i2c_send_max4() - * send up to 4 bytes to the i2c device - */ -static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr, - char *buf, int len) -{ - int ret; - int write_timeout; - unsigned char b2[6]; - BUG_ON(len < 1 || len > 4); - b2[5] = 0x80 + len - 1; - b2[4] = addr; - b2[3] = buf[0]; - if (len > 1) - b2[2] = buf[1]; - if (len > 2) - b2[1] = buf[2]; - if (len > 3) - b2[0] = buf[3]; - - ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); - if (ret != 2 + len) { - em28xx_warn("writing to i2c device failed (error=%i)\n", ret); - return -EIO; - } - for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; - write_timeout -= 5) { - ret = dev->em28xx_read_reg(dev, 0x05); - if (ret == 0x80 + len - 1) - return len; - msleep(5); - } - em28xx_warn("i2c write timed out\n"); - return -EIO; -} - -/* - * em2800_i2c_send_bytes() - */ -static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf, - short len) -{ - char *bufPtr = buf; - int ret; - int wrcount = 0; - int count; - int maxLen = 4; - struct em28xx *dev = (struct em28xx *)data; - while (len > 0) { - count = (len > maxLen) ? maxLen : len; - ret = em2800_i2c_send_max4(dev, addr, bufPtr, count); - if (ret > 0) { - len -= count; - bufPtr += count; - wrcount += count; - } else - return (ret < 0) ? ret : -EFAULT; - } - return wrcount; -} - -/* - * em2800_i2c_check_for_device() - * check if there is a i2c_device at the supplied address - */ -static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr) -{ - char msg; - int ret; - int write_timeout; - msg = addr; - ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1); - if (ret < 0) { - em28xx_warn("setting i2c device address failed (error=%i)\n", - ret); - return ret; - } - msg = 0x84; - ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1); - if (ret < 0) { - em28xx_warn("preparing i2c read failed (error=%i)\n", ret); - return ret; - } - for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; - write_timeout -= 5) { - unsigned reg = dev->em28xx_read_reg(dev, 0x5); - - if (reg == 0x94) - return -ENODEV; - else if (reg == 0x84) - return 0; - msleep(5); - } - return -ENODEV; -} - -/* - * em2800_i2c_recv_bytes() - * read from the i2c device - */ -static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, - char *buf, int len) -{ - int ret; - /* check for the device and set i2c read address */ - ret = em2800_i2c_check_for_device(dev, addr); - if (ret) { - em28xx_warn - ("preparing read at i2c address 0x%x failed (error=%i)\n", - addr, ret); - return ret; - } - ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len); - if (ret < 0) { - em28xx_warn("reading from i2c device at 0x%x failed (error=%i)", - addr, ret); - return ret; - } - return ret; -} - -/* - * em28xx_i2c_send_bytes() - * untested for more than 4 bytes - */ -static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf, - short len, int stop) -{ - int wrcount = 0; - struct em28xx *dev = (struct em28xx *)data; - - wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); - - return wrcount; -} - -/* - * em28xx_i2c_recv_bytes() - * read a byte from the i2c device - */ -static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, - char *buf, int len) -{ - int ret; - ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); - if (ret < 0) { - em28xx_warn("reading i2c device failed (error=%i)\n", ret); - return ret; - } - if (dev->em28xx_read_reg(dev, 0x5) != 0) - return -ENODEV; - return ret; -} - -/* - * em28xx_i2c_check_for_device() - * check if there is a i2c_device at the supplied address - */ -static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr) -{ - char msg; - int ret; - msg = addr; - - ret = dev->em28xx_read_reg_req(dev, 2, addr); - if (ret < 0) { - em28xx_warn("reading from i2c device failed (error=%i)\n", ret); - return ret; - } - if (dev->em28xx_read_reg(dev, 0x5) != 0) - return -ENODEV; - return 0; -} - -/* - * em28xx_i2c_xfer() - * the main i2c transfer function - */ -static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) -{ - struct em28xx *dev = i2c_adap->algo_data; - int addr, rc, i, byte; - - if (num <= 0) - return 0; - for (i = 0; i < num; i++) { - addr = msgs[i].addr << 1; - dprintk2(2, "%s %s addr=%x len=%d:", - (msgs[i].flags & I2C_M_RD) ? "read" : "write", - i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); - if (!msgs[i].len) { /* no len: check only for device presence */ - if (dev->board.is_em2800) - rc = em2800_i2c_check_for_device(dev, addr); - else - rc = em28xx_i2c_check_for_device(dev, addr); - if (rc < 0) { - dprintk2(2, " no device\n"); - return rc; - } - - } else if (msgs[i].flags & I2C_M_RD) { - /* read bytes */ - if (dev->board.is_em2800) - rc = em2800_i2c_recv_bytes(dev, addr, - msgs[i].buf, - msgs[i].len); - else - rc = em28xx_i2c_recv_bytes(dev, addr, - msgs[i].buf, - msgs[i].len); - if (i2c_debug >= 2) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } - } else { - /* write bytes */ - if (i2c_debug >= 2) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } - if (dev->board.is_em2800) - rc = em2800_i2c_send_bytes(dev, addr, - msgs[i].buf, - msgs[i].len); - else - rc = em28xx_i2c_send_bytes(dev, addr, - msgs[i].buf, - msgs[i].len, - i == num - 1); - } - if (rc < 0) - goto err; - if (i2c_debug >= 2) - printk("\n"); - } - - return num; -err: - dprintk2(2, " ERROR: %i\n", rc); - return rc; -} - -/* based on linux/sunrpc/svcauth.h and linux/hash.h - * The original hash function returns a different value, if arch is x86_64 - * or i386. - */ -static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) -{ - unsigned long hash = 0; - unsigned long l = 0; - int len = 0; - unsigned char c; - do { - if (len == length) { - c = (char)len; - len = -1; - } else - c = *buf++; - l = (l << 8) | c; - len++; - if ((len & (32 / 8 - 1)) == 0) - hash = ((hash^l) * 0x9e370001UL); - } while (len); - - return (hash >> (32 - bits)) & 0xffffffffUL; -} - -static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) -{ - unsigned char buf, *p = eedata; - struct em28xx_eeprom *em_eeprom = (void *)eedata; - int i, err, size = len, block; - - if (dev->chip_id == CHIP_ID_EM2874) { - /* Empia switched to a 16-bit addressable eeprom in newer - devices. While we could certainly write a routine to read - the eeprom, there is nothing of use in there that cannot be - accessed through registers, and there is the risk that we - could corrupt the eeprom (since a 16-bit read call is - interpreted as a write call by 8-bit eeproms). - */ - return 0; - } - - dev->i2c_client.addr = 0xa0 >> 1; - - /* Check if board has eeprom */ - err = i2c_master_recv(&dev->i2c_client, &buf, 0); - if (err < 0) { - em28xx_errdev("board has no eeprom\n"); - memset(eedata, 0, len); - return -ENODEV; - } - - buf = 0; - - err = i2c_master_send(&dev->i2c_client, &buf, 1); - if (err != 1) { - printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", - dev->name, err); - return err; - } - while (size > 0) { - if (size > 16) - block = 16; - else - block = size; - - if (block != - (err = i2c_master_recv(&dev->i2c_client, p, block))) { - printk(KERN_WARNING - "%s: i2c eeprom read error (err=%d)\n", - dev->name, err); - return err; - } - size -= block; - p += block; - } - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); - printk(" %02x", eedata[i]); - if (15 == (i % 16)) - printk("\n"); - } - - if (em_eeprom->id == 0x9567eb1a) - dev->hash = em28xx_hash_mem(eedata, len, 32); - - printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n", - dev->name, em_eeprom->id, dev->hash); - - printk(KERN_INFO "%s: EEPROM info:\n", dev->name); - - switch (em_eeprom->chip_conf >> 4 & 0x3) { - case 0: - printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name); - break; - case 1: - printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n", - dev->name); - break; - case 2: - printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n", - dev->name); - break; - case 3: - printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n", - dev->name); - break; - } - - if (em_eeprom->chip_conf & 1 << 3) - printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name); - - if (em_eeprom->chip_conf & 1 << 2) - printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name); - - switch (em_eeprom->chip_conf & 0x3) { - case 0: - printk(KERN_INFO "%s:\t500mA max power\n", dev->name); - break; - case 1: - printk(KERN_INFO "%s:\t400mA max power\n", dev->name); - break; - case 2: - printk(KERN_INFO "%s:\t300mA max power\n", dev->name); - break; - case 3: - printk(KERN_INFO "%s:\t200mA max power\n", dev->name); - break; - } - printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", - dev->name, - em_eeprom->string_idx_table, - em_eeprom->string1, - em_eeprom->string2, - em_eeprom->string3); - - return 0; -} - -/* ----------------------------------------------------------- */ - -/* - * functionality() - */ -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm em28xx_algo = { - .master_xfer = em28xx_i2c_xfer, - .functionality = functionality, -}; - -static struct i2c_adapter em28xx_adap_template = { - .owner = THIS_MODULE, - .name = "em28xx", - .algo = &em28xx_algo, -}; - -static struct i2c_client em28xx_client_template = { - .name = "em28xx internal", -}; - -/* ----------------------------------------------------------- */ - -/* - * i2c_devs - * incomplete list of known devices - */ -static char *i2c_devs[128] = { - [0x4a >> 1] = "saa7113h", - [0x60 >> 1] = "remote IR sensor", - [0x8e >> 1] = "remote IR sensor", - [0x86 >> 1] = "tda9887", - [0x80 >> 1] = "msp34xx", - [0x88 >> 1] = "msp34xx", - [0xa0 >> 1] = "eeprom", - [0xb0 >> 1] = "tda9874", - [0xb8 >> 1] = "tvp5150a", - [0xba >> 1] = "webcam sensor or tvp5150a", - [0xc0 >> 1] = "tuner (analog)", - [0xc2 >> 1] = "tuner (analog)", - [0xc4 >> 1] = "tuner (analog)", - [0xc6 >> 1] = "tuner (analog)", -}; - -/* - * do_i2c_scan() - * check i2c address range for devices - */ -void em28xx_do_i2c_scan(struct em28xx *dev) -{ - u8 i2c_devicelist[128]; - unsigned char buf; - int i, rc; - - memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); - - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - dev->i2c_client.addr = i; - rc = i2c_master_recv(&dev->i2c_client, &buf, 0); - if (rc < 0) - continue; - i2c_devicelist[i] = i; - printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", - dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); - } - - dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, - ARRAY_SIZE(i2c_devicelist), 32); -} - -/* - * em28xx_i2c_register() - * register i2c bus - */ -int em28xx_i2c_register(struct em28xx *dev) -{ - int retval; - - BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); - BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); - dev->i2c_adap = em28xx_adap_template; - dev->i2c_adap.dev.parent = &dev->udev->dev; - strcpy(dev->i2c_adap.name, dev->name); - dev->i2c_adap.algo_data = dev; - i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); - - retval = i2c_add_adapter(&dev->i2c_adap); - if (retval < 0) { - em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n", - __func__, retval); - return retval; - } - - dev->i2c_client = em28xx_client_template; - dev->i2c_client.adapter = &dev->i2c_adap; - - retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); - if ((retval < 0) && (retval != -ENODEV)) { - em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", - __func__, retval); - - return retval; - } - - if (i2c_scan) - em28xx_do_i2c_scan(dev); - - /* Instantiate the IR receiver device, if present */ - em28xx_register_i2c_ir(dev); - - return 0; -} - -/* - * em28xx_i2c_unregister() - * unregister i2c_bus - */ -int em28xx_i2c_unregister(struct em28xx *dev) -{ - i2c_del_adapter(&dev->i2c_adap); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-input.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-input.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,559 +0,0 @@ -/* - handle em28xx IR remotes via linux kernel input layer. - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - - 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, or - (at your option) any later version. - - 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 -#include -#include -#include -#include -#include - -#include "em28xx.h" - -#define EM28XX_SNAPSHOT_KEY KEY_CAMERA -#define EM28XX_SBUTTON_QUERY_INTERVAL 500 -#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20 - -static unsigned int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); - -#define MODULE_NAME "em28xx" - -#define i2cdprintk(fmt, arg...) \ - if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ - } - -#define dprintk(fmt, arg...) \ - if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ - } - -/********************************************************** - Polling structure used by em28xx IR's - **********************************************************/ - -struct em28xx_ir_poll_result { - unsigned int toggle_bit:1; - unsigned int read_count:7; - u8 rc_address; - u8 rc_data[4]; /* 1 byte on em2860/2880, 4 on em2874 */ -}; - -struct em28xx_IR { - struct em28xx *dev; - struct rc_dev *rc; - char name[32]; - char phys[32]; - - /* poll external decoder */ - int polling; - struct delayed_work work; - unsigned int full_code:1; - unsigned int last_readcount; - - int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); -}; - -/********************************************************** - I2C IR based get keycodes - should be used with ir-kbd-i2c - **********************************************************/ - -int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char b; - - /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); - return -EIO; - } - - /* it seems that 0xFE indicates that a button is still hold - down, while 0xff indicates that no button is hold - down. 0xfe sequences are sometimes interrupted by 0xFF */ - - i2cdprintk("key %02x\n", b); - - if (b == 0xff) - return 0; - - if (b == 0xfe) - /* keep old data */ - return 1; - - *ir_key = b; - *ir_raw = b; - return 1; -} - -int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char buf[2]; - u16 code; - int size; - - /* poll IR chip */ - size = i2c_master_recv(ir->c, buf, sizeof(buf)); - - if (size != 2) - return -EIO; - - /* Does eliminate repeated parity code */ - if (buf[1] == 0xff) - return 0; - - ir->old = buf[1]; - - /* - * Rearranges bits to the right order. - * The bit order were determined experimentally by using - * The original Hauppauge Grey IR and another RC5 that uses addr=0x08 - * The RC5 code has 14 bits, but we've experimentally determined - * the meaning for only 11 bits. - * So, the code translation is not complete. Yet, it is enough to - * work with the provided RC5 IR. - */ - code = - ((buf[0] & 0x01) ? 0x0020 : 0) | /* 0010 0000 */ - ((buf[0] & 0x02) ? 0x0010 : 0) | /* 0001 0000 */ - ((buf[0] & 0x04) ? 0x0008 : 0) | /* 0000 1000 */ - ((buf[0] & 0x08) ? 0x0004 : 0) | /* 0000 0100 */ - ((buf[0] & 0x10) ? 0x0002 : 0) | /* 0000 0010 */ - ((buf[0] & 0x20) ? 0x0001 : 0) | /* 0000 0001 */ - ((buf[1] & 0x08) ? 0x1000 : 0) | /* 0001 0000 */ - ((buf[1] & 0x10) ? 0x0800 : 0) | /* 0000 1000 */ - ((buf[1] & 0x20) ? 0x0400 : 0) | /* 0000 0100 */ - ((buf[1] & 0x40) ? 0x0200 : 0) | /* 0000 0010 */ - ((buf[1] & 0x80) ? 0x0100 : 0); /* 0000 0001 */ - - i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x%02x)\n", - code, buf[1], buf[0]); - - /* return key */ - *ir_key = code; - *ir_raw = code; - return 1; -} - -int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, - u32 *ir_raw) -{ - unsigned char buf[3]; - - /* poll IR chip */ - - if (3 != i2c_master_recv(ir->c, buf, 3)) { - i2cdprintk("read error\n"); - return -EIO; - } - - i2cdprintk("key %02x\n", buf[2]&0x3f); - if (buf[0] != 0x00) - return 0; - - *ir_key = buf[2]&0x3f; - *ir_raw = buf[2]&0x3f; - - return 1; -} - -int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char subaddr, keydetect, key; - - struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, .buf = &subaddr, .len = 1}, - - { .addr = ir->c->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} }; - - subaddr = 0x10; - if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { - i2cdprintk("read error\n"); - return -EIO; - } - if (keydetect == 0x00) - return 0; - - subaddr = 0x00; - msg[1].buf = &key; - if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { - i2cdprintk("read error\n"); - return -EIO; - } - if (key == 0x00) - return 0; - - *ir_key = key; - *ir_raw = key; - return 1; -} - -/********************************************************** - Poll based get keycode functions - **********************************************************/ - -/* This is for the em2860/em2880 */ -static int default_polling_getkey(struct em28xx_IR *ir, - struct em28xx_ir_poll_result *poll_result) -{ - struct em28xx *dev = ir->dev; - int rc; - u8 msg[3] = { 0, 0, 0 }; - - /* Read key toggle, brand, and key code - on registers 0x45, 0x46 and 0x47 - */ - rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR, - msg, sizeof(msg)); - if (rc < 0) - return rc; - - /* Infrared toggle (Reg 0x45[7]) */ - poll_result->toggle_bit = (msg[0] >> 7); - - /* Infrared read count (Reg 0x45[6:0] */ - poll_result->read_count = (msg[0] & 0x7f); - - /* Remote Control Address (Reg 0x46) */ - poll_result->rc_address = msg[1]; - - /* Remote Control Data (Reg 0x47) */ - poll_result->rc_data[0] = msg[2]; - - return 0; -} - -static int em2874_polling_getkey(struct em28xx_IR *ir, - struct em28xx_ir_poll_result *poll_result) -{ - struct em28xx *dev = ir->dev; - int rc; - u8 msg[5] = { 0, 0, 0, 0, 0 }; - - /* Read key toggle, brand, and key code - on registers 0x51-55 - */ - rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR, - msg, sizeof(msg)); - if (rc < 0) - return rc; - - /* Infrared toggle (Reg 0x51[7]) */ - poll_result->toggle_bit = (msg[0] >> 7); - - /* Infrared read count (Reg 0x51[6:0] */ - poll_result->read_count = (msg[0] & 0x7f); - - /* Remote Control Address (Reg 0x52) */ - poll_result->rc_address = msg[1]; - - /* Remote Control Data (Reg 0x53-55) */ - poll_result->rc_data[0] = msg[2]; - poll_result->rc_data[1] = msg[3]; - poll_result->rc_data[2] = msg[4]; - - return 0; -} - -/********************************************************** - Polling code for em28xx - **********************************************************/ - -static void em28xx_ir_handle_key(struct em28xx_IR *ir) -{ - int result; - struct em28xx_ir_poll_result poll_result; - - /* read the registers containing the IR status */ - result = ir->get_key(ir, &poll_result); - if (unlikely(result < 0)) { - dprintk("ir->get_key() failed %d\n", result); - return; - } - - if (unlikely(poll_result.read_count != ir->last_readcount)) { - dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__, - poll_result.toggle_bit, poll_result.read_count, - poll_result.rc_address, poll_result.rc_data[0]); - if (ir->full_code) - rc_keydown(ir->rc, - poll_result.rc_address << 8 | - poll_result.rc_data[0], - poll_result.toggle_bit); - else - rc_keydown(ir->rc, - poll_result.rc_data[0], - poll_result.toggle_bit); - - if (ir->dev->chip_id == CHIP_ID_EM2874) - /* The em2874 clears the readcount field every time the - register is read. The em2860/2880 datasheet says that it - is supposed to clear the readcount, but it doesn't. So with - the em2874, we are looking for a non-zero read count as - opposed to a readcount that is incrementing */ - ir->last_readcount = 0; - else - ir->last_readcount = poll_result.read_count; - } -} - -static void em28xx_ir_work(struct work_struct *work) -{ - struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work); - - em28xx_ir_handle_key(ir); - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); -} - -static int em28xx_ir_start(struct rc_dev *rc) -{ - struct em28xx_IR *ir = rc->priv; - - INIT_DELAYED_WORK(&ir->work, em28xx_ir_work); - schedule_delayed_work(&ir->work, 0); - - return 0; -} - -static void em28xx_ir_stop(struct rc_dev *rc) -{ - struct em28xx_IR *ir = rc->priv; - - cancel_delayed_work_sync(&ir->work); -} - -int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) -{ - int rc = 0; - struct em28xx_IR *ir = rc_dev->priv; - struct em28xx *dev = ir->dev; - u8 ir_config = EM2874_IR_RC5; - - /* Adjust xclk based o IR table for RC5/NEC tables */ - - if (rc_type == RC_TYPE_RC5) { - dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE; - ir->full_code = 1; - } else if (rc_type == RC_TYPE_NEC) { - dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE; - ir_config = EM2874_IR_NEC; - ir->full_code = 1; - } else if (rc_type != RC_TYPE_UNKNOWN) - rc = -EINVAL; - - em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk, - EM28XX_XCLK_IR_RC5_MODE); - - /* Setup the proper handler based on the chip */ - switch (dev->chip_id) { - case CHIP_ID_EM2860: - case CHIP_ID_EM2883: - ir->get_key = default_polling_getkey; - break; - case CHIP_ID_EM2874: - ir->get_key = em2874_polling_getkey; - em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); - break; - default: - printk("Unrecognized em28xx chip id: IR not supported\n"); - rc = -EINVAL; - } - - return rc; -} - -int em28xx_ir_init(struct em28xx *dev) -{ - struct em28xx_IR *ir; - struct rc_dev *rc; - int err = -ENOMEM; - - if (dev->board.ir_codes == NULL) { - /* No remote control support */ - return 0; - } - - ir = kzalloc(sizeof(*ir), GFP_KERNEL); - rc = rc_allocate_device(); - if (!ir || !rc) - goto err_out_free; - - /* record handles to ourself */ - ir->dev = dev; - dev->ir = ir; - ir->rc = rc; - - /* - * em2874 supports more protocols. For now, let's just announce - * the two protocols that were already tested - */ - rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; - rc->priv = ir; - rc->change_protocol = em28xx_ir_change_protocol; - rc->open = em28xx_ir_start; - rc->close = em28xx_ir_stop; - - /* By default, keep protocol field untouched */ - err = em28xx_ir_change_protocol(rc, RC_TYPE_UNKNOWN); - if (err) - goto err_out_free; - - /* This is how often we ask the chip for IR information */ - ir->polling = 100; /* ms */ - - /* init input device */ - snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", - dev->name); - - usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); - strlcat(ir->phys, "/input0", sizeof(ir->phys)); - - rc->input_name = ir->name; - rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_USB; - rc->input_id.version = 1; - rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); - rc->dev.parent = &dev->udev->dev; - rc->map_name = dev->board.ir_codes; - rc->driver_name = MODULE_NAME; - - /* all done */ - err = rc_register_device(rc); - if (err) - goto err_out_stop; - - return 0; - - err_out_stop: - dev->ir = NULL; - err_out_free: - rc_free_device(rc); - kfree(ir); - return err; -} - -int em28xx_ir_fini(struct em28xx *dev) -{ - struct em28xx_IR *ir = dev->ir; - - /* skip detach on non attached boards */ - if (!ir) - return 0; - - em28xx_ir_stop(ir->rc); - rc_unregister_device(ir->rc); - kfree(ir); - - /* done */ - dev->ir = NULL; - return 0; -} - -/********************************************************** - Handle Webcam snapshot button - **********************************************************/ - -static void em28xx_query_sbutton(struct work_struct *work) -{ - /* Poll the register and see if the button is depressed */ - struct em28xx *dev = - container_of(work, struct em28xx, sbutton_query_work.work); - int ret; - - ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP); - - if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) { - u8 cleared; - /* Button is depressed, clear the register */ - cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT; - em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1); - - /* Not emulate the keypress */ - input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, - 1); - /* Now unpress the key */ - input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, - 0); - } - - /* Schedule next poll */ - schedule_delayed_work(&dev->sbutton_query_work, - msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); -} - -void em28xx_register_snapshot_button(struct em28xx *dev) -{ - struct input_dev *input_dev; - int err; - - em28xx_info("Registering snapshot button...\n"); - input_dev = input_allocate_device(); - if (!input_dev) { - em28xx_errdev("input_allocate_device failed\n"); - return; - } - - usb_make_path(dev->udev, dev->snapshot_button_path, - sizeof(dev->snapshot_button_path)); - strlcat(dev->snapshot_button_path, "/sbutton", - sizeof(dev->snapshot_button_path)); - INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton); - - input_dev->name = "em28xx snapshot button"; - input_dev->phys = dev->snapshot_button_path; - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit); - input_dev->keycodesize = 0; - input_dev->keycodemax = 0; - input_dev->id.bustype = BUS_USB; - input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); - input_dev->id.version = 1; - input_dev->dev.parent = &dev->udev->dev; - - err = input_register_device(input_dev); - if (err) { - em28xx_errdev("input_register_device failed\n"); - input_free_device(input_dev); - return; - } - - dev->sbutton_input_dev = input_dev; - schedule_delayed_work(&dev->sbutton_query_work, - msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); - return; - -} - -void em28xx_deregister_snapshot_button(struct em28xx *dev) -{ - if (dev->sbutton_input_dev != NULL) { - em28xx_info("Deregistering snapshot button\n"); - cancel_delayed_work_sync(&dev->sbutton_query_work); - input_unregister_device(dev->sbutton_input_dev); - dev->sbutton_input_dev = NULL; - } - return; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,268 +0,0 @@ -#define EM_GPIO_0 (1 << 0) -#define EM_GPIO_1 (1 << 1) -#define EM_GPIO_2 (1 << 2) -#define EM_GPIO_3 (1 << 3) -#define EM_GPIO_4 (1 << 4) -#define EM_GPIO_5 (1 << 5) -#define EM_GPIO_6 (1 << 6) -#define EM_GPIO_7 (1 << 7) - -#define EM_GPO_0 (1 << 0) -#define EM_GPO_1 (1 << 1) -#define EM_GPO_2 (1 << 2) -#define EM_GPO_3 (1 << 3) - -/* em2800 registers */ -#define EM2800_R08_AUDIOSRC 0x08 - -/* em28xx registers */ - -#define EM28XX_R00_CHIPCFG 0x00 - -/* em28xx Chip Configuration 0x00 */ -#define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80 -#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40 -#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x30 -#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x20 -#define EM28XX_CHIPCFG_AC97 0x10 -#define EM28XX_CHIPCFG_AUDIOMASK 0x30 - -#define EM28XX_R01_CHIPCFG2 0x01 - -/* em28xx Chip Configuration 2 0x01 */ -#define EM28XX_CHIPCFG2_TS_PRESENT 0x10 -#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_MASK 0x0c /* bits 3-2 */ -#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_1MF 0x00 -#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_2MF 0x04 -#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_4MF 0x08 -#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_8MF 0x0c -#define EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK 0x03 /* bits 0-1 */ -#define EM28XX_CHIPCFG2_TS_PACKETSIZE_188 0x00 -#define EM28XX_CHIPCFG2_TS_PACKETSIZE_376 0x01 -#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564 0x02 -#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03 - - - /* GPIO/GPO registers */ -#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */ -#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ - -#define EM28XX_R06_I2C_CLK 0x06 - -/* em28xx I2C Clock Register (0x06) */ -#define EM28XX_I2C_CLK_ACK_LAST_READ 0x80 -#define EM28XX_I2C_CLK_WAIT_ENABLE 0x40 -#define EM28XX_I2C_EEPROM_ON_BOARD 0x08 -#define EM28XX_I2C_EEPROM_KEY_VALID 0x04 -#define EM2874_I2C_SECONDARY_BUS_SELECT 0x04 /* em2874 has two i2c busses */ -#define EM28XX_I2C_FREQ_1_5_MHZ 0x03 /* bus frequency (bits [1-0]) */ -#define EM28XX_I2C_FREQ_25_KHZ 0x02 -#define EM28XX_I2C_FREQ_400_KHZ 0x01 -#define EM28XX_I2C_FREQ_100_KHZ 0x00 - - -#define EM28XX_R0A_CHIPID 0x0a -#define EM28XX_R0C_USBSUSP 0x0c /* */ - -#define EM28XX_R0E_AUDIOSRC 0x0e -#define EM28XX_R0F_XCLK 0x0f - -/* em28xx XCLK Register (0x0f) */ -#define EM28XX_XCLK_AUDIO_UNMUTE 0x80 /* otherwise audio muted */ -#define EM28XX_XCLK_I2S_MSB_TIMING 0x40 /* otherwise standard timing */ -#define EM28XX_XCLK_IR_RC5_MODE 0x20 /* otherwise NEC mode */ -#define EM28XX_XCLK_IR_NEC_CHK_PARITY 0x10 -#define EM28XX_XCLK_FREQUENCY_30MHZ 0x00 /* Freq. select (bits [3-0]) */ -#define EM28XX_XCLK_FREQUENCY_15MHZ 0x01 -#define EM28XX_XCLK_FREQUENCY_10MHZ 0x02 -#define EM28XX_XCLK_FREQUENCY_7_5MHZ 0x03 -#define EM28XX_XCLK_FREQUENCY_6MHZ 0x04 -#define EM28XX_XCLK_FREQUENCY_5MHZ 0x05 -#define EM28XX_XCLK_FREQUENCY_4_3MHZ 0x06 -#define EM28XX_XCLK_FREQUENCY_12MHZ 0x07 -#define EM28XX_XCLK_FREQUENCY_20MHZ 0x08 -#define EM28XX_XCLK_FREQUENCY_20MHZ_2 0x09 -#define EM28XX_XCLK_FREQUENCY_48MHZ 0x0a -#define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b - -#define EM28XX_R10_VINMODE 0x10 - -#define EM28XX_R11_VINCTRL 0x11 - -/* em28xx Video Input Control Register 0x11 */ -#define EM28XX_VINCTRL_VBI_SLICED 0x80 -#define EM28XX_VINCTRL_VBI_RAW 0x40 -#define EM28XX_VINCTRL_VOUT_MODE_IN 0x20 /* HREF,VREF,VACT in output */ -#define EM28XX_VINCTRL_CCIR656_ENABLE 0x10 -#define EM28XX_VINCTRL_VBI_16BIT_RAW 0x08 /* otherwise 8-bit raw */ -#define EM28XX_VINCTRL_FID_ON_HREF 0x04 -#define EM28XX_VINCTRL_DUAL_EDGE_STROBE 0x02 -#define EM28XX_VINCTRL_INTERLACED 0x01 - -#define EM28XX_R12_VINENABLE 0x12 /* */ - -#define EM28XX_R14_GAMMA 0x14 -#define EM28XX_R15_RGAIN 0x15 -#define EM28XX_R16_GGAIN 0x16 -#define EM28XX_R17_BGAIN 0x17 -#define EM28XX_R18_ROFFSET 0x18 -#define EM28XX_R19_GOFFSET 0x19 -#define EM28XX_R1A_BOFFSET 0x1a - -#define EM28XX_R1B_OFLOW 0x1b -#define EM28XX_R1C_HSTART 0x1c -#define EM28XX_R1D_VSTART 0x1d -#define EM28XX_R1E_CWIDTH 0x1e -#define EM28XX_R1F_CHEIGHT 0x1f - -#define EM28XX_R20_YGAIN 0x20 -#define EM28XX_R21_YOFFSET 0x21 -#define EM28XX_R22_UVGAIN 0x22 -#define EM28XX_R23_UOFFSET 0x23 -#define EM28XX_R24_VOFFSET 0x24 -#define EM28XX_R25_SHARPNESS 0x25 - -#define EM28XX_R26_COMPR 0x26 -#define EM28XX_R27_OUTFMT 0x27 - -/* em28xx Output Format Register (0x27) */ -#define EM28XX_OUTFMT_RGB_8_RGRG 0x00 -#define EM28XX_OUTFMT_RGB_8_GRGR 0x01 -#define EM28XX_OUTFMT_RGB_8_GBGB 0x02 -#define EM28XX_OUTFMT_RGB_8_BGBG 0x03 -#define EM28XX_OUTFMT_RGB_16_656 0x04 -#define EM28XX_OUTFMT_RGB_8_BAYER 0x08 /* Pattern in Reg 0x10[1-0] */ -#define EM28XX_OUTFMT_YUV211 0x10 -#define EM28XX_OUTFMT_YUV422_Y0UY1V 0x14 -#define EM28XX_OUTFMT_YUV422_Y1UY0V 0x15 -#define EM28XX_OUTFMT_YUV411 0x18 - - -#define EM28XX_R28_XMIN 0x28 -#define EM28XX_R29_XMAX 0x29 -#define EM28XX_R2A_YMIN 0x2a -#define EM28XX_R2B_YMAX 0x2b - -#define EM28XX_R30_HSCALELOW 0x30 -#define EM28XX_R31_HSCALEHIGH 0x31 -#define EM28XX_R32_VSCALELOW 0x32 -#define EM28XX_R33_VSCALEHIGH 0x33 -#define EM28XX_R34_VBI_START_H 0x34 -#define EM28XX_R35_VBI_START_V 0x35 -#define EM28XX_R36_VBI_WIDTH 0x36 -#define EM28XX_R37_VBI_HEIGHT 0x37 - -#define EM28XX_R40_AC97LSB 0x40 -#define EM28XX_R41_AC97MSB 0x41 -#define EM28XX_R42_AC97ADDR 0x42 -#define EM28XX_R43_AC97BUSY 0x43 - -#define EM28XX_R45_IR 0x45 - /* 0x45 bit 7 - parity bit - bits 6-0 - count - 0x46 IR brand - 0x47 IR data - */ - -/* em2874 registers */ -#define EM2874_R50_IR_CONFIG 0x50 -#define EM2874_R51_IR 0x51 -#define EM2874_R5F_TS_ENABLE 0x5f -#define EM2874_R80_GPIO 0x80 - -/* em2874 IR config register (0x50) */ -#define EM2874_IR_NEC 0x00 -#define EM2874_IR_RC5 0x04 -#define EM2874_IR_RC6_MODE_0 0x08 -#define EM2874_IR_RC6_MODE_6A 0x0b - -/* em2874 Transport Stream Enable Register (0x5f) */ -#define EM2874_TS1_CAPTURE_ENABLE (1 << 0) -#define EM2874_TS1_FILTER_ENABLE (1 << 1) -#define EM2874_TS1_NULL_DISCARD (1 << 2) -#define EM2874_TS2_CAPTURE_ENABLE (1 << 4) -#define EM2874_TS2_FILTER_ENABLE (1 << 5) -#define EM2874_TS2_NULL_DISCARD (1 << 6) - -/* register settings */ -#define EM2800_AUDIO_SRC_TUNER 0x0d -#define EM2800_AUDIO_SRC_LINE 0x0c -#define EM28XX_AUDIO_SRC_TUNER 0xc0 -#define EM28XX_AUDIO_SRC_LINE 0x80 - -/* FIXME: Need to be populated with the other chip ID's */ -enum em28xx_chip_id { - CHIP_ID_EM2800 = 7, - CHIP_ID_EM2710 = 17, - CHIP_ID_EM2820 = 18, /* Also used by some em2710 */ - CHIP_ID_EM2840 = 20, - CHIP_ID_EM2750 = 33, - CHIP_ID_EM2860 = 34, - CHIP_ID_EM2870 = 35, - CHIP_ID_EM2883 = 36, - CHIP_ID_EM2874 = 65, -}; - -/* - * Registers used by em202 and other AC97 chips - */ - -/* Standard AC97 registers */ -#define AC97_RESET 0x00 - - /* Output volumes */ -#define AC97_MASTER_VOL 0x02 -#define AC97_LINE_LEVEL_VOL 0x04 /* Some devices use for headphones */ -#define AC97_MASTER_MONO_VOL 0x06 - - /* Input volumes */ -#define AC97_PC_BEEP_VOL 0x0a -#define AC97_PHONE_VOL 0x0c -#define AC97_MIC_VOL 0x0e -#define AC97_LINEIN_VOL 0x10 -#define AC97_CD_VOL 0x12 -#define AC97_VIDEO_VOL 0x14 -#define AC97_AUX_VOL 0x16 -#define AC97_PCM_OUT_VOL 0x18 - - /* capture registers */ -#define AC97_RECORD_SELECT 0x1a -#define AC97_RECORD_GAIN 0x1c - - /* control registers */ -#define AC97_GENERAL_PURPOSE 0x20 -#define AC97_3D_CTRL 0x22 -#define AC97_AUD_INT_AND_PAG 0x24 -#define AC97_POWER_DOWN_CTRL 0x26 -#define AC97_EXT_AUD_ID 0x28 -#define AC97_EXT_AUD_CTRL 0x2a - -/* Supported rate varies for each AC97 device - if write an unsupported value, it will return the closest one - */ -#define AC97_PCM_OUT_FRONT_SRATE 0x2c -#define AC97_PCM_OUT_SURR_SRATE 0x2e -#define AC97_PCM_OUT_LFE_SRATE 0x30 -#define AC97_PCM_IN_SRATE 0x32 - - /* For devices with more than 2 channels, extra output volumes */ -#define AC97_LFE_MASTER_VOL 0x36 -#define AC97_SURR_MASTER_VOL 0x38 - - /* Digital SPDIF output control */ -#define AC97_SPDIF_OUT_CTRL 0x3a - - /* Vendor ID identifier */ -#define AC97_VENDOR_ID1 0x7c -#define AC97_VENDOR_ID2 0x7e - -/* EMP202 vendor registers */ -#define EM202_EXT_MODEM_CTRL 0x3e -#define EM202_GPIO_CONF 0x4c -#define EM202_GPIO_POLARITY 0x4e -#define EM202_GPIO_STICKY 0x50 -#define EM202_GPIO_MASK 0x52 -#define EM202_GPIO_STATUS 0x54 -#define EM202_SPDIF_OUT_SEL 0x6a -#define EM202_ANTIPOP 0x72 -#define EM202_EAPD_GPIO_ACCESS 0x74 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-vbi.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -/* - em28xx-vbi.c - VBI driver for em28xx - - Copyright (C) 2009 Devin Heitmueller - - This work was sponsored by EyeMagnet Limited. - - 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, or - (at your option) any later version. - - 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., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - */ - -#include -#include -#include -#include - -#include "em28xx.h" - -static unsigned int vbibufs = 5; -module_param(vbibufs, int, 0644); -MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); - -static unsigned int vbi_debug; -module_param(vbi_debug, int, 0644); -MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); - -#define dprintk(level, fmt, arg...) if (vbi_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg) - -/* ------------------------------------------------------------------ */ - -static void -free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) -{ - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = fh->dev; - unsigned long flags = 0; - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.vbi_buf == buf) - dev->isoc_ctl.vbi_buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct em28xx_fh *fh = q->priv_data; - struct em28xx *dev = fh->dev; - - *size = dev->vbi_width * dev->vbi_height * 2; - - if (0 == *count) - *count = vbibufs; - if (*count < 2) - *count = 2; - if (*count > 32) - *count = 32; - return 0; -} - -static int -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct em28xx_fh *fh = q->priv_data; - struct em28xx *dev = fh->dev; - struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); - int rc = 0; - - buf->vb.size = dev->vbi_width * dev->vbi_height * 2; - - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - buf->vb.width = dev->vbi_width; - buf->vb.height = dev->vbi_height; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(q, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(q, buf); - return rc; -} - -static void -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct em28xx_buffer *buf = container_of(vb, - struct em28xx_buffer, - vb); - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = fh->dev; - struct em28xx_dmaqueue *vbiq = &dev->vbiq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vbiq->active); -} - -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); - free_buffer(q, buf); -} - -struct videobuf_queue_ops em28xx_vbi_qops = { - .buf_setup = vbi_setup, - .buf_prepare = vbi_prepare, - .buf_queue = vbi_queue, - .buf_release = vbi_release, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-video.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/em28xx-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2539 +0,0 @@ -/* - em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - - Some parts based on SN9C10x PC Camera Controllers GPL driver made - by Luca Risolia - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "em28xx.h" -#include -#include -#include -#include -#include - -#define DRIVER_AUTHOR "Ludovico Cavedon , " \ - "Markus Rechberger , " \ - "Mauro Carvalho Chehab , " \ - "Sascha Sommer " - -#define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 2) - -#define em28xx_videodbg(fmt, arg...) do {\ - if (video_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -static unsigned int isoc_debug; -module_param(isoc_debug, int, 0644); -MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); - -#define em28xx_isocdbg(fmt, arg...) \ -do {\ - if (isoc_debug) { \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); \ - } \ - } while (0) - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; - -module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); -MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); - -static unsigned int video_debug; -module_param(video_debug, int, 0644); -MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); - -/* supported video standards */ -static struct em28xx_fmt format[] = { - { - .name = "16 bpp YUY2, 4:2:2, packed", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .reg = EM28XX_OUTFMT_YUV422_Y0UY1V, - }, { - .name = "16 bpp RGB 565, LE", - .fourcc = V4L2_PIX_FMT_RGB565, - .depth = 16, - .reg = EM28XX_OUTFMT_RGB_16_656, - }, { - .name = "8 bpp Bayer BGBG..GRGR", - .fourcc = V4L2_PIX_FMT_SBGGR8, - .depth = 8, - .reg = EM28XX_OUTFMT_RGB_8_BGBG, - }, { - .name = "8 bpp Bayer GRGR..BGBG", - .fourcc = V4L2_PIX_FMT_SGRBG8, - .depth = 8, - .reg = EM28XX_OUTFMT_RGB_8_GRGR, - }, { - .name = "8 bpp Bayer GBGB..RGRG", - .fourcc = V4L2_PIX_FMT_SGBRG8, - .depth = 8, - .reg = EM28XX_OUTFMT_RGB_8_GBGB, - }, { - .name = "12 bpp YUV411", - .fourcc = V4L2_PIX_FMT_YUV411P, - .depth = 12, - .reg = EM28XX_OUTFMT_YUV411, - }, -}; - -/* supported controls */ -/* Common to all boards */ -static struct v4l2_queryctrl ac97_qctrl[] = { - { - .id = V4L2_CID_AUDIO_VOLUME, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Volume", - .minimum = 0x0, - .maximum = 0x1f, - .step = 0x1, - .default_value = 0x1f, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_AUDIO_MUTE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - .flags = 0, - } -}; - -/* ------------------------------------------------------------------ - DMA and thread functions - ------------------------------------------------------------------*/ - -/* - * Announces that a buffer were filled and request the next - */ -static inline void buffer_filled(struct em28xx *dev, - struct em28xx_dmaqueue *dma_q, - struct em28xx_buffer *buf) -{ - /* Advice that buffer was filled */ - em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - - dev->isoc_ctl.vid_buf = NULL; - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -static inline void vbi_buffer_filled(struct em28xx *dev, - struct em28xx_dmaqueue *dma_q, - struct em28xx_buffer *buf) -{ - /* Advice that buffer was filled */ - em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); - - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - - dev->isoc_ctl.vbi_buf = NULL; - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -/* - * Identify the buffer header type and properly handles - */ -static void em28xx_copy_video(struct em28xx *dev, - struct em28xx_dmaqueue *dma_q, - struct em28xx_buffer *buf, - unsigned char *p, - unsigned char *outp, unsigned long len) -{ - void *fieldstart, *startwrite, *startread; - int linesdone, currlinedone, offset, lencopy, remain; - int bytesperline = dev->width << 1; - - if (dma_q->pos + len > buf->vb.size) - len = buf->vb.size - dma_q->pos; - - startread = p; - remain = len; - - if (dev->progressive) - fieldstart = outp; - else { - /* Interlaces two half frames */ - if (buf->top_field) - fieldstart = outp; - else - fieldstart = outp + bytesperline; - } - - linesdone = dma_q->pos / bytesperline; - currlinedone = dma_q->pos % bytesperline; - - if (dev->progressive) - offset = linesdone * bytesperline + currlinedone; - else - offset = linesdone * bytesperline * 2 + currlinedone; - - startwrite = fieldstart + offset; - lencopy = bytesperline - currlinedone; - lencopy = lencopy > remain ? remain : lencopy; - - if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) { - em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n", - ((char *)startwrite + lencopy) - - ((char *)outp + buf->vb.size)); - remain = (char *)outp + buf->vb.size - (char *)startwrite; - lencopy = remain; - } - if (lencopy <= 0) - return; - memcpy(startwrite, startread, lencopy); - - remain -= lencopy; - - while (remain > 0) { - startwrite += lencopy + bytesperline; - startread += lencopy; - if (bytesperline > remain) - lencopy = remain; - else - lencopy = bytesperline; - - if ((char *)startwrite + lencopy > (char *)outp + - buf->vb.size) { - em28xx_isocdbg("Overflow of %zi bytes past buffer end" - "(2)\n", - ((char *)startwrite + lencopy) - - ((char *)outp + buf->vb.size)); - lencopy = remain = (char *)outp + buf->vb.size - - (char *)startwrite; - } - if (lencopy <= 0) - break; - - memcpy(startwrite, startread, lencopy); - - remain -= lencopy; - } - - dma_q->pos += len; -} - -static void em28xx_copy_vbi(struct em28xx *dev, - struct em28xx_dmaqueue *dma_q, - struct em28xx_buffer *buf, - unsigned char *p, - unsigned char *outp, unsigned long len) -{ - void *startwrite, *startread; - int offset; - int bytesperline; - - if (dev == NULL) { - em28xx_isocdbg("dev is null\n"); - return; - } - bytesperline = dev->vbi_width; - - if (dma_q == NULL) { - em28xx_isocdbg("dma_q is null\n"); - return; - } - if (buf == NULL) { - return; - } - if (p == NULL) { - em28xx_isocdbg("p is null\n"); - return; - } - if (outp == NULL) { - em28xx_isocdbg("outp is null\n"); - return; - } - - if (dma_q->pos + len > buf->vb.size) - len = buf->vb.size - dma_q->pos; - - startread = p; - - startwrite = outp + dma_q->pos; - offset = dma_q->pos; - - /* Make sure the bottom field populates the second half of the frame */ - if (buf->top_field == 0) { - startwrite += bytesperline * dev->vbi_height; - offset += bytesperline * dev->vbi_height; - } - - memcpy(startwrite, startread, len); - dma_q->pos += len; -} - -static inline void print_err_status(struct em28xx *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - em28xx_isocdbg("URB status %d [%s].\n", status, errmsg); - } else { - em28xx_isocdbg("URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -/* - * video-buf generic routine to get the next available buffer - */ -static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, - struct em28xx_buffer **buf) -{ - struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); - char *outp; - - if (list_empty(&dma_q->active)) { - em28xx_isocdbg("No active queue to serve\n"); - dev->isoc_ctl.vid_buf = NULL; - *buf = NULL; - return; - } - - /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); - - /* Cleans up buffer - Usefull for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - memset(outp, 0, (*buf)->vb.size); - - dev->isoc_ctl.vid_buf = *buf; - - return; -} - -/* - * video-buf generic routine to get the next available VBI buffer - */ -static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q, - struct em28xx_buffer **buf) -{ - struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq); - char *outp; - - if (list_empty(&dma_q->active)) { - em28xx_isocdbg("No active queue to serve\n"); - dev->isoc_ctl.vbi_buf = NULL; - *buf = NULL; - return; - } - - /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); - /* Cleans up buffer - Usefull for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - memset(outp, 0x00, (*buf)->vb.size); - - dev->isoc_ctl.vbi_buf = *buf; - - return; -} - -/* - * Controls the isoc copy of each urb packet - */ -static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) -{ - struct em28xx_buffer *buf; - struct em28xx_dmaqueue *dma_q = &dev->vidq; - unsigned char *outp = NULL; - int i, len = 0, rc = 1; - unsigned char *p; - - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - buf = dev->isoc_ctl.vid_buf; - if (buf != NULL) - outp = videobuf_to_vmalloc(&buf->vb); - - for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - if (urb->iso_frame_desc[i].status != -EPROTO) - continue; - } - - len = urb->iso_frame_desc[i].actual_length - 4; - - if (urb->iso_frame_desc[i].actual_length <= 0) { - /* em28xx_isocdbg("packet %d is empty",i); - spammy */ - continue; - } - if (urb->iso_frame_desc[i].actual_length > - dev->max_pkt_size) { - em28xx_isocdbg("packet bigger than packet size"); - continue; - } - - p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - /* FIXME: incomplete buffer checks where removed to make - logic simpler. Impacts of those changes should be evaluated - */ - if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) { - em28xx_isocdbg("VBI HEADER!!!\n"); - /* FIXME: Should add vbi copy */ - continue; - } - if (p[0] == 0x22 && p[1] == 0x5a) { - em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], - len, (p[2] & 1) ? "odd" : "even"); - - if (dev->progressive || !(p[2] & 1)) { - if (buf != NULL) - buffer_filled(dev, dma_q, buf); - get_next_buf(dma_q, &buf); - if (buf == NULL) - outp = NULL; - else - outp = videobuf_to_vmalloc(&buf->vb); - } - - if (buf != NULL) { - if (p[2] & 1) - buf->top_field = 0; - else - buf->top_field = 1; - } - - dma_q->pos = 0; - } - if (buf != NULL) { - if (p[0] != 0x88 && p[0] != 0x22) { - em28xx_isocdbg("frame is not complete\n"); - len += 4; - } else { - p += 4; - } - em28xx_copy_video(dev, dma_q, buf, p, outp, len); - } - } - return rc; -} - -/* Version of isoc handler that takes into account a mixture of video and - VBI data */ -static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb) -{ - struct em28xx_buffer *buf, *vbi_buf; - struct em28xx_dmaqueue *dma_q = &dev->vidq; - struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; - unsigned char *outp = NULL; - unsigned char *vbioutp = NULL; - int i, len = 0, rc = 1; - unsigned char *p; - int vbi_size; - - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - buf = dev->isoc_ctl.vid_buf; - if (buf != NULL) - outp = videobuf_to_vmalloc(&buf->vb); - - vbi_buf = dev->isoc_ctl.vbi_buf; - if (vbi_buf != NULL) - vbioutp = videobuf_to_vmalloc(&vbi_buf->vb); - - for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - if (urb->iso_frame_desc[i].status != -EPROTO) - continue; - } - - len = urb->iso_frame_desc[i].actual_length; - if (urb->iso_frame_desc[i].actual_length <= 0) { - /* em28xx_isocdbg("packet %d is empty",i); - spammy */ - continue; - } - if (urb->iso_frame_desc[i].actual_length > - dev->max_pkt_size) { - em28xx_isocdbg("packet bigger than packet size"); - continue; - } - - p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - /* capture type 0 = vbi start - capture type 1 = video start - capture type 2 = video in progress */ - if (p[0] == 0x33 && p[1] == 0x95) { - dev->capture_type = 0; - dev->vbi_read = 0; - em28xx_isocdbg("VBI START HEADER!!!\n"); - dev->cur_field = p[2]; - p += 4; - len -= 4; - } else if (p[0] == 0x88 && p[1] == 0x88 && - p[2] == 0x88 && p[3] == 0x88) { - /* continuation */ - p += 4; - len -= 4; - } else if (p[0] == 0x22 && p[1] == 0x5a) { - /* start video */ - p += 4; - len -= 4; - } - - vbi_size = dev->vbi_width * dev->vbi_height; - - if (dev->capture_type == 0) { - if (dev->vbi_read >= vbi_size) { - /* We've already read all the VBI data, so - treat the rest as video */ - em28xx_isocdbg("dev->vbi_read > vbi_size\n"); - } else if ((dev->vbi_read + len) < vbi_size) { - /* This entire frame is VBI data */ - if (dev->vbi_read == 0 && - (!(dev->cur_field & 1))) { - /* Brand new frame */ - if (vbi_buf != NULL) - vbi_buffer_filled(dev, - vbi_dma_q, - vbi_buf); - vbi_get_next_buf(vbi_dma_q, &vbi_buf); - if (vbi_buf == NULL) - vbioutp = NULL; - else - vbioutp = videobuf_to_vmalloc( - &vbi_buf->vb); - } - - if (dev->vbi_read == 0) { - vbi_dma_q->pos = 0; - if (vbi_buf != NULL) { - if (dev->cur_field & 1) - vbi_buf->top_field = 0; - else - vbi_buf->top_field = 1; - } - } - - dev->vbi_read += len; - em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p, - vbioutp, len); - } else { - /* Some of this frame is VBI data and some is - video data */ - int vbi_data_len = vbi_size - dev->vbi_read; - dev->vbi_read += vbi_data_len; - em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p, - vbioutp, vbi_data_len); - dev->capture_type = 1; - p += vbi_data_len; - len -= vbi_data_len; - } - } - - if (dev->capture_type == 1) { - dev->capture_type = 2; - if (dev->progressive || !(dev->cur_field & 1)) { - if (buf != NULL) - buffer_filled(dev, dma_q, buf); - get_next_buf(dma_q, &buf); - if (buf == NULL) - outp = NULL; - else - outp = videobuf_to_vmalloc(&buf->vb); - } - if (buf != NULL) { - if (dev->cur_field & 1) - buf->top_field = 0; - else - buf->top_field = 1; - } - - dma_q->pos = 0; - } - - if (buf != NULL && dev->capture_type == 2) { - if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 && - p[2] == 0x88 && p[3] == 0x88) { - p += 4; - len -= 4; - } - if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) { - em28xx_isocdbg("Video frame %d, len=%i, %s\n", - p[2], len, (p[2] & 1) ? - "odd" : "even"); - p += 4; - len -= 4; - } - - if (len > 0) - em28xx_copy_video(dev, dma_q, buf, p, outp, - len); - } - } - return rc; -} - - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ - -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) -{ - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = fh->dev; - struct v4l2_frequency f; - - *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) - >> 3; - - if (0 == *count) - *count = EM28XX_DEF_BUF; - - if (*count < EM28XX_MIN_BUF) - *count = EM28XX_MIN_BUF; - - /* Ask tuner to go to analog or radio mode */ - memset(&f, 0, sizeof(f)); - f.frequency = dev->ctl_freq; - f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); - - return 0; -} - -/* This is called *without* dev->slock held; please keep it that way */ -static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) -{ - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = fh->dev; - unsigned long flags = 0; - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.vid_buf == buf) - dev->isoc_ctl.vid_buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct em28xx_fh *fh = vq->priv_data; - struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); - struct em28xx *dev = fh->dev; - int rc = 0, urb_init = 0; - - buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth - + 7) >> 3; - - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - if (!dev->isoc_ctl.num_bufs) - urb_init = 1; - - if (urb_init) { - if (em28xx_vbi_supported(dev) == 1) - rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, - EM28XX_NUM_BUFS, - dev->max_pkt_size, - em28xx_isoc_copy_vbi); - else - rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, - EM28XX_NUM_BUFS, - dev->max_pkt_size, - em28xx_isoc_copy); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct em28xx_buffer *buf = container_of(vb, - struct em28xx_buffer, - vb); - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = fh->dev; - struct em28xx_dmaqueue *vidq = &dev->vidq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); - -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct em28xx_buffer *buf = container_of(vb, - struct em28xx_buffer, - vb); - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = (struct em28xx *)fh->dev; - - em28xx_isocdbg("em28xx: called buffer_release\n"); - - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops em28xx_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/********************* v4l2 interface **************************************/ - -static void video_mux(struct em28xx *dev, int index) -{ - dev->ctl_input = index; - dev->ctl_ainput = INPUT(index)->amux; - dev->ctl_aoutput = INPUT(index)->aout; - - if (!dev->ctl_aoutput) - dev->ctl_aoutput = EM28XX_AOUT_MASTER; - - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, - INPUT(index)->vmux, 0, 0); - - if (dev->board.has_msp34xx) { - if (dev->i2s_speed) { - v4l2_device_call_all(&dev->v4l2_dev, 0, audio, - s_i2s_clock_freq, dev->i2s_speed); - } - /* Note: this is msp3400 specific */ - v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, - dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0); - } - - if (dev->board.adecoder != EM28XX_NOADECODER) { - v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, - dev->ctl_ainput, dev->ctl_aoutput, 0); - } - - em28xx_audio_analog_set(dev); -} - -/* Usage lock check functions */ -static int res_get(struct em28xx_fh *fh, unsigned int bit) -{ - struct em28xx *dev = fh->dev; - - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - if (dev->resources & bit) { - /* no, someone else uses it */ - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - em28xx_videodbg("res: get %d\n", bit); - return 1; -} - -static int res_check(struct em28xx_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct em28xx *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct em28xx_fh *fh, unsigned int bits) -{ - struct em28xx *dev = fh->dev; - - BUG_ON((fh->resources & bits) != bits); - - fh->resources &= ~bits; - dev->resources &= ~bits; - em28xx_videodbg("res: put %d\n", bits); -} - -static int get_ressource(struct em28xx_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return EM28XX_RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return EM28XX_RESOURCE_VBI; - default: - BUG(); - return 0; - } -} - -/* - * ac97_queryctrl() - * return the ac97 supported controls - */ -static int ac97_queryctrl(struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) { - if (qc->id && qc->id == ac97_qctrl[i].id) { - memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc)); - return 0; - } - } - - /* Control is not ac97 related */ - return 1; -} - -/* - * ac97_get_ctrl() - * return the current values for ac97 mute and volume - */ -static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = dev->mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = dev->volume; - return 0; - default: - /* Control is not ac97 related */ - return 1; - } -} - -/* - * ac97_set_ctrl() - * set values for ac97 mute and volume - */ -static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) - if (ctrl->id == ac97_qctrl[i].id) - goto handle; - - /* Announce that hasn't handle it */ - return 1; - -handle: - if (ctrl->value < ac97_qctrl[i].minimum || - ctrl->value > ac97_qctrl[i].maximum) - return -ERANGE; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - dev->mute = ctrl->value; - break; - case V4L2_CID_AUDIO_VOLUME: - dev->volume = ctrl->value; - break; - } - - return em28xx_audio_analog_set(dev); -} - -static int check_dev(struct em28xx *dev) -{ - if (dev->state & DEV_DISCONNECTED) { - em28xx_errdev("v4l2 ioctl: device not present\n"); - return -ENODEV; - } - - if (dev->state & DEV_MISCONFIGURED) { - em28xx_errdev("v4l2 ioctl: device is misconfigured; " - "close and open it again\n"); - return -EIO; - } - return 0; -} - -static void get_scale(struct em28xx *dev, - unsigned int width, unsigned int height, - unsigned int *hscale, unsigned int *vscale) -{ - unsigned int maxw = norm_maxw(dev); - unsigned int maxh = norm_maxh(dev); - - *hscale = (((unsigned long)maxw) << 12) / width - 4096L; - if (*hscale >= 0x4000) - *hscale = 0x3fff; - - *vscale = (((unsigned long)maxh) << 12) / height - 4096L; - if (*vscale >= 0x4000) - *vscale = 0x3fff; -} - -/* ------------------------------------------------------------------ - IOCTL vidioc handling - ------------------------------------------------------------------*/ - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - f->fmt.pix.pixelformat = dev->format->fourcc; - f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - - /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ - if (dev->progressive) - f->fmt.pix.field = V4L2_FIELD_NONE; - else - f->fmt.pix.field = dev->interlaced ? - V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; - return 0; -} - -static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(format); i++) - if (format[i].fourcc == fourcc) - return &format[i]; - - return NULL; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - unsigned int width = f->fmt.pix.width; - unsigned int height = f->fmt.pix.height; - unsigned int maxw = norm_maxw(dev); - unsigned int maxh = norm_maxh(dev); - unsigned int hscale, vscale; - struct em28xx_fmt *fmt; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (!fmt) { - em28xx_videodbg("Fourcc format (%08x) invalid.\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - if (dev->board.is_em2800) { - /* the em2800 can only scale down to 50% */ - height = height > (3 * maxh / 4) ? maxh : maxh / 2; - width = width > (3 * maxw / 4) ? maxw : maxw / 2; - } else { - /* width must even because of the YUYV format - height must be even because of interlacing */ - v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, - 1, 0); - } - - get_scale(dev, width, height, &hscale, &vscale); - - width = (((unsigned long)maxw) << 12) / (hscale + 4096L); - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - - f->fmt.pix.width = width; - f->fmt.pix.height = height; - f->fmt.pix.pixelformat = fmt->fourcc; - f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - if (dev->progressive) - f->fmt.pix.field = V4L2_FIELD_NONE; - else - f->fmt.pix.field = dev->interlaced ? - V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; - - return 0; -} - -static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc, - unsigned width, unsigned height) -{ - struct em28xx_fmt *fmt; - - fmt = format_by_fourcc(fourcc); - if (!fmt) - return -EINVAL; - - dev->format = fmt; - dev->width = width; - dev->height = height; - - /* set new image size */ - get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - - em28xx_set_alternate(dev); - em28xx_resolution_set(dev); - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - vidioc_try_fmt_vid_cap(file, priv, f); - - if (videobuf_queue_is_busy(&fh->vb_vidq)) { - em28xx_errdev("%s queue busy\n", __func__); - return -EBUSY; - } - - return em28xx_set_video_format(dev, f->fmt.pix.pixelformat, - f->fmt.pix.width, f->fmt.pix.height); -} - -static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - *norm = dev->norm; - - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - struct v4l2_format f; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - dev->norm = *norm; - - /* Adjusts width/height, if needed */ - f.fmt.pix.width = dev->width; - f.fmt.pix.height = dev->height; - vidioc_try_fmt_vid_cap(file, priv, &f); - - /* set new image size */ - dev->width = f.fmt.pix.width; - dev->height = f.fmt.pix.height; - get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - - em28xx_resolution_set(dev); - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); - - return 0; -} - -static int vidioc_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *p) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc = 0; - - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (dev->board.is_webcam) - rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, - video, g_parm, p); - else - v4l2_video_std_frame_period(dev->norm, - &p->parm.capture.timeperframe); - - return rc; -} - -static int vidioc_s_parm(struct file *file, void *priv, - struct v4l2_streamparm *p) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - if (!dev->board.is_webcam) - return -EINVAL; - - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p); -} - -static const char *iname[] = { - [EM28XX_VMUX_COMPOSITE1] = "Composite1", - [EM28XX_VMUX_COMPOSITE2] = "Composite2", - [EM28XX_VMUX_COMPOSITE3] = "Composite3", - [EM28XX_VMUX_COMPOSITE4] = "Composite4", - [EM28XX_VMUX_SVIDEO] = "S-Video", - [EM28XX_VMUX_TELEVISION] = "Television", - [EM28XX_VMUX_CABLE] = "Cable TV", - [EM28XX_VMUX_DVB] = "DVB", - [EM28XX_VMUX_DEBUG] = "for debug only", -}; - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - unsigned int n; - - n = i->index; - if (n >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(n)->type) - return -EINVAL; - - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - - strcpy(i->name, iname[INPUT(n)->type]); - - if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || - (EM28XX_VMUX_CABLE == INPUT(n)->type)) - i->type = V4L2_INPUT_TYPE_TUNER; - - i->std = dev->vdev->tvnorms; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - *i = dev->ctl_input; - - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (i >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(i)->type) - return -EINVAL; - - dev->ctl_input = i; - - video_mux(dev, dev->ctl_input); - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - if (!dev->audio_mode.has_audio) - return -EINVAL; - - switch (a->index) { - case EM28XX_AMUX_VIDEO: - strcpy(a->name, "Television"); - break; - case EM28XX_AMUX_LINE_IN: - strcpy(a->name, "Line In"); - break; - case EM28XX_AMUX_VIDEO2: - strcpy(a->name, "Television alt"); - break; - case EM28XX_AMUX_PHONE: - strcpy(a->name, "Phone"); - break; - case EM28XX_AMUX_MIC: - strcpy(a->name, "Mic"); - break; - case EM28XX_AMUX_CD: - strcpy(a->name, "CD"); - break; - case EM28XX_AMUX_AUX: - strcpy(a->name, "Aux"); - break; - case EM28XX_AMUX_PCM_OUT: - strcpy(a->name, "PCM"); - break; - default: - return -EINVAL; - } - - a->index = dev->ctl_ainput; - a->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - - if (!dev->audio_mode.has_audio) - return -EINVAL; - - if (a->index >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(a->index)->type) - return -EINVAL; - - dev->ctl_ainput = INPUT(a->index)->amux; - dev->ctl_aoutput = INPUT(a->index)->aout; - - if (!dev->ctl_aoutput) - dev->ctl_aoutput = EM28XX_AOUT_MASTER; - - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int id = qc->id; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - memset(qc, 0, sizeof(*qc)); - - qc->id = id; - - /* enumerate AC97 controls */ - if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { - rc = ac97_queryctrl(qc); - if (!rc) - return 0; - } - - /* enumerate V4L2 device controls */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc); - - if (qc->type) - return 0; - else - return -EINVAL; -} - -/* - * FIXME: This is an indirect way to check if a control exists at a - * subdev. Instead of that hack, maybe the better would be to change all - * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported. - */ -static int check_subdev_ctrl(struct em28xx *dev, int id) -{ - struct v4l2_queryctrl qc; - - memset(&qc, 0, sizeof(qc)); - qc.id = id; - - /* enumerate V4L2 device controls */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc); - - if (qc.type) - return 0; - else - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - rc = 0; - - /* Set an AC97 control */ - if (dev->audio_mode.ac97 != EM28XX_NO_AC97) - rc = ac97_get_ctrl(dev, ctrl); - else - rc = 1; - - /* It were not an AC97 control. Sends it to the v4l2 dev interface */ - if (rc == 1) { - if (check_subdev_ctrl(dev, ctrl->id)) - return -EINVAL; - - v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); - rc = 0; - } - - return rc; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - /* Set an AC97 control */ - if (dev->audio_mode.ac97 != EM28XX_NO_AC97) - rc = ac97_set_ctrl(dev, ctrl); - else - rc = 1; - - /* It isn't an AC97 control. Sends it to the v4l2 dev interface */ - if (rc == 1) { - rc = check_subdev_ctrl(dev, ctrl->id); - if (!rc) - v4l2_device_call_all(&dev->v4l2_dev, 0, - core, s_ctrl, ctrl); - /* - * In the case of non-AC97 volume controls, we still need - * to do some setups at em28xx, in order to mute/unmute - * and to adjust audio volume. However, the value ranges - * should be checked by the corresponding V4L subdriver. - */ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - dev->mute = ctrl->value; - rc = em28xx_audio_analog_set(dev); - break; - case V4L2_CID_AUDIO_VOLUME: - dev->volume = ctrl->value; - rc = em28xx_audio_analog_set(dev); - } - } - return (rc < 0) ? rc : 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Tuner"); - t->type = V4L2_TUNER_ANALOG_TV; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != t->index) - return -EINVAL; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != f->tuner) - return -EINVAL; - - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; - - dev->ctl_freq = f->frequency; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int em28xx_reg_len(int reg) -{ - switch (reg) { - case EM28XX_R40_AC97LSB: - case EM28XX_R30_HSCALELOW: - case EM28XX_R32_VSCALELOW: - return 2; - default: - return 1; - } -} - -static int vidioc_g_chip_ident(struct file *file, void *priv, - struct v4l2_dbg_chip_ident *chip) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - - v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip); - - return 0; -} - - -static int vidioc_g_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int ret; - - switch (reg->match.type) { - case V4L2_CHIP_MATCH_AC97: - ret = em28xx_read_ac97(dev, reg->reg); - if (ret < 0) - return ret; - - reg->val = ret; - reg->size = 1; - return 0; - case V4L2_CHIP_MATCH_I2C_DRIVER: - v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); - return 0; - case V4L2_CHIP_MATCH_I2C_ADDR: - /* TODO: is this correct? */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); - return 0; - default: - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - } - - /* Match host */ - reg->size = em28xx_reg_len(reg->reg); - if (reg->size == 1) { - ret = em28xx_read_reg(dev, reg->reg); - - if (ret < 0) - return ret; - - reg->val = ret; - } else { - __le16 val = 0; - ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, - reg->reg, (char *)&val, 2); - if (ret < 0) - return ret; - - reg->val = le16_to_cpu(val); - } - - return 0; -} - -static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - __le16 buf; - - switch (reg->match.type) { - case V4L2_CHIP_MATCH_AC97: - return em28xx_write_ac97(dev, reg->reg, reg->val); - case V4L2_CHIP_MATCH_I2C_DRIVER: - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); - return 0; - case V4L2_CHIP_MATCH_I2C_ADDR: - /* TODO: is this correct? */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); - return 0; - default: - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - } - - /* Match host */ - buf = cpu_to_le16(reg->val); - - return em28xx_write_regs(dev, reg->reg, (char *)&buf, - em28xx_reg_len(reg->reg)); -} -#endif - - -static int vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cc) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - cc->bounds.left = 0; - cc->bounds.top = 0; - cc->bounds.width = dev->width; - cc->bounds.height = dev->height; - cc->defrect = cc->bounds; - cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ - cc->pixelaspect.denominator = 59; - - return 0; -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc = -EINVAL; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (unlikely(type != fh->type)) - return -EINVAL; - - em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n", - fh, type, fh->resources, dev->resources); - - if (unlikely(!res_get(fh, get_ressource(fh)))) - return -EBUSY; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_streamon(&fh->vb_vidq); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_streamon(&fh->vb_vbiq); - - return rc; -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) - return -EINVAL; - if (type != fh->type) - return -EINVAL; - - em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n", - fh, type, fh->resources, dev->resources); - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (res_check(fh, EM28XX_RESOURCE_VIDEO)) { - videobuf_streamoff(&fh->vb_vidq); - res_free(fh, EM28XX_RESOURCE_VIDEO); - } - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (res_check(fh, EM28XX_RESOURCE_VBI)) { - videobuf_streamoff(&fh->vb_vbiq); - res_free(fh, EM28XX_RESOURCE_VBI); - } - } - - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - - cap->version = EM28XX_VERSION_CODE; - - cap->capabilities = - V4L2_CAP_SLICED_VBI_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - - if (dev->vbi_dev) - cap->capabilities |= V4L2_CAP_VBI_CAPTURE; - - if (dev->audio_mode.has_audio) - cap->capabilities |= V4L2_CAP_AUDIO; - - if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (unlikely(f->index >= ARRAY_SIZE(format))) - return -EINVAL; - - strlcpy(f->description, format[f->index].name, sizeof(f->description)); - f->pixelformat = format[f->index].fourcc; - - return 0; -} - -/* Sliced VBI ioctls */ -static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - f->fmt.sliced.service_set = 0; - v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced); - - if (f->fmt.sliced.service_set == 0) - rc = -EINVAL; - - return rc; -} - -static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced); - - if (f->fmt.sliced.service_set == 0) - return -EINVAL; - - return 0; -} - -/* RAW VBI ioctls */ - -static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - format->fmt.vbi.samples_per_line = dev->vbi_width; - format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - format->fmt.vbi.offset = 0; - format->fmt.vbi.flags = 0; - format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; - format->fmt.vbi.count[0] = dev->vbi_height; - format->fmt.vbi.count[1] = dev->vbi_height; - - /* Varies by video standard (NTSC, PAL, etc.) */ - if (dev->norm & V4L2_STD_525_60) { - /* NTSC */ - format->fmt.vbi.start[0] = 10; - format->fmt.vbi.start[1] = 273; - } else if (dev->norm & V4L2_STD_625_50) { - /* PAL */ - format->fmt.vbi.start[0] = 6; - format->fmt.vbi.start[1] = 318; - } - - return 0; -} - -static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - format->fmt.vbi.samples_per_line = dev->vbi_width; - format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - format->fmt.vbi.offset = 0; - format->fmt.vbi.flags = 0; - format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; - format->fmt.vbi.count[0] = dev->vbi_height; - format->fmt.vbi.count[1] = dev->vbi_height; - - /* Varies by video standard (NTSC, PAL, etc.) */ - if (dev->norm & V4L2_STD_525_60) { - /* NTSC */ - format->fmt.vbi.start[0] = 10; - format->fmt.vbi.start[1] = 273; - } else if (dev->norm & V4L2_STD_625_50) { - /* PAL */ - format->fmt.vbi.start[0] = 6; - format->fmt.vbi.start[1] = 318; - } - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return videobuf_reqbufs(&fh->vb_vidq, rb); - else - return videobuf_reqbufs(&fh->vb_vbiq, rb); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return videobuf_querybuf(&fh->vb_vidq, b); - else { - /* FIXME: I'm not sure yet whether this is a bug in zvbi or - the videobuf framework, but we probably shouldn't be - returning a buffer larger than that which was asked for. - At a minimum, it causes a crash in zvbi since it does - a memcpy based on the source buffer length */ - int result = videobuf_querybuf(&fh->vb_vbiq, b); - b->length = dev->vbi_width * dev->vbi_height * 2; - - return result; - } -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return videobuf_qbuf(&fh->vb_vidq, b); - else - return videobuf_qbuf(&fh->vb_vbiq, b); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & - O_NONBLOCK); - else - return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & - O_NONBLOCK); -} - -/* ----------------------------------------------------------- */ -/* RADIO ESPECIFIC IOCTLS */ -/* ----------------------------------------------------------- */ - -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; - - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - - cap->version = EM28XX_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; - - if (unlikely(t->index > 0)) - return -EINVAL; - - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); - - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name, "Radio"); - return 0; -} - -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; - - if (0 != t->index) - return -EINVAL; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - - return 0; -} - -static int radio_s_audio(struct file *file, void *fh, - struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input(struct file *file, void *fh, unsigned int i) -{ - return 0; -} - -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - if (qc->id < V4L2_CID_BASE || - qc->id >= V4L2_CID_LASTP1) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) { - if (qc->id && qc->id == ac97_qctrl[i].id) { - memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc)); - return 0; - } - } - - return -EINVAL; -} - -/* - * em28xx_v4l2_open() - * inits the device and starts isoc transfer - */ -static int em28xx_v4l2_open(struct file *filp) -{ - int errCode = 0, radio = 0; - struct video_device *vdev = video_devdata(filp); - struct em28xx *dev = video_drvdata(filp); - enum v4l2_buf_type fh_type = 0; - struct em28xx_fh *fh; - enum v4l2_field field; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - } - - em28xx_videodbg("open dev=%s type=%s users=%d\n", - video_device_node_name(vdev), v4l2_type_names[fh_type], - dev->users); - - - fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); - if (!fh) { - em28xx_errdev("em28xx-video.c: Out of memory?!\n"); - return -ENOMEM; - } - fh->dev = dev; - fh->radio = radio; - fh->type = fh_type; - filp->private_data = fh; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { - em28xx_set_mode(dev, EM28XX_ANALOG_MODE); - em28xx_set_alternate(dev); - em28xx_resolution_set(dev); - - /* Needed, since GPIO might have disabled power of - some i2c device - */ - em28xx_wake_i2c(dev); - - } - if (fh->radio) { - em28xx_videodbg("video_open: setting radio device\n"); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); - } - - dev->users++; - - if (dev->progressive) - field = V4L2_FIELD_NONE; - else - field = V4L2_FIELD_INTERLACED; - - videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, - NULL, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, field, - sizeof(struct em28xx_buffer), fh, &dev->lock); - - videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops, - NULL, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct em28xx_buffer), fh, &dev->lock); - - return errCode; -} - -/* - * em28xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -void em28xx_release_analog_resources(struct em28xx *dev) -{ - - /*FIXME: I2C IR should be disconnected */ - - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - if (dev->vbi_dev) { - em28xx_info("V4L2 device %s deregistered\n", - video_device_node_name(dev->vbi_dev)); - if (video_is_registered(dev->vbi_dev)) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->vdev) { - em28xx_info("V4L2 device %s deregistered\n", - video_device_node_name(dev->vdev)); - if (video_is_registered(dev->vdev)) - video_unregister_device(dev->vdev); - else - video_device_release(dev->vdev); - dev->vdev = NULL; - } -} - -/* - * em28xx_v4l2_close() - * stops streaming and deallocates all resources allocated by the v4l2 - * calls and ioctls - */ -static int em28xx_v4l2_close(struct file *filp) -{ - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int errCode; - - em28xx_videodbg("users=%d\n", dev->users); - - if (res_check(fh, EM28XX_RESOURCE_VIDEO)) { - videobuf_stop(&fh->vb_vidq); - res_free(fh, EM28XX_RESOURCE_VIDEO); - } - - if (res_check(fh, EM28XX_RESOURCE_VBI)) { - videobuf_stop(&fh->vb_vbiq); - res_free(fh, EM28XX_RESOURCE_VBI); - } - - if (dev->users == 1) { - /* the device is already disconnect, - free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - em28xx_release_resources(dev); - kfree(dev); - return 0; - } - - /* Save some power by putting tuner to sleep */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); - - /* do this before setting alternate! */ - em28xx_uninit_isoc(dev); - em28xx_set_mode(dev, EM28XX_SUSPEND); - - /* set alternate 0 */ - dev->alt = 0; - em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(dev->udev, 0, 0); - if (errCode < 0) { - em28xx_errdev("cannot change alternate number to " - "0 (error=%i)\n", errCode); - } - } - - videobuf_mmap_free(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vbiq); - kfree(fh); - dev->users--; - wake_up_interruptible_nr(&dev->open, 1); - return 0; -} - -/* - * em28xx_v4l2_read() - * will allocate buffers when called for the first time - */ -static ssize_t -em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t *pos) -{ - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - /* FIXME: read() is not prepared to allow changing the video - resolution while streaming. Seems a bug at em28xx_set_fmt - */ - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (res_locked(dev, EM28XX_RESOURCE_VIDEO)) - return -EBUSY; - - return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - } - - - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (!res_get(fh, EM28XX_RESOURCE_VBI)) - return -EBUSY; - - return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - } - - return 0; -} - -/* - * em28xx_v4l2_poll() - * will allocate buffers when called for the first time - */ -static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait) -{ - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (!res_get(fh, EM28XX_RESOURCE_VIDEO)) - return POLLERR; - return videobuf_poll_stream(filp, &fh->vb_vidq, wait); - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (!res_get(fh, EM28XX_RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(filp, &fh->vb_vbiq, wait); - } else { - return POLLERR; - } -} - -/* - * em28xx_v4l2_mmap() - */ -static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma); - - em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, - rc); - - return rc; -} - -static const struct v4l2_file_operations em28xx_v4l_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .read = em28xx_v4l2_read, - .poll = em28xx_v4l2_poll, - .mmap = em28xx_v4l2_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_cropcap = vidioc_cropcap, - - .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, - .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, - .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, - - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_g_std = vidioc_g_std, - .vidioc_s_std = vidioc_s_std, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_s_parm = vidioc_s_parm, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, - .vidioc_g_chip_ident = vidioc_g_chip_ident, -#endif -}; - -static const struct video_device em28xx_video_template = { - .fops = &em28xx_v4l_fops, - .release = video_device_release, - .ioctl_ops = &video_ioctl_ops, - - .tvnorms = V4L2_STD_ALL, - .current_norm = V4L2_STD_PAL, -}; - -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif -}; - -static struct video_device em28xx_radio_template = { - .name = "em28xx-radio", - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, -}; - -/******************************** usb interface ******************************/ - - - -static struct video_device *em28xx_vdev_init(struct em28xx *dev, - const struct video_device *template, - const char *type_name) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - - *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; - vfd->debug = video_debug; - vfd->lock = &dev->lock; - - snprintf(vfd->name, sizeof(vfd->name), "%s %s", - dev->name, type_name); - - video_set_drvdata(vfd, dev); - return vfd; -} - -int em28xx_register_analog_devices(struct em28xx *dev) -{ - u8 val; - int ret; - - printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n", - dev->name, - (EM28XX_VERSION_CODE >> 16) & 0xff, - (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff); - - /* set default norm */ - dev->norm = em28xx_video_template.current_norm; - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); - dev->interlaced = EM28XX_INTERLACED_DEFAULT; - dev->ctl_input = 0; - - /* Analog specific initialization */ - dev->format = &format[0]; - em28xx_set_video_format(dev, format[0].fourcc, - norm_maxw(dev), norm_maxh(dev)); - - video_mux(dev, dev->ctl_input); - - /* Audio defaults */ - dev->mute = 1; - dev->volume = 0x1f; - -/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */ - val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK); - em28xx_write_reg(dev, EM28XX_R0F_XCLK, - (EM28XX_XCLK_AUDIO_UNMUTE | val)); - - em28xx_set_outfmt(dev); - em28xx_colorlevels_set_default(dev); - em28xx_compression_disable(dev); - - /* allocate and fill video video_device struct */ - dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); - if (!dev->vdev) { - em28xx_errdev("cannot allocate video_device.\n"); - return -ENODEV; - } - - /* register v4l2 video video_device */ - ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, - video_nr[dev->devno]); - if (ret) { - em28xx_errdev("unable to register video device (error=%i).\n", - ret); - return ret; - } - - /* Allocate and fill vbi video_device struct */ - if (em28xx_vbi_supported(dev) == 1) { - dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, - "vbi"); - - /* register v4l2 vbi video_device */ - ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, - vbi_nr[dev->devno]); - if (ret < 0) { - em28xx_errdev("unable to register vbi device\n"); - return ret; - } - } - - if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { - dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, - "radio"); - if (!dev->radio_dev) { - em28xx_errdev("cannot allocate video_device.\n"); - return -ENODEV; - } - ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr[dev->devno]); - if (ret < 0) { - em28xx_errdev("can't register radio device\n"); - return ret; - } - em28xx_info("Registered radio device as %s\n", - video_device_node_name(dev->radio_dev)); - } - - em28xx_info("V4L2 video device registered as %s\n", - video_device_node_name(dev->vdev)); - - if (dev->vbi_dev) - em28xx_info("V4L2 VBI device registered as %s\n", - video_device_node_name(dev->vbi_dev)); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -config VIDEO_EM28XX - tristate "Empia EM28xx USB video capture support" - depends on VIDEO_DEV && I2C - select VIDEO_TUNER - select VIDEO_TVEEPROM - depends on RC_CORE - select VIDEOBUF_VMALLOC - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_MT9V011 if VIDEO_HELPER_CHIPS_AUTO - - ---help--- - This is a video4linux driver for Empia 28xx based TV cards. - - To compile this driver as a module, choose M here: the - module will be called em28xx - -config VIDEO_EM28XX_ALSA - depends on VIDEO_EM28XX && SND - select SND_PCM - tristate "Empia EM28xx ALSA audio module" - ---help--- - This is an ALSA driver for some Empia 28xx based TV cards. - - This is not required for em2800/em2820/em2821 boards. However, - newer em28xx devices uses Vendor Class for audio, instead of - implementing the USB Audio Class. For those chips, this module - will enable digital audio. - - To compile this driver as a module, choose M here: the - module will be called em28xx-alsa - -config VIDEO_EM28XX_DVB - tristate "DVB/ATSC Support for em28xx based TV cards" - depends on VIDEO_EM28XX && DVB_CORE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_S921 if !DVB_FE_CUSTOMISE - select VIDEOBUF_DVB - ---help--- - This adds support for DVB cards based on the - Empiatech em28xx chips. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/em28xx/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ - em28xx-input.o em28xx-vbi.o - -em28xx-alsa-objs := em28xx-audio.o - -obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o -obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o -obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2711 +0,0 @@ -/*************************************************************************** - * V4L2 driver for ET61X[12]51 PC Camera Controllers * - * * - * Copyright (C) 2006-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "et61x251.h" - -/*****************************************************************************/ - -#define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \ - "PC Camera Controllers" -#define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia" -#define ET61X251_AUTHOR_EMAIL "" -#define ET61X251_MODULE_LICENSE "GPL" -#define ET61X251_MODULE_VERSION "1:1.09" -#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 9) - -/*****************************************************************************/ - -MODULE_DEVICE_TABLE(usb, et61x251_id_table); - -MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL); -MODULE_DESCRIPTION(ET61X251_MODULE_NAME); -MODULE_LICENSE(ET61X251_MODULE_LICENSE); - -static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1}; -module_param_array(video_nr, short, NULL, 0444); -MODULE_PARM_DESC(video_nr, - "\n<-1|n[,...]> Specify V4L2 minor mode number." - "\n -1 = use next available (default)" - "\n n = use minor number n (integer >= 0)" - "\nYou can specify up to " - __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way." - "\nFor example:" - "\nvideo_nr=-1,2,-1 would assign minor number 2 to" - "\nthe second registered camera and use auto for the first" - "\none and for every other camera." - "\n"); - -static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] = - ET61X251_FORCE_MUNMAP}; -module_param_array(force_munmap, bool, NULL, 0444); -MODULE_PARM_DESC(force_munmap, - "\n<0|1[,...]> Force the application to unmap previously" - "\nmapped buffer memory before calling any VIDIOC_S_CROP or" - "\nVIDIOC_S_FMT ioctl's. Not all the applications support" - "\nthis feature. This parameter is specific for each" - "\ndetected camera." - "\n 0 = do not force memory unmapping" - "\n 1 = force memory unmapping (save memory)" - "\nDefault value is "__MODULE_STRING(ET61X251_FORCE_MUNMAP)"." - "\n"); - -static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] = - ET61X251_FRAME_TIMEOUT}; -module_param_array(frame_timeout, uint, NULL, 0644); -MODULE_PARM_DESC(frame_timeout, - "\n Timeout for a video frame in seconds." - "\nThis parameter is specific for each detected camera." - "\nDefault value is " - __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"." - "\n"); - -#ifdef ET61X251_DEBUG -static unsigned short debug = ET61X251_DEBUG_LEVEL; -module_param(debug, ushort, 0644); -MODULE_PARM_DESC(debug, - "\n Debugging information level, from 0 to 3:" - "\n0 = none (use carefully)" - "\n1 = critical errors" - "\n2 = significant informations" - "\n3 = more verbose messages" - "\nLevel 3 is useful for testing only, when only " - "one device is used." - "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"." - "\n"); -#endif - -/*****************************************************************************/ - -static u32 -et61x251_request_buffers(struct et61x251_device* cam, u32 count, - enum et61x251_io_method io) -{ - struct v4l2_pix_format* p = &(cam->sensor.pix_format); - struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); - const size_t imagesize = cam->module_param.force_munmap || - io == IO_READ ? - (p->width * p->height * p->priv) / 8 : - (r->width * r->height * p->priv) / 8; - void* buff = NULL; - u32 i; - - if (count > ET61X251_MAX_FRAMES) - count = ET61X251_MAX_FRAMES; - - cam->nbuffers = count; - while (cam->nbuffers > 0) { - if ((buff = vmalloc_32_user(cam->nbuffers * - PAGE_ALIGN(imagesize)))) - break; - cam->nbuffers--; - } - - for (i = 0; i < cam->nbuffers; i++) { - cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.index = i; - cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.length = imagesize; - cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cam->frame[i].buf.sequence = 0; - cam->frame[i].buf.field = V4L2_FIELD_NONE; - cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; - cam->frame[i].buf.flags = 0; - } - - return cam->nbuffers; -} - - -static void et61x251_release_buffers(struct et61x251_device* cam) -{ - if (cam->nbuffers) { - vfree(cam->frame[0].bufmem); - cam->nbuffers = 0; - } - cam->frame_current = NULL; -} - - -static void et61x251_empty_framequeues(struct et61x251_device* cam) -{ - u32 i; - - INIT_LIST_HEAD(&cam->inqueue); - INIT_LIST_HEAD(&cam->outqueue); - - for (i = 0; i < ET61X251_MAX_FRAMES; i++) { - cam->frame[i].state = F_UNUSED; - cam->frame[i].buf.bytesused = 0; - } -} - - -static void et61x251_requeue_outqueue(struct et61x251_device* cam) -{ - struct et61x251_frame_t *i; - - list_for_each_entry(i, &cam->outqueue, frame) { - i->state = F_QUEUED; - list_add(&i->frame, &cam->inqueue); - } - - INIT_LIST_HEAD(&cam->outqueue); -} - - -static void et61x251_queue_unusedframes(struct et61x251_device* cam) -{ - unsigned long lock_flags; - u32 i; - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].state == F_UNUSED) { - cam->frame[i].state = F_QUEUED; - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[i].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - } -} - -/*****************************************************************************/ - -int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - *buff = value; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) { - DBG(3, "Failed to write a register (value 0x%02X, index " - "0x%02X, error %d)", value, index, res); - return -1; - } - - return 0; -} - - -static int et61x251_read_reg(struct et61x251_device* cam, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - DBG(3, "Failed to read a register (index 0x%02X, error %d)", - index, res); - - return (res >= 0) ? (int)(*buff) : -1; -} - - -static int -et61x251_i2c_wait(struct et61x251_device* cam, - const struct et61x251_sensor* sensor) -{ - int i, r; - - for (i = 1; i <= 8; i++) { - if (sensor->interface == ET61X251_I2C_3WIRES) { - r = et61x251_read_reg(cam, 0x8e); - if (!(r & 0x02) && (r >= 0)) - return 0; - } else { - r = et61x251_read_reg(cam, 0x8b); - if (!(r & 0x01) && (r >= 0)) - return 0; - } - if (r < 0) - return -EIO; - udelay(8*8); /* minimum for sensors at 400kHz */ - } - - return -EBUSY; -} - - -int -et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, - u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, - u8 data8, u8 address) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = data2; - data[1] = data3; - data[2] = data4; - data[3] = data5; - data[4] = data6; - data[5] = data7; - data[6] = data8; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x02 | (n << 4); - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - /* Start writing through the serial interface */ - data[0] = data1; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, &cam->sensor); - - if (err) - DBG(3, "I2C raw write failed for %s image sensor", - cam->sensor.name); - - PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, " - "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X," - " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address, - data1, data2, data3, data4, data5, data6, data7, data8); - - return err ? -1 : 0; - -} - - -/*****************************************************************************/ - -static void et61x251_urb_complete(struct urb *urb) -{ - struct et61x251_device* cam = urb->context; - struct et61x251_frame_t** f; - size_t imagesize; - u8 i; - int err = 0; - - if (urb->status == -ENOENT) - return; - - f = &cam->frame_current; - - if (cam->stream == STREAM_INTERRUPT) { - cam->stream = STREAM_OFF; - if ((*f)) - (*f)->state = F_QUEUED; - DBG(3, "Stream interrupted"); - wake_up(&cam->wait_stream); - } - - if (cam->state & DEV_DISCONNECTED) - return; - - if (cam->state & DEV_MISCONFIGURED) { - wake_up_interruptible(&cam->wait_frame); - return; - } - - if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) - goto resubmit_urb; - - if (!(*f)) - (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t, - frame); - - imagesize = (cam->sensor.pix_format.width * - cam->sensor.pix_format.height * - cam->sensor.pix_format.priv) / 8; - - for (i = 0; i < urb->number_of_packets; i++) { - unsigned int len, status; - void *pos; - u8* b1, * b2, sof; - const u8 VOID_BYTES = 6; - size_t imglen; - - len = urb->iso_frame_desc[i].actual_length; - status = urb->iso_frame_desc[i].status; - pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; - - if (status) { - DBG(3, "Error in isochronous frame"); - (*f)->state = F_ERROR; - continue; - } - - b1 = pos++; - b2 = pos++; - sof = ((*b1 & 0x3f) == 63); - imglen = ((*b1 & 0xc0) << 2) | *b2; - - PDBGG("Isochrnous frame: length %u, #%u i, image length %zu", - len, i, imglen); - - if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) -start_of_frame: - if (sof) { - (*f)->state = F_GRABBING; - (*f)->buf.bytesused = 0; - do_gettimeofday(&(*f)->buf.timestamp); - pos += 22; - DBG(3, "SOF detected: new video frame"); - } - - if ((*f)->state == F_GRABBING) { - if (sof && (*f)->buf.bytesused) { - if (cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_ET61X251) - goto end_of_frame; - else { - DBG(3, "Not expected SOF detected " - "after %lu bytes", - (unsigned long)(*f)->buf.bytesused); - (*f)->state = F_ERROR; - continue; - } - } - - if ((*f)->buf.bytesused + imglen > imagesize) { - DBG(3, "Video frame size exceeded"); - (*f)->state = F_ERROR; - continue; - } - - pos += VOID_BYTES; - - memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen); - (*f)->buf.bytesused += imglen; - - if ((*f)->buf.bytesused == imagesize) { - u32 b; -end_of_frame: - b = (*f)->buf.bytesused; - (*f)->state = F_DONE; - (*f)->buf.sequence= ++cam->frame_count; - spin_lock(&cam->queue_lock); - list_move_tail(&(*f)->frame, &cam->outqueue); - if (!list_empty(&cam->inqueue)) - (*f) = list_entry(cam->inqueue.next, - struct et61x251_frame_t, - frame); - else - (*f) = NULL; - spin_unlock(&cam->queue_lock); - DBG(3, "Video frame captured: : %lu bytes", - (unsigned long)(b)); - - if (!(*f)) - goto resubmit_urb; - - if (sof && - cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_ET61X251) - goto start_of_frame; - } - } - } - -resubmit_urb: - urb->dev = cam->usbdev; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0 && err != -EPERM) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "usb_submit_urb() failed"); - } - - wake_up_interruptible(&cam->wait_frame); -} - - -static int et61x251_start_transfer(struct et61x251_device* cam) -{ - struct usb_device *udev = cam->usbdev; - struct urb* urb; - struct usb_host_interface* altsetting = usb_altnum_to_altsetting( - usb_ifnum_to_if(udev, 0), - ET61X251_ALTERNATE_SETTING); - const unsigned int psz = le16_to_cpu(altsetting-> - endpoint[0].desc.wMaxPacketSize); - s8 i, j; - int err = 0; - - for (i = 0; i < ET61X251_URBS; i++) { - cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz, - GFP_KERNEL); - if (!cam->transfer_buffer[i]) { - err = -ENOMEM; - DBG(1, "Not enough memory"); - goto free_buffers; - } - } - - for (i = 0; i < ET61X251_URBS; i++) { - urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL); - cam->urb[i] = urb; - if (!urb) { - err = -ENOMEM; - DBG(1, "usb_alloc_urb() failed"); - goto free_urbs; - } - urb->dev = udev; - urb->context = cam; - urb->pipe = usb_rcvisocpipe(udev, 1); - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = ET61X251_ISO_PACKETS; - urb->complete = et61x251_urb_complete; - urb->transfer_buffer = cam->transfer_buffer[i]; - urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS; - urb->interval = 1; - for (j = 0; j < ET61X251_ISO_PACKETS; j++) { - urb->iso_frame_desc[j].offset = psz * j; - urb->iso_frame_desc[j].length = psz; - } - } - - err = et61x251_write_reg(cam, 0x01, 0x03); - err = et61x251_write_reg(cam, 0x00, 0x03); - err = et61x251_write_reg(cam, 0x08, 0x03); - if (err) { - err = -EIO; - DBG(1, "I/O hardware error"); - goto free_urbs; - } - - err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING); - if (err) { - DBG(1, "usb_set_interface() failed"); - goto free_urbs; - } - - cam->frame_current = NULL; - - for (i = 0; i < ET61X251_URBS; i++) { - err = usb_submit_urb(cam->urb[i], GFP_KERNEL); - if (err) { - for (j = i-1; j >= 0; j--) - usb_kill_urb(cam->urb[j]); - DBG(1, "usb_submit_urb() failed, error %d", err); - goto free_urbs; - } - } - - return 0; - -free_urbs: - for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++) - usb_free_urb(cam->urb[i]); - -free_buffers: - for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++) - kfree(cam->transfer_buffer[i]); - - return err; -} - - -static int et61x251_stop_transfer(struct et61x251_device* cam) -{ - struct usb_device *udev = cam->usbdev; - s8 i; - int err = 0; - - if (cam->state & DEV_DISCONNECTED) - return 0; - - for (i = ET61X251_URBS-1; i >= 0; i--) { - usb_kill_urb(cam->urb[i]); - usb_free_urb(cam->urb[i]); - kfree(cam->transfer_buffer[i]); - } - - err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ - if (err) - DBG(3, "usb_set_interface() failed"); - - return err; -} - - -static int et61x251_stream_interrupt(struct et61x251_device* cam) -{ - long timeout; - - cam->stream = STREAM_INTERRUPT; - timeout = wait_event_timeout(cam->wait_stream, - (cam->stream == STREAM_OFF) || - (cam->state & DEV_DISCONNECTED), - ET61X251_URB_TIMEOUT); - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - else if (cam->stream != STREAM_OFF) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "URB timeout reached. The camera is misconfigured. To " - "use it, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - return 0; -} - -/*****************************************************************************/ - -#ifdef CONFIG_VIDEO_ADV_DEBUG - -static int et61x251_i2c_try_read(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, - u8 address) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x10; - data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, sensor); - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - if (err) - DBG(3, "I2C read failed for %s image sensor", sensor->name); - - PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]); - - return err ? -1 : (int)data[0]; -} - - -static int et61x251_i2c_try_write(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, - u8 address, u8 value) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x12; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - data[0] = value; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, sensor); - - if (err) - DBG(3, "I2C write failed for %s image sensor", sensor->name); - - PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value); - - return err ? -1 : 0; -} - -static int et61x251_i2c_read(struct et61x251_device* cam, u8 address) -{ - return et61x251_i2c_try_read(cam, &cam->sensor, address); -} - -static int et61x251_i2c_write(struct et61x251_device* cam, - u8 address, u8 value) -{ - return et61x251_i2c_try_write(cam, &cam->sensor, address, value); -} - -static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) -{ - char str[5]; - char* endp; - unsigned long val; - - if (len < 4) { - strncpy(str, buff, len); - str[len] = '\0'; - } else { - strncpy(str, buff, 4); - str[4] = '\0'; - } - - val = simple_strtoul(str, &endp, 0); - - *count = 0; - if (val <= 0xff) - *count = (ssize_t)(endp - str); - if ((*count) && (len == *count+1) && (buff[*count] == '\n')) - *count += 1; - - return (u8)val; -} - -/* - NOTE 1: being inside one of the following methods implies that the v4l - device exists for sure (see kobjects and reference counters) - NOTE 2: buffers are PAGE_SIZE long -*/ - -static ssize_t et61x251_show_reg(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct et61x251_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.reg); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t -et61x251_store_reg(struct device* cd, - struct device_attribute *attr, const char* buf, size_t len) -{ - struct et61x251_device* cam; - u8 index; - ssize_t count; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - index = et61x251_strtou8(buf, len, &count); - if (index > 0x8e || !count) { - mutex_unlock(&et61x251_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.reg = index; - - DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t et61x251_show_val(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct et61x251_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) { - mutex_unlock(&et61x251_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t -et61x251_store_val(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct et61x251_device* cam; - u8 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - value = et61x251_strtou8(buf, len, &count); - if (!count) { - mutex_unlock(&et61x251_sysfs_lock); - return -EINVAL; - } - - err = et61x251_write_reg(cam, value, cam->sysfs.reg); - if (err) { - mutex_unlock(&et61x251_sysfs_lock); - return -EIO; - } - - DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X", - cam->sysfs.reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t et61x251_show_i2c_reg(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct et61x251_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t -et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct et61x251_device* cam; - u8 index; - ssize_t count; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - index = et61x251_strtou8(buf, len, &count); - if (!count) { - mutex_unlock(&et61x251_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.i2c_reg = index; - - DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t et61x251_show_i2c_val(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct et61x251_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENOSYS; - } - - if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { - mutex_unlock(&et61x251_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t -et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct et61x251_device* cam; - u8 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENOSYS; - } - - value = et61x251_strtou8(buf, len, &count); - if (!count) { - mutex_unlock(&et61x251_sysfs_lock); - return -EINVAL; - } - - err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value); - if (err) { - mutex_unlock(&et61x251_sysfs_lock); - return -EIO; - } - - DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", - cam->sysfs.i2c_reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - et61x251_show_reg, et61x251_store_reg); -static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - et61x251_show_val, et61x251_store_val); -static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - et61x251_show_i2c_reg, et61x251_store_i2c_reg); -static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - et61x251_show_i2c_val, et61x251_store_i2c_val); - - -static int et61x251_create_sysfs(struct et61x251_device* cam) -{ - struct device *classdev = &(cam->v4ldev->dev); - int err = 0; - - if ((err = device_create_file(classdev, &dev_attr_reg))) - goto err_out; - if ((err = device_create_file(classdev, &dev_attr_val))) - goto err_reg; - - if (cam->sensor.sysfs_ops) { - if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) - goto err_val; - if ((err = device_create_file(classdev, &dev_attr_i2c_val))) - goto err_i2c_reg; - } - -err_i2c_reg: - if (cam->sensor.sysfs_ops) - device_remove_file(classdev, &dev_attr_i2c_reg); -err_val: - device_remove_file(classdev, &dev_attr_val); -err_reg: - device_remove_file(classdev, &dev_attr_reg); -err_out: - return err; -} -#endif /* CONFIG_VIDEO_ADV_DEBUG */ - -/*****************************************************************************/ - -static int -et61x251_set_pix_format(struct et61x251_device* cam, - struct v4l2_pix_format* pix) -{ - int r, err = 0; - - if ((r = et61x251_read_reg(cam, 0x12)) < 0) - err += r; - if (pix->pixelformat == V4L2_PIX_FMT_ET61X251) - err += et61x251_write_reg(cam, r & 0xfd, 0x12); - else - err += et61x251_write_reg(cam, r | 0x02, 0x12); - - return err ? -EIO : 0; -} - - -static int -et61x251_set_compression(struct et61x251_device* cam, - struct v4l2_jpegcompression* compression) -{ - int r, err = 0; - - if ((r = et61x251_read_reg(cam, 0x12)) < 0) - err += r; - if (compression->quality == 0) - err += et61x251_write_reg(cam, r & 0xfb, 0x12); - else - err += et61x251_write_reg(cam, r | 0x04, 0x12); - - return err ? -EIO : 0; -} - - -static int et61x251_set_scale(struct et61x251_device* cam, u8 scale) -{ - int r = 0, err = 0; - - r = et61x251_read_reg(cam, 0x12); - if (r < 0) - err += r; - - if (scale == 1) - err += et61x251_write_reg(cam, r & ~0x01, 0x12); - else if (scale == 2) - err += et61x251_write_reg(cam, r | 0x01, 0x12); - - if (err) - return -EIO; - - PDBGG("Scaling factor: %u", scale); - - return 0; -} - - -static int -et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect) -{ - struct et61x251_sensor* s = &cam->sensor; - u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left + - s->active_pixel.left), - fmw_sy = (u16)(rect->top - s->cropcap.bounds.top + - s->active_pixel.top), - fmw_length = (u16)(rect->width), - fmw_height = (u16)(rect->height); - int err = 0; - - err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69); - err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a); - err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b); - err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c); - err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6) - | ((fmw_length & 0x300) >> 4) - | ((fmw_height & 0x300) >> 2), 0x6d); - if (err) - return -EIO; - - PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u", - fmw_sx, fmw_sy, fmw_length, fmw_height); - - return 0; -} - - -static int et61x251_init(struct et61x251_device* cam) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - struct v4l2_queryctrl *qctrl; - struct v4l2_rect* rect; - u8 i = 0; - int err = 0; - - if (!(cam->state & DEV_INITIALIZED)) { - mutex_init(&cam->open_mutex); - init_waitqueue_head(&cam->wait_open); - qctrl = s->qctrl; - rect = &(s->cropcap.defrect); - cam->compression.quality = ET61X251_COMPRESSION_QUALITY; - } else { /* use current values */ - qctrl = s->_qctrl; - rect = &(s->_rect); - } - - err += et61x251_set_scale(cam, rect->width / s->pix_format.width); - err += et61x251_set_crop(cam, rect); - if (err) - return err; - - if (s->init) { - err = s->init(cam); - if (err) { - DBG(3, "Sensor initialization failed"); - return err; - } - } - - err += et61x251_set_compression(cam, &cam->compression); - err += et61x251_set_pix_format(cam, &s->pix_format); - if (s->set_pix_format) - err += s->set_pix_format(cam, &s->pix_format); - if (err) - return err; - - if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251) - DBG(3, "Compressed video format is active, quality %d", - cam->compression.quality); - else - DBG(3, "Uncompressed video format is active"); - - if (s->set_crop) - if ((err = s->set_crop(cam, rect))) { - DBG(3, "set_crop() failed"); - return err; - } - - if (s->set_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (s->qctrl[i].id != 0 && - !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl.id = s->qctrl[i].id; - ctrl.value = qctrl[i].default_value; - err = s->set_ctrl(cam, &ctrl); - if (err) { - DBG(3, "Set %s control failed", - s->qctrl[i].name); - return err; - } - DBG(3, "Image sensor supports '%s' control", - s->qctrl[i].name); - } - } - - if (!(cam->state & DEV_INITIALIZED)) { - mutex_init(&cam->fileop_mutex); - spin_lock_init(&cam->queue_lock); - init_waitqueue_head(&cam->wait_frame); - init_waitqueue_head(&cam->wait_stream); - cam->nreadbuffers = 2; - memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); - memcpy(&(s->_rect), &(s->cropcap.defrect), - sizeof(struct v4l2_rect)); - cam->state |= DEV_INITIALIZED; - } - - DBG(2, "Initialization succeeded"); - return 0; -} - -/*****************************************************************************/ - -static void et61x251_release_resources(struct kref *kref) -{ - struct et61x251_device *cam; - - mutex_lock(&et61x251_sysfs_lock); - - cam = container_of(kref, struct et61x251_device, kref); - - DBG(2, "V4L2 device %s deregistered", - video_device_node_name(cam->v4ldev)); - video_set_drvdata(cam->v4ldev, NULL); - video_unregister_device(cam->v4ldev); - usb_put_dev(cam->usbdev); - kfree(cam->control_buffer); - kfree(cam); - - mutex_unlock(&et61x251_sysfs_lock); -} - - -static int et61x251_open(struct file *filp) -{ - struct et61x251_device* cam; - int err = 0; - - if (!down_read_trylock(&et61x251_dev_lock)) - return -ERESTARTSYS; - - cam = video_drvdata(filp); - - if (wait_for_completion_interruptible(&cam->probe)) { - up_read(&et61x251_dev_lock); - return -ERESTARTSYS; - } - - kref_get(&cam->kref); - - if (mutex_lock_interruptible(&cam->open_mutex)) { - kref_put(&cam->kref, et61x251_release_resources); - up_read(&et61x251_dev_lock); - return -ERESTARTSYS; - } - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - err = -ENODEV; - goto out; - } - - if (cam->users) { - DBG(2, "Device %s is already in use", - video_device_node_name(cam->v4ldev)); - DBG(3, "Simultaneous opens are not supported"); - if ((filp->f_flags & O_NONBLOCK) || - (filp->f_flags & O_NDELAY)) { - err = -EWOULDBLOCK; - goto out; - } - DBG(2, "A blocking open() has been requested. Wait for the " - "device to be released..."); - up_read(&et61x251_dev_lock); - err = wait_event_interruptible_exclusive(cam->wait_open, - (cam->state & DEV_DISCONNECTED) - || !cam->users); - down_read(&et61x251_dev_lock); - if (err) - goto out; - if (cam->state & DEV_DISCONNECTED) { - err = -ENODEV; - goto out; - } - } - - if (cam->state & DEV_MISCONFIGURED) { - err = et61x251_init(cam); - if (err) { - DBG(1, "Initialization failed again. " - "I will retry on next open()."); - goto out; - } - cam->state &= ~DEV_MISCONFIGURED; - } - - if ((err = et61x251_start_transfer(cam))) - goto out; - - filp->private_data = cam; - cam->users++; - cam->io = IO_NONE; - cam->stream = STREAM_OFF; - cam->nbuffers = 0; - cam->frame_count = 0; - et61x251_empty_framequeues(cam); - - DBG(3, "Video device %s is open", - video_device_node_name(cam->v4ldev)); - -out: - mutex_unlock(&cam->open_mutex); - if (err) - kref_put(&cam->kref, et61x251_release_resources); - up_read(&et61x251_dev_lock); - return err; -} - - -static int et61x251_release(struct file *filp) -{ - struct et61x251_device* cam; - - down_write(&et61x251_dev_lock); - - cam = video_drvdata(filp); - - et61x251_stop_transfer(cam); - et61x251_release_buffers(cam); - cam->users--; - wake_up_interruptible_nr(&cam->wait_open, 1); - - DBG(3, "Video device %s closed", - video_device_node_name(cam->v4ldev)); - - kref_put(&cam->kref, et61x251_release_resources); - - up_write(&et61x251_dev_lock); - - return 0; -} - - -static ssize_t -et61x251_read(struct file* filp, char __user * buf, - size_t count, loff_t* f_pos) -{ - struct et61x251_device *cam = video_drvdata(filp); - struct et61x251_frame_t* f, * i; - unsigned long lock_flags; - long timeout; - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (cam->io == IO_MMAP) { - DBG(3, "Close and open the device again to choose the read " - "method"); - mutex_unlock(&cam->fileop_mutex); - return -EBUSY; - } - - if (cam->io == IO_NONE) { - if (!et61x251_request_buffers(cam, cam->nreadbuffers, - IO_READ)) { - DBG(1, "read() failed, not enough memory"); - mutex_unlock(&cam->fileop_mutex); - return -ENOMEM; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (list_empty(&cam->inqueue)) { - if (!list_empty(&cam->outqueue)) - et61x251_empty_framequeues(cam); - et61x251_queue_unusedframes(cam); - } - - if (!count) { - mutex_unlock(&cam->fileop_mutex); - return 0; - } - - if (list_empty(&cam->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - msecs_to_jiffies( - cam->module_param.frame_timeout * 1000 - ) - ); - if (timeout < 0) { - mutex_unlock(&cam->fileop_mutex); - return timeout; - } - if (cam->state & DEV_DISCONNECTED) { - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - if (!timeout || (cam->state & DEV_MISCONFIGURED)) { - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - } - - f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame); - - if (count > f->buf.bytesused) - count = f->buf.bytesused; - - if (copy_to_user(buf, f->bufmem, count)) { - err = -EFAULT; - goto exit; - } - *f_pos += count; - -exit: - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(i, &cam->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - et61x251_queue_unusedframes(cam); - - PDBGG("Frame #%lu, bytes read: %zu", - (unsigned long)f->buf.index, count); - - mutex_unlock(&cam->fileop_mutex); - - return err ? err : count; -} - - -static unsigned int et61x251_poll(struct file *filp, poll_table *wait) -{ - struct et61x251_device *cam = video_drvdata(filp); - struct et61x251_frame_t* f; - unsigned long lock_flags; - unsigned int mask = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return POLLERR; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - goto error; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - goto error; - } - - if (cam->io == IO_NONE) { - if (!et61x251_request_buffers(cam, cam->nreadbuffers, - IO_READ)) { - DBG(1, "poll() failed, not enough memory"); - goto error; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (cam->io == IO_READ) { - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(f, &cam->outqueue, frame) - f->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - et61x251_queue_unusedframes(cam); - } - - poll_wait(filp, &cam->wait_frame, wait); - - if (!list_empty(&cam->outqueue)) - mask |= POLLIN | POLLRDNORM; - - mutex_unlock(&cam->fileop_mutex); - - return mask; - -error: - mutex_unlock(&cam->fileop_mutex); - return POLLERR; -} - - -static void et61x251_vm_open(struct vm_area_struct* vma) -{ - struct et61x251_frame_t* f = vma->vm_private_data; - f->vma_use_count++; -} - - -static void et61x251_vm_close(struct vm_area_struct* vma) -{ - /* NOTE: buffers are not freed here */ - struct et61x251_frame_t* f = vma->vm_private_data; - f->vma_use_count--; -} - - -static const struct vm_operations_struct et61x251_vm_ops = { - .open = et61x251_vm_open, - .close = et61x251_vm_close, -}; - - -static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) -{ - struct et61x251_device *cam = video_drvdata(filp); - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { - mutex_unlock(&cam->fileop_mutex); - return -EACCES; - } - - if (cam->io != IO_MMAP || - size != PAGE_ALIGN(cam->frame[0].buf.length)) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - for (i = 0; i < cam->nbuffers; i++) { - if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == cam->nbuffers) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; - - pos = cam->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &et61x251_vm_ops; - vma->vm_private_data = &cam->frame[i]; - et61x251_vm_open(vma); - - mutex_unlock(&cam->fileop_mutex); - - return 0; -} - -/*****************************************************************************/ - -static int -et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_capability cap = { - .driver = "et61x251", - .version = ET61X251_MODULE_VERSION_CODE, - .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING, - }; - - strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); - if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) - strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev), - sizeof(cap.bus_info)); - - if (copy_to_user(arg, &cap, sizeof(cap))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_input i; - - if (copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - - if (i.index) - return -EINVAL; - - memset(&i, 0, sizeof(i)); - strcpy(i.name, "Camera"); - i.type = V4L2_INPUT_TYPE_CAMERA; - i.capabilities = V4L2_IN_CAP_STD; - - if (copy_to_user(arg, &i, sizeof(i))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg) -{ - int index = 0; - - if (copy_to_user(arg, &index, sizeof(index))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg) -{ - int index; - - if (copy_from_user(&index, arg, sizeof(index))) - return -EFAULT; - - if (index != 0) - return -EINVAL; - - return 0; -} - - -static int -et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_queryctrl qc; - u8 i; - - if (copy_from_user(&qc, arg, sizeof(qc))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (qc.id && qc.id == s->qctrl[i].id) { - memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); - if (copy_to_user(arg, &qc, sizeof(qc))) - return -EFAULT; - return 0; - } - - return -EINVAL; -} - - -static int -et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - int err = 0; - u8 i; - - if (!s->get_ctrl && !s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - if (!s->get_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (ctrl.id == s->qctrl[i].id) { - ctrl.value = s->_qctrl[i].default_value; - goto exit; - } - return -EINVAL; - } else - err = s->get_ctrl(cam, &ctrl); - -exit: - if (copy_to_user(arg, &ctrl, sizeof(ctrl))) - return -EFAULT; - - return err; -} - - -static int -et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - u8 i; - int err = 0; - - if (!s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) { - if (ctrl.id == s->qctrl[i].id) { - if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) - return -EINVAL; - if (ctrl.value < s->qctrl[i].minimum || - ctrl.value > s->qctrl[i].maximum) - return -ERANGE; - ctrl.value -= ctrl.value % s->qctrl[i].step; - break; - } - } - if (i == ARRAY_SIZE(s->qctrl)) - return -EINVAL; - if ((err = s->set_ctrl(cam, &ctrl))) - return err; - - s->_qctrl[i].default_value = ctrl.value; - - return 0; -} - - -static int -et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_cropcap* cc = &(cam->sensor.cropcap); - - cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cc->pixelaspect.numerator = 1; - cc->pixelaspect.denominator = 1; - - if (copy_to_user(arg, cc, sizeof(*cc))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_crop crop = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - }; - - memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); - - if (copy_to_user(arg, &crop, sizeof(crop))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_crop crop; - struct v4l2_rect* rect; - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_pix_format* pix_format = &(s->pix_format); - u8 scale; - const enum et61x251_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&crop, arg, sizeof(crop))) - return -EFAULT; - - rect = &(crop.c); - - if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_CROP failed. " - "Unmap the buffers first."); - return -EBUSY; - } - - /* Preserve R,G or B origin */ - rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; - rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; - - if (rect->width < 16) - rect->width = 16; - if (rect->height < 16) - rect->height = 16; - if (rect->width > bounds->width) - rect->width = bounds->width; - if (rect->height > bounds->height) - rect->height = bounds->height; - if (rect->left < bounds->left) - rect->left = bounds->left; - if (rect->top < bounds->top) - rect->top = bounds->top; - if (rect->left + rect->width > bounds->left + bounds->width) - rect->left = bounds->left+bounds->width - rect->width; - if (rect->top + rect->height > bounds->top + bounds->height) - rect->top = bounds->top+bounds->height - rect->height; - - rect->width &= ~15L; - rect->height &= ~15L; - - if (ET61X251_PRESERVE_IMGSCALE) { - /* Calculate the actual scaling factor */ - u32 a, b; - a = rect->width * rect->height; - b = pix_format->width * pix_format->height; - scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; - } else - scale = 1; - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &crop, sizeof(crop))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - et61x251_release_buffers(cam); - - err = et61x251_set_crop(cam, rect); - if (s->set_crop) - err += s->set_crop(cam, rect); - err += et61x251_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - s->pix_format.width = rect->width/scale; - s->pix_format.height = rect->height/scale; - memcpy(&(s->_rect), rect, sizeof(*rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -ENOMEM; - } - - if (cam->io == IO_READ) - et61x251_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - et61x251_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -et61x251_vidioc_enum_framesizes(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_frmsizeenum frmsize; - - if (copy_from_user(&frmsize, arg, sizeof(frmsize))) - return -EFAULT; - - if (frmsize.index != 0) - return -EINVAL; - - if (frmsize.pixel_format != V4L2_PIX_FMT_ET61X251 && - frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) - return -EINVAL; - - frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE; - frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16; - frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16; - frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width; - frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height; - memset(&frmsize.reserved, 0, sizeof(frmsize.reserved)); - - if (copy_to_user(arg, &frmsize, sizeof(frmsize))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_fmtdesc fmtd; - - if (copy_from_user(&fmtd, arg, sizeof(fmtd))) - return -EFAULT; - - if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (fmtd.index == 0) { - strcpy(fmtd.description, "bayer rgb"); - fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; - } else if (fmtd.index == 1) { - strcpy(fmtd.description, "compressed"); - fmtd.pixelformat = V4L2_PIX_FMT_ET61X251; - fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; - } else - return -EINVAL; - - fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); - - if (copy_to_user(arg, &fmtd, sizeof(fmtd))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ? - 0 : V4L2_COLORSPACE_SRGB; - pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251) - ? 0 : (pfmt->width * pfmt->priv) / 8; - pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); - pfmt->field = V4L2_FIELD_NONE; - memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); - - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, - void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_format format; - struct v4l2_pix_format* pix; - struct v4l2_pix_format* pfmt = &(s->pix_format); - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_rect rect; - u8 scale; - const enum et61x251_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - pix = &(format.fmt.pix); - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memcpy(&rect, &(s->_rect), sizeof(rect)); - - { /* calculate the actual scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; - } - - rect.width = scale * pix->width; - rect.height = scale * pix->height; - - if (rect.width < 16) - rect.width = 16; - if (rect.height < 16) - rect.height = 16; - if (rect.width > bounds->left + bounds->width - rect.left) - rect.width = bounds->left + bounds->width - rect.left; - if (rect.height > bounds->top + bounds->height - rect.top) - rect.height = bounds->top + bounds->height - rect.top; - - rect.width &= ~15L; - rect.height &= ~15L; - - { /* adjust the scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; - } - - pix->width = rect.width / scale; - pix->height = rect.height / scale; - - if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 && - pix->pixelformat != V4L2_PIX_FMT_SBGGR8) - pix->pixelformat = pfmt->pixelformat; - pix->priv = pfmt->priv; /* bpp */ - pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ? - 0 : V4L2_COLORSPACE_SRGB; - pix->colorspace = pfmt->colorspace; - pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) - ? 0 : (pix->width * pix->priv) / 8; - pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); - pix->field = V4L2_FIELD_NONE; - - if (cmd == VIDIOC_TRY_FMT) { - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - return 0; - } - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_FMT failed. " - "Unmap the buffers first."); - return -EBUSY; - } - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &format, sizeof(format))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - et61x251_release_buffers(cam); - - err += et61x251_set_pix_format(cam, pix); - err += et61x251_set_crop(cam, &rect); - if (s->set_pix_format) - err += s->set_pix_format(cam, pix); - if (s->set_crop) - err += s->set_crop(cam, &rect); - err += et61x251_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - memcpy(pfmt, pix, sizeof(*pix)); - memcpy(&(s->_rect), &rect, sizeof(rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -ENOMEM; - } - - if (cam->io == IO_READ) - et61x251_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - et61x251_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg) -{ - if (copy_to_user(arg, &cam->compression, - sizeof(cam->compression))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_jpegcompression jc; - const enum et61x251_stream_state stream = cam->stream; - int err = 0; - - if (copy_from_user(&jc, arg, sizeof(jc))) - return -EFAULT; - - if (jc.quality != 0 && jc.quality != 1) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - err += et61x251_set_compression(cam, &jc); - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " - "problems. To use the camera, close and open " - "%s again.", video_device_node_name(cam->v4ldev)); - return -EIO; - } - - cam->compression.quality = jc.quality; - - cam->stream = stream; - - return 0; -} - - -static int -et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_requestbuffers rb; - u32 i; - int err; - - if (copy_from_user(&rb, arg, sizeof(rb))) - return -EFAULT; - - if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb.memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (cam->io == IO_READ) { - DBG(3, "Close and open the device again to choose the mmap " - "I/O method"); - return -EBUSY; - } - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_REQBUFS failed. " - "Previous buffers are still mapped."); - return -EBUSY; - } - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - et61x251_empty_framequeues(cam); - - et61x251_release_buffers(cam); - if (rb.count) - rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP); - - if (copy_to_user(arg, &rb, sizeof(rb))) { - et61x251_release_buffers(cam); - cam->io = IO_NONE; - return -EFAULT; - } - - cam->io = rb.count ? IO_MMAP : IO_NONE; - - return 0; -} - - -static int -et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); - - if (cam->frame[b.index].vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (cam->frame[b.index].state == F_DONE) - b.flags |= V4L2_BUF_FLAG_DONE; - else if (cam->frame[b.index].state != F_UNUSED) - b.flags |= V4L2_BUF_FLAG_QUEUED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - unsigned long lock_flags; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->frame[b.index].state != F_UNUSED) - return -EINVAL; - - cam->frame[b.index].state = F_QUEUED; - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - PDBGG("Frame #%lu queued", (unsigned long)b.index); - - return 0; -} - - -static int -et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp, - void __user * arg) -{ - struct v4l2_buffer b; - struct et61x251_frame_t *f; - unsigned long lock_flags; - long timeout; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) - return -EINVAL; - - if (list_empty(&cam->outqueue)) { - if (cam->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) - return timeout; - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - if (!timeout || (cam->state & DEV_MISCONFIGURED)) - return -EIO; - } - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame); - list_del(cam->outqueue.next); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - f->state = F_UNUSED; - - memcpy(&b, &f->buf, sizeof(b)); - if (f->vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); - - return 0; -} - - -static int -et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg) -{ - int type; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - cam->stream = STREAM_ON; - - DBG(3, "Stream on"); - - return 0; -} - - -static int -et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg) -{ - int type, err; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - et61x251_empty_framequeues(cam); - - DBG(3, "Stream off"); - - return 0; -} - - -static int -et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - - if (sp.parm.capture.readbuffers == 0) - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES) - sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - cam->nreadbuffers = sp.parm.capture.readbuffers; - - return 0; -} - - -static long et61x251_ioctl_v4l2(struct file *filp, - unsigned int cmd, void __user *arg) -{ - struct et61x251_device *cam = video_drvdata(filp); - - switch (cmd) { - - case VIDIOC_QUERYCAP: - return et61x251_vidioc_querycap(cam, arg); - - case VIDIOC_ENUMINPUT: - return et61x251_vidioc_enuminput(cam, arg); - - case VIDIOC_G_INPUT: - return et61x251_vidioc_g_input(cam, arg); - - case VIDIOC_S_INPUT: - return et61x251_vidioc_s_input(cam, arg); - - case VIDIOC_QUERYCTRL: - return et61x251_vidioc_query_ctrl(cam, arg); - - case VIDIOC_G_CTRL: - return et61x251_vidioc_g_ctrl(cam, arg); - - case VIDIOC_S_CTRL: - return et61x251_vidioc_s_ctrl(cam, arg); - - case VIDIOC_CROPCAP: - return et61x251_vidioc_cropcap(cam, arg); - - case VIDIOC_G_CROP: - return et61x251_vidioc_g_crop(cam, arg); - - case VIDIOC_S_CROP: - return et61x251_vidioc_s_crop(cam, arg); - - case VIDIOC_ENUM_FMT: - return et61x251_vidioc_enum_fmt(cam, arg); - - case VIDIOC_G_FMT: - return et61x251_vidioc_g_fmt(cam, arg); - - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - return et61x251_vidioc_try_s_fmt(cam, cmd, arg); - - case VIDIOC_ENUM_FRAMESIZES: - return et61x251_vidioc_enum_framesizes(cam, arg); - - case VIDIOC_G_JPEGCOMP: - return et61x251_vidioc_g_jpegcomp(cam, arg); - - case VIDIOC_S_JPEGCOMP: - return et61x251_vidioc_s_jpegcomp(cam, arg); - - case VIDIOC_REQBUFS: - return et61x251_vidioc_reqbufs(cam, arg); - - case VIDIOC_QUERYBUF: - return et61x251_vidioc_querybuf(cam, arg); - - case VIDIOC_QBUF: - return et61x251_vidioc_qbuf(cam, arg); - - case VIDIOC_DQBUF: - return et61x251_vidioc_dqbuf(cam, filp, arg); - - case VIDIOC_STREAMON: - return et61x251_vidioc_streamon(cam, arg); - - case VIDIOC_STREAMOFF: - return et61x251_vidioc_streamoff(cam, arg); - - case VIDIOC_G_PARM: - return et61x251_vidioc_g_parm(cam, arg); - - case VIDIOC_S_PARM: - return et61x251_vidioc_s_parm(cam, arg); - - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_QUERYSTD: - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYMENU: - case VIDIOC_ENUM_FRAMEINTERVALS: - return -EINVAL; - - default: - return -EINVAL; - - } -} - - -static long et61x251_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct et61x251_device *cam = video_drvdata(filp); - long err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - V4LDBG(3, "et61x251", cmd); - - err = et61x251_ioctl_v4l2(filp, cmd, (void __user *)arg); - - mutex_unlock(&cam->fileop_mutex); - - return err; -} - - -static const struct v4l2_file_operations et61x251_fops = { - .owner = THIS_MODULE, - .open = et61x251_open, - .release = et61x251_release, - .unlocked_ioctl = et61x251_ioctl, - .read = et61x251_read, - .poll = et61x251_poll, - .mmap = et61x251_mmap, -}; - -/*****************************************************************************/ - -/* It exists a single interface only. We do not need to validate anything. */ -static int -et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct et61x251_device* cam; - static unsigned int dev_nr; - unsigned int i; - int err = 0; - - if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL))) - return -ENOMEM; - - cam->usbdev = udev; - - if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { - DBG(1, "kmalloc() failed"); - err = -ENOMEM; - goto fail; - } - - if (!(cam->v4ldev = video_device_alloc())) { - DBG(1, "video_device_alloc() failed"); - err = -ENOMEM; - goto fail; - } - - DBG(2, "ET61X[12]51 PC Camera Controller detected " - "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct); - - for (i = 0; et61x251_sensor_table[i]; i++) { - err = et61x251_sensor_table[i](cam); - if (!err) - break; - } - - if (!err) - DBG(2, "%s image sensor detected", cam->sensor.name); - else { - DBG(1, "No supported image sensor detected"); - err = -ENODEV; - goto fail; - } - - if (et61x251_init(cam)) { - DBG(1, "Initialization failed. I will retry on open()."); - cam->state |= DEV_MISCONFIGURED; - } - - strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); - cam->v4ldev->fops = &et61x251_fops; - cam->v4ldev->release = video_device_release; - cam->v4ldev->parent = &udev->dev; - video_set_drvdata(cam->v4ldev, cam); - - init_completion(&cam->probe); - - err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, - video_nr[dev_nr]); - if (err) { - DBG(1, "V4L2 device registration failed"); - if (err == -ENFILE && video_nr[dev_nr] == -1) - DBG(1, "Free /dev/videoX node not found"); - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; - complete_all(&cam->probe); - goto fail; - } - - DBG(2, "V4L2 device registered as %s", - video_device_node_name(cam->v4ldev)); - - cam->module_param.force_munmap = force_munmap[dev_nr]; - cam->module_param.frame_timeout = frame_timeout[dev_nr]; - - dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; - -#ifdef CONFIG_VIDEO_ADV_DEBUG - err = et61x251_create_sysfs(cam); - if (!err) - DBG(2, "Optional device control through 'sysfs' " - "interface ready"); - else - DBG(2, "Failed to create 'sysfs' interface for optional " - "device controlling. Error #%d", err); -#else - DBG(2, "Optional device control through 'sysfs' interface disabled"); - DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " - "configuration option to enable it."); -#endif - - usb_set_intfdata(intf, cam); - kref_init(&cam->kref); - usb_get_dev(cam->usbdev); - - complete_all(&cam->probe); - - return 0; - -fail: - if (cam) { - kfree(cam->control_buffer); - if (cam->v4ldev) - video_device_release(cam->v4ldev); - kfree(cam); - } - return err; -} - - -static void et61x251_usb_disconnect(struct usb_interface* intf) -{ - struct et61x251_device* cam; - - down_write(&et61x251_dev_lock); - - cam = usb_get_intfdata(intf); - - DBG(2, "Disconnecting %s...", cam->v4ldev->name); - - if (cam->users) { - DBG(2, "Device %s is open! Deregistration and memory " - "deallocation are deferred.", - video_device_node_name(cam->v4ldev)); - cam->state |= DEV_MISCONFIGURED; - et61x251_stop_transfer(cam); - cam->state |= DEV_DISCONNECTED; - wake_up_interruptible(&cam->wait_frame); - wake_up(&cam->wait_stream); - } else - cam->state |= DEV_DISCONNECTED; - - wake_up_interruptible_all(&cam->wait_open); - - kref_put(&cam->kref, et61x251_release_resources); - - up_write(&et61x251_dev_lock); -} - - -static struct usb_driver et61x251_usb_driver = { - .name = "et61x251", - .id_table = et61x251_id_table, - .probe = et61x251_usb_probe, - .disconnect = et61x251_usb_disconnect, -}; - -/*****************************************************************************/ - -static int __init et61x251_module_init(void) -{ - int err = 0; - - KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION); - KDBG(3, ET61X251_MODULE_AUTHOR); - - if ((err = usb_register(&et61x251_usb_driver))) - KDBG(1, "usb_register() failed"); - - return err; -} - - -static void __exit et61x251_module_exit(void) -{ - usb_deregister(&et61x251_usb_driver); -} - - -module_init(et61x251_module_init); -module_exit(et61x251_module_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,210 +0,0 @@ -/*************************************************************************** - * V4L2 driver for ET61X[12]51 PC Camera Controllers * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _ET61X251_H_ -#define _ET61X251_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "et61x251_sensor.h" - -/*****************************************************************************/ - -#define ET61X251_DEBUG -#define ET61X251_DEBUG_LEVEL 2 -#define ET61X251_MAX_DEVICES 64 -#define ET61X251_PRESERVE_IMGSCALE 0 -#define ET61X251_FORCE_MUNMAP 0 -#define ET61X251_MAX_FRAMES 32 -#define ET61X251_COMPRESSION_QUALITY 0 -#define ET61X251_URBS 2 -#define ET61X251_ISO_PACKETS 7 -#define ET61X251_ALTERNATE_SETTING 13 -#define ET61X251_URB_TIMEOUT msecs_to_jiffies(2 * ET61X251_ISO_PACKETS) -#define ET61X251_CTRL_TIMEOUT 100 -#define ET61X251_FRAME_TIMEOUT 2 - -/*****************************************************************************/ - -static const struct usb_device_id et61x251_id_table[] = { - { USB_DEVICE(0x102c, 0x6251), }, - { } -}; - -ET61X251_SENSOR_TABLE - -/*****************************************************************************/ - -enum et61x251_frame_state { - F_UNUSED, - F_QUEUED, - F_GRABBING, - F_DONE, - F_ERROR, -}; - -struct et61x251_frame_t { - void* bufmem; - struct v4l2_buffer buf; - enum et61x251_frame_state state; - struct list_head frame; - unsigned long vma_use_count; -}; - -enum et61x251_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -enum et61x251_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -enum et61x251_stream_state { - STREAM_OFF, - STREAM_INTERRUPT, - STREAM_ON, -}; - -struct et61x251_sysfs_attr { - u8 reg, i2c_reg; -}; - -struct et61x251_module_param { - u8 force_munmap; - u16 frame_timeout; -}; - -static DEFINE_MUTEX(et61x251_sysfs_lock); -static DECLARE_RWSEM(et61x251_dev_lock); - -struct et61x251_device { - struct video_device* v4ldev; - - struct et61x251_sensor sensor; - - struct usb_device* usbdev; - struct urb* urb[ET61X251_URBS]; - void* transfer_buffer[ET61X251_URBS]; - u8* control_buffer; - - struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES]; - struct list_head inqueue, outqueue; - u32 frame_count, nbuffers, nreadbuffers; - - enum et61x251_io_method io; - enum et61x251_stream_state stream; - - struct v4l2_jpegcompression compression; - - struct et61x251_sysfs_attr sysfs; - struct et61x251_module_param module_param; - - struct kref kref; - enum et61x251_dev_state state; - u8 users; - - struct completion probe; - struct mutex open_mutex, fileop_mutex; - spinlock_t queue_lock; - wait_queue_head_t wait_open, wait_frame, wait_stream; -}; - -/*****************************************************************************/ - -struct et61x251_device* -et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id) -{ - return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; -} - - -void -et61x251_attach_sensor(struct et61x251_device* cam, - const struct et61x251_sensor* sensor) -{ - memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor)); -} - -/*****************************************************************************/ - -#undef DBG -#undef KDBG -#ifdef ET61X251_DEBUG -# define DBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1) \ - dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) == 2) \ - dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ - __FILE__, __func__, __LINE__ , ## args); \ - } \ -} while (0) -# define KDBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1 || (level) == 2) \ - pr_info("et61x251: " fmt "\n", ## args); \ - else if ((level) == 3) \ - pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \ - __func__, __LINE__ , ## args); \ - } \ -} while (0) -# define V4LDBG(level, name, cmd) \ -do { \ - if (debug >= (level)) \ - v4l_print_ioctl(name, cmd); \ -} while (0) -#else -# define DBG(level, fmt, args...) do {;} while(0) -# define KDBG(level, fmt, args...) do {;} while(0) -# define V4LDBG(level, name, cmd) do {;} while(0) -#endif - -#undef PDBG -#define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \ - __LINE__ , ## args) - -#undef PDBGG -#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ - -#endif /* _ET61X251_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_sensor.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_sensor.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_sensor.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_sensor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/*************************************************************************** - * API for image sensors connected to ET61X[12]51 PC Camera Controllers * - * * - * Copyright (C) 2006-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _ET61X251_SENSOR_H_ -#define _ET61X251_SENSOR_H_ - -#include -#include -#include -#include -#include -#include - -struct et61x251_device; -struct et61x251_sensor; - -/*****************************************************************************/ - -extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam); - -#define ET61X251_SENSOR_TABLE \ -/* Weak detections must go at the end of the list */ \ -static int (*et61x251_sensor_table[])(struct et61x251_device*) = { \ - &et61x251_probe_tas5130d1b, \ - NULL, \ -}; - -extern struct et61x251_device* -et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id); - -extern void -et61x251_attach_sensor(struct et61x251_device* cam, - const struct et61x251_sensor* sensor); - -/*****************************************************************************/ - -extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index); -extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1, - u8 data2, u8 data3, u8 data4, u8 data5, - u8 data6, u8 data7, u8 data8, u8 address); - -/*****************************************************************************/ - -enum et61x251_i2c_sysfs_ops { - ET61X251_I2C_READ = 0x01, - ET61X251_I2C_WRITE = 0x02, -}; - -enum et61x251_i2c_interface { - ET61X251_I2C_2WIRES, - ET61X251_I2C_3WIRES, -}; - -/* Repeat start condition when RSTA is high */ -enum et61x251_i2c_rsta { - ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */ - ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */ -}; - -#define ET61X251_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10) - -struct et61x251_sensor { - char name[32]; - - enum et61x251_i2c_sysfs_ops sysfs_ops; - - enum et61x251_i2c_interface interface; - u8 i2c_slave_id; - enum et61x251_i2c_rsta rsta; - struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */ - - struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS]; - struct v4l2_cropcap cropcap; - struct v4l2_pix_format pix_format; - - int (*init)(struct et61x251_device* cam); - int (*get_ctrl)(struct et61x251_device* cam, - struct v4l2_control* ctrl); - int (*set_ctrl)(struct et61x251_device* cam, - const struct v4l2_control* ctrl); - int (*set_crop)(struct et61x251_device* cam, - const struct v4l2_rect* rect); - int (*set_pix_format)(struct et61x251_device* cam, - const struct v4l2_pix_format* pix); - - /* Private */ - struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS]; - struct v4l2_rect _rect; -}; - -#endif /* _ET61X251_SENSOR_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_tas5130d1b.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_tas5130d1b.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_tas5130d1b.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/et61x251_tas5130d1b.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51 * - * PC Camera Controllers * - * * - * Copyright (C) 2006-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "et61x251_sensor.h" - - -static int tas5130d1b_init(struct et61x251_device* cam) -{ - int err = 0; - - err += et61x251_write_reg(cam, 0x14, 0x01); - err += et61x251_write_reg(cam, 0x1b, 0x02); - err += et61x251_write_reg(cam, 0x02, 0x12); - err += et61x251_write_reg(cam, 0x0e, 0x60); - err += et61x251_write_reg(cam, 0x80, 0x61); - err += et61x251_write_reg(cam, 0xf0, 0x62); - err += et61x251_write_reg(cam, 0x03, 0x63); - err += et61x251_write_reg(cam, 0x14, 0x64); - err += et61x251_write_reg(cam, 0xf4, 0x65); - err += et61x251_write_reg(cam, 0x01, 0x66); - err += et61x251_write_reg(cam, 0x05, 0x67); - err += et61x251_write_reg(cam, 0x8f, 0x68); - err += et61x251_write_reg(cam, 0x0f, 0x8d); - err += et61x251_write_reg(cam, 0x08, 0x8e); - - return err; -} - - -static int tas5130d1b_set_ctrl(struct et61x251_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += et61x251_i2c_raw_write(cam, 2, 0x20, - 0xf6-ctrl->value, 0, 0, 0, - 0, 0, 0, 0); - break; - case V4L2_CID_EXPOSURE: - err += et61x251_i2c_raw_write(cam, 2, 0x40, - 0x47-ctrl->value, 0, 0, 0, - 0, 0, 0, 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static const struct et61x251_sensor tas5130d1b = { - .name = "TAS5130D1B", - .interface = ET61X251_I2C_3WIRES, - .rsta = ET61X251_I2C_RSTA_STOP, - .active_pixel = { - .left = 106, - .top = 13, - }, - .init = &tas5130d1b_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xf6, - .step = 0x02, - .default_value = 0x0d, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x47, - .step = 0x01, - .default_value = 0x23, - .flags = 0, - }, - }, - .set_ctrl = &tas5130d1b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, -}; - - -int et61x251_probe_tas5130d1b(struct et61x251_device* cam) -{ - const struct usb_device_id tas5130d1b_id_table[] = { - { USB_DEVICE(0x102c, 0x6251), }, - { } - }; - - /* Sensor detection is based on USB pid/vid */ - if (!et61x251_match_id(cam, tas5130d1b_id_table)) - return -ENODEV; - - et61x251_attach_sensor(cam, &tas5130d1b); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -config USB_ET61X251 - tristate "USB ET61X[12]51 PC Camera Controller support (DEPRECATED)" - depends on VIDEO_V4L2 - default n - ---help--- - This driver is DEPRECATED please use the gspca zc3xx module - instead. - - Say Y here if you want support for cameras based on Etoms ET61X151 - or ET61X251 PC Camera Controllers. - - See for more info. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. - - To compile this driver as a module, choose M here: the - module will be called et61x251. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/et61x251/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o - -obj-$(CONFIG_USB_ET61X251) += et61x251.o - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/fsl-viu.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/fsl-viu.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/fsl-viu.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/fsl-viu.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1659 +0,0 @@ -/* - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * Freescale VIU video driver - * - * Authors: Hongjun Chen - * Porting to 2.6.35 by DENX Software Engineering, - * Anatolij Gustschin - * - * 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, or (at your - * option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "fsl_viu" -#define VIU_MAJOR_VERSION 0 -#define VIU_MINOR_VERSION 5 -#define VIU_RELEASE 0 -#define VIU_VERSION KERNEL_VERSION(VIU_MAJOR_VERSION, \ - VIU_MINOR_VERSION, \ - VIU_RELEASE) - -#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ - -#define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */ - -/* I2C address of video decoder chip is 0x4A */ -#define VIU_VIDEO_DECODER_ADDR 0x25 - -/* supported controls */ -static struct v4l2_queryctrl viu_qctrl[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - .flags = 0, - }, { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 0x1, - .default_value = 0x10, - .flags = 0, - }, { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 0x1, - .default_value = 127, - .flags = 0, - }, { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = -128, - .maximum = 127, - .step = 0x1, - .default_value = 0, - .flags = 0, - } -}; - -static int qctl_regs[ARRAY_SIZE(viu_qctrl)]; - -static int info_level; - -#define dprintk(level, fmt, arg...) \ - do { \ - if (level <= info_level) \ - printk(KERN_DEBUG "viu: " fmt , ## arg); \ - } while (0) - -/* - * Basic structures - */ -struct viu_fmt { - char name[32]; - u32 fourcc; /* v4l2 format id */ - u32 pixelformat; - int depth; -}; - -static struct viu_fmt formats[] = { - { - .name = "RGB-16 (5/B-6/G-5/R)", - .fourcc = V4L2_PIX_FMT_RGB565, - .pixelformat = V4L2_PIX_FMT_RGB565, - .depth = 16, - }, { - .name = "RGB-32 (A-R-G-B)", - .fourcc = V4L2_PIX_FMT_RGB32, - .pixelformat = V4L2_PIX_FMT_RGB32, - .depth = 32, - } -}; - -struct viu_dev; -struct viu_buf; - -/* buffer for one video frame */ -struct viu_buf { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - struct viu_fmt *fmt; -}; - -struct viu_dmaqueue { - struct viu_dev *dev; - struct list_head active; - struct list_head queued; - struct timer_list timeout; -}; - -struct viu_status { - u32 field_irq; - u32 vsync_irq; - u32 hsync_irq; - u32 vstart_irq; - u32 dma_end_irq; - u32 error_irq; -}; - -struct viu_reg { - u32 status_cfg; - u32 luminance; - u32 chroma_r; - u32 chroma_g; - u32 chroma_b; - u32 field_base_addr; - u32 dma_inc; - u32 picture_count; - u32 req_alarm; - u32 alpha; -} __attribute__ ((packed)); - -struct viu_dev { - struct v4l2_device v4l2_dev; - struct mutex lock; - spinlock_t slock; - int users; - - struct device *dev; - /* various device info */ - struct video_device *vdev; - struct viu_dmaqueue vidq; - enum v4l2_field capfield; - int field; - int first; - int dma_done; - - /* Hardware register area */ - struct viu_reg *vr; - - /* Interrupt vector */ - int irq; - struct viu_status irqs; - - /* video overlay */ - struct v4l2_framebuffer ovbuf; - struct viu_fmt *ovfmt; - unsigned int ovenable; - enum v4l2_field ovfield; - - /* crop */ - struct v4l2_rect crop_current; - - /* clock pointer */ - struct clk *clk; - - /* decoder */ - struct v4l2_subdev *decoder; - - v4l2_std_id std; -}; - -struct viu_fh { - struct viu_dev *dev; - - /* video capture */ - struct videobuf_queue vb_vidq; - spinlock_t vbq_lock; /* spinlock for the videobuf queue */ - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip clips[1]; - - /* video capture */ - struct viu_fmt *fmt; - int width, height, sizeimage; - enum v4l2_buf_type type; -}; - -static struct viu_reg reg_val; - -/* - * Macro definitions of VIU registers - */ - -/* STATUS_CONFIG register */ -enum status_config { - SOFT_RST = 1 << 0, - - ERR_MASK = 0x0f << 4, /* Error code mask */ - ERR_NO = 0x00, /* No error */ - ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */ - ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */ - ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */ - ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */ - ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */ - ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */ - ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */ - ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */ - ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */ - ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */ - - INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */ - INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */ - INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */ - INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */ - INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */ - INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */ - INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */ - - INT_FIELD_STATUS = 0x01 << 16, /* field interrupt status */ - INT_VSYNC_STATUS = 0x01 << 17, /* vsync interrupt status */ - INT_HSYNC_STATUS = 0x01 << 18, /* hsync interrupt status */ - INT_VSTART_STATUS = 0x01 << 19, /* vstart interrupt status */ - INT_DMA_END_STATUS = 0x01 << 20, /* DMA end interrupt status */ - INT_ERROR_STATUS = 0x01 << 21, /* error interrupt status */ - - DMA_ACT = 0x01 << 27, /* Enable DMA transfer */ - FIELD_NO = 0x01 << 28, /* Field number */ - DITHER_ON = 0x01 << 29, /* Dithering is on */ - ROUND_ON = 0x01 << 30, /* Round is on */ - MODE_32BIT = 0x01 << 31, /* Data in RGBa888, - * 0 in RGB565 - */ -}; - -#define norm_maxw() 720 -#define norm_maxh() 576 - -#define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \ - INT_HSYNC_STATUS | INT_VSTART_STATUS | \ - INT_DMA_END_STATUS | INT_ERROR_STATUS) - -#define NUM_FORMATS ARRAY_SIZE(formats) - -static irqreturn_t viu_intr(int irq, void *dev_id); - -struct viu_fmt *format_by_fourcc(int fourcc) -{ - int i; - - for (i = 0; i < NUM_FORMATS; i++) { - if (formats[i].pixelformat == fourcc) - return formats + i; - } - - dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc); - return NULL; -} - -void viu_start_dma(struct viu_dev *dev) -{ - struct viu_reg *vr = dev->vr; - - dev->field = 0; - - /* Enable DMA operation */ - out_be32(&vr->status_cfg, SOFT_RST); - out_be32(&vr->status_cfg, INT_FIELD_EN); -} - -void viu_stop_dma(struct viu_dev *dev) -{ - struct viu_reg *vr = dev->vr; - int cnt = 100; - u32 status_cfg; - - out_be32(&vr->status_cfg, 0); - - /* Clear pending interrupts */ - status_cfg = in_be32(&vr->status_cfg); - if (status_cfg & 0x3f0000) - out_be32(&vr->status_cfg, status_cfg & 0x3f0000); - - if (status_cfg & DMA_ACT) { - do { - status_cfg = in_be32(&vr->status_cfg); - if (status_cfg & INT_DMA_END_STATUS) - break; - } while (cnt--); - - if (cnt < 0) { - /* timed out, issue soft reset */ - out_be32(&vr->status_cfg, SOFT_RST); - out_be32(&vr->status_cfg, 0); - } else { - /* clear DMA_END and other pending irqs */ - out_be32(&vr->status_cfg, status_cfg & 0x3f0000); - } - } - - dev->field = 0; -} - -static int restart_video_queue(struct viu_dmaqueue *vidq) -{ - struct viu_buf *buf, *prev; - - dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq); - if (!list_empty(&vidq->active)) { - buf = list_entry(vidq->active.next, struct viu_buf, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - - viu_stop_dma(vidq->dev); - - /* cancel all outstanding capture requests */ - list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) { - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - } - mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&vidq->queued)) - return 0; - buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue); - if (prev == NULL) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &vidq->active); - - dprintk(1, "Restarting video dma\n"); - viu_stop_dma(vidq->dev); - viu_start_dma(vidq->dev); - - buf->vb.state = VIDEOBUF_ACTIVE; - mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] restart_queue - first active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(2, "[%p/%d] restart_queue - move to active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } -} - -static void viu_vid_timeout(unsigned long data) -{ - struct viu_dev *dev = (struct viu_dev *)data; - struct viu_buf *buf; - struct viu_dmaqueue *vidq = &dev->vidq; - - while (!list_empty(&vidq->active)) { - buf = list_entry(vidq->active.next, struct viu_buf, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i); - } - - restart_video_queue(vidq); -} - -/* - * Videobuf operations - */ -static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct viu_fh *fh = vq->priv_data; - - *size = fh->width * fh->height * fh->fmt->depth >> 3; - if (*count == 0) - *count = 32; - - while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024) - (*count)--; - - dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size); - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf) -{ - struct videobuf_buffer *vb = &buf->vb; - void *vaddr = NULL; - - BUG_ON(in_interrupt()); - - videobuf_waiton(vq, &buf->vb, 0, 0); - - if (vq->int_ops && vq->int_ops->vaddr) - vaddr = vq->int_ops->vaddr(vb); - - if (vaddr) - videobuf_dma_contig_free(vq, &buf->vb); - - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf) -{ - struct viu_reg *vr = dev->vr; - int bpp; - - /* setup the DMA base address */ - reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb); - - dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n", - buf, buf->vb.i, (unsigned long)reg_val.field_base_addr); - - /* interlace is on by default, set horizontal DMA increment */ - reg_val.status_cfg = 0; - bpp = buf->fmt->depth >> 3; - switch (bpp) { - case 2: - reg_val.status_cfg &= ~MODE_32BIT; - reg_val.dma_inc = buf->vb.width * 2; - break; - case 4: - reg_val.status_cfg |= MODE_32BIT; - reg_val.dma_inc = buf->vb.width * 4; - break; - default: - dprintk(0, "doesn't support color depth(%d)\n", - bpp * 8); - return -EINVAL; - } - - /* setup picture_count register */ - reg_val.picture_count = (buf->vb.height / 2) << 16 | - buf->vb.width; - - reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN; - - buf->vb.state = VIDEOBUF_ACTIVE; - dev->capfield = buf->vb.field; - - /* reset dma increment if needed */ - if (!V4L2_FIELD_HAS_BOTH(buf->vb.field)) - reg_val.dma_inc = 0; - - out_be32(&vr->dma_inc, reg_val.dma_inc); - out_be32(&vr->picture_count, reg_val.picture_count); - out_be32(&vr->field_base_addr, reg_val.field_base_addr); - mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT); - return 0; -} - -static int buffer_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct viu_fh *fh = vq->priv_data; - struct viu_buf *buf = container_of(vb, struct viu_buf, vb); - int rc; - - BUG_ON(fh->fmt == NULL); - - if (fh->width < 48 || fh->width > norm_maxw() || - fh->height < 32 || fh->height > norm_maxh()) - return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; - if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - } - - if (buf->vb.state == VIDEOBUF_NEEDS_INIT) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc != 0) - goto fail; - - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - buf->fmt = fh->fmt; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct viu_buf *buf = container_of(vb, struct viu_buf, vb); - struct viu_fh *fh = vq->priv_data; - struct viu_dev *dev = fh->dev; - struct viu_dmaqueue *vidq = &dev->vidq; - struct viu_buf *prev; - - if (!list_empty(&vidq->queued)) { - dprintk(1, "adding vb queue=0x%08lx\n", - (unsigned long)&buf->vb.queue); - dprintk(1, "vidq pointer 0x%p, queued 0x%p\n", - vidq, &vidq->queued); - dprintk(1, "dev %p, queued: self %p, next %p, head %p\n", - dev, &vidq->queued, vidq->queued.next, - vidq->queued.prev); - list_add_tail(&buf->vb.queue, &vidq->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", - buf, buf->vb.i); - } else if (list_empty(&vidq->active)) { - dprintk(1, "adding vb active=0x%08lx\n", - (unsigned long)&buf->vb.queue); - list_add_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; - mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] buffer_queue - first active\n", - buf, buf->vb.i); - - buffer_activate(dev, buf); - } else { - dprintk(1, "adding vb queue2=0x%08lx\n", - (unsigned long)&buf->vb.queue); - prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue); - if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - } else { - list_add_tail(&buf->vb.queue, &vidq->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", - buf, buf->vb.i); - } - } -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct viu_buf *buf = container_of(vb, struct viu_buf, vb); - struct viu_fh *fh = vq->priv_data; - struct viu_dev *dev = (struct viu_dev *)fh->dev; - - viu_stop_dma(dev); - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops viu_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* - * IOCTL vidioc handling - */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strcpy(cap->driver, "viu"); - strcpy(cap->card, "viu"); - cap->version = VIU_VERSION; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_READWRITE; - return 0; -} - -static int vidioc_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - int index = f->index; - - if (f->index > NUM_FORMATS) - return -EINVAL; - - strlcpy(f->description, formats[index].name, sizeof(f->description)); - f->pixelformat = formats[index].fourcc; - return 0; -} - -static int vidioc_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vb_vidq.field; - f->fmt.pix.pixelformat = fh->fmt->pixelformat; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = fh->sizeimage; - return 0; -} - -static int vidioc_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fmt *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (!fmt) { - dprintk(1, "Fourcc format (0x%08x) invalid.", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - field = f->fmt.pix.field; - - if (field == V4L2_FIELD_ANY) { - field = V4L2_FIELD_INTERLACED; - } else if (field != V4L2_FIELD_INTERLACED) { - dprintk(1, "Field type invalid.\n"); - return -EINVAL; - } - - maxw = norm_maxw(); - maxh = norm_maxh(); - - f->fmt.pix.field = field; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - - return 0; -} - -static int vidioc_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fh *fh = priv; - int ret; - - ret = vidioc_try_fmt_cap(file, fh, f); - if (ret < 0) - return ret; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->sizeimage = f->fmt.pix.sizeimage; - fh->vb_vidq.field = f->fmt.pix.field; - fh->type = f->type; - dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name); - return 0; -} - -static int vidioc_g_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fh *fh = priv; - - f->fmt.win = fh->win; - return 0; -} - -static int verify_preview(struct viu_dev *dev, struct v4l2_window *win) -{ - enum v4l2_field field; - int maxw, maxh; - - if (dev->ovbuf.base == NULL) - return -EINVAL; - if (dev->ovfmt == NULL) - return -EINVAL; - if (win->w.width < 48 || win->w.height < 32) - return -EINVAL; - - field = win->field; - maxw = dev->crop_current.width; - maxh = dev->crop_current.height; - - if (field == V4L2_FIELD_ANY) { - field = (win->w.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - win->field = field; - if (win->w.width > maxw) - win->w.width = maxw; - if (win->w.height > maxh) - win->w.height = maxh; - return 0; -} - -inline void viu_activate_overlay(struct viu_reg *viu_reg) -{ - struct viu_reg *vr = viu_reg; - - out_be32(&vr->field_base_addr, reg_val.field_base_addr); - out_be32(&vr->dma_inc, reg_val.dma_inc); - out_be32(&vr->picture_count, reg_val.picture_count); -} - -static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh) -{ - int bpp; - - dprintk(1, "%s %dx%d %s\n", __func__, - fh->win.w.width, fh->win.w.height, dev->ovfmt->name); - - reg_val.status_cfg = 0; - - /* setup window */ - reg_val.picture_count = (fh->win.w.height / 2) << 16 | - fh->win.w.width; - - /* setup color depth and dma increment */ - bpp = dev->ovfmt->depth / 8; - switch (bpp) { - case 2: - reg_val.status_cfg &= ~MODE_32BIT; - reg_val.dma_inc = fh->win.w.width * 2; - break; - case 4: - reg_val.status_cfg |= MODE_32BIT; - reg_val.dma_inc = fh->win.w.width * 4; - break; - default: - dprintk(0, "device doesn't support color depth(%d)\n", - bpp * 8); - return -EINVAL; - } - - dev->ovfield = fh->win.field; - if (!V4L2_FIELD_HAS_BOTH(dev->ovfield)) - reg_val.dma_inc = 0; - - reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN; - - /* setup the base address of the overlay buffer */ - reg_val.field_base_addr = (u32)dev->ovbuf.base; - - dev->ovenable = 1; - viu_activate_overlay(dev->vr); - - /* start dma */ - viu_start_dma(dev); - return 0; -} - -static int vidioc_s_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fh *fh = priv; - struct viu_dev *dev = (struct viu_dev *)fh->dev; - unsigned long flags; - int err; - - err = verify_preview(dev, &f->fmt.win); - if (err) - return err; - - mutex_lock(&dev->lock); - fh->win = f->fmt.win; - - spin_lock_irqsave(&dev->slock, flags); - viu_start_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_try_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - return 0; -} - -int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) -{ - struct viu_fh *fh = priv; - struct viu_dev *dev = fh->dev; - struct v4l2_framebuffer *fb = arg; - - *fb = dev->ovbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - return 0; -} - -int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) -{ - struct viu_fh *fh = priv; - struct viu_dev *dev = fh->dev; - struct v4l2_framebuffer *fb = arg; - struct viu_fmt *fmt; - - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (fmt == NULL) - return -EINVAL; - - /* ok, accept it */ - dev->ovbuf = *fb; - dev->ovfmt = fmt; - if (dev->ovbuf.fmt.bytesperline == 0) { - dev->ovbuf.fmt.bytesperline = - dev->ovbuf.fmt.width * fmt->depth / 8; - } - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct viu_fh *fh = priv; - - return videobuf_reqbufs(&fh->vb_vidq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct viu_fh *fh = priv; - - return videobuf_querybuf(&fh->vb_vidq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct viu_fh *fh = priv; - - return videobuf_qbuf(&fh->vb_vidq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct viu_fh *fh = priv; - - return videobuf_dqbuf(&fh->vb_vidq, p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct viu_fh *fh = priv; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (fh->type != i) - return -EINVAL; - - viu_start_dma(fh->dev); - - return videobuf_streamon(&fh->vb_vidq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct viu_fh *fh = priv; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (fh->type != i) - return -EINVAL; - - viu_stop_dma(fh->dev); - - return videobuf_streamoff(&fh->vb_vidq); -} - -#define decoder_call(viu, o, f, args...) \ - v4l2_subdev_call(viu->decoder, o, f, ##args) - -static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct viu_fh *fh = priv; - - decoder_call(fh->dev, video, querystd, std_id); - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct viu_fh *fh = priv; - - fh->dev->std = *id; - decoder_call(fh->dev, core, s_std, *id); - return 0; -} - -static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct viu_fh *fh = priv; - - *std_id = fh->dev->std; - return 0; -} - -/* only one input in this driver */ -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct viu_fh *fh = priv; - - if (inp->index != 0) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = fh->dev->vdev->tvnorms; - strcpy(inp->name, "Camera"); - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct viu_fh *fh = priv; - - if (i > 1) - return -EINVAL; - - decoder_call(fh->dev, video, s_routing, i, 0, 0); - return 0; -} - -/* Controls */ -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) { - if (qc->id && qc->id == viu_qctrl[i].id) { - memcpy(qc, &(viu_qctrl[i]), sizeof(*qc)); - return 0; - } - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) { - if (ctrl->id == viu_qctrl[i].id) { - ctrl->value = qctl_regs[i]; - return 0; - } - } - return -EINVAL; -} -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) { - if (ctrl->id == viu_qctrl[i].id) { - if (ctrl->value < viu_qctrl[i].minimum - || ctrl->value > viu_qctrl[i].maximum) - return -ERANGE; - qctl_regs[i] = ctrl->value; - return 0; - } - } - return -EINVAL; -} - -inline void viu_activate_next_buf(struct viu_dev *dev, - struct viu_dmaqueue *viuq) -{ - struct viu_dmaqueue *vidq = viuq; - struct viu_buf *buf; - - /* launch another DMA operation for an active/queued buffer */ - if (!list_empty(&vidq->active)) { - buf = list_entry(vidq->active.next, struct viu_buf, - vb.queue); - dprintk(1, "start another queued buffer: 0x%p\n", buf); - buffer_activate(dev, buf); - } else if (!list_empty(&vidq->queued)) { - buf = list_entry(vidq->queued.next, struct viu_buf, - vb.queue); - list_del(&buf->vb.queue); - - dprintk(1, "start another queued buffer: 0x%p\n", buf); - list_add_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buffer_activate(dev, buf); - } -} - -inline void viu_default_settings(struct viu_reg *viu_reg) -{ - struct viu_reg *vr = viu_reg; - - out_be32(&vr->luminance, 0x9512A254); - out_be32(&vr->chroma_r, 0x03310000); - out_be32(&vr->chroma_g, 0x06600F38); - out_be32(&vr->chroma_b, 0x00000409); - out_be32(&vr->alpha, 0x000000ff); - out_be32(&vr->req_alarm, 0x00000090); - dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n", - in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr)); -} - -static void viu_overlay_intr(struct viu_dev *dev, u32 status) -{ - struct viu_reg *vr = dev->vr; - - if (status & INT_DMA_END_STATUS) - dev->dma_done = 1; - - if (status & INT_FIELD_STATUS) { - if (dev->dma_done) { - u32 addr = reg_val.field_base_addr; - - dev->dma_done = 0; - if (status & FIELD_NO) - addr += reg_val.dma_inc; - - out_be32(&vr->field_base_addr, addr); - out_be32(&vr->dma_inc, reg_val.dma_inc); - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | - (status & INT_ALL_STATUS) | - reg_val.status_cfg); - } else if (status & INT_VSYNC_STATUS) { - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | - (status & INT_ALL_STATUS) | - reg_val.status_cfg); - } - } -} - -static void viu_capture_intr(struct viu_dev *dev, u32 status) -{ - struct viu_dmaqueue *vidq = &dev->vidq; - struct viu_reg *vr = dev->vr; - struct viu_buf *buf; - int field_num; - int need_two; - int dma_done = 0; - - field_num = status & FIELD_NO; - need_two = V4L2_FIELD_HAS_BOTH(dev->capfield); - - if (status & INT_DMA_END_STATUS) { - dma_done = 1; - if (((field_num == 0) && (dev->field == 0)) || - (field_num && (dev->field == 1))) - dev->field++; - } - - if (status & INT_FIELD_STATUS) { - dprintk(1, "irq: field %d, done %d\n", - !!field_num, dma_done); - if (unlikely(dev->first)) { - if (field_num == 0) { - dev->first = 0; - dprintk(1, "activate first buf\n"); - viu_activate_next_buf(dev, vidq); - } else - dprintk(1, "wait field 0\n"); - return; - } - - /* setup buffer address for next dma operation */ - if (!list_empty(&vidq->active)) { - u32 addr = reg_val.field_base_addr; - - if (field_num && need_two) { - addr += reg_val.dma_inc; - dprintk(1, "field 1, 0x%lx, dev field %d\n", - (unsigned long)addr, dev->field); - } - out_be32(&vr->field_base_addr, addr); - out_be32(&vr->dma_inc, reg_val.dma_inc); - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | - (status & INT_ALL_STATUS) | - reg_val.status_cfg); - return; - } - } - - if (dma_done && field_num && (dev->field == 2)) { - dev->field = 0; - buf = list_entry(vidq->active.next, - struct viu_buf, vb.queue); - dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n", - buf, buf->vb.i, - (unsigned long)videobuf_to_dma_contig(&buf->vb), - (unsigned long)in_be32(&vr->field_base_addr)); - - if (waitqueue_active(&buf->vb.done)) { - list_del(&buf->vb.queue); - do_gettimeofday(&buf->vb.ts); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - wake_up(&buf->vb.done); - } - /* activate next dma buffer */ - viu_activate_next_buf(dev, vidq); - } -} - -static irqreturn_t viu_intr(int irq, void *dev_id) -{ - struct viu_dev *dev = (struct viu_dev *)dev_id; - struct viu_reg *vr = dev->vr; - u32 status; - u32 error; - - status = in_be32(&vr->status_cfg); - - if (status & INT_ERROR_STATUS) { - dev->irqs.error_irq++; - error = status & ERR_MASK; - if (error) - dprintk(1, "Err: error(%d), times:%d!\n", - error >> 4, dev->irqs.error_irq); - /* Clear interrupt error bit and error flags */ - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | INT_ERROR_STATUS); - } - - if (status & INT_DMA_END_STATUS) { - dev->irqs.dma_end_irq++; - dev->dma_done = 1; - dprintk(2, "VIU DMA end interrupt times: %d\n", - dev->irqs.dma_end_irq); - } - - if (status & INT_HSYNC_STATUS) - dev->irqs.hsync_irq++; - - if (status & INT_FIELD_STATUS) { - dev->irqs.field_irq++; - dprintk(2, "VIU field interrupt times: %d\n", - dev->irqs.field_irq); - } - - if (status & INT_VSTART_STATUS) - dev->irqs.vstart_irq++; - - if (status & INT_VSYNC_STATUS) { - dev->irqs.vsync_irq++; - dprintk(2, "VIU vsync interrupt times: %d\n", - dev->irqs.vsync_irq); - } - - /* clear all pending irqs */ - status = in_be32(&vr->status_cfg); - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | (status & INT_ALL_STATUS)); - - if (dev->ovenable) { - viu_overlay_intr(dev, status); - return IRQ_HANDLED; - } - - /* Capture mode */ - viu_capture_intr(dev, status); - return IRQ_HANDLED; -} - -/* - * File operations for the device - */ -static int viu_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct viu_dev *dev = video_get_drvdata(vdev); - struct viu_fh *fh; - struct viu_reg *vr; - int minor = vdev->minor; - u32 status_cfg; - int i; - - dprintk(1, "viu: open (minor=%d)\n", minor); - - dev->users++; - if (dev->users > 1) { - dev->users--; - return -EBUSY; - } - - vr = dev->vr; - - dprintk(1, "open minor=%d type=%s users=%d\n", minor, - v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); - - /* allocate and initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) { - dev->users--; - return -ENOMEM; - } - - file->private_data = fh; - fh->dev = dev; - - fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_RGB32); - fh->width = norm_maxw(); - fh->height = norm_maxh(); - dev->crop_current.width = fh->width; - dev->crop_current.height = fh->height; - - /* Put all controls at a sane state */ - for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) - qctl_regs[i] = viu_qctrl[i].default_value; - - dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", - (unsigned long)fh, (unsigned long)dev, - (unsigned long)&dev->vidq); - dprintk(1, "Open: list_empty queued=%d\n", - list_empty(&dev->vidq.queued)); - dprintk(1, "Open: list_empty active=%d\n", - list_empty(&dev->vidq.active)); - - viu_default_settings(vr); - - status_cfg = in_be32(&vr->status_cfg); - out_be32(&vr->status_cfg, - status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN | - INT_FIELD_EN | INT_VSTART_EN | - INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN)); - - status_cfg = in_be32(&vr->status_cfg); - out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS); - - spin_lock_init(&fh->vbq_lock); - videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops, - dev->dev, &fh->vbq_lock, - fh->type, V4L2_FIELD_INTERLACED, - sizeof(struct viu_buf), fh, NULL); - return 0; -} - -static ssize_t viu_read(struct file *file, char __user *data, size_t count, - loff_t *ppos) -{ - struct viu_fh *fh = file->private_data; - struct viu_dev *dev = fh->dev; - int ret = 0; - - dprintk(2, "%s\n", __func__); - if (dev->ovenable) - dev->ovenable = 0; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - viu_start_dma(dev); - ret = videobuf_read_stream(&fh->vb_vidq, data, count, - ppos, 0, file->f_flags & O_NONBLOCK); - return ret; - } - return 0; -} - -static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait) -{ - struct viu_fh *fh = file->private_data; - struct videobuf_queue *q = &fh->vb_vidq; - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) - return POLLERR; - - return videobuf_poll_stream(file, q, wait); -} - -static int viu_release(struct file *file) -{ - struct viu_fh *fh = file->private_data; - struct viu_dev *dev = fh->dev; - int minor = video_devdata(file)->minor; - - viu_stop_dma(dev); - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - - kfree(fh); - - dev->users--; - dprintk(1, "close (minor=%d, users=%d)\n", - minor, dev->users); - return 0; -} - -void viu_reset(struct viu_reg *reg) -{ - out_be32(®->status_cfg, 0); - out_be32(®->luminance, 0x9512a254); - out_be32(®->chroma_r, 0x03310000); - out_be32(®->chroma_g, 0x06600f38); - out_be32(®->chroma_b, 0x00000409); - out_be32(®->field_base_addr, 0); - out_be32(®->dma_inc, 0); - out_be32(®->picture_count, 0x01e002d0); - out_be32(®->req_alarm, 0x00000090); - out_be32(®->alpha, 0x000000ff); -} - -static int viu_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct viu_fh *fh = file->private_data; - int ret; - - dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); - - ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); - - dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, - ret); - - return ret; -} - -static struct v4l2_file_operations viu_fops = { - .owner = THIS_MODULE, - .open = viu_open, - .release = viu_release, - .read = viu_read, - .poll = viu_poll, - .ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = viu_mmap, -}; - -static const struct v4l2_ioctl_ops viu_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap, - .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt, - .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay, - .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay, - .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay, - .vidioc_g_fbuf = vidioc_g_fbuf, - .vidioc_s_fbuf = vidioc_s_fbuf, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_g_std = vidioc_g_std, - .vidioc_s_std = vidioc_s_std, - .vidioc_querystd = vidioc_querystd, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, -}; - -static struct video_device viu_template = { - .name = "FSL viu", - .fops = &viu_fops, - .minor = -1, - .ioctl_ops = &viu_ioctl_ops, - .release = video_device_release, - - .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, - .current_norm = V4L2_STD_NTSC_M, -}; - -static int __devinit viu_of_probe(struct platform_device *op, - const struct of_device_id *match) -{ - struct viu_dev *viu_dev; - struct video_device *vdev; - struct resource r; - struct viu_reg __iomem *viu_regs; - struct i2c_adapter *ad; - int ret, viu_irq; - - ret = of_address_to_resource(op->dev.of_node, 0, &r); - if (ret) { - dev_err(&op->dev, "Can't parse device node resource\n"); - return -ENODEV; - } - - viu_irq = irq_of_parse_and_map(op->dev.of_node, 0); - if (viu_irq == NO_IRQ) { - dev_err(&op->dev, "Error while mapping the irq\n"); - return -EINVAL; - } - - /* request mem region */ - if (!devm_request_mem_region(&op->dev, r.start, - sizeof(struct viu_reg), DRV_NAME)) { - dev_err(&op->dev, "Error while requesting mem region\n"); - ret = -EBUSY; - goto err; - } - - /* remap registers */ - viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg)); - if (!viu_regs) { - dev_err(&op->dev, "Can't map register set\n"); - ret = -ENOMEM; - goto err; - } - - /* Prepare our private structure */ - viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC); - if (!viu_dev) { - dev_err(&op->dev, "Can't allocate private structure\n"); - ret = -ENOMEM; - goto err; - } - - viu_dev->vr = viu_regs; - viu_dev->irq = viu_irq; - viu_dev->dev = &op->dev; - - /* init video dma queues */ - INIT_LIST_HEAD(&viu_dev->vidq.active); - INIT_LIST_HEAD(&viu_dev->vidq.queued); - - /* initialize locks */ - mutex_init(&viu_dev->lock); - - snprintf(viu_dev->v4l2_dev.name, - sizeof(viu_dev->v4l2_dev.name), "%s", "VIU"); - ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev); - if (ret < 0) { - dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret); - goto err; - } - - ad = i2c_get_adapter(0); - viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad, - "saa7113", VIU_VIDEO_DECODER_ADDR, NULL); - - viu_dev->vidq.timeout.function = viu_vid_timeout; - viu_dev->vidq.timeout.data = (unsigned long)viu_dev; - init_timer(&viu_dev->vidq.timeout); - viu_dev->first = 1; - - /* Allocate memory for video device */ - vdev = video_device_alloc(); - if (vdev == NULL) { - ret = -ENOMEM; - goto err_vdev; - } - - memcpy(vdev, &viu_template, sizeof(viu_template)); - - vdev->v4l2_dev = &viu_dev->v4l2_dev; - - viu_dev->vdev = vdev; - - video_set_drvdata(viu_dev->vdev, viu_dev); - - ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1); - if (ret < 0) { - video_device_release(viu_dev->vdev); - goto err_vdev; - } - - /* enable VIU clock */ - viu_dev->clk = clk_get(&op->dev, "viu_clk"); - if (IS_ERR(viu_dev->clk)) { - dev_err(&op->dev, "failed to find the clock module!\n"); - ret = -ENODEV; - goto err_clk; - } else { - clk_enable(viu_dev->clk); - } - - /* reset VIU module */ - viu_reset(viu_dev->vr); - - /* install interrupt handler */ - if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) { - dev_err(&op->dev, "Request VIU IRQ failed.\n"); - ret = -ENODEV; - goto err_irq; - } - - dev_info(&op->dev, "Freescale VIU Video Capture Board\n"); - return ret; - -err_irq: - clk_disable(viu_dev->clk); - clk_put(viu_dev->clk); -err_clk: - video_unregister_device(viu_dev->vdev); -err_vdev: - i2c_put_adapter(ad); - v4l2_device_unregister(&viu_dev->v4l2_dev); -err: - irq_dispose_mapping(viu_irq); - return ret; -} - -static int __devexit viu_of_remove(struct platform_device *op) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); - struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); - struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next, - struct v4l2_subdev, list); - struct i2c_client *client = v4l2_get_subdevdata(sdev); - - free_irq(dev->irq, (void *)dev); - irq_dispose_mapping(dev->irq); - - clk_disable(dev->clk); - clk_put(dev->clk); - - video_unregister_device(dev->vdev); - i2c_put_adapter(client->adapter); - v4l2_device_unregister(&dev->v4l2_dev); - return 0; -} - -#ifdef CONFIG_PM -static int viu_suspend(struct platform_device *op, pm_message_t state) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); - struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); - - clk_disable(dev->clk); - return 0; -} - -static int viu_resume(struct platform_device *op) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); - struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); - - clk_enable(dev->clk); - return 0; -} -#endif - -/* - * Initialization and module stuff - */ -static struct of_device_id mpc512x_viu_of_match[] = { - { - .compatible = "fsl,mpc5121-viu", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match); - -static struct of_platform_driver viu_of_platform_driver = { - .probe = viu_of_probe, - .remove = __devexit_p(viu_of_remove), -#ifdef CONFIG_PM - .suspend = viu_suspend, - .resume = viu_resume, -#endif - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - .of_match_table = mpc512x_viu_of_match, - }, -}; - -static int __init viu_init(void) -{ - return of_register_platform_driver(&viu_of_platform_driver); -} - -static void __exit viu_exit(void) -{ - of_unregister_platform_driver(&viu_of_platform_driver); -} - -module_init(viu_init); -module_exit(viu_exit); - -MODULE_DESCRIPTION("Freescale Video-In(VIU)"); -MODULE_AUTHOR("Hongjun Chen"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/autogain_functions.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/autogain_functions.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/autogain_functions.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/autogain_functions.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,179 +0,0 @@ -/* - * Functions for auto gain. - * - * Copyright (C) 2010-2011 Hans de Goede - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -/* auto gain and exposure algorithm based on the knee algorithm described here: - http://ytse.tricolour.net/docs/LowLightOptimization.html - - Returns 0 if no changes were made, 1 if the gain and or exposure settings - where changed. */ -static inline int auto_gain_n_exposure( - struct gspca_dev *gspca_dev, - int avg_lum, - int desired_avg_lum, - int deadzone, - int gain_knee, - int exposure_knee) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, steps, gain, orig_gain, exposure, orig_exposure; - int retval = 0; - - orig_gain = gain = sd->ctrls[GAIN].val; - orig_exposure = exposure = sd->ctrls[EXPOSURE].val; - - /* If we are of a multiple of deadzone, do multiple steps to reach the - desired lumination fast (with the risc of a slight overshoot) */ - steps = abs(desired_avg_lum - avg_lum) / deadzone; - - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", - avg_lum, desired_avg_lum, steps); - - for (i = 0; i < steps; i++) { - if (avg_lum > desired_avg_lum) { - if (gain > gain_knee) - gain--; - else if (exposure > exposure_knee) - exposure--; - else if (gain > sd->ctrls[GAIN].def) - gain--; - else if (exposure > sd->ctrls[EXPOSURE].min) - exposure--; - else if (gain > sd->ctrls[GAIN].min) - gain--; - else - break; - } else { - if (gain < sd->ctrls[GAIN].def) - gain++; - else if (exposure < exposure_knee) - exposure++; - else if (gain < gain_knee) - gain++; - else if (exposure < sd->ctrls[EXPOSURE].max) - exposure++; - else if (gain < sd->ctrls[GAIN].max) - gain++; - else - break; - } - } - - if (gain != orig_gain) { - sd->ctrls[GAIN].val = gain; - setgain(gspca_dev); - retval = 1; - } - if (exposure != orig_exposure) { - sd->ctrls[EXPOSURE].val = exposure; - setexposure(gspca_dev); - retval = 1; - } - - if (retval) - PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", - gain, exposure); - return retval; -} - -/* Autogain + exposure algorithm for cameras with a coarse exposure control - (usually this means we can only control the clockdiv to change exposure) - As changing the clockdiv so that the fps drops from 30 to 15 fps for - example, will lead to a huge exposure change (it effectively doubles), - this algorithm normally tries to only adjust the gain (between 40 and - 80 %) and if that does not help, only then changes exposure. This leads - to a much more stable image then using the knee algorithm which at - certain points of the knee graph will only try to adjust exposure, - which leads to oscilating as one exposure step is huge. - - Note this assumes that the sd struct for the cam in question has - exp_too_high_cnt and exp_too_high_cnt int members for use by this function. - - Returns 0 if no changes were made, 1 if the gain and or exposure settings - where changed. */ -static inline int coarse_grained_expo_autogain( - struct gspca_dev *gspca_dev, - int avg_lum, - int desired_avg_lum, - int deadzone) -{ - struct sd *sd = (struct sd *) gspca_dev; - int steps, gain, orig_gain, exposure, orig_exposure; - int gain_low, gain_high; - int retval = 0; - - orig_gain = gain = sd->ctrls[GAIN].val; - orig_exposure = exposure = sd->ctrls[EXPOSURE].val; - - gain_low = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 2; - gain_low += sd->ctrls[GAIN].min; - gain_high = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 4; - gain_high += sd->ctrls[GAIN].min; - - /* If we are of a multiple of deadzone, do multiple steps to reach the - desired lumination fast (with the risc of a slight overshoot) */ - steps = (desired_avg_lum - avg_lum) / deadzone; - - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", - avg_lum, desired_avg_lum, steps); - - if ((gain + steps) > gain_high && - exposure < sd->ctrls[EXPOSURE].max) { - gain = gain_high; - sd->exp_too_low_cnt++; - sd->exp_too_high_cnt = 0; - } else if ((gain + steps) < gain_low && - exposure > sd->ctrls[EXPOSURE].min) { - gain = gain_low; - sd->exp_too_high_cnt++; - sd->exp_too_low_cnt = 0; - } else { - gain += steps; - if (gain > sd->ctrls[GAIN].max) - gain = sd->ctrls[GAIN].max; - else if (gain < sd->ctrls[GAIN].min) - gain = sd->ctrls[GAIN].min; - sd->exp_too_high_cnt = 0; - sd->exp_too_low_cnt = 0; - } - - if (sd->exp_too_high_cnt > 3) { - exposure--; - sd->exp_too_high_cnt = 0; - } else if (sd->exp_too_low_cnt > 3) { - exposure++; - sd->exp_too_low_cnt = 0; - } - - if (gain != orig_gain) { - sd->ctrls[GAIN].val = gain; - setgain(gspca_dev); - retval = 1; - } - if (exposure != orig_exposure) { - sd->ctrls[EXPOSURE].val = exposure; - setexposure(gspca_dev); - retval = 1; - } - - if (retval) - PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", - gain, exposure); - return retval; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/benq.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/benq.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/benq.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/benq.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,315 +0,0 @@ -/* - * Benq DC E300 subdriver - * - * Copyright (C) 2009 Jean-Francois Moine (http://moinejf.free.fr) - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "benq" - -#include "gspca.h" - -MODULE_AUTHOR("Jean-Francois Moine "); -MODULE_DESCRIPTION("Benq DC E300 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ -}; - -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[] = { -}; - -static const struct v4l2_pix_format vga_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG}, -}; - -static void sd_isoc_irq(struct urb *urb); - -/* -- write a register -- */ -static void reg_w(struct gspca_dev *gspca_dev, - u16 value, u16 index) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x02, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - NULL, - 0, - 500); - if (ret < 0) { - err("reg_w err %d", ret); - gspca_dev->usb_err = ret; - } -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - gspca_dev->cam.cam_mode = vga_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); - gspca_dev->cam.no_urb_create = 1; - gspca_dev->cam.reverse_alts = 1; - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - return 0; -} - -static int sd_isoc_init(struct gspca_dev *gspca_dev) -{ - int ret; - - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, - gspca_dev->nbalt - 1); - if (ret < 0) { - err("usb_set_interface failed"); - return ret; - } -/* reg_w(gspca_dev, 0x0003, 0x0002); */ - return 0; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct urb *urb; - int i, n; - - /* create 4 URBs - 2 on endpoint 0x83 and 2 on 0x082 */ -#if MAX_NURBS < 4 -#error "Not enough URBs in the gspca table" -#endif -#define SD_PKT_SZ 64 -#define SD_NPKT 32 - for (n = 0; n < 4; n++) { - urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); - if (!urb) { - err("usb_alloc_urb failed"); - return -ENOMEM; - } - gspca_dev->urb[n] = urb; - urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, - SD_PKT_SZ * SD_NPKT, - GFP_KERNEL, - &urb->transfer_dma); - - if (urb->transfer_buffer == NULL) { - err("usb_alloc_coherent failed"); - return -ENOMEM; - } - urb->dev = gspca_dev->dev; - urb->context = gspca_dev; - urb->transfer_buffer_length = SD_PKT_SZ * SD_NPKT; - urb->pipe = usb_rcvisocpipe(gspca_dev->dev, - n & 1 ? 0x82 : 0x83); - urb->transfer_flags = URB_ISO_ASAP - | URB_NO_TRANSFER_DMA_MAP; - urb->interval = 1; - urb->complete = sd_isoc_irq; - urb->number_of_packets = SD_NPKT; - for (i = 0; i < SD_NPKT; i++) { - urb->iso_frame_desc[i].length = SD_PKT_SZ; - urb->iso_frame_desc[i].offset = SD_PKT_SZ * i; - } - } - - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev, 0x003c, 0x0003); - reg_w(gspca_dev, 0x003c, 0x0004); - reg_w(gspca_dev, 0x003c, 0x0005); - reg_w(gspca_dev, 0x003c, 0x0006); - reg_w(gspca_dev, 0x003c, 0x0007); - usb_set_interface(gspca_dev->dev, gspca_dev->iface, - gspca_dev->nbalt - 1); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - /* unused */ -} - -/* reception of an URB */ -static void sd_isoc_irq(struct urb *urb) -{ - struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; - struct urb *urb0; - u8 *data; - int i, st; - - PDEBUG(D_PACK, "sd isoc irq"); - if (!gspca_dev->streaming) - return; - if (urb->status != 0) { - if (urb->status == -ESHUTDOWN) - return; /* disconnection */ -#ifdef CONFIG_PM - if (gspca_dev->frozen) - return; -#endif - err("urb status: %d", urb->status); - return; - } - - /* if this is a control URN (ep 0x83), wait */ - if (urb == gspca_dev->urb[0] || urb == gspca_dev->urb[2]) - return; - - /* scan both received URBs */ - if (urb == gspca_dev->urb[1]) - urb0 = gspca_dev->urb[0]; - else - urb0 = gspca_dev->urb[2]; - for (i = 0; i < urb->number_of_packets; i++) { - - /* check the packet status and length */ - if (urb0->iso_frame_desc[i].actual_length != SD_PKT_SZ - || urb->iso_frame_desc[i].actual_length != SD_PKT_SZ) { - PDEBUG(D_ERR, "ISOC bad lengths %d / %d", - urb0->iso_frame_desc[i].actual_length, - urb->iso_frame_desc[i].actual_length); - gspca_dev->last_packet_type = DISCARD_PACKET; - continue; - } - st = urb0->iso_frame_desc[i].status; - if (st == 0) - st = urb->iso_frame_desc[i].status; - if (st) { - err("ISOC data error: [%d] status=%d", - i, st); - gspca_dev->last_packet_type = DISCARD_PACKET; - continue; - } - - /* - * The images are received in URBs of different endpoints - * (0x83 and 0x82). - * Image pieces in URBs of ep 0x83 are continuated in URBs of - * ep 0x82 of the same index. - * The packets in the URBs of endpoint 0x83 start with: - * - 80 ba/bb 00 00 = start of image followed by 'ff d8' - * - 04 ba/bb oo oo = image piece - * where 'oo oo' is the image offset - (not cheked) - * - (other -> bad frame) - * The images are JPEG encoded with full header and - * normal ff escape. - * The end of image ('ff d9') may occur in any URB. - * (not cheked) - */ - data = (u8 *) urb0->transfer_buffer - + urb0->iso_frame_desc[i].offset; - if (data[0] == 0x80 && (data[1] & 0xfe) == 0xba) { - - /* new image */ - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - gspca_frame_add(gspca_dev, FIRST_PACKET, - data + 4, SD_PKT_SZ - 4); - } else if (data[0] == 0x04 && (data[1] & 0xfe) == 0xba) { - gspca_frame_add(gspca_dev, INTER_PACKET, - data + 4, SD_PKT_SZ - 4); - } else { - gspca_dev->last_packet_type = DISCARD_PACKET; - continue; - } - data = (u8 *) urb->transfer_buffer - + urb->iso_frame_desc[i].offset; - gspca_frame_add(gspca_dev, INTER_PACKET, - data, SD_PKT_SZ); - } - - /* resubmit the URBs */ - st = usb_submit_urb(urb0, GFP_ATOMIC); - if (st < 0) - err("usb_submit_urb(0) ret %d", st); - st = usb_submit_urb(urb, GFP_ATOMIC); - if (st < 0) - err("usb_submit_urb() ret %d", st); -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .isoc_init = sd_isoc_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x04a5, 0x3035)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/coarse_expo_autogain.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/coarse_expo_autogain.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/coarse_expo_autogain.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/coarse_expo_autogain.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -/* - * Auto gain algorithm for camera's with a coarse exposure control - * - * Copyright (C) 2010 Hans de Goede - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -/* Autogain + exposure algorithm for cameras with a coarse exposure control - (usually this means we can only control the clockdiv to change exposure) - As changing the clockdiv so that the fps drops from 30 to 15 fps for - example, will lead to a huge exposure change (it effectively doubles), - this algorithm normally tries to only adjust the gain (between 40 and - 80 %) and if that does not help, only then changes exposure. This leads - to a much more stable image then using the knee algorithm which at - certain points of the knee graph will only try to adjust exposure, - which leads to oscilating as one exposure step is huge. - - Note this assumes that the sd struct for the cam in question has - exp_too_high_cnt and exp_too_high_cnt int members for use by this function. - - Returns 0 if no changes were made, 1 if the gain and or exposure settings - where changed. */ -static int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev, - int avg_lum, int desired_avg_lum, int deadzone) -{ - int i, steps, gain, orig_gain, exposure, orig_exposure; - int gain_low, gain_high; - const struct ctrl *gain_ctrl = NULL; - const struct ctrl *exposure_ctrl = NULL; - struct sd *sd = (struct sd *) gspca_dev; - int retval = 0; - - for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { - if (gspca_dev->ctrl_dis & (1 << i)) - continue; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN) - gain_ctrl = &gspca_dev->sd_desc->ctrls[i]; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE) - exposure_ctrl = &gspca_dev->sd_desc->ctrls[i]; - } - if (!gain_ctrl || !exposure_ctrl) { - PDEBUG(D_ERR, "Error: gspca_coarse_grained_expo_autogain " - "called on cam without gain or exposure"); - return 0; - } - - if (gain_ctrl->get(gspca_dev, &gain) || - exposure_ctrl->get(gspca_dev, &exposure)) - return 0; - - orig_gain = gain; - orig_exposure = exposure; - gain_low = - (gain_ctrl->qctrl.maximum - gain_ctrl->qctrl.minimum) / 5 * 2; - gain_low += gain_ctrl->qctrl.minimum; - gain_high = - (gain_ctrl->qctrl.maximum - gain_ctrl->qctrl.minimum) / 5 * 4; - gain_high += gain_ctrl->qctrl.minimum; - - /* If we are of a multiple of deadzone, do multiple steps to reach the - desired lumination fast (with the risc of a slight overshoot) */ - steps = (desired_avg_lum - avg_lum) / deadzone; - - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", - avg_lum, desired_avg_lum, steps); - - if ((gain + steps) > gain_high && - sd->exposure < exposure_ctrl->qctrl.maximum) { - gain = gain_high; - sd->exp_too_low_cnt++; - } else if ((gain + steps) < gain_low && - sd->exposure > exposure_ctrl->qctrl.minimum) { - gain = gain_low; - sd->exp_too_high_cnt++; - } else { - gain += steps; - if (gain > gain_ctrl->qctrl.maximum) - gain = gain_ctrl->qctrl.maximum; - else if (gain < gain_ctrl->qctrl.minimum) - gain = gain_ctrl->qctrl.minimum; - sd->exp_too_high_cnt = 0; - sd->exp_too_low_cnt = 0; - } - - if (sd->exp_too_high_cnt > 3) { - exposure--; - sd->exp_too_high_cnt = 0; - } else if (sd->exp_too_low_cnt > 3) { - exposure++; - sd->exp_too_low_cnt = 0; - } - - if (gain != orig_gain) { - gain_ctrl->set(gspca_dev, gain); - retval = 1; - } - if (exposure != orig_exposure) { - exposure_ctrl->set(gspca_dev, exposure); - retval = 1; - } - - return retval; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/conex.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/conex.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/conex.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/conex.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1079 +0,0 @@ -/* - * Connexant Cx11646 library - * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "conex" - -#include "gspca.h" -#define CONEX_CAM 1 /* special JPEG header */ -#include "jpeg.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - unsigned char brightness; - unsigned char contrast; - unsigned char colors; - u8 quality; -#define QUALITY_MIN 30 -#define QUALITY_MAX 60 -#define QUALITY_DEF 40 - - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 0xd4 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0x0a, - .maximum = 0x1f, - .step = 1, -#define CONTRAST_DEF 0x0c - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 7, - .step = 1, -#define COLOR_DEF 3 - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 3}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -/* the read bytes are found in gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - __u16 index, - __u16 len) -{ - struct usb_device *dev = gspca_dev->dev; - -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); - return; - } -#endif - usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), - 0, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, - index, gspca_dev->usb_buf, len, - 500); - PDEBUG(D_USBI, "reg read [%02x] -> %02x ..", - index, gspca_dev->usb_buf[0]); -} - -/* the bytes to write are in gspca_dev->usb_buf */ -static void reg_w_val(struct gspca_dev *gspca_dev, - __u16 index, - __u8 val) -{ - struct usb_device *dev = gspca_dev->dev; - - gspca_dev->usb_buf[0] = val; - usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, - index, gspca_dev->usb_buf, 1, 500); -} - -static void reg_w(struct gspca_dev *gspca_dev, - __u16 index, - const __u8 *buffer, - __u16 len) -{ - struct usb_device *dev = gspca_dev->dev; - -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); - return; - } - PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); -#endif - memcpy(gspca_dev->usb_buf, buffer, len); - usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, - index, gspca_dev->usb_buf, len, 500); -} - -static const __u8 cx_sensor_init[][4] = { - {0x88, 0x11, 0x01, 0x01}, - {0x88, 0x12, 0x70, 0x01}, - {0x88, 0x0f, 0x00, 0x01}, - {0x88, 0x05, 0x01, 0x01}, - {} -}; - -static const __u8 cx11646_fw1[][3] = { - {0x00, 0x02, 0x00}, - {0x01, 0x43, 0x00}, - {0x02, 0xA7, 0x00}, - {0x03, 0x8B, 0x01}, - {0x04, 0xE9, 0x02}, - {0x05, 0x08, 0x04}, - {0x06, 0x08, 0x05}, - {0x07, 0x07, 0x06}, - {0x08, 0xE7, 0x06}, - {0x09, 0xC6, 0x07}, - {0x0A, 0x86, 0x08}, - {0x0B, 0x46, 0x09}, - {0x0C, 0x05, 0x0A}, - {0x0D, 0xA5, 0x0A}, - {0x0E, 0x45, 0x0B}, - {0x0F, 0xE5, 0x0B}, - {0x10, 0x85, 0x0C}, - {0x11, 0x25, 0x0D}, - {0x12, 0xC4, 0x0D}, - {0x13, 0x45, 0x0E}, - {0x14, 0xE4, 0x0E}, - {0x15, 0x64, 0x0F}, - {0x16, 0xE4, 0x0F}, - {0x17, 0x64, 0x10}, - {0x18, 0xE4, 0x10}, - {0x19, 0x64, 0x11}, - {0x1A, 0xE4, 0x11}, - {0x1B, 0x64, 0x12}, - {0x1C, 0xE3, 0x12}, - {0x1D, 0x44, 0x13}, - {0x1E, 0xC3, 0x13}, - {0x1F, 0x24, 0x14}, - {0x20, 0xA3, 0x14}, - {0x21, 0x04, 0x15}, - {0x22, 0x83, 0x15}, - {0x23, 0xE3, 0x15}, - {0x24, 0x43, 0x16}, - {0x25, 0xA4, 0x16}, - {0x26, 0x23, 0x17}, - {0x27, 0x83, 0x17}, - {0x28, 0xE3, 0x17}, - {0x29, 0x43, 0x18}, - {0x2A, 0xA3, 0x18}, - {0x2B, 0x03, 0x19}, - {0x2C, 0x63, 0x19}, - {0x2D, 0xC3, 0x19}, - {0x2E, 0x22, 0x1A}, - {0x2F, 0x63, 0x1A}, - {0x30, 0xC3, 0x1A}, - {0x31, 0x23, 0x1B}, - {0x32, 0x83, 0x1B}, - {0x33, 0xE2, 0x1B}, - {0x34, 0x23, 0x1C}, - {0x35, 0x83, 0x1C}, - {0x36, 0xE2, 0x1C}, - {0x37, 0x23, 0x1D}, - {0x38, 0x83, 0x1D}, - {0x39, 0xE2, 0x1D}, - {0x3A, 0x23, 0x1E}, - {0x3B, 0x82, 0x1E}, - {0x3C, 0xC3, 0x1E}, - {0x3D, 0x22, 0x1F}, - {0x3E, 0x63, 0x1F}, - {0x3F, 0xC1, 0x1F}, - {} -}; -static void cx11646_fw(struct gspca_dev*gspca_dev) -{ - int i = 0; - - reg_w_val(gspca_dev, 0x006a, 0x02); - while (cx11646_fw1[i][1]) { - reg_w(gspca_dev, 0x006b, cx11646_fw1[i], 3); - i++; - } - reg_w_val(gspca_dev, 0x006a, 0x00); -} - -static const __u8 cxsensor[] = { - 0x88, 0x12, 0x70, 0x01, - 0x88, 0x0d, 0x02, 0x01, - 0x88, 0x0f, 0x00, 0x01, - 0x88, 0x03, 0x71, 0x01, 0x88, 0x04, 0x00, 0x01, /* 3 */ - 0x88, 0x02, 0x10, 0x01, - 0x88, 0x00, 0xD4, 0x01, 0x88, 0x01, 0x01, 0x01, /* 5 */ - 0x88, 0x0B, 0x00, 0x01, - 0x88, 0x0A, 0x0A, 0x01, - 0x88, 0x00, 0x08, 0x01, 0x88, 0x01, 0x00, 0x01, /* 8 */ - 0x88, 0x05, 0x01, 0x01, - 0xA1, 0x18, 0x00, 0x01, - 0x00 -}; - -static const __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff }; -static const __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff }; -static const __u8 reg10[] = { 0xb1, 0xb1 }; -static const __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e }; /* 640 */ -static const __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f }; - /* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */ -static const __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 }; - /* 320{0x04,0x0c,0x05,0x0f}; //320 */ -static const __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 }; /* 176 */ -static const __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }; - -static void cx_sensor(struct gspca_dev*gspca_dev) -{ - int i = 0; - int length; - const __u8 *ptsensor = cxsensor; - - reg_w(gspca_dev, 0x0020, reg20, 8); - reg_w(gspca_dev, 0x0028, reg28, 8); - reg_w(gspca_dev, 0x0010, reg10, 8); - reg_w_val(gspca_dev, 0x0092, 0x03); - - switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - case 0: - reg_w(gspca_dev, 0x0071, reg71a, 4); - break; - case 1: - reg_w(gspca_dev, 0x0071, reg71b, 4); - break; - default: -/* case 2: */ - reg_w(gspca_dev, 0x0071, reg71c, 4); - break; - case 3: - reg_w(gspca_dev, 0x0071, reg71d, 4); - break; - } - reg_w(gspca_dev, 0x007b, reg7b, 6); - reg_w_val(gspca_dev, 0x00f8, 0x00); - reg_w(gspca_dev, 0x0010, reg10, 8); - reg_w_val(gspca_dev, 0x0098, 0x41); - for (i = 0; i < 11; i++) { - if (i == 3 || i == 5 || i == 8) - length = 8; - else - length = 4; - reg_w(gspca_dev, 0x00e5, ptsensor, length); - if (length == 4) - reg_r(gspca_dev, 0x00e8, 1); - else - reg_r(gspca_dev, 0x00e8, length); - ptsensor += length; - } - reg_r(gspca_dev, 0x00e7, 8); -} - -static const __u8 cx_inits_176[] = { - 0x33, 0x81, 0xB0, 0x00, 0x90, 0x00, 0x0A, 0x03, /* 176x144 */ - 0x00, 0x03, 0x03, 0x03, 0x1B, 0x05, 0x30, 0x03, - 0x65, 0x15, 0x18, 0x25, 0x03, 0x25, 0x08, 0x30, - 0x3B, 0x25, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, - 0xDC, 0xFF, 0xEE, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF, - 0xF7, 0xFF, 0x88, 0xFF, 0x66, 0x02, 0x28, 0x02, - 0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static const __u8 cx_inits_320[] = { - 0x7f, 0x7f, 0x40, 0x01, 0xf0, 0x00, 0x02, 0x01, - 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x02, 0x01, - 0x65, 0x45, 0xfa, 0x4c, 0x2c, 0xdf, 0xb9, 0x81, - 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff, - 0xf5, 0xff, 0x6d, 0xff, 0xf6, 0x01, 0x43, 0x02, - 0xd3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static const __u8 cx_inits_352[] = { - 0x2e, 0x7c, 0x60, 0x01, 0x20, 0x01, 0x05, 0x03, - 0x00, 0x06, 0x03, 0x06, 0x1b, 0x10, 0x05, 0x3b, - 0x30, 0x25, 0x18, 0x25, 0x08, 0x30, 0x03, 0x25, - 0x3b, 0x30, 0x25, 0x1b, 0x10, 0x05, 0x00, 0x00, - 0xe3, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff, - 0xf5, 0xff, 0x6b, 0xff, 0xee, 0x01, 0x43, 0x02, - 0xe4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static const __u8 cx_inits_640[] = { - 0x7e, 0x7e, 0x80, 0x02, 0xe0, 0x01, 0x01, 0x01, - 0x00, 0x02, 0x01, 0x02, 0x10, 0x30, 0x01, 0x01, - 0x65, 0x45, 0xf7, 0x52, 0x2c, 0xdf, 0xb9, 0x81, - 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff, - 0xf6, 0xff, 0x7b, 0xff, 0x01, 0x02, 0x43, 0x02, - 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static void cx11646_initsize(struct gspca_dev *gspca_dev) -{ - const __u8 *cxinit; - static const __u8 reg12[] = { 0x08, 0x05, 0x07, 0x04, 0x24 }; - static const __u8 reg17[] = - { 0x0a, 0x00, 0xf2, 0x01, 0x0f, 0x00, 0x97, 0x02 }; - - switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - case 0: - cxinit = cx_inits_640; - break; - case 1: - cxinit = cx_inits_352; - break; - default: -/* case 2: */ - cxinit = cx_inits_320; - break; - case 3: - cxinit = cx_inits_176; - break; - } - reg_w_val(gspca_dev, 0x009a, 0x01); - reg_w_val(gspca_dev, 0x0010, 0x10); - reg_w(gspca_dev, 0x0012, reg12, 5); - reg_w(gspca_dev, 0x0017, reg17, 8); - reg_w_val(gspca_dev, 0x00c0, 0x00); - reg_w_val(gspca_dev, 0x00c1, 0x04); - reg_w_val(gspca_dev, 0x00c2, 0x04); - - reg_w(gspca_dev, 0x0061, cxinit, 8); - cxinit += 8; - reg_w(gspca_dev, 0x00ca, cxinit, 8); - cxinit += 8; - reg_w(gspca_dev, 0x00d2, cxinit, 8); - cxinit += 8; - reg_w(gspca_dev, 0x00da, cxinit, 6); - cxinit += 8; - reg_w(gspca_dev, 0x0041, cxinit, 8); - cxinit += 8; - reg_w(gspca_dev, 0x0049, cxinit, 8); - cxinit += 8; - reg_w(gspca_dev, 0x0051, cxinit, 2); - - reg_r(gspca_dev, 0x0010, 1); -} - -static const __u8 cx_jpeg_init[][8] = { - {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x15}, /* 1 */ - {0x0f, 0x10, 0x12, 0x10, 0x0d, 0x15, 0x12, 0x11}, - {0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35, 0x22}, - {0x20, 0x1d, 0x1d, 0x20, 0x41, 0x2e, 0x31, 0x26}, - {0x35, 0x4d, 0x43, 0x51, 0x4f, 0x4b, 0x43, 0x4a}, - {0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A, 0x73}, - {0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73, 0x7D}, - {0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95, 0xA0}, - {0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83, 0x01}, - {0x15, 0x0F, 0x10, 0x12, 0x10, 0x0D, 0x15, 0x12}, - {0x11, 0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35}, - {0x22, 0x20, 0x1D, 0x1D, 0x20, 0x41, 0x2E, 0x31}, - {0x26, 0x35, 0x4D, 0x43, 0x51, 0x4F, 0x4B, 0x43}, - {0x4A, 0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A}, - {0x73, 0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73}, - {0x7D, 0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95}, - {0xA0, 0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83}, - {0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05}, - {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}, - {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, - {0x0B, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01}, - {0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}, - {0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00}, - {0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05}, - {0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01}, - {0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21}, - {0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22}, - {0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23}, - {0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24}, - {0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17}, - {0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29}, - {0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A}, - {0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A}, - {0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A}, - {0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A}, - {0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A}, - {0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A}, - {0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99}, - {0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8}, - {0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7}, - {0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6}, - {0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5}, - {0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3}, - {0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1}, - {0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9}, - {0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04}, - {0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01}, - {0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04}, - {0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07}, - {0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14}, - {0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33}, - {0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16}, - {0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19}, - {0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36}, - {0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46}, - {0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56}, - {0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66}, - {0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76}, - {0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85}, - {0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94}, - {0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3}, - {0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2}, - {0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA}, - {0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9}, - {0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8}, - {0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7}, - {0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6}, - {0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0x20, 0x00, 0x1F}, - {0x02, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x11, 0x00, 0x11, 0x22, 0x00, 0x22}, - {0x22, 0x11, 0x22, 0x22, 0x11, 0x33, 0x33, 0x11}, - {0x44, 0x66, 0x22, 0x55, 0x66, 0xFF, 0xDD, 0x00}, - {0x04, 0x00, 0x14, 0xFF, 0xC0, 0x00, 0x11, 0x08}, - {0x00, 0xF0, 0x01, 0x40, 0x03, 0x00, 0x21, 0x00}, - {0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xDA}, - {0x00, 0x0C, 0x03, 0x00, 0x00, 0x01, 0x11, 0x02}, - {0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9, 0x00, 0x00} /* 79 */ -}; - - -static const __u8 cxjpeg_640[][8] = { - {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x10}, /* 1 */ - {0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d}, - {0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a}, - {0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d}, - {0x28, 0x3a, 0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38}, - {0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57}, - {0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F}, - {0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79}, - {0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63, 0x01}, - {0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E}, - {0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28}, - {0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25}, - {0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33}, - {0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44}, - {0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57}, - {0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71}, - {0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63}, - {0xFF, 0x20, 0x00, 0x1F, 0x00, 0x83, 0x00, 0x00}, - {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, - {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, - {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, - {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x28, 0xFF}, - {0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80}, - {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, - {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, - {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, - {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */ -}; -static const __u8 cxjpeg_352[][8] = { - {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d}, - {0x09, 0x09, 0x0b, 0x09, 0x08, 0x0D, 0x0b, 0x0a}, - {0x0b, 0x0e, 0x0d, 0x0d, 0x0f, 0x13, 0x1f, 0x14}, - {0x13, 0x11, 0x11, 0x13, 0x26, 0x1b, 0x1d, 0x17}, - {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C}, - {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44}, - {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A}, - {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F}, - {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01}, - {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B}, - {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F}, - {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D}, - {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28}, - {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35}, - {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44}, - {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58}, - {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D}, - {0xFF, 0x20, 0x00, 0x1F, 0x01, 0x83, 0x00, 0x00}, - {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, - {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, - {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, - {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x16, 0xFF}, - {0xC0, 0x00, 0x11, 0x08, 0x01, 0x20, 0x01, 0x60}, - {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, - {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, - {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, - {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -}; -static const __u8 cxjpeg_320[][8] = { - {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x05}, - {0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04}, - {0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08}, - {0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09}, - {0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0f, 0x11}, - {0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 0x1A}, - {0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D}, - {0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 0x24}, - {0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0x01}, - {0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04}, - {0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C}, - {0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B}, - {0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F}, - {0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14}, - {0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A}, - {0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22}, - {0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E}, - {0xFF, 0x20, 0x00, 0x1F, 0x02, 0x0C, 0x00, 0x00}, - {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, - {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, - {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, - {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x14, 0xFF}, - {0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 0x40}, - {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, - {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, - {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, - {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */ -}; -static const __u8 cxjpeg_176[][8] = { - {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d}, - {0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B, 0x0A}, - {0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F, 0x14}, - {0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D, 0x17}, - {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C}, - {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44}, - {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A}, - {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F}, - {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01}, - {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B}, - {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F}, - {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D}, - {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28}, - {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35}, - {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44}, - {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58}, - {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D}, - {0xFF, 0x20, 0x00, 0x1F, 0x03, 0xA1, 0x00, 0x00}, - {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, - {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, - {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, - {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x0B, 0xFF}, - {0xC0, 0x00, 0x11, 0x08, 0x00, 0x90, 0x00, 0xB0}, - {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, - {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, - {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, - {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -}; -/* 640 take with the zcx30x part */ -static const __u8 cxjpeg_qtable[][8] = { - {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x08}, - {0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 0x07}, - {0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0a}, - {0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, 0x0f}, - {0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c}, - {0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, 0x2c}, - {0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30}, - {0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, 0x3d}, - {0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0x01}, - {0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0a}, - {0x0a, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32}, - {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, - {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, - {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, - {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, - {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, - {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, - {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 18 */ -}; - - -static void cx11646_jpegInit(struct gspca_dev*gspca_dev) -{ - int i; - int length; - - reg_w_val(gspca_dev, 0x00c0, 0x01); - reg_w_val(gspca_dev, 0x00c3, 0x00); - reg_w_val(gspca_dev, 0x00c0, 0x00); - reg_r(gspca_dev, 0x0001, 1); - length = 8; - for (i = 0; i < 79; i++) { - if (i == 78) - length = 6; - reg_w(gspca_dev, 0x0008, cx_jpeg_init[i], length); - } - reg_r(gspca_dev, 0x0002, 1); - reg_w_val(gspca_dev, 0x0055, 0x14); -} - -static const __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 }; -static const __u8 regE5_8[] = - { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 }; -static const __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 }; -static const __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 }; -static const __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 }; -static const __u8 reg51[] = { 0x77, 0x03 }; -#define reg70 0x03 - -static void cx11646_jpeg(struct gspca_dev*gspca_dev) -{ - int i; - int length; - __u8 Reg55; - int retry; - - reg_w_val(gspca_dev, 0x00c0, 0x01); - reg_w_val(gspca_dev, 0x00c3, 0x00); - reg_w_val(gspca_dev, 0x00c0, 0x00); - reg_r(gspca_dev, 0x0001, 1); - length = 8; - switch (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv) { - case 0: - for (i = 0; i < 27; i++) { - if (i == 26) - length = 2; - reg_w(gspca_dev, 0x0008, cxjpeg_640[i], length); - } - Reg55 = 0x28; - break; - case 1: - for (i = 0; i < 27; i++) { - if (i == 26) - length = 2; - reg_w(gspca_dev, 0x0008, cxjpeg_352[i], length); - } - Reg55 = 0x16; - break; - default: -/* case 2: */ - for (i = 0; i < 27; i++) { - if (i == 26) - length = 2; - reg_w(gspca_dev, 0x0008, cxjpeg_320[i], length); - } - Reg55 = 0x14; - break; - case 3: - for (i = 0; i < 27; i++) { - if (i == 26) - length = 2; - reg_w(gspca_dev, 0x0008, cxjpeg_176[i], length); - } - Reg55 = 0x0B; - break; - } - - reg_r(gspca_dev, 0x0002, 1); - reg_w_val(gspca_dev, 0x0055, Reg55); - reg_r(gspca_dev, 0x0002, 1); - reg_w(gspca_dev, 0x0010, reg10, 2); - reg_w_val(gspca_dev, 0x0054, 0x02); - reg_w_val(gspca_dev, 0x0054, 0x01); - reg_w_val(gspca_dev, 0x0000, 0x94); - reg_w_val(gspca_dev, 0x0053, 0xc0); - reg_w_val(gspca_dev, 0x00fc, 0xe1); - reg_w_val(gspca_dev, 0x0000, 0x00); - /* wait for completion */ - retry = 50; - do { - reg_r(gspca_dev, 0x0002, 1); - /* 0x07 until 0x00 */ - if (gspca_dev->usb_buf[0] == 0x00) - break; - reg_w_val(gspca_dev, 0x0053, 0x00); - } while (--retry); - if (retry == 0) - PDEBUG(D_ERR, "Damned Errors sending jpeg Table"); - /* send the qtable now */ - reg_r(gspca_dev, 0x0001, 1); /* -> 0x18 */ - length = 8; - for (i = 0; i < 18; i++) { - if (i == 17) - length = 2; - reg_w(gspca_dev, 0x0008, cxjpeg_qtable[i], length); - - } - reg_r(gspca_dev, 0x0002, 1); /* 0x00 */ - reg_r(gspca_dev, 0x0053, 1); /* 0x00 */ - reg_w_val(gspca_dev, 0x0054, 0x02); - reg_w_val(gspca_dev, 0x0054, 0x01); - reg_w_val(gspca_dev, 0x0000, 0x94); - reg_w_val(gspca_dev, 0x0053, 0xc0); - - reg_r(gspca_dev, 0x0038, 1); /* 0x40 */ - reg_r(gspca_dev, 0x0038, 1); /* 0x40 */ - reg_r(gspca_dev, 0x001f, 1); /* 0x38 */ - reg_w(gspca_dev, 0x0012, reg12, 5); - reg_w(gspca_dev, 0x00e5, regE5_8, 8); - reg_r(gspca_dev, 0x00e8, 8); - reg_w(gspca_dev, 0x00e5, regE5a, 4); - reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ - reg_w_val(gspca_dev, 0x009a, 0x01); - reg_w(gspca_dev, 0x00e5, regE5b, 4); - reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ - reg_w(gspca_dev, 0x00e5, regE5c, 4); - reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ - - reg_w(gspca_dev, 0x0051, reg51, 2); - reg_w(gspca_dev, 0x0010, reg10, 2); - reg_w_val(gspca_dev, 0x0070, reg70); -} - -static void cx11646_init1(struct gspca_dev *gspca_dev) -{ - int i = 0; - - reg_w_val(gspca_dev, 0x0010, 0x00); - reg_w_val(gspca_dev, 0x0053, 0x00); - reg_w_val(gspca_dev, 0x0052, 0x00); - reg_w_val(gspca_dev, 0x009b, 0x2f); - reg_w_val(gspca_dev, 0x009c, 0x10); - reg_r(gspca_dev, 0x0098, 1); - reg_w_val(gspca_dev, 0x0098, 0x40); - reg_r(gspca_dev, 0x0099, 1); - reg_w_val(gspca_dev, 0x0099, 0x07); - reg_w_val(gspca_dev, 0x0039, 0x40); - reg_w_val(gspca_dev, 0x003c, 0xff); - reg_w_val(gspca_dev, 0x003f, 0x1f); - reg_w_val(gspca_dev, 0x003d, 0x40); -/* reg_w_val(gspca_dev, 0x003d, 0x60); */ - reg_r(gspca_dev, 0x0099, 1); /* ->0x07 */ - - while (cx_sensor_init[i][0]) { - reg_w_val(gspca_dev, 0x00e5, cx_sensor_init[i][0]); - reg_r(gspca_dev, 0x00e8, 1); /* -> 0x00 */ - if (i == 1) { - reg_w_val(gspca_dev, 0x00ed, 0x01); - reg_r(gspca_dev, 0x00ed, 1); /* -> 0x01 */ - } - i++; - } - reg_w_val(gspca_dev, 0x00c3, 0x00); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->quality = QUALITY_DEF; - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - cx11646_init1(gspca_dev); - cx11646_initsize(gspca_dev); - cx11646_fw(gspca_dev); - cx_sensor(gspca_dev); - cx11646_jpegInit(gspca_dev); - return 0; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x22); /* JPEG 411 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - - cx11646_initsize(gspca_dev); - cx11646_fw(gspca_dev); - cx_sensor(gspca_dev); - cx11646_jpeg(gspca_dev); - return 0; -} - -/* called on streamoff with alt 0 and on disconnect */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - int retry = 50; - - if (!gspca_dev->present) - return; - reg_w_val(gspca_dev, 0x0000, 0x00); - reg_r(gspca_dev, 0x0002, 1); - reg_w_val(gspca_dev, 0x0053, 0x00); - - while (retry--) { -/* reg_r(gspca_dev, 0x0002, 1);*/ - reg_r(gspca_dev, 0x0053, 1); - if (gspca_dev->usb_buf[0] == 0) - break; - } - reg_w_val(gspca_dev, 0x0000, 0x00); - reg_r(gspca_dev, 0x0002, 1); - - reg_w_val(gspca_dev, 0x0010, 0x00); - reg_r(gspca_dev, 0x0033, 1); - reg_w_val(gspca_dev, 0x00fc, 0xe0); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (data[0] == 0xff && data[1] == 0xd8) { - - /* start of frame */ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - - /* put the JPEG header in the new frame */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - data += 2; - len -= 2; - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 }; - __u8 reg51c[2]; - __u8 bright; - __u8 colors; - - bright = sd->brightness; - regE5cbx[2] = bright; - reg_w(gspca_dev, 0x00e5, regE5cbx, 8); - reg_r(gspca_dev, 0x00e8, 8); - reg_w(gspca_dev, 0x00e5, regE5c, 4); - reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ - - colors = sd->colors; - reg51c[0] = 0x77; - reg51c[1] = colors; - reg_w(gspca_dev, 0x0051, reg51c, 2); - reg_w(gspca_dev, 0x0010, reg10, 2); - reg_w_val(gspca_dev, 0x0070, reg70); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 }; /* seem MSB */ -/* __u8 regE5bcx[] = { 0x88, 0x0b, 0x12, 0x01}; * LSB */ - __u8 reg51c[2]; - - regE5acx[2] = sd->contrast; - reg_w(gspca_dev, 0x00e5, regE5acx, 4); - reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ - reg51c[0] = 0x77; - reg51c[1] = sd->colors; - reg_w(gspca_dev, 0x0051, reg51c, 2); - reg_w(gspca_dev, 0x0010, reg10, 2); - reg_w_val(gspca_dev, 0x0070, reg70); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) { - setbrightness(gspca_dev); - setcontrast(gspca_dev); - } - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return 0; -} - -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0572, 0x0041)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/cpia1.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/cpia1.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/cpia1.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/cpia1.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2149 +0,0 @@ -/* - * cpia CPiA (1) gspca driver - * - * Copyright (C) 2010-2011 Hans de Goede - * - * This module is adapted from the in kernel v4l1 cpia driver which is : - * - * (C) Copyright 1999-2000 Peter Pregler - * (C) Copyright 1999-2000 Scott J. Bertin - * (C) Copyright 1999-2000 Johannes Erdfelt - * (C) Copyright 2000 STMicroelectronics - * - * 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, or - * (at your option) any later version. - * - * 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 - * - */ - -#define MODULE_NAME "cpia1" - -#include -#include "gspca.h" - -MODULE_AUTHOR("Hans de Goede "); -MODULE_DESCRIPTION("Vision CPiA"); -MODULE_LICENSE("GPL"); - -/* constant value's */ -#define MAGIC_0 0x19 -#define MAGIC_1 0x68 -#define DATA_IN 0xc0 -#define DATA_OUT 0x40 -#define VIDEOSIZE_QCIF 0 /* 176x144 */ -#define VIDEOSIZE_CIF 1 /* 352x288 */ -#define SUBSAMPLE_420 0 -#define SUBSAMPLE_422 1 -#define YUVORDER_YUYV 0 -#define YUVORDER_UYVY 1 -#define NOT_COMPRESSED 0 -#define COMPRESSED 1 -#define NO_DECIMATION 0 -#define DECIMATION_ENAB 1 -#define EOI 0xff /* End Of Image */ -#define EOL 0xfd /* End Of Line */ -#define FRAME_HEADER_SIZE 64 - -/* Image grab modes */ -#define CPIA_GRAB_SINGLE 0 -#define CPIA_GRAB_CONTINEOUS 1 - -/* Compression parameters */ -#define CPIA_COMPRESSION_NONE 0 -#define CPIA_COMPRESSION_AUTO 1 -#define CPIA_COMPRESSION_MANUAL 2 -#define CPIA_COMPRESSION_TARGET_QUALITY 0 -#define CPIA_COMPRESSION_TARGET_FRAMERATE 1 - -/* Return offsets for GetCameraState */ -#define SYSTEMSTATE 0 -#define GRABSTATE 1 -#define STREAMSTATE 2 -#define FATALERROR 3 -#define CMDERROR 4 -#define DEBUGFLAGS 5 -#define VPSTATUS 6 -#define ERRORCODE 7 - -/* SystemState */ -#define UNINITIALISED_STATE 0 -#define PASS_THROUGH_STATE 1 -#define LO_POWER_STATE 2 -#define HI_POWER_STATE 3 -#define WARM_BOOT_STATE 4 - -/* GrabState */ -#define GRAB_IDLE 0 -#define GRAB_ACTIVE 1 -#define GRAB_DONE 2 - -/* StreamState */ -#define STREAM_NOT_READY 0 -#define STREAM_READY 1 -#define STREAM_OPEN 2 -#define STREAM_PAUSED 3 -#define STREAM_FINISHED 4 - -/* Fatal Error, CmdError, and DebugFlags */ -#define CPIA_FLAG 1 -#define SYSTEM_FLAG 2 -#define INT_CTRL_FLAG 4 -#define PROCESS_FLAG 8 -#define COM_FLAG 16 -#define VP_CTRL_FLAG 32 -#define CAPTURE_FLAG 64 -#define DEBUG_FLAG 128 - -/* VPStatus */ -#define VP_STATE_OK 0x00 - -#define VP_STATE_FAILED_VIDEOINIT 0x01 -#define VP_STATE_FAILED_AECACBINIT 0x02 -#define VP_STATE_AEC_MAX 0x04 -#define VP_STATE_ACB_BMAX 0x08 - -#define VP_STATE_ACB_RMIN 0x10 -#define VP_STATE_ACB_GMIN 0x20 -#define VP_STATE_ACB_RMAX 0x40 -#define VP_STATE_ACB_GMAX 0x80 - -/* default (minimum) compensation values */ -#define COMP_RED 220 -#define COMP_GREEN1 214 -#define COMP_GREEN2 COMP_GREEN1 -#define COMP_BLUE 230 - -/* exposure status */ -#define EXPOSURE_VERY_LIGHT 0 -#define EXPOSURE_LIGHT 1 -#define EXPOSURE_NORMAL 2 -#define EXPOSURE_DARK 3 -#define EXPOSURE_VERY_DARK 4 - -#define CPIA_MODULE_CPIA (0 << 5) -#define CPIA_MODULE_SYSTEM (1 << 5) -#define CPIA_MODULE_VP_CTRL (5 << 5) -#define CPIA_MODULE_CAPTURE (6 << 5) -#define CPIA_MODULE_DEBUG (7 << 5) - -#define INPUT (DATA_IN << 8) -#define OUTPUT (DATA_OUT << 8) - -#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1) -#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2) -#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3) -#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4) -#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5) -#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7) -#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8) -#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10) - -#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1) -#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2) -#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3) -#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4) -#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5) -#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6) -#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7) -#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8) -#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9) -#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10) -#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11) -#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12) -#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13) - -#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1) -#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2) -#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3) -#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4) -#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6) -#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7) -#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8) -#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9) -#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10) -#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11) -#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16) -#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17) -#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18) -#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19) -#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25) -#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30) -#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31) - -#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1) -#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2) -#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3) -#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4) -#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5) -#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6) -#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7) -#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8) -#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9) -#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10) -#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11) -#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12) -#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13) -#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14) -#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15) - -#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1) -#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4) -#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5) -#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6) -#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8) -#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9) -#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10) -#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11) - -#define ROUND_UP_EXP_FOR_FLICKER 15 - -/* Constants for automatic frame rate adjustment */ -#define MAX_EXP 302 -#define MAX_EXP_102 255 -#define LOW_EXP 140 -#define VERY_LOW_EXP 70 -#define TC 94 -#define EXP_ACC_DARK 50 -#define EXP_ACC_LIGHT 90 -#define HIGH_COMP_102 160 -#define MAX_COMP 239 -#define DARK_TIME 3 -#define LIGHT_TIME 3 - -#define FIRMWARE_VERSION(x, y) (sd->params.version.firmwareVersion == (x) && \ - sd->params.version.firmwareRevision == (y)) - -/* Developer's Guide Table 5 p 3-34 - * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ -static u8 flicker_jumps[2][2][4] = -{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } }, - { { 64, 32, 16, 8 }, { 76, 38, 19, 9} } -}; - -struct cam_params { - struct { - u8 firmwareVersion; - u8 firmwareRevision; - u8 vcVersion; - u8 vcRevision; - } version; - struct { - u16 vendor; - u16 product; - u16 deviceRevision; - } pnpID; - struct { - u8 vpVersion; - u8 vpRevision; - u16 cameraHeadID; - } vpVersion; - struct { - u8 systemState; - u8 grabState; - u8 streamState; - u8 fatalError; - u8 cmdError; - u8 debugFlags; - u8 vpStatus; - u8 errorCode; - } status; - struct { - u8 brightness; - u8 contrast; - u8 saturation; - } colourParams; - struct { - u8 gainMode; - u8 expMode; - u8 compMode; - u8 centreWeight; - u8 gain; - u8 fineExp; - u8 coarseExpLo; - u8 coarseExpHi; - u8 redComp; - u8 green1Comp; - u8 green2Comp; - u8 blueComp; - } exposure; - struct { - u8 balanceMode; - u8 redGain; - u8 greenGain; - u8 blueGain; - } colourBalance; - struct { - u8 divisor; - u8 baserate; - } sensorFps; - struct { - u8 gain1; - u8 gain2; - u8 gain4; - u8 gain8; - } apcor; - struct { - u8 disabled; - u8 flickerMode; - u8 coarseJump; - u8 allowableOverExposure; - } flickerControl; - struct { - u8 gain1; - u8 gain2; - u8 gain4; - u8 gain8; - } vlOffset; - struct { - u8 mode; - u8 decimation; - } compression; - struct { - u8 frTargeting; - u8 targetFR; - u8 targetQ; - } compressionTarget; - struct { - u8 yThreshold; - u8 uvThreshold; - } yuvThreshold; - struct { - u8 hysteresis; - u8 threshMax; - u8 smallStep; - u8 largeStep; - u8 decimationHysteresis; - u8 frDiffStepThresh; - u8 qDiffStepThresh; - u8 decimationThreshMod; - } compressionParams; - struct { - u8 videoSize; /* CIF/QCIF */ - u8 subSample; - u8 yuvOrder; - } format; - struct { /* Intel QX3 specific data */ - u8 qx3_detected; /* a QX3 is present */ - u8 toplight; /* top light lit , R/W */ - u8 bottomlight; /* bottom light lit, R/W */ - u8 button; /* snapshot button pressed (R/O) */ - u8 cradled; /* microscope is in cradle (R/O) */ - } qx3; - struct { - u8 colStart; /* skip first 8*colStart pixels */ - u8 colEnd; /* finish at 8*colEnd pixels */ - u8 rowStart; /* skip first 4*rowStart lines */ - u8 rowEnd; /* finish at 4*rowEnd lines */ - } roi; - u8 ecpTiming; - u8 streamStartLine; -}; - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - struct cam_params params; /* camera settings */ - - atomic_t cam_exposure; - atomic_t fps; - int exposure_count; - u8 exposure_status; - u8 mainsFreq; /* 0 = 50hz, 1 = 60hz */ - u8 first_frame; - u8 freq; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { -#define BRIGHTNESS_IDX 0 - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 100, - .step = 1, -#define BRIGHTNESS_DEF 50 - .default_value = BRIGHTNESS_DEF, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define CONTRAST_IDX 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 96, - .step = 8, -#define CONTRAST_DEF 48 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SATURATION_IDX 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 100, - .step = 1, -#define SATURATION_DEF 50 - .default_value = SATURATION_DEF, - }, - .set = sd_setsaturation, - .get = sd_getsaturation, - }, -#define POWER_LINE_FREQUENCY_IDX 3 - { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, -#define FREQ_DEF 1 - .default_value = FREQ_DEF, - }, - .set = sd_setfreq, - .get = sd_getfreq, - }, -#define ILLUMINATORS_1_IDX 4 - { - { - .id = V4L2_CID_ILLUMINATORS_1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Illuminator 1", - .minimum = 0, - .maximum = 1, - .step = 1, -#define ILLUMINATORS_1_DEF 0 - .default_value = ILLUMINATORS_1_DEF, - }, - .set = sd_setilluminator1, - .get = sd_getilluminator1, - }, -#define ILLUMINATORS_2_IDX 5 - { - { - .id = V4L2_CID_ILLUMINATORS_2, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Illuminator 2", - .minimum = 0, - .maximum = 1, - .step = 1, -#define ILLUMINATORS_2_DEF 0 - .default_value = ILLUMINATORS_2_DEF, - }, - .set = sd_setilluminator2, - .get = sd_getilluminator2, - }, -#define COMP_TARGET_IDX 6 - { - { -#define V4L2_CID_COMP_TARGET V4L2_CID_PRIVATE_BASE - .id = V4L2_CID_COMP_TARGET, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Compression Target", - .minimum = 0, - .maximum = 1, - .step = 1, -#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY - .default_value = COMP_TARGET_DEF, - }, - .set = sd_setcomptarget, - .get = sd_getcomptarget, - }, -}; - -static const struct v4l2_pix_format mode[] = { - {160, 120, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, - /* The sizeimage is trial and error, as with low framerates - the camera will pad out usb frames, making the image - data larger then strictly necessary */ - .bytesperline = 160, - .sizeimage = 65536, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 3}, - {176, 144, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, - .bytesperline = 172, - .sizeimage = 65536, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {320, 240, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 262144, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {352, 288, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 262144, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -/********************************************************************** - * - * General functions - * - **********************************************************************/ - -static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command) -{ - u8 requesttype; - unsigned int pipe; - int ret, databytes = command[6] | (command[7] << 8); - /* Sometimes we see spurious EPIPE errors */ - int retries = 3; - - if (command[0] == DATA_IN) { - pipe = usb_rcvctrlpipe(gspca_dev->dev, 0); - requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - } else if (command[0] == DATA_OUT) { - pipe = usb_sndctrlpipe(gspca_dev->dev, 0); - requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE; - } else { - PDEBUG(D_ERR, "Unexpected first byte of command: %x", - command[0]); - return -EINVAL; - } - -retry: - ret = usb_control_msg(gspca_dev->dev, pipe, - command[1], - requesttype, - command[2] | (command[3] << 8), - command[4] | (command[5] << 8), - gspca_dev->usb_buf, databytes, 1000); - - if (ret < 0) - err("usb_control_msg %02x, error %d", command[1], - ret); - - if (ret == -EPIPE && retries > 0) { - retries--; - goto retry; - } - - return (ret < 0) ? ret : 0; -} - -/* send an arbitrary command to the camera */ -static int do_command(struct gspca_dev *gspca_dev, u16 command, - u8 a, u8 b, u8 c, u8 d) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret, datasize; - u8 cmd[8]; - - switch (command) { - case CPIA_COMMAND_GetCPIAVersion: - case CPIA_COMMAND_GetPnPID: - case CPIA_COMMAND_GetCameraStatus: - case CPIA_COMMAND_GetVPVersion: - case CPIA_COMMAND_GetColourParams: - case CPIA_COMMAND_GetColourBalance: - case CPIA_COMMAND_GetExposure: - datasize = 8; - break; - case CPIA_COMMAND_ReadMCPorts: - case CPIA_COMMAND_ReadVCRegs: - datasize = 4; - break; - default: - datasize = 0; - break; - } - - cmd[0] = command >> 8; - cmd[1] = command & 0xff; - cmd[2] = a; - cmd[3] = b; - cmd[4] = c; - cmd[5] = d; - cmd[6] = datasize; - cmd[7] = 0; - - ret = cpia_usb_transferCmd(gspca_dev, cmd); - if (ret) - return ret; - - switch (command) { - case CPIA_COMMAND_GetCPIAVersion: - sd->params.version.firmwareVersion = gspca_dev->usb_buf[0]; - sd->params.version.firmwareRevision = gspca_dev->usb_buf[1]; - sd->params.version.vcVersion = gspca_dev->usb_buf[2]; - sd->params.version.vcRevision = gspca_dev->usb_buf[3]; - break; - case CPIA_COMMAND_GetPnPID: - sd->params.pnpID.vendor = - gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8); - sd->params.pnpID.product = - gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8); - sd->params.pnpID.deviceRevision = - gspca_dev->usb_buf[4] | (gspca_dev->usb_buf[5] << 8); - break; - case CPIA_COMMAND_GetCameraStatus: - sd->params.status.systemState = gspca_dev->usb_buf[0]; - sd->params.status.grabState = gspca_dev->usb_buf[1]; - sd->params.status.streamState = gspca_dev->usb_buf[2]; - sd->params.status.fatalError = gspca_dev->usb_buf[3]; - sd->params.status.cmdError = gspca_dev->usb_buf[4]; - sd->params.status.debugFlags = gspca_dev->usb_buf[5]; - sd->params.status.vpStatus = gspca_dev->usb_buf[6]; - sd->params.status.errorCode = gspca_dev->usb_buf[7]; - break; - case CPIA_COMMAND_GetVPVersion: - sd->params.vpVersion.vpVersion = gspca_dev->usb_buf[0]; - sd->params.vpVersion.vpRevision = gspca_dev->usb_buf[1]; - sd->params.vpVersion.cameraHeadID = - gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8); - break; - case CPIA_COMMAND_GetColourParams: - sd->params.colourParams.brightness = gspca_dev->usb_buf[0]; - sd->params.colourParams.contrast = gspca_dev->usb_buf[1]; - sd->params.colourParams.saturation = gspca_dev->usb_buf[2]; - break; - case CPIA_COMMAND_GetColourBalance: - sd->params.colourBalance.redGain = gspca_dev->usb_buf[0]; - sd->params.colourBalance.greenGain = gspca_dev->usb_buf[1]; - sd->params.colourBalance.blueGain = gspca_dev->usb_buf[2]; - break; - case CPIA_COMMAND_GetExposure: - sd->params.exposure.gain = gspca_dev->usb_buf[0]; - sd->params.exposure.fineExp = gspca_dev->usb_buf[1]; - sd->params.exposure.coarseExpLo = gspca_dev->usb_buf[2]; - sd->params.exposure.coarseExpHi = gspca_dev->usb_buf[3]; - sd->params.exposure.redComp = gspca_dev->usb_buf[4]; - sd->params.exposure.green1Comp = gspca_dev->usb_buf[5]; - sd->params.exposure.green2Comp = gspca_dev->usb_buf[6]; - sd->params.exposure.blueComp = gspca_dev->usb_buf[7]; - break; - - case CPIA_COMMAND_ReadMCPorts: - /* test button press */ - a = ((gspca_dev->usb_buf[1] & 0x02) == 0); - if (a != sd->params.qx3.button) { -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - input_report_key(gspca_dev->input_dev, KEY_CAMERA, a); - input_sync(gspca_dev->input_dev); -#endif - sd->params.qx3.button = a; - } - if (sd->params.qx3.button) { - /* button pressed - unlock the latch */ - do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, - 3, 0xdf, 0xdf, 0); - do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, - 3, 0xff, 0xff, 0); - } - - /* test whether microscope is cradled */ - sd->params.qx3.cradled = ((gspca_dev->usb_buf[2] & 0x40) == 0); - break; - } - - return 0; -} - -/* send a command to the camera with an additional data transaction */ -static int do_command_extended(struct gspca_dev *gspca_dev, u16 command, - u8 a, u8 b, u8 c, u8 d, - u8 e, u8 f, u8 g, u8 h, - u8 i, u8 j, u8 k, u8 l) -{ - u8 cmd[8]; - - cmd[0] = command >> 8; - cmd[1] = command & 0xff; - cmd[2] = a; - cmd[3] = b; - cmd[4] = c; - cmd[5] = d; - cmd[6] = 8; - cmd[7] = 0; - gspca_dev->usb_buf[0] = e; - gspca_dev->usb_buf[1] = f; - gspca_dev->usb_buf[2] = g; - gspca_dev->usb_buf[3] = h; - gspca_dev->usb_buf[4] = i; - gspca_dev->usb_buf[5] = j; - gspca_dev->usb_buf[6] = k; - gspca_dev->usb_buf[7] = l; - - return cpia_usb_transferCmd(gspca_dev, cmd); -} - -/* find_over_exposure - * Finds a suitable value of OverExposure for use with SetFlickerCtrl - * Some calculation is required because this value changes with the brightness - * set with SetColourParameters - * - * Parameters: Brightness - last brightness value set with SetColourParameters - * - * Returns: OverExposure value to use with SetFlickerCtrl - */ -#define FLICKER_MAX_EXPOSURE 250 -#define FLICKER_ALLOWABLE_OVER_EXPOSURE 146 -#define FLICKER_BRIGHTNESS_CONSTANT 59 -static int find_over_exposure(int brightness) -{ - int MaxAllowableOverExposure, OverExposure; - - MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness - - FLICKER_BRIGHTNESS_CONSTANT; - - if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) - OverExposure = MaxAllowableOverExposure; - else - OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE; - - return OverExposure; -} -#undef FLICKER_MAX_EXPOSURE -#undef FLICKER_ALLOWABLE_OVER_EXPOSURE -#undef FLICKER_BRIGHTNESS_CONSTANT - -/* initialise cam_data structure */ -static void reset_camera_params(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam_params *params = &sd->params; - - /* The following parameter values are the defaults from - * "Software Developer's Guide for CPiA Cameras". Any changes - * to the defaults are noted in comments. */ - params->colourParams.brightness = BRIGHTNESS_DEF; - params->colourParams.contrast = CONTRAST_DEF; - params->colourParams.saturation = SATURATION_DEF; - params->exposure.gainMode = 4; - params->exposure.expMode = 2; /* AEC */ - params->exposure.compMode = 1; - params->exposure.centreWeight = 1; - params->exposure.gain = 0; - params->exposure.fineExp = 0; - params->exposure.coarseExpLo = 185; - params->exposure.coarseExpHi = 0; - params->exposure.redComp = COMP_RED; - params->exposure.green1Comp = COMP_GREEN1; - params->exposure.green2Comp = COMP_GREEN2; - params->exposure.blueComp = COMP_BLUE; - params->colourBalance.balanceMode = 2; /* ACB */ - params->colourBalance.redGain = 32; - params->colourBalance.greenGain = 6; - params->colourBalance.blueGain = 92; - params->apcor.gain1 = 0x18; - params->apcor.gain2 = 0x16; - params->apcor.gain4 = 0x24; - params->apcor.gain8 = 0x34; - params->flickerControl.flickerMode = 0; - params->flickerControl.disabled = 1; - - params->flickerControl.coarseJump = - flicker_jumps[sd->mainsFreq] - [params->sensorFps.baserate] - [params->sensorFps.divisor]; - params->flickerControl.allowableOverExposure = - find_over_exposure(params->colourParams.brightness); - params->vlOffset.gain1 = 20; - params->vlOffset.gain2 = 24; - params->vlOffset.gain4 = 26; - params->vlOffset.gain8 = 26; - params->compressionParams.hysteresis = 3; - params->compressionParams.threshMax = 11; - params->compressionParams.smallStep = 1; - params->compressionParams.largeStep = 3; - params->compressionParams.decimationHysteresis = 2; - params->compressionParams.frDiffStepThresh = 5; - params->compressionParams.qDiffStepThresh = 3; - params->compressionParams.decimationThreshMod = 2; - /* End of default values from Software Developer's Guide */ - - /* Set Sensor FPS to 15fps. This seems better than 30fps - * for indoor lighting. */ - params->sensorFps.divisor = 1; - params->sensorFps.baserate = 1; - - params->yuvThreshold.yThreshold = 6; /* From windows driver */ - params->yuvThreshold.uvThreshold = 6; /* From windows driver */ - - params->format.subSample = SUBSAMPLE_420; - params->format.yuvOrder = YUVORDER_YUYV; - - params->compression.mode = CPIA_COMPRESSION_AUTO; - params->compression.decimation = NO_DECIMATION; - - params->compressionTarget.frTargeting = COMP_TARGET_DEF; - params->compressionTarget.targetFR = 15; /* From windows driver */ - params->compressionTarget.targetQ = 5; /* From windows driver */ - - params->qx3.qx3_detected = 0; - params->qx3.toplight = 0; - params->qx3.bottomlight = 0; - params->qx3.button = 0; - params->qx3.cradled = 0; -} - -static void printstatus(struct cam_params *params) -{ - PDEBUG(D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x", - params->status.systemState, params->status.grabState, - params->status.streamState, params->status.fatalError, - params->status.cmdError, params->status.debugFlags, - params->status.vpStatus, params->status.errorCode); -} - -static int goto_low_power(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - ret = do_command(gspca_dev, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0); - if (ret) - return ret; - - ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); - if (ret) - return ret; - - if (sd->params.status.systemState != LO_POWER_STATE) { - if (sd->params.status.systemState != WARM_BOOT_STATE) { - PDEBUG(D_ERR, - "unexpected state after lo power cmd: %02x", - sd->params.status.systemState); - printstatus(&sd->params); - } - return -EIO; - } - - PDEBUG(D_CONF, "camera now in LOW power state"); - return 0; -} - -static int goto_high_power(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - ret = do_command(gspca_dev, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0); - if (ret) - return ret; - - msleep_interruptible(40); /* windows driver does it too */ - - if (signal_pending(current)) - return -EINTR; - - do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); - if (ret) - return ret; - - if (sd->params.status.systemState != HI_POWER_STATE) { - PDEBUG(D_ERR, "unexpected state after hi power cmd: %02x", - sd->params.status.systemState); - printstatus(&sd->params); - return -EIO; - } - - PDEBUG(D_CONF, "camera now in HIGH power state"); - return 0; -} - -static int get_version_information(struct gspca_dev *gspca_dev) -{ - int ret; - - /* GetCPIAVersion */ - ret = do_command(gspca_dev, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0); - if (ret) - return ret; - - /* GetPnPID */ - return do_command(gspca_dev, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0); -} - -static int save_camera_state(struct gspca_dev *gspca_dev) -{ - int ret; - - ret = do_command(gspca_dev, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); - if (ret) - return ret; - - return do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); -} - -static int command_setformat(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - ret = do_command(gspca_dev, CPIA_COMMAND_SetFormat, - sd->params.format.videoSize, - sd->params.format.subSample, - sd->params.format.yuvOrder, 0); - if (ret) - return ret; - - return do_command(gspca_dev, CPIA_COMMAND_SetROI, - sd->params.roi.colStart, sd->params.roi.colEnd, - sd->params.roi.rowStart, sd->params.roi.rowEnd); -} - -static int command_setcolourparams(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - return do_command(gspca_dev, CPIA_COMMAND_SetColourParams, - sd->params.colourParams.brightness, - sd->params.colourParams.contrast, - sd->params.colourParams.saturation, 0); -} - -static int command_setapcor(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - return do_command(gspca_dev, CPIA_COMMAND_SetApcor, - sd->params.apcor.gain1, - sd->params.apcor.gain2, - sd->params.apcor.gain4, - sd->params.apcor.gain8); -} - -static int command_setvloffset(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - return do_command(gspca_dev, CPIA_COMMAND_SetVLOffset, - sd->params.vlOffset.gain1, - sd->params.vlOffset.gain2, - sd->params.vlOffset.gain4, - sd->params.vlOffset.gain8); -} - -static int command_setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure, - sd->params.exposure.gainMode, - 1, - sd->params.exposure.compMode, - sd->params.exposure.centreWeight, - sd->params.exposure.gain, - sd->params.exposure.fineExp, - sd->params.exposure.coarseExpLo, - sd->params.exposure.coarseExpHi, - sd->params.exposure.redComp, - sd->params.exposure.green1Comp, - sd->params.exposure.green2Comp, - sd->params.exposure.blueComp); - if (ret) - return ret; - - if (sd->params.exposure.expMode != 1) { - ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure, - 0, - sd->params.exposure.expMode, - 0, 0, - sd->params.exposure.gain, - sd->params.exposure.fineExp, - sd->params.exposure.coarseExpLo, - sd->params.exposure.coarseExpHi, - 0, 0, 0, 0); - } - - return ret; -} - -static int command_setcolourbalance(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->params.colourBalance.balanceMode == 1) { - int ret; - - ret = do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, - 1, - sd->params.colourBalance.redGain, - sd->params.colourBalance.greenGain, - sd->params.colourBalance.blueGain); - if (ret) - return ret; - - return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, - 3, 0, 0, 0); - } - if (sd->params.colourBalance.balanceMode == 2) { - return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, - 2, 0, 0, 0); - } - if (sd->params.colourBalance.balanceMode == 3) { - return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, - 3, 0, 0, 0); - } - - return -EINVAL; -} - -static int command_setcompressiontarget(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return do_command(gspca_dev, CPIA_COMMAND_SetCompressionTarget, - sd->params.compressionTarget.frTargeting, - sd->params.compressionTarget.targetFR, - sd->params.compressionTarget.targetQ, 0); -} - -static int command_setyuvtresh(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return do_command(gspca_dev, CPIA_COMMAND_SetYUVThresh, - sd->params.yuvThreshold.yThreshold, - sd->params.yuvThreshold.uvThreshold, 0, 0); -} - -static int command_setcompressionparams(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return do_command_extended(gspca_dev, - CPIA_COMMAND_SetCompressionParams, - 0, 0, 0, 0, - sd->params.compressionParams.hysteresis, - sd->params.compressionParams.threshMax, - sd->params.compressionParams.smallStep, - sd->params.compressionParams.largeStep, - sd->params.compressionParams.decimationHysteresis, - sd->params.compressionParams.frDiffStepThresh, - sd->params.compressionParams.qDiffStepThresh, - sd->params.compressionParams.decimationThreshMod); -} - -static int command_setcompression(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return do_command(gspca_dev, CPIA_COMMAND_SetCompression, - sd->params.compression.mode, - sd->params.compression.decimation, 0, 0); -} - -static int command_setsensorfps(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return do_command(gspca_dev, CPIA_COMMAND_SetSensorFPS, - sd->params.sensorFps.divisor, - sd->params.sensorFps.baserate, 0, 0); -} - -static int command_setflickerctrl(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return do_command(gspca_dev, CPIA_COMMAND_SetFlickerCtrl, - sd->params.flickerControl.flickerMode, - sd->params.flickerControl.coarseJump, - sd->params.flickerControl.allowableOverExposure, - 0); -} - -static int command_setecptiming(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return do_command(gspca_dev, CPIA_COMMAND_SetECPTiming, - sd->params.ecpTiming, 0, 0, 0); -} - -static int command_pause(struct gspca_dev *gspca_dev) -{ - return do_command(gspca_dev, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0); -} - -static int command_resume(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return do_command(gspca_dev, CPIA_COMMAND_InitStreamCap, - 0, sd->params.streamStartLine, 0, 0); -} - -static int command_setlights(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret, p1, p2; - - if (!sd->params.qx3.qx3_detected) - return 0; - - p1 = (sd->params.qx3.bottomlight == 0) << 1; - p2 = (sd->params.qx3.toplight == 0) << 3; - - ret = do_command(gspca_dev, CPIA_COMMAND_WriteVCReg, - 0x90, 0x8f, 0x50, 0); - if (ret) - return ret; - - return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0, - p1 | p2 | 0xe0, 0); -} - -static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply) -{ - /* Everything in here is from the Windows driver */ -/* define for compgain calculation */ -#if 0 -#define COMPGAIN(base, curexp, newexp) \ - (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5) -#define EXP_FROM_COMP(basecomp, curcomp, curexp) \ - (u16)((float)curexp * (float)(u8)(curcomp + 128) / \ - (float)(u8)(basecomp - 128)) -#else - /* equivalent functions without floating point math */ -#define COMPGAIN(base, curexp, newexp) \ - (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2 * newexp))) -#define EXP_FROM_COMP(basecomp, curcomp, curexp) \ - (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128))) -#endif - - struct sd *sd = (struct sd *) gspca_dev; - int currentexp = sd->params.exposure.coarseExpLo + - sd->params.exposure.coarseExpHi * 256; - int ret, startexp; - - if (on) { - int cj = sd->params.flickerControl.coarseJump; - sd->params.flickerControl.flickerMode = 1; - sd->params.flickerControl.disabled = 0; - if (sd->params.exposure.expMode != 2) { - sd->params.exposure.expMode = 2; - sd->exposure_status = EXPOSURE_NORMAL; - } - currentexp = currentexp << sd->params.exposure.gain; - sd->params.exposure.gain = 0; - /* round down current exposure to nearest value */ - startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj; - if (startexp < 1) - startexp = 1; - startexp = (startexp * cj) - 1; - if (FIRMWARE_VERSION(1, 2)) - while (startexp > MAX_EXP_102) - startexp -= cj; - else - while (startexp > MAX_EXP) - startexp -= cj; - sd->params.exposure.coarseExpLo = startexp & 0xff; - sd->params.exposure.coarseExpHi = startexp >> 8; - if (currentexp > startexp) { - if (currentexp > (2 * startexp)) - currentexp = 2 * startexp; - sd->params.exposure.redComp = - COMPGAIN(COMP_RED, currentexp, startexp); - sd->params.exposure.green1Comp = - COMPGAIN(COMP_GREEN1, currentexp, startexp); - sd->params.exposure.green2Comp = - COMPGAIN(COMP_GREEN2, currentexp, startexp); - sd->params.exposure.blueComp = - COMPGAIN(COMP_BLUE, currentexp, startexp); - } else { - sd->params.exposure.redComp = COMP_RED; - sd->params.exposure.green1Comp = COMP_GREEN1; - sd->params.exposure.green2Comp = COMP_GREEN2; - sd->params.exposure.blueComp = COMP_BLUE; - } - if (FIRMWARE_VERSION(1, 2)) - sd->params.exposure.compMode = 0; - else - sd->params.exposure.compMode = 1; - - sd->params.apcor.gain1 = 0x18; - sd->params.apcor.gain2 = 0x18; - sd->params.apcor.gain4 = 0x16; - sd->params.apcor.gain8 = 0x14; - } else { - sd->params.flickerControl.flickerMode = 0; - sd->params.flickerControl.disabled = 1; - /* Average equivalent coarse for each comp channel */ - startexp = EXP_FROM_COMP(COMP_RED, - sd->params.exposure.redComp, currentexp); - startexp += EXP_FROM_COMP(COMP_GREEN1, - sd->params.exposure.green1Comp, currentexp); - startexp += EXP_FROM_COMP(COMP_GREEN2, - sd->params.exposure.green2Comp, currentexp); - startexp += EXP_FROM_COMP(COMP_BLUE, - sd->params.exposure.blueComp, currentexp); - startexp = startexp >> 2; - while (startexp > MAX_EXP && sd->params.exposure.gain < - sd->params.exposure.gainMode - 1) { - startexp = startexp >> 1; - ++sd->params.exposure.gain; - } - if (FIRMWARE_VERSION(1, 2) && startexp > MAX_EXP_102) - startexp = MAX_EXP_102; - if (startexp > MAX_EXP) - startexp = MAX_EXP; - sd->params.exposure.coarseExpLo = startexp & 0xff; - sd->params.exposure.coarseExpHi = startexp >> 8; - sd->params.exposure.redComp = COMP_RED; - sd->params.exposure.green1Comp = COMP_GREEN1; - sd->params.exposure.green2Comp = COMP_GREEN2; - sd->params.exposure.blueComp = COMP_BLUE; - sd->params.exposure.compMode = 1; - sd->params.apcor.gain1 = 0x18; - sd->params.apcor.gain2 = 0x16; - sd->params.apcor.gain4 = 0x24; - sd->params.apcor.gain8 = 0x34; - } - sd->params.vlOffset.gain1 = 20; - sd->params.vlOffset.gain2 = 24; - sd->params.vlOffset.gain4 = 26; - sd->params.vlOffset.gain8 = 26; - - if (apply) { - ret = command_setexposure(gspca_dev); - if (ret) - return ret; - - ret = command_setapcor(gspca_dev); - if (ret) - return ret; - - ret = command_setvloffset(gspca_dev); - if (ret) - return ret; - - ret = command_setflickerctrl(gspca_dev); - if (ret) - return ret; - } - - return 0; -#undef EXP_FROM_COMP -#undef COMPGAIN -} - -/* monitor the exposure and adjust the sensor frame rate if needed */ -static void monitor_exposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 exp_acc, bcomp, gain, coarseL, cmd[8]; - int ret, light_exp, dark_exp, very_dark_exp; - int old_exposure, new_exposure, framerate; - int setfps = 0, setexp = 0, setflicker = 0; - - /* get necessary stats and register settings from camera */ - /* do_command can't handle this, so do it ourselves */ - cmd[0] = CPIA_COMMAND_ReadVPRegs >> 8; - cmd[1] = CPIA_COMMAND_ReadVPRegs & 0xff; - cmd[2] = 30; - cmd[3] = 4; - cmd[4] = 9; - cmd[5] = 8; - cmd[6] = 8; - cmd[7] = 0; - ret = cpia_usb_transferCmd(gspca_dev, cmd); - if (ret) { - err("ReadVPRegs(30,4,9,8) - failed: %d", ret); - return; - } - exp_acc = gspca_dev->usb_buf[0]; - bcomp = gspca_dev->usb_buf[1]; - gain = gspca_dev->usb_buf[2]; - coarseL = gspca_dev->usb_buf[3]; - - light_exp = sd->params.colourParams.brightness + - TC - 50 + EXP_ACC_LIGHT; - if (light_exp > 255) - light_exp = 255; - dark_exp = sd->params.colourParams.brightness + - TC - 50 - EXP_ACC_DARK; - if (dark_exp < 0) - dark_exp = 0; - very_dark_exp = dark_exp / 2; - - old_exposure = sd->params.exposure.coarseExpHi * 256 + - sd->params.exposure.coarseExpLo; - - if (!sd->params.flickerControl.disabled) { - /* Flicker control on */ - int max_comp = FIRMWARE_VERSION(1, 2) ? MAX_COMP : - HIGH_COMP_102; - bcomp += 128; /* decode */ - if (bcomp >= max_comp && exp_acc < dark_exp) { - /* dark */ - if (exp_acc < very_dark_exp) { - /* very dark */ - if (sd->exposure_status == EXPOSURE_VERY_DARK) - ++sd->exposure_count; - else { - sd->exposure_status = - EXPOSURE_VERY_DARK; - sd->exposure_count = 1; - } - } else { - /* just dark */ - if (sd->exposure_status == EXPOSURE_DARK) - ++sd->exposure_count; - else { - sd->exposure_status = EXPOSURE_DARK; - sd->exposure_count = 1; - } - } - } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) { - /* light */ - if (old_exposure <= VERY_LOW_EXP) { - /* very light */ - if (sd->exposure_status == EXPOSURE_VERY_LIGHT) - ++sd->exposure_count; - else { - sd->exposure_status = - EXPOSURE_VERY_LIGHT; - sd->exposure_count = 1; - } - } else { - /* just light */ - if (sd->exposure_status == EXPOSURE_LIGHT) - ++sd->exposure_count; - else { - sd->exposure_status = EXPOSURE_LIGHT; - sd->exposure_count = 1; - } - } - } else { - /* not dark or light */ - sd->exposure_status = EXPOSURE_NORMAL; - } - } else { - /* Flicker control off */ - if (old_exposure >= MAX_EXP && exp_acc < dark_exp) { - /* dark */ - if (exp_acc < very_dark_exp) { - /* very dark */ - if (sd->exposure_status == EXPOSURE_VERY_DARK) - ++sd->exposure_count; - else { - sd->exposure_status = - EXPOSURE_VERY_DARK; - sd->exposure_count = 1; - } - } else { - /* just dark */ - if (sd->exposure_status == EXPOSURE_DARK) - ++sd->exposure_count; - else { - sd->exposure_status = EXPOSURE_DARK; - sd->exposure_count = 1; - } - } - } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) { - /* light */ - if (old_exposure <= VERY_LOW_EXP) { - /* very light */ - if (sd->exposure_status == EXPOSURE_VERY_LIGHT) - ++sd->exposure_count; - else { - sd->exposure_status = - EXPOSURE_VERY_LIGHT; - sd->exposure_count = 1; - } - } else { - /* just light */ - if (sd->exposure_status == EXPOSURE_LIGHT) - ++sd->exposure_count; - else { - sd->exposure_status = EXPOSURE_LIGHT; - sd->exposure_count = 1; - } - } - } else { - /* not dark or light */ - sd->exposure_status = EXPOSURE_NORMAL; - } - } - - framerate = atomic_read(&sd->fps); - if (framerate > 30 || framerate < 1) - framerate = 1; - - if (!sd->params.flickerControl.disabled) { - /* Flicker control on */ - if ((sd->exposure_status == EXPOSURE_VERY_DARK || - sd->exposure_status == EXPOSURE_DARK) && - sd->exposure_count >= DARK_TIME * framerate && - sd->params.sensorFps.divisor < 2) { - - /* dark for too long */ - ++sd->params.sensorFps.divisor; - setfps = 1; - - sd->params.flickerControl.coarseJump = - flicker_jumps[sd->mainsFreq] - [sd->params.sensorFps.baserate] - [sd->params.sensorFps.divisor]; - setflicker = 1; - - new_exposure = sd->params.flickerControl.coarseJump-1; - while (new_exposure < old_exposure / 2) - new_exposure += - sd->params.flickerControl.coarseJump; - sd->params.exposure.coarseExpLo = new_exposure & 0xff; - sd->params.exposure.coarseExpHi = new_exposure >> 8; - setexp = 1; - sd->exposure_status = EXPOSURE_NORMAL; - PDEBUG(D_CONF, "Automatically decreasing sensor_fps"); - - } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT || - sd->exposure_status == EXPOSURE_LIGHT) && - sd->exposure_count >= LIGHT_TIME * framerate && - sd->params.sensorFps.divisor > 0) { - - /* light for too long */ - int max_exp = FIRMWARE_VERSION(1, 2) ? MAX_EXP_102 : - MAX_EXP; - --sd->params.sensorFps.divisor; - setfps = 1; - - sd->params.flickerControl.coarseJump = - flicker_jumps[sd->mainsFreq] - [sd->params.sensorFps.baserate] - [sd->params.sensorFps.divisor]; - setflicker = 1; - - new_exposure = sd->params.flickerControl.coarseJump-1; - while (new_exposure < 2 * old_exposure && - new_exposure + - sd->params.flickerControl.coarseJump < max_exp) - new_exposure += - sd->params.flickerControl.coarseJump; - sd->params.exposure.coarseExpLo = new_exposure & 0xff; - sd->params.exposure.coarseExpHi = new_exposure >> 8; - setexp = 1; - sd->exposure_status = EXPOSURE_NORMAL; - PDEBUG(D_CONF, "Automatically increasing sensor_fps"); - } - } else { - /* Flicker control off */ - if ((sd->exposure_status == EXPOSURE_VERY_DARK || - sd->exposure_status == EXPOSURE_DARK) && - sd->exposure_count >= DARK_TIME * framerate && - sd->params.sensorFps.divisor < 2) { - - /* dark for too long */ - ++sd->params.sensorFps.divisor; - setfps = 1; - - if (sd->params.exposure.gain > 0) { - --sd->params.exposure.gain; - setexp = 1; - } - sd->exposure_status = EXPOSURE_NORMAL; - PDEBUG(D_CONF, "Automatically decreasing sensor_fps"); - - } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT || - sd->exposure_status == EXPOSURE_LIGHT) && - sd->exposure_count >= LIGHT_TIME * framerate && - sd->params.sensorFps.divisor > 0) { - - /* light for too long */ - --sd->params.sensorFps.divisor; - setfps = 1; - - if (sd->params.exposure.gain < - sd->params.exposure.gainMode - 1) { - ++sd->params.exposure.gain; - setexp = 1; - } - sd->exposure_status = EXPOSURE_NORMAL; - PDEBUG(D_CONF, "Automatically increasing sensor_fps"); - } - } - - if (setexp) - command_setexposure(gspca_dev); - - if (setfps) - command_setsensorfps(gspca_dev); - - if (setflicker) - command_setflickerctrl(gspca_dev); -} - -/*-----------------------------------------------------------------*/ -/* if flicker is switched off, this function switches it back on.It checks, - however, that conditions are suitable before restarting it. - This should only be called for firmware version 1.2. - - It also adjust the colour balance when an exposure step is detected - as - long as flicker is running -*/ -static void restart_flicker(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int cam_exposure, old_exp; - - if (!FIRMWARE_VERSION(1, 2)) - return; - - cam_exposure = atomic_read(&sd->cam_exposure); - - if (sd->params.flickerControl.flickerMode == 0 || - cam_exposure == 0) - return; - - old_exp = sd->params.exposure.coarseExpLo + - sd->params.exposure.coarseExpHi*256; - /* - see how far away camera exposure is from a valid - flicker exposure value - */ - cam_exposure %= sd->params.flickerControl.coarseJump; - if (!sd->params.flickerControl.disabled && - cam_exposure <= sd->params.flickerControl.coarseJump - 3) { - /* Flicker control auto-disabled */ - sd->params.flickerControl.disabled = 1; - } - - if (sd->params.flickerControl.disabled && - old_exp > sd->params.flickerControl.coarseJump + - ROUND_UP_EXP_FOR_FLICKER) { - /* exposure is now high enough to switch - flicker control back on */ - set_flicker(gspca_dev, 1, 1); - } -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct cam *cam; - - reset_camera_params(gspca_dev); - - PDEBUG(D_PROBE, "cpia CPiA camera detected (vid/pid 0x%04X:0x%04X)", - id->idVendor, id->idProduct); - - cam = &gspca_dev->cam; - cam->cam_mode = mode; - cam->nmodes = ARRAY_SIZE(mode); - - sd_setfreq(gspca_dev, FREQ_DEF); - - return 0; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int priv, ret; - - /* Start the camera in low power mode */ - if (goto_low_power(gspca_dev)) { - if (sd->params.status.systemState != WARM_BOOT_STATE) { - PDEBUG(D_ERR, "unexpected systemstate: %02x", - sd->params.status.systemState); - printstatus(&sd->params); - return -ENODEV; - } - - /* FIXME: this is just dirty trial and error */ - ret = goto_high_power(gspca_dev); - if (ret) - return ret; - - ret = do_command(gspca_dev, CPIA_COMMAND_DiscardFrame, - 0, 0, 0, 0); - if (ret) - return ret; - - ret = goto_low_power(gspca_dev); - if (ret) - return ret; - } - - /* procedure described in developer's guide p3-28 */ - - /* Check the firmware version. */ - sd->params.version.firmwareVersion = 0; - get_version_information(gspca_dev); - if (sd->params.version.firmwareVersion != 1) { - PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)", - sd->params.version.firmwareVersion); - return -ENODEV; - } - - /* A bug in firmware 1-02 limits gainMode to 2 */ - if (sd->params.version.firmwareRevision <= 2 && - sd->params.exposure.gainMode > 2) { - sd->params.exposure.gainMode = 2; - } - - /* set QX3 detected flag */ - sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 && - sd->params.pnpID.product == 0x0001); - - /* The fatal error checking should be done after - * the camera powers up (developer's guide p 3-38) */ - - /* Set streamState before transition to high power to avoid bug - * in firmware 1-02 */ - ret = do_command(gspca_dev, CPIA_COMMAND_ModifyCameraStatus, - STREAMSTATE, 0, STREAM_NOT_READY, 0); - if (ret) - return ret; - - /* GotoHiPower */ - ret = goto_high_power(gspca_dev); - if (ret) - return ret; - - /* Check the camera status */ - ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); - if (ret) - return ret; - - if (sd->params.status.fatalError) { - PDEBUG(D_ERR, "fatal_error: %04x, vp_status: %04x", - sd->params.status.fatalError, - sd->params.status.vpStatus); - return -EIO; - } - - /* VPVersion can't be retrieved before the camera is in HiPower, - * so get it here instead of in get_version_information. */ - ret = do_command(gspca_dev, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0); - if (ret) - return ret; - - /* Determine video mode settings */ - sd->params.streamStartLine = 120; - - priv = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - if (priv & 0x01) { /* crop */ - sd->params.roi.colStart = 2; - sd->params.roi.rowStart = 6; - } else { - sd->params.roi.colStart = 0; - sd->params.roi.rowStart = 0; - } - - if (priv & 0x02) { /* quarter */ - sd->params.format.videoSize = VIDEOSIZE_QCIF; - sd->params.roi.colStart /= 2; - sd->params.roi.rowStart /= 2; - sd->params.streamStartLine /= 2; - } else - sd->params.format.videoSize = VIDEOSIZE_CIF; - - sd->params.roi.colEnd = sd->params.roi.colStart + - (gspca_dev->width >> 3); - sd->params.roi.rowEnd = sd->params.roi.rowStart + - (gspca_dev->height >> 2); - - /* And now set the camera to a known state */ - ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode, - CPIA_GRAB_CONTINEOUS, 0, 0, 0); - if (ret) - return ret; - /* We start with compression disabled, as we need one uncompressed - frame to handle later compressed frames */ - ret = do_command(gspca_dev, CPIA_COMMAND_SetCompression, - CPIA_COMPRESSION_NONE, - NO_DECIMATION, 0, 0); - if (ret) - return ret; - ret = command_setcompressiontarget(gspca_dev); - if (ret) - return ret; - ret = command_setcolourparams(gspca_dev); - if (ret) - return ret; - ret = command_setformat(gspca_dev); - if (ret) - return ret; - ret = command_setyuvtresh(gspca_dev); - if (ret) - return ret; - ret = command_setecptiming(gspca_dev); - if (ret) - return ret; - ret = command_setcompressionparams(gspca_dev); - if (ret) - return ret; - ret = command_setexposure(gspca_dev); - if (ret) - return ret; - ret = command_setcolourbalance(gspca_dev); - if (ret) - return ret; - ret = command_setsensorfps(gspca_dev); - if (ret) - return ret; - ret = command_setapcor(gspca_dev); - if (ret) - return ret; - ret = command_setflickerctrl(gspca_dev); - if (ret) - return ret; - ret = command_setvloffset(gspca_dev); - if (ret) - return ret; - - /* Start stream */ - ret = command_resume(gspca_dev); - if (ret) - return ret; - - /* Wait 6 frames before turning compression on for the sensor to get - all settings and AEC/ACB to settle */ - sd->first_frame = 6; - sd->exposure_status = EXPOSURE_NORMAL; - sd->exposure_count = 0; - atomic_set(&sd->cam_exposure, 0); - atomic_set(&sd->fps, 0); - - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - command_pause(gspca_dev); - - /* save camera state for later open (developers guide ch 3.5.3) */ - save_camera_state(gspca_dev); - - /* GotoLoPower */ - goto_low_power(gspca_dev); - - /* Update the camera status */ - do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - /* If the last button state is pressed, release it now! */ - if (sd->params.qx3.button) { - /* The camera latch will hold the pressed state until we reset - the latch, so we do not reset sd->params.qx3.button now, to - avoid a false keypress being reported the next sd_start */ - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - } -#endif -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ -#ifdef GSPCA_DEBUG - struct sd *sd = (struct sd *) gspca_dev; -#endif - int ret; - - /* Start / Stop the camera to make sure we are talking to - a supported camera, and to get some information from it - to print. */ - ret = sd_start(gspca_dev); - if (ret) - return ret; - - /* Ensure the QX3 illuminators' states are restored upon resume, - or disable the illuminator controls, if this isn't a QX3 */ - if (sd->params.qx3.qx3_detected) - command_setlights(gspca_dev); - else - gspca_dev->ctrl_dis |= - ((1 << ILLUMINATORS_1_IDX) | (1 << ILLUMINATORS_2_IDX)); - - sd_stopN(gspca_dev); - - PDEBUG(D_PROBE, "CPIA Version: %d.%02d (%d.%d)", - sd->params.version.firmwareVersion, - sd->params.version.firmwareRevision, - sd->params.version.vcVersion, - sd->params.version.vcRevision); - PDEBUG(D_PROBE, "CPIA PnP-ID: %04x:%04x:%04x", - sd->params.pnpID.vendor, sd->params.pnpID.product, - sd->params.pnpID.deviceRevision); - PDEBUG(D_PROBE, "VP-Version: %d.%d %04x", - sd->params.vpVersion.vpVersion, - sd->params.vpVersion.vpRevision, - sd->params.vpVersion.cameraHeadID); - - return 0; -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, - int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* Check for SOF */ - if (len >= 64 && - data[0] == MAGIC_0 && data[1] == MAGIC_1 && - data[16] == sd->params.format.videoSize && - data[17] == sd->params.format.subSample && - data[18] == sd->params.format.yuvOrder && - data[24] == sd->params.roi.colStart && - data[25] == sd->params.roi.colEnd && - data[26] == sd->params.roi.rowStart && - data[27] == sd->params.roi.rowEnd) { - u8 *image; - - atomic_set(&sd->cam_exposure, data[39] * 2); - atomic_set(&sd->fps, data[41]); - - /* Check for proper EOF for last frame */ - image = gspca_dev->image; - if (image != NULL && - gspca_dev->image_len > 4 && - image[gspca_dev->image_len - 4] == 0xff && - image[gspca_dev->image_len - 3] == 0xff && - image[gspca_dev->image_len - 2] == 0xff && - image[gspca_dev->image_len - 1] == 0xff) - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - return; - } - - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static void sd_dq_callback(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* Set the normal compression settings once we have captured a - few uncompressed frames (and AEC has hopefully settled) */ - if (sd->first_frame) { - sd->first_frame--; - if (sd->first_frame == 0) - command_setcompression(gspca_dev); - } - - /* Switch flicker control back on if it got turned off */ - restart_flicker(gspca_dev); - - /* If AEC is enabled, monitor the exposure and - adjust the sensor frame rate if needed */ - if (sd->params.exposure.expMode == 2) - monitor_exposure(gspca_dev); - - /* Update our knowledge of the camera state */ - do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); - do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - sd->params.colourParams.brightness = val; - sd->params.flickerControl.allowableOverExposure = - find_over_exposure(sd->params.colourParams.brightness); - if (gspca_dev->streaming) { - ret = command_setcolourparams(gspca_dev); - if (ret) - return ret; - return command_setflickerctrl(gspca_dev); - } - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->params.colourParams.brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->params.colourParams.contrast = val; - if (gspca_dev->streaming) - return command_setcolourparams(gspca_dev); - - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->params.colourParams.contrast; - return 0; -} - -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->params.colourParams.saturation = val; - if (gspca_dev->streaming) - return command_setcolourparams(gspca_dev); - - return 0; -} - -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->params.colourParams.saturation; - return 0; -} - -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - int on; - - switch (val) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - on = 0; - break; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - on = 1; - sd->mainsFreq = 0; - break; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - on = 1; - sd->mainsFreq = 1; - break; - default: - return -EINVAL; - } - - sd->freq = val; - sd->params.flickerControl.coarseJump = - flicker_jumps[sd->mainsFreq] - [sd->params.sensorFps.baserate] - [sd->params.sensorFps.divisor]; - - return set_flicker(gspca_dev, on, gspca_dev->streaming); -} - -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->freq; - return 0; -} - -static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->params.compressionTarget.frTargeting = val; - if (gspca_dev->streaming) - return command_setcompressiontarget(gspca_dev); - - return 0; -} - -static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->params.compressionTarget.frTargeting; - return 0; -} - -static int sd_setilluminator(struct gspca_dev *gspca_dev, __s32 val, int n) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - if (!sd->params.qx3.qx3_detected) - return -EINVAL; - - switch (n) { - case 1: - sd->params.qx3.bottomlight = val ? 1 : 0; - break; - case 2: - sd->params.qx3.toplight = val ? 1 : 0; - break; - default: - return -EINVAL; - } - - ret = command_setlights(gspca_dev); - if (ret && ret != -EINVAL) - ret = -EBUSY; - - return ret; -} - -static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val) -{ - return sd_setilluminator(gspca_dev, val, 1); -} - -static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val) -{ - return sd_setilluminator(gspca_dev, val, 2); -} - -static int sd_getilluminator(struct gspca_dev *gspca_dev, __s32 *val, int n) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (!sd->params.qx3.qx3_detected) - return -EINVAL; - - switch (n) { - case 1: - *val = sd->params.qx3.bottomlight; - break; - case 2: - *val = sd->params.qx3.toplight; - break; - default: - return -EINVAL; - } - return 0; -} - -static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val) -{ - return sd_getilluminator(gspca_dev, val, 1); -} - -static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val) -{ - return sd_getilluminator(gspca_dev, val, 2); -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - case V4L2_CID_COMP_TARGET: - switch (menu->index) { - case CPIA_COMPRESSION_TARGET_QUALITY: - strcpy((char *) menu->name, "Quality"); - return 0; - case CPIA_COMPRESSION_TARGET_FRAMERATE: - strcpy((char *) menu->name, "Framerate"); - return 0; - } - break; - } - return -EINVAL; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .dq_callback = sd_dq_callback, - .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .other_input = 1, -#endif -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0553, 0x0002)}, - {USB_DEVICE(0x0813, 0x0001)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/etoms.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/etoms.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/etoms.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/etoms.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,908 +0,0 @@ -/* - * Etoms Et61x151 GPL Linux driver by Michel Xhaard (09/09/2004) - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "etoms" - -#include "gspca.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("Etoms USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - unsigned char brightness; - unsigned char contrast; - unsigned char colors; - unsigned char autogain; - - char sensor; -#define SENSOR_PAS106 0 -#define SENSOR_TAS5130CXX 1 - signed char ag_cnt; -#define AG_CNT_START 13 -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 1, - .maximum = 127, - .step = 1, -#define BRIGHTNESS_DEF 63 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, -#define CONTRAST_DEF 127 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define COLOR_IDX 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 15, - .step = 1, -#define COLOR_DEF 7 - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, -/* {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, */ -}; - -static const struct v4l2_pix_format sif_mode[] = { - {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -#define ETOMS_ALT_SIZE_1000 12 - -#define ET_GPIO_DIR_CTRL 0x04 /* Control IO bit[0..5] (0 in 1 out) */ -#define ET_GPIO_OUT 0x05 /* Only IO data */ -#define ET_GPIO_IN 0x06 /* Read Only IO data */ -#define ET_RESET_ALL 0x03 -#define ET_ClCK 0x01 -#define ET_CTRL 0x02 /* enable i2c OutClck Powerdown mode */ - -#define ET_COMP 0x12 /* Compression register */ -#define ET_MAXQt 0x13 -#define ET_MINQt 0x14 -#define ET_COMP_VAL0 0x02 -#define ET_COMP_VAL1 0x03 - -#define ET_REG1d 0x1d -#define ET_REG1e 0x1e -#define ET_REG1f 0x1f -#define ET_REG20 0x20 -#define ET_REG21 0x21 -#define ET_REG22 0x22 -#define ET_REG23 0x23 -#define ET_REG24 0x24 -#define ET_REG25 0x25 -/* base registers for luma calculation */ -#define ET_LUMA_CENTER 0x39 - -#define ET_G_RED 0x4d -#define ET_G_GREEN1 0x4e -#define ET_G_BLUE 0x4f -#define ET_G_GREEN2 0x50 -#define ET_G_GR_H 0x51 -#define ET_G_GB_H 0x52 - -#define ET_O_RED 0x34 -#define ET_O_GREEN1 0x35 -#define ET_O_BLUE 0x36 -#define ET_O_GREEN2 0x37 - -#define ET_SYNCHRO 0x68 -#define ET_STARTX 0x69 -#define ET_STARTY 0x6a -#define ET_WIDTH_LOW 0x6b -#define ET_HEIGTH_LOW 0x6c -#define ET_W_H_HEIGTH 0x6d - -#define ET_REG6e 0x6e /* OBW */ -#define ET_REG6f 0x6f /* OBW */ -#define ET_REG70 0x70 /* OBW_AWB */ -#define ET_REG71 0x71 /* OBW_AWB */ -#define ET_REG72 0x72 /* OBW_AWB */ -#define ET_REG73 0x73 /* Clkdelay ns */ -#define ET_REG74 0x74 /* test pattern */ -#define ET_REG75 0x75 /* test pattern */ - -#define ET_I2C_CLK 0x8c -#define ET_PXL_CLK 0x60 - -#define ET_I2C_BASE 0x89 -#define ET_I2C_COUNT 0x8a -#define ET_I2C_PREFETCH 0x8b -#define ET_I2C_REG 0x88 -#define ET_I2C_DATA7 0x87 -#define ET_I2C_DATA6 0x86 -#define ET_I2C_DATA5 0x85 -#define ET_I2C_DATA4 0x84 -#define ET_I2C_DATA3 0x83 -#define ET_I2C_DATA2 0x82 -#define ET_I2C_DATA1 0x81 -#define ET_I2C_DATA0 0x80 - -#define PAS106_REG2 0x02 /* pxlClk = systemClk/(reg2) */ -#define PAS106_REG3 0x03 /* line/frame H [11..4] */ -#define PAS106_REG4 0x04 /* line/frame L [3..0] */ -#define PAS106_REG5 0x05 /* exposure time line offset(default 5) */ -#define PAS106_REG6 0x06 /* exposure time pixel offset(default 6) */ -#define PAS106_REG7 0x07 /* signbit Dac (default 0) */ -#define PAS106_REG9 0x09 -#define PAS106_REG0e 0x0e /* global gain [4..0](default 0x0e) */ -#define PAS106_REG13 0x13 /* end i2c write */ - -static const __u8 GainRGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; - -static const __u8 I2c2[] = { 0x08, 0x08, 0x08, 0x08, 0x0d }; - -static const __u8 I2c3[] = { 0x12, 0x05 }; - -static const __u8 I2c4[] = { 0x41, 0x08 }; - -/* read 'len' bytes to gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - __u16 index, - __u16 len) -{ - struct usb_device *dev = gspca_dev->dev; - -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); - return; - } -#endif - usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), - 0, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 0, - index, gspca_dev->usb_buf, len, 500); - PDEBUG(D_USBI, "reg read [%02x] -> %02x ..", - index, gspca_dev->usb_buf[0]); -} - -static void reg_w_val(struct gspca_dev *gspca_dev, - __u16 index, - __u8 val) -{ - struct usb_device *dev = gspca_dev->dev; - - gspca_dev->usb_buf[0] = val; - usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 0, - index, gspca_dev->usb_buf, 1, 500); -} - -static void reg_w(struct gspca_dev *gspca_dev, - __u16 index, - const __u8 *buffer, - __u16 len) -{ - struct usb_device *dev = gspca_dev->dev; - -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); - return; - } - PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); -#endif - memcpy(gspca_dev->usb_buf, buffer, len); - usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 0, index, gspca_dev->usb_buf, len, 500); -} - -static int i2c_w(struct gspca_dev *gspca_dev, - __u8 reg, - const __u8 *buffer, - int len, __u8 mode) -{ - /* buffer should be [D0..D7] */ - __u8 ptchcount; - - /* set the base address */ - reg_w_val(gspca_dev, ET_I2C_BASE, 0x40); - /* sensor base for the pas106 */ - /* set count and prefetch */ - ptchcount = ((len & 0x07) << 4) | (mode & 0x03); - reg_w_val(gspca_dev, ET_I2C_COUNT, ptchcount); - /* set the register base */ - reg_w_val(gspca_dev, ET_I2C_REG, reg); - while (--len >= 0) - reg_w_val(gspca_dev, ET_I2C_DATA0 + len, buffer[len]); - return 0; -} - -static int i2c_r(struct gspca_dev *gspca_dev, - __u8 reg) -{ - /* set the base address */ - reg_w_val(gspca_dev, ET_I2C_BASE, 0x40); - /* sensor base for the pas106 */ - /* set count and prefetch (cnd: 4 bits - mode: 4 bits) */ - reg_w_val(gspca_dev, ET_I2C_COUNT, 0x11); - reg_w_val(gspca_dev, ET_I2C_REG, reg); /* set the register base */ - reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x02); /* prefetch */ - reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x00); - reg_r(gspca_dev, ET_I2C_DATA0, 1); /* read one byte */ - return 0; -} - -static int Et_WaitStatus(struct gspca_dev *gspca_dev) -{ - int retry = 10; - - while (retry--) { - reg_r(gspca_dev, ET_ClCK, 1); - if (gspca_dev->usb_buf[0] != 0) - return 1; - } - return 0; -} - -static int et_video(struct gspca_dev *gspca_dev, - int on) -{ - int ret; - - reg_w_val(gspca_dev, ET_GPIO_OUT, - on ? 0x10 /* startvideo - set Bit5 */ - : 0); /* stopvideo */ - ret = Et_WaitStatus(gspca_dev); - if (ret != 0) - PDEBUG(D_ERR, "timeout video on/off"); - return ret; -} - -static void Et_init2(struct gspca_dev *gspca_dev) -{ - __u8 value; - static const __u8 FormLine[] = { 0x84, 0x03, 0x14, 0xf4, 0x01, 0x05 }; - - PDEBUG(D_STREAM, "Open Init2 ET"); - reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 0x2f); - reg_w_val(gspca_dev, ET_GPIO_OUT, 0x10); - reg_r(gspca_dev, ET_GPIO_IN, 1); - reg_w_val(gspca_dev, ET_ClCK, 0x14); /* 0x14 // 0x16 enabled pattern */ - reg_w_val(gspca_dev, ET_CTRL, 0x1b); - - /* compression et subsampling */ - if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) - value = ET_COMP_VAL1; /* 320 */ - else - value = ET_COMP_VAL0; /* 640 */ - reg_w_val(gspca_dev, ET_COMP, value); - reg_w_val(gspca_dev, ET_MAXQt, 0x1f); - reg_w_val(gspca_dev, ET_MINQt, 0x04); - /* undocumented registers */ - reg_w_val(gspca_dev, ET_REG1d, 0xff); - reg_w_val(gspca_dev, ET_REG1e, 0xff); - reg_w_val(gspca_dev, ET_REG1f, 0xff); - reg_w_val(gspca_dev, ET_REG20, 0x35); - reg_w_val(gspca_dev, ET_REG21, 0x01); - reg_w_val(gspca_dev, ET_REG22, 0x00); - reg_w_val(gspca_dev, ET_REG23, 0xff); - reg_w_val(gspca_dev, ET_REG24, 0xff); - reg_w_val(gspca_dev, ET_REG25, 0x0f); - /* colors setting */ - reg_w_val(gspca_dev, 0x30, 0x11); /* 0x30 */ - reg_w_val(gspca_dev, 0x31, 0x40); - reg_w_val(gspca_dev, 0x32, 0x00); - reg_w_val(gspca_dev, ET_O_RED, 0x00); /* 0x34 */ - reg_w_val(gspca_dev, ET_O_GREEN1, 0x00); - reg_w_val(gspca_dev, ET_O_BLUE, 0x00); - reg_w_val(gspca_dev, ET_O_GREEN2, 0x00); - /*************/ - reg_w_val(gspca_dev, ET_G_RED, 0x80); /* 0x4d */ - reg_w_val(gspca_dev, ET_G_GREEN1, 0x80); - reg_w_val(gspca_dev, ET_G_BLUE, 0x80); - reg_w_val(gspca_dev, ET_G_GREEN2, 0x80); - reg_w_val(gspca_dev, ET_G_GR_H, 0x00); - reg_w_val(gspca_dev, ET_G_GB_H, 0x00); /* 0x52 */ - /* Window control registers */ - reg_w_val(gspca_dev, 0x61, 0x80); /* use cmc_out */ - reg_w_val(gspca_dev, 0x62, 0x02); - reg_w_val(gspca_dev, 0x63, 0x03); - reg_w_val(gspca_dev, 0x64, 0x14); - reg_w_val(gspca_dev, 0x65, 0x0e); - reg_w_val(gspca_dev, 0x66, 0x02); - reg_w_val(gspca_dev, 0x67, 0x02); - - /**************************************/ - reg_w_val(gspca_dev, ET_SYNCHRO, 0x8f); /* 0x68 */ - reg_w_val(gspca_dev, ET_STARTX, 0x69); /* 0x6a //0x69 */ - reg_w_val(gspca_dev, ET_STARTY, 0x0d); /* 0x0d //0x0c */ - reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x80); - reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0xe0); - reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x60); /* 6d */ - reg_w_val(gspca_dev, ET_REG6e, 0x86); - reg_w_val(gspca_dev, ET_REG6f, 0x01); - reg_w_val(gspca_dev, ET_REG70, 0x26); - reg_w_val(gspca_dev, ET_REG71, 0x7a); - reg_w_val(gspca_dev, ET_REG72, 0x01); - /* Clock Pattern registers ***************** */ - reg_w_val(gspca_dev, ET_REG73, 0x00); - reg_w_val(gspca_dev, ET_REG74, 0x18); /* 0x28 */ - reg_w_val(gspca_dev, ET_REG75, 0x0f); /* 0x01 */ - /**********************************************/ - reg_w_val(gspca_dev, 0x8a, 0x20); - reg_w_val(gspca_dev, 0x8d, 0x0f); - reg_w_val(gspca_dev, 0x8e, 0x08); - /**************************************/ - reg_w_val(gspca_dev, 0x03, 0x08); - reg_w_val(gspca_dev, ET_PXL_CLK, 0x03); - reg_w_val(gspca_dev, 0x81, 0xff); - reg_w_val(gspca_dev, 0x80, 0x00); - reg_w_val(gspca_dev, 0x81, 0xff); - reg_w_val(gspca_dev, 0x80, 0x20); - reg_w_val(gspca_dev, 0x03, 0x01); - reg_w_val(gspca_dev, 0x03, 0x00); - reg_w_val(gspca_dev, 0x03, 0x08); - /********************************************/ - -/* reg_r(gspca_dev, ET_I2C_BASE, 1); - always 0x40 as the pas106 ??? */ - /* set the sensor */ - if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) - value = 0x04; /* 320 */ - else /* 640 */ - value = 0x1e; /* 0x17 * setting PixelClock - * 0x03 mean 24/(3+1) = 6 Mhz - * 0x05 -> 24/(5+1) = 4 Mhz - * 0x0b -> 24/(11+1) = 2 Mhz - * 0x17 -> 24/(23+1) = 1 Mhz - */ - reg_w_val(gspca_dev, ET_PXL_CLK, value); - /* now set by fifo the FormatLine setting */ - reg_w(gspca_dev, 0x62, FormLine, 6); - - /* set exposure times [ 0..0x78] 0->longvalue 0x78->shortvalue */ - reg_w_val(gspca_dev, 0x81, 0x47); /* 0x47; */ - reg_w_val(gspca_dev, 0x80, 0x40); /* 0x40; */ - /* Pedro change */ - /* Brightness change Brith+ decrease value */ - /* Brigth- increase value */ - /* original value = 0x70; */ - reg_w_val(gspca_dev, 0x81, 0x30); /* 0x20; - set brightness */ - reg_w_val(gspca_dev, 0x80, 0x20); /* 0x20; */ -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - __u8 brightness = sd->brightness; - - for (i = 0; i < 4; i++) - reg_w_val(gspca_dev, ET_O_RED + i, brightness); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; - __u8 contrast = sd->contrast; - - memset(RGBG, contrast, sizeof(RGBG) - 2); - reg_w(gspca_dev, ET_G_RED, RGBG, 6); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d }; - __u8 i2cflags = 0x01; - /* __u8 green = 0; */ - __u8 colors = sd->colors; - - I2cc[3] = colors; /* red */ - I2cc[0] = 15 - colors; /* blue */ - /* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */ - /* I2cc[1] = I2cc[2] = green; */ - if (sd->sensor == SENSOR_PAS106) { - i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3); - i2c_w(gspca_dev, PAS106_REG9, I2cc, sizeof I2cc, 1); - } -/* PDEBUG(D_CONF , "Etoms red %d blue %d green %d", - I2cc[3], I2cc[0], green); */ -} - -static void getcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->sensor == SENSOR_PAS106) { -/* i2c_r(gspca_dev, PAS106_REG9); * blue */ - i2c_r(gspca_dev, PAS106_REG9 + 3); /* red */ - sd->colors = gspca_dev->usb_buf[0] & 0x0f; - } -} - -static void setautogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->autogain) - sd->ag_cnt = AG_CNT_START; - else - sd->ag_cnt = -1; -} - -static void Et_init1(struct gspca_dev *gspca_dev) -{ - __u8 value; -/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0x22, 0xac, 0x00, 0x01, 0x00}; */ - __u8 I2c0[] = { 0x0a, 0x12, 0x05, 0x6d, 0xcd, 0x00, 0x01, 0x00 }; - /* try 1/120 0x6d 0xcd 0x40 */ -/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0xfe, 0xfe, 0xc0, 0x01, 0x00}; - * 1/60000 hmm ?? */ - - PDEBUG(D_STREAM, "Open Init1 ET"); - reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 7); - reg_r(gspca_dev, ET_GPIO_IN, 1); - reg_w_val(gspca_dev, ET_RESET_ALL, 1); - reg_w_val(gspca_dev, ET_RESET_ALL, 0); - reg_w_val(gspca_dev, ET_ClCK, 0x10); - reg_w_val(gspca_dev, ET_CTRL, 0x19); - /* compression et subsampling */ - if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) - value = ET_COMP_VAL1; - else - value = ET_COMP_VAL0; - PDEBUG(D_STREAM, "Open mode %d Compression %d", - gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv, - value); - reg_w_val(gspca_dev, ET_COMP, value); - reg_w_val(gspca_dev, ET_MAXQt, 0x1d); - reg_w_val(gspca_dev, ET_MINQt, 0x02); - /* undocumented registers */ - reg_w_val(gspca_dev, ET_REG1d, 0xff); - reg_w_val(gspca_dev, ET_REG1e, 0xff); - reg_w_val(gspca_dev, ET_REG1f, 0xff); - reg_w_val(gspca_dev, ET_REG20, 0x35); - reg_w_val(gspca_dev, ET_REG21, 0x01); - reg_w_val(gspca_dev, ET_REG22, 0x00); - reg_w_val(gspca_dev, ET_REG23, 0xf7); - reg_w_val(gspca_dev, ET_REG24, 0xff); - reg_w_val(gspca_dev, ET_REG25, 0x07); - /* colors setting */ - reg_w_val(gspca_dev, ET_G_RED, 0x80); - reg_w_val(gspca_dev, ET_G_GREEN1, 0x80); - reg_w_val(gspca_dev, ET_G_BLUE, 0x80); - reg_w_val(gspca_dev, ET_G_GREEN2, 0x80); - reg_w_val(gspca_dev, ET_G_GR_H, 0x00); - reg_w_val(gspca_dev, ET_G_GB_H, 0x00); - /* Window control registers */ - reg_w_val(gspca_dev, ET_SYNCHRO, 0xf0); - reg_w_val(gspca_dev, ET_STARTX, 0x56); /* 0x56 */ - reg_w_val(gspca_dev, ET_STARTY, 0x05); /* 0x04 */ - reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x60); - reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0x20); - reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x50); - reg_w_val(gspca_dev, ET_REG6e, 0x86); - reg_w_val(gspca_dev, ET_REG6f, 0x01); - reg_w_val(gspca_dev, ET_REG70, 0x86); - reg_w_val(gspca_dev, ET_REG71, 0x14); - reg_w_val(gspca_dev, ET_REG72, 0x00); - /* Clock Pattern registers */ - reg_w_val(gspca_dev, ET_REG73, 0x00); - reg_w_val(gspca_dev, ET_REG74, 0x00); - reg_w_val(gspca_dev, ET_REG75, 0x0a); - reg_w_val(gspca_dev, ET_I2C_CLK, 0x04); - reg_w_val(gspca_dev, ET_PXL_CLK, 0x01); - /* set the sensor */ - if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - I2c0[0] = 0x06; - i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1); - i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1); - value = 0x06; - i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1); - i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1); - /* value = 0x1f; */ - value = 0x04; - i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1); - } else { - I2c0[0] = 0x0a; - - i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1); - i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1); - value = 0x0a; - i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1); - i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1); - value = 0x04; - /* value = 0x10; */ - i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1); - /* bit 2 enable bit 1:2 select 0 1 2 3 - value = 0x07; * curve 0 * - i2c_w(gspca_dev, PAS106_REG0f, &value, 1, 1); - */ - } - -/* value = 0x01; */ -/* value = 0x22; */ -/* i2c_w(gspca_dev, PAS106_REG5, &value, 1, 1); */ - /* magnetude and sign bit for DAC */ - i2c_w(gspca_dev, PAS106_REG7, I2c4, sizeof I2c4, 1); - /* now set by fifo the whole colors setting */ - reg_w(gspca_dev, ET_G_RED, GainRGBG, 6); - getcolors(gspca_dev); - setcolors(gspca_dev); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - sd->sensor = id->driver_info; - if (sd->sensor == SENSOR_PAS106) { - cam->cam_mode = sif_mode; - cam->nmodes = ARRAY_SIZE(sif_mode); - } else { - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - gspca_dev->ctrl_dis = (1 << COLOR_IDX); - } - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->ag_cnt = -1; - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->sensor == SENSOR_PAS106) - Et_init1(gspca_dev); - else - Et_init2(gspca_dev); - reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); - et_video(gspca_dev, 0); /* video off */ - return 0; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->sensor == SENSOR_PAS106) - Et_init1(gspca_dev); - else - Et_init2(gspca_dev); - - setautogain(gspca_dev); - - reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); - et_video(gspca_dev, 1); /* video on */ - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - et_video(gspca_dev, 0); /* video off */ -} - -static __u8 Et_getgainG(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->sensor == SENSOR_PAS106) { - i2c_r(gspca_dev, PAS106_REG0e); - PDEBUG(D_CONF, "Etoms gain G %d", gspca_dev->usb_buf[0]); - return gspca_dev->usb_buf[0]; - } - return 0x1f; -} - -static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->sensor == SENSOR_PAS106) { - __u8 i2cflags = 0x01; - - i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3); - i2c_w(gspca_dev, PAS106_REG0e, &gain, 1, 1); - } -} - -#define BLIMIT(bright) \ - (u8)((bright > 0x1f) ? 0x1f : ((bright < 4) ? 3 : bright)) -#define LIMIT(color) \ - (u8)((color > 0xff) ? 0xff : ((color < 0) ? 0 : color)) - -static void do_autogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 luma; - __u8 luma_mean = 128; - __u8 luma_delta = 20; - __u8 spring = 4; - int Gbright; - __u8 r, g, b; - - if (sd->ag_cnt < 0) - return; - if (--sd->ag_cnt >= 0) - return; - sd->ag_cnt = AG_CNT_START; - - Gbright = Et_getgainG(gspca_dev); - reg_r(gspca_dev, ET_LUMA_CENTER, 4); - g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1; - r = gspca_dev->usb_buf[1]; - b = gspca_dev->usb_buf[2]; - r = ((r << 8) - (r << 4) - (r << 3)) >> 10; - b = ((b << 7) >> 10); - g = ((g << 9) + (g << 7) + (g << 5)) >> 10; - luma = LIMIT(r + g + b); - PDEBUG(D_FRAM, "Etoms luma G %d", luma); - if (luma < luma_mean - luma_delta || luma > luma_mean + luma_delta) { - Gbright += (luma_mean - luma) >> spring; - Gbright = BLIMIT(Gbright); - PDEBUG(D_FRAM, "Etoms Gbright %d", Gbright); - Et_setgainG(gspca_dev, (__u8) Gbright); - } -} - -#undef BLIMIT -#undef LIMIT - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - int seqframe; - - seqframe = data[0] & 0x3f; - len = (int) (((data[0] & 0xc0) << 2) | data[1]); - if (seqframe == 0x3f) { - PDEBUG(D_FRAM, - "header packet found datalength %d !!", len); - PDEBUG(D_FRAM, "G %d R %d G %d B %d", - data[2], data[3], data[4], data[5]); - data += 30; - /* don't change datalength as the chips provided it */ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - return; - } - if (len) { - data += 8; - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - } else { /* Drop Packet */ - gspca_dev->last_packet_type = DISCARD_PACKET; - } -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - if (gspca_dev->streaming) - setautogain(gspca_dev); - return 0; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .dq_callback = do_autogain, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, -#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE - {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, -#endif - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/finepix.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/finepix.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/finepix.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/finepix.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,303 +0,0 @@ -/* - * Fujifilm Finepix subdriver - * - * Copyright (C) 2008 Frank Zago - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "finepix" - -#include "gspca.h" - -MODULE_AUTHOR("Frank Zago "); -MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver"); -MODULE_LICENSE("GPL"); - -/* Default timeout, in ms */ -#define FPIX_TIMEOUT 250 - -/* Maximum transfer size to use. The windows driver reads by chunks of - * 0x2000 bytes, so do the same. Note: reading more seems to work - * too. */ -#define FPIX_MAX_TRANSFER 0x2000 - -/* Structure to hold all of our device specific stuff */ -struct usb_fpix { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct work_struct work_struct; - struct workqueue_struct *work_thread; -}; - -/* Delay after which claim the next frame. If the delay is too small, - * the camera will return old frames. On the 4800Z, 20ms is bad, 25ms - * will fail every 4 or 5 frames, but 30ms is perfect. On the A210, - * 30ms is bad while 35ms is perfect. */ -#define NEXT_FRAME_DELAY 35 - -/* These cameras only support 320x200. */ -static const struct v4l2_pix_format fpix_mode[1] = { - { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0} -}; - -/* send a command to the webcam */ -static int command(struct gspca_dev *gspca_dev, - int order) /* 0: reset, 1: frame request */ -{ - static u8 order_values[2][12] = { - {0xc6, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0}, /* reset */ - {0xd3, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0}, /* fr req */ - }; - - memcpy(gspca_dev->usb_buf, order_values[order], 12); - return usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - USB_REQ_GET_STATUS, - USB_DIR_OUT | USB_TYPE_CLASS | - USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf, - 12, FPIX_TIMEOUT); -} - -/* workqueue */ -static void dostream(struct work_struct *work) -{ - struct usb_fpix *dev = container_of(work, struct usb_fpix, work_struct); - struct gspca_dev *gspca_dev = &dev->gspca_dev; - struct urb *urb = gspca_dev->urb[0]; - u8 *data = urb->transfer_buffer; - int ret = 0; - int len; - - /* synchronize with the main driver */ - mutex_lock(&gspca_dev->usb_lock); - mutex_unlock(&gspca_dev->usb_lock); - PDEBUG(D_STREAM, "dostream started"); - - /* loop reading a frame */ -again: - while (gspca_dev->present && gspca_dev->streaming) { - - /* request a frame */ - mutex_lock(&gspca_dev->usb_lock); - ret = command(gspca_dev, 1); - mutex_unlock(&gspca_dev->usb_lock); - if (ret < 0) - break; - if (!gspca_dev->present || !gspca_dev->streaming) - break; - - /* the frame comes in parts */ - for (;;) { - ret = usb_bulk_msg(gspca_dev->dev, - urb->pipe, - data, - FPIX_MAX_TRANSFER, - &len, FPIX_TIMEOUT); - if (ret < 0) { - /* Most of the time we get a timeout - * error. Just restart. */ - goto again; - } - if (!gspca_dev->present || !gspca_dev->streaming) - goto out; - if (len < FPIX_MAX_TRANSFER || - (data[len - 2] == 0xff && - data[len - 1] == 0xd9)) { - - /* If the result is less than what was asked - * for, then it's the end of the - * frame. Sometimes the jpeg is not complete, - * but there's nothing we can do. We also end - * here if the the jpeg ends right at the end - * of the frame. */ - gspca_frame_add(gspca_dev, LAST_PACKET, - data, len); - break; - } - - /* got a partial image */ - gspca_frame_add(gspca_dev, - gspca_dev->last_packet_type - == LAST_PACKET - ? FIRST_PACKET : INTER_PACKET, - data, len); - } - - /* We must wait before trying reading the next - * frame. If we don't, or if the delay is too short, - * the camera will disconnect. */ - msleep(NEXT_FRAME_DELAY); - } - -out: - PDEBUG(D_STREAM, "dostream stopped"); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; - struct cam *cam = &gspca_dev->cam; - - cam->cam_mode = fpix_mode; - cam->nmodes = 1; - cam->bulk = 1; - cam->bulk_size = FPIX_MAX_TRANSFER; - - INIT_WORK(&dev->work_struct, dostream); - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - return 0; -} - -/* start the camera */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; - int ret, len; - - /* Init the device */ - ret = command(gspca_dev, 0); - if (ret < 0) { - err("init failed %d", ret); - return ret; - } - - /* Read the result of the command. Ignore the result, for it - * varies with the device. */ - ret = usb_bulk_msg(gspca_dev->dev, - gspca_dev->urb[0]->pipe, - gspca_dev->urb[0]->transfer_buffer, - FPIX_MAX_TRANSFER, &len, - FPIX_TIMEOUT); - if (ret < 0) { - err("usb_bulk_msg failed %d", ret); - return ret; - } - - /* Request a frame, but don't read it */ - ret = command(gspca_dev, 1); - if (ret < 0) { - err("frame request failed %d", ret); - return ret; - } - - /* Again, reset bulk in endpoint */ - usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe); - - /* Start the workqueue function to do the streaming */ - dev->work_thread = create_singlethread_workqueue(MODULE_NAME); - queue_work(dev->work_thread, &dev->work_struct); - - return 0; -} - -/* called on streamoff with alt==0 and on disconnect */ -/* the usb_lock is held at entry - restore on exit */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; - - /* wait for the work queue to terminate */ - mutex_unlock(&gspca_dev->usb_lock); - destroy_workqueue(dev->work_thread); - mutex_lock(&gspca_dev->usb_lock); - dev->work_thread = NULL; -} - -/* Table of supported USB devices */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x04cb, 0x0104)}, - {USB_DEVICE(0x04cb, 0x0109)}, - {USB_DEVICE(0x04cb, 0x010b)}, - {USB_DEVICE(0x04cb, 0x010f)}, - {USB_DEVICE(0x04cb, 0x0111)}, - {USB_DEVICE(0x04cb, 0x0113)}, - {USB_DEVICE(0x04cb, 0x0115)}, - {USB_DEVICE(0x04cb, 0x0117)}, - {USB_DEVICE(0x04cb, 0x0119)}, - {USB_DEVICE(0x04cb, 0x011b)}, - {USB_DEVICE(0x04cb, 0x011d)}, - {USB_DEVICE(0x04cb, 0x0121)}, - {USB_DEVICE(0x04cb, 0x0123)}, - {USB_DEVICE(0x04cb, 0x0125)}, - {USB_DEVICE(0x04cb, 0x0127)}, - {USB_DEVICE(0x04cb, 0x0129)}, - {USB_DEVICE(0x04cb, 0x012b)}, - {USB_DEVICE(0x04cb, 0x012d)}, - {USB_DEVICE(0x04cb, 0x012f)}, - {USB_DEVICE(0x04cb, 0x0131)}, - {USB_DEVICE(0x04cb, 0x013b)}, - {USB_DEVICE(0x04cb, 0x013d)}, - {USB_DEVICE(0x04cb, 0x013f)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stop0 = sd_stop0, -}; - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, - &sd_desc, - sizeof(struct usb_fpix), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,748 +0,0 @@ -/* GSPCA subdrivers for Genesys Logic webcams with the GL860 chip - * Subdriver core - * - * 2009/09/24 Olivier Lorin - * GSPCA by Jean-Francois Moine - * Thanks BUGabundo and Malmostoso for your amazing help! - * - * 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, or - * any later version. - * - * 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, see . - */ -#include "gspca.h" -#include "gl860.h" - -MODULE_AUTHOR("Olivier Lorin "); -MODULE_DESCRIPTION("Genesys Logic USB PC Camera Driver"); -MODULE_LICENSE("GPL"); - -/*======================== static function declarations ====================*/ - -static void (*dev_init_settings)(struct gspca_dev *gspca_dev); - -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id); -static int sd_init(struct gspca_dev *gspca_dev); -static int sd_isoc_init(struct gspca_dev *gspca_dev); -static int sd_start(struct gspca_dev *gspca_dev); -static void sd_stop0(struct gspca_dev *gspca_dev); -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, int len); -static void sd_callback(struct gspca_dev *gspca_dev); - -static int gl860_guess_sensor(struct gspca_dev *gspca_dev, - u16 vendor_id, u16 product_id); - -/*============================ driver options ==============================*/ - -static s32 AC50Hz = 0xff; -module_param(AC50Hz, int, 0644); -MODULE_PARM_DESC(AC50Hz, " Does AC power frequency is 50Hz? (0/1)"); - -static char sensor[7]; -module_param_string(sensor, sensor, sizeof(sensor), 0644); -MODULE_PARM_DESC(sensor, - " Driver sensor ('MI1320'/'MI2020'/'OV9655'/'OV2640')"); - -/*============================ webcam controls =============================*/ - -/* Functions to get and set a control value */ -#define SD_SETGET(thename) \ -static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\ -{\ - struct sd *sd = (struct sd *) gspca_dev;\ -\ - sd->vcur.thename = val;\ - if (gspca_dev->streaming)\ - sd->waitSet = 1;\ - return 0;\ -} \ -static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\ -{\ - struct sd *sd = (struct sd *) gspca_dev;\ -\ - *val = sd->vcur.thename;\ - return 0;\ -} - -SD_SETGET(mirror) -SD_SETGET(flip) -SD_SETGET(AC50Hz) -SD_SETGET(backlight) -SD_SETGET(brightness) -SD_SETGET(gamma) -SD_SETGET(hue) -SD_SETGET(saturation) -SD_SETGET(sharpness) -SD_SETGET(whitebal) -SD_SETGET(contrast) - -#define GL860_NCTRLS 11 - -/* control table */ -static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS]; -static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS]; -static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS]; -static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS]; - -#define SET_MY_CTRL(theid, \ - thetype, thelabel, thename) \ - if (sd->vmax.thename != 0) {\ - sd_ctrls[nCtrls].qctrl.id = theid;\ - sd_ctrls[nCtrls].qctrl.type = thetype;\ - strcpy(sd_ctrls[nCtrls].qctrl.name, thelabel);\ - sd_ctrls[nCtrls].qctrl.minimum = 0;\ - sd_ctrls[nCtrls].qctrl.maximum = sd->vmax.thename;\ - sd_ctrls[nCtrls].qctrl.default_value = sd->vcur.thename;\ - sd_ctrls[nCtrls].qctrl.step = \ - (sd->vmax.thename < 16) ? 1 : sd->vmax.thename/16;\ - sd_ctrls[nCtrls].set = sd_set_##thename;\ - sd_ctrls[nCtrls].get = sd_get_##thename;\ - nCtrls++;\ - } - -static int gl860_build_control_table(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct ctrl *sd_ctrls; - int nCtrls = 0; - - if (_MI1320_) - sd_ctrls = sd_ctrls_mi1320; - else if (_MI2020_) - sd_ctrls = sd_ctrls_mi2020; - else if (_OV2640_) - sd_ctrls = sd_ctrls_ov2640; - else if (_OV9655_) - sd_ctrls = sd_ctrls_ov9655; - else - return 0; - - memset(sd_ctrls, 0, GL860_NCTRLS * sizeof(struct ctrl)); - - SET_MY_CTRL(V4L2_CID_BRIGHTNESS, - V4L2_CTRL_TYPE_INTEGER, "Brightness", brightness) - SET_MY_CTRL(V4L2_CID_SHARPNESS, - V4L2_CTRL_TYPE_INTEGER, "Sharpness", sharpness) - SET_MY_CTRL(V4L2_CID_CONTRAST, - V4L2_CTRL_TYPE_INTEGER, "Contrast", contrast) - SET_MY_CTRL(V4L2_CID_GAMMA, - V4L2_CTRL_TYPE_INTEGER, "Gamma", gamma) - SET_MY_CTRL(V4L2_CID_HUE, - V4L2_CTRL_TYPE_INTEGER, "Palette", hue) - SET_MY_CTRL(V4L2_CID_SATURATION, - V4L2_CTRL_TYPE_INTEGER, "Saturation", saturation) - SET_MY_CTRL(V4L2_CID_WHITE_BALANCE_TEMPERATURE, - V4L2_CTRL_TYPE_INTEGER, "White Bal.", whitebal) - SET_MY_CTRL(V4L2_CID_BACKLIGHT_COMPENSATION, - V4L2_CTRL_TYPE_INTEGER, "Backlight" , backlight) - - SET_MY_CTRL(V4L2_CID_HFLIP, - V4L2_CTRL_TYPE_BOOLEAN, "Mirror", mirror) - SET_MY_CTRL(V4L2_CID_VFLIP, - V4L2_CTRL_TYPE_BOOLEAN, "Flip", flip) - SET_MY_CTRL(V4L2_CID_POWER_LINE_FREQUENCY, - V4L2_CTRL_TYPE_BOOLEAN, "AC power 50Hz", AC50Hz) - - return nCtrls; -} - -/*==================== sud-driver structure initialisation =================*/ - -static const struct sd_desc sd_desc_mi1320 = { - .name = MODULE_NAME, - .ctrls = sd_ctrls_mi1320, - .nctrls = GL860_NCTRLS, - .config = sd_config, - .init = sd_init, - .isoc_init = sd_isoc_init, - .start = sd_start, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = sd_callback, -}; - -static const struct sd_desc sd_desc_mi2020 = { - .name = MODULE_NAME, - .ctrls = sd_ctrls_mi2020, - .nctrls = GL860_NCTRLS, - .config = sd_config, - .init = sd_init, - .isoc_init = sd_isoc_init, - .start = sd_start, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = sd_callback, -}; - -static const struct sd_desc sd_desc_ov2640 = { - .name = MODULE_NAME, - .ctrls = sd_ctrls_ov2640, - .nctrls = GL860_NCTRLS, - .config = sd_config, - .init = sd_init, - .isoc_init = sd_isoc_init, - .start = sd_start, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = sd_callback, -}; - -static const struct sd_desc sd_desc_ov9655 = { - .name = MODULE_NAME, - .ctrls = sd_ctrls_ov9655, - .nctrls = GL860_NCTRLS, - .config = sd_config, - .init = sd_init, - .isoc_init = sd_isoc_init, - .start = sd_start, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = sd_callback, -}; - -/*=========================== sub-driver image sizes =======================*/ - -static struct v4l2_pix_format mi2020_mode[] = { - { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - }, - { 800, 598, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 800, - .sizeimage = 800 * 598, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 - }, - {1280, 1024, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 1280, - .sizeimage = 1280 * 1024, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2 - }, - {1600, 1198, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 1600, - .sizeimage = 1600 * 1198, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 3 - }, -}; - -static struct v4l2_pix_format ov2640_mode[] = { - { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - }, - { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 800, - .sizeimage = 800 * 600, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 - }, - {1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 1280, - .sizeimage = 1280 * 960, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2 - }, - {1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 1600, - .sizeimage = 1600 * 1200, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 3 - }, -}; - -static struct v4l2_pix_format mi1320_mode[] = { - { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - }, - { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 800, - .sizeimage = 800 * 600, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 - }, - {1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 1280, - .sizeimage = 1280 * 960, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2 - }, -}; - -static struct v4l2_pix_format ov9655_mode[] = { - { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - }, - {1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 1280, - .sizeimage = 1280 * 960, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 - }, -}; - -/*========================= sud-driver functions ===========================*/ - -/* This function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - u16 vendor_id, product_id; - - /* Get USB VendorID and ProductID */ - vendor_id = id->idVendor; - product_id = id->idProduct; - - sd->nbRightUp = 1; - sd->nbIm = -1; - - sd->sensor = 0xff; - if (strcmp(sensor, "MI1320") == 0) - sd->sensor = ID_MI1320; - else if (strcmp(sensor, "OV2640") == 0) - sd->sensor = ID_OV2640; - else if (strcmp(sensor, "OV9655") == 0) - sd->sensor = ID_OV9655; - else if (strcmp(sensor, "MI2020") == 0) - sd->sensor = ID_MI2020; - - /* Get sensor and set the suitable init/start/../stop functions */ - if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1) - return -1; - - cam = &gspca_dev->cam; - gspca_dev->nbalt = 4; - - switch (sd->sensor) { - case ID_MI1320: - gspca_dev->sd_desc = &sd_desc_mi1320; - cam->cam_mode = mi1320_mode; - cam->nmodes = ARRAY_SIZE(mi1320_mode); - dev_init_settings = mi1320_init_settings; - break; - - case ID_MI2020: - gspca_dev->sd_desc = &sd_desc_mi2020; - cam->cam_mode = mi2020_mode; - cam->nmodes = ARRAY_SIZE(mi2020_mode); - dev_init_settings = mi2020_init_settings; - break; - - case ID_OV2640: - gspca_dev->sd_desc = &sd_desc_ov2640; - cam->cam_mode = ov2640_mode; - cam->nmodes = ARRAY_SIZE(ov2640_mode); - dev_init_settings = ov2640_init_settings; - break; - - case ID_OV9655: - gspca_dev->sd_desc = &sd_desc_ov9655; - cam->cam_mode = ov9655_mode; - cam->nmodes = ARRAY_SIZE(ov9655_mode); - dev_init_settings = ov9655_init_settings; - break; - } - - dev_init_settings(gspca_dev); - if (AC50Hz != 0xff) - ((struct sd *) gspca_dev)->vcur.AC50Hz = AC50Hz; - gl860_build_control_table(gspca_dev); - - return 0; -} - -/* This function is called at probe time after sd_config */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return sd->dev_init_at_startup(gspca_dev); -} - -/* This function is called before to choose the alt setting */ -static int sd_isoc_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return sd->dev_configure_alt(gspca_dev); -} - -/* This function is called to start the webcam */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return sd->dev_init_pre_alt(gspca_dev); -} - -/* This function is called to stop the webcam */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - return sd->dev_post_unset_alt(gspca_dev); -} - -/* This function is called when an image is being received */ -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - static s32 nSkipped; - - s32 mode = (s32) gspca_dev->curr_mode; - s32 nToSkip = - sd->swapRB * (gspca_dev->cam.cam_mode[mode].bytesperline + 1); - - /* Test only against 0202h, so endianess does not matter */ - switch (*(s16 *) data) { - case 0x0202: /* End of frame, start a new one */ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - nSkipped = 0; - if (sd->nbIm >= 0 && sd->nbIm < 10) - sd->nbIm++; - gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); - break; - - default: - data += 2; - len -= 2; - if (nSkipped + len <= nToSkip) - nSkipped += len; - else { - if (nSkipped < nToSkip && nSkipped + len > nToSkip) { - data += nToSkip - nSkipped; - len -= nToSkip - nSkipped; - nSkipped = nToSkip + 1; - } - gspca_frame_add(gspca_dev, - INTER_PACKET, data, len); - } - break; - } -} - -/* This function is called when an image has been read */ -/* This function is used to monitor webcam orientation */ -static void sd_callback(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (!_OV9655_) { - u8 state; - u8 upsideDown; - - /* Probe sensor orientation */ - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, (void *)&state); - - /* C8/40 means upside-down (looking backwards) */ - /* D8/50 means right-up (looking onwards) */ - upsideDown = (state == 0xc8 || state == 0x40); - - if (upsideDown && sd->nbRightUp > -4) { - if (sd->nbRightUp > 0) - sd->nbRightUp = 0; - if (sd->nbRightUp == -3) { - sd->mirrorMask = 1; - sd->waitSet = 1; - } - sd->nbRightUp--; - } - if (!upsideDown && sd->nbRightUp < 4) { - if (sd->nbRightUp < 0) - sd->nbRightUp = 0; - if (sd->nbRightUp == 3) { - sd->mirrorMask = 0; - sd->waitSet = 1; - } - sd->nbRightUp++; - } - } - - if (sd->waitSet) - sd->dev_camera_settings(gspca_dev); -} - -/*=================== USB driver structure initialisation ==================*/ - -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x05e3, 0x0503)}, - {USB_DEVICE(0x05e3, 0xf191)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct gspca_dev *gspca_dev; - s32 ret; - - ret = gspca_dev_probe(intf, id, - &sd_desc_mi1320, sizeof(struct sd), THIS_MODULE); - - if (ret >= 0) { - gspca_dev = usb_get_intfdata(intf); - - PDEBUG(D_PROBE, - "Camera is now controlling video device %s", - video_device_node_name(&gspca_dev->vdev)); - } - - return ret; -} - -static void sd_disconnect(struct usb_interface *intf) -{ - gspca_disconnect(intf); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = sd_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/*====================== Init and Exit module functions ====================*/ - -static int __init sd_mod_init(void) -{ - PDEBUG(D_PROBE, "driver startup - version %s", DRIVER_VERSION); - - if (usb_register(&sd_driver) < 0) - return -1; - return 0; -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); - -/*==========================================================================*/ - -int gl860_RTx(struct gspca_dev *gspca_dev, - unsigned char pref, u32 req, u16 val, u16 index, - s32 len, void *pdata) -{ - struct usb_device *udev = gspca_dev->dev; - s32 r = 0; - - if (pref == 0x40) { /* Send */ - if (len > 0) { - memcpy(gspca_dev->usb_buf, pdata, len); - r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - req, pref, val, index, - gspca_dev->usb_buf, - len, 400 + 200 * (len > 1)); - } else { - r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - req, pref, val, index, NULL, len, 400); - } - } else { /* Receive */ - if (len > 0) { - r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - req, pref, val, index, - gspca_dev->usb_buf, - len, 400 + 200 * (len > 1)); - memcpy(pdata, gspca_dev->usb_buf, len); - } else { - r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - req, pref, val, index, NULL, len, 400); - } - } - - if (r < 0) - err("ctrl transfer failed %4d " - "[p%02x r%d v%04x i%04x len%d]", - r, pref, req, val, index, len); - else if (len > 1 && r < len) - PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len); - - msleep(1); - - return r; -} - -int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len) -{ - int n; - - for (n = 0; n < len; n++) { - if (tbl[n].idx != 0xffff) - ctrl_out(gspca_dev, 0x40, 1, tbl[n].val, - tbl[n].idx, 0, NULL); - else if (tbl[n].val == 0xffff) - break; - else - msleep(tbl[n].val); - } - return n; -} - -int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl, - int len, int n) -{ - while (++n < len) { - if (tbl[n].idx != 0xffff) - ctrl_out(gspca_dev, 0x40, 1, tbl[n].val, tbl[n].idx, - 0, NULL); - else if (tbl[n].val == 0xffff) - break; - else - msleep(tbl[n].val); - } - return n; -} - -void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len) -{ - int n; - - for (n = 0; n < len; n++) { - if (memcmp(tbl[n].data, "\xff\xff\xff", 3) != 0) - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, tbl[n].idx, - 3, tbl[n].data); - else - msleep(tbl[n].idx); - } -} - -static int gl860_guess_sensor(struct gspca_dev *gspca_dev, - u16 vendor_id, u16 product_id) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 probe, nb26, nb96, nOV, ntry; - - if (product_id == 0xf191) - sd->sensor = ID_MI1320; - - if (sd->sensor == 0xff) { - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe); - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe); - - ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x0000, 0, NULL); - msleep(3); - ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); - msleep(3); - ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x00c0, 0, NULL); - msleep(3); - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c1, 0, NULL); - msleep(3); - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c2, 0, NULL); - msleep(3); - ctrl_out(gspca_dev, 0x40, 1, 0x0020, 0x0006, 0, NULL); - msleep(3); - ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL); - msleep(56); - - PDEBUG(D_PROBE, "probing for sensor MI2020 or OVXXXX"); - nOV = 0; - for (ntry = 0; ntry < 4; ntry++) { - ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); - msleep(3); - ctrl_out(gspca_dev, 0x40, 1, 0x0063, 0x0006, 0, NULL); - msleep(3); - ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL); - msleep(10); - ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &probe); - PDEBUG(D_PROBE, "probe=0x%02x", probe); - if (probe == 0xff) - nOV++; - } - - if (nOV) { - PDEBUG(D_PROBE, "0xff -> OVXXXX"); - PDEBUG(D_PROBE, "probing for sensor OV2640 or OV9655"); - - nb26 = nb96 = 0; - for (ntry = 0; ntry < 4; ntry++) { - ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, - 0, NULL); - msleep(3); - ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x800a, - 0, NULL); - msleep(10); - - /* Wait for 26(OV2640) or 96(OV9655) */ - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x800a, - 1, &probe); - - if (probe == 0x26 || probe == 0x40) { - PDEBUG(D_PROBE, - "probe=0x%02x -> OV2640", - probe); - sd->sensor = ID_OV2640; - nb26 += 4; - break; - } - if (probe == 0x96 || probe == 0x55) { - PDEBUG(D_PROBE, - "probe=0x%02x -> OV9655", - probe); - sd->sensor = ID_OV9655; - nb96 += 4; - break; - } - PDEBUG(D_PROBE, "probe=0x%02x", probe); - if (probe == 0x00) - nb26++; - if (probe == 0xff) - nb96++; - msleep(3); - } - if (nb26 < 4 && nb96 < 4) - return -1; - } else { - PDEBUG(D_PROBE, "Not any 0xff -> MI2020"); - sd->sensor = ID_MI2020; - } - } - - if (_MI1320_) { - PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)"); - } else if (_MI2020_) { - PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)"); - } else if (_OV9655_) { - PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)"); - } else if (_OV2640_) { - PDEBUG(D_PROBE, "05e3:0503 sensor OV2640 (2.0M)"); - } else { - PDEBUG(D_PROBE, "***** Unknown sensor *****"); - return -1; - } - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -/* GSPCA subdrivers for Genesys Logic webcams with the GL860 chip - * Subdriver declarations - * - * 2009/10/14 Olivier LORIN - * - * 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, or - * any later version. - * - * 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, see . - */ -#ifndef GL860_DEV_H -#define GL860_DEV_H -#include - -#include "gspca.h" - -#define MODULE_NAME "gspca_gl860" -#define DRIVER_VERSION "0.9d10" - -#define ctrl_in gl860_RTx -#define ctrl_out gl860_RTx - -#define ID_MI1320 1 -#define ID_OV2640 2 -#define ID_OV9655 4 -#define ID_MI2020 8 - -#define _MI1320_ (((struct sd *) gspca_dev)->sensor == ID_MI1320) -#define _MI2020_ (((struct sd *) gspca_dev)->sensor == ID_MI2020) -#define _OV2640_ (((struct sd *) gspca_dev)->sensor == ID_OV2640) -#define _OV9655_ (((struct sd *) gspca_dev)->sensor == ID_OV9655) - -#define IMAGE_640 0 -#define IMAGE_800 1 -#define IMAGE_1280 2 -#define IMAGE_1600 3 - -struct sd_gl860 { - u16 backlight; - u16 brightness; - u16 sharpness; - u16 contrast; - u16 gamma; - u16 hue; - u16 saturation; - u16 whitebal; - u8 mirror; - u8 flip; - u8 AC50Hz; -}; - -/* Specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct sd_gl860 vcur; - struct sd_gl860 vold; - struct sd_gl860 vmax; - - int (*dev_configure_alt) (struct gspca_dev *); - int (*dev_init_at_startup)(struct gspca_dev *); - int (*dev_init_pre_alt) (struct gspca_dev *); - void (*dev_post_unset_alt) (struct gspca_dev *); - int (*dev_camera_settings)(struct gspca_dev *); - - u8 swapRB; - u8 mirrorMask; - u8 sensor; - s32 nbIm; - s32 nbRightUp; - u8 waitSet; -}; - -struct validx { - u16 val; - u16 idx; -}; - -struct idxdata { - u8 idx; - u8 data[3]; -}; - -int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len); -int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl, - int len, int n); -void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len); - -int gl860_RTx(struct gspca_dev *gspca_dev, - unsigned char pref, u32 req, u16 val, u16 index, - s32 len, void *pdata); - -void mi1320_init_settings(struct gspca_dev *); -void ov2640_init_settings(struct gspca_dev *); -void ov9655_init_settings(struct gspca_dev *); -void mi2020_init_settings(struct gspca_dev *); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-mi1320.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-mi1320.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-mi1320.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-mi1320.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,536 +0,0 @@ -/* Subdriver for the GL860 chip with the MI1320 sensor - * Author Olivier LORIN from own logs - * - * 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, or - * any later version. - * - * 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, see . - */ - -/* Sensor : MI1320 */ - -#include "gl860.h" - -static struct validx tbl_common[] = { - {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba51, 0x0066}, {0xba02, 0x00f1}, - {0xba05, 0x0067}, {0xba05, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1}, - {0xffff, 0xffff}, - {0xba00, 0x00f0}, {0xba02, 0x00f1}, {0xbafa, 0x0028}, {0xba02, 0x00f1}, - {0xba00, 0x00f0}, {0xba01, 0x00f1}, {0xbaf0, 0x0006}, {0xba0e, 0x00f1}, - {0xba70, 0x0006}, {0xba0e, 0x00f1}, - {0xffff, 0xffff}, - {0xba74, 0x0006}, {0xba0e, 0x00f1}, - {0xffff, 0xffff}, - {0x0061, 0x0000}, {0x0068, 0x000d}, -}; - -static struct validx tbl_init_at_startup[] = { - {0x0000, 0x0000}, {0x0010, 0x0010}, - {35, 0xffff}, - {0x0008, 0x00c0}, {0x0001, 0x00c1}, {0x0001, 0x00c2}, {0x0020, 0x0006}, - {0x006a, 0x000d}, -}; - -static struct validx tbl_sensor_settings_common[] = { - {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0040, 0x0000}, - {0x006a, 0x0007}, {0x006a, 0x000d}, {0x0063, 0x0006}, -}; -static struct validx tbl_sensor_settings_1280[] = { - {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1}, - {0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1}, -}; -static struct validx tbl_sensor_settings_800[] = { - {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1}, - {0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1}, -}; -static struct validx tbl_sensor_settings_640[] = { - {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1}, - {0xba51, 0x0066}, {0xba02, 0x00f1}, {0xba05, 0x0067}, {0xba05, 0x00f1}, - {0xba20, 0x0065}, {0xba00, 0x00f1}, -}; -static struct validx tbl_post_unset_alt[] = { - {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1}, - {0x0061, 0x0000}, {0x0068, 0x000d}, -}; - -static u8 *tbl_1280[] = { - "\x0d\x80\xf1\x08\x03\x04\xf1\x00" "\x04\x05\xf1\x02\x05\x00\xf1\xf1" - "\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08" - "\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00" - "\xa9\x04\xf1\x00\xa1\x05\xf1\x00" "\xa4\x04\xf1\x00\xae\x0a\xf1\x08" - , - "\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47" - "\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c" - "\xd2\x00\xf1\xcf\xcb\x00\xf1\x01" - , - "\xd3\x02\xd4\x28\xd5\x01\xd0\x02" "\xd1\x18\xd2\xc1" -}; - -static u8 *tbl_800[] = { - "\x0d\x80\xf1\x08\x03\x03\xf1\xc0" "\x04\x05\xf1\x02\x05\x00\xf1\xf1" - "\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08" - "\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00" - "\xa9\x03\xf1\xc0\xa1\x03\xf1\x20" "\xa4\x02\xf1\x5a\xae\x0a\xf1\x08" - , - "\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47" - "\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c" - "\xd2\x00\xf1\xcf\xcb\x00\xf1\x01" - , - "\xd3\x02\xd4\x18\xd5\x21\xd0\x02" "\xd1\x10\xd2\x59" -}; - -static u8 *tbl_640[] = { - "\x0d\x80\xf1\x08\x03\x04\xf1\x04" "\x04\x05\xf1\x02\x07\x01\xf1\x7c" - "\x08\x00\xf1\x0e\x21\x80\xf1\x00" "\x0d\x00\xf1\x08\xf0\x00\xf1\x01" - "\x34\x10\xf1\x10\x3a\x43\xf1\x00" "\xa6\x05\xf1\x02\xa9\x04\xf1\x04" - "\xa7\x02\xf1\x81\xaa\x01\xf1\xe2" "\xae\x0c\xf1\x09" - , - "\xf0\x00\xf1\x02\x39\x03\xf1\xfc" "\x3b\x04\xf1\x04\x57\x01\xf1\xb6" - "\x58\x02\xf1\x0d\x5c\x1f\xf1\x19" "\x5d\x24\xf1\x1e\x64\x5e\xf1\x1c" - "\xd2\x00\xf1\x00\xcb\x00\xf1\x01" - , - "\xd3\x02\xd4\x10\xd5\x81\xd0\x02" "\xd1\x08\xd2\xe1" -}; - -static s32 tbl_sat[] = {0x25, 0x1d, 0x15, 0x0d, 0x05, 0x4d, 0x55, 0x5d, 0x2d}; -static s32 tbl_bright[] = {0, 8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70}; -static s32 tbl_backlight[] = {0x0e, 0x06, 0x02}; - -static s32 tbl_cntr1[] = { - 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xe0, 0xf0}; -static s32 tbl_cntr2[] = { - 0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40, 0x38, 0x30, 0x20, 0x10}; - -static u8 dat_wbalNL[] = - "\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x3b\x04\xf1\x2a\x47\x10\xf1\x10" - "\x9d\x3c\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\x91\xf1\x20" - "\x9c\x91\xf1\x20\x37\x03\xf1\x00" "\x9d\xc5\xf1\x0f\xf0\x00\xf1\x00"; - -static u8 dat_wbalLL[] = - "\xf0\x00\xf1\x01\x05\x00\xf1\x0c" "\x3b\x04\xf1\x2a\x47\x40\xf1\x40" - "\x9d\x20\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\xd1\xf1\x00" - "\x9c\xd1\xf1\x00\x37\x03\xf1\x00" "\x9d\xc5\xf1\x3f\xf0\x00\xf1\x00"; - -static u8 dat_wbalBL[] = - "\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x47\x10\xf1\x30\x9d\x3c\xf1\xae" - "\xaf\x10\xf1\x00\xf0\x00\xf1\x02" "\x2f\x91\xf1\x20\x9c\x91\xf1\x20" - "\x37\x03\xf1\x00\x9d\xc5\xf1\x2f" "\xf0\x00\xf1\x00"; - -static u8 dat_hvflip1[] = {0xf0, 0x00, 0xf1, 0x00}; - -static u8 dat_common00[] = - "\x00\x01\x07\x6a\x06\x63\x0d\x6a" "\xc0\x00\x10\x10\xc1\x03\xc2\x42" - "\xd8\x04\x58\x00\x04\x02"; -static u8 dat_common01[] = - "\x0d\x00\xf1\x0b\x0d\x00\xf1\x08" "\x35\x00\xf1\x22\x68\x00\xf1\x5d" - "\xf0\x00\xf1\x01\x06\x70\xf1\x0e" "\xf0\x00\xf1\x02\xdd\x18\xf1\xe0"; -static u8 dat_common02[] = - "\x05\x01\xf1\x84\x06\x00\xf1\x44" "\x07\x00\xf1\xbe\x08\x00\xf1\x1e" - "\x20\x01\xf1\x03\x21\x84\xf1\x00" "\x22\x0d\xf1\x0f\x24\x80\xf1\x00" - "\x34\x18\xf1\x2d\x35\x00\xf1\x22" "\x43\x83\xf1\x83\x59\x00\xf1\xff"; -static u8 dat_common03[] = - "\xf0\x00\xf1\x02\x39\x06\xf1\x8c" "\x3a\x06\xf1\x8c\x3b\x03\xf1\xda" - "\x3c\x05\xf1\x30\x57\x01\xf1\x0c" "\x58\x01\xf1\x42\x59\x01\xf1\x0c" - "\x5a\x01\xf1\x42\x5c\x13\xf1\x0e" "\x5d\x17\xf1\x12\x64\x1e\xf1\x1c"; -static u8 dat_common04[] = - "\xf0\x00\xf1\x02\x24\x5f\xf1\x20" "\x28\xea\xf1\x02\x5f\x41\xf1\x43"; -static u8 dat_common05[] = - "\x02\x00\xf1\xee\x03\x29\xf1\x1a" "\x04\x02\xf1\xa4\x09\x00\xf1\x68" - "\x0a\x00\xf1\x2a\x0b\x00\xf1\x04" "\x0c\x00\xf1\x93\x0d\x00\xf1\x82" - "\x0e\x00\xf1\x40\x0f\x00\xf1\x5f" "\x10\x00\xf1\x4e\x11\x00\xf1\x5b"; -static u8 dat_common06[] = - "\x15\x00\xf1\xc9\x16\x00\xf1\x5e" "\x17\x00\xf1\x9d\x18\x00\xf1\x06" - "\x19\x00\xf1\x89\x1a\x00\xf1\x12" "\x1b\x00\xf1\xa1\x1c\x00\xf1\xe4" - "\x1d\x00\xf1\x7a\x1e\x00\xf1\x64" "\xf6\x00\xf1\x5f"; -static u8 dat_common07[] = - "\xf0\x00\xf1\x01\x53\x09\xf1\x03" "\x54\x3d\xf1\x1c\x55\x99\xf1\x72" - "\x56\xc1\xf1\xb1\x57\xd8\xf1\xce" "\x58\xe0\xf1\x00\xdc\x0a\xf1\x03" - "\xdd\x45\xf1\x20\xde\xae\xf1\x82" "\xdf\xdc\xf1\xc9\xe0\xf6\xf1\xea" - "\xe1\xff\xf1\x00"; -static u8 dat_common08[] = - "\xf0\x00\xf1\x01\x80\x00\xf1\x06" "\x81\xf6\xf1\x08\x82\xfb\xf1\xf7" - "\x83\x00\xf1\xfe\xb6\x07\xf1\x03" "\xb7\x18\xf1\x0c\x84\xfb\xf1\x06" - "\x85\xfb\xf1\xf9\x86\x00\xf1\xff" "\xb8\x07\xf1\x04\xb9\x16\xf1\x0a"; -static u8 dat_common09[] = - "\x87\xfa\xf1\x05\x88\xfc\xf1\xf9" "\x89\x00\xf1\xff\xba\x06\xf1\x03" - "\xbb\x17\xf1\x09\x8a\xe8\xf1\x14" "\x8b\xf7\xf1\xf0\x8c\xfd\xf1\xfa" - "\x8d\x00\xf1\x00\xbc\x05\xf1\x01" "\xbd\x0c\xf1\x08\xbe\x00\xf1\x14"; -static u8 dat_common10[] = - "\x8e\xea\xf1\x13\x8f\xf7\xf1\xf2" "\x90\xfd\xf1\xfa\x91\x00\xf1\x00" - "\xbf\x05\xf1\x01\xc0\x0a\xf1\x08" "\xc1\x00\xf1\x0c\x92\xed\xf1\x0f" - "\x93\xf9\xf1\xf4\x94\xfe\xf1\xfb" "\x95\x00\xf1\x00\xc2\x04\xf1\x01" - "\xc3\x0a\xf1\x07\xc4\x00\xf1\x10"; -static u8 dat_common11[] = - "\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x25\x00\xf1\x55\x34\x10\xf1\x10" - "\x35\xf0\xf1\x10\x3a\x02\xf1\x03" "\x3b\x04\xf1\x2a\x9b\x43\xf1\x00" - "\xa4\x03\xf1\xc0\xa7\x02\xf1\x81"; - -static int mi1320_init_at_startup(struct gspca_dev *gspca_dev); -static int mi1320_configure_alt(struct gspca_dev *gspca_dev); -static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev); -static int mi1320_init_post_alt(struct gspca_dev *gspca_dev); -static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev); -static int mi1320_sensor_settings(struct gspca_dev *gspca_dev); -static int mi1320_camera_settings(struct gspca_dev *gspca_dev); -/*==========================================================================*/ - -void mi1320_init_settings(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vcur.backlight = 0; - sd->vcur.brightness = 0; - sd->vcur.sharpness = 6; - sd->vcur.contrast = 10; - sd->vcur.gamma = 20; - sd->vcur.hue = 0; - sd->vcur.saturation = 6; - sd->vcur.whitebal = 0; - sd->vcur.mirror = 0; - sd->vcur.flip = 0; - sd->vcur.AC50Hz = 1; - - sd->vmax.backlight = 2; - sd->vmax.brightness = 8; - sd->vmax.sharpness = 7; - sd->vmax.contrast = 0; /* 10 but not working with tihs driver */ - sd->vmax.gamma = 40; - sd->vmax.hue = 5 + 1; - sd->vmax.saturation = 8; - sd->vmax.whitebal = 2; - sd->vmax.mirror = 1; - sd->vmax.flip = 1; - sd->vmax.AC50Hz = 1; - - sd->dev_camera_settings = mi1320_camera_settings; - sd->dev_init_at_startup = mi1320_init_at_startup; - sd->dev_configure_alt = mi1320_configure_alt; - sd->dev_init_pre_alt = mi1320_init_pre_alt; - sd->dev_post_unset_alt = mi1320_post_unset_alt; -} - -/*==========================================================================*/ - -static void common(struct gspca_dev *gspca_dev) -{ - s32 n; /* reserved for FETCH functions */ - - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 22, dat_common00); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 32, dat_common01); - n = fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common)); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common02); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common03); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 16, dat_common04); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common05); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 44, dat_common06); - keep_on_fetching_validx(gspca_dev, tbl_common, - ARRAY_SIZE(tbl_common), n); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 52, dat_common07); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common08); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common09); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 56, dat_common10); - keep_on_fetching_validx(gspca_dev, tbl_common, - ARRAY_SIZE(tbl_common), n); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, dat_common11); - keep_on_fetching_validx(gspca_dev, tbl_common, - ARRAY_SIZE(tbl_common), n); -} - -static int mi1320_init_at_startup(struct gspca_dev *gspca_dev) -{ - fetch_validx(gspca_dev, tbl_init_at_startup, - ARRAY_SIZE(tbl_init_at_startup)); - - common(gspca_dev); - -/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */ - - return 0; -} - -static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->mirrorMask = 0; - - sd->vold.backlight = -1; - sd->vold.brightness = -1; - sd->vold.sharpness = -1; - sd->vold.contrast = -1; - sd->vold.saturation = -1; - sd->vold.gamma = -1; - sd->vold.hue = -1; - sd->vold.whitebal = -1; - sd->vold.mirror = -1; - sd->vold.flip = -1; - sd->vold.AC50Hz = -1; - - common(gspca_dev); - - mi1320_sensor_settings(gspca_dev); - - mi1320_init_post_alt(gspca_dev); - - return 0; -} - -static int mi1320_init_post_alt(struct gspca_dev *gspca_dev) -{ - mi1320_camera_settings(gspca_dev); - - return 0; -} - -static int mi1320_sensor_settings(struct gspca_dev *gspca_dev) -{ - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - - ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); - - fetch_validx(gspca_dev, tbl_sensor_settings_common, - ARRAY_SIZE(tbl_sensor_settings_common)); - - switch (reso) { - case IMAGE_1280: - fetch_validx(gspca_dev, tbl_sensor_settings_1280, - ARRAY_SIZE(tbl_sensor_settings_1280)); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_1280[0]); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_1280[1]); - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_1280[2]); - break; - - case IMAGE_800: - fetch_validx(gspca_dev, tbl_sensor_settings_800, - ARRAY_SIZE(tbl_sensor_settings_800)); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_800[0]); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_800[1]); - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_800[2]); - break; - - default: - fetch_validx(gspca_dev, tbl_sensor_settings_640, - ARRAY_SIZE(tbl_sensor_settings_640)); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 60, tbl_640[0]); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_640[1]); - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_640[2]); - break; - } - return 0; -} - -static int mi1320_configure_alt(struct gspca_dev *gspca_dev) -{ - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - - switch (reso) { - case IMAGE_640: - gspca_dev->alt = 3 + 1; - break; - - case IMAGE_800: - case IMAGE_1280: - gspca_dev->alt = 1 + 1; - break; - } - return 0; -} - -static int mi1320_camera_settings(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - s32 backlight = sd->vcur.backlight; - s32 bright = sd->vcur.brightness; - s32 sharp = sd->vcur.sharpness; - s32 cntr = sd->vcur.contrast; - s32 gam = sd->vcur.gamma; - s32 hue = sd->vcur.hue; - s32 sat = sd->vcur.saturation; - s32 wbal = sd->vcur.whitebal; - s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); - s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); - s32 freq = (sd->vcur.AC50Hz > 0); - s32 i; - - if (freq != sd->vold.AC50Hz) { - sd->vold.AC50Hz = freq; - - freq = 2 * (freq == 0); - ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba02, 0x00f1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x005b, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba01 + freq, 0x00f1, 0, NULL); - } - - if (wbal != sd->vold.whitebal) { - sd->vold.whitebal = wbal; - if (wbal < 0 || wbal > sd->vmax.whitebal) - wbal = 0; - - for (i = 0; i < 2; i++) { - if (wbal == 0) { /* Normal light */ - ctrl_out(gspca_dev, 0x40, 1, - 0x0010, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, - 0x0003, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, - 0x0042, 0x00c2, 0, NULL); - ctrl_out(gspca_dev, 0x40, 3, - 0xba00, 0x0200, 48, dat_wbalNL); - } - - if (wbal == 1) { /* Low light */ - ctrl_out(gspca_dev, 0x40, 1, - 0x0010, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, - 0x0004, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, - 0x0043, 0x00c2, 0, NULL); - ctrl_out(gspca_dev, 0x40, 3, - 0xba00, 0x0200, 48, dat_wbalLL); - } - - if (wbal == 2) { /* Back light */ - ctrl_out(gspca_dev, 0x40, 1, - 0x0010, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, - 0x0003, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, - 0x0042, 0x00c2, 0, NULL); - ctrl_out(gspca_dev, 0x40, 3, - 0xba00, 0x0200, 44, dat_wbalBL); - } - } - } - - if (bright != sd->vold.brightness) { - sd->vold.brightness = bright; - if (bright < 0 || bright > sd->vmax.brightness) - bright = 0; - - bright = tbl_bright[bright]; - ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x0034, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x00f1, 0, NULL); - } - - if (sat != sd->vold.saturation) { - sd->vold.saturation = sat; - if (sat < 0 || sat > sd->vmax.saturation) - sat = 0; - - sat = tbl_sat[sat]; - ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x0025, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sat, 0x00f1, 0, NULL); - } - - if (sharp != sd->vold.sharpness) { - sd->vold.sharpness = sharp; - if (sharp < 0 || sharp > sd->vmax.sharpness) - sharp = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x0005, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sharp, 0x00f1, 0, NULL); - } - - if (hue != sd->vold.hue) { - /* 0=normal 1=NB 2="sepia" 3=negative 4=other 5=other2 */ - if (hue < 0 || hue > sd->vmax.hue) - hue = 0; - if (hue == sd->vmax.hue) - sd->swapRB = 1; - else - sd->swapRB = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1, - 0, NULL); - } - - if (backlight != sd->vold.backlight) { - sd->vold.backlight = backlight; - if (backlight < 0 || backlight > sd->vmax.backlight) - backlight = 0; - - backlight = tbl_backlight[backlight]; - for (i = 0; i < 2; i++) { - ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba74, 0x0006, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba80 + backlight, 0x00f1, - 0, NULL); - } - } - - if (hue != sd->vold.hue) { - sd->vold.hue = hue; - - ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1, - 0, NULL); - } - - if (mirror != sd->vold.mirror || flip != sd->vold.flip) { - u8 dat_hvflip2[4] = {0x20, 0x01, 0xf1, 0x00}; - sd->vold.mirror = mirror; - sd->vold.flip = flip; - - dat_hvflip2[3] = flip + 2 * mirror; - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip1); - ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip2); - } - - if (gam != sd->vold.gamma) { - sd->vold.gamma = gam; - if (gam < 0 || gam > sd->vmax.gamma) - gam = 0; - - gam = 2 * gam; - ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba04 , 0x003b, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba02 + gam, 0x00f1, 0, NULL); - } - - if (cntr != sd->vold.contrast) { - sd->vold.contrast = cntr; - if (cntr < 0 || cntr > sd->vmax.contrast) - cntr = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr1[cntr], 0x0035, - 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr2[cntr], 0x00f1, - 0, NULL); - } - - return 0; -} - -static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev) -{ - ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); - - fetch_validx(gspca_dev, tbl_post_unset_alt, - ARRAY_SIZE(tbl_post_unset_alt)); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-mi2020.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-mi2020.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-mi2020.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-mi2020.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,733 +0,0 @@ -/* Subdriver for the GL860 chip with the MI2020 sensor - * Author Olivier LORIN, from logs by Iceman/Soro2005 + Fret_saw/Hulkie/Tricid - * with the help of Kytrix/BUGabundo/Blazercist. - * Driver achieved thanks to a webcam gift by Kytrix. - * - * 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, or - * any later version. - * - * 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, see . - */ - -/* Sensor : MI2020 */ - -#include "gl860.h" - -static u8 dat_wbal1[] = {0x8c, 0xa2, 0x0c}; - -static u8 dat_bright1[] = {0x8c, 0xa2, 0x06}; -static u8 dat_bright3[] = {0x8c, 0xa1, 0x02}; -static u8 dat_bright4[] = {0x90, 0x00, 0x0f}; -static u8 dat_bright5[] = {0x8c, 0xa1, 0x03}; -static u8 dat_bright6[] = {0x90, 0x00, 0x05}; - -static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19}; -static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b}; -static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03}; -static u8 dat_hvflip6[] = {0x90, 0x00, 0x06}; - -static struct idxdata tbl_middle_hvflip_low[] = { - {0x33, "\x90\x00\x06"}, - {6, "\xff\xff\xff"}, - {0x33, "\x90\x00\x06"}, - {6, "\xff\xff\xff"}, - {0x33, "\x90\x00\x06"}, - {6, "\xff\xff\xff"}, - {0x33, "\x90\x00\x06"}, - {6, "\xff\xff\xff"}, -}; - -static struct idxdata tbl_middle_hvflip_big[] = { - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, - {102, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"}, - {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, -}; - -static struct idxdata tbl_end_hvflip[] = { - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, - {6, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, - {6, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, - {6, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, -}; - -static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 }; - -static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 }; -static u8 dat_multi6[] = { 0x90, 0x00, 0x05 }; - -static struct validx tbl_init_at_startup[] = { - {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1}, - {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d}, - {53, 0xffff}, - {0x0040, 0x0000}, {0x0063, 0x0006}, -}; - -static struct validx tbl_common_0B[] = { - {0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d}, - {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, - {0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000}, -}; - -static struct idxdata tbl_common_3B[] = { - {0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"}, - {2, "\xff\xff\xff"}, - {0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"}, - {6, "\xff\xff\xff"}, /* 12 */ - {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, - {2, "\xff\xff\xff"}, /* - */ - {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\x22\x23"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0f"}, {0x33, "\x90\x00\x0d"}, - {0x33, "\x8c\xa2\x10"}, {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x11"}, - {0x33, "\x90\x00\x07"}, {0x33, "\xf4\x03\x1d"}, {0x35, "\xa2\x00\xe2"}, - {0x33, "\x8c\xab\x05"}, {0x33, "\x90\x00\x01"}, {0x32, "\x6e\x00\x86"}, - {0x32, "\x70\x0f\xaa"}, {0x32, "\x72\x0f\xe4"}, {0x33, "\x8c\xa3\x4a"}, - {0x33, "\x90\x00\x5a"}, {0x33, "\x8c\xa3\x4b"}, {0x33, "\x90\x00\xa6"}, - {0x33, "\x8c\xa3\x61"}, {0x33, "\x90\x00\xc8"}, {0x33, "\x8c\xa3\x62"}, - {0x33, "\x90\x00\xe1"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, - {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, - {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, - {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, - {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, - {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, - {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, - {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, - {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, - {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, - {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, - {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, - {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, - {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, - {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, - {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, - {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, - {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, - {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, - {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, - {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, - {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, - {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, - {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, - {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, - {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, - {0x33, "\x78\x00\x00"}, - {2, "\xff\xff\xff"}, - {0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"}, - {0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"}, - {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"}, - {0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"}, - {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"}, - {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"}, - {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"}, - {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"}, - {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"}, - {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"}, - {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, - {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"}, - {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"}, - {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"}, - {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"}, - {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"}, - {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"}, - {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"}, - {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"}, - {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"}, - {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"}, - {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"}, - {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"}, - {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"}, - {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"}, - {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"}, - {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"}, - {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"}, - {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, - {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"}, - {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"}, - {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"}, - {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"}, - {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"}, - {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"}, - {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"}, - {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"}, - {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"}, - {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"}, - {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"}, - {0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {3, "\xff\xff\xff"}, -}; - -static struct idxdata tbl_init_post_alt_low1[] = { - {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\x22\x2e"}, - {0x33, "\x90\x00\x81"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x17"}, - {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x1a"}, {0x33, "\x8c\xa4\x0a"}, - {0x33, "\x90\x00\x1d"}, {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x20"}, - {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\x81"}, {0x33, "\x8c\x24\x13"}, - {0x33, "\x90\x00\x9b"}, -}; - -static struct idxdata tbl_init_post_alt_low2[] = { - {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x03\x24"}, {0x33, "\x8c\x27\x05"}, - {0x33, "\x90\x02\x58"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {2, "\xff\xff\xff"}, -}; - -static struct idxdata tbl_init_post_alt_low3[] = { - {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, - {2, "\xff\xff\xff"}, - {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x20"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, - {0x33, "\x2e\x01\x00"}, {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x95"}, {0x33, "\x90\x01\x00"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, -}; - -static struct idxdata tbl_init_post_alt_big[] = { - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {2, "\xff\xff\xff"}, - {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, - {2, "\xff\xff\xff"}, - {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, {0x33, "\x8c\xa1\x20"}, - {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x30"}, {0x33, "\x90\x00\x03"}, - {0x33, "\x8c\xa1\x31"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x32"}, - {0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"}, - {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, - {0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"}, - {51, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, - {51, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, - {51, "\xff\xff\xff"}, -}; - -static struct idxdata tbl_init_post_alt_3B[] = { - {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, - {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, - {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, - {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, - {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, - {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, - {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, - {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, - {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, - {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, - {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, - {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, - {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, - {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, - {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, - {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, - {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, - {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, - {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, - {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, - {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, - {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, - {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, - {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, - {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, - {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, -}; - -static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81"; -static u8 *dat_800 = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21"; -static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01"; -static u8 *dat_1600 = "\xd0\x02\xd1\x20\xd2\xaf\xd3\x02\xd4\x30\xd5\x41"; - -static int mi2020_init_at_startup(struct gspca_dev *gspca_dev); -static int mi2020_configure_alt(struct gspca_dev *gspca_dev); -static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev); -static int mi2020_init_post_alt(struct gspca_dev *gspca_dev); -static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev); -static int mi2020_camera_settings(struct gspca_dev *gspca_dev); -/*==========================================================================*/ - -void mi2020_init_settings(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vcur.backlight = 0; - sd->vcur.brightness = 70; - sd->vcur.sharpness = 20; - sd->vcur.contrast = 0; - sd->vcur.gamma = 0; - sd->vcur.hue = 0; - sd->vcur.saturation = 60; - sd->vcur.whitebal = 0; /* 50, not done by hardware */ - sd->vcur.mirror = 0; - sd->vcur.flip = 0; - sd->vcur.AC50Hz = 1; - - sd->vmax.backlight = 64; - sd->vmax.brightness = 128; - sd->vmax.sharpness = 40; - sd->vmax.contrast = 3; - sd->vmax.gamma = 2; - sd->vmax.hue = 0 + 1; /* 200, not done by hardware */ - sd->vmax.saturation = 0; /* 100, not done by hardware */ - sd->vmax.whitebal = 2; /* 100, not done by hardware */ - sd->vmax.mirror = 1; - sd->vmax.flip = 1; - sd->vmax.AC50Hz = 1; - - sd->dev_camera_settings = mi2020_camera_settings; - sd->dev_init_at_startup = mi2020_init_at_startup; - sd->dev_configure_alt = mi2020_configure_alt; - sd->dev_init_pre_alt = mi2020_init_pre_alt; - sd->dev_post_unset_alt = mi2020_post_unset_alt; -} - -/*==========================================================================*/ - -static void common(struct gspca_dev *gspca_dev) -{ - fetch_validx(gspca_dev, tbl_common_0B, ARRAY_SIZE(tbl_common_0B)); - fetch_idxdata(gspca_dev, tbl_common_3B, ARRAY_SIZE(tbl_common_3B)); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); -} - -static int mi2020_init_at_startup(struct gspca_dev *gspca_dev) -{ - u8 c; - - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c); - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c); - - fetch_validx(gspca_dev, tbl_init_at_startup, - ARRAY_SIZE(tbl_init_at_startup)); - - ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL); - ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &c); - - common(gspca_dev); - - msleep(61); -/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */ -/* msleep(36); */ - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL); - - return 0; -} - -static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->mirrorMask = 0; - sd->vold.hue = -1; - - /* These controls need to be reset */ - sd->vold.brightness = -1; - sd->vold.sharpness = -1; - - /* If not different from default, they do not need to be set */ - sd->vold.contrast = 0; - sd->vold.gamma = 0; - sd->vold.backlight = 0; - - mi2020_init_post_alt(gspca_dev); - - return 0; -} - -static int mi2020_init_post_alt(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - - s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); - s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); - s32 freq = (sd->vcur.AC50Hz > 0); - s32 wbal = sd->vcur.whitebal; - - u8 dat_freq2[] = {0x90, 0x00, 0x80}; - u8 dat_multi1[] = {0x8c, 0xa7, 0x00}; - u8 dat_multi2[] = {0x90, 0x00, 0x00}; - u8 dat_multi3[] = {0x8c, 0xa7, 0x00}; - u8 dat_multi4[] = {0x90, 0x00, 0x00}; - u8 dat_hvflip2[] = {0x90, 0x04, 0x6c}; - u8 dat_hvflip4[] = {0x90, 0x00, 0x24}; - u8 dat_wbal2[] = {0x90, 0x00, 0x00}; - u8 c; - - sd->nbIm = -1; - - dat_freq2[2] = freq ? 0xc0 : 0x80; - dat_multi1[2] = 0x9d; - dat_multi3[2] = dat_multi1[2] + 1; - if (wbal == 0) { - dat_multi4[2] = dat_multi2[2] = 0; - dat_wbal2[2] = 0x17; - } else if (wbal == 1) { - dat_multi4[2] = dat_multi2[2] = 0; - dat_wbal2[2] = 0x35; - } else if (wbal == 2) { - dat_multi4[2] = dat_multi2[2] = 0x20; - dat_wbal2[2] = 0x17; - } - dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror); - dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror); - - msleep(200); - ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); - msleep(2); - - common(gspca_dev); - - msleep(142); - ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0003, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0042, 0x00c2, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL); - - switch (reso) { - case IMAGE_640: - case IMAGE_800: - if (reso != IMAGE_800) - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, - 12, dat_640); - else - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, - 12, dat_800); - - fetch_idxdata(gspca_dev, tbl_init_post_alt_low1, - ARRAY_SIZE(tbl_init_post_alt_low1)); - - if (reso == IMAGE_800) - fetch_idxdata(gspca_dev, tbl_init_post_alt_low2, - ARRAY_SIZE(tbl_init_post_alt_low2)); - - fetch_idxdata(gspca_dev, tbl_init_post_alt_low3, - ARRAY_SIZE(tbl_init_post_alt_low3)); - - ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); - msleep(120); - break; - - case IMAGE_1280: - case IMAGE_1600: - if (reso == IMAGE_1280) { - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, - 12, dat_1280); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, "\x8c\x27\x07"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, "\x90\x05\x04"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, "\x8c\x27\x09"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, "\x90\x04\x02"); - } else { - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, - 12, dat_1600); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, "\x8c\x27\x07"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, "\x90\x06\x40"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, "\x8c\x27\x09"); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, - 3, "\x90\x04\xb0"); - } - - fetch_idxdata(gspca_dev, tbl_init_post_alt_big, - ARRAY_SIZE(tbl_init_post_alt_big)); - - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); - msleep(1850); - } - - ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); - msleep(40); - - /* AC power frequency */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); - msleep(33); - /* light source */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); - msleep(7); - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c); - - fetch_idxdata(gspca_dev, tbl_init_post_alt_3B, - ARRAY_SIZE(tbl_init_post_alt_3B)); - - /* hvflip */ - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6); - msleep(250); - - if (reso == IMAGE_640 || reso == IMAGE_800) - fetch_idxdata(gspca_dev, tbl_middle_hvflip_low, - ARRAY_SIZE(tbl_middle_hvflip_low)); - else - fetch_idxdata(gspca_dev, tbl_middle_hvflip_big, - ARRAY_SIZE(tbl_middle_hvflip_big)); - - fetch_idxdata(gspca_dev, tbl_end_hvflip, - ARRAY_SIZE(tbl_end_hvflip)); - - sd->nbIm = 0; - - sd->vold.mirror = mirror; - sd->vold.flip = flip; - sd->vold.AC50Hz = freq; - sd->vold.whitebal = wbal; - - mi2020_camera_settings(gspca_dev); - - return 0; -} - -static int mi2020_configure_alt(struct gspca_dev *gspca_dev) -{ - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - - switch (reso) { - case IMAGE_640: - gspca_dev->alt = 3 + 1; - break; - - case IMAGE_800: - case IMAGE_1280: - case IMAGE_1600: - gspca_dev->alt = 1 + 1; - break; - } - return 0; -} - -static int mi2020_camera_settings(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - - s32 backlight = sd->vcur.backlight; - s32 bright = sd->vcur.brightness; - s32 sharp = sd->vcur.sharpness; - s32 cntr = sd->vcur.contrast; - s32 gam = sd->vcur.gamma; - s32 hue = (sd->vcur.hue > 0); - s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); - s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); - s32 freq = (sd->vcur.AC50Hz > 0); - s32 wbal = sd->vcur.whitebal; - - u8 dat_sharp[] = {0x6c, 0x00, 0x08}; - u8 dat_bright2[] = {0x90, 0x00, 0x00}; - u8 dat_freq2[] = {0x90, 0x00, 0x80}; - u8 dat_multi1[] = {0x8c, 0xa7, 0x00}; - u8 dat_multi2[] = {0x90, 0x00, 0x00}; - u8 dat_multi3[] = {0x8c, 0xa7, 0x00}; - u8 dat_multi4[] = {0x90, 0x00, 0x00}; - u8 dat_hvflip2[] = {0x90, 0x04, 0x6c}; - u8 dat_hvflip4[] = {0x90, 0x00, 0x24}; - u8 dat_wbal2[] = {0x90, 0x00, 0x00}; - - /* Less than 4 images received -> too early to set the settings */ - if (sd->nbIm < 4) { - sd->waitSet = 1; - return 0; - } - sd->waitSet = 0; - - if (freq != sd->vold.AC50Hz) { - sd->vold.AC50Hz = freq; - - dat_freq2[2] = freq ? 0xc0 : 0x80; - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); - msleep(20); - } - - if (wbal != sd->vold.whitebal) { - sd->vold.whitebal = wbal; - if (wbal < 0 || wbal > sd->vmax.whitebal) - wbal = 0; - - dat_multi1[2] = 0x9d; - dat_multi3[2] = dat_multi1[2] + 1; - if (wbal == 0) { - dat_multi4[2] = dat_multi2[2] = 0; - dat_wbal2[2] = 0x17; - } else if (wbal == 1) { - dat_multi4[2] = dat_multi2[2] = 0; - dat_wbal2[2] = 0x35; - } else if (wbal == 2) { - dat_multi4[2] = dat_multi2[2] = 0x20; - dat_wbal2[2] = 0x17; - } - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); - } - - if (mirror != sd->vold.mirror || flip != sd->vold.flip) { - sd->vold.mirror = mirror; - sd->vold.flip = flip; - - dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror); - dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror); - - fetch_idxdata(gspca_dev, tbl_init_post_alt_3B, - ARRAY_SIZE(tbl_init_post_alt_3B)); - - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6); - msleep(40); - - if (reso == IMAGE_640 || reso == IMAGE_800) - fetch_idxdata(gspca_dev, tbl_middle_hvflip_low, - ARRAY_SIZE(tbl_middle_hvflip_low)); - else - fetch_idxdata(gspca_dev, tbl_middle_hvflip_big, - ARRAY_SIZE(tbl_middle_hvflip_big)); - - fetch_idxdata(gspca_dev, tbl_end_hvflip, - ARRAY_SIZE(tbl_end_hvflip)); - } - - if (bright != sd->vold.brightness) { - sd->vold.brightness = bright; - if (bright < 0 || bright > sd->vmax.brightness) - bright = 0; - - dat_bright2[2] = bright; - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6); - } - - if (cntr != sd->vold.contrast || gam != sd->vold.gamma) { - sd->vold.contrast = cntr; - if (cntr < 0 || cntr > sd->vmax.contrast) - cntr = 0; - sd->vold.gamma = gam; - if (gam < 0 || gam > sd->vmax.gamma) - gam = 0; - - dat_multi1[2] = 0x6d; - dat_multi3[2] = dat_multi1[2] + 1; - if (cntr == 0) - cntr = 4; - dat_multi4[2] = dat_multi2[2] = cntr * 0x10 + 2 - gam; - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); - } - - if (backlight != sd->vold.backlight) { - sd->vold.backlight = backlight; - if (backlight < 0 || backlight > sd->vmax.backlight) - backlight = 0; - - dat_multi1[2] = 0x9d; - dat_multi3[2] = dat_multi1[2] + 1; - dat_multi4[2] = dat_multi2[2] = backlight; - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); - } - - if (sharp != sd->vold.sharpness) { - sd->vold.sharpness = sharp; - if (sharp < 0 || sharp > sd->vmax.sharpness) - sharp = 0; - - dat_sharp[1] = sharp; - ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0032, 3, dat_sharp); - } - - if (hue != sd->vold.hue) { - sd->swapRB = hue; - sd->vold.hue = hue; - } - - return 0; -} - -static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev) -{ - ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); - msleep(40); - ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-ov2640.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-ov2640.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-ov2640.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-ov2640.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,489 +0,0 @@ -/* Subdriver for the GL860 chip with the OV2640 sensor - * Author Olivier LORIN, from Malmostoso's logs - * - * 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, or - * any later version. - * - * 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, see . - */ - -/* Sensor : OV2640 */ - -#include "gl860.h" - -static u8 dat_init1[] = "\x00\x41\x07\x6a\x06\x61\x0d\x6a" "\x10\x10\xc1\x01"; - -static u8 c61[] = {0x61}; /* expected */ -static u8 c51[] = {0x51}; /* expected */ -static u8 c50[] = {0x50}; /* expected */ -static u8 c28[] = {0x28}; /* expected */ -static u8 ca8[] = {0xa8}; /* expected */ - -static u8 dat_post[] = - "\x00\x41\x07\x6a\x06\xef\x0d\x6a" "\x10\x10\xc1\x01"; - -static u8 dat_640[] = "\xd0\x01\xd1\x08\xd2\xe0\xd3\x02\xd4\x10\xd5\x81"; -static u8 dat_800[] = "\xd0\x01\xd1\x10\xd2\x58\xd3\x02\xd4\x18\xd5\x21"; -static u8 dat_1280[] = "\xd0\x01\xd1\x18\xd2\xc0\xd3\x02\xd4\x28\xd5\x01"; -static u8 dat_1600[] = "\xd0\x01\xd1\x20\xd2\xb0\xd3\x02\xd4\x30\xd5\x41"; - -static struct validx tbl_init_at_startup[] = { - {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1}, - {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d}, - {0x0050, 0x0000}, {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0061, 0x0006}, - {0x006a, 0x000d}, {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, - {0x0041, 0x00c2}, {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, - {0x0041, 0x0000}, {0x0061, 0x0000}, -}; - -static struct validx tbl_common[] = { - {0x6000, 0x00ff}, {0x60ff, 0x002c}, {0x60df, 0x002e}, {0x6001, 0x00ff}, - {0x6080, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010}, - {0x6035, 0x003c}, {0x6000, 0x0011}, {0x6028, 0x0004}, {0x60e5, 0x0013}, - {0x6088, 0x0014}, {0x600c, 0x002c}, {0x6078, 0x0033}, {0x60f7, 0x003b}, - {0x6000, 0x003e}, {0x6011, 0x0043}, {0x6010, 0x0016}, {0x6082, 0x0039}, - {0x6088, 0x0035}, {0x600a, 0x0022}, {0x6040, 0x0037}, {0x6000, 0x0023}, - {0x60a0, 0x0034}, {0x601a, 0x0036}, {0x6002, 0x0006}, {0x60c0, 0x0007}, - {0x60b7, 0x000d}, {0x6001, 0x000e}, {0x6000, 0x004c}, {0x6081, 0x004a}, - {0x6099, 0x0021}, {0x6002, 0x0009}, {0x603e, 0x0024}, {0x6034, 0x0025}, - {0x6081, 0x0026}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010}, - {0x6000, 0x005c}, {0x6000, 0x0063}, {0x6000, 0x007c}, {0x6070, 0x0061}, - {0x6080, 0x0062}, {0x6080, 0x0020}, {0x6030, 0x0028}, {0x6000, 0x006c}, - {0x6000, 0x006e}, {0x6002, 0x0070}, {0x6094, 0x0071}, {0x60c1, 0x0073}, - {0x6034, 0x003d}, {0x6057, 0x005a}, {0x60bb, 0x004f}, {0x609c, 0x0050}, - {0x6080, 0x006d}, {0x6002, 0x0039}, {0x6033, 0x003a}, {0x60f1, 0x003b}, - {0x6031, 0x003c}, {0x6000, 0x00ff}, {0x6014, 0x00e0}, {0x60ff, 0x0076}, - {0x60a0, 0x0033}, {0x6020, 0x0042}, {0x6018, 0x0043}, {0x6000, 0x004c}, - {0x60d0, 0x0087}, {0x600f, 0x0088}, {0x6003, 0x00d7}, {0x6010, 0x00d9}, - {0x6005, 0x00da}, {0x6082, 0x00d3}, {0x60c0, 0x00f9}, {0x6006, 0x0044}, - {0x6007, 0x00d1}, {0x6002, 0x00d2}, {0x6000, 0x00d2}, {0x6011, 0x00d8}, - {0x6008, 0x00c8}, {0x6080, 0x00c9}, {0x6008, 0x007c}, {0x6020, 0x007d}, - {0x6020, 0x007d}, {0x6000, 0x0090}, {0x600e, 0x0091}, {0x601a, 0x0091}, - {0x6031, 0x0091}, {0x605a, 0x0091}, {0x6069, 0x0091}, {0x6075, 0x0091}, - {0x607e, 0x0091}, {0x6088, 0x0091}, {0x608f, 0x0091}, {0x6096, 0x0091}, - {0x60a3, 0x0091}, {0x60af, 0x0091}, {0x60c4, 0x0091}, {0x60d7, 0x0091}, - {0x60e8, 0x0091}, {0x6020, 0x0091}, {0x6000, 0x0092}, {0x6006, 0x0093}, - {0x60e3, 0x0093}, {0x6005, 0x0093}, {0x6005, 0x0093}, {0x6000, 0x0093}, - {0x6004, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, - {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, - {0x6000, 0x0096}, {0x6008, 0x0097}, {0x6019, 0x0097}, {0x6002, 0x0097}, - {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097}, {0x6028, 0x0097}, - {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6098, 0x0097}, {0x6080, 0x0097}, - {0x6000, 0x0097}, {0x6000, 0x0097}, {0x60ed, 0x00c3}, {0x609a, 0x00c4}, - {0x6000, 0x00a4}, {0x6011, 0x00c5}, {0x6051, 0x00c6}, {0x6010, 0x00c7}, - {0x6066, 0x00b6}, {0x60a5, 0x00b8}, {0x6064, 0x00b7}, {0x607c, 0x00b9}, - {0x60af, 0x00b3}, {0x6097, 0x00b4}, {0x60ff, 0x00b5}, {0x60c5, 0x00b0}, - {0x6094, 0x00b1}, {0x600f, 0x00b2}, {0x605c, 0x00c4}, {0x6000, 0x00a8}, - {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x601d, 0x0086}, {0x6000, 0x0050}, - {0x6090, 0x0051}, {0x6018, 0x0052}, {0x6000, 0x0053}, {0x6000, 0x0054}, - {0x6088, 0x0055}, {0x6000, 0x0057}, {0x6090, 0x005a}, {0x6018, 0x005b}, - {0x6005, 0x005c}, {0x60ed, 0x00c3}, {0x6000, 0x007f}, {0x6005, 0x00da}, - {0x601f, 0x00e5}, {0x6067, 0x00e1}, {0x6000, 0x00e0}, {0x60ff, 0x00dd}, - {0x6000, 0x0005}, {0x6001, 0x00ff}, {0x6000, 0x0000}, {0x6000, 0x0045}, - {0x6000, 0x0010}, -}; - -static struct validx tbl_sensor_settings_common1[] = { - {0x0041, 0x0000}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d}, - {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2}, - {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0041, 0x0000}, - {50, 0xffff}, - {0x0061, 0x0000}, - {0xffff, 0xffff}, - {0x6000, 0x00ff}, {0x6000, 0x007c}, {0x6007, 0x007d}, - {30, 0xffff}, - {0x0040, 0x0000}, -}; - -static struct validx tbl_sensor_settings_common2[] = { - {0x6001, 0x00ff}, {0x6038, 0x000c}, - {10, 0xffff}, - {0x6000, 0x0011}, -}; - -static struct validx tbl_640[] = { - {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1}, - {0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, - {0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017}, - {0x6075, 0x0018}, {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032}, - {0x60bb, 0x004f}, {0x6057, 0x005a}, {0x609c, 0x0050}, {0x6080, 0x006d}, - {0x6092, 0x0026}, {0x60ff, 0x0020}, {0x6000, 0x0027}, {0x6000, 0x00ff}, - {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c}, {0x603d, 0x0086}, - {0x6089, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052}, {0x6000, 0x0053}, - {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057}, {0x60a0, 0x005a}, - {0x6078, 0x005b}, {0x6000, 0x005c}, {0x6004, 0x00d3}, {0x6000, 0x00e0}, - {0x60ff, 0x00dd}, {0x60a1, 0x005a}, -}; - -static struct validx tbl_800[] = { - {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1}, - {0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, - {0x6001, 0x00ff}, {0x6040, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017}, - {0x6043, 0x0018}, {0x6000, 0x0019}, {0x604b, 0x001a}, {0x6009, 0x0032}, - {0x60ca, 0x004f}, {0x60a8, 0x0050}, {0x6000, 0x006d}, {0x6038, 0x003d}, - {0x60c8, 0x0035}, {0x6000, 0x0022}, {0x6092, 0x0026}, {0x60ff, 0x0020}, - {0x6000, 0x0027}, {0x6000, 0x00ff}, {0x6064, 0x00c0}, {0x604b, 0x00c1}, - {0x6000, 0x008c}, {0x601d, 0x0086}, {0x6082, 0x00d3}, {0x6000, 0x00e0}, - {0x60ff, 0x00dd}, {0x6020, 0x008c}, {0x6001, 0x00ff}, {0x6044, 0x0018}, -}; - -static struct validx tbl_big1[] = { - {0x0002, 0x00c1}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, - {0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045}, - {0x6000, 0x0010}, {0x6000, 0x0011}, {0x6011, 0x0017}, {0x6075, 0x0018}, - {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032}, {0x60bb, 0x004f}, - {0x609c, 0x0050}, {0x6057, 0x005a}, {0x6080, 0x006d}, {0x6043, 0x000f}, - {0x608f, 0x0003}, {0x6005, 0x007c}, {0x6081, 0x0026}, {0x6000, 0x00ff}, - {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c}, -}; - -static struct validx tbl_big2[] = { - {0x603d, 0x0086}, {0x6000, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052}, - {0x6000, 0x0053}, {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057}, - {0x6040, 0x005a}, {0x60f0, 0x005b}, {0x6001, 0x005c}, {0x6082, 0x00d3}, - {0x6000, 0x008e}, -}; - -static struct validx tbl_big3[] = { - {0x6004, 0x00da}, {0x6000, 0x00e0}, {0x6067, 0x00e1}, {0x60ff, 0x00dd}, - {0x6001, 0x00ff}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, - {0x6001, 0x00ff}, {0x6000, 0x0011}, {0x6000, 0x00ff}, {0x6010, 0x00c7}, - {0x6000, 0x0092}, {0x6006, 0x0093}, {0x60e3, 0x0093}, {0x6005, 0x0093}, - {0x6005, 0x0093}, {0x60ed, 0x00c3}, {0x6000, 0x00a4}, {0x60d0, 0x0087}, - {0x6003, 0x0096}, {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097}, - {0x6028, 0x0097}, {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6001, 0x00ff}, - {0x6043, 0x000f}, {0x608f, 0x0003}, {0x6000, 0x002d}, {0x6000, 0x002e}, - {0x600a, 0x0022}, {0x6002, 0x0070}, {0x6008, 0x0014}, {0x6048, 0x0014}, - {0x6000, 0x00ff}, {0x6000, 0x00e0}, {0x60ff, 0x00dd}, -}; - -static struct validx tbl_post_unset_alt[] = { - {0x006a, 0x000d}, {0x6001, 0x00ff}, {0x6081, 0x0026}, {0x6000, 0x0000}, - {0x6000, 0x0045}, {0x6000, 0x0010}, {0x6068, 0x000d}, - {50, 0xffff}, - {0x0021, 0x0000}, -}; - -static int ov2640_init_at_startup(struct gspca_dev *gspca_dev); -static int ov2640_configure_alt(struct gspca_dev *gspca_dev); -static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev); -static int ov2640_init_post_alt(struct gspca_dev *gspca_dev); -static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev); -static int ov2640_camera_settings(struct gspca_dev *gspca_dev); -/*==========================================================================*/ - -void ov2640_init_settings(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vcur.backlight = 32; - sd->vcur.brightness = 0; - sd->vcur.sharpness = 6; - sd->vcur.contrast = 0; - sd->vcur.gamma = 32; - sd->vcur.hue = 0; - sd->vcur.saturation = 128; - sd->vcur.whitebal = 64; - sd->vcur.mirror = 0; - sd->vcur.flip = 0; - - sd->vmax.backlight = 64; - sd->vmax.brightness = 255; - sd->vmax.sharpness = 31; - sd->vmax.contrast = 255; - sd->vmax.gamma = 64; - sd->vmax.hue = 254 + 2; - sd->vmax.saturation = 255; - sd->vmax.whitebal = 128; - sd->vmax.mirror = 1; - sd->vmax.flip = 1; - sd->vmax.AC50Hz = 0; - - sd->dev_camera_settings = ov2640_camera_settings; - sd->dev_init_at_startup = ov2640_init_at_startup; - sd->dev_configure_alt = ov2640_configure_alt; - sd->dev_init_pre_alt = ov2640_init_pre_alt; - sd->dev_post_unset_alt = ov2640_post_unset_alt; -} - -/*==========================================================================*/ - -static void common(struct gspca_dev *gspca_dev) -{ - fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common)); -} - -static int ov2640_init_at_startup(struct gspca_dev *gspca_dev) -{ - fetch_validx(gspca_dev, tbl_init_at_startup, - ARRAY_SIZE(tbl_init_at_startup)); - - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_init1); - - common(gspca_dev); - - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0006, 1, c61); - - ctrl_out(gspca_dev, 0x40, 1, 0x00ef, 0x0006, 0, NULL); - - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c51); - - ctrl_out(gspca_dev, 0x40, 1, 0x0051, 0x0000, 0, NULL); -/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */ - - return 0; -} - -static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->mirrorMask = 0; - - sd->vold.backlight = -1; - sd->vold.brightness = -1; - sd->vold.sharpness = -1; - sd->vold.contrast = -1; - sd->vold.saturation = -1; - sd->vold.gamma = -1; - sd->vold.hue = -1; - sd->vold.whitebal = -1; - sd->vold.mirror = -1; - sd->vold.flip = -1; - - ov2640_init_post_alt(gspca_dev); - - return 0; -} - -static int ov2640_init_post_alt(struct gspca_dev *gspca_dev) -{ - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - s32 n; /* reserved for FETCH functions */ - - ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); - - n = fetch_validx(gspca_dev, tbl_sensor_settings_common1, - ARRAY_SIZE(tbl_sensor_settings_common1)); - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_post); - common(gspca_dev); - keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common1, - ARRAY_SIZE(tbl_sensor_settings_common1), n); - - switch (reso) { - case IMAGE_640: - n = fetch_validx(gspca_dev, tbl_640, ARRAY_SIZE(tbl_640)); - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_640); - break; - - case IMAGE_800: - n = fetch_validx(gspca_dev, tbl_800, ARRAY_SIZE(tbl_800)); - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_800); - break; - - case IMAGE_1600: - case IMAGE_1280: - n = fetch_validx(gspca_dev, tbl_big1, ARRAY_SIZE(tbl_big1)); - - if (reso == IMAGE_1280) { - n = fetch_validx(gspca_dev, tbl_big2, - ARRAY_SIZE(tbl_big2)); - } else { - ctrl_out(gspca_dev, 0x40, 1, 0x601d, 0x0086, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00d7, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6082, 0x00d3, 0, NULL); - } - - n = fetch_validx(gspca_dev, tbl_big3, ARRAY_SIZE(tbl_big3)); - - if (reso == IMAGE_1280) { - ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, - 12, dat_1280); - } else { - ctrl_out(gspca_dev, 0x40, 1, 0x6020, 0x008c, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6076, 0x0018, 0, NULL); - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, - 12, dat_1600); - } - break; - } - - n = fetch_validx(gspca_dev, tbl_sensor_settings_common2, - ARRAY_SIZE(tbl_sensor_settings_common2)); - - ov2640_camera_settings(gspca_dev); - - return 0; -} - -static int ov2640_configure_alt(struct gspca_dev *gspca_dev) -{ - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - - switch (reso) { - case IMAGE_640: - gspca_dev->alt = 3 + 1; - break; - - case IMAGE_800: - case IMAGE_1280: - case IMAGE_1600: - gspca_dev->alt = 1 + 1; - break; - } - return 0; -} - -static int ov2640_camera_settings(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - s32 backlight = sd->vcur.backlight; - s32 bright = sd->vcur.brightness; - s32 sharp = sd->vcur.sharpness; - s32 gam = sd->vcur.gamma; - s32 cntr = sd->vcur.contrast; - s32 sat = sd->vcur.saturation; - s32 hue = sd->vcur.hue; - s32 wbal = sd->vcur.whitebal; - s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) == 0); - s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) == 0); - - if (backlight != sd->vold.backlight) { - /* No sd->vold.backlight=backlight; (to be done again later) */ - if (backlight < 0 || backlight > sd->vmax.backlight) - backlight = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x00ff, - 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight , 0x0024, - 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025, - 0, NULL); - } - - if (bright != sd->vold.brightness) { - sd->vold.brightness = bright; - if (bright < 0 || bright > sd->vmax.brightness) - bright = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6009 , 0x007c, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6000 + bright, 0x007d, 0, NULL); - } - - if (wbal != sd->vold.whitebal) { - sd->vold.whitebal = wbal; - if (wbal < 0 || wbal > sd->vmax.whitebal) - wbal = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6003 , 0x007c, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6000 + wbal, 0x007d, 0, NULL); - } - - if (cntr != sd->vold.contrast) { - sd->vold.contrast = cntr; - if (cntr < 0 || cntr > sd->vmax.contrast) - cntr = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6007 , 0x007c, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6000 + cntr, 0x007d, 0, NULL); - } - - if (sat != sd->vold.saturation) { - sd->vold.saturation = sat; - if (sat < 0 || sat > sd->vmax.saturation) - sat = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x007c, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6000 + sat, 0x007d, 0, NULL); - } - - if (sharp != sd->vold.sharpness) { - sd->vold.sharpness = sharp; - if (sharp < 0 || sharp > sd->vmax.sharpness) - sharp = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x0092, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x60c0 + sharp, 0x0093, 0, NULL); - } - - if (hue != sd->vold.hue) { - sd->vold.hue = hue; - if (hue < 0 || hue > sd->vmax.hue) - hue = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6002 , 0x007c, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6000 + hue * (hue < 255), 0x007d, - 0, NULL); - if (hue >= 255) - sd->swapRB = 1; - else - sd->swapRB = 0; - } - - if (gam != sd->vold.gamma) { - sd->vold.gamma = gam; - if (gam < 0 || gam > sd->vmax.gamma) - gam = 0; - - ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6008 , 0x007c, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6000 + gam, 0x007d, 0, NULL); - } - - if (mirror != sd->vold.mirror || flip != sd->vold.flip) { - sd->vold.mirror = mirror; - sd->vold.flip = flip; - - mirror = 0x80 * mirror; - ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL); - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, c28); - ctrl_out(gspca_dev, 0x40, 1, 0x6028 + mirror, 0x0004, 0, NULL); - - flip = 0x50 * flip + mirror; - ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL); - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, ca8); - ctrl_out(gspca_dev, 0x40, 1, 0x6028 + flip, 0x0004, 0, NULL); - - ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50); - } - - if (backlight != sd->vold.backlight) { - sd->vold.backlight = backlight; - - ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x00ff, - 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight , 0x0024, - 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025, - 0, NULL); - } - - return 0; -} - -static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev) -{ - ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); - msleep(20); - fetch_validx(gspca_dev, tbl_post_unset_alt, - ARRAY_SIZE(tbl_post_unset_alt)); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-ov9655.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-ov9655.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-ov9655.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/gl860-ov9655.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,336 +0,0 @@ -/* Subdriver for the GL860 chip with the OV9655 sensor - * Author Olivier LORIN, from logs done by Simon (Sur3) and Almighurt - * on dsd's weblog - * - * 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, or - * any later version. - * - * 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, see . - */ - -/* Sensor : OV9655 */ - -#include "gl860.h" - -static struct validx tbl_init_at_startup[] = { - {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1}, - {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d}, - - {0x0040, 0x0000}, -}; - -static struct validx tbl_commmon[] = { - {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, - {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2}, - {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0040, 0x0000}, - {0x00f3, 0x0006}, {0x0058, 0x0000}, {0x0048, 0x0000}, {0x0061, 0x0000}, -}; - -static s32 tbl_length[] = {12, 56, 52, 54, 56, 42, 32, 12}; - -static u8 *tbl_640[] = { - "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01" - , - "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x03\x0b\x57\x0e\x61" - "\x0f\x42\x11\x01\x12\x60\x13\x00" "\x14\x3a\x16\x24\x17\x14\x18\x00" - "\x19\x01\x1a\x3d\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08" - "\x29\x15\x2a\x00\x2b\x00\x2c\x08" - , - "\x32\xff\x33\x00\x34\x3d\x35\x00" "\x36\xfa\x38\x72\x39\x57\x3a\x00" - "\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc1" "\x40\xc0\x41\x00\x42\xc0\x43\x0a" - "\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xee\x4b\xe7\x4c\xe7" - "\x4d\xe7\x4e\xe7" - , - "\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85" - "\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0" - "\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x0a\x6b\x5a\x6c\x04" - "\x6d\x55\x6e\x00\x6f\x9d" - , - "\x70\x15\x71\x78\x72\x00\x73\x00" "\x74\x3a\x75\x35\x76\x01\x77\x02" - "\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52" - "\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5" - "\x8a\x23\x8c\x8d\x90\x7c\x91\x7b" - , - "\x9d\x02\x9e\x02\x9f\x74\xa0\x73" "\xa1\x40\xa4\x50\xa5\x68\xa6\x70" - "\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80" - "\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf" - , - "\xbb\xae\xbc\x4f\xbd\x4e\xbe\x6a" "\xbf\x68\xc0\xaa\xc1\xc0\xc2\x01" - "\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93" - , - "\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80" -}; - -static u8 *tbl_1280[] = { - "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01" - , - "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61" - "\x0f\x42\x11\x00\x12\x00\x13\x00" "\x14\x3a\x16\x24\x17\x1b\x18\xbb" - "\x19\x01\x1a\x81\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08" - "\x29\x15\x2a\x00\x2b\x00\x2c\x08" - , - "\x32\xa4\x33\x00\x34\x3d\x35\x00" "\x36\xf8\x38\x72\x39\x57\x3a\x00" - "\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc2" "\x40\xc0\x41\x00\x42\xc0\x43\x0a" - "\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xec\x4b\xe8\x4c\xe8" - "\x4d\xe8\x4e\xe8" - , - "\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85" - "\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0" - "\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x02\x6b\x5a\x6c\x04" - "\x6d\x55\x6e\x00\x6f\x9d" - , - "\x70\x08\x71\x78\x72\x00\x73\x01" "\x74\x3a\x75\x35\x76\x01\x77\x02" - "\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52" - "\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5" - "\x8a\x23\x8c\x0d\x90\x90\x91\x90" - , - "\x9d\x02\x9e\x02\x9f\x94\xa0\x94" "\xa1\x01\xa4\x50\xa5\x68\xa6\x70" - "\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80" - "\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf" - , - "\xbb\xae\xbc\x38\xbd\x39\xbe\x01" "\xbf\x01\xc0\xe2\xc1\xc0\xc2\x01" - "\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93" - , - "\xd0\x21\xd1\x18\xd2\xe0\xd3\x01" "\xd4\x28\xd5\x00" -}; - -static u8 c04[] = {0x04}; -static u8 dat_post1[] = "\x04\x00\x10\x20\xa1\x00\x00\x02"; -static u8 dat_post2[] = "\x10\x10\xc1\x02"; -static u8 dat_post3[] = "\x04\x00\x10\x7c\xa1\x00\x00\x04"; -static u8 dat_post4[] = "\x10\x02\xc1\x06"; -static u8 dat_post5[] = "\x04\x00\x10\x7b\xa1\x00\x00\x08"; -static u8 dat_post6[] = "\x10\x10\xc1\x05"; -static u8 dat_post7[] = "\x04\x00\x10\x7c\xa1\x00\x00\x08"; -static u8 dat_post8[] = "\x04\x00\x10\x7c\xa1\x00\x00\x09"; - -static struct validx tbl_init_post_alt[] = { - {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x603c, 0x00ff}, - {0x6003, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6001, 0x00ff}, - {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6012, 0x0003}, - {0xffff, 0xffff}, - {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6012, 0x0003}, - {0xffff, 0xffff}, - {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6000, 0x801e}, - {0xffff, 0xffff}, - {0x6004, 0x001e}, {0x6012, 0x0003}, -}; - -static int ov9655_init_at_startup(struct gspca_dev *gspca_dev); -static int ov9655_configure_alt(struct gspca_dev *gspca_dev); -static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev); -static int ov9655_init_post_alt(struct gspca_dev *gspca_dev); -static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev); -static int ov9655_camera_settings(struct gspca_dev *gspca_dev); -/*==========================================================================*/ - -void ov9655_init_settings(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vcur.backlight = 0; - sd->vcur.brightness = 128; - sd->vcur.sharpness = 0; - sd->vcur.contrast = 0; - sd->vcur.gamma = 0; - sd->vcur.hue = 0; - sd->vcur.saturation = 0; - sd->vcur.whitebal = 0; - - sd->vmax.backlight = 0; - sd->vmax.brightness = 255; - sd->vmax.sharpness = 0; - sd->vmax.contrast = 0; - sd->vmax.gamma = 0; - sd->vmax.hue = 0 + 1; - sd->vmax.saturation = 0; - sd->vmax.whitebal = 0; - sd->vmax.mirror = 0; - sd->vmax.flip = 0; - sd->vmax.AC50Hz = 0; - - sd->dev_camera_settings = ov9655_camera_settings; - sd->dev_init_at_startup = ov9655_init_at_startup; - sd->dev_configure_alt = ov9655_configure_alt; - sd->dev_init_pre_alt = ov9655_init_pre_alt; - sd->dev_post_unset_alt = ov9655_post_unset_alt; -} - -/*==========================================================================*/ - -static int ov9655_init_at_startup(struct gspca_dev *gspca_dev) -{ - fetch_validx(gspca_dev, tbl_init_at_startup, - ARRAY_SIZE(tbl_init_at_startup)); - fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon)); -/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL);*/ - - return 0; -} - -static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vold.brightness = -1; - sd->vold.hue = -1; - - fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon)); - - ov9655_init_post_alt(gspca_dev); - - return 0; -} - -static int ov9655_init_post_alt(struct gspca_dev *gspca_dev) -{ - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - s32 n; /* reserved for FETCH functions */ - s32 i; - u8 **tbl; - - ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); - - tbl = (reso == IMAGE_640) ? tbl_640 : tbl_1280; - - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, - tbl_length[0], tbl[0]); - for (i = 1; i < 7; i++) - ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, - tbl_length[i], tbl[i]); - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, - tbl_length[7], tbl[7]); - - n = fetch_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt)); - - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); - keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, - ARRAY_SIZE(tbl_init_post_alt), n); - - ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1); - - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post2); - ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post3); - - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post4); - ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post5); - - ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post6); - ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post7); - - ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post8); - - ov9655_camera_settings(gspca_dev); - - return 0; -} - -static int ov9655_configure_alt(struct gspca_dev *gspca_dev) -{ - s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; - - switch (reso) { - case IMAGE_640: - gspca_dev->alt = 1 + 1; - break; - - default: - gspca_dev->alt = 1 + 1; - break; - } - return 0; -} - -static int ov9655_camera_settings(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - u8 dat_bright[] = "\x04\x00\x10\x7c\xa1\x00\x00\x70"; - - s32 bright = sd->vcur.brightness; - s32 hue = sd->vcur.hue; - - if (bright != sd->vold.brightness) { - sd->vold.brightness = bright; - if (bright < 0 || bright > sd->vmax.brightness) - bright = 0; - - dat_bright[3] = bright; - ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_bright); - } - - if (hue != sd->vold.hue) { - sd->vold.hue = hue; - sd->swapRB = (hue != 0); - } - - return 0; -} - -static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev) -{ - ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); - ctrl_out(gspca_dev, 0x40, 1, 0x0061, 0x0000, 0, NULL); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -config USB_GL860 - tristate "GL860 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the GL860 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_gl860. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gl860/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -obj-$(CONFIG_USB_GL860) += gspca_gl860.o - -gspca_gl860-objs := gl860.o \ - gl860-mi1320.o \ - gl860-ov2640.o \ - gl860-ov9655.o \ - gl860-mi2020.o - -EXTRA_CFLAGS += -Idrivers/media/video/gspca - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gspca.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gspca.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gspca.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gspca.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2500 +0,0 @@ -/* - * Main USB camera driver - * - * Copyright (C) 2008-2011 Jean-François Moine - * - * Camera button input handling by Márton Németh - * Copyright (C) 2009-2010 Márton Németh - * - * 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, or (at your - * option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define MODULE_NAME "gspca" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gspca.h" - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -#include -#include -#endif - -/* global values */ -#define DEF_NURBS 3 /* default number of URBs */ -#if DEF_NURBS > MAX_NURBS -#error "DEF_NURBS too big" -#endif - -MODULE_AUTHOR("Jean-François Moine "); -MODULE_DESCRIPTION("GSPCA USB Camera Driver"); -MODULE_LICENSE("GPL"); - -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 12, 0) - -#ifdef GSPCA_DEBUG -int gspca_debug = D_ERR | D_PROBE; -EXPORT_SYMBOL(gspca_debug); - -static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h) -{ - if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') { - PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d", - txt, - pixfmt & 0xff, - (pixfmt >> 8) & 0xff, - (pixfmt >> 16) & 0xff, - pixfmt >> 24, - w, h); - } else { - PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d", - txt, - pixfmt, - w, h); - } -} -#else -#define PDEBUG_MODE(txt, pixfmt, w, h) -#endif - -/* specific memory types - !! should be different from V4L2_MEMORY_xxx */ -#define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */ -#define GSPCA_MEMORY_READ 7 - -#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE) - -/* - * VMA operations. - */ -static void gspca_vm_open(struct vm_area_struct *vma) -{ - struct gspca_frame *frame = vma->vm_private_data; - - frame->vma_use_count++; - frame->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED; -} - -static void gspca_vm_close(struct vm_area_struct *vma) -{ - struct gspca_frame *frame = vma->vm_private_data; - - if (--frame->vma_use_count <= 0) - frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_MAPPED; -} - -static const struct vm_operations_struct gspca_vm_ops = { - .open = gspca_vm_open, - .close = gspca_vm_close, -}; - -/* - * Input and interrupt endpoint handling functions - */ -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static void int_irq(struct urb *urb) -{ - struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; - int ret; - - ret = urb->status; - switch (ret) { - case 0: - if (gspca_dev->sd_desc->int_pkt_scan(gspca_dev, - urb->transfer_buffer, urb->actual_length) < 0) { - PDEBUG(D_ERR, "Unknown packet received"); - } - break; - - case -ENOENT: - case -ECONNRESET: - case -ENODEV: - case -ESHUTDOWN: - /* Stop is requested either by software or hardware is gone, - * keep the ret value non-zero and don't resubmit later. - */ - break; - - default: - PDEBUG(D_ERR, "URB error %i, resubmitting", urb->status); - urb->status = 0; - ret = 0; - } - - if (ret == 0) { - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) - err("Resubmit URB failed with error %i", ret); - } -} - -static int gspca_input_connect(struct gspca_dev *dev) -{ - struct input_dev *input_dev; - int err = 0; - - dev->input_dev = NULL; - if (dev->sd_desc->int_pkt_scan || dev->sd_desc->other_input) { - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - usb_make_path(dev->dev, dev->phys, sizeof(dev->phys)); - strlcat(dev->phys, "/input0", sizeof(dev->phys)); - - input_dev->name = dev->sd_desc->name; - input_dev->phys = dev->phys; - - usb_to_input_id(dev->dev, &input_dev->id); - - input_dev->evbit[0] = BIT_MASK(EV_KEY); - input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA); - input_dev->dev.parent = &dev->dev->dev; - - err = input_register_device(input_dev); - if (err) { - err("Input device registration failed with error %i", - err); - input_dev->dev.parent = NULL; - input_free_device(input_dev); - } else { - dev->input_dev = input_dev; - } - } - - return err; -} - -static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev, - struct usb_endpoint_descriptor *ep) -{ - unsigned int buffer_len; - int interval; - struct urb *urb; - struct usb_device *dev; - void *buffer = NULL; - int ret = -EINVAL; - - buffer_len = le16_to_cpu(ep->wMaxPacketSize); - interval = ep->bInterval; - PDEBUG(D_CONF, "found int in endpoint: 0x%x, " - "buffer_len=%u, interval=%u", - ep->bEndpointAddress, buffer_len, interval); - - dev = gspca_dev->dev; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - ret = -ENOMEM; - goto error; - } - - buffer = usb_alloc_coherent(dev, buffer_len, - GFP_KERNEL, &urb->transfer_dma); - if (!buffer) { - ret = -ENOMEM; - goto error_buffer; - } - usb_fill_int_urb(urb, dev, - usb_rcvintpipe(dev, ep->bEndpointAddress), - buffer, buffer_len, - int_irq, (void *)gspca_dev, interval); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - ret = usb_submit_urb(urb, GFP_KERNEL); - if (ret < 0) { - PDEBUG(D_ERR, "submit int URB failed with error %i", ret); - goto error_submit; - } - gspca_dev->int_urb = urb; - return ret; - -error_submit: - usb_free_coherent(dev, - urb->transfer_buffer_length, - urb->transfer_buffer, - urb->transfer_dma); -error_buffer: - usb_free_urb(urb); -error: - return ret; -} - -static void gspca_input_create_urb(struct gspca_dev *gspca_dev) -{ - struct usb_interface *intf; - struct usb_host_interface *intf_desc; - struct usb_endpoint_descriptor *ep; - int i; - - if (gspca_dev->sd_desc->int_pkt_scan) { - intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); - intf_desc = intf->cur_altsetting; - for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { - ep = &intf_desc->endpoint[i].desc; - if (usb_endpoint_dir_in(ep) && - usb_endpoint_xfer_int(ep)) { - - alloc_and_submit_int_urb(gspca_dev, ep); - break; - } - } - } -} - -static void gspca_input_destroy_urb(struct gspca_dev *gspca_dev) -{ - struct urb *urb; - - urb = gspca_dev->int_urb; - if (urb) { - gspca_dev->int_urb = NULL; - usb_kill_urb(urb); - usb_free_coherent(gspca_dev->dev, - urb->transfer_buffer_length, - urb->transfer_buffer, - urb->transfer_dma); - usb_free_urb(urb); - } -} -#else -static inline void gspca_input_destroy_urb(struct gspca_dev *gspca_dev) -{ -} - -static inline void gspca_input_create_urb(struct gspca_dev *gspca_dev) -{ -} - -static inline int gspca_input_connect(struct gspca_dev *dev) -{ - return 0; -} -#endif - -/* - * fill a video frame from an URB and resubmit - */ -static void fill_frame(struct gspca_dev *gspca_dev, - struct urb *urb) -{ - u8 *data; /* address of data in the iso message */ - int i, len, st; - cam_pkt_op pkt_scan; - - if (urb->status != 0) { - if (urb->status == -ESHUTDOWN) - return; /* disconnection */ -#ifdef CONFIG_PM - if (gspca_dev->frozen) - return; -#endif - PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); - urb->status = 0; - goto resubmit; - } - pkt_scan = gspca_dev->sd_desc->pkt_scan; - for (i = 0; i < urb->number_of_packets; i++) { - len = urb->iso_frame_desc[i].actual_length; - - /* check the packet status and length */ - st = urb->iso_frame_desc[i].status; - if (st) { - err("ISOC data error: [%d] len=%d, status=%d", - i, len, st); - gspca_dev->last_packet_type = DISCARD_PACKET; - continue; - } - if (len == 0) { - if (gspca_dev->empty_packet == 0) - gspca_dev->empty_packet = 1; - continue; - } - - /* let the packet be analyzed by the subdriver */ - PDEBUG(D_PACK, "packet [%d] o:%d l:%d", - i, urb->iso_frame_desc[i].offset, len); - data = (u8 *) urb->transfer_buffer - + urb->iso_frame_desc[i].offset; - pkt_scan(gspca_dev, data, len); - } - -resubmit: - /* resubmit the URB */ - st = usb_submit_urb(urb, GFP_ATOMIC); - if (st < 0) - err("usb_submit_urb() ret %d", st); -} - -/* - * ISOC message interrupt from the USB device - * - * Analyse each packet and call the subdriver for copy to the frame buffer. - */ -static void isoc_irq(struct urb *urb) -{ - struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; - - PDEBUG(D_PACK, "isoc irq"); - if (!gspca_dev->streaming) - return; - fill_frame(gspca_dev, urb); -} - -/* - * bulk message interrupt from the USB device - */ -static void bulk_irq(struct urb *urb) -{ - struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; - int st; - - PDEBUG(D_PACK, "bulk irq"); - if (!gspca_dev->streaming) - return; - switch (urb->status) { - case 0: - break; - case -ESHUTDOWN: - return; /* disconnection */ - default: -#ifdef CONFIG_PM - if (gspca_dev->frozen) - return; -#endif - PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); - urb->status = 0; - goto resubmit; - } - - PDEBUG(D_PACK, "packet l:%d", urb->actual_length); - gspca_dev->sd_desc->pkt_scan(gspca_dev, - urb->transfer_buffer, - urb->actual_length); - -resubmit: - /* resubmit the URB */ - if (gspca_dev->cam.bulk_nurbs != 0) { - st = usb_submit_urb(urb, GFP_ATOMIC); - if (st < 0) - err("usb_submit_urb() ret %d", st); - } -} - -/* - * add data to the current frame - * - * This function is called by the subdrivers at interrupt level. - * - * To build a frame, these ones must add - * - one FIRST_PACKET - * - 0 or many INTER_PACKETs - * - one LAST_PACKET - * DISCARD_PACKET invalidates the whole frame. - */ -void gspca_frame_add(struct gspca_dev *gspca_dev, - enum gspca_packet_type packet_type, - const u8 *data, - int len) -{ - struct gspca_frame *frame; - int i, j; - - PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len); - - if (packet_type == FIRST_PACKET) { - i = atomic_read(&gspca_dev->fr_i); - - /* if there are no queued buffer, discard the whole frame */ - if (i == atomic_read(&gspca_dev->fr_q)) { - gspca_dev->last_packet_type = DISCARD_PACKET; - gspca_dev->sequence++; - return; - } - j = gspca_dev->fr_queue[i]; - frame = &gspca_dev->frame[j]; - frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get()); - frame->v4l2_buf.sequence = gspca_dev->sequence++; - gspca_dev->image = frame->data; - gspca_dev->image_len = 0; - } else { - switch (gspca_dev->last_packet_type) { - case DISCARD_PACKET: - if (packet_type == LAST_PACKET) - gspca_dev->last_packet_type = packet_type; - return; - case LAST_PACKET: - return; - } - } - - /* append the packet to the frame buffer */ - if (len > 0) { - if (gspca_dev->image_len + len > gspca_dev->frsz) { - PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d", - gspca_dev->image_len + len, - gspca_dev->frsz); - packet_type = DISCARD_PACKET; - } else { -/* !! image is NULL only when last pkt is LAST or DISCARD - if (gspca_dev->image == NULL) { - err("gspca_frame_add() image == NULL"); - return; - } - */ - memcpy(gspca_dev->image + gspca_dev->image_len, - data, len); - gspca_dev->image_len += len; - } - } - gspca_dev->last_packet_type = packet_type; - - /* if last packet, invalidate packet concatenation until - * next first packet, wake up the application and advance - * in the queue */ - if (packet_type == LAST_PACKET) { - i = atomic_read(&gspca_dev->fr_i); - j = gspca_dev->fr_queue[i]; - frame = &gspca_dev->frame[j]; - frame->v4l2_buf.bytesused = gspca_dev->image_len; - frame->v4l2_buf.flags = (frame->v4l2_buf.flags - | V4L2_BUF_FLAG_DONE) - & ~V4L2_BUF_FLAG_QUEUED; - i = (i + 1) % GSPCA_MAX_FRAMES; - atomic_set(&gspca_dev->fr_i, i); - wake_up_interruptible(&gspca_dev->wq); /* event = new frame */ - PDEBUG(D_FRAM, "frame complete len:%d", - frame->v4l2_buf.bytesused); - gspca_dev->image = NULL; - gspca_dev->image_len = 0; - } -} -EXPORT_SYMBOL(gspca_frame_add); - -static int gspca_is_compressed(__u32 format) -{ - switch (format) { - case V4L2_PIX_FMT_MJPEG: - case V4L2_PIX_FMT_JPEG: - case V4L2_PIX_FMT_SPCA561: - case V4L2_PIX_FMT_PAC207: - case V4L2_PIX_FMT_MR97310A: - return 1; - } - return 0; -} - -static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file, - enum v4l2_memory memory, unsigned int count) -{ - struct gspca_frame *frame; - unsigned int frsz; - int i; - - i = gspca_dev->curr_mode; - frsz = gspca_dev->cam.cam_mode[i].sizeimage; - PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz); - frsz = PAGE_ALIGN(frsz); - if (count >= GSPCA_MAX_FRAMES) - count = GSPCA_MAX_FRAMES - 1; - gspca_dev->frbuf = vmalloc_32(frsz * count); - if (!gspca_dev->frbuf) { - err("frame alloc failed"); - return -ENOMEM; - } - gspca_dev->capt_file = file; - gspca_dev->memory = memory; - gspca_dev->frsz = frsz; - gspca_dev->nframes = count; - for (i = 0; i < count; i++) { - frame = &gspca_dev->frame[i]; - frame->v4l2_buf.index = i; - frame->v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - frame->v4l2_buf.flags = 0; - frame->v4l2_buf.field = V4L2_FIELD_NONE; - frame->v4l2_buf.length = frsz; - frame->v4l2_buf.memory = memory; - frame->v4l2_buf.sequence = 0; - frame->data = gspca_dev->frbuf + i * frsz; - frame->v4l2_buf.m.offset = i * frsz; - } - atomic_set(&gspca_dev->fr_q, 0); - atomic_set(&gspca_dev->fr_i, 0); - gspca_dev->fr_o = 0; - return 0; -} - -static void frame_free(struct gspca_dev *gspca_dev) -{ - int i; - - PDEBUG(D_STREAM, "frame free"); - if (gspca_dev->frbuf != NULL) { - vfree(gspca_dev->frbuf); - gspca_dev->frbuf = NULL; - for (i = 0; i < gspca_dev->nframes; i++) - gspca_dev->frame[i].data = NULL; - } - gspca_dev->nframes = 0; - gspca_dev->frsz = 0; - gspca_dev->capt_file = NULL; - gspca_dev->memory = GSPCA_MEMORY_NO; -} - -static void destroy_urbs(struct gspca_dev *gspca_dev) -{ - struct urb *urb; - unsigned int i; - - PDEBUG(D_STREAM, "kill transfer"); - for (i = 0; i < MAX_NURBS; i++) { - urb = gspca_dev->urb[i]; - if (urb == NULL) - break; - - gspca_dev->urb[i] = NULL; - usb_kill_urb(urb); - if (urb->transfer_buffer != NULL) - usb_free_coherent(gspca_dev->dev, - urb->transfer_buffer_length, - urb->transfer_buffer, - urb->transfer_dma); - usb_free_urb(urb); - } -} - -static int gspca_set_alt0(struct gspca_dev *gspca_dev) -{ - int ret; - - if (gspca_dev->alt == 0) - return 0; - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0); - if (ret < 0) - err("set alt 0 err %d", ret); - return ret; -} - -/* Note: both the queue and the usb locks should be held when calling this */ -static void gspca_stream_off(struct gspca_dev *gspca_dev) -{ - gspca_dev->streaming = 0; - if (gspca_dev->present) { - if (gspca_dev->sd_desc->stopN) - gspca_dev->sd_desc->stopN(gspca_dev); - destroy_urbs(gspca_dev); - gspca_input_destroy_urb(gspca_dev); - gspca_set_alt0(gspca_dev); - gspca_input_create_urb(gspca_dev); - } - - /* always call stop0 to free the subdriver's resources */ - if (gspca_dev->sd_desc->stop0) - gspca_dev->sd_desc->stop0(gspca_dev); - PDEBUG(D_STREAM, "stream off OK"); -} - -/* - * look for an input transfer endpoint in an alternate setting - */ -static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, - int xfer) -{ - struct usb_host_endpoint *ep; - int i, attr; - - for (i = 0; i < alt->desc.bNumEndpoints; i++) { - ep = &alt->endpoint[i]; - attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - if (attr == xfer - && ep->desc.wMaxPacketSize != 0 - && usb_endpoint_dir_in(&ep->desc)) - return ep; - } - return NULL; -} - -/* - * look for an input (isoc or bulk) endpoint - * - * The endpoint is defined by the subdriver. - * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep). - * This routine may be called many times when the bandwidth is too small - * (the bandwidth is checked on urb submit). - */ -static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) -{ - struct usb_interface *intf; - struct usb_host_endpoint *ep; - int xfer, i, ret; - - intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); - ep = NULL; - xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK - : USB_ENDPOINT_XFER_ISOC; - i = gspca_dev->alt; /* previous alt setting */ - if (gspca_dev->cam.reverse_alts) { - while (++i < gspca_dev->nbalt) { - ep = alt_xfer(&intf->altsetting[i], xfer); - if (ep) - break; - } - } else { - while (--i >= 0) { - ep = alt_xfer(&intf->altsetting[i], xfer); - if (ep) - break; - } - } - if (ep == NULL) { - err("no transfer endpoint found"); - return NULL; - } - PDEBUG(D_STREAM, "use alt %d ep 0x%02x", - i, ep->desc.bEndpointAddress); - gspca_dev->alt = i; /* memorize the current alt setting */ - if (gspca_dev->nbalt > 1) { - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); - if (ret < 0) { - err("set alt %d err %d", i, ret); - ep = NULL; - } - } - return ep; -} - -/* - * create the URBs for image transfer - */ -static int create_urbs(struct gspca_dev *gspca_dev, - struct usb_host_endpoint *ep) -{ - struct urb *urb; - int n, nurbs, i, psize, npkt, bsize; - - /* calculate the packet size and the number of packets */ - psize = le16_to_cpu(ep->desc.wMaxPacketSize); - - if (!gspca_dev->cam.bulk) { /* isoc */ - - /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ - if (gspca_dev->pkt_size == 0) - psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - else - psize = gspca_dev->pkt_size; - npkt = gspca_dev->cam.npkt; - if (npkt == 0) - npkt = 32; /* default value */ - bsize = psize * npkt; - PDEBUG(D_STREAM, - "isoc %d pkts size %d = bsize:%d", - npkt, psize, bsize); - nurbs = DEF_NURBS; - } else { /* bulk */ - npkt = 0; - bsize = gspca_dev->cam.bulk_size; - if (bsize == 0) - bsize = psize; - PDEBUG(D_STREAM, "bulk bsize:%d", bsize); - if (gspca_dev->cam.bulk_nurbs != 0) - nurbs = gspca_dev->cam.bulk_nurbs; - else - nurbs = 1; - } - - for (n = 0; n < nurbs; n++) { - urb = usb_alloc_urb(npkt, GFP_KERNEL); - if (!urb) { - err("usb_alloc_urb failed"); - return -ENOMEM; - } - gspca_dev->urb[n] = urb; - urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, - bsize, - GFP_KERNEL, - &urb->transfer_dma); - - if (urb->transfer_buffer == NULL) { - err("usb_alloc_coherent failed"); - return -ENOMEM; - } - urb->dev = gspca_dev->dev; - urb->context = gspca_dev; - urb->transfer_buffer_length = bsize; - if (npkt != 0) { /* ISOC */ - urb->pipe = usb_rcvisocpipe(gspca_dev->dev, - ep->desc.bEndpointAddress); - urb->transfer_flags = URB_ISO_ASAP - | URB_NO_TRANSFER_DMA_MAP; - urb->interval = ep->desc.bInterval; - urb->complete = isoc_irq; - urb->number_of_packets = npkt; - for (i = 0; i < npkt; i++) { - urb->iso_frame_desc[i].length = psize; - urb->iso_frame_desc[i].offset = psize * i; - } - } else { /* bulk */ - urb->pipe = usb_rcvbulkpipe(gspca_dev->dev, - ep->desc.bEndpointAddress); - urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - urb->complete = bulk_irq; - } - } - return 0; -} - -/* - * start the USB transfer - */ -static int gspca_init_transfer(struct gspca_dev *gspca_dev) -{ - struct usb_host_endpoint *ep; - struct urb *urb; - int n, ret; - - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - - if (!gspca_dev->present) { - ret = -ENODEV; - goto unlock; - } - - /* reset the streaming variables */ - gspca_dev->image = NULL; - gspca_dev->image_len = 0; - gspca_dev->last_packet_type = DISCARD_PACKET; - gspca_dev->sequence = 0; - - gspca_dev->usb_err = 0; - - /* set the higher alternate setting and - * loop until urb submit succeeds */ - if (gspca_dev->cam.reverse_alts) - gspca_dev->alt = 0; - else - gspca_dev->alt = gspca_dev->nbalt; - - if (gspca_dev->sd_desc->isoc_init) { - ret = gspca_dev->sd_desc->isoc_init(gspca_dev); - if (ret < 0) - goto unlock; - } - - gspca_input_destroy_urb(gspca_dev); - ep = get_ep(gspca_dev); - if (ep == NULL) { - ret = -EIO; - goto out; - } - for (;;) { - if (!gspca_dev->cam.no_urb_create) { - PDEBUG(D_STREAM, "init transfer alt %d", - gspca_dev->alt); - ret = create_urbs(gspca_dev, ep); - if (ret < 0) { - destroy_urbs(gspca_dev); - goto out; - } - } - - /* clear the bulk endpoint */ - if (gspca_dev->cam.bulk) - usb_clear_halt(gspca_dev->dev, - gspca_dev->urb[0]->pipe); - - /* start the cam */ - ret = gspca_dev->sd_desc->start(gspca_dev); - if (ret < 0) { - destroy_urbs(gspca_dev); - goto out; - } - gspca_dev->streaming = 1; - - /* some bulk transfers are started by the subdriver */ - if (gspca_dev->cam.bulk && gspca_dev->cam.bulk_nurbs == 0) - break; - - /* submit the URBs */ - for (n = 0; n < MAX_NURBS; n++) { - urb = gspca_dev->urb[n]; - if (urb == NULL) - break; - ret = usb_submit_urb(urb, GFP_KERNEL); - if (ret < 0) - break; - } - if (ret >= 0) - break; - gspca_stream_off(gspca_dev); - if (ret != -ENOSPC) { - err("usb_submit_urb alt %d err %d", - gspca_dev->alt, ret); - goto out; - } - - /* the bandwidth is not wide enough - * negociate or try a lower alternate setting */ - PDEBUG(D_ERR|D_STREAM, - "bandwidth not wide enough - trying again"); - msleep(20); /* wait for kill complete */ - if (gspca_dev->sd_desc->isoc_nego) { - ret = gspca_dev->sd_desc->isoc_nego(gspca_dev); - if (ret < 0) - goto out; - } else { - ep = get_ep(gspca_dev); - if (ep == NULL) { - ret = -EIO; - goto out; - } - } - } -out: - gspca_input_create_urb(gspca_dev); -unlock: - mutex_unlock(&gspca_dev->usb_lock); - return ret; -} - -static void gspca_set_default_mode(struct gspca_dev *gspca_dev) -{ - struct gspca_ctrl *ctrl; - int i; - - i = gspca_dev->cam.nmodes - 1; /* take the highest mode */ - gspca_dev->curr_mode = i; - gspca_dev->width = gspca_dev->cam.cam_mode[i].width; - gspca_dev->height = gspca_dev->cam.cam_mode[i].height; - gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat; - - /* set the current control values to their default values - * which may have changed in sd_init() */ - ctrl = gspca_dev->cam.ctrls; - if (ctrl != NULL) { - for (i = 0; - i < gspca_dev->sd_desc->nctrls; - i++, ctrl++) - ctrl->val = ctrl->def; - } -} - -static int wxh_to_mode(struct gspca_dev *gspca_dev, - int width, int height) -{ - int i; - - for (i = gspca_dev->cam.nmodes; --i > 0; ) { - if (width >= gspca_dev->cam.cam_mode[i].width - && height >= gspca_dev->cam.cam_mode[i].height) - break; - } - return i; -} - -/* - * search a mode with the right pixel format - */ -static int gspca_get_mode(struct gspca_dev *gspca_dev, - int mode, - int pixfmt) -{ - int modeU, modeD; - - modeU = modeD = mode; - while ((modeU < gspca_dev->cam.nmodes) || modeD >= 0) { - if (--modeD >= 0) { - if (gspca_dev->cam.cam_mode[modeD].pixelformat - == pixfmt) - return modeD; - } - if (++modeU < gspca_dev->cam.nmodes) { - if (gspca_dev->cam.cam_mode[modeU].pixelformat - == pixfmt) - return modeU; - } - } - return -EINVAL; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - int ret; - struct gspca_dev *gspca_dev = priv; - - if (!gspca_dev->sd_desc->get_chip_ident) - return -EINVAL; - - if (!gspca_dev->sd_desc->get_register) - return -EINVAL; - - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->get_register(gspca_dev, reg); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - - return ret; -} - -static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - int ret; - struct gspca_dev *gspca_dev = priv; - - if (!gspca_dev->sd_desc->get_chip_ident) - return -EINVAL; - - if (!gspca_dev->sd_desc->set_register) - return -EINVAL; - - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->set_register(gspca_dev, reg); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - - return ret; -} -#endif - -static int vidioc_g_chip_ident(struct file *file, void *priv, - struct v4l2_dbg_chip_ident *chip) -{ - int ret; - struct gspca_dev *gspca_dev = priv; - - if (!gspca_dev->sd_desc->get_chip_ident) - return -EINVAL; - - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - - return ret; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmtdesc) -{ - struct gspca_dev *gspca_dev = priv; - int i, j, index; - __u32 fmt_tb[8]; - - /* give an index to each format */ - index = 0; - j = 0; - for (i = gspca_dev->cam.nmodes; --i >= 0; ) { - fmt_tb[index] = gspca_dev->cam.cam_mode[i].pixelformat; - j = 0; - for (;;) { - if (fmt_tb[j] == fmt_tb[index]) - break; - j++; - } - if (j == index) { - if (fmtdesc->index == index) - break; /* new format */ - index++; - if (index >= ARRAY_SIZE(fmt_tb)) - return -EINVAL; - } - } - if (i < 0) - return -EINVAL; /* no more format */ - - fmtdesc->pixelformat = fmt_tb[index]; - if (gspca_is_compressed(fmt_tb[index])) - fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED; - fmtdesc->description[0] = fmtdesc->pixelformat & 0xff; - fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff; - fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff; - fmtdesc->description[3] = fmtdesc->pixelformat >> 24; - fmtdesc->description[4] = '\0'; - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct gspca_dev *gspca_dev = priv; - int mode; - - mode = gspca_dev->curr_mode; - memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode], - sizeof fmt->fmt.pix); - return 0; -} - -static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, - struct v4l2_format *fmt) -{ - int w, h, mode, mode2; - - w = fmt->fmt.pix.width; - h = fmt->fmt.pix.height; - -#ifdef GSPCA_DEBUG - if (gspca_debug & D_CONF) - PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); -#endif - /* search the closest mode for width and height */ - mode = wxh_to_mode(gspca_dev, w, h); - - /* OK if right palette */ - if (gspca_dev->cam.cam_mode[mode].pixelformat - != fmt->fmt.pix.pixelformat) { - - /* else, search the closest mode with the same pixel format */ - mode2 = gspca_get_mode(gspca_dev, mode, - fmt->fmt.pix.pixelformat); - if (mode2 >= 0) - mode = mode2; -/* else - ; * no chance, return this mode */ - } - memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode], - sizeof fmt->fmt.pix); - return mode; /* used when s_fmt */ -} - -static int vidioc_try_fmt_vid_cap(struct file *file, - void *priv, - struct v4l2_format *fmt) -{ - struct gspca_dev *gspca_dev = priv; - int ret; - - ret = try_fmt_vid_cap(gspca_dev, fmt); - if (ret < 0) - return ret; - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct gspca_dev *gspca_dev = priv; - int ret; - - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - - ret = try_fmt_vid_cap(gspca_dev, fmt); - if (ret < 0) - goto out; - - if (gspca_dev->nframes != 0 - && fmt->fmt.pix.sizeimage > gspca_dev->frsz) { - ret = -EINVAL; - goto out; - } - - if (ret == gspca_dev->curr_mode) { - ret = 0; - goto out; /* same mode */ - } - - if (gspca_dev->streaming) { - ret = -EBUSY; - goto out; - } - gspca_dev->width = fmt->fmt.pix.width; - gspca_dev->height = fmt->fmt.pix.height; - gspca_dev->pixfmt = fmt->fmt.pix.pixelformat; - gspca_dev->curr_mode = ret; - - ret = 0; -out: - mutex_unlock(&gspca_dev->queue_lock); - return ret; -} - -static int vidioc_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - struct gspca_dev *gspca_dev = priv; - int i; - __u32 index = 0; - - for (i = 0; i < gspca_dev->cam.nmodes; i++) { - if (fsize->pixel_format != - gspca_dev->cam.cam_mode[i].pixelformat) - continue; - - if (fsize->index == index) { - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = - gspca_dev->cam.cam_mode[i].width; - fsize->discrete.height = - gspca_dev->cam.cam_mode[i].height; - return 0; - } - index++; - } - - return -EINVAL; -} - -static int vidioc_enum_frameintervals(struct file *filp, void *priv, - struct v4l2_frmivalenum *fival) -{ - struct gspca_dev *gspca_dev = priv; - int mode = wxh_to_mode(gspca_dev, fival->width, fival->height); - __u32 i; - - if (gspca_dev->cam.mode_framerates == NULL || - gspca_dev->cam.mode_framerates[mode].nrates == 0) - return -EINVAL; - - if (fival->pixel_format != - gspca_dev->cam.cam_mode[mode].pixelformat) - return -EINVAL; - - for (i = 0; i < gspca_dev->cam.mode_framerates[mode].nrates; i++) { - if (fival->index == i) { - fival->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fival->discrete.numerator = 1; - fival->discrete.denominator = - gspca_dev->cam.mode_framerates[mode].rates[i]; - return 0; - } - } - - return -EINVAL; -} - -static void gspca_release(struct video_device *vfd) -{ - struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); - - PDEBUG(D_PROBE, "%s released", - video_device_node_name(&gspca_dev->vdev)); - - kfree(gspca_dev->usb_buf); - kfree(gspca_dev); -} - -static int dev_open(struct file *file) -{ - struct gspca_dev *gspca_dev; - - PDEBUG(D_STREAM, "[%s] open", current->comm); - gspca_dev = (struct gspca_dev *) video_devdata(file); - if (!gspca_dev->present) - return -ENODEV; - - /* protect the subdriver against rmmod */ - if (!try_module_get(gspca_dev->module)) - return -ENODEV; - - file->private_data = gspca_dev; -#ifdef GSPCA_DEBUG - /* activate the v4l2 debug */ - if (gspca_debug & D_V4L2) - gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL - | V4L2_DEBUG_IOCTL_ARG; - else - gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL - | V4L2_DEBUG_IOCTL_ARG); -#endif - return 0; -} - -static int dev_close(struct file *file) -{ - struct gspca_dev *gspca_dev = file->private_data; - - PDEBUG(D_STREAM, "[%s] close", current->comm); - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - - /* if the file did the capture, free the streaming resources */ - if (gspca_dev->capt_file == file) { - if (gspca_dev->streaming) { - mutex_lock(&gspca_dev->usb_lock); - gspca_dev->usb_err = 0; - gspca_stream_off(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - } - frame_free(gspca_dev); - } - file->private_data = NULL; - module_put(gspca_dev->module); - mutex_unlock(&gspca_dev->queue_lock); - - PDEBUG(D_STREAM, "close done"); - - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct gspca_dev *gspca_dev = priv; - int ret; - - /* protect the access to the usb device */ - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (!gspca_dev->present) { - ret = -ENODEV; - goto out; - } - strncpy((char *) cap->driver, gspca_dev->sd_desc->name, - sizeof cap->driver); - if (gspca_dev->dev->product != NULL) { - strncpy((char *) cap->card, gspca_dev->dev->product, - sizeof cap->card); - } else { - snprintf((char *) cap->card, sizeof cap->card, - "USB Camera (%04x:%04x)", - le16_to_cpu(gspca_dev->dev->descriptor.idVendor), - le16_to_cpu(gspca_dev->dev->descriptor.idProduct)); - } - usb_make_path(gspca_dev->dev, (char *) cap->bus_info, - sizeof(cap->bus_info)); - cap->version = DRIVER_VERSION_NUMBER; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_STREAMING - | V4L2_CAP_READWRITE; - ret = 0; -out: - mutex_unlock(&gspca_dev->usb_lock); - return ret; -} - -static int get_ctrl(struct gspca_dev *gspca_dev, - int id) -{ - const struct ctrl *ctrls; - int i; - - for (i = 0, ctrls = gspca_dev->sd_desc->ctrls; - i < gspca_dev->sd_desc->nctrls; - i++, ctrls++) { - if (gspca_dev->ctrl_dis & (1 << i)) - continue; - if (id == ctrls->qctrl.id) - return i; - } - return -1; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *q_ctrl) -{ - struct gspca_dev *gspca_dev = priv; - const struct ctrl *ctrls; - struct gspca_ctrl *gspca_ctrl; - int i, idx; - u32 id; - - id = q_ctrl->id; - if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { - id &= V4L2_CTRL_ID_MASK; - id++; - idx = -1; - for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { - if (gspca_dev->ctrl_dis & (1 << i)) - continue; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id) - continue; - if (idx >= 0 - && gspca_dev->sd_desc->ctrls[i].qctrl.id - > gspca_dev->sd_desc->ctrls[idx].qctrl.id) - continue; - idx = i; - } - } else { - idx = get_ctrl(gspca_dev, id); - } - if (idx < 0) - return -EINVAL; - ctrls = &gspca_dev->sd_desc->ctrls[idx]; - memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl); - if (gspca_dev->cam.ctrls != NULL) { - gspca_ctrl = &gspca_dev->cam.ctrls[idx]; - q_ctrl->default_value = gspca_ctrl->def; - q_ctrl->minimum = gspca_ctrl->min; - q_ctrl->maximum = gspca_ctrl->max; - } - if (gspca_dev->ctrl_inac & (1 << idx)) - q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct gspca_dev *gspca_dev = priv; - const struct ctrl *ctrls; - struct gspca_ctrl *gspca_ctrl; - int idx, ret; - - idx = get_ctrl(gspca_dev, ctrl->id); - if (idx < 0) - return -EINVAL; - if (gspca_dev->ctrl_inac & (1 << idx)) - return -EINVAL; - ctrls = &gspca_dev->sd_desc->ctrls[idx]; - if (gspca_dev->cam.ctrls != NULL) { - gspca_ctrl = &gspca_dev->cam.ctrls[idx]; - if (ctrl->value < gspca_ctrl->min - || ctrl->value > gspca_ctrl->max) - return -ERANGE; - } else { - gspca_ctrl = NULL; - if (ctrl->value < ctrls->qctrl.minimum - || ctrl->value > ctrls->qctrl.maximum) - return -ERANGE; - } - PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (!gspca_dev->present) { - ret = -ENODEV; - goto out; - } - gspca_dev->usb_err = 0; - if (ctrls->set != NULL) { - ret = ctrls->set(gspca_dev, ctrl->value); - goto out; - } - if (gspca_ctrl != NULL) { - gspca_ctrl->val = ctrl->value; - if (ctrls->set_control != NULL - && gspca_dev->streaming) - ctrls->set_control(gspca_dev); - } - ret = gspca_dev->usb_err; -out: - mutex_unlock(&gspca_dev->usb_lock); - return ret; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct gspca_dev *gspca_dev = priv; - const struct ctrl *ctrls; - int idx, ret; - - idx = get_ctrl(gspca_dev, ctrl->id); - if (idx < 0) - return -EINVAL; - ctrls = &gspca_dev->sd_desc->ctrls[idx]; - - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (!gspca_dev->present) { - ret = -ENODEV; - goto out; - } - gspca_dev->usb_err = 0; - if (ctrls->get != NULL) { - ret = ctrls->get(gspca_dev, &ctrl->value); - goto out; - } - if (gspca_dev->cam.ctrls != NULL) - ctrl->value = gspca_dev->cam.ctrls[idx].val; - ret = 0; -out: - mutex_unlock(&gspca_dev->usb_lock); - return ret; -} - -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *qmenu) -{ - struct gspca_dev *gspca_dev = priv; - - if (!gspca_dev->sd_desc->querymenu) - return -EINVAL; - return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu); -} - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *input) -{ - struct gspca_dev *gspca_dev = priv; - - if (input->index != 0) - return -EINVAL; - input->type = V4L2_INPUT_TYPE_CAMERA; - input->status = gspca_dev->cam.input_flags; - strncpy(input->name, gspca_dev->sd_desc->name, - sizeof input->name); - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i > 0) - return -EINVAL; - return (0); -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct gspca_dev *gspca_dev = priv; - int i, ret = 0, streaming; - - i = rb->memory; /* (avoid compilation warning) */ - switch (i) { - case GSPCA_MEMORY_READ: /* (internal call) */ - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_USERPTR: - break; - default: - return -EINVAL; - } - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - - if (gspca_dev->memory != GSPCA_MEMORY_NO - && gspca_dev->memory != GSPCA_MEMORY_READ - && gspca_dev->memory != rb->memory) { - ret = -EBUSY; - goto out; - } - - /* only one file may do the capture */ - if (gspca_dev->capt_file != NULL - && gspca_dev->capt_file != file) { - ret = -EBUSY; - goto out; - } - - /* if allocated, the buffers must not be mapped */ - for (i = 0; i < gspca_dev->nframes; i++) { - if (gspca_dev->frame[i].vma_use_count) { - ret = -EBUSY; - goto out; - } - } - - /* stop streaming */ - streaming = gspca_dev->streaming; - if (streaming) { - mutex_lock(&gspca_dev->usb_lock); - gspca_dev->usb_err = 0; - gspca_stream_off(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - - /* Don't restart the stream when switching from read - * to mmap mode */ - if (gspca_dev->memory == GSPCA_MEMORY_READ) - streaming = 0; - } - - /* free the previous allocated buffers, if any */ - if (gspca_dev->nframes != 0) - frame_free(gspca_dev); - if (rb->count == 0) /* unrequest */ - goto out; - ret = frame_alloc(gspca_dev, file, rb->memory, rb->count); - if (ret == 0) { - rb->count = gspca_dev->nframes; - if (streaming) - ret = gspca_init_transfer(gspca_dev); - } -out: - mutex_unlock(&gspca_dev->queue_lock); - PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count); - return ret; -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *v4l2_buf) -{ - struct gspca_dev *gspca_dev = priv; - struct gspca_frame *frame; - - if (v4l2_buf->index < 0 - || v4l2_buf->index >= gspca_dev->nframes) - return -EINVAL; - - frame = &gspca_dev->frame[v4l2_buf->index]; - memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); - return 0; -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct gspca_dev *gspca_dev = priv; - int ret; - - if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - - /* check the capture file */ - if (gspca_dev->capt_file != file) { - ret = -EBUSY; - goto out; - } - - if (gspca_dev->nframes == 0 - || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) { - ret = -EINVAL; - goto out; - } - if (!gspca_dev->streaming) { - ret = gspca_init_transfer(gspca_dev); - if (ret < 0) - goto out; - } -#ifdef GSPCA_DEBUG - if (gspca_debug & D_STREAM) { - PDEBUG_MODE("stream on OK", - gspca_dev->pixfmt, - gspca_dev->width, - gspca_dev->height); - } -#endif - ret = 0; -out: - mutex_unlock(&gspca_dev->queue_lock); - return ret; -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct gspca_dev *gspca_dev = priv; - int ret; - - if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - - if (!gspca_dev->streaming) { - ret = 0; - goto out; - } - - /* check the capture file */ - if (gspca_dev->capt_file != file) { - ret = -EBUSY; - goto out; - } - - /* stop streaming */ - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { - ret = -ERESTARTSYS; - goto out; - } - gspca_dev->usb_err = 0; - gspca_stream_off(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - /* In case another thread is waiting in dqbuf */ - wake_up_interruptible(&gspca_dev->wq); - - /* empty the transfer queues */ - atomic_set(&gspca_dev->fr_q, 0); - atomic_set(&gspca_dev->fr_i, 0); - gspca_dev->fr_o = 0; - ret = 0; -out: - mutex_unlock(&gspca_dev->queue_lock); - return ret; -} - -static int vidioc_g_jpegcomp(struct file *file, void *priv, - struct v4l2_jpegcompression *jpegcomp) -{ - struct gspca_dev *gspca_dev = priv; - int ret; - - if (!gspca_dev->sd_desc->get_jcomp) - return -EINVAL; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - return ret; -} - -static int vidioc_s_jpegcomp(struct file *file, void *priv, - struct v4l2_jpegcompression *jpegcomp) -{ - struct gspca_dev *gspca_dev = priv; - int ret; - - if (!gspca_dev->sd_desc->set_jcomp) - return -EINVAL; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - return ret; -} - -static int vidioc_g_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parm) -{ - struct gspca_dev *gspca_dev = priv; - - parm->parm.capture.readbuffers = gspca_dev->nbufread; - - if (gspca_dev->sd_desc->get_streamparm) { - int ret; - - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (gspca_dev->present) { - gspca_dev->usb_err = 0; - gspca_dev->sd_desc->get_streamparm(gspca_dev, parm); - ret = gspca_dev->usb_err; - } else { - ret = -ENODEV; - } - mutex_unlock(&gspca_dev->usb_lock); - return ret; - } - - return 0; -} - -static int vidioc_s_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parm) -{ - struct gspca_dev *gspca_dev = priv; - int n; - - n = parm->parm.capture.readbuffers; - if (n == 0 || n >= GSPCA_MAX_FRAMES) - parm->parm.capture.readbuffers = gspca_dev->nbufread; - else - gspca_dev->nbufread = n; - - if (gspca_dev->sd_desc->set_streamparm) { - int ret; - - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (gspca_dev->present) { - gspca_dev->usb_err = 0; - gspca_dev->sd_desc->set_streamparm(gspca_dev, parm); - ret = gspca_dev->usb_err; - } else { - ret = -ENODEV; - } - mutex_unlock(&gspca_dev->usb_lock); - return ret; - } - - return 0; -} - -static int dev_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct gspca_dev *gspca_dev = file->private_data; - struct gspca_frame *frame; - struct page *page; - unsigned long addr, start, size; - int i, ret; - - start = vma->vm_start; - size = vma->vm_end - vma->vm_start; - PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size); - - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - if (!gspca_dev->present) { - ret = -ENODEV; - goto out; - } - if (gspca_dev->capt_file != file) { - ret = -EINVAL; - goto out; - } - - frame = NULL; - for (i = 0; i < gspca_dev->nframes; ++i) { - if (gspca_dev->frame[i].v4l2_buf.memory != V4L2_MEMORY_MMAP) { - PDEBUG(D_STREAM, "mmap bad memory type"); - break; - } - if ((gspca_dev->frame[i].v4l2_buf.m.offset >> PAGE_SHIFT) - == vma->vm_pgoff) { - frame = &gspca_dev->frame[i]; - break; - } - } - if (frame == NULL) { - PDEBUG(D_STREAM, "mmap no frame buffer found"); - ret = -EINVAL; - goto out; - } - if (size != frame->v4l2_buf.length) { - PDEBUG(D_STREAM, "mmap bad size"); - ret = -EINVAL; - goto out; - } - - /* - * - VM_IO marks the area as being a mmaped region for I/O to a - * device. It also prevents the region from being core dumped. - */ - vma->vm_flags |= VM_IO; - - addr = (unsigned long) frame->data; - while (size > 0) { - page = vmalloc_to_page((void *) addr); - ret = vm_insert_page(vma, start, page); - if (ret < 0) - goto out; - start += PAGE_SIZE; - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &gspca_vm_ops; - vma->vm_private_data = frame; - gspca_vm_open(vma); - ret = 0; -out: - mutex_unlock(&gspca_dev->queue_lock); - return ret; -} - -static int frame_ready_nolock(struct gspca_dev *gspca_dev, struct file *file, - enum v4l2_memory memory) -{ - if (!gspca_dev->present) - return -ENODEV; - if (gspca_dev->capt_file != file || gspca_dev->memory != memory || - !gspca_dev->streaming) - return -EINVAL; - - /* check if a frame is ready */ - return gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i); -} - -static int frame_ready(struct gspca_dev *gspca_dev, struct file *file, - enum v4l2_memory memory) -{ - int ret; - - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - ret = frame_ready_nolock(gspca_dev, file, memory); - mutex_unlock(&gspca_dev->queue_lock); - return ret; -} - -/* - * dequeue a video buffer - * - * If nonblock_ing is false, block until a buffer is available. - */ -static int vidioc_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *v4l2_buf) -{ - struct gspca_dev *gspca_dev = priv; - struct gspca_frame *frame; - int i, j, ret; - - PDEBUG(D_FRAM, "dqbuf"); - - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - - for (;;) { - ret = frame_ready_nolock(gspca_dev, file, v4l2_buf->memory); - if (ret < 0) - goto out; - if (ret > 0) - break; - - mutex_unlock(&gspca_dev->queue_lock); - - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - /* wait till a frame is ready */ - ret = wait_event_interruptible_timeout(gspca_dev->wq, - frame_ready(gspca_dev, file, v4l2_buf->memory), - msecs_to_jiffies(3000)); - if (ret < 0) - return ret; - if (ret == 0) - return -EIO; - - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - } - - i = gspca_dev->fr_o; - j = gspca_dev->fr_queue[i]; - frame = &gspca_dev->frame[j]; - - gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES; - - if (gspca_dev->sd_desc->dq_callback) { - mutex_lock(&gspca_dev->usb_lock); - gspca_dev->usb_err = 0; - if (gspca_dev->present) - gspca_dev->sd_desc->dq_callback(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - } - - frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; - memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); - PDEBUG(D_FRAM, "dqbuf %d", j); - ret = 0; - - if (gspca_dev->memory == V4L2_MEMORY_USERPTR) { - if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr, - frame->data, - frame->v4l2_buf.bytesused)) { - PDEBUG(D_ERR|D_STREAM, - "dqbuf cp to user failed"); - ret = -EFAULT; - } - } -out: - mutex_unlock(&gspca_dev->queue_lock); - return ret; -} - -/* - * queue a video buffer - * - * Attempting to queue a buffer that has already been - * queued will return -EINVAL. - */ -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *v4l2_buf) -{ - struct gspca_dev *gspca_dev = priv; - struct gspca_frame *frame; - int i, index, ret; - - PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index); - - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - - index = v4l2_buf->index; - if ((unsigned) index >= gspca_dev->nframes) { - PDEBUG(D_FRAM, - "qbuf idx %d >= %d", index, gspca_dev->nframes); - ret = -EINVAL; - goto out; - } - if (v4l2_buf->memory != gspca_dev->memory) { - PDEBUG(D_FRAM, "qbuf bad memory type"); - ret = -EINVAL; - goto out; - } - - frame = &gspca_dev->frame[index]; - if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) { - PDEBUG(D_FRAM, "qbuf bad state"); - ret = -EINVAL; - goto out; - } - - frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED; - - if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) { - frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr; - frame->v4l2_buf.length = v4l2_buf->length; - } - - /* put the buffer in the 'queued' queue */ - i = atomic_read(&gspca_dev->fr_q); - gspca_dev->fr_queue[i] = index; - atomic_set(&gspca_dev->fr_q, (i + 1) % GSPCA_MAX_FRAMES); - - v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; - v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE; - ret = 0; -out: - mutex_unlock(&gspca_dev->queue_lock); - return ret; -} - -/* - * allocate the resources for read() - */ -static int read_alloc(struct gspca_dev *gspca_dev, - struct file *file) -{ - struct v4l2_buffer v4l2_buf; - int i, ret; - - PDEBUG(D_STREAM, "read alloc"); - if (gspca_dev->nframes == 0) { - struct v4l2_requestbuffers rb; - - memset(&rb, 0, sizeof rb); - rb.count = gspca_dev->nbufread; - rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - rb.memory = GSPCA_MEMORY_READ; - ret = vidioc_reqbufs(file, gspca_dev, &rb); - if (ret != 0) { - PDEBUG(D_STREAM, "read reqbuf err %d", ret); - return ret; - } - memset(&v4l2_buf, 0, sizeof v4l2_buf); - v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - v4l2_buf.memory = GSPCA_MEMORY_READ; - for (i = 0; i < gspca_dev->nbufread; i++) { - v4l2_buf.index = i; - ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf); - if (ret != 0) { - PDEBUG(D_STREAM, "read qbuf err: %d", ret); - return ret; - } - } - gspca_dev->memory = GSPCA_MEMORY_READ; - } - - /* start streaming */ - ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (ret != 0) - PDEBUG(D_STREAM, "read streamon err %d", ret); - return ret; -} - -static unsigned int dev_poll(struct file *file, poll_table *wait) -{ - struct gspca_dev *gspca_dev = file->private_data; - int ret; - - PDEBUG(D_FRAM, "poll"); - - poll_wait(file, &gspca_dev->wq, wait); - - /* if reqbufs is not done, the user would use read() */ - if (gspca_dev->memory == GSPCA_MEMORY_NO) { - ret = read_alloc(gspca_dev, file); - if (ret != 0) - return POLLERR; - } - - if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) - return POLLERR; - - /* check if an image has been received */ - if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i)) - ret = POLLIN | POLLRDNORM; /* yes */ - else - ret = 0; - mutex_unlock(&gspca_dev->queue_lock); - if (!gspca_dev->present) - return POLLHUP; - return ret; -} - -static ssize_t dev_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct gspca_dev *gspca_dev = file->private_data; - struct gspca_frame *frame; - struct v4l2_buffer v4l2_buf; - struct timeval timestamp; - int n, ret, ret2; - - PDEBUG(D_FRAM, "read (%zd)", count); - if (!gspca_dev->present) - return -ENODEV; - if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */ - ret = read_alloc(gspca_dev, file); - if (ret != 0) - return ret; - } - - /* get a frame */ - timestamp = ktime_to_timeval(ktime_get()); - timestamp.tv_sec--; - n = 2; - for (;;) { - memset(&v4l2_buf, 0, sizeof v4l2_buf); - v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - v4l2_buf.memory = GSPCA_MEMORY_READ; - ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf); - if (ret != 0) { - PDEBUG(D_STREAM, "read dqbuf err %d", ret); - return ret; - } - - /* if the process slept for more than 1 second, - * get a newer frame */ - frame = &gspca_dev->frame[v4l2_buf.index]; - if (--n < 0) - break; /* avoid infinite loop */ - if (frame->v4l2_buf.timestamp.tv_sec >= timestamp.tv_sec) - break; - ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf); - if (ret != 0) { - PDEBUG(D_STREAM, "read qbuf err %d", ret); - return ret; - } - } - - /* copy the frame */ - if (count > frame->v4l2_buf.bytesused) - count = frame->v4l2_buf.bytesused; - ret = copy_to_user(data, frame->data, count); - if (ret != 0) { - PDEBUG(D_ERR|D_STREAM, - "read cp to user lack %d / %zd", ret, count); - ret = -EFAULT; - goto out; - } - ret = count; -out: - /* in each case, requeue the buffer */ - ret2 = vidioc_qbuf(file, gspca_dev, &v4l2_buf); - if (ret2 != 0) - return ret2; - return ret; -} - -static struct v4l2_file_operations dev_fops = { - .owner = THIS_MODULE, - .open = dev_open, - .release = dev_close, - .read = dev_read, - .mmap = dev_mmap, - .unlocked_ioctl = video_ioctl2, - .poll = dev_poll, -}; - -static const struct v4l2_ioctl_ops dev_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_streamon = vidioc_streamon, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_querymenu = vidioc_querymenu, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_jpegcomp = vidioc_g_jpegcomp, - .vidioc_s_jpegcomp = vidioc_s_jpegcomp, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_s_parm = vidioc_s_parm, - .vidioc_enum_framesizes = vidioc_enum_framesizes, - .vidioc_enum_frameintervals = vidioc_enum_frameintervals, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif - .vidioc_g_chip_ident = vidioc_g_chip_ident, -}; - -static const struct video_device gspca_template = { - .name = "gspca main driver", - .fops = &dev_fops, - .ioctl_ops = &dev_ioctl_ops, - .release = gspca_release, -}; - -/* initialize the controls */ -static void ctrls_init(struct gspca_dev *gspca_dev) -{ - struct gspca_ctrl *ctrl; - int i; - - for (i = 0, ctrl = gspca_dev->cam.ctrls; - i < gspca_dev->sd_desc->nctrls; - i++, ctrl++) { - ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value; - ctrl->val = ctrl->def; - ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum; - ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum; - } -} - -/* - * probe and create a new gspca device - * - * This function must be called by the sub-driver when it is - * called for probing a new device. - */ -int gspca_dev_probe2(struct usb_interface *intf, - const struct usb_device_id *id, - const struct sd_desc *sd_desc, - int dev_size, - struct module *module) -{ - struct gspca_dev *gspca_dev; - struct usb_device *dev = interface_to_usbdev(intf); - int ret; - - PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct); - - /* create the device */ - if (dev_size < sizeof *gspca_dev) - dev_size = sizeof *gspca_dev; - gspca_dev = kzalloc(dev_size, GFP_KERNEL); - if (!gspca_dev) { - err("couldn't kzalloc gspca struct"); - return -ENOMEM; - } - gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); - if (!gspca_dev->usb_buf) { - err("out of memory"); - ret = -ENOMEM; - goto out; - } - gspca_dev->dev = dev; - gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber; - gspca_dev->nbalt = intf->num_altsetting; - - /* check if any audio device */ - if (dev->config->desc.bNumInterfaces != 1) { - int i; - struct usb_interface *intf2; - - for (i = 0; i < dev->config->desc.bNumInterfaces; i++) { - intf2 = dev->config->interface[i]; - if (intf2 != NULL - && intf2->altsetting != NULL - && intf2->altsetting->desc.bInterfaceClass == - USB_CLASS_AUDIO) { - gspca_dev->audio = 1; - break; - } - } - } - - gspca_dev->sd_desc = sd_desc; - gspca_dev->nbufread = 2; - gspca_dev->empty_packet = -1; /* don't check the empty packets */ - - /* configure the subdriver and initialize the USB device */ - ret = sd_desc->config(gspca_dev, id); - if (ret < 0) - goto out; - if (gspca_dev->cam.ctrls != NULL) - ctrls_init(gspca_dev); - ret = sd_desc->init(gspca_dev); - if (ret < 0) - goto out; - gspca_set_default_mode(gspca_dev); - - ret = gspca_input_connect(gspca_dev); - if (ret) - goto out; - - mutex_init(&gspca_dev->usb_lock); - mutex_init(&gspca_dev->queue_lock); - init_waitqueue_head(&gspca_dev->wq); - - /* init video stuff */ - memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template); - gspca_dev->vdev.parent = &intf->dev; - gspca_dev->module = module; - gspca_dev->present = 1; - ret = video_register_device(&gspca_dev->vdev, - VFL_TYPE_GRABBER, - -1); - if (ret < 0) { - err("video_register_device err %d", ret); - goto out; - } - - usb_set_intfdata(intf, gspca_dev); - PDEBUG(D_PROBE, "%s created", video_device_node_name(&gspca_dev->vdev)); - - gspca_input_create_urb(gspca_dev); - - return 0; -out: -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - if (gspca_dev->input_dev) - input_unregister_device(gspca_dev->input_dev); -#endif - kfree(gspca_dev->usb_buf); - kfree(gspca_dev); - return ret; -} -EXPORT_SYMBOL(gspca_dev_probe2); - -/* same function as the previous one, but check the interface */ -int gspca_dev_probe(struct usb_interface *intf, - const struct usb_device_id *id, - const struct sd_desc *sd_desc, - int dev_size, - struct module *module) -{ - struct usb_device *dev = interface_to_usbdev(intf); - - /* we don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) { - err("%04x:%04x too many config", - id->idVendor, id->idProduct); - return -ENODEV; - } - - /* the USB video interface must be the first one */ - if (dev->config->desc.bNumInterfaces != 1 - && intf->cur_altsetting->desc.bInterfaceNumber != 0) - return -ENODEV; - - return gspca_dev_probe2(intf, id, sd_desc, dev_size, module); -} -EXPORT_SYMBOL(gspca_dev_probe); - -/* - * USB disconnection - * - * This function must be called by the sub-driver - * when the device disconnects, after the specific resources are freed. - */ -void gspca_disconnect(struct usb_interface *intf) -{ - struct gspca_dev *gspca_dev = usb_get_intfdata(intf); -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - struct input_dev *input_dev; -#endif - - PDEBUG(D_PROBE, "%s disconnect", - video_device_node_name(&gspca_dev->vdev)); - mutex_lock(&gspca_dev->usb_lock); - - gspca_dev->present = 0; - wake_up_interruptible(&gspca_dev->wq); - - destroy_urbs(gspca_dev); - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - gspca_input_destroy_urb(gspca_dev); - input_dev = gspca_dev->input_dev; - if (input_dev) { - gspca_dev->input_dev = NULL; - input_unregister_device(input_dev); - } -#endif - - /* the device is freed at exit of this function */ - gspca_dev->dev = NULL; - mutex_unlock(&gspca_dev->usb_lock); - - usb_set_intfdata(intf, NULL); - - /* release the device */ - /* (this will call gspca_release() immediatly or on last close) */ - video_unregister_device(&gspca_dev->vdev); - -/* PDEBUG(D_PROBE, "disconnect complete"); */ -} -EXPORT_SYMBOL(gspca_disconnect); - -#ifdef CONFIG_PM -int gspca_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct gspca_dev *gspca_dev = usb_get_intfdata(intf); - - if (!gspca_dev->streaming) - return 0; - gspca_dev->frozen = 1; /* avoid urb error messages */ - if (gspca_dev->sd_desc->stopN) - gspca_dev->sd_desc->stopN(gspca_dev); - destroy_urbs(gspca_dev); - gspca_input_destroy_urb(gspca_dev); - gspca_set_alt0(gspca_dev); - if (gspca_dev->sd_desc->stop0) - gspca_dev->sd_desc->stop0(gspca_dev); - return 0; -} -EXPORT_SYMBOL(gspca_suspend); - -int gspca_resume(struct usb_interface *intf) -{ - struct gspca_dev *gspca_dev = usb_get_intfdata(intf); - - gspca_dev->frozen = 0; - gspca_dev->sd_desc->init(gspca_dev); - gspca_input_create_urb(gspca_dev); - if (gspca_dev->streaming) - return gspca_init_transfer(gspca_dev); - return 0; -} -EXPORT_SYMBOL(gspca_resume); -#endif -/* -- cam driver utility functions -- */ - -/* auto gain and exposure algorithm based on the knee algorithm described here: - http://ytse.tricolour.net/docs/LowLightOptimization.html - - Returns 0 if no changes were made, 1 if the gain and or exposure settings - where changed. */ -int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, - int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee) -{ - int i, steps, gain, orig_gain, exposure, orig_exposure, autogain; - const struct ctrl *gain_ctrl = NULL; - const struct ctrl *exposure_ctrl = NULL; - const struct ctrl *autogain_ctrl = NULL; - int retval = 0; - - for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { - if (gspca_dev->ctrl_dis & (1 << i)) - continue; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN) - gain_ctrl = &gspca_dev->sd_desc->ctrls[i]; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE) - exposure_ctrl = &gspca_dev->sd_desc->ctrls[i]; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN) - autogain_ctrl = &gspca_dev->sd_desc->ctrls[i]; - } - if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) { - PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called " - "on cam without (auto)gain/exposure"); - return 0; - } - - if (gain_ctrl->get(gspca_dev, &gain) || - exposure_ctrl->get(gspca_dev, &exposure) || - autogain_ctrl->get(gspca_dev, &autogain) || !autogain) - return 0; - - orig_gain = gain; - orig_exposure = exposure; - - /* If we are of a multiple of deadzone, do multiple steps to reach the - desired lumination fast (with the risc of a slight overshoot) */ - steps = abs(desired_avg_lum - avg_lum) / deadzone; - - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", - avg_lum, desired_avg_lum, steps); - - for (i = 0; i < steps; i++) { - if (avg_lum > desired_avg_lum) { - if (gain > gain_knee) - gain--; - else if (exposure > exposure_knee) - exposure--; - else if (gain > gain_ctrl->qctrl.default_value) - gain--; - else if (exposure > exposure_ctrl->qctrl.minimum) - exposure--; - else if (gain > gain_ctrl->qctrl.minimum) - gain--; - else - break; - } else { - if (gain < gain_ctrl->qctrl.default_value) - gain++; - else if (exposure < exposure_knee) - exposure++; - else if (gain < gain_knee) - gain++; - else if (exposure < exposure_ctrl->qctrl.maximum) - exposure++; - else if (gain < gain_ctrl->qctrl.maximum) - gain++; - else - break; - } - } - - if (gain != orig_gain) { - gain_ctrl->set(gspca_dev, gain); - retval = 1; - } - if (exposure != orig_exposure) { - exposure_ctrl->set(gspca_dev, exposure); - retval = 1; - } - - return retval; -} -EXPORT_SYMBOL(gspca_auto_gain_n_exposure); - -/* -- module insert / remove -- */ -static int __init gspca_init(void) -{ - info("v%d.%d.%d registered", - (DRIVER_VERSION_NUMBER >> 16) & 0xff, - (DRIVER_VERSION_NUMBER >> 8) & 0xff, - DRIVER_VERSION_NUMBER & 0xff); - return 0; -} -static void __exit gspca_exit(void) -{ -} - -module_init(gspca_init); -module_exit(gspca_exit); - -#ifdef GSPCA_DEBUG -module_param_named(debug, gspca_debug, int, 0644); -MODULE_PARM_DESC(debug, - "Debug (bit) 0x01:error 0x02:probe 0x04:config" - " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout" - " 0x0100: v4l2"); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gspca.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gspca.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gspca.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/gspca.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,244 +0,0 @@ -#ifndef GSPCAV2_H -#define GSPCAV2_H - -#include -#include -#include -#include -#include -#include - -/* compilation option */ -#define GSPCA_DEBUG 1 - -#ifdef GSPCA_DEBUG -/* GSPCA our debug messages */ -extern int gspca_debug; -#define PDEBUG(level, fmt, args...) \ - do {\ - if (gspca_debug & (level)) \ - printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \ - } while (0) -#define D_ERR 0x01 -#define D_PROBE 0x02 -#define D_CONF 0x04 -#define D_STREAM 0x08 -#define D_FRAM 0x10 -#define D_PACK 0x20 -#define D_USBI 0x40 -#define D_USBO 0x80 -#define D_V4L2 0x0100 -#else -#define PDEBUG(level, fmt, args...) -#endif -#undef err -#define err(fmt, args...) \ - printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args) -#undef info -#define info(fmt, args...) \ - printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args) -#undef warn -#define warn(fmt, args...) \ - printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args) - -#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ -/* image transfers */ -#define MAX_NURBS 4 /* max number of URBs */ - - -/* used to list framerates supported by a camera mode (resolution) */ -struct framerates { - const u8 *rates; - int nrates; -}; - -/* control definition */ -struct gspca_ctrl { - s16 val; /* current value */ - s16 def; /* default value */ - s16 min, max; /* minimum and maximum values */ -}; - -/* device information - set at probe time */ -struct cam { - const struct v4l2_pix_format *cam_mode; /* size nmodes */ - const struct framerates *mode_framerates; /* must have size nmodes, - * just like cam_mode */ - struct gspca_ctrl *ctrls; /* control table - size nctrls */ - /* may be NULL */ - u32 bulk_size; /* buffer size when image transfer by bulk */ - u32 input_flags; /* value for ENUM_INPUT status flags */ - u8 nmodes; /* size of cam_mode */ - u8 no_urb_create; /* don't create transfer URBs */ - u8 bulk_nurbs; /* number of URBs in bulk mode - * - cannot be > MAX_NURBS - * - when 0 and bulk_size != 0 means - * 1 URB and submit done by subdriver */ - u8 bulk; /* image transfer by 0:isoc / 1:bulk */ - u8 npkt; /* number of packets in an ISOC message - * 0 is the default value: 32 packets */ - u8 reverse_alts; /* Alt settings are in high to low order */ -}; - -struct gspca_dev; -struct gspca_frame; - -/* subdriver operations */ -typedef int (*cam_op) (struct gspca_dev *); -typedef void (*cam_v_op) (struct gspca_dev *); -typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *); -typedef int (*cam_jpg_op) (struct gspca_dev *, - struct v4l2_jpegcompression *); -typedef int (*cam_reg_op) (struct gspca_dev *, - struct v4l2_dbg_register *); -typedef int (*cam_ident_op) (struct gspca_dev *, - struct v4l2_dbg_chip_ident *); -typedef void (*cam_streamparm_op) (struct gspca_dev *, - struct v4l2_streamparm *); -typedef int (*cam_qmnu_op) (struct gspca_dev *, - struct v4l2_querymenu *); -typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev, - u8 *data, - int len); -typedef int (*cam_int_pkt_op) (struct gspca_dev *gspca_dev, - u8 *data, - int len); - -struct ctrl { - struct v4l2_queryctrl qctrl; - int (*set)(struct gspca_dev *, __s32); - int (*get)(struct gspca_dev *, __s32 *); - cam_v_op set_control; -}; - -/* subdriver description */ -struct sd_desc { -/* information */ - const char *name; /* sub-driver name */ -/* controls */ - const struct ctrl *ctrls; /* static control definition */ - int nctrls; -/* mandatory operations */ - cam_cf_op config; /* called on probe */ - cam_op init; /* called on probe and resume */ - cam_op start; /* called on stream on after URBs creation */ - cam_pkt_op pkt_scan; -/* optional operations */ - cam_op isoc_init; /* called on stream on before getting the EP */ - cam_op isoc_nego; /* called when URB submit failed with NOSPC */ - cam_v_op stopN; /* called on stream off - main alt */ - cam_v_op stop0; /* called on stream off & disconnect - alt 0 */ - cam_v_op dq_callback; /* called when a frame has been dequeued */ - cam_jpg_op get_jcomp; - cam_jpg_op set_jcomp; - cam_qmnu_op querymenu; - cam_streamparm_op get_streamparm; - cam_streamparm_op set_streamparm; -#ifdef CONFIG_VIDEO_ADV_DEBUG - cam_reg_op set_register; - cam_reg_op get_register; -#endif - cam_ident_op get_chip_ident; -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - cam_int_pkt_op int_pkt_scan; - /* other_input makes the gspca core create gspca_dev->input even when - int_pkt_scan is NULL, for cams with non interrupt driven buttons */ - u8 other_input; -#endif -}; - -/* packet types when moving from iso buf to frame buf */ -enum gspca_packet_type { - DISCARD_PACKET, - FIRST_PACKET, - INTER_PACKET, - LAST_PACKET -}; - -struct gspca_frame { - __u8 *data; /* frame buffer */ - int vma_use_count; - struct v4l2_buffer v4l2_buf; -}; - -struct gspca_dev { - struct video_device vdev; /* !! must be the first item */ - struct module *module; /* subdriver handling the device */ - struct usb_device *dev; - struct file *capt_file; /* file doing video capture */ -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - struct input_dev *input_dev; - char phys[64]; /* physical device path */ -#endif - - struct cam cam; /* device information */ - const struct sd_desc *sd_desc; /* subdriver description */ - unsigned ctrl_dis; /* disabled controls (bit map) */ - unsigned ctrl_inac; /* inactive controls (bit map) */ - -#define USB_BUF_SZ 64 - __u8 *usb_buf; /* buffer for USB exchanges */ - struct urb *urb[MAX_NURBS]; -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - struct urb *int_urb; -#endif - - __u8 *frbuf; /* buffer for nframes */ - struct gspca_frame frame[GSPCA_MAX_FRAMES]; - u8 *image; /* image beeing filled */ - __u32 frsz; /* frame size */ - u32 image_len; /* current length of image */ - atomic_t fr_q; /* next frame to queue */ - atomic_t fr_i; /* frame being filled */ - signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */ - char nframes; /* number of frames */ - u8 fr_o; /* next frame to dequeue */ - __u8 last_packet_type; - __s8 empty_packet; /* if (-1) don't check empty packets */ - __u8 streaming; - - __u8 curr_mode; /* current camera mode */ - __u32 pixfmt; /* current mode parameters */ - __u16 width; - __u16 height; - __u32 sequence; /* frame sequence number */ - - wait_queue_head_t wq; /* wait queue */ - struct mutex usb_lock; /* usb exchange protection */ - struct mutex queue_lock; /* ISOC queue protection */ - int usb_err; /* USB error - protected by usb_lock */ - u16 pkt_size; /* ISOC packet size */ -#ifdef CONFIG_PM - char frozen; /* suspend - resume */ -#endif - char present; /* device connected */ - char nbufread; /* number of buffers for read() */ - char memory; /* memory type (V4L2_MEMORY_xxx) */ - __u8 iface; /* USB interface number */ - __u8 alt; /* USB alternate setting */ - __u8 nbalt; /* number of USB alternate settings */ - u8 audio; /* presence of audio device */ -}; - -int gspca_dev_probe(struct usb_interface *intf, - const struct usb_device_id *id, - const struct sd_desc *sd_desc, - int dev_size, - struct module *module); -int gspca_dev_probe2(struct usb_interface *intf, - const struct usb_device_id *id, - const struct sd_desc *sd_desc, - int dev_size, - struct module *module); -void gspca_disconnect(struct usb_interface *intf); -void gspca_frame_add(struct gspca_dev *gspca_dev, - enum gspca_packet_type packet_type, - const u8 *data, - int len); -#ifdef CONFIG_PM -int gspca_suspend(struct usb_interface *intf, pm_message_t message); -int gspca_resume(struct usb_interface *intf); -#endif -int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, - int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee); -#endif /* GSPCAV2_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/jeilinj.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/jeilinj.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/jeilinj.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/jeilinj.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,364 +0,0 @@ -/* - * Jeilinj subdriver - * - * Supports some Jeilin dual-mode cameras which use bulk transport and - * download raw JPEG data. - * - * Copyright (C) 2009 Theodore Kilgore - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "jeilinj" - -#include -#include -#include "gspca.h" -#include "jpeg.h" - -MODULE_AUTHOR("Theodore Kilgore "); -MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* Default timeouts, in ms */ -#define JEILINJ_CMD_TIMEOUT 500 -#define JEILINJ_DATA_TIMEOUT 1000 - -/* Maximum transfer size to use. */ -#define JEILINJ_MAX_TRANSFER 0x200 - -#define FRAME_HEADER_LEN 0x10 - -/* Structure to hold all of our device specific stuff */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - const struct v4l2_pix_format *cap_mode; - /* Driver stuff */ - struct work_struct work_struct; - struct workqueue_struct *work_thread; - u8 quality; /* image quality */ - u8 jpegqual; /* webcam quality */ - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; - - struct jlj_command { - unsigned char instruction[2]; - unsigned char ack_wanted; - }; - -/* AFAICT these cameras will only do 320x240. */ -static struct v4l2_pix_format jlj_mode[] = { - { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0} -}; - -/* - * cam uses endpoint 0x03 to send commands, 0x84 for read commands, - * and 0x82 for bulk transfer. - */ - -/* All commands are two bytes only */ -static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) -{ - int retval; - - memcpy(gspca_dev->usb_buf, command, 2); - retval = usb_bulk_msg(gspca_dev->dev, - usb_sndbulkpipe(gspca_dev->dev, 3), - gspca_dev->usb_buf, 2, NULL, 500); - if (retval < 0) - err("command write [%02x] error %d", - gspca_dev->usb_buf[0], retval); - return retval; -} - -/* Responses are one byte only */ -static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) -{ - int retval; - - retval = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 0x84), - gspca_dev->usb_buf, 1, NULL, 500); - response = gspca_dev->usb_buf[0]; - if (retval < 0) - err("read command [%02x] error %d", - gspca_dev->usb_buf[0], retval); - return retval; -} - -static int jlj_start(struct gspca_dev *gspca_dev) -{ - int i; - int retval = -1; - u8 response = 0xff; - struct jlj_command start_commands[] = { - {{0x71, 0x81}, 0}, - {{0x70, 0x05}, 0}, - {{0x95, 0x70}, 1}, - {{0x71, 0x81}, 0}, - {{0x70, 0x04}, 0}, - {{0x95, 0x70}, 1}, - {{0x71, 0x00}, 0}, - {{0x70, 0x08}, 0}, - {{0x95, 0x70}, 1}, - {{0x94, 0x02}, 0}, - {{0xde, 0x24}, 0}, - {{0x94, 0x02}, 0}, - {{0xdd, 0xf0}, 0}, - {{0x94, 0x02}, 0}, - {{0xe3, 0x2c}, 0}, - {{0x94, 0x02}, 0}, - {{0xe4, 0x00}, 0}, - {{0x94, 0x02}, 0}, - {{0xe5, 0x00}, 0}, - {{0x94, 0x02}, 0}, - {{0xe6, 0x2c}, 0}, - {{0x94, 0x03}, 0}, - {{0xaa, 0x00}, 0}, - {{0x71, 0x1e}, 0}, - {{0x70, 0x06}, 0}, - {{0x71, 0x80}, 0}, - {{0x70, 0x07}, 0} - }; - for (i = 0; i < ARRAY_SIZE(start_commands); i++) { - retval = jlj_write2(gspca_dev, start_commands[i].instruction); - if (retval < 0) - return retval; - if (start_commands[i].ack_wanted) - retval = jlj_read1(gspca_dev, response); - if (retval < 0) - return retval; - } - PDEBUG(D_ERR, "jlj_start retval is %d", retval); - return retval; -} - -static int jlj_stop(struct gspca_dev *gspca_dev) -{ - int i; - int retval; - struct jlj_command stop_commands[] = { - {{0x71, 0x00}, 0}, - {{0x70, 0x09}, 0}, - {{0x71, 0x80}, 0}, - {{0x70, 0x05}, 0} - }; - for (i = 0; i < ARRAY_SIZE(stop_commands); i++) { - retval = jlj_write2(gspca_dev, stop_commands[i].instruction); - if (retval < 0) - return retval; - } - return retval; -} - -/* This function is called as a workqueue function and runs whenever the camera - * is streaming data. Because it is a workqueue function it is allowed to sleep - * so we can use synchronous USB calls. To avoid possible collisions with other - * threads attempting to use the camera's USB interface the gspca usb_lock is - * used when performing the one USB control operation inside the workqueue, - * which tells the camera to close the stream. In practice the only thing - * which needs to be protected against is the usb_set_interface call that - * gspca makes during stream_off. Otherwise the camera doesn't provide any - * controls that the user could try to change. - */ - -static void jlj_dostream(struct work_struct *work) -{ - struct sd *dev = container_of(work, struct sd, work_struct); - struct gspca_dev *gspca_dev = &dev->gspca_dev; - int blocks_left; /* 0x200-sized blocks remaining in current frame. */ - int act_len; - int packet_type; - int ret; - u8 *buffer; - - buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); - if (!buffer) { - err("Couldn't allocate USB buffer"); - goto quit_stream; - } - while (gspca_dev->present && gspca_dev->streaming) { - /* - * Now request data block 0. Line 0 reports the size - * to download, in blocks of size 0x200, and also tells the - * "actual" data size, in bytes, which seems best to ignore. - */ - ret = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 0x82), - buffer, JEILINJ_MAX_TRANSFER, &act_len, - JEILINJ_DATA_TIMEOUT); - PDEBUG(D_STREAM, - "Got %d bytes out of %d for Block 0", - act_len, JEILINJ_MAX_TRANSFER); - if (ret < 0 || act_len < FRAME_HEADER_LEN) - goto quit_stream; - blocks_left = buffer[0x0a] - 1; - PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left); - - /* Start a new frame, and add the JPEG header, first thing */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - dev->jpeg_hdr, JPEG_HDR_SZ); - /* Toss line 0 of data block 0, keep the rest. */ - gspca_frame_add(gspca_dev, INTER_PACKET, - buffer + FRAME_HEADER_LEN, - JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN); - - while (blocks_left > 0) { - if (!gspca_dev->present) - goto quit_stream; - ret = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 0x82), - buffer, JEILINJ_MAX_TRANSFER, &act_len, - JEILINJ_DATA_TIMEOUT); - if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER) - goto quit_stream; - PDEBUG(D_STREAM, - "%d blocks remaining for frame", blocks_left); - blocks_left -= 1; - if (blocks_left == 0) - packet_type = LAST_PACKET; - else - packet_type = INTER_PACKET; - gspca_frame_add(gspca_dev, packet_type, - buffer, JEILINJ_MAX_TRANSFER); - } - } -quit_stream: - mutex_lock(&gspca_dev->usb_lock); - if (gspca_dev->present) - jlj_stop(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - kfree(buffer); -} - -/* This function is called at probe time just before sd_init */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct cam *cam = &gspca_dev->cam; - struct sd *dev = (struct sd *) gspca_dev; - - dev->quality = 85; - dev->jpegqual = 85; - PDEBUG(D_PROBE, - "JEILINJ camera detected" - " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - cam->cam_mode = jlj_mode; - cam->nmodes = 1; - cam->bulk = 1; - /* We don't use the buffer gspca allocates so make it small. */ - cam->bulk_size = 32; - INIT_WORK(&dev->work_struct, jlj_dostream); - return 0; -} - -/* called on streamoff with alt==0 and on disconnect */ -/* the usb_lock is held at entry - restore on exit */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *dev = (struct sd *) gspca_dev; - - /* wait for the work queue to terminate */ - mutex_unlock(&gspca_dev->usb_lock); - /* This waits for jlj_dostream to finish */ - destroy_workqueue(dev->work_thread); - dev->work_thread = NULL; - mutex_lock(&gspca_dev->usb_lock); -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - return 0; -} - -/* Set up for getting frames. */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *dev = (struct sd *) gspca_dev; - int ret; - - /* create the JPEG header */ - jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x21); /* JPEG 422 */ - jpeg_set_qual(dev->jpeg_hdr, dev->quality); - PDEBUG(D_STREAM, "Start streaming at 320x240"); - ret = jlj_start(gspca_dev); - if (ret < 0) { - PDEBUG(D_ERR, "Start streaming command failed"); - return ret; - } - /* Start the workqueue function to do the streaming */ - dev->work_thread = create_singlethread_workqueue(MODULE_NAME); - queue_work(dev->work_thread, &dev->work_struct); - - return 0; -} - -/* Table of supported USB devices */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0979, 0x0280)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stop0 = sd_stop0, -}; - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, - &sd_desc, - sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/jpeg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/jpeg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/jpeg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/jpeg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,168 +0,0 @@ -#ifndef JPEG_H -#define JPEG_H 1 -/* - * Insert a JPEG header at start of frame - * - * This module is used by the gspca subdrivers. - * A special case is done for Conexant webcams. - * - * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr) - * - * 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, or - * any later version. - * - * 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 - * - */ - -/* - * generation options - * CONEX_CAM Conexant if present - */ - -/* JPEG header */ -static const u8 jpeg_head[] = { - 0xff, 0xd8, /* jpeg */ - -/* quantization table quality 50% */ - 0xff, 0xdb, 0x00, 0x84, /* DQT */ -0, -#define JPEG_QT0_OFFSET 7 - 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, - 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, - 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, - 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, - 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, - 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, - 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, - 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, -1, -#define JPEG_QT1_OFFSET 72 - 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, - 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - -/* huffman table */ - 0xff, 0xc4, 0x01, 0xa2, - 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, - 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, - 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, - 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, - 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, - 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, - 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, - 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, - 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, - 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, - 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, - 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, - 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, - 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, - 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, - 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, - 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, - 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, - 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, - 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, - 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, - 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, - 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, - 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, - 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, - 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, - 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, - 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, - 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, - 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, - 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, - 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, - 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, -#ifdef CONEX_CAM -/* the Conexant frames start with SOF0 */ -#define JPEG_HDR_SZ 556 -#else - 0xff, 0xc0, 0x00, 0x11, /* SOF0 (start of frame 0 */ - 0x08, /* data precision */ -#define JPEG_HEIGHT_OFFSET 561 - 0x01, 0xe0, /* height */ - 0x02, 0x80, /* width */ - 0x03, /* component number */ - 0x01, - 0x21, /* samples Y */ - 0x00, /* quant Y */ - 0x02, 0x11, 0x01, /* samples CbCr - quant CbCr */ - 0x03, 0x11, 0x01, - - 0xff, 0xda, 0x00, 0x0c, /* SOS (start of scan) */ - 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 -#define JPEG_HDR_SZ 589 -#endif -}; - -/* define the JPEG header */ -static void jpeg_define(u8 *jpeg_hdr, - int height, - int width, - int samplesY) -{ - memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head); -#ifndef CONEX_CAM - jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8; - jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height; - jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8; - jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width; - jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY; -#endif -} - -/* set the JPEG quality */ -static void jpeg_set_qual(u8 *jpeg_hdr, - int quality) -{ - int i, sc; - - if (quality < 50) - sc = 5000 / quality; - else - sc = 200 - quality * 2; - for (i = 0; i < 64; i++) { - jpeg_hdr[JPEG_QT0_OFFSET + i] = - (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100; - jpeg_hdr[JPEG_QT1_OFFSET + i] = - (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100; - } -} -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,386 +0,0 @@ -menuconfig USB_GSPCA - tristate "GSPCA based webcams" - depends on VIDEO_V4L2 - default m - ---help--- - Say Y here if you want to enable selecting webcams based - on the GSPCA framework. - - See for more info. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. - - To compile this driver as modules, choose M here: the - module will be called gspca_main. - - -if USB_GSPCA && VIDEO_V4L2 - -source "drivers/media/video/gspca/m5602/Kconfig" -source "drivers/media/video/gspca/stv06xx/Kconfig" -source "drivers/media/video/gspca/gl860/Kconfig" - -config USB_GSPCA_BENQ - tristate "Benq USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for the Benq DC E300 camera. - - To compile this driver as a module, choose M here: the - module will be called gspca_benq. - -config USB_GSPCA_CONEX - tristate "Conexant Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Conexant chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_conex. - -config USB_GSPCA_CPIA1 - tristate "cpia CPiA (version 1) Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for USB cameras based on the cpia - CPiA chip. Note that you need atleast version 0.6.4 of libv4l for - applications to understand the videoformat generated by this driver. - - To compile this driver as a module, choose M here: the - module will be called gspca_cpia1. - -config USB_GSPCA_ETOMS - tristate "Etoms USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Etoms chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_etoms. - -config USB_GSPCA_FINEPIX - tristate "Fujifilm FinePix USB V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the FinePix chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_finepix. - -config USB_GSPCA_JEILINJ - tristate "Jeilin JPEG USB V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on this Jeilin chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_jeilinj. - -config USB_GSPCA_KONICA - tristate "Konica USB Camera V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Konica chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_konica. - -config USB_GSPCA_MARS - tristate "Mars USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Mars chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_mars. - -config USB_GSPCA_MR97310A - tristate "Mars-Semi MR97310A USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the MR97310A chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_mr97310a. - -config USB_GSPCA_NW80X - tristate "Divio based (NW80x) USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the NW80x chips. - - To compile this driver as a module, choose M here: the - module will be called gspca_nw80x. - -config USB_GSPCA_OV519 - tristate "OV51x / OVFX2 / W996xCF USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on one of these: - OV511(+), OV518(+), OV519, OVFX2, W9967CF, W9968CF - - To compile this driver as a module, choose M here: the - module will be called gspca_ov519. - -config USB_GSPCA_OV534 - tristate "OV534 OV772x USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the OV534 chip - and sensor OV772x (e.g. Sony Playstation EYE) - - To compile this driver as a module, choose M here: the - module will be called gspca_ov534. - -config USB_GSPCA_OV534_9 - tristate "OV534 OV965x USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the OV534 chip - and sensor OV965x (e.g. Hercules Dualpix) - - To compile this driver as a module, choose M here: the - module will be called gspca_ov534_9. - -config USB_GSPCA_PAC207 - tristate "Pixart PAC207 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the PAC207 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_pac207. - -config USB_GSPCA_PAC7302 - tristate "Pixart PAC7302 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the PAC7302 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_pac7302. - -config USB_GSPCA_PAC7311 - tristate "Pixart PAC7311 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the PAC7311 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_pac7311. - -config USB_GSPCA_SN9C2028 - tristate "SONIX Dual-Mode USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want streaming support for Sonix SN9C2028 cameras. - These are supported as stillcams in libgphoto2/camlibs/sonix. - - To compile this driver as a module, choose M here: the - module will be called gspca_sn9c2028. - -config USB_GSPCA_SN9C20X - tristate "SN9C20X USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the - sn9c20x chips (SN9C201 and SN9C202). - - To compile this driver as a module, choose M here: the - module will be called gspca_sn9c20x. - -config USB_GSPCA_SONIXB - tristate "SONIX Bayer USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Sonix - chips with Bayer format (SN9C101, SN9C102 and SN9C103). - - To compile this driver as a module, choose M here: the - module will be called gspca_sonixb. - -config USB_GSPCA_SONIXJ - tristate "SONIX JPEG USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Sonix - chips with JPEG format (SN9C102P, SN9C105 and >= SN9C110). - - To compile this driver as a module, choose M here: the - module will be called gspca_sonixj - -config USB_GSPCA_SPCA500 - tristate "SPCA500 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA500 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca500. - -config USB_GSPCA_SPCA501 - tristate "SPCA501 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA501 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca501. - -config USB_GSPCA_SPCA505 - tristate "SPCA505 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA505 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca505. - -config USB_GSPCA_SPCA506 - tristate "SPCA506 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA506 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca506. - -config USB_GSPCA_SPCA508 - tristate "SPCA508 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA508 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca508. - -config USB_GSPCA_SPCA561 - tristate "SPCA561 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA561 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca561. - -config USB_GSPCA_SPCA1528 - tristate "SPCA1528 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA1528 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca1528. - -config USB_GSPCA_SQ905 - tristate "SQ Technologies SQ905 based USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SQ905 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_sq905. - -config USB_GSPCA_SQ905C - tristate "SQ Technologies SQ905C based USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SQ905C chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_sq905c. - -config USB_GSPCA_SQ930X - tristate "SQ Technologies SQ930X based USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SQ930X chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_sq930x. - -config USB_GSPCA_STK014 - tristate "Syntek DV4000 (STK014) USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the STK014 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_stk014. - -config USB_GSPCA_STV0680 - tristate "STV0680 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the STV0680 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_stv0680. - -config USB_GSPCA_SUNPLUS - tristate "SUNPLUS USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Sunplus - SPCA504(abc) SPCA533 SPCA536 chips. - - To compile this driver as a module, choose M here: the - module will be called gspca_sunplus. - -config USB_GSPCA_T613 - tristate "T613 (JPEG Compliance) USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the T613 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_t613. - -config USB_GSPCA_TV8532 - tristate "TV8532 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the TV8531 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_tv8532. - -config USB_GSPCA_VC032X - tristate "VC032X USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the VC032X chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_vc032x. - -config USB_GSPCA_VICAM - tristate "ViCam USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for the 3com homeconnect camera - (vicam). - - To compile this driver as a module, choose M here: the - module will be called gspca_vicam. - -config USB_GSPCA_XIRLINK_CIT - tristate "Xirlink C-It USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for Xirlink C-It bases cameras. - - To compile this driver as a module, choose M here: the - module will be called gspca_xirlink_cit. - -config USB_GSPCA_ZC3XX - tristate "ZC3XX USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the ZC3XX chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_zc3xx. - -endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/konica.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/konica.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/konica.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/konica.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,646 +0,0 @@ -/* - * Driver for USB webcams based on Konica chipset. This - * chipset is used in Intel YC76 camera. - * - * Copyright (C) 2010 Hans de Goede - * - * Based on the usbvideo v4l1 konicawc driver which is: - * - * Copyright (C) 2002 Simon Evans - * - * The code for making gspca work with a webcam with 2 isoc endpoints was - * taken from the benq gspca subdriver which is: - * - * Copyright (C) 2009 Jean-Francois Moine (http://moinejf.free.fr) - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "konica" - -#include -#include "gspca.h" - -MODULE_AUTHOR("Hans de Goede "); -MODULE_DESCRIPTION("Konica chipset USB Camera Driver"); -MODULE_LICENSE("GPL"); - -#define WHITEBAL_REG 0x01 -#define BRIGHTNESS_REG 0x02 -#define SHARPNESS_REG 0x03 -#define CONTRAST_REG 0x04 -#define SATURATION_REG 0x05 - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - struct urb *last_data_urb; - u8 snapshot_pressed; - u8 brightness; - u8 contrast; - u8 saturation; - u8 whitebal; - u8 sharpness; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 9, - .step = 1, -#define BRIGHTNESS_DEFAULT 4 - .default_value = BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 9, - .step = 4, -#define CONTRAST_DEFAULT 10 - .default_value = CONTRAST_DEFAULT, - .flags = 0, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SD_SATURATION 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 9, - .step = 1, -#define SATURATION_DEFAULT 4 - .default_value = SATURATION_DEFAULT, - .flags = 0, - }, - .set = sd_setsaturation, - .get = sd_getsaturation, - }, -#define SD_WHITEBAL 3 - { - { - .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "White Balance", - .minimum = 0, - .maximum = 33, - .step = 1, -#define WHITEBAL_DEFAULT 25 - .default_value = WHITEBAL_DEFAULT, - .flags = 0, - }, - .set = sd_setwhitebal, - .get = sd_getwhitebal, - }, -#define SD_SHARPNESS 4 - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 9, - .step = 1, -#define SHARPNESS_DEFAULT 4 - .default_value = SHARPNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, -}; - -/* .priv is what goes to register 8 for this mode, known working values: - 0x00 -> 176x144, cropped - 0x01 -> 176x144, cropped - 0x02 -> 176x144, cropped - 0x03 -> 176x144, cropped - 0x04 -> 176x144, binned - 0x05 -> 320x240 - 0x06 -> 320x240 - 0x07 -> 160x120, cropped - 0x08 -> 160x120, cropped - 0x09 -> 160x120, binned (note has 136 lines) - 0x0a -> 160x120, binned (note has 136 lines) - 0x0b -> 160x120, cropped -*/ -static const struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 136 * 3 / 2 + 960, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0x0a}, - {176, 144, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 2 + 960, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0x04}, - {320, 240, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 2 + 960, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0x05}, -}; - -static void sd_isoc_irq(struct urb *urb); - -static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x02, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - NULL, - 0, - 1000); - if (ret < 0) { - err("reg_w err %d", ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - 0x03, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - gspca_dev->usb_buf, - 2, - 1000); - if (ret < 0) { - err("reg_w err %d", ret); - gspca_dev->usb_err = ret; - } -} - -static void konica_stream_on(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev, 1, 0x0b); -} - -static void konica_stream_off(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev, 0, 0x0b); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->cam.cam_mode = vga_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); - gspca_dev->cam.no_urb_create = 1; - /* The highest alt setting has an isoc packetsize of 0, so we - don't want to use it */ - gspca_dev->nbalt--; - - sd->brightness = BRIGHTNESS_DEFAULT; - sd->contrast = CONTRAST_DEFAULT; - sd->saturation = SATURATION_DEFAULT; - sd->whitebal = WHITEBAL_DEFAULT; - sd->sharpness = SHARPNESS_DEFAULT; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - /* HDG not sure if these 2 reads are needed */ - reg_r(gspca_dev, 0, 0x10); - PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x", - gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); - reg_r(gspca_dev, 0, 0x10); - PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x", - gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); - reg_w(gspca_dev, 0, 0x0d); - - return 0; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct urb *urb; - int i, n, packet_size; - struct usb_host_interface *alt; - struct usb_interface *intf; - - intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); - alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); - if (!alt) { - err("Couldn't get altsetting"); - return -EIO; - } - - packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); - - reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG); - reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG); - reg_w(gspca_dev, sd->contrast, CONTRAST_REG); - reg_w(gspca_dev, sd->saturation, SATURATION_REG); - reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG); - - n = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - reg_w(gspca_dev, n, 0x08); - - konica_stream_on(gspca_dev); - - if (gspca_dev->usb_err) - return gspca_dev->usb_err; - - /* create 4 URBs - 2 on endpoint 0x83 and 2 on 0x082 */ -#if MAX_NURBS < 4 -#error "Not enough URBs in the gspca table" -#endif -#define SD_NPKT 32 - for (n = 0; n < 4; n++) { - i = n & 1 ? 0 : 1; - packet_size = - le16_to_cpu(alt->endpoint[i].desc.wMaxPacketSize); - urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); - if (!urb) { - err("usb_alloc_urb failed"); - return -ENOMEM; - } - gspca_dev->urb[n] = urb; - urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, - packet_size * SD_NPKT, - GFP_KERNEL, - &urb->transfer_dma); - if (urb->transfer_buffer == NULL) { - err("usb_buffer_alloc failed"); - return -ENOMEM; - } - - urb->dev = gspca_dev->dev; - urb->context = gspca_dev; - urb->transfer_buffer_length = packet_size * SD_NPKT; - urb->pipe = usb_rcvisocpipe(gspca_dev->dev, - n & 1 ? 0x81 : 0x82); - urb->transfer_flags = URB_ISO_ASAP - | URB_NO_TRANSFER_DMA_MAP; - urb->interval = 1; - urb->complete = sd_isoc_irq; - urb->number_of_packets = SD_NPKT; - for (i = 0; i < SD_NPKT; i++) { - urb->iso_frame_desc[i].length = packet_size; - urb->iso_frame_desc[i].offset = packet_size * i; - } - } - - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - konica_stream_off(gspca_dev); -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - /* Don't keep the button in the pressed state "forever" if it was - pressed when streaming is stopped */ - if (sd->snapshot_pressed) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - sd->snapshot_pressed = 0; - } -#endif -} - -/* reception of an URB */ -static void sd_isoc_irq(struct urb *urb) -{ - struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; - struct sd *sd = (struct sd *) gspca_dev; - struct urb *data_urb, *status_urb; - u8 *data; - int i, st; - - PDEBUG(D_PACK, "sd isoc irq"); - if (!gspca_dev->streaming) - return; - - if (urb->status != 0) { - if (urb->status == -ESHUTDOWN) - return; /* disconnection */ -#ifdef CONFIG_PM - if (gspca_dev->frozen) - return; -#endif - PDEBUG(D_ERR, "urb status: %d", urb->status); - st = usb_submit_urb(urb, GFP_ATOMIC); - if (st < 0) - err("resubmit urb error %d", st); - return; - } - - /* if this is a data URB (ep 0x82), wait */ - if (urb->transfer_buffer_length > 32) { - sd->last_data_urb = urb; - return; - } - - status_urb = urb; - data_urb = sd->last_data_urb; - sd->last_data_urb = NULL; - - if (!data_urb || data_urb->start_frame != status_urb->start_frame) { - PDEBUG(D_ERR|D_PACK, "lost sync on frames"); - goto resubmit; - } - - if (data_urb->number_of_packets != status_urb->number_of_packets) { - PDEBUG(D_ERR|D_PACK, - "no packets does not match, data: %d, status: %d", - data_urb->number_of_packets, - status_urb->number_of_packets); - goto resubmit; - } - - for (i = 0; i < status_urb->number_of_packets; i++) { - if (data_urb->iso_frame_desc[i].status || - status_urb->iso_frame_desc[i].status) { - PDEBUG(D_ERR|D_PACK, - "pkt %d data-status %d, status-status %d", i, - data_urb->iso_frame_desc[i].status, - status_urb->iso_frame_desc[i].status); - gspca_dev->last_packet_type = DISCARD_PACKET; - continue; - } - - if (status_urb->iso_frame_desc[i].actual_length != 1) { - PDEBUG(D_ERR|D_PACK, - "bad status packet length %d", - status_urb->iso_frame_desc[i].actual_length); - gspca_dev->last_packet_type = DISCARD_PACKET; - continue; - } - - st = *((u8 *)status_urb->transfer_buffer - + status_urb->iso_frame_desc[i].offset); - - data = (u8 *)data_urb->transfer_buffer - + data_urb->iso_frame_desc[i].offset; - - /* st: 0x80-0xff: frame start with frame number (ie 0-7f) - * otherwise: - * bit 0 0: keep packet - * 1: drop packet (padding data) - * - * bit 4 0 button not clicked - * 1 button clicked - * button is used to `take a picture' (in software) - */ - if (st & 0x80) { - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); - } else { -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - u8 button_state = st & 0x40 ? 1 : 0; - if (sd->snapshot_pressed != button_state) { - input_report_key(gspca_dev->input_dev, - KEY_CAMERA, - button_state); - input_sync(gspca_dev->input_dev); - sd->snapshot_pressed = button_state; - } -#endif - if (st & 0x01) - continue; - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, - data_urb->iso_frame_desc[i].actual_length); - } - -resubmit: - if (data_urb) { - st = usb_submit_urb(data_urb, GFP_ATOMIC); - if (st < 0) - PDEBUG(D_ERR|D_PACK, - "usb_submit_urb(data_urb) ret %d", st); - } - st = usb_submit_urb(status_urb, GFP_ATOMIC); - if (st < 0) - err("usb_submit_urb(status_urb) ret %d", st); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) { - konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG); - konica_stream_on(gspca_dev); - } - - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) { - konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->contrast, CONTRAST_REG); - konica_stream_on(gspca_dev); - } - - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - - return 0; -} - -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->saturation = val; - if (gspca_dev->streaming) { - konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->saturation, SATURATION_REG); - konica_stream_on(gspca_dev); - } - return 0; -} - -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->saturation; - - return 0; -} - -static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->whitebal = val; - if (gspca_dev->streaming) { - konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG); - konica_stream_on(gspca_dev); - } - return 0; -} - -static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->whitebal; - - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) { - konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG); - konica_stream_on(gspca_dev); - } - return 0; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .other_input = 1, -#endif -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x04c8, 0x0720)}, /* Intel YC 76 */ - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -config USB_M5602 - tristate "ALi USB m5602 Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the - ALi m5602 connected to various image sensors. - - See for more info. - - To compile this driver as a module, choose M here: the - module will be called gspca_m5602. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_bridge.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_bridge.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_bridge.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_bridge.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,163 +0,0 @@ -/* - * USB Driver for ALi m5602 based webcams - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#ifndef M5602_BRIDGE_H_ -#define M5602_BRIDGE_H_ - -#include -#include "gspca.h" - -#define MODULE_NAME "ALi m5602" - -/*****************************************************************************/ - -#define M5602_XB_SENSOR_TYPE 0x00 -#define M5602_XB_SENSOR_CTRL 0x01 -#define M5602_XB_LINE_OF_FRAME_H 0x02 -#define M5602_XB_LINE_OF_FRAME_L 0x03 -#define M5602_XB_PIX_OF_LINE_H 0x04 -#define M5602_XB_PIX_OF_LINE_L 0x05 -#define M5602_XB_VSYNC_PARA 0x06 -#define M5602_XB_HSYNC_PARA 0x07 -#define M5602_XB_TEST_MODE_1 0x08 -#define M5602_XB_TEST_MODE_2 0x09 -#define M5602_XB_SIG_INI 0x0a -#define M5602_XB_DS_PARA 0x0e -#define M5602_XB_TRIG_PARA 0x0f -#define M5602_XB_CLK_PD 0x10 -#define M5602_XB_MCU_CLK_CTRL 0x12 -#define M5602_XB_MCU_CLK_DIV 0x13 -#define M5602_XB_SEN_CLK_CTRL 0x14 -#define M5602_XB_SEN_CLK_DIV 0x15 -#define M5602_XB_AUD_CLK_CTRL 0x16 -#define M5602_XB_AUD_CLK_DIV 0x17 -#define M5602_OB_AC_LINK_STATE 0x22 -#define M5602_OB_PCM_SLOT_INDEX 0x24 -#define M5602_OB_GPIO_SLOT_INDEX 0x25 -#define M5602_OB_ACRX_STATUS_ADDRESS_H 0x28 -#define M5602_OB_ACRX_STATUS_DATA_L 0x29 -#define M5602_OB_ACRX_STATUS_DATA_H 0x2a -#define M5602_OB_ACTX_COMMAND_ADDRESS 0x31 -#define M5602_OB_ACRX_COMMAND_DATA_L 0x32 -#define M5602_OB_ACTX_COMMAND_DATA_H 0X33 -#define M5602_XB_DEVCTR1 0x41 -#define M5602_XB_EPSETR0 0x42 -#define M5602_XB_EPAFCTR 0x47 -#define M5602_XB_EPBFCTR 0x49 -#define M5602_XB_EPEFCTR 0x4f -#define M5602_XB_TEST_REG 0x53 -#define M5602_XB_ALT2SIZE 0x54 -#define M5602_XB_ALT3SIZE 0x55 -#define M5602_XB_OBSFRAME 0x56 -#define M5602_XB_PWR_CTL 0x59 -#define M5602_XB_ADC_CTRL 0x60 -#define M5602_XB_ADC_DATA 0x61 -#define M5602_XB_MISC_CTRL 0x62 -#define M5602_XB_SNAPSHOT 0x63 -#define M5602_XB_SCRATCH_1 0x64 -#define M5602_XB_SCRATCH_2 0x65 -#define M5602_XB_SCRATCH_3 0x66 -#define M5602_XB_SCRATCH_4 0x67 -#define M5602_XB_I2C_CTRL 0x68 -#define M5602_XB_I2C_CLK_DIV 0x69 -#define M5602_XB_I2C_DEV_ADDR 0x6a -#define M5602_XB_I2C_REG_ADDR 0x6b -#define M5602_XB_I2C_DATA 0x6c -#define M5602_XB_I2C_STATUS 0x6d -#define M5602_XB_GPIO_DAT_H 0x70 -#define M5602_XB_GPIO_DAT_L 0x71 -#define M5602_XB_GPIO_DIR_H 0x72 -#define M5602_XB_GPIO_DIR_L 0x73 -#define M5602_XB_GPIO_EN_H 0x74 -#define M5602_XB_GPIO_EN_L 0x75 -#define M5602_XB_GPIO_DAT 0x76 -#define M5602_XB_GPIO_DIR 0x77 -#define M5602_XB_SEN_CLK_CONTROL 0x80 -#define M5602_XB_SEN_CLK_DIVISION 0x81 -#define M5602_XB_CPR_CLK_CONTROL 0x82 -#define M5602_XB_CPR_CLK_DIVISION 0x83 -#define M5602_XB_MCU_CLK_CONTROL 0x84 -#define M5602_XB_MCU_CLK_DIVISION 0x85 -#define M5602_XB_DCT_CLK_CONTROL 0x86 -#define M5602_XB_DCT_CLK_DIVISION 0x87 -#define M5602_XB_EC_CLK_CONTROL 0x88 -#define M5602_XB_EC_CLK_DIVISION 0x89 -#define M5602_XB_LBUF_CLK_CONTROL 0x8a -#define M5602_XB_LBUF_CLK_DIVISION 0x8b - -#define I2C_BUSY 0x80 - -/*****************************************************************************/ - -/* Driver info */ -#define DRIVER_AUTHOR "ALi m5602 Linux Driver Project" -#define DRIVER_DESC "ALi m5602 webcam driver" - -#define M5602_ISOC_ENDPOINT_ADDR 0x81 -#define M5602_INTR_ENDPOINT_ADDR 0x82 - -#define M5602_URB_MSG_TIMEOUT 5000 - -/*****************************************************************************/ - -/* A skeleton used for sending messages to the m5602 bridge */ -static const unsigned char bridge_urb_skeleton[] = { - 0x13, 0x00, 0x81, 0x00 -}; - -/* A skeleton used for sending messages to the sensor */ -static const unsigned char sensor_urb_skeleton[] = { - 0x23, M5602_XB_GPIO_EN_H, 0x81, 0x06, - 0x23, M5602_XB_MISC_CTRL, 0x81, 0x80, - 0x13, M5602_XB_I2C_DEV_ADDR, 0x81, 0x00, - 0x13, M5602_XB_I2C_REG_ADDR, 0x81, 0x00, - 0x13, M5602_XB_I2C_DATA, 0x81, 0x00, - 0x13, M5602_XB_I2C_CTRL, 0x81, 0x11 -}; - -struct sd { - struct gspca_dev gspca_dev; - - /* A pointer to the currently connected sensor */ - const struct m5602_sensor *sensor; - - struct sd_desc *desc; - - /* Sensor private data */ - void *sensor_priv; - - /* The current frame's id, used to detect frame boundaries */ - u8 frame_id; - - /* The current frame count */ - u32 frame_count; -}; - -int m5602_read_bridge( - struct sd *sd, const u8 address, u8 *i2c_data); - -int m5602_write_bridge( - struct sd *sd, const u8 address, const u8 i2c_data); - -int m5602_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - -int m5602_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,434 +0,0 @@ - /* - * USB Driver for ALi m5602 based webcams - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#include "m5602_ov9650.h" -#include "m5602_ov7660.h" -#include "m5602_mt9m111.h" -#include "m5602_po1030.h" -#include "m5602_s5k83a.h" -#include "m5602_s5k4aa.h" - -/* Kernel module parameters */ -int force_sensor; -static int dump_bridge; -int dump_sensor; - -static const struct usb_device_id m5602_table[] = { - {USB_DEVICE(0x0402, 0x5602)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, m5602_table); - -/* Reads a byte from the m5602 */ -int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data) -{ - int err; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x04, 0xc0, 0x14, - 0x8100 + address, buf, - 1, M5602_URB_MSG_TIMEOUT); - *i2c_data = buf[0]; - - PDEBUG(D_CONF, "Reading bridge register 0x%x containing 0x%x", - address, *i2c_data); - - /* usb_control_msg(...) returns the number of bytes sent upon success, - mask that and return zero instead*/ - return (err < 0) ? err : 0; -} - -/* Writes a byte to the m5602 */ -int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data) -{ - int err; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - PDEBUG(D_CONF, "Writing bridge register 0x%x with 0x%x", - address, i2c_data); - - memcpy(buf, bridge_urb_skeleton, - sizeof(bridge_urb_skeleton)); - buf[1] = address; - buf[3] = i2c_data; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x19, - 0x0000, buf, - 4, M5602_URB_MSG_TIMEOUT); - - /* usb_control_msg(...) returns the number of bytes sent upon success, - mask that and return zero instead */ - return (err < 0) ? err : 0; -} - -static int m5602_wait_for_i2c(struct sd *sd) -{ - int err; - u8 data; - - do { - err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data); - } while ((data & I2C_BUSY) && !err); - return err; -} - -int m5602_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - - if (!len || len > sd->sensor->i2c_regW) - return -EINVAL; - - err = m5602_wait_for_i2c(sd); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, - sd->sensor->i2c_slave_id); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); - if (err < 0) - return err; - - /* Sensors with registers that are of only - one byte width are differently read */ - - /* FIXME: This works with the ov9650, but has issues with the po1030 */ - if (sd->sensor->i2c_regW == 1) { - err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 1); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08); - } else { - err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len); - } - - for (i = 0; (i < len) && !err; i++) { - err = m5602_wait_for_i2c(sd); - if (err < 0) - return err; - - err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); - - PDEBUG(D_CONF, "Reading sensor register " - "0x%x containing 0x%x ", address, *i2c_data); - } - return err; -} - -int m5602_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - u8 *p; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - /* No sensor with a data width larger than 16 bits has yet been seen */ - if (len > sd->sensor->i2c_regW || !len) - return -EINVAL; - - memcpy(buf, sensor_urb_skeleton, - sizeof(sensor_urb_skeleton)); - - buf[11] = sd->sensor->i2c_slave_id; - buf[15] = address; - - /* Special case larger sensor writes */ - p = buf + 16; - - /* Copy a four byte write sequence for each byte to be written to */ - for (i = 0; i < len; i++) { - memcpy(p, sensor_urb_skeleton + 16, 4); - p[3] = i2c_data[i]; - p += 4; - PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x", - address, i2c_data[i]); - } - - /* Copy the tailer */ - memcpy(p, sensor_urb_skeleton + 20, 4); - - /* Set the total length */ - p[3] = 0x10 + len; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x19, - 0x0000, buf, - 20 + len * 4, M5602_URB_MSG_TIMEOUT); - - return (err < 0) ? err : 0; -} - -/* Dump all the registers of the m5602 bridge, - unfortunately this breaks the camera until it's power cycled */ -static void m5602_dump_bridge(struct sd *sd) -{ - int i; - for (i = 0; i < 0x80; i++) { - unsigned char val = 0; - m5602_read_bridge(sd, i, &val); - info("ALi m5602 address 0x%x contains 0x%x", i, val); - } - info("Warning: The ALi m5602 webcam probably won't work " - "until it's power cycled"); -} - -static int m5602_probe_sensor(struct sd *sd) -{ - /* Try the po1030 */ - sd->sensor = &po1030; - if (!sd->sensor->probe(sd)) - return 0; - - /* Try the mt9m111 sensor */ - sd->sensor = &mt9m111; - if (!sd->sensor->probe(sd)) - return 0; - - /* Try the s5k4aa */ - sd->sensor = &s5k4aa; - if (!sd->sensor->probe(sd)) - return 0; - - /* Try the ov9650 */ - sd->sensor = &ov9650; - if (!sd->sensor->probe(sd)) - return 0; - - /* Try the ov7660 */ - sd->sensor = &ov7660; - if (!sd->sensor->probe(sd)) - return 0; - - /* Try the s5k83a */ - sd->sensor = &s5k83a; - if (!sd->sensor->probe(sd)) - return 0; - - /* More sensor probe function goes here */ - info("Failed to find a sensor"); - sd->sensor = NULL; - return -ENODEV; -} - -static int m5602_configure(struct gspca_dev *gspca_dev, - const struct usb_device_id *id); - -static int m5602_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int err; - - PDEBUG(D_CONF, "Initializing ALi m5602 webcam"); - /* Run the init sequence */ - err = sd->sensor->init(sd); - - return err; -} - -static int m5602_start_transfer(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 *buf = sd->gspca_dev.usb_buf; - int err; - - /* Send start command to the camera */ - const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01}; - - if (sd->sensor->start) - sd->sensor->start(sd); - - memcpy(buf, buffer, sizeof(buffer)); - err = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x04, 0x40, 0x19, 0x0000, buf, - sizeof(buffer), M5602_URB_MSG_TIMEOUT); - - PDEBUG(D_STREAM, "Transfer started"); - return (err < 0) ? err : 0; -} - -static void m5602_urb_complete(struct gspca_dev *gspca_dev, - u8 *data, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (len < 6) { - PDEBUG(D_PACK, "Packet is less than 6 bytes"); - return; - } - - /* Frame delimiter: ff xx xx xx ff ff */ - if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff && - data[2] != sd->frame_id) { - PDEBUG(D_FRAM, "Frame delimiter detected"); - sd->frame_id = data[2]; - - /* Remove the extra fluff appended on each header */ - data += 6; - len -= 6; - - /* Complete the last frame (if any) */ - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - sd->frame_count++; - - /* Create a new frame */ - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - - PDEBUG(D_FRAM, "Starting new frame %d", - sd->frame_count); - - } else { - int cur_frame_len; - - cur_frame_len = gspca_dev->image_len; - /* Remove urb header */ - data += 4; - len -= 4; - - if (cur_frame_len + len <= gspca_dev->frsz) { - PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes", - sd->frame_count, len); - - gspca_frame_add(gspca_dev, INTER_PACKET, - data, len); - } else { - /* Add the remaining data up to frame size */ - gspca_frame_add(gspca_dev, INTER_PACKET, data, - gspca_dev->frsz - cur_frame_len); - } - } -} - -static void m5602_stop_transfer(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* Run the sensor specific end transfer sequence */ - if (sd->sensor->stop) - sd->sensor->stop(sd); -} - -/* sub-driver description, the ctrl and nctrl is filled at probe time */ -static struct sd_desc sd_desc = { - .name = MODULE_NAME, - .config = m5602_configure, - .init = m5602_init, - .start = m5602_start_transfer, - .stopN = m5602_stop_transfer, - .pkt_scan = m5602_urb_complete -}; - -/* this function is called at probe time */ -static int m5602_configure(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - int err; - - cam = &gspca_dev->cam; - sd->desc = &sd_desc; - - if (dump_bridge) - m5602_dump_bridge(sd); - - /* Probe sensor */ - err = m5602_probe_sensor(sd); - if (err) - goto fail; - - return 0; - -fail: - PDEBUG(D_ERR, "ALi m5602 webcam failed"); - cam->cam_mode = NULL; - cam->nmodes = 0; - - return err; -} - -static int m5602_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static void m5602_disconnect(struct usb_interface *intf) -{ - struct gspca_dev *gspca_dev = usb_get_intfdata(intf); - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->sensor->disconnect) - sd->sensor->disconnect(sd); - - gspca_disconnect(intf); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = m5602_table, - .probe = m5602_probe, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif - .disconnect = m5602_disconnect -}; - -/* -- module insert / remove -- */ -static int __init mod_m5602_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit mod_m5602_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(mod_m5602_init); -module_exit(mod_m5602_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -module_param(force_sensor, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(force_sensor, - "forces detection of a sensor, " - "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, " - "4 = MT9M111, 5 = PO1030, 6 = OV7660"); - -module_param(dump_bridge, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup"); - -module_param(dump_sensor, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers " - "at startup providing a sensor is found"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,645 +0,0 @@ -/* - * Driver for the mt9m111 sensor - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#include "m5602_mt9m111.h" - -static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val); -static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val); -static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); - -static struct v4l2_pix_format mt9m111_modes[] = { - { - 640, - 480, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = 640 * 480, - .bytesperline = 640, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - } -}; - -static const struct ctrl mt9m111_ctrls[] = { -#define VFLIP_IDX 0 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = mt9m111_set_vflip, - .get = mt9m111_get_vflip - }, -#define HFLIP_IDX 1 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = mt9m111_set_hflip, - .get = mt9m111_get_hflip - }, -#define GAIN_IDX 2 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0, - .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, - .step = 1, - .default_value = MT9M111_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = mt9m111_set_gain, - .get = mt9m111_get_gain - }, -#define AUTO_WHITE_BALANCE_IDX 3 - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = mt9m111_set_auto_white_balance, - .get = mt9m111_get_auto_white_balance - }, -#define GREEN_BALANCE_IDX 4 - { - { - .id = M5602_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x7ff, - .step = 0x1, - .default_value = MT9M111_GREEN_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = mt9m111_set_green_balance, - .get = mt9m111_get_green_balance - }, -#define BLUE_BALANCE_IDX 5 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x7ff, - .step = 0x1, - .default_value = MT9M111_BLUE_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = mt9m111_set_blue_balance, - .get = mt9m111_get_blue_balance - }, -#define RED_BALANCE_IDX 5 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x7ff, - .step = 0x1, - .default_value = MT9M111_RED_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = mt9m111_set_red_balance, - .get = mt9m111_get_red_balance - }, -}; - -static void mt9m111_dump_registers(struct sd *sd); - -int mt9m111_probe(struct sd *sd) -{ - u8 data[2] = {0x00, 0x00}; - int i; - s32 *sensor_settings; - - if (force_sensor) { - if (force_sensor == MT9M111_SENSOR) { - info("Forcing a %s sensor", mt9m111.name); - goto sensor_found; - } - /* If we want to force another sensor, don't try to probe this - * one */ - return -ENODEV; - } - - PDEBUG(D_PROBE, "Probing for a mt9m111 sensor"); - - /* Do the preinit */ - for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { - if (preinit_mt9m111[i][0] == BRIDGE) { - m5602_write_bridge(sd, - preinit_mt9m111[i][1], - preinit_mt9m111[i][2]); - } else { - data[0] = preinit_mt9m111[i][2]; - data[1] = preinit_mt9m111[i][3]; - m5602_write_sensor(sd, - preinit_mt9m111[i][1], data, 2); - } - } - - if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) - return -ENODEV; - - if ((data[0] == 0x14) && (data[1] == 0x3a)) { - info("Detected a mt9m111 sensor"); - goto sensor_found; - } - - return -ENODEV; - -sensor_found: - sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32), - GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - - sd->gspca_dev.cam.cam_mode = mt9m111_modes; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes); - sd->desc->ctrls = mt9m111_ctrls; - sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls); - - for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++) - sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; - - return 0; -} - -int mt9m111_init(struct sd *sd) -{ - int i, err = 0; - s32 *sensor_settings = sd->sensor_priv; - - /* Init the sensor */ - for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) { - u8 data[2]; - - if (init_mt9m111[i][0] == BRIDGE) { - err = m5602_write_bridge(sd, - init_mt9m111[i][1], - init_mt9m111[i][2]); - } else { - data[0] = init_mt9m111[i][2]; - data[1] = init_mt9m111[i][3]; - err = m5602_write_sensor(sd, - init_mt9m111[i][1], data, 2); - } - } - - if (dump_sensor) - mt9m111_dump_registers(sd); - - err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); - if (err < 0) - return err; - - err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; - - err = mt9m111_set_green_balance(&sd->gspca_dev, - sensor_settings[GREEN_BALANCE_IDX]); - if (err < 0) - return err; - - err = mt9m111_set_blue_balance(&sd->gspca_dev, - sensor_settings[BLUE_BALANCE_IDX]); - if (err < 0) - return err; - - err = mt9m111_set_red_balance(&sd->gspca_dev, - sensor_settings[RED_BALANCE_IDX]); - if (err < 0) - return err; - - return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); -} - -int mt9m111_start(struct sd *sd) -{ - int i, err = 0; - u8 data[2]; - struct cam *cam = &sd->gspca_dev.cam; - s32 *sensor_settings = sd->sensor_priv; - - int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1; - int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; - - for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) { - if (start_mt9m111[i][0] == BRIDGE) { - err = m5602_write_bridge(sd, - start_mt9m111[i][1], - start_mt9m111[i][2]); - } else { - data[0] = start_mt9m111[i][2]; - data[1] = start_mt9m111[i][3]; - err = m5602_write_sensor(sd, - start_mt9m111[i][1], data, 2); - } - } - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); - if (err < 0) - return err; - - for (i = 0; i < 2 && !err; i++) - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); - if (err < 0) - return err; - - for (i = 0; i < 2 && !err; i++) - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, - (width >> 8) & 0xff); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); - if (err < 0) - return err; - - switch (width) { - case 640: - PDEBUG(D_V4L2, "Configuring camera for VGA mode"); - data[0] = MT9M111_RMB_OVER_SIZED; - data[1] = MT9M111_RMB_ROW_SKIP_2X | - MT9M111_RMB_COLUMN_SKIP_2X | - (sensor_settings[VFLIP_IDX] << 0) | - (sensor_settings[HFLIP_IDX] << 1); - - err = m5602_write_sensor(sd, - MT9M111_SC_R_MODE_CONTEXT_B, data, 2); - break; - - case 320: - PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); - data[0] = MT9M111_RMB_OVER_SIZED; - data[1] = MT9M111_RMB_ROW_SKIP_4X | - MT9M111_RMB_COLUMN_SKIP_4X | - (sensor_settings[VFLIP_IDX] << 0) | - (sensor_settings[HFLIP_IDX] << 1); - err = m5602_write_sensor(sd, - MT9M111_SC_R_MODE_CONTEXT_B, data, 2); - break; - } - return err; -} - -void mt9m111_disconnect(struct sd *sd) -{ - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - -static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[2] = {0x00, 0x00}; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set vertical flip to %d", val); - - sensor_settings[VFLIP_IDX] = val; - - /* The mt9m111 is flipped by default */ - val = !val; - - /* Set the correct page map */ - err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); - if (err < 0) - return err; - - data[1] = (data[1] & 0xfe) | val; - err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, - data, 2); - return err; -} - -static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - - return 0; -} - -static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[2] = {0x00, 0x00}; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - - sensor_settings[HFLIP_IDX] = val; - - /* The mt9m111 is flipped by default */ - val = !val; - - /* Set the correct page map */ - err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); - if (err < 0) - return err; - - data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02); - err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, - data, 2); - return err; -} - -static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); - - return 0; -} - -static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - int err; - u8 data[2]; - - err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); - if (err < 0) - return err; - - sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01; - data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1)); - - err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); - - PDEBUG(D_V4L2, "Set auto white balance %d", val); - return err; -} - -static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val) { - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read auto white balance %d", *val); - return 0; -} - -static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err, tmp; - u8 data[2] = {0x00, 0x00}; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[GAIN_IDX] = val; - - /* Set the correct page map */ - err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); - if (err < 0) - return err; - - if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2) - return -EINVAL; - - if ((val >= INITIAL_MAX_GAIN * 2 * 2) && - (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2)) - tmp = (1 << 10) | (val << 9) | - (val << 8) | (val / 8); - else if ((val >= INITIAL_MAX_GAIN * 2) && - (val < INITIAL_MAX_GAIN * 2 * 2)) - tmp = (1 << 9) | (1 << 8) | (val / 4); - else if ((val >= INITIAL_MAX_GAIN) && - (val < INITIAL_MAX_GAIN * 2)) - tmp = (1 << 8) | (val / 2); - else - tmp = val; - - data[1] = (tmp & 0xff); - data[0] = (tmp & 0xff00) >> 8; - PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp, - data[1], data[0]); - - err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN, - data, 2); - - return err; -} - -static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[2]; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[GREEN_BALANCE_IDX] = val; - data[1] = (val & 0xff); - data[0] = (val & 0xff00) >> 8; - - PDEBUG(D_V4L2, "Set green balance %d", val); - err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN, - data, 2); - if (err < 0) - return err; - - return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN, - data, 2); -} - -static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GREEN_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read green balance %d", *val); - return 0; -} - -static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - u8 data[2]; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[BLUE_BALANCE_IDX] = val; - data[1] = (val & 0xff); - data[0] = (val & 0xff00) >> 8; - - PDEBUG(D_V4L2, "Set blue balance %d", val); - - return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN, - data, 2); -} - -static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BLUE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read blue balance %d", *val); - return 0; -} - -static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - u8 data[2]; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[RED_BALANCE_IDX] = val; - data[1] = (val & 0xff); - data[0] = (val & 0xff00) >> 8; - - PDEBUG(D_V4L2, "Set red balance %d", val); - - return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN, - data, 2); -} - -static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[RED_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read red balance %d", *val); - return 0; -} - -static void mt9m111_dump_registers(struct sd *sd) -{ - u8 address, value[2] = {0x00, 0x00}; - - info("Dumping the mt9m111 register state"); - - info("Dumping the mt9m111 sensor core registers"); - value[1] = MT9M111_SENSOR_CORE; - m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); - for (address = 0; address < 0xff; address++) { - m5602_read_sensor(sd, address, value, 2); - info("register 0x%x contains 0x%x%x", - address, value[0], value[1]); - } - - info("Dumping the mt9m111 color pipeline registers"); - value[1] = MT9M111_COLORPIPE; - m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); - for (address = 0; address < 0xff; address++) { - m5602_read_sensor(sd, address, value, 2); - info("register 0x%x contains 0x%x%x", - address, value[0], value[1]); - } - - info("Dumping the mt9m111 camera control registers"); - value[1] = MT9M111_CAMERA_CONTROL; - m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); - for (address = 0; address < 0xff; address++) { - m5602_read_sensor(sd, address, value, 2); - info("register 0x%x contains 0x%x%x", - address, value[0], value[1]); - } - - info("mt9m111 register state dump complete"); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,271 +0,0 @@ -/* - * Driver for the mt9m111 sensor - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * Some defines taken from the mt9m111 sensor driver - * Copyright (C) 2008, Robert Jarzmik - * - * 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, version 2. - * - */ - -#ifndef M5602_MT9M111_H_ -#define M5602_MT9M111_H_ - -#include "m5602_sensor.h" - -/*****************************************************************************/ - -#define MT9M111_SC_CHIPVER 0x00 -#define MT9M111_SC_ROWSTART 0x01 -#define MT9M111_SC_COLSTART 0x02 -#define MT9M111_SC_WINDOW_HEIGHT 0x03 -#define MT9M111_SC_WINDOW_WIDTH 0x04 -#define MT9M111_SC_HBLANK_CONTEXT_B 0x05 -#define MT9M111_SC_VBLANK_CONTEXT_B 0x06 -#define MT9M111_SC_HBLANK_CONTEXT_A 0x07 -#define MT9M111_SC_VBLANK_CONTEXT_A 0x08 -#define MT9M111_SC_SHUTTER_WIDTH 0x09 -#define MT9M111_SC_ROW_SPEED 0x0a -#define MT9M111_SC_EXTRA_DELAY 0x0b -#define MT9M111_SC_SHUTTER_DELAY 0x0c -#define MT9M111_SC_RESET 0x0d -#define MT9M111_SC_R_MODE_CONTEXT_B 0x20 -#define MT9M111_SC_R_MODE_CONTEXT_A 0x21 -#define MT9M111_SC_FLASH_CONTROL 0x23 -#define MT9M111_SC_GREEN_1_GAIN 0x2b -#define MT9M111_SC_BLUE_GAIN 0x2c -#define MT9M111_SC_RED_GAIN 0x2d -#define MT9M111_SC_GREEN_2_GAIN 0x2e -#define MT9M111_SC_GLOBAL_GAIN 0x2f - -#define MT9M111_CONTEXT_CONTROL 0xc8 -#define MT9M111_PAGE_MAP 0xf0 -#define MT9M111_BYTEWISE_ADDRESS 0xf1 - -#define MT9M111_CP_OPERATING_MODE_CTL 0x06 -#define MT9M111_CP_LUMA_OFFSET 0x34 -#define MT9M111_CP_LUMA_CLIP 0x35 -#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A 0x3a -#define MT9M111_CP_LENS_CORRECTION_1 0x3b -#define MT9M111_CP_DEFECT_CORR_CONTEXT_A 0x4c -#define MT9M111_CP_DEFECT_CORR_CONTEXT_B 0x4d -#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B 0x9b -#define MT9M111_CP_GLOBAL_CLK_CONTROL 0xb3 - -#define MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18 0x65 -#define MT9M111_CC_AWB_PARAMETER_7 0x28 - -#define MT9M111_SENSOR_CORE 0x00 -#define MT9M111_COLORPIPE 0x01 -#define MT9M111_CAMERA_CONTROL 0x02 - -#define MT9M111_RESET (1 << 0) -#define MT9M111_RESTART (1 << 1) -#define MT9M111_ANALOG_STANDBY (1 << 2) -#define MT9M111_CHIP_ENABLE (1 << 3) -#define MT9M111_CHIP_DISABLE (0 << 3) -#define MT9M111_OUTPUT_DISABLE (1 << 4) -#define MT9M111_SHOW_BAD_FRAMES (1 << 0) -#define MT9M111_RESTART_BAD_FRAMES (1 << 1) -#define MT9M111_SYNCHRONIZE_CHANGES (1 << 7) - -#define MT9M111_RMB_OVER_SIZED (1 << 0) -#define MT9M111_RMB_MIRROR_ROWS (1 << 0) -#define MT9M111_RMB_MIRROR_COLS (1 << 1) -#define MT9M111_RMB_ROW_SKIP_2X (1 << 2) -#define MT9M111_RMB_COLUMN_SKIP_2X (1 << 3) -#define MT9M111_RMB_ROW_SKIP_4X (1 << 4) -#define MT9M111_RMB_COLUMN_SKIP_4X (1 << 5) - -#define MT9M111_COLOR_MATRIX_BYPASS (1 << 4) -#define MT9M111_SEL_CONTEXT_B (1 << 3) - -#define MT9M111_TRISTATE_PIN_IN_STANDBY (1 << 1) -#define MT9M111_SOC_SOFT_STANDBY (1 << 0) - -#define MT9M111_2D_DEFECT_CORRECTION_ENABLE (1 << 0) - -#define INITIAL_MAX_GAIN 64 -#define MT9M111_DEFAULT_GAIN 283 -#define MT9M111_GREEN_GAIN_DEFAULT 0x20 -#define MT9M111_BLUE_GAIN_DEFAULT 0x20 -#define MT9M111_RED_GAIN_DEFAULT 0x20 - -/*****************************************************************************/ - -/* Kernel module parameters */ -extern int force_sensor; -extern int dump_sensor; - -int mt9m111_probe(struct sd *sd); -int mt9m111_init(struct sd *sd); -int mt9m111_start(struct sd *sd); -void mt9m111_disconnect(struct sd *sd); - -static const struct m5602_sensor mt9m111 = { - .name = "MT9M111", - - .i2c_slave_id = 0xba, - .i2c_regW = 2, - - .probe = mt9m111_probe, - .init = mt9m111_init, - .disconnect = mt9m111_disconnect, - .start = mt9m111_start, -}; - -static const unsigned char preinit_mt9m111[][4] = { - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, - MT9M111_RESET | - MT9M111_RESTART | - MT9M111_ANALOG_STANDBY | - MT9M111_CHIP_DISABLE, - MT9M111_SHOW_BAD_FRAMES | - MT9M111_RESTART_BAD_FRAMES | - MT9M111_SYNCHRONIZE_CHANGES}, - - {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00} -}; - -static const unsigned char init_mt9m111[][4] = { - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, - - {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, - MT9M111_CP_OPERATING_MODE_CTL}, - {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, - MT9M111_2D_DEFECT_CORRECTION_ENABLE}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, - MT9M111_2D_DEFECT_CORRECTION_ENABLE}, - {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, - {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, - {SENSOR, 0xcd, 0x00, 0x0e}, - {SENSOR, 0xd0, 0x00, 0x40}, - - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, - {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, - - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, 0x33, 0x03, 0x49}, - {SENSOR, 0x34, 0xc0, 0x19}, - {SENSOR, 0x3f, 0x20, 0x20}, - {SENSOR, 0x40, 0x20, 0x20}, - {SENSOR, 0x5a, 0xc0, 0x0a}, - {SENSOR, 0x70, 0x7b, 0x0a}, - {SENSOR, 0x71, 0xff, 0x00}, - {SENSOR, 0x72, 0x19, 0x0e}, - {SENSOR, 0x73, 0x18, 0x0f}, - {SENSOR, 0x74, 0x57, 0x32}, - {SENSOR, 0x75, 0x56, 0x34}, - {SENSOR, 0x76, 0x73, 0x35}, - {SENSOR, 0x77, 0x30, 0x12}, - {SENSOR, 0x78, 0x79, 0x02}, - {SENSOR, 0x79, 0x75, 0x06}, - {SENSOR, 0x7a, 0x77, 0x0a}, - {SENSOR, 0x7b, 0x78, 0x09}, - {SENSOR, 0x7c, 0x7d, 0x06}, - {SENSOR, 0x7d, 0x31, 0x10}, - {SENSOR, 0x7e, 0x00, 0x7e}, - {SENSOR, 0x80, 0x59, 0x04}, - {SENSOR, 0x81, 0x59, 0x04}, - {SENSOR, 0x82, 0x57, 0x0a}, - {SENSOR, 0x83, 0x58, 0x0b}, - {SENSOR, 0x84, 0x47, 0x0c}, - {SENSOR, 0x85, 0x48, 0x0e}, - {SENSOR, 0x86, 0x5b, 0x02}, - {SENSOR, 0x87, 0x00, 0x5c}, - {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, MT9M111_SEL_CONTEXT_B}, - {SENSOR, 0x60, 0x00, 0x80}, - {SENSOR, 0x61, 0x00, 0x00}, - {SENSOR, 0x62, 0x00, 0x00}, - {SENSOR, 0x63, 0x00, 0x00}, - {SENSOR, 0x64, 0x00, 0x00}, - - {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, /* 13 */ - {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, /* 18 */ - {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, /* 1024 */ - {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, /* 1296 */ - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, /* 352 */ - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, /* 17 */ - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, /* 352 */ - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, /* 17 */ - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, /* 271 */ - {SENSOR, 0x30, 0x04, 0x00}, - /* Set number of blank rows chosen to 400 */ - {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90}, -}; - -static const unsigned char start_mt9m111[][4] = { - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,487 +0,0 @@ -/* - * Driver for the ov7660 sensor - * - * Copyright (C) 2009 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#include "m5602_ov7660.h" - -static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val); -static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val); -static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); -static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val); - -static const struct ctrl ov7660_ctrls[] = { -#define GAIN_IDX 1 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = OV7660_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov7660_set_gain, - .get = ov7660_get_gain - }, -#define BLUE_BALANCE_IDX 2 -#define RED_BALANCE_IDX 3 -#define AUTO_WHITE_BALANCE_IDX 4 - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov7660_set_auto_white_balance, - .get = ov7660_get_auto_white_balance - }, -#define AUTO_GAIN_CTRL_IDX 5 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto gain control", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov7660_set_auto_gain, - .get = ov7660_get_auto_gain - }, -#define AUTO_EXPOSURE_IDX 6 - { - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov7660_set_auto_exposure, - .get = ov7660_get_auto_exposure - }, -#define HFLIP_IDX 7 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = ov7660_set_hflip, - .get = ov7660_get_hflip - }, -#define VFLIP_IDX 8 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = ov7660_set_vflip, - .get = ov7660_get_vflip - }, - -}; - -static struct v4l2_pix_format ov7660_modes[] = { - { - 640, - 480, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = - 640 * 480, - .bytesperline = 640, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - } -}; - -static void ov7660_dump_registers(struct sd *sd); - -int ov7660_probe(struct sd *sd) -{ - int err = 0, i; - u8 prod_id = 0, ver_id = 0; - - s32 *sensor_settings; - - if (force_sensor) { - if (force_sensor == OV7660_SENSOR) { - info("Forcing an %s sensor", ov7660.name); - goto sensor_found; - } - /* If we want to force another sensor, - don't try to probe this one */ - return -ENODEV; - } - - /* Do the preinit */ - for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) { - u8 data[2]; - - if (preinit_ov7660[i][0] == BRIDGE) { - err = m5602_write_bridge(sd, - preinit_ov7660[i][1], - preinit_ov7660[i][2]); - } else { - data[0] = preinit_ov7660[i][2]; - err = m5602_write_sensor(sd, - preinit_ov7660[i][1], data, 1); - } - } - if (err < 0) - return err; - - if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1)) - return -ENODEV; - - if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1)) - return -ENODEV; - - info("Sensor reported 0x%x%x", prod_id, ver_id); - - if ((prod_id == 0x76) && (ver_id == 0x60)) { - info("Detected a ov7660 sensor"); - goto sensor_found; - } - return -ENODEV; - -sensor_found: - sensor_settings = kmalloc( - ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - - sd->gspca_dev.cam.cam_mode = ov7660_modes; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes); - sd->desc->ctrls = ov7660_ctrls; - sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls); - - for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++) - sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; - - return 0; -} - -int ov7660_init(struct sd *sd) -{ - int i, err = 0; - s32 *sensor_settings = sd->sensor_priv; - - /* Init the sensor */ - for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { - u8 data[2]; - - if (init_ov7660[i][0] == BRIDGE) { - err = m5602_write_bridge(sd, - init_ov7660[i][1], - init_ov7660[i][2]); - } else { - data[0] = init_ov7660[i][2]; - err = m5602_write_sensor(sd, - init_ov7660[i][1], data, 1); - } - } - - if (dump_sensor) - ov7660_dump_registers(sd); - - err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; - - err = ov7660_set_auto_white_balance(&sd->gspca_dev, - sensor_settings[AUTO_WHITE_BALANCE_IDX]); - if (err < 0) - return err; - - err = ov7660_set_auto_gain(&sd->gspca_dev, - sensor_settings[AUTO_GAIN_CTRL_IDX]); - if (err < 0) - return err; - - err = ov7660_set_auto_exposure(&sd->gspca_dev, - sensor_settings[AUTO_EXPOSURE_IDX]); - if (err < 0) - return err; - err = ov7660_set_hflip(&sd->gspca_dev, - sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; - - err = ov7660_set_vflip(&sd->gspca_dev, - sensor_settings[VFLIP_IDX]); - - return err; -} - -int ov7660_start(struct sd *sd) -{ - return 0; -} - -int ov7660_stop(struct sd *sd) -{ - return 0; -} - -void ov7660_disconnect(struct sd *sd) -{ - ov7660_stop(sd); - - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); - return 0; -} - -static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Setting gain to %d", val); - - sensor_settings[GAIN_IDX] = val; - - err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); - return err; -} - - -static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; - return 0; -} - -static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set auto white balance to %d", val); - - sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; - err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); - err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); - - return err; -} - -static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_GAIN_CTRL_IDX]; - PDEBUG(D_V4L2, "Read auto gain control %d", *val); - return 0; -} - -static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set auto gain control to %d", val); - - sensor_settings[AUTO_GAIN_CTRL_IDX] = val; - err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); - - return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); -} - -static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Read auto exposure control %d", *val); - return 0; -} - -static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, - __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set auto exposure control to %d", val); - - sensor_settings[AUTO_EXPOSURE_IDX] = val; - err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); - - return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); -} - -static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - return 0; -} - -static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - - sensor_settings[HFLIP_IDX] = val; - - i2c_data = ((val & 0x01) << 5) | - (sensor_settings[VFLIP_IDX] << 4); - - err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); - - return err; -} - -static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - -static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set vertical flip to %d", val); - sensor_settings[VFLIP_IDX] = val; - - i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); - err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); - if (err < 0) - return err; - - /* When vflip is toggled we need to readjust the bridge hsync/vsync */ - if (gspca_dev->streaming) - err = ov7660_start(sd); - - return err; -} - -static void ov7660_dump_registers(struct sd *sd) -{ - int address; - info("Dumping the ov7660 register state"); - for (address = 0; address < 0xa9; address++) { - u8 value; - m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); - } - - info("ov7660 register state dump complete"); - - info("Probing for which registers that are read/write"); - for (address = 0; address < 0xff; address++) { - u8 old_value, ctrl_value; - u8 test_value[2] = {0xff, 0xff}; - - m5602_read_sensor(sd, address, &old_value, 1); - m5602_write_sensor(sd, address, test_value, 1); - m5602_read_sensor(sd, address, &ctrl_value, 1); - - if (ctrl_value == test_value[0]) - info("register 0x%x is writeable", address); - else - info("register 0x%x is read only", address); - - /* Restore original value */ - m5602_write_sensor(sd, address, &old_value, 1); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,260 +0,0 @@ -/* - * Driver for the ov7660 sensor - * - * Copyright (C) 2009 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#ifndef M5602_OV7660_H_ -#define M5602_OV7660_H_ - -#include "m5602_sensor.h" - -#define OV7660_GAIN 0x00 -#define OV7660_BLUE_GAIN 0x01 -#define OV7660_RED_GAIN 0x02 -#define OV7660_VREF 0x03 -#define OV7660_COM1 0x04 -#define OV7660_BAVE 0x05 -#define OV7660_GEAVE 0x06 -#define OV7660_AECHH 0x07 -#define OV7660_RAVE 0x08 -#define OV7660_COM2 0x09 -#define OV7660_PID 0x0a -#define OV7660_VER 0x0b -#define OV7660_COM3 0x0c -#define OV7660_COM4 0x0d -#define OV7660_COM5 0x0e -#define OV7660_COM6 0x0f -#define OV7660_AECH 0x10 -#define OV7660_CLKRC 0x11 -#define OV7660_COM7 0x12 -#define OV7660_COM8 0x13 -#define OV7660_COM9 0x14 -#define OV7660_COM10 0x15 -#define OV7660_RSVD16 0x16 -#define OV7660_HSTART 0x17 -#define OV7660_HSTOP 0x18 -#define OV7660_VSTART 0x19 -#define OV7660_VSTOP 0x1a -#define OV7660_PSHFT 0x1b -#define OV7660_MIDH 0x1c -#define OV7660_MIDL 0x1d -#define OV7660_MVFP 0x1e -#define OV7660_LAEC 0x1f -#define OV7660_BOS 0x20 -#define OV7660_GBOS 0x21 -#define OV7660_GROS 0x22 -#define OV7660_ROS 0x23 -#define OV7660_AEW 0x24 -#define OV7660_AEB 0x25 -#define OV7660_VPT 0x26 -#define OV7660_BBIAS 0x27 -#define OV7660_GbBIAS 0x28 -#define OV7660_RSVD29 0x29 -#define OV7660_RBIAS 0x2c -#define OV7660_HREF 0x32 -#define OV7660_ADC 0x37 -#define OV7660_OFON 0x39 -#define OV7660_TSLB 0x3a -#define OV7660_COM12 0x3c -#define OV7660_COM13 0x3d -#define OV7660_LCC1 0x62 -#define OV7660_LCC2 0x63 -#define OV7660_LCC3 0x64 -#define OV7660_LCC4 0x65 -#define OV7660_LCC5 0x66 -#define OV7660_HV 0x69 -#define OV7660_RSVDA1 0xa1 - -#define OV7660_DEFAULT_GAIN 0x0e -#define OV7660_DEFAULT_RED_GAIN 0x80 -#define OV7660_DEFAULT_BLUE_GAIN 0x80 -#define OV7660_DEFAULT_SATURATION 0x00 -#define OV7660_DEFAULT_EXPOSURE 0x20 - -/* Kernel module parameters */ -extern int force_sensor; -extern int dump_sensor; - -int ov7660_probe(struct sd *sd); -int ov7660_init(struct sd *sd); -int ov7660_start(struct sd *sd); -int ov7660_stop(struct sd *sd); -void ov7660_disconnect(struct sd *sd); - -static const struct m5602_sensor ov7660 = { - .name = "ov7660", - .i2c_slave_id = 0x42, - .i2c_regW = 1, - .probe = ov7660_probe, - .init = ov7660_init, - .start = ov7660_start, - .stop = ov7660_stop, - .disconnect = ov7660_disconnect, -}; - -static const unsigned char preinit_ov7660[][4] = { - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - - {SENSOR, OV7660_OFON, 0x0c}, - {SENSOR, OV7660_COM2, 0x11}, - {SENSOR, OV7660_COM7, 0x05}, - - {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00} -}; - -static const unsigned char init_ov7660[][4] = { - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, - {SENSOR, OV7660_COM7, 0x80}, - {SENSOR, OV7660_CLKRC, 0x80}, - {SENSOR, OV7660_COM9, 0x4c}, - {SENSOR, OV7660_OFON, 0x43}, - {SENSOR, OV7660_COM12, 0x28}, - {SENSOR, OV7660_COM8, 0x00}, - {SENSOR, OV7660_COM10, 0x40}, - {SENSOR, OV7660_HSTART, 0x0c}, - {SENSOR, OV7660_HSTOP, 0x61}, - {SENSOR, OV7660_HREF, 0xa4}, - {SENSOR, OV7660_PSHFT, 0x0b}, - {SENSOR, OV7660_VSTART, 0x01}, - {SENSOR, OV7660_VSTOP, 0x7a}, - {SENSOR, OV7660_VSTOP, 0x00}, - {SENSOR, OV7660_COM7, 0x05}, - {SENSOR, OV7660_COM6, 0x42}, - {SENSOR, OV7660_BBIAS, 0x94}, - {SENSOR, OV7660_GbBIAS, 0x94}, - {SENSOR, OV7660_RSVD29, 0x94}, - {SENSOR, OV7660_RBIAS, 0x94}, - {SENSOR, OV7660_COM1, 0x00}, - {SENSOR, OV7660_AECH, 0x00}, - {SENSOR, OV7660_AECHH, 0x00}, - {SENSOR, OV7660_ADC, 0x05}, - {SENSOR, OV7660_COM13, 0x00}, - {SENSOR, OV7660_RSVDA1, 0x23}, - {SENSOR, OV7660_TSLB, 0x0d}, - {SENSOR, OV7660_HV, 0x80}, - {SENSOR, OV7660_LCC1, 0x00}, - {SENSOR, OV7660_LCC2, 0x00}, - {SENSOR, OV7660_LCC3, 0x10}, - {SENSOR, OV7660_LCC4, 0x40}, - {SENSOR, OV7660_LCC5, 0x01}, - - {SENSOR, OV7660_AECH, 0x20}, - {SENSOR, OV7660_COM1, 0x00}, - {SENSOR, OV7660_OFON, 0x0c}, - {SENSOR, OV7660_COM2, 0x11}, - {SENSOR, OV7660_COM7, 0x05}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, - {SENSOR, OV7660_AECH, 0x5f}, - {SENSOR, OV7660_COM1, 0x03}, - {SENSOR, OV7660_OFON, 0x0c}, - {SENSOR, OV7660_COM2, 0x11}, - {SENSOR, OV7660_COM7, 0x05}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, - {BRIDGE, M5602_XB_SIG_INI, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x08}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x27}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0xa7}, - {BRIDGE, M5602_XB_SIG_INI, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,880 +0,0 @@ -/* - * Driver for the ov9650 sensor - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#include "m5602_ov9650.h" - -static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val); -static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val); -static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val); - -/* Vertically and horizontally flips the image if matched, needed for machines - where the sensor is mounted upside down */ -static - const - struct dmi_system_id ov9650_flip_dmi_table[] = { - { - .ident = "ASUS A6Ja", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6J") - } - }, - { - .ident = "ASUS A6JC", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") - } - }, - { - .ident = "ASUS A6K", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6K") - } - }, - { - .ident = "ASUS A6Kt", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") - } - }, - { - .ident = "ASUS A6VA", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6VA") - } - }, - { - - .ident = "ASUS A6VC", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6VC") - } - }, - { - .ident = "ASUS A6VM", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6VM") - } - }, - { - .ident = "ASUS A7V", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A7V") - } - }, - { - .ident = "Alienware Aurora m9700", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "alienware"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700") - } - }, - {} -}; - -static const struct ctrl ov9650_ctrls[] = { -#define EXPOSURE_IDX 0 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x1ff, - .step = 0x4, - .default_value = EXPOSURE_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov9650_set_exposure, - .get = ov9650_get_exposure - }, -#define GAIN_IDX 1 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0x3ff, - .step = 0x1, - .default_value = GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov9650_set_gain, - .get = ov9650_get_gain - }, -#define RED_BALANCE_IDX 2 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = RED_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov9650_set_red_balance, - .get = ov9650_get_red_balance - }, -#define BLUE_BALANCE_IDX 3 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = BLUE_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov9650_set_blue_balance, - .get = ov9650_get_blue_balance - }, -#define HFLIP_IDX 4 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = ov9650_set_hflip, - .get = ov9650_get_hflip - }, -#define VFLIP_IDX 5 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = ov9650_set_vflip, - .get = ov9650_get_vflip - }, -#define AUTO_WHITE_BALANCE_IDX 6 - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov9650_set_auto_white_balance, - .get = ov9650_get_auto_white_balance - }, -#define AUTO_GAIN_CTRL_IDX 7 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto gain control", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov9650_set_auto_gain, - .get = ov9650_get_auto_gain - }, -#define AUTO_EXPOSURE_IDX 8 - { - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov9650_set_auto_exposure, - .get = ov9650_get_auto_exposure - } - -}; - -static struct v4l2_pix_format ov9650_modes[] = { - { - 176, - 144, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = - 176 * 144, - .bytesperline = 176, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 9 - }, { - 320, - 240, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = - 320 * 240, - .bytesperline = 320, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 8 - }, { - 352, - 288, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = - 352 * 288, - .bytesperline = 352, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 9 - }, { - 640, - 480, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = - 640 * 480, - .bytesperline = 640, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 9 - } -}; - -static void ov9650_dump_registers(struct sd *sd); - -int ov9650_probe(struct sd *sd) -{ - int err = 0; - u8 prod_id = 0, ver_id = 0, i; - s32 *sensor_settings; - - if (force_sensor) { - if (force_sensor == OV9650_SENSOR) { - info("Forcing an %s sensor", ov9650.name); - goto sensor_found; - } - /* If we want to force another sensor, - don't try to probe this one */ - return -ENODEV; - } - - PDEBUG(D_PROBE, "Probing for an ov9650 sensor"); - - /* Run the pre-init before probing the sensor */ - for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) { - u8 data = preinit_ov9650[i][2]; - if (preinit_ov9650[i][0] == SENSOR) - err = m5602_write_sensor(sd, - preinit_ov9650[i][1], &data, 1); - else - err = m5602_write_bridge(sd, - preinit_ov9650[i][1], data); - } - - if (err < 0) - return err; - - if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1)) - return -ENODEV; - - if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1)) - return -ENODEV; - - if ((prod_id == 0x96) && (ver_id == 0x52)) { - info("Detected an ov9650 sensor"); - goto sensor_found; - } - return -ENODEV; - -sensor_found: - sensor_settings = kmalloc( - ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - - sd->gspca_dev.cam.cam_mode = ov9650_modes; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes); - sd->desc->ctrls = ov9650_ctrls; - sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls); - - for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++) - sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; - return 0; -} - -int ov9650_init(struct sd *sd) -{ - int i, err = 0; - u8 data; - s32 *sensor_settings = sd->sensor_priv; - - if (dump_sensor) - ov9650_dump_registers(sd); - - for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) { - data = init_ov9650[i][2]; - if (init_ov9650[i][0] == SENSOR) - err = m5602_write_sensor(sd, init_ov9650[i][1], - &data, 1); - else - err = m5602_write_bridge(sd, init_ov9650[i][1], data); - } - - err = ov9650_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; - - err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; - - err = ov9650_set_red_balance(&sd->gspca_dev, - sensor_settings[RED_BALANCE_IDX]); - if (err < 0) - return err; - - err = ov9650_set_blue_balance(&sd->gspca_dev, - sensor_settings[BLUE_BALANCE_IDX]); - if (err < 0) - return err; - - err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; - - err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); - if (err < 0) - return err; - - err = ov9650_set_auto_exposure(&sd->gspca_dev, - sensor_settings[AUTO_EXPOSURE_IDX]); - if (err < 0) - return err; - - err = ov9650_set_auto_white_balance(&sd->gspca_dev, - sensor_settings[AUTO_WHITE_BALANCE_IDX]); - if (err < 0) - return err; - - err = ov9650_set_auto_gain(&sd->gspca_dev, - sensor_settings[AUTO_GAIN_CTRL_IDX]); - return err; -} - -int ov9650_start(struct sd *sd) -{ - u8 data; - int i, err = 0; - struct cam *cam = &sd->gspca_dev.cam; - s32 *sensor_settings = sd->sensor_priv; - - int width = cam->cam_mode[sd->gspca_dev.curr_mode].width; - int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; - int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; - int hor_offs = OV9650_LEFT_OFFSET; - - if ((!dmi_check_system(ov9650_flip_dmi_table) && - sensor_settings[VFLIP_IDX]) || - (dmi_check_system(ov9650_flip_dmi_table) && - !sensor_settings[VFLIP_IDX])) - ver_offs--; - - if (width <= 320) - hor_offs /= 2; - - /* Synthesize the vsync/hsync setup */ - for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) { - if (res_init_ov9650[i][0] == BRIDGE) - err = m5602_write_bridge(sd, res_init_ov9650[i][1], - res_init_ov9650[i][2]); - else if (res_init_ov9650[i][0] == SENSOR) { - data = res_init_ov9650[i][2]; - err = m5602_write_sensor(sd, - res_init_ov9650[i][1], &data, 1); - } - } - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, - ((ver_offs >> 8) & 0xff)); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff)); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); - if (err < 0) - return err; - - for (i = 0; i < 2 && !err; i++) - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, - (hor_offs >> 8) & 0xff); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, - ((width + hor_offs) >> 8) & 0xff); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, - ((width + hor_offs) & 0xff)); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); - if (err < 0) - return err; - - switch (width) { - case 640: - PDEBUG(D_V4L2, "Configuring camera for VGA mode"); - - data = OV9650_VGA_SELECT | OV9650_RGB_SELECT | - OV9650_RAW_RGB_SELECT; - err = m5602_write_sensor(sd, OV9650_COM7, &data, 1); - break; - - case 352: - PDEBUG(D_V4L2, "Configuring camera for CIF mode"); - - data = OV9650_CIF_SELECT | OV9650_RGB_SELECT | - OV9650_RAW_RGB_SELECT; - err = m5602_write_sensor(sd, OV9650_COM7, &data, 1); - break; - - case 320: - PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); - - data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT | - OV9650_RAW_RGB_SELECT; - err = m5602_write_sensor(sd, OV9650_COM7, &data, 1); - break; - - case 176: - PDEBUG(D_V4L2, "Configuring camera for QCIF mode"); - - data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT | - OV9650_RAW_RGB_SELECT; - err = m5602_write_sensor(sd, OV9650_COM7, &data, 1); - break; - } - return err; -} - -int ov9650_stop(struct sd *sd) -{ - u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X; - return m5602_write_sensor(sd, OV9650_COM2, &data, 1); -} - -void ov9650_disconnect(struct sd *sd) -{ - ov9650_stop(sd); - - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Read exposure %d", *val); - return 0; -} - -static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - PDEBUG(D_V4L2, "Set exposure to %d", val); - - sensor_settings[EXPOSURE_IDX] = val; - /* The 6 MSBs */ - i2c_data = (val >> 10) & 0x3f; - err = m5602_write_sensor(sd, OV9650_AECHM, - &i2c_data, 1); - if (err < 0) - return err; - - /* The 8 middle bits */ - i2c_data = (val >> 2) & 0xff; - err = m5602_write_sensor(sd, OV9650_AECH, - &i2c_data, 1); - if (err < 0) - return err; - - /* The 2 LSBs */ - i2c_data = val & 0x03; - err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1); - return err; -} - -static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); - return 0; -} - -static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Setting gain to %d", val); - - sensor_settings[GAIN_IDX] = val; - - /* The 2 MSB */ - /* Read the OV9650_VREF register first to avoid - corrupting the VREF high and low bits */ - err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); - if (err < 0) - return err; - - /* Mask away all uninteresting bits */ - i2c_data = ((val & 0x0300) >> 2) | - (i2c_data & 0x3f); - err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1); - if (err < 0) - return err; - - /* The 8 LSBs */ - i2c_data = val & 0xff; - err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); - return err; -} - -static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[RED_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read red gain %d", *val); - return 0; -} - -static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set red gain to %d", val); - - sensor_settings[RED_BALANCE_IDX] = val; - - i2c_data = val & 0xff; - err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1); - return err; -} - -static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BLUE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read blue gain %d", *val); - - return 0; -} - -static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set blue gain to %d", val); - - sensor_settings[BLUE_BALANCE_IDX] = val; - - i2c_data = val & 0xff; - err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); - return err; -} - -static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - return 0; -} - -static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - - sensor_settings[HFLIP_IDX] = val; - - if (!dmi_check_system(ov9650_flip_dmi_table)) - i2c_data = ((val & 0x01) << 5) | - (sensor_settings[VFLIP_IDX] << 4); - else - i2c_data = ((val & 0x01) << 5) | - (!sensor_settings[VFLIP_IDX] << 4); - - err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); - - return err; -} - -static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - -static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set vertical flip to %d", val); - sensor_settings[VFLIP_IDX] = val; - - if (dmi_check_system(ov9650_flip_dmi_table)) - val = !val; - - i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); - err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); - if (err < 0) - return err; - - /* When vflip is toggled we need to readjust the bridge hsync/vsync */ - if (gspca_dev->streaming) - err = ov9650_start(sd); - - return err; -} - -static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Read auto exposure control %d", *val); - return 0; -} - -static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, - __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set auto exposure control to %d", val); - - sensor_settings[AUTO_EXPOSURE_IDX] = val; - err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); - - return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); -} - -static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; - return 0; -} - -static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set auto white balance to %d", val); - - sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; - err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); - err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); - - return err; -} - -static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_GAIN_CTRL_IDX]; - PDEBUG(D_V4L2, "Read auto gain control %d", *val); - return 0; -} - -static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set auto gain control to %d", val); - - sensor_settings[AUTO_GAIN_CTRL_IDX] = val; - err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); - - return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); -} - -static void ov9650_dump_registers(struct sd *sd) -{ - int address; - info("Dumping the ov9650 register state"); - for (address = 0; address < 0xa9; address++) { - u8 value; - m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); - } - - info("ov9650 register state dump complete"); - - info("Probing for which registers that are read/write"); - for (address = 0; address < 0xff; address++) { - u8 old_value, ctrl_value; - u8 test_value[2] = {0xff, 0xff}; - - m5602_read_sensor(sd, address, &old_value, 1); - m5602_write_sensor(sd, address, test_value, 1); - m5602_read_sensor(sd, address, &ctrl_value, 1); - - if (ctrl_value == test_value[0]) - info("register 0x%x is writeable", address); - else - info("register 0x%x is read only", address); - - /* Restore original value */ - m5602_write_sensor(sd, address, &old_value, 1); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,307 +0,0 @@ -/* - * Driver for the ov9650 sensor - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#ifndef M5602_OV9650_H_ -#define M5602_OV9650_H_ - -#include -#include "m5602_sensor.h" - -/*****************************************************************************/ - -#define OV9650_GAIN 0x00 -#define OV9650_BLUE 0x01 -#define OV9650_RED 0x02 -#define OV9650_VREF 0x03 -#define OV9650_COM1 0x04 -#define OV9650_BAVE 0x05 -#define OV9650_GEAVE 0x06 -#define OV9650_RSVD7 0x07 -#define OV9650_COM2 0x09 -#define OV9650_PID 0x0a -#define OV9650_VER 0x0b -#define OV9650_COM3 0x0c -#define OV9650_COM4 0x0d -#define OV9650_COM5 0x0e -#define OV9650_COM6 0x0f -#define OV9650_AECH 0x10 -#define OV9650_CLKRC 0x11 -#define OV9650_COM7 0x12 -#define OV9650_COM8 0x13 -#define OV9650_COM9 0x14 -#define OV9650_COM10 0x15 -#define OV9650_RSVD16 0x16 -#define OV9650_HSTART 0x17 -#define OV9650_HSTOP 0x18 -#define OV9650_VSTRT 0x19 -#define OV9650_VSTOP 0x1a -#define OV9650_PSHFT 0x1b -#define OV9650_MVFP 0x1e -#define OV9650_AEW 0x24 -#define OV9650_AEB 0x25 -#define OV9650_VPT 0x26 -#define OV9650_BBIAS 0x27 -#define OV9650_GbBIAS 0x28 -#define OV9650_Gr_COM 0x29 -#define OV9650_RBIAS 0x2c -#define OV9650_HREF 0x32 -#define OV9650_CHLF 0x33 -#define OV9650_ARBLM 0x34 -#define OV9650_RSVD35 0x35 -#define OV9650_RSVD36 0x36 -#define OV9650_ADC 0x37 -#define OV9650_ACOM38 0x38 -#define OV9650_OFON 0x39 -#define OV9650_TSLB 0x3a -#define OV9650_COM12 0x3c -#define OV9650_COM13 0x3d -#define OV9650_COM15 0x40 -#define OV9650_COM16 0x41 -#define OV9650_LCC1 0x62 -#define OV9650_LCC2 0x63 -#define OV9650_LCC3 0x64 -#define OV9650_LCC4 0x65 -#define OV9650_LCC5 0x66 -#define OV9650_HV 0x69 -#define OV9650_DBLV 0x6b -#define OV9650_COM21 0x8b -#define OV9650_COM22 0x8c -#define OV9650_COM24 0x8e -#define OV9650_DBLC1 0x8f -#define OV9650_RSVD94 0x94 -#define OV9650_RSVD95 0x95 -#define OV9650_RSVD96 0x96 -#define OV9650_LCCFB 0x9d -#define OV9650_LCCFR 0x9e -#define OV9650_AECHM 0xa1 -#define OV9650_COM26 0xa5 -#define OV9650_ACOMA8 0xa8 -#define OV9650_ACOMA9 0xa9 - -#define OV9650_REGISTER_RESET (1 << 7) -#define OV9650_VGA_SELECT (1 << 6) -#define OV9650_CIF_SELECT (1 << 5) -#define OV9650_QVGA_SELECT (1 << 4) -#define OV9650_QCIF_SELECT (1 << 3) -#define OV9650_RGB_SELECT (1 << 2) -#define OV9650_RAW_RGB_SELECT (1 << 0) - -#define OV9650_FAST_AGC_AEC (1 << 7) -#define OV9650_AEC_UNLIM_STEP_SIZE (1 << 6) -#define OV9650_BANDING (1 << 5) -#define OV9650_AGC_EN (1 << 2) -#define OV9650_AWB_EN (1 << 1) -#define OV9650_AEC_EN (1 << 0) - -#define OV9650_VARIOPIXEL (1 << 2) -#define OV9650_SYSTEM_CLK_SEL (1 << 7) -#define OV9650_SLAM_MODE (1 << 4) - -#define OV9650_QVGA_VARIOPIXEL (1 << 7) - -#define OV9650_VFLIP (1 << 4) -#define OV9650_HFLIP (1 << 5) - -#define OV9650_SOFT_SLEEP (1 << 4) -#define OV9650_OUTPUT_DRIVE_2X (1 << 0) - -#define OV9650_DENOISE_ENABLE (1 << 5) -#define OV9650_WHITE_PIXEL_ENABLE (1 << 1) -#define OV9650_WHITE_PIXEL_OPTION (1 << 0) - -#define OV9650_LEFT_OFFSET 0x62 - -#define GAIN_DEFAULT 0x14 -#define RED_GAIN_DEFAULT 0x70 -#define BLUE_GAIN_DEFAULT 0x20 -#define EXPOSURE_DEFAULT 0x1ff - -/*****************************************************************************/ - -/* Kernel module parameters */ -extern int force_sensor; -extern int dump_sensor; - -int ov9650_probe(struct sd *sd); -int ov9650_init(struct sd *sd); -int ov9650_start(struct sd *sd); -int ov9650_stop(struct sd *sd); -void ov9650_disconnect(struct sd *sd); - -static const struct m5602_sensor ov9650 = { - .name = "OV9650", - .i2c_slave_id = 0x60, - .i2c_regW = 1, - .probe = ov9650_probe, - .init = ov9650_init, - .start = ov9650_start, - .stop = ov9650_stop, - .disconnect = ov9650_disconnect, -}; - -static const unsigned char preinit_ov9650[][3] = { - /* [INITCAM] */ - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, - - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a}, - /* Reset chip */ - {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, - /* Enable double clock */ - {SENSOR, OV9650_CLKRC, 0x80}, - /* Do something out of spec with the power */ - {SENSOR, OV9650_OFON, 0x40} -}; - -static const unsigned char init_ov9650[][3] = { - /* [INITCAM] */ - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, - - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a}, - - /* Reset chip */ - {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, - /* One extra reset is needed in order to make the sensor behave - properly when resuming from ram, could be a timing issue */ - {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, - - /* Enable double clock */ - {SENSOR, OV9650_CLKRC, 0x80}, - /* Do something out of spec with the power */ - {SENSOR, OV9650_OFON, 0x40}, - - /* Set fast AGC/AEC algorithm with unlimited step size */ - {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC | - OV9650_AEC_UNLIM_STEP_SIZE}, - - {SENSOR, OV9650_CHLF, 0x10}, - {SENSOR, OV9650_ARBLM, 0xbf}, - {SENSOR, OV9650_ACOM38, 0x81}, - /* Turn off color matrix coefficient double option */ - {SENSOR, OV9650_COM16, 0x00}, - /* Enable color matrix for RGB/YUV, Delay Y channel, - set output Y/UV delay to 1 */ - {SENSOR, OV9650_COM13, 0x19}, - /* Enable digital BLC, Set output mode to U Y V Y */ - {SENSOR, OV9650_TSLB, 0x0c}, - /* Limit the AGC/AEC stable upper region */ - {SENSOR, OV9650_COM24, 0x00}, - /* Enable HREF and some out of spec things */ - {SENSOR, OV9650_COM12, 0x73}, - /* Set all DBLC offset signs to positive and - do some out of spec stuff */ - {SENSOR, OV9650_DBLC1, 0xdf}, - {SENSOR, OV9650_COM21, 0x06}, - {SENSOR, OV9650_RSVD35, 0x91}, - /* Necessary, no camera stream without it */ - {SENSOR, OV9650_RSVD16, 0x06}, - {SENSOR, OV9650_RSVD94, 0x99}, - {SENSOR, OV9650_RSVD95, 0x99}, - {SENSOR, OV9650_RSVD96, 0x04}, - /* Enable full range output */ - {SENSOR, OV9650_COM15, 0x0}, - /* Enable HREF at optical black, enable ADBLC bias, - enable ADBLC, reset timings at format change */ - {SENSOR, OV9650_COM6, 0x4b}, - /* Subtract 32 from the B channel bias */ - {SENSOR, OV9650_BBIAS, 0xa0}, - /* Subtract 32 from the Gb channel bias */ - {SENSOR, OV9650_GbBIAS, 0xa0}, - /* Do not bypass the analog BLC and to some out of spec stuff */ - {SENSOR, OV9650_Gr_COM, 0x00}, - /* Subtract 32 from the R channel bias */ - {SENSOR, OV9650_RBIAS, 0xa0}, - /* Subtract 32 from the R channel bias */ - {SENSOR, OV9650_RBIAS, 0x0}, - {SENSOR, OV9650_COM26, 0x80}, - {SENSOR, OV9650_ACOMA9, 0x98}, - /* Set the AGC/AEC stable region upper limit */ - {SENSOR, OV9650_AEW, 0x68}, - /* Set the AGC/AEC stable region lower limit */ - {SENSOR, OV9650_AEB, 0x5c}, - /* Set the high and low limit nibbles to 3 */ - {SENSOR, OV9650_VPT, 0xc3}, - /* Set the Automatic Gain Ceiling (AGC) to 128x, - drop VSYNC at frame drop, - limit exposure timing, - drop frame when the AEC step is larger than the exposure gap */ - {SENSOR, OV9650_COM9, 0x6e}, - /* Set VSYNC negative, Set RESET to SLHS (slave mode horizontal sync) - and set PWDN to SLVS (slave mode vertical sync) */ - {SENSOR, OV9650_COM10, 0x42}, - /* Set horizontal column start high to default value */ - {SENSOR, OV9650_HSTART, 0x1a}, /* 210 */ - /* Set horizontal column end */ - {SENSOR, OV9650_HSTOP, 0xbf}, /* 1534 */ - /* Complementing register to the two writes above */ - {SENSOR, OV9650_HREF, 0xb2}, - /* Set vertical row start high bits */ - {SENSOR, OV9650_VSTRT, 0x02}, - /* Set vertical row end low bits */ - {SENSOR, OV9650_VSTOP, 0x7e}, - /* Set complementing vertical frame control */ - {SENSOR, OV9650_VREF, 0x10}, - {SENSOR, OV9650_ADC, 0x04}, - {SENSOR, OV9650_HV, 0x40}, - - /* Enable denoise, and white-pixel erase */ - {SENSOR, OV9650_COM22, OV9650_DENOISE_ENABLE | - OV9650_WHITE_PIXEL_ENABLE | - OV9650_WHITE_PIXEL_OPTION}, - - /* Enable VARIOPIXEL */ - {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL}, - {SENSOR, OV9650_COM4, OV9650_QVGA_VARIOPIXEL}, - - /* Put the sensor in soft sleep mode */ - {SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X}, -}; - -static const unsigned char res_init_ov9650[][3] = { - {SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X}, - - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, - {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01} -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_po1030.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_po1030.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_po1030.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_po1030.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,762 +0,0 @@ -/* - * Driver for the po1030 sensor - * - * Copyright (c) 2008 Erik Andrén - * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (c) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#include "m5602_po1030.h" - -static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val); -static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val); -static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, - __s32 val); -static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, - __s32 *val); - -static struct v4l2_pix_format po1030_modes[] = { - { - 640, - 480, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = 640 * 480, - .bytesperline = 640, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2 - } -}; - -static const struct ctrl po1030_ctrls[] = { -#define GAIN_IDX 0 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0x4f, - .step = 0x1, - .default_value = PO1030_GLOBAL_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_gain, - .get = po1030_get_gain - }, -#define EXPOSURE_IDX 1 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x02ff, - .step = 0x1, - .default_value = PO1030_EXPOSURE_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_exposure, - .get = po1030_get_exposure - }, -#define RED_BALANCE_IDX 2 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = PO1030_RED_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_red_balance, - .get = po1030_get_red_balance - }, -#define BLUE_BALANCE_IDX 3 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = PO1030_BLUE_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_blue_balance, - .get = po1030_get_blue_balance - }, -#define HFLIP_IDX 4 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = po1030_set_hflip, - .get = po1030_get_hflip - }, -#define VFLIP_IDX 5 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = po1030_set_vflip, - .get = po1030_get_vflip - }, -#define AUTO_WHITE_BALANCE_IDX 6 - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = po1030_set_auto_white_balance, - .get = po1030_get_auto_white_balance - }, -#define AUTO_EXPOSURE_IDX 7 - { - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = po1030_set_auto_exposure, - .get = po1030_get_auto_exposure - }, -#define GREEN_BALANCE_IDX 8 - { - { - .id = M5602_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = PO1030_GREEN_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_green_balance, - .get = po1030_get_green_balance - }, -}; - -static void po1030_dump_registers(struct sd *sd); - -int po1030_probe(struct sd *sd) -{ - u8 dev_id_h = 0, i; - s32 *sensor_settings; - - if (force_sensor) { - if (force_sensor == PO1030_SENSOR) { - info("Forcing a %s sensor", po1030.name); - goto sensor_found; - } - /* If we want to force another sensor, don't try to probe this - * one */ - return -ENODEV; - } - - PDEBUG(D_PROBE, "Probing for a po1030 sensor"); - - /* Run the pre-init to actually probe the unit */ - for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { - u8 data = preinit_po1030[i][2]; - if (preinit_po1030[i][0] == SENSOR) - m5602_write_sensor(sd, - preinit_po1030[i][1], &data, 1); - else - m5602_write_bridge(sd, preinit_po1030[i][1], data); - } - - if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1)) - return -ENODEV; - - if (dev_id_h == 0x30) { - info("Detected a po1030 sensor"); - goto sensor_found; - } - return -ENODEV; - -sensor_found: - sensor_settings = kmalloc( - ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - - sd->gspca_dev.cam.cam_mode = po1030_modes; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes); - sd->desc->ctrls = po1030_ctrls; - sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls); - - for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++) - sensor_settings[i] = po1030_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; - - return 0; -} - -int po1030_init(struct sd *sd) -{ - s32 *sensor_settings = sd->sensor_priv; - int i, err = 0; - - /* Init the sensor */ - for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) { - u8 data[2] = {0x00, 0x00}; - - switch (init_po1030[i][0]) { - case BRIDGE: - err = m5602_write_bridge(sd, - init_po1030[i][1], - init_po1030[i][2]); - break; - - case SENSOR: - data[0] = init_po1030[i][2]; - err = m5602_write_sensor(sd, - init_po1030[i][1], data, 1); - break; - - default: - info("Invalid stream command, exiting init"); - return -EINVAL; - } - } - if (err < 0) - return err; - - if (dump_sensor) - po1030_dump_registers(sd); - - err = po1030_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; - - err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; - - err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; - - err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); - if (err < 0) - return err; - - err = po1030_set_red_balance(&sd->gspca_dev, - sensor_settings[RED_BALANCE_IDX]); - if (err < 0) - return err; - - err = po1030_set_blue_balance(&sd->gspca_dev, - sensor_settings[BLUE_BALANCE_IDX]); - if (err < 0) - return err; - - err = po1030_set_green_balance(&sd->gspca_dev, - sensor_settings[GREEN_BALANCE_IDX]); - if (err < 0) - return err; - - err = po1030_set_auto_white_balance(&sd->gspca_dev, - sensor_settings[AUTO_WHITE_BALANCE_IDX]); - if (err < 0) - return err; - - err = po1030_set_auto_exposure(&sd->gspca_dev, - sensor_settings[AUTO_EXPOSURE_IDX]); - return err; -} - -int po1030_start(struct sd *sd) -{ - struct cam *cam = &sd->gspca_dev.cam; - int i, err = 0; - int width = cam->cam_mode[sd->gspca_dev.curr_mode].width; - int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; - int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; - u8 data; - - switch (width) { - case 320: - data = PO1030_SUBSAMPLING; - err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); - if (err < 0) - return err; - - data = ((width + 3) >> 8) & 0xff; - err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); - if (err < 0) - return err; - - data = (width + 3) & 0xff; - err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); - if (err < 0) - return err; - - data = ((height + 1) >> 8) & 0xff; - err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); - if (err < 0) - return err; - - data = (height + 1) & 0xff; - err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); - - height += 6; - width -= 1; - break; - - case 640: - data = 0; - err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); - if (err < 0) - return err; - - data = ((width + 7) >> 8) & 0xff; - err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); - if (err < 0) - return err; - - data = (width + 7) & 0xff; - err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); - if (err < 0) - return err; - - data = ((height + 3) >> 8) & 0xff; - err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); - if (err < 0) - return err; - - data = (height + 3) & 0xff; - err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); - - height += 12; - width -= 2; - break; - } - err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, - ((ver_offs >> 8) & 0xff)); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff)); - if (err < 0) - return err; - - for (i = 0; i < 2 && !err; i++) - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); - if (err < 0) - return err; - - for (i = 0; i < 2 && !err; i++) - err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); - - for (i = 0; i < 2 && !err; i++) - err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); - - for (i = 0; i < 2 && !err; i++) - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff)); - if (err < 0) - return err; - - err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); - return err; -} - -static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Exposure read as %d", *val); - return 0; -} - -static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[EXPOSURE_IDX] = val; - PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff); - - i2c_data = ((val & 0xff00) >> 8); - PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x", - i2c_data); - - err = m5602_write_sensor(sd, PO1030_INTEGLINES_H, - &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = (val & 0xff); - PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x", - i2c_data); - err = m5602_write_sensor(sd, PO1030_INTEGLINES_M, - &i2c_data, 1); - - return err; -} - -static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read global gain %d", *val); - return 0; -} - -static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[GAIN_IDX] = val; - - i2c_data = val & 0xff; - PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); - err = m5602_write_sensor(sd, PO1030_GLOBALGAIN, - &i2c_data, 1); - return err; -} - -static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read hflip %d", *val); - - return 0; -} - -static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[HFLIP_IDX] = val; - - PDEBUG(D_V4L2, "Set hflip %d", val); - err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7); - - err = m5602_write_sensor(sd, PO1030_CONTROL2, - &i2c_data, 1); - - return err; -} - -static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vflip %d", *val); - - return 0; -} - -static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[VFLIP_IDX] = val; - - PDEBUG(D_V4L2, "Set vflip %d", val); - err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6); - - err = m5602_write_sensor(sd, PO1030_CONTROL2, - &i2c_data, 1); - - return err; -} - -static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[RED_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read red gain %d", *val); - return 0; -} - -static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[RED_BALANCE_IDX] = val; - - i2c_data = val & 0xff; - PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); - err = m5602_write_sensor(sd, PO1030_RED_GAIN, - &i2c_data, 1); - return err; -} - -static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BLUE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read blue gain %d", *val); - - return 0; -} - -static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[BLUE_BALANCE_IDX] = val; - - i2c_data = val & 0xff; - PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); - err = m5602_write_sensor(sd, PO1030_BLUE_GAIN, - &i2c_data, 1); - - return err; -} - -static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GREEN_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read green gain %d", *val); - - return 0; -} - -static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[GREEN_BALANCE_IDX] = val; - i2c_data = val & 0xff; - PDEBUG(D_V4L2, "Set green gain to %d", i2c_data); - - err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN, - &i2c_data, 1); - if (err < 0) - return err; - - return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN, - &i2c_data, 1); -} - -static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Auto white balancing is %d", *val); - - return 0; -} - -static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; - - err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); - if (err < 0) - return err; - - PDEBUG(D_V4L2, "Set auto white balance to %d", val); - i2c_data = (i2c_data & 0xfe) | (val & 0x01); - err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); - return err; -} - -static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, - __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Auto exposure is %d", *val); - return 0; -} - -static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, - __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[AUTO_EXPOSURE_IDX] = val; - err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); - if (err < 0) - return err; - - PDEBUG(D_V4L2, "Set auto exposure to %d", val); - i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1); - return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); -} - -void po1030_disconnect(struct sd *sd) -{ - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static void po1030_dump_registers(struct sd *sd) -{ - int address; - u8 value = 0; - - info("Dumping the po1030 sensor core registers"); - for (address = 0; address < 0x7f; address++) { - m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); - } - - info("po1030 register state dump complete"); - - info("Probing for which registers that are read/write"); - for (address = 0; address < 0xff; address++) { - u8 old_value, ctrl_value; - u8 test_value[2] = {0xff, 0xff}; - - m5602_read_sensor(sd, address, &old_value, 1); - m5602_write_sensor(sd, address, test_value, 1); - m5602_read_sensor(sd, address, &ctrl_value, 1); - - if (ctrl_value == test_value[0]) - info("register 0x%x is writeable", address); - else - info("register 0x%x is read only", address); - - /* Restore original value */ - m5602_write_sensor(sd, address, &old_value, 1); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_po1030.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_po1030.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_po1030.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_po1030.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,272 +0,0 @@ -/* - * Driver for the po1030 sensor. - * - * Copyright (c) 2008 Erik Andrén - * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (c) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * Register defines taken from Pascal Stangs Procyon Armlib - * - * 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, version 2. - * - */ - -#ifndef M5602_PO1030_H_ -#define M5602_PO1030_H_ - -#include "m5602_sensor.h" - -/*****************************************************************************/ - -#define PO1030_DEVID_H 0x00 -#define PO1030_DEVID_L 0x01 -#define PO1030_FRAMEWIDTH_H 0x04 -#define PO1030_FRAMEWIDTH_L 0x05 -#define PO1030_FRAMEHEIGHT_H 0x06 -#define PO1030_FRAMEHEIGHT_L 0x07 -#define PO1030_WINDOWX_H 0x08 -#define PO1030_WINDOWX_L 0x09 -#define PO1030_WINDOWY_H 0x0a -#define PO1030_WINDOWY_L 0x0b -#define PO1030_WINDOWWIDTH_H 0x0c -#define PO1030_WINDOWWIDTH_L 0x0d -#define PO1030_WINDOWHEIGHT_H 0x0e -#define PO1030_WINDOWHEIGHT_L 0x0f - -#define PO1030_GLOBALIBIAS 0x12 -#define PO1030_PIXELIBIAS 0x13 - -#define PO1030_GLOBALGAIN 0x15 -#define PO1030_RED_GAIN 0x16 -#define PO1030_GREEN_1_GAIN 0x17 -#define PO1030_BLUE_GAIN 0x18 -#define PO1030_GREEN_2_GAIN 0x19 - -#define PO1030_INTEGLINES_H 0x1a -#define PO1030_INTEGLINES_M 0x1b -#define PO1030_INTEGLINES_L 0x1c - -#define PO1030_CONTROL1 0x1d -#define PO1030_CONTROL2 0x1e -#define PO1030_CONTROL3 0x1f -#define PO1030_CONTROL4 0x20 - -#define PO1030_PERIOD50_H 0x23 -#define PO1030_PERIOD50_L 0x24 -#define PO1030_PERIOD60_H 0x25 -#define PO1030_PERIOD60_L 0x26 -#define PO1030_REGCLK167 0x27 -#define PO1030_FLICKER_DELTA50 0x28 -#define PO1030_FLICKERDELTA60 0x29 - -#define PO1030_ADCOFFSET 0x2c - -/* Gamma Correction Coeffs */ -#define PO1030_GC0 0x2d -#define PO1030_GC1 0x2e -#define PO1030_GC2 0x2f -#define PO1030_GC3 0x30 -#define PO1030_GC4 0x31 -#define PO1030_GC5 0x32 -#define PO1030_GC6 0x33 -#define PO1030_GC7 0x34 - -/* Color Transform Matrix */ -#define PO1030_CT0 0x35 -#define PO1030_CT1 0x36 -#define PO1030_CT2 0x37 -#define PO1030_CT3 0x38 -#define PO1030_CT4 0x39 -#define PO1030_CT5 0x3a -#define PO1030_CT6 0x3b -#define PO1030_CT7 0x3c -#define PO1030_CT8 0x3d - -#define PO1030_AUTOCTRL1 0x3e -#define PO1030_AUTOCTRL2 0x3f - -#define PO1030_YTARGET 0x40 -#define PO1030_GLOBALGAINMIN 0x41 -#define PO1030_GLOBALGAINMAX 0x42 - -#define PO1030_AWB_RED_TUNING 0x47 -#define PO1030_AWB_BLUE_TUNING 0x48 - -/* Output format control */ -#define PO1030_OUTFORMCTRL1 0x5a -#define PO1030_OUTFORMCTRL2 0x5b -#define PO1030_OUTFORMCTRL3 0x5c -#define PO1030_OUTFORMCTRL4 0x5d -#define PO1030_OUTFORMCTRL5 0x5e - -#define PO1030_EDGE_ENH_OFF 0x5f -#define PO1030_EGA 0x60 - -#define PO1030_Cb_U_GAIN 0x63 -#define PO1030_Cr_V_GAIN 0x64 - -#define PO1030_YCONTRAST 0x74 -#define PO1030_YSATURATION 0x75 - -#define PO1030_HFLIP (1 << 7) -#define PO1030_VFLIP (1 << 6) - -#define PO1030_HREF_ENABLE (1 << 6) - -#define PO1030_RAW_RGB_BAYER 0x4 - -#define PO1030_FRAME_EQUAL (1 << 3) -#define PO1030_AUTO_SUBSAMPLING (1 << 4) - -#define PO1030_WEIGHT_WIN_2X (1 << 3) - -#define PO1030_SHUTTER_MODE (1 << 6) -#define PO1030_AUTO_SUBSAMPLING (1 << 4) -#define PO1030_FRAME_EQUAL (1 << 3) - -#define PO1030_SENSOR_RESET (1 << 5) - -#define PO1030_SUBSAMPLING (1 << 6) - -/*****************************************************************************/ - -#define PO1030_GLOBAL_GAIN_DEFAULT 0x12 -#define PO1030_EXPOSURE_DEFAULT 0x0085 -#define PO1030_BLUE_GAIN_DEFAULT 0x36 -#define PO1030_RED_GAIN_DEFAULT 0x36 -#define PO1030_GREEN_GAIN_DEFAULT 0x40 - -/*****************************************************************************/ - -/* Kernel module parameters */ -extern int force_sensor; -extern int dump_sensor; - -int po1030_probe(struct sd *sd); -int po1030_init(struct sd *sd); -int po1030_start(struct sd *sd); -void po1030_disconnect(struct sd *sd); - -static const struct m5602_sensor po1030 = { - .name = "PO1030", - - .i2c_slave_id = 0xdc, - .i2c_regW = 1, - - .probe = po1030_probe, - .init = po1030_init, - .start = po1030_start, - .disconnect = po1030_disconnect, -}; - -static const unsigned char preinit_po1030[][3] = { - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, - - {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00} -}; - -static const unsigned char init_po1030[][3] = { - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - - {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)}, - - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - - {SENSOR, PO1030_AUTOCTRL2, 0x04}, - - {SENSOR, PO1030_OUTFORMCTRL2, PO1030_RAW_RGB_BAYER}, - {SENSOR, PO1030_AUTOCTRL1, PO1030_WEIGHT_WIN_2X}, - - {SENSOR, PO1030_CONTROL2, 0x03}, - {SENSOR, 0x21, 0x90}, - {SENSOR, PO1030_YTARGET, 0x60}, - {SENSOR, 0x59, 0x13}, - {SENSOR, PO1030_OUTFORMCTRL1, PO1030_HREF_ENABLE}, - {SENSOR, PO1030_EDGE_ENH_OFF, 0x00}, - {SENSOR, PO1030_EGA, 0x80}, - {SENSOR, 0x78, 0x14}, - {SENSOR, 0x6f, 0x01}, - {SENSOR, PO1030_GLOBALGAINMAX, 0x14}, - {SENSOR, PO1030_Cb_U_GAIN, 0x38}, - {SENSOR, PO1030_Cr_V_GAIN, 0x38}, - {SENSOR, PO1030_CONTROL1, PO1030_SHUTTER_MODE | - PO1030_AUTO_SUBSAMPLING | - PO1030_FRAME_EQUAL}, - {SENSOR, PO1030_GC0, 0x10}, - {SENSOR, PO1030_GC1, 0x20}, - {SENSOR, PO1030_GC2, 0x40}, - {SENSOR, PO1030_GC3, 0x60}, - {SENSOR, PO1030_GC4, 0x80}, - {SENSOR, PO1030_GC5, 0xa0}, - {SENSOR, PO1030_GC6, 0xc0}, - {SENSOR, PO1030_GC7, 0xff}, - - /* Set the width to 751 */ - {SENSOR, PO1030_FRAMEWIDTH_H, 0x02}, - {SENSOR, PO1030_FRAMEWIDTH_L, 0xef}, - - /* Set the height to 540 */ - {SENSOR, PO1030_FRAMEHEIGHT_H, 0x02}, - {SENSOR, PO1030_FRAMEHEIGHT_L, 0x1c}, - - /* Set the x window to 1 */ - {SENSOR, PO1030_WINDOWX_H, 0x00}, - {SENSOR, PO1030_WINDOWX_L, 0x01}, - - /* Set the y window to 1 */ - {SENSOR, PO1030_WINDOWY_H, 0x00}, - {SENSOR, PO1030_WINDOWY_L, 0x01}, - - /* with a very low lighted environment increase the exposure but - * decrease the FPS (Frame Per Second) */ - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,721 +0,0 @@ -/* - * Driver for the s5k4aa sensor - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#include "m5602_s5k4aa.h" - -static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val); - -static - const - struct dmi_system_id s5k4aa_vflip_dmi_table[] = { - { - .ident = "BRUNEINIT", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"), - DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"), - DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001") - } - }, { - .ident = "Fujitsu-Siemens Amilo Xa 2528", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") - } - }, { - .ident = "Fujitsu-Siemens Amilo Xi 2428", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428") - } - }, { - .ident = "Fujitsu-Siemens Amilo Xi 2528", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528") - } - }, { - .ident = "Fujitsu-Siemens Amilo Xi 2550", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") - } - }, { - .ident = "Fujitsu-Siemens Amilo Pa 2548", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548") - } - }, { - .ident = "MSI GX700", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), - DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), - DMI_MATCH(DMI_BIOS_DATE, "12/02/2008") - } - }, { - .ident = "MSI GX700", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), - DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), - DMI_MATCH(DMI_BIOS_DATE, "07/26/2007") - } - }, { - .ident = "MSI GX700", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), - DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), - DMI_MATCH(DMI_BIOS_DATE, "07/19/2007") - } - }, { - .ident = "MSI GX700/GX705/EX700", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), - DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700") - } - }, { - .ident = "MSI L735", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), - DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X") - } - }, { - .ident = "Lenovo Y300", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"), - DMI_MATCH(DMI_PRODUCT_NAME, "Y300") - } - }, - { } -}; - -static struct v4l2_pix_format s5k4aa_modes[] = { - { - 640, - 480, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = - 640 * 480, - .bytesperline = 640, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - }, - { - 1280, - 1024, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = - 1280 * 1024, - .bytesperline = 1280, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - } -}; - -static const struct ctrl s5k4aa_ctrls[] = { -#define VFLIP_IDX 0 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = s5k4aa_set_vflip, - .get = s5k4aa_get_vflip - }, -#define HFLIP_IDX 1 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = s5k4aa_set_hflip, - .get = s5k4aa_get_hflip - }, -#define GAIN_IDX 2 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = S5K4AA_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k4aa_set_gain, - .get = s5k4aa_get_gain - }, -#define EXPOSURE_IDX 3 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 13, - .maximum = 0xfff, - .step = 1, - .default_value = 0x100, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k4aa_set_exposure, - .get = s5k4aa_get_exposure - }, -#define NOISE_SUPP_IDX 4 - { - { - .id = V4L2_CID_PRIVATE_BASE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Noise suppression (smoothing)", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set = s5k4aa_set_noise, - .get = s5k4aa_get_noise - }, -#define BRIGHTNESS_IDX 5 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0x1f, - .step = 1, - .default_value = S5K4AA_DEFAULT_BRIGHTNESS, - }, - .set = s5k4aa_set_brightness, - .get = s5k4aa_get_brightness - }, - -}; - -static void s5k4aa_dump_registers(struct sd *sd); - -int s5k4aa_probe(struct sd *sd) -{ - u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; - int i, err = 0; - s32 *sensor_settings; - - if (force_sensor) { - if (force_sensor == S5K4AA_SENSOR) { - info("Forcing a %s sensor", s5k4aa.name); - goto sensor_found; - } - /* If we want to force another sensor, don't try to probe this - * one */ - return -ENODEV; - } - - PDEBUG(D_PROBE, "Probing for a s5k4aa sensor"); - - /* Preinit the sensor */ - for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) { - u8 data[2] = {0x00, 0x00}; - - switch (preinit_s5k4aa[i][0]) { - case BRIDGE: - err = m5602_write_bridge(sd, - preinit_s5k4aa[i][1], - preinit_s5k4aa[i][2]); - break; - - case SENSOR: - data[0] = preinit_s5k4aa[i][2]; - err = m5602_write_sensor(sd, - preinit_s5k4aa[i][1], - data, 1); - break; - - case SENSOR_LONG: - data[0] = preinit_s5k4aa[i][2]; - data[1] = preinit_s5k4aa[i][3]; - err = m5602_write_sensor(sd, - preinit_s5k4aa[i][1], - data, 2); - break; - default: - info("Invalid stream command, exiting init"); - return -EINVAL; - } - } - - /* Test some registers, but we don't know their exact meaning yet */ - if (m5602_read_sensor(sd, 0x00, prod_id, 2)) - return -ENODEV; - if (m5602_read_sensor(sd, 0x02, prod_id+2, 2)) - return -ENODEV; - if (m5602_read_sensor(sd, 0x04, prod_id+4, 2)) - return -ENODEV; - - if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) - return -ENODEV; - else - info("Detected a s5k4aa sensor"); - -sensor_found: - sensor_settings = kmalloc( - ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - - sd->gspca_dev.cam.cam_mode = s5k4aa_modes; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes); - sd->desc->ctrls = s5k4aa_ctrls; - sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls); - - for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++) - sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; - - return 0; -} - -int s5k4aa_start(struct sd *sd) -{ - int i, err = 0; - u8 data[2]; - struct cam *cam = &sd->gspca_dev.cam; - s32 *sensor_settings = sd->sensor_priv; - - switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { - case 1280: - PDEBUG(D_V4L2, "Configuring camera for SXGA mode"); - - for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) { - switch (SXGA_s5k4aa[i][0]) { - case BRIDGE: - err = m5602_write_bridge(sd, - SXGA_s5k4aa[i][1], - SXGA_s5k4aa[i][2]); - break; - - case SENSOR: - data[0] = SXGA_s5k4aa[i][2]; - err = m5602_write_sensor(sd, - SXGA_s5k4aa[i][1], - data, 1); - break; - - case SENSOR_LONG: - data[0] = SXGA_s5k4aa[i][2]; - data[1] = SXGA_s5k4aa[i][3]; - err = m5602_write_sensor(sd, - SXGA_s5k4aa[i][1], - data, 2); - break; - - default: - err("Invalid stream command, exiting init"); - return -EINVAL; - } - } - err = s5k4aa_set_noise(&sd->gspca_dev, 0); - if (err < 0) - return err; - break; - - case 640: - PDEBUG(D_V4L2, "Configuring camera for VGA mode"); - - for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) { - switch (VGA_s5k4aa[i][0]) { - case BRIDGE: - err = m5602_write_bridge(sd, - VGA_s5k4aa[i][1], - VGA_s5k4aa[i][2]); - break; - - case SENSOR: - data[0] = VGA_s5k4aa[i][2]; - err = m5602_write_sensor(sd, - VGA_s5k4aa[i][1], - data, 1); - break; - - case SENSOR_LONG: - data[0] = VGA_s5k4aa[i][2]; - data[1] = VGA_s5k4aa[i][3]; - err = m5602_write_sensor(sd, - VGA_s5k4aa[i][1], - data, 2); - break; - - default: - err("Invalid stream command, exiting init"); - return -EINVAL; - } - } - err = s5k4aa_set_noise(&sd->gspca_dev, 1); - if (err < 0) - return err; - break; - } - if (err < 0) - return err; - - err = s5k4aa_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; - - err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; - - err = s5k4aa_set_brightness(&sd->gspca_dev, - sensor_settings[BRIGHTNESS_IDX]); - if (err < 0) - return err; - - err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]); - if (err < 0) - return err; - - err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); - if (err < 0) - return err; - - return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); -} - -int s5k4aa_init(struct sd *sd) -{ - int i, err = 0; - - for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) { - u8 data[2] = {0x00, 0x00}; - - switch (init_s5k4aa[i][0]) { - case BRIDGE: - err = m5602_write_bridge(sd, - init_s5k4aa[i][1], - init_s5k4aa[i][2]); - break; - - case SENSOR: - data[0] = init_s5k4aa[i][2]; - err = m5602_write_sensor(sd, - init_s5k4aa[i][1], data, 1); - break; - - case SENSOR_LONG: - data[0] = init_s5k4aa[i][2]; - data[1] = init_s5k4aa[i][3]; - err = m5602_write_sensor(sd, - init_s5k4aa[i][1], data, 2); - break; - default: - info("Invalid stream command, exiting init"); - return -EINVAL; - } - } - - if (dump_sensor) - s5k4aa_dump_registers(sd); - - return err; -} - -static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Read exposure %d", *val); - - return 0; -} - -static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 data = S5K4AA_PAGE_MAP_2; - int err; - - sensor_settings[EXPOSURE_IDX] = val; - PDEBUG(D_V4L2, "Set exposure to %d", val); - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - data = (val >> 8) & 0xff; - err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); - if (err < 0) - return err; - data = val & 0xff; - err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); - - return err; -} - -static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - -static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 data = S5K4AA_PAGE_MAP_2; - int err; - - sensor_settings[VFLIP_IDX] = val; - - PDEBUG(D_V4L2, "Set vertical flip to %d", val); - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); - if (err < 0) - return err; - - if (dmi_check_system(s5k4aa_vflip_dmi_table)) - val = !val; - - data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7)); - err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); - if (err < 0) - return err; - if (val) - data &= 0xfe; - else - data |= 0x01; - err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); - return err; -} - -static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - - return 0; -} - -static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 data = S5K4AA_PAGE_MAP_2; - int err; - - sensor_settings[HFLIP_IDX] = val; - - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); - if (err < 0) - return err; - - if (dmi_check_system(s5k4aa_vflip_dmi_table)) - val = !val; - - data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6)); - err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); - if (err < 0) - return err; - if (val) - data &= 0xfe; - else - data |= 0x01; - err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); - return err; -} - -static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); - return 0; -} - -static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 data = S5K4AA_PAGE_MAP_2; - int err; - - sensor_settings[GAIN_IDX] = val; - - PDEBUG(D_V4L2, "Set gain to %d", val); - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - - data = val & 0xff; - err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1); - - return err; -} - -static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BRIGHTNESS_IDX]; - PDEBUG(D_V4L2, "Read brightness %d", *val); - return 0; -} - -static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 data = S5K4AA_PAGE_MAP_2; - int err; - - sensor_settings[BRIGHTNESS_IDX] = val; - - PDEBUG(D_V4L2, "Set brightness to %d", val); - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - - data = val & 0xff; - return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1); -} - -static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[NOISE_SUPP_IDX]; - PDEBUG(D_V4L2, "Read noise %d", *val); - return 0; -} - -static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 data = S5K4AA_PAGE_MAP_2; - int err; - - sensor_settings[NOISE_SUPP_IDX] = val; - - PDEBUG(D_V4L2, "Set noise to %d", val); - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - - data = val & 0x01; - return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1); -} - -void s5k4aa_disconnect(struct sd *sd) -{ - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static void s5k4aa_dump_registers(struct sd *sd) -{ - int address; - u8 page, old_page; - m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); - for (page = 0; page < 16; page++) { - m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); - info("Dumping the s5k4aa register state for page 0x%x", page); - for (address = 0; address <= 0xff; address++) { - u8 value = 0; - m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); - } - } - info("s5k4aa register state dump complete"); - - for (page = 0; page < 16; page++) { - m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); - info("Probing for which registers that are " - "read/write for page 0x%x", page); - for (address = 0; address <= 0xff; address++) { - u8 old_value, ctrl_value, test_value = 0xff; - - m5602_read_sensor(sd, address, &old_value, 1); - m5602_write_sensor(sd, address, &test_value, 1); - m5602_read_sensor(sd, address, &ctrl_value, 1); - - if (ctrl_value == test_value) - info("register 0x%x is writeable", address); - else - info("register 0x%x is read only", address); - - /* Restore original value */ - m5602_write_sensor(sd, address, &old_value, 1); - } - } - info("Read/write register probing complete"); - m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,283 +0,0 @@ -/* - * Driver for the s5k4aa sensor - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#ifndef M5602_S5K4AA_H_ -#define M5602_S5K4AA_H_ - -#include - -#include "m5602_sensor.h" - -/*****************************************************************************/ - -#define S5K4AA_PAGE_MAP 0xec - -#define S5K4AA_PAGE_MAP_0 0x00 -#define S5K4AA_PAGE_MAP_1 0x01 -#define S5K4AA_PAGE_MAP_2 0x02 - -/* Sensor register definitions for page 0x02 */ -#define S5K4AA_READ_MODE 0x03 -#define S5K4AA_ROWSTART_HI 0x04 -#define S5K4AA_ROWSTART_LO 0x05 -#define S5K4AA_COLSTART_HI 0x06 -#define S5K4AA_COLSTART_LO 0x07 -#define S5K4AA_WINDOW_HEIGHT_HI 0x08 -#define S5K4AA_WINDOW_HEIGHT_LO 0x09 -#define S5K4AA_WINDOW_WIDTH_HI 0x0a -#define S5K4AA_WINDOW_WIDTH_LO 0x0b -#define S5K4AA_GLOBAL_GAIN__ 0x0f -/* sync lost, if too low, reduces frame rate if too high */ -#define S5K4AA_H_BLANK_HI__ 0x1d -#define S5K4AA_H_BLANK_LO__ 0x1e -#define S5K4AA_EXPOSURE_HI 0x17 -#define S5K4AA_EXPOSURE_LO 0x18 -#define S5K4AA_BRIGHTNESS 0x1f /* (digital?) gain : 5 bits */ -#define S5K4AA_GAIN 0x20 /* (analogue?) gain : 7 bits */ -#define S5K4AA_NOISE_SUPP 0x37 - -#define S5K4AA_RM_ROW_SKIP_4X 0x08 -#define S5K4AA_RM_ROW_SKIP_2X 0x04 -#define S5K4AA_RM_COL_SKIP_4X 0x02 -#define S5K4AA_RM_COL_SKIP_2X 0x01 -#define S5K4AA_RM_H_FLIP 0x40 -#define S5K4AA_RM_V_FLIP 0x80 - -#define S5K4AA_DEFAULT_GAIN 0x5f -#define S5K4AA_DEFAULT_BRIGHTNESS 0x10 - -/*****************************************************************************/ - -/* Kernel module parameters */ -extern int force_sensor; -extern int dump_sensor; - -int s5k4aa_probe(struct sd *sd); -int s5k4aa_init(struct sd *sd); -int s5k4aa_start(struct sd *sd); -void s5k4aa_disconnect(struct sd *sd); - -static const struct m5602_sensor s5k4aa = { - .name = "S5K4AA", - .i2c_slave_id = 0x5a, - .i2c_regW = 2, - - .probe = s5k4aa_probe, - .init = s5k4aa_init, - .start = s5k4aa_start, - .disconnect = s5k4aa_disconnect, -}; - -static const unsigned char preinit_s5k4aa[][4] = { - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, - - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, - - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, - - {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00} -}; - -static const unsigned char init_s5k4aa[][4] = { - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, - - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, - - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, - - {SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00}, - {SENSOR, 0x36, 0x01, 0x00}, - {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}, - {SENSOR, 0x7b, 0xff, 0x00}, - {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, - {SENSOR, 0x0c, 0x05, 0x00}, - {SENSOR, 0x02, 0x0e, 0x00}, - {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00}, - {SENSOR, 0x37, 0x00, 0x00}, -}; - -static const unsigned char VGA_s5k4aa[][4] = { - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */ - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */ - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ - - {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, - {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X - | S5K4AA_RM_COL_SKIP_2X, 0x00}, - /* 0x37 : Fix image stability when light is too bright and improves - * image quality in 640x480, but worsens it in 1280x1024 */ - {SENSOR, 0x37, 0x01, 0x00}, - /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */ - {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00}, - {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00}, - /* window_height_hi, window_height_lo : 960 = 0x03c0 */ - {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00}, - {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00}, - /* window_width_hi, window_width_lo : 1280 = 0x0500 */ - {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, - {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, - {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00}, - {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */ - {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, - {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, - {SENSOR, 0x11, 0x04, 0x00}, - {SENSOR, 0x12, 0xc3, 0x00}, - {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, - {SENSOR, 0x02, 0x0e, 0x00}, -}; - -static const unsigned char SXGA_s5k4aa[][4] = { - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */ - {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */ - {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ - - {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, - {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00}, - {SENSOR, 0x37, 0x01, 0x00}, - {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00}, - {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00}, - {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00}, - {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00}, - {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, - {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, - {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00}, - {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, - {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, - {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, - {SENSOR, 0x11, 0x04, 0x00}, - {SENSOR, 0x12, 0xc3, 0x00}, - {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, - {SENSOR, 0x02, 0x0e, 0x00}, -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,601 +0,0 @@ -/* - * Driver for the s5k83a sensor - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#include -#include "m5602_s5k83a.h" - -static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val); -static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val); - -static struct v4l2_pix_format s5k83a_modes[] = { - { - 640, - 480, - V4L2_PIX_FMT_SBGGR8, - V4L2_FIELD_NONE, - .sizeimage = - 640 * 480, - .bytesperline = 640, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - } -}; - -static const struct ctrl s5k83a_ctrls[] = { -#define GAIN_IDX 0 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = S5K83A_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k83a_set_gain, - .get = s5k83a_get_gain - - }, -#define BRIGHTNESS_IDX 1 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = S5K83A_DEFAULT_BRIGHTNESS, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k83a_set_brightness, - .get = s5k83a_get_brightness, - }, -#define EXPOSURE_IDX 2 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = S5K83A_MAXIMUM_EXPOSURE, - .step = 0x01, - .default_value = S5K83A_DEFAULT_EXPOSURE, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k83a_set_exposure, - .get = s5k83a_get_exposure - }, -#define HFLIP_IDX 3 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = s5k83a_set_hflip, - .get = s5k83a_get_hflip - }, -#define VFLIP_IDX 4 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = s5k83a_set_vflip, - .get = s5k83a_get_vflip - } -}; - -static void s5k83a_dump_registers(struct sd *sd); -static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data); -static int s5k83a_set_led_indication(struct sd *sd, u8 val); -static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, - __s32 vflip, __s32 hflip); - -int s5k83a_probe(struct sd *sd) -{ - struct s5k83a_priv *sens_priv; - u8 prod_id = 0, ver_id = 0; - int i, err = 0; - - if (force_sensor) { - if (force_sensor == S5K83A_SENSOR) { - info("Forcing a %s sensor", s5k83a.name); - goto sensor_found; - } - /* If we want to force another sensor, don't try to probe this - * one */ - return -ENODEV; - } - - PDEBUG(D_PROBE, "Probing for a s5k83a sensor"); - - /* Preinit the sensor */ - for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) { - u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]}; - if (preinit_s5k83a[i][0] == SENSOR) - err = m5602_write_sensor(sd, preinit_s5k83a[i][1], - data, 2); - else - err = m5602_write_bridge(sd, preinit_s5k83a[i][1], - data[0]); - } - - /* We don't know what register (if any) that contain the product id - * Just pick the first addresses that seem to produce the same results - * on multiple machines */ - if (m5602_read_sensor(sd, 0x00, &prod_id, 1)) - return -ENODEV; - - if (m5602_read_sensor(sd, 0x01, &ver_id, 1)) - return -ENODEV; - - if ((prod_id == 0xff) || (ver_id == 0xff)) - return -ENODEV; - else - info("Detected a s5k83a sensor"); - -sensor_found: - sens_priv = kmalloc( - sizeof(struct s5k83a_priv), GFP_KERNEL); - if (!sens_priv) - return -ENOMEM; - - sens_priv->settings = - kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL); - if (!sens_priv->settings) { - kfree(sens_priv); - return -ENOMEM; - } - - sd->gspca_dev.cam.cam_mode = s5k83a_modes; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes); - sd->desc->ctrls = s5k83a_ctrls; - sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls); - - /* null the pointer! thread is't running now */ - sens_priv->rotation_thread = NULL; - - for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++) - sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value; - - sd->sensor_priv = sens_priv; - return 0; -} - -int s5k83a_init(struct sd *sd) -{ - int i, err = 0; - s32 *sensor_settings = - ((struct s5k83a_priv *) sd->sensor_priv)->settings; - - for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) { - u8 data[2] = {0x00, 0x00}; - - switch (init_s5k83a[i][0]) { - case BRIDGE: - err = m5602_write_bridge(sd, - init_s5k83a[i][1], - init_s5k83a[i][2]); - break; - - case SENSOR: - data[0] = init_s5k83a[i][2]; - err = m5602_write_sensor(sd, - init_s5k83a[i][1], data, 1); - break; - - case SENSOR_LONG: - data[0] = init_s5k83a[i][2]; - data[1] = init_s5k83a[i][3]; - err = m5602_write_sensor(sd, - init_s5k83a[i][1], data, 2); - break; - default: - info("Invalid stream command, exiting init"); - return -EINVAL; - } - } - - if (dump_sensor) - s5k83a_dump_registers(sd); - - err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; - - err = s5k83a_set_brightness(&sd->gspca_dev, - sensor_settings[BRIGHTNESS_IDX]); - if (err < 0) - return err; - - err = s5k83a_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; - - err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; - - err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); - - return err; -} - -static int rotation_thread_function(void *data) -{ - struct sd *sd = (struct sd *) data; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - u8 reg, previous_rotation = 0; - __s32 vflip, hflip; - - set_current_state(TASK_INTERRUPTIBLE); - while (!schedule_timeout(100)) { - if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock)) - break; - - s5k83a_get_rotation(sd, ®); - if (previous_rotation != reg) { - previous_rotation = reg; - info("Camera was flipped"); - - s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); - s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); - - if (reg) { - vflip = !vflip; - hflip = !hflip; - } - s5k83a_set_flip_real((struct gspca_dev *) sd, - vflip, hflip); - } - - mutex_unlock(&sd->gspca_dev.usb_lock); - set_current_state(TASK_INTERRUPTIBLE); - } - - /* return to "front" flip */ - if (previous_rotation) { - s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); - s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); - s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip); - } - - sens_priv->rotation_thread = NULL; - return 0; -} - -int s5k83a_start(struct sd *sd) -{ - int i, err = 0; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - /* Create another thread, polling the GPIO ports of the camera to check - if it got rotated. This is how the windows driver does it so we have - to assume that there is no better way of accomplishing this */ - sens_priv->rotation_thread = kthread_create(rotation_thread_function, - sd, "rotation thread"); - wake_up_process(sens_priv->rotation_thread); - - /* Preinit the sensor */ - for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) { - u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]}; - if (start_s5k83a[i][0] == SENSOR) - err = m5602_write_sensor(sd, start_s5k83a[i][1], - data, 2); - else - err = m5602_write_bridge(sd, start_s5k83a[i][1], - data[0]); - } - if (err < 0) - return err; - - return s5k83a_set_led_indication(sd, 1); -} - -int s5k83a_stop(struct sd *sd) -{ - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - if (sens_priv->rotation_thread) - kthread_stop(sens_priv->rotation_thread); - - return s5k83a_set_led_indication(sd, 0); -} - -void s5k83a_disconnect(struct sd *sd) -{ - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - s5k83a_stop(sd); - - sd->sensor = NULL; - kfree(sens_priv->settings); - kfree(sens_priv); -} - -static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[GAIN_IDX]; - return 0; -} - -static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[2]; - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - sens_priv->settings[GAIN_IDX] = val; - - data[0] = 0x00; - data[1] = 0x20; - err = m5602_write_sensor(sd, 0x14, data, 2); - if (err < 0) - return err; - - data[0] = 0x01; - data[1] = 0x00; - err = m5602_write_sensor(sd, 0x0d, data, 2); - if (err < 0) - return err; - - /* FIXME: This is not sane, we need to figure out the composition - of these registers */ - data[0] = val >> 3; /* gain, high 5 bits */ - data[1] = val >> 1; /* gain, high 7 bits */ - err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2); - - return err; -} - -static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[BRIGHTNESS_IDX]; - return 0; -} - -static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[1]; - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - sens_priv->settings[BRIGHTNESS_IDX] = val; - data[0] = val; - err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1); - return err; -} - -static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[EXPOSURE_IDX]; - return 0; -} - -static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[2]; - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - sens_priv->settings[EXPOSURE_IDX] = val; - data[0] = 0; - data[1] = val; - err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2); - return err; -} - -static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[VFLIP_IDX]; - return 0; -} - -static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, - __s32 vflip, __s32 hflip) -{ - int err; - u8 data[1]; - struct sd *sd = (struct sd *) gspca_dev; - - data[0] = 0x05; - err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); - if (err < 0) - return err; - - /* six bit is vflip, seven is hflip */ - data[0] = S5K83A_FLIP_MASK; - data[0] = (vflip) ? data[0] | 0x40 : data[0]; - data[0] = (hflip) ? data[0] | 0x80 : data[0]; - - err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1); - if (err < 0) - return err; - - data[0] = (vflip) ? 0x0b : 0x0a; - err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1); - if (err < 0) - return err; - - data[0] = (hflip) ? 0x0a : 0x0b; - err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1); - return err; -} - -static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 reg; - __s32 hflip; - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - sens_priv->settings[VFLIP_IDX] = val; - - s5k83a_get_hflip(gspca_dev, &hflip); - - err = s5k83a_get_rotation(sd, ®); - if (err < 0) - return err; - if (reg) { - val = !val; - hflip = !hflip; - } - - err = s5k83a_set_flip_real(gspca_dev, val, hflip); - return err; -} - -static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[HFLIP_IDX]; - return 0; -} - -static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 reg; - __s32 vflip; - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - sens_priv->settings[HFLIP_IDX] = val; - - s5k83a_get_vflip(gspca_dev, &vflip); - - err = s5k83a_get_rotation(sd, ®); - if (err < 0) - return err; - if (reg) { - val = !val; - vflip = !vflip; - } - - err = s5k83a_set_flip_real(gspca_dev, vflip, val); - return err; -} - -static int s5k83a_set_led_indication(struct sd *sd, u8 val) -{ - int err = 0; - u8 data[1]; - - err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data); - if (err < 0) - return err; - - if (val) - data[0] = data[0] | S5K83A_GPIO_LED_MASK; - else - data[0] = data[0] & ~S5K83A_GPIO_LED_MASK; - - err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]); - - return err; -} - -/* Get camera rotation on Acer notebooks */ -static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data) -{ - int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data); - *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1; - return err; -} - -static void s5k83a_dump_registers(struct sd *sd) -{ - int address; - u8 page, old_page; - m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); - - for (page = 0; page < 16; page++) { - m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); - info("Dumping the s5k83a register state for page 0x%x", page); - for (address = 0; address <= 0xff; address++) { - u8 val = 0; - m5602_read_sensor(sd, address, &val, 1); - info("register 0x%x contains 0x%x", - address, val); - } - } - info("s5k83a register state dump complete"); - - for (page = 0; page < 16; page++) { - m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); - info("Probing for which registers that are read/write " - "for page 0x%x", page); - for (address = 0; address <= 0xff; address++) { - u8 old_val, ctrl_val, test_val = 0xff; - - m5602_read_sensor(sd, address, &old_val, 1); - m5602_write_sensor(sd, address, &test_val, 1); - m5602_read_sensor(sd, address, &ctrl_val, 1); - - if (ctrl_val == test_val) - info("register 0x%x is writeable", address); - else - info("register 0x%x is read only", address); - - /* Restore original val */ - m5602_write_sensor(sd, address, &old_val, 1); - } - } - info("Read/write register probing complete"); - m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,193 +0,0 @@ -/* - * Driver for the s5k83a sensor - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#ifndef M5602_S5K83A_H_ -#define M5602_S5K83A_H_ - -#include "m5602_sensor.h" - -#define S5K83A_FLIP 0x01 -#define S5K83A_HFLIP_TUNE 0x03 -#define S5K83A_VFLIP_TUNE 0x05 -#define S5K83A_BRIGHTNESS 0x0a -#define S5K83A_EXPOSURE 0x18 -#define S5K83A_GAIN 0x1b -#define S5K83A_PAGE_MAP 0xec - -#define S5K83A_DEFAULT_GAIN 0x71 -#define S5K83A_DEFAULT_BRIGHTNESS 0x7e -#define S5K83A_DEFAULT_EXPOSURE 0x00 -#define S5K83A_MAXIMUM_EXPOSURE 0x3c -#define S5K83A_FLIP_MASK 0x10 -#define S5K83A_GPIO_LED_MASK 0x10 -#define S5K83A_GPIO_ROTATION_MASK 0x40 - -/*****************************************************************************/ - -/* Kernel module parameters */ -extern int force_sensor; -extern int dump_sensor; - -int s5k83a_probe(struct sd *sd); -int s5k83a_init(struct sd *sd); -int s5k83a_start(struct sd *sd); -int s5k83a_stop(struct sd *sd); -void s5k83a_disconnect(struct sd *sd); - -static const struct m5602_sensor s5k83a = { - .name = "S5K83A", - .probe = s5k83a_probe, - .init = s5k83a_init, - .start = s5k83a_start, - .stop = s5k83a_stop, - .disconnect = s5k83a_disconnect, - .i2c_slave_id = 0x5a, - .i2c_regW = 2, -}; - -struct s5k83a_priv { - /* We use another thread periodically - probing the orientation of the camera */ - struct task_struct *rotation_thread; - s32 *settings; -}; - -static const unsigned char preinit_s5k83a[][4] = { - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, - - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, -}; - -/* This could probably be considerably shortened. - I don't have the hardware to experiment with it, patches welcome -*/ -static const unsigned char init_s5k83a[][4] = { - /* The following sequence is useless after a clean boot - but is necessary after resume from suspend */ - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, - - {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00}, - {SENSOR, 0xaf, 0x01, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}, - {SENSOR, 0x7b, 0xff, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR, 0x01, 0x50, 0x00}, - {SENSOR, 0x12, 0x20, 0x00}, - {SENSOR, 0x17, 0x40, 0x00}, - {SENSOR, 0x1c, 0x00, 0x00}, - {SENSOR, 0x02, 0x70, 0x00}, - {SENSOR, 0x03, 0x0b, 0x00}, - {SENSOR, 0x04, 0xf0, 0x00}, - {SENSOR, 0x05, 0x0b, 0x00}, - {SENSOR, 0x06, 0x71, 0x00}, - {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */ - {SENSOR, 0x08, 0x02, 0x00}, - {SENSOR, 0x09, 0x88, 0x00}, /* 648 */ - {SENSOR, 0x14, 0x00, 0x00}, - {SENSOR, 0x15, 0x20, 0x00}, /* 32 */ - {SENSOR, 0x19, 0x00, 0x00}, - {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */ - {SENSOR, 0x0f, 0x02, 0x00}, - {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */ - /* normal colors - (this is value after boot, but after tries can be different) */ - {SENSOR, 0x00, 0x06, 0x00}, -}; - -static const unsigned char start_s5k83a[][4] = { - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */ - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */ - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_sensor.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_sensor.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_sensor.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/m5602_sensor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/* - * USB Driver for ALi m5602 based webcams - * - * Copyright (C) 2008 Erik Andrén - * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. - * Copyright (C) 2005 m5603x Linux Driver Project - * - * Portions of code to USB interface and ALi driver software, - * Copyright (c) 2006 Willem Duinker - * v4l2 interface modeled after the V4L2 driver - * for SN9C10x PC Camera Controllers - * - * 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, version 2. - * - */ - -#ifndef M5602_SENSOR_H_ -#define M5602_SENSOR_H_ - -#include "m5602_bridge.h" - -#define M5602_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 0) -#define M5602_V4L2_CID_NOISE_SUPPRESION (V4L2_CID_PRIVATE_BASE + 1) - -/* Enumerates all supported sensors */ -enum sensors { - OV9650_SENSOR = 1, - S5K83A_SENSOR = 2, - S5K4AA_SENSOR = 3, - MT9M111_SENSOR = 4, - PO1030_SENSOR = 5, - OV7660_SENSOR = 6, -}; - -/* Enumerates all possible instruction types */ -enum instruction { - BRIDGE, - SENSOR, - SENSOR_LONG -}; - -struct m5602_sensor { - /* Defines the name of a sensor */ - char name[32]; - - /* What i2c address the sensor is connected to */ - u8 i2c_slave_id; - - /* Width of each i2c register (in bytes) */ - u8 i2c_regW; - - /* Probes if the sensor is connected */ - int (*probe)(struct sd *sd); - - /* Performs a initialization sequence */ - int (*init)(struct sd *sd); - - /* Executed when the camera starts to send data */ - int (*start)(struct sd *sd); - - /* Executed when the camera ends to send data */ - int (*stop)(struct sd *sd); - - /* Executed when the device is disconnected */ - void (*disconnect)(struct sd *sd); -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/m5602/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -obj-$(CONFIG_USB_M5602) += gspca_m5602.o - -gspca_m5602-objs := m5602_core.o \ - m5602_ov9650.o \ - m5602_ov7660.o \ - m5602_mt9m111.o \ - m5602_po1030.o \ - m5602_s5k83a.o \ - m5602_s5k4aa.o - -EXTRA_CFLAGS += -Idrivers/media/video/gspca diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -obj-$(CONFIG_USB_GSPCA) += gspca_main.o -obj-$(CONFIG_USB_GSPCA_BENQ) += gspca_benq.o -obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o -obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o -obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o -obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o -obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o -obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o -obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o -obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o -obj-$(CONFIG_USB_GSPCA_NW80X) += gspca_nw80x.o -obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o -obj-$(CONFIG_USB_GSPCA_OV534) += gspca_ov534.o -obj-$(CONFIG_USB_GSPCA_OV534_9) += gspca_ov534_9.o -obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o -obj-$(CONFIG_USB_GSPCA_PAC7302) += gspca_pac7302.o -obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o -obj-$(CONFIG_USB_GSPCA_SN9C2028) += gspca_sn9c2028.o -obj-$(CONFIG_USB_GSPCA_SN9C20X) += gspca_sn9c20x.o -obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o -obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o -obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o -obj-$(CONFIG_USB_GSPCA_SPCA501) += gspca_spca501.o -obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o -obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o -obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o -obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o -obj-$(CONFIG_USB_GSPCA_SPCA1528) += gspca_spca1528.o -obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o -obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o -obj-$(CONFIG_USB_GSPCA_SQ930X) += gspca_sq930x.o -obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o -obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o -obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o -obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o -obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o -obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o -obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o -obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o -obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o - -gspca_main-objs := gspca.o -gspca_benq-objs := benq.o -gspca_conex-objs := conex.o -gspca_cpia1-objs := cpia1.o -gspca_etoms-objs := etoms.o -gspca_finepix-objs := finepix.o -gspca_jeilinj-objs := jeilinj.o -gspca_konica-objs := konica.o -gspca_mars-objs := mars.o -gspca_mr97310a-objs := mr97310a.o -gspca_nw80x-objs := nw80x.o -gspca_ov519-objs := ov519.o -gspca_ov534-objs := ov534.o -gspca_ov534_9-objs := ov534_9.o -gspca_pac207-objs := pac207.o -gspca_pac7302-objs := pac7302.o -gspca_pac7311-objs := pac7311.o -gspca_sn9c2028-objs := sn9c2028.o -gspca_sn9c20x-objs := sn9c20x.o -gspca_sonixb-objs := sonixb.o -gspca_sonixj-objs := sonixj.o -gspca_spca500-objs := spca500.o -gspca_spca501-objs := spca501.o -gspca_spca505-objs := spca505.o -gspca_spca506-objs := spca506.o -gspca_spca508-objs := spca508.o -gspca_spca561-objs := spca561.o -gspca_spca1528-objs := spca1528.o -gspca_sq905-objs := sq905.o -gspca_sq905c-objs := sq905c.o -gspca_sq930x-objs := sq930x.o -gspca_stk014-objs := stk014.o -gspca_stv0680-objs := stv0680.o -gspca_sunplus-objs := sunplus.o -gspca_t613-objs := t613.o -gspca_tv8532-objs := tv8532.o -gspca_vc032x-objs := vc032x.o -gspca_vicam-objs := vicam.o -gspca_xirlink_cit-objs := xirlink_cit.o -gspca_zc3xx-objs := zc3xx.o - -obj-$(CONFIG_USB_M5602) += m5602/ -obj-$(CONFIG_USB_STV06XX) += stv06xx/ -obj-$(CONFIG_USB_GL860) += gl860/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/mars.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/mars.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/mars.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/mars.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,529 +0,0 @@ -/* - * Mars-Semi MR97311A library - * Copyright (C) 2005 - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "mars" - -#include "gspca.h" -#include "jpeg.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* controls */ -enum e_ctrl { - BRIGHTNESS, - COLORS, - GAMMA, - SHARPNESS, - ILLUM_TOP, - ILLUM_BOT, - NCTRLS /* number of controls */ -}; - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRLS]; - - u8 quality; -#define QUALITY_MIN 40 -#define QUALITY_MAX 70 -#define QUALITY_DEF 50 - - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; - -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void setgamma(struct gspca_dev *gspca_dev); -static void setsharpness(struct gspca_dev *gspca_dev); -static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val); -static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 30, - .step = 1, - .default_value = 15, - }, - .set_control = setbrightness - }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 200, - }, - .set_control = setcolors - }, -[GAMMA] = { - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 1, - }, - .set_control = setgamma - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 2, - .step = 1, - .default_value = 1, - }, - .set_control = setsharpness - }, -[ILLUM_TOP] = { - { - .id = V4L2_CID_ILLUMINATORS_1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Top illuminator", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = V4L2_CTRL_FLAG_UPDATE, - }, - .set = sd_setilluminator1 - }, -[ILLUM_BOT] = { - { - .id = V4L2_CID_ILLUMINATORS_2, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Bottom illuminator", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = V4L2_CTRL_FLAG_UPDATE, - }, - .set = sd_setilluminator2 - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, -}; - -static const __u8 mi_data[0x20] = { -/* 01 02 03 04 05 06 07 08 */ - 0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00, -/* 09 0a 0b 0c 0d 0e 0f 10 */ - 0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, -/* 11 12 13 14 15 16 17 18 */ - 0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02, -/* 19 1a 1b 1c 1d 1e 1f 20 */ - 0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00 -}; - -/* write bytes from gspca_dev->usb_buf */ -static void reg_w(struct gspca_dev *gspca_dev, - int len) -{ - int alen, ret; - - if (gspca_dev->usb_err < 0) - return; - - ret = usb_bulk_msg(gspca_dev->dev, - usb_sndbulkpipe(gspca_dev->dev, 4), - gspca_dev->usb_buf, - len, - &alen, - 500); /* timeout in milliseconds */ - if (ret < 0) { - err("reg write [%02x] error %d", - gspca_dev->usb_buf[0], ret); - gspca_dev->usb_err = ret; - } -} - -static void mi_w(struct gspca_dev *gspca_dev, - u8 addr, - u8 value) -{ - gspca_dev->usb_buf[0] = 0x1f; - gspca_dev->usb_buf[1] = 0; /* control byte */ - gspca_dev->usb_buf[2] = addr; - gspca_dev->usb_buf[3] = value; - - reg_w(gspca_dev, 4); -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->usb_buf[0] = 0x61; - gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val; - reg_w(gspca_dev, 2); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - s16 val; - - val = sd->ctrls[COLORS].val; - gspca_dev->usb_buf[0] = 0x5f; - gspca_dev->usb_buf[1] = val << 3; - gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04; - reg_w(gspca_dev, 3); -} - -static void setgamma(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->usb_buf[0] = 0x06; - gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40; - reg_w(gspca_dev, 2); -} - -static void setsharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->usb_buf[0] = 0x67; - gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3; - reg_w(gspca_dev, 2); -} - -static void setilluminators(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->usb_buf[0] = 0x22; - if (sd->ctrls[ILLUM_TOP].val) - gspca_dev->usb_buf[1] = 0x76; - else if (sd->ctrls[ILLUM_BOT].val) - gspca_dev->usb_buf[1] = 0x7a; - else - gspca_dev->usb_buf[1] = 0x7e; - reg_w(gspca_dev, 2); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - cam->ctrls = sd->ctrls; - sd->quality = QUALITY_DEF; - gspca_dev->nbalt = 9; /* use the altsetting 08 */ - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT); - return 0; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 *data; - int i; - - /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x21); /* JPEG 422 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - - data = gspca_dev->usb_buf; - - data[0] = 0x01; /* address */ - data[1] = 0x01; - reg_w(gspca_dev, 2); - - /* - Initialize the MR97113 chip register - */ - data[0] = 0x00; /* address */ - data[1] = 0x0c | 0x01; /* reg 0 */ - data[2] = 0x01; /* reg 1 */ - data[3] = gspca_dev->width / 8; /* h_size , reg 2 */ - data[4] = gspca_dev->height / 8; /* v_size , reg 3 */ - data[5] = 0x30; /* reg 4, MI, PAS5101 : - * 0x30 for 24mhz , 0x28 for 12mhz */ - data[6] = 0x02; /* reg 5, H start - was 0x04 */ - data[7] = sd->ctrls[GAMMA].val * 0x40; /* reg 0x06: gamma */ - data[8] = 0x01; /* reg 7, V start - was 0x03 */ -/* if (h_size == 320 ) */ -/* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */ -/* else */ - data[9] = 0x52; /* reg 8, 24MHz, no scale down */ -/*jfm: from win trace*/ - data[10] = 0x18; - - reg_w(gspca_dev, 11); - - data[0] = 0x23; /* address */ - data[1] = 0x09; /* reg 35, append frame header */ - - reg_w(gspca_dev, 2); - - data[0] = 0x3c; /* address */ -/* if (gspca_dev->width == 1280) */ -/* data[1] = 200; * reg 60, pc-cam frame size - * (unit: 4KB) 800KB */ -/* else */ - data[1] = 50; /* 50 reg 60, pc-cam frame size - * (unit: 4KB) 200KB */ - reg_w(gspca_dev, 2); - - /* auto dark-gain */ - data[0] = 0x5e; /* address */ - data[1] = 0; /* reg 94, Y Gain (auto) */ -/*jfm: from win trace*/ - /* reg 0x5f/0x60 (LE) = saturation */ - /* h (60): xxxx x100 - * l (5f): xxxx x000 */ - data[2] = sd->ctrls[COLORS].val << 3; - data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04; - data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */ - data[5] = 0x00; - - reg_w(gspca_dev, 6); - - data[0] = 0x67; -/*jfm: from win trace*/ - data[1] = sd->ctrls[SHARPNESS].val * 4 + 3; - data[2] = 0x14; - reg_w(gspca_dev, 3); - - data[0] = 0x69; - data[1] = 0x2f; - data[2] = 0x28; - data[3] = 0x42; - reg_w(gspca_dev, 4); - - data[0] = 0x63; - data[1] = 0x07; - reg_w(gspca_dev, 2); -/*jfm: win trace - many writes here to reg 0x64*/ - - /* initialize the MI sensor */ - for (i = 0; i < sizeof mi_data; i++) - mi_w(gspca_dev, i + 1, mi_data[i]); - - data[0] = 0x00; - data[1] = 0x4d; /* ISOC transfering enable... */ - reg_w(gspca_dev, 2); - - gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */ - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT); - if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) { - sd->ctrls[ILLUM_TOP].val = 0; - sd->ctrls[ILLUM_BOT].val = 0; - setilluminators(gspca_dev); - msleep(20); - } - - gspca_dev->usb_buf[0] = 1; - gspca_dev->usb_buf[1] = 0; - reg_w(gspca_dev, 2); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - int p; - - if (len < 6) { -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; - } - for (p = 0; p < len - 6; p++) { - if (data[0 + p] == 0xff - && data[1 + p] == 0xff - && data[2 + p] == 0x00 - && data[3 + p] == 0xff - && data[4 + p] == 0x96) { - if (data[5 + p] == 0x64 - || data[5 + p] == 0x65 - || data[5 + p] == 0x66 - || data[5 + p] == 0x67) { - PDEBUG(D_PACK, "sof offset: %d len: %d", - p, len); - gspca_frame_add(gspca_dev, LAST_PACKET, - data, p); - - /* put the JPEG header */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - data += p + 16; - len -= p + 16; - break; - } - } - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* only one illuminator may be on */ - sd->ctrls[ILLUM_TOP].val = val; - if (val) - sd->ctrls[ILLUM_BOT].val = 0; - setilluminators(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* only one illuminator may be on */ - sd->ctrls[ILLUM_BOT].val = val; - if (val) - sd->ctrls[ILLUM_TOP].val = 0; - setilluminators(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return 0; -} - -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = NCTRLS, - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x093a, 0x050f)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/mr97310a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/mr97310a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/mr97310a.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/mr97310a.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1271 +0,0 @@ -/* - * Mars MR97310A library - * - * The original mr97310a driver, which supported the Aiptek Pencam VGA+, is - * Copyright (C) 2009 Kyle Guinn - * - * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+ - * and for the routines for detecting and classifying these various cameras, - * is Copyright (C) 2009 Theodore Kilgore - * - * Support for the control settings for the CIF cameras is - * Copyright (C) 2009 Hans de Goede and - * Thomas Kaiser - * - * Support for the control settings for the VGA cameras is - * Copyright (C) 2009 Theodore Kilgore - * - * Several previously unsupported cameras are owned and have been tested by - * Hans de Goede and - * Thomas Kaiser and - * Theodore Kilgore and - * Edmond Rodriguez and - * Aurelien Jacobs - * - * The MR97311A support in gspca/mars.c has been helpful in understanding some - * of the registers in these cameras. - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "mr97310a" - -#include "gspca.h" - -#define CAM_TYPE_CIF 0 -#define CAM_TYPE_VGA 1 - -#define MR97310A_BRIGHTNESS_DEFAULT 0 - -#define MR97310A_EXPOSURE_MIN 0 -#define MR97310A_EXPOSURE_MAX 4095 -#define MR97310A_EXPOSURE_DEFAULT 1000 - -#define MR97310A_GAIN_MIN 0 -#define MR97310A_GAIN_MAX 31 -#define MR97310A_GAIN_DEFAULT 25 - -#define MR97310A_CONTRAST_MIN 0 -#define MR97310A_CONTRAST_MAX 31 -#define MR97310A_CONTRAST_DEFAULT 23 - -#define MR97310A_CS_GAIN_MIN 0 -#define MR97310A_CS_GAIN_MAX 0x7ff -#define MR97310A_CS_GAIN_DEFAULT 0x110 - -#define MR97310A_MIN_CLOCKDIV_MIN 3 -#define MR97310A_MIN_CLOCKDIV_MAX 8 -#define MR97310A_MIN_CLOCKDIV_DEFAULT 3 - -MODULE_AUTHOR("Kyle Guinn ," - "Theodore Kilgore "); -MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* global parameters */ -static int force_sensor_type = -1; -module_param(force_sensor_type, int, 0644); -MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - u8 sof_read; - u8 cam_type; /* 0 is CIF and 1 is VGA */ - u8 sensor_type; /* We use 0 and 1 here, too. */ - u8 do_lcd_stop; - u8 adj_colors; - - int brightness; - u16 exposure; - u32 gain; - u8 contrast; - u8 min_clockdiv; -}; - -struct sensor_w_data { - u8 reg; - u8 flags; - u8 data[16]; - int len; -}; - -static void sd_stopN(struct gspca_dev *gspca_dev); -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val); -static void setbrightness(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static void setgain(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); - -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[] = { -/* Separate brightness control description for Argus QuickClix as it has - * different limits from the other mr97310a cameras, and separate gain - * control for Sakar CyberPix camera. */ - { -#define NORM_BRIGHTNESS_IDX 0 - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = -254, - .maximum = 255, - .step = 1, - .default_value = MR97310A_BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { -#define ARGUS_QC_BRIGHTNESS_IDX 1 - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = MR97310A_BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { -#define EXPOSURE_IDX 2 - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = MR97310A_EXPOSURE_MIN, - .maximum = MR97310A_EXPOSURE_MAX, - .step = 1, - .default_value = MR97310A_EXPOSURE_DEFAULT, - .flags = 0, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { -#define GAIN_IDX 3 - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = MR97310A_GAIN_MIN, - .maximum = MR97310A_GAIN_MAX, - .step = 1, - .default_value = MR97310A_GAIN_DEFAULT, - .flags = 0, - }, - .set = sd_setgain, - .get = sd_getgain, - }, - { -#define SAKAR_CS_GAIN_IDX 4 - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = MR97310A_CS_GAIN_MIN, - .maximum = MR97310A_CS_GAIN_MAX, - .step = 1, - .default_value = MR97310A_CS_GAIN_DEFAULT, - .flags = 0, - }, - .set = sd_setgain, - .get = sd_getgain, - }, - { -#define CONTRAST_IDX 5 - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = MR97310A_CONTRAST_MIN, - .maximum = MR97310A_CONTRAST_MAX, - .step = 1, - .default_value = MR97310A_CONTRAST_DEFAULT, - .flags = 0, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { -#define MIN_CLOCKDIV_IDX 6 - { - .id = V4L2_CID_PRIVATE_BASE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Minimum Clock Divider", - .minimum = MR97310A_MIN_CLOCKDIV_MIN, - .maximum = MR97310A_MIN_CLOCKDIV_MAX, - .step = 1, - .default_value = MR97310A_MIN_CLOCKDIV_DEFAULT, - .flags = 0, - }, - .set = sd_setmin_clockdiv, - .get = sd_getmin_clockdiv, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 4}, - {176, 144, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 3}, - {320, 240, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {352, 288, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -/* the bytes to write are in gspca_dev->usb_buf */ -static int mr_write(struct gspca_dev *gspca_dev, int len) -{ - int rc; - - rc = usb_bulk_msg(gspca_dev->dev, - usb_sndbulkpipe(gspca_dev->dev, 4), - gspca_dev->usb_buf, len, NULL, 500); - if (rc < 0) - err("reg write [%02x] error %d", - gspca_dev->usb_buf[0], rc); - return rc; -} - -/* the bytes are read into gspca_dev->usb_buf */ -static int mr_read(struct gspca_dev *gspca_dev, int len) -{ - int rc; - - rc = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 3), - gspca_dev->usb_buf, len, NULL, 500); - if (rc < 0) - err("reg read [%02x] error %d", - gspca_dev->usb_buf[0], rc); - return rc; -} - -static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags, - const u8 *data, int len) -{ - gspca_dev->usb_buf[0] = 0x1f; - gspca_dev->usb_buf[1] = flags; - gspca_dev->usb_buf[2] = reg; - memcpy(gspca_dev->usb_buf + 3, data, len); - - return mr_write(gspca_dev, len + 3); -} - -static int sensor_write_regs(struct gspca_dev *gspca_dev, - const struct sensor_w_data *data, int len) -{ - int i, rc; - - for (i = 0; i < len; i++) { - rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags, - data[i].data, data[i].len); - if (rc < 0) - return rc; - } - - return 0; -} - -static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 buf, confirm_reg; - int rc; - - buf = data; - if (sd->cam_type == CAM_TYPE_CIF) { - rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1); - confirm_reg = sd->sensor_type ? 0x13 : 0x11; - } else { - rc = sensor_write_reg(gspca_dev, reg, 0x00, &buf, 1); - confirm_reg = 0x11; - } - if (rc < 0) - return rc; - - buf = 0x01; - rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1); - if (rc < 0) - return rc; - - return 0; -} - -static int cam_get_response16(struct gspca_dev *gspca_dev, u8 reg, int verbose) -{ - int err_code; - - gspca_dev->usb_buf[0] = reg; - err_code = mr_write(gspca_dev, 1); - if (err_code < 0) - return err_code; - - err_code = mr_read(gspca_dev, 16); - if (err_code < 0) - return err_code; - - if (verbose) - PDEBUG(D_PROBE, "Register: %02x reads %02x%02x%02x", reg, - gspca_dev->usb_buf[0], - gspca_dev->usb_buf[1], - gspca_dev->usb_buf[2]); - - return 0; -} - -static int zero_the_pointer(struct gspca_dev *gspca_dev) -{ - __u8 *data = gspca_dev->usb_buf; - int err_code; - u8 status = 0; - int tries = 0; - - err_code = cam_get_response16(gspca_dev, 0x21, 0); - if (err_code < 0) - return err_code; - - data[0] = 0x19; - data[1] = 0x51; - err_code = mr_write(gspca_dev, 2); - if (err_code < 0) - return err_code; - - err_code = cam_get_response16(gspca_dev, 0x21, 0); - if (err_code < 0) - return err_code; - - data[0] = 0x19; - data[1] = 0xba; - err_code = mr_write(gspca_dev, 2); - if (err_code < 0) - return err_code; - - err_code = cam_get_response16(gspca_dev, 0x21, 0); - if (err_code < 0) - return err_code; - - data[0] = 0x19; - data[1] = 0x00; - err_code = mr_write(gspca_dev, 2); - if (err_code < 0) - return err_code; - - err_code = cam_get_response16(gspca_dev, 0x21, 0); - if (err_code < 0) - return err_code; - - data[0] = 0x19; - data[1] = 0x00; - err_code = mr_write(gspca_dev, 2); - if (err_code < 0) - return err_code; - - while (status != 0x0a && tries < 256) { - err_code = cam_get_response16(gspca_dev, 0x21, 0); - status = data[0]; - tries++; - if (err_code < 0) - return err_code; - } - if (status != 0x0a) - PDEBUG(D_ERR, "status is %02x", status); - - tries = 0; - while (tries < 4) { - data[0] = 0x19; - data[1] = 0x00; - err_code = mr_write(gspca_dev, 2); - if (err_code < 0) - return err_code; - - err_code = cam_get_response16(gspca_dev, 0x21, 0); - status = data[0]; - tries++; - if (err_code < 0) - return err_code; - } - - data[0] = 0x19; - err_code = mr_write(gspca_dev, 1); - if (err_code < 0) - return err_code; - - err_code = mr_read(gspca_dev, 16); - if (err_code < 0) - return err_code; - - return 0; -} - -static int stream_start(struct gspca_dev *gspca_dev) -{ - gspca_dev->usb_buf[0] = 0x01; - gspca_dev->usb_buf[1] = 0x01; - return mr_write(gspca_dev, 2); -} - -static void stream_stop(struct gspca_dev *gspca_dev) -{ - gspca_dev->usb_buf[0] = 0x01; - gspca_dev->usb_buf[1] = 0x00; - if (mr_write(gspca_dev, 2) < 0) - PDEBUG(D_ERR, "Stream Stop failed"); -} - -static void lcd_stop(struct gspca_dev *gspca_dev) -{ - gspca_dev->usb_buf[0] = 0x19; - gspca_dev->usb_buf[1] = 0x54; - if (mr_write(gspca_dev, 2) < 0) - PDEBUG(D_ERR, "LCD Stop failed"); -} - -static int isoc_enable(struct gspca_dev *gspca_dev) -{ - gspca_dev->usb_buf[0] = 0x00; - gspca_dev->usb_buf[1] = 0x4d; /* ISOC transfering enable... */ - return mr_write(gspca_dev, 2); -} - -/* This function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - int gain_default = MR97310A_GAIN_DEFAULT; - int err_code; - - cam = &gspca_dev->cam; - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - sd->do_lcd_stop = 0; - - /* Several of the supported CIF cameras share the same USB ID but - * require different initializations and different control settings. - * The same is true of the VGA cameras. Therefore, we are forced - * to start the initialization process in order to determine which - * camera is present. Some of the supported cameras require the - * memory pointer to be set to 0 as the very first item of business - * or else they will not stream. So we do that immediately. - */ - err_code = zero_the_pointer(gspca_dev); - if (err_code < 0) - return err_code; - - err_code = stream_start(gspca_dev); - if (err_code < 0) - return err_code; - - /* Now, the query for sensor type. */ - err_code = cam_get_response16(gspca_dev, 0x07, 1); - if (err_code < 0) - return err_code; - - if (id->idProduct == 0x0110 || id->idProduct == 0x010e) { - sd->cam_type = CAM_TYPE_CIF; - cam->nmodes--; - /* - * All but one of the known CIF cameras share the same USB ID, - * but two different init routines are in use, and the control - * settings are different, too. We need to detect which camera - * of the two known varieties is connected! - * - * A list of known CIF cameras follows. They all report either - * 0200 for type 0 or 0300 for type 1. - * If you have another to report, please do - * - * Name sd->sensor_type reported by - * - * Sakar 56379 Spy-shot 0 T. Kilgore - * Innovage 0 T. Kilgore - * Vivitar Mini 0 H. De Goede - * Vivitar Mini 0 E. Rodriguez - * Vivitar Mini 1 T. Kilgore - * Elta-Media 8212dc 1 T. Kaiser - * Philips dig. keych. 1 T. Kilgore - * Trust Spyc@m 100 1 A. Jacobs - */ - switch (gspca_dev->usb_buf[0]) { - case 2: - sd->sensor_type = 0; - break; - case 3: - sd->sensor_type = 1; - break; - default: - err("Unknown CIF Sensor id : %02x", - gspca_dev->usb_buf[1]); - return -ENODEV; - } - PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d", - sd->sensor_type); - } else { - sd->cam_type = CAM_TYPE_VGA; - - /* - * Here is a table of the responses to the query for sensor - * type, from the known MR97310A VGA cameras. Six different - * cameras of which five share the same USB ID. - * - * Name gspca_dev->usb_buf[] sd->sensor_type - * sd->do_lcd_stop - * Aiptek Pencam VGA+ 0300 0 1 - * ION digital 0300 0 1 - * Argus DC-1620 0450 1 0 - * Argus QuickClix 0420 1 1 - * Sakar 77379 Digital 0350 0 1 - * Sakar 1638x CyberPix 0120 0 2 - * - * Based upon these results, we assume default settings - * and then correct as necessary, as follows. - * - */ - - sd->sensor_type = 1; - sd->do_lcd_stop = 0; - sd->adj_colors = 0; - if (gspca_dev->usb_buf[0] == 0x01) { - sd->sensor_type = 2; - } else if ((gspca_dev->usb_buf[0] != 0x03) && - (gspca_dev->usb_buf[0] != 0x04)) { - err("Unknown VGA Sensor id Byte 0: %02x", - gspca_dev->usb_buf[0]); - err("Defaults assumed, may not work"); - err("Please report this"); - } - /* Sakar Digital color needs to be adjusted. */ - if ((gspca_dev->usb_buf[0] == 0x03) && - (gspca_dev->usb_buf[1] == 0x50)) - sd->adj_colors = 1; - if (gspca_dev->usb_buf[0] == 0x04) { - sd->do_lcd_stop = 1; - switch (gspca_dev->usb_buf[1]) { - case 0x50: - sd->sensor_type = 0; - PDEBUG(D_PROBE, "sensor_type corrected to 0"); - break; - case 0x20: - /* Nothing to do here. */ - break; - default: - err("Unknown VGA Sensor id Byte 1: %02x", - gspca_dev->usb_buf[1]); - err("Defaults assumed, may not work"); - err("Please report this"); - } - } - PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d", - sd->sensor_type); - } - /* Stop streaming as we've started it only to probe the sensor type. */ - sd_stopN(gspca_dev); - - if (force_sensor_type != -1) { - sd->sensor_type = !!force_sensor_type; - PDEBUG(D_PROBE, "Forcing sensor type to: %d", - sd->sensor_type); - } - - /* Setup controls depending on camera type */ - if (sd->cam_type == CAM_TYPE_CIF) { - /* No brightness for sensor_type 0 */ - if (sd->sensor_type == 0) - gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | - (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX); - else - gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX) | - (1 << MIN_CLOCKDIV_IDX); - } else { - /* All controls need to be disabled if VGA sensor_type is 0 */ - if (sd->sensor_type == 0) - gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | - (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << EXPOSURE_IDX) | - (1 << GAIN_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX) | - (1 << MIN_CLOCKDIV_IDX); - else if (sd->sensor_type == 2) { - gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | - (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << GAIN_IDX) | - (1 << MIN_CLOCKDIV_IDX); - gain_default = MR97310A_CS_GAIN_DEFAULT; - } else if (sd->do_lcd_stop) - /* Argus QuickClix has different brightness limits */ - gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX); - else - gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX); - } - - sd->brightness = MR97310A_BRIGHTNESS_DEFAULT; - sd->exposure = MR97310A_EXPOSURE_DEFAULT; - sd->gain = gain_default; - sd->contrast = MR97310A_CONTRAST_DEFAULT; - sd->min_clockdiv = MR97310A_MIN_CLOCKDIV_DEFAULT; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - return 0; -} - -static int start_cif_cam(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 *data = gspca_dev->usb_buf; - int err_code; - static const __u8 startup_string[] = { - 0x00, - 0x0d, - 0x01, - 0x00, /* Hsize/8 for 352 or 320 */ - 0x00, /* Vsize/4 for 288 or 240 */ - 0x13, /* or 0xbb, depends on sensor */ - 0x00, /* Hstart, depends on res. */ - 0x00, /* reserved ? */ - 0x00, /* Vstart, depends on res. and sensor */ - 0x50, /* 0x54 to get 176 or 160 */ - 0xc0 - }; - - /* Note: Some of the above descriptions guessed from MR97113A driver */ - - memcpy(data, startup_string, 11); - if (sd->sensor_type) - data[5] = 0xbb; - - switch (gspca_dev->width) { - case 160: - data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */ - /* fall thru */ - case 320: - default: - data[3] = 0x28; /* reg 2, H size/8 */ - data[4] = 0x3c; /* reg 3, V size/4 */ - data[6] = 0x14; /* reg 5, H start */ - data[8] = 0x1a + sd->sensor_type; /* reg 7, V start */ - break; - case 176: - data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */ - /* fall thru */ - case 352: - data[3] = 0x2c; /* reg 2, H size/8 */ - data[4] = 0x48; /* reg 3, V size/4 */ - data[6] = 0x06; /* reg 5, H start */ - data[8] = 0x06 - sd->sensor_type; /* reg 7, V start */ - break; - } - err_code = mr_write(gspca_dev, 11); - if (err_code < 0) - return err_code; - - if (!sd->sensor_type) { - static const struct sensor_w_data cif_sensor0_init_data[] = { - {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01, - 0x0f, 0x14, 0x0f, 0x10}, 8}, - {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5}, - {0x12, 0x00, {0x07}, 1}, - {0x1f, 0x00, {0x06}, 1}, - {0x27, 0x00, {0x04}, 1}, - {0x29, 0x00, {0x0c}, 1}, - {0x40, 0x00, {0x40, 0x00, 0x04}, 3}, - {0x50, 0x00, {0x60}, 1}, - {0x60, 0x00, {0x06}, 1}, - {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6}, - {0x72, 0x00, {0x1e, 0x56}, 2}, - {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02, - 0x31, 0x80, 0x00}, 9}, - {0x11, 0x00, {0x01}, 1}, - {0, 0, {0}, 0} - }; - err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data, - ARRAY_SIZE(cif_sensor0_init_data)); - } else { /* sd->sensor_type = 1 */ - static const struct sensor_w_data cif_sensor1_init_data[] = { - /* Reg 3,4, 7,8 get set by the controls */ - {0x02, 0x00, {0x10}, 1}, - {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */ - {0x06, 0x01, {0x00}, 1}, - {0x09, 0x02, {0x0e}, 1}, - {0x0a, 0x02, {0x05}, 1}, - {0x0b, 0x02, {0x05}, 1}, - {0x0c, 0x02, {0x0f}, 1}, - {0x0d, 0x02, {0x07}, 1}, - {0x0e, 0x02, {0x0c}, 1}, - {0x0f, 0x00, {0x00}, 1}, - {0x10, 0x00, {0x06}, 1}, - {0x11, 0x00, {0x07}, 1}, - {0x12, 0x00, {0x00}, 1}, - {0x13, 0x00, {0x01}, 1}, - {0, 0, {0}, 0} - }; - /* Without this command the cam won't work with USB-UHCI */ - gspca_dev->usb_buf[0] = 0x0a; - gspca_dev->usb_buf[1] = 0x00; - err_code = mr_write(gspca_dev, 2); - if (err_code < 0) - return err_code; - err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data, - ARRAY_SIZE(cif_sensor1_init_data)); - } - return err_code; -} - -static int start_vga_cam(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 *data = gspca_dev->usb_buf; - int err_code; - static const __u8 startup_string[] = - {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, 0x00, 0x00, - 0x00, 0x50, 0xc0}; - /* What some of these mean is explained in start_cif_cam(), above */ - - memcpy(data, startup_string, 11); - if (!sd->sensor_type) { - data[5] = 0x00; - data[10] = 0x91; - } - if (sd->sensor_type == 2) { - data[5] = 0x00; - data[10] = 0x18; - } - - switch (gspca_dev->width) { - case 160: - data[9] |= 0x0c; /* reg 8, 4:1 scale down */ - /* fall thru */ - case 320: - data[9] |= 0x04; /* reg 8, 2:1 scale down */ - /* fall thru */ - case 640: - default: - data[3] = 0x50; /* reg 2, H size/8 */ - data[4] = 0x78; /* reg 3, V size/4 */ - data[6] = 0x04; /* reg 5, H start */ - data[8] = 0x03; /* reg 7, V start */ - if (sd->sensor_type == 2) { - data[6] = 2; - data[8] = 1; - } - if (sd->do_lcd_stop) - data[8] = 0x04; /* Bayer tile shifted */ - break; - - case 176: - data[9] |= 0x04; /* reg 8, 2:1 scale down */ - /* fall thru */ - case 352: - data[3] = 0x2c; /* reg 2, H size */ - data[4] = 0x48; /* reg 3, V size */ - data[6] = 0x94; /* reg 5, H start */ - data[8] = 0x63; /* reg 7, V start */ - if (sd->do_lcd_stop) - data[8] = 0x64; /* Bayer tile shifted */ - break; - } - - err_code = mr_write(gspca_dev, 11); - if (err_code < 0) - return err_code; - - if (!sd->sensor_type) { - static const struct sensor_w_data vga_sensor0_init_data[] = { - {0x01, 0x00, {0x0c, 0x00, 0x04}, 3}, - {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4}, - {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4}, - {0x25, 0x00, {0x03, 0xa9, 0x80}, 3}, - {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4}, - {0, 0, {0}, 0} - }; - err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data, - ARRAY_SIZE(vga_sensor0_init_data)); - } else if (sd->sensor_type == 1) { - static const struct sensor_w_data color_adj[] = { - {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00, - /* adjusted blue, green, red gain correct - too much blue from the Sakar Digital */ - 0x05, 0x01, 0x04}, 8} - }; - - static const struct sensor_w_data color_no_adj[] = { - {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00, - /* default blue, green, red gain settings */ - 0x07, 0x00, 0x01}, 8} - }; - - static const struct sensor_w_data vga_sensor1_init_data[] = { - {0x11, 0x04, {0x01}, 1}, - {0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01, - /* These settings may be better for some cameras */ - /* {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, */ - 0x00, 0x0a}, 7}, - {0x11, 0x04, {0x01}, 1}, - {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6}, - {0x11, 0x04, {0x01}, 1}, - {0, 0, {0}, 0} - }; - - if (sd->adj_colors) - err_code = sensor_write_regs(gspca_dev, color_adj, - ARRAY_SIZE(color_adj)); - else - err_code = sensor_write_regs(gspca_dev, color_no_adj, - ARRAY_SIZE(color_no_adj)); - - if (err_code < 0) - return err_code; - - err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data, - ARRAY_SIZE(vga_sensor1_init_data)); - } else { /* sensor type == 2 */ - static const struct sensor_w_data vga_sensor2_init_data[] = { - - {0x01, 0x00, {0x48}, 1}, - {0x02, 0x00, {0x22}, 1}, - /* Reg 3 msb and 4 is lsb of the exposure setting*/ - {0x05, 0x00, {0x10}, 1}, - {0x06, 0x00, {0x00}, 1}, - {0x07, 0x00, {0x00}, 1}, - {0x08, 0x00, {0x00}, 1}, - {0x09, 0x00, {0x00}, 1}, - /* The following are used in the gain control - * which is BTW completely borked in the OEM driver - * The values for each color go from 0 to 0x7ff - *{0x0a, 0x00, {0x01}, 1}, green1 gain msb - *{0x0b, 0x00, {0x10}, 1}, green1 gain lsb - *{0x0c, 0x00, {0x01}, 1}, red gain msb - *{0x0d, 0x00, {0x10}, 1}, red gain lsb - *{0x0e, 0x00, {0x01}, 1}, blue gain msb - *{0x0f, 0x00, {0x10}, 1}, blue gain lsb - *{0x10, 0x00, {0x01}, 1}, green2 gain msb - *{0x11, 0x00, {0x10}, 1}, green2 gain lsb - */ - {0x12, 0x00, {0x00}, 1}, - {0x13, 0x00, {0x04}, 1}, /* weird effect on colors */ - {0x14, 0x00, {0x00}, 1}, - {0x15, 0x00, {0x06}, 1}, - {0x16, 0x00, {0x01}, 1}, - {0x17, 0x00, {0xe2}, 1}, /* vertical alignment */ - {0x18, 0x00, {0x02}, 1}, - {0x19, 0x00, {0x82}, 1}, /* don't mess with */ - {0x1a, 0x00, {0x00}, 1}, - {0x1b, 0x00, {0x20}, 1}, - /* {0x1c, 0x00, {0x17}, 1}, contrast control */ - {0x1d, 0x00, {0x80}, 1}, /* moving causes a mess */ - {0x1e, 0x00, {0x08}, 1}, /* moving jams the camera */ - {0x1f, 0x00, {0x0c}, 1}, - {0x20, 0x00, {0x00}, 1}, - {0, 0, {0}, 0} - }; - err_code = sensor_write_regs(gspca_dev, vga_sensor2_init_data, - ARRAY_SIZE(vga_sensor2_init_data)); - } - return err_code; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int err_code; - - sd->sof_read = 0; - - /* Some of the VGA cameras require the memory pointer - * to be set to 0 again. We have been forced to start the - * stream in sd_config() to detect the hardware, and closed it. - * Thus, we need here to do a completely fresh and clean start. */ - err_code = zero_the_pointer(gspca_dev); - if (err_code < 0) - return err_code; - - err_code = stream_start(gspca_dev); - if (err_code < 0) - return err_code; - - if (sd->cam_type == CAM_TYPE_CIF) { - err_code = start_cif_cam(gspca_dev); - } else { - err_code = start_vga_cam(gspca_dev); - } - if (err_code < 0) - return err_code; - - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setexposure(gspca_dev); - setgain(gspca_dev); - - return isoc_enable(gspca_dev); -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - stream_stop(gspca_dev); - /* Not all the cams need this, but even if not, probably a good idea */ - zero_the_pointer(gspca_dev); - if (sd->do_lcd_stop) - lcd_stop(gspca_dev); -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */ - u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */ - static const u8 quick_clix_table[] = - /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ - { 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15}; - /* - * This control is disabled for CIF type 1 and VGA type 0 cameras. - * It does not quite act linearly for the Argus QuickClix camera, - * but it does control brightness. The values are 0 - 15 only, and - * the table above makes them act consecutively. - */ - if ((gspca_dev->ctrl_dis & (1 << NORM_BRIGHTNESS_IDX)) && - (gspca_dev->ctrl_dis & (1 << ARGUS_QC_BRIGHTNESS_IDX))) - return; - - if (sd->cam_type == CAM_TYPE_VGA) { - sign_reg += 4; - value_reg += 4; - } - - /* Note register 7 is also seen as 0x8x or 0xCx in some dumps */ - if (sd->brightness > 0) { - sensor_write1(gspca_dev, sign_reg, 0x00); - val = sd->brightness; - } else { - sensor_write1(gspca_dev, sign_reg, 0x01); - val = (257 - sd->brightness); - } - /* Use lookup table for funky Argus QuickClix brightness */ - if (sd->do_lcd_stop) - val = quick_clix_table[val]; - - sensor_write1(gspca_dev, value_reg, val); -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int exposure = MR97310A_EXPOSURE_DEFAULT; - u8 buf[2]; - - if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) - return; - - if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) { - /* This cam does not like exposure settings < 300, - so scale 0 - 4095 to 300 - 4095 */ - exposure = (sd->exposure * 9267) / 10000 + 300; - sensor_write1(gspca_dev, 3, exposure >> 4); - sensor_write1(gspca_dev, 4, exposure & 0x0f); - } else if (sd->sensor_type == 2) { - exposure = sd->exposure; - exposure >>= 3; - sensor_write1(gspca_dev, 3, exposure >> 8); - sensor_write1(gspca_dev, 4, exposure & 0xff); - } else { - /* We have both a clock divider and an exposure register. - We first calculate the clock divider, as that determines - the maximum exposure and then we calculate the exposure - register setting (which goes from 0 - 511). - - Note our 0 - 4095 exposure is mapped to 0 - 511 - milliseconds exposure time */ - u8 clockdiv = (60 * sd->exposure + 7999) / 8000; - - /* Limit framerate to not exceed usb bandwidth */ - if (clockdiv < sd->min_clockdiv && gspca_dev->width >= 320) - clockdiv = sd->min_clockdiv; - else if (clockdiv < 2) - clockdiv = 2; - - if (sd->cam_type == CAM_TYPE_VGA && clockdiv < 4) - clockdiv = 4; - - /* Frame exposure time in ms = 1000 * clockdiv / 60 -> - exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */ - exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv); - if (exposure > 511) - exposure = 511; - - /* exposure register value is reversed! */ - exposure = 511 - exposure; - - buf[0] = exposure & 0xff; - buf[1] = exposure >> 8; - sensor_write_reg(gspca_dev, 0x0e, 0, buf, 2); - sensor_write1(gspca_dev, 0x02, clockdiv); - } -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 gainreg; - - if ((gspca_dev->ctrl_dis & (1 << GAIN_IDX)) && - (gspca_dev->ctrl_dis & (1 << SAKAR_CS_GAIN_IDX))) - return; - - if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) - sensor_write1(gspca_dev, 0x0e, sd->gain); - else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2) - for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) { - sensor_write1(gspca_dev, gainreg, sd->gain >> 8); - sensor_write1(gspca_dev, gainreg + 1, sd->gain & 0xff); - } - else - sensor_write1(gspca_dev, 0x10, sd->gain); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX)) - return; - - sensor_write1(gspca_dev, 0x1c, sd->contrast); -} - - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->min_clockdiv = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} - -static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->min_clockdiv; - return 0; -} - -/* Include pac common sof detection functions */ -#include "pac_common.h" - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - unsigned char *sof; - - sof = pac_find_sof(&sd->sof_read, data, len); - if (sof) { - int n; - - /* finish decoding current frame */ - n = sof - data; - if (n > sizeof pac_sof_marker) - n -= sizeof pac_sof_marker; - else - n = 0; - gspca_frame_add(gspca_dev, LAST_PACKET, - data, n); - /* Start next frame. */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - pac_sof_marker, sizeof pac_sof_marker); - len -= sof - data; - data = sof; - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x08ca, 0x0110)}, /* Trust Spyc@m 100 */ - {USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */ - {USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */ - {USB_DEVICE(0x093a, 0x010e)}, /* All known MR97310A CIF cams */ - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/nw80x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/nw80x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/nw80x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/nw80x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2145 +0,0 @@ -/* - * DivIO nw80x subdriver - * - * Copyright (C) 2011 Jean-François Moine (http://moinejf.free.fr) - * Copyright (C) 2003 Sylvain Munaut - * Kjell Claesson - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "nw80x" - -#include "gspca.h" - -MODULE_AUTHOR("Jean-Francois Moine "); -MODULE_DESCRIPTION("NW80x USB Camera Driver"); -MODULE_LICENSE("GPL"); - -static int webcam; - -/* controls */ -enum e_ctrl { - GAIN, - EXPOSURE, - AUTOGAIN, - NCTRLS /* number of controls */ -}; - -#define AUTOGAIN_DEF 1 - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRLS]; - - u32 ae_res; - s8 ag_cnt; -#define AG_CNT_START 13 - u8 exp_too_low_cnt; - u8 exp_too_high_cnt; - - u8 bridge; - u8 webcam; -}; - -enum bridges { - BRIDGE_NW800, /* and et31x110 */ - BRIDGE_NW801, - BRIDGE_NW802, -}; -enum webcams { - Generic800, - SpaceCam, /* Trust 120 SpaceCam */ - SpaceCam2, /* other Trust 120 SpaceCam */ - Cvideopro, /* Conceptronic Video Pro */ - Dlink350c, - DS3303u, - Kr651us, - Kritter, - Mustek300, - Proscope, - Twinkle, - DvcV6, - P35u, - Generic802, - NWEBCAMS /* number of webcams */ -}; - -static const u8 webcam_chip[NWEBCAMS] = { - [Generic800] = BRIDGE_NW800, /* 06a5:0000 - * Typhoon Webcam 100 USB */ - - [SpaceCam] = BRIDGE_NW800, /* 06a5:d800 - * Trust SpaceCam120 or SpaceCam100 PORTABLE */ - - [SpaceCam2] = BRIDGE_NW800, /* 06a5:d800 - pas106 - * other Trust SpaceCam120 or SpaceCam100 PORTABLE */ - - [Cvideopro] = BRIDGE_NW802, /* 06a5:d001 - * Conceptronic Video Pro 'CVIDEOPRO USB Webcam CCD' */ - - [Dlink350c] = BRIDGE_NW802, /* 06a5:d001 - * D-Link NetQam Pro 250plus */ - - [DS3303u] = BRIDGE_NW801, /* 06a5:d001 - * Plustek Opticam 500U or ProLink DS3303u */ - - [Kr651us] = BRIDGE_NW802, /* 06a5:d001 - * Panasonic GP-KR651US */ - - [Kritter] = BRIDGE_NW802, /* 06a5:d001 - * iRez Kritter cam */ - - [Mustek300] = BRIDGE_NW802, /* 055f:d001 - * Mustek Wcam 300 mini */ - - [Proscope] = BRIDGE_NW802, /* 06a5:d001 - * Scalar USB Microscope (ProScope) */ - - [Twinkle] = BRIDGE_NW800, /* 06a5:d800 - hv7121b? (seems pas106) - * Divio Chicony TwinkleCam - * DSB-C110 */ - - [DvcV6] = BRIDGE_NW802, /* 0502:d001 - * DVC V6 */ - - [P35u] = BRIDGE_NW801, /* 052b:d001, 06a5:d001 and 06be:d001 - * EZCam Pro p35u */ - - [Generic802] = BRIDGE_NW802, -}; -/* - * other webcams: - * - nw801 046d:d001 - * Logitech QuickCam Pro (dark focus ring) - * - nw801 0728:d001 - * AVerMedia Camguard - * - nw??? 06a5:d001 - * D-Link NetQam Pro 250plus - * - nw800 065a:d800 - * Showcam NGS webcam - * - nw??? ????:???? - * Sceptre svc300 - */ - -/* - * registers - * nw800/et31x110 nw801 nw802 - * 0000..009e 0000..00a1 0000..009e - * 0200..0211 id id - * 0300..0302 id id - * 0400..0406 (inex) 0400..0406 - * 0500..0505 0500..0506 (inex) - * 0600..061a 0600..0601 0600..0601 - * 0800..0814 id id - * 1000..109c 1000..10a1 1000..109a - */ - -/* resolutions - * nw800: 320x240, 352x288 - * nw801/802: 320x240, 640x480 - */ -static const struct v4l2_pix_format cif_mode[] = { - {320, 240, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 4 / 8, - .colorspace = V4L2_COLORSPACE_JPEG}, - {352, 288, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 4 / 8, - .colorspace = V4L2_COLORSPACE_JPEG} -}; -static const struct v4l2_pix_format vga_mode[] = { - {320, 240, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 4 / 8, - .colorspace = V4L2_COLORSPACE_JPEG}, - {640, 480, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8, - .colorspace = V4L2_COLORSPACE_JPEG}, -}; - -/* - * The sequences below contain: - * - 1st and 2nd bytes: either - * - register number (BE) - * - I2C0 + i2c address - * - 3rd byte: data length (=0 for end of sequence) - * - n bytes: data - */ -#define I2C0 0xff - -static const u8 nw800_init[] = { - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x01, - 0x04, 0x06, 0x01, 0x04, - 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, - 0x05, 0x05, 0x01, 0x00, - 0, 0, 0 -}; -static const u8 nw800_start[] = { - 0x04, 0x06, 0x01, 0xc0, - 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, - 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24, - 0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08, - 0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, - 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0xc0, - 0x05, 0x00, 0x06, 0xe8, 0x00, 0x00, 0x00, 0x20, 0x20, - 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62, - 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, - 0x01, 0x60, 0x01, 0x00, 0x00, - - 0x04, 0x04, 0x01, 0xff, - 0x04, 0x06, 0x01, 0xc4, - - 0x04, 0x06, 0x01, 0xc0, - 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, - 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24, - 0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08, - 0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, - 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0xc0, - 0x05, 0x00, 0x06, 0xe8, 0x00, 0x00, 0x00, 0x20, 0x20, - 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62, - 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, - 0x01, 0x60, 0x01, 0x00, 0x00, - - 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, - 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, - 0x40, - 0x00, 0x80, 0x01, 0xa0, - 0x10, 0x1a, 0x01, 0x00, - 0x00, 0x91, 0x02, 0x6c, 0x01, - 0x00, 0x03, 0x02, 0xc8, 0x01, - 0x10, 0x1a, 0x01, 0x00, - 0x10, 0x00, 0x01, 0x83, - 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, - 0x20, 0x01, 0x60, 0x01, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, - 0x10, 0x1b, 0x02, 0x69, 0x00, - 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, - 0x05, 0x02, 0x01, 0x02, - 0x06, 0x00, 0x02, 0x04, 0xd9, - 0x05, 0x05, 0x01, 0x20, - 0x05, 0x05, 0x01, 0x21, - 0x10, 0x0e, 0x01, 0x08, - 0x10, 0x41, 0x11, 0x00, 0x08, 0x21, 0x3d, 0x52, 0x63, 0x75, 0x83, - 0x91, 0x9e, 0xaa, 0xb6, 0xc1, 0xcc, 0xd6, 0xe0, - 0xea, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x13, 0x13, - 0x10, 0x03, 0x01, 0x14, - 0x10, 0x41, 0x11, 0x00, 0x08, 0x21, 0x3d, 0x52, 0x63, 0x75, 0x83, - 0x91, 0x9e, 0xaa, 0xb6, 0xc1, 0xcc, 0xd6, 0xe0, - 0xea, - 0x10, 0x0b, 0x01, 0x14, - 0x10, 0x0d, 0x01, 0x20, - 0x10, 0x0c, 0x01, 0x34, - 0x04, 0x06, 0x01, 0xc3, - 0x04, 0x04, 0x01, 0x00, - 0x05, 0x02, 0x01, 0x02, - 0x06, 0x00, 0x02, 0x00, 0x48, - 0x05, 0x05, 0x01, 0x20, - 0x05, 0x05, 0x01, 0x21, - 0, 0, 0 -}; - -/* 06a5:d001 - nw801 - Panasonic - * P35u */ -static const u8 nw801_start_1[] = { - 0x05, 0x06, 0x01, 0x04, - 0x00, 0x00, 0x40, 0x0e, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e, - 0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, - 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x22, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x69, 0xa8, 0x1f, 0x00, - 0x0d, 0x02, 0x07, 0x00, 0x01, 0x00, 0x19, 0x00, - 0xf2, 0x00, 0x18, 0x06, 0x10, 0x06, 0x10, 0x00, - 0x36, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0x22, 0x02, 0x80, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, 0x15, 0x08, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x35, 0xfd, 0x07, 0x3d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x02, - 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, 0xf7, - 0x10, 0x40, 0x40, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, 0x80, - 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, 0xa4, - 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, 0xcf, - 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, - 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, - 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x10, 0x80, 0x22, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x82, 0x02, - 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, 0x01, - 0xf0, 0x00, - 0, 0, 0, -}; -static const u8 nw801_start_qvga[] = { - 0x02, 0x00, 0x10, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x18, 0x0b, 0x06, 0xa2, 0x86, 0x78, - 0x02, 0x0f, 0x01, 0x6b, - 0x10, 0x1a, 0x01, 0x15, - 0x00, 0x00, 0x01, 0x1e, - 0x10, 0x00, 0x01, 0x2f, - 0x10, 0x8c, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x11, 0x08, 0x29, 0x00, 0x18, 0x01, 0x1f, 0x00, 0xd2, 0x00, - /* AE window */ - 0, 0, 0, -}; -static const u8 nw801_start_vga[] = { - 0x02, 0x00, 0x10, 0x78, 0xa0, 0x97, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xf0, - 0x02, 0x0f, 0x01, 0xd5, - 0x10, 0x1a, 0x01, 0x15, - 0x00, 0x00, 0x01, 0x0e, - 0x10, 0x00, 0x01, 0x22, - 0x10, 0x8c, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, - 0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01, - 0, 0, 0, -}; -static const u8 nw801_start_2[] = { - 0x10, 0x04, 0x01, 0x1a, - 0x10, 0x19, 0x01, 0x09, /* clock */ - 0x10, 0x24, 0x06, 0xc0, 0x00, 0x3f, 0x02, 0x00, 0x01, - /* .. gain .. */ - 0x00, 0x03, 0x02, 0x92, 0x03, - 0x00, 0x1d, 0x04, 0xf2, 0x00, 0x24, 0x07, - 0x00, 0x7b, 0x01, 0xcf, - 0x10, 0x94, 0x01, 0x07, - 0x05, 0x05, 0x01, 0x01, - 0x05, 0x04, 0x01, 0x01, - 0x10, 0x0e, 0x01, 0x08, - 0x10, 0x48, 0x11, 0x00, 0x37, 0x55, 0x6b, 0x7d, 0x8d, 0x9b, 0xa8, - 0xb4, 0xbf, 0xca, 0xd4, 0xdd, 0xe6, 0xef, 0xf0, - 0xf0, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x0c, 0x0c, - 0x10, 0x03, 0x01, 0x08, - 0x10, 0x48, 0x11, 0x00, 0x37, 0x55, 0x6b, 0x7d, 0x8d, 0x9b, 0xa8, - 0xb4, 0xbf, 0xca, 0xd4, 0xdd, 0xe6, 0xef, 0xf0, - 0xf0, - 0x10, 0x0b, 0x01, 0x0b, - 0x10, 0x0d, 0x01, 0x0b, - 0x10, 0x0c, 0x01, 0x1f, - 0x05, 0x06, 0x01, 0x03, - 0, 0, 0 -}; - -/* nw802 (sharp IR3Y38M?) */ -static const u8 nw802_start[] = { - 0x04, 0x06, 0x01, 0x04, - 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x4d, - 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, - 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, - 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, - 0x00, 0x10, 0x06, 0x08, 0x00, 0x18, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0xff, 0x01, 0xc0, 0x00, 0x14, - 0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x05, 0x82, - 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, - 0x01, 0xf0, 0x00, - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, - 0x40, - 0x10, 0x1a, 0x01, 0x00, - 0x10, 0x00, 0x01, 0xad, - 0x00, 0x00, 0x01, 0x08, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1b, 0x02, 0x00, 0x00, - 0x10, 0x11, 0x08, 0x51, 0x00, 0xf0, 0x00, 0x3d, 0x00, 0xb4, 0x00, - 0x10, 0x1d, 0x08, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, - 0x10, 0x0e, 0x01, 0x27, - 0x10, 0x41, 0x11, 0x00, 0x0e, 0x35, 0x4f, 0x62, 0x71, 0x7f, 0x8b, - 0x96, 0xa0, 0xa9, 0xb2, 0xbb, 0xc3, 0xca, 0xd2, - 0xd8, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x14, 0x14, - 0x10, 0x03, 0x01, 0x0c, - 0x10, 0x41, 0x11, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, 0x74, - 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, 0xf1, - 0xff, -/* 0x00, 0x0e, 0x35, 0x4f, 0x62, 0x71, 0x7f, 0x8b, - * 0x96, 0xa0, 0xa9, 0xb2, 0xbb, 0xc3, 0xca, 0xd2, - * 0xd8, */ - 0x10, 0x0b, 0x01, 0x10, - 0x10, 0x0d, 0x01, 0x11, - 0x10, 0x0c, 0x01, 0x1c, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x04, 0x01, 0x00, - 0, 0, 0 -}; -/* et31x110 - Trust 120 SpaceCam */ -static const u8 spacecam_init[] = { - 0x04, 0x05, 0x01, 0x01, - 0x04, 0x04, 0x01, 0x01, - 0x04, 0x06, 0x01, 0x04, - 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, - 0x05, 0x05, 0x01, 0x00, - 0, 0, 0 -}; -static const u8 spacecam_start[] = { - 0x04, 0x06, 0x01, 0x44, - 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, - 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24, - 0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08, - 0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, - 0x00, 0x4b, 0x00, 0x7c, 0x00, 0x80, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62, - 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, - 0x01, 0x60, 0x01, 0x00, 0x00, - 0x04, 0x06, 0x01, 0xc0, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, - 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, - 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, - 0x40, - 0x00, 0x80, 0x01, 0xa0, - 0x10, 0x1a, 0x01, 0x00, - 0x00, 0x91, 0x02, 0x32, 0x01, - 0x00, 0x03, 0x02, 0x08, 0x02, - 0x10, 0x00, 0x01, 0x83, - 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, - 0x20, 0x01, 0x60, 0x01, - 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, - 0x10, 0x0e, 0x01, 0x08, - 0x10, 0x41, 0x11, 0x00, 0x64, 0x99, 0xc0, 0xe2, 0xf9, 0xf9, 0xf9, - 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, - 0xf9, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x13, 0x13, - 0x10, 0x03, 0x01, 0x06, - 0x10, 0x41, 0x11, 0x00, 0x64, 0x99, 0xc0, 0xe2, 0xf9, 0xf9, 0xf9, - 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, - 0xf9, - 0x10, 0x0b, 0x01, 0x08, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x1f, - 0x04, 0x06, 0x01, 0xc3, - 0x04, 0x05, 0x01, 0x40, - 0x04, 0x04, 0x01, 0x40, - 0, 0, 0 -}; -/* et31x110 - pas106 - other Trust SpaceCam120 */ -static const u8 spacecam2_start[] = { - 0x04, 0x06, 0x01, 0x44, - 0x04, 0x06, 0x01, 0x00, - 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, - 0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc, - 0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03, - 0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, - 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00, - 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, - 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, - 0x01, 0x60, 0x01, 0x00, 0x00, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, - 0x04, 0x04, 0x01, 0x40, - 0x04, 0x04, 0x01, 0x00, - I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x05, - 0x00, 0x00, 0x05, 0x05, - I2C0, 0x40, 0x02, 0x11, 0x06, - I2C0, 0x40, 0x02, 0x14, 0x00, - I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ - 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, - 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, - 0x40, - I2C0, 0x40, 0x02, 0x02, 0x0c, /* pixel clock */ - I2C0, 0x40, 0x02, 0x0f, 0x00, - I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ - 0x10, 0x00, 0x01, 0x01, - 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, - 0x20, 0x01, 0x60, 0x01, - I2C0, 0x40, 0x02, 0x05, 0x0f, /* exposure */ - I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ - I2C0, 0x40, 0x07, 0x09, 0x0b, 0x0f, 0x05, 0x05, 0x0f, 0x00, - /* gains */ - I2C0, 0x40, 0x03, 0x12, 0x04, 0x01, - 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, - 0x10, 0x0e, 0x01, 0x08, - 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, - 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, - 0xf9, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x13, 0x13, - 0x10, 0x03, 0x01, 0x06, - 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, - 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, - 0xf9, - 0x10, 0x0b, 0x01, 0x11, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x14, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x00, - 0, 0, 0 -}; - -/* nw802 - Conceptronic Video Pro */ -static const u8 cvideopro_start[] = { - 0x04, 0x06, 0x01, 0x04, - 0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c, - 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4, - 0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, - 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, - 0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30, - 0x00, 0x80, 0x1f, 0x98, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, - 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, - 0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, - 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, - 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82, - 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, - 0x01, 0xf0, 0x00, - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0, - 0x40, - 0x10, 0x1a, 0x01, 0x03, - 0x10, 0x00, 0x01, 0xac, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1b, 0x02, 0x3b, 0x01, - 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, - 0x10, 0x1f, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, - 0x10, 0x1d, 0x02, 0x40, 0x06, - 0x10, 0x0e, 0x01, 0x08, - 0x10, 0x41, 0x11, 0x00, 0x0f, 0x46, 0x62, 0x76, 0x86, 0x94, 0xa0, - 0xab, 0xb6, 0xbf, 0xc8, 0xcf, 0xd7, 0xdc, 0xdc, - 0xdc, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x12, 0x12, - 0x10, 0x03, 0x01, 0x0c, - 0x10, 0x41, 0x11, 0x00, 0x0f, 0x46, 0x62, 0x76, 0x86, 0x94, 0xa0, - 0xab, 0xb6, 0xbf, 0xc8, 0xcf, 0xd7, 0xdc, 0xdc, - 0xdc, - 0x10, 0x0b, 0x01, 0x09, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x2f, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x04, 0x01, 0x00, - 0, 0, 0 -}; - -/* nw802 - D-link dru-350c cam */ -static const u8 dlink_start[] = { - 0x04, 0x06, 0x01, 0x04, - 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d, - 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, - 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, - 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, - 0x00, 0x10, 0x06, 0x10, 0x00, 0x36, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0xc0, 0x00, 0x14, - 0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x82, - 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, - 0x01, 0xf0, 0x00, - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, - 0x40, - 0x10, 0x1a, 0x01, 0x00, - 0x10, 0x00, 0x01, 0xad, - 0x00, 0x00, 0x01, 0x08, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1b, 0x02, 0x00, 0x00, - 0x10, 0x11, 0x08, 0x51, 0x00, 0xf0, 0x00, 0x3d, 0x00, 0xb4, 0x00, - 0x10, 0x1d, 0x08, 0x40, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, - 0x10, 0x0e, 0x01, 0x20, - 0x10, 0x41, 0x11, 0x00, 0x07, 0x1e, 0x38, 0x4d, 0x60, 0x70, 0x7f, - 0x8e, 0x9b, 0xa8, 0xb4, 0xbf, 0xca, 0xd5, 0xdf, - 0xea, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x11, 0x11, - 0x10, 0x03, 0x01, 0x10, - 0x10, 0x41, 0x11, 0x00, 0x07, 0x1e, 0x38, 0x4d, 0x60, 0x70, 0x7f, - 0x8e, 0x9b, 0xa8, 0xb4, 0xbf, 0xca, 0xd5, 0xdf, - 0xea, - 0x10, 0x0b, 0x01, 0x19, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x1e, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x04, 0x01, 0x00, - 0, 0, 0 -}; - -/* 06a5:d001 - nw801 - Sony - * Plustek Opticam 500U or ProLink DS3303u (Hitachi HD49322BF) */ -/*fixme: 320x240 only*/ -static const u8 ds3303_start[] = { - 0x05, 0x06, 0x01, 0x04, - 0x00, 0x00, 0x40, 0x16, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e, - 0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, - 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x22, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa9, 0xa8, 0x1f, 0x00, - 0x0d, 0x02, 0x07, 0x00, 0x01, 0x00, 0x19, 0x00, - 0xf2, 0x00, 0x18, 0x06, 0x10, 0x06, 0x10, 0x00, - 0x36, 0x00, - 0x02, 0x00, 0x12, 0x03, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0x50, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x05, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0x2f, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x1f, 0x10, 0x08, 0x0a, - 0x0a, 0x51, 0x00, 0xf1, 0x00, 0x3c, 0x00, 0xb4, - 0x00, 0x01, 0x15, 0xfd, 0x07, 0x3d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x8c, 0x04, 0x01, 0x20, - 0x02, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, 0xf7, - 0x10, 0x40, 0x40, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, 0x80, - 0x00, 0x2d, 0x46, 0x58, 0x67, 0x74, 0x7f, 0x88, - 0x94, 0x9d, 0xa6, 0xae, 0xb5, 0xbd, 0xc4, 0xcb, - 0xd1, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, - 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, - 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x10, 0x80, 0x22, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x3f, 0x01, - 0x00, 0x00, 0xef, 0x00, 0x02, 0x0a, 0x82, 0x02, - 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, 0x01, - 0xf0, 0x00, - - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x3f, 0x00, 0xf2, 0x8f, 0x81, - 0x40, - 0x10, 0x1a, 0x01, 0x15, - 0x10, 0x00, 0x01, 0x2f, - 0x10, 0x8c, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1b, 0x02, 0x00, 0x00, - 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, - 0x10, 0x26, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, - 0x10, 0x24, 0x02, 0x40, 0x06, - 0x10, 0x0e, 0x01, 0x08, - 0x10, 0x48, 0x11, 0x00, 0x15, 0x40, 0x67, 0x84, 0x9d, 0xb2, 0xc6, - 0xd6, 0xe7, 0xf6, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, - 0xf9, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x16, 0x16, - 0x10, 0x03, 0x01, 0x0c, - 0x10, 0x48, 0x11, 0x00, 0x15, 0x40, 0x67, 0x84, 0x9d, 0xb2, 0xc6, - 0xd6, 0xe7, 0xf6, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, - 0xf9, - 0x10, 0x0b, 0x01, 0x26, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x1c, - 0x05, 0x06, 0x01, 0x03, - 0x05, 0x04, 0x01, 0x00, - 0, 0, 0 -}; - -/* 06a5:d001 - nw802 - Panasonic - * GP-KR651US (Philips TDA8786) */ -static const u8 kr651_start_1[] = { - 0x04, 0x06, 0x01, 0x04, - 0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x48, - 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4, - 0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, - 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, - 0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30, - 0x00, 0x80, 0x1f, 0x18, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, - 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, - 0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, - 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x02, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, - 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82, - 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, - 0x01, 0xf0, 0x00, - 0, 0, 0 -}; -static const u8 kr651_start_qvga[] = { - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, - 0x40, - 0x10, 0x1a, 0x01, 0x03, - 0x10, 0x00, 0x01, 0xac, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1b, 0x02, 0x00, 0x00, - 0x10, 0x11, 0x08, 0x29, 0x00, 0x18, 0x01, 0x1f, 0x00, 0xd2, 0x00, - 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, - 0x10, 0x1d, 0x02, 0x28, 0x01, - 0, 0, 0 -}; -static const u8 kr651_start_vga[] = { - 0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x30, 0x03, 0x01, 0x82, 0x82, 0x98, - 0x80, - 0x10, 0x1a, 0x01, 0x03, - 0x10, 0x00, 0x01, 0xa0, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, - 0x10, 0x1b, 0x02, 0x00, 0x00, - 0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01, - 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, - 0x10, 0x1d, 0x02, 0x68, 0x00, -}; -static const u8 kr651_start_2[] = { - 0x10, 0x0e, 0x01, 0x08, - 0x10, 0x41, 0x11, 0x00, 0x11, 0x3c, 0x5c, 0x74, 0x88, 0x99, 0xa8, - 0xb7, 0xc4, 0xd0, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, - 0xdc, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x0c, 0x0c, - 0x10, 0x03, 0x01, 0x0c, - 0x10, 0x41, 0x11, 0x00, 0x11, 0x3c, 0x5c, 0x74, 0x88, 0x99, 0xa8, - 0xb7, 0xc4, 0xd0, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, - 0xdc, - 0x10, 0x0b, 0x01, 0x10, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x2d, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x04, 0x01, 0x00, - 0, 0, 0 -}; - -/* nw802 - iRez Kritter cam */ -static const u8 kritter_start[] = { - 0x04, 0x06, 0x01, 0x06, - 0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0x94, 0x03, 0x18, 0x00, 0x48, - 0x0f, 0x1e, 0x00, 0x0c, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x0b, 0x00, 0x1b, 0x00, 0x0a, 0x01, 0x28, - 0x07, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, - 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, - 0x00, 0x5d, 0x00, 0x0e, 0x00, 0x7e, 0x00, 0x30, - 0x00, 0x80, 0x1f, 0x18, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, - 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, - 0x00, 0x0b, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, - 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x02, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, - 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x82, - 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, - 0x01, 0xf0, 0x00, - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0, - 0x40, - 0x10, 0x1a, 0x01, 0x03, - 0x10, 0x00, 0x01, 0xaf, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1b, 0x02, 0x3b, 0x01, - 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, - 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, - 0x10, 0x1d, 0x02, 0x00, 0x00, - 0x10, 0x0e, 0x01, 0x08, - 0x10, 0x41, 0x11, 0x00, 0x0d, 0x36, 0x4e, 0x60, 0x6f, 0x7b, 0x86, - 0x90, 0x98, 0xa1, 0xa9, 0xb1, 0xb7, 0xbe, 0xc4, - 0xcb, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x0d, 0x0d, - 0x10, 0x03, 0x01, 0x02, - 0x10, 0x41, 0x11, 0x00, 0x0d, 0x36, 0x4e, 0x60, 0x6f, 0x7b, 0x86, - 0x90, 0x98, 0xa1, 0xa9, 0xb1, 0xb7, 0xbe, 0xc4, - 0xcb, - 0x10, 0x0b, 0x01, 0x17, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x1e, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x04, 0x01, 0x00, - 0, 0, 0 -}; - -/* nw802 - Mustek Wcam 300 mini */ -static const u8 mustek_start[] = { - 0x04, 0x06, 0x01, 0x04, - 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d, - 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, - 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, - 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, - 0x00, 0x10, 0x06, 0xfc, 0x05, 0x0c, 0x06, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0xc0, 0x00, 0x14, - 0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x82, - 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, - 0x01, 0xf0, 0x00, - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, - 0x40, - 0x10, 0x1a, 0x01, 0x00, - 0x10, 0x00, 0x01, 0xad, - 0x00, 0x00, 0x01, 0x08, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1b, 0x02, 0x00, 0x00, - 0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1d, 0x08, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, - 0x10, 0x0e, 0x01, 0x0f, - 0x10, 0x41, 0x11, 0x00, 0x0f, 0x29, 0x4a, 0x64, 0x7a, 0x8c, 0x9e, - 0xad, 0xba, 0xc7, 0xd3, 0xde, 0xe8, 0xf1, 0xf9, - 0xff, - 0x10, 0x0f, 0x02, 0x11, 0x11, - 0x10, 0x03, 0x01, 0x0c, - 0x10, 0x41, 0x11, 0x00, 0x0f, 0x29, 0x4a, 0x64, 0x7a, 0x8c, 0x9e, - 0xad, 0xba, 0xc7, 0xd3, 0xde, 0xe8, 0xf1, 0xf9, - 0xff, - 0x10, 0x0b, 0x01, 0x1c, - 0x10, 0x0d, 0x01, 0x1a, - 0x10, 0x0c, 0x01, 0x34, - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x40, - 0x04, 0x06, 0x01, 0x03, - 0, 0, 0 -}; - -/* nw802 - Scope USB Microscope M2 (ProScope) (Hitachi HD49322BF) */ -static const u8 proscope_init[] = { - 0x04, 0x05, 0x01, 0x21, - 0x04, 0x04, 0x01, 0x01, - 0, 0, 0 -}; -static const u8 proscope_start_1[] = { - 0x04, 0x06, 0x01, 0x04, - 0x00, 0x00, 0x40, 0x10, 0x01, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x04, - 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x08, 0x00, 0x17, 0x00, 0xce, 0x00, 0xf4, - 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0xce, 0x00, 0xf8, 0x03, 0x3e, 0x00, 0x86, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0xb6, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xf6, 0x03, 0x34, 0x04, 0xf6, 0x03, 0x34, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xe8, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x1f, 0x0f, 0x08, 0x20, 0xa8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, - 0x00, 0x0c, 0x02, 0x01, 0x00, 0x19, 0x00, 0x94, - 0x00, 0x10, 0x06, 0x10, 0x00, 0x36, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0xad, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x1f, 0x10, 0x08, 0x0a, - 0x0a, 0x51, 0x00, 0xf1, 0x00, 0x3c, 0x00, 0xb4, - 0x00, 0x49, 0x13, 0x00, 0x00, 0x8c, 0x04, 0x01, - 0x20, 0x02, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x2d, 0x46, 0x58, 0x67, 0x74, 0x7f, - 0x88, 0x94, 0x9d, 0xa6, 0xae, 0xb5, 0xbd, 0xc4, - 0xcb, 0xd1, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x3f, - 0x01, 0x00, 0x00, 0xef, 0x00, 0x09, 0x05, 0x82, - 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, - 0x01, 0xf0, 0x00, - 0, 0, 0 -}; -static const u8 proscope_start_qvga[] = { - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, - 0x40, - 0x10, 0x1a, 0x01, 0x06, - 0x00, 0x03, 0x02, 0xf9, 0x02, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1b, 0x02, 0x00, 0x00, - 0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1d, 0x08, 0xc0, 0x0d, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, - 0x10, 0x0e, 0x01, 0x10, - 0, 0, 0 -}; -static const u8 proscope_start_vga[] = { - 0x00, 0x03, 0x02, 0xf9, 0x02, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, - 0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x16, 0x00, 0x00, 0x82, 0x84, 0x00, - 0x80, - 0x10, 0x1a, 0x01, 0x06, - 0x10, 0x00, 0x01, 0xa1, - 0x10, 0x1b, 0x02, 0x00, 0x00, - 0x10, 0x1d, 0x08, 0xc0, 0x0d, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, - 0x10, 0x11, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, - 0x10, 0x0e, 0x01, 0x10, - 0x10, 0x41, 0x11, 0x00, 0x10, 0x51, 0x6e, 0x83, 0x93, 0xa1, 0xae, - 0xb9, 0xc3, 0xcc, 0xd4, 0xdd, 0xe4, 0xeb, 0xf2, - 0xf9, - 0x10, 0x03, 0x01, 0x00, - 0, 0, 0 -}; -static const u8 proscope_start_2[] = { - 0x10, 0x0f, 0x02, 0x0c, 0x0c, - 0x10, 0x03, 0x01, 0x0c, - 0x10, 0x41, 0x11, 0x00, 0x10, 0x51, 0x6e, 0x83, 0x93, 0xa1, 0xae, - 0xb9, 0xc3, 0xcc, 0xd4, 0xdd, 0xe4, 0xeb, 0xf2, - 0xf9, - 0x10, 0x0b, 0x01, 0x0b, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x1b, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x05, 0x01, 0x21, - 0x04, 0x04, 0x01, 0x00, - 0, 0, 0 -}; - -/* nw800 - hv7121b? (seems pas106) - Divio Chicony TwinkleCam */ -static const u8 twinkle_start[] = { - 0x04, 0x06, 0x01, 0x44, - 0x04, 0x06, 0x01, 0x00, - 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, - 0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc, - 0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03, - 0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, - 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00, - 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x08, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x10, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x00, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, - 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, - 0x01, 0x60, 0x01, 0x00, 0x00, - - 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, - 0x04, 0x04, 0x01, 0x10, - 0x04, 0x04, 0x01, 0x00, - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x01, - I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, - I2C0, 0x40, 0x02, 0x11, 0x06, - I2C0, 0x40, 0x02, 0x14, 0x00, - I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ - I2C0, 0x40, 0x02, 0x07, 0x01, - 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, - 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, - 0x40, - I2C0, 0x40, 0x02, 0x02, 0x0c, - I2C0, 0x40, 0x02, 0x13, 0x01, - 0x10, 0x00, 0x01, 0x01, - 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, - 0x20, 0x01, 0x60, 0x01, - I2C0, 0x40, 0x02, 0x05, 0x0f, - I2C0, 0x40, 0x02, 0x13, 0x01, - I2C0, 0x40, 0x08, 0x08, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x17, - I2C0, 0x40, 0x03, 0x12, 0x00, 0x01, - 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, - I2C0, 0x40, 0x02, 0x12, 0x00, - I2C0, 0x40, 0x02, 0x0e, 0x00, - I2C0, 0x40, 0x02, 0x11, 0x06, - 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, - 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, - 0xf9, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x0c, 0x0c, - 0x10, 0x03, 0x01, 0x06, - 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, - 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, - 0xf9, - 0x10, 0x0b, 0x01, 0x19, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x0d, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x41, - 0, 0, 0 -}; - -/* nw802 dvc-v6 */ -static const u8 dvcv6_start[] = { - 0x04, 0x06, 0x01, 0x06, - 0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c, - 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4, - 0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, - 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, - 0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30, - 0x00, 0x80, 0x1f, 0x98, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, - 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, - 0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, - 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, - 0x06, 0x00, 0x02, 0x09, 0x99, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, - 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, - 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82, - 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, - 0x01, 0xf0, 0x00, - 0x00, 0x03, 0x02, 0x94, 0x03, - 0x00, 0x1d, 0x04, 0x0a, 0x01, 0x28, 0x07, - 0x00, 0x7b, 0x02, 0xe0, 0x00, - 0x10, 0x8d, 0x01, 0x00, - 0x00, 0x09, 0x04, 0x1e, 0x00, 0x0c, 0x02, - 0x00, 0x91, 0x02, 0x0b, 0x02, - 0x10, 0x00, 0x01, 0xaf, - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8f, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0, - 0x40, - 0x10, 0x1a, 0x01, 0x02, - 0x10, 0x00, 0x01, 0xaf, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x10, 0x1b, 0x02, 0x07, 0x01, - 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, - 0x10, 0x1f, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, - 0x10, 0x1d, 0x02, 0x40, 0x06, - 0x10, 0x0e, 0x01, 0x08, - 0x10, 0x41, 0x11, 0x00, 0x0f, 0x54, 0x6f, 0x82, 0x91, 0x9f, 0xaa, - 0xb4, 0xbd, 0xc5, 0xcd, 0xd5, 0xdb, 0xdc, 0xdc, - 0xdc, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x12, 0x12, - 0x10, 0x03, 0x01, 0x11, - 0x10, 0x41, 0x11, 0x00, 0x0f, 0x54, 0x6f, 0x82, 0x91, 0x9f, 0xaa, - 0xb4, 0xbd, 0xc5, 0xcd, 0xd5, 0xdb, 0xdc, 0xdc, - 0xdc, - 0x10, 0x0b, 0x01, 0x16, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x1a, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x04, 0x01, 0x00, -}; - -static const u8 *webcam_start[] = { - [Generic800] = nw800_start, - [SpaceCam] = spacecam_start, - [SpaceCam2] = spacecam2_start, - [Cvideopro] = cvideopro_start, - [Dlink350c] = dlink_start, - [DS3303u] = ds3303_start, - [Kr651us] = kr651_start_1, - [Kritter] = kritter_start, - [Mustek300] = mustek_start, - [Proscope] = proscope_start_1, - [Twinkle] = twinkle_start, - [DvcV6] = dvcv6_start, - [P35u] = nw801_start_1, - [Generic802] = nw802_start, -}; - -/* -- write a register -- */ -static void reg_w(struct gspca_dev *gspca_dev, - u16 index, - const u8 *data, - int len) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - if (len == 1) - PDEBUG(D_USBO, "SET 00 0000 %04x %02x", index, *data); - else - PDEBUG(D_USBO, "SET 00 0000 %04x %02x %02x ...", - index, *data, data[1]); - memcpy(gspca_dev->usb_buf, data, len); - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x00, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, /* value */ - index, - gspca_dev->usb_buf, - len, - 500); - if (ret < 0) { - err("reg_w err %d", ret); - gspca_dev->usb_err = ret; - } -} - -/* -- read registers in usb_buf -- */ -static void reg_r(struct gspca_dev *gspca_dev, - u16 index, - int len) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - 0x00, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, index, - gspca_dev->usb_buf, len, 500); - if (ret < 0) { - err("reg_r err %d", ret); - gspca_dev->usb_err = ret; - return; - } - if (len == 1) - PDEBUG(D_USBI, "GET 00 0000 %04x %02x", - index, gspca_dev->usb_buf[0]); - else - PDEBUG(D_USBI, "GET 00 0000 %04x %02x %02x ..", - index, gspca_dev->usb_buf[0], - gspca_dev->usb_buf[1]); -} - -static void i2c_w(struct gspca_dev *gspca_dev, - u8 i2c_addr, - const u8 *data, - int len) -{ - u8 val[2]; - int i; - - reg_w(gspca_dev, 0x0600, data + 1, len - 1); - reg_w(gspca_dev, 0x0600, data, len); - val[0] = len; - val[1] = i2c_addr; - reg_w(gspca_dev, 0x0502, val, 2); - val[0] = 0x01; - reg_w(gspca_dev, 0x0501, val, 1); - for (i = 5; --i >= 0; ) { - msleep(4); - reg_r(gspca_dev, 0x0505, 1); - if (gspca_dev->usb_err < 0) - return; - if (gspca_dev->usb_buf[0] == 0) - return; - } - gspca_dev->usb_err = -ETIME; -} - -static void reg_w_buf(struct gspca_dev *gspca_dev, - const u8 *cmd) -{ - u16 reg; - int len; - - for (;;) { - reg = *cmd++ << 8; - reg += *cmd++; - len = *cmd++; - if (len == 0) - break; - if (cmd[-3] != I2C0) - reg_w(gspca_dev, reg, cmd, len); - else - i2c_w(gspca_dev, reg, cmd, len); - cmd += len; - } -} - -static int swap_bits(int v) -{ - int r, i; - - r = 0; - for (i = 0; i < 8; i++) { - r <<= 1; - if (v & 1) - r++; - v >>= 1; - } - return r; -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val, v[2]; - - val = sd->ctrls[GAIN].val; - switch (sd->webcam) { - case P35u: - /* Note the control goes from 0-255 not 0-127, but anything - above 127 just means amplifying noise */ - val >>= 1; /* 0 - 255 -> 0 - 127 */ - reg_w(gspca_dev, 0x1026, &val, 1); - break; - case Kr651us: - /* 0 - 253 */ - val = swap_bits(val); - v[0] = val << 3; - v[1] = val >> 5; - reg_w(gspca_dev, 0x101d, v, 2); /* SIF reg0/1 (AGC) */ - break; - } -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - s16 val; - u8 v[2]; - - val = sd->ctrls[EXPOSURE].val; - switch (sd->webcam) { - case P35u: - v[0] = ((9 - val) << 3) | 0x01; - reg_w(gspca_dev, 0x1019, v, 1); - break; - case Cvideopro: - case DvcV6: - case Kritter: - case Kr651us: - v[0] = val; - v[1] = val >> 8; - reg_w(gspca_dev, 0x101b, v, 2); - break; - } -} - -static void setautogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int w, h; - - if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) - return; - if (!sd->ctrls[AUTOGAIN].val) { - sd->ag_cnt = -1; - return; - } - sd->ag_cnt = AG_CNT_START; - - reg_r(gspca_dev, 0x1004, 1); - if (gspca_dev->usb_buf[0] & 0x04) { /* if AE_FULL_FRM */ - sd->ae_res = gspca_dev->width * gspca_dev->height; - } else { /* get the AE window size */ - reg_r(gspca_dev, 0x1011, 8); - w = (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0] - - (gspca_dev->usb_buf[3] << 8) - gspca_dev->usb_buf[2]; - h = (gspca_dev->usb_buf[5] << 8) + gspca_dev->usb_buf[4] - - (gspca_dev->usb_buf[7] << 8) - gspca_dev->usb_buf[6]; - sd->ae_res = h * w; - if (sd->ae_res == 0) - sd->ae_res = gspca_dev->width * gspca_dev->height; - } -} - -static int nw802_test_reg(struct gspca_dev *gspca_dev, - u16 index, - u8 value) -{ - /* write the value */ - reg_w(gspca_dev, index, &value, 1); - - /* read it */ - reg_r(gspca_dev, index, 1); - - return gspca_dev->usb_buf[0] == value; -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if ((unsigned) webcam >= NWEBCAMS) - webcam = 0; - sd->webcam = webcam; - gspca_dev->cam.reverse_alts = 1; - gspca_dev->cam.ctrls = sd->ctrls; - sd->ag_cnt = -1; - - /* - * Autodetect sequence inspired from some log. - * We try to detect what registers exist or not. - * If 0x0500 does not exist => NW802 - * If it does, test 0x109b. If it doesn't exist, - * then it's a NW801. Else, a NW800 - * If a et31x110 (nw800 and 06a5:d800) - * get the sensor ID - */ - if (!nw802_test_reg(gspca_dev, 0x0500, 0x55)) { - sd->bridge = BRIDGE_NW802; - if (sd->webcam == Generic800) - sd->webcam = Generic802; - } else if (!nw802_test_reg(gspca_dev, 0x109b, 0xaa)) { - sd->bridge = BRIDGE_NW801; - if (sd->webcam == Generic800) - sd->webcam = P35u; - } else if (id->idVendor == 0x06a5 && id->idProduct == 0xd800) { - reg_r(gspca_dev, 0x0403, 1); /* GPIO */ - PDEBUG(D_PROBE, "et31x110 sensor type %02x", - gspca_dev->usb_buf[0]); - switch (gspca_dev->usb_buf[0] >> 1) { - case 0x00: /* ?? */ - if (sd->webcam == Generic800) - sd->webcam = SpaceCam; - break; - case 0x01: /* Hynix? */ - if (sd->webcam == Generic800) - sd->webcam = Twinkle; - break; - case 0x0a: /* Pixart */ - if (sd->webcam == Generic800) - sd->webcam = SpaceCam2; - break; - } - } - if (webcam_chip[sd->webcam] != sd->bridge) { - err("Bad webcam type %d for NW80%d", sd->webcam, sd->bridge); - gspca_dev->usb_err = -ENODEV; - return gspca_dev->usb_err; - } - PDEBUG(D_PROBE, "Bridge nw80%d - type: %d", sd->bridge, sd->webcam); - - if (sd->bridge == BRIDGE_NW800) { - switch (sd->webcam) { - case DS3303u: - gspca_dev->cam.cam_mode = cif_mode; /* qvga */ - break; - default: - gspca_dev->cam.cam_mode = &cif_mode[1]; /* cif */ - break; - } - gspca_dev->cam.nmodes = 1; - } else { - gspca_dev->cam.cam_mode = vga_mode; - switch (sd->webcam) { - case Kr651us: - case Proscope: - case P35u: - gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); - break; - default: - gspca_dev->cam.nmodes = 1; /* qvga only */ - break; - } - } - switch (sd->webcam) { - case P35u: -/* sd->ctrls[EXPOSURE].max = 9; - * sd->ctrls[EXPOSURE].def = 9; */ - /* coarse expo auto gain function gain minimum, to avoid - * a large settings jump the first auto adjustment */ - sd->ctrls[GAIN].def = 255 / 5 * 2; - break; - case Cvideopro: - case DvcV6: - case Kritter: - gspca_dev->ctrl_dis = (1 << GAIN) | (1 << AUTOGAIN); - /* fall thru */ - case Kr651us: - sd->ctrls[EXPOSURE].max = 315; - sd->ctrls[EXPOSURE].def = 150; - break; - default: - gspca_dev->ctrl_dis = (1 << GAIN) | (1 << EXPOSURE) - | (1 << AUTOGAIN); - break; - } - -#if AUTOGAIN_DEF - if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN))) - gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); -#endif - return gspca_dev->usb_err; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->bridge) { - case BRIDGE_NW800: - switch (sd->webcam) { - case SpaceCam: - reg_w_buf(gspca_dev, spacecam_init); - break; - default: - reg_w_buf(gspca_dev, nw800_init); - break; - } - break; - default: - switch (sd->webcam) { - case Mustek300: - case P35u: - case Proscope: - reg_w_buf(gspca_dev, proscope_init); - break; - } - break; - } - return gspca_dev->usb_err; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - const u8 *cmd; - - cmd = webcam_start[sd->webcam]; - reg_w_buf(gspca_dev, cmd); - switch (sd->webcam) { - case P35u: - if (gspca_dev->width == 320) - reg_w_buf(gspca_dev, nw801_start_qvga); - else - reg_w_buf(gspca_dev, nw801_start_vga); - reg_w_buf(gspca_dev, nw801_start_2); - break; - case Kr651us: - if (gspca_dev->width == 320) - reg_w_buf(gspca_dev, kr651_start_qvga); - else - reg_w_buf(gspca_dev, kr651_start_vga); - reg_w_buf(gspca_dev, kr651_start_2); - break; - case Proscope: - if (gspca_dev->width == 320) - reg_w_buf(gspca_dev, proscope_start_qvga); - else - reg_w_buf(gspca_dev, proscope_start_vga); - reg_w_buf(gspca_dev, proscope_start_2); - break; - } - - setgain(gspca_dev); - setexposure(gspca_dev); - setautogain(gspca_dev); - sd->exp_too_high_cnt = 0; - sd->exp_too_low_cnt = 0; - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 value; - - /* 'go' off */ - if (sd->bridge != BRIDGE_NW801) { - value = 0x02; - reg_w(gspca_dev, 0x0406, &value, 1); - } - - /* LED off */ - switch (sd->webcam) { - case Cvideopro: - case Kr651us: - case DvcV6: - case Kritter: - value = 0xff; - break; - case Dlink350c: - value = 0x21; - break; - case SpaceCam: - case SpaceCam2: - case Proscope: - case Twinkle: - value = 0x01; - break; - default: - return; - } - reg_w(gspca_dev, 0x0404, &value, 1); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - /* - * frame header = '00 00 hh ww ss xx ff ff' - * with: - * - 'hh': height / 4 - * - 'ww': width / 4 - * - 'ss': frame sequence number c0..dd - */ - if (data[0] == 0x00 && data[1] == 0x00 - && data[6] == 0xff && data[7] == 0xff) { - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - gspca_frame_add(gspca_dev, FIRST_PACKET, data + 8, len - 8); - } else { - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - } -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AUTOGAIN].val = val; - if (val) - gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); - else - gspca_dev->ctrl_inac = 0; - if (gspca_dev->streaming) - setautogain(gspca_dev); - return gspca_dev->usb_err; -} - -#include "autogain_functions.h" - -static void do_autogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int luma; - - if (sd->ag_cnt < 0) - return; - if (--sd->ag_cnt >= 0) - return; - sd->ag_cnt = AG_CNT_START; - - /* get the average luma */ - reg_r(gspca_dev, sd->bridge == BRIDGE_NW801 ? 0x080d : 0x080c, 4); - luma = (gspca_dev->usb_buf[3] << 24) + (gspca_dev->usb_buf[2] << 16) - + (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; - luma /= sd->ae_res; - - switch (sd->webcam) { - case P35u: - coarse_grained_expo_autogain(gspca_dev, luma, 100, 5); - break; - default: - auto_gain_n_exposure(gspca_dev, luma, 100, 5, 230, 0); - break; - } -} - -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[NCTRLS] = { -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 253, - .step = 1, - .default_value = 128 - }, - .set_control = setgain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 9, - .step = 1, - .default_value = 9 - }, - .set_control = setexposure - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = AUTOGAIN_DEF, - .flags = V4L2_CTRL_FLAG_UPDATE - }, - .set = sd_setautogain - }, -}; - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .dq_callback = do_autogain, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x046d, 0xd001)}, - {USB_DEVICE(0x0502, 0xd001)}, - {USB_DEVICE(0x052b, 0xd001)}, - {USB_DEVICE(0x055f, 0xd001)}, - {USB_DEVICE(0x06a5, 0x0000)}, - {USB_DEVICE(0x06a5, 0xd001)}, - {USB_DEVICE(0x06a5, 0xd800)}, - {USB_DEVICE(0x06be, 0xd001)}, - {USB_DEVICE(0x0728, 0xd001)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); - -module_param(webcam, int, 0644); -MODULE_PARM_DESC(webcam, - "Webcam type\n" - "0: generic\n" - "1: Trust 120 SpaceCam\n" - "2: other Trust 120 SpaceCam\n" - "3: Conceptronic Video Pro\n" - "4: D-link dru-350c\n" - "5: Plustek Opticam 500U\n" - "6: Panasonic GP-KR651US\n" - "7: iRez Kritter\n" - "8: Mustek Wcam 300 mini\n" - "9: Scalar USB Microscope M2 (Proscope)\n" - "10: Divio Chicony TwinkleCam\n" - "11: DVC-V6\n"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov519.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov519.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov519.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov519.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,4987 +0,0 @@ -/** - * OV519 driver - * - * Copyright (C) 2008-2011 Jean-François Moine - * Copyright (C) 2009 Hans de Goede - * - * This module is adapted from the ov51x-jpeg package, which itself - * was adapted from the ov511 driver. - * - * Original copyright for the ov511 driver is: - * - * Copyright (c) 1999-2006 Mark W. McClelland - * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach - * Many improvements by Bret Wallach - * Color fixes by by Orion Sky Lawlor (2/26/2000) - * OV7620 fixes by Charl P. Botha - * Changes by Claudio Matsuoka - * - * ov51x-jpeg original copyright is: - * - * Copyright (c) 2004-2007 Romain Beauxis - * Support for OV7670 sensors was contributed by Sam Skipsey - * - * 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, or - * any later version. - * - * 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 - * - */ -#define MODULE_NAME "ov519" - -#include -#include "gspca.h" - -/* The jpeg_hdr is used by w996Xcf only */ -/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */ -#define CONEX_CAM -#include "jpeg.h" - -MODULE_AUTHOR("Jean-Francois Moine "); -MODULE_DESCRIPTION("OV519 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* global parameters */ -static int frame_rate; - -/* Number of times to retry a failed I2C transaction. Increase this if you - * are getting "Failed to read sensor ID..." */ -static int i2c_detect_tries = 10; - -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - EXPOSURE, - COLORS, - HFLIP, - VFLIP, - AUTOBRIGHT, - AUTOGAIN, - FREQ, - NCTRL /* number of controls */ -}; - -/* ov519 device descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRL]; - - u8 packet_nr; - - char bridge; -#define BRIDGE_OV511 0 -#define BRIDGE_OV511PLUS 1 -#define BRIDGE_OV518 2 -#define BRIDGE_OV518PLUS 3 -#define BRIDGE_OV519 4 /* = ov530 */ -#define BRIDGE_OVFX2 5 -#define BRIDGE_W9968CF 6 -#define BRIDGE_MASK 7 - - char invert_led; -#define BRIDGE_INVERT_LED 8 - - char snapshot_pressed; - char snapshot_needs_reset; - - /* Determined by sensor type */ - u8 sif; - - u8 quality; -#define QUALITY_MIN 50 -#define QUALITY_MAX 70 -#define QUALITY_DEF 50 - - u8 stopped; /* Streaming is temporarily paused */ - u8 first_frame; - - u8 frame_rate; /* current Framerate */ - u8 clockdiv; /* clockdiv override */ - - s8 sensor; /* Type of image sensor chip (SEN_*) */ - - u8 sensor_addr; - u16 sensor_width; - u16 sensor_height; - s16 sensor_reg_cache[256]; - - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; -enum sensors { - SEN_OV2610, - SEN_OV2610AE, - SEN_OV3610, - SEN_OV6620, - SEN_OV6630, - SEN_OV66308AF, - SEN_OV7610, - SEN_OV7620, - SEN_OV7620AE, - SEN_OV7640, - SEN_OV7648, - SEN_OV7660, - SEN_OV7670, - SEN_OV76BE, - SEN_OV8610, -}; - -/* Note this is a bit of a hack, but the w9968cf driver needs the code for all - the ov sensors which is already present here. When we have the time we - really should move the sensor drivers to v4l2 sub drivers. */ -#include "w996Xcf.c" - -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void sethvflip(struct gspca_dev *gspca_dev); -static void setautobright(struct gspca_dev *gspca_dev); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static void setfreq(struct gspca_dev *gspca_dev); -static void setfreq_i(struct sd *sd); - -static const struct ctrl sd_ctrls[] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setbrightness, - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setcontrast, - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setexposure, - }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setcolors, - }, -/* The flip controls work for sensors ov7660 and ov7670 only */ -[HFLIP] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip, - }, -[VFLIP] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip, - }, -[AUTOBRIGHT] = { - { - .id = V4L2_CID_AUTOBRIGHTNESS, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Brightness", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set_control = setautobright, - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - .flags = V4L2_CTRL_FLAG_UPDATE - }, - .set = sd_setautogain, - }, -[FREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: no flicker, 1: 50Hz, 2:60Hz, 3: auto */ - .step = 1, - .default_value = 0, - }, - .set_control = setfreq, - }, -}; - -/* table of the disabled controls */ -static const unsigned ctrl_dis[] = { -[SEN_OV2610] = ((1 << NCTRL) - 1) /* no control */ - ^ ((1 << EXPOSURE) /* but exposure */ - | (1 << AUTOGAIN)), /* and autogain */ - -[SEN_OV2610AE] = ((1 << NCTRL) - 1) /* no control */ - ^ ((1 << EXPOSURE) /* but exposure */ - | (1 << AUTOGAIN)), /* and autogain */ - -[SEN_OV3610] = (1 << NCTRL) - 1, /* no control */ - -[SEN_OV6620] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV6630] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV66308AF] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7610] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7620] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7620AE] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7640] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << AUTOBRIGHT) | - (1 << CONTRAST) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7648] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << AUTOBRIGHT) | - (1 << CONTRAST) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7660] = (1 << AUTOBRIGHT) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7670] = (1 << COLORS) | - (1 << AUTOBRIGHT) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV76BE] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV8610] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN) | - (1 << FREQ), -}; - -static const struct v4l2_pix_format ov519_vga_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; -static const struct v4l2_pix_format ov519_sif_mode[] = { - {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 3}, - {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -/* Note some of the sizeimage values for the ov511 / ov518 may seem - larger then necessary, however they need to be this big as the ov511 / - ov518 always fills the entire isoc frame, using 0 padding bytes when - it doesn't have any data. So with low framerates the amount of data - transfered can become quite large (libv4l will remove all the 0 padding - in userspace). */ -static const struct v4l2_pix_format ov518_vga_mode[] = { - {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 2, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; -static const struct v4l2_pix_format ov518_sif_mode[] = { - {160, 120, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 70000, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 3}, - {176, 144, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 70000, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {352, 288, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -static const struct v4l2_pix_format ov511_vga_mode[] = { - {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 2, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; -static const struct v4l2_pix_format ov511_sif_mode[] = { - {160, 120, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 70000, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 3}, - {176, 144, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 70000, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {352, 288, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -static const struct v4l2_pix_format ovfx2_vga_mode[] = { - {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; -static const struct v4l2_pix_format ovfx2_cif_mode[] = { - {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 3}, - {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; -static const struct v4l2_pix_format ovfx2_ov2610_mode[] = { - {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 800, - .sizeimage = 800 * 600, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 1600, - .sizeimage = 1600 * 1200, - .colorspace = V4L2_COLORSPACE_SRGB}, -}; -static const struct v4l2_pix_format ovfx2_ov3610_mode[] = { - {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 800, - .sizeimage = 800 * 600, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 1024, - .sizeimage = 1024 * 768, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 1600, - .sizeimage = 1600 * 1200, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, - {2048, 1536, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 2048, - .sizeimage = 2048 * 1536, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -/* Registers common to OV511 / OV518 */ -#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ -#define R51x_SYS_RESET 0x50 - /* Reset type flags */ - #define OV511_RESET_OMNICE 0x08 -#define R51x_SYS_INIT 0x53 -#define R51x_SYS_SNAP 0x52 -#define R51x_SYS_CUST_ID 0x5f -#define R51x_COMP_LUT_BEGIN 0x80 - -/* OV511 Camera interface register numbers */ -#define R511_CAM_DELAY 0x10 -#define R511_CAM_EDGE 0x11 -#define R511_CAM_PXCNT 0x12 -#define R511_CAM_LNCNT 0x13 -#define R511_CAM_PXDIV 0x14 -#define R511_CAM_LNDIV 0x15 -#define R511_CAM_UV_EN 0x16 -#define R511_CAM_LINE_MODE 0x17 -#define R511_CAM_OPTS 0x18 - -#define R511_SNAP_FRAME 0x19 -#define R511_SNAP_PXCNT 0x1a -#define R511_SNAP_LNCNT 0x1b -#define R511_SNAP_PXDIV 0x1c -#define R511_SNAP_LNDIV 0x1d -#define R511_SNAP_UV_EN 0x1e -#define R511_SNAP_OPTS 0x1f - -#define R511_DRAM_FLOW_CTL 0x20 -#define R511_FIFO_OPTS 0x31 -#define R511_I2C_CTL 0x40 -#define R511_SYS_LED_CTL 0x55 /* OV511+ only */ -#define R511_COMP_EN 0x78 -#define R511_COMP_LUT_EN 0x79 - -/* OV518 Camera interface register numbers */ -#define R518_GPIO_OUT 0x56 /* OV518(+) only */ -#define R518_GPIO_CTL 0x57 /* OV518(+) only */ - -/* OV519 Camera interface register numbers */ -#define OV519_R10_H_SIZE 0x10 -#define OV519_R11_V_SIZE 0x11 -#define OV519_R12_X_OFFSETL 0x12 -#define OV519_R13_X_OFFSETH 0x13 -#define OV519_R14_Y_OFFSETL 0x14 -#define OV519_R15_Y_OFFSETH 0x15 -#define OV519_R16_DIVIDER 0x16 -#define OV519_R20_DFR 0x20 -#define OV519_R25_FORMAT 0x25 - -/* OV519 System Controller register numbers */ -#define OV519_R51_RESET1 0x51 -#define OV519_R54_EN_CLK1 0x54 -#define OV519_R57_SNAPSHOT 0x57 - -#define OV519_GPIO_DATA_OUT0 0x71 -#define OV519_GPIO_IO_CTRL0 0x72 - -/*#define OV511_ENDPOINT_ADDRESS 1 * Isoc endpoint number */ - -/* - * The FX2 chip does not give us a zero length read at end of frame. - * It does, however, give a short read at the end of a frame, if - * necessary, rather than run two frames together. - * - * By choosing the right bulk transfer size, we are guaranteed to always - * get a short read for the last read of each frame. Frame sizes are - * always a composite number (width * height, or a multiple) so if we - * choose a prime number, we are guaranteed that the last read of a - * frame will be short. - * - * But it isn't that easy: the 2.6 kernel requires a multiple of 4KB, - * otherwise EOVERFLOW "babbling" errors occur. I have not been able - * to figure out why. [PMiller] - * - * The constant (13 * 4096) is the largest "prime enough" number less than 64KB. - * - * It isn't enough to know the number of bytes per frame, in case we - * have data dropouts or buffer overruns (even though the FX2 double - * buffers, there are some pretty strict real time constraints for - * isochronous transfer for larger frame sizes). - */ -/*jfm: this value works well for 1600x1200, but not 800x600 - see isoc_init */ -#define OVFX2_BULK_SIZE (13 * 4096) - -/* I2C registers */ -#define R51x_I2C_W_SID 0x41 -#define R51x_I2C_SADDR_3 0x42 -#define R51x_I2C_SADDR_2 0x43 -#define R51x_I2C_R_SID 0x44 -#define R51x_I2C_DATA 0x45 -#define R518_I2C_CTL 0x47 /* OV518(+) only */ -#define OVFX2_I2C_ADDR 0x00 - -/* I2C ADDRESSES */ -#define OV7xx0_SID 0x42 -#define OV_HIRES_SID 0x60 /* OV9xxx / OV2xxx / OV3xxx */ -#define OV8xx0_SID 0xa0 -#define OV6xx0_SID 0xc0 - -/* OV7610 registers */ -#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ -#define OV7610_REG_BLUE 0x01 /* blue channel balance */ -#define OV7610_REG_RED 0x02 /* red channel balance */ -#define OV7610_REG_SAT 0x03 /* saturation */ -#define OV8610_REG_HUE 0x04 /* 04 reserved */ -#define OV7610_REG_CNT 0x05 /* Y contrast */ -#define OV7610_REG_BRT 0x06 /* Y brightness */ -#define OV7610_REG_COM_C 0x14 /* misc common regs */ -#define OV7610_REG_ID_HIGH 0x1c /* manufacturer ID MSB */ -#define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */ -#define OV7610_REG_COM_I 0x29 /* misc settings */ - -/* OV7660 and OV7670 registers */ -#define OV7670_R00_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ -#define OV7670_R01_BLUE 0x01 /* blue gain */ -#define OV7670_R02_RED 0x02 /* red gain */ -#define OV7670_R03_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ -#define OV7670_R04_COM1 0x04 /* Control 1 */ -/*#define OV7670_R07_AECHH 0x07 * AEC MS 5 bits */ -#define OV7670_R0C_COM3 0x0c /* Control 3 */ -#define OV7670_R0D_COM4 0x0d /* Control 4 */ -#define OV7670_R0E_COM5 0x0e /* All "reserved" */ -#define OV7670_R0F_COM6 0x0f /* Control 6 */ -#define OV7670_R10_AECH 0x10 /* More bits of AEC value */ -#define OV7670_R11_CLKRC 0x11 /* Clock control */ -#define OV7670_R12_COM7 0x12 /* Control 7 */ -#define OV7670_COM7_FMT_VGA 0x00 -/*#define OV7670_COM7_YUV 0x00 * YUV */ -#define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */ -#define OV7670_COM7_FMT_MASK 0x38 -#define OV7670_COM7_RESET 0x80 /* Register reset */ -#define OV7670_R13_COM8 0x13 /* Control 8 */ -#define OV7670_COM8_AEC 0x01 /* Auto exposure enable */ -#define OV7670_COM8_AWB 0x02 /* White balance enable */ -#define OV7670_COM8_AGC 0x04 /* Auto gain enable */ -#define OV7670_COM8_BFILT 0x20 /* Band filter enable */ -#define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */ -#define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ -#define OV7670_R14_COM9 0x14 /* Control 9 - gain ceiling */ -#define OV7670_R15_COM10 0x15 /* Control 10 */ -#define OV7670_R17_HSTART 0x17 /* Horiz start high bits */ -#define OV7670_R18_HSTOP 0x18 /* Horiz stop high bits */ -#define OV7670_R19_VSTART 0x19 /* Vert start high bits */ -#define OV7670_R1A_VSTOP 0x1a /* Vert stop high bits */ -#define OV7670_R1E_MVFP 0x1e /* Mirror / vflip */ -#define OV7670_MVFP_VFLIP 0x10 /* vertical flip */ -#define OV7670_MVFP_MIRROR 0x20 /* Mirror image */ -#define OV7670_R24_AEW 0x24 /* AGC upper limit */ -#define OV7670_R25_AEB 0x25 /* AGC lower limit */ -#define OV7670_R26_VPT 0x26 /* AGC/AEC fast mode op region */ -#define OV7670_R32_HREF 0x32 /* HREF pieces */ -#define OV7670_R3A_TSLB 0x3a /* lots of stuff */ -#define OV7670_R3B_COM11 0x3b /* Control 11 */ -#define OV7670_COM11_EXP 0x02 -#define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ -#define OV7670_R3C_COM12 0x3c /* Control 12 */ -#define OV7670_R3D_COM13 0x3d /* Control 13 */ -#define OV7670_COM13_GAMMA 0x80 /* Gamma enable */ -#define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */ -#define OV7670_R3E_COM14 0x3e /* Control 14 */ -#define OV7670_R3F_EDGE 0x3f /* Edge enhancement factor */ -#define OV7670_R40_COM15 0x40 /* Control 15 */ -/*#define OV7670_COM15_R00FF 0xc0 * 00 to FF */ -#define OV7670_R41_COM16 0x41 /* Control 16 */ -#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */ -/* end of ov7660 common registers */ -#define OV7670_R55_BRIGHT 0x55 /* Brightness */ -#define OV7670_R56_CONTRAS 0x56 /* Contrast control */ -#define OV7670_R69_GFIX 0x69 /* Fix gain control */ -/*#define OV7670_R8C_RGB444 0x8c * RGB 444 control */ -#define OV7670_R9F_HAECC1 0x9f /* Hist AEC/AGC control 1 */ -#define OV7670_RA0_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ -#define OV7670_RA5_BD50MAX 0xa5 /* 50hz banding step limit */ -#define OV7670_RA6_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ -#define OV7670_RA7_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ -#define OV7670_RA8_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ -#define OV7670_RA9_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ -#define OV7670_RAA_HAECC7 0xaa /* Hist AEC/AGC control 7 */ -#define OV7670_RAB_BD60MAX 0xab /* 60hz banding step limit */ - -struct ov_regvals { - u8 reg; - u8 val; -}; -struct ov_i2c_regvals { - u8 reg; - u8 val; -}; - -/* Settings for OV2610 camera chip */ -static const struct ov_i2c_regvals norm_2610[] = { - { 0x12, 0x80 }, /* reset */ -}; - -static const struct ov_i2c_regvals norm_2610ae[] = { - {0x12, 0x80}, /* reset */ - {0x13, 0xcd}, - {0x09, 0x01}, - {0x0d, 0x00}, - {0x11, 0x80}, - {0x12, 0x20}, /* 1600x1200 */ - {0x33, 0x0c}, - {0x35, 0x90}, - {0x36, 0x37}, -/* ms-win traces */ - {0x11, 0x83}, /* clock / 3 ? */ - {0x2d, 0x00}, /* 60 Hz filter */ - {0x24, 0xb0}, /* normal colors */ - {0x25, 0x90}, - {0x10, 0x43}, -}; - -static const struct ov_i2c_regvals norm_3620b[] = { - /* - * From the datasheet: "Note that after writing to register COMH - * (0x12) to change the sensor mode, registers related to the - * sensor’s cropping window will be reset back to their default - * values." - * - * "wait 4096 external clock ... to make sure the sensor is - * stable and ready to access registers" i.e. 160us at 24MHz - */ - { 0x12, 0x80 }, /* COMH reset */ - { 0x12, 0x00 }, /* QXGA, master */ - - /* - * 11 CLKRC "Clock Rate Control" - * [7] internal frequency doublers: on - * [6] video port mode: master - * [5:0] clock divider: 1 - */ - { 0x11, 0x80 }, - - /* - * 13 COMI "Common Control I" - * = 192 (0xC0) 11000000 - * COMI[7] "AEC speed selection" - * = 1 (0x01) 1....... "Faster AEC correction" - * COMI[6] "AEC speed step selection" - * = 1 (0x01) .1...... "Big steps, fast" - * COMI[5] "Banding filter on off" - * = 0 (0x00) ..0..... "Off" - * COMI[4] "Banding filter option" - * = 0 (0x00) ...0.... "Main clock is 48 MHz and - * the PLL is ON" - * COMI[3] "Reserved" - * = 0 (0x00) ....0... - * COMI[2] "AGC auto manual control selection" - * = 0 (0x00) .....0.. "Manual" - * COMI[1] "AWB auto manual control selection" - * = 0 (0x00) ......0. "Manual" - * COMI[0] "Exposure control" - * = 0 (0x00) .......0 "Manual" - */ - { 0x13, 0xc0 }, - - /* - * 09 COMC "Common Control C" - * = 8 (0x08) 00001000 - * COMC[7:5] "Reserved" - * = 0 (0x00) 000..... - * COMC[4] "Sleep Mode Enable" - * = 0 (0x00) ...0.... "Normal mode" - * COMC[3:2] "Sensor sampling reset timing selection" - * = 2 (0x02) ....10.. "Longer reset time" - * COMC[1:0] "Output drive current select" - * = 0 (0x00) ......00 "Weakest" - */ - { 0x09, 0x08 }, - - /* - * 0C COMD "Common Control D" - * = 8 (0x08) 00001000 - * COMD[7] "Reserved" - * = 0 (0x00) 0....... - * COMD[6] "Swap MSB and LSB at the output port" - * = 0 (0x00) .0...... "False" - * COMD[5:3] "Reserved" - * = 1 (0x01) ..001... - * COMD[2] "Output Average On Off" - * = 0 (0x00) .....0.. "Output Normal" - * COMD[1] "Sensor precharge voltage selection" - * = 0 (0x00) ......0. "Selects internal - * reference precharge - * voltage" - * COMD[0] "Snapshot option" - * = 0 (0x00) .......0 "Enable live video output - * after snapshot sequence" - */ - { 0x0c, 0x08 }, - - /* - * 0D COME "Common Control E" - * = 161 (0xA1) 10100001 - * COME[7] "Output average option" - * = 1 (0x01) 1....... "Output average of 4 pixels" - * COME[6] "Anti-blooming control" - * = 0 (0x00) .0...... "Off" - * COME[5:3] "Reserved" - * = 4 (0x04) ..100... - * COME[2] "Clock output power down pin status" - * = 0 (0x00) .....0.. "Tri-state data output pin - * on power down" - * COME[1] "Data output pin status selection at power down" - * = 0 (0x00) ......0. "Tri-state VSYNC, PCLK, - * HREF, and CHSYNC pins on - * power down" - * COME[0] "Auto zero circuit select" - * = 1 (0x01) .......1 "On" - */ - { 0x0d, 0xa1 }, - - /* - * 0E COMF "Common Control F" - * = 112 (0x70) 01110000 - * COMF[7] "System clock selection" - * = 0 (0x00) 0....... "Use 24 MHz system clock" - * COMF[6:4] "Reserved" - * = 7 (0x07) .111.... - * COMF[3] "Manual auto negative offset canceling selection" - * = 0 (0x00) ....0... "Auto detect negative - * offset and cancel it" - * COMF[2:0] "Reserved" - * = 0 (0x00) .....000 - */ - { 0x0e, 0x70 }, - - /* - * 0F COMG "Common Control G" - * = 66 (0x42) 01000010 - * COMG[7] "Optical black output selection" - * = 0 (0x00) 0....... "Disable" - * COMG[6] "Black level calibrate selection" - * = 1 (0x01) .1...... "Use optical black pixels - * to calibrate" - * COMG[5:4] "Reserved" - * = 0 (0x00) ..00.... - * COMG[3] "Channel offset adjustment" - * = 0 (0x00) ....0... "Disable offset adjustment" - * COMG[2] "ADC black level calibration option" - * = 0 (0x00) .....0.. "Use B/G line and G/R - * line to calibrate each - * channel's black level" - * COMG[1] "Reserved" - * = 1 (0x01) ......1. - * COMG[0] "ADC black level calibration enable" - * = 0 (0x00) .......0 "Disable" - */ - { 0x0f, 0x42 }, - - /* - * 14 COMJ "Common Control J" - * = 198 (0xC6) 11000110 - * COMJ[7:6] "AGC gain ceiling" - * = 3 (0x03) 11...... "8x" - * COMJ[5:4] "Reserved" - * = 0 (0x00) ..00.... - * COMJ[3] "Auto banding filter" - * = 0 (0x00) ....0... "Banding filter is always - * on off depending on - * COMI[5] setting" - * COMJ[2] "VSYNC drop option" - * = 1 (0x01) .....1.. "SYNC is dropped if frame - * data is dropped" - * COMJ[1] "Frame data drop" - * = 1 (0x01) ......1. "Drop frame data if - * exposure is not within - * tolerance. In AEC mode, - * data is normally dropped - * when data is out of - * range." - * COMJ[0] "Reserved" - * = 0 (0x00) .......0 - */ - { 0x14, 0xc6 }, - - /* - * 15 COMK "Common Control K" - * = 2 (0x02) 00000010 - * COMK[7] "CHSYNC pin output swap" - * = 0 (0x00) 0....... "CHSYNC" - * COMK[6] "HREF pin output swap" - * = 0 (0x00) .0...... "HREF" - * COMK[5] "PCLK output selection" - * = 0 (0x00) ..0..... "PCLK always output" - * COMK[4] "PCLK edge selection" - * = 0 (0x00) ...0.... "Data valid on falling edge" - * COMK[3] "HREF output polarity" - * = 0 (0x00) ....0... "positive" - * COMK[2] "Reserved" - * = 0 (0x00) .....0.. - * COMK[1] "VSYNC polarity" - * = 1 (0x01) ......1. "negative" - * COMK[0] "HSYNC polarity" - * = 0 (0x00) .......0 "positive" - */ - { 0x15, 0x02 }, - - /* - * 33 CHLF "Current Control" - * = 9 (0x09) 00001001 - * CHLF[7:6] "Sensor current control" - * = 0 (0x00) 00...... - * CHLF[5] "Sensor current range control" - * = 0 (0x00) ..0..... "normal range" - * CHLF[4] "Sensor current" - * = 0 (0x00) ...0.... "normal current" - * CHLF[3] "Sensor buffer current control" - * = 1 (0x01) ....1... "half current" - * CHLF[2] "Column buffer current control" - * = 0 (0x00) .....0.. "normal current" - * CHLF[1] "Analog DSP current control" - * = 0 (0x00) ......0. "normal current" - * CHLF[1] "ADC current control" - * = 0 (0x00) ......0. "normal current" - */ - { 0x33, 0x09 }, - - /* - * 34 VBLM "Blooming Control" - * = 80 (0x50) 01010000 - * VBLM[7] "Hard soft reset switch" - * = 0 (0x00) 0....... "Hard reset" - * VBLM[6:4] "Blooming voltage selection" - * = 5 (0x05) .101.... - * VBLM[3:0] "Sensor current control" - * = 0 (0x00) ....0000 - */ - { 0x34, 0x50 }, - - /* - * 36 VCHG "Sensor Precharge Voltage Control" - * = 0 (0x00) 00000000 - * VCHG[7] "Reserved" - * = 0 (0x00) 0....... - * VCHG[6:4] "Sensor precharge voltage control" - * = 0 (0x00) .000.... - * VCHG[3:0] "Sensor array common reference" - * = 0 (0x00) ....0000 - */ - { 0x36, 0x00 }, - - /* - * 37 ADC "ADC Reference Control" - * = 4 (0x04) 00000100 - * ADC[7:4] "Reserved" - * = 0 (0x00) 0000.... - * ADC[3] "ADC input signal range" - * = 0 (0x00) ....0... "Input signal 1.0x" - * ADC[2:0] "ADC range control" - * = 4 (0x04) .....100 - */ - { 0x37, 0x04 }, - - /* - * 38 ACOM "Analog Common Ground" - * = 82 (0x52) 01010010 - * ACOM[7] "Analog gain control" - * = 0 (0x00) 0....... "Gain 1x" - * ACOM[6] "Analog black level calibration" - * = 1 (0x01) .1...... "On" - * ACOM[5:0] "Reserved" - * = 18 (0x12) ..010010 - */ - { 0x38, 0x52 }, - - /* - * 3A FREFA "Internal Reference Adjustment" - * = 0 (0x00) 00000000 - * FREFA[7:0] "Range" - * = 0 (0x00) 00000000 - */ - { 0x3a, 0x00 }, - - /* - * 3C FVOPT "Internal Reference Adjustment" - * = 31 (0x1F) 00011111 - * FVOPT[7:0] "Range" - * = 31 (0x1F) 00011111 - */ - { 0x3c, 0x1f }, - - /* - * 44 Undocumented = 0 (0x00) 00000000 - * 44[7:0] "It's a secret" - * = 0 (0x00) 00000000 - */ - { 0x44, 0x00 }, - - /* - * 40 Undocumented = 0 (0x00) 00000000 - * 40[7:0] "It's a secret" - * = 0 (0x00) 00000000 - */ - { 0x40, 0x00 }, - - /* - * 41 Undocumented = 0 (0x00) 00000000 - * 41[7:0] "It's a secret" - * = 0 (0x00) 00000000 - */ - { 0x41, 0x00 }, - - /* - * 42 Undocumented = 0 (0x00) 00000000 - * 42[7:0] "It's a secret" - * = 0 (0x00) 00000000 - */ - { 0x42, 0x00 }, - - /* - * 43 Undocumented = 0 (0x00) 00000000 - * 43[7:0] "It's a secret" - * = 0 (0x00) 00000000 - */ - { 0x43, 0x00 }, - - /* - * 45 Undocumented = 128 (0x80) 10000000 - * 45[7:0] "It's a secret" - * = 128 (0x80) 10000000 - */ - { 0x45, 0x80 }, - - /* - * 48 Undocumented = 192 (0xC0) 11000000 - * 48[7:0] "It's a secret" - * = 192 (0xC0) 11000000 - */ - { 0x48, 0xc0 }, - - /* - * 49 Undocumented = 25 (0x19) 00011001 - * 49[7:0] "It's a secret" - * = 25 (0x19) 00011001 - */ - { 0x49, 0x19 }, - - /* - * 4B Undocumented = 128 (0x80) 10000000 - * 4B[7:0] "It's a secret" - * = 128 (0x80) 10000000 - */ - { 0x4b, 0x80 }, - - /* - * 4D Undocumented = 196 (0xC4) 11000100 - * 4D[7:0] "It's a secret" - * = 196 (0xC4) 11000100 - */ - { 0x4d, 0xc4 }, - - /* - * 35 VREF "Reference Voltage Control" - * = 76 (0x4c) 01001100 - * VREF[7:5] "Column high reference control" - * = 2 (0x02) 010..... "higher voltage" - * VREF[4:2] "Column low reference control" - * = 3 (0x03) ...011.. "Highest voltage" - * VREF[1:0] "Reserved" - * = 0 (0x00) ......00 - */ - { 0x35, 0x4c }, - - /* - * 3D Undocumented = 0 (0x00) 00000000 - * 3D[7:0] "It's a secret" - * = 0 (0x00) 00000000 - */ - { 0x3d, 0x00 }, - - /* - * 3E Undocumented = 0 (0x00) 00000000 - * 3E[7:0] "It's a secret" - * = 0 (0x00) 00000000 - */ - { 0x3e, 0x00 }, - - /* - * 3B FREFB "Internal Reference Adjustment" - * = 24 (0x18) 00011000 - * FREFB[7:0] "Range" - * = 24 (0x18) 00011000 - */ - { 0x3b, 0x18 }, - - /* - * 33 CHLF "Current Control" - * = 25 (0x19) 00011001 - * CHLF[7:6] "Sensor current control" - * = 0 (0x00) 00...... - * CHLF[5] "Sensor current range control" - * = 0 (0x00) ..0..... "normal range" - * CHLF[4] "Sensor current" - * = 1 (0x01) ...1.... "double current" - * CHLF[3] "Sensor buffer current control" - * = 1 (0x01) ....1... "half current" - * CHLF[2] "Column buffer current control" - * = 0 (0x00) .....0.. "normal current" - * CHLF[1] "Analog DSP current control" - * = 0 (0x00) ......0. "normal current" - * CHLF[1] "ADC current control" - * = 0 (0x00) ......0. "normal current" - */ - { 0x33, 0x19 }, - - /* - * 34 VBLM "Blooming Control" - * = 90 (0x5A) 01011010 - * VBLM[7] "Hard soft reset switch" - * = 0 (0x00) 0....... "Hard reset" - * VBLM[6:4] "Blooming voltage selection" - * = 5 (0x05) .101.... - * VBLM[3:0] "Sensor current control" - * = 10 (0x0A) ....1010 - */ - { 0x34, 0x5a }, - - /* - * 3B FREFB "Internal Reference Adjustment" - * = 0 (0x00) 00000000 - * FREFB[7:0] "Range" - * = 0 (0x00) 00000000 - */ - { 0x3b, 0x00 }, - - /* - * 33 CHLF "Current Control" - * = 9 (0x09) 00001001 - * CHLF[7:6] "Sensor current control" - * = 0 (0x00) 00...... - * CHLF[5] "Sensor current range control" - * = 0 (0x00) ..0..... "normal range" - * CHLF[4] "Sensor current" - * = 0 (0x00) ...0.... "normal current" - * CHLF[3] "Sensor buffer current control" - * = 1 (0x01) ....1... "half current" - * CHLF[2] "Column buffer current control" - * = 0 (0x00) .....0.. "normal current" - * CHLF[1] "Analog DSP current control" - * = 0 (0x00) ......0. "normal current" - * CHLF[1] "ADC current control" - * = 0 (0x00) ......0. "normal current" - */ - { 0x33, 0x09 }, - - /* - * 34 VBLM "Blooming Control" - * = 80 (0x50) 01010000 - * VBLM[7] "Hard soft reset switch" - * = 0 (0x00) 0....... "Hard reset" - * VBLM[6:4] "Blooming voltage selection" - * = 5 (0x05) .101.... - * VBLM[3:0] "Sensor current control" - * = 0 (0x00) ....0000 - */ - { 0x34, 0x50 }, - - /* - * 12 COMH "Common Control H" - * = 64 (0x40) 01000000 - * COMH[7] "SRST" - * = 0 (0x00) 0....... "No-op" - * COMH[6:4] "Resolution selection" - * = 4 (0x04) .100.... "XGA" - * COMH[3] "Master slave selection" - * = 0 (0x00) ....0... "Master mode" - * COMH[2] "Internal B/R channel option" - * = 0 (0x00) .....0.. "B/R use same channel" - * COMH[1] "Color bar test pattern" - * = 0 (0x00) ......0. "Off" - * COMH[0] "Reserved" - * = 0 (0x00) .......0 - */ - { 0x12, 0x40 }, - - /* - * 17 HREFST "Horizontal window start" - * = 31 (0x1F) 00011111 - * HREFST[7:0] "Horizontal window start, 8 MSBs" - * = 31 (0x1F) 00011111 - */ - { 0x17, 0x1f }, - - /* - * 18 HREFEND "Horizontal window end" - * = 95 (0x5F) 01011111 - * HREFEND[7:0] "Horizontal Window End, 8 MSBs" - * = 95 (0x5F) 01011111 - */ - { 0x18, 0x5f }, - - /* - * 19 VSTRT "Vertical window start" - * = 0 (0x00) 00000000 - * VSTRT[7:0] "Vertical Window Start, 8 MSBs" - * = 0 (0x00) 00000000 - */ - { 0x19, 0x00 }, - - /* - * 1A VEND "Vertical window end" - * = 96 (0x60) 01100000 - * VEND[7:0] "Vertical Window End, 8 MSBs" - * = 96 (0x60) 01100000 - */ - { 0x1a, 0x60 }, - - /* - * 32 COMM "Common Control M" - * = 18 (0x12) 00010010 - * COMM[7:6] "Pixel clock divide option" - * = 0 (0x00) 00...... "/1" - * COMM[5:3] "Horizontal window end position, 3 LSBs" - * = 2 (0x02) ..010... - * COMM[2:0] "Horizontal window start position, 3 LSBs" - * = 2 (0x02) .....010 - */ - { 0x32, 0x12 }, - - /* - * 03 COMA "Common Control A" - * = 74 (0x4A) 01001010 - * COMA[7:4] "AWB Update Threshold" - * = 4 (0x04) 0100.... - * COMA[3:2] "Vertical window end line control 2 LSBs" - * = 2 (0x02) ....10.. - * COMA[1:0] "Vertical window start line control 2 LSBs" - * = 2 (0x02) ......10 - */ - { 0x03, 0x4a }, - - /* - * 11 CLKRC "Clock Rate Control" - * = 128 (0x80) 10000000 - * CLKRC[7] "Internal frequency doublers on off seclection" - * = 1 (0x01) 1....... "On" - * CLKRC[6] "Digital video master slave selection" - * = 0 (0x00) .0...... "Master mode, sensor - * provides PCLK" - * CLKRC[5:0] "Clock divider { CLK = PCLK/(1+CLKRC[5:0]) }" - * = 0 (0x00) ..000000 - */ - { 0x11, 0x80 }, - - /* - * 12 COMH "Common Control H" - * = 0 (0x00) 00000000 - * COMH[7] "SRST" - * = 0 (0x00) 0....... "No-op" - * COMH[6:4] "Resolution selection" - * = 0 (0x00) .000.... "QXGA" - * COMH[3] "Master slave selection" - * = 0 (0x00) ....0... "Master mode" - * COMH[2] "Internal B/R channel option" - * = 0 (0x00) .....0.. "B/R use same channel" - * COMH[1] "Color bar test pattern" - * = 0 (0x00) ......0. "Off" - * COMH[0] "Reserved" - * = 0 (0x00) .......0 - */ - { 0x12, 0x00 }, - - /* - * 12 COMH "Common Control H" - * = 64 (0x40) 01000000 - * COMH[7] "SRST" - * = 0 (0x00) 0....... "No-op" - * COMH[6:4] "Resolution selection" - * = 4 (0x04) .100.... "XGA" - * COMH[3] "Master slave selection" - * = 0 (0x00) ....0... "Master mode" - * COMH[2] "Internal B/R channel option" - * = 0 (0x00) .....0.. "B/R use same channel" - * COMH[1] "Color bar test pattern" - * = 0 (0x00) ......0. "Off" - * COMH[0] "Reserved" - * = 0 (0x00) .......0 - */ - { 0x12, 0x40 }, - - /* - * 17 HREFST "Horizontal window start" - * = 31 (0x1F) 00011111 - * HREFST[7:0] "Horizontal window start, 8 MSBs" - * = 31 (0x1F) 00011111 - */ - { 0x17, 0x1f }, - - /* - * 18 HREFEND "Horizontal window end" - * = 95 (0x5F) 01011111 - * HREFEND[7:0] "Horizontal Window End, 8 MSBs" - * = 95 (0x5F) 01011111 - */ - { 0x18, 0x5f }, - - /* - * 19 VSTRT "Vertical window start" - * = 0 (0x00) 00000000 - * VSTRT[7:0] "Vertical Window Start, 8 MSBs" - * = 0 (0x00) 00000000 - */ - { 0x19, 0x00 }, - - /* - * 1A VEND "Vertical window end" - * = 96 (0x60) 01100000 - * VEND[7:0] "Vertical Window End, 8 MSBs" - * = 96 (0x60) 01100000 - */ - { 0x1a, 0x60 }, - - /* - * 32 COMM "Common Control M" - * = 18 (0x12) 00010010 - * COMM[7:6] "Pixel clock divide option" - * = 0 (0x00) 00...... "/1" - * COMM[5:3] "Horizontal window end position, 3 LSBs" - * = 2 (0x02) ..010... - * COMM[2:0] "Horizontal window start position, 3 LSBs" - * = 2 (0x02) .....010 - */ - { 0x32, 0x12 }, - - /* - * 03 COMA "Common Control A" - * = 74 (0x4A) 01001010 - * COMA[7:4] "AWB Update Threshold" - * = 4 (0x04) 0100.... - * COMA[3:2] "Vertical window end line control 2 LSBs" - * = 2 (0x02) ....10.. - * COMA[1:0] "Vertical window start line control 2 LSBs" - * = 2 (0x02) ......10 - */ - { 0x03, 0x4a }, - - /* - * 02 RED "Red Gain Control" - * = 175 (0xAF) 10101111 - * RED[7] "Action" - * = 1 (0x01) 1....... "gain = 1/(1+bitrev([6:0]))" - * RED[6:0] "Value" - * = 47 (0x2F) .0101111 - */ - { 0x02, 0xaf }, - - /* - * 2D ADDVSL "VSYNC Pulse Width" - * = 210 (0xD2) 11010010 - * ADDVSL[7:0] "VSYNC pulse width, LSB" - * = 210 (0xD2) 11010010 - */ - { 0x2d, 0xd2 }, - - /* - * 00 GAIN = 24 (0x18) 00011000 - * GAIN[7:6] "Reserved" - * = 0 (0x00) 00...... - * GAIN[5] "Double" - * = 0 (0x00) ..0..... "False" - * GAIN[4] "Double" - * = 1 (0x01) ...1.... "True" - * GAIN[3:0] "Range" - * = 8 (0x08) ....1000 - */ - { 0x00, 0x18 }, - - /* - * 01 BLUE "Blue Gain Control" - * = 240 (0xF0) 11110000 - * BLUE[7] "Action" - * = 1 (0x01) 1....... "gain = 1/(1+bitrev([6:0]))" - * BLUE[6:0] "Value" - * = 112 (0x70) .1110000 - */ - { 0x01, 0xf0 }, - - /* - * 10 AEC "Automatic Exposure Control" - * = 10 (0x0A) 00001010 - * AEC[7:0] "Automatic Exposure Control, 8 MSBs" - * = 10 (0x0A) 00001010 - */ - { 0x10, 0x0a }, - - { 0xe1, 0x67 }, - { 0xe3, 0x03 }, - { 0xe4, 0x26 }, - { 0xe5, 0x3e }, - { 0xf8, 0x01 }, - { 0xff, 0x01 }, -}; - -static const struct ov_i2c_regvals norm_6x20[] = { - { 0x12, 0x80 }, /* reset */ - { 0x11, 0x01 }, - { 0x03, 0x60 }, - { 0x05, 0x7f }, /* For when autoadjust is off */ - { 0x07, 0xa8 }, - /* The ratio of 0x0c and 0x0d controls the white point */ - { 0x0c, 0x24 }, - { 0x0d, 0x24 }, - { 0x0f, 0x15 }, /* COMS */ - { 0x10, 0x75 }, /* AEC Exposure time */ - { 0x12, 0x24 }, /* Enable AGC */ - { 0x14, 0x04 }, - /* 0x16: 0x06 helps frame stability with moving objects */ - { 0x16, 0x06 }, -/* { 0x20, 0x30 }, * Aperture correction enable */ - { 0x26, 0xb2 }, /* BLC enable */ - /* 0x28: 0x05 Selects RGB format if RGB on */ - { 0x28, 0x05 }, - { 0x2a, 0x04 }, /* Disable framerate adjust */ -/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ - { 0x2d, 0x85 }, - { 0x33, 0xa0 }, /* Color Processing Parameter */ - { 0x34, 0xd2 }, /* Max A/D range */ - { 0x38, 0x8b }, - { 0x39, 0x40 }, - - { 0x3c, 0x39 }, /* Enable AEC mode changing */ - { 0x3c, 0x3c }, /* Change AEC mode */ - { 0x3c, 0x24 }, /* Disable AEC mode changing */ - - { 0x3d, 0x80 }, - /* These next two registers (0x4a, 0x4b) are undocumented. - * They control the color balance */ - { 0x4a, 0x80 }, - { 0x4b, 0x80 }, - { 0x4d, 0xd2 }, /* This reduces noise a bit */ - { 0x4e, 0xc1 }, - { 0x4f, 0x04 }, -/* Do 50-53 have any effect? */ -/* Toggle 0x12[2] off and on here? */ -}; - -static const struct ov_i2c_regvals norm_6x30[] = { - { 0x12, 0x80 }, /* Reset */ - { 0x00, 0x1f }, /* Gain */ - { 0x01, 0x99 }, /* Blue gain */ - { 0x02, 0x7c }, /* Red gain */ - { 0x03, 0xc0 }, /* Saturation */ - { 0x05, 0x0a }, /* Contrast */ - { 0x06, 0x95 }, /* Brightness */ - { 0x07, 0x2d }, /* Sharpness */ - { 0x0c, 0x20 }, - { 0x0d, 0x20 }, - { 0x0e, 0xa0 }, /* Was 0x20, bit7 enables a 2x gain which we need */ - { 0x0f, 0x05 }, - { 0x10, 0x9a }, - { 0x11, 0x00 }, /* Pixel clock = fastest */ - { 0x12, 0x24 }, /* Enable AGC and AWB */ - { 0x13, 0x21 }, - { 0x14, 0x80 }, - { 0x15, 0x01 }, - { 0x16, 0x03 }, - { 0x17, 0x38 }, - { 0x18, 0xea }, - { 0x19, 0x04 }, - { 0x1a, 0x93 }, - { 0x1b, 0x00 }, - { 0x1e, 0xc4 }, - { 0x1f, 0x04 }, - { 0x20, 0x20 }, - { 0x21, 0x10 }, - { 0x22, 0x88 }, - { 0x23, 0xc0 }, /* Crystal circuit power level */ - { 0x25, 0x9a }, /* Increase AEC black ratio */ - { 0x26, 0xb2 }, /* BLC enable */ - { 0x27, 0xa2 }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x84 }, /* 60 Hz power */ - { 0x2b, 0xa8 }, /* 60 Hz power */ - { 0x2c, 0xa0 }, - { 0x2d, 0x95 }, /* Enable auto-brightness */ - { 0x2e, 0x88 }, - { 0x33, 0x26 }, - { 0x34, 0x03 }, - { 0x36, 0x8f }, - { 0x37, 0x80 }, - { 0x38, 0x83 }, - { 0x39, 0x80 }, - { 0x3a, 0x0f }, - { 0x3b, 0x3c }, - { 0x3c, 0x1a }, - { 0x3d, 0x80 }, - { 0x3e, 0x80 }, - { 0x3f, 0x0e }, - { 0x40, 0x00 }, /* White bal */ - { 0x41, 0x00 }, /* White bal */ - { 0x42, 0x80 }, - { 0x43, 0x3f }, /* White bal */ - { 0x44, 0x80 }, - { 0x45, 0x20 }, - { 0x46, 0x20 }, - { 0x47, 0x80 }, - { 0x48, 0x7f }, - { 0x49, 0x00 }, - { 0x4a, 0x00 }, - { 0x4b, 0x80 }, - { 0x4c, 0xd0 }, - { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ - { 0x4e, 0x40 }, - { 0x4f, 0x07 }, /* UV avg., col. killer: max */ - { 0x50, 0xff }, - { 0x54, 0x23 }, /* Max AGC gain: 18dB */ - { 0x55, 0xff }, - { 0x56, 0x12 }, - { 0x57, 0x81 }, - { 0x58, 0x75 }, - { 0x59, 0x01 }, /* AGC dark current comp.: +1 */ - { 0x5a, 0x2c }, - { 0x5b, 0x0f }, /* AWB chrominance levels */ - { 0x5c, 0x10 }, - { 0x3d, 0x80 }, - { 0x27, 0xa6 }, - { 0x12, 0x20 }, /* Toggle AWB */ - { 0x12, 0x24 }, -}; - -/* Lawrence Glaister reports: - * - * Register 0x0f in the 7610 has the following effects: - * - * 0x85 (AEC method 1): Best overall, good contrast range - * 0x45 (AEC method 2): Very overexposed - * 0xa5 (spec sheet default): Ok, but the black level is - * shifted resulting in loss of contrast - * 0x05 (old driver setting): very overexposed, too much - * contrast - */ -static const struct ov_i2c_regvals norm_7610[] = { - { 0x10, 0xff }, - { 0x16, 0x06 }, - { 0x28, 0x24 }, - { 0x2b, 0xac }, - { 0x12, 0x00 }, - { 0x38, 0x81 }, - { 0x28, 0x24 }, /* 0c */ - { 0x0f, 0x85 }, /* lg's setting */ - { 0x15, 0x01 }, - { 0x20, 0x1c }, - { 0x23, 0x2a }, - { 0x24, 0x10 }, - { 0x25, 0x8a }, - { 0x26, 0xa2 }, - { 0x27, 0xc2 }, - { 0x2a, 0x04 }, - { 0x2c, 0xfe }, - { 0x2d, 0x93 }, - { 0x30, 0x71 }, - { 0x31, 0x60 }, - { 0x32, 0x26 }, - { 0x33, 0x20 }, - { 0x34, 0x48 }, - { 0x12, 0x24 }, - { 0x11, 0x01 }, - { 0x0c, 0x24 }, - { 0x0d, 0x24 }, -}; - -static const struct ov_i2c_regvals norm_7620[] = { - { 0x12, 0x80 }, /* reset */ - { 0x00, 0x00 }, /* gain */ - { 0x01, 0x80 }, /* blue gain */ - { 0x02, 0x80 }, /* red gain */ - { 0x03, 0xc0 }, /* OV7670_R03_VREF */ - { 0x06, 0x60 }, - { 0x07, 0x00 }, - { 0x0c, 0x24 }, - { 0x0c, 0x24 }, - { 0x0d, 0x24 }, - { 0x11, 0x01 }, - { 0x12, 0x24 }, - { 0x13, 0x01 }, - { 0x14, 0x84 }, - { 0x15, 0x01 }, - { 0x16, 0x03 }, - { 0x17, 0x2f }, - { 0x18, 0xcf }, - { 0x19, 0x06 }, - { 0x1a, 0xf5 }, - { 0x1b, 0x00 }, - { 0x20, 0x18 }, - { 0x21, 0x80 }, - { 0x22, 0x80 }, - { 0x23, 0x00 }, - { 0x26, 0xa2 }, - { 0x27, 0xea }, - { 0x28, 0x22 }, /* Was 0x20, bit1 enables a 2x gain which we need */ - { 0x29, 0x00 }, - { 0x2a, 0x10 }, - { 0x2b, 0x00 }, - { 0x2c, 0x88 }, - { 0x2d, 0x91 }, - { 0x2e, 0x80 }, - { 0x2f, 0x44 }, - { 0x60, 0x27 }, - { 0x61, 0x02 }, - { 0x62, 0x5f }, - { 0x63, 0xd5 }, - { 0x64, 0x57 }, - { 0x65, 0x83 }, - { 0x66, 0x55 }, - { 0x67, 0x92 }, - { 0x68, 0xcf }, - { 0x69, 0x76 }, - { 0x6a, 0x22 }, - { 0x6b, 0x00 }, - { 0x6c, 0x02 }, - { 0x6d, 0x44 }, - { 0x6e, 0x80 }, - { 0x6f, 0x1d }, - { 0x70, 0x8b }, - { 0x71, 0x00 }, - { 0x72, 0x14 }, - { 0x73, 0x54 }, - { 0x74, 0x00 }, - { 0x75, 0x8e }, - { 0x76, 0x00 }, - { 0x77, 0xff }, - { 0x78, 0x80 }, - { 0x79, 0x80 }, - { 0x7a, 0x80 }, - { 0x7b, 0xe2 }, - { 0x7c, 0x00 }, -}; - -/* 7640 and 7648. The defaults should be OK for most registers. */ -static const struct ov_i2c_regvals norm_7640[] = { - { 0x12, 0x80 }, - { 0x12, 0x14 }, -}; - -static const struct ov_regvals init_519_ov7660[] = { - { 0x5d, 0x03 }, /* Turn off suspend mode */ - { 0x53, 0x9b }, /* 0x9f enables the (unused) microcontroller */ - { 0x54, 0x0f }, /* bit2 (jpeg enable) */ - { 0xa2, 0x20 }, /* a2-a5 are undocumented */ - { 0xa3, 0x18 }, - { 0xa4, 0x04 }, - { 0xa5, 0x28 }, - { 0x37, 0x00 }, /* SetUsbInit */ - { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ - /* Enable both fields, YUV Input, disable defect comp (why?) */ - { 0x20, 0x0c }, /* 0x0d does U <-> V swap */ - { 0x21, 0x38 }, - { 0x22, 0x1d }, - { 0x17, 0x50 }, /* undocumented */ - { 0x37, 0x00 }, /* undocumented */ - { 0x40, 0xff }, /* I2C timeout counter */ - { 0x46, 0x00 }, /* I2C clock prescaler */ -}; -static const struct ov_i2c_regvals norm_7660[] = { - {OV7670_R12_COM7, OV7670_COM7_RESET}, - {OV7670_R11_CLKRC, 0x81}, - {0x92, 0x00}, /* DM_LNL */ - {0x93, 0x00}, /* DM_LNH */ - {0x9d, 0x4c}, /* BD50ST */ - {0x9e, 0x3f}, /* BD60ST */ - {OV7670_R3B_COM11, 0x02}, - {OV7670_R13_COM8, 0xf5}, - {OV7670_R10_AECH, 0x00}, - {OV7670_R00_GAIN, 0x00}, - {OV7670_R01_BLUE, 0x7c}, - {OV7670_R02_RED, 0x9d}, - {OV7670_R12_COM7, 0x00}, - {OV7670_R04_COM1, 00}, - {OV7670_R18_HSTOP, 0x01}, - {OV7670_R17_HSTART, 0x13}, - {OV7670_R32_HREF, 0x92}, - {OV7670_R19_VSTART, 0x02}, - {OV7670_R1A_VSTOP, 0x7a}, - {OV7670_R03_VREF, 0x00}, - {OV7670_R0E_COM5, 0x04}, - {OV7670_R0F_COM6, 0x62}, - {OV7670_R15_COM10, 0x00}, - {0x16, 0x02}, /* RSVD */ - {0x1b, 0x00}, /* PSHFT */ - {OV7670_R1E_MVFP, 0x01}, - {0x29, 0x3c}, /* RSVD */ - {0x33, 0x00}, /* CHLF */ - {0x34, 0x07}, /* ARBLM */ - {0x35, 0x84}, /* RSVD */ - {0x36, 0x00}, /* RSVD */ - {0x37, 0x04}, /* ADC */ - {0x39, 0x43}, /* OFON */ - {OV7670_R3A_TSLB, 0x00}, - {OV7670_R3C_COM12, 0x6c}, - {OV7670_R3D_COM13, 0x98}, - {OV7670_R3F_EDGE, 0x23}, - {OV7670_R40_COM15, 0xc1}, - {OV7670_R41_COM16, 0x22}, - {0x6b, 0x0a}, /* DBLV */ - {0xa1, 0x08}, /* RSVD */ - {0x69, 0x80}, /* HV */ - {0x43, 0xf0}, /* RSVD.. */ - {0x44, 0x10}, - {0x45, 0x78}, - {0x46, 0xa8}, - {0x47, 0x60}, - {0x48, 0x80}, - {0x59, 0xba}, - {0x5a, 0x9a}, - {0x5b, 0x22}, - {0x5c, 0xb9}, - {0x5d, 0x9b}, - {0x5e, 0x10}, - {0x5f, 0xe0}, - {0x60, 0x85}, - {0x61, 0x60}, - {0x9f, 0x9d}, /* RSVD */ - {0xa0, 0xa0}, /* DSPC2 */ - {0x4f, 0x60}, /* matrix */ - {0x50, 0x64}, - {0x51, 0x04}, - {0x52, 0x18}, - {0x53, 0x3c}, - {0x54, 0x54}, - {0x55, 0x40}, - {0x56, 0x40}, - {0x57, 0x40}, - {0x58, 0x0d}, /* matrix sign */ - {0x8b, 0xcc}, /* RSVD */ - {0x8c, 0xcc}, - {0x8d, 0xcf}, - {0x6c, 0x40}, /* gamma curve */ - {0x6d, 0xe0}, - {0x6e, 0xa0}, - {0x6f, 0x80}, - {0x70, 0x70}, - {0x71, 0x80}, - {0x72, 0x60}, - {0x73, 0x60}, - {0x74, 0x50}, - {0x75, 0x40}, - {0x76, 0x38}, - {0x77, 0x3c}, - {0x78, 0x32}, - {0x79, 0x1a}, - {0x7a, 0x28}, - {0x7b, 0x24}, - {0x7c, 0x04}, /* gamma curve */ - {0x7d, 0x12}, - {0x7e, 0x26}, - {0x7f, 0x46}, - {0x80, 0x54}, - {0x81, 0x64}, - {0x82, 0x70}, - {0x83, 0x7c}, - {0x84, 0x86}, - {0x85, 0x8e}, - {0x86, 0x9c}, - {0x87, 0xab}, - {0x88, 0xc4}, - {0x89, 0xd1}, - {0x8a, 0xe5}, - {OV7670_R14_COM9, 0x1e}, - {OV7670_R24_AEW, 0x80}, - {OV7670_R25_AEB, 0x72}, - {OV7670_R26_VPT, 0xb3}, - {0x62, 0x80}, /* LCC1 */ - {0x63, 0x80}, /* LCC2 */ - {0x64, 0x06}, /* LCC3 */ - {0x65, 0x00}, /* LCC4 */ - {0x66, 0x01}, /* LCC5 */ - {0x94, 0x0e}, /* RSVD.. */ - {0x95, 0x14}, - {OV7670_R13_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT - | 0x10 - | OV7670_COM8_AGC - | OV7670_COM8_AWB - | OV7670_COM8_AEC}, - {0xa1, 0xc8} -}; - -/* 7670. Defaults taken from OmniVision provided data, -* as provided by Jonathan Corbet of OLPC */ -static const struct ov_i2c_regvals norm_7670[] = { - { OV7670_R12_COM7, OV7670_COM7_RESET }, - { OV7670_R3A_TSLB, 0x04 }, /* OV */ - { OV7670_R12_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ - { OV7670_R11_CLKRC, 0x01 }, -/* - * Set the hardware window. These values from OV don't entirely - * make sense - hstop is less than hstart. But they work... - */ - { OV7670_R17_HSTART, 0x13 }, - { OV7670_R18_HSTOP, 0x01 }, - { OV7670_R32_HREF, 0xb6 }, - { OV7670_R19_VSTART, 0x02 }, - { OV7670_R1A_VSTOP, 0x7a }, - { OV7670_R03_VREF, 0x0a }, - - { OV7670_R0C_COM3, 0x00 }, - { OV7670_R3E_COM14, 0x00 }, -/* Mystery scaling numbers */ - { 0x70, 0x3a }, - { 0x71, 0x35 }, - { 0x72, 0x11 }, - { 0x73, 0xf0 }, - { 0xa2, 0x02 }, -/* { OV7670_R15_COM10, 0x0 }, */ - -/* Gamma curve values */ - { 0x7a, 0x20 }, - { 0x7b, 0x10 }, - { 0x7c, 0x1e }, - { 0x7d, 0x35 }, - { 0x7e, 0x5a }, - { 0x7f, 0x69 }, - { 0x80, 0x76 }, - { 0x81, 0x80 }, - { 0x82, 0x88 }, - { 0x83, 0x8f }, - { 0x84, 0x96 }, - { 0x85, 0xa3 }, - { 0x86, 0xaf }, - { 0x87, 0xc4 }, - { 0x88, 0xd7 }, - { 0x89, 0xe8 }, - -/* AGC and AEC parameters. Note we start by disabling those features, - then turn them only after tweaking the values. */ - { OV7670_R13_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT }, - { OV7670_R00_GAIN, 0x00 }, - { OV7670_R10_AECH, 0x00 }, - { OV7670_R0D_COM4, 0x40 }, /* magic reserved bit */ - { OV7670_R14_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ - { OV7670_RA5_BD50MAX, 0x05 }, - { OV7670_RAB_BD60MAX, 0x07 }, - { OV7670_R24_AEW, 0x95 }, - { OV7670_R25_AEB, 0x33 }, - { OV7670_R26_VPT, 0xe3 }, - { OV7670_R9F_HAECC1, 0x78 }, - { OV7670_RA0_HAECC2, 0x68 }, - { 0xa1, 0x03 }, /* magic */ - { OV7670_RA6_HAECC3, 0xd8 }, - { OV7670_RA7_HAECC4, 0xd8 }, - { OV7670_RA8_HAECC5, 0xf0 }, - { OV7670_RA9_HAECC6, 0x90 }, - { OV7670_RAA_HAECC7, 0x94 }, - { OV7670_R13_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT - | OV7670_COM8_AGC - | OV7670_COM8_AEC }, - -/* Almost all of these are magic "reserved" values. */ - { OV7670_R0E_COM5, 0x61 }, - { OV7670_R0F_COM6, 0x4b }, - { 0x16, 0x02 }, - { OV7670_R1E_MVFP, 0x07 }, - { 0x21, 0x02 }, - { 0x22, 0x91 }, - { 0x29, 0x07 }, - { 0x33, 0x0b }, - { 0x35, 0x0b }, - { 0x37, 0x1d }, - { 0x38, 0x71 }, - { 0x39, 0x2a }, - { OV7670_R3C_COM12, 0x78 }, - { 0x4d, 0x40 }, - { 0x4e, 0x20 }, - { OV7670_R69_GFIX, 0x00 }, - { 0x6b, 0x4a }, - { 0x74, 0x10 }, - { 0x8d, 0x4f }, - { 0x8e, 0x00 }, - { 0x8f, 0x00 }, - { 0x90, 0x00 }, - { 0x91, 0x00 }, - { 0x96, 0x00 }, - { 0x9a, 0x00 }, - { 0xb0, 0x84 }, - { 0xb1, 0x0c }, - { 0xb2, 0x0e }, - { 0xb3, 0x82 }, - { 0xb8, 0x0a }, - -/* More reserved magic, some of which tweaks white balance */ - { 0x43, 0x0a }, - { 0x44, 0xf0 }, - { 0x45, 0x34 }, - { 0x46, 0x58 }, - { 0x47, 0x28 }, - { 0x48, 0x3a }, - { 0x59, 0x88 }, - { 0x5a, 0x88 }, - { 0x5b, 0x44 }, - { 0x5c, 0x67 }, - { 0x5d, 0x49 }, - { 0x5e, 0x0e }, - { 0x6c, 0x0a }, - { 0x6d, 0x55 }, - { 0x6e, 0x11 }, - { 0x6f, 0x9f }, /* "9e for advance AWB" */ - { 0x6a, 0x40 }, - { OV7670_R01_BLUE, 0x40 }, - { OV7670_R02_RED, 0x60 }, - { OV7670_R13_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT - | OV7670_COM8_AGC - | OV7670_COM8_AEC - | OV7670_COM8_AWB }, - -/* Matrix coefficients */ - { 0x4f, 0x80 }, - { 0x50, 0x80 }, - { 0x51, 0x00 }, - { 0x52, 0x22 }, - { 0x53, 0x5e }, - { 0x54, 0x80 }, - { 0x58, 0x9e }, - - { OV7670_R41_COM16, OV7670_COM16_AWBGAIN }, - { OV7670_R3F_EDGE, 0x00 }, - { 0x75, 0x05 }, - { 0x76, 0xe1 }, - { 0x4c, 0x00 }, - { 0x77, 0x01 }, - { OV7670_R3D_COM13, OV7670_COM13_GAMMA - | OV7670_COM13_UVSAT - | 2}, /* was 3 */ - { 0x4b, 0x09 }, - { 0xc9, 0x60 }, - { OV7670_R41_COM16, 0x38 }, - { 0x56, 0x40 }, - - { 0x34, 0x11 }, - { OV7670_R3B_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, - { 0xa4, 0x88 }, - { 0x96, 0x00 }, - { 0x97, 0x30 }, - { 0x98, 0x20 }, - { 0x99, 0x30 }, - { 0x9a, 0x84 }, - { 0x9b, 0x29 }, - { 0x9c, 0x03 }, - { 0x9d, 0x4c }, - { 0x9e, 0x3f }, - { 0x78, 0x04 }, - -/* Extra-weird stuff. Some sort of multiplexor register */ - { 0x79, 0x01 }, - { 0xc8, 0xf0 }, - { 0x79, 0x0f }, - { 0xc8, 0x00 }, - { 0x79, 0x10 }, - { 0xc8, 0x7e }, - { 0x79, 0x0a }, - { 0xc8, 0x80 }, - { 0x79, 0x0b }, - { 0xc8, 0x01 }, - { 0x79, 0x0c }, - { 0xc8, 0x0f }, - { 0x79, 0x0d }, - { 0xc8, 0x20 }, - { 0x79, 0x09 }, - { 0xc8, 0x80 }, - { 0x79, 0x02 }, - { 0xc8, 0xc0 }, - { 0x79, 0x03 }, - { 0xc8, 0x40 }, - { 0x79, 0x05 }, - { 0xc8, 0x30 }, - { 0x79, 0x26 }, -}; - -static const struct ov_i2c_regvals norm_8610[] = { - { 0x12, 0x80 }, - { 0x00, 0x00 }, - { 0x01, 0x80 }, - { 0x02, 0x80 }, - { 0x03, 0xc0 }, - { 0x04, 0x30 }, - { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ - { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ - { 0x0a, 0x86 }, - { 0x0b, 0xb0 }, - { 0x0c, 0x20 }, - { 0x0d, 0x20 }, - { 0x11, 0x01 }, - { 0x12, 0x25 }, - { 0x13, 0x01 }, - { 0x14, 0x04 }, - { 0x15, 0x01 }, /* Lin and Win think different about UV order */ - { 0x16, 0x03 }, - { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ - { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ - { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ - { 0x1a, 0xf5 }, - { 0x1b, 0x00 }, - { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ - { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ - { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ - { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ - { 0x26, 0xa2 }, - { 0x27, 0xea }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x80 }, - { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ - { 0x2c, 0xac }, - { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ - { 0x2e, 0x80 }, - { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ - { 0x4c, 0x00 }, - { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ - { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ - { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ - { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ - { 0x63, 0xff }, - { 0x64, 0x53 }, /* new windrv 090403 says 0x57, - * maybe thats wrong */ - { 0x65, 0x00 }, - { 0x66, 0x55 }, - { 0x67, 0xb0 }, - { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ - { 0x69, 0x02 }, - { 0x6a, 0x22 }, - { 0x6b, 0x00 }, - { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but - * deleting bit7 colors the first images red */ - { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ - { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ - { 0x6f, 0x01 }, - { 0x70, 0x8b }, - { 0x71, 0x00 }, - { 0x72, 0x14 }, - { 0x73, 0x54 }, - { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */ - { 0x75, 0x0e }, - { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ - { 0x77, 0xff }, - { 0x78, 0x80 }, - { 0x79, 0x80 }, - { 0x7a, 0x80 }, - { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ - { 0x7c, 0x00 }, - { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ - { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ - { 0x7f, 0xfb }, - { 0x80, 0x28 }, - { 0x81, 0x00 }, - { 0x82, 0x23 }, - { 0x83, 0x0b }, - { 0x84, 0x00 }, - { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ - { 0x86, 0xc9 }, - { 0x87, 0x00 }, - { 0x88, 0x00 }, - { 0x89, 0x01 }, - { 0x12, 0x20 }, - { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ -}; - -static unsigned char ov7670_abs_to_sm(unsigned char v) -{ - if (v > 127) - return v & 0x7f; - return (128 - v) | 0x80; -} - -/* Write a OV519 register */ -static void reg_w(struct sd *sd, u16 index, u16 value) -{ - int ret, req = 0; - - if (sd->gspca_dev.usb_err < 0) - return; - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - req = 2; - break; - case BRIDGE_OVFX2: - req = 0x0a; - /* fall through */ - case BRIDGE_W9968CF: - PDEBUG(D_USBO, "SET %02x %04x %04x", - req, value, index); - ret = usb_control_msg(sd->gspca_dev.dev, - usb_sndctrlpipe(sd->gspca_dev.dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 500); - goto leave; - default: - req = 1; - } - - PDEBUG(D_USBO, "SET %02x 0000 %04x %02x", - req, index, value); - sd->gspca_dev.usb_buf[0] = value; - ret = usb_control_msg(sd->gspca_dev.dev, - usb_sndctrlpipe(sd->gspca_dev.dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, - sd->gspca_dev.usb_buf, 1, 500); -leave: - if (ret < 0) { - err("reg_w %02x failed %d", index, ret); - sd->gspca_dev.usb_err = ret; - return; - } -} - -/* Read from a OV519 register, note not valid for the w9968cf!! */ -/* returns: negative is error, pos or zero is data */ -static int reg_r(struct sd *sd, u16 index) -{ - int ret; - int req; - - if (sd->gspca_dev.usb_err < 0) - return -1; - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - req = 3; - break; - case BRIDGE_OVFX2: - req = 0x0b; - break; - default: - req = 1; - } - - ret = usb_control_msg(sd->gspca_dev.dev, - usb_rcvctrlpipe(sd->gspca_dev.dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, sd->gspca_dev.usb_buf, 1, 500); - - if (ret >= 0) { - ret = sd->gspca_dev.usb_buf[0]; - PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", - req, index, ret); - } else { - err("reg_r %02x failed %d", index, ret); - sd->gspca_dev.usb_err = ret; - } - - return ret; -} - -/* Read 8 values from a OV519 register */ -static int reg_r8(struct sd *sd, - u16 index) -{ - int ret; - - if (sd->gspca_dev.usb_err < 0) - return -1; - - ret = usb_control_msg(sd->gspca_dev.dev, - usb_rcvctrlpipe(sd->gspca_dev.dev, 0), - 1, /* REQ_IO */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, sd->gspca_dev.usb_buf, 8, 500); - - if (ret >= 0) { - ret = sd->gspca_dev.usb_buf[0]; - } else { - err("reg_r8 %02x failed %d", index, ret); - sd->gspca_dev.usb_err = ret; - } - - return ret; -} - -/* - * Writes bits at positions specified by mask to an OV51x reg. Bits that are in - * the same position as 1's in "mask" are cleared and set to "value". Bits - * that are in the same position as 0's in "mask" are preserved, regardless - * of their respective state in "value". - */ -static void reg_w_mask(struct sd *sd, - u16 index, - u8 value, - u8 mask) -{ - int ret; - u8 oldval; - - if (mask != 0xff) { - value &= mask; /* Enforce mask on value */ - ret = reg_r(sd, index); - if (ret < 0) - return; - - oldval = ret & ~mask; /* Clear the masked bits */ - value |= oldval; /* Set the desired bits */ - } - reg_w(sd, index, value); -} - -/* - * Writes multiple (n) byte value to a single register. Only valid with certain - * registers (0x30 and 0xc4 - 0xce). - */ -static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n) -{ - int ret; - - if (sd->gspca_dev.usb_err < 0) - return; - - *((__le32 *) sd->gspca_dev.usb_buf) = __cpu_to_le32(value); - - ret = usb_control_msg(sd->gspca_dev.dev, - usb_sndctrlpipe(sd->gspca_dev.dev, 0), - 1 /* REG_IO */, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, - sd->gspca_dev.usb_buf, n, 500); - if (ret < 0) { - err("reg_w32 %02x failed %d", index, ret); - sd->gspca_dev.usb_err = ret; - } -} - -static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value) -{ - int rc, retries; - - PDEBUG(D_USBO, "ov511_i2c_w %02x %02x", reg, value); - - /* Three byte write cycle */ - for (retries = 6; ; ) { - /* Select camera register */ - reg_w(sd, R51x_I2C_SADDR_3, reg); - - /* Write "value" to I2C data port of OV511 */ - reg_w(sd, R51x_I2C_DATA, value); - - /* Initiate 3-byte write cycle */ - reg_w(sd, R511_I2C_CTL, 0x01); - - do { - rc = reg_r(sd, R511_I2C_CTL); - } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ - - if (rc < 0) - return; - - if ((rc & 2) == 0) /* Ack? */ - break; - if (--retries < 0) { - PDEBUG(D_USBO, "i2c write retries exhausted"); - return; - } - } -} - -static int ov511_i2c_r(struct sd *sd, u8 reg) -{ - int rc, value, retries; - - /* Two byte write cycle */ - for (retries = 6; ; ) { - /* Select camera register */ - reg_w(sd, R51x_I2C_SADDR_2, reg); - - /* Initiate 2-byte write cycle */ - reg_w(sd, R511_I2C_CTL, 0x03); - - do { - rc = reg_r(sd, R511_I2C_CTL); - } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ - - if (rc < 0) - return rc; - - if ((rc & 2) == 0) /* Ack? */ - break; - - /* I2C abort */ - reg_w(sd, R511_I2C_CTL, 0x10); - - if (--retries < 0) { - PDEBUG(D_USBI, "i2c write retries exhausted"); - return -1; - } - } - - /* Two byte read cycle */ - for (retries = 6; ; ) { - /* Initiate 2-byte read cycle */ - reg_w(sd, R511_I2C_CTL, 0x05); - - do { - rc = reg_r(sd, R511_I2C_CTL); - } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ - - if (rc < 0) - return rc; - - if ((rc & 2) == 0) /* Ack? */ - break; - - /* I2C abort */ - reg_w(sd, R511_I2C_CTL, 0x10); - - if (--retries < 0) { - PDEBUG(D_USBI, "i2c read retries exhausted"); - return -1; - } - } - - value = reg_r(sd, R51x_I2C_DATA); - - PDEBUG(D_USBI, "ov511_i2c_r %02x %02x", reg, value); - - /* This is needed to make i2c_w() work */ - reg_w(sd, R511_I2C_CTL, 0x05); - - return value; -} - -/* - * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from i2c_w(). Note that this function - * always succeeds regardless of whether the sensor is present and working. - */ -static void ov518_i2c_w(struct sd *sd, - u8 reg, - u8 value) -{ - PDEBUG(D_USBO, "ov518_i2c_w %02x %02x", reg, value); - - /* Select camera register */ - reg_w(sd, R51x_I2C_SADDR_3, reg); - - /* Write "value" to I2C data port of OV511 */ - reg_w(sd, R51x_I2C_DATA, value); - - /* Initiate 3-byte write cycle */ - reg_w(sd, R518_I2C_CTL, 0x01); - - /* wait for write complete */ - msleep(4); - reg_r8(sd, R518_I2C_CTL); -} - -/* - * returns: negative is error, pos or zero is data - * - * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from i2c_r(). Note that this function - * always succeeds regardless of whether the sensor is present and working. - */ -static int ov518_i2c_r(struct sd *sd, u8 reg) -{ - int value; - - /* Select camera register */ - reg_w(sd, R51x_I2C_SADDR_2, reg); - - /* Initiate 2-byte write cycle */ - reg_w(sd, R518_I2C_CTL, 0x03); - - /* Initiate 2-byte read cycle */ - reg_w(sd, R518_I2C_CTL, 0x05); - value = reg_r(sd, R51x_I2C_DATA); - PDEBUG(D_USBI, "ov518_i2c_r %02x %02x", reg, value); - return value; -} - -static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value) -{ - int ret; - - if (sd->gspca_dev.usb_err < 0) - return; - - ret = usb_control_msg(sd->gspca_dev.dev, - usb_sndctrlpipe(sd->gspca_dev.dev, 0), - 0x02, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - (u16) value, (u16) reg, NULL, 0, 500); - - if (ret < 0) { - err("ovfx2_i2c_w %02x failed %d", reg, ret); - sd->gspca_dev.usb_err = ret; - } - - PDEBUG(D_USBO, "ovfx2_i2c_w %02x %02x", reg, value); -} - -static int ovfx2_i2c_r(struct sd *sd, u8 reg) -{ - int ret; - - if (sd->gspca_dev.usb_err < 0) - return -1; - - ret = usb_control_msg(sd->gspca_dev.dev, - usb_rcvctrlpipe(sd->gspca_dev.dev, 0), - 0x03, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, (u16) reg, sd->gspca_dev.usb_buf, 1, 500); - - if (ret >= 0) { - ret = sd->gspca_dev.usb_buf[0]; - PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret); - } else { - err("ovfx2_i2c_r %02x failed %d", reg, ret); - sd->gspca_dev.usb_err = ret; - } - - return ret; -} - -static void i2c_w(struct sd *sd, u8 reg, u8 value) -{ - if (sd->sensor_reg_cache[reg] == value) - return; - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - ov511_i2c_w(sd, reg, value); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - case BRIDGE_OV519: - ov518_i2c_w(sd, reg, value); - break; - case BRIDGE_OVFX2: - ovfx2_i2c_w(sd, reg, value); - break; - case BRIDGE_W9968CF: - w9968cf_i2c_w(sd, reg, value); - break; - } - - if (sd->gspca_dev.usb_err >= 0) { - /* Up on sensor reset empty the register cache */ - if (reg == 0x12 && (value & 0x80)) - memset(sd->sensor_reg_cache, -1, - sizeof(sd->sensor_reg_cache)); - else - sd->sensor_reg_cache[reg] = value; - } -} - -static int i2c_r(struct sd *sd, u8 reg) -{ - int ret = -1; - - if (sd->sensor_reg_cache[reg] != -1) - return sd->sensor_reg_cache[reg]; - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - ret = ov511_i2c_r(sd, reg); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - case BRIDGE_OV519: - ret = ov518_i2c_r(sd, reg); - break; - case BRIDGE_OVFX2: - ret = ovfx2_i2c_r(sd, reg); - break; - case BRIDGE_W9968CF: - ret = w9968cf_i2c_r(sd, reg); - break; - } - - if (ret >= 0) - sd->sensor_reg_cache[reg] = ret; - - return ret; -} - -/* Writes bits at positions specified by mask to an I2C reg. Bits that are in - * the same position as 1's in "mask" are cleared and set to "value". Bits - * that are in the same position as 0's in "mask" are preserved, regardless - * of their respective state in "value". - */ -static void i2c_w_mask(struct sd *sd, - u8 reg, - u8 value, - u8 mask) -{ - int rc; - u8 oldval; - - value &= mask; /* Enforce mask on value */ - rc = i2c_r(sd, reg); - if (rc < 0) - return; - oldval = rc & ~mask; /* Clear the masked bits */ - value |= oldval; /* Set the desired bits */ - i2c_w(sd, reg, value); -} - -/* Temporarily stops OV511 from functioning. Must do this before changing - * registers while the camera is streaming */ -static inline void ov51x_stop(struct sd *sd) -{ - PDEBUG(D_STREAM, "stopping"); - sd->stopped = 1; - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - reg_w(sd, R51x_SYS_RESET, 0x3d); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a); - break; - case BRIDGE_OV519: - reg_w(sd, OV519_R51_RESET1, 0x0f); - reg_w(sd, OV519_R51_RESET1, 0x00); - reg_w(sd, 0x22, 0x00); /* FRAR */ - break; - case BRIDGE_OVFX2: - reg_w_mask(sd, 0x0f, 0x00, 0x02); - break; - case BRIDGE_W9968CF: - reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */ - break; - } -} - -/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not - * actually stopped (for performance). */ -static inline void ov51x_restart(struct sd *sd) -{ - PDEBUG(D_STREAM, "restarting"); - if (!sd->stopped) - return; - sd->stopped = 0; - - /* Reinitialize the stream */ - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - reg_w(sd, R51x_SYS_RESET, 0x00); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - reg_w(sd, 0x2f, 0x80); - reg_w(sd, R51x_SYS_RESET, 0x00); - break; - case BRIDGE_OV519: - reg_w(sd, OV519_R51_RESET1, 0x0f); - reg_w(sd, OV519_R51_RESET1, 0x00); - reg_w(sd, 0x22, 0x1d); /* FRAR */ - break; - case BRIDGE_OVFX2: - reg_w_mask(sd, 0x0f, 0x02, 0x02); - break; - case BRIDGE_W9968CF: - reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */ - break; - } -} - -static void ov51x_set_slave_ids(struct sd *sd, u8 slave); - -/* This does an initial reset of an OmniVision sensor and ensures that I2C - * is synchronized. Returns <0 on failure. - */ -static int init_ov_sensor(struct sd *sd, u8 slave) -{ - int i; - - ov51x_set_slave_ids(sd, slave); - - /* Reset the sensor */ - i2c_w(sd, 0x12, 0x80); - - /* Wait for it to initialize */ - msleep(150); - - for (i = 0; i < i2c_detect_tries; i++) { - if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f && - i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) { - PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i); - return 0; - } - - /* Reset the sensor */ - i2c_w(sd, 0x12, 0x80); - - /* Wait for it to initialize */ - msleep(150); - - /* Dummy read to sync I2C */ - if (i2c_r(sd, 0x00) < 0) - return -1; - } - return -1; -} - -/* Set the read and write slave IDs. The "slave" argument is the write slave, - * and the read slave will be set to (slave + 1). - * This should not be called from outside the i2c I/O functions. - * Sets I2C read and write slave IDs. Returns <0 for error - */ -static void ov51x_set_slave_ids(struct sd *sd, - u8 slave) -{ - switch (sd->bridge) { - case BRIDGE_OVFX2: - reg_w(sd, OVFX2_I2C_ADDR, slave); - return; - case BRIDGE_W9968CF: - sd->sensor_addr = slave; - return; - } - - reg_w(sd, R51x_I2C_W_SID, slave); - reg_w(sd, R51x_I2C_R_SID, slave + 1); -} - -static void write_regvals(struct sd *sd, - const struct ov_regvals *regvals, - int n) -{ - while (--n >= 0) { - reg_w(sd, regvals->reg, regvals->val); - regvals++; - } -} - -static void write_i2c_regvals(struct sd *sd, - const struct ov_i2c_regvals *regvals, - int n) -{ - while (--n >= 0) { - i2c_w(sd, regvals->reg, regvals->val); - regvals++; - } -} - -/**************************************************************************** - * - * OV511 and sensor configuration - * - ***************************************************************************/ - -/* This initializes the OV2x10 / OV3610 / OV3620 */ -static void ov_hires_configure(struct sd *sd) -{ - int high, low; - - if (sd->bridge != BRIDGE_OVFX2) { - err("error hires sensors only supported with ovfx2"); - return; - } - - PDEBUG(D_PROBE, "starting ov hires configuration"); - - /* Detect sensor (sub)type */ - high = i2c_r(sd, 0x0a); - low = i2c_r(sd, 0x0b); - /* info("%x, %x", high, low); */ - if (high == 0x96 && low == 0x40) { - PDEBUG(D_PROBE, "Sensor is an OV2610"); - sd->sensor = SEN_OV2610; - } else if (high == 0x96 && low == 0x41) { - PDEBUG(D_PROBE, "Sensor is an OV2610AE"); - sd->sensor = SEN_OV2610AE; - } else if (high == 0x36 && (low & 0x0f) == 0x00) { - PDEBUG(D_PROBE, "Sensor is an OV3610"); - sd->sensor = SEN_OV3610; - } else { - err("Error unknown sensor type: %02x%02x", - high, low); - } -} - -/* This initializes the OV8110, OV8610 sensor. The OV8110 uses - * the same register settings as the OV8610, since they are very similar. - */ -static void ov8xx0_configure(struct sd *sd) -{ - int rc; - - PDEBUG(D_PROBE, "starting ov8xx0 configuration"); - - /* Detect sensor (sub)type */ - rc = i2c_r(sd, OV7610_REG_COM_I); - if (rc < 0) { - PDEBUG(D_ERR, "Error detecting sensor type"); - return; - } - if ((rc & 3) == 1) - sd->sensor = SEN_OV8610; - else - err("Unknown image sensor version: %d", rc & 3); -} - -/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses - * the same register settings as the OV7610, since they are very similar. - */ -static void ov7xx0_configure(struct sd *sd) -{ - int rc, high, low; - - PDEBUG(D_PROBE, "starting OV7xx0 configuration"); - - /* Detect sensor (sub)type */ - rc = i2c_r(sd, OV7610_REG_COM_I); - - /* add OV7670 here - * it appears to be wrongly detected as a 7610 by default */ - if (rc < 0) { - PDEBUG(D_ERR, "Error detecting sensor type"); - return; - } - if ((rc & 3) == 3) { - /* quick hack to make OV7670s work */ - high = i2c_r(sd, 0x0a); - low = i2c_r(sd, 0x0b); - /* info("%x, %x", high, low); */ - if (high == 0x76 && (low & 0xf0) == 0x70) { - PDEBUG(D_PROBE, "Sensor is an OV76%02x", low); - sd->sensor = SEN_OV7670; - } else { - PDEBUG(D_PROBE, "Sensor is an OV7610"); - sd->sensor = SEN_OV7610; - } - } else if ((rc & 3) == 1) { - /* I don't know what's different about the 76BE yet. */ - if (i2c_r(sd, 0x15) & 1) { - PDEBUG(D_PROBE, "Sensor is an OV7620AE"); - sd->sensor = SEN_OV7620AE; - } else { - PDEBUG(D_PROBE, "Sensor is an OV76BE"); - sd->sensor = SEN_OV76BE; - } - } else if ((rc & 3) == 0) { - /* try to read product id registers */ - high = i2c_r(sd, 0x0a); - if (high < 0) { - PDEBUG(D_ERR, "Error detecting camera chip PID"); - return; - } - low = i2c_r(sd, 0x0b); - if (low < 0) { - PDEBUG(D_ERR, "Error detecting camera chip VER"); - return; - } - if (high == 0x76) { - switch (low) { - case 0x30: - err("Sensor is an OV7630/OV7635"); - err("7630 is not supported by this driver"); - return; - case 0x40: - PDEBUG(D_PROBE, "Sensor is an OV7645"); - sd->sensor = SEN_OV7640; /* FIXME */ - break; - case 0x45: - PDEBUG(D_PROBE, "Sensor is an OV7645B"); - sd->sensor = SEN_OV7640; /* FIXME */ - break; - case 0x48: - PDEBUG(D_PROBE, "Sensor is an OV7648"); - sd->sensor = SEN_OV7648; - break; - case 0x60: - PDEBUG(D_PROBE, "Sensor is a OV7660"); - sd->sensor = SEN_OV7660; - sd->invert_led = 0; - break; - default: - PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); - return; - } - } else { - PDEBUG(D_PROBE, "Sensor is an OV7620"); - sd->sensor = SEN_OV7620; - } - } else { - err("Unknown image sensor version: %d", rc & 3); - } -} - -/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ -static void ov6xx0_configure(struct sd *sd) -{ - int rc; - PDEBUG(D_PROBE, "starting OV6xx0 configuration"); - - /* Detect sensor (sub)type */ - rc = i2c_r(sd, OV7610_REG_COM_I); - if (rc < 0) { - PDEBUG(D_ERR, "Error detecting sensor type"); - return; - } - - /* Ugh. The first two bits are the version bits, but - * the entire register value must be used. I guess OVT - * underestimated how many variants they would make. */ - switch (rc) { - case 0x00: - sd->sensor = SEN_OV6630; - warn("WARNING: Sensor is an OV66308. Your camera may have"); - warn("been misdetected in previous driver versions."); - break; - case 0x01: - sd->sensor = SEN_OV6620; - PDEBUG(D_PROBE, "Sensor is an OV6620"); - break; - case 0x02: - sd->sensor = SEN_OV6630; - PDEBUG(D_PROBE, "Sensor is an OV66308AE"); - break; - case 0x03: - sd->sensor = SEN_OV66308AF; - PDEBUG(D_PROBE, "Sensor is an OV66308AF"); - break; - case 0x90: - sd->sensor = SEN_OV6630; - warn("WARNING: Sensor is an OV66307. Your camera may have"); - warn("been misdetected in previous driver versions."); - break; - default: - err("FATAL: Unknown sensor version: 0x%02x", rc); - return; - } - - /* Set sensor-specific vars */ - sd->sif = 1; -} - -/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ -static void ov51x_led_control(struct sd *sd, int on) -{ - if (sd->invert_led) - on = !on; - - switch (sd->bridge) { - /* OV511 has no LED control */ - case BRIDGE_OV511PLUS: - reg_w(sd, R511_SYS_LED_CTL, on); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - reg_w_mask(sd, R518_GPIO_OUT, 0x02 * on, 0x02); - break; - case BRIDGE_OV519: - reg_w_mask(sd, OV519_GPIO_DATA_OUT0, on, 1); - break; - } -} - -static void sd_reset_snapshot(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (!sd->snapshot_needs_reset) - return; - - /* Note it is important that we clear sd->snapshot_needs_reset, - before actually clearing the snapshot state in the bridge - otherwise we might race with the pkt_scan interrupt handler */ - sd->snapshot_needs_reset = 0; - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - reg_w(sd, R51x_SYS_SNAP, 0x02); - reg_w(sd, R51x_SYS_SNAP, 0x00); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - reg_w(sd, R51x_SYS_SNAP, 0x02); /* Reset */ - reg_w(sd, R51x_SYS_SNAP, 0x01); /* Enable */ - break; - case BRIDGE_OV519: - reg_w(sd, R51x_SYS_RESET, 0x40); - reg_w(sd, R51x_SYS_RESET, 0x00); - break; - } -} - -static void ov51x_upload_quan_tables(struct sd *sd) -{ - const unsigned char yQuanTable511[] = { - 0, 1, 1, 2, 2, 3, 3, 4, - 1, 1, 1, 2, 2, 3, 4, 4, - 1, 1, 2, 2, 3, 4, 4, 4, - 2, 2, 2, 3, 4, 4, 4, 4, - 2, 2, 3, 4, 4, 5, 5, 5, - 3, 3, 4, 4, 5, 5, 5, 5, - 3, 4, 4, 4, 5, 5, 5, 5, - 4, 4, 4, 4, 5, 5, 5, 5 - }; - - const unsigned char uvQuanTable511[] = { - 0, 2, 2, 3, 4, 4, 4, 4, - 2, 2, 2, 4, 4, 4, 4, 4, - 2, 2, 3, 4, 4, 4, 4, 4, - 3, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4 - }; - - /* OV518 quantization tables are 8x4 (instead of 8x8) */ - const unsigned char yQuanTable518[] = { - 5, 4, 5, 6, 6, 7, 7, 7, - 5, 5, 5, 5, 6, 7, 7, 7, - 6, 6, 6, 6, 7, 7, 7, 8, - 7, 7, 6, 7, 7, 7, 8, 8 - }; - const unsigned char uvQuanTable518[] = { - 6, 6, 6, 7, 7, 7, 7, 7, - 6, 6, 6, 7, 7, 7, 7, 7, - 6, 6, 6, 7, 7, 7, 7, 8, - 7, 7, 7, 7, 7, 7, 8, 8 - }; - - const unsigned char *pYTable, *pUVTable; - unsigned char val0, val1; - int i, size, reg = R51x_COMP_LUT_BEGIN; - - PDEBUG(D_PROBE, "Uploading quantization tables"); - - if (sd->bridge == BRIDGE_OV511 || sd->bridge == BRIDGE_OV511PLUS) { - pYTable = yQuanTable511; - pUVTable = uvQuanTable511; - size = 32; - } else { - pYTable = yQuanTable518; - pUVTable = uvQuanTable518; - size = 16; - } - - for (i = 0; i < size; i++) { - val0 = *pYTable++; - val1 = *pYTable++; - val0 &= 0x0f; - val1 &= 0x0f; - val0 |= val1 << 4; - reg_w(sd, reg, val0); - - val0 = *pUVTable++; - val1 = *pUVTable++; - val0 &= 0x0f; - val1 &= 0x0f; - val0 |= val1 << 4; - reg_w(sd, reg + size, val0); - - reg++; - } -} - -/* This initializes the OV511/OV511+ and the sensor */ -static void ov511_configure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* For 511 and 511+ */ - const struct ov_regvals init_511[] = { - { R51x_SYS_RESET, 0x7f }, - { R51x_SYS_INIT, 0x01 }, - { R51x_SYS_RESET, 0x7f }, - { R51x_SYS_INIT, 0x01 }, - { R51x_SYS_RESET, 0x3f }, - { R51x_SYS_INIT, 0x01 }, - { R51x_SYS_RESET, 0x3d }, - }; - - const struct ov_regvals norm_511[] = { - { R511_DRAM_FLOW_CTL, 0x01 }, - { R51x_SYS_SNAP, 0x00 }, - { R51x_SYS_SNAP, 0x02 }, - { R51x_SYS_SNAP, 0x00 }, - { R511_FIFO_OPTS, 0x1f }, - { R511_COMP_EN, 0x00 }, - { R511_COMP_LUT_EN, 0x03 }, - }; - - const struct ov_regvals norm_511_p[] = { - { R511_DRAM_FLOW_CTL, 0xff }, - { R51x_SYS_SNAP, 0x00 }, - { R51x_SYS_SNAP, 0x02 }, - { R51x_SYS_SNAP, 0x00 }, - { R511_FIFO_OPTS, 0xff }, - { R511_COMP_EN, 0x00 }, - { R511_COMP_LUT_EN, 0x03 }, - }; - - const struct ov_regvals compress_511[] = { - { 0x70, 0x1f }, - { 0x71, 0x05 }, - { 0x72, 0x06 }, - { 0x73, 0x06 }, - { 0x74, 0x14 }, - { 0x75, 0x03 }, - { 0x76, 0x04 }, - { 0x77, 0x04 }, - }; - - PDEBUG(D_PROBE, "Device custom id %x", reg_r(sd, R51x_SYS_CUST_ID)); - - write_regvals(sd, init_511, ARRAY_SIZE(init_511)); - - switch (sd->bridge) { - case BRIDGE_OV511: - write_regvals(sd, norm_511, ARRAY_SIZE(norm_511)); - break; - case BRIDGE_OV511PLUS: - write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p)); - break; - } - - /* Init compression */ - write_regvals(sd, compress_511, ARRAY_SIZE(compress_511)); - - ov51x_upload_quan_tables(sd); -} - -/* This initializes the OV518/OV518+ and the sensor */ -static void ov518_configure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* For 518 and 518+ */ - const struct ov_regvals init_518[] = { - { R51x_SYS_RESET, 0x40 }, - { R51x_SYS_INIT, 0xe1 }, - { R51x_SYS_RESET, 0x3e }, - { R51x_SYS_INIT, 0xe1 }, - { R51x_SYS_RESET, 0x00 }, - { R51x_SYS_INIT, 0xe1 }, - { 0x46, 0x00 }, - { 0x5d, 0x03 }, - }; - - const struct ov_regvals norm_518[] = { - { R51x_SYS_SNAP, 0x02 }, /* Reset */ - { R51x_SYS_SNAP, 0x01 }, /* Enable */ - { 0x31, 0x0f }, - { 0x5d, 0x03 }, - { 0x24, 0x9f }, - { 0x25, 0x90 }, - { 0x20, 0x00 }, - { 0x51, 0x04 }, - { 0x71, 0x19 }, - { 0x2f, 0x80 }, - }; - - const struct ov_regvals norm_518_p[] = { - { R51x_SYS_SNAP, 0x02 }, /* Reset */ - { R51x_SYS_SNAP, 0x01 }, /* Enable */ - { 0x31, 0x0f }, - { 0x5d, 0x03 }, - { 0x24, 0x9f }, - { 0x25, 0x90 }, - { 0x20, 0x60 }, - { 0x51, 0x02 }, - { 0x71, 0x19 }, - { 0x40, 0xff }, - { 0x41, 0x42 }, - { 0x46, 0x00 }, - { 0x33, 0x04 }, - { 0x21, 0x19 }, - { 0x3f, 0x10 }, - { 0x2f, 0x80 }, - }; - - /* First 5 bits of custom ID reg are a revision ID on OV518 */ - PDEBUG(D_PROBE, "Device revision %d", - 0x1f & reg_r(sd, R51x_SYS_CUST_ID)); - - write_regvals(sd, init_518, ARRAY_SIZE(init_518)); - - /* Set LED GPIO pin to output mode */ - reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02); - - switch (sd->bridge) { - case BRIDGE_OV518: - write_regvals(sd, norm_518, ARRAY_SIZE(norm_518)); - break; - case BRIDGE_OV518PLUS: - write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p)); - break; - } - - ov51x_upload_quan_tables(sd); - - reg_w(sd, 0x2f, 0x80); -} - -static void ov519_configure(struct sd *sd) -{ - static const struct ov_regvals init_519[] = { - { 0x5a, 0x6d }, /* EnableSystem */ - { 0x53, 0x9b }, /* don't enable the microcontroller */ - { OV519_R54_EN_CLK1, 0xff }, /* set bit2 to enable jpeg */ - { 0x5d, 0x03 }, - { 0x49, 0x01 }, - { 0x48, 0x00 }, - /* Set LED pin to output mode. Bit 4 must be cleared or sensor - * detection will fail. This deserves further investigation. */ - { OV519_GPIO_IO_CTRL0, 0xee }, - { OV519_R51_RESET1, 0x0f }, - { OV519_R51_RESET1, 0x00 }, - { 0x22, 0x00 }, - /* windows reads 0x55 at this point*/ - }; - - write_regvals(sd, init_519, ARRAY_SIZE(init_519)); -} - -static void ovfx2_configure(struct sd *sd) -{ - static const struct ov_regvals init_fx2[] = { - { 0x00, 0x60 }, - { 0x02, 0x01 }, - { 0x0f, 0x1d }, - { 0xe9, 0x82 }, - { 0xea, 0xc7 }, - { 0xeb, 0x10 }, - { 0xec, 0xf6 }, - }; - - sd->stopped = 1; - - write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2)); -} - -/* set the mode */ -/* This function works for ov7660 only */ -static void ov519_set_mode(struct sd *sd) -{ - static const struct ov_regvals bridge_ov7660[2][10] = { - {{0x10, 0x14}, {0x11, 0x1e}, {0x12, 0x00}, {0x13, 0x00}, - {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c}, - {0x25, 0x01}, {0x26, 0x00}}, - {{0x10, 0x28}, {0x11, 0x3c}, {0x12, 0x00}, {0x13, 0x00}, - {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c}, - {0x25, 0x03}, {0x26, 0x00}} - }; - static const struct ov_i2c_regvals sensor_ov7660[2][3] = { - {{0x12, 0x00}, {0x24, 0x00}, {0x0c, 0x0c}}, - {{0x12, 0x00}, {0x04, 0x00}, {0x0c, 0x00}} - }; - static const struct ov_i2c_regvals sensor_ov7660_2[] = { - {OV7670_R17_HSTART, 0x13}, - {OV7670_R18_HSTOP, 0x01}, - {OV7670_R32_HREF, 0x92}, - {OV7670_R19_VSTART, 0x02}, - {OV7670_R1A_VSTOP, 0x7a}, - {OV7670_R03_VREF, 0x00}, -/* {0x33, 0x00}, */ -/* {0x34, 0x07}, */ -/* {0x36, 0x00}, */ -/* {0x6b, 0x0a}, */ - }; - - write_regvals(sd, bridge_ov7660[sd->gspca_dev.curr_mode], - ARRAY_SIZE(bridge_ov7660[0])); - write_i2c_regvals(sd, sensor_ov7660[sd->gspca_dev.curr_mode], - ARRAY_SIZE(sensor_ov7660[0])); - write_i2c_regvals(sd, sensor_ov7660_2, - ARRAY_SIZE(sensor_ov7660_2)); -} - -/* set the frame rate */ -/* This function works for sensors ov7640, ov7648 ov7660 and ov7670 only */ -static void ov519_set_fr(struct sd *sd) -{ - int fr; - u8 clock; - /* frame rate table with indices: - * - mode = 0: 320x240, 1: 640x480 - * - fr rate = 0: 30, 1: 25, 2: 20, 3: 15, 4: 10, 5: 5 - * - reg = 0: bridge a4, 1: bridge 23, 2: sensor 11 (clock) - */ - static const u8 fr_tb[2][6][3] = { - {{0x04, 0xff, 0x00}, - {0x04, 0x1f, 0x00}, - {0x04, 0x1b, 0x00}, - {0x04, 0x15, 0x00}, - {0x04, 0x09, 0x00}, - {0x04, 0x01, 0x00}}, - {{0x0c, 0xff, 0x00}, - {0x0c, 0x1f, 0x00}, - {0x0c, 0x1b, 0x00}, - {0x04, 0xff, 0x01}, - {0x04, 0x1f, 0x01}, - {0x04, 0x1b, 0x01}}, - }; - - if (frame_rate > 0) - sd->frame_rate = frame_rate; - if (sd->frame_rate >= 30) - fr = 0; - else if (sd->frame_rate >= 25) - fr = 1; - else if (sd->frame_rate >= 20) - fr = 2; - else if (sd->frame_rate >= 15) - fr = 3; - else if (sd->frame_rate >= 10) - fr = 4; - else - fr = 5; - reg_w(sd, 0xa4, fr_tb[sd->gspca_dev.curr_mode][fr][0]); - reg_w(sd, 0x23, fr_tb[sd->gspca_dev.curr_mode][fr][1]); - clock = fr_tb[sd->gspca_dev.curr_mode][fr][2]; - if (sd->sensor == SEN_OV7660) - clock |= 0x80; /* enable double clock */ - ov518_i2c_w(sd, OV7670_R11_CLKRC, clock); -} - -static void setautogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - i2c_w_mask(sd, 0x13, sd->ctrls[AUTOGAIN].val ? 0x05 : 0x00, 0x05); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam = &gspca_dev->cam; - - sd->bridge = id->driver_info & BRIDGE_MASK; - sd->invert_led = (id->driver_info & BRIDGE_INVERT_LED) != 0; - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - cam->cam_mode = ov511_vga_mode; - cam->nmodes = ARRAY_SIZE(ov511_vga_mode); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - cam->cam_mode = ov518_vga_mode; - cam->nmodes = ARRAY_SIZE(ov518_vga_mode); - break; - case BRIDGE_OV519: - cam->cam_mode = ov519_vga_mode; - cam->nmodes = ARRAY_SIZE(ov519_vga_mode); - sd->invert_led = !sd->invert_led; - break; - case BRIDGE_OVFX2: - cam->cam_mode = ov519_vga_mode; - cam->nmodes = ARRAY_SIZE(ov519_vga_mode); - cam->bulk_size = OVFX2_BULK_SIZE; - cam->bulk_nurbs = MAX_NURBS; - cam->bulk = 1; - break; - case BRIDGE_W9968CF: - cam->cam_mode = w9968cf_vga_mode; - cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode); - cam->reverse_alts = 1; - break; - } - - gspca_dev->cam.ctrls = sd->ctrls; - sd->quality = QUALITY_DEF; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam = &gspca_dev->cam; - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - ov511_configure(gspca_dev); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - ov518_configure(gspca_dev); - break; - case BRIDGE_OV519: - ov519_configure(sd); - break; - case BRIDGE_OVFX2: - ovfx2_configure(sd); - break; - case BRIDGE_W9968CF: - w9968cf_configure(sd); - break; - } - - /* The OV519 must be more aggressive about sensor detection since - * I2C write will never fail if the sensor is not present. We have - * to try to initialize the sensor to detect its presence */ - sd->sensor = -1; - - /* Test for 76xx */ - if (init_ov_sensor(sd, OV7xx0_SID) >= 0) { - ov7xx0_configure(sd); - - /* Test for 6xx0 */ - } else if (init_ov_sensor(sd, OV6xx0_SID) >= 0) { - ov6xx0_configure(sd); - - /* Test for 8xx0 */ - } else if (init_ov_sensor(sd, OV8xx0_SID) >= 0) { - ov8xx0_configure(sd); - - /* Test for 3xxx / 2xxx */ - } else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) { - ov_hires_configure(sd); - } else { - err("Can't determine sensor slave IDs"); - goto error; - } - - if (sd->sensor < 0) - goto error; - - ov51x_led_control(sd, 0); /* turn LED off */ - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - if (sd->sif) { - cam->cam_mode = ov511_sif_mode; - cam->nmodes = ARRAY_SIZE(ov511_sif_mode); - } - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - if (sd->sif) { - cam->cam_mode = ov518_sif_mode; - cam->nmodes = ARRAY_SIZE(ov518_sif_mode); - } - break; - case BRIDGE_OV519: - if (sd->sif) { - cam->cam_mode = ov519_sif_mode; - cam->nmodes = ARRAY_SIZE(ov519_sif_mode); - } - break; - case BRIDGE_OVFX2: - switch (sd->sensor) { - case SEN_OV2610: - case SEN_OV2610AE: - cam->cam_mode = ovfx2_ov2610_mode; - cam->nmodes = ARRAY_SIZE(ovfx2_ov2610_mode); - break; - case SEN_OV3610: - cam->cam_mode = ovfx2_ov3610_mode; - cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode); - break; - default: - if (sd->sif) { - cam->cam_mode = ov519_sif_mode; - cam->nmodes = ARRAY_SIZE(ov519_sif_mode); - } - break; - } - break; - case BRIDGE_W9968CF: - if (sd->sif) - cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode) - 1; - - /* w9968cf needs initialisation once the sensor is known */ - w9968cf_init(sd); - break; - } - - gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; - - /* initialize the sensor */ - switch (sd->sensor) { - case SEN_OV2610: - write_i2c_regvals(sd, norm_2610, ARRAY_SIZE(norm_2610)); - - /* Enable autogain, autoexpo, awb, bandfilter */ - i2c_w_mask(sd, 0x13, 0x27, 0x27); - break; - case SEN_OV2610AE: - write_i2c_regvals(sd, norm_2610ae, ARRAY_SIZE(norm_2610ae)); - - /* enable autoexpo */ - i2c_w_mask(sd, 0x13, 0x05, 0x05); - break; - case SEN_OV3610: - write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b)); - - /* Enable autogain, autoexpo, awb, bandfilter */ - i2c_w_mask(sd, 0x13, 0x27, 0x27); - break; - case SEN_OV6620: - write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)); - break; - case SEN_OV6630: - case SEN_OV66308AF: - sd->ctrls[CONTRAST].def = 200; - /* The default is too low for the ov6630 */ - write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)); - break; - default: -/* case SEN_OV7610: */ -/* case SEN_OV76BE: */ - write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)); - i2c_w_mask(sd, 0x0e, 0x00, 0x40); - break; - case SEN_OV7620: - case SEN_OV7620AE: - write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)); - break; - case SEN_OV7640: - case SEN_OV7648: - write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)); - break; - case SEN_OV7660: - i2c_w(sd, OV7670_R12_COM7, OV7670_COM7_RESET); - msleep(14); - reg_w(sd, OV519_R57_SNAPSHOT, 0x23); - write_regvals(sd, init_519_ov7660, - ARRAY_SIZE(init_519_ov7660)); - write_i2c_regvals(sd, norm_7660, ARRAY_SIZE(norm_7660)); - sd->gspca_dev.curr_mode = 1; /* 640x480 */ - sd->frame_rate = 15; - ov519_set_mode(sd); - ov519_set_fr(sd); - sd->ctrls[COLORS].max = 4; /* 0..4 */ - sd->ctrls[COLORS].val = - sd->ctrls[COLORS].def = 2; - setcolors(gspca_dev); - sd->ctrls[CONTRAST].max = 6; /* 0..6 */ - sd->ctrls[CONTRAST].val = - sd->ctrls[CONTRAST].def = 3; - setcontrast(gspca_dev); - sd->ctrls[BRIGHTNESS].max = 6; /* 0..6 */ - sd->ctrls[BRIGHTNESS].val = - sd->ctrls[BRIGHTNESS].def = 3; - setbrightness(gspca_dev); - sd_reset_snapshot(gspca_dev); - ov51x_restart(sd); - ov51x_stop(sd); /* not in win traces */ - ov51x_led_control(sd, 0); - break; - case SEN_OV7670: - sd->ctrls[FREQ].max = 3; /* auto */ - sd->ctrls[FREQ].def = 3; - write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)); - break; - case SEN_OV8610: - write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)); - break; - } - return gspca_dev->usb_err; -error: - PDEBUG(D_ERR, "OV519 Config failed"); - return -EINVAL; -} - -/* function called at start time before URB creation */ -static int sd_isoc_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->bridge) { - case BRIDGE_OVFX2: - if (gspca_dev->width == 1600) - gspca_dev->cam.bulk_size = OVFX2_BULK_SIZE; - else - gspca_dev->cam.bulk_size = 7 * 4096; - break; - } - return 0; -} - -/* Set up the OV511/OV511+ with the given image parameters. - * - * Do not put any sensor-specific code in here (including I2C I/O functions) - */ -static void ov511_mode_init_regs(struct sd *sd) -{ - int hsegs, vsegs, packet_size, fps, needed; - int interlaced = 0; - struct usb_host_interface *alt; - struct usb_interface *intf; - - intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); - alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); - if (!alt) { - err("Couldn't get altsetting"); - sd->gspca_dev.usb_err = -EIO; - return; - } - - packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); - reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5); - - reg_w(sd, R511_CAM_UV_EN, 0x01); - reg_w(sd, R511_SNAP_UV_EN, 0x01); - reg_w(sd, R511_SNAP_OPTS, 0x03); - - /* Here I'm assuming that snapshot size == image size. - * I hope that's always true. --claudio - */ - hsegs = (sd->gspca_dev.width >> 3) - 1; - vsegs = (sd->gspca_dev.height >> 3) - 1; - - reg_w(sd, R511_CAM_PXCNT, hsegs); - reg_w(sd, R511_CAM_LNCNT, vsegs); - reg_w(sd, R511_CAM_PXDIV, 0x00); - reg_w(sd, R511_CAM_LNDIV, 0x00); - - /* YUV420, low pass filter on */ - reg_w(sd, R511_CAM_OPTS, 0x03); - - /* Snapshot additions */ - reg_w(sd, R511_SNAP_PXCNT, hsegs); - reg_w(sd, R511_SNAP_LNCNT, vsegs); - reg_w(sd, R511_SNAP_PXDIV, 0x00); - reg_w(sd, R511_SNAP_LNDIV, 0x00); - - /******** Set the framerate ********/ - if (frame_rate > 0) - sd->frame_rate = frame_rate; - - switch (sd->sensor) { - case SEN_OV6620: - /* No framerate control, doesn't like higher rates yet */ - sd->clockdiv = 3; - break; - - /* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed - for more sensors we need to do this for them too */ - case SEN_OV7620: - case SEN_OV7620AE: - case SEN_OV7640: - case SEN_OV7648: - case SEN_OV76BE: - if (sd->gspca_dev.width == 320) - interlaced = 1; - /* Fall through */ - case SEN_OV6630: - case SEN_OV7610: - case SEN_OV7670: - switch (sd->frame_rate) { - case 30: - case 25: - /* Not enough bandwidth to do 640x480 @ 30 fps */ - if (sd->gspca_dev.width != 640) { - sd->clockdiv = 0; - break; - } - /* Fall through for 640x480 case */ - default: -/* case 20: */ -/* case 15: */ - sd->clockdiv = 1; - break; - case 10: - sd->clockdiv = 2; - break; - case 5: - sd->clockdiv = 5; - break; - } - if (interlaced) { - sd->clockdiv = (sd->clockdiv + 1) * 2 - 1; - /* Higher then 10 does not work */ - if (sd->clockdiv > 10) - sd->clockdiv = 10; - } - break; - - case SEN_OV8610: - /* No framerate control ?? */ - sd->clockdiv = 0; - break; - } - - /* Check if we have enough bandwidth to disable compression */ - fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1; - needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2; - /* 1400 is a conservative estimate of the max nr of isoc packets/sec */ - if (needed > 1400 * packet_size) { - /* Enable Y and UV quantization and compression */ - reg_w(sd, R511_COMP_EN, 0x07); - reg_w(sd, R511_COMP_LUT_EN, 0x03); - } else { - reg_w(sd, R511_COMP_EN, 0x06); - reg_w(sd, R511_COMP_LUT_EN, 0x00); - } - - reg_w(sd, R51x_SYS_RESET, OV511_RESET_OMNICE); - reg_w(sd, R51x_SYS_RESET, 0); -} - -/* Sets up the OV518/OV518+ with the given image parameters - * - * OV518 needs a completely different approach, until we can figure out what - * the individual registers do. Also, only 15 FPS is supported now. - * - * Do not put any sensor-specific code in here (including I2C I/O functions) - */ -static void ov518_mode_init_regs(struct sd *sd) -{ - int hsegs, vsegs, packet_size; - struct usb_host_interface *alt; - struct usb_interface *intf; - - intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); - alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); - if (!alt) { - err("Couldn't get altsetting"); - sd->gspca_dev.usb_err = -EIO; - return; - } - - packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); - ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2); - - /******** Set the mode ********/ - reg_w(sd, 0x2b, 0); - reg_w(sd, 0x2c, 0); - reg_w(sd, 0x2d, 0); - reg_w(sd, 0x2e, 0); - reg_w(sd, 0x3b, 0); - reg_w(sd, 0x3c, 0); - reg_w(sd, 0x3d, 0); - reg_w(sd, 0x3e, 0); - - if (sd->bridge == BRIDGE_OV518) { - /* Set 8-bit (YVYU) input format */ - reg_w_mask(sd, 0x20, 0x08, 0x08); - - /* Set 12-bit (4:2:0) output format */ - reg_w_mask(sd, 0x28, 0x80, 0xf0); - reg_w_mask(sd, 0x38, 0x80, 0xf0); - } else { - reg_w(sd, 0x28, 0x80); - reg_w(sd, 0x38, 0x80); - } - - hsegs = sd->gspca_dev.width / 16; - vsegs = sd->gspca_dev.height / 4; - - reg_w(sd, 0x29, hsegs); - reg_w(sd, 0x2a, vsegs); - - reg_w(sd, 0x39, hsegs); - reg_w(sd, 0x3a, vsegs); - - /* Windows driver does this here; who knows why */ - reg_w(sd, 0x2f, 0x80); - - /******** Set the framerate ********/ - sd->clockdiv = 1; - - /* Mode independent, but framerate dependent, regs */ - /* 0x51: Clock divider; Only works on some cams which use 2 crystals */ - reg_w(sd, 0x51, 0x04); - reg_w(sd, 0x22, 0x18); - reg_w(sd, 0x23, 0xff); - - if (sd->bridge == BRIDGE_OV518PLUS) { - switch (sd->sensor) { - case SEN_OV7620AE: - if (sd->gspca_dev.width == 320) { - reg_w(sd, 0x20, 0x00); - reg_w(sd, 0x21, 0x19); - } else { - reg_w(sd, 0x20, 0x60); - reg_w(sd, 0x21, 0x1f); - } - break; - case SEN_OV7620: - reg_w(sd, 0x20, 0x00); - reg_w(sd, 0x21, 0x19); - break; - default: - reg_w(sd, 0x21, 0x19); - } - } else - reg_w(sd, 0x71, 0x17); /* Compression-related? */ - - /* FIXME: Sensor-specific */ - /* Bit 5 is what matters here. Of course, it is "reserved" */ - i2c_w(sd, 0x54, 0x23); - - reg_w(sd, 0x2f, 0x80); - - if (sd->bridge == BRIDGE_OV518PLUS) { - reg_w(sd, 0x24, 0x94); - reg_w(sd, 0x25, 0x90); - ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */ - ov518_reg_w32(sd, 0xc6, 540, 2); /* 21ch */ - ov518_reg_w32(sd, 0xc7, 540, 2); /* 21ch */ - ov518_reg_w32(sd, 0xc8, 108, 2); /* 6ch */ - ov518_reg_w32(sd, 0xca, 131098, 3); /* 2001ah */ - ov518_reg_w32(sd, 0xcb, 532, 2); /* 214h */ - ov518_reg_w32(sd, 0xcc, 2400, 2); /* 960h */ - ov518_reg_w32(sd, 0xcd, 32, 2); /* 20h */ - ov518_reg_w32(sd, 0xce, 608, 2); /* 260h */ - } else { - reg_w(sd, 0x24, 0x9f); - reg_w(sd, 0x25, 0x90); - ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */ - ov518_reg_w32(sd, 0xc6, 381, 2); /* 17dh */ - ov518_reg_w32(sd, 0xc7, 381, 2); /* 17dh */ - ov518_reg_w32(sd, 0xc8, 128, 2); /* 80h */ - ov518_reg_w32(sd, 0xca, 183331, 3); /* 2cc23h */ - ov518_reg_w32(sd, 0xcb, 746, 2); /* 2eah */ - ov518_reg_w32(sd, 0xcc, 1750, 2); /* 6d6h */ - ov518_reg_w32(sd, 0xcd, 45, 2); /* 2dh */ - ov518_reg_w32(sd, 0xce, 851, 2); /* 353h */ - } - - reg_w(sd, 0x2f, 0x80); -} - -/* Sets up the OV519 with the given image parameters - * - * OV519 needs a completely different approach, until we can figure out what - * the individual registers do. - * - * Do not put any sensor-specific code in here (including I2C I/O functions) - */ -static void ov519_mode_init_regs(struct sd *sd) -{ - static const struct ov_regvals mode_init_519_ov7670[] = { - { 0x5d, 0x03 }, /* Turn off suspend mode */ - { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */ - { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */ - { 0xa2, 0x20 }, /* a2-a5 are undocumented */ - { 0xa3, 0x18 }, - { 0xa4, 0x04 }, - { 0xa5, 0x28 }, - { 0x37, 0x00 }, /* SetUsbInit */ - { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ - /* Enable both fields, YUV Input, disable defect comp (why?) */ - { 0x20, 0x0c }, - { 0x21, 0x38 }, - { 0x22, 0x1d }, - { 0x17, 0x50 }, /* undocumented */ - { 0x37, 0x00 }, /* undocumented */ - { 0x40, 0xff }, /* I2C timeout counter */ - { 0x46, 0x00 }, /* I2C clock prescaler */ - { 0x59, 0x04 }, /* new from windrv 090403 */ - { 0xff, 0x00 }, /* undocumented */ - /* windows reads 0x55 at this point, why? */ - }; - - static const struct ov_regvals mode_init_519[] = { - { 0x5d, 0x03 }, /* Turn off suspend mode */ - { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */ - { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */ - { 0xa2, 0x20 }, /* a2-a5 are undocumented */ - { 0xa3, 0x18 }, - { 0xa4, 0x04 }, - { 0xa5, 0x28 }, - { 0x37, 0x00 }, /* SetUsbInit */ - { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ - /* Enable both fields, YUV Input, disable defect comp (why?) */ - { 0x22, 0x1d }, - { 0x17, 0x50 }, /* undocumented */ - { 0x37, 0x00 }, /* undocumented */ - { 0x40, 0xff }, /* I2C timeout counter */ - { 0x46, 0x00 }, /* I2C clock prescaler */ - { 0x59, 0x04 }, /* new from windrv 090403 */ - { 0xff, 0x00 }, /* undocumented */ - /* windows reads 0x55 at this point, why? */ - }; - - /******** Set the mode ********/ - switch (sd->sensor) { - default: - write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519)); - if (sd->sensor == SEN_OV7640 || - sd->sensor == SEN_OV7648) { - /* Select 8-bit input mode */ - reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10); - } - break; - case SEN_OV7660: - return; /* done by ov519_set_mode/fr() */ - case SEN_OV7670: - write_regvals(sd, mode_init_519_ov7670, - ARRAY_SIZE(mode_init_519_ov7670)); - break; - } - - reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4); - reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.height >> 3); - if (sd->sensor == SEN_OV7670 && - sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv) - reg_w(sd, OV519_R12_X_OFFSETL, 0x04); - else if (sd->sensor == SEN_OV7648 && - sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv) - reg_w(sd, OV519_R12_X_OFFSETL, 0x01); - else - reg_w(sd, OV519_R12_X_OFFSETL, 0x00); - reg_w(sd, OV519_R13_X_OFFSETH, 0x00); - reg_w(sd, OV519_R14_Y_OFFSETL, 0x00); - reg_w(sd, OV519_R15_Y_OFFSETH, 0x00); - reg_w(sd, OV519_R16_DIVIDER, 0x00); - reg_w(sd, OV519_R25_FORMAT, 0x03); /* YUV422 */ - reg_w(sd, 0x26, 0x00); /* Undocumented */ - - /******** Set the framerate ********/ - if (frame_rate > 0) - sd->frame_rate = frame_rate; - -/* FIXME: These are only valid at the max resolution. */ - sd->clockdiv = 0; - switch (sd->sensor) { - case SEN_OV7640: - case SEN_OV7648: - switch (sd->frame_rate) { - default: -/* case 30: */ - reg_w(sd, 0xa4, 0x0c); - reg_w(sd, 0x23, 0xff); - break; - case 25: - reg_w(sd, 0xa4, 0x0c); - reg_w(sd, 0x23, 0x1f); - break; - case 20: - reg_w(sd, 0xa4, 0x0c); - reg_w(sd, 0x23, 0x1b); - break; - case 15: - reg_w(sd, 0xa4, 0x04); - reg_w(sd, 0x23, 0xff); - sd->clockdiv = 1; - break; - case 10: - reg_w(sd, 0xa4, 0x04); - reg_w(sd, 0x23, 0x1f); - sd->clockdiv = 1; - break; - case 5: - reg_w(sd, 0xa4, 0x04); - reg_w(sd, 0x23, 0x1b); - sd->clockdiv = 1; - break; - } - break; - case SEN_OV8610: - switch (sd->frame_rate) { - default: /* 15 fps */ -/* case 15: */ - reg_w(sd, 0xa4, 0x06); - reg_w(sd, 0x23, 0xff); - break; - case 10: - reg_w(sd, 0xa4, 0x06); - reg_w(sd, 0x23, 0x1f); - break; - case 5: - reg_w(sd, 0xa4, 0x06); - reg_w(sd, 0x23, 0x1b); - break; - } - break; - case SEN_OV7670: /* guesses, based on 7640 */ - PDEBUG(D_STREAM, "Setting framerate to %d fps", - (sd->frame_rate == 0) ? 15 : sd->frame_rate); - reg_w(sd, 0xa4, 0x10); - switch (sd->frame_rate) { - case 30: - reg_w(sd, 0x23, 0xff); - break; - case 20: - reg_w(sd, 0x23, 0x1b); - break; - default: -/* case 15: */ - reg_w(sd, 0x23, 0xff); - sd->clockdiv = 1; - break; - } - break; - } -} - -static void mode_init_ov_sensor_regs(struct sd *sd) -{ - struct gspca_dev *gspca_dev; - int qvga, xstart, xend, ystart, yend; - u8 v; - - gspca_dev = &sd->gspca_dev; - qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1; - - /******** Mode (VGA/QVGA) and sensor specific regs ********/ - switch (sd->sensor) { - case SEN_OV2610: - i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); - i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); - i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); - i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); - i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); - i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); - i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); - return; - case SEN_OV2610AE: { - u8 v; - - /* frame rates: - * 10fps / 5 fps for 1600x1200 - * 40fps / 20fps for 800x600 - */ - v = 80; - if (qvga) { - if (sd->frame_rate < 25) - v = 0x81; - } else { - if (sd->frame_rate < 10) - v = 0x81; - } - i2c_w(sd, 0x11, v); - i2c_w(sd, 0x12, qvga ? 0x60 : 0x20); - return; - } - case SEN_OV3610: - if (qvga) { - xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4); - ystart = (776 - gspca_dev->height) / 2; - } else { - xstart = (2076 - gspca_dev->width) / 2 + (0x10 << 4); - ystart = (1544 - gspca_dev->height) / 2; - } - xend = xstart + gspca_dev->width; - yend = ystart + gspca_dev->height; - /* Writing to the COMH register resets the other windowing regs - to their default values, so we must do this first. */ - i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0xf0); - i2c_w_mask(sd, 0x32, - (((xend >> 1) & 7) << 3) | ((xstart >> 1) & 7), - 0x3f); - i2c_w_mask(sd, 0x03, - (((yend >> 1) & 3) << 2) | ((ystart >> 1) & 3), - 0x0f); - i2c_w(sd, 0x17, xstart >> 4); - i2c_w(sd, 0x18, xend >> 4); - i2c_w(sd, 0x19, ystart >> 3); - i2c_w(sd, 0x1a, yend >> 3); - return; - case SEN_OV8610: - /* For OV8610 qvga means qsvga */ - i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5); - i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ - i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ - i2c_w_mask(sd, 0x2d, 0x00, 0x40); /* from windrv 090403 */ - i2c_w_mask(sd, 0x28, 0x20, 0x20); /* progressive mode on */ - break; - case SEN_OV7610: - i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); - i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e); - i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ - i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ - break; - case SEN_OV7620: - case SEN_OV7620AE: - case SEN_OV76BE: - i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); - i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); - i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); - i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); - i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); - i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0); - i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); - i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ - i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ - if (sd->sensor == SEN_OV76BE) - i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e); - break; - case SEN_OV7640: - case SEN_OV7648: - i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); - i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); - /* Setting this undocumented bit in qvga mode removes a very - annoying vertical shaking of the image */ - i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); - /* Unknown */ - i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); - /* Allow higher automatic gain (to allow higher framerates) */ - i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); - i2c_w_mask(sd, 0x12, 0x04, 0x04); /* AWB: 1 */ - break; - case SEN_OV7670: - /* set COM7_FMT_VGA or COM7_FMT_QVGA - * do we need to set anything else? - * HSTART etc are set in set_ov_sensor_window itself */ - i2c_w_mask(sd, OV7670_R12_COM7, - qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA, - OV7670_COM7_FMT_MASK); - i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ - i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_AWB, - OV7670_COM8_AWB); - if (qvga) { /* QVGA from ov7670.c by - * Jonathan Corbet */ - xstart = 164; - xend = 28; - ystart = 14; - yend = 494; - } else { /* VGA */ - xstart = 158; - xend = 14; - ystart = 10; - yend = 490; - } - /* OV7670 hardware window registers are split across - * multiple locations */ - i2c_w(sd, OV7670_R17_HSTART, xstart >> 3); - i2c_w(sd, OV7670_R18_HSTOP, xend >> 3); - v = i2c_r(sd, OV7670_R32_HREF); - v = (v & 0xc0) | ((xend & 0x7) << 3) | (xstart & 0x07); - msleep(10); /* need to sleep between read and write to - * same reg! */ - i2c_w(sd, OV7670_R32_HREF, v); - - i2c_w(sd, OV7670_R19_VSTART, ystart >> 2); - i2c_w(sd, OV7670_R1A_VSTOP, yend >> 2); - v = i2c_r(sd, OV7670_R03_VREF); - v = (v & 0xc0) | ((yend & 0x3) << 2) | (ystart & 0x03); - msleep(10); /* need to sleep between read and write to - * same reg! */ - i2c_w(sd, OV7670_R03_VREF, v); - break; - case SEN_OV6620: - i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); - i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ - i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ - break; - case SEN_OV6630: - case SEN_OV66308AF: - i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); - i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ - break; - default: - return; - } - - /******** Clock programming ********/ - i2c_w(sd, 0x11, sd->clockdiv); -} - -/* this function works for bridge ov519 and sensors ov7660 and ov7670 only */ -static void sethvflip(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->gspca_dev.streaming) - reg_w(sd, OV519_R51_RESET1, 0x0f); /* block stream */ - i2c_w_mask(sd, OV7670_R1E_MVFP, - OV7670_MVFP_MIRROR * sd->ctrls[HFLIP].val - | OV7670_MVFP_VFLIP * sd->ctrls[VFLIP].val, - OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP); - if (sd->gspca_dev.streaming) - reg_w(sd, OV519_R51_RESET1, 0x00); /* restart stream */ -} - -static void set_ov_sensor_window(struct sd *sd) -{ - struct gspca_dev *gspca_dev; - int qvga, crop; - int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale; - - /* mode setup is fully handled in mode_init_ov_sensor_regs for these */ - switch (sd->sensor) { - case SEN_OV2610: - case SEN_OV2610AE: - case SEN_OV3610: - case SEN_OV7670: - mode_init_ov_sensor_regs(sd); - return; - case SEN_OV7660: - ov519_set_mode(sd); - ov519_set_fr(sd); - return; - } - - gspca_dev = &sd->gspca_dev; - qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1; - crop = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 2; - - /* The different sensor ICs handle setting up of window differently. - * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */ - switch (sd->sensor) { - case SEN_OV8610: - hwsbase = 0x1e; - hwebase = 0x1e; - vwsbase = 0x02; - vwebase = 0x02; - break; - case SEN_OV7610: - case SEN_OV76BE: - hwsbase = 0x38; - hwebase = 0x3a; - vwsbase = vwebase = 0x05; - break; - case SEN_OV6620: - case SEN_OV6630: - case SEN_OV66308AF: - hwsbase = 0x38; - hwebase = 0x3a; - vwsbase = 0x05; - vwebase = 0x06; - if (sd->sensor == SEN_OV66308AF && qvga) - /* HDG: this fixes U and V getting swapped */ - hwsbase++; - if (crop) { - hwsbase += 8; - hwebase += 8; - vwsbase += 11; - vwebase += 11; - } - break; - case SEN_OV7620: - case SEN_OV7620AE: - hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ - hwebase = 0x2f; - vwsbase = vwebase = 0x05; - break; - case SEN_OV7640: - case SEN_OV7648: - hwsbase = 0x1a; - hwebase = 0x1a; - vwsbase = vwebase = 0x03; - break; - default: - return; - } - - switch (sd->sensor) { - case SEN_OV6620: - case SEN_OV6630: - case SEN_OV66308AF: - if (qvga) { /* QCIF */ - hwscale = 0; - vwscale = 0; - } else { /* CIF */ - hwscale = 1; - vwscale = 1; /* The datasheet says 0; - * it's wrong */ - } - break; - case SEN_OV8610: - if (qvga) { /* QSVGA */ - hwscale = 1; - vwscale = 1; - } else { /* SVGA */ - hwscale = 2; - vwscale = 2; - } - break; - default: /* SEN_OV7xx0 */ - if (qvga) { /* QVGA */ - hwscale = 1; - vwscale = 0; - } else { /* VGA */ - hwscale = 2; - vwscale = 1; - } - } - - mode_init_ov_sensor_regs(sd); - - i2c_w(sd, 0x17, hwsbase); - i2c_w(sd, 0x18, hwebase + (sd->sensor_width >> hwscale)); - i2c_w(sd, 0x19, vwsbase); - i2c_w(sd, 0x1a, vwebase + (sd->sensor_height >> vwscale)); -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* Default for most bridges, allow bridge_mode_init_regs to override */ - sd->sensor_width = sd->gspca_dev.width; - sd->sensor_height = sd->gspca_dev.height; - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - ov511_mode_init_regs(sd); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - ov518_mode_init_regs(sd); - break; - case BRIDGE_OV519: - ov519_mode_init_regs(sd); - break; - /* case BRIDGE_OVFX2: nothing to do */ - case BRIDGE_W9968CF: - w9968cf_mode_init_regs(sd); - break; - } - - set_ov_sensor_window(sd); - - if (!(sd->gspca_dev.ctrl_dis & (1 << CONTRAST))) - setcontrast(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << BRIGHTNESS))) - setbrightness(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << EXPOSURE))) - setexposure(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << COLORS))) - setcolors(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & ((1 << HFLIP) | (1 << VFLIP)))) - sethvflip(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOBRIGHT))) - setautobright(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOGAIN))) - setautogain(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << FREQ))) - setfreq_i(sd); - - /* Force clear snapshot state in case the snapshot button was - pressed while we weren't streaming */ - sd->snapshot_needs_reset = 1; - sd_reset_snapshot(gspca_dev); - - sd->first_frame = 3; - - ov51x_restart(sd); - ov51x_led_control(sd, 1); - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - ov51x_stop(sd); - ov51x_led_control(sd, 0); -} - -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (!sd->gspca_dev.present) - return; - if (sd->bridge == BRIDGE_W9968CF) - w9968cf_stop0(sd); - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - /* If the last button state is pressed, release it now! */ - if (sd->snapshot_pressed) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - sd->snapshot_pressed = 0; - } -#endif - if (sd->bridge == BRIDGE_OV519) - reg_w(sd, OV519_R57_SNAPSHOT, 0x23); -} - -static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->snapshot_pressed != state) { -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - input_report_key(gspca_dev->input_dev, KEY_CAMERA, state); - input_sync(gspca_dev->input_dev); -#endif - if (state) - sd->snapshot_needs_reset = 1; - - sd->snapshot_pressed = state; - } else { - /* On the ov511 / ov519 we need to reset the button state - multiple times, as resetting does not work as long as the - button stays pressed */ - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - case BRIDGE_OV519: - if (state) - sd->snapshot_needs_reset = 1; - break; - } - } -} - -static void ov511_pkt_scan(struct gspca_dev *gspca_dev, - u8 *in, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th - * byte non-zero. The EOF packet has image width/height in the - * 10th and 11th bytes. The 9th byte is given as follows: - * - * bit 7: EOF - * 6: compression enabled - * 5: 422/420/400 modes - * 4: 422/420/400 modes - * 3: 1 - * 2: snapshot button on - * 1: snapshot frame - * 0: even/odd field - */ - if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) && - (in[8] & 0x08)) { - ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1); - if (in[8] & 0x80) { - /* Frame end */ - if ((in[9] + 1) * 8 != gspca_dev->width || - (in[10] + 1) * 8 != gspca_dev->height) { - PDEBUG(D_ERR, "Invalid frame size, got: %dx%d," - " requested: %dx%d\n", - (in[9] + 1) * 8, (in[10] + 1) * 8, - gspca_dev->width, gspca_dev->height); - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - /* Add 11 byte footer to frame, might be usefull */ - gspca_frame_add(gspca_dev, LAST_PACKET, in, 11); - return; - } else { - /* Frame start */ - gspca_frame_add(gspca_dev, FIRST_PACKET, in, 0); - sd->packet_nr = 0; - } - } - - /* Ignore the packet number */ - len--; - - /* intermediate packet */ - gspca_frame_add(gspca_dev, INTER_PACKET, in, len); -} - -static void ov518_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* A false positive here is likely, until OVT gives me - * the definitive SOF/EOF format */ - if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) { - ov51x_handle_button(gspca_dev, (data[6] >> 1) & 1); - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); - sd->packet_nr = 0; - } - - if (gspca_dev->last_packet_type == DISCARD_PACKET) - return; - - /* Does this device use packet numbers ? */ - if (len & 7) { - len--; - if (sd->packet_nr == data[len]) - sd->packet_nr++; - /* The last few packets of the frame (which are all 0's - except that they may contain part of the footer), are - numbered 0 */ - else if (sd->packet_nr == 0 || data[len]) { - PDEBUG(D_ERR, "Invalid packet nr: %d (expect: %d)", - (int)data[len], (int)sd->packet_nr); - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - } - - /* intermediate packet */ - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static void ov519_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - /* Header of ov519 is 16 bytes: - * Byte Value Description - * 0 0xff magic - * 1 0xff magic - * 2 0xff magic - * 3 0xXX 0x50 = SOF, 0x51 = EOF - * 9 0xXX 0x01 initial frame without data, - * 0x00 standard frame with image - * 14 Lo in EOF: length of image data / 8 - * 15 Hi - */ - - if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) { - switch (data[3]) { - case 0x50: /* start of frame */ - /* Don't check the button state here, as the state - usually (always ?) changes at EOF and checking it - here leads to unnecessary snapshot state resets. */ -#define HDRSZ 16 - data += HDRSZ; - len -= HDRSZ; -#undef HDRSZ - if (data[0] == 0xff || data[1] == 0xd8) - gspca_frame_add(gspca_dev, FIRST_PACKET, - data, len); - else - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - case 0x51: /* end of frame */ - ov51x_handle_button(gspca_dev, data[11] & 1); - if (data[9] != 0) - gspca_dev->last_packet_type = DISCARD_PACKET; - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - return; - } - } - - /* intermediate packet */ - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - - /* A short read signals EOF */ - if (len < OVFX2_BULK_SIZE) { - /* If the frame is short, and it is one of the first ones - the sensor and bridge are still syncing, so drop it. */ - if (sd->first_frame) { - sd->first_frame--; - if (gspca_dev->image_len < - sd->gspca_dev.width * sd->gspca_dev.height) - gspca_dev->last_packet_type = DISCARD_PACKET; - } - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); - } -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->bridge) { - case BRIDGE_OV511: - case BRIDGE_OV511PLUS: - ov511_pkt_scan(gspca_dev, data, len); - break; - case BRIDGE_OV518: - case BRIDGE_OV518PLUS: - ov518_pkt_scan(gspca_dev, data, len); - break; - case BRIDGE_OV519: - ov519_pkt_scan(gspca_dev, data, len); - break; - case BRIDGE_OVFX2: - ovfx2_pkt_scan(gspca_dev, data, len); - break; - case BRIDGE_W9968CF: - w9968cf_pkt_scan(gspca_dev, data, len); - break; - } -} - -/* -- management routines -- */ - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int val; - static const struct ov_i2c_regvals brit_7660[][7] = { - {{0x0f, 0x6a}, {0x24, 0x40}, {0x25, 0x2b}, {0x26, 0x90}, - {0x27, 0xe0}, {0x28, 0xe0}, {0x2c, 0xe0}}, - {{0x0f, 0x6a}, {0x24, 0x50}, {0x25, 0x40}, {0x26, 0xa1}, - {0x27, 0xc0}, {0x28, 0xc0}, {0x2c, 0xc0}}, - {{0x0f, 0x6a}, {0x24, 0x68}, {0x25, 0x58}, {0x26, 0xc2}, - {0x27, 0xa0}, {0x28, 0xa0}, {0x2c, 0xa0}}, - {{0x0f, 0x6a}, {0x24, 0x70}, {0x25, 0x68}, {0x26, 0xd3}, - {0x27, 0x80}, {0x28, 0x80}, {0x2c, 0x80}}, - {{0x0f, 0x6a}, {0x24, 0x80}, {0x25, 0x70}, {0x26, 0xd3}, - {0x27, 0x20}, {0x28, 0x20}, {0x2c, 0x20}}, - {{0x0f, 0x6a}, {0x24, 0x88}, {0x25, 0x78}, {0x26, 0xd3}, - {0x27, 0x40}, {0x28, 0x40}, {0x2c, 0x40}}, - {{0x0f, 0x6a}, {0x24, 0x90}, {0x25, 0x80}, {0x26, 0xd4}, - {0x27, 0x60}, {0x28, 0x60}, {0x2c, 0x60}} - }; - - val = sd->ctrls[BRIGHTNESS].val; - switch (sd->sensor) { - case SEN_OV8610: - case SEN_OV7610: - case SEN_OV76BE: - case SEN_OV6620: - case SEN_OV6630: - case SEN_OV66308AF: - case SEN_OV7640: - case SEN_OV7648: - i2c_w(sd, OV7610_REG_BRT, val); - break; - case SEN_OV7620: - case SEN_OV7620AE: - /* 7620 doesn't like manual changes when in auto mode */ - if (!sd->ctrls[AUTOBRIGHT].val) - i2c_w(sd, OV7610_REG_BRT, val); - break; - case SEN_OV7660: - write_i2c_regvals(sd, brit_7660[val], - ARRAY_SIZE(brit_7660[0])); - break; - case SEN_OV7670: -/*win trace - * i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_AEC); */ - i2c_w(sd, OV7670_R55_BRIGHT, ov7670_abs_to_sm(val)); - break; - } -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int val; - static const struct ov_i2c_regvals contrast_7660[][31] = { - {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0xa0}, - {0x70, 0x58}, {0x71, 0x38}, {0x72, 0x30}, {0x73, 0x30}, - {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x24}, {0x77, 0x24}, - {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x34}, - {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x65}, - {0x80, 0x70}, {0x81, 0x77}, {0x82, 0x7d}, {0x83, 0x83}, - {0x84, 0x88}, {0x85, 0x8d}, {0x86, 0x96}, {0x87, 0x9f}, - {0x88, 0xb0}, {0x89, 0xc4}, {0x8a, 0xd9}}, - {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0x94}, - {0x70, 0x58}, {0x71, 0x40}, {0x72, 0x30}, {0x73, 0x30}, - {0x74, 0x30}, {0x75, 0x30}, {0x76, 0x2c}, {0x77, 0x24}, - {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x31}, - {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x62}, - {0x80, 0x6d}, {0x81, 0x75}, {0x82, 0x7b}, {0x83, 0x81}, - {0x84, 0x87}, {0x85, 0x8d}, {0x86, 0x98}, {0x87, 0xa1}, - {0x88, 0xb2}, {0x89, 0xc6}, {0x8a, 0xdb}}, - {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x84}, - {0x70, 0x58}, {0x71, 0x48}, {0x72, 0x40}, {0x73, 0x40}, - {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x28}, {0x77, 0x24}, - {0x78, 0x26}, {0x79, 0x28}, {0x7a, 0x28}, {0x7b, 0x34}, - {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x5d}, - {0x80, 0x68}, {0x81, 0x71}, {0x82, 0x79}, {0x83, 0x81}, - {0x84, 0x86}, {0x85, 0x8b}, {0x86, 0x95}, {0x87, 0x9e}, - {0x88, 0xb1}, {0x89, 0xc5}, {0x8a, 0xd9}}, - {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x70}, - {0x70, 0x58}, {0x71, 0x58}, {0x72, 0x48}, {0x73, 0x48}, - {0x74, 0x38}, {0x75, 0x40}, {0x76, 0x34}, {0x77, 0x34}, - {0x78, 0x2e}, {0x79, 0x28}, {0x7a, 0x24}, {0x7b, 0x22}, - {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x58}, - {0x80, 0x63}, {0x81, 0x6e}, {0x82, 0x77}, {0x83, 0x80}, - {0x84, 0x87}, {0x85, 0x8f}, {0x86, 0x9c}, {0x87, 0xa9}, - {0x88, 0xc0}, {0x89, 0xd4}, {0x8a, 0xe6}}, - {{0x6c, 0xa0}, {0x6d, 0xf0}, {0x6e, 0x90}, {0x6f, 0x80}, - {0x70, 0x70}, {0x71, 0x80}, {0x72, 0x60}, {0x73, 0x60}, - {0x74, 0x58}, {0x75, 0x60}, {0x76, 0x4c}, {0x77, 0x38}, - {0x78, 0x38}, {0x79, 0x2a}, {0x7a, 0x20}, {0x7b, 0x0e}, - {0x7c, 0x0a}, {0x7d, 0x14}, {0x7e, 0x26}, {0x7f, 0x46}, - {0x80, 0x54}, {0x81, 0x64}, {0x82, 0x70}, {0x83, 0x7c}, - {0x84, 0x87}, {0x85, 0x93}, {0x86, 0xa6}, {0x87, 0xb4}, - {0x88, 0xd0}, {0x89, 0xe5}, {0x8a, 0xf5}}, - {{0x6c, 0x60}, {0x6d, 0x80}, {0x6e, 0x60}, {0x6f, 0x80}, - {0x70, 0x80}, {0x71, 0x80}, {0x72, 0x88}, {0x73, 0x30}, - {0x74, 0x70}, {0x75, 0x68}, {0x76, 0x64}, {0x77, 0x50}, - {0x78, 0x3c}, {0x79, 0x22}, {0x7a, 0x10}, {0x7b, 0x08}, - {0x7c, 0x06}, {0x7d, 0x0e}, {0x7e, 0x1a}, {0x7f, 0x3a}, - {0x80, 0x4a}, {0x81, 0x5a}, {0x82, 0x6b}, {0x83, 0x7b}, - {0x84, 0x89}, {0x85, 0x96}, {0x86, 0xaf}, {0x87, 0xc3}, - {0x88, 0xe1}, {0x89, 0xf2}, {0x8a, 0xfa}}, - {{0x6c, 0x20}, {0x6d, 0x40}, {0x6e, 0x20}, {0x6f, 0x60}, - {0x70, 0x88}, {0x71, 0xc8}, {0x72, 0xc0}, {0x73, 0xb8}, - {0x74, 0xa8}, {0x75, 0xb8}, {0x76, 0x80}, {0x77, 0x5c}, - {0x78, 0x26}, {0x79, 0x10}, {0x7a, 0x08}, {0x7b, 0x04}, - {0x7c, 0x02}, {0x7d, 0x06}, {0x7e, 0x0a}, {0x7f, 0x22}, - {0x80, 0x33}, {0x81, 0x4c}, {0x82, 0x64}, {0x83, 0x7b}, - {0x84, 0x90}, {0x85, 0xa7}, {0x86, 0xc7}, {0x87, 0xde}, - {0x88, 0xf1}, {0x89, 0xf9}, {0x8a, 0xfd}}, - }; - - val = sd->ctrls[CONTRAST].val; - switch (sd->sensor) { - case SEN_OV7610: - case SEN_OV6620: - i2c_w(sd, OV7610_REG_CNT, val); - break; - case SEN_OV6630: - case SEN_OV66308AF: - i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f); - break; - case SEN_OV8610: { - static const u8 ctab[] = { - 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f - }; - - /* Use Y gamma control instead. Bit 0 enables it. */ - i2c_w(sd, 0x64, ctab[val >> 5]); - break; - } - case SEN_OV7620: - case SEN_OV7620AE: { - static const u8 ctab[] = { - 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, - 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff - }; - - /* Use Y gamma control instead. Bit 0 enables it. */ - i2c_w(sd, 0x64, ctab[val >> 4]); - break; - } - case SEN_OV7660: - write_i2c_regvals(sd, contrast_7660[val], - ARRAY_SIZE(contrast_7660[0])); - break; - case SEN_OV7670: - /* check that this isn't just the same as ov7610 */ - i2c_w(sd, OV7670_R56_CONTRAS, val >> 1); - break; - } -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (!sd->ctrls[AUTOGAIN].val) - i2c_w(sd, 0x10, sd->ctrls[EXPOSURE].val); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int val; - static const struct ov_i2c_regvals colors_7660[][6] = { - {{0x4f, 0x28}, {0x50, 0x2a}, {0x51, 0x02}, {0x52, 0x0a}, - {0x53, 0x19}, {0x54, 0x23}}, - {{0x4f, 0x47}, {0x50, 0x4a}, {0x51, 0x03}, {0x52, 0x11}, - {0x53, 0x2c}, {0x54, 0x3e}}, - {{0x4f, 0x66}, {0x50, 0x6b}, {0x51, 0x05}, {0x52, 0x19}, - {0x53, 0x40}, {0x54, 0x59}}, - {{0x4f, 0x84}, {0x50, 0x8b}, {0x51, 0x06}, {0x52, 0x20}, - {0x53, 0x53}, {0x54, 0x73}}, - {{0x4f, 0xa3}, {0x50, 0xab}, {0x51, 0x08}, {0x52, 0x28}, - {0x53, 0x66}, {0x54, 0x8e}}, - }; - - val = sd->ctrls[COLORS].val; - switch (sd->sensor) { - case SEN_OV8610: - case SEN_OV7610: - case SEN_OV76BE: - case SEN_OV6620: - case SEN_OV6630: - case SEN_OV66308AF: - i2c_w(sd, OV7610_REG_SAT, val); - break; - case SEN_OV7620: - case SEN_OV7620AE: - /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ -/* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e); - if (rc < 0) - goto out; */ - i2c_w(sd, OV7610_REG_SAT, val); - break; - case SEN_OV7640: - case SEN_OV7648: - i2c_w(sd, OV7610_REG_SAT, val & 0xf0); - break; - case SEN_OV7660: - write_i2c_regvals(sd, colors_7660[val], - ARRAY_SIZE(colors_7660[0])); - break; - case SEN_OV7670: - /* supported later once I work out how to do it - * transparently fail now! */ - /* set REG_COM13 values for UV sat auto mode */ - break; - } -} - -static void setautobright(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - i2c_w_mask(sd, 0x2d, sd->ctrls[AUTOBRIGHT].val ? 0x10 : 0x00, 0x10); -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AUTOGAIN].val = val; - if (val) { - gspca_dev->ctrl_inac |= (1 << EXPOSURE); - } else { - gspca_dev->ctrl_inac &= ~(1 << EXPOSURE); - sd->ctrls[EXPOSURE].val = i2c_r(sd, 0x10); - } - if (gspca_dev->streaming) - setautogain(gspca_dev); - return gspca_dev->usb_err; -} - -static void setfreq_i(struct sd *sd) -{ - if (sd->sensor == SEN_OV7660 - || sd->sensor == SEN_OV7670) { - switch (sd->ctrls[FREQ].val) { - case 0: /* Banding filter disabled */ - i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_BFILT); - break; - case 1: /* 50 hz */ - i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT, - OV7670_COM8_BFILT); - i2c_w_mask(sd, OV7670_R3B_COM11, 0x08, 0x18); - break; - case 2: /* 60 hz */ - i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT, - OV7670_COM8_BFILT); - i2c_w_mask(sd, OV7670_R3B_COM11, 0x00, 0x18); - break; - case 3: /* Auto hz - ov7670 only */ - i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT, - OV7670_COM8_BFILT); - i2c_w_mask(sd, OV7670_R3B_COM11, OV7670_COM11_HZAUTO, - 0x18); - break; - } - } else { - switch (sd->ctrls[FREQ].val) { - case 0: /* Banding filter disabled */ - i2c_w_mask(sd, 0x2d, 0x00, 0x04); - i2c_w_mask(sd, 0x2a, 0x00, 0x80); - break; - case 1: /* 50 hz (filter on and framerate adj) */ - i2c_w_mask(sd, 0x2d, 0x04, 0x04); - i2c_w_mask(sd, 0x2a, 0x80, 0x80); - /* 20 fps -> 16.667 fps */ - if (sd->sensor == SEN_OV6620 || - sd->sensor == SEN_OV6630 || - sd->sensor == SEN_OV66308AF) - i2c_w(sd, 0x2b, 0x5e); - else - i2c_w(sd, 0x2b, 0xac); - break; - case 2: /* 60 hz (filter on, ...) */ - i2c_w_mask(sd, 0x2d, 0x04, 0x04); - if (sd->sensor == SEN_OV6620 || - sd->sensor == SEN_OV6630 || - sd->sensor == SEN_OV66308AF) { - /* 20 fps -> 15 fps */ - i2c_w_mask(sd, 0x2a, 0x80, 0x80); - i2c_w(sd, 0x2b, 0xa8); - } else { - /* no framerate adj. */ - i2c_w_mask(sd, 0x2a, 0x00, 0x80); - } - break; - } - } -} -static void setfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - setfreq_i(sd); - - /* Ugly but necessary */ - if (sd->bridge == BRIDGE_W9968CF) - w9968cf_set_crop_window(sd); -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - case 3: - if (sd->sensor != SEN_OV7670) - return -EINVAL; - - strcpy((char *) menu->name, "Automatic"); - return 0; - } - break; - } - return -EINVAL; -} - -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->bridge != BRIDGE_W9968CF) - return -EINVAL; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT | - V4L2_JPEG_MARKER_DRI; - return 0; -} - -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->bridge != BRIDGE_W9968CF) - return -EINVAL; - - if (gspca_dev->streaming) - return -EBUSY; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - - /* Return resulting jcomp params to app */ - sd_get_jcomp(gspca_dev, jcomp); - - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .isoc_init = sd_isoc_init, - .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = sd_reset_snapshot, - .querymenu = sd_querymenu, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .other_input = 1, -#endif -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF }, - {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4064), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, - {USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4068), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, - {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x054c, 0x0155), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, - {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 }, - {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 }, - {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 }, - {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x05a9, 0xa511), .driver_info = BRIDGE_OV511PLUS }, - {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS }, - {USB_DEVICE(0x0813, 0x0002), .driver_info = BRIDGE_OV511PLUS }, - {USB_DEVICE(0x0b62, 0x0059), .driver_info = BRIDGE_OVFX2 }, - {USB_DEVICE(0x0e96, 0xc001), .driver_info = BRIDGE_OVFX2 }, - {USB_DEVICE(0x1046, 0x9967), .driver_info = BRIDGE_W9968CF }, - {USB_DEVICE(0x8020, 0xef04), .driver_info = BRIDGE_OVFX2 }, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); - -module_param(frame_rate, int, 0644); -MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov534_9.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov534_9.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov534_9.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov534_9.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1469 +0,0 @@ -/* - * ov534-ov965x gspca driver - * - * Copyright (C) 2009-2010 Jean-Francois Moine http://moinejf.free.fr - * Copyright (C) 2008 Antonio Ospite - * Copyright (C) 2008 Jim Paris - * - * Based on a prototype written by Mark Ferrell - * USB protocol reverse engineered by Jim Paris - * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "ov534_9" - -#include "gspca.h" - -#define OV534_REG_ADDRESS 0xf1 /* sensor address */ -#define OV534_REG_SUBADDR 0xf2 -#define OV534_REG_WRITE 0xf3 -#define OV534_REG_READ 0xf4 -#define OV534_REG_OPERATION 0xf5 -#define OV534_REG_STATUS 0xf6 - -#define OV534_OP_WRITE_3 0x37 -#define OV534_OP_WRITE_2 0x33 -#define OV534_OP_READ_2 0xf9 - -#define CTRL_TIMEOUT 500 - -MODULE_AUTHOR("Jean-Francois Moine "); -MODULE_DESCRIPTION("GSPCA/OV534_9 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - __u32 last_pts; - u8 last_fid; - - u8 brightness; - u8 contrast; - u8 autogain; - u8 exposure; - s8 sharpness; - u8 satur; - u8 freq; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { /* 0 */ - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 15, - .step = 1, -#define BRIGHTNESS_DEF 7 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { /* 1 */ - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 15, - .step = 1, -#define CONTRAST_DEF 3 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { /* 2 */ - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Autogain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -#define EXPO_IDX 3 - { /* 3 */ - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 3, - .step = 1, -#define EXPO_DEF 0 - .default_value = EXPO_DEF, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { /* 4 */ - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = -1, /* -1 = auto */ - .maximum = 4, - .step = 1, -#define SHARPNESS_DEF -1 - .default_value = SHARPNESS_DEF, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, - { /* 5 */ - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 4, - .step = 1, -#define SATUR_DEF 2 - .default_value = SATUR_DEF, - }, - .set = sd_setsatur, - .get = sd_getsatur, - }, - { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, -#define FREQ_DEF 0 - .default_value = FREQ_DEF, - }, - .set = sd_setfreq, - .get = sd_getfreq, - }, -}; - -static const struct v4l2_pix_format ov965x_mode[] = { -#define QVGA_MODE 0 - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG}, -#define VGA_MODE 1 - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG}, -#define SVGA_MODE 2 - {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 800, - .sizeimage = 800 * 600 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG}, -#define XGA_MODE 3 - {1024, 768, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 1024, - .sizeimage = 1024 * 768 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG}, -#define SXGA_MODE 4 - {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 1280, - .sizeimage = 1280 * 1024 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG}, -}; - -static const u8 bridge_init[][2] = { - {0x88, 0xf8}, - {0x89, 0xff}, - {0x76, 0x03}, - {0x92, 0x03}, - {0x95, 0x10}, - {0xe2, 0x00}, - {0xe7, 0x3e}, - {0x8d, 0x1c}, - {0x8e, 0x00}, - {0x8f, 0x00}, - {0x1f, 0x00}, - {0xc3, 0xf9}, - {0x89, 0xff}, - {0x88, 0xf8}, - {0x76, 0x03}, - {0x92, 0x01}, - {0x93, 0x18}, - {0x1c, 0x0a}, - {0x1d, 0x48}, - {0xc0, 0x50}, - {0xc1, 0x3c}, - {0x34, 0x05}, - {0xc2, 0x0c}, - {0xc3, 0xf9}, - {0x34, 0x05}, - {0xe7, 0x2e}, - {0x31, 0xf9}, - {0x35, 0x02}, - {0xd9, 0x10}, - {0x25, 0x42}, - {0x94, 0x11}, -}; - -static const u8 sensor_init[][2] = { - {0x12, 0x80}, /* com7 - SSCB reset */ - {0x00, 0x00}, /* gain */ - {0x01, 0x80}, /* blue */ - {0x02, 0x80}, /* red */ - {0x03, 0x1b}, /* vref */ - {0x04, 0x03}, /* com1 - exposure low bits */ - {0x0b, 0x57}, /* ver */ - {0x0e, 0x61}, /* com5 */ - {0x0f, 0x42}, /* com6 */ - {0x11, 0x00}, /* clkrc */ - {0x12, 0x02}, /* com7 - 15fps VGA YUYV */ - {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ - {0x14, 0x28}, /* com9 */ - {0x16, 0x24}, /* reg16 */ - {0x17, 0x1d}, /* hstart*/ - {0x18, 0xbd}, /* hstop */ - {0x19, 0x01}, /* vstrt */ - {0x1a, 0x81}, /* vstop*/ - {0x1e, 0x04}, /* mvfp */ - {0x24, 0x3c}, /* aew */ - {0x25, 0x36}, /* aeb */ - {0x26, 0x71}, /* vpt */ - {0x27, 0x08}, /* bbias */ - {0x28, 0x08}, /* gbbias */ - {0x29, 0x15}, /* gr com */ - {0x2a, 0x00}, /* exhch */ - {0x2b, 0x00}, /* exhcl */ - {0x2c, 0x08}, /* rbias */ - {0x32, 0xff}, /* href */ - {0x33, 0x00}, /* chlf */ - {0x34, 0x3f}, /* aref1 */ - {0x35, 0x00}, /* aref2 */ - {0x36, 0xf8}, /* aref3 */ - {0x38, 0x72}, /* adc2 */ - {0x39, 0x57}, /* aref4 */ - {0x3a, 0x80}, /* tslb - yuyv */ - {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ - {0x3d, 0x99}, /* com13 */ - {0x3f, 0xc1}, /* edge */ - {0x40, 0xc0}, /* com15 */ - {0x41, 0x40}, /* com16 */ - {0x42, 0xc0}, /* com17 */ - {0x43, 0x0a}, /* rsvd */ - {0x44, 0xf0}, - {0x45, 0x46}, - {0x46, 0x62}, - {0x47, 0x2a}, - {0x48, 0x3c}, - {0x4a, 0xfc}, - {0x4b, 0xfc}, - {0x4c, 0x7f}, - {0x4d, 0x7f}, - {0x4e, 0x7f}, - {0x4f, 0x98}, /* matrix */ - {0x50, 0x98}, - {0x51, 0x00}, - {0x52, 0x28}, - {0x53, 0x70}, - {0x54, 0x98}, - {0x58, 0x1a}, /* matrix coef sign */ - {0x59, 0x85}, /* AWB control */ - {0x5a, 0xa9}, - {0x5b, 0x64}, - {0x5c, 0x84}, - {0x5d, 0x53}, - {0x5e, 0x0e}, - {0x5f, 0xf0}, /* AWB blue limit */ - {0x60, 0xf0}, /* AWB red limit */ - {0x61, 0xf0}, /* AWB green limit */ - {0x62, 0x00}, /* lcc1 */ - {0x63, 0x00}, /* lcc2 */ - {0x64, 0x02}, /* lcc3 */ - {0x65, 0x16}, /* lcc4 */ - {0x66, 0x01}, /* lcc5 */ - {0x69, 0x02}, /* hv */ - {0x6b, 0x5a}, /* dbvl */ - {0x6c, 0x04}, - {0x6d, 0x55}, - {0x6e, 0x00}, - {0x6f, 0x9d}, - {0x70, 0x21}, /* dnsth */ - {0x71, 0x78}, - {0x72, 0x00}, /* poidx */ - {0x73, 0x01}, /* pckdv */ - {0x74, 0x3a}, /* xindx */ - {0x75, 0x35}, /* yindx */ - {0x76, 0x01}, - {0x77, 0x02}, - {0x7a, 0x12}, /* gamma curve */ - {0x7b, 0x08}, - {0x7c, 0x16}, - {0x7d, 0x30}, - {0x7e, 0x5e}, - {0x7f, 0x72}, - {0x80, 0x82}, - {0x81, 0x8e}, - {0x82, 0x9a}, - {0x83, 0xa4}, - {0x84, 0xac}, - {0x85, 0xb8}, - {0x86, 0xc3}, - {0x87, 0xd6}, - {0x88, 0xe6}, - {0x89, 0xf2}, - {0x8a, 0x03}, - {0x8c, 0x89}, /* com19 */ - {0x14, 0x28}, /* com9 */ - {0x90, 0x7d}, - {0x91, 0x7b}, - {0x9d, 0x03}, /* lcc6 */ - {0x9e, 0x04}, /* lcc7 */ - {0x9f, 0x7a}, - {0xa0, 0x79}, - {0xa1, 0x40}, /* aechm */ - {0xa4, 0x50}, /* com21 */ - {0xa5, 0x68}, /* com26 */ - {0xa6, 0x4a}, /* AWB green */ - {0xa8, 0xc1}, /* refa8 */ - {0xa9, 0xef}, /* refa9 */ - {0xaa, 0x92}, - {0xab, 0x04}, - {0xac, 0x80}, /* black level control */ - {0xad, 0x80}, - {0xae, 0x80}, - {0xaf, 0x80}, - {0xb2, 0xf2}, - {0xb3, 0x20}, - {0xb4, 0x20}, /* ctrlb4 */ - {0xb5, 0x00}, - {0xb6, 0xaf}, - {0xbb, 0xae}, - {0xbc, 0x7f}, /* ADC channel offsets */ - {0xdb, 0x7f}, - {0xbe, 0x7f}, - {0xbf, 0x7f}, - {0xc0, 0xe2}, - {0xc1, 0xc0}, - {0xc2, 0x01}, - {0xc3, 0x4e}, - {0xc6, 0x85}, - {0xc7, 0x80}, /* com24 */ - {0xc9, 0xe0}, - {0xca, 0xe8}, - {0xcb, 0xf0}, - {0xcc, 0xd8}, - {0xcd, 0xf1}, - {0x4f, 0x98}, /* matrix */ - {0x50, 0x98}, - {0x51, 0x00}, - {0x52, 0x28}, - {0x53, 0x70}, - {0x54, 0x98}, - {0x58, 0x1a}, - {0xff, 0x41}, /* read 41, write ff 00 */ - {0x41, 0x40}, /* com16 */ - - {0xc5, 0x03}, /* 60 Hz banding filter */ - {0x6a, 0x02}, /* 50 Hz banding filter */ - - {0x12, 0x62}, /* com7 - 30fps VGA YUV */ - {0x36, 0xfa}, /* aref3 */ - {0x69, 0x0a}, /* hv */ - {0x8c, 0x89}, /* com22 */ - {0x14, 0x28}, /* com9 */ - {0x3e, 0x0c}, - {0x41, 0x40}, /* com16 */ - {0x72, 0x00}, - {0x73, 0x00}, - {0x74, 0x3a}, - {0x75, 0x35}, - {0x76, 0x01}, - {0xc7, 0x80}, - {0x03, 0x12}, /* vref */ - {0x17, 0x16}, /* hstart */ - {0x18, 0x02}, /* hstop */ - {0x19, 0x01}, /* vstrt */ - {0x1a, 0x3d}, /* vstop */ - {0x32, 0xff}, /* href */ - {0xc0, 0xaa}, -}; - -static const u8 bridge_init_2[][2] = { - {0x94, 0xaa}, - {0xf1, 0x60}, - {0xe5, 0x04}, - {0xc0, 0x50}, - {0xc1, 0x3c}, - {0x8c, 0x00}, - {0x8d, 0x1c}, - {0x34, 0x05}, - - {0xc2, 0x0c}, - {0xc3, 0xf9}, - {0xda, 0x01}, - {0x50, 0x00}, - {0x51, 0xa0}, - {0x52, 0x3c}, - {0x53, 0x00}, - {0x54, 0x00}, - {0x55, 0x00}, - {0x57, 0x00}, - {0x5c, 0x00}, - {0x5a, 0xa0}, - {0x5b, 0x78}, - {0x35, 0x02}, - {0xd9, 0x10}, - {0x94, 0x11}, -}; - -static const u8 sensor_init_2[][2] = { - {0x3b, 0xc4}, - {0x1e, 0x04}, /* mvfp */ - {0x13, 0xe0}, /* com8 */ - {0x00, 0x00}, /* gain */ - {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ - {0x11, 0x03}, /* clkrc */ - {0x6b, 0x5a}, /* dblv */ - {0x6a, 0x05}, - {0xc5, 0x07}, - {0xa2, 0x4b}, - {0xa3, 0x3e}, - {0x2d, 0x00}, - {0xff, 0x42}, /* read 42, write ff 00 */ - {0x42, 0xc0}, /* com17 */ - {0x2d, 0x00}, - {0xff, 0x42}, /* read 42, write ff 00 */ - {0x42, 0xc1}, /* com17 */ -/* sharpness */ - {0x3f, 0x01}, - {0xff, 0x42}, /* read 42, write ff 00 */ - {0x42, 0xc1}, /* com17 */ -/* saturation */ - {0x4f, 0x98}, /* matrix */ - {0x50, 0x98}, - {0x51, 0x00}, - {0x52, 0x28}, - {0x53, 0x70}, - {0x54, 0x98}, - {0x58, 0x1a}, - {0xff, 0x41}, /* read 41, write ff 00 */ - {0x41, 0x40}, /* com16 */ -/* contrast */ - {0x56, 0x40}, -/* brightness */ - {0x55, 0x8f}, -/* expo */ - {0x10, 0x25}, /* aech - exposure high bits */ - {0xff, 0x13}, /* read 13, write ff 00 */ - {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ -}; - -static const u8 sensor_start_1_vga[][2] = { /* same for qvga */ - {0x12, 0x62}, /* com7 - 30fps VGA YUV */ - {0x36, 0xfa}, /* aref3 */ - {0x69, 0x0a}, /* hv */ - {0x8c, 0x89}, /* com22 */ - {0x14, 0x28}, /* com9 */ - {0x3e, 0x0c}, /* com14 */ - {0x41, 0x40}, /* com16 */ - {0x72, 0x00}, - {0x73, 0x00}, - {0x74, 0x3a}, - {0x75, 0x35}, - {0x76, 0x01}, - {0xc7, 0x80}, /* com24 */ - {0x03, 0x12}, /* vref */ - {0x17, 0x16}, /* hstart */ - {0x18, 0x02}, /* hstop */ - {0x19, 0x01}, /* vstrt */ - {0x1a, 0x3d}, /* vstop */ - {0x32, 0xff}, /* href */ - {0xc0, 0xaa}, -}; - -static const u8 sensor_start_1_svga[][2] = { - {0x12, 0x02}, /* com7 - YUYV - VGA 15 full resolution */ - {0x36, 0xf8}, /* aref3 */ - {0x69, 0x02}, /* hv */ - {0x8c, 0x0d}, /* com22 */ - {0x3e, 0x0c}, /* com14 */ - {0x41, 0x40}, /* com16 */ - {0x72, 0x00}, - {0x73, 0x01}, - {0x74, 0x3a}, - {0x75, 0x35}, - {0x76, 0x01}, - {0xc7, 0x80}, /* com24 */ - {0x03, 0x1b}, /* vref */ - {0x17, 0x1d}, /* hstart */ - {0x18, 0xbd}, /* hstop */ - {0x19, 0x01}, /* vstrt */ - {0x1a, 0x81}, /* vstop */ - {0x32, 0xff}, /* href */ - {0xc0, 0xe2}, -}; - -static const u8 sensor_start_1_xga[][2] = { - {0x12, 0x02}, /* com7 */ - {0x36, 0xf8}, /* aref3 */ - {0x69, 0x02}, /* hv */ - {0x8c, 0x89}, /* com22 */ - {0x14, 0x28}, /* com9 */ - {0x3e, 0x0c}, /* com14 */ - {0x41, 0x40}, /* com16 */ - {0x72, 0x00}, - {0x73, 0x01}, - {0x74, 0x3a}, - {0x75, 0x35}, - {0x76, 0x01}, - {0xc7, 0x80}, /* com24 */ - {0x03, 0x1b}, /* vref */ - {0x17, 0x1d}, /* hstart */ - {0x18, 0xbd}, /* hstop */ - {0x19, 0x01}, /* vstrt */ - {0x1a, 0x81}, /* vstop */ - {0x32, 0xff}, /* href */ - {0xc0, 0xe2}, -}; - -static const u8 sensor_start_1_sxga[][2] = { - {0x12, 0x02}, /* com7 */ - {0x36, 0xf8}, /* aref3 */ - {0x69, 0x02}, /* hv */ - {0x8c, 0x89}, /* com22 */ - {0x14, 0x28}, /* com9 */ - {0x3e, 0x0c}, /* com14 */ - {0x41, 0x40}, /* com16 */ - {0x72, 0x00}, - {0x73, 0x01}, - {0x74, 0x3a}, - {0x75, 0x35}, - {0x76, 0x01}, - {0xc7, 0x80}, /* com24 */ - {0x03, 0x1b}, /* vref */ - {0x17, 0x1d}, /* hstart */ - {0x18, 0x02}, /* hstop */ - {0x19, 0x01}, /* vstrt */ - {0x1a, 0x81}, /* vstop */ - {0x32, 0xff}, /* href */ - {0xc0, 0xe2}, -}; - -static const u8 bridge_start_qvga[][2] = { - {0x94, 0xaa}, - {0xf1, 0x60}, - {0xe5, 0x04}, - {0xc0, 0x50}, - {0xc1, 0x3c}, - {0x8c, 0x00}, - {0x8d, 0x1c}, - {0x34, 0x05}, - - {0xc2, 0x4c}, - {0xc3, 0xf9}, - {0xda, 0x00}, - {0x50, 0x00}, - {0x51, 0xa0}, - {0x52, 0x78}, - {0x53, 0x00}, - {0x54, 0x00}, - {0x55, 0x00}, - {0x57, 0x00}, - {0x5c, 0x00}, - {0x5a, 0x50}, - {0x5b, 0x3c}, - {0x35, 0x02}, - {0xd9, 0x10}, - {0x94, 0x11}, -}; - -static const u8 bridge_start_vga[][2] = { - {0x94, 0xaa}, - {0xf1, 0x60}, - {0xe5, 0x04}, - {0xc0, 0x50}, - {0xc1, 0x3c}, - {0x8c, 0x00}, - {0x8d, 0x1c}, - {0x34, 0x05}, - {0xc2, 0x0c}, - {0xc3, 0xf9}, - {0xda, 0x01}, - {0x50, 0x00}, - {0x51, 0xa0}, - {0x52, 0x3c}, - {0x53, 0x00}, - {0x54, 0x00}, - {0x55, 0x00}, - {0x57, 0x00}, - {0x5c, 0x00}, - {0x5a, 0xa0}, - {0x5b, 0x78}, - {0x35, 0x02}, - {0xd9, 0x10}, - {0x94, 0x11}, -}; - -static const u8 bridge_start_svga[][2] = { - {0x94, 0xaa}, - {0xf1, 0x60}, - {0xe5, 0x04}, - {0xc0, 0xa0}, - {0xc1, 0x80}, - {0x8c, 0x00}, - {0x8d, 0x1c}, - {0x34, 0x05}, - {0xc2, 0x4c}, - {0xc3, 0xf9}, - {0x50, 0x00}, - {0x51, 0x40}, - {0x52, 0x00}, - {0x53, 0x00}, - {0x54, 0x00}, - {0x55, 0x88}, - {0x57, 0x00}, - {0x5c, 0x00}, - {0x5a, 0xc8}, - {0x5b, 0x96}, - {0x35, 0x02}, - {0xd9, 0x10}, - {0xda, 0x00}, - {0x94, 0x11}, -}; - -static const u8 bridge_start_xga[][2] = { - {0x94, 0xaa}, - {0xf1, 0x60}, - {0xe5, 0x04}, - {0xc0, 0xa0}, - {0xc1, 0x80}, - {0x8c, 0x00}, - {0x8d, 0x1c}, - {0x34, 0x05}, - {0xc2, 0x4c}, - {0xc3, 0xf9}, - {0x50, 0x00}, - {0x51, 0x40}, - {0x52, 0x00}, - {0x53, 0x00}, - {0x54, 0x00}, - {0x55, 0x88}, - {0x57, 0x00}, - {0x5c, 0x01}, - {0x5a, 0x00}, - {0x5b, 0xc0}, - {0x35, 0x02}, - {0xd9, 0x10}, - {0xda, 0x01}, - {0x94, 0x11}, -}; - -static const u8 bridge_start_sxga[][2] = { - {0x94, 0xaa}, - {0xf1, 0x60}, - {0xe5, 0x04}, - {0xc0, 0xa0}, - {0xc1, 0x80}, - {0x8c, 0x00}, - {0x8d, 0x1c}, - {0x34, 0x05}, - {0xc2, 0x0c}, - {0xc3, 0xf9}, - {0xda, 0x00}, - {0x35, 0x02}, - {0xd9, 0x10}, - {0x94, 0x11}, -}; - -static const u8 sensor_start_2_qvga[][2] = { - {0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */ - {0x1e, 0x04}, /* mvfp */ - {0x13, 0xe0}, /* com8 */ - {0x00, 0x00}, - {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ - {0x11, 0x01}, /* clkrc */ - {0x6b, 0x5a}, /* dblv */ - {0x6a, 0x02}, /* 50 Hz banding filter */ - {0xc5, 0x03}, /* 60 Hz banding filter */ - {0xa2, 0x96}, /* bd50 */ - {0xa3, 0x7d}, /* bd60 */ - - {0xff, 0x13}, /* read 13, write ff 00 */ - {0x13, 0xe7}, - {0x3a, 0x80}, /* tslb - yuyv */ -}; - -static const u8 sensor_start_2_vga[][2] = { - {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ - {0x1e, 0x04}, /* mvfp */ - {0x13, 0xe0}, /* com8 */ - {0x00, 0x00}, - {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ - {0x11, 0x03}, /* clkrc */ - {0x6b, 0x5a}, /* dblv */ - {0x6a, 0x05}, /* 50 Hz banding filter */ - {0xc5, 0x07}, /* 60 Hz banding filter */ - {0xa2, 0x4b}, /* bd50 */ - {0xa3, 0x3e}, /* bd60 */ - - {0x2d, 0x00}, /* advfl */ -}; - -static const u8 sensor_start_2_svga[][2] = { /* same for xga */ - {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ - {0x1e, 0x04}, /* mvfp */ - {0x13, 0xe0}, /* com8 */ - {0x00, 0x00}, - {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ - {0x11, 0x01}, /* clkrc */ - {0x6b, 0x5a}, /* dblv */ - {0x6a, 0x0c}, /* 50 Hz banding filter */ - {0xc5, 0x0f}, /* 60 Hz banding filter */ - {0xa2, 0x4e}, /* bd50 */ - {0xa3, 0x41}, /* bd60 */ -}; - -static const u8 sensor_start_2_sxga[][2] = { - {0x13, 0xe0}, /* com8 */ - {0x00, 0x00}, - {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ - {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ - {0x1e, 0x04}, /* mvfp */ - {0x11, 0x01}, /* clkrc */ - {0x6b, 0x5a}, /* dblv */ - {0x6a, 0x0c}, /* 50 Hz banding filter */ - {0xc5, 0x0f}, /* 60 Hz banding filter */ - {0xa2, 0x4e}, /* bd50 */ - {0xa3, 0x41}, /* bd60 */ -}; - -static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val) -{ - struct usb_device *udev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - gspca_dev->usb_buf[0] = val; - ret = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - 0x01, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); - if (ret < 0) { - err("reg_w failed %d", ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_w(struct gspca_dev *gspca_dev, u16 reg, u8 val) -{ - PDEBUG(D_USBO, "reg_w [%04x] = %02x", reg, val); - reg_w_i(gspca_dev, reg, val); -} - -static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg) -{ - struct usb_device *udev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return 0; - ret = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - 0x01, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); - PDEBUG(D_USBI, "reg_r [%04x] -> %02x", reg, gspca_dev->usb_buf[0]); - if (ret < 0) { - err("reg_r err %d", ret); - gspca_dev->usb_err = ret; - } - return gspca_dev->usb_buf[0]; -} - -static int sccb_check_status(struct gspca_dev *gspca_dev) -{ - u8 data; - int i; - - for (i = 0; i < 5; i++) { - data = reg_r(gspca_dev, OV534_REG_STATUS); - - switch (data) { - case 0x00: - return 1; - case 0x04: - return 0; - case 0x03: - break; - default: - PDEBUG(D_USBI|D_USBO, - "sccb status 0x%02x, attempt %d/5", - data, i + 1); - } - } - return 0; -} - -static void sccb_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) -{ - PDEBUG(D_USBO, "sccb_write [%02x] = %02x", reg, val); - reg_w_i(gspca_dev, OV534_REG_SUBADDR, reg); - reg_w_i(gspca_dev, OV534_REG_WRITE, val); - reg_w_i(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); - - if (!sccb_check_status(gspca_dev)) - err("sccb_write failed"); -} - -static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg) -{ - reg_w(gspca_dev, OV534_REG_SUBADDR, reg); - reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); - if (!sccb_check_status(gspca_dev)) - err("sccb_read failed 1"); - - reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); - if (!sccb_check_status(gspca_dev)) - err("sccb_read failed 2"); - - return reg_r(gspca_dev, OV534_REG_READ); -} - -/* output a bridge sequence (reg - val) */ -static void reg_w_array(struct gspca_dev *gspca_dev, - const u8 (*data)[2], int len) -{ - while (--len >= 0) { - reg_w(gspca_dev, (*data)[0], (*data)[1]); - data++; - } -} - -/* output a sensor sequence (reg - val) */ -static void sccb_w_array(struct gspca_dev *gspca_dev, - const u8 (*data)[2], int len) -{ - while (--len >= 0) { - if ((*data)[0] != 0xff) { - sccb_write(gspca_dev, (*data)[0], (*data)[1]); - } else { - sccb_read(gspca_dev, (*data)[1]); - sccb_write(gspca_dev, 0xff, 0x00); - } - data++; - } -} - -/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. - * (direction and output)? */ -static void set_led(struct gspca_dev *gspca_dev, int status) -{ - u8 data; - - PDEBUG(D_CONF, "led status: %d", status); - - data = reg_r(gspca_dev, 0x21); - data |= 0x80; - reg_w(gspca_dev, 0x21, data); - - data = reg_r(gspca_dev, 0x23); - if (status) - data |= 0x80; - else - data &= ~0x80; - - reg_w(gspca_dev, 0x23, data); - - if (!status) { - data = reg_r(gspca_dev, 0x21); - data &= ~0x80; - reg_w(gspca_dev, 0x21, data); - } -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - val = sd->brightness; - if (val < 8) - val = 15 - val; /* f .. 8 */ - else - val = val - 8; /* 0 .. 7 */ - sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */ - 0x0f | (val << 4)); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sccb_write(gspca_dev, 0x56, /* cnst1 - contrast 1 ctrl coeff */ - sd->contrast << 4); -} - -static void setautogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - -/*fixme: should adjust agc/awb/aec by different controls */ - val = sccb_read(gspca_dev, 0x13); /* com8 */ - sccb_write(gspca_dev, 0xff, 0x00); - if (sd->autogain) - val |= 0x05; /* agc & aec */ - else - val &= 0xfa; - sccb_write(gspca_dev, 0x13, val); -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e}; - - sccb_write(gspca_dev, 0x10, /* aec[9:2] */ - expo[sd->exposure]); - - val = sccb_read(gspca_dev, 0x13); /* com8 */ - sccb_write(gspca_dev, 0xff, 0x00); - sccb_write(gspca_dev, 0x13, val); - - val = sccb_read(gspca_dev, 0xa1); /* aech */ - sccb_write(gspca_dev, 0xff, 0x00); - sccb_write(gspca_dev, 0xa1, val & 0xe0); /* aec[15:10] = 0 */ -} - -static void setsharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - s8 val; - - val = sd->sharpness; - if (val < 0) { /* auto */ - val = sccb_read(gspca_dev, 0x42); /* com17 */ - sccb_write(gspca_dev, 0xff, 0x00); - sccb_write(gspca_dev, 0x42, val | 0x40); - /* Edge enhancement strength auto adjust */ - return; - } - if (val != 0) - val = 1 << (val - 1); - sccb_write(gspca_dev, 0x3f, /* edge - edge enhance. factor */ - val); - val = sccb_read(gspca_dev, 0x42); /* com17 */ - sccb_write(gspca_dev, 0xff, 0x00); - sccb_write(gspca_dev, 0x42, val & 0xbf); -} - -static void setsatur(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val1, val2, val3; - static const u8 matrix[5][2] = { - {0x14, 0x38}, - {0x1e, 0x54}, - {0x28, 0x70}, - {0x32, 0x8c}, - {0x48, 0x90} - }; - - val1 = matrix[sd->satur][0]; - val2 = matrix[sd->satur][1]; - val3 = val1 + val2; - sccb_write(gspca_dev, 0x4f, val3); /* matrix coeff */ - sccb_write(gspca_dev, 0x50, val3); - sccb_write(gspca_dev, 0x51, 0x00); - sccb_write(gspca_dev, 0x52, val1); - sccb_write(gspca_dev, 0x53, val2); - sccb_write(gspca_dev, 0x54, val3); - sccb_write(gspca_dev, 0x58, 0x1a); /* mtxs - coeff signs */ - - val1 = sccb_read(gspca_dev, 0x41); /* com16 */ - sccb_write(gspca_dev, 0xff, 0x00); - sccb_write(gspca_dev, 0x41, val1); -} - -static void setfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - val = sccb_read(gspca_dev, 0x13); /* com8 */ - sccb_write(gspca_dev, 0xff, 0x00); - if (sd->freq == 0) { - sccb_write(gspca_dev, 0x13, val & 0xdf); - return; - } - sccb_write(gspca_dev, 0x13, val | 0x20); - - val = sccb_read(gspca_dev, 0x42); /* com17 */ - sccb_write(gspca_dev, 0xff, 0x00); - if (sd->freq == 1) - val |= 0x01; - else - val &= 0xfe; - sccb_write(gspca_dev, 0x42, val); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - - cam->cam_mode = ov965x_mode; - cam->nmodes = ARRAY_SIZE(ov965x_mode); - - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; -#if AUTOGAIN_DEF != 0 - sd->autogain = AUTOGAIN_DEF; - gspca_dev->ctrl_inac |= (1 << EXPO_IDX); -#endif -#if EXPO_DEF != 0 - sd->exposure = EXPO_DEF; -#endif -#if SHARPNESS_DEF != 0 - sd->sharpness = SHARPNESS_DEF; -#endif - sd->satur = SATUR_DEF; - sd->freq = FREQ_DEF; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - u16 sensor_id; - - /* reset bridge */ - reg_w(gspca_dev, 0xe7, 0x3a); - reg_w(gspca_dev, 0xe0, 0x08); - msleep(100); - - /* initialize the sensor address */ - reg_w(gspca_dev, OV534_REG_ADDRESS, 0x60); - - /* reset sensor */ - sccb_write(gspca_dev, 0x12, 0x80); - msleep(10); - - /* probe the sensor */ - sccb_read(gspca_dev, 0x0a); - sensor_id = sccb_read(gspca_dev, 0x0a) << 8; - sccb_read(gspca_dev, 0x0b); - sensor_id |= sccb_read(gspca_dev, 0x0b); - PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id); - - /* initialize */ - reg_w_array(gspca_dev, bridge_init, - ARRAY_SIZE(bridge_init)); - sccb_w_array(gspca_dev, sensor_init, - ARRAY_SIZE(sensor_init)); - reg_w_array(gspca_dev, bridge_init_2, - ARRAY_SIZE(bridge_init_2)); - sccb_w_array(gspca_dev, sensor_init_2, - ARRAY_SIZE(sensor_init_2)); - reg_w(gspca_dev, 0xe0, 0x00); - reg_w(gspca_dev, 0xe0, 0x01); - set_led(gspca_dev, 0); - reg_w(gspca_dev, 0xe0, 0x00); - - return gspca_dev->usb_err; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - switch (gspca_dev->curr_mode) { - case QVGA_MODE: /* 320x240 */ - sccb_w_array(gspca_dev, sensor_start_1_vga, - ARRAY_SIZE(sensor_start_1_vga)); - reg_w_array(gspca_dev, bridge_start_qvga, - ARRAY_SIZE(bridge_start_qvga)); - sccb_w_array(gspca_dev, sensor_start_2_qvga, - ARRAY_SIZE(sensor_start_2_qvga)); - break; - case VGA_MODE: /* 640x480 */ - sccb_w_array(gspca_dev, sensor_start_1_vga, - ARRAY_SIZE(sensor_start_1_vga)); - reg_w_array(gspca_dev, bridge_start_vga, - ARRAY_SIZE(bridge_start_vga)); - sccb_w_array(gspca_dev, sensor_start_2_vga, - ARRAY_SIZE(sensor_start_2_vga)); - break; - case SVGA_MODE: /* 800x600 */ - sccb_w_array(gspca_dev, sensor_start_1_svga, - ARRAY_SIZE(sensor_start_1_svga)); - reg_w_array(gspca_dev, bridge_start_svga, - ARRAY_SIZE(bridge_start_svga)); - sccb_w_array(gspca_dev, sensor_start_2_svga, - ARRAY_SIZE(sensor_start_2_svga)); - break; - case XGA_MODE: /* 1024x768 */ - sccb_w_array(gspca_dev, sensor_start_1_xga, - ARRAY_SIZE(sensor_start_1_xga)); - reg_w_array(gspca_dev, bridge_start_xga, - ARRAY_SIZE(bridge_start_xga)); - sccb_w_array(gspca_dev, sensor_start_2_svga, - ARRAY_SIZE(sensor_start_2_svga)); - break; - default: -/* case SXGA_MODE: * 1280x1024 */ - sccb_w_array(gspca_dev, sensor_start_1_sxga, - ARRAY_SIZE(sensor_start_1_sxga)); - reg_w_array(gspca_dev, bridge_start_sxga, - ARRAY_SIZE(bridge_start_sxga)); - sccb_w_array(gspca_dev, sensor_start_2_sxga, - ARRAY_SIZE(sensor_start_2_sxga)); - break; - } - setfreq(gspca_dev); - setautogain(gspca_dev); - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setexposure(gspca_dev); - setsharpness(gspca_dev); - setsatur(gspca_dev); - - reg_w(gspca_dev, 0xe0, 0x00); - reg_w(gspca_dev, 0xe0, 0x00); - set_led(gspca_dev, 1); - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev, 0xe0, 0x01); - set_led(gspca_dev, 0); - reg_w(gspca_dev, 0xe0, 0x00); -} - -/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ -#define UVC_STREAM_EOH (1 << 7) -#define UVC_STREAM_ERR (1 << 6) -#define UVC_STREAM_STI (1 << 5) -#define UVC_STREAM_RES (1 << 4) -#define UVC_STREAM_SCR (1 << 3) -#define UVC_STREAM_PTS (1 << 2) -#define UVC_STREAM_EOF (1 << 1) -#define UVC_STREAM_FID (1 << 0) - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u32 this_pts; - u8 this_fid; - int remaining_len = len; - - do { - len = min(remaining_len, 2040); - - /* Payloads are prefixed with a UVC-style header. We - consider a frame to start when the FID toggles, or the PTS - changes. A frame ends when EOF is set, and we've received - the correct number of bytes. */ - - /* Verify UVC header. Header length is always 12 */ - if (data[0] != 12 || len < 12) { - PDEBUG(D_PACK, "bad header"); - goto discard; - } - - /* Check errors */ - if (data[1] & UVC_STREAM_ERR) { - PDEBUG(D_PACK, "payload error"); - goto discard; - } - - /* Extract PTS and FID */ - if (!(data[1] & UVC_STREAM_PTS)) { - PDEBUG(D_PACK, "PTS not present"); - goto discard; - } - this_pts = (data[5] << 24) | (data[4] << 16) - | (data[3] << 8) | data[2]; - this_fid = data[1] & UVC_STREAM_FID; - - /* If PTS or FID has changed, start a new frame. */ - if (this_pts != sd->last_pts || this_fid != sd->last_fid) { - if (gspca_dev->last_packet_type == INTER_PACKET) - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - sd->last_pts = this_pts; - sd->last_fid = this_fid; - gspca_frame_add(gspca_dev, FIRST_PACKET, - data + 12, len - 12); - /* If this packet is marked as EOF, end the frame */ - } else if (data[1] & UVC_STREAM_EOF) { - sd->last_pts = 0; - gspca_frame_add(gspca_dev, LAST_PACKET, - data + 12, len - 12); - } else { - - /* Add the data from this payload */ - gspca_frame_add(gspca_dev, INTER_PACKET, - data + 12, len - 12); - } - - /* Done this payload */ - goto scan_next; - -discard: - /* Discard data until a new frame starts. */ - gspca_dev->last_packet_type = DISCARD_PACKET; - -scan_next: - remaining_len -= len; - data += len; - } while (remaining_len > 0); -} - -/* controls */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - - if (gspca_dev->streaming) { - if (val) - gspca_dev->ctrl_inac |= (1 << EXPO_IDX); - else - gspca_dev->ctrl_inac &= ~(1 << EXPO_IDX); - setautogain(gspca_dev); - } - return gspca_dev->usb_err; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - return 0; -} - -static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->satur = val; - if (gspca_dev->streaming) - setsatur(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->satur; - return 0; -} -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->freq = val; - if (gspca_dev->streaming) - setfreq(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->freq; - return 0; -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - } - return -EINVAL; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x06f8, 0x3003)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov534.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov534.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov534.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/ov534.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1546 +0,0 @@ -/* - * ov534-ov7xxx gspca driver - * - * Copyright (C) 2008 Antonio Ospite - * Copyright (C) 2008 Jim Paris - * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr - * - * Based on a prototype written by Mark Ferrell - * USB protocol reverse engineered by Jim Paris - * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ - * - * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr - * PS3 Eye camera - brightness, contrast, awb, agc, aec controls - * added by Max Thrun - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "ov534" - -#include "gspca.h" - -#define OV534_REG_ADDRESS 0xf1 /* sensor address */ -#define OV534_REG_SUBADDR 0xf2 -#define OV534_REG_WRITE 0xf3 -#define OV534_REG_READ 0xf4 -#define OV534_REG_OPERATION 0xf5 -#define OV534_REG_STATUS 0xf6 - -#define OV534_OP_WRITE_3 0x37 -#define OV534_OP_WRITE_2 0x33 -#define OV534_OP_READ_2 0xf9 - -#define CTRL_TIMEOUT 500 - -MODULE_AUTHOR("Antonio Ospite "); -MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - GAIN, - EXPOSURE, - AGC, - AWB, - AEC, - SHARPNESS, - HFLIP, - VFLIP, - COLORS, - LIGHTFREQ, - NCTRLS /* number of controls */ -}; - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRLS]; - - __u32 last_pts; - u16 last_fid; - u8 frame_rate; - - u8 sensor; -}; -enum sensors { - SENSOR_OV767x, - SENSOR_OV772x, - NSENSORS -}; - -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); -static void setgain(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val); -static void setawb(struct gspca_dev *gspca_dev); -static void setaec(struct gspca_dev *gspca_dev); -static void setsharpness(struct gspca_dev *gspca_dev); -static void sethvflip(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void setlightfreq(struct gspca_dev *gspca_dev); - -static int sd_start(struct gspca_dev *gspca_dev); -static void sd_stopN(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0, - }, - .set_control = setbrightness - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 32, - }, - .set_control = setcontrast - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Main Gain", - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 20, - }, - .set_control = setgain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 120, - }, - .set_control = setexposure - }, -[AGC] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set = sd_setagc - }, -[AWB] = { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto White Balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set_control = setawb - }, -[AEC] = { - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set_control = setaec - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 0, - }, - .set_control = setsharpness - }, -[HFLIP] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "HFlip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip - }, -[VFLIP] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "VFlip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip - }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 6, - .step = 1, - .default_value = 3, - }, - .set_control = setcolors - }, -[LIGHTFREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light Frequency Filter", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = setlightfreq - }, -}; - -static const struct v4l2_pix_format ov772x_mode[] = { - {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 320 * 2, - .sizeimage = 320 * 240 * 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 640 * 2, - .sizeimage = 640 * 480 * 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; -static const struct v4l2_pix_format ov767x_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG}, -}; - -static const u8 qvga_rates[] = {125, 100, 75, 60, 50, 40, 30}; -static const u8 vga_rates[] = {60, 50, 40, 30, 15}; - -static const struct framerates ov772x_framerates[] = { - { /* 320x240 */ - .rates = qvga_rates, - .nrates = ARRAY_SIZE(qvga_rates), - }, - { /* 640x480 */ - .rates = vga_rates, - .nrates = ARRAY_SIZE(vga_rates), - }, -}; - -struct reg_array { - const u8 (*val)[2]; - int len; -}; - -static const u8 bridge_init_767x[][2] = { -/* comments from the ms-win file apollo7670.set */ -/* str1 */ - {0xf1, 0x42}, - {0x88, 0xf8}, - {0x89, 0xff}, - {0x76, 0x03}, - {0x92, 0x03}, - {0x95, 0x10}, - {0xe2, 0x00}, - {0xe7, 0x3e}, - {0x8d, 0x1c}, - {0x8e, 0x00}, - {0x8f, 0x00}, - {0x1f, 0x00}, - {0xc3, 0xf9}, - {0x89, 0xff}, - {0x88, 0xf8}, - {0x76, 0x03}, - {0x92, 0x01}, - {0x93, 0x18}, - {0x1c, 0x00}, - {0x1d, 0x48}, - {0x1d, 0x00}, - {0x1d, 0xff}, - {0x1d, 0x02}, - {0x1d, 0x58}, - {0x1d, 0x00}, - {0x1c, 0x0a}, - {0x1d, 0x0a}, - {0x1d, 0x0e}, - {0xc0, 0x50}, /* HSize 640 */ - {0xc1, 0x3c}, /* VSize 480 */ - {0x34, 0x05}, /* enable Audio Suspend mode */ - {0xc2, 0x0c}, /* Input YUV */ - {0xc3, 0xf9}, /* enable PRE */ - {0x34, 0x05}, /* enable Audio Suspend mode */ - {0xe7, 0x2e}, /* this solves failure of "SuspendResumeTest" */ - {0x31, 0xf9}, /* enable 1.8V Suspend */ - {0x35, 0x02}, /* turn on JPEG */ - {0xd9, 0x10}, - {0x25, 0x42}, /* GPIO[8]:Input */ - {0x94, 0x11}, /* If the default setting is loaded when - * system boots up, this flag is closed here */ -}; -static const u8 sensor_init_767x[][2] = { - {0x12, 0x80}, - {0x11, 0x03}, - {0x3a, 0x04}, - {0x12, 0x00}, - {0x17, 0x13}, - {0x18, 0x01}, - {0x32, 0xb6}, - {0x19, 0x02}, - {0x1a, 0x7a}, - {0x03, 0x0a}, - {0x0c, 0x00}, - {0x3e, 0x00}, - {0x70, 0x3a}, - {0x71, 0x35}, - {0x72, 0x11}, - {0x73, 0xf0}, - {0xa2, 0x02}, - {0x7a, 0x2a}, /* set Gamma=1.6 below */ - {0x7b, 0x12}, - {0x7c, 0x1d}, - {0x7d, 0x2d}, - {0x7e, 0x45}, - {0x7f, 0x50}, - {0x80, 0x59}, - {0x81, 0x62}, - {0x82, 0x6b}, - {0x83, 0x73}, - {0x84, 0x7b}, - {0x85, 0x8a}, - {0x86, 0x98}, - {0x87, 0xb2}, - {0x88, 0xca}, - {0x89, 0xe0}, - {0x13, 0xe0}, - {0x00, 0x00}, - {0x10, 0x00}, - {0x0d, 0x40}, - {0x14, 0x38}, /* gain max 16x */ - {0xa5, 0x05}, - {0xab, 0x07}, - {0x24, 0x95}, - {0x25, 0x33}, - {0x26, 0xe3}, - {0x9f, 0x78}, - {0xa0, 0x68}, - {0xa1, 0x03}, - {0xa6, 0xd8}, - {0xa7, 0xd8}, - {0xa8, 0xf0}, - {0xa9, 0x90}, - {0xaa, 0x94}, - {0x13, 0xe5}, - {0x0e, 0x61}, - {0x0f, 0x4b}, - {0x16, 0x02}, - {0x21, 0x02}, - {0x22, 0x91}, - {0x29, 0x07}, - {0x33, 0x0b}, - {0x35, 0x0b}, - {0x37, 0x1d}, - {0x38, 0x71}, - {0x39, 0x2a}, - {0x3c, 0x78}, - {0x4d, 0x40}, - {0x4e, 0x20}, - {0x69, 0x00}, - {0x6b, 0x4a}, - {0x74, 0x10}, - {0x8d, 0x4f}, - {0x8e, 0x00}, - {0x8f, 0x00}, - {0x90, 0x00}, - {0x91, 0x00}, - {0x96, 0x00}, - {0x9a, 0x80}, - {0xb0, 0x84}, - {0xb1, 0x0c}, - {0xb2, 0x0e}, - {0xb3, 0x82}, - {0xb8, 0x0a}, - {0x43, 0x0a}, - {0x44, 0xf0}, - {0x45, 0x34}, - {0x46, 0x58}, - {0x47, 0x28}, - {0x48, 0x3a}, - {0x59, 0x88}, - {0x5a, 0x88}, - {0x5b, 0x44}, - {0x5c, 0x67}, - {0x5d, 0x49}, - {0x5e, 0x0e}, - {0x6c, 0x0a}, - {0x6d, 0x55}, - {0x6e, 0x11}, - {0x6f, 0x9f}, - {0x6a, 0x40}, - {0x01, 0x40}, - {0x02, 0x40}, - {0x13, 0xe7}, - {0x4f, 0x80}, - {0x50, 0x80}, - {0x51, 0x00}, - {0x52, 0x22}, - {0x53, 0x5e}, - {0x54, 0x80}, - {0x58, 0x9e}, - {0x41, 0x08}, - {0x3f, 0x00}, - {0x75, 0x04}, - {0x76, 0xe1}, - {0x4c, 0x00}, - {0x77, 0x01}, - {0x3d, 0xc2}, - {0x4b, 0x09}, - {0xc9, 0x60}, - {0x41, 0x38}, /* jfm: auto sharpness + auto de-noise */ - {0x56, 0x40}, - {0x34, 0x11}, - {0x3b, 0xc2}, - {0xa4, 0x8a}, /* Night mode trigger point */ - {0x96, 0x00}, - {0x97, 0x30}, - {0x98, 0x20}, - {0x99, 0x20}, - {0x9a, 0x84}, - {0x9b, 0x29}, - {0x9c, 0x03}, - {0x9d, 0x4c}, - {0x9e, 0x3f}, - {0x78, 0x04}, - {0x79, 0x01}, - {0xc8, 0xf0}, - {0x79, 0x0f}, - {0xc8, 0x00}, - {0x79, 0x10}, - {0xc8, 0x7e}, - {0x79, 0x0a}, - {0xc8, 0x80}, - {0x79, 0x0b}, - {0xc8, 0x01}, - {0x79, 0x0c}, - {0xc8, 0x0f}, - {0x79, 0x0d}, - {0xc8, 0x20}, - {0x79, 0x09}, - {0xc8, 0x80}, - {0x79, 0x02}, - {0xc8, 0xc0}, - {0x79, 0x03}, - {0xc8, 0x20}, - {0x79, 0x26}, -}; -static const u8 bridge_start_vga_767x[][2] = { -/* str59 JPG */ - {0x94, 0xaa}, - {0xf1, 0x42}, - {0xe5, 0x04}, - {0xc0, 0x50}, - {0xc1, 0x3c}, - {0xc2, 0x0c}, - {0x35, 0x02}, /* turn on JPEG */ - {0xd9, 0x10}, - {0xda, 0x00}, /* for higher clock rate(30fps) */ - {0x34, 0x05}, /* enable Audio Suspend mode */ - {0xc3, 0xf9}, /* enable PRE */ - {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ - {0x8d, 0x1c}, /* output YUV */ -/* {0x34, 0x05}, * enable Audio Suspend mode (?) */ - {0x50, 0x00}, /* H/V divider=0 */ - {0x51, 0xa0}, /* input H=640/4 */ - {0x52, 0x3c}, /* input V=480/4 */ - {0x53, 0x00}, /* offset X=0 */ - {0x54, 0x00}, /* offset Y=0 */ - {0x55, 0x00}, /* H/V size[8]=0 */ - {0x57, 0x00}, /* H-size[9]=0 */ - {0x5c, 0x00}, /* output size[9:8]=0 */ - {0x5a, 0xa0}, /* output H=640/4 */ - {0x5b, 0x78}, /* output V=480/4 */ - {0x1c, 0x0a}, - {0x1d, 0x0a}, - {0x94, 0x11}, -}; -static const u8 sensor_start_vga_767x[][2] = { - {0x11, 0x01}, - {0x1e, 0x04}, - {0x19, 0x02}, - {0x1a, 0x7a}, -}; -static const u8 bridge_start_qvga_767x[][2] = { -/* str86 JPG */ - {0x94, 0xaa}, - {0xf1, 0x42}, - {0xe5, 0x04}, - {0xc0, 0x80}, - {0xc1, 0x60}, - {0xc2, 0x0c}, - {0x35, 0x02}, /* turn on JPEG */ - {0xd9, 0x10}, - {0xc0, 0x50}, /* CIF HSize 640 */ - {0xc1, 0x3c}, /* CIF VSize 480 */ - {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ - {0x8d, 0x1c}, /* output YUV */ - {0x34, 0x05}, /* enable Audio Suspend mode */ - {0xc2, 0x4c}, /* output YUV and Enable DCW */ - {0xc3, 0xf9}, /* enable PRE */ - {0x1c, 0x00}, /* indirect addressing */ - {0x1d, 0x48}, /* output YUV422 */ - {0x50, 0x89}, /* H/V divider=/2; plus DCW AVG */ - {0x51, 0xa0}, /* DCW input H=640/4 */ - {0x52, 0x78}, /* DCW input V=480/4 */ - {0x53, 0x00}, /* offset X=0 */ - {0x54, 0x00}, /* offset Y=0 */ - {0x55, 0x00}, /* H/V size[8]=0 */ - {0x57, 0x00}, /* H-size[9]=0 */ - {0x5c, 0x00}, /* DCW output size[9:8]=0 */ - {0x5a, 0x50}, /* DCW output H=320/4 */ - {0x5b, 0x3c}, /* DCW output V=240/4 */ - {0x1c, 0x0a}, - {0x1d, 0x0a}, - {0x94, 0x11}, -}; -static const u8 sensor_start_qvga_767x[][2] = { - {0x11, 0x01}, - {0x1e, 0x04}, - {0x19, 0x02}, - {0x1a, 0x7a}, -}; - -static const u8 bridge_init_772x[][2] = { - { 0xc2, 0x0c }, - { 0x88, 0xf8 }, - { 0xc3, 0x69 }, - { 0x89, 0xff }, - { 0x76, 0x03 }, - { 0x92, 0x01 }, - { 0x93, 0x18 }, - { 0x94, 0x10 }, - { 0x95, 0x10 }, - { 0xe2, 0x00 }, - { 0xe7, 0x3e }, - - { 0x96, 0x00 }, - - { 0x97, 0x20 }, - { 0x97, 0x20 }, - { 0x97, 0x20 }, - { 0x97, 0x0a }, - { 0x97, 0x3f }, - { 0x97, 0x4a }, - { 0x97, 0x20 }, - { 0x97, 0x15 }, - { 0x97, 0x0b }, - - { 0x8e, 0x40 }, - { 0x1f, 0x81 }, - { 0x34, 0x05 }, - { 0xe3, 0x04 }, - { 0x88, 0x00 }, - { 0x89, 0x00 }, - { 0x76, 0x00 }, - { 0xe7, 0x2e }, - { 0x31, 0xf9 }, - { 0x25, 0x42 }, - { 0x21, 0xf0 }, - - { 0x1c, 0x00 }, - { 0x1d, 0x40 }, - { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */ - { 0x1d, 0x00 }, /* payload size */ - - { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */ - { 0x1d, 0x58 }, /* frame size */ - { 0x1d, 0x00 }, /* frame size */ - - { 0x1c, 0x0a }, - { 0x1d, 0x08 }, /* turn on UVC header */ - { 0x1d, 0x0e }, /* .. */ - - { 0x8d, 0x1c }, - { 0x8e, 0x80 }, - { 0xe5, 0x04 }, - - { 0xc0, 0x50 }, - { 0xc1, 0x3c }, - { 0xc2, 0x0c }, -}; -static const u8 sensor_init_772x[][2] = { - { 0x12, 0x80 }, - { 0x11, 0x01 }, -/*fixme: better have a delay?*/ - { 0x11, 0x01 }, - { 0x11, 0x01 }, - { 0x11, 0x01 }, - { 0x11, 0x01 }, - { 0x11, 0x01 }, - { 0x11, 0x01 }, - { 0x11, 0x01 }, - { 0x11, 0x01 }, - { 0x11, 0x01 }, - { 0x11, 0x01 }, - - { 0x3d, 0x03 }, - { 0x17, 0x26 }, - { 0x18, 0xa0 }, - { 0x19, 0x07 }, - { 0x1a, 0xf0 }, - { 0x32, 0x00 }, - { 0x29, 0xa0 }, - { 0x2c, 0xf0 }, - { 0x65, 0x20 }, - { 0x11, 0x01 }, - { 0x42, 0x7f }, - { 0x63, 0xaa }, /* AWB - was e0 */ - { 0x64, 0xff }, - { 0x66, 0x00 }, - { 0x13, 0xf0 }, /* com8 */ - { 0x0d, 0x41 }, - { 0x0f, 0xc5 }, - { 0x14, 0x11 }, - - { 0x22, 0x7f }, - { 0x23, 0x03 }, - { 0x24, 0x40 }, - { 0x25, 0x30 }, - { 0x26, 0xa1 }, - { 0x2a, 0x00 }, - { 0x2b, 0x00 }, - { 0x6b, 0xaa }, - { 0x13, 0xff }, /* AWB */ - - { 0x90, 0x05 }, - { 0x91, 0x01 }, - { 0x92, 0x03 }, - { 0x93, 0x00 }, - { 0x94, 0x60 }, - { 0x95, 0x3c }, - { 0x96, 0x24 }, - { 0x97, 0x1e }, - { 0x98, 0x62 }, - { 0x99, 0x80 }, - { 0x9a, 0x1e }, - { 0x9b, 0x08 }, - { 0x9c, 0x20 }, - { 0x9e, 0x81 }, - - { 0xa6, 0x04 }, - { 0x7e, 0x0c }, - { 0x7f, 0x16 }, - { 0x80, 0x2a }, - { 0x81, 0x4e }, - { 0x82, 0x61 }, - { 0x83, 0x6f }, - { 0x84, 0x7b }, - { 0x85, 0x86 }, - { 0x86, 0x8e }, - { 0x87, 0x97 }, - { 0x88, 0xa4 }, - { 0x89, 0xaf }, - { 0x8a, 0xc5 }, - { 0x8b, 0xd7 }, - { 0x8c, 0xe8 }, - { 0x8d, 0x20 }, - - { 0x0c, 0x90 }, - - { 0x2b, 0x00 }, - { 0x22, 0x7f }, - { 0x23, 0x03 }, - { 0x11, 0x01 }, - { 0x0c, 0xd0 }, - { 0x64, 0xff }, - { 0x0d, 0x41 }, - - { 0x14, 0x41 }, - { 0x0e, 0xcd }, - { 0xac, 0xbf }, - { 0x8e, 0x00 }, /* De-noise threshold */ - { 0x0c, 0xd0 } -}; -static const u8 bridge_start_vga_772x[][2] = { - {0x1c, 0x00}, - {0x1d, 0x40}, - {0x1d, 0x02}, - {0x1d, 0x00}, - {0x1d, 0x02}, - {0x1d, 0x58}, - {0x1d, 0x00}, - {0xc0, 0x50}, - {0xc1, 0x3c}, -}; -static const u8 sensor_start_vga_772x[][2] = { - {0x12, 0x00}, - {0x17, 0x26}, - {0x18, 0xa0}, - {0x19, 0x07}, - {0x1a, 0xf0}, - {0x29, 0xa0}, - {0x2c, 0xf0}, - {0x65, 0x20}, -}; -static const u8 bridge_start_qvga_772x[][2] = { - {0x1c, 0x00}, - {0x1d, 0x40}, - {0x1d, 0x02}, - {0x1d, 0x00}, - {0x1d, 0x01}, - {0x1d, 0x4b}, - {0x1d, 0x00}, - {0xc0, 0x28}, - {0xc1, 0x1e}, -}; -static const u8 sensor_start_qvga_772x[][2] = { - {0x12, 0x40}, - {0x17, 0x3f}, - {0x18, 0x50}, - {0x19, 0x03}, - {0x1a, 0x78}, - {0x29, 0x50}, - {0x2c, 0x78}, - {0x65, 0x2f}, -}; - -static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) -{ - struct usb_device *udev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - - PDEBUG(D_USBO, "SET 01 0000 %04x %02x", reg, val); - gspca_dev->usb_buf[0] = val; - ret = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - 0x01, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); - if (ret < 0) { - err("write failed %d", ret); - gspca_dev->usb_err = ret; - } -} - -static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) -{ - struct usb_device *udev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return 0; - ret = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - 0x01, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); - PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]); - if (ret < 0) { - err("read failed %d", ret); - gspca_dev->usb_err = ret; - } - return gspca_dev->usb_buf[0]; -} - -/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. - * (direction and output)? */ -static void ov534_set_led(struct gspca_dev *gspca_dev, int status) -{ - u8 data; - - PDEBUG(D_CONF, "led status: %d", status); - - data = ov534_reg_read(gspca_dev, 0x21); - data |= 0x80; - ov534_reg_write(gspca_dev, 0x21, data); - - data = ov534_reg_read(gspca_dev, 0x23); - if (status) - data |= 0x80; - else - data &= ~0x80; - - ov534_reg_write(gspca_dev, 0x23, data); - - if (!status) { - data = ov534_reg_read(gspca_dev, 0x21); - data &= ~0x80; - ov534_reg_write(gspca_dev, 0x21, data); - } -} - -static int sccb_check_status(struct gspca_dev *gspca_dev) -{ - u8 data; - int i; - - for (i = 0; i < 5; i++) { - data = ov534_reg_read(gspca_dev, OV534_REG_STATUS); - - switch (data) { - case 0x00: - return 1; - case 0x04: - return 0; - case 0x03: - break; - default: - PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5", - data, i + 1); - } - } - return 0; -} - -static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) -{ - PDEBUG(D_USBO, "sccb write: %02x %02x", reg, val); - ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); - ov534_reg_write(gspca_dev, OV534_REG_WRITE, val); - ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); - - if (!sccb_check_status(gspca_dev)) { - err("sccb_reg_write failed"); - gspca_dev->usb_err = -EIO; - } -} - -static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg) -{ - ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); - ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); - if (!sccb_check_status(gspca_dev)) - err("sccb_reg_read failed 1"); - - ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); - if (!sccb_check_status(gspca_dev)) - err("sccb_reg_read failed 2"); - - return ov534_reg_read(gspca_dev, OV534_REG_READ); -} - -/* output a bridge sequence (reg - val) */ -static void reg_w_array(struct gspca_dev *gspca_dev, - const u8 (*data)[2], int len) -{ - while (--len >= 0) { - ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]); - data++; - } -} - -/* output a sensor sequence (reg - val) */ -static void sccb_w_array(struct gspca_dev *gspca_dev, - const u8 (*data)[2], int len) -{ - while (--len >= 0) { - if ((*data)[0] != 0xff) { - sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]); - } else { - sccb_reg_read(gspca_dev, (*data)[1]); - sccb_reg_write(gspca_dev, 0xff, 0x00); - } - data++; - } -} - -/* ov772x specific controls */ -static void set_frame_rate(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - struct rate_s { - u8 fps; - u8 r11; - u8 r0d; - u8 re5; - }; - const struct rate_s *r; - static const struct rate_s rate_0[] = { /* 640x480 */ - {60, 0x01, 0xc1, 0x04}, - {50, 0x01, 0x41, 0x02}, - {40, 0x02, 0xc1, 0x04}, - {30, 0x04, 0x81, 0x02}, - {15, 0x03, 0x41, 0x04}, - }; - static const struct rate_s rate_1[] = { /* 320x240 */ - {125, 0x02, 0x81, 0x02}, - {100, 0x02, 0xc1, 0x04}, - {75, 0x03, 0xc1, 0x04}, - {60, 0x04, 0xc1, 0x04}, - {50, 0x02, 0x41, 0x04}, - {40, 0x03, 0x41, 0x04}, - {30, 0x04, 0x41, 0x04}, - }; - - if (sd->sensor != SENSOR_OV772x) - return; - if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) { - r = rate_0; - i = ARRAY_SIZE(rate_0); - } else { - r = rate_1; - i = ARRAY_SIZE(rate_1); - } - while (--i > 0) { - if (sd->frame_rate >= r->fps) - break; - r++; - } - - sccb_reg_write(gspca_dev, 0x11, r->r11); - sccb_reg_write(gspca_dev, 0x0d, r->r0d); - ov534_reg_write(gspca_dev, 0xe5, r->re5); - - PDEBUG(D_PROBE, "frame_rate: %d", r->fps); -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int val; - - val = sd->ctrls[BRIGHTNESS].val; - if (sd->sensor == SENSOR_OV767x) { - if (val < 0) - val = 0x80 - val; - sccb_reg_write(gspca_dev, 0x55, val); /* bright */ - } else { - sccb_reg_write(gspca_dev, 0x9b, val); - } -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - val = sd->ctrls[CONTRAST].val; - if (sd->sensor == SENSOR_OV767x) - sccb_reg_write(gspca_dev, 0x56, val); /* contras */ - else - sccb_reg_write(gspca_dev, 0x9c, val); -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - if (sd->ctrls[AGC].val) - return; - - val = sd->ctrls[GAIN].val; - switch (val & 0x30) { - case 0x00: - val &= 0x0f; - break; - case 0x10: - val &= 0x0f; - val |= 0x30; - break; - case 0x20: - val &= 0x0f; - val |= 0x70; - break; - default: -/* case 0x30: */ - val &= 0x0f; - val |= 0xf0; - break; - } - sccb_reg_write(gspca_dev, 0x00, val); -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - if (sd->ctrls[AEC].val) - return; - - val = sd->ctrls[EXPOSURE].val; - if (sd->sensor == SENSOR_OV767x) { - - /* set only aec[9:2] */ - sccb_reg_write(gspca_dev, 0x10, val); /* aech */ - } else { - - /* 'val' is one byte and represents half of the exposure value - * we are going to set into registers, a two bytes value: - * - * MSB: ((u16) val << 1) >> 8 == val >> 7 - * LSB: ((u16) val << 1) & 0xff == val << 1 - */ - sccb_reg_write(gspca_dev, 0x08, val >> 7); - sccb_reg_write(gspca_dev, 0x10, val << 1); - } -} - -static void setagc(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->ctrls[AGC].val) { - sccb_reg_write(gspca_dev, 0x13, - sccb_reg_read(gspca_dev, 0x13) | 0x04); - sccb_reg_write(gspca_dev, 0x64, - sccb_reg_read(gspca_dev, 0x64) | 0x03); - } else { - sccb_reg_write(gspca_dev, 0x13, - sccb_reg_read(gspca_dev, 0x13) & ~0x04); - sccb_reg_write(gspca_dev, 0x64, - sccb_reg_read(gspca_dev, 0x64) & ~0x03); - - setgain(gspca_dev); - } -} - -static void setawb(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->ctrls[AWB].val) { - sccb_reg_write(gspca_dev, 0x13, - sccb_reg_read(gspca_dev, 0x13) | 0x02); - if (sd->sensor == SENSOR_OV772x) - sccb_reg_write(gspca_dev, 0x63, - sccb_reg_read(gspca_dev, 0x63) | 0xc0); - } else { - sccb_reg_write(gspca_dev, 0x13, - sccb_reg_read(gspca_dev, 0x13) & ~0x02); - if (sd->sensor == SENSOR_OV772x) - sccb_reg_write(gspca_dev, 0x63, - sccb_reg_read(gspca_dev, 0x63) & ~0xc0); - } -} - -static void setaec(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 data; - - data = sd->sensor == SENSOR_OV767x ? - 0x05 : /* agc + aec */ - 0x01; /* agc */ - if (sd->ctrls[AEC].val) - sccb_reg_write(gspca_dev, 0x13, - sccb_reg_read(gspca_dev, 0x13) | data); - else { - sccb_reg_write(gspca_dev, 0x13, - sccb_reg_read(gspca_dev, 0x13) & ~data); - if (sd->sensor == SENSOR_OV767x) - sd->ctrls[EXPOSURE].val = - sccb_reg_read(gspca_dev, 10); /* aech */ - else - setexposure(gspca_dev); - } -} - -static void setsharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - val = sd->ctrls[SHARPNESS].val; - sccb_reg_write(gspca_dev, 0x91, val); /* Auto de-noise threshold */ - sccb_reg_write(gspca_dev, 0x8e, val); /* De-noise threshold */ -} - -static void sethvflip(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - if (sd->sensor == SENSOR_OV767x) { - val = sccb_reg_read(gspca_dev, 0x1e); /* mvfp */ - val &= ~0x30; - if (sd->ctrls[HFLIP].val) - val |= 0x20; - if (sd->ctrls[VFLIP].val) - val |= 0x10; - sccb_reg_write(gspca_dev, 0x1e, val); - } else { - val = sccb_reg_read(gspca_dev, 0x0c); - val &= ~0xc0; - if (sd->ctrls[HFLIP].val == 0) - val |= 0x40; - if (sd->ctrls[VFLIP].val == 0) - val |= 0x80; - sccb_reg_write(gspca_dev, 0x0c, val); - } -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - int i; - static u8 color_tb[][6] = { - {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, - {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, - {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, - {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, - {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, - {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, - {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, - }; - - val = sd->ctrls[COLORS].val; - for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) - sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); -} - -static void setlightfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - val = sd->ctrls[LIGHTFREQ].val ? 0x9e : 0x00; - if (sd->sensor == SENSOR_OV767x) { - sccb_reg_write(gspca_dev, 0x2a, 0x00); - if (val) - val = 0x9d; /* insert dummy to 25fps for 50Hz */ - } - sccb_reg_write(gspca_dev, 0x2b, val); -} - - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - - cam->ctrls = sd->ctrls; - - /* the auto white balance control works only when auto gain is set */ - if (sd_ctrls[AGC].qctrl.default_value == 0) - gspca_dev->ctrl_inac |= (1 << AWB); - - cam->cam_mode = ov772x_mode; - cam->nmodes = ARRAY_SIZE(ov772x_mode); - - sd->frame_rate = 30; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 sensor_id; - static const struct reg_array bridge_init[NSENSORS] = { - [SENSOR_OV767x] = {bridge_init_767x, ARRAY_SIZE(bridge_init_767x)}, - [SENSOR_OV772x] = {bridge_init_772x, ARRAY_SIZE(bridge_init_772x)}, - }; - static const struct reg_array sensor_init[NSENSORS] = { - [SENSOR_OV767x] = {sensor_init_767x, ARRAY_SIZE(sensor_init_767x)}, - [SENSOR_OV772x] = {sensor_init_772x, ARRAY_SIZE(sensor_init_772x)}, - }; - - /* reset bridge */ - ov534_reg_write(gspca_dev, 0xe7, 0x3a); - ov534_reg_write(gspca_dev, 0xe0, 0x08); - msleep(100); - - /* initialize the sensor address */ - ov534_reg_write(gspca_dev, OV534_REG_ADDRESS, 0x42); - - /* reset sensor */ - sccb_reg_write(gspca_dev, 0x12, 0x80); - msleep(10); - - /* probe the sensor */ - sccb_reg_read(gspca_dev, 0x0a); - sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8; - sccb_reg_read(gspca_dev, 0x0b); - sensor_id |= sccb_reg_read(gspca_dev, 0x0b); - PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id); - - if ((sensor_id & 0xfff0) == 0x7670) { - sd->sensor = SENSOR_OV767x; - gspca_dev->ctrl_dis = (1 << GAIN) | - (1 << AGC) | - (1 << SHARPNESS); /* auto */ - sd->ctrls[BRIGHTNESS].min = -127; - sd->ctrls[BRIGHTNESS].max = 127; - sd->ctrls[BRIGHTNESS].def = 0; - sd->ctrls[CONTRAST].max = 0x80; - sd->ctrls[CONTRAST].def = 0x40; - sd->ctrls[EXPOSURE].min = 0x08; - sd->ctrls[EXPOSURE].max = 0x60; - sd->ctrls[EXPOSURE].def = 0x13; - sd->ctrls[SHARPNESS].max = 9; - sd->ctrls[SHARPNESS].def = 4; - sd->ctrls[HFLIP].def = 1; - gspca_dev->cam.cam_mode = ov767x_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); - } else { - sd->sensor = SENSOR_OV772x; - gspca_dev->ctrl_dis = (1 << COLORS); - gspca_dev->cam.bulk = 1; - gspca_dev->cam.bulk_size = 16384; - gspca_dev->cam.bulk_nurbs = 2; - gspca_dev->cam.mode_framerates = ov772x_framerates; - } - - /* initialize */ - reg_w_array(gspca_dev, bridge_init[sd->sensor].val, - bridge_init[sd->sensor].len); - ov534_set_led(gspca_dev, 1); - sccb_w_array(gspca_dev, sensor_init[sd->sensor].val, - sensor_init[sd->sensor].len); - if (sd->sensor == SENSOR_OV767x) - sd_start(gspca_dev); - sd_stopN(gspca_dev); -/* set_frame_rate(gspca_dev); */ - - return gspca_dev->usb_err; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int mode; - static const struct reg_array bridge_start[NSENSORS][2] = { - [SENSOR_OV767x] = {{bridge_start_qvga_767x, - ARRAY_SIZE(bridge_start_qvga_767x)}, - {bridge_start_vga_767x, - ARRAY_SIZE(bridge_start_vga_767x)}}, - [SENSOR_OV772x] = {{bridge_start_qvga_772x, - ARRAY_SIZE(bridge_start_qvga_772x)}, - {bridge_start_vga_772x, - ARRAY_SIZE(bridge_start_vga_772x)}}, - }; - static const struct reg_array sensor_start[NSENSORS][2] = { - [SENSOR_OV767x] = {{sensor_start_qvga_767x, - ARRAY_SIZE(sensor_start_qvga_767x)}, - {sensor_start_vga_767x, - ARRAY_SIZE(sensor_start_vga_767x)}}, - [SENSOR_OV772x] = {{sensor_start_qvga_772x, - ARRAY_SIZE(sensor_start_qvga_772x)}, - {sensor_start_vga_772x, - ARRAY_SIZE(sensor_start_vga_772x)}}, - }; - - /* (from ms-win trace) */ - if (sd->sensor == SENSOR_OV767x) - sccb_reg_write(gspca_dev, 0x1e, 0x04); - /* black sun enable ? */ - - mode = gspca_dev->curr_mode; /* 0: 320x240, 1: 640x480 */ - reg_w_array(gspca_dev, bridge_start[sd->sensor][mode].val, - bridge_start[sd->sensor][mode].len); - sccb_w_array(gspca_dev, sensor_start[sd->sensor][mode].val, - sensor_start[sd->sensor][mode].len); - - set_frame_rate(gspca_dev); - - if (!(gspca_dev->ctrl_dis & (1 << AGC))) - setagc(gspca_dev); - setawb(gspca_dev); - setaec(gspca_dev); - if (!(gspca_dev->ctrl_dis & (1 << GAIN))) - setgain(gspca_dev); - setexposure(gspca_dev); - setbrightness(gspca_dev); - setcontrast(gspca_dev); - if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS))) - setsharpness(gspca_dev); - sethvflip(gspca_dev); - if (!(gspca_dev->ctrl_dis & (1 << COLORS))) - setcolors(gspca_dev); - setlightfreq(gspca_dev); - - ov534_set_led(gspca_dev, 1); - ov534_reg_write(gspca_dev, 0xe0, 0x00); - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - ov534_reg_write(gspca_dev, 0xe0, 0x09); - ov534_set_led(gspca_dev, 0); -} - -/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ -#define UVC_STREAM_EOH (1 << 7) -#define UVC_STREAM_ERR (1 << 6) -#define UVC_STREAM_STI (1 << 5) -#define UVC_STREAM_RES (1 << 4) -#define UVC_STREAM_SCR (1 << 3) -#define UVC_STREAM_PTS (1 << 2) -#define UVC_STREAM_EOF (1 << 1) -#define UVC_STREAM_FID (1 << 0) - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u32 this_pts; - u16 this_fid; - int remaining_len = len; - int payload_len; - - payload_len = gspca_dev->cam.bulk ? 2048 : 2040; - do { - len = min(remaining_len, payload_len); - - /* Payloads are prefixed with a UVC-style header. We - consider a frame to start when the FID toggles, or the PTS - changes. A frame ends when EOF is set, and we've received - the correct number of bytes. */ - - /* Verify UVC header. Header length is always 12 */ - if (data[0] != 12 || len < 12) { - PDEBUG(D_PACK, "bad header"); - goto discard; - } - - /* Check errors */ - if (data[1] & UVC_STREAM_ERR) { - PDEBUG(D_PACK, "payload error"); - goto discard; - } - - /* Extract PTS and FID */ - if (!(data[1] & UVC_STREAM_PTS)) { - PDEBUG(D_PACK, "PTS not present"); - goto discard; - } - this_pts = (data[5] << 24) | (data[4] << 16) - | (data[3] << 8) | data[2]; - this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0; - - /* If PTS or FID has changed, start a new frame. */ - if (this_pts != sd->last_pts || this_fid != sd->last_fid) { - if (gspca_dev->last_packet_type == INTER_PACKET) - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - sd->last_pts = this_pts; - sd->last_fid = this_fid; - gspca_frame_add(gspca_dev, FIRST_PACKET, - data + 12, len - 12); - /* If this packet is marked as EOF, end the frame */ - } else if (data[1] & UVC_STREAM_EOF) { - sd->last_pts = 0; - if (gspca_dev->pixfmt == V4L2_PIX_FMT_YUYV - && gspca_dev->image_len + len - 12 != - gspca_dev->width * gspca_dev->height * 2) { - PDEBUG(D_PACK, "wrong sized frame"); - goto discard; - } - gspca_frame_add(gspca_dev, LAST_PACKET, - data + 12, len - 12); - } else { - - /* Add the data from this payload */ - gspca_frame_add(gspca_dev, INTER_PACKET, - data + 12, len - 12); - } - - /* Done this payload */ - goto scan_next; - -discard: - /* Discard data until a new frame starts. */ - gspca_dev->last_packet_type = DISCARD_PACKET; - -scan_next: - remaining_len -= len; - data += len; - } while (remaining_len > 0); -} - -static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AGC].val = val; - - /* the auto white balance control works only - * when auto gain is set */ - if (val) { - gspca_dev->ctrl_inac &= ~(1 << AWB); - } else { - gspca_dev->ctrl_inac |= (1 << AWB); - if (sd->ctrls[AWB].val) { - sd->ctrls[AWB].val = 0; - if (gspca_dev->streaming) - setawb(gspca_dev); - } - } - if (gspca_dev->streaming) - setagc(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "Disabled"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - } - break; - } - - return -EINVAL; -} - -/* get stream parameters (framerate) */ -static void sd_get_streamparm(struct gspca_dev *gspca_dev, - struct v4l2_streamparm *parm) -{ - struct v4l2_captureparm *cp = &parm->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; - struct sd *sd = (struct sd *) gspca_dev; - - cp->capability |= V4L2_CAP_TIMEPERFRAME; - tpf->numerator = 1; - tpf->denominator = sd->frame_rate; -} - -/* set stream parameters (framerate) */ -static void sd_set_streamparm(struct gspca_dev *gspca_dev, - struct v4l2_streamparm *parm) -{ - struct v4l2_captureparm *cp = &parm->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; - struct sd *sd = (struct sd *) gspca_dev; - - /* Set requested framerate */ - sd->frame_rate = tpf->denominator / tpf->numerator; - if (gspca_dev->streaming) - set_frame_rate(gspca_dev); - - /* Return the actual framerate */ - tpf->numerator = 1; - tpf->denominator = sd->frame_rate; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, - .get_streamparm = sd_get_streamparm, - .set_streamparm = sd_set_streamparm, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x1415, 0x2000)}, - {USB_DEVICE(0x06f8, 0x3002)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac207.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac207.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac207.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac207.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,581 +0,0 @@ -/* - * Pixart PAC207BCA library - * - * Copyright (C) 2008 Hans de Goede - * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li - * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * (at your option) any later version. - * - * 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 - * - */ - -#define MODULE_NAME "pac207" - -#include -#include "gspca.h" - -MODULE_AUTHOR("Hans de Goede "); -MODULE_DESCRIPTION("Pixart PAC207"); -MODULE_LICENSE("GPL"); - -#define PAC207_CTRL_TIMEOUT 100 /* ms */ - -#define PAC207_BRIGHTNESS_MIN 0 -#define PAC207_BRIGHTNESS_MAX 255 -#define PAC207_BRIGHTNESS_DEFAULT 46 - -#define PAC207_EXPOSURE_MIN 3 -#define PAC207_EXPOSURE_MAX 26 -#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */ -#define PAC207_EXPOSURE_KNEE 8 /* 4 = 30 fps, 11 = 8, 15 = 6 */ - -#define PAC207_GAIN_MIN 0 -#define PAC207_GAIN_MAX 31 -#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */ -#define PAC207_GAIN_KNEE 31 - -#define PAC207_AUTOGAIN_DEADZONE 30 - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - u8 mode; - - u8 brightness; - u8 exposure; - u8 autogain; - u8 gain; - - u8 sof_read; - u8 header_read; - u8 autogain_ignore_frames; - - atomic_t avg_lum; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = PAC207_BRIGHTNESS_MIN, - .maximum = PAC207_BRIGHTNESS_MAX, - .step = 1, - .default_value = PAC207_BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_EXPOSURE 1 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = PAC207_EXPOSURE_MIN, - .maximum = PAC207_EXPOSURE_MAX, - .step = 1, - .default_value = PAC207_EXPOSURE_DEFAULT, - .flags = 0, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, -#define SD_AUTOGAIN 2 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - .flags = 0, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -#define SD_GAIN 3 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = PAC207_GAIN_MIN, - .maximum = PAC207_GAIN_MAX, - .step = 1, - .default_value = PAC207_GAIN_DEFAULT, - .flags = 0, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - -static const struct v4l2_pix_format sif_mode[] = { - {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = (176 + 2) * 144, - /* uncompressed, add 2 bytes / line for line header */ - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, - .bytesperline = 352, - /* compressed, but only when needed (not compressed - when the framerate is low) */ - .sizeimage = (352 + 2) * 288, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -static const __u8 pac207_sensor_init[][8] = { - {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84}, - {0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30}, - {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00}, - {0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00}, -}; - -static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, - const u8 *buffer, u16 length) -{ - struct usb_device *udev = gspca_dev->dev; - int err; - - memcpy(gspca_dev->usb_buf, buffer, length); - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 0x00, index, - gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT); - if (err < 0) - err("Failed to write registers to index 0x%04X, error %d)", - index, err); - - return err; -} - - -static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) -{ - struct usb_device *udev = gspca_dev->dev; - int err; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, index, NULL, 0, PAC207_CTRL_TIMEOUT); - if (err) - err("Failed to write a register (index 0x%04X," - " value 0x%02X, error %d)", index, value, err); - - return err; -} - -static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) -{ - struct usb_device *udev = gspca_dev->dev; - int res; - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 0x00, index, - gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT); - if (res < 0) { - err("Failed to read a register (index 0x%04X, error %d)", - index, res); - return res; - } - - return gspca_dev->usb_buf[0]; -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - u8 idreg[2]; - - idreg[0] = pac207_read_reg(gspca_dev, 0x0000); - idreg[1] = pac207_read_reg(gspca_dev, 0x0001); - idreg[0] = ((idreg[0] & 0x0f) << 4) | ((idreg[1] & 0xf0) >> 4); - idreg[1] = idreg[1] & 0x0f; - PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X", - idreg[0], idreg[1]); - - if (idreg[0] != 0x27) { - PDEBUG(D_PROBE, "Error invalid sensor ID!"); - return -ENODEV; - } - - PDEBUG(D_PROBE, - "Pixart PAC207BCA Image Processor and Control Chip detected" - " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - - cam = &gspca_dev->cam; - cam->cam_mode = sif_mode; - cam->nmodes = ARRAY_SIZE(sif_mode); - sd->brightness = PAC207_BRIGHTNESS_DEFAULT; - sd->exposure = PAC207_EXPOSURE_DEFAULT; - sd->gain = PAC207_GAIN_DEFAULT; - sd->autogain = AUTOGAIN_DEF; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - pac207_write_reg(gspca_dev, 0x41, 0x00); - /* Bit_0=Image Format, - * Bit_1=LED, - * Bit_2=Compression test mode enable */ - pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ - - return 0; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 mode; - - pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */ - pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8); - pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8); - pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8); - pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8); - - /* Compression Balance */ - if (gspca_dev->width == 176) - pac207_write_reg(gspca_dev, 0x4a, 0xff); - else - pac207_write_reg(gspca_dev, 0x4a, 0x30); - pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */ - pac207_write_reg(gspca_dev, 0x08, sd->brightness); - - /* PGA global gain (Bit 4-0) */ - pac207_write_reg(gspca_dev, 0x0e, sd->gain); - pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */ - - mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */ - if (gspca_dev->width == 176) { /* 176x144 */ - mode |= 0x01; - PDEBUG(D_STREAM, "pac207_start mode 176x144"); - } else { /* 352x288 */ - PDEBUG(D_STREAM, "pac207_start mode 352x288"); - } - pac207_write_reg(gspca_dev, 0x41, mode); - - pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ - pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ - msleep(10); - pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */ - - sd->sof_read = 0; - sd->autogain_ignore_frames = 0; - atomic_set(&sd->avg_lum, -1); - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */ - pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */ - pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ -} - -/* Include pac common sof detection functions */ -#include "pac_common.h" - -static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int avg_lum = atomic_read(&sd->avg_lum); - - if (avg_lum == -1) - return; - - if (sd->autogain_ignore_frames > 0) - sd->autogain_ignore_frames--; - else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, - 100, PAC207_AUTOGAIN_DEADZONE, - PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) - sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, - int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - unsigned char *sof; - - sof = pac_find_sof(&sd->sof_read, data, len); - if (sof) { - int n; - - /* finish decoding current frame */ - n = sof - data; - if (n > sizeof pac_sof_marker) - n -= sizeof pac_sof_marker; - else - n = 0; - gspca_frame_add(gspca_dev, LAST_PACKET, - data, n); - sd->header_read = 0; - gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); - len -= sof - data; - data = sof; - } - if (sd->header_read < 11) { - int needed; - - /* get average lumination from frame header (byte 5) */ - if (sd->header_read < 5) { - needed = 5 - sd->header_read; - if (len >= needed) - atomic_set(&sd->avg_lum, data[needed - 1]); - } - /* skip the rest of the header */ - needed = 11 - sd->header_read; - if (len <= needed) { - sd->header_read += len; - return; - } - data += needed; - len -= needed; - sd->header_read = 11; - } - - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - pac207_write_reg(gspca_dev, 0x08, sd->brightness); - pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ - pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - pac207_write_reg(gspca_dev, 0x02, sd->exposure); - pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ - pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - pac207_write_reg(gspca_dev, 0x0e, sd->gain); - pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ - pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - /* when switching to autogain set defaults to make sure - we are on a valid point of the autogain gain / - exposure knee graph, and give this change time to - take effect before doing autogain. */ - if (sd->autogain) { - sd->exposure = PAC207_EXPOSURE_DEFAULT; - sd->gain = PAC207_GAIN_DEFAULT; - if (gspca_dev->streaming) { - sd->autogain_ignore_frames = - PAC_AUTOGAIN_IGNORE_FRAMES; - setexposure(gspca_dev); - setgain(gspca_dev); - } - } - - return 0; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* interrupt packet data */ - int len) /* interrput packet length */ -{ - int ret = -EINVAL; - - if (len == 2 && data[0] == 0x5a && data[1] == 0x5a) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); - input_sync(gspca_dev->input_dev); - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - ret = 0; - } - - return ret; -} -#endif - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .dq_callback = pac207_do_auto_gain, - .pkt_scan = sd_pkt_scan, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -#endif -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x4028)}, - {USB_DEVICE(0x093a, 0x2460)}, - {USB_DEVICE(0x093a, 0x2461)}, - {USB_DEVICE(0x093a, 0x2463)}, - {USB_DEVICE(0x093a, 0x2464)}, - {USB_DEVICE(0x093a, 0x2468)}, - {USB_DEVICE(0x093a, 0x2470)}, - {USB_DEVICE(0x093a, 0x2471)}, - {USB_DEVICE(0x093a, 0x2472)}, - {USB_DEVICE(0x093a, 0x2474)}, - {USB_DEVICE(0x093a, 0x2476)}, - {USB_DEVICE(0x145f, 0x013a)}, - {USB_DEVICE(0x2001, 0xf115)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac7302.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac7302.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac7302.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac7302.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1233 +0,0 @@ -/* - * Pixart PAC7302 library - * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li - * - * V4L2 by Jean-Francois Moine - * - * Separated from Pixart PAC7311 library by Márton Németh - * Camera button input handling by Márton Németh - * Copyright (C) 2009-2010 Márton Németh - * - * 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, or - * any later version. - * - * 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 - */ - -/* Some documentation about various registers as determined by trial and error. - - Register page 1: - - Address Description - 0x78 Global control, bit 6 controls the LED (inverted) - - Register page 3: - - Address Description - 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on - the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? - 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps - 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps, - 63 -> ~27 fps, the 2 msb's must always be 1 !! - 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0: - 1 -> ~30 fps, 2 -> ~20 fps - 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time - 0x0f Exposure bit 8, 0-448, 448 = no exposure at all - 0x10 Master gain 0-31 - 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused - - The registers are accessed in the following functions: - - Page | Register | Function - -----+------------+--------------------------------------------------- - 0 | 0x0f..0x20 | setcolors() - 0 | 0xa2..0xab | setbrightcont() - 0 | 0xc5 | setredbalance() - 0 | 0xc6 | setwhitebalance() - 0 | 0xc7 | setbluebalance() - 0 | 0xdc | setbrightcont(), setcolors() - 3 | 0x02 | setexposure() - 3 | 0x10 | setgain() - 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip() - 3 | 0x21 | sethvflip() -*/ - -#define MODULE_NAME "pac7302" - -#include -#include -#include "gspca.h" - -MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); -MODULE_DESCRIPTION("Pixart PAC7302"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor for pac7302 */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - unsigned char brightness; - unsigned char contrast; - unsigned char colors; - unsigned char white_balance; - unsigned char red_balance; - unsigned char blue_balance; - unsigned char gain; - unsigned char autogain; - unsigned short exposure; - __u8 hflip; - __u8 vflip; - u8 flags; -#define FL_HFLIP 0x01 /* mirrored by default */ -#define FL_VFLIP 0x02 /* vertical flipped by default */ - - u8 sof_read; - u8 autogain_ignore_frames; - - atomic_t avg_lum; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, -#define BRIGHTNESS_MAX 0x20 - .maximum = BRIGHTNESS_MAX, - .step = 1, -#define BRIGHTNESS_DEF 0x10 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, -#define CONTRAST_MAX 255 - .maximum = CONTRAST_MAX, - .step = 1, -#define CONTRAST_DEF 127 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, -#define COLOR_MAX 255 - .maximum = COLOR_MAX, - .step = 1, -#define COLOR_DEF 127 - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, - { - { - .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "White Balance", - .minimum = 0, - .maximum = 255, - .step = 1, -#define WHITEBALANCE_DEF 4 - .default_value = WHITEBALANCE_DEF, - }, - .set = sd_setwhitebalance, - .get = sd_getwhitebalance, - }, - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red", - .minimum = 0, - .maximum = 3, - .step = 1, -#define REDBALANCE_DEF 1 - .default_value = REDBALANCE_DEF, - }, - .set = sd_setredbalance, - .get = sd_getredbalance, - }, - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue", - .minimum = 0, - .maximum = 3, - .step = 1, -#define BLUEBALANCE_DEF 1 - .default_value = BLUEBALANCE_DEF, - }, - .set = sd_setbluebalance, - .get = sd_getbluebalance, - }, - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, -#define GAIN_MAX 255 - .maximum = GAIN_MAX, - .step = 1, -#define GAIN_DEF 127 -#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 1023, - .step = 1, -#define EXPOSURE_DEF 66 /* 33 ms / 30 fps */ -#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ - .default_value = EXPOSURE_DEF, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, -#define HFLIP_DEF 0 - .default_value = HFLIP_DEF, - }, - .set = sd_sethflip, - .get = sd_gethflip, - }, - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, -#define VFLIP_DEF 0 - .default_value = VFLIP_DEF, - }, - .set = sd_setvflip, - .get = sd_getvflip, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -#define LOAD_PAGE3 255 -#define END_OF_SEQUENCE 0 - -/* pac 7302 */ -static const __u8 init_7302[] = { -/* index,value */ - 0xff, 0x01, /* page 1 */ - 0x78, 0x00, /* deactivate */ - 0xff, 0x01, - 0x78, 0x40, /* led off */ -}; -static const __u8 start_7302[] = { -/* index, len, [value]* */ - 0xff, 1, 0x00, /* page 0 */ - 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, - 0x00, 0x00, 0x00, 0x00, - 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00, - 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7, - 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11, - 0x26, 2, 0xaa, 0xaa, - 0x2e, 1, 0x31, - 0x38, 1, 0x01, - 0x3a, 3, 0x14, 0xff, 0x5a, - 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11, - 0x00, 0x54, 0x11, - 0x55, 1, 0x00, - 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, - 0x6b, 1, 0x00, - 0x6e, 3, 0x08, 0x06, 0x00, - 0x72, 3, 0x00, 0xff, 0x00, - 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c, - 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50, - 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00, - 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9, - 0xd2, 0xeb, - 0xaf, 1, 0x02, - 0xb5, 2, 0x08, 0x08, - 0xb8, 2, 0x08, 0x88, - 0xc4, 4, 0xae, 0x01, 0x04, 0x01, - 0xcc, 1, 0x00, - 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9, - 0xc1, 0xd7, 0xec, - 0xdc, 1, 0x01, - 0xff, 1, 0x01, /* page 1 */ - 0x12, 3, 0x02, 0x00, 0x01, - 0x3e, 2, 0x00, 0x00, - 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2, - 0x7c, 1, 0x00, - 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20, - 0x02, 0x00, - 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04, - 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, - 0x07, 0x00, 0x01, 0x07, 0x04, 0x01, - 0xd8, 1, 0x01, - 0xdb, 2, 0x00, 0x01, - 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00, - 0xe6, 4, 0x00, 0x00, 0x00, 0x01, - 0xeb, 1, 0x00, - 0xff, 1, 0x02, /* page 2 */ - 0x22, 1, 0x00, - 0xff, 1, 0x03, /* page 3 */ - 0, LOAD_PAGE3, /* load the page 3 */ - 0x11, 1, 0x01, - 0xff, 1, 0x02, /* page 2 */ - 0x13, 1, 0x00, - 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96, - 0x27, 2, 0x14, 0x0c, - 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22, - 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44, - 0x6e, 1, 0x08, - 0xff, 1, 0x01, /* page 1 */ - 0x78, 1, 0x00, - 0, END_OF_SEQUENCE /* end of sequence */ -}; - -#define SKIP 0xaa -/* page 3 - the value SKIP says skip the index - see reg_w_page() */ -static const __u8 page3_7302[] = { - 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16, - 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, - 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21, - 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54, - 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00, - SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8, - 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, - 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00, - 0x00 -}; - -static void reg_w_buf(struct gspca_dev *gspca_dev, - __u8 index, - const u8 *buffer, int len) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - memcpy(gspca_dev->usb_buf, buffer, len); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, len, - 500); - if (ret < 0) { - err("reg_w_buf failed index 0x%02x, error %d", - index, ret); - gspca_dev->usb_err = ret; - } -} - - -static void reg_w(struct gspca_dev *gspca_dev, - __u8 index, - __u8 value) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - gspca_dev->usb_buf[0] = value; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { - err("reg_w() failed index 0x%02x, value 0x%02x, error %d", - index, value, ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_w_seq(struct gspca_dev *gspca_dev, - const __u8 *seq, int len) -{ - while (--len >= 0) { - reg_w(gspca_dev, seq[0], seq[1]); - seq += 2; - } -} - -/* load the beginning of a page */ -static void reg_w_page(struct gspca_dev *gspca_dev, - const __u8 *page, int len) -{ - int index; - int ret = 0; - - if (gspca_dev->usb_err < 0) - return; - for (index = 0; index < len; index++) { - if (page[index] == SKIP) /* skip this index */ - continue; - gspca_dev->usb_buf[0] = page[index]; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { - err("reg_w_page() failed index 0x%02x, " - "value 0x%02x, error %d", - index, page[index], ret); - gspca_dev->usb_err = ret; - break; - } - } -} - -/* output a variable sequence */ -static void reg_w_var(struct gspca_dev *gspca_dev, - const __u8 *seq, - const __u8 *page3, unsigned int page3_len) -{ - int index, len; - - for (;;) { - index = *seq++; - len = *seq++; - switch (len) { - case END_OF_SEQUENCE: - return; - case LOAD_PAGE3: - reg_w_page(gspca_dev, page3, page3_len); - break; - default: - if (len > USB_BUF_SZ) { - PDEBUG(D_ERR|D_STREAM, - "Incorrect variable sequence"); - return; - } - while (len > 0) { - if (len < 8) { - reg_w_buf(gspca_dev, - index, seq, len); - seq += len; - break; - } - reg_w_buf(gspca_dev, index, seq, 8); - seq += 8; - index += 8; - len -= 8; - } - } - } - /* not reached */ -} - -/* this function is called at probe time for pac7302 */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - - PDEBUG(D_CONF, "Find Sensor PAC7302"); - cam->cam_mode = vga_mode; /* only 640x480 */ - cam->nmodes = ARRAY_SIZE(vga_mode); - - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->white_balance = WHITEBALANCE_DEF; - sd->red_balance = REDBALANCE_DEF; - sd->blue_balance = BLUEBALANCE_DEF; - sd->gain = GAIN_DEF; - sd->exposure = EXPOSURE_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->hflip = HFLIP_DEF; - sd->vflip = VFLIP_DEF; - sd->flags = id->driver_info; - return 0; -} - -/* This function is used by pac7302 only */ -static void setbrightcont(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, v; - static const __u8 max[10] = - {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, - 0xd4, 0xec}; - static const __u8 delta[10] = - {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, - 0x11, 0x0b}; - - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - for (i = 0; i < 10; i++) { - v = max[i]; - v += (sd->brightness - BRIGHTNESS_MAX) - * 150 / BRIGHTNESS_MAX; /* 200 ? */ - v -= delta[i] * sd->contrast / CONTRAST_MAX; - if (v < 0) - v = 0; - else if (v > 0xff) - v = 0xff; - reg_w(gspca_dev, 0xa2 + i, v); - } - reg_w(gspca_dev, 0xdc, 0x01); -} - -/* This function is used by pac7302 only */ -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, v; - static const int a[9] = - {217, -212, 0, -101, 170, -67, -38, -315, 355}; - static const int b[9] = - {19, 106, 0, 19, 106, 1, 19, 106, 1}; - - reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ - reg_w(gspca_dev, 0x11, 0x01); - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - for (i = 0; i < 9; i++) { - v = a[i] * sd->colors / COLOR_MAX + b[i]; - reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); - reg_w(gspca_dev, 0x0f + 2 * i + 1, v); - } - reg_w(gspca_dev, 0xdc, 0x01); - PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); -} - -static void setwhitebalance(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - reg_w(gspca_dev, 0xc6, sd->white_balance); - - reg_w(gspca_dev, 0xdc, 0x01); - PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance); -} - -static void setredbalance(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - reg_w(gspca_dev, 0xc5, sd->red_balance); - - reg_w(gspca_dev, 0xdc, 0x01); - PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance); -} - -static void setbluebalance(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - reg_w(gspca_dev, 0xc7, sd->blue_balance); - - reg_w(gspca_dev, 0xdc, 0x01); - PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance); -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ - reg_w(gspca_dev, 0x10, sd->gain >> 3); - - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 clockdiv; - __u16 exposure; - - /* register 2 of frame 3 contains the clock divider configuring the - no fps according to the formula: 90 / reg. sd->exposure is the - desired exposure time in 0.5 ms. */ - clockdiv = (90 * sd->exposure + 1999) / 2000; - - /* Note clockdiv = 3 also works, but when running at 30 fps, depending - on the scene being recorded, the camera switches to another - quantization table for certain JPEG blocks, and we don't know how - to decompress these blocks. So we cap the framerate at 15 fps */ - if (clockdiv < 6) - clockdiv = 6; - else if (clockdiv > 63) - clockdiv = 63; - - /* reg2 MUST be a multiple of 3, except when between 6 and 12? - Always round up, otherwise we cannot get the desired frametime - using the partial frame time exposure control */ - if (clockdiv < 6 || clockdiv > 12) - clockdiv = ((clockdiv + 2) / 3) * 3; - - /* frame exposure time in ms = 1000 * clockdiv / 90 -> - exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ - exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv); - /* 0 = use full frametime, 448 = no exposure, reverse it */ - exposure = 448 - exposure; - - reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ - reg_w(gspca_dev, 0x02, clockdiv); - reg_w(gspca_dev, 0x0e, exposure & 0xff); - reg_w(gspca_dev, 0x0f, exposure >> 8); - - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); -} - -static void sethvflip(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 data, hflip, vflip; - - hflip = sd->hflip; - if (sd->flags & FL_HFLIP) - hflip = !hflip; - vflip = sd->vflip; - if (sd->flags & FL_VFLIP) - vflip = !vflip; - - reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ - data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00); - reg_w(gspca_dev, 0x21, data); - - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); -} - -/* this function is called at probe and resume time for pac7302 */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2); - return gspca_dev->usb_err; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sof_read = 0; - - reg_w_var(gspca_dev, start_7302, - page3_7302, sizeof(page3_7302)); - setbrightcont(gspca_dev); - setcolors(gspca_dev); - setwhitebalance(gspca_dev); - setredbalance(gspca_dev); - setbluebalance(gspca_dev); - setgain(gspca_dev); - setexposure(gspca_dev); - sethvflip(gspca_dev); - - /* only resolution 640x480 is supported for pac7302 */ - - sd->sof_read = 0; - sd->autogain_ignore_frames = 0; - atomic_set(&sd->avg_lum, -1); - - /* start stream */ - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x78, 0x01); - - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - - /* stop stream */ - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x78, 0x00); -} - -/* called on streamoff with alt 0 and on disconnect for pac7302 */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - if (!gspca_dev->present) - return; - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x78, 0x40); -} - -/* Include pac common sof detection functions */ -#include "pac_common.h" - -static void do_autogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int avg_lum = atomic_read(&sd->avg_lum); - int desired_lum; - const int deadzone = 30; - - if (avg_lum == -1) - return; - - desired_lum = 270 + sd->brightness; - - if (sd->autogain_ignore_frames > 0) - sd->autogain_ignore_frames--; - else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, - deadzone, GAIN_KNEE, EXPOSURE_KNEE)) - sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; -} - -/* JPEG header, part 1 */ -static const unsigned char pac_jpeg_header1[] = { - 0xff, 0xd8, /* SOI: Start of Image */ - - 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ - 0x00, 0x11, /* length = 17 bytes (including this length field) */ - 0x08 /* Precision: 8 */ - /* 2 bytes is placed here: number of image lines */ - /* 2 bytes is placed here: samples per line */ -}; - -/* JPEG header, continued */ -static const unsigned char pac_jpeg_header2[] = { - 0x03, /* Number of image components: 3 */ - 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ - 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ - 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ - - 0xff, 0xda, /* SOS: Start Of Scan */ - 0x00, 0x0c, /* length = 12 bytes (including this length field) */ - 0x03, /* number of components: 3 */ - 0x01, 0x00, /* selector 1, table 0x00 */ - 0x02, 0x11, /* selector 2, table 0x11 */ - 0x03, 0x11, /* selector 3, table 0x11 */ - 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ - 0x00 /* Successive approximation: 0 */ -}; - -static void pac_start_frame(struct gspca_dev *gspca_dev, - __u16 lines, __u16 samples_per_line) -{ - unsigned char tmpbuf[4]; - - gspca_frame_add(gspca_dev, FIRST_PACKET, - pac_jpeg_header1, sizeof(pac_jpeg_header1)); - - tmpbuf[0] = lines >> 8; - tmpbuf[1] = lines & 0xff; - tmpbuf[2] = samples_per_line >> 8; - tmpbuf[3] = samples_per_line & 0xff; - - gspca_frame_add(gspca_dev, INTER_PACKET, - tmpbuf, sizeof(tmpbuf)); - gspca_frame_add(gspca_dev, INTER_PACKET, - pac_jpeg_header2, sizeof(pac_jpeg_header2)); -} - -/* this function is run at interrupt level */ -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 *image; - unsigned char *sof; - - sof = pac_find_sof(&sd->sof_read, data, len); - if (sof) { - int n, lum_offset, footer_length; - - /* 6 bytes after the FF D9 EOF marker a number of lumination - bytes are send corresponding to different parts of the - image, the 14th and 15th byte after the EOF seem to - correspond to the center of the image */ - lum_offset = 61 + sizeof pac_sof_marker; - footer_length = 74; - - /* Finish decoding current frame */ - n = (sof - data) - (footer_length + sizeof pac_sof_marker); - if (n < 0) { - gspca_dev->image_len += n; - n = 0; - } else { - gspca_frame_add(gspca_dev, INTER_PACKET, data, n); - } - - image = gspca_dev->image; - if (image != NULL - && image[gspca_dev->image_len - 2] == 0xff - && image[gspca_dev->image_len - 1] == 0xd9) - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - - n = sof - data; - len -= n; - data = sof; - - /* Get average lumination */ - if (gspca_dev->last_packet_type == LAST_PACKET && - n >= lum_offset) - atomic_set(&sd->avg_lum, data[-lum_offset] + - data[-lum_offset + 1]); - else - atomic_set(&sd->avg_lum, -1); - - /* Start the new frame with the jpeg header */ - /* The PAC7302 has the image rotated 90 degrees */ - pac_start_frame(gspca_dev, - gspca_dev->width, gspca_dev->height); - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightcont(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setbrightcont(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->white_balance = val; - if (gspca_dev->streaming) - setwhitebalance(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->white_balance; - return 0; -} - -static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->red_balance = val; - if (gspca_dev->streaming) - setredbalance(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->red_balance; - return 0; -} - -static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->blue_balance = val; - if (gspca_dev->streaming) - setbluebalance(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->blue_balance; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - /* when switching to autogain set defaults to make sure - we are on a valid point of the autogain gain / - exposure knee graph, and give this change time to - take effect before doing autogain. */ - if (sd->autogain) { - sd->exposure = EXPOSURE_DEF; - sd->gain = GAIN_DEF; - if (gspca_dev->streaming) { - sd->autogain_ignore_frames = - PAC_AUTOGAIN_IGNORE_FRAMES; - setexposure(gspca_dev); - setgain(gspca_dev); - } - } - - return gspca_dev->usb_err; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hflip; - return 0; -} - -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->vflip; - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int sd_dbg_s_register(struct gspca_dev *gspca_dev, - struct v4l2_dbg_register *reg) -{ - __u8 index; - __u8 value; - - /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit - long on the USB bus) - */ - if (reg->match.type == V4L2_CHIP_MATCH_HOST && - reg->match.addr == 0 && - (reg->reg < 0x000000ff) && - (reg->val <= 0x000000ff) - ) { - /* Currently writing to page 0 is only supported. */ - /* reg_w() only supports 8bit index */ - index = reg->reg & 0x000000ff; - value = reg->val & 0x000000ff; - - /* Note that there shall be no access to other page - by any other function between the page swith and - the actual register write */ - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - reg_w(gspca_dev, index, value); - - reg_w(gspca_dev, 0xdc, 0x01); - } - return gspca_dev->usb_err; -} - -static int sd_chip_ident(struct gspca_dev *gspca_dev, - struct v4l2_dbg_chip_ident *chip) -{ - int ret = -EINVAL; - - if (chip->match.type == V4L2_CHIP_MATCH_HOST && - chip->match.addr == 0) { - chip->revision = 0; - chip->ident = V4L2_IDENT_UNKNOWN; - ret = 0; - } - return ret; -} -#endif - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* interrupt packet data */ - int len) /* interrput packet length */ -{ - int ret = -EINVAL; - u8 data0, data1; - - if (len == 2) { - data0 = data[0]; - data1 = data[1]; - if ((data0 == 0x00 && data1 == 0x11) || - (data0 == 0x22 && data1 == 0x33) || - (data0 == 0x44 && data1 == 0x55) || - (data0 == 0x66 && data1 == 0x77) || - (data0 == 0x88 && data1 == 0x99) || - (data0 == 0xaa && data1 == 0xbb) || - (data0 == 0xcc && data1 == 0xdd) || - (data0 == 0xee && data1 == 0xff)) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); - input_sync(gspca_dev->input_dev); - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - ret = 0; - } - } - - return ret; -} -#endif - -/* sub-driver description for pac7302 */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = do_autogain, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .set_register = sd_dbg_s_register, - .get_chip_ident = sd_chip_ident, -#endif -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -#endif -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x06f8, 0x3009)}, - {USB_DEVICE(0x093a, 0x2620)}, - {USB_DEVICE(0x093a, 0x2621)}, - {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, - {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, - {USB_DEVICE(0x093a, 0x2625)}, - {USB_DEVICE(0x093a, 0x2626)}, - {USB_DEVICE(0x093a, 0x2628)}, - {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, - {USB_DEVICE(0x093a, 0x262a)}, - {USB_DEVICE(0x093a, 0x262c)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac7311.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac7311.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac7311.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac7311.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,881 +0,0 @@ -/* - * Pixart PAC7311 library - * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - */ - -/* Some documentation about various registers as determined by trial and error. - When the register addresses differ between the 7202 and the 7311 the 2 - different addresses are written as 7302addr/7311addr, when one of the 2 - addresses is a - sign that register description is not valid for the - matching IC. - - Register page 1: - - Address Description - -/0x08 Unknown compressor related, must always be 8 except when not - in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 ! - -/0x1b Auto white balance related, bit 0 is AWB enable (inverted) - bits 345 seem to toggle per color gains on/off (inverted) - 0x78 Global control, bit 6 controls the LED (inverted) - -/0x80 JPEG compression ratio ? Best not touched - - Register page 3/4: - - Address Description - 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on - the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? - -/0x0f Master gain 1-245, low value = high gain - 0x10/- Master gain 0-31 - -/0x10 Another gain 0-15, limited influence (1-2x gain I guess) - 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused - -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to - completely disable the analog amplification block. Set to 0x68 - for max gain, 0x14 for minimal gain. -*/ - -#define MODULE_NAME "pac7311" - -#include -#include "gspca.h" - -MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); -MODULE_DESCRIPTION("Pixart PAC7311"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor for pac7311 */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - unsigned char contrast; - unsigned char gain; - unsigned char exposure; - unsigned char autogain; - __u8 hflip; - __u8 vflip; - - u8 sof_read; - u8 autogain_ignore_frames; - - atomic_t avg_lum; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -/* This control is for both the 7302 and the 7311 */ - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, -#define CONTRAST_MAX 255 - .maximum = CONTRAST_MAX, - .step = 1, -#define CONTRAST_DEF 127 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -/* All controls below are for both the 7302 and the 7311 */ - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, -#define GAIN_MAX 255 - .maximum = GAIN_MAX, - .step = 1, -#define GAIN_DEF 127 -#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, -#define EXPOSURE_MAX 255 - .maximum = EXPOSURE_MAX, - .step = 1, -#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ -#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ - .default_value = EXPOSURE_DEF, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, -#define HFLIP_DEF 0 - .default_value = HFLIP_DEF, - }, - .set = sd_sethflip, - .get = sd_gethflip, - }, - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, -#define VFLIP_DEF 0 - .default_value = VFLIP_DEF, - }, - .set = sd_setvflip, - .get = sd_getvflip, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -#define LOAD_PAGE4 254 -#define END_OF_SEQUENCE 0 - -/* pac 7311 */ -static const __u8 init_7311[] = { - 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */ - 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */ - 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */ - 0xff, 0x04, - 0x27, 0x80, - 0x28, 0xca, - 0x29, 0x53, - 0x2a, 0x0e, - 0xff, 0x01, - 0x3e, 0x20, -}; - -static const __u8 start_7311[] = { -/* index, len, [value]* */ - 0xff, 1, 0x01, /* page 1 */ - 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00, - 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c, - 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e, - 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49, - 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48, - 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78, - 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b, - 0xd0, 0xff, - 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80, - 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84, - 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14, - 0x18, 0x20, - 0x96, 3, 0x01, 0x08, 0x04, - 0xa0, 4, 0x44, 0x44, 0x44, 0x04, - 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00, - 0x3f, 0x00, 0x0a, 0x01, 0x00, - 0xff, 1, 0x04, /* page 4 */ - 0, LOAD_PAGE4, /* load the page 4 */ - 0x11, 1, 0x01, - 0, END_OF_SEQUENCE /* end of sequence */ -}; - -#define SKIP 0xaa -/* page 4 - the value SKIP says skip the index - see reg_w_page() */ -static const __u8 page4_7311[] = { - SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f, - 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62, - 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP, - SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68, - 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00, - 0x23, 0x28, 0x04, 0x11, 0x00, 0x00 -}; - -static void reg_w_buf(struct gspca_dev *gspca_dev, - __u8 index, - const u8 *buffer, int len) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - memcpy(gspca_dev->usb_buf, buffer, len); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, len, - 500); - if (ret < 0) { - err("reg_w_buf() failed index 0x%02x, error %d", - index, ret); - gspca_dev->usb_err = ret; - } -} - - -static void reg_w(struct gspca_dev *gspca_dev, - __u8 index, - __u8 value) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - gspca_dev->usb_buf[0] = value; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { - err("reg_w() failed index 0x%02x, value 0x%02x, error %d", - index, value, ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_w_seq(struct gspca_dev *gspca_dev, - const __u8 *seq, int len) -{ - while (--len >= 0) { - reg_w(gspca_dev, seq[0], seq[1]); - seq += 2; - } -} - -/* load the beginning of a page */ -static void reg_w_page(struct gspca_dev *gspca_dev, - const __u8 *page, int len) -{ - int index; - int ret = 0; - - if (gspca_dev->usb_err < 0) - return; - for (index = 0; index < len; index++) { - if (page[index] == SKIP) /* skip this index */ - continue; - gspca_dev->usb_buf[0] = page[index]; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { - err("reg_w_page() failed index 0x%02x, " - "value 0x%02x, error %d", - index, page[index], ret); - gspca_dev->usb_err = ret; - break; - } - } -} - -/* output a variable sequence */ -static void reg_w_var(struct gspca_dev *gspca_dev, - const __u8 *seq, - const __u8 *page4, unsigned int page4_len) -{ - int index, len; - - for (;;) { - index = *seq++; - len = *seq++; - switch (len) { - case END_OF_SEQUENCE: - return; - case LOAD_PAGE4: - reg_w_page(gspca_dev, page4, page4_len); - break; - default: - if (len > USB_BUF_SZ) { - PDEBUG(D_ERR|D_STREAM, - "Incorrect variable sequence"); - return; - } - while (len > 0) { - if (len < 8) { - reg_w_buf(gspca_dev, - index, seq, len); - seq += len; - break; - } - reg_w_buf(gspca_dev, index, seq, 8); - seq += 8; - index += 8; - len -= 8; - } - } - } - /* not reached */ -} - -/* this function is called at probe time for pac7311 */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - - PDEBUG(D_CONF, "Find Sensor PAC7311"); - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - - sd->contrast = CONTRAST_DEF; - sd->gain = GAIN_DEF; - sd->exposure = EXPOSURE_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->hflip = HFLIP_DEF; - sd->vflip = VFLIP_DEF; - return 0; -} - -/* This function is used by pac7311 only */ -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x10, sd->contrast >> 4); - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int gain = GAIN_MAX - sd->gain; - - if (gain < 1) - gain = 1; - else if (gain > 245) - gain = 245; - reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ - reg_w(gspca_dev, 0x0e, 0x00); - reg_w(gspca_dev, 0x0f, gain); - - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 reg; - - /* register 2 of frame 3/4 contains the clock divider configuring the - no fps according to the formula: 60 / reg. sd->exposure is the - desired exposure time in ms. */ - reg = 120 * sd->exposure / 1000; - if (reg < 2) - reg = 2; - else if (reg > 63) - reg = 63; - - reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ - reg_w(gspca_dev, 0x02, reg); - - /* Page 1 register 8 must always be 0x08 except when not in - 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */ - reg_w(gspca_dev, 0xff, 0x01); - if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv && - reg <= 3) { - reg_w(gspca_dev, 0x08, 0x09); - } else { - reg_w(gspca_dev, 0x08, 0x08); - } - - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); -} - -static void sethvflip(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 data; - - reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ - data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00); - reg_w(gspca_dev, 0x21, data); - - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); -} - -/* this function is called at probe and resume time for pac7311 */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2); - return gspca_dev->usb_err; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sof_read = 0; - - reg_w_var(gspca_dev, start_7311, - page4_7311, sizeof(page4_7311)); - setcontrast(gspca_dev); - setgain(gspca_dev); - setexposure(gspca_dev); - sethvflip(gspca_dev); - - /* set correct resolution */ - switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - case 2: /* 160x120 pac7311 */ - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x17, 0x20); - reg_w(gspca_dev, 0x87, 0x10); - break; - case 1: /* 320x240 pac7311 */ - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x17, 0x30); - reg_w(gspca_dev, 0x87, 0x11); - break; - case 0: /* 640x480 */ - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x17, 0x00); - reg_w(gspca_dev, 0x87, 0x12); - break; - } - - sd->sof_read = 0; - sd->autogain_ignore_frames = 0; - atomic_set(&sd->avg_lum, -1); - - /* start stream */ - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x78, 0x05); - - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x27, 0x80); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x53); - reg_w(gspca_dev, 0x2a, 0x0e); - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x3e, 0x20); - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ -} - -/* called on streamoff with alt 0 and on disconnect for 7311 */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -/* Include pac common sof detection functions */ -#include "pac_common.h" - -static void do_autogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int avg_lum = atomic_read(&sd->avg_lum); - int desired_lum, deadzone; - - if (avg_lum == -1) - return; - - desired_lum = 200; - deadzone = 20; - - if (sd->autogain_ignore_frames > 0) - sd->autogain_ignore_frames--; - else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, - deadzone, GAIN_KNEE, EXPOSURE_KNEE)) - sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; -} - -/* JPEG header, part 1 */ -static const unsigned char pac_jpeg_header1[] = { - 0xff, 0xd8, /* SOI: Start of Image */ - - 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ - 0x00, 0x11, /* length = 17 bytes (including this length field) */ - 0x08 /* Precision: 8 */ - /* 2 bytes is placed here: number of image lines */ - /* 2 bytes is placed here: samples per line */ -}; - -/* JPEG header, continued */ -static const unsigned char pac_jpeg_header2[] = { - 0x03, /* Number of image components: 3 */ - 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ - 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ - 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ - - 0xff, 0xda, /* SOS: Start Of Scan */ - 0x00, 0x0c, /* length = 12 bytes (including this length field) */ - 0x03, /* number of components: 3 */ - 0x01, 0x00, /* selector 1, table 0x00 */ - 0x02, 0x11, /* selector 2, table 0x11 */ - 0x03, 0x11, /* selector 3, table 0x11 */ - 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ - 0x00 /* Successive approximation: 0 */ -}; - -static void pac_start_frame(struct gspca_dev *gspca_dev, - __u16 lines, __u16 samples_per_line) -{ - unsigned char tmpbuf[4]; - - gspca_frame_add(gspca_dev, FIRST_PACKET, - pac_jpeg_header1, sizeof(pac_jpeg_header1)); - - tmpbuf[0] = lines >> 8; - tmpbuf[1] = lines & 0xff; - tmpbuf[2] = samples_per_line >> 8; - tmpbuf[3] = samples_per_line & 0xff; - - gspca_frame_add(gspca_dev, INTER_PACKET, - tmpbuf, sizeof(tmpbuf)); - gspca_frame_add(gspca_dev, INTER_PACKET, - pac_jpeg_header2, sizeof(pac_jpeg_header2)); -} - -/* this function is run at interrupt level */ -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 *image; - unsigned char *sof; - - sof = pac_find_sof(&sd->sof_read, data, len); - if (sof) { - int n, lum_offset, footer_length; - - /* 6 bytes after the FF D9 EOF marker a number of lumination - bytes are send corresponding to different parts of the - image, the 14th and 15th byte after the EOF seem to - correspond to the center of the image */ - lum_offset = 24 + sizeof pac_sof_marker; - footer_length = 26; - - /* Finish decoding current frame */ - n = (sof - data) - (footer_length + sizeof pac_sof_marker); - if (n < 0) { - gspca_dev->image_len += n; - n = 0; - } else { - gspca_frame_add(gspca_dev, INTER_PACKET, data, n); - } - image = gspca_dev->image; - if (image != NULL - && image[gspca_dev->image_len - 2] == 0xff - && image[gspca_dev->image_len - 1] == 0xd9) - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - - n = sof - data; - len -= n; - data = sof; - - /* Get average lumination */ - if (gspca_dev->last_packet_type == LAST_PACKET && - n >= lum_offset) - atomic_set(&sd->avg_lum, data[-lum_offset] + - data[-lum_offset + 1]); - else - atomic_set(&sd->avg_lum, -1); - - /* Start the new frame with the jpeg header */ - pac_start_frame(gspca_dev, - gspca_dev->height, gspca_dev->width); - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - /* when switching to autogain set defaults to make sure - we are on a valid point of the autogain gain / - exposure knee graph, and give this change time to - take effect before doing autogain. */ - if (sd->autogain) { - sd->exposure = EXPOSURE_DEF; - sd->gain = GAIN_DEF; - if (gspca_dev->streaming) { - sd->autogain_ignore_frames = - PAC_AUTOGAIN_IGNORE_FRAMES; - setexposure(gspca_dev); - setgain(gspca_dev); - } - } - - return gspca_dev->usb_err; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hflip; - return 0; -} - -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->vflip; - return 0; -} - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* interrupt packet data */ - int len) /* interrupt packet length */ -{ - int ret = -EINVAL; - u8 data0, data1; - - if (len == 2) { - data0 = data[0]; - data1 = data[1]; - if ((data0 == 0x00 && data1 == 0x11) || - (data0 == 0x22 && data1 == 0x33) || - (data0 == 0x44 && data1 == 0x55) || - (data0 == 0x66 && data1 == 0x77) || - (data0 == 0x88 && data1 == 0x99) || - (data0 == 0xaa && data1 == 0xbb) || - (data0 == 0xcc && data1 == 0xdd) || - (data0 == 0xee && data1 == 0xff)) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); - input_sync(gspca_dev->input_dev); - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - ret = 0; - } - } - - return ret; -} -#endif - -/* sub-driver description for pac7311 */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = do_autogain, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -#endif -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x093a, 0x2600)}, - {USB_DEVICE(0x093a, 0x2601)}, - {USB_DEVICE(0x093a, 0x2603)}, - {USB_DEVICE(0x093a, 0x2608)}, - {USB_DEVICE(0x093a, 0x260e)}, - {USB_DEVICE(0x093a, 0x260f)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac_common.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/pac_common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -/* - * Pixart PAC207BCA / PAC73xx common functions - * - * Copyright (C) 2008 Hans de Goede - * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li - * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * (at your option) any later version. - * - * 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 - * - */ - -/* We calculate the autogain at the end of the transfer of a frame, at this - moment a frame with the old settings is being captured and transmitted. So - if we adjust the gain or exposure we must ignore atleast the next frame for - the new settings to come into effect before doing any other adjustments. */ -#define PAC_AUTOGAIN_IGNORE_FRAMES 2 - -static const unsigned char pac_sof_marker[5] = - { 0xff, 0xff, 0x00, 0xff, 0x96 }; - -/* - The following state machine finds the SOF marker sequence - 0xff, 0xff, 0x00, 0xff, 0x96 in a byte stream. - - +----------+ - | 0: START |<---------------\ - +----------+<-\ | - | \---/otherwise | - v 0xff | - +----------+ otherwise | - | 1 |--------------->* - | | ^ - +----------+ | - | | - v 0xff | - +----------+<-\0xff | - /->| |--/ | - | | 2 |--------------->* - | | | otherwise ^ - | +----------+ | - | | | - | v 0x00 | - | +----------+ | - | | 3 | | - | | |--------------->* - | +----------+ otherwise ^ - | | | - 0xff | v 0xff | - | +----------+ | - \--| 4 | | - | |----------------/ - +----------+ otherwise - | - v 0x96 - +----------+ - | FOUND | - +----------+ -*/ - -static unsigned char *pac_find_sof(u8 *sof_read, - unsigned char *m, int len) -{ - int i; - - /* Search for the SOF marker (fixed part) in the header */ - for (i = 0; i < len; i++) { - switch (*sof_read) { - case 0: - if (m[i] == 0xff) - *sof_read = 1; - break; - case 1: - if (m[i] == 0xff) - *sof_read = 2; - else - *sof_read = 0; - break; - case 2: - switch (m[i]) { - case 0x00: - *sof_read = 3; - break; - case 0xff: - /* stay in this state */ - break; - default: - *sof_read = 0; - } - break; - case 3: - if (m[i] == 0xff) - *sof_read = 4; - else - *sof_read = 0; - break; - case 4: - switch (m[i]) { - case 0x96: - /* Pattern found */ - PDEBUG(D_FRAM, - "SOF found, bytes to analyze: %u." - " Frame starts at byte #%u", - len, i + 1); - *sof_read = 0; - return m + i + 1; - break; - case 0xff: - *sof_read = 2; - break; - default: - *sof_read = 0; - } - break; - default: - *sof_read = 0; - } - } - - return NULL; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c2028.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c2028.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c2028.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c2028.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,750 +0,0 @@ -/* - * SN9C2028 library - * - * Copyright (C) 2009 Theodore Kilgore - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "sn9c2028" - -#include "gspca.h" - -MODULE_AUTHOR("Theodore Kilgore"); -MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - u8 sof_read; - u16 model; -}; - -struct init_command { - unsigned char instruction[6]; - unsigned char to_read; /* length to read. 0 means no reply requested */ -}; - -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[] = { -}; - -/* How to change the resolution of any of the VGA cams is unknown */ -static const struct v4l2_pix_format vga_mode[] = { - {640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 4, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -/* No way to change the resolution of the CIF cams is known */ -static const struct v4l2_pix_format cif_mode[] = { - {352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 4, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -/* the bytes to write are in gspca_dev->usb_buf */ -static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command) -{ - int rc; - - PDEBUG(D_USBO, "sending command %02x%02x%02x%02x%02x%02x", command[0], - command[1], command[2], command[3], command[4], command[5]); - - memcpy(gspca_dev->usb_buf, command, 6); - rc = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - USB_REQ_GET_CONFIGURATION, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 2, 0, gspca_dev->usb_buf, 6, 500); - if (rc < 0) { - err("command write [%02x] error %d", - gspca_dev->usb_buf[0], rc); - return rc; - } - - return 0; -} - -static int sn9c2028_read1(struct gspca_dev *gspca_dev) -{ - int rc; - - rc = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - USB_REQ_GET_STATUS, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 1, 0, gspca_dev->usb_buf, 1, 500); - if (rc != 1) { - err("read1 error %d", rc); - return (rc < 0) ? rc : -EIO; - } - PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]); - return gspca_dev->usb_buf[0]; -} - -static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading) -{ - int rc; - rc = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - USB_REQ_GET_STATUS, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 4, 0, gspca_dev->usb_buf, 4, 500); - if (rc != 4) { - err("read4 error %d", rc); - return (rc < 0) ? rc : -EIO; - } - memcpy(reading, gspca_dev->usb_buf, 4); - PDEBUG(D_USBI, "read4 response %02x%02x%02x%02x", reading[0], - reading[1], reading[2], reading[3]); - return rc; -} - -static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) -{ - int i, status; - __u8 reading[4]; - - status = sn9c2028_command(gspca_dev, command); - if (status < 0) - return status; - - status = -1; - for (i = 0; i < 256 && status < 2; i++) - status = sn9c2028_read1(gspca_dev); - if (status != 2) { - err("long command status read error %d", status); - return (status < 0) ? status : -EIO; - } - - memset(reading, 0, 4); - status = sn9c2028_read4(gspca_dev, reading); - if (status < 0) - return status; - - /* in general, the first byte of the response is the first byte of - * the command, or'ed with 8 */ - status = sn9c2028_read1(gspca_dev); - if (status < 0) - return status; - - return 0; -} - -static int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command) -{ - int err_code; - - err_code = sn9c2028_command(gspca_dev, command); - if (err_code < 0) - return err_code; - - err_code = sn9c2028_read1(gspca_dev); - if (err_code < 0) - return err_code; - - return 0; -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam = &gspca_dev->cam; - - PDEBUG(D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)", - id->idVendor, id->idProduct); - - sd->model = id->idProduct; - - switch (sd->model) { - case 0x7005: - PDEBUG(D_PROBE, "Genius Smart 300 camera"); - break; - case 0x8000: - PDEBUG(D_PROBE, "DC31VC"); - break; - case 0x8001: - PDEBUG(D_PROBE, "Spy camera"); - break; - case 0x8003: - PDEBUG(D_PROBE, "CIF camera"); - break; - case 0x8008: - PDEBUG(D_PROBE, "Mini-Shotz ms-350 camera"); - break; - case 0x800a: - PDEBUG(D_PROBE, "Vivitar 3350b type camera"); - cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP; - break; - } - - switch (sd->model) { - case 0x8000: - case 0x8001: - case 0x8003: - cam->cam_mode = cif_mode; - cam->nmodes = ARRAY_SIZE(cif_mode); - break; - default: - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - } - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - int status = -1; - - sn9c2028_read1(gspca_dev); - sn9c2028_read1(gspca_dev); - status = sn9c2028_read1(gspca_dev); - - return (status < 0) ? status : 0; -} - -static int run_start_commands(struct gspca_dev *gspca_dev, - struct init_command *cam_commands, int n) -{ - int i, err_code = -1; - - for (i = 0; i < n; i++) { - switch (cam_commands[i].to_read) { - case 4: - err_code = sn9c2028_long_command(gspca_dev, - cam_commands[i].instruction); - break; - case 1: - err_code = sn9c2028_short_command(gspca_dev, - cam_commands[i].instruction); - break; - case 0: - err_code = sn9c2028_command(gspca_dev, - cam_commands[i].instruction); - break; - } - if (err_code < 0) - return err_code; - } - return 0; -} - -static int start_spy_cam(struct gspca_dev *gspca_dev) -{ - struct init_command spy_start_commands[] = { - {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4}, - {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4}, - {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width 352 */ - {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */ - /* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */ - {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, - {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/ - /* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */ - {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4}, - /* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */ - {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, - /* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */ - {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, - /* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */ - {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, - {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, - {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, - {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/ - /*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */ - {{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */ - /*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */ - {{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */ - {{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */ - {{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4}, - /*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */ - {{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4}, - /* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */ - /* brightness or gain. 0 is default. 4 is good - * indoors at night with incandescent lighting */ - {{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/ - {{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4}, - /* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */ - {{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */ - /* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */ - {{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1}, - {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */ - /* Camera should start to capture now. */ - }; - - return run_start_commands(gspca_dev, spy_start_commands, - ARRAY_SIZE(spy_start_commands)); -} - -static int start_cif_cam(struct gspca_dev *gspca_dev) -{ - struct init_command cif_start_commands[] = { - {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, - /* The entire sequence below seems redundant */ - /* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4}, - {{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width? - {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height? - {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample? - {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4}, - {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, - {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, - {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, - {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, - {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/ - {{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1}, - {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */ - {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */ - /* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample? - * {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing - * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */ - /* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, - * causes subsampling - * but not a change in the resolution setting! */ - {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4}, - {{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4}, - {{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4}, - {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1}, - {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1}, - {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1}, - {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */ - /* Camera should start to capture now. */ - }; - - return run_start_commands(gspca_dev, cif_start_commands, - ARRAY_SIZE(cif_start_commands)); -} - -static int start_ms350_cam(struct gspca_dev *gspca_dev) -{ - struct init_command ms350_start_commands[] = { - {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4}, - {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4}, - {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, - {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, - {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, - {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, - {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, - {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, - {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, - {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, - {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width */ - {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */ - {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */ - {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, - {{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */ - {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, - {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, - {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, - {{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1}, - {{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0}, - /* Camera should start to capture now. */ - }; - - return run_start_commands(gspca_dev, ms350_start_commands, - ARRAY_SIZE(ms350_start_commands)); -} - -static int start_genius_cam(struct gspca_dev *gspca_dev) -{ - struct init_command genius_start_commands[] = { - {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, - {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, - /* "preliminary" width and height settings */ - {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, - {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, - {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, - {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, - {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, - {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */ - {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */ - {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, - {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, - {{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4}, - {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, - {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, - {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, - {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4}, - {{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4}, - {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1}, - {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1}, - {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0} - /* Camera should start to capture now. */ - }; - - return run_start_commands(gspca_dev, genius_start_commands, - ARRAY_SIZE(genius_start_commands)); -} - -static int start_vivitar_cam(struct gspca_dev *gspca_dev) -{ - struct init_command vivitar_start_commands[] = { - {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4}, - {{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4}, - {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, - {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, - {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, - {{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4}, - /* - * Above is changed from OEM 0x0b. Fixes Bayer tiling. - * Presumably gives a vertical shift of one row. - */ - {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4}, - /* Above seems to do horizontal shift. */ - {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, - {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, - {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, - {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, - /* Above three commands seem to relate to brightness. */ - {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, - {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1}, - /* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, - {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, - {{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */ - {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1}, - {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1}, - {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1}, - {{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1}, - /* Above is brightness; OEM driver setting is 0x10 */ - {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4}, - {{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1}, - {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1} - }; - - return run_start_commands(gspca_dev, vivitar_start_commands, - ARRAY_SIZE(vivitar_start_commands)); -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int err_code; - - sd->sof_read = 0; - - switch (sd->model) { - case 0x7005: - err_code = start_genius_cam(gspca_dev); - break; - case 0x8001: - err_code = start_spy_cam(gspca_dev); - break; - case 0x8003: - err_code = start_cif_cam(gspca_dev); - break; - case 0x8008: - err_code = start_ms350_cam(gspca_dev); - break; - case 0x800a: - err_code = start_vivitar_cam(gspca_dev); - break; - default: - err("Starting unknown camera, please report this"); - return -ENXIO; - } - - return err_code; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - int result; - __u8 data[6]; - - result = sn9c2028_read1(gspca_dev); - if (result < 0) - PDEBUG(D_ERR, "Camera Stop read failed"); - - memset(data, 0, 6); - data[0] = 0x14; - result = sn9c2028_command(gspca_dev, data); - if (result < 0) - PDEBUG(D_ERR, "Camera Stop command failed"); -} - -/* Include sn9c2028 sof detection functions */ -#include "sn9c2028.h" - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - __u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - unsigned char *sof; - - sof = sn9c2028_find_sof(gspca_dev, data, len); - if (sof) { - int n; - - /* finish decoding current frame */ - n = sof - data; - if (n > sizeof sn9c2028_sof_marker) - n -= sizeof sn9c2028_sof_marker; - else - n = 0; - gspca_frame_add(gspca_dev, LAST_PACKET, data, n); - /* Start next frame. */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - sn9c2028_sof_marker, sizeof sn9c2028_sof_marker); - len -= sof - data; - data = sof; - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */ - /* The Genius Smart is untested. I can't find an owner ! */ - /* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */ - {USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */ - {USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */ - /* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */ - {USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */ - {USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */ - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c2028.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c2028.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c2028.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c2028.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - * SN9C2028 common functions - * - * Copyright (C) 2009 Theodore Kilgore - * - * Based closely upon the file gspca/pac_common.h - * - * 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, or - * (at your option) any later version. - * - * 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 - * - */ - -static const unsigned char sn9c2028_sof_marker[5] = - { 0xff, 0xff, 0x00, 0xc4, 0xc4 }; - -static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev, - unsigned char *m, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - - /* Search for the SOF marker (fixed part) in the header */ - for (i = 0; i < len; i++) { - if (m[i] == sn9c2028_sof_marker[sd->sof_read]) { - sd->sof_read++; - if (sd->sof_read == sizeof(sn9c2028_sof_marker)) { - PDEBUG(D_FRAM, - "SOF found, bytes to analyze: %u." - " Frame starts at byte #%u", - len, i + 1); - sd->sof_read = 0; - return m + i + 1; - } - } else { - sd->sof_read = 0; - } - } - - return NULL; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c20x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c20x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c20x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sn9c20x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2566 +0,0 @@ -/* - * Sonix sn9c201 sn9c202 library - * Copyright (C) 2008-2009 microdia project - * Copyright (C) 2009 Brian Johnson - * - * 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, or - * any later version. - * - * 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 - -#include "gspca.h" -#include "jpeg.h" - -#include -#include - -MODULE_AUTHOR("Brian Johnson , " - "microdia project "); -MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver"); -MODULE_LICENSE("GPL"); - -#define MODULE_NAME "sn9c20x" - -/* - * Pixel format private data - */ -#define SCALE_MASK 0x0f -#define SCALE_160x120 0 -#define SCALE_320x240 1 -#define SCALE_640x480 2 -#define SCALE_1280x1024 3 -#define MODE_RAW 0x10 -#define MODE_JPEG 0x20 -#define MODE_SXGA 0x80 - -#define SENSOR_OV9650 0 -#define SENSOR_OV9655 1 -#define SENSOR_SOI968 2 -#define SENSOR_OV7660 3 -#define SENSOR_OV7670 4 -#define SENSOR_MT9V011 5 -#define SENSOR_MT9V111 6 -#define SENSOR_MT9V112 7 -#define SENSOR_MT9M001 8 -#define SENSOR_MT9M111 9 -#define SENSOR_MT9M112 10 -#define SENSOR_HV7131R 11 -#define SENSOR_MT9VPRB 20 - -/* camera flags */ -#define HAS_NO_BUTTON 0x1 -#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */ -#define FLIP_DETECT 0x4 - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; - -#define MIN_AVG_LUM 80 -#define MAX_AVG_LUM 130 - atomic_t avg_lum; - u8 old_step; - u8 older_step; - u8 exposure_step; - - u8 brightness; - u8 contrast; - u8 saturation; - s16 hue; - u8 gamma; - u8 red; - u8 blue; - - u8 hflip; - u8 vflip; - u8 gain; - u16 exposure; - u8 auto_exposure; - - u8 i2c_addr; - u8 sensor; - u8 hstart; - u8 vstart; - - u8 jpeg_hdr[JPEG_HDR_SZ]; - u8 quality; - - u8 flags; -}; - -struct i2c_reg_u8 { - u8 reg; - u8 val; -}; - -struct i2c_reg_u16 { - u8 reg; - u16 val; -}; - -static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val); -static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val); -static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val); -static int sd_sethue(struct gspca_dev *gspca_dev, s32 val); -static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val); -static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val); -static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val); -static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val); -static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val); -static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val); -static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val); -static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val); -static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val); -static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val); -static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val); -static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val); -static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val); - -static const struct dmi_system_id flip_dmi_table[] = { - { - .ident = "MSI MS-1034", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"), - DMI_MATCH(DMI_PRODUCT_VERSION, "0341") - } - }, - { - .ident = "MSI MS-1632", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), - DMI_MATCH(DMI_BOARD_NAME, "MS-1632") - } - }, - { - .ident = "MSI MS-1633X", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), - DMI_MATCH(DMI_BOARD_NAME, "MS-1633X") - } - }, - { - .ident = "MSI MS-1635X", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), - DMI_MATCH(DMI_BOARD_NAME, "MS-1635X") - } - }, - { - .ident = "ASUSTeK W7J", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_BOARD_NAME, "W7J ") - } - }, - {} -}; - -static const struct ctrl sd_ctrls[] = { - { -#define BRIGHTNESS_IDX 0 - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xff, - .step = 1, -#define BRIGHTNESS_DEFAULT 0x7f - .default_value = BRIGHTNESS_DEFAULT, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { -#define CONTRAST_IDX 1 - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, -#define CONTRAST_DEFAULT 0x7f - .default_value = CONTRAST_DEFAULT, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { -#define SATURATION_IDX 2 - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, -#define SATURATION_DEFAULT 0x7f - .default_value = SATURATION_DEFAULT, - }, - .set = sd_setsaturation, - .get = sd_getsaturation, - }, - { -#define HUE_IDX 3 - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = -180, - .maximum = 180, - .step = 1, -#define HUE_DEFAULT 0 - .default_value = HUE_DEFAULT, - }, - .set = sd_sethue, - .get = sd_gethue, - }, - { -#define GAMMA_IDX 4 - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 0xff, - .step = 1, -#define GAMMA_DEFAULT 0x10 - .default_value = GAMMA_DEFAULT, - }, - .set = sd_setgamma, - .get = sd_getgamma, - }, - { -#define BLUE_IDX 5 - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 0, - .maximum = 0x7f, - .step = 1, -#define BLUE_DEFAULT 0x28 - .default_value = BLUE_DEFAULT, - }, - .set = sd_setbluebalance, - .get = sd_getbluebalance, - }, - { -#define RED_IDX 6 - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 0, - .maximum = 0x7f, - .step = 1, -#define RED_DEFAULT 0x28 - .default_value = RED_DEFAULT, - }, - .set = sd_setredbalance, - .get = sd_getredbalance, - }, - { -#define HFLIP_IDX 7 - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Horizontal Flip", - .minimum = 0, - .maximum = 1, - .step = 1, -#define HFLIP_DEFAULT 0 - .default_value = HFLIP_DEFAULT, - }, - .set = sd_sethflip, - .get = sd_gethflip, - }, - { -#define VFLIP_IDX 8 - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vertical Flip", - .minimum = 0, - .maximum = 1, - .step = 1, -#define VFLIP_DEFAULT 0 - .default_value = VFLIP_DEFAULT, - }, - .set = sd_setvflip, - .get = sd_getvflip, - }, - { -#define EXPOSURE_IDX 9 - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 0x1780, - .step = 1, -#define EXPOSURE_DEFAULT 0x33 - .default_value = EXPOSURE_DEFAULT, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { -#define GAIN_IDX 10 - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 28, - .step = 1, -#define GAIN_DEFAULT 0x00 - .default_value = GAIN_DEFAULT, - }, - .set = sd_setgain, - .get = sd_getgain, - }, - { -#define AUTOGAIN_IDX 11 - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTO_EXPOSURE_DEFAULT 1 - .default_value = AUTO_EXPOSURE_DEFAULT, - }, - .set = sd_setautoexposure, - .get = sd_getautoexposure, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = SCALE_160x120 | MODE_JPEG}, - {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_160x120 | MODE_RAW}, - {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 240 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_160x120}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = SCALE_320x240 | MODE_JPEG}, - {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 , - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_320x240 | MODE_RAW}, - {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 480 * 240 , - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_320x240}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = SCALE_640x480 | MODE_JPEG}, - {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_640x480 | MODE_RAW}, - {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 960 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_640x480}, -}; - -static const struct v4l2_pix_format sxga_mode[] = { - {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = SCALE_160x120 | MODE_JPEG}, - {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_160x120 | MODE_RAW}, - {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 240 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_160x120}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = SCALE_320x240 | MODE_JPEG}, - {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 , - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_320x240 | MODE_RAW}, - {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 480 * 240 , - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_320x240}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = SCALE_640x480 | MODE_JPEG}, - {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_640x480 | MODE_RAW}, - {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 960 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_640x480}, - {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 1280, - .sizeimage = 1280 * 1024, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA}, -}; - -static const struct v4l2_pix_format mono_mode[] = { - {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_160x120 | MODE_RAW}, - {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 , - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_320x240 | MODE_RAW}, - {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_640x480 | MODE_RAW}, - {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, - .bytesperline = 1280, - .sizeimage = 1280 * 1024, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA}, -}; - -static const s16 hsv_red_x[] = { - 41, 44, 46, 48, 50, 52, 54, 56, - 58, 60, 62, 64, 66, 68, 70, 72, - 74, 76, 78, 80, 81, 83, 85, 87, - 88, 90, 92, 93, 95, 97, 98, 100, - 101, 102, 104, 105, 107, 108, 109, 110, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 123, 124, 125, 125, - 126, 127, 127, 128, 128, 129, 129, 129, - 130, 130, 130, 130, 131, 131, 131, 131, - 131, 131, 131, 131, 130, 130, 130, 130, - 129, 129, 129, 128, 128, 127, 127, 126, - 125, 125, 124, 123, 122, 122, 121, 120, - 119, 118, 117, 116, 115, 114, 112, 111, - 110, 109, 107, 106, 105, 103, 102, 101, - 99, 98, 96, 94, 93, 91, 90, 88, - 86, 84, 83, 81, 79, 77, 75, 74, - 72, 70, 68, 66, 64, 62, 60, 58, - 56, 54, 52, 49, 47, 45, 43, 41, - 39, 36, 34, 32, 30, 28, 25, 23, - 21, 19, 16, 14, 12, 9, 7, 5, - 3, 0, -1, -3, -6, -8, -10, -12, - -15, -17, -19, -22, -24, -26, -28, -30, - -33, -35, -37, -39, -41, -44, -46, -48, - -50, -52, -54, -56, -58, -60, -62, -64, - -66, -68, -70, -72, -74, -76, -78, -80, - -81, -83, -85, -87, -88, -90, -92, -93, - -95, -97, -98, -100, -101, -102, -104, -105, - -107, -108, -109, -110, -112, -113, -114, -115, - -116, -117, -118, -119, -120, -121, -122, -123, - -123, -124, -125, -125, -126, -127, -127, -128, - -128, -128, -128, -128, -128, -128, -128, -128, - -128, -128, -128, -128, -128, -128, -128, -128, - -128, -128, -128, -128, -128, -128, -128, -128, - -128, -127, -127, -126, -125, -125, -124, -123, - -122, -122, -121, -120, -119, -118, -117, -116, - -115, -114, -112, -111, -110, -109, -107, -106, - -105, -103, -102, -101, -99, -98, -96, -94, - -93, -91, -90, -88, -86, -84, -83, -81, - -79, -77, -75, -74, -72, -70, -68, -66, - -64, -62, -60, -58, -56, -54, -52, -49, - -47, -45, -43, -41, -39, -36, -34, -32, - -30, -28, -25, -23, -21, -19, -16, -14, - -12, -9, -7, -5, -3, 0, 1, 3, - 6, 8, 10, 12, 15, 17, 19, 22, - 24, 26, 28, 30, 33, 35, 37, 39, 41 -}; - -static const s16 hsv_red_y[] = { - 82, 80, 78, 76, 74, 73, 71, 69, - 67, 65, 63, 61, 58, 56, 54, 52, - 50, 48, 46, 44, 41, 39, 37, 35, - 32, 30, 28, 26, 23, 21, 19, 16, - 14, 12, 10, 7, 5, 3, 0, -1, - -3, -6, -8, -10, -13, -15, -17, -19, - -22, -24, -26, -29, -31, -33, -35, -38, - -40, -42, -44, -46, -48, -51, -53, -55, - -57, -59, -61, -63, -65, -67, -69, -71, - -73, -75, -77, -79, -81, -82, -84, -86, - -88, -89, -91, -93, -94, -96, -98, -99, - -101, -102, -104, -105, -106, -108, -109, -110, - -112, -113, -114, -115, -116, -117, -119, -120, - -120, -121, -122, -123, -124, -125, -126, -126, - -127, -128, -128, -128, -128, -128, -128, -128, - -128, -128, -128, -128, -128, -128, -128, -128, - -128, -128, -128, -128, -128, -128, -128, -128, - -128, -128, -128, -128, -128, -128, -128, -128, - -127, -127, -126, -125, -125, -124, -123, -122, - -121, -120, -119, -118, -117, -116, -115, -114, - -113, -111, -110, -109, -107, -106, -105, -103, - -102, -100, -99, -97, -96, -94, -92, -91, - -89, -87, -85, -84, -82, -80, -78, -76, - -74, -73, -71, -69, -67, -65, -63, -61, - -58, -56, -54, -52, -50, -48, -46, -44, - -41, -39, -37, -35, -32, -30, -28, -26, - -23, -21, -19, -16, -14, -12, -10, -7, - -5, -3, 0, 1, 3, 6, 8, 10, - 13, 15, 17, 19, 22, 24, 26, 29, - 31, 33, 35, 38, 40, 42, 44, 46, - 48, 51, 53, 55, 57, 59, 61, 63, - 65, 67, 69, 71, 73, 75, 77, 79, - 81, 82, 84, 86, 88, 89, 91, 93, - 94, 96, 98, 99, 101, 102, 104, 105, - 106, 108, 109, 110, 112, 113, 114, 115, - 116, 117, 119, 120, 120, 121, 122, 123, - 124, 125, 126, 126, 127, 128, 128, 129, - 129, 130, 130, 131, 131, 131, 131, 132, - 132, 132, 132, 132, 132, 132, 132, 132, - 132, 132, 132, 131, 131, 131, 130, 130, - 130, 129, 129, 128, 127, 127, 126, 125, - 125, 124, 123, 122, 121, 120, 119, 118, - 117, 116, 115, 114, 113, 111, 110, 109, - 107, 106, 105, 103, 102, 100, 99, 97, - 96, 94, 92, 91, 89, 87, 85, 84, 82 -}; - -static const s16 hsv_green_x[] = { - -124, -124, -125, -125, -125, -125, -125, -125, - -125, -126, -126, -125, -125, -125, -125, -125, - -125, -124, -124, -124, -123, -123, -122, -122, - -121, -121, -120, -120, -119, -118, -117, -117, - -116, -115, -114, -113, -112, -111, -110, -109, - -108, -107, -105, -104, -103, -102, -100, -99, - -98, -96, -95, -93, -92, -91, -89, -87, - -86, -84, -83, -81, -79, -77, -76, -74, - -72, -70, -69, -67, -65, -63, -61, -59, - -57, -55, -53, -51, -49, -47, -45, -43, - -41, -39, -37, -35, -33, -30, -28, -26, - -24, -22, -20, -18, -15, -13, -11, -9, - -7, -4, -2, 0, 1, 3, 6, 8, - 10, 12, 14, 17, 19, 21, 23, 25, - 27, 29, 32, 34, 36, 38, 40, 42, - 44, 46, 48, 50, 52, 54, 56, 58, - 60, 62, 64, 66, 68, 70, 71, 73, - 75, 77, 78, 80, 82, 83, 85, 87, - 88, 90, 91, 93, 94, 96, 97, 98, - 100, 101, 102, 104, 105, 106, 107, 108, - 109, 111, 112, 113, 113, 114, 115, 116, - 117, 118, 118, 119, 120, 120, 121, 122, - 122, 123, 123, 124, 124, 124, 125, 125, - 125, 125, 125, 125, 125, 126, 126, 125, - 125, 125, 125, 125, 125, 124, 124, 124, - 123, 123, 122, 122, 121, 121, 120, 120, - 119, 118, 117, 117, 116, 115, 114, 113, - 112, 111, 110, 109, 108, 107, 105, 104, - 103, 102, 100, 99, 98, 96, 95, 93, - 92, 91, 89, 87, 86, 84, 83, 81, - 79, 77, 76, 74, 72, 70, 69, 67, - 65, 63, 61, 59, 57, 55, 53, 51, - 49, 47, 45, 43, 41, 39, 37, 35, - 33, 30, 28, 26, 24, 22, 20, 18, - 15, 13, 11, 9, 7, 4, 2, 0, - -1, -3, -6, -8, -10, -12, -14, -17, - -19, -21, -23, -25, -27, -29, -32, -34, - -36, -38, -40, -42, -44, -46, -48, -50, - -52, -54, -56, -58, -60, -62, -64, -66, - -68, -70, -71, -73, -75, -77, -78, -80, - -82, -83, -85, -87, -88, -90, -91, -93, - -94, -96, -97, -98, -100, -101, -102, -104, - -105, -106, -107, -108, -109, -111, -112, -113, - -113, -114, -115, -116, -117, -118, -118, -119, - -120, -120, -121, -122, -122, -123, -123, -124, -124 -}; - -static const s16 hsv_green_y[] = { - -100, -99, -98, -97, -95, -94, -93, -91, - -90, -89, -87, -86, -84, -83, -81, -80, - -78, -76, -75, -73, -71, -70, -68, -66, - -64, -63, -61, -59, -57, -55, -53, -51, - -49, -48, -46, -44, -42, -40, -38, -36, - -34, -32, -30, -27, -25, -23, -21, -19, - -17, -15, -13, -11, -9, -7, -4, -2, - 0, 1, 3, 5, 7, 9, 11, 14, - 16, 18, 20, 22, 24, 26, 28, 30, - 32, 34, 36, 38, 40, 42, 44, 46, - 48, 50, 52, 54, 56, 58, 59, 61, - 63, 65, 67, 68, 70, 72, 74, 75, - 77, 78, 80, 82, 83, 85, 86, 88, - 89, 90, 92, 93, 95, 96, 97, 98, - 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 112, 113, 114, - 115, 115, 116, 116, 117, 117, 118, 118, - 119, 119, 119, 120, 120, 120, 120, 120, - 121, 121, 121, 121, 121, 121, 120, 120, - 120, 120, 120, 119, 119, 119, 118, 118, - 117, 117, 116, 116, 115, 114, 114, 113, - 112, 111, 111, 110, 109, 108, 107, 106, - 105, 104, 103, 102, 100, 99, 98, 97, - 95, 94, 93, 91, 90, 89, 87, 86, - 84, 83, 81, 80, 78, 76, 75, 73, - 71, 70, 68, 66, 64, 63, 61, 59, - 57, 55, 53, 51, 49, 48, 46, 44, - 42, 40, 38, 36, 34, 32, 30, 27, - 25, 23, 21, 19, 17, 15, 13, 11, - 9, 7, 4, 2, 0, -1, -3, -5, - -7, -9, -11, -14, -16, -18, -20, -22, - -24, -26, -28, -30, -32, -34, -36, -38, - -40, -42, -44, -46, -48, -50, -52, -54, - -56, -58, -59, -61, -63, -65, -67, -68, - -70, -72, -74, -75, -77, -78, -80, -82, - -83, -85, -86, -88, -89, -90, -92, -93, - -95, -96, -97, -98, -100, -101, -102, -103, - -104, -105, -106, -107, -108, -109, -110, -111, - -112, -112, -113, -114, -115, -115, -116, -116, - -117, -117, -118, -118, -119, -119, -119, -120, - -120, -120, -120, -120, -121, -121, -121, -121, - -121, -121, -120, -120, -120, -120, -120, -119, - -119, -119, -118, -118, -117, -117, -116, -116, - -115, -114, -114, -113, -112, -111, -111, -110, - -109, -108, -107, -106, -105, -104, -103, -102, -100 -}; - -static const s16 hsv_blue_x[] = { - 112, 113, 114, 114, 115, 116, 117, 117, - 118, 118, 119, 119, 120, 120, 120, 121, - 121, 121, 122, 122, 122, 122, 122, 122, - 122, 122, 122, 122, 122, 122, 121, 121, - 121, 120, 120, 120, 119, 119, 118, 118, - 117, 116, 116, 115, 114, 113, 113, 112, - 111, 110, 109, 108, 107, 106, 105, 104, - 103, 102, 100, 99, 98, 97, 95, 94, - 93, 91, 90, 88, 87, 85, 84, 82, - 80, 79, 77, 76, 74, 72, 70, 69, - 67, 65, 63, 61, 60, 58, 56, 54, - 52, 50, 48, 46, 44, 42, 40, 38, - 36, 34, 32, 30, 28, 26, 24, 22, - 19, 17, 15, 13, 11, 9, 7, 5, - 2, 0, -1, -3, -5, -7, -9, -12, - -14, -16, -18, -20, -22, -24, -26, -28, - -31, -33, -35, -37, -39, -41, -43, -45, - -47, -49, -51, -53, -54, -56, -58, -60, - -62, -64, -66, -67, -69, -71, -73, -74, - -76, -78, -79, -81, -83, -84, -86, -87, - -89, -90, -92, -93, -94, -96, -97, -98, - -99, -101, -102, -103, -104, -105, -106, -107, - -108, -109, -110, -111, -112, -113, -114, -114, - -115, -116, -117, -117, -118, -118, -119, -119, - -120, -120, -120, -121, -121, -121, -122, -122, - -122, -122, -122, -122, -122, -122, -122, -122, - -122, -122, -121, -121, -121, -120, -120, -120, - -119, -119, -118, -118, -117, -116, -116, -115, - -114, -113, -113, -112, -111, -110, -109, -108, - -107, -106, -105, -104, -103, -102, -100, -99, - -98, -97, -95, -94, -93, -91, -90, -88, - -87, -85, -84, -82, -80, -79, -77, -76, - -74, -72, -70, -69, -67, -65, -63, -61, - -60, -58, -56, -54, -52, -50, -48, -46, - -44, -42, -40, -38, -36, -34, -32, -30, - -28, -26, -24, -22, -19, -17, -15, -13, - -11, -9, -7, -5, -2, 0, 1, 3, - 5, 7, 9, 12, 14, 16, 18, 20, - 22, 24, 26, 28, 31, 33, 35, 37, - 39, 41, 43, 45, 47, 49, 51, 53, - 54, 56, 58, 60, 62, 64, 66, 67, - 69, 71, 73, 74, 76, 78, 79, 81, - 83, 84, 86, 87, 89, 90, 92, 93, - 94, 96, 97, 98, 99, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112 -}; - -static const s16 hsv_blue_y[] = { - -11, -13, -15, -17, -19, -21, -23, -25, - -27, -29, -31, -33, -35, -37, -39, -41, - -43, -45, -46, -48, -50, -52, -54, -55, - -57, -59, -61, -62, -64, -66, -67, -69, - -71, -72, -74, -75, -77, -78, -80, -81, - -83, -84, -86, -87, -88, -90, -91, -92, - -93, -95, -96, -97, -98, -99, -100, -101, - -102, -103, -104, -105, -106, -106, -107, -108, - -109, -109, -110, -111, -111, -112, -112, -113, - -113, -114, -114, -114, -115, -115, -115, -115, - -116, -116, -116, -116, -116, -116, -116, -116, - -116, -115, -115, -115, -115, -114, -114, -114, - -113, -113, -112, -112, -111, -111, -110, -110, - -109, -108, -108, -107, -106, -105, -104, -103, - -102, -101, -100, -99, -98, -97, -96, -95, - -94, -93, -91, -90, -89, -88, -86, -85, - -84, -82, -81, -79, -78, -76, -75, -73, - -71, -70, -68, -67, -65, -63, -62, -60, - -58, -56, -55, -53, -51, -49, -47, -45, - -44, -42, -40, -38, -36, -34, -32, -30, - -28, -26, -24, -22, -20, -18, -16, -14, - -12, -10, -8, -6, -4, -2, 0, 1, - 3, 5, 7, 9, 11, 13, 15, 17, - 19, 21, 23, 25, 27, 29, 31, 33, - 35, 37, 39, 41, 43, 45, 46, 48, - 50, 52, 54, 55, 57, 59, 61, 62, - 64, 66, 67, 69, 71, 72, 74, 75, - 77, 78, 80, 81, 83, 84, 86, 87, - 88, 90, 91, 92, 93, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, - 106, 106, 107, 108, 109, 109, 110, 111, - 111, 112, 112, 113, 113, 114, 114, 114, - 115, 115, 115, 115, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 115, 115, 115, - 115, 114, 114, 114, 113, 113, 112, 112, - 111, 111, 110, 110, 109, 108, 108, 107, - 106, 105, 104, 103, 102, 101, 100, 99, - 98, 97, 96, 95, 94, 93, 91, 90, - 89, 88, 86, 85, 84, 82, 81, 79, - 78, 76, 75, 73, 71, 70, 68, 67, - 65, 63, 62, 60, 58, 56, 55, 53, - 51, 49, 47, 45, 44, 42, 40, 38, - 36, 34, 32, 30, 28, 26, 24, 22, - 20, 18, 16, 14, 12, 10, 8, 6, - 4, 2, 0, -1, -3, -5, -7, -9, -11 -}; - -static u16 i2c_ident[] = { - V4L2_IDENT_OV9650, - V4L2_IDENT_OV9655, - V4L2_IDENT_SOI968, - V4L2_IDENT_OV7660, - V4L2_IDENT_OV7670, - V4L2_IDENT_MT9V011, - V4L2_IDENT_MT9V111, - V4L2_IDENT_MT9V112, - V4L2_IDENT_MT9M001C12ST, - V4L2_IDENT_MT9M111, - V4L2_IDENT_MT9M112, - V4L2_IDENT_HV7131R, -}; - -static u16 bridge_init[][2] = { - {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c}, - {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40}, - {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10}, - {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00}, - {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50}, - {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50}, - {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04}, - {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05}, - {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00}, - {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d}, - {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04}, - {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8}, - {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32}, - {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd}, - {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01}, - {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f}, - {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f}, - {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01}, - {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80}, - {0x1007, 0x00} -}; - -/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */ -static u8 ov_gain[] = { - 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */, - 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */, - 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */, - 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */, - 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */, - 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */, - 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */, - 0x70 /* 8x */ -}; - -/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */ -static u16 micron1_gain[] = { - /* 1x 1.25x 1.5x 1.75x */ - 0x0020, 0x0028, 0x0030, 0x0038, - /* 2x 2.25x 2.5x 2.75x */ - 0x00a0, 0x00a4, 0x00a8, 0x00ac, - /* 3x 3.25x 3.5x 3.75x */ - 0x00b0, 0x00b4, 0x00b8, 0x00bc, - /* 4x 4.25x 4.5x 4.75x */ - 0x00c0, 0x00c4, 0x00c8, 0x00cc, - /* 5x 5.25x 5.5x 5.75x */ - 0x00d0, 0x00d4, 0x00d8, 0x00dc, - /* 6x 6.25x 6.5x 6.75x */ - 0x00e0, 0x00e4, 0x00e8, 0x00ec, - /* 7x 7.25x 7.5x 7.75x */ - 0x00f0, 0x00f4, 0x00f8, 0x00fc, - /* 8x */ - 0x01c0 -}; - -/* mt9m001 sensor uses a different gain formula then other micron sensors */ -/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */ -static u16 micron2_gain[] = { - /* 1x 1.25x 1.5x 1.75x */ - 0x0008, 0x000a, 0x000c, 0x000e, - /* 2x 2.25x 2.5x 2.75x */ - 0x0010, 0x0012, 0x0014, 0x0016, - /* 3x 3.25x 3.5x 3.75x */ - 0x0018, 0x001a, 0x001c, 0x001e, - /* 4x 4.25x 4.5x 4.75x */ - 0x0020, 0x0051, 0x0052, 0x0053, - /* 5x 5.25x 5.5x 5.75x */ - 0x0054, 0x0055, 0x0056, 0x0057, - /* 6x 6.25x 6.5x 6.75x */ - 0x0058, 0x0059, 0x005a, 0x005b, - /* 7x 7.25x 7.5x 7.75x */ - 0x005c, 0x005d, 0x005e, 0x005f, - /* 8x */ - 0x0060 -}; - -/* Gain = .5 + bit[7:0] / 16 */ -static u8 hv7131r_gain[] = { - 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */, - 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */, - 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */, - 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */, - 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */, - 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */, - 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */, - 0x78 /* 8x */ -}; - -static struct i2c_reg_u8 soi968_init[] = { - {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f}, - {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00}, - {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c}, - {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff}, - {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20}, - {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e}, - {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13}, - {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79}, - {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40}, - {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32}, - {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80}, -}; - -static struct i2c_reg_u8 ov7660_init[] = { - {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3}, - {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40}, - {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a}, - /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using - 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */ - {0x17, 0x10}, {0x18, 0x61}, - {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43}, - {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6}, - {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50}, -}; - -static struct i2c_reg_u8 ov7670_init[] = { - {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01}, - {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00}, - {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0}, - {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00}, - {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07}, - {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75}, - {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8}, - {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5}, - {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27}, - {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b}, - {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a}, - {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00}, - {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00}, - {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80}, - {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82}, - {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20}, - {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c}, - {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66}, - {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11}, - {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40}, - {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02}, - {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a}, - {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08}, - {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04}, - {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30}, - {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88}, - {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30}, - {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99}, - {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0}, - {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e}, - {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01}, - {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20}, - {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0}, - {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30}, - {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06}, - {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a}, - {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a}, - {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84}, - {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d}, - {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d}, - {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00}, - {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, - {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60}, - {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, - {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e}, - {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56}, - {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03}, - {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47}, - {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74}, - {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2}, - {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00}, - {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a}, - {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00}, - {0x93, 0x00}, -}; - -static struct i2c_reg_u8 ov9650_init[] = { - {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78}, - {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03}, - {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00}, - {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00}, - {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c}, - {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2}, - {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07}, - {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00}, - {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04}, - {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68}, - {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80}, - {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00}, - {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00}, - {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30}, - {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf}, - {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00}, - {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01}, - {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19}, - {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1}, - {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80}, - {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00}, - {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20}, - {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf}, - {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88}, - {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00}, - {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8}, - {0xaa, 0x92}, {0xab, 0x0a}, -}; - -static struct i2c_reg_u8 ov9655_init[] = { - {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba}, - {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08}, - {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d}, - {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57}, - {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19}, - {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80}, - {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c}, - {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc}, - {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05}, - {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e}, - {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68}, - {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92}, - {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80}, - {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00}, - {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44}, - {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01}, - {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0}, - {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00}, - {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61}, - {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a}, - {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01}, - {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a}, - {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c}, - {0x04, 0x03}, {0x00, 0x13}, -}; - -static struct i2c_reg_u16 mt9v112_init[] = { - {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020}, - {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b}, - {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001}, - {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a}, - {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58}, - {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001}, - {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020}, - {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020}, - {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020}, - {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c}, - {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2}, - {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0}, - {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020}, - {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c}, - {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae}, - {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae}, -}; - -static struct i2c_reg_u16 mt9v111_init[] = { - {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000}, - {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0}, - {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e}, - {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016}, - {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004}, - {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008}, - {0x0e, 0x0008}, {0x20, 0x0000} -}; - -static struct i2c_reg_u16 mt9v011_init[] = { - {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000}, - {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1}, - {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006}, - {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000}, - {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000}, - {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000}, - {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000}, - {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000}, - {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000}, - {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000}, - {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000}, - {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000}, - {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024}, - {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000}, - {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100}, - {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1}, - {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000}, - {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000}, - {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000}, - {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101}, - {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003}, - {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0}, - {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000}, - {0x06, 0x0029}, {0x05, 0x0009}, -}; - -static struct i2c_reg_u16 mt9m001_init[] = { - {0x0d, 0x0001}, - {0x0d, 0x0000}, - {0x04, 0x0500}, /* hres = 1280 */ - {0x03, 0x0400}, /* vres = 1024 */ - {0x20, 0x1100}, - {0x06, 0x0010}, - {0x2b, 0x0024}, - {0x2e, 0x0024}, - {0x35, 0x0024}, - {0x2d, 0x0020}, - {0x2c, 0x0020}, - {0x09, 0x0ad4}, - {0x35, 0x0057}, -}; - -static struct i2c_reg_u16 mt9m111_init[] = { - {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008}, - {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300}, - {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e}, - {0xf0, 0x0000}, -}; - -static struct i2c_reg_u16 mt9m112_init[] = { - {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008}, - {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300}, - {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e}, - {0xf0, 0x0000}, -}; - -static struct i2c_reg_u8 hv7131r_init[] = { - {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08}, - {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0}, - {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08}, - {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07}, - {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62}, - {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10}, - {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00}, - {0x23, 0x09}, {0x01, 0x08}, -}; - -static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) -{ - struct usb_device *dev = gspca_dev->dev; - int result; - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - 0x00, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - reg, - 0x00, - gspca_dev->usb_buf, - length, - 500); - if (unlikely(result < 0 || result != length)) { - err("Read register failed 0x%02X", reg); - return -EIO; - } - return 0; -} - -static int reg_w(struct gspca_dev *gspca_dev, u16 reg, - const u8 *buffer, int length) -{ - struct usb_device *dev = gspca_dev->dev; - int result; - memcpy(gspca_dev->usb_buf, buffer, length); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - reg, - 0x00, - gspca_dev->usb_buf, - length, - 500); - if (unlikely(result < 0 || result != length)) { - err("Write register failed index 0x%02X", reg); - return -EIO; - } - return 0; -} - -static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value) -{ - u8 data[1] = {value}; - return reg_w(gspca_dev, reg, data, 1); -} - -static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer) -{ - int i; - reg_w(gspca_dev, 0x10c0, buffer, 8); - for (i = 0; i < 5; i++) { - reg_r(gspca_dev, 0x10c0, 1); - if (gspca_dev->usb_buf[0] & 0x04) { - if (gspca_dev->usb_buf[0] & 0x08) - return -EIO; - return 0; - } - msleep(1); - } - return -EIO; -} - -static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - u8 row[8]; - - /* - * from the point of view of the bridge, the length - * includes the address - */ - row[0] = 0x81 | (2 << 4); - row[1] = sd->i2c_addr; - row[2] = reg; - row[3] = val; - row[4] = 0x00; - row[5] = 0x00; - row[6] = 0x00; - row[7] = 0x10; - - return i2c_w(gspca_dev, row); -} - -static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 row[8]; - - /* - * from the point of view of the bridge, the length - * includes the address - */ - row[0] = 0x81 | (3 << 4); - row[1] = sd->i2c_addr; - row[2] = reg; - row[3] = (val >> 8) & 0xff; - row[4] = val & 0xff; - row[5] = 0x00; - row[6] = 0x00; - row[7] = 0x10; - - return i2c_w(gspca_dev, row); -} - -static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 row[8]; - - row[0] = 0x81 | (1 << 4); - row[1] = sd->i2c_addr; - row[2] = reg; - row[3] = 0; - row[4] = 0; - row[5] = 0; - row[6] = 0; - row[7] = 0x10; - if (i2c_w(gspca_dev, row) < 0) - return -EIO; - row[0] = 0x81 | (1 << 4) | 0x02; - row[2] = 0; - if (i2c_w(gspca_dev, row) < 0) - return -EIO; - if (reg_r(gspca_dev, 0x10c2, 5) < 0) - return -EIO; - *val = gspca_dev->usb_buf[4]; - return 0; -} - -static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 row[8]; - - row[0] = 0x81 | (1 << 4); - row[1] = sd->i2c_addr; - row[2] = reg; - row[3] = 0; - row[4] = 0; - row[5] = 0; - row[6] = 0; - row[7] = 0x10; - if (i2c_w(gspca_dev, row) < 0) - return -EIO; - row[0] = 0x81 | (2 << 4) | 0x02; - row[2] = 0; - if (i2c_w(gspca_dev, row) < 0) - return -EIO; - if (reg_r(gspca_dev, 0x10c2, 5) < 0) - return -EIO; - *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; - return 0; -} - -static int ov9650_init_sensor(struct gspca_dev *gspca_dev) -{ - int i; - u16 id; - struct sd *sd = (struct sd *) gspca_dev; - - if (i2c_r2(gspca_dev, 0x1c, &id) < 0) - return -EINVAL; - - if (id != 0x7fa2) { - err("sensor id for ov9650 doesn't match (0x%04x)", id); - return -ENODEV; - } - - for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) { - if (i2c_w1(gspca_dev, ov9650_init[i].reg, - ov9650_init[i].val) < 0) { - err("OV9650 sensor initialization failed"); - return -ENODEV; - } - } - sd->hstart = 1; - sd->vstart = 7; - return 0; -} - -static int ov9655_init_sensor(struct gspca_dev *gspca_dev) -{ - int i; - struct sd *sd = (struct sd *) gspca_dev; - - for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) { - if (i2c_w1(gspca_dev, ov9655_init[i].reg, - ov9655_init[i].val) < 0) { - err("OV9655 sensor initialization failed"); - return -ENODEV; - } - } - /* disable hflip and vflip */ - gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); - sd->hstart = 1; - sd->vstart = 2; - return 0; -} - -static int soi968_init_sensor(struct gspca_dev *gspca_dev) -{ - int i; - struct sd *sd = (struct sd *) gspca_dev; - - for (i = 0; i < ARRAY_SIZE(soi968_init); i++) { - if (i2c_w1(gspca_dev, soi968_init[i].reg, - soi968_init[i].val) < 0) { - err("SOI968 sensor initialization failed"); - return -ENODEV; - } - } - /* disable hflip and vflip */ - gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) - | (1 << EXPOSURE_IDX); - sd->hstart = 60; - sd->vstart = 11; - return 0; -} - -static int ov7660_init_sensor(struct gspca_dev *gspca_dev) -{ - int i; - struct sd *sd = (struct sd *) gspca_dev; - - for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) { - if (i2c_w1(gspca_dev, ov7660_init[i].reg, - ov7660_init[i].val) < 0) { - err("OV7660 sensor initialization failed"); - return -ENODEV; - } - } - sd->hstart = 3; - sd->vstart = 3; - return 0; -} - -static int ov7670_init_sensor(struct gspca_dev *gspca_dev) -{ - int i; - struct sd *sd = (struct sd *) gspca_dev; - - for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) { - if (i2c_w1(gspca_dev, ov7670_init[i].reg, - ov7670_init[i].val) < 0) { - err("OV7670 sensor initialization failed"); - return -ENODEV; - } - } - /* disable hflip and vflip */ - gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); - sd->hstart = 0; - sd->vstart = 1; - return 0; -} - -static int mt9v_init_sensor(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - u16 value; - int ret; - - sd->i2c_addr = 0x5d; - ret = i2c_r2(gspca_dev, 0xff, &value); - if ((ret == 0) && (value == 0x8243)) { - for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) { - if (i2c_w2(gspca_dev, mt9v011_init[i].reg, - mt9v011_init[i].val) < 0) { - err("MT9V011 sensor initialization failed"); - return -ENODEV; - } - } - sd->hstart = 2; - sd->vstart = 2; - sd->sensor = SENSOR_MT9V011; - info("MT9V011 sensor detected"); - return 0; - } - - sd->i2c_addr = 0x5c; - i2c_w2(gspca_dev, 0x01, 0x0004); - ret = i2c_r2(gspca_dev, 0xff, &value); - if ((ret == 0) && (value == 0x823a)) { - for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) { - if (i2c_w2(gspca_dev, mt9v111_init[i].reg, - mt9v111_init[i].val) < 0) { - err("MT9V111 sensor initialization failed"); - return -ENODEV; - } - } - gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) - | (1 << GAIN_IDX); - sd->hstart = 2; - sd->vstart = 2; - sd->sensor = SENSOR_MT9V111; - info("MT9V111 sensor detected"); - return 0; - } - - sd->i2c_addr = 0x5d; - ret = i2c_w2(gspca_dev, 0xf0, 0x0000); - if (ret < 0) { - sd->i2c_addr = 0x48; - i2c_w2(gspca_dev, 0xf0, 0x0000); - } - ret = i2c_r2(gspca_dev, 0x00, &value); - if ((ret == 0) && (value == 0x1229)) { - for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) { - if (i2c_w2(gspca_dev, mt9v112_init[i].reg, - mt9v112_init[i].val) < 0) { - err("MT9V112 sensor initialization failed"); - return -ENODEV; - } - } - sd->hstart = 6; - sd->vstart = 2; - sd->sensor = SENSOR_MT9V112; - info("MT9V112 sensor detected"); - return 0; - } - - return -ENODEV; -} - -static int mt9m112_init_sensor(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) { - if (i2c_w2(gspca_dev, mt9m112_init[i].reg, - mt9m112_init[i].val) < 0) { - err("MT9M112 sensor initialization failed"); - return -ENODEV; - } - } - gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) - | (1 << GAIN_IDX); - sd->hstart = 0; - sd->vstart = 2; - return 0; -} - -static int mt9m111_init_sensor(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) { - if (i2c_w2(gspca_dev, mt9m111_init[i].reg, - mt9m111_init[i].val) < 0) { - err("MT9M111 sensor initialization failed"); - return -ENODEV; - } - } - gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) - | (1 << GAIN_IDX); - sd->hstart = 0; - sd->vstart = 2; - return 0; -} - -static int mt9m001_init_sensor(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - u16 id; - - if (i2c_r2(gspca_dev, 0x00, &id) < 0) - return -EINVAL; - - /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ - switch (id) { - case 0x8411: - case 0x8421: - info("MT9M001 color sensor detected"); - break; - case 0x8431: - info("MT9M001 mono sensor detected"); - break; - default: - err("No MT9M001 chip detected, ID = %x\n", id); - return -ENODEV; - } - - for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) { - if (i2c_w2(gspca_dev, mt9m001_init[i].reg, - mt9m001_init[i].val) < 0) { - err("MT9M001 sensor initialization failed"); - return -ENODEV; - } - } - /* disable hflip and vflip */ - gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); - sd->hstart = 1; - sd->vstart = 1; - return 0; -} - -static int hv7131r_init_sensor(struct gspca_dev *gspca_dev) -{ - int i; - struct sd *sd = (struct sd *) gspca_dev; - - for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) { - if (i2c_w1(gspca_dev, hv7131r_init[i].reg, - hv7131r_init[i].val) < 0) { - err("HV7131R Sensor initialization failed"); - return -ENODEV; - } - } - sd->hstart = 0; - sd->vstart = 1; - return 0; -} - -static int set_cmatrix(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 hue_coord, hue_index = 180 + sd->hue; - u8 cmatrix[21]; - - memset(cmatrix, 0, sizeof cmatrix); - cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26; - cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; - cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; - cmatrix[18] = sd->brightness - 0x80; - - hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8; - cmatrix[6] = hue_coord; - cmatrix[7] = (hue_coord >> 8) & 0x0f; - - hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8; - cmatrix[8] = hue_coord; - cmatrix[9] = (hue_coord >> 8) & 0x0f; - - hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8; - cmatrix[10] = hue_coord; - cmatrix[11] = (hue_coord >> 8) & 0x0f; - - hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8; - cmatrix[12] = hue_coord; - cmatrix[13] = (hue_coord >> 8) & 0x0f; - - hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8; - cmatrix[14] = hue_coord; - cmatrix[15] = (hue_coord >> 8) & 0x0f; - - hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8; - cmatrix[16] = hue_coord; - cmatrix[17] = (hue_coord >> 8) & 0x0f; - - return reg_w(gspca_dev, 0x10e1, cmatrix, 21); -} - -static int set_gamma(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 gamma[17]; - u8 gval = sd->gamma * 0xb8 / 0x100; - - - gamma[0] = 0x0a; - gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); - gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8); - gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8); - gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8); - gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8); - gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8); - gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8); - gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8); - gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8); - gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8); - gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8); - gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8); - gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8); - gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8); - gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8); - gamma[16] = 0xf5; - - return reg_w(gspca_dev, 0x1190, gamma, 17); -} - -static int set_redblue(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - reg_w1(gspca_dev, 0x118c, sd->red); - reg_w1(gspca_dev, 0x118f, sd->blue); - return 0; -} - -static int set_hvflip(struct gspca_dev *gspca_dev) -{ - u8 value, tslb, hflip, vflip; - u16 value2; - struct sd *sd = (struct sd *) gspca_dev; - - if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) { - hflip = !sd->hflip; - vflip = !sd->vflip; - } else { - hflip = sd->hflip; - vflip = sd->vflip; - } - - switch (sd->sensor) { - case SENSOR_OV7660: - value = 0x01; - if (hflip) - value |= 0x20; - if (vflip) { - value |= 0x10; - sd->vstart = 2; - } else - sd->vstart = 3; - reg_w1(gspca_dev, 0x1182, sd->vstart); - i2c_w1(gspca_dev, 0x1e, value); - break; - case SENSOR_OV9650: - i2c_r1(gspca_dev, 0x1e, &value); - value &= ~0x30; - tslb = 0x01; - if (hflip) - value |= 0x20; - if (vflip) { - value |= 0x10; - tslb = 0x49; - } - i2c_w1(gspca_dev, 0x1e, value); - i2c_w1(gspca_dev, 0x3a, tslb); - break; - case SENSOR_MT9V111: - case SENSOR_MT9V011: - i2c_r2(gspca_dev, 0x20, &value2); - value2 &= ~0xc0a0; - if (hflip) - value2 |= 0x8080; - if (vflip) - value2 |= 0x4020; - i2c_w2(gspca_dev, 0x20, value2); - break; - case SENSOR_MT9M112: - case SENSOR_MT9M111: - case SENSOR_MT9V112: - i2c_r2(gspca_dev, 0x20, &value2); - value2 &= ~0x0003; - if (hflip) - value2 |= 0x0002; - if (vflip) - value2 |= 0x0001; - i2c_w2(gspca_dev, 0x20, value2); - break; - case SENSOR_HV7131R: - i2c_r1(gspca_dev, 0x01, &value); - value &= ~0x03; - if (vflip) - value |= 0x01; - if (hflip) - value |= 0x02; - i2c_w1(gspca_dev, 0x01, value); - break; - } - return 0; -} - -static int set_exposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e}; - switch (sd->sensor) { - case SENSOR_OV7660: - case SENSOR_OV7670: - case SENSOR_OV9655: - case SENSOR_OV9650: - exp[0] |= (3 << 4); - exp[2] = 0x2d; - exp[3] = sd->exposure & 0xff; - exp[4] = sd->exposure >> 8; - break; - case SENSOR_MT9M001: - case SENSOR_MT9V112: - case SENSOR_MT9V011: - exp[0] |= (3 << 4); - exp[2] = 0x09; - exp[3] = sd->exposure >> 8; - exp[4] = sd->exposure & 0xff; - break; - case SENSOR_HV7131R: - exp[0] |= (4 << 4); - exp[2] = 0x25; - exp[3] = (sd->exposure >> 5) & 0xff; - exp[4] = (sd->exposure << 3) & 0xff; - exp[5] = 0; - break; - default: - return 0; - } - i2c_w(gspca_dev, exp); - return 0; -} - -static int set_gain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; - switch (sd->sensor) { - case SENSOR_OV7660: - case SENSOR_OV7670: - case SENSOR_SOI968: - case SENSOR_OV9655: - case SENSOR_OV9650: - gain[0] |= (2 << 4); - gain[3] = ov_gain[sd->gain]; - break; - case SENSOR_MT9V011: - gain[0] |= (3 << 4); - gain[2] = 0x35; - gain[3] = micron1_gain[sd->gain] >> 8; - gain[4] = micron1_gain[sd->gain] & 0xff; - break; - case SENSOR_MT9V112: - gain[0] |= (3 << 4); - gain[2] = 0x2f; - gain[3] = micron1_gain[sd->gain] >> 8; - gain[4] = micron1_gain[sd->gain] & 0xff; - break; - case SENSOR_MT9M001: - gain[0] |= (3 << 4); - gain[2] = 0x2f; - gain[3] = micron2_gain[sd->gain] >> 8; - gain[4] = micron2_gain[sd->gain] & 0xff; - break; - case SENSOR_HV7131R: - gain[0] |= (2 << 4); - gain[2] = 0x30; - gain[3] = hv7131r_gain[sd->gain]; - break; - default: - return 0; - } - i2c_w(gspca_dev, gain); - return 0; -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - return set_cmatrix(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->brightness; - return 0; -} - - -static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - return set_cmatrix(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->contrast; - return 0; -} - -static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->saturation = val; - if (gspca_dev->streaming) - return set_cmatrix(gspca_dev); - return 0; -} - -static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->saturation; - return 0; -} - -static int sd_sethue(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hue = val; - if (gspca_dev->streaming) - return set_cmatrix(gspca_dev); - return 0; -} - -static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->hue; - return 0; -} - -static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gamma = val; - if (gspca_dev->streaming) - return set_gamma(gspca_dev); - return 0; -} - -static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->gamma; - return 0; -} - -static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->red = val; - if (gspca_dev->streaming) - return set_redblue(gspca_dev); - return 0; -} - -static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->red; - return 0; -} - -static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->blue = val; - if (gspca_dev->streaming) - return set_redblue(gspca_dev); - return 0; -} - -static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->blue; - return 0; -} - -static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hflip = val; - if (gspca_dev->streaming) - return set_hvflip(gspca_dev); - return 0; -} - -static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->hflip; - return 0; -} - -static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vflip = val; - if (gspca_dev->streaming) - return set_hvflip(gspca_dev); - return 0; -} - -static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->vflip; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - return set_exposure(gspca_dev); - return 0; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->exposure; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - return set_gain(gspca_dev); - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->gain; - return 0; -} - -static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - sd->auto_exposure = val; - return 0; -} - -static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - *val = sd->auto_exposure; - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int sd_dbg_g_register(struct gspca_dev *gspca_dev, - struct v4l2_dbg_register *reg) -{ - struct sd *sd = (struct sd *) gspca_dev; - switch (reg->match.type) { - case V4L2_CHIP_MATCH_HOST: - if (reg->match.addr != 0) - return -EINVAL; - if (reg->reg < 0x1000 || reg->reg > 0x11ff) - return -EINVAL; - if (reg_r(gspca_dev, reg->reg, 1) < 0) - return -EINVAL; - reg->val = gspca_dev->usb_buf[0]; - return 0; - case V4L2_CHIP_MATCH_I2C_ADDR: - if (reg->match.addr != sd->i2c_addr) - return -EINVAL; - if (sd->sensor >= SENSOR_MT9V011 && - sd->sensor <= SENSOR_MT9M112) { - if (i2c_r2(gspca_dev, reg->reg, (u16 *)®->val) < 0) - return -EINVAL; - } else { - if (i2c_r1(gspca_dev, reg->reg, (u8 *)®->val) < 0) - return -EINVAL; - } - return 0; - } - return -EINVAL; -} - -static int sd_dbg_s_register(struct gspca_dev *gspca_dev, - struct v4l2_dbg_register *reg) -{ - struct sd *sd = (struct sd *) gspca_dev; - switch (reg->match.type) { - case V4L2_CHIP_MATCH_HOST: - if (reg->match.addr != 0) - return -EINVAL; - if (reg->reg < 0x1000 || reg->reg > 0x11ff) - return -EINVAL; - if (reg_w1(gspca_dev, reg->reg, reg->val) < 0) - return -EINVAL; - return 0; - case V4L2_CHIP_MATCH_I2C_ADDR: - if (reg->match.addr != sd->i2c_addr) - return -EINVAL; - if (sd->sensor >= SENSOR_MT9V011 && - sd->sensor <= SENSOR_MT9M112) { - if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0) - return -EINVAL; - } else { - if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0) - return -EINVAL; - } - return 0; - } - return -EINVAL; -} -#endif - -static int sd_chip_ident(struct gspca_dev *gspca_dev, - struct v4l2_dbg_chip_ident *chip) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (chip->match.type) { - case V4L2_CHIP_MATCH_HOST: - if (chip->match.addr != 0) - return -EINVAL; - chip->revision = 0; - chip->ident = V4L2_IDENT_SN9C20X; - return 0; - case V4L2_CHIP_MATCH_I2C_ADDR: - if (chip->match.addr != sd->i2c_addr) - return -EINVAL; - chip->revision = 0; - chip->ident = i2c_ident[sd->sensor]; - return 0; - } - return -EINVAL; -} - -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - - sd->sensor = (id->driver_info >> 8) & 0xff; - sd->i2c_addr = id->driver_info & 0xff; - sd->flags = (id->driver_info >> 16) & 0xff; - - switch (sd->sensor) { - case SENSOR_MT9M112: - case SENSOR_MT9M111: - case SENSOR_OV9650: - case SENSOR_SOI968: - cam->cam_mode = sxga_mode; - cam->nmodes = ARRAY_SIZE(sxga_mode); - break; - case SENSOR_MT9M001: - cam->cam_mode = mono_mode; - cam->nmodes = ARRAY_SIZE(mono_mode); - break; - default: - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - break; - } - - sd->old_step = 0; - sd->older_step = 0; - sd->exposure_step = 16; - - sd->brightness = BRIGHTNESS_DEFAULT; - sd->contrast = CONTRAST_DEFAULT; - sd->saturation = SATURATION_DEFAULT; - sd->hue = HUE_DEFAULT; - sd->gamma = GAMMA_DEFAULT; - sd->red = RED_DEFAULT; - sd->blue = BLUE_DEFAULT; - - sd->hflip = HFLIP_DEFAULT; - sd->vflip = VFLIP_DEFAULT; - sd->exposure = EXPOSURE_DEFAULT; - sd->gain = GAIN_DEFAULT; - sd->auto_exposure = AUTO_EXPOSURE_DEFAULT; - - sd->quality = 95; - - return 0; -} - -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - u8 value; - u8 i2c_init[9] = - {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}; - - for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { - value = bridge_init[i][1]; - if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) { - err("Device initialization failed"); - return -ENODEV; - } - } - - if (sd->flags & LED_REVERSE) - reg_w1(gspca_dev, 0x1006, 0x00); - else - reg_w1(gspca_dev, 0x1006, 0x20); - - if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) { - err("Device initialization failed"); - return -ENODEV; - } - - switch (sd->sensor) { - case SENSOR_OV9650: - if (ov9650_init_sensor(gspca_dev) < 0) - return -ENODEV; - info("OV9650 sensor detected"); - break; - case SENSOR_OV9655: - if (ov9655_init_sensor(gspca_dev) < 0) - return -ENODEV; - info("OV9655 sensor detected"); - break; - case SENSOR_SOI968: - if (soi968_init_sensor(gspca_dev) < 0) - return -ENODEV; - info("SOI968 sensor detected"); - break; - case SENSOR_OV7660: - if (ov7660_init_sensor(gspca_dev) < 0) - return -ENODEV; - info("OV7660 sensor detected"); - break; - case SENSOR_OV7670: - if (ov7670_init_sensor(gspca_dev) < 0) - return -ENODEV; - info("OV7670 sensor detected"); - break; - case SENSOR_MT9VPRB: - if (mt9v_init_sensor(gspca_dev) < 0) - return -ENODEV; - break; - case SENSOR_MT9M111: - if (mt9m111_init_sensor(gspca_dev) < 0) - return -ENODEV; - info("MT9M111 sensor detected"); - break; - case SENSOR_MT9M112: - if (mt9m112_init_sensor(gspca_dev) < 0) - return -ENODEV; - info("MT9M112 sensor detected"); - break; - case SENSOR_MT9M001: - if (mt9m001_init_sensor(gspca_dev) < 0) - return -ENODEV; - break; - case SENSOR_HV7131R: - if (hv7131r_init_sensor(gspca_dev) < 0) - return -ENODEV; - info("HV7131R sensor detected"); - break; - default: - info("Unsupported Sensor"); - return -ENODEV; - } - - return 0; -} - -static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 value; - switch (sd->sensor) { - case SENSOR_SOI968: - if (mode & MODE_SXGA) { - i2c_w1(gspca_dev, 0x17, 0x1d); - i2c_w1(gspca_dev, 0x18, 0xbd); - i2c_w1(gspca_dev, 0x19, 0x01); - i2c_w1(gspca_dev, 0x1a, 0x81); - i2c_w1(gspca_dev, 0x12, 0x00); - sd->hstart = 140; - sd->vstart = 19; - } else { - i2c_w1(gspca_dev, 0x17, 0x13); - i2c_w1(gspca_dev, 0x18, 0x63); - i2c_w1(gspca_dev, 0x19, 0x01); - i2c_w1(gspca_dev, 0x1a, 0x79); - i2c_w1(gspca_dev, 0x12, 0x40); - sd->hstart = 60; - sd->vstart = 11; - } - break; - case SENSOR_OV9650: - if (mode & MODE_SXGA) { - i2c_w1(gspca_dev, 0x17, 0x1b); - i2c_w1(gspca_dev, 0x18, 0xbc); - i2c_w1(gspca_dev, 0x19, 0x01); - i2c_w1(gspca_dev, 0x1a, 0x82); - i2c_r1(gspca_dev, 0x12, &value); - i2c_w1(gspca_dev, 0x12, value & 0x07); - } else { - i2c_w1(gspca_dev, 0x17, 0x24); - i2c_w1(gspca_dev, 0x18, 0xc5); - i2c_w1(gspca_dev, 0x19, 0x00); - i2c_w1(gspca_dev, 0x1a, 0x3c); - i2c_r1(gspca_dev, 0x12, &value); - i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40); - } - break; - case SENSOR_MT9M112: - case SENSOR_MT9M111: - if (mode & MODE_SXGA) { - i2c_w2(gspca_dev, 0xf0, 0x0002); - i2c_w2(gspca_dev, 0xc8, 0x970b); - i2c_w2(gspca_dev, 0xf0, 0x0000); - } else { - i2c_w2(gspca_dev, 0xf0, 0x0002); - i2c_w2(gspca_dev, 0xc8, 0x8000); - i2c_w2(gspca_dev, 0xf0, 0x0000); - } - break; - } -} - -#define HW_WIN(mode, hstart, vstart) \ -((const u8 []){hstart, 0, vstart, 0, \ -(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \ -(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)}) - -#define CLR_WIN(width, height) \ -((const u8 [])\ -{0, width >> 2, 0, height >> 1,\ -((width >> 10) & 0x01) | ((height >> 8) & 0x6)}) - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - int width = gspca_dev->width; - int height = gspca_dev->height; - u8 fmt, scale = 0; - - jpeg_define(sd->jpeg_hdr, height, width, - 0x21); - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - - if (mode & MODE_RAW) - fmt = 0x2d; - else if (mode & MODE_JPEG) - fmt = 0x2c; - else - fmt = 0x2f; /* YUV 420 */ - - switch (mode & SCALE_MASK) { - case SCALE_1280x1024: - scale = 0xc0; - info("Set 1280x1024"); - break; - case SCALE_640x480: - scale = 0x80; - info("Set 640x480"); - break; - case SCALE_320x240: - scale = 0x90; - info("Set 320x240"); - break; - case SCALE_160x120: - scale = 0xa0; - info("Set 160x120"); - break; - } - - configure_sensor_output(gspca_dev, mode); - reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); - reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64); - reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5); - reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6); - reg_w1(gspca_dev, 0x1189, scale); - reg_w1(gspca_dev, 0x10e0, fmt); - - set_cmatrix(gspca_dev); - set_gamma(gspca_dev); - set_redblue(gspca_dev); - set_gain(gspca_dev); - set_exposure(gspca_dev); - set_hvflip(gspca_dev); - - reg_w1(gspca_dev, 0x1007, 0x20); - - reg_r(gspca_dev, 0x1061, 1); - reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02); - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - reg_w1(gspca_dev, 0x1007, 0x00); - - reg_r(gspca_dev, 0x1061, 1); - reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02); -} - -static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) -{ - struct sd *sd = (struct sd *) gspca_dev; - s16 new_exp; - - /* - * some hardcoded values are present - * like those for maximal/minimal exposure - * and exposure steps - */ - if (avg_lum < MIN_AVG_LUM) { - if (sd->exposure > 0x1770) - return; - - new_exp = sd->exposure + sd->exposure_step; - if (new_exp > 0x1770) - new_exp = 0x1770; - if (new_exp < 0x10) - new_exp = 0x10; - sd->exposure = new_exp; - set_exposure(gspca_dev); - - sd->older_step = sd->old_step; - sd->old_step = 1; - - if (sd->old_step ^ sd->older_step) - sd->exposure_step /= 2; - else - sd->exposure_step += 2; - } - if (avg_lum > MAX_AVG_LUM) { - if (sd->exposure < 0x10) - return; - new_exp = sd->exposure - sd->exposure_step; - if (new_exp > 0x1700) - new_exp = 0x1770; - if (new_exp < 0x10) - new_exp = 0x10; - sd->exposure = new_exp; - set_exposure(gspca_dev); - sd->older_step = sd->old_step; - sd->old_step = 0; - - if (sd->old_step ^ sd->older_step) - sd->exposure_step /= 2; - else - sd->exposure_step += 2; - } -} - -static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (avg_lum < MIN_AVG_LUM) { - if (sd->gain + 1 <= 28) { - sd->gain++; - set_gain(gspca_dev); - } - } - if (avg_lum > MAX_AVG_LUM) { - if (sd->gain > 0) { - sd->gain--; - set_gain(gspca_dev); - } - } -} - -static void sd_dqcallback(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int avg_lum; - - if (!sd->auto_exposure) - return; - - avg_lum = atomic_read(&sd->avg_lum); - if (sd->sensor == SENSOR_SOI968) - do_autogain(gspca_dev, avg_lum); - else - do_autoexposure(gspca_dev, avg_lum); -} - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* interrupt packet */ - int len) /* interrupt packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret = -EINVAL; - if (!(sd->flags & HAS_NO_BUTTON) && len == 1) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); - input_sync(gspca_dev->input_dev); - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - ret = 0; - } - return ret; -} -#endif - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - int avg_lum; - static u8 frame_header[] = - {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; - if (len == 64 && memcmp(data, frame_header, 6) == 0) { - avg_lum = ((data[35] >> 2) & 3) | - (data[20] << 2) | - (data[19] << 10); - avg_lum += ((data[35] >> 4) & 3) | - (data[22] << 2) | - (data[21] << 10); - avg_lum += ((data[35] >> 6) & 3) | - (data[24] << 2) | - (data[23] << 10); - avg_lum += (data[36] & 3) | - (data[26] << 2) | - (data[25] << 10); - avg_lum += ((data[36] >> 2) & 3) | - (data[28] << 2) | - (data[27] << 10); - avg_lum += ((data[36] >> 4) & 3) | - (data[30] << 2) | - (data[29] << 10); - avg_lum += ((data[36] >> 6) & 3) | - (data[32] << 2) | - (data[31] << 10); - avg_lum += ((data[44] >> 4) & 3) | - (data[34] << 2) | - (data[33] << 10); - avg_lum >>= 9; - atomic_set(&sd->avg_lum, avg_lum); - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - return; - } - if (gspca_dev->last_packet_type == LAST_PACKET) { - if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv - & MODE_JPEG) { - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - gspca_frame_add(gspca_dev, INTER_PACKET, - data, len); - } else { - gspca_frame_add(gspca_dev, FIRST_PACKET, - data, len); - } - } else { - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - } -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -#endif - .dq_callback = sd_dqcallback, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .set_register = sd_dbg_s_register, - .get_register = sd_dbg_g_register, -#endif - .get_chip_ident = sd_chip_ident, -}; - -#define SN9C20X(sensor, i2c_addr, flags) \ - .driver_info = ((flags & 0xff) << 16) \ - | (SENSOR_ ## sensor << 8) \ - | (i2c_addr) - -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)}, - {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)}, - {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)}, - {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)}, - {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)}, - {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30, - (FLIP_DETECT | HAS_NO_BUTTON))}, - {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)}, - {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)}, - {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)}, - {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)}, - {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, FLIP_DETECT)}, - {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)}, - {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)}, - {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)}, - {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)}, - {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)}, - {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)}, - {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)}, - {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)}, - {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)}, - {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)}, - {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)}, - {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)}, - {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)}, - {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)}, - {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)}, - {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)}, - {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)}, - {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)}, - {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)}, - {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)}, - {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)}, - {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)}, - {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)}, - {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)}, - {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, - .reset_resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sonixb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sonixb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sonixb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sonixb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1541 +0,0 @@ -/* - * sonix sn9c102 (bayer) library - * - * Copyright (C) 2009-2011 Jean-François Moine - * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr - * Add Pas106 Stefano Mozzi (C) 2004 - * - * 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, or - * any later version. - * - * 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 - */ - -/* Some documentation on known sonixb registers: - -Reg Use -sn9c101 / sn9c102: -0x10 high nibble red gain low nibble blue gain -0x11 low nibble green gain -sn9c103: -0x05 red gain 0-127 -0x06 blue gain 0-127 -0x07 green gain 0-127 -all: -0x08-0x0f i2c / 3wire registers -0x12 hstart -0x13 vstart -0x15 hsize (hsize = register-value * 16) -0x16 vsize (vsize = register-value * 16) -0x17 bit 0 toggle compression quality (according to sn9c102 driver) -0x18 bit 7 enables compression, bit 4-5 set image down scaling: - 00 scale 1, 01 scale 1/2, 10, scale 1/4 -0x19 high-nibble is sensor clock divider, changes exposure on sensors which - use a clock generated by the bridge. Some sensors have their own clock. -0x1c auto_exposure area (for avg_lum) startx (startx = register-value * 32) -0x1d auto_exposure area (for avg_lum) starty (starty = register-value * 32) -0x1e auto_exposure area (for avg_lum) stopx (hsize = (0x1e - 0x1c) * 32) -0x1f auto_exposure area (for avg_lum) stopy (vsize = (0x1f - 0x1d) * 32) -*/ - -#define MODULE_NAME "sonixb" - -#include -#include "gspca.h" - -MODULE_AUTHOR("Jean-François Moine "); -MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* controls */ -enum e_ctrl { - BRIGHTNESS, - GAIN, - EXPOSURE, - AUTOGAIN, - FREQ, - NCTRLS /* number of controls */ -}; - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRLS]; - - atomic_t avg_lum; - int prev_avg_lum; - int exp_too_low_cnt; - int exp_too_high_cnt; - int header_read; - u8 header[12]; /* Header without sof marker */ - - unsigned char autogain_ignore_frames; - unsigned char frames_to_drop; - - __u8 bridge; /* Type of bridge */ -#define BRIDGE_101 0 -#define BRIDGE_102 0 /* We make no difference between 101 and 102 */ -#define BRIDGE_103 1 - - __u8 sensor; /* Type of image sensor chip */ -#define SENSOR_HV7131D 0 -#define SENSOR_HV7131R 1 -#define SENSOR_OV6650 2 -#define SENSOR_OV7630 3 -#define SENSOR_PAS106 4 -#define SENSOR_PAS202 5 -#define SENSOR_TAS5110C 6 -#define SENSOR_TAS5110D 7 -#define SENSOR_TAS5130CXX 8 - __u8 reg11; -}; - -typedef const __u8 sensor_init_t[8]; - -struct sensor_data { - const __u8 *bridge_init; - sensor_init_t *sensor_init; - int sensor_init_size; - int flags; - unsigned ctrl_dis; - __u8 sensor_addr; -}; - -/* sensor_data flags */ -#define F_GAIN 0x01 /* has gain */ -#define F_SIF 0x02 /* sif or vga */ -#define F_COARSE_EXPO 0x04 /* exposure control is coarse */ - -/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */ -#define MODE_RAW 0x10 /* raw bayer mode */ -#define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */ - -/* ctrl_dis helper macros */ -#define NO_EXPO ((1 << EXPOSURE) | (1 << AUTOGAIN)) -#define NO_FREQ (1 << FREQ) -#define NO_BRIGHTNESS (1 << BRIGHTNESS) - -#define COMP 0xc7 /* 0x87 //0x07 */ -#define COMP1 0xc9 /* 0x89 //0x09 */ - -#define MCK_INIT 0x63 -#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/ - -#define SYS_CLK 0x04 - -#define SENS(bridge, sensor, _flags, _ctrl_dis, _sensor_addr) \ -{ \ - .bridge_init = bridge, \ - .sensor_init = sensor, \ - .sensor_init_size = sizeof(sensor), \ - .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \ -} - -/* We calculate the autogain at the end of the transfer of a frame, at this - moment a frame with the old settings is being captured and transmitted. So - if we adjust the gain or exposure we must ignore atleast the next frame for - the new settings to come into effect before doing any other adjustments. */ -#define AUTOGAIN_IGNORE_FRAMES 1 - -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setgain(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static void setfreq(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setbrightness - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 255, - .step = 1, -#define GAIN_KNEE 230 - .default_value = 127, - }, - .set_control = setgain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 1023, - .step = 1, - .default_value = 66, - /* 33 ms / 30 fps (except on PASXXX) */ -#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PASXXX) */ - .flags = 0, - }, - .set_control = setexposure - }, -/* for coarse exposure */ -#define COARSE_EXPOSURE_MIN 2 -#define COARSE_EXPOSURE_MAX 15 -#define COARSE_EXPOSURE_DEF 2 /* 30 fps */ -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain (and Exposure)", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - .flags = V4L2_CTRL_FLAG_UPDATE - }, - .set = sd_setautogain, - }, -[FREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, -#define FREQ_DEF 0 - .default_value = FREQ_DEF, - }, - .set_control = setfreq - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2 | MODE_RAW}, - {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 5 / 4, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 5 / 4, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 5 / 4, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; -static const struct v4l2_pix_format sif_mode[] = { - {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 | MODE_RAW | MODE_REDUCED_SIF}, - {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 5 / 4, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 | MODE_REDUCED_SIF}, - {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 | MODE_RAW}, - {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 5 / 4, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 5 / 4, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 | MODE_REDUCED_SIF}, - {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 5 / 4, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -static const __u8 initHv7131d[] = { - 0x04, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, - 0x28, 0x1e, 0x60, 0x8e, 0x42, -}; -static const __u8 hv7131d_sensor_init[][8] = { - {0xa0, 0x11, 0x01, 0x04, 0x00, 0x00, 0x00, 0x17}, - {0xa0, 0x11, 0x02, 0x00, 0x00, 0x00, 0x00, 0x17}, - {0xa0, 0x11, 0x28, 0x00, 0x00, 0x00, 0x00, 0x17}, - {0xa0, 0x11, 0x30, 0x30, 0x00, 0x00, 0x00, 0x17}, /* reset level */ - {0xa0, 0x11, 0x34, 0x02, 0x00, 0x00, 0x00, 0x17}, /* pixel bias volt */ -}; - -static const __u8 initHv7131r[] = { - 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, - 0x28, 0x1e, 0x60, 0x8a, 0x20, -}; -static const __u8 hv7131r_sensor_init[][8] = { - {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10}, - {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10}, - {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10}, - {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16}, - {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15}, -}; -static const __u8 initOv6650[] = { - 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b, - 0x10, -}; -static const __u8 ov6650_sensor_init[][8] = { - /* Bright, contrast, etc are set through SCBB interface. - * AVCAP on win2 do not send any data on this controls. */ - /* Anyway, some registers appears to alter bright and constrat */ - - /* Reset sensor */ - {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, - /* Set clock register 0x11 low nibble is clock divider */ - {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10}, - /* Next some unknown stuff */ - {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10}, -/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10}, - * THIS SET GREEN SCREEN - * (pixels could be innverted in decode kind of "brg", - * but blue wont be there. Avoid this data ... */ - {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */ - {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, - {0xa0, 0x60, 0x30, 0x3d, 0x0a, 0xd8, 0xa4, 0x10}, - /* Enable rgb brightness control */ - {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10}, - /* HDG: Note windows uses the line below, which sets both register 0x60 - and 0x61 I believe these registers of the ov6650 are identical as - those of the ov7630, because if this is true the windows settings - add a bit additional red gain and a lot additional blue gain, which - matches my findings that the windows settings make blue much too - blue and red a little too red. - {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */ - /* Some more unknown stuff */ - {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10}, - {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */ -}; - -static const __u8 initOv7630[] = { - 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */ - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */ - 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */ - 0x28, 0x1e, /* H & V sizes r15 .. r16 */ - 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */ -}; -static const __u8 ov7630_sensor_init[][8] = { - {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10}, -/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */ - {0xd0, 0x21, 0x12, 0x5c, 0x00, 0x80, 0x34, 0x10}, /* jfm */ - {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10}, - {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10}, - {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10}, - {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10}, - {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10}, - {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10}, - {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10}, - {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10}, -/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */ - {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10}, - {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10}, - {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10}, - {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10}, - {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10}, - {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10}, -}; - -static const __u8 initPas106[] = { - 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, - 0x16, 0x12, 0x24, COMP1, MCK_INIT1, -}; -/* compression 0x86 mckinit1 0x2b */ - -/* "Known" PAS106B registers: - 0x02 clock divider - 0x03 Variable framerate bits 4-11 - 0x04 Var framerate bits 0-3, one must leave the 4 msb's at 0 !! - The variable framerate control must never be set lower then 300, - which sets the framerate at 90 / reg02, otherwise vsync is lost. - 0x05 Shutter Time Line Offset, this can be used as an exposure control: - 0 = use full frame time, 255 = no exposure at all - Note this may never be larger then "var-framerate control" / 2 - 2. - When var-framerate control is < 514, no exposure is reached at the max - allowed value for the framerate control value, rather then at 255. - 0x06 Shutter Time Pixel Offset, like reg05 this influences exposure, but - only a very little bit, leave at 0xcd - 0x07 offset sign bit (bit0 1 > negative offset) - 0x08 offset - 0x09 Blue Gain - 0x0a Green1 Gain - 0x0b Green2 Gain - 0x0c Red Gain - 0x0e Global gain - 0x13 Write 1 to commit settings to sensor -*/ - -static const __u8 pas106_sensor_init[][8] = { - /* Pixel Clock Divider 6 */ - { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 }, - /* Frame Time MSB (also seen as 0x12) */ - { 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 }, - /* Frame Time LSB (also seen as 0x05) */ - { 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 }, - /* Shutter Time Line Offset (also seen as 0x6d) */ - { 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 }, - /* Shutter Time Pixel Offset (also seen as 0xb1) */ - { 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 }, - /* Black Level Subtract Sign (also seen 0x00) */ - { 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 }, - /* Black Level Subtract Level (also seen 0x01) */ - { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 }, - { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 }, - /* Color Gain B Pixel 5 a */ - { 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 }, - /* Color Gain G1 Pixel 1 5 */ - { 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 }, - /* Color Gain G2 Pixel 1 0 5 */ - { 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 }, - /* Color Gain R Pixel 3 1 */ - { 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 }, - /* Color GainH Pixel */ - { 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 }, - /* Global Gain */ - { 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 }, - /* Contrast */ - { 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 }, - /* H&V synchro polarity */ - { 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 }, - /* ?default */ - { 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 }, - /* DAC scale */ - { 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 }, - /* ?default */ - { 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 }, - /* Validate Settings */ - { 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 }, -}; - -static const __u8 initPas202[] = { - 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a, - 0x28, 0x1e, 0x20, 0x89, 0x20, -}; - -/* "Known" PAS202BCB registers: - 0x02 clock divider - 0x04 Variable framerate bits 6-11 (*) - 0x05 Var framerate bits 0-5, one must leave the 2 msb's at 0 !! - 0x07 Blue Gain - 0x08 Green Gain - 0x09 Red Gain - 0x0b offset sign bit (bit0 1 > negative offset) - 0x0c offset - 0x0e Unknown image is slightly brighter when bit 0 is 0, if reg0f is 0 too, - leave at 1 otherwise we get a jump in our exposure control - 0x0f Exposure 0-255, 0 = use full frame time, 255 = no exposure at all - 0x10 Master gain 0 - 31 - 0x11 write 1 to apply changes - (*) The variable framerate control must never be set lower then 500 - which sets the framerate at 30 / reg02, otherwise vsync is lost. -*/ -static const __u8 pas202_sensor_init[][8] = { - /* Set the clock divider to 4 -> 30 / 4 = 7.5 fps, we would like - to set it lower, but for some reason the bridge starts missing - vsync's then */ - {0xa0, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10}, - {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10}, - {0xd0, 0x40, 0x0c, 0x00, 0x0c, 0x01, 0x32, 0x10}, - {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10}, - {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10}, - {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10}, - {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10}, - {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10}, - {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10}, -}; - -static const __u8 initTas5110c[] = { - 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, 0x00, 0x45, 0x09, 0x0a, - 0x16, 0x12, 0x60, 0x86, 0x2b, -}; -/* Same as above, except a different hstart */ -static const __u8 initTas5110d[] = { - 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, 0x00, 0x41, 0x09, 0x0a, - 0x16, 0x12, 0x60, 0x86, 0x2b, -}; -/* tas5110c is 3 wire, tas5110d is 2 wire (regular i2c) */ -static const __u8 tas5110c_sensor_init[][8] = { - {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10}, - {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10}, -}; -/* Known TAS5110D registers - * reg02: gain, bit order reversed!! 0 == max gain, 255 == min gain - * reg03: bit3: vflip, bit4: ~hflip, bit7: ~gainboost (~ == inverted) - * Note: writing reg03 seems to only work when written together with 02 - */ -static const __u8 tas5110d_sensor_init[][8] = { - {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17}, /* reset */ -}; - -static const __u8 initTas5130[] = { - 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, 0x00, 0x68, 0x0c, 0x0a, - 0x28, 0x1e, 0x60, COMP, MCK_INIT, -}; -static const __u8 tas5130_sensor_init[][8] = { -/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10}, - * shutter 0x47 short exposure? */ - {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10}, - /* shutter 0x01 long exposure */ - {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}, -}; - -static const struct sensor_data sensor_data[] = { -SENS(initHv7131d, hv7131d_sensor_init, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initHv7131r, hv7131r_sensor_init, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), -SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60), -SENS(initOv7630, ov7630_sensor_init, F_GAIN, 0, 0x21), -SENS(initPas106, pas106_sensor_init, F_GAIN|F_SIF, NO_FREQ, 0), -SENS(initPas202, pas202_sensor_init, F_GAIN, NO_FREQ, 0), -SENS(initTas5110c, tas5110c_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, - NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initTas5110d, tas5110d_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, - NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initTas5130, tas5130_sensor_init, F_GAIN, - NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), -}; - -/* get one byte in gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - __u16 value) -{ - usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, - 0, /* index */ - gspca_dev->usb_buf, 1, - 500); -} - -static void reg_w(struct gspca_dev *gspca_dev, - __u16 value, - const __u8 *buffer, - int len) -{ -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow"); - return; - } -#endif - memcpy(gspca_dev->usb_buf, buffer, len); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, - 0, /* index */ - gspca_dev->usb_buf, len, - 500); -} - -static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer) -{ - int retry = 60; - - /* is i2c ready */ - reg_w(gspca_dev, 0x08, buffer, 8); - while (retry--) { - msleep(10); - reg_r(gspca_dev, 0x08); - if (gspca_dev->usb_buf[0] & 0x04) { - if (gspca_dev->usb_buf[0] & 0x08) - return -1; - return 0; - } - } - return -1; -} - -static void i2c_w_vector(struct gspca_dev *gspca_dev, - const __u8 buffer[][8], int len) -{ - for (;;) { - reg_w(gspca_dev, 0x08, *buffer, 8); - len -= 8; - if (len <= 0) - break; - buffer++; - } -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { - case SENSOR_OV6650: - case SENSOR_OV7630: { - __u8 i2cOV[] = - {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}; - - /* change reg 0x06 */ - i2cOV[1] = sensor_data[sd->sensor].sensor_addr; - i2cOV[3] = sd->ctrls[BRIGHTNESS].val; - if (i2c_w(gspca_dev, i2cOV) < 0) - goto err; - break; - } - case SENSOR_PAS106: - case SENSOR_PAS202: { - __u8 i2cpbright[] = - {0xb0, 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x16}; - __u8 i2cpdoit[] = - {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16}; - - /* PAS106 uses reg 7 and 8 instead of b and c */ - if (sd->sensor == SENSOR_PAS106) { - i2cpbright[2] = 7; - i2cpdoit[2] = 0x13; - } - - if (sd->ctrls[BRIGHTNESS].val < 127) { - /* change reg 0x0b, signreg */ - i2cpbright[3] = 0x01; - /* set reg 0x0c, offset */ - i2cpbright[4] = 127 - sd->ctrls[BRIGHTNESS].val; - } else - i2cpbright[4] = sd->ctrls[BRIGHTNESS].val - 127; - - if (i2c_w(gspca_dev, i2cpbright) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpdoit) < 0) - goto err; - break; - } - } - return; -err: - PDEBUG(D_ERR, "i2c error brightness"); -} - -static void setsensorgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 gain = sd->ctrls[GAIN].val; - - switch (sd->sensor) { - case SENSOR_HV7131D: { - __u8 i2c[] = - {0xc0, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x17}; - - i2c[3] = 0x3f - (gain / 4); - i2c[4] = 0x3f - (gain / 4); - i2c[5] = 0x3f - (gain / 4); - - if (i2c_w(gspca_dev, i2c) < 0) - goto err; - break; - } - case SENSOR_TAS5110C: - case SENSOR_TAS5130CXX: { - __u8 i2c[] = - {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}; - - i2c[4] = 255 - gain; - if (i2c_w(gspca_dev, i2c) < 0) - goto err; - break; - } - case SENSOR_TAS5110D: { - __u8 i2c[] = { - 0xb0, 0x61, 0x02, 0x00, 0x10, 0x00, 0x00, 0x17 }; - gain = 255 - gain; - /* The bits in the register are the wrong way around!! */ - i2c[3] |= (gain & 0x80) >> 7; - i2c[3] |= (gain & 0x40) >> 5; - i2c[3] |= (gain & 0x20) >> 3; - i2c[3] |= (gain & 0x10) >> 1; - i2c[3] |= (gain & 0x08) << 1; - i2c[3] |= (gain & 0x04) << 3; - i2c[3] |= (gain & 0x02) << 5; - i2c[3] |= (gain & 0x01) << 7; - if (i2c_w(gspca_dev, i2c) < 0) - goto err; - break; - } - - case SENSOR_OV6650: - gain >>= 1; - /* fall thru */ - case SENSOR_OV7630: { - __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; - - i2c[1] = sensor_data[sd->sensor].sensor_addr; - i2c[3] = gain >> 2; - if (i2c_w(gspca_dev, i2c) < 0) - goto err; - break; - } - case SENSOR_PAS106: - case SENSOR_PAS202: { - __u8 i2cpgain[] = - {0xa0, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15}; - __u8 i2cpcolorgain[] = - {0xc0, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x15}; - __u8 i2cpdoit[] = - {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16}; - - /* PAS106 uses different regs (and has split green gains) */ - if (sd->sensor == SENSOR_PAS106) { - i2cpgain[2] = 0x0e; - i2cpcolorgain[0] = 0xd0; - i2cpcolorgain[2] = 0x09; - i2cpdoit[2] = 0x13; - } - - i2cpgain[3] = gain >> 3; - i2cpcolorgain[3] = gain >> 4; - i2cpcolorgain[4] = gain >> 4; - i2cpcolorgain[5] = gain >> 4; - i2cpcolorgain[6] = gain >> 4; - - if (i2c_w(gspca_dev, i2cpgain) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpcolorgain) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpdoit) < 0) - goto err; - break; - } - } - return; -err: - PDEBUG(D_ERR, "i2c error gain"); -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 gain; - __u8 buf[3] = { 0, 0, 0 }; - - if (sensor_data[sd->sensor].flags & F_GAIN) { - /* Use the sensor gain to do the actual gain */ - setsensorgain(gspca_dev); - return; - } - - if (sd->bridge == BRIDGE_103) { - gain = sd->ctrls[GAIN].val >> 1; - buf[0] = gain; /* Red */ - buf[1] = gain; /* Green */ - buf[2] = gain; /* Blue */ - reg_w(gspca_dev, 0x05, buf, 3); - } else { - gain = sd->ctrls[GAIN].val >> 4; - buf[0] = gain << 4 | gain; /* Red and blue */ - buf[1] = gain; /* Green */ - reg_w(gspca_dev, 0x10, buf, 2); - } -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { - case SENSOR_HV7131D: { - /* Note the datasheet wrongly says line mode exposure uses reg - 0x26 and 0x27, testing has shown 0x25 + 0x26 */ - __u8 i2c[] = {0xc0, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x17}; - /* The HV7131D's exposure goes from 0 - 65535, we scale our - exposure of 0-1023 to 0-6138. There are 2 reasons for this: - 1) This puts our exposure knee of 200 at approx the point - where the framerate starts dropping - 2) At 6138 the framerate has already dropped to 2 fps, - going any lower makes little sense */ - u16 reg = sd->ctrls[EXPOSURE].val * 6; - - i2c[3] = reg >> 8; - i2c[4] = reg & 0xff; - if (i2c_w(gspca_dev, i2c) != 0) - goto err; - break; - } - case SENSOR_TAS5110C: - case SENSOR_TAS5110D: { - /* register 19's high nibble contains the sn9c10x clock divider - The high nibble configures the no fps according to the - formula: 60 / high_nibble. With a maximum of 30 fps */ - u8 reg = sd->ctrls[EXPOSURE].val; - - reg = (reg << 4) | 0x0b; - reg_w(gspca_dev, 0x19, ®, 1); - break; - } - case SENSOR_OV6650: - case SENSOR_OV7630: { - /* The ov6650 / ov7630 have 2 registers which both influence - exposure, register 11, whose low nibble sets the nr off fps - according to: fps = 30 / (low_nibble + 1) - - The fps configures the maximum exposure setting, but it is - possible to use less exposure then what the fps maximum - allows by setting register 10. register 10 configures the - actual exposure as quotient of the full exposure, with 0 - being no exposure at all (not very usefull) and reg10_max - being max exposure possible at that framerate. - - The code maps our 0 - 510 ms exposure ctrl to these 2 - registers, trying to keep fps as high as possible. - */ - __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}; - int reg10, reg11, reg10_max; - - /* ov6645 datasheet says reg10_max is 9a, but that uses - tline * 2 * reg10 as formula for calculating texpo, the - ov6650 probably uses the same formula as the 7730 which uses - tline * 4 * reg10, which explains why the reg10max we've - found experimentally for the ov6650 is exactly half that of - the ov6645. The ov7630 datasheet says the max is 0x41. */ - if (sd->sensor == SENSOR_OV6650) { - reg10_max = 0x4d; - i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */ - } else - reg10_max = 0x41; - - reg11 = (15 * sd->ctrls[EXPOSURE].val + 999) / 1000; - if (reg11 < 1) - reg11 = 1; - else if (reg11 > 16) - reg11 = 16; - - /* In 640x480, if the reg11 has less than 4, the image is - unstable (the bridge goes into a higher compression mode - which we have not reverse engineered yet). */ - if (gspca_dev->width == 640 && reg11 < 4) - reg11 = 4; - - /* frame exposure time in ms = 1000 * reg11 / 30 -> - reg10 = (sd->ctrls[EXPOSURE].val / 2) * reg10_max - / (1000 * reg11 / 30) */ - reg10 = (sd->ctrls[EXPOSURE].val * 15 * reg10_max) - / (1000 * reg11); - - /* Don't allow this to get below 10 when using autogain, the - steps become very large (relatively) when below 10 causing - the image to oscilate from much too dark, to much too bright - and back again. */ - if (sd->ctrls[AUTOGAIN].val && reg10 < 10) - reg10 = 10; - else if (reg10 > reg10_max) - reg10 = reg10_max; - - /* Write reg 10 and reg11 low nibble */ - i2c[1] = sensor_data[sd->sensor].sensor_addr; - i2c[3] = reg10; - i2c[4] |= reg11 - 1; - - /* If register 11 didn't change, don't change it */ - if (sd->reg11 == reg11) - i2c[0] = 0xa0; - - if (i2c_w(gspca_dev, i2c) == 0) - sd->reg11 = reg11; - else - goto err; - break; - } - case SENSOR_PAS202: { - __u8 i2cpframerate[] = - {0xb0, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x16}; - __u8 i2cpexpo[] = - {0xa0, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x16}; - const __u8 i2cpdoit[] = - {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16}; - int framerate_ctrl; - - /* The exposure knee for the autogain algorithm is 200 - (100 ms / 10 fps on other sensors), for values below this - use the control for setting the partial frame expose time, - above that use variable framerate. This way we run at max - framerate (640x480@7.5 fps, 320x240@10fps) until the knee - is reached. Using the variable framerate control above 200 - is better then playing around with both clockdiv + partial - frame exposure times (like we are doing with the ov chips), - as that sometimes leads to jumps in the exposure control, - which are bad for auto exposure. */ - if (sd->ctrls[EXPOSURE].val < 200) { - i2cpexpo[3] = 255 - (sd->ctrls[EXPOSURE].val * 255) - / 200; - framerate_ctrl = 500; - } else { - /* The PAS202's exposure control goes from 0 - 4095, - but anything below 500 causes vsync issues, so scale - our 200-1023 to 500-4095 */ - framerate_ctrl = (sd->ctrls[EXPOSURE].val - 200) - * 1000 / 229 + 500; - } - - i2cpframerate[3] = framerate_ctrl >> 6; - i2cpframerate[4] = framerate_ctrl & 0x3f; - if (i2c_w(gspca_dev, i2cpframerate) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpexpo) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpdoit) < 0) - goto err; - break; - } - case SENSOR_PAS106: { - __u8 i2cpframerate[] = - {0xb1, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x14}; - __u8 i2cpexpo[] = - {0xa1, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x14}; - const __u8 i2cpdoit[] = - {0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14}; - int framerate_ctrl; - - /* For values below 150 use partial frame exposure, above - that use framerate ctrl */ - if (sd->ctrls[EXPOSURE].val < 150) { - i2cpexpo[3] = 150 - sd->ctrls[EXPOSURE].val; - framerate_ctrl = 300; - } else { - /* The PAS106's exposure control goes from 0 - 4095, - but anything below 300 causes vsync issues, so scale - our 150-1023 to 300-4095 */ - framerate_ctrl = (sd->ctrls[EXPOSURE].val - 150) - * 1000 / 230 + 300; - } - - i2cpframerate[3] = framerate_ctrl >> 4; - i2cpframerate[4] = framerate_ctrl & 0x0f; - if (i2c_w(gspca_dev, i2cpframerate) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpexpo) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpdoit) < 0) - goto err; - break; - } - } - return; -err: - PDEBUG(D_ERR, "i2c error exposure"); -} - -static void setfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { - case SENSOR_OV6650: - case SENSOR_OV7630: { - /* Framerate adjust register for artificial light 50 hz flicker - compensation, for the ov6650 this is identical to ov6630 - 0x2b register, see ov6630 datasheet. - 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */ - __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}; - switch (sd->ctrls[FREQ].val) { - default: -/* case 0: * no filter*/ -/* case 2: * 60 hz */ - i2c[3] = 0; - break; - case 1: /* 50 hz */ - i2c[3] = (sd->sensor == SENSOR_OV6650) - ? 0x4f : 0x8a; - break; - } - i2c[1] = sensor_data[sd->sensor].sensor_addr; - if (i2c_w(gspca_dev, i2c) < 0) - PDEBUG(D_ERR, "i2c error setfreq"); - break; - } - } -} - -#include "autogain_functions.h" - -static void do_autogain(struct gspca_dev *gspca_dev) -{ - int deadzone, desired_avg_lum, result; - struct sd *sd = (struct sd *) gspca_dev; - int avg_lum = atomic_read(&sd->avg_lum); - - if ((gspca_dev->ctrl_dis & (1 << AUTOGAIN)) || - avg_lum == -1 || !sd->ctrls[AUTOGAIN].val) - return; - - if (sd->autogain_ignore_frames > 0) { - sd->autogain_ignore_frames--; - return; - } - - /* SIF / VGA sensors have a different autoexposure area and thus - different avg_lum values for the same picture brightness */ - if (sensor_data[sd->sensor].flags & F_SIF) { - deadzone = 500; - /* SIF sensors tend to overexpose, so keep this small */ - desired_avg_lum = 5000; - } else { - deadzone = 1500; - desired_avg_lum = 13000; - } - - if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) - result = coarse_grained_expo_autogain(gspca_dev, avg_lum, - sd->ctrls[BRIGHTNESS].val - * desired_avg_lum / 127, - deadzone); - else - result = auto_gain_n_exposure(gspca_dev, avg_lum, - sd->ctrls[BRIGHTNESS].val - * desired_avg_lum / 127, - deadzone, GAIN_KNEE, EXPOSURE_KNEE); - - if (result) { - PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d", - (int) sd->ctrls[GAIN].val, - (int) sd->ctrls[EXPOSURE].val); - sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; - } -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - reg_r(gspca_dev, 0x00); - if (gspca_dev->usb_buf[0] != 0x10) - return -ENODEV; - - /* copy the webcam info from the device id */ - sd->sensor = id->driver_info >> 8; - sd->bridge = id->driver_info & 0xff; - - gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis; -#if AUTOGAIN_DEF - if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN))) - gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); -#endif - - cam = &gspca_dev->cam; - cam->ctrls = sd->ctrls; - if (!(sensor_data[sd->sensor].flags & F_SIF)) { - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - } else { - cam->cam_mode = sif_mode; - cam->nmodes = ARRAY_SIZE(sif_mode); - } - cam->npkt = 36; /* 36 packets per ISOC message */ - - if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) { - sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN; - sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX; - sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF; - } - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - const __u8 stop = 0x09; /* Disable stream turn of LED */ - - reg_w(gspca_dev, 0x01, &stop, 1); - - return 0; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam = &gspca_dev->cam; - int i, mode; - __u8 regs[0x31]; - - mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07; - /* Copy registers 0x01 - 0x19 from the template */ - memcpy(®s[0x01], sensor_data[sd->sensor].bridge_init, 0x19); - /* Set the mode */ - regs[0x18] |= mode << 4; - - /* Set bridge gain to 1.0 */ - if (sd->bridge == BRIDGE_103) { - regs[0x05] = 0x20; /* Red */ - regs[0x06] = 0x20; /* Green */ - regs[0x07] = 0x20; /* Blue */ - } else { - regs[0x10] = 0x00; /* Red and blue */ - regs[0x11] = 0x00; /* Green */ - } - - /* Setup pixel numbers and auto exposure window */ - if (sensor_data[sd->sensor].flags & F_SIF) { - regs[0x1a] = 0x14; /* HO_SIZE 640, makes no sense */ - regs[0x1b] = 0x0a; /* VO_SIZE 320, makes no sense */ - regs[0x1c] = 0x02; /* AE H-start 64 */ - regs[0x1d] = 0x02; /* AE V-start 64 */ - regs[0x1e] = 0x09; /* AE H-end 288 */ - regs[0x1f] = 0x07; /* AE V-end 224 */ - } else { - regs[0x1a] = 0x1d; /* HO_SIZE 960, makes no sense */ - regs[0x1b] = 0x10; /* VO_SIZE 512, makes no sense */ - regs[0x1c] = 0x05; /* AE H-start 160 */ - regs[0x1d] = 0x03; /* AE V-start 96 */ - regs[0x1e] = 0x0f; /* AE H-end 480 */ - regs[0x1f] = 0x0c; /* AE V-end 384 */ - } - - /* Setup the gamma table (only used with the sn9c103 bridge) */ - for (i = 0; i < 16; i++) - regs[0x20 + i] = i * 16; - regs[0x20 + i] = 255; - - /* Special cases where some regs depend on mode or bridge */ - switch (sd->sensor) { - case SENSOR_TAS5130CXX: - /* FIXME / TESTME - probably not mode specific at all most likely the upper - nibble of 0x19 is exposure (clock divider) just as with - the tas5110, we need someone to test this. */ - regs[0x19] = mode ? 0x23 : 0x43; - break; - case SENSOR_OV7630: - /* FIXME / TESTME for some reason with the 101/102 bridge the - clock is set to 12 Mhz (reg1 == 0x04), rather then 24. - Also the hstart needs to go from 1 to 2 when using a 103, - which is likely related. This does not seem right. */ - if (sd->bridge == BRIDGE_103) { - regs[0x01] = 0x44; /* Select 24 Mhz clock */ - regs[0x12] = 0x02; /* Set hstart to 2 */ - } - } - /* Disable compression when the raw bayer format has been selected */ - if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) - regs[0x18] &= ~0x80; - - /* Vga mode emulation on SIF sensor? */ - if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) { - regs[0x12] += 16; /* hstart adjust */ - regs[0x13] += 24; /* vstart adjust */ - regs[0x15] = 320 / 16; /* hsize */ - regs[0x16] = 240 / 16; /* vsize */ - } - - /* reg 0x01 bit 2 video transfert on */ - reg_w(gspca_dev, 0x01, ®s[0x01], 1); - /* reg 0x17 SensorClk enable inv Clk 0x60 */ - reg_w(gspca_dev, 0x17, ®s[0x17], 1); - /* Set the registers from the template */ - reg_w(gspca_dev, 0x01, ®s[0x01], - (sd->bridge == BRIDGE_103) ? 0x30 : 0x1f); - - /* Init the sensor */ - i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init, - sensor_data[sd->sensor].sensor_init_size); - - /* Mode / bridge specific sensor setup */ - switch (sd->sensor) { - case SENSOR_PAS202: { - const __u8 i2cpclockdiv[] = - {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10}; - /* clockdiv from 4 to 3 (7.5 -> 10 fps) when in low res mode */ - if (mode) - i2c_w(gspca_dev, i2cpclockdiv); - break; - } - case SENSOR_OV7630: - /* FIXME / TESTME We should be able to handle this identical - for the 101/102 and the 103 case */ - if (sd->bridge == BRIDGE_103) { - const __u8 i2c[] = { 0xa0, 0x21, 0x13, - 0x80, 0x00, 0x00, 0x00, 0x10 }; - i2c_w(gspca_dev, i2c); - } - break; - } - /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */ - reg_w(gspca_dev, 0x15, ®s[0x15], 2); - /* compression register */ - reg_w(gspca_dev, 0x18, ®s[0x18], 1); - /* H_start */ - reg_w(gspca_dev, 0x12, ®s[0x12], 1); - /* V_START */ - reg_w(gspca_dev, 0x13, ®s[0x13], 1); - /* reset 0x17 SensorClk enable inv Clk 0x60 */ - /*fixme: ov7630 [17]=68 8f (+20 if 102)*/ - reg_w(gspca_dev, 0x17, ®s[0x17], 1); - /*MCKSIZE ->3 */ /*fixme: not ov7630*/ - reg_w(gspca_dev, 0x19, ®s[0x19], 1); - /* AE_STRX AE_STRY AE_ENDX AE_ENDY */ - reg_w(gspca_dev, 0x1c, ®s[0x1c], 4); - /* Enable video transfert */ - reg_w(gspca_dev, 0x01, ®s[0x01], 1); - /* Compression */ - reg_w(gspca_dev, 0x18, ®s[0x18], 2); - msleep(20); - - sd->reg11 = -1; - - setgain(gspca_dev); - setbrightness(gspca_dev); - setexposure(gspca_dev); - setfreq(gspca_dev); - - sd->frames_to_drop = 0; - sd->autogain_ignore_frames = 0; - sd->exp_too_high_cnt = 0; - sd->exp_too_low_cnt = 0; - atomic_set(&sd->avg_lum, -1); - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - sd_init(gspca_dev); -} - -static u8* find_sof(struct gspca_dev *gspca_dev, u8 *data, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, header_size = (sd->bridge == BRIDGE_103) ? 18 : 12; - - /* frames start with: - * ff ff 00 c4 c4 96 synchro - * 00 (unknown) - * xx (frame sequence / size / compression) - * (xx) (idem - extra byte for sn9c103) - * ll mm brightness sum inside auto exposure - * ll mm brightness sum outside auto exposure - * (xx xx xx xx xx) audio values for snc103 - */ - for (i = 0; i < len; i++) { - switch (sd->header_read) { - case 0: - if (data[i] == 0xff) - sd->header_read++; - break; - case 1: - if (data[i] == 0xff) - sd->header_read++; - else - sd->header_read = 0; - break; - case 2: - if (data[i] == 0x00) - sd->header_read++; - else if (data[i] != 0xff) - sd->header_read = 0; - break; - case 3: - if (data[i] == 0xc4) - sd->header_read++; - else if (data[i] == 0xff) - sd->header_read = 1; - else - sd->header_read = 0; - break; - case 4: - if (data[i] == 0xc4) - sd->header_read++; - else if (data[i] == 0xff) - sd->header_read = 1; - else - sd->header_read = 0; - break; - case 5: - if (data[i] == 0x96) - sd->header_read++; - else if (data[i] == 0xff) - sd->header_read = 1; - else - sd->header_read = 0; - break; - default: - sd->header[sd->header_read - 6] = data[i]; - sd->header_read++; - if (sd->header_read == header_size) { - sd->header_read = 0; - return data + i + 1; - } - } - } - return NULL; -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - int fr_h_sz = 0, lum_offset = 0, len_after_sof = 0; - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam = &gspca_dev->cam; - u8 *sof; - - sof = find_sof(gspca_dev, data, len); - if (sof) { - if (sd->bridge == BRIDGE_103) { - fr_h_sz = 18; - lum_offset = 3; - } else { - fr_h_sz = 12; - lum_offset = 2; - } - - len_after_sof = len - (sof - data); - len = (sof - data) - fr_h_sz; - if (len < 0) - len = 0; - } - - if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { - /* In raw mode we sometimes get some garbage after the frame - ignore this */ - int used; - int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage; - - used = gspca_dev->image_len; - if (used + len > size) - len = size - used; - } - - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - - if (sof) { - int lum = sd->header[lum_offset] + - (sd->header[lum_offset + 1] << 8); - - /* When exposure changes midway a frame we - get a lum of 0 in this case drop 2 frames - as the frames directly after an exposure - change have an unstable image. Sometimes lum - *really* is 0 (cam used in low light with - low exposure setting), so do not drop frames - if the previous lum was 0 too. */ - if (lum == 0 && sd->prev_avg_lum != 0) { - lum = -1; - sd->frames_to_drop = 2; - sd->prev_avg_lum = 0; - } else - sd->prev_avg_lum = lum; - atomic_set(&sd->avg_lum, lum); - - if (sd->frames_to_drop) - sd->frames_to_drop--; - else - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - - gspca_frame_add(gspca_dev, FIRST_PACKET, sof, len_after_sof); - } -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AUTOGAIN].val = val; - sd->exp_too_high_cnt = 0; - sd->exp_too_low_cnt = 0; - - /* when switching to autogain set defaults to make sure - we are on a valid point of the autogain gain / - exposure knee graph, and give this change time to - take effect before doing autogain. */ - if (sd->ctrls[AUTOGAIN].val - && !(sensor_data[sd->sensor].flags & F_COARSE_EXPO)) { - sd->ctrls[EXPOSURE].val = sd->ctrls[EXPOSURE].def; - sd->ctrls[GAIN].val = sd->ctrls[GAIN].def; - if (gspca_dev->streaming) { - sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; - setexposure(gspca_dev); - setgain(gspca_dev); - } - } - - if (sd->ctrls[AUTOGAIN].val) - gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); - else - gspca_dev->ctrl_inac = 0; - - return 0; -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - } - return -EINVAL; -} - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* interrupt packet data */ - int len) /* interrupt packet length */ -{ - int ret = -EINVAL; - - if (len == 1 && data[0] == 1) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); - input_sync(gspca_dev->input_dev); - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - ret = 0; - } - - return ret; -} -#endif - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, - .dq_callback = do_autogain, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -#endif -}; - -/* -- module initialisation -- */ -#define SB(sensor, bridge) \ - .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge - - -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110C, 102)}, /* TAS5110C1B */ - {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110C, 101)}, /* TAS5110C1B */ - {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110D, 101)}, /* TAS5110D */ - {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)}, - {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)}, - {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)}, - {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)}, -#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE - {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)}, - {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, -#endif - {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)}, - {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, - {USB_DEVICE(0x0c45, 0x602a), SB(HV7131D, 102)}, - /* {USB_DEVICE(0x0c45, 0x602b), SB(MI0343, 102)}, */ - {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, - {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)}, - {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)}, - /* {USB_DEVICE(0x0c45, 0x6030), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */ - /* {USB_DEVICE(0x0c45, 0x6082), SB(MI03XX, 103)}, */ /* MI0343 MI0360 */ - {USB_DEVICE(0x0c45, 0x6083), SB(HV7131D, 103)}, - {USB_DEVICE(0x0c45, 0x608c), SB(HV7131R, 103)}, - /* {USB_DEVICE(0x0c45, 0x608e), SB(CISVF10, 103)}, */ - {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)}, - {USB_DEVICE(0x0c45, 0x60a8), SB(PAS106, 103)}, - {USB_DEVICE(0x0c45, 0x60aa), SB(TAS5130CXX, 103)}, - {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)}, - {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sonixj.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sonixj.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sonixj.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sonixj.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3115 +0,0 @@ -/* - * Sonix sn9c102p sn9c105 sn9c120 (jpeg) subdriver - * - * Copyright (C) 2009-2010 Jean-François Moine - * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "sonixj" - -#include -#include "gspca.h" -#include "jpeg.h" - -MODULE_AUTHOR("Jean-François Moine "); -MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - COLORS, - BLUE, - RED, - GAMMA, - AUTOGAIN, - HFLIP, - VFLIP, - SHARPNESS, - ILLUM, - FREQ, - NCTRLS /* number of controls */ -}; - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRLS]; - - atomic_t avg_lum; - u32 exposure; - - struct work_struct work; - struct workqueue_struct *work_thread; - - u32 pktsz; /* (used by pkt_scan) */ - u16 npkt; - u8 nchg; - s8 short_mark; - - u8 quality; /* image quality */ -#define QUALITY_MIN 25 -#define QUALITY_MAX 90 -#define QUALITY_DEF 70 - - u8 reg01; - u8 reg17; - u8 reg18; - u8 flags; - - s8 ag_cnt; -#define AG_CNT_START 13 - - u8 bridge; -#define BRIDGE_SN9C102P 0 -#define BRIDGE_SN9C105 1 -#define BRIDGE_SN9C110 2 -#define BRIDGE_SN9C120 3 - u8 sensor; /* Type of image sensor chip */ - u8 i2c_addr; - - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; -enum sensors { - SENSOR_ADCM1700, - SENSOR_GC0307, - SENSOR_HV7131R, - SENSOR_MI0360, - SENSOR_MI0360B, - SENSOR_MO4000, - SENSOR_MT9V111, - SENSOR_OM6802, - SENSOR_OV7630, - SENSOR_OV7648, - SENSOR_OV7660, - SENSOR_PO1030, - SENSOR_PO2030N, - SENSOR_SOI768, - SENSOR_SP80708, -}; - -static void qual_upd(struct work_struct *work); - -/* device flags */ -#define F_PDN_INV 0x01 /* inverse pin S_PWR_DN / sn_xxx tables */ -#define F_ILLUM 0x02 /* presence of illuminator */ - -/* sn9c1xx definitions */ -/* register 0x01 */ -#define S_PWR_DN 0x01 /* sensor power down */ -#define S_PDN_INV 0x02 /* inverse pin S_PWR_DN */ -#define V_TX_EN 0x04 /* video transfer enable */ -#define LED 0x08 /* output to pin LED */ -#define SCL_SEL_OD 0x20 /* open-drain mode */ -#define SYS_SEL_48M 0x40 /* system clock 0: 24MHz, 1: 48MHz */ -/* register 0x17 */ -#define MCK_SIZE_MASK 0x1f /* sensor master clock */ -#define SEN_CLK_EN 0x20 /* enable sensor clock */ -#define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */ - -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void setredblue(struct gspca_dev *gspca_dev); -static void setgamma(struct gspca_dev *gspca_dev); -static void setautogain(struct gspca_dev *gspca_dev); -static void sethvflip(struct gspca_dev *gspca_dev); -static void setsharpness(struct gspca_dev *gspca_dev); -static void setillum(struct gspca_dev *gspca_dev); -static void setfreq(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x80, - }, - .set_control = setbrightness - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, -#define CONTRAST_MAX 127 - .maximum = CONTRAST_MAX, - .step = 1, - .default_value = 63, - }, - .set_control = setcontrast - }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 40, - .step = 1, -#define COLORS_DEF 25 - .default_value = COLORS_DEF, - }, - .set_control = setcolors - }, -[BLUE] = { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 24, - .maximum = 40, - .step = 1, - .default_value = 32, - }, - .set_control = setredblue - }, -[RED] = { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 24, - .maximum = 40, - .step = 1, - .default_value = 32, - }, - .set_control = setredblue - }, -[GAMMA] = { - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 40, - .step = 1, -#define GAMMA_DEF 20 - .default_value = GAMMA_DEF, - }, - .set_control = setgamma - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set_control = setautogain - }, -[HFLIP] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip - }, -[VFLIP] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 90, - }, - .set_control = setsharpness - }, -[ILLUM] = { - { - .id = V4L2_CID_ILLUMINATORS_1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Illuminator / infrared", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = setillum - }, -/* ov7630/ov7648/ov7660 only */ -[FREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, - .default_value = 1, - }, - .set_control = setfreq - }, -}; - -/* table of the disabled controls */ -static const __u32 ctrl_dis[] = { -[SENSOR_ADCM1700] = (1 << AUTOGAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_GC0307] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_HV7131R] = (1 << HFLIP) | - (1 << FREQ), - -[SENSOR_MI0360] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_MI0360B] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_MO4000] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_MT9V111] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_OM6802] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_OV7630] = (1 << HFLIP), - -[SENSOR_OV7648] = (1 << HFLIP), - -[SENSOR_OV7660] = (1 << AUTOGAIN) | - (1 << HFLIP) | - (1 << VFLIP), - -[SENSOR_PO1030] = (1 << AUTOGAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_PO2030N] = (1 << AUTOGAIN) | - (1 << FREQ), - -[SENSOR_SOI768] = (1 << AUTOGAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_SP80708] = (1 << AUTOGAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), -}; - -static const struct v4l2_pix_format cif_mode[] = { - {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; -static const struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - /* Note 3 / 8 is not large enough, not even 5 / 8 is ?! */ - .sizeimage = 640 * 480 * 3 / 4 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -static const u8 sn_adcm1700[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x43, 0x60, 0x00, 0x1a, 0x00, 0x00, 0x00, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x80, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x05, 0x01, 0x05, 0x16, 0x12, 0x42, -/* reg18 reg19 reg1a reg1b */ - 0x06, 0x00, 0x00, 0x00 -}; - -static const u8 sn_gc0307[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x61, 0x62, 0x00, 0x1a, 0x00, 0x00, 0x00, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x80, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x03, 0x01, 0x08, 0x28, 0x1e, 0x02, -/* reg18 reg19 reg1a reg1b */ - 0x06, 0x00, 0x00, 0x00 -}; - -static const u8 sn_hv7131[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x03, 0x60, 0x00, 0x1a, 0x20, 0x20, 0x20, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, -/* reg18 reg19 reg1a reg1b */ - 0x0a, 0x00, 0x00, 0x00 -}; - -static const u8 sn_mi0360[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x63, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, -/* reg18 reg19 reg1a reg1b */ - 0x06, 0x00, 0x00, 0x00 -}; - -static const u8 sn_mi0360b[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x40, -/* reg18 reg19 reg1a reg1b */ - 0x06, 0x00, 0x00, 0x00 -}; - -static const u8 sn_mo4000[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x23, 0x60, 0x00, 0x1a, 0x00, 0x20, 0x18, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, -/* reg18 reg19 reg1a reg1b */ - 0x08, 0x00, 0x00, 0x00 -}; - -static const u8 sn_mt9v111[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x02, 0x1c, 0x28, 0x1e, 0x40, -/* reg18 reg19 reg1a reg1b */ - 0x06, 0x00, 0x00, 0x00 -}; - -static const u8 sn_om6802[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x23, 0x72, 0x00, 0x1a, 0x20, 0x20, 0x19, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x51, 0x01, 0x00, 0x28, 0x1e, 0x40, -/* reg18 reg19 reg1a reg1b */ - 0x05, 0x00, 0x00, 0x00 -}; - -static const u8 sn_ov7630[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x21, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x04, 0x01, 0x0a, 0x28, 0x1e, 0xc2, -/* reg18 reg19 reg1a reg1b */ - 0x0b, 0x00, 0x00, 0x00 -}; - -static const u8 sn_ov7648[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x63, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x01, 0x00, 0x28, 0x1e, 0x00, -/* reg18 reg19 reg1a reg1b */ - 0x0b, 0x00, 0x00, 0x00 -}; - -static const u8 sn_ov7660[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, -/* reg18 reg19 reg1a reg1b */ - 0x07, 0x00, 0x00, 0x00 -}; - -static const u8 sn_po1030[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1e, 0x00, -/* reg18 reg19 reg1a reg1b */ - 0x07, 0x00, 0x00, 0x00 -}; - -static const u8 sn_po2030n[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x63, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x01, 0x14, 0x28, 0x1e, 0x00, -/* reg18 reg19 reg1a reg1b */ - 0x07, 0x00, 0x00, 0x00 -}; - -static const u8 sn_soi768[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x21, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x01, 0x08, 0x28, 0x1e, 0x00, -/* reg18 reg19 reg1a reg1b */ - 0x07, 0x00, 0x00, 0x00 -}; - -static const u8 sn_sp80708[0x1c] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x63, 0x60, 0x00, 0x1a, 0x20, 0x20, 0x20, -/* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x03, 0x04, 0x28, 0x1e, 0x00, -/* reg18 reg19 reg1a reg1b */ - 0x07, 0x00, 0x00, 0x00 -}; - -/* sequence specific to the sensors - !! index = SENSOR_xxx */ -static const u8 *sn_tb[] = { -[SENSOR_ADCM1700] = sn_adcm1700, -[SENSOR_GC0307] = sn_gc0307, -[SENSOR_HV7131R] = sn_hv7131, -[SENSOR_MI0360] = sn_mi0360, -[SENSOR_MI0360B] = sn_mi0360b, -[SENSOR_MO4000] = sn_mo4000, -[SENSOR_MT9V111] = sn_mt9v111, -[SENSOR_OM6802] = sn_om6802, -[SENSOR_OV7630] = sn_ov7630, -[SENSOR_OV7648] = sn_ov7648, -[SENSOR_OV7660] = sn_ov7660, -[SENSOR_PO1030] = sn_po1030, -[SENSOR_PO2030N] = sn_po2030n, -[SENSOR_SOI768] = sn_soi768, -[SENSOR_SP80708] = sn_sp80708, -}; - -/* default gamma table */ -static const u8 gamma_def[17] = { - 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99, - 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff -}; -/* gamma for sensor ADCM1700 */ -static const u8 gamma_spec_0[17] = { - 0x0f, 0x39, 0x5a, 0x74, 0x86, 0x95, 0xa6, 0xb4, - 0xbd, 0xc4, 0xcc, 0xd4, 0xd5, 0xde, 0xe4, 0xed, 0xf5 -}; -/* gamma for sensors HV7131R and MT9V111 */ -static const u8 gamma_spec_1[17] = { - 0x08, 0x3a, 0x52, 0x65, 0x75, 0x83, 0x91, 0x9d, - 0xa9, 0xb4, 0xbe, 0xc8, 0xd2, 0xdb, 0xe4, 0xed, 0xf5 -}; -/* gamma for sensor GC0307 */ -static const u8 gamma_spec_2[17] = { - 0x14, 0x37, 0x50, 0x6a, 0x7c, 0x8d, 0x9d, 0xab, - 0xb5, 0xbf, 0xc2, 0xcb, 0xd1, 0xd6, 0xdb, 0xe1, 0xeb -}; -/* gamma for sensor SP80708 */ -static const u8 gamma_spec_3[17] = { - 0x0a, 0x2d, 0x4e, 0x68, 0x7d, 0x8f, 0x9f, 0xab, - 0xb7, 0xc2, 0xcc, 0xd3, 0xd8, 0xde, 0xe2, 0xe5, 0xe6 -}; - -/* color matrix and offsets */ -static const u8 reg84[] = { - 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, /* YR YG YB gains */ - 0xe8, 0x0f, 0xda, 0x0f, 0x40, 0x00, /* UR UG UB */ - 0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f, /* VR VG VB */ - 0x00, 0x00, 0x00 /* YUV offsets */ -}; - -#define DELAY 0xdd - -static const u8 adcm1700_sensor_init[][8] = { - {0xa0, 0x51, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x04, 0x08, 0x00, 0x00, 0x00, 0x10}, /* reset */ - {DELAY, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xb0, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xb0, 0x51, 0x0c, 0xe0, 0x2e, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x10, 0x02, 0x02, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x14, 0x0e, 0x0e, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x1c, 0x00, 0x80, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x20, 0x01, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xb0, 0x51, 0x04, 0x04, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xb0, 0x51, 0x04, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x14, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 adcm1700_sensor_param1[][8] = { - {0xb0, 0x51, 0x26, 0xf9, 0x01, 0x00, 0x00, 0x10}, /* exposure? */ - {0xd0, 0x51, 0x1e, 0x8e, 0x8e, 0x8e, 0x8e, 0x10}, - - {0xa0, 0x51, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x32, 0x00, 0x72, 0x00, 0x00, 0x10}, - {0xd0, 0x51, 0x1e, 0xbe, 0xd7, 0xe8, 0xbe, 0x10}, /* exposure? */ - - {0xa0, 0x51, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10}, - {0xb0, 0x51, 0x32, 0x00, 0xa2, 0x00, 0x00, 0x10}, - {} -}; -static const u8 gc0307_sensor_init[][8] = { - {0xa0, 0x21, 0x43, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x44, 0xa2, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x01, 0x6a, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x02, 0x70, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x11, 0x05, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x08, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x09, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x0a, 0xe8, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x0b, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x0c, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x0d, 0x22, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x0f, 0xb2, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x12, 0x70, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 10ms*/ - {0xa0, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x15, 0xb8, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x16, 0x13, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x17, 0x52, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x18, 0x50, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x1e, 0x0d, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x1f, 0x32, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x61, 0x90, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x63, 0x70, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x65, 0x98, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x67, 0x90, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x04, 0x96, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x45, 0x27, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x47, 0x2c, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x43, 0x47, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x44, 0xd8, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 gc0307_sensor_param1[][8] = { - {0xa0, 0x21, 0x68, 0x13, 0x00, 0x00, 0x00, 0x10}, - {0xd0, 0x21, 0x61, 0x80, 0x00, 0x80, 0x00, 0x10}, - {0xc0, 0x21, 0x65, 0x80, 0x00, 0x80, 0x00, 0x10}, - {0xc0, 0x21, 0x63, 0xa0, 0x00, 0xa6, 0x00, 0x10}, -/*param3*/ - {0xa0, 0x21, 0x01, 0x6e, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x02, 0x88, 0x00, 0x00, 0x00, 0x10}, - {} -}; - -static const u8 hv7131r_sensor_init[][8] = { - {0xc1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10}, - {0xb1, 0x11, 0x34, 0x17, 0x7f, 0x00, 0x00, 0x10}, - {0xd1, 0x11, 0x40, 0xff, 0x7f, 0x7f, 0x7f, 0x10}, -/* {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10}, */ - {0xd1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x11, 0x14, 0x01, 0xe2, 0x02, 0x82, 0x10}, -/* {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, */ - - {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xc1, 0x11, 0x25, 0x00, 0x61, 0xa8, 0x00, 0x10}, - {0xa1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10}, - {0xc1, 0x11, 0x31, 0x20, 0x2e, 0x20, 0x00, 0x10}, - {0xc1, 0x11, 0x25, 0x00, 0xc3, 0x50, 0x00, 0x10}, - {0xa1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */ - {0xc1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */ - - {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x21, 0xd0, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10}, - - {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x21, 0xd0, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10}, - /* set sensor clock */ - {} -}; -static const u8 mi0360_sensor_init[][8] = { - {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10}, - {0xd1, 0x5d, 0x03, 0x01, 0xe2, 0x02, 0x82, 0x10}, - {0xd1, 0x5d, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10}, - {0xb1, 0x5d, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10}, - {0xd1, 0x5d, 0x2f, 0xf7, 0xB0, 0x00, 0x04, 0x10}, - {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10}, - {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x40, 0x01, 0xe0, 0x00, 0xd1, 0x10}, - {0xb1, 0x5d, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10}, - {0xd1, 0x5d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x5e, 0x00, 0x00, 0xa3, 0x1d, 0x10}, - {0xb1, 0x5d, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10}, - - {0xb1, 0x5d, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x2b, 0x00, 0xa0, 0x00, 0xb0, 0x10}, - {0xd1, 0x5d, 0x2d, 0x00, 0xa0, 0x00, 0xa0, 0x10}, - - {0xb1, 0x5d, 0x0a, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */ - {0xb1, 0x5d, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */ - - {0xd1, 0x5d, 0x2b, 0x00, 0xb9, 0x00, 0xe3, 0x10}, - {0xd1, 0x5d, 0x2d, 0x00, 0x5f, 0x00, 0xb9, 0x10}, /* 42 */ -/* {0xb1, 0x5d, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */ -/* {0xb1, 0x5d, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */ - {0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */ - {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */ - {} -}; -static const u8 mi0360b_sensor_init[][8] = { - {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, - {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 20ms*/ - {0xb1, 0x5d, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 20ms*/ - {0xd1, 0x5d, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10}, - {0xd1, 0x5d, 0x03, 0x01, 0xe2, 0x02, 0x82, 0x10}, - {0xd1, 0x5d, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10}, - {0xd1, 0x5d, 0x2f, 0xf7, 0xb0, 0x00, 0x04, 0x10}, - {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10}, - {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x40, 0x01, 0xe0, 0x00, 0xd1, 0x10}, - {0xb1, 0x5d, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10}, - {0xd1, 0x5d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x5e, 0x00, 0x00, 0xa3, 0x1d, 0x10}, - {0xb1, 0x5d, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10}, - - {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10}, - {0xd1, 0x5d, 0x2b, 0x00, 0x33, 0x00, 0xa0, 0x10}, - {0xd1, 0x5d, 0x2d, 0x00, 0xa0, 0x00, 0x33, 0x10}, - {} -}; -static const u8 mi0360b_sensor_param1[][8] = { - {0xb1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x06, 0x00, 0x53, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x05, 0x00, 0x09, 0x00, 0x00, 0x10}, - {0xb1, 0x5d, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */ - - {0xd1, 0x5d, 0x2b, 0x00, 0xd1, 0x01, 0xc9, 0x10}, - {0xd1, 0x5d, 0x2d, 0x00, 0xed, 0x00, 0xd1, 0x10}, - {0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */ - {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */ - {} -}; -static const u8 mo4000_sensor_init[][8] = { - {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 mt9v111_sensor_init[][8] = { - {0xb1, 0x5c, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, /* reset? */ - {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ - {0xb1, 0x5c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x10}, /* IFP select */ - {0xb1, 0x5c, 0x08, 0x04, 0x80, 0x00, 0x00, 0x10}, /* output fmt ctrl */ - {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, /* op mode ctrl */ - {0xb1, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10}, /* sensor select */ - {0xb1, 0x5c, 0x08, 0x00, 0x08, 0x00, 0x00, 0x10}, /* row start */ - {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10}, /* col start */ - {0xb1, 0x5c, 0x03, 0x01, 0xe7, 0x00, 0x00, 0x10}, /* window height */ - {0xb1, 0x5c, 0x04, 0x02, 0x87, 0x00, 0x00, 0x10}, /* window width */ - {0xb1, 0x5c, 0x07, 0x30, 0x02, 0x00, 0x00, 0x10}, /* output ctrl */ - {0xb1, 0x5c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10}, /* shutter delay */ - {0xb1, 0x5c, 0x12, 0x00, 0xb0, 0x00, 0x00, 0x10}, /* zoom col start */ - {0xb1, 0x5c, 0x13, 0x00, 0x7c, 0x00, 0x00, 0x10}, /* zoom row start */ - {0xb1, 0x5c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* digital zoom */ - {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, /* read mode */ - {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 mt9v111_sensor_param1[][8] = { - {0xd1, 0x5c, 0x2b, 0x00, 0x33, 0x00, 0xad, 0x10}, /* G1 and B gains */ - {0xd1, 0x5c, 0x2d, 0x00, 0xad, 0x00, 0x33, 0x10}, /* R and G2 gains */ - {0xb1, 0x5c, 0x06, 0x00, 0x40, 0x00, 0x00, 0x10}, /* vert blanking */ - {0xb1, 0x5c, 0x05, 0x00, 0x09, 0x00, 0x00, 0x10}, /* horiz blanking */ - {0xb1, 0x5c, 0x35, 0x01, 0xc0, 0x00, 0x00, 0x10}, /* global gain */ - {} -}; -static const u8 om6802_init0[2][8] = { -/*fixme: variable*/ - {0xa0, 0x34, 0x29, 0x0e, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x34, 0x23, 0xb0, 0x00, 0x00, 0x00, 0x10}, -}; -static const u8 om6802_sensor_init[][8] = { - {0xa0, 0x34, 0xdf, 0x6d, 0x00, 0x00, 0x00, 0x10}, - /* factory mode */ - {0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10}, - /* output raw RGB */ - {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10}, -/* {0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */ - {0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10}, - /* auto-exposure speed (0) / white balance mode (auto RGB) */ -/* {0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10}, - * set color mode */ -/* {0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10}, - * max AGC value in AE */ -/* {0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10}, - * preset AGC */ -/* {0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10}, - * preset brightness */ -/* {0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10}, - * preset contrast */ -/* {0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10}, - * preset gamma */ - {0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10}, - /* luminance mode (0x4f -> AutoExpo on) */ - {0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10}, - /* preset shutter */ -/* {0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10}, - * auto frame rate */ -/* {0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */ - {0xa0, 0x34, 0x5d, 0x80, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 om6802_sensor_param1[][8] = { - {0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 ov7630_sensor_init[][8] = { - {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ - {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ - {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, -/* win: i2c_r from 00 to 80 */ - {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10}, - {0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10}, -/* HDG: 0x11 was 0x00 change to 0x01 for better exposure (15 fps instead of 30) - 0x13 was 0xc0 change to 0xc3 for auto gain and exposure */ - {0xd1, 0x21, 0x11, 0x01, 0x48, 0xc3, 0x00, 0x10}, - {0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10}, - {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, - {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10}, - {0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10}, - {0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10}, - {0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10}, - {0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10}, - {0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10}, - {0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10}, - {0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10}, - {0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10}, - {0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10}, - {0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10}, - {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, - {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 ov7630_sensor_param1[][8] = { - {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, -/*fixme: + 0x12, 0x04*/ -/* {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10}, * COMN - * set by setvflip */ - {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10}, -/* */ -/* {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */ -/* {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */ -/* */ - {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10}, -/* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */ - {} -}; - -static const u8 ov7648_sensor_init[][8] = { - {0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */ - {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ - {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x21, 0x03, 0xa4, 0x30, 0x88, 0x00, 0x10}, - {0xb1, 0x21, 0x11, 0x80, 0x08, 0x00, 0x00, 0x10}, - {0xc1, 0x21, 0x13, 0xa0, 0x04, 0x84, 0x00, 0x10}, - {0xd1, 0x21, 0x17, 0x1a, 0x02, 0xba, 0xf4, 0x10}, - {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x21, 0x1f, 0x41, 0xc0, 0x80, 0x80, 0x10}, - {0xd1, 0x21, 0x23, 0xde, 0xa0, 0x80, 0x32, 0x10}, - {0xd1, 0x21, 0x27, 0xfe, 0xa0, 0x00, 0x91, 0x10}, - {0xd1, 0x21, 0x2b, 0x00, 0x88, 0x85, 0x80, 0x10}, - {0xc1, 0x21, 0x2f, 0x9c, 0x00, 0xc4, 0x00, 0x10}, - {0xd1, 0x21, 0x60, 0xa6, 0x60, 0x88, 0x12, 0x10}, - {0xd1, 0x21, 0x64, 0x88, 0x00, 0x00, 0x94, 0x10}, - {0xd1, 0x21, 0x68, 0x7a, 0x0c, 0x00, 0x00, 0x10}, - {0xd1, 0x21, 0x6c, 0x11, 0x33, 0x22, 0x00, 0x10}, - {0xd1, 0x21, 0x70, 0x11, 0x00, 0x10, 0x50, 0x10}, - {0xd1, 0x21, 0x74, 0x20, 0x06, 0x00, 0xb5, 0x10}, - {0xd1, 0x21, 0x78, 0x8a, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x7c, 0x00, 0x43, 0x00, 0x00, 0x10}, - - {0xd1, 0x21, 0x21, 0x86, 0x00, 0xde, 0xa0, 0x10}, -/* {0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */ -/* {0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */ -/* {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10}, set by setfreq */ - {} -}; -static const u8 ov7648_sensor_param1[][8] = { -/* {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */ -/* {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, * COMN - * set by setvflip */ - {0xa1, 0x21, 0x19, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10}, -/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ -/* {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, * GAIN - def */ -/* {0xb1, 0x21, 0x01, 0x6c, 0x6c, 0x00, 0x00, 0x10}, * B R - def: 80 */ -/*...*/ - {0xa1, 0x21, 0x11, 0x81, 0x00, 0x00, 0x00, 0x10}, /* CLKRC */ -/* {0xa1, 0x21, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ -/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ -/* {0xa1, 0x21, 0x2a, 0x91, 0x00, 0x00, 0x00, 0x10}, jfm done */ -/* {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ -/* {0xb1, 0x21, 0x01, 0x64, 0x84, 0x00, 0x00, 0x10}, * B R - def: 80 */ - - {} -}; - -static const u8 ov7660_sensor_init[][8] = { - {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ - {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ - {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10}, - /* Outformat = rawRGB */ - {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */ - {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10}, - /* GAIN BLUE RED VREF */ - {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10}, - /* COM 1 BAVE GEAVE AECHH */ - {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */ - {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */ - {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, - /* AECH CLKRC COM7 COM8 */ - {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */ - {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10}, - /* HSTART HSTOP VSTRT VSTOP */ - {0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */ - {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */ - {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10}, - /* BOS GBOS GROS ROS (BGGR offset) */ -/* {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10}, */ - {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, - /* AEW AEB VPT BBIAS */ - {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10}, - /* GbBIAS RSVD EXHCH EXHCL */ - {0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10}, - /* RBIAS ADVFL ASDVFH YAVE */ - {0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10}, - /* HSYST HSYEN HREF */ - {0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */ - {0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10}, - /* ADC ACOM OFON TSLB */ - {0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10}, - /* COM11 COM12 COM13 COM14 */ - {0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10}, - /* EDGE COM15 COM16 COM17 */ - {0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */ - {0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */ - {0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */ - {0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */ - {0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */ - {0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */ - {0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */ - {0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */ - {0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */ - {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10}, - /* LCC1 LCC2 LCC3 LCC4 */ - {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */ - {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10}, /* MANU */ - {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10}, - /* band gap reference [0:3] DBLV */ - {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */ - {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */ - {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */ - {0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */ - {0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */ - {0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */ - {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */ - {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */ - {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */ - {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */ -/* not in all ms-win traces*/ - {0xa1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 ov7660_sensor_param1[][8] = { - {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */ - /* bits[3..0]reserved */ - {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, - /* VREF vertical frame ctrl */ - {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* AECH 0x20 */ - {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFL */ - {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFH */ - {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, /* GAIN */ -/* {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, * BLUE */ -/****** (some exchanges in the win trace) ******/ -/*fixme:param2*/ - {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */ - {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10}, /* dummy line low */ - {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCH */ - {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCL */ -/* {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, * RED */ -/****** (some exchanges in the win trace) ******/ -/******!! startsensor KO if changed !!****/ -/*fixme: param3*/ - {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10}, - {} -}; - -static const u8 po1030_sensor_init[][8] = { -/* the sensor registers are described in m5602/m5602_po1030.h */ - {0xa1, 0x6e, 0x3f, 0x20, 0x00, 0x00, 0x00, 0x10}, /* sensor reset */ - {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ - {0xa1, 0x6e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x04, 0x02, 0xb1, 0x02, 0x39, 0x10}, - {0xd1, 0x6e, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x0c, 0x02, 0x7f, 0x01, 0xe0, 0x10}, - {0xd1, 0x6e, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10}, - {0xd1, 0x6e, 0x16, 0x85, 0x40, 0x4a, 0x40, 0x10}, /* r/g1/b/g2 gains */ - {0xc1, 0x6e, 0x1a, 0x00, 0x80, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x1d, 0x08, 0x03, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x23, 0x00, 0xb0, 0x00, 0x94, 0x10}, - {0xd1, 0x6e, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x6e, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x2d, 0x14, 0x35, 0x61, 0x84, 0x10}, /* gamma corr */ - {0xd1, 0x6e, 0x31, 0xa2, 0xbd, 0xd8, 0xff, 0x10}, - {0xd1, 0x6e, 0x35, 0x06, 0x1e, 0x12, 0x02, 0x10}, /* color matrix */ - {0xd1, 0x6e, 0x39, 0xaa, 0x53, 0x37, 0xd5, 0x10}, - {0xa1, 0x6e, 0x3d, 0xf2, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x3e, 0x00, 0x00, 0x80, 0x03, 0x10}, - {0xd1, 0x6e, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xc1, 0x6e, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10}, - {0xd1, 0x6e, 0x4b, 0x02, 0xef, 0x08, 0xcd, 0x10}, - {0xd1, 0x6e, 0x4f, 0x00, 0xd0, 0x00, 0xa0, 0x10}, - {0xd1, 0x6e, 0x53, 0x01, 0xaa, 0x01, 0x40, 0x10}, - {0xd1, 0x6e, 0x5a, 0x50, 0x04, 0x30, 0x03, 0x10}, /* raw rgb bayer */ - {0xa1, 0x6e, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x5f, 0x10, 0x40, 0xff, 0x00, 0x10}, - - {0xd1, 0x6e, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xc1, 0x6e, 0x73, 0x10, 0x80, 0xeb, 0x00, 0x10}, - {} -}; -static const u8 po1030_sensor_param1[][8] = { -/* from ms-win traces - these values change with auto gain/expo/wb.. */ - {0xa1, 0x6e, 0x1e, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x1e, 0x03, 0x00, 0x00, 0x00, 0x10}, -/* mean values */ - {0xc1, 0x6e, 0x1a, 0x02, 0xd4, 0xa4, 0x00, 0x10}, /* integlines */ - {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, /* global gain */ - {0xc1, 0x6e, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10}, /* r/g1/b gains */ - - {0xa1, 0x6e, 0x1d, 0x08, 0x00, 0x00, 0x00, 0x10}, /* control1 */ - {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, /* frameheight */ - {0xa1, 0x6e, 0x07, 0xd5, 0x00, 0x00, 0x00, 0x10}, -/* {0xc1, 0x6e, 0x16, 0x49, 0x40, 0x45, 0x00, 0x10}, */ - {} -}; - -static const u8 po2030n_sensor_init[][8] = { - {0xa1, 0x6e, 0x1e, 0x1a, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x1f, 0x99, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */ - {0xa1, 0x6e, 0x1e, 0x0a, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x1f, 0x19, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */ - {0xa1, 0x6e, 0x20, 0x44, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x05, 0x70, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x10}, - {0xd1, 0x6e, 0x0c, 0x03, 0x50, 0x01, 0xe8, 0x10}, - {0xd1, 0x6e, 0x1d, 0x20, 0x0a, 0x19, 0x44, 0x10}, - {0xd1, 0x6e, 0x21, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x25, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x29, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x35, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x39, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x41, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x45, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x49, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x4d, 0x00, 0x00, 0x00, 0xed, 0x10}, - {0xd1, 0x6e, 0x51, 0x17, 0x4a, 0x2f, 0xc0, 0x10}, - {0xd1, 0x6e, 0x55, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x59, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x61, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x69, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x71, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x79, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x85, 0x00, 0x00, 0x00, 0x08, 0x10}, - {0xd1, 0x6e, 0x89, 0x01, 0xe8, 0x00, 0x01, 0x10}, - {0xa1, 0x6e, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x21, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x25, 0x00, 0x00, 0x00, 0x01, 0x10}, - {0xd1, 0x6e, 0x29, 0xe6, 0x00, 0xbd, 0x03, 0x10}, - {0xd1, 0x6e, 0x2d, 0x41, 0x38, 0x68, 0x40, 0x10}, - {0xd1, 0x6e, 0x31, 0x2b, 0x00, 0x36, 0x00, 0x10}, - {0xd1, 0x6e, 0x35, 0x30, 0x30, 0x08, 0x00, 0x10}, - {0xd1, 0x6e, 0x39, 0x00, 0x00, 0x33, 0x06, 0x10}, - {0xb1, 0x6e, 0x3d, 0x06, 0x02, 0x00, 0x00, 0x10}, - {} -}; -static const u8 po2030n_sensor_param1[][8] = { - {0xa1, 0x6e, 0x1a, 0x01, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */ - {0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10}, -/*param2*/ - {0xa1, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10}, -/*after start*/ - {0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ - {0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10}, - {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ - {0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10}, - {} -}; - -static const u8 soi768_sensor_init[][8] = { - {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */ - {DELAY, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 96ms */ - {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 soi768_sensor_param1[][8] = { - {0xa1, 0x21, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x01, 0x7f, 0x7f, 0x00, 0x00, 0x10}, -/* */ -/* {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, */ -/* {0xa1, 0x21, 0x2d, 0x25, 0x00, 0x00, 0x00, 0x10}, */ - {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, -/* {0xb1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, */ - {0xa1, 0x21, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x10}, -/* the next sequence should be used for auto gain */ - {0xa1, 0x21, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10}, - /* global gain ? : 07 - change with 0x15 at the end */ - {0xa1, 0x21, 0x10, 0x3f, 0x00, 0x00, 0x00, 0x10}, /* ???? : 063f */ - {0xa1, 0x21, 0x04, 0x06, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x2d, 0x00, 0x02, 0x00, 0x00, 0x10}, - /* exposure ? : 0200 - change with 0x1e at the end */ - {} -}; - -static const u8 sp80708_sensor_init[][8] = { - {0xa1, 0x18, 0x06, 0xf9, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x09, 0x1f, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x10, 0x40, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x12, 0x53, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x15, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x19, 0x18, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x1a, 0x10, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x1c, 0x28, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x1d, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x26, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x27, 0x1e, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x28, 0x5a, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x29, 0x28, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x2a, 0x78, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x2c, 0xf7, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x2d, 0x2d, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x2e, 0xd5, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x39, 0x42, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x3a, 0x67, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x3b, 0x87, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x3c, 0xa3, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x3d, 0xb0, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x3e, 0xbc, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x3f, 0xc8, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x40, 0xd4, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x41, 0xdf, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x42, 0xea, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x43, 0xf5, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x45, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x46, 0x60, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x47, 0x50, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x48, 0x30, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x49, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x4d, 0xae, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x4e, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x4f, 0x66, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x50, 0x1c, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x44, 0x10, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x4a, 0x30, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x51, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x52, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x53, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x54, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x55, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x56, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x57, 0xe0, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x58, 0xc0, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x59, 0xab, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x5a, 0xa0, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x5b, 0x99, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x5c, 0x90, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x5e, 0x24, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x61, 0x73, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x63, 0x42, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x64, 0x42, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x65, 0x42, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x66, 0x24, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x67, 0x24, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x68, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x2f, 0xc9, 0x00, 0x00, 0x00, 0x10}, - {} -}; -static const u8 sp80708_sensor_param1[][8] = { - {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x03, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x04, 0xa4, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x14, 0x3f, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x18, 0x5d, 0x80, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x18, 0x11, 0x40, 0x40, 0x00, 0x00, 0x10}, - {} -}; - -static const u8 (*sensor_init[])[8] = { -[SENSOR_ADCM1700] = adcm1700_sensor_init, -[SENSOR_GC0307] = gc0307_sensor_init, -[SENSOR_HV7131R] = hv7131r_sensor_init, -[SENSOR_MI0360] = mi0360_sensor_init, -[SENSOR_MI0360B] = mi0360b_sensor_init, -[SENSOR_MO4000] = mo4000_sensor_init, -[SENSOR_MT9V111] = mt9v111_sensor_init, -[SENSOR_OM6802] = om6802_sensor_init, -[SENSOR_OV7630] = ov7630_sensor_init, -[SENSOR_OV7648] = ov7648_sensor_init, -[SENSOR_OV7660] = ov7660_sensor_init, -[SENSOR_PO1030] = po1030_sensor_init, -[SENSOR_PO2030N] = po2030n_sensor_init, -[SENSOR_SOI768] = soi768_sensor_init, -[SENSOR_SP80708] = sp80708_sensor_init, -}; - -/* read bytes to gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - u16 value, int len) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); - return; - } -#endif - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, 0, - gspca_dev->usb_buf, len, - 500); - PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]); - if (ret < 0) { - err("reg_r err %d", ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_w1(struct gspca_dev *gspca_dev, - u16 value, - u8 data) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_USBO, "reg_w1 [%04x] = %02x", value, data); - gspca_dev->usb_buf[0] = data; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, - 0, - gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { - err("reg_w1 err %d", ret); - gspca_dev->usb_err = ret; - } -} -static void reg_w(struct gspca_dev *gspca_dev, - u16 value, - const u8 *buffer, - int len) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..", - value, buffer[0], buffer[1]); -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); - return; - } -#endif - memcpy(gspca_dev->usb_buf, buffer, len); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, 0, - gspca_dev->usb_buf, len, - 500); - if (ret < 0) { - err("reg_w err %d", ret); - gspca_dev->usb_err = ret; - } -} - -/* I2C write 1 byte */ -static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_USBO, "i2c_w1 [%02x] = %02x", reg, val); - switch (sd->sensor) { - case SENSOR_ADCM1700: - case SENSOR_OM6802: - case SENSOR_GC0307: /* i2c command = a0 (100 kHz) */ - gspca_dev->usb_buf[0] = 0x80 | (2 << 4); - break; - default: /* i2c command = a1 (400 kHz) */ - gspca_dev->usb_buf[0] = 0x81 | (2 << 4); - break; - } - gspca_dev->usb_buf[1] = sd->i2c_addr; - gspca_dev->usb_buf[2] = reg; - gspca_dev->usb_buf[3] = val; - gspca_dev->usb_buf[4] = 0; - gspca_dev->usb_buf[5] = 0; - gspca_dev->usb_buf[6] = 0; - gspca_dev->usb_buf[7] = 0x10; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 0x08, /* value = i2c */ - 0, - gspca_dev->usb_buf, 8, - 500); - if (ret < 0) { - err("i2c_w1 err %d", ret); - gspca_dev->usb_err = ret; - } -} - -/* I2C write 8 bytes */ -static void i2c_w8(struct gspca_dev *gspca_dev, - const u8 *buffer) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_USBO, "i2c_w8 [%02x] = %02x ..", - buffer[2], buffer[3]); - memcpy(gspca_dev->usb_buf, buffer, 8); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 0x08, 0, /* value, index */ - gspca_dev->usb_buf, 8, - 500); - msleep(2); - if (ret < 0) { - err("i2c_w8 err %d", ret); - gspca_dev->usb_err = ret; - } -} - -/* sensor read 'len' (1..5) bytes in gspca_dev->usb_buf */ -static void i2c_r(struct gspca_dev *gspca_dev, u8 reg, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 mode[8]; - - switch (sd->sensor) { - case SENSOR_ADCM1700: - case SENSOR_OM6802: - case SENSOR_GC0307: /* i2c command = a0 (100 kHz) */ - mode[0] = 0x80 | 0x10; - break; - default: /* i2c command = 91 (400 kHz) */ - mode[0] = 0x81 | 0x10; - break; - } - mode[1] = sd->i2c_addr; - mode[2] = reg; - mode[3] = 0; - mode[4] = 0; - mode[5] = 0; - mode[6] = 0; - mode[7] = 0x10; - i2c_w8(gspca_dev, mode); - msleep(2); - mode[0] = (mode[0] & 0x81) | (len << 4) | 0x02; - mode[2] = 0; - i2c_w8(gspca_dev, mode); - msleep(2); - reg_r(gspca_dev, 0x0a, 5); -} - -static void i2c_w_seq(struct gspca_dev *gspca_dev, - const u8 (*data)[8]) -{ - while ((*data)[0] != 0) { - if ((*data)[0] != DELAY) - i2c_w8(gspca_dev, *data); - else - msleep((*data)[1]); - data++; - } -} - -/* check the ID of the hv7131 sensor */ -/* this sequence is needed because it activates the sensor */ -static void hv7131r_probe(struct gspca_dev *gspca_dev) -{ - i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */ - msleep(10); - reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */ - msleep(10); - i2c_r(gspca_dev, 0, 5); /* read sensor id */ - if (gspca_dev->usb_buf[0] == 0x02 /* chip ID (02 is R) */ - && gspca_dev->usb_buf[1] == 0x09 - && gspca_dev->usb_buf[2] == 0x01) { - PDEBUG(D_PROBE, "Sensor HV7131R found"); - return; - } - warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x", - gspca_dev->usb_buf[0], gspca_dev->usb_buf[1], - gspca_dev->usb_buf[2]); -} - -static void mi0360_probe(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, j; - u16 val = 0; - static const u8 probe_tb[][4][8] = { - { /* mi0360 */ - {0xb0, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, - {0x90, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa2, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb0, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10} - }, - { /* mt9v111 */ - {0xb0, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10}, - {0x90, 0x5c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa2, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, - {} - }, - }; - - for (i = 0; i < ARRAY_SIZE(probe_tb); i++) { - reg_w1(gspca_dev, 0x17, 0x62); - reg_w1(gspca_dev, 0x01, 0x08); - for (j = 0; j < 3; j++) - i2c_w8(gspca_dev, probe_tb[i][j]); - msleep(2); - reg_r(gspca_dev, 0x0a, 5); - val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; - if (probe_tb[i][3][0] != 0) - i2c_w8(gspca_dev, probe_tb[i][3]); - reg_w1(gspca_dev, 0x01, 0x29); - reg_w1(gspca_dev, 0x17, 0x42); - if (val != 0xffff) - break; - } - if (gspca_dev->usb_err < 0) - return; - switch (val) { - case 0x8221: - PDEBUG(D_PROBE, "Sensor mi0360b"); - sd->sensor = SENSOR_MI0360B; - break; - case 0x823a: - PDEBUG(D_PROBE, "Sensor mt9v111"); - sd->sensor = SENSOR_MT9V111; - break; - case 0x8243: - PDEBUG(D_PROBE, "Sensor mi0360"); - break; - default: - PDEBUG(D_PROBE, "Unknown sensor %04x - forced to mi0360", val); - break; - } -} - -static void ov7630_probe(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 val; - - /* check ov76xx */ - reg_w1(gspca_dev, 0x17, 0x62); - reg_w1(gspca_dev, 0x01, 0x08); - sd->i2c_addr = 0x21; - i2c_r(gspca_dev, 0x0a, 2); - val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; - reg_w1(gspca_dev, 0x01, 0x29); - reg_w1(gspca_dev, 0x17, 0x42); - if (gspca_dev->usb_err < 0) - return; - if (val == 0x7628) { /* soi768 */ - sd->sensor = SENSOR_SOI768; -/*fixme: only valid for 0c45:613e?*/ - gspca_dev->cam.input_flags = - V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP; - PDEBUG(D_PROBE, "Sensor soi768"); - return; - } - PDEBUG(D_PROBE, "Sensor ov%04x", val); -} - -static void ov7648_probe(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 val; - - /* check ov76xx */ - reg_w1(gspca_dev, 0x17, 0x62); - reg_w1(gspca_dev, 0x01, 0x08); - sd->i2c_addr = 0x21; - i2c_r(gspca_dev, 0x0a, 2); - val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; - reg_w1(gspca_dev, 0x01, 0x29); - reg_w1(gspca_dev, 0x17, 0x42); - if ((val & 0xff00) == 0x7600) { /* ov76xx */ - PDEBUG(D_PROBE, "Sensor ov%04x", val); - return; - } - - /* check po1030 */ - reg_w1(gspca_dev, 0x17, 0x62); - reg_w1(gspca_dev, 0x01, 0x08); - sd->i2c_addr = 0x6e; - i2c_r(gspca_dev, 0x00, 2); - val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; - reg_w1(gspca_dev, 0x01, 0x29); - reg_w1(gspca_dev, 0x17, 0x42); - if (gspca_dev->usb_err < 0) - return; - if (val == 0x1030) { /* po1030 */ - PDEBUG(D_PROBE, "Sensor po1030"); - sd->sensor = SENSOR_PO1030; - return; - } - err("Unknown sensor %04x", val); -} - -/* 0c45:6142 sensor may be po2030n, gc0305 or gc0307 */ -static void po2030n_probe(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 val; - - /* check gc0307 */ - reg_w1(gspca_dev, 0x17, 0x62); - reg_w1(gspca_dev, 0x01, 0x08); - reg_w1(gspca_dev, 0x02, 0x22); - sd->i2c_addr = 0x21; - i2c_r(gspca_dev, 0x00, 1); - val = gspca_dev->usb_buf[4]; - reg_w1(gspca_dev, 0x01, 0x29); /* reset */ - reg_w1(gspca_dev, 0x17, 0x42); - if (val == 0x99) { /* gc0307 (?) */ - PDEBUG(D_PROBE, "Sensor gc0307"); - sd->sensor = SENSOR_GC0307; - return; - } - - /* check po2030n */ - reg_w1(gspca_dev, 0x17, 0x62); - reg_w1(gspca_dev, 0x01, 0x0a); - sd->i2c_addr = 0x6e; - i2c_r(gspca_dev, 0x00, 2); - val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; - reg_w1(gspca_dev, 0x01, 0x29); - reg_w1(gspca_dev, 0x17, 0x42); - if (gspca_dev->usb_err < 0) - return; - if (val == 0x2030) { - PDEBUG(D_PROBE, "Sensor po2030n"); -/* sd->sensor = SENSOR_PO2030N; */ - } else { - err("Unknown sensor ID %04x", val); - } -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - sd->bridge = id->driver_info >> 16; - sd->sensor = id->driver_info >> 8; - sd->flags = id->driver_info; - - cam = &gspca_dev->cam; - if (sd->sensor == SENSOR_ADCM1700) { - cam->cam_mode = cif_mode; - cam->nmodes = ARRAY_SIZE(cif_mode); - } else { - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - } - cam->npkt = 24; /* 24 packets per ISOC message */ - cam->ctrls = sd->ctrls; - - sd->ag_cnt = -1; - sd->quality = QUALITY_DEF; - - /* if USB 1.1, let some bandwidth for the audio device */ - if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) - gspca_dev->nbalt--; - - INIT_WORK(&sd->work, qual_upd); - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - const u8 *sn9c1xx; - u8 regGpio[] = { 0x29, 0x70 }; /* no audio */ - u8 regF1; - - /* setup a selector by bridge */ - reg_w1(gspca_dev, 0xf1, 0x01); - reg_r(gspca_dev, 0x00, 1); - reg_w1(gspca_dev, 0xf1, 0x00); - reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */ - regF1 = gspca_dev->usb_buf[0]; - if (gspca_dev->usb_err < 0) - return gspca_dev->usb_err; - PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1); - if (gspca_dev->audio) - regGpio[1] |= 0x04; /* with audio */ - switch (sd->bridge) { - case BRIDGE_SN9C102P: - case BRIDGE_SN9C105: - if (regF1 != 0x11) - return -ENODEV; - break; - default: -/* case BRIDGE_SN9C110: */ -/* case BRIDGE_SN9C120: */ - if (regF1 != 0x12) - return -ENODEV; - } - - switch (sd->sensor) { - case SENSOR_MI0360: - mi0360_probe(gspca_dev); - break; - case SENSOR_OV7630: - ov7630_probe(gspca_dev); - break; - case SENSOR_OV7648: - ov7648_probe(gspca_dev); - break; - case SENSOR_PO2030N: - po2030n_probe(gspca_dev); - break; - } - - switch (sd->bridge) { - case BRIDGE_SN9C102P: - reg_w1(gspca_dev, 0x02, regGpio[1]); - break; - default: - reg_w(gspca_dev, 0x01, regGpio, 2); - break; - } - - if (sd->sensor == SENSOR_OM6802) - sd->ctrls[SHARPNESS].def = 0x10; - - /* Note we do not disable the sensor clock here (power saving mode), - as that also disables the button on the cam. */ - reg_w1(gspca_dev, 0xf1, 0x00); - - /* set the i2c address */ - sn9c1xx = sn_tb[sd->sensor]; - sd->i2c_addr = sn9c1xx[9]; - - gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; - if (!(sd->flags & F_ILLUM)) - gspca_dev->ctrl_dis |= (1 << ILLUM); - - return gspca_dev->usb_err; -} - -static u32 setexposure(struct gspca_dev *gspca_dev, - u32 expo) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { - case SENSOR_GC0307: { - int a, b; - - /* expo = 0..255 -> a = 19..43 */ - a = 19 + expo * 25 / 256; - i2c_w1(gspca_dev, 0x68, a); - a -= 12; - b = a * a * 4; /* heuristic */ - i2c_w1(gspca_dev, 0x03, b >> 8); - i2c_w1(gspca_dev, 0x04, b); - break; - } - case SENSOR_HV7131R: { - u8 Expodoit[] = - { 0xc1, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x16 }; - - Expodoit[3] = expo >> 16; - Expodoit[4] = expo >> 8; - Expodoit[5] = expo; - i2c_w8(gspca_dev, Expodoit); - break; - } - case SENSOR_MI0360: - case SENSOR_MI0360B: { - u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */ - { 0xb1, 0x5d, 0x09, 0x00, 0x00, 0x00, 0x00, 0x16 }; - static const u8 doit[] = /* update sensor */ - { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 }; - static const u8 sensorgo[] = /* sensor on */ - { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 }; - - if (expo > 0x0635) - expo = 0x0635; - else if (expo < 0x0001) - expo = 0x0001; - expoMi[3] = expo >> 8; - expoMi[4] = expo; - i2c_w8(gspca_dev, expoMi); - i2c_w8(gspca_dev, doit); - i2c_w8(gspca_dev, sensorgo); - break; - } - case SENSOR_MO4000: { - u8 expoMof[] = - { 0xa1, 0x21, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x10 }; - u8 expoMo10[] = - { 0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10 }; - static const u8 gainMo[] = - { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d }; - - if (expo > 0x1fff) - expo = 0x1fff; - else if (expo < 0x0001) - expo = 0x0001; - expoMof[3] = (expo & 0x03fc) >> 2; - i2c_w8(gspca_dev, expoMof); - expoMo10[3] = ((expo & 0x1c00) >> 10) - | ((expo & 0x0003) << 4); - i2c_w8(gspca_dev, expoMo10); - i2c_w8(gspca_dev, gainMo); - PDEBUG(D_FRAM, "set exposure %d", - ((expoMo10[3] & 0x07) << 10) - | (expoMof[3] << 2) - | ((expoMo10[3] & 0x30) >> 4)); - break; - } - case SENSOR_MT9V111: { - u8 expo_c1[] = - { 0xb1, 0x5c, 0x09, 0x00, 0x00, 0x00, 0x00, 0x10 }; - - if (expo > 0x0390) - expo = 0x0390; - else if (expo < 0x0060) - expo = 0x0060; - expo_c1[3] = expo >> 8; - expo_c1[4] = expo; - i2c_w8(gspca_dev, expo_c1); - break; - } - case SENSOR_OM6802: { - u8 gainOm[] = - { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 }; - /* preset AGC - works when AutoExpo = off */ - - if (expo > 0x03ff) - expo = 0x03ff; - if (expo < 0x0001) - expo = 0x0001; - gainOm[3] = expo >> 2; - i2c_w8(gspca_dev, gainOm); - reg_w1(gspca_dev, 0x96, expo >> 5); - PDEBUG(D_FRAM, "set exposure %d", gainOm[3]); - break; - } - } - return expo; -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - unsigned int expo; - int brightness; - u8 k2; - - brightness = sd->ctrls[BRIGHTNESS].val; - k2 = (brightness - 0x80) >> 2; - switch (sd->sensor) { - case SENSOR_ADCM1700: - if (k2 > 0x1f) - k2 = 0; /* only positive Y offset */ - break; - case SENSOR_HV7131R: - expo = brightness << 12; - if (expo > 0x002dc6c0) - expo = 0x002dc6c0; - else if (expo < 0x02a0) - expo = 0x02a0; - sd->exposure = setexposure(gspca_dev, expo); - break; - case SENSOR_MI0360: - case SENSOR_MO4000: - expo = brightness << 4; - sd->exposure = setexposure(gspca_dev, expo); - break; - case SENSOR_MI0360B: - expo = brightness << 2; - sd->exposure = setexposure(gspca_dev, expo); - break; - case SENSOR_GC0307: - expo = brightness; - sd->exposure = setexposure(gspca_dev, expo); - return; /* don't set the Y offset */ - case SENSOR_MT9V111: - expo = brightness << 2; - sd->exposure = setexposure(gspca_dev, expo); - return; /* don't set the Y offset */ - case SENSOR_OM6802: - expo = brightness << 2; - sd->exposure = setexposure(gspca_dev, expo); - k2 = brightness >> 3; - break; - } - - reg_w1(gspca_dev, 0x96, k2); /* color matrix Y offset */ -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 k2; - u8 contrast[6]; - - k2 = sd->ctrls[CONTRAST].val * 0x30 / (CONTRAST_MAX + 1) - + 0x10; /* 10..40 */ - contrast[0] = (k2 + 1) / 2; /* red */ - contrast[1] = 0; - contrast[2] = k2; /* green */ - contrast[3] = 0; - contrast[4] = (k2 + 1) / 5; /* blue */ - contrast[5] = 0; - reg_w(gspca_dev, 0x84, contrast, sizeof contrast); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, v, colors; - const s16 *uv; - u8 reg8a[12]; /* U & V gains */ - static const s16 uv_com[6] = { /* same as reg84 in signed decimal */ - -24, -38, 64, /* UR UG UB */ - 62, -51, -9 /* VR VG VB */ - }; - static const s16 uv_mi0360b[6] = { - -20, -38, 64, /* UR UG UB */ - 60, -51, -9 /* VR VG VB */ - }; - - colors = sd->ctrls[COLORS].val; - if (sd->sensor == SENSOR_MI0360B) - uv = uv_mi0360b; - else - uv = uv_com; - for (i = 0; i < 6; i++) { - v = uv[i] * colors / COLORS_DEF; - reg8a[i * 2] = v; - reg8a[i * 2 + 1] = (v >> 8) & 0x0f; - } - reg_w(gspca_dev, 0x8a, reg8a, sizeof reg8a); -} - -static void setredblue(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val); -/* reg_w1(gspca_dev, 0x07, 32); */ - reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val); -} - -static void setgamma(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, val; - u8 gamma[17]; - const u8 *gamma_base; - static const u8 delta[17] = { - 0x00, 0x14, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1a, - 0x18, 0x13, 0x10, 0x0e, 0x08, 0x07, 0x04, 0x02, 0x00 - }; - - switch (sd->sensor) { - case SENSOR_ADCM1700: - gamma_base = gamma_spec_0; - break; - case SENSOR_HV7131R: - case SENSOR_MI0360B: - case SENSOR_MT9V111: - gamma_base = gamma_spec_1; - break; - case SENSOR_GC0307: - gamma_base = gamma_spec_2; - break; - case SENSOR_SP80708: - gamma_base = gamma_spec_3; - break; - default: - gamma_base = gamma_def; - break; - } - - val = sd->ctrls[GAMMA].val; - for (i = 0; i < sizeof gamma; i++) - gamma[i] = gamma_base[i] - + delta[i] * (val - GAMMA_DEF) / 32; - reg_w(gspca_dev, 0x20, gamma, sizeof gamma); -} - -static void setautogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) - return; - switch (sd->sensor) { - case SENSOR_OV7630: - case SENSOR_OV7648: { - u8 comb; - - if (sd->sensor == SENSOR_OV7630) - comb = 0xc0; - else - comb = 0xa0; - if (sd->ctrls[AUTOGAIN].val) - comb |= 0x03; - i2c_w1(&sd->gspca_dev, 0x13, comb); - return; - } - } - if (sd->ctrls[AUTOGAIN].val) - sd->ag_cnt = AG_CNT_START; - else - sd->ag_cnt = -1; -} - -static void sethvflip(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 comn; - - switch (sd->sensor) { - case SENSOR_HV7131R: - comn = 0x18; /* clkdiv = 1, ablcen = 1 */ - if (sd->ctrls[VFLIP].val) - comn |= 0x01; - i2c_w1(gspca_dev, 0x01, comn); /* sctra */ - break; - case SENSOR_OV7630: - comn = 0x02; - if (!sd->ctrls[VFLIP].val) - comn |= 0x80; - i2c_w1(gspca_dev, 0x75, comn); - break; - case SENSOR_OV7648: - comn = 0x06; - if (sd->ctrls[VFLIP].val) - comn |= 0x80; - i2c_w1(gspca_dev, 0x75, comn); - break; - case SENSOR_PO2030N: - /* Reg. 0x1E: Timing Generator Control Register 2 (Tgcontrol2) - * (reset value: 0x0A) - * bit7: HM: Horizontal Mirror: 0: disable, 1: enable - * bit6: VM: Vertical Mirror: 0: disable, 1: enable - * bit5: ST: Shutter Selection: 0: electrical, 1: mechanical - * bit4: FT: Single Frame Transfer: 0: disable, 1: enable - * bit3-0: X - */ - comn = 0x0a; - if (sd->ctrls[HFLIP].val) - comn |= 0x80; - if (sd->ctrls[VFLIP].val) - comn |= 0x40; - i2c_w1(&sd->gspca_dev, 0x1e, comn); - break; - } -} - -static void setsharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w1(gspca_dev, 0x99, sd->ctrls[SHARPNESS].val); -} - -static void setillum(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << ILLUM)) - return; - switch (sd->sensor) { - case SENSOR_ADCM1700: - reg_w1(gspca_dev, 0x02, /* gpio */ - sd->ctrls[ILLUM].val ? 0x64 : 0x60); - break; - case SENSOR_MT9V111: - reg_w1(gspca_dev, 0x02, - sd->ctrls[ILLUM].val ? 0x77 : 0x74); -/* should have been: */ -/* 0x55 : 0x54); * 370i */ -/* 0x66 : 0x64); * Clip */ - break; - } -} - -static void setfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << FREQ)) - return; - if (sd->sensor == SENSOR_OV7660) { - u8 com8; - - com8 = 0xdf; /* auto gain/wb/expo */ - switch (sd->ctrls[FREQ].val) { - case 0: /* Banding filter disabled */ - i2c_w1(gspca_dev, 0x13, com8 | 0x20); - break; - case 1: /* 50 hz */ - i2c_w1(gspca_dev, 0x13, com8); - i2c_w1(gspca_dev, 0x3b, 0x0a); - break; - case 2: /* 60 hz */ - i2c_w1(gspca_dev, 0x13, com8); - i2c_w1(gspca_dev, 0x3b, 0x02); - break; - } - } else { - u8 reg2a = 0, reg2b = 0, reg2d = 0; - - /* Get reg2a / reg2d base values */ - switch (sd->sensor) { - case SENSOR_OV7630: - reg2a = 0x08; - reg2d = 0x01; - break; - case SENSOR_OV7648: - reg2a = 0x11; - reg2d = 0x81; - break; - } - - switch (sd->ctrls[FREQ].val) { - case 0: /* Banding filter disabled */ - break; - case 1: /* 50 hz (filter on and framerate adj) */ - reg2a |= 0x80; - reg2b = 0xac; - reg2d |= 0x04; - break; - case 2: /* 60 hz (filter on, no framerate adj) */ - reg2a |= 0x80; - reg2d |= 0x04; - break; - } - i2c_w1(gspca_dev, 0x2a, reg2a); - i2c_w1(gspca_dev, 0x2b, reg2b); - i2c_w1(gspca_dev, 0x2d, reg2d); - } -} - -static void setjpegqual(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - jpeg_set_qual(sd->jpeg_hdr, sd->quality); -#if USB_BUF_SZ < 64 -#error "No room enough in usb_buf for quantization table" -#endif - memcpy(gspca_dev->usb_buf, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 0x0100, 0, - gspca_dev->usb_buf, 64, - 500); - memcpy(gspca_dev->usb_buf, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - 0x0140, 0, - gspca_dev->usb_buf, 64, - 500); - - sd->reg18 ^= 0x40; - reg_w1(gspca_dev, 0x18, sd->reg18); -} - -/* JPEG quality update */ -/* This function is executed from a work queue. */ -static void qual_upd(struct work_struct *work) -{ - struct sd *sd = container_of(work, struct sd, work); - struct gspca_dev *gspca_dev = &sd->gspca_dev; - - mutex_lock(&gspca_dev->usb_lock); - PDEBUG(D_STREAM, "qual_upd %d%%", sd->quality); - setjpegqual(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - u8 reg01, reg17; - u8 reg0102[2]; - const u8 *sn9c1xx; - const u8 (*init)[8]; - const u8 *reg9a; - int mode; - static const u8 reg9a_def[] = - {0x00, 0x40, 0x20, 0x00, 0x00, 0x00}; - static const u8 reg9a_spec[] = - {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; - static const u8 regd4[] = {0x60, 0x00, 0x00}; - static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; - static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; - static const u8 CA_adcm1700[] = - { 0x14, 0xec, 0x0a, 0xf6 }; - static const u8 CA_po2030n[] = - { 0x1e, 0xe2, 0x14, 0xec }; - static const u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */ - static const u8 CE_gc0307[] = - { 0x32, 0xce, 0x2d, 0xd3 }; - static const u8 CE_ov76xx[] = - { 0x32, 0xdd, 0x32, 0xdd }; - static const u8 CE_po2030n[] = - { 0x14, 0xe7, 0x1e, 0xdd }; - - /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x21); /* JPEG 422 */ - - /* initialize the bridge */ - sn9c1xx = sn_tb[sd->sensor]; - - /* sensor clock already enabled in sd_init */ - /* reg_w1(gspca_dev, 0xf1, 0x00); */ - reg01 = sn9c1xx[1]; - if (sd->flags & F_PDN_INV) - reg01 ^= S_PDN_INV; /* power down inverted */ - reg_w1(gspca_dev, 0x01, reg01); - - /* configure gpio */ - reg0102[0] = reg01; - reg0102[1] = sn9c1xx[2]; - if (gspca_dev->audio) - reg0102[1] |= 0x04; /* keep the audio connection */ - reg_w(gspca_dev, 0x01, reg0102, 2); - reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2); - reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); - switch (sd->sensor) { - case SENSOR_GC0307: - case SENSOR_OV7660: - case SENSOR_PO1030: - case SENSOR_PO2030N: - case SENSOR_SOI768: - case SENSOR_SP80708: - reg9a = reg9a_spec; - break; - default: - reg9a = reg9a_def; - break; - } - reg_w(gspca_dev, 0x9a, reg9a, 6); - - reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); - - reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); - - reg17 = sn9c1xx[0x17]; - switch (sd->sensor) { - case SENSOR_GC0307: - msleep(50); /*fixme: is it useful? */ - break; - case SENSOR_OM6802: - msleep(10); - reg_w1(gspca_dev, 0x02, 0x73); - reg17 |= SEN_CLK_EN; - reg_w1(gspca_dev, 0x17, reg17); - reg_w1(gspca_dev, 0x01, 0x22); - msleep(100); - reg01 = SCL_SEL_OD | S_PDN_INV; - reg17 &= MCK_SIZE_MASK; - reg17 |= 0x04; /* clock / 4 */ - break; - } - reg01 |= SYS_SEL_48M; - reg_w1(gspca_dev, 0x01, reg01); - reg17 |= SEN_CLK_EN; - reg_w1(gspca_dev, 0x17, reg17); - reg01 &= ~S_PWR_DN; /* sensor power on */ - reg_w1(gspca_dev, 0x01, reg01); - reg01 &= ~SYS_SEL_48M; - reg_w1(gspca_dev, 0x01, reg01); - - switch (sd->sensor) { - case SENSOR_HV7131R: - hv7131r_probe(gspca_dev); /*fixme: is it useful? */ - break; - case SENSOR_OM6802: - msleep(10); - reg_w1(gspca_dev, 0x01, reg01); - i2c_w8(gspca_dev, om6802_init0[0]); - i2c_w8(gspca_dev, om6802_init0[1]); - msleep(15); - reg_w1(gspca_dev, 0x02, 0x71); - msleep(150); - break; - case SENSOR_SP80708: - msleep(100); - reg_w1(gspca_dev, 0x02, 0x62); - break; - } - - /* initialize the sensor */ - i2c_w_seq(gspca_dev, sensor_init[sd->sensor]); - - reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]); - reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]); - reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]); - reg_w1(gspca_dev, 0x13, sn9c1xx[0x13]); - reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); - if (sd->sensor == SENSOR_ADCM1700) { - reg_w1(gspca_dev, 0xd2, 0x3a); /* AE_H_SIZE = 116 */ - reg_w1(gspca_dev, 0xd3, 0x30); /* AE_V_SIZE = 96 */ - } else { - reg_w1(gspca_dev, 0xd2, 0x6a); /* AE_H_SIZE = 212 */ - reg_w1(gspca_dev, 0xd3, 0x50); /* AE_V_SIZE = 160 */ - } - reg_w1(gspca_dev, 0xc6, 0x00); - reg_w1(gspca_dev, 0xc7, 0x00); - if (sd->sensor == SENSOR_ADCM1700) { - reg_w1(gspca_dev, 0xc8, 0x2c); /* AW_H_STOP = 352 */ - reg_w1(gspca_dev, 0xc9, 0x24); /* AW_V_STOP = 288 */ - } else { - reg_w1(gspca_dev, 0xc8, 0x50); /* AW_H_STOP = 640 */ - reg_w1(gspca_dev, 0xc9, 0x3c); /* AW_V_STOP = 480 */ - } - reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); - switch (sd->sensor) { - case SENSOR_OM6802: -/* case SENSOR_OV7648: * fixme: sometimes */ - break; - default: - reg17 |= DEF_EN; - break; - } - reg_w1(gspca_dev, 0x17, reg17); - - reg_w1(gspca_dev, 0x05, 0x00); /* red */ - reg_w1(gspca_dev, 0x07, 0x00); /* green */ - reg_w1(gspca_dev, 0x06, 0x00); /* blue */ - reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]); - - setgamma(gspca_dev); - -/*fixme: 8 times with all zeroes and 1 or 2 times with normal values */ - for (i = 0; i < 8; i++) - reg_w(gspca_dev, 0x84, reg84, sizeof reg84); - switch (sd->sensor) { - case SENSOR_ADCM1700: - case SENSOR_OV7660: - case SENSOR_SP80708: - reg_w1(gspca_dev, 0x9a, 0x05); - break; - case SENSOR_GC0307: - case SENSOR_MT9V111: - case SENSOR_MI0360B: - reg_w1(gspca_dev, 0x9a, 0x07); - break; - case SENSOR_OV7630: - case SENSOR_OV7648: - reg_w1(gspca_dev, 0x9a, 0x0a); - break; - case SENSOR_PO2030N: - case SENSOR_SOI768: - reg_w1(gspca_dev, 0x9a, 0x06); - break; - default: - reg_w1(gspca_dev, 0x9a, 0x08); - break; - } - setsharpness(gspca_dev); - - reg_w(gspca_dev, 0x84, reg84, sizeof reg84); - reg_w1(gspca_dev, 0x05, 0x20); /* red */ - reg_w1(gspca_dev, 0x07, 0x20); /* green */ - reg_w1(gspca_dev, 0x06, 0x20); /* blue */ - - init = NULL; - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - reg01 |= SYS_SEL_48M | V_TX_EN; - reg17 &= ~MCK_SIZE_MASK; - reg17 |= 0x02; /* clock / 2 */ - switch (sd->sensor) { - case SENSOR_ADCM1700: - init = adcm1700_sensor_param1; - break; - case SENSOR_GC0307: - init = gc0307_sensor_param1; - break; - case SENSOR_HV7131R: - case SENSOR_MI0360: - if (mode) - reg01 |= SYS_SEL_48M; /* 320x240: clk 48Mhz */ - else - reg01 &= ~SYS_SEL_48M; /* 640x480: clk 24Mhz */ - reg17 &= ~MCK_SIZE_MASK; - reg17 |= 0x01; /* clock / 1 */ - break; - case SENSOR_MI0360B: - init = mi0360b_sensor_param1; - break; - case SENSOR_MO4000: - if (mode) { /* if 320x240 */ - reg01 &= ~SYS_SEL_48M; /* clk 24Mz */ - reg17 &= ~MCK_SIZE_MASK; - reg17 |= 0x01; /* clock / 1 */ - } - break; - case SENSOR_MT9V111: - init = mt9v111_sensor_param1; - break; - case SENSOR_OM6802: - init = om6802_sensor_param1; - if (!mode) { /* if 640x480 */ - reg17 &= ~MCK_SIZE_MASK; - reg17 |= 0x04; /* clock / 4 */ - } - break; - case SENSOR_OV7630: - init = ov7630_sensor_param1; - break; - case SENSOR_OV7648: - init = ov7648_sensor_param1; - reg17 &= ~MCK_SIZE_MASK; - reg17 |= 0x01; /* clock / 1 */ - break; - case SENSOR_OV7660: - init = ov7660_sensor_param1; - break; - case SENSOR_PO1030: - init = po1030_sensor_param1; - break; - case SENSOR_PO2030N: - init = po2030n_sensor_param1; - break; - case SENSOR_SOI768: - init = soi768_sensor_param1; - break; - case SENSOR_SP80708: - init = sp80708_sensor_param1; - break; - } - - /* more sensor initialization - param1 */ - if (init != NULL) { - i2c_w_seq(gspca_dev, init); -/* init = NULL; */ - } - - reg_w(gspca_dev, 0xc0, C0, 6); - switch (sd->sensor) { - case SENSOR_ADCM1700: - case SENSOR_GC0307: - case SENSOR_SOI768: - reg_w(gspca_dev, 0xca, CA_adcm1700, 4); - break; - case SENSOR_PO2030N: - reg_w(gspca_dev, 0xca, CA_po2030n, 4); - break; - default: - reg_w(gspca_dev, 0xca, CA, 4); - break; - } - switch (sd->sensor) { - case SENSOR_ADCM1700: - case SENSOR_OV7630: - case SENSOR_OV7648: - case SENSOR_OV7660: - case SENSOR_SOI768: - reg_w(gspca_dev, 0xce, CE_ov76xx, 4); - break; - case SENSOR_GC0307: - reg_w(gspca_dev, 0xce, CE_gc0307, 4); - break; - case SENSOR_PO2030N: - reg_w(gspca_dev, 0xce, CE_po2030n, 4); - break; - default: - reg_w(gspca_dev, 0xce, CE, 4); - /* ?? {0x1e, 0xdd, 0x2d, 0xe7} */ - break; - } - - /* here change size mode 0 -> VGA; 1 -> CIF */ - sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40; - reg_w1(gspca_dev, 0x18, sd->reg18); - setjpegqual(gspca_dev); - - reg_w1(gspca_dev, 0x17, reg17); - reg_w1(gspca_dev, 0x01, reg01); - sd->reg01 = reg01; - sd->reg17 = reg17; - - sethvflip(gspca_dev); - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setcolors(gspca_dev); - setautogain(gspca_dev); - setfreq(gspca_dev); - - sd->pktsz = sd->npkt = 0; - sd->nchg = sd->short_mark = 0; - sd->work_thread = create_singlethread_workqueue(MODULE_NAME); - - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - static const u8 stophv7131[] = - { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 }; - static const u8 stopmi0360[] = - { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 }; - static const u8 stopov7648[] = - { 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 }; - static const u8 stopsoi768[] = - { 0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10 }; - u8 reg01; - u8 reg17; - - reg01 = sd->reg01; - reg17 = sd->reg17 & ~SEN_CLK_EN; - switch (sd->sensor) { - case SENSOR_ADCM1700: - case SENSOR_GC0307: - case SENSOR_PO2030N: - case SENSOR_SP80708: - reg01 |= LED; - reg_w1(gspca_dev, 0x01, reg01); - reg01 &= ~(LED | V_TX_EN); - reg_w1(gspca_dev, 0x01, reg01); -/* reg_w1(gspca_dev, 0x02, 0x??); * LED off ? */ - break; - case SENSOR_HV7131R: - reg01 &= ~V_TX_EN; - reg_w1(gspca_dev, 0x01, reg01); - i2c_w8(gspca_dev, stophv7131); - break; - case SENSOR_MI0360: - case SENSOR_MI0360B: - reg01 &= ~V_TX_EN; - reg_w1(gspca_dev, 0x01, reg01); -/* reg_w1(gspca_dev, 0x02, 0x40); * LED off ? */ - i2c_w8(gspca_dev, stopmi0360); - break; - case SENSOR_MT9V111: - case SENSOR_OM6802: - case SENSOR_PO1030: - reg01 &= ~V_TX_EN; - reg_w1(gspca_dev, 0x01, reg01); - break; - case SENSOR_OV7630: - case SENSOR_OV7648: - reg01 &= ~V_TX_EN; - reg_w1(gspca_dev, 0x01, reg01); - i2c_w8(gspca_dev, stopov7648); - break; - case SENSOR_OV7660: - reg01 &= ~V_TX_EN; - reg_w1(gspca_dev, 0x01, reg01); - break; - case SENSOR_SOI768: - i2c_w8(gspca_dev, stopsoi768); - break; - } - - reg01 |= SCL_SEL_OD; - reg_w1(gspca_dev, 0x01, reg01); - reg01 |= S_PWR_DN; /* sensor power down */ - reg_w1(gspca_dev, 0x01, reg01); - reg_w1(gspca_dev, 0x17, reg17); - reg01 &= ~SYS_SEL_48M; /* clock 24MHz */ - reg_w1(gspca_dev, 0x01, reg01); - reg01 |= LED; - reg_w1(gspca_dev, 0x01, reg01); - /* Don't disable sensor clock as that disables the button on the cam */ - /* reg_w1(gspca_dev, 0xf1, 0x01); */ -} - -/* called on streamoff with alt==0 and on disconnect */ -/* the usb_lock is held at entry - restore on exit */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->work_thread != NULL) { - mutex_unlock(&gspca_dev->usb_lock); - destroy_workqueue(sd->work_thread); - mutex_lock(&gspca_dev->usb_lock); - sd->work_thread = NULL; - } -} - -static void do_autogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int delta; - int expotimes; - u8 luma_mean = 130; - u8 luma_delta = 20; - - /* Thanks S., without your advice, autobright should not work :) */ - if (sd->ag_cnt < 0) - return; - if (--sd->ag_cnt >= 0) - return; - sd->ag_cnt = AG_CNT_START; - - delta = atomic_read(&sd->avg_lum); - PDEBUG(D_FRAM, "mean lum %d", delta); - if (delta < luma_mean - luma_delta || - delta > luma_mean + luma_delta) { - switch (sd->sensor) { - case SENSOR_GC0307: - expotimes = sd->exposure; - expotimes += (luma_mean - delta) >> 6; - if (expotimes < 0) - expotimes = 0; - sd->exposure = setexposure(gspca_dev, - (unsigned int) expotimes); - break; - case SENSOR_HV7131R: - expotimes = sd->exposure >> 8; - expotimes += (luma_mean - delta) >> 4; - if (expotimes < 0) - expotimes = 0; - sd->exposure = setexposure(gspca_dev, - (unsigned int) (expotimes << 8)); - break; - case SENSOR_OM6802: - case SENSOR_MT9V111: - expotimes = sd->exposure; - expotimes += (luma_mean - delta) >> 2; - if (expotimes < 0) - expotimes = 0; - sd->exposure = setexposure(gspca_dev, - (unsigned int) expotimes); - setredblue(gspca_dev); - break; - default: -/* case SENSOR_MO4000: */ -/* case SENSOR_MI0360: */ -/* case SENSOR_MI0360B: */ - expotimes = sd->exposure; - expotimes += (luma_mean - delta) >> 6; - if (expotimes < 0) - expotimes = 0; - sd->exposure = setexposure(gspca_dev, - (unsigned int) expotimes); - setredblue(gspca_dev); - break; - } - } -} - -/* set the average luminosity from an isoc marker */ -static void set_lum(struct sd *sd, - u8 *data) -{ - int avg_lum; - - /* w0 w1 w2 - * w3 w4 w5 - * w6 w7 w8 - */ - avg_lum = (data[27] << 8) + data[28] /* w3 */ - - + (data[31] << 8) + data[32] /* w5 */ - - + (data[23] << 8) + data[24] /* w1 */ - - + (data[35] << 8) + data[36] /* w7 */ - - + (data[29] << 10) + (data[30] << 2); /* w4 * 4 */ - avg_lum >>= 10; - atomic_set(&sd->avg_lum, avg_lum); -} - -/* scan the URB packets */ -/* This function is run at interrupt level. */ -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, new_qual; - - /* - * A frame ends on the marker - * ff ff 00 c4 c4 96 .. - * which is 62 bytes long and is followed by various information - * including statuses and luminosity. - * - * A marker may be splitted on two packets. - * - * The 6th byte of a marker contains the bits: - * 0x08: USB full - * 0xc0: frame sequence - * When the bit 'USB full' is set, the frame must be discarded; - * this is also the case when the 2 bytes before the marker are - * not the JPEG end of frame ('ff d9'). - */ - -/*fixme: assumption about the following code: - * - there can be only one marker in a packet - */ - - /* skip the remaining bytes of a short marker */ - i = sd->short_mark; - if (i != 0) { - sd->short_mark = 0; - if (i < 0 /* if 'ff' at end of previous packet */ - && data[0] == 0xff - && data[1] == 0x00) - goto marker_found; - if (data[0] == 0xff && data[1] == 0xff) { - i = 0; - goto marker_found; - } - len -= i; - if (len <= 0) - return; - data += i; - } - - /* count the packets and their size */ - sd->npkt++; - sd->pktsz += len; - - /* search backwards if there is a marker in the packet */ - for (i = len - 1; --i >= 0; ) { - if (data[i] != 0xff) { - i--; - continue; - } - if (data[i + 1] == 0xff) { - - /* (there may be 'ff ff' inside a marker) */ - if (i + 2 >= len || data[i + 2] == 0x00) - goto marker_found; - } - } - - /* no marker found */ - /* add the JPEG header if first fragment */ - if (data[len - 1] == 0xff) - sd->short_mark = -1; - if (gspca_dev->last_packet_type == LAST_PACKET) - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - return; - - /* marker found */ - /* if some error, discard the frame and decrease the quality */ -marker_found: - new_qual = 0; - if (i > 2) { - if (data[i - 2] != 0xff || data[i - 1] != 0xd9) { - gspca_dev->last_packet_type = DISCARD_PACKET; - new_qual = -3; - } - } else if (i + 6 < len) { - if (data[i + 6] & 0x08) { - gspca_dev->last_packet_type = DISCARD_PACKET; - new_qual = -5; - } - } - - gspca_frame_add(gspca_dev, LAST_PACKET, data, i); - - /* compute the filling rate and a new JPEG quality */ - if (new_qual == 0) { - int r; - - r = (sd->pktsz * 100) / - (sd->npkt * - gspca_dev->urb[0]->iso_frame_desc[0].length); - if (r >= 85) - new_qual = -3; - else if (r < 75) - new_qual = 2; - } - if (new_qual != 0) { - sd->nchg += new_qual; - if (sd->nchg < -6 || sd->nchg >= 12) { - sd->nchg = 0; - new_qual += sd->quality; - if (new_qual < QUALITY_MIN) - new_qual = QUALITY_MIN; - else if (new_qual > QUALITY_MAX) - new_qual = QUALITY_MAX; - if (new_qual != sd->quality) { - sd->quality = new_qual; - queue_work(sd->work_thread, &sd->work); - } - } - } else { - sd->nchg = 0; - } - sd->pktsz = sd->npkt = 0; - - /* if the marker is smaller than 62 bytes, - * memorize the number of bytes to skip in the next packet */ - if (i + 62 > len) { /* no more usable data */ - sd->short_mark = i + 62 - len; - return; - } - if (sd->ag_cnt >= 0) - set_lum(sd, data + i); - - /* if more data, start a new frame */ - i += 62; - if (i < len) { - data += i; - len -= i; - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - } -} - -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; - return 0; -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - } - return -EINVAL; -} - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* interrupt packet data */ - int len) /* interrupt packet length */ -{ - int ret = -EINVAL; - - if (len == 1 && data[0] == 1) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); - input_sync(gspca_dev->input_dev); - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - ret = 0; - } - - return ret; -} -#endif - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = NCTRLS, - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = do_autogain, - .get_jcomp = sd_get_jcomp, - .querymenu = sd_querymenu, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -#endif -}; - -/* -- module initialisation -- */ -#define BS(bridge, sensor) \ - .driver_info = (BRIDGE_ ## bridge << 16) \ - | (SENSOR_ ## sensor << 8) -#define BSF(bridge, sensor, flags) \ - .driver_info = (BRIDGE_ ## bridge << 16) \ - | (SENSOR_ ## sensor << 8) \ - | (flags) -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)}, - {USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)}, - {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, F_PDN_INV)}, - {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, F_PDN_INV)}, - {USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)}, - {USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)}, - {USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)}, - {USB_DEVICE(0x06f8, 0x3004), BS(SN9C105, OV7660)}, - {USB_DEVICE(0x06f8, 0x3008), BS(SN9C105, OV7660)}, -/* {USB_DEVICE(0x0c45, 0x603a), BS(SN9C102P, OV7648)}, */ - {USB_DEVICE(0x0c45, 0x6040), BS(SN9C102P, HV7131R)}, -/* {USB_DEVICE(0x0c45, 0x607a), BS(SN9C102P, OV7648)}, */ -/* {USB_DEVICE(0x0c45, 0x607b), BS(SN9C102P, OV7660)}, */ - {USB_DEVICE(0x0c45, 0x607c), BS(SN9C102P, HV7131R)}, -/* {USB_DEVICE(0x0c45, 0x607e), BS(SN9C102P, OV7630)}, */ - {USB_DEVICE(0x0c45, 0x60c0), BSF(SN9C105, MI0360, F_ILLUM)}, - /* or MT9V111 */ -/* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */ -/* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */ -/* {USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */ - {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)}, - {USB_DEVICE(0x0c45, 0x60ec), BS(SN9C105, MO4000)}, -/* {USB_DEVICE(0x0c45, 0x60ef), BS(SN9C105, ICM105C)}, */ -/* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */ -/* {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */ - {USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)}, - {USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)}, - {USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)}, - {USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)}, /*sn9c128*/ - {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)}, /* /GC0305*/ -/* {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */ - {USB_DEVICE(0x0c45, 0x610a), BS(SN9C120, OV7648)}, /*sn9c128*/ - {USB_DEVICE(0x0c45, 0x610b), BS(SN9C120, OV7660)}, /*sn9c128*/ - {USB_DEVICE(0x0c45, 0x610c), BS(SN9C120, HV7131R)}, /*sn9c128*/ - {USB_DEVICE(0x0c45, 0x610e), BS(SN9C120, OV7630)}, /*sn9c128*/ -/* {USB_DEVICE(0x0c45, 0x610f), BS(SN9C120, S5K53BEB)}, */ -/* {USB_DEVICE(0x0c45, 0x6122), BS(SN9C110, ICM105C)}, */ -/* {USB_DEVICE(0x0c45, 0x6123), BS(SN9C110, SanyoCCD)}, */ - {USB_DEVICE(0x0c45, 0x6128), BS(SN9C120, OM6802)}, /*sn9c325?*/ -/*bw600.inf:*/ - {USB_DEVICE(0x0c45, 0x612a), BS(SN9C120, OV7648)}, /*sn9c325?*/ - {USB_DEVICE(0x0c45, 0x612b), BS(SN9C110, ADCM1700)}, - {USB_DEVICE(0x0c45, 0x612c), BS(SN9C110, MO4000)}, - {USB_DEVICE(0x0c45, 0x612e), BS(SN9C110, OV7630)}, -/* {USB_DEVICE(0x0c45, 0x612f), BS(SN9C110, ICM105C)}, */ - {USB_DEVICE(0x0c45, 0x6130), BS(SN9C120, MI0360)}, - /* or MT9V111 / MI0360B */ -/* {USB_DEVICE(0x0c45, 0x6132), BS(SN9C120, OV7670)}, */ - {USB_DEVICE(0x0c45, 0x6138), BS(SN9C120, MO4000)}, - {USB_DEVICE(0x0c45, 0x613a), BS(SN9C120, OV7648)}, - {USB_DEVICE(0x0c45, 0x613b), BS(SN9C120, OV7660)}, - {USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)}, - {USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)}, - {USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)}, /*sn9c120b*/ - /* or GC0305 / GC0307 */ - {USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/ - {USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/ - {USB_DEVICE(0x0c45, 0x614a), BSF(SN9C120, ADCM1700, F_ILLUM)}, -/* {USB_DEVICE(0x0c45, 0x614c), BS(SN9C120, GC0306)}, */ /*sn9c120b*/ - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca1528.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca1528.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca1528.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca1528.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,598 +0,0 @@ -/* - * spca1528 subdriver - * - * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr) - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "spca1528" - -#include "gspca.h" -#include "jpeg.h" - -MODULE_AUTHOR("Jean-Francois Moine "); -MODULE_DESCRIPTION("SPCA1528 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - u8 brightness; - u8 contrast; - u8 hue; - u8 color; - u8 sharpness; - - u8 pkt_seq; - - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 128 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 8, - .step = 1, -#define CONTRAST_DEF 1 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = 255, - .step = 1, -#define HUE_DEF 0 - .default_value = HUE_DEF, - }, - .set = sd_sethue, - .get = sd_gethue, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 8, - .step = 1, -#define COLOR_DEF 1 - .default_value = COLOR_DEF, - }, - .set = sd_setcolor, - .get = sd_getcolor, - }, - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define SHARPNESS_DEF 0 - .default_value = SHARPNESS_DEF, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { -/* (does not work correctly) - {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 5 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 3}, -*/ - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, -}; - -/* read bytes to gspca usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - u8 req, - u16 index, - int len) -{ -#if USB_BUF_SZ < 64 -#error "USB buffer too small" -#endif - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, /* value */ - index, - gspca_dev->usb_buf, len, - 500); - PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index, - gspca_dev->usb_buf[0]); - if (ret < 0) { - err("reg_r err %d", ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_w(struct gspca_dev *gspca_dev, - u8 req, - u16 value, - u16 index) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index); - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, - NULL, 0, 500); - if (ret < 0) { - err("reg_w err %d", ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_wb(struct gspca_dev *gspca_dev, - u8 req, - u16 value, - u16 index, - u8 byte) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_USBO, "SET %02x %04x %04x %02x", req, value, index, byte); - gspca_dev->usb_buf[0] = byte; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, - gspca_dev->usb_buf, 1, 500); - if (ret < 0) { - err("reg_w err %d", ret); - gspca_dev->usb_err = ret; - } -} - -static void wait_status_0(struct gspca_dev *gspca_dev) -{ - int i; - - i = 20; - do { - reg_r(gspca_dev, 0x21, 0x0000, 1); - if (gspca_dev->usb_buf[0] == 0) - return; - msleep(30); - } while (--i > 0); - PDEBUG(D_ERR, "wait_status_0 timeout"); - gspca_dev->usb_err = -ETIME; -} - -static void wait_status_1(struct gspca_dev *gspca_dev) -{ - int i; - - i = 10; - do { - reg_r(gspca_dev, 0x21, 0x0001, 1); - msleep(10); - if (gspca_dev->usb_buf[0] == 1) { - reg_wb(gspca_dev, 0x21, 0x0000, 0x0001, 0x00); - reg_r(gspca_dev, 0x21, 0x0001, 1); - return; - } - } while (--i > 0); - PDEBUG(D_ERR, "wait_status_1 timeout"); - gspca_dev->usb_err = -ETIME; -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, sd->brightness); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, sd->contrast); -} - -static void sethue(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, sd->hue); -} - -static void setcolor(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, sd->color); -} - -static void setsharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, sd->sharpness); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->cam.cam_mode = vga_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); - gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */ - /*fixme: 256 in ms-win traces*/ - - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->hue = HUE_DEF; - sd->color = COLOR_DEF; - sd->sharpness = SHARPNESS_DEF; - - gspca_dev->nbalt = 4; /* use alternate setting 3 */ - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev, 0x00, 0x0001, 0x2067); - reg_w(gspca_dev, 0x00, 0x00d0, 0x206b); - reg_w(gspca_dev, 0x00, 0x0000, 0x206c); - reg_w(gspca_dev, 0x00, 0x0001, 0x2069); - msleep(8); - reg_w(gspca_dev, 0x00, 0x00c0, 0x206b); - reg_w(gspca_dev, 0x00, 0x0000, 0x206c); - reg_w(gspca_dev, 0x00, 0x0001, 0x2069); - - reg_r(gspca_dev, 0x20, 0x0000, 1); - reg_r(gspca_dev, 0x20, 0x0000, 5); - reg_r(gspca_dev, 0x23, 0x0000, 64); - PDEBUG(D_PROBE, "%s%s", &gspca_dev->usb_buf[0x1c], - &gspca_dev->usb_buf[0x30]); - reg_r(gspca_dev, 0x23, 0x0001, 64); - return gspca_dev->usb_err; -} - -/* function called at start time before URB creation */ -static int sd_isoc_init(struct gspca_dev *gspca_dev) -{ - u8 mode; - - reg_r(gspca_dev, 0x00, 0x2520, 1); - wait_status_0(gspca_dev); - reg_w(gspca_dev, 0xc5, 0x0003, 0x0000); - wait_status_1(gspca_dev); - - wait_status_0(gspca_dev); - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode); - reg_r(gspca_dev, 0x25, 0x0004, 1); - reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06); - reg_r(gspca_dev, 0x27, 0x0000, 1); - return gspca_dev->usb_err; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* initialize the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x22); /* JPEG 411 */ - - /* the JPEG quality seems to be 82% */ - jpeg_set_qual(sd->jpeg_hdr, 82); - - /* set the controls */ - setbrightness(gspca_dev); - setcontrast(gspca_dev); - sethue(gspca_dev); - setcolor(gspca_dev); - setsharpness(gspca_dev); - - msleep(5); - reg_r(gspca_dev, 0x00, 0x2520, 1); - msleep(8); - - /* start the capture */ - wait_status_0(gspca_dev); - reg_w(gspca_dev, 0x31, 0x0000, 0x0004); - wait_status_1(gspca_dev); - wait_status_0(gspca_dev); - msleep(200); - - sd->pkt_seq = 0; - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - /* stop the capture */ - wait_status_0(gspca_dev); - reg_w(gspca_dev, 0x31, 0x0000, 0x0000); - wait_status_1(gspca_dev); - wait_status_0(gspca_dev); -} - -/* move a packet adding 0x00 after 0xff */ -static void add_packet(struct gspca_dev *gspca_dev, - u8 *data, - int len) -{ - int i; - - i = 0; - do { - if (data[i] == 0xff) { - gspca_frame_add(gspca_dev, INTER_PACKET, - data, i + 1); - len -= i; - data += i; - *data = 0x00; - i = 0; - } - } while (++i < len); - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - static const u8 ffd9[] = {0xff, 0xd9}; - - /* image packets start with: - * 02 8n - * with bit: - * 0x01: even (0) / odd (1) image - * 0x02: end of image when set - */ - if (len < 3) - return; /* empty packet */ - if (*data == 0x02) { - if (data[1] & 0x02) { - sd->pkt_seq = !(data[1] & 1); - add_packet(gspca_dev, data + 2, len - 2); - gspca_frame_add(gspca_dev, LAST_PACKET, - ffd9, 2); - return; - } - if ((data[1] & 1) != sd->pkt_seq) - goto err; - if (gspca_dev->last_packet_type == LAST_PACKET) - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - add_packet(gspca_dev, data + 2, len - 2); - return; - } -err: - gspca_dev->last_packet_type = DISCARD_PACKET; -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hue = val; - if (gspca_dev->streaming) - sethue(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hue; - return 0; -} - -static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->color = val; - if (gspca_dev->streaming) - setcolor(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->color; - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .isoc_init = sd_isoc_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x04fc, 0x1528)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - /* the video interface for isochronous transfer is 1 */ - if (intf->cur_altsetting->desc.bInterfaceNumber != 1) - return -ENODEV; - - return gspca_dev_probe2(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca500.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca500.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca500.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca500.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1104 +0,0 @@ -/* - * SPCA500 chip based cameras initialization data - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - * - */ - -#define MODULE_NAME "spca500" - -#include "gspca.h" -#include "jpeg.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - unsigned char brightness; - unsigned char contrast; - unsigned char colors; - u8 quality; -#define QUALITY_MIN 70 -#define QUALITY_MAX 95 -#define QUALITY_DEF 85 - - char subtype; -#define AgfaCl20 0 -#define AiptekPocketDV 1 -#define BenqDC1016 2 -#define CreativePCCam300 3 -#define DLinkDSC350 4 -#define Gsmartmini 5 -#define IntelPocketPCCamera 6 -#define KodakEZ200 7 -#define LogitechClickSmart310 8 -#define LogitechClickSmart510 9 -#define LogitechTraveler 10 -#define MustekGsmart300 11 -#define Optimedia 12 -#define PalmPixDC85 13 -#define ToptroIndus 14 - - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 127 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 63, - .step = 1, -#define CONTRAST_DEF 31 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 63, - .step = 1, -#define COLOR_DEF 31 - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -static const struct v4l2_pix_format sif_mode[] = { - {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -/* Frame packet header offsets for the spca500 */ -#define SPCA500_OFFSET_PADDINGLB 2 -#define SPCA500_OFFSET_PADDINGHB 3 -#define SPCA500_OFFSET_MODE 4 -#define SPCA500_OFFSET_IMGWIDTH 5 -#define SPCA500_OFFSET_IMGHEIGHT 6 -#define SPCA500_OFFSET_IMGMODE 7 -#define SPCA500_OFFSET_QTBLINDEX 8 -#define SPCA500_OFFSET_FRAMSEQ 9 -#define SPCA500_OFFSET_CDSPINFO 10 -#define SPCA500_OFFSET_GPIO 11 -#define SPCA500_OFFSET_AUGPIO 12 -#define SPCA500_OFFSET_DATA 16 - - -static const __u16 spca500_visual_defaults[][3] = { - {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync, - * hue (H byte) = 0, - * saturation/hue enable, - * brightness/contrast enable. - */ - {0x00, 0x0000, 0x8167}, /* brightness = 0 */ - {0x00, 0x0020, 0x8168}, /* contrast = 0 */ - {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync, - * hue (H byte) = 0, saturation/hue enable, - * brightness/contrast enable. - * was 0x0003, now 0x0000. - */ - {0x00, 0x0000, 0x816a}, /* hue (L byte) = 0 */ - {0x00, 0x0020, 0x8169}, /* saturation = 0x20 */ - {0x00, 0x0050, 0x8157}, /* edge gain high threshold */ - {0x00, 0x0030, 0x8158}, /* edge gain low threshold */ - {0x00, 0x0028, 0x8159}, /* edge bandwidth high threshold */ - {0x00, 0x000a, 0x815a}, /* edge bandwidth low threshold */ - {0x00, 0x0001, 0x8202}, /* clock rate compensation = 1/25 sec/frame */ - {0x0c, 0x0004, 0x0000}, - /* set interface */ - {} -}; -static const __u16 Clicksmart510_defaults[][3] = { - {0x00, 0x00, 0x8211}, - {0x00, 0x01, 0x82c0}, - {0x00, 0x10, 0x82cb}, - {0x00, 0x0f, 0x800d}, - {0x00, 0x82, 0x8225}, - {0x00, 0x21, 0x8228}, - {0x00, 0x00, 0x8203}, - {0x00, 0x00, 0x8204}, - {0x00, 0x08, 0x8205}, - {0x00, 0xf8, 0x8206}, - {0x00, 0x28, 0x8207}, - {0x00, 0xa0, 0x8208}, - {0x00, 0x08, 0x824a}, - {0x00, 0x08, 0x8214}, - {0x00, 0x80, 0x82c1}, - {0x00, 0x00, 0x82c2}, - {0x00, 0x00, 0x82ca}, - {0x00, 0x80, 0x82c1}, - {0x00, 0x04, 0x82c2}, - {0x00, 0x00, 0x82ca}, - {0x00, 0xfc, 0x8100}, - {0x00, 0xfc, 0x8105}, - {0x00, 0x30, 0x8101}, - {0x00, 0x00, 0x8102}, - {0x00, 0x00, 0x8103}, - {0x00, 0x66, 0x8107}, - {0x00, 0x00, 0x816b}, - {0x00, 0x00, 0x8155}, - {0x00, 0x01, 0x8156}, - {0x00, 0x60, 0x8157}, - {0x00, 0x40, 0x8158}, - {0x00, 0x0a, 0x8159}, - {0x00, 0x06, 0x815a}, - {0x00, 0x00, 0x813f}, - {0x00, 0x00, 0x8200}, - {0x00, 0x19, 0x8201}, - {0x00, 0x00, 0x82c1}, - {0x00, 0xa0, 0x82c2}, - {0x00, 0x00, 0x82ca}, - {0x00, 0x00, 0x8117}, - {0x00, 0x00, 0x8118}, - {0x00, 0x65, 0x8119}, - {0x00, 0x00, 0x811a}, - {0x00, 0x00, 0x811b}, - {0x00, 0x55, 0x811c}, - {0x00, 0x65, 0x811d}, - {0x00, 0x55, 0x811e}, - {0x00, 0x16, 0x811f}, - {0x00, 0x19, 0x8120}, - {0x00, 0x80, 0x8103}, - {0x00, 0x83, 0x816b}, - {0x00, 0x25, 0x8168}, - {0x00, 0x01, 0x820f}, - {0x00, 0xff, 0x8115}, - {0x00, 0x48, 0x8116}, - {0x00, 0x50, 0x8151}, - {0x00, 0x40, 0x8152}, - {0x00, 0x78, 0x8153}, - {0x00, 0x40, 0x8154}, - {0x00, 0x00, 0x8167}, - {0x00, 0x20, 0x8168}, - {0x00, 0x00, 0x816a}, - {0x00, 0x03, 0x816b}, - {0x00, 0x20, 0x8169}, - {0x00, 0x60, 0x8157}, - {0x00, 0x00, 0x8190}, - {0x00, 0x00, 0x81a1}, - {0x00, 0x00, 0x81b2}, - {0x00, 0x27, 0x8191}, - {0x00, 0x27, 0x81a2}, - {0x00, 0x27, 0x81b3}, - {0x00, 0x4b, 0x8192}, - {0x00, 0x4b, 0x81a3}, - {0x00, 0x4b, 0x81b4}, - {0x00, 0x66, 0x8193}, - {0x00, 0x66, 0x81a4}, - {0x00, 0x66, 0x81b5}, - {0x00, 0x79, 0x8194}, - {0x00, 0x79, 0x81a5}, - {0x00, 0x79, 0x81b6}, - {0x00, 0x8a, 0x8195}, - {0x00, 0x8a, 0x81a6}, - {0x00, 0x8a, 0x81b7}, - {0x00, 0x9b, 0x8196}, - {0x00, 0x9b, 0x81a7}, - {0x00, 0x9b, 0x81b8}, - {0x00, 0xa6, 0x8197}, - {0x00, 0xa6, 0x81a8}, - {0x00, 0xa6, 0x81b9}, - {0x00, 0xb2, 0x8198}, - {0x00, 0xb2, 0x81a9}, - {0x00, 0xb2, 0x81ba}, - {0x00, 0xbe, 0x8199}, - {0x00, 0xbe, 0x81aa}, - {0x00, 0xbe, 0x81bb}, - {0x00, 0xc8, 0x819a}, - {0x00, 0xc8, 0x81ab}, - {0x00, 0xc8, 0x81bc}, - {0x00, 0xd2, 0x819b}, - {0x00, 0xd2, 0x81ac}, - {0x00, 0xd2, 0x81bd}, - {0x00, 0xdb, 0x819c}, - {0x00, 0xdb, 0x81ad}, - {0x00, 0xdb, 0x81be}, - {0x00, 0xe4, 0x819d}, - {0x00, 0xe4, 0x81ae}, - {0x00, 0xe4, 0x81bf}, - {0x00, 0xed, 0x819e}, - {0x00, 0xed, 0x81af}, - {0x00, 0xed, 0x81c0}, - {0x00, 0xf7, 0x819f}, - {0x00, 0xf7, 0x81b0}, - {0x00, 0xf7, 0x81c1}, - {0x00, 0xff, 0x81a0}, - {0x00, 0xff, 0x81b1}, - {0x00, 0xff, 0x81c2}, - {0x00, 0x03, 0x8156}, - {0x00, 0x00, 0x8211}, - {0x00, 0x20, 0x8168}, - {0x00, 0x01, 0x8202}, - {0x00, 0x30, 0x8101}, - {0x00, 0x00, 0x8111}, - {0x00, 0x00, 0x8112}, - {0x00, 0x00, 0x8113}, - {0x00, 0x00, 0x8114}, - {} -}; - -static const __u8 qtable_creative_pccam[2][64] = { - { /* Q-table Y-components */ - 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, - 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, - 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, - 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, - 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, - 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, - 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, - 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e}, - { /* Q-table C-components */ - 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, - 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} -}; - -static const __u8 qtable_kodak_ez200[2][64] = { - { /* Q-table Y-components */ - 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06, - 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06, - 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06, - 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06, - 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08, - 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09, - 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a, - 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a}, - { /* Q-table C-components */ - 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a, - 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, - 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a} -}; - -static const __u8 qtable_pocketdv[2][64] = { - { /* Q-table Y-components start registers 0x8800 */ - 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18, - 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16, - 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16, - 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19, - 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f, - 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25, - 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28, - 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28, - }, - { /* Q-table C-components start registers 0x8840 */ - 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28, - 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28, - 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28} -}; - -/* read 'len' bytes to gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - __u16 index, - __u16 length) -{ - usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, length, 500); -} - -static int reg_w(struct gspca_dev *gspca_dev, - __u16 req, __u16 index, __u16 value) -{ - int ret; - - PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x", index, value); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 500); - if (ret < 0) - err("reg write: error %d", ret); - return ret; -} - -/* returns: negative is error, pos or zero is data */ -static int reg_r_12(struct gspca_dev *gspca_dev, - __u16 req, /* bRequest */ - __u16 index, /* wIndex */ - __u16 length) /* wLength (1 or 2 only) */ -{ - int ret; - - gspca_dev->usb_buf[1] = 0; - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, - gspca_dev->usb_buf, length, - 500); /* timeout */ - if (ret < 0) { - err("reg_r_12 err %d", ret); - return ret; - } - return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; -} - -/* - * Simple function to wait for a given 8-bit value to be returned from - * a reg_read call. - * Returns: negative is error or timeout, zero is success. - */ -static int reg_r_wait(struct gspca_dev *gspca_dev, - __u16 reg, __u16 index, __u16 value) -{ - int ret, cnt = 20; - - while (--cnt > 0) { - ret = reg_r_12(gspca_dev, reg, index, 1); - if (ret == value) - return 0; - msleep(50); - } - return -EIO; -} - -static int write_vector(struct gspca_dev *gspca_dev, - const __u16 data[][3]) -{ - int ret, i = 0; - - while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { - ret = reg_w(gspca_dev, data[i][0], data[i][2], data[i][1]); - if (ret < 0) - return ret; - i++; - } - return 0; -} - -static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, - unsigned int request, - unsigned int ybase, - unsigned int cbase, - const __u8 qtable[2][64]) -{ - int i, err; - - /* loop over y components */ - for (i = 0; i < 64; i++) { - err = reg_w(gspca_dev, request, ybase + i, qtable[0][i]); - if (err < 0) - return err; - } - - /* loop over c components */ - for (i = 0; i < 64; i++) { - err = reg_w(gspca_dev, request, cbase + i, qtable[1][i]); - if (err < 0) - return err; - } - return 0; -} - -static void spca500_ping310(struct gspca_dev *gspca_dev) -{ - reg_r(gspca_dev, 0x0d04, 2); - PDEBUG(D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x", - gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); -} - -static void spca500_clksmart310_init(struct gspca_dev *gspca_dev) -{ - reg_r(gspca_dev, 0x0d05, 2); - PDEBUG(D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x", - gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); - reg_w(gspca_dev, 0x00, 0x8167, 0x5a); - spca500_ping310(gspca_dev); - - reg_w(gspca_dev, 0x00, 0x8168, 0x22); - reg_w(gspca_dev, 0x00, 0x816a, 0xc0); - reg_w(gspca_dev, 0x00, 0x816b, 0x0b); - reg_w(gspca_dev, 0x00, 0x8169, 0x25); - reg_w(gspca_dev, 0x00, 0x8157, 0x5b); - reg_w(gspca_dev, 0x00, 0x8158, 0x5b); - reg_w(gspca_dev, 0x00, 0x813f, 0x03); - reg_w(gspca_dev, 0x00, 0x8151, 0x4a); - reg_w(gspca_dev, 0x00, 0x8153, 0x78); - reg_w(gspca_dev, 0x00, 0x0d01, 0x04); - /* 00 for adjust shutter */ - reg_w(gspca_dev, 0x00, 0x0d02, 0x01); - reg_w(gspca_dev, 0x00, 0x8169, 0x25); - reg_w(gspca_dev, 0x00, 0x0d01, 0x02); -} - -static void spca500_setmode(struct gspca_dev *gspca_dev, - __u8 xmult, __u8 ymult) -{ - int mode; - - /* set x multiplier */ - reg_w(gspca_dev, 0, 0x8001, xmult); - - /* set y multiplier */ - reg_w(gspca_dev, 0, 0x8002, ymult); - - /* use compressed mode, VGA, with mode specific subsample */ - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - reg_w(gspca_dev, 0, 0x8003, mode << 4); -} - -static int spca500_full_reset(struct gspca_dev *gspca_dev) -{ - int err; - - /* send the reset command */ - err = reg_w(gspca_dev, 0xe0, 0x0001, 0x0000); - if (err < 0) - return err; - - /* wait for the reset to complete */ - err = reg_r_wait(gspca_dev, 0x06, 0x0000, 0x0000); - if (err < 0) - return err; - err = reg_w(gspca_dev, 0xe0, 0x0000, 0x0000); - if (err < 0) - return err; - err = reg_r_wait(gspca_dev, 0x06, 0, 0); - if (err < 0) { - PDEBUG(D_ERR, "reg_r_wait() failed"); - return err; - } - /* all ok */ - return 0; -} - -/* Synchro the Bridge with sensor */ -/* Maybe that will work on all spca500 chip */ -/* because i only own a clicksmart310 try for that chip */ -/* using spca50x_set_packet_size() cause an Ooops here */ -/* usb_set_interface from kernel 2.6.x clear all the urb stuff */ -/* up-port the same feature as in 2.4.x kernel */ -static int spca500_synch310(struct gspca_dev *gspca_dev) -{ - if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) { - PDEBUG(D_ERR, "Set packet size: set interface error"); - goto error; - } - spca500_ping310(gspca_dev); - - reg_r(gspca_dev, 0x0d00, 1); - - /* need alt setting here */ - PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt); - - /* Windoze use pipe with altsetting 6 why 7 here */ - if (usb_set_interface(gspca_dev->dev, - gspca_dev->iface, - gspca_dev->alt) < 0) { - PDEBUG(D_ERR, "Set packet size: set interface error"); - goto error; - } - return 0; -error: - return -EBUSY; -} - -static void spca500_reinit(struct gspca_dev *gspca_dev) -{ - int err; - __u8 Data; - - /* some unknown command from Aiptek pocket dv and family300 */ - - reg_w(gspca_dev, 0x00, 0x0d01, 0x01); - reg_w(gspca_dev, 0x00, 0x0d03, 0x00); - reg_w(gspca_dev, 0x00, 0x0d02, 0x01); - - /* enable drop packet */ - reg_w(gspca_dev, 0x00, 0x850a, 0x0001); - - err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840, - qtable_pocketdv); - if (err < 0) - PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init"); - - /* set qtable index */ - reg_w(gspca_dev, 0x00, 0x8880, 2); - /* family cam Quicksmart stuff */ - reg_w(gspca_dev, 0x00, 0x800a, 0x00); - /* Set agc transfer: synced inbetween frames */ - reg_w(gspca_dev, 0x00, 0x820f, 0x01); - /* Init SDRAM - needed for SDRAM access */ - reg_w(gspca_dev, 0x00, 0x870a, 0x04); - /*Start init sequence or stream */ - reg_w(gspca_dev, 0, 0x8003, 0x00); - /* switch to video camera mode */ - reg_w(gspca_dev, 0x00, 0x8000, 0x0004); - msleep(2000); - if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) { - reg_r(gspca_dev, 0x816b, 1); - Data = gspca_dev->usb_buf[0]; - reg_w(gspca_dev, 0x00, 0x816b, Data); - } -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - sd->subtype = id->driver_info; - if (sd->subtype != LogitechClickSmart310) { - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - } else { - cam->cam_mode = sif_mode; - cam->nmodes = ARRAY_SIZE(sif_mode); - } - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->quality = QUALITY_DEF; - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* initialisation of spca500 based cameras is deferred */ - PDEBUG(D_STREAM, "SPCA500 init"); - if (sd->subtype == LogitechClickSmart310) - spca500_clksmart310_init(gspca_dev); -/* else - spca500_initialise(gspca_dev); */ - PDEBUG(D_STREAM, "SPCA500 init done"); - return 0; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int err; - __u8 Data; - __u8 xmult, ymult; - - /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x22); /* JPEG 411 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - - if (sd->subtype == LogitechClickSmart310) { - xmult = 0x16; - ymult = 0x12; - } else { - xmult = 0x28; - ymult = 0x1e; - } - - /* is there a sensor here ? */ - reg_r(gspca_dev, 0x8a04, 1); - PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02x", - gspca_dev->usb_buf[0]); - PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02x, Ymult: 0x%02x", - gspca_dev->curr_mode, xmult, ymult); - - /* setup qtable */ - switch (sd->subtype) { - case LogitechClickSmart310: - spca500_setmode(gspca_dev, xmult, ymult); - - /* enable drop packet */ - reg_w(gspca_dev, 0x00, 0x850a, 0x0001); - reg_w(gspca_dev, 0x00, 0x8880, 3); - err = spca50x_setup_qtable(gspca_dev, - 0x00, 0x8800, 0x8840, - qtable_creative_pccam); - if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); - /* Init SDRAM - needed for SDRAM access */ - reg_w(gspca_dev, 0x00, 0x870a, 0x04); - - /* switch to video camera mode */ - reg_w(gspca_dev, 0x00, 0x8000, 0x0004); - msleep(500); - if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) - PDEBUG(D_ERR, "reg_r_wait() failed"); - - reg_r(gspca_dev, 0x816b, 1); - Data = gspca_dev->usb_buf[0]; - reg_w(gspca_dev, 0x00, 0x816b, Data); - - spca500_synch310(gspca_dev); - - write_vector(gspca_dev, spca500_visual_defaults); - spca500_setmode(gspca_dev, xmult, ymult); - /* enable drop packet */ - err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001); - if (err < 0) - PDEBUG(D_ERR, "failed to enable drop packet"); - reg_w(gspca_dev, 0x00, 0x8880, 3); - err = spca50x_setup_qtable(gspca_dev, - 0x00, 0x8800, 0x8840, - qtable_creative_pccam); - if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); - - /* Init SDRAM - needed for SDRAM access */ - reg_w(gspca_dev, 0x00, 0x870a, 0x04); - - /* switch to video camera mode */ - reg_w(gspca_dev, 0x00, 0x8000, 0x0004); - - if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) - PDEBUG(D_ERR, "reg_r_wait() failed"); - - reg_r(gspca_dev, 0x816b, 1); - Data = gspca_dev->usb_buf[0]; - reg_w(gspca_dev, 0x00, 0x816b, Data); - break; - case CreativePCCam300: /* Creative PC-CAM 300 640x480 CCD */ - case IntelPocketPCCamera: /* FIXME: Temporary fix for - * Intel Pocket PC Camera - * - NWG (Sat 29th March 2003) */ - - /* do a full reset */ - err = spca500_full_reset(gspca_dev); - if (err < 0) - PDEBUG(D_ERR, "spca500_full_reset failed"); - - /* enable drop packet */ - err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001); - if (err < 0) - PDEBUG(D_ERR, "failed to enable drop packet"); - reg_w(gspca_dev, 0x00, 0x8880, 3); - err = spca50x_setup_qtable(gspca_dev, - 0x00, 0x8800, 0x8840, - qtable_creative_pccam); - if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); - - spca500_setmode(gspca_dev, xmult, ymult); - reg_w(gspca_dev, 0x20, 0x0001, 0x0004); - - /* switch to video camera mode */ - reg_w(gspca_dev, 0x00, 0x8000, 0x0004); - - if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) - PDEBUG(D_ERR, "reg_r_wait() failed"); - - reg_r(gspca_dev, 0x816b, 1); - Data = gspca_dev->usb_buf[0]; - reg_w(gspca_dev, 0x00, 0x816b, Data); - -/* write_vector(gspca_dev, spca500_visual_defaults); */ - break; - case KodakEZ200: /* Kodak EZ200 */ - - /* do a full reset */ - err = spca500_full_reset(gspca_dev); - if (err < 0) - PDEBUG(D_ERR, "spca500_full_reset failed"); - /* enable drop packet */ - reg_w(gspca_dev, 0x00, 0x850a, 0x0001); - reg_w(gspca_dev, 0x00, 0x8880, 0); - err = spca50x_setup_qtable(gspca_dev, - 0x00, 0x8800, 0x8840, - qtable_kodak_ez200); - if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); - spca500_setmode(gspca_dev, xmult, ymult); - - reg_w(gspca_dev, 0x20, 0x0001, 0x0004); - - /* switch to video camera mode */ - reg_w(gspca_dev, 0x00, 0x8000, 0x0004); - - if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) - PDEBUG(D_ERR, "reg_r_wait() failed"); - - reg_r(gspca_dev, 0x816b, 1); - Data = gspca_dev->usb_buf[0]; - reg_w(gspca_dev, 0x00, 0x816b, Data); - -/* write_vector(gspca_dev, spca500_visual_defaults); */ - break; - - case BenqDC1016: - case DLinkDSC350: /* FamilyCam 300 */ - case AiptekPocketDV: /* Aiptek PocketDV */ - case Gsmartmini: /*Mustek Gsmart Mini */ - case MustekGsmart300: /* Mustek Gsmart 300 */ - case PalmPixDC85: - case Optimedia: - case ToptroIndus: - case AgfaCl20: - spca500_reinit(gspca_dev); - reg_w(gspca_dev, 0x00, 0x0d01, 0x01); - /* enable drop packet */ - reg_w(gspca_dev, 0x00, 0x850a, 0x0001); - - err = spca50x_setup_qtable(gspca_dev, - 0x00, 0x8800, 0x8840, qtable_pocketdv); - if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); - reg_w(gspca_dev, 0x00, 0x8880, 2); - - /* familycam Quicksmart pocketDV stuff */ - reg_w(gspca_dev, 0x00, 0x800a, 0x00); - /* Set agc transfer: synced inbetween frames */ - reg_w(gspca_dev, 0x00, 0x820f, 0x01); - /* Init SDRAM - needed for SDRAM access */ - reg_w(gspca_dev, 0x00, 0x870a, 0x04); - - spca500_setmode(gspca_dev, xmult, ymult); - /* switch to video camera mode */ - reg_w(gspca_dev, 0x00, 0x8000, 0x0004); - - reg_r_wait(gspca_dev, 0, 0x8000, 0x44); - - reg_r(gspca_dev, 0x816b, 1); - Data = gspca_dev->usb_buf[0]; - reg_w(gspca_dev, 0x00, 0x816b, Data); - break; - case LogitechTraveler: - case LogitechClickSmart510: - reg_w(gspca_dev, 0x02, 0x00, 0x00); - /* enable drop packet */ - reg_w(gspca_dev, 0x00, 0x850a, 0x0001); - - err = spca50x_setup_qtable(gspca_dev, - 0x00, 0x8800, - 0x8840, qtable_creative_pccam); - if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); - reg_w(gspca_dev, 0x00, 0x8880, 3); - reg_w(gspca_dev, 0x00, 0x800a, 0x00); - /* Init SDRAM - needed for SDRAM access */ - reg_w(gspca_dev, 0x00, 0x870a, 0x04); - - spca500_setmode(gspca_dev, xmult, ymult); - - /* switch to video camera mode */ - reg_w(gspca_dev, 0x00, 0x8000, 0x0004); - reg_r_wait(gspca_dev, 0, 0x8000, 0x44); - - reg_r(gspca_dev, 0x816b, 1); - Data = gspca_dev->usb_buf[0]; - reg_w(gspca_dev, 0x00, 0x816b, Data); - write_vector(gspca_dev, Clicksmart510_defaults); - break; - } - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev, 0, 0x8003, 0x00); - - /* switch to video camera mode */ - reg_w(gspca_dev, 0x00, 0x8000, 0x0004); - reg_r(gspca_dev, 0x8000, 1); - PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x", - gspca_dev->usb_buf[0]); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - static __u8 ffd9[] = {0xff, 0xd9}; - -/* frames are jpeg 4.1.1 without 0xff escape */ - if (data[0] == 0xff) { - if (data[1] != 0x01) { /* drop packet */ -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; - } - gspca_frame_add(gspca_dev, LAST_PACKET, - ffd9, 2); - - /* put the JPEG header in the new frame */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - - data += SPCA500_OFFSET_DATA; - len -= SPCA500_OFFSET_DATA; - } else { - data += 1; - len -= 1; - } - - /* add 0x00 after 0xff */ - i = 0; - do { - if (data[i] == 0xff) { - gspca_frame_add(gspca_dev, INTER_PACKET, - data, i + 1); - len -= i; - data += i; - *data = 0x00; - i = 0; - } - i++; - } while (i < len); - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0x00, 0x8167, - (__u8) (sd->brightness - 128)); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0x00, 0x8168, sd->contrast); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0x00, 0x8169, sd->colors); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return 0; -} - -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200}, - {USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300}, - {USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler}, - {USB_DEVICE(0x046d, 0x0900), .driver_info = LogitechClickSmart310}, - {USB_DEVICE(0x046d, 0x0901), .driver_info = LogitechClickSmart510}, - {USB_DEVICE(0x04a5, 0x300c), .driver_info = BenqDC1016}, - {USB_DEVICE(0x04fc, 0x7333), .driver_info = PalmPixDC85}, - {USB_DEVICE(0x055f, 0xc200), .driver_info = MustekGsmart300}, - {USB_DEVICE(0x055f, 0xc220), .driver_info = Gsmartmini}, - {USB_DEVICE(0x06bd, 0x0404), .driver_info = AgfaCl20}, - {USB_DEVICE(0x06be, 0x0800), .driver_info = Optimedia}, - {USB_DEVICE(0x084d, 0x0003), .driver_info = DLinkDSC350}, - {USB_DEVICE(0x08ca, 0x0103), .driver_info = AiptekPocketDV}, - {USB_DEVICE(0x2899, 0x012c), .driver_info = ToptroIndus}, - {USB_DEVICE(0x8086, 0x0630), .driver_info = IntelPocketPCCamera}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca501.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca501.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca501.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca501.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2200 +0,0 @@ -/* - * SPCA501 chip based cameras initialization data - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - * - */ - -#define MODULE_NAME "spca501" - -#include "gspca.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("GSPCA/SPCA501 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - unsigned short contrast; - __u8 brightness; - __u8 colors; - __u8 blue_balance; - __u8 red_balance; - - char subtype; -#define Arowana300KCMOSCamera 0 -#define IntelCreateAndShare 1 -#define KodakDVC325 2 -#define MystFromOriUnknownCamera 3 -#define SmileIntlCamera 4 -#define ThreeComHomeConnectLite 5 -#define ViewQuestM318B 6 -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define MY_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define MY_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 64725, - .step = 1, - .default_value = 64725, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define MY_COLOR 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 20, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -#define MY_BLUE_BALANCE 3 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 0, - }, - .set = sd_setblue_balance, - .get = sd_getblue_balance, - }, -#define MY_RED_BALANCE 4 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 0, - }, - .set = sd_setred_balance, - .get = sd_getred_balance, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {320, 240, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -#define SPCA50X_REG_USB 0x2 /* spca505 501 */ -/* - * Data to initialize a SPCA501. From a capture file provided by Bill Roehl - * With SPCA501 chip description - */ -#define CCDSP_SET /* set CCDSP parameters */ -#define TG_SET /* set time generator set */ -#undef DSPWIN_SET /* set DSP windows parameters */ -#undef ALTER_GAMA /* Set alternate set to YUV transform coeffs. */ -#define SPCA501_SNAPBIT 0x80 -#define SPCA501_SNAPCTRL 0x10 -/* Frame packet header offsets for the spca501 */ -#define SPCA501_OFFSET_GPIO 1 -#define SPCA501_OFFSET_TYPE 2 -#define SPCA501_OFFSET_TURN3A 3 -#define SPCA501_OFFSET_FRAMSEQ 4 -#define SPCA501_OFFSET_COMPRESS 5 -#define SPCA501_OFFSET_QUANT 6 -#define SPCA501_OFFSET_QUANT2 7 -#define SPCA501_OFFSET_DATA 8 - -#define SPCA501_PROP_COMP_ENABLE(d) ((d) & 1) -#define SPCA501_PROP_SNAP(d) ((d) & 0x40) -#define SPCA501_PROP_SNAP_CTRL(d) ((d) & 0x10) -#define SPCA501_PROP_COMP_THRESH(d) (((d) & 0x0e) >> 1) -#define SPCA501_PROP_COMP_QUANT(d) (((d) & 0x70) >> 4) - -/* SPCA501 CCDSP control */ -#define SPCA501_REG_CCDSP 0x01 -/* SPCA501 control/status registers */ -#define SPCA501_REG_CTLRL 0x02 - -/* registers for color correction and YUV transformation */ -#define SPCA501_A11 0x08 -#define SPCA501_A12 0x09 -#define SPCA501_A13 0x0A -#define SPCA501_A21 0x0B -#define SPCA501_A22 0x0C -#define SPCA501_A23 0x0D -#define SPCA501_A31 0x0E -#define SPCA501_A32 0x0F -#define SPCA501_A33 0x10 - -/* Data for video camera initialization before capturing */ -static const __u16 spca501_open_data[][3] = { - /* bmRequest,value,index */ - - {0x2, 0x50, 0x00}, /* C/S enable soft reset */ - {0x2, 0x40, 0x00}, /* C/S disable soft reset */ - {0x2, 0x02, 0x05}, /* C/S general purpose I/O data */ - {0x2, 0x03, 0x05}, /* C/S general purpose I/O data */ - -#ifdef CCDSP_SET - {0x1, 0x38, 0x01}, /* CCDSP options */ - {0x1, 0x05, 0x02}, /* CCDSP Optical black level for user settings */ - {0x1, 0xC0, 0x03}, /* CCDSP Optical black settings */ - - {0x1, 0x67, 0x07}, - {0x1, 0x63, 0x3f}, /* CCDSP CCD gamma enable */ - {0x1, 0x03, 0x56}, /* Add gamma correction */ - - {0x1, 0xFF, 0x15}, /* CCDSP High luminance for white balance */ - {0x1, 0x01, 0x16}, /* CCDSP Low luminance for white balance */ - -/* Color correction and RGB-to-YUV transformation coefficients changing */ -#ifdef ALTER_GAMA - {0x0, 0x00, 0x08}, /* A11 */ - {0x0, 0x00, 0x09}, /* A12 */ - {0x0, 0x90, 0x0A}, /* A13 */ - {0x0, 0x12, 0x0B}, /* A21 */ - {0x0, 0x00, 0x0C}, /* A22 */ - {0x0, 0x00, 0x0D}, /* A23 */ - {0x0, 0x00, 0x0E}, /* A31 */ - {0x0, 0x02, 0x0F}, /* A32 */ - {0x0, 0x00, 0x10}, /* A33 */ -#else - {0x1, 0x2a, 0x08}, /* A11 0x31 */ - {0x1, 0xf8, 0x09}, /* A12 f8 */ - {0x1, 0xf8, 0x0A}, /* A13 f8 */ - {0x1, 0xf8, 0x0B}, /* A21 f8 */ - {0x1, 0x14, 0x0C}, /* A22 0x14 */ - {0x1, 0xf8, 0x0D}, /* A23 f8 */ - {0x1, 0xf8, 0x0E}, /* A31 f8 */ - {0x1, 0xf8, 0x0F}, /* A32 f8 */ - {0x1, 0x20, 0x10}, /* A33 0x20 */ -#endif - {0x1, 0x00, 0x11}, /* R offset */ - {0x1, 0x00, 0x12}, /* G offset */ - {0x1, 0x00, 0x13}, /* B offset */ - {0x1, 0x00, 0x14}, /* GB offset */ - -#endif - -#ifdef TG_SET - /* Time generator manipulations */ - {0x0, 0xfc, 0x0}, /* Set up high bits of shutter speed */ - {0x0, 0x01, 0x1}, /* Set up low bits of shutter speed */ - - {0x0, 0xe4, 0x04}, /* DCLK*2 clock phase adjustment */ - {0x0, 0x08, 0x05}, /* ADCK phase adjustment, inv. ext. VB */ - {0x0, 0x03, 0x06}, /* FR phase adjustment */ - {0x0, 0x01, 0x07}, /* FCDS phase adjustment */ - {0x0, 0x39, 0x08}, /* FS phase adjustment */ - {0x0, 0x88, 0x0a}, /* FH1 phase and delay adjustment */ - {0x0, 0x03, 0x0f}, /* pixel identification */ - {0x0, 0x00, 0x11}, /* clock source selection (default) */ - - /*VERY strange manipulations with - * select DMCLP or OBPX to be ADCLP output (0x0C) - * OPB always toggle or not (0x0D) but they allow - * us to set up brightness - */ - {0x0, 0x01, 0x0c}, - {0x0, 0xe0, 0x0d}, - /* Done */ -#endif - -#ifdef DSPWIN_SET - {0x1, 0xa0, 0x01}, /* Setting image processing parameters */ - {0x1, 0x1c, 0x17}, /* Changing Windows positions X1 */ - {0x1, 0xe2, 0x19}, /* X2 */ - {0x1, 0x1c, 0x1b}, /* X3 */ - {0x1, 0xe2, 0x1d}, /* X4 */ - {0x1, 0x5f, 0x1f}, /* X5 */ - {0x1, 0x32, 0x20}, /* Y5 */ - {0x1, 0x01, 0x10}, /* Changing A33 */ -#endif - - {0x2, 0x204a, 0x07},/* Setting video compression & resolution 160x120 */ - {0x2, 0x94, 0x06}, /* Setting video no compression */ - {} -}; - -/* - The SPCAxxx docs from Sunplus document these values - in tables, one table per register number. In the data - below, dmRequest is the register number, index is the Addr, - and value is a combination of Bit values. - Bit Value (hex) - 0 01 - 1 02 - 2 04 - 3 08 - 4 10 - 5 20 - 6 40 - 7 80 - */ - -/* Data for chip initialization (set default values) */ -static const __u16 spca501_init_data[][3] = { - /* Set all the values to powerup defaults */ - /* bmRequest,value,index */ - {0x0, 0xAA, 0x00}, - {0x0, 0x02, 0x01}, - {0x0, 0x01, 0x02}, - {0x0, 0x02, 0x03}, - {0x0, 0xCE, 0x04}, - {0x0, 0x00, 0x05}, - {0x0, 0x00, 0x06}, - {0x0, 0x00, 0x07}, - {0x0, 0x00, 0x08}, - {0x0, 0x00, 0x09}, - {0x0, 0x90, 0x0A}, - {0x0, 0x12, 0x0B}, - {0x0, 0x00, 0x0C}, - {0x0, 0x00, 0x0D}, - {0x0, 0x00, 0x0E}, - {0x0, 0x02, 0x0F}, - {0x0, 0x00, 0x10}, - {0x0, 0x00, 0x11}, - {0x0, 0x00, 0x12}, - {0x0, 0x00, 0x13}, - {0x0, 0x00, 0x14}, - {0x0, 0x00, 0x15}, - {0x0, 0x00, 0x16}, - {0x0, 0x00, 0x17}, - {0x0, 0x00, 0x18}, - {0x0, 0x00, 0x19}, - {0x0, 0x00, 0x1A}, - {0x0, 0x00, 0x1B}, - {0x0, 0x00, 0x1C}, - {0x0, 0x00, 0x1D}, - {0x0, 0x00, 0x1E}, - {0x0, 0x00, 0x1F}, - {0x0, 0x00, 0x20}, - {0x0, 0x00, 0x21}, - {0x0, 0x00, 0x22}, - {0x0, 0x00, 0x23}, - {0x0, 0x00, 0x24}, - {0x0, 0x00, 0x25}, - {0x0, 0x00, 0x26}, - {0x0, 0x00, 0x27}, - {0x0, 0x00, 0x28}, - {0x0, 0x00, 0x29}, - {0x0, 0x00, 0x2A}, - {0x0, 0x00, 0x2B}, - {0x0, 0x00, 0x2C}, - {0x0, 0x00, 0x2D}, - {0x0, 0x00, 0x2E}, - {0x0, 0x00, 0x2F}, - {0x0, 0x00, 0x30}, - {0x0, 0x00, 0x31}, - {0x0, 0x00, 0x32}, - {0x0, 0x00, 0x33}, - {0x0, 0x00, 0x34}, - {0x0, 0x00, 0x35}, - {0x0, 0x00, 0x36}, - {0x0, 0x00, 0x37}, - {0x0, 0x00, 0x38}, - {0x0, 0x00, 0x39}, - {0x0, 0x00, 0x3A}, - {0x0, 0x00, 0x3B}, - {0x0, 0x00, 0x3C}, - {0x0, 0x00, 0x3D}, - {0x0, 0x00, 0x3E}, - {0x0, 0x00, 0x3F}, - {0x0, 0x00, 0x40}, - {0x0, 0x00, 0x41}, - {0x0, 0x00, 0x42}, - {0x0, 0x00, 0x43}, - {0x0, 0x00, 0x44}, - {0x0, 0x00, 0x45}, - {0x0, 0x00, 0x46}, - {0x0, 0x00, 0x47}, - {0x0, 0x00, 0x48}, - {0x0, 0x00, 0x49}, - {0x0, 0x00, 0x4A}, - {0x0, 0x00, 0x4B}, - {0x0, 0x00, 0x4C}, - {0x0, 0x00, 0x4D}, - {0x0, 0x00, 0x4E}, - {0x0, 0x00, 0x4F}, - {0x0, 0x00, 0x50}, - {0x0, 0x00, 0x51}, - {0x0, 0x00, 0x52}, - {0x0, 0x00, 0x53}, - {0x0, 0x00, 0x54}, - {0x0, 0x00, 0x55}, - {0x0, 0x00, 0x56}, - {0x0, 0x00, 0x57}, - {0x0, 0x00, 0x58}, - {0x0, 0x00, 0x59}, - {0x0, 0x00, 0x5A}, - {0x0, 0x00, 0x5B}, - {0x0, 0x00, 0x5C}, - {0x0, 0x00, 0x5D}, - {0x0, 0x00, 0x5E}, - {0x0, 0x00, 0x5F}, - {0x0, 0x00, 0x60}, - {0x0, 0x00, 0x61}, - {0x0, 0x00, 0x62}, - {0x0, 0x00, 0x63}, - {0x0, 0x00, 0x64}, - {0x0, 0x00, 0x65}, - {0x0, 0x00, 0x66}, - {0x0, 0x00, 0x67}, - {0x0, 0x00, 0x68}, - {0x0, 0x00, 0x69}, - {0x0, 0x00, 0x6A}, - {0x0, 0x00, 0x6B}, - {0x0, 0x00, 0x6C}, - {0x0, 0x00, 0x6D}, - {0x0, 0x00, 0x6E}, - {0x0, 0x00, 0x6F}, - {0x0, 0x00, 0x70}, - {0x0, 0x00, 0x71}, - {0x0, 0x00, 0x72}, - {0x0, 0x00, 0x73}, - {0x0, 0x00, 0x74}, - {0x0, 0x00, 0x75}, - {0x0, 0x00, 0x76}, - {0x0, 0x00, 0x77}, - {0x0, 0x00, 0x78}, - {0x0, 0x00, 0x79}, - {0x0, 0x00, 0x7A}, - {0x0, 0x00, 0x7B}, - {0x0, 0x00, 0x7C}, - {0x0, 0x00, 0x7D}, - {0x0, 0x00, 0x7E}, - {0x0, 0x00, 0x7F}, - {0x0, 0x00, 0x80}, - {0x0, 0x00, 0x81}, - {0x0, 0x00, 0x82}, - {0x0, 0x00, 0x83}, - {0x0, 0x00, 0x84}, - {0x0, 0x00, 0x85}, - {0x0, 0x00, 0x86}, - {0x0, 0x00, 0x87}, - {0x0, 0x00, 0x88}, - {0x0, 0x00, 0x89}, - {0x0, 0x00, 0x8A}, - {0x0, 0x00, 0x8B}, - {0x0, 0x00, 0x8C}, - {0x0, 0x00, 0x8D}, - {0x0, 0x00, 0x8E}, - {0x0, 0x00, 0x8F}, - {0x0, 0x00, 0x90}, - {0x0, 0x00, 0x91}, - {0x0, 0x00, 0x92}, - {0x0, 0x00, 0x93}, - {0x0, 0x00, 0x94}, - {0x0, 0x00, 0x95}, - {0x0, 0x00, 0x96}, - {0x0, 0x00, 0x97}, - {0x0, 0x00, 0x98}, - {0x0, 0x00, 0x99}, - {0x0, 0x00, 0x9A}, - {0x0, 0x00, 0x9B}, - {0x0, 0x00, 0x9C}, - {0x0, 0x00, 0x9D}, - {0x0, 0x00, 0x9E}, - {0x0, 0x00, 0x9F}, - {0x0, 0x00, 0xA0}, - {0x0, 0x00, 0xA1}, - {0x0, 0x00, 0xA2}, - {0x0, 0x00, 0xA3}, - {0x0, 0x00, 0xA4}, - {0x0, 0x00, 0xA5}, - {0x0, 0x00, 0xA6}, - {0x0, 0x00, 0xA7}, - {0x0, 0x00, 0xA8}, - {0x0, 0x00, 0xA9}, - {0x0, 0x00, 0xAA}, - {0x0, 0x00, 0xAB}, - {0x0, 0x00, 0xAC}, - {0x0, 0x00, 0xAD}, - {0x0, 0x00, 0xAE}, - {0x0, 0x00, 0xAF}, - {0x0, 0x00, 0xB0}, - {0x0, 0x00, 0xB1}, - {0x0, 0x00, 0xB2}, - {0x0, 0x00, 0xB3}, - {0x0, 0x00, 0xB4}, - {0x0, 0x00, 0xB5}, - {0x0, 0x00, 0xB6}, - {0x0, 0x00, 0xB7}, - {0x0, 0x00, 0xB8}, - {0x0, 0x00, 0xB9}, - {0x0, 0x00, 0xBA}, - {0x0, 0x00, 0xBB}, - {0x0, 0x00, 0xBC}, - {0x0, 0x00, 0xBD}, - {0x0, 0x00, 0xBE}, - {0x0, 0x00, 0xBF}, - {0x0, 0x00, 0xC0}, - {0x0, 0x00, 0xC1}, - {0x0, 0x00, 0xC2}, - {0x0, 0x00, 0xC3}, - {0x0, 0x00, 0xC4}, - {0x0, 0x00, 0xC5}, - {0x0, 0x00, 0xC6}, - {0x0, 0x00, 0xC7}, - {0x0, 0x00, 0xC8}, - {0x0, 0x00, 0xC9}, - {0x0, 0x00, 0xCA}, - {0x0, 0x00, 0xCB}, - {0x0, 0x00, 0xCC}, - {0x1, 0xF4, 0x00}, - {0x1, 0x38, 0x01}, - {0x1, 0x40, 0x02}, - {0x1, 0x0A, 0x03}, - {0x1, 0x40, 0x04}, - {0x1, 0x40, 0x05}, - {0x1, 0x40, 0x06}, - {0x1, 0x67, 0x07}, - {0x1, 0x31, 0x08}, - {0x1, 0x00, 0x09}, - {0x1, 0x00, 0x0A}, - {0x1, 0x00, 0x0B}, - {0x1, 0x14, 0x0C}, - {0x1, 0x00, 0x0D}, - {0x1, 0x00, 0x0E}, - {0x1, 0x00, 0x0F}, - {0x1, 0x1E, 0x10}, - {0x1, 0x00, 0x11}, - {0x1, 0x00, 0x12}, - {0x1, 0x00, 0x13}, - {0x1, 0x00, 0x14}, - {0x1, 0xFF, 0x15}, - {0x1, 0x01, 0x16}, - {0x1, 0x32, 0x17}, - {0x1, 0x23, 0x18}, - {0x1, 0xCE, 0x19}, - {0x1, 0x23, 0x1A}, - {0x1, 0x32, 0x1B}, - {0x1, 0x8D, 0x1C}, - {0x1, 0xCE, 0x1D}, - {0x1, 0x8D, 0x1E}, - {0x1, 0x00, 0x1F}, - {0x1, 0x00, 0x20}, - {0x1, 0xFF, 0x3E}, - {0x1, 0x02, 0x3F}, - {0x1, 0x00, 0x40}, - {0x1, 0x00, 0x41}, - {0x1, 0x00, 0x42}, - {0x1, 0x00, 0x43}, - {0x1, 0x00, 0x44}, - {0x1, 0x00, 0x45}, - {0x1, 0x00, 0x46}, - {0x1, 0x00, 0x47}, - {0x1, 0x00, 0x48}, - {0x1, 0x00, 0x49}, - {0x1, 0x00, 0x4A}, - {0x1, 0x00, 0x4B}, - {0x1, 0x00, 0x4C}, - {0x1, 0x00, 0x4D}, - {0x1, 0x00, 0x4E}, - {0x1, 0x00, 0x4F}, - {0x1, 0x00, 0x50}, - {0x1, 0x00, 0x51}, - {0x1, 0x00, 0x52}, - {0x1, 0x00, 0x53}, - {0x1, 0x00, 0x54}, - {0x1, 0x00, 0x55}, - {0x1, 0x00, 0x56}, - {0x1, 0x00, 0x57}, - {0x1, 0x00, 0x58}, - {0x1, 0x00, 0x59}, - {0x1, 0x00, 0x5A}, - {0x2, 0x03, 0x00}, - {0x2, 0x00, 0x01}, - {0x2, 0x00, 0x05}, - {0x2, 0x00, 0x06}, - {0x2, 0x00, 0x07}, - {0x2, 0x00, 0x10}, - {0x2, 0x00, 0x11}, - /* Strange - looks like the 501 driver doesn't do anything - * at insert time except read the EEPROM - */ - {} -}; - -/* Data for video camera init before capture. - * Capture and decoding by Colin Peart. - * This is is for the 3com HomeConnect Lite which is spca501a based. - */ -static const __u16 spca501_3com_open_data[][3] = { - /* bmRequest,value,index */ - {0x2, 0x0050, 0x0000}, /* C/S Enable TG soft reset, timing mode=010 */ - {0x2, 0x0043, 0x0000}, /* C/S Disable TG soft reset, timing mode=010 */ - {0x2, 0x0002, 0x0005}, /* C/S GPIO */ - {0x2, 0x0003, 0x0005}, /* C/S GPIO */ - -#ifdef CCDSP_SET - {0x1, 0x0020, 0x0001}, /* CCDSP Options */ - - {0x1, 0x0020, 0x0002}, /* CCDSP Black Level */ - {0x1, 0x006e, 0x0007}, /* CCDSP Gamma options */ - {0x1, 0x0090, 0x0015}, /* CCDSP Luminance Low */ - {0x1, 0x00ff, 0x0016}, /* CCDSP Luminance High */ - {0x1, 0x0003, 0x003F}, /* CCDSP Gamma correction toggle */ - -#ifdef ALTER_GAMMA - {0x1, 0x0010, 0x0008}, /* CCDSP YUV A11 */ - {0x1, 0x0000, 0x0009}, /* CCDSP YUV A12 */ - {0x1, 0x0000, 0x000a}, /* CCDSP YUV A13 */ - {0x1, 0x0000, 0x000b}, /* CCDSP YUV A21 */ - {0x1, 0x0010, 0x000c}, /* CCDSP YUV A22 */ - {0x1, 0x0000, 0x000d}, /* CCDSP YUV A23 */ - {0x1, 0x0000, 0x000e}, /* CCDSP YUV A31 */ - {0x1, 0x0000, 0x000f}, /* CCDSP YUV A32 */ - {0x1, 0x0010, 0x0010}, /* CCDSP YUV A33 */ - {0x1, 0x0000, 0x0011}, /* CCDSP R Offset */ - {0x1, 0x0000, 0x0012}, /* CCDSP G Offset */ - {0x1, 0x0001, 0x0013}, /* CCDSP B Offset */ - {0x1, 0x0001, 0x0014}, /* CCDSP BG Offset */ - {0x1, 0x003f, 0x00C1}, /* CCDSP Gamma Correction Enable */ -#endif -#endif - -#ifdef TG_SET - {0x0, 0x00fc, 0x0000}, /* TG Shutter Speed High Bits */ - {0x0, 0x0000, 0x0001}, /* TG Shutter Speed Low Bits */ - {0x0, 0x00e4, 0x0004}, /* TG DCLK*2 Adjust */ - {0x0, 0x0008, 0x0005}, /* TG ADCK Adjust */ - {0x0, 0x0003, 0x0006}, /* TG FR Phase Adjust */ - {0x0, 0x0001, 0x0007}, /* TG FCDS Phase Adjust */ - {0x0, 0x0039, 0x0008}, /* TG FS Phase Adjust */ - {0x0, 0x0088, 0x000a}, /* TG MH1 */ - {0x0, 0x0003, 0x000f}, /* TG Pixel ID */ - - /* Like below, unexplained toglleing */ - {0x0, 0x0080, 0x000c}, - {0x0, 0x0000, 0x000d}, - {0x0, 0x0080, 0x000c}, - {0x0, 0x0004, 0x000d}, - {0x0, 0x0000, 0x000c}, - {0x0, 0x0000, 0x000d}, - {0x0, 0x0040, 0x000c}, - {0x0, 0x0017, 0x000d}, - {0x0, 0x00c0, 0x000c}, - {0x0, 0x0000, 0x000d}, - {0x0, 0x0080, 0x000c}, - {0x0, 0x0006, 0x000d}, - {0x0, 0x0080, 0x000c}, - {0x0, 0x0004, 0x000d}, - {0x0, 0x0002, 0x0003}, -#endif - -#ifdef DSPWIN_SET - {0x1, 0x001c, 0x0017}, /* CCDSP W1 Start X */ - {0x1, 0x00e2, 0x0019}, /* CCDSP W2 Start X */ - {0x1, 0x001c, 0x001b}, /* CCDSP W3 Start X */ - {0x1, 0x00e2, 0x001d}, /* CCDSP W4 Start X */ - {0x1, 0x00aa, 0x001f}, /* CCDSP W5 Start X */ - {0x1, 0x0070, 0x0020}, /* CCDSP W5 Start Y */ -#endif - {0x0, 0x0001, 0x0010}, /* TG Start Clock */ - -/* {0x2, 0x006a, 0x0001}, * C/S Enable ISOSYNCH Packet Engine */ - {0x2, 0x0068, 0x0001}, /* C/S Diable ISOSYNCH Packet Engine */ - {0x2, 0x0000, 0x0005}, - {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */ - {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */ - {0x2, 0x0002, 0x0005}, /* C/S GPIO */ - {0x2, 0x0003, 0x0005}, /* C/S GPIO */ - - {0x2, 0x006a, 0x0001}, /* C/S Enable ISOSYNCH Packet Engine */ - {} -}; - -/* - * Data used to initialize a SPCA501C with HV7131B sensor. - * From a capture file taken with USBSnoop v 1.5 - * I have a "SPCA501C pc camera chipset" manual by sunplus, but some - * of the value meanings are obscure or simply "reserved". - * to do list: - * 1) Understand what every value means - * 2) Understand why some values seem to appear more than once - * 3) Write a small comment for each line of the following arrays. - */ -static const __u16 spca501c_arowana_open_data[][3] = { - /* bmRequest,value,index */ - {0x02, 0x0007, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x01, 0x0006, 0x0011}, - {0x01, 0x00ff, 0x0012}, - {0x01, 0x0014, 0x0013}, - {0x01, 0x0000, 0x0014}, - {0x01, 0x0042, 0x0051}, - {0x01, 0x0040, 0x0052}, - {0x01, 0x0051, 0x0053}, - {0x01, 0x0040, 0x0054}, - {0x01, 0x0000, 0x0055}, - {0x00, 0x0025, 0x0000}, - {0x00, 0x0026, 0x0000}, - {0x00, 0x0001, 0x0000}, - {0x00, 0x0027, 0x0000}, - {0x00, 0x008a, 0x0000}, - {} -}; - -static const __u16 spca501c_arowana_init_data[][3] = { - /* bmRequest,value,index */ - {0x02, 0x0007, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x01, 0x0006, 0x0011}, - {0x01, 0x00ff, 0x0012}, - {0x01, 0x0014, 0x0013}, - {0x01, 0x0000, 0x0014}, - {0x01, 0x0042, 0x0051}, - {0x01, 0x0040, 0x0052}, - {0x01, 0x0051, 0x0053}, - {0x01, 0x0040, 0x0054}, - {0x01, 0x0000, 0x0055}, - {0x00, 0x0025, 0x0000}, - {0x00, 0x0026, 0x0000}, - {0x00, 0x0001, 0x0000}, - {0x00, 0x0027, 0x0000}, - {0x00, 0x008a, 0x0000}, - {0x02, 0x0000, 0x0005}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x2000, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0015, 0x0001}, - {0x05, 0x00ea, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0023, 0x0001}, - {0x05, 0x0003, 0x0000}, - {0x05, 0x0030, 0x0001}, - {0x05, 0x002b, 0x0000}, - {0x05, 0x0031, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0032, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0033, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0034, 0x0001}, - {0x05, 0x0002, 0x0000}, - {0x05, 0x0050, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0051, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0052, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0054, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x00, 0x0000, 0x0001}, - {0x00, 0x0000, 0x0002}, - {0x00, 0x000c, 0x0003}, - {0x00, 0x0000, 0x0004}, - {0x00, 0x0090, 0x0005}, - {0x00, 0x0000, 0x0006}, - {0x00, 0x0040, 0x0007}, - {0x00, 0x00c0, 0x0008}, - {0x00, 0x004a, 0x0009}, - {0x00, 0x0000, 0x000a}, - {0x00, 0x0000, 0x000b}, - {0x00, 0x0001, 0x000c}, - {0x00, 0x0001, 0x000d}, - {0x00, 0x0000, 0x000e}, - {0x00, 0x0002, 0x000f}, - {0x00, 0x0001, 0x0010}, - {0x00, 0x0000, 0x0011}, - {0x00, 0x0000, 0x0012}, - {0x00, 0x0002, 0x0020}, - {0x00, 0x0080, 0x0021}, - {0x00, 0x0001, 0x0022}, - {0x00, 0x00e0, 0x0023}, - {0x00, 0x0000, 0x0024}, - {0x00, 0x00d5, 0x0025}, - {0x00, 0x0000, 0x0026}, - {0x00, 0x000b, 0x0027}, - {0x00, 0x0000, 0x0046}, - {0x00, 0x0000, 0x0047}, - {0x00, 0x0000, 0x0048}, - {0x00, 0x0000, 0x0049}, - {0x00, 0x0008, 0x004a}, - {0xff, 0x0000, 0x00d0}, - {0xff, 0x00d8, 0x00d1}, - {0xff, 0x0000, 0x00d4}, - {0xff, 0x0000, 0x00d5}, - {0x01, 0x00a6, 0x0000}, - {0x01, 0x0028, 0x0001}, - {0x01, 0x0000, 0x0002}, - {0x01, 0x000a, 0x0003}, - {0x01, 0x0040, 0x0004}, - {0x01, 0x0066, 0x0007}, - {0x01, 0x0011, 0x0008}, - {0x01, 0x0032, 0x0009}, - {0x01, 0x00fd, 0x000a}, - {0x01, 0x0038, 0x000b}, - {0x01, 0x00d1, 0x000c}, - {0x01, 0x00f7, 0x000d}, - {0x01, 0x00ed, 0x000e}, - {0x01, 0x00d8, 0x000f}, - {0x01, 0x0038, 0x0010}, - {0x01, 0x00ff, 0x0015}, - {0x01, 0x0001, 0x0016}, - {0x01, 0x0032, 0x0017}, - {0x01, 0x0023, 0x0018}, - {0x01, 0x00ce, 0x0019}, - {0x01, 0x0023, 0x001a}, - {0x01, 0x0032, 0x001b}, - {0x01, 0x008d, 0x001c}, - {0x01, 0x00ce, 0x001d}, - {0x01, 0x008d, 0x001e}, - {0x01, 0x0000, 0x001f}, - {0x01, 0x0000, 0x0020}, - {0x01, 0x00ff, 0x003e}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0000, 0x0040}, - {0x01, 0x0035, 0x0041}, - {0x01, 0x0053, 0x0042}, - {0x01, 0x0069, 0x0043}, - {0x01, 0x007c, 0x0044}, - {0x01, 0x008c, 0x0045}, - {0x01, 0x009a, 0x0046}, - {0x01, 0x00a8, 0x0047}, - {0x01, 0x00b4, 0x0048}, - {0x01, 0x00bf, 0x0049}, - {0x01, 0x00ca, 0x004a}, - {0x01, 0x00d4, 0x004b}, - {0x01, 0x00dd, 0x004c}, - {0x01, 0x00e7, 0x004d}, - {0x01, 0x00ef, 0x004e}, - {0x01, 0x00f8, 0x004f}, - {0x01, 0x00ff, 0x0050}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x0060, 0x0057}, - {0x01, 0x0040, 0x0058}, - {0x01, 0x0011, 0x0059}, - {0x01, 0x0001, 0x005a}, - {0x02, 0x0007, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x0015, 0x0006}, - {0x02, 0x100a, 0x0007}, - {0x02, 0xa048, 0x0000}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x000f, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0025, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0001, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0020, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x00, 0x0090, 0x0005}, - {0x01, 0x00a6, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x2000, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0015, 0x0001}, - {0x05, 0x00ea, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0023, 0x0001}, - {0x05, 0x0003, 0x0000}, - {0x05, 0x0030, 0x0001}, - {0x05, 0x002b, 0x0000}, - {0x05, 0x0031, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0032, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0033, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0034, 0x0001}, - {0x05, 0x0002, 0x0000}, - {0x05, 0x0050, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0051, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0052, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0054, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x00, 0x0000, 0x0001}, - {0x00, 0x0000, 0x0002}, - {0x00, 0x000c, 0x0003}, - {0x00, 0x0000, 0x0004}, - {0x00, 0x0090, 0x0005}, - {0x00, 0x0000, 0x0006}, - {0x00, 0x0040, 0x0007}, - {0x00, 0x00c0, 0x0008}, - {0x00, 0x004a, 0x0009}, - {0x00, 0x0000, 0x000a}, - {0x00, 0x0000, 0x000b}, - {0x00, 0x0001, 0x000c}, - {0x00, 0x0001, 0x000d}, - {0x00, 0x0000, 0x000e}, - {0x00, 0x0002, 0x000f}, - {0x00, 0x0001, 0x0010}, - {0x00, 0x0000, 0x0011}, - {0x00, 0x0000, 0x0012}, - {0x00, 0x0002, 0x0020}, - {0x00, 0x0080, 0x0021}, - {0x00, 0x0001, 0x0022}, - {0x00, 0x00e0, 0x0023}, - {0x00, 0x0000, 0x0024}, - {0x00, 0x00d5, 0x0025}, - {0x00, 0x0000, 0x0026}, - {0x00, 0x000b, 0x0027}, - {0x00, 0x0000, 0x0046}, - {0x00, 0x0000, 0x0047}, - {0x00, 0x0000, 0x0048}, - {0x00, 0x0000, 0x0049}, - {0x00, 0x0008, 0x004a}, - {0xff, 0x0000, 0x00d0}, - {0xff, 0x00d8, 0x00d1}, - {0xff, 0x0000, 0x00d4}, - {0xff, 0x0000, 0x00d5}, - {0x01, 0x00a6, 0x0000}, - {0x01, 0x0028, 0x0001}, - {0x01, 0x0000, 0x0002}, - {0x01, 0x000a, 0x0003}, - {0x01, 0x0040, 0x0004}, - {0x01, 0x0066, 0x0007}, - {0x01, 0x0011, 0x0008}, - {0x01, 0x0032, 0x0009}, - {0x01, 0x00fd, 0x000a}, - {0x01, 0x0038, 0x000b}, - {0x01, 0x00d1, 0x000c}, - {0x01, 0x00f7, 0x000d}, - {0x01, 0x00ed, 0x000e}, - {0x01, 0x00d8, 0x000f}, - {0x01, 0x0038, 0x0010}, - {0x01, 0x00ff, 0x0015}, - {0x01, 0x0001, 0x0016}, - {0x01, 0x0032, 0x0017}, - {0x01, 0x0023, 0x0018}, - {0x01, 0x00ce, 0x0019}, - {0x01, 0x0023, 0x001a}, - {0x01, 0x0032, 0x001b}, - {0x01, 0x008d, 0x001c}, - {0x01, 0x00ce, 0x001d}, - {0x01, 0x008d, 0x001e}, - {0x01, 0x0000, 0x001f}, - {0x01, 0x0000, 0x0020}, - {0x01, 0x00ff, 0x003e}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0000, 0x0040}, - {0x01, 0x0035, 0x0041}, - {0x01, 0x0053, 0x0042}, - {0x01, 0x0069, 0x0043}, - {0x01, 0x007c, 0x0044}, - {0x01, 0x008c, 0x0045}, - {0x01, 0x009a, 0x0046}, - {0x01, 0x00a8, 0x0047}, - {0x01, 0x00b4, 0x0048}, - {0x01, 0x00bf, 0x0049}, - {0x01, 0x00ca, 0x004a}, - {0x01, 0x00d4, 0x004b}, - {0x01, 0x00dd, 0x004c}, - {0x01, 0x00e7, 0x004d}, - {0x01, 0x00ef, 0x004e}, - {0x01, 0x00f8, 0x004f}, - {0x01, 0x00ff, 0x0050}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x0060, 0x0057}, - {0x01, 0x0040, 0x0058}, - {0x01, 0x0011, 0x0059}, - {0x01, 0x0001, 0x005a}, - {0x02, 0x0007, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x0015, 0x0006}, - {0x02, 0x100a, 0x0007}, - {0x02, 0xa048, 0x0000}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x000f, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0025, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0001, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0020, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x00, 0x0090, 0x0005}, - {0x01, 0x00a6, 0x0000}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x0011, 0x0008}, - {0x01, 0x0032, 0x0009}, - {0x01, 0xfffd, 0x000a}, - {0x01, 0x0023, 0x000b}, - {0x01, 0xffea, 0x000c}, - {0x01, 0xfff4, 0x000d}, - {0x01, 0xfffc, 0x000e}, - {0x01, 0xffe3, 0x000f}, - {0x01, 0x001f, 0x0010}, - {0x01, 0x00a8, 0x0001}, - {0x01, 0x0067, 0x0007}, - {0x01, 0x0032, 0x0017}, - {0x01, 0x0023, 0x0018}, - {0x01, 0x00ce, 0x0019}, - {0x01, 0x0023, 0x001a}, - {0x01, 0x0032, 0x001b}, - {0x01, 0x008d, 0x001c}, - {0x01, 0x00ce, 0x001d}, - {0x01, 0x008d, 0x001e}, - {0x01, 0x00c8, 0x0015}, - {0x01, 0x0032, 0x0016}, - {0x01, 0x0000, 0x0011}, - {0x01, 0x0000, 0x0012}, - {0x01, 0x0000, 0x0013}, - {0x01, 0x000a, 0x0003}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x0007, 0x0005}, - {0x02, 0xc000, 0x0001}, - {0x02, 0x0000, 0x0005}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x2000, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0015, 0x0001}, - {0x05, 0x00ea, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0023, 0x0001}, - {0x05, 0x0003, 0x0000}, - {0x05, 0x0030, 0x0001}, - {0x05, 0x002b, 0x0000}, - {0x05, 0x0031, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0032, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0033, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0034, 0x0001}, - {0x05, 0x0002, 0x0000}, - {0x05, 0x0050, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0051, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0052, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0054, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x00, 0x0000, 0x0001}, - {0x00, 0x0000, 0x0002}, - {0x00, 0x000c, 0x0003}, - {0x00, 0x0000, 0x0004}, - {0x00, 0x0090, 0x0005}, - {0x00, 0x0000, 0x0006}, - {0x00, 0x0040, 0x0007}, - {0x00, 0x00c0, 0x0008}, - {0x00, 0x004a, 0x0009}, - {0x00, 0x0000, 0x000a}, - {0x00, 0x0000, 0x000b}, - {0x00, 0x0001, 0x000c}, - {0x00, 0x0001, 0x000d}, - {0x00, 0x0000, 0x000e}, - {0x00, 0x0002, 0x000f}, - {0x00, 0x0001, 0x0010}, - {0x00, 0x0000, 0x0011}, - {0x00, 0x0000, 0x0012}, - {0x00, 0x0002, 0x0020}, - {0x00, 0x0080, 0x0021}, - {0x00, 0x0001, 0x0022}, - {0x00, 0x00e0, 0x0023}, - {0x00, 0x0000, 0x0024}, - {0x00, 0x00d5, 0x0025}, - {0x00, 0x0000, 0x0026}, - {0x00, 0x000b, 0x0027}, - {0x00, 0x0000, 0x0046}, - {0x00, 0x0000, 0x0047}, - {0x00, 0x0000, 0x0048}, - {0x00, 0x0000, 0x0049}, - {0x00, 0x0008, 0x004a}, - {0xff, 0x0000, 0x00d0}, - {0xff, 0x00d8, 0x00d1}, - {0xff, 0x0000, 0x00d4}, - {0xff, 0x0000, 0x00d5}, - {0x01, 0x00a6, 0x0000}, - {0x01, 0x0028, 0x0001}, - {0x01, 0x0000, 0x0002}, - {0x01, 0x000a, 0x0003}, - {0x01, 0x0040, 0x0004}, - {0x01, 0x0066, 0x0007}, - {0x01, 0x0011, 0x0008}, - {0x01, 0x0032, 0x0009}, - {0x01, 0x00fd, 0x000a}, - {0x01, 0x0038, 0x000b}, - {0x01, 0x00d1, 0x000c}, - {0x01, 0x00f7, 0x000d}, - {0x01, 0x00ed, 0x000e}, - {0x01, 0x00d8, 0x000f}, - {0x01, 0x0038, 0x0010}, - {0x01, 0x00ff, 0x0015}, - {0x01, 0x0001, 0x0016}, - {0x01, 0x0032, 0x0017}, - {0x01, 0x0023, 0x0018}, - {0x01, 0x00ce, 0x0019}, - {0x01, 0x0023, 0x001a}, - {0x01, 0x0032, 0x001b}, - {0x01, 0x008d, 0x001c}, - {0x01, 0x00ce, 0x001d}, - {0x01, 0x008d, 0x001e}, - {0x01, 0x0000, 0x001f}, - {0x01, 0x0000, 0x0020}, - {0x01, 0x00ff, 0x003e}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0000, 0x0040}, - {0x01, 0x0035, 0x0041}, - {0x01, 0x0053, 0x0042}, - {0x01, 0x0069, 0x0043}, - {0x01, 0x007c, 0x0044}, - {0x01, 0x008c, 0x0045}, - {0x01, 0x009a, 0x0046}, - {0x01, 0x00a8, 0x0047}, - {0x01, 0x00b4, 0x0048}, - {0x01, 0x00bf, 0x0049}, - {0x01, 0x00ca, 0x004a}, - {0x01, 0x00d4, 0x004b}, - {0x01, 0x00dd, 0x004c}, - {0x01, 0x00e7, 0x004d}, - {0x01, 0x00ef, 0x004e}, - {0x01, 0x00f8, 0x004f}, - {0x01, 0x00ff, 0x0050}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x0060, 0x0057}, - {0x01, 0x0040, 0x0058}, - {0x01, 0x0011, 0x0059}, - {0x01, 0x0001, 0x005a}, - {0x02, 0x0007, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x0015, 0x0006}, - {0x02, 0x100a, 0x0007}, - {0x02, 0xa048, 0x0000}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x000f, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0025, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0001, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0020, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x00, 0x0090, 0x0005}, - {0x01, 0x00a6, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x2000, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0015, 0x0001}, - {0x05, 0x00ea, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0023, 0x0001}, - {0x05, 0x0003, 0x0000}, - {0x05, 0x0030, 0x0001}, - {0x05, 0x002b, 0x0000}, - {0x05, 0x0031, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0032, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0033, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0034, 0x0001}, - {0x05, 0x0002, 0x0000}, - {0x05, 0x0050, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0051, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0052, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0054, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x00, 0x0000, 0x0001}, - {0x00, 0x0000, 0x0002}, - {0x00, 0x000c, 0x0003}, - {0x00, 0x0000, 0x0004}, - {0x00, 0x0090, 0x0005}, - {0x00, 0x0000, 0x0006}, - {0x00, 0x0040, 0x0007}, - {0x00, 0x00c0, 0x0008}, - {0x00, 0x004a, 0x0009}, - {0x00, 0x0000, 0x000a}, - {0x00, 0x0000, 0x000b}, - {0x00, 0x0001, 0x000c}, - {0x00, 0x0001, 0x000d}, - {0x00, 0x0000, 0x000e}, - {0x00, 0x0002, 0x000f}, - {0x00, 0x0001, 0x0010}, - {0x00, 0x0000, 0x0011}, - {0x00, 0x0000, 0x0012}, - {0x00, 0x0002, 0x0020}, - {0x00, 0x0080, 0x0021}, - {0x00, 0x0001, 0x0022}, - {0x00, 0x00e0, 0x0023}, - {0x00, 0x0000, 0x0024}, - {0x00, 0x00d5, 0x0025}, - {0x00, 0x0000, 0x0026}, - {0x00, 0x000b, 0x0027}, - {0x00, 0x0000, 0x0046}, - {0x00, 0x0000, 0x0047}, - {0x00, 0x0000, 0x0048}, - {0x00, 0x0000, 0x0049}, - {0x00, 0x0008, 0x004a}, - {0xff, 0x0000, 0x00d0}, - {0xff, 0x00d8, 0x00d1}, - {0xff, 0x0000, 0x00d4}, - {0xff, 0x0000, 0x00d5}, - {0x01, 0x00a6, 0x0000}, - {0x01, 0x0028, 0x0001}, - {0x01, 0x0000, 0x0002}, - {0x01, 0x000a, 0x0003}, - {0x01, 0x0040, 0x0004}, - {0x01, 0x0066, 0x0007}, - {0x01, 0x0011, 0x0008}, - {0x01, 0x0032, 0x0009}, - {0x01, 0x00fd, 0x000a}, - {0x01, 0x0038, 0x000b}, - {0x01, 0x00d1, 0x000c}, - {0x01, 0x00f7, 0x000d}, - {0x01, 0x00ed, 0x000e}, - {0x01, 0x00d8, 0x000f}, - {0x01, 0x0038, 0x0010}, - {0x01, 0x00ff, 0x0015}, - {0x01, 0x0001, 0x0016}, - {0x01, 0x0032, 0x0017}, - {0x01, 0x0023, 0x0018}, - {0x01, 0x00ce, 0x0019}, - {0x01, 0x0023, 0x001a}, - {0x01, 0x0032, 0x001b}, - {0x01, 0x008d, 0x001c}, - {0x01, 0x00ce, 0x001d}, - {0x01, 0x008d, 0x001e}, - {0x01, 0x0000, 0x001f}, - {0x01, 0x0000, 0x0020}, - {0x01, 0x00ff, 0x003e}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0000, 0x0040}, - {0x01, 0x0035, 0x0041}, - {0x01, 0x0053, 0x0042}, - {0x01, 0x0069, 0x0043}, - {0x01, 0x007c, 0x0044}, - {0x01, 0x008c, 0x0045}, - {0x01, 0x009a, 0x0046}, - {0x01, 0x00a8, 0x0047}, - {0x01, 0x00b4, 0x0048}, - {0x01, 0x00bf, 0x0049}, - {0x01, 0x00ca, 0x004a}, - {0x01, 0x00d4, 0x004b}, - {0x01, 0x00dd, 0x004c}, - {0x01, 0x00e7, 0x004d}, - {0x01, 0x00ef, 0x004e}, - {0x01, 0x00f8, 0x004f}, - {0x01, 0x00ff, 0x0050}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x0060, 0x0057}, - {0x01, 0x0040, 0x0058}, - {0x01, 0x0011, 0x0059}, - {0x01, 0x0001, 0x005a}, - {0x02, 0x0007, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x0015, 0x0006}, - {0x02, 0x100a, 0x0007}, - {0x02, 0xa048, 0x0000}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x000f, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0025, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0001, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0020, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x00, 0x0090, 0x0005}, - {0x01, 0x00a6, 0x0000}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x000f, 0x0000}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x0011, 0x0008}, - {0x01, 0x0032, 0x0009}, - {0x01, 0xfffd, 0x000a}, - {0x01, 0x0023, 0x000b}, - {0x01, 0xffea, 0x000c}, - {0x01, 0xfff4, 0x000d}, - {0x01, 0xfffc, 0x000e}, - {0x01, 0xffe3, 0x000f}, - {0x01, 0x001f, 0x0010}, - {0x01, 0x00a8, 0x0001}, - {0x01, 0x0067, 0x0007}, - {0x01, 0x0042, 0x0051}, - {0x01, 0x0051, 0x0053}, - {0x01, 0x000a, 0x0003}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x0007, 0x0005}, - {0x02, 0xc000, 0x0001}, - {0x02, 0x0000, 0x0005}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x2000, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0015, 0x0001}, - {0x05, 0x00ea, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0023, 0x0001}, - {0x05, 0x0003, 0x0000}, - {0x05, 0x0030, 0x0001}, - {0x05, 0x002b, 0x0000}, - {0x05, 0x0031, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0032, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0033, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0034, 0x0001}, - {0x05, 0x0002, 0x0000}, - {0x05, 0x0050, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0051, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0052, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0054, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x00, 0x0000, 0x0001}, - {0x00, 0x0000, 0x0002}, - {0x00, 0x000c, 0x0003}, - {0x00, 0x0000, 0x0004}, - {0x00, 0x0090, 0x0005}, - {0x00, 0x0000, 0x0006}, - {0x00, 0x0040, 0x0007}, - {0x00, 0x00c0, 0x0008}, - {0x00, 0x004a, 0x0009}, - {0x00, 0x0000, 0x000a}, - {0x00, 0x0000, 0x000b}, - {0x00, 0x0001, 0x000c}, - {0x00, 0x0001, 0x000d}, - {0x00, 0x0000, 0x000e}, - {0x00, 0x0002, 0x000f}, - {0x00, 0x0001, 0x0010}, - {0x00, 0x0000, 0x0011}, - {0x00, 0x0000, 0x0012}, - {0x00, 0x0002, 0x0020}, - {0x00, 0x0080, 0x0021}, - {0x00, 0x0001, 0x0022}, - {0x00, 0x00e0, 0x0023}, - {0x00, 0x0000, 0x0024}, - {0x00, 0x00d5, 0x0025}, - {0x00, 0x0000, 0x0026}, - {0x00, 0x000b, 0x0027}, - {0x00, 0x0000, 0x0046}, - {0x00, 0x0000, 0x0047}, - {0x00, 0x0000, 0x0048}, - {0x00, 0x0000, 0x0049}, - {0x00, 0x0008, 0x004a}, - {0xff, 0x0000, 0x00d0}, - {0xff, 0x00d8, 0x00d1}, - {0xff, 0x0000, 0x00d4}, - {0xff, 0x0000, 0x00d5}, - {0x01, 0x00a6, 0x0000}, - {0x01, 0x0028, 0x0001}, - {0x01, 0x0000, 0x0002}, - {0x01, 0x000a, 0x0003}, - {0x01, 0x0040, 0x0004}, - {0x01, 0x0066, 0x0007}, - {0x01, 0x0011, 0x0008}, - {0x01, 0x0032, 0x0009}, - {0x01, 0x00fd, 0x000a}, - {0x01, 0x0038, 0x000b}, - {0x01, 0x00d1, 0x000c}, - {0x01, 0x00f7, 0x000d}, - {0x01, 0x00ed, 0x000e}, - {0x01, 0x00d8, 0x000f}, - {0x01, 0x0038, 0x0010}, - {0x01, 0x00ff, 0x0015}, - {0x01, 0x0001, 0x0016}, - {0x01, 0x0032, 0x0017}, - {0x01, 0x0023, 0x0018}, - {0x01, 0x00ce, 0x0019}, - {0x01, 0x0023, 0x001a}, - {0x01, 0x0032, 0x001b}, - {0x01, 0x008d, 0x001c}, - {0x01, 0x00ce, 0x001d}, - {0x01, 0x008d, 0x001e}, - {0x01, 0x0000, 0x001f}, - {0x01, 0x0000, 0x0020}, - {0x01, 0x00ff, 0x003e}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0000, 0x0040}, - {0x01, 0x0035, 0x0041}, - {0x01, 0x0053, 0x0042}, - {0x01, 0x0069, 0x0043}, - {0x01, 0x007c, 0x0044}, - {0x01, 0x008c, 0x0045}, - {0x01, 0x009a, 0x0046}, - {0x01, 0x00a8, 0x0047}, - {0x01, 0x00b4, 0x0048}, - {0x01, 0x00bf, 0x0049}, - {0x01, 0x00ca, 0x004a}, - {0x01, 0x00d4, 0x004b}, - {0x01, 0x00dd, 0x004c}, - {0x01, 0x00e7, 0x004d}, - {0x01, 0x00ef, 0x004e}, - {0x01, 0x00f8, 0x004f}, - {0x01, 0x00ff, 0x0050}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x0060, 0x0057}, - {0x01, 0x0040, 0x0058}, - {0x01, 0x0011, 0x0059}, - {0x01, 0x0001, 0x005a}, - {0x02, 0x0007, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x0015, 0x0006}, - {0x02, 0x100a, 0x0007}, - {0x02, 0xa048, 0x0000}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x000f, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0025, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0001, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0020, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x00, 0x0090, 0x0005}, - {0x01, 0x00a6, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x2000, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0015, 0x0001}, - {0x05, 0x00ea, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0023, 0x0001}, - {0x05, 0x0003, 0x0000}, - {0x05, 0x0030, 0x0001}, - {0x05, 0x002b, 0x0000}, - {0x05, 0x0031, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0032, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0033, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0034, 0x0001}, - {0x05, 0x0002, 0x0000}, - {0x05, 0x0050, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0051, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0052, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0054, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x00, 0x0000, 0x0001}, - {0x00, 0x0000, 0x0002}, - {0x00, 0x000c, 0x0003}, - {0x00, 0x0000, 0x0004}, - {0x00, 0x0090, 0x0005}, - {0x00, 0x0000, 0x0006}, - {0x00, 0x0040, 0x0007}, - {0x00, 0x00c0, 0x0008}, - {0x00, 0x004a, 0x0009}, - {0x00, 0x0000, 0x000a}, - {0x00, 0x0000, 0x000b}, - {0x00, 0x0001, 0x000c}, - {0x00, 0x0001, 0x000d}, - {0x00, 0x0000, 0x000e}, - {0x00, 0x0002, 0x000f}, - {0x00, 0x0001, 0x0010}, - {0x00, 0x0000, 0x0011}, - {0x00, 0x0000, 0x0012}, - {0x00, 0x0002, 0x0020}, - {0x00, 0x0080, 0x0021}, - {0x00, 0x0001, 0x0022}, - {0x00, 0x00e0, 0x0023}, - {0x00, 0x0000, 0x0024}, - {0x00, 0x00d5, 0x0025}, - {0x00, 0x0000, 0x0026}, - {0x00, 0x000b, 0x0027}, - {0x00, 0x0000, 0x0046}, - {0x00, 0x0000, 0x0047}, - {0x00, 0x0000, 0x0048}, - {0x00, 0x0000, 0x0049}, - {0x00, 0x0008, 0x004a}, - {0xff, 0x0000, 0x00d0}, - {0xff, 0x00d8, 0x00d1}, - {0xff, 0x0000, 0x00d4}, - {0xff, 0x0000, 0x00d5}, - {0x01, 0x00a6, 0x0000}, - {0x01, 0x0028, 0x0001}, - {0x01, 0x0000, 0x0002}, - {0x01, 0x000a, 0x0003}, - {0x01, 0x0040, 0x0004}, - {0x01, 0x0066, 0x0007}, - {0x01, 0x0011, 0x0008}, - {0x01, 0x0032, 0x0009}, - {0x01, 0x00fd, 0x000a}, - {0x01, 0x0038, 0x000b}, - {0x01, 0x00d1, 0x000c}, - {0x01, 0x00f7, 0x000d}, - {0x01, 0x00ed, 0x000e}, - {0x01, 0x00d8, 0x000f}, - {0x01, 0x0038, 0x0010}, - {0x01, 0x00ff, 0x0015}, - {0x01, 0x0001, 0x0016}, - {0x01, 0x0032, 0x0017}, - {0x01, 0x0023, 0x0018}, - {0x01, 0x00ce, 0x0019}, - {0x01, 0x0023, 0x001a}, - {0x01, 0x0032, 0x001b}, - {0x01, 0x008d, 0x001c}, - {0x01, 0x00ce, 0x001d}, - {0x01, 0x008d, 0x001e}, - {0x01, 0x0000, 0x001f}, - {0x01, 0x0000, 0x0020}, - {0x01, 0x00ff, 0x003e}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0000, 0x0040}, - {0x01, 0x0035, 0x0041}, - {0x01, 0x0053, 0x0042}, - {0x01, 0x0069, 0x0043}, - {0x01, 0x007c, 0x0044}, - {0x01, 0x008c, 0x0045}, - {0x01, 0x009a, 0x0046}, - {0x01, 0x00a8, 0x0047}, - {0x01, 0x00b4, 0x0048}, - {0x01, 0x00bf, 0x0049}, - {0x01, 0x00ca, 0x004a}, - {0x01, 0x00d4, 0x004b}, - {0x01, 0x00dd, 0x004c}, - {0x01, 0x00e7, 0x004d}, - {0x01, 0x00ef, 0x004e}, - {0x01, 0x00f8, 0x004f}, - {0x01, 0x00ff, 0x0050}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x0060, 0x0057}, - {0x01, 0x0040, 0x0058}, - {0x01, 0x0011, 0x0059}, - {0x01, 0x0001, 0x005a}, - {0x02, 0x0007, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x0015, 0x0006}, - {0x02, 0x100a, 0x0007}, - {0x02, 0xa048, 0x0000}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x000f, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0025, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0001, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0020, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x00, 0x0090, 0x0005}, - {0x01, 0x00a6, 0x0000}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x001e, 0x0000}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x0011, 0x0008}, - {0x01, 0x0032, 0x0009}, - {0x01, 0xfffd, 0x000a}, - {0x01, 0x0023, 0x000b}, - {0x01, 0xffea, 0x000c}, - {0x01, 0xfff4, 0x000d}, - {0x01, 0xfffc, 0x000e}, - {0x01, 0xffe3, 0x000f}, - {0x01, 0x001f, 0x0010}, - {0x01, 0x00a8, 0x0001}, - {0x01, 0x0067, 0x0007}, - {0x01, 0x0042, 0x0051}, - {0x01, 0x0051, 0x0053}, - {0x01, 0x000a, 0x0003}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x0007, 0x0005}, - {0x01, 0x0042, 0x0051}, - {0x01, 0x0051, 0x0053}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x002d, 0x0000}, - {0x01, 0x0003, 0x003f}, - {0x01, 0x0001, 0x0056}, - {0x02, 0xc000, 0x0001}, - {0x02, 0x0000, 0x0005}, - {} -}; - -/* Unknown camera from Ori Usbid 0x0000:0x0000 */ -/* Based on snoops from Ori Cohen */ -static const __u16 spca501c_mysterious_open_data[][3] = { - {0x02, 0x000f, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, -/* DSP Registers */ - {0x01, 0x0016, 0x0011}, /* RGB offset */ - {0x01, 0x0000, 0x0012}, - {0x01, 0x0006, 0x0013}, - {0x01, 0x0078, 0x0051}, - {0x01, 0x0040, 0x0052}, - {0x01, 0x0046, 0x0053}, - {0x01, 0x0040, 0x0054}, - {0x00, 0x0025, 0x0000}, -/* {0x00, 0x0000, 0x0000 }, */ -/* Part 2 */ -/* TG Registers */ - {0x00, 0x0026, 0x0000}, - {0x00, 0x0001, 0x0000}, - {0x00, 0x0027, 0x0000}, - {0x00, 0x008a, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x2000, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0015, 0x0001}, - {0x05, 0x00ea, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0023, 0x0001}, - {0x05, 0x0003, 0x0000}, - {0x05, 0x0030, 0x0001}, - {0x05, 0x002b, 0x0000}, - {0x05, 0x0031, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0032, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0033, 0x0001}, - {0x05, 0x0023, 0x0000}, - {0x05, 0x0034, 0x0001}, - {0x05, 0x0002, 0x0000}, - {0x05, 0x0050, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0051, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0052, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0054, 0x0001}, - {0x05, 0x0001, 0x0000}, - {} -}; - -/* Based on snoops from Ori Cohen */ -static const __u16 spca501c_mysterious_init_data[][3] = { -/* Part 3 */ -/* TG registers */ -/* {0x00, 0x0000, 0x0000}, */ - {0x00, 0x0000, 0x0001}, - {0x00, 0x0000, 0x0002}, - {0x00, 0x0006, 0x0003}, - {0x00, 0x0000, 0x0004}, - {0x00, 0x0090, 0x0005}, - {0x00, 0x0000, 0x0006}, - {0x00, 0x0040, 0x0007}, - {0x00, 0x00c0, 0x0008}, - {0x00, 0x004a, 0x0009}, - {0x00, 0x0000, 0x000a}, - {0x00, 0x0000, 0x000b}, - {0x00, 0x0001, 0x000c}, - {0x00, 0x0001, 0x000d}, - {0x00, 0x0000, 0x000e}, - {0x00, 0x0002, 0x000f}, - {0x00, 0x0001, 0x0010}, - {0x00, 0x0000, 0x0011}, - {0x00, 0x0001, 0x0012}, - {0x00, 0x0002, 0x0020}, - {0x00, 0x0080, 0x0021}, /* 640 */ - {0x00, 0x0001, 0x0022}, - {0x00, 0x00e0, 0x0023}, /* 480 */ - {0x00, 0x0000, 0x0024}, /* Offset H hight */ - {0x00, 0x00d3, 0x0025}, /* low */ - {0x00, 0x0000, 0x0026}, /* Offset V */ - {0x00, 0x000d, 0x0027}, /* low */ - {0x00, 0x0000, 0x0046}, - {0x00, 0x0000, 0x0047}, - {0x00, 0x0000, 0x0048}, - {0x00, 0x0000, 0x0049}, - {0x00, 0x0008, 0x004a}, -/* DSP Registers */ - {0x01, 0x00a6, 0x0000}, - {0x01, 0x0028, 0x0001}, - {0x01, 0x0000, 0x0002}, - {0x01, 0x000a, 0x0003}, /* Level Calc bit7 ->1 Auto */ - {0x01, 0x0040, 0x0004}, - {0x01, 0x0066, 0x0007}, - {0x01, 0x000f, 0x0008}, /* A11 Color correction coeff */ - {0x01, 0x002d, 0x0009}, /* A12 */ - {0x01, 0x0005, 0x000a}, /* A13 */ - {0x01, 0x0023, 0x000b}, /* A21 */ - {0x01, 0x00e0, 0x000c}, /* A22 */ - {0x01, 0x00fd, 0x000d}, /* A23 */ - {0x01, 0x00f4, 0x000e}, /* A31 */ - {0x01, 0x00e4, 0x000f}, /* A32 */ - {0x01, 0x0028, 0x0010}, /* A33 */ - {0x01, 0x00ff, 0x0015}, /* Reserved */ - {0x01, 0x0001, 0x0016}, /* Reserved */ - {0x01, 0x0032, 0x0017}, /* Win1 Start begin */ - {0x01, 0x0023, 0x0018}, - {0x01, 0x00ce, 0x0019}, - {0x01, 0x0023, 0x001a}, - {0x01, 0x0032, 0x001b}, - {0x01, 0x008d, 0x001c}, - {0x01, 0x00ce, 0x001d}, - {0x01, 0x008d, 0x001e}, - {0x01, 0x0000, 0x001f}, - {0x01, 0x0000, 0x0020}, /* Win1 Start end */ - {0x01, 0x00ff, 0x003e}, /* Reserved begin */ - {0x01, 0x0002, 0x003f}, - {0x01, 0x0000, 0x0040}, - {0x01, 0x0035, 0x0041}, - {0x01, 0x0053, 0x0042}, - {0x01, 0x0069, 0x0043}, - {0x01, 0x007c, 0x0044}, - {0x01, 0x008c, 0x0045}, - {0x01, 0x009a, 0x0046}, - {0x01, 0x00a8, 0x0047}, - {0x01, 0x00b4, 0x0048}, - {0x01, 0x00bf, 0x0049}, - {0x01, 0x00ca, 0x004a}, - {0x01, 0x00d4, 0x004b}, - {0x01, 0x00dd, 0x004c}, - {0x01, 0x00e7, 0x004d}, - {0x01, 0x00ef, 0x004e}, - {0x01, 0x00f8, 0x004f}, - {0x01, 0x00ff, 0x0050}, - {0x01, 0x0003, 0x0056}, /* Reserved end */ - {0x01, 0x0060, 0x0057}, /* Edge Gain */ - {0x01, 0x0040, 0x0058}, - {0x01, 0x0011, 0x0059}, /* Edge Bandwidth */ - {0x01, 0x0001, 0x005a}, - {0x02, 0x0007, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x02, 0x0007, 0x0005}, - {0x02, 0x0015, 0x0006}, - {0x02, 0x200a, 0x0007}, - {0x02, 0xa048, 0x0000}, - {0x02, 0xc000, 0x0001}, - {0x02, 0x000f, 0x0005}, - {0x02, 0xa048, 0x0000}, - {0x05, 0x0022, 0x0004}, - {0x05, 0x0025, 0x0001}, - {0x05, 0x0000, 0x0000}, -/* Part 4 */ - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0001, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x05, 0x0021, 0x0001}, - {0x05, 0x00d2, 0x0000}, - {0x05, 0x0020, 0x0001}, - {0x05, 0x0000, 0x0000}, - {0x00, 0x0090, 0x0005}, - {0x01, 0x00a6, 0x0000}, - {0x02, 0x0000, 0x0005}, - {0x05, 0x0026, 0x0001}, - {0x05, 0x0001, 0x0000}, - {0x05, 0x0027, 0x0001}, - {0x05, 0x004e, 0x0000}, -/* Part 5 */ - {0x01, 0x0003, 0x003f}, - {0x01, 0x0001, 0x0056}, - {0x01, 0x000f, 0x0008}, - {0x01, 0x002d, 0x0009}, - {0x01, 0x0005, 0x000a}, - {0x01, 0x0023, 0x000b}, - {0x01, 0xffe0, 0x000c}, - {0x01, 0xfffd, 0x000d}, - {0x01, 0xfff4, 0x000e}, - {0x01, 0xffe4, 0x000f}, - {0x01, 0x0028, 0x0010}, - {0x01, 0x00a8, 0x0001}, - {0x01, 0x0066, 0x0007}, - {0x01, 0x0032, 0x0017}, - {0x01, 0x0023, 0x0018}, - {0x01, 0x00ce, 0x0019}, - {0x01, 0x0023, 0x001a}, - {0x01, 0x0032, 0x001b}, - {0x01, 0x008d, 0x001c}, - {0x01, 0x00ce, 0x001d}, - {0x01, 0x008d, 0x001e}, - {0x01, 0x00c8, 0x0015}, /* c8 Poids fort Luma */ - {0x01, 0x0032, 0x0016}, /* 32 */ - {0x01, 0x0016, 0x0011}, /* R 00 */ - {0x01, 0x0016, 0x0012}, /* G 00 */ - {0x01, 0x0016, 0x0013}, /* B 00 */ - {0x01, 0x000a, 0x0003}, - {0x02, 0xc002, 0x0001}, - {0x02, 0x0007, 0x0005}, - {} -}; - -static int reg_write(struct usb_device *dev, - __u16 req, __u16 index, __u16 value) -{ - int ret; - - ret = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - req, - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 500); - PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x", - req, index, value); - if (ret < 0) - err("reg write: error %d", ret); - return ret; -} - - -static int write_vector(struct gspca_dev *gspca_dev, - const __u16 data[][3]) -{ - struct usb_device *dev = gspca_dev->dev; - int ret, i = 0; - - while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { - ret = reg_write(dev, data[i][0], data[i][2], data[i][1]); - if (ret < 0) { - PDEBUG(D_ERR, - "Reg write failed for 0x%02x,0x%02x,0x%02x", - data[i][0], data[i][1], data[i][2]); - return ret; - } - i++; - } - return 0; -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_write(gspca_dev->dev, 0x00, 0x00, - (sd->contrast >> 8) & 0xff); - reg_write(gspca_dev->dev, 0x00, 0x01, - sd->contrast & 0xff); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors); -} - -static void setblue_balance(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->blue_balance); -} - -static void setred_balance(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->red_balance); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - sd->subtype = id->driver_info; - sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value; - sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value; - sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->subtype) { - case Arowana300KCMOSCamera: - case SmileIntlCamera: - /* Arowana 300k CMOS Camera data */ - if (write_vector(gspca_dev, spca501c_arowana_init_data)) - goto error; - break; - case MystFromOriUnknownCamera: - /* Unknown Ori CMOS Camera data */ - if (write_vector(gspca_dev, spca501c_mysterious_open_data)) - goto error; - break; - default: - /* generic spca501 init data */ - if (write_vector(gspca_dev, spca501_init_data)) - goto error; - break; - } - PDEBUG(D_STREAM, "Initializing SPCA501 finished"); - return 0; -error: - return -EINVAL; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; - int mode; - - switch (sd->subtype) { - case ThreeComHomeConnectLite: - /* Special handling for 3com data */ - write_vector(gspca_dev, spca501_3com_open_data); - break; - case Arowana300KCMOSCamera: - case SmileIntlCamera: - /* Arowana 300k CMOS Camera data */ - write_vector(gspca_dev, spca501c_arowana_open_data); - break; - case MystFromOriUnknownCamera: - /* Unknown CMOS Camera data */ - write_vector(gspca_dev, spca501c_mysterious_init_data); - break; - default: - /* Generic 501 open data */ - write_vector(gspca_dev, spca501_open_data); - } - - /* memorize the wanted pixel format */ - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - - /* Enable ISO packet machine CTRL reg=2, - * index=1 bitmask=0x2 (bit ordinal 1) */ - reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94); - switch (mode) { - case 0: /* 640x480 */ - reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a); - break; - case 1: /* 320x240 */ - reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a); - break; - default: -/* case 2: * 160x120 */ - reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a); - break; - } - reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02); - - /* HDG atleast the Intel CreateAndShare needs to have one of its - * brightness / contrast / color set otherwise it assumes what seems - * max contrast. Note that strange enough setting any of these is - * enough to fix the max contrast problem, to be sure we set all 3 */ - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setcolors(gspca_dev); - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - /* Disable ISO packet - * machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */ - reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00); -} - -/* called on streamoff with alt 0 and on disconnect */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - if (!gspca_dev->present) - return; - reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - switch (data[0]) { - case 0: /* start of frame */ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - data += SPCA501_OFFSET_DATA; - len -= SPCA501_OFFSET_DATA; - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - return; - case 0xff: /* drop */ -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; - } - data++; - len--; - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->blue_balance = val; - if (gspca_dev->streaming) - setblue_balance(gspca_dev); - return 0; -} - -static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->blue_balance; - return 0; -} - -static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->red_balance = val; - if (gspca_dev->streaming) - setred_balance(gspca_dev); - return 0; -} - -static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->red_balance; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x040a, 0x0002), .driver_info = KodakDVC325}, - {USB_DEVICE(0x0497, 0xc001), .driver_info = SmileIntlCamera}, - {USB_DEVICE(0x0506, 0x00df), .driver_info = ThreeComHomeConnectLite}, - {USB_DEVICE(0x0733, 0x0401), .driver_info = IntelCreateAndShare}, - {USB_DEVICE(0x0733, 0x0402), .driver_info = ViewQuestM318B}, - {USB_DEVICE(0x1776, 0x501c), .driver_info = Arowana300KCMOSCamera}, - {USB_DEVICE(0x0000, 0x0000), .driver_info = MystFromOriUnknownCamera}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca505.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca505.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca505.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca505.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,827 +0,0 @@ -/* - * SPCA505 chip based cameras initialization data - * - * V4L2 by Jean-Francis Moine - * - * 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, or - * any later version. - * - * 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 - * - */ - -#define MODULE_NAME "spca505" - -#include "gspca.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - u8 brightness; - - u8 subtype; -#define IntelPCCameraPro 0 -#define Nxultra 1 -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 127 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 4}, - {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 3}, - {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -#define SPCA50X_OFFSET_DATA 10 - -#define SPCA50X_REG_USB 0x02 /* spca505 501 */ - -#define SPCA50X_USB_CTRL 0x00 /* spca505 */ -#define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */ - -#define SPCA50X_REG_GLOBAL 0x03 /* spca505 */ -#define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */ -#define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */ - -#define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */ -#define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */ -#define SPCA50X_GMISC3_SAA7113RST 0x20 /* Not sure about this one spca505 */ - -/* Image format and compression control */ -#define SPCA50X_REG_COMPRESS 0x04 - -/* - * Data to initialize a SPCA505. Common to the CCD and external modes - */ -static const u8 spca505_init_data[][3] = { - /* bmRequest,value,index */ - {SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3}, - /* Sensor reset */ - {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3}, - {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1}, - /* Block USB reset */ - {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL, SPCA50X_GLOBAL_MISC0}, - - {0x05, 0x01, 0x10}, - /* Maybe power down some stuff */ - {0x05, 0x0f, 0x11}, - - /* Setup internal CCD ? */ - {0x06, 0x10, 0x08}, - {0x06, 0x00, 0x09}, - {0x06, 0x00, 0x0a}, - {0x06, 0x00, 0x0b}, - {0x06, 0x10, 0x0c}, - {0x06, 0x00, 0x0d}, - {0x06, 0x00, 0x0e}, - {0x06, 0x00, 0x0f}, - {0x06, 0x10, 0x10}, - {0x06, 0x02, 0x11}, - {0x06, 0x00, 0x12}, - {0x06, 0x04, 0x13}, - {0x06, 0x02, 0x14}, - {0x06, 0x8a, 0x51}, - {0x06, 0x40, 0x52}, - {0x06, 0xb6, 0x53}, - {0x06, 0x3d, 0x54}, - {} -}; - -/* - * Data to initialize the camera using the internal CCD - */ -static const u8 spca505_open_data_ccd[][3] = { - /* bmRequest,value,index */ - /* Internal CCD data set */ - {0x03, 0x04, 0x01}, - /* This could be a reset */ - {0x03, 0x00, 0x01}, - - /* Setup compression and image registers. 0x6 and 0x7 seem to be - related to H&V hold, and are resolution mode specific */ - {0x04, 0x10, 0x01}, - /* DIFF(0x50), was (0x10) */ - {0x04, 0x00, 0x04}, - {0x04, 0x00, 0x05}, - {0x04, 0x20, 0x06}, - {0x04, 0x20, 0x07}, - - {0x08, 0x0a, 0x00}, - /* DIFF (0x4a), was (0xa) */ - - {0x05, 0x00, 0x10}, - {0x05, 0x00, 0x11}, - {0x05, 0x00, 0x00}, - /* DIFF not written */ - {0x05, 0x00, 0x01}, - /* DIFF not written */ - {0x05, 0x00, 0x02}, - /* DIFF not written */ - {0x05, 0x00, 0x03}, - /* DIFF not written */ - {0x05, 0x00, 0x04}, - /* DIFF not written */ - {0x05, 0x80, 0x05}, - /* DIFF not written */ - {0x05, 0xe0, 0x06}, - /* DIFF not written */ - {0x05, 0x20, 0x07}, - /* DIFF not written */ - {0x05, 0xa0, 0x08}, - /* DIFF not written */ - {0x05, 0x0, 0x12}, - /* DIFF not written */ - {0x05, 0x02, 0x0f}, - /* DIFF not written */ - {0x05, 0x10, 0x46}, - /* DIFF not written */ - {0x05, 0x8, 0x4a}, - /* DIFF not written */ - - {0x03, 0x08, 0x03}, - /* DIFF (0x3,0x28,0x3) */ - {0x03, 0x08, 0x01}, - {0x03, 0x0c, 0x03}, - /* DIFF not written */ - {0x03, 0x21, 0x00}, - /* DIFF (0x39) */ - -/* Extra block copied from init to hopefully ensure CCD is in a sane state */ - {0x06, 0x10, 0x08}, - {0x06, 0x00, 0x09}, - {0x06, 0x00, 0x0a}, - {0x06, 0x00, 0x0b}, - {0x06, 0x10, 0x0c}, - {0x06, 0x00, 0x0d}, - {0x06, 0x00, 0x0e}, - {0x06, 0x00, 0x0f}, - {0x06, 0x10, 0x10}, - {0x06, 0x02, 0x11}, - {0x06, 0x00, 0x12}, - {0x06, 0x04, 0x13}, - {0x06, 0x02, 0x14}, - {0x06, 0x8a, 0x51}, - {0x06, 0x40, 0x52}, - {0x06, 0xb6, 0x53}, - {0x06, 0x3d, 0x54}, - /* End of extra block */ - - {0x06, 0x3f, 0x1}, - /* Block skipped */ - {0x06, 0x10, 0x02}, - {0x06, 0x64, 0x07}, - {0x06, 0x10, 0x08}, - {0x06, 0x00, 0x09}, - {0x06, 0x00, 0x0a}, - {0x06, 0x00, 0x0b}, - {0x06, 0x10, 0x0c}, - {0x06, 0x00, 0x0d}, - {0x06, 0x00, 0x0e}, - {0x06, 0x00, 0x0f}, - {0x06, 0x10, 0x10}, - {0x06, 0x02, 0x11}, - {0x06, 0x00, 0x12}, - {0x06, 0x04, 0x13}, - {0x06, 0x02, 0x14}, - {0x06, 0x8a, 0x51}, - {0x06, 0x40, 0x52}, - {0x06, 0xb6, 0x53}, - {0x06, 0x3d, 0x54}, - {0x06, 0x60, 0x57}, - {0x06, 0x20, 0x58}, - {0x06, 0x15, 0x59}, - {0x06, 0x05, 0x5a}, - - {0x05, 0x01, 0xc0}, - {0x05, 0x10, 0xcb}, - {0x05, 0x80, 0xc1}, - /* */ - {0x05, 0x0, 0xc2}, - /* 4 was 0 */ - {0x05, 0x00, 0xca}, - {0x05, 0x80, 0xc1}, - /* */ - {0x05, 0x04, 0xc2}, - {0x05, 0x00, 0xca}, - {0x05, 0x0, 0xc1}, - /* */ - {0x05, 0x00, 0xc2}, - {0x05, 0x00, 0xca}, - {0x05, 0x40, 0xc1}, - /* */ - {0x05, 0x17, 0xc2}, - {0x05, 0x00, 0xca}, - {0x05, 0x80, 0xc1}, - /* */ - {0x05, 0x06, 0xc2}, - {0x05, 0x00, 0xca}, - {0x05, 0x80, 0xc1}, - /* */ - {0x05, 0x04, 0xc2}, - {0x05, 0x00, 0xca}, - - {0x03, 0x4c, 0x3}, - {0x03, 0x18, 0x1}, - - {0x06, 0x70, 0x51}, - {0x06, 0xbe, 0x53}, - {0x06, 0x71, 0x57}, - {0x06, 0x20, 0x58}, - {0x06, 0x05, 0x59}, - {0x06, 0x15, 0x5a}, - - {0x04, 0x00, 0x08}, - /* Compress = OFF (0x1 to turn on) */ - {0x04, 0x12, 0x09}, - {0x04, 0x21, 0x0a}, - {0x04, 0x10, 0x0b}, - {0x04, 0x21, 0x0c}, - {0x04, 0x05, 0x00}, - /* was 5 (Image Type ? ) */ - {0x04, 0x00, 0x01}, - - {0x06, 0x3f, 0x01}, - - {0x04, 0x00, 0x04}, - {0x04, 0x00, 0x05}, - {0x04, 0x40, 0x06}, - {0x04, 0x40, 0x07}, - - {0x06, 0x1c, 0x17}, - {0x06, 0xe2, 0x19}, - {0x06, 0x1c, 0x1b}, - {0x06, 0xe2, 0x1d}, - {0x06, 0xaa, 0x1f}, - {0x06, 0x70, 0x20}, - - {0x05, 0x01, 0x10}, - {0x05, 0x00, 0x11}, - {0x05, 0x01, 0x00}, - {0x05, 0x05, 0x01}, - {0x05, 0x00, 0xc1}, - /* */ - {0x05, 0x00, 0xc2}, - {0x05, 0x00, 0xca}, - - {0x06, 0x70, 0x51}, - {0x06, 0xbe, 0x53}, - {} -}; - -/* - * Made by Tomasz Zablocki (skalamandra@poczta.onet.pl) - * SPCA505b chip based cameras initialization data - */ -/* jfm */ -#define initial_brightness 0x7f /* 0x0(white)-0xff(black) */ -/* #define initial_brightness 0x0 //0x0(white)-0xff(black) */ -/* - * Data to initialize a SPCA505. Common to the CCD and external modes - */ -static const u8 spca505b_init_data[][3] = { -/* start */ - {0x02, 0x00, 0x00}, /* init */ - {0x02, 0x00, 0x01}, - {0x02, 0x00, 0x02}, - {0x02, 0x00, 0x03}, - {0x02, 0x00, 0x04}, - {0x02, 0x00, 0x05}, - {0x02, 0x00, 0x06}, - {0x02, 0x00, 0x07}, - {0x02, 0x00, 0x08}, - {0x02, 0x00, 0x09}, - {0x03, 0x00, 0x00}, - {0x03, 0x00, 0x01}, - {0x03, 0x00, 0x02}, - {0x03, 0x00, 0x03}, - {0x03, 0x00, 0x04}, - {0x03, 0x00, 0x05}, - {0x03, 0x00, 0x06}, - {0x04, 0x00, 0x00}, - {0x04, 0x00, 0x02}, - {0x04, 0x00, 0x04}, - {0x04, 0x00, 0x05}, - {0x04, 0x00, 0x06}, - {0x04, 0x00, 0x07}, - {0x04, 0x00, 0x08}, - {0x04, 0x00, 0x09}, - {0x04, 0x00, 0x0a}, - {0x04, 0x00, 0x0b}, - {0x04, 0x00, 0x0c}, - {0x07, 0x00, 0x00}, - {0x07, 0x00, 0x03}, - {0x08, 0x00, 0x00}, - {0x08, 0x00, 0x01}, - {0x08, 0x00, 0x02}, - {0x06, 0x18, 0x08}, - {0x06, 0xfc, 0x09}, - {0x06, 0xfc, 0x0a}, - {0x06, 0xfc, 0x0b}, - {0x06, 0x18, 0x0c}, - {0x06, 0xfc, 0x0d}, - {0x06, 0xfc, 0x0e}, - {0x06, 0xfc, 0x0f}, - {0x06, 0x18, 0x10}, - {0x06, 0xfe, 0x12}, - {0x06, 0x00, 0x11}, - {0x06, 0x00, 0x14}, - {0x06, 0x00, 0x13}, - {0x06, 0x28, 0x51}, - {0x06, 0xff, 0x53}, - {0x02, 0x00, 0x08}, - - {0x03, 0x00, 0x03}, - {0x03, 0x10, 0x03}, - {} -}; - -/* - * Data to initialize the camera using the internal CCD - */ -static const u8 spca505b_open_data_ccd[][3] = { - -/* {0x02,0x00,0x00}, */ - {0x03, 0x04, 0x01}, /* rst */ - {0x03, 0x00, 0x01}, - {0x03, 0x00, 0x00}, - {0x03, 0x21, 0x00}, - {0x03, 0x00, 0x04}, - {0x03, 0x00, 0x03}, - {0x03, 0x18, 0x03}, - {0x03, 0x08, 0x01}, - {0x03, 0x1c, 0x03}, - {0x03, 0x5c, 0x03}, - {0x03, 0x5c, 0x03}, - {0x03, 0x18, 0x01}, - -/* same as 505 */ - {0x04, 0x10, 0x01}, - {0x04, 0x00, 0x04}, - {0x04, 0x00, 0x05}, - {0x04, 0x20, 0x06}, - {0x04, 0x20, 0x07}, - - {0x08, 0x0a, 0x00}, - - {0x05, 0x00, 0x10}, - {0x05, 0x00, 0x11}, - {0x05, 0x00, 0x12}, - {0x05, 0x6f, 0x00}, - {0x05, initial_brightness >> 6, 0x00}, - {0x05, (initial_brightness << 2) & 0xff, 0x01}, - {0x05, 0x00, 0x02}, - {0x05, 0x01, 0x03}, - {0x05, 0x00, 0x04}, - {0x05, 0x03, 0x05}, - {0x05, 0xe0, 0x06}, - {0x05, 0x20, 0x07}, - {0x05, 0xa0, 0x08}, - {0x05, 0x00, 0x12}, - {0x05, 0x02, 0x0f}, - {0x05, 0x80, 0x14}, /* max exposure off (0=on) */ - {0x05, 0x01, 0xb0}, - {0x05, 0x01, 0xbf}, - {0x03, 0x02, 0x06}, - {0x05, 0x10, 0x46}, - {0x05, 0x08, 0x4a}, - - {0x06, 0x00, 0x01}, - {0x06, 0x10, 0x02}, - {0x06, 0x64, 0x07}, - {0x06, 0x18, 0x08}, - {0x06, 0xfc, 0x09}, - {0x06, 0xfc, 0x0a}, - {0x06, 0xfc, 0x0b}, - {0x04, 0x00, 0x01}, - {0x06, 0x18, 0x0c}, - {0x06, 0xfc, 0x0d}, - {0x06, 0xfc, 0x0e}, - {0x06, 0xfc, 0x0f}, - {0x06, 0x11, 0x10}, /* contrast */ - {0x06, 0x00, 0x11}, - {0x06, 0xfe, 0x12}, - {0x06, 0x00, 0x13}, - {0x06, 0x00, 0x14}, - {0x06, 0x9d, 0x51}, - {0x06, 0x40, 0x52}, - {0x06, 0x7c, 0x53}, - {0x06, 0x40, 0x54}, - {0x06, 0x02, 0x57}, - {0x06, 0x03, 0x58}, - {0x06, 0x15, 0x59}, - {0x06, 0x05, 0x5a}, - {0x06, 0x03, 0x56}, - {0x06, 0x02, 0x3f}, - {0x06, 0x00, 0x40}, - {0x06, 0x39, 0x41}, - {0x06, 0x69, 0x42}, - {0x06, 0x87, 0x43}, - {0x06, 0x9e, 0x44}, - {0x06, 0xb1, 0x45}, - {0x06, 0xbf, 0x46}, - {0x06, 0xcc, 0x47}, - {0x06, 0xd5, 0x48}, - {0x06, 0xdd, 0x49}, - {0x06, 0xe3, 0x4a}, - {0x06, 0xe8, 0x4b}, - {0x06, 0xed, 0x4c}, - {0x06, 0xf2, 0x4d}, - {0x06, 0xf7, 0x4e}, - {0x06, 0xfc, 0x4f}, - {0x06, 0xff, 0x50}, - - {0x05, 0x01, 0xc0}, - {0x05, 0x10, 0xcb}, - {0x05, 0x40, 0xc1}, - {0x05, 0x04, 0xc2}, - {0x05, 0x00, 0xca}, - {0x05, 0x40, 0xc1}, - {0x05, 0x09, 0xc2}, - {0x05, 0x00, 0xca}, - {0x05, 0xc0, 0xc1}, - {0x05, 0x09, 0xc2}, - {0x05, 0x00, 0xca}, - {0x05, 0x40, 0xc1}, - {0x05, 0x59, 0xc2}, - {0x05, 0x00, 0xca}, - {0x04, 0x00, 0x01}, - {0x05, 0x80, 0xc1}, - {0x05, 0xec, 0xc2}, - {0x05, 0x0, 0xca}, - - {0x06, 0x02, 0x57}, - {0x06, 0x01, 0x58}, - {0x06, 0x15, 0x59}, - {0x06, 0x0a, 0x5a}, - {0x06, 0x01, 0x57}, - {0x06, 0x8a, 0x03}, - {0x06, 0x0a, 0x6c}, - {0x06, 0x30, 0x01}, - {0x06, 0x20, 0x02}, - {0x06, 0x00, 0x03}, - - {0x05, 0x8c, 0x25}, - - {0x06, 0x4d, 0x51}, /* maybe saturation (4d) */ - {0x06, 0x84, 0x53}, /* making green (84) */ - {0x06, 0x00, 0x57}, /* sharpness (1) */ - {0x06, 0x18, 0x08}, - {0x06, 0xfc, 0x09}, - {0x06, 0xfc, 0x0a}, - {0x06, 0xfc, 0x0b}, - {0x06, 0x18, 0x0c}, /* maybe hue (18) */ - {0x06, 0xfc, 0x0d}, - {0x06, 0xfc, 0x0e}, - {0x06, 0xfc, 0x0f}, - {0x06, 0x18, 0x10}, /* maybe contrast (18) */ - - {0x05, 0x01, 0x02}, - - {0x04, 0x00, 0x08}, /* compression */ - {0x04, 0x12, 0x09}, - {0x04, 0x21, 0x0a}, - {0x04, 0x10, 0x0b}, - {0x04, 0x21, 0x0c}, - {0x04, 0x1d, 0x00}, /* imagetype (1d) */ - {0x04, 0x41, 0x01}, /* hardware snapcontrol */ - - {0x04, 0x00, 0x04}, - {0x04, 0x00, 0x05}, - {0x04, 0x10, 0x06}, - {0x04, 0x10, 0x07}, - {0x04, 0x40, 0x06}, - {0x04, 0x40, 0x07}, - {0x04, 0x00, 0x04}, - {0x04, 0x00, 0x05}, - - {0x06, 0x1c, 0x17}, - {0x06, 0xe2, 0x19}, - {0x06, 0x1c, 0x1b}, - {0x06, 0xe2, 0x1d}, - {0x06, 0x5f, 0x1f}, - {0x06, 0x32, 0x20}, - - {0x05, initial_brightness >> 6, 0x00}, - {0x05, (initial_brightness << 2) & 0xff, 0x01}, - {0x05, 0x06, 0xc1}, - {0x05, 0x58, 0xc2}, - {0x05, 0x00, 0xca}, - {0x05, 0x00, 0x11}, - {} -}; - -static int reg_write(struct usb_device *dev, - u16 req, u16 index, u16 value) -{ - int ret; - - ret = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - req, - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 500); - PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d", - req, index, value, ret); - if (ret < 0) - err("reg write: error %d", ret); - return ret; -} - -/* returns: negative is error, pos or zero is data */ -static int reg_read(struct gspca_dev *gspca_dev, - u16 req, /* bRequest */ - u16 index) /* wIndex */ -{ - int ret; - - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, - gspca_dev->usb_buf, 2, - 500); /* timeout */ - if (ret < 0) - return ret; - return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; -} - -static int write_vector(struct gspca_dev *gspca_dev, - const u8 data[][3]) -{ - struct usb_device *dev = gspca_dev->dev; - int ret, i = 0; - - while (data[i][0] != 0) { - ret = reg_write(dev, data[i][0], data[i][2], data[i][1]); - if (ret < 0) - return ret; - i++; - } - return 0; -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - cam->cam_mode = vga_mode; - sd->subtype = id->driver_info; - if (sd->subtype != IntelPCCameraPro) - cam->nmodes = ARRAY_SIZE(vga_mode); - else /* no 640x480 for IntelPCCameraPro */ - cam->nmodes = ARRAY_SIZE(vga_mode) - 1; - sd->brightness = BRIGHTNESS_DEF; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (write_vector(gspca_dev, - sd->subtype == Nxultra - ? spca505b_init_data - : spca505_init_data)) - return -EIO; - return 0; -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 brightness = sd->brightness; - - reg_write(gspca_dev->dev, 0x05, 0x00, (255 - brightness) >> 6); - reg_write(gspca_dev->dev, 0x05, 0x01, (255 - brightness) << 2); -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; - int ret, mode; - static u8 mode_tb[][3] = { - /* r00 r06 r07 */ - {0x00, 0x10, 0x10}, /* 640x480 */ - {0x01, 0x1a, 0x1a}, /* 352x288 */ - {0x02, 0x1c, 0x1d}, /* 320x240 */ - {0x04, 0x34, 0x34}, /* 176x144 */ - {0x05, 0x40, 0x40} /* 160x120 */ - }; - - if (sd->subtype == Nxultra) - write_vector(gspca_dev, spca505b_open_data_ccd); - else - write_vector(gspca_dev, spca505_open_data_ccd); - ret = reg_read(gspca_dev, 0x06, 0x16); - - if (ret < 0) { - PDEBUG(D_ERR|D_CONF, - "register read failed err: %d", - ret); - return ret; - } - if (ret != 0x0101) { - err("After vector read returns 0x%04x should be 0x0101", - ret); - } - - ret = reg_write(gspca_dev->dev, 0x06, 0x16, 0x0a); - if (ret < 0) - return ret; - reg_write(gspca_dev->dev, 0x05, 0xc2, 0x12); - - /* necessary because without it we can see stream - * only once after loading module */ - /* stopping usb registers Tomasz change */ - reg_write(dev, 0x02, 0x00, 0x00); - - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - reg_write(dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]); - reg_write(dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]); - reg_write(dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]); - - ret = reg_write(dev, SPCA50X_REG_USB, - SPCA50X_USB_CTRL, - SPCA50X_CUSB_ENABLE); - - setbrightness(gspca_dev); - - return ret; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - /* Disable ISO packet machine */ - reg_write(gspca_dev->dev, 0x02, 0x00, 0x00); -} - -/* called on streamoff with alt 0 and on disconnect */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - if (!gspca_dev->present) - return; - - /* This maybe reset or power control */ - reg_write(gspca_dev->dev, 0x03, 0x03, 0x20); - reg_write(gspca_dev->dev, 0x03, 0x01, 0x00); - reg_write(gspca_dev->dev, 0x03, 0x00, 0x01); - reg_write(gspca_dev->dev, 0x05, 0x10, 0x01); - reg_write(gspca_dev->dev, 0x05, 0x11, 0x0f); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - switch (data[0]) { - case 0: /* start of frame */ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - data += SPCA50X_OFFSET_DATA; - len -= SPCA50X_OFFSET_DATA; - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - break; - case 0xff: /* drop */ - break; - default: - data += 1; - len -= 1; - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - break; - } -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra}, - {USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro}, -/*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca506.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca506.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca506.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca506.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,734 +0,0 @@ -/* - * SPCA506 chip based cameras function - * M Xhaard 15/04/2004 based on different work Mark Taylor and others - * and my own snoopy file on a pv-321c donate by a german compagny - * "Firma Frank Gmbh" from Saarbruecken - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "spca506" - -#include "gspca.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - unsigned char brightness; - unsigned char contrast; - unsigned char colors; - unsigned char hue; - char norme; - char channel; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x80, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x47, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SD_COLOR 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x40, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -#define SD_HUE 3 - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0, - }, - .set = sd_sethue, - .get = sd_gethue, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 5}, - {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 4}, - {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -#define SPCA50X_OFFSET_DATA 10 - -#define SAA7113_bright 0x0a /* defaults 0x80 */ -#define SAA7113_contrast 0x0b /* defaults 0x47 */ -#define SAA7113_saturation 0x0c /* defaults 0x40 */ -#define SAA7113_hue 0x0d /* defaults 0x00 */ -#define SAA7113_I2C_BASE_WRITE 0x4a - -/* read 'len' bytes to gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - __u16 req, - __u16 index, - __u16 length) -{ - usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, length, - 500); -} - -static void reg_w(struct usb_device *dev, - __u16 req, - __u16 value, - __u16 index) -{ - usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, - NULL, 0, 500); -} - -static void spca506_Initi2c(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004); -} - -static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur, - __u16 reg) -{ - int retry = 60; - - reg_w(gspca_dev->dev, 0x07, reg, 0x0001); - reg_w(gspca_dev->dev, 0x07, valeur, 0x0000); - while (retry--) { - reg_r(gspca_dev, 0x07, 0x0003, 2); - if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00) - break; - } -} - -static void spca506_SetNormeInput(struct gspca_dev *gspca_dev, - __u16 norme, - __u16 channel) -{ - struct sd *sd = (struct sd *) gspca_dev; -/* fixme: check if channel == 0..3 and 6..9 (8 values) */ - __u8 setbit0 = 0x00; - __u8 setbit1 = 0x00; - __u8 videomask = 0x00; - - PDEBUG(D_STREAM, "** Open Set Norme **"); - spca506_Initi2c(gspca_dev); - /* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l) */ - /* Composite channel bit1 -> 1 S-video bit 1 -> 0 */ - /* and exclude SAA7113 reserved channel set default 0 otherwise */ - if (norme & V4L2_STD_NTSC) - setbit0 = 0x01; - if (channel == 4 || channel == 5 || channel > 9) - channel = 0; - if (channel < 4) - setbit1 = 0x02; - videomask = (0x48 | setbit0 | setbit1); - reg_w(gspca_dev->dev, 0x08, videomask, 0x0000); - spca506_WriteI2c(gspca_dev, (0xc0 | (channel & 0x0F)), 0x02); - - if (norme & V4L2_STD_NTSC) - spca506_WriteI2c(gspca_dev, 0x33, 0x0e); - /* Chrominance Control NTSC N */ - else if (norme & V4L2_STD_SECAM) - spca506_WriteI2c(gspca_dev, 0x53, 0x0e); - /* Chrominance Control SECAM */ - else - spca506_WriteI2c(gspca_dev, 0x03, 0x0e); - /* Chrominance Control PAL BGHIV */ - - sd->norme = norme; - sd->channel = channel; - PDEBUG(D_STREAM, "Set Video Byte to 0x%2x", videomask); - PDEBUG(D_STREAM, "Set Norme: %08x Channel %d", norme, channel); -} - -static void spca506_GetNormeInput(struct gspca_dev *gspca_dev, - __u16 *norme, __u16 *channel) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* Read the register is not so good value change so - we use your own copy in spca50x struct */ - *norme = sd->norme; - *channel = sd->channel; - PDEBUG(D_STREAM, "Get Norme: %d Channel %d", *norme, *channel); -} - -static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code, - __u16 xmult, __u16 ymult) -{ - struct usb_device *dev = gspca_dev->dev; - - PDEBUG(D_STREAM, "** SetSize **"); - reg_w(dev, 0x04, (0x18 | (code & 0x07)), 0x0000); - /* Soft snap 0x40 Hard 0x41 */ - reg_w(dev, 0x04, 0x41, 0x0001); - reg_w(dev, 0x04, 0x00, 0x0002); - /* reserved */ - reg_w(dev, 0x04, 0x00, 0x0003); - - /* reserved */ - reg_w(dev, 0x04, 0x00, 0x0004); - /* reserved */ - reg_w(dev, 0x04, 0x01, 0x0005); - /* reserced */ - reg_w(dev, 0x04, xmult, 0x0006); - /* reserved */ - reg_w(dev, 0x04, ymult, 0x0007); - /* compression 1 */ - reg_w(dev, 0x04, 0x00, 0x0008); - /* T=64 -> 2 */ - reg_w(dev, 0x04, 0x00, 0x0009); - /* threshold2D */ - reg_w(dev, 0x04, 0x21, 0x000a); - /* quantization */ - reg_w(dev, 0x04, 0x00, 0x000b); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; - sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; - sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; - sd->hue = sd_ctrls[SD_HUE].qctrl.default_value; - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct usb_device *dev = gspca_dev->dev; - - reg_w(dev, 0x03, 0x00, 0x0004); - reg_w(dev, 0x03, 0xFF, 0x0003); - reg_w(dev, 0x03, 0x00, 0x0000); - reg_w(dev, 0x03, 0x1c, 0x0001); - reg_w(dev, 0x03, 0x18, 0x0001); - /* Init on PAL and composite input0 */ - spca506_SetNormeInput(gspca_dev, 0, 0); - reg_w(dev, 0x03, 0x1c, 0x0001); - reg_w(dev, 0x03, 0x18, 0x0001); - reg_w(dev, 0x05, 0x00, 0x0000); - reg_w(dev, 0x05, 0xef, 0x0001); - reg_w(dev, 0x05, 0x00, 0x00c1); - reg_w(dev, 0x05, 0x00, 0x00c2); - reg_w(dev, 0x06, 0x18, 0x0002); - reg_w(dev, 0x06, 0xf5, 0x0011); - reg_w(dev, 0x06, 0x02, 0x0012); - reg_w(dev, 0x06, 0xfb, 0x0013); - reg_w(dev, 0x06, 0x00, 0x0014); - reg_w(dev, 0x06, 0xa4, 0x0051); - reg_w(dev, 0x06, 0x40, 0x0052); - reg_w(dev, 0x06, 0x71, 0x0053); - reg_w(dev, 0x06, 0x40, 0x0054); - /************************************************/ - reg_w(dev, 0x03, 0x00, 0x0004); - reg_w(dev, 0x03, 0x00, 0x0003); - reg_w(dev, 0x03, 0x00, 0x0004); - reg_w(dev, 0x03, 0xFF, 0x0003); - reg_w(dev, 0x02, 0x00, 0x0000); - reg_w(dev, 0x03, 0x60, 0x0000); - reg_w(dev, 0x03, 0x18, 0x0001); - /* for a better reading mx :) */ - /*sdca506_WriteI2c(value,register) */ - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, 0x08, 0x01); - spca506_WriteI2c(gspca_dev, 0xc0, 0x02); - /* input composite video */ - spca506_WriteI2c(gspca_dev, 0x33, 0x03); - spca506_WriteI2c(gspca_dev, 0x00, 0x04); - spca506_WriteI2c(gspca_dev, 0x00, 0x05); - spca506_WriteI2c(gspca_dev, 0x0d, 0x06); - spca506_WriteI2c(gspca_dev, 0xf0, 0x07); - spca506_WriteI2c(gspca_dev, 0x98, 0x08); - spca506_WriteI2c(gspca_dev, 0x03, 0x09); - spca506_WriteI2c(gspca_dev, 0x80, 0x0a); - spca506_WriteI2c(gspca_dev, 0x47, 0x0b); - spca506_WriteI2c(gspca_dev, 0x48, 0x0c); - spca506_WriteI2c(gspca_dev, 0x00, 0x0d); - spca506_WriteI2c(gspca_dev, 0x03, 0x0e); /* Chroma Pal adjust */ - spca506_WriteI2c(gspca_dev, 0x2a, 0x0f); - spca506_WriteI2c(gspca_dev, 0x00, 0x10); - spca506_WriteI2c(gspca_dev, 0x0c, 0x11); - spca506_WriteI2c(gspca_dev, 0xb8, 0x12); - spca506_WriteI2c(gspca_dev, 0x01, 0x13); - spca506_WriteI2c(gspca_dev, 0x00, 0x14); - spca506_WriteI2c(gspca_dev, 0x00, 0x15); - spca506_WriteI2c(gspca_dev, 0x00, 0x16); - spca506_WriteI2c(gspca_dev, 0x00, 0x17); - spca506_WriteI2c(gspca_dev, 0x00, 0x18); - spca506_WriteI2c(gspca_dev, 0x00, 0x19); - spca506_WriteI2c(gspca_dev, 0x00, 0x1a); - spca506_WriteI2c(gspca_dev, 0x00, 0x1b); - spca506_WriteI2c(gspca_dev, 0x00, 0x1c); - spca506_WriteI2c(gspca_dev, 0x00, 0x1d); - spca506_WriteI2c(gspca_dev, 0x00, 0x1e); - spca506_WriteI2c(gspca_dev, 0xa1, 0x1f); - spca506_WriteI2c(gspca_dev, 0x02, 0x40); - spca506_WriteI2c(gspca_dev, 0xff, 0x41); - spca506_WriteI2c(gspca_dev, 0xff, 0x42); - spca506_WriteI2c(gspca_dev, 0xff, 0x43); - spca506_WriteI2c(gspca_dev, 0xff, 0x44); - spca506_WriteI2c(gspca_dev, 0xff, 0x45); - spca506_WriteI2c(gspca_dev, 0xff, 0x46); - spca506_WriteI2c(gspca_dev, 0xff, 0x47); - spca506_WriteI2c(gspca_dev, 0xff, 0x48); - spca506_WriteI2c(gspca_dev, 0xff, 0x49); - spca506_WriteI2c(gspca_dev, 0xff, 0x4a); - spca506_WriteI2c(gspca_dev, 0xff, 0x4b); - spca506_WriteI2c(gspca_dev, 0xff, 0x4c); - spca506_WriteI2c(gspca_dev, 0xff, 0x4d); - spca506_WriteI2c(gspca_dev, 0xff, 0x4e); - spca506_WriteI2c(gspca_dev, 0xff, 0x4f); - spca506_WriteI2c(gspca_dev, 0xff, 0x50); - spca506_WriteI2c(gspca_dev, 0xff, 0x51); - spca506_WriteI2c(gspca_dev, 0xff, 0x52); - spca506_WriteI2c(gspca_dev, 0xff, 0x53); - spca506_WriteI2c(gspca_dev, 0xff, 0x54); - spca506_WriteI2c(gspca_dev, 0xff, 0x55); - spca506_WriteI2c(gspca_dev, 0xff, 0x56); - spca506_WriteI2c(gspca_dev, 0xff, 0x57); - spca506_WriteI2c(gspca_dev, 0x00, 0x58); - spca506_WriteI2c(gspca_dev, 0x54, 0x59); - spca506_WriteI2c(gspca_dev, 0x07, 0x5a); - spca506_WriteI2c(gspca_dev, 0x83, 0x5b); - spca506_WriteI2c(gspca_dev, 0x00, 0x5c); - spca506_WriteI2c(gspca_dev, 0x00, 0x5d); - spca506_WriteI2c(gspca_dev, 0x00, 0x5e); - spca506_WriteI2c(gspca_dev, 0x00, 0x5f); - spca506_WriteI2c(gspca_dev, 0x00, 0x60); - spca506_WriteI2c(gspca_dev, 0x05, 0x61); - spca506_WriteI2c(gspca_dev, 0x9f, 0x62); - PDEBUG(D_STREAM, "** Close Init *"); - return 0; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct usb_device *dev = gspca_dev->dev; - __u16 norme; - __u16 channel; - - /**************************************/ - reg_w(dev, 0x03, 0x00, 0x0004); - reg_w(dev, 0x03, 0x00, 0x0003); - reg_w(dev, 0x03, 0x00, 0x0004); - reg_w(dev, 0x03, 0xFF, 0x0003); - reg_w(dev, 0x02, 0x00, 0x0000); - reg_w(dev, 0x03, 0x60, 0x0000); - reg_w(dev, 0x03, 0x18, 0x0001); - - /*sdca506_WriteI2c(value,register) */ - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, 0x08, 0x01); /* Increment Delay */ -/* spca506_WriteI2c(gspca_dev, 0xc0, 0x02); * Analog Input Control 1 */ - spca506_WriteI2c(gspca_dev, 0x33, 0x03); - /* Analog Input Control 2 */ - spca506_WriteI2c(gspca_dev, 0x00, 0x04); - /* Analog Input Control 3 */ - spca506_WriteI2c(gspca_dev, 0x00, 0x05); - /* Analog Input Control 4 */ - spca506_WriteI2c(gspca_dev, 0x0d, 0x06); - /* Horizontal Sync Start 0xe9-0x0d */ - spca506_WriteI2c(gspca_dev, 0xf0, 0x07); - /* Horizontal Sync Stop 0x0d-0xf0 */ - - spca506_WriteI2c(gspca_dev, 0x98, 0x08); /* Sync Control */ -/* Defaults value */ - spca506_WriteI2c(gspca_dev, 0x03, 0x09); /* Luminance Control */ - spca506_WriteI2c(gspca_dev, 0x80, 0x0a); - /* Luminance Brightness */ - spca506_WriteI2c(gspca_dev, 0x47, 0x0b); /* Luminance Contrast */ - spca506_WriteI2c(gspca_dev, 0x48, 0x0c); - /* Chrominance Saturation */ - spca506_WriteI2c(gspca_dev, 0x00, 0x0d); - /* Chrominance Hue Control */ - spca506_WriteI2c(gspca_dev, 0x2a, 0x0f); - /* Chrominance Gain Control */ - /**************************************/ - spca506_WriteI2c(gspca_dev, 0x00, 0x10); - /* Format/Delay Control */ - spca506_WriteI2c(gspca_dev, 0x0c, 0x11); /* Output Control 1 */ - spca506_WriteI2c(gspca_dev, 0xb8, 0x12); /* Output Control 2 */ - spca506_WriteI2c(gspca_dev, 0x01, 0x13); /* Output Control 3 */ - spca506_WriteI2c(gspca_dev, 0x00, 0x14); /* reserved */ - spca506_WriteI2c(gspca_dev, 0x00, 0x15); /* VGATE START */ - spca506_WriteI2c(gspca_dev, 0x00, 0x16); /* VGATE STOP */ - spca506_WriteI2c(gspca_dev, 0x00, 0x17); /* VGATE Control (MSB) */ - spca506_WriteI2c(gspca_dev, 0x00, 0x18); - spca506_WriteI2c(gspca_dev, 0x00, 0x19); - spca506_WriteI2c(gspca_dev, 0x00, 0x1a); - spca506_WriteI2c(gspca_dev, 0x00, 0x1b); - spca506_WriteI2c(gspca_dev, 0x00, 0x1c); - spca506_WriteI2c(gspca_dev, 0x00, 0x1d); - spca506_WriteI2c(gspca_dev, 0x00, 0x1e); - spca506_WriteI2c(gspca_dev, 0xa1, 0x1f); - spca506_WriteI2c(gspca_dev, 0x02, 0x40); - spca506_WriteI2c(gspca_dev, 0xff, 0x41); - spca506_WriteI2c(gspca_dev, 0xff, 0x42); - spca506_WriteI2c(gspca_dev, 0xff, 0x43); - spca506_WriteI2c(gspca_dev, 0xff, 0x44); - spca506_WriteI2c(gspca_dev, 0xff, 0x45); - spca506_WriteI2c(gspca_dev, 0xff, 0x46); - spca506_WriteI2c(gspca_dev, 0xff, 0x47); - spca506_WriteI2c(gspca_dev, 0xff, 0x48); - spca506_WriteI2c(gspca_dev, 0xff, 0x49); - spca506_WriteI2c(gspca_dev, 0xff, 0x4a); - spca506_WriteI2c(gspca_dev, 0xff, 0x4b); - spca506_WriteI2c(gspca_dev, 0xff, 0x4c); - spca506_WriteI2c(gspca_dev, 0xff, 0x4d); - spca506_WriteI2c(gspca_dev, 0xff, 0x4e); - spca506_WriteI2c(gspca_dev, 0xff, 0x4f); - spca506_WriteI2c(gspca_dev, 0xff, 0x50); - spca506_WriteI2c(gspca_dev, 0xff, 0x51); - spca506_WriteI2c(gspca_dev, 0xff, 0x52); - spca506_WriteI2c(gspca_dev, 0xff, 0x53); - spca506_WriteI2c(gspca_dev, 0xff, 0x54); - spca506_WriteI2c(gspca_dev, 0xff, 0x55); - spca506_WriteI2c(gspca_dev, 0xff, 0x56); - spca506_WriteI2c(gspca_dev, 0xff, 0x57); - spca506_WriteI2c(gspca_dev, 0x00, 0x58); - spca506_WriteI2c(gspca_dev, 0x54, 0x59); - spca506_WriteI2c(gspca_dev, 0x07, 0x5a); - spca506_WriteI2c(gspca_dev, 0x83, 0x5b); - spca506_WriteI2c(gspca_dev, 0x00, 0x5c); - spca506_WriteI2c(gspca_dev, 0x00, 0x5d); - spca506_WriteI2c(gspca_dev, 0x00, 0x5e); - spca506_WriteI2c(gspca_dev, 0x00, 0x5f); - spca506_WriteI2c(gspca_dev, 0x00, 0x60); - spca506_WriteI2c(gspca_dev, 0x05, 0x61); - spca506_WriteI2c(gspca_dev, 0x9f, 0x62); - /**************************************/ - reg_w(dev, 0x05, 0x00, 0x0003); - reg_w(dev, 0x05, 0x00, 0x0004); - reg_w(dev, 0x03, 0x10, 0x0001); - reg_w(dev, 0x03, 0x78, 0x0000); - switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - case 0: - spca506_Setsize(gspca_dev, 0, 0x10, 0x10); - break; - case 1: - spca506_Setsize(gspca_dev, 1, 0x1a, 0x1a); - break; - case 2: - spca506_Setsize(gspca_dev, 2, 0x1c, 0x1c); - break; - case 4: - spca506_Setsize(gspca_dev, 4, 0x34, 0x34); - break; - default: -/* case 5: */ - spca506_Setsize(gspca_dev, 5, 0x40, 0x40); - break; - } - - /* compress setting and size */ - /* set i2c luma */ - reg_w(dev, 0x02, 0x01, 0x0000); - reg_w(dev, 0x03, 0x12, 0x0000); - reg_r(gspca_dev, 0x04, 0x0001, 2); - PDEBUG(D_STREAM, "webcam started"); - spca506_GetNormeInput(gspca_dev, &norme, &channel); - spca506_SetNormeInput(gspca_dev, norme, channel); - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct usb_device *dev = gspca_dev->dev; - - reg_w(dev, 0x02, 0x00, 0x0000); - reg_w(dev, 0x03, 0x00, 0x0004); - reg_w(dev, 0x03, 0x00, 0x0003); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - switch (data[0]) { - case 0: /* start of frame */ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - data += SPCA50X_OFFSET_DATA; - len -= SPCA50X_OFFSET_DATA; - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - break; - case 0xff: /* drop */ -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - break; - default: - data += 1; - len -= 1; - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - break; - } -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, sd->brightness, SAA7113_bright); - spca506_WriteI2c(gspca_dev, 0x01, 0x09); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, sd->contrast, SAA7113_contrast); - spca506_WriteI2c(gspca_dev, 0x01, 0x09); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, sd->colors, SAA7113_saturation); - spca506_WriteI2c(gspca_dev, 0x01, 0x09); -} - -static void sethue(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, sd->hue, SAA7113_hue); - spca506_WriteI2c(gspca_dev, 0x01, 0x09); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hue = val; - if (gspca_dev->streaming) - sethue(gspca_dev); - return 0; -} - -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hue; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] __devinitconst = { - {USB_DEVICE(0x06e1, 0xa190)}, -/*fixme: may be IntelPCCameraPro BRIDGE_SPCA505 - {USB_DEVICE(0x0733, 0x0430)}, */ - {USB_DEVICE(0x0734, 0x043b)}, - {USB_DEVICE(0x99fa, 0x8988)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int __devinit sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - int ret; - ret = usb_register(&sd_driver); - if (ret < 0) - return ret; - PDEBUG(D_PROBE, "registered"); - return 0; -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); - PDEBUG(D_PROBE, "deregistered"); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca508.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca508.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca508.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca508.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1553 +0,0 @@ -/* - * SPCA508 chip based cameras subdriver - * - * Copyright (C) 2009 Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "spca508" - -#include "gspca.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("GSPCA/SPCA508 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - u8 brightness; - - u8 subtype; -#define CreativeVista 0 -#define HamaUSBSightcam 1 -#define HamaUSBSightcam2 2 -#define IntelEasyPCCamera 3 -#define MicroInnovationIC200 4 -#define ViewQuestVQ110 5 -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 128 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -}; - -static const struct v4l2_pix_format sif_mode[] = { - {160, 120, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 3}, - {176, 144, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {320, 240, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {352, 288, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -/* Frame packet header offsets for the spca508 */ -#define SPCA508_OFFSET_DATA 37 - -/* - * Initialization data: this is the first set-up data written to the - * device (before the open data). - */ -static const u16 spca508_init_data[][2] = { - {0x0000, 0x870b}, - - {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */ - {0x0003, 0x8111}, /* Reset compression & memory */ - {0x0000, 0x8110}, /* Disable all outputs */ - /* READ {0x0000, 0x8114} -> 0000: 00 */ - {0x0000, 0x8114}, /* SW GPIO data */ - {0x0008, 0x8110}, /* Enable charge pump output */ - {0x0002, 0x8116}, /* 200 kHz pump clock */ - /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */ - {0x0003, 0x8111}, /* Reset compression & memory */ - {0x0000, 0x8111}, /* Normal mode (not reset) */ - {0x0098, 0x8110}, - /* Enable charge pump output, sync.serial,external 2x clock */ - {0x000d, 0x8114}, /* SW GPIO data */ - {0x0002, 0x8116}, /* 200 kHz pump clock */ - {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */ -/* --------------------------------------- */ - {0x000f, 0x8402}, /* memory bank */ - {0x0000, 0x8403}, /* ... address */ -/* --------------------------------------- */ -/* 0x88__ is Synchronous Serial Interface. */ -/* TBD: This table could be expressed more compactly */ -/* using spca508_write_i2c_vector(). */ -/* TBD: Should see if the values in spca50x_i2c_data */ -/* would work with the VQ110 instead of the values */ -/* below. */ - {0x00c0, 0x8804}, /* SSI slave addr */ - {0x0008, 0x8802}, /* 375 Khz SSI clock */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, /* 375 Khz SSI clock */ - {0x0012, 0x8801}, /* SSI reg addr */ - {0x0080, 0x8800}, /* SSI data to write */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, /* 375 Khz SSI clock */ - {0x0012, 0x8801}, /* SSI reg addr */ - {0x0000, 0x8800}, /* SSI data to write */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, /* 375 Khz SSI clock */ - {0x0011, 0x8801}, /* SSI reg addr */ - {0x0040, 0x8800}, /* SSI data to write */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0013, 0x8801}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0014, 0x8801}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0015, 0x8801}, - {0x0001, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0016, 0x8801}, - {0x0003, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0017, 0x8801}, - {0x0036, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0018, 0x8801}, - {0x00ec, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x001a, 0x8801}, - {0x0094, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x001b, 0x8801}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0027, 0x8801}, - {0x00a2, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0028, 0x8801}, - {0x0040, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x002a, 0x8801}, - {0x0084, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x002b, 0x8801}, - {0x00a8, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x002c, 0x8801}, - {0x00fe, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x002d, 0x8801}, - {0x0003, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0038, 0x8801}, - {0x0083, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0033, 0x8801}, - {0x0081, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0034, 0x8801}, - {0x004a, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0039, 0x8801}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0010, 0x8801}, - {0x00a8, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0006, 0x8801}, - {0x0058, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0000, 0x8801}, - {0x0004, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0040, 0x8801}, - {0x0080, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0041, 0x8801}, - {0x000c, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0042, 0x8801}, - {0x000c, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0043, 0x8801}, - {0x0028, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0044, 0x8801}, - {0x0080, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0045, 0x8801}, - {0x0020, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0046, 0x8801}, - {0x0020, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0047, 0x8801}, - {0x0080, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0048, 0x8801}, - {0x004c, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x0049, 0x8801}, - {0x0084, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x004a, 0x8801}, - {0x0084, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x0008, 0x8802}, - {0x004b, 0x8801}, - {0x0084, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* --------------------------------------- */ - {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ - {0x0000, 0x8701}, /* CKx1 clock delay adj */ - {0x0000, 0x8701}, /* CKx1 clock delay adj */ - {0x0001, 0x870c}, /* CKOx2 output */ - /* --------------------------------------- */ - {0x0080, 0x8600}, /* Line memory read counter (L) */ - {0x0001, 0x8606}, /* reserved */ - {0x0064, 0x8607}, /* Line memory read counter (H) 0x6480=25,728 */ - {0x002a, 0x8601}, /* CDSP sharp interpolation mode, - * line sel for color sep, edge enhance enab */ - {0x0000, 0x8602}, /* optical black level for user settng = 0 */ - {0x0080, 0x8600}, /* Line memory read counter (L) */ - {0x000a, 0x8603}, /* optical black level calc mode: - * auto; optical black offset = 10 */ - {0x00df, 0x865b}, /* Horiz offset for valid pixels (L)=0xdf */ - {0x0012, 0x865c}, /* Vert offset for valid lines (L)=0x12 */ - -/* The following two lines seem to be the "wrong" resolution. */ -/* But perhaps these indicate the actual size of the sensor */ -/* rather than the size of the current video mode. */ - {0x0058, 0x865d}, /* Horiz valid pixels (*4) (L) = 352 */ - {0x0048, 0x865e}, /* Vert valid lines (*4) (L) = 288 */ - - {0x0015, 0x8608}, /* A11 Coef ... */ - {0x0030, 0x8609}, - {0x00fb, 0x860a}, - {0x003e, 0x860b}, - {0x00ce, 0x860c}, - {0x00f4, 0x860d}, - {0x00eb, 0x860e}, - {0x00dc, 0x860f}, - {0x0039, 0x8610}, - {0x0001, 0x8611}, /* R offset for white balance ... */ - {0x0000, 0x8612}, - {0x0001, 0x8613}, - {0x0000, 0x8614}, - {0x005b, 0x8651}, /* R gain for white balance ... */ - {0x0040, 0x8652}, - {0x0060, 0x8653}, - {0x0040, 0x8654}, - {0x0000, 0x8655}, - {0x0001, 0x863f}, /* Fixed gamma correction enable, USB control, - * lum filter disable, lum noise clip disable */ - {0x00a1, 0x8656}, /* Window1 size 256x256, Windows2 size 64x64, - * gamma look-up disable, - * new edge enhancement enable */ - {0x0018, 0x8657}, /* Edge gain high thresh */ - {0x0020, 0x8658}, /* Edge gain low thresh */ - {0x000a, 0x8659}, /* Edge bandwidth high threshold */ - {0x0005, 0x865a}, /* Edge bandwidth low threshold */ - /* -------------------------------- */ - {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0xa908, 0x8802}, - {0x0034, 0x8801}, /* SSI reg addr */ - {0x00ca, 0x8800}, - /* SSI data to write */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0x1f08, 0x8802}, - {0x0006, 0x8801}, - {0x0080, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - -/* ----- Read back coefs we wrote earlier. */ - /* READ { 0x0000, 0x8608 } -> 0000: 15 */ - /* READ { 0x0000, 0x8609 } -> 0000: 30 */ - /* READ { 0x0000, 0x860a } -> 0000: fb */ - /* READ { 0x0000, 0x860b } -> 0000: 3e */ - /* READ { 0x0000, 0x860c } -> 0000: ce */ - /* READ { 0x0000, 0x860d } -> 0000: f4 */ - /* READ { 0x0000, 0x860e } -> 0000: eb */ - /* READ { 0x0000, 0x860f } -> 0000: dc */ - /* READ { 0x0000, 0x8610 } -> 0000: 39 */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 08 */ - {0xb008, 0x8802}, - {0x0006, 0x8801}, - {0x007d, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - - /* This chunk is seemingly redundant with */ - /* earlier commands (A11 Coef...), but if I disable it, */ - /* the image appears too dark. Maybe there was some kind of */ - /* reset since the earlier commands, so this is necessary again. */ - {0x0015, 0x8608}, - {0x0030, 0x8609}, - {0xfffb, 0x860a}, - {0x003e, 0x860b}, - {0xffce, 0x860c}, - {0xfff4, 0x860d}, - {0xffeb, 0x860e}, - {0xffdc, 0x860f}, - {0x0039, 0x8610}, - {0x0018, 0x8657}, - - {0x0000, 0x8508}, /* Disable compression. */ - /* Previous line was: - {0x0021, 0x8508}, * Enable compression. */ - {0x0032, 0x850b}, /* compression stuff */ - {0x0003, 0x8509}, /* compression stuff */ - {0x0011, 0x850a}, /* compression stuff */ - {0x0021, 0x850d}, /* compression stuff */ - {0x0010, 0x850c}, /* compression stuff */ - {0x0003, 0x8500}, /* *** Video mode: 160x120 */ - {0x0001, 0x8501}, /* Hardware-dominated snap control */ - {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128, - * gamma look-up disable, - * new edge enhancement enable */ - {0x0018, 0x8617}, /* Window1 start X (*2) */ - {0x0008, 0x8618}, /* Window1 start Y (*2) */ - {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128, - * gamma look-up disable, - * new edge enhancement enable */ - {0x0058, 0x8619}, /* Window2 start X (*2) */ - {0x0008, 0x861a}, /* Window2 start Y (*2) */ - {0x00ff, 0x8615}, /* High lum thresh for white balance */ - {0x0000, 0x8616}, /* Low lum thresh for white balance */ - {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ - {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ - /* READ { 0x0000, 0x8656 } -> 0000: 61 */ - {0x0028, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 28 */ - {0x1f28, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */ - {0x0010, 0x8801}, /* SSI reg addr */ - {0x003e, 0x8800}, /* SSI data to write */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - {0x0028, 0x8802}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 28 */ - {0x1f28, 0x8802}, - {0x0000, 0x8801}, - {0x001f, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - {0x0001, 0x8602}, /* optical black level for user settning = 1 */ - - /* Original: */ - {0x0023, 0x8700}, /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */ - {0x000f, 0x8602}, /* optical black level for user settning = 15 */ - - {0x0028, 0x8802}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 28 */ - {0x1f28, 0x8802}, - {0x0010, 0x8801}, - {0x007b, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - {0x002f, 0x8651}, /* R gain for white balance ... */ - {0x0080, 0x8653}, - /* READ { 0x0000, 0x8655 } -> 0000: 00 */ - {0x0000, 0x8655}, - - {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */ - {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */ - /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */ - {} -}; - -/* - * Initialization data for Intel EasyPC Camera CS110 - */ -static const u16 spca508cs110_init_data[][2] = { - {0x0000, 0x870b}, /* Reset CTL3 */ - {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */ - {0x0000, 0x8111}, /* Normal operation on reset */ - {0x0090, 0x8110}, - /* External Clock 2x & Synchronous Serial Interface Output */ - {0x0020, 0x8112}, /* Video Drop packet enable */ - {0x0000, 0x8114}, /* Software GPIO output data */ - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0003, 0x8114}, - - /* Initial sequence Synchronous Serial Interface */ - {0x000f, 0x8402}, /* Memory bank Address */ - {0x0000, 0x8403}, /* Memory bank Address */ - {0x00ba, 0x8804}, /* SSI Slave address */ - {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */ - {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */ - - {0x0001, 0x8801}, - {0x000a, 0x8805}, /* a - NWG: Dunno what this is about */ - {0x0000, 0x8800}, - {0x0010, 0x8802}, - - {0x0002, 0x8801}, - {0x0000, 0x8805}, - {0x0000, 0x8800}, - {0x0010, 0x8802}, - - {0x0003, 0x8801}, - {0x0027, 0x8805}, - {0x0001, 0x8800}, - {0x0010, 0x8802}, - - {0x0004, 0x8801}, - {0x0065, 0x8805}, - {0x0001, 0x8800}, - {0x0010, 0x8802}, - - {0x0005, 0x8801}, - {0x0003, 0x8805}, - {0x0000, 0x8800}, - {0x0010, 0x8802}, - - {0x0006, 0x8801}, - {0x001c, 0x8805}, - {0x0000, 0x8800}, - {0x0010, 0x8802}, - - {0x0007, 0x8801}, - {0x002a, 0x8805}, - {0x0000, 0x8800}, - {0x0010, 0x8802}, - - {0x0002, 0x8704}, /* External input CKIx1 */ - {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */ - {0x009a, 0x8600}, /* Line memory Read Counter (L) */ - {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */ - {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */ - {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */ - - {0x0006, 0x8660}, /* Nibble data + input order */ - - {0x000a, 0x8602}, /* Optical black level set to 0x0a */ - {0x0000, 0x8603}, /* Optical black level Offset */ - -/* {0x0000, 0x8611}, * 0 R Offset for white Balance */ -/* {0x0000, 0x8612}, * 1 Gr Offset for white Balance */ -/* {0x0000, 0x8613}, * 1f B Offset for white Balance */ -/* {0x0000, 0x8614}, * f0 Gb Offset for white Balance */ - - {0x0040, 0x8651}, /* 2b BLUE gain for white balance good at all 60 */ - {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */ - {0x0035, 0x8653}, /* 26 RED gain for white balance */ - {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */ - {0x0041, 0x863f}, - /* Fixed Gamma correction enabled (makes colours look better) */ - - {0x0000, 0x8655}, - /* High bits for white balance*****brightness control*** */ - {} -}; - -static const u16 spca508_sightcam_init_data[][2] = { -/* This line seems to setup the frame/canvas */ - {0x000f, 0x8402}, - -/* Theese 6 lines are needed to startup the webcam */ - {0x0090, 0x8110}, - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0003, 0x8114}, - {0x0080, 0x8804}, - -/* This part seems to make the pictures darker? (autobrightness?) */ - {0x0001, 0x8801}, - {0x0004, 0x8800}, - {0x0003, 0x8801}, - {0x00e0, 0x8800}, - {0x0004, 0x8801}, - {0x00b4, 0x8800}, - {0x0005, 0x8801}, - {0x0000, 0x8800}, - - {0x0006, 0x8801}, - {0x00e0, 0x8800}, - {0x0007, 0x8801}, - {0x000c, 0x8800}, - -/* This section is just needed, it probably - * does something like the previous section, - * but the cam won't start if it's not included. - */ - {0x0014, 0x8801}, - {0x0008, 0x8800}, - {0x0015, 0x8801}, - {0x0067, 0x8800}, - {0x0016, 0x8801}, - {0x0000, 0x8800}, - {0x0017, 0x8801}, - {0x0020, 0x8800}, - {0x0018, 0x8801}, - {0x0044, 0x8800}, - -/* Makes the picture darker - and the - * cam won't start if not included - */ - {0x001e, 0x8801}, - {0x00ea, 0x8800}, - {0x001f, 0x8801}, - {0x0001, 0x8800}, - {0x0003, 0x8801}, - {0x00e0, 0x8800}, - -/* seems to place the colors ontop of each other #1 */ - {0x0006, 0x8704}, - {0x0001, 0x870c}, - {0x0016, 0x8600}, - {0x0002, 0x8606}, - -/* if not included the pictures becomes _very_ dark */ - {0x0064, 0x8607}, - {0x003a, 0x8601}, - {0x0000, 0x8602}, - -/* seems to place the colors ontop of each other #2 */ - {0x0016, 0x8600}, - {0x0018, 0x8617}, - {0x0008, 0x8618}, - {0x00a1, 0x8656}, - -/* webcam won't start if not included */ - {0x0007, 0x865b}, - {0x0001, 0x865c}, - {0x0058, 0x865d}, - {0x0048, 0x865e}, - -/* adjusts the colors */ - {0x0049, 0x8651}, - {0x0040, 0x8652}, - {0x004c, 0x8653}, - {0x0040, 0x8654}, - {} -}; - -static const u16 spca508_sightcam2_init_data[][2] = { - {0x0020, 0x8112}, - - {0x000f, 0x8402}, - {0x0000, 0x8403}, - - {0x0008, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x0009, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x000a, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x000b, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x000c, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x000d, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x000e, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x0007, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x000f, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - - {0x0018, 0x8660}, - {0x0010, 0x8201}, - - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x0011, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - - {0x0000, 0x86b0}, - {0x0034, 0x86b1}, - {0x0000, 0x86b2}, - {0x0049, 0x86b3}, - {0x0000, 0x86b4}, - {0x0000, 0x86b4}, - - {0x0012, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - {0x0013, 0x8201}, - {0x0008, 0x8200}, - {0x0001, 0x8200}, - - {0x0001, 0x86b0}, - {0x00aa, 0x86b1}, - {0x0000, 0x86b2}, - {0x00e4, 0x86b3}, - {0x0000, 0x86b4}, - {0x0000, 0x86b4}, - - {0x0018, 0x8660}, - - {0x0090, 0x8110}, - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0003, 0x8114}, - - {0x0080, 0x8804}, - {0x0003, 0x8801}, - {0x0012, 0x8800}, - {0x0004, 0x8801}, - {0x0005, 0x8800}, - {0x0005, 0x8801}, - {0x0000, 0x8800}, - {0x0006, 0x8801}, - {0x0000, 0x8800}, - {0x0007, 0x8801}, - {0x0000, 0x8800}, - {0x0008, 0x8801}, - {0x0005, 0x8800}, - {0x000a, 0x8700}, - {0x000e, 0x8801}, - {0x0004, 0x8800}, - {0x0005, 0x8801}, - {0x0047, 0x8800}, - {0x0006, 0x8801}, - {0x0000, 0x8800}, - {0x0007, 0x8801}, - {0x00c0, 0x8800}, - {0x0008, 0x8801}, - {0x0003, 0x8800}, - {0x0013, 0x8801}, - {0x0001, 0x8800}, - {0x0009, 0x8801}, - {0x0000, 0x8800}, - {0x000a, 0x8801}, - {0x0000, 0x8800}, - {0x000b, 0x8801}, - {0x0000, 0x8800}, - {0x000c, 0x8801}, - {0x0000, 0x8800}, - {0x000e, 0x8801}, - {0x0004, 0x8800}, - {0x000f, 0x8801}, - {0x0000, 0x8800}, - {0x0010, 0x8801}, - {0x0006, 0x8800}, - {0x0011, 0x8801}, - {0x0006, 0x8800}, - {0x0012, 0x8801}, - {0x0000, 0x8800}, - {0x0013, 0x8801}, - {0x0001, 0x8800}, - - {0x000a, 0x8700}, - {0x0000, 0x8702}, - {0x0000, 0x8703}, - {0x00c2, 0x8704}, - {0x0001, 0x870c}, - - {0x0044, 0x8600}, - {0x0002, 0x8606}, - {0x0064, 0x8607}, - {0x003a, 0x8601}, - {0x0008, 0x8602}, - {0x0044, 0x8600}, - {0x0018, 0x8617}, - {0x0008, 0x8618}, - {0x00a1, 0x8656}, - {0x0004, 0x865b}, - {0x0002, 0x865c}, - {0x0058, 0x865d}, - {0x0048, 0x865e}, - {0x0012, 0x8608}, - {0x002c, 0x8609}, - {0x0002, 0x860a}, - {0x002c, 0x860b}, - {0x00db, 0x860c}, - {0x00f9, 0x860d}, - {0x00f1, 0x860e}, - {0x00e3, 0x860f}, - {0x002c, 0x8610}, - {0x006c, 0x8651}, - {0x0041, 0x8652}, - {0x0059, 0x8653}, - {0x0040, 0x8654}, - {0x00fa, 0x8611}, - {0x00ff, 0x8612}, - {0x00f8, 0x8613}, - {0x0000, 0x8614}, - {0x0001, 0x863f}, - {0x0000, 0x8640}, - {0x0026, 0x8641}, - {0x0045, 0x8642}, - {0x0060, 0x8643}, - {0x0075, 0x8644}, - {0x0088, 0x8645}, - {0x009b, 0x8646}, - {0x00b0, 0x8647}, - {0x00c5, 0x8648}, - {0x00d2, 0x8649}, - {0x00dc, 0x864a}, - {0x00e5, 0x864b}, - {0x00eb, 0x864c}, - {0x00f0, 0x864d}, - {0x00f6, 0x864e}, - {0x00fa, 0x864f}, - {0x00ff, 0x8650}, - {0x0060, 0x8657}, - {0x0010, 0x8658}, - {0x0018, 0x8659}, - {0x0005, 0x865a}, - {0x0018, 0x8660}, - {0x0003, 0x8509}, - {0x0011, 0x850a}, - {0x0032, 0x850b}, - {0x0010, 0x850c}, - {0x0021, 0x850d}, - {0x0001, 0x8500}, - {0x0000, 0x8508}, - {0x0012, 0x8608}, - {0x002c, 0x8609}, - {0x0002, 0x860a}, - {0x0039, 0x860b}, - {0x00d0, 0x860c}, - {0x00f7, 0x860d}, - {0x00ed, 0x860e}, - {0x00db, 0x860f}, - {0x0039, 0x8610}, - {0x0012, 0x8657}, - {0x000c, 0x8619}, - {0x0004, 0x861a}, - {0x00a1, 0x8656}, - {0x00c8, 0x8615}, - {0x0032, 0x8616}, - - {0x0030, 0x8112}, - {0x0020, 0x8112}, - {0x0020, 0x8112}, - {0x000f, 0x8402}, - {0x0000, 0x8403}, - - {0x0090, 0x8110}, - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0003, 0x8114}, - {0x0080, 0x8804}, - - {0x0003, 0x8801}, - {0x0012, 0x8800}, - {0x0004, 0x8801}, - {0x0005, 0x8800}, - {0x0005, 0x8801}, - {0x0047, 0x8800}, - {0x0006, 0x8801}, - {0x0000, 0x8800}, - {0x0007, 0x8801}, - {0x00c0, 0x8800}, - {0x0008, 0x8801}, - {0x0003, 0x8800}, - {0x000a, 0x8700}, - {0x000e, 0x8801}, - {0x0004, 0x8800}, - {0x0005, 0x8801}, - {0x0047, 0x8800}, - {0x0006, 0x8801}, - {0x0000, 0x8800}, - {0x0007, 0x8801}, - {0x00c0, 0x8800}, - {0x0008, 0x8801}, - {0x0003, 0x8800}, - {0x0013, 0x8801}, - {0x0001, 0x8800}, - {0x0009, 0x8801}, - {0x0000, 0x8800}, - {0x000a, 0x8801}, - {0x0000, 0x8800}, - {0x000b, 0x8801}, - {0x0000, 0x8800}, - {0x000c, 0x8801}, - {0x0000, 0x8800}, - {0x000e, 0x8801}, - {0x0004, 0x8800}, - {0x000f, 0x8801}, - {0x0000, 0x8800}, - {0x0010, 0x8801}, - {0x0006, 0x8800}, - {0x0011, 0x8801}, - {0x0006, 0x8800}, - {0x0012, 0x8801}, - {0x0000, 0x8800}, - {0x0013, 0x8801}, - {0x0001, 0x8800}, - {0x000a, 0x8700}, - {0x0000, 0x8702}, - {0x0000, 0x8703}, - {0x00c2, 0x8704}, - {0x0001, 0x870c}, - {0x0044, 0x8600}, - {0x0002, 0x8606}, - {0x0064, 0x8607}, - {0x003a, 0x8601}, - {0x0008, 0x8602}, - {0x0044, 0x8600}, - {0x0018, 0x8617}, - {0x0008, 0x8618}, - {0x00a1, 0x8656}, - {0x0004, 0x865b}, - {0x0002, 0x865c}, - {0x0058, 0x865d}, - {0x0048, 0x865e}, - {0x0012, 0x8608}, - {0x002c, 0x8609}, - {0x0002, 0x860a}, - {0x002c, 0x860b}, - {0x00db, 0x860c}, - {0x00f9, 0x860d}, - {0x00f1, 0x860e}, - {0x00e3, 0x860f}, - {0x002c, 0x8610}, - {0x006c, 0x8651}, - {0x0041, 0x8652}, - {0x0059, 0x8653}, - {0x0040, 0x8654}, - {0x00fa, 0x8611}, - {0x00ff, 0x8612}, - {0x00f8, 0x8613}, - {0x0000, 0x8614}, - {0x0001, 0x863f}, - {0x0000, 0x8640}, - {0x0026, 0x8641}, - {0x0045, 0x8642}, - {0x0060, 0x8643}, - {0x0075, 0x8644}, - {0x0088, 0x8645}, - {0x009b, 0x8646}, - {0x00b0, 0x8647}, - {0x00c5, 0x8648}, - {0x00d2, 0x8649}, - {0x00dc, 0x864a}, - {0x00e5, 0x864b}, - {0x00eb, 0x864c}, - {0x00f0, 0x864d}, - {0x00f6, 0x864e}, - {0x00fa, 0x864f}, - {0x00ff, 0x8650}, - {0x0060, 0x8657}, - {0x0010, 0x8658}, - {0x0018, 0x8659}, - {0x0005, 0x865a}, - {0x0018, 0x8660}, - {0x0003, 0x8509}, - {0x0011, 0x850a}, - {0x0032, 0x850b}, - {0x0010, 0x850c}, - {0x0021, 0x850d}, - {0x0001, 0x8500}, - {0x0000, 0x8508}, - - {0x0012, 0x8608}, - {0x002c, 0x8609}, - {0x0002, 0x860a}, - {0x0039, 0x860b}, - {0x00d0, 0x860c}, - {0x00f7, 0x860d}, - {0x00ed, 0x860e}, - {0x00db, 0x860f}, - {0x0039, 0x8610}, - {0x0012, 0x8657}, - {0x0064, 0x8619}, - -/* This line starts it all, it is not needed here */ -/* since it has been build into the driver */ -/* jfm: don't start now */ -/* {0x0030, 0x8112}, */ - {} -}; - -/* - * Initialization data for Creative Webcam Vista - */ -static const u16 spca508_vista_init_data[][2] = { - {0x0008, 0x8200}, /* Clear register */ - {0x0000, 0x870b}, /* Reset CTL3 */ - {0x0020, 0x8112}, /* Video Drop packet enable */ - {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */ - {0x0000, 0x8110}, /* Disable everything */ - {0x0000, 0x8114}, /* Software GPIO output data */ - {0x0000, 0x8114}, - - {0x0003, 0x8111}, - {0x0000, 0x8111}, - {0x0090, 0x8110}, /* Enable: SSI output, External 2X clock output */ - {0x0020, 0x8112}, - {0x0000, 0x8114}, - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0001, 0x8114}, - {0x0003, 0x8114}, - - {0x000f, 0x8402}, /* Memory bank Address */ - {0x0000, 0x8403}, /* Memory bank Address */ - {0x00ba, 0x8804}, /* SSI Slave address */ - {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, /* Will write 2 bytes (DATA1+DATA2) */ - {0x0020, 0x8801}, /* Register address for SSI read/write */ - {0x0044, 0x8805}, /* DATA2 */ - {0x0004, 0x8800}, /* DATA1 -> write triggered */ - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0009, 0x8801}, - {0x0042, 0x8805}, - {0x0001, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x003c, 0x8801}, - {0x0001, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0001, 0x8801}, - {0x000a, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0002, 0x8801}, - {0x0000, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0003, 0x8801}, - {0x0027, 0x8805}, - {0x0001, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0004, 0x8801}, - {0x0065, 0x8805}, - {0x0001, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0005, 0x8801}, - {0x0003, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0006, 0x8801}, - {0x001c, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0007, 0x8801}, - {0x002a, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x000e, 0x8801}, - {0x0000, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0028, 0x8801}, - {0x002e, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0039, 0x8801}, - {0x0013, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x003b, 0x8801}, - {0x000c, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0035, 0x8801}, - {0x0028, 0x8805}, - {0x0000, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0x0001, 0x8802 } -> 0000: 10 */ - {0x0010, 0x8802}, - {0x0009, 0x8801}, - {0x0042, 0x8805}, - {0x0001, 0x8800}, - /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - - {0x0050, 0x8703}, - {0x0002, 0x8704}, /* External input CKIx1 */ - {0x0001, 0x870c}, /* Select CKOx2 output */ - {0x009a, 0x8600}, /* Line memory Read Counter (L) */ - {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */ - {0x0023, 0x8601}, - {0x0010, 0x8602}, - {0x000a, 0x8603}, - {0x009a, 0x8600}, - {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */ - {0x0003, 0x865c}, /* Vertical offset for valid lines (L) */ - {0x0058, 0x865d}, /* Horizontal valid pixels window (L) */ - {0x0048, 0x865e}, /* Vertical valid lines window (L) */ - {0x0000, 0x865f}, - - {0x0006, 0x8660}, - /* Enable nibble data input, select nibble input order */ - - {0x0013, 0x8608}, /* A11 Coeficients for color correction */ - {0x0028, 0x8609}, - /* Note: these values are confirmed at the end of array */ - {0x0005, 0x860a}, /* ... */ - {0x0025, 0x860b}, - {0x00e1, 0x860c}, - {0x00fa, 0x860d}, - {0x00f4, 0x860e}, - {0x00e8, 0x860f}, - {0x0025, 0x8610}, /* A33 Coef. */ - {0x00fc, 0x8611}, /* White balance offset: R */ - {0x0001, 0x8612}, /* White balance offset: Gr */ - {0x00fe, 0x8613}, /* White balance offset: B */ - {0x0000, 0x8614}, /* White balance offset: Gb */ - - {0x0064, 0x8651}, /* R gain for white balance (L) */ - {0x0040, 0x8652}, /* Gr gain for white balance (L) */ - {0x0066, 0x8653}, /* B gain for white balance (L) */ - {0x0040, 0x8654}, /* Gb gain for white balance (L) */ - {0x0001, 0x863f}, /* Enable fixed gamma correction */ - - {0x00a1, 0x8656}, /* Size - Window1: 256x256, Window2: 128x128, - * UV division: UV no change, - * Enable New edge enhancement */ - {0x0018, 0x8657}, /* Edge gain high threshold */ - {0x0020, 0x8658}, /* Edge gain low threshold */ - {0x000a, 0x8659}, /* Edge bandwidth high threshold */ - {0x0005, 0x865a}, /* Edge bandwidth low threshold */ - {0x0064, 0x8607}, /* UV filter enable */ - - {0x0016, 0x8660}, - {0x0000, 0x86b0}, /* Bad pixels compensation address */ - {0x00dc, 0x86b1}, /* X coord for bad pixels compensation (L) */ - {0x0000, 0x86b2}, - {0x0009, 0x86b3}, /* Y coord for bad pixels compensation (L) */ - {0x0000, 0x86b4}, - - {0x0001, 0x86b0}, - {0x00f5, 0x86b1}, - {0x0000, 0x86b2}, - {0x00c6, 0x86b3}, - {0x0000, 0x86b4}, - - {0x0002, 0x86b0}, - {0x001c, 0x86b1}, - {0x0001, 0x86b2}, - {0x00d7, 0x86b3}, - {0x0000, 0x86b4}, - - {0x0003, 0x86b0}, - {0x001c, 0x86b1}, - {0x0001, 0x86b2}, - {0x00d8, 0x86b3}, - {0x0000, 0x86b4}, - - {0x0004, 0x86b0}, - {0x001d, 0x86b1}, - {0x0001, 0x86b2}, - {0x00d8, 0x86b3}, - {0x0000, 0x86b4}, - {0x001e, 0x8660}, - - /* READ { 0x0000, 0x8608 } -> 0000: 13 */ - /* READ { 0x0000, 0x8609 } -> 0000: 28 */ - /* READ { 0x0000, 0x8610 } -> 0000: 05 */ - /* READ { 0x0000, 0x8611 } -> 0000: 25 */ - /* READ { 0x0000, 0x8612 } -> 0000: e1 */ - /* READ { 0x0000, 0x8613 } -> 0000: fa */ - /* READ { 0x0000, 0x8614 } -> 0000: f4 */ - /* READ { 0x0000, 0x8615 } -> 0000: e8 */ - /* READ { 0x0000, 0x8616 } -> 0000: 25 */ - {} -}; - -static int reg_write(struct usb_device *dev, - u16 index, u16 value) -{ - int ret; - - ret = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - 0, /* request */ - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 500); - PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x", - index, value); - if (ret < 0) - err("reg write: error %d", ret); - return ret; -} - -/* read 1 byte */ -/* returns: negative is error, pos or zero is data */ -static int reg_read(struct gspca_dev *gspca_dev, - u16 index) /* wIndex */ -{ - int ret; - - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0, /* register */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, - gspca_dev->usb_buf, 1, - 500); /* timeout */ - PDEBUG(D_USBI, "reg read i:%04x --> %02x", - index, gspca_dev->usb_buf[0]); - if (ret < 0) { - err("reg_read err %d", ret); - return ret; - } - return gspca_dev->usb_buf[0]; -} - -/* send 1 or 2 bytes to the sensor via the Synchronous Serial Interface */ -static int ssi_w(struct gspca_dev *gspca_dev, - u16 reg, u16 val) -{ - struct usb_device *dev = gspca_dev->dev; - int ret, retry; - - ret = reg_write(dev, 0x8802, reg >> 8); - if (ret < 0) - goto out; - ret = reg_write(dev, 0x8801, reg & 0x00ff); - if (ret < 0) - goto out; - if ((reg & 0xff00) == 0x1000) { /* if 2 bytes */ - ret = reg_write(dev, 0x8805, val & 0x00ff); - if (ret < 0) - goto out; - val >>= 8; - } - ret = reg_write(dev, 0x8800, val); - if (ret < 0) - goto out; - - /* poll until not busy */ - retry = 10; - for (;;) { - ret = reg_read(gspca_dev, 0x8803); - if (ret < 0) - break; - if (gspca_dev->usb_buf[0] == 0) - break; - if (--retry <= 0) { - PDEBUG(D_ERR, "ssi_w busy %02x", - gspca_dev->usb_buf[0]); - ret = -1; - break; - } - msleep(8); - } - -out: - return ret; -} - -static int write_vector(struct gspca_dev *gspca_dev, - const u16 (*data)[2]) -{ - struct usb_device *dev = gspca_dev->dev; - int ret = 0; - - while ((*data)[1] != 0) { - if ((*data)[1] & 0x8000) { - if ((*data)[1] == 0xdd00) /* delay */ - msleep((*data)[0]); - else - ret = reg_write(dev, (*data)[1], (*data)[0]); - } else { - ret = ssi_w(gspca_dev, (*data)[1], (*data)[0]); - } - if (ret < 0) - break; - data++; - } - return ret; -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - int data1, data2; - const u16 (*init_data)[2]; - static const u16 (*(init_data_tb[]))[2] = { - spca508_vista_init_data, /* CreativeVista 0 */ - spca508_sightcam_init_data, /* HamaUSBSightcam 1 */ - spca508_sightcam2_init_data, /* HamaUSBSightcam2 2 */ - spca508cs110_init_data, /* IntelEasyPCCamera 3 */ - spca508cs110_init_data, /* MicroInnovationIC200 4 */ - spca508_init_data, /* ViewQuestVQ110 5 */ - }; - - /* Read from global register the USB product and vendor IDs, just to - * prove that we can communicate with the device. This works, which - * confirms at we are communicating properly and that the device - * is a 508. */ - data1 = reg_read(gspca_dev, 0x8104); - data2 = reg_read(gspca_dev, 0x8105); - PDEBUG(D_PROBE, "Webcam Vendor ID: 0x%02x%02x", data2, data1); - - data1 = reg_read(gspca_dev, 0x8106); - data2 = reg_read(gspca_dev, 0x8107); - PDEBUG(D_PROBE, "Webcam Product ID: 0x%02x%02x", data2, data1); - - data1 = reg_read(gspca_dev, 0x8621); - PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1); - - cam = &gspca_dev->cam; - cam->cam_mode = sif_mode; - cam->nmodes = ARRAY_SIZE(sif_mode); - - sd->subtype = id->driver_info; - sd->brightness = BRIGHTNESS_DEF; - - init_data = init_data_tb[sd->subtype]; - return write_vector(gspca_dev, init_data); -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - return 0; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - int mode; - - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - reg_write(gspca_dev->dev, 0x8500, mode); - switch (mode) { - case 0: - case 1: - reg_write(gspca_dev->dev, 0x8700, 0x28); /* clock */ - break; - default: -/* case 2: */ -/* case 3: */ - reg_write(gspca_dev->dev, 0x8700, 0x23); /* clock */ - break; - } - reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20); - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - /* Video ISO disable, Video Drop Packet enable: */ - reg_write(gspca_dev->dev, 0x8112, 0x20); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - switch (data[0]) { - case 0: /* start of frame */ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - data += SPCA508_OFFSET_DATA; - len -= SPCA508_OFFSET_DATA; - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - break; - case 0xff: /* drop */ - break; - default: - data += 1; - len -= 1; - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - break; - } -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 brightness = sd->brightness; - - /* MX seem contrast */ - reg_write(gspca_dev->dev, 0x8651, brightness); - reg_write(gspca_dev->dev, 0x8652, brightness); - reg_write(gspca_dev->dev, 0x8653, brightness); - reg_write(gspca_dev->dev, 0x8654, brightness); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0130, 0x0130), .driver_info = HamaUSBSightcam}, - {USB_DEVICE(0x041e, 0x4018), .driver_info = CreativeVista}, - {USB_DEVICE(0x0733, 0x0110), .driver_info = ViewQuestVQ110}, - {USB_DEVICE(0x0af9, 0x0010), .driver_info = HamaUSBSightcam}, - {USB_DEVICE(0x0af9, 0x0011), .driver_info = HamaUSBSightcam2}, - {USB_DEVICE(0x8086, 0x0110), .driver_info = IntelEasyPCCamera}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca561.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca561.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca561.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/spca561.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1118 +0,0 @@ -/* - * Sunplus spca561 subdriver - * - * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "spca561" - -#include -#include "gspca.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - __u16 exposure; /* rev12a only */ -#define EXPOSURE_MIN 1 -#define EXPOSURE_DEF 700 /* == 10 fps */ -#define EXPOSURE_MAX (2047 + 325) /* see setexposure */ - - __u8 contrast; /* rev72a only */ -#define CONTRAST_MIN 0x00 -#define CONTRAST_DEF 0x20 -#define CONTRAST_MAX 0x3f - - __u8 brightness; /* rev72a only */ -#define BRIGHTNESS_MIN 0 -#define BRIGHTNESS_DEF 0x20 -#define BRIGHTNESS_MAX 0x3f - - __u8 white; -#define HUE_MIN 1 -#define HUE_DEF 0x40 -#define HUE_MAX 0x7f - - __u8 autogain; -#define AUTOGAIN_MIN 0 -#define AUTOGAIN_DEF 1 -#define AUTOGAIN_MAX 1 - - __u8 gain; /* rev12a only */ -#define GAIN_MIN 0 -#define GAIN_DEF 63 -#define GAIN_MAX 255 - -#define EXPO12A_DEF 3 - __u8 expo12a; /* expo/gain? for rev 12a */ - - __u8 chip_revision; -#define Rev012A 0 -#define Rev072A 1 - - signed char ag_cnt; -#define AG_CNT_START 13 -}; - -static const struct v4l2_pix_format sif_012a_mode[] = { - {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 3}, - {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 4 / 8, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 4 / 8, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -static const struct v4l2_pix_format sif_072a_mode[] = { - {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 3}, - {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -/* - * Initialization data - * I'm not very sure how to split initialization from open data - * chunks. For now, we'll consider everything as initialization - */ -/* Frame packet header offsets for the spca561 */ -#define SPCA561_OFFSET_SNAP 1 -#define SPCA561_OFFSET_TYPE 2 -#define SPCA561_OFFSET_COMPRESS 3 -#define SPCA561_OFFSET_FRAMSEQ 4 -#define SPCA561_OFFSET_GPIO 5 -#define SPCA561_OFFSET_USBBUFF 6 -#define SPCA561_OFFSET_WIN2GRAVE 7 -#define SPCA561_OFFSET_WIN2RAVE 8 -#define SPCA561_OFFSET_WIN2BAVE 9 -#define SPCA561_OFFSET_WIN2GBAVE 10 -#define SPCA561_OFFSET_WIN1GRAVE 11 -#define SPCA561_OFFSET_WIN1RAVE 12 -#define SPCA561_OFFSET_WIN1BAVE 13 -#define SPCA561_OFFSET_WIN1GBAVE 14 -#define SPCA561_OFFSET_FREQ 15 -#define SPCA561_OFFSET_VSYNC 16 -#define SPCA561_INDEX_I2C_BASE 0x8800 -#define SPCA561_SNAPBIT 0x20 -#define SPCA561_SNAPCTRL 0x40 - -static const u16 rev72a_reset[][2] = { - {0x0000, 0x8114}, /* Software GPIO output data */ - {0x0001, 0x8114}, /* Software GPIO output data */ - {0x0000, 0x8112}, /* Some kind of reset */ - {} -}; -static const __u16 rev72a_init_data1[][2] = { - {0x0003, 0x8701}, /* PCLK clock delay adjustment */ - {0x0001, 0x8703}, /* HSYNC from cmos inverted */ - {0x0011, 0x8118}, /* Enable and conf sensor */ - {0x0001, 0x8118}, /* Conf sensor */ - {0x0092, 0x8804}, /* I know nothing about these */ - {0x0010, 0x8802}, /* 0x88xx registers, so I won't */ - {} -}; -static const u16 rev72a_init_sensor1[][2] = { - {0x0001, 0x000d}, - {0x0002, 0x0018}, - {0x0004, 0x0165}, - {0x0005, 0x0021}, - {0x0007, 0x00aa}, - {0x0020, 0x1504}, - {0x0039, 0x0002}, - {0x0035, 0x0010}, - {0x0009, 0x1049}, - {0x0028, 0x000b}, - {0x003b, 0x000f}, - {0x003c, 0x0000}, - {} -}; -static const __u16 rev72a_init_data2[][2] = { - {0x0018, 0x8601}, /* Pixel/line selection for color separation */ - {0x0000, 0x8602}, /* Optical black level for user setting */ - {0x0060, 0x8604}, /* Optical black horizontal offset */ - {0x0002, 0x8605}, /* Optical black vertical offset */ - {0x0000, 0x8603}, /* Non-automatic optical black level */ - {0x0002, 0x865b}, /* Horizontal offset for valid pixels */ - {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */ - {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */ - {0x0090, 0x865e}, /* Vertical valid lines window (x2) */ - {0x00e0, 0x8406}, /* Memory buffer threshold */ - {0x0000, 0x8660}, /* Compensation memory stuff */ - {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */ - {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */ - {0x0001, 0x8200}, /* OprMode to be executed by hardware */ -/* from ms-win */ - {0x0000, 0x8611}, /* R offset for white balance */ - {0x00fd, 0x8612}, /* Gr offset for white balance */ - {0x0003, 0x8613}, /* B offset for white balance */ - {0x0000, 0x8614}, /* Gb offset for white balance */ -/* from ms-win */ - {0x0035, 0x8651}, /* R gain for white balance */ - {0x0040, 0x8652}, /* Gr gain for white balance */ - {0x005f, 0x8653}, /* B gain for white balance */ - {0x0040, 0x8654}, /* Gb gain for white balance */ - {0x0002, 0x8502}, /* Maximum average bit rate stuff */ - {0x0011, 0x8802}, - - {0x0087, 0x8700}, /* Set master clock (96Mhz????) */ - {0x0081, 0x8702}, /* Master clock output enable */ - - {0x0000, 0x8500}, /* Set image type (352x288 no compression) */ - /* Originally was 0x0010 (352x288 compression) */ - - {0x0002, 0x865b}, /* Horizontal offset for valid pixels */ - {0x0003, 0x865c}, /* Vertical offset for valid lines */ - {} -}; -static const u16 rev72a_init_sensor2[][2] = { - {0x0003, 0x0121}, - {0x0004, 0x0165}, - {0x0005, 0x002f}, /* blanking control column */ - {0x0006, 0x0000}, /* blanking mode row*/ - {0x000a, 0x0002}, - {0x0009, 0x1061}, /* setexposure times && pixel clock - * 0001 0 | 000 0110 0001 */ - {0x0035, 0x0014}, - {} -}; - -/******************** QC Express etch2 stuff ********************/ -static const __u16 Pb100_1map8300[][2] = { - /* reg, value */ - {0x8320, 0x3304}, - - {0x8303, 0x0125}, /* image area */ - {0x8304, 0x0169}, - {0x8328, 0x000b}, - {0x833c, 0x0001}, /*fixme: win:07*/ - - {0x832f, 0x1904}, /*fixme: was 0419*/ - {0x8307, 0x00aa}, - {0x8301, 0x0003}, - {0x8302, 0x000e}, - {} -}; -static const __u16 Pb100_2map8300[][2] = { - /* reg, value */ - {0x8339, 0x0000}, - {0x8307, 0x00aa}, - {} -}; - -static const __u16 spca561_161rev12A_data1[][2] = { - {0x29, 0x8118}, /* Control register (various enable bits) */ - {0x08, 0x8114}, /* GPIO: Led off */ - {0x0e, 0x8112}, /* 0x0e stream off 0x3e stream on */ - {0x00, 0x8102}, /* white balance - new */ - {0x92, 0x8804}, - {0x04, 0x8802}, /* windows uses 08 */ - {} -}; -static const __u16 spca561_161rev12A_data2[][2] = { - {0x21, 0x8118}, - {0x10, 0x8500}, - {0x07, 0x8601}, - {0x07, 0x8602}, - {0x04, 0x8501}, - - {0x07, 0x8201}, /* windows uses 02 */ - {0x08, 0x8200}, - {0x01, 0x8200}, - - {0x90, 0x8604}, - {0x00, 0x8605}, - {0xb0, 0x8603}, - - /* sensor gains */ - {0x07, 0x8601}, /* white balance - new */ - {0x07, 0x8602}, /* white balance - new */ - {0x00, 0x8610}, /* *red */ - {0x00, 0x8611}, /* 3f *green */ - {0x00, 0x8612}, /* green *blue */ - {0x00, 0x8613}, /* blue *green */ - {0x43, 0x8614}, /* green *red - white balance - was 0x35 */ - {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */ - {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */ - {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */ - - {0x0c, 0x8620}, /* 0c */ - {0xc8, 0x8631}, /* c8 */ - {0xc8, 0x8634}, /* c8 */ - {0x23, 0x8635}, /* 23 */ - {0x1f, 0x8636}, /* 1f */ - {0xdd, 0x8637}, /* dd */ - {0xe1, 0x8638}, /* e1 */ - {0x1d, 0x8639}, /* 1d */ - {0x21, 0x863a}, /* 21 */ - {0xe3, 0x863b}, /* e3 */ - {0xdf, 0x863c}, /* df */ - {0xf0, 0x8505}, - {0x32, 0x850a}, -/* {0x99, 0x8700}, * - white balance - new (removed) */ - /* HDG we used to do this in stop0, making the init state and the state - after a start / stop different, so do this here instead. */ - {0x29, 0x8118}, - {} -}; - -static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) -{ - int ret; - - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 500); - PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value); - if (ret < 0) - err("reg write: error %d", ret); -} - -static void write_vector(struct gspca_dev *gspca_dev, - const __u16 data[][2]) -{ - struct usb_device *dev = gspca_dev->dev; - int i; - - i = 0; - while (data[i][1] != 0) { - reg_w_val(dev, data[i][1], data[i][0]); - i++; - } -} - -/* read 'len' bytes to gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - __u16 index, __u16 length) -{ - usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, length, 500); -} - -/* write 'len' bytes from gspca_dev->usb_buf */ -static void reg_w_buf(struct gspca_dev *gspca_dev, - __u16 index, __u16 len) -{ - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, len, 500); -} - -static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg) -{ - int retry = 60; - - reg_w_val(gspca_dev->dev, 0x8801, reg); - reg_w_val(gspca_dev->dev, 0x8805, value); - reg_w_val(gspca_dev->dev, 0x8800, value >> 8); - do { - reg_r(gspca_dev, 0x8803, 1); - if (!gspca_dev->usb_buf[0]) - return; - msleep(10); - } while (--retry); -} - -static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) -{ - int retry = 60; - __u8 value; - - reg_w_val(gspca_dev->dev, 0x8804, 0x92); - reg_w_val(gspca_dev->dev, 0x8801, reg); - reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01); - do { - reg_r(gspca_dev, 0x8803, 1); - if (!gspca_dev->usb_buf[0]) { - reg_r(gspca_dev, 0x8800, 1); - value = gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8805, 1); - return ((int) value << 8) | gspca_dev->usb_buf[0]; - } - msleep(10); - } while (--retry); - return -1; -} - -static void sensor_mapwrite(struct gspca_dev *gspca_dev, - const __u16 (*sensormap)[2]) -{ - while ((*sensormap)[0]) { - gspca_dev->usb_buf[0] = (*sensormap)[1]; - gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8; - reg_w_buf(gspca_dev, (*sensormap)[0], 2); - sensormap++; - } -} - -static void write_sensor_72a(struct gspca_dev *gspca_dev, - const __u16 (*sensor)[2]) -{ - while ((*sensor)[0]) { - i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]); - sensor++; - } -} - -static void init_161rev12A(struct gspca_dev *gspca_dev) -{ - write_vector(gspca_dev, spca561_161rev12A_data1); - sensor_mapwrite(gspca_dev, Pb100_1map8300); -/*fixme: should be in sd_start*/ - write_vector(gspca_dev, spca561_161rev12A_data2); - sensor_mapwrite(gspca_dev, Pb100_2map8300); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - __u16 vendor, product; - __u8 data1, data2; - - /* Read frm global register the USB product and vendor IDs, just to - * prove that we can communicate with the device. This works, which - * confirms at we are communicating properly and that the device - * is a 561. */ - reg_r(gspca_dev, 0x8104, 1); - data1 = gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8105, 1); - data2 = gspca_dev->usb_buf[0]; - vendor = (data2 << 8) | data1; - reg_r(gspca_dev, 0x8106, 1); - data1 = gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8107, 1); - data2 = gspca_dev->usb_buf[0]; - product = (data2 << 8) | data1; - if (vendor != id->idVendor || product != id->idProduct) { - PDEBUG(D_PROBE, "Bad vendor / product from device"); - return -EINVAL; - } - - cam = &gspca_dev->cam; - gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ - - sd->chip_revision = id->driver_info; - if (sd->chip_revision == Rev012A) { - cam->cam_mode = sif_012a_mode; - cam->nmodes = ARRAY_SIZE(sif_012a_mode); - } else { - cam->cam_mode = sif_072a_mode; - cam->nmodes = ARRAY_SIZE(sif_072a_mode); - } - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->white = HUE_DEF; - sd->exposure = EXPOSURE_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->gain = GAIN_DEF; - sd->expo12a = EXPO12A_DEF; - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init_12a(struct gspca_dev *gspca_dev) -{ - PDEBUG(D_STREAM, "Chip revision: 012a"); - init_161rev12A(gspca_dev); - return 0; -} -static int sd_init_72a(struct gspca_dev *gspca_dev) -{ - PDEBUG(D_STREAM, "Chip revision: 072a"); - write_vector(gspca_dev, rev72a_reset); - msleep(200); - write_vector(gspca_dev, rev72a_init_data1); - write_sensor_72a(gspca_dev, rev72a_init_sensor1); - write_vector(gspca_dev, rev72a_init_data2); - write_sensor_72a(gspca_dev, rev72a_init_sensor2); - reg_w_val(gspca_dev->dev, 0x8112, 0x30); - return 0; -} - -/* rev 72a only */ -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; - __u8 value; - - value = sd->brightness; - - /* offsets for white balance */ - reg_w_val(dev, 0x8611, value); /* R */ - reg_w_val(dev, 0x8612, value); /* Gr */ - reg_w_val(dev, 0x8613, value); /* B */ - reg_w_val(dev, 0x8614, value); /* Gb */ -} - -static void setwhite(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u16 white; - __u8 blue, red; - __u16 reg; - - /* try to emulate MS-win as possible */ - white = sd->white; - red = 0x20 + white * 3 / 8; - blue = 0x90 - white * 5 / 8; - if (sd->chip_revision == Rev012A) { - reg = 0x8614; - } else { - reg = 0x8651; - red += sd->contrast - 0x20; - blue += sd->contrast - 0x20; - } - reg_w_val(gspca_dev->dev, reg, red); - reg_w_val(gspca_dev->dev, reg + 2, blue); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; - __u8 value; - - if (sd->chip_revision != Rev072A) - return; - value = sd->contrast + 0x20; - - /* gains for white balance */ - setwhite(gspca_dev); -/* reg_w_val(dev, 0x8651, value); * R - done by setwhite */ - reg_w_val(dev, 0x8652, value); /* Gr */ -/* reg_w_val(dev, 0x8653, value); * B - done by setwhite */ - reg_w_val(dev, 0x8654, value); /* Gb */ -} - -/* rev 12a only */ -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, expo = 0; - - /* Register 0x8309 controls exposure for the spca561, - the basic exposure setting goes from 1-2047, where 1 is completely - dark and 2047 is very bright. It not only influences exposure but - also the framerate (to allow for longer exposure) from 1 - 300 it - only raises the exposure time then from 300 - 600 it halves the - framerate to be able to further raise the exposure time and for every - 300 more it halves the framerate again. This allows for a maximum - exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps). - Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12 - configure a divider for the base framerate which us used at the - exposure setting of 1-300. These bits configure the base framerate - according to the following formula: fps = 60 / (value + 2) */ - - /* We choose to use the high bits setting the fixed framerate divisor - asap, as setting high basic exposure setting without the fixed - divider in combination with high gains makes the cam stop */ - int table[] = { 0, 450, 550, 625, EXPOSURE_MAX }; - - for (i = 0; i < ARRAY_SIZE(table) - 1; i++) { - if (sd->exposure <= table[i + 1]) { - expo = sd->exposure - table[i]; - if (i) - expo += 300; - expo |= i << 11; - break; - } - } - - gspca_dev->usb_buf[0] = expo; - gspca_dev->usb_buf[1] = expo >> 8; - reg_w_buf(gspca_dev, 0x8309, 2); -} - -/* rev 12a only */ -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the - sensitivity when set, so 31 + one of them set == 63, and 15 - with both of them set == 63 */ - if (sd->gain < 64) - gspca_dev->usb_buf[0] = sd->gain; - else if (sd->gain < 128) - gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40; - else - gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xc0; - - gspca_dev->usb_buf[1] = 0; - reg_w_buf(gspca_dev, 0x8335, 2); -} - -static void setautogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->autogain) - sd->ag_cnt = AG_CNT_START; - else - sd->ag_cnt = -1; -} - -static int sd_start_12a(struct gspca_dev *gspca_dev) -{ - struct usb_device *dev = gspca_dev->dev; - int mode; - static const __u8 Reg8391[8] = - {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00}; - - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - if (mode <= 1) { - /* Use compression on 320x240 and above */ - reg_w_val(dev, 0x8500, 0x10 | mode); - } else { - /* I couldn't get the compression to work below 320x240 - * Fortunately at these resolutions the bandwidth - * is sufficient to push raw frames at ~20fps */ - reg_w_val(dev, 0x8500, mode); - } /* -- qq@kuku.eu.org */ - - gspca_dev->usb_buf[0] = 0xaa; - gspca_dev->usb_buf[1] = 0x00; - reg_w_buf(gspca_dev, 0x8307, 2); - /* clock - lower 0x8X values lead to fps > 30 */ - reg_w_val(gspca_dev->dev, 0x8700, 0x8a); - /* 0x8f 0x85 0x27 clock */ - reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); - reg_w_val(gspca_dev->dev, 0x850b, 0x03); - memcpy(gspca_dev->usb_buf, Reg8391, 8); - reg_w_buf(gspca_dev, 0x8391, 8); - reg_w_buf(gspca_dev, 0x8390, 8); - setwhite(gspca_dev); - setgain(gspca_dev); - setexposure(gspca_dev); - - /* Led ON (bit 3 -> 0 */ - reg_w_val(gspca_dev->dev, 0x8114, 0x00); - return 0; -} -static int sd_start_72a(struct gspca_dev *gspca_dev) -{ - struct usb_device *dev = gspca_dev->dev; - int Clck; - int mode; - - write_vector(gspca_dev, rev72a_reset); - msleep(200); - write_vector(gspca_dev, rev72a_init_data1); - write_sensor_72a(gspca_dev, rev72a_init_sensor1); - - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - switch (mode) { - default: - case 0: - Clck = 0x27; /* ms-win 0x87 */ - break; - case 1: - Clck = 0x25; - break; - case 2: - Clck = 0x22; - break; - case 3: - Clck = 0x21; - break; - } - reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ - reg_w_val(dev, 0x8702, 0x81); - reg_w_val(dev, 0x8500, mode); /* mode */ - write_sensor_72a(gspca_dev, rev72a_init_sensor2); - setcontrast(gspca_dev); -/* setbrightness(gspca_dev); * fixme: bad values */ - setautogain(gspca_dev); - reg_w_val(dev, 0x8112, 0x10 | 0x20); - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->chip_revision == Rev012A) { - reg_w_val(gspca_dev->dev, 0x8112, 0x0e); - /* Led Off (bit 3 -> 1 */ - reg_w_val(gspca_dev->dev, 0x8114, 0x08); - } else { - reg_w_val(gspca_dev->dev, 0x8112, 0x20); -/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */ - } -} - -static void do_autogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int expotimes; - int pixelclk; - int gainG; - __u8 R, Gr, Gb, B; - int y; - __u8 luma_mean = 110; - __u8 luma_delta = 20; - __u8 spring = 4; - - if (sd->ag_cnt < 0) - return; - if (--sd->ag_cnt >= 0) - return; - sd->ag_cnt = AG_CNT_START; - - switch (sd->chip_revision) { - case Rev072A: - reg_r(gspca_dev, 0x8621, 1); - Gr = gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8622, 1); - R = gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8623, 1); - B = gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8624, 1); - Gb = gspca_dev->usb_buf[0]; - y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8; - /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */ - /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */ - /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */ - - if (y < luma_mean - luma_delta || - y > luma_mean + luma_delta) { - expotimes = i2c_read(gspca_dev, 0x09, 0x10); - pixelclk = 0x0800; - expotimes = expotimes & 0x07ff; - /* PDEBUG(D_PACK, - "Exposition Times 0x%03X Clock 0x%04X ", - expotimes,pixelclk); */ - gainG = i2c_read(gspca_dev, 0x35, 0x10); - /* PDEBUG(D_PACK, - "reading Gain register %d", gainG); */ - - expotimes += (luma_mean - y) >> spring; - gainG += (luma_mean - y) / 50; - /* PDEBUG(D_PACK, - "compute expotimes %d gain %d", - expotimes,gainG); */ - - if (gainG > 0x3f) - gainG = 0x3f; - else if (gainG < 3) - gainG = 3; - i2c_write(gspca_dev, gainG, 0x35); - - if (expotimes > 0x0256) - expotimes = 0x0256; - else if (expotimes < 3) - expotimes = 3; - i2c_write(gspca_dev, expotimes | pixelclk, 0x09); - } - break; - } -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - len--; - switch (*data++) { /* sequence number */ - case 0: /* start of frame */ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - - /* This should never happen */ - if (len < 2) { - PDEBUG(D_ERR, "Short SOF packet, ignoring"); - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - if (data[0] & 0x20) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); - input_sync(gspca_dev->input_dev); - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - } -#endif - - if (data[1] & 0x10) { - /* compressed bayer */ - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - } else { - /* raw bayer (with a header, which we skip) */ - if (sd->chip_revision == Rev012A) { - data += 20; - len -= 20; - } else { - data += 16; - len -= 16; - } - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - } - return; - case 0xff: /* drop (empty mpackets) */ - return; - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -/* rev 72a only */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -/* rev 72a only */ -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - if (gspca_dev->streaming) - setautogain(gspca_dev); - return 0; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->white = val; - if (gspca_dev->streaming) - setwhite(gspca_dev); - return 0; -} - -static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->white; - return 0; -} - -/* rev12a only */ -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -/* rev12a only */ -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -/* control tables */ -static const struct ctrl sd_ctrls_12a[] = { - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = HUE_MIN, - .maximum = HUE_MAX, - .step = 1, - .default_value = HUE_DEF, - }, - .set = sd_setwhite, - .get = sd_getwhite, - }, - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = EXPOSURE_MIN, - .maximum = EXPOSURE_MAX, - .step = 1, - .default_value = EXPOSURE_DEF, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = GAIN_MIN, - .maximum = GAIN_MAX, - .step = 1, - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - -static const struct ctrl sd_ctrls_72a[] = { - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = HUE_MIN, - .maximum = HUE_MAX, - .step = 1, - .default_value = HUE_DEF, - }, - .set = sd_setwhite, - .get = sd_getwhite, - }, - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = BRIGHTNESS_MIN, - .maximum = BRIGHTNESS_MAX, - .step = 1, - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = CONTRAST_MIN, - .maximum = CONTRAST_MAX, - .step = 1, - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = AUTOGAIN_MIN, - .maximum = AUTOGAIN_MAX, - .step = 1, - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -}; - -/* sub-driver description */ -static const struct sd_desc sd_desc_12a = { - .name = MODULE_NAME, - .ctrls = sd_ctrls_12a, - .nctrls = ARRAY_SIZE(sd_ctrls_12a), - .config = sd_config, - .init = sd_init_12a, - .start = sd_start_12a, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .other_input = 1, -#endif -}; -static const struct sd_desc sd_desc_72a = { - .name = MODULE_NAME, - .ctrls = sd_ctrls_72a, - .nctrls = ARRAY_SIZE(sd_ctrls_72a), - .config = sd_config, - .init = sd_init_72a, - .start = sd_start_72a, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .dq_callback = do_autogain, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .other_input = 1, -#endif -}; -static const struct sd_desc *sd_desc[2] = { - &sd_desc_12a, - &sd_desc_72a -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A}, - {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A}, - {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A}, - {USB_DEVICE(0x0461, 0x0815), .driver_info = Rev072A}, - {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A}, - {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A}, - {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A}, - {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A}, - {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A}, - {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A}, - {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A}, - {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A}, - {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A}, - {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A}, - {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A}, - {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, - sd_desc[id->driver_info], - sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq905.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq905.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq905.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq905.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,448 +0,0 @@ -/* - * SQ905 subdriver - * - * Copyright (C) 2008, 2009 Adam Baker and Theodore Kilgore - * - * 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, or - * any later version. - * - * 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 - */ - -/* - * History and Acknowledgments - * - * The original Linux driver for SQ905 based cameras was written by - * Marcell Lengyel and furter developed by many other contributers - * and is available from http://sourceforge.net/projects/sqcam/ - * - * This driver takes advantage of the reverse engineering work done for - * that driver and for libgphoto2 but shares no code with them. - * - * This driver has used as a base the finepix driver and other gspca - * based drivers and may still contain code fragments taken from those - * drivers. - */ - -#define MODULE_NAME "sq905" - -#include -#include -#include "gspca.h" - -MODULE_AUTHOR("Adam Baker , " - "Theodore Kilgore "); -MODULE_DESCRIPTION("GSPCA/SQ905 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* Default timeouts, in ms */ -#define SQ905_CMD_TIMEOUT 500 -#define SQ905_DATA_TIMEOUT 1000 - -/* Maximum transfer size to use. */ -#define SQ905_MAX_TRANSFER 0x8000 -#define FRAME_HEADER_LEN 64 - -/* The known modes, or registers. These go in the "value" slot. */ - -/* 00 is "none" obviously */ - -#define SQ905_BULK_READ 0x03 /* precedes any bulk read */ -#define SQ905_COMMAND 0x06 /* precedes the command codes below */ -#define SQ905_PING 0x07 /* when reading an "idling" command */ -#define SQ905_READ_DONE 0xc0 /* ack bulk read completed */ - -/* Any non-zero value in the bottom 2 bits of the 2nd byte of - * the ID appears to indicate the camera can do 640*480. If the - * LSB of that byte is set the image is just upside down, otherwise - * it is rotated 180 degrees. */ -#define SQ905_HIRES_MASK 0x00000300 -#define SQ905_ORIENTATION_MASK 0x00000100 - -/* Some command codes. These go in the "index" slot. */ - -#define SQ905_ID 0xf0 /* asks for model string */ -#define SQ905_CONFIG 0x20 /* gets photo alloc. table, not used here */ -#define SQ905_DATA 0x30 /* accesses photo data, not used here */ -#define SQ905_CLEAR 0xa0 /* clear everything */ -#define SQ905_CAPTURE_LOW 0x60 /* Starts capture at 160x120 */ -#define SQ905_CAPTURE_MED 0x61 /* Starts capture at 320x240 */ -#define SQ905_CAPTURE_HIGH 0x62 /* Starts capture at 640x480 (some cams only) */ -/* note that the capture command also controls the output dimensions */ - -/* Structure to hold all of our device specific stuff */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - /* - * Driver stuff - */ - struct work_struct work_struct; - struct workqueue_struct *work_thread; -}; - -static struct v4l2_pix_format sq905_mode[] = { - { 160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, - { 320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, - { 640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0} -}; - -/* - * Send a command to the camera. - */ -static int sq905_command(struct gspca_dev *gspca_dev, u16 index) -{ - int ret; - - gspca_dev->usb_buf[0] = '\0'; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - USB_REQ_SYNCH_FRAME, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - SQ905_COMMAND, index, gspca_dev->usb_buf, 1, - SQ905_CMD_TIMEOUT); - if (ret < 0) { - err("%s: usb_control_msg failed (%d)", - __func__, ret); - return ret; - } - - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - USB_REQ_SYNCH_FRAME, /* request */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - SQ905_PING, 0, gspca_dev->usb_buf, 1, - SQ905_CMD_TIMEOUT); - if (ret < 0) { - err("%s: usb_control_msg failed 2 (%d)", - __func__, ret); - return ret; - } - - return 0; -} - -/* - * Acknowledge the end of a frame - see warning on sq905_command. - */ -static int sq905_ack_frame(struct gspca_dev *gspca_dev) -{ - int ret; - - gspca_dev->usb_buf[0] = '\0'; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - USB_REQ_SYNCH_FRAME, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - SQ905_READ_DONE, 0, gspca_dev->usb_buf, 1, - SQ905_CMD_TIMEOUT); - if (ret < 0) { - err("%s: usb_control_msg failed (%d)", __func__, ret); - return ret; - } - - return 0; -} - -/* - * request and read a block of data - see warning on sq905_command. - */ -static int -sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock) -{ - int ret; - int act_len; - - gspca_dev->usb_buf[0] = '\0'; - if (need_lock) - mutex_lock(&gspca_dev->usb_lock); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - USB_REQ_SYNCH_FRAME, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - SQ905_BULK_READ, size, gspca_dev->usb_buf, - 1, SQ905_CMD_TIMEOUT); - if (need_lock) - mutex_unlock(&gspca_dev->usb_lock); - if (ret < 0) { - err("%s: usb_control_msg failed (%d)", __func__, ret); - return ret; - } - ret = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 0x81), - data, size, &act_len, SQ905_DATA_TIMEOUT); - - /* successful, it returns 0, otherwise negative */ - if (ret < 0 || act_len != size) { - err("bulk read fail (%d) len %d/%d", - ret, act_len, size); - return -EIO; - } - return 0; -} - -/* This function is called as a workqueue function and runs whenever the camera - * is streaming data. Because it is a workqueue function it is allowed to sleep - * so we can use synchronous USB calls. To avoid possible collisions with other - * threads attempting to use the camera's USB interface we take the gspca - * usb_lock when performing USB operations. In practice the only thing we need - * to protect against is the usb_set_interface call that gspca makes during - * stream_off as the camera doesn't provide any controls that the user could try - * to change. - */ -static void sq905_dostream(struct work_struct *work) -{ - struct sd *dev = container_of(work, struct sd, work_struct); - struct gspca_dev *gspca_dev = &dev->gspca_dev; - int bytes_left; /* bytes remaining in current frame. */ - int data_len; /* size to use for the next read. */ - int header_read; /* true if we have already read the frame header. */ - int packet_type; - int frame_sz; - int ret; - u8 *data; - u8 *buffer; - - buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); - if (!buffer) { - err("Couldn't allocate USB buffer"); - goto quit_stream; - } - - frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage - + FRAME_HEADER_LEN; - - while (gspca_dev->present && gspca_dev->streaming) { - /* request some data and then read it until we have - * a complete frame. */ - bytes_left = frame_sz; - header_read = 0; - - /* Note we do not check for gspca_dev->streaming here, as - we must finish reading an entire frame, otherwise the - next time we stream we start reading in the middle of a - frame. */ - while (bytes_left > 0 && gspca_dev->present) { - data_len = bytes_left > SQ905_MAX_TRANSFER ? - SQ905_MAX_TRANSFER : bytes_left; - ret = sq905_read_data(gspca_dev, buffer, data_len, 1); - if (ret < 0) - goto quit_stream; - PDEBUG(D_PACK, - "Got %d bytes out of %d for frame", - data_len, bytes_left); - bytes_left -= data_len; - data = buffer; - if (!header_read) { - packet_type = FIRST_PACKET; - /* The first 64 bytes of each frame are - * a header full of FF 00 bytes */ - data += FRAME_HEADER_LEN; - data_len -= FRAME_HEADER_LEN; - header_read = 1; - } else if (bytes_left == 0) { - packet_type = LAST_PACKET; - } else { - packet_type = INTER_PACKET; - } - gspca_frame_add(gspca_dev, packet_type, - data, data_len); - /* If entire frame fits in one packet we still - need to add a LAST_PACKET */ - if (packet_type == FIRST_PACKET && - bytes_left == 0) - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - } - if (gspca_dev->present) { - /* acknowledge the frame */ - mutex_lock(&gspca_dev->usb_lock); - ret = sq905_ack_frame(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - if (ret < 0) - goto quit_stream; - } - } -quit_stream: - if (gspca_dev->present) { - mutex_lock(&gspca_dev->usb_lock); - sq905_command(gspca_dev, SQ905_CLEAR); - mutex_unlock(&gspca_dev->usb_lock); - } - kfree(buffer); -} - -/* This function is called at probe time just before sd_init */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct cam *cam = &gspca_dev->cam; - struct sd *dev = (struct sd *) gspca_dev; - - /* We don't use the buffer gspca allocates so make it small. */ - cam->bulk = 1; - cam->bulk_size = 64; - - INIT_WORK(&dev->work_struct, sq905_dostream); - - return 0; -} - -/* called on streamoff with alt==0 and on disconnect */ -/* the usb_lock is held at entry - restore on exit */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *dev = (struct sd *) gspca_dev; - - /* wait for the work queue to terminate */ - mutex_unlock(&gspca_dev->usb_lock); - /* This waits for sq905_dostream to finish */ - destroy_workqueue(dev->work_thread); - dev->work_thread = NULL; - mutex_lock(&gspca_dev->usb_lock); -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - u32 ident; - int ret; - - /* connect to the camera and read - * the model ID and process that and put it away. - */ - ret = sq905_command(gspca_dev, SQ905_CLEAR); - if (ret < 0) - return ret; - ret = sq905_command(gspca_dev, SQ905_ID); - if (ret < 0) - return ret; - ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4, 0); - if (ret < 0) - return ret; - /* usb_buf is allocated with kmalloc so is aligned. - * Camera model number is the right way round if we assume this - * reverse engineered ID is supposed to be big endian. */ - ident = be32_to_cpup((__be32 *)gspca_dev->usb_buf); - ret = sq905_command(gspca_dev, SQ905_CLEAR); - if (ret < 0) - return ret; - PDEBUG(D_CONF, "SQ905 camera ID %08x detected", ident); - gspca_dev->cam.cam_mode = sq905_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(sq905_mode); - if (!(ident & SQ905_HIRES_MASK)) - gspca_dev->cam.nmodes--; - - if (ident & SQ905_ORIENTATION_MASK) - gspca_dev->cam.input_flags = V4L2_IN_ST_VFLIP; - else - gspca_dev->cam.input_flags = V4L2_IN_ST_VFLIP | - V4L2_IN_ST_HFLIP; - return 0; -} - -/* Set up for getting frames. */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *dev = (struct sd *) gspca_dev; - int ret; - - /* "Open the shutter" and set size, to start capture */ - switch (gspca_dev->curr_mode) { - default: -/* case 2: */ - PDEBUG(D_STREAM, "Start streaming at high resolution"); - ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_HIGH); - break; - case 1: - PDEBUG(D_STREAM, "Start streaming at medium resolution"); - ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_MED); - break; - case 0: - PDEBUG(D_STREAM, "Start streaming at low resolution"); - ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_LOW); - } - - if (ret < 0) { - PDEBUG(D_ERR, "Start streaming command failed"); - return ret; - } - /* Start the workqueue function to do the streaming */ - dev->work_thread = create_singlethread_workqueue(MODULE_NAME); - queue_work(dev->work_thread, &dev->work_struct); - - return 0; -} - -/* Table of supported USB devices */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x2770, 0x9120)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stop0 = sd_stop0, -}; - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, - &sd_desc, - sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq905c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq905c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq905c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq905c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,354 +0,0 @@ -/* - * SQ905C subdriver - * - * Copyright (C) 2009 Theodore Kilgore - * - * 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, or - * any later version. - * - * 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 - */ - -/* - * - * This driver uses work done in - * libgphoto2/camlibs/digigr8, Copyright (C) Theodore Kilgore. - * - * This driver has also used as a base the sq905c driver - * and may contain code fragments from it. - */ - -#define MODULE_NAME "sq905c" - -#include -#include -#include "gspca.h" - -MODULE_AUTHOR("Theodore Kilgore "); -MODULE_DESCRIPTION("GSPCA/SQ905C USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* Default timeouts, in ms */ -#define SQ905C_CMD_TIMEOUT 500 -#define SQ905C_DATA_TIMEOUT 1000 - -/* Maximum transfer size to use. */ -#define SQ905C_MAX_TRANSFER 0x8000 - -#define FRAME_HEADER_LEN 0x50 - -/* Commands. These go in the "value" slot. */ -#define SQ905C_CLEAR 0xa0 /* clear everything */ -#define SQ905C_GET_ID 0x14f4 /* Read version number */ -#define SQ905C_CAPTURE_LOW 0xa040 /* Starts capture at 160x120 */ -#define SQ905C_CAPTURE_MED 0x1440 /* Starts capture at 320x240 */ -#define SQ905C_CAPTURE_HI 0x2840 /* Starts capture at 320x240 */ - -/* For capture, this must go in the "index" slot. */ -#define SQ905C_CAPTURE_INDEX 0x110f - -/* Structure to hold all of our device specific stuff */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - const struct v4l2_pix_format *cap_mode; - /* Driver stuff */ - struct work_struct work_struct; - struct workqueue_struct *work_thread; -}; - -/* - * Most of these cameras will do 640x480 and 320x240. 160x120 works - * in theory but gives very poor output. Therefore, not supported. - * The 0x2770:0x9050 cameras have max resolution of 320x240. - */ -static struct v4l2_pix_format sq905c_mode[] = { - { 320, 240, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, - { 640, 480, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0} -}; - -/* Send a command to the camera. */ -static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index) -{ - int ret; - - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - USB_REQ_SYNCH_FRAME, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - command, index, NULL, 0, - SQ905C_CMD_TIMEOUT); - if (ret < 0) { - err("%s: usb_control_msg failed (%d)", - __func__, ret); - return ret; - } - - return 0; -} - -static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index, - int size) -{ - int ret; - - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - USB_REQ_SYNCH_FRAME, /* request */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - command, index, gspca_dev->usb_buf, size, - SQ905C_CMD_TIMEOUT); - if (ret < 0) { - err("%s: usb_control_msg failed (%d)", - __func__, ret); - return ret; - } - - return 0; -} - -/* This function is called as a workqueue function and runs whenever the camera - * is streaming data. Because it is a workqueue function it is allowed to sleep - * so we can use synchronous USB calls. To avoid possible collisions with other - * threads attempting to use the camera's USB interface the gspca usb_lock is - * used when performing the one USB control operation inside the workqueue, - * which tells the camera to close the stream. In practice the only thing - * which needs to be protected against is the usb_set_interface call that - * gspca makes during stream_off. Otherwise the camera doesn't provide any - * controls that the user could try to change. - */ -static void sq905c_dostream(struct work_struct *work) -{ - struct sd *dev = container_of(work, struct sd, work_struct); - struct gspca_dev *gspca_dev = &dev->gspca_dev; - int bytes_left; /* bytes remaining in current frame. */ - int data_len; /* size to use for the next read. */ - int act_len; - int packet_type; - int ret; - u8 *buffer; - - buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); - if (!buffer) { - err("Couldn't allocate USB buffer"); - goto quit_stream; - } - - while (gspca_dev->present && gspca_dev->streaming) { - /* Request the header, which tells the size to download */ - ret = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 0x81), - buffer, FRAME_HEADER_LEN, &act_len, - SQ905C_DATA_TIMEOUT); - PDEBUG(D_STREAM, - "Got %d bytes out of %d for header", - act_len, FRAME_HEADER_LEN); - if (ret < 0 || act_len < FRAME_HEADER_LEN) - goto quit_stream; - /* size is read from 4 bytes starting 0x40, little endian */ - bytes_left = buffer[0x40]|(buffer[0x41]<<8)|(buffer[0x42]<<16) - |(buffer[0x43]<<24); - PDEBUG(D_STREAM, "bytes_left = 0x%x", bytes_left); - /* We keep the header. It has other information, too. */ - packet_type = FIRST_PACKET; - gspca_frame_add(gspca_dev, packet_type, - buffer, FRAME_HEADER_LEN); - while (bytes_left > 0 && gspca_dev->present) { - data_len = bytes_left > SQ905C_MAX_TRANSFER ? - SQ905C_MAX_TRANSFER : bytes_left; - ret = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 0x81), - buffer, data_len, &act_len, - SQ905C_DATA_TIMEOUT); - if (ret < 0 || act_len < data_len) - goto quit_stream; - PDEBUG(D_STREAM, - "Got %d bytes out of %d for frame", - data_len, bytes_left); - bytes_left -= data_len; - if (bytes_left == 0) - packet_type = LAST_PACKET; - else - packet_type = INTER_PACKET; - gspca_frame_add(gspca_dev, packet_type, - buffer, data_len); - } - } -quit_stream: - if (gspca_dev->present) { - mutex_lock(&gspca_dev->usb_lock); - sq905c_command(gspca_dev, SQ905C_CLEAR, 0); - mutex_unlock(&gspca_dev->usb_lock); - } - kfree(buffer); -} - -/* This function is called at probe time just before sd_init */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct cam *cam = &gspca_dev->cam; - struct sd *dev = (struct sd *) gspca_dev; - int ret; - - PDEBUG(D_PROBE, - "SQ9050 camera detected" - " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - - ret = sq905c_command(gspca_dev, SQ905C_GET_ID, 0); - if (ret < 0) { - PDEBUG(D_ERR, "Get version command failed"); - return ret; - } - - ret = sq905c_read(gspca_dev, 0xf5, 0, 20); - if (ret < 0) { - PDEBUG(D_ERR, "Reading version command failed"); - return ret; - } - /* Note we leave out the usb id and the manufacturing date */ - PDEBUG(D_PROBE, - "SQ9050 ID string: %02x - %02x %02x %02x %02x %02x %02x", - gspca_dev->usb_buf[3], - gspca_dev->usb_buf[14], gspca_dev->usb_buf[15], - gspca_dev->usb_buf[16], gspca_dev->usb_buf[17], - gspca_dev->usb_buf[18], gspca_dev->usb_buf[19]); - - cam->cam_mode = sq905c_mode; - cam->nmodes = 2; - if (gspca_dev->usb_buf[15] == 0) - cam->nmodes = 1; - /* We don't use the buffer gspca allocates so make it small. */ - cam->bulk_size = 32; - cam->bulk = 1; - INIT_WORK(&dev->work_struct, sq905c_dostream); - return 0; -} - -/* called on streamoff with alt==0 and on disconnect */ -/* the usb_lock is held at entry - restore on exit */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *dev = (struct sd *) gspca_dev; - - /* wait for the work queue to terminate */ - mutex_unlock(&gspca_dev->usb_lock); - /* This waits for sq905c_dostream to finish */ - destroy_workqueue(dev->work_thread); - dev->work_thread = NULL; - mutex_lock(&gspca_dev->usb_lock); -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - int ret; - - /* connect to the camera and reset it. */ - ret = sq905c_command(gspca_dev, SQ905C_CLEAR, 0); - return ret; -} - -/* Set up for getting frames. */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *dev = (struct sd *) gspca_dev; - int ret; - - dev->cap_mode = gspca_dev->cam.cam_mode; - /* "Open the shutter" and set size, to start capture */ - switch (gspca_dev->width) { - case 640: - PDEBUG(D_STREAM, "Start streaming at high resolution"); - dev->cap_mode++; - ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_HI, - SQ905C_CAPTURE_INDEX); - break; - default: /* 320 */ - PDEBUG(D_STREAM, "Start streaming at medium resolution"); - ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_MED, - SQ905C_CAPTURE_INDEX); - } - - if (ret < 0) { - PDEBUG(D_ERR, "Start streaming command failed"); - return ret; - } - /* Start the workqueue function to do the streaming */ - dev->work_thread = create_singlethread_workqueue(MODULE_NAME); - queue_work(dev->work_thread, &dev->work_struct); - - return 0; -} - -/* Table of supported USB devices */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x2770, 0x905c)}, - {USB_DEVICE(0x2770, 0x9050)}, - {USB_DEVICE(0x2770, 0x9051)}, - {USB_DEVICE(0x2770, 0x9052)}, - {USB_DEVICE(0x2770, 0x913d)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stop0 = sd_stop0, -}; - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, - &sd_desc, - sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq930x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq930x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq930x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sq930x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1208 +0,0 @@ -/* - * SQ930x subdriver - * - * Copyright (C) 2010 Jean-François Moine - * Copyright (C) 2006 -2008 Gerard Klaver - * Copyright (C) 2007 Sam Revitch - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "sq930x" - -#include "gspca.h" - -MODULE_AUTHOR("Jean-Francois Moine \n" - "Gerard Klaver "); -MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* Structure to hold all of our device specific stuff */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - u16 expo; - u8 gain; - - u8 do_ctrl; - u8 gpio[2]; - u8 sensor; - u8 type; -#define Generic 0 -#define Creative_live_motion 1 -}; -enum sensors { - SENSOR_ICX098BQ, - SENSOR_LZ24BP, - SENSOR_MI0360, - SENSOR_MT9V111, /* = MI360SOC */ - SENSOR_OV7660, - SENSOR_OV9630, -}; - -static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0x0001, - .maximum = 0x0fff, - .step = 1, -#define EXPO_DEF 0x0356 - .default_value = EXPO_DEF, - }, - .set = sd_setexpo, - .get = sd_getexpo, - }, - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0x01, - .maximum = 0xff, - .step = 1, -#define GAIN_DEF 0x8d - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - -static struct v4l2_pix_format vga_mode[] = { - {320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, - {640, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, -}; - -/* sq930x registers */ -#define SQ930_CTRL_UCBUS_IO 0x0001 -#define SQ930_CTRL_I2C_IO 0x0002 -#define SQ930_CTRL_GPIO 0x0005 -#define SQ930_CTRL_CAP_START 0x0010 -#define SQ930_CTRL_CAP_STOP 0x0011 -#define SQ930_CTRL_SET_EXPOSURE 0x001d -#define SQ930_CTRL_RESET 0x001e -#define SQ930_CTRL_GET_DEV_INFO 0x001f - -/* gpio 1 (8..15) */ -#define SQ930_GPIO_DFL_I2C_SDA 0x0001 -#define SQ930_GPIO_DFL_I2C_SCL 0x0002 -#define SQ930_GPIO_RSTBAR 0x0004 -#define SQ930_GPIO_EXTRA1 0x0040 -#define SQ930_GPIO_EXTRA2 0x0080 -/* gpio 3 (24..31) */ -#define SQ930_GPIO_POWER 0x0200 -#define SQ930_GPIO_DFL_LED 0x1000 - -struct ucbus_write_cmd { - u16 bw_addr; - u8 bw_data; -}; -struct i2c_write_cmd { - u8 reg; - u16 val; -}; - -static const struct ucbus_write_cmd icx098bq_start_0[] = { - {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce}, - {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e}, - {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02}, - {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02}, - {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00}, - {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04}, - {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00}, - {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48}, - {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, - {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, - {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff}, - {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, - {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00}, - {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, - {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, - {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c}, - {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30}, - {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30}, - {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc}, - {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, - {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00}, - {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00}, - {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa}, - {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa}, - {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, - {0xf800, 0x03} -}; -static const struct ucbus_write_cmd icx098bq_start_1[] = { - {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, - {0xf5f4, 0xc0}, - {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, - {0xf5f4, 0xc0}, - {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, - {0xf5f9, 0x00} -}; - -static const struct ucbus_write_cmd icx098bq_start_2[] = { - {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00}, - {0xf807, 0x7f}, {0xf800, 0x03}, - {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00}, - {0xf807, 0x7f}, {0xf800, 0x03}, - {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0}, - {0xf807, 0x7f}, {0xf800, 0x03}, - {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, - {0xf807, 0x7f}, {0xf800, 0x03} -}; - -static const struct ucbus_write_cmd lz24bp_start_0[] = { - {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe}, - {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06}, - {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02}, - {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00}, - {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00}, - {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03}, - {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00}, - {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48}, - {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, - {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, - {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0}, - {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, - {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00}, - {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, - {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, - {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30}, - {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c}, - {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c}, - {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d}, - {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, - {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d}, - {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d}, - {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04}, - {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04}, - {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, - {0xf800, 0x03} -}; -static const struct ucbus_write_cmd lz24bp_start_1_gen[] = { - {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, - {0xf5f4, 0xb3}, - {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, - {0xf5f4, 0xb3}, - {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, - {0xf5f9, 0x00} -}; - -static const struct ucbus_write_cmd lz24bp_start_1_clm[] = { - {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, - {0xf5f4, 0xc0}, - {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, - {0xf5f4, 0xc0}, - {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, - {0xf5f9, 0x00} -}; - -static const struct ucbus_write_cmd lz24bp_start_2[] = { - {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00}, - {0xf807, 0x7f}, {0xf800, 0x03}, - {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00}, - {0xf807, 0x7f}, {0xf800, 0x03}, - {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48}, - {0xf807, 0x7f}, {0xf800, 0x03}, - {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, - {0xf807, 0x7f}, {0xf800, 0x03} -}; - -static const struct ucbus_write_cmd mi0360_start_0[] = { - {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc}, - {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00} -}; -static const struct i2c_write_cmd mi0360_init_23[] = { - {0x30, 0x0040}, /* reserved - def 0x0005 */ - {0x31, 0x0000}, /* reserved - def 0x002a */ - {0x34, 0x0100}, /* reserved - def 0x0100 */ - {0x3d, 0x068f}, /* reserved - def 0x068f */ -}; -static const struct i2c_write_cmd mi0360_init_24[] = { - {0x03, 0x01e5}, /* window height */ - {0x04, 0x0285}, /* window width */ -}; -static const struct i2c_write_cmd mi0360_init_25[] = { - {0x35, 0x0020}, /* global gain */ - {0x2b, 0x0020}, /* green1 gain */ - {0x2c, 0x002a}, /* blue gain */ - {0x2d, 0x0028}, /* red gain */ - {0x2e, 0x0020}, /* green2 gain */ -}; -static const struct ucbus_write_cmd mi0360_start_1[] = { - {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, - {0xf5f4, 0xa6}, - {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, - {0xf5f4, 0xa6}, - {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, - {0xf5f9, 0x00} -}; -static const struct i2c_write_cmd mi0360_start_2[] = { - {0x62, 0x041d}, /* reserved - def 0x0418 */ -}; -static const struct i2c_write_cmd mi0360_start_3[] = { - {0x05, 0x007b}, /* horiz blanking */ -}; -static const struct i2c_write_cmd mi0360_start_4[] = { - {0x05, 0x03f5}, /* horiz blanking */ -}; - -static const struct i2c_write_cmd mt9v111_init_0[] = { - {0x01, 0x0001}, /* select IFP/SOC registers */ - {0x06, 0x300c}, /* operating mode control */ - {0x08, 0xcc00}, /* output format control (RGB) */ - {0x01, 0x0004}, /* select sensor core registers */ -}; -static const struct i2c_write_cmd mt9v111_init_1[] = { - {0x03, 0x01e5}, /* window height */ - {0x04, 0x0285}, /* window width */ -}; -static const struct i2c_write_cmd mt9v111_init_2[] = { - {0x30, 0x7800}, - {0x31, 0x0000}, - {0x07, 0x3002}, /* output control */ - {0x35, 0x0020}, /* global gain */ - {0x2b, 0x0020}, /* green1 gain */ - {0x2c, 0x0020}, /* blue gain */ - {0x2d, 0x0020}, /* red gain */ - {0x2e, 0x0020}, /* green2 gain */ -}; -static const struct ucbus_write_cmd mt9v111_start_1[] = { - {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, - {0xf5f4, 0xaa}, - {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, - {0xf5f4, 0xaa}, - {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a}, - {0xf5f9, 0x0a} -}; -static const struct i2c_write_cmd mt9v111_init_3[] = { - {0x62, 0x0405}, -}; -static const struct i2c_write_cmd mt9v111_init_4[] = { -/* {0x05, 0x00ce}, */ - {0x05, 0x005d}, /* horizontal blanking */ -}; - -static const struct ucbus_write_cmd ov7660_start_0[] = { - {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0}, - {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03} -}; - -static const struct ucbus_write_cmd ov9630_start_0[] = { - {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00}, - {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03} -}; - -/* start parameters indexed by [sensor][mode] */ -static const struct cap_s { - u8 cc_sizeid; - u8 cc_bytes[32]; -} capconfig[4][2] = { - [SENSOR_ICX098BQ] = { - {2, /* Bayer 320x240 */ - {0x05, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, - 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, - {4, /* Bayer 640x480 */ - {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, - 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, - }, - [SENSOR_LZ24BP] = { - {2, /* Bayer 320x240 */ - {0x05, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, - 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, - {4, /* Bayer 640x480 */ - {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, - 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, - }, - [SENSOR_MI0360] = { - {2, /* Bayer 320x240 */ - {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, - 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, - {4, /* Bayer 640x480 */ - {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, - 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, - }, - [SENSOR_MT9V111] = { - {2, /* Bayer 320x240 */ - {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, - 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, - {4, /* Bayer 640x480 */ - {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, - 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, - }, -}; - -struct sensor_s { - const char *name; - u8 i2c_addr; - u8 i2c_dum; - u8 gpio[5]; - u8 cmd_len; - const struct ucbus_write_cmd *cmd; -}; - -static const struct sensor_s sensor_tb[] = { - [SENSOR_ICX098BQ] = { - "icx098bp", - 0x00, 0x00, - {0, - SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, - SQ930_GPIO_DFL_I2C_SDA, - 0, - SQ930_GPIO_RSTBAR - }, - 8, icx098bq_start_0 - }, - [SENSOR_LZ24BP] = { - "lz24bp", - 0x00, 0x00, - {0, - SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, - SQ930_GPIO_DFL_I2C_SDA, - 0, - SQ930_GPIO_RSTBAR - }, - 8, lz24bp_start_0 - }, - [SENSOR_MI0360] = { - "mi0360", - 0x5d, 0x80, - {SQ930_GPIO_RSTBAR, - SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, - SQ930_GPIO_DFL_I2C_SDA, - 0, - 0 - }, - 7, mi0360_start_0 - }, - [SENSOR_MT9V111] = { - "mt9v111", - 0x5c, 0x7f, - {SQ930_GPIO_RSTBAR, - SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, - SQ930_GPIO_DFL_I2C_SDA, - 0, - 0 - }, - 7, mi0360_start_0 - }, - [SENSOR_OV7660] = { - "ov7660", - 0x21, 0x00, - {0, - SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, - SQ930_GPIO_DFL_I2C_SDA, - 0, - SQ930_GPIO_RSTBAR - }, - 7, ov7660_start_0 - }, - [SENSOR_OV9630] = { - "ov9630", - 0x30, 0x00, - {0, - SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, - SQ930_GPIO_DFL_I2C_SDA, - 0, - SQ930_GPIO_RSTBAR - }, - 7, ov9630_start_0 - }, -}; - -static void reg_r(struct gspca_dev *gspca_dev, - u16 value, int len) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0x0c, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, 0, gspca_dev->usb_buf, len, - 500); - if (ret < 0) { - err("reg_r %04x failed %d", value, ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x0c, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, - 500); - msleep(30); - if (ret < 0) { - err("reg_w %04x %04x failed %d", value, index, ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index, - const u8 *data, int len) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x", - value, index, *data, data[len - 1]); - memcpy(gspca_dev->usb_buf, data, len); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x0c, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, gspca_dev->usb_buf, len, - 1000); - msleep(30); - if (ret < 0) { - err("reg_wb %04x %04x failed %d", value, index, ret); - gspca_dev->usb_err = ret; - } -} - -static void i2c_write(struct sd *sd, - const struct i2c_write_cmd *cmd, - int ncmds) -{ - struct gspca_dev *gspca_dev = &sd->gspca_dev; - const struct sensor_s *sensor; - u16 val, idx; - u8 *buf; - int ret; - - if (gspca_dev->usb_err < 0) - return; - - sensor = &sensor_tb[sd->sensor]; - - val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO; - idx = (cmd->val & 0xff00) | cmd->reg; - - buf = gspca_dev->usb_buf; - *buf++ = sensor->i2c_dum; - *buf++ = cmd->val; - - while (--ncmds > 0) { - cmd++; - *buf++ = cmd->reg; - *buf++ = cmd->val >> 8; - *buf++ = sensor->i2c_dum; - *buf++ = cmd->val; - } - - PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x", - val, idx, gspca_dev->usb_buf[0], buf[-1]); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x0c, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - val, idx, - gspca_dev->usb_buf, buf - gspca_dev->usb_buf, - 500); - if (ret < 0) { - err("i2c_write failed %d", ret); - gspca_dev->usb_err = ret; - } -} - -static void ucbus_write(struct gspca_dev *gspca_dev, - const struct ucbus_write_cmd *cmd, - int ncmds, - int batchsize) -{ - u8 *buf; - u16 val, idx; - int len, ret; - - if (gspca_dev->usb_err < 0) - return; - -#ifdef GSPCA_DEBUG - if ((batchsize - 1) * 3 > USB_BUF_SZ) { - err("Bug: usb_buf overflow"); - gspca_dev->usb_err = -ENOMEM; - return; - } -#endif - - for (;;) { - len = ncmds; - if (len > batchsize) - len = batchsize; - ncmds -= len; - - val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO; - idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8); - - buf = gspca_dev->usb_buf; - while (--len > 0) { - cmd++; - *buf++ = cmd->bw_addr; - *buf++ = cmd->bw_addr >> 8; - *buf++ = cmd->bw_data; - } - if (buf != gspca_dev->usb_buf) - PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x", - val, idx, - gspca_dev->usb_buf[0], buf[-1]); - else - PDEBUG(D_USBO, "ucbus v: %04x i: %04x", - val, idx); - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x0c, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - val, idx, - gspca_dev->usb_buf, buf - gspca_dev->usb_buf, - 500); - if (ret < 0) { - err("ucbus_write failed %d", ret); - gspca_dev->usb_err = ret; - return; - } - msleep(30); - if (ncmds <= 0) - break; - cmd++; - } -} - -static void gpio_set(struct sd *sd, u16 val, u16 mask) -{ - struct gspca_dev *gspca_dev = &sd->gspca_dev; - - if (mask & 0x00ff) { - sd->gpio[0] &= ~mask; - sd->gpio[0] |= val; - reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO, - ~sd->gpio[0] << 8); - } - mask >>= 8; - val >>= 8; - if (mask) { - sd->gpio[1] &= ~mask; - sd->gpio[1] |= val; - reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO, - ~sd->gpio[1] << 8); - } -} - -static void gpio_init(struct sd *sd, - const u8 *gpio) -{ - gpio_set(sd, *gpio++, 0x000f); - gpio_set(sd, *gpio++, 0x000f); - gpio_set(sd, *gpio++, 0x000f); - gpio_set(sd, *gpio++, 0x000f); - gpio_set(sd, *gpio, 0x000f); -} - -static void bridge_init(struct sd *sd) -{ - static const struct ucbus_write_cmd clkfreq_cmd = { - 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */ - }; - - ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1); - - gpio_set(sd, SQ930_GPIO_POWER, 0xff00); -} - -static void cmos_probe(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - const struct sensor_s *sensor; - static const u8 probe_order[] = { -/* SENSOR_LZ24BP, (tested as ccd) */ - SENSOR_OV9630, - SENSOR_MI0360, - SENSOR_OV7660, - SENSOR_MT9V111, - }; - - for (i = 0; i < ARRAY_SIZE(probe_order); i++) { - sensor = &sensor_tb[probe_order[i]]; - ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8); - gpio_init(sd, sensor->gpio); - msleep(100); - reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1); - msleep(100); - if (gspca_dev->usb_buf[0] != 0) - break; - } - if (i >= ARRAY_SIZE(probe_order)) { - err("Unknown sensor"); - gspca_dev->usb_err = -EINVAL; - return; - } - sd->sensor = probe_order[i]; - switch (sd->sensor) { - case SENSOR_OV7660: - case SENSOR_OV9630: - err("Sensor %s not yet treated", sensor_tb[sd->sensor].name); - gspca_dev->usb_err = -EINVAL; - break; - } -} - -static void mt9v111_init(struct gspca_dev *gspca_dev) -{ - int i, nwait; - static const u8 cmd_001b[] = { - 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00 - }; - static const u8 cmd_011b[][7] = { - {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00}, - {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00}, - {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00}, - {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00}, - }; - - reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b); - for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) { - reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i], - ARRAY_SIZE(cmd_011b[0])); - msleep(400); - nwait = 20; - for (;;) { - reg_r(gspca_dev, 0x031b, 1); - if (gspca_dev->usb_buf[0] == 0 - || gspca_dev->usb_err != 0) - break; - if (--nwait < 0) { - PDEBUG(D_PROBE, "mt9v111_init timeout"); - gspca_dev->usb_err = -ETIME; - return; - } - msleep(50); - } - } -} - -static void global_init(struct sd *sd, int first_time) -{ - switch (sd->sensor) { - case SENSOR_ICX098BQ: - if (first_time) - ucbus_write(&sd->gspca_dev, - icx098bq_start_0, - 8, 8); - gpio_init(sd, sensor_tb[sd->sensor].gpio); - break; - case SENSOR_LZ24BP: - if (sd->type != Creative_live_motion) - gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff); - else - gpio_set(sd, 0, 0x00ff); - msleep(50); - if (first_time) - ucbus_write(&sd->gspca_dev, - lz24bp_start_0, - 8, 8); - gpio_init(sd, sensor_tb[sd->sensor].gpio); - break; - case SENSOR_MI0360: - if (first_time) - ucbus_write(&sd->gspca_dev, - mi0360_start_0, - ARRAY_SIZE(mi0360_start_0), - 8); - gpio_init(sd, sensor_tb[sd->sensor].gpio); - gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2); - break; - default: -/* case SENSOR_MT9V111: */ - if (first_time) - mt9v111_init(&sd->gspca_dev); - else - gpio_init(sd, sensor_tb[sd->sensor].gpio); - break; - } -} - -static void lz24bp_ppl(struct sd *sd, u16 ppl) -{ - struct ucbus_write_cmd cmds[2] = { - {0xf810, ppl >> 8}, - {0xf811, ppl} - }; - - ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2); -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, integclks, intstartclk, frameclks, min_frclk; - const struct sensor_s *sensor; - u16 cmd; - u8 buf[15]; - - integclks = sd->expo; - i = 0; - cmd = SQ930_CTRL_SET_EXPOSURE; - - switch (sd->sensor) { - case SENSOR_ICX098BQ: /* ccd */ - case SENSOR_LZ24BP: - min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f; - if (integclks >= min_frclk) { - intstartclk = 0; - frameclks = integclks; - } else { - intstartclk = min_frclk - integclks; - frameclks = min_frclk; - } - buf[i++] = intstartclk >> 8; - buf[i++] = intstartclk; - buf[i++] = frameclks >> 8; - buf[i++] = frameclks; - buf[i++] = sd->gain; - break; - default: /* cmos */ -/* case SENSOR_MI0360: */ -/* case SENSOR_MT9V111: */ - cmd |= 0x0100; - sensor = &sensor_tb[sd->sensor]; - buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */ - buf[i++] = 0x08; /* 2 * ni2c */ - buf[i++] = 0x09; /* reg = shutter width */ - buf[i++] = integclks >> 8; /* val H */ - buf[i++] = sensor->i2c_dum; - buf[i++] = integclks; /* val L */ - buf[i++] = 0x35; /* reg = global gain */ - buf[i++] = 0x00; /* val H */ - buf[i++] = sensor->i2c_dum; - buf[i++] = 0x80 + sd->gain / 2; /* val L */ - buf[i++] = 0x00; - buf[i++] = 0x00; - buf[i++] = 0x00; - buf[i++] = 0x00; - buf[i++] = 0x83; - break; - } - reg_wb(gspca_dev, cmd, 0, buf, i); -} - -/* This function is called at probe time just before sd_init */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam = &gspca_dev->cam; - - sd->sensor = id->driver_info >> 8; - sd->type = id->driver_info; - - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - - cam->bulk = 1; - - sd->gain = GAIN_DEF; - sd->expo = EXPO_DEF; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */ - -/*fixme: is this needed for icx098bp and mi0360? - if (sd->sensor != SENSOR_LZ24BP) - reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000); - */ - - reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8); - if (gspca_dev->usb_err < 0) - return gspca_dev->usb_err; - -/* it returns: - * 03 00 12 93 0b f6 c9 00 live! ultra - * 03 00 07 93 0b f6 ca 00 live! ultra for notebook - * 03 00 12 93 0b fe c8 00 Trust WB-3500T - * 02 00 06 93 0b fe c8 00 Joy-IT 318S - * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq - * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam - * - * byte - * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit) - * 1: 00 - * 2: 06 / 07 / 12 = mode webcam? firmware?? - * 3: 93 chip = 930b (930b or 930c) - * 4: 0b - * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors) - * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam? - * 7: 00 - */ - PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x", - gspca_dev->usb_buf[0], - gspca_dev->usb_buf[1], - gspca_dev->usb_buf[2], - gspca_dev->usb_buf[3], - gspca_dev->usb_buf[4], - gspca_dev->usb_buf[5], - gspca_dev->usb_buf[6], - gspca_dev->usb_buf[7]); - - bridge_init(sd); - - if (sd->sensor == SENSOR_MI0360) { - - /* no sensor probe for icam tracer */ - if (gspca_dev->usb_buf[5] == 0xf6) /* if ccd */ - sd->sensor = SENSOR_ICX098BQ; - else - cmos_probe(gspca_dev); - } - if (gspca_dev->usb_err >= 0) { - PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name); - global_init(sd, 1); - } - return gspca_dev->usb_err; -} - -/* send the start/stop commands to the webcam */ -static void send_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - const struct cap_s *cap; - int mode; - - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - cap = &capconfig[sd->sensor][mode]; - reg_wb(gspca_dev, 0x0900 | SQ930_CTRL_CAP_START, - 0x0a00 | cap->cc_sizeid, - cap->cc_bytes, 32); -} - -static void send_stop(struct gspca_dev *gspca_dev) -{ - reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0); -} - -/* function called at start time before URB creation */ -static int sd_isoc_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */ - sd->do_ctrl = 0; - gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height + 8; - return 0; -} - -/* start the capture */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int mode; - - bridge_init(sd); - global_init(sd, 0); - msleep(100); - - switch (sd->sensor) { - case SENSOR_ICX098BQ: - ucbus_write(gspca_dev, icx098bq_start_0, - ARRAY_SIZE(icx098bq_start_0), - 8); - ucbus_write(gspca_dev, icx098bq_start_1, - ARRAY_SIZE(icx098bq_start_1), - 5); - ucbus_write(gspca_dev, icx098bq_start_2, - ARRAY_SIZE(icx098bq_start_2), - 6); - msleep(50); - - /* 1st start */ - send_start(gspca_dev); - gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); - msleep(70); - reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000); - gpio_set(sd, 0x7f, 0x00ff); - - /* 2nd start */ - send_start(gspca_dev); - gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); - goto out; - case SENSOR_LZ24BP: - ucbus_write(gspca_dev, lz24bp_start_0, - ARRAY_SIZE(lz24bp_start_0), - 8); - if (sd->type != Creative_live_motion) - ucbus_write(gspca_dev, lz24bp_start_1_gen, - ARRAY_SIZE(lz24bp_start_1_gen), - 5); - else - ucbus_write(gspca_dev, lz24bp_start_1_clm, - ARRAY_SIZE(lz24bp_start_1_clm), - 5); - ucbus_write(gspca_dev, lz24bp_start_2, - ARRAY_SIZE(lz24bp_start_2), - 6); - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - lz24bp_ppl(sd, mode == 1 ? 0x0564 : 0x0310); - msleep(10); - break; - case SENSOR_MI0360: - ucbus_write(gspca_dev, mi0360_start_0, - ARRAY_SIZE(mi0360_start_0), - 8); - i2c_write(sd, mi0360_init_23, - ARRAY_SIZE(mi0360_init_23)); - i2c_write(sd, mi0360_init_24, - ARRAY_SIZE(mi0360_init_24)); - i2c_write(sd, mi0360_init_25, - ARRAY_SIZE(mi0360_init_25)); - ucbus_write(gspca_dev, mi0360_start_1, - ARRAY_SIZE(mi0360_start_1), - 5); - i2c_write(sd, mi0360_start_2, - ARRAY_SIZE(mi0360_start_2)); - i2c_write(sd, mi0360_start_3, - ARRAY_SIZE(mi0360_start_3)); - - /* 1st start */ - send_start(gspca_dev); - msleep(60); - send_stop(gspca_dev); - - i2c_write(sd, - mi0360_start_4, ARRAY_SIZE(mi0360_start_4)); - break; - default: -/* case SENSOR_MT9V111: */ - ucbus_write(gspca_dev, mi0360_start_0, - ARRAY_SIZE(mi0360_start_0), - 8); - i2c_write(sd, mt9v111_init_0, - ARRAY_SIZE(mt9v111_init_0)); - i2c_write(sd, mt9v111_init_1, - ARRAY_SIZE(mt9v111_init_1)); - i2c_write(sd, mt9v111_init_2, - ARRAY_SIZE(mt9v111_init_2)); - ucbus_write(gspca_dev, mt9v111_start_1, - ARRAY_SIZE(mt9v111_start_1), - 5); - i2c_write(sd, mt9v111_init_3, - ARRAY_SIZE(mt9v111_init_3)); - i2c_write(sd, mt9v111_init_4, - ARRAY_SIZE(mt9v111_init_4)); - break; - } - - send_start(gspca_dev); -out: - msleep(1000); - - if (sd->sensor == SENSOR_MT9V111) - gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED); - - sd->do_ctrl = 1; /* set the exposure */ - - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->sensor == SENSOR_MT9V111) - gpio_set(sd, 0, SQ930_GPIO_DFL_LED); - send_stop(gspca_dev); -} - -/* function called when the application gets a new frame */ -/* It sets the exposure if required and restart the bulk transfer. */ -static void sd_dq_callback(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0) - return; - sd->do_ctrl = 0; - - setexposure(gspca_dev); - - gspca_dev->cam.bulk_nurbs = 1; - ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC); - if (ret < 0) - err("sd_dq_callback() err %d", ret); - - /* wait a little time, otherwise the webcam crashes */ - msleep(100); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->do_ctrl) - gspca_dev->cam.bulk_nurbs = 0; - gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); - gspca_frame_add(gspca_dev, INTER_PACKET, data, len - 8); - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - sd->do_ctrl = 1; - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} -static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->expo = val; - if (gspca_dev->streaming) - sd->do_ctrl = 1; - return 0; -} - -static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->expo; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .isoc_init = sd_isoc_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .dq_callback = sd_dq_callback, -}; - -/* Table of supported USB devices */ -#define ST(sensor, type) \ - .driver_info = (SENSOR_ ## sensor << 8) \ - | (type) -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)}, - {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)}, - {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)}, - {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)}, - {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)}, - {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stk014.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stk014.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stk014.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stk014.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,534 +0,0 @@ -/* - * Syntek DV4000 (STK014) subdriver - * - * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr) - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "stk014" - -#include "gspca.h" -#include "jpeg.h" - -MODULE_AUTHOR("Jean-Francois Moine "); -MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - COLORS, - LIGHTFREQ, - NCTRLS /* number of controls */ -}; - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRLS]; - - u8 quality; -#define QUALITY_MIN 70 -#define QUALITY_MAX 95 -#define QUALITY_DEF 88 - - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; - -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void setlightfreq(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setbrightness - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setcontrast - }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setcolors - }, -[LIGHTFREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 1, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, - .default_value = 1, - }, - .set_control = setlightfreq - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -/* -- read a register -- */ -static u8 reg_r(struct gspca_dev *gspca_dev, - __u16 index) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return 0; - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - 0x00, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, - index, - gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { - err("reg_r err %d", ret); - gspca_dev->usb_err = ret; - return 0; - } - return gspca_dev->usb_buf[0]; -} - -/* -- write a register -- */ -static void reg_w(struct gspca_dev *gspca_dev, - __u16 index, __u16 value) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x01, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - NULL, - 0, - 500); - if (ret < 0) { - err("reg_w err %d", ret); - gspca_dev->usb_err = ret; - } -} - -/* -- get a bulk value (4 bytes) -- */ -static void rcv_val(struct gspca_dev *gspca_dev, - int ads) -{ - struct usb_device *dev = gspca_dev->dev; - int alen, ret; - - reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff); - reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff); - reg_w(gspca_dev, 0x636, ads & 0xff); - reg_w(gspca_dev, 0x637, 0); - reg_w(gspca_dev, 0x638, 4); /* len & 0xff */ - reg_w(gspca_dev, 0x639, 0); /* len >> 8 */ - reg_w(gspca_dev, 0x63a, 0); - reg_w(gspca_dev, 0x63b, 0); - reg_w(gspca_dev, 0x630, 5); - if (gspca_dev->usb_err < 0) - return; - ret = usb_bulk_msg(dev, - usb_rcvbulkpipe(dev, 0x05), - gspca_dev->usb_buf, - 4, /* length */ - &alen, - 500); /* timeout in milliseconds */ - if (ret < 0) { - err("rcv_val err %d", ret); - gspca_dev->usb_err = ret; - } -} - -/* -- send a bulk value -- */ -static void snd_val(struct gspca_dev *gspca_dev, - int ads, - unsigned int val) -{ - struct usb_device *dev = gspca_dev->dev; - int alen, ret; - __u8 seq = 0; - - if (ads == 0x003f08) { - reg_r(gspca_dev, 0x0704); - seq = reg_r(gspca_dev, 0x0705); - reg_r(gspca_dev, 0x0650); - reg_w(gspca_dev, 0x654, seq); - } else { - reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff); - } - reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff); - reg_w(gspca_dev, 0x656, ads & 0xff); - reg_w(gspca_dev, 0x657, 0); - reg_w(gspca_dev, 0x658, 0x04); /* size */ - reg_w(gspca_dev, 0x659, 0); - reg_w(gspca_dev, 0x65a, 0); - reg_w(gspca_dev, 0x65b, 0); - reg_w(gspca_dev, 0x650, 5); - if (gspca_dev->usb_err < 0) - return; - gspca_dev->usb_buf[0] = val >> 24; - gspca_dev->usb_buf[1] = val >> 16; - gspca_dev->usb_buf[2] = val >> 8; - gspca_dev->usb_buf[3] = val; - ret = usb_bulk_msg(dev, - usb_sndbulkpipe(dev, 6), - gspca_dev->usb_buf, - 4, - &alen, - 500); /* timeout in milliseconds */ - if (ret < 0) { - err("snd_val err %d", ret); - gspca_dev->usb_err = ret; - } else { - if (ads == 0x003f08) { - seq += 4; - seq &= 0x3f; - reg_w(gspca_dev, 0x705, seq); - } - } -} - -/* set a camera parameter */ -static void set_par(struct gspca_dev *gspca_dev, - int parval) -{ - snd_val(gspca_dev, 0x003f08, parval); -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int parval; - - parval = 0x06000000 /* whiteness */ - + (sd->ctrls[BRIGHTNESS].val << 16); - set_par(gspca_dev, parval); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int parval; - - parval = 0x07000000 /* contrast */ - + (sd->ctrls[CONTRAST].val << 16); - set_par(gspca_dev, parval); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int parval; - - parval = 0x08000000 /* saturation */ - + (sd->ctrls[COLORS].val << 16); - set_par(gspca_dev, parval); -} - -static void setlightfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - set_par(gspca_dev, sd->ctrls[LIGHTFREQ].val == 1 - ? 0x33640000 /* 50 Hz */ - : 0x33780000); /* 60 Hz */ -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->cam.cam_mode = vga_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); - gspca_dev->cam.ctrls = sd->ctrls; - sd->quality = QUALITY_DEF; - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - u8 ret; - - /* check if the device responds */ - usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); - ret = reg_r(gspca_dev, 0x0740); - if (gspca_dev->usb_err >= 0) { - if (ret != 0xff) { - err("init reg: 0x%02x", ret); - gspca_dev->usb_err = -EIO; - } - } - return gspca_dev->usb_err; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret, value; - - /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x22); /* JPEG 411 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - - /* work on alternate 1 */ - usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); - - set_par(gspca_dev, 0x10000000); - set_par(gspca_dev, 0x00000000); - set_par(gspca_dev, 0x8002e001); - set_par(gspca_dev, 0x14000000); - if (gspca_dev->width > 320) - value = 0x8002e001; /* 640x480 */ - else - value = 0x4001f000; /* 320x240 */ - set_par(gspca_dev, value); - ret = usb_set_interface(gspca_dev->dev, - gspca_dev->iface, - gspca_dev->alt); - if (ret < 0) { - err("set intf %d %d failed", - gspca_dev->iface, gspca_dev->alt); - gspca_dev->usb_err = ret; - goto out; - } - reg_r(gspca_dev, 0x0630); - rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ - reg_r(gspca_dev, 0x0650); - snd_val(gspca_dev, 0x000020, 0xffffffff); - reg_w(gspca_dev, 0x0620, 0); - reg_w(gspca_dev, 0x0630, 0); - reg_w(gspca_dev, 0x0640, 0); - reg_w(gspca_dev, 0x0650, 0); - reg_w(gspca_dev, 0x0660, 0); - setbrightness(gspca_dev); /* whiteness */ - setcontrast(gspca_dev); /* contrast */ - setcolors(gspca_dev); /* saturation */ - set_par(gspca_dev, 0x09800000); /* Red ? */ - set_par(gspca_dev, 0x0a800000); /* Green ? */ - set_par(gspca_dev, 0x0b800000); /* Blue ? */ - set_par(gspca_dev, 0x0d030000); /* Gamma ? */ - setlightfreq(gspca_dev); - - /* start the video flow */ - set_par(gspca_dev, 0x01000000); - set_par(gspca_dev, 0x01000000); - if (gspca_dev->usb_err >= 0) - PDEBUG(D_STREAM, "camera started alt: 0x%02x", - gspca_dev->alt); -out: - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct usb_device *dev = gspca_dev->dev; - - set_par(gspca_dev, 0x02000000); - set_par(gspca_dev, 0x02000000); - usb_set_interface(dev, gspca_dev->iface, 1); - reg_r(gspca_dev, 0x0630); - rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ - reg_r(gspca_dev, 0x0650); - snd_val(gspca_dev, 0x000020, 0xffffffff); - reg_w(gspca_dev, 0x0620, 0); - reg_w(gspca_dev, 0x0630, 0); - reg_w(gspca_dev, 0x0640, 0); - reg_w(gspca_dev, 0x0650, 0); - reg_w(gspca_dev, 0x0660, 0); - PDEBUG(D_STREAM, "camera stopped"); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - static unsigned char ffd9[] = {0xff, 0xd9}; - - /* a frame starts with: - * - 0xff 0xfe - * - 0x08 0x00 - length (little endian ?!) - * - 4 bytes = size of whole frame (BE - including header) - * - 0x00 0x0c - * - 0xff 0xd8 - * - .. JPEG image with escape sequences (ff 00) - * (without ending - ff d9) - */ - if (data[0] == 0xff && data[1] == 0xfe) { - gspca_frame_add(gspca_dev, LAST_PACKET, - ffd9, 2); - - /* put the JPEG 411 header */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - - /* beginning of the frame */ -#define STKHDRSZ 12 - data += STKHDRSZ; - len -= STKHDRSZ; - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - } - return -EINVAL; -} - -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return gspca_dev->usb_err; -} - -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = NCTRLS, - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x05e1, 0x0893)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv0680.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv0680.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv0680.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv0680.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,367 +0,0 @@ -/* - * STV0680 USB Camera Driver - * - * Copyright (C) 2009 Hans de Goede - * - * This module is adapted from the in kernel v4l1 stv680 driver: - * - * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net) - * - * Thanks to STMicroelectronics for information on the usb commands, and - * to Steve Miller at STM for his help and encouragement while I was - * writing this driver. - * - * 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, or - * (at your option) any later version. - * - * 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 - * - */ - -#define MODULE_NAME "stv0680" - -#include "gspca.h" - -MODULE_AUTHOR("Hans de Goede "); -MODULE_DESCRIPTION("STV0680 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - struct v4l2_pix_format mode; - u8 orig_mode; - u8 video_mode; - u8 current_mode; -}; - -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[] = { -}; - -static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val, - int size) -{ - int ret = -1; - u8 req_type = 0; - unsigned int pipe = 0; - - switch (set) { - case 0: /* 0xc1 */ - req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; - pipe = usb_rcvctrlpipe(gspca_dev->dev, 0); - break; - case 1: /* 0x41 */ - req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; - pipe = usb_sndctrlpipe(gspca_dev->dev, 0); - break; - case 2: /* 0x80 */ - req_type = USB_DIR_IN | USB_RECIP_DEVICE; - pipe = usb_rcvctrlpipe(gspca_dev->dev, 0); - break; - case 3: /* 0x40 */ - req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - pipe = usb_sndctrlpipe(gspca_dev->dev, 0); - break; - } - - ret = usb_control_msg(gspca_dev->dev, pipe, - req, req_type, - val, 0, gspca_dev->usb_buf, size, 500); - - if ((ret < 0) && (req != 0x0a)) - err("usb_control_msg error %i, request = 0x%x, error = %i", - set, req, ret); - - return ret; -} - -static int stv0680_handle_error(struct gspca_dev *gspca_dev, int ret) -{ - stv_sndctrl(gspca_dev, 0, 0x80, 0, 0x02); /* Get Last Error */ - PDEBUG(D_ERR, "last error: %i, command = 0x%x", - gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); - return ret; -} - -static int stv0680_get_video_mode(struct gspca_dev *gspca_dev) -{ - /* Note not sure if this init of usb_buf is really necessary */ - memset(gspca_dev->usb_buf, 0, 8); - gspca_dev->usb_buf[0] = 0x0f; - - if (stv_sndctrl(gspca_dev, 0, 0x87, 0, 0x08) != 0x08) { - PDEBUG(D_ERR, "Get_Camera_Mode failed"); - return stv0680_handle_error(gspca_dev, -EIO); - } - - return gspca_dev->usb_buf[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */ -} - -static int stv0680_set_video_mode(struct gspca_dev *gspca_dev, u8 mode) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->current_mode == mode) - return 0; - - memset(gspca_dev->usb_buf, 0, 8); - gspca_dev->usb_buf[0] = mode; - - if (stv_sndctrl(gspca_dev, 3, 0x07, 0x0100, 0x08) != 0x08) { - PDEBUG(D_ERR, "Set_Camera_Mode failed"); - return stv0680_handle_error(gspca_dev, -EIO); - } - - /* Verify we got what we've asked for */ - if (stv0680_get_video_mode(gspca_dev) != mode) { - PDEBUG(D_ERR, "Error setting camera video mode!"); - return -EIO; - } - - sd->current_mode = mode; - - return 0; -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - int ret; - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam = &gspca_dev->cam; - - /* Give the camera some time to settle, otherwise initalization will - fail on hotplug, and yes it really needs a full second. */ - msleep(1000); - - /* ping camera to be sure STV0680 is present */ - if (stv_sndctrl(gspca_dev, 0, 0x88, 0x5678, 0x02) != 0x02 || - gspca_dev->usb_buf[0] != 0x56 || gspca_dev->usb_buf[1] != 0x78) { - PDEBUG(D_ERR, "STV(e): camera ping failed!!"); - return stv0680_handle_error(gspca_dev, -ENODEV); - } - - /* get camera descriptor */ - if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x09) != 0x09) - return stv0680_handle_error(gspca_dev, -ENODEV); - - if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x22) != 0x22 || - gspca_dev->usb_buf[7] != 0xa0 || gspca_dev->usb_buf[8] != 0x23) { - PDEBUG(D_ERR, "Could not get descriptor 0200."); - return stv0680_handle_error(gspca_dev, -ENODEV); - } - if (stv_sndctrl(gspca_dev, 0, 0x8a, 0, 0x02) != 0x02) - return stv0680_handle_error(gspca_dev, -ENODEV); - if (stv_sndctrl(gspca_dev, 0, 0x8b, 0, 0x24) != 0x24) - return stv0680_handle_error(gspca_dev, -ENODEV); - if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10) - return stv0680_handle_error(gspca_dev, -ENODEV); - - if (!(gspca_dev->usb_buf[7] & 0x09)) { - PDEBUG(D_ERR, "Camera supports neither CIF nor QVGA mode"); - return -ENODEV; - } - if (gspca_dev->usb_buf[7] & 0x01) - PDEBUG(D_PROBE, "Camera supports CIF mode"); - if (gspca_dev->usb_buf[7] & 0x02) - PDEBUG(D_PROBE, "Camera supports VGA mode"); - if (gspca_dev->usb_buf[7] & 0x04) - PDEBUG(D_PROBE, "Camera supports QCIF mode"); - if (gspca_dev->usb_buf[7] & 0x08) - PDEBUG(D_PROBE, "Camera supports QVGA mode"); - - if (gspca_dev->usb_buf[7] & 0x01) - sd->video_mode = 0x00; /* CIF */ - else - sd->video_mode = 0x03; /* QVGA */ - - /* FW rev, ASIC rev, sensor ID */ - PDEBUG(D_PROBE, "Firmware rev is %i.%i", - gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); - PDEBUG(D_PROBE, "ASIC rev is %i.%i", - gspca_dev->usb_buf[2], gspca_dev->usb_buf[3]); - PDEBUG(D_PROBE, "Sensor ID is %i", - (gspca_dev->usb_buf[4]*16) + (gspca_dev->usb_buf[5]>>4)); - - - ret = stv0680_get_video_mode(gspca_dev); - if (ret < 0) - return ret; - sd->current_mode = sd->orig_mode = ret; - - ret = stv0680_set_video_mode(gspca_dev, sd->video_mode); - if (ret < 0) - return ret; - - /* Get mode details */ - if (stv_sndctrl(gspca_dev, 0, 0x8f, 0, 0x10) != 0x10) - return stv0680_handle_error(gspca_dev, -EIO); - - cam->bulk = 1; - cam->bulk_nurbs = 1; /* The cam cannot handle more */ - cam->bulk_size = (gspca_dev->usb_buf[0] << 24) | - (gspca_dev->usb_buf[1] << 16) | - (gspca_dev->usb_buf[2] << 8) | - (gspca_dev->usb_buf[3]); - sd->mode.width = (gspca_dev->usb_buf[4] << 8) | - (gspca_dev->usb_buf[5]); /* 322, 356, 644 */ - sd->mode.height = (gspca_dev->usb_buf[6] << 8) | - (gspca_dev->usb_buf[7]); /* 242, 292, 484 */ - sd->mode.pixelformat = V4L2_PIX_FMT_STV0680; - sd->mode.field = V4L2_FIELD_NONE; - sd->mode.bytesperline = sd->mode.width; - sd->mode.sizeimage = cam->bulk_size; - sd->mode.colorspace = V4L2_COLORSPACE_SRGB; - - /* origGain = gspca_dev->usb_buf[12]; */ - - cam->cam_mode = &sd->mode; - cam->nmodes = 1; - - - ret = stv0680_set_video_mode(gspca_dev, sd->orig_mode); - if (ret < 0) - return ret; - - if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 || - gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) { - err("Could not get descriptor 0100."); - return stv0680_handle_error(gspca_dev, -EIO); - } - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - return 0; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - int ret; - struct sd *sd = (struct sd *) gspca_dev; - - ret = stv0680_set_video_mode(gspca_dev, sd->video_mode); - if (ret < 0) - return ret; - - if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10) - return stv0680_handle_error(gspca_dev, -EIO); - - /* Start stream at: - 0x0000 = CIF (352x288) - 0x0100 = VGA (640x480) - 0x0300 = QVGA (320x240) */ - if (stv_sndctrl(gspca_dev, 1, 0x09, sd->video_mode << 8, 0x0) != 0x0) - return stv0680_handle_error(gspca_dev, -EIO); - - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - /* This is a high priority command; it stops all lower order cmds */ - if (stv_sndctrl(gspca_dev, 1, 0x04, 0x0000, 0x0) != 0x0) - stv0680_handle_error(gspca_dev, -EIO); -} - -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (!sd->gspca_dev.present) - return; - - stv0680_set_video_mode(gspca_dev, sd->orig_mode); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, - int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* Every now and then the camera sends a 16 byte packet, no idea - what it contains, but it is not image data, when this - happens the frame received before this packet is corrupt, - so discard it. */ - if (len != sd->mode.sizeimage) { - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - - /* Finish the previous frame, we do this upon reception of the next - packet, even though it is already complete so that the strange 16 - byte packets send after a corrupt frame can discard it. */ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - - /* Store the just received frame */ - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0553, 0x0202)}, - {USB_DEVICE(0x041e, 0x4007)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -config USB_STV06XX - tristate "STV06XX USB Camera Driver" - depends on USB_GSPCA - help - Say Y here if you want support for cameras based on - the ST STV06XX chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_stv06xx. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o - -gspca_stv06xx-objs := stv06xx.o \ - stv06xx_vv6410.o \ - stv06xx_hdcs.o \ - stv06xx_pb0100.o \ - stv06xx_st6422.o - -EXTRA_CFLAGS += -Idrivers/media/video/gspca - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,630 +0,0 @@ -/* - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * Copyright (c) 2008 Erik Andrén - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * P/N 861037: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express - * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam - * P/N 861075-0040: Sensor HDCS1000 ASIC - * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB - * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web - */ - -#include -#include "stv06xx_sensor.h" - -MODULE_AUTHOR("Erik Andrén"); -MODULE_DESCRIPTION("STV06XX USB Camera Driver"); -MODULE_LICENSE("GPL"); - -static int dump_bridge; -static int dump_sensor; - -int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data) -{ - int err; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - u8 len = (i2c_data > 0xff) ? 2 : 1; - - buf[0] = i2c_data & 0xff; - buf[1] = (i2c_data >> 8) & 0xff; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, address, 0, buf, len, - STV06XX_URB_MSG_TIMEOUT); - - PDEBUG(D_CONF, "Written 0x%x to address 0x%x, status: %d", - i2c_data, address, err); - - return (err < 0) ? err : 0; -} - -int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data) -{ - int err; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x04, 0xc0, address, 0, buf, 1, - STV06XX_URB_MSG_TIMEOUT); - - *i2c_data = buf[0]; - - PDEBUG(D_CONF, "Reading 0x%x from address 0x%x, status %d", - *i2c_data, address, err); - - return (err < 0) ? err : 0; -} - -/* Wraps the normal write sensor bytes / words functions for writing a - single value */ -int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value) -{ - if (sd->sensor->i2c_len == 2) { - u16 data[2] = { address, value }; - return stv06xx_write_sensor_words(sd, data, 1); - } else { - u8 data[2] = { address, value }; - return stv06xx_write_sensor_bytes(sd, data, 1); - } -} - -static int stv06xx_write_sensor_finish(struct sd *sd) -{ - int err = 0; - - if (sd->bridge == BRIDGE_STV610) { - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - buf[0] = 0; - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x1704, 0, buf, 1, - STV06XX_URB_MSG_TIMEOUT); - } - - return (err < 0) ? err : 0; -} - -int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len) -{ - int err, i, j; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len); - for (i = 0; i < len;) { - /* Build the command buffer */ - memset(buf, 0, I2C_BUFFER_LENGTH); - for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) { - buf[j] = data[2*i]; - buf[0x10 + j] = data[2*i+1]; - PDEBUG(D_CONF, "I2C: Writing 0x%02x to reg 0x%02x", - data[2*i+1], data[2*i]); - } - buf[0x20] = sd->sensor->i2c_addr; - buf[0x21] = j - 1; /* Number of commands to send - 1 */ - buf[0x22] = I2C_WRITE_CMD; - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x0400, 0, buf, - I2C_BUFFER_LENGTH, - STV06XX_URB_MSG_TIMEOUT); - if (err < 0) - return err; - } - return stv06xx_write_sensor_finish(sd); -} - -int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len) -{ - int err, i, j; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len); - - for (i = 0; i < len;) { - /* Build the command buffer */ - memset(buf, 0, I2C_BUFFER_LENGTH); - for (j = 0; j < I2C_MAX_WORDS && i < len; j++, i++) { - buf[j] = data[2*i]; - buf[0x10 + j * 2] = data[2*i+1]; - buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8; - PDEBUG(D_CONF, "I2C: Writing 0x%04x to reg 0x%02x", - data[2*i+1], data[2*i]); - } - buf[0x20] = sd->sensor->i2c_addr; - buf[0x21] = j - 1; /* Number of commands to send - 1 */ - buf[0x22] = I2C_WRITE_CMD; - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x0400, 0, buf, - I2C_BUFFER_LENGTH, - STV06XX_URB_MSG_TIMEOUT); - if (err < 0) - return err; - } - return stv06xx_write_sensor_finish(sd); -} - -int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value) -{ - int err; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - err = stv06xx_write_bridge(sd, STV_I2C_FLUSH, sd->sensor->i2c_flush); - if (err < 0) - return err; - - /* Clear mem */ - memset(buf, 0, I2C_BUFFER_LENGTH); - - buf[0] = address; - buf[0x20] = sd->sensor->i2c_addr; - buf[0x21] = 0; - - /* Read I2C register */ - buf[0x22] = I2C_READ_CMD; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH, - STV06XX_URB_MSG_TIMEOUT); - if (err < 0) { - err("I2C: Read error writing address: %d", err); - return err; - } - - err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x04, 0xc0, 0x1410, 0, buf, sd->sensor->i2c_len, - STV06XX_URB_MSG_TIMEOUT); - if (sd->sensor->i2c_len == 2) - *value = buf[0] | (buf[1] << 8); - else - *value = buf[0]; - - PDEBUG(D_CONF, "I2C: Read 0x%x from address 0x%x, status: %d", - *value, address, err); - - return (err < 0) ? err : 0; -} - -/* Dumps all bridge registers */ -static void stv06xx_dump_bridge(struct sd *sd) -{ - int i; - u8 data, buf; - - info("Dumping all stv06xx bridge registers"); - for (i = 0x1400; i < 0x160f; i++) { - stv06xx_read_bridge(sd, i, &data); - - info("Read 0x%x from address 0x%x", data, i); - } - - info("Testing stv06xx bridge registers for writability"); - for (i = 0x1400; i < 0x160f; i++) { - stv06xx_read_bridge(sd, i, &data); - buf = data; - - stv06xx_write_bridge(sd, i, 0xff); - stv06xx_read_bridge(sd, i, &data); - if (data == 0xff) - info("Register 0x%x is read/write", i); - else if (data != buf) - info("Register 0x%x is read/write," - " but only partially", i); - else - info("Register 0x%x is read-only", i); - - stv06xx_write_bridge(sd, i, buf); - } -} - -/* this function is called at probe and resume time */ -static int stv06xx_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int err; - - PDEBUG(D_PROBE, "Initializing camera"); - - /* Let the usb init settle for a bit - before performing the initialization */ - msleep(250); - - err = sd->sensor->init(sd); - - if (dump_sensor && sd->sensor->dump) - sd->sensor->dump(sd); - - return (err < 0) ? err : 0; -} - -/* Start the camera */ -static int stv06xx_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct usb_host_interface *alt; - struct usb_interface *intf; - int err, packet_size; - - intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); - alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); - if (!alt) { - PDEBUG(D_ERR, "Couldn't get altsetting"); - return -EIO; - } - - packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); - err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size); - if (err < 0) - return err; - - /* Prepare the sensor for start */ - err = sd->sensor->start(sd); - if (err < 0) - goto out; - - /* Start isochronous streaming */ - err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 1); - -out: - if (err < 0) - PDEBUG(D_STREAM, "Starting stream failed"); - else - PDEBUG(D_STREAM, "Started streaming"); - - return (err < 0) ? err : 0; -} - -static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) -{ - struct usb_host_interface *alt; - struct sd *sd = (struct sd *) gspca_dev; - - /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; - alt->endpoint[0].desc.wMaxPacketSize = - cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]); - - return 0; -} - -static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev) -{ - int ret, packet_size, min_packet_size; - struct usb_host_interface *alt; - struct sd *sd = (struct sd *) gspca_dev; - - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; - packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); - min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; - if (packet_size <= min_packet_size) - return -EIO; - - packet_size -= 100; - if (packet_size < min_packet_size) - packet_size = min_packet_size; - alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size); - - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); - if (ret < 0) - PDEBUG(D_ERR|D_STREAM, "set alt 1 err %d", ret); - - return ret; -} - -static void stv06xx_stopN(struct gspca_dev *gspca_dev) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - - /* stop ISO-streaming */ - err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0); - if (err < 0) - goto out; - - err = sd->sensor->stop(sd); - -out: - if (err < 0) - PDEBUG(D_STREAM, "Failed to stop stream"); - else - PDEBUG(D_STREAM, "Stopped streaming"); -} - -/* - * Analyse an USB packet of the data stream and store it appropriately. - * Each packet contains an integral number of chunks. Each chunk has - * 2-bytes identification, followed by 2-bytes that describe the chunk - * length. Known/guessed chunk identifications are: - * 8001/8005/C001/C005 - Begin new frame - * 8002/8006/C002/C006 - End frame - * 0200/4200 - Contains actual image data, bayer or compressed - * 0005 - 11 bytes of unknown data - * 0100 - 2 bytes of unknown data - * The 0005 and 0100 chunks seem to appear only in compressed stream. - */ -static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - PDEBUG(D_PACK, "Packet of length %d arrived", len); - - /* A packet may contain several frames - loop until the whole packet is reached */ - while (len) { - int id, chunk_len; - - if (len < 4) { - PDEBUG(D_PACK, "Packet is smaller than 4 bytes"); - return; - } - - /* Capture the id */ - id = (data[0] << 8) | data[1]; - - /* Capture the chunk length */ - chunk_len = (data[2] << 8) | data[3]; - PDEBUG(D_PACK, "Chunk id: %x, length: %d", id, chunk_len); - - data += 4; - len -= 4; - - if (len < chunk_len) { - PDEBUG(D_ERR, "URB packet length is smaller" - " than the specified chunk length"); - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - - /* First byte seem to be 02=data 2nd byte is unknown??? */ - if (sd->bridge == BRIDGE_ST6422 && (id & 0xff00) == 0x0200) - goto frame_data; - - switch (id) { - case 0x0200: - case 0x4200: -frame_data: - PDEBUG(D_PACK, "Frame data packet detected"); - - if (sd->to_skip) { - int skip = (sd->to_skip < chunk_len) ? - sd->to_skip : chunk_len; - data += skip; - len -= skip; - chunk_len -= skip; - sd->to_skip -= skip; - } - - gspca_frame_add(gspca_dev, INTER_PACKET, - data, chunk_len); - break; - - case 0x8001: - case 0x8005: - case 0xc001: - case 0xc005: - PDEBUG(D_PACK, "Starting new frame"); - - /* Create a new frame, chunk length should be zero */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - NULL, 0); - - if (sd->bridge == BRIDGE_ST6422) - sd->to_skip = gspca_dev->width * 4; - - if (chunk_len) - PDEBUG(D_ERR, "Chunk length is " - "non-zero on a SOF"); - break; - - case 0x8002: - case 0x8006: - case 0xc002: - PDEBUG(D_PACK, "End of frame detected"); - - /* Complete the last frame (if any) */ - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - - if (chunk_len) - PDEBUG(D_ERR, "Chunk length is " - "non-zero on a EOF"); - break; - - case 0x0005: - PDEBUG(D_PACK, "Chunk 0x005 detected"); - /* Unknown chunk with 11 bytes of data, - occurs just before end of each frame - in compressed mode */ - break; - - case 0x0100: - PDEBUG(D_PACK, "Chunk 0x0100 detected"); - /* Unknown chunk with 2 bytes of data, - occurs 2-3 times per USB interrupt */ - break; - case 0x42ff: - PDEBUG(D_PACK, "Chunk 0x42ff detected"); - /* Special chunk seen sometimes on the ST6422 */ - break; - default: - PDEBUG(D_PACK, "Unknown chunk 0x%04x detected", id); - /* Unknown chunk */ - } - data += chunk_len; - len -= chunk_len; - } -} - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* interrupt packet data */ - int len) /* interrupt packet length */ -{ - int ret = -EINVAL; - - if (len == 1 && data[0] == 0x80) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); - input_sync(gspca_dev->input_dev); - ret = 0; - } - - if (len == 1 && data[0] == 0x88) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - ret = 0; - } - - return ret; -} -#endif - -static int stv06xx_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id); - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .config = stv06xx_config, - .init = stv06xx_init, - .start = stv06xx_start, - .stopN = stv06xx_stopN, - .pkt_scan = stv06xx_pkt_scan, - .isoc_init = stv06xx_isoc_init, - .isoc_nego = stv06xx_isoc_nego, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -#endif -}; - -/* This function is called at probe time */ -static int stv06xx_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - - PDEBUG(D_PROBE, "Configuring camera"); - - sd->desc = sd_desc; - sd->bridge = id->driver_info; - gspca_dev->sd_desc = &sd->desc; - - if (dump_bridge) - stv06xx_dump_bridge(sd); - - sd->sensor = &stv06xx_sensor_st6422; - if (!sd->sensor->probe(sd)) - return 0; - - sd->sensor = &stv06xx_sensor_vv6410; - if (!sd->sensor->probe(sd)) - return 0; - - sd->sensor = &stv06xx_sensor_hdcs1x00; - if (!sd->sensor->probe(sd)) - return 0; - - sd->sensor = &stv06xx_sensor_hdcs1020; - if (!sd->sensor->probe(sd)) - return 0; - - sd->sensor = &stv06xx_sensor_pb0100; - if (!sd->sensor->probe(sd)) - return 0; - - sd->sensor = NULL; - return -ENODEV; -} - - - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - /* QuickCam Express */ - {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 }, - /* LEGO cam / QuickCam Web */ - {USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 }, - /* Dexxa WebCam USB */ - {USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 }, - /* QuickCam Messenger */ - {USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 }, - /* QuickCam Communicate */ - {USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 }, - /* QuickCam Messenger (new) */ - {USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 }, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - PDEBUG(D_PROBE, "Probing for a stv06xx device"); - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static void sd_disconnect(struct usb_interface *intf) -{ - struct gspca_dev *gspca_dev = usb_get_intfdata(intf); - struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_PROBE, "Disconnecting the stv06xx device"); - - if (sd->sensor->disconnect) - sd->sensor->disconnect(sd); - gspca_disconnect(intf); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = sd_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); - -module_param(dump_bridge, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup"); - -module_param(dump_sensor, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dump_sensor, "Dumps all sensor registers at startup"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * Copyright (c) 2008 Erik Andrén - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * P/N 861037: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express - * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam - * P/N 861075-0040: Sensor HDCS1000 ASIC - * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB - * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web - */ - -#ifndef STV06XX_H_ -#define STV06XX_H_ - -#include -#include "gspca.h" - -#define MODULE_NAME "STV06xx" - -#define STV_ISOC_ENDPOINT_ADDR 0x81 - -#define STV_REG23 0x0423 - -/* Control registers of the STV0600 ASIC */ -#define STV_I2C_PARTNER 0x1420 -#define STV_I2C_VAL_REG_VAL_PAIRS_MIN1 0x1421 -#define STV_I2C_READ_WRITE_TOGGLE 0x1422 -#define STV_I2C_FLUSH 0x1423 -#define STV_I2C_SUCC_READ_REG_VALS 0x1424 - -#define STV_ISO_ENABLE 0x1440 -#define STV_SCAN_RATE 0x1443 -#define STV_LED_CTRL 0x1445 -#define STV_STV0600_EMULATION 0x1446 -#define STV_REG00 0x1500 -#define STV_REG01 0x1501 -#define STV_REG02 0x1502 -#define STV_REG03 0x1503 -#define STV_REG04 0x1504 - -#define STV_ISO_SIZE_L 0x15c1 -#define STV_ISO_SIZE_H 0x15c2 - -/* Refers to the CIF 352x288 and QCIF 176x144 */ -/* 1: 288 lines, 2: 144 lines */ -#define STV_Y_CTRL 0x15c3 - -/* 0xa: 352 columns, 0x6: 176 columns */ -#define STV_X_CTRL 0x1680 - -#define STV06XX_URB_MSG_TIMEOUT 5000 - -#define I2C_MAX_BYTES 16 -#define I2C_MAX_WORDS 8 - -#define I2C_BUFFER_LENGTH 0x23 -#define I2C_READ_CMD 3 -#define I2C_WRITE_CMD 1 - -#define LED_ON 1 -#define LED_OFF 0 - -/* STV06xx device descriptor */ -struct sd { - struct gspca_dev gspca_dev; - - /* A pointer to the currently connected sensor */ - const struct stv06xx_sensor *sensor; - - /* A pointer to the sd_desc struct */ - struct sd_desc desc; - - /* Sensor private data */ - void *sensor_priv; - - /* The first 4 lines produced by the stv6422 are no good, this keeps - track of how many bytes we still need to skip during a frame */ - int to_skip; - - /* Bridge / Camera type */ - u8 bridge; - #define BRIDGE_STV600 0 - #define BRIDGE_STV602 1 - #define BRIDGE_STV610 2 - #define BRIDGE_ST6422 3 /* With integrated sensor */ -}; - -int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data); -int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data); - -int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len); -int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len); - -int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value); -int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,611 +0,0 @@ -/* - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * Copyright (c) 2008 Erik Andrén - * Copyright (c) 2008 Chia-I Wu - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * P/N 861037: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express - * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam - * P/N 861075-0040: Sensor HDCS1000 ASIC - * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB - * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web - */ - -#include "stv06xx_hdcs.h" - -static const struct ctrl hdcs1x00_ctrl[] = { - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = HDCS_DEFAULT_EXPOSURE, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = hdcs_set_exposure, - .get = hdcs_get_exposure - }, { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = HDCS_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = hdcs_set_gain, - .get = hdcs_get_gain - } -}; - -static struct v4l2_pix_format hdcs1x00_mode[] = { - { - HDCS_1X00_DEF_WIDTH, - HDCS_1X00_DEF_HEIGHT, - V4L2_PIX_FMT_SGRBG8, - V4L2_FIELD_NONE, - .sizeimage = - HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT, - .bytesperline = HDCS_1X00_DEF_WIDTH, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 - } -}; - -static const struct ctrl hdcs1020_ctrl[] = { - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0xffff, - .step = 0x1, - .default_value = HDCS_DEFAULT_EXPOSURE, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = hdcs_set_exposure, - .get = hdcs_get_exposure - }, { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = HDCS_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = hdcs_set_gain, - .get = hdcs_get_gain - } -}; - -static struct v4l2_pix_format hdcs1020_mode[] = { - { - HDCS_1020_DEF_WIDTH, - HDCS_1020_DEF_HEIGHT, - V4L2_PIX_FMT_SGRBG8, - V4L2_FIELD_NONE, - .sizeimage = - HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT, - .bytesperline = HDCS_1020_DEF_WIDTH, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 - } -}; - -enum hdcs_power_state { - HDCS_STATE_SLEEP, - HDCS_STATE_IDLE, - HDCS_STATE_RUN -}; - -/* no lock? */ -struct hdcs { - enum hdcs_power_state state; - int w, h; - - /* visible area of the sensor array */ - struct { - int left, top; - int width, height; - int border; - } array; - - struct { - /* Column timing overhead */ - u8 cto; - /* Column processing overhead */ - u8 cpo; - /* Row sample period constant */ - u16 rs; - /* Exposure reset duration */ - u16 er; - } exp; - - int psmp; - u8 exp_cache, gain_cache; -}; - -static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len) -{ - u8 regs[I2C_MAX_BYTES * 2]; - int i; - - if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) || - (reg + len > 0xff))) - return -EINVAL; - - for (i = 0; i < len; i++) { - regs[2 * i] = reg; - regs[2 * i + 1] = vals[i]; - /* All addresses are shifted left one bit - * as bit 0 toggles r/w */ - reg += 2; - } - - return stv06xx_write_sensor_bytes(sd, regs, len); -} - -static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state) -{ - struct hdcs *hdcs = sd->sensor_priv; - u8 val; - int ret; - - if (hdcs->state == state) - return 0; - - /* we need to go idle before running or sleeping */ - if (hdcs->state != HDCS_STATE_IDLE) { - ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); - if (ret) - return ret; - } - - hdcs->state = HDCS_STATE_IDLE; - - if (state == HDCS_STATE_IDLE) - return 0; - - switch (state) { - case HDCS_STATE_SLEEP: - val = HDCS_SLEEP_MODE; - break; - - case HDCS_STATE_RUN: - val = HDCS_RUN_ENABLE; - break; - - default: - return -EINVAL; - } - - ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val); - - /* Update the state if the write succeeded */ - if (!ret) - hdcs->state = state; - - return ret; -} - -static int hdcs_reset(struct sd *sd) -{ - struct hdcs *hdcs = sd->sensor_priv; - int err; - - err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1); - if (err < 0) - return err; - - err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); - if (err < 0) - hdcs->state = HDCS_STATE_IDLE; - - return err; -} - -static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct hdcs *hdcs = sd->sensor_priv; - - *val = hdcs->exp_cache; - - return 0; -} - -static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct hdcs *hdcs = sd->sensor_priv; - int rowexp, srowexp; - int max_srowexp; - /* Column time period */ - int ct; - /* Column processing period */ - int cp; - /* Row processing period */ - int rp; - /* Minimum number of column timing periods - within the column processing period */ - int mnct; - int cycles, err; - u8 exp[14]; - - val &= 0xff; - hdcs->exp_cache = val; - - cycles = val * HDCS_CLK_FREQ_MHZ * 257; - - ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); - cp = hdcs->exp.cto + (hdcs->w * ct / 2); - - /* the cycles one row takes */ - rp = hdcs->exp.rs + cp; - - rowexp = cycles / rp; - - /* the remaining cycles */ - cycles -= rowexp * rp; - - /* calculate sub-row exposure */ - if (IS_1020(sd)) { - /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */ - srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct; - - mnct = (hdcs->exp.er + 12 + ct - 1) / ct; - max_srowexp = hdcs->w - mnct; - } else { - /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */ - srowexp = cp - hdcs->exp.er - 6 - cycles; - - mnct = (hdcs->exp.er + 5 + ct - 1) / ct; - max_srowexp = cp - mnct * ct - 1; - } - - if (srowexp < 0) - srowexp = 0; - else if (srowexp > max_srowexp) - srowexp = max_srowexp; - - if (IS_1020(sd)) { - exp[0] = HDCS20_CONTROL; - exp[1] = 0x00; /* Stop streaming */ - exp[2] = HDCS_ROWEXPL; - exp[3] = rowexp & 0xff; - exp[4] = HDCS_ROWEXPH; - exp[5] = rowexp >> 8; - exp[6] = HDCS20_SROWEXP; - exp[7] = (srowexp >> 2) & 0xff; - exp[8] = HDCS20_ERROR; - exp[9] = 0x10; /* Clear exposure error flag*/ - exp[10] = HDCS20_CONTROL; - exp[11] = 0x04; /* Restart streaming */ - err = stv06xx_write_sensor_bytes(sd, exp, 6); - } else { - exp[0] = HDCS00_CONTROL; - exp[1] = 0x00; /* Stop streaming */ - exp[2] = HDCS_ROWEXPL; - exp[3] = rowexp & 0xff; - exp[4] = HDCS_ROWEXPH; - exp[5] = rowexp >> 8; - exp[6] = HDCS00_SROWEXPL; - exp[7] = srowexp & 0xff; - exp[8] = HDCS00_SROWEXPH; - exp[9] = srowexp >> 8; - exp[10] = HDCS_STATUS; - exp[11] = 0x10; /* Clear exposure error flag*/ - exp[12] = HDCS00_CONTROL; - exp[13] = 0x04; /* Restart streaming */ - err = stv06xx_write_sensor_bytes(sd, exp, 7); - if (err < 0) - return err; - } - PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d", - val, rowexp, srowexp); - return err; -} - -static int hdcs_set_gains(struct sd *sd, u8 g) -{ - struct hdcs *hdcs = sd->sensor_priv; - int err; - u8 gains[4]; - - hdcs->gain_cache = g; - - /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */ - if (g > 127) - g = 0x80 | (g / 2); - - gains[0] = g; - gains[1] = g; - gains[2] = g; - gains[3] = g; - - err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4); - return err; -} - -static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct hdcs *hdcs = sd->sensor_priv; - - *val = hdcs->gain_cache; - - return 0; -} - -static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - PDEBUG(D_V4L2, "Writing gain %d", val); - return hdcs_set_gains((struct sd *) gspca_dev, - val & 0xff); -} - -static int hdcs_set_size(struct sd *sd, - unsigned int width, unsigned int height) -{ - struct hdcs *hdcs = sd->sensor_priv; - u8 win[4]; - unsigned int x, y; - int err; - - /* must be multiple of 4 */ - width = (width + 3) & ~0x3; - height = (height + 3) & ~0x3; - - if (width > hdcs->array.width) - width = hdcs->array.width; - - if (IS_1020(sd)) { - /* the borders are also invalid */ - if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP - > hdcs->array.height) - height = hdcs->array.height - 2 * hdcs->array.border - - HDCS_1020_BOTTOM_Y_SKIP; - - y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2 - + hdcs->array.top; - } else { - if (height > hdcs->array.height) - height = hdcs->array.height; - - y = hdcs->array.top + (hdcs->array.height - height) / 2; - } - - x = hdcs->array.left + (hdcs->array.width - width) / 2; - - win[0] = y / 4; - win[1] = x / 4; - win[2] = (y + height) / 4 - 1; - win[3] = (x + width) / 4 - 1; - - err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4); - if (err < 0) - return err; - - /* Update the current width and height */ - hdcs->w = width; - hdcs->h = height; - return err; -} - -static int hdcs_probe_1x00(struct sd *sd) -{ - struct hdcs *hdcs; - u16 sensor; - int ret; - - ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); - if (ret < 0 || sensor != 0x08) - return -ENODEV; - - info("HDCS-1000/1100 sensor detected"); - - sd->gspca_dev.cam.cam_mode = hdcs1x00_mode; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode); - sd->desc.ctrls = hdcs1x00_ctrl; - sd->desc.nctrls = ARRAY_SIZE(hdcs1x00_ctrl); - - hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); - if (!hdcs) - return -ENOMEM; - - hdcs->array.left = 8; - hdcs->array.top = 8; - hdcs->array.width = HDCS_1X00_DEF_WIDTH; - hdcs->array.height = HDCS_1X00_DEF_HEIGHT; - hdcs->array.border = 4; - - hdcs->exp.cto = 4; - hdcs->exp.cpo = 2; - hdcs->exp.rs = 186; - hdcs->exp.er = 100; - - /* - * Frame rate on HDCS-1000 with STV600 depends on PSMP: - * 4 = doesn't work at all - * 5 = 7.8 fps, - * 6 = 6.9 fps, - * 8 = 6.3 fps, - * 10 = 5.5 fps, - * 15 = 4.4 fps, - * 31 = 2.8 fps - * - * Frame rate on HDCS-1000 with STV602 depends on PSMP: - * 15 = doesn't work at all - * 18 = doesn't work at all - * 19 = 7.3 fps - * 20 = 7.4 fps - * 21 = 7.4 fps - * 22 = 7.4 fps - * 24 = 6.3 fps - * 30 = 5.4 fps - */ - hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5; - - sd->sensor_priv = hdcs; - - return 0; -} - -static int hdcs_probe_1020(struct sd *sd) -{ - struct hdcs *hdcs; - u16 sensor; - int ret; - - ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); - if (ret < 0 || sensor != 0x10) - return -ENODEV; - - info("HDCS-1020 sensor detected"); - - sd->gspca_dev.cam.cam_mode = hdcs1020_mode; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode); - sd->desc.ctrls = hdcs1020_ctrl; - sd->desc.nctrls = ARRAY_SIZE(hdcs1020_ctrl); - - hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); - if (!hdcs) - return -ENOMEM; - - /* - * From Andrey's test image: looks like HDCS-1020 upper-left - * visible pixel is at 24,8 (y maybe even smaller?) and lower-right - * visible pixel at 375,299 (x maybe even larger?) - */ - hdcs->array.left = 24; - hdcs->array.top = 4; - hdcs->array.width = HDCS_1020_DEF_WIDTH; - hdcs->array.height = 304; - hdcs->array.border = 4; - - hdcs->psmp = 6; - - hdcs->exp.cto = 3; - hdcs->exp.cpo = 3; - hdcs->exp.rs = 155; - hdcs->exp.er = 96; - - sd->sensor_priv = hdcs; - - return 0; -} - -static int hdcs_start(struct sd *sd) -{ - PDEBUG(D_STREAM, "Starting stream"); - - return hdcs_set_state(sd, HDCS_STATE_RUN); -} - -static int hdcs_stop(struct sd *sd) -{ - PDEBUG(D_STREAM, "Halting stream"); - - return hdcs_set_state(sd, HDCS_STATE_SLEEP); -} - -static void hdcs_disconnect(struct sd *sd) -{ - PDEBUG(D_PROBE, "Disconnecting the sensor"); - kfree(sd->sensor_priv); -} - -static int hdcs_init(struct sd *sd) -{ - struct hdcs *hdcs = sd->sensor_priv; - int i, err = 0; - - /* Set the STV0602AA in STV0600 emulation mode */ - if (sd->bridge == BRIDGE_STV602) - stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1); - - /* Execute the bridge init */ - for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) { - err = stv06xx_write_bridge(sd, stv_bridge_init[i][0], - stv_bridge_init[i][1]); - } - if (err < 0) - return err; - - /* sensor soft reset */ - hdcs_reset(sd); - - /* Execute the sensor init */ - for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) { - err = stv06xx_write_sensor(sd, stv_sensor_init[i][0], - stv_sensor_init[i][1]); - } - if (err < 0) - return err; - - /* Enable continous frame capture, bit 2: stop when frame complete */ - err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3)); - if (err < 0) - return err; - - /* Set PGA sample duration - (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */ - if (IS_1020(sd)) - err = stv06xx_write_sensor(sd, HDCS_TCTRL, - (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp); - else - err = stv06xx_write_sensor(sd, HDCS_TCTRL, - (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp); - if (err < 0) - return err; - - err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN); - if (err < 0) - return err; - - err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height); - if (err < 0) - return err; - - err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE); - return err; -} - -static int hdcs_dump(struct sd *sd) -{ - u16 reg, val; - - info("Dumping sensor registers:"); - - for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { - stv06xx_read_sensor(sd, reg, &val); - info("reg 0x%02x = 0x%02x", reg, val); - } - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * Copyright (c) 2008 Erik Andrén - * Copyright (c) 2008 Chia-I Wu - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * P/N 861037: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express - * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam - * P/N 861075-0040: Sensor HDCS1000 ASIC - * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB - * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web - */ - -#ifndef STV06XX_HDCS_H_ -#define STV06XX_HDCS_H_ - -#include "stv06xx_sensor.h" - -#define HDCS_REG_CONFIG(sd) (IS_1020(sd) ? HDCS20_CONFIG : HDCS00_CONFIG) -#define HDCS_REG_CONTROL(sd) (IS_1020(sd) ? HDCS20_CONTROL : HDCS00_CONTROL) - -#define HDCS_1X00_DEF_WIDTH 360 -#define HDCS_1X00_DEF_HEIGHT 296 - -#define HDCS_1020_DEF_WIDTH 352 -#define HDCS_1020_DEF_HEIGHT 292 - -#define HDCS_1020_BOTTOM_Y_SKIP 4 - -#define HDCS_CLK_FREQ_MHZ 25 - -#define HDCS_ADC_START_SIG_DUR 3 - -/* LSB bit of I2C or register address signifies write (0) or read (1) */ -/* I2C Registers common for both HDCS-1000/1100 and HDCS-1020 */ -/* Identifications Register */ -#define HDCS_IDENT (0x00 << 1) -/* Status Register */ -#define HDCS_STATUS (0x01 << 1) -/* Interrupt Mask Register */ -#define HDCS_IMASK (0x02 << 1) -/* Pad Control Register */ -#define HDCS_PCTRL (0x03 << 1) -/* Pad Drive Control Register */ -#define HDCS_PDRV (0x04 << 1) -/* Interface Control Register */ -#define HDCS_ICTRL (0x05 << 1) -/* Interface Timing Register */ -#define HDCS_ITMG (0x06 << 1) -/* Baud Fraction Register */ -#define HDCS_BFRAC (0x07 << 1) -/* Baud Rate Register */ -#define HDCS_BRATE (0x08 << 1) -/* ADC Control Register */ -#define HDCS_ADCCTRL (0x09 << 1) -/* First Window Row Register */ -#define HDCS_FWROW (0x0a << 1) -/* First Window Column Register */ -#define HDCS_FWCOL (0x0b << 1) -/* Last Window Row Register */ -#define HDCS_LWROW (0x0c << 1) -/* Last Window Column Register */ -#define HDCS_LWCOL (0x0d << 1) -/* Timing Control Register */ -#define HDCS_TCTRL (0x0e << 1) -/* PGA Gain Register: Even Row, Even Column */ -#define HDCS_ERECPGA (0x0f << 1) -/* PGA Gain Register: Even Row, Odd Column */ -#define HDCS_EROCPGA (0x10 << 1) -/* PGA Gain Register: Odd Row, Even Column */ -#define HDCS_ORECPGA (0x11 << 1) -/* PGA Gain Register: Odd Row, Odd Column */ -#define HDCS_OROCPGA (0x12 << 1) -/* Row Exposure Low Register */ -#define HDCS_ROWEXPL (0x13 << 1) -/* Row Exposure High Register */ -#define HDCS_ROWEXPH (0x14 << 1) - -/* I2C Registers only for HDCS-1000/1100 */ -/* Sub-Row Exposure Low Register */ -#define HDCS00_SROWEXPL (0x15 << 1) -/* Sub-Row Exposure High Register */ -#define HDCS00_SROWEXPH (0x16 << 1) -/* Configuration Register */ -#define HDCS00_CONFIG (0x17 << 1) -/* Control Register */ -#define HDCS00_CONTROL (0x18 << 1) - -/* I2C Registers only for HDCS-1020 */ -/* Sub-Row Exposure Register */ -#define HDCS20_SROWEXP (0x15 << 1) -/* Error Control Register */ -#define HDCS20_ERROR (0x16 << 1) -/* Interface Timing 2 Register */ -#define HDCS20_ITMG2 (0x17 << 1) -/* Interface Control 2 Register */ -#define HDCS20_ICTRL2 (0x18 << 1) -/* Horizontal Blank Register */ -#define HDCS20_HBLANK (0x19 << 1) -/* Vertical Blank Register */ -#define HDCS20_VBLANK (0x1a << 1) -/* Configuration Register */ -#define HDCS20_CONFIG (0x1b << 1) -/* Control Register */ -#define HDCS20_CONTROL (0x1c << 1) - -#define HDCS_RUN_ENABLE (1 << 2) -#define HDCS_SLEEP_MODE (1 << 1) - -#define HDCS_DEFAULT_EXPOSURE 48 -#define HDCS_DEFAULT_GAIN 128 - -static int hdcs_probe_1x00(struct sd *sd); -static int hdcs_probe_1020(struct sd *sd); -static int hdcs_start(struct sd *sd); -static int hdcs_init(struct sd *sd); -static int hdcs_stop(struct sd *sd); -static int hdcs_dump(struct sd *sd); -static void hdcs_disconnect(struct sd *sd); - -static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val); - -const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = { - .name = "HP HDCS-1000/1100", - .i2c_flush = 0, - .i2c_addr = (0x55 << 1), - .i2c_len = 1, - - /* FIXME (see if we can lower min_packet_size, needs testing, and also - adjusting framerate when the bandwidth gets lower) */ - .min_packet_size = { 847 }, - .max_packet_size = { 847 }, - - .init = hdcs_init, - .probe = hdcs_probe_1x00, - .start = hdcs_start, - .stop = hdcs_stop, - .disconnect = hdcs_disconnect, - .dump = hdcs_dump, -}; - -const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = { - .name = "HDCS-1020", - .i2c_flush = 0, - .i2c_addr = (0x55 << 1), - .i2c_len = 1, - - /* FIXME (see if we can lower min_packet_size, needs testing, and also - adjusting framerate when the bandwidthm gets lower) */ - .min_packet_size = { 847 }, - .max_packet_size = { 847 }, - - .init = hdcs_init, - .probe = hdcs_probe_1020, - .start = hdcs_start, - .stop = hdcs_stop, - .dump = hdcs_dump, -}; - -static const u16 stv_bridge_init[][2] = { - {STV_ISO_ENABLE, 0}, - {STV_REG23, 0}, - {STV_REG00, 0x1d}, - {STV_REG01, 0xb5}, - {STV_REG02, 0xa8}, - {STV_REG03, 0x95}, - {STV_REG04, 0x07}, - - {STV_SCAN_RATE, 0x20}, - {STV_Y_CTRL, 0x01}, - {STV_X_CTRL, 0x0a} -}; - -static const u8 stv_sensor_init[][2] = { - /* Clear status (writing 1 will clear the corresponding status bit) */ - {HDCS_STATUS, BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, - /* Disable all interrupts */ - {HDCS_IMASK, 0x00}, - {HDCS_PCTRL, BIT(6) | BIT(5) | BIT(1) | BIT(0)}, - {HDCS_PDRV, 0x00}, - {HDCS_ICTRL, BIT(5)}, - {HDCS_ITMG, BIT(4) | BIT(1)}, - /* ADC output resolution to 10 bits */ - {HDCS_ADCCTRL, 10} -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,571 +0,0 @@ -/* - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * Copyright (c) 2008 Erik Andrén - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * P/N 861037: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express - * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam - * P/N 861075-0040: Sensor HDCS1000 ASIC - * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB - * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web - */ - -/* - * The spec file for the PB-0100 suggests the following for best quality - * images after the sensor has been reset : - * - * PB_ADCGAINL = R60 = 0x03 (3 dec) : sets low reference of ADC - to produce good black level - * PB_PREADCTRL = R32 = 0x1400 (5120 dec) : Enables global gain changes - through R53 - * PB_ADCMINGAIN = R52 = 0x10 (16 dec) : Sets the minimum gain for - auto-exposure - * PB_ADCGLOBALGAIN = R53 = 0x10 (16 dec) : Sets the global gain - * PB_EXPGAIN = R14 = 0x11 (17 dec) : Sets the auto-exposure value - * PB_UPDATEINT = R23 = 0x02 (2 dec) : Sets the speed on - auto-exposure routine - * PB_CFILLIN = R5 = 0x0E (14 dec) : Sets the frame rate - */ - -#include "stv06xx_pb0100.h" - -static const struct ctrl pb0100_ctrl[] = { -#define GAIN_IDX 0 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128 - }, - .set = pb0100_set_gain, - .get = pb0100_get_gain - }, -#define RED_BALANCE_IDX 1 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = -255, - .maximum = 255, - .step = 1, - .default_value = 0 - }, - .set = pb0100_set_red_balance, - .get = pb0100_get_red_balance - }, -#define BLUE_BALANCE_IDX 2 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = -255, - .maximum = 255, - .step = 1, - .default_value = 0 - }, - .set = pb0100_set_blue_balance, - .get = pb0100_get_blue_balance - }, -#define EXPOSURE_IDX 3 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 511, - .step = 1, - .default_value = 12 - }, - .set = pb0100_set_exposure, - .get = pb0100_get_exposure - }, -#define AUTOGAIN_IDX 4 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain and Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = pb0100_set_autogain, - .get = pb0100_get_autogain - }, -#define AUTOGAIN_TARGET_IDX 5 - { - { - .id = V4L2_CTRL_CLASS_USER + 0x1000, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Automatic Gain Target", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128 - }, - .set = pb0100_set_autogain_target, - .get = pb0100_get_autogain_target - }, -#define NATURAL_IDX 6 - { - { - .id = V4L2_CTRL_CLASS_USER + 0x1001, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Natural Light Source", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = pb0100_set_natural, - .get = pb0100_get_natural - } -}; - -static struct v4l2_pix_format pb0100_mode[] = { -/* low res / subsample modes disabled as they are only half res horizontal, - halving the vertical resolution does not seem to work */ - { - 320, - 240, - V4L2_PIX_FMT_SGRBG8, - V4L2_FIELD_NONE, - .sizeimage = 320 * 240, - .bytesperline = 320, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = PB0100_CROP_TO_VGA - }, - { - 352, - 288, - V4L2_PIX_FMT_SGRBG8, - V4L2_FIELD_NONE, - .sizeimage = 352 * 288, - .bytesperline = 352, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - } -}; - -static int pb0100_probe(struct sd *sd) -{ - u16 sensor; - int i, err; - s32 *sensor_settings; - - err = stv06xx_read_sensor(sd, PB_IDENT, &sensor); - - if (err < 0) - return -ENODEV; - - if ((sensor >> 8) == 0x64) { - sensor_settings = kmalloc( - ARRAY_SIZE(pb0100_ctrl) * sizeof(s32), - GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - - info("Photobit pb0100 sensor detected"); - - sd->gspca_dev.cam.cam_mode = pb0100_mode; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode); - sd->desc.ctrls = pb0100_ctrl; - sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl); - for (i = 0; i < sd->desc.nctrls; i++) - sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; - - return 0; - } - - return -ENODEV; -} - -static int pb0100_start(struct sd *sd) -{ - int err, packet_size, max_packet_size; - struct usb_host_interface *alt; - struct usb_interface *intf; - struct cam *cam = &sd->gspca_dev.cam; - s32 *sensor_settings = sd->sensor_priv; - u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv; - - intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); - alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); - packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); - - /* If we don't have enough bandwidth use a lower framerate */ - max_packet_size = sd->sensor->max_packet_size[sd->gspca_dev.curr_mode]; - if (packet_size < max_packet_size) - stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1)); - else - stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(5)|BIT(3)|BIT(1)); - - /* Setup sensor window */ - if (mode & PB0100_CROP_TO_VGA) { - stv06xx_write_sensor(sd, PB_RSTART, 30); - stv06xx_write_sensor(sd, PB_CSTART, 20); - stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1); - stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1); - } else { - stv06xx_write_sensor(sd, PB_RSTART, 8); - stv06xx_write_sensor(sd, PB_CSTART, 4); - stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1); - stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1); - } - - if (mode & PB0100_SUBSAMPLE) { - stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */ - stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); - - stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); - } else { - stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); - stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); - /* larger -> slower */ - stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); - } - - /* set_gain also sets red and blue balance */ - pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]); - pb0100_set_autogain_target(&sd->gspca_dev, - sensor_settings[AUTOGAIN_TARGET_IDX]); - pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]); - - err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1)); - PDEBUG(D_STREAM, "Started stream, status: %d", err); - - return (err < 0) ? err : 0; -} - -static int pb0100_stop(struct sd *sd) -{ - int err; - - err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1); - - if (err < 0) - goto out; - - /* Set bit 1 to zero */ - err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)); - - PDEBUG(D_STREAM, "Halting stream"); -out: - return (err < 0) ? err : 0; -} - -static void pb0100_disconnect(struct sd *sd) -{ - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -/* FIXME: Sort the init commands out and put them into tables, - this is only for getting the camera to work */ -/* FIXME: No error handling for now, - add this once the init has been converted to proper tables */ -static int pb0100_init(struct sd *sd) -{ - stv06xx_write_bridge(sd, STV_REG00, 1); - stv06xx_write_bridge(sd, STV_SCAN_RATE, 0); - - /* Reset sensor */ - stv06xx_write_sensor(sd, PB_RESET, 1); - stv06xx_write_sensor(sd, PB_RESET, 0); - - /* Disable chip */ - stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)); - - /* Gain stuff...*/ - stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6)); - stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12); - - /* Set up auto-exposure */ - /* ADC VREF_HI new setting for a transition - from the Expose1 to the Expose2 setting */ - stv06xx_write_sensor(sd, PB_R28, 12); - /* gain max for autoexposure */ - stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180); - /* gain min for autoexposure */ - stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12); - /* Maximum frame integration time (programmed into R8) - allowed for auto-exposure routine */ - stv06xx_write_sensor(sd, PB_R54, 3); - /* Minimum frame integration time (programmed into R8) - allowed for auto-exposure routine */ - stv06xx_write_sensor(sd, PB_R55, 0); - stv06xx_write_sensor(sd, PB_UPDATEINT, 1); - /* R15 Expose0 (maximum that auto-exposure may use) */ - stv06xx_write_sensor(sd, PB_R15, 800); - /* R17 Expose2 (minimum that auto-exposure may use) */ - stv06xx_write_sensor(sd, PB_R17, 10); - - stv06xx_write_sensor(sd, PB_EXPGAIN, 0); - - /* 0x14 */ - stv06xx_write_sensor(sd, PB_VOFFSET, 0); - /* 0x0D */ - stv06xx_write_sensor(sd, PB_ADCGAINH, 11); - /* Set black level (important!) */ - stv06xx_write_sensor(sd, PB_ADCGAINL, 0); - - /* ??? */ - stv06xx_write_bridge(sd, STV_REG00, 0x11); - stv06xx_write_bridge(sd, STV_REG03, 0x45); - stv06xx_write_bridge(sd, STV_REG04, 0x07); - - /* Scan/timing for the sensor */ - stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1)); - stv06xx_write_sensor(sd, PB_CFILLIN, 14); - stv06xx_write_sensor(sd, PB_VBL, 0); - stv06xx_write_sensor(sd, PB_FINTTIME, 0); - stv06xx_write_sensor(sd, PB_RINTTIME, 123); - - stv06xx_write_bridge(sd, STV_REG01, 0xc2); - stv06xx_write_bridge(sd, STV_REG02, 0xb0); - return 0; -} - -static int pb0100_dump(struct sd *sd) -{ - return 0; -} - -static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - - return 0; -} - -static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - if (sensor_settings[AUTOGAIN_IDX]) - return -EBUSY; - - sensor_settings[GAIN_IDX] = val; - err = stv06xx_write_sensor(sd, PB_G1GAIN, val); - if (!err) - err = stv06xx_write_sensor(sd, PB_G2GAIN, val); - PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err); - - if (!err) - err = pb0100_set_red_balance(gspca_dev, - sensor_settings[RED_BALANCE_IDX]); - if (!err) - err = pb0100_set_blue_balance(gspca_dev, - sensor_settings[BLUE_BALANCE_IDX]); - - return err; -} - -static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[RED_BALANCE_IDX]; - - return 0; -} - -static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - if (sensor_settings[AUTOGAIN_IDX]) - return -EBUSY; - - sensor_settings[RED_BALANCE_IDX] = val; - val += sensor_settings[GAIN_IDX]; - if (val < 0) - val = 0; - else if (val > 255) - val = 255; - - err = stv06xx_write_sensor(sd, PB_RGAIN, val); - PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err); - - return err; -} - -static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BLUE_BALANCE_IDX]; - - return 0; -} - -static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - if (sensor_settings[AUTOGAIN_IDX]) - return -EBUSY; - - sensor_settings[BLUE_BALANCE_IDX] = val; - val += sensor_settings[GAIN_IDX]; - if (val < 0) - val = 0; - else if (val > 255) - val = 255; - - err = stv06xx_write_sensor(sd, PB_BGAIN, val); - PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err); - - return err; -} - -static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[EXPOSURE_IDX]; - - return 0; -} - -static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - if (sensor_settings[AUTOGAIN_IDX]) - return -EBUSY; - - sensor_settings[EXPOSURE_IDX] = val; - err = stv06xx_write_sensor(sd, PB_RINTTIME, val); - PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err); - - return err; -} - -static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTOGAIN_IDX]; - - return 0; -} - -static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[AUTOGAIN_IDX] = val; - if (sensor_settings[AUTOGAIN_IDX]) { - if (sensor_settings[NATURAL_IDX]) - val = BIT(6)|BIT(4)|BIT(0); - else - val = BIT(4)|BIT(0); - } else - val = 0; - - err = stv06xx_write_sensor(sd, PB_EXPGAIN, val); - PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d", - sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX], - err); - - return err; -} - -static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTOGAIN_TARGET_IDX]; - - return 0; -} - -static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val) -{ - int err, totalpixels, brightpixels, darkpixels; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[AUTOGAIN_TARGET_IDX] = val; - - /* Number of pixels counted by the sensor when subsampling the pixels. - * Slightly larger than the real value to avoid oscillation */ - totalpixels = gspca_dev->width * gspca_dev->height; - totalpixels = totalpixels/(8*8) + totalpixels/(64*64); - - brightpixels = (totalpixels * val) >> 8; - darkpixels = totalpixels - brightpixels; - err = stv06xx_write_sensor(sd, PB_R21, brightpixels); - if (!err) - err = stv06xx_write_sensor(sd, PB_R22, darkpixels); - - PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err); - - return err; -} - -static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[NATURAL_IDX]; - - return 0; -} - -static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[NATURAL_IDX] = val; - - return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * Copyright (c) 2008 Erik Andrén - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * P/N 861037: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express - * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam - * P/N 861075-0040: Sensor HDCS1000 ASIC - * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB - * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web - */ - -#ifndef STV06XX_PB0100_H_ -#define STV06XX_PB0100_H_ - -#include "stv06xx_sensor.h" - -/* mode priv field flags */ -#define PB0100_CROP_TO_VGA 0x01 -#define PB0100_SUBSAMPLE 0x02 - -/* I2C Registers */ -#define PB_IDENT 0x00 /* Chip Version */ -#define PB_RSTART 0x01 /* Row Window Start */ -#define PB_CSTART 0x02 /* Column Window Start */ -#define PB_RWSIZE 0x03 /* Row Window Size */ -#define PB_CWSIZE 0x04 /* Column Window Size */ -#define PB_CFILLIN 0x05 /* Column Fill-In */ -#define PB_VBL 0x06 /* Vertical Blank Count */ -#define PB_CONTROL 0x07 /* Control Mode */ -#define PB_FINTTIME 0x08 /* Integration Time/Frame Unit Count */ -#define PB_RINTTIME 0x09 /* Integration Time/Row Unit Count */ -#define PB_ROWSPEED 0x0a /* Row Speed Control */ -#define PB_ABORTFRAME 0x0b /* Abort Frame */ -#define PB_R12 0x0c /* Reserved */ -#define PB_RESET 0x0d /* Reset */ -#define PB_EXPGAIN 0x0e /* Exposure Gain Command */ -#define PB_R15 0x0f /* Expose0 */ -#define PB_R16 0x10 /* Expose1 */ -#define PB_R17 0x11 /* Expose2 */ -#define PB_R18 0x12 /* Low0_DAC */ -#define PB_R19 0x13 /* Low1_DAC */ -#define PB_R20 0x14 /* Low2_DAC */ -#define PB_R21 0x15 /* Threshold11 */ -#define PB_R22 0x16 /* Threshold0x */ -#define PB_UPDATEINT 0x17 /* Update Interval */ -#define PB_R24 0x18 /* High_DAC */ -#define PB_R25 0x19 /* Trans0H */ -#define PB_R26 0x1a /* Trans1L */ -#define PB_R27 0x1b /* Trans1H */ -#define PB_R28 0x1c /* Trans2L */ -#define PB_R29 0x1d /* Reserved */ -#define PB_R30 0x1e /* Reserved */ -#define PB_R31 0x1f /* Wait to Read */ -#define PB_PREADCTRL 0x20 /* Pixel Read Control Mode */ -#define PB_R33 0x21 /* IREF_VLN */ -#define PB_R34 0x22 /* IREF_VLP */ -#define PB_R35 0x23 /* IREF_VLN_INTEG */ -#define PB_R36 0x24 /* IREF_MASTER */ -#define PB_R37 0x25 /* IDACP */ -#define PB_R38 0x26 /* IDACN */ -#define PB_R39 0x27 /* DAC_Control_Reg */ -#define PB_R40 0x28 /* VCL */ -#define PB_R41 0x29 /* IREF_VLN_ADCIN */ -#define PB_R42 0x2a /* Reserved */ -#define PB_G1GAIN 0x2b /* Green 1 Gain */ -#define PB_BGAIN 0x2c /* Blue Gain */ -#define PB_RGAIN 0x2d /* Red Gain */ -#define PB_G2GAIN 0x2e /* Green 2 Gain */ -#define PB_R47 0x2f /* Dark Row Address */ -#define PB_R48 0x30 /* Dark Row Options */ -#define PB_R49 0x31 /* Reserved */ -#define PB_R50 0x32 /* Image Test Data */ -#define PB_ADCMAXGAIN 0x33 /* Maximum Gain */ -#define PB_ADCMINGAIN 0x34 /* Minimum Gain */ -#define PB_ADCGLOBALGAIN 0x35 /* Global Gain */ -#define PB_R54 0x36 /* Maximum Frame */ -#define PB_R55 0x37 /* Minimum Frame */ -#define PB_R56 0x38 /* Reserved */ -#define PB_VOFFSET 0x39 /* VOFFSET */ -#define PB_R58 0x3a /* Snap-Shot Sequence Trigger */ -#define PB_ADCGAINH 0x3b /* VREF_HI */ -#define PB_ADCGAINL 0x3c /* VREF_LO */ -#define PB_R61 0x3d /* Reserved */ -#define PB_R62 0x3e /* Reserved */ -#define PB_R63 0x3f /* Reserved */ -#define PB_R64 0x40 /* Red/Blue Gain */ -#define PB_R65 0x41 /* Green 2/Green 1 Gain */ -#define PB_R66 0x42 /* VREF_HI/LO */ -#define PB_R67 0x43 /* Integration Time/Row Unit Count */ -#define PB_R240 0xf0 /* ADC Test */ -#define PB_R241 0xf1 /* Chip Enable */ -#define PB_R242 0xf2 /* Reserved */ - -static int pb0100_probe(struct sd *sd); -static int pb0100_start(struct sd *sd); -static int pb0100_init(struct sd *sd); -static int pb0100_stop(struct sd *sd); -static int pb0100_dump(struct sd *sd); -static void pb0100_disconnect(struct sd *sd); - -/* V4L2 controls supported by the driver */ -static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val); -static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val); -static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val); -static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val); - -const struct stv06xx_sensor stv06xx_sensor_pb0100 = { - .name = "PB-0100", - .i2c_flush = 1, - .i2c_addr = 0xba, - .i2c_len = 2, - - .min_packet_size = { 635, 847 }, - .max_packet_size = { 847, 923 }, - - .init = pb0100_init, - .probe = pb0100_probe, - .start = pb0100_start, - .stop = pb0100_stop, - .dump = pb0100_dump, - .disconnect = pb0100_disconnect, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * Copyright (c) 2008 Erik Andrén - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * P/N 861037: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express - * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam - * P/N 861075-0040: Sensor HDCS1000 ASIC - * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB - * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web - */ - -#ifndef STV06XX_SENSOR_H_ -#define STV06XX_SENSOR_H_ - -#include "stv06xx.h" - -#define IS_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020) - -extern const struct stv06xx_sensor stv06xx_sensor_vv6410; -extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00; -extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020; -extern const struct stv06xx_sensor stv06xx_sensor_pb0100; -extern const struct stv06xx_sensor stv06xx_sensor_st6422; - -struct stv06xx_sensor { - /* Defines the name of a sensor */ - char name[32]; - - /* Sensor i2c address */ - u8 i2c_addr; - - /* Flush value*/ - u8 i2c_flush; - - /* length of an i2c word */ - u8 i2c_len; - - /* Isoc packet size (per mode) */ - int min_packet_size[4]; - int max_packet_size[4]; - - /* Probes if the sensor is connected */ - int (*probe)(struct sd *sd); - - /* Performs a initialization sequence */ - int (*init)(struct sd *sd); - - /* Executed at device disconnect */ - void (*disconnect)(struct sd *sd); - - /* Reads a sensor register */ - int (*read_sensor)(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - - /* Writes to a sensor register */ - int (*write_sensor)(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - - /* Instructs the sensor to start streaming */ - int (*start)(struct sd *sd); - - /* Instructs the sensor to stop streaming */ - int (*stop)(struct sd *sd); - - /* Instructs the sensor to dump all its contents */ - int (*dump)(struct sd *sd); -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,401 +0,0 @@ -/* - * Support for the sensor part which is integrated (I think) into the - * st6422 stv06xx alike bridge, as its integrated there are no i2c writes - * but instead direct bridge writes. - * - * Copyright (c) 2009 Hans de Goede - * - * Strongly based on qc-usb-messenger, which is: - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * - * 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, or - * (at your option) any later version. - * - * 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 "stv06xx_st6422.h" - -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - GAIN, - EXPOSURE, - NCTRLS /* number of controls */ -}; - -/* sensor settings */ -struct st6422_settings { - struct gspca_ctrl ctrls[NCTRLS]; -}; - -static struct v4l2_pix_format st6422_mode[] = { - /* Note we actually get 124 lines of data, of which we skip the 4st - 4 as they are garbage */ - { - 162, - 120, - V4L2_PIX_FMT_SGRBG8, - V4L2_FIELD_NONE, - .sizeimage = 162 * 120, - .bytesperline = 162, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 - }, - /* Note we actually get 248 lines of data, of which we skip the 4st - 4 as they are garbage, and we tell the app it only gets the - first 240 of the 244 lines it actually gets, so that it ignores - the last 4. */ - { - 324, - 240, - V4L2_PIX_FMT_SGRBG8, - V4L2_FIELD_NONE, - .sizeimage = 324 * 244, - .bytesperline = 324, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - }, -}; - -/* V4L2 controls supported by the driver */ -static void st6422_set_brightness(struct gspca_dev *gspca_dev); -static void st6422_set_contrast(struct gspca_dev *gspca_dev); -static void st6422_set_gain(struct gspca_dev *gspca_dev); -static void st6422_set_exposure(struct gspca_dev *gspca_dev); - -static const struct ctrl st6422_ctrl[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 31, - .step = 1, - .default_value = 3 - }, - .set_control = st6422_set_brightness - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 11 - }, - .set_control = st6422_set_contrast - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 64 - }, - .set_control = st6422_set_gain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, -#define EXPOSURE_MAX 1023 - .maximum = EXPOSURE_MAX, - .step = 1, - .default_value = 256 - }, - .set_control = st6422_set_exposure - }, -}; - -static int st6422_probe(struct sd *sd) -{ - struct st6422_settings *sensor_settings; - - if (sd->bridge != BRIDGE_ST6422) - return -ENODEV; - - info("st6422 sensor detected"); - - sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - - sd->gspca_dev.cam.cam_mode = st6422_mode; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode); - sd->gspca_dev.cam.ctrls = sensor_settings->ctrls; - sd->desc.ctrls = st6422_ctrl; - sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl); - sd->sensor_priv = sensor_settings; - - return 0; -} - -static int st6422_init(struct sd *sd) -{ - int err = 0, i; - - const u16 st6422_bridge_init[][2] = { - { STV_ISO_ENABLE, 0x00 }, /* disable capture */ - { 0x1436, 0x00 }, - { 0x1432, 0x03 }, /* 0x00-0x1F brightness */ - { 0x143a, 0xf9 }, /* 0x00-0x0F contrast */ - { 0x0509, 0x38 }, /* R */ - { 0x050a, 0x38 }, /* G */ - { 0x050b, 0x38 }, /* B */ - { 0x050c, 0x2a }, - { 0x050d, 0x01 }, - - - { 0x1431, 0x00 }, /* 0x00-0x07 ??? */ - { 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */ - { 0x1438, 0x18 }, /* 640x480 */ -/* 18 bayes */ -/* 10 compressed? */ - - { 0x1439, 0x00 }, -/* anti-noise? 0xa2 gives a perfect image */ - - { 0x143b, 0x05 }, - { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ - - -/* shutter time 0x0000-0x03FF */ -/* low value give good picures on moving objects (but requires much light) */ -/* high value gives good picures in darkness (but tends to be overexposed) */ - { 0x143e, 0x01 }, - { 0x143d, 0x00 }, - - { 0x1442, 0xe2 }, -/* write: 1x1x xxxx */ -/* read: 1x1x xxxx */ -/* bit 5 == button pressed and hold if 0 */ -/* write 0xe2,0xea */ - -/* 0x144a */ -/* 0x00 init */ -/* bit 7 == button has been pressed, but not handled */ - -/* interrupt */ -/* if(urb->iso_frame_desc[i].status == 0x80) { */ -/* if(urb->iso_frame_desc[i].status == 0x88) { */ - - { 0x1500, 0xd0 }, - { 0x1500, 0xd0 }, - { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ - - { 0x1501, 0xaf }, -/* high val-> light area gets darker */ -/* low val -> light area gets lighter */ - { 0x1502, 0xc2 }, -/* high val-> light area gets darker */ -/* low val -> light area gets lighter */ - { 0x1503, 0x45 }, -/* high val-> light area gets darker */ -/* low val -> light area gets lighter */ - { 0x1505, 0x02 }, -/* 2 : 324x248 80352 bytes */ -/* 7 : 248x162 40176 bytes */ -/* c+f: 162*124 20088 bytes */ - - { 0x150e, 0x8e }, - { 0x150f, 0x37 }, - { 0x15c0, 0x00 }, - { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */ - - - { 0x143f, 0x01 }, /* commit settings */ - - }; - - for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) { - err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0], - st6422_bridge_init[i][1]); - } - - return err; -} - -static void st6422_disconnect(struct sd *sd) -{ - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static int setbrightness(struct sd *sd) -{ - struct st6422_settings *sensor_settings = sd->sensor_priv; - - /* val goes from 0 -> 31 */ - return stv06xx_write_bridge(sd, 0x1432, - sensor_settings->ctrls[BRIGHTNESS].val); -} - -static int setcontrast(struct sd *sd) -{ - struct st6422_settings *sensor_settings = sd->sensor_priv; - - /* Val goes from 0 -> 15 */ - return stv06xx_write_bridge(sd, 0x143a, - sensor_settings->ctrls[CONTRAST].val | 0xf0); -} - -static int setgain(struct sd *sd) -{ - struct st6422_settings *sensor_settings = sd->sensor_priv; - u8 gain; - int err; - - gain = sensor_settings->ctrls[GAIN].val; - - /* Set red, green, blue, gain */ - err = stv06xx_write_bridge(sd, 0x0509, gain); - if (err < 0) - return err; - - err = stv06xx_write_bridge(sd, 0x050a, gain); - if (err < 0) - return err; - - err = stv06xx_write_bridge(sd, 0x050b, gain); - if (err < 0) - return err; - - /* 2 mystery writes */ - err = stv06xx_write_bridge(sd, 0x050c, 0x2a); - if (err < 0) - return err; - - return stv06xx_write_bridge(sd, 0x050d, 0x01); -} - -static int setexposure(struct sd *sd) -{ - struct st6422_settings *sensor_settings = sd->sensor_priv; - u16 expo; - int err; - - expo = sensor_settings->ctrls[EXPOSURE].val; - err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff); - if (err < 0) - return err; - - return stv06xx_write_bridge(sd, 0x143e, expo >> 8); -} - -static int st6422_start(struct sd *sd) -{ - int err; - struct cam *cam = &sd->gspca_dev.cam; - - if (cam->cam_mode[sd->gspca_dev.curr_mode].priv) - err = stv06xx_write_bridge(sd, 0x1505, 0x0f); - else - err = stv06xx_write_bridge(sd, 0x1505, 0x02); - if (err < 0) - return err; - - err = setbrightness(sd); - if (err < 0) - return err; - - err = setcontrast(sd); - if (err < 0) - return err; - - err = setexposure(sd); - if (err < 0) - return err; - - err = setgain(sd); - if (err < 0) - return err; - - /* commit settings */ - err = stv06xx_write_bridge(sd, 0x143f, 0x01); - return (err < 0) ? err : 0; -} - -static int st6422_stop(struct sd *sd) -{ - PDEBUG(D_STREAM, "Halting stream"); - - return 0; -} - -static void st6422_set_brightness(struct gspca_dev *gspca_dev) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - - err = setbrightness(sd); - - /* commit settings */ - if (err >= 0) - err = stv06xx_write_bridge(sd, 0x143f, 0x01); - - gspca_dev->usb_err = err; -} - -static void st6422_set_contrast(struct gspca_dev *gspca_dev) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - - err = setcontrast(sd); - - /* commit settings */ - if (err >= 0) - err = stv06xx_write_bridge(sd, 0x143f, 0x01); - - gspca_dev->usb_err = err; -} - -static void st6422_set_gain(struct gspca_dev *gspca_dev) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - - err = setgain(sd); - - /* commit settings */ - if (err >= 0) - err = stv06xx_write_bridge(sd, 0x143f, 0x01); - - gspca_dev->usb_err = err; -} - -static void st6422_set_exposure(struct gspca_dev *gspca_dev) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - - err = setexposure(sd); - - /* commit settings */ - if (err >= 0) - err = stv06xx_write_bridge(sd, 0x143f, 0x01); - - gspca_dev->usb_err = err; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * Support for the sensor part which is integrated (I think) into the - * st6422 stv06xx alike bridge, as its integrated there are no i2c writes - * but instead direct bridge writes. - * - * Copyright (c) 2009 Hans de Goede - * - * Strongly based on qc-usb-messenger, which is: - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * - * 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, or - * (at your option) any later version. - * - * 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 - * - */ - -#ifndef STV06XX_ST6422_H_ -#define STV06XX_ST6422_H_ - -#include "stv06xx_sensor.h" - -static int st6422_probe(struct sd *sd); -static int st6422_start(struct sd *sd); -static int st6422_init(struct sd *sd); -static int st6422_stop(struct sd *sd); -static void st6422_disconnect(struct sd *sd); - -const struct stv06xx_sensor stv06xx_sensor_st6422 = { - .name = "ST6422", - /* No known way to lower framerate in case of less bandwidth */ - .min_packet_size = { 300, 847 }, - .max_packet_size = { 300, 847 }, - .init = st6422_init, - .probe = st6422_probe, - .start = st6422_start, - .stop = st6422_stop, - .disconnect = st6422_disconnect, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,392 +0,0 @@ -/* - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * Copyright (c) 2008 Erik Andrén - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * P/N 861037: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express - * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam - * P/N 861075-0040: Sensor HDCS1000 ASIC - * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB - * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web - */ - -#include "stv06xx_vv6410.h" - -static struct v4l2_pix_format vv6410_mode[] = { - { - 356, - 292, - V4L2_PIX_FMT_SGRBG8, - V4L2_FIELD_NONE, - .sizeimage = 356 * 292, - .bytesperline = 356, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 - } -}; - -static const struct ctrl vv6410_ctrl[] = { -#define HFLIP_IDX 0 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = vv6410_set_hflip, - .get = vv6410_get_hflip - }, -#define VFLIP_IDX 1 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = vv6410_set_vflip, - .get = vv6410_get_vflip - }, -#define GAIN_IDX 2 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "analog gain", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 10 - }, - .set = vv6410_set_analog_gain, - .get = vv6410_get_analog_gain - }, -#define EXPOSURE_IDX 3 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0, - .maximum = 32768, - .step = 1, - .default_value = 20000 - }, - .set = vv6410_set_exposure, - .get = vv6410_get_exposure - } - }; - -static int vv6410_probe(struct sd *sd) -{ - u16 data; - int err, i; - s32 *sensor_settings; - - err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data); - if (err < 0) - return -ENODEV; - - if (data == 0x19) { - info("vv6410 sensor detected"); - - sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32), - GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - - sd->gspca_dev.cam.cam_mode = vv6410_mode; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode); - sd->desc.ctrls = vv6410_ctrl; - sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl); - - for (i = 0; i < sd->desc.nctrls; i++) - sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; - return 0; - } - return -ENODEV; -} - -static int vv6410_init(struct sd *sd) -{ - int err = 0, i; - s32 *sensor_settings = sd->sensor_priv; - - for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { - /* if NULL then len contains single value */ - if (stv_bridge_init[i].data == NULL) { - err = stv06xx_write_bridge(sd, - stv_bridge_init[i].start, - stv_bridge_init[i].len); - } else { - int j; - for (j = 0; j < stv_bridge_init[i].len; j++) - err = stv06xx_write_bridge(sd, - stv_bridge_init[i].start + j, - stv_bridge_init[i].data[j]); - } - } - - if (err < 0) - return err; - - err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, - ARRAY_SIZE(vv6410_sensor_init)); - if (err < 0) - return err; - - err = vv6410_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; - - err = vv6410_set_analog_gain(&sd->gspca_dev, - sensor_settings[GAIN_IDX]); - - return (err < 0) ? err : 0; -} - -static void vv6410_disconnect(struct sd *sd) -{ - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static int vv6410_start(struct sd *sd) -{ - int err; - struct cam *cam = &sd->gspca_dev.cam; - u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; - - if (priv & VV6410_CROP_TO_QVGA) { - PDEBUG(D_CONF, "Cropping to QVGA"); - stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1); - stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1); - } else { - stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1); - stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1); - } - - if (priv & VV6410_SUBSAMPLE) { - PDEBUG(D_CONF, "Enabling subsampling"); - stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); - stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); - - stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); - } else { - stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); - stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); - - stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); - } - - /* Turn on LED */ - err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON); - if (err < 0) - return err; - - err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0); - if (err < 0) - return err; - - PDEBUG(D_STREAM, "Starting stream"); - - return 0; -} - -static int vv6410_stop(struct sd *sd) -{ - int err; - - /* Turn off LED */ - err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF); - if (err < 0) - return err; - - err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE); - if (err < 0) - return err; - - PDEBUG(D_STREAM, "Halting stream"); - - return (err < 0) ? err : 0; -} - -static int vv6410_dump(struct sd *sd) -{ - u8 i; - int err = 0; - - info("Dumping all vv6410 sensor registers"); - for (i = 0; i < 0xff && !err; i++) { - u16 data; - err = stv06xx_read_sensor(sd, i, &data); - info("Register 0x%x contained 0x%x", i, data); - } - return (err < 0) ? err : 0; -} - -static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - - return 0; -} - -static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u16 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[HFLIP_IDX] = val; - err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); - if (err < 0) - return err; - - if (val) - i2c_data |= VV6410_HFLIP; - else - i2c_data &= ~VV6410_HFLIP; - - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); - - return (err < 0) ? err : 0; -} - -static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - -static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u16 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[VFLIP_IDX] = val; - err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); - if (err < 0) - return err; - - if (val) - i2c_data |= VV6410_VFLIP; - else - i2c_data &= ~VV6410_VFLIP; - - PDEBUG(D_V4L2, "Set vertical flip to %d", val); - err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); - - return (err < 0) ? err : 0; -} - -static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - - PDEBUG(D_V4L2, "Read analog gain %d", *val); - - return 0; -} - -static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[GAIN_IDX] = val; - PDEBUG(D_V4L2, "Set analog gain to %d", val); - err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); - - return (err < 0) ? err : 0; -} - -static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[EXPOSURE_IDX]; - - PDEBUG(D_V4L2, "Read exposure %d", *val); - - return 0; -} - -static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - unsigned int fine, coarse; - - sensor_settings[EXPOSURE_IDX] = val; - - val = (val * val >> 14) + val / 4; - - fine = val % VV6410_CIF_LINELENGTH; - coarse = min(512, val / VV6410_CIF_LINELENGTH); - - PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d", - coarse, fine); - - err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8); - if (err < 0) - goto out; - - err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff); - if (err < 0) - goto out; - - err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8); - if (err < 0) - goto out; - - err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff); - -out: - return err; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher - * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland - * Copyright (c) 2002, 2003 Tuukka Toivonen - * Copyright (c) 2008 Erik Andrén - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * P/N 861037: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 - * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express - * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam - * P/N 861075-0040: Sensor HDCS1000 ASIC - * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB - * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web - */ - -#ifndef STV06XX_VV6410_H_ -#define STV06XX_VV6410_H_ - -#include "stv06xx_sensor.h" - -#define VV6410_COLS 416 -#define VV6410_ROWS 320 - -/* Status registers */ -/* Chip identification number including revision indicator */ -#define VV6410_DEVICEH 0x00 -#define VV6410_DEVICEL 0x01 - -/* User can determine whether timed I2C data - has been consumed by interrogating flag states */ -#define VV6410_STATUS0 0x02 - -/* Current line counter value */ -#define VV6410_LINECOUNTH 0x03 -#define VV6410_LINECOUNTL 0x04 - -/* End x coordinate of image size */ -#define VV6410_XENDH 0x05 -#define VV6410_XENDL 0x06 - -/* End y coordinate of image size */ -#define VV6410_YENDH 0x07 -#define VV6410_YENDL 0x08 - -/* This is the average pixel value returned from the - dark line offset cancellation algorithm */ -#define VV6410_DARKAVGH 0x09 -#define VV6410_DARKAVGL 0x0a - -/* This is the average pixel value returned from the - black line offset cancellation algorithm */ -#define VV6410_BLACKAVGH 0x0b -#define VV6410_BLACKAVGL 0x0c - -/* Flags to indicate whether the x or y image coordinates have been clipped */ -#define VV6410_STATUS1 0x0d - -/* Setup registers */ - -/* Low-power/sleep modes & video timing */ -#define VV6410_SETUP0 0x10 - -/* Various parameters */ -#define VV6410_SETUP1 0x11 - -/* Contains pixel counter reset value used by external sync */ -#define VV6410_SYNCVALUE 0x12 - -/* Frame grabbing modes (FST, LST and QCK) */ -#define VV6410_FGMODES 0x14 - -/* FST and QCK mapping modes. */ -#define VV6410_PINMAPPING 0x15 - -/* Data resolution */ -#define VV6410_DATAFORMAT 0x16 - -/* Output coding formats */ -#define VV6410_OPFORMAT 0x17 - -/* Various mode select bits */ -#define VV6410_MODESELECT 0x18 - -/* Exposure registers */ -/* Fine exposure. */ -#define VV6410_FINEH 0x20 -#define VV6410_FINEL 0x21 - -/* Coarse exposure */ -#define VV6410_COARSEH 0x22 -#define VV6410_COARSEL 0x23 - -/* Analog gain setting */ -#define VV6410_ANALOGGAIN 0x24 - -/* Clock division */ -#define VV6410_CLKDIV 0x25 - -/* Dark line offset cancellation value */ -#define VV6410_DARKOFFSETH 0x2c -#define VV6410_DARKOFFSETL 0x2d - -/* Dark line offset cancellation enable */ -#define VV6410_DARKOFFSETSETUP 0x2e - -/* Video timing registers */ -/* Line Length (Pixel Clocks) */ -#define VV6410_LINELENGTHH 0x52 -#define VV6410_LINELENGTHL 0x53 - -/* X-co-ordinate of top left corner of region of interest (x-offset) */ -#define VV6410_XOFFSETH 0x57 -#define VV6410_XOFFSETL 0x58 - -/* Y-coordinate of top left corner of region of interest (y-offset) */ -#define VV6410_YOFFSETH 0x59 -#define VV6410_YOFFSETL 0x5a - -/* Field length (Lines) */ -#define VV6410_FIELDLENGTHH 0x61 -#define VV6410_FIELDLENGTHL 0x62 - -/* System registers */ -/* Black offset cancellation default value */ -#define VV6410_BLACKOFFSETH 0x70 -#define VV6410_BLACKOFFSETL 0x71 - -/* Black offset cancellation setup */ -#define VV6410_BLACKOFFSETSETUP 0x72 - -/* Analog Control Register 0 */ -#define VV6410_CR0 0x75 - -/* Analog Control Register 1 */ -#define VV6410_CR1 0x76 - -/* ADC Setup Register */ -#define VV6410_AS0 0x77 - -/* Analog Test Register */ -#define VV6410_AT0 0x78 - -/* Audio Amplifier Setup Register */ -#define VV6410_AT1 0x79 - -#define VV6410_HFLIP (1 << 3) -#define VV6410_VFLIP (1 << 4) - -#define VV6410_LOW_POWER_MODE (1 << 0) -#define VV6410_SOFT_RESET (1 << 2) -#define VV6410_PAL_25_FPS (0 << 3) - -#define VV6410_CLK_DIV_2 (1 << 1) - -#define VV6410_FINE_EXPOSURE 320 -#define VV6410_COARSE_EXPOSURE 192 -#define VV6410_DEFAULT_GAIN 5 - -#define VV6410_SUBSAMPLE 0x01 -#define VV6410_CROP_TO_QVGA 0x02 - -#define VV6410_CIF_LINELENGTH 415 - -static int vv6410_probe(struct sd *sd); -static int vv6410_start(struct sd *sd); -static int vv6410_init(struct sd *sd); -static int vv6410_stop(struct sd *sd); -static int vv6410_dump(struct sd *sd); -static void vv6410_disconnect(struct sd *sd); - -/* V4L2 controls supported by the driver */ -static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val); -static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val); - -const struct stv06xx_sensor stv06xx_sensor_vv6410 = { - .name = "ST VV6410", - .i2c_flush = 5, - .i2c_addr = 0x20, - .i2c_len = 1, - /* FIXME (see if we can lower packet_size-s, needs testing, and also - adjusting framerate when the bandwidth gets lower) */ - .min_packet_size = { 1023 }, - .max_packet_size = { 1023 }, - .init = vv6410_init, - .probe = vv6410_probe, - .start = vv6410_start, - .stop = vv6410_stop, - .dump = vv6410_dump, - .disconnect = vv6410_disconnect, -}; - -/* If NULL, only single value to write, stored in len */ -struct stv_init { - const u8 *data; - u16 start; - u8 len; -}; - -static const u8 x1500[] = { /* 0x1500 - 0x150f */ - 0x0b, 0xa7, 0xb7, 0x00, 0x00 -}; - -static const u8 x1536[] = { /* 0x1536 - 0x153b */ - 0x02, 0x00, 0x60, 0x01, 0x20, 0x01 -}; - -static const struct stv_init stv_bridge_init[] = { - /* This reg is written twice. Some kind of reset? */ - {NULL, 0x1620, 0x80}, - {NULL, 0x1620, 0x00}, - {NULL, 0x1443, 0x00}, - {NULL, 0x1423, 0x04}, - {x1500, 0x1500, ARRAY_SIZE(x1500)}, - {x1536, 0x1536, ARRAY_SIZE(x1536)}, -}; - -static const u8 vv6410_sensor_init[][2] = { - /* Setup registers */ - {VV6410_SETUP0, VV6410_SOFT_RESET}, - {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, - /* Use shuffled read-out mode */ - {VV6410_SETUP1, BIT(6)}, - /* All modes to 1 */ - {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, - {VV6410_PINMAPPING, 0x00}, - /* Pre-clock generator divide off */ - {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, - - {VV6410_CLKDIV, VV6410_CLK_DIV_2}, - - /* System registers */ - /* Enable voltage doubler */ - {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, - {VV6410_AT0, 0x00}, - /* Power up audio, differential */ - {VV6410_AT1, BIT(4)|BIT(0)}, -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sunplus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sunplus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sunplus.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/sunplus.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1259 +0,0 @@ -/* - * Sunplus spca504(abc) spca533 spca536 library - * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "sunplus" - -#include "gspca.h" -#include "jpeg.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - s8 brightness; - u8 contrast; - u8 colors; - u8 autogain; - u8 quality; -#define QUALITY_MIN 70 -#define QUALITY_MAX 95 -#define QUALITY_DEF 85 - - u8 bridge; -#define BRIDGE_SPCA504 0 -#define BRIDGE_SPCA504B 1 -#define BRIDGE_SPCA504C 2 -#define BRIDGE_SPCA533 3 -#define BRIDGE_SPCA536 4 - u8 subtype; -#define AiptekMiniPenCam13 1 -#define LogitechClickSmart420 2 -#define LogitechClickSmart820 3 -#define MegapixV4 4 -#define MegaImageVI 5 - - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = -128, - .maximum = 127, - .step = 1, -#define BRIGHTNESS_DEF 0 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, -#define CONTRAST_DEF 0x20 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 0xff, - .step = 1, -#define COLOR_DEF 0x1a - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, -}; - -static const struct v4l2_pix_format custom_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 464, - .sizeimage = 464 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, -}; - -static const struct v4l2_pix_format vga_mode2[] = { - {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 4}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 3}, - {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, -}; - -#define SPCA50X_OFFSET_DATA 10 -#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3 -#define SPCA504_PCCAM600_OFFSET_COMPRESS 4 -#define SPCA504_PCCAM600_OFFSET_MODE 5 -#define SPCA504_PCCAM600_OFFSET_DATA 14 - /* Frame packet header offsets for the spca533 */ -#define SPCA533_OFFSET_DATA 16 -#define SPCA533_OFFSET_FRAMSEQ 15 -/* Frame packet header offsets for the spca536 */ -#define SPCA536_OFFSET_DATA 4 -#define SPCA536_OFFSET_FRAMSEQ 1 - -struct cmd { - u8 req; - u16 val; - u16 idx; -}; - -/* Initialisation data for the Creative PC-CAM 600 */ -static const struct cmd spca504_pccam600_init_data[] = { -/* {0xa0, 0x0000, 0x0503}, * capture mode */ - {0x00, 0x0000, 0x2000}, - {0x00, 0x0013, 0x2301}, - {0x00, 0x0003, 0x2000}, - {0x00, 0x0001, 0x21ac}, - {0x00, 0x0001, 0x21a6}, - {0x00, 0x0000, 0x21a7}, /* brightness */ - {0x00, 0x0020, 0x21a8}, /* contrast */ - {0x00, 0x0001, 0x21ac}, /* sat/hue */ - {0x00, 0x0000, 0x21ad}, /* hue */ - {0x00, 0x001a, 0x21ae}, /* saturation */ - {0x00, 0x0002, 0x21a3}, /* gamma */ - {0x30, 0x0154, 0x0008}, - {0x30, 0x0004, 0x0006}, - {0x30, 0x0258, 0x0009}, - {0x30, 0x0004, 0x0000}, - {0x30, 0x0093, 0x0004}, - {0x30, 0x0066, 0x0005}, - {0x00, 0x0000, 0x2000}, - {0x00, 0x0013, 0x2301}, - {0x00, 0x0003, 0x2000}, - {0x00, 0x0013, 0x2301}, - {0x00, 0x0003, 0x2000}, -}; - -/* Creative PC-CAM 600 specific open data, sent before using the - * generic initialisation data from spca504_open_data. - */ -static const struct cmd spca504_pccam600_open_data[] = { - {0x00, 0x0001, 0x2501}, - {0x20, 0x0500, 0x0001}, /* snapshot mode */ - {0x00, 0x0003, 0x2880}, - {0x00, 0x0001, 0x2881}, -}; - -/* Initialisation data for the logitech clicksmart 420 */ -static const struct cmd spca504A_clicksmart420_init_data[] = { -/* {0xa0, 0x0000, 0x0503}, * capture mode */ - {0x00, 0x0000, 0x2000}, - {0x00, 0x0013, 0x2301}, - {0x00, 0x0003, 0x2000}, - {0x00, 0x0001, 0x21ac}, - {0x00, 0x0001, 0x21a6}, - {0x00, 0x0000, 0x21a7}, /* brightness */ - {0x00, 0x0020, 0x21a8}, /* contrast */ - {0x00, 0x0001, 0x21ac}, /* sat/hue */ - {0x00, 0x0000, 0x21ad}, /* hue */ - {0x00, 0x001a, 0x21ae}, /* saturation */ - {0x00, 0x0002, 0x21a3}, /* gamma */ - {0x30, 0x0004, 0x000a}, - {0xb0, 0x0001, 0x0000}, - - - {0xa1, 0x0080, 0x0001}, - {0x30, 0x0049, 0x0000}, - {0x30, 0x0060, 0x0005}, - {0x0c, 0x0004, 0x0000}, - {0x00, 0x0000, 0x0000}, - {0x00, 0x0000, 0x2000}, - {0x00, 0x0013, 0x2301}, - {0x00, 0x0003, 0x2000}, - {0x00, 0x0000, 0x2000}, - -}; - -/* clicksmart 420 open data ? */ -static const struct cmd spca504A_clicksmart420_open_data[] = { - {0x00, 0x0001, 0x2501}, - {0x20, 0x0502, 0x0000}, - {0x06, 0x0000, 0x0000}, - {0x00, 0x0004, 0x2880}, - {0x00, 0x0001, 0x2881}, - - {0xa0, 0x0000, 0x0503}, -}; - -static const u8 qtable_creative_pccam[2][64] = { - { /* Q-table Y-components */ - 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, - 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, - 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, - 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, - 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, - 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, - 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, - 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e}, - { /* Q-table C-components */ - 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, - 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} -}; - -/* FIXME: This Q-table is identical to the Creative PC-CAM one, - * except for one byte. Possibly a typo? - * NWG: 18/05/2003. - */ -static const u8 qtable_spca504_default[2][64] = { - { /* Q-table Y-components */ - 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, - 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, - 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, - 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, - 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, - 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, - 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, - 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e, - }, - { /* Q-table C-components */ - 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, - 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} -}; - -/* read bytes to gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - u8 req, - u16 index, - u16 len) -{ - int ret; - -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); - return; - } -#endif - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, - len ? gspca_dev->usb_buf : NULL, len, - 500); - if (ret < 0) { - err("reg_r err %d", ret); - gspca_dev->usb_err = ret; - } -} - -/* write one byte */ -static void reg_w_1(struct gspca_dev *gspca_dev, - u8 req, - u16 value, - u16 index, - u16 byte) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - gspca_dev->usb_buf[0] = byte; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, - gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { - err("reg_w_1 err %d", ret); - gspca_dev->usb_err = ret; - } -} - -/* write req / index / value */ -static void reg_w_riv(struct gspca_dev *gspca_dev, - u8 req, u16 index, u16 value) -{ - struct usb_device *dev = gspca_dev->dev; - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 500); - if (ret < 0) { - err("reg_w_riv err %d", ret); - gspca_dev->usb_err = ret; - return; - } - PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x", - req, index, value); -} - -/* read 1 byte */ -static u8 reg_r_1(struct gspca_dev *gspca_dev, - u16 value) /* wValue */ -{ - int ret; - - if (gspca_dev->usb_err < 0) - return 0; - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0x20, /* request */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - 0, /* index */ - gspca_dev->usb_buf, 1, - 500); /* timeout */ - if (ret < 0) { - err("reg_r_1 err %d", ret); - gspca_dev->usb_err = ret; - return 0; - } - return gspca_dev->usb_buf[0]; -} - -/* read 1 or 2 bytes */ -static u16 reg_r_12(struct gspca_dev *gspca_dev, - u8 req, /* bRequest */ - u16 index, /* wIndex */ - u16 length) /* wLength (1 or 2 only) */ -{ - int ret; - - if (gspca_dev->usb_err < 0) - return 0; - gspca_dev->usb_buf[1] = 0; - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, - gspca_dev->usb_buf, length, - 500); - if (ret < 0) { - err("reg_r_12 err %d", ret); - gspca_dev->usb_err = ret; - return 0; - } - return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; -} - -static void write_vector(struct gspca_dev *gspca_dev, - const struct cmd *data, int ncmds) -{ - while (--ncmds >= 0) { - reg_w_riv(gspca_dev, data->req, data->idx, data->val); - data++; - } -} - -static void setup_qtable(struct gspca_dev *gspca_dev, - const u8 qtable[2][64]) -{ - int i; - - /* loop over y components */ - for (i = 0; i < 64; i++) - reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]); - - /* loop over c components */ - for (i = 0; i < 64; i++) - reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]); -} - -static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, - u8 req, u16 idx, u16 val) -{ - u16 notdone; - - reg_w_riv(gspca_dev, req, idx, val); - notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); - reg_w_riv(gspca_dev, req, idx, val); - - PDEBUG(D_FRAM, "before wait 0x%04x", notdone); - - msleep(200); - notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); - PDEBUG(D_FRAM, "after wait 0x%04x", notdone); -} - -static void spca504_read_info(struct gspca_dev *gspca_dev) -{ - int i; - u8 info[6]; - - for (i = 0; i < 6; i++) - info[i] = reg_r_1(gspca_dev, i); - PDEBUG(D_STREAM, - "Read info: %d %d %d %d %d %d." - " Should be 1,0,2,2,0,0", - info[0], info[1], info[2], - info[3], info[4], info[5]); -} - -static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, - u8 req, - u16 idx, u16 val, u16 endcode, u8 count) -{ - u16 status; - - reg_w_riv(gspca_dev, req, idx, val); - status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode); - if (!count) - return; - count = 200; - while (--count > 0) { - msleep(10); - /* gsmart mini2 write a each wait setting 1 ms is enough */ -/* reg_w_riv(gspca_dev, req, idx, val); */ - status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); - if (status == endcode) { - PDEBUG(D_FRAM, "status 0x%04x after wait %d", - status, 200 - count); - break; - } - } -} - -static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev) -{ - int count = 10; - - while (--count > 0) { - reg_r(gspca_dev, 0x21, 0, 1); - if ((gspca_dev->usb_buf[0] & 0x01) == 0) - break; - msleep(10); - } -} - -static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) -{ - int count = 50; - - while (--count > 0) { - reg_r(gspca_dev, 0x21, 1, 1); - if (gspca_dev->usb_buf[0] != 0) { - reg_w_1(gspca_dev, 0x21, 0, 1, 0); - reg_r(gspca_dev, 0x21, 1, 1); - spca504B_PollingDataReady(gspca_dev); - break; - } - msleep(10); - } -} - -static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) -{ - u8 *data; - - data = gspca_dev->usb_buf; - reg_r(gspca_dev, 0x20, 0, 5); - PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ", - data[0], data[1], data[2], data[3], data[4]); - reg_r(gspca_dev, 0x23, 0, 64); - reg_r(gspca_dev, 0x23, 1, 64); -} - -static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 Size; - - Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - switch (sd->bridge) { - case BRIDGE_SPCA533: - reg_w_riv(gspca_dev, 0x31, 0, 0); - spca504B_WaitCmdStatus(gspca_dev); - spca504B_PollingDataReady(gspca_dev); - spca50x_GetFirmware(gspca_dev); - reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ - reg_r(gspca_dev, 0x24, 8, 1); - - reg_w_1(gspca_dev, 0x25, 0, 4, Size); - reg_r(gspca_dev, 0x25, 4, 1); /* size */ - spca504B_PollingDataReady(gspca_dev); - - /* Init the cam width height with some values get on init ? */ - reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00); - spca504B_WaitCmdStatus(gspca_dev); - spca504B_PollingDataReady(gspca_dev); - break; - default: -/* case BRIDGE_SPCA504B: */ -/* case BRIDGE_SPCA536: */ - reg_w_1(gspca_dev, 0x25, 0, 4, Size); - reg_r(gspca_dev, 0x25, 4, 1); /* size */ - reg_w_1(gspca_dev, 0x27, 0, 0, 6); - reg_r(gspca_dev, 0x27, 0, 1); /* type */ - spca504B_PollingDataReady(gspca_dev); - break; - case BRIDGE_SPCA504: - Size += 3; - if (sd->subtype == AiptekMiniPenCam13) { - /* spca504a aiptek */ - spca504A_acknowledged_command(gspca_dev, - 0x08, Size, 0, - 0x80 | (Size & 0x0f), 1); - spca504A_acknowledged_command(gspca_dev, - 1, 3, 0, 0x9f, 0); - } else { - spca504_acknowledged_command(gspca_dev, 0x08, Size, 0); - } - break; - case BRIDGE_SPCA504C: - /* capture mode */ - reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); - reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); - break; - } -} - -static void spca504_wait_status(struct gspca_dev *gspca_dev) -{ - int cnt; - - cnt = 256; - while (--cnt > 0) { - /* With this we get the status, when return 0 it's all ok */ - if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0) - return; - msleep(10); - } -} - -static void spca504B_setQtable(struct gspca_dev *gspca_dev) -{ - reg_w_1(gspca_dev, 0x26, 0, 0, 3); - reg_r(gspca_dev, 0x26, 0, 1); - spca504B_PollingDataReady(gspca_dev); -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 reg; - - reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7; - reg_w_riv(gspca_dev, 0x00, reg, sd->brightness); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 reg; - - reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8; - reg_w_riv(gspca_dev, 0x00, reg, sd->contrast); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 reg; - - reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae; - reg_w_riv(gspca_dev, 0x00, reg, sd->colors); -} - -static void init_ctl_reg(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int pollreg = 1; - - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setcolors(gspca_dev); - - switch (sd->bridge) { - case BRIDGE_SPCA504: - case BRIDGE_SPCA504C: - pollreg = 0; - /* fall thru */ - default: -/* case BRIDGE_SPCA533: */ -/* case BRIDGE_SPCA504B: */ - reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */ - reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */ - reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */ - break; - case BRIDGE_SPCA536: - reg_w_riv(gspca_dev, 0, 0x20f5, 0x40); - reg_w_riv(gspca_dev, 0, 0x20f4, 0x01); - reg_w_riv(gspca_dev, 0, 0x2089, 0x00); - break; - } - if (pollreg) - spca504B_PollingDataReady(gspca_dev); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - - sd->bridge = id->driver_info >> 8; - sd->subtype = id->driver_info; - - if (sd->subtype == AiptekMiniPenCam13) { - - /* try to get the firmware as some cam answer 2.0.1.2.2 - * and should be a spca504b then overwrite that setting */ - reg_r(gspca_dev, 0x20, 0, 1); - switch (gspca_dev->usb_buf[0]) { - case 1: - break; /* (right bridge/subtype) */ - case 2: - sd->bridge = BRIDGE_SPCA504B; - sd->subtype = 0; - break; - default: - return -ENODEV; - } - } - - switch (sd->bridge) { - default: -/* case BRIDGE_SPCA504B: */ -/* case BRIDGE_SPCA504: */ -/* case BRIDGE_SPCA536: */ - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - break; - case BRIDGE_SPCA533: - cam->cam_mode = custom_mode; - if (sd->subtype == MegaImageVI) /* 320x240 only */ - cam->nmodes = ARRAY_SIZE(custom_mode) - 1; - else - cam->nmodes = ARRAY_SIZE(custom_mode); - break; - case BRIDGE_SPCA504C: - cam->cam_mode = vga_mode2; - cam->nmodes = ARRAY_SIZE(vga_mode2); - break; - } - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->quality = QUALITY_DEF; - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->bridge) { - case BRIDGE_SPCA504B: - reg_w_riv(gspca_dev, 0x1d, 0x00, 0); - reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01); - reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00); - reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00); - reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13); - reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00); - /* fall thru */ - case BRIDGE_SPCA533: - spca504B_PollingDataReady(gspca_dev); - spca50x_GetFirmware(gspca_dev); - break; - case BRIDGE_SPCA536: - spca50x_GetFirmware(gspca_dev); - reg_r(gspca_dev, 0x00, 0x5002, 1); - reg_w_1(gspca_dev, 0x24, 0, 0, 0); - reg_r(gspca_dev, 0x24, 0, 1); - spca504B_PollingDataReady(gspca_dev); - reg_w_riv(gspca_dev, 0x34, 0, 0); - spca504B_WaitCmdStatus(gspca_dev); - break; - case BRIDGE_SPCA504C: /* pccam600 */ - PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)"); - reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000); - reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */ - spca504_wait_status(gspca_dev); - if (sd->subtype == LogitechClickSmart420) - write_vector(gspca_dev, - spca504A_clicksmart420_open_data, - ARRAY_SIZE(spca504A_clicksmart420_open_data)); - else - write_vector(gspca_dev, spca504_pccam600_open_data, - ARRAY_SIZE(spca504_pccam600_open_data)); - setup_qtable(gspca_dev, qtable_creative_pccam); - break; - default: -/* case BRIDGE_SPCA504: */ - PDEBUG(D_STREAM, "Opening SPCA504"); - if (sd->subtype == AiptekMiniPenCam13) { - spca504_read_info(gspca_dev); - - /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ - spca504A_acknowledged_command(gspca_dev, 0x24, - 8, 3, 0x9e, 1); - /* Twice sequential need status 0xff->0x9e->0x9d */ - spca504A_acknowledged_command(gspca_dev, 0x24, - 8, 3, 0x9e, 0); - - spca504A_acknowledged_command(gspca_dev, 0x24, - 0, 0, 0x9d, 1); - /******************************/ - /* spca504a aiptek */ - spca504A_acknowledged_command(gspca_dev, 0x08, - 6, 0, 0x86, 1); -/* reg_write (dev, 0, 0x2000, 0); */ -/* reg_write (dev, 0, 0x2883, 1); */ -/* spca504A_acknowledged_command (gspca_dev, 0x08, - 6, 0, 0x86, 1); */ -/* spca504A_acknowledged_command (gspca_dev, 0x24, - 0, 0, 0x9D, 1); */ - reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); - /* L92 sno1t.txt */ - reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); - spca504A_acknowledged_command(gspca_dev, 0x01, - 0x0f, 0, 0xff, 0); - } - /* setup qtable */ - reg_w_riv(gspca_dev, 0, 0x2000, 0); - reg_w_riv(gspca_dev, 0, 0x2883, 1); - setup_qtable(gspca_dev, qtable_spca504_default); - break; - } - return gspca_dev->usb_err; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int enable; - - /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x22); /* JPEG 411 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - - if (sd->bridge == BRIDGE_SPCA504B) - spca504B_setQtable(gspca_dev); - spca504B_SetSizeType(gspca_dev); - switch (sd->bridge) { - default: -/* case BRIDGE_SPCA504B: */ -/* case BRIDGE_SPCA533: */ -/* case BRIDGE_SPCA536: */ - switch (sd->subtype) { - case MegapixV4: - case LogitechClickSmart820: - case MegaImageVI: - reg_w_riv(gspca_dev, 0xf0, 0, 0); - spca504B_WaitCmdStatus(gspca_dev); - reg_r(gspca_dev, 0xf0, 4, 0); - spca504B_WaitCmdStatus(gspca_dev); - break; - default: - reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00); - spca504B_WaitCmdStatus(gspca_dev); - spca504B_PollingDataReady(gspca_dev); - break; - } - break; - case BRIDGE_SPCA504: - if (sd->subtype == AiptekMiniPenCam13) { - spca504_read_info(gspca_dev); - - /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ - spca504A_acknowledged_command(gspca_dev, 0x24, - 8, 3, 0x9e, 1); - /* Twice sequential need status 0xff->0x9e->0x9d */ - spca504A_acknowledged_command(gspca_dev, 0x24, - 8, 3, 0x9e, 0); - spca504A_acknowledged_command(gspca_dev, 0x24, - 0, 0, 0x9d, 1); - } else { - spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); - spca504_read_info(gspca_dev); - spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); - spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); - } - spca504B_SetSizeType(gspca_dev); - reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); - /* L92 sno1t.txt */ - reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); - break; - case BRIDGE_SPCA504C: - if (sd->subtype == LogitechClickSmart420) { - write_vector(gspca_dev, - spca504A_clicksmart420_init_data, - ARRAY_SIZE(spca504A_clicksmart420_init_data)); - } else { - write_vector(gspca_dev, spca504_pccam600_init_data, - ARRAY_SIZE(spca504_pccam600_init_data)); - } - enable = (sd->autogain ? 0x04 : 0x01); - reg_w_riv(gspca_dev, 0x0c, 0x0000, enable); - /* auto exposure */ - reg_w_riv(gspca_dev, 0xb0, 0x0000, enable); - /* auto whiteness */ - - /* set default exposure compensation and whiteness balance */ - reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */ - reg_w_riv(gspca_dev, 0x30, 0x0002, 1600); - spca504B_SetSizeType(gspca_dev); - break; - } - init_ctl_reg(gspca_dev); - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->bridge) { - default: -/* case BRIDGE_SPCA533: */ -/* case BRIDGE_SPCA536: */ -/* case BRIDGE_SPCA504B: */ - reg_w_riv(gspca_dev, 0x31, 0, 0); - spca504B_WaitCmdStatus(gspca_dev); - spca504B_PollingDataReady(gspca_dev); - break; - case BRIDGE_SPCA504: - case BRIDGE_SPCA504C: - reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000); - - if (sd->subtype == AiptekMiniPenCam13) { - /* spca504a aiptek */ -/* spca504A_acknowledged_command(gspca_dev, 0x08, - 6, 0, 0x86, 1); */ - spca504A_acknowledged_command(gspca_dev, 0x24, - 0x00, 0x00, 0x9d, 1); - spca504A_acknowledged_command(gspca_dev, 0x01, - 0x0f, 0x00, 0xff, 1); - } else { - spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); - reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000); - } - break; - } -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, sof = 0; - static u8 ffd9[] = {0xff, 0xd9}; - -/* frames are jpeg 4.1.1 without 0xff escape */ - switch (sd->bridge) { - case BRIDGE_SPCA533: - if (data[0] == 0xff) { - if (data[1] != 0x01) { /* drop packet */ -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; - } - sof = 1; - data += SPCA533_OFFSET_DATA; - len -= SPCA533_OFFSET_DATA; - } else { - data += 1; - len -= 1; - } - break; - case BRIDGE_SPCA536: - if (data[0] == 0xff) { - sof = 1; - data += SPCA536_OFFSET_DATA; - len -= SPCA536_OFFSET_DATA; - } else { - data += 2; - len -= 2; - } - break; - default: -/* case BRIDGE_SPCA504: */ -/* case BRIDGE_SPCA504B: */ - switch (data[0]) { - case 0xfe: /* start of frame */ - sof = 1; - data += SPCA50X_OFFSET_DATA; - len -= SPCA50X_OFFSET_DATA; - break; - case 0xff: /* drop packet */ -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; - default: - data += 1; - len -= 1; - break; - } - break; - case BRIDGE_SPCA504C: - switch (data[0]) { - case 0xfe: /* start of frame */ - sof = 1; - data += SPCA504_PCCAM600_OFFSET_DATA; - len -= SPCA504_PCCAM600_OFFSET_DATA; - break; - case 0xff: /* drop packet */ -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; - default: - data += 1; - len -= 1; - break; - } - break; - } - if (sof) { /* start of frame */ - gspca_frame_add(gspca_dev, LAST_PACKET, - ffd9, 2); - - /* put the JPEG header in the new frame */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - } - - /* add 0x00 after 0xff */ - i = 0; - do { - if (data[i] == 0xff) { - gspca_frame_add(gspca_dev, INTER_PACKET, - data, i + 1); - len -= i; - data += i; - *data = 0x00; - i = 0; - } - i++; - } while (i < len); - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - return 0; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return gspca_dev->usb_err; -} - -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, -}; - -/* -- module initialisation -- */ -#define BS(bridge, subtype) \ - .driver_info = (BRIDGE_ ## bridge << 8) \ - | (subtype) -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)}, - {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)}, - {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)}, - {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)}, - {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)}, - {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)}, - {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)}, - {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)}, - {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)}, - {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)}, - {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)}, - {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)}, - {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)}, - {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)}, - {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)}, - {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)}, - {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)}, - {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)}, - {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)}, - {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)}, - {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)}, - {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)}, - {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)}, - {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)}, - {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)}, - {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)}, - {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)}, - {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)}, - {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)}, - {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)}, - {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)}, - {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)}, - {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)}, - {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)}, - {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)}, - {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)}, - {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)}, - {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)}, - {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)}, - {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)}, - {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)}, - {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)}, - {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)}, - {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)}, - {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)}, - {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)}, - {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)}, - {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)}, - {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)}, - {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)}, - {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)}, - {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)}, - {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)}, - {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)}, - {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)}, - {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)}, - {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)}, - {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)}, - {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/t613.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/t613.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/t613.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/t613.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1455 +0,0 @@ -/* - * T613 subdriver - * - * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr) - * - * 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, or - * any later version. - * - * 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 - * - *Notes: * t613 + tas5130A - * * Focus to light do not balance well as in win. - * Quality in win is not good, but its kinda better. - * * Fix some "extraneous bytes", most of apps will show the image anyway - * * Gamma table, is there, but its really doing something? - * * 7~8 Fps, its ok, max on win its 10. - * Costantino Leandro - */ - -#define MODULE_NAME "t613" - -#include -#include "gspca.h" - -#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0) - -MODULE_AUTHOR("Leandro Costantino "); -MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver"); -MODULE_LICENSE("GPL"); - -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - u8 brightness; - u8 contrast; - u8 colors; - u8 autogain; - u8 gamma; - u8 sharpness; - u8 freq; - u8 red_gain; - u8 blue_gain; - u8 green_gain; - u8 awb; /* set default r/g/b and activate */ - u8 mirror; - u8 effect; - - u8 sensor; -}; -enum sensors { - SENSOR_OM6802, - SENSOR_OTHER, - SENSOR_TAS5130A, - SENSOR_LT168G, /* must verify if this is the actual model */ -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); - -static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); - -static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val); -static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 14, - .step = 1, -#define BRIGHTNESS_DEF 8 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0x0d, - .step = 1, -#define CONTRAST_DEF 0x07 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 0x0f, - .step = 1, -#define COLORS_DEF 0x05 - .default_value = COLORS_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -#define GAMMA_MAX 16 -#define GAMMA_DEF 10 - { - { - .id = V4L2_CID_GAMMA, /* (gamma on win) */ - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = GAMMA_MAX - 1, - .step = 1, - .default_value = GAMMA_DEF, - }, - .set = sd_setgamma, - .get = sd_getgamma, - }, - { - { - .id = V4L2_CID_BACKLIGHT_COMPENSATION, /* Activa lowlight, - * some apps dont bring up the - * backligth_compensation control) */ - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Low Light", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 0x01 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setlowlight, - .get = sd_getlowlight, - }, - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror Image", - .minimum = 0, - .maximum = 1, - .step = 1, -#define MIRROR_DEF 0 - .default_value = MIRROR_DEF, - }, - .set = sd_setmirror, - .get = sd_getmirror - }, - { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light Frequency Filter", - .minimum = 1, /* 1 -> 0x50, 2->0x60 */ - .maximum = 2, - .step = 1, -#define FREQ_DEF 1 - .default_value = FREQ_DEF, - }, - .set = sd_setfreq, - .get = sd_getfreq}, - - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Auto White Balance", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AWB_DEF 0 - .default_value = AWB_DEF, - }, - .set = sd_setawb, - .get = sd_getawb - }, - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 15, - .step = 1, -#define SHARPNESS_DEF 0x06 - .default_value = SHARPNESS_DEF, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, - { - { - .id = V4L2_CID_EFFECTS, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Webcam Effects", - .minimum = 0, - .maximum = 4, - .step = 1, -#define EFFECTS_DEF 0 - .default_value = EFFECTS_DEF, - }, - .set = sd_seteffect, - .get = sd_geteffect - }, - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 0x10, - .maximum = 0x40, - .step = 1, -#define BLUE_GAIN_DEF 0x20 - .default_value = BLUE_GAIN_DEF, - }, - .set = sd_setblue_gain, - .get = sd_getblue_gain, - }, - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 0x10, - .maximum = 0x40, - .step = 1, -#define RED_GAIN_DEF 0x20 - .default_value = RED_GAIN_DEF, - }, - .set = sd_setred_gain, - .get = sd_getred_gain, - }, - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0x10, - .maximum = 0x40, - .step = 1, -#define GAIN_DEF 0x20 - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - -static const struct v4l2_pix_format vga_mode_t16[] = { - {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 4}, - {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 3}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, - {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -/* sensor specific data */ -struct additional_sensor_data { - const u8 n3[6]; - const u8 *n4, n4sz; - const u8 reg80, reg8e; - const u8 nset8[6]; - const u8 data1[10]; - const u8 data2[9]; - const u8 data3[9]; - const u8 data5[6]; - const u8 stream[4]; -}; - -static const u8 n4_om6802[] = { - 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c, - 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68, - 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1, - 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8, - 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48, - 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0, - 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68, - 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40, - 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46 -}; -static const u8 n4_other[] = { - 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69, - 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68, - 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8, - 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8, - 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56, - 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5, - 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0, - 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00 -}; -static const u8 n4_tas5130a[] = { - 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20, - 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4, - 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10, - 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08, - 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a, - 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8, - 0xc6, 0xda -}; -static const u8 n4_lt168g[] = { - 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28, - 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70, - 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3, - 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20, - 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68, - 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40, - 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0, - 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c, - 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80 -}; - -static const struct additional_sensor_data sensor_data[] = { -[SENSOR_OM6802] = { - .n3 = - {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04}, - .n4 = n4_om6802, - .n4sz = sizeof n4_om6802, - .reg80 = 0x3c, - .reg8e = 0x33, - .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00}, - .data1 = - {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06, - 0xb3, 0xfc}, - .data2 = - {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff, - 0xff}, - .data3 = - {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff, - 0xff}, - .data5 = /* this could be removed later */ - {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23}, - .stream = - {0x0b, 0x04, 0x0a, 0x78}, - }, -[SENSOR_OTHER] = { - .n3 = - {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00}, - .n4 = n4_other, - .n4sz = sizeof n4_other, - .reg80 = 0xac, - .reg8e = 0xb8, - .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00}, - .data1 = - {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a, - 0xe8, 0xfc}, - .data2 = - {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96, - 0xd9}, - .data3 = - {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96, - 0xd9}, - .data5 = - {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69}, - .stream = - {0x0b, 0x04, 0x0a, 0x00}, - }, -[SENSOR_TAS5130A] = { - .n3 = - {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08}, - .n4 = n4_tas5130a, - .n4sz = sizeof n4_tas5130a, - .reg80 = 0x3c, - .reg8e = 0xb4, - .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00}, - .data1 = - {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27, - 0xc8, 0xfc}, - .data2 = - {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8, - 0xe0}, - .data3 = - {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8, - 0xe0}, - .data5 = - {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20}, - .stream = - {0x0b, 0x04, 0x0a, 0x40}, - }, -[SENSOR_LT168G] = { - .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00}, - .n4 = n4_lt168g, - .n4sz = sizeof n4_lt168g, - .reg80 = 0x7c, - .reg8e = 0xb3, - .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00}, - .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40, - 0xb0, 0xf4}, - .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6, - 0xff}, - .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6, - 0xff}, - .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b}, - .stream = {0x0b, 0x04, 0x0a, 0x28}, - }, -}; - -#define MAX_EFFECTS 7 -/* easily done by soft, this table could be removed, - * i keep it here just in case */ -static char *effects_control[MAX_EFFECTS] = { - "Normal", - "Emboss", /* disabled */ - "Monochrome", - "Sepia", - "Sketch", - "Sun Effect", /* disabled */ - "Negative", -}; -static const u8 effects_table[MAX_EFFECTS][6] = { - {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */ - {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */ - {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */ - {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */ - {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */ - {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */ - {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */ -}; - -static const u8 gamma_table[GAMMA_MAX][17] = { -/* gamma table from cam1690.ini */ - {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */ - 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb, - 0xff}, - {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */ - 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1, - 0xff}, - {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */ - 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3, - 0xff}, - {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */ - 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6, - 0xff}, - {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */ - 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9, - 0xff}, - {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */ - 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec, - 0xff}, - {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */ - 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, - 0xff}, - {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */ - 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - 0xff}, - {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */ - 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0, - 0xff}, - {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */ - 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2, - 0xff}, - {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */ - 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3, - 0xff}, - {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */ - 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5, - 0xff}, - {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */ - 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6, - 0xff}, - {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */ - 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9, - 0xff}, - {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */ - 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa, - 0xff}, - {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */ - 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc, - 0xff} -}; - -static const u8 tas5130a_sensor_init[][8] = { - {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09}, - {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09}, - {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}, -}; - -static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07}; - -/* read 1 byte */ -static u8 reg_r(struct gspca_dev *gspca_dev, - u16 index) -{ - usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, - gspca_dev->usb_buf, 1, 500); - return gspca_dev->usb_buf[0]; -} - -static void reg_w(struct gspca_dev *gspca_dev, - u16 index) -{ - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, - NULL, 0, 500); -} - -static void reg_w_buf(struct gspca_dev *gspca_dev, - const u8 *buffer, u16 len) -{ - if (len <= USB_BUF_SZ) { - memcpy(gspca_dev->usb_buf, buffer, len); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x01, 0, - gspca_dev->usb_buf, len, 500); - } else { - u8 *tmpbuf; - - tmpbuf = kmemdup(buffer, len, GFP_KERNEL); - if (!tmpbuf) { - err("Out of memory"); - return; - } - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x01, 0, - tmpbuf, len, 500); - kfree(tmpbuf); - } -} - -/* write values to consecutive registers */ -static void reg_w_ixbuf(struct gspca_dev *gspca_dev, - u8 reg, - const u8 *buffer, u16 len) -{ - int i; - u8 *p, *tmpbuf; - - if (len * 2 <= USB_BUF_SZ) { - p = tmpbuf = gspca_dev->usb_buf; - } else { - p = tmpbuf = kmalloc(len * 2, GFP_KERNEL); - if (!tmpbuf) { - err("Out of memory"); - return; - } - } - i = len; - while (--i >= 0) { - *p++ = reg++; - *p++ = *buffer++; - } - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x01, 0, - tmpbuf, len * 2, 500); - if (len * 2 > USB_BUF_SZ) - kfree(tmpbuf); -} - -static void om6802_sensor_init(struct gspca_dev *gspca_dev) -{ - int i; - const u8 *p; - u8 byte; - u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05}; - static const u8 sensor_init[] = { - 0xdf, 0x6d, - 0xdd, 0x18, - 0x5a, 0xe0, - 0x5c, 0x07, - 0x5d, 0xb0, - 0x5e, 0x1e, - 0x60, 0x71, - 0xef, 0x00, - 0xe9, 0x00, - 0xea, 0x00, - 0x90, 0x24, - 0x91, 0xb2, - 0x82, 0x32, - 0xfd, 0x41, - 0x00 /* table end */ - }; - - reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset); - msleep(100); - i = 4; - while (--i > 0) { - byte = reg_r(gspca_dev, 0x0060); - if (!(byte & 0x01)) - break; - msleep(100); - } - byte = reg_r(gspca_dev, 0x0063); - if (byte != 0x17) { - err("Bad sensor reset %02x", byte); - /* continue? */ - } - - p = sensor_init; - while (*p != 0) { - val[1] = *p++; - val[3] = *p++; - if (*p == 0) - reg_w(gspca_dev, 0x3c80); - reg_w_buf(gspca_dev, val, sizeof val); - i = 4; - while (--i >= 0) { - msleep(15); - byte = reg_r(gspca_dev, 0x60); - if (!(byte & 0x01)) - break; - } - } - msleep(15); - reg_w(gspca_dev, 0x3c80); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - - cam->cam_mode = vga_mode_t16; - cam->nmodes = ARRAY_SIZE(vga_mode_t16); - - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLORS_DEF; - sd->gamma = GAMMA_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->mirror = MIRROR_DEF; - sd->freq = FREQ_DEF; - sd->awb = AWB_DEF; - sd->sharpness = SHARPNESS_DEF; - sd->effect = EFFECTS_DEF; - sd->red_gain = RED_GAIN_DEF; - sd->blue_gain = BLUE_GAIN_DEF; - sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF; - - return 0; -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - unsigned int brightness; - u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 }; - - brightness = sd->brightness; - if (brightness < 7) { - set6[1] = 0x26; - set6[3] = 0x70 - brightness * 0x10; - } else { - set6[3] = 0x00 + ((brightness - 7) * 0x10); - } - - reg_w_buf(gspca_dev, set6, sizeof set6); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - unsigned int contrast = sd->contrast; - u16 reg_to_write; - - if (contrast < 7) - reg_to_write = 0x8ea9 - contrast * 0x200; - else - reg_to_write = 0x00a9 + (contrast - 7) * 0x200; - - reg_w(gspca_dev, reg_to_write); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 reg_to_write; - - reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */ - reg_w(gspca_dev, reg_to_write); -} - -static void setgamma(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - PDEBUG(D_CONF, "Gamma: %d", sd->gamma); - reg_w_ixbuf(gspca_dev, 0x90, - gamma_table[sd->gamma], sizeof gamma_table[0]); -} - -static void setRGB(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 all_gain_reg[6] = - {0x87, 0x00, 0x88, 0x00, 0x89, 0x00}; - - all_gain_reg[1] = sd->red_gain; - all_gain_reg[3] = sd->blue_gain; - all_gain_reg[5] = sd->green_gain; - reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg); -} - -/* Generic fnc for r/b balance, exposure and awb */ -static void setawb(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 reg80; - - reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80; - - /* on awb leave defaults values */ - if (!sd->awb) { - /* shoud we wait here.. */ - /* update and reset RGB gains with webcam values */ - sd->red_gain = reg_r(gspca_dev, 0x0087); - sd->blue_gain = reg_r(gspca_dev, 0x0088); - sd->green_gain = reg_r(gspca_dev, 0x0089); - reg80 &= ~0x0400; /* AWB off */ - } - reg_w(gspca_dev, reg80); - reg_w(gspca_dev, reg80); -} - -static void init_gains(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 reg80; - u8 all_gain_reg[8] = - {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00}; - - all_gain_reg[1] = sd->red_gain; - all_gain_reg[3] = sd->blue_gain; - all_gain_reg[5] = sd->green_gain; - reg80 = sensor_data[sd->sensor].reg80; - if (!sd->awb) - reg80 &= ~0x04; - all_gain_reg[7] = reg80; - reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg); - - reg_w(gspca_dev, (sd->red_gain << 8) + 0x87); - reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88); - reg_w(gspca_dev, (sd->green_gain << 8) + 0x89); -} - -static void setsharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 reg_to_write; - - reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness; - - reg_w(gspca_dev, reg_to_write); -} - -static void setfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 reg66; - u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 }; - - switch (sd->sensor) { - case SENSOR_LT168G: - if (sd->freq != 0) - freq[3] = 0xa8; - reg66 = 0x41; - break; - case SENSOR_OM6802: - reg66 = 0xca; - break; - default: - reg66 = 0x40; - break; - } - switch (sd->freq) { - case 0: /* no flicker */ - freq[3] = 0xf0; - break; - case 2: /* 60Hz */ - reg66 &= ~0x40; - break; - } - freq[1] = reg66; - - reg_w_buf(gspca_dev, freq, sizeof freq); -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - /* some of this registers are not really neded, because - * they are overriden by setbrigthness, setcontrast, etc, - * but wont hurt anyway, and can help someone with similar webcam - * to see the initial parameters.*/ - struct sd *sd = (struct sd *) gspca_dev; - const struct additional_sensor_data *sensor; - int i; - u16 sensor_id; - u8 test_byte = 0; - - static const u8 read_indexs[] = - { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5, - 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 }; - static const u8 n1[] = - {0x08, 0x03, 0x09, 0x03, 0x12, 0x04}; - static const u8 n2[] = - {0x08, 0x00}; - - sensor_id = (reg_r(gspca_dev, 0x06) << 8) - | reg_r(gspca_dev, 0x07); - switch (sensor_id & 0xff0f) { - case 0x0801: - PDEBUG(D_PROBE, "sensor tas5130a"); - sd->sensor = SENSOR_TAS5130A; - break; - case 0x0802: - PDEBUG(D_PROBE, "sensor lt168g"); - sd->sensor = SENSOR_LT168G; - break; - case 0x0803: - PDEBUG(D_PROBE, "sensor 'other'"); - sd->sensor = SENSOR_OTHER; - break; - case 0x0807: - PDEBUG(D_PROBE, "sensor om6802"); - sd->sensor = SENSOR_OM6802; - break; - default: - err("unknown sensor %04x", sensor_id); - return -EINVAL; - } - - if (sd->sensor == SENSOR_OM6802) { - reg_w_buf(gspca_dev, n1, sizeof n1); - i = 5; - while (--i >= 0) { - reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset); - test_byte = reg_r(gspca_dev, 0x0063); - msleep(100); - if (test_byte == 0x17) - break; /* OK */ - } - if (i < 0) { - err("Bad sensor reset %02x", test_byte); - return -EIO; - } - reg_w_buf(gspca_dev, n2, sizeof n2); - } - - i = 0; - while (read_indexs[i] != 0x00) { - test_byte = reg_r(gspca_dev, read_indexs[i]); - PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i], - test_byte); - i++; - } - - sensor = &sensor_data[sd->sensor]; - reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3); - reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz); - - if (sd->sensor == SENSOR_LT168G) { - test_byte = reg_r(gspca_dev, 0x80); - PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80, - test_byte); - reg_w(gspca_dev, 0x6c80); - } - - reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1); - reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2); - reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3); - - reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80); - reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80); - reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e); - - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setgamma(gspca_dev); - setcolors(gspca_dev); - setsharpness(gspca_dev); - init_gains(gspca_dev); - setfreq(gspca_dev); - - reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5); - reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8); - reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); - - if (sd->sensor == SENSOR_LT168G) { - test_byte = reg_r(gspca_dev, 0x80); - PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80, - test_byte); - reg_w(gspca_dev, 0x6c80); - } - - reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1); - reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2); - reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3); - - return 0; -} - -static void setmirror(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 hflipcmd[8] = - {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}; - - if (sd->mirror) - hflipcmd[3] = 0x01; - - reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd); -} - -static void seteffect(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w_buf(gspca_dev, effects_table[sd->effect], - sizeof effects_table[0]); - if (sd->effect == 1 || sd->effect == 5) { - PDEBUG(D_CONF, - "This effect have been disabled for webcam \"safety\""); - return; - } - - if (sd->effect == 1 || sd->effect == 4) - reg_w(gspca_dev, 0x4aa6); - else - reg_w(gspca_dev, 0xfaa6); -} - -/* Is this really needed? - * i added some module parameters for test with some users */ -static void poll_sensor(struct gspca_dev *gspca_dev) -{ - static const u8 poll1[] = - {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82, - 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34, - 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01, - 0x60, 0x14}; - static const u8 poll2[] = - {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9, - 0x73, 0x02, 0x73, 0x02, 0x60, 0x14}; - static const u8 noise03[] = /* (some differences / ms-drv) */ - {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f, - 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c, - 0xc2, 0x80, 0xc3, 0x10}; - - PDEBUG(D_STREAM, "[Sensor requires polling]"); - reg_w_buf(gspca_dev, poll1, sizeof poll1); - reg_w_buf(gspca_dev, poll2, sizeof poll2); - reg_w_buf(gspca_dev, noise03, sizeof noise03); -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - const struct additional_sensor_data *sensor; - int i, mode; - u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 }; - static const u8 t3[] = - { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 }; - - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - switch (mode) { - case 0: /* 640x480 (0x00) */ - break; - case 1: /* 352x288 */ - t2[1] = 0x40; - break; - case 2: /* 320x240 */ - t2[1] = 0x10; - break; - case 3: /* 176x144 */ - t2[1] = 0x50; - break; - default: -/* case 4: * 160x120 */ - t2[1] = 0x20; - break; - } - - switch (sd->sensor) { - case SENSOR_OM6802: - om6802_sensor_init(gspca_dev); - break; - case SENSOR_TAS5130A: - i = 0; - for (;;) { - reg_w_buf(gspca_dev, tas5130a_sensor_init[i], - sizeof tas5130a_sensor_init[0]); - if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1) - break; - i++; - } - reg_w(gspca_dev, 0x3c80); - /* just in case and to keep sync with logs (for mine) */ - reg_w_buf(gspca_dev, tas5130a_sensor_init[i], - sizeof tas5130a_sensor_init[0]); - reg_w(gspca_dev, 0x3c80); - break; - } - sensor = &sensor_data[sd->sensor]; - setfreq(gspca_dev); - reg_r(gspca_dev, 0x0012); - reg_w_buf(gspca_dev, t2, sizeof t2); - reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3); - reg_w(gspca_dev, 0x0013); - msleep(15); - reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); - reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); - - if (sd->sensor == SENSOR_OM6802) - poll_sensor(gspca_dev); - - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream, - sizeof sensor_data[sd->sensor].stream); - reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream, - sizeof sensor_data[sd->sensor].stream); - if (sd->sensor == SENSOR_OM6802) { - msleep(20); - reg_w(gspca_dev, 0x0309); - } -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - int pkt_type; - - if (data[0] == 0x5a) { - /* Control Packet, after this came the header again, - * but extra bytes came in the packet before this, - * sometimes an EOF arrives, sometimes not... */ - return; - } - data += 2; - len -= 2; - if (data[0] == 0xff && data[1] == 0xd8) - pkt_type = FIRST_PACKET; - else if (data[len - 2] == 0xff && data[len - 1] == 0xd9) - pkt_type = LAST_PACKET; - else - pkt_type = INTER_PACKET; - gspca_frame_add(gspca_dev, pkt_type, data, len); -} - -static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->blue_gain = val; - if (gspca_dev->streaming) - reg_w(gspca_dev, (val << 8) + 0x88); - return 0; -} - -static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->blue_gain; - return 0; -} - -static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->red_gain = val; - if (gspca_dev->streaming) - reg_w(gspca_dev, (val << 8) + 0x87); - - return 0; -} - -static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->red_gain; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 psg, nsg; - - psg = sd->red_gain + sd->blue_gain + sd->green_gain; - nsg = val * 3; - sd->red_gain = sd->red_gain * nsg / psg; - if (sd->red_gain > 0x40) - sd->red_gain = 0x40; - else if (sd->red_gain < 0x10) - sd->red_gain = 0x10; - sd->blue_gain = sd->blue_gain * nsg / psg; - if (sd->blue_gain > 0x40) - sd->blue_gain = 0x40; - else if (sd->blue_gain < 0x10) - sd->blue_gain = 0x10; - sd->green_gain = sd->green_gain * nsg / psg; - if (sd->green_gain > 0x40) - sd->green_gain = 0x40; - else if (sd->green_gain < 0x10) - sd->green_gain = 0x10; - - if (gspca_dev->streaming) - setRGB(gspca_dev); - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3; - return 0; -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return *val; -} - -static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->awb = val; - if (gspca_dev->streaming) - setawb(gspca_dev); - return 0; -} - -static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->awb; - return *val; -} - -static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->mirror = val; - if (gspca_dev->streaming) - setmirror(gspca_dev); - return 0; -} - -static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->mirror; - return *val; -} - -static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->effect = val; - if (gspca_dev->streaming) - seteffect(gspca_dev); - return 0; -} - -static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->effect; - return *val; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return *val; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gamma = val; - if (gspca_dev->streaming) - setgamma(gspca_dev); - return 0; -} - -static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gamma; - return 0; -} - -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->freq = val; - if (gspca_dev->streaming) - setfreq(gspca_dev); - return 0; -} - -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->freq; - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return 0; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - return 0; -} - -/* Low Light set here......*/ -static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - if (val != 0) - reg_w(gspca_dev, 0xf48e); - else - reg_w(gspca_dev, 0xb48e); - return 0; -} - -static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - case V4L2_CID_EFFECTS: - if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { - strncpy((char *) menu->name, - effects_control[menu->index], - sizeof menu->name); - return 0; - } - break; - } - return -EINVAL; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x17a1, 0x0128)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/tv8532.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/tv8532.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/tv8532.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/tv8532.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,433 +0,0 @@ -/* - * Quickcam cameras initialization data - * - * V4L2 by Jean-Francois Moine - * - * 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, or - * any later version. - * - * 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 - * - */ -#define MODULE_NAME "tv8532" - -#include "gspca.h" - -MODULE_AUTHOR("Michel Xhaard "); -MODULE_DESCRIPTION("TV8532 USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - __u16 exposure; - __u16 gain; - - __u8 packet; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 0x18f, - .step = 1, -#define EXPOSURE_DEF 0x18f - .default_value = EXPOSURE_DEF, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 0x7ff, - .step = 1, -#define GAIN_DEF 0x100 - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - -static const struct v4l2_pix_format sif_mode[] = { - {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; - -/* TV-8532A (ICM532A) registers (LE) */ -#define R00_PART_CONTROL 0x00 -#define LATENT_CHANGE 0x80 -#define EXPO_CHANGE 0x04 -#define R01_TIMING_CONTROL_LOW 0x01 -#define CMD_EEprom_Open 0x30 -#define CMD_EEprom_Close 0x29 -#define R03_TABLE_ADDR 0x03 -#define R04_WTRAM_DATA_L 0x04 -#define R05_WTRAM_DATA_M 0x05 -#define R06_WTRAM_DATA_H 0x06 -#define R07_TABLE_LEN 0x07 -#define R08_RAM_WRITE_ACTION 0x08 -#define R0C_AD_WIDTHL 0x0c -#define R0D_AD_WIDTHH 0x0d -#define R0E_AD_HEIGHTL 0x0e -#define R0F_AD_HEIGHTH 0x0f -#define R10_AD_COL_BEGINL 0x10 -#define R11_AD_COL_BEGINH 0x11 -#define MIRROR 0x04 /* [10] */ -#define R14_AD_ROW_BEGINL 0x14 -#define R15_AD_ROWBEGINH 0x15 -#define R1C_AD_EXPOSE_TIMEL 0x1c -#define R20_GAIN_G1L 0x20 -#define R21_GAIN_G1H 0x21 -#define R22_GAIN_RL 0x22 -#define R23_GAIN_RH 0x23 -#define R24_GAIN_BL 0x24 -#define R25_GAIN_BH 0x25 -#define R26_GAIN_G2L 0x26 -#define R27_GAIN_G2H 0x27 -#define R28_QUANT 0x28 -#define R29_LINE 0x29 -#define R2C_POLARITY 0x2c -#define R2D_POINT 0x2d -#define R2E_POINTH 0x2e -#define R2F_POINTB 0x2f -#define R30_POINTBH 0x30 -#define R31_UPD 0x31 -#define R2A_HIGH_BUDGET 0x2a -#define R2B_LOW_BUDGET 0x2b -#define R34_VID 0x34 -#define R35_VIDH 0x35 -#define R36_PID 0x36 -#define R37_PIDH 0x37 -#define R39_Test1 0x39 /* GPIO */ -#define R3B_Test3 0x3b /* GPIO */ -#define R83_AD_IDH 0x83 -#define R91_AD_SLOPEREG 0x91 -#define R94_AD_BITCONTROL 0x94 - -static const u8 eeprom_data[][3] = { -/* dataH dataM dataL */ - {0x01, 0x00, 0x01}, - {0x01, 0x80, 0x11}, - {0x05, 0x00, 0x14}, - {0x05, 0x00, 0x1c}, - {0x0d, 0x00, 0x1e}, - {0x05, 0x00, 0x1f}, - {0x05, 0x05, 0x19}, - {0x05, 0x01, 0x1b}, - {0x05, 0x09, 0x1e}, - {0x0d, 0x89, 0x2e}, - {0x05, 0x89, 0x2f}, - {0x05, 0x0d, 0xd9}, - {0x05, 0x09, 0xf1}, -}; - - -/* write 1 byte */ -static void reg_w1(struct gspca_dev *gspca_dev, - __u16 index, __u8 value) -{ - gspca_dev->usb_buf[0] = value; - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x02, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, 1, 500); -} - -/* write 2 bytes */ -static void reg_w2(struct gspca_dev *gspca_dev, - u16 index, u16 value) -{ - gspca_dev->usb_buf[0] = value; - gspca_dev->usb_buf[1] = value >> 8; - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x02, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, 2, 500); -} - -static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev) -{ - int i; - - reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Open); - for (i = 0; i < ARRAY_SIZE(eeprom_data); i++) { - reg_w1(gspca_dev, R03_TABLE_ADDR, i); - reg_w1(gspca_dev, R04_WTRAM_DATA_L, eeprom_data[i][2]); - reg_w1(gspca_dev, R05_WTRAM_DATA_M, eeprom_data[i][1]); - reg_w1(gspca_dev, R06_WTRAM_DATA_H, eeprom_data[i][0]); - reg_w1(gspca_dev, R08_RAM_WRITE_ACTION, 0); - } - reg_w1(gspca_dev, R07_TABLE_LEN, i); - reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - cam->cam_mode = sif_mode; - cam->nmodes = ARRAY_SIZE(sif_mode); - - sd->exposure = EXPOSURE_DEF; - sd->gain = GAIN_DEF; - return 0; -} - -static void tv_8532_setReg(struct gspca_dev *gspca_dev) -{ - reg_w1(gspca_dev, R3B_Test3, 0x0a); /* Test0Sel = 10 */ - /******************************************************/ - reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90); - reg_w1(gspca_dev, R0F_AD_HEIGHTH, 0x01); - reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f); - reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44); - /* begin active line */ - reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00); - /* mirror and digital gain */ - reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a); - - reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02); - reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00); - reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); - /* = 0x84 */ -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - tv_8532WriteEEprom(gspca_dev); - - return 0; -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->exposure); - reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); - /* 0x84 */ -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w2(gspca_dev, R20_GAIN_G1L, sd->gain); - reg_w2(gspca_dev, R22_GAIN_RL, sd->gain); - reg_w2(gspca_dev, R24_GAIN_BL, sd->gain); - reg_w2(gspca_dev, R26_GAIN_G2L, sd->gain); -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); /* 0x20; 0x0c */ - reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03); - - /************************************************/ - reg_w1(gspca_dev, R28_QUANT, 0x90); - /* 0x72 compressed mode 0x28 */ - if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - /* 176x144 */ - reg_w1(gspca_dev, R29_LINE, 0x41); - /* CIF - 2 lines/packet */ - } else { - /* 352x288 */ - reg_w1(gspca_dev, R29_LINE, 0x81); - /* CIF - 2 lines/packet */ - } - /************************************************/ - reg_w1(gspca_dev, R2C_POLARITY, 0x10); /* slow clock */ - reg_w1(gspca_dev, R2D_POINT, 0x14); - reg_w1(gspca_dev, R2E_POINTH, 0x01); - reg_w1(gspca_dev, R2F_POINTB, 0x12); - reg_w1(gspca_dev, R30_POINTBH, 0x01); - - tv_8532_setReg(gspca_dev); - - setexposure(gspca_dev); - setgain(gspca_dev); - - /************************************************/ - reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */ - msleep(200); - reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */ - - gspca_dev->empty_packet = 0; /* check the empty packets */ - sd->packet = 0; /* ignore the first packets */ - - return 0; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */ -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - int packet_type0, packet_type1; - - packet_type0 = packet_type1 = INTER_PACKET; - if (gspca_dev->empty_packet) { - gspca_dev->empty_packet = 0; - sd->packet = gspca_dev->height / 2; - packet_type0 = FIRST_PACKET; - } else if (sd->packet == 0) - return; /* 2 more lines in 352x288 ! */ - sd->packet--; - if (sd->packet == 0) - packet_type1 = LAST_PACKET; - - /* each packet contains: - * - header 2 bytes - * - RGRG line - * - 4 bytes - * - GBGB line - * - 4 bytes - */ - gspca_frame_add(gspca_dev, packet_type0, - data + 2, gspca_dev->width); - gspca_frame_add(gspca_dev, packet_type1, - data + gspca_dev->width + 5, gspca_dev->width); -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .pkt_scan = sd_pkt_scan, -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x046d, 0x0920)}, - {USB_DEVICE(0x046d, 0x0921)}, - {USB_DEVICE(0x0545, 0x808b)}, - {USB_DEVICE(0x0545, 0x8333)}, - {USB_DEVICE(0x0923, 0x010f)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/vc032x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/vc032x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/vc032x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/vc032x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,4243 +0,0 @@ -/* - * Z-star vc0321 library - * - * Copyright (C) 2009-2010 Jean-François Moine - * Copyright (C) 2006 Koninski Artur takeshi87@o2.pl - * Copyright (C) 2006 Michel Xhaard - * - * 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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "vc032x" - -#include "gspca.h" - -MODULE_AUTHOR("Jean-François Moine "); -MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver"); -MODULE_LICENSE("GPL"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - u8 brightness; - u8 contrast; - u8 colors; - u8 hflip; - u8 vflip; - u8 lightfreq; - s8 sharpness; - u16 exposure; - u8 gain; - u8 autogain; - u8 backlight; - - u8 image_offset; - - u8 bridge; - u8 sensor; - u8 flags; -#define FL_SAMSUNG 0x01 /* SamsungQ1 (2 sensors) */ -#define FL_HFLIP 0x02 /* mirrored by default */ -#define FL_VFLIP 0x04 /* vertical flipped by default */ -}; -enum bridges { - BRIDGE_VC0321, - BRIDGE_VC0323, -}; -enum sensors { - SENSOR_HV7131R, - SENSOR_MI0360, - SENSOR_MI1310_SOC, - SENSOR_MI1320, - SENSOR_MI1320_SOC, - SENSOR_OV7660, - SENSOR_OV7670, - SENSOR_PO1200, - SENSOR_PO3130NC, - SENSOR_POxxxx, - NSENSORS -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setbacklight(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbacklight(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define BRIGHTNESS_IDX 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 128 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define CONTRAST_IDX 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, -#define CONTRAST_DEF 127 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define COLORS_IDX 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 1, - .maximum = 127, - .step = 1, -#define COLOR_DEF 63 - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -/* next 2 controls work with some sensors only */ -#define HFLIP_IDX 3 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, -#define HFLIP_DEF 0 - .default_value = HFLIP_DEF, - }, - .set = sd_sethflip, - .get = sd_gethflip, - }, -#define VFLIP_IDX 4 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, -#define VFLIP_DEF 0 - .default_value = VFLIP_DEF, - }, - .set = sd_setvflip, - .get = sd_getvflip, - }, -#define LIGHTFREQ_IDX 5 - { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: No, 1: 50Hz, 2:60Hz */ - .step = 1, -#define FREQ_DEF 1 - .default_value = FREQ_DEF, - }, - .set = sd_setfreq, - .get = sd_getfreq, - }, -#define SHARPNESS_IDX 6 - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = -1, - .maximum = 2, - .step = 1, -#define SHARPNESS_DEF -1 - .default_value = SHARPNESS_DEF, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, -#define GAIN_IDX 7 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 78, - .step = 1, -#define GAIN_DEF 0 - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -#define EXPOSURE_IDX 8 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", -#define EXPOSURE_DEF 450 - .minimum = 0, - .maximum = 4095, - .step = 1, - .default_value = EXPOSURE_DEF, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, -#define AUTOGAIN_IDX 9 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain and Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -#define BACKLIGHT_IDX 10 - { - { - .id = V4L2_CID_BACKLIGHT_COMPENSATION, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Backlight Compensation", - .minimum = 0, - .maximum = 15, - .step = 1, -#define BACKLIGHT_DEF 15 - .default_value = BACKLIGHT_DEF, - }, - .set = sd_setbacklight, - .get = sd_getbacklight, - }, -}; - -/* table of the disabled controls */ -static u32 ctrl_dis[NSENSORS] = { - [SENSOR_HV7131R] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX) - | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_MI0360] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX) - | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_MI1310_SOC] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_MI1320] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_MI1320_SOC] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_OV7660] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_OV7670] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_PO1200] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_PO3130NC] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX) - | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_POxxxx] = - (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX), -}; - -static const struct v4l2_pix_format vc0321_mode[] = { - {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; -static const struct v4l2_pix_format vc0323_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, - {1280, 960, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi1310_soc only */ - .bytesperline = 1280, - .sizeimage = 1280 * 960 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 2}, -}; -static const struct v4l2_pix_format bi_mode[] = { - {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 2}, - {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1}, - {1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 1280, - .sizeimage = 1280 * 1024 * 2, - .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0}, -}; -static const struct v4l2_pix_format svga_mode[] = { - {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 800, - .sizeimage = 800 * 600 * 1 / 4 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -/* OV7660/7670 registers */ -#define OV7660_REG_MVFP 0x1e -#define OV7660_MVFP_MIRROR 0x20 -#define OV7660_MVFP_VFLIP 0x10 - -static const u8 mi0360_matrix[9] = { - 0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50 -}; - -static const u8 mi0360_initVGA_JPG[][4] = { - {0xb0, 0x03, 0x19, 0xcc}, - {0xb0, 0x04, 0x02, 0xcc}, - {0xb3, 0x00, 0x24, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x03, 0xcc}, - {0xb3, 0x03, 0x0a, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */ - {0xb3, 0x34, 0x02, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, - {0xbc, 0x00, 0x71, 0xcc}, - {0xb8, 0x00, 0x13, 0xcc}, - {0xb8, 0x27, 0x20, 0xcc}, - {0xb8, 0x2c, 0x50, 0xcc}, - {0xb8, 0x2d, 0xf8, 0xcc}, - {0xb8, 0x2e, 0xf8, 0xcc}, - {0xb8, 0x2f, 0xf8, 0xcc}, - {0xb8, 0x30, 0x50, 0xcc}, - {0xb8, 0x31, 0xf8, 0xcc}, - {0xb8, 0x32, 0xf8, 0xcc}, - {0xb8, 0x33, 0xf8, 0xcc}, - {0xb8, 0x34, 0x50, 0xcc}, - {0xb8, 0x35, 0x00, 0xcc}, - {0xb8, 0x36, 0x00, 0xcc}, - {0xb8, 0x37, 0x00, 0xcc}, - {0xb8, 0x01, 0x79, 0xcc}, - {0xb8, 0x08, 0xe0, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0xb8, 0x01, 0x79, 0xcc}, - {0xb8, 0x14, 0x18, 0xcc}, - {0xb8, 0xb2, 0x0a, 0xcc}, - {0xb8, 0xb4, 0x0a, 0xcc}, - {0xb8, 0xb5, 0x0a, 0xcc}, - {0xb8, 0xfe, 0x00, 0xcc}, - {0xb8, 0xff, 0x28, 0xcc}, - {0xb9, 0x00, 0x28, 0xcc}, - {0xb9, 0x01, 0x28, 0xcc}, - {0xb9, 0x02, 0x28, 0xcc}, - {0xb9, 0x03, 0x00, 0xcc}, - {0xb9, 0x04, 0x00, 0xcc}, - {0xb9, 0x05, 0x3c, 0xcc}, - {0xb9, 0x06, 0x3c, 0xcc}, - {0xb9, 0x07, 0x3c, 0xcc}, - {0xb9, 0x08, 0x3c, 0xcc}, - {0xb8, 0x8e, 0x00, 0xcc}, - {0xb8, 0x8f, 0xff, 0xcc}, - {0xb8, 0x81, 0x09, 0xcc}, - {0x31, 0x00, 0x00, 0xbb}, - {0x09, 0x01, 0xc7, 0xbb}, - {0x34, 0x01, 0x00, 0xbb}, - {0x2b, 0x00, 0x28, 0xbb}, - {0x2c, 0x00, 0x30, 0xbb}, - {0x2d, 0x00, 0x30, 0xbb}, - {0x2e, 0x00, 0x28, 0xbb}, - {0x62, 0x04, 0x11, 0xbb}, - {0x03, 0x01, 0xe0, 0xbb}, - {0x2c, 0x00, 0x2c, 0xbb}, - {0x20, 0xd0, 0x00, 0xbb}, - {0x01, 0x00, 0x08, 0xbb}, - {0x06, 0x00, 0x10, 0xbb}, - {0x05, 0x00, 0x20, 0xbb}, - {0x20, 0x00, 0x00, 0xbb}, - {0xb6, 0x00, 0x00, 0xcc}, - {0xb6, 0x03, 0x02, 0xcc}, - {0xb6, 0x02, 0x80, 0xcc}, - {0xb6, 0x05, 0x01, 0xcc}, - {0xb6, 0x04, 0xe0, 0xcc}, - {0xb6, 0x12, 0x78, 0xcc}, - {0xb6, 0x18, 0x02, 0xcc}, - {0xb6, 0x17, 0x58, 0xcc}, - {0xb6, 0x16, 0x00, 0xcc}, - {0xb6, 0x22, 0x12, 0xcc}, - {0xb6, 0x23, 0x0b, 0xcc}, - {0xb3, 0x02, 0x02, 0xcc}, - {0xbf, 0xc0, 0x39, 0xcc}, - {0xbf, 0xc1, 0x04, 0xcc}, - {0xbf, 0xcc, 0x10, 0xcc}, - {0xb9, 0x12, 0x00, 0xcc}, - {0xb9, 0x13, 0x0a, 0xcc}, - {0xb9, 0x14, 0x0a, 0xcc}, - {0xb9, 0x15, 0x0a, 0xcc}, - {0xb9, 0x16, 0x0a, 0xcc}, - {0xb9, 0x18, 0x00, 0xcc}, - {0xb9, 0x19, 0x0f, 0xcc}, - {0xb9, 0x1a, 0x0f, 0xcc}, - {0xb9, 0x1b, 0x0f, 0xcc}, - {0xb9, 0x1c, 0x0f, 0xcc}, - {0xb8, 0x8e, 0x00, 0xcc}, - {0xb8, 0x8f, 0xff, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, - {0xb8, 0x0c, 0x20, 0xcc}, - {0xb8, 0x0d, 0x70, 0xcc}, - {0xb6, 0x13, 0x13, 0xcc}, - {0x35, 0x00, 0x60, 0xbb}, - {0xb3, 0x5c, 0x01, 0xcc}, - {} -}; -static const u8 mi0360_initQVGA_JPG[][4] = { - {0xb0, 0x03, 0x19, 0xcc}, - {0xb0, 0x04, 0x02, 0xcc}, - {0xb3, 0x00, 0x24, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x03, 0xcc}, - {0xb3, 0x03, 0x0a, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x35, 0xdd, 0xcc}, - {0xb3, 0x34, 0x02, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, - {0xbc, 0x00, 0xd1, 0xcc}, - {0xb8, 0x00, 0x13, 0xcc}, - {0xb8, 0x27, 0x20, 0xcc}, - {0xb8, 0x2c, 0x50, 0xcc}, - {0xb8, 0x2d, 0xf8, 0xcc}, - {0xb8, 0x2e, 0xf8, 0xcc}, - {0xb8, 0x2f, 0xf8, 0xcc}, - {0xb8, 0x30, 0x50, 0xcc}, - {0xb8, 0x31, 0xf8, 0xcc}, - {0xb8, 0x32, 0xf8, 0xcc}, - {0xb8, 0x33, 0xf8, 0xcc}, - {0xb8, 0x34, 0x50, 0xcc}, - {0xb8, 0x35, 0x00, 0xcc}, - {0xb8, 0x36, 0x00, 0xcc}, - {0xb8, 0x37, 0x00, 0xcc}, - {0xb8, 0x01, 0x79, 0xcc}, - {0xb8, 0x08, 0xe0, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0xb8, 0x01, 0x79, 0xcc}, - {0xb8, 0x14, 0x18, 0xcc}, - {0xb8, 0xb2, 0x0a, 0xcc}, - {0xb8, 0xb4, 0x0a, 0xcc}, - {0xb8, 0xb5, 0x0a, 0xcc}, - {0xb8, 0xfe, 0x00, 0xcc}, - {0xb8, 0xff, 0x28, 0xcc}, - {0xb9, 0x00, 0x28, 0xcc}, - {0xb9, 0x01, 0x28, 0xcc}, - {0xb9, 0x02, 0x28, 0xcc}, - {0xb9, 0x03, 0x00, 0xcc}, - {0xb9, 0x04, 0x00, 0xcc}, - {0xb9, 0x05, 0x3c, 0xcc}, - {0xb9, 0x06, 0x3c, 0xcc}, - {0xb9, 0x07, 0x3c, 0xcc}, - {0xb9, 0x08, 0x3c, 0xcc}, - {0xb8, 0x8e, 0x00, 0xcc}, - {0xb8, 0x8f, 0xff, 0xcc}, - {0xb8, 0x81, 0x09, 0xcc}, - {0x31, 0x00, 0x00, 0xbb}, - {0x09, 0x01, 0xc7, 0xbb}, - {0x34, 0x01, 0x00, 0xbb}, - {0x2b, 0x00, 0x28, 0xbb}, - {0x2c, 0x00, 0x30, 0xbb}, - {0x2d, 0x00, 0x30, 0xbb}, - {0x2e, 0x00, 0x28, 0xbb}, - {0x62, 0x04, 0x11, 0xbb}, - {0x03, 0x01, 0xe0, 0xbb}, - {0x2c, 0x00, 0x2c, 0xbb}, - {0x20, 0xd0, 0x00, 0xbb}, - {0x01, 0x00, 0x08, 0xbb}, - {0x06, 0x00, 0x10, 0xbb}, - {0x05, 0x00, 0x20, 0xbb}, - {0x20, 0x00, 0x00, 0xbb}, - {0xb6, 0x00, 0x00, 0xcc}, - {0xb6, 0x03, 0x01, 0xcc}, - {0xb6, 0x02, 0x40, 0xcc}, - {0xb6, 0x05, 0x00, 0xcc}, - {0xb6, 0x04, 0xf0, 0xcc}, - {0xb6, 0x12, 0x78, 0xcc}, - {0xb6, 0x18, 0x00, 0xcc}, - {0xb6, 0x17, 0x96, 0xcc}, - {0xb6, 0x16, 0x00, 0xcc}, - {0xb6, 0x22, 0x12, 0xcc}, - {0xb6, 0x23, 0x0b, 0xcc}, - {0xb3, 0x02, 0x02, 0xcc}, - {0xbf, 0xc0, 0x39, 0xcc}, - {0xbf, 0xc1, 0x04, 0xcc}, - {0xbf, 0xcc, 0x10, 0xcc}, - {0xb9, 0x12, 0x00, 0xcc}, - {0xb9, 0x13, 0x0a, 0xcc}, - {0xb9, 0x14, 0x0a, 0xcc}, - {0xb9, 0x15, 0x0a, 0xcc}, - {0xb9, 0x16, 0x0a, 0xcc}, - {0xb9, 0x18, 0x00, 0xcc}, - {0xb9, 0x19, 0x0f, 0xcc}, - {0xb9, 0x1a, 0x0f, 0xcc}, - {0xb9, 0x1b, 0x0f, 0xcc}, - {0xb9, 0x1c, 0x0f, 0xcc}, - {0xb8, 0x8e, 0x00, 0xcc}, - {0xb8, 0x8f, 0xff, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, - {0xb6, 0x13, 0x13, 0xcc}, - {0xbc, 0x02, 0x18, 0xcc}, - {0xbc, 0x03, 0x50, 0xcc}, - {0xbc, 0x04, 0x18, 0xcc}, - {0xbc, 0x05, 0x00, 0xcc}, - {0xbc, 0x06, 0x00, 0xcc}, - {0xbc, 0x08, 0x30, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, - {0xbc, 0x0a, 0x10, 0xcc}, - {0xb8, 0x0c, 0x20, 0xcc}, - {0xb8, 0x0d, 0x70, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, - {0xbc, 0x0c, 0x00, 0xcc}, - {0x35, 0x00, 0xef, 0xbb}, - {0xb3, 0x5c, 0x01, 0xcc}, - {} -}; - -static const u8 mi1310_socinitVGA_JPG[][4] = { - {0xb0, 0x03, 0x19, 0xcc}, - {0xb0, 0x04, 0x02, 0xcc}, - {0xb3, 0x00, 0x64, 0xcc}, - {0xb3, 0x00, 0x65, 0xcc}, - {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x00, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x34, 0x02, 0xcc}, - {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */ - {0xb3, 0x02, 0x00, 0xcc}, - {0xb3, 0x03, 0x0a, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x03, 0xcc}, - {0xb3, 0x23, 0xc0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x04, 0xcc}, - {0xb3, 0x17, 0xff, 0xcc}, - {0xb3, 0x00, 0x65, 0xcc}, - {0xb8, 0x00, 0x00, 0xcc}, - {0xbc, 0x00, 0xd0, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, - {0xf0, 0x00, 0x02, 0xbb}, - {0xc8, 0x9f, 0x0b, 0xbb}, - {0x5b, 0x00, 0x01, 0xbb}, - {0x2f, 0xde, 0x20, 0xbb}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */ - {0xf0, 0x00, 0x01, 0xbb}, - {0x05, 0x00, 0x07, 0xbb}, - {0x34, 0x00, 0x00, 0xbb}, - {0x35, 0xff, 0x00, 0xbb}, - {0xdc, 0x07, 0x02, 0xbb}, - {0xdd, 0x3c, 0x18, 0xbb}, - {0xde, 0x92, 0x6d, 0xbb}, - {0xdf, 0xcd, 0xb1, 0xbb}, - {0xe0, 0xff, 0xe7, 0xbb}, - {0x06, 0xf0, 0x0d, 0xbb}, - {0x06, 0x70, 0x0e, 0xbb}, - {0x4c, 0x00, 0x01, 0xbb}, - {0x4d, 0x00, 0x01, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x2e, 0x0c, 0x55, 0xbb}, - {0x21, 0xb6, 0x6e, 0xbb}, - {0x36, 0x30, 0x10, 0xbb}, - {0x37, 0x00, 0xc1, 0xbb}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x07, 0x00, 0x84, 0xbb}, - {0x08, 0x02, 0x4a, 0xbb}, - {0x05, 0x01, 0x10, 0xbb}, - {0x06, 0x00, 0x39, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x58, 0x02, 0x67, 0xbb}, - {0x57, 0x02, 0x00, 0xbb}, - {0x5a, 0x02, 0x67, 0xbb}, - {0x59, 0x02, 0x00, 0xbb}, - {0x5c, 0x12, 0x0d, 0xbb}, - {0x5d, 0x16, 0x11, 0xbb}, - {0x39, 0x06, 0x18, 0xbb}, - {0x3a, 0x06, 0x18, 0xbb}, - {0x3b, 0x06, 0x18, 0xbb}, - {0x3c, 0x06, 0x18, 0xbb}, - {0x64, 0x7b, 0x5b, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x36, 0x30, 0x10, 0xbb}, - {0x37, 0x00, 0xc0, 0xbb}, - {0xbc, 0x0e, 0x00, 0xcc}, - {0xbc, 0x0f, 0x05, 0xcc}, - {0xbc, 0x10, 0xc0, 0xcc}, - {0xbc, 0x11, 0x03, 0xcc}, - {0xb6, 0x00, 0x00, 0xcc}, - {0xb6, 0x03, 0x02, 0xcc}, - {0xb6, 0x02, 0x80, 0xcc}, - {0xb6, 0x05, 0x01, 0xcc}, - {0xb6, 0x04, 0xe0, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, - {0xb6, 0x13, 0x25, 0xcc}, - {0xb6, 0x18, 0x02, 0xcc}, - {0xb6, 0x17, 0x58, 0xcc}, - {0xb6, 0x16, 0x00, 0xcc}, - {0xb6, 0x22, 0x12, 0xcc}, - {0xb6, 0x23, 0x0b, 0xcc}, - {0xbf, 0xc0, 0x39, 0xcc}, - {0xbf, 0xc1, 0x04, 0xcc}, - {0xbf, 0xcc, 0x00, 0xcc}, - {0xbc, 0x02, 0x18, 0xcc}, - {0xbc, 0x03, 0x50, 0xcc}, - {0xbc, 0x04, 0x18, 0xcc}, - {0xbc, 0x05, 0x00, 0xcc}, - {0xbc, 0x06, 0x00, 0xcc}, - {0xbc, 0x08, 0x30, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, - {0xbc, 0x0a, 0x10, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, - {0xbc, 0x0c, 0x00, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xf0, 0x00, 0x01, 0xbb}, - {0x80, 0x00, 0x03, 0xbb}, - {0x81, 0xc7, 0x14, 0xbb}, - {0x82, 0xeb, 0xe8, 0xbb}, - {0x83, 0xfe, 0xf4, 0xbb}, - {0x84, 0xcd, 0x10, 0xbb}, - {0x85, 0xf3, 0xee, 0xbb}, - {0x86, 0xff, 0xf1, 0xbb}, - {0x87, 0xcd, 0x10, 0xbb}, - {0x88, 0xf3, 0xee, 0xbb}, - {0x89, 0x01, 0xf1, 0xbb}, - {0x8a, 0xe5, 0x17, 0xbb}, - {0x8b, 0xe8, 0xe2, 0xbb}, - {0x8c, 0xf7, 0xed, 0xbb}, - {0x8d, 0x00, 0xff, 0xbb}, - {0x8e, 0xec, 0x10, 0xbb}, - {0x8f, 0xf0, 0xed, 0xbb}, - {0x90, 0xf9, 0xf2, 0xbb}, - {0x91, 0x00, 0x00, 0xbb}, - {0x92, 0xe9, 0x0d, 0xbb}, - {0x93, 0xf4, 0xf2, 0xbb}, - {0x94, 0xfb, 0xf5, 0xbb}, - {0x95, 0x00, 0xff, 0xbb}, - {0xb6, 0x0f, 0x08, 0xbb}, - {0xb7, 0x3d, 0x16, 0xbb}, - {0xb8, 0x0c, 0x04, 0xbb}, - {0xb9, 0x1c, 0x07, 0xbb}, - {0xba, 0x0a, 0x03, 0xbb}, - {0xbb, 0x1b, 0x09, 0xbb}, - {0xbc, 0x17, 0x0d, 0xbb}, - {0xbd, 0x23, 0x1d, 0xbb}, - {0xbe, 0x00, 0x28, 0xbb}, - {0xbf, 0x11, 0x09, 0xbb}, - {0xc0, 0x16, 0x15, 0xbb}, - {0xc1, 0x00, 0x1b, 0xbb}, - {0xc2, 0x0e, 0x07, 0xbb}, - {0xc3, 0x14, 0x10, 0xbb}, - {0xc4, 0x00, 0x17, 0xbb}, - {0x06, 0x74, 0x8e, 0xbb}, - {0xf0, 0x00, 0x01, 0xbb}, - {0x06, 0xf4, 0x8e, 0xbb}, - {0x00, 0x00, 0x50, 0xdd}, - {0x06, 0x74, 0x8e, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x24, 0x50, 0x20, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x34, 0x0c, 0x50, 0xbb}, - {0xb3, 0x01, 0x41, 0xcc}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x03, 0x03, 0xc0, 0xbb}, - {}, -}; -static const u8 mi1310_socinitQVGA_JPG[][4] = { - {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc}, - {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, - {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc}, - {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc}, - {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc}, - {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, - {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb}, - {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb}, - {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb}, - {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */ - {0xf0, 0x00, 0x01, 0xbb}, - {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb}, - {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb}, - {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb}, - {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb}, - {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb}, - {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb}, - {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb}, - {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb}, - {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb}, - {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb}, - {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb}, - {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb}, - {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb}, - {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb}, - {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb}, - {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc}, - {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc}, - {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc}, - {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc}, - {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc}, - {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc}, - {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc}, - {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc}, - {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb}, - {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb}, - {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb}, - {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb}, - {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb}, - {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb}, - {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb}, - {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb}, - {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb}, - {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb}, - {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb}, - {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb}, - {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb}, - {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb}, - {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb}, - {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb}, - {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb}, - {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb}, - {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb}, - {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb}, - {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb}, - {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb}, - {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb}, - {0x03, 0x03, 0xc0, 0xbb}, - {}, -}; -static const u8 mi1310_soc_InitSXGA_JPG[][4] = { - {0xb0, 0x03, 0x19, 0xcc}, - {0xb0, 0x04, 0x02, 0xcc}, - {0xb3, 0x00, 0x64, 0xcc}, - {0xb3, 0x00, 0x65, 0xcc}, - {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x00, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x34, 0x02, 0xcc}, - {0xb3, 0x35, 0xdd, 0xcc}, - {0xb3, 0x02, 0x00, 0xcc}, - {0xb3, 0x03, 0x0a, 0xcc}, - {0xb3, 0x04, 0x0d, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x03, 0xcc}, - {0xb3, 0x23, 0xc0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x04, 0xcc}, - {0xb3, 0x17, 0xff, 0xcc}, - {0xb3, 0x00, 0x65, 0xcc}, - {0xb8, 0x00, 0x00, 0xcc}, - {0xbc, 0x00, 0x70, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, - {0xf0, 0x00, 0x02, 0xbb}, - {0xc8, 0x9f, 0x0b, 0xbb}, - {0x5b, 0x00, 0x01, 0xbb}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */ - {0xf0, 0x00, 0x01, 0xbb}, - {0x05, 0x00, 0x07, 0xbb}, - {0x34, 0x00, 0x00, 0xbb}, - {0x35, 0xff, 0x00, 0xbb}, - {0xdc, 0x07, 0x02, 0xbb}, - {0xdd, 0x3c, 0x18, 0xbb}, - {0xde, 0x92, 0x6d, 0xbb}, - {0xdf, 0xcd, 0xb1, 0xbb}, - {0xe0, 0xff, 0xe7, 0xbb}, - {0x06, 0xf0, 0x0d, 0xbb}, - {0x06, 0x70, 0x0e, 0xbb}, - {0x4c, 0x00, 0x01, 0xbb}, - {0x4d, 0x00, 0x01, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x2e, 0x0c, 0x60, 0xbb}, - {0x21, 0xb6, 0x6e, 0xbb}, - {0x37, 0x01, 0x40, 0xbb}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x07, 0x00, 0x84, 0xbb}, - {0x08, 0x02, 0x4a, 0xbb}, - {0x05, 0x01, 0x10, 0xbb}, - {0x06, 0x00, 0x39, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x58, 0x02, 0x67, 0xbb}, - {0x57, 0x02, 0x00, 0xbb}, - {0x5a, 0x02, 0x67, 0xbb}, - {0x59, 0x02, 0x00, 0xbb}, - {0x5c, 0x12, 0x0d, 0xbb}, - {0x5d, 0x16, 0x11, 0xbb}, - {0x39, 0x06, 0x18, 0xbb}, - {0x3a, 0x06, 0x18, 0xbb}, - {0x3b, 0x06, 0x18, 0xbb}, - {0x3c, 0x06, 0x18, 0xbb}, - {0x64, 0x7b, 0x5b, 0xbb}, - {0xb6, 0x00, 0x00, 0xcc}, - {0xb6, 0x03, 0x05, 0xcc}, - {0xb6, 0x02, 0x00, 0xcc}, - {0xb6, 0x05, 0x03, 0xcc}, - {0xb6, 0x04, 0xc0, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, - {0xb6, 0x13, 0x29, 0xcc}, - {0xb6, 0x18, 0x09, 0xcc}, - {0xb6, 0x17, 0x60, 0xcc}, - {0xb6, 0x16, 0x00, 0xcc}, - {0xb6, 0x22, 0x12, 0xcc}, - {0xb6, 0x23, 0x0b, 0xcc}, - {0xbf, 0xc0, 0x39, 0xcc}, - {0xbf, 0xc1, 0x04, 0xcc}, - {0xbf, 0xcc, 0x00, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0x00, 0x00, 0x80, 0xdd}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x00, 0x00, 0x10, 0xdd}, - {0x22, 0xa0, 0x78, 0xbb}, - {0x23, 0xa0, 0x78, 0xbb}, - {0x24, 0x7f, 0x00, 0xbb}, - {0x28, 0xea, 0x02, 0xbb}, - {0x29, 0x86, 0x7a, 0xbb}, - {0x5e, 0x52, 0x4c, 0xbb}, - {0x5f, 0x20, 0x24, 0xbb}, - {0x60, 0x00, 0x02, 0xbb}, - {0x02, 0x00, 0xee, 0xbb}, - {0x03, 0x39, 0x23, 0xbb}, - {0x04, 0x07, 0x24, 0xbb}, - {0x09, 0x00, 0xc0, 0xbb}, - {0x0a, 0x00, 0x79, 0xbb}, - {0x0b, 0x00, 0x04, 0xbb}, - {0x0c, 0x00, 0x5c, 0xbb}, - {0x0d, 0x00, 0xd9, 0xbb}, - {0x0e, 0x00, 0x53, 0xbb}, - {0x0f, 0x00, 0x21, 0xbb}, - {0x10, 0x00, 0xa4, 0xbb}, - {0x11, 0x00, 0xe5, 0xbb}, - {0x15, 0x00, 0x00, 0xbb}, - {0x16, 0x00, 0x00, 0xbb}, - {0x17, 0x00, 0x00, 0xbb}, - {0x18, 0x00, 0x00, 0xbb}, - {0x19, 0x00, 0x00, 0xbb}, - {0x1a, 0x00, 0x00, 0xbb}, - {0x1b, 0x00, 0x00, 0xbb}, - {0x1c, 0x00, 0x00, 0xbb}, - {0x1d, 0x00, 0x00, 0xbb}, - {0x1e, 0x00, 0x00, 0xbb}, - {0xf0, 0x00, 0x01, 0xbb}, - {0x00, 0x00, 0x20, 0xdd}, - {0x06, 0xf0, 0x8e, 0xbb}, - {0x00, 0x00, 0x80, 0xdd}, - {0x06, 0x70, 0x8e, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x00, 0x00, 0x20, 0xdd}, - {0x5e, 0x6a, 0x53, 0xbb}, - {0x5f, 0x40, 0x2c, 0xbb}, - {0xf0, 0x00, 0x01, 0xbb}, - {0x00, 0x00, 0x20, 0xdd}, - {0x58, 0x00, 0x00, 0xbb}, - {0x53, 0x09, 0x03, 0xbb}, - {0x54, 0x31, 0x18, 0xbb}, - {0x55, 0x8b, 0x5f, 0xbb}, - {0x56, 0xc0, 0xa9, 0xbb}, - {0x57, 0xe0, 0xd2, 0xbb}, - {0xe1, 0x00, 0x00, 0xbb}, - {0xdc, 0x09, 0x03, 0xbb}, - {0xdd, 0x31, 0x18, 0xbb}, - {0xde, 0x8b, 0x5f, 0xbb}, - {0xdf, 0xc0, 0xa9, 0xbb}, - {0xe0, 0xe0, 0xd2, 0xbb}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xf0, 0x00, 0x01, 0xbb}, - {0x06, 0xf0, 0x8e, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x2f, 0xde, 0x20, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x24, 0x50, 0x20, 0xbb}, - {0xbc, 0x0e, 0x00, 0xcc}, - {0xbc, 0x0f, 0x05, 0xcc}, - {0xbc, 0x10, 0xc0, 0xcc}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x34, 0x0c, 0x50, 0xbb}, - {0xbc, 0x11, 0x03, 0xcc}, - {0xf0, 0x00, 0x01, 0xbb}, - {0x80, 0x00, 0x03, 0xbb}, - {0x81, 0xc7, 0x14, 0xbb}, - {0x82, 0xeb, 0xe8, 0xbb}, - {0x83, 0xfe, 0xf4, 0xbb}, - {0x84, 0xcd, 0x10, 0xbb}, - {0x85, 0xf3, 0xee, 0xbb}, - {0x86, 0xff, 0xf1, 0xbb}, - {0x87, 0xcd, 0x10, 0xbb}, - {0x88, 0xf3, 0xee, 0xbb}, - {0x89, 0x01, 0xf1, 0xbb}, - {0x8a, 0xe5, 0x17, 0xbb}, - {0x8b, 0xe8, 0xe2, 0xbb}, - {0x8c, 0xf7, 0xed, 0xbb}, - {0x8d, 0x00, 0xff, 0xbb}, - {0x8e, 0xec, 0x10, 0xbb}, - {0x8f, 0xf0, 0xed, 0xbb}, - {0x90, 0xf9, 0xf2, 0xbb}, - {0x91, 0x00, 0x00, 0xbb}, - {0x92, 0xe9, 0x0d, 0xbb}, - {0x93, 0xf4, 0xf2, 0xbb}, - {0x94, 0xfb, 0xf5, 0xbb}, - {0x95, 0x00, 0xff, 0xbb}, - {0xb6, 0x0f, 0x08, 0xbb}, - {0xb7, 0x3d, 0x16, 0xbb}, - {0xb8, 0x0c, 0x04, 0xbb}, - {0xb9, 0x1c, 0x07, 0xbb}, - {0xba, 0x0a, 0x03, 0xbb}, - {0xbb, 0x1b, 0x09, 0xbb}, - {0xbc, 0x17, 0x0d, 0xbb}, - {0xbd, 0x23, 0x1d, 0xbb}, - {0xbe, 0x00, 0x28, 0xbb}, - {0xbf, 0x11, 0x09, 0xbb}, - {0xc0, 0x16, 0x15, 0xbb}, - {0xc1, 0x00, 0x1b, 0xbb}, - {0xc2, 0x0e, 0x07, 0xbb}, - {0xc3, 0x14, 0x10, 0xbb}, - {0xc4, 0x00, 0x17, 0xbb}, - {0x06, 0x74, 0x8e, 0xbb}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x03, 0x03, 0xc0, 0xbb}, - {} -}; - -static const u8 mi1320_gamma[17] = { - 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, - 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff -}; -static const u8 mi1320_matrix[9] = { - 0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52 -}; -static const u8 mi1320_initVGA_data[][4] = { - {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, - {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, - {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, - {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, - {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x00, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc}, - {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */ - {0xb3, 0x02, 0x00, 0xcc}, - {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x03, 0xcc}, {0xb3, 0x23, 0xc0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x04, 0xcc}, {0xb3, 0x17, 0xff, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, {0xbc, 0x00, 0xd0, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x00, 0xbb}, - {0x0d, 0x00, 0x09, 0xbb}, {0x00, 0x01, 0x00, 0xdd}, - {0x0d, 0x00, 0x08, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, - {0xa1, 0x05, 0x00, 0xbb}, {0xa4, 0x03, 0xc0, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, - {0xc8, 0x9f, 0x0b, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, - {0xf0, 0x00, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, - {0x20, 0x01, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, - {0xf0, 0x00, 0x01, 0xbb}, {0x9d, 0x3c, 0xa0, 0xbb}, - {0x47, 0x30, 0x30, 0xbb}, {0xf0, 0x00, 0x00, 0xbb}, - {0x0a, 0x80, 0x11, 0xbb}, {0x35, 0x00, 0x22, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x9d, 0xc5, 0x05, 0xbb}, - {0xdc, 0x0f, 0xfc, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, - {0x06, 0x74, 0x0e, 0xbb}, {0x80, 0x00, 0x06, 0xbb}, - {0x81, 0x04, 0x00, 0xbb}, {0x82, 0x01, 0x02, 0xbb}, - {0x83, 0x03, 0x02, 0xbb}, {0x84, 0x05, 0x00, 0xbb}, - {0x85, 0x01, 0x00, 0xbb}, {0x86, 0x03, 0x02, 0xbb}, - {0x87, 0x05, 0x00, 0xbb}, {0x88, 0x01, 0x00, 0xbb}, - {0x89, 0x02, 0x02, 0xbb}, {0x8a, 0xfd, 0x04, 0xbb}, - {0x8b, 0xfc, 0xfd, 0xbb}, {0x8c, 0xff, 0xfd, 0xbb}, - {0x8d, 0x00, 0x00, 0xbb}, {0x8e, 0xfe, 0x05, 0xbb}, - {0x8f, 0xfc, 0xfd, 0xbb}, {0x90, 0xfe, 0xfd, 0xbb}, - {0x91, 0x00, 0x00, 0xbb}, {0x92, 0xfe, 0x03, 0xbb}, - {0x93, 0xfd, 0xfe, 0xbb}, {0x94, 0xff, 0xfd, 0xbb}, - {0x95, 0x00, 0x00, 0xbb}, {0xb6, 0x07, 0x05, 0xbb}, - {0xb7, 0x13, 0x06, 0xbb}, {0xb8, 0x08, 0x06, 0xbb}, - {0xb9, 0x14, 0x08, 0xbb}, {0xba, 0x06, 0x05, 0xbb}, - {0xbb, 0x13, 0x06, 0xbb}, {0xbc, 0x03, 0x01, 0xbb}, - {0xbd, 0x03, 0x04, 0xbb}, {0xbe, 0x00, 0x02, 0xbb}, - {0xbf, 0x03, 0x01, 0xbb}, {0xc0, 0x02, 0x04, 0xbb}, - {0xc1, 0x00, 0x04, 0xbb}, {0xc2, 0x02, 0x01, 0xbb}, - {0xc3, 0x01, 0x03, 0xbb}, {0xc4, 0x00, 0x04, 0xbb}, - {0xf0, 0x00, 0x00, 0xbb}, {0x05, 0x01, 0x13, 0xbb}, - {0x06, 0x00, 0x11, 0xbb}, {0x07, 0x00, 0x85, 0xbb}, - {0x08, 0x00, 0x27, 0xbb}, - {0x20, 0x01, 0x00, 0xbb}, /* h/v flips - was 03 */ - {0x21, 0x80, 0x00, 0xbb}, {0x22, 0x0d, 0x0f, 0xbb}, - {0x24, 0x80, 0x00, 0xbb}, {0x59, 0x00, 0xff, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x39, 0x03, 0x0d, 0xbb}, - {0x3a, 0x06, 0x1b, 0xbb}, {0x3b, 0x00, 0x95, 0xbb}, - {0x3c, 0x04, 0xdb, 0xbb}, {0x57, 0x02, 0x00, 0xbb}, - {0x58, 0x02, 0x66, 0xbb}, {0x59, 0x00, 0xff, 0xbb}, - {0x5a, 0x01, 0x33, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb}, - {0x5d, 0x16, 0x11, 0xbb}, {0x64, 0x5e, 0x1c, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb}, - {0x5b, 0x00, 0x01, 0xbb}, {0xf0, 0x00, 0x02, 0xbb}, - {0x36, 0x68, 0x10, 0xbb}, {0x00, 0x00, 0x30, 0xdd}, - {0x37, 0x82, 0x00, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc}, - {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc}, - {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc}, - {0xb6, 0x03, 0x05, 0xcc}, {0xb6, 0x02, 0x00, 0xcc}, - {0xb6, 0x05, 0x04, 0xcc}, {0xb6, 0x04, 0x00, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x29, 0xcc}, - {0xb6, 0x18, 0x0a, 0xcc}, {0xb6, 0x17, 0x00, 0xcc}, - {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc}, - {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x26, 0xcc}, - {0xbf, 0xc1, 0x02, 0xcc}, {0xbf, 0xcc, 0x04, 0xcc}, - {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc}, - {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc}, - {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x41, 0xcc}, - {} -}; -static const u8 mi1320_initQVGA_data[][4] = { - {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, - {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, - {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, - {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, - {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc}, - {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc}, - {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x00, 0x65, 0xcc}, {0xb8, 0x00, 0x00, 0xcc}, - {0xbc, 0x00, 0xd0, 0xcc}, {0xbc, 0x01, 0x01, 0xcc}, - {0xf0, 0x00, 0x00, 0xbb}, {0x0d, 0x00, 0x09, 0xbb}, - {0x00, 0x01, 0x00, 0xdd}, {0x0d, 0x00, 0x08, 0xbb}, - {0xf0, 0x00, 0x00, 0xbb}, {0x02, 0x00, 0x64, 0xbb}, - {0x05, 0x01, 0x78, 0xbb}, {0x06, 0x00, 0x11, 0xbb}, - {0x07, 0x01, 0x42, 0xbb}, {0x08, 0x00, 0x11, 0xbb}, - {0x20, 0x01, 0x00, 0xbb}, {0x21, 0x80, 0x00, 0xbb}, - {0x22, 0x0d, 0x0f, 0xbb}, {0x24, 0x80, 0x00, 0xbb}, - {0x59, 0x00, 0xff, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, - {0x9d, 0x3c, 0xa0, 0xbb}, {0x47, 0x30, 0x30, 0xbb}, - {0xf0, 0x00, 0x00, 0xbb}, {0x0a, 0x80, 0x11, 0xbb}, - {0x35, 0x00, 0x22, 0xbb}, {0xf0, 0x00, 0x02, 0xbb}, - {0x9d, 0xc5, 0x05, 0xbb}, {0xdc, 0x0f, 0xfc, 0xbb}, - {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0x74, 0x0e, 0xbb}, - {0x80, 0x00, 0x06, 0xbb}, {0x81, 0x04, 0x00, 0xbb}, - {0x82, 0x01, 0x02, 0xbb}, {0x83, 0x03, 0x02, 0xbb}, - {0x84, 0x05, 0x00, 0xbb}, {0x85, 0x01, 0x00, 0xbb}, - {0x86, 0x03, 0x02, 0xbb}, {0x87, 0x05, 0x00, 0xbb}, - {0x88, 0x01, 0x00, 0xbb}, {0x89, 0x02, 0x02, 0xbb}, - {0x8a, 0xfd, 0x04, 0xbb}, {0x8b, 0xfc, 0xfd, 0xbb}, - {0x8c, 0xff, 0xfd, 0xbb}, {0x8d, 0x00, 0x00, 0xbb}, - {0x8e, 0xfe, 0x05, 0xbb}, {0x8f, 0xfc, 0xfd, 0xbb}, - {0x90, 0xfe, 0xfd, 0xbb}, {0x91, 0x00, 0x00, 0xbb}, - {0x92, 0xfe, 0x03, 0xbb}, {0x93, 0xfd, 0xfe, 0xbb}, - {0x94, 0xff, 0xfd, 0xbb}, {0x95, 0x00, 0x00, 0xbb}, - {0xb6, 0x07, 0x05, 0xbb}, {0xb7, 0x13, 0x06, 0xbb}, - {0xb8, 0x08, 0x06, 0xbb}, {0xb9, 0x14, 0x08, 0xbb}, - {0xba, 0x06, 0x05, 0xbb}, {0xbb, 0x13, 0x06, 0xbb}, - {0xbc, 0x03, 0x01, 0xbb}, {0xbd, 0x03, 0x04, 0xbb}, - {0xbe, 0x00, 0x02, 0xbb}, {0xbf, 0x03, 0x01, 0xbb}, - {0xc0, 0x02, 0x04, 0xbb}, {0xc1, 0x00, 0x04, 0xbb}, - {0xc2, 0x02, 0x01, 0xbb}, {0xc3, 0x01, 0x03, 0xbb}, - {0xc4, 0x00, 0x04, 0xbb}, {0xf0, 0x00, 0x02, 0xbb}, - {0xc8, 0x00, 0x00, 0xbb}, {0x2e, 0x00, 0x00, 0xbb}, - {0x2e, 0x0c, 0x5b, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb}, - {0x39, 0x03, 0xca, 0xbb}, {0x3a, 0x06, 0x80, 0xbb}, - {0x3b, 0x01, 0x52, 0xbb}, {0x3c, 0x05, 0x40, 0xbb}, - {0x57, 0x01, 0x9c, 0xbb}, {0x58, 0x01, 0xee, 0xbb}, - {0x59, 0x00, 0xf0, 0xbb}, {0x5a, 0x01, 0x20, 0xbb}, - {0x5c, 0x1d, 0x17, 0xbb}, {0x5d, 0x22, 0x1c, 0xbb}, - {0x64, 0x1e, 0x1c, 0xbb}, {0x5b, 0x00, 0x01, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x68, 0x10, 0xbb}, - {0x00, 0x00, 0x30, 0xdd}, {0x37, 0x81, 0x00, 0xbb}, - {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc}, - {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc}, - {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, - {0xbf, 0xc0, 0x26, 0xcc}, {0xbf, 0xc1, 0x02, 0xcc}, - {0xbf, 0xcc, 0x04, 0xcc}, {0xb3, 0x5c, 0x01, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {} -}; - -static const u8 mi1320_soc_InitVGA[][4] = { - {0xb3, 0x01, 0x01, 0xcc}, - {0xb0, 0x03, 0x19, 0xcc}, - {0xb0, 0x04, 0x02, 0xcc}, - {0x00, 0x00, 0x30, 0xdd}, - {0xb3, 0x00, 0x64, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x34, 0x02, 0xcc}, - {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */ - {0xb3, 0x02, 0x00, 0xcc}, - {0xb3, 0x03, 0x0a, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb8, 0x00, 0x00, 0xcc}, - {0xbc, 0x00, 0x71, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x00, 0x00, 0x10, 0xdd}, - {0xc8, 0x00, 0x00, 0xbb}, - {0x00, 0x00, 0x30, 0xdd}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x00, 0x00, 0x10, 0xdd}, - {0x07, 0x00, 0xe0, 0xbb}, - {0x08, 0x00, 0x0b, 0xbb}, - {0x21, 0x00, 0x0c, 0xbb}, - {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ - {0xbf, 0xc0, 0x26, 0xcc}, - {0xbf, 0xc1, 0x02, 0xcc}, - {0xbf, 0xcc, 0x04, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x05, 0x01, 0x78, 0xbb}, - {0x06, 0x00, 0x11, 0xbb}, - {0x07, 0x01, 0x42, 0xbb}, - {0x08, 0x00, 0x11, 0xbb}, - {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ - {0x21, 0x80, 0x00, 0xbb}, - {0x22, 0x0d, 0x0f, 0xbb}, - {0x24, 0x80, 0x00, 0xbb}, - {0x59, 0x00, 0xff, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x39, 0x03, 0xca, 0xbb}, - {0x3a, 0x06, 0x80, 0xbb}, - {0x3b, 0x01, 0x52, 0xbb}, - {0x3c, 0x05, 0x40, 0xbb}, - {0x57, 0x01, 0x9c, 0xbb}, - {0x58, 0x01, 0xee, 0xbb}, - {0x59, 0x00, 0xf0, 0xbb}, - {0x5a, 0x01, 0x20, 0xbb}, - {0x5c, 0x1d, 0x17, 0xbb}, - {0x5d, 0x22, 0x1c, 0xbb}, - {0x64, 0x1e, 0x1c, 0xbb}, - {0x5b, 0x00, 0x00, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x22, 0xa0, 0x78, 0xbb}, - {0x23, 0xa0, 0x78, 0xbb}, - {0x24, 0x7f, 0x00, 0xbb}, - {0x28, 0xea, 0x02, 0xbb}, - {0x29, 0x86, 0x7a, 0xbb}, - {0x5e, 0x52, 0x4c, 0xbb}, - {0x5f, 0x20, 0x24, 0xbb}, - {0x60, 0x00, 0x02, 0xbb}, - {0x02, 0x00, 0xee, 0xbb}, - {0x03, 0x39, 0x23, 0xbb}, - {0x04, 0x07, 0x24, 0xbb}, - {0x09, 0x00, 0xc0, 0xbb}, - {0x0a, 0x00, 0x79, 0xbb}, - {0x0b, 0x00, 0x04, 0xbb}, - {0x0c, 0x00, 0x5c, 0xbb}, - {0x0d, 0x00, 0xd9, 0xbb}, - {0x0e, 0x00, 0x53, 0xbb}, - {0x0f, 0x00, 0x21, 0xbb}, - {0x10, 0x00, 0xa4, 0xbb}, - {0x11, 0x00, 0xe5, 0xbb}, - {0x15, 0x00, 0x00, 0xbb}, - {0x16, 0x00, 0x00, 0xbb}, - {0x17, 0x00, 0x00, 0xbb}, - {0x18, 0x00, 0x00, 0xbb}, - {0x19, 0x00, 0x00, 0xbb}, - {0x1a, 0x00, 0x00, 0xbb}, - {0x1b, 0x00, 0x00, 0xbb}, - {0x1c, 0x00, 0x00, 0xbb}, - {0x1d, 0x00, 0x00, 0xbb}, - {0x1e, 0x00, 0x00, 0xbb}, - {0xf0, 0x00, 0x01, 0xbb}, - {0x06, 0xe0, 0x0e, 0xbb}, - {0x06, 0x60, 0x0e, 0xbb}, - {0xb3, 0x5c, 0x01, 0xcc}, - {} -}; -static const u8 mi1320_soc_InitQVGA[][4] = { - {0xb3, 0x01, 0x01, 0xcc}, - {0xb0, 0x03, 0x19, 0xcc}, - {0xb0, 0x04, 0x02, 0xcc}, - {0x00, 0x00, 0x30, 0xdd}, - {0xb3, 0x00, 0x64, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x34, 0x02, 0xcc}, - {0xb3, 0x35, 0xc8, 0xcc}, - {0xb3, 0x02, 0x00, 0xcc}, - {0xb3, 0x03, 0x0a, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb8, 0x00, 0x00, 0xcc}, - {0xbc, 0x00, 0xd1, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x00, 0x00, 0x10, 0xdd}, - {0xc8, 0x00, 0x00, 0xbb}, - {0x00, 0x00, 0x30, 0xdd}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x00, 0x00, 0x10, 0xdd}, - {0x07, 0x00, 0xe0, 0xbb}, - {0x08, 0x00, 0x0b, 0xbb}, - {0x21, 0x00, 0x0c, 0xbb}, - {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ - {0xbf, 0xc0, 0x26, 0xcc}, - {0xbf, 0xc1, 0x02, 0xcc}, - {0xbf, 0xcc, 0x04, 0xcc}, - {0xbc, 0x02, 0x18, 0xcc}, - {0xbc, 0x03, 0x50, 0xcc}, - {0xbc, 0x04, 0x18, 0xcc}, - {0xbc, 0x05, 0x00, 0xcc}, - {0xbc, 0x06, 0x00, 0xcc}, - {0xbc, 0x08, 0x30, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, - {0xbc, 0x0a, 0x10, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, - {0xbc, 0x0c, 0x00, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x05, 0x01, 0x78, 0xbb}, - {0x06, 0x00, 0x11, 0xbb}, - {0x07, 0x01, 0x42, 0xbb}, - {0x08, 0x00, 0x11, 0xbb}, - {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ - {0x21, 0x80, 0x00, 0xbb}, - {0x22, 0x0d, 0x0f, 0xbb}, - {0x24, 0x80, 0x00, 0xbb}, - {0x59, 0x00, 0xff, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x39, 0x03, 0xca, 0xbb}, - {0x3a, 0x06, 0x80, 0xbb}, - {0x3b, 0x01, 0x52, 0xbb}, - {0x3c, 0x05, 0x40, 0xbb}, - {0x57, 0x01, 0x9c, 0xbb}, - {0x58, 0x01, 0xee, 0xbb}, - {0x59, 0x00, 0xf0, 0xbb}, - {0x5a, 0x01, 0x20, 0xbb}, - {0x5c, 0x1d, 0x17, 0xbb}, - {0x5d, 0x22, 0x1c, 0xbb}, - {0x64, 0x1e, 0x1c, 0xbb}, - {0x5b, 0x00, 0x00, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x22, 0xa0, 0x78, 0xbb}, - {0x23, 0xa0, 0x78, 0xbb}, - {0x24, 0x7f, 0x00, 0xbb}, - {0x28, 0xea, 0x02, 0xbb}, - {0x29, 0x86, 0x7a, 0xbb}, - {0x5e, 0x52, 0x4c, 0xbb}, - {0x5f, 0x20, 0x24, 0xbb}, - {0x60, 0x00, 0x02, 0xbb}, - {0x02, 0x00, 0xee, 0xbb}, - {0x03, 0x39, 0x23, 0xbb}, - {0x04, 0x07, 0x24, 0xbb}, - {0x09, 0x00, 0xc0, 0xbb}, - {0x0a, 0x00, 0x79, 0xbb}, - {0x0b, 0x00, 0x04, 0xbb}, - {0x0c, 0x00, 0x5c, 0xbb}, - {0x0d, 0x00, 0xd9, 0xbb}, - {0x0e, 0x00, 0x53, 0xbb}, - {0x0f, 0x00, 0x21, 0xbb}, - {0x10, 0x00, 0xa4, 0xbb}, - {0x11, 0x00, 0xe5, 0xbb}, - {0x15, 0x00, 0x00, 0xbb}, - {0x16, 0x00, 0x00, 0xbb}, - {0x17, 0x00, 0x00, 0xbb}, - {0x18, 0x00, 0x00, 0xbb}, - {0x19, 0x00, 0x00, 0xbb}, - {0x1a, 0x00, 0x00, 0xbb}, - {0x1b, 0x00, 0x00, 0xbb}, - {0x1c, 0x00, 0x00, 0xbb}, - {0x1d, 0x00, 0x00, 0xbb}, - {0x1e, 0x00, 0x00, 0xbb}, - {0xf0, 0x00, 0x01, 0xbb}, - {0x06, 0xe0, 0x0e, 0xbb}, - {0x06, 0x60, 0x0e, 0xbb}, - {0xb3, 0x5c, 0x01, 0xcc}, - {} -}; -static const u8 mi1320_soc_InitSXGA[][4] = { - {0xb3, 0x01, 0x01, 0xcc}, - {0xb0, 0x03, 0x19, 0xcc}, - {0x00, 0x00, 0x30, 0xdd}, - {0xb3, 0x00, 0x64, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x34, 0x02, 0xcc}, - {0xb3, 0x35, 0xc8, 0xcc}, - {0xb3, 0x02, 0x00, 0xcc}, - {0xb3, 0x03, 0x0a, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x04, 0xcc}, - {0xb3, 0x23, 0x00, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x04, 0xcc}, - {0xb3, 0x17, 0xff, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xbc, 0x00, 0x71, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x00, 0x00, 0x30, 0xdd}, - {0xc8, 0x9f, 0x0b, 0xbb}, - {0x00, 0x00, 0x20, 0xdd}, - {0x5b, 0x00, 0x01, 0xbb}, - {0x00, 0x00, 0x20, 0xdd}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x00, 0x00, 0x30, 0xdd}, - {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ - {0x00, 0x00, 0x20, 0xdd}, - {0xbf, 0xc0, 0x26, 0xcc}, - {0xbf, 0xc1, 0x02, 0xcc}, - {0xbf, 0xcc, 0x04, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x05, 0x01, 0x78, 0xbb}, - {0x06, 0x00, 0x11, 0xbb}, - {0x07, 0x01, 0x42, 0xbb}, - {0x08, 0x00, 0x11, 0xbb}, - {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ - {0x21, 0x80, 0x00, 0xbb}, - {0x22, 0x0d, 0x0f, 0xbb}, - {0x24, 0x80, 0x00, 0xbb}, - {0x59, 0x00, 0xff, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x39, 0x03, 0xca, 0xbb}, - {0x3a, 0x06, 0x80, 0xbb}, - {0x3b, 0x01, 0x52, 0xbb}, - {0x3c, 0x05, 0x40, 0xbb}, - {0x57, 0x01, 0x9c, 0xbb}, - {0x58, 0x01, 0xee, 0xbb}, - {0x59, 0x00, 0xf0, 0xbb}, - {0x5a, 0x01, 0x20, 0xbb}, - {0x5c, 0x1d, 0x17, 0xbb}, - {0x5d, 0x22, 0x1c, 0xbb}, - {0x64, 0x1e, 0x1c, 0xbb}, - {0x5b, 0x00, 0x00, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x22, 0xa0, 0x78, 0xbb}, - {0x23, 0xa0, 0x78, 0xbb}, - {0x24, 0x7f, 0x00, 0xbb}, - {0x28, 0xea, 0x02, 0xbb}, - {0x29, 0x86, 0x7a, 0xbb}, - {0x5e, 0x52, 0x4c, 0xbb}, - {0x5f, 0x20, 0x24, 0xbb}, - {0x60, 0x00, 0x02, 0xbb}, - {0x02, 0x00, 0xee, 0xbb}, - {0x03, 0x39, 0x23, 0xbb}, - {0x04, 0x07, 0x24, 0xbb}, - {0x09, 0x00, 0xc0, 0xbb}, - {0x0a, 0x00, 0x79, 0xbb}, - {0x0b, 0x00, 0x04, 0xbb}, - {0x0c, 0x00, 0x5c, 0xbb}, - {0x0d, 0x00, 0xd9, 0xbb}, - {0x0e, 0x00, 0x53, 0xbb}, - {0x0f, 0x00, 0x21, 0xbb}, - {0x10, 0x00, 0xa4, 0xbb}, - {0x11, 0x00, 0xe5, 0xbb}, - {0x15, 0x00, 0x00, 0xbb}, - {0x16, 0x00, 0x00, 0xbb}, - {0x17, 0x00, 0x00, 0xbb}, - {0x18, 0x00, 0x00, 0xbb}, - {0x19, 0x00, 0x00, 0xbb}, - {0x1a, 0x00, 0x00, 0xbb}, - {0x1b, 0x00, 0x00, 0xbb}, - {0x1c, 0x00, 0x00, 0xbb}, - {0x1d, 0x00, 0x00, 0xbb}, - {0x1e, 0x00, 0x00, 0xbb}, - {0xf0, 0x00, 0x01, 0xbb}, - {0x06, 0xe0, 0x0e, 0xbb}, - {0x06, 0x60, 0x0e, 0xbb}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xf0, 0x00, 0x00, 0xbb}, - {0x05, 0x01, 0x13, 0xbb}, - {0x06, 0x00, 0x11, 0xbb}, - {0x07, 0x00, 0x85, 0xbb}, - {0x08, 0x00, 0x27, 0xbb}, - {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ - {0x21, 0x80, 0x00, 0xbb}, - {0x22, 0x0d, 0x0f, 0xbb}, - {0x24, 0x80, 0x00, 0xbb}, - {0x59, 0x00, 0xff, 0xbb}, - {0xf0, 0x00, 0x02, 0xbb}, - {0x39, 0x03, 0x0d, 0xbb}, - {0x3a, 0x06, 0x1b, 0xbb}, - {0x3b, 0x00, 0x95, 0xbb}, - {0x3c, 0x04, 0xdb, 0xbb}, - {0x57, 0x02, 0x00, 0xbb}, - {0x58, 0x02, 0x66, 0xbb}, - {0x59, 0x00, 0xff, 0xbb}, - {0x5a, 0x01, 0x33, 0xbb}, - {0x5c, 0x12, 0x0d, 0xbb}, - {0x5d, 0x16, 0x11, 0xbb}, - {0x64, 0x5e, 0x1c, 0xbb}, - {} -}; -static const u8 po3130_gamma[17] = { - 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, - 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff -}; -static const u8 po3130_matrix[9] = { - 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63 -}; - -static const u8 po3130_initVGA_data[][4] = { - {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, - {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc}, - {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe8, 0xcc}, {0xb8, 0x08, 0xe8, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */ - {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0x71, 0xcc}, - {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc}, - {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, - {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, - {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, - {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc}, - {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc}, - {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc}, - {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, - {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa}, - {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa}, - {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa}, - {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa}, - {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa}, - {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa}, - {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa}, - {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa}, - {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x5a, 0x04, 0xaa}, - {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa}, - {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa}, - {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa}, - {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa}, - {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa}, - {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa}, - {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa}, - {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa}, - {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa}, - {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa}, - {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa}, - {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa}, - {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa}, - {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa}, - {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa}, - {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa}, - {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, - {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, - {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, - {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, - {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, - {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, - {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa}, - {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa}, - {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa}, - {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa}, - {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa}, - {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa}, - {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa}, - {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, - {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, - {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, - {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, - {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, - {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, - {0x00, 0x7e, 0xea, 0xaa}, - {0x00, 0x4c, 0x07, 0xaa}, - {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa}, - {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa}, -/* {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa}, - {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, */ - {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0x20, 0xc4, 0xaa}, - {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, - {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc}, - {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, - {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, - {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, - {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc}, - {0xb9, 0x08, 0x3c, 0xcc}, {0x00, 0x05, 0x00, 0xaa}, - {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc}, - {} -}; -static const u8 po3130_rundata[][4] = { - {0x00, 0x47, 0x45, 0xaa}, {0x00, 0x48, 0x9b, 0xaa}, - {0x00, 0x49, 0x3a, 0xaa}, {0x00, 0x4a, 0x01, 0xaa}, - {0x00, 0x44, 0x40, 0xaa}, -/* {0x00, 0xd5, 0x7c, 0xaa}, */ - {0x00, 0xad, 0x04, 0xaa}, {0x00, 0xae, 0x00, 0xaa}, - {0x00, 0xb0, 0x78, 0xaa}, {0x00, 0x98, 0x02, 0xaa}, - {0x00, 0x94, 0x25, 0xaa}, {0x00, 0x95, 0x25, 0xaa}, - {0x00, 0x59, 0x68, 0xaa}, {0x00, 0x44, 0x20, 0xaa}, - {0x00, 0x17, 0x50, 0xaa}, {0x00, 0x19, 0x50, 0xaa}, - {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0xd1, 0x3c, 0xaa}, - {0x00, 0x1e, 0x06, 0xaa}, {0x00, 0x1e, 0x06, 0xaa}, - {} -}; - -static const u8 po3130_initQVGA_data[][4] = { - {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x09, 0xcc}, - {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc}, - {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, {0xb8, 0x08, 0xe0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc}, - {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc}, - {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc}, - {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, - {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, - {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, - {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc}, - {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc}, - {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc}, - {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, - {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa}, - {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa}, - {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa}, - {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa}, - {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa}, - {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa}, - {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa}, - {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa}, - {0x00, 0x59, 0x6f, 0xaa}, {0x00, 0x5a, 0x04, 0xaa}, - {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa}, - {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa}, - {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa}, - {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa}, - {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa}, - {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa}, - {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa}, - {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa}, - {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa}, - {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa}, - {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa}, - {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa}, - {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa}, - {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa}, - {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa}, - {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa}, - {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, - {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, - {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, - {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, - {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, - {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, - {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa}, - {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa}, - {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa}, - {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa}, - {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa}, - {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa}, - {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa}, - {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, - {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, - {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, - {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, - {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, - {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, - {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0x4c, 0x07, 0xaa}, - {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa}, - {0x00, 0x59, 0x66, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa}, - {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa}, - {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, - {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc}, - {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, - {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, - {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, - {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc}, - {0xb9, 0x08, 0x3c, 0xcc}, {0xbc, 0x02, 0x18, 0xcc}, - {0xbc, 0x03, 0x50, 0xcc}, {0xbc, 0x04, 0x18, 0xcc}, - {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc}, - {0xbc, 0x08, 0x30, 0xcc}, {0xbc, 0x09, 0x40, 0xcc}, - {0xbc, 0x0a, 0x10, 0xcc}, {0xbc, 0x0b, 0x00, 0xcc}, - {0xbc, 0x0c, 0x00, 0xcc}, {0x00, 0x05, 0x00, 0xaa}, - {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc}, - {} -}; - -static const u8 hv7131r_gamma[17] = { - 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, - 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff -}; -static const u8 hv7131r_matrix[9] = { - 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63 -}; -static const u8 hv7131r_initVGA_data[][4] = { - {0xb3, 0x01, 0x01, 0xcc}, - {0xb0, 0x03, 0x19, 0xcc}, - {0xb0, 0x04, 0x02, 0xcc}, - {0x00, 0x00, 0x20, 0xdd}, - {0xb3, 0x00, 0x24, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x03, 0xcc}, - {0xb3, 0x01, 0x45, 0xcc}, - {0xb3, 0x03, 0x0b, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x02, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x35, 0x91, 0xcc}, /* i2c add: 11 */ - {0xb3, 0x00, 0x27, 0xcc}, - {0xbc, 0x00, 0x73, 0xcc}, - {0xb8, 0x00, 0x23, 0xcc}, - {0xb8, 0x2c, 0x50, 0xcc}, - {0xb8, 0x2d, 0xf8, 0xcc}, - {0xb8, 0x2e, 0xf8, 0xcc}, - {0xb8, 0x2f, 0xf8, 0xcc}, - {0xb8, 0x30, 0x50, 0xcc}, - {0xb8, 0x31, 0xf8, 0xcc}, - {0xb8, 0x32, 0xf8, 0xcc}, - {0xb8, 0x33, 0xf8, 0xcc}, - {0xb8, 0x34, 0x58, 0xcc}, - {0xb8, 0x35, 0x00, 0xcc}, - {0xb8, 0x36, 0x00, 0xcc}, - {0xb8, 0x37, 0x00, 0xcc}, - {0xb8, 0x27, 0x20, 0xcc}, - {0xb8, 0x01, 0x7d, 0xcc}, - {0xb8, 0x81, 0x09, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0xb8, 0x8e, 0x00, 0xcc}, - {0xb8, 0x8f, 0xff, 0xcc}, - {0x00, 0x01, 0x0c, 0xaa}, - {0x00, 0x14, 0x01, 0xaa}, - {0x00, 0x15, 0xe6, 0xaa}, - {0x00, 0x16, 0x02, 0xaa}, - {0x00, 0x17, 0x86, 0xaa}, - {0x00, 0x23, 0x00, 0xaa}, - {0x00, 0x25, 0x03, 0xaa}, - {0x00, 0x26, 0xa9, 0xaa}, - {0x00, 0x27, 0x80, 0xaa}, - {0x00, 0x30, 0x18, 0xaa}, - {0xb6, 0x00, 0x00, 0xcc}, - {0xb6, 0x03, 0x02, 0xcc}, - {0xb6, 0x02, 0x80, 0xcc}, - {0xb6, 0x05, 0x01, 0xcc}, - {0xb6, 0x04, 0xe0, 0xcc}, - {0xb6, 0x12, 0x78, 0xcc}, - {0xb6, 0x18, 0x02, 0xcc}, - {0xb6, 0x17, 0x58, 0xcc}, - {0xb6, 0x16, 0x00, 0xcc}, - {0xb6, 0x22, 0x12, 0xcc}, - {0xb6, 0x23, 0x0b, 0xcc}, - {0xb3, 0x02, 0x02, 0xcc}, - {0xbf, 0xc0, 0x39, 0xcc}, - {0xbf, 0xc1, 0x04, 0xcc}, - {0xbf, 0xcc, 0x10, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, - {0xb6, 0x13, 0x13, 0xcc}, - {0xb9, 0x12, 0x00, 0xcc}, - {0xb9, 0x13, 0x0a, 0xcc}, - {0xb9, 0x14, 0x0a, 0xcc}, - {0xb9, 0x15, 0x0a, 0xcc}, - {0xb9, 0x16, 0x0a, 0xcc}, - {0xb8, 0x0c, 0x20, 0xcc}, - {0xb8, 0x0d, 0x70, 0xcc}, - {0xb9, 0x18, 0x00, 0xcc}, - {0xb9, 0x19, 0x0f, 0xcc}, - {0xb9, 0x1a, 0x0f, 0xcc}, - {0xb9, 0x1b, 0x0f, 0xcc}, - {0xb9, 0x1c, 0x0f, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {} -}; - -static const u8 hv7131r_initQVGA_data[][4] = { - {0xb3, 0x01, 0x01, 0xcc}, - {0xb0, 0x03, 0x19, 0xcc}, - {0xb0, 0x04, 0x02, 0xcc}, - {0x00, 0x00, 0x20, 0xdd}, - {0xb3, 0x00, 0x24, 0xcc}, - {0xb3, 0x00, 0x25, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x03, 0xcc}, - {0xb3, 0x01, 0x45, 0xcc}, - {0xb3, 0x03, 0x0b, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x02, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x35, 0x91, 0xcc}, - {0xb3, 0x00, 0x27, 0xcc}, - {0xbc, 0x00, 0xd3, 0xcc}, - {0xb8, 0x00, 0x23, 0xcc}, - {0xb8, 0x2c, 0x50, 0xcc}, - {0xb8, 0x2d, 0xf8, 0xcc}, - {0xb8, 0x2e, 0xf8, 0xcc}, - {0xb8, 0x2f, 0xf8, 0xcc}, - {0xb8, 0x30, 0x50, 0xcc}, - {0xb8, 0x31, 0xf8, 0xcc}, - {0xb8, 0x32, 0xf8, 0xcc}, - {0xb8, 0x33, 0xf8, 0xcc}, - {0xb8, 0x34, 0x58, 0xcc}, - {0xb8, 0x35, 0x00, 0xcc}, - {0xb8, 0x36, 0x00, 0xcc}, - {0xb8, 0x37, 0x00, 0xcc}, - {0xb8, 0x27, 0x20, 0xcc}, - {0xb8, 0x01, 0x7d, 0xcc}, - {0xb8, 0x81, 0x09, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0xb8, 0x8e, 0x00, 0xcc}, - {0xb8, 0x8f, 0xff, 0xcc}, - {0x00, 0x01, 0x0c, 0xaa}, - {0x00, 0x14, 0x01, 0xaa}, - {0x00, 0x15, 0xe6, 0xaa}, - {0x00, 0x16, 0x02, 0xaa}, - {0x00, 0x17, 0x86, 0xaa}, - {0x00, 0x23, 0x00, 0xaa}, - {0x00, 0x25, 0x03, 0xaa}, - {0x00, 0x26, 0xa9, 0xaa}, - {0x00, 0x27, 0x80, 0xaa}, - {0x00, 0x30, 0x18, 0xaa}, - {0xb6, 0x00, 0x00, 0xcc}, - {0xb6, 0x03, 0x01, 0xcc}, - {0xb6, 0x02, 0x40, 0xcc}, - {0xb6, 0x05, 0x00, 0xcc}, - {0xb6, 0x04, 0xf0, 0xcc}, - {0xb6, 0x12, 0x78, 0xcc}, - {0xb6, 0x18, 0x00, 0xcc}, - {0xb6, 0x17, 0x96, 0xcc}, - {0xb6, 0x16, 0x00, 0xcc}, - {0xb6, 0x22, 0x12, 0xcc}, - {0xb6, 0x23, 0x0b, 0xcc}, - {0xb3, 0x02, 0x02, 0xcc}, - {0xbf, 0xc0, 0x39, 0xcc}, - {0xbf, 0xc1, 0x04, 0xcc}, - {0xbf, 0xcc, 0x10, 0xcc}, - {0xbc, 0x02, 0x18, 0xcc}, - {0xbc, 0x03, 0x50, 0xcc}, - {0xbc, 0x04, 0x18, 0xcc}, - {0xbc, 0x05, 0x00, 0xcc}, - {0xbc, 0x06, 0x00, 0xcc}, - {0xbc, 0x08, 0x30, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, - {0xbc, 0x0a, 0x10, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, - {0xbc, 0x0c, 0x00, 0xcc}, - {0xb9, 0x12, 0x00, 0xcc}, - {0xb9, 0x13, 0x0a, 0xcc}, - {0xb9, 0x14, 0x0a, 0xcc}, - {0xb9, 0x15, 0x0a, 0xcc}, - {0xb9, 0x16, 0x0a, 0xcc}, - {0xb9, 0x18, 0x00, 0xcc}, - {0xb9, 0x19, 0x0f, 0xcc}, - {0xb8, 0x0c, 0x20, 0xcc}, - {0xb8, 0x0d, 0x70, 0xcc}, - {0xb9, 0x1a, 0x0f, 0xcc}, - {0xb9, 0x1b, 0x0f, 0xcc}, - {0xb9, 0x1c, 0x0f, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, - {0xb6, 0x13, 0x13, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {} -}; - -static const u8 ov7660_gamma[17] = { - 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, - 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff -}; -static const u8 ov7660_matrix[9] = { - 0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62 -}; -static const u8 ov7660_initVGA_data[][4] = { - {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, - {0xb0, 0x03, 0x01, 0xcc}, - {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x03, 0xcc}, - {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */ - {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc}, - {0xb3, 0x1f, 0x02, 0xcc}, - {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */ - {0xb3, 0x00, 0x26, 0xcc}, - {0xb8, 0x00, 0x33, 0xcc}, /* 13 */ - {0xb8, 0x01, 0x7d, 0xcc}, - {0xbc, 0x00, 0x73, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, - {0xb8, 0x27, 0x20, 0xcc}, - {0xb8, 0x8f, 0x50, 0xcc}, - {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa}, - {0x00, 0x12, 0x80, 0xaa}, - {0x00, 0x12, 0x05, 0xaa}, - {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */ - {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */ - {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */ - {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa}, - {0x00, 0x13, 0xa7, 0xaa}, - {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa}, - {0x00, 0x36, 0x00, 0xaa}, - {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa}, - {0x00, 0x39, 0x43, 0xaa}, - {0x00, 0x8d, 0xcf, 0xaa}, - {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa}, - {0x00, 0x0f, 0x62, 0xaa}, - {0x00, 0x35, 0x84, 0xaa}, - {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */ - {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/ - {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */ - {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc}, - {0x00, 0x01, 0x80, 0xaa}, - {0x00, 0x02, 0x80, 0xaa}, - {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc}, - {0xb9, 0x00, 0x28, 0xcc}, - {0xb9, 0x01, 0x28, 0xcc}, {0xb9, 0x02, 0x28, 0xcc}, - {0xb9, 0x03, 0x00, 0xcc}, - {0xb9, 0x04, 0x00, 0xcc}, - {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc}, - {0xb9, 0x07, 0x3c, 0xcc}, - {0xb9, 0x08, 0x3c, 0xcc}, - - {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, - - {0x00, 0x29, 0x3c, 0xaa}, {0xb3, 0x01, 0x45, 0xcc}, - {} -}; -static const u8 ov7660_initQVGA_data[][4] = { - {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, - {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x03, 0xcc}, - {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */ - {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc}, - {0xb3, 0x1f, 0x02, 0xcc}, {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, - {0xb8, 0x00, 0x33, 0xcc}, /* 13 */ - {0xb8, 0x01, 0x7d, 0xcc}, -/* sizer */ - {0xbc, 0x00, 0xd3, 0xcc}, - {0xb8, 0x81, 0x09, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, - {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x8f, 0x50, 0xcc}, - {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa}, - {0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa}, - {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */ - {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */ - {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */ - {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa}, - {0x00, 0x13, 0xa7, 0xaa}, - {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa}, - {0x00, 0x36, 0x00, 0xaa}, - {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa}, - {0x00, 0x39, 0x43, 0xaa}, {0x00, 0x8d, 0xcf, 0xaa}, - {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa}, - {0x00, 0x0f, 0x62, 0xaa}, {0x00, 0x35, 0x84, 0xaa}, - {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */ - {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/ - {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */ - {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc}, - {0x00, 0x01, 0x80, 0xaa}, - {0x00, 0x02, 0x80, 0xaa}, -/* sizer filters */ - {0xbc, 0x02, 0x08, 0xcc}, - {0xbc, 0x03, 0x70, 0xcc}, - {0xb8, 0x35, 0x00, 0xcc}, - {0xb8, 0x36, 0x00, 0xcc}, - {0xb8, 0x37, 0x00, 0xcc}, - {0xbc, 0x04, 0x08, 0xcc}, - {0xbc, 0x05, 0x00, 0xcc}, - {0xbc, 0x06, 0x00, 0xcc}, - {0xbc, 0x08, 0x3c, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, - {0xbc, 0x0a, 0x04, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, - {0xbc, 0x0c, 0x00, 0xcc}, -/* */ - {0xb8, 0xfe, 0x00, 0xcc}, - {0xb8, 0xff, 0x28, 0xcc}, -/* */ - {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, - {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, - {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, - {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc}, - {0xb9, 0x08, 0x3c, 0xcc}, -/* */ - {0xb8, 0x8e, 0x00, 0xcc}, - {0xb8, 0x8f, 0xff, 0xcc}, /* ff */ - {0x00, 0x29, 0x3c, 0xaa}, - {0xb3, 0x01, 0x45, 0xcc}, /* 45 */ - {} -}; - -static const u8 ov7660_50HZ[][4] = { - {0x00, 0x3b, 0x08, 0xaa}, - {0x00, 0x9d, 0x40, 0xaa}, - {0x00, 0x13, 0xa7, 0xaa}, - {} -}; - -static const u8 ov7660_60HZ[][4] = { - {0x00, 0x3b, 0x00, 0xaa}, - {0x00, 0x9e, 0x40, 0xaa}, - {0x00, 0x13, 0xa7, 0xaa}, - {} -}; - -static const u8 ov7660_NoFliker[][4] = { - {0x00, 0x13, 0x87, 0xaa}, - {} -}; - -static const u8 ov7670_InitVGA[][4] = { - {0xb3, 0x01, 0x05, 0xcc}, - {0x00, 0x00, 0x30, 0xdd}, - {0xb0, 0x03, 0x19, 0xcc}, - {0x00, 0x00, 0x10, 0xdd}, - {0xb0, 0x04, 0x02, 0xcc}, - {0x00, 0x00, 0x10, 0xdd}, - {0xb3, 0x00, 0x66, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb0, 0x16, 0x01, 0xcc}, - {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */ - {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x02, 0x02, 0xcc}, - {0xb3, 0x03, 0x1f, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, - {0xbc, 0x00, 0x41, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, - {0x00, 0x12, 0x80, 0xaa}, - {0x00, 0x00, 0x20, 0xdd}, - {0x00, 0x12, 0x00, 0xaa}, - {0x00, 0x11, 0x40, 0xaa}, - {0x00, 0x6b, 0x0a, 0xaa}, - {0x00, 0x3a, 0x04, 0xaa}, - {0x00, 0x40, 0xc0, 0xaa}, - {0x00, 0x8c, 0x00, 0xaa}, - {0x00, 0x7a, 0x29, 0xaa}, - {0x00, 0x7b, 0x0e, 0xaa}, - {0x00, 0x7c, 0x1a, 0xaa}, - {0x00, 0x7d, 0x31, 0xaa}, - {0x00, 0x7e, 0x53, 0xaa}, - {0x00, 0x7f, 0x60, 0xaa}, - {0x00, 0x80, 0x6b, 0xaa}, - {0x00, 0x81, 0x73, 0xaa}, - {0x00, 0x82, 0x7b, 0xaa}, - {0x00, 0x83, 0x82, 0xaa}, - {0x00, 0x84, 0x89, 0xaa}, - {0x00, 0x85, 0x96, 0xaa}, - {0x00, 0x86, 0xa1, 0xaa}, - {0x00, 0x87, 0xb7, 0xaa}, - {0x00, 0x88, 0xcc, 0xaa}, - {0x00, 0x89, 0xe1, 0xaa}, - {0x00, 0x13, 0xe0, 0xaa}, - {0x00, 0x00, 0x00, 0xaa}, - {0x00, 0x10, 0x00, 0xaa}, - {0x00, 0x0d, 0x40, 0xaa}, - {0x00, 0x14, 0x28, 0xaa}, - {0x00, 0xa5, 0x05, 0xaa}, - {0x00, 0xab, 0x07, 0xaa}, - {0x00, 0x24, 0x95, 0xaa}, - {0x00, 0x25, 0x33, 0xaa}, - {0x00, 0x26, 0xe3, 0xaa}, - {0x00, 0x9f, 0x88, 0xaa}, - {0x00, 0xa0, 0x78, 0xaa}, - {0x00, 0x55, 0x90, 0xaa}, - {0x00, 0xa1, 0x03, 0xaa}, - {0x00, 0xa6, 0xe0, 0xaa}, - {0x00, 0xa7, 0xd8, 0xaa}, - {0x00, 0xa8, 0xf0, 0xaa}, - {0x00, 0xa9, 0x90, 0xaa}, - {0x00, 0xaa, 0x14, 0xaa}, - {0x00, 0x13, 0xe5, 0xaa}, - {0x00, 0x0e, 0x61, 0xaa}, - {0x00, 0x0f, 0x4b, 0xaa}, - {0x00, 0x16, 0x02, 0xaa}, - {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */ - {0x00, 0x21, 0x02, 0xaa}, - {0x00, 0x22, 0x91, 0xaa}, - {0x00, 0x29, 0x07, 0xaa}, - {0x00, 0x33, 0x0b, 0xaa}, - {0x00, 0x35, 0x0b, 0xaa}, - {0x00, 0x37, 0x1d, 0xaa}, - {0x00, 0x38, 0x71, 0xaa}, - {0x00, 0x39, 0x2a, 0xaa}, - {0x00, 0x3c, 0x78, 0xaa}, - {0x00, 0x4d, 0x40, 0xaa}, - {0x00, 0x4e, 0x20, 0xaa}, - {0x00, 0x74, 0x19, 0xaa}, - {0x00, 0x8d, 0x4f, 0xaa}, - {0x00, 0x8e, 0x00, 0xaa}, - {0x00, 0x8f, 0x00, 0xaa}, - {0x00, 0x90, 0x00, 0xaa}, - {0x00, 0x91, 0x00, 0xaa}, - {0x00, 0x96, 0x00, 0xaa}, - {0x00, 0x9a, 0x80, 0xaa}, - {0x00, 0xb0, 0x84, 0xaa}, - {0x00, 0xb1, 0x0c, 0xaa}, - {0x00, 0xb2, 0x0e, 0xaa}, - {0x00, 0xb3, 0x82, 0xaa}, - {0x00, 0xb8, 0x0a, 0xaa}, - {0x00, 0x43, 0x14, 0xaa}, - {0x00, 0x44, 0xf0, 0xaa}, - {0x00, 0x45, 0x45, 0xaa}, - {0x00, 0x46, 0x63, 0xaa}, - {0x00, 0x47, 0x2d, 0xaa}, - {0x00, 0x48, 0x46, 0xaa}, - {0x00, 0x59, 0x88, 0xaa}, - {0x00, 0x5a, 0xa0, 0xaa}, - {0x00, 0x5b, 0xc6, 0xaa}, - {0x00, 0x5c, 0x7d, 0xaa}, - {0x00, 0x5d, 0x5f, 0xaa}, - {0x00, 0x5e, 0x19, 0xaa}, - {0x00, 0x6c, 0x0a, 0xaa}, - {0x00, 0x6d, 0x55, 0xaa}, - {0x00, 0x6e, 0x11, 0xaa}, - {0x00, 0x6f, 0x9e, 0xaa}, - {0x00, 0x69, 0x00, 0xaa}, - {0x00, 0x6a, 0x40, 0xaa}, - {0x00, 0x01, 0x40, 0xaa}, - {0x00, 0x02, 0x40, 0xaa}, - {0x00, 0x13, 0xe7, 0xaa}, - {0x00, 0x5f, 0xf0, 0xaa}, - {0x00, 0x60, 0xf0, 0xaa}, - {0x00, 0x61, 0xf0, 0xaa}, - {0x00, 0x27, 0xa0, 0xaa}, - {0x00, 0x28, 0x80, 0xaa}, - {0x00, 0x2c, 0x90, 0xaa}, - {0x00, 0x4f, 0x66, 0xaa}, - {0x00, 0x50, 0x66, 0xaa}, - {0x00, 0x51, 0x00, 0xaa}, - {0x00, 0x52, 0x22, 0xaa}, - {0x00, 0x53, 0x5e, 0xaa}, - {0x00, 0x54, 0x80, 0xaa}, - {0x00, 0x58, 0x9e, 0xaa}, - {0x00, 0x41, 0x08, 0xaa}, - {0x00, 0x3f, 0x00, 0xaa}, - {0x00, 0x75, 0x85, 0xaa}, - {0x00, 0x76, 0xe1, 0xaa}, - {0x00, 0x4c, 0x00, 0xaa}, - {0x00, 0x77, 0x0a, 0xaa}, - {0x00, 0x3d, 0x88, 0xaa}, - {0x00, 0x4b, 0x09, 0xaa}, - {0x00, 0xc9, 0x60, 0xaa}, - {0x00, 0x41, 0x38, 0xaa}, - {0x00, 0x62, 0x30, 0xaa}, - {0x00, 0x63, 0x30, 0xaa}, - {0x00, 0x64, 0x08, 0xaa}, - {0x00, 0x94, 0x07, 0xaa}, - {0x00, 0x95, 0x0b, 0xaa}, - {0x00, 0x65, 0x00, 0xaa}, - {0x00, 0x66, 0x05, 0xaa}, - {0x00, 0x56, 0x50, 0xaa}, - {0x00, 0x34, 0x11, 0xaa}, - {0x00, 0xa4, 0x88, 0xaa}, - {0x00, 0x96, 0x00, 0xaa}, - {0x00, 0x97, 0x30, 0xaa}, - {0x00, 0x98, 0x20, 0xaa}, - {0x00, 0x99, 0x30, 0xaa}, - {0x00, 0x9a, 0x84, 0xaa}, - {0x00, 0x9b, 0x29, 0xaa}, - {0x00, 0x9c, 0x03, 0xaa}, - {0x00, 0x78, 0x04, 0xaa}, - {0x00, 0x79, 0x01, 0xaa}, - {0x00, 0xc8, 0xf0, 0xaa}, - {0x00, 0x79, 0x0f, 0xaa}, - {0x00, 0xc8, 0x00, 0xaa}, - {0x00, 0x79, 0x10, 0xaa}, - {0x00, 0xc8, 0x7e, 0xaa}, - {0x00, 0x79, 0x0a, 0xaa}, - {0x00, 0xc8, 0x80, 0xaa}, - {0x00, 0x79, 0x0b, 0xaa}, - {0x00, 0xc8, 0x01, 0xaa}, - {0x00, 0x79, 0x0c, 0xaa}, - {0x00, 0xc8, 0x0f, 0xaa}, - {0x00, 0x79, 0x0d, 0xaa}, - {0x00, 0xc8, 0x20, 0xaa}, - {0x00, 0x79, 0x09, 0xaa}, - {0x00, 0xc8, 0x80, 0xaa}, - {0x00, 0x79, 0x02, 0xaa}, - {0x00, 0xc8, 0xc0, 0xaa}, - {0x00, 0x79, 0x03, 0xaa}, - {0x00, 0xc8, 0x40, 0xaa}, - {0x00, 0x79, 0x05, 0xaa}, - {0x00, 0xc8, 0x30, 0xaa}, - {0x00, 0x79, 0x26, 0xaa}, - {0x00, 0x11, 0x40, 0xaa}, - {0x00, 0x3a, 0x04, 0xaa}, - {0x00, 0x12, 0x00, 0xaa}, - {0x00, 0x40, 0xc0, 0xaa}, - {0x00, 0x8c, 0x00, 0xaa}, - {0x00, 0x17, 0x14, 0xaa}, - {0x00, 0x18, 0x02, 0xaa}, - {0x00, 0x32, 0x92, 0xaa}, - {0x00, 0x19, 0x02, 0xaa}, - {0x00, 0x1a, 0x7a, 0xaa}, - {0x00, 0x03, 0x0a, 0xaa}, - {0x00, 0x0c, 0x00, 0xaa}, - {0x00, 0x3e, 0x00, 0xaa}, - {0x00, 0x70, 0x3a, 0xaa}, - {0x00, 0x71, 0x35, 0xaa}, - {0x00, 0x72, 0x11, 0xaa}, - {0x00, 0x73, 0xf0, 0xaa}, - {0x00, 0xa2, 0x02, 0xaa}, - {0x00, 0xb1, 0x00, 0xaa}, - {0x00, 0xb1, 0x0c, 0xaa}, - {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */ - {0x00, 0xaa, 0x14, 0xaa}, - {0x00, 0x24, 0x80, 0xaa}, - {0x00, 0x25, 0x74, 0xaa}, - {0x00, 0x26, 0xd3, 0xaa}, - {0x00, 0x0d, 0x00, 0xaa}, - {0x00, 0x14, 0x18, 0xaa}, - {0x00, 0x9d, 0x99, 0xaa}, - {0x00, 0x9e, 0x7f, 0xaa}, - {0x00, 0x64, 0x08, 0xaa}, - {0x00, 0x94, 0x07, 0xaa}, - {0x00, 0x95, 0x06, 0xaa}, - {0x00, 0x66, 0x05, 0xaa}, - {0x00, 0x41, 0x08, 0xaa}, - {0x00, 0x3f, 0x00, 0xaa}, - {0x00, 0x75, 0x07, 0xaa}, - {0x00, 0x76, 0xe1, 0xaa}, - {0x00, 0x4c, 0x00, 0xaa}, - {0x00, 0x77, 0x00, 0xaa}, - {0x00, 0x3d, 0xc2, 0xaa}, - {0x00, 0x4b, 0x09, 0xaa}, - {0x00, 0xc9, 0x60, 0xaa}, - {0x00, 0x41, 0x38, 0xaa}, - {0xbf, 0xc0, 0x26, 0xcc}, - {0xbf, 0xc1, 0x02, 0xcc}, - {0xbf, 0xcc, 0x04, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xb3, 0x01, 0x45, 0xcc}, - {0x00, 0x77, 0x05, 0xaa}, - {}, -}; - -static const u8 ov7670_InitQVGA[][4] = { - {0xb3, 0x01, 0x05, 0xcc}, - {0x00, 0x00, 0x30, 0xdd}, - {0xb0, 0x03, 0x19, 0xcc}, - {0x00, 0x00, 0x10, 0xdd}, - {0xb0, 0x04, 0x02, 0xcc}, - {0x00, 0x00, 0x10, 0xdd}, - {0xb3, 0x00, 0x66, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb0, 0x16, 0x01, 0xcc}, - {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */ - {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x02, 0x02, 0xcc}, - {0xb3, 0x03, 0x1f, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, - {0xb3, 0x23, 0xe0, 0xcc}, - {0xbc, 0x00, 0xd1, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, - {0x00, 0x12, 0x80, 0xaa}, - {0x00, 0x00, 0x20, 0xdd}, - {0x00, 0x12, 0x00, 0xaa}, - {0x00, 0x11, 0x40, 0xaa}, - {0x00, 0x6b, 0x0a, 0xaa}, - {0x00, 0x3a, 0x04, 0xaa}, - {0x00, 0x40, 0xc0, 0xaa}, - {0x00, 0x8c, 0x00, 0xaa}, - {0x00, 0x7a, 0x29, 0xaa}, - {0x00, 0x7b, 0x0e, 0xaa}, - {0x00, 0x7c, 0x1a, 0xaa}, - {0x00, 0x7d, 0x31, 0xaa}, - {0x00, 0x7e, 0x53, 0xaa}, - {0x00, 0x7f, 0x60, 0xaa}, - {0x00, 0x80, 0x6b, 0xaa}, - {0x00, 0x81, 0x73, 0xaa}, - {0x00, 0x82, 0x7b, 0xaa}, - {0x00, 0x83, 0x82, 0xaa}, - {0x00, 0x84, 0x89, 0xaa}, - {0x00, 0x85, 0x96, 0xaa}, - {0x00, 0x86, 0xa1, 0xaa}, - {0x00, 0x87, 0xb7, 0xaa}, - {0x00, 0x88, 0xcc, 0xaa}, - {0x00, 0x89, 0xe1, 0xaa}, - {0x00, 0x13, 0xe0, 0xaa}, - {0x00, 0x00, 0x00, 0xaa}, - {0x00, 0x10, 0x00, 0xaa}, - {0x00, 0x0d, 0x40, 0xaa}, - {0x00, 0x14, 0x28, 0xaa}, - {0x00, 0xa5, 0x05, 0xaa}, - {0x00, 0xab, 0x07, 0xaa}, - {0x00, 0x24, 0x95, 0xaa}, - {0x00, 0x25, 0x33, 0xaa}, - {0x00, 0x26, 0xe3, 0xaa}, - {0x00, 0x9f, 0x88, 0xaa}, - {0x00, 0xa0, 0x78, 0xaa}, - {0x00, 0x55, 0x90, 0xaa}, - {0x00, 0xa1, 0x03, 0xaa}, - {0x00, 0xa6, 0xe0, 0xaa}, - {0x00, 0xa7, 0xd8, 0xaa}, - {0x00, 0xa8, 0xf0, 0xaa}, - {0x00, 0xa9, 0x90, 0xaa}, - {0x00, 0xaa, 0x14, 0xaa}, - {0x00, 0x13, 0xe5, 0xaa}, - {0x00, 0x0e, 0x61, 0xaa}, - {0x00, 0x0f, 0x4b, 0xaa}, - {0x00, 0x16, 0x02, 0xaa}, - {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */ - {0x00, 0x21, 0x02, 0xaa}, - {0x00, 0x22, 0x91, 0xaa}, - {0x00, 0x29, 0x07, 0xaa}, - {0x00, 0x33, 0x0b, 0xaa}, - {0x00, 0x35, 0x0b, 0xaa}, - {0x00, 0x37, 0x1d, 0xaa}, - {0x00, 0x38, 0x71, 0xaa}, - {0x00, 0x39, 0x2a, 0xaa}, - {0x00, 0x3c, 0x78, 0xaa}, - {0x00, 0x4d, 0x40, 0xaa}, - {0x00, 0x4e, 0x20, 0xaa}, - {0x00, 0x74, 0x19, 0xaa}, - {0x00, 0x8d, 0x4f, 0xaa}, - {0x00, 0x8e, 0x00, 0xaa}, - {0x00, 0x8f, 0x00, 0xaa}, - {0x00, 0x90, 0x00, 0xaa}, - {0x00, 0x91, 0x00, 0xaa}, - {0x00, 0x96, 0x00, 0xaa}, - {0x00, 0x9a, 0x80, 0xaa}, - {0x00, 0xb0, 0x84, 0xaa}, - {0x00, 0xb1, 0x0c, 0xaa}, - {0x00, 0xb2, 0x0e, 0xaa}, - {0x00, 0xb3, 0x82, 0xaa}, - {0x00, 0xb8, 0x0a, 0xaa}, - {0x00, 0x43, 0x14, 0xaa}, - {0x00, 0x44, 0xf0, 0xaa}, - {0x00, 0x45, 0x45, 0xaa}, - {0x00, 0x46, 0x63, 0xaa}, - {0x00, 0x47, 0x2d, 0xaa}, - {0x00, 0x48, 0x46, 0xaa}, - {0x00, 0x59, 0x88, 0xaa}, - {0x00, 0x5a, 0xa0, 0xaa}, - {0x00, 0x5b, 0xc6, 0xaa}, - {0x00, 0x5c, 0x7d, 0xaa}, - {0x00, 0x5d, 0x5f, 0xaa}, - {0x00, 0x5e, 0x19, 0xaa}, - {0x00, 0x6c, 0x0a, 0xaa}, - {0x00, 0x6d, 0x55, 0xaa}, - {0x00, 0x6e, 0x11, 0xaa}, - {0x00, 0x6f, 0x9e, 0xaa}, - {0x00, 0x69, 0x00, 0xaa}, - {0x00, 0x6a, 0x40, 0xaa}, - {0x00, 0x01, 0x40, 0xaa}, - {0x00, 0x02, 0x40, 0xaa}, - {0x00, 0x13, 0xe7, 0xaa}, - {0x00, 0x5f, 0xf0, 0xaa}, - {0x00, 0x60, 0xf0, 0xaa}, - {0x00, 0x61, 0xf0, 0xaa}, - {0x00, 0x27, 0xa0, 0xaa}, - {0x00, 0x28, 0x80, 0xaa}, - {0x00, 0x2c, 0x90, 0xaa}, - {0x00, 0x4f, 0x66, 0xaa}, - {0x00, 0x50, 0x66, 0xaa}, - {0x00, 0x51, 0x00, 0xaa}, - {0x00, 0x52, 0x22, 0xaa}, - {0x00, 0x53, 0x5e, 0xaa}, - {0x00, 0x54, 0x80, 0xaa}, - {0x00, 0x58, 0x9e, 0xaa}, - {0x00, 0x41, 0x08, 0xaa}, - {0x00, 0x3f, 0x00, 0xaa}, - {0x00, 0x75, 0x85, 0xaa}, - {0x00, 0x76, 0xe1, 0xaa}, - {0x00, 0x4c, 0x00, 0xaa}, - {0x00, 0x77, 0x0a, 0xaa}, - {0x00, 0x3d, 0x88, 0xaa}, - {0x00, 0x4b, 0x09, 0xaa}, - {0x00, 0xc9, 0x60, 0xaa}, - {0x00, 0x41, 0x38, 0xaa}, - {0x00, 0x62, 0x30, 0xaa}, - {0x00, 0x63, 0x30, 0xaa}, - {0x00, 0x64, 0x08, 0xaa}, - {0x00, 0x94, 0x07, 0xaa}, - {0x00, 0x95, 0x0b, 0xaa}, - {0x00, 0x65, 0x00, 0xaa}, - {0x00, 0x66, 0x05, 0xaa}, - {0x00, 0x56, 0x50, 0xaa}, - {0x00, 0x34, 0x11, 0xaa}, - {0x00, 0xa4, 0x88, 0xaa}, - {0x00, 0x96, 0x00, 0xaa}, - {0x00, 0x97, 0x30, 0xaa}, - {0x00, 0x98, 0x20, 0xaa}, - {0x00, 0x99, 0x30, 0xaa}, - {0x00, 0x9a, 0x84, 0xaa}, - {0x00, 0x9b, 0x29, 0xaa}, - {0x00, 0x9c, 0x03, 0xaa}, - {0x00, 0x78, 0x04, 0xaa}, - {0x00, 0x79, 0x01, 0xaa}, - {0x00, 0xc8, 0xf0, 0xaa}, - {0x00, 0x79, 0x0f, 0xaa}, - {0x00, 0xc8, 0x00, 0xaa}, - {0x00, 0x79, 0x10, 0xaa}, - {0x00, 0xc8, 0x7e, 0xaa}, - {0x00, 0x79, 0x0a, 0xaa}, - {0x00, 0xc8, 0x80, 0xaa}, - {0x00, 0x79, 0x0b, 0xaa}, - {0x00, 0xc8, 0x01, 0xaa}, - {0x00, 0x79, 0x0c, 0xaa}, - {0x00, 0xc8, 0x0f, 0xaa}, - {0x00, 0x79, 0x0d, 0xaa}, - {0x00, 0xc8, 0x20, 0xaa}, - {0x00, 0x79, 0x09, 0xaa}, - {0x00, 0xc8, 0x80, 0xaa}, - {0x00, 0x79, 0x02, 0xaa}, - {0x00, 0xc8, 0xc0, 0xaa}, - {0x00, 0x79, 0x03, 0xaa}, - {0x00, 0xc8, 0x40, 0xaa}, - {0x00, 0x79, 0x05, 0xaa}, - {0x00, 0xc8, 0x30, 0xaa}, - {0x00, 0x79, 0x26, 0xaa}, - {0x00, 0x11, 0x40, 0xaa}, - {0x00, 0x3a, 0x04, 0xaa}, - {0x00, 0x12, 0x00, 0xaa}, - {0x00, 0x40, 0xc0, 0xaa}, - {0x00, 0x8c, 0x00, 0xaa}, - {0x00, 0x17, 0x14, 0xaa}, - {0x00, 0x18, 0x02, 0xaa}, - {0x00, 0x32, 0x92, 0xaa}, - {0x00, 0x19, 0x02, 0xaa}, - {0x00, 0x1a, 0x7a, 0xaa}, - {0x00, 0x03, 0x0a, 0xaa}, - {0x00, 0x0c, 0x00, 0xaa}, - {0x00, 0x3e, 0x00, 0xaa}, - {0x00, 0x70, 0x3a, 0xaa}, - {0x00, 0x71, 0x35, 0xaa}, - {0x00, 0x72, 0x11, 0xaa}, - {0x00, 0x73, 0xf0, 0xaa}, - {0x00, 0xa2, 0x02, 0xaa}, - {0x00, 0xb1, 0x00, 0xaa}, - {0x00, 0xb1, 0x0c, 0xaa}, - {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */ - {0x00, 0xaa, 0x14, 0xaa}, - {0x00, 0x24, 0x80, 0xaa}, - {0x00, 0x25, 0x74, 0xaa}, - {0x00, 0x26, 0xd3, 0xaa}, - {0x00, 0x0d, 0x00, 0xaa}, - {0x00, 0x14, 0x18, 0xaa}, - {0x00, 0x9d, 0x99, 0xaa}, - {0x00, 0x9e, 0x7f, 0xaa}, - {0x00, 0x64, 0x08, 0xaa}, - {0x00, 0x94, 0x07, 0xaa}, - {0x00, 0x95, 0x06, 0xaa}, - {0x00, 0x66, 0x05, 0xaa}, - {0x00, 0x41, 0x08, 0xaa}, - {0x00, 0x3f, 0x00, 0xaa}, - {0x00, 0x75, 0x07, 0xaa}, - {0x00, 0x76, 0xe1, 0xaa}, - {0x00, 0x4c, 0x00, 0xaa}, - {0x00, 0x77, 0x00, 0xaa}, - {0x00, 0x3d, 0xc2, 0xaa}, - {0x00, 0x4b, 0x09, 0xaa}, - {0x00, 0xc9, 0x60, 0xaa}, - {0x00, 0x41, 0x38, 0xaa}, - {0xbc, 0x02, 0x18, 0xcc}, - {0xbc, 0x03, 0x50, 0xcc}, - {0xbc, 0x04, 0x18, 0xcc}, - {0xbc, 0x05, 0x00, 0xcc}, - {0xbc, 0x06, 0x00, 0xcc}, - {0xbc, 0x08, 0x30, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, - {0xbc, 0x0a, 0x10, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, - {0xbc, 0x0c, 0x00, 0xcc}, - {0xbf, 0xc0, 0x26, 0xcc}, - {0xbf, 0xc1, 0x02, 0xcc}, - {0xbf, 0xcc, 0x04, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xb3, 0x01, 0x45, 0xcc}, - {0x00, 0x77, 0x05, 0xaa}, - {}, -}; - -/* PO1200 - values from usbvm326.inf and ms-win trace */ -static const u8 po1200_gamma[17] = { - 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, - 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff -}; -static const u8 po1200_matrix[9] = { - 0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e -}; -static const u8 po1200_initVGA_data[][4] = { - {0xb0, 0x03, 0x19, 0xcc}, /* reset? */ - {0xb0, 0x03, 0x19, 0xcc}, -/* {0x00, 0x00, 0x33, 0xdd}, */ - {0xb0, 0x04, 0x02, 0xcc}, - {0xb0, 0x02, 0x02, 0xcc}, - {0xb3, 0x5d, 0x00, 0xcc}, - {0xb3, 0x01, 0x01, 0xcc}, - {0xb3, 0x00, 0x64, 0xcc}, - {0xb3, 0x00, 0x65, 0xcc}, - {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb3, 0x02, 0xb2, 0xcc}, - {0xb3, 0x03, 0x18, 0xcc}, - {0xb3, 0x04, 0x15, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x02, 0xcc}, - {0xb3, 0x23, 0x58, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x03, 0xcc}, - {0xb3, 0x17, 0x1f, 0xcc}, - {0xbc, 0x00, 0x71, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, - {0xb0, 0x54, 0x13, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x35, 0xdc, 0xcc}, /* i2c add: 5c */ - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0x12, 0x05, 0xaa}, - {0x00, 0x13, 0x02, 0xaa}, - {0x00, 0x1e, 0xc6, 0xaa}, /* h/v flip */ - {0x00, 0x21, 0x00, 0xaa}, - {0x00, 0x25, 0x02, 0xaa}, - {0x00, 0x3c, 0x4f, 0xaa}, - {0x00, 0x3f, 0xe0, 0xaa}, - {0x00, 0x42, 0xff, 0xaa}, - {0x00, 0x45, 0x34, 0xaa}, - {0x00, 0x55, 0xfe, 0xaa}, - {0x00, 0x59, 0xd3, 0xaa}, - {0x00, 0x5e, 0x04, 0xaa}, - {0x00, 0x61, 0xb8, 0xaa}, /* sharpness */ - {0x00, 0x62, 0x02, 0xaa}, - {0x00, 0xa7, 0x31, 0xaa}, - {0x00, 0xa9, 0x66, 0xaa}, - {0x00, 0xb0, 0x00, 0xaa}, - {0x00, 0xb1, 0x00, 0xaa}, - {0x00, 0xb3, 0x11, 0xaa}, - {0x00, 0xb6, 0x26, 0xaa}, - {0x00, 0xb7, 0x20, 0xaa}, - {0x00, 0xba, 0x04, 0xaa}, - {0x00, 0x88, 0x42, 0xaa}, - {0x00, 0x89, 0x9a, 0xaa}, - {0x00, 0x8a, 0x88, 0xaa}, - {0x00, 0x8b, 0x8e, 0xaa}, - {0x00, 0x8c, 0x3e, 0xaa}, - {0x00, 0x8d, 0x90, 0xaa}, - {0x00, 0x8e, 0x87, 0xaa}, - {0x00, 0x8f, 0x96, 0xaa}, - {0x00, 0x90, 0x3d, 0xaa}, - {0x00, 0x64, 0x00, 0xaa}, - {0x00, 0x65, 0x10, 0xaa}, - {0x00, 0x66, 0x20, 0xaa}, - {0x00, 0x67, 0x2b, 0xaa}, - {0x00, 0x68, 0x36, 0xaa}, - {0x00, 0x69, 0x49, 0xaa}, - {0x00, 0x6a, 0x5a, 0xaa}, - {0x00, 0x6b, 0x7f, 0xaa}, - {0x00, 0x6c, 0x9b, 0xaa}, - {0x00, 0x6d, 0xba, 0xaa}, - {0x00, 0x6e, 0xd4, 0xaa}, - {0x00, 0x6f, 0xea, 0xaa}, - {0x00, 0x70, 0x00, 0xaa}, - {0x00, 0x71, 0x10, 0xaa}, - {0x00, 0x72, 0x20, 0xaa}, - {0x00, 0x73, 0x2b, 0xaa}, - {0x00, 0x74, 0x36, 0xaa}, - {0x00, 0x75, 0x49, 0xaa}, - {0x00, 0x76, 0x5a, 0xaa}, - {0x00, 0x77, 0x7f, 0xaa}, - {0x00, 0x78, 0x9b, 0xaa}, - {0x00, 0x79, 0xba, 0xaa}, - {0x00, 0x7a, 0xd4, 0xaa}, - {0x00, 0x7b, 0xea, 0xaa}, - {0x00, 0x7c, 0x00, 0xaa}, - {0x00, 0x7d, 0x10, 0xaa}, - {0x00, 0x7e, 0x20, 0xaa}, - {0x00, 0x7f, 0x2b, 0xaa}, - {0x00, 0x80, 0x36, 0xaa}, - {0x00, 0x81, 0x49, 0xaa}, - {0x00, 0x82, 0x5a, 0xaa}, - {0x00, 0x83, 0x7f, 0xaa}, - {0x00, 0x84, 0x9b, 0xaa}, - {0x00, 0x85, 0xba, 0xaa}, - {0x00, 0x86, 0xd4, 0xaa}, - {0x00, 0x87, 0xea, 0xaa}, - {0x00, 0x57, 0x2a, 0xaa}, - {0x00, 0x03, 0x01, 0xaa}, - {0x00, 0x04, 0x10, 0xaa}, - {0x00, 0x05, 0x10, 0xaa}, - {0x00, 0x06, 0x10, 0xaa}, - {0x00, 0x07, 0x10, 0xaa}, - {0x00, 0x08, 0x13, 0xaa}, - {0x00, 0x0a, 0x00, 0xaa}, - {0x00, 0x0b, 0x10, 0xaa}, - {0x00, 0x0c, 0x20, 0xaa}, - {0x00, 0x0d, 0x18, 0xaa}, - {0x00, 0x22, 0x01, 0xaa}, - {0x00, 0x23, 0x60, 0xaa}, - {0x00, 0x25, 0x08, 0xaa}, - {0x00, 0x26, 0x82, 0xaa}, - {0x00, 0x2e, 0x0f, 0xaa}, - {0x00, 0x2f, 0x1e, 0xaa}, - {0x00, 0x30, 0x2d, 0xaa}, - {0x00, 0x31, 0x3c, 0xaa}, - {0x00, 0x32, 0x4b, 0xaa}, - {0x00, 0x33, 0x5a, 0xaa}, - {0x00, 0x34, 0x69, 0xaa}, - {0x00, 0x35, 0x78, 0xaa}, - {0x00, 0x36, 0x87, 0xaa}, - {0x00, 0x37, 0x96, 0xaa}, - {0x00, 0x38, 0xa5, 0xaa}, - {0x00, 0x39, 0xb4, 0xaa}, - {0x00, 0x3a, 0xc3, 0xaa}, - {0x00, 0x3b, 0xd2, 0xaa}, - {0x00, 0x3c, 0xe1, 0xaa}, - {0x00, 0x3e, 0xff, 0xaa}, - {0x00, 0x3f, 0xff, 0xaa}, - {0x00, 0x40, 0xff, 0xaa}, - {0x00, 0x41, 0xff, 0xaa}, - {0x00, 0x42, 0xff, 0xaa}, - {0x00, 0x43, 0xff, 0xaa}, - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0x20, 0xc4, 0xaa}, - {0x00, 0x13, 0x03, 0xaa}, - {0x00, 0x3c, 0x50, 0xaa}, - {0x00, 0x61, 0x6a, 0xaa}, /* sharpness? */ - {0x00, 0x51, 0x5b, 0xaa}, - {0x00, 0x52, 0x91, 0xaa}, - {0x00, 0x53, 0x4c, 0xaa}, - {0x00, 0x54, 0x50, 0xaa}, - {0x00, 0x56, 0x02, 0xaa}, - {0xb6, 0x00, 0x00, 0xcc}, - {0xb6, 0x03, 0x03, 0xcc}, - {0xb6, 0x02, 0x20, 0xcc}, - {0xb6, 0x05, 0x02, 0xcc}, - {0xb6, 0x04, 0x58, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, - {0xb6, 0x13, 0x21, 0xcc}, - {0xb6, 0x18, 0x03, 0xcc}, - {0xb6, 0x17, 0xa9, 0xcc}, - {0xb6, 0x16, 0x80, 0xcc}, - {0xb6, 0x22, 0x12, 0xcc}, - {0xb6, 0x23, 0x0b, 0xcc}, - {0xbf, 0xc0, 0x39, 0xcc}, - {0xbf, 0xc1, 0x04, 0xcc}, - {0xbf, 0xcc, 0x00, 0xcc}, - {0xb8, 0x06, 0x20, 0xcc}, - {0xb8, 0x07, 0x03, 0xcc}, - {0xb8, 0x08, 0x58, 0xcc}, - {0xb8, 0x09, 0x02, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0xd9, 0x0f, 0xaa}, - {0x00, 0xda, 0xaa, 0xaa}, - {0x00, 0xd9, 0x10, 0xaa}, - {0x00, 0xda, 0xaa, 0xaa}, - {0x00, 0xd9, 0x11, 0xaa}, - {0x00, 0xda, 0x00, 0xaa}, - {0x00, 0xd9, 0x12, 0xaa}, - {0x00, 0xda, 0xff, 0xaa}, - {0x00, 0xd9, 0x13, 0xaa}, - {0x00, 0xda, 0xff, 0xaa}, - {0x00, 0xe8, 0x11, 0xaa}, - {0x00, 0xe9, 0x12, 0xaa}, - {0x00, 0xea, 0x5c, 0xaa}, - {0x00, 0xeb, 0xff, 0xaa}, - {0x00, 0xd8, 0x80, 0xaa}, - {0x00, 0xe6, 0x02, 0xaa}, - {0x00, 0xd6, 0x40, 0xaa}, - {0x00, 0xe3, 0x05, 0xaa}, - {0x00, 0xe0, 0x40, 0xaa}, - {0x00, 0xde, 0x03, 0xaa}, - {0x00, 0xdf, 0x03, 0xaa}, - {0x00, 0xdb, 0x02, 0xaa}, - {0x00, 0xdc, 0x00, 0xaa}, - {0x00, 0xdd, 0x03, 0xaa}, - {0x00, 0xe1, 0x08, 0xaa}, - {0x00, 0xe2, 0x01, 0xaa}, - {0x00, 0xd6, 0x40, 0xaa}, - {0x00, 0xe4, 0x40, 0xaa}, - {0x00, 0xa8, 0x8f, 0xaa}, - {0x00, 0xb4, 0x16, 0xaa}, - {0xb0, 0x02, 0x06, 0xcc}, - {0xb0, 0x18, 0x06, 0xcc}, - {0xb0, 0x19, 0x06, 0xcc}, - {0xb3, 0x5d, 0x18, 0xcc}, - {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x00, 0xcc}, - {0x00, 0xb4, 0x0e, 0xaa}, - {0x00, 0xb5, 0x49, 0xaa}, - {0x00, 0xb6, 0x1c, 0xaa}, - {0x00, 0xb7, 0x96, 0xaa}, -/* end of usbvm326.inf - start of ms-win trace */ - {0xb6, 0x12, 0xf8, 0xcc}, - {0xb6, 0x13, 0x3d, 0xcc}, -/*read b306*/ - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0x1a, 0x09, 0xaa}, - {0x00, 0x1b, 0x8a, 0xaa}, -/*read b827*/ - {0xb8, 0x27, 0x00, 0xcc}, - {0xb8, 0x26, 0x60, 0xcc}, - {0xb8, 0x26, 0x60, 0xcc}, -/*gamma - to do?*/ - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0xae, 0x84, 0xaa}, -/*gamma again*/ - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0x96, 0xa0, 0xaa}, -/*matrix*/ - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0x91, 0x35, 0xaa}, - {0x00, 0x92, 0x22, 0xaa}, -/*gamma*/ - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0x95, 0x85, 0xaa}, -/*matrix*/ - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0x4d, 0x20, 0xaa}, - {0xb8, 0x22, 0x40, 0xcc}, - {0xb8, 0x23, 0x40, 0xcc}, - {0xb8, 0x24, 0x40, 0xcc}, - {0xb8, 0x81, 0x09, 0xcc}, - {0x00, 0x00, 0x64, 0xdd}, - {0x00, 0x03, 0x01, 0xaa}, -/*read 46*/ - {0x00, 0x46, 0x3c, 0xaa}, - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0x16, 0x40, 0xaa}, - {0x00, 0x17, 0x40, 0xaa}, - {0x00, 0x18, 0x40, 0xaa}, - {0x00, 0x19, 0x41, 0xaa}, - {0x00, 0x03, 0x01, 0xaa}, - {0x00, 0x46, 0x3c, 0xaa}, - {0x00, 0x00, 0x18, 0xdd}, -/*read bfff*/ - {0x00, 0x03, 0x00, 0xaa}, - {0x00, 0xb4, 0x1c, 0xaa}, - {0x00, 0xb5, 0x92, 0xaa}, - {0x00, 0xb6, 0x39, 0xaa}, - {0x00, 0xb7, 0x24, 0xaa}, -/*write 89 0400 1415*/ - {} -}; - -static const u8 poxxxx_init_common[][4] = { - {0xb3, 0x00, 0x04, 0xcc}, - {0x00, 0x00, 0x10, 0xdd}, - {0xb3, 0x00, 0x64, 0xcc}, - {0x00, 0x00, 0x10, 0xdd}, - {0xb3, 0x00, 0x65, 0xcc}, - {0x00, 0x00, 0x10, 0xdd}, - {0xb3, 0x00, 0x67, 0xcc}, - {0xb0, 0x03, 0x09, 0xcc}, - {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x00, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, - {0xb3, 0x34, 0x01, 0xcc}, - {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */ - {0xb3, 0x02, 0xb0, 0xcc}, - {0xb3, 0x03, 0x18, 0xcc}, - {0xb3, 0x04, 0x15, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, - {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x04, 0xcc}, /* sensor height = 1024 */ - {0xb3, 0x23, 0x00, 0xcc}, - {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, - {0xb3, 0x16, 0x04, 0xcc}, /* sensor width = 1280 */ - {0xb3, 0x17, 0xff, 0xcc}, - {0xb3, 0x2c, 0x03, 0xcc}, - {0xb3, 0x2d, 0x56, 0xcc}, - {0xb3, 0x2e, 0x02, 0xcc}, - {0xb3, 0x2f, 0x0a, 0xcc}, - {0xb3, 0x40, 0x00, 0xcc}, - {0xb3, 0x41, 0x34, 0xcc}, - {0xb3, 0x42, 0x01, 0xcc}, - {0xb3, 0x43, 0xe0, 0xcc}, - {0xbc, 0x00, 0x71, 0xcc}, - {0xbc, 0x01, 0x01, 0xcc}, - {0xb3, 0x01, 0x41, 0xcc}, - {0xb3, 0x4d, 0x00, 0xcc}, - {0x00, 0x0b, 0x2a, 0xaa}, - {0x00, 0x0e, 0x03, 0xaa}, - {0x00, 0x0f, 0xea, 0xaa}, - {0x00, 0x12, 0x08, 0xaa}, - {0x00, 0x1e, 0x06, 0xaa}, - {0x00, 0x21, 0x00, 0xaa}, - {0x00, 0x31, 0x1f, 0xaa}, - {0x00, 0x33, 0x38, 0xaa}, - {0x00, 0x36, 0xc0, 0xaa}, - {0x00, 0x37, 0xc8, 0xaa}, - {0x00, 0x3b, 0x36, 0xaa}, - {0x00, 0x4b, 0xfe, 0xaa}, - {0x00, 0x4d, 0x2e, 0xaa}, - {0x00, 0x51, 0x1c, 0xaa}, - {0x00, 0x52, 0x01, 0xaa}, - {0x00, 0x55, 0x0a, 0xaa}, - {0x00, 0x56, 0x0a, 0xaa}, - {0x00, 0x57, 0x07, 0xaa}, - {0x00, 0x58, 0x07, 0xaa}, - {0x00, 0x59, 0x04, 0xaa}, - {0x00, 0x70, 0x68, 0xaa}, - {0x00, 0x71, 0x04, 0xaa}, - {0x00, 0x72, 0x10, 0xaa}, - {0x00, 0x80, 0x71, 0xaa}, - {0x00, 0x81, 0x08, 0xaa}, - {0x00, 0x82, 0x00, 0xaa}, - {0x00, 0x83, 0x55, 0xaa}, - {0x00, 0x84, 0x06, 0xaa}, - {0x00, 0x85, 0x06, 0xaa}, - {0x00, 0x8b, 0x25, 0xaa}, - {0x00, 0x8c, 0x00, 0xaa}, - {0x00, 0x8d, 0x86, 0xaa}, - {0x00, 0x8e, 0x82, 0xaa}, - {0x00, 0x8f, 0x2d, 0xaa}, - {0x00, 0x90, 0x8b, 0xaa}, - {0x00, 0x91, 0x81, 0xaa}, - {0x00, 0x92, 0x81, 0xaa}, - {0x00, 0x93, 0x23, 0xaa}, - {0x00, 0xa3, 0x2a, 0xaa}, - {0x00, 0xa4, 0x03, 0xaa}, - {0x00, 0xa5, 0xea, 0xaa}, - {0x00, 0xb0, 0x68, 0xaa}, - {0x00, 0xbc, 0x04, 0xaa}, - {0x00, 0xbe, 0x3b, 0xaa}, - {0x00, 0x4e, 0x40, 0xaa}, - {0x00, 0x06, 0x04, 0xaa}, - {0x00, 0x07, 0x03, 0xaa}, - {0x00, 0xcd, 0x18, 0xaa}, - {0x00, 0x28, 0x03, 0xaa}, - {0x00, 0x29, 0xef, 0xaa}, -/* reinit on alt 2 (qvga) or alt7 (vga) */ - {0xb3, 0x05, 0x00, 0xcc}, - {0xb3, 0x06, 0x00, 0xcc}, - {0xb8, 0x00, 0x01, 0xcc}, - - {0x00, 0x1d, 0x85, 0xaa}, - {0x00, 0x1e, 0xc6, 0xaa}, - {0x00, 0x00, 0x40, 0xdd}, - {0x00, 0x1d, 0x05, 0xaa}, - {} -}; -static const u8 poxxxx_gamma[][4] = { - {0x00, 0xd6, 0x22, 0xaa}, /* gamma 0 */ - {0x00, 0x73, 0x00, 0xaa}, - {0x00, 0x74, 0x0a, 0xaa}, - {0x00, 0x75, 0x16, 0xaa}, - {0x00, 0x76, 0x25, 0xaa}, - {0x00, 0x77, 0x34, 0xaa}, - {0x00, 0x78, 0x49, 0xaa}, - {0x00, 0x79, 0x5a, 0xaa}, - {0x00, 0x7a, 0x7f, 0xaa}, - {0x00, 0x7b, 0x9b, 0xaa}, - {0x00, 0x7c, 0xba, 0xaa}, - {0x00, 0x7d, 0xd4, 0xaa}, - {0x00, 0x7e, 0xea, 0xaa}, - - {0x00, 0xd6, 0x62, 0xaa}, /* gamma 1 */ - {0x00, 0x73, 0x00, 0xaa}, - {0x00, 0x74, 0x0a, 0xaa}, - {0x00, 0x75, 0x16, 0xaa}, - {0x00, 0x76, 0x25, 0xaa}, - {0x00, 0x77, 0x34, 0xaa}, - {0x00, 0x78, 0x49, 0xaa}, - {0x00, 0x79, 0x5a, 0xaa}, - {0x00, 0x7a, 0x7f, 0xaa}, - {0x00, 0x7b, 0x9b, 0xaa}, - {0x00, 0x7c, 0xba, 0xaa}, - {0x00, 0x7d, 0xd4, 0xaa}, - {0x00, 0x7e, 0xea, 0xaa}, - - {0x00, 0xd6, 0xa2, 0xaa}, /* gamma 2 */ - {0x00, 0x73, 0x00, 0xaa}, - {0x00, 0x74, 0x0a, 0xaa}, - {0x00, 0x75, 0x16, 0xaa}, - {0x00, 0x76, 0x25, 0xaa}, - {0x00, 0x77, 0x34, 0xaa}, - {0x00, 0x78, 0x49, 0xaa}, - {0x00, 0x79, 0x5a, 0xaa}, - {0x00, 0x7a, 0x7f, 0xaa}, - {0x00, 0x7b, 0x9b, 0xaa}, - {0x00, 0x7c, 0xba, 0xaa}, - {0x00, 0x7d, 0xd4, 0xaa}, - {0x00, 0x7e, 0xea, 0xaa}, - {} -}; -static const u8 poxxxx_init_start_3[][4] = { - {0x00, 0xb8, 0x28, 0xaa}, - {0x00, 0xb9, 0x1e, 0xaa}, - {0x00, 0xb6, 0x14, 0xaa}, - {0x00, 0xb7, 0x0f, 0xaa}, - {0x00, 0x5c, 0x10, 0xaa}, - {0x00, 0x5d, 0x18, 0xaa}, - {0x00, 0x5e, 0x24, 0xaa}, - {0x00, 0x5f, 0x24, 0xaa}, - {0x00, 0x86, 0x1a, 0xaa}, - {0x00, 0x60, 0x00, 0xaa}, - {0x00, 0x61, 0x1b, 0xaa}, - {0x00, 0x62, 0x30, 0xaa}, - {0x00, 0x63, 0x40, 0xaa}, - {0x00, 0x87, 0x1a, 0xaa}, - {0x00, 0x64, 0x00, 0xaa}, - {0x00, 0x65, 0x08, 0xaa}, - {0x00, 0x66, 0x10, 0xaa}, - {0x00, 0x67, 0x20, 0xaa}, - {0x00, 0x88, 0x10, 0xaa}, - {0x00, 0x68, 0x00, 0xaa}, - {0x00, 0x69, 0x08, 0xaa}, - {0x00, 0x6a, 0x0f, 0xaa}, - {0x00, 0x6b, 0x0f, 0xaa}, - {0x00, 0x89, 0x07, 0xaa}, - {0x00, 0xd5, 0x4c, 0xaa}, - {0x00, 0x0a, 0x00, 0xaa}, - {0x00, 0x0b, 0x2a, 0xaa}, - {0x00, 0x0e, 0x03, 0xaa}, - {0x00, 0x0f, 0xea, 0xaa}, - {0x00, 0xa2, 0x00, 0xaa}, - {0x00, 0xa3, 0x2a, 0xaa}, - {0x00, 0xa4, 0x03, 0xaa}, - {0x00, 0xa5, 0xea, 0xaa}, - {} -}; -static const u8 poxxxx_initVGA[][4] = { - {0x00, 0x20, 0x11, 0xaa}, - {0x00, 0x33, 0x38, 0xaa}, - {0x00, 0xbb, 0x0d, 0xaa}, - {0xb3, 0x22, 0x01, 0xcc}, /* change to 640x480 */ - {0xb3, 0x23, 0xe0, 0xcc}, - {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, - {0xb3, 0x02, 0xb0, 0xcc}, - {0xb3, 0x06, 0x00, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, - {0x00, 0x04, 0x06, 0xaa}, - {0x00, 0x05, 0x3f, 0xaa}, - {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */ - {} -}; -static const u8 poxxxx_initQVGA[][4] = { - {0x00, 0x20, 0x33, 0xaa}, - {0x00, 0x33, 0x38, 0xaa}, - {0x00, 0xbb, 0x0d, 0xaa}, - {0xb3, 0x22, 0x00, 0xcc}, /* change to 320x240 */ - {0xb3, 0x23, 0xf0, 0xcc}, - {0xb3, 0x16, 0x01, 0xcc}, - {0xb3, 0x17, 0x3f, 0xcc}, - {0xb3, 0x02, 0xb0, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, - {0xb3, 0x5c, 0x00, 0xcc}, - {0x00, 0x04, 0x06, 0xaa}, - {0x00, 0x05, 0x3f, 0xaa}, - {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */ - {} -}; -static const u8 poxxxx_init_end_1[][4] = { - {0x00, 0x47, 0x25, 0xaa}, - {0x00, 0x48, 0x80, 0xaa}, - {0x00, 0x49, 0x1f, 0xaa}, - {0x00, 0x4a, 0x40, 0xaa}, - {0x00, 0x44, 0x40, 0xaa}, - {0x00, 0xab, 0x4a, 0xaa}, - {0x00, 0xb1, 0x00, 0xaa}, - {0x00, 0xb2, 0x04, 0xaa}, - {0x00, 0xb3, 0x08, 0xaa}, - {0x00, 0xb4, 0x0b, 0xaa}, - {0x00, 0xb5, 0x0d, 0xaa}, - {} -}; -static const u8 poxxxx_init_end_2[][4] = { - {0x00, 0x1d, 0x85, 0xaa}, - {0x00, 0x1e, 0x06, 0xaa}, - {0x00, 0x1d, 0x05, 0xaa}, - {} -}; - -struct sensor_info { - s8 sensorId; - u8 I2cAdd; - u8 IdAdd; - u16 VpId; - u8 m1; - u8 m2; - u8 op; -}; - -/* probe values */ -static const struct sensor_info vc0321_probe_data[] = { -/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */ -/* 0 OV9640 */ - {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, -/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */ - {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01}, -/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/ - {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01}, -/* 3 MI1310 */ - {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01}, -/* 4 MI360 - tested in vc032x_probe_sensor */ -/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */ -/* 5 7131R */ - {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01}, -/* 6 OV7649 */ - {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05}, -/* 7 PAS302BCW */ - {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05}, -/* 8 OV7660 */ - {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05}, -/* 9 PO3130NC - (tested in vc032x_probe_sensor) */ -/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */ -/* 10 PO1030KC */ - {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01}, -/* 11 MI1310_SOC */ - {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01}, -/* 12 OV9650 */ - {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, -/* 13 S5K532 */ - {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01}, -/* 14 MI360_SOC - ??? */ -/* 15 PO1200N */ - {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01}, -/* 16 PO3030K */ - {-1, 0x80 | 0x18, 0x00, 0x0000, 0x24, 0x25, 0x01}, -/* 17 PO2030 */ - {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01}, -/* ?? */ - {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01}, - {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01}, -}; -static const struct sensor_info vc0323_probe_data[] = { -/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */ -/* 0 OV9640 */ - {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, -/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */ - {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01}, -/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/ - {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01}, -/* 3 MI1310 */ - {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01}, -/* 4 MI360 - tested in vc032x_probe_sensor */ -/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */ -/* 5 7131R */ - {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01}, -/* 6 OV7649 */ - {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05}, -/* 7 PAS302BCW */ - {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05}, -/* 8 OV7660 */ - {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05}, -/* 9 PO3130NC - (tested in vc032x_probe_sensor) */ -/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */ -/* 10 PO1030KC */ - {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01}, -/* 11 MI1310_SOC */ - {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01}, -/* 12 OV9650 */ - {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, -/* 13 S5K532 */ - {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01}, -/* 14 MI360_SOC - ??? */ -/* 15 PO1200N */ - {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01}, -/* 16 ?? */ - {-1, 0x80 | 0x2d, 0x00, 0x0000, 0x65, 0x67, 0x01}, -/* 17 PO2030 */ - {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01}, -/* ?? */ - {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01}, - {SENSOR_MI1320_SOC, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x67, 0x01}, -/*fixme: not in the ms-win probe - may be found before? */ - {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05}, -}; - -/* read 'len' bytes in gspca_dev->usb_buf */ -static void reg_r_i(struct gspca_dev *gspca_dev, - u16 req, - u16 index, - u16 len) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 1, /* value */ - index, gspca_dev->usb_buf, len, - 500); - if (ret < 0) { - err("reg_r err %d", ret); - gspca_dev->usb_err = ret; - } -} -static void reg_r(struct gspca_dev *gspca_dev, - u16 req, - u16 index, - u16 len) -{ - reg_r_i(gspca_dev, req, index, len); -#ifdef GSPCA_DEBUG - if (gspca_dev->usb_err < 0) - return; - if (len == 1) - PDEBUG(D_USBI, "GET %02x 0001 %04x %02x", req, index, - gspca_dev->usb_buf[0]); - else - PDEBUG(D_USBI, "GET %02x 0001 %04x %02x %02x %02x", - req, index, - gspca_dev->usb_buf[0], - gspca_dev->usb_buf[1], - gspca_dev->usb_buf[2]); -#endif -} - -static void reg_w_i(struct gspca_dev *gspca_dev, - u16 req, - u16 value, - u16 index) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, - 500); - if (ret < 0) { - err("reg_w err %d", ret); - gspca_dev->usb_err = ret; - } -} -static void reg_w(struct gspca_dev *gspca_dev, - u16 req, - u16 value, - u16 index) -{ -#ifdef GSPCA_DEBUG - if (gspca_dev->usb_err < 0) - return; - PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index); -#endif - reg_w_i(gspca_dev, req, value, index); -} - -static u16 read_sensor_register(struct gspca_dev *gspca_dev, - u16 address) -{ - u8 ldata, mdata, hdata; - int retry = 50; - - reg_r(gspca_dev, 0xa1, 0xb33f, 1); - if (!(gspca_dev->usb_buf[0] & 0x02)) { - err("I2c Bus Busy Wait %02x", - gspca_dev->usb_buf[0]); - return 0; - } - reg_w(gspca_dev, 0xa0, address, 0xb33a); - reg_w(gspca_dev, 0xa0, 0x02, 0xb339); - - do { - reg_r(gspca_dev, 0xa1, 0xb33b, 1); - if (gspca_dev->usb_buf[0] == 0x00) - break; - msleep(40); - } while (--retry >= 0); - - reg_r(gspca_dev, 0xa1, 0xb33e, 1); - ldata = gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0xa1, 0xb33d, 1); - mdata = gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0xa1, 0xb33c, 1); - hdata = gspca_dev->usb_buf[0]; - if (hdata != 0 && mdata != 0 && ldata != 0) - PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x", - hdata, mdata, ldata); - reg_r(gspca_dev, 0xa1, 0xb334, 1); - if (gspca_dev->usb_buf[0] == 0x02) - return (hdata << 8) + mdata; - return hdata; -} - -static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, n; - u16 value; - const struct sensor_info *ptsensor_info; - -/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/ - if (sd->flags & FL_SAMSUNG) { - reg_w(gspca_dev, 0xa0, 0x01, 0xb301); - reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff); - /* select the back sensor */ - } - - reg_r(gspca_dev, 0xa1, 0xbfcf, 1); - PDEBUG(D_PROBE, "vc032%d check sensor header %02x", - sd->bridge == BRIDGE_VC0321 ? 1 : 3, gspca_dev->usb_buf[0]); - if (sd->bridge == BRIDGE_VC0321) { - ptsensor_info = vc0321_probe_data; - n = ARRAY_SIZE(vc0321_probe_data); - } else { - ptsensor_info = vc0323_probe_data; - n = ARRAY_SIZE(vc0323_probe_data); - } - for (i = 0; i < n; i++) { - reg_w(gspca_dev, 0xa0, 0x02, 0xb334); - reg_w(gspca_dev, 0xa0, ptsensor_info->m1, 0xb300); - reg_w(gspca_dev, 0xa0, ptsensor_info->m2, 0xb300); - reg_w(gspca_dev, 0xa0, 0x01, 0xb308); - reg_w(gspca_dev, 0xa0, 0x0c, 0xb309); - reg_w(gspca_dev, 0xa0, ptsensor_info->I2cAdd, 0xb335); - reg_w(gspca_dev, 0xa0, ptsensor_info->op, 0xb301); - value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd); - if (value == 0 && ptsensor_info->IdAdd == 0x82) - value = read_sensor_register(gspca_dev, 0x83); - if (value != 0) { - PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)", - value, i); - if (value == ptsensor_info->VpId) - return ptsensor_info->sensorId; - - switch (value) { - case 0x3130: - return SENSOR_PO3130NC; - case 0x7673: - return SENSOR_OV7670; - case 0x8243: - return SENSOR_MI0360; - } - } - ptsensor_info++; - } - return -1; -} - -static void i2c_write(struct gspca_dev *gspca_dev, - u8 reg, const u8 *val, - u8 size) /* 1 or 2 */ -{ - int retry; - -#ifdef GSPCA_DEBUG - if (gspca_dev->usb_err < 0) - return; - if (size == 1) - PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val); - else - PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]); -#endif - reg_r_i(gspca_dev, 0xa1, 0xb33f, 1); -/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/ - reg_w_i(gspca_dev, 0xa0, size, 0xb334); - reg_w_i(gspca_dev, 0xa0, reg, 0xb33a); - reg_w_i(gspca_dev, 0xa0, val[0], 0xb336); - if (size > 1) - reg_w_i(gspca_dev, 0xa0, val[1], 0xb337); - reg_w_i(gspca_dev, 0xa0, 0x01, 0xb339); - retry = 4; - do { - reg_r_i(gspca_dev, 0xa1, 0xb33b, 1); - if (gspca_dev->usb_buf[0] == 0) - break; - msleep(20); - } while (--retry > 0); - if (retry <= 0) - err("i2c_write timeout"); -} - -static void put_tab_to_reg(struct gspca_dev *gspca_dev, - const u8 *tab, u8 tabsize, u16 addr) -{ - int j; - u16 ad = addr; - - for (j = 0; j < tabsize; j++) - reg_w(gspca_dev, 0xa0, tab[j], ad++); -} - -static void usb_exchange(struct gspca_dev *gspca_dev, - const u8 data[][4]) -{ - int i = 0; - - for (;;) { - switch (data[i][3]) { - default: - return; - case 0xcc: /* normal write */ - reg_w(gspca_dev, 0xa0, data[i][2], - (data[i][0]) << 8 | data[i][1]); - break; - case 0xaa: /* i2c op */ - i2c_write(gspca_dev, data[i][1], &data[i][2], 1); - break; - case 0xbb: /* i2c op */ - i2c_write(gspca_dev, data[i][0], &data[i][1], 2); - break; - case 0xdd: - msleep(data[i][1] * 256 + data[i][2] + 10); - break; - } - i++; - } - /*not reached*/ -} - - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->bridge = id->driver_info >> 8; - sd->flags = id->driver_info & 0xff; - - if (id->idVendor == 0x046d && - (id->idProduct == 0x0892 || id->idProduct == 0x0896)) - sd->sensor = SENSOR_POxxxx; /* no probe */ - - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->hflip = HFLIP_DEF; - sd->vflip = VFLIP_DEF; - sd->lightfreq = FREQ_DEF; - sd->sharpness = SHARPNESS_DEF; - sd->gain = GAIN_DEF; - sd->exposure = EXPOSURE_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->backlight = BACKLIGHT_DEF; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - int sensor; - /* number of packets per ISOC message */ - static u8 npkt[NSENSORS] = { - [SENSOR_HV7131R] = 64, - [SENSOR_MI0360] = 32, - [SENSOR_MI1310_SOC] = 32, - [SENSOR_MI1320] = 64, - [SENSOR_MI1320_SOC] = 128, - [SENSOR_OV7660] = 32, - [SENSOR_OV7670] = 64, - [SENSOR_PO1200] = 128, - [SENSOR_PO3130NC] = 128, - [SENSOR_POxxxx] = 128, - }; - - if (sd->sensor != SENSOR_POxxxx) - sensor = vc032x_probe_sensor(gspca_dev); - else - sensor = sd->sensor; - - switch (sensor) { - case -1: - err("Unknown sensor..."); - return -EINVAL; - case SENSOR_HV7131R: - PDEBUG(D_PROBE, "Find Sensor HV7131R"); - break; - case SENSOR_MI0360: - PDEBUG(D_PROBE, "Find Sensor MI0360"); - sd->bridge = BRIDGE_VC0323; - break; - case SENSOR_MI1310_SOC: - PDEBUG(D_PROBE, "Find Sensor MI1310_SOC"); - break; - case SENSOR_MI1320: - PDEBUG(D_PROBE, "Find Sensor MI1320"); - break; - case SENSOR_MI1320_SOC: - PDEBUG(D_PROBE, "Find Sensor MI1320_SOC"); - break; - case SENSOR_OV7660: - PDEBUG(D_PROBE, "Find Sensor OV7660"); - break; - case SENSOR_OV7670: - PDEBUG(D_PROBE, "Find Sensor OV7670"); - break; - case SENSOR_PO1200: - PDEBUG(D_PROBE, "Find Sensor PO1200"); - break; - case SENSOR_PO3130NC: - PDEBUG(D_PROBE, "Find Sensor PO3130NC"); - break; - case SENSOR_POxxxx: - PDEBUG(D_PROBE, "Sensor POxxxx"); - break; - } - sd->sensor = sensor; - - cam = &gspca_dev->cam; - if (sd->bridge == BRIDGE_VC0321) { - cam->cam_mode = vc0321_mode; - cam->nmodes = ARRAY_SIZE(vc0321_mode); - } else { - switch (sensor) { - case SENSOR_PO1200: - cam->cam_mode = svga_mode; - cam->nmodes = ARRAY_SIZE(svga_mode); - break; - case SENSOR_MI1310_SOC: - cam->cam_mode = vc0323_mode; - cam->nmodes = ARRAY_SIZE(vc0323_mode); - break; - case SENSOR_MI1320_SOC: - cam->cam_mode = bi_mode; - cam->nmodes = ARRAY_SIZE(bi_mode); - break; - case SENSOR_OV7670: - cam->cam_mode = bi_mode; - cam->nmodes = ARRAY_SIZE(bi_mode) - 1; - break; - default: - cam->cam_mode = vc0323_mode; - cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1; - break; - } - } - cam->npkt = npkt[sd->sensor]; - gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; - - if (sd->sensor == SENSOR_OV7670) - sd->flags |= FL_HFLIP | FL_VFLIP; - - if (sd->bridge == BRIDGE_VC0321) { - reg_r(gspca_dev, 0x8a, 0, 3); - reg_w(gspca_dev, 0x87, 0x00, 0x0f0f); - reg_r(gspca_dev, 0x8b, 0, 3); - reg_w(gspca_dev, 0x88, 0x00, 0x0202); - if (sd->sensor == SENSOR_POxxxx) { - reg_r(gspca_dev, 0xa1, 0xb300, 1); - if (gspca_dev->usb_buf[0] != 0) { - reg_w(gspca_dev, 0xa0, 0x26, 0xb300); - reg_w(gspca_dev, 0xa0, 0x04, 0xb300); - } - reg_w(gspca_dev, 0xa0, 0x00, 0xb300); - } - } - return gspca_dev->usb_err; -} - -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 data; - - if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX)) - return; - data = sd->brightness; - if (data >= 0x80) - data &= 0x7f; - else - data = 0xff ^ data; - i2c_write(gspca_dev, 0x98, &data, 1); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX)) - return; - i2c_write(gspca_dev, 0x99, &sd->contrast, 1); -} - -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 data; - - if (gspca_dev->ctrl_dis & (1 << COLORS_IDX)) - return; - data = sd->colors - (sd->colors >> 3) - 1; - i2c_write(gspca_dev, 0x94, &data, 1); - i2c_write(gspca_dev, 0x95, &sd->colors, 1); -} - -static void sethvflip(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 data[2], hflip, vflip; - - hflip = sd->hflip; - if (sd->flags & FL_HFLIP) - hflip = !hflip; - vflip = sd->vflip; - if (sd->flags & FL_VFLIP) - vflip = !vflip; - switch (sd->sensor) { - case SENSOR_MI1310_SOC: - case SENSOR_MI1320: - case SENSOR_MI1320_SOC: - data[0] = data[1] = 0; /* select page 0 */ - i2c_write(gspca_dev, 0xf0, data, 2); - data[0] = sd->sensor == SENSOR_MI1310_SOC ? 0x03 : 0x01; - data[1] = 0x02 * hflip - | 0x01 * vflip; - i2c_write(gspca_dev, 0x20, data, 2); - break; - case SENSOR_OV7660: - case SENSOR_OV7670: - data[0] = sd->sensor == SENSOR_OV7660 ? 0x01 : 0x07; - data[0] |= OV7660_MVFP_MIRROR * hflip - | OV7660_MVFP_VFLIP * vflip; - i2c_write(gspca_dev, OV7660_REG_MVFP, data, 1); - break; - case SENSOR_PO1200: - data[0] = 0; - i2c_write(gspca_dev, 0x03, data, 1); - data[0] = 0x80 * hflip - | 0x40 * vflip - | 0x06; - i2c_write(gspca_dev, 0x1e, data, 1); - break; - } -} - -static void setlightfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - static const u8 (*ov7660_freq_tb[3])[4] = - {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ}; - - if (sd->sensor != SENSOR_OV7660) - return; - usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]); -} - -static void setsharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 data; - - switch (sd->sensor) { - case SENSOR_PO1200: - data = 0; - i2c_write(gspca_dev, 0x03, &data, 1); - if (sd->sharpness < 0) - data = 0x6a; - else - data = 0xb5 + sd->sharpness * 3; - i2c_write(gspca_dev, 0x61, &data, 1); - break; - case SENSOR_POxxxx: - if (sd->sharpness < 0) - data = 0x7e; /* def = max */ - else - data = 0x60 + sd->sharpness * 0x0f; - i2c_write(gspca_dev, 0x59, &data, 1); - break; - } -} -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << GAIN_IDX)) - return; - i2c_write(gspca_dev, 0x15, &sd->gain, 1); -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 data; - - if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) - return; - data = sd->exposure >> 8; - i2c_write(gspca_dev, 0x1a, &data, 1); - data = sd->exposure; - i2c_write(gspca_dev, 0x1b, &data, 1); -} - -static void setautogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - static const u8 data[2] = {0x28, 0x3c}; - - if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) - return; - i2c_write(gspca_dev, 0xd1, &data[sd->autogain], 1); -} - -static void setgamma(struct gspca_dev *gspca_dev) -{ -/*fixme:to do */ - usb_exchange(gspca_dev, poxxxx_gamma); -} - -static void setbacklight(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 v; - u8 data; - - data = (sd->backlight << 4) | 0x0f; - i2c_write(gspca_dev, 0xaa, &data, 1); - v = 613 + 12 * sd->backlight; - data = v >> 8; - i2c_write(gspca_dev, 0xc4, &data, 1); - data = v; - i2c_write(gspca_dev, 0xc5, &data, 1); - v = 1093 - 12 * sd->backlight; - data = v >> 8; - i2c_write(gspca_dev, 0xc6, &data, 1); - data = v; - i2c_write(gspca_dev, 0xc7, &data, 1); - v = 342 + 9 * sd->backlight; - data = v >> 8; - i2c_write(gspca_dev, 0xc8, &data, 1); - data = v; - i2c_write(gspca_dev, 0xc9, &data, 1); - v = 702 - 9 * sd->backlight; - data = v >> 8; - i2c_write(gspca_dev, 0xca, &data, 1); - data = v; - i2c_write(gspca_dev, 0xcb, &data, 1); -} - -static void setwb(struct gspca_dev *gspca_dev) -{ -/*fixme:to do - valid when reg d1 = 0x1c - (reg16 + reg15 = 0xa3)*/ - static const u8 data[2] = {0x00, 0x00}; - - i2c_write(gspca_dev, 0x16, &data[0], 1); - i2c_write(gspca_dev, 0x18, &data[1], 1); -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - const u8 (*init)[4]; - const u8 *GammaT = NULL; - const u8 *MatrixT = NULL; - int mode; - static const u8 (*mi1320_soc_init[])[4] = { - mi1320_soc_InitSXGA, - mi1320_soc_InitVGA, - mi1320_soc_InitQVGA, - }; - -/*fixme: back sensor only*/ - if (sd->flags & FL_SAMSUNG) { - reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff); - reg_w(gspca_dev, 0xa9, 0x8348, 0x000e); - reg_w(gspca_dev, 0xa9, 0x0000, 0x001a); - } - - /* Assume start use the good resolution from gspca_dev->mode */ - if (sd->bridge == BRIDGE_VC0321) { - reg_w(gspca_dev, 0xa0, 0xff, 0xbfec); - reg_w(gspca_dev, 0xa0, 0xff, 0xbfed); - reg_w(gspca_dev, 0xa0, 0xff, 0xbfee); - reg_w(gspca_dev, 0xa0, 0xff, 0xbfef); - sd->image_offset = 46; - } else { - if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat - == V4L2_PIX_FMT_JPEG) - sd->image_offset = 0; - else - sd->image_offset = 32; - } - - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - switch (sd->sensor) { - case SENSOR_HV7131R: - GammaT = hv7131r_gamma; - MatrixT = hv7131r_matrix; - if (mode) - init = hv7131r_initQVGA_data; /* 320x240 */ - else - init = hv7131r_initVGA_data; /* 640x480 */ - break; - case SENSOR_OV7660: - GammaT = ov7660_gamma; - MatrixT = ov7660_matrix; - if (mode) - init = ov7660_initQVGA_data; /* 320x240 */ - else - init = ov7660_initVGA_data; /* 640x480 */ - break; - case SENSOR_MI0360: - GammaT = mi1320_gamma; - MatrixT = mi0360_matrix; - if (mode) - init = mi0360_initQVGA_JPG; /* 320x240 */ - else - init = mi0360_initVGA_JPG; /* 640x480 */ - break; - case SENSOR_MI1310_SOC: - GammaT = mi1320_gamma; - MatrixT = mi1320_matrix; - switch (mode) { - case 1: - init = mi1310_socinitQVGA_JPG; /* 320x240 */ - break; - case 0: - init = mi1310_socinitVGA_JPG; /* 640x480 */ - break; - default: - init = mi1310_soc_InitSXGA_JPG; /* 1280x1024 */ - break; - } - break; - case SENSOR_MI1320: - GammaT = mi1320_gamma; - MatrixT = mi1320_matrix; - if (mode) - init = mi1320_initQVGA_data; /* 320x240 */ - else - init = mi1320_initVGA_data; /* 640x480 */ - break; - case SENSOR_MI1320_SOC: - GammaT = mi1320_gamma; - MatrixT = mi1320_matrix; - init = mi1320_soc_init[mode]; - break; - case SENSOR_OV7670: - init = mode == 1 ? ov7670_InitVGA : ov7670_InitQVGA; - break; - case SENSOR_PO3130NC: - GammaT = po3130_gamma; - MatrixT = po3130_matrix; - if (mode) - init = po3130_initQVGA_data; /* 320x240 */ - else - init = po3130_initVGA_data; /* 640x480 */ - usb_exchange(gspca_dev, init); - init = po3130_rundata; - break; - case SENSOR_PO1200: - GammaT = po1200_gamma; - MatrixT = po1200_matrix; - init = po1200_initVGA_data; - break; - default: -/* case SENSOR_POxxxx: */ - usb_exchange(gspca_dev, poxxxx_init_common); - setgamma(gspca_dev); - setbacklight(gspca_dev); - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setcolors(gspca_dev); - setsharpness(gspca_dev); - setautogain(gspca_dev); - setexposure(gspca_dev); - setgain(gspca_dev); - usb_exchange(gspca_dev, poxxxx_init_start_3); - if (mode) - init = poxxxx_initQVGA; - else - init = poxxxx_initVGA; - usb_exchange(gspca_dev, init); - reg_r(gspca_dev, 0x8c, 0x0000, 3); - reg_w(gspca_dev, 0xa0, - gspca_dev->usb_buf[2] & 1 ? 0 : 1, - 0xb35c); - msleep(300); -/*fixme: i2c read 04 and 05*/ - init = poxxxx_init_end_1; - break; - } - usb_exchange(gspca_dev, init); - if (GammaT && MatrixT) { - put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a); - put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b); - put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c); - put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c); - - switch (sd->sensor) { - case SENSOR_PO1200: - case SENSOR_HV7131R: - reg_w(gspca_dev, 0x89, 0x0400, 0x1415); - break; - case SENSOR_MI1310_SOC: - reg_w(gspca_dev, 0x89, 0x058c, 0x0000); - break; - } - msleep(100); - sethvflip(gspca_dev); - setlightfreq(gspca_dev); - } - switch (sd->sensor) { - case SENSOR_OV7670: - reg_w(gspca_dev, 0x87, 0xffff, 0xffff); - reg_w(gspca_dev, 0x88, 0xff00, 0xf0f1); - reg_w(gspca_dev, 0xa0, 0x0000, 0xbfff); - break; - case SENSOR_POxxxx: - usb_exchange(gspca_dev, poxxxx_init_end_2); - setwb(gspca_dev); - msleep(80); /* led on */ - reg_w(gspca_dev, 0x89, 0xffff, 0xfdff); - break; - } - return gspca_dev->usb_err; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { - case SENSOR_MI1310_SOC: - reg_w(gspca_dev, 0x89, 0x058c, 0x00ff); - break; - case SENSOR_POxxxx: - return; - default: - if (!(sd->flags & FL_SAMSUNG)) - reg_w(gspca_dev, 0x89, 0xffff, 0xffff); - break; - } - reg_w(gspca_dev, 0xa0, 0x01, 0xb301); - reg_w(gspca_dev, 0xa0, 0x09, 0xb003); -} - -/* called on streamoff with alt 0 and on disconnect */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (!gspca_dev->present) - return; -/*fixme: is this useful?*/ - if (sd->sensor == SENSOR_MI1310_SOC) - reg_w(gspca_dev, 0x89, 0x058c, 0x00ff); - else if (!(sd->flags & FL_SAMSUNG)) - reg_w(gspca_dev, 0x89, 0xffff, 0xffff); - - if (sd->sensor == SENSOR_POxxxx) { - reg_w(gspca_dev, 0xa0, 0x26, 0xb300); - reg_w(gspca_dev, 0xa0, 0x04, 0xb300); - reg_w(gspca_dev, 0xa0, 0x00, 0xb300); - } -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso pkt length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (data[0] == 0xff && data[1] == 0xd8) { - PDEBUG(D_PACK, - "vc032x header packet found len %d", len); - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - data += sd->image_offset; - len -= sd->image_offset; - gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); - return; - } - - /* The vc0321 sends some additional data after sending the complete - * frame, we ignore this. */ - if (sd->bridge == BRIDGE_VC0321) { - int size, l; - - l = gspca_dev->image_len; - size = gspca_dev->frsz; - if (len > size - l) - len = size - l; - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hflip; - return 0; -} - -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->vflip; - return 0; -} - -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->lightfreq = val; - if (gspca_dev->streaming) - setlightfreq(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->lightfreq; - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - if (gspca_dev->streaming) - setautogain(gspca_dev); - - return gspca_dev->usb_err; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_setbacklight(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->backlight = val; - if (gspca_dev->streaming) - setbacklight(gspca_dev); - - return gspca_dev->usb_err; -} - -static int sd_getbacklight(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->backlight; - return 0; -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; - - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - if (menu->index >= ARRAY_SIZE(freq_nm)) - break; - strcpy((char *) menu->name, freq_nm[menu->index]); - return 0; - } - return -EINVAL; -} - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, -}; - -/* -- module initialisation -- */ -#define BF(bridge, flags) \ - .driver_info = (BRIDGE_ ## bridge << 8) \ - | (flags) -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)}, - {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)}, - {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)}, - {USB_DEVICE(0x046d, 0x0897), BF(VC0321, 0)}, - {USB_DEVICE(0x0ac8, 0x0321), BF(VC0321, 0)}, - {USB_DEVICE(0x0ac8, 0x0323), BF(VC0323, 0)}, - {USB_DEVICE(0x0ac8, 0x0328), BF(VC0321, 0)}, - {USB_DEVICE(0x0ac8, 0xc001), BF(VC0321, 0)}, - {USB_DEVICE(0x0ac8, 0xc002), BF(VC0321, 0)}, - {USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, FL_SAMSUNG)}, - {USB_DEVICE(0x15b8, 0x6001), BF(VC0323, 0)}, - {USB_DEVICE(0x15b8, 0x6002), BF(VC0323, 0)}, - {USB_DEVICE(0x17ef, 0x4802), BF(VC0323, 0)}, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/vicam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/vicam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/vicam.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/vicam.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,381 +0,0 @@ -/* - * gspca ViCam subdriver - * - * Copyright (C) 2011 Hans de Goede - * - * Based on the usbvideo vicam driver, which is: - * - * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), - * Christopher L Cheney (ccheney@cheney.cx), - * Pavel Machek (pavel@ucw.cz), - * John Tyner (jtyner@cs.ucr.edu), - * Monroe Williams (monroe@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, or - * any later version. - * - * 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 - */ - -#define MODULE_NAME "vicam" -#define HEADER_SIZE 64 - -#include -#include -#include -#include -#include "gspca.h" - -MODULE_AUTHOR("Hans de Goede "); -MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver"); -MODULE_LICENSE("GPL"); - -enum e_ctrl { - GAIN, - EXPOSURE, - NCTRL /* number of controls */ -}; - -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - struct work_struct work_struct; - struct workqueue_struct *work_thread; - struct gspca_ctrl ctrls[NCTRL]; -}; - -/* The vicam sensor has a resolution of 512 x 244, with I believe square - pixels, but this is forced to a 4:3 ratio by optics. So it has - non square pixels :( */ -static struct v4l2_pix_format vicam_mode[] = { - { 256, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, - .bytesperline = 256, - .sizeimage = 256 * 122, - .colorspace = V4L2_COLORSPACE_SRGB,}, - /* 2 modes with somewhat more square pixels */ - { 256, 200, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, - .bytesperline = 256, - .sizeimage = 256 * 200, - .colorspace = V4L2_COLORSPACE_SRGB,}, - { 256, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, - .bytesperline = 256, - .sizeimage = 256 * 240, - .colorspace = V4L2_COLORSPACE_SRGB,}, -#if 0 /* This mode has extremely non square pixels, testing use only */ - { 512, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, - .bytesperline = 512, - .sizeimage = 512 * 122, - .colorspace = V4L2_COLORSPACE_SRGB,}, -#endif - { 512, 244, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, - .bytesperline = 512, - .sizeimage = 512 * 244, - .colorspace = V4L2_COLORSPACE_SRGB,}, -}; - -static const struct ctrl sd_ctrls[] = { -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 200, - }, - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 2047, - .step = 1, - .default_value = 256, - }, - }, -}; - -static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request, - u16 value, u16 index, u8 *data, u16 len) -{ - int ret; - - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, data, len, 1000); - if (ret < 0) - err("control msg req %02X error %d", request, ret); - - return ret; -} - -static int vicam_set_camera_power(struct gspca_dev *gspca_dev, int state) -{ - int ret; - - ret = vicam_control_msg(gspca_dev, 0x50, state, 0, NULL, 0); - if (ret < 0) - return ret; - - if (state) - ret = vicam_control_msg(gspca_dev, 0x55, 1, 0, NULL, 0); - - return ret; -} - -/* - * request and read a block of data - see warning on vicam_command. - */ -static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size) -{ - struct sd *sd = (struct sd *)gspca_dev; - int ret, unscaled_height, act_len = 0; - u8 *req_data = gspca_dev->usb_buf; - - memset(req_data, 0, 16); - req_data[0] = sd->ctrls[GAIN].val; - if (gspca_dev->width == 256) - req_data[1] |= 0x01; /* low nibble x-scale */ - if (gspca_dev->height <= 122) { - req_data[1] |= 0x10; /* high nibble y-scale */ - unscaled_height = gspca_dev->height * 2; - } else - unscaled_height = gspca_dev->height; - req_data[2] = 0x90; /* unknown, does not seem to do anything */ - if (unscaled_height <= 200) - req_data[3] = 0x06; /* vend? */ - else if (unscaled_height <= 242) /* Yes 242 not 240 */ - req_data[3] = 0x07; /* vend? */ - else /* Up to 244 lines with req_data[3] == 0x08 */ - req_data[3] = 0x08; /* vend? */ - - if (sd->ctrls[EXPOSURE].val < 256) { - /* Frame rate maxed out, use partial frame expo time */ - req_data[4] = 255 - sd->ctrls[EXPOSURE].val; - req_data[5] = 0x00; - req_data[6] = 0x00; - req_data[7] = 0x01; - } else { - /* Modify frame rate */ - req_data[4] = 0x00; - req_data[5] = 0x00; - req_data[6] = sd->ctrls[EXPOSURE].val & 0xFF; - req_data[7] = sd->ctrls[EXPOSURE].val >> 8; - } - req_data[8] = ((244 - unscaled_height) / 2) & ~0x01; /* vstart */ - /* bytes 9-15 do not seem to affect exposure or image quality */ - - mutex_lock(&gspca_dev->usb_lock); - ret = vicam_control_msg(gspca_dev, 0x51, 0x80, 0, req_data, 16); - mutex_unlock(&gspca_dev->usb_lock); - if (ret < 0) - return ret; - - ret = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 0x81), - data, size, &act_len, 10000); - /* successful, it returns 0, otherwise negative */ - if (ret < 0 || act_len != size) { - err("bulk read fail (%d) len %d/%d", - ret, act_len, size); - return -EIO; - } - return 0; -} - -/* This function is called as a workqueue function and runs whenever the camera - * is streaming data. Because it is a workqueue function it is allowed to sleep - * so we can use synchronous USB calls. To avoid possible collisions with other - * threads attempting to use the camera's USB interface we take the gspca - * usb_lock when performing USB operations. In practice the only thing we need - * to protect against is the usb_set_interface call that gspca makes during - * stream_off as the camera doesn't provide any controls that the user could try - * to change. - */ -static void vicam_dostream(struct work_struct *work) -{ - struct sd *sd = container_of(work, struct sd, work_struct); - struct gspca_dev *gspca_dev = &sd->gspca_dev; - int ret, frame_sz; - u8 *buffer; - - frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage + - HEADER_SIZE; - buffer = kmalloc(frame_sz, GFP_KERNEL | GFP_DMA); - if (!buffer) { - err("Couldn't allocate USB buffer"); - goto exit; - } - - while (gspca_dev->present && gspca_dev->streaming) { - ret = vicam_read_frame(gspca_dev, buffer, frame_sz); - if (ret < 0) - break; - - /* Note the frame header contents seem to be completely - constant, they do not change with either image, or - settings. So we simply discard it. The frames have - a very similar 64 byte footer, which we don't even - bother reading from the cam */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - buffer + HEADER_SIZE, - frame_sz - HEADER_SIZE); - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - } -exit: - kfree(buffer); -} - -/* This function is called at probe time just before sd_init */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct cam *cam = &gspca_dev->cam; - struct sd *sd = (struct sd *)gspca_dev; - - /* We don't use the buffer gspca allocates so make it small. */ - cam->bulk = 1; - cam->bulk_size = 64; - cam->cam_mode = vicam_mode; - cam->nmodes = ARRAY_SIZE(vicam_mode); - cam->ctrls = sd->ctrls; - - INIT_WORK(&sd->work_struct, vicam_dostream); - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - int ret; - const struct ihex_binrec *rec; - const struct firmware *uninitialized_var(fw); - u8 *firmware_buf; - - ret = request_ihex_firmware(&fw, "vicam/firmware.fw", - &gspca_dev->dev->dev); - if (ret) { - err("Failed to load \"vicam/firmware.fw\": %d\n", ret); - return ret; - } - - firmware_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!firmware_buf) { - ret = -ENOMEM; - goto exit; - } - for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { - memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len)); - ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf, - be16_to_cpu(rec->len)); - if (ret < 0) - break; - } - - kfree(firmware_buf); -exit: - release_firmware(fw); - return ret; -} - -/* Set up for getting frames. */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *)gspca_dev; - int ret; - - ret = vicam_set_camera_power(gspca_dev, 1); - if (ret < 0) - return ret; - - /* Start the workqueue function to do the streaming */ - sd->work_thread = create_singlethread_workqueue(MODULE_NAME); - queue_work(sd->work_thread, &sd->work_struct); - - return 0; -} - -/* called on streamoff with alt==0 and on disconnect */ -/* the usb_lock is held at entry - restore on exit */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *dev = (struct sd *)gspca_dev; - - /* wait for the work queue to terminate */ - mutex_unlock(&gspca_dev->usb_lock); - /* This waits for vicam_dostream to finish */ - destroy_workqueue(dev->work_thread); - dev->work_thread = NULL; - mutex_lock(&gspca_dev->usb_lock); - - vicam_set_camera_power(gspca_dev, 0); -} - -/* Table of supported USB devices */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x04c1, 0x009d)}, - {USB_DEVICE(0x0602, 0x1001)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stop0 = sd_stop0, -}; - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, - &sd_desc, - sizeof(struct sd), - THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/w996Xcf.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/w996Xcf.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/w996Xcf.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/w996Xcf.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,558 +0,0 @@ -/** - * - * GSPCA sub driver for W996[78]CF JPEG USB Dual Mode Camera Chip. - * - * Copyright (C) 2009 Hans de Goede - * - * This module is adapted from the in kernel v4l1 w9968cf driver: - * - * Copyright (C) 2002-2004 by Luca Risolia - * - * 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, or - * any later version. - * - * 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 - * - */ - -/* Note this is not a stand alone driver, it gets included in ov519.c, this - is a bit of a hack, but it needs the driver code for a lot of different - ov sensors which is already present in ov519.c (the old v4l1 driver used - the ovchipcam framework). When we have the time we really should move - the sensor drivers to v4l2 sub drivers, and properly split of this - driver from ov519.c */ - -#define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ - -#define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET]) -#define UV_QUANTABLE (&sd->jpeg_hdr[JPEG_QT1_OFFSET]) - -static const struct v4l2_pix_format w9968cf_vga_mode[] = { - {160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, - .bytesperline = 160 * 2, - .sizeimage = 160 * 120 * 2, - .colorspace = V4L2_COLORSPACE_JPEG}, - {176, 144, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, - .bytesperline = 176 * 2, - .sizeimage = 176 * 144 * 2, - .colorspace = V4L2_COLORSPACE_JPEG}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320 * 2, - .sizeimage = 320 * 240 * 2, - .colorspace = V4L2_COLORSPACE_JPEG}, - {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 352 * 2, - .sizeimage = 352 * 288 * 2, - .colorspace = V4L2_COLORSPACE_JPEG}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640 * 2, - .sizeimage = 640 * 480 * 2, - .colorspace = V4L2_COLORSPACE_JPEG}, -}; - -static void reg_w(struct sd *sd, u16 index, u16 value); - -/*-------------------------------------------------------------------------- - Write 64-bit data to the fast serial bus registers. - Return 0 on success, -1 otherwise. - --------------------------------------------------------------------------*/ -static void w9968cf_write_fsb(struct sd *sd, u16* data) -{ - struct usb_device *udev = sd->gspca_dev.dev; - u16 value; - int ret; - - if (sd->gspca_dev.usb_err < 0) - return; - - value = *data++; - memcpy(sd->gspca_dev.usb_buf, data, 6); - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - value, 0x06, sd->gspca_dev.usb_buf, 6, 500); - if (ret < 0) { - err("Write FSB registers failed (%d)", ret); - sd->gspca_dev.usb_err = ret; - } -} - -/*-------------------------------------------------------------------------- - Write data to the serial bus control register. - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static void w9968cf_write_sb(struct sd *sd, u16 value) -{ - int ret; - - if (sd->gspca_dev.usb_err < 0) - return; - - /* We don't use reg_w here, as that would cause all writes when - bitbanging i2c to be logged, making the logs impossible to read */ - ret = usb_control_msg(sd->gspca_dev.dev, - usb_sndctrlpipe(sd->gspca_dev.dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, 0x01, NULL, 0, 500); - - udelay(W9968CF_I2C_BUS_DELAY); - - if (ret < 0) { - err("Write SB reg [01] %04x failed", value); - sd->gspca_dev.usb_err = ret; - } -} - -/*-------------------------------------------------------------------------- - Read data from the serial bus control register. - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_read_sb(struct sd *sd) -{ - int ret; - - if (sd->gspca_dev.usb_err < 0) - return -1; - - /* We don't use reg_r here, as the w9968cf is special and has 16 - bit registers instead of 8 bit */ - ret = usb_control_msg(sd->gspca_dev.dev, - usb_rcvctrlpipe(sd->gspca_dev.dev, 0), - 1, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, 0x01, sd->gspca_dev.usb_buf, 2, 500); - if (ret >= 0) { - ret = sd->gspca_dev.usb_buf[0] | - (sd->gspca_dev.usb_buf[1] << 8); - } else { - err("Read SB reg [01] failed"); - sd->gspca_dev.usb_err = ret; - } - - udelay(W9968CF_I2C_BUS_DELAY); - - return ret; -} - -/*-------------------------------------------------------------------------- - Upload quantization tables for the JPEG compression. - This function is called by w9968cf_start_transfer(). - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static void w9968cf_upload_quantizationtables(struct sd *sd) -{ - u16 a, b; - int i, j; - - reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */ - - for (i = 0, j = 0; i < 32; i++, j += 2) { - a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j + 1]) << 8); - b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j + 1]) << 8); - reg_w(sd, 0x40 + i, a); - reg_w(sd, 0x60 + i, b); - } - reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */ -} - -/**************************************************************************** - * Low-level I2C I/O functions. * - * The adapter supports the following I2C transfer functions: * - * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) * - * i2c_adap_read_byte_data() * - * i2c_adap_read_byte() * - ****************************************************************************/ - -static void w9968cf_smbus_start(struct sd *sd) -{ - w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */ - w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */ -} - -static void w9968cf_smbus_stop(struct sd *sd) -{ - w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */ - w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */ - w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */ -} - -static void w9968cf_smbus_write_byte(struct sd *sd, u8 v) -{ - u8 bit; - int sda; - - for (bit = 0 ; bit < 8 ; bit++) { - sda = (v & 0x80) ? 2 : 0; - v <<= 1; - /* SDE=1, SDA=sda, SCL=0 */ - w9968cf_write_sb(sd, 0x10 | sda); - /* SDE=1, SDA=sda, SCL=1 */ - w9968cf_write_sb(sd, 0x11 | sda); - /* SDE=1, SDA=sda, SCL=0 */ - w9968cf_write_sb(sd, 0x10 | sda); - } -} - -static void w9968cf_smbus_read_byte(struct sd *sd, u8 *v) -{ - u8 bit; - - /* No need to ensure SDA is high as we are always called after - read_ack which ends with SDA high */ - *v = 0; - for (bit = 0 ; bit < 8 ; bit++) { - *v <<= 1; - /* SDE=1, SDA=1, SCL=1 */ - w9968cf_write_sb(sd, 0x0013); - *v |= (w9968cf_read_sb(sd) & 0x0008) ? 1 : 0; - /* SDE=1, SDA=1, SCL=0 */ - w9968cf_write_sb(sd, 0x0012); - } -} - -static void w9968cf_smbus_write_nack(struct sd *sd) -{ - /* No need to ensure SDA is high as we are always called after - read_byte which ends with SDA high */ - w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */ - w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */ -} - -static void w9968cf_smbus_read_ack(struct sd *sd) -{ - int sda; - - /* Ensure SDA is high before raising clock to avoid a spurious stop */ - w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */ - w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */ - sda = w9968cf_read_sb(sd); - w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */ - if (sda >= 0 && (sda & 0x08)) { - PDEBUG(D_USBI, "Did not receive i2c ACK"); - sd->gspca_dev.usb_err = -EIO; - } -} - -/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ -static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value) -{ - u16* data = (u16 *)sd->gspca_dev.usb_buf; - - data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0); - data[0] |= (sd->sensor_addr & 0x40) ? 0x4000 : 0x0; - data[1] = 0x2082 | ((sd->sensor_addr & 0x40) ? 0x0005 : 0x0); - data[1] |= (sd->sensor_addr & 0x20) ? 0x0150 : 0x0; - data[1] |= (sd->sensor_addr & 0x10) ? 0x5400 : 0x0; - data[2] = 0x8208 | ((sd->sensor_addr & 0x08) ? 0x0015 : 0x0); - data[2] |= (sd->sensor_addr & 0x04) ? 0x0540 : 0x0; - data[2] |= (sd->sensor_addr & 0x02) ? 0x5000 : 0x0; - data[3] = 0x1d20 | ((sd->sensor_addr & 0x02) ? 0x0001 : 0x0); - data[3] |= (sd->sensor_addr & 0x01) ? 0x0054 : 0x0; - - w9968cf_write_fsb(sd, data); - - data[0] = 0x8208 | ((reg & 0x80) ? 0x0015 : 0x0); - data[0] |= (reg & 0x40) ? 0x0540 : 0x0; - data[0] |= (reg & 0x20) ? 0x5000 : 0x0; - data[1] = 0x0820 | ((reg & 0x20) ? 0x0001 : 0x0); - data[1] |= (reg & 0x10) ? 0x0054 : 0x0; - data[1] |= (reg & 0x08) ? 0x1500 : 0x0; - data[1] |= (reg & 0x04) ? 0x4000 : 0x0; - data[2] = 0x2082 | ((reg & 0x04) ? 0x0005 : 0x0); - data[2] |= (reg & 0x02) ? 0x0150 : 0x0; - data[2] |= (reg & 0x01) ? 0x5400 : 0x0; - data[3] = 0x001d; - - w9968cf_write_fsb(sd, data); - - data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); - data[0] |= (value & 0x40) ? 0x0540 : 0x0; - data[0] |= (value & 0x20) ? 0x5000 : 0x0; - data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0); - data[1] |= (value & 0x10) ? 0x0054 : 0x0; - data[1] |= (value & 0x08) ? 0x1500 : 0x0; - data[1] |= (value & 0x04) ? 0x4000 : 0x0; - data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0); - data[2] |= (value & 0x02) ? 0x0150 : 0x0; - data[2] |= (value & 0x01) ? 0x5400 : 0x0; - data[3] = 0xfe1d; - - w9968cf_write_fsb(sd, data); - - PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg); -} - -/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ -static int w9968cf_i2c_r(struct sd *sd, u8 reg) -{ - int ret = 0; - u8 value; - - /* Fast serial bus data control disable */ - w9968cf_write_sb(sd, 0x0013); /* don't change ! */ - - w9968cf_smbus_start(sd); - w9968cf_smbus_write_byte(sd, sd->sensor_addr); - w9968cf_smbus_read_ack(sd); - w9968cf_smbus_write_byte(sd, reg); - w9968cf_smbus_read_ack(sd); - w9968cf_smbus_stop(sd); - w9968cf_smbus_start(sd); - w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1); - w9968cf_smbus_read_ack(sd); - w9968cf_smbus_read_byte(sd, &value); - /* signal we don't want to read anymore, the v4l1 driver used to - send an ack here which is very wrong! (and then fixed - the issues this gave by retrying reads) */ - w9968cf_smbus_write_nack(sd); - w9968cf_smbus_stop(sd); - - /* Fast serial bus data control re-enable */ - w9968cf_write_sb(sd, 0x0030); - - if (sd->gspca_dev.usb_err >= 0) { - ret = value; - PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value); - } else - PDEBUG(D_ERR, "i2c read [0x%02x] failed", reg); - - return ret; -} - -/*-------------------------------------------------------------------------- - Turn on the LED on some webcams. A beep should be heard too. - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static void w9968cf_configure(struct sd *sd) -{ - reg_w(sd, 0x00, 0xff00); /* power-down */ - reg_w(sd, 0x00, 0xbf17); /* reset everything */ - reg_w(sd, 0x00, 0xbf10); /* normal operation */ - reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */ - reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */ - reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */ - reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */ - - sd->stopped = 1; -} - -static void w9968cf_init(struct sd *sd) -{ - unsigned long hw_bufsize = sd->sif ? (352 * 288 * 2) : (640 * 480 * 2), - y0 = 0x0000, - u0 = y0 + hw_bufsize / 2, - v0 = u0 + hw_bufsize / 4, - y1 = v0 + hw_bufsize / 4, - u1 = y1 + hw_bufsize / 2, - v1 = u1 + hw_bufsize / 4; - - reg_w(sd, 0x00, 0xff00); /* power off */ - reg_w(sd, 0x00, 0xbf10); /* power on */ - - reg_w(sd, 0x03, 0x405d); /* DRAM timings */ - reg_w(sd, 0x04, 0x0030); /* SDRAM timings */ - - reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */ - reg_w(sd, 0x21, y0 >> 16); /* Y buf.0, high */ - reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */ - reg_w(sd, 0x25, u0 >> 16); /* U buf.0, high */ - reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */ - reg_w(sd, 0x29, v0 >> 16); /* V buf.0, high */ - - reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */ - reg_w(sd, 0x23, y1 >> 16); /* Y buf.1, high */ - reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */ - reg_w(sd, 0x27, u1 >> 16); /* U buf.1, high */ - reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */ - reg_w(sd, 0x2b, v1 >> 16); /* V buf.1, high */ - - reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */ - reg_w(sd, 0x33, y1 >> 16); /* JPEG buf 0 high */ - - reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */ - reg_w(sd, 0x35, y1 >> 16); /* JPEG bug 1 high */ - - reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */ - reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/ - reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */ - reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */ -} - -static void w9968cf_set_crop_window(struct sd *sd) -{ - int start_cropx, start_cropy, x, y, fw, fh, cw, ch, - max_width, max_height; - - if (sd->sif) { - max_width = 352; - max_height = 288; - } else { - max_width = 640; - max_height = 480; - } - - if (sd->sensor == SEN_OV7620) { - /* Sigh, this is dependend on the clock / framerate changes - made by the frequency control, sick. */ - if (sd->ctrls[FREQ].val == 1) { - start_cropx = 277; - start_cropy = 37; - } else { - start_cropx = 105; - start_cropy = 37; - } - } else { - start_cropx = 320; - start_cropy = 35; - } - - /* Work around to avoid FP arithmetics */ - #define SC(x) ((x) << 10) - - /* Scaling factors */ - fw = SC(sd->gspca_dev.width) / max_width; - fh = SC(sd->gspca_dev.height) / max_height; - - cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width) / fh; - ch = (fw >= fh) ? SC(sd->gspca_dev.height) / fw : max_height; - - sd->sensor_width = max_width; - sd->sensor_height = max_height; - - x = (max_width - cw) / 2; - y = (max_height - ch) / 2; - - reg_w(sd, 0x10, start_cropx + x); - reg_w(sd, 0x11, start_cropy + y); - reg_w(sd, 0x12, start_cropx + x + cw); - reg_w(sd, 0x13, start_cropy + y + ch); -} - -static void w9968cf_mode_init_regs(struct sd *sd) -{ - int val, vs_polarity, hs_polarity; - - w9968cf_set_crop_window(sd); - - reg_w(sd, 0x14, sd->gspca_dev.width); - reg_w(sd, 0x15, sd->gspca_dev.height); - - /* JPEG width & height */ - reg_w(sd, 0x30, sd->gspca_dev.width); - reg_w(sd, 0x31, sd->gspca_dev.height); - - /* Y & UV frame buffer strides (in WORD) */ - if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == - V4L2_PIX_FMT_JPEG) { - reg_w(sd, 0x2c, sd->gspca_dev.width / 2); - reg_w(sd, 0x2d, sd->gspca_dev.width / 4); - } else - reg_w(sd, 0x2c, sd->gspca_dev.width); - - reg_w(sd, 0x00, 0xbf17); /* reset everything */ - reg_w(sd, 0x00, 0xbf10); /* normal operation */ - - /* Transfer size in WORDS (for UYVY format only) */ - val = sd->gspca_dev.width * sd->gspca_dev.height; - reg_w(sd, 0x3d, val & 0xffff); /* low bits */ - reg_w(sd, 0x3e, val >> 16); /* high bits */ - - if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == - V4L2_PIX_FMT_JPEG) { - /* We may get called multiple times (usb isoc bw negotiat.) */ - jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height, - sd->gspca_dev.width, 0x22); /* JPEG 420 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - w9968cf_upload_quantizationtables(sd); - } - - /* Video Capture Control Register */ - if (sd->sensor == SEN_OV7620) { - /* Seems to work around a bug in the image sensor */ - vs_polarity = 1; - hs_polarity = 1; - } else { - vs_polarity = 1; - hs_polarity = 0; - } - - val = (vs_polarity << 12) | (hs_polarity << 11); - - /* NOTE: We may not have enough memory to do double buffering while - doing compression (amount of memory differs per model cam). - So we use the second image buffer also as jpeg stream buffer - (see w9968cf_init), and disable double buffering. */ - if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == - V4L2_PIX_FMT_JPEG) { - /* val |= 0x0002; YUV422P */ - val |= 0x0003; /* YUV420P */ - } else - val |= 0x0080; /* Enable HW double buffering */ - - /* val |= 0x0020; enable clamping */ - /* val |= 0x0008; enable (1-2-1) filter */ - /* val |= 0x000c; enable (2-3-6-3-2) filter */ - - val |= 0x8000; /* capt. enable */ - - reg_w(sd, 0x16, val); - - sd->gspca_dev.empty_packet = 0; -} - -static void w9968cf_stop0(struct sd *sd) -{ - reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */ - reg_w(sd, 0x16, 0x0000); /* stop video capture */ -} - -/* The w9968cf docs say that a 0 sized packet means EOF (and also SOF - for the next frame). This seems to simply not be true when operating - in JPEG mode, in this case there may be empty packets within the - frame. So in JPEG mode use the JPEG SOI marker to detect SOF. - - Note to make things even more interesting the w9968cf sends *PLANAR* jpeg, - to be precise it sends: SOI, SOF, DRI, SOS, Y-data, SOS, U-data, SOS, - V-data, EOI. */ -static void w9968cf_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (w9968cf_vga_mode[gspca_dev->curr_mode].pixelformat == - V4L2_PIX_FMT_JPEG) { - if (len >= 2 && - data[0] == 0xff && - data[1] == 0xd8) { - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - /* Strip the ff d8, our own header (which adds - huffman and quantization tables) already has this */ - len -= 2; - data += 2; - } - } else { - /* In UYVY mode an empty packet signals EOF */ - if (gspca_dev->empty_packet) { - gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); - gspca_frame_add(gspca_dev, FIRST_PACKET, - NULL, 0); - gspca_dev->empty_packet = 0; - } - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/xirlink_cit.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/xirlink_cit.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/xirlink_cit.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/xirlink_cit.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3337 +0,0 @@ -/* - * USB IBM C-It Video Camera driver - * - * Supports Xirlink C-It Video Camera, IBM PC Camera, - * IBM NetCamera and Veo Stingray. - * - * Copyright (C) 2010 Hans de Goede - * - * This driver is based on earlier work of: - * - * (C) Copyright 1999 Johannes Erdfelt - * (C) Copyright 1999 Randy Dunlap - * - * 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, or - * (at your option) any later version. - * - * 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 - * - */ - -#define MODULE_NAME "xirlink-cit" - -#include -#include "gspca.h" - -MODULE_AUTHOR("Hans de Goede "); -MODULE_DESCRIPTION("Xirlink C-IT"); -MODULE_LICENSE("GPL"); - -/* FIXME we should autodetect this */ -static int ibm_netcam_pro; -module_param(ibm_netcam_pro, int, 0); -MODULE_PARM_DESC(ibm_netcam_pro, - "Use IBM Netcamera Pro init sequences for Model 3 cams"); - -/* FIXME this should be handled through the V4L2 input selection API */ -static int rca_input; -module_param(rca_input, int, 0644); -MODULE_PARM_DESC(rca_input, - "Use rca input instead of ccd sensor on Model 3 cams"); - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - u8 model; -#define CIT_MODEL0 0 /* bcd version 0.01 cams ie the xvp-500 */ -#define CIT_MODEL1 1 /* The model 1 - 4 nomenclature comes from the old */ -#define CIT_MODEL2 2 /* ibmcam driver */ -#define CIT_MODEL3 3 -#define CIT_MODEL4 4 -#define CIT_IBM_NETCAM_PRO 5 - u8 input_index; - u8 button_state; - u8 stop_on_control_change; - u8 sof_read; - u8 sof_len; - u8 contrast; - u8 brightness; - u8 hue; - u8 sharpness; - u8 lighting; - u8 hflip; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setlighting(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getlighting(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); -static void sd_stop0(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 63, - .step = 1, -#define BRIGHTNESS_DEFAULT 32 - .default_value = BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "contrast", - .minimum = 0, - .maximum = 20, - .step = 1, -#define CONTRAST_DEFAULT 10 - .default_value = CONTRAST_DEFAULT, - .flags = 0, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SD_HUE 2 - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = 127, - .step = 1, -#define HUE_DEFAULT 63 - .default_value = HUE_DEFAULT, - .flags = 0, - }, - .set = sd_sethue, - .get = sd_gethue, - }, -#define SD_SHARPNESS 3 - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 6, - .step = 1, -#define SHARPNESS_DEFAULT 3 - .default_value = SHARPNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, -#define SD_LIGHTING 4 - { - { - .id = V4L2_CID_BACKLIGHT_COMPENSATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Lighting", - .minimum = 0, - .maximum = 2, - .step = 1, -#define LIGHTING_DEFAULT 1 - .default_value = LIGHTING_DEFAULT, - .flags = 0, - }, - .set = sd_setlighting, - .get = sd_getlighting, - }, -#define SD_HFLIP 5 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, -#define HFLIP_DEFAULT 0 - .default_value = HFLIP_DEFAULT, - }, - .set = sd_sethflip, - .get = sd_gethflip, - }, -}; - -static const struct v4l2_pix_format cif_yuv_mode[] = { - {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, - {352, 288, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, -}; - -static const struct v4l2_pix_format vga_yuv_mode[] = { - {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, - {320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, - {640, 480, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, -}; - -static const struct v4l2_pix_format model0_mode[] = { - {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, - {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, - {320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, -}; - -static const struct v4l2_pix_format model2_mode[] = { - {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, - {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 2 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, - {320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, - {352, 288, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 + 4, - .colorspace = V4L2_COLORSPACE_SRGB}, -}; - -/* - * 01.01.08 - Added for RCA video in support -LO - * This struct is used to init the Model3 cam to use the RCA video in port - * instead of the CCD sensor. - */ -static const u16 rca_initdata[][3] = { - {0, 0x0000, 0x010c}, - {0, 0x0006, 0x012c}, - {0, 0x0078, 0x012d}, - {0, 0x0046, 0x012f}, - {0, 0xd141, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfea8, 0x0124}, - {1, 0x0000, 0x0116}, - {0, 0x0064, 0x0116}, - {1, 0x0000, 0x0115}, - {0, 0x0003, 0x0115}, - {0, 0x0008, 0x0123}, - {0, 0x0000, 0x0117}, - {0, 0x0000, 0x0112}, - {0, 0x0080, 0x0100}, - {0, 0x0000, 0x0100}, - {1, 0x0000, 0x0116}, - {0, 0x0060, 0x0116}, - {0, 0x0002, 0x0112}, - {0, 0x0000, 0x0123}, - {0, 0x0001, 0x0117}, - {0, 0x0040, 0x0108}, - {0, 0x0019, 0x012c}, - {0, 0x0040, 0x0116}, - {0, 0x000a, 0x0115}, - {0, 0x000b, 0x0115}, - {0, 0x0078, 0x012d}, - {0, 0x0046, 0x012f}, - {0, 0xd141, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfea8, 0x0124}, - {0, 0x0064, 0x0116}, - {0, 0x0000, 0x0115}, - {0, 0x0001, 0x0115}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00aa, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00f2, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x000f, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00f8, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00fc, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00f9, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x003c, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0027, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0019, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0021, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0006, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0045, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002a, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x000e, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002b, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00f4, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002c, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0004, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002d, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0014, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002e, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0003, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002f, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0003, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0014, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0053, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0x0000, 0x0101}, - {0, 0x00a0, 0x0103}, - {0, 0x0078, 0x0105}, - {0, 0x0000, 0x010a}, - {0, 0x0024, 0x010b}, - {0, 0x0028, 0x0119}, - {0, 0x0088, 0x011b}, - {0, 0x0002, 0x011d}, - {0, 0x0003, 0x011e}, - {0, 0x0000, 0x0129}, - {0, 0x00fc, 0x012b}, - {0, 0x0008, 0x0102}, - {0, 0x0000, 0x0104}, - {0, 0x0008, 0x011a}, - {0, 0x0028, 0x011c}, - {0, 0x0021, 0x012a}, - {0, 0x0000, 0x0118}, - {0, 0x0000, 0x0132}, - {0, 0x0000, 0x0109}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0031, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00dc, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0032, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0020, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0030, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0008, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0x0003, 0x0111}, -}; - -/* TESTME the old ibmcam driver repeats certain commands to Model1 cameras, we - do the same for now (testing needed to see if this is really necessary) */ -static const int cit_model1_ntries = 5; -static const int cit_model1_ntries2 = 2; - -static int cit_write_reg(struct gspca_dev *gspca_dev, u16 value, u16 index) -{ - struct usb_device *udev = gspca_dev->dev; - int err; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, - value, index, NULL, 0, 1000); - if (err < 0) - err("Failed to write a register (index 0x%04X," - " value 0x%02X, error %d)", index, value, err); - - return 0; -} - -static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index, int verbose) -{ - struct usb_device *udev = gspca_dev->dev; - __u8 *buf = gspca_dev->usb_buf; - int res; - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x01, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, - 0x00, index, buf, 8, 1000); - if (res < 0) { - err("Failed to read a register (index 0x%04X, error %d)", - index, res); - return res; - } - - if (verbose) - PDEBUG(D_PROBE, "Register %04x value: %02x", index, buf[0]); - - return 0; -} - -/* - * cit_send_FF_04_02() - * - * This procedure sends magic 3-command prefix to the camera. - * The purpose of this prefix is not known. - * - * History: - * 1/2/00 Created. - */ -static void cit_send_FF_04_02(struct gspca_dev *gspca_dev) -{ - cit_write_reg(gspca_dev, 0x00FF, 0x0127); - cit_write_reg(gspca_dev, 0x0004, 0x0124); - cit_write_reg(gspca_dev, 0x0002, 0x0124); -} - -static void cit_send_00_04_06(struct gspca_dev *gspca_dev) -{ - cit_write_reg(gspca_dev, 0x0000, 0x0127); - cit_write_reg(gspca_dev, 0x0004, 0x0124); - cit_write_reg(gspca_dev, 0x0006, 0x0124); -} - -static void cit_send_x_00(struct gspca_dev *gspca_dev, unsigned short x) -{ - cit_write_reg(gspca_dev, x, 0x0127); - cit_write_reg(gspca_dev, 0x0000, 0x0124); -} - -static void cit_send_x_00_05(struct gspca_dev *gspca_dev, unsigned short x) -{ - cit_send_x_00(gspca_dev, x); - cit_write_reg(gspca_dev, 0x0005, 0x0124); -} - -static void cit_send_x_00_05_02(struct gspca_dev *gspca_dev, unsigned short x) -{ - cit_write_reg(gspca_dev, x, 0x0127); - cit_write_reg(gspca_dev, 0x0000, 0x0124); - cit_write_reg(gspca_dev, 0x0005, 0x0124); - cit_write_reg(gspca_dev, 0x0002, 0x0124); -} - -static void cit_send_x_01_00_05(struct gspca_dev *gspca_dev, u16 x) -{ - cit_write_reg(gspca_dev, x, 0x0127); - cit_write_reg(gspca_dev, 0x0001, 0x0124); - cit_write_reg(gspca_dev, 0x0000, 0x0124); - cit_write_reg(gspca_dev, 0x0005, 0x0124); -} - -static void cit_send_x_00_05_02_01(struct gspca_dev *gspca_dev, u16 x) -{ - cit_write_reg(gspca_dev, x, 0x0127); - cit_write_reg(gspca_dev, 0x0000, 0x0124); - cit_write_reg(gspca_dev, 0x0005, 0x0124); - cit_write_reg(gspca_dev, 0x0002, 0x0124); - cit_write_reg(gspca_dev, 0x0001, 0x0124); -} - -static void cit_send_x_00_05_02_08_01(struct gspca_dev *gspca_dev, u16 x) -{ - cit_write_reg(gspca_dev, x, 0x0127); - cit_write_reg(gspca_dev, 0x0000, 0x0124); - cit_write_reg(gspca_dev, 0x0005, 0x0124); - cit_write_reg(gspca_dev, 0x0002, 0x0124); - cit_write_reg(gspca_dev, 0x0008, 0x0124); - cit_write_reg(gspca_dev, 0x0001, 0x0124); -} - -static void cit_Packet_Format1(struct gspca_dev *gspca_dev, u16 fkey, u16 val) -{ - cit_send_x_01_00_05(gspca_dev, 0x0088); - cit_send_x_00_05(gspca_dev, fkey); - cit_send_x_00_05_02_08_01(gspca_dev, val); - cit_send_x_00_05(gspca_dev, 0x0088); - cit_send_x_00_05_02_01(gspca_dev, fkey); - cit_send_x_00_05(gspca_dev, 0x0089); - cit_send_x_00(gspca_dev, fkey); - cit_send_00_04_06(gspca_dev); - cit_read_reg(gspca_dev, 0x0126, 0); - cit_send_FF_04_02(gspca_dev); -} - -static void cit_PacketFormat2(struct gspca_dev *gspca_dev, u16 fkey, u16 val) -{ - cit_send_x_01_00_05(gspca_dev, 0x0088); - cit_send_x_00_05(gspca_dev, fkey); - cit_send_x_00_05_02(gspca_dev, val); -} - -static void cit_model2_Packet2(struct gspca_dev *gspca_dev) -{ - cit_write_reg(gspca_dev, 0x00ff, 0x012d); - cit_write_reg(gspca_dev, 0xfea3, 0x0124); -} - -static void cit_model2_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2) -{ - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x00ff, 0x012e); - cit_write_reg(gspca_dev, v1, 0x012f); - cit_write_reg(gspca_dev, 0x00ff, 0x0130); - cit_write_reg(gspca_dev, 0xc719, 0x0124); - cit_write_reg(gspca_dev, v2, 0x0127); - - cit_model2_Packet2(gspca_dev); -} - -/* - * cit_model3_Packet1() - * - * 00_0078_012d - * 00_0097_012f - * 00_d141_0124 - * 00_0096_0127 - * 00_fea8_0124 -*/ -static void cit_model3_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2) -{ - cit_write_reg(gspca_dev, 0x0078, 0x012d); - cit_write_reg(gspca_dev, v1, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, v2, 0x0127); - cit_write_reg(gspca_dev, 0xfea8, 0x0124); -} - -static void cit_model4_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2) -{ - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, v1, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, v2, 0x0127); - cit_write_reg(gspca_dev, 0xfea8, 0x0124); -} - -static void cit_model4_BrightnessPacket(struct gspca_dev *gspca_dev, u16 val) -{ - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0026, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, val, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0038, 0x012d); - cit_write_reg(gspca_dev, 0x0004, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0xfffa, 0x0124); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - sd->model = id->driver_info; - if (sd->model == CIT_MODEL3 && ibm_netcam_pro) - sd->model = CIT_IBM_NETCAM_PRO; - - cam = &gspca_dev->cam; - switch (sd->model) { - case CIT_MODEL0: - cam->cam_mode = model0_mode; - cam->nmodes = ARRAY_SIZE(model0_mode); - cam->reverse_alts = 1; - gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP)); - sd->sof_len = 4; - break; - case CIT_MODEL1: - cam->cam_mode = cif_yuv_mode; - cam->nmodes = ARRAY_SIZE(cif_yuv_mode); - cam->reverse_alts = 1; - gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP); - sd->sof_len = 4; - break; - case CIT_MODEL2: - cam->cam_mode = model2_mode + 1; /* no 160x120 */ - cam->nmodes = 3; - gspca_dev->ctrl_dis = (1 << SD_CONTRAST) | - (1 << SD_SHARPNESS) | - (1 << SD_HFLIP); - break; - case CIT_MODEL3: - cam->cam_mode = vga_yuv_mode; - cam->nmodes = ARRAY_SIZE(vga_yuv_mode); - gspca_dev->ctrl_dis = (1 << SD_HUE) | - (1 << SD_LIGHTING) | - (1 << SD_HFLIP); - sd->stop_on_control_change = 1; - sd->sof_len = 4; - break; - case CIT_MODEL4: - cam->cam_mode = model2_mode; - cam->nmodes = ARRAY_SIZE(model2_mode); - gspca_dev->ctrl_dis = (1 << SD_CONTRAST) | - (1 << SD_SHARPNESS) | - (1 << SD_LIGHTING) | - (1 << SD_HFLIP); - break; - case CIT_IBM_NETCAM_PRO: - cam->cam_mode = vga_yuv_mode; - cam->nmodes = 2; /* no 640 x 480 */ - cam->input_flags = V4L2_IN_ST_VFLIP; - gspca_dev->ctrl_dis = ~(1 << SD_CONTRAST); - sd->stop_on_control_change = 1; - sd->sof_len = 4; - break; - } - - sd->brightness = BRIGHTNESS_DEFAULT; - sd->contrast = CONTRAST_DEFAULT; - sd->hue = HUE_DEFAULT; - sd->sharpness = SHARPNESS_DEFAULT; - sd->lighting = LIGHTING_DEFAULT; - sd->hflip = HFLIP_DEFAULT; - - return 0; -} - -static int cit_init_model0(struct gspca_dev *gspca_dev) -{ - cit_write_reg(gspca_dev, 0x0000, 0x0100); /* turn on led */ - cit_write_reg(gspca_dev, 0x0001, 0x0112); /* turn on autogain ? */ - cit_write_reg(gspca_dev, 0x0000, 0x0400); - cit_write_reg(gspca_dev, 0x0001, 0x0400); - cit_write_reg(gspca_dev, 0x0000, 0x0420); - cit_write_reg(gspca_dev, 0x0001, 0x0420); - cit_write_reg(gspca_dev, 0x000d, 0x0409); - cit_write_reg(gspca_dev, 0x0002, 0x040a); - cit_write_reg(gspca_dev, 0x0018, 0x0405); - cit_write_reg(gspca_dev, 0x0008, 0x0435); - cit_write_reg(gspca_dev, 0x0026, 0x040b); - cit_write_reg(gspca_dev, 0x0007, 0x0437); - cit_write_reg(gspca_dev, 0x0015, 0x042f); - cit_write_reg(gspca_dev, 0x002b, 0x0439); - cit_write_reg(gspca_dev, 0x0026, 0x043a); - cit_write_reg(gspca_dev, 0x0008, 0x0438); - cit_write_reg(gspca_dev, 0x001e, 0x042b); - cit_write_reg(gspca_dev, 0x0041, 0x042c); - - return 0; -} - -static int cit_init_ibm_netcam_pro(struct gspca_dev *gspca_dev) -{ - cit_read_reg(gspca_dev, 0x128, 1); - cit_write_reg(gspca_dev, 0x0003, 0x0133); - cit_write_reg(gspca_dev, 0x0000, 0x0117); - cit_write_reg(gspca_dev, 0x0008, 0x0123); - cit_write_reg(gspca_dev, 0x0000, 0x0100); - cit_read_reg(gspca_dev, 0x0116, 0); - cit_write_reg(gspca_dev, 0x0060, 0x0116); - cit_write_reg(gspca_dev, 0x0002, 0x0112); - cit_write_reg(gspca_dev, 0x0000, 0x0133); - cit_write_reg(gspca_dev, 0x0000, 0x0123); - cit_write_reg(gspca_dev, 0x0001, 0x0117); - cit_write_reg(gspca_dev, 0x0040, 0x0108); - cit_write_reg(gspca_dev, 0x0019, 0x012c); - cit_write_reg(gspca_dev, 0x0060, 0x0116); - cit_write_reg(gspca_dev, 0x0002, 0x0115); - cit_write_reg(gspca_dev, 0x000b, 0x0115); - - cit_write_reg(gspca_dev, 0x0078, 0x012d); - cit_write_reg(gspca_dev, 0x0001, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0079, 0x012d); - cit_write_reg(gspca_dev, 0x00ff, 0x0130); - cit_write_reg(gspca_dev, 0xcd41, 0x0124); - cit_write_reg(gspca_dev, 0xfffa, 0x0124); - cit_read_reg(gspca_dev, 0x0126, 1); - - cit_model3_Packet1(gspca_dev, 0x0000, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0000, 0x0001); - cit_model3_Packet1(gspca_dev, 0x000b, 0x0000); - cit_model3_Packet1(gspca_dev, 0x000c, 0x0008); - cit_model3_Packet1(gspca_dev, 0x000d, 0x003a); - cit_model3_Packet1(gspca_dev, 0x000e, 0x0060); - cit_model3_Packet1(gspca_dev, 0x000f, 0x0060); - cit_model3_Packet1(gspca_dev, 0x0010, 0x0008); - cit_model3_Packet1(gspca_dev, 0x0011, 0x0004); - cit_model3_Packet1(gspca_dev, 0x0012, 0x0028); - cit_model3_Packet1(gspca_dev, 0x0013, 0x0002); - cit_model3_Packet1(gspca_dev, 0x0014, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0015, 0x00fb); - cit_model3_Packet1(gspca_dev, 0x0016, 0x0002); - cit_model3_Packet1(gspca_dev, 0x0017, 0x0037); - cit_model3_Packet1(gspca_dev, 0x0018, 0x0036); - cit_model3_Packet1(gspca_dev, 0x001e, 0x0000); - cit_model3_Packet1(gspca_dev, 0x001f, 0x0008); - cit_model3_Packet1(gspca_dev, 0x0020, 0x00c1); - cit_model3_Packet1(gspca_dev, 0x0021, 0x0034); - cit_model3_Packet1(gspca_dev, 0x0022, 0x0034); - cit_model3_Packet1(gspca_dev, 0x0025, 0x0002); - cit_model3_Packet1(gspca_dev, 0x0028, 0x0022); - cit_model3_Packet1(gspca_dev, 0x0029, 0x000a); - cit_model3_Packet1(gspca_dev, 0x002b, 0x0000); - cit_model3_Packet1(gspca_dev, 0x002c, 0x0000); - cit_model3_Packet1(gspca_dev, 0x002d, 0x00ff); - cit_model3_Packet1(gspca_dev, 0x002e, 0x00ff); - cit_model3_Packet1(gspca_dev, 0x002f, 0x00ff); - cit_model3_Packet1(gspca_dev, 0x0030, 0x00ff); - cit_model3_Packet1(gspca_dev, 0x0031, 0x00ff); - cit_model3_Packet1(gspca_dev, 0x0032, 0x0007); - cit_model3_Packet1(gspca_dev, 0x0033, 0x0005); - cit_model3_Packet1(gspca_dev, 0x0037, 0x0040); - cit_model3_Packet1(gspca_dev, 0x0039, 0x0000); - cit_model3_Packet1(gspca_dev, 0x003a, 0x0000); - cit_model3_Packet1(gspca_dev, 0x003b, 0x0001); - cit_model3_Packet1(gspca_dev, 0x003c, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0040, 0x000c); - cit_model3_Packet1(gspca_dev, 0x0041, 0x00fb); - cit_model3_Packet1(gspca_dev, 0x0042, 0x0002); - cit_model3_Packet1(gspca_dev, 0x0043, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0045, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0046, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0047, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0048, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0049, 0x0000); - cit_model3_Packet1(gspca_dev, 0x004a, 0x00ff); - cit_model3_Packet1(gspca_dev, 0x004b, 0x00ff); - cit_model3_Packet1(gspca_dev, 0x004c, 0x00ff); - cit_model3_Packet1(gspca_dev, 0x004f, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0050, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0051, 0x0002); - cit_model3_Packet1(gspca_dev, 0x0055, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0056, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0057, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0058, 0x0002); - cit_model3_Packet1(gspca_dev, 0x0059, 0x0000); - cit_model3_Packet1(gspca_dev, 0x005c, 0x0016); - cit_model3_Packet1(gspca_dev, 0x005d, 0x0022); - cit_model3_Packet1(gspca_dev, 0x005e, 0x003c); - cit_model3_Packet1(gspca_dev, 0x005f, 0x0050); - cit_model3_Packet1(gspca_dev, 0x0060, 0x0044); - cit_model3_Packet1(gspca_dev, 0x0061, 0x0005); - cit_model3_Packet1(gspca_dev, 0x006a, 0x007e); - cit_model3_Packet1(gspca_dev, 0x006f, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0072, 0x001b); - cit_model3_Packet1(gspca_dev, 0x0073, 0x0005); - cit_model3_Packet1(gspca_dev, 0x0074, 0x000a); - cit_model3_Packet1(gspca_dev, 0x0075, 0x001b); - cit_model3_Packet1(gspca_dev, 0x0076, 0x002a); - cit_model3_Packet1(gspca_dev, 0x0077, 0x003c); - cit_model3_Packet1(gspca_dev, 0x0078, 0x0050); - cit_model3_Packet1(gspca_dev, 0x007b, 0x0000); - cit_model3_Packet1(gspca_dev, 0x007c, 0x0011); - cit_model3_Packet1(gspca_dev, 0x007d, 0x0024); - cit_model3_Packet1(gspca_dev, 0x007e, 0x0043); - cit_model3_Packet1(gspca_dev, 0x007f, 0x005a); - cit_model3_Packet1(gspca_dev, 0x0084, 0x0020); - cit_model3_Packet1(gspca_dev, 0x0085, 0x0033); - cit_model3_Packet1(gspca_dev, 0x0086, 0x000a); - cit_model3_Packet1(gspca_dev, 0x0087, 0x0030); - cit_model3_Packet1(gspca_dev, 0x0088, 0x0070); - cit_model3_Packet1(gspca_dev, 0x008b, 0x0008); - cit_model3_Packet1(gspca_dev, 0x008f, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0090, 0x0006); - cit_model3_Packet1(gspca_dev, 0x0091, 0x0028); - cit_model3_Packet1(gspca_dev, 0x0092, 0x005a); - cit_model3_Packet1(gspca_dev, 0x0093, 0x0082); - cit_model3_Packet1(gspca_dev, 0x0096, 0x0014); - cit_model3_Packet1(gspca_dev, 0x0097, 0x0020); - cit_model3_Packet1(gspca_dev, 0x0098, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00b0, 0x0046); - cit_model3_Packet1(gspca_dev, 0x00b1, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00b2, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00b3, 0x0004); - cit_model3_Packet1(gspca_dev, 0x00b4, 0x0007); - cit_model3_Packet1(gspca_dev, 0x00b6, 0x0002); - cit_model3_Packet1(gspca_dev, 0x00b7, 0x0004); - cit_model3_Packet1(gspca_dev, 0x00bb, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00bc, 0x0001); - cit_model3_Packet1(gspca_dev, 0x00bd, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00bf, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00c0, 0x00c8); - cit_model3_Packet1(gspca_dev, 0x00c1, 0x0014); - cit_model3_Packet1(gspca_dev, 0x00c2, 0x0001); - cit_model3_Packet1(gspca_dev, 0x00c3, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00c4, 0x0004); - cit_model3_Packet1(gspca_dev, 0x00cb, 0x00bf); - cit_model3_Packet1(gspca_dev, 0x00cc, 0x00bf); - cit_model3_Packet1(gspca_dev, 0x00cd, 0x00bf); - cit_model3_Packet1(gspca_dev, 0x00ce, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00cf, 0x0020); - cit_model3_Packet1(gspca_dev, 0x00d0, 0x0040); - cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf); - cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf); - cit_model3_Packet1(gspca_dev, 0x00d2, 0x00bf); - cit_model3_Packet1(gspca_dev, 0x00d3, 0x00bf); - cit_model3_Packet1(gspca_dev, 0x00ea, 0x0008); - cit_model3_Packet1(gspca_dev, 0x00eb, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00ec, 0x00e8); - cit_model3_Packet1(gspca_dev, 0x00ed, 0x0001); - cit_model3_Packet1(gspca_dev, 0x00ef, 0x0022); - cit_model3_Packet1(gspca_dev, 0x00f0, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00f2, 0x0028); - cit_model3_Packet1(gspca_dev, 0x00f4, 0x0002); - cit_model3_Packet1(gspca_dev, 0x00f5, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00fa, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00fb, 0x0001); - cit_model3_Packet1(gspca_dev, 0x00fc, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00fd, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00fe, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00ff, 0x0000); - - cit_model3_Packet1(gspca_dev, 0x00be, 0x0003); - cit_model3_Packet1(gspca_dev, 0x00c8, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00c9, 0x0020); - cit_model3_Packet1(gspca_dev, 0x00ca, 0x0040); - cit_model3_Packet1(gspca_dev, 0x0053, 0x0001); - cit_model3_Packet1(gspca_dev, 0x0082, 0x000e); - cit_model3_Packet1(gspca_dev, 0x0083, 0x0020); - cit_model3_Packet1(gspca_dev, 0x0034, 0x003c); - cit_model3_Packet1(gspca_dev, 0x006e, 0x0055); - cit_model3_Packet1(gspca_dev, 0x0062, 0x0005); - cit_model3_Packet1(gspca_dev, 0x0063, 0x0008); - cit_model3_Packet1(gspca_dev, 0x0066, 0x000a); - cit_model3_Packet1(gspca_dev, 0x0067, 0x0006); - cit_model3_Packet1(gspca_dev, 0x006b, 0x0010); - cit_model3_Packet1(gspca_dev, 0x005a, 0x0001); - cit_model3_Packet1(gspca_dev, 0x005b, 0x000a); - cit_model3_Packet1(gspca_dev, 0x0023, 0x0006); - cit_model3_Packet1(gspca_dev, 0x0026, 0x0004); - cit_model3_Packet1(gspca_dev, 0x0036, 0x0069); - cit_model3_Packet1(gspca_dev, 0x0038, 0x0064); - cit_model3_Packet1(gspca_dev, 0x003d, 0x0003); - cit_model3_Packet1(gspca_dev, 0x003e, 0x0001); - cit_model3_Packet1(gspca_dev, 0x00b8, 0x0014); - cit_model3_Packet1(gspca_dev, 0x00b9, 0x0014); - cit_model3_Packet1(gspca_dev, 0x00e6, 0x0004); - cit_model3_Packet1(gspca_dev, 0x00e8, 0x0001); - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->model) { - case CIT_MODEL0: - cit_init_model0(gspca_dev); - sd_stop0(gspca_dev); - break; - case CIT_MODEL1: - case CIT_MODEL2: - case CIT_MODEL3: - case CIT_MODEL4: - break; /* All is done in sd_start */ - case CIT_IBM_NETCAM_PRO: - cit_init_ibm_netcam_pro(gspca_dev); - sd_stop0(gspca_dev); - break; - } - return 0; -} - -static int cit_set_brightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - - switch (sd->model) { - case CIT_MODEL0: - case CIT_IBM_NETCAM_PRO: - /* No (known) brightness control for these */ - break; - case CIT_MODEL1: - /* Model 1: Brightness range 0 - 63 */ - cit_Packet_Format1(gspca_dev, 0x0031, sd->brightness); - cit_Packet_Format1(gspca_dev, 0x0032, sd->brightness); - cit_Packet_Format1(gspca_dev, 0x0033, sd->brightness); - break; - case CIT_MODEL2: - /* Model 2: Brightness range 0x60 - 0xee */ - /* Scale 0 - 63 to 0x60 - 0xee */ - i = 0x60 + sd->brightness * 2254 / 1000; - cit_model2_Packet1(gspca_dev, 0x001a, i); - break; - case CIT_MODEL3: - /* Model 3: Brightness range 'i' in [0x0C..0x3F] */ - i = sd->brightness; - if (i < 0x0c) - i = 0x0c; - cit_model3_Packet1(gspca_dev, 0x0036, i); - break; - case CIT_MODEL4: - /* Model 4: Brightness range 'i' in [0x04..0xb4] */ - /* Scale 0 - 63 to 0x04 - 0xb4 */ - i = 0x04 + sd->brightness * 2794 / 1000; - cit_model4_BrightnessPacket(gspca_dev, i); - break; - } - - return 0; -} - -static int cit_set_contrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->model) { - case CIT_MODEL0: { - int i; - /* gain 0-15, 0-20 -> 0-15 */ - i = sd->contrast * 1000 / 1333; - cit_write_reg(gspca_dev, i, 0x0422); - /* gain 0-31, may not be lower then 0x0422, 0-20 -> 0-31 */ - i = sd->contrast * 2000 / 1333; - cit_write_reg(gspca_dev, i, 0x0423); - /* gain 0-127, may not be lower then 0x0423, 0-20 -> 0-63 */ - i = sd->contrast * 4000 / 1333; - cit_write_reg(gspca_dev, i, 0x0424); - /* gain 0-127, may not be lower then 0x0424, , 0-20 -> 0-127 */ - i = sd->contrast * 8000 / 1333; - cit_write_reg(gspca_dev, i, 0x0425); - break; - } - case CIT_MODEL2: - case CIT_MODEL4: - /* These models do not have this control. */ - break; - case CIT_MODEL1: - { - /* Scale 0 - 20 to 15 - 0 */ - int i, new_contrast = (20 - sd->contrast) * 1000 / 1333; - for (i = 0; i < cit_model1_ntries; i++) { - cit_Packet_Format1(gspca_dev, 0x0014, new_contrast); - cit_send_FF_04_02(gspca_dev); - } - break; - } - case CIT_MODEL3: - { /* Preset hardware values */ - static const struct { - unsigned short cv1; - unsigned short cv2; - unsigned short cv3; - } cv[7] = { - { 0x05, 0x05, 0x0f }, /* Minimum */ - { 0x04, 0x04, 0x16 }, - { 0x02, 0x03, 0x16 }, - { 0x02, 0x08, 0x16 }, - { 0x01, 0x0c, 0x16 }, - { 0x01, 0x0e, 0x16 }, - { 0x01, 0x10, 0x16 } /* Maximum */ - }; - int i = sd->contrast / 3; - cit_model3_Packet1(gspca_dev, 0x0067, cv[i].cv1); - cit_model3_Packet1(gspca_dev, 0x005b, cv[i].cv2); - cit_model3_Packet1(gspca_dev, 0x005c, cv[i].cv3); - break; - } - case CIT_IBM_NETCAM_PRO: - cit_model3_Packet1(gspca_dev, 0x005b, sd->contrast + 1); - break; - } - return 0; -} - -static int cit_set_hue(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->model) { - case CIT_MODEL0: - case CIT_MODEL1: - case CIT_IBM_NETCAM_PRO: - /* No hue control for these models */ - break; - case CIT_MODEL2: - cit_model2_Packet1(gspca_dev, 0x0024, sd->hue); - /* cit_model2_Packet1(gspca_dev, 0x0020, sat); */ - break; - case CIT_MODEL3: { - /* Model 3: Brightness range 'i' in [0x05..0x37] */ - /* TESTME according to the ibmcam driver this does not work */ - if (0) { - /* Scale 0 - 127 to 0x05 - 0x37 */ - int i = 0x05 + sd->hue * 1000 / 2540; - cit_model3_Packet1(gspca_dev, 0x007e, i); - } - break; - } - case CIT_MODEL4: - /* HDG: taken from ibmcam, setting the color gains does not - * really belong here. - * - * I am not sure r/g/b_gain variables exactly control gain - * of those channels. Most likely they subtly change some - * very internal image processing settings in the camera. - * In any case, here is what they do, and feel free to tweak: - * - * r_gain: seriously affects red gain - * g_gain: seriously affects green gain - * b_gain: seriously affects blue gain - * hue: changes average color from violet (0) to red (0xFF) - */ - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x001e, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 160, 0x0127); /* Green gain */ - cit_write_reg(gspca_dev, 160, 0x012e); /* Red gain */ - cit_write_reg(gspca_dev, 160, 0x0130); /* Blue gain */ - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, sd->hue, 0x012d); /* Hue */ - cit_write_reg(gspca_dev, 0xf545, 0x0124); - break; - } - return 0; -} - -static int cit_set_sharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->model) { - case CIT_MODEL0: - case CIT_MODEL2: - case CIT_MODEL4: - case CIT_IBM_NETCAM_PRO: - /* These models do not have this control */ - break; - case CIT_MODEL1: { - int i; - const unsigned short sa[] = { - 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a }; - - for (i = 0; i < cit_model1_ntries; i++) - cit_PacketFormat2(gspca_dev, 0x0013, sa[sd->sharpness]); - break; - } - case CIT_MODEL3: - { /* - * "Use a table of magic numbers. - * This setting doesn't really change much. - * But that's how Windows does it." - */ - static const struct { - unsigned short sv1; - unsigned short sv2; - unsigned short sv3; - unsigned short sv4; - } sv[7] = { - { 0x00, 0x00, 0x05, 0x14 }, /* Smoothest */ - { 0x01, 0x04, 0x05, 0x14 }, - { 0x02, 0x04, 0x05, 0x14 }, - { 0x03, 0x04, 0x05, 0x14 }, - { 0x03, 0x05, 0x05, 0x14 }, - { 0x03, 0x06, 0x05, 0x14 }, - { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */ - }; - cit_model3_Packet1(gspca_dev, 0x0060, sv[sd->sharpness].sv1); - cit_model3_Packet1(gspca_dev, 0x0061, sv[sd->sharpness].sv2); - cit_model3_Packet1(gspca_dev, 0x0062, sv[sd->sharpness].sv3); - cit_model3_Packet1(gspca_dev, 0x0063, sv[sd->sharpness].sv4); - break; - } - } - return 0; -} - -/* - * cit_set_lighting() - * - * Camera model 1: - * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low. - * - * Camera model 2: - * We have 16 levels of lighting, 0 for bright light and up to 15 for - * low light. But values above 5 or so are useless because camera is - * not really capable to produce anything worth viewing at such light. - * This setting may be altered only in certain camera state. - * - * Low lighting forces slower FPS. - * - * History: - * 1/5/00 Created. - * 2/20/00 Added support for Model 2 cameras. - */ -static void cit_set_lighting(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->model) { - case CIT_MODEL0: - case CIT_MODEL2: - case CIT_MODEL3: - case CIT_MODEL4: - case CIT_IBM_NETCAM_PRO: - break; - case CIT_MODEL1: { - int i; - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting); - break; - } - } -} - -static void cit_set_hflip(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->model) { - case CIT_MODEL0: - if (sd->hflip) - cit_write_reg(gspca_dev, 0x0020, 0x0115); - else - cit_write_reg(gspca_dev, 0x0040, 0x0115); - break; - case CIT_MODEL1: - case CIT_MODEL2: - case CIT_MODEL3: - case CIT_MODEL4: - case CIT_IBM_NETCAM_PRO: - break; - } -} - -static int cit_restart_stream(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->model) { - case CIT_MODEL0: - case CIT_MODEL1: - cit_write_reg(gspca_dev, 0x0001, 0x0114); - /* Fall through */ - case CIT_MODEL2: - case CIT_MODEL4: - cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */ - usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe); - break; - case CIT_MODEL3: - case CIT_IBM_NETCAM_PRO: - cit_write_reg(gspca_dev, 0x0001, 0x0114); - cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */ - usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe); - /* Clear button events from while we were not streaming */ - cit_write_reg(gspca_dev, 0x0001, 0x0113); - break; - } - - sd->sof_read = 0; - - return 0; -} - -static int cit_get_packet_size(struct gspca_dev *gspca_dev) -{ - struct usb_host_interface *alt; - struct usb_interface *intf; - - intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); - alt = usb_altnum_to_altsetting(intf, gspca_dev->alt); - if (!alt) { - err("Couldn't get altsetting"); - return -EIO; - } - - return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); -} - -/* Calculate the clockdiv giving us max fps given the available bandwidth */ -static int cit_get_clock_div(struct gspca_dev *gspca_dev) -{ - int clock_div = 7; /* 0=30 1=25 2=20 3=15 4=12 5=7.5 6=6 7=3fps ?? */ - int fps[8] = { 30, 25, 20, 15, 12, 8, 6, 3 }; - int packet_size; - - packet_size = cit_get_packet_size(gspca_dev); - if (packet_size < 0) - return packet_size; - - while (clock_div > 3 && - 1000 * packet_size > - gspca_dev->width * gspca_dev->height * - fps[clock_div - 1] * 3 / 2) - clock_div--; - - PDEBUG(D_PROBE, - "PacketSize: %d, res: %dx%d -> using clockdiv: %d (%d fps)", - packet_size, gspca_dev->width, gspca_dev->height, clock_div, - fps[clock_div]); - - return clock_div; -} - -static int cit_start_model0(struct gspca_dev *gspca_dev) -{ - const unsigned short compression = 0; /* 0=none, 7=best frame rate */ - int clock_div; - - clock_div = cit_get_clock_div(gspca_dev); - if (clock_div < 0) - return clock_div; - - cit_write_reg(gspca_dev, 0x0000, 0x0100); /* turn on led */ - cit_write_reg(gspca_dev, 0x0003, 0x0438); - cit_write_reg(gspca_dev, 0x001e, 0x042b); - cit_write_reg(gspca_dev, 0x0041, 0x042c); - cit_write_reg(gspca_dev, 0x0008, 0x0436); - cit_write_reg(gspca_dev, 0x0024, 0x0403); - cit_write_reg(gspca_dev, 0x002c, 0x0404); - cit_write_reg(gspca_dev, 0x0002, 0x0426); - cit_write_reg(gspca_dev, 0x0014, 0x0427); - - switch (gspca_dev->width) { - case 160: /* 160x120 */ - cit_write_reg(gspca_dev, 0x0004, 0x010b); - cit_write_reg(gspca_dev, 0x0001, 0x010a); - cit_write_reg(gspca_dev, 0x0010, 0x0102); - cit_write_reg(gspca_dev, 0x00a0, 0x0103); - cit_write_reg(gspca_dev, 0x0000, 0x0104); - cit_write_reg(gspca_dev, 0x0078, 0x0105); - break; - - case 176: /* 176x144 */ - cit_write_reg(gspca_dev, 0x0006, 0x010b); - cit_write_reg(gspca_dev, 0x0000, 0x010a); - cit_write_reg(gspca_dev, 0x0005, 0x0102); - cit_write_reg(gspca_dev, 0x00b0, 0x0103); - cit_write_reg(gspca_dev, 0x0000, 0x0104); - cit_write_reg(gspca_dev, 0x0090, 0x0105); - break; - - case 320: /* 320x240 */ - cit_write_reg(gspca_dev, 0x0008, 0x010b); - cit_write_reg(gspca_dev, 0x0004, 0x010a); - cit_write_reg(gspca_dev, 0x0005, 0x0102); - cit_write_reg(gspca_dev, 0x00a0, 0x0103); - cit_write_reg(gspca_dev, 0x0010, 0x0104); - cit_write_reg(gspca_dev, 0x0078, 0x0105); - break; - } - - cit_write_reg(gspca_dev, compression, 0x0109); - cit_write_reg(gspca_dev, clock_div, 0x0111); - - return 0; -} - -static int cit_start_model1(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, clock_div; - - clock_div = cit_get_clock_div(gspca_dev); - if (clock_div < 0) - return clock_div; - - cit_read_reg(gspca_dev, 0x0128, 1); - cit_read_reg(gspca_dev, 0x0100, 0); - cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */ - cit_read_reg(gspca_dev, 0x0100, 0); - cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */ - cit_read_reg(gspca_dev, 0x0100, 0); - cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */ - cit_write_reg(gspca_dev, 0x01, 0x0108); - - cit_write_reg(gspca_dev, 0x03, 0x0112); - cit_read_reg(gspca_dev, 0x0115, 0); - cit_write_reg(gspca_dev, 0x06, 0x0115); - cit_read_reg(gspca_dev, 0x0116, 0); - cit_write_reg(gspca_dev, 0x44, 0x0116); - cit_read_reg(gspca_dev, 0x0116, 0); - cit_write_reg(gspca_dev, 0x40, 0x0116); - cit_read_reg(gspca_dev, 0x0115, 0); - cit_write_reg(gspca_dev, 0x0e, 0x0115); - cit_write_reg(gspca_dev, 0x19, 0x012c); - - cit_Packet_Format1(gspca_dev, 0x00, 0x1e); - cit_Packet_Format1(gspca_dev, 0x39, 0x0d); - cit_Packet_Format1(gspca_dev, 0x39, 0x09); - cit_Packet_Format1(gspca_dev, 0x3b, 0x00); - cit_Packet_Format1(gspca_dev, 0x28, 0x22); - cit_Packet_Format1(gspca_dev, 0x27, 0x00); - cit_Packet_Format1(gspca_dev, 0x2b, 0x1f); - cit_Packet_Format1(gspca_dev, 0x39, 0x08); - - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x2c, 0x00); - - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x30, 0x14); - - cit_PacketFormat2(gspca_dev, 0x39, 0x02); - cit_PacketFormat2(gspca_dev, 0x01, 0xe1); - cit_PacketFormat2(gspca_dev, 0x02, 0xcd); - cit_PacketFormat2(gspca_dev, 0x03, 0xcd); - cit_PacketFormat2(gspca_dev, 0x04, 0xfa); - cit_PacketFormat2(gspca_dev, 0x3f, 0xff); - cit_PacketFormat2(gspca_dev, 0x39, 0x00); - - cit_PacketFormat2(gspca_dev, 0x39, 0x02); - cit_PacketFormat2(gspca_dev, 0x0a, 0x37); - cit_PacketFormat2(gspca_dev, 0x0b, 0xb8); - cit_PacketFormat2(gspca_dev, 0x0c, 0xf3); - cit_PacketFormat2(gspca_dev, 0x0d, 0xe3); - cit_PacketFormat2(gspca_dev, 0x0e, 0x0d); - cit_PacketFormat2(gspca_dev, 0x0f, 0xf2); - cit_PacketFormat2(gspca_dev, 0x10, 0xd5); - cit_PacketFormat2(gspca_dev, 0x11, 0xba); - cit_PacketFormat2(gspca_dev, 0x12, 0x53); - cit_PacketFormat2(gspca_dev, 0x3f, 0xff); - cit_PacketFormat2(gspca_dev, 0x39, 0x00); - - cit_PacketFormat2(gspca_dev, 0x39, 0x02); - cit_PacketFormat2(gspca_dev, 0x16, 0x00); - cit_PacketFormat2(gspca_dev, 0x17, 0x28); - cit_PacketFormat2(gspca_dev, 0x18, 0x7d); - cit_PacketFormat2(gspca_dev, 0x19, 0xbe); - cit_PacketFormat2(gspca_dev, 0x3f, 0xff); - cit_PacketFormat2(gspca_dev, 0x39, 0x00); - - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x00, 0x18); - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x13, 0x18); - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x14, 0x06); - - /* TESTME These are handled through controls - KEEP until someone can test leaving this out is ok */ - if (0) { - /* This is default brightness */ - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x31, 0x37); - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x32, 0x46); - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x33, 0x55); - } - - cit_Packet_Format1(gspca_dev, 0x2e, 0x04); - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x2d, 0x04); - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x29, 0x80); - cit_Packet_Format1(gspca_dev, 0x2c, 0x01); - cit_Packet_Format1(gspca_dev, 0x30, 0x17); - cit_Packet_Format1(gspca_dev, 0x39, 0x08); - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x34, 0x00); - - cit_write_reg(gspca_dev, 0x00, 0x0101); - cit_write_reg(gspca_dev, 0x00, 0x010a); - - switch (gspca_dev->width) { - case 128: /* 128x96 */ - cit_write_reg(gspca_dev, 0x80, 0x0103); - cit_write_reg(gspca_dev, 0x60, 0x0105); - cit_write_reg(gspca_dev, 0x0c, 0x010b); - cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x0b, 0x011d); - cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x00, 0x0129); - break; - case 176: /* 176x144 */ - cit_write_reg(gspca_dev, 0xb0, 0x0103); - cit_write_reg(gspca_dev, 0x8f, 0x0105); - cit_write_reg(gspca_dev, 0x06, 0x010b); - cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x0d, 0x011d); - cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x03, 0x0129); - break; - case 352: /* 352x288 */ - cit_write_reg(gspca_dev, 0xb0, 0x0103); - cit_write_reg(gspca_dev, 0x90, 0x0105); - cit_write_reg(gspca_dev, 0x02, 0x010b); - cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x05, 0x011d); - cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x00, 0x0129); - break; - } - - cit_write_reg(gspca_dev, 0xff, 0x012b); - - /* TESTME These are handled through controls - KEEP until someone can test leaving this out is ok */ - if (0) { - /* This is another brightness - don't know why */ - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x31, 0xc3); - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x32, 0xd2); - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x33, 0xe1); - - /* Default contrast */ - for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x14, 0x0a); - - /* Default sharpness */ - for (i = 0; i < cit_model1_ntries2; i++) - cit_PacketFormat2(gspca_dev, 0x13, 0x1a); - - /* Default lighting conditions */ - cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting); - } - - /* Assorted init */ - switch (gspca_dev->width) { - case 128: /* 128x96 */ - cit_Packet_Format1(gspca_dev, 0x2b, 0x1e); - cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x36, 0x0102); - cit_write_reg(gspca_dev, 0x1a, 0x0104); - cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x2b, 0x011c); - cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */ - break; - case 176: /* 176x144 */ - cit_Packet_Format1(gspca_dev, 0x2b, 0x1e); - cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x04, 0x0102); - cit_write_reg(gspca_dev, 0x02, 0x0104); - cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x2b, 0x011c); - cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */ - break; - case 352: /* 352x288 */ - cit_Packet_Format1(gspca_dev, 0x2b, 0x1f); - cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x08, 0x0102); - cit_write_reg(gspca_dev, 0x01, 0x0104); - cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */ - cit_write_reg(gspca_dev, 0x2f, 0x011c); - cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */ - break; - } - - cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */ - cit_write_reg(gspca_dev, clock_div, 0x0111); - - return 0; -} - -static int cit_start_model2(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int clock_div = 0; - - cit_write_reg(gspca_dev, 0x0000, 0x0100); /* LED on */ - cit_read_reg(gspca_dev, 0x0116, 0); - cit_write_reg(gspca_dev, 0x0060, 0x0116); - cit_write_reg(gspca_dev, 0x0002, 0x0112); - cit_write_reg(gspca_dev, 0x00bc, 0x012c); - cit_write_reg(gspca_dev, 0x0008, 0x012b); - cit_write_reg(gspca_dev, 0x0000, 0x0108); - cit_write_reg(gspca_dev, 0x0001, 0x0133); - cit_write_reg(gspca_dev, 0x0001, 0x0102); - switch (gspca_dev->width) { - case 176: /* 176x144 */ - cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */ - cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ - cit_write_reg(gspca_dev, 0x0024, 0x0105); /* 176x144, 352x288 */ - cit_write_reg(gspca_dev, 0x00b9, 0x010a); /* Unique to this mode */ - cit_write_reg(gspca_dev, 0x0038, 0x0119); /* Unique to this mode */ - /* TESTME HDG: this does not seem right - (it is 2 for all other resolutions) */ - sd->sof_len = 10; - break; - case 320: /* 320x240 */ - cit_write_reg(gspca_dev, 0x0028, 0x0103); /* Unique to this mode */ - cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ - cit_write_reg(gspca_dev, 0x001e, 0x0105); /* 320x240, 352x240 */ - cit_write_reg(gspca_dev, 0x0039, 0x010a); /* All except 176x144 */ - cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */ - sd->sof_len = 2; - break; - /* case VIDEOSIZE_352x240: */ - cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */ - cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ - cit_write_reg(gspca_dev, 0x001e, 0x0105); /* 320x240, 352x240 */ - cit_write_reg(gspca_dev, 0x0039, 0x010a); /* All except 176x144 */ - cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */ - sd->sof_len = 2; - break; - case 352: /* 352x288 */ - cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */ - cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ - cit_write_reg(gspca_dev, 0x0024, 0x0105); /* 176x144, 352x288 */ - cit_write_reg(gspca_dev, 0x0039, 0x010a); /* All except 176x144 */ - cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */ - sd->sof_len = 2; - break; - } - - cit_write_reg(gspca_dev, 0x0000, 0x0100); /* LED on */ - - switch (gspca_dev->width) { - case 176: /* 176x144 */ - cit_write_reg(gspca_dev, 0x0050, 0x0111); - cit_write_reg(gspca_dev, 0x00d0, 0x0111); - break; - case 320: /* 320x240 */ - case 352: /* 352x288 */ - cit_write_reg(gspca_dev, 0x0040, 0x0111); - cit_write_reg(gspca_dev, 0x00c0, 0x0111); - break; - } - cit_write_reg(gspca_dev, 0x009b, 0x010f); - cit_write_reg(gspca_dev, 0x00bb, 0x010f); - - /* - * Hardware settings, may affect CMOS sensor; not user controls! - * ------------------------------------------------------------- - * 0x0004: no effect - * 0x0006: hardware effect - * 0x0008: no effect - * 0x000a: stops video stream, probably important h/w setting - * 0x000c: changes color in hardware manner (not user setting) - * 0x0012: changes number of colors (does not affect speed) - * 0x002a: no effect - * 0x002c: hardware setting (related to scan lines) - * 0x002e: stops video stream, probably important h/w setting - */ - cit_model2_Packet1(gspca_dev, 0x000a, 0x005c); - cit_model2_Packet1(gspca_dev, 0x0004, 0x0000); - cit_model2_Packet1(gspca_dev, 0x0006, 0x00fb); - cit_model2_Packet1(gspca_dev, 0x0008, 0x0000); - cit_model2_Packet1(gspca_dev, 0x000c, 0x0009); - cit_model2_Packet1(gspca_dev, 0x0012, 0x000a); - cit_model2_Packet1(gspca_dev, 0x002a, 0x0000); - cit_model2_Packet1(gspca_dev, 0x002c, 0x0000); - cit_model2_Packet1(gspca_dev, 0x002e, 0x0008); - - /* - * Function 0x0030 pops up all over the place. Apparently - * it is a hardware control register, with every bit assigned to - * do something. - */ - cit_model2_Packet1(gspca_dev, 0x0030, 0x0000); - - /* - * Magic control of CMOS sensor. Only lower values like - * 0-3 work, and picture shifts left or right. Don't change. - */ - switch (gspca_dev->width) { - case 176: /* 176x144 */ - cit_model2_Packet1(gspca_dev, 0x0014, 0x0002); - cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */ - cit_model2_Packet1(gspca_dev, 0x0018, 0x004a); /* Another hardware setting */ - clock_div = 6; - break; - case 320: /* 320x240 */ - cit_model2_Packet1(gspca_dev, 0x0014, 0x0009); - cit_model2_Packet1(gspca_dev, 0x0016, 0x0005); /* Horizontal shift */ - cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Another hardware setting */ - clock_div = 8; - break; - /* case VIDEOSIZE_352x240: */ - /* This mode doesn't work as Windows programs it; changed to work */ - cit_model2_Packet1(gspca_dev, 0x0014, 0x0009); /* Windows sets this to 8 */ - cit_model2_Packet1(gspca_dev, 0x0016, 0x0003); /* Horizontal shift */ - cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Windows sets this to 0x0045 */ - clock_div = 10; - break; - case 352: /* 352x288 */ - cit_model2_Packet1(gspca_dev, 0x0014, 0x0003); - cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */ - cit_model2_Packet1(gspca_dev, 0x0018, 0x004a); /* Another hardware setting */ - clock_div = 16; - break; - } - - /* TESTME These are handled through controls - KEEP until someone can test leaving this out is ok */ - if (0) - cit_model2_Packet1(gspca_dev, 0x001a, 0x005a); - - /* - * We have our own frame rate setting varying from 0 (slowest) to 6 - * (fastest). The camera model 2 allows frame rate in range [0..0x1F] - # where 0 is also the slowest setting. However for all practical - # reasons high settings make no sense because USB is not fast enough - # to support high FPS. Be aware that the picture datastream will be - # severely disrupted if you ask for frame rate faster than allowed - # for the video size - see below: - * - * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz): - * ----------------------------------------------------------------- - * 176x144: [6..31] - * 320x240: [8..31] - * 352x240: [10..31] - * 352x288: [16..31] I have to raise lower threshold for stability... - * - * As usual, slower FPS provides better sensitivity. - */ - cit_model2_Packet1(gspca_dev, 0x001c, clock_div); - - /* - * This setting does not visibly affect pictures; left it here - * because it was present in Windows USB data stream. This function - * does not allow arbitrary values and apparently is a bit mask, to - * be activated only at appropriate time. Don't change it randomly! - */ - switch (gspca_dev->width) { - case 176: /* 176x144 */ - cit_model2_Packet1(gspca_dev, 0x0026, 0x00c2); - break; - case 320: /* 320x240 */ - cit_model2_Packet1(gspca_dev, 0x0026, 0x0044); - break; - /* case VIDEOSIZE_352x240: */ - cit_model2_Packet1(gspca_dev, 0x0026, 0x0046); - break; - case 352: /* 352x288 */ - cit_model2_Packet1(gspca_dev, 0x0026, 0x0048); - break; - } - - /* FIXME this cannot be changed while streaming, so we - should report a grabbed flag for this control. */ - cit_model2_Packet1(gspca_dev, 0x0028, sd->lighting); - /* color balance rg2 */ - cit_model2_Packet1(gspca_dev, 0x001e, 0x002f); - /* saturation */ - cit_model2_Packet1(gspca_dev, 0x0020, 0x0034); - /* color balance yb */ - cit_model2_Packet1(gspca_dev, 0x0022, 0x00a0); - - /* Hardware control command */ - cit_model2_Packet1(gspca_dev, 0x0030, 0x0004); - - return 0; -} - -static int cit_start_model3(struct gspca_dev *gspca_dev) -{ - const unsigned short compression = 0; /* 0=none, 7=best frame rate */ - int i, clock_div = 0; - - /* HDG not in ibmcam driver, added to see if it helps with - auto-detecting between model3 and ibm netcamera pro */ - cit_read_reg(gspca_dev, 0x128, 1); - - cit_write_reg(gspca_dev, 0x0000, 0x0100); - cit_read_reg(gspca_dev, 0x0116, 0); - cit_write_reg(gspca_dev, 0x0060, 0x0116); - cit_write_reg(gspca_dev, 0x0002, 0x0112); - cit_write_reg(gspca_dev, 0x0000, 0x0123); - cit_write_reg(gspca_dev, 0x0001, 0x0117); - cit_write_reg(gspca_dev, 0x0040, 0x0108); - cit_write_reg(gspca_dev, 0x0019, 0x012c); - cit_write_reg(gspca_dev, 0x0060, 0x0116); - cit_write_reg(gspca_dev, 0x0002, 0x0115); - cit_write_reg(gspca_dev, 0x0003, 0x0115); - cit_read_reg(gspca_dev, 0x0115, 0); - cit_write_reg(gspca_dev, 0x000b, 0x0115); - - /* TESTME HDG not in ibmcam driver, added to see if it helps with - auto-detecting between model3 and ibm netcamera pro */ - if (0) { - cit_write_reg(gspca_dev, 0x0078, 0x012d); - cit_write_reg(gspca_dev, 0x0001, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0079, 0x012d); - cit_write_reg(gspca_dev, 0x00ff, 0x0130); - cit_write_reg(gspca_dev, 0xcd41, 0x0124); - cit_write_reg(gspca_dev, 0xfffa, 0x0124); - cit_read_reg(gspca_dev, 0x0126, 1); - } - - cit_model3_Packet1(gspca_dev, 0x000a, 0x0040); - cit_model3_Packet1(gspca_dev, 0x000b, 0x00f6); - cit_model3_Packet1(gspca_dev, 0x000c, 0x0002); - cit_model3_Packet1(gspca_dev, 0x000d, 0x0020); - cit_model3_Packet1(gspca_dev, 0x000e, 0x0033); - cit_model3_Packet1(gspca_dev, 0x000f, 0x0007); - cit_model3_Packet1(gspca_dev, 0x0010, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0011, 0x0070); - cit_model3_Packet1(gspca_dev, 0x0012, 0x0030); - cit_model3_Packet1(gspca_dev, 0x0013, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0014, 0x0001); - cit_model3_Packet1(gspca_dev, 0x0015, 0x0001); - cit_model3_Packet1(gspca_dev, 0x0016, 0x0001); - cit_model3_Packet1(gspca_dev, 0x0017, 0x0001); - cit_model3_Packet1(gspca_dev, 0x0018, 0x0000); - cit_model3_Packet1(gspca_dev, 0x001e, 0x00c3); - cit_model3_Packet1(gspca_dev, 0x0020, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0028, 0x0010); - cit_model3_Packet1(gspca_dev, 0x0029, 0x0054); - cit_model3_Packet1(gspca_dev, 0x002a, 0x0013); - cit_model3_Packet1(gspca_dev, 0x002b, 0x0007); - cit_model3_Packet1(gspca_dev, 0x002d, 0x0028); - cit_model3_Packet1(gspca_dev, 0x002e, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0031, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0032, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0033, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0034, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0035, 0x0038); - cit_model3_Packet1(gspca_dev, 0x003a, 0x0001); - cit_model3_Packet1(gspca_dev, 0x003c, 0x001e); - cit_model3_Packet1(gspca_dev, 0x003f, 0x000a); - cit_model3_Packet1(gspca_dev, 0x0041, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0046, 0x003f); - cit_model3_Packet1(gspca_dev, 0x0047, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0050, 0x0005); - cit_model3_Packet1(gspca_dev, 0x0052, 0x001a); - cit_model3_Packet1(gspca_dev, 0x0053, 0x0003); - cit_model3_Packet1(gspca_dev, 0x005a, 0x006b); - cit_model3_Packet1(gspca_dev, 0x005d, 0x001e); - cit_model3_Packet1(gspca_dev, 0x005e, 0x0030); - cit_model3_Packet1(gspca_dev, 0x005f, 0x0041); - cit_model3_Packet1(gspca_dev, 0x0064, 0x0008); - cit_model3_Packet1(gspca_dev, 0x0065, 0x0015); - cit_model3_Packet1(gspca_dev, 0x0068, 0x000f); - cit_model3_Packet1(gspca_dev, 0x0079, 0x0000); - cit_model3_Packet1(gspca_dev, 0x007a, 0x0000); - cit_model3_Packet1(gspca_dev, 0x007c, 0x003f); - cit_model3_Packet1(gspca_dev, 0x0082, 0x000f); - cit_model3_Packet1(gspca_dev, 0x0085, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0099, 0x0000); - cit_model3_Packet1(gspca_dev, 0x009b, 0x0023); - cit_model3_Packet1(gspca_dev, 0x009c, 0x0022); - cit_model3_Packet1(gspca_dev, 0x009d, 0x0096); - cit_model3_Packet1(gspca_dev, 0x009e, 0x0096); - cit_model3_Packet1(gspca_dev, 0x009f, 0x000a); - - switch (gspca_dev->width) { - case 160: - cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */ - cit_write_reg(gspca_dev, 0x0024, 0x010b); /* Differs everywhere */ - cit_write_reg(gspca_dev, 0x00a9, 0x0119); - cit_write_reg(gspca_dev, 0x0016, 0x011b); - cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */ - cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */ - cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */ - cit_write_reg(gspca_dev, 0x0018, 0x0102); - cit_write_reg(gspca_dev, 0x0004, 0x0104); - cit_write_reg(gspca_dev, 0x0004, 0x011a); - cit_write_reg(gspca_dev, 0x0028, 0x011c); - cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */ - cit_write_reg(gspca_dev, 0x0000, 0x0118); - cit_write_reg(gspca_dev, 0x0000, 0x0132); - cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */ - cit_write_reg(gspca_dev, compression, 0x0109); - clock_div = 3; - break; - case 320: - cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */ - cit_write_reg(gspca_dev, 0x0028, 0x010b); /* Differs everywhere */ - cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same */ - cit_write_reg(gspca_dev, 0x0000, 0x011e); - cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */ - cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */ - /* 4 commands from 160x120 skipped */ - cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */ - cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */ - cit_write_reg(gspca_dev, compression, 0x0109); - cit_write_reg(gspca_dev, 0x00d9, 0x0119); - cit_write_reg(gspca_dev, 0x0006, 0x011b); - cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ - cit_write_reg(gspca_dev, 0x0010, 0x0104); - cit_write_reg(gspca_dev, 0x0004, 0x011a); - cit_write_reg(gspca_dev, 0x003f, 0x011c); - cit_write_reg(gspca_dev, 0x001c, 0x0118); - cit_write_reg(gspca_dev, 0x0000, 0x0132); - clock_div = 5; - break; - case 640: - cit_write_reg(gspca_dev, 0x00f0, 0x0105); - cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */ - cit_write_reg(gspca_dev, 0x0038, 0x010b); /* Differs everywhere */ - cit_write_reg(gspca_dev, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */ - cit_write_reg(gspca_dev, 0x0006, 0x011b); /* Same on 320x240, 640x480 */ - cit_write_reg(gspca_dev, 0x0004, 0x011d); /* NC */ - cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */ - cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */ - cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */ - cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ - cit_write_reg(gspca_dev, 0x0016, 0x0104); /* NC */ - cit_write_reg(gspca_dev, 0x0004, 0x011a); /* Same on 320x240, 640x480 */ - cit_write_reg(gspca_dev, 0x003f, 0x011c); /* Same on 320x240, 640x480 */ - cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */ - cit_write_reg(gspca_dev, 0x001c, 0x0118); /* Same on 320x240, 640x480 */ - cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */ - cit_write_reg(gspca_dev, compression, 0x0109); - cit_write_reg(gspca_dev, 0x0040, 0x0101); - cit_write_reg(gspca_dev, 0x0040, 0x0103); - cit_write_reg(gspca_dev, 0x0000, 0x0132); /* Same on 320x240, 640x480 */ - clock_div = 7; - break; - } - - cit_model3_Packet1(gspca_dev, 0x007e, 0x000e); /* Hue */ - cit_model3_Packet1(gspca_dev, 0x0036, 0x0011); /* Brightness */ - cit_model3_Packet1(gspca_dev, 0x0060, 0x0002); /* Sharpness */ - cit_model3_Packet1(gspca_dev, 0x0061, 0x0004); /* Sharpness */ - cit_model3_Packet1(gspca_dev, 0x0062, 0x0005); /* Sharpness */ - cit_model3_Packet1(gspca_dev, 0x0063, 0x0014); /* Sharpness */ - cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0); /* Red sharpness */ - cit_model3_Packet1(gspca_dev, 0x0097, 0x0096); /* Blue sharpness */ - cit_model3_Packet1(gspca_dev, 0x0067, 0x0001); /* Contrast */ - cit_model3_Packet1(gspca_dev, 0x005b, 0x000c); /* Contrast */ - cit_model3_Packet1(gspca_dev, 0x005c, 0x0016); /* Contrast */ - cit_model3_Packet1(gspca_dev, 0x0098, 0x000b); - cit_model3_Packet1(gspca_dev, 0x002c, 0x0003); /* Was 1, broke 640x480 */ - cit_model3_Packet1(gspca_dev, 0x002f, 0x002a); - cit_model3_Packet1(gspca_dev, 0x0030, 0x0029); - cit_model3_Packet1(gspca_dev, 0x0037, 0x0002); - cit_model3_Packet1(gspca_dev, 0x0038, 0x0059); - cit_model3_Packet1(gspca_dev, 0x003d, 0x002e); - cit_model3_Packet1(gspca_dev, 0x003e, 0x0028); - cit_model3_Packet1(gspca_dev, 0x0078, 0x0005); - cit_model3_Packet1(gspca_dev, 0x007b, 0x0011); - cit_model3_Packet1(gspca_dev, 0x007d, 0x004b); - cit_model3_Packet1(gspca_dev, 0x007f, 0x0022); - cit_model3_Packet1(gspca_dev, 0x0080, 0x000c); - cit_model3_Packet1(gspca_dev, 0x0081, 0x000b); - cit_model3_Packet1(gspca_dev, 0x0083, 0x00fd); - cit_model3_Packet1(gspca_dev, 0x0086, 0x000b); - cit_model3_Packet1(gspca_dev, 0x0087, 0x000b); - cit_model3_Packet1(gspca_dev, 0x007e, 0x000e); - cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0); /* Red sharpness */ - cit_model3_Packet1(gspca_dev, 0x0097, 0x0096); /* Blue sharpness */ - cit_model3_Packet1(gspca_dev, 0x0098, 0x000b); - - /* FIXME we should probably use cit_get_clock_div() here (in - combination with isoc negotiation using the programmable isoc size) - like with the IBM netcam pro). */ - cit_write_reg(gspca_dev, clock_div, 0x0111); /* Clock Divider */ - - switch (gspca_dev->width) { - case 160: - cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */ - cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */ - cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */ - cit_model3_Packet1(gspca_dev, 0x0040, 0x000a); - cit_model3_Packet1(gspca_dev, 0x0051, 0x000a); - break; - case 320: - cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */ - cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */ - cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */ - cit_model3_Packet1(gspca_dev, 0x0040, 0x0008); - cit_model3_Packet1(gspca_dev, 0x0051, 0x000b); - break; - case 640: - cit_model3_Packet1(gspca_dev, 0x001f, 0x0002); /* !Same */ - cit_model3_Packet1(gspca_dev, 0x0039, 0x003e); /* !Same */ - cit_model3_Packet1(gspca_dev, 0x0040, 0x0008); - cit_model3_Packet1(gspca_dev, 0x0051, 0x000a); - break; - } - -/* if (sd->input_index) { */ - if (rca_input) { - for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) { - if (rca_initdata[i][0]) - cit_read_reg(gspca_dev, rca_initdata[i][2], 0); - else - cit_write_reg(gspca_dev, rca_initdata[i][1], - rca_initdata[i][2]); - } - } - - return 0; -} - -static int cit_start_model4(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - cit_write_reg(gspca_dev, 0x0000, 0x0100); - cit_write_reg(gspca_dev, 0x00c0, 0x0111); - cit_write_reg(gspca_dev, 0x00bc, 0x012c); - cit_write_reg(gspca_dev, 0x0080, 0x012b); - cit_write_reg(gspca_dev, 0x0000, 0x0108); - cit_write_reg(gspca_dev, 0x0001, 0x0133); - cit_write_reg(gspca_dev, 0x009b, 0x010f); - cit_write_reg(gspca_dev, 0x00bb, 0x010f); - cit_model4_Packet1(gspca_dev, 0x0038, 0x0000); - cit_model4_Packet1(gspca_dev, 0x000a, 0x005c); - - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0004, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0000, 0x0127); - cit_write_reg(gspca_dev, 0x00fb, 0x012e); - cit_write_reg(gspca_dev, 0x0000, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012f); - cit_write_reg(gspca_dev, 0xd055, 0x0124); - cit_write_reg(gspca_dev, 0x000c, 0x0127); - cit_write_reg(gspca_dev, 0x0009, 0x012e); - cit_write_reg(gspca_dev, 0xaa28, 0x0124); - - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0012, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0008, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x002a, 0x012d); - cit_write_reg(gspca_dev, 0x0000, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0xfffa, 0x0124); - cit_model4_Packet1(gspca_dev, 0x0034, 0x0000); - - switch (gspca_dev->width) { - case 128: /* 128x96 */ - cit_write_reg(gspca_dev, 0x0070, 0x0119); - cit_write_reg(gspca_dev, 0x00d0, 0x0111); - cit_write_reg(gspca_dev, 0x0039, 0x010a); - cit_write_reg(gspca_dev, 0x0001, 0x0102); - cit_write_reg(gspca_dev, 0x0028, 0x0103); - cit_write_reg(gspca_dev, 0x0000, 0x0104); - cit_write_reg(gspca_dev, 0x001e, 0x0105); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0016, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x000a, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0014, 0x012d); - cit_write_reg(gspca_dev, 0x0008, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012e); - cit_write_reg(gspca_dev, 0x001a, 0x0130); - cit_write_reg(gspca_dev, 0x8a0a, 0x0124); - cit_write_reg(gspca_dev, 0x005a, 0x012d); - cit_write_reg(gspca_dev, 0x9545, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x0127); - cit_write_reg(gspca_dev, 0x0018, 0x012e); - cit_write_reg(gspca_dev, 0x0043, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012f); - cit_write_reg(gspca_dev, 0xd055, 0x0124); - cit_write_reg(gspca_dev, 0x001c, 0x0127); - cit_write_reg(gspca_dev, 0x00eb, 0x012e); - cit_write_reg(gspca_dev, 0xaa28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0032, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0000, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0036, 0x012d); - cit_write_reg(gspca_dev, 0x0008, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0xfffa, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x001e, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0017, 0x0127); - cit_write_reg(gspca_dev, 0x0013, 0x012e); - cit_write_reg(gspca_dev, 0x0031, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x0017, 0x012d); - cit_write_reg(gspca_dev, 0x0078, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x0000, 0x0127); - cit_write_reg(gspca_dev, 0xfea8, 0x0124); - sd->sof_len = 2; - break; - case 160: /* 160x120 */ - cit_write_reg(gspca_dev, 0x0038, 0x0119); - cit_write_reg(gspca_dev, 0x00d0, 0x0111); - cit_write_reg(gspca_dev, 0x00b9, 0x010a); - cit_write_reg(gspca_dev, 0x0001, 0x0102); - cit_write_reg(gspca_dev, 0x0028, 0x0103); - cit_write_reg(gspca_dev, 0x0000, 0x0104); - cit_write_reg(gspca_dev, 0x001e, 0x0105); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0016, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x000b, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0014, 0x012d); - cit_write_reg(gspca_dev, 0x0008, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012e); - cit_write_reg(gspca_dev, 0x001a, 0x0130); - cit_write_reg(gspca_dev, 0x8a0a, 0x0124); - cit_write_reg(gspca_dev, 0x005a, 0x012d); - cit_write_reg(gspca_dev, 0x9545, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x0127); - cit_write_reg(gspca_dev, 0x0018, 0x012e); - cit_write_reg(gspca_dev, 0x0043, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012f); - cit_write_reg(gspca_dev, 0xd055, 0x0124); - cit_write_reg(gspca_dev, 0x001c, 0x0127); - cit_write_reg(gspca_dev, 0x00c7, 0x012e); - cit_write_reg(gspca_dev, 0xaa28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0032, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0025, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0036, 0x012d); - cit_write_reg(gspca_dev, 0x0008, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0xfffa, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x001e, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0048, 0x0127); - cit_write_reg(gspca_dev, 0x0035, 0x012e); - cit_write_reg(gspca_dev, 0x00d0, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x0048, 0x012d); - cit_write_reg(gspca_dev, 0x0090, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x0001, 0x0127); - cit_write_reg(gspca_dev, 0xfea8, 0x0124); - sd->sof_len = 2; - break; - case 176: /* 176x144 */ - cit_write_reg(gspca_dev, 0x0038, 0x0119); - cit_write_reg(gspca_dev, 0x00d0, 0x0111); - cit_write_reg(gspca_dev, 0x00b9, 0x010a); - cit_write_reg(gspca_dev, 0x0001, 0x0102); - cit_write_reg(gspca_dev, 0x002c, 0x0103); - cit_write_reg(gspca_dev, 0x0000, 0x0104); - cit_write_reg(gspca_dev, 0x0024, 0x0105); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0016, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0007, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0014, 0x012d); - cit_write_reg(gspca_dev, 0x0001, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012e); - cit_write_reg(gspca_dev, 0x001a, 0x0130); - cit_write_reg(gspca_dev, 0x8a0a, 0x0124); - cit_write_reg(gspca_dev, 0x005e, 0x012d); - cit_write_reg(gspca_dev, 0x9545, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x0127); - cit_write_reg(gspca_dev, 0x0018, 0x012e); - cit_write_reg(gspca_dev, 0x0049, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012f); - cit_write_reg(gspca_dev, 0xd055, 0x0124); - cit_write_reg(gspca_dev, 0x001c, 0x0127); - cit_write_reg(gspca_dev, 0x00c7, 0x012e); - cit_write_reg(gspca_dev, 0xaa28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0032, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0028, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0036, 0x012d); - cit_write_reg(gspca_dev, 0x0008, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0xfffa, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x001e, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0010, 0x0127); - cit_write_reg(gspca_dev, 0x0013, 0x012e); - cit_write_reg(gspca_dev, 0x002a, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x0010, 0x012d); - cit_write_reg(gspca_dev, 0x006d, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x0001, 0x0127); - cit_write_reg(gspca_dev, 0xfea8, 0x0124); - /* TESTME HDG: this does not seem right - (it is 2 for all other resolutions) */ - sd->sof_len = 10; - break; - case 320: /* 320x240 */ - cit_write_reg(gspca_dev, 0x0070, 0x0119); - cit_write_reg(gspca_dev, 0x00d0, 0x0111); - cit_write_reg(gspca_dev, 0x0039, 0x010a); - cit_write_reg(gspca_dev, 0x0001, 0x0102); - cit_write_reg(gspca_dev, 0x0028, 0x0103); - cit_write_reg(gspca_dev, 0x0000, 0x0104); - cit_write_reg(gspca_dev, 0x001e, 0x0105); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0016, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x000a, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0014, 0x012d); - cit_write_reg(gspca_dev, 0x0008, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012e); - cit_write_reg(gspca_dev, 0x001a, 0x0130); - cit_write_reg(gspca_dev, 0x8a0a, 0x0124); - cit_write_reg(gspca_dev, 0x005a, 0x012d); - cit_write_reg(gspca_dev, 0x9545, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x0127); - cit_write_reg(gspca_dev, 0x0018, 0x012e); - cit_write_reg(gspca_dev, 0x0043, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012f); - cit_write_reg(gspca_dev, 0xd055, 0x0124); - cit_write_reg(gspca_dev, 0x001c, 0x0127); - cit_write_reg(gspca_dev, 0x00eb, 0x012e); - cit_write_reg(gspca_dev, 0xaa28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0032, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0000, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0036, 0x012d); - cit_write_reg(gspca_dev, 0x0008, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0xfffa, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x001e, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0017, 0x0127); - cit_write_reg(gspca_dev, 0x0013, 0x012e); - cit_write_reg(gspca_dev, 0x0031, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x0017, 0x012d); - cit_write_reg(gspca_dev, 0x0078, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x0000, 0x0127); - cit_write_reg(gspca_dev, 0xfea8, 0x0124); - sd->sof_len = 2; - break; - case 352: /* 352x288 */ - cit_write_reg(gspca_dev, 0x0070, 0x0119); - cit_write_reg(gspca_dev, 0x00c0, 0x0111); - cit_write_reg(gspca_dev, 0x0039, 0x010a); - cit_write_reg(gspca_dev, 0x0001, 0x0102); - cit_write_reg(gspca_dev, 0x002c, 0x0103); - cit_write_reg(gspca_dev, 0x0000, 0x0104); - cit_write_reg(gspca_dev, 0x0024, 0x0105); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0016, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0006, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0014, 0x012d); - cit_write_reg(gspca_dev, 0x0002, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012e); - cit_write_reg(gspca_dev, 0x001a, 0x0130); - cit_write_reg(gspca_dev, 0x8a0a, 0x0124); - cit_write_reg(gspca_dev, 0x005e, 0x012d); - cit_write_reg(gspca_dev, 0x9545, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x0127); - cit_write_reg(gspca_dev, 0x0018, 0x012e); - cit_write_reg(gspca_dev, 0x0049, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012f); - cit_write_reg(gspca_dev, 0xd055, 0x0124); - cit_write_reg(gspca_dev, 0x001c, 0x0127); - cit_write_reg(gspca_dev, 0x00cf, 0x012e); - cit_write_reg(gspca_dev, 0xaa28, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x0032, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0000, 0x0127); - cit_write_reg(gspca_dev, 0x00aa, 0x0130); - cit_write_reg(gspca_dev, 0x82a8, 0x0124); - cit_write_reg(gspca_dev, 0x0036, 0x012d); - cit_write_reg(gspca_dev, 0x0008, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0xfffa, 0x0124); - cit_write_reg(gspca_dev, 0x00aa, 0x012d); - cit_write_reg(gspca_dev, 0x001e, 0x012f); - cit_write_reg(gspca_dev, 0xd141, 0x0124); - cit_write_reg(gspca_dev, 0x0010, 0x0127); - cit_write_reg(gspca_dev, 0x0013, 0x012e); - cit_write_reg(gspca_dev, 0x0025, 0x0130); - cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, 0x0010, 0x012d); - cit_write_reg(gspca_dev, 0x0048, 0x012f); - cit_write_reg(gspca_dev, 0xd145, 0x0124); - cit_write_reg(gspca_dev, 0x0000, 0x0127); - cit_write_reg(gspca_dev, 0xfea8, 0x0124); - sd->sof_len = 2; - break; - } - - cit_model4_Packet1(gspca_dev, 0x0038, 0x0004); - - return 0; -} - -static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev) -{ - const unsigned short compression = 0; /* 0=none, 7=best frame rate */ - int i, clock_div; - - clock_div = cit_get_clock_div(gspca_dev); - if (clock_div < 0) - return clock_div; - - cit_write_reg(gspca_dev, 0x0003, 0x0133); - cit_write_reg(gspca_dev, 0x0000, 0x0117); - cit_write_reg(gspca_dev, 0x0008, 0x0123); - cit_write_reg(gspca_dev, 0x0000, 0x0100); - cit_write_reg(gspca_dev, 0x0060, 0x0116); - /* cit_write_reg(gspca_dev, 0x0002, 0x0112); see sd_stop0 */ - cit_write_reg(gspca_dev, 0x0000, 0x0133); - cit_write_reg(gspca_dev, 0x0000, 0x0123); - cit_write_reg(gspca_dev, 0x0001, 0x0117); - cit_write_reg(gspca_dev, 0x0040, 0x0108); - cit_write_reg(gspca_dev, 0x0019, 0x012c); - cit_write_reg(gspca_dev, 0x0060, 0x0116); - /* cit_write_reg(gspca_dev, 0x000b, 0x0115); see sd_stop0 */ - - cit_model3_Packet1(gspca_dev, 0x0049, 0x0000); - - cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x003a, 0x0102); /* Hstart */ - cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */ - cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */ - cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */ - cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */ - cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */ - - switch (gspca_dev->width) { - case 160: /* 160x120 */ - cit_write_reg(gspca_dev, 0x0024, 0x010b); - cit_write_reg(gspca_dev, 0x0089, 0x0119); - cit_write_reg(gspca_dev, 0x000a, 0x011b); - cit_write_reg(gspca_dev, 0x0003, 0x011e); - cit_write_reg(gspca_dev, 0x0007, 0x0104); - cit_write_reg(gspca_dev, 0x0009, 0x011a); - cit_write_reg(gspca_dev, 0x008b, 0x011c); - cit_write_reg(gspca_dev, 0x0008, 0x0118); - cit_write_reg(gspca_dev, 0x0000, 0x0132); - break; - case 320: /* 320x240 */ - cit_write_reg(gspca_dev, 0x0028, 0x010b); - cit_write_reg(gspca_dev, 0x00d9, 0x0119); - cit_write_reg(gspca_dev, 0x0006, 0x011b); - cit_write_reg(gspca_dev, 0x0000, 0x011e); - cit_write_reg(gspca_dev, 0x000e, 0x0104); - cit_write_reg(gspca_dev, 0x0004, 0x011a); - cit_write_reg(gspca_dev, 0x003f, 0x011c); - cit_write_reg(gspca_dev, 0x000c, 0x0118); - cit_write_reg(gspca_dev, 0x0000, 0x0132); - break; - } - - cit_model3_Packet1(gspca_dev, 0x0019, 0x0031); - cit_model3_Packet1(gspca_dev, 0x001a, 0x0003); - cit_model3_Packet1(gspca_dev, 0x001b, 0x0038); - cit_model3_Packet1(gspca_dev, 0x001c, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0024, 0x0001); - cit_model3_Packet1(gspca_dev, 0x0027, 0x0001); - cit_model3_Packet1(gspca_dev, 0x002a, 0x0004); - cit_model3_Packet1(gspca_dev, 0x0035, 0x000b); - cit_model3_Packet1(gspca_dev, 0x003f, 0x0001); - cit_model3_Packet1(gspca_dev, 0x0044, 0x0000); - cit_model3_Packet1(gspca_dev, 0x0054, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00c4, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00e7, 0x0001); - cit_model3_Packet1(gspca_dev, 0x00e9, 0x0001); - cit_model3_Packet1(gspca_dev, 0x00ee, 0x0000); - cit_model3_Packet1(gspca_dev, 0x00f3, 0x00c0); - - cit_write_reg(gspca_dev, compression, 0x0109); - cit_write_reg(gspca_dev, clock_div, 0x0111); - -/* if (sd->input_index) { */ - if (rca_input) { - for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) { - if (rca_initdata[i][0]) - cit_read_reg(gspca_dev, rca_initdata[i][2], 0); - else - cit_write_reg(gspca_dev, rca_initdata[i][1], - rca_initdata[i][2]); - } - } - - return 0; -} - -/* -- start the camera -- */ -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int packet_size; - - packet_size = cit_get_packet_size(gspca_dev); - if (packet_size < 0) - return packet_size; - - switch (sd->model) { - case CIT_MODEL0: - cit_start_model0(gspca_dev); - break; - case CIT_MODEL1: - cit_start_model1(gspca_dev); - break; - case CIT_MODEL2: - cit_start_model2(gspca_dev); - break; - case CIT_MODEL3: - cit_start_model3(gspca_dev); - break; - case CIT_MODEL4: - cit_start_model4(gspca_dev); - break; - case CIT_IBM_NETCAM_PRO: - cit_start_ibm_netcam_pro(gspca_dev); - break; - } - - cit_set_brightness(gspca_dev); - cit_set_contrast(gspca_dev); - cit_set_hue(gspca_dev); - cit_set_sharpness(gspca_dev); - cit_set_lighting(gspca_dev); - cit_set_hflip(gspca_dev); - - /* Program max isoc packet size */ - cit_write_reg(gspca_dev, packet_size >> 8, 0x0106); - cit_write_reg(gspca_dev, packet_size & 0xff, 0x0107); - - cit_restart_stream(gspca_dev); - - return 0; -} - -static int sd_isoc_init(struct gspca_dev *gspca_dev) -{ - struct usb_host_interface *alt; - int max_packet_size; - - switch (gspca_dev->width) { - case 160: - max_packet_size = 450; - break; - case 176: - max_packet_size = 600; - break; - default: - max_packet_size = 1022; - break; - } - - /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; - alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size); - - return 0; -} - -static int sd_isoc_nego(struct gspca_dev *gspca_dev) -{ - int ret, packet_size, min_packet_size; - struct usb_host_interface *alt; - - switch (gspca_dev->width) { - case 160: - min_packet_size = 200; - break; - case 176: - min_packet_size = 266; - break; - default: - min_packet_size = 400; - break; - } - - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; - packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); - if (packet_size <= min_packet_size) - return -EIO; - - packet_size -= 100; - if (packet_size < min_packet_size) - packet_size = min_packet_size; - alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size); - - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); - if (ret < 0) - err("set alt 1 err %d", ret); - - return ret; -} - -static void sd_stopN(struct gspca_dev *gspca_dev) -{ - cit_write_reg(gspca_dev, 0x0000, 0x010c); -} - -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* We cannot use gspca_dev->present here as that is not set when - sd_init gets called and we get called from sd_init */ - if (!gspca_dev->dev) - return; - - switch (sd->model) { - case CIT_MODEL0: - /* HDG windows does this, but it causes the cams autogain to - restart from a gain of 0, which does not look good when - changing resolutions. */ - /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */ - cit_write_reg(gspca_dev, 0x00c0, 0x0100); /* LED Off */ - break; - case CIT_MODEL1: - cit_send_FF_04_02(gspca_dev); - cit_read_reg(gspca_dev, 0x0100, 0); - cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */ - break; - case CIT_MODEL2: - case CIT_MODEL4: - cit_model2_Packet1(gspca_dev, 0x0030, 0x0004); - - cit_write_reg(gspca_dev, 0x0080, 0x0100); /* LED Off */ - cit_write_reg(gspca_dev, 0x0020, 0x0111); - cit_write_reg(gspca_dev, 0x00a0, 0x0111); - - cit_model2_Packet1(gspca_dev, 0x0030, 0x0002); - - cit_write_reg(gspca_dev, 0x0020, 0x0111); - cit_write_reg(gspca_dev, 0x0000, 0x0112); - break; - case CIT_MODEL3: - cit_write_reg(gspca_dev, 0x0006, 0x012c); - cit_model3_Packet1(gspca_dev, 0x0046, 0x0000); - cit_read_reg(gspca_dev, 0x0116, 0); - cit_write_reg(gspca_dev, 0x0064, 0x0116); - cit_read_reg(gspca_dev, 0x0115, 0); - cit_write_reg(gspca_dev, 0x0003, 0x0115); - cit_write_reg(gspca_dev, 0x0008, 0x0123); - cit_write_reg(gspca_dev, 0x0000, 0x0117); - cit_write_reg(gspca_dev, 0x0000, 0x0112); - cit_write_reg(gspca_dev, 0x0080, 0x0100); - break; - case CIT_IBM_NETCAM_PRO: - cit_model3_Packet1(gspca_dev, 0x0049, 0x00ff); - cit_write_reg(gspca_dev, 0x0006, 0x012c); - cit_write_reg(gspca_dev, 0x0000, 0x0116); - /* HDG windows does this, but I cannot get the camera - to restart with this without redoing the entire init - sequence which makes switching modes really slow */ - /* cit_write_reg(gspca_dev, 0x0006, 0x0115); */ - cit_write_reg(gspca_dev, 0x0008, 0x0123); - cit_write_reg(gspca_dev, 0x0000, 0x0117); - cit_write_reg(gspca_dev, 0x0003, 0x0133); - cit_write_reg(gspca_dev, 0x0000, 0x0111); - /* HDG windows does this, but I get a green picture when - restarting the stream after this */ - /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */ - cit_write_reg(gspca_dev, 0x00c0, 0x0100); - break; - } - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - /* If the last button state is pressed, release it now! */ - if (sd->button_state) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - sd->button_state = 0; - } -#endif -} - -static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 byte3 = 0, byte4 = 0; - int i; - - switch (sd->model) { - case CIT_MODEL0: - case CIT_MODEL1: - case CIT_MODEL3: - case CIT_IBM_NETCAM_PRO: - switch (gspca_dev->width) { - case 160: /* 160x120 */ - byte3 = 0x02; - byte4 = 0x0a; - break; - case 176: /* 176x144 */ - byte3 = 0x02; - byte4 = 0x0e; - break; - case 320: /* 320x240 */ - byte3 = 0x02; - byte4 = 0x08; - break; - case 352: /* 352x288 */ - byte3 = 0x02; - byte4 = 0x00; - break; - case 640: - byte3 = 0x03; - byte4 = 0x08; - break; - } - - /* These have a different byte3 */ - if (sd->model <= CIT_MODEL1) - byte3 = 0x00; - - for (i = 0; i < len; i++) { - /* For this model the SOF always starts at offset 0 - so no need to search the entire frame */ - if (sd->model == CIT_MODEL0 && sd->sof_read != i) - break; - - switch (sd->sof_read) { - case 0: - if (data[i] == 0x00) - sd->sof_read++; - break; - case 1: - if (data[i] == 0xff) - sd->sof_read++; - else if (data[i] == 0x00) - sd->sof_read = 1; - else - sd->sof_read = 0; - break; - case 2: - if (data[i] == byte3) - sd->sof_read++; - else if (data[i] == 0x00) - sd->sof_read = 1; - else - sd->sof_read = 0; - break; - case 3: - if (data[i] == byte4) { - sd->sof_read = 0; - return data + i + (sd->sof_len - 3); - } - if (byte3 == 0x00 && data[i] == 0xff) - sd->sof_read = 2; - else if (data[i] == 0x00) - sd->sof_read = 1; - else - sd->sof_read = 0; - break; - } - } - break; - case CIT_MODEL2: - case CIT_MODEL4: - /* TESTME we need to find a longer sof signature to avoid - false positives */ - for (i = 0; i < len; i++) { - switch (sd->sof_read) { - case 0: - if (data[i] == 0x00) - sd->sof_read++; - break; - case 1: - sd->sof_read = 0; - if (data[i] == 0xff) { - if (i >= 4) - PDEBUG(D_FRAM, - "header found at offset: %d: %02x %02x 00 %02x %02x %02x\n", - i - 1, - data[i - 4], - data[i - 3], - data[i], - data[i + 1], - data[i + 2]); - else - PDEBUG(D_FRAM, - "header found at offset: %d: 00 %02x %02x %02x\n", - i - 1, - data[i], - data[i + 1], - data[i + 2]); - return data + i + (sd->sof_len - 1); - } - break; - } - } - break; - } - return NULL; -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - unsigned char *sof; - - sof = cit_find_sof(gspca_dev, data, len); - if (sof) { - int n; - - /* finish decoding current frame */ - n = sof - data; - if (n > sd->sof_len) - n -= sd->sof_len; - else - n = 0; - gspca_frame_add(gspca_dev, LAST_PACKET, - data, n); - gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); - len -= sof - data; - data = sof; - } - - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_brightness(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_contrast(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - - return 0; -} - -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hue = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_hue(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - return 0; -} - -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hue; - - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_sharpness(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - return 0; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - - return 0; -} - -static int sd_setlighting(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->lighting = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_lighting(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - return 0; -} - -static int sd_getlighting(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->lighting; - - return 0; -} - -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hflip = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_hflip(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - return 0; -} - -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hflip; - - return 0; -} - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static void cit_check_button(struct gspca_dev *gspca_dev) -{ - int new_button_state; - struct sd *sd = (struct sd *)gspca_dev; - - switch (sd->model) { - case CIT_MODEL3: - case CIT_IBM_NETCAM_PRO: - break; - default: /* TEST ME unknown if this works on other models too */ - return; - } - - /* Read the button state */ - cit_read_reg(gspca_dev, 0x0113, 0); - new_button_state = !gspca_dev->usb_buf[0]; - - /* Tell the cam we've seen the button press, notice that this - is a nop (iow the cam keeps reporting pressed) until the - button is actually released. */ - if (new_button_state) - cit_write_reg(gspca_dev, 0x01, 0x0113); - - if (sd->button_state != new_button_state) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, - new_button_state); - input_sync(gspca_dev->input_dev); - sd->button_state = new_button_state; - } -} -#endif - -/* sub-driver description */ -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .dq_callback = cit_check_button, - .other_input = 1, -#endif -}; - -static const struct sd_desc sd_desc_isoc_nego = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .isoc_init = sd_isoc_init, - .isoc_nego = sd_isoc_nego, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .dq_callback = cit_check_button, - .other_input = 1, -#endif -}; - -/* -- module initialisation -- */ -static const struct usb_device_id device_table[] = { - { USB_DEVICE_VER(0x0545, 0x8080, 0x0001, 0x0001), .driver_info = CIT_MODEL0 }, - { USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002), .driver_info = CIT_MODEL1 }, - { USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a), .driver_info = CIT_MODEL2 }, - { USB_DEVICE_VER(0x0545, 0x8080, 0x0301, 0x0301), .driver_info = CIT_MODEL3 }, - { USB_DEVICE_VER(0x0545, 0x8002, 0x030a, 0x030a), .driver_info = CIT_MODEL4 }, - { USB_DEVICE_VER(0x0545, 0x800c, 0x030a, 0x030a), .driver_info = CIT_MODEL2 }, - { USB_DEVICE_VER(0x0545, 0x800d, 0x030a, 0x030a), .driver_info = CIT_MODEL4 }, - {} -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - const struct sd_desc *desc = &sd_desc; - - switch (id->driver_info) { - case CIT_MODEL0: - case CIT_MODEL1: - if (intf->cur_altsetting->desc.bInterfaceNumber != 2) - return -ENODEV; - break; - case CIT_MODEL2: - case CIT_MODEL4: - if (intf->cur_altsetting->desc.bInterfaceNumber != 0) - return -ENODEV; - break; - case CIT_MODEL3: - if (intf->cur_altsetting->desc.bInterfaceNumber != 0) - return -ENODEV; - /* FIXME this likely applies to all model3 cams and probably - to other models too. */ - if (ibm_netcam_pro) - desc = &sd_desc_isoc_nego; - break; - } - - return gspca_dev_probe2(intf, id, desc, sizeof(struct sd), THIS_MODULE); -} - -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -/* -- module insert / remove -- */ -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/zc3xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/zc3xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/zc3xx.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/zc3xx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,7092 +0,0 @@ -/* - * Z-Star/Vimicro zc301/zc302p/vc30x library - * - * Copyright (C) 2009-2011 Jean-Francois Moine - * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define MODULE_NAME "zc3xx" - -#include -#include "gspca.h" -#include "jpeg.h" - -MODULE_AUTHOR("Jean-Francois Moine , " - "Serge A. Suchkov "); -MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver"); -MODULE_LICENSE("GPL"); - -static int force_sensor = -1; - -#define QUANT_VAL 1 /* quantization table */ -#include "zc3xx-reg.h" - -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - EXPOSURE, - GAMMA, - AUTOGAIN, - LIGHTFREQ, - SHARPNESS, - NCTRLS /* number of controls */ -}; - -#define AUTOGAIN_DEF 1 - -/* specific webcam descriptor */ -struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRLS]; - - u8 quality; /* image quality */ -#define QUALITY_MIN 50 -#define QUALITY_MAX 80 -#define QUALITY_DEF 70 - - u8 bridge; - u8 sensor; /* Type of image sensor chip */ - u16 chip_revision; - - u8 jpeg_hdr[JPEG_HDR_SZ]; -}; -enum bridges { - BRIDGE_ZC301, - BRIDGE_ZC303, -}; -enum sensors { - SENSOR_ADCM2700, - SENSOR_CS2102, - SENSOR_CS2102K, - SENSOR_GC0303, - SENSOR_GC0305, - SENSOR_HDCS2020, - SENSOR_HV7131B, - SENSOR_HV7131R, - SENSOR_ICM105A, - SENSOR_MC501CB, - SENSOR_MT9V111_1, /* (mi360soc) zc301 */ - SENSOR_MT9V111_3, /* (mi360soc) zc303 */ - SENSOR_OV7620, /* OV7648 - same values */ - SENSOR_OV7630C, - SENSOR_PAS106, - SENSOR_PAS202B, - SENSOR_PB0330, - SENSOR_PO2030, - SENSOR_TAS5130C, - SENSOR_MAX -}; - -/* V4L2 controls supported by the driver */ -static void setcontrast(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static void setlightfreq(struct gspca_dev *gspca_dev); -static void setsharpness(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128, - }, - .set_control = setcontrast - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128, - }, - .set_control = setcontrast - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0x30d, - .maximum = 0x493e, - .step = 1, - .default_value = 0x927 - }, - .set_control = setexposure - }, -[GAMMA] = { - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 1, - .maximum = 6, - .step = 1, - .default_value = 4, - }, - .set_control = setcontrast - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = AUTOGAIN_DEF, - .flags = V4L2_CTRL_FLAG_UPDATE - }, - .set = sd_setautogain - }, -[LIGHTFREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, - .default_value = 0, - }, - .set_control = setlightfreq - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 2, - }, - .set_control = setsharpness - }, -}; - -static const struct v4l2_pix_format vga_mode[] = { - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -static const struct v4l2_pix_format broken_vga_mode[] = { - {320, 232, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 232 * 4 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {640, 472, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 640, - .sizeimage = 640 * 472 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -static const struct v4l2_pix_format sif_mode[] = { - {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 1}, - {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, - .priv = 0}, -}; - -/* usb exchanges */ -struct usb_action { - u8 req; - u8 val; - u16 idx; -}; - -static const struct usb_action adcm2700_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */ - {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */ - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ - {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */ - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x58, ZC3XX_R116_RGAIN}, /* 01,16,58,cc */ - {0xa0, 0x5a, ZC3XX_R118_BGAIN}, /* 01,18,5a,cc */ - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ - {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */ - {0xbb, 0x00, 0x0408}, /* 04,00,08,bb */ - {0xdd, 0x00, 0x0200}, /* 00,02,00,dd */ - {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */ - {0xbb, 0xe0, 0x0c2e}, /* 0c,e0,2e,bb */ - {0xbb, 0x01, 0x2000}, /* 20,01,00,bb */ - {0xbb, 0x96, 0x2400}, /* 24,96,00,bb */ - {0xbb, 0x06, 0x1006}, /* 10,06,06,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xbb, 0x5f, 0x2090}, /* 20,5f,90,bb */ - {0xbb, 0x01, 0x8000}, /* 80,01,00,bb */ - {0xbb, 0x09, 0x8400}, /* 84,09,00,bb */ - {0xbb, 0x86, 0x0002}, /* 00,86,02,bb */ - {0xbb, 0xe6, 0x0401}, /* 04,e6,01,bb */ - {0xbb, 0x86, 0x0802}, /* 08,86,02,bb */ - {0xbb, 0xe6, 0x0c01}, /* 0c,e6,01,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0020}, /* 00,fe,20,aa */ -/*mswin+*/ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, - {0xaa, 0xfe, 0x0002}, - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, - {0xaa, 0xb4, 0xcd37}, - {0xaa, 0xa4, 0x0004}, - {0xaa, 0xa8, 0x0007}, - {0xaa, 0xac, 0x0004}, -/*mswin-*/ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xbb, 0x04, 0x0400}, /* 04,04,00,bb */ - {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ - {0xbb, 0x01, 0x0400}, /* 04,01,00,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xbb, 0x41, 0x2803}, /* 28,41,03,bb */ - {0xbb, 0x40, 0x2c03}, /* 2c,40,03,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ - {} -}; -static const struct usb_action adcm2700_InitialScale[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ - {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */ - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ - {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */ - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x58, ZC3XX_R116_RGAIN}, /* 01,16,58,cc */ - {0xa0, 0x5a, ZC3XX_R118_BGAIN}, /* 01,18,5a,cc */ - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ - {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */ - {0xbb, 0x00, 0x0408}, /* 04,00,08,bb */ - {0xdd, 0x00, 0x0200}, /* 00,02,00,dd */ - {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */ - {0xdd, 0x00, 0x0050}, /* 00,00,50,dd */ - {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */ - {0xbb, 0xe0, 0x0c2e}, /* 0c,e0,2e,bb */ - {0xbb, 0x01, 0x2000}, /* 20,01,00,bb */ - {0xbb, 0x96, 0x2400}, /* 24,96,00,bb */ - {0xbb, 0x06, 0x1006}, /* 10,06,06,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xbb, 0x5f, 0x2090}, /* 20,5f,90,bb */ - {0xbb, 0x01, 0x8000}, /* 80,01,00,bb */ - {0xbb, 0x09, 0x8400}, /* 84,09,00,bb */ - {0xbb, 0x86, 0x0002}, /* 00,88,02,bb */ - {0xbb, 0xe6, 0x0401}, /* 04,e6,01,bb */ - {0xbb, 0x86, 0x0802}, /* 08,88,02,bb */ - {0xbb, 0xe6, 0x0c01}, /* 0c,e6,01,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0020}, /* 00,fe,20,aa */ - /*******/ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ - {0xbb, 0x04, 0x0400}, /* 04,04,00,bb */ - {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ - {0xbb, 0x01, 0x0400}, /* 04,01,00,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xbb, 0x41, 0x2803}, /* 28,41,03,bb */ - {0xbb, 0x40, 0x2c03}, /* 2c,40,03,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ - {} -}; -static const struct usb_action adcm2700_50HZ[] = { - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xbb, 0x05, 0x8400}, /* 84,05,00,bb */ - {0xbb, 0xd0, 0xb007}, /* b0,d0,07,bb */ - {0xbb, 0xa0, 0xb80f}, /* b8,a0,0f,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ - {0xaa, 0x26, 0x00d0}, /* 00,26,d0,aa */ - {0xaa, 0x28, 0x0002}, /* 00,28,02,aa */ - {} -}; -static const struct usb_action adcm2700_60HZ[] = { - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xbb, 0x07, 0x8400}, /* 84,07,00,bb */ - {0xbb, 0x82, 0xb006}, /* b0,82,06,bb */ - {0xbb, 0x04, 0xb80d}, /* b8,04,0d,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ - {0xaa, 0x26, 0x0057}, /* 00,26,57,aa */ - {0xaa, 0x28, 0x0002}, /* 00,28,02,aa */ - {} -}; -static const struct usb_action adcm2700_NoFliker[] = { - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ - {0xbb, 0x07, 0x8400}, /* 84,07,00,bb */ - {0xbb, 0x05, 0xb000}, /* b0,05,00,bb */ - {0xbb, 0xa0, 0xb801}, /* b8,a0,01,bb */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ - {} -}; -static const struct usb_action cs2102_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x20, ZC3XX_R080_HBLANKHIGH}, - {0xa0, 0x21, ZC3XX_R081_HBLANKLOW}, - {0xa0, 0x30, ZC3XX_R083_RGAINADDR}, - {0xa0, 0x31, ZC3XX_R084_GGAINADDR}, - {0xa0, 0x32, ZC3XX_R085_BGAINADDR}, - {0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH}, - {0xa0, 0x24, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x25, ZC3XX_R088_EXPTIMELOW}, - {0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xaa, 0x02, 0x0008}, - {0xaa, 0x03, 0x0000}, - {0xaa, 0x11, 0x0000}, - {0xaa, 0x12, 0x0089}, - {0xaa, 0x13, 0x0000}, - {0xaa, 0x14, 0x00e9}, - {0xaa, 0x20, 0x0000}, - {0xaa, 0x22, 0x0000}, - {0xaa, 0x0b, 0x0004}, - {0xaa, 0x30, 0x0030}, - {0xaa, 0x31, 0x0030}, - {0xaa, 0x32, 0x0030}, - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x10, 0x01ae}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x68, ZC3XX_R18D_YTARGET}, - {0xa0, 0x00, 0x01ad}, - {} -}; - -static const struct usb_action cs2102_Initial[] = { /* 640x480 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x20, ZC3XX_R080_HBLANKHIGH}, - {0xa0, 0x21, ZC3XX_R081_HBLANKLOW}, - {0xa0, 0x30, ZC3XX_R083_RGAINADDR}, - {0xa0, 0x31, ZC3XX_R084_GGAINADDR}, - {0xa0, 0x32, ZC3XX_R085_BGAINADDR}, - {0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH}, - {0xa0, 0x24, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x25, ZC3XX_R088_EXPTIMELOW}, - {0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xaa, 0x02, 0x0008}, - {0xaa, 0x03, 0x0000}, - {0xaa, 0x11, 0x0001}, - {0xaa, 0x12, 0x0087}, - {0xaa, 0x13, 0x0001}, - {0xaa, 0x14, 0x00e7}, - {0xaa, 0x20, 0x0000}, - {0xaa, 0x22, 0x0000}, - {0xaa, 0x0b, 0x0004}, - {0xaa, 0x30, 0x0030}, - {0xaa, 0x31, 0x0030}, - {0xaa, 0x32, 0x0030}, - {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x15, 0x01ae}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x68, ZC3XX_R18D_YTARGET}, - {0xa0, 0x00, 0x01ad}, - {} -}; -static const struct usb_action cs2102_50HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x23, 0x0001}, - {0xaa, 0x24, 0x005f}, - {0xaa, 0x25, 0x0090}, - {0xaa, 0x21, 0x00dd}, - {0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0xbf, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x3a, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x98, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xdd, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xe4, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf0, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action cs2102_50HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x23, 0x0000}, - {0xaa, 0x24, 0x00af}, - {0xaa, 0x25, 0x00c8}, - {0xaa, 0x21, 0x0068}, - {0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x5f, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x90, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x1d, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x4c, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x68, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xe3, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf0, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action cs2102_60HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x23, 0x0001}, - {0xaa, 0x24, 0x0055}, - {0xaa, 0x25, 0x00cc}, - {0xaa, 0x21, 0x003f}, - {0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0xab, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x98, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x30, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0xd4, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x39, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x70, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xb0, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action cs2102_60HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x23, 0x0000}, - {0xaa, 0x24, 0x00aa}, - {0xaa, 0x25, 0x00e6}, - {0xaa, 0x21, 0x003f}, - {0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x55, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xcc, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x18, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x6a, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x3f, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xa5, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf0, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action cs2102_NoFlikerScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x23, 0x0001}, - {0xaa, 0x24, 0x005f}, - {0xaa, 0x25, 0x0000}, - {0xaa, 0x21, 0x0001}, - {0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0xbf, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x80, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x01, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xa0, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action cs2102_NoFliker[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x23, 0x0000}, - {0xaa, 0x24, 0x00af}, - {0xaa, 0x25, 0x0080}, - {0xaa, 0x21, 0x0001}, - {0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x5f, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x80, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x01, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xa0, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {} -}; - -/* CS2102_KOCOM */ -static const struct usb_action cs2102K_InitialScale[] = { - {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, - {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x7c, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x01, 0x01b1}, - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x60, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x4c, ZC3XX_R118_BGAIN}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ - {0xa0, 0x38, ZC3XX_R121_GAMMA01}, - {0xa0, 0x59, ZC3XX_R122_GAMMA02}, - {0xa0, 0x79, ZC3XX_R123_GAMMA03}, - {0xa0, 0x92, ZC3XX_R124_GAMMA04}, - {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, - {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, - {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, - {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, - {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, - {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, - {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, - {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, - {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, - {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, - {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, - {0xa0, 0x26, ZC3XX_R130_GAMMA10}, - {0xa0, 0x22, ZC3XX_R131_GAMMA11}, - {0xa0, 0x20, ZC3XX_R132_GAMMA12}, - {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, - {0xa0, 0x16, ZC3XX_R134_GAMMA14}, - {0xa0, 0x13, ZC3XX_R135_GAMMA15}, - {0xa0, 0x10, ZC3XX_R136_GAMMA16}, - {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, - {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, - {0xa0, 0x09, ZC3XX_R139_GAMMA19}, - {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, - {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, - {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, - {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, - {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, - {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, - {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf4, ZC3XX_R10B_RGB01}, - {0xa0, 0xf4, ZC3XX_R10C_RGB02}, - {0xa0, 0xf4, ZC3XX_R10D_RGB10}, - {0xa0, 0x58, ZC3XX_R10E_RGB11}, - {0xa0, 0xf4, ZC3XX_R10F_RGB12}, - {0xa0, 0xf4, ZC3XX_R110_RGB20}, - {0xa0, 0xf4, ZC3XX_R111_RGB21}, - {0xa0, 0x58, ZC3XX_R112_RGB22}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, - {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x19, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x1f, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x60, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x4c, ZC3XX_R118_BGAIN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {} -}; - -static const struct usb_action cs2102K_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, -/*fixme: next sequence = i2c exchanges*/ - {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x01, 0x01b1}, - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x60, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x4c, ZC3XX_R118_BGAIN}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ - {0xa0, 0x38, ZC3XX_R121_GAMMA01}, - {0xa0, 0x59, ZC3XX_R122_GAMMA02}, - {0xa0, 0x79, ZC3XX_R123_GAMMA03}, - {0xa0, 0x92, ZC3XX_R124_GAMMA04}, - {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, - {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, - {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, - {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, - {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, - {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, - {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, - {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, - {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, - {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, - {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, - {0xa0, 0x26, ZC3XX_R130_GAMMA10}, - {0xa0, 0x22, ZC3XX_R131_GAMMA11}, - {0xa0, 0x20, ZC3XX_R132_GAMMA12}, - {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, - {0xa0, 0x16, ZC3XX_R134_GAMMA14}, - {0xa0, 0x13, ZC3XX_R135_GAMMA15}, - {0xa0, 0x10, ZC3XX_R136_GAMMA16}, - {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, - {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, - {0xa0, 0x09, ZC3XX_R139_GAMMA19}, - {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, - {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, - {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, - {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, - {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, - {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, - {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf4, ZC3XX_R10B_RGB01}, - {0xa0, 0xf4, ZC3XX_R10C_RGB02}, - {0xa0, 0xf4, ZC3XX_R10D_RGB10}, - {0xa0, 0x58, ZC3XX_R10E_RGB11}, - {0xa0, 0xf4, ZC3XX_R10F_RGB12}, - {0xa0, 0xf4, ZC3XX_R110_RGB20}, - {0xa0, 0xf4, ZC3XX_R111_RGB21}, - {0xa0, 0x58, ZC3XX_R112_RGB22}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, - {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x19, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x1f, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x60, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x4c, ZC3XX_R118_BGAIN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, -/*fixme:what does the next sequence?*/ - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x44, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x44, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {} -}; - -static const struct usb_action gc0305_Initial[] = { /* 640x480 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */ - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ - {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc */ - {0xaa, 0x13, 0x0002}, /* 00,13,02,aa */ - {0xaa, 0x15, 0x0003}, /* 00,15,03,aa */ - {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ - {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */ - {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ - {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */ - {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */ - {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */ - {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */ - {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc */ - {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc */ - {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc */ - {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ - {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */ - {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */ - {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */ - {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */ - {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */ - {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ - {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */ - {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */ - {0xaa, 0x17, 0x00e6}, /* 00,17,e6,aa */ - {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */ - {0xaa, 0x19, 0x0086}, /* 00,19,86,aa */ - {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ - {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */ - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc */ - {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ - {0xa0, 0x85, ZC3XX_R18D_YTARGET}, /* 01,8d,85,cc */ - {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */ - {0xa0, 0x52, ZC3XX_R116_RGAIN}, /* 01,16,52,cc */ - {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* 01,17,40,cc */ - {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ - {0xa0, 0x03, ZC3XX_R113_RGB03}, /* 01,13,03,cc */ - {} -}; -static const struct usb_action gc0305_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc */ - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ - {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc */ - {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */ - {0xaa, 0x15, 0x0001}, /* 00,15,01,aa */ - {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ - {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */ - {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ - {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */ - {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */ - {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */ - {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */ - {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc */ - {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc */ - {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc */ - {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ - {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */ - {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */ - {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */ - {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */ - {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */ - {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ - {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */ - {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */ - {0xaa, 0x17, 0x00e8}, /* 00,17,e8,aa */ - {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */ - {0xaa, 0x19, 0x0088}, /* 00,19,88,aa */ - {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ - {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */ - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc */ - {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ - {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */ - {0xa0, 0x52, ZC3XX_R116_RGAIN}, /* 01,16,52,cc */ - {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* 01,17,40,cc */ - {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ - {0xa0, 0x03, ZC3XX_R113_RGB03}, /* 01,13,03,cc */ - {} -}; -static const struct usb_action gc0305_50HZ[] = { - {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */ - {0xaa, 0x84, 0x0038}, /* 00,84,38,aa */ /* win: 00,84,ec */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc */ - {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ - /* win: 01,92,10 */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,8e,cc */ - /* win: 01,97,ec */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */ - {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */ - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ -/* {0xa0, 0x85, ZC3XX_R18D_YTARGET}, * 01,8d,85,cc * - * if 640x480 */ - {} -}; -static const struct usb_action gc0305_60HZ[] = { - {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ - {0xaa, 0x84, 0x00ec}, /* 00,84,ec,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc */ - {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0xec, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,ec,cc */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */ - {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */ - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ - {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* 01,8d,80,cc */ - {} -}; - -static const struct usb_action gc0305_NoFliker[] = { - {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc */ - {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ - {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,00,cc */ - {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,48,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */ - {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */ - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */ - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */ - {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */ - {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* 01,8d,80,cc */ - {} -}; - -static const struct usb_action hdcs2020_InitialScale[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* qtable 0x05 */ - {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, - {0xaa, 0x1c, 0x0000}, - {0xaa, 0x0a, 0x0001}, - {0xaa, 0x0b, 0x0006}, - {0xaa, 0x0c, 0x007b}, - {0xaa, 0x0d, 0x00a7}, - {0xaa, 0x03, 0x00fb}, - {0xaa, 0x05, 0x0000}, - {0xaa, 0x06, 0x0003}, - {0xaa, 0x09, 0x0008}, - - {0xaa, 0x0f, 0x0018}, /* set sensor gain */ - {0xaa, 0x10, 0x0018}, - {0xaa, 0x11, 0x0018}, - {0xaa, 0x12, 0x0018}, - - {0xaa, 0x15, 0x004e}, - {0xaa, 0x1c, 0x0004}, - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x70, ZC3XX_R18D_YTARGET}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa1, 0x01, 0x0002}, - {0xa1, 0x01, 0x0008}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ - {0xa0, 0x38, ZC3XX_R121_GAMMA01}, - {0xa0, 0x59, ZC3XX_R122_GAMMA02}, - {0xa0, 0x79, ZC3XX_R123_GAMMA03}, - {0xa0, 0x92, ZC3XX_R124_GAMMA04}, - {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, - {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, - {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, - {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, - {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, - {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, - {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, - {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, - {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, - {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, - {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, - {0xa0, 0x26, ZC3XX_R130_GAMMA10}, - {0xa0, 0x22, ZC3XX_R131_GAMMA11}, - {0xa0, 0x20, ZC3XX_R132_GAMMA12}, - {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, - {0xa0, 0x16, ZC3XX_R134_GAMMA14}, - {0xa0, 0x13, ZC3XX_R135_GAMMA15}, - {0xa0, 0x10, ZC3XX_R136_GAMMA16}, - {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, - {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, - {0xa0, 0x09, ZC3XX_R139_GAMMA19}, - {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, - {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, - {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, - {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, - {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, - {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, - - {0xa0, 0x66, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xed, ZC3XX_R10B_RGB01}, - {0xa0, 0xed, ZC3XX_R10C_RGB02}, - {0xa0, 0xed, ZC3XX_R10D_RGB10}, - {0xa0, 0x66, ZC3XX_R10E_RGB11}, - {0xa0, 0xed, ZC3XX_R10F_RGB12}, - {0xa0, 0xed, ZC3XX_R110_RGB20}, - {0xa0, 0xed, ZC3XX_R111_RGB21}, - {0xa0, 0x66, ZC3XX_R112_RGB22}, - - {0xa1, 0x01, 0x0180}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x13, 0x0031}, - {0xaa, 0x14, 0x0001}, - {0xaa, 0x0e, 0x0004}, - {0xaa, 0x19, 0x00cd}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - - {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 0x14 */ - {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x41, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - {} -}; -static const struct usb_action hdcs2020_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, - {0xaa, 0x1c, 0x0000}, - {0xaa, 0x0a, 0x0001}, - {0xaa, 0x0b, 0x0006}, - {0xaa, 0x0c, 0x007a}, - {0xaa, 0x0d, 0x00a7}, - {0xaa, 0x03, 0x00fb}, - {0xaa, 0x05, 0x0000}, - {0xaa, 0x06, 0x0003}, - {0xaa, 0x09, 0x0008}, - {0xaa, 0x0f, 0x0018}, /* original setting */ - {0xaa, 0x10, 0x0018}, - {0xaa, 0x11, 0x0018}, - {0xaa, 0x12, 0x0018}, - {0xaa, 0x15, 0x004e}, - {0xaa, 0x1c, 0x0004}, - {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x70, ZC3XX_R18D_YTARGET}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa1, 0x01, 0x0002}, - {0xa1, 0x01, 0x0008}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ - {0xa0, 0x38, ZC3XX_R121_GAMMA01}, - {0xa0, 0x59, ZC3XX_R122_GAMMA02}, - {0xa0, 0x79, ZC3XX_R123_GAMMA03}, - {0xa0, 0x92, ZC3XX_R124_GAMMA04}, - {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, - {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, - {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, - {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, - {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, - {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, - {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, - {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, - {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, - {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, - {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, - {0xa0, 0x26, ZC3XX_R130_GAMMA10}, - {0xa0, 0x22, ZC3XX_R131_GAMMA11}, - {0xa0, 0x20, ZC3XX_R132_GAMMA12}, - {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, - {0xa0, 0x16, ZC3XX_R134_GAMMA14}, - {0xa0, 0x13, ZC3XX_R135_GAMMA15}, - {0xa0, 0x10, ZC3XX_R136_GAMMA16}, - {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, - {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, - {0xa0, 0x09, ZC3XX_R139_GAMMA19}, - {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, - {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, - {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, - {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, - {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, - {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, - {0xa0, 0x66, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xed, ZC3XX_R10B_RGB01}, - {0xa0, 0xed, ZC3XX_R10C_RGB02}, - {0xa0, 0xed, ZC3XX_R10D_RGB10}, - {0xa0, 0x66, ZC3XX_R10E_RGB11}, - {0xa0, 0xed, ZC3XX_R10F_RGB12}, - {0xa0, 0xed, ZC3XX_R110_RGB20}, - {0xa0, 0xed, ZC3XX_R111_RGB21}, - {0xa0, 0x66, ZC3XX_R112_RGB22}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - /**** set exposure ***/ - {0xaa, 0x13, 0x0031}, - {0xaa, 0x14, 0x0001}, - {0xaa, 0x0e, 0x0004}, - {0xaa, 0x19, 0x00cd}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x41, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - {} -}; -static const struct usb_action hdcs2020_50HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x13, 0x0018}, /* 00,13,18,aa */ - {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ - {0xaa, 0x0e, 0x0005}, /* 00,0e,05,aa */ - {0xaa, 0x19, 0x001f}, /* 00,19,1f,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ - {0xa0, 0x76, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,76,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x46, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,46,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ - {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */ - {0xa0, 0x05, ZC3XX_R01D_HSYNC_0}, /* 00,1d,05,cc */ - {0xa0, 0x1a, ZC3XX_R01E_HSYNC_1}, /* 00,1e,1a,cc */ - {0xa0, 0x2f, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2f,cc */ - {} -}; -static const struct usb_action hdcs2020_60HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x13, 0x0031}, /* 00,13,31,aa */ - {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ - {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ - {0xaa, 0x19, 0x00cd}, /* 00,19,cd,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ - {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,62,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3d,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ - {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */ - {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */ - {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, /* 00,1e,18,cc */ - {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */ - {} -}; -static const struct usb_action hdcs2020_NoFliker[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */ - {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ - {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ - {0xaa, 0x19, 0x0000}, /* 00,19,00,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ - {0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ - {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */ - {0xa0, 0x17, ZC3XX_R01E_HSYNC_1}, /* 00,1e,17,cc */ - {0xa0, 0x2a, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2a,cc */ - {} -}; - -static const struct usb_action hv7131b_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xaa, 0x30, 0x002d}, - {0xaa, 0x01, 0x0005}, - {0xaa, 0x11, 0x0000}, - {0xaa, 0x13, 0x0001}, /* {0xaa, 0x13, 0x0000}, */ - {0xaa, 0x14, 0x0001}, - {0xaa, 0x15, 0x00e8}, - {0xaa, 0x16, 0x0002}, - {0xaa, 0x17, 0x0086}, /* 00,17,88,aa */ - {0xaa, 0x31, 0x0038}, - {0xaa, 0x32, 0x0038}, - {0xaa, 0x33, 0x0038}, - {0xaa, 0x5b, 0x0001}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x68, ZC3XX_R18D_YTARGET}, - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0xc0, 0x019b}, - {0xa0, 0xa0, 0x019c}, - {0xa0, 0x02, ZC3XX_R188_MINGAIN}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xaa, 0x02, 0x0090}, /* 00,02,80,aa */ - {} -}; - -static const struct usb_action hv7131b_Initial[] = { /* 640x480*/ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xaa, 0x30, 0x002d}, - {0xaa, 0x01, 0x0005}, - {0xaa, 0x11, 0x0001}, - {0xaa, 0x13, 0x0000}, /* {0xaa, 0x13, 0x0001}; */ - {0xaa, 0x14, 0x0001}, - {0xaa, 0x15, 0x00e6}, - {0xaa, 0x16, 0x0002}, - {0xaa, 0x17, 0x0086}, - {0xaa, 0x31, 0x0038}, - {0xaa, 0x32, 0x0038}, - {0xaa, 0x33, 0x0038}, - {0xaa, 0x5b, 0x0001}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x70, ZC3XX_R18D_YTARGET}, - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0xc0, 0x019b}, - {0xa0, 0xa0, 0x019c}, - {0xa0, 0x02, ZC3XX_R188_MINGAIN}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xaa, 0x02, 0x0090}, /* {0xaa, 0x02, 0x0080}, */ - {} -}; -static const struct usb_action hv7131b_50HZ[] = { /* 640x480*/ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ - {0xaa, 0x26, 0x0053}, /* 00,26,53,aa */ - {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ - {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ - {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ - {0xaa, 0x22, 0x001b}, /* 00,22,1b,aa */ - {0xaa, 0x23, 0x00fc}, /* 00,23,fc,aa */ - {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ - {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,9b,cc */ - {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0xea, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,ea,cc */ - {0xa0, 0x60, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,60,cc */ - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ - {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ - {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ - {0xa0, 0x1b, ZC3XX_R01F_HSYNC_2}, /* 00,1f,1b,cc */ - {0xa0, 0xfc, ZC3XX_R020_HSYNC_3}, /* 00,20,fc,cc */ - {} -}; -static const struct usb_action hv7131b_50HZScale[] = { /* 320x240 */ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ - {0xaa, 0x26, 0x0053}, /* 00,26,53,aa */ - {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ - {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ - {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ - {0xaa, 0x22, 0x0012}, /* 00,22,12,aa */ - {0xaa, 0x23, 0x0080}, /* 00,23,80,aa */ - {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ - {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,9b,cc */ - {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */ - {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,01,cc */ - {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,d4,cc */ - {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,c0,cc */ - {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ - {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ - {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ - {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ - {0xa0, 0x12, ZC3XX_R01F_HSYNC_2}, /* 00,1f,12,cc */ - {0xa0, 0x80, ZC3XX_R020_HSYNC_3}, /* 00,20,80,cc */ - {} -}; -static const struct usb_action hv7131b_60HZ[] = { /* 640x480*/ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ - {0xaa, 0x26, 0x00a1}, /* 00,26,a1,aa */ - {0xaa, 0x27, 0x0020}, /* 00,27,20,aa */ - {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ - {0xaa, 0x21, 0x0040}, /* 00,21,40,aa */ - {0xaa, 0x22, 0x0013}, /* 00,22,13,aa */ - {0xaa, 0x23, 0x004c}, /* 00,23,4c,aa */ - {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ - {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,4d,cc */ - {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,60,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,c3,cc */ - {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,50,cc */ - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ - {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ - {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */ - {0xa0, 0x13, ZC3XX_R01F_HSYNC_2}, /* 00,1f,13,cc */ - {0xa0, 0x4c, ZC3XX_R020_HSYNC_3}, /* 00,20,4c,cc */ - {} -}; -static const struct usb_action hv7131b_60HZScale[] = { /* 320x240 */ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ - {0xaa, 0x26, 0x00a1}, /* 00,26,a1,aa */ - {0xaa, 0x27, 0x0020}, /* 00,27,20,aa */ - {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ - {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ - {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ - {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ - {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ - {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,4d,cc */ - {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,60,cc */ - {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,01,cc */ - {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,86,cc */ - {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,a0,cc */ - {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ - {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ - {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ - {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,a0,cc */ - {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, /* 00,1f,16,cc */ - {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ - {} -}; -static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ - {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ - {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ - {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ - {0xaa, 0x21, 0x0010}, /* 00,21,10,aa */ - {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ - {0xaa, 0x23, 0x0003}, /* 00,23,03,aa */ - {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ - {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,f8,cc */ - {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,00,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,02,cc */ - {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,00,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ - {0xa0, 0x10, ZC3XX_R01E_HSYNC_1}, /* 00,1e,10,cc */ - {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, /* 00,1f,00,cc */ - {0xa0, 0x03, ZC3XX_R020_HSYNC_3}, /* 00,20,03,cc */ - {} -}; -static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ - {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ - {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ - {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ - {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ - {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ - {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ - {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ - {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,f8,cc */ - {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,00,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,02,cc */ - {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,00,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ - {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,a0,cc */ - {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, /* 00,1f,16,cc */ - {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ - {} -}; - -/* from lPEPI264v.inf (hv7131b!) */ -static const struct usb_action hv7131r_InitialScale[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xdd, 0x00, 0x0200}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xaa, 0x01, 0x000c}, - {0xaa, 0x11, 0x0000}, - {0xaa, 0x13, 0x0000}, - {0xaa, 0x14, 0x0001}, - {0xaa, 0x15, 0x00e8}, - {0xaa, 0x16, 0x0002}, - {0xaa, 0x17, 0x0088}, - {0xaa, 0x30, 0x000b}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, - {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0xc0, 0x019b}, - {0xa0, 0xa0, 0x019c}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {} -}; -static const struct usb_action hv7131r_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, - {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xdd, 0x00, 0x0200}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xaa, 0x01, 0x000c}, - {0xaa, 0x11, 0x0000}, - {0xaa, 0x13, 0x0000}, - {0xaa, 0x14, 0x0001}, - {0xaa, 0x15, 0x00e6}, - {0xaa, 0x16, 0x0002}, - {0xaa, 0x17, 0x0086}, - {0xaa, 0x30, 0x000b}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, - {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0xc0, 0x019b}, - {0xa0, 0xa0, 0x019c}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {} -}; -static const struct usb_action hv7131r_50HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x06, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x68, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0xea, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x60, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x18, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action hv7131r_50HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x0c, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0xd1, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x40, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x18, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action hv7131r_60HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x06, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x1a, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x18, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action hv7131r_60HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x0c, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x35, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x18, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action hv7131r_NoFliker[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x58, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action hv7131r_NoFlikerScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x04, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0xb0, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, - {} -}; - -static const struct usb_action icm105a_InitialScale[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH}, - {0xa0, 0x01, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH}, - {0xa0, 0x01, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x01, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x01, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xaa, 0x01, 0x0010}, - {0xaa, 0x03, 0x0000}, - {0xaa, 0x04, 0x0001}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x0001}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0001}, - {0xaa, 0x04, 0x0011}, - {0xaa, 0x05, 0x00a0}, - {0xaa, 0x06, 0x0001}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0002}, - {0xaa, 0x04, 0x0013}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x0001}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0003}, - {0xaa, 0x04, 0x0015}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0004}, - {0xaa, 0x04, 0x0017}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x000d}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0005}, - {0xaa, 0x04, 0x0019}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0006}, - {0xaa, 0x04, 0x0017}, - {0xaa, 0x05, 0x0026}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0007}, - {0xaa, 0x04, 0x0019}, - {0xaa, 0x05, 0x0022}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0008}, - {0xaa, 0x04, 0x0021}, - {0xaa, 0x05, 0x00aa}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0009}, - {0xaa, 0x04, 0x0023}, - {0xaa, 0x05, 0x00aa}, - {0xaa, 0x06, 0x000d}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x000a}, - {0xaa, 0x04, 0x0025}, - {0xaa, 0x05, 0x00aa}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x000b}, - {0xaa, 0x04, 0x00ec}, - {0xaa, 0x05, 0x002e}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x000c}, - {0xaa, 0x04, 0x00fa}, - {0xaa, 0x05, 0x002a}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x07, 0x000d}, - {0xaa, 0x01, 0x0005}, - {0xaa, 0x94, 0x0002}, - {0xaa, 0x90, 0x0000}, - {0xaa, 0x91, 0x001f}, - {0xaa, 0x10, 0x0064}, - {0xaa, 0x9b, 0x00f0}, - {0xaa, 0x9c, 0x0002}, - {0xaa, 0x14, 0x001a}, - {0xaa, 0x20, 0x0080}, - {0xaa, 0x22, 0x0080}, - {0xaa, 0x24, 0x0080}, - {0xaa, 0x26, 0x0080}, - {0xaa, 0x00, 0x0084}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xaa, 0xa8, 0x00c0}, - {0xa1, 0x01, 0x0002}, - {0xa1, 0x01, 0x0008}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - {0xa1, 0x01, 0x0008}, - - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - {0xa0, 0x52, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf7, ZC3XX_R10B_RGB01}, - {0xa0, 0xf7, ZC3XX_R10C_RGB02}, - {0xa0, 0xf7, ZC3XX_R10D_RGB10}, - {0xa0, 0x52, ZC3XX_R10E_RGB11}, - {0xa0, 0xf7, ZC3XX_R10F_RGB12}, - {0xa0, 0xf7, ZC3XX_R110_RGB20}, - {0xa0, 0xf7, ZC3XX_R111_RGB21}, - {0xa0, 0x52, ZC3XX_R112_RGB22}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x0d, 0x0003}, - {0xaa, 0x0c, 0x008c}, - {0xaa, 0x0e, 0x0095}, - {0xaa, 0x0f, 0x0002}, - {0xaa, 0x1c, 0x0094}, - {0xaa, 0x1d, 0x0002}, - {0xaa, 0x20, 0x0080}, - {0xaa, 0x22, 0x0080}, - {0xaa, 0x24, 0x0080}, - {0xaa, 0x26, 0x0080}, - {0xaa, 0x00, 0x0084}, - {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, - {0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xe3, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xec, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf5, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0xc0, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - {} -}; - -static const struct usb_action icm105a_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH}, - {0xa0, 0x02, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH}, - {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x02, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, - {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, - {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xaa, 0x01, 0x0010}, - {0xaa, 0x03, 0x0000}, - {0xaa, 0x04, 0x0001}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x0001}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0001}, - {0xaa, 0x04, 0x0011}, - {0xaa, 0x05, 0x00a0}, - {0xaa, 0x06, 0x0001}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0002}, - {0xaa, 0x04, 0x0013}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x0001}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0003}, - {0xaa, 0x04, 0x0015}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0004}, - {0xaa, 0x04, 0x0017}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x000d}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0005}, - {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x19, ZC3XX_R093_I2CSETVALUE}, - {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, - {0xa1, 0x01, 0x0091}, - {0xaa, 0x05, 0x0020}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0006}, - {0xaa, 0x04, 0x0017}, - {0xaa, 0x05, 0x0026}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0007}, - {0xaa, 0x04, 0x0019}, - {0xaa, 0x05, 0x0022}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0008}, - {0xaa, 0x04, 0x0021}, - {0xaa, 0x05, 0x00aa}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x0009}, - {0xaa, 0x04, 0x0023}, - {0xaa, 0x05, 0x00aa}, - {0xaa, 0x06, 0x000d}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x000a}, - {0xaa, 0x04, 0x0025}, - {0xaa, 0x05, 0x00aa}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x000b}, - {0xaa, 0x04, 0x00ec}, - {0xaa, 0x05, 0x002e}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x03, 0x000c}, - {0xaa, 0x04, 0x00fa}, - {0xaa, 0x05, 0x002a}, - {0xaa, 0x06, 0x0005}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x07, 0x000d}, - {0xaa, 0x01, 0x0005}, - {0xaa, 0x94, 0x0002}, - {0xaa, 0x90, 0x0000}, - {0xaa, 0x91, 0x0010}, - {0xaa, 0x10, 0x0064}, - {0xaa, 0x9b, 0x00f0}, - {0xaa, 0x9c, 0x0002}, - {0xaa, 0x14, 0x001a}, - {0xaa, 0x20, 0x0080}, - {0xaa, 0x22, 0x0080}, - {0xaa, 0x24, 0x0080}, - {0xaa, 0x26, 0x0080}, - {0xaa, 0x00, 0x0084}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xaa, 0xa8, 0x0080}, - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, - {0xa1, 0x01, 0x0002}, - {0xa1, 0x01, 0x0008}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - {0xa1, 0x01, 0x0008}, - - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - - {0xa0, 0x52, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf7, ZC3XX_R10B_RGB01}, - {0xa0, 0xf7, ZC3XX_R10C_RGB02}, - {0xa0, 0xf7, ZC3XX_R10D_RGB10}, - {0xa0, 0x52, ZC3XX_R10E_RGB11}, - {0xa0, 0xf7, ZC3XX_R10F_RGB12}, - {0xa0, 0xf7, ZC3XX_R110_RGB20}, - {0xa0, 0xf7, ZC3XX_R111_RGB21}, - {0xa0, 0x52, ZC3XX_R112_RGB22}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x0d, 0x0003}, - {0xaa, 0x0c, 0x0020}, - {0xaa, 0x0e, 0x000e}, - {0xaa, 0x0f, 0x0002}, - {0xaa, 0x1c, 0x000d}, - {0xaa, 0x1d, 0x0002}, - {0xaa, 0x20, 0x0080}, - {0xaa, 0x22, 0x0080}, - {0xaa, 0x24, 0x0080}, - {0xaa, 0x26, 0x0080}, - {0xaa, 0x00, 0x0084}, - {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, - {0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xd8, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - {} -}; -static const struct usb_action icm105a_50HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ - {0xaa, 0x0c, 0x0020}, /* 00,0c,20,aa */ - {0xaa, 0x0e, 0x000e}, /* 00,0e,0e,aa */ - {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ - {0xaa, 0x1c, 0x000d}, /* 00,1c,0d,aa */ - {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ - {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ - {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ - {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ - {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ - {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ - {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ - {0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,0d,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ - {0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,1a,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4b,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ - {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ - {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */ - {0xa0, 0xd8, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d8,cc */ - {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {} -}; -static const struct usb_action icm105a_50HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ - {0xaa, 0x0c, 0x008c}, /* 00,0c,8c,aa */ - {0xaa, 0x0e, 0x0095}, /* 00,0e,95,aa */ - {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ - {0xaa, 0x1c, 0x0094}, /* 00,1c,94,aa */ - {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ - {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ - {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ - {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ - {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ - {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ - {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ - {0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,94,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ - {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,84,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ - {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ - {0xa0, 0xe3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,e3,cc */ - {0xa0, 0xec, ZC3XX_R01E_HSYNC_1}, /* 00,1e,ec,cc */ - {0xa0, 0xf5, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f5,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */ - {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ - {} -}; -static const struct usb_action icm105a_60HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ - {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ - {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */ - {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ - {0xaa, 0x1c, 0x0008}, /* 00,1c,08,aa */ - {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ - {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ - {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ - {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ - {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ - {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ - {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ - {0xa0, 0x08, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,08,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ - {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x41, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,41,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ - {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ - {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */ - {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */ - {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {} -}; -static const struct usb_action icm105a_60HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ - {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */ - {0xaa, 0x0e, 0x0086}, /* 00,0e,86,aa */ - {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ - {0xaa, 0x1c, 0x0085}, /* 00,1c,85,aa */ - {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ - {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ - {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ - {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ - {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ - {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ - {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ - {0xa0, 0x85, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,85,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ - {0xa0, 0x08, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,08,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ - {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ - {0xa0, 0xc2, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c2,cc */ - {0xa0, 0xd6, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d6,cc */ - {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */ - {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ - {} -}; -static const struct usb_action icm105a_NoFlikerScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ - {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ - {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */ - {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ - {0xaa, 0x1c, 0x0000}, /* 00,1c,00,aa */ - {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ - {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ - {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ - {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ - {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ - {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ - {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ - {0xa0, 0x00, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,00,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ - {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ - {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */ - {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */ - {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {} -}; -static const struct usb_action icm105a_NoFliker[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ - {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ - {0xaa, 0x0e, 0x0081}, /* 00,0e,81,aa */ - {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ - {0xaa, 0x1c, 0x0080}, /* 00,1c,80,aa */ - {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ - {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ - {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ - {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ - {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ - {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ - {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ - {0xa0, 0x80, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,80,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ - {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ - {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */ - {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */ - {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */ - {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ - {} -}; - -static const struct usb_action mc501cb_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ - {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */ - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ - {0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */ - {0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */ - {0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */ - {0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ - {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */ - {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ - {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ - {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */ - {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */ - {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */ - {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ - {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */ - {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */ - {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */ - {0xaa, 0x18, 0x00de}, /* 00,18,de,aa */ - {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ - {0xaa, 0x1a, 0x0086}, /* 00,1a,86,aa */ - {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */ - {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ - {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */ - {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */ - {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */ - {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */ - {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */ - {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */ - {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */ - {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */ - {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */ - {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */ - {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */ - {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */ - {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */ - {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */ - {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */ - {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */ - {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */ - {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */ - {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */ - {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */ - {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */ - {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */ - {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */ - {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */ - {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */ - {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */ - {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */ - {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */ - {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */ - {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */ - {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */ - {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */ - {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */ - {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */ - {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */ - {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */ - {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ - {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */ - {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */ - {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x1c, 0x0050}, /* 00,1C,50,aa */ - {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */ - {0xaa, 0x3b, 0x001d}, /* 00,3b,1D,aa */ - {0xaa, 0x3c, 0x004c}, /* 00,3c,4C,aa */ - {0xaa, 0x3d, 0x0018}, /* 00,3d,18,aa */ - {0xaa, 0x3e, 0x006a}, /* 00,3e,6A,aa */ - {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ - {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ - {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */ - {0xaa, 0x51, 0x0027}, /* 00,51,27,aa */ - {0xaa, 0x52, 0x0020}, /* 00,52,20,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */ - {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */ - {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */ - {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */ - {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */ - {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */ - - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ - {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ - {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ - {} -}; - -static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ - {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */ - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ - {0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */ - {0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */ - {0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */ - {0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ - {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */ - {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ - {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ - {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */ - {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */ - {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */ - {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ - {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */ - {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */ - {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */ - {0xaa, 0x18, 0x00d8}, /* 00,18,d8,aa */ - {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ - {0xaa, 0x1a, 0x0088}, /* 00,1a,88,aa */ - {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */ - {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ - {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */ - {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */ - {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */ - {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */ - {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */ - {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */ - {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */ - {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */ - {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */ - {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */ - {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */ - {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */ - {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */ - {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */ - {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */ - {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */ - {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */ - {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */ - {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */ - {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */ - {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */ - {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */ - {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */ - {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */ - {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */ - {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */ - {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */ - {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */ - {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */ - {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */ - {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */ - {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */ - {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */ - {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */ - {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */ - {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */ - {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ - {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */ - {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */ - {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x1c, 0x0050}, /* 00,1c,50,aa */ - {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */ - {0xaa, 0x3b, 0x003a}, /* 00,3b,3A,aa */ - {0xaa, 0x3c, 0x0098}, /* 00,3c,98,aa */ - {0xaa, 0x3d, 0x0030}, /* 00,3d,30,aa */ - {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ - {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ - {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ - {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */ - {0xaa, 0x51, 0x004e}, /* 00,51,4E,aa */ - {0xaa, 0x52, 0x0041}, /* 00,52,41,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */ - {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */ - {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */ - {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */ - {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */ - {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ - {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ - {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ - {} -}; - -static const struct usb_action mc501cb_50HZScale[] = { - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ - {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ - {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ - {0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */ - {0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */ - {0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ - {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */ - {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */ - {} -}; - -static const struct usb_action mc501cb_50HZ[] = { - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ - {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */ - {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */ - {0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */ - {0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */ - {0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ - {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ - {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ - {} -}; - -static const struct usb_action mc501cb_60HZScale[] = { - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ - {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ - {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ - {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ - {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ - {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ - {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ - {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ - {} -}; - -static const struct usb_action mc501cb_60HZ[] = { - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ - {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ - {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ - {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ - {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */ - {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ - {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ - {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ - {} -}; - -static const struct usb_action mc501cb_NoFlikerScale[] = { - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ - {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ - {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ - {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ - {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ - {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ - {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ - {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ - {} -}; - -static const struct usb_action mc501cb_NoFliker[] = { - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ - {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ - {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ - {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ - {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */ - {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */ - {} -}; - -/* from zs211.inf */ -static const struct usb_action ov7620_Initial[] = { /* 640x480 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, /* 00,02,40,cc */ - {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */ - {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, /* 00,83,02,cc */ - {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, /* 00,85,01,cc */ - {0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,80,cc */ - {0xa0, 0x81, ZC3XX_R087_EXPTIMEMID}, /* 00,87,81,cc */ - {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, /* 00,88,10,cc */ - {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */ - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */ - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ - {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */ - {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */ - {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ - {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ - {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */ - {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ - {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ - {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ - {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */ - {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */ - {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ - {0xaa, 0x1a, 0x00f1}, /* 00,1a,f1,aa */ - {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */ - {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */ - {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */ - {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */ - {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */ - {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ - {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */ - {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */ - {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ - {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */ - {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */ - {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */ - {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */ - {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */ - {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */ - {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */ - {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x68, ZC3XX_R116_RGAIN}, /* 01,16,68,cc */ - {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ - {0xa0, 0x40, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,40,cc */ - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ - {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */ - {} -}; -static const struct usb_action ov7620_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x50, ZC3XX_R002_CLOCKSELECT}, /* 00,02,50,cc */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */ - /* mx change? */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */ - {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, /* 00,83,02,cc */ - {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, /* 00,85,01,cc */ - {0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,80,cc */ - {0xa0, 0x81, ZC3XX_R087_EXPTIMEMID}, /* 00,87,81,cc */ - {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, /* 00,88,10,cc */ - {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */ - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0xd6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d6,cc */ - /* OV7648 00,9c,d8,cc */ - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ - {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */ - {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */ - {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ - {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ - {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */ - {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ - {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ - {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ - {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */ - {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */ - {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */ - {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */ - {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ - {0xaa, 0x1a, 0x00f2}, /* 00,1a,f2,aa */ - {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */ - {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */ - {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */ - {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ - {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */ - {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */ - {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ - {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */ - {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */ - {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */ - {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */ - {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */ - {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */ - {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */ - {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x68, ZC3XX_R116_RGAIN}, /* 01,16,68,cc */ - {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ - {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,50,cc */ - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ - {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */ - {} -}; -static const struct usb_action ov7620_50HZ[] = { - {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ - {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ - {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */ - {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ - {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ - {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */ - {0xaa, 0x10, 0x0082}, /* 00,10,82,aa */ - {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */ -/* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc - * if mode0 (640x480) */ - {} -}; -static const struct usb_action ov7620_60HZ[] = { - {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ - /* (bug in zs211.inf) */ - {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ - {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */ - {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ - {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ - {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */ - {0xaa, 0x10, 0x0020}, /* 00,10,20,aa */ - {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */ -/* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc - * if mode0 (640x480) */ -/* ?? in gspca v1, it was - {0xa0, 0x00, 0x0039}, * 00,00,00,dd * - {0xa1, 0x01, 0x0037}, */ - {} -}; -static const struct usb_action ov7620_NoFliker[] = { - {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ - /* (bug in zs211.inf) */ - {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ - {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */ - {0xaa, 0x75, 0x008e}, /* 00,75,8e,aa */ - {0xaa, 0x2d, 0x0001}, /* 00,2d,01,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ - {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,01,cc */ -/* {0xa0, 0x44, ZC3XX_R002_CLOCKSELECT}, * 00,02,44,cc - * if mode1 (320x240) */ -/* ?? was - {0xa0, 0x00, 0x0039}, * 00,00,00,dd * - {0xa1, 0x01, 0x0037}, */ - {} -}; - -static const struct usb_action ov7630c_InitialScale[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xaa, 0x12, 0x0080}, - {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, - {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, - {0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH}, - {0xa0, 0x91, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, - {0xaa, 0x12, 0x0069}, - {0xaa, 0x04, 0x0020}, - {0xaa, 0x06, 0x0050}, - {0xaa, 0x13, 0x0083}, - {0xaa, 0x14, 0x0000}, - {0xaa, 0x15, 0x0024}, - {0xaa, 0x17, 0x0018}, - {0xaa, 0x18, 0x00ba}, - {0xaa, 0x19, 0x0002}, - {0xaa, 0x1a, 0x00f6}, - {0xaa, 0x1b, 0x0002}, - {0xaa, 0x20, 0x00c2}, - {0xaa, 0x24, 0x0060}, - {0xaa, 0x25, 0x0040}, - {0xaa, 0x26, 0x0030}, - {0xaa, 0x27, 0x00ea}, - {0xaa, 0x28, 0x00a0}, - {0xaa, 0x21, 0x0000}, - {0xaa, 0x2a, 0x0081}, - {0xaa, 0x2b, 0x0096}, - {0xaa, 0x2d, 0x0094}, - {0xaa, 0x2f, 0x003d}, - {0xaa, 0x30, 0x0024}, - {0xaa, 0x60, 0x0000}, - {0xaa, 0x61, 0x0040}, - {0xaa, 0x68, 0x007c}, - {0xaa, 0x6f, 0x0015}, - {0xaa, 0x75, 0x0088}, - {0xaa, 0x77, 0x00b5}, - {0xaa, 0x01, 0x0060}, - {0xaa, 0x02, 0x0060}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x60, ZC3XX_R116_RGAIN}, - {0xa0, 0x46, ZC3XX_R118_BGAIN}, - {0xa0, 0x04, ZC3XX_R113_RGB03}, -/* 0x10, */ - {0xa1, 0x01, 0x0002}, - {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf8, ZC3XX_R10B_RGB01}, - {0xa0, 0xf8, ZC3XX_R10C_RGB02}, - {0xa0, 0xf8, ZC3XX_R10D_RGB10}, - {0xa0, 0x50, ZC3XX_R10E_RGB11}, - {0xa0, 0xf8, ZC3XX_R10F_RGB12}, - {0xa0, 0xf8, ZC3XX_R110_RGB20}, - {0xa0, 0xf8, ZC3XX_R111_RGB21}, - {0xa0, 0x50, ZC3XX_R112_RGB22}, - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - {0xa0, 0x01, ZC3XX_R120_GAMMA00}, /* gamma 2 ?*/ - {0xa0, 0x0c, ZC3XX_R121_GAMMA01}, - {0xa0, 0x1f, ZC3XX_R122_GAMMA02}, - {0xa0, 0x3a, ZC3XX_R123_GAMMA03}, - {0xa0, 0x53, ZC3XX_R124_GAMMA04}, - {0xa0, 0x6d, ZC3XX_R125_GAMMA05}, - {0xa0, 0x85, ZC3XX_R126_GAMMA06}, - {0xa0, 0x9c, ZC3XX_R127_GAMMA07}, - {0xa0, 0xb0, ZC3XX_R128_GAMMA08}, - {0xa0, 0xc2, ZC3XX_R129_GAMMA09}, - {0xa0, 0xd1, ZC3XX_R12A_GAMMA0A}, - {0xa0, 0xde, ZC3XX_R12B_GAMMA0B}, - {0xa0, 0xe9, ZC3XX_R12C_GAMMA0C}, - {0xa0, 0xf2, ZC3XX_R12D_GAMMA0D}, - {0xa0, 0xf9, ZC3XX_R12E_GAMMA0E}, - {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, - {0xa0, 0x05, ZC3XX_R130_GAMMA10}, - {0xa0, 0x0f, ZC3XX_R131_GAMMA11}, - {0xa0, 0x16, ZC3XX_R132_GAMMA12}, - {0xa0, 0x1a, ZC3XX_R133_GAMMA13}, - {0xa0, 0x19, ZC3XX_R134_GAMMA14}, - {0xa0, 0x19, ZC3XX_R135_GAMMA15}, - {0xa0, 0x17, ZC3XX_R136_GAMMA16}, - {0xa0, 0x15, ZC3XX_R137_GAMMA17}, - {0xa0, 0x12, ZC3XX_R138_GAMMA18}, - {0xa0, 0x10, ZC3XX_R139_GAMMA19}, - {0xa0, 0x0e, ZC3XX_R13A_GAMMA1A}, - {0xa0, 0x0b, ZC3XX_R13B_GAMMA1B}, - {0xa0, 0x09, ZC3XX_R13C_GAMMA1C}, - {0xa0, 0x08, ZC3XX_R13D_GAMMA1D}, - {0xa0, 0x06, ZC3XX_R13E_GAMMA1E}, - {0xa0, 0x03, ZC3XX_R13F_GAMMA1F}, - {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf8, ZC3XX_R10B_RGB01}, - {0xa0, 0xf8, ZC3XX_R10C_RGB02}, - {0xa0, 0xf8, ZC3XX_R10D_RGB10}, - {0xa0, 0x50, ZC3XX_R10E_RGB11}, - {0xa0, 0xf8, ZC3XX_R10F_RGB12}, - {0xa0, 0xf8, ZC3XX_R110_RGB20}, - {0xa0, 0xf8, ZC3XX_R111_RGB21}, - {0xa0, 0x50, ZC3XX_R112_RGB22}, - - {0xa1, 0x01, 0x0180}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xaa, 0x10, 0x001b}, - {0xaa, 0x76, 0x0002}, - {0xaa, 0x2a, 0x0081}, - {0xaa, 0x2b, 0x0000}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xb8, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x37, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xaa, 0x13, 0x0083}, /* 40 */ - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; - -static const struct usb_action ov7630c_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - - {0xaa, 0x12, 0x0080}, - {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, - {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, - {0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH}, - {0xa0, 0x91, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, - {0xaa, 0x12, 0x0069}, /* i2c */ - {0xaa, 0x04, 0x0020}, - {0xaa, 0x06, 0x0050}, - {0xaa, 0x13, 0x00c3}, - {0xaa, 0x14, 0x0000}, - {0xaa, 0x15, 0x0024}, - {0xaa, 0x19, 0x0003}, - {0xaa, 0x1a, 0x00f6}, - {0xaa, 0x1b, 0x0002}, - {0xaa, 0x20, 0x00c2}, - {0xaa, 0x24, 0x0060}, - {0xaa, 0x25, 0x0040}, - {0xaa, 0x26, 0x0030}, - {0xaa, 0x27, 0x00ea}, - {0xaa, 0x28, 0x00a0}, - {0xaa, 0x21, 0x0000}, - {0xaa, 0x2a, 0x0081}, - {0xaa, 0x2b, 0x0096}, - {0xaa, 0x2d, 0x0084}, - {0xaa, 0x2f, 0x003d}, - {0xaa, 0x30, 0x0024}, - {0xaa, 0x60, 0x0000}, - {0xaa, 0x61, 0x0040}, - {0xaa, 0x68, 0x007c}, - {0xaa, 0x6f, 0x0015}, - {0xaa, 0x75, 0x0088}, - {0xaa, 0x77, 0x00b5}, - {0xaa, 0x01, 0x0060}, - {0xaa, 0x02, 0x0060}, - {0xaa, 0x17, 0x0018}, - {0xaa, 0x18, 0x00ba}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x60, ZC3XX_R116_RGAIN}, - {0xa0, 0x46, ZC3XX_R118_BGAIN}, - {0xa0, 0x04, ZC3XX_R113_RGB03}, - - {0xa1, 0x01, 0x0002}, - {0xa0, 0x4e, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xfe, ZC3XX_R10B_RGB01}, - {0xa0, 0xf4, ZC3XX_R10C_RGB02}, - {0xa0, 0xf7, ZC3XX_R10D_RGB10}, - {0xa0, 0x4d, ZC3XX_R10E_RGB11}, - {0xa0, 0xfc, ZC3XX_R10F_RGB12}, - {0xa0, 0x00, ZC3XX_R110_RGB20}, - {0xa0, 0xf6, ZC3XX_R111_RGB21}, - {0xa0, 0x4a, ZC3XX_R112_RGB22}, - - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - {0xa0, 0x16, ZC3XX_R120_GAMMA00}, /* gamma ~4 */ - {0xa0, 0x3a, ZC3XX_R121_GAMMA01}, - {0xa0, 0x5b, ZC3XX_R122_GAMMA02}, - {0xa0, 0x7c, ZC3XX_R123_GAMMA03}, - {0xa0, 0x94, ZC3XX_R124_GAMMA04}, - {0xa0, 0xa9, ZC3XX_R125_GAMMA05}, - {0xa0, 0xbb, ZC3XX_R126_GAMMA06}, - {0xa0, 0xca, ZC3XX_R127_GAMMA07}, - {0xa0, 0xd7, ZC3XX_R128_GAMMA08}, - {0xa0, 0xe1, ZC3XX_R129_GAMMA09}, - {0xa0, 0xea, ZC3XX_R12A_GAMMA0A}, - {0xa0, 0xf1, ZC3XX_R12B_GAMMA0B}, - {0xa0, 0xf7, ZC3XX_R12C_GAMMA0C}, - {0xa0, 0xfc, ZC3XX_R12D_GAMMA0D}, - {0xa0, 0xff, ZC3XX_R12E_GAMMA0E}, - {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, - {0xa0, 0x20, ZC3XX_R130_GAMMA10}, - {0xa0, 0x22, ZC3XX_R131_GAMMA11}, - {0xa0, 0x20, ZC3XX_R132_GAMMA12}, - {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, - {0xa0, 0x16, ZC3XX_R134_GAMMA14}, - {0xa0, 0x13, ZC3XX_R135_GAMMA15}, - {0xa0, 0x10, ZC3XX_R136_GAMMA16}, - {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, - {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, - {0xa0, 0x09, ZC3XX_R139_GAMMA19}, - {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, - {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, - {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, - {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, - {0xa0, 0x00, ZC3XX_R13E_GAMMA1E}, - {0xa0, 0x01, ZC3XX_R13F_GAMMA1F}, - {0xa0, 0x4e, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xfe, ZC3XX_R10B_RGB01}, - {0xa0, 0xf4, ZC3XX_R10C_RGB02}, - {0xa0, 0xf7, ZC3XX_R10D_RGB10}, - {0xa0, 0x4d, ZC3XX_R10E_RGB11}, - {0xa0, 0xfc, ZC3XX_R10F_RGB12}, - {0xa0, 0x00, ZC3XX_R110_RGB20}, - {0xa0, 0xf6, ZC3XX_R111_RGB21}, - {0xa0, 0x4a, ZC3XX_R112_RGB22}, - - {0xa1, 0x01, 0x0180}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xaa, 0x10, 0x000d}, - {0xaa, 0x76, 0x0002}, - {0xaa, 0x2a, 0x0081}, - {0xaa, 0x2b, 0x0000}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xd8, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x1b, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xaa, 0x13, 0x00c3}, - - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; - -static const struct usb_action pas106b_Initial_com[] = { -/* Sream and Sensor specific */ - {0xa1, 0x01, 0x0010}, /* CMOSSensorSelect */ -/* System */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* SystemControl */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* SystemControl */ -/* Picture size */ - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* ClockSelect */ - {0xa0, 0x03, 0x003a}, - {0xa0, 0x0c, 0x003b}, - {0xa0, 0x04, 0x0038}, - {} -}; - -static const struct usb_action pas106b_InitialScale[] = { /* 176x144 */ -/* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, -/* Sream and Sensor specific */ - {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, -/* Picture size */ - {0xa0, 0x00, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0xb0, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x00, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0x90, ZC3XX_R006_FRAMEHEIGHTLOW}, -/* System */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, -/* Sream and Sensor specific */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, -/* Sensor Interface */ - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, -/* Window inside sensor array */ - {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, -/* Init the sensor */ - {0xaa, 0x02, 0x0004}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x09, 0x0005}, - {0xaa, 0x0a, 0x0002}, - {0xaa, 0x0b, 0x0002}, - {0xaa, 0x0c, 0x0005}, - {0xaa, 0x0d, 0x0000}, - {0xaa, 0x0e, 0x0002}, - {0xaa, 0x14, 0x0081}, -/* Other registers */ - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, -/* Frame retreiving */ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, -/* Gains */ - {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, -/* Unknown */ - {0xa0, 0x00, 0x01ad}, -/* Sharpness */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, -/* Other registers */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, -/* Auto exposure and white balance */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, -/*Dead pixels */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, -/* EEPROM */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, -/* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, -/* Other registers */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, -/* Auto exposure and white balance */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, -/*Dead pixels */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, -/* EEPROM */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, -/* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, - - {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf4, ZC3XX_R10B_RGB01}, - {0xa0, 0xf4, ZC3XX_R10C_RGB02}, - {0xa0, 0xf4, ZC3XX_R10D_RGB10}, - {0xa0, 0x58, ZC3XX_R10E_RGB11}, - {0xa0, 0xf4, ZC3XX_R10F_RGB12}, - {0xa0, 0xf4, ZC3XX_R110_RGB20}, - {0xa0, 0xf4, ZC3XX_R111_RGB21}, - {0xa0, 0x58, ZC3XX_R112_RGB22}, -/* Auto correction */ - {0xa0, 0x03, ZC3XX_R181_WINXSTART}, - {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, - {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, - {0xa0, 0x03, ZC3XX_R184_WINYSTART}, - {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, - {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, -/* Auto exposure and white balance */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, -/* sensor on */ - {0xaa, 0x07, 0x00b1}, - {0xaa, 0x05, 0x0003}, - {0xaa, 0x04, 0x0001}, - {0xaa, 0x03, 0x003b}, -/* Gains */ - {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, -/* Auto correction */ - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, -/* Gains */ - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - {} -}; - -static const struct usb_action pas106b_Initial[] = { /* 352x288 */ -/* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, -/* Sream and Sensor specific */ - {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, -/* Picture size */ - {0xa0, 0x01, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x60, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0x20, ZC3XX_R006_FRAMEHEIGHTLOW}, -/* System */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, -/* Sream and Sensor specific */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, -/* Sensor Interface */ - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, -/* Window inside sensor array */ - {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, -/* Init the sensor */ - {0xaa, 0x02, 0x0004}, - {0xaa, 0x08, 0x0000}, - {0xaa, 0x09, 0x0005}, - {0xaa, 0x0a, 0x0002}, - {0xaa, 0x0b, 0x0002}, - {0xaa, 0x0c, 0x0005}, - {0xaa, 0x0d, 0x0000}, - {0xaa, 0x0e, 0x0002}, - {0xaa, 0x14, 0x0081}, -/* Other registers */ - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, -/* Frame retreiving */ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, -/* Gains */ - {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, -/* Unknown */ - {0xa0, 0x00, 0x01ad}, -/* Sharpness */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, -/* Other registers */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, -/* Auto exposure and white balance */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x80, ZC3XX_R18D_YTARGET}, -/*Dead pixels */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, -/* EEPROM */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, -/* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, -/* Other registers */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, -/* Auto exposure and white balance */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, -/*Dead pixels */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, -/* EEPROM */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, -/* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, - - {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf4, ZC3XX_R10B_RGB01}, - {0xa0, 0xf4, ZC3XX_R10C_RGB02}, - {0xa0, 0xf4, ZC3XX_R10D_RGB10}, - {0xa0, 0x58, ZC3XX_R10E_RGB11}, - {0xa0, 0xf4, ZC3XX_R10F_RGB12}, - {0xa0, 0xf4, ZC3XX_R110_RGB20}, - {0xa0, 0xf4, ZC3XX_R111_RGB21}, - {0xa0, 0x58, ZC3XX_R112_RGB22}, -/* Auto correction */ - {0xa0, 0x03, ZC3XX_R181_WINXSTART}, - {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, - {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, - {0xa0, 0x03, ZC3XX_R184_WINYSTART}, - {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, - {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - -/* Auto exposure and white balance */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, - - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, - - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, -/* sensor on */ - {0xaa, 0x07, 0x00b1}, - {0xaa, 0x05, 0x0003}, - {0xaa, 0x04, 0x0001}, - {0xaa, 0x03, 0x003b}, -/* Gains */ - {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, -/* Auto correction */ - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, -/* Gains */ - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, - - {0xa0, 0x00, 0x0007}, /* AutoCorrectEnable */ - {0xa0, 0xff, ZC3XX_R018_FRAMELOST}, /* Frame adjust */ - {} -}; -static const struct usb_action pas106b_50HZ[] = { - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ - {0xa0, 0x54, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,54,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,87,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,30,cc */ - {0xaa, 0x03, 0x0021}, /* 00,03,21,aa */ - {0xaa, 0x04, 0x000c}, /* 00,04,0c,aa */ - {0xaa, 0x05, 0x0002}, /* 00,05,02,aa */ - {0xaa, 0x07, 0x001c}, /* 00,07,1c,aa */ - {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */ - {} -}; -static const struct usb_action pas106b_60HZ[] = { - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ - {0xa0, 0x2e, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,2e,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x71, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,71,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,30,cc */ - {0xaa, 0x03, 0x001c}, /* 00,03,1c,aa */ - {0xaa, 0x04, 0x0004}, /* 00,04,04,aa */ - {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */ - {0xaa, 0x07, 0x00c4}, /* 00,07,c4,aa */ - {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */ - {} -}; -static const struct usb_action pas106b_NoFliker[] = { - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ - {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xaa, 0x03, 0x0013}, /* 00,03,13,aa */ - {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */ - {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */ - {0xaa, 0x07, 0x0030}, /* 00,07,30,aa */ - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {} -}; - -/* from lvWIMv.inf 046d:08a2/:08aa 2007/06/03 */ -static const struct usb_action pas202b_Initial[] = { /* 640x480 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */ - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,03,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,03,cc */ - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ - {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */ - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ - {0xaa, 0x02, 0x0002}, /* 00,02,04,aa --> 02 */ - {0xaa, 0x07, 0x0006}, /* 00,07,06,aa */ - {0xaa, 0x08, 0x0002}, /* 00,08,02,aa */ - {0xaa, 0x09, 0x0006}, /* 00,09,06,aa */ - {0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */ - {0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */ - {0xaa, 0x0c, 0x0006}, - {0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ - {0xaa, 0x12, 0x0005}, /* 00,12,05,aa */ - {0xaa, 0x13, 0x0063}, /* 00,13,63,aa */ - {0xaa, 0x15, 0x0070}, /* 00,15,70,aa */ - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x70, ZC3XX_R18D_YTARGET}, /* 01,8d,70,cc */ - {} -}; -static const struct usb_action pas202b_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */ - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ - {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,08,cc */ - {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,02,cc */ - {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,08,cc */ - {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,02,cc */ - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ - {0xaa, 0x02, 0x0002}, /* 00,02,02,aa */ - {0xaa, 0x07, 0x0006}, /* 00,07,06,aa */ - {0xaa, 0x08, 0x0002}, /* 00,08,02,aa */ - {0xaa, 0x09, 0x0006}, /* 00,09,06,aa */ - {0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */ - {0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */ - {0xaa, 0x0c, 0x0006}, - {0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ - {0xaa, 0x12, 0x0005}, /* 00,12,05,aa */ - {0xaa, 0x13, 0x0063}, /* 00,13,63,aa */ - {0xaa, 0x15, 0x0070}, /* 00,15,70,aa */ - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x70, ZC3XX_R18D_YTARGET}, /* 01,8d,70,cc */ - {0xa0, 0xff, ZC3XX_R097_WINYSTARTHIGH}, - {0xa0, 0xfe, ZC3XX_R098_WINYSTARTLOW}, - {} -}; -static const struct usb_action pas202b_50HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ - {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ - {0xaa, 0x21, 0x001b}, - {0xaa, 0x03, 0x0044}, /* 00,03,44,aa */ - {0xaa, 0x04, 0x0008}, - {0xaa, 0x05, 0x001b}, - {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ - {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ - {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4d,cc */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x44, ZC3XX_R01D_HSYNC_0}, /* 00,1d,44,cc */ - {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */ - {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */ - {0xa0, 0xeb, ZC3XX_R020_HSYNC_3}, /* 00,20,eb,cc */ - {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ - {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ - {} -}; -static const struct usb_action pas202b_50HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ - {0xaa, 0x20, 0x0004}, - {0xaa, 0x21, 0x003d}, - {0xaa, 0x03, 0x0041}, /* 00,03,41,aa */ - {0xaa, 0x04, 0x0010}, - {0xaa, 0x05, 0x003d}, - {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ - {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ - {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,9b,cc */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, /* 00,1d,41,cc */ - {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */ - {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ - {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ - {} -}; -static const struct usb_action pas202b_60HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ - {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ - {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ - {0xaa, 0x03, 0x0045}, /* 00,03,45,aa */ - {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */ - {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ - {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ - {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ - {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x40, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,40,cc */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x45, ZC3XX_R01D_HSYNC_0}, /* 00,1d,45,cc */ - {0xa0, 0x8e, ZC3XX_R01E_HSYNC_1}, /* 00,1e,8e,cc */ - {0xa0, 0xc1, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c1,cc */ - {0xa0, 0xf5, ZC3XX_R020_HSYNC_3}, /* 00,20,f5,cc */ - {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ - {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ - {} -}; -static const struct usb_action pas202b_60HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ - {0xaa, 0x20, 0x0004}, - {0xaa, 0x21, 0x0008}, - {0xaa, 0x03, 0x0042}, /* 00,03,42,aa */ - {0xaa, 0x04, 0x0010}, - {0xaa, 0x05, 0x0008}, - {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ - {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ - {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x08, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x42, ZC3XX_R01D_HSYNC_0}, /* 00,1d,42,cc */ - {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */ - {0xa0, 0xaf, ZC3XX_R01F_HSYNC_2}, /* 00,1f,af,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ - {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ - {} -}; -static const struct usb_action pas202b_NoFliker[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ - {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ - {0xaa, 0x21, 0x0006}, - {0xaa, 0x03, 0x0040}, /* 00,03,40,aa */ - {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */ - {0xaa, 0x05, 0x0006}, - {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ - {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x06, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */ - {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */ - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ - {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ - {} -}; -static const struct usb_action pas202b_NoFlikerScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ - {0xaa, 0x20, 0x0004}, - {0xaa, 0x21, 0x000c}, - {0xaa, 0x03, 0x0040}, /* 00,03,40,aa */ - {0xaa, 0x04, 0x0010}, - {0xaa, 0x05, 0x000c}, - {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ - {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x0c, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,02,cc */ - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */ - {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */ - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ - {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ - {} -}; - -/* mt9v111 (mi0360soc) and pb0330 from vm30x.inf 0ac8:301b 07/02/13 */ -static const struct usb_action mt9v111_1_Initial[] = { /* 640x480 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, - {0xdd, 0x00, 0x0200}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xaa, 0x01, 0x0001}, - {0xaa, 0x06, 0x0000}, - {0xaa, 0x08, 0x0483}, - {0xaa, 0x01, 0x0004}, - {0xaa, 0x08, 0x0006}, - {0xaa, 0x02, 0x0011}, - {0xaa, 0x03, 0x01e5}, /*jfm: was 01e7*/ - {0xaa, 0x04, 0x0285}, /*jfm: was 0287*/ - {0xaa, 0x07, 0x3002}, - {0xaa, 0x20, 0x5100}, - {0xaa, 0x35, 0x507f}, - {0xaa, 0x30, 0x0005}, - {0xaa, 0x31, 0x0000}, - {0xaa, 0x58, 0x0078}, - {0xaa, 0x62, 0x0411}, - {0xaa, 0x2b, 0x007f}, - {0xaa, 0x2c, 0x007f}, /*jfm: was 0030*/ - {0xaa, 0x2d, 0x007f}, /*jfm: was 0030*/ - {0xaa, 0x2e, 0x007f}, /*jfm: was 0030*/ - {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x09, 0x01ad}, /*jfm: was 00*/ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, - {0xa0, 0x61, ZC3XX_R116_RGAIN}, - {0xa0, 0x65, ZC3XX_R118_BGAIN}, - {} -}; -static const struct usb_action mt9v111_1_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, - {0xdd, 0x00, 0x0200}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xaa, 0x01, 0x0001}, - {0xaa, 0x06, 0x0000}, - {0xaa, 0x08, 0x0483}, - {0xaa, 0x01, 0x0004}, - {0xaa, 0x08, 0x0006}, - {0xaa, 0x02, 0x0011}, - {0xaa, 0x03, 0x01e7}, - {0xaa, 0x04, 0x0287}, - {0xaa, 0x07, 0x3002}, - {0xaa, 0x20, 0x5100}, - {0xaa, 0x35, 0x007f}, /*jfm: was 0050*/ - {0xaa, 0x30, 0x0005}, - {0xaa, 0x31, 0x0000}, - {0xaa, 0x58, 0x0078}, - {0xaa, 0x62, 0x0411}, - {0xaa, 0x2b, 0x007f}, /*jfm: was 28*/ - {0xaa, 0x2c, 0x007f}, /*jfm: was 30*/ - {0xaa, 0x2d, 0x007f}, /*jfm: was 30*/ - {0xaa, 0x2e, 0x007f}, /*jfm: was 28*/ - {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x09, 0x01ad}, /*jfm: was 00*/ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, - {0xa0, 0x61, ZC3XX_R116_RGAIN}, - {0xa0, 0x65, ZC3XX_R118_BGAIN}, - {} -}; -static const struct usb_action mt9v111_1_AE50HZ[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0562}, - {0xbb, 0x01, 0x09aa}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x9b, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_1_AE50HZScale[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0509}, - {0xbb, 0x01, 0x0934}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_1_AE60HZ[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x05, 0x003d}, - {0xaa, 0x09, 0x016e}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xdd, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_1_AE60HZScale[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0509}, - {0xbb, 0x01, 0x0983}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x8f, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_1_AENoFliker[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0509}, - {0xbb, 0x01, 0x0960}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_1_AENoFlikerScale[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0534}, - {0xbb, 0x02, 0x0960}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x34, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -/* from usbvm303.inf 0ac8:303b 07/03/25 (3 - tas5130c) */ -static const struct usb_action mt9v111_3_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, - {0xdd, 0x00, 0x0200}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xaa, 0x01, 0x0001}, /* select IFP/SOC registers */ - {0xaa, 0x06, 0x0000}, /* operating mode control */ - {0xaa, 0x08, 0x0483}, /* output format control */ - /* H red first, V red or blue first, - * raw Bayer, auto flicker */ - {0xaa, 0x01, 0x0004}, /* select sensor core registers */ - {0xaa, 0x08, 0x0006}, /* row start */ - {0xaa, 0x02, 0x0011}, /* column start */ - {0xaa, 0x03, 0x01e5}, /* window height - 1 */ - {0xaa, 0x04, 0x0285}, /* window width - 1 */ - {0xaa, 0x07, 0x3002}, /* output control */ - {0xaa, 0x20, 0x1100}, /* read mode: bits 8 & 12 (?) */ - {0xaa, 0x35, 0x007f}, /* global gain */ - {0xaa, 0x30, 0x0005}, - {0xaa, 0x31, 0x0000}, - {0xaa, 0x58, 0x0078}, - {0xaa, 0x62, 0x0411}, - {0xaa, 0x2b, 0x007f}, /* green1 gain */ - {0xaa, 0x2c, 0x007f}, /* blue gain */ - {0xaa, 0x2d, 0x007f}, /* red gain */ - {0xaa, 0x2e, 0x007f}, /* green2 gain */ - {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x80, ZC3XX_R18D_YTARGET}, - {0xa0, 0x61, ZC3XX_R116_RGAIN}, - {0xa0, 0x65, ZC3XX_R118_BGAIN}, - {} -}; -static const struct usb_action mt9v111_3_InitialScale[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, - {0xdd, 0x00, 0x0200}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xaa, 0x01, 0x0001}, - {0xaa, 0x06, 0x0000}, - {0xaa, 0x08, 0x0483}, - {0xaa, 0x01, 0x0004}, - {0xaa, 0x08, 0x0006}, - {0xaa, 0x02, 0x0011}, - {0xaa, 0x03, 0x01e7}, - {0xaa, 0x04, 0x0287}, - {0xaa, 0x07, 0x3002}, - {0xaa, 0x20, 0x1100}, - {0xaa, 0x35, 0x007f}, - {0xaa, 0x30, 0x0005}, - {0xaa, 0x31, 0x0000}, - {0xaa, 0x58, 0x0078}, - {0xaa, 0x62, 0x0411}, - {0xaa, 0x2b, 0x007f}, - {0xaa, 0x2c, 0x007f}, - {0xaa, 0x2d, 0x007f}, - {0xaa, 0x2e, 0x007f}, - {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x80, ZC3XX_R18D_YTARGET}, - {0xa0, 0x61, ZC3XX_R116_RGAIN}, - {0xa0, 0x65, ZC3XX_R118_BGAIN}, - {} -}; -static const struct usb_action mt9v111_3_AE50HZ[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x05, 0x0009}, /* horizontal blanking */ - {0xaa, 0x09, 0x01ce}, /* shutter width */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_3_AE50HZScale[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x05, 0x0009}, - {0xaa, 0x09, 0x01ce}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_3_AE60HZ[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x05, 0x0009}, - {0xaa, 0x09, 0x0083}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x8f, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_3_AE60HZScale[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x05, 0x0009}, - {0xaa, 0x09, 0x0083}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x8f, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_3_AENoFliker[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x05, 0x0034}, - {0xaa, 0x09, 0x0260}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x34, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; -static const struct usb_action mt9v111_3_AENoFlikerScale[] = { - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x05, 0x0034}, - {0xaa, 0x09, 0x0260}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x34, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {} -}; - -static const struct usb_action pb0330_Initial[] = { /* 640x480 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xdd, 0x00, 0x0200}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xaa, 0x01, 0x0006}, - {0xaa, 0x02, 0x0011}, - {0xaa, 0x03, 0x01e5}, /*jfm: was 1e7*/ - {0xaa, 0x04, 0x0285}, /*jfm: was 0287*/ - {0xaa, 0x06, 0x0003}, - {0xaa, 0x07, 0x3002}, - {0xaa, 0x20, 0x1100}, - {0xaa, 0x2f, 0xf7b0}, - {0xaa, 0x30, 0x0005}, - {0xaa, 0x31, 0x0000}, - {0xaa, 0x34, 0x0100}, - {0xaa, 0x35, 0x0060}, - {0xaa, 0x3d, 0x068f}, - {0xaa, 0x40, 0x01e0}, - {0xaa, 0x58, 0x0078}, - {0xaa, 0x62, 0x0411}, - {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x09, 0x01ad}, /*jfm: was 00 */ - {0xa0, 0x15, 0x01ae}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /*jfm: was 6c*/ - {} -}; -static const struct usb_action pb0330_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ - {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, - {0xdd, 0x00, 0x0200}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xaa, 0x01, 0x0006}, - {0xaa, 0x02, 0x0011}, - {0xaa, 0x03, 0x01e7}, - {0xaa, 0x04, 0x0287}, - {0xaa, 0x06, 0x0003}, - {0xaa, 0x07, 0x3002}, - {0xaa, 0x20, 0x1100}, - {0xaa, 0x2f, 0xf7b0}, - {0xaa, 0x30, 0x0005}, - {0xaa, 0x31, 0x0000}, - {0xaa, 0x34, 0x0100}, - {0xaa, 0x35, 0x0060}, - {0xaa, 0x3d, 0x068f}, - {0xaa, 0x40, 0x01e0}, - {0xaa, 0x58, 0x0078}, - {0xaa, 0x62, 0x0411}, - {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x09, 0x01ad}, - {0xa0, 0x15, 0x01ae}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /*jfm: was 6c*/ - {} -}; -static const struct usb_action pb0330_50HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x055c}, - {0xbb, 0x01, 0x09aa}, - {0xbb, 0x00, 0x1001}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xc4, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x5c, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action pb0330_50HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0566}, - {0xbb, 0x02, 0x09b2}, - {0xbb, 0x00, 0x1002}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x8c, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xf0, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action pb0330_60HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0535}, - {0xbb, 0x01, 0x0974}, - {0xbb, 0x00, 0x1001}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xfe, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x3e, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x35, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xd0, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action pb0330_60HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0535}, - {0xbb, 0x02, 0x096c}, - {0xbb, 0x00, 0x1002}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xc0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x7c, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x35, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xd0, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action pb0330_NoFliker[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0509}, - {0xbb, 0x02, 0x0940}, - {0xbb, 0x00, 0x1002}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, - {} -}; -static const struct usb_action pb0330_NoFlikerScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xbb, 0x00, 0x0535}, - {0xbb, 0x01, 0x0980}, - {0xbb, 0x00, 0x1001}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x35, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, - {} -}; - -/* from oem9.inf */ -static const struct usb_action po2030_Initial[] = { /* 640x480 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */ - {0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */ - {0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */ - {0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */ - {0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */ - {0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */ - {0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */ - {0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ - {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */ - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ - {0xaa, 0x09, 0x00ce}, /* 00,09,ce,aa */ - {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */ - {0xaa, 0x0d, 0x0054}, /* 00,0d,54,aa */ - {0xaa, 0x0f, 0x00eb}, /* 00,0f,eb,aa */ - {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */ - {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */ - {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */ - {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */ - {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */ - {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */ - {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */ - {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ - {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */ - {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */ - {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */ - {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */ - {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */ - {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */ - {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */ - {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */ - {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */ - {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */ - {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ - {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */ - {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */ - {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */ - {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */ - {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */ - {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */ - {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */ - {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */ - {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */ - {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */ - {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */ - {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */ - {0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */ - {} -}; - -/* from oem9.inf */ -static const struct usb_action po2030_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ - {0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */ - {0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */ - {0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */ - {0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */ - {0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */ - {0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */ - {0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */ - {0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ - {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc */ - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ - {0xaa, 0x09, 0x00cc}, /* 00,09,cc,aa */ - {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */ - {0xaa, 0x0d, 0x0058}, /* 00,0d,58,aa */ - {0xaa, 0x0f, 0x00ed}, /* 00,0f,ed,aa */ - {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */ - {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */ - {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */ - {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */ - {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */ - {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */ - {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */ - {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ - {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */ - {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */ - {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */ - {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */ - {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */ - {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */ - {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */ - {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */ - {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */ - {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */ - {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ - {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */ - {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */ - {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */ - {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */ - {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */ - {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */ - {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */ - {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */ - {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */ - {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */ - {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */ - {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ - {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ - {0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */ - {0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */ - {} -}; - -static const struct usb_action po2030_50HZ[] = { - {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ - {0xaa, 0x1a, 0x0001}, /* 00,1a,01,aa */ - {0xaa, 0x1b, 0x000a}, /* 00,1b,0a,aa */ - {0xaa, 0x1c, 0x00b0}, /* 00,1c,b0,aa */ - {0xa0, 0x05, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,05,cc */ - {0xa0, 0x35, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,35,cc */ - {0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x85, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,85,cc */ - {0xa0, 0x58, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,58,cc */ - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ - {0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,22,cc */ - {0xa0, 0x88, ZC3XX_R18D_YTARGET}, /* 01,8d,88,cc */ - {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ - {} -}; - -static const struct usb_action po2030_60HZ[] = { - {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ - {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ - {0xaa, 0x1b, 0x00de}, /* 00,1b,de,aa */ - {0xaa, 0x1c, 0x0040}, /* 00,1c,40,aa */ - {0xa0, 0x08, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,08,cc */ - {0xa0, 0xae, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,ae,cc */ - {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x6f, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,6f,cc */ - {0xa0, 0x20, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,20,cc */ - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ - {0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,22,cc */ - {0xa0, 0x88, ZC3XX_R18D_YTARGET}, /* 01,8d,88,cc */ - /* win: 01,8d,80 */ - {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ - {} -}; - -static const struct usb_action po2030_NoFliker[] = { - {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ - {0xaa, 0x8d, 0x000d}, /* 00,8d,0d,aa */ - {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ - {0xaa, 0x1b, 0x0002}, /* 00,1b,02,aa */ - {0xaa, 0x1c, 0x0078}, /* 00,1c,78,aa */ - {0xaa, 0x46, 0x0000}, /* 00,46,00,aa */ - {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */ - {} -}; - -static const struct usb_action tas5130c_InitialScale[] = { /* 320x240 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x50, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - - {0xa0, 0x04, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x04, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, - {0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE}, - {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x70, ZC3XX_R18D_YTARGET}, - {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, - {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, - {} -}; -static const struct usb_action tas5130c_Initial[] = { /* 640x480 */ - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x05, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x05, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, - {0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE}, - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x70, ZC3XX_R18D_YTARGET}, - {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, - {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, - {} -}; -static const struct usb_action tas5130c_50HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ - {0xaa, 0xa4, 0x0063}, /* 00,a4,63,aa */ - {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ - {0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,63,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xfe, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc */ - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xd3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,d3,cc */ - {0xa0, 0xda, ZC3XX_R01E_HSYNC_1}, /* 00,1e,da,cc */ - {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ - {0xa0, 0x4c, ZC3XX_R0A0_MAXXLOW}, - {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, - {} -}; -static const struct usb_action tas5130c_50HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ - {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */ - {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ - {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xd0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */ - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xf0, ZC3XX_R01D_HSYNC_0}, /* 00,1d,f0,cc */ - {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f4,cc */ - {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ - {0xa0, 0xc0, ZC3XX_R0A0_MAXXLOW}, - {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, - {} -}; -static const struct usb_action tas5130c_60HZ[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ - {0xaa, 0xa4, 0x0036}, /* 00,a4,36,aa */ - {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ - {0xa0, 0x36, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,36,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x54, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x3e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3e,cc */ - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xca, ZC3XX_R01D_HSYNC_0}, /* 00,1d,ca,cc */ - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ - {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ - {0xa0, 0x28, ZC3XX_R0A0_MAXXLOW}, - {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, - {} -}; -static const struct usb_action tas5130c_60HZScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ - {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */ - {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ - {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x09, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x47, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ - {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */ - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */ - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ - {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ - {0xa0, 0x20, ZC3XX_R0A0_MAXXLOW}, - {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, - {} -}; -static const struct usb_action tas5130c_NoFliker[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ - {0xaa, 0xa4, 0x0040}, /* 00,a4,40,aa */ - {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ - {0xa0, 0x40, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,40,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ - {0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */ - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ - {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */ - {0xa0, 0xf0, ZC3XX_R0A0_MAXXLOW}, - {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, - {} -}; - -static const struct usb_action tas5130c_NoFlikerScale[] = { - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ - {0xaa, 0xa4, 0x0090}, /* 00,a4,90,aa */ - {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ - {0xa0, 0x90, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,90,cc */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ - {0xa0, 0x0a, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ - {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ - {0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */ - {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ - {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ - {0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */ - {0xa0, 0xf0, ZC3XX_R0A0_MAXXLOW}, - {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, - {} -}; - -static const struct usb_action gc0303_InitialScale[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ - {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc, - * 0<->10 */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc, */ - {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc, */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc, */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc, */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc, */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc, */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc, */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc, */ - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc, - * 6<->8 */ - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc, - * 6<->8 */ - {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ - {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ - {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ - {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ - {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ - {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ - {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ -/*?? {0xaa, 0x01, 0x0000}, */ - {0xaa, 0x01, 0x0000}, - {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ - {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ - {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ - {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ - {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ - {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ - {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ - {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ - {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ - {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ - {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ - {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ - {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ -/*?? {0xa0, 0x00, 0x0039}, - {0xa1, 0x01, 0x0037}, */ - {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ - {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */ - {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ - {0xaa, 0x19, 0x0088}, /* 00,19,86,aa, */ - {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */ - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */ - {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc, */ - {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc, */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ - {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ - {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ - {} -}; - -static const struct usb_action gc0303_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ - {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ - {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc, */ - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc, */ - {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc, */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc, */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc, */ - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc, */ - {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc, */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc, */ - {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc, */ - {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc, - * 8<->6 */ - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc, - * 8<->6 */ - {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ - {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ - {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ - {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ - {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ - {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ - {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ -/*?? {0xaa, 0x01, 0x0000}, */ - {0xaa, 0x01, 0x0000}, - {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ - {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ - {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ - {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ - {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ - {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ - {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ - {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ - {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ - {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ - {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ - {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ - {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ -/*?? {0xa0, 0x00, 0x0039}, - {0xa1, 0x01, 0x0037}, */ - {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ - {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */ - {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ - {0xaa, 0x19, 0x0088}, /* 00,19,88,aa, */ - {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */ - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */ - {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */ - {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc, */ - {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc, */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ - {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ - {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ - {} -}; -static const struct usb_action gc0303_50HZScale[] = { - {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ - {0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ - {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */ - {0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ - {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ - {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ - {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ - {} -}; - -static const struct usb_action gc0303_50HZ[] = { - {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0003}, /* 00,83,03,aa */ - {0xaa, 0x84, 0x0054}, /* 00,84,54,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ - {0xa0, 0x0d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */ - {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ - {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,8e,cc, */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ - {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ - {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ - {} -}; - -static const struct usb_action gc0303_60HZScale[] = { - {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ - {0xaa, 0x84, 0x0062}, /* 00,84,62,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ - {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ - {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ - {0xa0, 0x3b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3b,cc, */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ - {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ - {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ - {} -}; - -static const struct usb_action gc0303_60HZ[] = { - {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */ - {0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ - {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,1,0b,cc, */ - {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,2,10,cc, */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,5,00,cc, */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,6,00,cc, */ - {0xa0, 0x76, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,7,76,cc, */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,c,0e,cc, */ - {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,f,15,cc, */ - {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,9,10,cc, */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,a,24,cc, */ - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,d,62,cc, */ - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,e,90,cc, */ - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,f,c8,cc, */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,0,ff,cc, */ - {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,d,58,cc, */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,d,78,cc */ - {} -}; - -static const struct usb_action gc0303_NoFlikerScale[] = { - {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ - {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ - {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,0,00,cc, */ - {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ - {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ - {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ - {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ - {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ - {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */ - {} -}; - -static const struct usb_action gc0303_NoFliker[] = { - {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ - {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ - {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ - {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc, */ - {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc, */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ - {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ - {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ - {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ - {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ - {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ - {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ - {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ - {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */ - {} -}; - -static u8 reg_r_i(struct gspca_dev *gspca_dev, - u16 index) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return 0; - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0xa1, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x01, /* value */ - index, gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { - err("reg_r_i err %d", ret); - gspca_dev->usb_err = ret; - return 0; - } - return gspca_dev->usb_buf[0]; -} - -static u8 reg_r(struct gspca_dev *gspca_dev, - u16 index) -{ - u8 ret; - - ret = reg_r_i(gspca_dev, index); - PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret); - return ret; -} - -static void reg_w_i(struct gspca_dev *gspca_dev, - u8 value, - u16 index) -{ - int ret; - - if (gspca_dev->usb_err < 0) - return; - ret = usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0xa0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, - 500); - if (ret < 0) { - err("reg_w_i err %d", ret); - gspca_dev->usb_err = ret; - } -} - -static void reg_w(struct gspca_dev *gspca_dev, - u8 value, - u16 index) -{ - PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value); - reg_w_i(gspca_dev, value, index); -} - -static u16 i2c_read(struct gspca_dev *gspca_dev, - u8 reg) -{ - u8 retbyte; - u16 retval; - - if (gspca_dev->usb_err < 0) - return 0; - reg_w_i(gspca_dev, reg, 0x0092); - reg_w_i(gspca_dev, 0x02, 0x0090); /* <- read command */ - msleep(20); - retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ - if (retbyte != 0x00) - err("i2c_r status error %02x", retbyte); - retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ - retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */ - PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)", - reg, retval, retbyte); - return retval; -} - -static u8 i2c_write(struct gspca_dev *gspca_dev, - u8 reg, - u8 valL, - u8 valH) -{ - u8 retbyte; - - if (gspca_dev->usb_err < 0) - return 0; - reg_w_i(gspca_dev, reg, 0x92); - reg_w_i(gspca_dev, valL, 0x93); - reg_w_i(gspca_dev, valH, 0x94); - reg_w_i(gspca_dev, 0x01, 0x90); /* <- write command */ - msleep(1); - retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ - if (retbyte != 0x00) - err("i2c_w status error %02x", retbyte); - PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)", - reg, valH, valL, retbyte); - return retbyte; -} - -static void usb_exchange(struct gspca_dev *gspca_dev, - const struct usb_action *action) -{ - while (action->req) { - switch (action->req) { - case 0xa0: /* write register */ - reg_w(gspca_dev, action->val, action->idx); - break; - case 0xa1: /* read status */ - reg_r(gspca_dev, action->idx); - break; - case 0xaa: - i2c_write(gspca_dev, - action->val, /* reg */ - action->idx & 0xff, /* valL */ - action->idx >> 8); /* valH */ - break; - case 0xbb: - i2c_write(gspca_dev, - action->idx >> 8, /* reg */ - action->idx & 0xff, /* valL */ - action->val); /* valH */ - break; - default: -/* case 0xdd: * delay */ - msleep(action->idx); - break; - } - action++; - msleep(1); - } -} - -static void setmatrix(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - const u8 *matrix; - static const u8 adcm2700_matrix[9] = -/* {0x66, 0xed, 0xed, 0xed, 0x66, 0xed, 0xed, 0xed, 0x66}; */ -/*ms-win*/ - {0x74, 0xed, 0xed, 0xed, 0x74, 0xed, 0xed, 0xed, 0x74}; - static const u8 gc0305_matrix[9] = - {0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50}; - static const u8 ov7620_matrix[9] = - {0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58}; - static const u8 pas202b_matrix[9] = - {0x4c, 0xf5, 0xff, 0xf9, 0x51, 0xf5, 0xfb, 0xed, 0x5f}; - static const u8 po2030_matrix[9] = - {0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60}; - static const u8 tas5130c_matrix[9] = - {0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68}; - static const u8 gc0303_matrix[9] = - {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b}; - static const u8 *matrix_tb[SENSOR_MAX] = { - [SENSOR_ADCM2700] = adcm2700_matrix, - [SENSOR_CS2102] = ov7620_matrix, - [SENSOR_CS2102K] = NULL, - [SENSOR_GC0303] = gc0303_matrix, - [SENSOR_GC0305] = gc0305_matrix, - [SENSOR_HDCS2020] = NULL, - [SENSOR_HV7131B] = NULL, - [SENSOR_HV7131R] = po2030_matrix, - [SENSOR_ICM105A] = po2030_matrix, - [SENSOR_MC501CB] = NULL, - [SENSOR_MT9V111_1] = gc0305_matrix, - [SENSOR_MT9V111_3] = gc0305_matrix, - [SENSOR_OV7620] = ov7620_matrix, - [SENSOR_OV7630C] = NULL, - [SENSOR_PAS106] = NULL, - [SENSOR_PAS202B] = pas202b_matrix, - [SENSOR_PB0330] = gc0305_matrix, - [SENSOR_PO2030] = po2030_matrix, - [SENSOR_TAS5130C] = tas5130c_matrix, - }; - - matrix = matrix_tb[sd->sensor]; - if (matrix == NULL) - return; /* matrix already loaded */ - for (i = 0; i < ARRAY_SIZE(ov7620_matrix); i++) - reg_w(gspca_dev, matrix[i], 0x010a + i); -} - -static void setsharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int sharpness; - static const u8 sharpness_tb[][2] = { - {0x02, 0x03}, - {0x04, 0x07}, - {0x08, 0x0f}, - {0x10, 0x1e} - }; - - sharpness = sd->ctrls[SHARPNESS].val; - reg_w(gspca_dev, sharpness_tb[sharpness][0], 0x01c6); - reg_r(gspca_dev, 0x01c8); - reg_r(gspca_dev, 0x01c9); - reg_r(gspca_dev, 0x01ca); - reg_w(gspca_dev, sharpness_tb[sharpness][1], 0x01cb); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - const u8 *Tgamma; - int g, i, brightness, contrast, adj, gp1, gp2; - u8 gr[16]; - static const u8 delta_b[16] = /* delta for brightness */ - {0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d, - 0x1d, 0x1b, 0x1b, 0x1b, 0x19, 0x18, 0x18, 0x18}; - static const u8 delta_c[16] = /* delta for contrast */ - {0x2c, 0x1a, 0x12, 0x0c, 0x0a, 0x06, 0x06, 0x06, - 0x04, 0x06, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02}; - static const u8 gamma_tb[6][16] = { - {0x00, 0x00, 0x03, 0x0d, 0x1b, 0x2e, 0x45, 0x5f, - 0x79, 0x93, 0xab, 0xc1, 0xd4, 0xe5, 0xf3, 0xff}, - {0x01, 0x0c, 0x1f, 0x3a, 0x53, 0x6d, 0x85, 0x9c, - 0xb0, 0xc2, 0xd1, 0xde, 0xe9, 0xf2, 0xf9, 0xff}, - {0x04, 0x16, 0x30, 0x4e, 0x68, 0x81, 0x98, 0xac, - 0xbe, 0xcd, 0xda, 0xe4, 0xed, 0xf5, 0xfb, 0xff}, - {0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, - 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff}, - {0x20, 0x4b, 0x6e, 0x8d, 0xa3, 0xb5, 0xc5, 0xd2, - 0xdc, 0xe5, 0xec, 0xf2, 0xf6, 0xfa, 0xfd, 0xff}, - {0x24, 0x44, 0x64, 0x84, 0x9d, 0xb2, 0xc4, 0xd3, - 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff}, - }; - - Tgamma = gamma_tb[sd->ctrls[GAMMA].val - 1]; - - contrast = ((int) sd->ctrls[CONTRAST].val - 128); /* -128 / 127 */ - brightness = ((int) sd->ctrls[BRIGHTNESS].val - 128); /* -128 / 92 */ - adj = 0; - gp1 = gp2 = 0; - for (i = 0; i < 16; i++) { - g = Tgamma[i] + delta_b[i] * brightness / 256 - - delta_c[i] * contrast / 256 - adj / 2; - if (g > 0xff) - g = 0xff; - else if (g < 0) - g = 0; - reg_w(gspca_dev, g, 0x0120 + i); /* gamma */ - if (contrast > 0) - adj--; - else if (contrast < 0) - adj++; - if (i > 1) - gr[i - 1] = (g - gp2) / 2; - else if (i != 0) - gr[0] = gp1 == 0 ? 0 : (g - gp1); - gp2 = gp1; - gp1 = g; - } - gr[15] = (0xff - gp2) / 2; - for (i = 0; i < 16; i++) - reg_w(gspca_dev, gr[i], 0x0130 + i); /* gradient */ -} - -static void getexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9) - | (i2c_read(gspca_dev, 0x26) << 1) - | (i2c_read(gspca_dev, 0x27) >> 7); -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int val; - - val = sd->ctrls[EXPOSURE].val; - i2c_write(gspca_dev, 0x25, val >> 9, 0x00); - i2c_write(gspca_dev, 0x26, val >> 1, 0x00); - i2c_write(gspca_dev, 0x27, val << 7, 0x00); -} - -static void setquality(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 frxt; - - switch (sd->sensor) { - case SENSOR_ADCM2700: - case SENSOR_GC0305: - case SENSOR_HV7131B: - case SENSOR_HV7131R: - case SENSOR_OV7620: - case SENSOR_PAS202B: - case SENSOR_PO2030: - return; - } -/*fixme: is it really 0008 0007 0018 for all other sensors? */ - reg_w(gspca_dev, QUANT_VAL, 0x0008); - frxt = 0x30; - reg_w(gspca_dev, frxt, 0x0007); -#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2 - frxt = 0xff; -#elif QUANT_VAL == 3 - frxt = 0xf0; -#elif QUANT_VAL == 4 - frxt = 0xe0; -#else - frxt = 0x20; -#endif - reg_w(gspca_dev, frxt, 0x0018); -} - -/* Matches the sensor's internal frame rate to the lighting frequency. - * Valid frequencies are: - * 50Hz, for European and Asian lighting (default) - * 60Hz, for American lighting - * 0 = No Fliker (for outdoore usage) - */ -static void setlightfreq(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, mode; - const struct usb_action *zc3_freq; - static const struct usb_action *freq_tb[SENSOR_MAX][6] = { - [SENSOR_ADCM2700] = - {adcm2700_NoFliker, adcm2700_NoFliker, - adcm2700_50HZ, adcm2700_50HZ, - adcm2700_60HZ, adcm2700_60HZ}, - [SENSOR_CS2102] = - {cs2102_NoFliker, cs2102_NoFlikerScale, - cs2102_50HZ, cs2102_50HZScale, - cs2102_60HZ, cs2102_60HZScale}, - [SENSOR_CS2102K] = - {cs2102_NoFliker, cs2102_NoFlikerScale, - NULL, NULL, /* currently disabled */ - NULL, NULL}, - [SENSOR_GC0303] = - {gc0303_NoFliker, gc0303_NoFlikerScale, - gc0303_50HZ, gc0303_50HZScale, - gc0303_60HZ, gc0303_60HZScale}, - [SENSOR_GC0305] = - {gc0305_NoFliker, gc0305_NoFliker, - gc0305_50HZ, gc0305_50HZ, - gc0305_60HZ, gc0305_60HZ}, - [SENSOR_HDCS2020] = - {hdcs2020_NoFliker, hdcs2020_NoFliker, - hdcs2020_50HZ, hdcs2020_50HZ, - hdcs2020_60HZ, hdcs2020_60HZ}, - [SENSOR_HV7131B] = - {hv7131b_NoFliker, hv7131b_NoFlikerScale, - hv7131b_50HZ, hv7131b_50HZScale, - hv7131b_60HZ, hv7131b_60HZScale}, - [SENSOR_HV7131R] = - {hv7131r_NoFliker, hv7131r_NoFlikerScale, - hv7131r_50HZ, hv7131r_50HZScale, - hv7131r_60HZ, hv7131r_60HZScale}, - [SENSOR_ICM105A] = - {icm105a_NoFliker, icm105a_NoFlikerScale, - icm105a_50HZ, icm105a_50HZScale, - icm105a_60HZ, icm105a_60HZScale}, - [SENSOR_MC501CB] = - {mc501cb_NoFliker, mc501cb_NoFlikerScale, - mc501cb_50HZ, mc501cb_50HZScale, - mc501cb_60HZ, mc501cb_60HZScale}, - [SENSOR_MT9V111_1] = - {mt9v111_1_AENoFliker, mt9v111_1_AENoFlikerScale, - mt9v111_1_AE50HZ, mt9v111_1_AE50HZScale, - mt9v111_1_AE60HZ, mt9v111_1_AE60HZScale}, - [SENSOR_MT9V111_3] = - {mt9v111_3_AENoFliker, mt9v111_3_AENoFlikerScale, - mt9v111_3_AE50HZ, mt9v111_3_AE50HZScale, - mt9v111_3_AE60HZ, mt9v111_3_AE60HZScale}, - [SENSOR_OV7620] = - {ov7620_NoFliker, ov7620_NoFliker, - ov7620_50HZ, ov7620_50HZ, - ov7620_60HZ, ov7620_60HZ}, - [SENSOR_OV7630C] = - {NULL, NULL, - NULL, NULL, - NULL, NULL}, - [SENSOR_PAS106] = - {pas106b_NoFliker, pas106b_NoFliker, - pas106b_50HZ, pas106b_50HZ, - pas106b_60HZ, pas106b_60HZ}, - [SENSOR_PAS202B] = - {pas202b_NoFliker, pas202b_NoFlikerScale, - pas202b_50HZ, pas202b_50HZScale, - pas202b_60HZ, pas202b_60HZScale}, - [SENSOR_PB0330] = - {pb0330_NoFliker, pb0330_NoFlikerScale, - pb0330_50HZ, pb0330_50HZScale, - pb0330_60HZ, pb0330_60HZScale}, - [SENSOR_PO2030] = - {po2030_NoFliker, po2030_NoFliker, - po2030_50HZ, po2030_50HZ, - po2030_60HZ, po2030_60HZ}, - [SENSOR_TAS5130C] = - {tas5130c_NoFliker, tas5130c_NoFlikerScale, - tas5130c_50HZ, tas5130c_50HZScale, - tas5130c_60HZ, tas5130c_60HZScale}, - }; - - i = sd->ctrls[LIGHTFREQ].val * 2; - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - if (mode) - i++; /* 320x240 */ - zc3_freq = freq_tb[sd->sensor][i]; - if (zc3_freq == NULL) - return; - usb_exchange(gspca_dev, zc3_freq); - switch (sd->sensor) { - case SENSOR_GC0305: - if (mode /* if 320x240 */ - && sd->ctrls[LIGHTFREQ].val == 1) /* and 50Hz */ - reg_w(gspca_dev, 0x85, 0x018d); - /* win: 0x80, 0x018d */ - break; - case SENSOR_OV7620: - if (!mode) { /* if 640x480 */ - if (sd->ctrls[LIGHTFREQ].val != 0) /* and filter */ - reg_w(gspca_dev, 0x40, 0x0002); - else - reg_w(gspca_dev, 0x44, 0x0002); - } - break; - case SENSOR_PAS202B: - reg_w(gspca_dev, 0x00, 0x01a7); - break; - } -} - -static void setautogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 autoval; - - if (sd->ctrls[AUTOGAIN].val) - autoval = 0x42; - else - autoval = 0x02; - reg_w(gspca_dev, autoval, 0x0180); -} - -static void send_unknown(struct gspca_dev *gspca_dev, int sensor) -{ - reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */ - switch (sensor) { - case SENSOR_PAS106: - reg_w(gspca_dev, 0x03, 0x003a); - reg_w(gspca_dev, 0x0c, 0x003b); - reg_w(gspca_dev, 0x08, 0x0038); - break; - case SENSOR_ADCM2700: - case SENSOR_GC0305: - case SENSOR_OV7620: - case SENSOR_MT9V111_1: - case SENSOR_MT9V111_3: - case SENSOR_PB0330: - case SENSOR_PO2030: - reg_w(gspca_dev, 0x0d, 0x003a); - reg_w(gspca_dev, 0x02, 0x003b); - reg_w(gspca_dev, 0x00, 0x0038); - break; - case SENSOR_HV7131R: - case SENSOR_PAS202B: - reg_w(gspca_dev, 0x03, 0x003b); - reg_w(gspca_dev, 0x0c, 0x003a); - reg_w(gspca_dev, 0x0b, 0x0039); - if (sensor == SENSOR_PAS202B) - reg_w(gspca_dev, 0x0b, 0x0038); - break; - } -} - -/* start probe 2 wires */ -static void start_2wr_probe(struct gspca_dev *gspca_dev, int sensor) -{ - reg_w(gspca_dev, 0x01, 0x0000); - reg_w(gspca_dev, sensor, 0x0010); - reg_w(gspca_dev, 0x01, 0x0001); - reg_w(gspca_dev, 0x03, 0x0012); - reg_w(gspca_dev, 0x01, 0x0012); -/* msleep(2); */ -} - -static int sif_probe(struct gspca_dev *gspca_dev) -{ - u16 checkword; - - start_2wr_probe(gspca_dev, 0x0f); /* PAS106 */ - reg_w(gspca_dev, 0x08, 0x008d); - msleep(150); - checkword = ((i2c_read(gspca_dev, 0x00) & 0x0f) << 4) - | ((i2c_read(gspca_dev, 0x01) & 0xf0) >> 4); - PDEBUG(D_PROBE, "probe sif 0x%04x", checkword); - if (checkword == 0x0007) { - send_unknown(gspca_dev, SENSOR_PAS106); - return 0x0f; /* PAS106 */ - } - return -1; -} - -static int vga_2wr_probe(struct gspca_dev *gspca_dev) -{ - u16 retword; - - start_2wr_probe(gspca_dev, 0x00); /* HV7131B */ - i2c_write(gspca_dev, 0x01, 0xaa, 0x00); - retword = i2c_read(gspca_dev, 0x01); - if (retword != 0) - return 0x00; /* HV7131B */ - - start_2wr_probe(gspca_dev, 0x04); /* CS2102 */ - i2c_write(gspca_dev, 0x01, 0xaa, 0x00); - retword = i2c_read(gspca_dev, 0x01); - if (retword != 0) - return 0x04; /* CS2102 */ - - start_2wr_probe(gspca_dev, 0x06); /* OmniVision */ - reg_w(gspca_dev, 0x08, 0x008d); - i2c_write(gspca_dev, 0x11, 0xaa, 0x00); - retword = i2c_read(gspca_dev, 0x11); - if (retword != 0) { - /* (should have returned 0xaa) --> Omnivision? */ - /* reg_r 0x10 -> 0x06 --> */ - goto ov_check; - } - - start_2wr_probe(gspca_dev, 0x08); /* HDCS2020 */ - i2c_write(gspca_dev, 0x1c, 0x00, 0x00); - i2c_write(gspca_dev, 0x15, 0xaa, 0x00); - retword = i2c_read(gspca_dev, 0x15); - if (retword != 0) - return 0x08; /* HDCS2020 */ - - start_2wr_probe(gspca_dev, 0x0a); /* PB0330 */ - i2c_write(gspca_dev, 0x07, 0xaa, 0xaa); - retword = i2c_read(gspca_dev, 0x07); - if (retword != 0) - return 0x0a; /* PB0330 */ - retword = i2c_read(gspca_dev, 0x03); - if (retword != 0) - return 0x0a; /* PB0330 ?? */ - retword = i2c_read(gspca_dev, 0x04); - if (retword != 0) - return 0x0a; /* PB0330 ?? */ - - start_2wr_probe(gspca_dev, 0x0c); /* ICM105A */ - i2c_write(gspca_dev, 0x01, 0x11, 0x00); - retword = i2c_read(gspca_dev, 0x01); - if (retword != 0) - return 0x0c; /* ICM105A */ - - start_2wr_probe(gspca_dev, 0x0e); /* PAS202BCB */ - reg_w(gspca_dev, 0x08, 0x008d); - i2c_write(gspca_dev, 0x03, 0xaa, 0x00); - msleep(50); - retword = i2c_read(gspca_dev, 0x03); - if (retword != 0) { - send_unknown(gspca_dev, SENSOR_PAS202B); - return 0x0e; /* PAS202BCB */ - } - - start_2wr_probe(gspca_dev, 0x02); /* TAS5130C */ - i2c_write(gspca_dev, 0x01, 0xaa, 0x00); - retword = i2c_read(gspca_dev, 0x01); - if (retword != 0) - return 0x02; /* TAS5130C */ -ov_check: - reg_r(gspca_dev, 0x0010); /* ?? */ - reg_r(gspca_dev, 0x0010); - - reg_w(gspca_dev, 0x01, 0x0000); - reg_w(gspca_dev, 0x01, 0x0001); - reg_w(gspca_dev, 0x06, 0x0010); /* OmniVision */ - reg_w(gspca_dev, 0xa1, 0x008b); - reg_w(gspca_dev, 0x08, 0x008d); - msleep(500); - reg_w(gspca_dev, 0x01, 0x0012); - i2c_write(gspca_dev, 0x12, 0x80, 0x00); /* sensor reset */ - retword = i2c_read(gspca_dev, 0x0a) << 8; - retword |= i2c_read(gspca_dev, 0x0b); - PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", retword); - switch (retword) { - case 0x7631: /* OV7630C */ - reg_w(gspca_dev, 0x06, 0x0010); - break; - case 0x7620: /* OV7620 */ - case 0x7648: /* OV7648 */ - break; - default: - return -1; /* not OmniVision */ - } - return retword; -} - -struct sensor_by_chipset_revision { - u16 revision; - u8 internal_sensor_id; -}; -static const struct sensor_by_chipset_revision chipset_revision_sensor[] = { - {0xc000, 0x12}, /* TAS5130C */ - {0xc001, 0x13}, /* MT9V111 */ - {0xe001, 0x13}, - {0x8001, 0x13}, - {0x8000, 0x14}, /* CS2102K */ - {0x8400, 0x15}, /* MT9V111 */ - {0xe400, 0x15}, -}; - -static int vga_3wr_probe(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - u8 retbyte; - u16 retword; - -/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/ - reg_w(gspca_dev, 0x02, 0x0010); - reg_r(gspca_dev, 0x0010); - reg_w(gspca_dev, 0x01, 0x0000); - reg_w(gspca_dev, 0x00, 0x0010); - reg_w(gspca_dev, 0x01, 0x0001); - reg_w(gspca_dev, 0x91, 0x008b); - reg_w(gspca_dev, 0x03, 0x0012); - reg_w(gspca_dev, 0x01, 0x0012); - reg_w(gspca_dev, 0x05, 0x0012); - retword = i2c_read(gspca_dev, 0x14); - if (retword != 0) - return 0x11; /* HV7131R */ - retword = i2c_read(gspca_dev, 0x15); - if (retword != 0) - return 0x11; /* HV7131R */ - retword = i2c_read(gspca_dev, 0x16); - if (retword != 0) - return 0x11; /* HV7131R */ - - reg_w(gspca_dev, 0x02, 0x0010); - retword = reg_r(gspca_dev, 0x000b) << 8; - retword |= reg_r(gspca_dev, 0x000a); - PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", retword); - reg_r(gspca_dev, 0x0010); - if ((retword & 0xff00) == 0x6400) - return 0x02; /* TAS5130C */ - for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) { - if (chipset_revision_sensor[i].revision == retword) { - sd->chip_revision = retword; - send_unknown(gspca_dev, SENSOR_PB0330); - return chipset_revision_sensor[i].internal_sensor_id; - } - } - - reg_w(gspca_dev, 0x01, 0x0000); /* check PB0330 */ - reg_w(gspca_dev, 0x01, 0x0001); - reg_w(gspca_dev, 0xdd, 0x008b); - reg_w(gspca_dev, 0x0a, 0x0010); - reg_w(gspca_dev, 0x03, 0x0012); - reg_w(gspca_dev, 0x01, 0x0012); - retword = i2c_read(gspca_dev, 0x00); - if (retword != 0) { - PDEBUG(D_PROBE, "probe 3wr vga type 0a"); - return 0x0a; /* PB0330 */ - } - - /* probe gc0303 / gc0305 */ - reg_w(gspca_dev, 0x01, 0x0000); - reg_w(gspca_dev, 0x01, 0x0001); - reg_w(gspca_dev, 0x98, 0x008b); - reg_w(gspca_dev, 0x01, 0x0010); - reg_w(gspca_dev, 0x03, 0x0012); - msleep(2); - reg_w(gspca_dev, 0x01, 0x0012); - retword = i2c_read(gspca_dev, 0x00); - if (retword != 0) { - PDEBUG(D_PROBE, "probe 3wr vga type %02x", retword); - if (retword == 0x0011) /* gc0303 */ - return 0x0303; - if (retword == 0x0029) /* gc0305 */ - send_unknown(gspca_dev, SENSOR_GC0305); - return retword; - } - - reg_w(gspca_dev, 0x01, 0x0000); /* check OmniVision */ - reg_w(gspca_dev, 0x01, 0x0001); - reg_w(gspca_dev, 0xa1, 0x008b); - reg_w(gspca_dev, 0x08, 0x008d); - reg_w(gspca_dev, 0x06, 0x0010); - reg_w(gspca_dev, 0x01, 0x0012); - reg_w(gspca_dev, 0x05, 0x0012); - if (i2c_read(gspca_dev, 0x1c) == 0x007f /* OV7610 - manufacturer ID */ - && i2c_read(gspca_dev, 0x1d) == 0x00a2) { - send_unknown(gspca_dev, SENSOR_OV7620); - return 0x06; /* OmniVision confirm ? */ - } - - reg_w(gspca_dev, 0x01, 0x0000); - reg_w(gspca_dev, 0x00, 0x0002); - reg_w(gspca_dev, 0x01, 0x0010); - reg_w(gspca_dev, 0x01, 0x0001); - reg_w(gspca_dev, 0xee, 0x008b); - reg_w(gspca_dev, 0x03, 0x0012); - reg_w(gspca_dev, 0x01, 0x0012); - reg_w(gspca_dev, 0x05, 0x0012); - retword = i2c_read(gspca_dev, 0x00) << 8; /* ID 0 */ - retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */ - PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword); - if (retword == 0x2030) { - retbyte = i2c_read(gspca_dev, 0x02); /* revision number */ - PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte); - send_unknown(gspca_dev, SENSOR_PO2030); - return retword; - } - - reg_w(gspca_dev, 0x01, 0x0000); - reg_w(gspca_dev, 0x0a, 0x0010); - reg_w(gspca_dev, 0xd3, 0x008b); - reg_w(gspca_dev, 0x01, 0x0001); - reg_w(gspca_dev, 0x03, 0x0012); - reg_w(gspca_dev, 0x01, 0x0012); - reg_w(gspca_dev, 0x05, 0x0012); - reg_w(gspca_dev, 0xd3, 0x008b); - retword = i2c_read(gspca_dev, 0x01); - if (retword != 0) { - PDEBUG(D_PROBE, "probe 3wr vga type 0a ? ret: %04x", retword); - return 0x16; /* adcm2700 (6100/6200) */ - } - return -1; -} - -static int zcxx_probeSensor(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int sensor; - - switch (sd->sensor) { - case SENSOR_MC501CB: - return -1; /* don't probe */ - case SENSOR_GC0303: - /* may probe but with no write in reg 0x0010 */ - return -1; /* don't probe */ - case SENSOR_PAS106: - sensor = sif_probe(gspca_dev); - if (sensor >= 0) - return sensor; - break; - } - sensor = vga_2wr_probe(gspca_dev); - if (sensor >= 0) - return sensor; - return vga_3wr_probe(gspca_dev); -} - -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (id->idProduct == 0x301b) - sd->bridge = BRIDGE_ZC301; - else - sd->bridge = BRIDGE_ZC303; - - /* define some sensors from the vendor/product */ - sd->sensor = id->driver_info; - - gspca_dev->cam.ctrls = sd->ctrls; - sd->quality = QUALITY_DEF; - - /* if USB 1.1, let some bandwidth for the audio device */ - if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) - gspca_dev->nbalt--; - - return 0; -} - -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - int sensor; - static const u8 gamma[SENSOR_MAX] = { - [SENSOR_ADCM2700] = 4, - [SENSOR_CS2102] = 4, - [SENSOR_CS2102K] = 5, - [SENSOR_GC0303] = 3, - [SENSOR_GC0305] = 4, - [SENSOR_HDCS2020] = 4, - [SENSOR_HV7131B] = 4, - [SENSOR_HV7131R] = 4, - [SENSOR_ICM105A] = 4, - [SENSOR_MC501CB] = 4, - [SENSOR_MT9V111_1] = 4, - [SENSOR_MT9V111_3] = 4, - [SENSOR_OV7620] = 3, - [SENSOR_OV7630C] = 4, - [SENSOR_PAS106] = 4, - [SENSOR_PAS202B] = 4, - [SENSOR_PB0330] = 4, - [SENSOR_PO2030] = 4, - [SENSOR_TAS5130C] = 3, - }; - static const u8 mode_tb[SENSOR_MAX] = { - [SENSOR_ADCM2700] = 2, - [SENSOR_CS2102] = 1, - [SENSOR_CS2102K] = 1, - [SENSOR_GC0303] = 1, - [SENSOR_GC0305] = 1, - [SENSOR_HDCS2020] = 1, - [SENSOR_HV7131B] = 1, - [SENSOR_HV7131R] = 1, - [SENSOR_ICM105A] = 1, - [SENSOR_MC501CB] = 2, - [SENSOR_MT9V111_1] = 1, - [SENSOR_MT9V111_3] = 1, - [SENSOR_OV7620] = 2, - [SENSOR_OV7630C] = 1, - [SENSOR_PAS106] = 0, - [SENSOR_PAS202B] = 1, - [SENSOR_PB0330] = 1, - [SENSOR_PO2030] = 1, - [SENSOR_TAS5130C] = 1, - }; - - sensor = zcxx_probeSensor(gspca_dev); - if (sensor >= 0) - PDEBUG(D_PROBE, "probe sensor -> %04x", sensor); - if ((unsigned) force_sensor < SENSOR_MAX) { - sd->sensor = force_sensor; - PDEBUG(D_PROBE, "sensor forced to %d", force_sensor); - } else { - switch (sensor) { - case -1: - switch (sd->sensor) { - case SENSOR_MC501CB: - PDEBUG(D_PROBE, "Sensor MC501CB"); - break; - case SENSOR_GC0303: - PDEBUG(D_PROBE, "Sensor GC0303"); - break; - default: - warn("Unknown sensor - set to TAS5130C"); - sd->sensor = SENSOR_TAS5130C; - } - break; - case 0: - /* check the sensor type */ - sensor = i2c_read(gspca_dev, 0x00); - PDEBUG(D_PROBE, "Sensor hv7131 type %d", sensor); - switch (sensor) { - case 0: /* hv7131b */ - case 1: /* hv7131e */ - PDEBUG(D_PROBE, "Find Sensor HV7131B"); - sd->sensor = SENSOR_HV7131B; - break; - default: -/* case 2: * hv7131r */ - PDEBUG(D_PROBE, "Find Sensor HV7131R"); - sd->sensor = SENSOR_HV7131R; - break; - } - break; - case 0x02: - PDEBUG(D_PROBE, "Sensor TAS5130C"); - sd->sensor = SENSOR_TAS5130C; - break; - case 0x04: - PDEBUG(D_PROBE, "Find Sensor CS2102"); - sd->sensor = SENSOR_CS2102; - break; - case 0x08: - PDEBUG(D_PROBE, "Find Sensor HDCS2020"); - sd->sensor = SENSOR_HDCS2020; - break; - case 0x0a: - PDEBUG(D_PROBE, - "Find Sensor PB0330. Chip revision %x", - sd->chip_revision); - sd->sensor = SENSOR_PB0330; - break; - case 0x0c: - PDEBUG(D_PROBE, "Find Sensor ICM105A"); - sd->sensor = SENSOR_ICM105A; - break; - case 0x0e: - PDEBUG(D_PROBE, "Find Sensor PAS202B"); - sd->sensor = SENSOR_PAS202B; -/* sd->sharpness = 1; */ - break; - case 0x0f: - PDEBUG(D_PROBE, "Find Sensor PAS106"); - sd->sensor = SENSOR_PAS106; - break; - case 0x10: - case 0x12: - PDEBUG(D_PROBE, "Find Sensor TAS5130C"); - sd->sensor = SENSOR_TAS5130C; - break; - case 0x11: - PDEBUG(D_PROBE, "Find Sensor HV7131R"); - sd->sensor = SENSOR_HV7131R; - break; - case 0x13: - case 0x15: - PDEBUG(D_PROBE, - "Sensor MT9V111. Chip revision %04x", - sd->chip_revision); - sd->sensor = sd->bridge == BRIDGE_ZC301 - ? SENSOR_MT9V111_1 - : SENSOR_MT9V111_3; - break; - case 0x14: - PDEBUG(D_PROBE, - "Find Sensor CS2102K?. Chip revision %x", - sd->chip_revision); - sd->sensor = SENSOR_CS2102K; - break; - case 0x16: - PDEBUG(D_PROBE, "Find Sensor ADCM2700"); - sd->sensor = SENSOR_ADCM2700; - break; - case 0x29: - PDEBUG(D_PROBE, "Find Sensor GC0305"); - sd->sensor = SENSOR_GC0305; - break; - case 0x0303: - PDEBUG(D_PROBE, "Sensor GC0303"); - sd->sensor = SENSOR_GC0303; - break; - case 0x2030: - PDEBUG(D_PROBE, "Find Sensor PO2030"); - sd->sensor = SENSOR_PO2030; - sd->ctrls[SHARPNESS].def = 0; /* from win traces */ - break; - case 0x7620: - PDEBUG(D_PROBE, "Find Sensor OV7620"); - sd->sensor = SENSOR_OV7620; - break; - case 0x7631: - PDEBUG(D_PROBE, "Find Sensor OV7630C"); - sd->sensor = SENSOR_OV7630C; - break; - case 0x7648: - PDEBUG(D_PROBE, "Find Sensor OV7648"); - sd->sensor = SENSOR_OV7620; /* same sensor (?) */ - break; - default: - err("Unknown sensor %04x", sensor); - return -EINVAL; - } - } - if (sensor < 0x20) { - if (sensor == -1 || sensor == 0x10 || sensor == 0x12) - reg_w(gspca_dev, 0x02, 0x0010); - reg_r(gspca_dev, 0x0010); - } - - cam = &gspca_dev->cam; - switch (mode_tb[sd->sensor]) { - case 0: - cam->cam_mode = sif_mode; - cam->nmodes = ARRAY_SIZE(sif_mode); - break; - case 1: - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - break; - default: -/* case 2: */ - cam->cam_mode = broken_vga_mode; - cam->nmodes = ARRAY_SIZE(broken_vga_mode); - break; - } - - sd->ctrls[GAMMA].def = gamma[sd->sensor]; - - switch (sd->sensor) { - case SENSOR_HV7131R: - break; - case SENSOR_OV7630C: - gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE); - break; - default: - gspca_dev->ctrl_dis = (1 << EXPOSURE); - break; - } -#if AUTOGAIN_DEF - if (sd->ctrls[AUTOGAIN].val) - gspca_dev->ctrl_inac = (1 << EXPOSURE); -#endif - - /* switch off the led */ - reg_w(gspca_dev, 0x01, 0x0000); - return gspca_dev->usb_err; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int mode; - static const struct usb_action *init_tb[SENSOR_MAX][2] = { - [SENSOR_ADCM2700] = - {adcm2700_Initial, adcm2700_InitialScale}, - [SENSOR_CS2102] = - {cs2102_Initial, cs2102_InitialScale}, - [SENSOR_CS2102K] = - {cs2102K_Initial, cs2102K_InitialScale}, - [SENSOR_GC0303] = - {gc0303_Initial, gc0303_InitialScale}, - [SENSOR_GC0305] = - {gc0305_Initial, gc0305_InitialScale}, - [SENSOR_HDCS2020] = - {hdcs2020_Initial, hdcs2020_InitialScale}, - [SENSOR_HV7131B] = - {hv7131b_Initial, hv7131b_InitialScale}, - [SENSOR_HV7131R] = - {hv7131r_Initial, hv7131r_InitialScale}, - [SENSOR_ICM105A] = - {icm105a_Initial, icm105a_InitialScale}, - [SENSOR_MC501CB] = - {mc501cb_Initial, mc501cb_InitialScale}, - [SENSOR_MT9V111_1] = - {mt9v111_1_Initial, mt9v111_1_InitialScale}, - [SENSOR_MT9V111_3] = - {mt9v111_3_Initial, mt9v111_3_InitialScale}, - [SENSOR_OV7620] = - {ov7620_Initial, ov7620_InitialScale}, - [SENSOR_OV7630C] = - {ov7630c_Initial, ov7630c_InitialScale}, - [SENSOR_PAS106] = - {pas106b_Initial, pas106b_InitialScale}, - [SENSOR_PAS202B] = - {pas202b_Initial, pas202b_InitialScale}, - [SENSOR_PB0330] = - {pb0330_Initial, pb0330_InitialScale}, - [SENSOR_PO2030] = - {po2030_Initial, po2030_InitialScale}, - [SENSOR_TAS5130C] = - {tas5130c_Initial, tas5130c_InitialScale}, - }; - - /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x21); /* JPEG 422 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - switch (sd->sensor) { - case SENSOR_HV7131R: - zcxx_probeSensor(gspca_dev); - break; - case SENSOR_PAS106: - usb_exchange(gspca_dev, pas106b_Initial_com); - break; - } - usb_exchange(gspca_dev, init_tb[sd->sensor][mode]); - - switch (sd->sensor) { - case SENSOR_ADCM2700: - case SENSOR_GC0305: - case SENSOR_OV7620: - case SENSOR_PO2030: - case SENSOR_TAS5130C: - case SENSOR_GC0303: -/* msleep(100); * ?? */ - reg_r(gspca_dev, 0x0002); /* --> 0x40 */ - reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */ - reg_w(gspca_dev, 0x15, 0x01ae); - if (sd->sensor == SENSOR_TAS5130C) - break; - reg_w(gspca_dev, 0x0d, 0x003a); - reg_w(gspca_dev, 0x02, 0x003b); - reg_w(gspca_dev, 0x00, 0x0038); - break; - case SENSOR_HV7131R: - case SENSOR_PAS202B: - reg_w(gspca_dev, 0x03, 0x003b); - reg_w(gspca_dev, 0x0c, 0x003a); - reg_w(gspca_dev, 0x0b, 0x0039); - if (sd->sensor == SENSOR_HV7131R) - reg_w(gspca_dev, 0x50, ZC3XX_R11D_GLOBALGAIN); - break; - } - - setmatrix(gspca_dev); - switch (sd->sensor) { - case SENSOR_ADCM2700: - case SENSOR_OV7620: - reg_r(gspca_dev, 0x0008); - reg_w(gspca_dev, 0x00, 0x0008); - break; - case SENSOR_PAS202B: - case SENSOR_GC0305: - case SENSOR_HV7131R: - case SENSOR_TAS5130C: - reg_r(gspca_dev, 0x0008); - /* fall thru */ - case SENSOR_PO2030: - reg_w(gspca_dev, 0x03, 0x0008); - break; - } - setsharpness(gspca_dev); - - /* set the gamma tables when not set */ - switch (sd->sensor) { - case SENSOR_CS2102K: /* gamma set in xxx_Initial */ - case SENSOR_HDCS2020: - case SENSOR_OV7630C: - break; - default: - setcontrast(gspca_dev); - break; - } - setmatrix(gspca_dev); /* one more time? */ - switch (sd->sensor) { - case SENSOR_OV7620: - case SENSOR_PAS202B: - reg_r(gspca_dev, 0x0180); /* from win */ - reg_w(gspca_dev, 0x00, 0x0180); - break; - default: - setquality(gspca_dev); - break; - } - setlightfreq(gspca_dev); - - switch (sd->sensor) { - case SENSOR_ADCM2700: - reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */ - reg_w(gspca_dev, 0x15, 0x01ae); - reg_w(gspca_dev, 0x02, 0x0180); - /* ms-win + */ - reg_w(gspca_dev, 0x40, 0x0117); - break; - case SENSOR_HV7131R: - if (!sd->ctrls[AUTOGAIN].val) - setexposure(gspca_dev); - reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN); - break; - case SENSOR_GC0305: - case SENSOR_TAS5130C: - reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */ - reg_w(gspca_dev, 0x15, 0x01ae); - /* fall thru */ - case SENSOR_PAS202B: - case SENSOR_PO2030: -/* reg_w(gspca_dev, 0x40, ZC3XX_R117_GGAIN); in win traces */ - reg_r(gspca_dev, 0x0180); - break; - case SENSOR_OV7620: - reg_w(gspca_dev, 0x09, 0x01ad); - reg_w(gspca_dev, 0x15, 0x01ae); - i2c_read(gspca_dev, 0x13); /*fixme: returns 0xa3 */ - i2c_write(gspca_dev, 0x13, 0xa3, 0x00); - /*fixme: returned value to send? */ - reg_w(gspca_dev, 0x40, 0x0117); - reg_r(gspca_dev, 0x0180); - break; - } - - setautogain(gspca_dev); - switch (sd->sensor) { - case SENSOR_PO2030: - msleep(50); - reg_w(gspca_dev, 0x00, 0x0007); /* (from win traces) */ - reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING); - break; - } - return gspca_dev->usb_err; -} - -/* called on streamoff with alt 0 and on disconnect */ -static void sd_stop0(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (!gspca_dev->present) - return; - send_unknown(gspca_dev, sd->sensor); -} - -static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, - int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* check the JPEG end of frame */ - if (len >= 3 - && data[len - 3] == 0xff && data[len - 2] == 0xd9) { -/*fixme: what does the last byte mean?*/ - gspca_frame_add(gspca_dev, LAST_PACKET, - data, len - 1); - return; - } - - /* check the JPEG start of a frame */ - if (data[0] == 0xff && data[1] == 0xd8) { - /* put the JPEG header in the new frame */ - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - - /* remove the webcam's header: - * ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp - * - 'ss ss' is the frame sequence number (BE) - * - 'ww ww' and 'hh hh' are the window dimensions (BE) - * - 'pp pp' is the packet sequence number (BE) - */ - data += 18; - len -= 18; - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AUTOGAIN].val = val; - if (val) { - gspca_dev->ctrl_inac |= (1 << EXPOSURE); - } else { - gspca_dev->ctrl_inac &= ~(1 << EXPOSURE); - if (gspca_dev->streaming) - getexposure(gspca_dev); - } - if (gspca_dev->streaming) - setautogain(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - } - return -EINVAL; -} - -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return gspca_dev->usb_err; -} - -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; - return 0; -} - -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) -static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* interrupt packet data */ - int len) /* interrput packet length */ -{ - if (len == 8 && data[4] == 1) { - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); - input_sync(gspca_dev->input_dev); - input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); - input_sync(gspca_dev->input_dev); - } - - return 0; -} -#endif - -static const struct sd_desc sd_desc = { - .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, - .init = sd_init, - .start = sd_start, - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, -#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -#endif -}; - -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x041e)}, - {USB_DEVICE(0x041e, 0x4017)}, - {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106}, - {USB_DEVICE(0x041e, 0x401e)}, - {USB_DEVICE(0x041e, 0x401f)}, - {USB_DEVICE(0x041e, 0x4022)}, - {USB_DEVICE(0x041e, 0x4029)}, - {USB_DEVICE(0x041e, 0x4034), .driver_info = SENSOR_PAS106}, - {USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106}, - {USB_DEVICE(0x041e, 0x4036)}, - {USB_DEVICE(0x041e, 0x403a)}, - {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_GC0303}, - {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_GC0303}, - {USB_DEVICE(0x0458, 0x7007)}, - {USB_DEVICE(0x0458, 0x700c)}, - {USB_DEVICE(0x0458, 0x700f)}, - {USB_DEVICE(0x0461, 0x0a00)}, - {USB_DEVICE(0x046d, 0x089d), .driver_info = SENSOR_MC501CB}, - {USB_DEVICE(0x046d, 0x08a0)}, - {USB_DEVICE(0x046d, 0x08a1)}, - {USB_DEVICE(0x046d, 0x08a2)}, - {USB_DEVICE(0x046d, 0x08a3)}, - {USB_DEVICE(0x046d, 0x08a6)}, - {USB_DEVICE(0x046d, 0x08a7)}, - {USB_DEVICE(0x046d, 0x08a9)}, - {USB_DEVICE(0x046d, 0x08aa)}, - {USB_DEVICE(0x046d, 0x08ac)}, - {USB_DEVICE(0x046d, 0x08ad)}, - {USB_DEVICE(0x046d, 0x08ae)}, - {USB_DEVICE(0x046d, 0x08af)}, - {USB_DEVICE(0x046d, 0x08b9)}, - {USB_DEVICE(0x046d, 0x08d7)}, - {USB_DEVICE(0x046d, 0x08d8)}, - {USB_DEVICE(0x046d, 0x08d9)}, - {USB_DEVICE(0x046d, 0x08da)}, - {USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB}, - {USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106}, - {USB_DEVICE(0x0471, 0x0326), .driver_info = SENSOR_PAS106}, - {USB_DEVICE(0x0471, 0x032d), .driver_info = SENSOR_PAS106}, - {USB_DEVICE(0x0471, 0x032e), .driver_info = SENSOR_PAS106}, - {USB_DEVICE(0x055f, 0xc005)}, - {USB_DEVICE(0x055f, 0xd003)}, - {USB_DEVICE(0x055f, 0xd004)}, - {USB_DEVICE(0x0698, 0x2003)}, - {USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106}, - {USB_DEVICE(0x0ac8, 0x0302), .driver_info = SENSOR_PAS106}, - {USB_DEVICE(0x0ac8, 0x301b)}, - {USB_DEVICE(0x0ac8, 0x303b)}, - {USB_DEVICE(0x0ac8, 0x305b)}, - {USB_DEVICE(0x0ac8, 0x307b)}, - {USB_DEVICE(0x10fd, 0x0128)}, - {USB_DEVICE(0x10fd, 0x804d)}, - {USB_DEVICE(0x10fd, 0x8050)}, - {} /* end of entry */ -}; -MODULE_DEVICE_TABLE(usb, device_table); - -/* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); -} - -/* USB driver */ -static struct usb_driver sd_driver = { - .name = MODULE_NAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -#ifdef CONFIG_PM - .suspend = gspca_suspend, - .resume = gspca_resume, -#endif -}; - -static int __init sd_mod_init(void) -{ - return usb_register(&sd_driver); -} - -static void __exit sd_mod_exit(void) -{ - usb_deregister(&sd_driver); -} - -module_init(sd_mod_init); -module_exit(sd_mod_exit); - -module_param(force_sensor, int, 0644); -MODULE_PARM_DESC(force_sensor, - "Force sensor. Only for experts!!!"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/zc3xx-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/zc3xx-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/zc3xx-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/gspca/zc3xx-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,251 +0,0 @@ -/* - * zc030x registers - * - * Copyright (c) 2008 Mauro Carvalho Chehab - * - * The register aliases used here came from this driver: - * http://zc0302.sourceforge.net/zc0302.php - * - * This code is placed under the terms of the GNU General Public License v2 - */ - -/* Define the register map */ -#define ZC3XX_R000_SYSTEMCONTROL 0x0000 -#define ZC3XX_R001_SYSTEMOPERATING 0x0001 - -/* Picture size */ -#define ZC3XX_R002_CLOCKSELECT 0x0002 -#define ZC3XX_R003_FRAMEWIDTHHIGH 0x0003 -#define ZC3XX_R004_FRAMEWIDTHLOW 0x0004 -#define ZC3XX_R005_FRAMEHEIGHTHIGH 0x0005 -#define ZC3XX_R006_FRAMEHEIGHTLOW 0x0006 - -/* JPEG control */ -#define ZC3XX_R008_CLOCKSETTING 0x0008 - -/* Test mode */ -#define ZC3XX_R00B_TESTMODECONTROL 0x000b - -/* Frame retreiving */ -#define ZC3XX_R00C_LASTACQTIME 0x000c -#define ZC3XX_R00D_MONITORRES 0x000d -#define ZC3XX_R00E_TIMESTAMPHIGH 0x000e -#define ZC3XX_R00F_TIMESTAMPLOW 0x000f -#define ZC3XX_R018_FRAMELOST 0x0018 -#define ZC3XX_R019_AUTOADJUSTFPS 0x0019 -#define ZC3XX_R01A_LASTFRAMESTATE 0x001a -#define ZC3XX_R025_DATACOUNTER 0x0025 - -/* Stream and sensor specific */ -#define ZC3XX_R010_CMOSSENSORSELECT 0x0010 -#define ZC3XX_R011_VIDEOSTATUS 0x0011 -#define ZC3XX_R012_VIDEOCONTROLFUNC 0x0012 - -/* Horizontal and vertical synchros */ -#define ZC3XX_R01D_HSYNC_0 0x001d -#define ZC3XX_R01E_HSYNC_1 0x001e -#define ZC3XX_R01F_HSYNC_2 0x001f -#define ZC3XX_R020_HSYNC_3 0x0020 - -/* Target picture size in byte */ -#define ZC3XX_R022_TARGETPICTSIZE_0 0x0022 -#define ZC3XX_R023_TARGETPICTSIZE_1 0x0023 -#define ZC3XX_R024_TARGETPICTSIZE_2 0x0024 - -/* Audio registers */ -#define ZC3XX_R030_AUDIOADC 0x0030 -#define ZC3XX_R031_AUDIOSTREAMSTATUS 0x0031 -#define ZC3XX_R032_AUDIOSTATUS 0x0032 - -/* Sensor interface */ -#define ZC3XX_R080_HBLANKHIGH 0x0080 -#define ZC3XX_R081_HBLANKLOW 0x0081 -#define ZC3XX_R082_RESETLEVELADDR 0x0082 -#define ZC3XX_R083_RGAINADDR 0x0083 -#define ZC3XX_R084_GGAINADDR 0x0084 -#define ZC3XX_R085_BGAINADDR 0x0085 -#define ZC3XX_R086_EXPTIMEHIGH 0x0086 -#define ZC3XX_R087_EXPTIMEMID 0x0087 -#define ZC3XX_R088_EXPTIMELOW 0x0088 -#define ZC3XX_R089_RESETBLACKHIGH 0x0089 -#define ZC3XX_R08A_RESETWHITEHIGH 0x008a -#define ZC3XX_R08B_I2CDEVICEADDR 0x008b -#define ZC3XX_R08C_I2CIDLEANDNACK 0x008c -#define ZC3XX_R08D_COMPABILITYMODE 0x008d -#define ZC3XX_R08E_COMPABILITYMODE2 0x008e - -/* I2C control */ -#define ZC3XX_R090_I2CCOMMAND 0x0090 -#define ZC3XX_R091_I2CSTATUS 0x0091 -#define ZC3XX_R092_I2CADDRESSSELECT 0x0092 -#define ZC3XX_R093_I2CSETVALUE 0x0093 -#define ZC3XX_R094_I2CWRITEACK 0x0094 -#define ZC3XX_R095_I2CREAD 0x0095 -#define ZC3XX_R096_I2CREADACK 0x0096 - -/* Window inside the sensor array */ -#define ZC3XX_R097_WINYSTARTHIGH 0x0097 -#define ZC3XX_R098_WINYSTARTLOW 0x0098 -#define ZC3XX_R099_WINXSTARTHIGH 0x0099 -#define ZC3XX_R09A_WINXSTARTLOW 0x009a -#define ZC3XX_R09B_WINHEIGHTHIGH 0x009b -#define ZC3XX_R09C_WINHEIGHTLOW 0x009c -#define ZC3XX_R09D_WINWIDTHHIGH 0x009d -#define ZC3XX_R09E_WINWIDTHLOW 0x009e -#define ZC3XX_R119_FIRSTYHIGH 0x0119 -#define ZC3XX_R11A_FIRSTYLOW 0x011a -#define ZC3XX_R11B_FIRSTXHIGH 0x011b -#define ZC3XX_R11C_FIRSTXLOW 0x011c - -/* Max sensor array size */ -#define ZC3XX_R09F_MAXXHIGH 0x009f -#define ZC3XX_R0A0_MAXXLOW 0x00a0 -#define ZC3XX_R0A1_MAXYHIGH 0x00a1 -#define ZC3XX_R0A2_MAXYLOW 0x00a2 -#define ZC3XX_R0A3_EXPOSURETIMEHIGH 0x00a3 -#define ZC3XX_R0A4_EXPOSURETIMELOW 0x00a4 -#define ZC3XX_R0A5_EXPOSUREGAIN 0x00a5 -#define ZC3XX_R0A6_EXPOSUREBLACKLVL 0x00a6 - -/* Other registers */ -#define ZC3XX_R100_OPERATIONMODE 0x0100 -#define ZC3XX_R101_SENSORCORRECTION 0x0101 - -/* Gains */ -#define ZC3XX_R116_RGAIN 0x0116 -#define ZC3XX_R117_GGAIN 0x0117 -#define ZC3XX_R118_BGAIN 0x0118 -#define ZC3XX_R11D_GLOBALGAIN 0x011d -#define ZC3XX_R1A8_DIGITALGAIN 0x01a8 -#define ZC3XX_R1A9_DIGITALLIMITDIFF 0x01a9 -#define ZC3XX_R1AA_DIGITALGAINSTEP 0x01aa - -/* Auto correction */ -#define ZC3XX_R180_AUTOCORRECTENABLE 0x0180 -#define ZC3XX_R181_WINXSTART 0x0181 -#define ZC3XX_R182_WINXWIDTH 0x0182 -#define ZC3XX_R183_WINXCENTER 0x0183 -#define ZC3XX_R184_WINYSTART 0x0184 -#define ZC3XX_R185_WINYWIDTH 0x0185 -#define ZC3XX_R186_WINYCENTER 0x0186 - -/* Gain range */ -#define ZC3XX_R187_MAXGAIN 0x0187 -#define ZC3XX_R188_MINGAIN 0x0188 - -/* Auto exposure and white balance */ -#define ZC3XX_R189_AWBSTATUS 0x0189 -#define ZC3XX_R18A_AWBFREEZE 0x018a -#define ZC3XX_R18B_AESTATUS 0x018b -#define ZC3XX_R18C_AEFREEZE 0x018c -#define ZC3XX_R18F_AEUNFREEZE 0x018f -#define ZC3XX_R190_EXPOSURELIMITHIGH 0x0190 -#define ZC3XX_R191_EXPOSURELIMITMID 0x0191 -#define ZC3XX_R192_EXPOSURELIMITLOW 0x0192 -#define ZC3XX_R195_ANTIFLICKERHIGH 0x0195 -#define ZC3XX_R196_ANTIFLICKERMID 0x0196 -#define ZC3XX_R197_ANTIFLICKERLOW 0x0197 - -/* What is this ? */ -#define ZC3XX_R18D_YTARGET 0x018d -#define ZC3XX_R18E_RESETLVL 0x018e - -/* Color */ -#define ZC3XX_R1A0_REDMEANAFTERAGC 0x01a0 -#define ZC3XX_R1A1_GREENMEANAFTERAGC 0x01a1 -#define ZC3XX_R1A2_BLUEMEANAFTERAGC 0x01a2 -#define ZC3XX_R1A3_REDMEANAFTERAWB 0x01a3 -#define ZC3XX_R1A4_GREENMEANAFTERAWB 0x01a4 -#define ZC3XX_R1A5_BLUEMEANAFTERAWB 0x01a5 -#define ZC3XX_R1A6_YMEANAFTERAE 0x01a6 -#define ZC3XX_R1A7_CALCGLOBALMEAN 0x01a7 - -/* Matrixes */ - -/* Color matrix is like : - R' = R * RGB00 + G * RGB01 + B * RGB02 + RGB03 - G' = R * RGB10 + G * RGB11 + B * RGB22 + RGB13 - B' = R * RGB20 + G * RGB21 + B * RGB12 + RGB23 - */ -#define ZC3XX_R10A_RGB00 0x010a -#define ZC3XX_R10B_RGB01 0x010b -#define ZC3XX_R10C_RGB02 0x010c -#define ZC3XX_R113_RGB03 0x0113 -#define ZC3XX_R10D_RGB10 0x010d -#define ZC3XX_R10E_RGB11 0x010e -#define ZC3XX_R10F_RGB12 0x010f -#define ZC3XX_R114_RGB13 0x0114 -#define ZC3XX_R110_RGB20 0x0110 -#define ZC3XX_R111_RGB21 0x0111 -#define ZC3XX_R112_RGB22 0x0112 -#define ZC3XX_R115_RGB23 0x0115 - -/* Gamma matrix */ -#define ZC3XX_R120_GAMMA00 0x0120 -#define ZC3XX_R121_GAMMA01 0x0121 -#define ZC3XX_R122_GAMMA02 0x0122 -#define ZC3XX_R123_GAMMA03 0x0123 -#define ZC3XX_R124_GAMMA04 0x0124 -#define ZC3XX_R125_GAMMA05 0x0125 -#define ZC3XX_R126_GAMMA06 0x0126 -#define ZC3XX_R127_GAMMA07 0x0127 -#define ZC3XX_R128_GAMMA08 0x0128 -#define ZC3XX_R129_GAMMA09 0x0129 -#define ZC3XX_R12A_GAMMA0A 0x012a -#define ZC3XX_R12B_GAMMA0B 0x012b -#define ZC3XX_R12C_GAMMA0C 0x012c -#define ZC3XX_R12D_GAMMA0D 0x012d -#define ZC3XX_R12E_GAMMA0E 0x012e -#define ZC3XX_R12F_GAMMA0F 0x012f -#define ZC3XX_R130_GAMMA10 0x0130 -#define ZC3XX_R131_GAMMA11 0x0131 -#define ZC3XX_R132_GAMMA12 0x0132 -#define ZC3XX_R133_GAMMA13 0x0133 -#define ZC3XX_R134_GAMMA14 0x0134 -#define ZC3XX_R135_GAMMA15 0x0135 -#define ZC3XX_R136_GAMMA16 0x0136 -#define ZC3XX_R137_GAMMA17 0x0137 -#define ZC3XX_R138_GAMMA18 0x0138 -#define ZC3XX_R139_GAMMA19 0x0139 -#define ZC3XX_R13A_GAMMA1A 0x013a -#define ZC3XX_R13B_GAMMA1B 0x013b -#define ZC3XX_R13C_GAMMA1C 0x013c -#define ZC3XX_R13D_GAMMA1D 0x013d -#define ZC3XX_R13E_GAMMA1E 0x013e -#define ZC3XX_R13F_GAMMA1F 0x013f - -/* Luminance gamma */ -#define ZC3XX_R140_YGAMMA00 0x0140 -#define ZC3XX_R141_YGAMMA01 0x0141 -#define ZC3XX_R142_YGAMMA02 0x0142 -#define ZC3XX_R143_YGAMMA03 0x0143 -#define ZC3XX_R144_YGAMMA04 0x0144 -#define ZC3XX_R145_YGAMMA05 0x0145 -#define ZC3XX_R146_YGAMMA06 0x0146 -#define ZC3XX_R147_YGAMMA07 0x0147 -#define ZC3XX_R148_YGAMMA08 0x0148 -#define ZC3XX_R149_YGAMMA09 0x0149 -#define ZC3XX_R14A_YGAMMA0A 0x014a -#define ZC3XX_R14B_YGAMMA0B 0x014b -#define ZC3XX_R14C_YGAMMA0C 0x014c -#define ZC3XX_R14D_YGAMMA0D 0x014d -#define ZC3XX_R14E_YGAMMA0E 0x014e -#define ZC3XX_R14F_YGAMMA0F 0x014f -#define ZC3XX_R150_YGAMMA10 0x0150 -#define ZC3XX_R151_YGAMMA11 0x0151 - -#define ZC3XX_R1C5_SHARPNESSMODE 0x01c5 -#define ZC3XX_R1C6_SHARPNESS00 0x01c6 -#define ZC3XX_R1C7_SHARPNESS01 0x01c7 -#define ZC3XX_R1C8_SHARPNESS02 0x01c8 -#define ZC3XX_R1C9_SHARPNESS03 0x01c9 -#define ZC3XX_R1CA_SHARPNESS04 0x01ca -#define ZC3XX_R1CB_SHARPNESS05 0x01cb - -/* Dead pixels */ -#define ZC3XX_R250_DEADPIXELSMODE 0x0250 - -/* EEPROM */ -#define ZC3XX_R300_EEPROMCONFIG 0x0300 -#define ZC3XX_R301_EEPROMACCESS 0x0301 -#define ZC3XX_R302_EEPROMSTATUS 0x0302 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-control.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-control.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-control.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-control.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,198 +0,0 @@ -/* - * Hauppauge HD PVR USB driver - video 4 linux 2 interface - * - * Copyright (C) 2008 Janne Grunau (j@jannau.net) - * - * 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, version 2. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "hdpvr.h" - - -int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf) -{ - int ret; - char request_type = 0x38, snd_request = 0x01; - - mutex_lock(&dev->usbc_mutex); - dev->usbc_buf[0] = valbuf; - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - snd_request, 0x00 | request_type, - value, CTRL_DEFAULT_INDEX, - dev->usbc_buf, 1, 10000); - - mutex_unlock(&dev->usbc_mutex); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "config call request for value 0x%x returned %d\n", value, - ret); - - return ret < 0 ? ret : 0; -} - -struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev) -{ - struct hdpvr_video_info *vidinf = NULL; -#ifdef HDPVR_DEBUG - char print_buf[15]; -#endif - int ret; - - vidinf = kzalloc(sizeof(struct hdpvr_video_info), GFP_KERNEL); - if (!vidinf) { - v4l2_err(&dev->v4l2_dev, "out of memory\n"); - goto err; - } - - mutex_lock(&dev->usbc_mutex); - ret = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - 0x81, 0x80 | 0x38, - 0x1400, 0x0003, - dev->usbc_buf, 5, - 1000); - if (ret == 5) { - vidinf->width = dev->usbc_buf[1] << 8 | dev->usbc_buf[0]; - vidinf->height = dev->usbc_buf[3] << 8 | dev->usbc_buf[2]; - vidinf->fps = dev->usbc_buf[4]; - } - -#ifdef HDPVR_DEBUG - if (hdpvr_debug & MSG_INFO) { - hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf, - sizeof(print_buf), 0); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "get video info returned: %d, %s\n", ret, print_buf); - } -#endif - mutex_unlock(&dev->usbc_mutex); - - if (!vidinf->width || !vidinf->height || !vidinf->fps) { - kfree(vidinf); - vidinf = NULL; - } -err: - return vidinf; -} - -int get_input_lines_info(struct hdpvr_device *dev) -{ -#ifdef HDPVR_DEBUG - char print_buf[9]; -#endif - int ret, lines; - - mutex_lock(&dev->usbc_mutex); - ret = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - 0x81, 0x80 | 0x38, - 0x1800, 0x0003, - dev->usbc_buf, 3, - 1000); - -#ifdef HDPVR_DEBUG - if (hdpvr_debug & MSG_INFO) { - hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf, - sizeof(print_buf), 0); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "get input lines info returned: %d, %s\n", ret, - print_buf); - } -#endif - lines = dev->usbc_buf[1] << 8 | dev->usbc_buf[0]; - mutex_unlock(&dev->usbc_mutex); - return lines; -} - - -int hdpvr_set_bitrate(struct hdpvr_device *dev) -{ - int ret; - - mutex_lock(&dev->usbc_mutex); - memset(dev->usbc_buf, 0, 4); - dev->usbc_buf[0] = dev->options.bitrate; - dev->usbc_buf[2] = dev->options.peak_bitrate; - - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - 0x01, 0x38, CTRL_BITRATE_VALUE, - CTRL_DEFAULT_INDEX, dev->usbc_buf, 4, 1000); - mutex_unlock(&dev->usbc_mutex); - - return ret; -} - -int hdpvr_set_audio(struct hdpvr_device *dev, u8 input, - enum v4l2_mpeg_audio_encoding codec) -{ - int ret = 0; - - if (dev->flags & HDPVR_FLAG_AC3_CAP) { - mutex_lock(&dev->usbc_mutex); - memset(dev->usbc_buf, 0, 2); - dev->usbc_buf[0] = input; - if (codec == V4L2_MPEG_AUDIO_ENCODING_AAC) - dev->usbc_buf[1] = 0; - else if (codec == V4L2_MPEG_AUDIO_ENCODING_AC3) - dev->usbc_buf[1] = 1; - else { - mutex_unlock(&dev->usbc_mutex); - v4l2_err(&dev->v4l2_dev, "invalid audio codec %d\n", - codec); - ret = -EINVAL; - goto error; - } - - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - 0x01, 0x38, CTRL_AUDIO_INPUT_VALUE, - CTRL_DEFAULT_INDEX, dev->usbc_buf, 2, - 1000); - mutex_unlock(&dev->usbc_mutex); - if (ret == 2) - ret = 0; - } else - ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE, input); -error: - return ret; -} - -int hdpvr_set_options(struct hdpvr_device *dev) -{ - hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std); - - hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, - dev->options.video_input+1); - - hdpvr_set_audio(dev, dev->options.audio_input+1, - dev->options.audio_codec); - - hdpvr_set_bitrate(dev); - hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, - dev->options.bitrate_mode); - hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode); - - hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness); - hdpvr_config_call(dev, CTRL_CONTRAST, dev->options.contrast); - hdpvr_config_call(dev, CTRL_HUE, dev->options.hue); - hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation); - hdpvr_config_call(dev, CTRL_SHARPNESS, dev->options.sharpness); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,478 +0,0 @@ -/* - * Hauppauge HD PVR USB driver - * - * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2008 Janne Grunau (j@jannau.net) - * Copyright (C) 2008 John Poet - * - * 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, version 2. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "hdpvr.h" - -static int video_nr[HDPVR_MAX] = {[0 ... (HDPVR_MAX - 1)] = UNSET}; -module_param_array(video_nr, int, NULL, 0); -MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)"); - -/* holds the number of currently registered devices */ -static atomic_t dev_nr = ATOMIC_INIT(-1); - -int hdpvr_debug; -module_param(hdpvr_debug, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(hdpvr_debug, "enable debugging output"); - -static uint default_video_input = HDPVR_VIDEO_INPUTS; -module_param(default_video_input, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / " - "1=S-Video / 2=Composite"); - -static uint default_audio_input = HDPVR_AUDIO_INPUTS; -module_param(default_audio_input, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / " - "1=RCA front / 2=S/PDIF"); - -static int boost_audio; -module_param(boost_audio, bool, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(boost_audio, "boost the audio signal"); - - -/* table of devices that work with this driver */ -static struct usb_device_id hdpvr_table[] = { - { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID) }, - { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) }, - { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) }, - { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID3) }, - { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID4) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, hdpvr_table); - - -void hdpvr_delete(struct hdpvr_device *dev) -{ - hdpvr_free_buffers(dev); - - if (dev->video_dev) - video_device_release(dev->video_dev); - - usb_put_dev(dev->udev); -} - -static void challenge(u8 *bytes) -{ - u64 *i64P, tmp64; - uint i, idx; - - for (idx = 0; idx < 32; ++idx) { - - if (idx & 0x3) - bytes[(idx >> 3) + 3] = bytes[(idx >> 2) & 0x3]; - - switch (idx & 0x3) { - case 0x3: - bytes[2] += bytes[3] * 4 + bytes[4] + bytes[5]; - bytes[4] += bytes[(idx & 0x1) * 2] * 9 + 9; - break; - case 0x1: - bytes[0] *= 8; - bytes[0] += 7*idx + 4; - bytes[6] += bytes[3] * 3; - break; - case 0x0: - bytes[3 - (idx >> 3)] = bytes[idx >> 2]; - bytes[5] += bytes[6] * 3; - for (i = 0; i < 3; i++) - bytes[3] *= bytes[3] + 1; - break; - case 0x2: - for (i = 0; i < 3; i++) - bytes[1] *= bytes[6] + 1; - for (i = 0; i < 3; i++) { - i64P = (u64 *)bytes; - tmp64 = le64_to_cpup(i64P); - tmp64 <<= bytes[7] & 0x0f; - *i64P += cpu_to_le64(tmp64); - } - break; - } - } -} - -/* try to init the device like the windows driver */ -static int device_authorization(struct hdpvr_device *dev) -{ - - int ret, retval = -ENOMEM; - char request_type = 0x38, rcv_request = 0x81; - char *response; -#ifdef HDPVR_DEBUG - size_t buf_size = 46; - char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL); - if (!print_buf) { - v4l2_err(&dev->v4l2_dev, "Out of memory\n"); - return retval; - } -#endif - - mutex_lock(&dev->usbc_mutex); - ret = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - rcv_request, 0x80 | request_type, - 0x0400, 0x0003, - dev->usbc_buf, 46, - 10000); - if (ret != 46) { - v4l2_err(&dev->v4l2_dev, - "unexpected answer of status request, len %d\n", ret); - goto unlock; - } -#ifdef HDPVR_DEBUG - else { - hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf, - 5*buf_size+1, 0); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "Status request returned, len %d: %s\n", - ret, print_buf); - } -#endif - - v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n", - dev->usbc_buf[1], &dev->usbc_buf[2]); - - switch (dev->usbc_buf[1]) { - case HDPVR_FIRMWARE_VERSION: - dev->flags &= ~HDPVR_FLAG_AC3_CAP; - break; - case HDPVR_FIRMWARE_VERSION_AC3: - case HDPVR_FIRMWARE_VERSION_0X12: - case HDPVR_FIRMWARE_VERSION_0X15: - dev->flags |= HDPVR_FLAG_AC3_CAP; - break; - default: - v4l2_info(&dev->v4l2_dev, "untested firmware, the driver might" - " not work.\n"); - if (dev->usbc_buf[1] >= HDPVR_FIRMWARE_VERSION_AC3) - dev->flags |= HDPVR_FLAG_AC3_CAP; - else - dev->flags &= ~HDPVR_FLAG_AC3_CAP; - } - - response = dev->usbc_buf+38; -#ifdef HDPVR_DEBUG - hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n", - print_buf); -#endif - challenge(response); -#ifdef HDPVR_DEBUG - hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n", - print_buf); -#endif - - msleep(100); - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - 0xd1, 0x00 | request_type, - 0x0000, 0x0000, - response, 8, - 10000); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "magic request returned %d\n", ret); - - retval = ret != 8; -unlock: - mutex_unlock(&dev->usbc_mutex); - return retval; -} - -static int hdpvr_device_init(struct hdpvr_device *dev) -{ - int ret; - u8 *buf; - struct hdpvr_video_info *vidinf; - - if (device_authorization(dev)) - return -EACCES; - - /* default options for init */ - hdpvr_set_options(dev); - - /* set filter options */ - mutex_lock(&dev->usbc_mutex); - buf = dev->usbc_buf; - buf[0] = 0x03; buf[1] = 0x03; buf[2] = 0x00; buf[3] = 0x00; - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - 0x01, 0x38, - CTRL_LOW_PASS_FILTER_VALUE, CTRL_DEFAULT_INDEX, - buf, 4, - 1000); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "control request returned %d\n", ret); - mutex_unlock(&dev->usbc_mutex); - - vidinf = get_video_info(dev); - if (!vidinf) - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "no valid video signal or device init failed\n"); - else - kfree(vidinf); - - /* enable fan and bling leds */ - mutex_lock(&dev->usbc_mutex); - buf[0] = 0x1; - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - 0xd4, 0x38, 0, 0, buf, 1, - 1000); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "control request returned %d\n", ret); - - /* boost analog audio */ - buf[0] = boost_audio; - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - 0xd5, 0x38, 0, 0, buf, 1, - 1000); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "control request returned %d\n", ret); - mutex_unlock(&dev->usbc_mutex); - - dev->status = STATUS_IDLE; - return 0; -} - -static const struct hdpvr_options hdpvr_default_options = { - .video_std = HDPVR_60HZ, - .video_input = HDPVR_COMPONENT, - .audio_input = HDPVR_RCA_BACK, - .bitrate = 65, /* 6 mbps */ - .peak_bitrate = 90, /* 9 mbps */ - .bitrate_mode = HDPVR_CONSTANT, - .gop_mode = HDPVR_SIMPLE_IDR_GOP, - .audio_codec = V4L2_MPEG_AUDIO_ENCODING_AAC, - .brightness = 0x86, - .contrast = 0x80, - .hue = 0x80, - .saturation = 0x80, - .sharpness = 0x80, -}; - -static int hdpvr_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct hdpvr_device *dev; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - struct i2c_client *client; - size_t buffer_size; - int i; - int retval = -ENOMEM; - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - err("Out of memory"); - goto error; - } - - dev->workqueue = 0; - - /* register v4l2_device early so it can be used for printks */ - if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) { - err("v4l2_device_register failed"); - goto error; - } - - mutex_init(&dev->io_mutex); - mutex_init(&dev->i2c_mutex); - mutex_init(&dev->usbc_mutex); - dev->usbc_buf = kmalloc(64, GFP_KERNEL); - if (!dev->usbc_buf) { - v4l2_err(&dev->v4l2_dev, "Out of memory\n"); - goto error; - } - - init_waitqueue_head(&dev->wait_buffer); - init_waitqueue_head(&dev->wait_data); - - dev->workqueue = create_singlethread_workqueue("hdpvr_buffer"); - if (!dev->workqueue) - goto error; - - /* init video transfer queues */ - INIT_LIST_HEAD(&dev->free_buff_list); - INIT_LIST_HEAD(&dev->rec_buff_list); - - dev->options = hdpvr_default_options; - - if (default_video_input < HDPVR_VIDEO_INPUTS) - dev->options.video_input = default_video_input; - - if (default_audio_input < HDPVR_AUDIO_INPUTS) { - dev->options.audio_input = default_audio_input; - if (default_audio_input == HDPVR_SPDIF) - dev->options.audio_codec = - V4L2_MPEG_AUDIO_ENCODING_AC3; - } - - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - - /* set up the endpoint information */ - /* use only the first bulk-in and bulk-out endpoints */ - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (!dev->bulk_in_endpointAddr && - usb_endpoint_is_bulk_in(endpoint)) { - /* USB interface description is buggy, reported max - * packet size is 512 bytes, windows driver uses 8192 */ - buffer_size = 8192; - dev->bulk_in_size = buffer_size; - dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; - } - - } - if (!dev->bulk_in_endpointAddr) { - v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n"); - goto error; - } - - /* init the device */ - if (hdpvr_device_init(dev)) { - v4l2_err(&dev->v4l2_dev, "device init failed\n"); - goto error; - } - - mutex_lock(&dev->io_mutex); - if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) { - mutex_unlock(&dev->io_mutex); - v4l2_err(&dev->v4l2_dev, - "allocating transfer buffers failed\n"); - goto error; - } - mutex_unlock(&dev->io_mutex); - - if (hdpvr_register_videodev(dev, &interface->dev, - video_nr[atomic_inc_return(&dev_nr)])) { - v4l2_err(&dev->v4l2_dev, "registering videodev failed\n"); - goto error; - } - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - retval = hdpvr_register_i2c_adapter(dev); - if (retval < 0) { - v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n"); - goto error; - } - - client = hdpvr_register_ir_rx_i2c(dev); - if (!client) { - v4l2_err(&dev->v4l2_dev, "i2c IR RX device register failed\n"); - goto reg_fail; - } - - client = hdpvr_register_ir_tx_i2c(dev); - if (!client) { - v4l2_err(&dev->v4l2_dev, "i2c IR TX device register failed\n"); - goto reg_fail; - } -#endif - - /* let the user know what node this device is now attached to */ - v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", - video_device_node_name(dev->video_dev)); - return 0; - -reg_fail: -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_adapter(&dev->i2c_adapter); -#endif -error: - if (dev) { - /* Destroy single thread */ - if (dev->workqueue) - destroy_workqueue(dev->workqueue); - /* this frees allocated memory */ - hdpvr_delete(dev); - } - return retval; -} - -static void hdpvr_disconnect(struct usb_interface *interface) -{ - struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface)); - - v4l2_info(&dev->v4l2_dev, "device %s disconnected\n", - video_device_node_name(dev->video_dev)); - /* prevent more I/O from starting and stop any ongoing */ - mutex_lock(&dev->io_mutex); - dev->status = STATUS_DISCONNECTED; - wake_up_interruptible(&dev->wait_data); - wake_up_interruptible(&dev->wait_buffer); - mutex_unlock(&dev->io_mutex); - v4l2_device_disconnect(&dev->v4l2_dev); - msleep(100); - flush_workqueue(dev->workqueue); - mutex_lock(&dev->io_mutex); - hdpvr_cancel_queue(dev); - mutex_unlock(&dev->io_mutex); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_adapter(&dev->i2c_adapter); -#endif - video_unregister_device(dev->video_dev); - atomic_dec(&dev_nr); -} - - -static struct usb_driver hdpvr_usb_driver = { - .name = "hdpvr", - .probe = hdpvr_probe, - .disconnect = hdpvr_disconnect, - .id_table = hdpvr_table, -}; - -static int __init hdpvr_init(void) -{ - int result; - - /* register this driver with the USB subsystem */ - result = usb_register(&hdpvr_usb_driver); - if (result) - err("usb_register failed. Error number %d", result); - - return result; -} - -static void __exit hdpvr_exit(void) -{ - /* deregister this driver with the USB subsystem */ - usb_deregister(&hdpvr_usb_driver); -} - -module_init(hdpvr_init); -module_exit(hdpvr_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Janne Grunau"); -MODULE_DESCRIPTION("Hauppauge HD PVR driver"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,322 +0,0 @@ -/* - * Hauppauge HD PVR USB driver - * - * Copyright (C) 2008 Janne Grunau (j@jannau.net) - * - * 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, version 2. - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -#define HDPVR_MAJOR_VERSION 0 -#define HDPVR_MINOR_VERSION 2 -#define HDPVR_RELEASE 0 -#define HDPVR_VERSION \ - KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE) - -#define HDPVR_MAX 8 -#define HDPVR_I2C_MAX_SIZE 128 - -/* Define these values to match your devices */ -#define HD_PVR_VENDOR_ID 0x2040 -#define HD_PVR_PRODUCT_ID 0x4900 -#define HD_PVR_PRODUCT_ID1 0x4901 -#define HD_PVR_PRODUCT_ID2 0x4902 -#define HD_PVR_PRODUCT_ID4 0x4903 -#define HD_PVR_PRODUCT_ID3 0x4982 - -#define UNSET (-1U) - -#define NUM_BUFFERS 64 - -#define HDPVR_FIRMWARE_VERSION 0x08 -#define HDPVR_FIRMWARE_VERSION_AC3 0x0d -#define HDPVR_FIRMWARE_VERSION_0X12 0x12 -#define HDPVR_FIRMWARE_VERSION_0X15 0x15 - -/* #define HDPVR_DEBUG */ - -extern int hdpvr_debug; - -#define MSG_INFO 1 -#define MSG_BUFFER 2 - -struct hdpvr_options { - u8 video_std; - u8 video_input; - u8 audio_input; - u8 bitrate; /* in 100kbps */ - u8 peak_bitrate; /* in 100kbps */ - u8 bitrate_mode; - u8 gop_mode; - enum v4l2_mpeg_audio_encoding audio_codec; - u8 brightness; - u8 contrast; - u8 hue; - u8 saturation; - u8 sharpness; -}; - -/* Structure to hold all of our device specific stuff */ -struct hdpvr_device { - /* the v4l device for this device */ - struct video_device *video_dev; - /* the usb device for this device */ - struct usb_device *udev; - /* v4l2-device unused */ - struct v4l2_device v4l2_dev; - - /* the max packet size of the bulk endpoint */ - size_t bulk_in_size; - /* the address of the bulk in endpoint */ - __u8 bulk_in_endpointAddr; - - /* holds the current device status */ - __u8 status; - /* count the number of openers */ - uint open_count; - - /* holds the cureent set options */ - struct hdpvr_options options; - - uint flags; - - /* synchronize I/O */ - struct mutex io_mutex; - /* available buffers */ - struct list_head free_buff_list; - /* in progress buffers */ - struct list_head rec_buff_list; - /* waitqueue for buffers */ - wait_queue_head_t wait_buffer; - /* waitqueue for data */ - wait_queue_head_t wait_data; - /**/ - struct workqueue_struct *workqueue; - /**/ - struct work_struct worker; - - /* I2C adapter */ - struct i2c_adapter i2c_adapter; - /* I2C lock */ - struct mutex i2c_mutex; - /* I2C message buffer space */ - char i2c_buf[HDPVR_I2C_MAX_SIZE]; - - /* For passing data to ir-kbd-i2c */ - struct IR_i2c_init_data ir_i2c_init_data; - - /* usb control transfer buffer and lock */ - struct mutex usbc_mutex; - u8 *usbc_buf; -}; - -static inline struct hdpvr_device *to_hdpvr_dev(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct hdpvr_device, v4l2_dev); -} - - -/* buffer one bulk urb of data */ -struct hdpvr_buffer { - struct list_head buff_list; - - struct urb *urb; - - struct hdpvr_device *dev; - - uint pos; - - __u8 status; -}; - -/* */ - -struct hdpvr_video_info { - u16 width; - u16 height; - u8 fps; -}; - -enum { - STATUS_UNINITIALIZED = 0, - STATUS_IDLE, - STATUS_STARTING, - STATUS_SHUTTING_DOWN, - STATUS_STREAMING, - STATUS_ERROR, - STATUS_DISCONNECTED, -}; - -enum { - HDPVR_FLAG_AC3_CAP = 1, -}; - -enum { - BUFSTAT_UNINITIALIZED = 0, - BUFSTAT_AVAILABLE, - BUFSTAT_INPROGRESS, - BUFSTAT_READY, -}; - -#define CTRL_START_STREAMING_VALUE 0x0700 -#define CTRL_STOP_STREAMING_VALUE 0x0800 -#define CTRL_BITRATE_VALUE 0x1000 -#define CTRL_BITRATE_MODE_VALUE 0x1200 -#define CTRL_GOP_MODE_VALUE 0x1300 -#define CTRL_VIDEO_INPUT_VALUE 0x1500 -#define CTRL_VIDEO_STD_TYPE 0x1700 -#define CTRL_AUDIO_INPUT_VALUE 0x2500 -#define CTRL_BRIGHTNESS 0x2900 -#define CTRL_CONTRAST 0x2a00 -#define CTRL_HUE 0x2b00 -#define CTRL_SATURATION 0x2c00 -#define CTRL_SHARPNESS 0x2d00 -#define CTRL_LOW_PASS_FILTER_VALUE 0x3100 - -#define CTRL_DEFAULT_INDEX 0x0003 - - - /* :0 s 38 01 1000 0003 0004 4 = 0a00ca00 - * BITRATE SETTING - * 1st and 2nd byte (little endian): average bitrate in 100 000 bit/s - * min: 1 mbit/s, max: 13.5 mbit/s - * 3rd and 4th byte (little endian): peak bitrate in 100 000 bit/s - * min: average + 100kbit/s, - * max: 20.2 mbit/s - */ - - /* :0 s 38 01 1200 0003 0001 1 = 02 - * BIT RATE MODE - * constant = 1, variable (peak) = 2, variable (average) = 3 - */ - - /* :0 s 38 01 1300 0003 0001 1 = 03 - * GOP MODE (2 bit) - * low bit 0/1: advanced/simple GOP - * high bit 0/1: IDR(4/32/128) / no IDR (4/32/0) - */ - - /* :0 s 38 01 1700 0003 0001 1 = 00 - * VIDEO STANDARD or FREQUNCY 0 = 60hz, 1 = 50hz - */ - - /* :0 s 38 01 3100 0003 0004 4 = 03030000 - * FILTER CONTROL - * 1st byte luma low pass filter strength, - * 2nd byte chroma low pass filter strength, - * 3rd byte MF enable chroma, min=0, max=1 - * 4th byte n - */ - - - /* :0 s 38 b9 0001 0000 0000 0 */ - - - -/* :0 s 38 d3 0000 0000 0001 1 = 00 */ -/* ret = usb_control_msg(dev->udev, */ -/* usb_sndctrlpipe(dev->udev, 0), */ -/* 0xd3, 0x38, */ -/* 0, 0, */ -/* "\0", 1, */ -/* 1000); */ - -/* info("control request returned %d", ret); */ -/* msleep(5000); */ - - - /* :0 s b8 81 1400 0003 0005 5 < - * :0 0 5 = d0024002 19 - * QUERY FRAME SIZE AND RATE - * 1st and 2nd byte (little endian): horizontal resolution - * 3rd and 4th byte (little endian): vertical resolution - * 5th byte: frame rate - */ - - /* :0 s b8 81 1800 0003 0003 3 < - * :0 0 3 = 030104 - * QUERY SIGNAL AND DETECTED LINES, maybe INPUT - */ - -enum hdpvr_video_std { - HDPVR_60HZ = 0, - HDPVR_50HZ, -}; - -enum hdpvr_video_input { - HDPVR_COMPONENT = 0, - HDPVR_SVIDEO, - HDPVR_COMPOSITE, - HDPVR_VIDEO_INPUTS -}; - -enum hdpvr_audio_inputs { - HDPVR_RCA_BACK = 0, - HDPVR_RCA_FRONT, - HDPVR_SPDIF, - HDPVR_AUDIO_INPUTS -}; - -enum hdpvr_bitrate_mode { - HDPVR_CONSTANT = 1, - HDPVR_VARIABLE_PEAK, - HDPVR_VARIABLE_AVERAGE, -}; - -enum hdpvr_gop_mode { - HDPVR_ADVANCED_IDR_GOP = 0, - HDPVR_SIMPLE_IDR_GOP, - HDPVR_ADVANCED_NOIDR_GOP, - HDPVR_SIMPLE_NOIDR_GOP, -}; - -void hdpvr_delete(struct hdpvr_device *dev); - -/*========================================================================*/ -/* hardware control functions */ -int hdpvr_set_options(struct hdpvr_device *dev); - -int hdpvr_set_bitrate(struct hdpvr_device *dev); - -int hdpvr_set_audio(struct hdpvr_device *dev, u8 input, - enum v4l2_mpeg_audio_encoding codec); - -int hdpvr_config_call(struct hdpvr_device *dev, uint value, - unsigned char valbuf); - -struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev); - -/* :0 s b8 81 1800 0003 0003 3 < */ -/* :0 0 3 = 0301ff */ -int get_input_lines_info(struct hdpvr_device *dev); - - -/*========================================================================*/ -/* v4l2 registration */ -int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, - int devnumber); - -int hdpvr_cancel_queue(struct hdpvr_device *dev); - -/*========================================================================*/ -/* i2c adapter registration */ -int hdpvr_register_i2c_adapter(struct hdpvr_device *dev); - -struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev); -struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev); - -/*========================================================================*/ -/* buffer management */ -int hdpvr_free_buffers(struct hdpvr_device *dev); -int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,230 +0,0 @@ - -/* - * Hauppauge HD PVR USB driver - * - * Copyright (C) 2008 Janne Grunau (j@jannau.net) - * - * IR device registration code is - * Copyright (C) 2010 Andy Walls - * - * 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, version 2. - * - */ - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -#include -#include - -#include "hdpvr.h" - -#define CTRL_READ_REQUEST 0xb8 -#define CTRL_WRITE_REQUEST 0x38 - -#define REQTYPE_I2C_READ 0xb1 -#define REQTYPE_I2C_WRITE 0xb0 -#define REQTYPE_I2C_WRITE_STATT 0xd0 - -#define Z8F0811_IR_TX_I2C_ADDR 0x70 -#define Z8F0811_IR_RX_I2C_ADDR 0x71 - - -struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev) -{ - struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; - struct i2c_board_info hdpvr_ir_tx_i2c_board_info = { - I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR), - }; - - init_data->name = "HD-PVR"; - hdpvr_ir_tx_i2c_board_info.platform_data = init_data; - - return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_tx_i2c_board_info); -} - -struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) -{ - struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; - struct i2c_board_info hdpvr_ir_rx_i2c_board_info = { - I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR), - }; - - /* Our default information for ir-kbd-i2c.c to use */ - init_data->ir_codes = RC_MAP_HAUPPAUGE; - init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; - init_data->name = "HD-PVR"; - init_data->polling_interval = 405; /* ms, duplicated from Windows */ - hdpvr_ir_rx_i2c_board_info.platform_data = init_data; - - return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_rx_i2c_board_info); -} - -static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, - unsigned char addr, char *wdata, int wlen, - char *data, int len) -{ - int ret; - - if ((len > sizeof(dev->i2c_buf)) || (wlen > sizeof(dev->i2c_buf))) - return -EINVAL; - - if (wlen) { - memcpy(&dev->i2c_buf, wdata, wlen); - ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, - (bus << 8) | addr, 0, &dev->i2c_buf, - wlen, 1000); - if (ret < 0) - return ret; - } - - ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), - REQTYPE_I2C_READ, CTRL_READ_REQUEST, - (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); - - if (ret == len) { - memcpy(data, &dev->i2c_buf, len); - ret = 0; - } else if (ret >= 0) - ret = -EIO; - - return ret; -} - -static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus, - unsigned char addr, char *data, int len) -{ - int ret; - - if (len > sizeof(dev->i2c_buf)) - return -EINVAL; - - memcpy(&dev->i2c_buf, data, len); - ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, - (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); - - if (ret < 0) - return ret; - - ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), - REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, - 0, 0, &dev->i2c_buf, 2, 1000); - - if ((ret == 2) && (dev->i2c_buf[1] == (len - 1))) - ret = 0; - else if (ret >= 0) - ret = -EIO; - - return ret; -} - -static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, - int num) -{ - struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter); - int retval = 0, addr; - - if (num <= 0) - return 0; - - mutex_lock(&dev->i2c_mutex); - - addr = msgs[0].addr << 1; - - if (num == 1) { - if (msgs[0].flags & I2C_M_RD) - retval = hdpvr_i2c_read(dev, 1, addr, NULL, 0, - msgs[0].buf, msgs[0].len); - else - retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf, - msgs[0].len); - } else if (num == 2) { - if (msgs[0].addr != msgs[1].addr) { - v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer " - "with conflicting target addresses\n"); - retval = -EINVAL; - goto out; - } - - if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) { - v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with " - "r0=%d, r1=%d\n", msgs[0].flags & I2C_M_RD, - msgs[1].flags & I2C_M_RD); - retval = -EINVAL; - goto out; - } - - /* - * Write followed by atomic read is the only complex xfer that - * we actually support here. - */ - retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len, - msgs[1].buf, msgs[1].len); - } else { - v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num); - } - -out: - mutex_unlock(&dev->i2c_mutex); - - return retval ? retval : num; -} - -static u32 hdpvr_functionality(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm hdpvr_algo = { - .master_xfer = hdpvr_transfer, - .functionality = hdpvr_functionality, -}; - -static struct i2c_adapter hdpvr_i2c_adapter_template = { - .name = "Hauppage HD PVR I2C", - .owner = THIS_MODULE, - .algo = &hdpvr_algo, -}; - -static int hdpvr_activate_ir(struct hdpvr_device *dev) -{ - char buffer[2]; - - mutex_lock(&dev->i2c_mutex); - - hdpvr_i2c_read(dev, 0, 0x54, NULL, 0, buffer, 1); - - buffer[0] = 0; - buffer[1] = 0x8; - hdpvr_i2c_write(dev, 1, 0x54, buffer, 2); - - buffer[1] = 0x18; - hdpvr_i2c_write(dev, 1, 0x54, buffer, 2); - - mutex_unlock(&dev->i2c_mutex); - - return 0; -} - -int hdpvr_register_i2c_adapter(struct hdpvr_device *dev) -{ - int retval = -ENOMEM; - - hdpvr_activate_ir(dev); - - memcpy(&dev->i2c_adapter, &hdpvr_i2c_adapter_template, - sizeof(struct i2c_adapter)); - dev->i2c_adapter.dev.parent = &dev->udev->dev; - - i2c_set_adapdata(&dev->i2c_adapter, dev); - - retval = i2c_add_adapter(&dev->i2c_adapter); - - return retval; -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/hdpvr-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1271 +0,0 @@ -/* - * Hauppauge HD PVR USB driver - video 4 linux 2 interface - * - * Copyright (C) 2008 Janne Grunau (j@jannau.net) - * - * 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, version 2. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "hdpvr.h" - -#define BULK_URB_TIMEOUT 90 /* 0.09 seconds */ - -#define print_buffer_status() { \ - v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, \ - "%s:%d buffer stat: %d free, %d proc\n", \ - __func__, __LINE__, \ - list_size(&dev->free_buff_list), \ - list_size(&dev->rec_buff_list)); } - -struct hdpvr_fh { - struct hdpvr_device *dev; -}; - -static uint list_size(struct list_head *list) -{ - struct list_head *tmp; - uint count = 0; - - list_for_each(tmp, list) { - count++; - } - - return count; -} - -/*=========================================================================*/ -/* urb callback */ -static void hdpvr_read_bulk_callback(struct urb *urb) -{ - struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context; - struct hdpvr_device *dev = buf->dev; - - /* marking buffer as received and wake waiting */ - buf->status = BUFSTAT_READY; - wake_up_interruptible(&dev->wait_data); -} - -/*=========================================================================*/ -/* bufffer bits */ - -/* function expects dev->io_mutex to be hold by caller */ -int hdpvr_cancel_queue(struct hdpvr_device *dev) -{ - struct hdpvr_buffer *buf; - - list_for_each_entry(buf, &dev->rec_buff_list, buff_list) { - usb_kill_urb(buf->urb); - buf->status = BUFSTAT_AVAILABLE; - } - - list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev); - - return 0; -} - -static int hdpvr_free_queue(struct list_head *q) -{ - struct list_head *tmp; - struct list_head *p; - struct hdpvr_buffer *buf; - struct urb *urb; - - for (p = q->next; p != q;) { - buf = list_entry(p, struct hdpvr_buffer, buff_list); - - urb = buf->urb; - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); - usb_free_urb(urb); - tmp = p->next; - list_del(p); - kfree(buf); - p = tmp; - } - - return 0; -} - -/* function expects dev->io_mutex to be hold by caller */ -int hdpvr_free_buffers(struct hdpvr_device *dev) -{ - hdpvr_cancel_queue(dev); - - hdpvr_free_queue(&dev->free_buff_list); - hdpvr_free_queue(&dev->rec_buff_list); - - return 0; -} - -/* function expects dev->io_mutex to be hold by caller */ -int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count) -{ - uint i; - int retval = -ENOMEM; - u8 *mem; - struct hdpvr_buffer *buf; - struct urb *urb; - - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "allocating %u buffers\n", count); - - for (i = 0; i < count; i++) { - - buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL); - if (!buf) { - v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n"); - goto exit; - } - buf->dev = dev; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n"); - goto exit_urb; - } - buf->urb = urb; - - mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL, - &urb->transfer_dma); - if (!mem) { - v4l2_err(&dev->v4l2_dev, - "cannot allocate usb transfer buffer\n"); - goto exit_urb_buffer; - } - - usb_fill_bulk_urb(buf->urb, dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->bulk_in_endpointAddr), - mem, dev->bulk_in_size, - hdpvr_read_bulk_callback, buf); - - buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - buf->status = BUFSTAT_AVAILABLE; - list_add_tail(&buf->buff_list, &dev->free_buff_list); - } - return 0; -exit_urb_buffer: - usb_free_urb(urb); -exit_urb: - kfree(buf); -exit: - hdpvr_free_buffers(dev); - return retval; -} - -static int hdpvr_submit_buffers(struct hdpvr_device *dev) -{ - struct hdpvr_buffer *buf; - struct urb *urb; - int ret = 0, err_count = 0; - - mutex_lock(&dev->io_mutex); - - while (dev->status == STATUS_STREAMING && - !list_empty(&dev->free_buff_list)) { - - buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer, - buff_list); - if (buf->status != BUFSTAT_AVAILABLE) { - v4l2_err(&dev->v4l2_dev, - "buffer not marked as available\n"); - ret = -EFAULT; - goto err; - } - - urb = buf->urb; - urb->status = 0; - urb->actual_length = 0; - ret = usb_submit_urb(urb, GFP_KERNEL); - if (ret) { - v4l2_err(&dev->v4l2_dev, - "usb_submit_urb in %s returned %d\n", - __func__, ret); - if (++err_count > 2) - break; - continue; - } - buf->status = BUFSTAT_INPROGRESS; - list_move_tail(&buf->buff_list, &dev->rec_buff_list); - } -err: - print_buffer_status(); - mutex_unlock(&dev->io_mutex); - return ret; -} - -static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev) -{ - struct hdpvr_buffer *buf; - - mutex_lock(&dev->io_mutex); - - if (list_empty(&dev->rec_buff_list)) { - mutex_unlock(&dev->io_mutex); - return NULL; - } - - buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer, - buff_list); - mutex_unlock(&dev->io_mutex); - - return buf; -} - -static void hdpvr_transmit_buffers(struct work_struct *work) -{ - struct hdpvr_device *dev = container_of(work, struct hdpvr_device, - worker); - - while (dev->status == STATUS_STREAMING) { - - if (hdpvr_submit_buffers(dev)) { - v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n"); - goto error; - } - if (wait_event_interruptible(dev->wait_buffer, - !list_empty(&dev->free_buff_list) || - dev->status != STATUS_STREAMING)) - goto error; - } - - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "transmit worker exited\n"); - return; -error: - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "transmit buffers errored\n"); - dev->status = STATUS_ERROR; -} - -/* function expects dev->io_mutex to be hold by caller */ -static int hdpvr_start_streaming(struct hdpvr_device *dev) -{ - int ret; - struct hdpvr_video_info *vidinf; - - if (dev->status == STATUS_STREAMING) - return 0; - else if (dev->status != STATUS_IDLE) - return -EAGAIN; - - vidinf = get_video_info(dev); - - if (vidinf) { - v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, - "video signal: %dx%d@%dhz\n", vidinf->width, - vidinf->height, vidinf->fps); - kfree(vidinf); - - /* start streaming 2 request */ - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - 0xb8, 0x38, 0x1, 0, NULL, 0, 8000); - v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, - "encoder start control request returned %d\n", ret); - - hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00); - - INIT_WORK(&dev->worker, hdpvr_transmit_buffers); - queue_work(dev->workqueue, &dev->worker); - - v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, - "streaming started\n"); - dev->status = STATUS_STREAMING; - - return 0; - } - msleep(250); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "no video signal at input %d\n", dev->options.video_input); - return -EAGAIN; -} - - -/* function expects dev->io_mutex to be hold by caller */ -static int hdpvr_stop_streaming(struct hdpvr_device *dev) -{ - int actual_length; - uint c = 0; - u8 *buf; - - if (dev->status == STATUS_IDLE) - return 0; - else if (dev->status != STATUS_STREAMING) - return -EAGAIN; - - buf = kmalloc(dev->bulk_in_size, GFP_KERNEL); - if (!buf) - v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer " - "for emptying the internal device buffer. " - "Next capture start will be slow\n"); - - dev->status = STATUS_SHUTTING_DOWN; - hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00); - mutex_unlock(&dev->io_mutex); - - wake_up_interruptible(&dev->wait_buffer); - msleep(50); - - flush_workqueue(dev->workqueue); - - mutex_lock(&dev->io_mutex); - /* kill the still outstanding urbs */ - hdpvr_cancel_queue(dev); - - /* emptying the device buffer beforeshutting it down */ - while (buf && ++c < 500 && - !usb_bulk_msg(dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->bulk_in_endpointAddr), - buf, dev->bulk_in_size, &actual_length, - BULK_URB_TIMEOUT)) { - v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, - "%2d: got %d bytes\n", c, actual_length); - } - kfree(buf); - v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, - "used %d urbs to empty device buffers\n", c-1); - msleep(10); - - dev->status = STATUS_IDLE; - - return 0; -} - - -/*=======================================================================*/ -/* - * video 4 linux 2 file operations - */ - -static int hdpvr_open(struct file *file) -{ - struct hdpvr_device *dev; - struct hdpvr_fh *fh; - int retval = -ENOMEM; - - dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file)); - if (!dev) { - pr_err("open failing with with ENODEV\n"); - retval = -ENODEV; - goto err; - } - - fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL); - if (!fh) { - v4l2_err(&dev->v4l2_dev, "Out of memory\n"); - goto err; - } - /* lock the device to allow correctly handling errors - * in resumption */ - mutex_lock(&dev->io_mutex); - dev->open_count++; - mutex_unlock(&dev->io_mutex); - - fh->dev = dev; - - /* save our object in the file's private structure */ - file->private_data = fh; - - retval = 0; -err: - return retval; -} - -static int hdpvr_release(struct file *file) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - - if (!dev) - return -ENODEV; - - mutex_lock(&dev->io_mutex); - if (!(--dev->open_count) && dev->status == STATUS_STREAMING) - hdpvr_stop_streaming(dev); - - mutex_unlock(&dev->io_mutex); - - return 0; -} - -/* - * hdpvr_v4l2_read() - * will allocate buffers when called for the first time - */ -static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, - loff_t *pos) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - struct hdpvr_buffer *buf = NULL; - struct urb *urb; - unsigned int ret = 0; - int rem, cnt; - - if (*pos) - return -ESPIPE; - - if (!dev) - return -ENODEV; - - mutex_lock(&dev->io_mutex); - if (dev->status == STATUS_IDLE) { - if (hdpvr_start_streaming(dev)) { - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "start_streaming failed\n"); - ret = -EIO; - msleep(200); - dev->status = STATUS_IDLE; - mutex_unlock(&dev->io_mutex); - goto err; - } - print_buffer_status(); - } - mutex_unlock(&dev->io_mutex); - - /* wait for the first buffer */ - if (!(file->f_flags & O_NONBLOCK)) { - if (wait_event_interruptible(dev->wait_data, - hdpvr_get_next_buffer(dev))) - return -ERESTARTSYS; - } - - buf = hdpvr_get_next_buffer(dev); - - while (count > 0 && buf) { - - if (buf->status != BUFSTAT_READY && - dev->status != STATUS_DISCONNECTED) { - /* return nonblocking */ - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto err; - } - - if (wait_event_interruptible(dev->wait_data, - buf->status == BUFSTAT_READY)) { - ret = -ERESTARTSYS; - goto err; - } - } - - if (buf->status != BUFSTAT_READY) - break; - - /* set remaining bytes to copy */ - urb = buf->urb; - rem = urb->actual_length - buf->pos; - cnt = rem > count ? count : rem; - - if (copy_to_user(buffer, urb->transfer_buffer + buf->pos, - cnt)) { - v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n"); - if (!ret) - ret = -EFAULT; - goto err; - } - - buf->pos += cnt; - count -= cnt; - buffer += cnt; - ret += cnt; - - /* finished, take next buffer */ - if (buf->pos == urb->actual_length) { - mutex_lock(&dev->io_mutex); - buf->pos = 0; - buf->status = BUFSTAT_AVAILABLE; - - list_move_tail(&buf->buff_list, &dev->free_buff_list); - - print_buffer_status(); - - mutex_unlock(&dev->io_mutex); - - wake_up_interruptible(&dev->wait_buffer); - - buf = hdpvr_get_next_buffer(dev); - } - } -err: - if (!ret && !buf) - ret = -EAGAIN; - return ret; -} - -static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) -{ - struct hdpvr_buffer *buf = NULL; - struct hdpvr_fh *fh = filp->private_data; - struct hdpvr_device *dev = fh->dev; - unsigned int mask = 0; - - mutex_lock(&dev->io_mutex); - - if (!video_is_registered(dev->video_dev)) { - mutex_unlock(&dev->io_mutex); - return -EIO; - } - - if (dev->status == STATUS_IDLE) { - if (hdpvr_start_streaming(dev)) { - v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, - "start_streaming failed\n"); - dev->status = STATUS_IDLE; - } - - print_buffer_status(); - } - mutex_unlock(&dev->io_mutex); - - buf = hdpvr_get_next_buffer(dev); - /* only wait if no data is available */ - if (!buf || buf->status != BUFSTAT_READY) { - poll_wait(filp, &dev->wait_data, wait); - buf = hdpvr_get_next_buffer(dev); - } - if (buf && buf->status == BUFSTAT_READY) - mask |= POLLIN | POLLRDNORM; - - return mask; -} - - -static const struct v4l2_file_operations hdpvr_fops = { - .owner = THIS_MODULE, - .open = hdpvr_open, - .release = hdpvr_release, - .read = hdpvr_read, - .poll = hdpvr_poll, - .unlocked_ioctl = video_ioctl2, -}; - -/*=======================================================================*/ -/* - * V4L2 ioctl handling - */ - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct hdpvr_device *dev = video_drvdata(file); - - strcpy(cap->driver, "hdpvr"); - strcpy(cap->card, "Hauppauge HD PVR"); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = HDPVR_VERSION; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE; - return 0; -} - -static int vidioc_s_std(struct file *file, void *private_data, - v4l2_std_id *std) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - u8 std_type = 1; - - if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60)) - std_type = 0; - - return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); -} - -static const char *iname[] = { - [HDPVR_COMPONENT] = "Component", - [HDPVR_SVIDEO] = "S-Video", - [HDPVR_COMPOSITE] = "Composite", -}; - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - unsigned int n; - - n = i->index; - if (n >= HDPVR_VIDEO_INPUTS) - return -EINVAL; - - i->type = V4L2_INPUT_TYPE_CAMERA; - - strncpy(i->name, iname[n], sizeof(i->name) - 1); - i->name[sizeof(i->name) - 1] = '\0'; - - i->audioset = 1<std = dev->video_dev->tvnorms; - - return 0; -} - -static int vidioc_s_input(struct file *file, void *private_data, - unsigned int index) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int retval; - - if (index >= HDPVR_VIDEO_INPUTS) - return -EINVAL; - - if (dev->status != STATUS_IDLE) - return -EAGAIN; - - retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1); - if (!retval) - dev->options.video_input = index; - - return retval; -} - -static int vidioc_g_input(struct file *file, void *private_data, - unsigned int *index) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - - *index = dev->options.video_input; - return 0; -} - - -static const char *audio_iname[] = { - [HDPVR_RCA_FRONT] = "RCA front", - [HDPVR_RCA_BACK] = "RCA back", - [HDPVR_SPDIF] = "SPDIF", -}; - -static int vidioc_enumaudio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - unsigned int n; - - n = audio->index; - if (n >= HDPVR_AUDIO_INPUTS) - return -EINVAL; - - audio->capability = V4L2_AUDCAP_STEREO; - - strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1); - audio->name[sizeof(audio->name) - 1] = '\0'; - - return 0; -} - -static int vidioc_s_audio(struct file *file, void *private_data, - struct v4l2_audio *audio) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int retval; - - if (audio->index >= HDPVR_AUDIO_INPUTS) - return -EINVAL; - - if (dev->status != STATUS_IDLE) - return -EAGAIN; - - retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec); - if (!retval) - dev->options.audio_input = audio->index; - - return retval; -} - -static int vidioc_g_audio(struct file *file, void *private_data, - struct v4l2_audio *audio) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - - audio->index = dev->options.audio_input; - audio->capability = V4L2_AUDCAP_STEREO; - strncpy(audio->name, audio_iname[audio->index], sizeof(audio->name)); - audio->name[sizeof(audio->name) - 1] = '\0'; - return 0; -} - -static const s32 supported_v4l2_ctrls[] = { - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_SHARPNESS, - V4L2_CID_MPEG_AUDIO_ENCODING, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, - V4L2_CID_MPEG_VIDEO_BITRATE, - V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, -}; - -static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc, - int ac3) -{ - int err; - - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - case V4L2_CID_SHARPNESS: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - case V4L2_CID_MPEG_AUDIO_ENCODING: - return v4l2_ctrl_query_fill( - qc, V4L2_MPEG_AUDIO_ENCODING_AAC, - ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 - : V4L2_MPEG_AUDIO_ENCODING_AAC, - 1, V4L2_MPEG_AUDIO_ENCODING_AAC); - case V4L2_CID_MPEG_VIDEO_ENCODING: - return v4l2_ctrl_query_fill( - qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); - -/* case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */ -/* return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */ - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - return v4l2_ctrl_query_fill( - qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); - - case V4L2_CID_MPEG_VIDEO_BITRATE: - return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000, - 6500000); - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000, - 9000000); - if (!err && opt->bitrate_mode == HDPVR_CONSTANT) - qc->flags |= V4L2_CTRL_FLAG_INACTIVE; - return err; - default: - return -EINVAL; - } -} - -static int vidioc_queryctrl(struct file *file, void *private_data, - struct v4l2_queryctrl *qc) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int i, next; - u32 id = qc->id; - - memset(qc, 0, sizeof(*qc)); - - next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL); - qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL; - - for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) { - if (next) { - if (qc->id < supported_v4l2_ctrls[i]) - qc->id = supported_v4l2_ctrls[i]; - else - continue; - } - - if (qc->id == supported_v4l2_ctrls[i]) - return fill_queryctrl(&dev->options, qc, - dev->flags & HDPVR_FLAG_AC3_CAP); - - if (qc->id < supported_v4l2_ctrls[i]) - break; - } - - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *private_data, - struct v4l2_control *ctrl) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dev->options.brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dev->options.contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = dev->options.saturation; - break; - case V4L2_CID_HUE: - ctrl->value = dev->options.hue; - break; - case V4L2_CID_SHARPNESS: - ctrl->value = dev->options.sharpness; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *private_data, - struct v4l2_control *ctrl) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int retval; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value); - if (!retval) - dev->options.brightness = ctrl->value; - break; - case V4L2_CID_CONTRAST: - retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value); - if (!retval) - dev->options.contrast = ctrl->value; - break; - case V4L2_CID_SATURATION: - retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value); - if (!retval) - dev->options.saturation = ctrl->value; - break; - case V4L2_CID_HUE: - retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value); - if (!retval) - dev->options.hue = ctrl->value; - break; - case V4L2_CID_SHARPNESS: - retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value); - if (!retval) - dev->options.sharpness = ctrl->value; - break; - default: - return -EINVAL; - } - - return retval; -} - - -static int hdpvr_get_ctrl(struct hdpvr_options *opt, - struct v4l2_ext_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_MPEG_AUDIO_ENCODING: - ctrl->value = opt->audio_codec; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC; - break; -/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ -/* ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */ -/* break; */ - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT - ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR - : V4L2_MPEG_VIDEO_BITRATE_MODE_VBR; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - ctrl->value = opt->bitrate * 100000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - ctrl->value = opt->peak_bitrate * 100000; - break; - case V4L2_CID_MPEG_STREAM_TYPE: - ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = hdpvr_get_ctrl(&dev->options, ctrl); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - - } - - return -EINVAL; -} - - -static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3) -{ - int ret = -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_MPEG_AUDIO_ENCODING: - if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC || - (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC) - ret = 0; - break; -/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ -/* if (ctrl->value == 0 || ctrl->value == 128) */ -/* ret = 0; */ -/* break; */ - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR || - ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - { - uint bitrate = ctrl->value / 100000; - if (bitrate >= 10 && bitrate <= 135) - ret = 0; - break; - } - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - { - uint peak_bitrate = ctrl->value / 100000; - if (peak_bitrate >= 10 && peak_bitrate <= 202) - ret = 0; - break; - } - case V4L2_CID_MPEG_STREAM_TYPE: - if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) - ret = 0; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_try_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = hdpvr_try_ctrl(ctrl, - dev->flags & HDPVR_FLAG_AC3_CAP); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - } - - return -EINVAL; -} - - -static int hdpvr_set_ctrl(struct hdpvr_device *dev, - struct v4l2_ext_control *ctrl) -{ - struct hdpvr_options *opt = &dev->options; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_MPEG_AUDIO_ENCODING: - if (dev->flags & HDPVR_FLAG_AC3_CAP) { - opt->audio_codec = ctrl->value; - ret = hdpvr_set_audio(dev, opt->audio_input, - opt->audio_codec); - } - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - break; -/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ -/* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */ -/* opt->gop_mode |= 0x2; */ -/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ -/* opt->gop_mode); */ -/* } */ -/* if (ctrl->value == 128 && opt->gop_mode & 0x2) { */ -/* opt->gop_mode &= ~0x2; */ -/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ -/* opt->gop_mode); */ -/* } */ -/* break; */ - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && - opt->bitrate_mode != HDPVR_CONSTANT) { - opt->bitrate_mode = HDPVR_CONSTANT; - hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, - opt->bitrate_mode); - } - if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && - opt->bitrate_mode == HDPVR_CONSTANT) { - opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE; - hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, - opt->bitrate_mode); - } - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: { - uint bitrate = ctrl->value / 100000; - - opt->bitrate = bitrate; - if (bitrate >= opt->peak_bitrate) - opt->peak_bitrate = bitrate+1; - - hdpvr_set_bitrate(dev); - break; - } - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: { - uint peak_bitrate = ctrl->value / 100000; - - if (opt->bitrate_mode == HDPVR_CONSTANT) - break; - - if (opt->bitrate < peak_bitrate) { - opt->peak_bitrate = peak_bitrate; - hdpvr_set_bitrate(dev); - } else - ret = -EINVAL; - break; - } - case V4L2_CID_MPEG_STREAM_TYPE: - break; - default: - return -EINVAL; - } - return ret; -} - -static int vidioc_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = hdpvr_try_ctrl(ctrl, - dev->flags & HDPVR_FLAG_AC3_CAP); - if (err) { - ctrls->error_idx = i; - break; - } - err = hdpvr_set_ctrl(dev, ctrl); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - - } - - return -EINVAL; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, - struct v4l2_fmtdesc *f) -{ - - if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32); - f->pixelformat = V4L2_PIX_FMT_MPEG; - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data, - struct v4l2_format *f) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - struct hdpvr_video_info *vid_info; - - if (!dev) - return -ENODEV; - - vid_info = get_video_info(dev); - if (!vid_info) - return -EFAULT; - - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.width = vid_info->width; - f->fmt.pix.height = vid_info->height; - f->fmt.pix.sizeimage = dev->bulk_in_size; - f->fmt.pix.colorspace = 0; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.field = V4L2_FIELD_ANY; - - kfree(vid_info); - return 0; -} - -static int vidioc_encoder_cmd(struct file *filp, void *priv, - struct v4l2_encoder_cmd *a) -{ - struct hdpvr_fh *fh = filp->private_data; - struct hdpvr_device *dev = fh->dev; - int res; - - mutex_lock(&dev->io_mutex); - - memset(&a->raw, 0, sizeof(a->raw)); - switch (a->cmd) { - case V4L2_ENC_CMD_START: - a->flags = 0; - res = hdpvr_start_streaming(dev); - break; - case V4L2_ENC_CMD_STOP: - res = hdpvr_stop_streaming(dev); - break; - default: - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "Unsupported encoder cmd %d\n", a->cmd); - res = -EINVAL; - } - mutex_unlock(&dev->io_mutex); - return res; -} - -static int vidioc_try_encoder_cmd(struct file *filp, void *priv, - struct v4l2_encoder_cmd *a) -{ - switch (a->cmd) { - case V4L2_ENC_CMD_START: - case V4L2_ENC_CMD_STOP: - return 0; - default: - return -EINVAL; - } -} - -static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_enumaudio = vidioc_enumaudio, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_encoder_cmd = vidioc_encoder_cmd, - .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, -}; - -static void hdpvr_device_release(struct video_device *vdev) -{ - struct hdpvr_device *dev = video_get_drvdata(vdev); - - hdpvr_delete(dev); - mutex_lock(&dev->io_mutex); - destroy_workqueue(dev->workqueue); - mutex_unlock(&dev->io_mutex); - - v4l2_device_unregister(&dev->v4l2_dev); - - /* deregister I2C adapter */ -#if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE) - mutex_lock(&dev->i2c_mutex); - i2c_del_adapter(&dev->i2c_adapter); - mutex_unlock(&dev->i2c_mutex); -#endif /* CONFIG_I2C */ - - kfree(dev->usbc_buf); - kfree(dev); -} - -static const struct video_device hdpvr_video_template = { -/* .type = VFL_TYPE_GRABBER, */ -/* .type2 = VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */ - .fops = &hdpvr_fops, - .release = hdpvr_device_release, - .ioctl_ops = &hdpvr_ioctl_ops, - .tvnorms = - V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_B | - V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I | - V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N | - V4L2_STD_PAL_60, - .current_norm = V4L2_STD_NTSC | V4L2_STD_PAL_M | - V4L2_STD_PAL_60, -}; - -int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, - int devnum) -{ - /* setup and register video device */ - dev->video_dev = video_device_alloc(); - if (!dev->video_dev) { - v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n"); - goto error; - } - - *(dev->video_dev) = hdpvr_video_template; - strcpy(dev->video_dev->name, "Hauppauge HD PVR"); - dev->video_dev->parent = parent; - video_set_drvdata(dev->video_dev, dev); - - if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) { - v4l2_err(&dev->v4l2_dev, "video_device registration failed\n"); - goto error; - } - - return 0; -error: - return -ENOMEM; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ - -config VIDEO_HDPVR - tristate "Hauppauge HD PVR support" - depends on VIDEO_DEV - ---help--- - This is a video4linux driver for Hauppauge's HD PVR USB device. - - To compile this driver as a module, choose M here: the - module will be called hdpvr - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hdpvr/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o - -obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o - -EXTRA_CFLAGS += -Idrivers/media/video - -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hexium_gemini.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hexium_gemini.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hexium_gemini.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hexium_gemini.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,528 +0,0 @@ -/* - hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards - - Visit http://www.mihu.de/linux/saa7146/ and follow the link - to "hexium" for further details about this card. - - Copyright (C) 2003 Michael Hunold - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#define DEBUG_VARIABLE debug - -#include - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "debug verbosity"); - -/* global variables */ -static int hexium_num; - -#define HEXIUM_GEMINI 4 -#define HEXIUM_GEMINI_DUAL 5 - -#define HEXIUM_INPUTS 9 -static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = { - { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, -}; - -#define HEXIUM_AUDIOS 0 - -struct hexium_data -{ - s8 adr; - u8 byte; -}; - -#define HEXIUM_CONTROLS 1 -static struct v4l2_queryctrl hexium_controls[] = { - { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 }, -}; - -#define HEXIUM_GEMINI_V_1_0 1 -#define HEXIUM_GEMINI_DUAL_V_1_0 2 - -struct hexium -{ - int type; - - struct video_device *video_dev; - struct i2c_adapter i2c_adapter; - - int cur_input; /* current input */ - v4l2_std_id cur_std; /* current standard */ - int cur_bw; /* current black/white status */ -}; - -/* Samsung KS0127B decoder default registers */ -static u8 hexium_ks0127b[0x100]={ -/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10, -/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06, -/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00, -/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22, -/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00, -/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80, -/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00, -/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; - -static struct hexium_data hexium_pal[] = { - { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } -}; - -static struct hexium_data hexium_pal_bw[] = { - { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } -}; - -static struct hexium_data hexium_ntsc[] = { - { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF } -}; - -static struct hexium_data hexium_ntsc_bw[] = { - { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF } -}; - -static struct hexium_data hexium_secam[] = { - { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } -}; - -static struct hexium_data hexium_input_select[] = { - { 0x02, 0x60 }, - { 0x02, 0x64 }, - { 0x02, 0x61 }, - { 0x02, 0x65 }, - { 0x02, 0x62 }, - { 0x02, 0x66 }, - { 0x02, 0x68 }, - { 0x02, 0x69 }, - { 0x02, 0x6A }, -}; - -/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which - are currently *not* supported*/ -static struct saa7146_standard hexium_standards[] = { - { - .name = "PAL", .id = V4L2_STD_PAL, - .v_offset = 28, .v_field = 288, - .h_offset = 1, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 28, .v_field = 240, - .h_offset = 1, .h_pixels = 640, - .v_max_out = 480, .h_max_out = 640, - }, { - .name = "SECAM", .id = V4L2_STD_SECAM, - .v_offset = 28, .v_field = 288, - .h_offset = 1, .h_pixels = 720, - .v_max_out = 576, .h_max_out = 768, - } -}; - -/* bring hardware to a sane state. this has to be done, just in case someone - wants to capture from this device before it has been properly initialized. - the capture engine would badly fail, because no valid signal arrives on the - saa7146, thus leading to timeouts and stuff. */ -static int hexium_init_done(struct saa7146_dev *dev) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - union i2c_smbus_data data; - int i = 0; - - DEB_D(("hexium_init_done called.\n")); - - /* initialize the helper ics to useful values */ - for (i = 0; i < sizeof(hexium_ks0127b); i++) { - data.byte = hexium_ks0127b[i]; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { - printk("hexium_gemini: hexium_init_done() failed for address 0x%02x\n", i); - } - } - - return 0; -} - -static int hexium_set_input(struct hexium *hexium, int input) -{ - union i2c_smbus_data data; - - DEB_D((".\n")); - - data.byte = hexium_input_select[input].byte; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) { - return -1; - } - - return 0; -} - -static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) -{ - union i2c_smbus_data data; - int i = 0; - - DEB_D((".\n")); - - while (vdec[i].adr != -1) { - data.byte = vdec[i].byte; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) { - printk("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", i); - return -1; - } - i++; - } - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - - if (i->index >= HEXIUM_INPUTS) - return -EINVAL; - - memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - - DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - *input = hexium->cur_input; - - DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); - - if (input >= HEXIUM_INPUTS) - return -EINVAL; - - hexium->cur_input = input; - hexium_set_input(hexium, input); - return 0; -} - -/* the saa7146 provides some controls (brightness, contrast, saturation) - which gets registered *after* this function. because of this we have - to return with a value != 0 even if the function succeded.. */ -static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - int i; - - for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { - if (hexium_controls[i].id == qc->id) { - *qc = hexium_controls[i]; - DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); - return 0; - } - } - return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); -} - -static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - int i; - - for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { - if (hexium_controls[i].id == vc->id) - break; - } - - if (i < 0) - return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); - - if (vc->id == V4L2_CID_PRIVATE_BASE) { - vc->value = hexium->cur_bw; - DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - int i = 0; - - for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { - if (hexium_controls[i].id == vc->id) - break; - } - - if (i < 0) - return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); - - if (vc->id == V4L2_CID_PRIVATE_BASE) - hexium->cur_bw = vc->value; - - DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); - - if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { - hexium_set_standard(hexium, hexium_pal); - return 0; - } - if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { - hexium_set_standard(hexium, hexium_ntsc); - return 0; - } - if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { - hexium_set_standard(hexium, hexium_secam); - return 0; - } - if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { - hexium_set_standard(hexium, hexium_pal_bw); - return 0; - } - if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { - hexium_set_standard(hexium, hexium_ntsc_bw); - return 0; - } - if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) - /* fixme: is there no bw secam mode? */ - return -EINVAL; - - return -EINVAL; -} - - -static struct saa7146_ext_vv vv_data; - -/* this function only gets called when the probing was successful */ -static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - int ret; - - DEB_EE((".\n")); - - hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); - if (NULL == hexium) { - printk("hexium_gemini: not enough kernel memory in hexium_attach().\n"); - return -ENOMEM; - } - dev->ext_priv = hexium; - - /* enable i2c-port pins */ - saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); - - hexium->i2c_adapter = (struct i2c_adapter) { - .name = "hexium gemini", - }; - saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); - if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { - DEB_S(("cannot register i2c-device. skipping.\n")); - kfree(hexium); - return -EFAULT; - } - - /* set HWControl GPIO number 2 */ - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - - saa7146_write(dev, DD1_INIT, 0x07000700); - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - /* the rest */ - hexium->cur_input = 0; - hexium_init_done(dev); - - hexium_set_standard(hexium, hexium_pal); - hexium->cur_std = V4L2_STD_PAL; - - hexium_set_input(hexium, 0); - hexium->cur_input = 0; - - saa7146_vv_init(dev, &vv_data); - vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; - vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; - vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; - vv_data.ops.vidioc_enum_input = vidioc_enum_input; - vv_data.ops.vidioc_g_input = vidioc_g_input; - vv_data.ops.vidioc_s_input = vidioc_s_input; - ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER); - if (ret < 0) { - printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n"); - return ret; - } - - printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num); - hexium_num++; - - return 0; -} - -static int hexium_detach(struct saa7146_dev *dev) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - DEB_EE(("dev:%p\n", dev)); - - saa7146_unregister_device(&hexium->video_dev, dev); - saa7146_vv_release(dev); - - hexium_num--; - - i2c_del_adapter(&hexium->i2c_adapter); - kfree(hexium); - return 0; -} - -static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - if (V4L2_STD_PAL == std->id) { - hexium_set_standard(hexium, hexium_pal); - hexium->cur_std = V4L2_STD_PAL; - return 0; - } else if (V4L2_STD_NTSC == std->id) { - hexium_set_standard(hexium, hexium_ntsc); - hexium->cur_std = V4L2_STD_NTSC; - return 0; - } else if (V4L2_STD_SECAM == std->id) { - hexium_set_standard(hexium, hexium_secam); - hexium->cur_std = V4L2_STD_SECAM; - return 0; - } - - return -1; -} - -static struct saa7146_extension hexium_extension; - -static struct saa7146_pci_extension_data hexium_gemini_4bnc = { - .ext_priv = "Hexium Gemini (4 BNC)", - .ext = &hexium_extension, -}; - -static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = { - .ext_priv = "Hexium Gemini Dual (4 BNC)", - .ext = &hexium_extension, -}; - -static struct pci_device_id pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2401, - .driver_data = (unsigned long) &hexium_gemini_4bnc, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2402, - .driver_data = (unsigned long) &hexium_gemini_dual_4bnc, - }, - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_ext_vv vv_data = { - .inputs = HEXIUM_INPUTS, - .capabilities = 0, - .stds = &hexium_standards[0], - .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), - .std_callback = &std_callback, -}; - -static struct saa7146_extension hexium_extension = { - .name = "hexium gemini", - .flags = SAA7146_USE_I2C_IRQ, - - .pci_tbl = &pci_tbl[0], - .module = THIS_MODULE, - - .attach = hexium_attach, - .detach = hexium_detach, - - .irq_mask = 0, - .irq_func = NULL, -}; - -static int __init hexium_init_module(void) -{ - if (0 != saa7146_register_extension(&hexium_extension)) { - DEB_S(("failed to register extension.\n")); - return -ENODEV; - } - - return 0; -} - -static void __exit hexium_cleanup_module(void) -{ - saa7146_unregister_extension(&hexium_extension); -} - -module_init(hexium_init_module); -module_exit(hexium_cleanup_module); - -MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards"); -MODULE_AUTHOR("Michael Hunold "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hexium_orion.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hexium_orion.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hexium_orion.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/hexium_orion.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,499 +0,0 @@ -/* - hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards - - Visit http://www.mihu.de/linux/saa7146/ and follow the link - to "hexium" for further details about this card. - - Copyright (C) 2003 Michael Hunold - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#define DEBUG_VARIABLE debug - -#include - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "debug verbosity"); - -/* global variables */ -static int hexium_num; - -#define HEXIUM_HV_PCI6_ORION 1 -#define HEXIUM_ORION_1SVHS_3BNC 2 -#define HEXIUM_ORION_4BNC 3 - -#define HEXIUM_INPUTS 9 -static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = { - { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, -}; - -#define HEXIUM_AUDIOS 0 - -struct hexium_data -{ - s8 adr; - u8 byte; -}; - -struct hexium -{ - int type; - struct video_device *video_dev; - struct i2c_adapter i2c_adapter; - - int cur_input; /* current input */ -}; - -/* Philips SAA7110 decoder default registers */ -static u8 hexium_saa7110[53]={ -/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00, -/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90, -/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA, -/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00, -/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F, -/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03, -/*30*/ 0x44,0x75,0x01,0x8C,0x03 -}; - -static struct { - struct hexium_data data[8]; -} hexium_input_select[] = { -{ - { /* cvbs 1 */ - { 0x06, 0x00 }, - { 0x20, 0xD9 }, - { 0x21, 0x17 }, // 0x16, - { 0x22, 0x40 }, - { 0x2C, 0x03 }, - { 0x30, 0x44 }, - { 0x31, 0x75 }, // ?? - { 0x21, 0x16 }, // 0x03, - } -}, { - { /* cvbs 2 */ - { 0x06, 0x00 }, - { 0x20, 0x78 }, - { 0x21, 0x07 }, // 0x03, - { 0x22, 0xD2 }, - { 0x2C, 0x83 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, // ? - { 0x21, 0x03 }, - } -}, { - { /* cvbs 3 */ - { 0x06, 0x00 }, - { 0x20, 0xBA }, - { 0x21, 0x07 }, // 0x05, - { 0x22, 0x91 }, - { 0x2C, 0x03 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, // ?? - { 0x21, 0x05 }, // 0x03, - } -}, { - { /* cvbs 4 */ - { 0x06, 0x00 }, - { 0x20, 0xD8 }, - { 0x21, 0x17 }, // 0x16, - { 0x22, 0x40 }, - { 0x2C, 0x03 }, - { 0x30, 0x44 }, - { 0x31, 0x75 }, // ?? - { 0x21, 0x16 }, // 0x03, - } -}, { - { /* cvbs 5 */ - { 0x06, 0x00 }, - { 0x20, 0xB8 }, - { 0x21, 0x07 }, // 0x05, - { 0x22, 0x91 }, - { 0x2C, 0x03 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, // ?? - { 0x21, 0x05 }, // 0x03, - } -}, { - { /* cvbs 6 */ - { 0x06, 0x00 }, - { 0x20, 0x7C }, - { 0x21, 0x07 }, // 0x03 - { 0x22, 0xD2 }, - { 0x2C, 0x83 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, // ?? - { 0x21, 0x03 }, - } -}, { - { /* y/c 1 */ - { 0x06, 0x80 }, - { 0x20, 0x59 }, - { 0x21, 0x17 }, - { 0x22, 0x42 }, - { 0x2C, 0xA3 }, - { 0x30, 0x44 }, - { 0x31, 0x75 }, - { 0x21, 0x12 }, - } -}, { - { /* y/c 2 */ - { 0x06, 0x80 }, - { 0x20, 0x9A }, - { 0x21, 0x17 }, - { 0x22, 0xB1 }, - { 0x2C, 0x13 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, - { 0x21, 0x14 }, - } -}, { - { /* y/c 3 */ - { 0x06, 0x80 }, - { 0x20, 0x3C }, - { 0x21, 0x27 }, - { 0x22, 0xC1 }, - { 0x2C, 0x23 }, - { 0x30, 0x44 }, - { 0x31, 0x75 }, - { 0x21, 0x21 }, - } -} -}; - -static struct saa7146_standard hexium_standards[] = { - { - .name = "PAL", .id = V4L2_STD_PAL, - .v_offset = 16, .v_field = 288, - .h_offset = 1, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 16, .v_field = 240, - .h_offset = 1, .h_pixels = 640, - .v_max_out = 480, .h_max_out = 640, - }, { - .name = "SECAM", .id = V4L2_STD_SECAM, - .v_offset = 16, .v_field = 288, - .h_offset = 1, .h_pixels = 720, - .v_max_out = 576, .h_max_out = 768, - } -}; - -/* this is only called for old HV-PCI6/Orion cards - without eeprom */ -static int hexium_probe(struct saa7146_dev *dev) -{ - struct hexium *hexium = NULL; - union i2c_smbus_data data; - int err = 0; - - DEB_EE((".\n")); - - /* there are no hexium orion cards with revision 0 saa7146s */ - if (0 == dev->revision) { - return -EFAULT; - } - - hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); - if (NULL == hexium) { - printk("hexium_orion: hexium_probe: not enough kernel memory.\n"); - return -ENOMEM; - } - - /* enable i2c-port pins */ - saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); - - saa7146_write(dev, DD1_INIT, 0x01000100); - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - hexium->i2c_adapter = (struct i2c_adapter) { - .name = "hexium orion", - }; - saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); - if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { - DEB_S(("cannot register i2c-device. skipping.\n")); - kfree(hexium); - return -EFAULT; - } - - /* set SAA7110 control GPIO 0 */ - saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI); - /* set HWControl GPIO number 2 */ - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - - mdelay(10); - - /* detect newer Hexium Orion cards by subsystem ids */ - if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) { - printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n"); - /* we store the pointer in our private data field */ - dev->ext_priv = hexium; - hexium->type = HEXIUM_ORION_1SVHS_3BNC; - return 0; - } - - if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) { - printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n"); - /* we store the pointer in our private data field */ - dev->ext_priv = hexium; - hexium->type = HEXIUM_ORION_4BNC; - return 0; - } - - /* check if this is an old hexium Orion card by looking at - a saa7110 at address 0x4e */ - if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) { - printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n"); - /* we store the pointer in our private data field */ - dev->ext_priv = hexium; - hexium->type = HEXIUM_HV_PCI6_ORION; - return 0; - } - - i2c_del_adapter(&hexium->i2c_adapter); - kfree(hexium); - return -EFAULT; -} - -/* bring hardware to a sane state. this has to be done, just in case someone - wants to capture from this device before it has been properly initialized. - the capture engine would badly fail, because no valid signal arrives on the - saa7146, thus leading to timeouts and stuff. */ -static int hexium_init_done(struct saa7146_dev *dev) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - union i2c_smbus_data data; - int i = 0; - - DEB_D(("hexium_init_done called.\n")); - - /* initialize the helper ics to useful values */ - for (i = 0; i < sizeof(hexium_saa7110); i++) { - data.byte = hexium_saa7110[i]; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { - printk("hexium_orion: failed for address 0x%02x\n", i); - } - } - - return 0; -} - -static int hexium_set_input(struct hexium *hexium, int input) -{ - union i2c_smbus_data data; - int i = 0; - - DEB_D((".\n")); - - for (i = 0; i < 8; i++) { - int adr = hexium_input_select[input].data[i].adr; - data.byte = hexium_input_select[input].data[i].byte; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) { - return -1; - } - printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte); - } - - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - - if (i->index >= HEXIUM_INPUTS) - return -EINVAL; - - memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - - DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - *input = hexium->cur_input; - - DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - if (input >= HEXIUM_INPUTS) - return -EINVAL; - - hexium->cur_input = input; - hexium_set_input(hexium, input); - - return 0; -} - -static struct saa7146_ext_vv vv_data; - -/* this function only gets called when the probing was successful */ -static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - DEB_EE((".\n")); - - saa7146_vv_init(dev, &vv_data); - vv_data.ops.vidioc_enum_input = vidioc_enum_input; - vv_data.ops.vidioc_g_input = vidioc_g_input; - vv_data.ops.vidioc_s_input = vidioc_s_input; - if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { - printk("hexium_orion: cannot register capture v4l2 device. skipping.\n"); - return -1; - } - - printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num); - hexium_num++; - - /* the rest */ - hexium->cur_input = 0; - hexium_init_done(dev); - - return 0; -} - -static int hexium_detach(struct saa7146_dev *dev) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - DEB_EE(("dev:%p\n", dev)); - - saa7146_unregister_device(&hexium->video_dev, dev); - saa7146_vv_release(dev); - - hexium_num--; - - i2c_del_adapter(&hexium->i2c_adapter); - kfree(hexium); - return 0; -} - -static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) -{ - return 0; -} - -static struct saa7146_extension extension; - -static struct saa7146_pci_extension_data hexium_hv_pci6 = { - .ext_priv = "Hexium HV-PCI6 / Orion", - .ext = &extension, -}; - -static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = { - .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)", - .ext = &extension, -}; - -static struct saa7146_pci_extension_data hexium_orion_4bnc = { - .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)", - .ext = &extension, -}; - -static struct pci_device_id pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x0000, - .subdevice = 0x0000, - .driver_data = (unsigned long) &hexium_hv_pci6, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x0101, - .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2101, - .driver_data = (unsigned long) &hexium_orion_4bnc, - }, - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_ext_vv vv_data = { - .inputs = HEXIUM_INPUTS, - .capabilities = 0, - .stds = &hexium_standards[0], - .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), - .std_callback = &std_callback, -}; - -static struct saa7146_extension extension = { - .name = "hexium HV-PCI6 Orion", - .flags = 0, // SAA7146_USE_I2C_IRQ, - - .pci_tbl = &pci_tbl[0], - .module = THIS_MODULE, - - .probe = hexium_probe, - .attach = hexium_attach, - .detach = hexium_detach, - - .irq_mask = 0, - .irq_func = NULL, -}; - -static int __init hexium_init_module(void) -{ - if (0 != saa7146_register_extension(&extension)) { - DEB_S(("failed to register extension.\n")); - return -ENODEV; - } - - return 0; -} - -static void __exit hexium_cleanup_module(void) -{ - saa7146_unregister_extension(&extension); -} - -module_init(hexium_init_module); -module_exit(hexium_cleanup_module); - -MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards"); -MODULE_AUTHOR("Michael Hunold "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ibmmpeg2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ibmmpeg2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ibmmpeg2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ibmmpeg2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -/* ibmmpeg2.h - IBM MPEGCD21 definitions */ - -#ifndef __IBM_MPEG2__ -#define __IBM_MPEG2__ - -/* Define all MPEG Decoder registers */ -/* Chip Control and Status */ -#define IBM_MP2_CHIP_CONTROL 0x200*2 -#define IBM_MP2_CHIP_MODE 0x201*2 -/* Timer Control and Status */ -#define IBM_MP2_SYNC_STC2 0x202*2 -#define IBM_MP2_SYNC_STC1 0x203*2 -#define IBM_MP2_SYNC_STC0 0x204*2 -#define IBM_MP2_SYNC_PTS2 0x205*2 -#define IBM_MP2_SYNC_PTS1 0x206*2 -#define IBM_MP2_SYNC_PTS0 0x207*2 -/* Video FIFO Control */ -#define IBM_MP2_FIFO 0x208*2 -#define IBM_MP2_FIFOW 0x100*2 -#define IBM_MP2_FIFO_STAT 0x209*2 -#define IBM_MP2_RB_THRESHOLD 0x22b*2 -/* Command buffer */ -#define IBM_MP2_COMMAND 0x20a*2 -#define IBM_MP2_CMD_DATA 0x20b*2 -#define IBM_MP2_CMD_STAT 0x20c*2 -#define IBM_MP2_CMD_ADDR 0x20d*2 -/* Internal Processor Control and Status */ -#define IBM_MP2_PROC_IADDR 0x20e*2 -#define IBM_MP2_PROC_IDATA 0x20f*2 -#define IBM_MP2_WR_PROT 0x235*2 -/* DRAM Access */ -#define IBM_MP2_DRAM_ADDR 0x210*2 -#define IBM_MP2_DRAM_DATA 0x212*2 -#define IBM_MP2_DRAM_CMD_STAT 0x213*2 -#define IBM_MP2_BLOCK_SIZE 0x23b*2 -#define IBM_MP2_SRC_ADDR 0x23c*2 -/* Onscreen Display */ -#define IBM_MP2_OSD_ADDR 0x214*2 -#define IBM_MP2_OSD_DATA 0x215*2 -#define IBM_MP2_OSD_MODE 0x217*2 -#define IBM_MP2_OSD_LINK_ADDR 0x229*2 -#define IBM_MP2_OSD_SIZE 0x22a*2 -/* Interrupt Control */ -#define IBM_MP2_HOST_INT 0x218*2 -#define IBM_MP2_MASK0 0x219*2 -#define IBM_MP2_HOST_INT1 0x23e*2 -#define IBM_MP2_MASK1 0x23f*2 -/* Audio Control */ -#define IBM_MP2_AUD_IADDR 0x21a*2 -#define IBM_MP2_AUD_IDATA 0x21b*2 -#define IBM_MP2_AUD_FIFO 0x21c*2 -#define IBM_MP2_AUD_FIFOW 0x101*2 -#define IBM_MP2_AUD_CTL 0x21d*2 -#define IBM_MP2_BEEP_CTL 0x21e*2 -#define IBM_MP2_FRNT_ATTEN 0x22d*2 -/* Display Control */ -#define IBM_MP2_DISP_MODE 0x220*2 -#define IBM_MP2_DISP_DLY 0x221*2 -#define IBM_MP2_VBI_CTL 0x222*2 -#define IBM_MP2_DISP_LBOR 0x223*2 -#define IBM_MP2_DISP_TBOR 0x224*2 -/* Polarity Control */ -#define IBM_MP2_INFC_CTL 0x22c*2 - -/* control commands */ -#define IBM_MP2_PLAY 0 -#define IBM_MP2_PAUSE 1 -#define IBM_MP2_SINGLE_FRAME 2 -#define IBM_MP2_FAST_FORWARD 3 -#define IBM_MP2_SLOW_MOTION 4 -#define IBM_MP2_IMED_NORM_PLAY 5 -#define IBM_MP2_RESET_WINDOW 6 -#define IBM_MP2_FREEZE_FRAME 7 -#define IBM_MP2_RESET_VID_RATE 8 -#define IBM_MP2_CONFIG_DECODER 9 -#define IBM_MP2_CHANNEL_SWITCH 10 -#define IBM_MP2_RESET_AUD_RATE 11 -#define IBM_MP2_PRE_OP_CHN_SW 12 -#define IBM_MP2_SET_STILL_MODE 14 - -/* Define Xilinx FPGA Internal Registers */ - -/* general control register 0 */ -#define XILINX_CTL0 0x600 -/* genlock delay resister 1 */ -#define XILINX_GLDELAY 0x602 -/* send 16 bits to CS3310 port */ -#define XILINX_CS3310 0x604 -/* send 16 bits to CS3310 and complete */ -#define XILINX_CS3310_CMPLT 0x60c -/* pulse width modulator control */ -#define XILINX_PWM 0x606 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/imx074.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/imx074.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/imx074.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/imx074.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,505 +0,0 @@ -/* - * Driver for IMX074 CMOS Image Sensor from Sony - * - * Copyright (C) 2010, Guennadi Liakhovetski - * - * Partially inspired by the IMX074 driver from the Android / MSM tree - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -/* IMX074 registers */ - -#define MODE_SELECT 0x0100 -#define IMAGE_ORIENTATION 0x0101 -#define GROUPED_PARAMETER_HOLD 0x0104 - -/* Integration Time */ -#define COARSE_INTEGRATION_TIME_HI 0x0202 -#define COARSE_INTEGRATION_TIME_LO 0x0203 -/* Gain */ -#define ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204 -#define ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205 - -/* PLL registers */ -#define PRE_PLL_CLK_DIV 0x0305 -#define PLL_MULTIPLIER 0x0307 -#define PLSTATIM 0x302b -#define VNDMY_ABLMGSHLMT 0x300a -#define Y_OPBADDR_START_DI 0x3014 -/* mode setting */ -#define FRAME_LENGTH_LINES_HI 0x0340 -#define FRAME_LENGTH_LINES_LO 0x0341 -#define LINE_LENGTH_PCK_HI 0x0342 -#define LINE_LENGTH_PCK_LO 0x0343 -#define YADDR_START 0x0347 -#define YADDR_END 0x034b -#define X_OUTPUT_SIZE_MSB 0x034c -#define X_OUTPUT_SIZE_LSB 0x034d -#define Y_OUTPUT_SIZE_MSB 0x034e -#define Y_OUTPUT_SIZE_LSB 0x034f -#define X_EVEN_INC 0x0381 -#define X_ODD_INC 0x0383 -#define Y_EVEN_INC 0x0385 -#define Y_ODD_INC 0x0387 - -#define HMODEADD 0x3001 -#define VMODEADD 0x3016 -#define VAPPLINE_START 0x3069 -#define VAPPLINE_END 0x306b -#define SHUTTER 0x3086 -#define HADDAVE 0x30e8 -#define LANESEL 0x3301 - -/* IMX074 supported geometry */ -#define IMX074_WIDTH 1052 -#define IMX074_HEIGHT 780 - -/* IMX074 has only one fixed colorspace per pixelcode */ -struct imx074_datafmt { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; -}; - -struct imx074 { - struct v4l2_subdev subdev; - const struct imx074_datafmt *fmt; -}; - -static const struct imx074_datafmt imx074_colour_fmts[] = { - {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, -}; - -static struct imx074 *to_imx074(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct imx074, subdev); -} - -/* Find a data format by a pixel code in an array */ -static const struct imx074_datafmt *imx074_find_datafmt(enum v4l2_mbus_pixelcode code) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(imx074_colour_fmts); i++) - if (imx074_colour_fmts[i].code == code) - return imx074_colour_fmts + i; - - return NULL; -} - -static int reg_write(struct i2c_client *client, const u16 addr, const u8 data) -{ - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - unsigned char tx[3]; - int ret; - - msg.addr = client->addr; - msg.buf = tx; - msg.len = 3; - msg.flags = 0; - - tx[0] = addr >> 8; - tx[1] = addr & 0xff; - tx[2] = data; - - ret = i2c_transfer(adap, &msg, 1); - - mdelay(2); - - return ret == 1 ? 0 : -EIO; -} - -static int reg_read(struct i2c_client *client, const u16 addr) -{ - u8 buf[2] = {addr >> 8, addr & 0xff}; - int ret; - struct i2c_msg msgs[] = { - { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = buf, - }, { - .addr = client->addr, - .flags = I2C_M_RD, - .len = 2, - .buf = buf, - }, - }; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) { - dev_warn(&client->dev, "Reading register %x from %x failed\n", - addr, client->addr); - return ret; - } - - return buf[0] & 0xff; /* no sign-extension */ -} - -static int imx074_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code); - - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); - - if (!fmt) { - mf->code = imx074_colour_fmts[0].code; - mf->colorspace = imx074_colour_fmts[0].colorspace; - } - - mf->width = IMX074_WIDTH; - mf->height = IMX074_HEIGHT; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int imx074_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx074 *priv = to_imx074(client); - - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); - - /* MIPI CSI could have changed the format, double-check */ - if (!imx074_find_datafmt(mf->code)) - return -EINVAL; - - imx074_try_fmt(sd, mf); - - priv->fmt = imx074_find_datafmt(mf->code); - - return 0; -} - -static int imx074_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx074 *priv = to_imx074(client); - - const struct imx074_datafmt *fmt = priv->fmt; - - mf->code = fmt->code; - mf->colorspace = fmt->colorspace; - mf->width = IMX074_WIDTH; - mf->height = IMX074_HEIGHT; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int imx074_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct v4l2_rect *rect = &a->c; - - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - rect->top = 0; - rect->left = 0; - rect->width = IMX074_WIDTH; - rect->height = IMX074_HEIGHT; - - return 0; -} - -static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = IMX074_WIDTH; - a->bounds.height = IMX074_HEIGHT; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts)) - return -EINVAL; - - *code = imx074_colour_fmts[index].code; - return 0; -} - -static int imx074_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* MODE_SELECT: stream or standby */ - return reg_write(client, MODE_SELECT, !!enable); -} - -static int imx074_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) - return -EINVAL; - - if (id->match.addr != client->addr) - return -ENODEV; - - id->ident = V4L2_IDENT_IMX074; - id->revision = 0; - - return 0; -} - -static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { - .s_stream = imx074_s_stream, - .s_mbus_fmt = imx074_s_fmt, - .g_mbus_fmt = imx074_g_fmt, - .try_mbus_fmt = imx074_try_fmt, - .enum_mbus_fmt = imx074_enum_fmt, - .g_crop = imx074_g_crop, - .cropcap = imx074_cropcap, -}; - -static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { - .g_chip_ident = imx074_g_chip_ident, -}; - -static struct v4l2_subdev_ops imx074_subdev_ops = { - .core = &imx074_subdev_core_ops, - .video = &imx074_subdev_video_ops, -}; - -/* - * We have to provide soc-camera operations, but we don't have anything to say - * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param - */ -static unsigned long imx074_query_bus_param(struct soc_camera_device *icd) -{ - return 0; -} - -static int imx074_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return -1; -} - -static struct soc_camera_ops imx074_ops = { - .query_bus_param = imx074_query_bus_param, - .set_bus_param = imx074_set_bus_param, -}; - -static int imx074_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - int ret; - u16 id; - - /* Read sensor Model ID */ - ret = reg_read(client, 0); - if (ret < 0) - return ret; - - id = ret << 8; - - ret = reg_read(client, 1); - if (ret < 0) - return ret; - - id |= ret; - - dev_info(&client->dev, "Chip ID 0x%04x detected\n", id); - - if (id != 0x74) - return -ENODEV; - - /* PLL Setting EXTCLK=24MHz, 22.5times */ - reg_write(client, PLL_MULTIPLIER, 0x2D); - reg_write(client, PRE_PLL_CLK_DIV, 0x02); - reg_write(client, PLSTATIM, 0x4B); - - /* 2-lane mode */ - reg_write(client, 0x3024, 0x00); - - reg_write(client, IMAGE_ORIENTATION, 0x00); - - /* select RAW mode: - * 0x08+0x08 = top 8 bits - * 0x0a+0x08 = compressed 8-bits - * 0x0a+0x0a = 10 bits - */ - reg_write(client, 0x0112, 0x08); - reg_write(client, 0x0113, 0x08); - - /* Base setting for High frame mode */ - reg_write(client, VNDMY_ABLMGSHLMT, 0x80); - reg_write(client, Y_OPBADDR_START_DI, 0x08); - reg_write(client, 0x3015, 0x37); - reg_write(client, 0x301C, 0x01); - reg_write(client, 0x302C, 0x05); - reg_write(client, 0x3031, 0x26); - reg_write(client, 0x3041, 0x60); - reg_write(client, 0x3051, 0x24); - reg_write(client, 0x3053, 0x34); - reg_write(client, 0x3057, 0xC0); - reg_write(client, 0x305C, 0x09); - reg_write(client, 0x305D, 0x07); - reg_write(client, 0x3060, 0x30); - reg_write(client, 0x3065, 0x00); - reg_write(client, 0x30AA, 0x08); - reg_write(client, 0x30AB, 0x1C); - reg_write(client, 0x30B0, 0x32); - reg_write(client, 0x30B2, 0x83); - reg_write(client, 0x30D3, 0x04); - reg_write(client, 0x3106, 0x78); - reg_write(client, 0x310C, 0x82); - reg_write(client, 0x3304, 0x05); - reg_write(client, 0x3305, 0x04); - reg_write(client, 0x3306, 0x11); - reg_write(client, 0x3307, 0x02); - reg_write(client, 0x3308, 0x0C); - reg_write(client, 0x3309, 0x06); - reg_write(client, 0x330A, 0x08); - reg_write(client, 0x330B, 0x04); - reg_write(client, 0x330C, 0x08); - reg_write(client, 0x330D, 0x06); - reg_write(client, 0x330E, 0x01); - reg_write(client, 0x3381, 0x00); - - /* V : 1/2V-addition (1,3), H : 1/2H-averaging (1,3) -> Full HD */ - /* 1608 = 1560 + 48 (black lines) */ - reg_write(client, FRAME_LENGTH_LINES_HI, 0x06); - reg_write(client, FRAME_LENGTH_LINES_LO, 0x48); - reg_write(client, YADDR_START, 0x00); - reg_write(client, YADDR_END, 0x2F); - /* 0x838 == 2104 */ - reg_write(client, X_OUTPUT_SIZE_MSB, 0x08); - reg_write(client, X_OUTPUT_SIZE_LSB, 0x38); - /* 0x618 == 1560 */ - reg_write(client, Y_OUTPUT_SIZE_MSB, 0x06); - reg_write(client, Y_OUTPUT_SIZE_LSB, 0x18); - reg_write(client, X_EVEN_INC, 0x01); - reg_write(client, X_ODD_INC, 0x03); - reg_write(client, Y_EVEN_INC, 0x01); - reg_write(client, Y_ODD_INC, 0x03); - reg_write(client, HMODEADD, 0x00); - reg_write(client, VMODEADD, 0x16); - reg_write(client, VAPPLINE_START, 0x24); - reg_write(client, VAPPLINE_END, 0x53); - reg_write(client, SHUTTER, 0x00); - reg_write(client, HADDAVE, 0x80); - - reg_write(client, LANESEL, 0x00); - - reg_write(client, GROUPED_PARAMETER_HOLD, 0x00); /* off */ - - return 0; -} - -static int imx074_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct imx074 *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "IMX074: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "IMX074: missing platform data!\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); - return -EIO; - } - - priv = kzalloc(sizeof(struct imx074), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); - - icd->ops = &imx074_ops; - priv->fmt = &imx074_colour_fmts[0]; - - ret = imx074_video_probe(icd, client); - if (ret < 0) { - icd->ops = NULL; - kfree(priv); - return ret; - } - - return ret; -} - -static int imx074_remove(struct i2c_client *client) -{ - struct imx074 *priv = to_imx074(client); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); - - icd->ops = NULL; - if (icl->free_bus) - icl->free_bus(icl); - kfree(priv); - - return 0; -} - -static const struct i2c_device_id imx074_id[] = { - { "imx074", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, imx074_id); - -static struct i2c_driver imx074_i2c_driver = { - .driver = { - .name = "imx074", - }, - .probe = imx074_probe, - .remove = imx074_remove, - .id_table = imx074_id, -}; - -static int __init imx074_mod_init(void) -{ - return i2c_add_driver(&imx074_i2c_driver); -} - -static void __exit imx074_mod_exit(void) -{ - i2c_del_driver(&imx074_i2c_driver); -} - -module_init(imx074_mod_init); -module_exit(imx074_mod_exit); - -MODULE_DESCRIPTION("Sony IMX074 Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/indycam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/indycam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/indycam.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/indycam.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,400 +0,0 @@ -/* - * indycam.c - Silicon Graphics IndyCam digital camera driver - * - * Copyright (C) 2003 Ladislav Michl - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* IndyCam decodes stream of photons into digital image representation ;-) */ -#include -#include -#include -#include - -#include "indycam.h" - -#define INDYCAM_MODULE_VERSION "0.0.5" - -MODULE_DESCRIPTION("SGI IndyCam driver"); -MODULE_AUTHOR("Mikael Nousiainen "); -MODULE_LICENSE("GPL"); - - -// #define INDYCAM_DEBUG - -#ifdef INDYCAM_DEBUG -#define dprintk(x...) printk("IndyCam: " x); -#define indycam_regdump(client) indycam_regdump_debug(client) -#else -#define dprintk(x...) -#define indycam_regdump(client) -#endif - -struct indycam { - struct v4l2_subdev sd; - u8 version; -}; - -static inline struct indycam *to_indycam(struct v4l2_subdev *sd) -{ - return container_of(sd, struct indycam, sd); -} - -static const u8 initseq[] = { - INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */ - INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */ - INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */ - 0x00, /* INDYCAM_BRIGHTNESS (read-only) */ - INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */ - INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */ - INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */ - INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */ -}; - -/* IndyCam register handling */ - -static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (reg == INDYCAM_REG_RESET) { - dprintk("indycam_read_reg(): " - "skipping write-only register %d\n", reg); - *value = 0; - return 0; - } - - ret = i2c_smbus_read_byte_data(client, reg); - - if (ret < 0) { - printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, " - "register = 0x%02x\n", reg); - return ret; - } - - *value = (u8)ret; - - return 0; -} - -static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int err; - - if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) { - dprintk("indycam_write_reg(): " - "skipping read-only register %d\n", reg); - return 0; - } - - dprintk("Writing Reg %d = 0x%02x\n", reg, value); - err = i2c_smbus_write_byte_data(client, reg, value); - - if (err) { - printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, " - "register = 0x%02x, value = 0x%02x\n", reg, value); - } - return err; -} - -static int indycam_write_block(struct v4l2_subdev *sd, u8 reg, - u8 length, u8 *data) -{ - int i, err; - - for (i = 0; i < length; i++) { - err = indycam_write_reg(sd, reg + i, data[i]); - if (err) - return err; - } - - return 0; -} - -/* Helper functions */ - -#ifdef INDYCAM_DEBUG -static void indycam_regdump_debug(struct v4l2_subdev *sd) -{ - int i; - u8 val; - - for (i = 0; i < 9; i++) { - indycam_read_reg(sd, i, &val); - dprintk("Reg %d = 0x%02x\n", i, val); - } -} -#endif - -static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct indycam *camera = to_indycam(sd); - u8 reg; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, ®); - if (ret) - return -EIO; - if (ctrl->id == V4L2_CID_AUTOGAIN) - ctrl->value = (reg & INDYCAM_CONTROL_AGCENA) - ? 1 : 0; - else - ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL) - ? 1 : 0; - break; - case V4L2_CID_EXPOSURE: - ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, ®); - if (ret) - return -EIO; - ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1); - break; - case V4L2_CID_GAIN: - ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case V4L2_CID_RED_BALANCE: - ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case V4L2_CID_BLUE_BALANCE: - ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case INDYCAM_CONTROL_RED_SATURATION: - ret = indycam_read_reg(sd, - INDYCAM_REG_RED_SATURATION, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case INDYCAM_CONTROL_BLUE_SATURATION: - ret = indycam_read_reg(sd, - INDYCAM_REG_BLUE_SATURATION, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case V4L2_CID_GAMMA: - if (camera->version == CAMERA_VERSION_MOOSE) { - ret = indycam_read_reg(sd, - INDYCAM_REG_GAMMA, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - } else { - ctrl->value = INDYCAM_GAMMA_DEFAULT; - } - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct indycam *camera = to_indycam(sd); - u8 reg; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, ®); - if (ret) - break; - - if (ctrl->id == V4L2_CID_AUTOGAIN) { - if (ctrl->value) - reg |= INDYCAM_CONTROL_AGCENA; - else - reg &= ~INDYCAM_CONTROL_AGCENA; - } else { - if (ctrl->value) - reg |= INDYCAM_CONTROL_AWBCTL; - else - reg &= ~INDYCAM_CONTROL_AWBCTL; - } - - ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg); - break; - case V4L2_CID_EXPOSURE: - reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1); - ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg); - break; - case V4L2_CID_GAIN: - ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value); - break; - case V4L2_CID_RED_BALANCE: - ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE, - ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE, - ctrl->value); - break; - case INDYCAM_CONTROL_RED_SATURATION: - ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION, - ctrl->value); - break; - case INDYCAM_CONTROL_BLUE_SATURATION: - ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION, - ctrl->value); - break; - case V4L2_CID_GAMMA: - if (camera->version == CAMERA_VERSION_MOOSE) { - ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA, - ctrl->value); - } - break; - default: - ret = -EINVAL; - } - - return ret; -} - -/* I2C-interface */ - -static int indycam_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct indycam *camera = to_indycam(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM, - camera->version); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops indycam_core_ops = { - .g_chip_ident = indycam_g_chip_ident, - .g_ctrl = indycam_g_ctrl, - .s_ctrl = indycam_s_ctrl, -}; - -static const struct v4l2_subdev_ops indycam_ops = { - .core = &indycam_core_ops, -}; - -static int indycam_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int err = 0; - struct indycam *camera; - struct v4l2_subdev *sd; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - camera = kzalloc(sizeof(struct indycam), GFP_KERNEL); - if (!camera) - return -ENOMEM; - - sd = &camera->sd; - v4l2_i2c_subdev_init(sd, client, &indycam_ops); - - camera->version = i2c_smbus_read_byte_data(client, - INDYCAM_REG_VERSION); - if (camera->version != CAMERA_VERSION_INDY && - camera->version != CAMERA_VERSION_MOOSE) { - kfree(camera); - return -ENODEV; - } - - printk(KERN_INFO "IndyCam v%d.%d detected\n", - INDYCAM_VERSION_MAJOR(camera->version), - INDYCAM_VERSION_MINOR(camera->version)); - - indycam_regdump(sd); - - // initialize - err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq); - if (err) { - printk(KERN_ERR "IndyCam initialization failed\n"); - kfree(camera); - return -EIO; - } - - indycam_regdump(sd); - - // white balance - err = indycam_write_reg(sd, INDYCAM_REG_CONTROL, - INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL); - if (err) { - printk(KERN_ERR "IndyCam: White balancing camera failed\n"); - kfree(camera); - return -EIO; - } - - indycam_regdump(sd); - - printk(KERN_INFO "IndyCam initialized\n"); - - return 0; -} - -static int indycam_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_indycam(sd)); - return 0; -} - -static const struct i2c_device_id indycam_id[] = { - { "indycam", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, indycam_id); - -static struct i2c_driver indycam_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "indycam", - }, - .probe = indycam_probe, - .remove = indycam_remove, - .id_table = indycam_id, -}; - -static __init int init_indycam(void) -{ - return i2c_add_driver(&indycam_driver); -} - -static __exit void exit_indycam(void) -{ - i2c_del_driver(&indycam_driver); -} - -module_init(init_indycam); -module_exit(exit_indycam); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/indycam.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/indycam.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/indycam.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/indycam.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/* - * indycam.h - Silicon Graphics IndyCam digital camera driver - * - * Copyright (C) 2003 Ladislav Michl - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _INDYCAM_H_ -#define _INDYCAM_H_ - -/* I2C address for the Guinness Camera */ -#define INDYCAM_ADDR 0x56 - -/* Camera version */ -#define CAMERA_VERSION_INDY 0x10 /* v1.0 */ -#define CAMERA_VERSION_MOOSE 0x12 /* v1.2 */ -#define INDYCAM_VERSION_MAJOR(x) (((x) & 0xf0) >> 4) -#define INDYCAM_VERSION_MINOR(x) ((x) & 0x0f) - -/* Register bus addresses */ -#define INDYCAM_REG_CONTROL 0x00 -#define INDYCAM_REG_SHUTTER 0x01 -#define INDYCAM_REG_GAIN 0x02 -#define INDYCAM_REG_BRIGHTNESS 0x03 /* read-only */ -#define INDYCAM_REG_RED_BALANCE 0x04 -#define INDYCAM_REG_BLUE_BALANCE 0x05 -#define INDYCAM_REG_RED_SATURATION 0x06 -#define INDYCAM_REG_BLUE_SATURATION 0x07 -#define INDYCAM_REG_GAMMA 0x08 -#define INDYCAM_REG_VERSION 0x0e /* read-only */ -#define INDYCAM_REG_RESET 0x0f /* write-only */ - -#define INDYCAM_REG_LED 0x46 -#define INDYCAM_REG_ORIENTATION 0x47 -#define INDYCAM_REG_BUTTON 0x48 - -/* Field definitions of registers */ -#define INDYCAM_CONTROL_AGCENA (1<<0) /* automatic gain control */ -#define INDYCAM_CONTROL_AWBCTL (1<<1) /* automatic white balance */ - /* 2-3 are reserved */ -#define INDYCAM_CONTROL_EVNFLD (1<<4) /* read-only */ - -#define INDYCAM_SHUTTER_10000 0x02 /* 1/10000 second */ -#define INDYCAM_SHUTTER_4000 0x04 /* 1/4000 second */ -#define INDYCAM_SHUTTER_2000 0x08 /* 1/2000 second */ -#define INDYCAM_SHUTTER_1000 0x10 /* 1/1000 second */ -#define INDYCAM_SHUTTER_500 0x20 /* 1/500 second */ -#define INDYCAM_SHUTTER_250 0x3f /* 1/250 second */ -#define INDYCAM_SHUTTER_125 0x7e /* 1/125 second */ -#define INDYCAM_SHUTTER_100 0x9e /* 1/100 second */ -#define INDYCAM_SHUTTER_60 0x00 /* 1/60 second */ - -#define INDYCAM_LED_ACTIVE 0x10 -#define INDYCAM_LED_INACTIVE 0x30 -#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP 0x40 -#define INDYCAM_BUTTON_RELEASED 0x10 - -/* Values for controls */ -#define INDYCAM_SHUTTER_MIN 0x00 -#define INDYCAM_SHUTTER_MAX 0xff -#define INDYCAM_GAIN_MIN 0x00 -#define INDYCAM_GAIN_MAX 0xff -#define INDYCAM_RED_BALANCE_MIN 0x00 -#define INDYCAM_RED_BALANCE_MAX 0xff -#define INDYCAM_BLUE_BALANCE_MIN 0x00 -#define INDYCAM_BLUE_BALANCE_MAX 0xff -#define INDYCAM_RED_SATURATION_MIN 0x00 -#define INDYCAM_RED_SATURATION_MAX 0xff -#define INDYCAM_BLUE_SATURATION_MIN 0x00 -#define INDYCAM_BLUE_SATURATION_MAX 0xff -#define INDYCAM_GAMMA_MIN 0x00 -#define INDYCAM_GAMMA_MAX 0xff - -#define INDYCAM_AGC_DEFAULT 1 -#define INDYCAM_AWB_DEFAULT 0 -#define INDYCAM_SHUTTER_DEFAULT 0xff -#define INDYCAM_GAIN_DEFAULT 0x80 -#define INDYCAM_RED_BALANCE_DEFAULT 0x18 -#define INDYCAM_BLUE_BALANCE_DEFAULT 0xa4 -#define INDYCAM_RED_SATURATION_DEFAULT 0x80 -#define INDYCAM_BLUE_SATURATION_DEFAULT 0xc0 -#define INDYCAM_GAMMA_DEFAULT 0x80 - -/* Driver interface definitions */ - -#define INDYCAM_CONTROL_RED_SATURATION (V4L2_CID_PRIVATE_BASE + 0) -#define INDYCAM_CONTROL_BLUE_SATURATION (V4L2_CID_PRIVATE_BASE + 1) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ir-kbd-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ir-kbd-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ir-kbd-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ir-kbd-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,499 +0,0 @@ -/* - * - * keyboard input driver for i2c IR remote controls - * - * Copyright (c) 2000-2003 Gerd Knorr - * modified for PixelView (BT878P+W/FM) by - * Michal Kochanowicz - * Christoph Bartelmus - * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by - * Ulrich Mueller - * modified for em2820 based USB TV tuners by - * Markus Rechberger - * modified for DViCO Fusion HDTV 5 RT GOLD by - * Chaogui Zhang - * modified for MSI TV@nywhere Plus by - * Henry Wong - * Mark Schultz - * Brian Rogers - * modified for AVerMedia Cardbus by - * Oldrich Jedlicka - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* ----------------------------------------------------------------------- */ -/* insmod parameters */ - -static int debug; -module_param(debug, int, 0644); /* debug level (0,1,2) */ - - -#define MODULE_NAME "ir-kbd-i2c" -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG MODULE_NAME ": " fmt , ## arg) - -/* ----------------------------------------------------------------------- */ - -static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, - int size, int offset) -{ - unsigned char buf[6]; - int start, range, toggle, dev, code, ircode; - - /* poll IR chip */ - if (size != i2c_master_recv(ir->c, buf, size)) - return -EIO; - - /* split rc5 data block ... */ - start = (buf[offset] >> 7) & 1; - range = (buf[offset] >> 6) & 1; - toggle = (buf[offset] >> 5) & 1; - dev = buf[offset] & 0x1f; - code = (buf[offset+1] >> 2) & 0x3f; - - /* rc5 has two start bits - * the first bit must be one - * the second bit defines the command range (1 = 0-63, 0 = 64 - 127) - */ - if (!start) - /* no key pressed */ - return 0; - /* - * Hauppauge remotes (black/silver) always use - * specific device ids. If we do not filter the - * device ids then messages destined for devices - * such as TVs (id=0) will get through causing - * mis-fired events. - * - * We also filter out invalid key presses which - * produce annoying debug log entries. - */ - ircode= (start << 12) | (toggle << 11) | (dev << 6) | code; - if ((ircode & 0x1fff)==0x1fff) - /* invalid key press */ - return 0; - - if (!range) - code += 64; - - dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", - start, range, toggle, dev, code); - - /* return key */ - *ir_key = (dev << 8) | code; - *ir_raw = ircode; - return 1; -} - -static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - return get_key_haup_common (ir, ir_key, ir_raw, 3, 0); -} - -static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - int ret; - unsigned char buf[1] = { 0 }; - - /* - * This is the same apparent "are you ready?" poll command observed - * watching Windows driver traffic and implemented in lirc_zilog. With - * this added, we get far saner remote behavior with z8 chips on usb - * connected devices, even with the default polling interval of 100ms. - */ - ret = i2c_master_send(ir->c, buf, 1); - if (ret != 1) - return (ret < 0) ? ret : -EINVAL; - - return get_key_haup_common (ir, ir_key, ir_raw, 6, 3); -} - -static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char b; - - /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk(1,"read error\n"); - return -EIO; - } - *ir_key = b; - *ir_raw = b; - return 1; -} - -static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char buf[4]; - - /* poll IR chip */ - if (4 != i2c_master_recv(ir->c, buf, 4)) { - dprintk(1,"read error\n"); - return -EIO; - } - - if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) - dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__, - buf[0], buf[1], buf[2], buf[3]); - - /* no key pressed or signal from other ir remote */ - if(buf[0] != 0x1 || buf[1] != 0xfe) - return 0; - - *ir_key = buf[2]; - *ir_raw = (buf[2] << 8) | buf[3]; - - return 1; -} - -static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char b; - - /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk(1,"read error\n"); - return -EIO; - } - - /* it seems that 0xFE indicates that a button is still hold - down, while 0xff indicates that no button is hold - down. 0xfe sequences are sometimes interrupted by 0xFF */ - - dprintk(2,"key %02x\n", b); - - if (b == 0xff) - return 0; - - if (b == 0xfe) - /* keep old data */ - return 1; - - *ir_key = b; - *ir_raw = b; - return 1; -} - -static int get_key_avermedia_cardbus(struct IR_i2c *ir, - u32 *ir_key, u32 *ir_raw) -{ - unsigned char subaddr, key, keygroup; - struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, - .buf = &subaddr, .len = 1}, - { .addr = ir->c->addr, .flags = I2C_M_RD, - .buf = &key, .len = 1} }; - subaddr = 0x0d; - if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { - dprintk(1, "read error\n"); - return -EIO; - } - - if (key == 0xff) - return 0; - - subaddr = 0x0b; - msg[1].buf = &keygroup; - if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { - dprintk(1, "read error\n"); - return -EIO; - } - - if (keygroup == 0xff) - return 0; - - dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup); - if (keygroup < 2 || keygroup > 3) { - /* Only a warning */ - dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n", - keygroup, key); - } - key |= (keygroup & 1) << 6; - - *ir_key = key; - *ir_raw = key; - return 1; -} - -/* ----------------------------------------------------------------------- */ - -static void ir_key_poll(struct IR_i2c *ir) -{ - static u32 ir_key, ir_raw; - int rc; - - dprintk(3, "%s\n", __func__); - rc = ir->get_key(ir, &ir_key, &ir_raw); - if (rc < 0) { - dprintk(2,"error\n"); - return; - } - - if (rc) { - dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key); - rc_keydown(ir->rc, ir_key, 0); - } -} - -static void ir_work(struct work_struct *work) -{ - struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); - - ir_key_poll(ir); - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); -} - -/* ----------------------------------------------------------------------- */ - -static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - char *ir_codes = NULL; - const char *name = NULL; - u64 rc_type = RC_TYPE_UNKNOWN; - struct IR_i2c *ir; - struct rc_dev *rc = NULL; - struct i2c_adapter *adap = client->adapter; - unsigned short addr = client->addr; - int err; - - ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL); - if (!ir) - return -ENOMEM; - - ir->c = client; - ir->polling_interval = DEFAULT_POLLING_INTERVAL; - i2c_set_clientdata(client, ir); - - switch(addr) { - case 0x64: - name = "Pixelview"; - ir->get_key = get_key_pixelview; - rc_type = RC_TYPE_OTHER; - ir_codes = RC_MAP_EMPTY; - break; - case 0x18: - case 0x1f: - case 0x1a: - name = "Hauppauge"; - ir->get_key = get_key_haup; - rc_type = RC_TYPE_RC5; - ir_codes = RC_MAP_HAUPPAUGE; - break; - case 0x30: - name = "KNC One"; - ir->get_key = get_key_knc1; - rc_type = RC_TYPE_OTHER; - ir_codes = RC_MAP_EMPTY; - break; - case 0x6b: - name = "FusionHDTV"; - ir->get_key = get_key_fusionhdtv; - rc_type = RC_TYPE_RC5; - ir_codes = RC_MAP_FUSIONHDTV_MCE; - break; - case 0x40: - name = "AVerMedia Cardbus remote"; - ir->get_key = get_key_avermedia_cardbus; - rc_type = RC_TYPE_OTHER; - ir_codes = RC_MAP_AVERMEDIA_CARDBUS; - break; - case 0x71: - name = "Hauppauge/Zilog Z8"; - ir->get_key = get_key_haup_xvr; - rc_type = RC_TYPE_RC5; - ir_codes = RC_MAP_HAUPPAUGE; - break; - } - - /* Let the caller override settings */ - if (client->dev.platform_data) { - const struct IR_i2c_init_data *init_data = - client->dev.platform_data; - - ir_codes = init_data->ir_codes; - rc = init_data->rc_dev; - - name = init_data->name; - if (init_data->type) - rc_type = init_data->type; - - if (init_data->polling_interval) - ir->polling_interval = init_data->polling_interval; - - switch (init_data->internal_get_key_func) { - case IR_KBD_GET_KEY_CUSTOM: - /* The bridge driver provided us its own function */ - ir->get_key = init_data->get_key; - break; - case IR_KBD_GET_KEY_PIXELVIEW: - ir->get_key = get_key_pixelview; - break; - case IR_KBD_GET_KEY_HAUP: - ir->get_key = get_key_haup; - break; - case IR_KBD_GET_KEY_KNC1: - ir->get_key = get_key_knc1; - break; - case IR_KBD_GET_KEY_FUSIONHDTV: - ir->get_key = get_key_fusionhdtv; - break; - case IR_KBD_GET_KEY_HAUP_XVR: - ir->get_key = get_key_haup_xvr; - break; - case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS: - ir->get_key = get_key_avermedia_cardbus; - break; - } - } - - if (!rc) { - /* - * If platform_data doesn't specify rc_dev, initilize it - * internally - */ - rc = rc_allocate_device(); - if (!rc) { - err = -ENOMEM; - goto err_out_free; - } - } - ir->rc = rc; - - /* Make sure we are all setup before going on */ - if (!name || !ir->get_key || !rc_type || !ir_codes) { - dprintk(1, ": Unsupported device at address 0x%02x\n", - addr); - err = -ENODEV; - goto err_out_free; - } - - /* Sets name */ - snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name); - ir->ir_codes = ir_codes; - - snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", - dev_name(&adap->dev), - dev_name(&client->dev)); - - /* - * Initialize input_dev fields - * It doesn't make sense to allow overriding them via platform_data - */ - rc->input_id.bustype = BUS_I2C; - rc->input_phys = ir->phys; - rc->input_name = ir->name; - - /* - * Initialize the other fields of rc_dev - */ - rc->map_name = ir->ir_codes; - rc->allowed_protos = rc_type; - if (!rc->driver_name) - rc->driver_name = MODULE_NAME; - - err = rc_register_device(rc); - if (err) - goto err_out_free; - - printk(MODULE_NAME ": %s detected at %s [%s]\n", - ir->name, ir->phys, adap->name); - - /* start polling via eventd */ - INIT_DELAYED_WORK(&ir->work, ir_work); - schedule_delayed_work(&ir->work, 0); - - return 0; - - err_out_free: - /* Only frees rc if it were allocated internally */ - rc_free_device(rc); - kfree(ir); - return err; -} - -static int ir_remove(struct i2c_client *client) -{ - struct IR_i2c *ir = i2c_get_clientdata(client); - - /* kill outstanding polls */ - cancel_delayed_work_sync(&ir->work); - - /* unregister device */ - rc_unregister_device(ir->rc); - - /* free memory */ - kfree(ir); - return 0; -} - -static const struct i2c_device_id ir_kbd_id[] = { - /* Generic entry for any IR receiver */ - { "ir_video", 0 }, - /* IR device specific entries should be added here */ - { "ir_rx_z8f0811_haup", 0 }, - { "ir_rx_z8f0811_hdpvr", 0 }, - { } -}; - -static struct i2c_driver driver = { - .driver = { - .name = "ir-kbd-i2c", - }, - .probe = ir_probe, - .remove = ir_remove, - .id_table = ir_kbd_id, -}; - -/* ----------------------------------------------------------------------- */ - -MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); -MODULE_DESCRIPTION("input driver for i2c IR remote controls"); -MODULE_LICENSE("GPL"); - -static int __init ir_init(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit ir_fini(void) -{ - i2c_del_driver(&driver); -} - -module_init(ir_init); -module_exit(ir_fini); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-cards.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1370 +0,0 @@ -/* - Functions to query card hardware - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-cards.h" -#include "ivtv-i2c.h" - -#include -#include -#include -#include -#include -#include - -#define MSP_TUNER MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ - MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER) -#define MSP_SCART1 MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) -#define MSP_SCART2 MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, \ - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) -#define MSP_SCART3 MSP_INPUT(MSP_IN_SCART3, MSP_IN_TUNER1, \ - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) -#define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) - -#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM) - -/* usual i2c tuner addresses to probe */ -static struct ivtv_card_tuner_i2c ivtv_i2c_std = { - .radio = { I2C_CLIENT_END }, - .demod = { 0x43, I2C_CLIENT_END }, - .tv = { 0x61, 0x60, I2C_CLIENT_END }, -}; - -/* as above, but with possible radio tuner */ -static struct ivtv_card_tuner_i2c ivtv_i2c_radio = { - .radio = { 0x60, I2C_CLIENT_END }, - .demod = { 0x43, I2C_CLIENT_END }, - .tv = { 0x61, I2C_CLIENT_END }, -}; - -/* using the tda8290+75a combo */ -static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = { - .radio = { I2C_CLIENT_END }, - .demod = { I2C_CLIENT_END }, - .tv = { 0x4b, I2C_CLIENT_END }, -}; - -/********************** card configuration *******************************/ - -/* Please add new PCI IDs to: http://pci-ids.ucw.cz/ - This keeps the PCI ID database up to date. Note that the entries - must be added under vendor 0x4444 (Conexant) as subsystem IDs. - New vendor IDs should still be added to the vendor ID list. */ - -/* Hauppauge PVR-250 cards */ - -/* Note: for Hauppauge cards the tveeprom information is used instead of PCI IDs */ -static const struct ivtv_card ivtv_card_pvr250 = { - .type = IVTV_CARD_PVR_250, - .name = "Hauppauge WinTV PVR-250", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | - IVTV_HW_TVEEPROM | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, - { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, - { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Hauppauge PVR-350 cards */ - -/* Outputs for Hauppauge PVR350 cards */ -static struct ivtv_card_output ivtv_pvr350_outputs[] = { - { - .name = "S-Video + Composite", - .video_output = 0, - }, { - .name = "Composite", - .video_output = 1, - }, { - .name = "S-Video", - .video_output = 2, - }, { - .name = "RGB", - .video_output = 3, - }, { - .name = "YUV C", - .video_output = 4, - }, { - .name = "YUV V", - .video_output = 5, - } -}; - -static const struct ivtv_card ivtv_card_pvr350 = { - .type = IVTV_CARD_PVR_350, - .name = "Hauppauge WinTV PVR-350", - .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, - .video_outputs = ivtv_pvr350_outputs, - .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | - IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER | - IVTV_HW_I2C_IR_RX_HAUP_EXT | IVTV_HW_I2C_IR_RX_HAUP_INT, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, - { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, - { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, - .i2c = &ivtv_i2c_std, -}; - -/* PVR-350 V1 boards have a different audio tuner input and use a - saa7114 instead of a saa7115. - Note that the info below comes from a pre-production model so it may - not be correct. Especially the audio behaves strangely (mono only it seems) */ -static const struct ivtv_card ivtv_card_pvr350_v1 = { - .type = IVTV_CARD_PVR_350_V1, - .name = "Hauppauge WinTV PVR-350 (V1)", - .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, - .video_outputs = ivtv_pvr350_outputs, - .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), - .hw_video = IVTV_HW_SAA7114, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7114 | - IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, - { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, MSP_MONO }, - { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, - { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Hauppauge PVR-150/PVR-500 cards */ - -static const struct ivtv_card ivtv_card_pvr150 = { - .type = IVTV_CARD_PVR_150, - .name = "Hauppauge WinTV PVR-150", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_muxer = IVTV_HW_WM8775, - .hw_all = IVTV_HW_WM8775 | IVTV_HW_CX25840 | - IVTV_HW_TVEEPROM | IVTV_HW_TUNER | - IVTV_HW_I2C_IR_RX_HAUP_EXT | IVTV_HW_I2C_IR_RX_HAUP_INT | - IVTV_HW_Z8F0811_IR_HAUP, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE7 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, - { IVTV_CARD_INPUT_SVIDEO2, 2, CX25840_SVIDEO2 }, - { IVTV_CARD_INPUT_COMPOSITE2, 2, CX25840_COMPOSITE4 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, - CX25840_AUDIO8, WM8775_AIN2 }, - { IVTV_CARD_INPUT_LINE_IN1, - CX25840_AUDIO_SERIAL, WM8775_AIN2 }, - { IVTV_CARD_INPUT_LINE_IN2, - CX25840_AUDIO_SERIAL, WM8775_AIN3 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, - CX25840_AUDIO_SERIAL, WM8775_AIN4 }, - /* apparently needed for the IR blaster */ - .gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 }, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* AVerMedia M179 cards */ - -static const struct ivtv_card_pci_info ivtv_pci_m179[] = { - { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3cf }, - { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3ce }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_m179 = { - .type = IVTV_CARD_M179, - .name = "AVerMedia M179", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7114, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0xe380, .initial_value = 0x8290 }, - .gpio_audio_input = { .mask = 0x8040, .tuner = 0x8000, .linein = 0x0000 }, - .gpio_audio_mute = { .mask = 0x2000, .mute = 0x2000 }, - .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, - .lang1 = 0x0200, .lang2 = 0x0100, .both = 0x0000 }, - .gpio_audio_freq = { .mask = 0x0018, .f32000 = 0x0000, - .f44100 = 0x0008, .f48000 = 0x0010 }, - .gpio_audio_detect = { .mask = 0x4000, .stereo = 0x0000 }, - .tuners = { - /* As far as we know all M179 cards use this tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC }, - }, - .pci_list = ivtv_pci_m179, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPG600/Kuroutoshikou ITVC16-STVLP cards */ - -static const struct ivtv_card_pci_info ivtv_pci_mpg600[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xfff3 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xffff }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_mpg600 = { - .type = IVTV_CARD_MPG600, - .name = "Yuan MPG600, Kuroutoshikou ITVC16-STVLP", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0x3080, .initial_value = 0x0004 }, - .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, - .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, - .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, - .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, - .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, - .tuners = { - /* The PAL tuner is confirmed */ - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_mpg600, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPG160/Kuroutoshikou ITVC15-STVLP cards */ - -static const struct ivtv_card_pci_info ivtv_pci_mpg160[] = { - { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_YUAN1, 0 }, - { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_IODATA, 0x40a0 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_mpg160 = { - .type = IVTV_CARD_MPG160, - .name = "YUAN MPG160, Kuroutoshikou ITVC15-STVLP, I/O Data GV-M2TV/PCI", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7114, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0x7080, .initial_value = 0x400c }, - .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, - .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, - .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, - .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, - .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, - .tuners = { - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_mpg160, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan PG600/Diamond PVR-550 cards */ - -static const struct ivtv_card_pci_info ivtv_pci_pg600[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_DIAMONDMM, 0x0070 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_pg600 = { - .type = IVTV_CARD_PG600, - .name = "Yuan PG600, Diamond PVR-550", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, - }, - .tuners = { - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_pg600, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Adaptec VideOh! AVC-2410 card */ - -static const struct ivtv_card_pci_info ivtv_pci_avc2410[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0093 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_avc2410 = { - .type = IVTV_CARD_AVC2410, - .name = "Adaptec VideOh! AVC-2410", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_muxer = IVTV_HW_CS53L32A, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_CS53L32A | - IVTV_HW_SAA7115 | IVTV_HW_TUNER | - IVTV_HW_I2C_IR_RX_ADAPTEC, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, - MSP_TUNER, CS53L32A_IN0 }, - { IVTV_CARD_INPUT_LINE_IN1, - MSP_SCART1, CS53L32A_IN2 }, - }, - /* This card has no eeprom and in fact the Windows driver relies - on the country/region setting of the user to decide which tuner - is available. */ - .tuners = { - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - { .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP, - .tuner = TUNER_PHILIPS_FM1236_MK3 }, - { .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_avc2410, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Adaptec VideOh! AVC-2010 card */ - -static const struct ivtv_card_pci_info ivtv_pci_avc2010[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0092 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_avc2010 = { - .type = IVTV_CARD_AVC2010, - .name = "Adaptec VideOh! AVC-2010", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_CS53L32A, - .hw_audio_ctrl = IVTV_HW_CS53L32A, - .hw_all = IVTV_HW_CS53L32A | IVTV_HW_SAA7115, - .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_LINE_IN1, CS53L32A_IN2 }, - }, - /* Does not have a tuner */ - .pci_list = ivtv_pci_avc2010, -}; - -/* ------------------------------------------------------------------------- */ - -/* Nagase Transgear 5000TV card */ - -static const struct ivtv_card_pci_info ivtv_pci_tg5000tv[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_tg5000tv = { - .type = IVTV_CARD_TG5000TV, - .name = "Nagase Transgear 5000TV", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7114 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | - IVTV_HW_GPIO, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gr_config = UPD64031A_VERTICAL_EXTERNAL, - .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, - .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, - .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, - .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, - .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, - .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, - .composite = 0x0010, .svideo = 0x0020 }, - .tuners = { - { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_tg5000tv, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* AOpen VA2000MAX-SNT6 card */ - -static const struct ivtv_card_pci_info ivtv_pci_va2000[] = { - { PCI_DEVICE_ID_IVTV16, 0, 0xff5f }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_va2000 = { - .type = IVTV_CARD_VA2000MAX_SNT6, - .name = "AOpen VA2000MAX-SNT6", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD6408X, - .hw_audio = IVTV_HW_MSP34XX, - .hw_audio_ctrl = IVTV_HW_MSP34XX, - .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | - IVTV_HW_UPD6408X | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, - }, - .tuners = { - { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_va2000, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPG600GR/Kuroutoshikou CX23416GYC-STVLP cards */ - -static const struct ivtv_card_pci_info ivtv_pci_cx23416gyc[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN4, 0x0600 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x0523 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_cx23416gyc = { - .type = IVTV_CARD_CX23416GYC, - .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .hw_audio = IVTV_HW_SAA717X, - .hw_audio_ctrl = IVTV_HW_SAA717X, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO3 | - IVTV_SAA717X_TUNER_FLAG }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, - }, - .gr_config = UPD64031A_VERTICAL_EXTERNAL, - .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, - .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, - .composite = 0x0020, .svideo = 0x0020 }, - .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, - .f44100 = 0x4000, .f48000 = 0x8000 }, - .tuners = { - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, - }, - .pci_list = ivtv_pci_cx23416gyc, - .i2c = &ivtv_i2c_std, -}; - -static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { - .type = IVTV_CARD_CX23416GYC_NOGR, - .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR)", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | IVTV_HW_UPD6408X, - .hw_audio = IVTV_HW_SAA717X, - .hw_audio_ctrl = IVTV_HW_SAA717X, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | - IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | - IVTV_SAA717X_TUNER_FLAG }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, - }, - .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, - .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, - .composite = 0x0020, .svideo = 0x0020 }, - .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, - .f44100 = 0x4000, .f48000 = 0x8000 }, - .tuners = { - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, - }, - .i2c = &ivtv_i2c_std, -}; - -static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { - .type = IVTV_CARD_CX23416GYC_NOGRYCS, - .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR/YCS)", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO, - .hw_audio = IVTV_HW_SAA717X, - .hw_audio_ctrl = IVTV_HW_SAA717X, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | - IVTV_SAA717X_TUNER_FLAG }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, - }, - .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, - .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, - .composite = 0x0020, .svideo = 0x0020 }, - .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, - .f44100 = 0x4000, .f48000 = 0x8000 }, - .tuners = { - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, - }, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* I/O Data GV-MVP/RX & GV-MVP/RX2W (dual tuner) cards */ - -static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd01e }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd038 }, /* 2W unit #1 */ - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd039 }, /* 2W unit #2 */ - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_gv_mvprx = { - .type = IVTV_CARD_GV_MVPRX, - .name = "I/O Data GV-MVP/RX, GV-MVP/RX2W (dual tuner)", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_WM8739, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX | - IVTV_HW_TUNER | IVTV_HW_WM8739 | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO1 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, - .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, - .tuners = { - /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, - }, - .pci_list = ivtv_pci_gv_mvprx, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* I/O Data GV-MVP/RX2E card */ - -static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx2e[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd025 }, - {0, 0, 0} -}; - -static const struct ivtv_card ivtv_card_gv_mvprx2e = { - .type = IVTV_CARD_GV_MVPRX2E, - .name = "I/O Data GV-MVP/RX2E", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_WM8739, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | - IVTV_HW_VP27SMPX | IVTV_HW_WM8739, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, - .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, - .tuners = { - /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, - }, - .pci_list = ivtv_pci_gv_mvprx2e, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* GotVIEW PCI DVD card */ - -static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_gotview_pci_dvd = { - .type = IVTV_CARD_GOTVIEW_PCI_DVD, - .name = "GotView PCI DVD", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA717X, - .hw_audio = IVTV_HW_SAA717X, - .hw_audio_ctrl = IVTV_HW_SAA717X, - .hw_all = IVTV_HW_SAA717X | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE1 }, /* pin 116 */ - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, /* pin 114/109 */ - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, /* pin 118 */ - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN0 }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN2 }, - }, - .gpio_init = { .direction = 0xf000, .initial_value = 0xA000 }, - .tuners = { - /* This card has a Philips FQ1216ME MK3 tuner */ - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - }, - .pci_list = ivtv_pci_gotview_pci_dvd, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* GotVIEW PCI DVD2 Deluxe card */ - -static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd2[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW1, 0x0600 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { - .type = IVTV_CARD_GOTVIEW_PCI_DVD2, - .name = "GotView PCI DVD2 Deluxe", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_muxer = IVTV_HW_GPIO, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, - .gpio_init = { .direction = 0x0800, .initial_value = 0 }, - .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, - .tuners = { - /* This card has a Philips FQ1216ME MK5 tuner */ - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - }, - .pci_list = ivtv_pci_gotview_pci_dvd2, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPC622 miniPCI card */ - -static const struct ivtv_card_pci_info ivtv_pci_yuan_mpc622[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN2, 0xd998 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_yuan_mpc622 = { - .type = IVTV_CARD_YUAN_MPC622, - .name = "Yuan MPC622", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, - }, - .gpio_init = { .direction = 0x00ff, .initial_value = 0x0002 }, - .tuners = { - /* This card has the TDA8290/TDA8275 tuner chips */ - { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 }, - }, - .pci_list = ivtv_pci_yuan_mpc622, - .i2c = &ivtv_i2c_tda8290, -}; - -/* ------------------------------------------------------------------------- */ - -/* DIGITAL COWBOY DCT-MTVP1 card */ - -static const struct ivtv_card_pci_info ivtv_pci_dctmvtvp1[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_dctmvtvp1 = { - .type = IVTV_CARD_DCTMTVP1, - .name = "Digital Cowboy DCT-MTVP1", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | - IVTV_HW_GPIO, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | - IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, - .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, - .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, - .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, - .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, - .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, - .composite = 0x0010, .svideo = 0x0020}, - .tuners = { - { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, - }, - .pci_list = ivtv_pci_dctmvtvp1, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan PG600-2/GotView PCI DVD Lite cards */ - -static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW2, 0x0600 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_pg600v2 = { - .type = IVTV_CARD_PG600V2, - .name = "Yuan PG600-2, GotView PCI DVD Lite", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - /* XC2028 support apparently works for the Yuan, it's still - uncertain whether it also works with the GotView. */ - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - .xceive_pin = 12, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .pci_list = ivtv_pci_pg600v2, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Club3D ZAP-TV1x01 cards */ - -static const struct ivtv_card_pci_info ivtv_pci_club3d[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_club3d = { - .type = IVTV_CARD_CLUB3D, - .name = "Club3D ZAP-TV1x01", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - .xceive_pin = 12, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .pci_list = ivtv_pci_club3d, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* AVerTV MCE 116 Plus (M116) card */ - -static const struct ivtv_card_pci_info ivtv_pci_avertv_mce116[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc439 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_avertv_mce116 = { - .type = IVTV_CARD_AVERTV_MCE116, - .name = "AVerTV MCE 116 Plus", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739 | - IVTV_HW_I2C_IR_RX_AVER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - /* enable line-in */ - .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, - .xceive_pin = 10, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .pci_list = ivtv_pci_avertv_mce116, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* AVerMedia PVR-150 Plus / AVerTV M113 cards with a Daewoo/Partsnic Tuner */ - -static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc034 }, /* NTSC */ - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, /* NTSC FM */ - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_aver_pvr150 = { - .type = IVTV_CARD_AVER_PVR150PLUS, - .name = "AVerMedia PVR-150 Plus / AVerTV M113 Partsnic (Daewoo) Tuner", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_muxer = IVTV_HW_GPIO, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | - IVTV_HW_WM8739 | IVTV_HW_GPIO, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, - /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */ - .gpio_init = { .direction = 0xc000, .initial_value = 0 }, - .gpio_audio_input = { .mask = 0xc000, - .tuner = 0x0000, - .linein = 0x4000, - .radio = 0x8000 }, - .tuners = { - /* Subsystem ID's 0xc03[45] have a Partsnic PTI-5NF05 tuner */ - { .std = V4L2_STD_MN, .tuner = TUNER_PARTSNIC_PTI_5NF05 }, - }, - .pci_list = ivtv_pci_aver_pvr150, - /* Subsystem ID 0xc035 has a TEA5767(?) FM tuner, 0xc034 does not */ - .i2c = &ivtv_i2c_radio, -}; - -/* ------------------------------------------------------------------------- */ - -/* AVerMedia UltraTV 1500 MCE (newer non-cx88 version, M113 variant) card */ - -static const struct ivtv_card_pci_info ivtv_pci_aver_ultra1500mce[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc019 }, /* NTSC */ - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc01b }, /* PAL/SECAM */ - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_aver_ultra1500mce = { - .type = IVTV_CARD_AVER_ULTRA1500MCE, - .name = "AVerMedia UltraTV 1500 MCE / AVerTV M113 Philips Tuner", - .comment = "For non-NTSC tuners, use the pal= or secam= module options", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_muxer = IVTV_HW_GPIO, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | - IVTV_HW_WM8739 | IVTV_HW_GPIO, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, - /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */ - .gpio_init = { .direction = 0xc000, .initial_value = 0 }, - .gpio_audio_input = { .mask = 0xc000, - .tuner = 0x0000, - .linein = 0x4000, - .radio = 0x8000 }, - .tuners = { - /* The UltraTV 1500 MCE has a Philips FM1236 MK5 TV/FM tuner */ - { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 }, - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216MK5 }, - }, - .pci_list = ivtv_pci_aver_ultra1500mce, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* AVerMedia EZMaker PCI Deluxe card */ - -static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_aver_ezmaker = { - .type = IVTV_CARD_AVER_EZMAKER, - .name = "AVerMedia EZMaker PCI Deluxe", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, - .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 0 }, - }, - .gpio_init = { .direction = 0x4000, .initial_value = 0x4000 }, - /* Does not have a tuner */ - .pci_list = ivtv_pci_aver_ezmaker, -}; - -/* ------------------------------------------------------------------------- */ - -/* ASUS Falcon2 */ - -static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_asus_falcon2 = { - .type = IVTV_CARD_ASUS_FALCON2, - .name = "ASUS Falcon2", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_muxer = IVTV_HW_M52790, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, - M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, - .tuners = { - { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 }, - }, - .pci_list = ivtv_pci_asus_falcon2, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* AVerMedia M104 miniPCI card */ - -static const struct ivtv_card_pci_info ivtv_pci_aver_m104[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc136 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_aver_m104 = { - .type = IVTV_CARD_AVER_M104, - .name = "AVerMedia M104", - .comment = "Not yet supported!\n", - .v4l2_capabilities = 0, /*IVTV_CAP_ENCODER,*/ - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, - .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, - /* enable line-in + reset tuner */ - .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, - .xceive_pin = 10, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .pci_list = ivtv_pci_aver_m104, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Buffalo PC-MV5L/PCI cards */ - -static const struct ivtv_card_pci_info ivtv_pci_buffalo[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x052b }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_buffalo = { - .type = IVTV_CARD_BUFFALO_MV5L, - .name = "Buffalo PC-MV5L/PCI", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, - }, - .xceive_pin = 12, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .pci_list = ivtv_pci_buffalo, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ -/* Sony Kikyou */ - -static const struct ivtv_card_pci_info ivtv_pci_kikyou[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_SONY, 0x813d }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_kikyou = { - .type = IVTV_CARD_KIKYOU, - .name = "Sony VAIO Giga Pocket (ENX Kikyou)", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_SAA7115, - .hw_audio = IVTV_HW_GPIO, - .hw_audio_ctrl = IVTV_HW_GPIO, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE1 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE1 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, - { IVTV_CARD_INPUT_LINE_IN2, IVTV_GPIO_LINE_IN }, - }, - .gpio_init = { .direction = 0x03e1, .initial_value = 0x0320 }, - .gpio_audio_input = { .mask = 0x0060, - .tuner = 0x0020, - .linein = 0x0000, - .radio = 0x0060 }, - .gpio_audio_mute = { .mask = 0x0000, - .mute = 0x0000 }, /* 0x200? Disable for now. */ - .gpio_audio_mode = { .mask = 0x0080, - .mono = 0x0000, - .stereo = 0x0000, /* SAP */ - .lang1 = 0x0080, - .lang2 = 0x0000, - .both = 0x0080 }, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_SONY_BTF_PXN01Z }, - }, - .pci_list = ivtv_pci_kikyou, - .i2c = &ivtv_i2c_std, -}; - - -static const struct ivtv_card *ivtv_card_list[] = { - &ivtv_card_pvr250, - &ivtv_card_pvr350, - &ivtv_card_pvr150, - &ivtv_card_m179, - &ivtv_card_mpg600, - &ivtv_card_mpg160, - &ivtv_card_pg600, - &ivtv_card_avc2410, - &ivtv_card_avc2010, - &ivtv_card_tg5000tv, - &ivtv_card_va2000, - &ivtv_card_cx23416gyc, - &ivtv_card_gv_mvprx, - &ivtv_card_gv_mvprx2e, - &ivtv_card_gotview_pci_dvd, - &ivtv_card_gotview_pci_dvd2, - &ivtv_card_yuan_mpc622, - &ivtv_card_dctmvtvp1, - &ivtv_card_pg600v2, - &ivtv_card_club3d, - &ivtv_card_avertv_mce116, - &ivtv_card_asus_falcon2, - &ivtv_card_aver_pvr150, - &ivtv_card_aver_ezmaker, - &ivtv_card_aver_m104, - &ivtv_card_buffalo, - &ivtv_card_aver_ultra1500mce, - &ivtv_card_kikyou, - - /* Variations of standard cards but with the same PCI IDs. - These cards must come last in this list. */ - &ivtv_card_pvr350_v1, - &ivtv_card_cx23416gyc_nogr, - &ivtv_card_cx23416gyc_nogrycs, -}; - -const struct ivtv_card *ivtv_get_card(u16 index) -{ - if (index >= ARRAY_SIZE(ivtv_card_list)) - return NULL; - return ivtv_card_list[index]; -} - -int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input) -{ - const struct ivtv_card_video_input *card_input = itv->card->video_inputs + index; - static const char * const input_strs[] = { - "Tuner 1", - "S-Video 1", - "S-Video 2", - "Composite 1", - "Composite 2", - "Composite 3" - }; - - if (index >= itv->nof_inputs) - return -EINVAL; - input->index = index; - strlcpy(input->name, input_strs[card_input->video_type - 1], - sizeof(input->name)); - input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ? - V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); - input->audioset = (1 << itv->nof_audio_inputs) - 1; - input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? - itv->tuner_std : V4L2_STD_ALL; - return 0; -} - -int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output) -{ - const struct ivtv_card_output *card_output = itv->card->video_outputs + index; - - if (index >= itv->card->nof_outputs) - return -EINVAL; - output->index = index; - strlcpy(output->name, card_output->name, sizeof(output->name)); - output->type = V4L2_OUTPUT_TYPE_ANALOG; - output->audioset = 1; - output->std = V4L2_STD_ALL; - return 0; -} - -int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio) -{ - const struct ivtv_card_audio_input *aud_input = itv->card->audio_inputs + index; - static const char * const input_strs[] = { - "Tuner 1", - "Line In 1", - "Line In 2" - }; - - memset(audio, 0, sizeof(*audio)); - if (index >= itv->nof_audio_inputs) - return -EINVAL; - strlcpy(audio->name, input_strs[aud_input->audio_type - 1], - sizeof(audio->name)); - audio->index = index; - audio->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud_output) -{ - memset(aud_output, 0, sizeof(*aud_output)); - if (itv->card->video_outputs == NULL || index != 0) - return -EINVAL; - strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name)); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-cards.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-cards.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-cards.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-cards.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,309 +0,0 @@ -/* - Functions to query card hardware - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_CARDS_H -#define IVTV_CARDS_H - -/* Supported cards */ -#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ -#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ -#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two - PVR150s on one PCI board) */ -#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ -#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ -#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 - cx23415 based, but does not have tv-out */ -#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ -#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ -#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ -#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ -#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ -#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ -#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ -#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ -#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ -#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ -#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ -#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ -#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ -#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ -#define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ -#define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ -#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */ -#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */ -#define IVTV_CARD_BUFFALO_MV5L 25 /* Buffalo PC-MV5L/PCI card */ -#define IVTV_CARD_AVER_ULTRA1500MCE 26 /* AVerMedia UltraTV 1500 MCE */ -#define IVTV_CARD_KIKYOU 27 /* Sony VAIO Giga Pocket (ENX Kikyou) */ -#define IVTV_CARD_LAST 27 - -/* Variants of existing cards but with the same PCI IDs. The driver - detects these based on other device information. - These cards must always come last. - New cards must be inserted above, and the indices of the cards below - must be adjusted accordingly. */ - -/* PVR-350 V1 (uses saa7114) */ -#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) -/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) -#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) - -/* system vendor and device IDs */ -#define PCI_VENDOR_ID_ICOMP 0x4444 -#define PCI_DEVICE_ID_IVTV15 0x0803 -#define PCI_DEVICE_ID_IVTV16 0x0016 - -/* subsystem vendor ID */ -#define IVTV_PCI_ID_HAUPPAUGE 0x0070 -#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 -#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 -#define IVTV_PCI_ID_ADAPTEC 0x9005 -#define IVTV_PCI_ID_ASUSTEK 0x1043 -#define IVTV_PCI_ID_AVERMEDIA 0x1461 -#define IVTV_PCI_ID_YUAN1 0x12ab -#define IVTV_PCI_ID_YUAN2 0xff01 -#define IVTV_PCI_ID_YUAN3 0xffab -#define IVTV_PCI_ID_YUAN4 0xfbab -#define IVTV_PCI_ID_DIAMONDMM 0xff92 -#define IVTV_PCI_ID_IODATA 0x10fc -#define IVTV_PCI_ID_MELCO 0x1154 -#define IVTV_PCI_ID_GOTVIEW1 0xffac -#define IVTV_PCI_ID_GOTVIEW2 0xffad -#define IVTV_PCI_ID_SONY 0x104d - -/* hardware flags, no gaps allowed */ -#define IVTV_HW_CX25840 (1 << 0) -#define IVTV_HW_SAA7115 (1 << 1) -#define IVTV_HW_SAA7127 (1 << 2) -#define IVTV_HW_MSP34XX (1 << 3) -#define IVTV_HW_TUNER (1 << 4) -#define IVTV_HW_WM8775 (1 << 5) -#define IVTV_HW_CS53L32A (1 << 6) -#define IVTV_HW_TVEEPROM (1 << 7) -#define IVTV_HW_SAA7114 (1 << 8) -#define IVTV_HW_UPD64031A (1 << 9) -#define IVTV_HW_UPD6408X (1 << 10) -#define IVTV_HW_SAA717X (1 << 11) -#define IVTV_HW_WM8739 (1 << 12) -#define IVTV_HW_VP27SMPX (1 << 13) -#define IVTV_HW_M52790 (1 << 14) -#define IVTV_HW_GPIO (1 << 15) -#define IVTV_HW_I2C_IR_RX_AVER (1 << 16) -#define IVTV_HW_I2C_IR_RX_HAUP_EXT (1 << 17) /* External before internal */ -#define IVTV_HW_I2C_IR_RX_HAUP_INT (1 << 18) -#define IVTV_HW_Z8F0811_IR_TX_HAUP (1 << 19) -#define IVTV_HW_Z8F0811_IR_RX_HAUP (1 << 20) -#define IVTV_HW_I2C_IR_RX_ADAPTEC (1 << 21) - -#define IVTV_HW_Z8F0811_IR_HAUP (IVTV_HW_Z8F0811_IR_RX_HAUP | \ - IVTV_HW_Z8F0811_IR_TX_HAUP) - -#define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) - -#define IVTV_HW_IR_RX_ANY (IVTV_HW_I2C_IR_RX_AVER | \ - IVTV_HW_I2C_IR_RX_HAUP_EXT | \ - IVTV_HW_I2C_IR_RX_HAUP_INT | \ - IVTV_HW_Z8F0811_IR_RX_HAUP | \ - IVTV_HW_I2C_IR_RX_ADAPTEC) - -#define IVTV_HW_IR_TX_ANY (IVTV_HW_Z8F0811_IR_TX_HAUP) - -#define IVTV_HW_IR_ANY (IVTV_HW_IR_RX_ANY | IVTV_HW_IR_TX_ANY) - -/* video inputs */ -#define IVTV_CARD_INPUT_VID_TUNER 1 -#define IVTV_CARD_INPUT_SVIDEO1 2 -#define IVTV_CARD_INPUT_SVIDEO2 3 -#define IVTV_CARD_INPUT_COMPOSITE1 4 -#define IVTV_CARD_INPUT_COMPOSITE2 5 -#define IVTV_CARD_INPUT_COMPOSITE3 6 - -/* audio inputs */ -#define IVTV_CARD_INPUT_AUD_TUNER 1 -#define IVTV_CARD_INPUT_LINE_IN1 2 -#define IVTV_CARD_INPUT_LINE_IN2 3 - -#define IVTV_CARD_MAX_VIDEO_INPUTS 6 -#define IVTV_CARD_MAX_AUDIO_INPUTS 3 -#define IVTV_CARD_MAX_TUNERS 3 - -/* SAA71XX HW inputs */ -#define IVTV_SAA71XX_COMPOSITE0 0 -#define IVTV_SAA71XX_COMPOSITE1 1 -#define IVTV_SAA71XX_COMPOSITE2 2 -#define IVTV_SAA71XX_COMPOSITE3 3 -#define IVTV_SAA71XX_COMPOSITE4 4 -#define IVTV_SAA71XX_COMPOSITE5 5 -#define IVTV_SAA71XX_SVIDEO0 6 -#define IVTV_SAA71XX_SVIDEO1 7 -#define IVTV_SAA71XX_SVIDEO2 8 -#define IVTV_SAA71XX_SVIDEO3 9 - -/* SAA717X needs to mark the tuner input by ORing with this flag */ -#define IVTV_SAA717X_TUNER_FLAG 0x80 - -/* Dummy HW input */ -#define IVTV_DUMMY_AUDIO 0 - -/* GPIO HW inputs */ -#define IVTV_GPIO_TUNER 0 -#define IVTV_GPIO_LINE_IN 1 - -/* SAA717X HW inputs */ -#define IVTV_SAA717X_IN0 0 -#define IVTV_SAA717X_IN1 1 -#define IVTV_SAA717X_IN2 2 - -/* V4L2 capability aliases */ -#define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \ - V4L2_CAP_SLICED_VBI_CAPTURE) -#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | \ - V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY) - -struct ivtv_card_video_input { - u8 video_type; /* video input type */ - u8 audio_index; /* index in ivtv_card_audio_input array */ - u16 video_input; /* hardware video input */ -}; - -struct ivtv_card_audio_input { - u8 audio_type; /* audio input type */ - u32 audio_input; /* hardware audio input */ - u16 muxer_input; /* hardware muxer input for boards with a - multiplexer chip */ -}; - -struct ivtv_card_output { - u8 name[32]; - u16 video_output; /* hardware video output */ -}; - -struct ivtv_card_pci_info { - u16 device; - u16 subsystem_vendor; - u16 subsystem_device; -}; - -/* GPIO definitions */ - -/* The mask is the set of bits used by the operation */ - -struct ivtv_gpio_init { /* set initial GPIO DIR and OUT values */ - u16 direction; /* DIR setting. Leave to 0 if no init is needed */ - u16 initial_value; -}; - -struct ivtv_gpio_video_input { /* select tuner/line in input */ - u16 mask; /* leave to 0 if not supported */ - u16 tuner; - u16 composite; - u16 svideo; -}; - -struct ivtv_gpio_audio_input { /* select tuner/line in input */ - u16 mask; /* leave to 0 if not supported */ - u16 tuner; - u16 linein; - u16 radio; -}; - -struct ivtv_gpio_audio_mute { - u16 mask; /* leave to 0 if not supported */ - u16 mute; /* set this value to mute, 0 to unmute */ -}; - -struct ivtv_gpio_audio_mode { - u16 mask; /* leave to 0 if not supported */ - u16 mono; /* set audio to mono */ - u16 stereo; /* set audio to stereo */ - u16 lang1; /* set audio to the first language */ - u16 lang2; /* set audio to the second language */ - u16 both; /* both languages are output */ -}; - -struct ivtv_gpio_audio_freq { - u16 mask; /* leave to 0 if not supported */ - u16 f32000; - u16 f44100; - u16 f48000; -}; - -struct ivtv_gpio_audio_detect { - u16 mask; /* leave to 0 if not supported */ - u16 stereo; /* if the input matches this value then - stereo is detected */ -}; - -struct ivtv_card_tuner { - v4l2_std_id std; /* standard for which the tuner is suitable */ - int tuner; /* tuner ID (from tuner.h) */ -}; - -struct ivtv_card_tuner_i2c { - unsigned short radio[2];/* radio tuner i2c address to probe */ - unsigned short demod[2];/* demodulator i2c address to probe */ - unsigned short tv[4]; /* tv tuner i2c addresses to probe */ -}; - -/* for card information/parameters */ -struct ivtv_card { - int type; - char *name; - char *comment; - u32 v4l2_capabilities; - u32 hw_video; /* hardware used to process video */ - u32 hw_audio; /* hardware used to process audio */ - u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only 1 dev allowed) */ - u32 hw_muxer; /* hardware used to multiplex audio input */ - u32 hw_all; /* all hardware used by the board */ - struct ivtv_card_video_input video_inputs[IVTV_CARD_MAX_VIDEO_INPUTS]; - struct ivtv_card_audio_input audio_inputs[IVTV_CARD_MAX_AUDIO_INPUTS]; - struct ivtv_card_audio_input radio_input; - int nof_outputs; - const struct ivtv_card_output *video_outputs; - u8 gr_config; /* config byte for the ghost reduction device */ - u8 xceive_pin; /* XCeive tuner GPIO reset pin */ - - /* GPIO card-specific settings */ - struct ivtv_gpio_init gpio_init; - struct ivtv_gpio_video_input gpio_video_input; - struct ivtv_gpio_audio_input gpio_audio_input; - struct ivtv_gpio_audio_mute gpio_audio_mute; - struct ivtv_gpio_audio_mode gpio_audio_mode; - struct ivtv_gpio_audio_freq gpio_audio_freq; - struct ivtv_gpio_audio_detect gpio_audio_detect; - - struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS]; - struct ivtv_card_tuner_i2c *i2c; - - /* list of device and subsystem vendor/devices that - correspond to this card type. */ - const struct ivtv_card_pci_info *pci_list; -}; - -int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input); -int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output); -int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input); -int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output); -const struct ivtv_card *ivtv_get_card(u16 index); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-controls.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-controls.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-controls.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-controls.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -/* - ioctl control functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-ioctl.h" -#include "ivtv-controls.h" - -static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) -{ - struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); - - /* First try to allocate sliced VBI buffers if needed. */ - if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) { - int i; - - for (i = 0; i < IVTV_VBI_FRAMES; i++) { - /* Yuck, hardcoded. Needs to be a define */ - itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); - if (itv->vbi.sliced_mpeg_data[i] == NULL) { - while (--i >= 0) { - kfree(itv->vbi.sliced_mpeg_data[i]); - itv->vbi.sliced_mpeg_data[i] = NULL; - } - return -ENOMEM; - } - } - } - - itv->vbi.insert_mpeg = fmt; - - if (itv->vbi.insert_mpeg == 0) { - return 0; - } - /* Need sliced data for mpeg insertion */ - if (ivtv_get_service_set(itv->vbi.sliced_in) == 0) { - if (itv->is_60hz) - itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; - else - itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; - ivtv_expand_service_set(itv->vbi.sliced_in, itv->is_50hz); - } - return 0; -} - -static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) -{ - struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); - int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; - - /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = V4L2_MBUS_FMT_FIXED; - v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt); - return 0; -} - -static int ivtv_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) -{ - static const u32 freqs[3] = { 44100, 48000, 32000 }; - struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); - - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (idx < ARRAY_SIZE(freqs)) - ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]); - return 0; -} - -static int ivtv_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) -{ - struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); - - itv->dualwatch_stereo_mode = val; - return 0; -} - -struct cx2341x_handler_ops ivtv_cxhdl_ops = { - .s_audio_mode = ivtv_s_audio_mode, - .s_audio_sampling_freq = ivtv_s_audio_sampling_freq, - .s_video_encoding = ivtv_s_video_encoding, - .s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-controls.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-controls.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-controls.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-controls.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -/* - ioctl control functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_CONTROLS_H -#define IVTV_CONTROLS_H - -extern struct cx2341x_handler_ops ivtv_cxhdl_ops; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-driver.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-driver.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1473 +0,0 @@ -/* - ivtv driver initialization and card probing - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -/* Main Driver file for the ivtv project: - * Driver for the Conexant CX23415/CX23416 chip. - * Author: Kevin Thayer (nufan_wfk at yahoo.com) - * License: GPL - * http://www.ivtvdriver.org - * - * ----- - * MPG600/MPG160 support by T.Adachi - * and Takeru KOMORIYA - * - * AVerMedia M179 GPIO info by Chris Pinkham - * using information provided by Jiun-Kuei Jung @ AVerMedia. - * - * Kurouto Sikou CX23416GYC-STVLP tested by K.Ohta - * using information from T.Adachi,Takeru KOMORIYA and others :-) - * - * Nagase TRANSGEAR 5000TV, Aopen VA2000MAX-STN6 and I/O data GV-MVP/RX - * version by T.Adachi. Special thanks Mr.Suzuki - */ - -#include "ivtv-driver.h" -#include "ivtv-version.h" -#include "ivtv-fileops.h" -#include "ivtv-i2c.h" -#include "ivtv-firmware.h" -#include "ivtv-queue.h" -#include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-mailbox.h" -#include "ivtv-streams.h" -#include "ivtv-ioctl.h" -#include "ivtv-cards.h" -#include "ivtv-vbi.h" -#include "ivtv-routing.h" -#include "ivtv-controls.h" -#include "ivtv-gpio.h" - -#include -#include -#include -#include "tuner-xc2028.h" - -/* If you have already X v4l cards, then set this to X. This way - the device numbers stay matched. Example: you have a WinTV card - without radio and a PVR-350 with. Normally this would give a - video1 device together with a radio0 device for the PVR. By - setting this to 1 you ensure that radio0 is now also radio1. */ -int ivtv_first_minor; - -/* add your revision and whatnot here */ -static struct pci_device_id ivtv_pci_tbl[] __devinitdata = { - {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); - -/* ivtv instance counter */ -static atomic_t ivtv_instance = ATOMIC_INIT(0); - -/* Parameter declarations */ -static int cardtype[IVTV_MAX_CARDS]; -static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; - -static unsigned int cardtype_c = 1; -static unsigned int tuner_c = 1; -static unsigned int radio_c = 1; -static unsigned int i2c_clock_period_c = 1; -static char pal[] = "---"; -static char secam[] = "--"; -static char ntsc[] = "-"; - -/* Buffers */ - -/* DMA Buffers, Default size in MB allocated */ -#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 -#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 -#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 -/* Exception: size in kB for this stream (MB is overkill) */ -#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 -#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 -#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 -/* Exception: size in kB for this stream (MB is way overkill) */ -#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 - -static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS; -static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS; -static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS; -static int enc_pcm_buffers = IVTV_DEFAULT_ENC_PCM_BUFFERS; -static int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS; -static int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS; -static int dec_vbi_buffers = IVTV_DEFAULT_DEC_VBI_BUFFERS; - -static int ivtv_yuv_mode; -static int ivtv_yuv_threshold = -1; -static int ivtv_pci_latency = 1; - -int ivtv_debug; -#ifdef CONFIG_VIDEO_ADV_DEBUG -int ivtv_fw_debug; -#endif - -static int tunertype = -1; -static int newi2c = -1; - -module_param_array(tuner, int, &tuner_c, 0644); -module_param_array(radio, bool, &radio_c, 0644); -module_param_array(cardtype, int, &cardtype_c, 0644); -module_param_string(pal, pal, sizeof(pal), 0644); -module_param_string(secam, secam, sizeof(secam), 0644); -module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); -module_param_named(debug,ivtv_debug, int, 0644); -#ifdef CONFIG_VIDEO_ADV_DEBUG -module_param_named(fw_debug, ivtv_fw_debug, int, 0644); -#endif -module_param(ivtv_pci_latency, int, 0644); -module_param(ivtv_yuv_mode, int, 0644); -module_param(ivtv_yuv_threshold, int, 0644); -module_param(ivtv_first_minor, int, 0644); - -module_param(enc_mpg_buffers, int, 0644); -module_param(enc_yuv_buffers, int, 0644); -module_param(enc_vbi_buffers, int, 0644); -module_param(enc_pcm_buffers, int, 0644); -module_param(dec_mpg_buffers, int, 0644); -module_param(dec_yuv_buffers, int, 0644); -module_param(dec_vbi_buffers, int, 0644); - -module_param(tunertype, int, 0644); -module_param(newi2c, int, 0644); -module_param_array(i2c_clock_period, int, &i2c_clock_period_c, 0644); - -MODULE_PARM_DESC(tuner, "Tuner type selection,\n" - "\t\t\tsee tuner.h for values"); -MODULE_PARM_DESC(radio, - "Enable or disable the radio. Use only if autodetection\n" - "\t\t\tfails. 0 = disable, 1 = enable"); -MODULE_PARM_DESC(cardtype, - "Only use this option if your card is not detected properly.\n" - "\t\tSpecify card type:\n" - "\t\t\t 1 = WinTV PVR 250\n" - "\t\t\t 2 = WinTV PVR 350\n" - "\t\t\t 3 = WinTV PVR-150 or PVR-500\n" - "\t\t\t 4 = AVerMedia M179\n" - "\t\t\t 5 = YUAN MPG600/Kuroutoshikou iTVC16-STVLP\n" - "\t\t\t 6 = YUAN MPG160/Kuroutoshikou iTVC15-STVLP\n" - "\t\t\t 7 = YUAN PG600/DIAMONDMM PVR-550 (CX Falcon 2)\n" - "\t\t\t 8 = Adaptec AVC-2410\n" - "\t\t\t 9 = Adaptec AVC-2010\n" - "\t\t\t10 = NAGASE TRANSGEAR 5000TV\n" - "\t\t\t11 = AOpen VA2000MAX-STN6\n" - "\t\t\t12 = YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP\n" - "\t\t\t13 = I/O Data GV-MVP/RX\n" - "\t\t\t14 = I/O Data GV-MVP/RX2E\n" - "\t\t\t15 = GOTVIEW PCI DVD\n" - "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n" - "\t\t\t17 = Yuan MPC622\n" - "\t\t\t18 = Digital Cowboy DCT-MTVP1\n" - "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n" - "\t\t\t20 = Club3D ZAP-TV1x01\n" - "\t\t\t21 = AverTV MCE 116 Plus\n" - "\t\t\t22 = ASUS Falcon2\n" - "\t\t\t23 = AverMedia PVR-150 Plus\n" - "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n" - "\t\t\t25 = AverMedia M104 (not yet working)\n" - "\t\t\t26 = Buffalo PC-MV5L/PCI\n" - "\t\t\t27 = AVerMedia UltraTV 1500 MCE\n" - "\t\t\t28 = Sony VAIO Giga Pocket (ENX Kikyou)\n" - "\t\t\t 0 = Autodetect (default)\n" - "\t\t\t-1 = Ignore this card\n\t\t"); -MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60"); -MODULE_PARM_DESC(secam, "Set SECAM standard: BGH, DK, L, LC"); -MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J (Japan), K (South Korea)"); -MODULE_PARM_DESC(tunertype, - "Specify tuner type:\n" - "\t\t\t 0 = tuner for PAL-B/G/H/D/K/I, SECAM-B/G/H/D/K/L/Lc\n" - "\t\t\t 1 = tuner for NTSC-M/J/K, PAL-M/N/Nc\n" - "\t\t\t-1 = Autodetect (default)\n"); -MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: 0\n" - "\t\t\t 1/0x0001: warning\n" - "\t\t\t 2/0x0002: info\n" - "\t\t\t 4/0x0004: mailbox\n" - "\t\t\t 8/0x0008: ioctl\n" - "\t\t\t 16/0x0010: file\n" - "\t\t\t 32/0x0020: dma\n" - "\t\t\t 64/0x0040: irq\n" - "\t\t\t 128/0x0080: decoder\n" - "\t\t\t 256/0x0100: yuv\n" - "\t\t\t 512/0x0200: i2c\n" - "\t\t\t1024/0x0400: high volume\n"); -#ifdef CONFIG_VIDEO_ADV_DEBUG -MODULE_PARM_DESC(fw_debug, - "Enable code for debugging firmware problems. Default: 0\n"); -#endif -MODULE_PARM_DESC(ivtv_pci_latency, - "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" - "\t\t\tDefault: Yes"); -MODULE_PARM_DESC(ivtv_yuv_mode, - "Specify the yuv playback mode:\n" - "\t\t\t0 = interlaced\n\t\t\t1 = progressive\n\t\t\t2 = auto\n" - "\t\t\tDefault: 0 (interlaced)"); -MODULE_PARM_DESC(ivtv_yuv_threshold, - "If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n" - "\t\t\tDefault: 480"); -MODULE_PARM_DESC(enc_mpg_buffers, - "Encoder MPG Buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS)); -MODULE_PARM_DESC(enc_yuv_buffers, - "Encoder YUV Buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_YUV_BUFFERS)); -MODULE_PARM_DESC(enc_vbi_buffers, - "Encoder VBI Buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS)); -MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffers (in kB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS)); -MODULE_PARM_DESC(dec_mpg_buffers, - "Decoder MPG buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_MPG_BUFFERS)); -MODULE_PARM_DESC(dec_yuv_buffers, - "Decoder YUV buffers (in MB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS)); -MODULE_PARM_DESC(dec_vbi_buffers, - "Decoder VBI buffers (in kB)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS)); -MODULE_PARM_DESC(newi2c, - "Use new I2C implementation\n" - "\t\t\t-1 is autodetect, 0 is off, 1 is on\n" - "\t\t\tDefault is autodetect"); -MODULE_PARM_DESC(i2c_clock_period, - "Period of SCL for the I2C bus controlled by the CX23415/6\n" - "\t\t\tMin: 10 usec (100 kHz), Max: 4500 usec (222 Hz)\n" - "\t\t\tDefault: " __stringify(IVTV_DEFAULT_I2C_CLOCK_PERIOD)); - -MODULE_PARM_DESC(ivtv_first_minor, "Set device node number assigned to first card"); - -MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); -MODULE_DESCRIPTION("CX23415/CX23416 driver"); -MODULE_SUPPORTED_DEVICE - ("CX23415/CX23416 MPEG2 encoder (WinTV PVR-150/250/350/500,\n" - "\t\t\tYuan MPG series and similar)"); -MODULE_LICENSE("GPL"); - - -void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask) -{ - itv->irqmask &= ~mask; - write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); -} - -void ivtv_set_irq_mask(struct ivtv *itv, u32 mask) -{ - itv->irqmask |= mask; - write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); -} - -int ivtv_set_output_mode(struct ivtv *itv, int mode) -{ - int old_mode; - - spin_lock(&itv->lock); - old_mode = itv->output_mode; - if (old_mode == 0) - itv->output_mode = old_mode = mode; - spin_unlock(&itv->lock); - return old_mode; -} - -struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv) -{ - switch (itv->output_mode) { - case OUT_MPG: - return &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - case OUT_YUV: - return &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - default: - return NULL; - } -} - -int ivtv_waitq(wait_queue_head_t *waitq) -{ - DEFINE_WAIT(wait); - - prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); - schedule(); - finish_wait(waitq, &wait); - return signal_pending(current) ? -EINTR : 0; -} - -/* Generic utility functions */ -int ivtv_msleep_timeout(unsigned int msecs, int intr) -{ - int timeout = msecs_to_jiffies(msecs); - - do { - set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - timeout = schedule_timeout(timeout); - if (intr) { - int ret = signal_pending(current); - - if (ret) - return ret; - } - } while (timeout); - return 0; -} - -/* Release ioremapped memory */ -static void ivtv_iounmap(struct ivtv *itv) -{ - if (itv == NULL) - return; - - /* Release registers memory */ - if (itv->reg_mem != NULL) { - IVTV_DEBUG_INFO("releasing reg_mem\n"); - iounmap(itv->reg_mem); - itv->reg_mem = NULL; - } - /* Release io memory */ - if (itv->has_cx23415 && itv->dec_mem != NULL) { - IVTV_DEBUG_INFO("releasing dec_mem\n"); - iounmap(itv->dec_mem); - } - itv->dec_mem = NULL; - - /* Release io memory */ - if (itv->enc_mem != NULL) { - IVTV_DEBUG_INFO("releasing enc_mem\n"); - iounmap(itv->enc_mem); - itv->enc_mem = NULL; - } -} - -/* Hauppauge card? get values from tveeprom */ -void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv) -{ - u8 eedata[256]; - - itv->i2c_client.addr = 0xA0 >> 1; - tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata)); - tveeprom_hauppauge_analog(&itv->i2c_client, tv, eedata); -} - -static void ivtv_process_eeprom(struct ivtv *itv) -{ - struct tveeprom tv; - int pci_slot = PCI_SLOT(itv->pdev->devfn); - - ivtv_read_eeprom(itv, &tv); - - /* Many thanks to Steven Toth from Hauppauge for providing the - model numbers */ - switch (tv.model) { - /* In a few cases the PCI subsystem IDs do not correctly - identify the card. A better method is to check the - model number from the eeprom instead. */ - case 30012 ... 30039: /* Low profile PVR250 */ - case 32000 ... 32999: - case 48000 ... 48099: /* 48??? range are PVR250s with a cx23415 */ - case 48400 ... 48599: - itv->card = ivtv_get_card(IVTV_CARD_PVR_250); - break; - case 48100 ... 48399: - case 48600 ... 48999: - itv->card = ivtv_get_card(IVTV_CARD_PVR_350); - break; - case 23000 ... 23999: /* PVR500 */ - case 25000 ... 25999: /* Low profile PVR150 */ - case 26000 ... 26999: /* Regular PVR150 */ - itv->card = ivtv_get_card(IVTV_CARD_PVR_150); - break; - case 0: - IVTV_ERR("Invalid EEPROM\n"); - return; - default: - IVTV_ERR("Unknown model %d, defaulting to PVR-150\n", tv.model); - itv->card = ivtv_get_card(IVTV_CARD_PVR_150); - break; - } - - switch (tv.model) { - /* Old style PVR350 (with an saa7114) uses this input for - the tuner. */ - case 48254: - itv->card = ivtv_get_card(IVTV_CARD_PVR_350_V1); - break; - default: - break; - } - - itv->v4l2_cap = itv->card->v4l2_capabilities; - itv->card_name = itv->card->name; - itv->card_i2c = itv->card->i2c; - - /* If this is a PVR500 then it should be possible to detect whether it is the - first or second unit by looking at the subsystem device ID: is bit 4 is - set, then it is the second unit (according to info from Hauppauge). - - However, while this works for most cards, I have seen a few PVR500 cards - where both units have the same subsystem ID. - - So instead I look at the reported 'PCI slot' (which is the slot on the PVR500 - PCI bridge) and if it is 8, then it is assumed to be the first unit, otherwise - it is the second unit. It is possible that it is a different slot when ivtv is - used in Xen, in that case I ignore this card here. The worst that can happen - is that the card presents itself with a non-working radio device. - - This detection is needed since the eeprom reports incorrectly that a radio is - present on the second unit. */ - if (tv.model / 1000 == 23) { - static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = { - .radio = { 0x60, I2C_CLIENT_END }, - .demod = { 0x43, I2C_CLIENT_END }, - .tv = { 0x61, I2C_CLIENT_END }, - }; - - itv->card_name = "WinTV PVR 500"; - itv->card_i2c = &ivtv_i2c_radio; - if (pci_slot == 8 || pci_slot == 9) { - int is_first = (pci_slot & 1) == 0; - - itv->card_name = is_first ? "WinTV PVR 500 (unit #1)" : - "WinTV PVR 500 (unit #2)"; - if (!is_first) { - IVTV_INFO("Correcting tveeprom data: no radio present on second unit\n"); - tv.has_radio = 0; - } - } - } - IVTV_INFO("Autodetected %s\n", itv->card_name); - - switch (tv.tuner_hauppauge_model) { - case 85: - case 99: - case 112: - itv->pvr150_workaround = 1; - break; - default: - break; - } - if (tv.tuner_type == TUNER_ABSENT) - IVTV_ERR("tveeprom cannot autodetect tuner!\n"); - - if (itv->options.tuner == -1) - itv->options.tuner = tv.tuner_type; - if (itv->options.radio == -1) - itv->options.radio = (tv.has_radio != 0); - /* only enable newi2c if an IR blaster is present */ - if (itv->options.newi2c == -1 && tv.has_ir) { - itv->options.newi2c = (tv.has_ir & 4) ? 1 : 0; - if (itv->options.newi2c) { - IVTV_INFO("Reopen i2c bus for IR-blaster support\n"); - exit_ivtv_i2c(itv); - init_ivtv_i2c(itv); - } - } - - if (itv->std != 0) - /* user specified tuner standard */ - return; - - /* autodetect tuner standard */ - if (tv.tuner_formats & V4L2_STD_PAL) { - IVTV_DEBUG_INFO("PAL tuner detected\n"); - itv->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; - } else if (tv.tuner_formats & V4L2_STD_NTSC) { - IVTV_DEBUG_INFO("NTSC tuner detected\n"); - itv->std |= V4L2_STD_NTSC_M; - } else if (tv.tuner_formats & V4L2_STD_SECAM) { - IVTV_DEBUG_INFO("SECAM tuner detected\n"); - itv->std |= V4L2_STD_SECAM_L; - } else { - IVTV_INFO("No tuner detected, default to NTSC-M\n"); - itv->std |= V4L2_STD_NTSC_M; - } -} - -static v4l2_std_id ivtv_parse_std(struct ivtv *itv) -{ - switch (pal[0]) { - case '6': - tunertype = 0; - return V4L2_STD_PAL_60; - case 'b': - case 'B': - case 'g': - case 'G': - case 'h': - case 'H': - tunertype = 0; - return V4L2_STD_PAL_BG | V4L2_STD_PAL_H; - case 'n': - case 'N': - tunertype = 1; - if (pal[1] == 'c' || pal[1] == 'C') - return V4L2_STD_PAL_Nc; - return V4L2_STD_PAL_N; - case 'i': - case 'I': - tunertype = 0; - return V4L2_STD_PAL_I; - case 'd': - case 'D': - case 'k': - case 'K': - tunertype = 0; - return V4L2_STD_PAL_DK; - case 'M': - case 'm': - tunertype = 1; - return V4L2_STD_PAL_M; - case '-': - break; - default: - IVTV_WARN("pal= argument not recognised\n"); - return 0; - } - - switch (secam[0]) { - case 'b': - case 'B': - case 'g': - case 'G': - case 'h': - case 'H': - tunertype = 0; - return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; - case 'd': - case 'D': - case 'k': - case 'K': - tunertype = 0; - return V4L2_STD_SECAM_DK; - case 'l': - case 'L': - tunertype = 0; - if (secam[1] == 'C' || secam[1] == 'c') - return V4L2_STD_SECAM_LC; - return V4L2_STD_SECAM_L; - case '-': - break; - default: - IVTV_WARN("secam= argument not recognised\n"); - return 0; - } - - switch (ntsc[0]) { - case 'm': - case 'M': - tunertype = 1; - return V4L2_STD_NTSC_M; - case 'j': - case 'J': - tunertype = 1; - return V4L2_STD_NTSC_M_JP; - case 'k': - case 'K': - tunertype = 1; - return V4L2_STD_NTSC_M_KR; - case '-': - break; - default: - IVTV_WARN("ntsc= argument not recognised\n"); - return 0; - } - - /* no match found */ - return 0; -} - -static void ivtv_process_options(struct ivtv *itv) -{ - const char *chipname; - int i, j; - - itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024; - itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024; - itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024; - itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; - itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024; - itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024; - itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; - itv->options.cardtype = cardtype[itv->instance]; - itv->options.tuner = tuner[itv->instance]; - itv->options.radio = radio[itv->instance]; - - itv->options.i2c_clock_period = i2c_clock_period[itv->instance]; - if (itv->options.i2c_clock_period == -1) - itv->options.i2c_clock_period = IVTV_DEFAULT_I2C_CLOCK_PERIOD; - else if (itv->options.i2c_clock_period < 10) - itv->options.i2c_clock_period = 10; - else if (itv->options.i2c_clock_period > 4500) - itv->options.i2c_clock_period = 4500; - - itv->options.newi2c = newi2c; - if (tunertype < -1 || tunertype > 1) { - IVTV_WARN("Invalid tunertype argument, will autodetect instead\n"); - tunertype = -1; - } - itv->std = ivtv_parse_std(itv); - if (itv->std == 0 && tunertype >= 0) - itv->std = tunertype ? V4L2_STD_MN : (V4L2_STD_ALL & ~V4L2_STD_MN); - itv->has_cx23415 = (itv->pdev->device == PCI_DEVICE_ID_IVTV15); - chipname = itv->has_cx23415 ? "cx23415" : "cx23416"; - if (itv->options.cardtype == -1) { - IVTV_INFO("Ignore card (detected %s based chip)\n", chipname); - return; - } - if ((itv->card = ivtv_get_card(itv->options.cardtype - 1))) { - IVTV_INFO("User specified %s card (detected %s based chip)\n", - itv->card->name, chipname); - } else if (itv->options.cardtype != 0) { - IVTV_ERR("Unknown user specified type, trying to autodetect card\n"); - } - if (itv->card == NULL) { - if (itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE || - itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 || - itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) { - itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150); - IVTV_INFO("Autodetected Hauppauge card (%s based)\n", - chipname); - } - } - if (itv->card == NULL) { - for (i = 0; (itv->card = ivtv_get_card(i)); i++) { - if (itv->card->pci_list == NULL) - continue; - for (j = 0; itv->card->pci_list[j].device; j++) { - if (itv->pdev->device != - itv->card->pci_list[j].device) - continue; - if (itv->pdev->subsystem_vendor != - itv->card->pci_list[j].subsystem_vendor) - continue; - if (itv->pdev->subsystem_device != - itv->card->pci_list[j].subsystem_device) - continue; - IVTV_INFO("Autodetected %s card (%s based)\n", - itv->card->name, chipname); - goto done; - } - } - } -done: - - if (itv->card == NULL) { - itv->card = ivtv_get_card(IVTV_CARD_PVR_150); - IVTV_ERR("Unknown card: vendor/device: [%04x:%04x]\n", - itv->pdev->vendor, itv->pdev->device); - IVTV_ERR(" subsystem vendor/device: [%04x:%04x]\n", - itv->pdev->subsystem_vendor, itv->pdev->subsystem_device); - IVTV_ERR(" %s based\n", chipname); - IVTV_ERR("Defaulting to %s card\n", itv->card->name); - IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); - IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); - IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n"); - } - itv->v4l2_cap = itv->card->v4l2_capabilities; - itv->card_name = itv->card->name; - itv->card_i2c = itv->card->i2c; -} - -/* Precondition: the ivtv structure has been memset to 0. Only - the dev and num fields have been filled in. - No assumptions on the card type may be made here (see ivtv_init_struct2 - for that). - */ -static int __devinit ivtv_init_struct1(struct ivtv *itv) -{ - struct sched_param param = { .sched_priority = 99 }; - - itv->base_addr = pci_resource_start(itv->pdev, 0); - itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ - itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ - - mutex_init(&itv->serialize_lock); - mutex_init(&itv->i2c_bus_lock); - mutex_init(&itv->udma.lock); - - spin_lock_init(&itv->lock); - spin_lock_init(&itv->dma_reg_lock); - - init_kthread_worker(&itv->irq_worker); - itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker, - itv->v4l2_dev.name); - if (IS_ERR(itv->irq_worker_task)) { - IVTV_ERR("Could not create ivtv task\n"); - return -1; - } - /* must use the FIFO scheduler as it is realtime sensitive */ - sched_setscheduler(itv->irq_worker_task, SCHED_FIFO, ¶m); - - init_kthread_work(&itv->irq_work, ivtv_irq_work_handler); - - /* start counting open_id at 1 */ - itv->open_id = 1; - - /* Initial settings */ - itv->cxhdl.port = CX2341X_PORT_MEMORY; - itv->cxhdl.capabilities = CX2341X_CAP_HAS_SLICED_VBI; - init_waitqueue_head(&itv->eos_waitq); - init_waitqueue_head(&itv->event_waitq); - init_waitqueue_head(&itv->vsync_waitq); - init_waitqueue_head(&itv->dma_waitq); - init_timer(&itv->dma_timer); - itv->dma_timer.function = ivtv_unfinished_dma; - itv->dma_timer.data = (unsigned long)itv; - - itv->cur_dma_stream = -1; - itv->cur_pio_stream = -1; - itv->audio_stereo_mode = AUDIO_STEREO; - itv->audio_bilingual_mode = AUDIO_MONO_LEFT; - - /* Ctrls */ - itv->speed = 1000; - - /* VBI */ - itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; - itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced; - - /* Init the sg table for osd/yuv output */ - sg_init_table(itv->udma.SGlist, IVTV_DMA_SG_OSD_ENT); - - /* OSD */ - itv->osd_global_alpha_state = 1; - itv->osd_global_alpha = 255; - - /* YUV */ - atomic_set(&itv->yuv_info.next_dma_frame, -1); - itv->yuv_info.lace_mode = ivtv_yuv_mode; - itv->yuv_info.lace_threshold = ivtv_yuv_threshold; - itv->yuv_info.max_frames_buffered = 3; - itv->yuv_info.track_osd = 1; - return 0; -} - -/* Second initialization part. Here the card type has been - autodetected. */ -static void __devinit ivtv_init_struct2(struct ivtv *itv) -{ - int i; - - for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++) - if (itv->card->video_inputs[i].video_type == 0) - break; - itv->nof_inputs = i; - for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++) - if (itv->card->audio_inputs[i].audio_type == 0) - break; - itv->nof_audio_inputs = i; - - if (itv->card->hw_all & IVTV_HW_CX25840) { - itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */ - } else { - itv->vbi.sliced_size = 64; /* multiple of 16, real size = 52 */ - } - - /* Find tuner input */ - for (i = 0; i < itv->nof_inputs; i++) { - if (itv->card->video_inputs[i].video_type == - IVTV_CARD_INPUT_VID_TUNER) - break; - } - if (i == itv->nof_inputs) - i = 0; - itv->active_input = i; - itv->audio_input = itv->card->video_inputs[i].audio_index; -} - -static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, - const struct pci_device_id *pci_id) -{ - u16 cmd; - u8 card_rev; - unsigned char pci_latency; - - IVTV_DEBUG_INFO("Enabling pci device\n"); - - if (pci_enable_device(pdev)) { - IVTV_ERR("Can't enable device!\n"); - return -EIO; - } - if (pci_set_dma_mask(pdev, 0xffffffff)) { - IVTV_ERR("No suitable DMA available.\n"); - return -EIO; - } - if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) { - IVTV_ERR("Cannot request encoder memory region.\n"); - return -EIO; - } - - if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET, - IVTV_REG_SIZE, "ivtv registers")) { - IVTV_ERR("Cannot request register memory region.\n"); - release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); - return -EIO; - } - - if (itv->has_cx23415 && - !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, - IVTV_DECODER_SIZE, "ivtv decoder")) { - IVTV_ERR("Cannot request decoder memory region.\n"); - release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); - release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - return -EIO; - } - - /* Check for bus mastering */ - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_MASTER)) { - IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n"); - pci_set_master(pdev); - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_MASTER)) { - IVTV_ERR("Bus Mastering is not enabled\n"); - return -ENXIO; - } - } - IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); - - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &card_rev); - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - - if (pci_latency < 64 && ivtv_pci_latency) { - IVTV_INFO("Unreasonably low latency timer, " - "setting to 64 (was %d)\n", pci_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - } - /* This config space value relates to DMA latencies. The - default value 0x8080 is too low however and will lead - to DMA errors. 0xffff is the max value which solves - these problems. */ - pci_write_config_dword(pdev, 0x40, 0xffff); - - IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " - "irq: %d, latency: %d, memory: 0x%lx\n", - pdev->device, card_rev, pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - pdev->irq, pci_latency, (unsigned long)itv->base_addr); - - return 0; -} - -static void ivtv_load_and_init_modules(struct ivtv *itv) -{ - u32 hw = itv->card->hw_all; - unsigned i; - - /* check which i2c devices are actually found */ - for (i = 0; i < 32; i++) { - u32 device = 1 << i; - - if (!(device & hw)) - continue; - if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) { - /* GPIO and TVEEPROM do not use i2c probing */ - itv->hw_flags |= device; - continue; - } - if (ivtv_i2c_register(itv, i) == 0) - itv->hw_flags |= device; - } - - /* probe for legacy IR controllers that aren't in card definitions */ - if ((itv->hw_flags & IVTV_HW_IR_ANY) == 0) - ivtv_i2c_new_ir_legacy(itv); - - if (itv->card->hw_all & IVTV_HW_CX25840) - itv->sd_video = ivtv_find_hw(itv, IVTV_HW_CX25840); - else if (itv->card->hw_all & IVTV_HW_SAA717X) - itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA717X); - else if (itv->card->hw_all & IVTV_HW_SAA7114) - itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7114); - else - itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7115); - itv->sd_audio = ivtv_find_hw(itv, itv->card->hw_audio_ctrl); - itv->sd_muxer = ivtv_find_hw(itv, itv->card->hw_muxer); - - hw = itv->hw_flags; - - if (itv->card->type == IVTV_CARD_CX23416GYC) { - /* Several variations of this card exist, detect which card - type should be used. */ - if ((hw & (IVTV_HW_UPD64031A | IVTV_HW_UPD6408X)) == 0) - itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGRYCS); - else if ((hw & IVTV_HW_UPD64031A) == 0) - itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR); - } - else if (itv->card->type == IVTV_CARD_GV_MVPRX || - itv->card->type == IVTV_CARD_GV_MVPRX2E) { - /* The crystal frequency of GVMVPRX is 24.576MHz */ - v4l2_subdev_call(itv->sd_video, video, s_crystal_freq, - SAA7115_FREQ_24_576_MHZ, SAA7115_FREQ_FL_UCGC); - } - - if (hw & IVTV_HW_CX25840) { - itv->vbi.raw_decoder_line_size = 1444; - itv->vbi.raw_decoder_sav_odd_field = 0x20; - itv->vbi.raw_decoder_sav_even_field = 0x60; - itv->vbi.sliced_decoder_line_size = 272; - itv->vbi.sliced_decoder_sav_odd_field = 0xB0; - itv->vbi.sliced_decoder_sav_even_field = 0xF0; - } - - if (hw & IVTV_HW_SAA711X) { - struct v4l2_dbg_chip_ident v; - - /* determine the exact saa711x model */ - itv->hw_flags &= ~IVTV_HW_SAA711X; - - v.match.type = V4L2_CHIP_MATCH_I2C_DRIVER; - strlcpy(v.match.name, "saa7115", sizeof(v.match.name)); - ivtv_call_hw(itv, IVTV_HW_SAA711X, core, g_chip_ident, &v); - if (v.ident == V4L2_IDENT_SAA7114) { - itv->hw_flags |= IVTV_HW_SAA7114; - /* VBI is not yet supported by the saa7114 driver. */ - itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE); - } else { - itv->hw_flags |= IVTV_HW_SAA7115; - } - itv->vbi.raw_decoder_line_size = 1443; - itv->vbi.raw_decoder_sav_odd_field = 0x25; - itv->vbi.raw_decoder_sav_even_field = 0x62; - itv->vbi.sliced_decoder_line_size = 51; - itv->vbi.sliced_decoder_sav_odd_field = 0xAB; - itv->vbi.sliced_decoder_sav_even_field = 0xEC; - } - - if (hw & IVTV_HW_SAA717X) { - itv->vbi.raw_decoder_line_size = 1443; - itv->vbi.raw_decoder_sav_odd_field = 0x25; - itv->vbi.raw_decoder_sav_even_field = 0x62; - itv->vbi.sliced_decoder_line_size = 51; - itv->vbi.sliced_decoder_sav_odd_field = 0xAB; - itv->vbi.sliced_decoder_sav_even_field = 0xEC; - } -} - -static int __devinit ivtv_probe(struct pci_dev *pdev, - const struct pci_device_id *pci_id) -{ - int retval = 0; - int vbi_buf_size; - struct ivtv *itv; - - itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC); - if (itv == NULL) - return -ENOMEM; - itv->pdev = pdev; - itv->instance = v4l2_device_set_name(&itv->v4l2_dev, "ivtv", - &ivtv_instance); - - retval = v4l2_device_register(&pdev->dev, &itv->v4l2_dev); - if (retval) { - kfree(itv); - return retval; - } - IVTV_INFO("Initializing card %d\n", itv->instance); - - ivtv_process_options(itv); - if (itv->options.cardtype == -1) { - retval = -ENODEV; - goto err; - } - if (ivtv_init_struct1(itv)) { - retval = -ENOMEM; - goto err; - } - retval = cx2341x_handler_init(&itv->cxhdl, 50); - if (retval) - goto err; - itv->v4l2_dev.ctrl_handler = &itv->cxhdl.hdl; - itv->cxhdl.ops = &ivtv_cxhdl_ops; - itv->cxhdl.priv = itv; - itv->cxhdl.func = ivtv_api_func; - - IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); - - /* PCI Device Setup */ - retval = ivtv_setup_pci(itv, pdev, pci_id); - if (retval == -EIO) - goto free_worker; - if (retval == -ENXIO) - goto free_mem; - - /* map io memory */ - IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", - itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); - itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET, - IVTV_ENCODER_SIZE); - if (!itv->enc_mem) { - IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 " - "encoder memory\n"); - IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of " - "vmalloc address space for this window\n"); - IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); - IVTV_ERR("Use the vmalloc= kernel command line option to set " - "VmallocTotal to a larger value\n"); - retval = -ENOMEM; - goto free_mem; - } - - if (itv->has_cx23415) { - IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", - itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); - itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET, - IVTV_DECODER_SIZE); - if (!itv->dec_mem) { - IVTV_ERR("ioremap failed. Can't get a window into " - "CX23415 decoder memory\n"); - IVTV_ERR("Each capture card with a CX23415 needs 8 MB " - "of vmalloc address space for this window\n"); - IVTV_ERR("Check the output of 'grep Vmalloc " - "/proc/meminfo'\n"); - IVTV_ERR("Use the vmalloc= kernel command line option " - "to set VmallocTotal to a larger value\n"); - retval = -ENOMEM; - goto free_mem; - } - } - else { - itv->dec_mem = itv->enc_mem; - } - - /* map registers memory */ - IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", - itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - itv->reg_mem = - ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - if (!itv->reg_mem) { - IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 " - "register space\n"); - IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of " - "vmalloc address space for this window\n"); - IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); - IVTV_ERR("Use the vmalloc= kernel command line option to set " - "VmallocTotal to a larger value\n"); - retval = -ENOMEM; - goto free_io; - } - - retval = ivtv_gpio_init(itv); - if (retval) - goto free_io; - - /* active i2c */ - IVTV_DEBUG_INFO("activating i2c...\n"); - if (init_ivtv_i2c(itv)) { - IVTV_ERR("Could not initialize i2c\n"); - goto free_io; - } - - if (itv->card->hw_all & IVTV_HW_TVEEPROM) { - /* Based on the model number the cardtype may be changed. - The PCI IDs are not always reliable. */ - ivtv_process_eeprom(itv); - } - if (itv->card->comment) - IVTV_INFO("%s", itv->card->comment); - if (itv->card->v4l2_capabilities == 0) { - /* card was detected but is not supported */ - retval = -ENODEV; - goto free_i2c; - } - - if (itv->std == 0) { - itv->std = V4L2_STD_NTSC_M; - } - - if (itv->options.tuner == -1) { - int i; - - for (i = 0; i < IVTV_CARD_MAX_TUNERS; i++) { - if ((itv->std & itv->card->tuners[i].std) == 0) - continue; - itv->options.tuner = itv->card->tuners[i].tuner; - break; - } - } - /* if no tuner was found, then pick the first tuner in the card list */ - if (itv->options.tuner == -1 && itv->card->tuners[0].std) { - itv->std = itv->card->tuners[0].std; - if (itv->std & V4L2_STD_PAL) - itv->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; - else if (itv->std & V4L2_STD_NTSC) - itv->std = V4L2_STD_NTSC_M; - else if (itv->std & V4L2_STD_SECAM) - itv->std = V4L2_STD_SECAM_L; - itv->options.tuner = itv->card->tuners[0].tuner; - } - if (itv->options.radio == -1) - itv->options.radio = (itv->card->radio_input.audio_type != 0); - - /* The card is now fully identified, continue with card-specific - initialization. */ - ivtv_init_struct2(itv); - - ivtv_load_and_init_modules(itv); - - if (itv->std & V4L2_STD_525_60) { - itv->is_60hz = 1; - itv->is_out_60hz = 1; - } else { - itv->is_50hz = 1; - itv->is_out_50hz = 1; - } - - itv->yuv_info.osd_full_w = 720; - itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480; - itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w; - itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h; - - cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz); - - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200; - itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000; - itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000; - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000; - - /* Setup VBI Raw Size. Should be big enough to hold PAL. - It is possible to switch between PAL and NTSC, so we need to - take the largest size here. */ - /* 1456 is multiple of 16, real size = 1444 */ - itv->vbi.raw_size = 1456; - /* We use a buffer size of 1/2 of the total size needed for a - frame. This is actually very useful, since we now receive - a field at a time and that makes 'compressing' the raw data - down to size by stripping off the SAV codes a lot easier. - Note: having two different buffer sizes prevents standard - switching on the fly. We need to find a better solution... */ - vbi_buf_size = itv->vbi.raw_size * (itv->is_60hz ? 24 : 36) / 2; - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_VBI] = vbi_buf_size; - itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_VBI] = sizeof(struct v4l2_sliced_vbi_data) * 36; - - if (itv->options.radio > 0) - itv->v4l2_cap |= V4L2_CAP_RADIO; - - if (itv->options.tuner > -1) { - struct tuner_setup setup; - - setup.addr = ADDR_UNSET; - setup.type = itv->options.tuner; - setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ - setup.tuner_callback = (setup.type == TUNER_XC2028) ? - ivtv_reset_tuner_gpio : NULL; - ivtv_call_all(itv, tuner, s_type_addr, &setup); - if (setup.type == TUNER_XC2028) { - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - }; - struct v4l2_priv_tun_config cfg = { - .tuner = itv->options.tuner, - .priv = &ctrl, - }; - ivtv_call_all(itv, tuner, s_config, &cfg); - } - } - - /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) - are not. */ - itv->tuner_std = itv->std; - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - ivtv_call_all(itv, video, s_std_output, itv->std); - /* Turn off the output signal. The mpeg decoder is not yet - active so without this you would get a green image until the - mpeg decoder becomes active. */ - ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0); - } - - /* clear interrupt mask, effectively disabling interrupts */ - ivtv_set_irq_mask(itv, 0xffffffff); - - /* Register IRQ */ - retval = request_irq(itv->pdev->irq, ivtv_irq_handler, - IRQF_SHARED | IRQF_DISABLED, itv->v4l2_dev.name, (void *)itv); - if (retval) { - IVTV_ERR("Failed to register irq %d\n", retval); - goto free_i2c; - } - - retval = ivtv_streams_setup(itv); - if (retval) { - IVTV_ERR("Error %d setting up streams\n", retval); - goto free_irq; - } - retval = ivtv_streams_register(itv); - if (retval) { - IVTV_ERR("Error %d registering devices\n", retval); - goto free_streams; - } - IVTV_INFO("Initialized card: %s\n", itv->card_name); - return 0; - -free_streams: - ivtv_streams_cleanup(itv, 1); -free_irq: - free_irq(itv->pdev->irq, (void *)itv); -free_i2c: - exit_ivtv_i2c(itv); -free_io: - ivtv_iounmap(itv); -free_mem: - release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); - release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - if (itv->has_cx23415) - release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); -free_worker: - kthread_stop(itv->irq_worker_task); -err: - if (retval == 0) - retval = -ENODEV; - IVTV_ERR("Error %d on initialization\n", retval); - - v4l2_device_unregister(&itv->v4l2_dev); - kfree(itv); - return retval; -} - -int ivtv_init_on_first_open(struct ivtv *itv) -{ - struct v4l2_frequency vf; - /* Needed to call ioctls later */ - struct ivtv_open_id fh; - int fw_retry_count = 3; - int video_input; - - fh.itv = itv; - - if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) - return -ENXIO; - - if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) - return 0; - - while (--fw_retry_count > 0) { - /* load firmware */ - if (ivtv_firmware_init(itv) == 0) - break; - if (fw_retry_count > 1) - IVTV_WARN("Retry loading firmware\n"); - } - - if (fw_retry_count == 0) { - set_bit(IVTV_F_I_FAILED, &itv->i_flags); - return -ENXIO; - } - - /* Try and get firmware versions */ - IVTV_DEBUG_INFO("Getting firmware version..\n"); - ivtv_firmware_versions(itv); - - if (itv->card->hw_all & IVTV_HW_CX25840) - v4l2_subdev_call(itv->sd_video, core, load_fw); - - vf.tuner = 0; - vf.type = V4L2_TUNER_ANALOG_TV; - vf.frequency = 6400; /* the tuner 'baseline' frequency */ - - /* Set initial frequency. For PAL/SECAM broadcasts no - 'default' channel exists AFAIK. */ - if (itv->std == V4L2_STD_NTSC_M_JP) { - vf.frequency = 1460; /* ch. 1 91250*16/1000 */ - } - else if (itv->std & V4L2_STD_NTSC_M) { - vf.frequency = 1076; /* ch. 4 67250*16/1000 */ - } - - video_input = itv->active_input; - itv->active_input++; /* Force update of input */ - ivtv_s_input(NULL, &fh, video_input); - - /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code - in one place. */ - itv->std++; /* Force full standard initialization */ - itv->std_out = itv->std; - ivtv_s_frequency(NULL, &fh, &vf); - - if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { - /* Turn on the TV-out: ivtv_init_mpeg_decoder() initializes - the mpeg decoder so now the saa7127 receives a proper - signal. */ - ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1); - ivtv_init_mpeg_decoder(itv); - } - - /* On a cx23416 this seems to be able to enable DMA to the chip? */ - if (!itv->has_cx23415) - write_reg_sync(0x03, IVTV_REG_DMACONTROL); - - /* Default interrupts enabled. For the PVR350 this includes the - decoder VSYNC interrupt, which is always on. It is not only used - during decoding but also by the OSD. - Some old PVR250 cards had a cx23415, so testing for that is too - general. Instead test if the card has video output capability. */ - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); - ivtv_set_osd_alpha(itv); - } - else - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); - - /* For cards with video out, this call needs interrupts enabled */ - ivtv_s_std(NULL, &fh, &itv->tuner_std); - - /* Setup initial controls */ - cx2341x_handler_setup(&itv->cxhdl); - return 0; -} - -static void ivtv_remove(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct ivtv *itv = to_ivtv(v4l2_dev); - int i; - - IVTV_DEBUG_INFO("Removing card\n"); - - if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) { - /* Stop all captures */ - IVTV_DEBUG_INFO("Stopping all streams\n"); - if (atomic_read(&itv->capturing) > 0) - ivtv_stop_all_captures(itv); - - /* Stop all decoding */ - IVTV_DEBUG_INFO("Stopping decoding\n"); - - /* Turn off the TV-out */ - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) - ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0); - if (atomic_read(&itv->decoding) > 0) { - int type; - - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - type = IVTV_DEC_STREAM_TYPE_YUV; - else - type = IVTV_DEC_STREAM_TYPE_MPG; - ivtv_stop_v4l2_decode_stream(&itv->streams[type], - VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); - } - ivtv_halt_firmware(itv); - } - - /* Interrupts */ - ivtv_set_irq_mask(itv, 0xffffffff); - del_timer_sync(&itv->dma_timer); - - /* Kill irq worker */ - flush_kthread_worker(&itv->irq_worker); - kthread_stop(itv->irq_worker_task); - - ivtv_streams_cleanup(itv, 1); - ivtv_udma_free(itv); - - exit_ivtv_i2c(itv); - - free_irq(itv->pdev->irq, (void *)itv); - ivtv_iounmap(itv); - - release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); - release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - if (itv->has_cx23415) - release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); - - pci_disable_device(itv->pdev); - for (i = 0; i < IVTV_VBI_FRAMES; i++) - kfree(itv->vbi.sliced_mpeg_data[i]); - - printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name); - - v4l2_device_unregister(&itv->v4l2_dev); - kfree(itv); -} - -/* define a pci_driver for card detection */ -static struct pci_driver ivtv_pci_driver = { - .name = "ivtv", - .id_table = ivtv_pci_tbl, - .probe = ivtv_probe, - .remove = ivtv_remove, -}; - -static int __init module_start(void) -{ - printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION); - - /* Validate parameters */ - if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n", - IVTV_MAX_CARDS - 1); - return -1; - } - - if (ivtv_debug < 0 || ivtv_debug > 2047) { - ivtv_debug = 0; - printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n"); - } - - if (pci_register_driver(&ivtv_pci_driver)) { - printk(KERN_ERR "ivtv: Error detecting PCI card\n"); - return -ENODEV; - } - printk(KERN_INFO "ivtv: End initialization\n"); - return 0; -} - -static void __exit module_cleanup(void) -{ - pci_unregister_driver(&ivtv_pci_driver); -} - -/* Note: These symbols are exported because they are used by the ivtvfb - framebuffer module and an infrared module for the IR-blaster. */ -EXPORT_SYMBOL(ivtv_set_irq_mask); -EXPORT_SYMBOL(ivtv_api); -EXPORT_SYMBOL(ivtv_vapi); -EXPORT_SYMBOL(ivtv_vapi_result); -EXPORT_SYMBOL(ivtv_clear_irq_mask); -EXPORT_SYMBOL(ivtv_debug); -#ifdef CONFIG_VIDEO_ADV_DEBUG -EXPORT_SYMBOL(ivtv_fw_debug); -#endif -EXPORT_SYMBOL(ivtv_reset_ir_gpio); -EXPORT_SYMBOL(ivtv_udma_setup); -EXPORT_SYMBOL(ivtv_udma_unmap); -EXPORT_SYMBOL(ivtv_udma_alloc); -EXPORT_SYMBOL(ivtv_udma_prepare); -EXPORT_SYMBOL(ivtv_init_on_first_open); -EXPORT_SYMBOL(ivtv_firmware_check); - -module_init(module_start); -module_exit(module_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-driver.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-driver.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-driver.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-driver.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,832 +0,0 @@ -/* - ivtv driver internal defines and structures - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_DRIVER_H -#define IVTV_DRIVER_H - -/* Internal header for ivtv project: - * Driver for the cx23415/6 chip. - * Author: Kevin Thayer (nufan_wfk at yahoo.com) - * License: GPL - * http://www.ivtvdriver.org - * - * ----- - * MPG600/MPG160 support by T.Adachi - * and Takeru KOMORIYA - * - * AVerMedia M179 GPIO info by Chris Pinkham - * using information provided by Jiun-Kuei Jung @ AVerMedia. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Memory layout */ -#define IVTV_ENCODER_OFFSET 0x00000000 -#define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ -#define IVTV_DECODER_OFFSET 0x01000000 -#define IVTV_DECODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ -#define IVTV_REG_OFFSET 0x02000000 -#define IVTV_REG_SIZE 0x00010000 - -/* Maximum ivtv driver instances. Some people have a huge number of - capture cards, so set this to a high value. */ -#define IVTV_MAX_CARDS 32 - -#define IVTV_ENC_STREAM_TYPE_MPG 0 -#define IVTV_ENC_STREAM_TYPE_YUV 1 -#define IVTV_ENC_STREAM_TYPE_VBI 2 -#define IVTV_ENC_STREAM_TYPE_PCM 3 -#define IVTV_ENC_STREAM_TYPE_RAD 4 -#define IVTV_DEC_STREAM_TYPE_MPG 5 -#define IVTV_DEC_STREAM_TYPE_VBI 6 -#define IVTV_DEC_STREAM_TYPE_VOUT 7 -#define IVTV_DEC_STREAM_TYPE_YUV 8 -#define IVTV_MAX_STREAMS 9 - -#define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */ - -/* DMA Registers */ -#define IVTV_REG_DMAXFER (0x0000) -#define IVTV_REG_DMASTATUS (0x0004) -#define IVTV_REG_DECDMAADDR (0x0008) -#define IVTV_REG_ENCDMAADDR (0x000c) -#define IVTV_REG_DMACONTROL (0x0010) -#define IVTV_REG_IRQSTATUS (0x0040) -#define IVTV_REG_IRQMASK (0x0048) - -/* Setup Registers */ -#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) -#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) -#define IVTV_REG_DEC_SDRAM_REFRESH (0x08F8) -#define IVTV_REG_DEC_SDRAM_PRECHARGE (0x08FC) -#define IVTV_REG_VDM (0x2800) -#define IVTV_REG_AO (0x2D00) -#define IVTV_REG_BYTEFLUSH (0x2D24) -#define IVTV_REG_SPU (0x9050) -#define IVTV_REG_HW_BLOCKS (0x9054) -#define IVTV_REG_VPU (0x9058) -#define IVTV_REG_APU (0xA064) - -/* Other registers */ -#define IVTV_REG_DEC_LINE_FIELD (0x28C0) - -/* debugging */ -extern int ivtv_debug; -#ifdef CONFIG_VIDEO_ADV_DEBUG -extern int ivtv_fw_debug; -#endif - -#define IVTV_DBGFLG_WARN (1 << 0) -#define IVTV_DBGFLG_INFO (1 << 1) -#define IVTV_DBGFLG_MB (1 << 2) -#define IVTV_DBGFLG_IOCTL (1 << 3) -#define IVTV_DBGFLG_FILE (1 << 4) -#define IVTV_DBGFLG_DMA (1 << 5) -#define IVTV_DBGFLG_IRQ (1 << 6) -#define IVTV_DBGFLG_DEC (1 << 7) -#define IVTV_DBGFLG_YUV (1 << 8) -#define IVTV_DBGFLG_I2C (1 << 9) -/* Flag to turn on high volume debugging */ -#define IVTV_DBGFLG_HIGHVOL (1 << 10) - -#define IVTV_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtv_debug) \ - v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args); \ - } while (0) -#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args) -#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) -#define IVTV_DEBUG_MB(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_MB, "mb", fmt , ## args) -#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) -#define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_FILE(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_FILE, "file", fmt , ## args) -#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) - -#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \ - do { \ - if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \ - v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args); \ - } while (0) -#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args) -#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args) -#define IVTV_DEBUG_HI_MB(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB, "mb", fmt , ## args) -#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) -#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_HI_FILE(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE, "file", fmt , ## args) -#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) - -/* Standard kernel messages */ -#define IVTV_ERR(fmt, args...) v4l2_err(&itv->v4l2_dev, fmt , ## args) -#define IVTV_WARN(fmt, args...) v4l2_warn(&itv->v4l2_dev, fmt , ## args) -#define IVTV_INFO(fmt, args...) v4l2_info(&itv->v4l2_dev, fmt , ## args) - -/* output modes (cx23415 only) */ -#define OUT_NONE 0 -#define OUT_MPG 1 -#define OUT_YUV 2 -#define OUT_UDMA_YUV 3 -#define OUT_PASSTHROUGH 4 - -#define IVTV_MAX_PGM_INDEX (400) - -/* Default I2C SCL period in microseconds */ -#define IVTV_DEFAULT_I2C_CLOCK_PERIOD 20 - -struct ivtv_options { - int kilobytes[IVTV_MAX_STREAMS]; /* size in kilobytes of each stream */ - int cardtype; /* force card type on load */ - int tuner; /* set tuner on load */ - int radio; /* enable/disable radio */ - int newi2c; /* new I2C algorithm */ - int i2c_clock_period; /* period of SCL for I2C bus */ -}; - -/* ivtv-specific mailbox template */ -struct ivtv_mailbox { - u32 flags; - u32 cmd; - u32 retval; - u32 timeout; - u32 data[CX2341X_MBOX_MAX_DATA]; -}; - -struct ivtv_api_cache { - unsigned long last_jiffies; /* when last command was issued */ - u32 data[CX2341X_MBOX_MAX_DATA]; /* last sent api data */ -}; - -struct ivtv_mailbox_data { - volatile struct ivtv_mailbox __iomem *mbox; - /* Bits 0-2 are for the encoder mailboxes, 0-1 are for the decoder mailboxes. - If the bit is set, then the corresponding mailbox is in use by the driver. */ - unsigned long busy; - u8 max_mbox; -}; - -/* per-buffer bit flags */ -#define IVTV_F_B_NEED_BUF_SWAP (1 << 0) /* this buffer should be byte swapped */ - -/* per-stream, s_flags */ -#define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ -#define IVTV_F_S_DMA_HAS_VBI 1 /* the current DMA request also requests VBI data */ -#define IVTV_F_S_NEEDS_DATA 2 /* this decoding stream needs more data */ - -#define IVTV_F_S_CLAIMED 3 /* this stream is claimed */ -#define IVTV_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ -#define IVTV_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ -#define IVTV_F_S_PASSTHROUGH 6 /* this stream is in passthrough mode */ -#define IVTV_F_S_STREAMOFF 7 /* signal end of stream EOS */ -#define IVTV_F_S_APPL_IO 8 /* this stream is used read/written by an application */ - -#define IVTV_F_S_PIO_PENDING 9 /* this stream has pending PIO */ -#define IVTV_F_S_PIO_HAS_VBI 1 /* the current PIO request also requests VBI data */ - -/* per-ivtv, i_flags */ -#define IVTV_F_I_DMA 0 /* DMA in progress */ -#define IVTV_F_I_UDMA 1 /* UDMA in progress */ -#define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */ -#define IVTV_F_I_SPEED_CHANGE 3 /* a speed change is in progress */ -#define IVTV_F_I_EOS 4 /* end of encoder stream reached */ -#define IVTV_F_I_RADIO_USER 5 /* the radio tuner is selected */ -#define IVTV_F_I_DIG_RST 6 /* reset digitizer */ -#define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ -#define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ -#define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ -#define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */ -#define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */ -#define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */ -#define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */ -#define IVTV_F_I_HAVE_WORK 15 /* used in the interrupt handler: there is work to be done */ -#define IVTV_F_I_WORK_HANDLER_VBI 16 /* there is work to be done for VBI */ -#define IVTV_F_I_WORK_HANDLER_YUV 17 /* there is work to be done for YUV */ -#define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */ -#define IVTV_F_I_PIO 19 /* PIO in progress */ -#define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ -#define IVTV_F_I_INITED 21 /* set after first open */ -#define IVTV_F_I_FAILED 22 /* set if first open failed */ - -/* Event notifications */ -#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ -#define IVTV_F_I_EV_VSYNC 29 /* VSYNC event */ -#define IVTV_F_I_EV_VSYNC_FIELD 30 /* VSYNC event field (0 = first, 1 = second field) */ -#define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */ - -/* Scatter-Gather array element, used in DMA transfers */ -struct ivtv_sg_element { - __le32 src; - __le32 dst; - __le32 size; -}; - -struct ivtv_sg_host_element { - u32 src; - u32 dst; - u32 size; -}; - -struct ivtv_user_dma { - struct mutex lock; - int page_count; - struct page *map[IVTV_DMA_SG_OSD_ENT]; - /* Needed when dealing with highmem userspace buffers */ - struct page *bouncemap[IVTV_DMA_SG_OSD_ENT]; - - /* Base Dev SG Array for cx23415/6 */ - struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; - dma_addr_t SG_handle; - int SG_length; - - /* SG List of Buffers */ - struct scatterlist SGlist[IVTV_DMA_SG_OSD_ENT]; -}; - -struct ivtv_dma_page_info { - unsigned long uaddr; - unsigned long first; - unsigned long last; - unsigned int offset; - unsigned int tail; - int page_count; -}; - -struct ivtv_buffer { - struct list_head list; - dma_addr_t dma_handle; - unsigned short b_flags; - unsigned short dma_xfer_cnt; - char *buf; - u32 bytesused; - u32 readpos; -}; - -struct ivtv_queue { - struct list_head list; /* the list of buffers in this queue */ - u32 buffers; /* number of buffers in this queue */ - u32 length; /* total number of bytes of available buffer space */ - u32 bytesused; /* total number of bytes used in this queue */ -}; - -struct ivtv; /* forward reference */ - -struct ivtv_stream { - /* These first four fields are always set, even if the stream - is not actually created. */ - struct video_device *vdev; /* NULL when stream not created */ - struct ivtv *itv; /* for ease of use */ - const char *name; /* name of the stream */ - int type; /* stream type */ - - u32 id; - spinlock_t qlock; /* locks access to the queues */ - unsigned long s_flags; /* status flags, see above */ - int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ - u32 pending_offset; - u32 pending_backup; - u64 pending_pts; - - u32 dma_offset; - u32 dma_backup; - u64 dma_pts; - - int subtype; - wait_queue_head_t waitq; - u32 dma_last_offset; - - /* Buffer Stats */ - u32 buffers; - u32 buf_size; - u32 buffers_stolen; - - /* Buffer Queues */ - struct ivtv_queue q_free; /* free buffers */ - struct ivtv_queue q_full; /* full buffers */ - struct ivtv_queue q_io; /* waiting for I/O */ - struct ivtv_queue q_dma; /* waiting for DMA */ - struct ivtv_queue q_predma; /* waiting for DMA */ - - /* DMA xfer counter, buffers belonging to the same DMA - xfer will have the same dma_xfer_cnt. */ - u16 dma_xfer_cnt; - - /* Base Dev SG Array for cx23415/6 */ - struct ivtv_sg_host_element *sg_pending; - struct ivtv_sg_host_element *sg_processing; - struct ivtv_sg_element *sg_dma; - dma_addr_t sg_handle; - int sg_pending_size; - int sg_processing_size; - int sg_processed; - - /* SG List of Buffers */ - struct scatterlist *SGlist; -}; - -struct ivtv_open_id { - struct v4l2_fh fh; - u32 open_id; /* unique ID for this file descriptor */ - int type; /* stream type */ - int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */ - struct ivtv *itv; -}; - -static inline struct ivtv_open_id *fh2id(struct v4l2_fh *fh) -{ - return container_of(fh, struct ivtv_open_id, fh); -} - -struct yuv_frame_info -{ - u32 update; - s32 src_x; - s32 src_y; - u32 src_w; - u32 src_h; - s32 dst_x; - s32 dst_y; - u32 dst_w; - u32 dst_h; - s32 pan_x; - s32 pan_y; - u32 vis_w; - u32 vis_h; - u32 interlaced_y; - u32 interlaced_uv; - s32 tru_x; - u32 tru_w; - u32 tru_h; - u32 offset_y; - s32 lace_mode; - u32 sync_field; - u32 delay; - u32 interlaced; -}; - -#define IVTV_YUV_MODE_INTERLACED 0x00 -#define IVTV_YUV_MODE_PROGRESSIVE 0x01 -#define IVTV_YUV_MODE_AUTO 0x02 -#define IVTV_YUV_MODE_MASK 0x03 - -#define IVTV_YUV_SYNC_EVEN 0x00 -#define IVTV_YUV_SYNC_ODD 0x04 -#define IVTV_YUV_SYNC_MASK 0x04 - -#define IVTV_YUV_BUFFERS 8 - -struct yuv_playback_info -{ - u32 reg_2834; - u32 reg_2838; - u32 reg_283c; - u32 reg_2840; - u32 reg_2844; - u32 reg_2848; - u32 reg_2854; - u32 reg_285c; - u32 reg_2864; - - u32 reg_2870; - u32 reg_2874; - u32 reg_2890; - u32 reg_2898; - u32 reg_289c; - - u32 reg_2918; - u32 reg_291c; - u32 reg_2920; - u32 reg_2924; - u32 reg_2928; - u32 reg_292c; - u32 reg_2930; - - u32 reg_2934; - - u32 reg_2938; - u32 reg_293c; - u32 reg_2940; - u32 reg_2944; - u32 reg_2948; - u32 reg_294c; - u32 reg_2950; - u32 reg_2954; - u32 reg_2958; - u32 reg_295c; - u32 reg_2960; - u32 reg_2964; - u32 reg_2968; - u32 reg_296c; - - u32 reg_2970; - - int v_filter_1; - int v_filter_2; - int h_filter; - - u8 track_osd; /* Should yuv output track the OSD size & position */ - - u32 osd_x_offset; - u32 osd_y_offset; - - u32 osd_x_pan; - u32 osd_y_pan; - - u32 osd_vis_w; - u32 osd_vis_h; - - u32 osd_full_w; - u32 osd_full_h; - - int decode_height; - - int lace_mode; - int lace_threshold; - int lace_sync_field; - - atomic_t next_dma_frame; - atomic_t next_fill_frame; - - u32 yuv_forced_update; - int update_frame; - - u8 fields_lapsed; /* Counter used when delaying a frame */ - - struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS]; - struct yuv_frame_info old_frame_info; - struct yuv_frame_info old_frame_info_args; - - void *blanking_ptr; - dma_addr_t blanking_dmaptr; - - int stream_size; - - u8 draw_frame; /* PVR350 buffer to draw into */ - u8 max_frames_buffered; /* Maximum number of frames to buffer */ - - struct v4l2_rect main_rect; - u32 v4l2_src_w; - u32 v4l2_src_h; - - u8 running; /* Have any frames been displayed */ -}; - -#define IVTV_VBI_FRAMES 32 - -/* VBI data */ -struct vbi_cc { - u8 odd[2]; /* two-byte payload of odd field */ - u8 even[2]; /* two-byte payload of even field */; -}; - -struct vbi_vps { - u8 data[5]; /* five-byte VPS payload */ -}; - -struct vbi_info { - /* VBI general data, does not change during streaming */ - - u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ - u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */ - u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */ - u32 sliced_decoder_line_size; /* sliced VBI line size from digitizer */ - u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */ - u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */ - - u32 start[2]; /* start of first VBI line in the odd/even fields */ - u32 count; /* number of VBI lines per field */ - u32 raw_size; /* size of raw VBI line from the digitizer */ - u32 sliced_size; /* size of sliced VBI line from the digitizer */ - - u32 dec_start; /* start in decoder memory of VBI re-insertion buffers */ - u32 enc_start; /* start in encoder memory of VBI capture buffers */ - u32 enc_size; /* size of VBI capture area */ - int fpi; /* number of VBI frames per interrupt */ - - struct v4l2_format in; /* current VBI capture format */ - struct v4l2_sliced_vbi_format *sliced_in; /* convenience pointer to sliced struct in vbi.in union */ - int insert_mpeg; /* if non-zero, then embed VBI data in MPEG stream */ - - /* Raw VBI compatibility hack */ - - u32 frame; /* frame counter hack needed for backwards compatibility - of old VBI software */ - - /* Sliced VBI output data */ - - struct vbi_cc cc_payload[256]; /* sliced VBI CC payload array: it is an array to - prevent dropping CC data if they couldn't be - processed fast enough */ - int cc_payload_idx; /* index in cc_payload */ - u8 cc_missing_cnt; /* counts number of frames without CC for passthrough mode */ - int wss_payload; /* sliced VBI WSS payload */ - u8 wss_missing_cnt; /* counts number of frames without WSS for passthrough mode */ - struct vbi_vps vps_payload; /* sliced VBI VPS payload */ - - /* Sliced VBI capture data */ - - struct v4l2_sliced_vbi_data sliced_data[36]; /* sliced VBI storage for VBI encoder stream */ - struct v4l2_sliced_vbi_data sliced_dec_data[36];/* sliced VBI storage for VBI decoder stream */ - - /* VBI Embedding data */ - - /* Buffer for VBI data inserted into MPEG stream. - The first byte is a dummy byte that's never used. - The next 16 bytes contain the MPEG header for the VBI data, - the remainder is the actual VBI data. - The max size accepted by the MPEG VBI reinsertion turns out - to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes, - where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is - a single line header byte and 2 * 18 is the number of VBI lines per frame. - - However, it seems that the data must be 1K aligned, so we have to - pad the data until the 1 or 2 K boundary. - - This pointer array will allocate 2049 bytes to store each VBI frame. */ - u8 *sliced_mpeg_data[IVTV_VBI_FRAMES]; - u32 sliced_mpeg_size[IVTV_VBI_FRAMES]; - struct ivtv_buffer sliced_mpeg_buf; /* temporary buffer holding data from sliced_mpeg_data */ - u32 inserted_frame; /* index in sliced_mpeg_size of next sliced data - to be inserted in the MPEG stream */ -}; - -/* forward declaration of struct defined in ivtv-cards.h */ -struct ivtv_card; - -/* Struct to hold info about ivtv cards */ -struct ivtv { - /* General fixed card data */ - struct pci_dev *pdev; /* PCI device */ - const struct ivtv_card *card; /* card information */ - const char *card_name; /* full name of the card */ - const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ - u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ - u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ - u8 nof_inputs; /* number of video inputs */ - u8 nof_audio_inputs; /* number of audio inputs */ - u32 v4l2_cap; /* V4L2 capabilities of card */ - u32 hw_flags; /* hardware description of the board */ - v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */ - struct v4l2_subdev *sd_video; /* controlling video decoder subdev */ - struct v4l2_subdev *sd_audio; /* controlling audio subdev */ - struct v4l2_subdev *sd_muxer; /* controlling audio muxer subdev */ - u32 base_addr; /* PCI resource base address */ - volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */ - volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */ - volatile void __iomem *reg_mem; /* pointer to mapped registers */ - struct ivtv_options options; /* user options */ - - struct v4l2_device v4l2_dev; - struct cx2341x_handler cxhdl; - struct v4l2_ctrl_handler hdl_gpio; - struct v4l2_subdev sd_gpio; /* GPIO sub-device */ - u16 instance; - - /* High-level state info */ - unsigned long i_flags; /* global ivtv flags */ - u8 is_50hz; /* 1 if the current capture standard is 50 Hz */ - u8 is_60hz /* 1 if the current capture standard is 60 Hz */; - u8 is_out_50hz /* 1 if the current TV output standard is 50 Hz */; - u8 is_out_60hz /* 1 if the current TV output standard is 60 Hz */; - int output_mode; /* decoder output mode: NONE, MPG, YUV, UDMA YUV, passthrough */ - u32 audio_input; /* current audio input */ - u32 active_input; /* current video input */ - u32 active_output; /* current video output */ - v4l2_std_id std; /* current capture TV standard */ - v4l2_std_id std_out; /* current TV output standard */ - u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */ - u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */ - - - /* Locking */ - spinlock_t lock; /* lock access to this struct */ - struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ - - /* Streams */ - int stream_buf_size[IVTV_MAX_STREAMS]; /* stream buffer size */ - struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* stream data */ - atomic_t capturing; /* count number of active capture streams */ - atomic_t decoding; /* count number of active decoding streams */ - - - /* Interrupts & DMA */ - u32 irqmask; /* active interrupts */ - u32 irq_rr_idx; /* round-robin stream index */ - struct kthread_worker irq_worker; /* kthread worker for PIO/YUV/VBI actions */ - struct task_struct *irq_worker_task; /* task for irq_worker */ - struct kthread_work irq_work; /* kthread work entry */ - spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ - int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */ - int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */ - u32 dma_data_req_offset; /* store offset in decoder memory of current DMA request */ - u32 dma_data_req_size; /* store size of current DMA request */ - int dma_retries; /* current DMA retry attempt */ - struct ivtv_user_dma udma; /* user based DMA for OSD */ - struct timer_list dma_timer; /* timer used to catch unfinished DMAs */ - u32 last_vsync_field; /* last seen vsync field */ - wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */ - wait_queue_head_t eos_waitq; /* wake up when EOS arrives */ - wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */ - wait_queue_head_t vsync_waitq; /* wake up when the next decoder vsync arrives */ - - - /* Mailbox */ - struct ivtv_mailbox_data enc_mbox; /* encoder mailboxes */ - struct ivtv_mailbox_data dec_mbox; /* decoder mailboxes */ - struct ivtv_api_cache api_cache[256]; /* cached API commands */ - - - /* I2C */ - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - int i2c_state; /* i2c bit state */ - struct mutex i2c_bus_lock; /* lock i2c bus */ - - struct IR_i2c_init_data ir_i2c_init_data; - - /* Program Index information */ - u32 pgm_info_offset; /* start of pgm info in encoder memory */ - u32 pgm_info_num; /* number of elements in the pgm cyclic buffer in encoder memory */ - u32 pgm_info_write_idx; /* last index written by the card that was transferred to pgm_info[] */ - u32 pgm_info_read_idx; /* last index in pgm_info read by the application */ - struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; /* filled from the pgm cyclic buffer on the card */ - - - /* Miscellaneous */ - u32 open_id; /* incremented each time an open occurs, is >= 1 */ - int search_pack_header; /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */ - int speed; /* current playback speed setting */ - u8 speed_mute_audio; /* 1 if audio should be muted when fast forward */ - u64 mpg_data_received; /* number of bytes received from the MPEG stream */ - u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */ - u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */ - unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */ - u32 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */ - - - /* VBI state info */ - struct vbi_info vbi; /* VBI-specific data */ - - - /* YUV playback */ - struct yuv_playback_info yuv_info; /* YUV playback data */ - - - /* OSD support */ - unsigned long osd_video_pbase; - int osd_global_alpha_state; /* 1 = global alpha is on */ - int osd_local_alpha_state; /* 1 = local alpha is on */ - int osd_chroma_key_state; /* 1 = chroma-keying is on */ - u8 osd_global_alpha; /* current global alpha */ - u32 osd_chroma_key; /* current chroma key */ - struct v4l2_rect osd_rect; /* current OSD position and size */ - struct v4l2_rect main_rect; /* current Main window position and size */ - struct osd_info *osd_info; /* ivtvfb private OSD info */ - void (*ivtvfb_restore)(struct ivtv *itv); /* Used for a warm start */ -}; - -static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct ivtv, v4l2_dev); -} - -/* Globals */ -extern int ivtv_first_minor; - -/*==============Prototypes==================*/ - -/* Hardware/IRQ */ -void ivtv_set_irq_mask(struct ivtv *itv, u32 mask); -void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask); - -/* try to set output mode, return current mode. */ -int ivtv_set_output_mode(struct ivtv *itv, int mode); - -/* return current output stream based on current mode */ -struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv); - -/* Return non-zero if a signal is pending */ -int ivtv_msleep_timeout(unsigned int msecs, int intr); - -/* Wait on queue, returns -EINTR if interrupted */ -int ivtv_waitq(wait_queue_head_t *waitq); - -/* Read Hauppauge eeprom */ -struct tveeprom; /* forward reference */ -void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv); - -/* First-open initialization: load firmware, init cx25840, etc. */ -int ivtv_init_on_first_open(struct ivtv *itv); - -/* Test if the current VBI mode is raw (1) or sliced (0) */ -static inline int ivtv_raw_vbi(const struct ivtv *itv) -{ - return itv->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE; -} - -/* This is a PCI post thing, where if the pci register is not read, then - the write doesn't always take effect right away. By reading back the - register any pending PCI writes will be performed (in order), and so - you can be sure that the writes are guaranteed to be done. - - Rarely needed, only in some timing sensitive cases. - Apparently if this is not done some motherboards seem - to kill the firmware and get into the broken state until computer is - rebooted. */ -#define write_sync(val, reg) \ - do { writel(val, reg); readl(reg); } while (0) - -#define read_reg(reg) readl(itv->reg_mem + (reg)) -#define write_reg(val, reg) writel(val, itv->reg_mem + (reg)) -#define write_reg_sync(val, reg) \ - do { write_reg(val, reg); read_reg(reg); } while (0) - -#define read_enc(addr) readl(itv->enc_mem + (u32)(addr)) -#define write_enc(val, addr) writel(val, itv->enc_mem + (u32)(addr)) -#define write_enc_sync(val, addr) \ - do { write_enc(val, addr); read_enc(addr); } while (0) - -#define read_dec(addr) readl(itv->dec_mem + (u32)(addr)) -#define write_dec(val, addr) writel(val, itv->dec_mem + (u32)(addr)) -#define write_dec_sync(val, addr) \ - do { write_dec(val, addr); read_dec(addr); } while (0) - -/* Call the specified callback for all subdevs matching hw (if 0, then - match them all). Ignore any errors. */ -#define ivtv_call_hw(itv, hw, o, f, args...) \ - do { \ - struct v4l2_subdev *__sd; \ - __v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd, \ - !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ - } while (0) - -#define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args) - -/* Call the specified callback for all subdevs matching hw (if 0, then - match them all). If the callback returns an error other than 0 or - -ENOIOCTLCMD, then return with that error code. */ -#define ivtv_call_hw_err(itv, hw, o, f, args...) \ -({ \ - struct v4l2_subdev *__sd; \ - __v4l2_device_call_subdevs_until_err_p(&(itv)->v4l2_dev, __sd, \ - !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ -}) - -#define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtvfb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtvfb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtvfb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtvfb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1310 +0,0 @@ -/* - On Screen Display cx23415 Framebuffer driver - - This module presents the cx23415 OSD (onscreen display) framebuffer memory - as a standard Linux /dev/fb style framebuffer device. The framebuffer has - support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp - mode, there is a choice of a three color depths (12, 15 or 16 bits), but no - local alpha. The colorspace is selectable between rgb & yuv. - Depending on the TV standard configured in the ivtv module at load time, - the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. - Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) - or 59.94 (NTSC) - - Copyright (c) 2003 Matt T. Yourst - - Derived from drivers/video/vesafb.c - Portions (c) 1998 Gerd Knorr - - 2.6 kernel port: - Copyright (C) 2004 Matthias Badaire - - Copyright (C) 2004 Chris Kennedy - - Copyright (C) 2006 Ian Armstrong - - 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, or - (at your option) any later version. - - 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 -#include -#include -#include -#include - -#ifdef CONFIG_MTRR -#include -#endif - -#include "ivtv-driver.h" -#include "ivtv-cards.h" -#include "ivtv-i2c.h" -#include "ivtv-udma.h" -#include "ivtv-mailbox.h" -#include "ivtv-firmware.h" - -/* card parameters */ -static int ivtvfb_card_id = -1; -static int ivtvfb_debug = 0; -static int osd_laced; -static int osd_depth; -static int osd_upper; -static int osd_left; -static int osd_yres; -static int osd_xres; - -module_param(ivtvfb_card_id, int, 0444); -module_param_named(debug,ivtvfb_debug, int, 0644); -module_param(osd_laced, bool, 0444); -module_param(osd_depth, int, 0444); -module_param(osd_upper, int, 0444); -module_param(osd_left, int, 0444); -module_param(osd_yres, int, 0444); -module_param(osd_xres, int, 0444); - -MODULE_PARM_DESC(ivtvfb_card_id, - "Only use framebuffer of the specified ivtv card (0-31)\n" - "\t\t\tdefault -1: initialize all available framebuffers"); - -MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: errors only\n" - "\t\t\t(debug = 3 gives full debugging)"); - -/* Why upper, left, xres, yres, depth, laced ? To match terminology used - by fbset. - Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ - -MODULE_PARM_DESC(osd_laced, - "Interlaced mode\n" - "\t\t\t0=off\n" - "\t\t\t1=on\n" - "\t\t\tdefault off"); - -MODULE_PARM_DESC(osd_depth, - "Bits per pixel - 8, 16, 32\n" - "\t\t\tdefault 8"); - -MODULE_PARM_DESC(osd_upper, - "Vertical start position\n" - "\t\t\tdefault 0 (Centered)"); - -MODULE_PARM_DESC(osd_left, - "Horizontal start position\n" - "\t\t\tdefault 0 (Centered)"); - -MODULE_PARM_DESC(osd_yres, - "Display height\n" - "\t\t\tdefault 480 (PAL)\n" - "\t\t\t 400 (NTSC)"); - -MODULE_PARM_DESC(osd_xres, - "Display width\n" - "\t\t\tdefault 640"); - -MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); -MODULE_LICENSE("GPL"); - -/* --------------------------------------------------------------------- */ - -#define IVTVFB_DBGFLG_WARN (1 << 0) -#define IVTVFB_DBGFLG_INFO (1 << 1) - -#define IVTVFB_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtvfb_debug) \ - printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \ - } while (0) -#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args) - -/* Standard kernel messages */ -#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->instance , ## args) -#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->instance , ## args) -#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args) - -/* --------------------------------------------------------------------- */ - -#define IVTV_OSD_MAX_WIDTH 720 -#define IVTV_OSD_MAX_HEIGHT 576 - -#define IVTV_OSD_BPP_8 0x00 -#define IVTV_OSD_BPP_16_444 0x03 -#define IVTV_OSD_BPP_16_555 0x02 -#define IVTV_OSD_BPP_16_565 0x01 -#define IVTV_OSD_BPP_32 0x04 - -struct osd_info { - /* Physical base address */ - unsigned long video_pbase; - /* Relative base address (relative to start of decoder memory) */ - u32 video_rbase; - /* Mapped base address */ - volatile char __iomem *video_vbase; - /* Buffer size */ - u32 video_buffer_size; - -#ifdef CONFIG_MTRR - /* video_base rounded down as required by hardware MTRRs */ - unsigned long fb_start_aligned_physaddr; - /* video_base rounded up as required by hardware MTRRs */ - unsigned long fb_end_aligned_physaddr; -#endif - - /* Store the buffer offset */ - int set_osd_coords_x; - int set_osd_coords_y; - - /* Current dimensions (NOT VISIBLE SIZE!) */ - int display_width; - int display_height; - int display_byte_stride; - - /* Current bits per pixel */ - int bits_per_pixel; - int bytes_per_pixel; - - /* Frame buffer stuff */ - struct fb_info ivtvfb_info; - struct fb_var_screeninfo ivtvfb_defined; - struct fb_fix_screeninfo ivtvfb_fix; - - /* Used for a warm start */ - struct fb_var_screeninfo fbvar_cur; - int blank_cur; - u32 palette_cur[256]; - u32 pan_cur; -}; - -struct ivtv_osd_coords { - unsigned long offset; - unsigned long max_offset; - int pixel_stride; - int lines; - int x; - int y; -}; - -/* --------------------------------------------------------------------- */ - -/* ivtv API calls for framebuffer related support */ - -static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase, - u32 *fblength) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - int rc; - - ivtv_firmware_check(itv, "ivtvfb_get_framebuffer"); - rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); - *fbbase = data[0]; - *fblength = data[1]; - return rc; -} - -static int ivtvfb_get_osd_coords(struct ivtv *itv, - struct ivtv_osd_coords *osd) -{ - struct osd_info *oi = itv->osd_info; - u32 data[CX2341X_MBOX_MAX_DATA]; - - ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); - - osd->offset = data[0] - oi->video_rbase; - osd->max_offset = oi->display_width * oi->display_height * 4; - osd->pixel_stride = data[1]; - osd->lines = data[2]; - osd->x = data[3]; - osd->y = data[4]; - return 0; -} - -static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) -{ - struct osd_info *oi = itv->osd_info; - - oi->display_width = osd->pixel_stride; - oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel; - oi->set_osd_coords_x += osd->x; - oi->set_osd_coords_y = osd->y; - - return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, - osd->offset + oi->video_rbase, - osd->pixel_stride, - osd->lines, osd->x, osd->y); -} - -static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) -{ - int osd_height_limit = itv->is_50hz ? 576 : 480; - - /* Only fail if resolution too high, otherwise fudge the start coords. */ - if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) - return -EINVAL; - - /* Ensure we don't exceed display limits */ - if (ivtv_window->top + ivtv_window->height > osd_height_limit) { - IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", - ivtv_window->top, ivtv_window->height); - ivtv_window->top = osd_height_limit - ivtv_window->height; - } - - if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { - IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", - ivtv_window->left, ivtv_window->width); - ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; - } - - /* Set the OSD origin */ - write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); - - /* How much to display */ - write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); - - /* Pass this info back the yuv handler */ - itv->yuv_info.osd_vis_w = ivtv_window->width; - itv->yuv_info.osd_vis_h = ivtv_window->height; - itv->yuv_info.osd_x_offset = ivtv_window->left; - itv->yuv_info.osd_y_offset = ivtv_window->top; - - return 0; -} - -static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv, - unsigned long ivtv_dest_addr, void __user *userbuf, - int size_in_bytes) -{ - DEFINE_WAIT(wait); - int got_sig = 0; - - mutex_lock(&itv->udma.lock); - /* Map User DMA */ - if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { - mutex_unlock(&itv->udma.lock); - IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, " - "Error with get_user_pages: %d bytes, %d pages returned\n", - size_in_bytes, itv->udma.page_count); - - /* get_user_pages must have failed completely */ - return -EIO; - } - - IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", - size_in_bytes, itv->udma.page_count); - - ivtv_udma_prepare(itv); - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); - /* if no UDMA is pending and no UDMA is in progress, then the DMA - is finished */ - while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) || - test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - /* don't interrupt if the DMA is in progress but break off - a still pending DMA. */ - got_sig = signal_pending(current); - if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) - break; - got_sig = 0; - schedule(); - } - finish_wait(&itv->dma_waitq, &wait); - - /* Unmap Last DMA Xfer */ - ivtv_udma_unmap(itv); - mutex_unlock(&itv->udma.lock); - if (got_sig) { - IVTV_DEBUG_INFO("User stopped OSD\n"); - return -EINTR; - } - - return 0; -} - -static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, - unsigned long dest_offset, int count) -{ - DEFINE_WAIT(wait); - struct osd_info *oi = itv->osd_info; - - /* Nothing to do */ - if (count == 0) { - IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n"); - return -EINVAL; - } - - /* Check Total FB Size */ - if ((dest_offset + count) > oi->video_buffer_size) { - IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", - dest_offset + count, oi->video_buffer_size); - return -E2BIG; - } - - /* Not fatal, but will have undesirable results */ - if ((unsigned long)source & 3) - IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", - (unsigned long)source); - - if (dest_offset & 3) - IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); - - if (count & 3) - IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count); - - /* Check Source */ - if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n", - (unsigned long)source); - - IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", - dest_offset, (unsigned long)source, - count); - return -EINVAL; - } - - /* OSD Address to send DMA to */ - dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; - - /* Fill Buffers */ - return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count); -} - -static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long p = *ppos; - void *dst; - int err = 0; - int dma_err; - unsigned long total_size; - struct ivtv *itv = (struct ivtv *) info->par; - unsigned long dma_offset = - IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; - unsigned long dma_size; - u16 lead = 0, tail = 0; - - if (info->state != FBINFO_STATE_RUNNING) - return -EPERM; - - total_size = info->screen_size; - - if (total_size == 0) - total_size = info->fix.smem_len; - - if (p > total_size) - return -EFBIG; - - if (count > total_size) { - err = -EFBIG; - count = total_size; - } - - if (count + p > total_size) { - if (!err) - err = -ENOSPC; - count = total_size - p; - } - - dst = (void __force *) (info->screen_base + p); - - if (info->fbops->fb_sync) - info->fbops->fb_sync(info); - - /* If transfer size > threshold and both src/dst - addresses are aligned, use DMA */ - if (count >= 4096 && - ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) { - /* Odd address = can't DMA. Align */ - if ((unsigned long)dst & 3) { - lead = 4 - ((unsigned long)dst & 3); - if (copy_from_user(dst, buf, lead)) - return -EFAULT; - buf += lead; - dst += lead; - } - /* DMA resolution is 32 bits */ - if ((count - lead) & 3) - tail = (count - lead) & 3; - /* DMA the data */ - dma_size = count - lead - tail; - dma_err = ivtvfb_prep_dec_dma_to_device(itv, - p + lead + dma_offset, (void __user *)buf, dma_size); - if (dma_err) - return dma_err; - dst += dma_size; - buf += dma_size; - /* Copy any leftover data */ - if (tail && copy_from_user(dst, buf, tail)) - return -EFAULT; - } else if (copy_from_user(dst, buf, count)) { - return -EFAULT; - } - - if (!err) - *ppos += count; - - return (err) ? err : count; -} - -static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) -{ - DEFINE_WAIT(wait); - struct ivtv *itv = (struct ivtv *)info->par; - int rc = 0; - - switch (cmd) { - case FBIOGET_VBLANK: { - struct fb_vblank vblank; - u32 trace; - - memset(&vblank, 0, sizeof(struct fb_vblank)); - - vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | - FB_VBLANK_HAVE_VSYNC; - trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16; - if (itv->is_50hz && trace > 312) - trace -= 312; - else if (itv->is_60hz && trace > 262) - trace -= 262; - if (trace == 1) - vblank.flags |= FB_VBLANK_VSYNCING; - vblank.count = itv->last_vsync_field; - vblank.vcount = trace; - vblank.hcount = 0; - if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) - return -EFAULT; - return 0; - } - - case FBIO_WAITFORVSYNC: - prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); - if (!schedule_timeout(msecs_to_jiffies(50))) - rc = -ETIMEDOUT; - finish_wait(&itv->vsync_waitq, &wait); - return rc; - - case IVTVFB_IOC_DMA_FRAME: { - struct ivtvfb_dma_frame args; - - IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); - if (copy_from_user(&args, (void __user *)arg, sizeof(args))) - return -EFAULT; - - return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); - } - - default: - IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); - return -EINVAL; - } - return 0; -} - -/* Framebuffer device handling */ - -static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) -{ - struct osd_info *oi = itv->osd_info; - struct ivtv_osd_coords ivtv_osd; - struct v4l2_rect ivtv_window; - int osd_mode = -1; - - IVTVFB_DEBUG_INFO("ivtvfb_set_var\n"); - - /* Select color space */ - if (var->nonstd) /* YUV */ - write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); - else /* RGB */ - write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); - - /* Set the color mode */ - switch (var->bits_per_pixel) { - case 8: - osd_mode = IVTV_OSD_BPP_8; - break; - case 32: - osd_mode = IVTV_OSD_BPP_32; - break; - case 16: - switch (var->green.length) { - case 4: - osd_mode = IVTV_OSD_BPP_16_444; - break; - case 5: - osd_mode = IVTV_OSD_BPP_16_555; - break; - case 6: - osd_mode = IVTV_OSD_BPP_16_565; - break; - default: - IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); - } - break; - default: - IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); - } - - /* Set video mode. Although rare, the display can become scrambled even - if we don't change mode. Always 'bounce' to osd_mode via mode 0 */ - if (osd_mode != -1) { - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode); - } - - oi->bits_per_pixel = var->bits_per_pixel; - oi->bytes_per_pixel = var->bits_per_pixel / 8; - - /* Set the flicker filter */ - switch (var->vmode & FB_VMODE_MASK) { - case FB_VMODE_NONINTERLACED: /* Filter on */ - ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); - break; - case FB_VMODE_INTERLACED: /* Filter off */ - ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); - break; - default: - IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); - } - - /* Read the current osd info */ - ivtvfb_get_osd_coords(itv, &ivtv_osd); - - /* Now set the OSD to the size we want */ - ivtv_osd.pixel_stride = var->xres_virtual; - ivtv_osd.lines = var->yres_virtual; - ivtv_osd.x = 0; - ivtv_osd.y = 0; - ivtvfb_set_osd_coords(itv, &ivtv_osd); - - /* Can't seem to find the right API combo for this. - Use another function which does what we need through direct register access. */ - ivtv_window.width = var->xres; - ivtv_window.height = var->yres; - - /* Minimum margin cannot be 0, as X won't allow such a mode */ - if (!var->upper_margin) - var->upper_margin++; - if (!var->left_margin) - var->left_margin++; - ivtv_window.top = var->upper_margin - 1; - ivtv_window.left = var->left_margin - 1; - - ivtvfb_set_display_window(itv, &ivtv_window); - - /* Pass screen size back to yuv handler */ - itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride; - itv->yuv_info.osd_full_h = ivtv_osd.lines; - - /* Force update of yuv registers */ - itv->yuv_info.yuv_forced_update = 1; - - /* Keep a copy of these settings */ - memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur)); - - IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", - var->xres, var->yres, - var->xres_virtual, var->yres_virtual, - var->bits_per_pixel); - - IVTVFB_DEBUG_INFO("Display position: %d, %d\n", - var->left_margin, var->upper_margin); - - IVTVFB_DEBUG_INFO("Display filter: %s\n", - (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); - - return 0; -} - -static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) -{ - struct osd_info *oi = itv->osd_info; - - IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n"); - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id)); - fix->smem_start = oi->video_pbase; - fix->smem_len = oi->video_buffer_size; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - fix->xpanstep = 1; - fix->ypanstep = 1; - fix->ywrapstep = 0; - fix->line_length = oi->display_byte_stride; - fix->accel = FB_ACCEL_NONE; - return 0; -} - -/* Check the requested display mode, returning -EINVAL if we can't - handle it. */ - -static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - int osd_height_limit; - u32 pixclock, hlimit, vlimit; - - IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); - - /* Set base references for mode calcs. */ - if (itv->is_50hz) { - pixclock = 84316; - hlimit = 776; - vlimit = 591; - osd_height_limit = 576; - } - else { - pixclock = 83926; - hlimit = 776; - vlimit = 495; - osd_height_limit = 480; - } - - if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { - var->transp.offset = 24; - var->transp.length = 8; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - } - else if (var->bits_per_pixel == 16) { - /* To find out the true mode, check green length */ - switch (var->green.length) { - case 4: - var->red.offset = 8; - var->red.length = 4; - var->green.offset = 4; - var->green.length = 4; - var->blue.offset = 0; - var->blue.length = 4; - var->transp.offset = 12; - var->transp.length = 1; - break; - case 5: - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 15; - var->transp.length = 1; - break; - default: - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; - } - } - else { - IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); - return -EINVAL; - } - - /* Check the resolution */ - if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { - IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n", - var->xres, var->yres); - return -EINVAL; - } - - /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ - if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || - var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || - var->xres_virtual < var->xres || - var->yres_virtual < var->yres) { - IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", - var->xres_virtual, var->yres_virtual); - return -EINVAL; - } - - /* Some extra checks if in 8 bit mode */ - if (var->bits_per_pixel == 8) { - /* Width must be a multiple of 4 */ - if (var->xres & 3) { - IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); - return -EINVAL; - } - if (var->xres_virtual & 3) { - IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); - return -EINVAL; - } - } - else if (var->bits_per_pixel == 16) { - /* Width must be a multiple of 2 */ - if (var->xres & 1) { - IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); - return -EINVAL; - } - if (var->xres_virtual & 1) { - IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); - return -EINVAL; - } - } - - /* Now check the offsets */ - if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { - IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", - var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); - return -EINVAL; - } - - /* Check pixel format */ - if (var->nonstd > 1) { - IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); - return -EINVAL; - } - - /* Check video mode */ - if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && - ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { - IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); - return -EINVAL; - } - - /* Check the left & upper margins - If the margins are too large, just center the screen - (enforcing margins causes too many problems) */ - - if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) { - var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); - } - if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) { - var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2); - } - - /* Maintain overall 'size' for a constant refresh rate */ - var->right_margin = hlimit - var->left_margin - var->xres; - var->lower_margin = vlimit - var->upper_margin - var->yres; - - /* Fixed sync times */ - var->hsync_len = 24; - var->vsync_len = 2; - - /* Non-interlaced / interlaced mode is used to switch the OSD filter - on or off. Adjust the clock timings to maintain a constant - vertical refresh rate. */ - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) - var->pixclock = pixclock / 2; - else - var->pixclock = pixclock; - - itv->osd_rect.width = var->xres; - itv->osd_rect.height = var->yres; - - IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", - var->xres, var->yres, - var->xres_virtual, var->yres_virtual, - var->bits_per_pixel); - - IVTVFB_DEBUG_INFO("Display position: %d, %d\n", - var->left_margin, var->upper_margin); - - IVTVFB_DEBUG_INFO("Display filter: %s\n", - (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); - return 0; -} - -static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct ivtv *itv = (struct ivtv *) info->par; - IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); - return _ivtvfb_check_var(var, itv); -} - -static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -{ - u32 osd_pan_index; - struct ivtv *itv = (struct ivtv *) info->par; - - osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; - write_reg(osd_pan_index, 0x02A0C); - - /* Pass this info back the yuv handler */ - itv->yuv_info.osd_x_pan = var->xoffset; - itv->yuv_info.osd_y_pan = var->yoffset; - /* Force update of yuv registers */ - itv->yuv_info.yuv_forced_update = 1; - /* Remember this value */ - itv->osd_info->pan_cur = osd_pan_index; - return 0; -} - -static int ivtvfb_set_par(struct fb_info *info) -{ - int rc = 0; - struct ivtv *itv = (struct ivtv *) info->par; - - IVTVFB_DEBUG_INFO("ivtvfb_set_par\n"); - - rc = ivtvfb_set_var(itv, &info->var); - ivtvfb_pan_display(&info->var, info); - ivtvfb_get_fix(itv, &info->fix); - ivtv_firmware_check(itv, "ivtvfb_set_par"); - return rc; -} - -static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - u32 color, *palette; - struct ivtv *itv = (struct ivtv *)info->par; - - if (regno >= info->cmap.len) - return -EINVAL; - - color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); - if (info->var.bits_per_pixel <= 8) { - write_reg(regno, 0x02a30); - write_reg(color, 0x02a34); - itv->osd_info->palette_cur[regno] = color; - return 0; - } - if (regno >= 16) - return -EINVAL; - - palette = info->pseudo_palette; - if (info->var.bits_per_pixel == 16) { - switch (info->var.green.length) { - case 4: - color = ((red & 0xf000) >> 4) | - ((green & 0xf000) >> 8) | - ((blue & 0xf000) >> 12); - break; - case 5: - color = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 6: - color = (red & 0xf800 ) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - } - } - palette[regno] = color; - return 0; -} - -/* We don't really support blanking. All this does is enable or - disable the OSD. */ -static int ivtvfb_blank(int blank_mode, struct fb_info *info) -{ - struct ivtv *itv = (struct ivtv *)info->par; - - IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); - switch (blank_mode) { - case FB_BLANK_UNBLANK: - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); - ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1); - break; - case FB_BLANK_NORMAL: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_VSYNC_SUSPEND: - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); - ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1); - break; - case FB_BLANK_POWERDOWN: - ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); - break; - } - itv->osd_info->blank_cur = blank_mode; - return 0; -} - -static struct fb_ops ivtvfb_ops = { - .owner = THIS_MODULE, - .fb_write = ivtvfb_write, - .fb_check_var = ivtvfb_check_var, - .fb_set_par = ivtvfb_set_par, - .fb_setcolreg = ivtvfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_cursor = NULL, - .fb_ioctl = ivtvfb_ioctl, - .fb_pan_display = ivtvfb_pan_display, - .fb_blank = ivtvfb_blank, -}; - -/* Restore hardware after firmware restart */ -static void ivtvfb_restore(struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - int i; - - ivtvfb_set_var(itv, &oi->fbvar_cur); - ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info); - for (i = 0; i < 256; i++) { - write_reg(i, 0x02a30); - write_reg(oi->palette_cur[i], 0x02a34); - } - write_reg(oi->pan_cur, 0x02a0c); -} - -/* Initialization */ - - -/* Setup our initial video mode */ -static int ivtvfb_init_vidmode(struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - struct v4l2_rect start_window; - int max_height; - - /* Color mode */ - - if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) - osd_depth = 8; - oi->bits_per_pixel = osd_depth; - oi->bytes_per_pixel = oi->bits_per_pixel / 8; - - /* Horizontal size & position */ - - if (osd_xres > 720) - osd_xres = 720; - - /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ - if (osd_depth == 8) - osd_xres &= ~3; - else if (osd_depth == 16) - osd_xres &= ~1; - - start_window.width = osd_xres ? osd_xres : 640; - - /* Check horizontal start (osd_left). */ - if (osd_left && osd_left + start_window.width > 721) { - IVTVFB_ERR("Invalid osd_left - assuming default\n"); - osd_left = 0; - } - - /* Hardware coords start at 0, user coords start at 1. */ - osd_left--; - - start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); - - oi->display_byte_stride = - start_window.width * oi->bytes_per_pixel; - - /* Vertical size & position */ - - max_height = itv->is_50hz ? 576 : 480; - - if (osd_yres > max_height) - osd_yres = max_height; - - start_window.height = osd_yres ? osd_yres : itv->is_50hz ? 480 : 400; - - /* Check vertical start (osd_upper). */ - if (osd_upper + start_window.height > max_height + 1) { - IVTVFB_ERR("Invalid osd_upper - assuming default\n"); - osd_upper = 0; - } - - /* Hardware coords start at 0, user coords start at 1. */ - osd_upper--; - - start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); - - oi->display_width = start_window.width; - oi->display_height = start_window.height; - - /* Generate a valid fb_var_screeninfo */ - - oi->ivtvfb_defined.xres = oi->display_width; - oi->ivtvfb_defined.yres = oi->display_height; - oi->ivtvfb_defined.xres_virtual = oi->display_width; - oi->ivtvfb_defined.yres_virtual = oi->display_height; - oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; - oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); - oi->ivtvfb_defined.left_margin = start_window.left + 1; - oi->ivtvfb_defined.upper_margin = start_window.top + 1; - oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; - oi->ivtvfb_defined.nonstd = 0; - - /* We've filled in the most data, let the usual mode check - routine fill in the rest. */ - _ivtvfb_check_var(&oi->ivtvfb_defined, itv); - - /* Generate valid fb_fix_screeninfo */ - - ivtvfb_get_fix(itv, &oi->ivtvfb_fix); - - /* Generate valid fb_info */ - - oi->ivtvfb_info.node = -1; - oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; - oi->ivtvfb_info.fbops = &ivtvfb_ops; - oi->ivtvfb_info.par = itv; - oi->ivtvfb_info.var = oi->ivtvfb_defined; - oi->ivtvfb_info.fix = oi->ivtvfb_fix; - oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; - oi->ivtvfb_info.fbops = &ivtvfb_ops; - - /* Supply some monitor specs. Bogus values will do for now */ - oi->ivtvfb_info.monspecs.hfmin = 8000; - oi->ivtvfb_info.monspecs.hfmax = 70000; - oi->ivtvfb_info.monspecs.vfmin = 10; - oi->ivtvfb_info.monspecs.vfmax = 100; - - /* Allocate color map */ - if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { - IVTVFB_ERR("abort, unable to alloc cmap\n"); - return -ENOMEM; - } - - /* Allocate the pseudo palette */ - oi->ivtvfb_info.pseudo_palette = - kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN); - - if (!oi->ivtvfb_info.pseudo_palette) { - IVTVFB_ERR("abort, unable to alloc pseudo pallete\n"); - return -ENOMEM; - } - - return 0; -} - -/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ - -static int ivtvfb_init_io(struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - - mutex_lock(&itv->serialize_lock); - if (ivtv_init_on_first_open(itv)) { - mutex_unlock(&itv->serialize_lock); - IVTVFB_ERR("Failed to initialize ivtv\n"); - return -ENXIO; - } - mutex_unlock(&itv->serialize_lock); - - if (ivtvfb_get_framebuffer(itv, &oi->video_rbase, - &oi->video_buffer_size) < 0) { - IVTVFB_ERR("Firmware failed to respond\n"); - return -EIO; - } - - /* The osd buffer size depends on the number of video buffers allocated - on the PVR350 itself. For now we'll hardcode the smallest osd buffer - size to prevent any overlap. */ - oi->video_buffer_size = 1704960; - - oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; - oi->video_vbase = itv->dec_mem + oi->video_rbase; - - if (!oi->video_vbase) { - IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", - oi->video_buffer_size, oi->video_pbase); - return -EIO; - } - - IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - oi->video_pbase, oi->video_vbase, - oi->video_buffer_size / 1024); - -#ifdef CONFIG_MTRR - { - /* Find the largest power of two that maps the whole buffer */ - int size_shift = 31; - - while (!(oi->video_buffer_size & (1 << size_shift))) { - size_shift--; - } - size_shift++; - oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); - oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; - oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; - oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); - if (mtrr_add(oi->fb_start_aligned_physaddr, - oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, - MTRR_TYPE_WRCOMB, 1) < 0) { - IVTVFB_INFO("disabled mttr\n"); - oi->fb_start_aligned_physaddr = 0; - oi->fb_end_aligned_physaddr = 0; - } - } -#endif - - /* Blank the entire osd. */ - memset_io(oi->video_vbase, 0, oi->video_buffer_size); - - return 0; -} - -/* Release any memory we've grabbed & remove mtrr entry */ -static void ivtvfb_release_buffers (struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - - /* Release cmap */ - if (oi->ivtvfb_info.cmap.len) - fb_dealloc_cmap(&oi->ivtvfb_info.cmap); - - /* Release pseudo palette */ - if (oi->ivtvfb_info.pseudo_palette) - kfree(oi->ivtvfb_info.pseudo_palette); - -#ifdef CONFIG_MTRR - if (oi->fb_end_aligned_physaddr) { - mtrr_del(-1, oi->fb_start_aligned_physaddr, - oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); - } -#endif - - kfree(oi); - itv->osd_info = NULL; -} - -/* Initialize the specified card */ - -static int ivtvfb_init_card(struct ivtv *itv) -{ - int rc; - - if (itv->osd_info) { - IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id); - return -EBUSY; - } - - itv->osd_info = kzalloc(sizeof(struct osd_info), - GFP_ATOMIC|__GFP_NOWARN); - if (itv->osd_info == NULL) { - IVTVFB_ERR("Failed to allocate memory for osd_info\n"); - return -ENOMEM; - } - - /* Find & setup the OSD buffer */ - rc = ivtvfb_init_io(itv); - if (rc) { - ivtvfb_release_buffers(itv); - return rc; - } - - /* Set the startup video mode information */ - if ((rc = ivtvfb_init_vidmode(itv))) { - ivtvfb_release_buffers(itv); - return rc; - } - - /* Register the framebuffer */ - if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { - ivtvfb_release_buffers(itv); - return -EINVAL; - } - - itv->osd_video_pbase = itv->osd_info->video_pbase; - - /* Set the card to the requested mode */ - ivtvfb_set_par(&itv->osd_info->ivtvfb_info); - - /* Set color 0 to black */ - write_reg(0, 0x02a30); - write_reg(0, 0x02a34); - - /* Enable the osd */ - ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); - - /* Enable restart */ - itv->ivtvfb_restore = ivtvfb_restore; - - /* Allocate DMA */ - ivtv_udma_alloc(itv); - return 0; - -} - -static int __init ivtvfb_callback_init(struct device *dev, void *p) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); - struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev); - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - if (ivtvfb_init_card(itv) == 0) { - IVTVFB_INFO("Framebuffer registered on %s\n", - itv->v4l2_dev.name); - (*(int *)p)++; - } - } - return 0; -} - -static int ivtvfb_callback_cleanup(struct device *dev, void *p) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); - struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev); - struct osd_info *oi = itv->osd_info; - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) { - IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", - itv->instance); - return 0; - } - IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance); - itv->ivtvfb_restore = NULL; - ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info); - ivtvfb_release_buffers(itv); - itv->osd_video_pbase = 0; - } - return 0; -} - -static int __init ivtvfb_init(void) -{ - struct device_driver *drv; - int registered = 0; - int err; - - if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n", - IVTV_MAX_CARDS - 1); - return -EINVAL; - } - - drv = driver_find("ivtv", &pci_bus_type); - err = driver_for_each_device(drv, NULL, ®istered, ivtvfb_callback_init); - put_driver(drv); - if (!registered) { - printk(KERN_ERR "ivtvfb: no cards found\n"); - return -ENODEV; - } - return 0; -} - -static void ivtvfb_cleanup(void) -{ - struct device_driver *drv; - int err; - - printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n"); - - drv = driver_find("ivtv", &pci_bus_type); - err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup); - put_driver(drv); -} - -module_init(ivtvfb_init); -module_exit(ivtvfb_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-fileops.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-fileops.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-fileops.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-fileops.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1065 +0,0 @@ -/* - file operation functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-fileops.h" -#include "ivtv-i2c.h" -#include "ivtv-queue.h" -#include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-vbi.h" -#include "ivtv-mailbox.h" -#include "ivtv-routing.h" -#include "ivtv-streams.h" -#include "ivtv-yuv.h" -#include "ivtv-ioctl.h" -#include "ivtv-cards.h" -#include "ivtv-firmware.h" -#include -#include - -/* This function tries to claim the stream for a specific file descriptor. - If no one else is using this stream then the stream is claimed and - associated VBI streams are also automatically claimed. - Possible error returns: -EBUSY if someone else has claimed - the stream or 0 on success. */ -static int ivtv_claim_stream(struct ivtv_open_id *id, int type) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[type]; - struct ivtv_stream *s_vbi; - int vbi_type; - - if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { - /* someone already claimed this stream */ - if (s->id == id->open_id) { - /* yes, this file descriptor did. So that's OK. */ - return 0; - } - if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI || - type == IVTV_ENC_STREAM_TYPE_VBI)) { - /* VBI is handled already internally, now also assign - the file descriptor to this stream for external - reading of the stream. */ - s->id = id->open_id; - IVTV_DEBUG_INFO("Start Read VBI\n"); - return 0; - } - /* someone else is using this stream already */ - IVTV_DEBUG_INFO("Stream %d is busy\n", type); - return -EBUSY; - } - s->id = id->open_id; - if (type == IVTV_DEC_STREAM_TYPE_VBI) { - /* Enable reinsertion interrupt */ - ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); - } - - /* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI, - IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI - (provided VBI insertion is on and sliced VBI is selected), for all - other streams we're done */ - if (type == IVTV_DEC_STREAM_TYPE_MPG) { - vbi_type = IVTV_DEC_STREAM_TYPE_VBI; - } else if (type == IVTV_ENC_STREAM_TYPE_MPG && - itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) { - vbi_type = IVTV_ENC_STREAM_TYPE_VBI; - } else { - return 0; - } - s_vbi = &itv->streams[vbi_type]; - - if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) { - /* Enable reinsertion interrupt */ - if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI) - ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); - } - /* mark that it is used internally */ - set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags); - return 0; -} - -/* This function releases a previously claimed stream. It will take into - account associated VBI streams. */ -void ivtv_release_stream(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - struct ivtv_stream *s_vbi; - - s->id = -1; - if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && - test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { - /* this stream is still in use internally */ - return; - } - if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { - IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name); - return; - } - - ivtv_flush_queues(s); - - /* disable reinsertion interrupt */ - if (s->type == IVTV_DEC_STREAM_TYPE_VBI) - ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); - - /* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI, - IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI, - for all other streams we're done */ - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) - s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; - else if (s->type == IVTV_ENC_STREAM_TYPE_MPG) - s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - else - return; - - /* clear internal use flag */ - if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) { - /* was already cleared */ - return; - } - if (s_vbi->id != -1) { - /* VBI stream still claimed by a file descriptor */ - return; - } - /* disable reinsertion interrupt */ - if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI) - ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); - clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags); - ivtv_flush_queues(s_vbi); -} - -static void ivtv_dualwatch(struct ivtv *itv) -{ - struct v4l2_tuner vt; - u32 new_stereo_mode; - const u32 dual = 0x02; - - new_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode); - memset(&vt, 0, sizeof(vt)); - ivtv_call_all(itv, tuner, g_tuner, &vt); - if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) - new_stereo_mode = dual; - - if (new_stereo_mode == itv->dualwatch_stereo_mode) - return; - - IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", - itv->dualwatch_stereo_mode, new_stereo_mode); - if (v4l2_ctrl_s_ctrl(itv->cxhdl.audio_mode, new_stereo_mode)) - IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); -} - -static void ivtv_update_pgm_info(struct ivtv *itv) -{ - u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24; - int cnt; - int i = 0; - - if (wr_idx >= itv->pgm_info_num) { - IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num); - return; - } - cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num; - while (i < cnt) { - int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; - struct v4l2_enc_idx_entry *e = itv->pgm_info + idx; - u32 addr = itv->pgm_info_offset + 4 + idx * 24; - const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1, - V4L2_ENC_IDX_FRAME_B, -1, -1, -1 }; - // 1=I, 2=P, 4=B - - e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32); - if (e->offset > itv->mpg_data_received) { - break; - } - e->offset += itv->vbi_data_inserted; - e->length = read_enc(addr); - e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32); - e->flags = mapping[read_enc(addr + 12) & 7]; - i++; - } - itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; -} - -static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err) -{ - struct ivtv *itv = s->itv; - struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - struct ivtv_buffer *buf; - DEFINE_WAIT(wait); - - *err = 0; - while (1) { - if (s->type == IVTV_ENC_STREAM_TYPE_MPG) { - /* Process pending program info updates and pending VBI data */ - ivtv_update_pgm_info(itv); - - if (time_after(jiffies, - itv->dualwatch_jiffies + - msecs_to_jiffies(1000))) { - itv->dualwatch_jiffies = jiffies; - ivtv_dualwatch(itv); - } - - if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && - !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { - while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) { - /* byteswap and process VBI data */ - ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type); - ivtv_enqueue(s_vbi, buf, &s_vbi->q_free); - } - } - buf = &itv->vbi.sliced_mpeg_buf; - if (buf->readpos != buf->bytesused) { - return buf; - } - } - - /* do we have leftover data? */ - buf = ivtv_dequeue(s, &s->q_io); - if (buf) - return buf; - - /* do we have new data? */ - buf = ivtv_dequeue(s, &s->q_full); - if (buf) { - if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0) - return buf; - buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP; - if (s->type == IVTV_ENC_STREAM_TYPE_MPG) - /* byteswap MPG data */ - ivtv_buf_swap(buf); - else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) { - /* byteswap and process VBI data */ - ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type); - } - return buf; - } - - /* return if end of stream */ - if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - IVTV_DEBUG_INFO("EOS %s\n", s->name); - return NULL; - } - - /* return if file was opened with O_NONBLOCK */ - if (non_block) { - *err = -EAGAIN; - return NULL; - } - - /* wait for more data to arrive */ - prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); - /* New buffers might have become available before we were added to the waitqueue */ - if (!s->q_full.buffers) - schedule(); - finish_wait(&s->waitq, &wait); - if (signal_pending(current)) { - /* return if a signal was received */ - IVTV_DEBUG_INFO("User stopped %s\n", s->name); - *err = -EINTR; - return NULL; - } - } -} - -static void ivtv_setup_sliced_vbi_buf(struct ivtv *itv) -{ - int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; - - itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx]; - itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx]; - itv->vbi.sliced_mpeg_buf.readpos = 0; -} - -static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf, - char __user *ubuf, size_t ucount) -{ - struct ivtv *itv = s->itv; - size_t len = buf->bytesused - buf->readpos; - - if (len > ucount) len = ucount; - if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG && - !ivtv_raw_vbi(itv) && buf != &itv->vbi.sliced_mpeg_buf) { - const char *start = buf->buf + buf->readpos; - const char *p = start + 1; - const u8 *q; - u8 ch = itv->search_pack_header ? 0xba : 0xe0; - int stuffing, i; - - while (start + len > p && (q = memchr(p, 0, start + len - p))) { - p = q + 1; - if ((char *)q + 15 >= buf->buf + buf->bytesused || - q[1] != 0 || q[2] != 1 || q[3] != ch) { - continue; - } - if (!itv->search_pack_header) { - if ((q[6] & 0xc0) != 0x80) - continue; - if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) || - ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) { - ch = 0xba; - itv->search_pack_header = 1; - p = q + 9; - } - continue; - } - stuffing = q[13] & 7; - /* all stuffing bytes must be 0xff */ - for (i = 0; i < stuffing; i++) - if (q[14 + i] != 0xff) - break; - if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 && - q[14 + stuffing] == 0 && q[15 + stuffing] == 0 && - q[16 + stuffing] == 1) { - itv->search_pack_header = 0; - len = (char *)q - start; - ivtv_setup_sliced_vbi_buf(itv); - break; - } - } - } - if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { - IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name); - return -EFAULT; - } - /*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount, - buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len, - buf == &itv->vbi.sliced_mpeg_buf); */ - buf->readpos += len; - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf) - itv->mpg_data_received += len; - return len; -} - -static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block) -{ - struct ivtv *itv = s->itv; - size_t tot_written = 0; - int single_frame = 0; - - if (atomic_read(&itv->capturing) == 0 && s->id == -1) { - /* shouldn't happen */ - IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); - return -EIO; - } - - /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should - arrive one-by-one, so make sure we never output more than one VBI frame at a time */ - if (s->type == IVTV_DEC_STREAM_TYPE_VBI || - (s->type == IVTV_ENC_STREAM_TYPE_VBI && !ivtv_raw_vbi(itv))) - single_frame = 1; - - for (;;) { - struct ivtv_buffer *buf; - int rc; - - buf = ivtv_get_buffer(s, non_block, &rc); - /* if there is no data available... */ - if (buf == NULL) { - /* if we got data, then return that regardless */ - if (tot_written) - break; - /* EOS condition */ - if (rc == 0) { - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - ivtv_release_stream(s); - } - /* set errno */ - return rc; - } - rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written); - if (buf != &itv->vbi.sliced_mpeg_buf) { - ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io); - } - else if (buf->readpos == buf->bytesused) { - int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; - itv->vbi.sliced_mpeg_size[idx] = 0; - itv->vbi.inserted_frame++; - itv->vbi_data_inserted += buf->bytesused; - } - if (rc < 0) - return rc; - tot_written += rc; - - if (tot_written == tot_count || single_frame) - break; - } - return tot_written; -} - -static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count, - loff_t *pos, int non_block) -{ - ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; - struct ivtv *itv = s->itv; - - IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); - if (rc > 0) - pos += rc; - return rc; -} - -int ivtv_start_capture(struct ivtv_open_id *id) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - struct ivtv_stream *s_vbi; - - if (s->type == IVTV_ENC_STREAM_TYPE_RAD || - s->type == IVTV_DEC_STREAM_TYPE_MPG || - s->type == IVTV_DEC_STREAM_TYPE_YUV || - s->type == IVTV_DEC_STREAM_TYPE_VOUT) { - /* you cannot read from these stream types. */ - return -EPERM; - } - - /* Try to claim this stream. */ - if (ivtv_claim_stream(id, s->type)) - return -EBUSY; - - /* This stream does not need to start capturing */ - if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return 0; - } - - /* If capture is already in progress, then we also have to - do nothing extra. */ - if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return 0; - } - - /* Start VBI capture if required */ - s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && - test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && - !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { - /* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed - automatically when the MPG stream is claimed. - We only need to start the VBI capturing. */ - if (ivtv_start_v4l2_encode_stream(s_vbi)) { - IVTV_DEBUG_WARN("VBI capture start failed\n"); - - /* Failure, clean up and return an error */ - clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - /* also releases the associated VBI stream */ - ivtv_release_stream(s); - return -EIO; - } - IVTV_DEBUG_INFO("VBI insertion started\n"); - } - - /* Tell the card to start capturing */ - if (!ivtv_start_v4l2_encode_stream(s)) { - /* We're done */ - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - /* Resume a possibly paused encoder */ - if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); - return 0; - } - - /* failure, clean up */ - IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); - - /* Note: the IVTV_ENC_STREAM_TYPE_VBI is released - automatically when the MPG stream is released. - We only need to stop the VBI capturing. */ - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && - test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { - ivtv_stop_v4l2_encode_stream(s_vbi, 0); - clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); - } - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - ivtv_release_stream(s); - return -EIO; -} - -ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos) -{ - struct ivtv_open_id *id = fh2id(filp->private_data); - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - int rc; - - IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); - - mutex_lock(&itv->serialize_lock); - rc = ivtv_start_capture(id); - mutex_unlock(&itv->serialize_lock); - if (rc) - return rc; - return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); -} - -int ivtv_start_decoding(struct ivtv_open_id *id, int speed) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - int rc; - - if (atomic_read(&itv->decoding) == 0) { - if (ivtv_claim_stream(id, s->type)) { - /* someone else is using this stream already */ - IVTV_DEBUG_WARN("start decode, stream already claimed\n"); - return -EBUSY; - } - rc = ivtv_start_v4l2_decode_stream(s, 0); - if (rc < 0) { - if (rc == -EAGAIN) - rc = ivtv_start_v4l2_decode_stream(s, 0); - if (rc < 0) - return rc; - } - } - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) - return ivtv_set_speed(itv, speed); - return 0; -} - -ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) -{ - struct ivtv_open_id *id = fh2id(filp->private_data); - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - struct yuv_playback_info *yi = &itv->yuv_info; - struct ivtv_buffer *buf; - struct ivtv_queue q; - int bytes_written = 0; - int mode; - int rc; - DEFINE_WAIT(wait); - - IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name); - - if (s->type != IVTV_DEC_STREAM_TYPE_MPG && - s->type != IVTV_DEC_STREAM_TYPE_YUV && - s->type != IVTV_DEC_STREAM_TYPE_VOUT) - /* not decoder streams */ - return -EPERM; - - /* Try to claim this stream */ - if (ivtv_claim_stream(id, s->type)) - return -EBUSY; - - /* This stream does not need to start any decoding */ - if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) { - int elems = count / sizeof(struct v4l2_sliced_vbi_data); - - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return ivtv_write_vbi_from_user(itv, - (const struct v4l2_sliced_vbi_data __user *)user_buf, elems); - } - - mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV; - - if (ivtv_set_output_mode(itv, mode) != mode) { - ivtv_release_stream(s); - return -EBUSY; - } - ivtv_queue_init(&q); - set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - - /* Start decoder (returns 0 if already started) */ - mutex_lock(&itv->serialize_lock); - rc = ivtv_start_decoding(id, itv->speed); - mutex_unlock(&itv->serialize_lock); - if (rc) { - IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); - - /* failure, clean up */ - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return rc; - } - -retry: - /* If possible, just DMA the entire frame - Check the data transfer size - since we may get here before the stream has been fully set-up */ - if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) { - while (count >= itv->dma_data_req_size) { - rc = ivtv_yuv_udma_stream_frame(itv, (void __user *)user_buf); - - if (rc < 0) - return rc; - - bytes_written += itv->dma_data_req_size; - user_buf += itv->dma_data_req_size; - count -= itv->dma_data_req_size; - } - if (count == 0) { - IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); - return bytes_written; - } - } - - for (;;) { - /* Gather buffers */ - while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) - ivtv_enqueue(s, buf, &q); - while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) { - ivtv_enqueue(s, buf, &q); - } - if (q.buffers) - break; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); - /* New buffers might have become free before we were added to the waitqueue */ - if (!s->q_free.buffers) - schedule(); - finish_wait(&s->waitq, &wait); - if (signal_pending(current)) { - IVTV_DEBUG_INFO("User stopped %s\n", s->name); - return -EINTR; - } - } - - /* copy user data into buffers */ - while ((buf = ivtv_dequeue(s, &q))) { - /* yuv is a pain. Don't copy more data than needed for a single - frame, otherwise we lose sync with the incoming stream */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && - yi->stream_size + count > itv->dma_data_req_size) - rc = ivtv_buf_copy_from_user(s, buf, user_buf, - itv->dma_data_req_size - yi->stream_size); - else - rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); - - /* Make sure we really got all the user data */ - if (rc < 0) { - ivtv_queue_move(s, &q, NULL, &s->q_free, 0); - return rc; - } - user_buf += rc; - count -= rc; - bytes_written += rc; - - if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { - yi->stream_size += rc; - /* If we have a complete yuv frame, break loop now */ - if (yi->stream_size == itv->dma_data_req_size) { - ivtv_enqueue(s, buf, &s->q_full); - yi->stream_size = 0; - break; - } - } - - if (buf->bytesused != s->buf_size) { - /* incomplete, leave in q_io for next time */ - ivtv_enqueue(s, buf, &s->q_io); - break; - } - /* Byteswap MPEG buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) - ivtv_buf_swap(buf); - ivtv_enqueue(s, buf, &s->q_full); - } - - if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { - if (s->q_full.length >= itv->dma_data_req_size) { - int got_sig; - - if (mode == OUT_YUV) - ivtv_yuv_setup_stream_frame(itv); - - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); - while (!(got_sig = signal_pending(current)) && - test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { - schedule(); - } - finish_wait(&itv->dma_waitq, &wait); - if (got_sig) { - IVTV_DEBUG_INFO("User interrupted %s\n", s->name); - return -EINTR; - } - - clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); - ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1); - } - } - /* more user data is available, wait until buffers become free - to transfer the rest. */ - if (count && !(filp->f_flags & O_NONBLOCK)) - goto retry; - IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); - return bytes_written; -} - -unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) -{ - struct ivtv_open_id *id = fh2id(filp->private_data); - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - int res = 0; - - /* add stream's waitq to the poll list */ - IVTV_DEBUG_HI_FILE("Decoder poll\n"); - - /* If there are subscribed events, then only use the new event - API instead of the old video.h based API. */ - if (!list_empty(&id->fh.events->subscribed)) { - poll_wait(filp, &id->fh.events->wait, wait); - /* Turn off the old-style vsync events */ - clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); - if (v4l2_event_pending(&id->fh)) - res = POLLPRI; - } else { - /* This is the old-style API which is here only for backwards - compatibility. */ - poll_wait(filp, &s->waitq, wait); - set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); - if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) || - test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) - res = POLLPRI; - } - - /* Allow write if buffers are available for writing */ - if (s->q_free.buffers) - res |= POLLOUT | POLLWRNORM; - return res; -} - -unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) -{ - struct ivtv_open_id *id = fh2id(filp->private_data); - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - /* Start a capture if there is none */ - if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - int rc; - - mutex_lock(&itv->serialize_lock); - rc = ivtv_start_capture(id); - mutex_unlock(&itv->serialize_lock); - if (rc) { - IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", - s->name, rc); - return POLLERR; - } - IVTV_DEBUG_FILE("Encoder poll started capture\n"); - } - - /* add stream's waitq to the poll list */ - IVTV_DEBUG_HI_FILE("Encoder poll\n"); - poll_wait(filp, &s->waitq, wait); - - if (s->q_full.length || s->q_io.length) - return POLLIN | POLLRDNORM; - if (eof) - return POLLHUP; - return 0; -} - -void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - - IVTV_DEBUG_FILE("close() of %s\n", s->name); - - /* 'Unclaim' this stream */ - - /* Stop capturing */ - if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - - IVTV_DEBUG_INFO("close stopping capture\n"); - /* Special case: a running VBI capture for VBI insertion - in the mpeg stream. Need to stop that too. */ - if (id->type == IVTV_ENC_STREAM_TYPE_MPG && - test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) && - !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { - IVTV_DEBUG_INFO("close stopping embedded VBI capture\n"); - ivtv_stop_v4l2_encode_stream(s_vbi, 0); - } - if ((id->type == IVTV_DEC_STREAM_TYPE_VBI || - id->type == IVTV_ENC_STREAM_TYPE_VBI) && - test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { - /* Also used internally, don't stop capturing */ - s->id = -1; - } - else { - ivtv_stop_v4l2_encode_stream(s, gop_end); - } - } - if (!gop_end) { - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - ivtv_release_stream(s); - } -} - -static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) -{ - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - - IVTV_DEBUG_FILE("close() of %s\n", s->name); - - if (id->type == IVTV_DEC_STREAM_TYPE_YUV && - test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { - /* Restore registers we've changed & clean up any mess */ - ivtv_yuv_close(itv); - } - - /* Stop decoding */ - if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - IVTV_DEBUG_INFO("close stopping decode\n"); - - ivtv_stop_v4l2_decode_stream(s, flags, pts); - itv->output_mode = OUT_NONE; - } - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames) - itv->output_mode = OUT_NONE; - - itv->speed = 0; - clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); - ivtv_release_stream(s); -} - -int ivtv_v4l2_close(struct file *filp) -{ - struct v4l2_fh *fh = filp->private_data; - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; - - IVTV_DEBUG_FILE("close %s\n", s->name); - - v4l2_fh_del(fh); - v4l2_fh_exit(fh); - - /* Easy case first: this stream was never claimed by us */ - if (s->id != id->open_id) { - kfree(id); - return 0; - } - - /* 'Unclaim' this stream */ - - /* Stop radio */ - mutex_lock(&itv->serialize_lock); - if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { - /* Closing radio device, return to TV mode */ - ivtv_mute(itv); - /* Mark that the radio is no longer in use */ - clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); - /* Switch tuner to TV */ - ivtv_call_all(itv, core, s_std, itv->std); - /* Select correct audio input (i.e. TV tuner or Line in) */ - ivtv_audio_set_io(itv); - if (itv->hw_flags & IVTV_HW_SAA711X) { - ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, - SAA7115_FREQ_32_11_MHZ, 0); - } - if (atomic_read(&itv->capturing) > 0) { - /* Undo video mute */ - ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, - v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) | - (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8)); - } - /* Done! Unmute and continue. */ - ivtv_unmute(itv); - ivtv_release_stream(s); - } else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { - struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; - - ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); - - /* If all output streams are closed, and if the user doesn't have - IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ - if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) { - /* disable CC on TV-out */ - ivtv_disable_cc(itv); - } - } else { - ivtv_stop_capture(id, 0); - } - kfree(id); - mutex_unlock(&itv->serialize_lock); - return 0; -} - -static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) -{ -#ifdef CONFIG_VIDEO_ADV_DEBUG - struct video_device *vdev = video_devdata(filp); -#endif - struct ivtv *itv = s->itv; - struct ivtv_open_id *item; - int res = 0; - - IVTV_DEBUG_FILE("open %s\n", s->name); - -#ifdef CONFIG_VIDEO_ADV_DEBUG - /* Unless ivtv_fw_debug is set, error out if firmware dead. */ - if (ivtv_fw_debug) { - IVTV_WARN("Opening %s with dead firmware lockout disabled\n", - video_device_node_name(vdev)); - IVTV_WARN("Selected firmware errors will be ignored\n"); - } else { -#else - if (1) { -#endif - res = ivtv_firmware_check(itv, "ivtv_serialized_open"); - if (res == -EAGAIN) - res = ivtv_firmware_check(itv, "ivtv_serialized_open"); - if (res < 0) - return -EIO; - } - - if (s->type == IVTV_DEC_STREAM_TYPE_MPG && - test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) - return -EBUSY; - - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && - test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) - return -EBUSY; - - if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { - if (read_reg(0x82c) == 0) { - IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); - /* return -ENODEV; */ - } - ivtv_udma_alloc(itv); - } - - /* Allocate memory */ - item = kzalloc(sizeof(struct ivtv_open_id), GFP_KERNEL); - if (NULL == item) { - IVTV_DEBUG_WARN("nomem on v4l2 open\n"); - return -ENOMEM; - } - v4l2_fh_init(&item->fh, s->vdev); - if (s->type == IVTV_DEC_STREAM_TYPE_YUV || - s->type == IVTV_DEC_STREAM_TYPE_MPG) { - res = v4l2_event_alloc(&item->fh, 60); - } - if (res < 0) { - v4l2_fh_exit(&item->fh); - kfree(item); - return res; - } - item->itv = itv; - item->type = s->type; - - item->open_id = itv->open_id++; - filp->private_data = &item->fh; - - if (item->type == IVTV_ENC_STREAM_TYPE_RAD) { - /* Try to claim this stream */ - if (ivtv_claim_stream(item, item->type)) { - /* No, it's already in use */ - v4l2_fh_exit(&item->fh); - kfree(item); - return -EBUSY; - } - - if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - if (atomic_read(&itv->capturing) > 0) { - /* switching to radio while capture is - in progress is not polite */ - ivtv_release_stream(s); - v4l2_fh_exit(&item->fh); - kfree(item); - return -EBUSY; - } - } - /* Mark that the radio is being used. */ - set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); - /* We have the radio */ - ivtv_mute(itv); - /* Switch tuner to radio */ - ivtv_call_all(itv, tuner, s_radio); - /* Select the correct audio input (i.e. radio tuner) */ - ivtv_audio_set_io(itv); - if (itv->hw_flags & IVTV_HW_SAA711X) { - ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, - SAA7115_FREQ_32_11_MHZ, SAA7115_FREQ_FL_APLL); - } - /* Done! Unmute and continue. */ - ivtv_unmute(itv); - } - - /* YUV or MPG Decoding Mode? */ - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) { - clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { - set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - /* For yuv, we need to know the dma size before we start */ - itv->dma_data_req_size = - 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); - itv->yuv_info.stream_size = 0; - } - v4l2_fh_add(&item->fh); - return 0; -} - -int ivtv_v4l2_open(struct file *filp) -{ - int res; - struct ivtv *itv = NULL; - struct ivtv_stream *s = NULL; - struct video_device *vdev = video_devdata(filp); - - s = video_get_drvdata(vdev); - itv = s->itv; - - mutex_lock(&itv->serialize_lock); - if (ivtv_init_on_first_open(itv)) { - IVTV_ERR("Failed to initialize on device %s\n", - video_device_node_name(vdev)); - mutex_unlock(&itv->serialize_lock); - return -ENXIO; - } - res = ivtv_serialized_open(s, filp); - mutex_unlock(&itv->serialize_lock); - return res; -} - -void ivtv_mute(struct ivtv *itv) -{ - if (atomic_read(&itv->capturing)) - ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1); - IVTV_DEBUG_INFO("Mute\n"); -} - -void ivtv_unmute(struct ivtv *itv) -{ - if (atomic_read(&itv->capturing)) { - ivtv_msleep_timeout(100, 0); - ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); - ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); - } - IVTV_DEBUG_INFO("Unmute\n"); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-fileops.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-fileops.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-fileops.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-fileops.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -/* - file operation functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_FILEOPS_H -#define IVTV_FILEOPS_H - -/* Testing/Debugging */ -int ivtv_v4l2_open(struct file *filp); -ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t * pos); -ssize_t ivtv_v4l2_write(struct file *filp, const char __user *buf, size_t count, - loff_t * pos); -int ivtv_v4l2_close(struct file *filp); -unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait); -unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table * wait); -int ivtv_start_capture(struct ivtv_open_id *id); -void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end); -int ivtv_start_decoding(struct ivtv_open_id *id, int speed); -void ivtv_mute(struct ivtv *itv); -void ivtv_unmute(struct ivtv *itv); - -/* Utilities */ - -/* Release a previously claimed stream. */ -void ivtv_release_stream(struct ivtv_stream *s); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-firmware.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-firmware.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,395 +0,0 @@ -/* - ivtv firmware functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-mailbox.h" -#include "ivtv-firmware.h" -#include "ivtv-yuv.h" -#include "ivtv-ioctl.h" -#include "ivtv-cards.h" -#include -#include - -#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE -#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6 -#define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB -#define IVTV_CMD_VDM_STOP 0x00000000 -#define IVTV_CMD_AO_STOP 0x00000005 -#define IVTV_CMD_APU_PING 0x00000000 -#define IVTV_CMD_VPU_STOP15 0xFFFFFFFE -#define IVTV_CMD_VPU_STOP16 0xFFFFFFEE -#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF -#define IVTV_CMD_SPU_STOP 0x00000001 -#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A -#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640 -#define IVTV_SDRAM_SLEEPTIME 600 - -#define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg" -#define IVTV_DECODE_INIT_MPEG_SIZE (152*1024) - -/* Encoder/decoder firmware sizes */ -#define IVTV_FW_ENC_SIZE (376836) -#define IVTV_FW_DEC_SIZE (256*1024) - -static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv *itv, long size) -{ - const struct firmware *fw = NULL; - int retries = 3; - -retry: - if (retries && request_firmware(&fw, fn, &itv->pdev->dev) == 0) { - int i; - volatile u32 __iomem *dst = (volatile u32 __iomem *)mem; - const u32 *src = (const u32 *)fw->data; - - if (fw->size != size) { - /* Due to race conditions in firmware loading (esp. with udev <0.95) - the wrong file was sometimes loaded. So we check filesizes to - see if at least the right-sized file was loaded. If not, then we - retry. */ - IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size); - release_firmware(fw); - retries--; - goto retry; - } - for (i = 0; i < fw->size; i += 4) { - /* no need for endianness conversion on the ppc */ - __raw_writel(*src, dst); - dst++; - src++; - } - IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size); - release_firmware(fw); - return size; - } - IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size); - IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n"); - return -ENOMEM; -} - -void ivtv_halt_firmware(struct ivtv *itv) -{ - IVTV_DEBUG_INFO("Preparing for firmware halt.\n"); - if (itv->has_cx23415 && itv->dec_mbox.mbox) - ivtv_vapi(itv, CX2341X_DEC_HALT_FW, 0); - if (itv->enc_mbox.mbox) - ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0); - - ivtv_msleep_timeout(10, 0); - itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL; - - IVTV_DEBUG_INFO("Stopping VDM\n"); - write_reg(IVTV_CMD_VDM_STOP, IVTV_REG_VDM); - - IVTV_DEBUG_INFO("Stopping AO\n"); - write_reg(IVTV_CMD_AO_STOP, IVTV_REG_AO); - - IVTV_DEBUG_INFO("pinging (?) APU\n"); - write_reg(IVTV_CMD_APU_PING, IVTV_REG_APU); - - IVTV_DEBUG_INFO("Stopping VPU\n"); - if (!itv->has_cx23415) - write_reg(IVTV_CMD_VPU_STOP16, IVTV_REG_VPU); - else - write_reg(IVTV_CMD_VPU_STOP15, IVTV_REG_VPU); - - IVTV_DEBUG_INFO("Resetting Hw Blocks\n"); - write_reg(IVTV_CMD_HW_BLOCKS_RST, IVTV_REG_HW_BLOCKS); - - IVTV_DEBUG_INFO("Stopping SPU\n"); - write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU); - - ivtv_msleep_timeout(10, 0); - - IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n"); - write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE); - - IVTV_DEBUG_INFO("init Encoder SDRAM refresh to 1us\n"); - write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_ENC_SDRAM_REFRESH); - - if (itv->has_cx23415) { - IVTV_DEBUG_INFO("init Decoder SDRAM pre-charge\n"); - write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_DEC_SDRAM_PRECHARGE); - - IVTV_DEBUG_INFO("init Decoder SDRAM refresh to 1us\n"); - write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH); - } - - IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME); - ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0); -} - -void ivtv_firmware_versions(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - - /* Encoder */ - ivtv_vapi_result(itv, data, CX2341X_ENC_GET_VERSION, 0); - IVTV_INFO("Encoder revision: 0x%08x\n", data[0]); - - if (data[0] != 0x02060039) - IVTV_WARN("Recommended firmware version is 0x02060039.\n"); - - if (itv->has_cx23415) { - /* Decoder */ - ivtv_vapi_result(itv, data, CX2341X_DEC_GET_VERSION, 0); - IVTV_INFO("Decoder revision: 0x%08x\n", data[0]); - } -} - -static int ivtv_firmware_copy(struct ivtv *itv) -{ - IVTV_DEBUG_INFO("Loading encoder image\n"); - if (load_fw_direct(CX2341X_FIRM_ENC_FILENAME, - itv->enc_mem, itv, IVTV_FW_ENC_SIZE) != IVTV_FW_ENC_SIZE) { - IVTV_DEBUG_WARN("failed loading encoder firmware\n"); - return -3; - } - if (!itv->has_cx23415) - return 0; - - IVTV_DEBUG_INFO("Loading decoder image\n"); - if (load_fw_direct(CX2341X_FIRM_DEC_FILENAME, - itv->dec_mem, itv, IVTV_FW_DEC_SIZE) != IVTV_FW_DEC_SIZE) { - IVTV_DEBUG_WARN("failed loading decoder firmware\n"); - return -1; - } - return 0; -} - -static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile u8 __iomem *mem, u32 size) -{ - int i; - - /* mailbox is preceeded by a 16 byte 'magic cookie' starting at a 256-byte - address boundary */ - for (i = 0; i < size; i += 0x100) { - if (readl(mem + i) == 0x12345678 && - readl(mem + i + 4) == 0x34567812 && - readl(mem + i + 8) == 0x56781234 && - readl(mem + i + 12) == 0x78123456) { - return (volatile struct ivtv_mailbox __iomem *)(mem + i + 16); - } - } - return NULL; -} - -int ivtv_firmware_init(struct ivtv *itv) -{ - int err; - - ivtv_halt_firmware(itv); - - /* load firmware */ - err = ivtv_firmware_copy(itv); - if (err) { - IVTV_DEBUG_WARN("Error %d loading firmware\n", err); - return err; - } - - /* start firmware */ - write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU); - ivtv_msleep_timeout(100, 0); - if (itv->has_cx23415) - write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU); - else - write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU); - ivtv_msleep_timeout(100, 0); - - /* find mailboxes and ping firmware */ - itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE); - if (itv->enc_mbox.mbox == NULL) - IVTV_ERR("Encoder mailbox not found\n"); - else if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0)) { - IVTV_ERR("Encoder firmware dead!\n"); - itv->enc_mbox.mbox = NULL; - } - if (itv->enc_mbox.mbox == NULL) - return -ENODEV; - - if (!itv->has_cx23415) - return 0; - - itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE); - if (itv->dec_mbox.mbox == NULL) { - IVTV_ERR("Decoder mailbox not found\n"); - } else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) { - IVTV_ERR("Decoder firmware dead!\n"); - itv->dec_mbox.mbox = NULL; - } else { - /* Firmware okay, so check yuv output filter table */ - ivtv_yuv_filter_check(itv); - } - return itv->dec_mbox.mbox ? 0 : -ENODEV; -} - -void ivtv_init_mpeg_decoder(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - long readbytes; - volatile u8 __iomem *mem_offset; - - data[0] = 0; - data[1] = itv->cxhdl.width; /* YUV source width */ - data[2] = itv->cxhdl.height; - data[3] = itv->cxhdl.audio_properties; /* Audio settings to use, - bitmap. see docs. */ - if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) { - IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n"); - return; - } - - if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) { - IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n"); - return; - } - ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data); - mem_offset = itv->dec_mem + data[1]; - - if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME, - mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) { - IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n", - IVTV_DECODE_INIT_MPEG_FILENAME); - } else { - ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0); - ivtv_msleep_timeout(100, 0); - } - ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); -} - -/* Try to restart the card & restore previous settings */ -int ivtv_firmware_restart(struct ivtv *itv) -{ - int rc = 0; - v4l2_std_id std; - struct ivtv_open_id fh; - fh.itv = itv; - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) - /* Display test image during restart */ - ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, - SAA7127_INPUT_TYPE_TEST_IMAGE, - itv->card->video_outputs[itv->active_output].video_output, - 0); - - mutex_lock(&itv->udma.lock); - - rc = ivtv_firmware_init(itv); - if (rc) { - mutex_unlock(&itv->udma.lock); - return rc; - } - - /* Allow settings to reload */ - ivtv_mailbox_cache_invalidate(itv); - - /* Restore video standard */ - std = itv->std; - itv->std = 0; - ivtv_s_std(NULL, &fh, &std); - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - ivtv_init_mpeg_decoder(itv); - - /* Restore framebuffer if active */ - if (itv->ivtvfb_restore) - itv->ivtvfb_restore(itv); - - /* Restore alpha settings */ - ivtv_set_osd_alpha(itv); - - /* Restore normal output */ - ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, - SAA7127_INPUT_TYPE_NORMAL, - itv->card->video_outputs[itv->active_output].video_output, - 0); - } - - mutex_unlock(&itv->udma.lock); - return rc; -} - -/* Check firmware running state. The checks fall through - allowing multiple failures to be logged. */ -int ivtv_firmware_check(struct ivtv *itv, char *where) -{ - int res = 0; - - /* Check encoder is still running */ - if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) { - IVTV_WARN("Encoder has died : %s\n", where); - res = -1; - } - - /* Also check audio. Only check if not in use & encoder is okay */ - if (!res && !atomic_read(&itv->capturing) && - (!atomic_read(&itv->decoding) || - (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV, - &itv->i_flags)))) { - - if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) { - IVTV_WARN("Audio has died (Encoder OK) : %s\n", where); - res = -2; - } - } - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - /* Second audio check. Skip if audio already failed */ - if (res != -2 && read_dec(0x100) != read_dec(0x104)) { - /* Wait & try again to be certain. */ - ivtv_msleep_timeout(14, 0); - if (read_dec(0x100) != read_dec(0x104)) { - IVTV_WARN("Audio has died (Decoder) : %s\n", - where); - res = -1; - } - } - - /* Check decoder is still running */ - if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) { - IVTV_WARN("Decoder has died : %s\n", where); - res = -1; - } - } - - /* If something failed & currently idle, try to reload */ - if (res && !atomic_read(&itv->capturing) && - !atomic_read(&itv->decoding)) { - IVTV_INFO("Detected in %s that firmware had failed - " - "Reloading\n", where); - res = ivtv_firmware_restart(itv); - /* - * Even if restarted ok, still signal a problem had occured. - * The caller can come through this function again to check - * if things are really ok after the restart. - */ - if (!res) { - IVTV_INFO("Firmware restart okay\n"); - res = -EAGAIN; - } else { - IVTV_INFO("Firmware restart failed\n"); - } - } else if (res) { - res = -EIO; - } - - return res; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-firmware.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-firmware.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-firmware.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-firmware.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - ivtv firmware functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_FIRMWARE_H -#define IVTV_FIRMWARE_H - -int ivtv_firmware_init(struct ivtv *itv); -void ivtv_firmware_versions(struct ivtv *itv); -void ivtv_halt_firmware(struct ivtv *itv); -void ivtv_init_mpeg_decoder(struct ivtv *itv); -int ivtv_firmware_check(struct ivtv *itv, char *where); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-gpio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-gpio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-gpio.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-gpio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,374 +0,0 @@ -/* - gpio functions. - Merging GPIO support into driver: - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-cards.h" -#include "ivtv-gpio.h" -#include "tuner-xc2028.h" -#include -#include - -/* - * GPIO assignment of Yuan MPG600/MPG160 - * - * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 - * OUTPUT IN1 IN0 AM3 AM2 AM1 AM0 - * INPUT DM1 DM0 - * - * IN* : Input selection - * IN1 IN0 - * 1 1 N/A - * 1 0 Line - * 0 1 N/A - * 0 0 Tuner - * - * AM* : Audio Mode - * AM3 0: Normal 1: Mixed(Sub+Main channel) - * AM2 0: Subchannel 1: Main channel - * AM1 0: Stereo 1: Mono - * AM0 0: Normal 1: Mute - * - * DM* : Detected tuner audio Mode - * DM1 0: Stereo 1: Mono - * DM0 0: Multiplex 1: Normal - * - * GPIO Initial Settings - * MPG600 MPG160 - * DIR 0x3080 0x7080 - * OUTPUT 0x000C 0x400C - * - * Special thanks to Makoto Iguchi and Mr. Anonymous - * for analyzing GPIO of MPG160. - * - ***************************************************************************** - * - * GPIO assignment of Avermedia M179 (per information direct from AVerMedia) - * - * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 - * OUTPUT IN0 AM0 IN1 AM1 AM2 IN2 BR0 BR1 - * INPUT - * - * IN* : Input selection - * IN0 IN1 IN2 - * * 1 * Mute - * 0 0 0 Line-In - * 1 0 0 TV Tuner Audio - * 0 0 1 FM Audio - * 1 0 1 Mute - * - * AM* : Audio Mode - * AM0 AM1 AM2 - * 0 0 0 TV Tuner Audio: L_OUT=(L+R)/2, R_OUT=SAP - * 0 0 1 TV Tuner Audio: L_OUT=R_OUT=SAP (SAP) - * 0 1 0 TV Tuner Audio: L_OUT=L, R_OUT=R (stereo) - * 0 1 1 TV Tuner Audio: mute - * 1 * * TV Tuner Audio: L_OUT=R_OUT=(L+R)/2 (mono) - * - * BR* : Audio Sample Rate (BR stands for bitrate for some reason) - * BR0 BR1 - * 0 0 32 kHz - * 0 1 44.1 kHz - * 1 0 48 kHz - * - * DM* : Detected tuner audio Mode - * Unknown currently - * - * Special thanks to AVerMedia Technologies, Inc. and Jiun-Kuei Jung at - * AVerMedia for providing the GPIO information used to add support - * for the M179 cards. - */ - -/********************* GPIO stuffs *********************/ - -/* GPIO registers */ -#define IVTV_REG_GPIO_IN 0x9008 -#define IVTV_REG_GPIO_OUT 0x900c -#define IVTV_REG_GPIO_DIR 0x9020 - -void ivtv_reset_ir_gpio(struct ivtv *itv) -{ - int curdir, curout; - - if (itv->card->type != IVTV_CARD_PVR_150) - return; - IVTV_DEBUG_INFO("Resetting PVR150 IR\n"); - curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= 0x80; - write_reg(curdir, IVTV_REG_GPIO_DIR); - curout = (curout & ~0xF) | 1; - write_reg(curout, IVTV_REG_GPIO_OUT); - /* We could use something else for smaller time */ - schedule_timeout_interruptible(msecs_to_jiffies(1)); - curout |= 2; - write_reg(curout, IVTV_REG_GPIO_OUT); - curdir &= ~0x80; - write_reg(curdir, IVTV_REG_GPIO_DIR); -} - -/* Xceive tuner reset function */ -int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value) -{ - struct i2c_algo_bit_data *algo = dev; - struct ivtv *itv = algo->data; - u32 curout; - - if (cmd != XC2028_TUNER_RESET) - return 0; - IVTV_DEBUG_INFO("Resetting tuner\n"); - curout = read_reg(IVTV_REG_GPIO_OUT); - curout &= ~(1 << itv->card->xceive_pin); - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - - curout |= 1 << itv->card->xceive_pin; - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - return 0; -} - -static inline struct ivtv *sd_to_ivtv(struct v4l2_subdev *sd) -{ - return container_of(sd, struct ivtv, sd_gpio); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct ivtv, hdl_gpio)->sd_gpio; -} - -static int subdev_s_clock_freq(struct v4l2_subdev *sd, u32 freq) -{ - struct ivtv *itv = sd_to_ivtv(sd); - u16 mask, data; - - mask = itv->card->gpio_audio_freq.mask; - switch (freq) { - case 32000: - data = itv->card->gpio_audio_freq.f32000; - break; - case 44100: - data = itv->card->gpio_audio_freq.f44100; - break; - case 48000: - default: - data = itv->card->gpio_audio_freq.f48000; - break; - } - if (mask) - write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); - return 0; -} - -static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct ivtv *itv = sd_to_ivtv(sd); - u16 mask; - - mask = itv->card->gpio_audio_detect.mask; - if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask)) - vt->rxsubchans = V4L2_TUNER_SUB_STEREO | - V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - else - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - return 0; -} - -static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct ivtv *itv = sd_to_ivtv(sd); - u16 mask, data; - - mask = itv->card->gpio_audio_mode.mask; - switch (vt->audmode) { - case V4L2_TUNER_MODE_LANG1: - data = itv->card->gpio_audio_mode.lang1; - break; - case V4L2_TUNER_MODE_LANG2: - data = itv->card->gpio_audio_mode.lang2; - break; - case V4L2_TUNER_MODE_MONO: - data = itv->card->gpio_audio_mode.mono; - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - default: - data = itv->card->gpio_audio_mode.stereo; - break; - } - if (mask) - write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); - return 0; -} - -static int subdev_s_radio(struct v4l2_subdev *sd) -{ - struct ivtv *itv = sd_to_ivtv(sd); - u16 mask, data; - - mask = itv->card->gpio_audio_input.mask; - data = itv->card->gpio_audio_input.radio; - if (mask) - write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); - return 0; -} - -static int subdev_s_audio_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct ivtv *itv = sd_to_ivtv(sd); - u16 mask, data; - - if (input > 2) - return -EINVAL; - mask = itv->card->gpio_audio_input.mask; - switch (input) { - case 0: - data = itv->card->gpio_audio_input.tuner; - break; - case 1: - data = itv->card->gpio_audio_input.linein; - break; - case 2: - default: - data = itv->card->gpio_audio_input.radio; - break; - } - if (mask) - write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); - return 0; -} - -static int subdev_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct ivtv *itv = sd_to_ivtv(sd); - u16 mask, data; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - mask = itv->card->gpio_audio_mute.mask; - data = ctrl->val ? itv->card->gpio_audio_mute.mute : 0; - if (mask) - write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | - (data & mask), IVTV_REG_GPIO_OUT); - return 0; - } - return -EINVAL; -} - - -static int subdev_log_status(struct v4l2_subdev *sd) -{ - struct ivtv *itv = sd_to_ivtv(sd); - - IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n", - read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT), - read_reg(IVTV_REG_GPIO_IN)); - v4l2_ctrl_handler_log_status(&itv->hdl_gpio, sd->name); - return 0; -} - -static int subdev_s_video_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct ivtv *itv = sd_to_ivtv(sd); - u16 mask, data; - - if (input > 2) /* 0:Tuner 1:Composite 2:S-Video */ - return -EINVAL; - mask = itv->card->gpio_video_input.mask; - if (input == 0) - data = itv->card->gpio_video_input.tuner; - else if (input == 1) - data = itv->card->gpio_video_input.composite; - else - data = itv->card->gpio_video_input.svideo; - if (mask) - write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); - return 0; -} - -static const struct v4l2_ctrl_ops gpio_ctrl_ops = { - .s_ctrl = subdev_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops subdev_core_ops = { - .log_status = subdev_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - -static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = { - .s_radio = subdev_s_radio, - .g_tuner = subdev_g_tuner, - .s_tuner = subdev_s_tuner, -}; - -static const struct v4l2_subdev_audio_ops subdev_audio_ops = { - .s_clock_freq = subdev_s_clock_freq, - .s_routing = subdev_s_audio_routing, -}; - -static const struct v4l2_subdev_video_ops subdev_video_ops = { - .s_routing = subdev_s_video_routing, -}; - -static const struct v4l2_subdev_ops subdev_ops = { - .core = &subdev_core_ops, - .tuner = &subdev_tuner_ops, - .audio = &subdev_audio_ops, - .video = &subdev_video_ops, -}; - -int ivtv_gpio_init(struct ivtv *itv) -{ - u16 pin = 0; - - if (itv->card->xceive_pin) - pin = 1 << itv->card->xceive_pin; - - if ((itv->card->gpio_init.direction | pin) == 0) - return 0; - - IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", - read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT)); - - /* init output data then direction */ - write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT); - write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR); - v4l2_subdev_init(&itv->sd_gpio, &subdev_ops); - snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->v4l2_dev.name); - itv->sd_gpio.grp_id = IVTV_HW_GPIO; - v4l2_ctrl_handler_init(&itv->hdl_gpio, 1); - v4l2_ctrl_new_std(&itv->hdl_gpio, &gpio_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - if (itv->hdl_gpio.error) - return itv->hdl_gpio.error; - itv->sd_gpio.ctrl_handler = &itv->hdl_gpio; - v4l2_ctrl_handler_setup(&itv->hdl_gpio); - return v4l2_device_register_subdev(&itv->v4l2_dev, &itv->sd_gpio); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-gpio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-gpio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-gpio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-gpio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* - gpio functions. - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_GPIO_H -#define IVTV_GPIO_H - -/* GPIO stuff */ -int ivtv_gpio_init(struct ivtv *itv); -void ivtv_reset_ir_gpio(struct ivtv *itv); -int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,760 +0,0 @@ -/* - I2C functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -/* - This file includes an i2c implementation that was reverse engineered - from the Hauppauge windows driver. Older ivtv versions used i2c-algo-bit, - which whilst fine under most circumstances, had trouble with the Zilog - CPU on the PVR-150 which handles IR functions (occasional inability to - communicate with the chip until it was reset) and also with the i2c - bus being completely unreachable when multiple PVR cards were present. - - The implementation is very similar to i2c-algo-bit, but there are enough - subtle differences that the two are hard to merge. The general strategy - employed by i2c-algo-bit is to use udelay() to implement the timing - when putting out bits on the scl/sda lines. The general strategy taken - here is to poll the lines for state changes (see ivtv_waitscl and - ivtv_waitsda). In addition there are small delays at various locations - which poll the SCL line 5 times (ivtv_scldelay). I would guess that - since this is memory mapped I/O that the length of those delays is tied - to the PCI bus clock. There is some extra code to do with recovery - and retries. Since it is not known what causes the actual i2c problems - in the first place, the only goal if one was to attempt to use - i2c-algo-bit would be to try to make it follow the same code path. - This would be a lot of work, and I'm also not convinced that it would - provide a generic benefit to i2c-algo-bit. Therefore consider this - an engineering solution -- not pretty, but it works. - - Some more general comments about what we are doing: - - The i2c bus is a 2 wire serial bus, with clock (SCL) and data (SDA) - lines. To communicate on the bus (as a master, we don't act as a slave), - we first initiate a start condition (ivtv_start). We then write the - address of the device that we want to communicate with, along with a flag - that indicates whether this is a read or a write. The slave then issues - an ACK signal (ivtv_ack), which tells us that it is ready for reading / - writing. We then proceed with reading or writing (ivtv_read/ivtv_write), - and finally issue a stop condition (ivtv_stop) to make the bus available - to other masters. - - There is an additional form of transaction where a write may be - immediately followed by a read. In this case, there is no intervening - stop condition. (Only the msp3400 chip uses this method of data transfer). - */ - -#include "ivtv-driver.h" -#include "ivtv-cards.h" -#include "ivtv-gpio.h" -#include "ivtv-i2c.h" -#include - -/* i2c implementation for cx23415/6 chip, ivtv project. - * Author: Kevin Thayer (nufan_wfk at yahoo.com) - */ -/* i2c stuff */ -#define IVTV_REG_I2C_SETSCL_OFFSET 0x7000 -#define IVTV_REG_I2C_SETSDA_OFFSET 0x7004 -#define IVTV_REG_I2C_GETSCL_OFFSET 0x7008 -#define IVTV_REG_I2C_GETSDA_OFFSET 0x700c - -#define IVTV_CS53L32A_I2C_ADDR 0x11 -#define IVTV_M52790_I2C_ADDR 0x48 -#define IVTV_CX25840_I2C_ADDR 0x44 -#define IVTV_SAA7115_I2C_ADDR 0x21 -#define IVTV_SAA7127_I2C_ADDR 0x44 -#define IVTV_SAA717x_I2C_ADDR 0x21 -#define IVTV_MSP3400_I2C_ADDR 0x40 -#define IVTV_HAUPPAUGE_I2C_ADDR 0x50 -#define IVTV_WM8739_I2C_ADDR 0x1a -#define IVTV_WM8775_I2C_ADDR 0x1b -#define IVTV_TEA5767_I2C_ADDR 0x60 -#define IVTV_UPD64031A_I2C_ADDR 0x12 -#define IVTV_UPD64083_I2C_ADDR 0x5c -#define IVTV_VP27SMPX_I2C_ADDR 0x5b -#define IVTV_M52790_I2C_ADDR 0x48 -#define IVTV_AVERMEDIA_IR_RX_I2C_ADDR 0x40 -#define IVTV_HAUP_EXT_IR_RX_I2C_ADDR 0x1a -#define IVTV_HAUP_INT_IR_RX_I2C_ADDR 0x18 -#define IVTV_Z8F0811_IR_TX_I2C_ADDR 0x70 -#define IVTV_Z8F0811_IR_RX_I2C_ADDR 0x71 -#define IVTV_ADAPTEC_IR_ADDR 0x6b - -/* This array should match the IVTV_HW_ defines */ -static const u8 hw_addrs[] = { - IVTV_CX25840_I2C_ADDR, - IVTV_SAA7115_I2C_ADDR, - IVTV_SAA7127_I2C_ADDR, - IVTV_MSP3400_I2C_ADDR, - 0, - IVTV_WM8775_I2C_ADDR, - IVTV_CS53L32A_I2C_ADDR, - 0, - IVTV_SAA7115_I2C_ADDR, - IVTV_UPD64031A_I2C_ADDR, - IVTV_UPD64083_I2C_ADDR, - IVTV_SAA717x_I2C_ADDR, - IVTV_WM8739_I2C_ADDR, - IVTV_VP27SMPX_I2C_ADDR, - IVTV_M52790_I2C_ADDR, - 0, /* IVTV_HW_GPIO dummy driver ID */ - IVTV_AVERMEDIA_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_AVER */ - IVTV_HAUP_EXT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_EXT */ - IVTV_HAUP_INT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_INT */ - IVTV_Z8F0811_IR_TX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_TX_HAUP */ - IVTV_Z8F0811_IR_RX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_RX_HAUP */ - IVTV_ADAPTEC_IR_ADDR, /* IVTV_HW_I2C_IR_RX_ADAPTEC */ -}; - -/* This array should match the IVTV_HW_ defines */ -static const char * const hw_devicenames[] = { - "cx25840", - "saa7115", - "saa7127_auto", /* saa7127 or saa7129 */ - "msp3400", - "tuner", - "wm8775", - "cs53l32a", - "tveeprom", - "saa7114", - "upd64031a", - "upd64083", - "saa717x", - "wm8739", - "vp27smpx", - "m52790", - "gpio", - "ir_video", /* IVTV_HW_I2C_IR_RX_AVER */ - "ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_EXT */ - "ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_INT */ - "ir_tx_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_TX_HAUP */ - "ir_rx_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_RX_HAUP */ - "ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */ -}; - -static int get_key_adaptec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char keybuf[4]; - - keybuf[0] = 0x00; - i2c_master_send(ir->c, keybuf, 1); - /* poll IR chip */ - if (i2c_master_recv(ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) { - return 0; - } - - /* key pressed ? */ - if (keybuf[2] == 0xff) - return 0; - - /* remove repeat bit */ - keybuf[2] &= 0x7f; - keybuf[3] |= 0x80; - - *ir_key = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24; - *ir_raw = *ir_key; - - return 1; -} - -static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) -{ - struct i2c_board_info info; - struct i2c_adapter *adap = &itv->i2c_adap; - struct IR_i2c_init_data *init_data = &itv->ir_i2c_init_data; - unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; - - /* Only allow one IR transmitter to be registered per board */ - if (hw & IVTV_HW_IR_TX_ANY) { - if (itv->hw_flags & IVTV_HW_IR_TX_ANY) - return -1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, type, I2C_NAME_SIZE); - return i2c_new_probed_device(adap, &info, addr_list, NULL) - == NULL ? -1 : 0; - } - - /* Only allow one IR receiver to be registered per board */ - if (itv->hw_flags & IVTV_HW_IR_RX_ANY) - return -1; - - /* Our default information for ir-kbd-i2c.c to use */ - switch (hw) { - case IVTV_HW_I2C_IR_RX_AVER: - init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS; - init_data->internal_get_key_func = - IR_KBD_GET_KEY_AVERMEDIA_CARDBUS; - init_data->type = RC_TYPE_OTHER; - init_data->name = "AVerMedia AVerTV card"; - break; - case IVTV_HW_I2C_IR_RX_HAUP_EXT: - case IVTV_HW_I2C_IR_RX_HAUP_INT: - init_data->ir_codes = RC_MAP_HAUPPAUGE; - init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; - init_data->type = RC_TYPE_RC5; - init_data->name = itv->card_name; - break; - case IVTV_HW_Z8F0811_IR_RX_HAUP: - /* Default to grey remote */ - init_data->ir_codes = RC_MAP_HAUPPAUGE; - init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; - init_data->name = itv->card_name; - break; - case IVTV_HW_I2C_IR_RX_ADAPTEC: - init_data->get_key = get_key_adaptec; - init_data->name = itv->card_name; - /* FIXME: The protocol and RC_MAP needs to be corrected */ - init_data->ir_codes = RC_MAP_EMPTY; - init_data->type = RC_TYPE_UNKNOWN; - break; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.platform_data = init_data; - strlcpy(info.type, type, I2C_NAME_SIZE); - - return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? - -1 : 0; -} - -/* Instantiate the IR receiver device using probing -- undesirable */ -struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv) -{ - struct i2c_board_info info; - /* - * The external IR receiver is at i2c address 0x34. - * The internal IR receiver is at i2c address 0x30. - * - * In theory, both can be fitted, and Hauppauge suggests an external - * overrides an internal. That's why we probe 0x1a (~0x34) first. CB - * - * Some of these addresses we probe may collide with other i2c address - * allocations, so this function must be called after all other i2c - * devices we care about are registered. - */ - const unsigned short addr_list[] = { - 0x1a, /* Hauppauge IR external - collides with WM8739 */ - 0x18, /* Hauppauge IR internal */ - I2C_CLIENT_END - }; - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list, NULL); -} - -int ivtv_i2c_register(struct ivtv *itv, unsigned idx) -{ - struct v4l2_subdev *sd; - struct i2c_adapter *adap = &itv->i2c_adap; - const char *type = hw_devicenames[idx]; - u32 hw = 1 << idx; - - if (idx >= ARRAY_SIZE(hw_addrs)) - return -1; - if (hw == IVTV_HW_TUNER) { - /* special tuner handling */ - sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, - itv->card_i2c->radio); - if (sd) - sd->grp_id = 1 << idx; - sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, - itv->card_i2c->demod); - if (sd) - sd->grp_id = 1 << idx; - sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, - itv->card_i2c->tv); - if (sd) - sd->grp_id = 1 << idx; - return sd ? 0 : -1; - } - - if (hw & IVTV_HW_IR_ANY) - return ivtv_i2c_new_ir(itv, hw, type, hw_addrs[idx]); - - /* Is it not an I2C device or one we do not wish to register? */ - if (!hw_addrs[idx]) - return -1; - - /* It's an I2C device other than an analog tuner or IR chip */ - if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) { - sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, - adap, type, 0, I2C_ADDRS(hw_addrs[idx])); - } else if (hw == IVTV_HW_CX25840) { - struct cx25840_platform_data pdata; - struct i2c_board_info cx25840_info = { - .type = "cx25840", - .addr = hw_addrs[idx], - .platform_data = &pdata, - }; - - pdata.pvr150_workaround = itv->pvr150_workaround; - sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, - &cx25840_info, NULL); - } else { - sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, - adap, type, hw_addrs[idx], NULL); - } - if (sd) - sd->grp_id = 1 << idx; - return sd ? 0 : -1; -} - -struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw) -{ - struct v4l2_subdev *result = NULL; - struct v4l2_subdev *sd; - - spin_lock(&itv->v4l2_dev.lock); - v4l2_device_for_each_subdev(sd, &itv->v4l2_dev) { - if (sd->grp_id == hw) { - result = sd; - break; - } - } - spin_unlock(&itv->v4l2_dev.lock); - return result; -} - -/* Set the serial clock line to the desired state */ -static void ivtv_setscl(struct ivtv *itv, int state) -{ - /* write them out */ - /* write bits are inverted */ - write_reg(~state, IVTV_REG_I2C_SETSCL_OFFSET); -} - -/* Set the serial data line to the desired state */ -static void ivtv_setsda(struct ivtv *itv, int state) -{ - /* write them out */ - /* write bits are inverted */ - write_reg(~state & 1, IVTV_REG_I2C_SETSDA_OFFSET); -} - -/* Read the serial clock line */ -static int ivtv_getscl(struct ivtv *itv) -{ - return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; -} - -/* Read the serial data line */ -static int ivtv_getsda(struct ivtv *itv) -{ - return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; -} - -/* Implement a short delay by polling the serial clock line */ -static void ivtv_scldelay(struct ivtv *itv) -{ - int i; - - for (i = 0; i < 5; ++i) - ivtv_getscl(itv); -} - -/* Wait for the serial clock line to become set to a specific value */ -static int ivtv_waitscl(struct ivtv *itv, int val) -{ - int i; - - ivtv_scldelay(itv); - for (i = 0; i < 1000; ++i) { - if (ivtv_getscl(itv) == val) - return 1; - } - return 0; -} - -/* Wait for the serial data line to become set to a specific value */ -static int ivtv_waitsda(struct ivtv *itv, int val) -{ - int i; - - ivtv_scldelay(itv); - for (i = 0; i < 1000; ++i) { - if (ivtv_getsda(itv) == val) - return 1; - } - return 0; -} - -/* Wait for the slave to issue an ACK */ -static int ivtv_ack(struct ivtv *itv) -{ - int ret = 0; - - if (ivtv_getscl(itv) == 1) { - IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n"); - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n"); - return -EREMOTEIO; - } - } - ivtv_setsda(itv, 1); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - if (!ivtv_waitsda(itv, 0)) { - IVTV_DEBUG_I2C("Slave did not ack\n"); - ret = -EREMOTEIO; - } - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("Failed to set SCL low after ACK\n"); - ret = -EREMOTEIO; - } - return ret; -} - -/* Write a single byte to the i2c bus and wait for the slave to ACK */ -static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte) -{ - int i, bit; - - IVTV_DEBUG_HI_I2C("write %x\n",byte); - for (i = 0; i < 8; ++i, byte<<=1) { - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("Error setting SCL low\n"); - return -EREMOTEIO; - } - bit = (byte>>7)&1; - ivtv_setsda(itv, bit); - if (!ivtv_waitsda(itv, bit)) { - IVTV_DEBUG_I2C("Error setting SDA\n"); - return -EREMOTEIO; - } - ivtv_setscl(itv, 1); - if (!ivtv_waitscl(itv, 1)) { - IVTV_DEBUG_I2C("Slave not ready for bit\n"); - return -EREMOTEIO; - } - } - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("Error setting SCL low\n"); - return -EREMOTEIO; - } - return ivtv_ack(itv); -} - -/* Read a byte from the i2c bus and send a NACK if applicable (i.e. for the - final byte) */ -static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack) -{ - int i; - - *byte = 0; - - ivtv_setsda(itv, 1); - ivtv_scldelay(itv); - for (i = 0; i < 8; ++i) { - ivtv_setscl(itv, 0); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - if (!ivtv_waitscl(itv, 1)) { - IVTV_DEBUG_I2C("Error setting SCL high\n"); - return -EREMOTEIO; - } - *byte = ((*byte)<<1)|ivtv_getsda(itv); - } - ivtv_setscl(itv, 0); - ivtv_scldelay(itv); - ivtv_setsda(itv, nack); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - ivtv_scldelay(itv); - ivtv_setscl(itv, 0); - ivtv_scldelay(itv); - IVTV_DEBUG_HI_I2C("read %x\n",*byte); - return 0; -} - -/* Issue a start condition on the i2c bus to alert slaves to prepare for - an address write */ -static int ivtv_start(struct ivtv *itv) -{ - int sda; - - sda = ivtv_getsda(itv); - if (sda != 1) { - IVTV_DEBUG_HI_I2C("SDA was low at start\n"); - ivtv_setsda(itv, 1); - if (!ivtv_waitsda(itv, 1)) { - IVTV_DEBUG_I2C("SDA stuck low\n"); - return -EREMOTEIO; - } - } - if (ivtv_getscl(itv) != 1) { - ivtv_setscl(itv, 1); - if (!ivtv_waitscl(itv, 1)) { - IVTV_DEBUG_I2C("SCL stuck low at start\n"); - return -EREMOTEIO; - } - } - ivtv_setsda(itv, 0); - ivtv_scldelay(itv); - return 0; -} - -/* Issue a stop condition on the i2c bus to release it */ -static int ivtv_stop(struct ivtv *itv) -{ - int i; - - if (ivtv_getscl(itv) != 0) { - IVTV_DEBUG_HI_I2C("SCL not low when stopping\n"); - ivtv_setscl(itv, 0); - if (!ivtv_waitscl(itv, 0)) { - IVTV_DEBUG_I2C("SCL could not be set low\n"); - } - } - ivtv_setsda(itv, 0); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - if (!ivtv_waitscl(itv, 1)) { - IVTV_DEBUG_I2C("SCL could not be set high\n"); - return -EREMOTEIO; - } - ivtv_scldelay(itv); - ivtv_setsda(itv, 1); - if (!ivtv_waitsda(itv, 1)) { - IVTV_DEBUG_I2C("resetting I2C\n"); - for (i = 0; i < 16; ++i) { - ivtv_setscl(itv, 0); - ivtv_scldelay(itv); - ivtv_setscl(itv, 1); - ivtv_scldelay(itv); - ivtv_setsda(itv, 1); - } - ivtv_waitsda(itv, 1); - return -EREMOTEIO; - } - return 0; -} - -/* Write a message to the given i2c slave. do_stop may be 0 to prevent - issuing the i2c stop condition (when following with a read) */ -static int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop) -{ - int retry, ret = -EREMOTEIO; - u32 i; - - for (retry = 0; ret != 0 && retry < 8; ++retry) { - ret = ivtv_start(itv); - - if (ret == 0) { - ret = ivtv_sendbyte(itv, addr<<1); - for (i = 0; ret == 0 && i < len; ++i) - ret = ivtv_sendbyte(itv, data[i]); - } - if (ret != 0 || do_stop) { - ivtv_stop(itv); - } - } - if (ret) - IVTV_DEBUG_I2C("i2c write to %x failed\n", addr); - return ret; -} - -/* Read data from the given i2c slave. A stop condition is always issued. */ -static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len) -{ - int retry, ret = -EREMOTEIO; - u32 i; - - for (retry = 0; ret != 0 && retry < 8; ++retry) { - ret = ivtv_start(itv); - if (ret == 0) - ret = ivtv_sendbyte(itv, (addr << 1) | 1); - for (i = 0; ret == 0 && i < len; ++i) { - ret = ivtv_readbyte(itv, &data[i], i == len - 1); - } - ivtv_stop(itv); - } - if (ret) - IVTV_DEBUG_I2C("i2c read from %x failed\n", addr); - return ret; -} - -/* Kernel i2c transfer implementation. Takes a number of messages to be read - or written. If a read follows a write, this will occur without an - intervening stop condition */ -static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) -{ - struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap); - struct ivtv *itv = to_ivtv(v4l2_dev); - int retval; - int i; - - mutex_lock(&itv->i2c_bus_lock); - for (i = retval = 0; retval == 0 && i < num; i++) { - if (msgs[i].flags & I2C_M_RD) - retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len); - else { - /* if followed by a read, don't stop */ - int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD); - - retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop); - } - } - mutex_unlock(&itv->i2c_bus_lock); - return retval ? retval : num; -} - -/* Kernel i2c capabilities */ -static u32 ivtv_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm ivtv_algo = { - .master_xfer = ivtv_xfer, - .functionality = ivtv_functionality, -}; - -/* template for our-bit banger */ -static struct i2c_adapter ivtv_i2c_adap_hw_template = { - .name = "ivtv i2c driver", - .algo = &ivtv_algo, - .algo_data = NULL, /* filled from template */ - .owner = THIS_MODULE, -}; - -static void ivtv_setscl_old(void *data, int state) -{ - struct ivtv *itv = (struct ivtv *)data; - - if (state) - itv->i2c_state |= 0x01; - else - itv->i2c_state &= ~0x01; - - /* write them out */ - /* write bits are inverted */ - write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET); -} - -static void ivtv_setsda_old(void *data, int state) -{ - struct ivtv *itv = (struct ivtv *)data; - - if (state) - itv->i2c_state |= 0x01; - else - itv->i2c_state &= ~0x01; - - /* write them out */ - /* write bits are inverted */ - write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET); -} - -static int ivtv_getscl_old(void *data) -{ - struct ivtv *itv = (struct ivtv *)data; - - return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; -} - -static int ivtv_getsda_old(void *data) -{ - struct ivtv *itv = (struct ivtv *)data; - - return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; -} - -/* template for i2c-bit-algo */ -static struct i2c_adapter ivtv_i2c_adap_template = { - .name = "ivtv i2c driver", - .algo = NULL, /* set by i2c-algo-bit */ - .algo_data = NULL, /* filled from template */ - .owner = THIS_MODULE, -}; - -#define IVTV_ALGO_BIT_TIMEOUT (2) /* seconds */ - -static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { - .setsda = ivtv_setsda_old, - .setscl = ivtv_setscl_old, - .getsda = ivtv_getsda_old, - .getscl = ivtv_getscl_old, - .udelay = IVTV_DEFAULT_I2C_CLOCK_PERIOD / 2, /* microseconds */ - .timeout = IVTV_ALGO_BIT_TIMEOUT * HZ, /* jiffies */ -}; - -static struct i2c_client ivtv_i2c_client_template = { - .name = "ivtv internal", -}; - -/* init + register i2c adapter */ -int init_ivtv_i2c(struct ivtv *itv) -{ - int retval; - - IVTV_DEBUG_I2C("i2c init\n"); - - /* Sanity checks for the I2C hardware arrays. They must be the - * same size. - */ - if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs)) { - IVTV_ERR("Mismatched I2C hardware arrays\n"); - return -ENODEV; - } - if (itv->options.newi2c > 0) { - memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template, - sizeof(struct i2c_adapter)); - } else { - memcpy(&itv->i2c_adap, &ivtv_i2c_adap_template, - sizeof(struct i2c_adapter)); - memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, - sizeof(struct i2c_algo_bit_data)); - } - itv->i2c_algo.udelay = itv->options.i2c_clock_period / 2; - itv->i2c_algo.data = itv; - itv->i2c_adap.algo_data = &itv->i2c_algo; - - sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", - itv->instance); - i2c_set_adapdata(&itv->i2c_adap, &itv->v4l2_dev); - - memcpy(&itv->i2c_client, &ivtv_i2c_client_template, - sizeof(struct i2c_client)); - itv->i2c_client.adapter = &itv->i2c_adap; - itv->i2c_adap.dev.parent = &itv->pdev->dev; - - IVTV_DEBUG_I2C("setting scl and sda to 1\n"); - ivtv_setscl(itv, 1); - ivtv_setsda(itv, 1); - - if (itv->options.newi2c > 0) - retval = i2c_add_adapter(&itv->i2c_adap); - else - retval = i2c_bit_add_bus(&itv->i2c_adap); - - return retval; -} - -void exit_ivtv_i2c(struct ivtv *itv) -{ - IVTV_DEBUG_I2C("i2c exit\n"); - - i2c_del_adapter(&itv->i2c_adap); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-i2c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-i2c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/* - I2C functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_I2C_H -#define IVTV_I2C_H - -struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv); -int ivtv_i2c_register(struct ivtv *itv, unsigned idx); -struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw); - -/* init + register i2c algo-bit adapter */ -int init_ivtv_i2c(struct ivtv *itv); -void exit_ivtv_i2c(struct ivtv *itv); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-ioctl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-ioctl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-ioctl.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-ioctl.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1926 +0,0 @@ -/* - ioctl system call - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-version.h" -#include "ivtv-mailbox.h" -#include "ivtv-i2c.h" -#include "ivtv-queue.h" -#include "ivtv-fileops.h" -#include "ivtv-vbi.h" -#include "ivtv-routing.h" -#include "ivtv-streams.h" -#include "ivtv-yuv.h" -#include "ivtv-ioctl.h" -#include "ivtv-gpio.h" -#include "ivtv-controls.h" -#include "ivtv-cards.h" -#include -#include -#include -#include -#include - -u16 ivtv_service2vbi(int type) -{ - switch (type) { - case V4L2_SLICED_TELETEXT_B: - return IVTV_SLICED_TYPE_TELETEXT_B; - case V4L2_SLICED_CAPTION_525: - return IVTV_SLICED_TYPE_CAPTION_525; - case V4L2_SLICED_WSS_625: - return IVTV_SLICED_TYPE_WSS_625; - case V4L2_SLICED_VPS: - return IVTV_SLICED_TYPE_VPS; - default: - return 0; - } -} - -static int valid_service_line(int field, int line, int is_pal) -{ - return (is_pal && line >= 6 && (line != 23 || field == 0)) || - (!is_pal && line >= 10 && line < 22); -} - -static u16 select_service_from_set(int field, int line, u16 set, int is_pal) -{ - u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); - int i; - - set = set & valid_set; - if (set == 0 || !valid_service_line(field, line, is_pal)) { - return 0; - } - if (!is_pal) { - if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) - return V4L2_SLICED_CAPTION_525; - } - else { - if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) - return V4L2_SLICED_VPS; - if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) - return V4L2_SLICED_WSS_625; - if (line == 23) - return 0; - } - for (i = 0; i < 32; i++) { - if ((1 << i) & set) - return 1 << i; - } - return 0; -} - -void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) -{ - u16 set = fmt->service_set; - int f, l; - - fmt->service_set = 0; - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); - } - } -} - -static void check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) -{ - int f, l; - - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); - } - } -} - -u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt) -{ - int f, l; - u16 set = 0; - - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - set |= fmt->service_lines[f][l]; - } - } - return set; -} - -void ivtv_set_osd_alpha(struct ivtv *itv) -{ - ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, - itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); - ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key); -} - -int ivtv_set_speed(struct ivtv *itv, int speed) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - int single_step = (speed == 1 || speed == -1); - DEFINE_WAIT(wait); - - if (speed == 0) speed = 1000; - - /* No change? */ - if (speed == itv->speed && !single_step) - return 0; - - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - - if (single_step && (speed < 0) == (itv->speed < 0)) { - /* Single step video and no need to change direction */ - ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); - itv->speed = speed; - return 0; - } - if (single_step) - /* Need to change direction */ - speed = speed < 0 ? -1000 : 1000; - - data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0; - data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0; - data[1] = (speed < 0); - data[2] = speed < 0 ? 3 : 7; - data[3] = v4l2_ctrl_g_ctrl(itv->cxhdl.video_b_frames); - data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0; - data[5] = 0; - data[6] = 0; - - if (speed == 1500 || speed == -1500) data[0] |= 1; - else if (speed == 2000 || speed == -2000) data[0] |= 2; - else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed); - else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed); - - /* If not decoding, just change speed setting */ - if (atomic_read(&itv->decoding) > 0) { - int got_sig = 0; - - /* Stop all DMA and decoding activity */ - ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0); - - /* Wait for any DMA to finish */ - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); - while (test_bit(IVTV_F_I_DMA, &itv->i_flags)) { - got_sig = signal_pending(current); - if (got_sig) - break; - got_sig = 0; - schedule(); - } - finish_wait(&itv->dma_waitq, &wait); - if (got_sig) - return -EINTR; - - /* Change Speed safely */ - ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data); - IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", - data[0], data[1], data[2], data[3], data[4], data[5], data[6]); - } - if (single_step) { - speed = (speed < 0) ? -1 : 1; - ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); - } - itv->speed = speed; - return 0; -} - -static int ivtv_validate_speed(int cur_speed, int new_speed) -{ - int fact = new_speed < 0 ? -1 : 1; - int s; - - if (cur_speed == 0) - cur_speed = 1000; - if (new_speed < 0) - new_speed = -new_speed; - if (cur_speed < 0) - cur_speed = -cur_speed; - - if (cur_speed <= new_speed) { - if (new_speed > 1500) - return fact * 2000; - if (new_speed > 1000) - return fact * 1500; - } - else { - if (new_speed >= 2000) - return fact * 2000; - if (new_speed >= 1500) - return fact * 1500; - if (new_speed >= 1000) - return fact * 1000; - } - if (new_speed == 0) - return 1000; - if (new_speed == 1 || new_speed == 1000) - return fact * new_speed; - - s = new_speed; - new_speed = 1000 / new_speed; - if (1000 / cur_speed == new_speed) - new_speed += (cur_speed < s) ? -1 : 1; - if (new_speed > 60) return 1000 / (fact * 60); - return 1000 / (fact * new_speed); -} - -static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, - struct video_command *vc, int try) -{ - struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - - switch (vc->cmd) { - case VIDEO_CMD_PLAY: { - vc->flags = 0; - vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed); - if (vc->play.speed < 0) - vc->play.format = VIDEO_PLAY_FMT_GOP; - if (try) break; - - if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) - return -EBUSY; - if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { - /* forces ivtv_set_speed to be called */ - itv->speed = 0; - } - return ivtv_start_decoding(id, vc->play.speed); - } - - case VIDEO_CMD_STOP: - vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK; - if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY) - vc->stop.pts = 0; - if (try) break; - if (atomic_read(&itv->decoding) == 0) - return 0; - if (itv->output_mode != OUT_MPG) - return -EBUSY; - - itv->output_mode = OUT_NONE; - return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts); - - case VIDEO_CMD_FREEZE: - vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK; - if (try) break; - if (itv->output_mode != OUT_MPG) - return -EBUSY; - if (atomic_read(&itv->decoding) > 0) { - ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, - (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0); - set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); - } - break; - - case VIDEO_CMD_CONTINUE: - vc->flags = 0; - if (try) break; - if (itv->output_mode != OUT_MPG) - return -EBUSY; - if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { - int speed = itv->speed; - itv->speed = 0; - return ivtv_start_decoding(id, speed); - } - break; - - default: - return -EINVAL; - } - return 0; -} - -static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv *itv = fh2id(fh)->itv; - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) - return -EINVAL; - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - if (itv->is_60hz) { - vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } else { - vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; - vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; - } - vbifmt->service_set = ivtv_get_service_set(vbifmt); - return 0; -} - -static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - pixfmt->width = itv->cxhdl.width; - pixfmt->height = itv->cxhdl.height; - pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - pixfmt->field = V4L2_FIELD_INTERLACED; - pixfmt->priv = 0; - if (id->type == IVTV_ENC_STREAM_TYPE_YUV) { - pixfmt->pixelformat = V4L2_PIX_FMT_HM12; - /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */ - pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; - pixfmt->bytesperline = 720; - } else { - pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; - pixfmt->sizeimage = 128 * 1024; - pixfmt->bytesperline = 0; - } - return 0; -} - -static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv *itv = fh2id(fh)->itv; - struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; - - vbifmt->sampling_rate = 27000000; - vbifmt->offset = 248; - vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4; - vbifmt->sample_format = V4L2_PIX_FMT_GREY; - vbifmt->start[0] = itv->vbi.start[0]; - vbifmt->start[1] = itv->vbi.start[1]; - vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count; - vbifmt->flags = 0; - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - return 0; -} - -static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - - if (id->type == IVTV_DEC_STREAM_TYPE_VBI) { - vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : - V4L2_SLICED_VBI_525; - ivtv_expand_service_set(vbifmt, itv->is_50hz); - return 0; - } - - v4l2_subdev_call(itv->sd_video, vbi, g_sliced_fmt, vbifmt); - vbifmt->service_set = ivtv_get_service_set(vbifmt); - return 0; -} - -static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - pixfmt->width = itv->main_rect.width; - pixfmt->height = itv->main_rect.height; - pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - pixfmt->field = V4L2_FIELD_INTERLACED; - pixfmt->priv = 0; - if (id->type == IVTV_DEC_STREAM_TYPE_YUV) { - switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { - case IVTV_YUV_MODE_INTERLACED: - pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? - V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; - break; - case IVTV_YUV_MODE_PROGRESSIVE: - pixfmt->field = V4L2_FIELD_NONE; - break; - default: - pixfmt->field = V4L2_FIELD_ANY; - break; - } - pixfmt->pixelformat = V4L2_PIX_FMT_HM12; - pixfmt->bytesperline = 720; - pixfmt->width = itv->yuv_info.v4l2_src_w; - pixfmt->height = itv->yuv_info.v4l2_src_h; - /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ - pixfmt->sizeimage = - 1080 * ((pixfmt->height + 31) & ~31); - } else { - pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; - pixfmt->sizeimage = 128 * 1024; - pixfmt->bytesperline = 0; - } - return 0; -} - -static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv *itv = fh2id(fh)->itv; - struct v4l2_window *winfmt = &fmt->fmt.win; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - winfmt->chromakey = itv->osd_chroma_key; - winfmt->global_alpha = itv->osd_global_alpha; - winfmt->field = V4L2_FIELD_INTERLACED; - winfmt->clips = NULL; - winfmt->clipcount = 0; - winfmt->bitmap = NULL; - winfmt->w.top = winfmt->w.left = 0; - winfmt->w.width = itv->osd_rect.width; - winfmt->w.height = itv->osd_rect.height; - return 0; -} - -static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) -{ - return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); -} - -static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; - int min_h = 2; - - w = min(w, 720); - w = max(w, 2); - if (id->type == IVTV_ENC_STREAM_TYPE_YUV) { - /* YUV height must be a multiple of 32 */ - h &= ~0x1f; - min_h = 32; - } - h = min(h, itv->is_50hz ? 576 : 480); - h = max(h, min_h); - ivtv_g_fmt_vid_cap(file, fh, fmt); - fmt->fmt.pix.width = w; - fmt->fmt.pix.height = h; - return 0; -} - -static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - return ivtv_g_fmt_vbi_cap(file, fh, fmt); -} - -static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - - if (id->type == IVTV_DEC_STREAM_TYPE_VBI) - return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt); - - /* set sliced VBI capture format */ - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - - if (vbifmt->service_set) - ivtv_expand_service_set(vbifmt, itv->is_50hz); - check_service_set(vbifmt, itv->is_50hz); - vbifmt->service_set = ivtv_get_service_set(vbifmt); - return 0; -} - -static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv_open_id *id = fh2id(fh); - s32 w = fmt->fmt.pix.width; - s32 h = fmt->fmt.pix.height; - int field = fmt->fmt.pix.field; - int ret = ivtv_g_fmt_vid_out(file, fh, fmt); - - w = min(w, 720); - w = max(w, 2); - /* Why can the height be 576 even when the output is NTSC? - - Internally the buffers of the PVR350 are always set to 720x576. The - decoded video frame will always be placed in the top left corner of - this buffer. For any video which is not 720x576, the buffer will - then be cropped to remove the unused right and lower areas, with - the remaining image being scaled by the hardware to fit the display - area. The video can be scaled both up and down, so a 720x480 video - can be displayed full-screen on PAL and a 720x576 video can be - displayed without cropping on NTSC. - - Note that the scaling only occurs on the video stream, the osd - resolution is locked to the broadcast standard and not scaled. - - Thanks to Ian Armstrong for this explanation. */ - h = min(h, 576); - h = max(h, 2); - if (id->type == IVTV_DEC_STREAM_TYPE_YUV) - fmt->fmt.pix.field = field; - fmt->fmt.pix.width = w; - fmt->fmt.pix.height = h; - return ret; -} - -static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv *itv = fh2id(fh)->itv; - u32 chromakey = fmt->fmt.win.chromakey; - u8 global_alpha = fmt->fmt.win.global_alpha; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - ivtv_g_fmt_vid_out_overlay(file, fh, fmt); - fmt->fmt.win.chromakey = chromakey; - fmt->fmt.win.global_alpha = global_alpha; - return 0; -} - -static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) -{ - return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); -} - -static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - struct v4l2_mbus_framefmt mbus_fmt; - int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; - - if (ret) - return ret; - - if (itv->cxhdl.width == w && itv->cxhdl.height == h) - return 0; - - if (atomic_read(&itv->capturing) > 0) - return -EBUSY; - - itv->cxhdl.width = w; - itv->cxhdl.height = h; - if (v4l2_ctrl_g_ctrl(itv->cxhdl.video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) - fmt->fmt.pix.width /= 2; - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = h; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt); - return ivtv_g_fmt_vid_cap(file, fh, fmt); -} - -static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0) - return -EBUSY; - itv->vbi.sliced_in->service_set = 0; - itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; - v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &fmt->fmt.vbi); - return ivtv_g_fmt_vbi_cap(file, fh, fmt); -} - -static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt); - - if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI) - return ret; - - check_service_set(vbifmt, itv->is_50hz); - if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0) - return -EBUSY; - itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, vbifmt); - memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in)); - return 0; -} - -static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - int ret = ivtv_try_fmt_vid_out(file, fh, fmt); - - if (ret) - return ret; - - if (id->type != IVTV_DEC_STREAM_TYPE_YUV) - return 0; - - /* Return now if we already have some frame data */ - if (yi->stream_size) - return -EBUSY; - - yi->v4l2_src_w = fmt->fmt.pix.width; - yi->v4l2_src_h = fmt->fmt.pix.height; - - switch (fmt->fmt.pix.field) { - case V4L2_FIELD_NONE: - yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; - break; - case V4L2_FIELD_ANY: - yi->lace_mode = IVTV_YUV_MODE_AUTO; - break; - case V4L2_FIELD_INTERLACED_BT: - yi->lace_mode = - IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; - break; - case V4L2_FIELD_INTERLACED_TB: - default: - yi->lace_mode = IVTV_YUV_MODE_INTERLACED; - break; - } - yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; - - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - itv->dma_data_req_size = - 1080 * ((yi->v4l2_src_h + 31) & ~31); - - return 0; -} - -static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ivtv *itv = fh2id(fh)->itv; - int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt); - - if (ret == 0) { - itv->osd_chroma_key = fmt->fmt.win.chromakey; - itv->osd_global_alpha = fmt->fmt.win.global_alpha; - ivtv_set_osd_alpha(itv); - } - return ret; -} - -static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip) -{ - struct ivtv *itv = fh2id(fh)->itv; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (chip->match.type == V4L2_CHIP_MATCH_HOST) { - if (v4l2_chip_match_host(&chip->match)) - chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; - return 0; - } - if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && - chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) - return -EINVAL; - /* TODO: is this correct? */ - return ivtv_call_all_err(itv, core, g_chip_ident, chip); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) -{ - struct v4l2_dbg_register *regs = arg; - volatile u8 __iomem *reg_start; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) - reg_start = itv->reg_mem - IVTV_REG_OFFSET; - else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET && - regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) - reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; - else if (regs->reg < IVTV_ENCODER_SIZE) - reg_start = itv->enc_mem; - else - return -EINVAL; - - regs->size = 4; - if (cmd == VIDIOC_DBG_G_REGISTER) - regs->val = readl(regs->reg + reg_start); - else - writel(regs->val, regs->reg + reg_start); - return 0; -} - -static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (v4l2_chip_match_host(®->match)) - return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg); - /* TODO: subdev errors should not be ignored, this should become a - subdev helper function. */ - ivtv_call_all(itv, core, g_register, reg); - return 0; -} - -static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (v4l2_chip_match_host(®->match)) - return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg); - /* TODO: subdev errors should not be ignored, this should become a - subdev helper function. */ - ivtv_call_all(itv, core, s_register, reg); - return 0; -} -#endif - -static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) -{ - struct ivtv *itv = fh2id(fh)->itv; - - strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); - strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); - snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); - vcap->version = IVTV_DRIVER_VERSION; /* version */ - vcap->capabilities = itv->v4l2_cap; /* capabilities */ - return 0; -} - -static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) -{ - struct ivtv *itv = fh2id(fh)->itv; - - return ivtv_get_audio_input(itv, vin->index, vin); -} - -static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) -{ - struct ivtv *itv = fh2id(fh)->itv; - - vin->index = itv->audio_input; - return ivtv_get_audio_input(itv, vin->index, vin); -} - -static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (vout->index >= itv->nof_audio_inputs) - return -EINVAL; - - itv->audio_input = vout->index; - ivtv_audio_set_io(itv); - - return 0; -} - -static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin) -{ - struct ivtv *itv = fh2id(fh)->itv; - - /* set it to defaults from our table */ - return ivtv_get_audio_output(itv, vin->index, vin); -} - -static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) -{ - struct ivtv *itv = fh2id(fh)->itv; - - vin->index = 0; - return ivtv_get_audio_output(itv, vin->index, vin); -} - -static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout) -{ - struct ivtv *itv = fh2id(fh)->itv; - - return ivtv_get_audio_output(itv, vout->index, vout); -} - -static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - struct ivtv *itv = fh2id(fh)->itv; - - /* set it to defaults from our table */ - return ivtv_get_input(itv, vin->index, vin); -} - -static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout) -{ - struct ivtv *itv = fh2id(fh)->itv; - - return ivtv_get_output(itv, vout->index, vout); -} - -static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - int streamtype; - - streamtype = id->type; - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - cropcap->bounds.height = itv->is_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; - } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - if (yi->track_osd) { - cropcap->bounds.width = yi->osd_full_w; - cropcap->bounds.height = yi->osd_full_h; - } else { - cropcap->bounds.width = 720; - cropcap->bounds.height = - itv->is_out_50hz ? 576 : 480; - } - cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; - } else { - cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; - } - cropcap->defrect = cropcap->bounds; - return 0; -} - -static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - int streamtype; - - streamtype = id->type; - - if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - yi->main_rect = crop->c; - return 0; - } else { - if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { - itv->main_rect = crop->c; - return 0; - } - } - return -EINVAL; - } - return -EINVAL; -} - -static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - int streamtype; - - streamtype = id->type; - - if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) - crop->c = yi->main_rect; - else - crop->c = itv->main_rect; - return 0; - } - return -EINVAL; -} - -static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, - { 0, 0, 0, 0 } - }, - { 1, 0, V4L2_FMT_FLAG_COMPRESSED, - "MPEG", V4L2_PIX_FMT_MPEG, - { 0, 0, 0, 0 } - } - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 1) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - struct ivtv *itv = fh2id(fh)->itv; - - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, - { 0, 0, 0, 0 } - }, - { 1, 0, V4L2_FMT_FLAG_COMPRESSED, - "MPEG", V4L2_PIX_FMT_MPEG, - { 0, 0, 0, 0 } - } - }; - enum v4l2_buf_type type = fmt->type; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - - if (fmt->index > 1) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - - return 0; -} - -static int ivtv_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct ivtv *itv = fh2id(fh)->itv; - - *i = itv->active_input; - - return 0; -} - -int ivtv_s_input(struct file *file, void *fh, unsigned int inp) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (inp < 0 || inp >= itv->nof_inputs) - return -EINVAL; - - if (inp == itv->active_input) { - IVTV_DEBUG_INFO("Input unchanged\n"); - return 0; - } - - if (atomic_read(&itv->capturing) > 0) { - return -EBUSY; - } - - IVTV_DEBUG_INFO("Changing input from %d to %d\n", - itv->active_input, inp); - - itv->active_input = inp; - /* Set the audio input to whatever is appropriate for the - input type. */ - itv->audio_input = itv->card->video_inputs[inp].audio_index; - - /* prevent others from messing with the streams until - we're finished changing inputs. */ - ivtv_mute(itv); - ivtv_video_set_io(itv); - ivtv_audio_set_io(itv); - ivtv_unmute(itv); - - return 0; -} - -static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - - *i = itv->active_output; - - return 0; -} - -static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (outp >= itv->card->nof_outputs) - return -EINVAL; - - if (outp == itv->active_output) { - IVTV_DEBUG_INFO("Output unchanged\n"); - return 0; - } - IVTV_DEBUG_INFO("Changing output from %d to %d\n", - itv->active_output, outp); - - itv->active_output = outp; - ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, - SAA7127_INPUT_TYPE_NORMAL, - itv->card->video_outputs[outp].video_output, 0); - - return 0; -} - -static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (vf->tuner != 0) - return -EINVAL; - - ivtv_call_all(itv, tuner, g_frequency, vf); - return 0; -} - -int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (vf->tuner != 0) - return -EINVAL; - - ivtv_mute(itv); - IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); - ivtv_call_all(itv, tuner, s_frequency, vf); - ivtv_unmute(itv); - return 0; -} - -static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) -{ - struct ivtv *itv = fh2id(fh)->itv; - - *std = itv->std; - return 0; -} - -int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) -{ - DEFINE_WAIT(wait); - struct ivtv *itv = fh2id(fh)->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - int f; - - if ((*std & V4L2_STD_ALL) == 0) - return -EINVAL; - - if (*std == itv->std) - return 0; - - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || - atomic_read(&itv->capturing) > 0 || - atomic_read(&itv->decoding) > 0) { - /* Switching standard would turn off the radio or mess - with already running streams, prevent that by - returning EBUSY. */ - return -EBUSY; - } - - itv->std = *std; - itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; - itv->is_50hz = !itv->is_60hz; - cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz); - itv->cxhdl.width = 720; - itv->cxhdl.height = itv->is_50hz ? 576 : 480; - itv->vbi.count = itv->is_50hz ? 18 : 12; - itv->vbi.start[0] = itv->is_50hz ? 6 : 10; - itv->vbi.start[1] = itv->is_50hz ? 318 : 273; - - if (itv->hw_flags & IVTV_HW_CX25840) - itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; - - IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std); - - /* Tuner */ - ivtv_call_all(itv, core, s_std, itv->std); - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - /* set display standard */ - itv->std_out = *std; - itv->is_out_60hz = itv->is_60hz; - itv->is_out_50hz = itv->is_50hz; - ivtv_call_all(itv, video, s_std_output, itv->std_out); - - /* - * The next firmware call is time sensitive. Time it to - * avoid risk of a hard lock, by trying to ensure the call - * happens within the first 100 lines of the top field. - * Make 4 attempts to sync to the decoder before giving up. - */ - for (f = 0; f < 4; f++) { - prepare_to_wait(&itv->vsync_waitq, &wait, - TASK_UNINTERRUPTIBLE); - if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100) - break; - schedule_timeout(msecs_to_jiffies(25)); - } - finish_wait(&itv->vsync_waitq, &wait); - - if (f == 4) - IVTV_WARN("Mode change failed to sync to decoder\n"); - - ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); - itv->main_rect.left = itv->main_rect.top = 0; - itv->main_rect.width = 720; - itv->main_rect.height = itv->cxhdl.height; - ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - 720, itv->main_rect.height, 0, 0); - yi->main_rect = itv->main_rect; - if (!itv->osd_info) { - yi->osd_full_w = 720; - yi->osd_full_h = itv->is_out_50hz ? 576 : 480; - } - } - return 0; -} - -static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - - if (vt->index != 0) - return -EINVAL; - - ivtv_call_all(itv, tuner, s_tuner, vt); - - return 0; -} - -static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (vt->index != 0) - return -EINVAL; - - ivtv_call_all(itv, tuner, g_tuner, vt); - - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_RADIO; - } else { - strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_ANALOG_TV; - } - - return 0; -} - -static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) -{ - struct ivtv *itv = fh2id(fh)->itv; - int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; - int f, l; - - if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - if (valid_service_line(f, l, itv->is_50hz)) - cap->service_lines[f][l] = set; - } - } - return 0; - } - if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { - if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) - return -EINVAL; - if (itv->is_60hz) { - cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } else { - cap->service_lines[0][23] = V4L2_SLICED_WSS_625; - cap->service_lines[0][16] = V4L2_SLICED_VPS; - } - return 0; - } - return -EINVAL; -} - -static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) -{ - struct ivtv *itv = fh2id(fh)->itv; - struct v4l2_enc_idx_entry *e = idx->entry; - int entries; - int i; - - entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % - IVTV_MAX_PGM_INDEX; - if (entries > V4L2_ENC_IDX_ENTRIES) - entries = V4L2_ENC_IDX_ENTRIES; - idx->entries = 0; - for (i = 0; i < entries; i++) { - *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; - if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) { - idx->entries++; - e++; - } - } - itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; - return 0; -} - -static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - - - switch (enc->cmd) { - case V4L2_ENC_CMD_START: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); - enc->flags = 0; - return ivtv_start_capture(id); - - case V4L2_ENC_CMD_STOP: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); - return 0; - - case V4L2_ENC_CMD_PAUSE: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); - enc->flags = 0; - - if (!atomic_read(&itv->capturing)) - return -EPERM; - if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - return 0; - - ivtv_mute(itv); - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); - break; - - case V4L2_ENC_CMD_RESUME: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); - enc->flags = 0; - - if (!atomic_read(&itv->capturing)) - return -EPERM; - - if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) - return 0; - - ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); - ivtv_unmute(itv); - break; - default: - IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); - return -EINVAL; - } - - return 0; -} - -static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) -{ - struct ivtv *itv = fh2id(fh)->itv; - - switch (enc->cmd) { - case V4L2_ENC_CMD_START: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); - enc->flags = 0; - return 0; - - case V4L2_ENC_CMD_STOP: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - return 0; - - case V4L2_ENC_CMD_PAUSE: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); - enc->flags = 0; - return 0; - - case V4L2_ENC_CMD_RESUME: - IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); - enc->flags = 0; - return 0; - default: - IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); - return -EINVAL; - } -} - -static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) -{ - struct ivtv *itv = fh2id(fh)->itv; - u32 data[CX2341X_MBOX_MAX_DATA]; - struct yuv_playback_info *yi = &itv->yuv_info; - - int pixfmt; - static u32 pixel_format[16] = { - V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ - V4L2_PIX_FMT_RGB565, - V4L2_PIX_FMT_RGB555, - V4L2_PIX_FMT_RGB444, - V4L2_PIX_FMT_RGB32, - 0, - 0, - 0, - V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ - V4L2_PIX_FMT_YUV565, - V4L2_PIX_FMT_YUV555, - V4L2_PIX_FMT_YUV444, - V4L2_PIX_FMT_YUV32, - 0, - 0, - 0, - }; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; - if (!itv->osd_video_pbase) - return -EINVAL; - - fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | - V4L2_FBUF_CAP_GLOBAL_ALPHA; - - ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); - data[0] |= (read_reg(0x2a00) >> 7) & 0x40; - pixfmt = (data[0] >> 3) & 0xf; - - fb->fmt.pixelformat = pixel_format[pixfmt]; - fb->fmt.width = itv->osd_rect.width; - fb->fmt.height = itv->osd_rect.height; - fb->fmt.field = V4L2_FIELD_INTERLACED; - fb->fmt.bytesperline = fb->fmt.width; - fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; - fb->fmt.field = V4L2_FIELD_INTERLACED; - fb->fmt.priv = 0; - if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8) - fb->fmt.bytesperline *= 2; - if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 || - fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32) - fb->fmt.bytesperline *= 2; - fb->fmt.sizeimage = fb->fmt.bytesperline * fb->fmt.height; - fb->base = (void *)itv->osd_video_pbase; - fb->flags = 0; - - if (itv->osd_chroma_key_state) - fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; - - if (itv->osd_global_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; - - if (yi->track_osd) - fb->flags |= V4L2_FBUF_FLAG_OVERLAY; - - pixfmt &= 7; - - /* no local alpha for RGB565 or unknown formats */ - if (pixfmt == 1 || pixfmt > 4) - return 0; - - /* 16-bit formats have inverted local alpha */ - if (pixfmt == 2 || pixfmt == 3) - fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; - else - fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; - - if (itv->osd_local_alpha_state) { - /* 16-bit formats have inverted local alpha */ - if (pixfmt == 2 || pixfmt == 3) - fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; - else - fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; - } - - return 0; -} - -static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; - if (!itv->osd_video_pbase) - return -EINVAL; - - itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; - itv->osd_local_alpha_state = - (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; - itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; - ivtv_set_osd_alpha(itv); - yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; - return ivtv_g_fbuf(file, fh, fb); -} - -static int ivtv_overlay(struct file *file, void *fh, unsigned int on) -{ - struct ivtv_open_id *id = fh2id(fh); - struct ivtv *itv = id->itv; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; - - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0); - - return 0; -} - -static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscription *sub) -{ - switch (sub->type) { - case V4L2_EVENT_VSYNC: - case V4L2_EVENT_EOS: - break; - default: - return -EINVAL; - } - return v4l2_event_subscribe(fh, sub); -} - -static int ivtv_log_status(struct file *file, void *fh) -{ - struct ivtv *itv = fh2id(fh)->itv; - u32 data[CX2341X_MBOX_MAX_DATA]; - - int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; - struct v4l2_input vidin; - struct v4l2_audio audin; - int i; - - IVTV_INFO("================= START STATUS CARD #%d =================\n", - itv->instance); - IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); - if (itv->hw_flags & IVTV_HW_TVEEPROM) { - struct tveeprom tv; - - ivtv_read_eeprom(itv, &tv); - } - ivtv_call_all(itv, core, log_status); - ivtv_get_input(itv, itv->active_input, &vidin); - ivtv_get_audio_input(itv, itv->audio_input, &audin); - IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s%s\n", audin.name, - (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); - if (has_output) { - struct v4l2_output vidout; - struct v4l2_audioout audout; - int mode = itv->output_mode; - static const char * const output_modes[5] = { - "None", - "MPEG Streaming", - "YUV Streaming", - "YUV Frames", - "Passthrough", - }; - static const char * const audio_modes[5] = { - "Stereo", - "Left", - "Right", - "Mono", - "Swapped" - }; - static const char * const alpha_mode[4] = { - "None", - "Global", - "Local", - "Global and Local" - }; - static const char * const pixel_format[16] = { - "ARGB Indexed", - "RGB 5:6:5", - "ARGB 1:5:5:5", - "ARGB 1:4:4:4", - "ARGB 8:8:8:8", - "5", - "6", - "7", - "AYUV Indexed", - "YUV 5:6:5", - "AYUV 1:5:5:5", - "AYUV 1:4:4:4", - "AYUV 8:8:8:8", - "13", - "14", - "15", - }; - - ivtv_get_output(itv, itv->active_output, &vidout); - ivtv_get_audio_output(itv, 0, &audout); - IVTV_INFO("Video Output: %s\n", vidout.name); - IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, - audio_modes[itv->audio_stereo_mode], - audio_modes[itv->audio_bilingual_mode]); - if (mode < 0 || mode > OUT_PASSTHROUGH) - mode = OUT_NONE; - IVTV_INFO("Output Mode: %s\n", output_modes[mode]); - ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); - data[0] |= (read_reg(0x2a00) >> 7) & 0x40; - IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", - data[0] & 1 ? "On" : "Off", - alpha_mode[(data[0] >> 1) & 0x3], - pixel_format[(data[0] >> 3) & 0xf]); - } - IVTV_INFO("Tuner: %s\n", - test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); - v4l2_ctrl_handler_log_status(&itv->cxhdl.hdl, itv->v4l2_dev.name); - IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); - for (i = 0; i < IVTV_MAX_STREAMS; i++) { - struct ivtv_stream *s = &itv->streams[i]; - - if (s->vdev == NULL || s->buffers == 0) - continue; - IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, - (s->buffers - s->q_free.buffers) * 100 / s->buffers, - (s->buffers * s->buf_size) / 1024, s->buffers); - } - - IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", - (long long)itv->mpg_data_received, - (long long)itv->vbi_data_inserted); - IVTV_INFO("================== END STATUS CARD #%d ==================\n", - itv->instance); - - return 0; -} - -static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) -{ - struct ivtv_open_id *id = fh2id(filp->private_data); - struct ivtv *itv = id->itv; - int nonblocking = filp->f_flags & O_NONBLOCK; - struct ivtv_stream *s = &itv->streams[id->type]; - unsigned long iarg = (unsigned long)arg; - - switch (cmd) { - case IVTV_IOC_DMA_FRAME: { - struct ivtv_dma_frame *args = arg; - - IVTV_DEBUG_IOCTL("IVTV_IOC_DMA_FRAME\n"); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - if (args->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL) - return 0; - if (ivtv_start_decoding(id, id->type)) { - return -EBUSY; - } - if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) { - ivtv_release_stream(s); - return -EBUSY; - } - /* Mark that this file handle started the UDMA_YUV mode */ - id->yuv_frames = 1; - if (args->y_source == NULL) - return 0; - return ivtv_yuv_prep_frame(itv, args); - } - - case VIDEO_GET_PTS: { - u32 data[CX2341X_MBOX_MAX_DATA]; - u64 *pts = arg; - - IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n"); - if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { - *pts = s->dma_pts; - break; - } - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - - if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { - *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) | - (u64)itv->last_dec_timing[1]; - break; - } - *pts = 0; - if (atomic_read(&itv->decoding)) { - if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { - IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); - return -EIO; - } - memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); - set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); - *pts = (u64) ((u64) data[2] << 32) | (u64) data[1]; - /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ - } - break; - } - - case VIDEO_GET_FRAME_COUNT: { - u32 data[CX2341X_MBOX_MAX_DATA]; - u64 *frame = arg; - - IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n"); - if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { - *frame = 0; - break; - } - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - - if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { - *frame = itv->last_dec_timing[0]; - break; - } - *frame = 0; - if (atomic_read(&itv->decoding)) { - if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { - IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); - return -EIO; - } - memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); - set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); - *frame = data[0]; - } - break; - } - - case VIDEO_PLAY: { - struct video_command vc; - - IVTV_DEBUG_IOCTL("VIDEO_PLAY\n"); - memset(&vc, 0, sizeof(vc)); - vc.cmd = VIDEO_CMD_PLAY; - return ivtv_video_command(itv, id, &vc, 0); - } - - case VIDEO_STOP: { - struct video_command vc; - - IVTV_DEBUG_IOCTL("VIDEO_STOP\n"); - memset(&vc, 0, sizeof(vc)); - vc.cmd = VIDEO_CMD_STOP; - vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY; - return ivtv_video_command(itv, id, &vc, 0); - } - - case VIDEO_FREEZE: { - struct video_command vc; - - IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n"); - memset(&vc, 0, sizeof(vc)); - vc.cmd = VIDEO_CMD_FREEZE; - return ivtv_video_command(itv, id, &vc, 0); - } - - case VIDEO_CONTINUE: { - struct video_command vc; - - IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n"); - memset(&vc, 0, sizeof(vc)); - vc.cmd = VIDEO_CMD_CONTINUE; - return ivtv_video_command(itv, id, &vc, 0); - } - - case VIDEO_COMMAND: - case VIDEO_TRY_COMMAND: { - struct video_command *vc = arg; - int try = (cmd == VIDEO_TRY_COMMAND); - - if (try) - IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd); - else - IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd); - return ivtv_video_command(itv, id, vc, try); - } - - case VIDEO_GET_EVENT: { - struct video_event *ev = arg; - DEFINE_WAIT(wait); - - IVTV_DEBUG_IOCTL("VIDEO_GET_EVENT\n"); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - memset(ev, 0, sizeof(*ev)); - set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); - - while (1) { - if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) - ev->type = VIDEO_EVENT_DECODER_STOPPED; - else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) { - ev->type = VIDEO_EVENT_VSYNC; - ev->u.vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ? - VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN; - if (itv->output_mode == OUT_UDMA_YUV && - (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) == - IVTV_YUV_MODE_PROGRESSIVE) { - ev->u.vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE; - } - } - if (ev->type) - return 0; - if (nonblocking) - return -EAGAIN; - /* Wait for event. Note that serialize_lock is locked, - so to allow other processes to access the driver while - we are waiting unlock first and later lock again. */ - mutex_unlock(&itv->serialize_lock); - prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); - if (!test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags) && - !test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) - schedule(); - finish_wait(&itv->event_waitq, &wait); - mutex_lock(&itv->serialize_lock); - if (signal_pending(current)) { - /* return if a signal was received */ - IVTV_DEBUG_INFO("User stopped wait for event\n"); - return -EINTR; - } - } - break; - } - - case VIDEO_SELECT_SOURCE: - IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n"); - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - return ivtv_passthrough_mode(itv, iarg == VIDEO_SOURCE_DEMUX); - - case AUDIO_SET_MUTE: - IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n"); - itv->speed_mute_audio = iarg; - return 0; - - case AUDIO_CHANNEL_SELECT: - IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); - if (iarg > AUDIO_STEREO_SWAPPED) - return -EINVAL; - itv->audio_stereo_mode = iarg; - ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); - return 0; - - case AUDIO_BILINGUAL_CHANNEL_SELECT: - IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); - if (iarg > AUDIO_STEREO_SWAPPED) - return -EINVAL; - itv->audio_bilingual_mode = iarg; - ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); - return 0; - - default: - return -EINVAL; - } - return 0; -} - -static long ivtv_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) -{ - struct ivtv *itv = fh2id(fh)->itv; - - if (!valid_prio) { - switch (cmd) { - case VIDEO_PLAY: - case VIDEO_STOP: - case VIDEO_FREEZE: - case VIDEO_CONTINUE: - case VIDEO_COMMAND: - case VIDEO_SELECT_SOURCE: - case AUDIO_SET_MUTE: - case AUDIO_CHANNEL_SELECT: - case AUDIO_BILINGUAL_CHANNEL_SELECT: - return -EBUSY; - } - } - - switch (cmd) { - case VIDIOC_INT_RESET: { - u32 val = *(u32 *)arg; - - if ((val == 0 && itv->options.newi2c) || (val & 0x01)) - ivtv_reset_ir_gpio(itv); - if (val & 0x02) - v4l2_subdev_call(itv->sd_video, core, reset, 0); - break; - } - - case IVTV_IOC_DMA_FRAME: - case VIDEO_GET_PTS: - case VIDEO_GET_FRAME_COUNT: - case VIDEO_GET_EVENT: - case VIDEO_PLAY: - case VIDEO_STOP: - case VIDEO_FREEZE: - case VIDEO_CONTINUE: - case VIDEO_COMMAND: - case VIDEO_TRY_COMMAND: - case VIDEO_SELECT_SOURCE: - case AUDIO_SET_MUTE: - case AUDIO_CHANNEL_SELECT: - case AUDIO_BILINGUAL_CHANNEL_SELECT: - return ivtv_decoder_ioctls(file, cmd, (void *)arg); - - default: - return -EINVAL; - } - return 0; -} - -static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct video_device *vfd = video_devdata(filp); - long ret; - - if (ivtv_debug & IVTV_DBGFLG_IOCTL) - vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; - ret = video_ioctl2(filp, cmd, arg); - vfd->debug = 0; - return ret; -} - -long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct ivtv_open_id *id = fh2id(filp->private_data); - struct ivtv *itv = id->itv; - long res; - - /* DQEVENT can block, so this should not run with the serialize lock */ - if (cmd == VIDIOC_DQEVENT) - return ivtv_serialized_ioctl(itv, filp, cmd, arg); - mutex_lock(&itv->serialize_lock); - res = ivtv_serialized_ioctl(itv, filp, cmd, arg); - mutex_unlock(&itv->serialize_lock); - return res; -} - -static const struct v4l2_ioctl_ops ivtv_ioctl_ops = { - .vidioc_querycap = ivtv_querycap, - .vidioc_s_audio = ivtv_s_audio, - .vidioc_g_audio = ivtv_g_audio, - .vidioc_enumaudio = ivtv_enumaudio, - .vidioc_s_audout = ivtv_s_audout, - .vidioc_g_audout = ivtv_g_audout, - .vidioc_enum_input = ivtv_enum_input, - .vidioc_enum_output = ivtv_enum_output, - .vidioc_enumaudout = ivtv_enumaudout, - .vidioc_cropcap = ivtv_cropcap, - .vidioc_s_crop = ivtv_s_crop, - .vidioc_g_crop = ivtv_g_crop, - .vidioc_g_input = ivtv_g_input, - .vidioc_s_input = ivtv_s_input, - .vidioc_g_output = ivtv_g_output, - .vidioc_s_output = ivtv_s_output, - .vidioc_g_frequency = ivtv_g_frequency, - .vidioc_s_frequency = ivtv_s_frequency, - .vidioc_s_tuner = ivtv_s_tuner, - .vidioc_g_tuner = ivtv_g_tuner, - .vidioc_g_enc_index = ivtv_g_enc_index, - .vidioc_g_fbuf = ivtv_g_fbuf, - .vidioc_s_fbuf = ivtv_s_fbuf, - .vidioc_g_std = ivtv_g_std, - .vidioc_s_std = ivtv_s_std, - .vidioc_overlay = ivtv_overlay, - .vidioc_log_status = ivtv_log_status, - .vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap, - .vidioc_encoder_cmd = ivtv_encoder_cmd, - .vidioc_try_encoder_cmd = ivtv_try_encoder_cmd, - .vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out, - .vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap, - .vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap, - .vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out, - .vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay, - .vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out, - .vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap, - .vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap, - .vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap, - .vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out, - .vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay, - .vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out, - .vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap, - .vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap, - .vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap, - .vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out, - .vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay, - .vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out, - .vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap, - .vidioc_g_chip_ident = ivtv_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = ivtv_g_register, - .vidioc_s_register = ivtv_s_register, -#endif - .vidioc_default = ivtv_default, - .vidioc_subscribe_event = ivtv_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -void ivtv_set_funcs(struct video_device *vdev) -{ - vdev->ioctl_ops = &ivtv_ioctl_ops; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-ioctl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-ioctl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-ioctl.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-ioctl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - ioctl system call - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_IOCTL_H -#define IVTV_IOCTL_H - -u16 ivtv_service2vbi(int type); -void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); -u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt); -void ivtv_set_osd_alpha(struct ivtv *itv); -int ivtv_set_speed(struct ivtv *itv, int speed); -void ivtv_set_funcs(struct video_device *vdev); -int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std); -int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); -int ivtv_s_input(struct file *file, void *fh, unsigned int inp); -long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-irq.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-irq.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-irq.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-irq.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1038 +0,0 @@ -/* interrupt handling - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-queue.h" -#include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-mailbox.h" -#include "ivtv-vbi.h" -#include "ivtv-yuv.h" -#include - -#define DMA_MAGIC_COOKIE 0x000001fe - -static void ivtv_dma_dec_start(struct ivtv_stream *s); - -static const int ivtv_stream_map[] = { - IVTV_ENC_STREAM_TYPE_MPG, - IVTV_ENC_STREAM_TYPE_YUV, - IVTV_ENC_STREAM_TYPE_PCM, - IVTV_ENC_STREAM_TYPE_VBI, -}; - - -static void ivtv_pio_work_handler(struct ivtv *itv) -{ - struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream]; - struct ivtv_buffer *buf; - int i = 0; - - IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n"); - if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS || - s->vdev == NULL || !ivtv_use_pio(s)) { - itv->cur_pio_stream = -1; - /* trigger PIO complete user interrupt */ - write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); - return; - } - IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name); - list_for_each_entry(buf, &s->q_dma.list, list) { - u32 size = s->sg_processing[i].size & 0x3ffff; - - /* Copy the data from the card to the buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { - memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size); - } - else { - memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size); - } - i++; - if (i == s->sg_processing_size) - break; - } - write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); -} - -void ivtv_irq_work_handler(struct kthread_work *work) -{ - struct ivtv *itv = container_of(work, struct ivtv, irq_work); - - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) - ivtv_pio_work_handler(itv); - - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags)) - ivtv_vbi_work_handler(itv); - - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags)) - ivtv_yuv_work_handler(itv); -} - -/* Determine the required DMA size, setup enough buffers in the predma queue and - actually copy the data from the card to the buffers in case a PIO transfer is - required for this stream. - */ -static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA]) -{ - struct ivtv *itv = s->itv; - struct ivtv_buffer *buf; - u32 bytes_needed = 0; - u32 offset, size; - u32 UVoffset = 0, UVsize = 0; - int skip_bufs = s->q_predma.buffers; - int idx = s->sg_pending_size; - int rc; - - /* sanity checks */ - if (s->vdev == NULL) { - IVTV_DEBUG_WARN("Stream %s not started\n", s->name); - return -1; - } - if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { - IVTV_DEBUG_WARN("Stream %s not open\n", s->name); - return -1; - } - - /* determine offset, size and PTS for the various streams */ - switch (s->type) { - case IVTV_ENC_STREAM_TYPE_MPG: - offset = data[1]; - size = data[2]; - s->pending_pts = 0; - break; - - case IVTV_ENC_STREAM_TYPE_YUV: - offset = data[1]; - size = data[2]; - UVoffset = data[3]; - UVsize = data[4]; - s->pending_pts = ((u64) data[5] << 32) | data[6]; - break; - - case IVTV_ENC_STREAM_TYPE_PCM: - offset = data[1] + 12; - size = data[2] - 12; - s->pending_pts = read_dec(offset - 8) | - ((u64)(read_dec(offset - 12)) << 32); - if (itv->has_cx23415) - offset += IVTV_DECODER_OFFSET; - break; - - case IVTV_ENC_STREAM_TYPE_VBI: - size = itv->vbi.enc_size * itv->vbi.fpi; - offset = read_enc(itv->vbi.enc_start - 4) + 12; - if (offset == 12) { - IVTV_DEBUG_INFO("VBI offset == 0\n"); - return -1; - } - s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); - break; - - case IVTV_DEC_STREAM_TYPE_VBI: - size = read_dec(itv->vbi.dec_start + 4) + 8; - offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; - s->pending_pts = 0; - offset += IVTV_DECODER_OFFSET; - break; - default: - /* shouldn't happen */ - return -1; - } - - /* if this is the start of the DMA then fill in the magic cookie */ - if (s->sg_pending_size == 0 && ivtv_use_dma(s)) { - if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || - s->type == IVTV_DEC_STREAM_TYPE_VBI)) { - s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); - write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); - } - else { - s->pending_backup = read_enc(offset); - write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); - } - s->pending_offset = offset; - } - - bytes_needed = size; - if (s->type == IVTV_ENC_STREAM_TYPE_YUV) { - /* The size for the Y samples needs to be rounded upwards to a - multiple of the buf_size. The UV samples then start in the - next buffer. */ - bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size); - bytes_needed += UVsize; - } - - IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n", - ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset); - - rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed); - if (rc < 0) { /* Insufficient buffers */ - IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n", - bytes_needed, s->name); - return -1; - } - if (rc && !s->buffers_stolen && test_bit(IVTV_F_S_APPL_IO, &s->s_flags)) { - IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name); - IVTV_WARN("Cause: the application is not reading fast enough.\n"); - } - s->buffers_stolen = rc; - - /* got the buffers, now fill in sg_pending */ - buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); - memset(buf->buf, 0, 128); - list_for_each_entry(buf, &s->q_predma.list, list) { - if (skip_bufs-- > 0) - continue; - s->sg_pending[idx].dst = buf->dma_handle; - s->sg_pending[idx].src = offset; - s->sg_pending[idx].size = s->buf_size; - buf->bytesused = min(size, s->buf_size); - buf->dma_xfer_cnt = s->dma_xfer_cnt; - - s->q_predma.bytesused += buf->bytesused; - size -= buf->bytesused; - offset += s->buf_size; - - /* Sync SG buffers */ - ivtv_buf_sync_for_device(s, buf); - - if (size == 0) { /* YUV */ - /* process the UV section */ - offset = UVoffset; - size = UVsize; - } - idx++; - } - s->sg_pending_size = idx; - return 0; -} - -static void dma_post(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - struct ivtv_buffer *buf = NULL; - struct list_head *p; - u32 offset; - __le32 *u32buf; - int x = 0; - - IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA", - s->name, s->dma_offset); - list_for_each(p, &s->q_dma.list) { - buf = list_entry(p, struct ivtv_buffer, list); - u32buf = (__le32 *)buf->buf; - - /* Sync Buffer */ - ivtv_buf_sync_for_cpu(s, buf); - - if (x == 0 && ivtv_use_dma(s)) { - offset = s->dma_last_offset; - if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) - { - for (offset = 0; offset < 64; offset++) { - if (u32buf[offset] == DMA_MAGIC_COOKIE) { - break; - } - } - offset *= 4; - if (offset == 256) { - IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name); - offset = s->dma_last_offset; - } - if (s->dma_last_offset != offset) - IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset); - s->dma_last_offset = offset; - } - if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || - s->type == IVTV_DEC_STREAM_TYPE_VBI)) { - write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET); - } - else { - write_enc_sync(0, s->dma_offset); - } - if (offset) { - buf->bytesused -= offset; - memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset); - } - *u32buf = cpu_to_le32(s->dma_backup); - } - x++; - /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ - if (s->type == IVTV_ENC_STREAM_TYPE_MPG || - s->type == IVTV_ENC_STREAM_TYPE_VBI) - buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP; - } - if (buf) - buf->bytesused += s->dma_last_offset; - if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { - list_for_each_entry(buf, &s->q_dma.list, list) { - /* Parse and Groom VBI Data */ - s->q_dma.bytesused -= buf->bytesused; - ivtv_process_vbi_data(itv, buf, 0, s->type); - s->q_dma.bytesused += buf->bytesused; - } - if (s->id == -1) { - ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); - return; - } - } - ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused); - if (s->id != -1) - wake_up(&s->waitq); -} - -void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) -{ - struct ivtv *itv = s->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - u8 frame = yi->draw_frame; - struct yuv_frame_info *f = &yi->new_frame_info[frame]; - struct ivtv_buffer *buf; - u32 y_size = 720 * ((f->src_h + 31) & ~31); - u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; - int y_done = 0; - int bytes_written = 0; - unsigned long flags = 0; - int idx = 0; - - IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); - - /* Insert buffer block for YUV if needed */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) { - if (yi->blanking_dmaptr) { - s->sg_pending[idx].src = yi->blanking_dmaptr; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = 720 * 16; - } - offset += 720 * 16; - idx++; - } - - list_for_each_entry(buf, &s->q_predma.list, list) { - /* YUV UV Offset from Y Buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && - (bytes_written + buf->bytesused) >= y_size) { - s->sg_pending[idx].src = buf->dma_handle; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = y_size - bytes_written; - offset = uv_offset; - if (s->sg_pending[idx].size != buf->bytesused) { - idx++; - s->sg_pending[idx].src = - buf->dma_handle + s->sg_pending[idx - 1].size; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = - buf->bytesused - s->sg_pending[idx - 1].size; - offset += s->sg_pending[idx].size; - } - y_done = 1; - } else { - s->sg_pending[idx].src = buf->dma_handle; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = buf->bytesused; - offset += buf->bytesused; - } - bytes_written += buf->bytesused; - - /* Sync SG buffers */ - ivtv_buf_sync_for_device(s, buf); - idx++; - } - s->sg_pending_size = idx; - - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - if (lock) - spin_lock_irqsave(&itv->dma_reg_lock, flags); - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) { - ivtv_dma_dec_start(s); - } - else { - set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); - } - if (lock) - spin_unlock_irqrestore(&itv->dma_reg_lock, flags); -} - -static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - - s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); - s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); - s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); - s->sg_processed++; - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); - add_timer(&itv->dma_timer); -} - -static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - - s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); - s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); - s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); - s->sg_processed++; - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); - add_timer(&itv->dma_timer); -} - -/* start the encoder DMA */ -static void ivtv_dma_enc_start(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - int i; - - IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name); - - if (s->q_predma.bytesused) - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); - - if (ivtv_use_dma(s)) - s->sg_pending[s->sg_pending_size - 1].size += 256; - - /* If this is an MPEG stream, and VBI data is also pending, then append the - VBI DMA to the MPEG DMA and transfer both sets of data at once. - - VBI DMA is a second class citizen compared to MPEG and mixing them together - will confuse the firmware (the end of a VBI DMA is seen as the end of a - MPEG DMA, thus effectively dropping an MPEG frame). So instead we make - sure we only use the MPEG DMA to transfer the VBI DMA if both are in - use. This way no conflicts occur. */ - clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size && - s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) { - ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); - if (ivtv_use_dma(s_vbi)) - s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256; - for (i = 0; i < s_vbi->sg_pending_size; i++) { - s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i]; - } - s_vbi->dma_offset = s_vbi->pending_offset; - s_vbi->sg_pending_size = 0; - s_vbi->dma_xfer_cnt++; - set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name); - } - - s->dma_xfer_cnt++; - memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size); - s->sg_processing_size = s->sg_pending_size; - s->sg_pending_size = 0; - s->sg_processed = 0; - s->dma_offset = s->pending_offset; - s->dma_backup = s->pending_backup; - s->dma_pts = s->pending_pts; - - if (ivtv_use_pio(s)) { - set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags); - set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); - set_bit(IVTV_F_I_PIO, &itv->i_flags); - itv->cur_pio_stream = s->type; - } - else { - itv->dma_retries = 0; - ivtv_dma_enc_start_xfer(s); - set_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = s->type; - } -} - -static void ivtv_dma_dec_start(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - - if (s->q_predma.bytesused) - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); - s->dma_xfer_cnt++; - memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size); - s->sg_processing_size = s->sg_pending_size; - s->sg_pending_size = 0; - s->sg_processed = 0; - - IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name); - itv->dma_retries = 0; - ivtv_dma_dec_start_xfer(s); - set_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = s->type; -} - -static void ivtv_irq_dma_read(struct ivtv *itv) -{ - struct ivtv_stream *s = NULL; - struct ivtv_buffer *buf; - int hw_stream_type = 0; - - IVTV_DEBUG_HI_IRQ("DEC DMA READ\n"); - - del_timer(&itv->dma_timer); - - if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) - return; - - if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - s = &itv->streams[itv->cur_dma_stream]; - ivtv_stream_sync_for_cpu(s); - - if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { - IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n", - read_reg(IVTV_REG_DMASTATUS), - s->sg_processed, s->sg_processing_size, itv->dma_retries); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - if (itv->dma_retries == 3) { - /* Too many retries, give up on this frame */ - itv->dma_retries = 0; - s->sg_processed = s->sg_processing_size; - } - else { - /* Retry, starting with the first xfer segment. - Just retrying the current segment is not sufficient. */ - s->sg_processed = 0; - itv->dma_retries++; - } - } - if (s->sg_processed < s->sg_processing_size) { - /* DMA next buffer */ - ivtv_dma_dec_start_xfer(s); - return; - } - if (s->type == IVTV_DEC_STREAM_TYPE_YUV) - hw_stream_type = 2; - IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); - - /* For some reason must kick the firmware, like PIO mode, - I think this tells the firmware we are done and the size - of the xfer so it can calculate what we need next. - I think we can do this part ourselves but would have to - fully calculate xfer info ourselves and not use interrupts - */ - ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused, - hw_stream_type); - - /* Free last DMA call */ - while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) { - ivtv_buf_sync_for_cpu(s, buf); - ivtv_enqueue(s, buf, &s->q_free); - } - wake_up(&s->waitq); - } - clear_bit(IVTV_F_I_UDMA, &itv->i_flags); - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_enc_dma_complete(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data); - IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream); - - del_timer(&itv->dma_timer); - - if (itv->cur_dma_stream < 0) - return; - - s = &itv->streams[itv->cur_dma_stream]; - ivtv_stream_sync_for_cpu(s); - - if (data[0] & 0x18) { - IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0], - s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - if (itv->dma_retries == 3) { - /* Too many retries, give up on this frame */ - itv->dma_retries = 0; - s->sg_processed = s->sg_processing_size; - } - else { - /* Retry, starting with the first xfer segment. - Just retrying the current segment is not sufficient. */ - s->sg_processed = 0; - itv->dma_retries++; - } - } - if (s->sg_processed < s->sg_processing_size) { - /* DMA next buffer */ - ivtv_dma_enc_start_xfer(s); - return; - } - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - dma_post(s); - if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - dma_post(s); - } - s->sg_processing_size = 0; - s->sg_processed = 0; - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_enc_pio_complete(struct ivtv *itv) -{ - struct ivtv_stream *s; - - if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS) { - itv->cur_pio_stream = -1; - return; - } - s = &itv->streams[itv->cur_pio_stream]; - IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - clear_bit(IVTV_F_I_PIO, &itv->i_flags); - itv->cur_pio_stream = -1; - dma_post(s); - if (s->type == IVTV_ENC_STREAM_TYPE_MPG) - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 0); - else if (s->type == IVTV_ENC_STREAM_TYPE_YUV) - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 1); - else if (s->type == IVTV_ENC_STREAM_TYPE_PCM) - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2); - clear_bit(IVTV_F_I_PIO, &itv->i_flags); - if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - dma_post(s); - } - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_dma_err(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - u32 status; - - del_timer(&itv->dma_timer); - - ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data); - status = read_reg(IVTV_REG_DMASTATUS); - IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], - status, itv->cur_dma_stream); - /* - * We do *not* write back to the IVTV_REG_DMASTATUS register to - * clear the error status, if either the encoder write (0x02) or - * decoder read (0x01) bus master DMA operation do not indicate - * completed. We can race with the DMA engine, which may have - * transitioned to completed status *after* we read the register. - * Setting a IVTV_REG_DMASTATUS flag back to "busy" status, after the - * DMA engine has completed, will cause the DMA engine to stop working. - */ - status &= 0x3; - if (status == 0x3) - write_reg(status, IVTV_REG_DMASTATUS); - - if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && - itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { - struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; - - if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { - /* retry */ - /* - * FIXME - handle cases of DMA error similar to - * encoder below, except conditioned on status & 0x1 - */ - ivtv_dma_dec_start(s); - return; - } else { - if ((status & 0x2) == 0) { - /* - * CX2341x Bus Master DMA write is ongoing. - * Reset the timer and let it complete. - */ - itv->dma_timer.expires = - jiffies + msecs_to_jiffies(600); - add_timer(&itv->dma_timer); - return; - } - - if (itv->dma_retries < 3) { - /* - * CX2341x Bus Master DMA write has ended. - * Retry the write, starting with the first - * xfer segment. Just retrying the current - * segment is not sufficient. - */ - s->sg_processed = 0; - itv->dma_retries++; - ivtv_dma_enc_start_xfer(s); - return; - } - /* Too many retries, give up on this one */ - } - - } - if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - ivtv_udma_start(itv); - return; - } - clear_bit(IVTV_F_I_UDMA, &itv->i_flags); - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_enc_start_cap(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - /* Get DMA destination and size arguments from card */ - ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, 7, data); - IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]); - - if (data[0] > 2 || data[1] == 0 || data[2] == 0) { - IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n", - data[0], data[1], data[2]); - return; - } - s = &itv->streams[ivtv_stream_map[data[0]]]; - if (!stream_enc_dma_append(s, data)) { - set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); - } -} - -static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n"); - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - - if (!stream_enc_dma_append(s, data)) - set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); -} - -static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; - - IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n"); - if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) && - !stream_enc_dma_append(s, data)) { - set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags); - } -} - -static void ivtv_irq_dec_data_req(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - /* YUV or MPG */ - - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data); - itv->dma_data_req_size = - 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); - itv->dma_data_req_offset = data[1]; - if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0) - ivtv_yuv_frame_complete(itv); - s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - } - else { - ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 3, data); - itv->dma_data_req_size = min_t(u32, data[2], 0x10000); - itv->dma_data_req_offset = data[1]; - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - } - IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused, - itv->dma_data_req_offset, itv->dma_data_req_size); - if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) { - set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - } - else { - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - ivtv_yuv_setup_stream_frame(itv); - clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); - ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); - } -} - -static void ivtv_irq_vsync(struct ivtv *itv) -{ - /* The vsync interrupt is unusual in that it won't clear until - * the end of the first line for the current field, at which - * point it clears itself. This can result in repeated vsync - * interrupts, or a missed vsync. Read some of the registers - * to determine the line being displayed and ensure we handle - * one vsync per frame. - */ - unsigned int frame = read_reg(IVTV_REG_DEC_LINE_FIELD) & 1; - struct yuv_playback_info *yi = &itv->yuv_info; - int last_dma_frame = atomic_read(&yi->next_dma_frame); - struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame]; - - if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - - if (((frame ^ f->sync_field) == 0 && - ((itv->last_vsync_field & 1) ^ f->sync_field)) || - (frame != (itv->last_vsync_field & 1) && !f->interlaced)) { - int next_dma_frame = last_dma_frame; - - if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) { - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) { - write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS; - atomic_set(&yi->next_dma_frame, next_dma_frame); - yi->fields_lapsed = -1; - yi->running = 1; - } - } - } - if (frame != (itv->last_vsync_field & 1)) { - static const struct v4l2_event evtop = { - .type = V4L2_EVENT_VSYNC, - .u.vsync.field = V4L2_FIELD_TOP, - }; - static const struct v4l2_event evbottom = { - .type = V4L2_EVENT_VSYNC, - .u.vsync.field = V4L2_FIELD_BOTTOM, - }; - struct ivtv_stream *s = ivtv_get_output_stream(itv); - - itv->last_vsync_field += 1; - if (frame == 0) { - clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); - clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); - } - else { - set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); - } - if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) { - set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags); - wake_up(&itv->event_waitq); - if (s) - wake_up(&s->waitq); - } - if (s && s->vdev) - v4l2_event_queue(s->vdev, frame ? &evtop : &evbottom); - wake_up(&itv->vsync_waitq); - - /* Send VBI to saa7127 */ - if (frame && (itv->output_mode == OUT_PASSTHROUGH || - test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) || - test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) || - test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) { - set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); - set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); - } - - /* Check if we need to update the yuv registers */ - if (yi->running && (yi->yuv_forced_update || f->update)) { - if (!f->update) { - last_dma_frame = - (u8)(atomic_read(&yi->next_dma_frame) - - 1) % IVTV_YUV_BUFFERS; - f = &yi->new_frame_info[last_dma_frame]; - } - - if (f->src_w) { - yi->update_frame = last_dma_frame; - f->update = 0; - yi->yuv_forced_update = 0; - set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); - set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); - } - } - - yi->fields_lapsed++; - } -} - -#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT) - -irqreturn_t ivtv_irq_handler(int irq, void *dev_id) -{ - struct ivtv *itv = (struct ivtv *)dev_id; - u32 combo; - u32 stat; - int i; - u8 vsync_force = 0; - - spin_lock(&itv->dma_reg_lock); - /* get contents of irq status register */ - stat = read_reg(IVTV_REG_IRQSTATUS); - - combo = ~itv->irqmask & stat; - - /* Clear out IRQ */ - if (combo) write_reg(combo, IVTV_REG_IRQSTATUS); - - if (0 == combo) { - /* The vsync interrupt is unusual and clears itself. If we - * took too long, we may have missed it. Do some checks - */ - if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { - /* vsync is enabled, see if we're in a new field */ - if ((itv->last_vsync_field & 1) != - (read_reg(IVTV_REG_DEC_LINE_FIELD) & 1)) { - /* New field, looks like we missed it */ - IVTV_DEBUG_YUV("VSync interrupt missed %d\n", - read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16); - vsync_force = 1; - } - } - - if (!vsync_force) { - /* No Vsync expected, wasn't for us */ - spin_unlock(&itv->dma_reg_lock); - return IRQ_NONE; - } - } - - /* Exclude interrupts noted below from the output, otherwise the log is flooded with - these messages */ - if (combo & ~0xff6d0400) - IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo); - - if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) { - IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n"); - } - - if (combo & IVTV_IRQ_DMA_READ) { - ivtv_irq_dma_read(itv); - } - - if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) { - ivtv_irq_enc_dma_complete(itv); - } - - if (combo & IVTV_IRQ_ENC_PIO_COMPLETE) { - ivtv_irq_enc_pio_complete(itv); - } - - if (combo & IVTV_IRQ_DMA_ERR) { - ivtv_irq_dma_err(itv); - } - - if (combo & IVTV_IRQ_ENC_START_CAP) { - ivtv_irq_enc_start_cap(itv); - } - - if (combo & IVTV_IRQ_ENC_VBI_CAP) { - ivtv_irq_enc_vbi_cap(itv); - } - - if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) { - ivtv_irq_dec_vbi_reinsert(itv); - } - - if (combo & IVTV_IRQ_ENC_EOS) { - IVTV_DEBUG_IRQ("ENC EOS\n"); - set_bit(IVTV_F_I_EOS, &itv->i_flags); - wake_up(&itv->eos_waitq); - } - - if (combo & IVTV_IRQ_DEC_DATA_REQ) { - ivtv_irq_dec_data_req(itv); - } - - /* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */ - if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { - ivtv_irq_vsync(itv); - } - - if (combo & IVTV_IRQ_ENC_VIM_RST) { - IVTV_DEBUG_IRQ("VIM RST\n"); - /*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */ - } - - if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) { - IVTV_DEBUG_INFO("Stereo mode changed\n"); - } - - if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { - itv->irq_rr_idx++; - for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; - struct ivtv_stream *s = &itv->streams[idx]; - - if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) - continue; - if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) - ivtv_dma_dec_start(s); - else - ivtv_dma_enc_start(s); - break; - } - - if (i == IVTV_MAX_STREAMS && - test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) - ivtv_udma_start(itv); - } - - if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) { - itv->irq_rr_idx++; - for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; - struct ivtv_stream *s = &itv->streams[idx]; - - if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags)) - continue; - if (s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type < IVTV_DEC_STREAM_TYPE_MPG) - ivtv_dma_enc_start(s); - break; - } - } - - if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { - queue_kthread_work(&itv->irq_worker, &itv->irq_work); - } - - spin_unlock(&itv->dma_reg_lock); - - /* If we've just handled a 'forced' vsync, it's safest to say it - * wasn't ours. Another device may have triggered it at just - * the right time. - */ - return vsync_force ? IRQ_NONE : IRQ_HANDLED; -} - -void ivtv_unfinished_dma(unsigned long arg) -{ - struct ivtv *itv = (struct ivtv *)arg; - - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) - return; - IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); - - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - clear_bit(IVTV_F_I_UDMA, &itv->i_flags); - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - wake_up(&itv->dma_waitq); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-irq.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-irq.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-irq.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-irq.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/* - interrupt handling - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_IRQ_H -#define IVTV_IRQ_H - -#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) -#define IVTV_IRQ_ENC_EOS (0x1 << 30) -#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) -#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) -#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) -#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) -#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) -#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) -#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) -#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) -#define IVTV_IRQ_DMA_ERR (0x1 << 18) -#define IVTV_IRQ_DMA_WRITE (0x1 << 17) -#define IVTV_IRQ_DMA_READ (0x1 << 16) -#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) - -/* IRQ Masks */ -#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ - IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE) - -#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) -#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) - -irqreturn_t ivtv_irq_handler(int irq, void *dev_id); - -void ivtv_irq_work_handler(struct kthread_work *work); -void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); -void ivtv_unfinished_dma(unsigned long arg); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-mailbox.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-mailbox.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-mailbox.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-mailbox.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,387 +0,0 @@ -/* - mailbox functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - -#include "ivtv-driver.h" -#include "ivtv-mailbox.h" - -/* Firmware mailbox flags*/ -#define IVTV_MBOX_FIRMWARE_DONE 0x00000004 -#define IVTV_MBOX_DRIVER_DONE 0x00000002 -#define IVTV_MBOX_DRIVER_BUSY 0x00000001 -#define IVTV_MBOX_FREE 0x00000000 - -/* Firmware mailbox standard timeout */ -#define IVTV_API_STD_TIMEOUT 0x02000000 - -#define API_CACHE (1 << 0) /* Allow the command to be stored in the cache */ -#define API_RESULT (1 << 1) /* Allow 1 second for this cmd to end */ -#define API_FAST_RESULT (3 << 1) /* Allow 0.1 second for this cmd to end */ -#define API_DMA (1 << 3) /* DMA mailbox, has special handling */ -#define API_HIGH_VOL (1 << 5) /* High volume command (i.e. called during encoding or decoding) */ -#define API_NO_WAIT_MB (1 << 4) /* Command may not wait for a free mailbox */ -#define API_NO_WAIT_RES (1 << 5) /* Command may not wait for the result */ -#define API_NO_POLL (1 << 6) /* Avoid pointless polling */ - -struct ivtv_api_info { - int flags; /* Flags, see above */ - const char *name; /* The name of the command */ -}; - -#define API_ENTRY(x, f) [x] = { (f), #x } - -static const struct ivtv_api_info api_info[256] = { - /* MPEG encoder API */ - API_ENTRY(CX2341X_ENC_PING_FW, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_START_CAPTURE, API_RESULT | API_NO_POLL), - API_ENTRY(CX2341X_ENC_STOP_CAPTURE, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_PCR_ID, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_FRAME_RATE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_FRAME_SIZE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_BIT_RATE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_GOP_PROPERTIES, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_ASPECT_RATIO, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_MODE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_PROPS, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_CORING_LEVELS, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_VBI_LINE, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_STREAM_TYPE, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_OUTPUT_PORT, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_AUDIO_PROPERTIES, API_CACHE), - API_ENTRY(CX2341X_ENC_HALT_FW, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_GET_VERSION, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_SET_GOP_CLOSURE, API_CACHE), - API_ENTRY(CX2341X_ENC_GET_SEQ_END, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_PGM_INDEX_INFO, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_SET_VBI_CONFIG, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, API_CACHE), - API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA | API_HIGH_VOL), - API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, API_CACHE), - API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, API_RESULT), - API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB | API_HIGH_VOL), - API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, API_CACHE), - API_ENTRY(CX2341X_ENC_SET_PLACEHOLDER, API_CACHE), - API_ENTRY(CX2341X_ENC_MUTE_VIDEO, API_RESULT), - API_ENTRY(CX2341X_ENC_MUTE_AUDIO, API_RESULT), - API_ENTRY(CX2341X_ENC_SET_VERT_CROP_LINE, API_FAST_RESULT), - API_ENTRY(CX2341X_ENC_MISC, API_FAST_RESULT), - /* Obsolete PULLDOWN API command */ - API_ENTRY(0xb1, API_CACHE), - - /* MPEG decoder API */ - API_ENTRY(CX2341X_DEC_PING_FW, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_START_PLAYBACK, API_RESULT | API_NO_POLL), - API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, API_RESULT), - API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, API_RESULT), - API_ENTRY(CX2341X_DEC_STEP_VIDEO, API_RESULT), - API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, API_CACHE), - API_ENTRY(CX2341X_DEC_GET_XFER_INFO, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA | API_HIGH_VOL), - API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, API_RESULT), - API_ENTRY(CX2341X_DEC_HALT_FW, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_SET_STANDARD, API_CACHE), - API_ENTRY(CX2341X_DEC_GET_VERSION, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_SET_STREAM_INPUT, API_CACHE), - API_ENTRY(CX2341X_DEC_GET_TIMING_INFO, API_RESULT /*| API_NO_WAIT_RES*/), - API_ENTRY(CX2341X_DEC_SET_AUDIO_MODE, API_CACHE), - API_ENTRY(CX2341X_DEC_SET_EVENT_NOTIFICATION, API_RESULT), - API_ENTRY(CX2341X_DEC_SET_DISPLAY_BUFFERS, API_CACHE), - API_ENTRY(CX2341X_DEC_EXTRACT_VBI, API_RESULT), - API_ENTRY(CX2341X_DEC_SET_DECODER_SOURCE, API_FAST_RESULT), - API_ENTRY(CX2341X_DEC_SET_PREBUFFERING, API_CACHE), - - /* OSD API */ - API_ENTRY(CX2341X_OSD_GET_FRAMEBUFFER, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_GET_PIXEL_FORMAT, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_PIXEL_FORMAT, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_STATE, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_STATE, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_OSD_COORDS, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_OSD_COORDS, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_SCREEN_COORDS, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_SCREEN_COORDS, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_GLOBAL_ALPHA, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_GLOBAL_ALPHA, API_CACHE), - API_ENTRY(CX2341X_OSD_SET_BLEND_COORDS, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_FLICKER_STATE, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_FLICKER_STATE, API_CACHE), - API_ENTRY(CX2341X_OSD_BLT_COPY, API_RESULT), - API_ENTRY(CX2341X_OSD_BLT_FILL, API_RESULT), - API_ENTRY(CX2341X_OSD_BLT_TEXT, API_RESULT), - API_ENTRY(CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, API_CACHE), - API_ENTRY(CX2341X_OSD_SET_CHROMA_KEY, API_CACHE), - API_ENTRY(CX2341X_OSD_GET_ALPHA_CONTENT_INDEX, API_FAST_RESULT), - API_ENTRY(CX2341X_OSD_SET_ALPHA_CONTENT_INDEX, API_CACHE) -}; - -static int try_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int mb) -{ - u32 flags = readl(&mbdata->mbox[mb].flags); - int is_free = flags == IVTV_MBOX_FREE || (flags & IVTV_MBOX_FIRMWARE_DONE); - - /* if the mailbox is free, then try to claim it */ - if (is_free && !test_and_set_bit(mb, &mbdata->busy)) { - write_sync(IVTV_MBOX_DRIVER_BUSY, &mbdata->mbox[mb].flags); - return 1; - } - return 0; -} - -/* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not - attempted here. */ -static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int flags) -{ - unsigned long then = jiffies; - int i, mb; - int max_mbox = mbdata->max_mbox; - int retries = 100; - - /* All slow commands use the same mailbox, serializing them and also - leaving the other mailbox free for simple fast commands. */ - if ((flags & API_FAST_RESULT) == API_RESULT) - max_mbox = 1; - - /* find free non-DMA mailbox */ - for (i = 0; i < retries; i++) { - for (mb = 1; mb <= max_mbox; mb++) - if (try_mailbox(itv, mbdata, mb)) - return mb; - - /* Sleep before a retry, if not atomic */ - if (!(flags & API_NO_WAIT_MB)) { - if (time_after(jiffies, - then + msecs_to_jiffies(10*retries))) - break; - ivtv_msleep_timeout(10, 0); - } - } - return -ENODEV; -} - -static void write_mailbox(volatile struct ivtv_mailbox __iomem *mbox, int cmd, int args, u32 data[]) -{ - int i; - - write_sync(cmd, &mbox->cmd); - write_sync(IVTV_API_STD_TIMEOUT, &mbox->timeout); - - for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) - write_sync(data[i], &mbox->data[i]); - - write_sync(IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_DRIVER_BUSY, &mbox->flags); -} - -static void clear_all_mailboxes(struct ivtv *itv, struct ivtv_mailbox_data *mbdata) -{ - int i; - - for (i = 0; i <= mbdata->max_mbox; i++) { - IVTV_DEBUG_WARN("Clearing mailbox %d: cmd 0x%08x flags 0x%08x\n", - i, readl(&mbdata->mbox[i].cmd), readl(&mbdata->mbox[i].flags)); - write_sync(0, &mbdata->mbox[i].flags); - clear_bit(i, &mbdata->busy); - } -} - -static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) -{ - struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox; - volatile struct ivtv_mailbox __iomem *mbox; - int api_timeout = msecs_to_jiffies(1000); - int flags, mb, i; - unsigned long then; - - /* sanity checks */ - if (NULL == mbdata) { - IVTV_ERR("No mailbox allocated\n"); - return -ENODEV; - } - if (args < 0 || args > CX2341X_MBOX_MAX_DATA || - cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) { - IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args); - return -EINVAL; - } - - if (api_info[cmd].flags & API_HIGH_VOL) { - IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name); - } - else { - IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name); - } - - /* clear possibly uninitialized part of data array */ - for (i = args; i < CX2341X_MBOX_MAX_DATA; i++) - data[i] = 0; - - /* If this command was issued within the last 30 minutes and with identical - data, then just return 0 as there is no need to issue this command again. - Just an optimization to prevent unnecessary use of mailboxes. */ - if (itv->api_cache[cmd].last_jiffies && - time_before(jiffies, - itv->api_cache[cmd].last_jiffies + - msecs_to_jiffies(1800000)) && - !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) { - itv->api_cache[cmd].last_jiffies = jiffies; - return 0; - } - - flags = api_info[cmd].flags; - - if (flags & API_DMA) { - for (i = 0; i < 100; i++) { - mb = i % (mbdata->max_mbox + 1); - if (try_mailbox(itv, mbdata, mb)) { - write_mailbox(&mbdata->mbox[mb], cmd, args, data); - clear_bit(mb, &mbdata->busy); - return 0; - } - IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n", - api_info[cmd].name, mb, readl(&mbdata->mbox[mb].flags)); - } - IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info[cmd].name); - clear_all_mailboxes(itv, mbdata); - return -EBUSY; - } - - if ((flags & API_FAST_RESULT) == API_FAST_RESULT) - api_timeout = msecs_to_jiffies(100); - - mb = get_mailbox(itv, mbdata, flags); - if (mb < 0) { - IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info[cmd].name); - clear_all_mailboxes(itv, mbdata); - return -EBUSY; - } - mbox = &mbdata->mbox[mb]; - write_mailbox(mbox, cmd, args, data); - if (flags & API_CACHE) { - memcpy(itv->api_cache[cmd].data, data, sizeof(itv->api_cache[cmd].data)); - itv->api_cache[cmd].last_jiffies = jiffies; - } - if ((flags & API_RESULT) == 0) { - clear_bit(mb, &mbdata->busy); - return 0; - } - - /* Get results */ - then = jiffies; - - if (!(flags & API_NO_POLL)) { - /* First try to poll, then switch to delays */ - for (i = 0; i < 100; i++) { - if (readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE) - break; - } - } - while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) { - if (time_after(jiffies, then + api_timeout)) { - IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name); - /* reset the mailbox, but it is likely too late already */ - write_sync(0, &mbox->flags); - clear_bit(mb, &mbdata->busy); - return -EIO; - } - if (flags & API_NO_WAIT_RES) - mdelay(1); - else - ivtv_msleep_timeout(1, 0); - } - if (time_after(jiffies, then + msecs_to_jiffies(100))) - IVTV_DEBUG_WARN("%s took %u jiffies\n", - api_info[cmd].name, - jiffies_to_msecs(jiffies - then)); - - for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) - data[i] = readl(&mbox->data[i]); - write_sync(0, &mbox->flags); - clear_bit(mb, &mbdata->busy); - return 0; -} - -int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]) -{ - int res = ivtv_api_call(itv, cmd, args, data); - - /* Allow a single retry, probably already too late though. - If there is no free mailbox then that is usually an indication - of a more serious problem. */ - return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res; -} - -int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) -{ - return ivtv_api(priv, cmd, in, data); -} - -int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...) -{ - va_list ap; - int i; - - va_start(ap, args); - for (i = 0; i < args; i++) { - data[i] = va_arg(ap, u32); - } - va_end(ap); - return ivtv_api(itv, cmd, args, data); -} - -int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - va_list ap; - int i; - - va_start(ap, args); - for (i = 0; i < args; i++) { - data[i] = va_arg(ap, u32); - } - va_end(ap); - return ivtv_api(itv, cmd, args, data); -} - -/* This one is for stuff that can't sleep.. irq handlers, etc.. */ -void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb, - int argc, u32 data[]) -{ - volatile u32 __iomem *p = mbdata->mbox[mb].data; - int i; - for (i = 0; i < argc; i++, p++) - data[i] = readl(p); -} - -/* Wipe api cache */ -void ivtv_mailbox_cache_invalidate(struct ivtv *itv) -{ - int i; - for (i = 0; i < 256; i++) - itv->api_cache[i].last_jiffies = 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-mailbox.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-mailbox.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-mailbox.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-mailbox.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - mailbox functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_MAILBOX_H -#define IVTV_MAILBOX_H - -#define IVTV_MBOX_DMA_END 8 -#define IVTV_MBOX_DMA 9 - -void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb, - int argc, u32 data[]); -int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); -int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); -int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); -int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); -void ivtv_mailbox_cache_invalidate(struct ivtv *itv); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-queue.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-queue.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-queue.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-queue.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,297 +0,0 @@ -/* - buffer queues. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-queue.h" - -int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes) -{ - if (s->buf_size - buf->bytesused < copybytes) - copybytes = s->buf_size - buf->bytesused; - if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) { - return -EFAULT; - } - buf->bytesused += copybytes; - return copybytes; -} - -void ivtv_buf_swap(struct ivtv_buffer *buf) -{ - int i; - - for (i = 0; i < buf->bytesused; i += 4) - swab32s((u32 *)(buf->buf + i)); -} - -void ivtv_queue_init(struct ivtv_queue *q) -{ - INIT_LIST_HEAD(&q->list); - q->buffers = 0; - q->length = 0; - q->bytesused = 0; -} - -void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q) -{ - unsigned long flags; - - /* clear the buffer if it is going to be enqueued to the free queue */ - if (q == &s->q_free) { - buf->bytesused = 0; - buf->readpos = 0; - buf->b_flags = 0; - buf->dma_xfer_cnt = 0; - } - spin_lock_irqsave(&s->qlock, flags); - list_add_tail(&buf->list, &q->list); - q->buffers++; - q->length += s->buf_size; - q->bytesused += buf->bytesused - buf->readpos; - spin_unlock_irqrestore(&s->qlock, flags); -} - -struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) -{ - struct ivtv_buffer *buf = NULL; - unsigned long flags; - - spin_lock_irqsave(&s->qlock, flags); - if (!list_empty(&q->list)) { - buf = list_entry(q->list.next, struct ivtv_buffer, list); - list_del_init(q->list.next); - q->buffers--; - q->length -= s->buf_size; - q->bytesused -= buf->bytesused - buf->readpos; - } - spin_unlock_irqrestore(&s->qlock, flags); - return buf; -} - -static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, - struct ivtv_queue *to, int clear) -{ - struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); - - list_move_tail(from->list.next, &to->list); - from->buffers--; - from->length -= s->buf_size; - from->bytesused -= buf->bytesused - buf->readpos; - /* special handling for q_free */ - if (clear) - buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; - to->buffers++; - to->length += s->buf_size; - to->bytesused += buf->bytesused - buf->readpos; -} - -/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. - If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. - If 'steal' != NULL, then buffers may also taken from that queue if - needed, but only if 'from' is the free queue. - - The buffer is automatically cleared if it goes to the free queue. It is - also cleared if buffers need to be taken from the 'steal' queue and - the 'from' queue is the free queue. - - When 'from' is q_free, then needed_bytes is compared to the total - available buffer length, otherwise needed_bytes is compared to the - bytesused value. For the 'steal' queue the total available buffer - length is always used. - - -ENOMEM is returned if the buffers could not be obtained, 0 if all - buffers where obtained from the 'from' list and if non-zero then - the number of stolen buffers is returned. */ -int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, - struct ivtv_queue *to, int needed_bytes) -{ - unsigned long flags; - int rc = 0; - int from_free = from == &s->q_free; - int to_free = to == &s->q_free; - int bytes_available, bytes_steal; - - spin_lock_irqsave(&s->qlock, flags); - if (needed_bytes == 0) { - from_free = 1; - needed_bytes = from->length; - } - - bytes_available = from_free ? from->length : from->bytesused; - bytes_steal = (from_free && steal) ? steal->length : 0; - - if (bytes_available + bytes_steal < needed_bytes) { - spin_unlock_irqrestore(&s->qlock, flags); - return -ENOMEM; - } - while (bytes_available < needed_bytes) { - struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list); - u16 dma_xfer_cnt = buf->dma_xfer_cnt; - - /* move buffers from the tail of the 'steal' queue to the tail of the - 'from' queue. Always copy all the buffers with the same dma_xfer_cnt - value, this ensures that you do not end up with partial frame data - if one frame is stored in multiple buffers. */ - while (dma_xfer_cnt == buf->dma_xfer_cnt) { - list_move_tail(steal->list.prev, &from->list); - rc++; - steal->buffers--; - steal->length -= s->buf_size; - steal->bytesused -= buf->bytesused - buf->readpos; - buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; - from->buffers++; - from->length += s->buf_size; - bytes_available += s->buf_size; - if (list_empty(&steal->list)) - break; - buf = list_entry(steal->list.prev, struct ivtv_buffer, list); - } - } - if (from_free) { - u32 old_length = to->length; - - while (to->length - old_length < needed_bytes) { - ivtv_queue_move_buf(s, from, to, 1); - } - } - else { - u32 old_bytesused = to->bytesused; - - while (to->bytesused - old_bytesused < needed_bytes) { - ivtv_queue_move_buf(s, from, to, to_free); - } - } - spin_unlock_irqrestore(&s->qlock, flags); - return rc; -} - -void ivtv_flush_queues(struct ivtv_stream *s) -{ - ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0); - ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0); - ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); -} - -int ivtv_stream_alloc(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - int SGsize = sizeof(struct ivtv_sg_host_element) * s->buffers; - int i; - - if (s->buffers == 0) - return 0; - - IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n", - s->dma != PCI_DMA_NONE ? "DMA " : "", - s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - - s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); - if (s->sg_pending == NULL) { - IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); - return -ENOMEM; - } - s->sg_pending_size = 0; - - s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); - if (s->sg_processing == NULL) { - IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); - kfree(s->sg_pending); - s->sg_pending = NULL; - return -ENOMEM; - } - s->sg_processing_size = 0; - - s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), - GFP_KERNEL|__GFP_NOWARN); - if (s->sg_dma == NULL) { - IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); - kfree(s->sg_pending); - s->sg_pending = NULL; - kfree(s->sg_processing); - s->sg_processing = NULL; - return -ENOMEM; - } - if (ivtv_might_use_dma(s)) { - s->sg_handle = pci_map_single(itv->pdev, s->sg_dma, - sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); - ivtv_stream_sync_for_cpu(s); - } - - /* allocate stream buffers. Initially all buffers are in q_free. */ - for (i = 0; i < s->buffers; i++) { - struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), - GFP_KERNEL|__GFP_NOWARN); - - if (buf == NULL) - break; - buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN); - if (buf->buf == NULL) { - kfree(buf); - break; - } - INIT_LIST_HEAD(&buf->list); - if (ivtv_might_use_dma(s)) { - buf->dma_handle = pci_map_single(s->itv->pdev, - buf->buf, s->buf_size + 256, s->dma); - ivtv_buf_sync_for_cpu(s, buf); - } - ivtv_enqueue(s, buf, &s->q_free); - } - if (i == s->buffers) - return 0; - IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name); - ivtv_stream_free(s); - return -ENOMEM; -} - -void ivtv_stream_free(struct ivtv_stream *s) -{ - struct ivtv_buffer *buf; - - /* move all buffers to q_free */ - ivtv_flush_queues(s); - - /* empty q_free */ - while ((buf = ivtv_dequeue(s, &s->q_free))) { - if (ivtv_might_use_dma(s)) - pci_unmap_single(s->itv->pdev, buf->dma_handle, - s->buf_size + 256, s->dma); - kfree(buf->buf); - kfree(buf); - } - - /* Free SG Array/Lists */ - if (s->sg_dma != NULL) { - if (s->sg_handle != IVTV_DMA_UNMAPPED) { - pci_unmap_single(s->itv->pdev, s->sg_handle, - sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); - s->sg_handle = IVTV_DMA_UNMAPPED; - } - kfree(s->sg_pending); - kfree(s->sg_processing); - kfree(s->sg_dma); - s->sg_pending = NULL; - s->sg_processing = NULL; - s->sg_dma = NULL; - s->sg_pending_size = 0; - s->sg_processing_size = 0; - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-queue.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-queue.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-queue.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-queue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/* - buffer queues. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_QUEUE_H -#define IVTV_QUEUE_H - -#define IVTV_DMA_UNMAPPED ((u32) -1) -#define SLICED_VBI_PIO 0 - -/* ivtv_buffer utility functions */ - -static inline int ivtv_might_use_pio(struct ivtv_stream *s) -{ - return s->dma == PCI_DMA_NONE || (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI); -} - -static inline int ivtv_use_pio(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - - return s->dma == PCI_DMA_NONE || - (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set); -} - -static inline int ivtv_might_use_dma(struct ivtv_stream *s) -{ - return s->dma != PCI_DMA_NONE; -} - -static inline int ivtv_use_dma(struct ivtv_stream *s) -{ - return !ivtv_use_pio(s); -} - -static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf) -{ - if (ivtv_use_dma(s)) - pci_dma_sync_single_for_cpu(s->itv->pdev, buf->dma_handle, - s->buf_size + 256, s->dma); -} - -static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf) -{ - if (ivtv_use_dma(s)) - pci_dma_sync_single_for_device(s->itv->pdev, buf->dma_handle, - s->buf_size + 256, s->dma); -} - -int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes); -void ivtv_buf_swap(struct ivtv_buffer *buf); - -/* ivtv_queue utility functions */ -void ivtv_queue_init(struct ivtv_queue *q); -void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q); -struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q); -int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, - struct ivtv_queue *to, int needed_bytes); -void ivtv_flush_queues(struct ivtv_stream *s); - -/* ivtv_stream utility functions */ -int ivtv_stream_alloc(struct ivtv_stream *s); -void ivtv_stream_free(struct ivtv_stream *s); - -static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s) -{ - if (ivtv_use_dma(s)) - pci_dma_sync_single_for_cpu(s->itv->pdev, s->sg_handle, - sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); -} - -static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) -{ - if (ivtv_use_dma(s)) - pci_dma_sync_single_for_device(s->itv->pdev, s->sg_handle, - sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-routing.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-routing.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-routing.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-routing.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,119 +0,0 @@ -/* - Audio/video-routing-related ivtv functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-i2c.h" -#include "ivtv-cards.h" -#include "ivtv-gpio.h" -#include "ivtv-routing.h" - -#include -#include -#include -#include - -/* Selects the audio input and output according to the current - settings. */ -void ivtv_audio_set_io(struct ivtv *itv) -{ - const struct ivtv_card_audio_input *in; - u32 input, output = 0; - - /* Determine which input to use */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) - in = &itv->card->radio_input; - else - in = &itv->card->audio_inputs[itv->audio_input]; - - /* handle muxer chips */ - input = in->muxer_input; - if (itv->card->hw_muxer & IVTV_HW_M52790) - output = M52790_OUT_STEREO; - v4l2_subdev_call(itv->sd_muxer, audio, s_routing, - input, output, 0); - - input = in->audio_input; - output = 0; - if (itv->card->hw_audio & IVTV_HW_MSP34XX) - output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing, - input, output, 0); -} - -/* Selects the video input and output according to the current - settings. */ -void ivtv_video_set_io(struct ivtv *itv) -{ - int inp = itv->active_input; - u32 input; - u32 type; - - v4l2_subdev_call(itv->sd_video, video, s_routing, - itv->card->video_inputs[inp].video_input, 0, 0); - - type = itv->card->video_inputs[inp].video_type; - - if (type == IVTV_CARD_INPUT_VID_TUNER) { - input = 0; /* Tuner */ - } else if (type < IVTV_CARD_INPUT_COMPOSITE1) { - input = 2; /* S-Video */ - } else { - input = 1; /* Composite */ - } - - if (itv->card->hw_video & IVTV_HW_GPIO) - ivtv_call_hw(itv, IVTV_HW_GPIO, video, s_routing, - input, 0, 0); - - if (itv->card->hw_video & IVTV_HW_UPD64031A) { - if (type == IVTV_CARD_INPUT_VID_TUNER || - type >= IVTV_CARD_INPUT_COMPOSITE1) { - /* Composite: GR on, connect to 3DYCS */ - input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE; - } else { - /* S-Video: GR bypassed, turn it off */ - input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE; - } - input |= itv->card->gr_config; - - ivtv_call_hw(itv, IVTV_HW_UPD64031A, video, s_routing, - input, 0, 0); - } - - if (itv->card->hw_video & IVTV_HW_UPD6408X) { - input = UPD64083_YCS_MODE; - if (type > IVTV_CARD_INPUT_VID_TUNER && - type < IVTV_CARD_INPUT_COMPOSITE1) { - /* S-Video uses YCNR mode and internal Y-ADC, the - upd64031a is not used. */ - input |= UPD64083_YCNR_MODE; - } - else if (itv->card->hw_video & IVTV_HW_UPD64031A) { - /* Use upd64031a output for tuner and - composite(CX23416GYC only) inputs */ - if (type == IVTV_CARD_INPUT_VID_TUNER || - itv->card->type == IVTV_CARD_CX23416GYC) { - input |= UPD64083_EXT_Y_ADC; - } - } - ivtv_call_hw(itv, IVTV_HW_UPD6408X, video, s_routing, - input, 0, 0); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-routing.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-routing.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-routing.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-routing.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* - Audio/video-routing-related ivtv functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_ROUTING_H -#define IVTV_ROUTING_H - -void ivtv_audio_set_io(struct ivtv *itv); -void ivtv_video_set_io(struct ivtv *itv); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-streams.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-streams.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-streams.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-streams.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1000 +0,0 @@ -/* - init/start/stop/exit stream functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -/* License: GPL - * Author: Kevin Thayer - * - * This file will hold API related functions, both internal (firmware api) - * and external (v4l2, etc) - * - * ----- - * MPG600/MPG160 support by T.Adachi - * and Takeru KOMORIYA - * - * AVerMedia M179 GPIO info by Chris Pinkham - * using information provided by Jiun-Kuei Jung @ AVerMedia. - */ - -#include "ivtv-driver.h" -#include "ivtv-fileops.h" -#include "ivtv-queue.h" -#include "ivtv-mailbox.h" -#include "ivtv-ioctl.h" -#include "ivtv-irq.h" -#include "ivtv-yuv.h" -#include "ivtv-cards.h" -#include "ivtv-streams.h" -#include "ivtv-firmware.h" -#include - -static const struct v4l2_file_operations ivtv_v4l2_enc_fops = { - .owner = THIS_MODULE, - .read = ivtv_v4l2_read, - .write = ivtv_v4l2_write, - .open = ivtv_v4l2_open, - .unlocked_ioctl = ivtv_v4l2_ioctl, - .release = ivtv_v4l2_close, - .poll = ivtv_v4l2_enc_poll, -}; - -static const struct v4l2_file_operations ivtv_v4l2_dec_fops = { - .owner = THIS_MODULE, - .read = ivtv_v4l2_read, - .write = ivtv_v4l2_write, - .open = ivtv_v4l2_open, - .unlocked_ioctl = ivtv_v4l2_ioctl, - .release = ivtv_v4l2_close, - .poll = ivtv_v4l2_dec_poll, -}; - -#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ -#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ -#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ -#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ - -static struct { - const char *name; - int vfl_type; - int num_offset; - int dma, pio; - enum v4l2_buf_type buf_type; - const struct v4l2_file_operations *fops; -} ivtv_stream_info[] = { - { /* IVTV_ENC_STREAM_TYPE_MPG */ - "encoder MPG", - VFL_TYPE_GRABBER, 0, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_YUV */ - "encoder YUV", - VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_VBI */ - "encoder VBI", - VFL_TYPE_VBI, 0, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_PCM */ - "encoder PCM", - VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_RAD */ - "encoder radio", - VFL_TYPE_RADIO, 0, - PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_DEC_STREAM_TYPE_MPG */ - "decoder MPG", - VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, - PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, - &ivtv_v4l2_dec_fops - }, - { /* IVTV_DEC_STREAM_TYPE_VBI */ - "decoder VBI", - VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, - PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_DEC_STREAM_TYPE_VOUT */ - "decoder VOUT", - VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, - PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, - &ivtv_v4l2_dec_fops - }, - { /* IVTV_DEC_STREAM_TYPE_YUV */ - "decoder YUV", - VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, - PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, - &ivtv_v4l2_dec_fops - } -}; - -static void ivtv_stream_init(struct ivtv *itv, int type) -{ - struct ivtv_stream *s = &itv->streams[type]; - struct video_device *vdev = s->vdev; - - /* we need to keep vdev, so restore it afterwards */ - memset(s, 0, sizeof(*s)); - s->vdev = vdev; - - /* initialize ivtv_stream fields */ - s->itv = itv; - s->type = type; - s->name = ivtv_stream_info[type].name; - - if (ivtv_stream_info[type].pio) - s->dma = PCI_DMA_NONE; - else - s->dma = ivtv_stream_info[type].dma; - s->buf_size = itv->stream_buf_size[type]; - if (s->buf_size) - s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size; - spin_lock_init(&s->qlock); - init_waitqueue_head(&s->waitq); - s->id = -1; - s->sg_handle = IVTV_DMA_UNMAPPED; - ivtv_queue_init(&s->q_free); - ivtv_queue_init(&s->q_full); - ivtv_queue_init(&s->q_dma); - ivtv_queue_init(&s->q_predma); - ivtv_queue_init(&s->q_io); -} - -static int ivtv_prep_dev(struct ivtv *itv, int type) -{ - struct ivtv_stream *s = &itv->streams[type]; - int num_offset = ivtv_stream_info[type].num_offset; - int num = itv->instance + ivtv_first_minor + num_offset; - - /* These four fields are always initialized. If vdev == NULL, then - this stream is not in use. In that case no other fields but these - four can be used. */ - s->vdev = NULL; - s->itv = itv; - s->type = type; - s->name = ivtv_stream_info[type].name; - - /* Check whether the radio is supported */ - if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO)) - return 0; - if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return 0; - - /* User explicitly selected 0 buffers for these streams, so don't - create them. */ - if (ivtv_stream_info[type].dma != PCI_DMA_NONE && - itv->options.kilobytes[type] == 0) { - IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); - return 0; - } - - ivtv_stream_init(itv, type); - - /* allocate and initialize the v4l2 video device structure */ - s->vdev = video_device_alloc(); - if (s->vdev == NULL) { - IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); - return -ENOMEM; - } - - snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s", - itv->v4l2_dev.name, s->name); - - s->vdev->num = num; - s->vdev->v4l2_dev = &itv->v4l2_dev; - s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler; - s->vdev->fops = ivtv_stream_info[type].fops; - s->vdev->release = video_device_release; - s->vdev->tvnorms = V4L2_STD_ALL; - set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags); - ivtv_set_funcs(s->vdev); - return 0; -} - -/* Initialize v4l2 variables and prepare v4l2 devices */ -int ivtv_streams_setup(struct ivtv *itv) -{ - int type; - - /* Setup V4L2 Devices */ - for (type = 0; type < IVTV_MAX_STREAMS; type++) { - /* Prepare device */ - if (ivtv_prep_dev(itv, type)) - break; - - if (itv->streams[type].vdev == NULL) - continue; - - /* Allocate Stream */ - if (ivtv_stream_alloc(&itv->streams[type])) - break; - } - if (type == IVTV_MAX_STREAMS) - return 0; - - /* One or more streams could not be initialized. Clean 'em all up. */ - ivtv_streams_cleanup(itv, 0); - return -ENOMEM; -} - -static int ivtv_reg_dev(struct ivtv *itv, int type) -{ - struct ivtv_stream *s = &itv->streams[type]; - int vfl_type = ivtv_stream_info[type].vfl_type; - const char *name; - int num; - - if (s->vdev == NULL) - return 0; - - num = s->vdev->num; - /* card number + user defined offset + device offset */ - if (type != IVTV_ENC_STREAM_TYPE_MPG) { - struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; - - if (s_mpg->vdev) - num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset; - } - video_set_drvdata(s->vdev, s); - - /* Register device. First try the desired minor, then any free one. */ - if (video_register_device_no_warn(s->vdev, vfl_type, num)) { - IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", - s->name, num); - video_device_release(s->vdev); - s->vdev = NULL; - return -ENOMEM; - } - name = video_device_node_name(s->vdev); - - switch (vfl_type) { - case VFL_TYPE_GRABBER: - IVTV_INFO("Registered device %s for %s (%d kB)\n", - name, s->name, itv->options.kilobytes[type]); - break; - case VFL_TYPE_RADIO: - IVTV_INFO("Registered device %s for %s\n", - name, s->name); - break; - case VFL_TYPE_VBI: - if (itv->options.kilobytes[type]) - IVTV_INFO("Registered device %s for %s (%d kB)\n", - name, s->name, itv->options.kilobytes[type]); - else - IVTV_INFO("Registered device %s for %s\n", - name, s->name); - break; - } - return 0; -} - -/* Register v4l2 devices */ -int ivtv_streams_register(struct ivtv *itv) -{ - int type; - int err = 0; - - /* Register V4L2 devices */ - for (type = 0; type < IVTV_MAX_STREAMS; type++) - err |= ivtv_reg_dev(itv, type); - - if (err == 0) - return 0; - - /* One or more streams could not be initialized. Clean 'em all up. */ - ivtv_streams_cleanup(itv, 1); - return -ENOMEM; -} - -/* Unregister v4l2 devices */ -void ivtv_streams_cleanup(struct ivtv *itv, int unregister) -{ - int type; - - /* Teardown all streams */ - for (type = 0; type < IVTV_MAX_STREAMS; type++) { - struct video_device *vdev = itv->streams[type].vdev; - - itv->streams[type].vdev = NULL; - if (vdev == NULL) - continue; - - ivtv_stream_free(&itv->streams[type]); - /* Unregister or release device */ - if (unregister) - video_unregister_device(vdev); - else - video_device_release(vdev); - } -} - -static void ivtv_vbi_setup(struct ivtv *itv) -{ - int raw = ivtv_raw_vbi(itv); - u32 data[CX2341X_MBOX_MAX_DATA]; - int lines; - int i; - - /* Reset VBI */ - ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); - - /* setup VBI registers */ - if (raw) - v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &itv->vbi.in.fmt.vbi); - else - v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, &itv->vbi.in.fmt.sliced); - - /* determine number of lines and total number of VBI bytes. - A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 - The '- 1' byte is probably an unused U or V byte. Or something... - A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal - header, 42 data bytes + checksum (to be confirmed) */ - if (raw) { - lines = itv->vbi.count * 2; - } else { - lines = itv->is_60hz ? 24 : 38; - if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840)) - lines += 2; - } - - itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); - - /* Note: sliced vs raw flag doesn't seem to have any effect - TODO: check mode (0x02) value with older ivtv versions. */ - data[0] = raw | 0x02 | (0xbd << 8); - - /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ - data[1] = 1; - /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ - data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size); - /* The start/stop codes determine which VBI lines end up in the raw VBI data area. - The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line - is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) - code. These values for raw VBI are obtained from a driver disassembly. The sliced - start/stop codes was deduced from this, but they do not appear in the driver. - Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54. - However, I have no idea what these values are for. */ - if (itv->hw_flags & IVTV_HW_CX25840) { - /* Setup VBI for the cx25840 digitizer */ - if (raw) { - data[3] = 0x20602060; - data[4] = 0x30703070; - } else { - data[3] = 0xB0F0B0F0; - data[4] = 0xA0E0A0E0; - } - /* Lines per frame */ - data[5] = lines; - /* bytes per line */ - data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); - } else { - /* Setup VBI for the saa7115 digitizer */ - if (raw) { - data[3] = 0x25256262; - data[4] = 0x387F7F7F; - } else { - data[3] = 0xABABECEC; - data[4] = 0xB6F1F1F1; - } - /* Lines per frame */ - data[5] = lines; - /* bytes per line */ - data[6] = itv->vbi.enc_size / lines; - } - - IVTV_DEBUG_INFO( - "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n", - data[0], data[1], data[2], data[5], data[6]); - - ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data); - - /* returns the VBI encoder memory area. */ - itv->vbi.enc_start = data[2]; - itv->vbi.fpi = data[0]; - if (!itv->vbi.fpi) - itv->vbi.fpi = 1; - - IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n", - itv->vbi.enc_start, data[1], itv->vbi.fpi); - - /* select VBI lines. - Note that the sliced argument seems to have no effect. */ - for (i = 2; i <= 24; i++) { - int valid; - - if (itv->is_60hz) { - valid = i >= 10 && i < 22; - } else { - valid = i >= 6 && i < 24; - } - ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1, - valid, 0 , 0, 0); - ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000, - valid, 0, 0, 0); - } - - /* Remaining VBI questions: - - Is it possible to select particular VBI lines only for inclusion in the MPEG - stream? Currently you can only get the first X lines. - - Is mixed raw and sliced VBI possible? - - What's the meaning of the raw/sliced flag? - - What's the meaning of params 2, 3 & 4 of the Select VBI command? */ -} - -int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv *itv = s->itv; - int captype = 0, subtype = 0; - int enable_passthrough = 0; - - if (s->vdev == NULL) - return -EINVAL; - - IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); - - switch (s->type) { - case IVTV_ENC_STREAM_TYPE_MPG: - captype = 0; - subtype = 3; - - /* Stop Passthrough */ - if (itv->output_mode == OUT_PASSTHROUGH) { - ivtv_passthrough_mode(itv, 0); - enable_passthrough = 1; - } - itv->mpg_data_received = itv->vbi_data_inserted = 0; - itv->dualwatch_jiffies = jiffies; - itv->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode); - itv->search_pack_header = 0; - break; - - case IVTV_ENC_STREAM_TYPE_YUV: - if (itv->output_mode == OUT_PASSTHROUGH) { - captype = 2; - subtype = 11; /* video+audio+decoder */ - break; - } - captype = 1; - subtype = 1; - break; - case IVTV_ENC_STREAM_TYPE_PCM: - captype = 1; - subtype = 2; - break; - case IVTV_ENC_STREAM_TYPE_VBI: - captype = 1; - subtype = 4; - - itv->vbi.frame = 0; - itv->vbi.inserted_frame = 0; - memset(itv->vbi.sliced_mpeg_size, - 0, sizeof(itv->vbi.sliced_mpeg_size)); - break; - default: - return -EINVAL; - } - s->subtype = subtype; - s->buffers_stolen = 0; - - /* Clear Streamoff flags in case left from last capture */ - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - if (atomic_read(&itv->capturing) == 0) { - int digitizer; - - /* Always use frame based mode. Experiments have demonstrated that byte - stream based mode results in dropped frames and corruption. Not often, - but occasionally. Many thanks go to Leonard Orb who spent a lot of - effort and time trying to trace the cause of the drop outs. */ - /* 1 frame per DMA */ - /*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */ - ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1); - - /* Stuff from Windows, we don't know what it is */ - ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0); - /* According to the docs, this should be correct. However, this is - untested. I don't dare enable this without having tested it. - Only very few old cards actually have this hardware combination. - ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, - ((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0); - */ - ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415); - ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0); - ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1); - ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); - - /* assign placeholder */ - ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - - if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) - digitizer = 0xF1; - else if (itv->card->hw_all & IVTV_HW_SAA7114) - digitizer = 0xEF; - else /* cx25840 */ - digitizer = 0x140; - - ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer); - - /* Setup VBI */ - if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) { - ivtv_vbi_setup(itv); - } - - /* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */ - ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400); - itv->pgm_info_offset = data[0]; - itv->pgm_info_num = data[1]; - itv->pgm_info_write_idx = 0; - itv->pgm_info_read_idx = 0; - - IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n", - itv->pgm_info_offset, itv->pgm_info_num); - - /* Setup API for Stream */ - cx2341x_handler_setup(&itv->cxhdl); - - /* mute if capturing radio */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) - ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, - 1 | (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8)); - } - - /* Vsync Setup */ - if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { - /* event notification (on) */ - ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1); - ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); - } - - if (atomic_read(&itv->capturing) == 0) { - /* Clear all Pending Interrupts */ - ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); - - clear_bit(IVTV_F_I_EOS, &itv->i_flags); - - cx2341x_handler_set_busy(&itv->cxhdl, 1); - - /* Initialize Digitizer for Capture */ - /* Avoid tinny audio problem - ensure audio clocks are going */ - v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1); - /* Avoid unpredictable PCI bus hang - disable video clocks */ - v4l2_subdev_call(itv->sd_video, video, s_stream, 0); - ivtv_msleep_timeout(300, 1); - ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - v4l2_subdev_call(itv->sd_video, video, s_stream, 1); - } - - /* begin_capture */ - if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) - { - IVTV_DEBUG_WARN( "Error starting capture!\n"); - return -EINVAL; - } - - /* Start Passthrough */ - if (enable_passthrough) { - ivtv_passthrough_mode(itv, 1); - } - - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) - ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); - else - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); - - /* you're live! sit back and await interrupts :) */ - atomic_inc(&itv->capturing); - return 0; -} - -static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv *itv = s->itv; - int datatype; - u16 width; - u16 height; - - if (s->vdev == NULL) - return -EINVAL; - - IVTV_DEBUG_INFO("Setting some initial decoder settings\n"); - - width = itv->cxhdl.width; - height = itv->cxhdl.height; - - /* set audio mode to left/stereo for dual/stereo mode. */ - ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); - - /* set number of internal decoder buffers */ - ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0); - - /* prebuffering */ - ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1); - - /* extract from user packets */ - ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1); - itv->vbi.dec_start = data[0]; - - IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n", - itv->vbi.dec_start, data[1]); - - /* set decoder source settings */ - /* Data type: 0 = mpeg from host, - 1 = yuv from encoder, - 2 = yuv_from_host */ - switch (s->type) { - case IVTV_DEC_STREAM_TYPE_YUV: - if (itv->output_mode == OUT_PASSTHROUGH) { - datatype = 1; - } else { - /* Fake size to avoid switching video standard */ - datatype = 2; - width = 720; - height = itv->is_out_50hz ? 576 : 480; - } - IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype); - break; - case IVTV_DEC_STREAM_TYPE_MPG: - default: - datatype = 0; - break; - } - if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype, - width, height, itv->cxhdl.audio_properties)) { - IVTV_DEBUG_WARN("Couldn't initialize decoder source\n"); - } - - /* Decoder sometimes dies here, so wait a moment */ - ivtv_msleep_timeout(10, 0); - - /* Known failure point for firmware, so check */ - return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream"); -} - -int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) -{ - struct ivtv *itv = s->itv; - int rc; - - if (s->vdev == NULL) - return -EINVAL; - - if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) - return 0; /* already started */ - - IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); - - rc = ivtv_setup_v4l2_decode_stream(s); - if (rc < 0) { - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - return rc; - } - - /* set dma size to 65536 bytes */ - ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); - - /* Clear Streamoff */ - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - /* Zero out decoder counters */ - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]); - - /* turn on notification of dual/stereo mode change */ - ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); - - /* start playback */ - ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0); - - /* Let things settle before we actually start */ - ivtv_msleep_timeout(10, 0); - - /* Clear the following Interrupt mask bits for decoding */ - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE); - IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask); - - /* you're live! sit back and await interrupts :) */ - atomic_inc(&itv->decoding); - return 0; -} - -void ivtv_stop_all_captures(struct ivtv *itv) -{ - int i; - - for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) { - struct ivtv_stream *s = &itv->streams[i]; - - if (s->vdev == NULL) - continue; - if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - ivtv_stop_v4l2_encode_stream(s, 0); - } - } -} - -int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) -{ - struct ivtv *itv = s->itv; - DECLARE_WAITQUEUE(wait, current); - int cap_type; - int stopmode; - - if (s->vdev == NULL) - return -EINVAL; - - /* This function assumes that you are allowed to stop the capture - and that we are actually capturing */ - - IVTV_DEBUG_INFO("Stop Capture\n"); - - if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) - return 0; - if (atomic_read(&itv->capturing) == 0) - return 0; - - switch (s->type) { - case IVTV_ENC_STREAM_TYPE_YUV: - cap_type = 1; - break; - case IVTV_ENC_STREAM_TYPE_PCM: - cap_type = 1; - break; - case IVTV_ENC_STREAM_TYPE_VBI: - cap_type = 1; - break; - case IVTV_ENC_STREAM_TYPE_MPG: - default: - cap_type = 0; - break; - } - - /* Stop Capture Mode */ - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { - stopmode = 0; - } else { - stopmode = 1; - } - - /* end_capture */ - /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ - ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); - - if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { - /* only run these if we're shutting down the last cap */ - unsigned long duration; - unsigned long then = jiffies; - - add_wait_queue(&itv->eos_waitq, &wait); - - set_current_state(TASK_INTERRUPTIBLE); - - /* wait 2s for EOS interrupt */ - while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && - time_before(jiffies, - then + msecs_to_jiffies(2000))) { - schedule_timeout(msecs_to_jiffies(10)); - } - - /* To convert jiffies to ms, we must multiply by 1000 - * and divide by HZ. To avoid runtime division, we - * convert this to multiplication by 1000/HZ. - * Since integer division truncates, we get the best - * accuracy if we do a rounding calculation of the constant. - * Think of the case where HZ is 1024. - */ - duration = ((1000 + HZ / 2) / HZ) * (jiffies - then); - - if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) { - IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name); - IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration); - } else { - IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&itv->eos_waitq, &wait); - set_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - } - - /* Handle any pending interrupts */ - ivtv_msleep_timeout(100, 1); - } - - atomic_dec(&itv->capturing); - - /* Clear capture and no-read bits */ - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) - ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); - - if (atomic_read(&itv->capturing) > 0) { - return 0; - } - - cx2341x_handler_set_busy(&itv->cxhdl, 0); - - /* Set the following Interrupt mask bits for capture */ - ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); - del_timer(&itv->dma_timer); - - /* event notification (off) */ - if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { - /* type: 0 = refresh */ - /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */ - ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1); - ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); - } - - /* Raw-passthrough is implied on start. Make sure it's stopped so - the encoder will re-initialize when next started */ - ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 7); - - wake_up(&s->waitq); - - return 0; -} - -int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) -{ - static const struct v4l2_event ev = { - .type = V4L2_EVENT_EOS, - }; - struct ivtv *itv = s->itv; - - if (s->vdev == NULL) - return -EINVAL; - - if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG) - return -EINVAL; - - if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags)) - return 0; - - IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags); - - /* Stop Decoder */ - if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) { - u32 tmp = 0; - - /* Wait until the decoder is no longer running */ - if (pts) { - ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, - 0, (u32)(pts & 0xffffffff), (u32)(pts >> 32)); - } - while (1) { - u32 data[CX2341X_MBOX_MAX_DATA]; - ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0); - if (s->q_full.buffers + s->q_dma.buffers == 0) { - if (tmp == data[3]) - break; - tmp = data[3]; - } - if (ivtv_msleep_timeout(100, 1)) - break; - } - } - ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0); - - /* turn off notification of dual/stereo mode change */ - ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); - - ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); - del_timer(&itv->dma_timer); - - clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - ivtv_flush_queues(s); - - /* decoder needs time to settle */ - ivtv_msleep_timeout(40, 0); - - /* decrement decoding */ - atomic_dec(&itv->decoding); - - set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags); - wake_up(&itv->event_waitq); - v4l2_event_queue(s->vdev, &ev); - - /* wake up wait queues */ - wake_up(&s->waitq); - - return 0; -} - -int ivtv_passthrough_mode(struct ivtv *itv, int enable) -{ - struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV]; - struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - - if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL) - return -EINVAL; - - IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n"); - - /* Prevent others from starting/stopping streams while we - initiate/terminate passthrough mode */ - if (enable) { - if (itv->output_mode == OUT_PASSTHROUGH) { - return 0; - } - if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH) - return -EBUSY; - - /* Fully initialize stream, and then unflag init */ - set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); - set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); - - /* Setup YUV Decoder */ - ivtv_setup_v4l2_decode_stream(dec_stream); - - /* Start Decoder */ - ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1); - atomic_inc(&itv->decoding); - - /* Setup capture if not already done */ - if (atomic_read(&itv->capturing) == 0) { - cx2341x_handler_setup(&itv->cxhdl); - cx2341x_handler_set_busy(&itv->cxhdl, 1); - } - - /* Start Passthrough Mode */ - ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11); - atomic_inc(&itv->capturing); - return 0; - } - - if (itv->output_mode != OUT_PASSTHROUGH) - return 0; - - /* Stop Passthrough Mode */ - ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11); - ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0); - - atomic_dec(&itv->capturing); - atomic_dec(&itv->decoding); - clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); - clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); - itv->output_mode = OUT_NONE; - if (atomic_read(&itv->capturing) == 0) - cx2341x_handler_set_busy(&itv->cxhdl, 0); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-streams.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-streams.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-streams.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-streams.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* - init/start/stop/exit stream functions - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_STREAMS_H -#define IVTV_STREAMS_H - -int ivtv_streams_setup(struct ivtv *itv); -int ivtv_streams_register(struct ivtv *itv); -void ivtv_streams_cleanup(struct ivtv *itv, int unregister); - -/* Capture related */ -int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s); -int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end); -int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset); -int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts); - -void ivtv_stop_all_captures(struct ivtv *itv); -int ivtv_passthrough_mode(struct ivtv *itv, int enable); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-udma.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-udma.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-udma.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-udma.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,234 +0,0 @@ -/* - User DMA - - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-udma.h" - -void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size) -{ - dma_page->uaddr = first & PAGE_MASK; - dma_page->offset = first & ~PAGE_MASK; - dma_page->tail = 1 + ((first+size-1) & ~PAGE_MASK); - dma_page->first = (first & PAGE_MASK) >> PAGE_SHIFT; - dma_page->last = ((first+size-1) & PAGE_MASK) >> PAGE_SHIFT; - dma_page->page_count = dma_page->last - dma_page->first + 1; - if (dma_page->page_count == 1) dma_page->tail -= dma_page->offset; -} - -int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) -{ - int i, offset; - unsigned long flags; - - if (map_offset < 0) - return map_offset; - - offset = dma_page->offset; - - /* Fill SG Array with new values */ - for (i = 0; i < dma_page->page_count; i++) { - unsigned int len = (i == dma_page->page_count - 1) ? - dma_page->tail : PAGE_SIZE - offset; - - if (PageHighMem(dma->map[map_offset])) { - void *src; - - if (dma->bouncemap[map_offset] == NULL) - dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); - if (dma->bouncemap[map_offset] == NULL) - return -1; - local_irq_save(flags); - src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; - memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); - kunmap_atomic(src, KM_BOUNCE_READ); - local_irq_restore(flags); - sg_set_page(&dma->SGlist[map_offset], dma->bouncemap[map_offset], len, offset); - } - else { - sg_set_page(&dma->SGlist[map_offset], dma->map[map_offset], len, offset); - } - offset = 0; - map_offset++; - } - return map_offset; -} - -void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { - int i; - struct scatterlist *sg; - - for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg++) { - dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg)); - dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg)); - dma->SGarray[i].dst = cpu_to_le32(buffer_offset); - buffer_offset += sg_dma_len(sg); - - split -= sg_dma_len(sg); - if (split == 0) - buffer_offset = buffer_offset_2; - } -} - -/* User DMA Buffers */ -void ivtv_udma_alloc(struct ivtv *itv) -{ - if (itv->udma.SG_handle == 0) { - /* Map DMA Page Array Buffer */ - itv->udma.SG_handle = pci_map_single(itv->pdev, itv->udma.SGarray, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); - ivtv_udma_sync_for_cpu(itv); - } -} - -int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, - void __user *userbuf, int size_in_bytes) -{ - struct ivtv_dma_page_info user_dma; - struct ivtv_user_dma *dma = &itv->udma; - int i, err; - - IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); - - /* Still in USE */ - if (dma->SG_length || dma->page_count) { - IVTV_DEBUG_WARN("ivtv_udma_setup: SG_length %d page_count %d still full?\n", - dma->SG_length, dma->page_count); - return -EBUSY; - } - - ivtv_udma_get_page_info(&user_dma, (unsigned long)userbuf, size_in_bytes); - - if (user_dma.page_count <= 0) { - IVTV_DEBUG_WARN("ivtv_udma_setup: Error %d page_count from %d bytes %d offset\n", - user_dma.page_count, size_in_bytes, user_dma.offset); - return -EINVAL; - } - - /* Get user pages for DMA Xfer */ - down_read(¤t->mm->mmap_sem); - err = get_user_pages(current, current->mm, - user_dma.uaddr, user_dma.page_count, 0, 1, dma->map, NULL); - up_read(¤t->mm->mmap_sem); - - if (user_dma.page_count != err) { - IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", - err, user_dma.page_count); - if (err >= 0) { - for (i = 0; i < err; i++) - put_page(dma->map[i]); - return -EINVAL; - } - return err; - } - - dma->page_count = user_dma.page_count; - - /* Fill SG List with new values */ - if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) { - for (i = 0; i < dma->page_count; i++) { - put_page(dma->map[i]); - } - dma->page_count = 0; - return -ENOMEM; - } - - /* Map SG List */ - dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); - - /* Fill SG Array with new values */ - ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1); - - /* Tag SG Array with Interrupt Bit */ - dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); - - ivtv_udma_sync_for_device(itv); - return dma->page_count; -} - -void ivtv_udma_unmap(struct ivtv *itv) -{ - struct ivtv_user_dma *dma = &itv->udma; - int i; - - IVTV_DEBUG_INFO("ivtv_unmap_user_dma\n"); - - /* Nothing to free */ - if (dma->page_count == 0) - return; - - /* Unmap Scatterlist */ - if (dma->SG_length) { - pci_unmap_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); - dma->SG_length = 0; - } - /* sync DMA */ - ivtv_udma_sync_for_cpu(itv); - - /* Release User Pages */ - for (i = 0; i < dma->page_count; i++) { - put_page(dma->map[i]); - } - dma->page_count = 0; -} - -void ivtv_udma_free(struct ivtv *itv) -{ - int i; - - /* Unmap SG Array */ - if (itv->udma.SG_handle) { - pci_unmap_single(itv->pdev, itv->udma.SG_handle, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); - } - - /* Unmap Scatterlist */ - if (itv->udma.SG_length) { - pci_unmap_sg(itv->pdev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); - } - - for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) { - if (itv->udma.bouncemap[i]) - __free_page(itv->udma.bouncemap[i]); - } -} - -void ivtv_udma_start(struct ivtv *itv) -{ - IVTV_DEBUG_DMA("start UDMA\n"); - write_reg(itv->udma.SG_handle, IVTV_REG_DECDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); - set_bit(IVTV_F_I_DMA, &itv->i_flags); - set_bit(IVTV_F_I_UDMA, &itv->i_flags); - clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags); -} - -void ivtv_udma_prepare(struct ivtv *itv) -{ - unsigned long flags; - - spin_lock_irqsave(&itv->dma_reg_lock, flags); - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) - ivtv_udma_start(itv); - else - set_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags); - spin_unlock_irqrestore(&itv->dma_reg_lock, flags); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-udma.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-udma.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-udma.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-udma.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004 Chris Kennedy - Copyright (C) 2006-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_UDMA_H -#define IVTV_UDMA_H - -/* User DMA functions */ -void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size); -int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset); -void ivtv_udma_fill_sg_array(struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split); -int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, - void __user *userbuf, int size_in_bytes); -void ivtv_udma_unmap(struct ivtv *itv); -void ivtv_udma_free(struct ivtv *itv); -void ivtv_udma_alloc(struct ivtv *itv); -void ivtv_udma_prepare(struct ivtv *itv); -void ivtv_udma_start(struct ivtv *itv); - -static inline void ivtv_udma_sync_for_device(struct ivtv *itv) -{ - pci_dma_sync_single_for_device(itv->pdev, itv->udma.SG_handle, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); -} - -static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv) -{ - pci_dma_sync_single_for_cpu(itv->pdev, itv->udma.SG_handle, - sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-vbi.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,549 +0,0 @@ -/* - Vertical Blank Interval support functions - Copyright (C) 2004-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-i2c.h" -#include "ivtv-ioctl.h" -#include "ivtv-queue.h" -#include "ivtv-cards.h" -#include "ivtv-vbi.h" - -static void ivtv_set_vps(struct ivtv *itv, int enabled) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_VPS; - data.field = 0; - data.line = enabled ? 16 : 0; - data.data[2] = itv->vbi.vps_payload.data[0]; - data.data[8] = itv->vbi.vps_payload.data[1]; - data.data[9] = itv->vbi.vps_payload.data[2]; - data.data[10] = itv->vbi.vps_payload.data[3]; - data.data[11] = itv->vbi.vps_payload.data[4]; - ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data); -} - -static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_CAPTION_525; - data.field = 0; - data.line = (mode & 1) ? 21 : 0; - data.data[0] = cc->odd[0]; - data.data[1] = cc->odd[1]; - ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data); - data.field = 1; - data.line = (mode & 2) ? 21 : 0; - data.data[0] = cc->even[0]; - data.data[1] = cc->even[1]; - ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data); -} - -static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - /* When using a 50 Hz system, always turn on the - wide screen signal with 4x3 ratio as the default. - Turning this signal on and off can confuse certain - TVs. As far as I can tell there is no reason not to - transmit this signal. */ - if ((itv->std & V4L2_STD_625_50) && !enabled) { - enabled = 1; - mode = 0x08; /* 4x3 full format */ - } - data.id = V4L2_SLICED_WSS_625; - data.field = 0; - data.line = enabled ? 23 : 0; - data.data[0] = mode & 0xff; - data.data[1] = (mode >> 8) & 0xff; - ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data); -} - -static int odd_parity(u8 c) -{ - c ^= (c >> 4); - c ^= (c >> 2); - c ^= (c >> 1); - - return c & 1; -} - -static void ivtv_write_vbi_line(struct ivtv *itv, - const struct v4l2_sliced_vbi_data *d, - struct vbi_cc *cc, int *found_cc) -{ - struct vbi_info *vi = &itv->vbi; - - if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { - if (d->field) { - cc->even[0] = d->data[0]; - cc->even[1] = d->data[1]; - } else { - cc->odd[0] = d->data[0]; - cc->odd[1] = d->data[1]; - } - *found_cc = 1; - } else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { - struct vbi_vps vps; - - vps.data[0] = d->data[2]; - vps.data[1] = d->data[8]; - vps.data[2] = d->data[9]; - vps.data[3] = d->data[10]; - vps.data[4] = d->data[11]; - if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) { - vi->vps_payload = vps; - set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); - } - } else if (d->id == V4L2_SLICED_WSS_625 && - d->line == 23 && d->field == 0) { - int wss = d->data[0] | d->data[1] << 8; - - if (vi->wss_payload != wss) { - vi->wss_payload = wss; - set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - } - } -} - -static void ivtv_write_vbi_cc_lines(struct ivtv *itv, const struct vbi_cc *cc) -{ - struct vbi_info *vi = &itv->vbi; - - if (vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) { - memcpy(&vi->cc_payload[vi->cc_payload_idx], cc, - sizeof(struct vbi_cc)); - vi->cc_payload_idx++; - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - } -} - -static void ivtv_write_vbi(struct ivtv *itv, - const struct v4l2_sliced_vbi_data *sliced, - size_t cnt) -{ - struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; - int found_cc = 0; - size_t i; - - for (i = 0; i < cnt; i++) - ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc); - - if (found_cc) - ivtv_write_vbi_cc_lines(itv, &cc); -} - -ssize_t -ivtv_write_vbi_from_user(struct ivtv *itv, - const struct v4l2_sliced_vbi_data __user *sliced, - size_t cnt) -{ - struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; - int found_cc = 0; - size_t i; - struct v4l2_sliced_vbi_data d; - ssize_t ret = cnt * sizeof(struct v4l2_sliced_vbi_data); - - for (i = 0; i < cnt; i++) { - if (copy_from_user(&d, sliced + i, - sizeof(struct v4l2_sliced_vbi_data))) { - ret = -EFAULT; - break; - } - ivtv_write_vbi_line(itv, &d, &cc, &found_cc); - } - - if (found_cc) - ivtv_write_vbi_cc_lines(itv, &cc); - - return ret; -} - -static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp) -{ - int line = 0; - int i; - u32 linemask[2] = { 0, 0 }; - unsigned short size; - static const u8 mpeg_hdr_data[] = { - 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, - 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, - 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, - 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff - }; - const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ - int idx = itv->vbi.frame % IVTV_VBI_FRAMES; - u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0]; - - for (i = 0; i < lines; i++) { - int f, l; - - if (itv->vbi.sliced_data[i].id == 0) - continue; - - l = itv->vbi.sliced_data[i].line - 6; - f = itv->vbi.sliced_data[i].field; - if (f) - l += 18; - if (l < 32) - linemask[0] |= (1 << l); - else - linemask[1] |= (1 << (l - 32)); - dst[sd + 12 + line * 43] = - ivtv_service2vbi(itv->vbi.sliced_data[i].id); - memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42); - line++; - } - memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); - if (line == 36) { - /* All lines are used, so there is no space for the linemask - (the max size of the VBI data is 36 * 43 + 4 bytes). - So in this case we use the magic number 'ITV0'. */ - memcpy(dst + sd, "ITV0", 4); - memcpy(dst + sd + 4, dst + sd + 12, line * 43); - size = 4 + ((43 * line + 3) & ~3); - } else { - memcpy(dst + sd, "itv0", 4); - cpu_to_le32s(&linemask[0]); - cpu_to_le32s(&linemask[1]); - memcpy(dst + sd + 4, &linemask[0], 8); - size = 12 + ((43 * line + 3) & ~3); - } - dst[4+16] = (size + 10) >> 8; - dst[5+16] = (size + 10) & 0xff; - dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); - dst[10+16] = (pts_stamp >> 22) & 0xff; - dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); - dst[12+16] = (pts_stamp >> 7) & 0xff; - dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); - itv->vbi.sliced_mpeg_size[idx] = sd + size; -} - -static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) -{ - u32 linemask[2]; - int i, l, id2; - int line = 0; - - if (!memcmp(p, "itv0", 4)) { - memcpy(linemask, p + 4, 8); - p += 12; - } else if (!memcmp(p, "ITV0", 4)) { - linemask[0] = 0xffffffff; - linemask[1] = 0xf; - p += 4; - } else { - /* unknown VBI data, convert to empty VBI frame */ - linemask[0] = linemask[1] = 0; - } - for (i = 0; i < 36; i++) { - int err = 0; - - if (i < 32 && !(linemask[0] & (1 << i))) - continue; - if (i >= 32 && !(linemask[1] & (1 << (i - 32)))) - continue; - id2 = *p & 0xf; - switch (id2) { - case IVTV_SLICED_TYPE_TELETEXT_B: - id2 = V4L2_SLICED_TELETEXT_B; - break; - case IVTV_SLICED_TYPE_CAPTION_525: - id2 = V4L2_SLICED_CAPTION_525; - err = !odd_parity(p[1]) || !odd_parity(p[2]); - break; - case IVTV_SLICED_TYPE_VPS: - id2 = V4L2_SLICED_VPS; - break; - case IVTV_SLICED_TYPE_WSS_625: - id2 = V4L2_SLICED_WSS_625; - break; - default: - id2 = 0; - break; - } - if (err == 0) { - l = (i < 18) ? i + 6 : i - 18 + 6; - itv->vbi.sliced_dec_data[line].line = l; - itv->vbi.sliced_dec_data[line].field = i >= 18; - itv->vbi.sliced_dec_data[line].id = id2; - memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42); - line++; - } - p += 43; - } - while (line < 36) { - itv->vbi.sliced_dec_data[line].id = 0; - itv->vbi.sliced_dec_data[line].line = 0; - itv->vbi.sliced_dec_data[line].field = 0; - line++; - } - return line * sizeof(itv->vbi.sliced_dec_data[0]); -} - -/* Compress raw VBI format, removes leading SAV codes and surplus space after the - field. - Returns new compressed size. */ -static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size) -{ - u32 line_size = itv->vbi.raw_decoder_line_size; - u32 lines = itv->vbi.count; - u8 sav1 = itv->vbi.raw_decoder_sav_odd_field; - u8 sav2 = itv->vbi.raw_decoder_sav_even_field; - u8 *q = buf; - u8 *p; - int i; - - for (i = 0; i < lines; i++) { - p = buf + i * line_size; - - /* Look for SAV code */ - if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) { - break; - } - memcpy(q, p + 4, line_size - 4); - q += line_size - 4; - } - return lines * (line_size - 4); -} - - -/* Compressed VBI format, all found sliced blocks put next to one another - Returns new compressed size */ -static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav) -{ - u32 line_size = itv->vbi.sliced_decoder_line_size; - struct v4l2_decode_vbi_line vbi; - int i; - unsigned lines = 0; - - /* find the first valid line */ - for (i = 0; i < size; i++, buf++) { - if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) - break; - } - - size -= i; - if (size < line_size) { - return line; - } - for (i = 0; i < size / line_size; i++) { - u8 *p = buf + i * line_size; - - /* Look for SAV code */ - if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) { - continue; - } - vbi.p = p + 4; - v4l2_subdev_call(itv->sd_video, vbi, decode_vbi_line, &vbi); - if (vbi.type && !(lines & (1 << vbi.line))) { - lines |= 1 << vbi.line; - itv->vbi.sliced_data[line].id = vbi.type; - itv->vbi.sliced_data[line].field = vbi.is_second_field; - itv->vbi.sliced_data[line].line = vbi.line; - memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42); - line++; - } - } - return line; -} - -void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, - u64 pts_stamp, int streamtype) -{ - u8 *p = (u8 *) buf->buf; - u32 size = buf->bytesused; - int y; - - /* Raw VBI data */ - if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && ivtv_raw_vbi(itv)) { - u8 type; - - ivtv_buf_swap(buf); - - type = p[3]; - - size = buf->bytesused = compress_raw_buf(itv, p, size); - - /* second field of the frame? */ - if (type == itv->vbi.raw_decoder_sav_even_field) { - /* Dirty hack needed for backwards - compatibility of old VBI software. */ - p += size - 4; - memcpy(p, &itv->vbi.frame, 4); - itv->vbi.frame++; - } - return; - } - - /* Sliced VBI data with data insertion */ - if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) { - int lines; - - ivtv_buf_swap(buf); - - /* first field */ - lines = compress_sliced_buf(itv, 0, p, size / 2, - itv->vbi.sliced_decoder_sav_odd_field); - /* second field */ - /* experimentation shows that the second half does not always begin - at the exact address. So start a bit earlier (hence 32). */ - lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32, - itv->vbi.sliced_decoder_sav_even_field); - /* always return at least one empty line */ - if (lines == 0) { - itv->vbi.sliced_data[0].id = 0; - itv->vbi.sliced_data[0].line = 0; - itv->vbi.sliced_data[0].field = 0; - lines = 1; - } - buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]); - memcpy(p, &itv->vbi.sliced_data[0], size); - - if (itv->vbi.insert_mpeg) { - copy_vbi_data(itv, lines, pts_stamp); - } - itv->vbi.frame++; - return; - } - - /* Sliced VBI re-inserted from an MPEG stream */ - if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { - /* If the size is not 4-byte aligned, then the starting address - for the swapping is also shifted. After swapping the data the - real start address of the VBI data is exactly 4 bytes after the - original start. It's a bit fiddly but it works like a charm. - Non-4-byte alignment happens when an lseek is done on the input - mpeg file to a non-4-byte aligned position. So on arrival here - the VBI data is also non-4-byte aligned. */ - int offset = size & 3; - int cnt; - - if (offset) { - p += 4 - offset; - } - /* Swap Buffer */ - for (y = 0; y < size; y += 4) { - swab32s((u32 *)(p + y)); - } - - cnt = ivtv_convert_ivtv_vbi(itv, p + offset); - memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); - buf->bytesused = cnt; - - ivtv_write_vbi(itv, itv->vbi.sliced_dec_data, - cnt / sizeof(itv->vbi.sliced_dec_data[0])); - return; - } -} - -void ivtv_disable_cc(struct ivtv *itv) -{ - struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; - - clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - ivtv_set_cc(itv, 0, &cc); - itv->vbi.cc_payload_idx = 0; -} - - -void ivtv_vbi_work_handler(struct ivtv *itv) -{ - struct vbi_info *vi = &itv->vbi; - struct v4l2_sliced_vbi_data data; - struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; - - /* Lock */ - if (itv->output_mode == OUT_PASSTHROUGH) { - if (itv->is_50hz) { - data.id = V4L2_SLICED_WSS_625; - data.field = 0; - - if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) { - ivtv_set_wss(itv, 1, data.data[0] & 0xf); - vi->wss_missing_cnt = 0; - } else if (vi->wss_missing_cnt == 4) { - ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ - } else { - vi->wss_missing_cnt++; - } - } - else { - int mode = 0; - - data.id = V4L2_SLICED_CAPTION_525; - data.field = 0; - if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) { - mode |= 1; - cc.odd[0] = data.data[0]; - cc.odd[1] = data.data[1]; - } - data.field = 1; - if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) { - mode |= 2; - cc.even[0] = data.data[0]; - cc.even[1] = data.data[1]; - } - if (mode) { - vi->cc_missing_cnt = 0; - ivtv_set_cc(itv, mode, &cc); - } else if (vi->cc_missing_cnt == 4) { - ivtv_set_cc(itv, 0, &cc); - } else { - vi->cc_missing_cnt++; - } - } - return; - } - - if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { - ivtv_set_wss(itv, 1, vi->wss_payload & 0xf); - } - - if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { - if (vi->cc_payload_idx == 0) { - clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - ivtv_set_cc(itv, 3, &cc); - } - while (vi->cc_payload_idx) { - cc = vi->cc_payload[0]; - - memcpy(vi->cc_payload, vi->cc_payload + 1, - sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0])); - vi->cc_payload_idx--; - if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80) - continue; - - ivtv_set_cc(itv, 3, &cc); - break; - } - } - - if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { - ivtv_set_vps(itv, 1); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-vbi.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-vbi.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-vbi.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-vbi.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - Vertical Blank Interval support functions - Copyright (C) 2004-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_VBI_H -#define IVTV_VBI_H - -ssize_t -ivtv_write_vbi_from_user(struct ivtv *itv, - const struct v4l2_sliced_vbi_data __user *sliced, - size_t count); -void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, - u64 pts_stamp, int streamtype); -int ivtv_used_line(struct ivtv *itv, int line, int field); -void ivtv_disable_cc(struct ivtv *itv); -void ivtv_set_vbi(unsigned long arg); -void ivtv_vbi_work_handler(struct ivtv *itv); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-version.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-version.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-version.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-version.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* - ivtv driver version information - Copyright (C) 2005-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_VERSION_H -#define IVTV_VERSION_H - -#define IVTV_DRIVER_NAME "ivtv" -#define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 4 -#define IVTV_DRIVER_VERSION_PATCHLEVEL 2 - -#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) -#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-yuv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-yuv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-yuv.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-yuv.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1280 +0,0 @@ -/* - yuv support - - Copyright (C) 2007 Ian Armstrong - - 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, or - (at your option) any later version. - - 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 "ivtv-driver.h" -#include "ivtv-udma.h" -#include "ivtv-yuv.h" - -/* YUV buffer offsets */ -const u32 yuv_offset[IVTV_YUV_BUFFERS] = { - 0x001a8600, - 0x00240400, - 0x002d8200, - 0x00370000, - 0x00029000, - 0x000C0E00, - 0x006B0400, - 0x00748200 -}; - -static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, - struct ivtv_dma_frame *args) -{ - struct ivtv_dma_page_info y_dma; - struct ivtv_dma_page_info uv_dma; - struct yuv_playback_info *yi = &itv->yuv_info; - u8 frame = yi->draw_frame; - struct yuv_frame_info *f = &yi->new_frame_info[frame]; - int i; - int y_pages, uv_pages; - unsigned long y_buffer_offset, uv_buffer_offset; - int y_decode_height, uv_decode_height, y_size; - - y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; - uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; - - y_decode_height = uv_decode_height = f->src_h + f->src_y; - - if (f->offset_y) - y_buffer_offset += 720 * 16; - - if (y_decode_height & 15) - y_decode_height = (y_decode_height + 16) & ~15; - - if (uv_decode_height & 31) - uv_decode_height = (uv_decode_height + 32) & ~31; - - y_size = 720 * y_decode_height; - - /* Still in USE */ - if (dma->SG_length || dma->page_count) { - IVTV_DEBUG_WARN - ("prep_user_dma: SG_length %d page_count %d still full?\n", - dma->SG_length, dma->page_count); - return -EBUSY; - } - - ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height); - ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height); - - /* Get user pages for DMA Xfer */ - down_read(¤t->mm->mmap_sem); - y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL); - uv_pages = 0; /* silence gcc. value is set and consumed only if: */ - if (y_pages == y_dma.page_count) { - uv_pages = get_user_pages(current, current->mm, - uv_dma.uaddr, uv_dma.page_count, 0, 1, - &dma->map[y_pages], NULL); - } - up_read(¤t->mm->mmap_sem); - - if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) { - int rc = -EFAULT; - - if (y_pages == y_dma.page_count) { - IVTV_DEBUG_WARN - ("failed to map uv user pages, returned %d " - "expecting %d\n", uv_pages, uv_dma.page_count); - - if (uv_pages >= 0) { - for (i = 0; i < uv_pages; i++) - put_page(dma->map[y_pages + i]); - rc = -EFAULT; - } else { - rc = uv_pages; - } - } else { - IVTV_DEBUG_WARN - ("failed to map y user pages, returned %d " - "expecting %d\n", y_pages, y_dma.page_count); - } - if (y_pages >= 0) { - for (i = 0; i < y_pages; i++) - put_page(dma->map[i]); - /* - * Inherit the -EFAULT from rc's - * initialization, but allow it to be - * overriden by uv_pages above if it was an - * actual errno. - */ - } else { - rc = y_pages; - } - return rc; - } - - dma->page_count = y_pages + uv_pages; - - /* Fill & map SG List */ - if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) { - IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); - for (i = 0; i < dma->page_count; i++) { - put_page(dma->map[i]); - } - dma->page_count = 0; - return -ENOMEM; - } - dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); - - /* Fill SG Array with new values */ - ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); - - /* If we've offset the y plane, ensure top area is blanked */ - if (f->offset_y && yi->blanking_dmaptr) { - dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); - dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr); - dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); - dma->SG_length++; - } - - /* Tag SG Array with Interrupt Bit */ - dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); - - ivtv_udma_sync_for_device(itv); - return 0; -} - -/* We rely on a table held in the firmware - Quick check. */ -int ivtv_yuv_filter_check(struct ivtv *itv) -{ - int i, y, uv; - - for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) { - if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) || - (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) { - IVTV_WARN ("YUV filter table not found in firmware.\n"); - return -1; - } - } - return 0; -} - -static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2) -{ - u32 i, line; - - /* If any filter is -1, then don't update it */ - if (h_filter > -1) { - if (h_filter > 4) - h_filter = 4; - i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384); - for (line = 0; line < 16; line++) { - write_reg(read_dec(i), 0x02804); - write_reg(read_dec(i), 0x0281c); - i += 4; - write_reg(read_dec(i), 0x02808); - write_reg(read_dec(i), 0x02820); - i += 4; - write_reg(read_dec(i), 0x0280c); - write_reg(read_dec(i), 0x02824); - i += 4; - write_reg(read_dec(i), 0x02810); - write_reg(read_dec(i), 0x02828); - i += 4; - write_reg(read_dec(i), 0x02814); - write_reg(read_dec(i), 0x0282c); - i += 8; - write_reg(0, 0x02818); - write_reg(0, 0x02830); - } - IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter); - } - - if (v_filter_1 > -1) { - if (v_filter_1 > 4) - v_filter_1 = 4; - i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192); - for (line = 0; line < 16; line++) { - write_reg(read_dec(i), 0x02900); - i += 4; - write_reg(read_dec(i), 0x02904); - i += 8; - write_reg(0, 0x02908); - } - IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1); - } - - if (v_filter_2 > -1) { - if (v_filter_2 > 4) - v_filter_2 = 4; - i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192); - for (line = 0; line < 16; line++) { - write_reg(read_dec(i), 0x0290c); - i += 4; - write_reg(read_dec(i), 0x02910); - i += 8; - write_reg(0, 0x02914); - } - IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2); - } -} - -static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - u32 reg_2834, reg_2838, reg_283c; - u32 reg_2844, reg_2854, reg_285c; - u32 reg_2864, reg_2874, reg_2890; - u32 reg_2870, reg_2870_base, reg_2870_offset; - int x_cutoff; - int h_filter; - u32 master_width; - - IVTV_DEBUG_WARN - ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", - f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x); - - /* How wide is the src image */ - x_cutoff = f->src_w + f->src_x; - - /* Set the display width */ - reg_2834 = f->dst_w; - reg_2838 = reg_2834; - - /* Set the display position */ - reg_2890 = f->dst_x; - - /* Index into the image horizontally */ - reg_2870 = 0; - - /* 2870 is normally fudged to align video coords with osd coords. - If running full screen, it causes an unwanted left shift - Remove the fudge if we almost fill the screen. - Gradually adjust the offset to avoid the video 'snapping' - left/right if it gets dragged through this region. - Only do this if osd is full width. */ - if (f->vis_w == 720) { - if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680)) - reg_2870 = 10 - (f->tru_x - f->pan_x) / 4; - else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660)) - reg_2870 = (10 + (f->tru_x - f->pan_x) / 2); - - if (f->dst_w >= f->src_w) - reg_2870 = reg_2870 << 16 | reg_2870; - else - reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1); - } - - if (f->dst_w < f->src_w) - reg_2870 = 0x000d000e - reg_2870; - else - reg_2870 = 0x0012000e - reg_2870; - - /* We're also using 2870 to shift the image left (src_x & negative dst_x) */ - reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19; - - if (f->dst_w >= f->src_w) { - x_cutoff &= ~1; - master_width = (f->src_w * 0x00200000) / (f->dst_w); - if (master_width * f->dst_w != f->src_w * 0x00200000) - master_width++; - reg_2834 = (reg_2834 << 16) | x_cutoff; - reg_2838 = (reg_2838 << 16) | x_cutoff; - reg_283c = master_width >> 2; - reg_2844 = master_width >> 2; - reg_2854 = master_width; - reg_285c = master_width >> 1; - reg_2864 = master_width >> 1; - - /* We also need to factor in the scaling - (src_w - dst_w) / (src_w / 4) */ - if (f->dst_w > f->src_w) - reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14); - else - reg_2870_base = 0; - - reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base); - reg_2874 = 0; - } else if (f->dst_w < f->src_w / 2) { - master_width = (f->src_w * 0x00080000) / f->dst_w; - if (master_width * f->dst_w != f->src_w * 0x00080000) - master_width++; - reg_2834 = (reg_2834 << 16) | x_cutoff; - reg_2838 = (reg_2838 << 16) | x_cutoff; - reg_283c = master_width >> 2; - reg_2844 = master_width >> 1; - reg_2854 = master_width; - reg_285c = master_width >> 1; - reg_2864 = master_width >> 1; - reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset; - reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16; - reg_2874 = 0x00000012; - } else { - master_width = (f->src_w * 0x00100000) / f->dst_w; - if (master_width * f->dst_w != f->src_w * 0x00100000) - master_width++; - reg_2834 = (reg_2834 << 16) | x_cutoff; - reg_2838 = (reg_2838 << 16) | x_cutoff; - reg_283c = master_width >> 2; - reg_2844 = master_width >> 1; - reg_2854 = master_width; - reg_285c = master_width >> 1; - reg_2864 = master_width >> 1; - reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1; - reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16; - reg_2874 = 0x00000001; - } - - /* Select the horizontal filter */ - if (f->src_w == f->dst_w) { - /* An exact size match uses filter 0 */ - h_filter = 0; - } else { - /* Figure out which filter to use */ - h_filter = ((f->src_w << 16) / f->dst_w) >> 15; - h_filter = (h_filter >> 1) + (h_filter & 1); - /* Only an exact size match can use filter 0 */ - h_filter += !h_filter; - } - - write_reg(reg_2834, 0x02834); - write_reg(reg_2838, 0x02838); - IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n", - yi->reg_2834, reg_2834, yi->reg_2838, reg_2838); - - write_reg(reg_283c, 0x0283c); - write_reg(reg_2844, 0x02844); - - IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n", - yi->reg_283c, reg_283c, yi->reg_2844, reg_2844); - - write_reg(0x00080514, 0x02840); - write_reg(0x00100514, 0x02848); - IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n", - yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514); - - write_reg(reg_2854, 0x02854); - IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n", - yi->reg_2854, reg_2854); - - write_reg(reg_285c, 0x0285c); - write_reg(reg_2864, 0x02864); - IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n", - yi->reg_285c, reg_285c, yi->reg_2864, reg_2864); - - write_reg(reg_2874, 0x02874); - IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n", - yi->reg_2874, reg_2874); - - write_reg(reg_2870, 0x02870); - IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n", - yi->reg_2870, reg_2870); - - write_reg(reg_2890, 0x02890); - IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n", - yi->reg_2890, reg_2890); - - /* Only update the filter if we really need to */ - if (h_filter != yi->h_filter) { - ivtv_yuv_filter(itv, h_filter, -1, -1); - yi->h_filter = h_filter; - } -} - -static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - u32 master_height; - u32 reg_2918, reg_291c, reg_2920, reg_2928; - u32 reg_2930, reg_2934, reg_293c; - u32 reg_2940, reg_2944, reg_294c; - u32 reg_2950, reg_2954, reg_2958, reg_295c; - u32 reg_2960, reg_2964, reg_2968, reg_296c; - u32 reg_289c; - u32 src_major_y, src_minor_y; - u32 src_major_uv, src_minor_uv; - u32 reg_2964_base, reg_2968_base; - int v_filter_1, v_filter_2; - - IVTV_DEBUG_WARN - ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", - f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y); - - /* What scaling mode is being used... */ - IVTV_DEBUG_YUV("Scaling mode Y: %s\n", - f->interlaced_y ? "Interlaced" : "Progressive"); - - IVTV_DEBUG_YUV("Scaling mode UV: %s\n", - f->interlaced_uv ? "Interlaced" : "Progressive"); - - /* What is the source video being treated as... */ - IVTV_DEBUG_WARN("Source video: %s\n", - f->interlaced ? "Interlaced" : "Progressive"); - - /* We offset into the image using two different index methods, so split - the y source coord into two parts. */ - if (f->src_y < 8) { - src_minor_uv = f->src_y; - src_major_uv = 0; - } else { - src_minor_uv = 8; - src_major_uv = f->src_y - 8; - } - - src_minor_y = src_minor_uv; - src_major_y = src_major_uv; - - if (f->offset_y) - src_minor_y += 16; - - if (f->interlaced_y) - reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y); - else - reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1); - - if (f->interlaced_uv) - reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1); - else - reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv); - - reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14; - reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14; - - if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) { - master_height = (f->src_h * 0x00400000) / f->dst_h; - if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2) - master_height++; - reg_2920 = master_height >> 2; - reg_2928 = master_height >> 3; - reg_2930 = master_height; - reg_2940 = master_height >> 1; - reg_2964_base >>= 3; - reg_2968_base >>= 3; - reg_296c = 0x00000000; - } else if (f->dst_h >= f->src_h) { - master_height = (f->src_h * 0x00400000) / f->dst_h; - master_height = (master_height >> 1) + (master_height & 1); - reg_2920 = master_height >> 2; - reg_2928 = master_height >> 2; - reg_2930 = master_height; - reg_2940 = master_height >> 1; - reg_296c = 0x00000000; - if (f->interlaced_y) { - reg_2964_base >>= 3; - } else { - reg_296c++; - reg_2964_base >>= 2; - } - if (f->interlaced_uv) - reg_2928 >>= 1; - reg_2968_base >>= 3; - } else if (f->dst_h >= f->src_h / 2) { - master_height = (f->src_h * 0x00200000) / f->dst_h; - master_height = (master_height >> 1) + (master_height & 1); - reg_2920 = master_height >> 2; - reg_2928 = master_height >> 2; - reg_2930 = master_height; - reg_2940 = master_height; - reg_296c = 0x00000101; - if (f->interlaced_y) { - reg_2964_base >>= 2; - } else { - reg_296c++; - reg_2964_base >>= 1; - } - if (f->interlaced_uv) - reg_2928 >>= 1; - reg_2968_base >>= 2; - } else { - master_height = (f->src_h * 0x00100000) / f->dst_h; - master_height = (master_height >> 1) + (master_height & 1); - reg_2920 = master_height >> 2; - reg_2928 = master_height >> 2; - reg_2930 = master_height; - reg_2940 = master_height; - reg_2964_base >>= 1; - reg_2968_base >>= 2; - reg_296c = 0x00000102; - } - - /* FIXME These registers change depending on scaled / unscaled output - We really need to work out what they should be */ - if (f->src_h == f->dst_h) { - reg_2934 = 0x00020000; - reg_293c = 0x00100000; - reg_2944 = 0x00040000; - reg_294c = 0x000b0000; - } else { - reg_2934 = 0x00000FF0; - reg_293c = 0x00000FF0; - reg_2944 = 0x00000FF0; - reg_294c = 0x00000FF0; - } - - /* The first line to be displayed */ - reg_2950 = 0x00010000 + src_major_y; - if (f->interlaced_y) - reg_2950 += 0x00010000; - reg_2954 = reg_2950 + 1; - - reg_2958 = 0x00010000 + (src_major_y >> 1); - if (f->interlaced_uv) - reg_2958 += 0x00010000; - reg_295c = reg_2958 + 1; - - if (yi->decode_height == 480) - reg_289c = 0x011e0017; - else - reg_289c = 0x01500017; - - if (f->dst_y < 0) - reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1); - else - reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1); - - /* How much of the source to decode. - Take into account the source offset */ - reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) | - (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15); - - /* Calculate correct value for register 2964 */ - if (f->src_h == f->dst_h) { - reg_2964 = 1; - } else { - reg_2964 = 2 + ((f->dst_h << 1) / f->src_h); - reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1); - } - reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1); - reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94); - - /* Okay, we've wasted time working out the correct value, - but if we use it, it fouls the the window alignment. - Fudge it to what we want... */ - reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16)); - reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16)); - - /* Deviate further from what it should be. I find the flicker headache - inducing so try to reduce it slightly. Leave 2968 as-is otherwise - colours foul. */ - if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h)) - reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2); - - if (!f->interlaced_y) - reg_2964 -= 0x00010001; - if (!f->interlaced_uv) - reg_2968 -= 0x00010001; - - reg_2964 += ((reg_2964_base << 16) | reg_2964_base); - reg_2968 += ((reg_2968_base << 16) | reg_2968_base); - - /* Select the vertical filter */ - if (f->src_h == f->dst_h) { - /* An exact size match uses filter 0/1 */ - v_filter_1 = 0; - v_filter_2 = 1; - } else { - /* Figure out which filter to use */ - v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15; - v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); - /* Only an exact size match can use filter 0 */ - v_filter_1 += !v_filter_1; - v_filter_2 = v_filter_1; - } - - write_reg(reg_2934, 0x02934); - write_reg(reg_293c, 0x0293c); - IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n", - yi->reg_2934, reg_2934, yi->reg_293c, reg_293c); - write_reg(reg_2944, 0x02944); - write_reg(reg_294c, 0x0294c); - IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n", - yi->reg_2944, reg_2944, yi->reg_294c, reg_294c); - - /* Ensure 2970 is 0 (does it ever change ?) */ -/* write_reg(0,0x02970); */ -/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */ - - write_reg(reg_2930, 0x02938); - write_reg(reg_2930, 0x02930); - IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n", - yi->reg_2930, reg_2930, yi->reg_2938, reg_2930); - - write_reg(reg_2928, 0x02928); - write_reg(reg_2928 + 0x514, 0x0292C); - IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n", - yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514); - - write_reg(reg_2920, 0x02920); - write_reg(reg_2920 + 0x514, 0x02924); - IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n", - yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514); - - write_reg(reg_2918, 0x02918); - write_reg(reg_291c, 0x0291C); - IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n", - yi->reg_2918, reg_2918, yi->reg_291c, reg_291c); - - write_reg(reg_296c, 0x0296c); - IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n", - yi->reg_296c, reg_296c); - - write_reg(reg_2940, 0x02948); - write_reg(reg_2940, 0x02940); - IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n", - yi->reg_2940, reg_2940, yi->reg_2948, reg_2940); - - write_reg(reg_2950, 0x02950); - write_reg(reg_2954, 0x02954); - IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n", - yi->reg_2950, reg_2950, yi->reg_2954, reg_2954); - - write_reg(reg_2958, 0x02958); - write_reg(reg_295c, 0x0295C); - IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n", - yi->reg_2958, reg_2958, yi->reg_295c, reg_295c); - - write_reg(reg_2960, 0x02960); - IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n", - yi->reg_2960, reg_2960); - - write_reg(reg_2964, 0x02964); - write_reg(reg_2968, 0x02968); - IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n", - yi->reg_2964, reg_2964, yi->reg_2968, reg_2968); - - write_reg(reg_289c, 0x0289c); - IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n", - yi->reg_289c, reg_289c); - - /* Only update filter 1 if we really need to */ - if (v_filter_1 != yi->v_filter_1) { - ivtv_yuv_filter(itv, -1, v_filter_1, -1); - yi->v_filter_1 = v_filter_1; - } - - /* Only update filter 2 if we really need to */ - if (v_filter_2 != yi->v_filter_2) { - ivtv_yuv_filter(itv, -1, -1, v_filter_2); - yi->v_filter_2 = v_filter_2; - } -} - -/* Modify the supplied coordinate information to fit the visible osd area */ -static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) -{ - struct yuv_frame_info *of = &itv->yuv_info.old_frame_info; - int osd_crop; - u32 osd_scale; - u32 yuv_update = 0; - - /* Sorry, but no negative coords for src */ - if (f->src_x < 0) - f->src_x = 0; - if (f->src_y < 0) - f->src_y = 0; - - /* Can only reduce width down to 1/4 original size */ - if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) { - f->src_x += osd_crop / 2; - f->src_w = (f->src_w - osd_crop) & ~3; - f->dst_w = f->src_w / 4; - f->dst_w += f->dst_w & 1; - } - - /* Can only reduce height down to 1/4 original size */ - if (f->src_h / f->dst_h >= 2) { - /* Overflow may be because we're running progressive, - so force mode switch */ - f->interlaced_y = 1; - /* Make sure we're still within limits for interlace */ - if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) { - /* If we reach here we'll have to force the height. */ - f->src_y += osd_crop / 2; - f->src_h = (f->src_h - osd_crop) & ~3; - f->dst_h = f->src_h / 4; - f->dst_h += f->dst_h & 1; - } - } - - /* If there's nothing to safe to display, we may as well stop now */ - if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || - (int)f->src_w <= 2 || (int)f->src_h <= 2) { - return IVTV_YUV_UPDATE_INVALID; - } - - /* Ensure video remains inside OSD area */ - osd_scale = (f->src_h << 16) / f->dst_h; - - if ((osd_crop = f->pan_y - f->dst_y) > 0) { - /* Falls off the upper edge - crop */ - f->src_y += (osd_scale * osd_crop) >> 16; - f->src_h -= (osd_scale * osd_crop) >> 16; - f->dst_h -= osd_crop; - f->dst_y = 0; - } else { - f->dst_y -= f->pan_y; - } - - if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) { - /* Falls off the lower edge - crop */ - f->dst_h -= osd_crop; - f->src_h -= (osd_scale * osd_crop) >> 16; - } - - osd_scale = (f->src_w << 16) / f->dst_w; - - if ((osd_crop = f->pan_x - f->dst_x) > 0) { - /* Fall off the left edge - crop */ - f->src_x += (osd_scale * osd_crop) >> 16; - f->src_w -= (osd_scale * osd_crop) >> 16; - f->dst_w -= osd_crop; - f->dst_x = 0; - } else { - f->dst_x -= f->pan_x; - } - - if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) { - /* Falls off the right edge - crop */ - f->dst_w -= osd_crop; - f->src_w -= (osd_scale * osd_crop) >> 16; - } - - if (itv->yuv_info.track_osd) { - /* The OSD can be moved. Track to it */ - f->dst_x += itv->yuv_info.osd_x_offset; - f->dst_y += itv->yuv_info.osd_y_offset; - } - - /* Width & height for both src & dst must be even. - Same for coordinates. */ - f->dst_w &= ~1; - f->dst_x &= ~1; - - f->src_w += f->src_x & 1; - f->src_x &= ~1; - - f->src_w &= ~1; - f->dst_w &= ~1; - - f->dst_h &= ~1; - f->dst_y &= ~1; - - f->src_h += f->src_y & 1; - f->src_y &= ~1; - - f->src_h &= ~1; - f->dst_h &= ~1; - - /* Due to rounding, we may have reduced the output size to <1/4 of - the source. Check again, but this time just resize. Don't change - source coordinates */ - if (f->dst_w < f->src_w / 4) { - f->src_w &= ~3; - f->dst_w = f->src_w / 4; - f->dst_w += f->dst_w & 1; - } - if (f->dst_h < f->src_h / 4) { - f->src_h &= ~3; - f->dst_h = f->src_h / 4; - f->dst_h += f->dst_h & 1; - } - - /* Check again. If there's nothing to safe to display, stop now */ - if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || - (int)f->src_w <= 2 || (int)f->src_h <= 2) { - return IVTV_YUV_UPDATE_INVALID; - } - - /* Both x offset & width are linked, so they have to be done together */ - if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) || - (of->dst_x != f->dst_x) || (of->src_x != f->src_x) || - (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) { - yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; - } - - if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) || - (of->dst_y != f->dst_y) || (of->src_y != f->src_y) || - (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) || - (of->lace_mode != f->lace_mode) || - (of->interlaced_y != f->interlaced_y) || - (of->interlaced_uv != f->interlaced_uv)) { - yuv_update |= IVTV_YUV_UPDATE_VERTICAL; - } - - return yuv_update; -} - -/* Update the scaling register to the requested value */ -void ivtv_yuv_work_handler(struct ivtv *itv) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - struct yuv_frame_info f; - int frame = yi->update_frame; - u32 yuv_update; - - IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame); - f = yi->new_frame_info[frame]; - - if (yi->track_osd) { - /* Snapshot the osd pan info */ - f.pan_x = yi->osd_x_pan; - f.pan_y = yi->osd_y_pan; - f.vis_w = yi->osd_vis_w; - f.vis_h = yi->osd_vis_h; - } else { - /* Not tracking the osd, so assume full screen */ - f.pan_x = 0; - f.pan_y = 0; - f.vis_w = 720; - f.vis_h = yi->decode_height; - } - - /* Calculate the display window coordinates. Exit if nothing left */ - if (!(yuv_update = ivtv_yuv_window_setup(itv, &f))) - return; - - if (yuv_update & IVTV_YUV_UPDATE_INVALID) { - write_reg(0x01008080, 0x2898); - } else if (yuv_update) { - write_reg(0x00108080, 0x2898); - - if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) - ivtv_yuv_handle_horizontal(itv, &f); - - if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) - ivtv_yuv_handle_vertical(itv, &f); - } - yi->old_frame_info = f; -} - -static void ivtv_yuv_init(struct ivtv *itv) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - - IVTV_DEBUG_YUV("ivtv_yuv_init\n"); - - /* Take a snapshot of the current register settings */ - yi->reg_2834 = read_reg(0x02834); - yi->reg_2838 = read_reg(0x02838); - yi->reg_283c = read_reg(0x0283c); - yi->reg_2840 = read_reg(0x02840); - yi->reg_2844 = read_reg(0x02844); - yi->reg_2848 = read_reg(0x02848); - yi->reg_2854 = read_reg(0x02854); - yi->reg_285c = read_reg(0x0285c); - yi->reg_2864 = read_reg(0x02864); - yi->reg_2870 = read_reg(0x02870); - yi->reg_2874 = read_reg(0x02874); - yi->reg_2898 = read_reg(0x02898); - yi->reg_2890 = read_reg(0x02890); - - yi->reg_289c = read_reg(0x0289c); - yi->reg_2918 = read_reg(0x02918); - yi->reg_291c = read_reg(0x0291c); - yi->reg_2920 = read_reg(0x02920); - yi->reg_2924 = read_reg(0x02924); - yi->reg_2928 = read_reg(0x02928); - yi->reg_292c = read_reg(0x0292c); - yi->reg_2930 = read_reg(0x02930); - yi->reg_2934 = read_reg(0x02934); - yi->reg_2938 = read_reg(0x02938); - yi->reg_293c = read_reg(0x0293c); - yi->reg_2940 = read_reg(0x02940); - yi->reg_2944 = read_reg(0x02944); - yi->reg_2948 = read_reg(0x02948); - yi->reg_294c = read_reg(0x0294c); - yi->reg_2950 = read_reg(0x02950); - yi->reg_2954 = read_reg(0x02954); - yi->reg_2958 = read_reg(0x02958); - yi->reg_295c = read_reg(0x0295c); - yi->reg_2960 = read_reg(0x02960); - yi->reg_2964 = read_reg(0x02964); - yi->reg_2968 = read_reg(0x02968); - yi->reg_296c = read_reg(0x0296c); - yi->reg_2970 = read_reg(0x02970); - - yi->v_filter_1 = -1; - yi->v_filter_2 = -1; - yi->h_filter = -1; - - /* Set some valid size info */ - yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF; - yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF; - - /* Bit 2 of reg 2878 indicates current decoder output format - 0 : NTSC 1 : PAL */ - if (read_reg(0x2878) & 4) - yi->decode_height = 576; - else - yi->decode_height = 480; - - if (!itv->osd_info) { - yi->osd_vis_w = 720 - yi->osd_x_offset; - yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; - } else { - /* If no visible size set, assume full size */ - if (!yi->osd_vis_w) - yi->osd_vis_w = 720 - yi->osd_x_offset; - - if (!yi->osd_vis_h) { - yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; - } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { - /* If output video standard has changed, requested height may - not be legal */ - IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", - yi->osd_vis_h + yi->osd_y_offset, - yi->decode_height); - yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; - } - } - - /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ - yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN); - if (yi->blanking_ptr) { - yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); - } else { - yi->blanking_dmaptr = 0; - IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); - } - - /* Enable YUV decoder output */ - write_reg_sync(0x01, IVTV_REG_VDM); - - set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); - atomic_set(&yi->next_dma_frame, 0); -} - -/* Get next available yuv buffer on PVR350 */ -static void ivtv_yuv_next_free(struct ivtv *itv) -{ - int draw, display; - struct yuv_playback_info *yi = &itv->yuv_info; - - if (atomic_read(&yi->next_dma_frame) == -1) - ivtv_yuv_init(itv); - - draw = atomic_read(&yi->next_fill_frame); - display = atomic_read(&yi->next_dma_frame); - - if (display > draw) - display -= IVTV_YUV_BUFFERS; - - if (draw - display >= yi->max_frames_buffered) - draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS; - else - yi->new_frame_info[draw].update = 0; - - yi->draw_frame = draw; -} - -/* Set up frame according to ivtv_dma_frame parameters */ -static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - u8 frame = yi->draw_frame; - u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS; - struct yuv_frame_info *nf = &yi->new_frame_info[frame]; - struct yuv_frame_info *of = &yi->new_frame_info[last_frame]; - int lace_threshold = yi->lace_threshold; - - /* Preserve old update flag in case we're overwriting a queued frame */ - int update = nf->update; - - /* Take a snapshot of the yuv coordinate information */ - nf->src_x = args->src.left; - nf->src_y = args->src.top; - nf->src_w = args->src.width; - nf->src_h = args->src.height; - nf->dst_x = args->dst.left; - nf->dst_y = args->dst.top; - nf->dst_w = args->dst.width; - nf->dst_h = args->dst.height; - nf->tru_x = args->dst.left; - nf->tru_w = args->src_width; - nf->tru_h = args->src_height; - - /* Are we going to offset the Y plane */ - nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0; - - nf->update = 0; - nf->interlaced_y = 0; - nf->interlaced_uv = 0; - nf->delay = 0; - nf->sync_field = 0; - nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK; - - if (lace_threshold < 0) - lace_threshold = yi->decode_height - 1; - - /* Work out the lace settings */ - switch (nf->lace_mode) { - case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ - nf->interlaced = 0; - if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021)) - nf->interlaced_y = 0; - else - nf->interlaced_y = 1; - - if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) - nf->interlaced_uv = 0; - else - nf->interlaced_uv = 1; - break; - - case IVTV_YUV_MODE_AUTO: - if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) { - nf->interlaced = 0; - if ((nf->tru_h < 512) || - (nf->tru_h > 576 && nf->tru_h < 1021) || - (nf->tru_w > 720 && nf->tru_h < 1021)) - nf->interlaced_y = 0; - else - nf->interlaced_y = 1; - if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) - nf->interlaced_uv = 0; - else - nf->interlaced_uv = 1; - } else { - nf->interlaced = 1; - nf->interlaced_y = 1; - nf->interlaced_uv = 1; - } - break; - - case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ - default: - nf->interlaced = 1; - nf->interlaced_y = 1; - nf->interlaced_uv = 1; - break; - } - - if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) { - yi->old_frame_info_args = *nf; - nf->update = 1; - IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame); - } - - nf->update |= update; - nf->sync_field = yi->lace_sync_field; - nf->delay = nf->sync_field != of->sync_field; -} - -/* Frame is complete & ready for display */ -void ivtv_yuv_frame_complete(struct ivtv *itv) -{ - atomic_set(&itv->yuv_info.next_fill_frame, - (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS); -} - -static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args) -{ - DEFINE_WAIT(wait); - int rc = 0; - int got_sig = 0; - /* DMA the frame */ - mutex_lock(&itv->udma.lock); - - if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) { - mutex_unlock(&itv->udma.lock); - return rc; - } - - ivtv_udma_prepare(itv); - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); - /* if no UDMA is pending and no UDMA is in progress, then the DMA - is finished */ - while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) || - test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - /* don't interrupt if the DMA is in progress but break off - a still pending DMA. */ - got_sig = signal_pending(current); - if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) - break; - got_sig = 0; - schedule(); - } - finish_wait(&itv->dma_waitq, &wait); - - /* Unmap Last DMA Xfer */ - ivtv_udma_unmap(itv); - - if (got_sig) { - IVTV_DEBUG_INFO("User stopped YUV UDMA\n"); - mutex_unlock(&itv->udma.lock); - return -EINTR; - } - - ivtv_yuv_frame_complete(itv); - - mutex_unlock(&itv->udma.lock); - return rc; -} - -/* Setup frame according to V4L2 parameters */ -void ivtv_yuv_setup_stream_frame(struct ivtv *itv) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - struct ivtv_dma_frame dma_args; - - ivtv_yuv_next_free(itv); - - /* Copy V4L2 parameters to an ivtv_dma_frame struct... */ - dma_args.y_source = NULL; - dma_args.uv_source = NULL; - dma_args.src.left = 0; - dma_args.src.top = 0; - dma_args.src.width = yi->v4l2_src_w; - dma_args.src.height = yi->v4l2_src_h; - dma_args.dst = yi->main_rect; - dma_args.src_width = yi->v4l2_src_w; - dma_args.src_height = yi->v4l2_src_h; - - /* ... and use the same setup routine as ivtv_yuv_prep_frame */ - ivtv_yuv_setup_frame(itv, &dma_args); - - if (!itv->dma_data_req_offset) - itv->dma_data_req_offset = yuv_offset[yi->draw_frame]; -} - -/* Attempt to dma a frame from a user buffer */ -int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - struct ivtv_dma_frame dma_args; - - ivtv_yuv_setup_stream_frame(itv); - - /* We only need to supply source addresses for this */ - dma_args.y_source = src; - dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31); - return ivtv_yuv_udma_frame(itv, &dma_args); -} - -/* IVTV_IOC_DMA_FRAME ioctl handler */ -int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) -{ -/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */ - - ivtv_yuv_next_free(itv); - ivtv_yuv_setup_frame(itv, args); - return ivtv_yuv_udma_frame(itv, args); -} - -void ivtv_yuv_close(struct ivtv *itv) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - int h_filter, v_filter_1, v_filter_2; - - IVTV_DEBUG_YUV("ivtv_yuv_close\n"); - ivtv_waitq(&itv->vsync_waitq); - - yi->running = 0; - atomic_set(&yi->next_dma_frame, -1); - atomic_set(&yi->next_fill_frame, 0); - - /* Reset registers we have changed so mpeg playback works */ - - /* If we fully restore this register, the display may remain active. - Restore, but set one bit to blank the video. Firmware will always - clear this bit when needed, so not a problem. */ - write_reg(yi->reg_2898 | 0x01000000, 0x2898); - - write_reg(yi->reg_2834, 0x02834); - write_reg(yi->reg_2838, 0x02838); - write_reg(yi->reg_283c, 0x0283c); - write_reg(yi->reg_2840, 0x02840); - write_reg(yi->reg_2844, 0x02844); - write_reg(yi->reg_2848, 0x02848); - write_reg(yi->reg_2854, 0x02854); - write_reg(yi->reg_285c, 0x0285c); - write_reg(yi->reg_2864, 0x02864); - write_reg(yi->reg_2870, 0x02870); - write_reg(yi->reg_2874, 0x02874); - write_reg(yi->reg_2890, 0x02890); - write_reg(yi->reg_289c, 0x0289c); - - write_reg(yi->reg_2918, 0x02918); - write_reg(yi->reg_291c, 0x0291c); - write_reg(yi->reg_2920, 0x02920); - write_reg(yi->reg_2924, 0x02924); - write_reg(yi->reg_2928, 0x02928); - write_reg(yi->reg_292c, 0x0292c); - write_reg(yi->reg_2930, 0x02930); - write_reg(yi->reg_2934, 0x02934); - write_reg(yi->reg_2938, 0x02938); - write_reg(yi->reg_293c, 0x0293c); - write_reg(yi->reg_2940, 0x02940); - write_reg(yi->reg_2944, 0x02944); - write_reg(yi->reg_2948, 0x02948); - write_reg(yi->reg_294c, 0x0294c); - write_reg(yi->reg_2950, 0x02950); - write_reg(yi->reg_2954, 0x02954); - write_reg(yi->reg_2958, 0x02958); - write_reg(yi->reg_295c, 0x0295c); - write_reg(yi->reg_2960, 0x02960); - write_reg(yi->reg_2964, 0x02964); - write_reg(yi->reg_2968, 0x02968); - write_reg(yi->reg_296c, 0x0296c); - write_reg(yi->reg_2970, 0x02970); - - /* Prepare to restore filters */ - - /* First the horizontal filter */ - if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) { - /* An exact size match uses filter 0 */ - h_filter = 0; - } else { - /* Figure out which filter to use */ - h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15; - h_filter = (h_filter >> 1) + (h_filter & 1); - /* Only an exact size match can use filter 0. */ - h_filter += !h_filter; - } - - /* Now the vertical filter */ - if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) { - /* An exact size match uses filter 0/1 */ - v_filter_1 = 0; - v_filter_2 = 1; - } else { - /* Figure out which filter to use */ - v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15; - v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); - /* Only an exact size match can use filter 0 */ - v_filter_1 += !v_filter_1; - v_filter_2 = v_filter_1; - } - - /* Now restore the filters */ - ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2); - - /* and clear a few registers */ - write_reg(0, 0x02814); - write_reg(0, 0x0282c); - write_reg(0, 0x02904); - write_reg(0, 0x02910); - - /* Release the blanking buffer */ - if (yi->blanking_ptr) { - kfree(yi->blanking_ptr); - yi->blanking_ptr = NULL; - pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); - } - - /* Invalidate the old dimension information */ - yi->old_frame_info.src_w = 0; - yi->old_frame_info.src_h = 0; - yi->old_frame_info_args.src_w = 0; - yi->old_frame_info_args.src_h = 0; - - /* All done. */ - clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-yuv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-yuv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-yuv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/ivtv-yuv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -/* - yuv support - - Copyright (C) 2007 Ian Armstrong - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef IVTV_YUV_H -#define IVTV_YUV_H - -#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ - -/* Offset to filter table in firmware */ -#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 -#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 - -#define IVTV_YUV_UPDATE_HORIZONTAL 0x01 -#define IVTV_YUV_UPDATE_VERTICAL 0x02 -#define IVTV_YUV_UPDATE_INVALID 0x04 - -extern const u32 yuv_offset[IVTV_YUV_BUFFERS]; - -int ivtv_yuv_filter_check(struct ivtv *itv); -void ivtv_yuv_setup_stream_frame(struct ivtv *itv); -int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src); -void ivtv_yuv_frame_complete(struct ivtv *itv); -int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); -void ivtv_yuv_close(struct ivtv *itv); -void ivtv_yuv_work_handler(struct ivtv *itv); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -config VIDEO_IVTV - tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" - depends on VIDEO_V4L2 && PCI && I2C - select I2C_ALGOBIT - depends on RC_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_CX2341X - select VIDEO_CX25840 - select VIDEO_MSP3400 - select VIDEO_SAA711X - select VIDEO_SAA717X - select VIDEO_SAA7127 - select VIDEO_CS53L32A - select VIDEO_M52790 - select VIDEO_WM8775 - select VIDEO_WM8739 - select VIDEO_VP27SMPX - select VIDEO_UPD64031A - select VIDEO_UPD64083 - ---help--- - This is a video4linux driver for Conexant cx23416 or cx23415 based - PCI personal video recorder devices. - - This is used in devices such as the Hauppauge PVR-150/250/350/500 - cards. There is a driver homepage at . - - To compile this driver as a module, choose M here: the - module will be called ivtv. - -config VIDEO_FB_IVTV - tristate "Conexant cx23415 framebuffer support" - depends on VIDEO_IVTV && FB - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - This is a framebuffer driver for the Conexant cx23415 MPEG - encoder/decoder. - - This is used in the Hauppauge PVR-350 card. There is a driver - homepage at . - - To compile this driver as a module, choose M here: the - module will be called ivtvfb. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ivtv/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ - ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \ - ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \ - ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \ - ivtv-vbi.o ivtv-yuv.o - -obj-$(CONFIG_VIDEO_IVTV) += ivtv.o -obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,1034 +0,0 @@ -# -# Generic video config states -# - -config VIDEO_V4L2 - tristate - depends on VIDEO_DEV && VIDEO_V4L2_COMMON - default VIDEO_DEV && VIDEO_V4L2_COMMON - -config VIDEOBUF_GEN - tristate - -config VIDEOBUF_DMA_SG - depends on HAS_DMA - select VIDEOBUF_GEN - tristate - -config VIDEOBUF_VMALLOC - select VIDEOBUF_GEN - tristate - -config VIDEOBUF_DMA_CONTIG - depends on HAS_DMA - select VIDEOBUF_GEN - tristate - -config VIDEOBUF_DVB - tristate - select VIDEOBUF_GEN - -config VIDEO_BTCX - depends on PCI - tristate - -config VIDEO_TVEEPROM - tristate - depends on I2C - -config VIDEO_TUNER - tristate - depends on MEDIA_TUNER - -config V4L2_MEM2MEM_DEV - tristate - depends on VIDEOBUF2_CORE - -config VIDEOBUF2_CORE - tristate - -config VIDEOBUF2_MEMOPS - tristate - -config VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_CORE - select VIDEOBUF2_MEMOPS - tristate - -config VIDEOBUF2_VMALLOC - select VIDEOBUF2_CORE - select VIDEOBUF2_MEMOPS - tristate - - -config VIDEOBUF2_DMA_SG - #depends on HAS_DMA - select VIDEOBUF2_CORE - select VIDEOBUF2_MEMOPS - tristate -# -# Multimedia Video device configuration -# - -menuconfig VIDEO_CAPTURE_DRIVERS - bool "Video capture adapters" - depends on VIDEO_V4L2 - default y - ---help--- - Say Y here to enable selecting the video adapters for - webcams, analog TV, and hybrid analog/digital TV. - Some of those devices also supports FM radio. - -if VIDEO_CAPTURE_DRIVERS && VIDEO_V4L2 - -config VIDEO_ADV_DEBUG - bool "Enable advanced debug functionality" - default n - ---help--- - Say Y here to enable advanced debugging functionality on some - V4L devices. - In doubt, say N. - -config VIDEO_FIXED_MINOR_RANGES - bool "Enable old-style fixed minor ranges for video devices" - default n - ---help--- - Say Y here to enable the old-style fixed-range minor assignments. - Only useful if you rely on the old behavior and use mknod instead of udev. - - When in doubt, say N. - -config VIDEO_HELPER_CHIPS_AUTO - bool "Autoselect pertinent encoders/decoders and other helper chips" - default y if !EXPERT - ---help--- - Most video cards may require additional modules to encode or - decode audio/video standards. This option will autoselect - all pertinent modules to each selected video module. - - Unselect this only if you know exactly what you are doing, since - it may break support on some boards. - - In doubt, say Y. - -config VIDEO_IR_I2C - tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO - depends on I2C && RC_CORE - default y - ---help--- - Most boards have an IR chip directly connected via GPIO. However, - some video boards have the IR connected via I2C bus. - - If your board doesn't have an I2C IR chip, you may disable this - option. - - In doubt, say Y. - -# -# Encoder / Decoder module configuration -# - -menu "Encoders/decoders and other helper chips" - visible if !VIDEO_HELPER_CHIPS_AUTO - -comment "Audio decoders" - -config VIDEO_TVAUDIO - tristate "Simple audio decoder chips" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for several audio decoder chips found on some bt8xx boards: - Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, - tea6320, tea6420, tda8425, ta8874z. - Microchip: pic16c54 based design on ProVideo PV951 board. - - To compile this driver as a module, choose M here: the - module will be called tvaudio. - -config VIDEO_TDA7432 - tristate "Philips TDA7432 audio processor" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for tda7432 audio decoder chip found on some bt8xx boards. - - To compile this driver as a module, choose M here: the - module will be called tda7432. - -config VIDEO_TDA9840 - tristate "Philips TDA9840 audio processor" - depends on I2C - ---help--- - Support for tda9840 audio decoder chip found on some Zoran boards. - - To compile this driver as a module, choose M here: the - module will be called tda9840. - -config VIDEO_TEA6415C - tristate "Philips TEA6415C audio processor" - depends on I2C - ---help--- - Support for tea6415c audio decoder chip found on some bt8xx boards. - - To compile this driver as a module, choose M here: the - module will be called tea6415c. - -config VIDEO_TEA6420 - tristate "Philips TEA6420 audio processor" - depends on I2C - ---help--- - Support for tea6420 audio decoder chip found on some bt8xx boards. - - To compile this driver as a module, choose M here: the - module will be called tea6420. - -config VIDEO_MSP3400 - tristate "Micronas MSP34xx audio decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Micronas MSP34xx series of audio decoders. - - To compile this driver as a module, choose M here: the - module will be called msp3400. - -config VIDEO_CS5345 - tristate "Cirrus Logic CS5345 audio ADC" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Cirrus Logic CS5345 24-bit, 192 kHz - stereo A/D converter. - - To compile this driver as a module, choose M here: the - module will be called cs5345. - -config VIDEO_CS53L32A - tristate "Cirrus Logic CS53L32A audio ADC" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Cirrus Logic CS53L32A low voltage - stereo A/D converter. - - To compile this driver as a module, choose M here: the - module will be called cs53l32a. - -config VIDEO_M52790 - tristate "Mitsubishi M52790 A/V switch" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Mitsubishi M52790 A/V switch. - - To compile this driver as a module, choose M here: the - module will be called m52790. - -config VIDEO_TLV320AIC23B - tristate "Texas Instruments TLV320AIC23B audio codec" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL - ---help--- - Support for the Texas Instruments TLV320AIC23B audio codec. - - To compile this driver as a module, choose M here: the - module will be called tlv320aic23b. - -config VIDEO_WM8775 - tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Wolfson Microelectronics WM8775 high - performance stereo A/D Converter with a 4 channel input mixer. - - To compile this driver as a module, choose M here: the - module will be called wm8775. - -config VIDEO_WM8739 - tristate "Wolfson Microelectronics WM8739 stereo audio ADC" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Wolfson Microelectronics WM8739 - stereo A/D Converter. - - To compile this driver as a module, choose M here: the - module will be called wm8739. - -config VIDEO_VP27SMPX - tristate "Panasonic VP27s internal MPX" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the internal MPX of the Panasonic VP27s tuner. - - To compile this driver as a module, choose M here: the - module will be called vp27smpx. - -comment "RDS decoders" - -config VIDEO_SAA6588 - tristate "SAA6588 Radio Chip RDS decoder support" - depends on VIDEO_V4L2 && I2C - - help - Support for this Radio Data System (RDS) decoder. This allows - seeing radio station identification transmitted using this - standard. - - To compile this driver as a module, choose M here: the - module will be called saa6588. - -comment "Video decoders" - -config VIDEO_ADV7180 - tristate "Analog Devices ADV7180 decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Analog Devices ADV7180 video decoder. - - To compile this driver as a module, choose M here: the - module will be called adv7180. - -config VIDEO_BT819 - tristate "BT819A VideoStream decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for BT819A video decoder. - - To compile this driver as a module, choose M here: the - module will be called bt819. - -config VIDEO_BT856 - tristate "BT856 VideoStream decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for BT856 video decoder. - - To compile this driver as a module, choose M here: the - module will be called bt856. - -config VIDEO_BT866 - tristate "BT866 VideoStream decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for BT866 video decoder. - - To compile this driver as a module, choose M here: the - module will be called bt866. - -config VIDEO_KS0127 - tristate "KS0127 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for KS0127 video decoder. - - This chip is used on AverMedia AVS6EYES Zoran-based MJPEG - cards. - - To compile this driver as a module, choose M here: the - module will be called ks0127. - -config VIDEO_OV7670 - tristate "OmniVision OV7670 sensor support" - depends on I2C && VIDEO_V4L2 - ---help--- - This is a Video4Linux2 sensor-level driver for the OmniVision - OV7670 VGA camera. It currently only works with the M88ALP01 - controller. - -config VIDEO_MT9V011 - tristate "Micron mt9v011 sensor support" - depends on I2C && VIDEO_V4L2 - ---help--- - This is a Video4Linux2 sensor-level driver for the Micron - mt0v011 1.3 Mpixel camera. It currently only works with the - em28xx driver. - -config VIDEO_TCM825X - tristate "TCM825x camera sensor support" - depends on I2C && VIDEO_V4L2 - ---help--- - This is a driver for the Toshiba TCM825x VGA camera sensor. - It is used for example in Nokia N800. - -config VIDEO_SAA7110 - tristate "Philips SAA7110 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7110 video decoders. - - To compile this driver as a module, choose M here: the - module will be called saa7110. - -config VIDEO_SAA711X - tristate "Philips SAA7111/3/4/5 video decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7111/3/4/5 video decoders. - - To compile this driver as a module, choose M here: the - module will be called saa7115. - -config VIDEO_SAA717X - tristate "Philips SAA7171/3/4 audio/video decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7171/3/4 audio/video decoders. - - To compile this driver as a module, choose M here: the - module will be called saa717x. - -config VIDEO_SAA7191 - tristate "Philips SAA7191 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7191 video decoder. - - To compile this driver as a module, choose M here: the - module will be called saa7191. - -config VIDEO_TVP514X - tristate "Texas Instruments TVP514x video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - This is a Video4Linux2 sensor-level driver for the TI TVP5146/47 - decoder. It is currently working with the TI OMAP3 camera - controller. - - To compile this driver as a module, choose M here: the - module will be called tvp514x. - -config VIDEO_TVP5150 - tristate "Texas Instruments TVP5150 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Texas Instruments TVP5150 video decoder. - - To compile this driver as a module, choose M here: the - module will be called tvp5150. - -config VIDEO_TVP7002 - tristate "Texas Instruments TVP7002 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Texas Instruments TVP7002 video decoder. - - To compile this driver as a module, choose M here: the - module will be called tvp7002. - -config VIDEO_VPX3220 - tristate "vpx3220a, vpx3216b & vpx3214c video decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for VPX322x video decoders. - - To compile this driver as a module, choose M here: the - module will be called vpx3220. - -comment "Video and audio decoders" - -source "drivers/media/video/cx25840/Kconfig" - -comment "MPEG video encoders" - -config VIDEO_CX2341X - tristate "Conexant CX2341x MPEG encoders" - depends on VIDEO_V4L2 && VIDEO_V4L2_COMMON - ---help--- - Support for the Conexant CX23416 MPEG encoders - and CX23415 MPEG encoder/decoders. - - This module currently supports the encoding functions only. - - To compile this driver as a module, choose M here: the - module will be called cx2341x. - -comment "Video encoders" - -config VIDEO_SAA7127 - tristate "Philips SAA7127/9 digital video encoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7127/9 digital video encoders. - - To compile this driver as a module, choose M here: the - module will be called saa7127. - -config VIDEO_SAA7185 - tristate "Philips SAA7185 video encoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7185 video encoder. - - To compile this driver as a module, choose M here: the - module will be called saa7185. - -config VIDEO_ADV7170 - tristate "Analog Devices ADV7170 video encoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Analog Devices ADV7170 video encoder driver - - To compile this driver as a module, choose M here: the - module will be called adv7170. - -config VIDEO_ADV7175 - tristate "Analog Devices ADV7175 video encoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Analog Devices ADV7175 video encoder driver - - To compile this driver as a module, choose M here: the - module will be called adv7175. - -config VIDEO_THS7303 - tristate "THS7303 Video Amplifier" - depends on I2C - help - Support for TI THS7303 video amplifier - - To compile this driver as a module, choose M here: the - module will be called ths7303. - -config VIDEO_ADV7343 - tristate "ADV7343 video encoder" - depends on I2C - help - Support for Analog Devices I2C bus based ADV7343 encoder. - - To compile this driver as a module, choose M here: the - module will be called adv7343. - -config VIDEO_AK881X - tristate "AK8813/AK8814 video encoders" - depends on I2C - help - Video output driver for AKM AK8813 and AK8814 TV encoders - -comment "Video improvement chips" - -config VIDEO_UPD64031A - tristate "NEC Electronics uPD64031A Ghost Reduction" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the NEC Electronics uPD64031A Ghost Reduction - video chip. It is most often found in NTSC TV cards made for - Japan and is used to reduce the 'ghosting' effect that can - be present in analog TV broadcasts. - - To compile this driver as a module, choose M here: the - module will be called upd64031a. - -config VIDEO_UPD64083 - tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the NEC Electronics uPD64083 3-Dimensional Y/C - separation video chip. It is used to improve the quality of - the colors of a composite signal. - - To compile this driver as a module, choose M here: the - module will be called upd64083. - -endmenu # encoder / decoder chips - -config VIDEO_SH_VOU - tristate "SuperH VOU video output driver" - depends on VIDEO_DEV && ARCH_SHMOBILE - select VIDEOBUF_DMA_CONTIG - help - Support for the Video Output Unit (VOU) on SuperH SoCs. - -config VIDEO_VIU - tristate "Freescale VIU Video Driver" - depends on VIDEO_V4L2 && PPC_MPC512x - select VIDEOBUF_DMA_CONTIG - default y - ---help--- - Support for Freescale VIU video driver. This device captures - video data, or overlays video on DIU frame buffer. - - Say Y here if you want to enable VIU device on MPC5121e Rev2+. - In doubt, say N. - -config VIDEO_VIVI - tristate "Virtual Video Driver" - depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 - depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE - select FONT_8x16 - select VIDEOBUF2_VMALLOC - default n - ---help--- - Enables a virtual video driver. This device shows a color bar - and a timestamp, as a real device would generate by using V4L2 - api. - Say Y here if you want to test video apps or debug V4L devices. - In doubt, say N. - -source "drivers/media/video/davinci/Kconfig" - -source "drivers/media/video/omap/Kconfig" - -source "drivers/media/video/bt8xx/Kconfig" - -config VIDEO_PMS - tristate "Mediavision Pro Movie Studio Video For Linux" - depends on ISA && VIDEO_V4L2 - help - Say Y if you have such a thing. - - To compile this driver as a module, choose M here: the - module will be called pms. - -config VIDEO_BWQCAM - tristate "Quickcam BW Video For Linux" - depends on PARPORT && VIDEO_V4L2 - help - Say Y have if you the black and white version of the QuickCam - camera. See the next option for the color version. - - To compile this driver as a module, choose M here: the - module will be called bw-qcam. - -config VIDEO_CQCAM - tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)" - depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2 - help - This is the video4linux driver for the colour version of the - Connectix QuickCam. If you have one of these cameras, say Y here, - otherwise say N. This driver does not work with the original - monochrome QuickCam, QuickCam VC or QuickClip. It is also available - as a module (c-qcam). - Read for more information. - -config VIDEO_W9966 - tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux" - depends on PARPORT_1284 && PARPORT && VIDEO_V4L2 - help - Video4linux driver for Winbond's w9966 based Webcams. - Currently tested with the LifeView FlyCam Supra. - If you have one of these cameras, say Y here - otherwise say N. - This driver is also available as a module (w9966). - - Check out for more - information. - -source "drivers/media/video/cpia2/Kconfig" - -config VIDEO_VINO - tristate "SGI Vino Video For Linux (EXPERIMENTAL)" - depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 - select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO - help - Say Y here to build in support for the Vino video input system found - on SGI Indy machines. - -source "drivers/media/video/zoran/Kconfig" - -config VIDEO_MEYE - tristate "Sony Vaio Picturebook Motion Eye Video For Linux" - depends on PCI && SONY_LAPTOP && VIDEO_V4L2 - ---help--- - This is the video4linux driver for the Motion Eye camera found - in the Vaio Picturebook laptops. Please read the material in - for more information. - - If you say Y or M here, you need to say Y or M to "Sony Laptop - Extras" in the misc device section. - - To compile this driver as a module, choose M here: the - module will be called meye. - -source "drivers/media/video/saa7134/Kconfig" - -config VIDEO_MXB - tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV - select VIDEO_TUNER - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO - ---help--- - This is a video4linux driver for the 'Multimedia eXtension Board' - TV card by Siemens-Nixdorf. - - To compile this driver as a module, choose M here: the - module will be called mxb. - -config VIDEO_HEXIUM_ORION - tristate "Hexium HV-PCI6 and Orion frame grabber" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV - ---help--- - This is a video4linux driver for the Hexium HV-PCI6 and - Orion frame grabber cards by Hexium. - - To compile this driver as a module, choose M here: the - module will be called hexium_orion. - -config VIDEO_HEXIUM_GEMINI - tristate "Hexium Gemini frame grabber" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV - ---help--- - This is a video4linux driver for the Hexium Gemini frame - grabber card by Hexium. Please note that the Gemini Dual - card is *not* fully supported. - - To compile this driver as a module, choose M here: the - module will be called hexium_gemini. - -config VIDEO_TIMBERDALE - tristate "Support for timberdale Video In/LogiWIN" - depends on VIDEO_V4L2 && I2C - select DMA_ENGINE - select TIMB_DMA - select VIDEO_ADV7180 - select VIDEOBUF_DMA_CONTIG - ---help--- - Add support for the Video In peripherial of the timberdale FPGA. - -source "drivers/media/video/cx88/Kconfig" - -source "drivers/media/video/cx23885/Kconfig" - -source "drivers/media/video/au0828/Kconfig" - -source "drivers/media/video/ivtv/Kconfig" - -source "drivers/media/video/cx18/Kconfig" - -source "drivers/media/video/saa7164/Kconfig" - -config VIDEO_M32R_AR - tristate "AR devices" - depends on M32R && VIDEO_V4L2 - ---help--- - This is a video4linux driver for the Renesas AR (Artificial Retina) - camera module. - -config VIDEO_M32R_AR_M64278 - tristate "AR device with color module M64278(VGA)" - depends on PLAT_M32700UT - select VIDEO_M32R_AR - ---help--- - This is a video4linux driver for the Renesas AR (Artificial - Retina) with M64278E-800 camera module. - This module supports VGA(640x480 pixels) resolutions. - - To compile this driver as a module, choose M here: the - module will be called arv. - -config VIDEO_CAFE_CCIC - tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" - depends on PCI && I2C && VIDEO_V4L2 - select VIDEO_OV7670 - ---help--- - This is a video4linux2 driver for the Marvell 88ALP01 integrated - CMOS camera controller. This is the controller found on first- - generation OLPC systems. - -config VIDEO_SR030PC30 - tristate "SR030PC30 VGA camera sensor support" - depends on I2C && VIDEO_V4L2 - ---help--- - This driver supports SR030PC30 VGA camera from Siliconfile - -config VIDEO_VIA_CAMERA - tristate "VIAFB camera controller support" - depends on FB_VIA - select VIDEOBUF_DMA_SG - select VIDEO_OV7670 - help - Driver support for the integrated camera controller in VIA - Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems - with ov7670 sensors. - -config VIDEO_NOON010PC30 - tristate "NOON010PC30 CIF camera sensor support" - depends on I2C && VIDEO_V4L2 - ---help--- - This driver supports NOON010PC30 CIF camera from Siliconfile - -config VIDEO_OMAP3 - tristate "OMAP 3 Camera support (EXPERIMENTAL)" - select OMAP_IOMMU - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL - ---help--- - Driver for an OMAP 3 camera controller. - -config VIDEO_OMAP3_DEBUG - bool "OMAP 3 Camera debug messages" - depends on VIDEO_OMAP3 - ---help--- - Enable debug messages on OMAP 3 camera controller driver. - -config SOC_CAMERA - tristate "SoC camera support" - depends on VIDEO_V4L2 && HAS_DMA && I2C - select VIDEOBUF_GEN - select VIDEOBUF2_CORE - help - SoC Camera is a common API to several cameras, not connecting - over a bus like PCI or USB. For example some i2c camera connected - directly to the data bus of an SoC. - -config SOC_CAMERA_IMX074 - tristate "imx074 support" - depends on SOC_CAMERA && I2C - help - This driver supports IMX074 cameras from Sony - -config SOC_CAMERA_MT9M001 - tristate "mt9m001 support" - depends on SOC_CAMERA && I2C - select GPIO_PCA953X if MT9M001_PCA9536_SWITCH - help - This driver supports MT9M001 cameras from Micron, monochrome - and colour models. - -config SOC_CAMERA_MT9M111 - tristate "mt9m111, mt9m112 and mt9m131 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9M111, MT9M112 and MT9M131 cameras from - Micron/Aptina - -config SOC_CAMERA_MT9T031 - tristate "mt9t031 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9T031 cameras from Micron. - -config SOC_CAMERA_MT9T112 - tristate "mt9t112 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9T112 cameras from Aptina. - -config SOC_CAMERA_MT9V022 - tristate "mt9v022 support" - depends on SOC_CAMERA && I2C - select GPIO_PCA953X if MT9V022_PCA9536_SWITCH - help - This driver supports MT9V022 cameras from Micron - -config SOC_CAMERA_RJ54N1 - tristate "rj54n1cb0c support" - depends on SOC_CAMERA && I2C - help - This is a rj54n1cb0c video driver - -config SOC_CAMERA_TW9910 - tristate "tw9910 support" - depends on SOC_CAMERA && I2C - help - This is a tw9910 video driver - -config SOC_CAMERA_PLATFORM - tristate "platform camera support" - depends on SOC_CAMERA - help - This is a generic SoC camera platform driver, useful for testing - -config SOC_CAMERA_OV2640 - tristate "ov2640 camera support" - depends on SOC_CAMERA && I2C - help - This is a ov2640 camera driver - -config SOC_CAMERA_OV6650 - tristate "ov6650 sensor support" - depends on SOC_CAMERA && I2C - ---help--- - This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor - -config SOC_CAMERA_OV772X - tristate "ov772x camera support" - depends on SOC_CAMERA && I2C - help - This is a ov772x camera driver - -config SOC_CAMERA_OV9640 - tristate "ov9640 camera support" - depends on SOC_CAMERA && I2C - help - This is a ov9640 camera driver - -config SOC_CAMERA_OV9740 - tristate "ov9740 camera support" - depends on SOC_CAMERA && I2C - help - This is a ov9740 camera driver - -config MX1_VIDEO - bool - -config VIDEO_MX1 - tristate "i.MX1/i.MXL CMOS Sensor Interface driver" - depends on VIDEO_DEV && ARCH_MX1 && SOC_CAMERA - select FIQ - select VIDEOBUF_DMA_CONTIG - select MX1_VIDEO - ---help--- - This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface - -config MX3_VIDEO - bool - -config VIDEO_MX3 - tristate "i.MX3x Camera Sensor Interface driver" - depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA - select VIDEOBUF_DMA_CONTIG - select MX3_VIDEO - ---help--- - This is a v4l2 driver for the i.MX3x Camera Sensor Interface - -config VIDEO_PXA27x - tristate "PXA27x Quick Capture Interface driver" - depends on VIDEO_DEV && PXA27x && SOC_CAMERA - select VIDEOBUF_DMA_SG - ---help--- - This is a v4l2 driver for the PXA27x Quick Capture Interface - -config VIDEO_SH_MOBILE_CSI2 - tristate "SuperH Mobile MIPI CSI-2 Interface driver" - depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK - ---help--- - This is a v4l2 driver for the SuperH MIPI CSI-2 Interface - -config VIDEO_SH_MOBILE_CEU - tristate "SuperH Mobile CEU Interface driver" - depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK - select VIDEOBUF2_DMA_CONTIG - ---help--- - This is a v4l2 driver for the SuperH Mobile CEU Interface - -config VIDEO_OMAP1 - tristate "OMAP1 Camera Interface driver" - depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA - select VIDEOBUF_DMA_CONTIG - select VIDEOBUF_DMA_SG - ---help--- - This is a v4l2 driver for the TI OMAP1 camera interface - -config VIDEO_OMAP2 - tristate "OMAP2 Camera Capture Interface driver" - depends on VIDEO_DEV && ARCH_OMAP2 - select VIDEOBUF_DMA_SG - ---help--- - This is a v4l2 driver for the TI OMAP2 camera capture interface - -config VIDEO_MX2_HOSTSUPPORT - bool - -config VIDEO_MX2 - tristate "i.MX27/i.MX25 Camera Sensor Interface driver" - depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25) - select VIDEOBUF_DMA_CONTIG - select VIDEO_MX2_HOSTSUPPORT - ---help--- - This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor - Interface - - -# -# USB Multimedia device configuration -# - -menuconfig V4L_USB_DRIVERS - bool "V4L USB devices" - depends on USB - default y - -if V4L_USB_DRIVERS && USB - -source "drivers/media/video/uvc/Kconfig" - -source "drivers/media/video/gspca/Kconfig" - -source "drivers/media/video/pvrusb2/Kconfig" - -source "drivers/media/video/hdpvr/Kconfig" - -source "drivers/media/video/em28xx/Kconfig" - -source "drivers/media/video/tlg2300/Kconfig" - -source "drivers/media/video/cx231xx/Kconfig" - -source "drivers/media/video/usbvision/Kconfig" - -source "drivers/media/video/et61x251/Kconfig" - -source "drivers/media/video/sn9c102/Kconfig" - -source "drivers/media/video/pwc/Kconfig" - -config USB_ZR364XX - tristate "USB ZR364XX Camera support" - depends on VIDEO_V4L2 - select VIDEOBUF_GEN - select VIDEOBUF_VMALLOC - ---help--- - Say Y here if you want to connect this type of camera to your - computer's USB port. - See for more info - and list of supported cameras. - - To compile this driver as a module, choose M here: the - module will be called zr364xx. - -config USB_STKWEBCAM - tristate "USB Syntek DC1125 Camera support" - depends on VIDEO_V4L2 && EXPERIMENTAL - ---help--- - Say Y here if you want to use this type of camera. - Supported devices are typically found in some Asus laptops, - with USB id 174f:a311 and 05e1:0501. Other Syntek cameras - may be supported by the stk11xx driver, from which this is - derived, see - - To compile this driver as a module, choose M here: the - module will be called stkwebcam. - -config USB_S2255 - tristate "USB Sensoray 2255 video capture device" - depends on VIDEO_V4L2 - select VIDEOBUF_VMALLOC - default n - help - Say Y here if you want support for the Sensoray 2255 USB device. - This driver can be compiled as a module, called s2255drv. - -endif # V4L_USB_DRIVERS -endif # VIDEO_CAPTURE_DRIVERS - -menuconfig V4L_MEM2MEM_DRIVERS - bool "Memory-to-memory multimedia devices" - depends on VIDEO_V4L2 - default n - ---help--- - Say Y here to enable selecting drivers for V4L devices that - use system memory for both source and destination buffers, as opposed - to capture and output drivers, which use memory buffers for just - one of those. - -if V4L_MEM2MEM_DRIVERS - -config VIDEO_MEM2MEM_TESTDEV - tristate "Virtual test device for mem2mem framework" - depends on VIDEO_DEV && VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - select V4L2_MEM2MEM_DEV - default n - ---help--- - This is a virtual test device for the memory-to-memory driver - framework. - -config VIDEO_SAMSUNG_S5P_FIMC - tristate "Samsung S5P FIMC (video postprocessor) driver" - depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - help - This is a v4l2 driver for the S5P camera interface - (video postprocessor) - -endif # V4L_MEM2MEM_DRIVERS diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ks0127.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ks0127.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ks0127.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ks0127.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,735 +0,0 @@ -/* - * Video Capture Driver (Video for Linux 1/2) - * for the Matrox Marvel G200,G400 and Rainbow Runner-G series - * - * This module is an interface to the KS0127 video decoder chip. - * - * Copyright (C) 1999 Ryan Drake - * - * 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, or (at your option) any later version. - * - * 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. - * - ***************************************************************************** - * - * Modified and extended by - * Mike Bernson - * Gerard v.d. Horst - * Leon van Stuivenberg - * Gernot Ziegler - * - * Version History: - * V1.0 Ryan Drake Initial version by Ryan Drake - * V1.1 Gerard v.d. Horst Added some debugoutput, reset the video-standard - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ks0127.h" - -MODULE_DESCRIPTION("KS0127 video decoder driver"); -MODULE_AUTHOR("Ryan Drake"); -MODULE_LICENSE("GPL"); - -/* Addresses */ -#define I2C_KS0127_ADDON 0xD8 -#define I2C_KS0127_ONBOARD 0xDA - - -/* ks0127 control registers */ -#define KS_STAT 0x00 -#define KS_CMDA 0x01 -#define KS_CMDB 0x02 -#define KS_CMDC 0x03 -#define KS_CMDD 0x04 -#define KS_HAVB 0x05 -#define KS_HAVE 0x06 -#define KS_HS1B 0x07 -#define KS_HS1E 0x08 -#define KS_HS2B 0x09 -#define KS_HS2E 0x0a -#define KS_AGC 0x0b -#define KS_HXTRA 0x0c -#define KS_CDEM 0x0d -#define KS_PORTAB 0x0e -#define KS_LUMA 0x0f -#define KS_CON 0x10 -#define KS_BRT 0x11 -#define KS_CHROMA 0x12 -#define KS_CHROMB 0x13 -#define KS_DEMOD 0x14 -#define KS_SAT 0x15 -#define KS_HUE 0x16 -#define KS_VERTIA 0x17 -#define KS_VERTIB 0x18 -#define KS_VERTIC 0x19 -#define KS_HSCLL 0x1a -#define KS_HSCLH 0x1b -#define KS_VSCLL 0x1c -#define KS_VSCLH 0x1d -#define KS_OFMTA 0x1e -#define KS_OFMTB 0x1f -#define KS_VBICTL 0x20 -#define KS_CCDAT2 0x21 -#define KS_CCDAT1 0x22 -#define KS_VBIL30 0x23 -#define KS_VBIL74 0x24 -#define KS_VBIL118 0x25 -#define KS_VBIL1512 0x26 -#define KS_TTFRAM 0x27 -#define KS_TESTA 0x28 -#define KS_UVOFFH 0x29 -#define KS_UVOFFL 0x2a -#define KS_UGAIN 0x2b -#define KS_VGAIN 0x2c -#define KS_VAVB 0x2d -#define KS_VAVE 0x2e -#define KS_CTRACK 0x2f -#define KS_POLCTL 0x30 -#define KS_REFCOD 0x31 -#define KS_INVALY 0x32 -#define KS_INVALU 0x33 -#define KS_INVALV 0x34 -#define KS_UNUSEY 0x35 -#define KS_UNUSEU 0x36 -#define KS_UNUSEV 0x37 -#define KS_USRSAV 0x38 -#define KS_USREAV 0x39 -#define KS_SHS1A 0x3a -#define KS_SHS1B 0x3b -#define KS_SHS1C 0x3c -#define KS_CMDE 0x3d -#define KS_VSDEL 0x3e -#define KS_CMDF 0x3f -#define KS_GAMMA0 0x40 -#define KS_GAMMA1 0x41 -#define KS_GAMMA2 0x42 -#define KS_GAMMA3 0x43 -#define KS_GAMMA4 0x44 -#define KS_GAMMA5 0x45 -#define KS_GAMMA6 0x46 -#define KS_GAMMA7 0x47 -#define KS_GAMMA8 0x48 -#define KS_GAMMA9 0x49 -#define KS_GAMMA10 0x4a -#define KS_GAMMA11 0x4b -#define KS_GAMMA12 0x4c -#define KS_GAMMA13 0x4d -#define KS_GAMMA14 0x4e -#define KS_GAMMA15 0x4f -#define KS_GAMMA16 0x50 -#define KS_GAMMA17 0x51 -#define KS_GAMMA18 0x52 -#define KS_GAMMA19 0x53 -#define KS_GAMMA20 0x54 -#define KS_GAMMA21 0x55 -#define KS_GAMMA22 0x56 -#define KS_GAMMA23 0x57 -#define KS_GAMMA24 0x58 -#define KS_GAMMA25 0x59 -#define KS_GAMMA26 0x5a -#define KS_GAMMA27 0x5b -#define KS_GAMMA28 0x5c -#define KS_GAMMA29 0x5d -#define KS_GAMMA30 0x5e -#define KS_GAMMA31 0x5f -#define KS_GAMMAD0 0x60 -#define KS_GAMMAD1 0x61 -#define KS_GAMMAD2 0x62 -#define KS_GAMMAD3 0x63 -#define KS_GAMMAD4 0x64 -#define KS_GAMMAD5 0x65 -#define KS_GAMMAD6 0x66 -#define KS_GAMMAD7 0x67 -#define KS_GAMMAD8 0x68 -#define KS_GAMMAD9 0x69 -#define KS_GAMMAD10 0x6a -#define KS_GAMMAD11 0x6b -#define KS_GAMMAD12 0x6c -#define KS_GAMMAD13 0x6d -#define KS_GAMMAD14 0x6e -#define KS_GAMMAD15 0x6f -#define KS_GAMMAD16 0x70 -#define KS_GAMMAD17 0x71 -#define KS_GAMMAD18 0x72 -#define KS_GAMMAD19 0x73 -#define KS_GAMMAD20 0x74 -#define KS_GAMMAD21 0x75 -#define KS_GAMMAD22 0x76 -#define KS_GAMMAD23 0x77 -#define KS_GAMMAD24 0x78 -#define KS_GAMMAD25 0x79 -#define KS_GAMMAD26 0x7a -#define KS_GAMMAD27 0x7b -#define KS_GAMMAD28 0x7c -#define KS_GAMMAD29 0x7d -#define KS_GAMMAD30 0x7e -#define KS_GAMMAD31 0x7f - - -/**************************************************************************** -* mga_dev : represents one ks0127 chip. -****************************************************************************/ - -struct adjust { - int contrast; - int bright; - int hue; - int ugain; - int vgain; -}; - -struct ks0127 { - struct v4l2_subdev sd; - v4l2_std_id norm; - int ident; - u8 regs[256]; -}; - -static inline struct ks0127 *to_ks0127(struct v4l2_subdev *sd) -{ - return container_of(sd, struct ks0127, sd); -} - - -static int debug; /* insmod parameter */ - -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug output"); - -static u8 reg_defaults[64]; - -static void init_reg_defaults(void) -{ - static int initialized; - u8 *table = reg_defaults; - - if (initialized) - return; - initialized = 1; - - table[KS_CMDA] = 0x2c; /* VSE=0, CCIR 601, autodetect standard */ - table[KS_CMDB] = 0x12; /* VALIGN=0, AGC control and input */ - table[KS_CMDC] = 0x00; /* Test options */ - /* clock & input select, write 1 to PORTA */ - table[KS_CMDD] = 0x01; - table[KS_HAVB] = 0x00; /* HAV Start Control */ - table[KS_HAVE] = 0x00; /* HAV End Control */ - table[KS_HS1B] = 0x10; /* HS1 Start Control */ - table[KS_HS1E] = 0x00; /* HS1 End Control */ - table[KS_HS2B] = 0x00; /* HS2 Start Control */ - table[KS_HS2E] = 0x00; /* HS2 End Control */ - table[KS_AGC] = 0x53; /* Manual setting for AGC */ - table[KS_HXTRA] = 0x00; /* Extra Bits for HAV and HS1/2 */ - table[KS_CDEM] = 0x00; /* Chroma Demodulation Control */ - table[KS_PORTAB] = 0x0f; /* port B is input, port A output GPPORT */ - table[KS_LUMA] = 0x01; /* Luma control */ - table[KS_CON] = 0x00; /* Contrast Control */ - table[KS_BRT] = 0x00; /* Brightness Control */ - table[KS_CHROMA] = 0x2a; /* Chroma control A */ - table[KS_CHROMB] = 0x90; /* Chroma control B */ - table[KS_DEMOD] = 0x00; /* Chroma Demodulation Control & Status */ - table[KS_SAT] = 0x00; /* Color Saturation Control*/ - table[KS_HUE] = 0x00; /* Hue Control */ - table[KS_VERTIA] = 0x00; /* Vertical Processing Control A */ - /* Vertical Processing Control B, luma 1 line delayed */ - table[KS_VERTIB] = 0x12; - table[KS_VERTIC] = 0x0b; /* Vertical Processing Control C */ - table[KS_HSCLL] = 0x00; /* Horizontal Scaling Ratio Low */ - table[KS_HSCLH] = 0x00; /* Horizontal Scaling Ratio High */ - table[KS_VSCLL] = 0x00; /* Vertical Scaling Ratio Low */ - table[KS_VSCLH] = 0x00; /* Vertical Scaling Ratio High */ - /* 16 bit YCbCr 4:2:2 output; I can't make the bt866 like 8 bit /Sam */ - table[KS_OFMTA] = 0x30; - table[KS_OFMTB] = 0x00; /* Output Control B */ - /* VBI Decoder Control; 4bit fmt: avoid Y overflow */ - table[KS_VBICTL] = 0x5d; - table[KS_CCDAT2] = 0x00; /* Read Only register */ - table[KS_CCDAT1] = 0x00; /* Read Only register */ - table[KS_VBIL30] = 0xa8; /* VBI data decoding options */ - table[KS_VBIL74] = 0xaa; /* VBI data decoding options */ - table[KS_VBIL118] = 0x2a; /* VBI data decoding options */ - table[KS_VBIL1512] = 0x00; /* VBI data decoding options */ - table[KS_TTFRAM] = 0x00; /* Teletext frame alignment pattern */ - table[KS_TESTA] = 0x00; /* test register, shouldn't be written */ - table[KS_UVOFFH] = 0x00; /* UV Offset Adjustment High */ - table[KS_UVOFFL] = 0x00; /* UV Offset Adjustment Low */ - table[KS_UGAIN] = 0x00; /* U Component Gain Adjustment */ - table[KS_VGAIN] = 0x00; /* V Component Gain Adjustment */ - table[KS_VAVB] = 0x07; /* VAV Begin */ - table[KS_VAVE] = 0x00; /* VAV End */ - table[KS_CTRACK] = 0x00; /* Chroma Tracking Control */ - table[KS_POLCTL] = 0x41; /* Timing Signal Polarity Control */ - table[KS_REFCOD] = 0x80; /* Reference Code Insertion Control */ - table[KS_INVALY] = 0x10; /* Invalid Y Code */ - table[KS_INVALU] = 0x80; /* Invalid U Code */ - table[KS_INVALV] = 0x80; /* Invalid V Code */ - table[KS_UNUSEY] = 0x10; /* Unused Y Code */ - table[KS_UNUSEU] = 0x80; /* Unused U Code */ - table[KS_UNUSEV] = 0x80; /* Unused V Code */ - table[KS_USRSAV] = 0x00; /* reserved */ - table[KS_USREAV] = 0x00; /* reserved */ - table[KS_SHS1A] = 0x00; /* User Defined SHS1 A */ - /* User Defined SHS1 B, ALT656=1 on 0127B */ - table[KS_SHS1B] = 0x80; - table[KS_SHS1C] = 0x00; /* User Defined SHS1 C */ - table[KS_CMDE] = 0x00; /* Command Register E */ - table[KS_VSDEL] = 0x00; /* VS Delay Control */ - /* Command Register F, update -immediately- */ - /* (there might come no vsync)*/ - table[KS_CMDF] = 0x02; -} - - -/* We need to manually read because of a bug in the KS0127 chip. - * - * An explanation from kayork@mail.utexas.edu: - * - * During I2C reads, the KS0127 only samples for a stop condition - * during the place where the acknowledge bit should be. Any standard - * I2C implementation (correctly) throws in another clock transition - * at the 9th bit, and the KS0127 will not recognize the stop condition - * and will continue to clock out data. - * - * So we have to do the read ourself. Big deal. - * workaround in i2c-algo-bit - */ - - -static u8 ks0127_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - char val = 0; - struct i2c_msg msgs[] = { - { client->addr, 0, sizeof(reg), ® }, - { client->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val } - }; - int ret; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) - v4l2_dbg(1, debug, sd, "read error\n"); - - return val; -} - - -static void ks0127_write(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ks0127 *ks = to_ks0127(sd); - char msg[] = { reg, val }; - - if (i2c_master_send(client, msg, sizeof(msg)) != sizeof(msg)) - v4l2_dbg(1, debug, sd, "write error\n"); - - ks->regs[reg] = val; -} - - -/* generic bit-twiddling */ -static void ks0127_and_or(struct v4l2_subdev *sd, u8 reg, u8 and_v, u8 or_v) -{ - struct ks0127 *ks = to_ks0127(sd); - - u8 val = ks->regs[reg]; - val = (val & and_v) | or_v; - ks0127_write(sd, reg, val); -} - - - -/**************************************************************************** -* ks0127 private api -****************************************************************************/ -static void ks0127_init(struct v4l2_subdev *sd) -{ - struct ks0127 *ks = to_ks0127(sd); - u8 *table = reg_defaults; - int i; - - ks->ident = V4L2_IDENT_KS0127; - - v4l2_dbg(1, debug, sd, "reset\n"); - msleep(1); - - /* initialize all registers to known values */ - /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */ - - for (i = 1; i < 33; i++) - ks0127_write(sd, i, table[i]); - - for (i = 35; i < 40; i++) - ks0127_write(sd, i, table[i]); - - for (i = 41; i < 56; i++) - ks0127_write(sd, i, table[i]); - - for (i = 58; i < 64; i++) - ks0127_write(sd, i, table[i]); - - - if ((ks0127_read(sd, KS_STAT) & 0x80) == 0) { - ks->ident = V4L2_IDENT_KS0122S; - v4l2_dbg(1, debug, sd, "ks0122s found\n"); - return; - } - - switch (ks0127_read(sd, KS_CMDE) & 0x0f) { - case 0: - v4l2_dbg(1, debug, sd, "ks0127 found\n"); - break; - - case 9: - ks->ident = V4L2_IDENT_KS0127B; - v4l2_dbg(1, debug, sd, "ks0127B Revision A found\n"); - break; - - default: - v4l2_dbg(1, debug, sd, "unknown revision\n"); - break; - } -} - -static int ks0127_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct ks0127 *ks = to_ks0127(sd); - - switch (input) { - case KS_INPUT_COMPOSITE_1: - case KS_INPUT_COMPOSITE_2: - case KS_INPUT_COMPOSITE_3: - case KS_INPUT_COMPOSITE_4: - case KS_INPUT_COMPOSITE_5: - case KS_INPUT_COMPOSITE_6: - v4l2_dbg(1, debug, sd, - "s_routing %d: Composite\n", input); - /* autodetect 50/60 Hz */ - ks0127_and_or(sd, KS_CMDA, 0xfc, 0x00); - /* VSE=0 */ - ks0127_and_or(sd, KS_CMDA, ~0x40, 0x00); - /* set input line */ - ks0127_and_or(sd, KS_CMDB, 0xb0, input); - /* non-freerunning mode */ - ks0127_and_or(sd, KS_CMDC, 0x70, 0x0a); - /* analog input */ - ks0127_and_or(sd, KS_CMDD, 0x03, 0x00); - /* enable chroma demodulation */ - ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00); - /* chroma trap, HYBWR=1 */ - ks0127_and_or(sd, KS_LUMA, 0x00, - (reg_defaults[KS_LUMA])|0x0c); - /* scaler fullbw, luma comb off */ - ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81); - /* manual chroma comb .25 .5 .25 */ - ks0127_and_or(sd, KS_VERTIC, 0x0f, 0x90); - - /* chroma path delay */ - ks0127_and_or(sd, KS_CHROMB, 0x0f, 0x90); - - ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]); - ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]); - ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]); - ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]); - break; - - case KS_INPUT_SVIDEO_1: - case KS_INPUT_SVIDEO_2: - case KS_INPUT_SVIDEO_3: - v4l2_dbg(1, debug, sd, - "s_routing %d: S-Video\n", input); - /* autodetect 50/60 Hz */ - ks0127_and_or(sd, KS_CMDA, 0xfc, 0x00); - /* VSE=0 */ - ks0127_and_or(sd, KS_CMDA, ~0x40, 0x00); - /* set input line */ - ks0127_and_or(sd, KS_CMDB, 0xb0, input); - /* non-freerunning mode */ - ks0127_and_or(sd, KS_CMDC, 0x70, 0x0a); - /* analog input */ - ks0127_and_or(sd, KS_CMDD, 0x03, 0x00); - /* enable chroma demodulation */ - ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00); - ks0127_and_or(sd, KS_LUMA, 0x00, - reg_defaults[KS_LUMA]); - /* disable luma comb */ - ks0127_and_or(sd, KS_VERTIA, 0x08, - (reg_defaults[KS_VERTIA]&0xf0)|0x01); - ks0127_and_or(sd, KS_VERTIC, 0x0f, - reg_defaults[KS_VERTIC]&0xf0); - - ks0127_and_or(sd, KS_CHROMB, 0x0f, - reg_defaults[KS_CHROMB]&0xf0); - - ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]); - ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]); - ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]); - ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]); - break; - - case KS_INPUT_YUV656: - v4l2_dbg(1, debug, sd, "s_routing 15: YUV656\n"); - if (ks->norm & V4L2_STD_525_60) - /* force 60 Hz */ - ks0127_and_or(sd, KS_CMDA, 0xfc, 0x03); - else - /* force 50 Hz */ - ks0127_and_or(sd, KS_CMDA, 0xfc, 0x02); - - ks0127_and_or(sd, KS_CMDA, 0xff, 0x40); /* VSE=1 */ - /* set input line and VALIGN */ - ks0127_and_or(sd, KS_CMDB, 0xb0, (input | 0x40)); - /* freerunning mode, */ - /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/ - ks0127_and_or(sd, KS_CMDC, 0x70, 0x87); - /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */ - ks0127_and_or(sd, KS_CMDD, 0x03, 0x08); - /* disable chroma demodulation */ - ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x30); - /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */ - ks0127_and_or(sd, KS_LUMA, 0x00, 0x71); - ks0127_and_or(sd, KS_VERTIC, 0x0f, - reg_defaults[KS_VERTIC]&0xf0); - - /* scaler fullbw, luma comb off */ - ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81); - - ks0127_and_or(sd, KS_CHROMB, 0x0f, - reg_defaults[KS_CHROMB]&0xf0); - - ks0127_and_or(sd, KS_CON, 0x00, 0x00); - ks0127_and_or(sd, KS_BRT, 0x00, 32); /* spec: 34 */ - /* spec: 229 (e5) */ - ks0127_and_or(sd, KS_SAT, 0x00, 0xe8); - ks0127_and_or(sd, KS_HUE, 0x00, 0); - - ks0127_and_or(sd, KS_UGAIN, 0x00, 238); - ks0127_and_or(sd, KS_VGAIN, 0x00, 0x00); - - /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */ - ks0127_and_or(sd, KS_UVOFFH, 0x00, 0x4f); - ks0127_and_or(sd, KS_UVOFFL, 0x00, 0x00); - break; - - default: - v4l2_dbg(1, debug, sd, - "s_routing: Unknown input %d\n", input); - break; - } - - /* hack: CDMLPF sometimes spontaneously switches on; */ - /* force back off */ - ks0127_write(sd, KS_DEMOD, reg_defaults[KS_DEMOD]); - return 0; -} - -static int ks0127_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct ks0127 *ks = to_ks0127(sd); - - /* Set to automatic SECAM/Fsc mode */ - ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00); - - ks->norm = std; - if (std & V4L2_STD_NTSC) { - v4l2_dbg(1, debug, sd, - "s_std: NTSC_M\n"); - ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20); - } else if (std & V4L2_STD_PAL_N) { - v4l2_dbg(1, debug, sd, - "s_std: NTSC_N (fixme)\n"); - ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40); - } else if (std & V4L2_STD_PAL) { - v4l2_dbg(1, debug, sd, - "s_std: PAL_N\n"); - ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20); - } else if (std & V4L2_STD_PAL_M) { - v4l2_dbg(1, debug, sd, - "s_std: PAL_M (fixme)\n"); - ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40); - } else if (std & V4L2_STD_SECAM) { - v4l2_dbg(1, debug, sd, - "s_std: SECAM\n"); - - /* set to secam autodetection */ - ks0127_and_or(sd, KS_CHROMA, 0xdf, 0x20); - ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00); - schedule_timeout_interruptible(HZ/10+1); - - /* did it autodetect? */ - if (!(ks0127_read(sd, KS_DEMOD) & 0x40)) - /* force to secam mode */ - ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x0f); - } else { - v4l2_dbg(1, debug, sd, "s_std: Unknown norm %llx\n", - (unsigned long long)std); - } - return 0; -} - -static int ks0127_s_stream(struct v4l2_subdev *sd, int enable) -{ - v4l2_dbg(1, debug, sd, "s_stream(%d)\n", enable); - if (enable) { - /* All output pins on */ - ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x30); - /* Obey the OEN pin */ - ks0127_and_or(sd, KS_CDEM, 0x7f, 0x00); - } else { - /* Video output pins off */ - ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x00); - /* Ignore the OEN pin */ - ks0127_and_or(sd, KS_CDEM, 0x7f, 0x80); - } - return 0; -} - -static int ks0127_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) -{ - int stat = V4L2_IN_ST_NO_SIGNAL; - u8 status; - v4l2_std_id std = V4L2_STD_ALL; - - status = ks0127_read(sd, KS_STAT); - if (!(status & 0x20)) /* NOVID not set */ - stat = 0; - if (!(status & 0x01)) /* CLOCK set */ - stat |= V4L2_IN_ST_NO_COLOR; - if ((status & 0x08)) /* PALDET set */ - std = V4L2_STD_PAL; - else - std = V4L2_STD_NTSC; - if (pstd) - *pstd = std; - if (pstatus) - *pstatus = stat; - return 0; -} - -static int ks0127_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) -{ - v4l2_dbg(1, debug, sd, "querystd\n"); - return ks0127_status(sd, NULL, std); -} - -static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status) -{ - v4l2_dbg(1, debug, sd, "g_input_status\n"); - return ks0127_status(sd, status, NULL); -} - -static int ks0127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ks0127 *ks = to_ks0127(sd); - - return v4l2_chip_ident_i2c_client(client, chip, ks->ident, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops ks0127_core_ops = { - .g_chip_ident = ks0127_g_chip_ident, - .s_std = ks0127_s_std, -}; - -static const struct v4l2_subdev_video_ops ks0127_video_ops = { - .s_routing = ks0127_s_routing, - .s_stream = ks0127_s_stream, - .querystd = ks0127_querystd, - .g_input_status = ks0127_g_input_status, -}; - -static const struct v4l2_subdev_ops ks0127_ops = { - .core = &ks0127_core_ops, - .video = &ks0127_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - - -static int ks0127_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct ks0127 *ks; - struct v4l2_subdev *sd; - - v4l_info(client, "%s chip found @ 0x%x (%s)\n", - client->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board", - client->addr << 1, client->adapter->name); - - ks = kzalloc(sizeof(*ks), GFP_KERNEL); - if (ks == NULL) - return -ENOMEM; - sd = &ks->sd; - v4l2_i2c_subdev_init(sd, client, &ks0127_ops); - - /* power up */ - init_reg_defaults(); - ks0127_write(sd, KS_CMDA, 0x2c); - mdelay(10); - - /* reset the device */ - ks0127_init(sd); - return 0; -} - -static int ks0127_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - ks0127_write(sd, KS_OFMTA, 0x20); /* tristate */ - ks0127_write(sd, KS_CMDA, 0x2c | 0x80); /* power down */ - kfree(to_ks0127(sd)); - return 0; -} - -static const struct i2c_device_id ks0127_id[] = { - { "ks0127", 0 }, - { "ks0127b", 0 }, - { "ks0122s", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ks0127_id); - -static struct i2c_driver ks0127_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "ks0127", - }, - .probe = ks0127_probe, - .remove = ks0127_remove, - .id_table = ks0127_id, -}; - -static __init int init_ks0127(void) -{ - return i2c_add_driver(&ks0127_driver); -} - -static __exit void exit_ks0127(void) -{ - i2c_del_driver(&ks0127_driver); -} - -module_init(init_ks0127); -module_exit(exit_ks0127); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ks0127.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ks0127.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ks0127.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ks0127.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - * Video Capture Driver ( Video for Linux 1/2 ) - * for the Matrox Marvel G200,G400 and Rainbow Runner-G series - * - * This module is an interface to the KS0127 video decoder chip. - * - * Copyright (C) 1999 Ryan Drake - * - * 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, or (at your option) any later version. - * - * 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. - */ - -#ifndef KS0127_H -#define KS0127_H - -/* input channels */ -#define KS_INPUT_COMPOSITE_1 0 -#define KS_INPUT_COMPOSITE_2 1 -#define KS_INPUT_COMPOSITE_3 2 -#define KS_INPUT_COMPOSITE_4 4 -#define KS_INPUT_COMPOSITE_5 5 -#define KS_INPUT_COMPOSITE_6 6 - -#define KS_INPUT_SVIDEO_1 8 -#define KS_INPUT_SVIDEO_2 9 -#define KS_INPUT_SVIDEO_3 10 - -#define KS_INPUT_YUV656 15 -#define KS_INPUT_COUNT 10 - -/* output channels */ -#define KS_OUTPUT_YUV656E 0 -#define KS_OUTPUT_EXV 1 - -/* video standards */ -#define KS_STD_NTSC_N 112 /* 50 Hz NTSC */ -#define KS_STD_PAL_M 113 /* 60 Hz PAL */ - -#endif /* KS0127_H */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/m52790.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/m52790.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/m52790.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/m52790.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,227 +0,0 @@ -/* - * m52790 i2c ivtv driver. - * Copyright (C) 2007 Hans Verkuil - * - * A/V source switching Mitsubishi M52790SP/FP - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch"); -MODULE_AUTHOR("Hans Verkuil"); -MODULE_LICENSE("GPL"); - - -struct m52790_state { - struct v4l2_subdev sd; - u16 input; - u16 output; -}; - -static inline struct m52790_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct m52790_state, sd); -} - -/* ----------------------------------------------------------------------- */ - -static int m52790_write(struct v4l2_subdev *sd) -{ - struct m52790_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - u8 sw1 = (state->input | state->output) & 0xff; - u8 sw2 = (state->input | state->output) >> 8; - - return i2c_smbus_write_byte_data(client, sw1, sw2); -} - -/* Note: audio and video are linked and cannot be switched separately. - So audio and video routing commands are identical for this chip. - In theory the video amplifier and audio modes could be handled - separately for the output, but that seems to be overkill right now. - The same holds for implementing an audio mute control, this is now - part of the audio output routing. The normal case is that another - chip takes care of the actual muting so making it part of the - output routing seems to be the right thing to do for now. */ -static int m52790_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct m52790_state *state = to_state(sd); - - state->input = input; - state->output = output; - m52790_write(sd); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct m52790_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (reg->reg != 0) - return -EINVAL; - reg->size = 1; - reg->val = state->input | state->output; - return 0; -} - -static int m52790_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct m52790_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (reg->reg != 0) - return -EINVAL; - state->input = reg->val & 0x0303; - state->output = reg->val & ~0x0303; - m52790_write(sd); - return 0; -} -#endif - -static int m52790_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_M52790, 0); -} - -static int m52790_log_status(struct v4l2_subdev *sd) -{ - struct m52790_state *state = to_state(sd); - - v4l2_info(sd, "Switch 1: %02x\n", - (state->input | state->output) & 0xff); - v4l2_info(sd, "Switch 2: %02x\n", - (state->input | state->output) >> 8); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops m52790_core_ops = { - .log_status = m52790_log_status, - .g_chip_ident = m52790_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = m52790_g_register, - .s_register = m52790_s_register, -#endif -}; - -static const struct v4l2_subdev_audio_ops m52790_audio_ops = { - .s_routing = m52790_s_routing, -}; - -static const struct v4l2_subdev_video_ops m52790_video_ops = { - .s_routing = m52790_s_routing, -}; - -static const struct v4l2_subdev_ops m52790_ops = { - .core = &m52790_core_ops, - .audio = &m52790_audio_ops, - .video = &m52790_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ - -static int m52790_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct m52790_state *state; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &m52790_ops); - state->input = M52790_IN_TUNER; - state->output = M52790_OUT_STEREO; - m52790_write(sd); - return 0; -} - -static int m52790_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id m52790_id[] = { - { "m52790", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, m52790_id); - -static struct i2c_driver m52790_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "m52790", - }, - .probe = m52790_probe, - .remove = m52790_remove, - .id_table = m52790_id, -}; - -static __init int init_m52790(void) -{ - return i2c_add_driver(&m52790_driver); -} - -static __exit void exit_m52790(void) -{ - i2c_del_driver(&m52790_driver); -} - -module_init(init_m52790); -module_exit(exit_m52790); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,186 +0,0 @@ -# -# Makefile for the video capture/playback device drivers. -# - -tuner-objs := tuner-core.o - -msp3400-objs := msp3400-driver.o msp3400-kthreads.o - -stkwebcam-objs := stk-webcam.o stk-sensor.o - -omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o - -videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ - v4l2-event.o v4l2-ctrls.o v4l2-subdev.o - -# V4L2 core modules - -obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o -ifeq ($(CONFIG_COMPAT),y) - obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o -endif - -obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o - -# All i2c modules must come first: - -obj-$(CONFIG_VIDEO_TUNER) += tuner.o -obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o -obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o -obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o -obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o -obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o -obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o -obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o -obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o -obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o -obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o -obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o -obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o -obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o -obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o -obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o -obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o -obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o -obj-$(CONFIG_VIDEO_BT819) += bt819.o -obj-$(CONFIG_VIDEO_BT856) += bt856.o -obj-$(CONFIG_VIDEO_BT866) += bt866.o -obj-$(CONFIG_VIDEO_KS0127) += ks0127.o -obj-$(CONFIG_VIDEO_THS7303) += ths7303.o -obj-$(CONFIG_VIDEO_VINO) += indycam.o -obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o -obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o -obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o -obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o -obj-$(CONFIG_VIDEO_CS5345) += cs5345.o -obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o -obj-$(CONFIG_VIDEO_M52790) += m52790.o -obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o -obj-$(CONFIG_VIDEO_WM8775) += wm8775.o -obj-$(CONFIG_VIDEO_WM8739) += wm8739.o -obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o -obj-$(CONFIG_VIDEO_CX25840) += cx25840/ -obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o -obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o -obj-$(CONFIG_VIDEO_OV7670) += ov7670.o -obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o -obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o -obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o -obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o -obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o - -obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o -obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o -obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o -obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o -obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o -obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o -obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o -obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o -obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o -obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o -obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o -obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o -obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o - -# And now the v4l2 drivers: - -obj-$(CONFIG_VIDEO_BT848) += bt8xx/ -obj-$(CONFIG_VIDEO_ZORAN) += zoran/ -obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o -obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o -obj-$(CONFIG_VIDEO_W9966) += w9966.o -obj-$(CONFIG_VIDEO_PMS) += pms.o -obj-$(CONFIG_VIDEO_VINO) += vino.o -obj-$(CONFIG_VIDEO_MEYE) += meye.o -obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ -obj-$(CONFIG_VIDEO_CX88) += cx88/ -obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ -obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/ -obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ -obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ -obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ -obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ -obj-$(CONFIG_VIDEO_MXB) += mxb.o -obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o -obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o -obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o - -obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o -obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o -obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o -obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o -obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o -obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o - -obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o -obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o -obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o -obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o -obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o - -obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o - -obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o - -obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o - -obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o - -obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o - -obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ - -obj-$(CONFIG_USB_ZR364XX) += zr364xx.o -obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o - -obj-$(CONFIG_USB_SN9C102) += sn9c102/ -obj-$(CONFIG_USB_ET61X251) += et61x251/ -obj-$(CONFIG_USB_PWC) += pwc/ -obj-$(CONFIG_USB_GSPCA) += gspca/ - -obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ - -obj-$(CONFIG_USB_S2255) += s2255drv.o - -obj-$(CONFIG_VIDEO_IVTV) += ivtv/ -obj-$(CONFIG_VIDEO_CX18) += cx18/ - -obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o -obj-$(CONFIG_VIDEO_VIVI) += vivi.o -obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o -obj-$(CONFIG_VIDEO_CX23885) += cx23885/ - -obj-$(CONFIG_VIDEO_AK881X) += ak881x.o - -obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o -obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o -obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o -# soc-camera host drivers have to be linked after camera drivers -obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o -obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o -obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o -obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o -obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o -obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o -obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ - -obj-$(CONFIG_ARCH_DAVINCI) += davinci/ - -obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o - -obj-$(CONFIG_VIDEO_AU0828) += au0828/ - -obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ -obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ - -obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o - -obj-y += davinci/ - -obj-$(CONFIG_ARCH_OMAP) += omap/ - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/common/tuners diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mem2mem_testdev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mem2mem_testdev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mem2mem_testdev.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mem2mem_testdev.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1037 +0,0 @@ -/* - * A virtual v4l2-mem2mem example device. - * - * This is a virtual device driver for testing mem-to-mem videobuf framework. - * It simulates a device that uses memory buffers for both source and - * destination, processes the data and issues an "irq" (simulated by a timer). - * The device is capable of multi-instance, multi-buffer-per-transaction - * operation (via the mem2mem framework). - * - * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. - * Pawel Osciak, - * Marek Szyprowski, - * - * 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, or (at your option) any later version - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev" - -MODULE_DESCRIPTION("Virtual device for mem2mem framework testing"); -MODULE_AUTHOR("Pawel Osciak, "); -MODULE_LICENSE("GPL"); - - -#define MIN_W 32 -#define MIN_H 32 -#define MAX_W 640 -#define MAX_H 480 -#define DIM_ALIGN_MASK 0x08 /* 8-alignment for dimensions */ - -/* Flags that indicate a format can be used for capture/output */ -#define MEM2MEM_CAPTURE (1 << 0) -#define MEM2MEM_OUTPUT (1 << 1) - -#define MEM2MEM_NAME "m2m-testdev" - -/* Per queue */ -#define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME -/* In bytes, per queue */ -#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024) - -/* Default transaction time in msec */ -#define MEM2MEM_DEF_TRANSTIME 1000 -/* Default number of buffers per transaction */ -#define MEM2MEM_DEF_TRANSLEN 1 -#define MEM2MEM_COLOR_STEP (0xff >> 4) -#define MEM2MEM_NUM_TILES 8 - -#define dprintk(dev, fmt, arg...) \ - v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) - - -void m2mtest_dev_release(struct device *dev) -{} - -static struct platform_device m2mtest_pdev = { - .name = MEM2MEM_NAME, - .dev.release = m2mtest_dev_release, -}; - -struct m2mtest_fmt { - char *name; - u32 fourcc; - int depth; - /* Types the format can be used for */ - u32 types; -}; - -static struct m2mtest_fmt formats[] = { - { - .name = "RGB565 (BE)", - .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ - .depth = 16, - /* Both capture and output format */ - .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, - }, - { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - /* Output-only format */ - .types = MEM2MEM_OUTPUT, - }, -}; - -/* Per-queue, driver-specific private data */ -struct m2mtest_q_data { - unsigned int width; - unsigned int height; - unsigned int sizeimage; - struct m2mtest_fmt *fmt; -}; - -enum { - V4L2_M2M_SRC = 0, - V4L2_M2M_DST = 1, -}; - -/* Source and destination queue data */ -static struct m2mtest_q_data q_data[2]; - -static struct m2mtest_q_data *get_q_data(enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return &q_data[V4L2_M2M_SRC]; - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &q_data[V4L2_M2M_DST]; - default: - BUG(); - } - return NULL; -} - -#define V4L2_CID_TRANS_TIME_MSEC V4L2_CID_PRIVATE_BASE -#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_PRIVATE_BASE + 1) - -static struct v4l2_queryctrl m2mtest_ctrls[] = { - { - .id = V4L2_CID_TRANS_TIME_MSEC, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Transaction time (msec)", - .minimum = 1, - .maximum = 10000, - .step = 100, - .default_value = 1000, - .flags = 0, - }, { - .id = V4L2_CID_TRANS_NUM_BUFS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Buffers per transaction", - .minimum = 1, - .maximum = MEM2MEM_DEF_NUM_BUFS, - .step = 1, - .default_value = 1, - .flags = 0, - }, -}; - -#define NUM_FORMATS ARRAY_SIZE(formats) - -static struct m2mtest_fmt *find_format(struct v4l2_format *f) -{ - struct m2mtest_fmt *fmt; - unsigned int k; - - for (k = 0; k < NUM_FORMATS; k++) { - fmt = &formats[k]; - if (fmt->fourcc == f->fmt.pix.pixelformat) - break; - } - - if (k == NUM_FORMATS) - return NULL; - - return &formats[k]; -} - -struct m2mtest_dev { - struct v4l2_device v4l2_dev; - struct video_device *vfd; - - atomic_t num_inst; - struct mutex dev_mutex; - spinlock_t irqlock; - - struct timer_list timer; - - struct v4l2_m2m_dev *m2m_dev; -}; - -struct m2mtest_ctx { - struct m2mtest_dev *dev; - - /* Processed buffers in this transaction */ - u8 num_processed; - - /* Transaction length (i.e. how many buffers per transaction) */ - u32 translen; - /* Transaction time (i.e. simulated processing time) in milliseconds */ - u32 transtime; - - /* Abort requested by m2m */ - int aborting; - - struct v4l2_m2m_ctx *m2m_ctx; -}; - -static struct v4l2_queryctrl *get_ctrl(int id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(m2mtest_ctrls); ++i) { - if (id == m2mtest_ctrls[i].id) - return &m2mtest_ctrls[i]; - } - - return NULL; -} - -static int device_process(struct m2mtest_ctx *ctx, - struct vb2_buffer *in_vb, - struct vb2_buffer *out_vb) -{ - struct m2mtest_dev *dev = ctx->dev; - struct m2mtest_q_data *q_data; - u8 *p_in, *p_out; - int x, y, t, w; - int tile_w, bytes_left; - int width, height, bytesperline; - - q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); - - width = q_data->width; - height = q_data->height; - bytesperline = (q_data->width * q_data->fmt->depth) >> 3; - - p_in = vb2_plane_vaddr(in_vb, 0); - p_out = vb2_plane_vaddr(out_vb, 0); - if (!p_in || !p_out) { - v4l2_err(&dev->v4l2_dev, - "Acquiring kernel pointers to buffers failed\n"); - return -EFAULT; - } - - if (vb2_plane_size(in_vb, 0) > vb2_plane_size(out_vb, 0)) { - v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n"); - return -EINVAL; - } - - tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3)) - / MEM2MEM_NUM_TILES; - bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES; - w = 0; - - for (y = 0; y < height; ++y) { - for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { - if (w & 0x1) { - for (x = 0; x < tile_w; ++x) - *p_out++ = *p_in++ + MEM2MEM_COLOR_STEP; - } else { - for (x = 0; x < tile_w; ++x) - *p_out++ = *p_in++ - MEM2MEM_COLOR_STEP; - } - ++w; - } - p_in += bytes_left; - p_out += bytes_left; - } - - return 0; -} - -static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout) -{ - dprintk(dev, "Scheduling a simulated irq\n"); - mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout)); -} - -/* - * mem2mem callbacks - */ - -/** - * job_ready() - check whether an instance is ready to be scheduled to run - */ -static int job_ready(void *priv) -{ - struct m2mtest_ctx *ctx = priv; - - if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen - || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) { - dprintk(ctx->dev, "Not enough buffers available\n"); - return 0; - } - - return 1; -} - -static void job_abort(void *priv) -{ - struct m2mtest_ctx *ctx = priv; - - /* Will cancel the transaction in the next interrupt handler */ - ctx->aborting = 1; -} - -static void m2mtest_lock(void *priv) -{ - struct m2mtest_ctx *ctx = priv; - struct m2mtest_dev *dev = ctx->dev; - mutex_lock(&dev->dev_mutex); -} - -static void m2mtest_unlock(void *priv) -{ - struct m2mtest_ctx *ctx = priv; - struct m2mtest_dev *dev = ctx->dev; - mutex_unlock(&dev->dev_mutex); -} - - -/* device_run() - prepares and starts the device - * - * This simulates all the immediate preparations required before starting - * a device. This will be called by the framework when it decides to schedule - * a particular instance. - */ -static void device_run(void *priv) -{ - struct m2mtest_ctx *ctx = priv; - struct m2mtest_dev *dev = ctx->dev; - struct vb2_buffer *src_buf, *dst_buf; - - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - - device_process(ctx, src_buf, dst_buf); - - /* Run a timer, which simulates a hardware irq */ - schedule_irq(dev, ctx->transtime); -} - -static void device_isr(unsigned long priv) -{ - struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv; - struct m2mtest_ctx *curr_ctx; - struct vb2_buffer *src_vb, *dst_vb; - unsigned long flags; - - curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev); - - if (NULL == curr_ctx) { - printk(KERN_ERR - "Instance released before the end of transaction\n"); - return; - } - - src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); - dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); - - curr_ctx->num_processed++; - - spin_lock_irqsave(&m2mtest_dev->irqlock, flags); - v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); - v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); - spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags); - - if (curr_ctx->num_processed == curr_ctx->translen - || curr_ctx->aborting) { - dprintk(curr_ctx->dev, "Finishing transaction\n"); - curr_ctx->num_processed = 0; - v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx); - } else { - device_run(curr_ctx); - } -} - -/* - * video ioctls - */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); - cap->bus_info[0] = 0; - cap->version = KERNEL_VERSION(0, 1, 0); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT - | V4L2_CAP_STREAMING; - - return 0; -} - -static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) -{ - int i, num; - struct m2mtest_fmt *fmt; - - num = 0; - - for (i = 0; i < NUM_FORMATS; ++i) { - if (formats[i].types & type) { - /* index-th format of type type found ? */ - if (num == f->index) - break; - /* Correct type but haven't reached our index yet, - * just increment per-type index */ - ++num; - } - } - - if (i < NUM_FORMATS) { - /* Format found */ - fmt = &formats[i]; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); - f->pixelformat = fmt->fourcc; - return 0; - } - - /* Format not found */ - return -EINVAL; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return enum_fmt(f, MEM2MEM_CAPTURE); -} - -static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return enum_fmt(f, MEM2MEM_OUTPUT); -} - -static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) -{ - struct vb2_queue *vq; - struct m2mtest_q_data *q_data; - - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - q_data = get_q_data(f->type); - - f->fmt.pix.width = q_data->width; - f->fmt.pix.height = q_data->height; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.pixelformat = q_data->fmt->fourcc; - f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3; - f->fmt.pix.sizeimage = q_data->sizeimage; - - return 0; -} - -static int vidioc_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - return vidioc_g_fmt(priv, f); -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - return vidioc_g_fmt(priv, f); -} - -static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt) -{ - enum v4l2_field field; - - field = f->fmt.pix.field; - - if (field == V4L2_FIELD_ANY) - field = V4L2_FIELD_NONE; - else if (V4L2_FIELD_NONE != field) - return -EINVAL; - - /* V4L2 specification suggests the driver corrects the format struct - * if any of the dimensions is unsupported */ - f->fmt.pix.field = field; - - if (f->fmt.pix.height < MIN_H) - f->fmt.pix.height = MIN_H; - else if (f->fmt.pix.height > MAX_H) - f->fmt.pix.height = MAX_H; - - if (f->fmt.pix.width < MIN_W) - f->fmt.pix.width = MIN_W; - else if (f->fmt.pix.width > MAX_W) - f->fmt.pix.width = MAX_W; - - f->fmt.pix.width &= ~DIM_ALIGN_MASK; - f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct m2mtest_fmt *fmt; - struct m2mtest_ctx *ctx = priv; - - fmt = find_format(f); - if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { - v4l2_err(&ctx->dev->v4l2_dev, - "Fourcc format (0x%08x) invalid.\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - return vidioc_try_fmt(f, fmt); -} - -static int vidioc_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct m2mtest_fmt *fmt; - struct m2mtest_ctx *ctx = priv; - - fmt = find_format(f); - if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { - v4l2_err(&ctx->dev->v4l2_dev, - "Fourcc format (0x%08x) invalid.\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - return vidioc_try_fmt(f, fmt); -} - -static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) -{ - struct m2mtest_q_data *q_data; - struct vb2_queue *vq; - - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - q_data = get_q_data(f->type); - if (!q_data) - return -EINVAL; - - if (vb2_is_busy(vq)) { - v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); - return -EBUSY; - } - - q_data->fmt = find_format(f); - q_data->width = f->fmt.pix.width; - q_data->height = f->fmt.pix.height; - q_data->sizeimage = q_data->width * q_data->height - * q_data->fmt->depth >> 3; - - dprintk(ctx->dev, - "Setting format for type %d, wxh: %dx%d, fmt: %d\n", - f->type, q_data->width, q_data->height, q_data->fmt->fourcc); - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - int ret; - - ret = vidioc_try_fmt_vid_cap(file, priv, f); - if (ret) - return ret; - - return vidioc_s_fmt(priv, f); -} - -static int vidioc_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - int ret; - - ret = vidioc_try_fmt_vid_out(file, priv, f); - if (ret) - return ret; - - return vidioc_s_fmt(priv, f); -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct m2mtest_ctx *ctx = priv; - - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct m2mtest_ctx *ctx = priv; - - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct m2mtest_ctx *ctx = priv; - - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct m2mtest_ctx *ctx = priv; - - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct m2mtest_ctx *ctx = priv; - - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct m2mtest_ctx *ctx = priv; - - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct v4l2_queryctrl *c; - - c = get_ctrl(qc->id); - if (!c) - return -EINVAL; - - *qc = *c; - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct m2mtest_ctx *ctx = priv; - - switch (ctrl->id) { - case V4L2_CID_TRANS_TIME_MSEC: - ctrl->value = ctx->transtime; - break; - - case V4L2_CID_TRANS_NUM_BUFS: - ctrl->value = ctx->translen; - break; - - default: - v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); - return -EINVAL; - } - - return 0; -} - -static int check_ctrl_val(struct m2mtest_ctx *ctx, struct v4l2_control *ctrl) -{ - struct v4l2_queryctrl *c; - - c = get_ctrl(ctrl->id); - if (!c) - return -EINVAL; - - if (ctrl->value < c->minimum || ctrl->value > c->maximum) { - v4l2_err(&ctx->dev->v4l2_dev, "Value out of range\n"); - return -ERANGE; - } - - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct m2mtest_ctx *ctx = priv; - int ret = 0; - - ret = check_ctrl_val(ctx, ctrl); - if (ret != 0) - return ret; - - switch (ctrl->id) { - case V4L2_CID_TRANS_TIME_MSEC: - ctx->transtime = ctrl->value; - break; - - case V4L2_CID_TRANS_NUM_BUFS: - ctx->translen = ctrl->value; - break; - - default: - v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); - return -EINVAL; - } - - return 0; -} - - -static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, - .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, - .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, - .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - - -/* - * Queue operations - */ - -static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned long sizes[], - void *alloc_ctxs[]) -{ - struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); - struct m2mtest_q_data *q_data; - unsigned int size, count = *nbuffers; - - q_data = get_q_data(vq->type); - - size = q_data->width * q_data->height * q_data->fmt->depth >> 3; - - while (size * count > MEM2MEM_VID_MEM_LIMIT) - (count)--; - - *nplanes = 1; - *nbuffers = count; - sizes[0] = size; - - /* - * videobuf2-vmalloc allocator is context-less so no need to set - * alloc_ctxs array. - */ - - dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); - - return 0; -} - -static int m2mtest_buf_prepare(struct vb2_buffer *vb) -{ - struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct m2mtest_q_data *q_data; - - dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); - - q_data = get_q_data(vb->vb2_queue->type); - - if (vb2_plane_size(vb, 0) < q_data->sizeimage) { - dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage); - return -EINVAL; - } - - vb2_set_plane_payload(vb, 0, q_data->sizeimage); - - return 0; -} - -static void m2mtest_buf_queue(struct vb2_buffer *vb) -{ - struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); -} - -static struct vb2_ops m2mtest_qops = { - .queue_setup = m2mtest_queue_setup, - .buf_prepare = m2mtest_buf_prepare, - .buf_queue = m2mtest_buf_queue, -}; - -static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) -{ - struct m2mtest_ctx *ctx = priv; - int ret; - - memset(src_vq, 0, sizeof(*src_vq)); - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_MMAP; - src_vq->drv_priv = ctx; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->ops = &m2mtest_qops; - src_vq->mem_ops = &vb2_vmalloc_memops; - - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - memset(dst_vq, 0, sizeof(*dst_vq)); - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_MMAP; - dst_vq->drv_priv = ctx; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->ops = &m2mtest_qops; - dst_vq->mem_ops = &vb2_vmalloc_memops; - - return vb2_queue_init(dst_vq); -} - -/* - * File operations - */ -static int m2mtest_open(struct file *file) -{ - struct m2mtest_dev *dev = video_drvdata(file); - struct m2mtest_ctx *ctx = NULL; - - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - file->private_data = ctx; - ctx->dev = dev; - ctx->translen = MEM2MEM_DEF_TRANSLEN; - ctx->transtime = MEM2MEM_DEF_TRANSTIME; - ctx->num_processed = 0; - - ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); - - if (IS_ERR(ctx->m2m_ctx)) { - int ret = PTR_ERR(ctx->m2m_ctx); - - kfree(ctx); - return ret; - } - - atomic_inc(&dev->num_inst); - - dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); - - return 0; -} - -static int m2mtest_release(struct file *file) -{ - struct m2mtest_dev *dev = video_drvdata(file); - struct m2mtest_ctx *ctx = file->private_data; - - dprintk(dev, "Releasing instance %p\n", ctx); - - v4l2_m2m_ctx_release(ctx->m2m_ctx); - kfree(ctx); - - atomic_dec(&dev->num_inst); - - return 0; -} - -static unsigned int m2mtest_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct m2mtest_ctx *ctx = file->private_data; - - return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); -} - -static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct m2mtest_ctx *ctx = file->private_data; - - return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); -} - -static const struct v4l2_file_operations m2mtest_fops = { - .owner = THIS_MODULE, - .open = m2mtest_open, - .release = m2mtest_release, - .poll = m2mtest_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = m2mtest_mmap, -}; - -static struct video_device m2mtest_videodev = { - .name = MEM2MEM_NAME, - .fops = &m2mtest_fops, - .ioctl_ops = &m2mtest_ioctl_ops, - .minor = -1, - .release = video_device_release, -}; - -static struct v4l2_m2m_ops m2m_ops = { - .device_run = device_run, - .job_ready = job_ready, - .job_abort = job_abort, - .lock = m2mtest_lock, - .unlock = m2mtest_unlock, -}; - -static int m2mtest_probe(struct platform_device *pdev) -{ - struct m2mtest_dev *dev; - struct video_device *vfd; - int ret; - - dev = kzalloc(sizeof *dev, GFP_KERNEL); - if (!dev) - return -ENOMEM; - - spin_lock_init(&dev->irqlock); - - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); - if (ret) - goto free_dev; - - atomic_set(&dev->num_inst, 0); - mutex_init(&dev->dev_mutex); - - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); - ret = -ENOMEM; - goto unreg_dev; - } - - *vfd = m2mtest_videodev; - vfd->lock = &dev->dev_mutex; - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto rel_vdev; - } - - video_set_drvdata(vfd, dev); - snprintf(vfd->name, sizeof(vfd->name), "%s", m2mtest_videodev.name); - dev->vfd = vfd; - v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME - "Device registered as /dev/video%d\n", vfd->num); - - setup_timer(&dev->timer, device_isr, (long)dev); - platform_set_drvdata(pdev, dev); - - dev->m2m_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(dev->m2m_dev)) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); - ret = PTR_ERR(dev->m2m_dev); - goto err_m2m; - } - - q_data[V4L2_M2M_SRC].fmt = &formats[0]; - q_data[V4L2_M2M_DST].fmt = &formats[0]; - - return 0; - - v4l2_m2m_release(dev->m2m_dev); -err_m2m: - video_unregister_device(dev->vfd); -rel_vdev: - video_device_release(vfd); -unreg_dev: - v4l2_device_unregister(&dev->v4l2_dev); -free_dev: - kfree(dev); - - return ret; -} - -static int m2mtest_remove(struct platform_device *pdev) -{ - struct m2mtest_dev *dev = - (struct m2mtest_dev *)platform_get_drvdata(pdev); - - v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME); - v4l2_m2m_release(dev->m2m_dev); - del_timer_sync(&dev->timer); - video_unregister_device(dev->vfd); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - - return 0; -} - -static struct platform_driver m2mtest_pdrv = { - .probe = m2mtest_probe, - .remove = m2mtest_remove, - .driver = { - .name = MEM2MEM_NAME, - .owner = THIS_MODULE, - }, -}; - -static void __exit m2mtest_exit(void) -{ - platform_driver_unregister(&m2mtest_pdrv); - platform_device_unregister(&m2mtest_pdev); -} - -static int __init m2mtest_init(void) -{ - int ret; - - ret = platform_device_register(&m2mtest_pdev); - if (ret) - return ret; - - ret = platform_driver_register(&m2mtest_pdrv); - if (ret) - platform_device_unregister(&m2mtest_pdev); - - return 0; -} - -module_init(m2mtest_init); -module_exit(m2mtest_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/meye.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/meye.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/meye.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/meye.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1963 +0,0 @@ -/* - * Motion Eye video4linux driver for Sony Vaio PictureBook - * - * Copyright (C) 2001-2004 Stelian Pop - * - * Copyright (C) 2001-2002 Alcôve - * - * Copyright (C) 2000 Andrew Tridgell - * - * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. - * - * Some parts borrowed from various video4linux drivers, especially - * bttv-driver.c and zoran.c, see original files for credits. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "meye.h" -#include - -MODULE_AUTHOR("Stelian Pop "); -MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera"); -MODULE_LICENSE("GPL"); - -/* number of grab buffers */ -static unsigned int gbuffers = 2; -module_param(gbuffers, int, 0444); -MODULE_PARM_DESC(gbuffers, "number of capture buffers, default is 2 (32 max)"); - -/* size of a grab buffer */ -static unsigned int gbufsize = MEYE_MAX_BUFSIZE; -module_param(gbufsize, int, 0444); -MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 614400" - " (will be rounded up to a page multiple)"); - -/* /dev/videoX registration number */ -static int video_nr = -1; -module_param(video_nr, int, 0444); -MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)"); - -/* driver structure - only one possible */ -static struct meye meye; - -/****************************************************************************/ -/* Memory allocation routines (stolen from bttv-driver.c) */ -/****************************************************************************/ -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (mem) { - memset(mem, 0, size); - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (mem) { - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); - } -} - -/* - * return a page table pointing to N pages of locked memory - * - * NOTE: The meye device expects DMA addresses on 32 bits, we build - * a table of 1024 entries = 4 bytes * 1024 = 4096 bytes. - */ -static int ptable_alloc(void) -{ - u32 *pt; - int i; - - memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); - - /* give only 32 bit DMA addresses */ - if (dma_set_mask(&meye.mchip_dev->dev, DMA_BIT_MASK(32))) - return -1; - - meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - &meye.mchip_dmahandle, - GFP_KERNEL); - if (!meye.mchip_ptable_toc) { - meye.mchip_dmahandle = 0; - return -1; - } - - pt = meye.mchip_ptable_toc; - for (i = 0; i < MCHIP_NB_PAGES; i++) { - dma_addr_t dma; - meye.mchip_ptable[i] = dma_alloc_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - &dma, - GFP_KERNEL); - if (!meye.mchip_ptable[i]) { - int j; - pt = meye.mchip_ptable_toc; - for (j = 0; j < i; ++j) { - dma = (dma_addr_t) *pt; - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable[j], dma); - pt++; - } - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable_toc, - meye.mchip_dmahandle); - meye.mchip_ptable_toc = NULL; - meye.mchip_dmahandle = 0; - return -1; - } - *pt = (u32) dma; - pt++; - } - return 0; -} - -static void ptable_free(void) -{ - u32 *pt; - int i; - - pt = meye.mchip_ptable_toc; - for (i = 0; i < MCHIP_NB_PAGES; i++) { - dma_addr_t dma = (dma_addr_t) *pt; - if (meye.mchip_ptable[i]) - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable[i], dma); - pt++; - } - - if (meye.mchip_ptable_toc) - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable_toc, - meye.mchip_dmahandle); - - memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); - meye.mchip_ptable_toc = NULL; - meye.mchip_dmahandle = 0; -} - -/* copy data from ptable into buf */ -static void ptable_copy(u8 *buf, int start, int size, int pt_pages) -{ - int i; - - for (i = 0; i < (size / PAGE_SIZE) * PAGE_SIZE; i += PAGE_SIZE) { - memcpy(buf + i, meye.mchip_ptable[start++], PAGE_SIZE); - if (start >= pt_pages) - start = 0; - } - memcpy(buf + i, meye.mchip_ptable[start], size % PAGE_SIZE); -} - -/****************************************************************************/ -/* JPEG tables at different qualities to load into the VRJ chip */ -/****************************************************************************/ - -/* return a set of quantisation tables based on a quality from 1 to 10 */ -static u16 *jpeg_quantisation_tables(int *length, int quality) -{ - static u16 jpeg_tables[][70] = { { - 0xdbff, 0x4300, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - 0xdbff, 0x4300, 0xff01, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - }, - { - 0xdbff, 0x4300, 0x5000, 0x3c37, 0x3c46, 0x5032, 0x4146, 0x5a46, - 0x5055, 0x785f, 0x82c8, 0x6e78, 0x786e, 0xaff5, 0x91b9, 0xffc8, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - 0xdbff, 0x4300, 0x5501, 0x5a5a, 0x6978, 0xeb78, 0x8282, 0xffeb, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - }, - { - 0xdbff, 0x4300, 0x2800, 0x1e1c, 0x1e23, 0x2819, 0x2123, 0x2d23, - 0x282b, 0x3c30, 0x4164, 0x373c, 0x3c37, 0x587b, 0x495d, 0x9164, - 0x9980, 0x8f96, 0x8c80, 0xa08a, 0xe6b4, 0xa0c3, 0xdaaa, 0x8aad, - 0xc88c, 0xcbff, 0xeeda, 0xfff5, 0xffff, 0xc19b, 0xffff, 0xfaff, - 0xe6ff, 0xfffd, 0xfff8, - 0xdbff, 0x4300, 0x2b01, 0x2d2d, 0x353c, 0x763c, 0x4141, 0xf876, - 0x8ca5, 0xf8a5, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, - 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, - 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, - 0xf8f8, 0xf8f8, 0xfff8, - }, - { - 0xdbff, 0x4300, 0x1b00, 0x1412, 0x1417, 0x1b11, 0x1617, 0x1e17, - 0x1b1c, 0x2820, 0x2b42, 0x2528, 0x2825, 0x3a51, 0x303d, 0x6042, - 0x6555, 0x5f64, 0x5d55, 0x6a5b, 0x9978, 0x6a81, 0x9071, 0x5b73, - 0x855d, 0x86b5, 0x9e90, 0xaba3, 0xabad, 0x8067, 0xc9bc, 0xa6ba, - 0x99c7, 0xaba8, 0xffa4, - 0xdbff, 0x4300, 0x1c01, 0x1e1e, 0x2328, 0x4e28, 0x2b2b, 0xa44e, - 0x5d6e, 0xa46e, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, - 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, - 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, - 0xa4a4, 0xa4a4, 0xffa4, - }, - { - 0xdbff, 0x4300, 0x1400, 0x0f0e, 0x0f12, 0x140d, 0x1012, 0x1712, - 0x1415, 0x1e18, 0x2132, 0x1c1e, 0x1e1c, 0x2c3d, 0x242e, 0x4932, - 0x4c40, 0x474b, 0x4640, 0x5045, 0x735a, 0x5062, 0x6d55, 0x4556, - 0x6446, 0x6588, 0x776d, 0x817b, 0x8182, 0x604e, 0x978d, 0x7d8c, - 0x7396, 0x817e, 0xff7c, - 0xdbff, 0x4300, 0x1501, 0x1717, 0x1a1e, 0x3b1e, 0x2121, 0x7c3b, - 0x4653, 0x7c53, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, - 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, - 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, - 0x7c7c, 0x7c7c, 0xff7c, - }, - { - 0xdbff, 0x4300, 0x1000, 0x0c0b, 0x0c0e, 0x100a, 0x0d0e, 0x120e, - 0x1011, 0x1813, 0x1a28, 0x1618, 0x1816, 0x2331, 0x1d25, 0x3a28, - 0x3d33, 0x393c, 0x3833, 0x4037, 0x5c48, 0x404e, 0x5744, 0x3745, - 0x5038, 0x516d, 0x5f57, 0x6762, 0x6768, 0x4d3e, 0x7971, 0x6470, - 0x5c78, 0x6765, 0xff63, - 0xdbff, 0x4300, 0x1101, 0x1212, 0x1518, 0x2f18, 0x1a1a, 0x632f, - 0x3842, 0x6342, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, - 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, - 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, - 0x6363, 0x6363, 0xff63, - }, - { - 0xdbff, 0x4300, 0x0d00, 0x0a09, 0x0a0b, 0x0d08, 0x0a0b, 0x0e0b, - 0x0d0e, 0x130f, 0x1520, 0x1213, 0x1312, 0x1c27, 0x171e, 0x2e20, - 0x3129, 0x2e30, 0x2d29, 0x332c, 0x4a3a, 0x333e, 0x4636, 0x2c37, - 0x402d, 0x4157, 0x4c46, 0x524e, 0x5253, 0x3e32, 0x615a, 0x505a, - 0x4a60, 0x5251, 0xff4f, - 0xdbff, 0x4300, 0x0e01, 0x0e0e, 0x1113, 0x2613, 0x1515, 0x4f26, - 0x2d35, 0x4f35, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, - 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, - 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, - 0x4f4f, 0x4f4f, 0xff4f, - }, - { - 0xdbff, 0x4300, 0x0a00, 0x0707, 0x0708, 0x0a06, 0x0808, 0x0b08, - 0x0a0a, 0x0e0b, 0x1018, 0x0d0e, 0x0e0d, 0x151d, 0x1116, 0x2318, - 0x251f, 0x2224, 0x221f, 0x2621, 0x372b, 0x262f, 0x3429, 0x2129, - 0x3022, 0x3141, 0x3934, 0x3e3b, 0x3e3e, 0x2e25, 0x4944, 0x3c43, - 0x3748, 0x3e3d, 0xff3b, - 0xdbff, 0x4300, 0x0a01, 0x0b0b, 0x0d0e, 0x1c0e, 0x1010, 0x3b1c, - 0x2228, 0x3b28, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, - 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, - 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, - 0x3b3b, 0x3b3b, 0xff3b, - }, - { - 0xdbff, 0x4300, 0x0600, 0x0504, 0x0506, 0x0604, 0x0506, 0x0706, - 0x0607, 0x0a08, 0x0a10, 0x090a, 0x0a09, 0x0e14, 0x0c0f, 0x1710, - 0x1814, 0x1718, 0x1614, 0x1a16, 0x251d, 0x1a1f, 0x231b, 0x161c, - 0x2016, 0x202c, 0x2623, 0x2927, 0x292a, 0x1f19, 0x302d, 0x282d, - 0x2530, 0x2928, 0xff28, - 0xdbff, 0x4300, 0x0701, 0x0707, 0x080a, 0x130a, 0x0a0a, 0x2813, - 0x161a, 0x281a, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, - 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, - 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, - 0x2828, 0x2828, 0xff28, - }, - { - 0xdbff, 0x4300, 0x0300, 0x0202, 0x0203, 0x0302, 0x0303, 0x0403, - 0x0303, 0x0504, 0x0508, 0x0405, 0x0504, 0x070a, 0x0607, 0x0c08, - 0x0c0a, 0x0b0c, 0x0b0a, 0x0d0b, 0x120e, 0x0d10, 0x110e, 0x0b0e, - 0x100b, 0x1016, 0x1311, 0x1514, 0x1515, 0x0f0c, 0x1817, 0x1416, - 0x1218, 0x1514, 0xff14, - 0xdbff, 0x4300, 0x0301, 0x0404, 0x0405, 0x0905, 0x0505, 0x1409, - 0x0b0d, 0x140d, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, - 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, - 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, - 0x1414, 0x1414, 0xff14, - }, - { - 0xdbff, 0x4300, 0x0100, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0xff01, - 0xdbff, 0x4300, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0xff01, - } }; - - if (quality < 0 || quality > 10) { - printk(KERN_WARNING - "meye: invalid quality level %d - using 8\n", quality); - quality = 8; - } - - *length = ARRAY_SIZE(jpeg_tables[quality]); - return jpeg_tables[quality]; -} - -/* return a generic set of huffman tables */ -static u16 *jpeg_huffman_tables(int *length) -{ - static u16 tables[] = { - 0xC4FF, 0xB500, 0x0010, 0x0102, 0x0303, 0x0402, 0x0503, 0x0405, - 0x0004, 0x0100, 0x017D, 0x0302, 0x0400, 0x0511, 0x2112, 0x4131, - 0x1306, 0x6151, 0x2207, 0x1471, 0x8132, 0xA191, 0x2308, 0xB142, - 0x15C1, 0xD152, 0x24F0, 0x6233, 0x8272, 0x0A09, 0x1716, 0x1918, - 0x251A, 0x2726, 0x2928, 0x342A, 0x3635, 0x3837, 0x3A39, 0x4443, - 0x4645, 0x4847, 0x4A49, 0x5453, 0x5655, 0x5857, 0x5A59, 0x6463, - 0x6665, 0x6867, 0x6A69, 0x7473, 0x7675, 0x7877, 0x7A79, 0x8483, - 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, 0xA29A, - 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, 0xB9B8, - 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, 0xD7D6, - 0xD9D8, 0xE1DA, 0xE3E2, 0xE5E4, 0xE7E6, 0xE9E8, 0xF1EA, 0xF3F2, - 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, - 0xC4FF, 0xB500, 0x0011, 0x0102, 0x0402, 0x0304, 0x0704, 0x0405, - 0x0004, 0x0201, 0x0077, 0x0201, 0x1103, 0x0504, 0x3121, 0x1206, - 0x5141, 0x6107, 0x1371, 0x3222, 0x0881, 0x4214, 0xA191, 0xC1B1, - 0x2309, 0x5233, 0x15F0, 0x7262, 0x0AD1, 0x2416, 0xE134, 0xF125, - 0x1817, 0x1A19, 0x2726, 0x2928, 0x352A, 0x3736, 0x3938, 0x433A, - 0x4544, 0x4746, 0x4948, 0x534A, 0x5554, 0x5756, 0x5958, 0x635A, - 0x6564, 0x6766, 0x6968, 0x736A, 0x7574, 0x7776, 0x7978, 0x827A, - 0x8483, 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, - 0xA29A, 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, - 0xB9B8, 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, - 0xD7D6, 0xD9D8, 0xE2DA, 0xE4E3, 0xE6E5, 0xE8E7, 0xEAE9, 0xF3F2, - 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, - 0xC4FF, 0x1F00, 0x0000, 0x0501, 0x0101, 0x0101, 0x0101, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, - 0xFF0B, - 0xC4FF, 0x1F00, 0x0001, 0x0103, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, - 0xFF0B - }; - - *length = ARRAY_SIZE(tables); - return tables; -} - -/****************************************************************************/ -/* MCHIP low-level functions */ -/****************************************************************************/ - -/* returns the horizontal capture size */ -static inline int mchip_hsize(void) -{ - return meye.params.subsample ? 320 : 640; -} - -/* returns the vertical capture size */ -static inline int mchip_vsize(void) -{ - return meye.params.subsample ? 240 : 480; -} - -/* waits for a register to be available */ -static void mchip_sync(int reg) -{ - u32 status; - int i; - - if (reg == MCHIP_MM_FIFO_DATA) { - for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { - status = readl(meye.mchip_mmregs + - MCHIP_MM_FIFO_STATUS); - if (!(status & MCHIP_MM_FIFO_WAIT)) { - printk(KERN_WARNING "meye: fifo not ready\n"); - return; - } - if (status & MCHIP_MM_FIFO_READY) - return; - udelay(1); - } - } else if (reg > 0x80) { - u32 mask = (reg < 0x100) ? MCHIP_HIC_STATUS_MCC_RDY - : MCHIP_HIC_STATUS_VRJ_RDY; - for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { - status = readl(meye.mchip_mmregs + MCHIP_HIC_STATUS); - if (status & mask) - return; - udelay(1); - } - } else - return; - printk(KERN_WARNING - "meye: mchip_sync() timeout on reg 0x%x status=0x%x\n", - reg, status); -} - -/* sets a value into the register */ -static inline void mchip_set(int reg, u32 v) -{ - mchip_sync(reg); - writel(v, meye.mchip_mmregs + reg); -} - -/* get the register value */ -static inline u32 mchip_read(int reg) -{ - mchip_sync(reg); - return readl(meye.mchip_mmregs + reg); -} - -/* wait for a register to become a particular value */ -static inline int mchip_delay(u32 reg, u32 v) -{ - int n = 10; - while (--n && mchip_read(reg) != v) - udelay(1); - return n; -} - -/* setup subsampling */ -static void mchip_subsample(void) -{ - mchip_set(MCHIP_MCC_R_SAMPLING, meye.params.subsample); - mchip_set(MCHIP_MCC_R_XRANGE, mchip_hsize()); - mchip_set(MCHIP_MCC_R_YRANGE, mchip_vsize()); - mchip_set(MCHIP_MCC_B_XRANGE, mchip_hsize()); - mchip_set(MCHIP_MCC_B_YRANGE, mchip_vsize()); - mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); -} - -/* set the framerate into the mchip */ -static void mchip_set_framerate(void) -{ - mchip_set(MCHIP_HIC_S_RATE, meye.params.framerate); -} - -/* load some huffman and quantisation tables into the VRJ chip ready - for JPEG compression */ -static void mchip_load_tables(void) -{ - int i; - int length; - u16 *tables; - - tables = jpeg_huffman_tables(&length); - for (i = 0; i < length; i++) - writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); - - tables = jpeg_quantisation_tables(&length, meye.params.quality); - for (i = 0; i < length; i++) - writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); -} - -/* setup the VRJ parameters in the chip */ -static void mchip_vrj_setup(u8 mode) -{ - mchip_set(MCHIP_VRJ_BUS_MODE, 5); - mchip_set(MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL, 0x1f); - mchip_set(MCHIP_VRJ_PDAT_USE, 1); - mchip_set(MCHIP_VRJ_IRQ_FLAG, 0xa0); - mchip_set(MCHIP_VRJ_MODE_SPECIFY, mode); - mchip_set(MCHIP_VRJ_NUM_LINES, mchip_vsize()); - mchip_set(MCHIP_VRJ_NUM_PIXELS, mchip_hsize()); - mchip_set(MCHIP_VRJ_NUM_COMPONENTS, 0x1b); - mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_LO, 0xFFFF); - mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_HI, 0xFFFF); - mchip_set(MCHIP_VRJ_COMP_DATA_FORMAT, 0xC); - mchip_set(MCHIP_VRJ_RESTART_INTERVAL, 0); - mchip_set(MCHIP_VRJ_SOF1, 0x601); - mchip_set(MCHIP_VRJ_SOF2, 0x1502); - mchip_set(MCHIP_VRJ_SOF3, 0x1503); - mchip_set(MCHIP_VRJ_SOF4, 0x1596); - mchip_set(MCHIP_VRJ_SOS, 0x0ed0); - - mchip_load_tables(); -} - -/* sets the DMA parameters into the chip */ -static void mchip_dma_setup(dma_addr_t dma_addr) -{ - int i; - - mchip_set(MCHIP_MM_PT_ADDR, (u32)dma_addr); - for (i = 0; i < 4; i++) - mchip_set(MCHIP_MM_FIR(i), 0); - meye.mchip_fnum = 0; -} - -/* setup for DMA transfers - also zeros the framebuffer */ -static int mchip_dma_alloc(void) -{ - if (!meye.mchip_dmahandle) - if (ptable_alloc()) - return -1; - return 0; -} - -/* frees the DMA buffer */ -static void mchip_dma_free(void) -{ - if (meye.mchip_dmahandle) { - mchip_dma_setup(0); - ptable_free(); - } -} - -/* stop any existing HIC action and wait for any dma to complete then - reset the dma engine */ -static void mchip_hic_stop(void) -{ - int i, j; - - meye.mchip_mode = MCHIP_HIC_MODE_NOOP; - if (!(mchip_read(MCHIP_HIC_STATUS) & MCHIP_HIC_STATUS_BUSY)) - return; - for (i = 0; i < 20; ++i) { - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP); - mchip_delay(MCHIP_HIC_CMD, 0); - for (j = 0; j < 100; ++j) { - if (mchip_delay(MCHIP_HIC_STATUS, - MCHIP_HIC_STATUS_IDLE)) - return; - msleep(1); - } - printk(KERN_ERR "meye: need to reset HIC!\n"); - - mchip_set(MCHIP_HIC_CTL, MCHIP_HIC_CTL_SOFT_RESET); - msleep(250); - } - printk(KERN_ERR "meye: resetting HIC hanged!\n"); -} - -/****************************************************************************/ -/* MCHIP frame processing functions */ -/****************************************************************************/ - -/* get the next ready frame from the dma engine */ -static u32 mchip_get_frame(void) -{ - u32 v; - - v = mchip_read(MCHIP_MM_FIR(meye.mchip_fnum)); - return v; -} - -/* frees the current frame from the dma engine */ -static void mchip_free_frame(void) -{ - mchip_set(MCHIP_MM_FIR(meye.mchip_fnum), 0); - meye.mchip_fnum++; - meye.mchip_fnum %= 4; -} - -/* read one frame from the framebuffer assuming it was captured using - a uncompressed transfer */ -static void mchip_cont_read_frame(u32 v, u8 *buf, int size) -{ - int pt_id; - - pt_id = (v >> 17) & 0x3FF; - - ptable_copy(buf, pt_id, size, MCHIP_NB_PAGES); -} - -/* read a compressed frame from the framebuffer */ -static int mchip_comp_read_frame(u32 v, u8 *buf, int size) -{ - int pt_start, pt_end, trailer; - int fsize; - int i; - - pt_start = (v >> 19) & 0xFF; - pt_end = (v >> 11) & 0xFF; - trailer = (v >> 1) & 0x3FF; - - if (pt_end < pt_start) - fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE + - pt_end * PAGE_SIZE + trailer * 4; - else - fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4; - - if (fsize > size) { - printk(KERN_WARNING "meye: oversized compressed frame %d\n", - fsize); - return -1; - } - - ptable_copy(buf, pt_start, fsize, MCHIP_NB_PAGES_MJPEG); - -#ifdef MEYE_JPEG_CORRECTION - - /* Some mchip generated jpeg frames are incorrect. In most - * (all ?) of those cases, the final EOI (0xff 0xd9) marker - * is not present at the end of the frame. - * - * Since adding the final marker is not enough to restore - * the jpeg integrity, we drop the frame. - */ - - for (i = fsize - 1; i > 0 && buf[i] == 0xff; i--) ; - - if (i < 2 || buf[i - 1] != 0xff || buf[i] != 0xd9) - return -1; - -#endif - - return fsize; -} - -/* take a picture into SDRAM */ -static void mchip_take_picture(void) -{ - int i; - - mchip_hic_stop(); - mchip_subsample(); - mchip_dma_setup(meye.mchip_dmahandle); - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - - for (i = 0; i < 100; ++i) { - if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) - break; - msleep(1); - } -} - -/* dma a previously taken picture into a buffer */ -static void mchip_get_picture(u8 *buf, int bufsize) -{ - u32 v; - int i; - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_OUT); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - for (i = 0; i < 100; ++i) { - if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) - break; - msleep(1); - } - for (i = 0; i < 4; ++i) { - v = mchip_get_frame(); - if (v & MCHIP_MM_FIR_RDY) { - mchip_cont_read_frame(v, buf, bufsize); - break; - } - mchip_free_frame(); - } -} - -/* start continuous dma capture */ -static void mchip_continuous_start(void) -{ - mchip_hic_stop(); - mchip_subsample(); - mchip_set_framerate(); - mchip_dma_setup(meye.mchip_dmahandle); - - meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_OUT); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); -} - -/* compress one frame into a buffer */ -static int mchip_compress_frame(u8 *buf, int bufsize) -{ - u32 v; - int len = -1, i; - - mchip_vrj_setup(0x3f); - udelay(50); - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_COMP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - for (i = 0; i < 100; ++i) { - if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) - break; - msleep(1); - } - - for (i = 0; i < 4; ++i) { - v = mchip_get_frame(); - if (v & MCHIP_MM_FIR_RDY) { - len = mchip_comp_read_frame(v, buf, bufsize); - break; - } - mchip_free_frame(); - } - return len; -} - -#if 0 -/* uncompress one image into a buffer */ -static int mchip_uncompress_frame(u8 *img, int imgsize, u8 *buf, int bufsize) -{ - mchip_vrj_setup(0x3f); - udelay(50); - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_DECOMP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - - return mchip_comp_read_frame(buf, bufsize); -} -#endif - -/* start continuous compressed capture */ -static void mchip_cont_compression_start(void) -{ - mchip_hic_stop(); - mchip_vrj_setup(0x3f); - mchip_subsample(); - mchip_set_framerate(); - mchip_dma_setup(meye.mchip_dmahandle); - - meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_COMP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); -} - -/****************************************************************************/ -/* Interrupt handling */ -/****************************************************************************/ - -static irqreturn_t meye_irq(int irq, void *dev_id) -{ - u32 v; - int reqnr; - static int sequence; - - v = mchip_read(MCHIP_MM_INTA); - - if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT && - meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) - return IRQ_NONE; - -again: - v = mchip_get_frame(); - if (!(v & MCHIP_MM_FIR_RDY)) - return IRQ_HANDLED; - - if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) { - if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, - sizeof(int), &meye.grabq_lock) != sizeof(int)) { - mchip_free_frame(); - return IRQ_HANDLED; - } - mchip_cont_read_frame(v, meye.grab_fbuffer + gbufsize * reqnr, - mchip_hsize() * mchip_vsize() * 2); - meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2; - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); - meye.grab_buffer[reqnr].sequence = sequence++; - kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, - sizeof(int), &meye.doneq_lock); - wake_up_interruptible(&meye.proc_list); - } else { - int size; - size = mchip_comp_read_frame(v, meye.grab_temp, gbufsize); - if (size == -1) { - mchip_free_frame(); - goto again; - } - if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, - sizeof(int), &meye.grabq_lock) != sizeof(int)) { - mchip_free_frame(); - goto again; - } - memcpy(meye.grab_fbuffer + gbufsize * reqnr, meye.grab_temp, - size); - meye.grab_buffer[reqnr].size = size; - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); - meye.grab_buffer[reqnr].sequence = sequence++; - kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, - sizeof(int), &meye.doneq_lock); - wake_up_interruptible(&meye.proc_list); - } - mchip_free_frame(); - goto again; -} - -/****************************************************************************/ -/* video4linux integration */ -/****************************************************************************/ - -static int meye_open(struct file *file) -{ - int i; - - if (test_and_set_bit(0, &meye.in_use)) - return -EBUSY; - - mchip_hic_stop(); - - if (mchip_dma_alloc()) { - printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); - clear_bit(0, &meye.in_use); - return -ENOBUFS; - } - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; - kfifo_reset(&meye.grabq); - kfifo_reset(&meye.doneq); - return 0; -} - -static int meye_release(struct file *file) -{ - mchip_hic_stop(); - mchip_dma_free(); - clear_bit(0, &meye.in_use); - return 0; -} - -static int meyeioc_g_params(struct meye_params *p) -{ - *p = meye.params; - return 0; -} - -static int meyeioc_s_params(struct meye_params *jp) -{ - if (jp->subsample > 1) - return -EINVAL; - - if (jp->quality > 10) - return -EINVAL; - - if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63) - return -EINVAL; - - if (jp->framerate > 31) - return -EINVAL; - - mutex_lock(&meye.lock); - - if (meye.params.subsample != jp->subsample || - meye.params.quality != jp->quality) - mchip_hic_stop(); /* need restart */ - - meye.params = *jp; - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, - meye.params.sharpness); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, - meye.params.agc); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, - meye.params.picture); - mutex_unlock(&meye.lock); - - return 0; -} - -static int meyeioc_qbuf_capt(int *nb) -{ - if (!meye.grab_fbuffer) - return -EINVAL; - - if (*nb >= gbuffers) - return -EINVAL; - - if (*nb < 0) { - /* stop capture */ - mchip_hic_stop(); - return 0; - } - - if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED) - return -EBUSY; - - mutex_lock(&meye.lock); - - if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) - mchip_cont_compression_start(); - - meye.grab_buffer[*nb].state = MEYE_BUF_USING; - kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int), - &meye.grabq_lock); - mutex_unlock(&meye.lock); - - return 0; -} - -static int meyeioc_sync(struct file *file, void *fh, int *i) -{ - int unused; - - if (*i < 0 || *i >= gbuffers) - return -EINVAL; - - mutex_lock(&meye.lock); - switch (meye.grab_buffer[*i].state) { - - case MEYE_BUF_UNUSED: - mutex_unlock(&meye.lock); - return -EINVAL; - case MEYE_BUF_USING: - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - if (wait_event_interruptible(meye.proc_list, - (meye.grab_buffer[*i].state != MEYE_BUF_USING))) { - mutex_unlock(&meye.lock); - return -EINTR; - } - /* fall through */ - case MEYE_BUF_DONE: - meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; - if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused, - sizeof(int), &meye.doneq_lock) != sizeof(int)) - break; - } - *i = meye.grab_buffer[*i].size; - mutex_unlock(&meye.lock); - return 0; -} - -static int meyeioc_stillcapt(void) -{ - if (!meye.grab_fbuffer) - return -EINVAL; - - if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) - return -EBUSY; - - mutex_lock(&meye.lock); - meye.grab_buffer[0].state = MEYE_BUF_USING; - mchip_take_picture(); - - mchip_get_picture(meye.grab_fbuffer, - mchip_hsize() * mchip_vsize() * 2); - - meye.grab_buffer[0].state = MEYE_BUF_DONE; - mutex_unlock(&meye.lock); - - return 0; -} - -static int meyeioc_stilljcapt(int *len) -{ - if (!meye.grab_fbuffer) - return -EINVAL; - - if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) - return -EBUSY; - - mutex_lock(&meye.lock); - meye.grab_buffer[0].state = MEYE_BUF_USING; - *len = -1; - - while (*len == -1) { - mchip_take_picture(); - *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); - } - - meye.grab_buffer[0].state = MEYE_BUF_DONE; - mutex_unlock(&meye.lock); - return 0; -} - -static int vidioc_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) -{ - strcpy(cap->driver, "meye"); - strcpy(cap->card, "meye"); - sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev)); - - cap->version = (MEYE_DRIVER_MAJORVERSION << 8) + - MEYE_DRIVER_MINORVERSION; - - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING; - - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - strcpy(i->name, "Camera"); - i->type = V4L2_INPUT_TYPE_CAMERA; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int i) -{ - if (i != 0) - return -EINVAL; - - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *fh, - struct v4l2_queryctrl *c) -{ - switch (c->id) { - - case V4L2_CID_BRIGHTNESS: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Brightness"); - c->minimum = 0; - c->maximum = 63; - c->step = 1; - c->default_value = 32; - c->flags = 0; - break; - case V4L2_CID_HUE: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Hue"); - c->minimum = 0; - c->maximum = 63; - c->step = 1; - c->default_value = 32; - c->flags = 0; - break; - case V4L2_CID_CONTRAST: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Contrast"); - c->minimum = 0; - c->maximum = 63; - c->step = 1; - c->default_value = 32; - c->flags = 0; - break; - case V4L2_CID_SATURATION: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Saturation"); - c->minimum = 0; - c->maximum = 63; - c->step = 1; - c->default_value = 32; - c->flags = 0; - break; - case V4L2_CID_AGC: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Agc"); - c->minimum = 0; - c->maximum = 63; - c->step = 1; - c->default_value = 48; - c->flags = 0; - break; - case V4L2_CID_MEYE_SHARPNESS: - case V4L2_CID_SHARPNESS: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Sharpness"); - c->minimum = 0; - c->maximum = 63; - c->step = 1; - c->default_value = 32; - - /* Continue to report legacy private SHARPNESS ctrl but - * say it is disabled in preference to ctrl in the spec - */ - c->flags = (c->id == V4L2_CID_SHARPNESS) ? 0 : - V4L2_CTRL_FLAG_DISABLED; - break; - case V4L2_CID_PICTURE: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Picture"); - c->minimum = 0; - c->maximum = 63; - c->step = 1; - c->default_value = 0; - c->flags = 0; - break; - case V4L2_CID_JPEGQUAL: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "JPEG quality"); - c->minimum = 0; - c->maximum = 10; - c->step = 1; - c->default_value = 8; - c->flags = 0; - break; - case V4L2_CID_FRAMERATE: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Framerate"); - c->minimum = 0; - c->maximum = 31; - c->step = 1; - c->default_value = 0; - c->flags = 0; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) -{ - mutex_lock(&meye.lock); - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value); - meye.brightness = c->value << 10; - break; - case V4L2_CID_HUE: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAHUE, c->value); - meye.hue = c->value << 10; - break; - case V4L2_CID_CONTRAST: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value); - meye.contrast = c->value << 10; - break; - case V4L2_CID_SATURATION: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERACOLOR, c->value); - meye.colour = c->value << 10; - break; - case V4L2_CID_AGC: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAAGC, c->value); - meye.params.agc = c->value; - break; - case V4L2_CID_SHARPNESS: - case V4L2_CID_MEYE_SHARPNESS: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value); - meye.params.sharpness = c->value; - break; - case V4L2_CID_PICTURE: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value); - meye.params.picture = c->value; - break; - case V4L2_CID_JPEGQUAL: - meye.params.quality = c->value; - break; - case V4L2_CID_FRAMERATE: - meye.params.framerate = c->value; - break; - default: - mutex_unlock(&meye.lock); - return -EINVAL; - } - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) -{ - mutex_lock(&meye.lock); - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = meye.brightness >> 10; - break; - case V4L2_CID_HUE: - c->value = meye.hue >> 10; - break; - case V4L2_CID_CONTRAST: - c->value = meye.contrast >> 10; - break; - case V4L2_CID_SATURATION: - c->value = meye.colour >> 10; - break; - case V4L2_CID_AGC: - c->value = meye.params.agc; - break; - case V4L2_CID_SHARPNESS: - case V4L2_CID_MEYE_SHARPNESS: - c->value = meye.params.sharpness; - break; - case V4L2_CID_PICTURE: - c->value = meye.params.picture; - break; - case V4L2_CID_JPEGQUAL: - c->value = meye.params.quality; - break; - case V4L2_CID_FRAMERATE: - c->value = meye.params.framerate; - break; - default: - mutex_unlock(&meye.lock); - return -EINVAL; - } - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - if (f->index > 1) - return -EINVAL; - - if (f->index == 0) { - /* standard YUV 422 capture */ - f->flags = 0; - strcpy(f->description, "YUV422"); - f->pixelformat = V4L2_PIX_FMT_YUYV; - } else { - /* compressed MJPEG capture */ - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strcpy(f->description, "MJPEG"); - f->pixelformat = V4L2_PIX_FMT_MJPEG; - } - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && - f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - if (f->fmt.pix.field != V4L2_FIELD_ANY && - f->fmt.pix.field != V4L2_FIELD_NONE) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - - if (f->fmt.pix.width <= 320) { - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - } else { - f->fmt.pix.width = 640; - f->fmt.pix.height = 480; - } - - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - f->fmt.pix.priv = 0; - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - switch (meye.mchip_mode) { - case MCHIP_HIC_MODE_CONT_OUT: - default: - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - break; - case MCHIP_HIC_MODE_CONT_COMP: - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; - break; - } - - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.width = mchip_hsize(); - f->fmt.pix.height = mchip_vsize(); - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && - f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - if (f->fmt.pix.field != V4L2_FIELD_ANY && - f->fmt.pix.field != V4L2_FIELD_NONE) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - mutex_lock(&meye.lock); - - if (f->fmt.pix.width <= 320) { - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - meye.params.subsample = 1; - } else { - f->fmt.pix.width = 640; - f->fmt.pix.height = 480; - meye.params.subsample = 0; - } - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_YUYV: - meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; - break; - case V4L2_PIX_FMT_MJPEG: - meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; - break; - } - - mutex_unlock(&meye.lock); - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - f->fmt.pix.priv = 0; - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req) -{ - int i; - - if (req->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (meye.grab_fbuffer && req->count == gbuffers) { - /* already allocated, no modifications */ - return 0; - } - - mutex_lock(&meye.lock); - if (meye.grab_fbuffer) { - for (i = 0; i < gbuffers; i++) - if (meye.vma_use_count[i]) { - mutex_unlock(&meye.lock); - return -EINVAL; - } - rvfree(meye.grab_fbuffer, gbuffers * gbufsize); - meye.grab_fbuffer = NULL; - } - - gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS)); - req->count = gbuffers; - meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize); - - if (!meye.grab_fbuffer) { - printk(KERN_ERR "meye: v4l framebuffer allocation" - " failed\n"); - mutex_unlock(&meye.lock); - return -ENOMEM; - } - - for (i = 0; i < gbuffers; i++) - meye.vma_use_count[i] = 0; - - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - unsigned int index = buf->index; - - if (index >= gbuffers) - return -EINVAL; - - buf->bytesused = meye.grab_buffer[index].size; - buf->flags = V4L2_BUF_FLAG_MAPPED; - - if (meye.grab_buffer[index].state == MEYE_BUF_USING) - buf->flags |= V4L2_BUF_FLAG_QUEUED; - - if (meye.grab_buffer[index].state == MEYE_BUF_DONE) - buf->flags |= V4L2_BUF_FLAG_DONE; - - buf->field = V4L2_FIELD_NONE; - buf->timestamp = meye.grab_buffer[index].timestamp; - buf->sequence = meye.grab_buffer[index].sequence; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = index * gbufsize; - buf->length = gbufsize; - - return 0; -} - -static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (buf->index >= gbuffers) - return -EINVAL; - - if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED) - return -EINVAL; - - mutex_lock(&meye.lock); - buf->flags |= V4L2_BUF_FLAG_QUEUED; - buf->flags &= ~V4L2_BUF_FLAG_DONE; - meye.grab_buffer[buf->index].state = MEYE_BUF_USING; - kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index, - sizeof(int), &meye.grabq_lock); - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - int reqnr; - - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - mutex_lock(&meye.lock); - - if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - - if (wait_event_interruptible(meye.proc_list, - kfifo_len(&meye.doneq) != 0) < 0) { - mutex_unlock(&meye.lock); - return -EINTR; - } - - if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr, - sizeof(int), &meye.doneq_lock)) { - mutex_unlock(&meye.lock); - return -EBUSY; - } - - if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) { - mutex_unlock(&meye.lock); - return -EINVAL; - } - - buf->index = reqnr; - buf->bytesused = meye.grab_buffer[reqnr].size; - buf->flags = V4L2_BUF_FLAG_MAPPED; - buf->field = V4L2_FIELD_NONE; - buf->timestamp = meye.grab_buffer[reqnr].timestamp; - buf->sequence = meye.grab_buffer[reqnr].sequence; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = reqnr * gbufsize; - buf->length = gbufsize; - meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED; - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) -{ - mutex_lock(&meye.lock); - - switch (meye.mchip_mode) { - case MCHIP_HIC_MODE_CONT_OUT: - mchip_continuous_start(); - break; - case MCHIP_HIC_MODE_CONT_COMP: - mchip_cont_compression_start(); - break; - default: - mutex_unlock(&meye.lock); - return -EINVAL; - } - - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) -{ - mutex_lock(&meye.lock); - mchip_hic_stop(); - kfifo_reset(&meye.grabq); - kfifo_reset(&meye.doneq); - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; - - mutex_unlock(&meye.lock); - return 0; -} - -static long vidioc_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) -{ - switch (cmd) { - case MEYEIOC_G_PARAMS: - return meyeioc_g_params((struct meye_params *) arg); - - case MEYEIOC_S_PARAMS: - return meyeioc_s_params((struct meye_params *) arg); - - case MEYEIOC_QBUF_CAPT: - return meyeioc_qbuf_capt((int *) arg); - - case MEYEIOC_SYNC: - return meyeioc_sync(file, fh, (int *) arg); - - case MEYEIOC_STILLCAPT: - return meyeioc_stillcapt(); - - case MEYEIOC_STILLJCAPT: - return meyeioc_stilljcapt((int *) arg); - - default: - return -EINVAL; - } - -} - -static unsigned int meye_poll(struct file *file, poll_table *wait) -{ - unsigned int res = 0; - - mutex_lock(&meye.lock); - poll_wait(file, &meye.proc_list, wait); - if (kfifo_len(&meye.doneq)) - res = POLLIN | POLLRDNORM; - mutex_unlock(&meye.lock); - return res; -} - -static void meye_vm_open(struct vm_area_struct *vma) -{ - long idx = (long)vma->vm_private_data; - meye.vma_use_count[idx]++; -} - -static void meye_vm_close(struct vm_area_struct *vma) -{ - long idx = (long)vma->vm_private_data; - meye.vma_use_count[idx]--; -} - -static const struct vm_operations_struct meye_vm_ops = { - .open = meye_vm_open, - .close = meye_vm_close, -}; - -static int meye_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long page, pos; - - mutex_lock(&meye.lock); - if (size > gbuffers * gbufsize) { - mutex_unlock(&meye.lock); - return -EINVAL; - } - if (!meye.grab_fbuffer) { - int i; - - /* lazy allocation */ - meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize); - if (!meye.grab_fbuffer) { - printk(KERN_ERR "meye: v4l framebuffer allocation failed\n"); - mutex_unlock(&meye.lock); - return -ENOMEM; - } - for (i = 0; i < gbuffers; i++) - meye.vma_use_count[i] = 0; - } - pos = (unsigned long)meye.grab_fbuffer + offset; - - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - vma->vm_ops = &meye_vm_ops; - vma->vm_flags &= ~VM_IO; /* not I/O memory */ - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ - vma->vm_private_data = (void *) (offset / gbufsize); - meye_vm_open(vma); - - mutex_unlock(&meye.lock); - return 0; -} - -static const struct v4l2_file_operations meye_fops = { - .owner = THIS_MODULE, - .open = meye_open, - .release = meye_release, - .mmap = meye_mmap, - .unlocked_ioctl = video_ioctl2, - .poll = meye_poll, -}; - -static const struct v4l2_ioctl_ops meye_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_default = vidioc_default, -}; - -static struct video_device meye_template = { - .name = "meye", - .fops = &meye_fops, - .ioctl_ops = &meye_ioctl_ops, - .release = video_device_release, -}; - -#ifdef CONFIG_PM -static int meye_suspend(struct pci_dev *pdev, pm_message_t state) -{ - pci_save_state(pdev); - meye.pm_mchip_mode = meye.mchip_mode; - mchip_hic_stop(); - mchip_set(MCHIP_MM_INTA, 0x0); - return 0; -} - -static int meye_resume(struct pci_dev *pdev) -{ - pci_restore_state(pdev); - pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); - - mchip_delay(MCHIP_HIC_CMD, 0); - mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); - msleep(1); - mchip_set(MCHIP_VRJ_SOFT_RESET, 1); - msleep(1); - mchip_set(MCHIP_MM_PCI_MODE, 5); - msleep(1); - mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); - - switch (meye.pm_mchip_mode) { - case MCHIP_HIC_MODE_CONT_OUT: - mchip_continuous_start(); - break; - case MCHIP_HIC_MODE_CONT_COMP: - mchip_cont_compression_start(); - break; - } - return 0; -} -#endif - -static int __devinit meye_probe(struct pci_dev *pcidev, - const struct pci_device_id *ent) -{ - struct v4l2_device *v4l2_dev = &meye.v4l2_dev; - int ret = -EBUSY; - unsigned long mchip_adr; - - if (meye.mchip_dev != NULL) { - printk(KERN_ERR "meye: only one device allowed!\n"); - goto outnotdev; - } - - ret = v4l2_device_register(&pcidev->dev, v4l2_dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return ret; - } - ret = -ENOMEM; - meye.mchip_dev = pcidev; - meye.vdev = video_device_alloc(); - if (!meye.vdev) { - v4l2_err(v4l2_dev, "video_device_alloc() failed!\n"); - goto outnotdev; - } - - meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE); - if (!meye.grab_temp) { - v4l2_err(v4l2_dev, "grab buffer allocation failed\n"); - goto outvmalloc; - } - - spin_lock_init(&meye.grabq_lock); - if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); - goto outkfifoalloc1; - } - spin_lock_init(&meye.doneq_lock); - if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); - goto outkfifoalloc2; - } - - memcpy(meye.vdev, &meye_template, sizeof(meye_template)); - meye.vdev->v4l2_dev = &meye.v4l2_dev; - - ret = -EIO; - if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) { - v4l2_err(v4l2_dev, "meye: unable to power on the camera\n"); - v4l2_err(v4l2_dev, "meye: did you enable the camera in " - "sonypi using the module options ?\n"); - goto outsonypienable; - } - - if ((ret = pci_enable_device(meye.mchip_dev))) { - v4l2_err(v4l2_dev, "meye: pci_enable_device failed\n"); - goto outenabledev; - } - - mchip_adr = pci_resource_start(meye.mchip_dev,0); - if (!mchip_adr) { - v4l2_err(v4l2_dev, "meye: mchip has no device base address\n"); - goto outregions; - } - if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0), - pci_resource_len(meye.mchip_dev, 0), - "meye")) { - v4l2_err(v4l2_dev, "meye: request_mem_region failed\n"); - goto outregions; - } - meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS); - if (!meye.mchip_mmregs) { - v4l2_err(v4l2_dev, "meye: ioremap failed\n"); - goto outremap; - } - - meye.mchip_irq = pcidev->irq; - if (request_irq(meye.mchip_irq, meye_irq, - IRQF_DISABLED | IRQF_SHARED, "meye", meye_irq)) { - v4l2_err(v4l2_dev, "request_irq failed\n"); - goto outreqirq; - } - - pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8); - pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64); - - pci_set_master(meye.mchip_dev); - - /* Ask the camera to perform a soft reset. */ - pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); - - mchip_delay(MCHIP_HIC_CMD, 0); - mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); - - msleep(1); - mchip_set(MCHIP_VRJ_SOFT_RESET, 1); - - msleep(1); - mchip_set(MCHIP_MM_PCI_MODE, 5); - - msleep(1); - mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); - - mutex_init(&meye.lock); - init_waitqueue_head(&meye.proc_list); - meye.brightness = 32 << 10; - meye.hue = 32 << 10; - meye.colour = 32 << 10; - meye.contrast = 32 << 10; - meye.params.subsample = 0; - meye.params.quality = 8; - meye.params.sharpness = 32; - meye.params.agc = 48; - meye.params.picture = 0; - meye.params.framerate = 0; - - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48); - - if (video_register_device(meye.vdev, VFL_TYPE_GRABBER, - video_nr) < 0) { - v4l2_err(v4l2_dev, "video_register_device failed\n"); - goto outvideoreg; - } - - v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n", - MEYE_DRIVER_VERSION); - v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n", - meye.mchip_dev->revision, mchip_adr, meye.mchip_irq); - - return 0; - -outvideoreg: - free_irq(meye.mchip_irq, meye_irq); -outreqirq: - iounmap(meye.mchip_mmregs); -outremap: - release_mem_region(pci_resource_start(meye.mchip_dev, 0), - pci_resource_len(meye.mchip_dev, 0)); -outregions: - pci_disable_device(meye.mchip_dev); -outenabledev: - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); -outsonypienable: - kfifo_free(&meye.doneq); -outkfifoalloc2: - kfifo_free(&meye.grabq); -outkfifoalloc1: - vfree(meye.grab_temp); -outvmalloc: - video_device_release(meye.vdev); -outnotdev: - return ret; -} - -static void __devexit meye_remove(struct pci_dev *pcidev) -{ - video_unregister_device(meye.vdev); - - mchip_hic_stop(); - - mchip_dma_free(); - - /* disable interrupts */ - mchip_set(MCHIP_MM_INTA, 0x0); - - free_irq(meye.mchip_irq, meye_irq); - - iounmap(meye.mchip_mmregs); - - release_mem_region(pci_resource_start(meye.mchip_dev, 0), - pci_resource_len(meye.mchip_dev, 0)); - - pci_disable_device(meye.mchip_dev); - - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); - - kfifo_free(&meye.doneq); - kfifo_free(&meye.grabq); - - vfree(meye.grab_temp); - - if (meye.grab_fbuffer) { - rvfree(meye.grab_fbuffer, gbuffers*gbufsize); - meye.grab_fbuffer = NULL; - } - - printk(KERN_INFO "meye: removed\n"); -} - -static struct pci_device_id meye_pci_tbl[] = { - { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 }, - { } -}; - -MODULE_DEVICE_TABLE(pci, meye_pci_tbl); - -static struct pci_driver meye_driver = { - .name = "meye", - .id_table = meye_pci_tbl, - .probe = meye_probe, - .remove = __devexit_p(meye_remove), -#ifdef CONFIG_PM - .suspend = meye_suspend, - .resume = meye_resume, -#endif -}; - -static int __init meye_init(void) -{ - gbuffers = max(2, min((int)gbuffers, MEYE_MAX_BUFNBRS)); - if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE) - gbufsize = MEYE_MAX_BUFSIZE; - gbufsize = PAGE_ALIGN(gbufsize); - printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) " - "for capture\n", - gbuffers, - gbufsize / 1024, gbuffers * gbufsize / 1024); - return pci_register_driver(&meye_driver); -} - -static void __exit meye_exit(void) -{ - pci_unregister_driver(&meye_driver); -} - -module_init(meye_init); -module_exit(meye_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/meye.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/meye.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/meye.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/meye.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,324 +0,0 @@ -/* - * Motion Eye video4linux driver for Sony Vaio PictureBook - * - * Copyright (C) 2001-2004 Stelian Pop - * - * Copyright (C) 2001-2002 Alcôve - * - * Copyright (C) 2000 Andrew Tridgell - * - * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. - * - * Some parts borrowed from various video4linux drivers, especially - * bttv-driver.c and zoran.c, see original files for credits. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _MEYE_PRIV_H_ -#define _MEYE_PRIV_H_ - -#define MEYE_DRIVER_MAJORVERSION 1 -#define MEYE_DRIVER_MINORVERSION 14 - -#define MEYE_DRIVER_VERSION __stringify(MEYE_DRIVER_MAJORVERSION) "." \ - __stringify(MEYE_DRIVER_MINORVERSION) - -#include -#include -#include - -/****************************************************************************/ -/* Motion JPEG chip registers */ -/****************************************************************************/ - -/* Motion JPEG chip PCI configuration registers */ -#define MCHIP_PCI_POWER_CSR 0x54 -#define MCHIP_PCI_MCORE_STATUS 0x60 /* see HIC_STATUS */ -#define MCHIP_PCI_HOSTUSEREQ_SET 0x64 -#define MCHIP_PCI_HOSTUSEREQ_CLR 0x68 -#define MCHIP_PCI_LOWPOWER_SET 0x6c -#define MCHIP_PCI_LOWPOWER_CLR 0x70 -#define MCHIP_PCI_SOFTRESET_SET 0x74 - -/* Motion JPEG chip memory mapped registers */ -#define MCHIP_MM_REGS 0x200 /* 512 bytes */ -#define MCHIP_REG_TIMEOUT 1000 /* reg access, ~us */ -#define MCHIP_MCC_VRJ_TIMEOUT 1000 /* MCC & VRJ access */ - -#define MCHIP_MM_PCI_MODE 0x00 /* PCI access mode */ -#define MCHIP_MM_PCI_MODE_RETRY 0x00000001 /* retry mode */ -#define MCHIP_MM_PCI_MODE_MASTER 0x00000002 /* master access */ -#define MCHIP_MM_PCI_MODE_READ_LINE 0x00000004 /* read line */ - -#define MCHIP_MM_INTA 0x04 /* Int status/mask */ -#define MCHIP_MM_INTA_MCC 0x00000001 /* MCC interrupt */ -#define MCHIP_MM_INTA_VRJ 0x00000002 /* VRJ interrupt */ -#define MCHIP_MM_INTA_HIC_1 0x00000004 /* one frame done */ -#define MCHIP_MM_INTA_HIC_1_MASK 0x00000400 /* 1: enable */ -#define MCHIP_MM_INTA_HIC_END 0x00000008 /* all frames done */ -#define MCHIP_MM_INTA_HIC_END_MASK 0x00000800 -#define MCHIP_MM_INTA_JPEG 0x00000010 /* decompress. error */ -#define MCHIP_MM_INTA_JPEG_MASK 0x00001000 -#define MCHIP_MM_INTA_CAPTURE 0x00000020 /* capture end */ -#define MCHIP_MM_INTA_PCI_ERR 0x00000040 /* PCI error */ -#define MCHIP_MM_INTA_PCI_ERR_MASK 0x00004000 - -#define MCHIP_MM_PT_ADDR 0x08 /* page table address*/ - /* n*4kB */ -#define MCHIP_NB_PAGES 1024 /* pages for display */ -#define MCHIP_NB_PAGES_MJPEG 256 /* pages for mjpeg */ - -#define MCHIP_MM_FIR(n) (0x0c+(n)*4) /* Frame info 0-3 */ -#define MCHIP_MM_FIR_RDY 0x00000001 /* frame ready */ -#define MCHIP_MM_FIR_FAILFR_MASK 0xf8000000 /* # of failed frames */ -#define MCHIP_MM_FIR_FAILFR_SHIFT 27 - - /* continuous comp/decomp mode */ -#define MCHIP_MM_FIR_C_ENDL_MASK 0x000007fe /* end DW [10] */ -#define MCHIP_MM_FIR_C_ENDL_SHIFT 1 -#define MCHIP_MM_FIR_C_ENDP_MASK 0x0007f800 /* end page [8] */ -#define MCHIP_MM_FIR_C_ENDP_SHIFT 11 -#define MCHIP_MM_FIR_C_STARTP_MASK 0x07f80000 /* start page [8] */ -#define MCHIP_MM_FIR_C_STARTP_SHIFT 19 - - /* continuous picture output mode */ -#define MCHIP_MM_FIR_O_STARTP_MASK 0x7ffe0000 /* start page [10] */ -#define MCHIP_MM_FIR_O_STARTP_SHIFT 17 - -#define MCHIP_MM_FIFO_DATA 0x1c /* PCI TGT FIFO data */ -#define MCHIP_MM_FIFO_STATUS 0x20 /* PCI TGT FIFO stat */ -#define MCHIP_MM_FIFO_MASK 0x00000003 -#define MCHIP_MM_FIFO_WAIT_OR_READY 0x00000002 /* Bits common to WAIT & READY*/ -#define MCHIP_MM_FIFO_IDLE 0x0 /* HIC idle */ -#define MCHIP_MM_FIFO_IDLE1 0x1 /* idem ??? */ -#define MCHIP_MM_FIFO_WAIT 0x2 /* wait request */ -#define MCHIP_MM_FIFO_READY 0x3 /* data ready */ - -#define MCHIP_HIC_HOST_USEREQ 0x40 /* host uses MCORE */ - -#define MCHIP_HIC_TP_BUSY 0x44 /* taking picture */ - -#define MCHIP_HIC_PIC_SAVED 0x48 /* pic in SDRAM */ - -#define MCHIP_HIC_LOWPOWER 0x4c /* clock stopped */ - -#define MCHIP_HIC_CTL 0x50 /* HIC control */ -#define MCHIP_HIC_CTL_SOFT_RESET 0x00000001 /* MCORE reset */ -#define MCHIP_HIC_CTL_MCORE_RDY 0x00000002 /* MCORE ready */ - -#define MCHIP_HIC_CMD 0x54 /* HIC command */ -#define MCHIP_HIC_CMD_BITS 0x00000003 /* cmd width=[1:0]*/ -#define MCHIP_HIC_CMD_NOOP 0x0 -#define MCHIP_HIC_CMD_START 0x1 -#define MCHIP_HIC_CMD_STOP 0x2 - -#define MCHIP_HIC_MODE 0x58 -#define MCHIP_HIC_MODE_NOOP 0x0 -#define MCHIP_HIC_MODE_STILL_CAP 0x1 /* still pic capt */ -#define MCHIP_HIC_MODE_DISPLAY 0x2 /* display */ -#define MCHIP_HIC_MODE_STILL_COMP 0x3 /* still pic comp. */ -#define MCHIP_HIC_MODE_STILL_DECOMP 0x4 /* still pic decomp. */ -#define MCHIP_HIC_MODE_CONT_COMP 0x5 /* cont capt+comp */ -#define MCHIP_HIC_MODE_CONT_DECOMP 0x6 /* cont decomp+disp */ -#define MCHIP_HIC_MODE_STILL_OUT 0x7 /* still pic output */ -#define MCHIP_HIC_MODE_CONT_OUT 0x8 /* cont output */ - -#define MCHIP_HIC_STATUS 0x5c -#define MCHIP_HIC_STATUS_MCC_RDY 0x00000001 /* MCC reg acc ok */ -#define MCHIP_HIC_STATUS_VRJ_RDY 0x00000002 /* VRJ reg acc ok */ -#define MCHIP_HIC_STATUS_IDLE 0x00000003 -#define MCHIP_HIC_STATUS_CAPDIS 0x00000004 /* cap/disp in prog */ -#define MCHIP_HIC_STATUS_COMPDEC 0x00000008 /* (de)comp in prog */ -#define MCHIP_HIC_STATUS_BUSY 0x00000010 /* HIC busy */ - -#define MCHIP_HIC_S_RATE 0x60 /* MJPEG # frames */ - -#define MCHIP_HIC_PCI_VFMT 0x64 /* video format */ -#define MCHIP_HIC_PCI_VFMT_YVYU 0x00000001 /* 0: V Y' U Y */ - /* 1: Y' V Y U */ - -#define MCHIP_MCC_CMD 0x80 /* MCC commands */ -#define MCHIP_MCC_CMD_INITIAL 0x0 /* idle ? */ -#define MCHIP_MCC_CMD_IIC_START_SET 0x1 -#define MCHIP_MCC_CMD_IIC_END_SET 0x2 -#define MCHIP_MCC_CMD_FM_WRITE 0x3 /* frame memory */ -#define MCHIP_MCC_CMD_FM_READ 0x4 -#define MCHIP_MCC_CMD_FM_STOP 0x5 -#define MCHIP_MCC_CMD_CAPTURE 0x6 -#define MCHIP_MCC_CMD_DISPLAY 0x7 -#define MCHIP_MCC_CMD_END_DISP 0x8 -#define MCHIP_MCC_CMD_STILL_COMP 0x9 -#define MCHIP_MCC_CMD_STILL_DECOMP 0xa -#define MCHIP_MCC_CMD_STILL_OUTPUT 0xb -#define MCHIP_MCC_CMD_CONT_OUTPUT 0xc -#define MCHIP_MCC_CMD_CONT_COMP 0xd -#define MCHIP_MCC_CMD_CONT_DECOMP 0xe -#define MCHIP_MCC_CMD_RESET 0xf /* MCC reset */ - -#define MCHIP_MCC_IIC_WR 0x84 - -#define MCHIP_MCC_MCC_WR 0x88 - -#define MCHIP_MCC_MCC_RD 0x8c - -#define MCHIP_MCC_STATUS 0x90 -#define MCHIP_MCC_STATUS_CAPT 0x00000001 /* capturing */ -#define MCHIP_MCC_STATUS_DISP 0x00000002 /* displaying */ -#define MCHIP_MCC_STATUS_COMP 0x00000004 /* compressing */ -#define MCHIP_MCC_STATUS_DECOMP 0x00000008 /* decompressing */ -#define MCHIP_MCC_STATUS_MCC_WR 0x00000010 /* register ready */ -#define MCHIP_MCC_STATUS_MCC_RD 0x00000020 /* register ready */ -#define MCHIP_MCC_STATUS_IIC_WR 0x00000040 /* register ready */ -#define MCHIP_MCC_STATUS_OUTPUT 0x00000080 /* output in prog */ - -#define MCHIP_MCC_SIG_POLARITY 0x94 -#define MCHIP_MCC_SIG_POL_VS_H 0x00000001 /* VS active-high */ -#define MCHIP_MCC_SIG_POL_HS_H 0x00000002 /* HS active-high */ -#define MCHIP_MCC_SIG_POL_DOE_H 0x00000004 /* DOE active-high */ - -#define MCHIP_MCC_IRQ 0x98 -#define MCHIP_MCC_IRQ_CAPDIS_STRT 0x00000001 /* cap/disp started */ -#define MCHIP_MCC_IRQ_CAPDIS_STRT_MASK 0x00000010 -#define MCHIP_MCC_IRQ_CAPDIS_END 0x00000002 /* cap/disp ended */ -#define MCHIP_MCC_IRQ_CAPDIS_END_MASK 0x00000020 -#define MCHIP_MCC_IRQ_COMPDEC_STRT 0x00000004 /* (de)comp started */ -#define MCHIP_MCC_IRQ_COMPDEC_STRT_MASK 0x00000040 -#define MCHIP_MCC_IRQ_COMPDEC_END 0x00000008 /* (de)comp ended */ -#define MCHIP_MCC_IRQ_COMPDEC_END_MASK 0x00000080 - -#define MCHIP_MCC_HSTART 0x9c /* video in */ -#define MCHIP_MCC_VSTART 0xa0 -#define MCHIP_MCC_HCOUNT 0xa4 -#define MCHIP_MCC_VCOUNT 0xa8 -#define MCHIP_MCC_R_XBASE 0xac /* capt/disp */ -#define MCHIP_MCC_R_YBASE 0xb0 -#define MCHIP_MCC_R_XRANGE 0xb4 -#define MCHIP_MCC_R_YRANGE 0xb8 -#define MCHIP_MCC_B_XBASE 0xbc /* comp/decomp */ -#define MCHIP_MCC_B_YBASE 0xc0 -#define MCHIP_MCC_B_XRANGE 0xc4 -#define MCHIP_MCC_B_YRANGE 0xc8 - -#define MCHIP_MCC_R_SAMPLING 0xcc /* 1: 1:4 */ - -#define MCHIP_VRJ_CMD 0x100 /* VRJ commands */ - -/* VRJ registers (see table 12.2.4) */ -#define MCHIP_VRJ_COMPRESSED_DATA 0x1b0 -#define MCHIP_VRJ_PIXEL_DATA 0x1b8 - -#define MCHIP_VRJ_BUS_MODE 0x100 -#define MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL 0x108 -#define MCHIP_VRJ_PDAT_USE 0x110 -#define MCHIP_VRJ_MODE_SPECIFY 0x118 -#define MCHIP_VRJ_LIMIT_COMPRESSED_LO 0x120 -#define MCHIP_VRJ_LIMIT_COMPRESSED_HI 0x124 -#define MCHIP_VRJ_COMP_DATA_FORMAT 0x128 -#define MCHIP_VRJ_TABLE_DATA 0x140 -#define MCHIP_VRJ_RESTART_INTERVAL 0x148 -#define MCHIP_VRJ_NUM_LINES 0x150 -#define MCHIP_VRJ_NUM_PIXELS 0x158 -#define MCHIP_VRJ_NUM_COMPONENTS 0x160 -#define MCHIP_VRJ_SOF1 0x168 -#define MCHIP_VRJ_SOF2 0x170 -#define MCHIP_VRJ_SOF3 0x178 -#define MCHIP_VRJ_SOF4 0x180 -#define MCHIP_VRJ_SOS 0x188 -#define MCHIP_VRJ_SOFT_RESET 0x190 - -#define MCHIP_VRJ_STATUS 0x1c0 -#define MCHIP_VRJ_STATUS_BUSY 0x00001 -#define MCHIP_VRJ_STATUS_COMP_ACCESS 0x00002 -#define MCHIP_VRJ_STATUS_PIXEL_ACCESS 0x00004 -#define MCHIP_VRJ_STATUS_ERROR 0x00008 - -#define MCHIP_VRJ_IRQ_FLAG 0x1c8 -#define MCHIP_VRJ_ERROR_REPORT 0x1d8 - -#define MCHIP_VRJ_START_COMMAND 0x1a0 - -/****************************************************************************/ -/* Driver definitions. */ -/****************************************************************************/ - -/* Sony Programmable I/O Controller for accessing the camera commands */ -#include - -/* private API definitions */ -#include -#include - - -/* Enable jpg software correction */ -#define MEYE_JPEG_CORRECTION 1 - -/* Maximum size of a buffer */ -#define MEYE_MAX_BUFSIZE 614400 /* 640 * 480 * 2 */ - -/* Maximum number of buffers */ -#define MEYE_MAX_BUFNBRS 32 - -/* State of a buffer */ -#define MEYE_BUF_UNUSED 0 /* not used */ -#define MEYE_BUF_USING 1 /* currently grabbing / playing */ -#define MEYE_BUF_DONE 2 /* done */ - -/* grab buffer */ -struct meye_grab_buffer { - int state; /* state of buffer */ - unsigned long size; /* size of jpg frame */ - struct timeval timestamp; /* timestamp */ - unsigned long sequence; /* sequence number */ -}; - -/* size of kfifos containings buffer indices */ -#define MEYE_QUEUE_SIZE MEYE_MAX_BUFNBRS - -/* Motion Eye device structure */ -struct meye { - struct v4l2_device v4l2_dev; /* Main v4l2_device struct */ - struct pci_dev *mchip_dev; /* pci device */ - u8 mchip_irq; /* irq */ - u8 mchip_mode; /* actual mchip mode: HIC_MODE... */ - u8 mchip_fnum; /* current mchip frame number */ - unsigned char __iomem *mchip_mmregs;/* mchip: memory mapped registers */ - u8 *mchip_ptable[MCHIP_NB_PAGES];/* mchip: ptable */ - void *mchip_ptable_toc; /* mchip: ptable toc */ - dma_addr_t mchip_dmahandle; /* mchip: dma handle to ptable toc */ - unsigned char *grab_fbuffer; /* capture framebuffer */ - unsigned char *grab_temp; /* temporary buffer */ - /* list of buffers */ - struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; - int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */ - struct mutex lock; /* mutex for open/mmap... */ - struct kfifo grabq; /* queue for buffers to be grabbed */ - spinlock_t grabq_lock; /* lock protecting the queue */ - struct kfifo doneq; /* queue for grabbed buffers */ - spinlock_t doneq_lock; /* lock protecting the queue */ - wait_queue_head_t proc_list; /* wait queue */ - struct video_device *vdev; /* video device parameters */ - u16 brightness; - u16 hue; - u16 contrast; - u16 colour; - struct meye_params params; /* additional parameters */ - unsigned long in_use; /* set to 1 if the device is in use */ -#ifdef CONFIG_PM - u8 pm_mchip_mode; /* old mchip mode */ -#endif -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-driver.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-driver.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,881 +0,0 @@ -/* - * Programming the mspx4xx sound processor family - * - * (c) 1997-2001 Gerd Knorr - * - * what works and what doesn't: - * - * AM-Mono - * Support for Hauppauge cards added (decoding handled by tuner) added by - * Frederic Crozat - * - * FM-Mono - * should work. The stereo modes are backward compatible to FM-mono, - * therefore FM-Mono should be allways available. - * - * FM-Stereo (B/G, used in germany) - * should work, with autodetect - * - * FM-Stereo (satellite) - * should work, no autodetect (i.e. default is mono, but you can - * switch to stereo -- untested) - * - * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) - * should work, with autodetect. Support for NICAM was added by - * Pekka Pietikainen - * - * TODO: - * - better SAT support - * - * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) - * using soundcore instead of OSS - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msp3400-driver.h" - -/* ---------------------------------------------------------------------- */ - -MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("GPL"); - -/* module parameters */ -static int opmode = OPMODE_AUTO; -int msp_debug; /* msp_debug output */ -int msp_once; /* no continous stereo monitoring */ -int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), - the autoscan seems work well only with FM... */ -int msp_standard = 1; /* Override auto detect of audio msp_standard, - if needed. */ -int msp_dolby; - -int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual - (msp34xxg only) 0x00a0-0x03c0 */ - -/* read-only */ -module_param(opmode, int, 0444); - -/* read-write */ -module_param_named(once, msp_once, bool, 0644); -module_param_named(debug, msp_debug, int, 0644); -module_param_named(stereo_threshold, msp_stereo_thresh, int, 0644); -module_param_named(standard, msp_standard, int, 0644); -module_param_named(amsound, msp_amsound, bool, 0644); -module_param_named(dolby, msp_dolby, bool, 0644); - -MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); -MODULE_PARM_DESC(once, "No continuous stereo monitoring"); -MODULE_PARM_DESC(debug, "Enable debug messages [0-3]"); -MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); -MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); -MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); -MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); - -/* ---------------------------------------------------------------------- */ - -/* control subaddress */ -#define I2C_MSP_CONTROL 0x00 -/* demodulator unit subaddress */ -#define I2C_MSP_DEM 0x10 -/* DSP unit subaddress */ -#define I2C_MSP_DSP 0x12 - - -/* ----------------------------------------------------------------------- */ -/* functions for talking to the MSP3400C Sound processor */ - -int msp_reset(struct i2c_client *client) -{ - /* reset and read revision code */ - static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 }; - static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 }; - static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e }; - u8 read[2]; - struct i2c_msg reset[2] = { - { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, - { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, - }; - struct i2c_msg test[2] = { - { client->addr, 0, 3, write }, - { client->addr, I2C_M_RD, 2, read }, - }; - - v4l_dbg(3, msp_debug, client, "msp_reset\n"); - if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || - i2c_transfer(client->adapter, &reset[1], 1) != 1 || - i2c_transfer(client->adapter, test, 2) != 2) { - v4l_err(client, "chip reset failed\n"); - return -1; - } - return 0; -} - -static int msp_read(struct i2c_client *client, int dev, int addr) -{ - int err, retval; - u8 write[3]; - u8 read[2]; - struct i2c_msg msgs[2] = { - { client->addr, 0, 3, write }, - { client->addr, I2C_M_RD, 2, read } - }; - - write[0] = dev + 1; - write[1] = addr >> 8; - write[2] = addr & 0xff; - - for (err = 0; err < 3; err++) { - if (i2c_transfer(client->adapter, msgs, 2) == 2) - break; - v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err, - dev, addr); - schedule_timeout_interruptible(msecs_to_jiffies(10)); - } - if (err == 3) { - v4l_warn(client, "resetting chip, sound will go off.\n"); - msp_reset(client); - return -1; - } - retval = read[0] << 8 | read[1]; - v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", - dev, addr, retval); - return retval; -} - -int msp_read_dem(struct i2c_client *client, int addr) -{ - return msp_read(client, I2C_MSP_DEM, addr); -} - -int msp_read_dsp(struct i2c_client *client, int addr) -{ - return msp_read(client, I2C_MSP_DSP, addr); -} - -static int msp_write(struct i2c_client *client, int dev, int addr, int val) -{ - int err; - u8 buffer[5]; - - buffer[0] = dev; - buffer[1] = addr >> 8; - buffer[2] = addr & 0xff; - buffer[3] = val >> 8; - buffer[4] = val & 0xff; - - v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", - dev, addr, val); - for (err = 0; err < 3; err++) { - if (i2c_master_send(client, buffer, 5) == 5) - break; - v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err, - dev, addr); - schedule_timeout_interruptible(msecs_to_jiffies(10)); - } - if (err == 3) { - v4l_warn(client, "resetting chip, sound will go off.\n"); - msp_reset(client); - return -1; - } - return 0; -} - -int msp_write_dem(struct i2c_client *client, int addr, int val) -{ - return msp_write(client, I2C_MSP_DEM, addr, val); -} - -int msp_write_dsp(struct i2c_client *client, int addr, int val) -{ - return msp_write(client, I2C_MSP_DSP, addr, val); -} - -/* ----------------------------------------------------------------------- * - * bits 9 8 5 - SCART DSP input Select: - * 0 0 0 - SCART 1 to DSP input (reset position) - * 0 1 0 - MONO to DSP input - * 1 0 0 - SCART 2 to DSP input - * 1 1 1 - Mute DSP input - * - * bits 11 10 6 - SCART 1 Output Select: - * 0 0 0 - undefined (reset position) - * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) - * 1 0 0 - MONO input to SCART 1 Output - * 1 1 0 - SCART 1 DA to SCART 1 Output - * 0 0 1 - SCART 2 DA to SCART 1 Output - * 0 1 1 - SCART 1 Input to SCART 1 Output - * 1 1 1 - Mute SCART 1 Output - * - * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): - * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) - * 0 1 0 - SCART 1 Input to SCART 2 Output - * 1 0 0 - MONO input to SCART 2 Output - * 0 0 1 - SCART 2 DA to SCART 2 Output - * 0 1 1 - SCART 2 Input to SCART 2 Output - * 1 1 0 - Mute SCART 2 Output - * - * Bits 4 to 0 should be zero. - * ----------------------------------------------------------------------- */ - -static int scarts[3][9] = { - /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ - /* SCART DSP Input select */ - { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, - /* SCART1 Output select */ - { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, - /* SCART2 Output select */ - { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, -}; - -static char *scart_names[] = { - "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" -}; - -void msp_set_scart(struct i2c_client *client, int in, int out) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - state->in_scart = in; - - if (in >= 0 && in <= 7 && out >= 0 && out <= 2) { - if (-1 == scarts[out][in + 1]) - return; - - state->acb &= ~scarts[out][0]; - state->acb |= scarts[out][in + 1]; - } else - state->acb = 0xf60; /* Mute Input and SCART 1 Output */ - - v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n", - scart_names[in], out, state->acb); - msp_write_dsp(client, 0x13, state->acb); - - /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ - if (state->has_i2s_conf) - msp_write_dem(client, 0x40, state->i2s_mode); -} - -/* ------------------------------------------------------------------------ */ - -static void msp_wake_thread(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - if (NULL == state->kthread) - return; - state->watch_stereo = 0; - state->restart = 1; - wake_up_interruptible(&state->wq); -} - -int msp_sleep(struct msp_state *state, int timeout) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&state->wq, &wait); - if (!kthread_should_stop()) { - if (timeout < 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } else { - schedule_timeout_interruptible - (msecs_to_jiffies(timeout)); - } - } - - remove_wait_queue(&state->wq, &wait); - try_to_freeze(); - return state->restart; -} - -/* ------------------------------------------------------------------------ */ - -static int msp_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct msp_state *state = ctrl_to_state(ctrl); - struct i2c_client *client = v4l2_get_subdevdata(&state->sd); - int val = ctrl->val; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: { - /* audio volume cluster */ - int reallymuted = state->muted->val | state->scan_in_progress; - - if (!reallymuted) - val = (val * 0x7f / 65535) << 8; - - v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", - state->muted->val ? "on" : "off", - state->scan_in_progress ? "yes" : "no", - state->volume->val); - - msp_write_dsp(client, 0x0000, val); - msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1)); - if (state->has_scart2_out_volume) - msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1)); - if (state->has_headphones) - msp_write_dsp(client, 0x0006, val); - break; - } - - case V4L2_CID_AUDIO_BASS: - val = ((val - 32768) * 0x60 / 65535) << 8; - msp_write_dsp(client, 0x0002, val); - if (state->has_headphones) - msp_write_dsp(client, 0x0031, val); - break; - - case V4L2_CID_AUDIO_TREBLE: - val = ((val - 32768) * 0x60 / 65535) << 8; - msp_write_dsp(client, 0x0003, val); - if (state->has_headphones) - msp_write_dsp(client, 0x0032, val); - break; - - case V4L2_CID_AUDIO_LOUDNESS: - val = val ? ((5 * 4) << 8) : 0; - msp_write_dsp(client, 0x0004, val); - if (state->has_headphones) - msp_write_dsp(client, 0x0033, val); - break; - - case V4L2_CID_AUDIO_BALANCE: - val = (u8)((val / 256) - 128); - msp_write_dsp(client, 0x0001, val << 8); - if (state->has_headphones) - msp_write_dsp(client, 0x0030, val << 8); - break; - - default: - return -EINVAL; - } - return 0; -} - -void msp_update_volume(struct msp_state *state) -{ - /* Force an update of the volume/mute cluster */ - v4l2_ctrl_lock(state->volume); - state->volume->val = state->volume->cur.val; - state->muted->val = state->muted->cur.val; - msp_s_ctrl(state->volume); - v4l2_ctrl_unlock(state->volume); -} - -/* --- v4l2 ioctls --- */ -static int msp_s_radio(struct v4l2_subdev *sd) -{ - struct msp_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (state->radio) - return 0; - state->radio = 1; - v4l_dbg(1, msp_debug, client, "switching to radio mode\n"); - state->watch_stereo = 0; - switch (state->opmode) { - case OPMODE_MANUAL: - /* set msp3400 to FM radio mode */ - msp3400c_set_mode(client, MSP_MODE_FM_RADIO); - msp3400c_set_carrier(client, MSP_CARRIER(10.7), - MSP_CARRIER(10.7)); - msp_update_volume(state); - break; - case OPMODE_AUTODETECT: - case OPMODE_AUTOSELECT: - /* the thread will do for us */ - msp_wake_thread(client); - break; - } - return 0; -} - -static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* new channel -- kick audio carrier scan */ - msp_wake_thread(client); - return 0; -} - -static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id) -{ - struct msp_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int update = state->radio || state->v4l2_std != id; - - state->v4l2_std = id; - state->radio = 0; - if (update) - msp_wake_thread(client); - return 0; -} - -static int msp_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct msp_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int tuner = (input >> 3) & 1; - int sc_in = input & 0x7; - int sc1_out = output & 0xf; - int sc2_out = (output >> 4) & 0xf; - u16 val, reg; - int i; - int extern_input = 1; - - if (state->route_in == input && state->route_out == output) - return 0; - state->route_in = input; - state->route_out = output; - /* check if the tuner input is used */ - for (i = 0; i < 5; i++) { - if (((input >> (4 + i * 4)) & 0xf) == 0) - extern_input = 0; - } - state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT; - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp_set_scart(client, sc_in, 0); - msp_set_scart(client, sc1_out, 1); - msp_set_scart(client, sc2_out, 2); - msp_set_audmode(client); - reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb; - val = msp_read_dem(client, reg); - msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8)); - /* wake thread when a new input is chosen */ - msp_wake_thread(client); - return 0; -} - -static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct msp_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (state->radio) - return 0; - if (state->opmode == OPMODE_AUTOSELECT) - msp_detect_stereo(client); - vt->audmode = state->audmode; - vt->rxsubchans = state->rxsubchans; - vt->capability |= V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - return 0; -} - -static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct msp_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (state->radio) /* TODO: add mono/stereo support for radio */ - return 0; - if (state->audmode == vt->audmode) - return 0; - state->audmode = vt->audmode; - /* only set audmode */ - msp_set_audmode(client); - return 0; -} - -static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) -{ - struct msp_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq); - - switch (freq) { - case 1024000: - state->i2s_mode = 0; - break; - case 2048000: - state->i2s_mode = 1; - break; - default: - return -EINVAL; - } - return 0; -} - -static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct msp_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, state->ident, - (state->rev1 << 16) | state->rev2); -} - -static int msp_log_status(struct v4l2_subdev *sd) -{ - struct msp_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - const char *p; - char prefix[V4L2_SUBDEV_NAME_SIZE + 20]; - - if (state->opmode == OPMODE_AUTOSELECT) - msp_detect_stereo(client); - v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", - client->name, state->rev1, state->rev2); - snprintf(prefix, sizeof(prefix), "%s: Audio: ", sd->name); - v4l2_ctrl_handler_log_status(&state->hdl, prefix); - switch (state->mode) { - case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; - case MSP_MODE_FM_RADIO: p = "FM Radio"; break; - case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; - case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; - case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; - case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; - case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break; - case MSP_MODE_BTSC: p = "BTSC"; break; - case MSP_MODE_EXTERN: p = "External input"; break; - default: p = "unknown"; break; - } - if (state->mode == MSP_MODE_EXTERN) { - v4l_info(client, "Mode: %s\n", p); - } else if (state->opmode == OPMODE_MANUAL) { - v4l_info(client, "Mode: %s (%s%s)\n", p, - (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", - (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); - } else { - if (state->opmode == OPMODE_AUTODETECT) - v4l_info(client, "Mode: %s\n", p); - v4l_info(client, "Standard: %s (%s%s)\n", - msp_standard_std_name(state->std), - (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", - (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); - } - v4l_info(client, "Audmode: 0x%04x\n", state->audmode); - v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", - state->route_in, state->route_out); - v4l_info(client, "ACB: 0x%04x\n", state->acb); - return 0; -} - -static int msp_suspend(struct i2c_client *client, pm_message_t state) -{ - v4l_dbg(1, msp_debug, client, "suspend\n"); - msp_reset(client); - return 0; -} - -static int msp_resume(struct i2c_client *client) -{ - v4l_dbg(1, msp_debug, client, "resume\n"); - msp_wake_thread(client); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops msp_ctrl_ops = { - .s_ctrl = msp_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops msp_core_ops = { - .log_status = msp_log_status, - .g_chip_ident = msp_g_chip_ident, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = msp_s_std, -}; - -static const struct v4l2_subdev_tuner_ops msp_tuner_ops = { - .s_frequency = msp_s_frequency, - .g_tuner = msp_g_tuner, - .s_tuner = msp_s_tuner, - .s_radio = msp_s_radio, -}; - -static const struct v4l2_subdev_audio_ops msp_audio_ops = { - .s_routing = msp_s_routing, - .s_i2s_clock_freq = msp_s_i2s_clock_freq, -}; - -static const struct v4l2_subdev_ops msp_ops = { - .core = &msp_core_ops, - .tuner = &msp_tuner_ops, - .audio = &msp_audio_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct msp_state *state; - struct v4l2_subdev *sd; - struct v4l2_ctrl_handler *hdl; - int (*thread_func)(void *data) = NULL; - int msp_hard; - int msp_family; - int msp_revision; - int msp_product, msp_prod_hi, msp_prod_lo; - int msp_rom; - - if (!id) - strlcpy(client->name, "msp3400", sizeof(client->name)); - - if (msp_reset(client) == -1) { - v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); - return -ENODEV; - } - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return -ENOMEM; - - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &msp_ops); - - state->v4l2_std = V4L2_STD_NTSC; - state->audmode = V4L2_TUNER_MODE_STEREO; - state->input = -1; - state->i2s_mode = 0; - init_waitqueue_head(&state->wq); - /* These are the reset input/output positions */ - state->route_in = MSP_INPUT_DEFAULT; - state->route_out = MSP_OUTPUT_DEFAULT; - - state->rev1 = msp_read_dsp(client, 0x1e); - if (state->rev1 != -1) - state->rev2 = msp_read_dsp(client, 0x1f); - v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", - state->rev1, state->rev2); - if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { - v4l_dbg(1, msp_debug, client, - "not an msp3400 (cannot read chip version)\n"); - kfree(state); - return -ENODEV; - } - - msp_family = ((state->rev1 >> 4) & 0x0f) + 3; - msp_product = (state->rev2 >> 8) & 0xff; - msp_prod_hi = msp_product / 10; - msp_prod_lo = msp_product % 10; - msp_revision = (state->rev1 & 0x0f) + '@'; - msp_hard = ((state->rev1 >> 8) & 0xff) + '@'; - msp_rom = state->rev2 & 0x1f; - /* Rev B=2, C=3, D=4, G=7 */ - state->ident = msp_family * 10000 + 4000 + msp_product * 10 + - msp_revision - '@'; - - /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ - state->has_nicam = - msp_prod_hi == 1 || msp_prod_hi == 5; - /* Has radio support: was added with revision G */ - state->has_radio = - msp_revision >= 'G'; - /* Has headphones output: not for stripped down products */ - state->has_headphones = - msp_prod_lo < 5; - /* Has scart2 input: not in stripped down products of the '3' family */ - state->has_scart2 = - msp_family >= 4 || msp_prod_lo < 7; - /* Has scart3 input: not in stripped down products of the '3' family */ - state->has_scart3 = - msp_family >= 4 || msp_prod_lo < 5; - /* Has scart4 input: not in pre D revisions, not in stripped D revs */ - state->has_scart4 = - msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); - /* Has scart2 output: not in stripped down products of - * the '3' family */ - state->has_scart2_out = - msp_family >= 4 || msp_prod_lo < 5; - /* Has scart2 a volume control? Not in pre-D revisions. */ - state->has_scart2_out_volume = - msp_revision > 'C' && state->has_scart2_out; - /* Has a configurable i2s out? */ - state->has_i2s_conf = - msp_revision >= 'G' && msp_prod_lo < 7; - /* Has subwoofer output: not in pre-D revs and not in stripped down - * products */ - state->has_subwoofer = - msp_revision >= 'D' && msp_prod_lo < 5; - /* Has soundprocessing (bass/treble/balance/loudness/equalizer): - * not in stripped down products */ - state->has_sound_processing = - msp_prod_lo < 7; - /* Has Virtual Dolby Surround: only in msp34x1 */ - state->has_virtual_dolby_surround = - msp_revision == 'G' && msp_prod_lo == 1; - /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */ - state->has_dolby_pro_logic = - msp_revision == 'G' && msp_prod_lo == 2; - /* The msp343xG supports BTSC only and cannot do Automatic Standard - * Detection. */ - state->force_btsc = - msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; - - state->opmode = opmode; - if (state->opmode == OPMODE_AUTO) { - /* MSP revision G and up have both autodetect and autoselect */ - if (msp_revision >= 'G') - state->opmode = OPMODE_AUTOSELECT; - /* MSP revision D and up have autodetect */ - else if (msp_revision >= 'D') - state->opmode = OPMODE_AUTODETECT; - else - state->opmode = OPMODE_MANUAL; - } - - hdl = &state->hdl; - v4l2_ctrl_handler_init(hdl, 6); - if (state->has_sound_processing) { - v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, - V4L2_CID_AUDIO_BASS, 0, 65535, 65535 / 100, 32768); - v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, - V4L2_CID_AUDIO_TREBLE, 0, 65535, 65535 / 100, 32768); - v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, - V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 0); - } - state->volume = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 58880); - v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768); - state->muted = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - sd->ctrl_handler = hdl; - if (hdl->error) { - int err = hdl->error; - - v4l2_ctrl_handler_free(hdl); - kfree(state); - return err; - } - - v4l2_ctrl_cluster(2, &state->volume); - v4l2_ctrl_handler_setup(hdl); - - /* hello world :-) */ - v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n", - msp_family, msp_product, - msp_revision, msp_hard, msp_rom, - client->addr << 1, client->adapter->name); - v4l_info(client, "%s ", client->name); - if (state->has_nicam && state->has_radio) - printk(KERN_CONT "supports nicam and radio, "); - else if (state->has_nicam) - printk(KERN_CONT "supports nicam, "); - else if (state->has_radio) - printk(KERN_CONT "supports radio, "); - printk(KERN_CONT "mode is "); - - /* version-specific initialization */ - switch (state->opmode) { - case OPMODE_MANUAL: - printk(KERN_CONT "manual"); - thread_func = msp3400c_thread; - break; - case OPMODE_AUTODETECT: - printk(KERN_CONT "autodetect"); - thread_func = msp3410d_thread; - break; - case OPMODE_AUTOSELECT: - printk(KERN_CONT "autodetect and autoselect"); - thread_func = msp34xxg_thread; - break; - } - printk(KERN_CONT "\n"); - - /* startup control thread if needed */ - if (thread_func) { - state->kthread = kthread_run(thread_func, client, "msp34xx"); - - if (IS_ERR(state->kthread)) - v4l_warn(client, "kernel_thread() failed\n"); - msp_wake_thread(client); - } - return 0; -} - -static int msp_remove(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - v4l2_device_unregister_subdev(&state->sd); - /* shutdown control thread */ - if (state->kthread) { - state->restart = 1; - kthread_stop(state->kthread); - } - msp_reset(client); - - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id msp_id[] = { - { "msp3400", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, msp_id); - -static struct i2c_driver msp_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "msp3400", - }, - .probe = msp_probe, - .remove = msp_remove, - .suspend = msp_suspend, - .resume = msp_resume, - .id_table = msp_id, -}; - -static __init int init_msp(void) -{ - return i2c_add_driver(&msp_driver); -} - -static __exit void exit_msp(void) -{ - i2c_del_driver(&msp_driver); -} - -module_init(init_msp); -module_exit(exit_msp); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-driver.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-driver.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-driver.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-driver.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,137 +0,0 @@ -/* - */ - -#ifndef MSP3400_DRIVER_H -#define MSP3400_DRIVER_H - -#include -#include -#include - -/* ---------------------------------------------------------------------- */ - -/* This macro is allowed for *constants* only, gcc must calculate it - at compile time. Remember -- no floats in kernel mode */ -#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24))) - -#define MSP_MODE_AM_DETECT 0 -#define MSP_MODE_FM_RADIO 2 -#define MSP_MODE_FM_TERRA 3 -#define MSP_MODE_FM_SAT 4 -#define MSP_MODE_FM_NICAM1 5 -#define MSP_MODE_FM_NICAM2 6 -#define MSP_MODE_AM_NICAM 7 -#define MSP_MODE_BTSC 8 -#define MSP_MODE_EXTERN 9 - -#define SCART_IN1 0 -#define SCART_IN2 1 -#define SCART_IN3 2 -#define SCART_IN4 3 -#define SCART_IN1_DA 4 -#define SCART_IN2_DA 5 -#define SCART_MONO 6 -#define SCART_MUTE 7 - -#define SCART_DSP_IN 0 -#define SCART1_OUT 1 -#define SCART2_OUT 2 - -#define OPMODE_AUTO -1 -#define OPMODE_MANUAL 0 -#define OPMODE_AUTODETECT 1 /* use autodetect (>= msp3410 only) */ -#define OPMODE_AUTOSELECT 2 /* use autodetect & autoselect (>= msp34xxG) */ - -/* module parameters */ -extern int msp_debug; -extern int msp_once; -extern int msp_amsound; -extern int msp_standard; -extern int msp_dolby; -extern int msp_stereo_thresh; - -struct msp_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - int rev1, rev2; - int ident; - u8 has_nicam; - u8 has_radio; - u8 has_headphones; - u8 has_ntsc_jp_d_k3; - u8 has_scart2; - u8 has_scart3; - u8 has_scart4; - u8 has_scart2_out; - u8 has_scart2_out_volume; - u8 has_i2s_conf; - u8 has_subwoofer; - u8 has_sound_processing; - u8 has_virtual_dolby_surround; - u8 has_dolby_pro_logic; - u8 force_btsc; - - int radio; - int opmode; - int std; - int mode; - v4l2_std_id v4l2_std; - int nicam_on; - int acb; - int in_scart; - int i2s_mode; - int main, second; /* sound carrier */ - int input; - u32 route_in; - u32 route_out; - - /* v4l2 */ - int audmode; - int rxsubchans; - - struct { - /* volume cluster */ - struct v4l2_ctrl *volume; - struct v4l2_ctrl *muted; - }; - - int scan_in_progress; - - /* thread */ - struct task_struct *kthread; - wait_queue_head_t wq; - unsigned int restart:1; - unsigned int watch_stereo:1; -}; - -static inline struct msp_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct msp_state, sd); -} - -static inline struct msp_state *ctrl_to_state(struct v4l2_ctrl *ctrl) -{ - return container_of(ctrl->handler, struct msp_state, hdl); -} - -/* msp3400-driver.c */ -int msp_write_dem(struct i2c_client *client, int addr, int val); -int msp_write_dsp(struct i2c_client *client, int addr, int val); -int msp_read_dem(struct i2c_client *client, int addr); -int msp_read_dsp(struct i2c_client *client, int addr); -int msp_reset(struct i2c_client *client); -void msp_set_scart(struct i2c_client *client, int in, int out); -void msp_update_volume(struct msp_state *state); -int msp_sleep(struct msp_state *state, int timeout); - -/* msp3400-kthreads.c */ -const char *msp_standard_std_name(int std); -void msp_set_audmode(struct i2c_client *client); -int msp_detect_stereo(struct i2c_client *client); -int msp3400c_thread(void *data); -int msp3410d_thread(void *data); -int msp34xxg_thread(void *data); -void msp3400c_set_mode(struct i2c_client *client, int mode); -void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2); - -#endif /* MSP3400_DRIVER_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-kthreads.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-kthreads.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-kthreads.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/msp3400-kthreads.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1123 +0,0 @@ -/* - * Programming the mspx4xx sound processor family - * - * (c) 1997-2001 Gerd Knorr - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msp3400-driver.h" - -/* this one uses the automatic sound standard detection of newer msp34xx - chip versions */ -static struct { - int retval; - int main, second; - char *name; -} msp_stdlist[] = { - { 0x0000, 0, 0, "could not detect sound standard" }, - { 0x0001, 0, 0, "autodetect start" }, - { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, - { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, - { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, - { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, - { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, - { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), "6.5/5.74 D/K3 Dual FM-Stereo" }, - { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, - { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, - { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, - { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, - { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, - { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV3)" }, - { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, - { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, - { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, - { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, - { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, - { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, - { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, - { -1, 0, 0, NULL }, /* EOF */ -}; - -static struct msp3400c_init_data_dem { - int fir1[6]; - int fir2[6]; - int cdo1; - int cdo2; - int ad_cv; - int mode_reg; - int dsp_src; - int dsp_matrix; -} msp3400c_init_data[] = { - { /* AM (for carrier detect / msp3400) */ - {75, 19, 36, 35, 39, 40}, - {75, 19, 36, 35, 39, 40}, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0500, 0x0020, 0x3000 - }, { /* AM (for carrier detect / msp3410) */ - {-1, -1, -8, 2, 59, 126}, - {-1, -1, -8, 2, 59, 126}, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0100, 0x0020, 0x3000 - }, { /* FM Radio */ - {-8, -8, 4, 6, 78, 107}, - {-8, -8, 4, 6, 78, 107}, - MSP_CARRIER(10.7), MSP_CARRIER(10.7), - 0x00d0, 0x0480, 0x0020, 0x3000 - }, { /* Terrestial FM-mono + FM-stereo */ - {3, 18, 27, 48, 66, 72}, - {3, 18, 27, 48, 66, 72}, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0480, 0x0030, 0x3000 - }, { /* Sat FM-mono */ - { 1, 9, 14, 24, 33, 37}, - { 3, 18, 27, 48, 66, 72}, - MSP_CARRIER(6.5), MSP_CARRIER(6.5), - 0x00c6, 0x0480, 0x0000, 0x3000 - }, { /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ - {-2, -8, -10, 10, 50, 86}, - {3, 18, 27, 48, 66, 72}, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0040, 0x0120, 0x3000 - }, { /* NICAM/FM -- I (6.0/6.552) */ - {2, 4, -6, -4, 40, 94}, - {3, 18, 27, 48, 66, 72}, - MSP_CARRIER(6.0), MSP_CARRIER(6.0), - 0x00d0, 0x0040, 0x0120, 0x3000 - }, { /* NICAM/AM -- L (6.5/5.85) */ - {-2, -8, -10, 10, 50, 86}, - {-4, -12, -9, 23, 79, 126}, - MSP_CARRIER(6.5), MSP_CARRIER(6.5), - 0x00c6, 0x0140, 0x0120, 0x7c00 - }, -}; - -struct msp3400c_carrier_detect { - int cdo; - char *name; -}; - -static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = { - /* main carrier */ - { MSP_CARRIER(4.5), "4.5 NTSC" }, - { MSP_CARRIER(5.5), "5.5 PAL B/G" }, - { MSP_CARRIER(6.0), "6.0 PAL I" }, - { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } -}; - -static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = { - /* PAL B/G */ - { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, - { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } -}; - -static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = { - /* PAL SAT / SECAM */ - { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, - { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, - { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, - { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, - { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, - { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, -}; - -/* ------------------------------------------------------------------------ */ - -const char *msp_standard_std_name(int std) -{ - int i; - - for (i = 0; msp_stdlist[i].name != NULL; i++) - if (msp_stdlist[i].retval == std) - return msp_stdlist[i].name; - return "unknown"; -} - -static void msp_set_source(struct i2c_client *client, u16 src) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - if (msp_dolby) { - msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */ - msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */ - } else { - msp_write_dsp(client, 0x0008, src); - msp_write_dsp(client, 0x0009, src); - } - msp_write_dsp(client, 0x000a, src); - msp_write_dsp(client, 0x000b, src); - msp_write_dsp(client, 0x000c, src); - if (state->has_scart2_out) - msp_write_dsp(client, 0x0041, src); -} - -void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2) -{ - msp_write_dem(client, 0x0093, cdo1 & 0xfff); - msp_write_dem(client, 0x009b, cdo1 >> 12); - msp_write_dem(client, 0x00a3, cdo2 & 0xfff); - msp_write_dem(client, 0x00ab, cdo2 >> 12); - msp_write_dem(client, 0x0056, 0); /* LOAD_REG_1/2 */ -} - -void msp3400c_set_mode(struct i2c_client *client, int mode) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode]; - int tuner = (state->route_in >> 3) & 1; - int i; - - v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode); - state->mode = mode; - state->rxsubchans = V4L2_TUNER_SUB_MONO; - - msp_write_dem(client, 0x00bb, data->ad_cv | (tuner ? 0x100 : 0)); - - for (i = 5; i >= 0; i--) /* fir 1 */ - msp_write_dem(client, 0x0001, data->fir1[i]); - - msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */ - msp_write_dem(client, 0x0005, 0x0040); - msp_write_dem(client, 0x0005, 0x0000); - for (i = 5; i >= 0; i--) - msp_write_dem(client, 0x0005, data->fir2[i]); - - msp_write_dem(client, 0x0083, data->mode_reg); - - msp3400c_set_carrier(client, data->cdo1, data->cdo2); - - msp_set_source(client, data->dsp_src); - /* set prescales */ - - /* volume prescale for SCART (AM mono input) */ - msp_write_dsp(client, 0x000d, 0x1900); - msp_write_dsp(client, 0x000e, data->dsp_matrix); - if (state->has_nicam) /* nicam prescale */ - msp_write_dsp(client, 0x0010, 0x5a00); -} - -/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP, - nor do they support stereo BTSC. */ -static void msp3400c_set_audmode(struct i2c_client *client) -{ - static char *strmode[] = { - "mono", "stereo", "lang2", "lang1", "lang1+lang2" - }; - struct msp_state *state = to_state(i2c_get_clientdata(client)); - char *modestr = (state->audmode >= 0 && state->audmode < 5) ? - strmode[state->audmode] : "unknown"; - int src = 0; /* channel source: FM/AM, nicam or SCART */ - int audmode = state->audmode; - - if (state->opmode == OPMODE_AUTOSELECT) { - /* this method would break everything, let's make sure - * it's never called - */ - v4l_dbg(1, msp_debug, client, - "set_audmode called with mode=%d instead of set_source (ignored)\n", - state->audmode); - return; - } - - /* Note: for the C and D revs no NTSC stereo + SAP is possible as - the hardware does not support SAP. So the rxsubchans combination - of STEREO | LANG2 does not occur. */ - - if (state->mode != MSP_MODE_EXTERN) { - /* switch to mono if only mono is available */ - if (state->rxsubchans == V4L2_TUNER_SUB_MONO) - audmode = V4L2_TUNER_MODE_MONO; - /* if bilingual */ - else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) { - /* and mono or stereo, then fallback to lang1 */ - if (audmode == V4L2_TUNER_MODE_MONO || - audmode == V4L2_TUNER_MODE_STEREO) - audmode = V4L2_TUNER_MODE_LANG1; - } - /* if stereo, and audmode is not mono, then switch to stereo */ - else if (audmode != V4L2_TUNER_MODE_MONO) - audmode = V4L2_TUNER_MODE_STEREO; - } - - /* switch demodulator */ - switch (state->mode) { - case MSP_MODE_FM_TERRA: - v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr); - switch (audmode) { - case V4L2_TUNER_MODE_STEREO: - msp_write_dsp(client, 0x000e, 0x3001); - break; - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - case V4L2_TUNER_MODE_LANG2: - case V4L2_TUNER_MODE_LANG1_LANG2: - msp_write_dsp(client, 0x000e, 0x3000); - break; - } - break; - case MSP_MODE_FM_SAT: - v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr); - switch (audmode) { - case V4L2_TUNER_MODE_MONO: - msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); - break; - case V4L2_TUNER_MODE_LANG1: - msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); - break; - case V4L2_TUNER_MODE_LANG2: - msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); - break; - } - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - case MSP_MODE_AM_NICAM: - v4l_dbg(1, msp_debug, client, - "NICAM set_audmode: %s\n", modestr); - if (state->nicam_on) - src = 0x0100; /* NICAM */ - break; - case MSP_MODE_BTSC: - v4l_dbg(1, msp_debug, client, - "BTSC set_audmode: %s\n", modestr); - break; - case MSP_MODE_EXTERN: - v4l_dbg(1, msp_debug, client, - "extern set_audmode: %s\n", modestr); - src = 0x0200; /* SCART */ - break; - case MSP_MODE_FM_RADIO: - v4l_dbg(1, msp_debug, client, - "FM-Radio set_audmode: %s\n", modestr); - break; - default: - v4l_dbg(1, msp_debug, client, "mono set_audmode\n"); - return; - } - - /* switch audio */ - v4l_dbg(1, msp_debug, client, "set audmode %d\n", audmode); - switch (audmode) { - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - src |= 0x0020; - break; - case V4L2_TUNER_MODE_MONO: - if (state->mode == MSP_MODE_AM_NICAM) { - v4l_dbg(1, msp_debug, client, "switching to AM mono\n"); - /* AM mono decoding is handled by tuner, not MSP chip */ - /* SCART switching control register */ - msp_set_scart(client, SCART_MONO, 0); - src = 0x0200; - break; - } - if (state->rxsubchans & V4L2_TUNER_SUB_STEREO) - src = 0x0030; - break; - case V4L2_TUNER_MODE_LANG1: - break; - case V4L2_TUNER_MODE_LANG2: - src |= 0x0010; - break; - } - v4l_dbg(1, msp_debug, client, - "set_audmode final source/matrix = 0x%x\n", src); - - msp_set_source(client, src); -} - -static void msp3400c_print_mode(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - if (state->main == state->second) - v4l_dbg(1, msp_debug, client, - "mono sound carrier: %d.%03d MHz\n", - state->main / 910000, (state->main / 910) % 1000); - else - v4l_dbg(1, msp_debug, client, - "main sound carrier: %d.%03d MHz\n", - state->main / 910000, (state->main / 910) % 1000); - if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) - v4l_dbg(1, msp_debug, client, - "NICAM/FM carrier : %d.%03d MHz\n", - state->second / 910000, (state->second/910) % 1000); - if (state->mode == MSP_MODE_AM_NICAM) - v4l_dbg(1, msp_debug, client, - "NICAM/AM carrier : %d.%03d MHz\n", - state->second / 910000, (state->second / 910) % 1000); - if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) { - v4l_dbg(1, msp_debug, client, - "FM-stereo carrier : %d.%03d MHz\n", - state->second / 910000, (state->second / 910) % 1000); - } -} - -/* ----------------------------------------------------------------------- */ - -static int msp3400c_detect_stereo(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - int val; - int rxsubchans = state->rxsubchans; - int newnicam = state->nicam_on; - int update = 0; - - switch (state->mode) { - case MSP_MODE_FM_TERRA: - val = msp_read_dsp(client, 0x18); - if (val > 32767) - val -= 65536; - v4l_dbg(2, msp_debug, client, - "stereo detect register: %d\n", val); - if (val > 8192) { - rxsubchans = V4L2_TUNER_SUB_STEREO; - } else if (val < -4096) { - rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - } else { - rxsubchans = V4L2_TUNER_SUB_MONO; - } - newnicam = 0; - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - case MSP_MODE_AM_NICAM: - val = msp_read_dem(client, 0x23); - v4l_dbg(2, msp_debug, client, "nicam sync=%d, mode=%d\n", - val & 1, (val & 0x1e) >> 1); - - if (val & 1) { - /* nicam synced */ - switch ((val & 0x1e) >> 1) { - case 0: - case 8: - rxsubchans = V4L2_TUNER_SUB_STEREO; - break; - case 1: - case 9: - rxsubchans = V4L2_TUNER_SUB_MONO; - break; - case 2: - case 10: - rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - break; - default: - rxsubchans = V4L2_TUNER_SUB_MONO; - break; - } - newnicam = 1; - } else { - newnicam = 0; - rxsubchans = V4L2_TUNER_SUB_MONO; - } - break; - } - if (rxsubchans != state->rxsubchans) { - update = 1; - v4l_dbg(1, msp_debug, client, - "watch: rxsubchans %02x => %02x\n", - state->rxsubchans, rxsubchans); - state->rxsubchans = rxsubchans; - } - if (newnicam != state->nicam_on) { - update = 1; - v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n", - state->nicam_on, newnicam); - state->nicam_on = newnicam; - } - return update; -} - -/* - * A kernel thread for msp3400 control -- we don't want to block the - * in the ioctl while doing the sound carrier & stereo detect - */ -/* stereo/multilang monitoring */ -static void watch_stereo(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - if (msp_detect_stereo(client)) - msp_set_audmode(client); - - if (msp_once) - state->watch_stereo = 0; -} - -int msp3400c_thread(void *data) -{ - struct i2c_client *client = data; - struct msp_state *state = to_state(i2c_get_clientdata(client)); - struct msp3400c_carrier_detect *cd; - int count, max1, max2, val1, val2, val, i; - - v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); - set_freezable(); - for (;;) { - v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n"); - msp_sleep(state, -1); - v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n"); - -restart: - v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); - state->restart = 0; - if (kthread_should_stop()) - break; - - if (state->radio || MSP_MODE_EXTERN == state->mode) { - /* no carrier scan, just unmute */ - v4l_dbg(1, msp_debug, client, - "thread: no carrier scan\n"); - state->scan_in_progress = 0; - msp_update_volume(state); - continue; - } - - /* mute audio */ - state->scan_in_progress = 1; - msp_update_volume(state); - - msp3400c_set_mode(client, MSP_MODE_AM_DETECT); - val1 = val2 = 0; - max1 = max2 = -1; - state->watch_stereo = 0; - state->nicam_on = 0; - - /* wait for tuner to settle down after a channel change */ - if (msp_sleep(state, 200)) - goto restart; - - /* carrier detect pass #1 -- main carrier */ - cd = msp3400c_carrier_detect_main; - count = ARRAY_SIZE(msp3400c_carrier_detect_main); - - if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) { - /* autodetect doesn't work well with AM ... */ - max1 = 3; - count = 0; - v4l_dbg(1, msp_debug, client, "AM sound override\n"); - } - - for (i = 0; i < count; i++) { - msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); - if (msp_sleep(state, 100)) - goto restart; - val = msp_read_dsp(client, 0x1b); - if (val > 32767) - val -= 65536; - if (val1 < val) - val1 = val, max1 = i; - v4l_dbg(1, msp_debug, client, - "carrier1 val: %5d / %s\n", val, cd[i].name); - } - - /* carrier detect pass #2 -- second (stereo) carrier */ - switch (max1) { - case 1: /* 5.5 */ - cd = msp3400c_carrier_detect_55; - count = ARRAY_SIZE(msp3400c_carrier_detect_55); - break; - case 3: /* 6.5 */ - cd = msp3400c_carrier_detect_65; - count = ARRAY_SIZE(msp3400c_carrier_detect_65); - break; - case 0: /* 4.5 */ - case 2: /* 6.0 */ - default: - cd = NULL; - count = 0; - break; - } - - if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) { - /* autodetect doesn't work well with AM ... */ - cd = NULL; - count = 0; - max2 = 0; - } - for (i = 0; i < count; i++) { - msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); - if (msp_sleep(state, 100)) - goto restart; - val = msp_read_dsp(client, 0x1b); - if (val > 32767) - val -= 65536; - if (val2 < val) - val2 = val, max2 = i; - v4l_dbg(1, msp_debug, client, - "carrier2 val: %5d / %s\n", val, cd[i].name); - } - - /* program the msp3400 according to the results */ - state->main = msp3400c_carrier_detect_main[max1].cdo; - switch (max1) { - case 1: /* 5.5 */ - if (max2 == 0) { - /* B/G FM-stereo */ - state->second = msp3400c_carrier_detect_55[max2].cdo; - msp3400c_set_mode(client, MSP_MODE_FM_TERRA); - state->watch_stereo = 1; - } else if (max2 == 1 && state->has_nicam) { - /* B/G NICAM */ - state->second = msp3400c_carrier_detect_55[max2].cdo; - msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); - state->nicam_on = 1; - state->watch_stereo = 1; - } else { - goto no_second; - } - break; - case 2: /* 6.0 */ - /* PAL I NICAM */ - state->second = MSP_CARRIER(6.552); - msp3400c_set_mode(client, MSP_MODE_FM_NICAM2); - state->nicam_on = 1; - state->watch_stereo = 1; - break; - case 3: /* 6.5 */ - if (max2 == 1 || max2 == 2) { - /* D/K FM-stereo */ - state->second = msp3400c_carrier_detect_65[max2].cdo; - msp3400c_set_mode(client, MSP_MODE_FM_TERRA); - state->watch_stereo = 1; - } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) { - /* L NICAM or AM-mono */ - state->second = msp3400c_carrier_detect_65[max2].cdo; - msp3400c_set_mode(client, MSP_MODE_AM_NICAM); - state->watch_stereo = 1; - } else if (max2 == 0 && state->has_nicam) { - /* D/K NICAM */ - state->second = msp3400c_carrier_detect_65[max2].cdo; - msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); - state->nicam_on = 1; - state->watch_stereo = 1; - } else { - goto no_second; - } - break; - case 0: /* 4.5 */ - default: -no_second: - state->second = msp3400c_carrier_detect_main[max1].cdo; - msp3400c_set_mode(client, MSP_MODE_FM_TERRA); - break; - } - msp3400c_set_carrier(client, state->second, state->main); - - /* unmute */ - state->scan_in_progress = 0; - msp3400c_set_audmode(client); - msp_update_volume(state); - - if (msp_debug) - msp3400c_print_mode(client); - - /* monitor tv audio mode, the first time don't wait - so long to get a quick stereo/bilingual result */ - count = 3; - while (state->watch_stereo) { - if (msp_sleep(state, count ? 1000 : 5000)) - goto restart; - if (count) - count--; - watch_stereo(client); - } - } - v4l_dbg(1, msp_debug, client, "thread: exit\n"); - return 0; -} - - -int msp3410d_thread(void *data) -{ - struct i2c_client *client = data; - struct msp_state *state = to_state(i2c_get_clientdata(client)); - int val, i, std, count; - - v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); - set_freezable(); - for (;;) { - v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); - msp_sleep(state, -1); - v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n"); - -restart: - v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); - state->restart = 0; - if (kthread_should_stop()) - break; - - if (state->mode == MSP_MODE_EXTERN) { - /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, - "thread: no carrier scan\n"); - state->scan_in_progress = 0; - msp_update_volume(state); - continue; - } - - /* mute audio */ - state->scan_in_progress = 1; - msp_update_volume(state); - - /* start autodetect. Note: autodetect is not supported for - NTSC-M and radio, hence we force the standard in those - cases. */ - if (state->radio) - std = 0x40; - else - std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1; - state->watch_stereo = 0; - state->nicam_on = 0; - - /* wait for tuner to settle down after a channel change */ - if (msp_sleep(state, 200)) - goto restart; - - if (msp_debug) - v4l_dbg(2, msp_debug, client, - "setting standard: %s (0x%04x)\n", - msp_standard_std_name(std), std); - - if (std != 1) { - /* programmed some specific mode */ - val = std; - } else { - /* triggered autodetect */ - msp_write_dem(client, 0x20, std); - for (;;) { - if (msp_sleep(state, 100)) - goto restart; - - /* check results */ - val = msp_read_dem(client, 0x7e); - if (val < 0x07ff) - break; - v4l_dbg(2, msp_debug, client, - "detection still in progress\n"); - } - } - for (i = 0; msp_stdlist[i].name != NULL; i++) - if (msp_stdlist[i].retval == val) - break; - v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n", - msp_standard_std_name(val), val); - state->main = msp_stdlist[i].main; - state->second = msp_stdlist[i].second; - state->std = val; - state->rxsubchans = V4L2_TUNER_SUB_MONO; - - if (msp_amsound && !state->radio && - (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) { - /* autodetection has failed, let backup */ - v4l_dbg(1, msp_debug, client, "autodetection failed," - " switching to backup standard: %s (0x%04x)\n", - msp_stdlist[8].name ? - msp_stdlist[8].name : "unknown", val); - state->std = val = 0x0009; - msp_write_dem(client, 0x20, val); - } - - /* set stereo */ - switch (val) { - case 0x0008: /* B/G NICAM */ - case 0x000a: /* I NICAM */ - case 0x000b: /* D/K NICAM */ - if (val == 0x000a) - state->mode = MSP_MODE_FM_NICAM2; - else - state->mode = MSP_MODE_FM_NICAM1; - /* just turn on stereo */ - state->nicam_on = 1; - state->watch_stereo = 1; - break; - case 0x0009: - state->mode = MSP_MODE_AM_NICAM; - state->nicam_on = 1; - state->watch_stereo = 1; - break; - case 0x0020: /* BTSC */ - /* The pre-'G' models only have BTSC-mono */ - state->mode = MSP_MODE_BTSC; - break; - case 0x0040: /* FM radio */ - state->mode = MSP_MODE_FM_RADIO; - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - /* not needed in theory if we have radio, but - short programming enables carrier mute */ - msp3400c_set_mode(client, MSP_MODE_FM_RADIO); - msp3400c_set_carrier(client, MSP_CARRIER(10.7), - MSP_CARRIER(10.7)); - break; - case 0x0002: - case 0x0003: - case 0x0004: - case 0x0005: - state->mode = MSP_MODE_FM_TERRA; - state->watch_stereo = 1; - break; - } - - /* set various prescales */ - msp_write_dsp(client, 0x0d, 0x1900); /* scart */ - msp_write_dsp(client, 0x0e, 0x3000); /* FM */ - if (state->has_nicam) - msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ - - if (state->has_i2s_conf) - msp_write_dem(client, 0x40, state->i2s_mode); - - /* unmute */ - msp3400c_set_audmode(client); - state->scan_in_progress = 0; - msp_update_volume(state); - - /* monitor tv audio mode, the first time don't wait - so long to get a quick stereo/bilingual result */ - count = 3; - while (state->watch_stereo) { - if (msp_sleep(state, count ? 1000 : 5000)) - goto restart; - if (count) - count--; - watch_stereo(client); - } - } - v4l_dbg(1, msp_debug, client, "thread: exit\n"); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* msp34xxG + (autoselect no-thread) - * this one uses both automatic standard detection and automatic sound - * select which are available in the newer G versions - * struct msp: only norm, acb and source are really used in this mode - */ - -static int msp34xxg_modus(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - if (state->radio) { - v4l_dbg(1, msp_debug, client, "selected radio modus\n"); - return 0x0001; - } - if (state->v4l2_std == V4L2_STD_NTSC_M_JP) { - v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n"); - return 0x4001; - } - if (state->v4l2_std == V4L2_STD_NTSC_M_KR) { - v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n"); - return 0x0001; - } - if (state->v4l2_std == V4L2_STD_SECAM_L) { - v4l_dbg(1, msp_debug, client, "selected SECAM-L modus\n"); - return 0x6001; - } - if (state->v4l2_std & V4L2_STD_MN) { - v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n"); - return 0x2001; - } - return 0x7001; -} - -static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) - { - struct msp_state *state = to_state(i2c_get_clientdata(client)); - int source, matrix; - - switch (state->audmode) { - case V4L2_TUNER_MODE_MONO: - source = 0; /* mono only */ - matrix = 0x30; - break; - case V4L2_TUNER_MODE_LANG2: - source = 4; /* stereo or B */ - matrix = 0x10; - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - source = 1; /* stereo or A|B */ - matrix = 0x20; - break; - case V4L2_TUNER_MODE_LANG1: - source = 3; /* stereo or A */ - matrix = 0x00; - break; - case V4L2_TUNER_MODE_STEREO: - default: - source = 3; /* stereo or A */ - matrix = 0x20; - break; - } - - if (in == MSP_DSP_IN_TUNER) - source = (source << 8) | 0x20; - /* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14 - instead of 11, 12, 13. So we add one for that msp version. */ - else if (in >= MSP_DSP_IN_MAIN_AVC && state->has_dolby_pro_logic) - source = ((in + 1) << 8) | matrix; - else - source = (in << 8) | matrix; - - v4l_dbg(1, msp_debug, client, - "set source to %d (0x%x) for output %02x\n", in, source, reg); - msp_write_dsp(client, reg, source); -} - -static void msp34xxg_set_sources(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - u32 in = state->route_in; - - msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf); - /* quasi-peak detector is set to same input as the loudspeaker (MAIN) */ - msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf); - msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf); - msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf); - if (state->has_scart2_out) - msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf); - msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf); -} - -/* (re-)initialize the msp34xxg */ -static void msp34xxg_reset(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - int tuner = (state->route_in >> 3) & 1; - int modus; - - /* initialize std to 1 (autodetect) to signal that no standard is - selected yet. */ - state->std = 1; - - msp_reset(client); - - if (state->has_i2s_conf) - msp_write_dem(client, 0x40, state->i2s_mode); - - /* step-by-step initialisation, as described in the manual */ - modus = msp34xxg_modus(client); - modus |= tuner ? 0x100 : 0; - msp_write_dem(client, 0x30, modus); - - /* write the dsps that may have an influence on - standard/audio autodetection right now */ - msp34xxg_set_sources(client); - - msp_write_dsp(client, 0x0d, 0x1900); /* scart */ - msp_write_dsp(client, 0x0e, 0x3000); /* FM */ - if (state->has_nicam) - msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ - - /* set identification threshold. Personally, I - * I set it to a higher value than the default - * of 0x190 to ignore noisy stereo signals. - * this needs tuning. (recommended range 0x00a0-0x03c0) - * 0x7f0 = forced mono mode - * - * a2 threshold for stereo/bilingual. - * Note: this register is part of the Manual/Compatibility mode. - * It is supported by all 'G'-family chips. - */ - msp_write_dem(client, 0x22, msp_stereo_thresh); -} - -int msp34xxg_thread(void *data) -{ - struct i2c_client *client = data; - struct msp_state *state = to_state(i2c_get_clientdata(client)); - int val, i; - - v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); - set_freezable(); - for (;;) { - v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n"); - msp_sleep(state, -1); - v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n"); - -restart: - v4l_dbg(1, msp_debug, client, "thread: restart scan\n"); - state->restart = 0; - if (kthread_should_stop()) - break; - - if (state->mode == MSP_MODE_EXTERN) { - /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, - "thread: no carrier scan\n"); - state->scan_in_progress = 0; - msp_update_volume(state); - continue; - } - - /* setup the chip*/ - msp34xxg_reset(client); - state->std = state->radio ? 0x40 : - (state->force_btsc && msp_standard == 1) ? 32 : msp_standard; - msp_write_dem(client, 0x20, state->std); - /* start autodetect */ - if (state->std != 1) - goto unmute; - - /* watch autodetect */ - v4l_dbg(1, msp_debug, client, - "started autodetect, waiting for result\n"); - for (i = 0; i < 10; i++) { - if (msp_sleep(state, 100)) - goto restart; - - /* check results */ - val = msp_read_dem(client, 0x7e); - if (val < 0x07ff) { - state->std = val; - break; - } - v4l_dbg(2, msp_debug, client, - "detection still in progress\n"); - } - if (state->std == 1) { - v4l_dbg(1, msp_debug, client, - "detection still in progress after 10 tries. giving up.\n"); - continue; - } - -unmute: - v4l_dbg(1, msp_debug, client, - "detected standard: %s (0x%04x)\n", - msp_standard_std_name(state->std), state->std); - - if (state->std == 9) { - /* AM NICAM mode */ - msp_write_dsp(client, 0x0e, 0x7c00); - } - - /* unmute: dispatch sound to scart output, set scart volume */ - msp_update_volume(state); - - /* restore ACB */ - if (msp_write_dsp(client, 0x13, state->acb)) - return -1; - - /* the periodic stereo/SAP check is only relevant for - the 0x20 standard (BTSC) */ - if (state->std != 0x20) - continue; - - state->watch_stereo = 1; - - /* monitor tv audio mode, the first time don't wait - in order to get a quick stereo/SAP update */ - watch_stereo(client); - while (state->watch_stereo) { - watch_stereo(client); - if (msp_sleep(state, 5000)) - goto restart; - } - } - v4l_dbg(1, msp_debug, client, "thread: exit\n"); - return 0; -} - -static int msp34xxg_detect_stereo(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - int status = msp_read_dem(client, 0x0200); - int is_bilingual = status & 0x100; - int is_stereo = status & 0x40; - int oldrx = state->rxsubchans; - - if (state->mode == MSP_MODE_EXTERN) - return 0; - - state->rxsubchans = 0; - if (is_stereo) - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - else - state->rxsubchans = V4L2_TUNER_SUB_MONO; - if (is_bilingual) { - if (state->std == 0x20) - state->rxsubchans |= V4L2_TUNER_SUB_SAP; - else - state->rxsubchans = - V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - } - v4l_dbg(1, msp_debug, client, - "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", - status, is_stereo, is_bilingual, state->rxsubchans); - return (oldrx != state->rxsubchans); -} - -static void msp34xxg_set_audmode(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - if (state->std == 0x20) { - if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) && - (state->audmode == V4L2_TUNER_MODE_LANG1_LANG2 || - state->audmode == V4L2_TUNER_MODE_LANG2)) { - msp_write_dem(client, 0x20, 0x21); - } else { - msp_write_dem(client, 0x20, 0x20); - } - } - - msp34xxg_set_sources(client); -} - -void msp_set_audmode(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - switch (state->opmode) { - case OPMODE_MANUAL: - case OPMODE_AUTODETECT: - msp3400c_set_audmode(client); - break; - case OPMODE_AUTOSELECT: - msp34xxg_set_audmode(client); - break; - } -} - -int msp_detect_stereo(struct i2c_client *client) -{ - struct msp_state *state = to_state(i2c_get_clientdata(client)); - - switch (state->opmode) { - case OPMODE_MANUAL: - case OPMODE_AUTODETECT: - return msp3400c_detect_stereo(client); - case OPMODE_AUTOSELECT: - return msp34xxg_detect_stereo(client); - } - return 0; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9m001.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9m001.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9m001.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9m001.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,836 +0,0 @@ -/* - * Driver for MT9M001 CMOS Image Sensor from Micron - * - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include -#include -#include - -/* - * mt9m001 i2c address 0x5d - * The platform has to define ctruct i2c_board_info objects and link to them - * from struct soc_camera_link - */ - -/* mt9m001 selected register addresses */ -#define MT9M001_CHIP_VERSION 0x00 -#define MT9M001_ROW_START 0x01 -#define MT9M001_COLUMN_START 0x02 -#define MT9M001_WINDOW_HEIGHT 0x03 -#define MT9M001_WINDOW_WIDTH 0x04 -#define MT9M001_HORIZONTAL_BLANKING 0x05 -#define MT9M001_VERTICAL_BLANKING 0x06 -#define MT9M001_OUTPUT_CONTROL 0x07 -#define MT9M001_SHUTTER_WIDTH 0x09 -#define MT9M001_FRAME_RESTART 0x0b -#define MT9M001_SHUTTER_DELAY 0x0c -#define MT9M001_RESET 0x0d -#define MT9M001_READ_OPTIONS1 0x1e -#define MT9M001_READ_OPTIONS2 0x20 -#define MT9M001_GLOBAL_GAIN 0x35 -#define MT9M001_CHIP_ENABLE 0xF1 - -#define MT9M001_MAX_WIDTH 1280 -#define MT9M001_MAX_HEIGHT 1024 -#define MT9M001_MIN_WIDTH 48 -#define MT9M001_MIN_HEIGHT 32 -#define MT9M001_COLUMN_SKIP 20 -#define MT9M001_ROW_SKIP 12 - -/* MT9M001 has only one fixed colorspace per pixelcode */ -struct mt9m001_datafmt { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; -}; - -/* Find a data format by a pixel code in an array */ -static const struct mt9m001_datafmt *mt9m001_find_datafmt( - enum v4l2_mbus_pixelcode code, const struct mt9m001_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - -static const struct mt9m001_datafmt mt9m001_colour_fmts[] = { - /* - * Order important: first natively supported, - * second supported with a GPIO extender - */ - {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, -}; - -static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { - /* Order important - see above */ - {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, -}; - -struct mt9m001 { - struct v4l2_subdev subdev; - struct v4l2_rect rect; /* Sensor window */ - const struct mt9m001_datafmt *fmt; - const struct mt9m001_datafmt *fmts; - int num_fmts; - int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ - unsigned int gain; - unsigned int exposure; - unsigned short y_skip_top; /* Lines to skip at the top */ - unsigned char autoexposure; -}; - -static struct mt9m001 *to_mt9m001(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct mt9m001, subdev); -} - -static int reg_read(struct i2c_client *client, const u8 reg) -{ - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : swab16(data); -} - -static int reg_write(struct i2c_client *client, const u8 reg, - const u16 data) -{ - return i2c_smbus_write_word_data(client, reg, swab16(data)); -} - -static int reg_set(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret | data); -} - -static int reg_clear(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret & ~data); -} - -static int mt9m001_init(struct i2c_client *client) -{ - int ret; - - dev_dbg(&client->dev, "%s\n", __func__); - - /* - * We don't know, whether platform provides reset, issue a soft reset - * too. This returns all registers to their default values. - */ - ret = reg_write(client, MT9M001_RESET, 1); - if (!ret) - ret = reg_write(client, MT9M001_RESET, 0); - - /* Disable chip, synchronous option update */ - if (!ret) - ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); - - return ret; -} - -static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* Switch to master "normal" mode or stop sensor readout */ - if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0) - return -EIO; - return 0; -} - -static int mt9m001_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; - - /* Only one width bit may be set */ - if (!is_power_of_2(width_flag)) - return -EINVAL; - - if (icl->set_bus_param) - return icl->set_bus_param(icl, width_flag); - - /* - * Without board specific bus width settings we only support the - * sensors native bus width - */ - if (width_flag == SOCAM_DATAWIDTH_10) - return 0; - - return -EINVAL; -} - -static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - /* MT9M001 has all capture_format parameters fixed */ - unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER; - - if (icl->query_bus_param) - flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct v4l2_rect rect = a->c; - struct soc_camera_device *icd = client->dev.platform_data; - int ret; - const u16 hblank = 9, vblank = 25; - unsigned int total_h; - - if (mt9m001->fmts == mt9m001_colour_fmts) - /* - * Bayer format - even number of rows for simplicity, - * but let the user play with the top row. - */ - rect.height = ALIGN(rect.height, 2); - - /* Datasheet requirement: see register description */ - rect.width = ALIGN(rect.width, 2); - rect.left = ALIGN(rect.left, 2); - - soc_camera_limit_side(&rect.left, &rect.width, - MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH); - - soc_camera_limit_side(&rect.top, &rect.height, - MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); - - total_h = rect.height + mt9m001->y_skip_top + vblank; - - /* Blanking and start values - default... */ - ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); - if (!ret) - ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank); - - /* - * The caller provides a supported format, as verified per - * call to icd->try_fmt() - */ - if (!ret) - ret = reg_write(client, MT9M001_COLUMN_START, rect.left); - if (!ret) - ret = reg_write(client, MT9M001_ROW_START, rect.top); - if (!ret) - ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1); - if (!ret) - ret = reg_write(client, MT9M001_WINDOW_HEIGHT, - rect.height + mt9m001->y_skip_top - 1); - if (!ret && mt9m001->autoexposure) { - ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); - if (!ret) { - const struct v4l2_queryctrl *qctrl = - soc_camera_find_qctrl(icd->ops, - V4L2_CID_EXPOSURE); - mt9m001->exposure = (524 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - 1048 + qctrl->minimum; - } - } - - if (!ret) - mt9m001->rect = rect; - - return ret; -} - -static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - - a->c = mt9m001->rect; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = MT9M001_COLUMN_SKIP; - a->bounds.top = MT9M001_ROW_SKIP; - a->bounds.width = MT9M001_MAX_WIDTH; - a->bounds.height = MT9M001_MAX_HEIGHT; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int mt9m001_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - - mf->width = mt9m001->rect.width; - mf->height = mt9m001->rect.height; - mf->code = mt9m001->fmt->code; - mf->colorspace = mt9m001->fmt->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9m001_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct v4l2_crop a = { - .c = { - .left = mt9m001->rect.left, - .top = mt9m001->rect.top, - .width = mf->width, - .height = mf->height, - }, - }; - int ret; - - /* No support for scaling so far, just crop. TODO: use skipping */ - ret = mt9m001_s_crop(sd, &a); - if (!ret) { - mf->width = mt9m001->rect.width; - mf->height = mt9m001->rect.height; - mt9m001->fmt = mt9m001_find_datafmt(mf->code, - mt9m001->fmts, mt9m001->num_fmts); - mf->colorspace = mt9m001->fmt->colorspace; - } - - return ret; -} - -static int mt9m001_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - const struct mt9m001_datafmt *fmt; - - v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH, - MT9M001_MAX_WIDTH, 1, - &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top, - MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0); - - if (mt9m001->fmts == mt9m001_colour_fmts) - mf->height = ALIGN(mf->height - 1, 2); - - fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts, - mt9m001->num_fmts); - if (!fmt) { - fmt = mt9m001->fmt; - mf->code = fmt->code; - } - - mf->colorspace = fmt->colorspace; - - return 0; -} - -static int mt9m001_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - - if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) - return -EINVAL; - - if (id->match.addr != client->addr) - return -ENODEV; - - id->ident = mt9m001->model; - id->revision = 0; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9m001_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - reg->size = 2; - reg->val = reg_read(client, reg->reg); - - if (reg->val > 0xffff) - return -EIO; - - return 0; -} - -static int mt9m001_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - if (reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static const struct v4l2_queryctrl mt9m001_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9m001_ops = { - .set_bus_param = mt9m001_set_bus_param, - .query_bus_param = mt9m001_query_bus_param, - .controls = mt9m001_controls, - .num_controls = ARRAY_SIZE(mt9m001_controls), -}; - -static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - int data; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, MT9M001_READ_OPTIONS2); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x8000); - break; - case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = mt9m001->autoexposure; - break; - case V4L2_CID_GAIN: - ctrl->value = mt9m001->gain; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = mt9m001->exposure; - break; - } - return 0; -} - -static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_device *icd = client->dev.platform_data; - const struct v4l2_queryctrl *qctrl; - int data; - - qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id); - - if (!qctrl) - return -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->value) - data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); - else - data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); - if (data < 0) - return -EIO; - break; - case V4L2_CID_GAIN: - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - /* See Datasheet Table 7, Gain settings. */ - if (ctrl->value <= qctrl->default_value) { - /* Pack it into 0..1 step 0.125, register values 0..8 */ - unsigned long range = qctrl->default_value - qctrl->minimum; - data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; - - dev_dbg(&client->dev, "Setting gain %d\n", data); - data = reg_write(client, MT9M001_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; - } else { - /* Pack it into 1.125..15 variable step, register values 9..67 */ - /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ - unsigned long range = qctrl->maximum - qctrl->default_value - 1; - unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * - 111 + range / 2) / range + 9; - - if (gain <= 32) - data = gain; - else if (gain <= 64) - data = ((gain - 32) * 16 + 16) / 32 + 80; - else - data = ((gain - 64) * 7 + 28) / 56 + 96; - - dev_dbg(&client->dev, "Setting gain from %d to %d\n", - reg_read(client, MT9M001_GLOBAL_GAIN), data); - data = reg_write(client, MT9M001_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; - } - - /* Success */ - mt9m001->gain = ctrl->value; - break; - case V4L2_CID_EXPOSURE: - /* mt9m001 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - unsigned long range = qctrl->maximum - qctrl->minimum; - unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 + - range / 2) / range + 1; - - dev_dbg(&client->dev, - "Setting shutter width from %d to %lu\n", - reg_read(client, MT9M001_SHUTTER_WIDTH), - shutter); - if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) - return -EIO; - mt9m001->exposure = ctrl->value; - mt9m001->autoexposure = 0; - } - break; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->value) { - const u16 vblank = 25; - unsigned int total_h = mt9m001->rect.height + - mt9m001->y_skip_top + vblank; - if (reg_write(client, MT9M001_SHUTTER_WIDTH, - total_h) < 0) - return -EIO; - qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); - mt9m001->exposure = (524 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - 1048 + qctrl->minimum; - mt9m001->autoexposure = 1; - } else - mt9m001->autoexposure = 0; - break; - } - return 0; -} - -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int mt9m001_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - s32 data; - unsigned long flags; - int ret; - - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; - - /* Enable the chip */ - data = reg_write(client, MT9M001_CHIP_ENABLE, 1); - dev_dbg(&client->dev, "write: %d\n", data); - - /* Read out the chip version register */ - data = reg_read(client, MT9M001_CHIP_VERSION); - - /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ - switch (data) { - case 0x8411: - case 0x8421: - mt9m001->model = V4L2_IDENT_MT9M001C12ST; - mt9m001->fmts = mt9m001_colour_fmts; - break; - case 0x8431: - mt9m001->model = V4L2_IDENT_MT9M001C12STM; - mt9m001->fmts = mt9m001_monochrome_fmts; - break; - default: - dev_err(&client->dev, - "No MT9M001 chip detected, register read %x\n", data); - return -ENODEV; - } - - mt9m001->num_fmts = 0; - - /* - * This is a 10bit sensor, so by default we only allow 10bit. - * The platform may support different bus widths due to - * different routing of the data lines. - */ - if (icl->query_bus_param) - flags = icl->query_bus_param(icl); - else - flags = SOCAM_DATAWIDTH_10; - - if (flags & SOCAM_DATAWIDTH_10) - mt9m001->num_fmts++; - else - mt9m001->fmts++; - - if (flags & SOCAM_DATAWIDTH_8) - mt9m001->num_fmts++; - - mt9m001->fmt = &mt9m001->fmts[0]; - - dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, - data == 0x8431 ? "C12STM" : "C12ST"); - - ret = mt9m001_init(client); - if (ret < 0) - dev_err(&client->dev, "Failed to initialise the camera\n"); - - /* mt9m001_init() has reset the chip, returning registers to defaults */ - mt9m001->gain = 64; - mt9m001->exposure = 255; - - return ret; -} - -static void mt9m001_video_remove(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - dev_dbg(&icd->dev, "Video removed: %p, %p\n", - icd->dev.parent, icd->vdev); - if (icl->free_bus) - icl->free_bus(icl); -} - -static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - - *lines = mt9m001->y_skip_top; - - return 0; -} - -static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { - .g_ctrl = mt9m001_g_ctrl, - .s_ctrl = mt9m001_s_ctrl, - .g_chip_ident = mt9m001_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9m001_g_register, - .s_register = mt9m001_s_register, -#endif -}; - -static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - - if (index >= mt9m001->num_fmts) - return -EINVAL; - - *code = mt9m001->fmts[index].code; - return 0; -} - -static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { - .s_stream = mt9m001_s_stream, - .s_mbus_fmt = mt9m001_s_fmt, - .g_mbus_fmt = mt9m001_g_fmt, - .try_mbus_fmt = mt9m001_try_fmt, - .s_crop = mt9m001_s_crop, - .g_crop = mt9m001_g_crop, - .cropcap = mt9m001_cropcap, - .enum_mbus_fmt = mt9m001_enum_fmt, -}; - -static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { - .g_skip_top_lines = mt9m001_g_skip_top_lines, -}; - -static struct v4l2_subdev_ops mt9m001_subdev_ops = { - .core = &mt9m001_subdev_core_ops, - .video = &mt9m001_subdev_video_ops, - .sensor = &mt9m001_subdev_sensor_ops, -}; - -static int mt9m001_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9m001 *mt9m001; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "MT9M001: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "MT9M001 driver needs platform data\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); - return -EIO; - } - - mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL); - if (!mt9m001) - return -ENOMEM; - - v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); - - /* Second stage probe - when a capture adapter is there */ - icd->ops = &mt9m001_ops; - - mt9m001->y_skip_top = 0; - mt9m001->rect.left = MT9M001_COLUMN_SKIP; - mt9m001->rect.top = MT9M001_ROW_SKIP; - mt9m001->rect.width = MT9M001_MAX_WIDTH; - mt9m001->rect.height = MT9M001_MAX_HEIGHT; - - /* - * Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width - */ - mt9m001->autoexposure = 1; - - ret = mt9m001_video_probe(icd, client); - if (ret) { - icd->ops = NULL; - kfree(mt9m001); - } - - return ret; -} - -static int mt9m001_remove(struct i2c_client *client) -{ - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_device *icd = client->dev.platform_data; - - icd->ops = NULL; - mt9m001_video_remove(icd); - kfree(mt9m001); - - return 0; -} - -static const struct i2c_device_id mt9m001_id[] = { - { "mt9m001", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9m001_id); - -static struct i2c_driver mt9m001_i2c_driver = { - .driver = { - .name = "mt9m001", - }, - .probe = mt9m001_probe, - .remove = mt9m001_remove, - .id_table = mt9m001_id, -}; - -static int __init mt9m001_mod_init(void) -{ - return i2c_add_driver(&mt9m001_i2c_driver); -} - -static void __exit mt9m001_mod_exit(void) -{ - i2c_del_driver(&mt9m001_i2c_driver); -} - -module_init(mt9m001_mod_init); -module_exit(mt9m001_mod_exit); - -MODULE_DESCRIPTION("Micron MT9M001 Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9m111.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9m111.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9m111.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9m111.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1130 +0,0 @@ -/* - * Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina - * - * Copyright (C) 2008, Robert Jarzmik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * MT9M111, MT9M112 and MT9M131: - * i2c address is 0x48 or 0x5d (depending on SADDR pin) - * The platform has to define i2c_board_info and call i2c_register_board_info() - */ - -/* - * Sensor core register addresses (0x000..0x0ff) - */ -#define MT9M111_CHIP_VERSION 0x000 -#define MT9M111_ROW_START 0x001 -#define MT9M111_COLUMN_START 0x002 -#define MT9M111_WINDOW_HEIGHT 0x003 -#define MT9M111_WINDOW_WIDTH 0x004 -#define MT9M111_HORIZONTAL_BLANKING_B 0x005 -#define MT9M111_VERTICAL_BLANKING_B 0x006 -#define MT9M111_HORIZONTAL_BLANKING_A 0x007 -#define MT9M111_VERTICAL_BLANKING_A 0x008 -#define MT9M111_SHUTTER_WIDTH 0x009 -#define MT9M111_ROW_SPEED 0x00a -#define MT9M111_EXTRA_DELAY 0x00b -#define MT9M111_SHUTTER_DELAY 0x00c -#define MT9M111_RESET 0x00d -#define MT9M111_READ_MODE_B 0x020 -#define MT9M111_READ_MODE_A 0x021 -#define MT9M111_FLASH_CONTROL 0x023 -#define MT9M111_GREEN1_GAIN 0x02b -#define MT9M111_BLUE_GAIN 0x02c -#define MT9M111_RED_GAIN 0x02d -#define MT9M111_GREEN2_GAIN 0x02e -#define MT9M111_GLOBAL_GAIN 0x02f -#define MT9M111_CONTEXT_CONTROL 0x0c8 -#define MT9M111_PAGE_MAP 0x0f0 -#define MT9M111_BYTE_WISE_ADDR 0x0f1 - -#define MT9M111_RESET_SYNC_CHANGES (1 << 15) -#define MT9M111_RESET_RESTART_BAD_FRAME (1 << 9) -#define MT9M111_RESET_SHOW_BAD_FRAMES (1 << 8) -#define MT9M111_RESET_RESET_SOC (1 << 5) -#define MT9M111_RESET_OUTPUT_DISABLE (1 << 4) -#define MT9M111_RESET_CHIP_ENABLE (1 << 3) -#define MT9M111_RESET_ANALOG_STANDBY (1 << 2) -#define MT9M111_RESET_RESTART_FRAME (1 << 1) -#define MT9M111_RESET_RESET_MODE (1 << 0) - -#define MT9M111_RMB_MIRROR_COLS (1 << 1) -#define MT9M111_RMB_MIRROR_ROWS (1 << 0) -#define MT9M111_CTXT_CTRL_RESTART (1 << 15) -#define MT9M111_CTXT_CTRL_DEFECTCOR_B (1 << 12) -#define MT9M111_CTXT_CTRL_RESIZE_B (1 << 10) -#define MT9M111_CTXT_CTRL_CTRL2_B (1 << 9) -#define MT9M111_CTXT_CTRL_GAMMA_B (1 << 8) -#define MT9M111_CTXT_CTRL_XENON_EN (1 << 7) -#define MT9M111_CTXT_CTRL_READ_MODE_B (1 << 3) -#define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2) -#define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1) -#define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0) - -/* - * Colorpipe register addresses (0x100..0x1ff) - */ -#define MT9M111_OPER_MODE_CTRL 0x106 -#define MT9M111_OUTPUT_FORMAT_CTRL 0x108 -#define MT9M111_REDUCER_XZOOM_B 0x1a0 -#define MT9M111_REDUCER_XSIZE_B 0x1a1 -#define MT9M111_REDUCER_YZOOM_B 0x1a3 -#define MT9M111_REDUCER_YSIZE_B 0x1a4 -#define MT9M111_REDUCER_XZOOM_A 0x1a6 -#define MT9M111_REDUCER_XSIZE_A 0x1a7 -#define MT9M111_REDUCER_YZOOM_A 0x1a9 -#define MT9M111_REDUCER_YSIZE_A 0x1aa - -#define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a -#define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b - -#define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14) -#define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1) - -#define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14) -#define MT9M111_OUTFMT_BYPASS_IFP (1 << 10) -#define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9) -#define MT9M111_OUTFMT_RGB (1 << 8) -#define MT9M111_OUTFMT_RGB565 (0 << 6) -#define MT9M111_OUTFMT_RGB555 (1 << 6) -#define MT9M111_OUTFMT_RGB444x (2 << 6) -#define MT9M111_OUTFMT_RGBx444 (3 << 6) -#define MT9M111_OUTFMT_TST_RAMP_OFF (0 << 4) -#define MT9M111_OUTFMT_TST_RAMP_COL (1 << 4) -#define MT9M111_OUTFMT_TST_RAMP_ROW (2 << 4) -#define MT9M111_OUTFMT_TST_RAMP_FRAME (3 << 4) -#define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3) -#define MT9M111_OUTFMT_AVG_CHROMA (1 << 2) -#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y (1 << 1) -#define MT9M111_OUTFMT_SWAP_RGB_EVEN (1 << 1) -#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr (1 << 0) - -/* - * Camera control register addresses (0x200..0x2ff not implemented) - */ - -#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg) -#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val)) -#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val)) -#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val)) - -#define MT9M111_MIN_DARK_ROWS 8 -#define MT9M111_MIN_DARK_COLS 26 -#define MT9M111_MAX_HEIGHT 1024 -#define MT9M111_MAX_WIDTH 1280 - -/* MT9M111 has only one fixed colorspace per pixelcode */ -struct mt9m111_datafmt { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; -}; - -/* Find a data format by a pixel code in an array */ -static const struct mt9m111_datafmt *mt9m111_find_datafmt( - enum v4l2_mbus_pixelcode code, const struct mt9m111_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - -static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { - {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, -}; - -enum mt9m111_context { - HIGHPOWER = 0, - LOWPOWER, -}; - -struct mt9m111 { - struct v4l2_subdev subdev; - int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code - * from v4l2-chip-ident.h */ - enum mt9m111_context context; - struct v4l2_rect rect; - const struct mt9m111_datafmt *fmt; - unsigned int gain; - unsigned char autoexposure; - unsigned char datawidth; - unsigned int powered:1; - unsigned int hflip:1; - unsigned int vflip:1; - unsigned int swap_rgb_even_odd:1; - unsigned int swap_rgb_red_blue:1; - unsigned int swap_yuv_y_chromas:1; - unsigned int swap_yuv_cb_cr:1; - unsigned int autowhitebalance:1; -}; - -static struct mt9m111 *to_mt9m111(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct mt9m111, subdev); -} - -static int reg_page_map_set(struct i2c_client *client, const u16 reg) -{ - int ret; - u16 page; - static int lastpage = -1; /* PageMap cache value */ - - page = (reg >> 8); - if (page == lastpage) - return 0; - if (page > 2) - return -EINVAL; - - ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page)); - if (!ret) - lastpage = page; - return ret; -} - -static int mt9m111_reg_read(struct i2c_client *client, const u16 reg) -{ - int ret; - - ret = reg_page_map_set(client, reg); - if (!ret) - ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff)); - - dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); - return ret; -} - -static int mt9m111_reg_write(struct i2c_client *client, const u16 reg, - const u16 data) -{ - int ret; - - ret = reg_page_map_set(client, reg); - if (!ret) - ret = i2c_smbus_write_word_data(client, reg & 0xff, - swab16(data)); - dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); - return ret; -} - -static int mt9m111_reg_set(struct i2c_client *client, const u16 reg, - const u16 data) -{ - int ret; - - ret = mt9m111_reg_read(client, reg); - if (ret >= 0) - ret = mt9m111_reg_write(client, reg, ret | data); - return ret; -} - -static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg, - const u16 data) -{ - int ret; - - ret = mt9m111_reg_read(client, reg); - return mt9m111_reg_write(client, reg, ret & ~data); -} - -static int mt9m111_set_context(struct i2c_client *client, - enum mt9m111_context ctxt) -{ - int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B - | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B - | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B - | MT9M111_CTXT_CTRL_VBLANK_SEL_B - | MT9M111_CTXT_CTRL_HBLANK_SEL_B; - int valA = MT9M111_CTXT_CTRL_RESTART; - - if (ctxt == HIGHPOWER) - return reg_write(CONTEXT_CONTROL, valB); - else - return reg_write(CONTEXT_CONTROL, valA); -} - -static int mt9m111_setup_rect(struct i2c_client *client, - struct v4l2_rect *rect) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int ret, is_raw_format; - int width = rect->width; - int height = rect->height; - - if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || - mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) - is_raw_format = 1; - else - is_raw_format = 0; - - ret = reg_write(COLUMN_START, rect->left); - if (!ret) - ret = reg_write(ROW_START, rect->top); - - if (is_raw_format) { - if (!ret) - ret = reg_write(WINDOW_WIDTH, width); - if (!ret) - ret = reg_write(WINDOW_HEIGHT, height); - } else { - if (!ret) - ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH); - if (!ret) - ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT); - if (!ret) - ret = reg_write(REDUCER_XSIZE_B, width); - if (!ret) - ret = reg_write(REDUCER_YSIZE_B, height); - if (!ret) - ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH); - if (!ret) - ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT); - if (!ret) - ret = reg_write(REDUCER_XSIZE_A, width); - if (!ret) - ret = reg_write(REDUCER_YSIZE_A, height); - } - - return ret; -} - -static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt) -{ - int ret; - - ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); - if (!ret) - ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt); - return ret; -} - -static int mt9m111_setfmt_bayer8(struct i2c_client *client) -{ - return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER | - MT9M111_OUTFMT_RGB); -} - -static int mt9m111_setfmt_bayer10(struct i2c_client *client) -{ - return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_BYPASS_IFP); -} - -static int mt9m111_setfmt_rgb565(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int val = 0; - - if (mt9m111->swap_rgb_red_blue) - val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; - if (mt9m111->swap_rgb_even_odd) - val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; - val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; - - return mt9m111_setup_pixfmt(client, val); -} - -static int mt9m111_setfmt_rgb555(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int val = 0; - - if (mt9m111->swap_rgb_red_blue) - val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; - if (mt9m111->swap_rgb_even_odd) - val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; - val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; - - return mt9m111_setup_pixfmt(client, val); -} - -static int mt9m111_setfmt_yuv(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int val = 0; - - if (mt9m111->swap_yuv_cb_cr) - val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; - if (mt9m111->swap_yuv_y_chromas) - val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y; - - return mt9m111_setup_pixfmt(client, val); -} - -static int mt9m111_enable(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int ret; - - ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); - if (!ret) - mt9m111->powered = 1; - return ret; -} - -static int mt9m111_reset(struct i2c_client *client) -{ - int ret; - - ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); - if (!ret) - ret = reg_set(RESET, MT9M111_RESET_RESET_SOC); - if (!ret) - ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE - | MT9M111_RESET_RESET_SOC); - - return ret; -} - -static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) -{ - return 0; -} - -static int mt9m111_make_rect(struct i2c_client *client, - struct v4l2_rect *rect) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - - if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || - mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { - /* Bayer format - even size lengths */ - rect->width = ALIGN(rect->width, 2); - rect->height = ALIGN(rect->height, 2); - /* Let the user play with the starting pixel */ - } - - /* FIXME: the datasheet doesn't specify minimum sizes */ - soc_camera_limit_side(&rect->left, &rect->width, - MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH); - - soc_camera_limit_side(&rect->top, &rect->height, - MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT); - - return mt9m111_setup_rect(client, rect); -} - -static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct v4l2_rect rect = a->c; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); - int ret; - - dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n", - __func__, rect.left, rect.top, rect.width, rect.height); - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - ret = mt9m111_make_rect(client, &rect); - if (!ret) - mt9m111->rect = rect; - return ret; -} - -static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); - - a->c = mt9m111->rect; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - a->bounds.left = MT9M111_MIN_DARK_COLS; - a->bounds.top = MT9M111_MIN_DARK_ROWS; - a->bounds.width = MT9M111_MAX_WIDTH; - a->bounds.height = MT9M111_MAX_HEIGHT; - a->defrect = a->bounds; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int mt9m111_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); - - mf->width = mt9m111->rect.width; - mf->height = mt9m111->rect.height; - mf->code = mt9m111->fmt->code; - mf->colorspace = mt9m111->fmt->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9m111_set_pixfmt(struct i2c_client *client, - enum v4l2_mbus_pixelcode code) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int ret; - - switch (code) { - case V4L2_MBUS_FMT_SBGGR8_1X8: - ret = mt9m111_setfmt_bayer8(client); - break; - case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: - ret = mt9m111_setfmt_bayer10(client); - break; - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: - ret = mt9m111_setfmt_rgb555(client); - break; - case V4L2_MBUS_FMT_RGB565_2X8_LE: - ret = mt9m111_setfmt_rgb565(client); - break; - case V4L2_MBUS_FMT_UYVY8_2X8: - mt9m111->swap_yuv_y_chromas = 0; - mt9m111->swap_yuv_cb_cr = 0; - ret = mt9m111_setfmt_yuv(client); - break; - case V4L2_MBUS_FMT_VYUY8_2X8: - mt9m111->swap_yuv_y_chromas = 0; - mt9m111->swap_yuv_cb_cr = 1; - ret = mt9m111_setfmt_yuv(client); - break; - case V4L2_MBUS_FMT_YUYV8_2X8: - mt9m111->swap_yuv_y_chromas = 1; - mt9m111->swap_yuv_cb_cr = 0; - ret = mt9m111_setfmt_yuv(client); - break; - case V4L2_MBUS_FMT_YVYU8_2X8: - mt9m111->swap_yuv_y_chromas = 1; - mt9m111->swap_yuv_cb_cr = 1; - ret = mt9m111_setfmt_yuv(client); - break; - default: - dev_err(&client->dev, "Pixel format not handled : %x\n", - code); - ret = -EINVAL; - } - - return ret; -} - -static int mt9m111_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct mt9m111_datafmt *fmt; - struct mt9m111 *mt9m111 = to_mt9m111(client); - struct v4l2_rect rect = { - .left = mt9m111->rect.left, - .top = mt9m111->rect.top, - .width = mf->width, - .height = mf->height, - }; - int ret; - - fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, - ARRAY_SIZE(mt9m111_colour_fmts)); - if (!fmt) - return -EINVAL; - - dev_dbg(&client->dev, - "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__, - mf->code, rect.left, rect.top, rect.width, rect.height); - - ret = mt9m111_make_rect(client, &rect); - if (!ret) - ret = mt9m111_set_pixfmt(client, mf->code); - if (!ret) { - mt9m111->rect = rect; - mt9m111->fmt = fmt; - mf->colorspace = fmt->colorspace; - } - - return ret; -} - -static int mt9m111_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); - const struct mt9m111_datafmt *fmt; - bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || - mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE; - - fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, - ARRAY_SIZE(mt9m111_colour_fmts)); - if (!fmt) { - fmt = mt9m111->fmt; - mf->code = fmt->code; - } - - /* - * With Bayer format enforce even side lengths, but let the user play - * with the starting pixel - */ - - if (mf->height > MT9M111_MAX_HEIGHT) - mf->height = MT9M111_MAX_HEIGHT; - else if (mf->height < 2) - mf->height = 2; - else if (bayer) - mf->height = ALIGN(mf->height, 2); - - if (mf->width > MT9M111_MAX_WIDTH) - mf->width = MT9M111_MAX_WIDTH; - else if (mf->width < 2) - mf->width = 2; - else if (bayer) - mf->width = ALIGN(mf->width, 2); - - mf->colorspace = fmt->colorspace; - - return 0; -} - -static int mt9m111_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); - - if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) - return -EINVAL; - - if (id->match.addr != client->addr) - return -ENODEV; - - id->ident = mt9m111->model; - id->revision = 0; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9m111_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int val; - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) - return -EINVAL; - if (reg->match.addr != client->addr) - return -ENODEV; - - val = mt9m111_reg_read(client, reg->reg); - reg->size = 2; - reg->val = (u64)val; - - if (reg->val > 0xffff) - return -EIO; - - return 0; -} - -static int mt9m111_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - if (mt9m111_reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static const struct v4l2_queryctrl mt9m111_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Verticaly", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontaly", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { /* gain = 1/32*val (=>gain=1 if val==32) */ - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 63 * 2 * 2, - .step = 1, - .default_value = 32, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static int mt9m111_resume(struct soc_camera_device *icd); -static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state); - -static struct soc_camera_ops mt9m111_ops = { - .suspend = mt9m111_suspend, - .resume = mt9m111_resume, - .query_bus_param = mt9m111_query_bus_param, - .set_bus_param = mt9m111_set_bus_param, - .controls = mt9m111_controls, - .num_controls = ARRAY_SIZE(mt9m111_controls), -}; - -static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int ret; - - if (mt9m111->context == HIGHPOWER) { - if (flip) - ret = reg_set(READ_MODE_B, mask); - else - ret = reg_clear(READ_MODE_B, mask); - } else { - if (flip) - ret = reg_set(READ_MODE_A, mask); - else - ret = reg_clear(READ_MODE_A, mask); - } - - return ret; -} - -static int mt9m111_get_global_gain(struct i2c_client *client) -{ - int data; - - data = reg_read(GLOBAL_GAIN); - if (data >= 0) - return (data & 0x2f) * (1 << ((data >> 10) & 1)) * - (1 << ((data >> 9) & 1)); - return data; -} - -static int mt9m111_set_global_gain(struct i2c_client *client, int gain) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - u16 val; - - if (gain > 63 * 2 * 2) - return -EINVAL; - - mt9m111->gain = gain; - if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) - val = (1 << 10) | (1 << 9) | (gain / 4); - else if ((gain >= 64) && (gain < 64 * 2)) - val = (1 << 9) | (gain / 2); - else - val = gain; - - return reg_write(GLOBAL_GAIN, val); -} - -static int mt9m111_set_autoexposure(struct i2c_client *client, int on) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int ret; - - if (on) - ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); - else - ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); - - if (!ret) - mt9m111->autoexposure = on; - - return ret; -} - -static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int ret; - - if (on) - ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); - else - ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); - - if (!ret) - mt9m111->autowhitebalance = on; - - return ret; -} - -static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); - int data; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (mt9m111->context == HIGHPOWER) - data = reg_read(READ_MODE_B); - else - data = reg_read(READ_MODE_A); - - if (data < 0) - return -EIO; - ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS); - break; - case V4L2_CID_HFLIP: - if (mt9m111->context == HIGHPOWER) - data = reg_read(READ_MODE_B); - else - data = reg_read(READ_MODE_A); - - if (data < 0) - return -EIO; - ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); - break; - case V4L2_CID_GAIN: - data = mt9m111_get_global_gain(client); - if (data < 0) - return data; - ctrl->value = data; - break; - case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = mt9m111->autoexposure; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = mt9m111->autowhitebalance; - break; - } - return 0; -} - -static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = to_mt9m111(client); - const struct v4l2_queryctrl *qctrl; - int ret; - - qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); - if (!qctrl) - return -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - mt9m111->vflip = ctrl->value; - ret = mt9m111_set_flip(client, ctrl->value, - MT9M111_RMB_MIRROR_ROWS); - break; - case V4L2_CID_HFLIP: - mt9m111->hflip = ctrl->value; - ret = mt9m111_set_flip(client, ctrl->value, - MT9M111_RMB_MIRROR_COLS); - break; - case V4L2_CID_GAIN: - ret = mt9m111_set_global_gain(client, ctrl->value); - break; - case V4L2_CID_EXPOSURE_AUTO: - ret = mt9m111_set_autoexposure(client, ctrl->value); - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = mt9m111_set_autowhitebalance(client, ctrl->value); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9m111 *mt9m111 = to_mt9m111(client); - - mt9m111->gain = mt9m111_get_global_gain(client); - - return 0; -} - -static int mt9m111_restore_state(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - - mt9m111_set_context(client, mt9m111->context); - mt9m111_set_pixfmt(client, mt9m111->fmt->code); - mt9m111_setup_rect(client, &mt9m111->rect); - mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); - mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); - mt9m111_set_global_gain(client, mt9m111->gain); - mt9m111_set_autoexposure(client, mt9m111->autoexposure); - mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance); - return 0; -} - -static int mt9m111_resume(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9m111 *mt9m111 = to_mt9m111(client); - int ret = 0; - - if (mt9m111->powered) { - ret = mt9m111_enable(client); - if (!ret) - ret = mt9m111_reset(client); - if (!ret) - ret = mt9m111_restore_state(client); - } - return ret; -} - -static int mt9m111_init(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - int ret; - - mt9m111->context = HIGHPOWER; - ret = mt9m111_enable(client); - if (!ret) - ret = mt9m111_reset(client); - if (!ret) - ret = mt9m111_set_context(client, mt9m111->context); - if (!ret) - ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure); - if (ret) - dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); - return ret; -} - -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int mt9m111_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - s32 data; - int ret; - - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; - - mt9m111->autoexposure = 1; - mt9m111->autowhitebalance = 1; - - mt9m111->swap_rgb_even_odd = 1; - mt9m111->swap_rgb_red_blue = 1; - - data = reg_read(CHIP_VERSION); - - switch (data) { - case 0x143a: /* MT9M111 or MT9M131 */ - mt9m111->model = V4L2_IDENT_MT9M111; - dev_info(&client->dev, - "Detected a MT9M111/MT9M131 chip ID %x\n", data); - break; - case 0x148c: /* MT9M112 */ - mt9m111->model = V4L2_IDENT_MT9M112; - dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); - break; - default: - ret = -ENODEV; - dev_err(&client->dev, - "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", - data); - goto ei2c; - } - - ret = mt9m111_init(client); - -ei2c: - return ret; -} - -static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { - .g_ctrl = mt9m111_g_ctrl, - .s_ctrl = mt9m111_s_ctrl, - .g_chip_ident = mt9m111_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9m111_g_register, - .s_register = mt9m111_s_register, -#endif -}; - -static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index >= ARRAY_SIZE(mt9m111_colour_fmts)) - return -EINVAL; - - *code = mt9m111_colour_fmts[index].code; - return 0; -} - -static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { - .s_mbus_fmt = mt9m111_s_fmt, - .g_mbus_fmt = mt9m111_g_fmt, - .try_mbus_fmt = mt9m111_try_fmt, - .s_crop = mt9m111_s_crop, - .g_crop = mt9m111_g_crop, - .cropcap = mt9m111_cropcap, - .enum_mbus_fmt = mt9m111_enum_fmt, -}; - -static struct v4l2_subdev_ops mt9m111_subdev_ops = { - .core = &mt9m111_subdev_core_ops, - .video = &mt9m111_subdev_video_ops, -}; - -static int mt9m111_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9m111 *mt9m111; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "mt9m111: soc-camera data missing!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "mt9m111: driver needs platform data\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); - return -EIO; - } - - mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL); - if (!mt9m111) - return -ENOMEM; - - v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); - - /* Second stage probe - when a capture adapter is there */ - icd->ops = &mt9m111_ops; - - mt9m111->rect.left = MT9M111_MIN_DARK_COLS; - mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; - mt9m111->rect.width = MT9M111_MAX_WIDTH; - mt9m111->rect.height = MT9M111_MAX_HEIGHT; - mt9m111->fmt = &mt9m111_colour_fmts[0]; - - ret = mt9m111_video_probe(icd, client); - if (ret) { - icd->ops = NULL; - kfree(mt9m111); - } - - return ret; -} - -static int mt9m111_remove(struct i2c_client *client) -{ - struct mt9m111 *mt9m111 = to_mt9m111(client); - struct soc_camera_device *icd = client->dev.platform_data; - - icd->ops = NULL; - kfree(mt9m111); - - return 0; -} - -static const struct i2c_device_id mt9m111_id[] = { - { "mt9m111", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9m111_id); - -static struct i2c_driver mt9m111_i2c_driver = { - .driver = { - .name = "mt9m111", - }, - .probe = mt9m111_probe, - .remove = mt9m111_remove, - .id_table = mt9m111_id, -}; - -static int __init mt9m111_mod_init(void) -{ - return i2c_add_driver(&mt9m111_i2c_driver); -} - -static void __exit mt9m111_mod_exit(void) -{ - i2c_del_driver(&mt9m111_i2c_driver); -} - -module_init(mt9m111_mod_init); -module_exit(mt9m111_mod_exit); - -MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver"); -MODULE_AUTHOR("Robert Jarzmik"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9t031.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9t031.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9t031.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9t031.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,934 +0,0 @@ -/* - * Driver for MT9T031 CMOS Image Sensor from Micron - * - * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * mt9t031 i2c address 0x5d - * The platform has to define i2c_board_info and link to it from - * struct soc_camera_link - */ - -/* mt9t031 selected register addresses */ -#define MT9T031_CHIP_VERSION 0x00 -#define MT9T031_ROW_START 0x01 -#define MT9T031_COLUMN_START 0x02 -#define MT9T031_WINDOW_HEIGHT 0x03 -#define MT9T031_WINDOW_WIDTH 0x04 -#define MT9T031_HORIZONTAL_BLANKING 0x05 -#define MT9T031_VERTICAL_BLANKING 0x06 -#define MT9T031_OUTPUT_CONTROL 0x07 -#define MT9T031_SHUTTER_WIDTH_UPPER 0x08 -#define MT9T031_SHUTTER_WIDTH 0x09 -#define MT9T031_PIXEL_CLOCK_CONTROL 0x0a -#define MT9T031_FRAME_RESTART 0x0b -#define MT9T031_SHUTTER_DELAY 0x0c -#define MT9T031_RESET 0x0d -#define MT9T031_READ_MODE_1 0x1e -#define MT9T031_READ_MODE_2 0x20 -#define MT9T031_READ_MODE_3 0x21 -#define MT9T031_ROW_ADDRESS_MODE 0x22 -#define MT9T031_COLUMN_ADDRESS_MODE 0x23 -#define MT9T031_GLOBAL_GAIN 0x35 -#define MT9T031_CHIP_ENABLE 0xF8 - -#define MT9T031_MAX_HEIGHT 1536 -#define MT9T031_MAX_WIDTH 2048 -#define MT9T031_MIN_HEIGHT 2 -#define MT9T031_MIN_WIDTH 18 -#define MT9T031_HORIZONTAL_BLANK 142 -#define MT9T031_VERTICAL_BLANK 25 -#define MT9T031_COLUMN_SKIP 32 -#define MT9T031_ROW_SKIP 20 - -#define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \ - SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \ - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \ - SOCAM_MASTER | SOCAM_DATAWIDTH_10) - -struct mt9t031 { - struct v4l2_subdev subdev; - struct v4l2_rect rect; /* Sensor window */ - int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ - u16 xskip; - u16 yskip; - unsigned int gain; - unsigned short y_skip_top; /* Lines to skip at the top */ - unsigned int exposure; - unsigned char autoexposure; -}; - -static struct mt9t031 *to_mt9t031(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct mt9t031, subdev); -} - -static int reg_read(struct i2c_client *client, const u8 reg) -{ - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : swab16(data); -} - -static int reg_write(struct i2c_client *client, const u8 reg, - const u16 data) -{ - return i2c_smbus_write_word_data(client, reg, swab16(data)); -} - -static int reg_set(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret | data); -} - -static int reg_clear(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret & ~data); -} - -static int set_shutter(struct i2c_client *client, const u32 data) -{ - int ret; - - ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16); - - if (ret >= 0) - ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff); - - return ret; -} - -static int get_shutter(struct i2c_client *client, u32 *data) -{ - int ret; - - ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER); - *data = ret << 16; - - if (ret >= 0) - ret = reg_read(client, MT9T031_SHUTTER_WIDTH); - *data |= ret & 0xffff; - - return ret < 0 ? ret : 0; -} - -static int mt9t031_idle(struct i2c_client *client) -{ - int ret; - - /* Disable chip output, synchronous option update */ - ret = reg_write(client, MT9T031_RESET, 1); - if (ret >= 0) - ret = reg_write(client, MT9T031_RESET, 0); - if (ret >= 0) - ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); - - return ret >= 0 ? 0 : -EIO; -} - -static int mt9t031_disable(struct i2c_client *client) -{ - /* Disable the chip */ - reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); - - return 0; -} - -static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (enable) - /* Switch to master "normal" mode */ - ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2); - else - /* Stop sensor readout */ - ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); - - if (ret < 0) - return -EIO; - - return 0; -} - -static int mt9t031_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - - /* The caller should have queried our parameters, check anyway */ - if (flags & ~MT9T031_BUS_PARAM) - return -EINVAL; - - if (flags & SOCAM_PCLK_SAMPLE_FALLING) - reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); - else - reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); - - return 0; -} - -static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); -} - -enum { - MT9T031_CTRL_VFLIP, - MT9T031_CTRL_HFLIP, - MT9T031_CTRL_GAIN, - MT9T031_CTRL_EXPOSURE, - MT9T031_CTRL_EXPOSURE_AUTO, -}; - -static const struct v4l2_queryctrl mt9t031_controls[] = { - [MT9T031_CTRL_VFLIP] = { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - [MT9T031_CTRL_HFLIP] = { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - [MT9T031_CTRL_GAIN] = { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, - [MT9T031_CTRL_EXPOSURE] = { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, - [MT9T031_CTRL_EXPOSURE_AUTO] = { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9t031_ops = { - .set_bus_param = mt9t031_set_bus_param, - .query_bus_param = mt9t031_query_bus_param, - .controls = mt9t031_controls, - .num_controls = ARRAY_SIZE(mt9t031_controls), -}; - -/* target must be _even_ */ -static u16 mt9t031_skip(s32 *source, s32 target, s32 max) -{ - unsigned int skip; - - if (*source < target + target / 2) { - *source = target; - return 1; - } - - skip = min(max, *source + target / 2) / target; - if (skip > 8) - skip = 8; - *source = target * skip; - - return skip; -} - -/* rect is the sensor rectangle, the caller guarantees parameter validity */ -static int mt9t031_set_params(struct i2c_client *client, - struct v4l2_rect *rect, u16 xskip, u16 yskip) -{ - struct mt9t031 *mt9t031 = to_mt9t031(client); - int ret; - u16 xbin, ybin; - const u16 hblank = MT9T031_HORIZONTAL_BLANK, - vblank = MT9T031_VERTICAL_BLANK; - - xbin = min(xskip, (u16)3); - ybin = min(yskip, (u16)3); - - /* - * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper. - * There is always a valid suitably aligned value. The worst case is - * xbin = 3, width = 2048. Then we will start at 36, the last read out - * pixel will be 2083, which is < 2085 - first black pixel. - * - * MT9T031 datasheet imposes window left border alignment, depending on - * the selected xskip. Failing to conform to this requirement produces - * dark horizontal stripes in the image. However, even obeying to this - * requirement doesn't eliminate the stripes in all configurations. They - * appear "locally reproducibly," but can differ between tests under - * different lighting conditions. - */ - switch (xbin) { - case 1: - rect->left &= ~1; - break; - case 2: - rect->left &= ~3; - break; - case 3: - rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ? - (rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6); - } - - rect->top &= ~1; - - dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n", - xskip, yskip, rect->width, rect->height, rect->left, rect->top); - - /* Disable register update, reconfigure atomically */ - ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1); - if (ret < 0) - return ret; - - /* Blanking and start values - default... */ - ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank); - if (ret >= 0) - ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank); - - if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) { - /* Binning, skipping */ - if (ret >= 0) - ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE, - ((xbin - 1) << 4) | (xskip - 1)); - if (ret >= 0) - ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, - ((ybin - 1) << 4) | (yskip - 1)); - } - dev_dbg(&client->dev, "new physical left %u, top %u\n", - rect->left, rect->top); - - /* - * The caller provides a supported format, as guaranteed by - * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() - */ - if (ret >= 0) - ret = reg_write(client, MT9T031_COLUMN_START, rect->left); - if (ret >= 0) - ret = reg_write(client, MT9T031_ROW_START, rect->top); - if (ret >= 0) - ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1); - if (ret >= 0) - ret = reg_write(client, MT9T031_WINDOW_HEIGHT, - rect->height + mt9t031->y_skip_top - 1); - if (ret >= 0 && mt9t031->autoexposure) { - unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank; - ret = set_shutter(client, total_h); - if (ret >= 0) { - const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; - const struct v4l2_queryctrl *qctrl = - &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; - mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - shutter_max + qctrl->minimum; - } - } - - /* Re-enable register update, commit all changes */ - if (ret >= 0) - ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); - - if (ret >= 0) { - mt9t031->rect = *rect; - mt9t031->xskip = xskip; - mt9t031->yskip = yskip; - } - - return ret < 0 ? ret : 0; -} - -static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct v4l2_rect rect = a->c; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - rect.width = ALIGN(rect.width, 2); - rect.height = ALIGN(rect.height, 2); - - soc_camera_limit_side(&rect.left, &rect.width, - MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH); - - soc_camera_limit_side(&rect.top, &rect.height, - MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT); - - return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip); -} - -static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - a->c = mt9t031->rect; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = MT9T031_COLUMN_SKIP; - a->bounds.top = MT9T031_ROW_SKIP; - a->bounds.width = MT9T031_MAX_WIDTH; - a->bounds.height = MT9T031_MAX_HEIGHT; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int mt9t031_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - mf->width = mt9t031->rect.width / mt9t031->xskip; - mf->height = mt9t031->rect.height / mt9t031->yskip; - mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; - mf->colorspace = V4L2_COLORSPACE_SRGB; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9t031_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - u16 xskip, yskip; - struct v4l2_rect rect = mt9t031->rect; - - /* - * try_fmt has put width and height within limits. - * S_FMT: use binning and skipping for scaling - */ - xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH); - yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT); - - mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; - mf->colorspace = V4L2_COLORSPACE_SRGB; - - /* mt9t031_set_params() doesn't change width and height */ - return mt9t031_set_params(client, &rect, xskip, yskip); -} - -/* - * If a user window larger than sensor window is requested, we'll increase the - * sensor window. - */ -static int mt9t031_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - v4l_bound_align_image( - &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, - &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); - - mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; - mf->colorspace = V4L2_COLORSPACE_SRGB; - - return 0; -} - -static int mt9t031_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) - return -EINVAL; - - if (id->match.addr != client->addr) - return -ENODEV; - - id->ident = mt9t031->model; - id->revision = 0; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9t031_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - reg->val = reg_read(client, reg->reg); - - if (reg->val > 0xffff) - return -EIO; - - return 0; -} - -static int mt9t031_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - if (reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - int data; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, MT9T031_READ_MODE_2); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x8000); - break; - case V4L2_CID_HFLIP: - data = reg_read(client, MT9T031_READ_MODE_2); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x4000); - break; - case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = mt9t031->autoexposure; - break; - case V4L2_CID_GAIN: - ctrl->value = mt9t031->gain; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = mt9t031->exposure; - break; - } - return 0; -} - -static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - const struct v4l2_queryctrl *qctrl; - int data; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->value) - data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); - else - data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); - if (data < 0) - return -EIO; - break; - case V4L2_CID_HFLIP: - if (ctrl->value) - data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); - else - data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); - if (data < 0) - return -EIO; - break; - case V4L2_CID_GAIN: - qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN]; - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - /* See Datasheet Table 7, Gain settings. */ - if (ctrl->value <= qctrl->default_value) { - /* Pack it into 0..1 step 0.125, register values 0..8 */ - unsigned long range = qctrl->default_value - qctrl->minimum; - data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; - - dev_dbg(&client->dev, "Setting gain %d\n", data); - data = reg_write(client, MT9T031_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; - } else { - /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ - /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ - unsigned long range = qctrl->maximum - qctrl->default_value - 1; - /* calculated gain: map 65..127 to 9..1024 step 0.125 */ - unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * - 1015 + range / 2) / range + 9; - - if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ - data = gain; - else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */ - data = ((gain - 32) * 16 + 16) / 32 + 80; - else - /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */ - data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; - - dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n", - reg_read(client, MT9T031_GLOBAL_GAIN), data); - data = reg_write(client, MT9T031_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; - } - - /* Success */ - mt9t031->gain = ctrl->value; - break; - case V4L2_CID_EXPOSURE: - qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; - /* mt9t031 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - const unsigned long range = qctrl->maximum - qctrl->minimum; - const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 + - range / 2) / range + 1; - u32 old; - - get_shutter(client, &old); - dev_dbg(&client->dev, "Set shutter from %u to %u\n", - old, shutter); - if (set_shutter(client, shutter) < 0) - return -EIO; - mt9t031->exposure = ctrl->value; - mt9t031->autoexposure = 0; - } - break; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->value) { - const u16 vblank = MT9T031_VERTICAL_BLANK; - const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; - unsigned int total_h = mt9t031->rect.height + - mt9t031->y_skip_top + vblank; - - if (set_shutter(client, total_h) < 0) - return -EIO; - qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; - mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - shutter_max + qctrl->minimum; - mt9t031->autoexposure = 1; - } else - mt9t031->autoexposure = 0; - break; - default: - return -EINVAL; - } - return 0; -} - -/* - * Power Management: - * This function does nothing for now but must be present for pm to work - */ -static int mt9t031_runtime_suspend(struct device *dev) -{ - return 0; -} - -/* - * Power Management: - * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged - * they are however changed at reset if the platform hook is present - * thus we rewrite them with the values stored by the driver - */ -static int mt9t031_runtime_resume(struct device *dev) -{ - struct video_device *vdev = to_video_device(dev); - struct soc_camera_device *icd = container_of(vdev->parent, - struct soc_camera_device, dev); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - int ret; - u16 xbin, ybin; - - xbin = min(mt9t031->xskip, (u16)3); - ybin = min(mt9t031->yskip, (u16)3); - - ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE, - ((xbin - 1) << 4) | (mt9t031->xskip - 1)); - if (ret < 0) - return ret; - - ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, - ((ybin - 1) << 4) | (mt9t031->yskip - 1)); - if (ret < 0) - return ret; - - return 0; -} - -static struct dev_pm_ops mt9t031_dev_pm_ops = { - .runtime_suspend = mt9t031_runtime_suspend, - .runtime_resume = mt9t031_runtime_resume, -}; - -static struct device_type mt9t031_dev_type = { - .name = "MT9T031", - .pm = &mt9t031_dev_pm_ops, -}; - -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int mt9t031_video_probe(struct i2c_client *client) -{ - struct mt9t031 *mt9t031 = to_mt9t031(client); - struct video_device *vdev = soc_camera_i2c_to_vdev(client); - s32 data; - int ret; - - /* Enable the chip */ - data = reg_write(client, MT9T031_CHIP_ENABLE, 1); - dev_dbg(&client->dev, "write: %d\n", data); - - /* Read out the chip version register */ - data = reg_read(client, MT9T031_CHIP_VERSION); - - switch (data) { - case 0x1621: - mt9t031->model = V4L2_IDENT_MT9T031; - break; - default: - dev_err(&client->dev, - "No MT9T031 chip detected, register read %x\n", data); - return -ENODEV; - } - - dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); - - ret = mt9t031_idle(client); - if (ret < 0) - dev_err(&client->dev, "Failed to initialise the camera\n"); - else - vdev->dev.type = &mt9t031_dev_type; - - /* mt9t031_idle() has reset the chip to default. */ - mt9t031->exposure = 255; - mt9t031->gain = 64; - - return ret; -} - -static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - *lines = mt9t031->y_skip_top; - - return 0; -} - -static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { - .g_ctrl = mt9t031_g_ctrl, - .s_ctrl = mt9t031_s_ctrl, - .g_chip_ident = mt9t031_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9t031_g_register, - .s_register = mt9t031_s_register, -#endif -}; - -static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index) - return -EINVAL; - - *code = V4L2_MBUS_FMT_SBGGR10_1X10; - return 0; -} - -static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { - .s_stream = mt9t031_s_stream, - .s_mbus_fmt = mt9t031_s_fmt, - .g_mbus_fmt = mt9t031_g_fmt, - .try_mbus_fmt = mt9t031_try_fmt, - .s_crop = mt9t031_s_crop, - .g_crop = mt9t031_g_crop, - .cropcap = mt9t031_cropcap, - .enum_mbus_fmt = mt9t031_enum_fmt, -}; - -static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { - .g_skip_top_lines = mt9t031_g_skip_top_lines, -}; - -static struct v4l2_subdev_ops mt9t031_subdev_ops = { - .core = &mt9t031_subdev_core_ops, - .video = &mt9t031_subdev_video_ops, - .sensor = &mt9t031_subdev_sensor_ops, -}; - -static int mt9t031_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9t031 *mt9t031; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - int ret; - - if (icd) { - struct soc_camera_link *icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "MT9T031 driver needs platform data\n"); - return -EINVAL; - } - - icd->ops = &mt9t031_ops; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); - return -EIO; - } - - mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL); - if (!mt9t031) - return -ENOMEM; - - v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); - - mt9t031->y_skip_top = 0; - mt9t031->rect.left = MT9T031_COLUMN_SKIP; - mt9t031->rect.top = MT9T031_ROW_SKIP; - mt9t031->rect.width = MT9T031_MAX_WIDTH; - mt9t031->rect.height = MT9T031_MAX_HEIGHT; - - /* - * Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width - */ - mt9t031->autoexposure = 1; - - mt9t031->xskip = 1; - mt9t031->yskip = 1; - - mt9t031_idle(client); - - ret = mt9t031_video_probe(client); - - mt9t031_disable(client); - - if (ret) { - if (icd) - icd->ops = NULL; - kfree(mt9t031); - } - - return ret; -} - -static int mt9t031_remove(struct i2c_client *client) -{ - struct mt9t031 *mt9t031 = to_mt9t031(client); - struct soc_camera_device *icd = client->dev.platform_data; - - if (icd) - icd->ops = NULL; - kfree(mt9t031); - - return 0; -} - -static const struct i2c_device_id mt9t031_id[] = { - { "mt9t031", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9t031_id); - -static struct i2c_driver mt9t031_i2c_driver = { - .driver = { - .name = "mt9t031", - }, - .probe = mt9t031_probe, - .remove = mt9t031_remove, - .id_table = mt9t031_id, -}; - -static int __init mt9t031_mod_init(void) -{ - return i2c_add_driver(&mt9t031_i2c_driver); -} - -static void __exit mt9t031_mod_exit(void) -{ - i2c_del_driver(&mt9t031_i2c_driver); -} - -module_init(mt9t031_mod_init); -module_exit(mt9t031_mod_exit); - -MODULE_DESCRIPTION("Micron MT9T031 Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9t112.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9t112.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9t112.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9t112.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1175 +0,0 @@ -/* - * mt9t112 Camera Driver - * - * Copyright (C) 2009 Renesas Solutions Corp. - * Kuninori Morimoto - * - * Based on ov772x driver, mt9m111 driver, - * - * Copyright (C) 2008 Kuninori Morimoto - * Copyright (C) 2008, Robert Jarzmik - * Copyright 2006-7 Jonathan Corbet - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* you can check PLL/clock info */ -/* #define EXT_CLOCK 24000000 */ - -/************************************************************************ - - - macro - - -************************************************************************/ -/* - * frame size - */ -#define MAX_WIDTH 2048 -#define MAX_HEIGHT 1536 - -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 - -/* - * macro of read/write - */ -#define ECHECKER(ret, x) \ - do { \ - (ret) = (x); \ - if ((ret) < 0) \ - return (ret); \ - } while (0) - -#define mt9t112_reg_write(ret, client, a, b) \ - ECHECKER(ret, __mt9t112_reg_write(client, a, b)) -#define mt9t112_mcu_write(ret, client, a, b) \ - ECHECKER(ret, __mt9t112_mcu_write(client, a, b)) - -#define mt9t112_reg_mask_set(ret, client, a, b, c) \ - ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c)) -#define mt9t112_mcu_mask_set(ret, client, a, b, c) \ - ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c)) - -#define mt9t112_reg_read(ret, client, a) \ - ECHECKER(ret, __mt9t112_reg_read(client, a)) - -/* - * Logical address - */ -#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff)) -#define VAR(id, offset) _VAR(id, offset, 0x0000) -#define VAR8(id, offset) _VAR(id, offset, 0x8000) - -/************************************************************************ - - - struct - - -************************************************************************/ -struct mt9t112_frame_size { - u16 width; - u16 height; -}; - -struct mt9t112_format { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; - u16 fmt; - u16 order; -}; - -struct mt9t112_priv { - struct v4l2_subdev subdev; - struct mt9t112_camera_info *info; - struct i2c_client *client; - struct soc_camera_device icd; - struct mt9t112_frame_size frame; - const struct mt9t112_format *format; - int model; - u32 flags; -/* for flags */ -#define INIT_DONE (1<<0) -}; - -/************************************************************************ - - - supported format - - -************************************************************************/ - -static const struct mt9t112_format mt9t112_cfmts[] = { - { - .code = V4L2_MBUS_FMT_UYVY8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 0, - }, { - .code = V4L2_MBUS_FMT_VYUY8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 1, - }, { - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 2, - }, { - .code = V4L2_MBUS_FMT_YVYU8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .fmt = 1, - .order = 3, - }, { - .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 8, - .order = 2, - }, { - .code = V4L2_MBUS_FMT_RGB565_2X8_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 4, - .order = 2, - }, -}; - -/************************************************************************ - - - general function - - -************************************************************************/ -static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), - struct mt9t112_priv, - subdev); -} - -static int __mt9t112_reg_read(const struct i2c_client *client, u16 command) -{ - struct i2c_msg msg[2]; - u8 buf[2]; - int ret; - - command = swab16(command); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = (u8 *)&command; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = 2; - msg[1].buf = buf; - - /* - * if return value of this function is < 0, - * it mean error. - * else, under 16bit is valid data. - */ - ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) - return ret; - - memcpy(&ret, buf, 2); - return swab16(ret); -} - -static int __mt9t112_reg_write(const struct i2c_client *client, - u16 command, u16 data) -{ - struct i2c_msg msg; - u8 buf[4]; - int ret; - - command = swab16(command); - data = swab16(data); - - memcpy(buf + 0, &command, 2); - memcpy(buf + 2, &data, 2); - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 4; - msg.buf = buf; - - /* - * i2c_transfer return message length, - * but this function should return 0 if correct case - */ - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret >= 0) - ret = 0; - - return ret; -} - -static int __mt9t112_reg_mask_set(const struct i2c_client *client, - u16 command, - u16 mask, - u16 set) -{ - int val = __mt9t112_reg_read(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return __mt9t112_reg_write(client, command, val); -} - -/* mcu access */ -static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command) -{ - int ret; - - ret = __mt9t112_reg_write(client, 0x098E, command); - if (ret < 0) - return ret; - - return __mt9t112_reg_read(client, 0x0990); -} - -static int __mt9t112_mcu_write(const struct i2c_client *client, - u16 command, u16 data) -{ - int ret; - - ret = __mt9t112_reg_write(client, 0x098E, command); - if (ret < 0) - return ret; - - return __mt9t112_reg_write(client, 0x0990, data); -} - -static int __mt9t112_mcu_mask_set(const struct i2c_client *client, - u16 command, - u16 mask, - u16 set) -{ - int val = __mt9t112_mcu_read(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return __mt9t112_mcu_write(client, command, val); -} - -static int mt9t112_reset(const struct i2c_client *client) -{ - int ret; - - mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); - msleep(1); - mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); - - return ret; -} - -#ifndef EXT_CLOCK -#define CLOCK_INFO(a, b) -#else -#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b) -static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) -{ - int m, n, p1, p2, p3, p4, p5, p6, p7; - u32 vco, clk; - char *enable; - - ext /= 1000; /* kbyte order */ - - mt9t112_reg_read(n, client, 0x0012); - p1 = n & 0x000f; - n = n >> 4; - p2 = n & 0x000f; - n = n >> 4; - p3 = n & 0x000f; - - mt9t112_reg_read(n, client, 0x002a); - p4 = n & 0x000f; - n = n >> 4; - p5 = n & 0x000f; - n = n >> 4; - p6 = n & 0x000f; - - mt9t112_reg_read(n, client, 0x002c); - p7 = n & 0x000f; - - mt9t112_reg_read(n, client, 0x0010); - m = n & 0x00ff; - n = (n >> 8) & 0x003f; - - enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; - dev_info(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); - - vco = 2 * m * ext / (n+1); - enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; - dev_info(&client->dev, "VCO : %10u K %s\n", vco, enable); - - clk = vco / (p1+1) / (p2+1); - enable = (96000 < clk) ? "X" : ""; - dev_info(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); - - clk = vco / (p3+1); - enable = (768000 < clk) ? "X" : ""; - dev_info(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); - - clk = vco / (p6+1); - enable = (96000 < clk) ? "X" : ""; - dev_info(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); - - clk = vco / (p5+1); - enable = (54000 < clk) ? "X" : ""; - dev_info(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); - - clk = vco / (p4+1); - enable = (70000 < clk) ? "X" : ""; - dev_info(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); - - clk = vco / (p7+1); - dev_info(&client->dev, "External sensor : %10u K\n", clk); - - clk = ext / (n+1); - enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; - dev_info(&client->dev, "PFD : %10u K %s\n", clk, enable); - - return 0; -} -#endif - -static void mt9t112_frame_check(u32 *width, u32 *height) -{ - if (*width > MAX_WIDTH) - *width = MAX_WIDTH; - - if (*height > MAX_HEIGHT) - *height = MAX_HEIGHT; -} - -static int mt9t112_set_a_frame_size(const struct i2c_client *client, - u16 width, - u16 height) -{ - int ret; - u16 wstart = (MAX_WIDTH - width) / 2; - u16 hstart = (MAX_HEIGHT - height) / 2; - - /* (Context A) Image Width/Height */ - mt9t112_mcu_write(ret, client, VAR(26, 0), width); - mt9t112_mcu_write(ret, client, VAR(26, 2), height); - - /* (Context A) Output Width/Height */ - mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); - mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); - - /* (Context A) Start Row/Column */ - mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); - mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); - - /* (Context A) End Row/Column */ - mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); - mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); - - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - - return ret; -} - -static int mt9t112_set_pll_dividers(const struct i2c_client *client, - u8 m, u8 n, - u8 p1, u8 p2, u8 p3, - u8 p4, u8 p5, u8 p6, - u8 p7) -{ - int ret; - u16 val; - - /* N/M */ - val = (n << 8) | - (m << 0); - mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); - - /* P1/P2/P3 */ - val = ((p3 & 0x0F) << 8) | - ((p2 & 0x0F) << 4) | - ((p1 & 0x0F) << 0); - mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); - - /* P4/P5/P6 */ - val = (0x7 << 12) | - ((p6 & 0x0F) << 8) | - ((p5 & 0x0F) << 4) | - ((p4 & 0x0F) << 0); - mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); - - /* P7 */ - val = (0x1 << 12) | - ((p7 & 0x0F) << 0); - mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); - - return ret; -} - -static int mt9t112_init_pll(const struct i2c_client *client) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - int data, i, ret; - - mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); - - /* PLL control: BYPASS PLL = 8517 */ - mt9t112_reg_write(ret, client, 0x0014, 0x2145); - - /* Replace these registers when new timing parameters are generated */ - mt9t112_set_pll_dividers(client, - priv->info->divider.m, - priv->info->divider.n, - priv->info->divider.p1, - priv->info->divider.p2, - priv->info->divider.p3, - priv->info->divider.p4, - priv->info->divider.p5, - priv->info->divider.p6, - priv->info->divider.p7); - - /* - * TEST_BYPASS on - * PLL_ENABLE on - * SEL_LOCK_DET on - * TEST_BYPASS off - */ - mt9t112_reg_write(ret, client, 0x0014, 0x2525); - mt9t112_reg_write(ret, client, 0x0014, 0x2527); - mt9t112_reg_write(ret, client, 0x0014, 0x3427); - mt9t112_reg_write(ret, client, 0x0014, 0x3027); - - mdelay(10); - - /* - * PLL_BYPASS off - * Reference clock count - * I2C Master Clock Divider - */ - mt9t112_reg_write(ret, client, 0x0014, 0x3046); - mt9t112_reg_write(ret, client, 0x0022, 0x0190); - mt9t112_reg_write(ret, client, 0x3B84, 0x0212); - - /* External sensor clock is PLL bypass */ - mt9t112_reg_write(ret, client, 0x002E, 0x0500); - - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); - mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); - - /* MCU disabled */ - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); - - /* out of standby */ - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); - - mdelay(50); - - /* - * Standby Workaround - * Disable Secondary I2C Pads - */ - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - - /* poll to verify out of standby. Must Poll this bit */ - for (i = 0; i < 100; i++) { - mt9t112_reg_read(data, client, 0x0018); - if (!(0x4000 & data)) - break; - - mdelay(10); - } - - return ret; -} - -static int mt9t112_init_setting(const struct i2c_client *client) -{ - - int ret; - - /* Adaptive Output Clock (A) */ - mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000); - - /* Read Mode (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024); - - /* Fine Correction (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC); - - /* Fine IT Min (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1); - - /* Fine IT Max Margin (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF); - - /* Base Frame Lines (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D); - - /* Min Line Length (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a); - - /* Line Length (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0); - - /* Adaptive Output Clock (B) */ - mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000); - - /* Row Start (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004); - - /* Column Start (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004); - - /* Row End (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B); - - /* Column End (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B); - - /* Fine Correction (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C); - - /* Fine IT Min (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1); - - /* Fine IT Max Margin (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF); - - /* Base Frame Lines (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668); - - /* Min Line Length (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0); - - /* Line Length (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); - - /* - * Flicker Dectection registers - * This section should be replaced whenever new Timing file is generated - * All the following registers need to be replaced - * Following registers are generated from Register Wizard but user can - * modify them. For detail see auto flicker detection tuning - */ - - /* FD_FDPERIOD_SELECT */ - mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01); - - /* PRI_B_CONFIG_FD_ALGO_RUN */ - mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003); - - /* PRI_A_CONFIG_FD_ALGO_RUN */ - mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); - - /* - * AFD range detection tuning registers - */ - - /* search_f1_50 */ - mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); - - /* search_f2_50 */ - mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); - - /* search_f1_60 */ - mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); - - /* search_f2_60 */ - mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); - - /* period_50Hz (A) */ - mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); - - /* secret register by aptina */ - /* period_50Hz (A MSB) */ - mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); - - /* period_60Hz (A) */ - mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); - - /* secret register by aptina */ - /* period_60Hz (A MSB) */ - mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); - - /* period_50Hz (B) */ - mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); - - /* secret register by aptina */ - /* period_50Hz (B) MSB */ - mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); - - /* period_60Hz (B) */ - mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); - - /* secret register by aptina */ - /* period_60Hz (B) MSB */ - mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); - - /* FD Mode */ - mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10); - - /* Stat_min */ - mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02); - - /* Stat_max */ - mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03); - - /* Min_amplitude */ - mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A); - - /* RX FIFO Watermark (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014); - - /* RX FIFO Watermark (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014); - - /* MCLK: 16MHz - * PCLK: 73MHz - * CorePixCLK: 36.5 MHz - */ - mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133); - mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110); - mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130); - mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108); - - mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27); - mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30); - mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32); - mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35); - - return ret; -} - -static int mt9t112_auto_focus_setting(const struct i2c_client *client) -{ - int ret; - - mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F); - mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F); - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - - mt9t112_reg_write(ret, client, 0x0614, 0x0000); - - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); - mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02); - mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002); - mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001); - mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025); - mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193); - mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18); - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); - - return ret; -} - -static int mt9t112_auto_focus_trigger(const struct i2c_client *client) -{ - int ret; - - mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01); - - return ret; -} - -static int mt9t112_init_camera(const struct i2c_client *client) -{ - int ret; - - ECHECKER(ret, mt9t112_reset(client)); - - ECHECKER(ret, mt9t112_init_pll(client)); - - ECHECKER(ret, mt9t112_init_setting(client)); - - ECHECKER(ret, mt9t112_auto_focus_setting(client)); - - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); - - /* Analog setting B */ - mt9t112_reg_write(ret, client, 0x3084, 0x2409); - mt9t112_reg_write(ret, client, 0x3092, 0x0A49); - mt9t112_reg_write(ret, client, 0x3094, 0x4949); - mt9t112_reg_write(ret, client, 0x3096, 0x4950); - - /* - * Disable adaptive clock - * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR - * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR - */ - mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); - mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); - - /* Configure STatus in Status_before_length Format and enable header */ - /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ - mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); - - /* Enable JPEG in context B */ - /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ - mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); - - /* Disable Dac_TXLO */ - mt9t112_reg_write(ret, client, 0x316C, 0x350F); - - /* Set max slew rates */ - mt9t112_reg_write(ret, client, 0x1E, 0x777); - - return ret; -} - -/************************************************************************ - - - soc_camera_ops - - -************************************************************************/ -static int mt9t112_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -static unsigned long mt9t112_query_bus_param(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9t112_priv *priv = to_mt9t112(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH; - - flags |= (priv->info->flags & MT9T112_FLAG_PCLK_RISING_EDGE) ? - SOCAM_PCLK_SAMPLE_RISING : SOCAM_PCLK_SAMPLE_FALLING; - - if (priv->info->flags & MT9T112_FLAG_DATAWIDTH_8) - flags |= SOCAM_DATAWIDTH_8; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static struct soc_camera_ops mt9t112_ops = { - .set_bus_param = mt9t112_set_bus_param, - .query_bus_param = mt9t112_query_bus_param, -}; - -/************************************************************************ - - - v4l2_subdev_core_ops - - -************************************************************************/ -static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - - id->ident = priv->model; - id->revision = 0; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9t112_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - reg->size = 2; - mt9t112_reg_read(ret, client, reg->reg); - - reg->val = (__u64)ret; - - return 0; -} - -static int mt9t112_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mt9t112_reg_write(ret, client, reg->reg, reg->val); - - return ret; -} -#endif - -static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { - .g_chip_ident = mt9t112_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9t112_g_register, - .s_register = mt9t112_s_register, -#endif -}; - - -/************************************************************************ - - - v4l2_subdev_video_ops - - -************************************************************************/ -static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - int ret = 0; - - if (!enable) { - /* FIXME - * - * If user selected large output size, - * and used it long time, - * mt9t112 camera will be very warm. - * - * But current driver can not stop mt9t112 camera. - * So, set small size here to solve this problem. - */ - mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT); - return ret; - } - - if (!(priv->flags & INIT_DONE)) { - u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE & - priv->info->flags) ? 0x0001 : 0x0000; - - ECHECKER(ret, mt9t112_init_camera(client)); - - /* Invert PCLK (Data sampled on falling edge of pixclk) */ - mt9t112_reg_write(ret, client, 0x3C20, param); - - mdelay(5); - - priv->flags |= INIT_DONE; - } - - mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); - mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - - mt9t112_set_a_frame_size(client, - priv->frame.width, - priv->frame.height); - - ECHECKER(ret, mt9t112_auto_focus_trigger(client)); - - dev_dbg(&client->dev, "format : %d\n", priv->format->code); - dev_dbg(&client->dev, "size : %d x %d\n", - priv->frame.width, - priv->frame.height); - - CLOCK_INFO(client, EXT_CLOCK); - - return ret; -} - -static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, - enum v4l2_mbus_pixelcode code) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - int i; - - priv->format = NULL; - - /* - * frame size check - */ - mt9t112_frame_check(&width, &height); - - /* - * get color format - */ - for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++) - if (mt9t112_cfmts[i].code == code) - break; - - if (i == ARRAY_SIZE(mt9t112_cfmts)) - return -EINVAL; - - priv->frame.width = (u16)width; - priv->frame.height = (u16)height; - - priv->format = mt9t112_cfmts + i; - - return 0; -} - -static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = VGA_WIDTH; - a->bounds.height = VGA_HEIGHT; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - a->c.left = 0; - a->c.top = 0; - a->c.width = VGA_WIDTH; - a->c.height = VGA_HEIGHT; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct v4l2_rect *rect = &a->c; - - return mt9t112_set_params(client, rect->width, rect->height, - V4L2_MBUS_FMT_UYVY8_2X8); -} - -static int mt9t112_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (!priv->format) { - int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT, - V4L2_MBUS_FMT_UYVY8_2X8); - if (ret < 0) - return ret; - } - - mf->width = priv->frame.width; - mf->height = priv->frame.height; - /* TODO: set colorspace */ - mf->code = priv->format->code; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9t112_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* TODO: set colorspace */ - return mt9t112_set_params(client, mf->width, mf->height, mf->code); -} - -static int mt9t112_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - mt9t112_frame_check(&mf->width, &mf->height); - - /* TODO: set colorspace */ - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index >= ARRAY_SIZE(mt9t112_cfmts)) - return -EINVAL; - - *code = mt9t112_cfmts[index].code; - return 0; -} - -static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { - .s_stream = mt9t112_s_stream, - .g_mbus_fmt = mt9t112_g_fmt, - .s_mbus_fmt = mt9t112_s_fmt, - .try_mbus_fmt = mt9t112_try_fmt, - .cropcap = mt9t112_cropcap, - .g_crop = mt9t112_g_crop, - .s_crop = mt9t112_s_crop, - .enum_mbus_fmt = mt9t112_enum_fmt, -}; - -/************************************************************************ - - - i2c driver - - -************************************************************************/ -static struct v4l2_subdev_ops mt9t112_subdev_ops = { - .core = &mt9t112_subdev_core_ops, - .video = &mt9t112_subdev_video_ops, -}; - -static int mt9t112_camera_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - const char *devname; - int chipid; - - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; - - /* - * check and show chip ID - */ - mt9t112_reg_read(chipid, client, 0x0000); - - switch (chipid) { - case 0x2680: - devname = "mt9t111"; - priv->model = V4L2_IDENT_MT9T111; - break; - case 0x2682: - devname = "mt9t112"; - priv->model = V4L2_IDENT_MT9T112; - break; - default: - dev_err(&client->dev, "Product ID error %04x\n", chipid); - return -ENODEV; - } - - dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); - - return 0; -} - -static int mt9t112_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9t112_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "mt9t112: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) - return -EINVAL; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->info = icl->priv; - - v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - - icd->ops = &mt9t112_ops; - - ret = mt9t112_camera_probe(icd, client); - if (ret) { - icd->ops = NULL; - kfree(priv); - } - - return ret; -} - -static int mt9t112_remove(struct i2c_client *client) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - struct soc_camera_device *icd = client->dev.platform_data; - - icd->ops = NULL; - kfree(priv); - return 0; -} - -static const struct i2c_device_id mt9t112_id[] = { - { "mt9t112", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9t112_id); - -static struct i2c_driver mt9t112_i2c_driver = { - .driver = { - .name = "mt9t112", - }, - .probe = mt9t112_probe, - .remove = mt9t112_remove, - .id_table = mt9t112_id, -}; - -/************************************************************************ - - - module function - - -************************************************************************/ -static int __init mt9t112_module_init(void) -{ - return i2c_add_driver(&mt9t112_i2c_driver); -} - -static void __exit mt9t112_module_exit(void) -{ - i2c_del_driver(&mt9t112_i2c_driver); -} - -module_init(mt9t112_module_init); -module_exit(mt9t112_module_exit); - -MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); -MODULE_AUTHOR("Kuninori Morimoto"); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9v011.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9v011.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9v011.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9v011.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,661 +0,0 @@ -/* - * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor - * - * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com) - * This code is placed under the terms of the GNU General Public License v2 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("Micron mt9v011 sensor driver"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-2)"); - -#define R00_MT9V011_CHIP_VERSION 0x00 -#define R01_MT9V011_ROWSTART 0x01 -#define R02_MT9V011_COLSTART 0x02 -#define R03_MT9V011_HEIGHT 0x03 -#define R04_MT9V011_WIDTH 0x04 -#define R05_MT9V011_HBLANK 0x05 -#define R06_MT9V011_VBLANK 0x06 -#define R07_MT9V011_OUT_CTRL 0x07 -#define R09_MT9V011_SHUTTER_WIDTH 0x09 -#define R0A_MT9V011_CLK_SPEED 0x0a -#define R0B_MT9V011_RESTART 0x0b -#define R0C_MT9V011_SHUTTER_DELAY 0x0c -#define R0D_MT9V011_RESET 0x0d -#define R1E_MT9V011_DIGITAL_ZOOM 0x1e -#define R20_MT9V011_READ_MODE 0x20 -#define R2B_MT9V011_GREEN_1_GAIN 0x2b -#define R2C_MT9V011_BLUE_GAIN 0x2c -#define R2D_MT9V011_RED_GAIN 0x2d -#define R2E_MT9V011_GREEN_2_GAIN 0x2e -#define R35_MT9V011_GLOBAL_GAIN 0x35 -#define RF1_MT9V011_CHIP_ENABLE 0xf1 - -#define MT9V011_VERSION 0x8232 -#define MT9V011_REV_B_VERSION 0x8243 - -/* supported controls */ -static struct v4l2_queryctrl mt9v011_qctrl[] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = (1 << 10) - 1, - .step = 1, - .default_value = 0x0020, - .flags = 0, - }, { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = -1 << 9, - .maximum = (1 << 9) - 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = -1 << 9, - .maximum = (1 << 9) - 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, { - } -}; - -struct mt9v011 { - struct v4l2_subdev sd; - unsigned width, height; - unsigned xtal; - unsigned hflip:1; - unsigned vflip:1; - - u16 global_gain, red_bal, blue_bal; -}; - -static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd) -{ - return container_of(sd, struct mt9v011, sd); -} - -static int mt9v011_read(struct v4l2_subdev *sd, unsigned char addr) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - __be16 buffer; - int rc, val; - - rc = i2c_master_send(c, &addr, 1); - if (rc != 1) - v4l2_dbg(0, debug, sd, - "i2c i/o error: rc == %d (should be 1)\n", rc); - - msleep(10); - - rc = i2c_master_recv(c, (char *)&buffer, 2); - if (rc != 2) - v4l2_dbg(0, debug, sd, - "i2c i/o error: rc == %d (should be 2)\n", rc); - - val = be16_to_cpu(buffer); - - v4l2_dbg(2, debug, sd, "mt9v011: read 0x%02x = 0x%04x\n", addr, val); - - return val; -} - -static void mt9v011_write(struct v4l2_subdev *sd, unsigned char addr, - u16 value) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - unsigned char buffer[3]; - int rc; - - buffer[0] = addr; - buffer[1] = value >> 8; - buffer[2] = value & 0xff; - - v4l2_dbg(2, debug, sd, - "mt9v011: writing 0x%02x 0x%04x\n", buffer[0], value); - rc = i2c_master_send(c, buffer, 3); - if (rc != 3) - v4l2_dbg(0, debug, sd, - "i2c i/o error: rc == %d (should be 3)\n", rc); -} - - -struct i2c_reg_value { - unsigned char reg; - u16 value; -}; - -/* - * Values used at the original driver - * Some values are marked as Reserved at the datasheet - */ -static const struct i2c_reg_value mt9v011_init_default[] = { - { R0D_MT9V011_RESET, 0x0001 }, - { R0D_MT9V011_RESET, 0x0000 }, - - { R0C_MT9V011_SHUTTER_DELAY, 0x0000 }, - { R09_MT9V011_SHUTTER_WIDTH, 0x1fc }, - - { R0A_MT9V011_CLK_SPEED, 0x0000 }, - { R1E_MT9V011_DIGITAL_ZOOM, 0x0000 }, - - { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */ -}; - -static void set_balance(struct v4l2_subdev *sd) -{ - struct mt9v011 *core = to_mt9v011(sd); - u16 green1_gain, green2_gain, blue_gain, red_gain; - - green1_gain = core->global_gain; - green2_gain = core->global_gain; - - blue_gain = core->global_gain + - core->global_gain * core->blue_bal / (1 << 9); - - red_gain = core->global_gain + - core->global_gain * core->blue_bal / (1 << 9); - - mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green1_gain); - mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green1_gain); - mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain); - mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); -} - -static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator) -{ - struct mt9v011 *core = to_mt9v011(sd); - unsigned height, width, hblank, vblank, speed; - unsigned row_time, t_time; - u64 frames_per_ms; - unsigned tmp; - - height = mt9v011_read(sd, R03_MT9V011_HEIGHT); - width = mt9v011_read(sd, R04_MT9V011_WIDTH); - hblank = mt9v011_read(sd, R05_MT9V011_HBLANK); - vblank = mt9v011_read(sd, R06_MT9V011_VBLANK); - speed = mt9v011_read(sd, R0A_MT9V011_CLK_SPEED); - - row_time = (width + 113 + hblank) * (speed + 2); - t_time = row_time * (height + vblank + 1); - - frames_per_ms = core->xtal * 1000l; - do_div(frames_per_ms, t_time); - tmp = frames_per_ms; - - v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n", - tmp / 1000, tmp % 1000, t_time); - - if (numerator && denominator) { - *numerator = 1000; - *denominator = (u32)frames_per_ms; - } -} - -static u16 calc_speed(struct v4l2_subdev *sd, u32 numerator, u32 denominator) -{ - struct mt9v011 *core = to_mt9v011(sd); - unsigned height, width, hblank, vblank; - unsigned row_time, line_time; - u64 t_time, speed; - - /* Avoid bogus calculus */ - if (!numerator || !denominator) - return 0; - - height = mt9v011_read(sd, R03_MT9V011_HEIGHT); - width = mt9v011_read(sd, R04_MT9V011_WIDTH); - hblank = mt9v011_read(sd, R05_MT9V011_HBLANK); - vblank = mt9v011_read(sd, R06_MT9V011_VBLANK); - - row_time = width + 113 + hblank; - line_time = height + vblank + 1; - - t_time = core->xtal * ((u64)numerator); - /* round to the closest value */ - t_time += denominator / 2; - do_div(t_time, denominator); - - speed = t_time; - do_div(speed, row_time * line_time); - - /* Avoid having a negative value for speed */ - if (speed < 2) - speed = 0; - else - speed -= 2; - - /* Avoid speed overflow */ - if (speed > 15) - return 15; - - return (u16)speed; -} - -static void set_res(struct v4l2_subdev *sd) -{ - struct mt9v011 *core = to_mt9v011(sd); - unsigned vstart, hstart; - - /* - * The mt9v011 doesn't have scaling. So, in order to select the desired - * resolution, we're cropping at the middle of the sensor. - * hblank and vblank should be adjusted, in order to warrant that - * we'll preserve the line timings for 30 fps, no matter what resolution - * is selected. - * NOTE: datasheet says that width (and height) should be filled with - * width-1. However, this doesn't work, since one pixel per line will - * be missing. - */ - - hstart = 14 + (640 - core->width) / 2; - mt9v011_write(sd, R02_MT9V011_COLSTART, hstart); - mt9v011_write(sd, R04_MT9V011_WIDTH, core->width); - mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width); - - vstart = 8 + (480 - core->height) / 2; - mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart); - mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); - mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); - - calc_fps(sd, NULL, NULL); -}; - -static void set_read_mode(struct v4l2_subdev *sd) -{ - struct mt9v011 *core = to_mt9v011(sd); - unsigned mode = 0x1000; - - if (core->hflip) - mode |= 0x4000; - - if (core->vflip) - mode |= 0x8000; - - mt9v011_write(sd, R20_MT9V011_READ_MODE, mode); -} - -static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mt9v011_init_default); i++) - mt9v011_write(sd, mt9v011_init_default[i].reg, - mt9v011_init_default[i].value); - - set_balance(sd); - set_res(sd); - set_read_mode(sd); - - return 0; -}; - -static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct mt9v011 *core = to_mt9v011(sd); - - v4l2_dbg(1, debug, sd, "g_ctrl called\n"); - - switch (ctrl->id) { - case V4L2_CID_GAIN: - ctrl->value = core->global_gain; - return 0; - case V4L2_CID_RED_BALANCE: - ctrl->value = core->red_bal; - return 0; - case V4L2_CID_BLUE_BALANCE: - ctrl->value = core->blue_bal; - return 0; - case V4L2_CID_HFLIP: - ctrl->value = core->hflip ? 1 : 0; - return 0; - case V4L2_CID_VFLIP: - ctrl->value = core->vflip ? 1 : 0; - return 0; - } - return -EINVAL; -} - -static int mt9v011_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - int i; - - v4l2_dbg(1, debug, sd, "queryctrl called\n"); - - for (i = 0; i < ARRAY_SIZE(mt9v011_qctrl); i++) - if (qc->id && qc->id == mt9v011_qctrl[i].id) { - memcpy(qc, &(mt9v011_qctrl[i]), - sizeof(*qc)); - return 0; - } - - return -EINVAL; -} - - -static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct mt9v011 *core = to_mt9v011(sd); - u8 i, n; - n = ARRAY_SIZE(mt9v011_qctrl); - - for (i = 0; i < n; i++) { - if (ctrl->id != mt9v011_qctrl[i].id) - continue; - if (ctrl->value < mt9v011_qctrl[i].minimum || - ctrl->value > mt9v011_qctrl[i].maximum) - return -ERANGE; - v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n", - ctrl->id, ctrl->value); - break; - } - - switch (ctrl->id) { - case V4L2_CID_GAIN: - core->global_gain = ctrl->value; - break; - case V4L2_CID_RED_BALANCE: - core->red_bal = ctrl->value; - break; - case V4L2_CID_BLUE_BALANCE: - core->blue_bal = ctrl->value; - break; - case V4L2_CID_HFLIP: - core->hflip = ctrl->value; - set_read_mode(sd); - return 0; - case V4L2_CID_VFLIP: - core->vflip = ctrl->value; - set_read_mode(sd); - return 0; - default: - return -EINVAL; - } - - set_balance(sd); - - return 0; -} - -static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - enum v4l2_mbus_pixelcode *code) -{ - if (index > 0) - return -EINVAL; - - *code = V4L2_MBUS_FMT_SGRBG8_1X8; - return 0; -} - -static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) -{ - if (fmt->code != V4L2_MBUS_FMT_SGRBG8_1X8) - return -EINVAL; - - v4l_bound_align_image(&fmt->width, 48, 639, 1, - &fmt->height, 32, 480, 1, 0); - fmt->field = V4L2_FIELD_NONE; - fmt->colorspace = V4L2_COLORSPACE_SRGB; - - return 0; -} - -static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -{ - struct v4l2_captureparm *cp = &parms->parm.capture; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(struct v4l2_captureparm)); - cp->capability = V4L2_CAP_TIMEPERFRAME; - calc_fps(sd, - &cp->timeperframe.numerator, - &cp->timeperframe.denominator); - - return 0; -} - -static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -{ - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; - u16 speed; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (cp->extendedmode != 0) - return -EINVAL; - - speed = calc_speed(sd, tpf->numerator, tpf->denominator); - - mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed); - v4l2_dbg(1, debug, sd, "Setting speed to %d\n", speed); - - /* Recalculate and update fps info */ - calc_fps(sd, &tpf->numerator, &tpf->denominator); - - return 0; -} - -static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) -{ - struct mt9v011 *core = to_mt9v011(sd); - int rc; - - rc = mt9v011_try_mbus_fmt(sd, fmt); - if (rc < 0) - return -EINVAL; - - core->width = fmt->width; - core->height = fmt->height; - - set_res(sd); - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9v011_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - reg->val = mt9v011_read(sd, reg->reg & 0xff); - reg->size = 2; - - return 0; -} - -static int mt9v011_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - mt9v011_write(sd, reg->reg & 0xff, reg->val & 0xffff); - - return 0; -} -#endif - -static int mt9v011_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - u16 version; - struct i2c_client *client = v4l2_get_subdevdata(sd); - - version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9V011, - version); -} - -static const struct v4l2_subdev_core_ops mt9v011_core_ops = { - .queryctrl = mt9v011_queryctrl, - .g_ctrl = mt9v011_g_ctrl, - .s_ctrl = mt9v011_s_ctrl, - .reset = mt9v011_reset, - .g_chip_ident = mt9v011_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9v011_g_register, - .s_register = mt9v011_s_register, -#endif -}; - -static const struct v4l2_subdev_video_ops mt9v011_video_ops = { - .enum_mbus_fmt = mt9v011_enum_mbus_fmt, - .try_mbus_fmt = mt9v011_try_mbus_fmt, - .s_mbus_fmt = mt9v011_s_mbus_fmt, - .g_parm = mt9v011_g_parm, - .s_parm = mt9v011_s_parm, -}; - -static const struct v4l2_subdev_ops mt9v011_ops = { - .core = &mt9v011_core_ops, - .video = &mt9v011_video_ops, -}; - - -/**************************************************************************** - I2C Client & Driver - ****************************************************************************/ - -static int mt9v011_probe(struct i2c_client *c, - const struct i2c_device_id *id) -{ - u16 version; - struct mt9v011 *core; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(c->adapter, - I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - return -EIO; - - core = kzalloc(sizeof(struct mt9v011), GFP_KERNEL); - if (!core) - return -ENOMEM; - - sd = &core->sd; - v4l2_i2c_subdev_init(sd, c, &mt9v011_ops); - - /* Check if the sensor is really a MT9V011 */ - version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION); - if ((version != MT9V011_VERSION) && - (version != MT9V011_REV_B_VERSION)) { - v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n", - version); - kfree(core); - return -EINVAL; - } - - core->global_gain = 0x0024; - core->width = 640; - core->height = 480; - core->xtal = 27000000; /* Hz */ - - if (c->dev.platform_data) { - struct mt9v011_platform_data *pdata = c->dev.platform_data; - - core->xtal = pdata->xtal; - v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n", - core->xtal / 1000000, (core->xtal / 1000) % 1000); - } - - v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n", - c->addr << 1, c->adapter->name, version); - - return 0; -} - -static int mt9v011_remove(struct i2c_client *c) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(c); - - v4l2_dbg(1, debug, sd, - "mt9v011.c: removing mt9v011 adapter on address 0x%x\n", - c->addr << 1); - - v4l2_device_unregister_subdev(sd); - kfree(to_mt9v011(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id mt9v011_id[] = { - { "mt9v011", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9v011_id); - -static struct i2c_driver mt9v011_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "mt9v011", - }, - .probe = mt9v011_probe, - .remove = mt9v011_remove, - .id_table = mt9v011_id, -}; - -static __init int init_mt9v011(void) -{ - return i2c_add_driver(&mt9v011_driver); -} - -static __exit void exit_mt9v011(void) -{ - i2c_del_driver(&mt9v011_driver); -} - -module_init(init_mt9v011); -module_exit(exit_mt9v011); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9v022.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9v022.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9v022.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mt9v022.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,967 +0,0 @@ -/* - * Driver for MT9V022 CMOS Image Sensor from Micron - * - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c - * The platform has to define ctruct i2c_board_info objects and link to them - * from struct soc_camera_link - */ - -static char *sensor_type; -module_param(sensor_type, charp, S_IRUGO); -MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); - -/* mt9v022 selected register addresses */ -#define MT9V022_CHIP_VERSION 0x00 -#define MT9V022_COLUMN_START 0x01 -#define MT9V022_ROW_START 0x02 -#define MT9V022_WINDOW_HEIGHT 0x03 -#define MT9V022_WINDOW_WIDTH 0x04 -#define MT9V022_HORIZONTAL_BLANKING 0x05 -#define MT9V022_VERTICAL_BLANKING 0x06 -#define MT9V022_CHIP_CONTROL 0x07 -#define MT9V022_SHUTTER_WIDTH1 0x08 -#define MT9V022_SHUTTER_WIDTH2 0x09 -#define MT9V022_SHUTTER_WIDTH_CTRL 0x0a -#define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b -#define MT9V022_RESET 0x0c -#define MT9V022_READ_MODE 0x0d -#define MT9V022_MONITOR_MODE 0x0e -#define MT9V022_PIXEL_OPERATION_MODE 0x0f -#define MT9V022_LED_OUT_CONTROL 0x1b -#define MT9V022_ADC_MODE_CONTROL 0x1c -#define MT9V022_ANALOG_GAIN 0x35 -#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 -#define MT9V022_PIXCLK_FV_LV 0x74 -#define MT9V022_DIGITAL_TEST_PATTERN 0x7f -#define MT9V022_AEC_AGC_ENABLE 0xAF -#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD - -/* Progressive scan, master, defaults */ -#define MT9V022_CHIP_CONTROL_DEFAULT 0x188 - -#define MT9V022_MAX_WIDTH 752 -#define MT9V022_MAX_HEIGHT 480 -#define MT9V022_MIN_WIDTH 48 -#define MT9V022_MIN_HEIGHT 32 -#define MT9V022_COLUMN_SKIP 1 -#define MT9V022_ROW_SKIP 4 - -/* MT9V022 has only one fixed colorspace per pixelcode */ -struct mt9v022_datafmt { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; -}; - -/* Find a data format by a pixel code in an array */ -static const struct mt9v022_datafmt *mt9v022_find_datafmt( - enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - -static const struct mt9v022_datafmt mt9v022_colour_fmts[] = { - /* - * Order important: first natively supported, - * second supported with a GPIO extender - */ - {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, -}; - -static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { - /* Order important - see above */ - {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, -}; - -struct mt9v022 { - struct v4l2_subdev subdev; - struct v4l2_rect rect; /* Sensor window */ - const struct mt9v022_datafmt *fmt; - const struct mt9v022_datafmt *fmts; - int num_fmts; - int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ - u16 chip_control; - unsigned short y_skip_top; /* Lines to skip at the top */ -}; - -static struct mt9v022 *to_mt9v022(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct mt9v022, subdev); -} - -static int reg_read(struct i2c_client *client, const u8 reg) -{ - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : swab16(data); -} - -static int reg_write(struct i2c_client *client, const u8 reg, - const u16 data) -{ - return i2c_smbus_write_word_data(client, reg, swab16(data)); -} - -static int reg_set(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret | data); -} - -static int reg_clear(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret & ~data); -} - -static int mt9v022_init(struct i2c_client *client) -{ - struct mt9v022 *mt9v022 = to_mt9v022(client); - int ret; - - /* - * Almost the default mode: master, parallel, simultaneous, and an - * undocumented bit 0x200, which is present in table 7, but not in 8, - * plus snapshot mode to disable scan for now - */ - mt9v022->chip_control |= 0x10; - ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); - if (!ret) - ret = reg_write(client, MT9V022_READ_MODE, 0x300); - - /* All defaults */ - if (!ret) - /* AEC, AGC on */ - ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); - if (!ret) - ret = reg_write(client, MT9V022_ANALOG_GAIN, 16); - if (!ret) - ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480); - if (!ret) - ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); - if (!ret) - /* default - auto */ - ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); - if (!ret) - ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); - - return ret; -} - -static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - if (enable) - /* Switch to master "normal" mode */ - mt9v022->chip_control &= ~0x10; - else - /* Switch to snapshot mode */ - mt9v022->chip_control |= 0x10; - - if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) - return -EIO; - return 0; -} - -static int mt9v022_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; - int ret; - u16 pixclk = 0; - - /* Only one width bit may be set */ - if (!is_power_of_2(width_flag)) - return -EINVAL; - - if (icl->set_bus_param) { - ret = icl->set_bus_param(icl, width_flag); - if (ret) - return ret; - } else { - /* - * Without board specific bus width settings we only support the - * sensors native bus width - */ - if (width_flag != SOCAM_DATAWIDTH_10) - return -EINVAL; - } - - flags = soc_camera_apply_sensor_flags(icl, flags); - - if (flags & SOCAM_PCLK_SAMPLE_RISING) - pixclk |= 0x10; - - if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH)) - pixclk |= 0x1; - - if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH)) - pixclk |= 0x2; - - ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); - if (ret < 0) - return ret; - - if (!(flags & SOCAM_MASTER)) - mt9v022->chip_control &= ~0x8; - - ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); - if (ret < 0) - return ret; - - dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", - pixclk, mt9v022->chip_control); - - return 0; -} - -static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned int flags = SOCAM_MASTER | SOCAM_SLAVE | - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH; - - if (icl->query_bus_param) - flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct v4l2_rect rect = a->c; - int ret; - - /* Bayer format - even size lengths */ - if (mt9v022->fmts == mt9v022_colour_fmts) { - rect.width = ALIGN(rect.width, 2); - rect.height = ALIGN(rect.height, 2); - /* Let the user play with the starting pixel */ - } - - soc_camera_limit_side(&rect.left, &rect.width, - MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH); - - soc_camera_limit_side(&rect.top, &rect.height, - MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT); - - /* Like in example app. Contradicts the datasheet though */ - ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); - if (ret >= 0) { - if (ret & 1) /* Autoexposure */ - ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, - rect.height + mt9v022->y_skip_top + 43); - else - ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, - rect.height + mt9v022->y_skip_top + 43); - } - /* Setup frame format: defaults apart from width and height */ - if (!ret) - ret = reg_write(client, MT9V022_COLUMN_START, rect.left); - if (!ret) - ret = reg_write(client, MT9V022_ROW_START, rect.top); - if (!ret) - /* - * Default 94, Phytec driver says: - * "width + horizontal blank >= 660" - */ - ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, - rect.width > 660 - 43 ? 43 : - 660 - rect.width); - if (!ret) - ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); - if (!ret) - ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); - if (!ret) - ret = reg_write(client, MT9V022_WINDOW_HEIGHT, - rect.height + mt9v022->y_skip_top); - - if (ret < 0) - return ret; - - dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height); - - mt9v022->rect = rect; - - return 0; -} - -static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - a->c = mt9v022->rect; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = MT9V022_COLUMN_SKIP; - a->bounds.top = MT9V022_ROW_SKIP; - a->bounds.width = MT9V022_MAX_WIDTH; - a->bounds.height = MT9V022_MAX_HEIGHT; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int mt9v022_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - mf->width = mt9v022->rect.width; - mf->height = mt9v022->rect.height; - mf->code = mt9v022->fmt->code; - mf->colorspace = mt9v022->fmt->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9v022_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct v4l2_crop a = { - .c = { - .left = mt9v022->rect.left, - .top = mt9v022->rect.top, - .width = mf->width, - .height = mf->height, - }, - }; - int ret; - - /* - * The caller provides a supported format, as verified per call to - * icd->try_fmt(), datawidth is from our supported format list - */ - switch (mf->code) { - case V4L2_MBUS_FMT_Y8_1X8: - case V4L2_MBUS_FMT_Y10_1X10: - if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) - return -EINVAL; - break; - case V4L2_MBUS_FMT_SBGGR8_1X8: - case V4L2_MBUS_FMT_SBGGR10_1X10: - if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) - return -EINVAL; - break; - default: - return -EINVAL; - } - - /* No support for scaling on this camera, just crop. */ - ret = mt9v022_s_crop(sd, &a); - if (!ret) { - mf->width = mt9v022->rect.width; - mf->height = mt9v022->rect.height; - mt9v022->fmt = mt9v022_find_datafmt(mf->code, - mt9v022->fmts, mt9v022->num_fmts); - mf->colorspace = mt9v022->fmt->colorspace; - } - - return ret; -} - -static int mt9v022_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - const struct mt9v022_datafmt *fmt; - int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || - mf->code == V4L2_MBUS_FMT_SBGGR10_1X10; - - v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH, - MT9V022_MAX_WIDTH, align, - &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top, - MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0); - - fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts, - mt9v022->num_fmts); - if (!fmt) { - fmt = mt9v022->fmt; - mf->code = fmt->code; - } - - mf->colorspace = fmt->colorspace; - - return 0; -} - -static int mt9v022_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) - return -EINVAL; - - if (id->match.addr != client->addr) - return -ENODEV; - - id->ident = mt9v022->model; - id->revision = 0; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9v022_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - reg->size = 2; - reg->val = reg_read(client, reg->reg); - - if (reg->val > 0xffff) - return -EIO; - - return 0; -} - -static int mt9v022_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - if (reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static const struct v4l2_queryctrl mt9v022_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Analog Gain", - .minimum = 64, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9v022_ops = { - .set_bus_param = mt9v022_set_bus_param, - .query_bus_param = mt9v022_query_bus_param, - .controls = mt9v022_controls, - .num_controls = ARRAY_SIZE(mt9v022_controls), -}; - -static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct v4l2_queryctrl *qctrl; - unsigned long range; - int data; - - qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, MT9V022_READ_MODE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x10); - break; - case V4L2_CID_HFLIP: - data = reg_read(client, MT9V022_READ_MODE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x20); - break; - case V4L2_CID_EXPOSURE_AUTO: - data = reg_read(client, MT9V022_AEC_AGC_ENABLE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x1); - break; - case V4L2_CID_AUTOGAIN: - data = reg_read(client, MT9V022_AEC_AGC_ENABLE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x2); - break; - case V4L2_CID_GAIN: - data = reg_read(client, MT9V022_ANALOG_GAIN); - if (data < 0) - return -EIO; - - range = qctrl->maximum - qctrl->minimum; - ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; - - break; - case V4L2_CID_EXPOSURE: - data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); - if (data < 0) - return -EIO; - - range = qctrl->maximum - qctrl->minimum; - ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; - - break; - } - return 0; -} - -static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - int data; - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct v4l2_queryctrl *qctrl; - - qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); - if (!qctrl) - return -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->value) - data = reg_set(client, MT9V022_READ_MODE, 0x10); - else - data = reg_clear(client, MT9V022_READ_MODE, 0x10); - if (data < 0) - return -EIO; - break; - case V4L2_CID_HFLIP: - if (ctrl->value) - data = reg_set(client, MT9V022_READ_MODE, 0x20); - else - data = reg_clear(client, MT9V022_READ_MODE, 0x20); - if (data < 0) - return -EIO; - break; - case V4L2_CID_GAIN: - /* mt9v022 has minimum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - unsigned long range = qctrl->maximum - qctrl->minimum; - /* Valid values 16 to 64, 32 to 64 must be even. */ - unsigned long gain = ((ctrl->value - qctrl->minimum) * - 48 + range / 2) / range + 16; - if (gain >= 32) - gain &= ~1; - /* - * The user wants to set gain manually, hope, she - * knows, what she's doing... Switch AGC off. - */ - - if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) - return -EIO; - - dev_dbg(&client->dev, "Setting gain from %d to %lu\n", - reg_read(client, MT9V022_ANALOG_GAIN), gain); - if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) - return -EIO; - } - break; - case V4L2_CID_EXPOSURE: - /* mt9v022 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - unsigned long range = qctrl->maximum - qctrl->minimum; - unsigned long shutter = ((ctrl->value - qctrl->minimum) * - 479 + range / 2) / range + 1; - /* - * The user wants to set shutter width manually, hope, - * she knows, what she's doing... Switch AEC off. - */ - - if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) - return -EIO; - - dev_dbg(&client->dev, "Shutter width from %d to %lu\n", - reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), - shutter); - if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, - shutter) < 0) - return -EIO; - } - break; - case V4L2_CID_AUTOGAIN: - if (ctrl->value) - data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); - else - data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); - if (data < 0) - return -EIO; - break; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->value) - data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); - else - data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); - if (data < 0) - return -EIO; - break; - } - return 0; -} - -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int mt9v022_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - s32 data; - int ret; - unsigned long flags; - - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; - - /* Read out the chip version register */ - data = reg_read(client, MT9V022_CHIP_VERSION); - - /* must be 0x1311 or 0x1313 */ - if (data != 0x1311 && data != 0x1313) { - ret = -ENODEV; - dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n", - data); - goto ei2c; - } - - /* Soft reset */ - ret = reg_write(client, MT9V022_RESET, 1); - if (ret < 0) - goto ei2c; - /* 15 clock cycles */ - udelay(200); - if (reg_read(client, MT9V022_RESET)) { - dev_err(&client->dev, "Resetting MT9V022 failed!\n"); - if (ret > 0) - ret = -EIO; - goto ei2c; - } - - /* Set monochrome or colour sensor type */ - if (sensor_type && (!strcmp("colour", sensor_type) || - !strcmp("color", sensor_type))) { - ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); - mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; - mt9v022->fmts = mt9v022_colour_fmts; - } else { - ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); - mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; - mt9v022->fmts = mt9v022_monochrome_fmts; - } - - if (ret < 0) - goto ei2c; - - mt9v022->num_fmts = 0; - - /* - * This is a 10bit sensor, so by default we only allow 10bit. - * The platform may support different bus widths due to - * different routing of the data lines. - */ - if (icl->query_bus_param) - flags = icl->query_bus_param(icl); - else - flags = SOCAM_DATAWIDTH_10; - - if (flags & SOCAM_DATAWIDTH_10) - mt9v022->num_fmts++; - else - mt9v022->fmts++; - - if (flags & SOCAM_DATAWIDTH_8) - mt9v022->num_fmts++; - - mt9v022->fmt = &mt9v022->fmts[0]; - - dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", - data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? - "monochrome" : "colour"); - - ret = mt9v022_init(client); - if (ret < 0) - dev_err(&client->dev, "Failed to initialise the camera\n"); - -ei2c: - return ret; -} - -static void mt9v022_video_remove(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - dev_dbg(&icd->dev, "Video removed: %p, %p\n", - icd->dev.parent, icd->vdev); - if (icl->free_bus) - icl->free_bus(icl); -} - -static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - *lines = mt9v022->y_skip_top; - - return 0; -} - -static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { - .g_ctrl = mt9v022_g_ctrl, - .s_ctrl = mt9v022_s_ctrl, - .g_chip_ident = mt9v022_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9v022_g_register, - .s_register = mt9v022_s_register, -#endif -}; - -static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - if (index >= mt9v022->num_fmts) - return -EINVAL; - - *code = mt9v022->fmts[index].code; - return 0; -} - -static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { - .s_stream = mt9v022_s_stream, - .s_mbus_fmt = mt9v022_s_fmt, - .g_mbus_fmt = mt9v022_g_fmt, - .try_mbus_fmt = mt9v022_try_fmt, - .s_crop = mt9v022_s_crop, - .g_crop = mt9v022_g_crop, - .cropcap = mt9v022_cropcap, - .enum_mbus_fmt = mt9v022_enum_fmt, -}; - -static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { - .g_skip_top_lines = mt9v022_g_skip_top_lines, -}; - -static struct v4l2_subdev_ops mt9v022_subdev_ops = { - .core = &mt9v022_subdev_core_ops, - .video = &mt9v022_subdev_video_ops, - .sensor = &mt9v022_subdev_sensor_ops, -}; - -static int mt9v022_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9v022 *mt9v022; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "MT9V022 driver needs platform data\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); - return -EIO; - } - - mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL); - if (!mt9v022) - return -ENOMEM; - - v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); - - mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; - - icd->ops = &mt9v022_ops; - /* - * MT9V022 _really_ corrupts the first read out line. - * TODO: verify on i.MX31 - */ - mt9v022->y_skip_top = 1; - mt9v022->rect.left = MT9V022_COLUMN_SKIP; - mt9v022->rect.top = MT9V022_ROW_SKIP; - mt9v022->rect.width = MT9V022_MAX_WIDTH; - mt9v022->rect.height = MT9V022_MAX_HEIGHT; - - ret = mt9v022_video_probe(icd, client); - if (ret) { - icd->ops = NULL; - kfree(mt9v022); - } - - return ret; -} - -static int mt9v022_remove(struct i2c_client *client) -{ - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_device *icd = client->dev.platform_data; - - icd->ops = NULL; - mt9v022_video_remove(icd); - kfree(mt9v022); - - return 0; -} -static const struct i2c_device_id mt9v022_id[] = { - { "mt9v022", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9v022_id); - -static struct i2c_driver mt9v022_i2c_driver = { - .driver = { - .name = "mt9v022", - }, - .probe = mt9v022_probe, - .remove = mt9v022_remove, - .id_table = mt9v022_id, -}; - -static int __init mt9v022_mod_init(void) -{ - return i2c_add_driver(&mt9v022_i2c_driver); -} - -static void __exit mt9v022_mod_exit(void) -{ - i2c_del_driver(&mt9v022_i2c_driver); -} - -module_init(mt9v022_mod_init); -module_exit(mt9v022_mod_exit); - -MODULE_DESCRIPTION("Micron MT9V022 Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx1_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx1_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx1_camera.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx1_camera.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,890 +0,0 @@ -/* - * V4L2 Driver for i.MXL/i.MXL camera (CSI) host - * - * Copyright (C) 2008, Paulius Zaleckas - * Copyright (C) 2009, Darius Augulis - * - * Based on PXA SoC camera driver - * Copyright (C) 2006, Sascha Hauer, Pengutronix - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * CSI registers - */ -#define CSICR1 0x00 /* CSI Control Register 1 */ -#define CSISR 0x08 /* CSI Status Register */ -#define CSIRXR 0x10 /* CSI RxFIFO Register */ - -#define CSICR1_RXFF_LEVEL(x) (((x) & 0x3) << 19) -#define CSICR1_SOF_POL (1 << 17) -#define CSICR1_SOF_INTEN (1 << 16) -#define CSICR1_MCLKDIV(x) (((x) & 0xf) << 12) -#define CSICR1_MCLKEN (1 << 9) -#define CSICR1_FCC (1 << 8) -#define CSICR1_BIG_ENDIAN (1 << 7) -#define CSICR1_CLR_RXFIFO (1 << 5) -#define CSICR1_GCLK_MODE (1 << 4) -#define CSICR1_DATA_POL (1 << 2) -#define CSICR1_REDGE (1 << 1) -#define CSICR1_EN (1 << 0) - -#define CSISR_SFF_OR_INT (1 << 25) -#define CSISR_RFF_OR_INT (1 << 24) -#define CSISR_STATFF_INT (1 << 21) -#define CSISR_RXFF_INT (1 << 18) -#define CSISR_SOF_INT (1 << 16) -#define CSISR_DRDY (1 << 0) - -#define VERSION_CODE KERNEL_VERSION(0, 0, 1) -#define DRIVER_NAME "mx1-camera" - -#define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \ - CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT) - -#define CSI_BUS_FLAGS (SOCAM_MASTER | SOCAM_HSYNC_ACTIVE_HIGH | \ - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | \ - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW | \ - SOCAM_DATAWIDTH_8) - -#define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */ - -/* - * Structures - */ - -/* buffer for one video frame */ -struct mx1_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - enum v4l2_mbus_pixelcode code; - int inwork; -}; - -/* - * i.MX1/i.MXL is only supposed to handle one camera on its Camera Sensor - * Interface. If anyone ever builds hardware to enable more than - * one camera, they will have to modify this driver too - */ -struct mx1_camera_dev { - struct soc_camera_host soc_host; - struct soc_camera_device *icd; - struct mx1_camera_pdata *pdata; - struct mx1_buffer *active; - struct resource *res; - struct clk *clk; - struct list_head capture; - - void __iomem *base; - int dma_chan; - unsigned int irq; - unsigned long mclk; - - spinlock_t lock; -}; - -/* - * Videobuf operations - */ -static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct soc_camera_device *icd = vq->priv_data; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - if (bytes_per_line < 0) - return bytes_per_line; - - *size = bytes_per_line * icd->user_height; - - if (!*count) - *count = 32; - - if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) - *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; - - dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf) -{ - struct soc_camera_device *icd = vq->priv_data; - struct videobuf_buffer *vb = &buf->vb; - - BUG_ON(in_interrupt()); - - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - /* - * This waits until this buffer is out of danger, i.e., until it is no - * longer in STATE_QUEUED or STATE_ACTIVE - */ - videobuf_waiton(vq, vb, 0, 0); - videobuf_dma_contig_free(vq, vb); - - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static int mx1_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct soc_camera_device *icd = vq->priv_data; - struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); - int ret; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - if (bytes_per_line < 0) - return bytes_per_line; - - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - /* Added list head initialization on alloc */ - WARN_ON(!list_empty(&vb->queue)); - - BUG_ON(NULL == icd->current_fmt); - - /* - * I think, in buf_prepare you only have to protect global data, - * the actual buffer is yours - */ - buf->inwork = 1; - - if (buf->code != icd->current_fmt->code || - vb->width != icd->user_width || - vb->height != icd->user_height || - vb->field != field) { - buf->code = icd->current_fmt->code; - vb->width = icd->user_width; - vb->height = icd->user_height; - vb->field = field; - vb->state = VIDEOBUF_NEEDS_INIT; - } - - vb->size = bytes_per_line * vb->height; - if (0 != vb->baddr && vb->bsize < vb->size) { - ret = -EINVAL; - goto out; - } - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret) - goto fail; - - vb->state = VIDEOBUF_PREPARED; - } - - buf->inwork = 0; - - return 0; - -fail: - free_buffer(vq, buf); -out: - buf->inwork = 0; - return ret; -} - -static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) -{ - struct videobuf_buffer *vbuf = &pcdev->active->vb; - struct device *dev = pcdev->icd->dev.parent; - int ret; - - if (unlikely(!pcdev->active)) { - dev_err(dev, "DMA End IRQ with no active buffer\n"); - return -EFAULT; - } - - /* setup sg list for future DMA */ - ret = imx_dma_setup_single(pcdev->dma_chan, - videobuf_to_dma_contig(vbuf), - vbuf->size, pcdev->res->start + - CSIRXR, DMA_MODE_READ); - if (unlikely(ret)) - dev_err(dev, "Failed to setup DMA sg list\n"); - - return ret; -} - -/* Called under spinlock_irqsave(&pcdev->lock, ...) */ -static void mx1_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx1_camera_dev *pcdev = ici->priv; - struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); - - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - list_add_tail(&vb->queue, &pcdev->capture); - - vb->state = VIDEOBUF_ACTIVE; - - if (!pcdev->active) { - pcdev->active = buf; - - /* setup sg list for future DMA */ - if (!mx1_camera_setup_dma(pcdev)) { - unsigned int temp; - /* enable SOF irq */ - temp = __raw_readl(pcdev->base + CSICR1) | - CSICR1_SOF_INTEN; - __raw_writel(temp, pcdev->base + CSICR1); - } - } -} - -static void mx1_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); -#ifdef DEBUG - struct soc_camera_device *icd = vq->priv_data; - struct device *dev = icd->dev.parent; - - dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - switch (vb->state) { - case VIDEOBUF_ACTIVE: - dev_dbg(dev, "%s (active)\n", __func__); - break; - case VIDEOBUF_QUEUED: - dev_dbg(dev, "%s (queued)\n", __func__); - break; - case VIDEOBUF_PREPARED: - dev_dbg(dev, "%s (prepared)\n", __func__); - break; - default: - dev_dbg(dev, "%s (unknown)\n", __func__); - break; - } -#endif - - free_buffer(vq, buf); -} - -static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev, - struct videobuf_buffer *vb, - struct mx1_buffer *buf) -{ - /* _init is used to debug races, see comment in mx1_camera_reqbufs() */ - list_del_init(&vb->queue); - vb->state = VIDEOBUF_DONE; - do_gettimeofday(&vb->ts); - vb->field_count++; - wake_up(&vb->done); - - if (list_empty(&pcdev->capture)) { - pcdev->active = NULL; - return; - } - - pcdev->active = list_entry(pcdev->capture.next, - struct mx1_buffer, vb.queue); - - /* setup sg list for future DMA */ - if (likely(!mx1_camera_setup_dma(pcdev))) { - unsigned int temp; - - /* enable SOF irq */ - temp = __raw_readl(pcdev->base + CSICR1) | CSICR1_SOF_INTEN; - __raw_writel(temp, pcdev->base + CSICR1); - } -} - -static void mx1_camera_dma_irq(int channel, void *data) -{ - struct mx1_camera_dev *pcdev = data; - struct device *dev = pcdev->icd->dev.parent; - struct mx1_buffer *buf; - struct videobuf_buffer *vb; - unsigned long flags; - - spin_lock_irqsave(&pcdev->lock, flags); - - imx_dma_disable(channel); - - if (unlikely(!pcdev->active)) { - dev_err(dev, "DMA End IRQ with no active buffer\n"); - goto out; - } - - vb = &pcdev->active->vb; - buf = container_of(vb, struct mx1_buffer, vb); - WARN_ON(buf->inwork || list_empty(&vb->queue)); - dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - mx1_camera_wakeup(pcdev, vb, buf); -out: - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static struct videobuf_queue_ops mx1_videobuf_ops = { - .buf_setup = mx1_videobuf_setup, - .buf_prepare = mx1_videobuf_prepare, - .buf_queue = mx1_videobuf_queue, - .buf_release = mx1_videobuf_release, -}; - -static void mx1_camera_init_videobuf(struct videobuf_queue *q, - struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx1_camera_dev *pcdev = ici->priv; - - videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent, - &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_NONE, - sizeof(struct mx1_buffer), icd, &icd->video_lock); -} - -static int mclk_get_divisor(struct mx1_camera_dev *pcdev) -{ - unsigned int mclk = pcdev->mclk; - unsigned long div; - unsigned long lcdclk; - - lcdclk = clk_get_rate(pcdev->clk); - - /* - * We verify platform_mclk_10khz != 0, so if anyone breaks it, here - * they get a nice Oops - */ - div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; - - dev_dbg(pcdev->icd->dev.parent, - "System clock %lukHz, target freq %dkHz, divisor %lu\n", - lcdclk / 1000, mclk / 1000, div); - - return div; -} - -static void mx1_camera_activate(struct mx1_camera_dev *pcdev) -{ - unsigned int csicr1 = CSICR1_EN; - - dev_dbg(pcdev->icd->dev.parent, "Activate device\n"); - - clk_enable(pcdev->clk); - - /* enable CSI before doing anything else */ - __raw_writel(csicr1, pcdev->base + CSICR1); - - csicr1 |= CSICR1_MCLKEN | CSICR1_FCC | CSICR1_GCLK_MODE; - csicr1 |= CSICR1_MCLKDIV(mclk_get_divisor(pcdev)); - csicr1 |= CSICR1_RXFF_LEVEL(2); /* 16 words */ - - __raw_writel(csicr1, pcdev->base + CSICR1); -} - -static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) -{ - dev_dbg(pcdev->icd->dev.parent, "Deactivate device\n"); - - /* Disable all CSI interface */ - __raw_writel(0x00, pcdev->base + CSICR1); - - clk_disable(pcdev->clk); -} - -/* - * The following two functions absolutely depend on the fact, that - * there can be only one camera on i.MX1/i.MXL camera sensor interface - */ -static int mx1_camera_add_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx1_camera_dev *pcdev = ici->priv; - int ret; - - if (pcdev->icd) { - ret = -EBUSY; - goto ebusy; - } - - dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n", - icd->devnum); - - mx1_camera_activate(pcdev); - - pcdev->icd = icd; - -ebusy: - return ret; -} - -static void mx1_camera_remove_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx1_camera_dev *pcdev = ici->priv; - unsigned int csicr1; - - BUG_ON(icd != pcdev->icd); - - /* disable interrupts */ - csicr1 = __raw_readl(pcdev->base + CSICR1) & ~CSI_IRQ_MASK; - __raw_writel(csicr1, pcdev->base + CSICR1); - - /* Stop DMA engine */ - imx_dma_disable(pcdev->dma_chan); - - dev_info(icd->dev.parent, "MX1 Camera driver detached from camera %d\n", - icd->devnum); - - mx1_camera_deactivate(pcdev); - - pcdev->icd = NULL; -} - -static int mx1_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_subdev_call(sd, video, s_crop, a); -} - -static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx1_camera_dev *pcdev = ici->priv; - unsigned long camera_flags, common_flags; - unsigned int csicr1; - int ret; - - camera_flags = icd->ops->query_bus_param(icd); - - /* MX1 supports only 8bit buswidth */ - common_flags = soc_camera_bus_param_compatible(camera_flags, - CSI_BUS_FLAGS); - if (!common_flags) - return -EINVAL; - - /* Make choises, based on platform choice */ - if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { - if (!pcdev->pdata || - pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH) - common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; - else - common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; - } - - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { - if (!pcdev->pdata || - pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING) - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; - else - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; - } - - if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && - (common_flags & SOCAM_DATA_ACTIVE_LOW)) { - if (!pcdev->pdata || - pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH) - common_flags &= ~SOCAM_DATA_ACTIVE_LOW; - else - common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; - } - - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) - return ret; - - csicr1 = __raw_readl(pcdev->base + CSICR1); - - if (common_flags & SOCAM_PCLK_SAMPLE_RISING) - csicr1 |= CSICR1_REDGE; - if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) - csicr1 |= CSICR1_SOF_POL; - if (common_flags & SOCAM_DATA_ACTIVE_LOW) - csicr1 |= CSICR1_DATA_POL; - - __raw_writel(csicr1, pcdev->base + CSICR1); - - return 0; -} - -static int mx1_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - int ret, buswidth; - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", - pix->pixelformat); - return -EINVAL; - } - - buswidth = xlate->host_fmt->bits_per_sample; - if (buswidth > 8) { - dev_warn(icd->dev.parent, - "bits-per-sample %d for format %x unsupported\n", - buswidth, pix->pixelformat); - return -EINVAL; - } - - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); - if (ret < 0) - return ret; - - if (mf.code != xlate->code) - return -EINVAL; - - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; - icd->current_fmt = xlate; - - return ret; -} - -static int mx1_camera_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - int ret; - /* TODO: limit to mx1 hardware capabilities */ - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", - pix->pixelformat); - return -EINVAL; - } - - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - /* limit to sensor capabilities */ - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); - if (ret < 0) - return ret; - - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; - - return 0; -} - -static int mx1_camera_reqbufs(struct soc_camera_device *icd, - struct v4l2_requestbuffers *p) -{ - int i; - - /* - * This is for locking debugging only. I removed spinlocks and now I - * check whether .prepare is ever called on a linked buffer, or whether - * a dma IRQ can occur for an in-work or unlinked buffer. Until now - * it hadn't triggered - */ - for (i = 0; i < p->count; i++) { - struct mx1_buffer *buf = container_of(icd->vb_vidq.bufs[i], - struct mx1_buffer, vb); - buf->inwork = 0; - INIT_LIST_HEAD(&buf->vb.queue); - } - - return 0; -} - -static unsigned int mx1_camera_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - struct mx1_buffer *buf; - - buf = list_entry(icd->vb_vidq.stream.next, struct mx1_buffer, - vb.stream); - - poll_wait(file, &buf->vb.done, pt); - - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - return POLLIN | POLLRDNORM; - - return 0; -} - -static int mx1_camera_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - /* cap->name is set by the friendly caller:-> */ - strlcpy(cap->card, "i.MX1/i.MXL Camera", sizeof(cap->card)); - cap->version = VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - - return 0; -} - -static struct soc_camera_host_ops mx1_soc_camera_host_ops = { - .owner = THIS_MODULE, - .add = mx1_camera_add_device, - .remove = mx1_camera_remove_device, - .set_bus_param = mx1_camera_set_bus_param, - .set_crop = mx1_camera_set_crop, - .set_fmt = mx1_camera_set_fmt, - .try_fmt = mx1_camera_try_fmt, - .init_videobuf = mx1_camera_init_videobuf, - .reqbufs = mx1_camera_reqbufs, - .poll = mx1_camera_poll, - .querycap = mx1_camera_querycap, -}; - -static struct fiq_handler fh = { - .name = "csi_sof" -}; - -static int __init mx1_camera_probe(struct platform_device *pdev) -{ - struct mx1_camera_dev *pcdev; - struct resource *res; - struct pt_regs regs; - struct clk *clk; - void __iomem *base; - unsigned int irq; - int err = 0; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!res || (int)irq <= 0) { - err = -ENODEV; - goto exit; - } - - clk = clk_get(&pdev->dev, "csi_clk"); - if (IS_ERR(clk)) { - err = PTR_ERR(clk); - goto exit; - } - - pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); - if (!pcdev) { - dev_err(&pdev->dev, "Could not allocate pcdev\n"); - err = -ENOMEM; - goto exit_put_clk; - } - - pcdev->res = res; - pcdev->clk = clk; - - pcdev->pdata = pdev->dev.platform_data; - - if (pcdev->pdata) - pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; - - if (!pcdev->mclk) { - dev_warn(&pdev->dev, - "mclk_10khz == 0! Please, fix your platform data. " - "Using default 20MHz\n"); - pcdev->mclk = 20000000; - } - - INIT_LIST_HEAD(&pcdev->capture); - spin_lock_init(&pcdev->lock); - - /* - * Request the regions. - */ - if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) { - err = -EBUSY; - goto exit_kfree; - } - - base = ioremap(res->start, resource_size(res)); - if (!base) { - err = -ENOMEM; - goto exit_release; - } - pcdev->irq = irq; - pcdev->base = base; - - /* request dma */ - pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH); - if (pcdev->dma_chan < 0) { - dev_err(&pdev->dev, "Can't request DMA for MX1 CSI\n"); - err = -EBUSY; - goto exit_iounmap; - } - dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chan); - - imx_dma_setup_handlers(pcdev->dma_chan, mx1_camera_dma_irq, NULL, - pcdev); - - imx_dma_config_channel(pcdev->dma_chan, IMX_DMA_TYPE_FIFO, - IMX_DMA_MEMSIZE_32, MX1_DMA_REQ_CSI_R, 0); - /* burst length : 16 words = 64 bytes */ - imx_dma_config_burstlen(pcdev->dma_chan, 0); - - /* request irq */ - err = claim_fiq(&fh); - if (err) { - dev_err(&pdev->dev, "Camera interrupt register failed \n"); - goto exit_free_dma; - } - - set_fiq_handler(&mx1_camera_sof_fiq_start, &mx1_camera_sof_fiq_end - - &mx1_camera_sof_fiq_start); - - regs.ARM_r8 = (long)MX1_DMA_DIMR; - regs.ARM_r9 = (long)MX1_DMA_CCR(pcdev->dma_chan); - regs.ARM_r10 = (long)pcdev->base + CSICR1; - regs.ARM_fp = (long)pcdev->base + CSISR; - regs.ARM_sp = 1 << pcdev->dma_chan; - set_fiq_regs(®s); - - mxc_set_irq_fiq(irq, 1); - enable_fiq(irq); - - pcdev->soc_host.drv_name = DRIVER_NAME; - pcdev->soc_host.ops = &mx1_soc_camera_host_ops; - pcdev->soc_host.priv = pcdev; - pcdev->soc_host.v4l2_dev.dev = &pdev->dev; - pcdev->soc_host.nr = pdev->id; - err = soc_camera_host_register(&pcdev->soc_host); - if (err) - goto exit_free_irq; - - dev_info(&pdev->dev, "MX1 Camera driver loaded\n"); - - return 0; - -exit_free_irq: - disable_fiq(irq); - mxc_set_irq_fiq(irq, 0); - release_fiq(&fh); -exit_free_dma: - imx_dma_free(pcdev->dma_chan); -exit_iounmap: - iounmap(base); -exit_release: - release_mem_region(res->start, resource_size(res)); -exit_kfree: - kfree(pcdev); -exit_put_clk: - clk_put(clk); -exit: - return err; -} - -static int __exit mx1_camera_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - struct mx1_camera_dev *pcdev = container_of(soc_host, - struct mx1_camera_dev, soc_host); - struct resource *res; - - imx_dma_free(pcdev->dma_chan); - disable_fiq(pcdev->irq); - mxc_set_irq_fiq(pcdev->irq, 0); - release_fiq(&fh); - - clk_put(pcdev->clk); - - soc_camera_host_unregister(soc_host); - - iounmap(pcdev->base); - - res = pcdev->res; - release_mem_region(res->start, resource_size(res)); - - kfree(pcdev); - - dev_info(&pdev->dev, "MX1 Camera driver unloaded\n"); - - return 0; -} - -static struct platform_driver mx1_camera_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .remove = __exit_p(mx1_camera_remove), -}; - -static int __init mx1_camera_init(void) -{ - return platform_driver_probe(&mx1_camera_driver, mx1_camera_probe); -} - -static void __exit mx1_camera_exit(void) -{ - return platform_driver_unregister(&mx1_camera_driver); -} - -module_init(mx1_camera_init); -module_exit(mx1_camera_exit); - -MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver"); -MODULE_AUTHOR("Paulius Zaleckas "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx2_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx2_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx2_camera.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx2_camera.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1525 +0,0 @@ -/* - * V4L2 Driver for i.MX27/i.MX25 camera host - * - * Copyright (C) 2008, Sascha Hauer, Pengutronix - * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography - * - * 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, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#ifdef CONFIG_MACH_MX27 -#include -#endif -#include - -#include - -#define MX2_CAM_DRV_NAME "mx2-camera" -#define MX2_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) -#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera" - -/* reset values */ -#define CSICR1_RESET_VAL 0x40000800 -#define CSICR2_RESET_VAL 0x0 -#define CSICR3_RESET_VAL 0x0 - -/* csi control reg 1 */ -#define CSICR1_SWAP16_EN (1 << 31) -#define CSICR1_EXT_VSYNC (1 << 30) -#define CSICR1_EOF_INTEN (1 << 29) -#define CSICR1_PRP_IF_EN (1 << 28) -#define CSICR1_CCIR_MODE (1 << 27) -#define CSICR1_COF_INTEN (1 << 26) -#define CSICR1_SF_OR_INTEN (1 << 25) -#define CSICR1_RF_OR_INTEN (1 << 24) -#define CSICR1_STATFF_LEVEL (3 << 22) -#define CSICR1_STATFF_INTEN (1 << 21) -#define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) /* MX27 */ -#define CSICR1_FB2_DMA_INTEN (1 << 20) /* MX25 */ -#define CSICR1_FB1_DMA_INTEN (1 << 19) /* MX25 */ -#define CSICR1_RXFF_INTEN (1 << 18) -#define CSICR1_SOF_POL (1 << 17) -#define CSICR1_SOF_INTEN (1 << 16) -#define CSICR1_MCLKDIV(d) (((d) & 0xF) << 12) -#define CSICR1_HSYNC_POL (1 << 11) -#define CSICR1_CCIR_EN (1 << 10) -#define CSICR1_MCLKEN (1 << 9) -#define CSICR1_FCC (1 << 8) -#define CSICR1_PACK_DIR (1 << 7) -#define CSICR1_CLR_STATFIFO (1 << 6) -#define CSICR1_CLR_RXFIFO (1 << 5) -#define CSICR1_GCLK_MODE (1 << 4) -#define CSICR1_INV_DATA (1 << 3) -#define CSICR1_INV_PCLK (1 << 2) -#define CSICR1_REDGE (1 << 1) - -#define SHIFT_STATFF_LEVEL 22 -#define SHIFT_RXFF_LEVEL 19 -#define SHIFT_MCLKDIV 12 - -/* control reg 3 */ -#define CSICR3_FRMCNT (0xFFFF << 16) -#define CSICR3_FRMCNT_RST (1 << 15) -#define CSICR3_DMA_REFLASH_RFF (1 << 14) -#define CSICR3_DMA_REFLASH_SFF (1 << 13) -#define CSICR3_DMA_REQ_EN_RFF (1 << 12) -#define CSICR3_DMA_REQ_EN_SFF (1 << 11) -#define CSICR3_RXFF_LEVEL(l) (((l) & 7) << 4) /* MX25 */ -#define CSICR3_CSI_SUP (1 << 3) -#define CSICR3_ZERO_PACK_EN (1 << 2) -#define CSICR3_ECC_INT_EN (1 << 1) -#define CSICR3_ECC_AUTO_EN (1 << 0) - -#define SHIFT_FRMCNT 16 - -/* csi status reg */ -#define CSISR_SFF_OR_INT (1 << 25) -#define CSISR_RFF_OR_INT (1 << 24) -#define CSISR_STATFF_INT (1 << 21) -#define CSISR_DMA_TSF_FB2_INT (1 << 20) /* MX25 */ -#define CSISR_DMA_TSF_FB1_INT (1 << 19) /* MX25 */ -#define CSISR_RXFF_INT (1 << 18) -#define CSISR_EOF_INT (1 << 17) -#define CSISR_SOF_INT (1 << 16) -#define CSISR_F2_INT (1 << 15) -#define CSISR_F1_INT (1 << 14) -#define CSISR_COF_INT (1 << 13) -#define CSISR_ECC_INT (1 << 1) -#define CSISR_DRDY (1 << 0) - -#define CSICR1 0x00 -#define CSICR2 0x04 -#define CSISR (cpu_is_mx27() ? 0x08 : 0x18) -#define CSISTATFIFO 0x0c -#define CSIRFIFO 0x10 -#define CSIRXCNT 0x14 -#define CSICR3 (cpu_is_mx27() ? 0x1C : 0x08) -#define CSIDMASA_STATFIFO 0x20 -#define CSIDMATA_STATFIFO 0x24 -#define CSIDMASA_FB1 0x28 -#define CSIDMASA_FB2 0x2c -#define CSIFBUF_PARA 0x30 -#define CSIIMAG_PARA 0x34 - -/* EMMA PrP */ -#define PRP_CNTL 0x00 -#define PRP_INTR_CNTL 0x04 -#define PRP_INTRSTATUS 0x08 -#define PRP_SOURCE_Y_PTR 0x0c -#define PRP_SOURCE_CB_PTR 0x10 -#define PRP_SOURCE_CR_PTR 0x14 -#define PRP_DEST_RGB1_PTR 0x18 -#define PRP_DEST_RGB2_PTR 0x1c -#define PRP_DEST_Y_PTR 0x20 -#define PRP_DEST_CB_PTR 0x24 -#define PRP_DEST_CR_PTR 0x28 -#define PRP_SRC_FRAME_SIZE 0x2c -#define PRP_DEST_CH1_LINE_STRIDE 0x30 -#define PRP_SRC_PIXEL_FORMAT_CNTL 0x34 -#define PRP_CH1_PIXEL_FORMAT_CNTL 0x38 -#define PRP_CH1_OUT_IMAGE_SIZE 0x3c -#define PRP_CH2_OUT_IMAGE_SIZE 0x40 -#define PRP_SRC_LINE_STRIDE 0x44 -#define PRP_CSC_COEF_012 0x48 -#define PRP_CSC_COEF_345 0x4c -#define PRP_CSC_COEF_678 0x50 -#define PRP_CH1_RZ_HORI_COEF1 0x54 -#define PRP_CH1_RZ_HORI_COEF2 0x58 -#define PRP_CH1_RZ_HORI_VALID 0x5c -#define PRP_CH1_RZ_VERT_COEF1 0x60 -#define PRP_CH1_RZ_VERT_COEF2 0x64 -#define PRP_CH1_RZ_VERT_VALID 0x68 -#define PRP_CH2_RZ_HORI_COEF1 0x6c -#define PRP_CH2_RZ_HORI_COEF2 0x70 -#define PRP_CH2_RZ_HORI_VALID 0x74 -#define PRP_CH2_RZ_VERT_COEF1 0x78 -#define PRP_CH2_RZ_VERT_COEF2 0x7c -#define PRP_CH2_RZ_VERT_VALID 0x80 - -#define PRP_CNTL_CH1EN (1 << 0) -#define PRP_CNTL_CH2EN (1 << 1) -#define PRP_CNTL_CSIEN (1 << 2) -#define PRP_CNTL_DATA_IN_YUV420 (0 << 3) -#define PRP_CNTL_DATA_IN_YUV422 (1 << 3) -#define PRP_CNTL_DATA_IN_RGB16 (2 << 3) -#define PRP_CNTL_DATA_IN_RGB32 (3 << 3) -#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5) -#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5) -#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5) -#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5) -#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7) -#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7) -#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7) -#define PRP_CNTL_CH1_LEN (1 << 9) -#define PRP_CNTL_CH2_LEN (1 << 10) -#define PRP_CNTL_SKIP_FRAME (1 << 11) -#define PRP_CNTL_SWRST (1 << 12) -#define PRP_CNTL_CLKEN (1 << 13) -#define PRP_CNTL_WEN (1 << 14) -#define PRP_CNTL_CH1BYP (1 << 15) -#define PRP_CNTL_IN_TSKIP(x) ((x) << 16) -#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19) -#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22) -#define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25) -#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) -#define PRP_CNTL_CH2B1EN (1 << 29) -#define PRP_CNTL_CH2B2EN (1 << 30) -#define PRP_CNTL_CH2FEN (1 << 31) - -/* IRQ Enable and status register */ -#define PRP_INTR_RDERR (1 << 0) -#define PRP_INTR_CH1WERR (1 << 1) -#define PRP_INTR_CH2WERR (1 << 2) -#define PRP_INTR_CH1FC (1 << 3) -#define PRP_INTR_CH2FC (1 << 5) -#define PRP_INTR_LBOVF (1 << 7) -#define PRP_INTR_CH2OVF (1 << 8) - -#define mx27_camera_emma(pcdev) (cpu_is_mx27() && pcdev->use_emma) - -#define MAX_VIDEO_MEM 16 - -struct mx2_camera_dev { - struct device *dev; - struct soc_camera_host soc_host; - struct soc_camera_device *icd; - struct clk *clk_csi, *clk_emma; - - unsigned int irq_csi, irq_emma; - void __iomem *base_csi, *base_emma; - unsigned long base_dma; - - struct mx2_camera_platform_data *pdata; - struct resource *res_csi, *res_emma; - unsigned long platform_flags; - - struct list_head capture; - struct list_head active_bufs; - - spinlock_t lock; - - int dma; - struct mx2_buffer *active; - struct mx2_buffer *fb1_active; - struct mx2_buffer *fb2_active; - - int use_emma; - - u32 csicr1; - - void *discard_buffer; - dma_addr_t discard_buffer_dma; - size_t discard_size; -}; - -/* buffer for one video frame */ -struct mx2_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - enum v4l2_mbus_pixelcode code; - - int bufnum; -}; - -static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) -{ - unsigned long flags; - - clk_disable(pcdev->clk_csi); - writel(0, pcdev->base_csi + CSICR1); - if (mx27_camera_emma(pcdev)) { - writel(0, pcdev->base_emma + PRP_CNTL); - } else if (cpu_is_mx25()) { - spin_lock_irqsave(&pcdev->lock, flags); - pcdev->fb1_active = NULL; - pcdev->fb2_active = NULL; - writel(0, pcdev->base_csi + CSIDMASA_FB1); - writel(0, pcdev->base_csi + CSIDMASA_FB2); - spin_unlock_irqrestore(&pcdev->lock, flags); - } -} - -/* - * The following two functions absolutely depend on the fact, that - * there can be only one camera on mx2 camera sensor interface - */ -static int mx2_camera_add_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx2_camera_dev *pcdev = ici->priv; - int ret; - u32 csicr1; - - if (pcdev->icd) - return -EBUSY; - - ret = clk_enable(pcdev->clk_csi); - if (ret < 0) - return ret; - - csicr1 = CSICR1_MCLKEN; - - if (mx27_camera_emma(pcdev)) { - csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | - CSICR1_RXFF_LEVEL(0); - } else if (cpu_is_mx27()) - csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2); - - pcdev->csicr1 = csicr1; - writel(pcdev->csicr1, pcdev->base_csi + CSICR1); - - pcdev->icd = icd; - - dev_info(icd->dev.parent, "Camera driver attached to camera %d\n", - icd->devnum); - - return 0; -} - -static void mx2_camera_remove_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx2_camera_dev *pcdev = ici->priv; - - BUG_ON(icd != pcdev->icd); - - dev_info(icd->dev.parent, "Camera driver detached from camera %d\n", - icd->devnum); - - mx2_camera_deactivate(pcdev); - - if (pcdev->discard_buffer) { - dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size, - pcdev->discard_buffer, - pcdev->discard_buffer_dma); - pcdev->discard_buffer = NULL; - } - - pcdev->icd = NULL; -} - -#ifdef CONFIG_MACH_MX27 -static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev) -{ - u32 tmp; - - imx_dma_enable(pcdev->dma); - - tmp = readl(pcdev->base_csi + CSICR1); - tmp |= CSICR1_RF_OR_INTEN; - writel(tmp, pcdev->base_csi + CSICR1); -} - -static irqreturn_t mx27_camera_irq(int irq_csi, void *data) -{ - struct mx2_camera_dev *pcdev = data; - u32 status = readl(pcdev->base_csi + CSISR); - - if (status & CSISR_SOF_INT && pcdev->active) { - u32 tmp; - - tmp = readl(pcdev->base_csi + CSICR1); - writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1); - mx27_camera_dma_enable(pcdev); - } - - writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR); - - return IRQ_HANDLED; -} -#else -static irqreturn_t mx27_camera_irq(int irq_csi, void *data) -{ - return IRQ_NONE; -} -#endif /* CONFIG_MACH_MX27 */ - -static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb, - int state) -{ - struct videobuf_buffer *vb; - struct mx2_buffer *buf; - struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active : - &pcdev->fb2_active; - u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2; - unsigned long flags; - - spin_lock_irqsave(&pcdev->lock, flags); - - if (*fb_active == NULL) - goto out; - - vb = &(*fb_active)->vb; - dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - vb->state = state; - do_gettimeofday(&vb->ts); - vb->field_count++; - - wake_up(&vb->done); - - if (list_empty(&pcdev->capture)) { - buf = NULL; - writel(0, pcdev->base_csi + fb_reg); - } else { - buf = list_entry(pcdev->capture.next, struct mx2_buffer, - vb.queue); - vb = &buf->vb; - list_del(&vb->queue); - vb->state = VIDEOBUF_ACTIVE; - writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg); - } - - *fb_active = buf; - -out: - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static irqreturn_t mx25_camera_irq(int irq_csi, void *data) -{ - struct mx2_camera_dev *pcdev = data; - u32 status = readl(pcdev->base_csi + CSISR); - - if (status & CSISR_DMA_TSF_FB1_INT) - mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE); - else if (status & CSISR_DMA_TSF_FB2_INT) - mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE); - - /* FIXME: handle CSISR_RFF_OR_INT */ - - writel(status, pcdev->base_csi + CSISR); - - return IRQ_HANDLED; -} - -/* - * Videobuf operations - */ -static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct soc_camera_device *icd = vq->priv_data; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); - - if (bytes_per_line < 0) - return bytes_per_line; - - *size = bytes_per_line * icd->user_height; - - if (0 == *count) - *count = 32; - if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) - *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf) -{ - struct soc_camera_device *icd = vq->priv_data; - struct videobuf_buffer *vb = &buf->vb; - - dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - /* - * This waits until this buffer is out of danger, i.e., until it is no - * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE - */ - videobuf_waiton(vq, vb, 0, 0); - - videobuf_dma_contig_free(vq, vb); - dev_dbg(&icd->dev, "%s freed\n", __func__); - - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static int mx2_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct soc_camera_device *icd = vq->priv_data; - struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - int ret = 0; - - dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - if (bytes_per_line < 0) - return bytes_per_line; - -#ifdef DEBUG - /* - * This can be useful if you want to see if we actually fill - * the buffer with something - */ - memset((void *)vb->baddr, 0xaa, vb->bsize); -#endif - - if (buf->code != icd->current_fmt->code || - vb->width != icd->user_width || - vb->height != icd->user_height || - vb->field != field) { - buf->code = icd->current_fmt->code; - vb->width = icd->user_width; - vb->height = icd->user_height; - vb->field = field; - vb->state = VIDEOBUF_NEEDS_INIT; - } - - vb->size = bytes_per_line * vb->height; - if (vb->baddr && vb->bsize < vb->size) { - ret = -EINVAL; - goto out; - } - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret) - goto fail; - - vb->state = VIDEOBUF_PREPARED; - } - - return 0; - -fail: - free_buffer(vq, buf); -out: - return ret; -} - -static void mx2_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); - unsigned long flags; - - dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - spin_lock_irqsave(&pcdev->lock, flags); - - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &pcdev->capture); - - if (mx27_camera_emma(pcdev)) { - goto out; -#ifdef CONFIG_MACH_MX27 - } else if (cpu_is_mx27()) { - int ret; - - if (pcdev->active == NULL) { - ret = imx_dma_setup_single(pcdev->dma, - videobuf_to_dma_contig(vb), vb->size, - (u32)pcdev->base_dma + 0x10, - DMA_MODE_READ); - if (ret) { - vb->state = VIDEOBUF_ERROR; - wake_up(&vb->done); - goto out; - } - - vb->state = VIDEOBUF_ACTIVE; - pcdev->active = buf; - } -#endif - } else { /* cpu_is_mx25() */ - u32 csicr3, dma_inten = 0; - - if (pcdev->fb1_active == NULL) { - writel(videobuf_to_dma_contig(vb), - pcdev->base_csi + CSIDMASA_FB1); - pcdev->fb1_active = buf; - dma_inten = CSICR1_FB1_DMA_INTEN; - } else if (pcdev->fb2_active == NULL) { - writel(videobuf_to_dma_contig(vb), - pcdev->base_csi + CSIDMASA_FB2); - pcdev->fb2_active = buf; - dma_inten = CSICR1_FB2_DMA_INTEN; - } - - if (dma_inten) { - list_del(&vb->queue); - vb->state = VIDEOBUF_ACTIVE; - - csicr3 = readl(pcdev->base_csi + CSICR3); - - /* Reflash DMA */ - writel(csicr3 | CSICR3_DMA_REFLASH_RFF, - pcdev->base_csi + CSICR3); - - /* clear & enable interrupts */ - writel(dma_inten, pcdev->base_csi + CSISR); - pcdev->csicr1 |= dma_inten; - writel(pcdev->csicr1, pcdev->base_csi + CSICR1); - - /* enable DMA */ - csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1); - writel(csicr3, pcdev->base_csi + CSICR3); - } - } - -out: - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static void mx2_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); - unsigned long flags; - -#ifdef DEBUG - dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - switch (vb->state) { - case VIDEOBUF_ACTIVE: - dev_info(&icd->dev, "%s (active)\n", __func__); - break; - case VIDEOBUF_QUEUED: - dev_info(&icd->dev, "%s (queued)\n", __func__); - break; - case VIDEOBUF_PREPARED: - dev_info(&icd->dev, "%s (prepared)\n", __func__); - break; - default: - dev_info(&icd->dev, "%s (unknown) %d\n", __func__, - vb->state); - break; - } -#endif - - /* - * Terminate only queued but inactive buffers. Active buffers are - * released when they become inactive after videobuf_waiton(). - * - * FIXME: implement forced termination of active buffers for mx27 and - * mx27 eMMA, so that the user won't get stuck in an uninterruptible - * state. This requires a specific handling for each of the these DMA - * types. - */ - spin_lock_irqsave(&pcdev->lock, flags); - if (vb->state == VIDEOBUF_QUEUED) { - list_del(&vb->queue); - vb->state = VIDEOBUF_ERROR; - } else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) { - if (pcdev->fb1_active == buf) { - pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; - writel(0, pcdev->base_csi + CSIDMASA_FB1); - pcdev->fb1_active = NULL; - } else if (pcdev->fb2_active == buf) { - pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN; - writel(0, pcdev->base_csi + CSIDMASA_FB2); - pcdev->fb2_active = NULL; - } - writel(pcdev->csicr1, pcdev->base_csi + CSICR1); - vb->state = VIDEOBUF_ERROR; - } - spin_unlock_irqrestore(&pcdev->lock, flags); - - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops mx2_videobuf_ops = { - .buf_setup = mx2_videobuf_setup, - .buf_prepare = mx2_videobuf_prepare, - .buf_queue = mx2_videobuf_queue, - .buf_release = mx2_videobuf_release, -}; - -static void mx2_camera_init_videobuf(struct videobuf_queue *q, - struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx2_camera_dev *pcdev = ici->priv; - - videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev, - &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_NONE, sizeof(struct mx2_buffer), - icd, &icd->video_lock); -} - -#define MX2_BUS_FLAGS (SOCAM_DATAWIDTH_8 | \ - SOCAM_MASTER | \ - SOCAM_VSYNC_ACTIVE_HIGH | \ - SOCAM_VSYNC_ACTIVE_LOW | \ - SOCAM_HSYNC_ACTIVE_HIGH | \ - SOCAM_HSYNC_ACTIVE_LOW | \ - SOCAM_PCLK_SAMPLE_RISING | \ - SOCAM_PCLK_SAMPLE_FALLING | \ - SOCAM_DATA_ACTIVE_HIGH | \ - SOCAM_DATA_ACTIVE_LOW) - -static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) -{ - u32 cntl; - int count = 0; - - cntl = readl(pcdev->base_emma + PRP_CNTL); - writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); - while (count++ < 100) { - if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) - return 0; - barrier(); - udelay(1); - } - - return -ETIMEDOUT; -} - -static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, - int bytesperline) -{ - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); - struct mx2_camera_dev *pcdev = ici->priv; - - writel(pcdev->discard_buffer_dma, - pcdev->base_emma + PRP_DEST_RGB1_PTR); - writel(pcdev->discard_buffer_dma, - pcdev->base_emma + PRP_DEST_RGB2_PTR); - - /* - * We only use the EMMA engine to get rid of the broken - * DMA Engine. No color space consversion at the moment. - * We set the incomming and outgoing pixelformat to an - * 16 Bit wide format and adjust the bytesperline - * accordingly. With this configuration the inputdata - * will not be changed by the emma and could be any type - * of 16 Bit Pixelformat. - */ - writel(PRP_CNTL_CH1EN | - PRP_CNTL_CSIEN | - PRP_CNTL_DATA_IN_RGB16 | - PRP_CNTL_CH1_OUT_RGB16 | - PRP_CNTL_CH1_LEN | - PRP_CNTL_CH1BYP | - PRP_CNTL_CH1_TSKIP(0) | - PRP_CNTL_IN_TSKIP(0), - pcdev->base_emma + PRP_CNTL); - - writel(((bytesperline >> 1) << 16) | icd->user_height, - pcdev->base_emma + PRP_SRC_FRAME_SIZE); - writel(((bytesperline >> 1) << 16) | icd->user_height, - pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); - writel(bytesperline, - pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); - writel(0x2ca00565, /* RGB565 */ - pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); - writel(0x2ca00565, /* RGB565 */ - pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); - - /* Enable interrupts */ - writel(PRP_INTR_RDERR | - PRP_INTR_CH1WERR | - PRP_INTR_CH2WERR | - PRP_INTR_CH1FC | - PRP_INTR_CH2FC | - PRP_INTR_LBOVF | - PRP_INTR_CH2OVF, - pcdev->base_emma + PRP_INTR_CNTL); -} - -static int mx2_camera_set_bus_param(struct soc_camera_device *icd, - __u32 pixfmt) -{ - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); - struct mx2_camera_dev *pcdev = ici->priv; - unsigned long camera_flags, common_flags; - int ret = 0; - int bytesperline; - u32 csicr1 = pcdev->csicr1; - - camera_flags = icd->ops->query_bus_param(icd); - - common_flags = soc_camera_bus_param_compatible(camera_flags, - MX2_BUS_FLAGS); - if (!common_flags) - return -EINVAL; - - if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { - if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) - common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; - else - common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; - } - - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { - if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; - else - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; - } - - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) - return ret; - - if (common_flags & SOCAM_PCLK_SAMPLE_RISING) - csicr1 |= CSICR1_REDGE; - if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) - csicr1 |= CSICR1_SOF_POL; - if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH) - csicr1 |= CSICR1_HSYNC_POL; - if (pcdev->platform_flags & MX2_CAMERA_SWAP16) - csicr1 |= CSICR1_SWAP16_EN; - if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) - csicr1 |= CSICR1_EXT_VSYNC; - if (pcdev->platform_flags & MX2_CAMERA_CCIR) - csicr1 |= CSICR1_CCIR_EN; - if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE) - csicr1 |= CSICR1_CCIR_MODE; - if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK) - csicr1 |= CSICR1_GCLK_MODE; - if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) - csicr1 |= CSICR1_INV_DATA; - if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB) - csicr1 |= CSICR1_PACK_DIR; - - pcdev->csicr1 = csicr1; - - bytesperline = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - if (bytesperline < 0) - return bytesperline; - - if (mx27_camera_emma(pcdev)) { - ret = mx27_camera_emma_prp_reset(pcdev); - if (ret) - return ret; - - if (pcdev->discard_buffer) - dma_free_coherent(ici->v4l2_dev.dev, - pcdev->discard_size, pcdev->discard_buffer, - pcdev->discard_buffer_dma); - - /* - * I didn't manage to properly enable/disable the prp - * on a per frame basis during running transfers, - * thus we allocate a buffer here and use it to - * discard frames when no buffer is available. - * Feel free to work on this ;) - */ - pcdev->discard_size = icd->user_height * bytesperline; - pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, - pcdev->discard_size, &pcdev->discard_buffer_dma, - GFP_KERNEL); - if (!pcdev->discard_buffer) - return -ENOMEM; - - mx27_camera_emma_buf_init(icd, bytesperline); - } else if (cpu_is_mx25()) { - writel((bytesperline * icd->user_height) >> 2, - pcdev->base_csi + CSIRXCNT); - writel((bytesperline << 16) | icd->user_height, - pcdev->base_csi + CSIIMAG_PARA); - } - - writel(pcdev->csicr1, pcdev->base_csi + CSICR1); - - return 0; -} - -static int mx2_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) -{ - struct v4l2_rect *rect = &a->c; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; - int ret; - - soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); - soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); - - ret = v4l2_subdev_call(sd, video, s_crop, a); - if (ret < 0) - return ret; - - /* The capture device might have changed its output */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); - if (ret < 0) - return ret; - - dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", - mf.width, mf.height); - - icd->user_width = mf.width; - icd->user_height = mf.height; - - return ret; -} - -static int mx2_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", - pix->pixelformat); - return -EINVAL; - } - - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - - if (mf.code != xlate->code) - return -EINVAL; - - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; - icd->current_fmt = xlate; - - return 0; -} - -static int mx2_camera_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - __u32 pixfmt = pix->pixelformat; - unsigned int width_limit; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (pixfmt && !xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - /* FIXME: implement MX27 limits */ - - /* limit to MX25 hardware capabilities */ - if (cpu_is_mx25()) { - if (xlate->host_fmt->bits_per_sample <= 8) - width_limit = 0xffff * 4; - else - width_limit = 0xffff * 2; - /* CSIIMAG_PARA limit */ - if (pix->width > width_limit) - pix->width = width_limit; - if (pix->height > 0xffff) - pix->height = 0xffff; - - pix->bytesperline = soc_mbus_bytes_per_line(pix->width, - xlate->host_fmt); - if (pix->bytesperline < 0) - return pix->bytesperline; - pix->sizeimage = pix->height * pix->bytesperline; - if (pix->sizeimage > (4 * 0x3ffff)) { /* CSIRXCNT limit */ - dev_warn(icd->dev.parent, - "Image size (%u) above limit\n", - pix->sizeimage); - return -EINVAL; - } - } - - /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); - if (ret < 0) - return ret; - - if (mf.field == V4L2_FIELD_ANY) - mf.field = V4L2_FIELD_NONE; - if (mf.field != V4L2_FIELD_NONE) { - dev_err(icd->dev.parent, "Field type %d unsupported.\n", - mf.field); - return -EINVAL; - } - - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; - - return 0; -} - -static int mx2_camera_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - /* cap->name is set by the friendly caller:-> */ - strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); - cap->version = MX2_CAM_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - - return 0; -} - -static int mx2_camera_reqbufs(struct soc_camera_device *icd, - struct v4l2_requestbuffers *p) -{ - int i; - - for (i = 0; i < p->count; i++) { - struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i], - struct mx2_buffer, vb); - INIT_LIST_HEAD(&buf->vb.queue); - } - - return 0; -} - -#ifdef CONFIG_MACH_MX27 -static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state) -{ - struct videobuf_buffer *vb; - struct mx2_buffer *buf; - unsigned long flags; - int ret; - - spin_lock_irqsave(&pcdev->lock, flags); - - if (!pcdev->active) { - dev_err(pcdev->dev, "%s called with no active buffer!\n", - __func__); - goto out; - } - - vb = &pcdev->active->vb; - buf = container_of(vb, struct mx2_buffer, vb); - WARN_ON(list_empty(&vb->queue)); - dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ - list_del_init(&vb->queue); - vb->state = state; - do_gettimeofday(&vb->ts); - vb->field_count++; - - wake_up(&vb->done); - - if (list_empty(&pcdev->capture)) { - pcdev->active = NULL; - goto out; - } - - pcdev->active = list_entry(pcdev->capture.next, - struct mx2_buffer, vb.queue); - - vb = &pcdev->active->vb; - vb->state = VIDEOBUF_ACTIVE; - - ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb), - vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ); - - if (ret) { - vb->state = VIDEOBUF_ERROR; - pcdev->active = NULL; - wake_up(&vb->done); - } - -out: - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static void mx27_camera_dma_err_callback(int channel, void *data, int err) -{ - struct mx2_camera_dev *pcdev = data; - - mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR); -} - -static void mx27_camera_dma_callback(int channel, void *data) -{ - struct mx2_camera_dev *pcdev = data; - - mx27_camera_frame_done(pcdev, VIDEOBUF_DONE); -} - -#define DMA_REQ_CSI_RX 31 /* FIXME: Add this to a resource */ - -static int __devinit mx27_camera_dma_init(struct platform_device *pdev, - struct mx2_camera_dev *pcdev) -{ - int err; - - pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH); - if (pcdev->dma < 0) { - dev_err(&pdev->dev, "%s failed to request DMA channel\n", - __func__); - return pcdev->dma; - } - - err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback, - mx27_camera_dma_err_callback, pcdev); - if (err) { - dev_err(&pdev->dev, "%s failed to set DMA callback\n", - __func__); - goto err_out; - } - - err = imx_dma_config_channel(pcdev->dma, - IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO, - IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, - DMA_REQ_CSI_RX, 1); - if (err) { - dev_err(&pdev->dev, "%s failed to config DMA channel\n", - __func__); - goto err_out; - } - - imx_dma_config_burstlen(pcdev->dma, 64); - - return 0; - -err_out: - imx_dma_free(pcdev->dma); - - return err; -} -#endif /* CONFIG_MACH_MX27 */ - -static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - - return videobuf_poll_stream(file, &icd->vb_vidq, pt); -} - -static struct soc_camera_host_ops mx2_soc_camera_host_ops = { - .owner = THIS_MODULE, - .add = mx2_camera_add_device, - .remove = mx2_camera_remove_device, - .set_fmt = mx2_camera_set_fmt, - .set_crop = mx2_camera_set_crop, - .try_fmt = mx2_camera_try_fmt, - .init_videobuf = mx2_camera_init_videobuf, - .reqbufs = mx2_camera_reqbufs, - .poll = mx2_camera_poll, - .querycap = mx2_camera_querycap, - .set_bus_param = mx2_camera_set_bus_param, -}; - -static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, - int bufnum, int state) -{ - struct mx2_buffer *buf; - struct videobuf_buffer *vb; - unsigned long phys; - - if (!list_empty(&pcdev->active_bufs)) { - buf = list_entry(pcdev->active_bufs.next, - struct mx2_buffer, vb.queue); - - BUG_ON(buf->bufnum != bufnum); - - vb = &buf->vb; -#ifdef DEBUG - phys = videobuf_to_dma_contig(vb); - if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum) - != phys) { - dev_err(pcdev->dev, "%p != %p\n", phys, - readl(pcdev->base_emma + - PRP_DEST_RGB1_PTR + - 4 * bufnum)); - } -#endif - dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, - vb->baddr, vb->bsize); - - list_del(&vb->queue); - vb->state = state; - do_gettimeofday(&vb->ts); - vb->field_count++; - - wake_up(&vb->done); - } - - if (list_empty(&pcdev->capture)) { - writel(pcdev->discard_buffer_dma, pcdev->base_emma + - PRP_DEST_RGB1_PTR + 4 * bufnum); - return; - } - - buf = list_entry(pcdev->capture.next, - struct mx2_buffer, vb.queue); - - buf->bufnum = !bufnum; - - list_move_tail(pcdev->capture.next, &pcdev->active_bufs); - - vb = &buf->vb; - vb->state = VIDEOBUF_ACTIVE; - - phys = videobuf_to_dma_contig(vb); - writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); -} - -static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) -{ - struct mx2_camera_dev *pcdev = data; - unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); - struct mx2_buffer *buf; - - if (status & (1 << 7)) { /* overflow */ - u32 cntl; - /* - * We only disable channel 1 here since this is the only - * enabled channel - * - * FIXME: the correct DMA overflow handling should be resetting - * the buffer, returning an error frame, and continuing with - * the next one. - */ - cntl = readl(pcdev->base_emma + PRP_CNTL); - writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL); - writel(cntl, pcdev->base_emma + PRP_CNTL); - } - if ((status & (3 << 5)) == (3 << 5) - && !list_empty(&pcdev->active_bufs)) { - /* - * Both buffers have triggered, process the one we're expecting - * to first - */ - buf = list_entry(pcdev->active_bufs.next, - struct mx2_buffer, vb.queue); - mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE); - status &= ~(1 << (6 - buf->bufnum)); /* mark processed */ - } - if (status & (1 << 6)) - mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE); - if (status & (1 << 5)) - mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE); - - writel(status, pcdev->base_emma + PRP_INTRSTATUS); - - return IRQ_HANDLED; -} - -static int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev) -{ - struct resource *res_emma = pcdev->res_emma; - int err = 0; - - if (!request_mem_region(res_emma->start, resource_size(res_emma), - MX2_CAM_DRV_NAME)) { - err = -EBUSY; - goto out; - } - - pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma)); - if (!pcdev->base_emma) { - err = -ENOMEM; - goto exit_release; - } - - err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0, - MX2_CAM_DRV_NAME, pcdev); - if (err) { - dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n"); - goto exit_iounmap; - } - - pcdev->clk_emma = clk_get(NULL, "emma"); - if (IS_ERR(pcdev->clk_emma)) { - err = PTR_ERR(pcdev->clk_emma); - goto exit_free_irq; - } - - clk_enable(pcdev->clk_emma); - - err = mx27_camera_emma_prp_reset(pcdev); - if (err) - goto exit_clk_emma_put; - - return err; - -exit_clk_emma_put: - clk_disable(pcdev->clk_emma); - clk_put(pcdev->clk_emma); -exit_free_irq: - free_irq(pcdev->irq_emma, pcdev); -exit_iounmap: - iounmap(pcdev->base_emma); -exit_release: - release_mem_region(res_emma->start, resource_size(res_emma)); -out: - return err; -} - -static int __devinit mx2_camera_probe(struct platform_device *pdev) -{ - struct mx2_camera_dev *pcdev; - struct resource *res_csi, *res_emma; - void __iomem *base_csi; - int irq_csi, irq_emma; - irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq - : mx27_camera_irq; - int err = 0; - - dev_dbg(&pdev->dev, "initialising\n"); - - res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq_csi = platform_get_irq(pdev, 0); - if (res_csi == NULL || irq_csi < 0) { - dev_err(&pdev->dev, "Missing platform resources data\n"); - err = -ENODEV; - goto exit; - } - - pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); - if (!pcdev) { - dev_err(&pdev->dev, "Could not allocate pcdev\n"); - err = -ENOMEM; - goto exit; - } - - pcdev->clk_csi = clk_get(&pdev->dev, NULL); - if (IS_ERR(pcdev->clk_csi)) { - err = PTR_ERR(pcdev->clk_csi); - goto exit_kfree; - } - - dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n", - clk_get_rate(pcdev->clk_csi)); - - /* Initialize DMA */ -#ifdef CONFIG_MACH_MX27 - if (cpu_is_mx27()) { - err = mx27_camera_dma_init(pdev, pcdev); - if (err) - goto exit_clk_put; - } -#endif /* CONFIG_MACH_MX27 */ - - pcdev->res_csi = res_csi; - pcdev->pdata = pdev->dev.platform_data; - if (pcdev->pdata) { - long rate; - - pcdev->platform_flags = pcdev->pdata->flags; - - rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2); - if (rate <= 0) { - err = -ENODEV; - goto exit_dma_free; - } - err = clk_set_rate(pcdev->clk_csi, rate); - if (err < 0) - goto exit_dma_free; - } - - INIT_LIST_HEAD(&pcdev->capture); - INIT_LIST_HEAD(&pcdev->active_bufs); - spin_lock_init(&pcdev->lock); - - /* - * Request the regions. - */ - if (!request_mem_region(res_csi->start, resource_size(res_csi), - MX2_CAM_DRV_NAME)) { - err = -EBUSY; - goto exit_dma_free; - } - - base_csi = ioremap(res_csi->start, resource_size(res_csi)); - if (!base_csi) { - err = -ENOMEM; - goto exit_release; - } - pcdev->irq_csi = irq_csi; - pcdev->base_csi = base_csi; - pcdev->base_dma = res_csi->start; - pcdev->dev = &pdev->dev; - - err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0, - MX2_CAM_DRV_NAME, pcdev); - if (err) { - dev_err(pcdev->dev, "Camera interrupt register failed \n"); - goto exit_iounmap; - } - - if (cpu_is_mx27()) { - /* EMMA support */ - res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); - irq_emma = platform_get_irq(pdev, 1); - - if (res_emma && irq_emma >= 0) { - dev_info(&pdev->dev, "Using EMMA\n"); - pcdev->use_emma = 1; - pcdev->res_emma = res_emma; - pcdev->irq_emma = irq_emma; - if (mx27_camera_emma_init(pcdev)) - goto exit_free_irq; - } - } - - pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, - pcdev->soc_host.ops = &mx2_soc_camera_host_ops, - pcdev->soc_host.priv = pcdev; - pcdev->soc_host.v4l2_dev.dev = &pdev->dev; - pcdev->soc_host.nr = pdev->id; - err = soc_camera_host_register(&pcdev->soc_host); - if (err) - goto exit_free_emma; - - dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n", - clk_get_rate(pcdev->clk_csi)); - - return 0; - -exit_free_emma: - if (mx27_camera_emma(pcdev)) { - free_irq(pcdev->irq_emma, pcdev); - clk_disable(pcdev->clk_emma); - clk_put(pcdev->clk_emma); - iounmap(pcdev->base_emma); - release_mem_region(res_emma->start, resource_size(res_emma)); - } -exit_free_irq: - free_irq(pcdev->irq_csi, pcdev); -exit_iounmap: - iounmap(base_csi); -exit_release: - release_mem_region(res_csi->start, resource_size(res_csi)); -exit_dma_free: -#ifdef CONFIG_MACH_MX27 - if (cpu_is_mx27()) - imx_dma_free(pcdev->dma); -exit_clk_put: - clk_put(pcdev->clk_csi); -#endif /* CONFIG_MACH_MX27 */ -exit_kfree: - kfree(pcdev); -exit: - return err; -} - -static int __devexit mx2_camera_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - struct mx2_camera_dev *pcdev = container_of(soc_host, - struct mx2_camera_dev, soc_host); - struct resource *res; - - clk_put(pcdev->clk_csi); -#ifdef CONFIG_MACH_MX27 - if (cpu_is_mx27()) - imx_dma_free(pcdev->dma); -#endif /* CONFIG_MACH_MX27 */ - free_irq(pcdev->irq_csi, pcdev); - if (mx27_camera_emma(pcdev)) - free_irq(pcdev->irq_emma, pcdev); - - soc_camera_host_unregister(&pcdev->soc_host); - - iounmap(pcdev->base_csi); - - if (mx27_camera_emma(pcdev)) { - clk_disable(pcdev->clk_emma); - clk_put(pcdev->clk_emma); - iounmap(pcdev->base_emma); - res = pcdev->res_emma; - release_mem_region(res->start, resource_size(res)); - } - - res = pcdev->res_csi; - release_mem_region(res->start, resource_size(res)); - - kfree(pcdev); - - dev_info(&pdev->dev, "MX2 Camera driver unloaded\n"); - - return 0; -} - -static struct platform_driver mx2_camera_driver = { - .driver = { - .name = MX2_CAM_DRV_NAME, - }, - .remove = __devexit_p(mx2_camera_remove), -}; - - -static int __init mx2_camera_init(void) -{ - return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe); -} - -static void __exit mx2_camera_exit(void) -{ - return platform_driver_unregister(&mx2_camera_driver); -} - -module_init(mx2_camera_init); -module_exit(mx2_camera_exit); - -MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver"); -MODULE_AUTHOR("Sascha Hauer "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx3_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx3_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx3_camera.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mx3_camera.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1296 +0,0 @@ -/* - * V4L2 Driver for i.MX3x camera host - * - * Copyright (C) 2008 - * Guennadi Liakhovetski, DENX Software Engineering, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#define MX3_CAM_DRV_NAME "mx3-camera" - -/* CMOS Sensor Interface Registers */ -#define CSI_REG_START 0x60 - -#define CSI_SENS_CONF (0x60 - CSI_REG_START) -#define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START) -#define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START) -#define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START) -#define CSI_TST_CTRL (0x70 - CSI_REG_START) -#define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START) -#define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START) -#define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START) -#define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START) -#define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START) - -#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0 -#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1 -#define CSI_SENS_CONF_DATA_POL_SHIFT 2 -#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3 -#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4 -#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7 -#define CSI_SENS_CONF_DATA_FMT_SHIFT 8 -#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10 -#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15 -#define CSI_SENS_CONF_DIVRATIO_SHIFT 16 - -#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT) -#define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT) -#define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT) - -#define MAX_VIDEO_MEM 16 - -enum csi_buffer_state { - CSI_BUF_NEEDS_INIT, - CSI_BUF_PREPARED, -}; - -struct mx3_camera_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_buffer vb; - enum csi_buffer_state state; - struct list_head queue; - - /* One descriptot per scatterlist (per frame) */ - struct dma_async_tx_descriptor *txd; - - /* We have to "build" a scatterlist ourselves - one element per frame */ - struct scatterlist sg; -}; - -/** - * struct mx3_camera_dev - i.MX3x camera (CSI) object - * @dev: camera device, to which the coherent buffer is attached - * @icd: currently attached camera sensor - * @clk: pointer to clock - * @base: remapped register base address - * @pdata: platform data - * @platform_flags: platform flags - * @mclk: master clock frequency in Hz - * @capture: list of capture videobuffers - * @lock: protects video buffer lists - * @active: active video buffer - * @idmac_channel: array of pointers to IPU DMAC DMA channels - * @soc_host: embedded soc_host object - */ -struct mx3_camera_dev { - /* - * i.MX3x is only supposed to handle one camera on its Camera Sensor - * Interface. If anyone ever builds hardware to enable more than one - * camera _simultaneously_, they will have to modify this driver too - */ - struct soc_camera_device *icd; - struct clk *clk; - - void __iomem *base; - - struct mx3_camera_pdata *pdata; - - unsigned long platform_flags; - unsigned long mclk; - - struct list_head capture; - spinlock_t lock; /* Protects video buffer lists */ - struct mx3_camera_buffer *active; - struct vb2_alloc_ctx *alloc_ctx; - enum v4l2_field field; - int sequence; - - /* IDMAC / dmaengine interface */ - struct idmac_channel *idmac_channel[1]; /* We need one channel */ - - struct soc_camera_host soc_host; -}; - -struct dma_chan_request { - struct mx3_camera_dev *mx3_cam; - enum ipu_channel id; -}; - -static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg) -{ - return __raw_readl(mx3->base + reg); -} - -static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg) -{ - __raw_writel(value, mx3->base + reg); -} - -static struct mx3_camera_buffer *to_mx3_vb(struct vb2_buffer *vb) -{ - return container_of(vb, struct mx3_camera_buffer, vb); -} - -/* Called from the IPU IDMAC ISR */ -static void mx3_cam_dma_done(void *arg) -{ - struct idmac_tx_desc *desc = to_tx_desc(arg); - struct dma_chan *chan = desc->txd.chan; - struct idmac_channel *ichannel = to_idmac_chan(chan); - struct mx3_camera_dev *mx3_cam = ichannel->client; - - dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n", - desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0); - - spin_lock(&mx3_cam->lock); - if (mx3_cam->active) { - struct vb2_buffer *vb = &mx3_cam->active->vb; - struct mx3_camera_buffer *buf = to_mx3_vb(vb); - - list_del_init(&buf->queue); - do_gettimeofday(&vb->v4l2_buf.timestamp); - vb->v4l2_buf.field = mx3_cam->field; - vb->v4l2_buf.sequence = mx3_cam->sequence++; - vb2_buffer_done(vb, VB2_BUF_STATE_DONE); - } - - if (list_empty(&mx3_cam->capture)) { - mx3_cam->active = NULL; - spin_unlock(&mx3_cam->lock); - - /* - * stop capture - without further buffers IPU_CHA_BUF0_RDY will - * not get updated - */ - return; - } - - mx3_cam->active = list_entry(mx3_cam->capture.next, - struct mx3_camera_buffer, queue); - spin_unlock(&mx3_cam->lock); -} - -/* - * Videobuf operations - */ - -/* - * Calculate the __buffer__ (not data) size and number of buffers. - */ -static int mx3_videobuf_setup(struct vb2_queue *vq, - unsigned int *count, unsigned int *num_planes, - unsigned long sizes[], void *alloc_ctxs[]) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vq); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - if (bytes_per_line < 0) - return bytes_per_line; - - if (!mx3_cam->idmac_channel[0]) - return -EINVAL; - - *num_planes = 1; - - mx3_cam->sequence = 0; - sizes[0] = bytes_per_line * icd->user_height; - alloc_ctxs[0] = mx3_cam->alloc_ctx; - - if (!*count) - *count = 32; - - if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) - *count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0]; - - return 0; -} - -static int mx3_videobuf_prepare(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; - struct scatterlist *sg; - struct mx3_camera_buffer *buf; - size_t new_size; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - if (bytes_per_line < 0) - return bytes_per_line; - - buf = to_mx3_vb(vb); - sg = &buf->sg; - - new_size = bytes_per_line * icd->user_height; - - if (vb2_plane_size(vb, 0) < new_size) { - dev_err(icd->dev.parent, "Buffer too small (%lu < %zu)\n", - vb2_plane_size(vb, 0), new_size); - return -ENOBUFS; - } - - if (buf->state == CSI_BUF_NEEDS_INIT) { - sg_dma_address(sg) = vb2_dma_contig_plane_paddr(vb, 0); - sg_dma_len(sg) = new_size; - - buf->txd = ichan->dma_chan.device->device_prep_slave_sg( - &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT); - if (!buf->txd) - return -EIO; - - buf->txd->callback_param = buf->txd; - buf->txd->callback = mx3_cam_dma_done; - - buf->state = CSI_BUF_PREPARED; - } - - vb2_set_plane_payload(vb, 0, new_size); - - return 0; -} - -static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) -{ - /* Add more formats as need arises and test possibilities appear... */ - switch (fourcc) { - case V4L2_PIX_FMT_RGB24: - return IPU_PIX_FMT_RGB24; - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_RGB565: - default: - return IPU_PIX_FMT_GENERIC; - } -} - -static void mx3_videobuf_queue(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct mx3_camera_buffer *buf = to_mx3_vb(vb); - struct dma_async_tx_descriptor *txd = buf->txd; - struct idmac_channel *ichan = to_idmac_chan(txd->chan); - struct idmac_video_param *video = &ichan->params.video; - dma_cookie_t cookie; - u32 fourcc = icd->current_fmt->host_fmt->fourcc; - unsigned long flags; - - /* This is the configuration of one sg-element */ - video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); - - if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { - /* - * If the IPU DMA channel is configured to transport - * generic 8-bit data, we have to set up correctly the - * geometry parameters upon the current pixel format. - * So, since the DMA horizontal parameters are expressed - * in bytes not pixels, convert these in the right unit. - */ - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - BUG_ON(bytes_per_line <= 0); - - video->out_width = bytes_per_line; - video->out_height = icd->user_height; - video->out_stride = bytes_per_line; - } else { - /* - * For IPU known formats the pixel unit will be managed - * successfully by the IPU code - */ - video->out_width = icd->user_width; - video->out_height = icd->user_height; - video->out_stride = icd->user_width; - } - -#ifdef DEBUG - /* helps to see what DMA actually has written */ - if (vb2_plane_vaddr(vb, 0)) - memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); -#endif - - spin_lock_irqsave(&mx3_cam->lock, flags); - list_add_tail(&buf->queue, &mx3_cam->capture); - - if (!mx3_cam->active) - mx3_cam->active = buf; - - spin_unlock_irq(&mx3_cam->lock); - - cookie = txd->tx_submit(txd); - dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n", - cookie, sg_dma_address(&buf->sg)); - - if (cookie >= 0) - return; - - spin_lock_irq(&mx3_cam->lock); - - /* Submit error */ - list_del_init(&buf->queue); - - if (mx3_cam->active == buf) - mx3_cam->active = NULL; - - spin_unlock_irqrestore(&mx3_cam->lock, flags); - vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); -} - -static void mx3_videobuf_release(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct mx3_camera_buffer *buf = to_mx3_vb(vb); - struct dma_async_tx_descriptor *txd = buf->txd; - unsigned long flags; - - dev_dbg(icd->dev.parent, - "Release%s DMA 0x%08x, queue %sempty\n", - mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg), - list_empty(&buf->queue) ? "" : "not "); - - spin_lock_irqsave(&mx3_cam->lock, flags); - - if (mx3_cam->active == buf) - mx3_cam->active = NULL; - - /* Doesn't hurt also if the list is empty */ - list_del_init(&buf->queue); - buf->state = CSI_BUF_NEEDS_INIT; - - if (txd) { - buf->txd = NULL; - if (mx3_cam->idmac_channel[0]) - async_tx_ack(txd); - } - - spin_unlock_irqrestore(&mx3_cam->lock, flags); -} - -static int mx3_videobuf_init(struct vb2_buffer *vb) -{ - struct mx3_camera_buffer *buf = to_mx3_vb(vb); - /* This is for locking debugging only */ - INIT_LIST_HEAD(&buf->queue); - sg_init_table(&buf->sg, 1); - - buf->state = CSI_BUF_NEEDS_INIT; - buf->txd = NULL; - - return 0; -} - -static struct vb2_ops mx3_videobuf_ops = { - .queue_setup = mx3_videobuf_setup, - .buf_prepare = mx3_videobuf_prepare, - .buf_queue = mx3_videobuf_queue, - .buf_cleanup = mx3_videobuf_release, - .buf_init = mx3_videobuf_init, - .wait_prepare = soc_camera_unlock, - .wait_finish = soc_camera_lock, -}; - -static int mx3_camera_init_videobuf(struct vb2_queue *q, - struct soc_camera_device *icd) -{ - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->drv_priv = icd; - q->ops = &mx3_videobuf_ops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct mx3_camera_buffer); - - return vb2_queue_init(q); -} - -/* First part of ipu_csi_init_interface() */ -static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam, - struct soc_camera_device *icd) -{ - u32 conf; - long rate; - - /* Set default size: ipu_csi_set_window_size() */ - csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE); - /* ...and position to 0:0: ipu_csi_set_window_pos() */ - conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; - csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL); - - /* We use only gated clock synchronisation mode so far */ - conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT; - - /* Set generic data, platform-biggest bus-width */ - conf |= CSI_SENS_CONF_DATA_FMT_BAYER; - - if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) - conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) - conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) - conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/ - conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - - if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC) - conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC) - conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_DP) - conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_PCP) - conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_HSP) - conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; - if (mx3_cam->platform_flags & MX3_CAMERA_VSP) - conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; - - /* ipu_csi_init_interface() */ - csi_reg_write(mx3_cam, conf, CSI_SENS_CONF); - - clk_enable(mx3_cam->clk); - rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); - dev_dbg(icd->dev.parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate); - if (rate) - clk_set_rate(mx3_cam->clk, rate); -} - -/* Called with .video_lock held */ -static int mx3_camera_add_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - - if (mx3_cam->icd) - return -EBUSY; - - mx3_camera_activate(mx3_cam, icd); - - mx3_cam->icd = icd; - - dev_info(icd->dev.parent, "MX3 Camera driver attached to camera %d\n", - icd->devnum); - - return 0; -} - -/* Called with .video_lock held */ -static void mx3_camera_remove_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; - - BUG_ON(icd != mx3_cam->icd); - - if (*ichan) { - dma_release_channel(&(*ichan)->dma_chan); - *ichan = NULL; - } - - clk_disable(mx3_cam->clk); - - mx3_cam->icd = NULL; - - dev_info(icd->dev.parent, "MX3 Camera driver detached from camera %d\n", - icd->devnum); -} - -static int test_platform_param(struct mx3_camera_dev *mx3_cam, - unsigned char buswidth, unsigned long *flags) -{ - /* - * Platform specified synchronization and pixel clock polarities are - * only a recommendation and are only used during probing. MX3x - * camera interface only works in master mode, i.e., uses HSYNC and - * VSYNC signals from the sensor - */ - *flags = SOCAM_MASTER | - SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_PCLK_SAMPLE_RISING | - SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_DATA_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_LOW; - - /* - * If requested data width is supported by the platform, use it or any - * possible lower value - i.MX31 is smart enough to schift bits - */ - if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) - *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | - SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) - *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | - SOCAM_DATAWIDTH_4; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) - *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; - else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) - *flags |= SOCAM_DATAWIDTH_4; - - switch (buswidth) { - case 15: - if (!(*flags & SOCAM_DATAWIDTH_15)) - return -EINVAL; - break; - case 10: - if (!(*flags & SOCAM_DATAWIDTH_10)) - return -EINVAL; - break; - case 8: - if (!(*flags & SOCAM_DATAWIDTH_8)) - return -EINVAL; - break; - case 4: - if (!(*flags & SOCAM_DATAWIDTH_4)) - return -EINVAL; - break; - default: - dev_warn(mx3_cam->soc_host.v4l2_dev.dev, - "Unsupported bus width %d\n", buswidth); - return -EINVAL; - } - - return 0; -} - -static int mx3_camera_try_bus_param(struct soc_camera_device *icd, - const unsigned int depth) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - unsigned long bus_flags, camera_flags; - int ret = test_platform_param(mx3_cam, depth, &bus_flags); - - dev_dbg(icd->dev.parent, "request bus width %d bit: %d\n", depth, ret); - - if (ret < 0) - return ret; - - camera_flags = icd->ops->query_bus_param(icd); - - ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); - if (ret < 0) - dev_warn(icd->dev.parent, - "Flags incompatible: camera %lx, host %lx\n", - camera_flags, bus_flags); - - return ret; -} - -static bool chan_filter(struct dma_chan *chan, void *arg) -{ - struct dma_chan_request *rq = arg; - struct mx3_camera_pdata *pdata; - - if (!imx_dma_is_ipu(chan)) - return false; - - if (!rq) - return false; - - pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data; - - return rq->id == chan->chan_id && - pdata->dma_dev == chan->device->dev; -} - -static const struct soc_mbus_pixelfmt mx3_camera_formats[] = { - { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .name = "Bayer BGGR (sRGB) 8 bit", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - }, { - .fourcc = V4L2_PIX_FMT_GREY, - .name = "Monochrome 8 bit", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - }, -}; - -/* This will be corrected as we get more formats */ -static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) -{ - return fmt->packing == SOC_MBUS_PACKING_NONE || - (fmt->bits_per_sample == 8 && - fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || - (fmt->bits_per_sample > 8 && - fmt->packing == SOC_MBUS_PACKING_EXTEND16); -} - -static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, - struct soc_camera_format_xlate *xlate) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->dev.parent; - int formats = 0, ret; - enum v4l2_mbus_pixelcode code; - const struct soc_mbus_pixelfmt *fmt; - - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); - if (ret < 0) - /* No more formats */ - return 0; - - fmt = soc_mbus_get_fmtdesc(code); - if (!fmt) { - dev_err(icd->dev.parent, - "Invalid format code #%u: %d\n", idx, code); - return 0; - } - - /* This also checks support for the requested bits-per-sample */ - ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample); - if (ret < 0) - return 0; - - switch (code) { - case V4L2_MBUS_FMT_SBGGR10_1X10: - formats++; - if (xlate) { - xlate->host_fmt = &mx3_camera_formats[0]; - xlate->code = code; - xlate++; - dev_dbg(dev, "Providing format %s using code %d\n", - mx3_camera_formats[0].name, code); - } - break; - case V4L2_MBUS_FMT_Y10_1X10: - formats++; - if (xlate) { - xlate->host_fmt = &mx3_camera_formats[1]; - xlate->code = code; - xlate++; - dev_dbg(dev, "Providing format %s using code %d\n", - mx3_camera_formats[1].name, code); - } - break; - default: - if (!mx3_camera_packing_supported(fmt)) - return 0; - } - - /* Generic pass-through */ - formats++; - if (xlate) { - xlate->host_fmt = fmt; - xlate->code = code; - dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n", - (fmt->fourcc >> (0*8)) & 0xFF, - (fmt->fourcc >> (1*8)) & 0xFF, - (fmt->fourcc >> (2*8)) & 0xFF, - (fmt->fourcc >> (3*8)) & 0xFF); - xlate++; - } - - return formats; -} - -static void configure_geometry(struct mx3_camera_dev *mx3_cam, - unsigned int width, unsigned int height, - enum v4l2_mbus_pixelcode code) -{ - u32 ctrl, width_field, height_field; - const struct soc_mbus_pixelfmt *fmt; - - fmt = soc_mbus_get_fmtdesc(code); - BUG_ON(!fmt); - - if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) { - /* - * As the CSI will be configured to output BAYER, here - * the width parameter count the number of samples to - * capture to complete the whole image width. - */ - width *= soc_mbus_samples_per_pixel(fmt); - BUG_ON(width < 0); - } - - /* Setup frame size - this cannot be changed on-the-fly... */ - width_field = width - 1; - height_field = height - 1; - csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); - - csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); - csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2); - - csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE); - - /* ...and position */ - ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; - /* Sensor does the cropping */ - csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); -} - -static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) -{ - dma_cap_mask_t mask; - struct dma_chan *chan; - struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; - /* We have to use IDMAC_IC_7 for Bayer / generic data */ - struct dma_chan_request rq = {.mx3_cam = mx3_cam, - .id = IDMAC_IC_7}; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_cap_set(DMA_PRIVATE, mask); - chan = dma_request_channel(mask, chan_filter, &rq); - if (!chan) - return -EBUSY; - - *ichan = to_idmac_chan(chan); - (*ichan)->client = mx3_cam; - - return 0; -} - -/* - * FIXME: learn to use stride != width, then we can keep stride properly aligned - * and support arbitrary (even) widths. - */ -static inline void stride_align(__u32 *width) -{ - if (((*width + 7) & ~7) < 4096) - *width = (*width + 7) & ~7; - else - *width = *width & ~7; -} - -/* - * As long as we don't implement host-side cropping and scaling, we can use - * default g_crop and cropcap from soc_camera.c - */ -static int mx3_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) -{ - struct v4l2_rect *rect = &a->c; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; - int ret; - - soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); - soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); - - ret = v4l2_subdev_call(sd, video, s_crop, a); - if (ret < 0) - return ret; - - /* The capture device might have changed its output */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); - if (ret < 0) - return ret; - - if (mf.width & 7) { - /* Ouch! We can only handle 8-byte aligned width... */ - stride_align(&mf.width); - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); - if (ret < 0) - return ret; - } - - if (mf.width != icd->user_width || mf.height != icd->user_height) - configure_geometry(mx3_cam, mf.width, mf.height, mf.code); - - dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", - mf.width, mf.height); - - icd->user_width = mf.width; - icd->user_height = mf.height; - - return ret; -} - -static int mx3_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", - pix->pixelformat); - return -EINVAL; - } - - stride_align(&pix->width); - dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height); - - /* - * Might have to perform a complete interface initialisation like in - * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider - * mxc_v4l2_s_fmt() - */ - - configure_geometry(mx3_cam, pix->width, pix->height, xlate->code); - - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); - if (ret < 0) - return ret; - - if (mf.code != xlate->code) - return -EINVAL; - - if (!mx3_cam->idmac_channel[0]) { - ret = acquire_dma_channel(mx3_cam); - if (ret < 0) - return ret; - } - - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - mx3_cam->field = mf.field; - pix->colorspace = mf.colorspace; - icd->current_fmt = xlate; - - pix->bytesperline = soc_mbus_bytes_per_line(pix->width, - xlate->host_fmt); - if (pix->bytesperline < 0) - return pix->bytesperline; - pix->sizeimage = pix->height * pix->bytesperline; - - dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height); - - return ret; -} - -static int mx3_camera_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - __u32 pixfmt = pix->pixelformat; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (pixfmt && !xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - /* limit to MX3 hardware capabilities */ - if (pix->height > 4096) - pix->height = 4096; - if (pix->width > 4096) - pix->width = 4096; - - pix->bytesperline = soc_mbus_bytes_per_line(pix->width, - xlate->host_fmt); - if (pix->bytesperline < 0) - return pix->bytesperline; - pix->sizeimage = pix->height * pix->bytesperline; - - /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); - if (ret < 0) - return ret; - - pix->width = mf.width; - pix->height = mf.height; - pix->colorspace = mf.colorspace; - - switch (mf.field) { - case V4L2_FIELD_ANY: - pix->field = V4L2_FIELD_NONE; - break; - case V4L2_FIELD_NONE: - break; - default: - dev_err(icd->dev.parent, "Field type %d unsupported.\n", - mf.field); - ret = -EINVAL; - } - - return ret; -} - -static int mx3_camera_reqbufs(struct soc_camera_device *icd, - struct v4l2_requestbuffers *p) -{ - return 0; -} - -static unsigned int mx3_camera_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - - return vb2_poll(&icd->vb2_vidq, file, pt); -} - -static int mx3_camera_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - /* cap->name is set by the firendly caller:-> */ - strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card)); - cap->version = KERNEL_VERSION(0, 2, 2); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - - return 0; -} - -static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - unsigned long bus_flags, camera_flags, common_flags; - u32 dw, sens_conf; - const struct soc_mbus_pixelfmt *fmt; - int buswidth; - int ret; - const struct soc_camera_format_xlate *xlate; - struct device *dev = icd->dev.parent; - - fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); - if (!fmt) - return -EINVAL; - - buswidth = fmt->bits_per_sample; - ret = test_platform_param(mx3_cam, buswidth, &bus_flags); - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - dev_warn(dev, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); - - if (ret < 0) - return ret; - - camera_flags = icd->ops->query_bus_param(icd); - - common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); - dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", - camera_flags, bus_flags, common_flags); - if (!common_flags) { - dev_dbg(dev, "no common flags"); - return -EINVAL; - } - - /* Make choices, based on platform preferences */ - if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { - if (mx3_cam->platform_flags & MX3_CAMERA_HSP) - common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; - else - common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; - } - - if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { - if (mx3_cam->platform_flags & MX3_CAMERA_VSP) - common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; - else - common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; - } - - if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && - (common_flags & SOCAM_DATA_ACTIVE_LOW)) { - if (mx3_cam->platform_flags & MX3_CAMERA_DP) - common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; - else - common_flags &= ~SOCAM_DATA_ACTIVE_LOW; - } - - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { - if (mx3_cam->platform_flags & MX3_CAMERA_PCP) - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; - else - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; - } - - /* - * Make the camera work in widest common mode, we'll take care of - * the rest - */ - if (common_flags & SOCAM_DATAWIDTH_15) - common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | - SOCAM_DATAWIDTH_15; - else if (common_flags & SOCAM_DATAWIDTH_10) - common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | - SOCAM_DATAWIDTH_10; - else if (common_flags & SOCAM_DATAWIDTH_8) - common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | - SOCAM_DATAWIDTH_8; - else - common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | - SOCAM_DATAWIDTH_4; - - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) { - dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n", - common_flags, ret); - return ret; - } - - /* - * So far only gated clock mode is supported. Add a line - * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) | - * below and select the required mode when supporting other - * synchronisation protocols. - */ - sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) & - ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) | - (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) | - (1 << CSI_SENS_CONF_DATA_POL_SHIFT) | - (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) | - (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) | - (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT)); - - /* TODO: Support RGB and YUV formats */ - - /* This has been set in mx3_camera_activate(), but we clear it above */ - sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; - - if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) - sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; - if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) - sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; - if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) - sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; - if (common_flags & SOCAM_DATA_ACTIVE_LOW) - sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; - - /* Just do what we're asked to do */ - switch (xlate->host_fmt->bits_per_sample) { - case 4: - dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - break; - case 8: - dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - break; - case 10: - dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - break; - default: - /* - * Actually it can only be 15 now, default is just to silence - * compiler warnings - */ - case 15: - dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; - } - - csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); - - dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw); - - return 0; -} - -static struct soc_camera_host_ops mx3_soc_camera_host_ops = { - .owner = THIS_MODULE, - .add = mx3_camera_add_device, - .remove = mx3_camera_remove_device, - .set_crop = mx3_camera_set_crop, - .set_fmt = mx3_camera_set_fmt, - .try_fmt = mx3_camera_try_fmt, - .get_formats = mx3_camera_get_formats, - .init_videobuf2 = mx3_camera_init_videobuf, - .reqbufs = mx3_camera_reqbufs, - .poll = mx3_camera_poll, - .querycap = mx3_camera_querycap, - .set_bus_param = mx3_camera_set_bus_param, -}; - -static int __devinit mx3_camera_probe(struct platform_device *pdev) -{ - struct mx3_camera_dev *mx3_cam; - struct resource *res; - void __iomem *base; - int err = 0; - struct soc_camera_host *soc_host; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - err = -ENODEV; - goto egetres; - } - - mx3_cam = vzalloc(sizeof(*mx3_cam)); - if (!mx3_cam) { - dev_err(&pdev->dev, "Could not allocate mx3 camera object\n"); - err = -ENOMEM; - goto ealloc; - } - - mx3_cam->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(mx3_cam->clk)) { - err = PTR_ERR(mx3_cam->clk); - goto eclkget; - } - - mx3_cam->pdata = pdev->dev.platform_data; - mx3_cam->platform_flags = mx3_cam->pdata->flags; - if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 | - MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 | - MX3_CAMERA_DATAWIDTH_15))) { - /* - * Platform hasn't set available data widths. This is bad. - * Warn and use a default. - */ - dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " - "data widths, using default 8 bit\n"); - mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; - } - - mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; - if (!mx3_cam->mclk) { - dev_warn(&pdev->dev, - "mclk_10khz == 0! Please, fix your platform data. " - "Using default 20MHz\n"); - mx3_cam->mclk = 20000000; - } - - /* list of video-buffers */ - INIT_LIST_HEAD(&mx3_cam->capture); - spin_lock_init(&mx3_cam->lock); - - base = ioremap(res->start, resource_size(res)); - if (!base) { - pr_err("Couldn't map %x@%x\n", resource_size(res), res->start); - err = -ENOMEM; - goto eioremap; - } - - mx3_cam->base = base; - - soc_host = &mx3_cam->soc_host; - soc_host->drv_name = MX3_CAM_DRV_NAME; - soc_host->ops = &mx3_soc_camera_host_ops; - soc_host->priv = mx3_cam; - soc_host->v4l2_dev.dev = &pdev->dev; - soc_host->nr = pdev->id; - - mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); - if (IS_ERR(mx3_cam->alloc_ctx)) { - err = PTR_ERR(mx3_cam->alloc_ctx); - goto eallocctx; - } - - err = soc_camera_host_register(soc_host); - if (err) - goto ecamhostreg; - - /* IDMAC interface */ - dmaengine_get(); - - return 0; - -ecamhostreg: - vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); -eallocctx: - iounmap(base); -eioremap: - clk_put(mx3_cam->clk); -eclkget: - vfree(mx3_cam); -ealloc: -egetres: - return err; -} - -static int __devexit mx3_camera_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - struct mx3_camera_dev *mx3_cam = container_of(soc_host, - struct mx3_camera_dev, soc_host); - - clk_put(mx3_cam->clk); - - soc_camera_host_unregister(soc_host); - - iounmap(mx3_cam->base); - - /* - * The channel has either not been allocated, - * or should have been released - */ - if (WARN_ON(mx3_cam->idmac_channel[0])) - dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan); - - vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); - - vfree(mx3_cam); - - dmaengine_put(); - - dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n"); - - return 0; -} - -static struct platform_driver mx3_camera_driver = { - .driver = { - .name = MX3_CAM_DRV_NAME, - }, - .probe = mx3_camera_probe, - .remove = __devexit_p(mx3_camera_remove), -}; - - -static int __init mx3_camera_init(void) -{ - return platform_driver_register(&mx3_camera_driver); -} - -static void __exit mx3_camera_exit(void) -{ - platform_driver_unregister(&mx3_camera_driver); -} - -module_init(mx3_camera_init); -module_exit(mx3_camera_exit); - -MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mxb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mxb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mxb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mxb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,872 +0,0 @@ -/* - mxb - v4l2 driver for the Multimedia eXtension Board - - Copyright (C) 1998-2006 Michael Hunold - - Visit http://www.themm.net/~mihu/linux/saa7146/mxb.html - for further details about this card. - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#define DEBUG_VARIABLE debug - -#include -#include -#include -#include - -#include "mxb.h" -#include "tea6415c.h" -#include "tea6420.h" - -#define I2C_SAA7111A 0x24 -#define I2C_TDA9840 0x42 -#define I2C_TEA6415C 0x43 -#define I2C_TEA6420_1 0x4c -#define I2C_TEA6420_2 0x4d -#define I2C_TUNER 0x60 - -#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) - -/* global variable */ -static int mxb_num; - -/* initial frequence the tuner will be tuned to. - in verden (lower saxony, germany) 4148 is a - channel called "phoenix" */ -static int freq = 4148; -module_param(freq, int, 0644); -MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup"); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); - -#define MXB_INPUTS 4 -enum { TUNER, AUX1, AUX3, AUX3_YC }; - -static struct v4l2_input mxb_inputs[MXB_INPUTS] = { - { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, -}; - -/* this array holds the information, which port of the saa7146 each - input actually uses. the mxb uses port 0 for every input */ -static struct { - int hps_source; - int hps_sync; -} input_port_selection[MXB_INPUTS] = { - { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, - { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, - { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, - { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, -}; - -/* this array holds the information of the audio source (mxb_audios), - which has to be switched corresponding to the video source (mxb_channels) */ -static int video_audio_connect[MXB_INPUTS] = - { 0, 1, 3, 3 }; - -struct mxb_routing { - u32 input; - u32 output; -}; - -/* These are the necessary input-output-pins for bringing one audio source - (see above) to the CD-output. Note that gain is set to 0 in this table. */ -static struct mxb_routing TEA6420_cd[MXB_AUDIOS + 1][2] = { - { { 1, 1 }, { 1, 1 } }, /* Tuner */ - { { 5, 1 }, { 6, 1 } }, /* AUX 1 */ - { { 4, 1 }, { 6, 1 } }, /* AUX 2 */ - { { 3, 1 }, { 6, 1 } }, /* AUX 3 */ - { { 1, 1 }, { 3, 1 } }, /* Radio */ - { { 1, 1 }, { 2, 1 } }, /* CD-Rom */ - { { 6, 1 }, { 6, 1 } } /* Mute */ -}; - -/* These are the necessary input-output-pins for bringing one audio source - (see above) to the line-output. Note that gain is set to 0 in this table. */ -static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = { - { { 2, 3 }, { 1, 2 } }, - { { 5, 3 }, { 6, 2 } }, - { { 4, 3 }, { 6, 2 } }, - { { 3, 3 }, { 6, 2 } }, - { { 2, 3 }, { 3, 2 } }, - { { 2, 3 }, { 2, 2 } }, - { { 6, 3 }, { 6, 2 } } /* Mute */ -}; - -#define MAXCONTROLS 1 -static struct v4l2_queryctrl mxb_controls[] = { - { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 }, -}; - -struct mxb -{ - struct video_device *video_dev; - struct video_device *vbi_dev; - - struct i2c_adapter i2c_adapter; - - struct v4l2_subdev *saa7111a; - struct v4l2_subdev *tda9840; - struct v4l2_subdev *tea6415c; - struct v4l2_subdev *tuner; - struct v4l2_subdev *tea6420_1; - struct v4l2_subdev *tea6420_2; - - int cur_mode; /* current audio mode (mono, stereo, ...) */ - int cur_input; /* current input */ - int cur_mute; /* current mute status */ - struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */ -}; - -#define saa7111a_call(mxb, o, f, args...) \ - v4l2_subdev_call(mxb->saa7111a, o, f, ##args) -#define tda9840_call(mxb, o, f, args...) \ - v4l2_subdev_call(mxb->tda9840, o, f, ##args) -#define tea6415c_call(mxb, o, f, args...) \ - v4l2_subdev_call(mxb->tea6415c, o, f, ##args) -#define tuner_call(mxb, o, f, args...) \ - v4l2_subdev_call(mxb->tuner, o, f, ##args) -#define call_all(dev, o, f, args...) \ - v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args) - -static inline void tea6420_route_cd(struct mxb *mxb, int idx) -{ - v4l2_subdev_call(mxb->tea6420_1, audio, s_routing, - TEA6420_cd[idx][0].input, TEA6420_cd[idx][0].output, 0); - v4l2_subdev_call(mxb->tea6420_2, audio, s_routing, - TEA6420_cd[idx][1].input, TEA6420_cd[idx][1].output, 0); -} - -static inline void tea6420_route_line(struct mxb *mxb, int idx) -{ - v4l2_subdev_call(mxb->tea6420_1, audio, s_routing, - TEA6420_line[idx][0].input, TEA6420_line[idx][0].output, 0); - v4l2_subdev_call(mxb->tea6420_2, audio, s_routing, - TEA6420_line[idx][1].input, TEA6420_line[idx][1].output, 0); -} - -static struct saa7146_extension extension; - -static int mxb_probe(struct saa7146_dev *dev) -{ - struct mxb *mxb = NULL; - - mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL); - if (mxb == NULL) { - DEB_D(("not enough kernel memory.\n")); - return -ENOMEM; - } - - snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num); - - saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); - if (i2c_add_adapter(&mxb->i2c_adapter) < 0) { - DEB_S(("cannot register i2c-device. skipping.\n")); - kfree(mxb); - return -EFAULT; - } - - mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "saa7111", I2C_SAA7111A, NULL); - mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tea6420", I2C_TEA6420_1, NULL); - mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tea6420", I2C_TEA6420_2, NULL); - mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tea6415c", I2C_TEA6415C, NULL); - mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tda9840", I2C_TDA9840, NULL); - mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tuner", I2C_TUNER, NULL); - - /* check if all devices are present */ - if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || - !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) { - printk("mxb: did not find all i2c devices. aborting\n"); - i2c_del_adapter(&mxb->i2c_adapter); - kfree(mxb); - return -ENODEV; - } - - /* all devices are present, probe was successful */ - - /* we store the pointer in our private data field */ - dev->ext_priv = mxb; - - return 0; -} - -/* some init data for the saa7740, the so-called 'sound arena module'. - there are no specs available, so we simply use some init values */ -static struct { - int length; - char data[9]; -} mxb_saa7740_init[] = { - { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } }, - { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } }, - { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } }, - { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } }, - { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } }, - { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } }, - { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } }, - { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } }, - { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } }, - { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } }, - { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } }, - { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } }, - { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } }, - { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } }, - { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } }, - { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } }, - { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } }, - { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } }, - { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } }, - { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } }, - { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } }, - { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } }, - { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } }, - { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } }, - { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } }, - { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } }, - { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } }, - { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } }, - { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } }, - { 3, { 0x48, 0x00, 0x01 } }, - { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } }, - { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } }, - { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } }, - { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } }, - { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } }, - { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } }, - { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } }, - { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } }, - { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } }, - { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } }, - { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } }, - { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } }, - { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } }, - { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } }, - { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } }, - { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } }, - { 3, { 0x80, 0xb3, 0x0a } }, - {-1, { 0 } } -}; - -/* bring hardware to a sane state. this has to be done, just in case someone - wants to capture from this device before it has been properly initialized. - the capture engine would badly fail, because no valid signal arrives on the - saa7146, thus leading to timeouts and stuff. */ -static int mxb_init_done(struct saa7146_dev* dev) -{ - struct mxb* mxb = (struct mxb*)dev->ext_priv; - struct i2c_msg msg; - struct tuner_setup tun_setup; - v4l2_std_id std = V4L2_STD_PAL_BG; - - int i = 0, err = 0; - - /* select video mode in saa7111a */ - saa7111a_call(mxb, core, s_std, std); - - /* select tuner-output on saa7111a */ - i = 0; - saa7111a_call(mxb, video, s_routing, SAA7115_COMPOSITE0, - SAA7111_FMT_CCIR, 0); - - /* select a tuner type */ - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.addr = ADDR_UNSET; - tun_setup.type = TUNER_PHILIPS_PAL; - tuner_call(mxb, tuner, s_type_addr, &tun_setup); - /* tune in some frequency on tuner */ - mxb->cur_freq.tuner = 0; - mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV; - mxb->cur_freq.frequency = freq; - tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq); - - /* set a default video standard */ - tuner_call(mxb, core, s_std, std); - - /* mute audio on tea6420s */ - tea6420_route_line(mxb, 6); - tea6420_route_cd(mxb, 6); - - /* switch to tuner-channel on tea6415c */ - tea6415c_call(mxb, video, s_routing, 3, 17, 0); - - /* select tuner-output on multicable on tea6415c */ - tea6415c_call(mxb, video, s_routing, 3, 13, 0); - - /* the rest for mxb */ - mxb->cur_input = 0; - mxb->cur_mute = 1; - - mxb->cur_mode = V4L2_TUNER_MODE_STEREO; - - /* check if the saa7740 (aka 'sound arena module') is present - on the mxb. if so, we must initialize it. due to lack of - informations about the saa7740, the values were reverse - engineered. */ - msg.addr = 0x1b; - msg.flags = 0; - msg.len = mxb_saa7740_init[0].length; - msg.buf = &mxb_saa7740_init[0].data[0]; - - err = i2c_transfer(&mxb->i2c_adapter, &msg, 1); - if (err == 1) { - /* the sound arena module is a pos, that's probably the reason - philips refuses to hand out a datasheet for the saa7740... - it seems to screw up the i2c bus, so we disable fast irq - based i2c transactions here and rely on the slow and safe - polling method ... */ - extension.flags &= ~SAA7146_USE_I2C_IRQ; - for (i = 1; ; i++) { - if (-1 == mxb_saa7740_init[i].length) - break; - - msg.len = mxb_saa7740_init[i].length; - msg.buf = &mxb_saa7740_init[i].data[0]; - err = i2c_transfer(&mxb->i2c_adapter, &msg, 1); - if (err != 1) { - DEB_D(("failed to initialize 'sound arena module'.\n")); - goto err; - } - } - INFO(("'sound arena module' detected.\n")); - } -err: - /* the rest for saa7146: you should definitely set some basic values - for the input-port handling of the saa7146. */ - - /* ext->saa has been filled by the core driver */ - - /* some stuff is done via variables */ - saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, - input_port_selection[mxb->cur_input].hps_sync); - - /* some stuff is done via direct write to the registers */ - - /* this is ugly, but because of the fact that this is completely - hardware dependend, it should be done directly... */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, DD1_INIT, 0x02000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - return 0; -} - -/* interrupt-handler. this gets called when irq_mask is != 0. - it must clear the interrupt-bits in irq_mask it has handled */ -/* -void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask) -{ - struct mxb* mxb = (struct mxb*)dev->ext_priv; -} -*/ - -static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - int i; - - for (i = MAXCONTROLS - 1; i >= 0; i--) { - if (mxb_controls[i].id == qc->id) { - *qc = mxb_controls[i]; - DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); - return 0; - } - } - return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); -} - -static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - int i; - - for (i = MAXCONTROLS - 1; i >= 0; i--) { - if (mxb_controls[i].id == vc->id) - break; - } - - if (i < 0) - return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); - - if (vc->id == V4L2_CID_AUDIO_MUTE) { - vc->value = mxb->cur_mute; - DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); - return 0; - } - - DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - int i = 0; - - for (i = MAXCONTROLS - 1; i >= 0; i--) { - if (mxb_controls[i].id == vc->id) - break; - } - - if (i < 0) - return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); - - if (vc->id == V4L2_CID_AUDIO_MUTE) { - mxb->cur_mute = vc->value; - /* switch the audio-source */ - tea6420_route_line(mxb, vc->value ? 6 : - video_audio_connect[mxb->cur_input]); - DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value)); - } - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - if (i->index >= MXB_INPUTS) - return -EINVAL; - memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - *i = mxb->cur_input; - - DEB_EE(("VIDIOC_G_INPUT %d.\n", *i)); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - int err = 0; - int i = 0; - - DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); - - if (input >= MXB_INPUTS) - return -EINVAL; - - mxb->cur_input = input; - - saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, - input_port_selection[input].hps_sync); - - /* prepare switching of tea6415c and saa7111a; - have a look at the 'background'-file for further informations */ - switch (input) { - case TUNER: - i = SAA7115_COMPOSITE0; - - err = tea6415c_call(mxb, video, s_routing, 3, 17, 0); - - /* connect tuner-output always to multicable */ - if (!err) - err = tea6415c_call(mxb, video, s_routing, 3, 13, 0); - break; - case AUX3_YC: - /* nothing to be done here. aux3_yc is - directly connected to the saa711a */ - i = SAA7115_SVIDEO1; - break; - case AUX3: - /* nothing to be done here. aux3 is - directly connected to the saa711a */ - i = SAA7115_COMPOSITE1; - break; - case AUX1: - i = SAA7115_COMPOSITE0; - err = tea6415c_call(mxb, video, s_routing, 1, 17, 0); - break; - } - - if (err) - return err; - - /* switch video in saa7111a */ - if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0)) - printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a.\n"); - - /* switch the audio-source only if necessary */ - if (0 == mxb->cur_mute) - tea6420_route_line(mxb, video_audio_connect[input]); - - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - if (t->index) { - DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); - return -EINVAL; - } - - DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); - - memset(t, 0, sizeof(*t)); - strlcpy(t->name, "TV Tuner", sizeof(t->name)); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - t->audmode = mxb->cur_mode; - return call_all(dev, tuner, g_tuner, t); -} - -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - if (t->index) { - DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index)); - return -EINVAL; - } - - mxb->cur_mode = t->audmode; - return call_all(dev, tuner, s_tuner, t); -} - -static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - if (mxb->cur_input) { - DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", - mxb->cur_input)); - return -EINVAL; - } - - *f = mxb->cur_freq; - - DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - struct saa7146_vv *vv = dev->vv_data; - - if (f->tuner) - return -EINVAL; - - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - - if (mxb->cur_input) { - DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); - return -EINVAL; - } - - mxb->cur_freq = *f; - DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); - - /* tune in desired frequency */ - tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq); - - /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ - spin_lock(&dev->slock); - vv->vbi_fieldcount = 0; - spin_unlock(&dev->slock); - - return 0; -} - -static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - if (a->index > MXB_INPUTS) { - DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); - return -EINVAL; - } - - DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index)); - memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); - return 0; -} - -static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index)); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - - return call_all(dev, core, g_register, reg); -} - -static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - - return call_all(dev, core, s_register, reg); -} -#endif - -static long vidioc_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - switch (cmd) { - case MXB_S_AUDIO_CD: - { - int i = *(int *)arg; - - if (i < 0 || i >= MXB_AUDIOS) { - DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i)); - return -EINVAL; - } - - DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i)); - - tea6420_route_cd(mxb, i); - return 0; - } - case MXB_S_AUDIO_LINE: - { - int i = *(int *)arg; - - if (i < 0 || i >= MXB_AUDIOS) { - DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i)); - return -EINVAL; - } - - DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i)); - tea6420_route_line(mxb, i); - return 0; - } - default: -/* - DEB2(printk("does not handle this ioctl.\n")); -*/ - return -ENOIOCTLCMD; - } - return 0; -} - -static struct saa7146_ext_vv vv_data; - -/* this function only gets called when the probing was successful */ -static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct mxb *mxb; - - DEB_EE(("dev:%p\n", dev)); - - saa7146_vv_init(dev, &vv_data); - if (mxb_probe(dev)) { - saa7146_vv_release(dev); - return -1; - } - mxb = (struct mxb *)dev->ext_priv; - - vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; - vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; - vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; - vv_data.ops.vidioc_enum_input = vidioc_enum_input; - vv_data.ops.vidioc_g_input = vidioc_g_input; - vv_data.ops.vidioc_s_input = vidioc_s_input; - vv_data.ops.vidioc_g_tuner = vidioc_g_tuner; - vv_data.ops.vidioc_s_tuner = vidioc_s_tuner; - vv_data.ops.vidioc_g_frequency = vidioc_g_frequency; - vv_data.ops.vidioc_s_frequency = vidioc_s_frequency; - vv_data.ops.vidioc_g_audio = vidioc_g_audio; - vv_data.ops.vidioc_s_audio = vidioc_s_audio; -#ifdef CONFIG_VIDEO_ADV_DEBUG - vv_data.ops.vidioc_g_register = vidioc_g_register; - vv_data.ops.vidioc_s_register = vidioc_s_register; -#endif - vv_data.ops.vidioc_default = vidioc_default; - if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { - ERR(("cannot register capture v4l2 device. skipping.\n")); - saa7146_vv_release(dev); - return -1; - } - - /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ - if (MXB_BOARD_CAN_DO_VBI(dev)) { - if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { - ERR(("cannot register vbi v4l2 device. skipping.\n")); - } - } - - printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); - - mxb_num++; - mxb_init_done(dev); - return 0; -} - -static int mxb_detach(struct saa7146_dev *dev) -{ - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - DEB_EE(("dev:%p\n", dev)); - - saa7146_unregister_device(&mxb->video_dev,dev); - if (MXB_BOARD_CAN_DO_VBI(dev)) - saa7146_unregister_device(&mxb->vbi_dev, dev); - saa7146_vv_release(dev); - - mxb_num--; - - i2c_del_adapter(&mxb->i2c_adapter); - kfree(mxb); - - return 0; -} - -static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard) -{ - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - if (V4L2_STD_PAL_I == standard->id) { - v4l2_std_id std = V4L2_STD_PAL_I; - - DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n")); - /* set the 7146 gpio register -- I don't know what this does exactly */ - saa7146_write(dev, GPIO_CTRL, 0x00404050); - /* unset the 7111 gpio register -- I don't know what this does exactly */ - saa7111a_call(mxb, core, s_gpio, 0); - tuner_call(mxb, core, s_std, std); - } else { - v4l2_std_id std = V4L2_STD_PAL_BG; - - DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n")); - /* set the 7146 gpio register -- I don't know what this does exactly */ - saa7146_write(dev, GPIO_CTRL, 0x00404050); - /* set the 7111 gpio register -- I don't know what this does exactly */ - saa7111a_call(mxb, core, s_gpio, 1); - tuner_call(mxb, core, s_std, std); - } - return 0; -} - -static struct saa7146_standard standard[] = { - { - .name = "PAL-BG", .id = V4L2_STD_PAL_BG, - .v_offset = 0x17, .v_field = 288, - .h_offset = 0x14, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "PAL-I", .id = V4L2_STD_PAL_I, - .v_offset = 0x17, .v_field = 288, - .h_offset = 0x14, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 0x16, .v_field = 240, - .h_offset = 0x06, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - }, { - .name = "SECAM", .id = V4L2_STD_SECAM, - .v_offset = 0x14, .v_field = 288, - .h_offset = 0x14, .h_pixels = 720, - .v_max_out = 576, .h_max_out = 768, - } -}; - -static struct saa7146_pci_extension_data mxb = { - .ext_priv = "Multimedia eXtension Board", - .ext = &extension, -}; - -static struct pci_device_id pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x0000, - .subdevice = 0x0000, - .driver_data = (unsigned long)&mxb, - }, { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_ext_vv vv_data = { - .inputs = MXB_INPUTS, - .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE, - .stds = &standard[0], - .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), - .std_callback = &std_callback, -}; - -static struct saa7146_extension extension = { - .name = MXB_IDENTIFIER, - .flags = SAA7146_USE_I2C_IRQ, - - .pci_tbl = &pci_tbl[0], - .module = THIS_MODULE, - - .attach = mxb_attach, - .detach = mxb_detach, - - .irq_mask = 0, - .irq_func = NULL, -}; - -static int __init mxb_init_module(void) -{ - if (saa7146_register_extension(&extension)) { - DEB_S(("failed to register extension.\n")); - return -ENODEV; - } - - return 0; -} - -static void __exit mxb_cleanup_module(void) -{ - saa7146_unregister_extension(&extension); -} - -module_init(mxb_init_module); -module_exit(mxb_cleanup_module); - -MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'"); -MODULE_AUTHOR("Michael Hunold "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mxb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mxb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mxb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/mxb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -#ifndef __MXB__ -#define __MXB__ - -#define BASE_VIDIOC_MXB 10 - -#define MXB_S_AUDIO_CD _IOW ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+0, int) -#define MXB_S_AUDIO_LINE _IOW ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+1, int) - -#define MXB_IDENTIFIER "Multimedia eXtension Board" - -#define MXB_AUDIOS 6 - -/* these are the available audio sources, which can switched - to the line- and cd-output individually */ -static struct v4l2_audio mxb_audios[MXB_AUDIOS] = { - { - .index = 0, - .name = "Tuner", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 1, - .name = "AUX1", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 2, - .name = "AUX2", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 3, - .name = "AUX3", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 4, - .name = "Radio (X9)", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 5, - .name = "CD-ROM (X10)", - .capability = V4L2_AUDCAP_STEREO, - } -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/noon010pc30.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/noon010pc30.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/noon010pc30.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/noon010pc30.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,792 +0,0 @@ -/* - * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP - * - * Copyright (C) 2010 Samsung Electronics - * Contact: Sylwester Nawrocki, - * - * Initial register configuration based on a driver authored by - * HeungJun Kim . - * - * 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, or - * (at your option) any later vergsion. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable module debug trace. Set to 1 to enable."); - -#define MODULE_NAME "NOON010PC30" - -/* - * Register offsets within a page - * b15..b8 - page id, b7..b0 - register address - */ -#define POWER_CTRL_REG 0x0001 -#define PAGEMODE_REG 0x03 -#define DEVICE_ID_REG 0x0004 -#define NOON010PC30_ID 0x86 -#define VDO_CTL_REG(n) (0x0010 + (n)) -#define SYNC_CTL_REG 0x0012 -/* Window size and position */ -#define WIN_ROWH_REG 0x0013 -#define WIN_ROWL_REG 0x0014 -#define WIN_COLH_REG 0x0015 -#define WIN_COLL_REG 0x0016 -#define WIN_HEIGHTH_REG 0x0017 -#define WIN_HEIGHTL_REG 0x0018 -#define WIN_WIDTHH_REG 0x0019 -#define WIN_WIDTHL_REG 0x001A -#define HBLANKH_REG 0x001B -#define HBLANKL_REG 0x001C -#define VSYNCH_REG 0x001D -#define VSYNCL_REG 0x001E -/* VSYNC control */ -#define VS_CTL_REG(n) (0x00A1 + (n)) -/* page 1 */ -#define ISP_CTL_REG(n) (0x0110 + (n)) -#define YOFS_REG 0x0119 -#define DARK_YOFS_REG 0x011A -#define SAT_CTL_REG 0x0120 -#define BSAT_REG 0x0121 -#define RSAT_REG 0x0122 -/* Color correction */ -#define CMC_CTL_REG 0x0130 -#define CMC_OFSGH_REG 0x0133 -#define CMC_OFSGL_REG 0x0135 -#define CMC_SIGN_REG 0x0136 -#define CMC_GOFS_REG 0x0137 -#define CMC_COEF_REG(n) (0x0138 + (n)) -#define CMC_OFS_REG(n) (0x0141 + (n)) -/* Gamma correction */ -#define GMA_CTL_REG 0x0160 -#define GMA_COEF_REG(n) (0x0161 + (n)) -/* Lens Shading */ -#define LENS_CTRL_REG 0x01D0 -#define LENS_XCEN_REG 0x01D1 -#define LENS_YCEN_REG 0x01D2 -#define LENS_RC_REG 0x01D3 -#define LENS_GC_REG 0x01D4 -#define LENS_BC_REG 0x01D5 -#define L_AGON_REG 0x01D6 -#define L_AGOFF_REG 0x01D7 -/* Page 3 - Auto Exposure */ -#define AE_CTL_REG(n) (0x0310 + (n)) -#define AE_CTL9_REG 0x032C -#define AE_CTL10_REG 0x032D -#define AE_YLVL_REG 0x031C -#define AE_YTH_REG(n) (0x031D + (n)) -#define AE_WGT_REG 0x0326 -#define EXP_TIMEH_REG 0x0333 -#define EXP_TIMEM_REG 0x0334 -#define EXP_TIMEL_REG 0x0335 -#define EXP_MMINH_REG 0x0336 -#define EXP_MMINL_REG 0x0337 -#define EXP_MMAXH_REG 0x0338 -#define EXP_MMAXM_REG 0x0339 -#define EXP_MMAXL_REG 0x033A -/* Page 4 - Auto White Balance */ -#define AWB_CTL_REG(n) (0x0410 + (n)) -#define AWB_ENABE 0x80 -#define AWB_WGHT_REG 0x0419 -#define BGAIN_PAR_REG(n) (0x044F + (n)) -/* Manual white balance, when AWB_CTL2[0]=1 */ -#define MWB_RGAIN_REG 0x0466 -#define MWB_BGAIN_REG 0x0467 - -/* The token to mark an array end */ -#define REG_TERM 0xFFFF - -struct noon010_format { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; - u16 ispctl1_reg; -}; - -struct noon010_frmsize { - u16 width; - u16 height; - int vid_ctl1; -}; - -static const char * const noon010_supply_name[] = { - "vdd_core", "vddio", "vdda" -}; - -#define NOON010_NUM_SUPPLIES ARRAY_SIZE(noon010_supply_name) - -struct noon010_info { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - const struct noon010pc30_platform_data *pdata; - const struct noon010_format *curr_fmt; - const struct noon010_frmsize *curr_win; - unsigned int hflip:1; - unsigned int vflip:1; - unsigned int power:1; - u8 i2c_reg_page; - struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES]; - u32 gpio_nreset; - u32 gpio_nstby; -}; - -struct i2c_regval { - u16 addr; - u16 val; -}; - -/* Supported resolutions. */ -static const struct noon010_frmsize noon010_sizes[] = { - { - .width = 352, - .height = 288, - .vid_ctl1 = 0, - }, { - .width = 176, - .height = 144, - .vid_ctl1 = 0x10, - }, { - .width = 88, - .height = 72, - .vid_ctl1 = 0x20, - }, -}; - -/* Supported pixel formats. */ -static const struct noon010_format noon010_formats[] = { - { - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0x03, - }, { - .code = V4L2_MBUS_FMT_YVYU8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0x02, - }, { - .code = V4L2_MBUS_FMT_VYUY8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0, - }, { - .code = V4L2_MBUS_FMT_UYVY8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0x01, - }, { - .code = V4L2_MBUS_FMT_RGB565_2X8_BE, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0x40, - }, -}; - -static const struct i2c_regval noon010_base_regs[] = { - { WIN_COLL_REG, 0x06 }, { HBLANKL_REG, 0x7C }, - /* Color corection and saturation */ - { ISP_CTL_REG(0), 0x30 }, { ISP_CTL_REG(2), 0x30 }, - { YOFS_REG, 0x80 }, { DARK_YOFS_REG, 0x04 }, - { SAT_CTL_REG, 0x1F }, { BSAT_REG, 0x90 }, - { CMC_CTL_REG, 0x0F }, { CMC_OFSGH_REG, 0x3C }, - { CMC_OFSGL_REG, 0x2C }, { CMC_SIGN_REG, 0x3F }, - { CMC_COEF_REG(0), 0x79 }, { CMC_OFS_REG(0), 0x00 }, - { CMC_COEF_REG(1), 0x39 }, { CMC_OFS_REG(1), 0x00 }, - { CMC_COEF_REG(2), 0x00 }, { CMC_OFS_REG(2), 0x00 }, - { CMC_COEF_REG(3), 0x11 }, { CMC_OFS_REG(3), 0x8B }, - { CMC_COEF_REG(4), 0x65 }, { CMC_OFS_REG(4), 0x07 }, - { CMC_COEF_REG(5), 0x14 }, { CMC_OFS_REG(5), 0x04 }, - { CMC_COEF_REG(6), 0x01 }, { CMC_OFS_REG(6), 0x9C }, - { CMC_COEF_REG(7), 0x33 }, { CMC_OFS_REG(7), 0x89 }, - { CMC_COEF_REG(8), 0x74 }, { CMC_OFS_REG(8), 0x25 }, - /* Automatic white balance */ - { AWB_CTL_REG(0), 0x78 }, { AWB_CTL_REG(1), 0x2E }, - { AWB_CTL_REG(2), 0x20 }, { AWB_CTL_REG(3), 0x85 }, - /* Auto exposure */ - { AE_CTL_REG(0), 0xDC }, { AE_CTL_REG(1), 0x81 }, - { AE_CTL_REG(2), 0x30 }, { AE_CTL_REG(3), 0xA5 }, - { AE_CTL_REG(4), 0x40 }, { AE_CTL_REG(5), 0x51 }, - { AE_CTL_REG(6), 0x33 }, { AE_CTL_REG(7), 0x7E }, - { AE_CTL9_REG, 0x00 }, { AE_CTL10_REG, 0x02 }, - { AE_YLVL_REG, 0x44 }, { AE_YTH_REG(0), 0x34 }, - { AE_YTH_REG(1), 0x30 }, { AE_WGT_REG, 0xD5 }, - /* Lens shading compensation */ - { LENS_CTRL_REG, 0x01 }, { LENS_XCEN_REG, 0x80 }, - { LENS_YCEN_REG, 0x70 }, { LENS_RC_REG, 0x53 }, - { LENS_GC_REG, 0x40 }, { LENS_BC_REG, 0x3E }, - { REG_TERM, 0 }, -}; - -static inline struct noon010_info *to_noon010(struct v4l2_subdev *sd) -{ - return container_of(sd, struct noon010_info, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct noon010_info, hdl)->sd; -} - -static inline int set_i2c_page(struct noon010_info *info, - struct i2c_client *client, unsigned int reg) -{ - u32 page = reg >> 8 & 0xFF; - int ret = 0; - - if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) { - ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page); - if (!ret) - info->i2c_reg_page = page; - } - return ret; -} - -static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct noon010_info *info = to_noon010(sd); - int ret = set_i2c_page(info, client, reg_addr); - - if (ret) - return ret; - return i2c_smbus_read_byte_data(client, reg_addr & 0xFF); -} - -static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct noon010_info *info = to_noon010(sd); - int ret = set_i2c_page(info, client, reg_addr); - - if (ret) - return ret; - return i2c_smbus_write_byte_data(client, reg_addr & 0xFF, val); -} - -static inline int noon010_bulk_write_reg(struct v4l2_subdev *sd, - const struct i2c_regval *msg) -{ - while (msg->addr != REG_TERM) { - int ret = cam_i2c_write(sd, msg->addr, msg->val); - - if (ret) - return ret; - msg++; - } - return 0; -} - -/* Device reset and sleep mode control */ -static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep) -{ - struct noon010_info *info = to_noon010(sd); - u8 reg = sleep ? 0xF1 : 0xF0; - int ret = 0; - - if (reset) - ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02); - if (!ret) { - ret = cam_i2c_write(sd, POWER_CTRL_REG, reg); - if (reset && !ret) - info->i2c_reg_page = -1; - } - return ret; -} - -/* Automatic white balance control */ -static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on) -{ - int ret; - - ret = cam_i2c_write(sd, AWB_CTL_REG(1), on ? 0x2E : 0x2F); - if (!ret) - ret = cam_i2c_write(sd, AWB_CTL_REG(0), on ? 0xFB : 0x7B); - return ret; -} - -static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip) -{ - struct noon010_info *info = to_noon010(sd); - int reg, ret; - - reg = cam_i2c_read(sd, VDO_CTL_REG(1)); - if (reg < 0) - return reg; - - reg &= 0x7C; - if (hflip) - reg |= 0x01; - if (vflip) - reg |= 0x02; - - ret = cam_i2c_write(sd, VDO_CTL_REG(1), reg | 0x80); - if (!ret) { - info->hflip = hflip; - info->vflip = vflip; - } - return ret; -} - -/* Configure resolution and color format */ -static int noon010_set_params(struct v4l2_subdev *sd) -{ - struct noon010_info *info = to_noon010(sd); - int ret; - - if (!info->curr_win) - return -EINVAL; - - ret = cam_i2c_write(sd, VDO_CTL_REG(0), info->curr_win->vid_ctl1); - - if (!ret && info->curr_fmt) - ret = cam_i2c_write(sd, ISP_CTL_REG(0), - info->curr_fmt->ispctl1_reg); - return ret; -} - -/* Find nearest matching image pixel size. */ -static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf) -{ - unsigned int min_err = ~0; - int i = ARRAY_SIZE(noon010_sizes); - const struct noon010_frmsize *fsize = &noon010_sizes[0], - *match = NULL; - - while (i--) { - int err = abs(fsize->width - mf->width) - + abs(fsize->height - mf->height); - - if (err < min_err) { - min_err = err; - match = fsize; - } - fsize++; - } - if (match) { - mf->width = match->width; - mf->height = match->height; - return 0; - } - return -EINVAL; -} - -static int power_enable(struct noon010_info *info) -{ - int ret; - - if (info->power) { - v4l2_info(&info->sd, "%s: sensor is already on\n", __func__); - return 0; - } - - if (gpio_is_valid(info->gpio_nstby)) - gpio_set_value(info->gpio_nstby, 0); - - if (gpio_is_valid(info->gpio_nreset)) - gpio_set_value(info->gpio_nreset, 0); - - ret = regulator_bulk_enable(NOON010_NUM_SUPPLIES, info->supply); - if (ret) - return ret; - - if (gpio_is_valid(info->gpio_nreset)) { - msleep(50); - gpio_set_value(info->gpio_nreset, 1); - } - if (gpio_is_valid(info->gpio_nstby)) { - udelay(1000); - gpio_set_value(info->gpio_nstby, 1); - } - if (gpio_is_valid(info->gpio_nreset)) { - udelay(1000); - gpio_set_value(info->gpio_nreset, 0); - msleep(100); - gpio_set_value(info->gpio_nreset, 1); - msleep(20); - } - info->power = 1; - - v4l2_dbg(1, debug, &info->sd, "%s: sensor is on\n", __func__); - return 0; -} - -static int power_disable(struct noon010_info *info) -{ - int ret; - - if (!info->power) { - v4l2_info(&info->sd, "%s: sensor is already off\n", __func__); - return 0; - } - - ret = regulator_bulk_disable(NOON010_NUM_SUPPLIES, info->supply); - if (ret) - return ret; - - if (gpio_is_valid(info->gpio_nstby)) - gpio_set_value(info->gpio_nstby, 0); - - if (gpio_is_valid(info->gpio_nreset)) - gpio_set_value(info->gpio_nreset, 0); - - info->power = 0; - - v4l2_dbg(1, debug, &info->sd, "%s: sensor is off\n", __func__); - - return 0; -} - -static int noon010_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - - v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n", - __func__, ctrl->id, ctrl->val); - - switch (ctrl->id) { - case V4L2_CID_AUTO_WHITE_BALANCE: - return noon010_enable_autowhitebalance(sd, ctrl->val); - case V4L2_CID_BLUE_BALANCE: - return cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val); - case V4L2_CID_RED_BALANCE: - return cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val); - default: - return -EINVAL; - } -} - -static int noon010_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (!code || index >= ARRAY_SIZE(noon010_formats)) - return -EINVAL; - - *code = noon010_formats[index].code; - return 0; -} - -static int noon010_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) -{ - struct noon010_info *info = to_noon010(sd); - int ret; - - if (!mf) - return -EINVAL; - - if (!info->curr_win || !info->curr_fmt) { - ret = noon010_set_params(sd); - if (ret) - return ret; - } - - mf->width = info->curr_win->width; - mf->height = info->curr_win->height; - mf->code = info->curr_fmt->code; - mf->colorspace = info->curr_fmt->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -/* Return nearest media bus frame format. */ -static const struct noon010_format *try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - int i = ARRAY_SIZE(noon010_formats); - - noon010_try_frame_size(mf); - - while (i--) - if (mf->code == noon010_formats[i].code) - break; - - mf->code = noon010_formats[i].code; - - return &noon010_formats[i]; -} - -static int noon010_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - if (!sd || !mf) - return -EINVAL; - - try_fmt(sd, mf); - return 0; -} - -static int noon010_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct noon010_info *info = to_noon010(sd); - - if (!sd || !mf) - return -EINVAL; - - info->curr_fmt = try_fmt(sd, mf); - - return noon010_set_params(sd); -} - -static int noon010_base_config(struct v4l2_subdev *sd) -{ - struct noon010_info *info = to_noon010(sd); - int ret; - - ret = noon010_bulk_write_reg(sd, noon010_base_regs); - if (!ret) { - info->curr_fmt = &noon010_formats[0]; - info->curr_win = &noon010_sizes[0]; - ret = noon010_set_params(sd); - } - if (!ret) - ret = noon010_set_flip(sd, 1, 0); - if (!ret) - ret = noon010_power_ctrl(sd, false, false); - - /* sync the handler and the registers state */ - v4l2_ctrl_handler_setup(&to_noon010(sd)->hdl); - return ret; -} - -static int noon010_s_power(struct v4l2_subdev *sd, int on) -{ - struct noon010_info *info = to_noon010(sd); - const struct noon010pc30_platform_data *pdata = info->pdata; - int ret = 0; - - if (WARN(pdata == NULL, "No platform data!\n")) - return -ENOMEM; - - if (on) { - ret = power_enable(info); - if (ret) - return ret; - ret = noon010_base_config(sd); - } else { - noon010_power_ctrl(sd, false, true); - ret = power_disable(info); - info->curr_win = NULL; - info->curr_fmt = NULL; - } - - return ret; -} - -static int noon010_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, - V4L2_IDENT_NOON010PC30, 0); -} - -static int noon010_log_status(struct v4l2_subdev *sd) -{ - struct noon010_info *info = to_noon010(sd); - - v4l2_ctrl_handler_log_status(&info->hdl, sd->name); - return 0; -} - -static const struct v4l2_ctrl_ops noon010_ctrl_ops = { - .s_ctrl = noon010_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops noon010_core_ops = { - .g_chip_ident = noon010_g_chip_ident, - .s_power = noon010_s_power, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .log_status = noon010_log_status, -}; - -static const struct v4l2_subdev_video_ops noon010_video_ops = { - .g_mbus_fmt = noon010_g_fmt, - .s_mbus_fmt = noon010_s_fmt, - .try_mbus_fmt = noon010_try_fmt, - .enum_mbus_fmt = noon010_enum_fmt, -}; - -static const struct v4l2_subdev_ops noon010_ops = { - .core = &noon010_core_ops, - .video = &noon010_video_ops, -}; - -/* Return 0 if NOON010PC30L sensor type was detected or -ENODEV otherwise. */ -static int noon010_detect(struct i2c_client *client, struct noon010_info *info) -{ - int ret; - - ret = power_enable(info); - if (ret) - return ret; - - ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG); - if (ret < 0) - dev_err(&client->dev, "I2C read failed: 0x%X\n", ret); - - power_disable(info); - - return ret == NOON010PC30_ID ? 0 : -ENODEV; -} - -static int noon010_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct noon010_info *info; - struct v4l2_subdev *sd; - const struct noon010pc30_platform_data *pdata - = client->dev.platform_data; - int ret; - int i; - - if (!pdata) { - dev_err(&client->dev, "No platform data!\n"); - return -EIO; - } - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - sd = &info->sd; - strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); - v4l2_i2c_subdev_init(sd, client, &noon010_ops); - - v4l2_ctrl_handler_init(&info->hdl, 3); - - v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, - V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); - v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, - V4L2_CID_RED_BALANCE, 0, 127, 1, 64); - v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, - V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64); - - sd->ctrl_handler = &info->hdl; - - ret = info->hdl.error; - if (ret) - goto np_err; - - info->pdata = client->dev.platform_data; - info->i2c_reg_page = -1; - info->gpio_nreset = -EINVAL; - info->gpio_nstby = -EINVAL; - - if (gpio_is_valid(pdata->gpio_nreset)) { - ret = gpio_request(pdata->gpio_nreset, "NOON010PC30 NRST"); - if (ret) { - dev_err(&client->dev, "GPIO request error: %d\n", ret); - goto np_err; - } - info->gpio_nreset = pdata->gpio_nreset; - gpio_direction_output(info->gpio_nreset, 0); - gpio_export(info->gpio_nreset, 0); - } - - if (gpio_is_valid(pdata->gpio_nstby)) { - ret = gpio_request(pdata->gpio_nstby, "NOON010PC30 NSTBY"); - if (ret) { - dev_err(&client->dev, "GPIO request error: %d\n", ret); - goto np_gpio_err; - } - info->gpio_nstby = pdata->gpio_nstby; - gpio_direction_output(info->gpio_nstby, 0); - gpio_export(info->gpio_nstby, 0); - } - - for (i = 0; i < NOON010_NUM_SUPPLIES; i++) - info->supply[i].supply = noon010_supply_name[i]; - - ret = regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES, - info->supply); - if (ret) - goto np_reg_err; - - ret = noon010_detect(client, info); - if (!ret) - return 0; - - /* the sensor detection failed */ - regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply); -np_reg_err: - if (gpio_is_valid(info->gpio_nstby)) - gpio_free(info->gpio_nstby); -np_gpio_err: - if (gpio_is_valid(info->gpio_nreset)) - gpio_free(info->gpio_nreset); -np_err: - v4l2_ctrl_handler_free(&info->hdl); - v4l2_device_unregister_subdev(sd); - kfree(info); - return ret; -} - -static int noon010_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct noon010_info *info = to_noon010(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&info->hdl); - - regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply); - - if (gpio_is_valid(info->gpio_nreset)) - gpio_free(info->gpio_nreset); - - if (gpio_is_valid(info->gpio_nstby)) - gpio_free(info->gpio_nstby); - - kfree(info); - return 0; -} - -static const struct i2c_device_id noon010_id[] = { - { MODULE_NAME, 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, noon010_id); - - -static struct i2c_driver noon010_i2c_driver = { - .driver = { - .name = MODULE_NAME - }, - .probe = noon010_probe, - .remove = noon010_remove, - .id_table = noon010_id, -}; - -static int __init noon010_init(void) -{ - return i2c_add_driver(&noon010_i2c_driver); -} - -static void __exit noon010_exit(void) -{ - i2c_del_driver(&noon010_i2c_driver); -} - -module_init(noon010_init); -module_exit(noon010_exit); - -MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver"); -MODULE_AUTHOR("Sylwester Nawrocki "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -config VIDEO_OMAP2_VOUT - tristate "OMAP2/OMAP3 V4L2-Display driver" - depends on ARCH_OMAP2 || ARCH_OMAP3 - select VIDEOBUF_GEN - select VIDEOBUF_DMA_CONTIG - select OMAP2_DSS - select OMAP2_VRAM - select OMAP2_VRFB - default n - ---help--- - V4L2 Display driver support for OMAP2/3 based boards. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -# -# Makefile for the omap video device drivers. -# - -# OMAP2/3 Display driver -omap-vout-y := omap_vout.o omap_voutlib.o -obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_vout.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_vout.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_vout.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_vout.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2620 +0,0 @@ -/* - * omap_vout.c - * - * Copyright (C) 2005-2010 Texas Instruments. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - * Leveraged code from the OMAP2 camera driver - * Video-for-Linux (Version 2) camera capture driver for - * the OMAP24xx camera controller. - * - * Author: Andy Lowe (source@mvista.com) - * - * Copyright (C) 2004 MontaVista Software, Inc. - * Copyright (C) 2010 Texas Instruments. - * - * History: - * 20-APR-2006 Khasim Modified VRFB based Rotation, - * The image data is always read from 0 degree - * view and written - * to the virtual space of desired rotation angle - * 4-DEC-2006 Jian Changed to support better memory management - * - * 17-Nov-2008 Hardik Changed driver to use video_ioctl2 - * - * 23-Feb-2010 Vaibhav H Modified to use new DSS2 interface - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include "omap_voutlib.h" -#include "omap_voutdef.h" - -MODULE_AUTHOR("Texas Instruments"); -MODULE_DESCRIPTION("OMAP Video for Linux Video out driver"); -MODULE_LICENSE("GPL"); - - -/* Driver Configuration macros */ -#define VOUT_NAME "omap_vout" - -enum omap_vout_channels { - OMAP_VIDEO1, - OMAP_VIDEO2, -}; - -enum dma_channel_state { - DMA_CHAN_NOT_ALLOTED, - DMA_CHAN_ALLOTED, -}; - -#define QQVGA_WIDTH 160 -#define QQVGA_HEIGHT 120 - -/* Max Resolution supported by the driver */ -#define VID_MAX_WIDTH 1280 /* Largest width */ -#define VID_MAX_HEIGHT 720 /* Largest height */ - -/* Mimimum requirement is 2x2 for DSS */ -#define VID_MIN_WIDTH 2 -#define VID_MIN_HEIGHT 2 - -/* 2048 x 2048 is max res supported by OMAP display controller */ -#define MAX_PIXELS_PER_LINE 2048 - -#define VRFB_TX_TIMEOUT 1000 -#define VRFB_NUM_BUFS 4 - -/* Max buffer size tobe allocated during init */ -#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4) - -static struct videobuf_queue_ops video_vbq_ops; -/* Variables configurable through module params*/ -static u32 video1_numbuffers = 3; -static u32 video2_numbuffers = 3; -static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE; -static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE; -static u32 vid1_static_vrfb_alloc; -static u32 vid2_static_vrfb_alloc; -static int debug; - -/* Module parameters */ -module_param(video1_numbuffers, uint, S_IRUGO); -MODULE_PARM_DESC(video1_numbuffers, - "Number of buffers to be allocated at init time for Video1 device."); - -module_param(video2_numbuffers, uint, S_IRUGO); -MODULE_PARM_DESC(video2_numbuffers, - "Number of buffers to be allocated at init time for Video2 device."); - -module_param(video1_bufsize, uint, S_IRUGO); -MODULE_PARM_DESC(video1_bufsize, - "Size of the buffer to be allocated for video1 device"); - -module_param(video2_bufsize, uint, S_IRUGO); -MODULE_PARM_DESC(video2_bufsize, - "Size of the buffer to be allocated for video2 device"); - -module_param(vid1_static_vrfb_alloc, bool, S_IRUGO); -MODULE_PARM_DESC(vid1_static_vrfb_alloc, - "Static allocation of the VRFB buffer for video1 device"); - -module_param(vid2_static_vrfb_alloc, bool, S_IRUGO); -MODULE_PARM_DESC(vid2_static_vrfb_alloc, - "Static allocation of the VRFB buffer for video2 device"); - -module_param(debug, bool, S_IRUGO); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -/* list of image formats supported by OMAP2 video pipelines */ -const static struct v4l2_fmtdesc omap_formats[] = { - { - /* Note: V4L2 defines RGB565 as: - * - * Byte 0 Byte 1 - * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 - * - * We interpret RGB565 as: - * - * Byte 0 Byte 1 - * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 - */ - .description = "RGB565, le", - .pixelformat = V4L2_PIX_FMT_RGB565, - }, - { - /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use - * this for RGB24 unpack mode, the last 8 bits are ignored - * */ - .description = "RGB32, le", - .pixelformat = V4L2_PIX_FMT_RGB32, - }, - { - /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use - * this for RGB24 packed mode - * - */ - .description = "RGB24, le", - .pixelformat = V4L2_PIX_FMT_RGB24, - }, - { - .description = "YUYV (YUV 4:2:2), packed", - .pixelformat = V4L2_PIX_FMT_YUYV, - }, - { - .description = "UYVY, packed", - .pixelformat = V4L2_PIX_FMT_UYVY, - }, -}; - -#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats)) - -/* - * Allocate buffers - */ -static unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr) -{ - u32 order, size; - unsigned long virt_addr, addr; - - size = PAGE_ALIGN(buf_size); - order = get_order(size); - virt_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, order); - addr = virt_addr; - - if (virt_addr) { - while (size > 0) { - SetPageReserved(virt_to_page(addr)); - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - } - *phys_addr = (u32) virt_to_phys((void *) virt_addr); - return virt_addr; -} - -/* - * Free buffers - */ -static void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size) -{ - u32 order, size; - unsigned long addr = virtaddr; - - size = PAGE_ALIGN(buf_size); - order = get_order(size); - - while (size > 0) { - ClearPageReserved(virt_to_page(addr)); - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - free_pages((unsigned long) virtaddr, order); -} - -/* - * Function for allocating video buffers - */ -static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout, - unsigned int *count, int startindex) -{ - int i, j; - - for (i = 0; i < *count; i++) { - if (!vout->smsshado_virt_addr[i]) { - vout->smsshado_virt_addr[i] = - omap_vout_alloc_buffer(vout->smsshado_size, - &vout->smsshado_phy_addr[i]); - } - if (!vout->smsshado_virt_addr[i] && startindex != -1) { - if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex) - break; - } - if (!vout->smsshado_virt_addr[i]) { - for (j = 0; j < i; j++) { - omap_vout_free_buffer( - vout->smsshado_virt_addr[j], - vout->smsshado_size); - vout->smsshado_virt_addr[j] = 0; - vout->smsshado_phy_addr[j] = 0; - } - *count = 0; - return -ENOMEM; - } - memset((void *) vout->smsshado_virt_addr[i], 0, - vout->smsshado_size); - } - return 0; -} - -/* - * Try format - */ -static int omap_vout_try_format(struct v4l2_pix_format *pix) -{ - int ifmt, bpp = 0; - - pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT, - (u32)VID_MAX_HEIGHT); - pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH); - - for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) { - if (pix->pixelformat == omap_formats[ifmt].pixelformat) - break; - } - - if (ifmt == NUM_OUTPUT_FORMATS) - ifmt = 0; - - pix->pixelformat = omap_formats[ifmt].pixelformat; - pix->field = V4L2_FIELD_ANY; - pix->priv = 0; - - switch (pix->pixelformat) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - default: - pix->colorspace = V4L2_COLORSPACE_JPEG; - bpp = YUYV_BPP; - break; - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - pix->colorspace = V4L2_COLORSPACE_SRGB; - bpp = RGB565_BPP; - break; - case V4L2_PIX_FMT_RGB24: - pix->colorspace = V4L2_COLORSPACE_SRGB; - bpp = RGB24_BPP; - break; - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_BGR32: - pix->colorspace = V4L2_COLORSPACE_SRGB; - bpp = RGB32_BPP; - break; - } - pix->bytesperline = pix->width * bpp; - pix->sizeimage = pix->bytesperline * pix->height; - - return bpp; -} - -/* - * omap_vout_uservirt_to_phys: This inline function is used to convert user - * space virtual address to physical address. - */ -static u32 omap_vout_uservirt_to_phys(u32 virtp) -{ - unsigned long physp = 0; - struct vm_area_struct *vma; - struct mm_struct *mm = current->mm; - - vma = find_vma(mm, virtp); - /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) { - physp = virt_to_phys((void *) virtp); - } else if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) { - /* this will catch, kernel-allocated, mmaped-to-usermode - addresses */ - physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); - } else { - /* otherwise, use get_user_pages() for general userland pages */ - int res, nr_pages = 1; - struct page *pages; - down_read(¤t->mm->mmap_sem); - - res = get_user_pages(current, current->mm, virtp, nr_pages, 1, - 0, &pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (res == nr_pages) { - physp = __pa(page_address(&pages[0]) + - (virtp & ~PAGE_MASK)); - } else { - printk(KERN_WARNING VOUT_NAME - "get_user_pages failed\n"); - return 0; - } - } - - return physp; -} - -/* - * Wakes up the application once the DMA transfer to VRFB space is completed. - */ -static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data) -{ - struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data; - - t->tx_status = 1; - wake_up_interruptible(&t->wait); -} - -/* - * Release the VRFB context once the module exits - */ -static void omap_vout_release_vrfb(struct omap_vout_device *vout) -{ - int i; - - for (i = 0; i < VRFB_NUM_BUFS; i++) - omap_vrfb_release_ctx(&vout->vrfb_context[i]); - - if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) { - vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; - omap_free_dma(vout->vrfb_dma_tx.dma_ch); - } -} - -/* - * Return true if rotation is 90 or 270 - */ -static inline int rotate_90_or_270(const struct omap_vout_device *vout) -{ - return (vout->rotation == dss_rotation_90_degree || - vout->rotation == dss_rotation_270_degree); -} - -/* - * Return true if rotation is enabled - */ -static inline int rotation_enabled(const struct omap_vout_device *vout) -{ - return vout->rotation || vout->mirror; -} - -/* - * Reverse the rotation degree if mirroring is enabled - */ -static inline int calc_rotation(const struct omap_vout_device *vout) -{ - if (!vout->mirror) - return vout->rotation; - - switch (vout->rotation) { - case dss_rotation_90_degree: - return dss_rotation_270_degree; - case dss_rotation_270_degree: - return dss_rotation_90_degree; - case dss_rotation_180_degree: - return dss_rotation_0_degree; - default: - return dss_rotation_180_degree; - } -} - -/* - * Free the V4L2 buffers - */ -static void omap_vout_free_buffers(struct omap_vout_device *vout) -{ - int i, numbuffers; - - /* Allocate memory for the buffers */ - numbuffers = (vout->vid) ? video2_numbuffers : video1_numbuffers; - vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize; - - for (i = 0; i < numbuffers; i++) { - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - vout->buf_phy_addr[i] = 0; - vout->buf_virt_addr[i] = 0; - } -} - -/* - * Free VRFB buffers - */ -static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) -{ - int j; - - for (j = 0; j < VRFB_NUM_BUFS; j++) { - omap_vout_free_buffer(vout->smsshado_virt_addr[j], - vout->smsshado_size); - vout->smsshado_virt_addr[j] = 0; - vout->smsshado_phy_addr[j] = 0; - } -} - -/* - * Allocate the buffers for the VRFB space. Data is copied from V4L2 - * buffers to the VRFB buffers using the DMA engine. - */ -static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, - unsigned int *count, unsigned int startindex) -{ - int i; - bool yuv_mode; - - /* Allocate the VRFB buffers only if the buffers are not - * allocated during init time. - */ - if ((rotation_enabled(vout)) && !vout->vrfb_static_allocation) - if (omap_vout_allocate_vrfb_buffers(vout, count, startindex)) - return -ENOMEM; - - if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 || - vout->dss_mode == OMAP_DSS_COLOR_UYVY) - yuv_mode = true; - else - yuv_mode = false; - - for (i = 0; i < *count; i++) - omap_vrfb_setup(&vout->vrfb_context[i], - vout->smsshado_phy_addr[i], vout->pix.width, - vout->pix.height, vout->bpp, yuv_mode); - - return 0; -} - -/* - * Convert V4L2 rotation to DSS rotation - * V4L2 understand 0, 90, 180, 270. - * Convert to 0, 1, 2 and 3 repsectively for DSS - */ -static int v4l2_rot_to_dss_rot(int v4l2_rotation, - enum dss_rotation *rotation, bool mirror) -{ - int ret = 0; - - switch (v4l2_rotation) { - case 90: - *rotation = dss_rotation_90_degree; - break; - case 180: - *rotation = dss_rotation_180_degree; - break; - case 270: - *rotation = dss_rotation_270_degree; - break; - case 0: - *rotation = dss_rotation_0_degree; - break; - default: - ret = -EINVAL; - } - return ret; -} - -/* - * Calculate the buffer offsets from which the streaming should - * start. This offset calculation is mainly required because of - * the VRFB 32 pixels alignment with rotation. - */ -static int omap_vout_calculate_offset(struct omap_vout_device *vout) -{ - struct omap_overlay *ovl; - enum dss_rotation rotation; - struct omapvideo_info *ovid; - bool mirroring = vout->mirror; - struct omap_dss_device *cur_display; - struct v4l2_rect *crop = &vout->crop; - struct v4l2_pix_format *pix = &vout->pix; - int *cropped_offset = &vout->cropped_offset; - int vr_ps = 1, ps = 2, temp_ps = 2; - int offset = 0, ctop = 0, cleft = 0, line_length = 0; - - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - /* get the display device attached to the overlay */ - if (!ovl->manager || !ovl->manager->device) - return -1; - - cur_display = ovl->manager->device; - rotation = calc_rotation(vout); - - if (V4L2_PIX_FMT_YUYV == pix->pixelformat || - V4L2_PIX_FMT_UYVY == pix->pixelformat) { - if (rotation_enabled(vout)) { - /* - * ps - Actual pixel size for YUYV/UYVY for - * VRFB/Mirroring is 4 bytes - * vr_ps - Virtually pixel size for YUYV/UYVY is - * 2 bytes - */ - ps = 4; - vr_ps = 2; - } else { - ps = 2; /* otherwise the pixel size is 2 byte */ - } - } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) { - ps = 4; - } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) { - ps = 3; - } - vout->ps = ps; - vout->vr_ps = vr_ps; - - if (rotation_enabled(vout)) { - line_length = MAX_PIXELS_PER_LINE; - ctop = (pix->height - crop->height) - crop->top; - cleft = (pix->width - crop->width) - crop->left; - } else { - line_length = pix->width; - } - vout->line_length = line_length; - switch (rotation) { - case dss_rotation_90_degree: - offset = vout->vrfb_context[0].yoffset * - vout->vrfb_context[0].bytespp; - temp_ps = ps / vr_ps; - if (mirroring == 0) { - *cropped_offset = offset + line_length * - temp_ps * cleft + crop->top * temp_ps; - } else { - *cropped_offset = offset + line_length * temp_ps * - cleft + crop->top * temp_ps + (line_length * - ((crop->width / (vr_ps)) - 1) * ps); - } - break; - case dss_rotation_180_degree: - offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset * - vout->vrfb_context[0].bytespp) + - (vout->vrfb_context[0].xoffset * - vout->vrfb_context[0].bytespp)); - if (mirroring == 0) { - *cropped_offset = offset + (line_length * ps * ctop) + - (cleft / vr_ps) * ps; - - } else { - *cropped_offset = offset + (line_length * ps * ctop) + - (cleft / vr_ps) * ps + (line_length * - (crop->height - 1) * ps); - } - break; - case dss_rotation_270_degree: - offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset * - vout->vrfb_context[0].bytespp; - temp_ps = ps / vr_ps; - if (mirroring == 0) { - *cropped_offset = offset + line_length * - temp_ps * crop->left + ctop * ps; - } else { - *cropped_offset = offset + line_length * - temp_ps * crop->left + ctop * ps + - (line_length * ((crop->width / vr_ps) - 1) * - ps); - } - break; - case dss_rotation_0_degree: - if (mirroring == 0) { - *cropped_offset = (line_length * ps) * - crop->top + (crop->left / vr_ps) * ps; - } else { - *cropped_offset = (line_length * ps) * - crop->top + (crop->left / vr_ps) * ps + - (line_length * (crop->height - 1) * ps); - } - break; - default: - *cropped_offset = (line_length * ps * crop->top) / - vr_ps + (crop->left * ps) / vr_ps + - ((crop->width / vr_ps) - 1) * ps; - break; - } - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n", - __func__, *cropped_offset); - return 0; -} - -/* - * Convert V4L2 pixel format to DSS pixel format - */ -static int video_mode_to_dss_mode(struct omap_vout_device *vout) -{ - struct omap_overlay *ovl; - struct omapvideo_info *ovid; - struct v4l2_pix_format *pix = &vout->pix; - enum omap_color_mode mode; - - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - - switch (pix->pixelformat) { - case 0: - break; - case V4L2_PIX_FMT_YUYV: - mode = OMAP_DSS_COLOR_YUV2; - break; - case V4L2_PIX_FMT_UYVY: - mode = OMAP_DSS_COLOR_UYVY; - break; - case V4L2_PIX_FMT_RGB565: - mode = OMAP_DSS_COLOR_RGB16; - break; - case V4L2_PIX_FMT_RGB24: - mode = OMAP_DSS_COLOR_RGB24P; - break; - case V4L2_PIX_FMT_RGB32: - mode = (ovl->id == OMAP_DSS_VIDEO1) ? - OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32; - break; - case V4L2_PIX_FMT_BGR32: - mode = OMAP_DSS_COLOR_RGBX32; - break; - default: - mode = -EINVAL; - } - return mode; -} - -/* - * Setup the overlay - */ -int omapvid_setup_overlay(struct omap_vout_device *vout, - struct omap_overlay *ovl, int posx, int posy, int outw, - int outh, u32 addr) -{ - int ret = 0; - struct omap_overlay_info info; - int cropheight, cropwidth, pixheight, pixwidth; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 && - (outw != vout->pix.width || outh != vout->pix.height)) { - ret = -EINVAL; - goto setup_ovl_err; - } - - vout->dss_mode = video_mode_to_dss_mode(vout); - if (vout->dss_mode == -EINVAL) { - ret = -EINVAL; - goto setup_ovl_err; - } - - /* Setup the input plane parameters according to - * rotation value selected. - */ - if (rotate_90_or_270(vout)) { - cropheight = vout->crop.width; - cropwidth = vout->crop.height; - pixheight = vout->pix.width; - pixwidth = vout->pix.height; - } else { - cropheight = vout->crop.height; - cropwidth = vout->crop.width; - pixheight = vout->pix.height; - pixwidth = vout->pix.width; - } - - ovl->get_overlay_info(ovl, &info); - info.paddr = addr; - info.vaddr = NULL; - info.width = cropwidth; - info.height = cropheight; - info.color_mode = vout->dss_mode; - info.mirror = vout->mirror; - info.pos_x = posx; - info.pos_y = posy; - info.out_width = outw; - info.out_height = outh; - info.global_alpha = vout->win.global_alpha; - if (!rotation_enabled(vout)) { - info.rotation = 0; - info.rotation_type = OMAP_DSS_ROT_DMA; - info.screen_width = pixwidth; - } else { - info.rotation = vout->rotation; - info.rotation_type = OMAP_DSS_ROT_VRFB; - info.screen_width = 2048; - } - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n" - "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n" - "out_height=%d rotation_type=%d screen_width=%d\n", - __func__, info.enabled, info.paddr, info.width, info.height, - info.color_mode, info.rotation, info.mirror, info.pos_x, - info.pos_y, info.out_width, info.out_height, info.rotation_type, - info.screen_width); - - ret = ovl->set_overlay_info(ovl, &info); - if (ret) - goto setup_ovl_err; - - return 0; - -setup_ovl_err: - v4l2_warn(&vout->vid_dev->v4l2_dev, "setup_overlay failed\n"); - return ret; -} - -/* - * Initialize the overlay structure - */ -int omapvid_init(struct omap_vout_device *vout, u32 addr) -{ - int ret = 0, i; - struct v4l2_window *win; - struct omap_overlay *ovl; - int posx, posy, outw, outh, temp; - struct omap_video_timings *timing; - struct omapvideo_info *ovid = &vout->vid_info; - - win = &vout->win; - for (i = 0; i < ovid->num_overlays; i++) { - ovl = ovid->overlays[i]; - if (!ovl->manager || !ovl->manager->device) - return -EINVAL; - - timing = &ovl->manager->device->panel.timings; - - outw = win->w.width; - outh = win->w.height; - switch (vout->rotation) { - case dss_rotation_90_degree: - /* Invert the height and width for 90 - * and 270 degree rotation - */ - temp = outw; - outw = outh; - outh = temp; - posy = (timing->y_res - win->w.width) - win->w.left; - posx = win->w.top; - break; - - case dss_rotation_180_degree: - posx = (timing->x_res - win->w.width) - win->w.left; - posy = (timing->y_res - win->w.height) - win->w.top; - break; - - case dss_rotation_270_degree: - temp = outw; - outw = outh; - outh = temp; - posy = win->w.left; - posx = (timing->x_res - win->w.height) - win->w.top; - break; - - default: - posx = win->w.left; - posy = win->w.top; - break; - } - - ret = omapvid_setup_overlay(vout, ovl, posx, posy, - outw, outh, addr); - if (ret) - goto omapvid_init_err; - } - return 0; - -omapvid_init_err: - v4l2_warn(&vout->vid_dev->v4l2_dev, "apply_changes failed\n"); - return ret; -} - -/* - * Apply the changes set the go bit of DSS - */ -int omapvid_apply_changes(struct omap_vout_device *vout) -{ - int i; - struct omap_overlay *ovl; - struct omapvideo_info *ovid = &vout->vid_info; - - for (i = 0; i < ovid->num_overlays; i++) { - ovl = ovid->overlays[i]; - if (!ovl->manager || !ovl->manager->device) - return -EINVAL; - ovl->manager->apply(ovl->manager); - } - - return 0; -} - -void omap_vout_isr(void *arg, unsigned int irqstatus) -{ - int ret; - u32 addr, fid; - struct omap_overlay *ovl; - struct timeval timevalue; - struct omapvideo_info *ovid; - struct omap_dss_device *cur_display; - struct omap_vout_device *vout = (struct omap_vout_device *)arg; - - if (!vout->streaming) - return; - - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - /* get the display device attached to the overlay */ - if (!ovl->manager || !ovl->manager->device) - return; - - cur_display = ovl->manager->device; - - spin_lock(&vout->vbq_lock); - do_gettimeofday(&timevalue); - if (cur_display->type == OMAP_DISPLAY_TYPE_DPI) { - if (!(irqstatus & DISPC_IRQ_VSYNC)) - goto vout_isr_err; - - if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { - vout->cur_frm->ts = timevalue; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); - vout->cur_frm = vout->next_frm; - } - vout->first_int = 0; - if (list_empty(&vout->dma_queue)) - goto vout_isr_err; - - vout->next_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vout->next_frm->queue); - - vout->next_frm->state = VIDEOBUF_ACTIVE; - - addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i] - + vout->cropped_offset; - - /* First save the configuration in ovelray structure */ - ret = omapvid_init(vout, addr); - if (ret) - printk(KERN_ERR VOUT_NAME - "failed to set overlay info\n"); - /* Enable the pipeline and set the Go bit */ - ret = omapvid_apply_changes(vout); - if (ret) - printk(KERN_ERR VOUT_NAME "failed to change mode\n"); - } else { - - if (vout->first_int) { - vout->first_int = 0; - goto vout_isr_err; - } - if (irqstatus & DISPC_IRQ_EVSYNC_ODD) - fid = 1; - else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) - fid = 0; - else - goto vout_isr_err; - - vout->field_id ^= 1; - if (fid != vout->field_id) { - if (0 == fid) - vout->field_id = fid; - - goto vout_isr_err; - } - if (0 == fid) { - if (vout->cur_frm == vout->next_frm) - goto vout_isr_err; - - vout->cur_frm->ts = timevalue; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); - vout->cur_frm = vout->next_frm; - } else if (1 == fid) { - if (list_empty(&vout->dma_queue) || - (vout->cur_frm != vout->next_frm)) - goto vout_isr_err; - - vout->next_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vout->next_frm->queue); - - vout->next_frm->state = VIDEOBUF_ACTIVE; - addr = (unsigned long) - vout->queued_buf_addr[vout->next_frm->i] + - vout->cropped_offset; - /* First save the configuration in ovelray structure */ - ret = omapvid_init(vout, addr); - if (ret) - printk(KERN_ERR VOUT_NAME - "failed to set overlay info\n"); - /* Enable the pipeline and set the Go bit */ - ret = omapvid_apply_changes(vout); - if (ret) - printk(KERN_ERR VOUT_NAME - "failed to change mode\n"); - } - - } - -vout_isr_err: - spin_unlock(&vout->vbq_lock); -} - - -/* Video buffer call backs */ - -/* - * Buffer setup function is called by videobuf layer when REQBUF ioctl is - * called. This is used to setup buffers and return size and count of - * buffers allocated. After the call to this buffer, videobuf layer will - * setup buffer queue depending on the size and count of buffers - */ -static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - int startindex = 0, i, j; - u32 phy_addr = 0, virt_addr = 0; - struct omap_vout_device *vout = q->priv_data; - - if (!vout) - return -EINVAL; - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type) - return -EINVAL; - - startindex = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex) - *count = startindex; - - if ((rotation_enabled(vout)) && *count > VRFB_NUM_BUFS) - *count = VRFB_NUM_BUFS; - - /* If rotation is enabled, allocate memory for VRFB space also */ - if (rotation_enabled(vout)) - if (omap_vout_vrfb_buffer_setup(vout, count, startindex)) - return -ENOMEM; - - if (V4L2_MEMORY_MMAP != vout->memory) - return 0; - - /* Now allocated the V4L2 buffers */ - *size = PAGE_ALIGN(vout->pix.width * vout->pix.height * vout->bpp); - startindex = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - - for (i = startindex; i < *count; i++) { - vout->buffer_size = *size; - - virt_addr = omap_vout_alloc_buffer(vout->buffer_size, - &phy_addr); - if (!virt_addr) { - if (!rotation_enabled(vout)) - break; - /* Free the VRFB buffers if no space for V4L2 buffers */ - for (j = i; j < *count; j++) { - omap_vout_free_buffer( - vout->smsshado_virt_addr[j], - vout->smsshado_size); - vout->smsshado_virt_addr[j] = 0; - vout->smsshado_phy_addr[j] = 0; - } - } - vout->buf_virt_addr[i] = virt_addr; - vout->buf_phy_addr[i] = phy_addr; - } - *count = vout->buffer_allocated = i; - - return 0; -} - -/* - * Free the V4L2 buffers additionally allocated than default - * number of buffers and free all the VRFB buffers - */ -static void omap_vout_free_allbuffers(struct omap_vout_device *vout) -{ - int num_buffers = 0, i; - - num_buffers = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - - for (i = num_buffers; i < vout->buffer_allocated; i++) { - if (vout->buf_virt_addr[i]) - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - - vout->buf_virt_addr[i] = 0; - vout->buf_phy_addr[i] = 0; - } - /* Free the VRFB buffers only if they are allocated - * during reqbufs. Don't free if init time allocated - */ - if (!vout->vrfb_static_allocation) { - for (i = 0; i < VRFB_NUM_BUFS; i++) { - if (vout->smsshado_virt_addr[i]) { - omap_vout_free_buffer( - vout->smsshado_virt_addr[i], - vout->smsshado_size); - vout->smsshado_virt_addr[i] = 0; - vout->smsshado_phy_addr[i] = 0; - } - } - } - vout->buffer_allocated = num_buffers; -} - -/* - * This function will be called when VIDIOC_QBUF ioctl is called. - * It prepare buffers before give out for the display. This function - * converts user space virtual address into physical address if userptr memory - * exchange mechanism is used. If rotation is enabled, it copies entire - * buffer into VRFB memory space before giving it to the DSS. - */ -static int omap_vout_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - dma_addr_t dmabuf; - struct vid_vrfb_dma *tx; - enum dss_rotation rotation; - struct omap_vout_device *vout = q->priv_data; - u32 dest_frame_index = 0, src_element_index = 0; - u32 dest_element_index = 0, src_frame_index = 0; - u32 elem_count = 0, frame_count = 0, pixsize = 2; - - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = vout->pix.width; - vb->height = vout->pix.height; - vb->size = vb->width * vb->height * vout->bpp; - vb->field = field; - } - vb->state = VIDEOBUF_PREPARED; - /* if user pointer memory mechanism is used, get the physical - * address of the buffer - */ - if (V4L2_MEMORY_USERPTR == vb->memory) { - if (0 == vb->baddr) - return -EINVAL; - /* Physical address */ - vout->queued_buf_addr[vb->i] = (u8 *) - omap_vout_uservirt_to_phys(vb->baddr); - } else { - vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i]; - } - - if (!rotation_enabled(vout)) - return 0; - - dmabuf = vout->buf_phy_addr[vb->i]; - /* If rotation is enabled, copy input buffer into VRFB - * memory space using DMA. We are copying input buffer - * into VRFB memory space of desired angle and DSS will - * read image VRFB memory for 0 degree angle - */ - pixsize = vout->bpp * vout->vrfb_bpp; - /* - * DMA transfer in double index mode - */ - - /* Frame index */ - dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) - - (vout->pix.width * vout->bpp)) + 1; - - /* Source and destination parameters */ - src_element_index = 0; - src_frame_index = 0; - dest_element_index = 1; - /* Number of elements per frame */ - elem_count = vout->pix.width * vout->bpp; - frame_count = vout->pix.height; - tx = &vout->vrfb_dma_tx; - tx->tx_status = 0; - omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32, - (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT, - tx->dev_id, 0x0); - /* src_port required only for OMAP1 */ - omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC, - dmabuf, src_element_index, src_frame_index); - /*set dma source burst mode for VRFB */ - omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); - rotation = calc_rotation(vout); - - /* dest_port required only for OMAP1 */ - omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX, - vout->vrfb_context[vb->i].paddr[0], dest_element_index, - dest_frame_index); - /*set dma dest burst mode for VRFB */ - omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); - omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0); - - omap_start_dma(tx->dma_ch); - interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT); - - if (tx->tx_status == 0) { - omap_stop_dma(tx->dma_ch); - return -EINVAL; - } - /* Store buffers physical address into an array. Addresses - * from this array will be used to configure DSS */ - vout->queued_buf_addr[vb->i] = (u8 *) - vout->vrfb_context[vb->i].paddr[rotation]; - return 0; -} - -/* - * Buffer queue funtion will be called from the videobuf layer when _QBUF - * ioctl is called. It is used to enqueue buffer, which is ready to be - * displayed. - */ -static void omap_vout_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct omap_vout_device *vout = q->priv_data; - - /* Driver is also maintainig a queue. So enqueue buffer in the driver - * queue */ - list_add_tail(&vb->queue, &vout->dma_queue); - - vb->state = VIDEOBUF_QUEUED; -} - -/* - * Buffer release function is called from videobuf layer to release buffer - * which are already allocated - */ -static void omap_vout_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct omap_vout_device *vout = q->priv_data; - - vb->state = VIDEOBUF_NEEDS_INIT; - - if (V4L2_MEMORY_MMAP != vout->memory) - return; -} - -/* - * File operations - */ -static void omap_vout_vm_open(struct vm_area_struct *vma) -{ - struct omap_vout_device *vout = vma->vm_private_data; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end); - vout->mmap_count++; -} - -static void omap_vout_vm_close(struct vm_area_struct *vma) -{ - struct omap_vout_device *vout = vma->vm_private_data; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end); - vout->mmap_count--; -} - -static struct vm_operations_struct omap_vout_vm_ops = { - .open = omap_vout_vm_open, - .close = omap_vout_vm_close, -}; - -static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma) -{ - int i; - void *pos; - unsigned long start = vma->vm_start; - unsigned long size = (vma->vm_end - vma->vm_start); - struct omap_vout_device *vout = file->private_data; - struct videobuf_queue *q = &vout->vbq; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__, - vma->vm_pgoff, vma->vm_start, vma->vm_end); - - /* look for the buffer to map */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[i]->memory) - continue; - if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT)) - break; - } - - if (VIDEO_MAX_FRAME == i) { - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - return -EINVAL; - } - q->bufs[i]->baddr = vma->vm_start; - - vma->vm_flags |= VM_RESERVED; - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - vma->vm_ops = &omap_vout_vm_ops; - vma->vm_private_data = (void *) vout; - pos = (void *)vout->buf_virt_addr[i]; - vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT; - while (size > 0) { - unsigned long pfn; - pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT; - if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - vout->mmap_count++; - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); - - return 0; -} - -static int omap_vout_release(struct file *file) -{ - unsigned int ret, i; - struct videobuf_queue *q; - struct omapvideo_info *ovid; - struct omap_vout_device *vout = file->private_data; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); - ovid = &vout->vid_info; - - if (!vout) - return 0; - - q = &vout->vbq; - /* Disable all the overlay managers connected with this interface */ - for (i = 0; i < ovid->num_overlays; i++) { - struct omap_overlay *ovl = ovid->overlays[i]; - if (ovl->manager && ovl->manager->device) { - struct omap_overlay_info info; - ovl->get_overlay_info(ovl, &info); - info.enabled = 0; - ovl->set_overlay_info(ovl, &info); - } - } - /* Turn off the pipeline */ - ret = omapvid_apply_changes(vout); - if (ret) - v4l2_warn(&vout->vid_dev->v4l2_dev, - "Unable to apply changes\n"); - - /* Free all buffers */ - omap_vout_free_allbuffers(vout); - videobuf_mmap_free(q); - - /* Even if apply changes fails we should continue - freeing allocated memory */ - if (vout->streaming) { - u32 mask = 0; - - mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | - DISPC_IRQ_EVSYNC_ODD; - omap_dispc_unregister_isr(omap_vout_isr, vout, mask); - vout->streaming = 0; - - videobuf_streamoff(q); - videobuf_queue_cancel(q); - } - - if (vout->mmap_count != 0) - vout->mmap_count = 0; - - vout->opened -= 1; - file->private_data = NULL; - - if (vout->buffer_allocated) - videobuf_mmap_free(q); - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); - return ret; -} - -static int omap_vout_open(struct file *file) -{ - struct videobuf_queue *q; - struct omap_vout_device *vout = NULL; - - vout = video_drvdata(file); - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); - - if (vout == NULL) - return -ENODEV; - - /* for now, we only support single open */ - if (vout->opened) - return -EBUSY; - - vout->opened += 1; - - file->private_data = vout; - vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - - q = &vout->vbq; - video_vbq_ops.buf_setup = omap_vout_buffer_setup; - video_vbq_ops.buf_prepare = omap_vout_buffer_prepare; - video_vbq_ops.buf_release = omap_vout_buffer_release; - video_vbq_ops.buf_queue = omap_vout_buffer_queue; - spin_lock_init(&vout->vbq_lock); - - videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev, - &vout->vbq_lock, vout->type, V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), vout, NULL); - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); - return 0; -} - -/* - * V4L2 ioctls - */ -static int vidioc_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) -{ - struct omap_vout_device *vout = fh; - - strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver)); - strlcpy(cap->card, vout->vfd->name, sizeof(cap->card)); - cap->bus_info[0] = '\0'; - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT; - - return 0; -} - -static int vidioc_enum_fmt_vid_out(struct file *file, void *fh, - struct v4l2_fmtdesc *fmt) -{ - int index = fmt->index; - enum v4l2_buf_type type = fmt->type; - - fmt->index = index; - fmt->type = type; - if (index >= NUM_OUTPUT_FORMATS) - return -EINVAL; - - fmt->flags = omap_formats[index].flags; - strlcpy(fmt->description, omap_formats[index].description, - sizeof(fmt->description)); - fmt->pixelformat = omap_formats[index].pixelformat; - - return 0; -} - -static int vidioc_g_fmt_vid_out(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct omap_vout_device *vout = fh; - - f->fmt.pix = vout->pix; - return 0; - -} - -static int vidioc_try_fmt_vid_out(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct omap_overlay *ovl; - struct omapvideo_info *ovid; - struct omap_video_timings *timing; - struct omap_vout_device *vout = fh; - - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - - if (!ovl->manager || !ovl->manager->device) - return -EINVAL; - /* get the display device attached to the overlay */ - timing = &ovl->manager->device->panel.timings; - - vout->fbuf.fmt.height = timing->y_res; - vout->fbuf.fmt.width = timing->x_res; - - omap_vout_try_format(&f->fmt.pix); - return 0; -} - -static int vidioc_s_fmt_vid_out(struct file *file, void *fh, - struct v4l2_format *f) -{ - int ret, bpp; - struct omap_overlay *ovl; - struct omapvideo_info *ovid; - struct omap_video_timings *timing; - struct omap_vout_device *vout = fh; - - if (vout->streaming) - return -EBUSY; - - mutex_lock(&vout->lock); - - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - - /* get the display device attached to the overlay */ - if (!ovl->manager || !ovl->manager->device) { - ret = -EINVAL; - goto s_fmt_vid_out_exit; - } - timing = &ovl->manager->device->panel.timings; - - /* We dont support RGB24-packed mode if vrfb rotation - * is enabled*/ - if ((rotation_enabled(vout)) && - f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) { - ret = -EINVAL; - goto s_fmt_vid_out_exit; - } - - /* get the framebuffer parameters */ - - if (rotate_90_or_270(vout)) { - vout->fbuf.fmt.height = timing->x_res; - vout->fbuf.fmt.width = timing->y_res; - } else { - vout->fbuf.fmt.height = timing->y_res; - vout->fbuf.fmt.width = timing->x_res; - } - - /* change to samller size is OK */ - - bpp = omap_vout_try_format(&f->fmt.pix); - f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp; - - /* try & set the new output format */ - vout->bpp = bpp; - vout->pix = f->fmt.pix; - vout->vrfb_bpp = 1; - - /* If YUYV then vrfb bpp is 2, for others its 1 */ - if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat || - V4L2_PIX_FMT_UYVY == vout->pix.pixelformat) - vout->vrfb_bpp = 2; - - /* set default crop and win */ - omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win); - - /* Save the changes in the overlay strcuture */ - ret = omapvid_init(vout, 0); - if (ret) { - v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n"); - goto s_fmt_vid_out_exit; - } - - ret = 0; - -s_fmt_vid_out_exit: - mutex_unlock(&vout->lock); - return ret; -} - -static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, - struct v4l2_format *f) -{ - int ret = 0; - struct omap_vout_device *vout = fh; - struct v4l2_window *win = &f->fmt.win; - - ret = omap_vout_try_window(&vout->fbuf, win); - - if (!ret) { - if (vout->vid == OMAP_VIDEO1) - win->global_alpha = 255; - else - win->global_alpha = f->fmt.win.global_alpha; - } - - return ret; -} - -static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh, - struct v4l2_format *f) -{ - int ret = 0; - struct omap_overlay *ovl; - struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; - struct v4l2_window *win = &f->fmt.win; - - mutex_lock(&vout->lock); - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - - ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win); - if (!ret) { - /* Video1 plane does not support global alpha */ - if (ovl->id == OMAP_DSS_VIDEO1) - vout->win.global_alpha = 255; - else - vout->win.global_alpha = f->fmt.win.global_alpha; - - vout->win.chromakey = f->fmt.win.chromakey; - } - mutex_unlock(&vout->lock); - return ret; -} - -static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh, - struct v4l2_fmtdesc *fmt) -{ - int index = fmt->index; - enum v4l2_buf_type type = fmt->type; - - fmt->index = index; - fmt->type = type; - if (index >= NUM_OUTPUT_FORMATS) - return -EINVAL; - - fmt->flags = omap_formats[index].flags; - strlcpy(fmt->description, omap_formats[index].description, - sizeof(fmt->description)); - fmt->pixelformat = omap_formats[index].pixelformat; - return 0; -} - -static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, - struct v4l2_format *f) -{ - u32 key_value = 0; - struct omap_overlay *ovl; - struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; - struct omap_overlay_manager_info info; - struct v4l2_window *win = &f->fmt.win; - - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - - win->w = vout->win.w; - win->field = vout->win.field; - win->global_alpha = vout->win.global_alpha; - - if (ovl->manager && ovl->manager->get_manager_info) { - ovl->manager->get_manager_info(ovl->manager, &info); - key_value = info.trans_key; - } - win->chromakey = key_value; - return 0; -} - -static int vidioc_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cropcap) -{ - struct omap_vout_device *vout = fh; - struct v4l2_pix_format *pix = &vout->pix; - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - /* Width and height are always even */ - cropcap->bounds.width = pix->width & ~1; - cropcap->bounds.height = pix->height & ~1; - - omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect); - cropcap->pixelaspect.numerator = 1; - cropcap->pixelaspect.denominator = 1; - return 0; -} - -static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct omap_vout_device *vout = fh; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - crop->c = vout->crop; - return 0; -} - -static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - int ret = -EINVAL; - struct omap_vout_device *vout = fh; - struct omapvideo_info *ovid; - struct omap_overlay *ovl; - struct omap_video_timings *timing; - - if (vout->streaming) - return -EBUSY; - - mutex_lock(&vout->lock); - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - - if (!ovl->manager || !ovl->manager->device) { - ret = -EINVAL; - goto s_crop_err; - } - /* get the display device attached to the overlay */ - timing = &ovl->manager->device->panel.timings; - - if (rotate_90_or_270(vout)) { - vout->fbuf.fmt.height = timing->x_res; - vout->fbuf.fmt.width = timing->y_res; - } else { - vout->fbuf.fmt.height = timing->y_res; - vout->fbuf.fmt.width = timing->x_res; - } - - if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win, - &vout->fbuf, &crop->c); - -s_crop_err: - mutex_unlock(&vout->lock); - return ret; -} - -static int vidioc_queryctrl(struct file *file, void *fh, - struct v4l2_queryctrl *ctrl) -{ - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_ROTATE: - ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0); - break; - case V4L2_CID_BG_COLOR: - ret = v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0); - break; - case V4L2_CID_VFLIP: - ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0); - break; - default: - ctrl->name[0] = '\0'; - ret = -EINVAL; - } - return ret; -} - -static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) -{ - int ret = 0; - struct omap_vout_device *vout = fh; - - switch (ctrl->id) { - case V4L2_CID_ROTATE: - ctrl->value = vout->control[0].value; - break; - case V4L2_CID_BG_COLOR: - { - struct omap_overlay_manager_info info; - struct omap_overlay *ovl; - - ovl = vout->vid_info.overlays[0]; - if (!ovl->manager || !ovl->manager->get_manager_info) { - ret = -EINVAL; - break; - } - - ovl->manager->get_manager_info(ovl->manager, &info); - ctrl->value = info.default_color; - break; - } - case V4L2_CID_VFLIP: - ctrl->value = vout->control[2].value; - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) -{ - int ret = 0; - struct omap_vout_device *vout = fh; - - switch (a->id) { - case V4L2_CID_ROTATE: - { - int rotation = a->value; - - mutex_lock(&vout->lock); - - if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { - mutex_unlock(&vout->lock); - ret = -EINVAL; - break; - } - - if (v4l2_rot_to_dss_rot(rotation, &vout->rotation, - vout->mirror)) { - mutex_unlock(&vout->lock); - ret = -EINVAL; - break; - } - - vout->control[0].value = rotation; - mutex_unlock(&vout->lock); - break; - } - case V4L2_CID_BG_COLOR: - { - struct omap_overlay *ovl; - unsigned int color = a->value; - struct omap_overlay_manager_info info; - - ovl = vout->vid_info.overlays[0]; - - mutex_lock(&vout->lock); - if (!ovl->manager || !ovl->manager->get_manager_info) { - mutex_unlock(&vout->lock); - ret = -EINVAL; - break; - } - - ovl->manager->get_manager_info(ovl->manager, &info); - info.default_color = color; - if (ovl->manager->set_manager_info(ovl->manager, &info)) { - mutex_unlock(&vout->lock); - ret = -EINVAL; - break; - } - - vout->control[1].value = color; - mutex_unlock(&vout->lock); - break; - } - case V4L2_CID_VFLIP: - { - struct omap_overlay *ovl; - struct omapvideo_info *ovid; - unsigned int mirror = a->value; - - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - - mutex_lock(&vout->lock); - - if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { - mutex_unlock(&vout->lock); - ret = -EINVAL; - break; - } - vout->mirror = mirror; - vout->control[2].value = mirror; - mutex_unlock(&vout->lock); - break; - } - default: - ret = -EINVAL; - } - return ret; -} - -static int vidioc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req) -{ - int ret = 0; - unsigned int i, num_buffers = 0; - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; - - if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0)) - return -EINVAL; - /* if memory is not mmp or userptr - return error */ - if ((V4L2_MEMORY_MMAP != req->memory) && - (V4L2_MEMORY_USERPTR != req->memory)) - return -EINVAL; - - mutex_lock(&vout->lock); - /* Cannot be requested when streaming is on */ - if (vout->streaming) { - ret = -EBUSY; - goto reqbuf_err; - } - - /* If buffers are already allocated free them */ - if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) { - if (vout->mmap_count) { - ret = -EBUSY; - goto reqbuf_err; - } - num_buffers = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - for (i = num_buffers; i < vout->buffer_allocated; i++) { - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - vout->buf_virt_addr[i] = 0; - vout->buf_phy_addr[i] = 0; - } - vout->buffer_allocated = num_buffers; - videobuf_mmap_free(q); - } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) { - if (vout->buffer_allocated) { - videobuf_mmap_free(q); - for (i = 0; i < vout->buffer_allocated; i++) { - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - vout->buffer_allocated = 0; - } - } - - /*store the memory type in data structure */ - vout->memory = req->memory; - - INIT_LIST_HEAD(&vout->dma_queue); - - /* call videobuf_reqbufs api */ - ret = videobuf_reqbufs(q, req); - if (ret < 0) - goto reqbuf_err; - - vout->buffer_allocated = req->count; - -reqbuf_err: - mutex_unlock(&vout->lock); - return ret; -} - -static int vidioc_querybuf(struct file *file, void *fh, - struct v4l2_buffer *b) -{ - struct omap_vout_device *vout = fh; - - return videobuf_querybuf(&vout->vbq, b); -} - -static int vidioc_qbuf(struct file *file, void *fh, - struct v4l2_buffer *buffer) -{ - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; - - if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) || - (buffer->index >= vout->buffer_allocated) || - (q->bufs[buffer->index]->memory != buffer->memory)) { - return -EINVAL; - } - if (V4L2_MEMORY_USERPTR == buffer->memory) { - if ((buffer->length < vout->pix.sizeimage) || - (0 == buffer->m.userptr)) { - return -EINVAL; - } - } - - if ((rotation_enabled(vout)) && - vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) { - v4l2_warn(&vout->vid_dev->v4l2_dev, - "DMA Channel not allocated for Rotation\n"); - return -EINVAL; - } - - return videobuf_qbuf(q, buffer); -} - -static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; - - if (!vout->streaming) - return -EINVAL; - - if (file->f_flags & O_NONBLOCK) - /* Call videobuf_dqbuf for non blocking mode */ - return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1); - else - /* Call videobuf_dqbuf for blocking mode */ - return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0); -} - -static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) -{ - int ret = 0, j; - u32 addr = 0, mask = 0; - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; - struct omapvideo_info *ovid = &vout->vid_info; - - mutex_lock(&vout->lock); - - if (vout->streaming) { - ret = -EBUSY; - goto streamon_err; - } - - ret = videobuf_streamon(q); - if (ret) - goto streamon_err; - - if (list_empty(&vout->dma_queue)) { - ret = -EIO; - goto streamon_err1; - } - - /* Get the next frame from the buffer queue */ - vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); - /* Remove buffer from the buffer queue */ - list_del(&vout->cur_frm->queue); - /* Mark state of the current frame to active */ - vout->cur_frm->state = VIDEOBUF_ACTIVE; - /* Initialize field_id and started member */ - vout->field_id = 0; - - /* set flag here. Next QBUF will start DMA */ - vout->streaming = 1; - - vout->first_int = 1; - - if (omap_vout_calculate_offset(vout)) { - ret = -EINVAL; - goto streamon_err1; - } - addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i] - + vout->cropped_offset; - - mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD; - - omap_dispc_register_isr(omap_vout_isr, vout, mask); - - for (j = 0; j < ovid->num_overlays; j++) { - struct omap_overlay *ovl = ovid->overlays[j]; - - if (ovl->manager && ovl->manager->device) { - struct omap_overlay_info info; - ovl->get_overlay_info(ovl, &info); - info.enabled = 1; - info.paddr = addr; - if (ovl->set_overlay_info(ovl, &info)) { - ret = -EINVAL; - goto streamon_err1; - } - } - } - - /* First save the configuration in ovelray structure */ - ret = omapvid_init(vout, addr); - if (ret) - v4l2_err(&vout->vid_dev->v4l2_dev, - "failed to set overlay info\n"); - /* Enable the pipeline and set the Go bit */ - ret = omapvid_apply_changes(vout); - if (ret) - v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n"); - - ret = 0; - -streamon_err1: - if (ret) - ret = videobuf_streamoff(q); -streamon_err: - mutex_unlock(&vout->lock); - return ret; -} - -static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) -{ - u32 mask = 0; - int ret = 0, j; - struct omap_vout_device *vout = fh; - struct omapvideo_info *ovid = &vout->vid_info; - - if (!vout->streaming) - return -EINVAL; - - vout->streaming = 0; - mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD; - - omap_dispc_unregister_isr(omap_vout_isr, vout, mask); - - for (j = 0; j < ovid->num_overlays; j++) { - struct omap_overlay *ovl = ovid->overlays[j]; - - if (ovl->manager && ovl->manager->device) { - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - info.enabled = 0; - ret = ovl->set_overlay_info(ovl, &info); - if (ret) - v4l2_err(&vout->vid_dev->v4l2_dev, - "failed to update overlay info in streamoff\n"); - } - } - - /* Turn of the pipeline */ - ret = omapvid_apply_changes(vout); - if (ret) - v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode in" - " streamoff\n"); - - INIT_LIST_HEAD(&vout->dma_queue); - ret = videobuf_streamoff(&vout->vbq); - - return ret; -} - -static int vidioc_s_fbuf(struct file *file, void *fh, - struct v4l2_framebuffer *a) -{ - int enable = 0; - struct omap_overlay *ovl; - struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; - struct omap_overlay_manager_info info; - enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST; - - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - - /* OMAP DSS doesn't support Source and Destination color - key together */ - if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) && - (a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) - return -EINVAL; - /* OMAP DSS Doesn't support the Destination color key - and alpha blending together */ - if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) && - (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)) - return -EINVAL; - - if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) { - vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; - key_type = OMAP_DSS_COLOR_KEY_VID_SRC; - } else - vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY; - - if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) { - vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY; - key_type = OMAP_DSS_COLOR_KEY_GFX_DST; - } else - vout->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY; - - if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY | - V4L2_FBUF_FLAG_SRC_CHROMAKEY)) - enable = 1; - else - enable = 0; - if (ovl->manager && ovl->manager->get_manager_info && - ovl->manager->set_manager_info) { - - ovl->manager->get_manager_info(ovl->manager, &info); - info.trans_enabled = enable; - info.trans_key_type = key_type; - info.trans_key = vout->win.chromakey; - - if (ovl->manager->set_manager_info(ovl->manager, &info)) - return -EINVAL; - } - if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) { - vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; - enable = 1; - } else { - vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA; - enable = 0; - } - if (ovl->manager && ovl->manager->get_manager_info && - ovl->manager->set_manager_info) { - ovl->manager->get_manager_info(ovl->manager, &info); - info.alpha_enabled = enable; - if (ovl->manager->set_manager_info(ovl->manager, &info)) - return -EINVAL; - } - - return 0; -} - -static int vidioc_g_fbuf(struct file *file, void *fh, - struct v4l2_framebuffer *a) -{ - struct omap_overlay *ovl; - struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; - struct omap_overlay_manager_info info; - - ovid = &vout->vid_info; - ovl = ovid->overlays[0]; - - a->flags = 0x0; - a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY - | V4L2_FBUF_CAP_SRC_CHROMAKEY; - - if (ovl->manager && ovl->manager->get_manager_info) { - ovl->manager->get_manager_info(ovl->manager, &info); - if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC) - a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; - if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST) - a->flags |= V4L2_FBUF_FLAG_CHROMAKEY; - } - if (ovl->manager && ovl->manager->get_manager_info) { - ovl->manager->get_manager_info(ovl->manager, &info); - if (info.alpha_enabled) - a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; - } - - return 0; -} - -static const struct v4l2_ioctl_ops vout_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, - .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, - .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, - .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_fbuf = vidioc_s_fbuf, - .vidioc_g_fbuf = vidioc_g_fbuf, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, - .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, - .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, - .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, - .vidioc_cropcap = vidioc_cropcap, - .vidioc_g_crop = vidioc_g_crop, - .vidioc_s_crop = vidioc_s_crop, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, -}; - -static const struct v4l2_file_operations omap_vout_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - .mmap = omap_vout_mmap, - .open = omap_vout_open, - .release = omap_vout_release, -}; - -/* Init functions used during driver initialization */ -/* Initial setup of video_data */ -static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) -{ - struct video_device *vfd; - struct v4l2_pix_format *pix; - struct v4l2_control *control; - struct omap_dss_device *display = - vout->vid_info.overlays[0]->manager->device; - - /* set the default pix */ - pix = &vout->pix; - - /* Set the default picture of QVGA */ - pix->width = QQVGA_WIDTH; - pix->height = QQVGA_HEIGHT; - - /* Default pixel format is RGB 5-6-5 */ - pix->pixelformat = V4L2_PIX_FMT_RGB565; - pix->field = V4L2_FIELD_ANY; - pix->bytesperline = pix->width * 2; - pix->sizeimage = pix->bytesperline * pix->height; - pix->priv = 0; - pix->colorspace = V4L2_COLORSPACE_JPEG; - - vout->bpp = RGB565_BPP; - vout->fbuf.fmt.width = display->panel.timings.x_res; - vout->fbuf.fmt.height = display->panel.timings.y_res; - - /* Set the data structures for the overlay parameters*/ - vout->win.global_alpha = 255; - vout->fbuf.flags = 0; - vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA | - V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY; - vout->win.chromakey = 0; - - omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win); - - /*Initialize the control variables for - rotation, flipping and background color. */ - control = vout->control; - control[0].id = V4L2_CID_ROTATE; - control[0].value = 0; - vout->rotation = 0; - vout->mirror = 0; - vout->control[2].id = V4L2_CID_HFLIP; - vout->control[2].value = 0; - vout->vrfb_bpp = 2; - - control[1].id = V4L2_CID_BG_COLOR; - control[1].value = 0; - - /* initialize the video_device struct */ - vfd = vout->vfd = video_device_alloc(); - - if (!vfd) { - printk(KERN_ERR VOUT_NAME ": could not allocate" - " video device struct\n"); - return -ENOMEM; - } - vfd->release = video_device_release; - vfd->ioctl_ops = &vout_ioctl_ops; - - strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name)); - - vfd->fops = &omap_vout_fops; - vfd->v4l2_dev = &vout->vid_dev->v4l2_dev; - mutex_init(&vout->lock); - - vfd->minor = -1; - return 0; - -} - -/* Setup video buffers */ -static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, - int vid_num) -{ - u32 numbuffers; - int ret = 0, i, j; - int image_width, image_height; - struct video_device *vfd; - struct omap_vout_device *vout; - int static_vrfb_allocation = 0, vrfb_num_bufs = VRFB_NUM_BUFS; - struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); - struct omap2video_device *vid_dev = - container_of(v4l2_dev, struct omap2video_device, v4l2_dev); - - vout = vid_dev->vouts[vid_num]; - vfd = vout->vfd; - - numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers; - vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize; - dev_info(&pdev->dev, "Buffer Size = %d\n", vout->buffer_size); - - for (i = 0; i < numbuffers; i++) { - vout->buf_virt_addr[i] = - omap_vout_alloc_buffer(vout->buffer_size, - (u32 *) &vout->buf_phy_addr[i]); - if (!vout->buf_virt_addr[i]) { - numbuffers = i; - ret = -ENOMEM; - goto free_buffers; - } - } - - for (i = 0; i < VRFB_NUM_BUFS; i++) { - if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) { - dev_info(&pdev->dev, ": VRFB allocation failed\n"); - for (j = 0; j < i; j++) - omap_vrfb_release_ctx(&vout->vrfb_context[j]); - ret = -ENOMEM; - goto free_buffers; - } - } - vout->cropped_offset = 0; - - /* Calculate VRFB memory size */ - /* allocate for worst case size */ - image_width = VID_MAX_WIDTH / TILE_SIZE; - if (VID_MAX_WIDTH % TILE_SIZE) - image_width++; - - image_width = image_width * TILE_SIZE; - image_height = VID_MAX_HEIGHT / TILE_SIZE; - - if (VID_MAX_HEIGHT % TILE_SIZE) - image_height++; - - image_height = image_height * TILE_SIZE; - vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2); - - /* - * Request and Initialize DMA, for DMA based VRFB transfer - */ - vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE; - vout->vrfb_dma_tx.dma_ch = -1; - vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED; - ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX", - omap_vout_vrfb_dma_tx_callback, - (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch); - if (ret < 0) { - vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; - dev_info(&pdev->dev, ": failed to allocate DMA Channel for" - " video%d\n", vfd->minor); - } - init_waitqueue_head(&vout->vrfb_dma_tx.wait); - - /* Allocate VRFB buffers if selected through bootargs */ - static_vrfb_allocation = (vid_num == 0) ? - vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; - - /* statically allocated the VRFB buffer is done through - commands line aruments */ - if (static_vrfb_allocation) { - if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) { - ret = -ENOMEM; - goto release_vrfb_ctx; - } - vout->vrfb_static_allocation = 1; - } - return 0; - -release_vrfb_ctx: - for (j = 0; j < VRFB_NUM_BUFS; j++) - omap_vrfb_release_ctx(&vout->vrfb_context[j]); - -free_buffers: - for (i = 0; i < numbuffers; i++) { - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - vout->buf_virt_addr[i] = 0; - vout->buf_phy_addr[i] = 0; - } - return ret; - -} - -/* Create video out devices */ -static int __init omap_vout_create_video_devices(struct platform_device *pdev) -{ - int ret = 0, k; - struct omap_vout_device *vout; - struct video_device *vfd = NULL; - struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); - struct omap2video_device *vid_dev = container_of(v4l2_dev, - struct omap2video_device, v4l2_dev); - - for (k = 0; k < pdev->num_resources; k++) { - - vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL); - if (!vout) { - dev_err(&pdev->dev, ": could not allocate memory\n"); - return -ENOMEM; - } - - vout->vid = k; - vid_dev->vouts[k] = vout; - vout->vid_dev = vid_dev; - /* Select video2 if only 1 overlay is controlled by V4L2 */ - if (pdev->num_resources == 1) - vout->vid_info.overlays[0] = vid_dev->overlays[k + 2]; - else - /* Else select video1 and video2 one by one. */ - vout->vid_info.overlays[0] = vid_dev->overlays[k + 1]; - vout->vid_info.num_overlays = 1; - vout->vid_info.id = k + 1; - - /* Setup the default configuration for the video devices - */ - if (omap_vout_setup_video_data(vout) != 0) { - ret = -ENOMEM; - goto error; - } - - /* Allocate default number of buffers for the video streaming - * and reserve the VRFB space for rotation - */ - if (omap_vout_setup_video_bufs(pdev, k) != 0) { - ret = -ENOMEM; - goto error1; - } - - /* Register the Video device with V4L2 - */ - vfd = vout->vfd; - if (video_register_device(vfd, VFL_TYPE_GRABBER, k + 1) < 0) { - dev_err(&pdev->dev, ": Could not register " - "Video for Linux device\n"); - vfd->minor = -1; - ret = -ENODEV; - goto error2; - } - video_set_drvdata(vfd, vout); - - /* Configure the overlay structure */ - ret = omapvid_init(vid_dev->vouts[k], 0); - if (!ret) - goto success; - -error2: - omap_vout_release_vrfb(vout); - omap_vout_free_buffers(vout); -error1: - video_device_release(vfd); -error: - kfree(vout); - return ret; - -success: - dev_info(&pdev->dev, ": registered and initialized" - " video device %d\n", vfd->minor); - if (k == (pdev->num_resources - 1)) - return 0; - } - - return -ENODEV; -} -/* Driver functions */ -static void omap_vout_cleanup_device(struct omap_vout_device *vout) -{ - struct video_device *vfd; - - if (!vout) - return; - - vfd = vout->vfd; - if (vfd) { - if (!video_is_registered(vfd)) { - /* - * The device was never registered, so release the - * video_device struct directly. - */ - video_device_release(vfd); - } else { - /* - * The unregister function will release the video_device - * struct as well as unregistering it. - */ - video_unregister_device(vfd); - } - } - - omap_vout_release_vrfb(vout); - omap_vout_free_buffers(vout); - /* Free the VRFB buffer if allocated - * init time - */ - if (vout->vrfb_static_allocation) - omap_vout_free_vrfb_buffers(vout); - - kfree(vout); -} - -static int omap_vout_remove(struct platform_device *pdev) -{ - int k; - struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); - struct omap2video_device *vid_dev = container_of(v4l2_dev, struct - omap2video_device, v4l2_dev); - - v4l2_device_unregister(v4l2_dev); - for (k = 0; k < pdev->num_resources; k++) - omap_vout_cleanup_device(vid_dev->vouts[k]); - - for (k = 0; k < vid_dev->num_displays; k++) { - if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED) - vid_dev->displays[k]->driver->disable(vid_dev->displays[k]); - - omap_dss_put_device(vid_dev->displays[k]); - } - kfree(vid_dev); - return 0; -} - -static int __init omap_vout_probe(struct platform_device *pdev) -{ - int ret = 0, i; - struct omap_overlay *ovl; - struct omap_dss_device *dssdev = NULL; - struct omap_dss_device *def_display; - struct omap2video_device *vid_dev = NULL; - - if (pdev->num_resources == 0) { - dev_err(&pdev->dev, "probed for an unknown device\n"); - return -ENODEV; - } - - vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL); - if (vid_dev == NULL) - return -ENOMEM; - - vid_dev->num_displays = 0; - for_each_dss_dev(dssdev) { - omap_dss_get_device(dssdev); - vid_dev->displays[vid_dev->num_displays++] = dssdev; - } - - if (vid_dev->num_displays == 0) { - dev_err(&pdev->dev, "no displays\n"); - ret = -EINVAL; - goto probe_err0; - } - - vid_dev->num_overlays = omap_dss_get_num_overlays(); - for (i = 0; i < vid_dev->num_overlays; i++) - vid_dev->overlays[i] = omap_dss_get_overlay(i); - - vid_dev->num_managers = omap_dss_get_num_overlay_managers(); - for (i = 0; i < vid_dev->num_managers; i++) - vid_dev->managers[i] = omap_dss_get_overlay_manager(i); - - /* Get the Video1 overlay and video2 overlay. - * Setup the Display attached to that overlays - */ - for (i = 1; i < vid_dev->num_overlays; i++) { - ovl = omap_dss_get_overlay(i); - if (ovl->manager && ovl->manager->device) { - def_display = ovl->manager->device; - } else { - dev_warn(&pdev->dev, "cannot find display\n"); - def_display = NULL; - } - if (def_display) { - struct omap_dss_driver *dssdrv = def_display->driver; - - ret = dssdrv->enable(def_display); - if (ret) { - /* Here we are not considering a error - * as display may be enabled by frame - * buffer driver - */ - dev_warn(&pdev->dev, - "'%s' Display already enabled\n", - def_display->name); - } - /* set the update mode */ - if (def_display->caps & - OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { - if (dssdrv->enable_te) - dssdrv->enable_te(def_display, 0); - if (dssdrv->set_update_mode) - dssdrv->set_update_mode(def_display, - OMAP_DSS_UPDATE_MANUAL); - } else { - if (dssdrv->set_update_mode) - dssdrv->set_update_mode(def_display, - OMAP_DSS_UPDATE_AUTO); - } - } - } - - if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) { - dev_err(&pdev->dev, "v4l2_device_register failed\n"); - ret = -ENODEV; - goto probe_err1; - } - - ret = omap_vout_create_video_devices(pdev); - if (ret) - goto probe_err2; - - for (i = 0; i < vid_dev->num_displays; i++) { - struct omap_dss_device *display = vid_dev->displays[i]; - - if (display->driver->update) - display->driver->update(display, 0, 0, - display->panel.timings.x_res, - display->panel.timings.y_res); - } - return 0; - -probe_err2: - v4l2_device_unregister(&vid_dev->v4l2_dev); -probe_err1: - for (i = 1; i < vid_dev->num_overlays; i++) { - def_display = NULL; - ovl = omap_dss_get_overlay(i); - if (ovl->manager && ovl->manager->device) - def_display = ovl->manager->device; - - if (def_display && def_display->driver) - def_display->driver->disable(def_display); - } -probe_err0: - kfree(vid_dev); - return ret; -} - -static struct platform_driver omap_vout_driver = { - .driver = { - .name = VOUT_NAME, - }, - .probe = omap_vout_probe, - .remove = omap_vout_remove, -}; - -static int __init omap_vout_init(void) -{ - if (platform_driver_register(&omap_vout_driver) != 0) { - printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n"); - return -EINVAL; - } - return 0; -} - -static void omap_vout_cleanup(void) -{ - platform_driver_unregister(&omap_vout_driver); -} - -late_initcall(omap_vout_init); -module_exit(omap_vout_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutdef.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutdef.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutdef.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutdef.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -/* - * omap_voutdef.h - * - * Copyright (C) 2010 Texas Instruments. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#ifndef OMAP_VOUTDEF_H -#define OMAP_VOUTDEF_H - -#include - -#define YUYV_BPP 2 -#define RGB565_BPP 2 -#define RGB24_BPP 3 -#define RGB32_BPP 4 -#define TILE_SIZE 32 -#define YUYV_VRFB_BPP 2 -#define RGB_VRFB_BPP 1 -#define MAX_CID 3 -#define MAC_VRFB_CTXS 4 -#define MAX_VOUT_DEV 2 -#define MAX_OVLS 3 -#define MAX_DISPLAYS 3 -#define MAX_MANAGERS 3 - -/* Enum for Rotation - * DSS understands rotation in 0, 1, 2, 3 context - * while V4L2 driver understands it as 0, 90, 180, 270 - */ -enum dss_rotation { - dss_rotation_0_degree = 0, - dss_rotation_90_degree = 1, - dss_rotation_180_degree = 2, - dss_rotation_270_degree = 3, -}; -/* - * This structure is used to store the DMA transfer parameters - * for VRFB hidden buffer - */ -struct vid_vrfb_dma { - int dev_id; - int dma_ch; - int req_status; - int tx_status; - wait_queue_head_t wait; -}; - -struct omapvideo_info { - int id; - int num_overlays; - struct omap_overlay *overlays[MAX_OVLS]; -}; - -struct omap2video_device { - struct mutex mtx; - - int state; - - struct v4l2_device v4l2_dev; - struct omap_vout_device *vouts[MAX_VOUT_DEV]; - - int num_displays; - struct omap_dss_device *displays[MAX_DISPLAYS]; - int num_overlays; - struct omap_overlay *overlays[MAX_OVLS]; - int num_managers; - struct omap_overlay_manager *managers[MAX_MANAGERS]; -}; - -/* per-device data structure */ -struct omap_vout_device { - - struct omapvideo_info vid_info; - struct video_device *vfd; - struct omap2video_device *vid_dev; - int vid; - int opened; - - /* we don't allow to change image fmt/size once buffer has - * been allocated - */ - int buffer_allocated; - /* allow to reuse previously allocated buffer which is big enough */ - int buffer_size; - /* keep buffer info across opens */ - unsigned long buf_virt_addr[VIDEO_MAX_FRAME]; - unsigned long buf_phy_addr[VIDEO_MAX_FRAME]; - enum omap_color_mode dss_mode; - - /* we don't allow to request new buffer when old buffers are - * still mmaped - */ - int mmap_count; - - spinlock_t vbq_lock; /* spinlock for videobuf queues */ - unsigned long field_count; /* field counter for videobuf_buffer */ - - /* non-NULL means streaming is in progress. */ - bool streaming; - - struct v4l2_pix_format pix; - struct v4l2_rect crop; - struct v4l2_window win; - struct v4l2_framebuffer fbuf; - - /* Lock to protect the shared data structures in ioctl */ - struct mutex lock; - - /* V4L2 control structure for different control id */ - struct v4l2_control control[MAX_CID]; - enum dss_rotation rotation; - bool mirror; - int flicker_filter; - /* V4L2 control structure for different control id */ - - int bpp; /* bytes per pixel */ - int vrfb_bpp; /* bytes per pixel with respect to VRFB */ - - struct vid_vrfb_dma vrfb_dma_tx; - unsigned int smsshado_phy_addr[MAC_VRFB_CTXS]; - unsigned int smsshado_virt_addr[MAC_VRFB_CTXS]; - struct vrfb vrfb_context[MAC_VRFB_CTXS]; - bool vrfb_static_allocation; - unsigned int smsshado_size; - unsigned char pos; - - int ps, vr_ps, line_length, first_int, field_id; - enum v4l2_memory memory; - struct videobuf_buffer *cur_frm, *next_frm; - struct list_head dma_queue; - u8 *queued_buf_addr[VIDEO_MAX_FRAME]; - u32 cropped_offset; - s32 tv_field1_offset; - void *isr_handle; - - /* Buffer queue variables */ - struct omap_vout_device *vout; - enum v4l2_buf_type type; - struct videobuf_queue vbq; - int io_allowed; - -}; -#endif /* ifndef OMAP_VOUTDEF_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutlib.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutlib.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutlib.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutlib.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,293 +0,0 @@ -/* - * omap_voutlib.c - * - * Copyright (C) 2005-2010 Texas Instruments. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - * Based on the OMAP2 camera driver - * Video-for-Linux (Version 2) camera capture driver for - * the OMAP24xx camera controller. - * - * Author: Andy Lowe (source@mvista.com) - * - * Copyright (C) 2004 MontaVista Software, Inc. - * Copyright (C) 2010 Texas Instruments. - * - */ - -#include -#include -#include -#include -#include - -#include - -MODULE_AUTHOR("Texas Instruments"); -MODULE_DESCRIPTION("OMAP Video library"); -MODULE_LICENSE("GPL"); - -/* Return the default overlay cropping rectangle in crop given the image - * size in pix and the video display size in fbuf. The default - * cropping rectangle is the largest rectangle no larger than the capture size - * that will fit on the display. The default cropping rectangle is centered in - * the image. All dimensions and offsets are rounded down to even numbers. - */ -void omap_vout_default_crop(struct v4l2_pix_format *pix, - struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop) -{ - crop->width = (pix->width < fbuf->fmt.width) ? - pix->width : fbuf->fmt.width; - crop->height = (pix->height < fbuf->fmt.height) ? - pix->height : fbuf->fmt.height; - crop->width &= ~1; - crop->height &= ~1; - crop->left = ((pix->width - crop->width) >> 1) & ~1; - crop->top = ((pix->height - crop->height) >> 1) & ~1; -} -EXPORT_SYMBOL_GPL(omap_vout_default_crop); - -/* Given a new render window in new_win, adjust the window to the - * nearest supported configuration. The adjusted window parameters are - * returned in new_win. - * Returns zero if succesful, or -EINVAL if the requested window is - * impossible and cannot reasonably be adjusted. - */ -int omap_vout_try_window(struct v4l2_framebuffer *fbuf, - struct v4l2_window *new_win) -{ - struct v4l2_rect try_win; - - /* make a working copy of the new_win rectangle */ - try_win = new_win->w; - - /* adjust the preview window so it fits on the display by clipping any - * offscreen areas - */ - if (try_win.left < 0) { - try_win.width += try_win.left; - try_win.left = 0; - } - if (try_win.top < 0) { - try_win.height += try_win.top; - try_win.top = 0; - } - try_win.width = (try_win.width < fbuf->fmt.width) ? - try_win.width : fbuf->fmt.width; - try_win.height = (try_win.height < fbuf->fmt.height) ? - try_win.height : fbuf->fmt.height; - if (try_win.left + try_win.width > fbuf->fmt.width) - try_win.width = fbuf->fmt.width - try_win.left; - if (try_win.top + try_win.height > fbuf->fmt.height) - try_win.height = fbuf->fmt.height - try_win.top; - try_win.width &= ~1; - try_win.height &= ~1; - - if (try_win.width <= 0 || try_win.height <= 0) - return -EINVAL; - - /* We now have a valid preview window, so go with it */ - new_win->w = try_win; - new_win->field = V4L2_FIELD_ANY; - return 0; -} -EXPORT_SYMBOL_GPL(omap_vout_try_window); - -/* Given a new render window in new_win, adjust the window to the - * nearest supported configuration. The image cropping window in crop - * will also be adjusted if necessary. Preference is given to keeping the - * the window as close to the requested configuration as possible. If - * successful, new_win, vout->win, and crop are updated. - * Returns zero if succesful, or -EINVAL if the requested preview window is - * impossible and cannot reasonably be adjusted. - */ -int omap_vout_new_window(struct v4l2_rect *crop, - struct v4l2_window *win, struct v4l2_framebuffer *fbuf, - struct v4l2_window *new_win) -{ - int err; - - err = omap_vout_try_window(fbuf, new_win); - if (err) - return err; - - /* update our preview window */ - win->w = new_win->w; - win->field = new_win->field; - win->chromakey = new_win->chromakey; - - /* Adjust the cropping window to allow for resizing limitation */ - if (cpu_is_omap24xx()) { - /* For 24xx limit is 8x to 1/2x scaling. */ - if ((crop->height/win->w.height) >= 2) - crop->height = win->w.height * 2; - - if ((crop->width/win->w.width) >= 2) - crop->width = win->w.width * 2; - - if (crop->width > 768) { - /* The OMAP2420 vertical resizing line buffer is 768 - * pixels wide. If the cropped image is wider than - * 768 pixels then it cannot be vertically resized. - */ - if (crop->height != win->w.height) - crop->width = 768; - } - } else if (cpu_is_omap34xx()) { - /* For 34xx limit is 8x to 1/4x scaling. */ - if ((crop->height/win->w.height) >= 4) - crop->height = win->w.height * 4; - - if ((crop->width/win->w.width) >= 4) - crop->width = win->w.width * 4; - } - return 0; -} -EXPORT_SYMBOL_GPL(omap_vout_new_window); - -/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to - * the nearest supported configuration. The image render window in win will - * also be adjusted if necessary. The preview window is adjusted such that the - * horizontal and vertical rescaling ratios stay constant. If the render - * window would fall outside the display boundaries, the cropping rectangle - * will also be adjusted to maintain the rescaling ratios. If successful, crop - * and win are updated. - * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is - * impossible and cannot reasonably be adjusted. - */ -int omap_vout_new_crop(struct v4l2_pix_format *pix, - struct v4l2_rect *crop, struct v4l2_window *win, - struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop) -{ - struct v4l2_rect try_crop; - unsigned long vresize, hresize; - - /* make a working copy of the new_crop rectangle */ - try_crop = *new_crop; - - /* adjust the cropping rectangle so it fits in the image */ - if (try_crop.left < 0) { - try_crop.width += try_crop.left; - try_crop.left = 0; - } - if (try_crop.top < 0) { - try_crop.height += try_crop.top; - try_crop.top = 0; - } - try_crop.width = (try_crop.width < pix->width) ? - try_crop.width : pix->width; - try_crop.height = (try_crop.height < pix->height) ? - try_crop.height : pix->height; - if (try_crop.left + try_crop.width > pix->width) - try_crop.width = pix->width - try_crop.left; - if (try_crop.top + try_crop.height > pix->height) - try_crop.height = pix->height - try_crop.top; - - try_crop.width &= ~1; - try_crop.height &= ~1; - - if (try_crop.width <= 0 || try_crop.height <= 0) - return -EINVAL; - - if (cpu_is_omap24xx()) { - if (crop->height != win->w.height) { - /* If we're resizing vertically, we can't support a - * crop width wider than 768 pixels. - */ - if (try_crop.width > 768) - try_crop.width = 768; - } - } - /* vertical resizing */ - vresize = (1024 * crop->height) / win->w.height; - if (cpu_is_omap24xx() && (vresize > 2048)) - vresize = 2048; - else if (cpu_is_omap34xx() && (vresize > 4096)) - vresize = 4096; - - win->w.height = ((1024 * try_crop.height) / vresize) & ~1; - if (win->w.height == 0) - win->w.height = 2; - if (win->w.height + win->w.top > fbuf->fmt.height) { - /* We made the preview window extend below the bottom of the - * display, so clip it to the display boundary and resize the - * cropping height to maintain the vertical resizing ratio. - */ - win->w.height = (fbuf->fmt.height - win->w.top) & ~1; - if (try_crop.height == 0) - try_crop.height = 2; - } - /* horizontal resizing */ - hresize = (1024 * crop->width) / win->w.width; - if (cpu_is_omap24xx() && (hresize > 2048)) - hresize = 2048; - else if (cpu_is_omap34xx() && (hresize > 4096)) - hresize = 4096; - - win->w.width = ((1024 * try_crop.width) / hresize) & ~1; - if (win->w.width == 0) - win->w.width = 2; - if (win->w.width + win->w.left > fbuf->fmt.width) { - /* We made the preview window extend past the right side of the - * display, so clip it to the display boundary and resize the - * cropping width to maintain the horizontal resizing ratio. - */ - win->w.width = (fbuf->fmt.width - win->w.left) & ~1; - if (try_crop.width == 0) - try_crop.width = 2; - } - if (cpu_is_omap24xx()) { - if ((try_crop.height/win->w.height) >= 2) - try_crop.height = win->w.height * 2; - - if ((try_crop.width/win->w.width) >= 2) - try_crop.width = win->w.width * 2; - - if (try_crop.width > 768) { - /* The OMAP2420 vertical resizing line buffer is - * 768 pixels wide. If the cropped image is wider - * than 768 pixels then it cannot be vertically resized. - */ - if (try_crop.height != win->w.height) - try_crop.width = 768; - } - } else if (cpu_is_omap34xx()) { - if ((try_crop.height/win->w.height) >= 4) - try_crop.height = win->w.height * 4; - - if ((try_crop.width/win->w.width) >= 4) - try_crop.width = win->w.width * 4; - } - /* update our cropping rectangle and we're done */ - *crop = try_crop; - return 0; -} -EXPORT_SYMBOL_GPL(omap_vout_new_crop); - -/* Given a new format in pix and fbuf, crop and win - * structures are initialized to default values. crop - * is initialized to the largest window size that will fit on the display. The - * crop window is centered in the image. win is initialized to - * the same size as crop and is centered on the display. - * All sizes and offsets are constrained to be even numbers. - */ -void omap_vout_new_format(struct v4l2_pix_format *pix, - struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop, - struct v4l2_window *win) -{ - /* crop defines the preview source window in the image capture - * buffer - */ - omap_vout_default_crop(pix, fbuf, crop); - - /* win defines the preview target window on the display */ - win->w.width = crop->width; - win->w.height = crop->height; - win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1; - win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1; -} -EXPORT_SYMBOL_GPL(omap_vout_new_format); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutlib.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutlib.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutlib.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap/omap_voutlib.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - * omap_voutlib.h - * - * Copyright (C) 2010 Texas Instruments. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - */ - -#ifndef OMAP_VOUTLIB_H -#define OMAP_VOUTLIB_H - -extern void omap_vout_default_crop(struct v4l2_pix_format *pix, - struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop); - -extern int omap_vout_new_crop(struct v4l2_pix_format *pix, - struct v4l2_rect *crop, struct v4l2_window *win, - struct v4l2_framebuffer *fbuf, - const struct v4l2_rect *new_crop); - -extern int omap_vout_try_window(struct v4l2_framebuffer *fbuf, - struct v4l2_window *new_win); - -extern int omap_vout_new_window(struct v4l2_rect *crop, - struct v4l2_window *win, struct v4l2_framebuffer *fbuf, - struct v4l2_window *new_win); - -extern void omap_vout_new_format(struct v4l2_pix_format *pix, - struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop, - struct v4l2_window *win); -#endif /* #ifndef OMAP_VOUTLIB_H */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap1_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap1_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap1_camera.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap1_camera.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1702 +0,0 @@ -/* - * V4L2 SoC Camera driver for OMAP1 Camera Interface - * - * Copyright (C) 2010, Janusz Krzysztofik - * - * Based on V4L2 Driver for i.MXL/i.MXL camera (CSI) host - * Copyright (C) 2008, Paulius Zaleckas - * Copyright (C) 2009, Darius Augulis - * - * Based on PXA SoC camera driver - * Copyright (C) 2006, Sascha Hauer, Pengutronix - * Copyright (C) 2008, Guennadi Liakhovetski - * - * Hardware specific bits initialy based on former work by Matt Callow - * drivers/media/video/omap/omap1510cam.c - * Copyright (C) 2006 Matt Callow - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - - -#define DRIVER_NAME "omap1-camera" -#define VERSION_CODE KERNEL_VERSION(0, 0, 1) - - -/* - * --------------------------------------------------------------------------- - * OMAP1 Camera Interface registers - * --------------------------------------------------------------------------- - */ - -#define REG_CTRLCLOCK 0x00 -#define REG_IT_STATUS 0x04 -#define REG_MODE 0x08 -#define REG_STATUS 0x0C -#define REG_CAMDATA 0x10 -#define REG_GPIO 0x14 -#define REG_PEAK_COUNTER 0x18 - -/* CTRLCLOCK bit shifts */ -#define LCLK_EN BIT(7) -#define DPLL_EN BIT(6) -#define MCLK_EN BIT(5) -#define CAMEXCLK_EN BIT(4) -#define POLCLK BIT(3) -#define FOSCMOD_SHIFT 0 -#define FOSCMOD_MASK (0x7 << FOSCMOD_SHIFT) -#define FOSCMOD_12MHz 0x0 -#define FOSCMOD_6MHz 0x2 -#define FOSCMOD_9_6MHz 0x4 -#define FOSCMOD_24MHz 0x5 -#define FOSCMOD_8MHz 0x6 - -/* IT_STATUS bit shifts */ -#define DATA_TRANSFER BIT(5) -#define FIFO_FULL BIT(4) -#define H_DOWN BIT(3) -#define H_UP BIT(2) -#define V_DOWN BIT(1) -#define V_UP BIT(0) - -/* MODE bit shifts */ -#define RAZ_FIFO BIT(18) -#define EN_FIFO_FULL BIT(17) -#define EN_NIRQ BIT(16) -#define THRESHOLD_SHIFT 9 -#define THRESHOLD_MASK (0x7f << THRESHOLD_SHIFT) -#define DMA BIT(8) -#define EN_H_DOWN BIT(7) -#define EN_H_UP BIT(6) -#define EN_V_DOWN BIT(5) -#define EN_V_UP BIT(4) -#define ORDERCAMD BIT(3) - -#define IRQ_MASK (EN_V_UP | EN_V_DOWN | EN_H_UP | EN_H_DOWN | \ - EN_NIRQ | EN_FIFO_FULL) - -/* STATUS bit shifts */ -#define HSTATUS BIT(1) -#define VSTATUS BIT(0) - -/* GPIO bit shifts */ -#define CAM_RST BIT(0) - -/* end of OMAP1 Camera Interface registers */ - - -#define SOCAM_BUS_FLAGS (SOCAM_MASTER | \ - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | \ - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8) - - -#define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1) -#define FIFO_SHIFT __fls(FIFO_SIZE) - -#define DMA_BURST_SHIFT (1 + OMAP_DMA_DATA_BURST_4) -#define DMA_BURST_SIZE (1 << DMA_BURST_SHIFT) - -#define DMA_ELEMENT_SHIFT OMAP_DMA_DATA_TYPE_S32 -#define DMA_ELEMENT_SIZE (1 << DMA_ELEMENT_SHIFT) - -#define DMA_FRAME_SHIFT_CONTIG (FIFO_SHIFT - 1) -#define DMA_FRAME_SHIFT_SG DMA_BURST_SHIFT - -#define DMA_FRAME_SHIFT(x) ((x) == OMAP1_CAM_DMA_CONTIG ? \ - DMA_FRAME_SHIFT_CONTIG : \ - DMA_FRAME_SHIFT_SG) -#define DMA_FRAME_SIZE(x) (1 << DMA_FRAME_SHIFT(x)) -#define DMA_SYNC OMAP_DMA_SYNC_FRAME -#define THRESHOLD_LEVEL DMA_FRAME_SIZE - - -#define MAX_VIDEO_MEM 4 /* arbitrary video memory limit in MB */ - - -/* - * Structures - */ - -/* buffer for one video frame */ -struct omap1_cam_buf { - struct videobuf_buffer vb; - enum v4l2_mbus_pixelcode code; - int inwork; - struct scatterlist *sgbuf; - int sgcount; - int bytes_left; - enum videobuf_state result; -}; - -struct omap1_cam_dev { - struct soc_camera_host soc_host; - struct soc_camera_device *icd; - struct clk *clk; - - unsigned int irq; - void __iomem *base; - - int dma_ch; - - struct omap1_cam_platform_data *pdata; - struct resource *res; - unsigned long pflags; - unsigned long camexclk; - - struct list_head capture; - - /* lock used to protect videobuf */ - spinlock_t lock; - - /* Pointers to DMA buffers */ - struct omap1_cam_buf *active; - struct omap1_cam_buf *ready; - - enum omap1_cam_vb_mode vb_mode; - int (*mmap_mapper)(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma); - - u32 reg_cache[0]; -}; - - -static void cam_write(struct omap1_cam_dev *pcdev, u16 reg, u32 val) -{ - pcdev->reg_cache[reg / sizeof(u32)] = val; - __raw_writel(val, pcdev->base + reg); -} - -static u32 cam_read(struct omap1_cam_dev *pcdev, u16 reg, bool from_cache) -{ - return !from_cache ? __raw_readl(pcdev->base + reg) : - pcdev->reg_cache[reg / sizeof(u32)]; -} - -#define CAM_READ(pcdev, reg) \ - cam_read(pcdev, REG_##reg, false) -#define CAM_WRITE(pcdev, reg, val) \ - cam_write(pcdev, REG_##reg, val) -#define CAM_READ_CACHE(pcdev, reg) \ - cam_read(pcdev, REG_##reg, true) - -/* - * Videobuf operations - */ -static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct soc_camera_device *icd = vq->priv_data; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - - if (bytes_per_line < 0) - return bytes_per_line; - - *size = bytes_per_line * icd->user_height; - - if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode)) - *count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode); - - if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) - *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; - - dev_dbg(icd->dev.parent, - "%s: count=%d, size=%d\n", __func__, *count, *size); - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf, - enum omap1_cam_vb_mode vb_mode) -{ - struct videobuf_buffer *vb = &buf->vb; - - BUG_ON(in_interrupt()); - - videobuf_waiton(vq, vb, 0, 0); - - if (vb_mode == OMAP1_CAM_DMA_CONTIG) { - videobuf_dma_contig_free(vq, vb); - } else { - struct soc_camera_device *icd = vq->priv_data; - struct device *dev = icd->dev.parent; - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - - videobuf_dma_unmap(dev, dma); - videobuf_dma_free(dma); - } - - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static int omap1_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct soc_camera_device *icd = vq->priv_data; - struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb); - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - int ret; - - if (bytes_per_line < 0) - return bytes_per_line; - - WARN_ON(!list_empty(&vb->queue)); - - BUG_ON(NULL == icd->current_fmt); - - buf->inwork = 1; - - if (buf->code != icd->current_fmt->code || vb->field != field || - vb->width != icd->user_width || - vb->height != icd->user_height) { - buf->code = icd->current_fmt->code; - vb->width = icd->user_width; - vb->height = icd->user_height; - vb->field = field; - vb->state = VIDEOBUF_NEEDS_INIT; - } - - vb->size = bytes_per_line * vb->height; - - if (vb->baddr && vb->bsize < vb->size) { - ret = -EINVAL; - goto out; - } - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret) - goto fail; - - vb->state = VIDEOBUF_PREPARED; - } - buf->inwork = 0; - - return 0; -fail: - free_buffer(vq, buf, pcdev->vb_mode); -out: - buf->inwork = 0; - return ret; -} - -static void set_dma_dest_params(int dma_ch, struct omap1_cam_buf *buf, - enum omap1_cam_vb_mode vb_mode) -{ - dma_addr_t dma_addr; - unsigned int block_size; - - if (vb_mode == OMAP1_CAM_DMA_CONTIG) { - dma_addr = videobuf_to_dma_contig(&buf->vb); - block_size = buf->vb.size; - } else { - if (WARN_ON(!buf->sgbuf)) { - buf->result = VIDEOBUF_ERROR; - return; - } - dma_addr = sg_dma_address(buf->sgbuf); - if (WARN_ON(!dma_addr)) { - buf->sgbuf = NULL; - buf->result = VIDEOBUF_ERROR; - return; - } - block_size = sg_dma_len(buf->sgbuf); - if (WARN_ON(!block_size)) { - buf->sgbuf = NULL; - buf->result = VIDEOBUF_ERROR; - return; - } - if (unlikely(buf->bytes_left < block_size)) - block_size = buf->bytes_left; - if (WARN_ON(dma_addr & (DMA_FRAME_SIZE(vb_mode) * - DMA_ELEMENT_SIZE - 1))) { - dma_addr = ALIGN(dma_addr, DMA_FRAME_SIZE(vb_mode) * - DMA_ELEMENT_SIZE); - block_size &= ~(DMA_FRAME_SIZE(vb_mode) * - DMA_ELEMENT_SIZE - 1); - } - buf->bytes_left -= block_size; - buf->sgcount++; - } - - omap_set_dma_dest_params(dma_ch, - OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0); - omap_set_dma_transfer_params(dma_ch, - OMAP_DMA_DATA_TYPE_S32, DMA_FRAME_SIZE(vb_mode), - block_size >> (DMA_FRAME_SHIFT(vb_mode) + DMA_ELEMENT_SHIFT), - DMA_SYNC, 0, 0); -} - -static struct omap1_cam_buf *prepare_next_vb(struct omap1_cam_dev *pcdev) -{ - struct omap1_cam_buf *buf; - - /* - * If there is already a buffer pointed out by the pcdev->ready, - * (re)use it, otherwise try to fetch and configure a new one. - */ - buf = pcdev->ready; - if (!buf) { - if (list_empty(&pcdev->capture)) - return buf; - buf = list_entry(pcdev->capture.next, - struct omap1_cam_buf, vb.queue); - buf->vb.state = VIDEOBUF_ACTIVE; - pcdev->ready = buf; - list_del_init(&buf->vb.queue); - } - - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, we can safely enter next buffer parameters - * into the DMA programming register set after the DMA - * has already been activated on the previous buffer - */ - set_dma_dest_params(pcdev->dma_ch, buf, pcdev->vb_mode); - } else { - /* - * In SG mode, the above is not safe since there are probably - * a bunch of sgbufs from previous sglist still pending. - * Instead, mark the sglist fresh for the upcoming - * try_next_sgbuf(). - */ - buf->sgbuf = NULL; - } - - return buf; -} - -static struct scatterlist *try_next_sgbuf(int dma_ch, struct omap1_cam_buf *buf) -{ - struct scatterlist *sgbuf; - - if (likely(buf->sgbuf)) { - /* current sglist is active */ - if (unlikely(!buf->bytes_left)) { - /* indicate sglist complete */ - sgbuf = NULL; - } else { - /* process next sgbuf */ - sgbuf = sg_next(buf->sgbuf); - if (WARN_ON(!sgbuf)) { - buf->result = VIDEOBUF_ERROR; - } else if (WARN_ON(!sg_dma_len(sgbuf))) { - sgbuf = NULL; - buf->result = VIDEOBUF_ERROR; - } - } - buf->sgbuf = sgbuf; - } else { - /* sglist is fresh, initialize it before using */ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - - sgbuf = dma->sglist; - if (!(WARN_ON(!sgbuf))) { - buf->sgbuf = sgbuf; - buf->sgcount = 0; - buf->bytes_left = buf->vb.size; - buf->result = VIDEOBUF_DONE; - } - } - if (sgbuf) - /* - * Put our next sgbuf parameters (address, size) - * into the DMA programming register set. - */ - set_dma_dest_params(dma_ch, buf, OMAP1_CAM_DMA_SG); - - return sgbuf; -} - -static void start_capture(struct omap1_cam_dev *pcdev) -{ - struct omap1_cam_buf *buf = pcdev->active; - u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); - u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN; - - if (WARN_ON(!buf)) - return; - - /* - * Enable start of frame interrupt, which we will use for activating - * our end of frame watchdog when capture actually starts. - */ - mode |= EN_V_UP; - - if (unlikely(ctrlclock & LCLK_EN)) - /* stop pixel clock before FIFO reset */ - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); - /* reset FIFO */ - CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO); - - omap_start_dma(pcdev->dma_ch); - - if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { - /* - * In SG mode, it's a good moment for fetching next sgbuf - * from the current sglist and, if available, already putting - * its parameters into the DMA programming register set. - */ - try_next_sgbuf(pcdev->dma_ch, buf); - } - - /* (re)enable pixel clock */ - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN); - /* release FIFO reset */ - CAM_WRITE(pcdev, MODE, mode); -} - -static void suspend_capture(struct omap1_cam_dev *pcdev) -{ - u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); - - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); - omap_stop_dma(pcdev->dma_ch); -} - -static void disable_capture(struct omap1_cam_dev *pcdev) -{ - u32 mode = CAM_READ_CACHE(pcdev, MODE); - - CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA)); -} - -static void omap1_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - struct omap1_cam_buf *buf; - u32 mode; - - list_add_tail(&vb->queue, &pcdev->capture); - vb->state = VIDEOBUF_QUEUED; - - if (pcdev->active) { - /* - * Capture in progress, so don't touch pcdev->ready even if - * empty. Since the transfer of the DMA programming register set - * content to the DMA working register set is done automatically - * by the DMA hardware, this can pretty well happen while we - * are keeping the lock here. Leave fetching it from the queue - * to be done when a next DMA interrupt occures instead. - */ - return; - } - - WARN_ON(pcdev->ready); - - buf = prepare_next_vb(pcdev); - if (WARN_ON(!buf)) - return; - - pcdev->active = buf; - pcdev->ready = NULL; - - dev_dbg(icd->dev.parent, - "%s: capture not active, setup FIFO, start DMA\n", __func__); - mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK; - mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT; - CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA); - - if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { - /* - * In SG mode, the above prepare_next_vb() didn't actually - * put anything into the DMA programming register set, - * so we have to do it now, before activating DMA. - */ - try_next_sgbuf(pcdev->dma_ch, buf); - } - - start_capture(pcdev); -} - -static void omap1_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct omap1_cam_buf *buf = - container_of(vb, struct omap1_cam_buf, vb); - struct soc_camera_device *icd = vq->priv_data; - struct device *dev = icd->dev.parent; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - - switch (vb->state) { - case VIDEOBUF_DONE: - dev_dbg(dev, "%s (done)\n", __func__); - break; - case VIDEOBUF_ACTIVE: - dev_dbg(dev, "%s (active)\n", __func__); - break; - case VIDEOBUF_QUEUED: - dev_dbg(dev, "%s (queued)\n", __func__); - break; - case VIDEOBUF_PREPARED: - dev_dbg(dev, "%s (prepared)\n", __func__); - break; - default: - dev_dbg(dev, "%s (unknown %d)\n", __func__, vb->state); - break; - } - - free_buffer(vq, buf, pcdev->vb_mode); -} - -static void videobuf_done(struct omap1_cam_dev *pcdev, - enum videobuf_state result) -{ - struct omap1_cam_buf *buf = pcdev->active; - struct videobuf_buffer *vb; - struct device *dev = pcdev->icd->dev.parent; - - if (WARN_ON(!buf)) { - suspend_capture(pcdev); - disable_capture(pcdev); - return; - } - - if (result == VIDEOBUF_ERROR) - suspend_capture(pcdev); - - vb = &buf->vb; - if (waitqueue_active(&vb->done)) { - if (!pcdev->ready && result != VIDEOBUF_ERROR) { - /* - * No next buffer has been entered into the DMA - * programming register set on time (could be done only - * while the previous DMA interurpt was processed, not - * later), so the last DMA block, be it a whole buffer - * if in CONTIG or its last sgbuf if in SG mode, is - * about to be reused by the just autoreinitialized DMA - * engine, and overwritten with next frame data. Best we - * can do is stopping the capture as soon as possible, - * hopefully before the next frame start. - */ - suspend_capture(pcdev); - } - vb->state = result; - do_gettimeofday(&vb->ts); - if (result != VIDEOBUF_ERROR) - vb->field_count++; - wake_up(&vb->done); - - /* shift in next buffer */ - buf = pcdev->ready; - pcdev->active = buf; - pcdev->ready = NULL; - - if (!buf) { - /* - * No next buffer was ready on time (see above), so - * indicate error condition to force capture restart or - * stop, depending on next buffer already queued or not. - */ - result = VIDEOBUF_ERROR; - prepare_next_vb(pcdev); - - buf = pcdev->ready; - pcdev->active = buf; - pcdev->ready = NULL; - } - } else if (pcdev->ready) { - /* - * In both CONTIG and SG mode, the DMA engine has possibly - * been already autoreinitialized with the preprogrammed - * pcdev->ready buffer. We can either accept this fact - * and just swap the buffers, or provoke an error condition - * and restart capture. The former seems less intrusive. - */ - dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n", - __func__); - pcdev->active = pcdev->ready; - - if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { - /* - * In SG mode, we have to make sure that the buffer we - * are putting back into the pcdev->ready is marked - * fresh. - */ - buf->sgbuf = NULL; - } - pcdev->ready = buf; - - buf = pcdev->active; - } else { - /* - * No next buffer has been entered into - * the DMA programming register set on time. - */ - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, the DMA engine has already been - * reinitialized with the current buffer. Best we can do - * is not touching it. - */ - dev_dbg(dev, - "%s: nobody waiting on videobuf, reuse it\n", - __func__); - } else { - /* - * In SG mode, the DMA engine has just been - * autoreinitialized with the last sgbuf from the - * current list. Restart capture in order to transfer - * next frame start into the first sgbuf, not the last - * one. - */ - if (result != VIDEOBUF_ERROR) { - suspend_capture(pcdev); - result = VIDEOBUF_ERROR; - } - } - } - - if (!buf) { - dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__); - disable_capture(pcdev); - return; - } - - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, the current buffer parameters had already - * been entered into the DMA programming register set while the - * buffer was fetched with prepare_next_vb(), they may have also - * been transfered into the runtime set and already active if - * the DMA still running. - */ - } else { - /* In SG mode, extra steps are required */ - if (result == VIDEOBUF_ERROR) - /* make sure we (re)use sglist from start on error */ - buf->sgbuf = NULL; - - /* - * In any case, enter the next sgbuf parameters into the DMA - * programming register set. They will be used either during - * nearest DMA autoreinitialization or, in case of an error, - * on DMA startup below. - */ - try_next_sgbuf(pcdev->dma_ch, buf); - } - - if (result == VIDEOBUF_ERROR) { - dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n", - __func__); - start_capture(pcdev); - /* - * In SG mode, the above also resulted in the next sgbuf - * parameters being entered into the DMA programming register - * set, making them ready for next DMA autoreinitialization. - */ - } - - /* - * Finally, try fetching next buffer. - * In CONTIG mode, it will also enter it into the DMA programming - * register set, making it ready for next DMA autoreinitialization. - */ - prepare_next_vb(pcdev); -} - -static void dma_isr(int channel, unsigned short status, void *data) -{ - struct omap1_cam_dev *pcdev = data; - struct omap1_cam_buf *buf = pcdev->active; - unsigned long flags; - - spin_lock_irqsave(&pcdev->lock, flags); - - if (WARN_ON(!buf)) { - suspend_capture(pcdev); - disable_capture(pcdev); - goto out; - } - - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, assume we have just managed to collect the - * whole frame, hopefully before our end of frame watchdog is - * triggered. Then, all we have to do is disabling the watchdog - * for this frame, and calling videobuf_done() with success - * indicated. - */ - CAM_WRITE(pcdev, MODE, - CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN); - videobuf_done(pcdev, VIDEOBUF_DONE); - } else { - /* - * In SG mode, we have to process every sgbuf from the current - * sglist, one after another. - */ - if (buf->sgbuf) { - /* - * Current sglist not completed yet, try fetching next - * sgbuf, hopefully putting it into the DMA programming - * register set, making it ready for next DMA - * autoreinitialization. - */ - try_next_sgbuf(pcdev->dma_ch, buf); - if (buf->sgbuf) - goto out; - - /* - * No more sgbufs left in the current sglist. This - * doesn't mean that the whole videobuffer is already - * complete, but only that the last sgbuf from the - * current sglist is about to be filled. It will be - * ready on next DMA interrupt, signalled with the - * buf->sgbuf set back to NULL. - */ - if (buf->result != VIDEOBUF_ERROR) { - /* - * Video frame collected without errors so far, - * we can prepare for collecting a next one - * as soon as DMA gets autoreinitialized - * after the current (last) sgbuf is completed. - */ - buf = prepare_next_vb(pcdev); - if (!buf) - goto out; - - try_next_sgbuf(pcdev->dma_ch, buf); - goto out; - } - } - /* end of videobuf */ - videobuf_done(pcdev, buf->result); - } - -out: - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static irqreturn_t cam_isr(int irq, void *data) -{ - struct omap1_cam_dev *pcdev = data; - struct device *dev = pcdev->icd->dev.parent; - struct omap1_cam_buf *buf = pcdev->active; - u32 it_status; - unsigned long flags; - - it_status = CAM_READ(pcdev, IT_STATUS); - if (!it_status) - return IRQ_NONE; - - spin_lock_irqsave(&pcdev->lock, flags); - - if (WARN_ON(!buf)) { - dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n", - __func__, it_status); - suspend_capture(pcdev); - disable_capture(pcdev); - goto out; - } - - if (unlikely(it_status & FIFO_FULL)) { - dev_warn(dev, "%s: FIFO overflow\n", __func__); - - } else if (it_status & V_DOWN) { - /* end of video frame watchdog */ - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, the watchdog is disabled with - * successful DMA end of block interrupt, and reenabled - * on next frame start. If we get here, there is nothing - * to check, we must be out of sync. - */ - } else { - if (buf->sgcount == 2) { - /* - * If exactly 2 sgbufs from the next sglist have - * been programmed into the DMA engine (the - * frist one already transfered into the DMA - * runtime register set, the second one still - * in the programming set), then we are in sync. - */ - goto out; - } - } - dev_notice(dev, "%s: unexpected end of video frame\n", - __func__); - - } else if (it_status & V_UP) { - u32 mode; - - if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { - /* - * In CONTIG mode, we need this interrupt every frame - * in oredr to reenable our end of frame watchdog. - */ - mode = CAM_READ_CACHE(pcdev, MODE); - } else { - /* - * In SG mode, the below enabled end of frame watchdog - * is kept on permanently, so we can turn this one shot - * setup off. - */ - mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP; - } - - if (!(mode & EN_V_DOWN)) { - /* (re)enable end of frame watchdog interrupt */ - mode |= EN_V_DOWN; - } - CAM_WRITE(pcdev, MODE, mode); - goto out; - - } else { - dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n", - __func__, it_status); - goto out; - } - - videobuf_done(pcdev, VIDEOBUF_ERROR); -out: - spin_unlock_irqrestore(&pcdev->lock, flags); - return IRQ_HANDLED; -} - -static struct videobuf_queue_ops omap1_videobuf_ops = { - .buf_setup = omap1_videobuf_setup, - .buf_prepare = omap1_videobuf_prepare, - .buf_queue = omap1_videobuf_queue, - .buf_release = omap1_videobuf_release, -}; - - -/* - * SOC Camera host operations - */ - -static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset) -{ - /* apply/release camera sensor reset if requested by platform data */ - if (pcdev->pflags & OMAP1_CAMERA_RST_HIGH) - CAM_WRITE(pcdev, GPIO, reset); - else if (pcdev->pflags & OMAP1_CAMERA_RST_LOW) - CAM_WRITE(pcdev, GPIO, !reset); -} - -/* - * The following two functions absolutely depend on the fact, that - * there can be only one camera on OMAP1 camera sensor interface - */ -static int omap1_cam_add_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - u32 ctrlclock; - - if (pcdev->icd) - return -EBUSY; - - clk_enable(pcdev->clk); - - /* setup sensor clock */ - ctrlclock = CAM_READ(pcdev, CTRLCLOCK); - ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN); - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - - ctrlclock &= ~FOSCMOD_MASK; - switch (pcdev->camexclk) { - case 6000000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz; - break; - case 8000000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN; - break; - case 9600000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN; - break; - case 12000000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz; - break; - case 24000000: - ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN; - default: - break; - } - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN); - - /* enable internal clock */ - ctrlclock |= MCLK_EN; - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - - sensor_reset(pcdev, false); - - pcdev->icd = icd; - - dev_dbg(icd->dev.parent, "OMAP1 Camera driver attached to camera %d\n", - icd->devnum); - return 0; -} - -static void omap1_cam_remove_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - u32 ctrlclock; - - BUG_ON(icd != pcdev->icd); - - suspend_capture(pcdev); - disable_capture(pcdev); - - sensor_reset(pcdev, true); - - /* disable and release system clocks */ - ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); - ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN); - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - - ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz; - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN); - - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN); - - clk_disable(pcdev->clk); - - pcdev->icd = NULL; - - dev_dbg(icd->dev.parent, - "OMAP1 Camera driver detached from camera %d\n", icd->devnum); -} - -/* Duplicate standard formats based on host capability of byte swapping */ -static const struct soc_mbus_pixelfmt omap1_cam_formats[] = { - [V4L2_MBUS_FMT_UYVY8_2X8] = { - .fourcc = V4L2_PIX_FMT_YUYV, - .name = "YUYV", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - }, - [V4L2_MBUS_FMT_VYUY8_2X8] = { - .fourcc = V4L2_PIX_FMT_YVYU, - .name = "YVYU", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - }, - [V4L2_MBUS_FMT_YUYV8_2X8] = { - .fourcc = V4L2_PIX_FMT_UYVY, - .name = "UYVY", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - }, - [V4L2_MBUS_FMT_YVYU8_2X8] = { - .fourcc = V4L2_PIX_FMT_VYUY, - .name = "VYUY", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - }, - [V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE] = { - .fourcc = V4L2_PIX_FMT_RGB555, - .name = "RGB555", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - }, - [V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE] = { - .fourcc = V4L2_PIX_FMT_RGB555X, - .name = "RGB555X", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - }, - [V4L2_MBUS_FMT_RGB565_2X8_BE] = { - .fourcc = V4L2_PIX_FMT_RGB565, - .name = "RGB565", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - }, - [V4L2_MBUS_FMT_RGB565_2X8_LE] = { - .fourcc = V4L2_PIX_FMT_RGB565X, - .name = "RGB565X", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - }, -}; - -static int omap1_cam_get_formats(struct soc_camera_device *icd, - unsigned int idx, struct soc_camera_format_xlate *xlate) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->dev.parent; - int formats = 0, ret; - enum v4l2_mbus_pixelcode code; - const struct soc_mbus_pixelfmt *fmt; - - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); - if (ret < 0) - /* No more formats */ - return 0; - - fmt = soc_mbus_get_fmtdesc(code); - if (!fmt) { - dev_err(dev, "%s: invalid format code #%d: %d\n", __func__, - idx, code); - return 0; - } - - /* Check support for the requested bits-per-sample */ - if (fmt->bits_per_sample != 8) - return 0; - - switch (code) { - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_YVYU8_2X8: - case V4L2_MBUS_FMT_UYVY8_2X8: - case V4L2_MBUS_FMT_VYUY8_2X8: - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: - case V4L2_MBUS_FMT_RGB565_2X8_BE: - case V4L2_MBUS_FMT_RGB565_2X8_LE: - formats++; - if (xlate) { - xlate->host_fmt = &omap1_cam_formats[code]; - xlate->code = code; - xlate++; - dev_dbg(dev, - "%s: providing format %s as byte swapped code #%d\n", - __func__, omap1_cam_formats[code].name, code); - } - default: - if (xlate) - dev_dbg(dev, - "%s: providing format %s in pass-through mode\n", - __func__, fmt->name); - } - formats++; - if (xlate) { - xlate->host_fmt = fmt; - xlate->code = code; - xlate++; - } - - return formats; -} - -static bool is_dma_aligned(s32 bytes_per_line, unsigned int height, - enum omap1_cam_vb_mode vb_mode) -{ - int size = bytes_per_line * height; - - return IS_ALIGNED(bytes_per_line, DMA_ELEMENT_SIZE) && - IS_ALIGNED(size, DMA_FRAME_SIZE(vb_mode) * DMA_ELEMENT_SIZE); -} - -static int dma_align(int *width, int *height, - const struct soc_mbus_pixelfmt *fmt, - enum omap1_cam_vb_mode vb_mode, bool enlarge) -{ - s32 bytes_per_line = soc_mbus_bytes_per_line(*width, fmt); - - if (bytes_per_line < 0) - return bytes_per_line; - - if (!is_dma_aligned(bytes_per_line, *height, vb_mode)) { - unsigned int pxalign = __fls(bytes_per_line / *width); - unsigned int salign = DMA_FRAME_SHIFT(vb_mode) + - DMA_ELEMENT_SHIFT - pxalign; - unsigned int incr = enlarge << salign; - - v4l_bound_align_image(width, 1, *width + incr, 0, - height, 1, *height + incr, 0, salign); - return 0; - } - return 1; -} - -#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...) \ -({ \ - struct soc_camera_sense sense = { \ - .master_clock = pcdev->camexclk, \ - .pixel_clock_max = 0, \ - }; \ - int __ret; \ - \ - if (pcdev->pdata) \ - sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \ - icd->sense = &sense; \ - __ret = v4l2_subdev_call(sd, video, function, ##args); \ - icd->sense = NULL; \ - \ - if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \ - if (sense.pixel_clock > sense.pixel_clock_max) { \ - dev_err(dev, \ - "%s: pixel clock %lu set by the camera too high!\n", \ - __func__, sense.pixel_clock); \ - __ret = -EINVAL; \ - } \ - } \ - __ret; \ -}) - -static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev, - struct soc_camera_device *icd, struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf, - const struct soc_camera_format_xlate *xlate) -{ - s32 bytes_per_line; - int ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_mbus_fmt, mf); - - if (ret < 0) { - dev_err(dev, "%s: s_mbus_fmt failed\n", __func__); - return ret; - } - - if (mf->code != xlate->code) { - dev_err(dev, "%s: unexpected pixel code change\n", __func__); - return -EINVAL; - } - - bytes_per_line = soc_mbus_bytes_per_line(mf->width, xlate->host_fmt); - if (bytes_per_line < 0) { - dev_err(dev, "%s: soc_mbus_bytes_per_line() failed\n", - __func__); - return bytes_per_line; - } - - if (!is_dma_aligned(bytes_per_line, mf->height, pcdev->vb_mode)) { - dev_err(dev, "%s: resulting geometry %ux%u not DMA aligned\n", - __func__, mf->width, mf->height); - return -EINVAL; - } - return 0; -} - -static int omap1_cam_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *crop) -{ - struct v4l2_rect *rect = &crop->c; - const struct soc_camera_format_xlate *xlate = icd->current_fmt; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - struct device *dev = icd->dev.parent; - struct v4l2_mbus_framefmt mf; - int ret; - - ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop); - if (ret < 0) { - dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__, - rect->width, rect->height, rect->left, rect->top); - return ret; - } - - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); - if (ret < 0) { - dev_warn(dev, "%s: failed to fetch current format\n", __func__); - return ret; - } - - ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode, - false); - if (ret < 0) { - dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", - __func__, mf.width, mf.height, - xlate->host_fmt->name); - return ret; - } - - if (!ret) { - /* sensor returned geometry not DMA aligned, trying to fix */ - ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate); - if (ret < 0) { - dev_err(dev, "%s: failed to set format\n", __func__); - return ret; - } - } - - icd->user_width = mf.width; - icd->user_height = mf.height; - - return 0; -} - -static int omap1_cam_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct device *dev = icd->dev.parent; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(dev, "%s: format %#x not found\n", __func__, - pix->pixelformat); - return -EINVAL; - } - - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode, - true); - if (ret < 0) { - dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", - __func__, pix->width, pix->height, - xlate->host_fmt->name); - return ret; - } - - ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate); - if (ret < 0) { - dev_err(dev, "%s: failed to set format\n", __func__); - return ret; - } - - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; - icd->current_fmt = xlate; - - return 0; -} - -static int omap1_cam_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - int ret; - /* TODO: limit to mx1 hardware capabilities */ - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(icd->dev.parent, "Format %#x not found\n", - pix->pixelformat); - return -EINVAL; - } - - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - /* limit to sensor capabilities */ - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); - if (ret < 0) - return ret; - - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; - - return 0; -} - -static bool sg_mode; - -/* - * Local mmap_mapper wrapper, - * used for detecting videobuf-dma-contig buffer allocation failures - * and switching to videobuf-dma-sg automatically for future attempts. - */ -static int omap1_cam_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct soc_camera_device *icd = q->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - int ret; - - ret = pcdev->mmap_mapper(q, buf, vma); - - if (ret == -ENOMEM) - sg_mode = true; - - return ret; -} - -static void omap1_cam_init_videobuf(struct videobuf_queue *q, - struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - - if (!sg_mode) - videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops, - icd->dev.parent, &pcdev->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct omap1_cam_buf), icd, &icd->video_lock); - else - videobuf_queue_sg_init(q, &omap1_videobuf_ops, - icd->dev.parent, &pcdev->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct omap1_cam_buf), icd, &icd->video_lock); - - /* use videobuf mode (auto)selected with the module parameter */ - pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG; - - /* - * Ensure we substitute the videobuf-dma-contig version of the - * mmap_mapper() callback with our own wrapper, used for switching - * automatically to videobuf-dma-sg on buffer allocation failure. - */ - if (!sg_mode && q->int_ops->mmap_mapper != omap1_cam_mmap_mapper) { - pcdev->mmap_mapper = q->int_ops->mmap_mapper; - q->int_ops->mmap_mapper = omap1_cam_mmap_mapper; - } -} - -static int omap1_cam_reqbufs(struct soc_camera_device *icd, - struct v4l2_requestbuffers *p) -{ - int i; - - /* - * This is for locking debugging only. I removed spinlocks and now I - * check whether .prepare is ever called on a linked buffer, or whether - * a dma IRQ can occur for an in-work or unlinked buffer. Until now - * it hadn't triggered - */ - for (i = 0; i < p->count; i++) { - struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i], - struct omap1_cam_buf, vb); - buf->inwork = 0; - INIT_LIST_HEAD(&buf->vb.queue); - } - - return 0; -} - -static int omap1_cam_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - /* cap->name is set by the friendly caller:-> */ - strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card)); - cap->version = VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - - return 0; -} - -static int omap1_cam_set_bus_param(struct soc_camera_device *icd, - __u32 pixfmt) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct omap1_cam_dev *pcdev = ici->priv; - struct device *dev = icd->dev.parent; - const struct soc_camera_format_xlate *xlate; - const struct soc_mbus_pixelfmt *fmt; - unsigned long camera_flags, common_flags; - u32 ctrlclock, mode; - int ret; - - camera_flags = icd->ops->query_bus_param(icd); - - common_flags = soc_camera_bus_param_compatible(camera_flags, - SOCAM_BUS_FLAGS); - if (!common_flags) - return -EINVAL; - - /* Make choices, possibly based on platform configuration */ - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { - if (!pcdev->pdata || - pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; - else - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; - } - - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) - return ret; - - ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); - if (ctrlclock & LCLK_EN) - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); - - if (common_flags & SOCAM_PCLK_SAMPLE_RISING) { - dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n"); - ctrlclock |= POLCLK; - } else { - dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n"); - ctrlclock &= ~POLCLK; - } - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); - - if (ctrlclock & LCLK_EN) - CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); - - /* select bus endianess */ - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - fmt = xlate->host_fmt; - - mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA); - if (fmt->order == SOC_MBUS_ORDER_LE) { - dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n"); - CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD); - } else { - dev_dbg(dev, "MODE_REG |= ORDERCAMD\n"); - CAM_WRITE(pcdev, MODE, mode | ORDERCAMD); - } - - return 0; -} - -static unsigned int omap1_cam_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - struct omap1_cam_buf *buf; - - buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf, - vb.stream); - - poll_wait(file, &buf->vb.done, pt); - - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - return POLLIN | POLLRDNORM; - - return 0; -} - -static struct soc_camera_host_ops omap1_host_ops = { - .owner = THIS_MODULE, - .add = omap1_cam_add_device, - .remove = omap1_cam_remove_device, - .get_formats = omap1_cam_get_formats, - .set_crop = omap1_cam_set_crop, - .set_fmt = omap1_cam_set_fmt, - .try_fmt = omap1_cam_try_fmt, - .init_videobuf = omap1_cam_init_videobuf, - .reqbufs = omap1_cam_reqbufs, - .querycap = omap1_cam_querycap, - .set_bus_param = omap1_cam_set_bus_param, - .poll = omap1_cam_poll, -}; - -static int __init omap1_cam_probe(struct platform_device *pdev) -{ - struct omap1_cam_dev *pcdev; - struct resource *res; - struct clk *clk; - void __iomem *base; - unsigned int irq; - int err = 0; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!res || (int)irq <= 0) { - err = -ENODEV; - goto exit; - } - - clk = clk_get(&pdev->dev, "armper_ck"); - if (IS_ERR(clk)) { - err = PTR_ERR(clk); - goto exit; - } - - pcdev = kzalloc(sizeof(*pcdev) + resource_size(res), GFP_KERNEL); - if (!pcdev) { - dev_err(&pdev->dev, "Could not allocate pcdev\n"); - err = -ENOMEM; - goto exit_put_clk; - } - - pcdev->res = res; - pcdev->clk = clk; - - pcdev->pdata = pdev->dev.platform_data; - pcdev->pflags = pcdev->pdata->flags; - - if (pcdev->pdata) - pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000; - - switch (pcdev->camexclk) { - case 6000000: - case 8000000: - case 9600000: - case 12000000: - case 24000000: - break; - default: - dev_warn(&pdev->dev, - "Incorrect sensor clock frequency %ld kHz, " - "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, " - "please correct your platform data\n", - pcdev->pdata->camexclk_khz); - pcdev->camexclk = 0; - case 0: - dev_info(&pdev->dev, - "Not providing sensor clock\n"); - } - - INIT_LIST_HEAD(&pcdev->capture); - spin_lock_init(&pcdev->lock); - - /* - * Request the region. - */ - if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) { - err = -EBUSY; - goto exit_kfree; - } - - base = ioremap(res->start, resource_size(res)); - if (!base) { - err = -ENOMEM; - goto exit_release; - } - pcdev->irq = irq; - pcdev->base = base; - - sensor_reset(pcdev, true); - - err = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, DRIVER_NAME, - dma_isr, (void *)pcdev, &pcdev->dma_ch); - if (err < 0) { - dev_err(&pdev->dev, "Can't request DMA for OMAP1 Camera\n"); - err = -EBUSY; - goto exit_iounmap; - } - dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_ch); - - /* preconfigure DMA */ - omap_set_dma_src_params(pcdev->dma_ch, OMAP_DMA_PORT_TIPB, - OMAP_DMA_AMODE_CONSTANT, res->start + REG_CAMDATA, - 0, 0); - omap_set_dma_dest_burst_mode(pcdev->dma_ch, OMAP_DMA_DATA_BURST_4); - /* setup DMA autoinitialization */ - omap_dma_link_lch(pcdev->dma_ch, pcdev->dma_ch); - - err = request_irq(pcdev->irq, cam_isr, 0, DRIVER_NAME, pcdev); - if (err) { - dev_err(&pdev->dev, "Camera interrupt register failed\n"); - goto exit_free_dma; - } - - pcdev->soc_host.drv_name = DRIVER_NAME; - pcdev->soc_host.ops = &omap1_host_ops; - pcdev->soc_host.priv = pcdev; - pcdev->soc_host.v4l2_dev.dev = &pdev->dev; - pcdev->soc_host.nr = pdev->id; - - err = soc_camera_host_register(&pcdev->soc_host); - if (err) - goto exit_free_irq; - - dev_info(&pdev->dev, "OMAP1 Camera Interface driver loaded\n"); - - return 0; - -exit_free_irq: - free_irq(pcdev->irq, pcdev); -exit_free_dma: - omap_free_dma(pcdev->dma_ch); -exit_iounmap: - iounmap(base); -exit_release: - release_mem_region(res->start, resource_size(res)); -exit_kfree: - kfree(pcdev); -exit_put_clk: - clk_put(clk); -exit: - return err; -} - -static int __exit omap1_cam_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - struct omap1_cam_dev *pcdev = container_of(soc_host, - struct omap1_cam_dev, soc_host); - struct resource *res; - - free_irq(pcdev->irq, pcdev); - - omap_free_dma(pcdev->dma_ch); - - soc_camera_host_unregister(soc_host); - - iounmap(pcdev->base); - - res = pcdev->res; - release_mem_region(res->start, resource_size(res)); - - clk_put(pcdev->clk); - - kfree(pcdev); - - dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n"); - - return 0; -} - -static struct platform_driver omap1_cam_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = omap1_cam_probe, - .remove = __exit_p(omap1_cam_remove), -}; - -static int __init omap1_cam_init(void) -{ - return platform_driver_register(&omap1_cam_driver); -} -module_init(omap1_cam_init); - -static void __exit omap1_cam_exit(void) -{ - platform_driver_unregister(&omap1_cam_driver); -} -module_exit(omap1_cam_exit); - -module_param(sg_mode, bool, 0644); -MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg"); - -MODULE_DESCRIPTION("OMAP1 Camera Interface driver"); -MODULE_AUTHOR("Janusz Krzysztofik "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1900 +0,0 @@ -/* - * drivers/media/video/omap24xxcam.c - * - * OMAP 2 camera block driver. - * - * Copyright (C) 2004 MontaVista Software, Inc. - * Copyright (C) 2004 Texas Instruments. - * Copyright (C) 2007-2008 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * Based on code from Andy Lowe - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include /* needed for videobufs */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "omap24xxcam.h" - -#define OMAP24XXCAM_VERSION KERNEL_VERSION(0, 0, 0) - -#define RESET_TIMEOUT_NS 10000 - -static void omap24xxcam_reset(struct omap24xxcam_device *cam); -static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam); -static void omap24xxcam_device_unregister(struct v4l2_int_device *s); -static int omap24xxcam_remove(struct platform_device *pdev); - -/* module parameters */ -static int video_nr = -1; /* video device minor (-1 ==> auto assign) */ -/* - * Maximum amount of memory to use for capture buffers. - * Default is 4800KB, enough to double-buffer SXGA. - */ -static int capture_mem = 1280 * 960 * 2 * 2; - -static struct v4l2_int_device omap24xxcam; - -/* - * - * Clocks. - * - */ - -static void omap24xxcam_clock_put(struct omap24xxcam_device *cam) -{ - if (cam->ick != NULL && !IS_ERR(cam->ick)) - clk_put(cam->ick); - if (cam->fck != NULL && !IS_ERR(cam->fck)) - clk_put(cam->fck); - - cam->ick = cam->fck = NULL; -} - -static int omap24xxcam_clock_get(struct omap24xxcam_device *cam) -{ - int rval = 0; - - cam->fck = clk_get(cam->dev, "fck"); - if (IS_ERR(cam->fck)) { - dev_err(cam->dev, "can't get camera fck"); - rval = PTR_ERR(cam->fck); - omap24xxcam_clock_put(cam); - return rval; - } - - cam->ick = clk_get(cam->dev, "ick"); - if (IS_ERR(cam->ick)) { - dev_err(cam->dev, "can't get camera ick"); - rval = PTR_ERR(cam->ick); - omap24xxcam_clock_put(cam); - } - - return rval; -} - -static void omap24xxcam_clock_on(struct omap24xxcam_device *cam) -{ - clk_enable(cam->fck); - clk_enable(cam->ick); -} - -static void omap24xxcam_clock_off(struct omap24xxcam_device *cam) -{ - clk_disable(cam->fck); - clk_disable(cam->ick); -} - -/* - * - * Camera core - * - */ - -/* - * Set xclk. - * - * To disable xclk, use value zero. - */ -static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam, - u32 xclk) -{ - if (xclk) { - u32 divisor = CAM_MCLK / xclk; - - if (divisor == 1) - omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, - CC_CTRL_XCLK, - CC_CTRL_XCLK_DIV_BYPASS); - else - omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, - CC_CTRL_XCLK, divisor); - } else - omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, - CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW); -} - -static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam) -{ - /* - * Setting the camera core AUTOIDLE bit causes problems with frame - * synchronization, so we will clear the AUTOIDLE bit instead. - */ - omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG, - CC_SYSCONFIG_AUTOIDLE); - - /* program the camera interface DMA packet size */ - omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA, - CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1)); - - /* enable camera core error interrupts */ - omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE, - CC_IRQENABLE_FW_ERR_IRQ - | CC_IRQENABLE_FSC_ERR_IRQ - | CC_IRQENABLE_SSC_ERR_IRQ - | CC_IRQENABLE_FIFO_OF_IRQ); -} - -/* - * Enable the camera core. - * - * Data transfer to the camera DMA starts from next starting frame. - */ -static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam) -{ - - omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL, - cam->cc_ctrl); -} - -/* - * Disable camera core. - * - * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The - * core internal state machines will be reset. Use - * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current - * frame completely. - */ -static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam) -{ - omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL, - CC_CTRL_CC_RST); -} - -/* Interrupt service routine for camera core interrupts. */ -static void omap24xxcam_core_isr(struct omap24xxcam_device *cam) -{ - u32 cc_irqstatus; - const u32 cc_irqstatus_err = - CC_IRQSTATUS_FW_ERR_IRQ - | CC_IRQSTATUS_FSC_ERR_IRQ - | CC_IRQSTATUS_SSC_ERR_IRQ - | CC_IRQSTATUS_FIFO_UF_IRQ - | CC_IRQSTATUS_FIFO_OF_IRQ; - - cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET, - CC_IRQSTATUS); - omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS, - cc_irqstatus); - - if (cc_irqstatus & cc_irqstatus_err - && !atomic_read(&cam->in_reset)) { - dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n", - cc_irqstatus); - omap24xxcam_reset(cam); - } -} - -/* - * - * videobuf_buffer handling. - * - * Memory for mmapped videobuf_buffers is not allocated - * conventionally, but by several kmalloc allocations and then - * creating the scatterlist on our own. User-space buffers are handled - * normally. - * - */ - -/* - * Free the memory-mapped buffer memory allocated for a - * videobuf_buffer and the associated scatterlist. - */ -static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - size_t alloc_size; - struct page *page; - int i; - - if (dma->sglist == NULL) - return; - - i = dma->sglen; - while (i) { - i--; - alloc_size = sg_dma_len(&dma->sglist[i]); - page = sg_page(&dma->sglist[i]); - do { - ClearPageReserved(page++); - } while (alloc_size -= PAGE_SIZE); - __free_pages(sg_page(&dma->sglist[i]), - get_order(sg_dma_len(&dma->sglist[i]))); - } - - kfree(dma->sglist); - dma->sglist = NULL; -} - -/* Release all memory related to the videobuf_queue. */ -static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq) -{ - int i; - - mutex_lock(&vbq->vb_lock); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == vbq->bufs[i]) - continue; - if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory) - continue; - vbq->ops->buf_release(vbq, vbq->bufs[i]); - omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]); - kfree(vbq->bufs[i]); - vbq->bufs[i] = NULL; - } - - mutex_unlock(&vbq->vb_lock); - - videobuf_mmap_free(vbq); -} - -/* - * Allocate physically as contiguous as possible buffer for video - * frame and allocate and build DMA scatter-gather list for it. - */ -static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb) -{ - unsigned int order; - size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */ - struct page *page; - int max_pages, err = 0, i = 0; - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - - /* - * allocate maximum size scatter-gather list. Note this is - * overhead. We may not use as many entries as we allocate - */ - max_pages = vb->bsize >> PAGE_SHIFT; - dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL); - if (dma->sglist == NULL) { - err = -ENOMEM; - goto out; - } - - while (size) { - order = get_order(size); - /* - * do not over-allocate even if we would get larger - * contiguous chunk that way - */ - if ((PAGE_SIZE << order) > size) - order--; - - /* try to allocate as many contiguous pages as possible */ - page = alloc_pages(GFP_KERNEL | GFP_DMA, order); - /* if allocation fails, try to allocate smaller amount */ - while (page == NULL) { - order--; - page = alloc_pages(GFP_KERNEL | GFP_DMA, order); - if (page == NULL && !order) { - err = -ENOMEM; - goto out; - } - } - size -= (PAGE_SIZE << order); - - /* append allocated chunk of pages into scatter-gather list */ - sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0); - dma->sglen++; - i++; - - alloc_size = (PAGE_SIZE << order); - - /* clear pages before giving them to user space */ - memset(page_address(page), 0, alloc_size); - - /* mark allocated pages reserved */ - do { - SetPageReserved(page++); - } while (alloc_size -= PAGE_SIZE); - } - /* - * REVISIT: not fully correct to assign nr_pages == sglen but - * video-buf is passing nr_pages for e.g. unmap_sg calls - */ - dma->nr_pages = dma->sglen; - dma->direction = PCI_DMA_FROMDEVICE; - - return 0; - -out: - omap24xxcam_vbq_free_mmap_buffer(vb); - return err; -} - -static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq, - unsigned int count) -{ - int i, err = 0; - struct omap24xxcam_fh *fh = - container_of(vbq, struct omap24xxcam_fh, vbq); - - mutex_lock(&vbq->vb_lock); - - for (i = 0; i < count; i++) { - err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]); - if (err) - goto out; - dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n", - videobuf_to_dma(vbq->bufs[i])->sglen, i); - } - - mutex_unlock(&vbq->vb_lock); - - return 0; -out: - while (i) { - i--; - omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]); - } - - mutex_unlock(&vbq->vb_lock); - - return err; -} - -/* - * This routine is called from interrupt context when a scatter-gather DMA - * transfer of a videobuf_buffer completes. - */ -static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma, - u32 csr, void *arg) -{ - struct omap24xxcam_device *cam = - container_of(sgdma, struct omap24xxcam_device, sgdma); - struct omap24xxcam_fh *fh = cam->streaming->private_data; - struct videobuf_buffer *vb = (struct videobuf_buffer *)arg; - const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR - | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR - | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; - unsigned long flags; - - spin_lock_irqsave(&cam->core_enable_disable_lock, flags); - if (--cam->sgdma_in_queue == 0) - omap24xxcam_core_disable(cam); - spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); - - do_gettimeofday(&vb->ts); - vb->field_count = atomic_add_return(2, &fh->field_count); - if (csr & csr_error) { - vb->state = VIDEOBUF_ERROR; - if (!atomic_read(&fh->cam->in_reset)) { - dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr); - omap24xxcam_reset(cam); - } - } else - vb->state = VIDEOBUF_DONE; - wake_up(&vb->done); -} - -static void omap24xxcam_vbq_release(struct videobuf_queue *vbq, - struct videobuf_buffer *vb) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - - /* wait for buffer, especially to get out of the sgdma queue */ - videobuf_waiton(vbq, vb, 0, 0); - if (vb->memory == V4L2_MEMORY_MMAP) { - dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen, - dma->direction); - dma->direction = DMA_NONE; - } else { - videobuf_dma_unmap(vbq->dev, videobuf_to_dma(vb)); - videobuf_dma_free(videobuf_to_dma(vb)); - } - - vb->state = VIDEOBUF_NEEDS_INIT; -} - -/* - * Limit the number of available kernel image capture buffers based on the - * number requested, the currently selected image size, and the maximum - * amount of memory permitted for kernel capture buffers. - */ -static int omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt, - unsigned int *size) -{ - struct omap24xxcam_fh *fh = vbq->priv_data; - - if (*cnt <= 0) - *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */ - - if (*cnt > VIDEO_MAX_FRAME) - *cnt = VIDEO_MAX_FRAME; - - *size = fh->pix.sizeimage; - - /* accessing fh->cam->capture_mem is ok, it's constant */ - if (*size * *cnt > fh->cam->capture_mem) - *cnt = fh->cam->capture_mem / *size; - - return 0; -} - -static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq, - struct videobuf_dmabuf *dma) -{ - int err = 0; - - dma->direction = PCI_DMA_FROMDEVICE; - if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) { - kfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - err = -EIO; - } - - return err; -} - -static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct omap24xxcam_fh *fh = vbq->priv_data; - int err = 0; - - /* - * Accessing pix here is okay since it's constant while - * streaming is on (and we only get called then). - */ - if (vb->baddr) { - /* This is a userspace buffer. */ - if (fh->pix.sizeimage > vb->bsize) { - /* The buffer isn't big enough. */ - err = -EINVAL; - } else - vb->size = fh->pix.sizeimage; - } else { - if (vb->state != VIDEOBUF_NEEDS_INIT) { - /* - * We have a kernel bounce buffer that has - * already been allocated. - */ - if (fh->pix.sizeimage > vb->size) { - /* - * The image size has been changed to - * a larger size since this buffer was - * allocated, so we need to free and - * reallocate it. - */ - omap24xxcam_vbq_release(vbq, vb); - vb->size = fh->pix.sizeimage; - } - } else { - /* We need to allocate a new kernel bounce buffer. */ - vb->size = fh->pix.sizeimage; - } - } - - if (err) - return err; - - vb->width = fh->pix.width; - vb->height = fh->pix.height; - vb->field = field; - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - if (vb->memory == V4L2_MEMORY_MMAP) - /* - * we have built the scatter-gather list by ourself so - * do the scatter-gather mapping as well - */ - err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb)); - else - err = videobuf_iolock(vbq, vb, NULL); - } - - if (!err) - vb->state = VIDEOBUF_PREPARED; - else - omap24xxcam_vbq_release(vbq, vb); - - return err; -} - -static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq, - struct videobuf_buffer *vb) -{ - struct omap24xxcam_fh *fh = vbq->priv_data; - struct omap24xxcam_device *cam = fh->cam; - enum videobuf_state state = vb->state; - unsigned long flags; - int err; - - /* - * FIXME: We're marking the buffer active since we have no - * pretty way of marking it active exactly when the - * scatter-gather transfer starts. - */ - vb->state = VIDEOBUF_ACTIVE; - - err = omap24xxcam_sgdma_queue(&fh->cam->sgdma, - videobuf_to_dma(vb)->sglist, - videobuf_to_dma(vb)->sglen, vb->size, - omap24xxcam_vbq_complete, vb); - - if (!err) { - spin_lock_irqsave(&cam->core_enable_disable_lock, flags); - if (++cam->sgdma_in_queue == 1 - && !atomic_read(&cam->in_reset)) - omap24xxcam_core_enable(cam); - spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); - } else { - /* - * Oops. We're not supposed to get any errors here. - * The only way we could get an error is if we ran out - * of scatter-gather DMA slots, but we are supposed to - * have at least as many scatter-gather DMA slots as - * video buffers so that can't happen. - */ - dev_err(cam->dev, "failed to queue a video buffer for dma!\n"); - dev_err(cam->dev, "likely a bug in the driver!\n"); - vb->state = state; - } -} - -static struct videobuf_queue_ops omap24xxcam_vbq_ops = { - .buf_setup = omap24xxcam_vbq_setup, - .buf_prepare = omap24xxcam_vbq_prepare, - .buf_queue = omap24xxcam_vbq_queue, - .buf_release = omap24xxcam_vbq_release, -}; - -/* - * - * OMAP main camera system - * - */ - -/* - * Reset camera block to power-on state. - */ -static void omap24xxcam_poweron_reset(struct omap24xxcam_device *cam) -{ - int max_loop = RESET_TIMEOUT_NS; - - /* Reset whole camera subsystem */ - omap24xxcam_reg_out(cam->mmio_base, - CAM_SYSCONFIG, - CAM_SYSCONFIG_SOFTRESET); - - /* Wait till it's finished */ - while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS) - & CAM_SYSSTATUS_RESETDONE) - && --max_loop) { - ndelay(1); - } - - if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS) - & CAM_SYSSTATUS_RESETDONE)) - dev_err(cam->dev, "camera soft reset timeout\n"); -} - -/* - * (Re)initialise the camera block. - */ -static void omap24xxcam_hwinit(struct omap24xxcam_device *cam) -{ - omap24xxcam_poweron_reset(cam); - - /* set the camera subsystem autoidle bit */ - omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG, - CAM_SYSCONFIG_AUTOIDLE); - - /* set the camera MMU autoidle bit */ - omap24xxcam_reg_out(cam->mmio_base, - CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG, - CAMMMU_SYSCONFIG_AUTOIDLE); - - omap24xxcam_core_hwinit(cam); - - omap24xxcam_dma_hwinit(&cam->sgdma.dma); -} - -/* - * Callback for dma transfer stalling. - */ -static void omap24xxcam_stalled_dma_reset(unsigned long data) -{ - struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data; - - if (!atomic_read(&cam->in_reset)) { - dev_dbg(cam->dev, "dma stalled, resetting camera\n"); - omap24xxcam_reset(cam); - } -} - -/* - * Stop capture. Mark we're doing a reset, stop DMA transfers and - * core. (No new scatter-gather transfers will be queued whilst - * in_reset is non-zero.) - * - * If omap24xxcam_capture_stop is called from several places at - * once, only the first call will have an effect. Similarly, the last - * call omap24xxcam_streaming_cont will have effect. - * - * Serialisation is ensured by using cam->core_enable_disable_lock. - */ -static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->core_enable_disable_lock, flags); - - if (atomic_inc_return(&cam->in_reset) != 1) { - spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); - return; - } - - omap24xxcam_core_disable(cam); - - spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); - - omap24xxcam_sgdma_sync(&cam->sgdma); -} - -/* - * Reset and continue streaming. - * - * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL - * register is supposed to be sufficient to recover from a camera - * interface error, but it doesn't seem to be enough. If we only do - * that then subsequent image captures are out of sync by either one - * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the - * entire camera subsystem prevents the problem with frame - * synchronization. - */ -static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->core_enable_disable_lock, flags); - - if (atomic_read(&cam->in_reset) != 1) - goto out; - - omap24xxcam_hwinit(cam); - - omap24xxcam_sensor_if_enable(cam); - - omap24xxcam_sgdma_process(&cam->sgdma); - - if (cam->sgdma_in_queue) - omap24xxcam_core_enable(cam); - -out: - atomic_dec(&cam->in_reset); - spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags); -} - -static ssize_t -omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct omap24xxcam_device *cam = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive"); -} -static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL); - -/* - * Stop capture and restart it. I.e. reset the camera during use. - */ -static void omap24xxcam_reset(struct omap24xxcam_device *cam) -{ - omap24xxcam_capture_stop(cam); - omap24xxcam_capture_cont(cam); -} - -/* - * The main interrupt handler. - */ -static irqreturn_t omap24xxcam_isr(int irq, void *arg) -{ - struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg; - u32 irqstatus; - unsigned int irqhandled = 0; - - irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS); - - if (irqstatus & - (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1 - | CAM_IRQSTATUS_DMA_IRQ0)) { - omap24xxcam_dma_isr(&cam->sgdma.dma); - irqhandled = 1; - } - if (irqstatus & CAM_IRQSTATUS_CC_IRQ) { - omap24xxcam_core_isr(cam); - irqhandled = 1; - } - if (irqstatus & CAM_IRQSTATUS_MMU_IRQ) - dev_err(cam->dev, "unhandled camera MMU interrupt!\n"); - - return IRQ_RETVAL(irqhandled); -} - -/* - * - * Sensor handling. - * - */ - -/* - * Enable the external sensor interface. Try to negotiate interface - * parameters with the sensor and start using the new ones. The calls - * to sensor_if_enable and sensor_if_disable need not to be balanced. - */ -static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam) -{ - int rval; - struct v4l2_ifparm p; - - rval = vidioc_int_g_ifparm(cam->sdev, &p); - if (rval) { - dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval); - return rval; - } - - cam->if_type = p.if_type; - - cam->cc_ctrl = CC_CTRL_CC_EN; - - switch (p.if_type) { - case V4L2_IF_TYPE_BT656: - if (p.u.bt656.frame_start_on_rising_vs) - cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO; - if (p.u.bt656.bt_sync_correct) - cam->cc_ctrl |= CC_CTRL_BT_CORRECT; - if (p.u.bt656.swap) - cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM; - if (p.u.bt656.latch_clk_inv) - cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL; - if (p.u.bt656.nobt_hs_inv) - cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL; - if (p.u.bt656.nobt_vs_inv) - cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL; - - switch (p.u.bt656.mode) { - case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT: - cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8; - break; - case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT: - cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10; - break; - case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT: - cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12; - break; - case V4L2_IF_TYPE_BT656_MODE_BT_8BIT: - cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8; - break; - case V4L2_IF_TYPE_BT656_MODE_BT_10BIT: - cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10; - break; - default: - dev_err(cam->dev, - "bt656 interface mode %d not supported\n", - p.u.bt656.mode); - return -EINVAL; - } - /* - * The clock rate that the sensor wants has changed. - * We have to adjust the xclk from OMAP 2 side to - * match the sensor's wish as closely as possible. - */ - if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) { - u32 xclk = p.u.bt656.clock_curr; - u32 divisor; - - if (xclk == 0) - return -EINVAL; - - if (xclk > CAM_MCLK) - xclk = CAM_MCLK; - - divisor = CAM_MCLK / xclk; - if (divisor * xclk < CAM_MCLK) - divisor++; - if (CAM_MCLK / divisor < p.u.bt656.clock_min - && divisor > 1) - divisor--; - if (divisor > 30) - divisor = 30; - - xclk = CAM_MCLK / divisor; - - if (xclk < p.u.bt656.clock_min - || xclk > p.u.bt656.clock_max) - return -EINVAL; - - cam->if_u.bt656.xclk = xclk; - } - omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk); - break; - default: - /* FIXME: how about other interfaces? */ - dev_err(cam->dev, "interface type %d not supported\n", - p.if_type); - return -EINVAL; - } - - return 0; -} - -static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam) -{ - switch (cam->if_type) { - case V4L2_IF_TYPE_BT656: - omap24xxcam_core_xclk_set(cam, 0); - break; - } -} - -/* - * Initialise the sensor hardware. - */ -static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam) -{ - int err = 0; - struct v4l2_int_device *sdev = cam->sdev; - - omap24xxcam_clock_on(cam); - err = omap24xxcam_sensor_if_enable(cam); - if (err) { - dev_err(cam->dev, "sensor interface could not be enabled at " - "initialisation, %d\n", err); - cam->sdev = NULL; - goto out; - } - - /* power up sensor during sensor initialization */ - vidioc_int_s_power(sdev, 1); - - err = vidioc_int_dev_init(sdev); - if (err) { - dev_err(cam->dev, "cannot initialize sensor, error %d\n", err); - /* Sensor init failed --- it's nonexistent to us! */ - cam->sdev = NULL; - goto out; - } - - dev_info(cam->dev, "sensor is %s\n", sdev->name); - -out: - omap24xxcam_sensor_if_disable(cam); - omap24xxcam_clock_off(cam); - - vidioc_int_s_power(sdev, 0); - - return err; -} - -static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam) -{ - if (cam->sdev) - vidioc_int_dev_exit(cam->sdev); -} - -static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam) -{ - omap24xxcam_sensor_if_disable(cam); - omap24xxcam_clock_off(cam); - vidioc_int_s_power(cam->sdev, 0); -} - -/* - * Power-up and configure camera sensor. It's ready for capturing now. - */ -static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam) -{ - int rval; - - omap24xxcam_clock_on(cam); - - omap24xxcam_sensor_if_enable(cam); - - rval = vidioc_int_s_power(cam->sdev, 1); - if (rval) - goto out; - - rval = vidioc_int_init(cam->sdev); - if (rval) - goto out; - - return 0; - -out: - omap24xxcam_sensor_disable(cam); - - return rval; -} - -static void omap24xxcam_sensor_reset_work(struct work_struct *work) -{ - struct omap24xxcam_device *cam = - container_of(work, struct omap24xxcam_device, - sensor_reset_work); - - if (atomic_read(&cam->reset_disable)) - return; - - omap24xxcam_capture_stop(cam); - - if (vidioc_int_reset(cam->sdev) == 0) { - vidioc_int_init(cam->sdev); - } else { - /* Can't reset it by vidioc_int_reset. */ - omap24xxcam_sensor_disable(cam); - omap24xxcam_sensor_enable(cam); - } - - omap24xxcam_capture_cont(cam); -} - -/* - * - * IOCTL interface. - * - */ - -static int vidioc_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - - strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver)); - strlcpy(cap->card, cam->vfd->name, sizeof(cap->card)); - cap->version = OMAP24XXCAM_VERSION; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - rval = vidioc_int_enum_fmt_cap(cam->sdev, f); - - return rval; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - mutex_lock(&cam->mutex); - rval = vidioc_int_g_fmt_cap(cam->sdev, f); - mutex_unlock(&cam->mutex); - - return rval; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - mutex_lock(&cam->mutex); - if (cam->streaming) { - rval = -EBUSY; - goto out; - } - - rval = vidioc_int_s_fmt_cap(cam->sdev, f); - -out: - mutex_unlock(&cam->mutex); - - if (!rval) { - mutex_lock(&ofh->vbq.vb_lock); - ofh->pix = f->fmt.pix; - mutex_unlock(&ofh->vbq.vb_lock); - } - - memset(f, 0, sizeof(*f)); - vidioc_g_fmt_vid_cap(file, fh, f); - - return rval; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - mutex_lock(&cam->mutex); - rval = vidioc_int_try_fmt_cap(cam->sdev, f); - mutex_unlock(&cam->mutex); - - return rval; -} - -static int vidioc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *b) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - mutex_lock(&cam->mutex); - if (cam->streaming) { - mutex_unlock(&cam->mutex); - return -EBUSY; - } - - omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq); - mutex_unlock(&cam->mutex); - - rval = videobuf_reqbufs(&ofh->vbq, b); - - /* - * Either videobuf_reqbufs failed or the buffers are not - * memory-mapped (which would need special attention). - */ - if (rval < 0 || b->memory != V4L2_MEMORY_MMAP) - goto out; - - rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval); - if (rval) - omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq); - -out: - return rval; -} - -static int vidioc_querybuf(struct file *file, void *fh, - struct v4l2_buffer *b) -{ - struct omap24xxcam_fh *ofh = fh; - - return videobuf_querybuf(&ofh->vbq, b); -} - -static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct omap24xxcam_fh *ofh = fh; - - return videobuf_qbuf(&ofh->vbq, b); -} - -static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - struct videobuf_buffer *vb; - int rval; - -videobuf_dqbuf_again: - rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK); - if (rval) - goto out; - - vb = ofh->vbq.bufs[b->index]; - - mutex_lock(&cam->mutex); - /* _needs_reset returns -EIO if reset is required. */ - rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr); - mutex_unlock(&cam->mutex); - if (rval == -EIO) - schedule_work(&cam->sensor_reset_work); - else - rval = 0; - -out: - /* - * This is a hack. We don't want to show -EIO to the user - * space. Requeue the buffer and try again if we're not doing - * this in non-blocking mode. - */ - if (rval == -EIO) { - videobuf_qbuf(&ofh->vbq, b); - if (!(file->f_flags & O_NONBLOCK)) - goto videobuf_dqbuf_again; - /* - * We don't have a videobuf_buffer now --- maybe next - * time... - */ - rval = -EAGAIN; - } - - return rval; -} - -static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - mutex_lock(&cam->mutex); - if (cam->streaming) { - rval = -EBUSY; - goto out; - } - - rval = omap24xxcam_sensor_if_enable(cam); - if (rval) { - dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n"); - goto out; - } - - rval = videobuf_streamon(&ofh->vbq); - if (!rval) { - cam->streaming = file; - sysfs_notify(&cam->dev->kobj, NULL, "streaming"); - } - -out: - mutex_unlock(&cam->mutex); - - return rval; -} - -static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - struct videobuf_queue *q = &ofh->vbq; - int rval; - - atomic_inc(&cam->reset_disable); - - flush_work_sync(&cam->sensor_reset_work); - - rval = videobuf_streamoff(q); - if (!rval) { - mutex_lock(&cam->mutex); - cam->streaming = NULL; - mutex_unlock(&cam->mutex); - sysfs_notify(&cam->dev->kobj, NULL, "streaming"); - } - - atomic_dec(&cam->reset_disable); - - return rval; -} - -static int vidioc_enum_input(struct file *file, void *fh, - struct v4l2_input *inp) -{ - if (inp->index > 0) - return -EINVAL; - - strlcpy(inp->name, "camera", sizeof(inp->name)); - inp->type = V4L2_INPUT_TYPE_CAMERA; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - *i = 0; - - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int i) -{ - if (i > 0) - return -EINVAL; - - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *fh, - struct v4l2_queryctrl *a) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - rval = vidioc_int_queryctrl(cam->sdev, a); - - return rval; -} - -static int vidioc_g_ctrl(struct file *file, void *fh, - struct v4l2_control *a) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - mutex_lock(&cam->mutex); - rval = vidioc_int_g_ctrl(cam->sdev, a); - mutex_unlock(&cam->mutex); - - return rval; -} - -static int vidioc_s_ctrl(struct file *file, void *fh, - struct v4l2_control *a) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - mutex_lock(&cam->mutex); - rval = vidioc_int_s_ctrl(cam->sdev, a); - mutex_unlock(&cam->mutex); - - return rval; -} - -static int vidioc_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) { - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - int rval; - - mutex_lock(&cam->mutex); - rval = vidioc_int_g_parm(cam->sdev, a); - mutex_unlock(&cam->mutex); - - return rval; -} - -static int vidioc_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) -{ - struct omap24xxcam_fh *ofh = fh; - struct omap24xxcam_device *cam = ofh->cam; - struct v4l2_streamparm old_streamparm; - int rval; - - mutex_lock(&cam->mutex); - if (cam->streaming) { - rval = -EBUSY; - goto out; - } - - old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - rval = vidioc_int_g_parm(cam->sdev, &old_streamparm); - if (rval) - goto out; - - rval = vidioc_int_s_parm(cam->sdev, a); - if (rval) - goto out; - - rval = omap24xxcam_sensor_if_enable(cam); - /* - * Revert to old streaming parameters if enabling sensor - * interface with the new ones failed. - */ - if (rval) - vidioc_int_s_parm(cam->sdev, &old_streamparm); - -out: - mutex_unlock(&cam->mutex); - - return rval; -} - -/* - * - * File operations. - * - */ - -static unsigned int omap24xxcam_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct omap24xxcam_fh *fh = file->private_data; - struct omap24xxcam_device *cam = fh->cam; - struct videobuf_buffer *vb; - - mutex_lock(&cam->mutex); - if (cam->streaming != file) { - mutex_unlock(&cam->mutex); - return POLLERR; - } - mutex_unlock(&cam->mutex); - - mutex_lock(&fh->vbq.vb_lock); - if (list_empty(&fh->vbq.stream)) { - mutex_unlock(&fh->vbq.vb_lock); - return POLLERR; - } - vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream); - mutex_unlock(&fh->vbq.vb_lock); - - poll_wait(file, &vb->done, wait); - - if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR) - return POLLIN | POLLRDNORM; - - return 0; -} - -static int omap24xxcam_mmap_buffers(struct file *file, - struct vm_area_struct *vma) -{ - struct omap24xxcam_fh *fh = file->private_data; - struct omap24xxcam_device *cam = fh->cam; - struct videobuf_queue *vbq = &fh->vbq; - unsigned int first, last, size, i, j; - int err = 0; - - mutex_lock(&cam->mutex); - if (cam->streaming) { - mutex_unlock(&cam->mutex); - return -EBUSY; - } - mutex_unlock(&cam->mutex); - mutex_lock(&vbq->vb_lock); - - /* look for first buffer to map */ - for (first = 0; first < VIDEO_MAX_FRAME; first++) { - if (NULL == vbq->bufs[first]) - continue; - if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory) - continue; - if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) - break; - } - - /* look for last buffer to map */ - for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { - if (NULL == vbq->bufs[last]) - continue; - if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory) - continue; - size += vbq->bufs[last]->bsize; - if (size == (vma->vm_end - vma->vm_start)) - break; - } - - size = 0; - for (i = first; i <= last && i < VIDEO_MAX_FRAME; i++) { - struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]); - - for (j = 0; j < dma->sglen; j++) { - err = remap_pfn_range( - vma, vma->vm_start + size, - page_to_pfn(sg_page(&dma->sglist[j])), - sg_dma_len(&dma->sglist[j]), vma->vm_page_prot); - if (err) - goto out; - size += sg_dma_len(&dma->sglist[j]); - } - } - -out: - mutex_unlock(&vbq->vb_lock); - - return err; -} - -static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct omap24xxcam_fh *fh = file->private_data; - int rval; - - /* let the video-buf mapper check arguments and set-up structures */ - rval = videobuf_mmap_mapper(&fh->vbq, vma); - if (rval) - return rval; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - /* do mapping to our allocated buffers */ - rval = omap24xxcam_mmap_buffers(file, vma); - /* - * In case of error, free vma->vm_private_data allocated by - * videobuf_mmap_mapper. - */ - if (rval) - kfree(vma->vm_private_data); - - return rval; -} - -static int omap24xxcam_open(struct file *file) -{ - struct omap24xxcam_device *cam = omap24xxcam.priv; - struct omap24xxcam_fh *fh; - struct v4l2_format format; - - if (!cam || !cam->vfd) - return -ENODEV; - - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (fh == NULL) - return -ENOMEM; - - mutex_lock(&cam->mutex); - if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) { - mutex_unlock(&cam->mutex); - goto out_try_module_get; - } - - if (atomic_inc_return(&cam->users) == 1) { - omap24xxcam_hwinit(cam); - if (omap24xxcam_sensor_enable(cam)) { - mutex_unlock(&cam->mutex); - goto out_omap24xxcam_sensor_enable; - } - } - mutex_unlock(&cam->mutex); - - fh->cam = cam; - mutex_lock(&cam->mutex); - vidioc_int_g_fmt_cap(cam->sdev, &format); - mutex_unlock(&cam->mutex); - /* FIXME: how about fh->pix when there are more users? */ - fh->pix = format.fmt.pix; - - file->private_data = fh; - - spin_lock_init(&fh->vbq_lock); - - videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL, - &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), fh, NULL); - - return 0; - -out_omap24xxcam_sensor_enable: - omap24xxcam_poweron_reset(cam); - module_put(cam->sdev->module); - -out_try_module_get: - kfree(fh); - - return -ENODEV; -} - -static int omap24xxcam_release(struct file *file) -{ - struct omap24xxcam_fh *fh = file->private_data; - struct omap24xxcam_device *cam = fh->cam; - - atomic_inc(&cam->reset_disable); - - flush_work_sync(&cam->sensor_reset_work); - - /* stop streaming capture */ - videobuf_streamoff(&fh->vbq); - - mutex_lock(&cam->mutex); - if (cam->streaming == file) { - cam->streaming = NULL; - mutex_unlock(&cam->mutex); - sysfs_notify(&cam->dev->kobj, NULL, "streaming"); - } else { - mutex_unlock(&cam->mutex); - } - - atomic_dec(&cam->reset_disable); - - omap24xxcam_vbq_free_mmap_buffers(&fh->vbq); - - /* - * Make sure the reset work we might have scheduled is not - * pending! It may be run *only* if we have users. (And it may - * not be scheduled anymore since streaming is already - * disabled.) - */ - flush_work_sync(&cam->sensor_reset_work); - - mutex_lock(&cam->mutex); - if (atomic_dec_return(&cam->users) == 0) { - omap24xxcam_sensor_disable(cam); - omap24xxcam_poweron_reset(cam); - } - mutex_unlock(&cam->mutex); - - file->private_data = NULL; - - module_put(cam->sdev->module); - kfree(fh); - - return 0; -} - -static struct v4l2_file_operations omap24xxcam_fops = { - .ioctl = video_ioctl2, - .poll = omap24xxcam_poll, - .mmap = omap24xxcam_mmap, - .open = omap24xxcam_open, - .release = omap24xxcam_release, -}; - -/* - * - * Power management. - * - */ - -#ifdef CONFIG_PM -static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct omap24xxcam_device *cam = platform_get_drvdata(pdev); - - if (atomic_read(&cam->users) == 0) - return 0; - - if (!atomic_read(&cam->reset_disable)) - omap24xxcam_capture_stop(cam); - - omap24xxcam_sensor_disable(cam); - omap24xxcam_poweron_reset(cam); - - return 0; -} - -static int omap24xxcam_resume(struct platform_device *pdev) -{ - struct omap24xxcam_device *cam = platform_get_drvdata(pdev); - - if (atomic_read(&cam->users) == 0) - return 0; - - omap24xxcam_hwinit(cam); - omap24xxcam_sensor_enable(cam); - - if (!atomic_read(&cam->reset_disable)) - omap24xxcam_capture_cont(cam); - - return 0; -} -#endif /* CONFIG_PM */ - -static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_s_parm = vidioc_s_parm, -}; - -/* - * - * Camera device (i.e. /dev/video). - * - */ - -static int omap24xxcam_device_register(struct v4l2_int_device *s) -{ - struct omap24xxcam_device *cam = s->u.slave->master->priv; - struct video_device *vfd; - int rval; - - /* We already have a slave. */ - if (cam->sdev) - return -EBUSY; - - cam->sdev = s; - - if (device_create_file(cam->dev, &dev_attr_streaming) != 0) { - dev_err(cam->dev, "could not register sysfs entry\n"); - rval = -EBUSY; - goto err; - } - - /* initialize the video_device struct */ - vfd = cam->vfd = video_device_alloc(); - if (!vfd) { - dev_err(cam->dev, "could not allocate video device struct\n"); - rval = -ENOMEM; - goto err; - } - vfd->release = video_device_release; - - vfd->parent = cam->dev; - - strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name)); - vfd->fops = &omap24xxcam_fops; - vfd->ioctl_ops = &omap24xxcam_ioctl_fops; - - omap24xxcam_hwinit(cam); - - rval = omap24xxcam_sensor_init(cam); - if (rval) - goto err; - - if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) { - dev_err(cam->dev, "could not register V4L device\n"); - rval = -EBUSY; - goto err; - } - - omap24xxcam_poweron_reset(cam); - - dev_info(cam->dev, "registered device %s\n", - video_device_node_name(vfd)); - - return 0; - -err: - omap24xxcam_device_unregister(s); - - return rval; -} - -static void omap24xxcam_device_unregister(struct v4l2_int_device *s) -{ - struct omap24xxcam_device *cam = s->u.slave->master->priv; - - omap24xxcam_sensor_exit(cam); - - if (cam->vfd) { - if (!video_is_registered(cam->vfd)) { - /* - * The device was never registered, so release the - * video_device struct directly. - */ - video_device_release(cam->vfd); - } else { - /* - * The unregister function will release the - * video_device struct as well as - * unregistering it. - */ - video_unregister_device(cam->vfd); - } - cam->vfd = NULL; - } - - device_remove_file(cam->dev, &dev_attr_streaming); - - cam->sdev = NULL; -} - -static struct v4l2_int_master omap24xxcam_master = { - .attach = omap24xxcam_device_register, - .detach = omap24xxcam_device_unregister, -}; - -static struct v4l2_int_device omap24xxcam = { - .module = THIS_MODULE, - .name = CAM_NAME, - .type = v4l2_int_type_master, - .u = { - .master = &omap24xxcam_master - }, -}; - -/* - * - * Driver initialisation and deinitialisation. - * - */ - -static int __devinit omap24xxcam_probe(struct platform_device *pdev) -{ - struct omap24xxcam_device *cam; - struct resource *mem; - int irq; - - cam = kzalloc(sizeof(*cam), GFP_KERNEL); - if (!cam) { - dev_err(&pdev->dev, "could not allocate memory\n"); - goto err; - } - - platform_set_drvdata(pdev, cam); - - cam->dev = &pdev->dev; - - /* - * Impose a lower limit on the amount of memory allocated for - * capture. We require at least enough memory to double-buffer - * QVGA (300KB). - */ - if (capture_mem < 320 * 240 * 2 * 2) - capture_mem = 320 * 240 * 2 * 2; - cam->capture_mem = capture_mem; - - /* request the mem region for the camera registers */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(cam->dev, "no mem resource?\n"); - goto err; - } - if (!request_mem_region(mem->start, (mem->end - mem->start) + 1, - pdev->name)) { - dev_err(cam->dev, - "cannot reserve camera register I/O region\n"); - goto err; - } - cam->mmio_base_phys = mem->start; - cam->mmio_size = (mem->end - mem->start) + 1; - - /* map the region */ - cam->mmio_base = (unsigned long) - ioremap_nocache(cam->mmio_base_phys, cam->mmio_size); - if (!cam->mmio_base) { - dev_err(cam->dev, "cannot map camera register I/O region\n"); - goto err; - } - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(cam->dev, "no irq for camera?\n"); - goto err; - } - - /* install the interrupt service routine */ - if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) { - dev_err(cam->dev, - "could not install interrupt service routine\n"); - goto err; - } - cam->irq = irq; - - if (omap24xxcam_clock_get(cam)) - goto err; - - INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work); - - mutex_init(&cam->mutex); - spin_lock_init(&cam->core_enable_disable_lock); - - omap24xxcam_sgdma_init(&cam->sgdma, - cam->mmio_base + CAMDMA_REG_OFFSET, - omap24xxcam_stalled_dma_reset, - (unsigned long)cam); - - omap24xxcam.priv = cam; - - if (v4l2_int_device_register(&omap24xxcam)) - goto err; - - return 0; - -err: - omap24xxcam_remove(pdev); - return -ENODEV; -} - -static int omap24xxcam_remove(struct platform_device *pdev) -{ - struct omap24xxcam_device *cam = platform_get_drvdata(pdev); - - if (!cam) - return 0; - - if (omap24xxcam.priv != NULL) - v4l2_int_device_unregister(&omap24xxcam); - omap24xxcam.priv = NULL; - - omap24xxcam_clock_put(cam); - - if (cam->irq) { - free_irq(cam->irq, cam); - cam->irq = 0; - } - - if (cam->mmio_base) { - iounmap((void *)cam->mmio_base); - cam->mmio_base = 0; - } - - if (cam->mmio_base_phys) { - release_mem_region(cam->mmio_base_phys, cam->mmio_size); - cam->mmio_base_phys = 0; - } - - kfree(cam); - - return 0; -} - -static struct platform_driver omap24xxcam_driver = { - .probe = omap24xxcam_probe, - .remove = omap24xxcam_remove, -#ifdef CONFIG_PM - .suspend = omap24xxcam_suspend, - .resume = omap24xxcam_resume, -#endif - .driver = { - .name = CAM_NAME, - .owner = THIS_MODULE, - }, -}; - -/* - * - * Module initialisation and deinitialisation - * - */ - -static int __init omap24xxcam_init(void) -{ - return platform_driver_register(&omap24xxcam_driver); -} - -static void __exit omap24xxcam_cleanup(void) -{ - platform_driver_unregister(&omap24xxcam_driver); -} - -MODULE_AUTHOR("Sakari Ailus "); -MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver"); -MODULE_LICENSE("GPL"); -module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr, - "Minor number for video device (-1 ==> auto assign)"); -module_param(capture_mem, int, 0); -MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture " - "buffers (default 4800kiB)"); - -module_init(omap24xxcam_init); -module_exit(omap24xxcam_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam-dma.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam-dma.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam-dma.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam-dma.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,601 +0,0 @@ -/* - * drivers/media/video/omap24xxcam-dma.c - * - * Copyright (C) 2004 MontaVista Software, Inc. - * Copyright (C) 2004 Texas Instruments. - * Copyright (C) 2007 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * Based on code from Andy Lowe and - * David Cohen . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include - -#include "omap24xxcam.h" - -/* - * - * DMA hardware. - * - */ - -/* Ack all interrupt on CSR and IRQSTATUS_L0 */ -static void omap24xxcam_dmahw_ack_all(unsigned long base) -{ - u32 csr; - int i; - - for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) { - csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i)); - /* ack interrupt in CSR */ - omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr); - } - omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf); -} - -/* Ack dmach on CSR and IRQSTATUS_L0 */ -static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach) -{ - u32 csr; - - csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach)); - /* ack interrupt in CSR */ - omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr); - /* ack interrupt in IRQSTATUS */ - omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach)); - - return csr; -} - -static int omap24xxcam_dmahw_running(unsigned long base, int dmach) -{ - return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE; -} - -static void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach, - dma_addr_t start, u32 len) -{ - omap24xxcam_reg_out(base, CAMDMA_CCR(dmach), - CAMDMA_CCR_SEL_SRC_DST_SYNC - | CAMDMA_CCR_BS - | CAMDMA_CCR_DST_AMODE_POST_INC - | CAMDMA_CCR_SRC_AMODE_POST_INC - | CAMDMA_CCR_FS - | CAMDMA_CCR_WR_ACTIVE - | CAMDMA_CCR_RD_ACTIVE - | CAMDMA_CCR_SYNCHRO_CAMERA); - omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0); - omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len); - omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1); - omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach), - CAMDMA_CSDP_WRITE_MODE_POSTED - | CAMDMA_CSDP_DST_BURST_EN_32 - | CAMDMA_CSDP_DST_PACKED - | CAMDMA_CSDP_SRC_BURST_EN_32 - | CAMDMA_CSDP_SRC_PACKED - | CAMDMA_CSDP_DATA_TYPE_8BITS); - omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0); - omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start); - omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0); - omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD); - omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0); - omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0); - omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), - CAMDMA_CSR_MISALIGNED_ERR - | CAMDMA_CSR_SECURE_ERR - | CAMDMA_CSR_TRANS_ERR - | CAMDMA_CSR_BLOCK - | CAMDMA_CSR_DROP); - omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), - CAMDMA_CICR_MISALIGNED_ERR_IE - | CAMDMA_CICR_SECURE_ERR_IE - | CAMDMA_CICR_TRANS_ERR_IE - | CAMDMA_CICR_BLOCK_IE - | CAMDMA_CICR_DROP_IE); -} - -static void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach) -{ - omap24xxcam_reg_out(base, CAMDMA_CCR(dmach), - CAMDMA_CCR_SEL_SRC_DST_SYNC - | CAMDMA_CCR_BS - | CAMDMA_CCR_DST_AMODE_POST_INC - | CAMDMA_CCR_SRC_AMODE_POST_INC - | CAMDMA_CCR_ENABLE - | CAMDMA_CCR_FS - | CAMDMA_CCR_SYNCHRO_CAMERA); -} - -static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach, - int free_dmach) -{ - int prev_dmach, ch; - - if (dmach == 0) - prev_dmach = NUM_CAMDMA_CHANNELS - 1; - else - prev_dmach = dmach - 1; - omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach), - CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach); - /* Did we chain the DMA transfer before the previous one - * finished? - */ - ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS; - while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch)) - & CAMDMA_CCR_ENABLE)) { - if (ch == dmach) { - /* The previous transfer has ended and this one - * hasn't started, so we must not have chained - * to the previous one in time. We'll have to - * start it now. - */ - omap24xxcam_dmahw_transfer_start(base, dmach); - break; - } else - ch = (ch + 1) % NUM_CAMDMA_CHANNELS; - } -} - -/* Abort all chained DMA transfers. After all transfers have been - * aborted and the DMA controller is idle, the completion routines for - * any aborted transfers will be called in sequence. The DMA - * controller may not be idle after this routine completes, because - * the completion routines might start new transfers. - */ -static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach) -{ - /* mask all interrupts from this channel */ - omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0); - /* unlink this channel */ - omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0, - CAMDMA_CLNK_CTRL_ENABLE_LNK); - /* disable this channel */ - omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE); -} - -static void omap24xxcam_dmahw_init(unsigned long base) -{ - omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG, - CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY - | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE - | CAMDMA_OCP_SYSCONFIG_AUTOIDLE); - - omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10, - CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH); - - omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf); -} - -/* - * - * Individual DMA channel handling. - * - */ - -/* Start a DMA transfer from the camera to memory. - * Returns zero if the transfer was successfully started, or non-zero if all - * DMA channels are already in use or starting is currently inhibited. - */ -static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start, - u32 len, dma_callback_t callback, void *arg) -{ - unsigned long flags; - int dmach; - - spin_lock_irqsave(&dma->lock, flags); - - if (!dma->free_dmach || atomic_read(&dma->dma_stop)) { - spin_unlock_irqrestore(&dma->lock, flags); - return -EBUSY; - } - - dmach = dma->next_dmach; - - dma->ch_state[dmach].callback = callback; - dma->ch_state[dmach].arg = arg; - - omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len); - - /* We're ready to start the DMA transfer. */ - - if (dma->free_dmach < NUM_CAMDMA_CHANNELS) { - /* A transfer is already in progress, so try to chain to it. */ - omap24xxcam_dmahw_transfer_chain(dma->base, dmach, - dma->free_dmach); - } else { - /* No transfer is in progress, so we'll just start this one - * now. - */ - omap24xxcam_dmahw_transfer_start(dma->base, dmach); - } - - dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS; - dma->free_dmach--; - - spin_unlock_irqrestore(&dma->lock, flags); - - return 0; -} - -/* Abort all chained DMA transfers. After all transfers have been - * aborted and the DMA controller is idle, the completion routines for - * any aborted transfers will be called in sequence. The DMA - * controller may not be idle after this routine completes, because - * the completion routines might start new transfers. - */ -static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr) -{ - unsigned long flags; - int dmach, i, free_dmach; - dma_callback_t callback; - void *arg; - - spin_lock_irqsave(&dma->lock, flags); - - /* stop any DMA transfers in progress */ - dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS; - for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) { - omap24xxcam_dmahw_abort_ch(dma->base, dmach); - dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS; - } - - /* We have to be careful here because the callback routine - * might start a new DMA transfer, and we only want to abort - * transfers that were started before this routine was called. - */ - free_dmach = dma->free_dmach; - while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) && - (free_dmach < NUM_CAMDMA_CHANNELS)) { - dmach = (dma->next_dmach + dma->free_dmach) - % NUM_CAMDMA_CHANNELS; - callback = dma->ch_state[dmach].callback; - arg = dma->ch_state[dmach].arg; - dma->free_dmach++; - free_dmach++; - if (callback) { - /* leave interrupts disabled during callback */ - spin_unlock(&dma->lock); - (*callback) (dma, csr, arg); - spin_lock(&dma->lock); - } - } - - spin_unlock_irqrestore(&dma->lock, flags); -} - -/* Abort all chained DMA transfers. After all transfers have been - * aborted and the DMA controller is idle, the completion routines for - * any aborted transfers will be called in sequence. If the completion - * routines attempt to start a new DMA transfer it will fail, so the - * DMA controller will be idle after this routine completes. - */ -static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr) -{ - atomic_inc(&dma->dma_stop); - omap24xxcam_dma_abort(dma, csr); - atomic_dec(&dma->dma_stop); -} - -/* Camera DMA interrupt service routine. */ -void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma) -{ - int dmach; - dma_callback_t callback; - void *arg; - u32 csr; - const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR - | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR - | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; - - spin_lock(&dma->lock); - - if (dma->free_dmach == NUM_CAMDMA_CHANNELS) { - /* A camera DMA interrupt occurred while all channels - * are idle, so we'll acknowledge the interrupt in the - * IRQSTATUS register and exit. - */ - omap24xxcam_dmahw_ack_all(dma->base); - spin_unlock(&dma->lock); - return; - } - - while (dma->free_dmach < NUM_CAMDMA_CHANNELS) { - dmach = (dma->next_dmach + dma->free_dmach) - % NUM_CAMDMA_CHANNELS; - if (omap24xxcam_dmahw_running(dma->base, dmach)) { - /* This buffer hasn't finished yet, so we're done. */ - break; - } - csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach); - if (csr & csr_error) { - /* A DMA error occurred, so stop all DMA - * transfers in progress. - */ - spin_unlock(&dma->lock); - omap24xxcam_dma_stop(dma, csr); - return; - } else { - callback = dma->ch_state[dmach].callback; - arg = dma->ch_state[dmach].arg; - dma->free_dmach++; - if (callback) { - spin_unlock(&dma->lock); - (*callback) (dma, csr, arg); - spin_lock(&dma->lock); - } - } - } - - spin_unlock(&dma->lock); - - omap24xxcam_sgdma_process( - container_of(dma, struct omap24xxcam_sgdma, dma)); -} - -void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma) -{ - unsigned long flags; - - spin_lock_irqsave(&dma->lock, flags); - - omap24xxcam_dmahw_init(dma->base); - - spin_unlock_irqrestore(&dma->lock, flags); -} - -static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma, - unsigned long base) -{ - int ch; - - /* group all channels on DMA IRQ0 and unmask irq */ - spin_lock_init(&dma->lock); - dma->base = base; - dma->free_dmach = NUM_CAMDMA_CHANNELS; - dma->next_dmach = 0; - for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) { - dma->ch_state[ch].callback = NULL; - dma->ch_state[ch].arg = NULL; - } -} - -/* - * - * Scatter-gather DMA. - * - * High-level DMA construct for transferring whole picture frames to - * memory that is discontinuous. - * - */ - -/* DMA completion routine for the scatter-gather DMA fragments. */ -static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr, - void *arg) -{ - struct omap24xxcam_sgdma *sgdma = - container_of(dma, struct omap24xxcam_sgdma, dma); - int sgslot = (int)arg; - struct sgdma_state *sg_state; - const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR - | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR - | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; - - spin_lock(&sgdma->lock); - - /* We got an interrupt, we can remove the timer */ - del_timer(&sgdma->reset_timer); - - sg_state = sgdma->sg_state + sgslot; - if (!sg_state->queued_sglist) { - spin_unlock(&sgdma->lock); - printk(KERN_ERR "%s: sgdma completed when none queued!\n", - __func__); - return; - } - - sg_state->csr |= csr; - if (!--sg_state->queued_sglist) { - /* Queue for this sglist is empty, so check to see if we're - * done. - */ - if ((sg_state->next_sglist == sg_state->sglen) - || (sg_state->csr & csr_error)) { - sgdma_callback_t callback = sg_state->callback; - void *arg = sg_state->arg; - u32 sg_csr = sg_state->csr; - /* All done with this sglist */ - sgdma->free_sgdma++; - if (callback) { - spin_unlock(&sgdma->lock); - (*callback) (sgdma, sg_csr, arg); - return; - } - } - } - - spin_unlock(&sgdma->lock); -} - -/* Start queued scatter-gather DMA transfers. */ -void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma) -{ - unsigned long flags; - int queued_sgdma, sgslot; - struct sgdma_state *sg_state; - const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR - | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR - | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; - - spin_lock_irqsave(&sgdma->lock, flags); - - queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma; - sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA; - while (queued_sgdma > 0) { - sg_state = sgdma->sg_state + sgslot; - while ((sg_state->next_sglist < sg_state->sglen) && - !(sg_state->csr & csr_error)) { - const struct scatterlist *sglist; - unsigned int len; - - sglist = sg_state->sglist + sg_state->next_sglist; - /* try to start the next DMA transfer */ - if (sg_state->next_sglist + 1 == sg_state->sglen) { - /* - * On the last sg, we handle the case where - * cam->img.pix.sizeimage % PAGE_ALIGN != 0 - */ - len = sg_state->len - sg_state->bytes_read; - } else { - len = sg_dma_len(sglist); - } - - if (omap24xxcam_dma_start(&sgdma->dma, - sg_dma_address(sglist), - len, - omap24xxcam_sgdma_callback, - (void *)sgslot)) { - /* DMA start failed */ - spin_unlock_irqrestore(&sgdma->lock, flags); - return; - } else { - unsigned long expires; - /* DMA start was successful */ - sg_state->next_sglist++; - sg_state->bytes_read += len; - sg_state->queued_sglist++; - - /* We start the reset timer */ - expires = jiffies + HZ; - mod_timer(&sgdma->reset_timer, expires); - } - } - queued_sgdma--; - sgslot = (sgslot + 1) % NUM_SG_DMA; - } - - spin_unlock_irqrestore(&sgdma->lock, flags); -} - -/* - * Queue a scatter-gather DMA transfer from the camera to memory. - * Returns zero if the transfer was successfully queued, or non-zero - * if all of the scatter-gather slots are already in use. - */ -int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma, - const struct scatterlist *sglist, int sglen, - int len, sgdma_callback_t callback, void *arg) -{ - unsigned long flags; - struct sgdma_state *sg_state; - - if ((sglen < 0) || ((sglen > 0) & !sglist)) - return -EINVAL; - - spin_lock_irqsave(&sgdma->lock, flags); - - if (!sgdma->free_sgdma) { - spin_unlock_irqrestore(&sgdma->lock, flags); - return -EBUSY; - } - - sg_state = sgdma->sg_state + sgdma->next_sgdma; - - sg_state->sglist = sglist; - sg_state->sglen = sglen; - sg_state->next_sglist = 0; - sg_state->bytes_read = 0; - sg_state->len = len; - sg_state->queued_sglist = 0; - sg_state->csr = 0; - sg_state->callback = callback; - sg_state->arg = arg; - - sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA; - sgdma->free_sgdma--; - - spin_unlock_irqrestore(&sgdma->lock, flags); - - omap24xxcam_sgdma_process(sgdma); - - return 0; -} - -/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress. - * Any queued scatter-gather DMA transactions that have not yet been started - * will remain queued. The DMA controller will be idle after this routine - * completes. When the scatter-gather queue is restarted, the next - * scatter-gather DMA transfer will begin at the start of a new transaction. - */ -void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma) -{ - unsigned long flags; - int sgslot; - struct sgdma_state *sg_state; - u32 csr = CAMDMA_CSR_TRANS_ERR; - - /* stop any DMA transfers in progress */ - omap24xxcam_dma_stop(&sgdma->dma, csr); - - spin_lock_irqsave(&sgdma->lock, flags); - - if (sgdma->free_sgdma < NUM_SG_DMA) { - sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA; - sg_state = sgdma->sg_state + sgslot; - if (sg_state->next_sglist != 0) { - /* This DMA transfer was in progress, so abort it. */ - sgdma_callback_t callback = sg_state->callback; - void *arg = sg_state->arg; - sgdma->free_sgdma++; - if (callback) { - /* leave interrupts masked */ - spin_unlock(&sgdma->lock); - (*callback) (sgdma, csr, arg); - spin_lock(&sgdma->lock); - } - } - } - - spin_unlock_irqrestore(&sgdma->lock, flags); -} - -void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma, - unsigned long base, - void (*reset_callback)(unsigned long data), - unsigned long reset_callback_data) -{ - int sg; - - spin_lock_init(&sgdma->lock); - sgdma->free_sgdma = NUM_SG_DMA; - sgdma->next_sgdma = 0; - for (sg = 0; sg < NUM_SG_DMA; sg++) { - sgdma->sg_state[sg].sglen = 0; - sgdma->sg_state[sg].next_sglist = 0; - sgdma->sg_state[sg].bytes_read = 0; - sgdma->sg_state[sg].queued_sglist = 0; - sgdma->sg_state[sg].csr = 0; - sgdma->sg_state[sg].callback = NULL; - sgdma->sg_state[sg].arg = NULL; - } - - omap24xxcam_dma_init(&sgdma->dma, base); - setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap24xxcam.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,593 +0,0 @@ -/* - * drivers/media/video/omap24xxcam.h - * - * Copyright (C) 2004 MontaVista Software, Inc. - * Copyright (C) 2004 Texas Instruments. - * Copyright (C) 2007 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * Based on code from Andy Lowe . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP24XXCAM_H -#define OMAP24XXCAM_H - -#include -#include - -/* - * - * General driver related definitions. - * - */ - -#define CAM_NAME "omap24xxcam" - -#define CAM_MCLK 96000000 - -/* number of bytes transferred per DMA request */ -#define DMA_THRESHOLD 32 - -/* - * NUM_CAMDMA_CHANNELS is the number of logical channels provided by - * the camera DMA controller. - */ -#define NUM_CAMDMA_CHANNELS 4 - -/* - * NUM_SG_DMA is the number of scatter-gather DMA transfers that can - * be queued. (We don't have any overlay sglists now.) - */ -#define NUM_SG_DMA (VIDEO_MAX_FRAME) - -/* - * - * Register definitions. - * - */ - -/* subsystem register block offsets */ -#define CC_REG_OFFSET 0x00000400 -#define CAMDMA_REG_OFFSET 0x00000800 -#define CAMMMU_REG_OFFSET 0x00000C00 - -/* define camera subsystem register offsets */ -#define CAM_REVISION 0x000 -#define CAM_SYSCONFIG 0x010 -#define CAM_SYSSTATUS 0x014 -#define CAM_IRQSTATUS 0x018 -#define CAM_GPO 0x040 -#define CAM_GPI 0x050 - -/* define camera core register offsets */ -#define CC_REVISION 0x000 -#define CC_SYSCONFIG 0x010 -#define CC_SYSSTATUS 0x014 -#define CC_IRQSTATUS 0x018 -#define CC_IRQENABLE 0x01C -#define CC_CTRL 0x040 -#define CC_CTRL_DMA 0x044 -#define CC_CTRL_XCLK 0x048 -#define CC_FIFODATA 0x04C -#define CC_TEST 0x050 -#define CC_GENPAR 0x054 -#define CC_CCPFSCR 0x058 -#define CC_CCPFECR 0x05C -#define CC_CCPLSCR 0x060 -#define CC_CCPLECR 0x064 -#define CC_CCPDFR 0x068 - -/* define camera dma register offsets */ -#define CAMDMA_REVISION 0x000 -#define CAMDMA_IRQSTATUS_L0 0x008 -#define CAMDMA_IRQSTATUS_L1 0x00C -#define CAMDMA_IRQSTATUS_L2 0x010 -#define CAMDMA_IRQSTATUS_L3 0x014 -#define CAMDMA_IRQENABLE_L0 0x018 -#define CAMDMA_IRQENABLE_L1 0x01C -#define CAMDMA_IRQENABLE_L2 0x020 -#define CAMDMA_IRQENABLE_L3 0x024 -#define CAMDMA_SYSSTATUS 0x028 -#define CAMDMA_OCP_SYSCONFIG 0x02C -#define CAMDMA_CAPS_0 0x064 -#define CAMDMA_CAPS_2 0x06C -#define CAMDMA_CAPS_3 0x070 -#define CAMDMA_CAPS_4 0x074 -#define CAMDMA_GCR 0x078 -#define CAMDMA_CCR(n) (0x080 + (n)*0x60) -#define CAMDMA_CLNK_CTRL(n) (0x084 + (n)*0x60) -#define CAMDMA_CICR(n) (0x088 + (n)*0x60) -#define CAMDMA_CSR(n) (0x08C + (n)*0x60) -#define CAMDMA_CSDP(n) (0x090 + (n)*0x60) -#define CAMDMA_CEN(n) (0x094 + (n)*0x60) -#define CAMDMA_CFN(n) (0x098 + (n)*0x60) -#define CAMDMA_CSSA(n) (0x09C + (n)*0x60) -#define CAMDMA_CDSA(n) (0x0A0 + (n)*0x60) -#define CAMDMA_CSEI(n) (0x0A4 + (n)*0x60) -#define CAMDMA_CSFI(n) (0x0A8 + (n)*0x60) -#define CAMDMA_CDEI(n) (0x0AC + (n)*0x60) -#define CAMDMA_CDFI(n) (0x0B0 + (n)*0x60) -#define CAMDMA_CSAC(n) (0x0B4 + (n)*0x60) -#define CAMDMA_CDAC(n) (0x0B8 + (n)*0x60) -#define CAMDMA_CCEN(n) (0x0BC + (n)*0x60) -#define CAMDMA_CCFN(n) (0x0C0 + (n)*0x60) -#define CAMDMA_COLOR(n) (0x0C4 + (n)*0x60) - -/* define camera mmu register offsets */ -#define CAMMMU_REVISION 0x000 -#define CAMMMU_SYSCONFIG 0x010 -#define CAMMMU_SYSSTATUS 0x014 -#define CAMMMU_IRQSTATUS 0x018 -#define CAMMMU_IRQENABLE 0x01C -#define CAMMMU_WALKING_ST 0x040 -#define CAMMMU_CNTL 0x044 -#define CAMMMU_FAULT_AD 0x048 -#define CAMMMU_TTB 0x04C -#define CAMMMU_LOCK 0x050 -#define CAMMMU_LD_TLB 0x054 -#define CAMMMU_CAM 0x058 -#define CAMMMU_RAM 0x05C -#define CAMMMU_GFLUSH 0x060 -#define CAMMMU_FLUSH_ENTRY 0x064 -#define CAMMMU_READ_CAM 0x068 -#define CAMMMU_READ_RAM 0x06C -#define CAMMMU_EMU_FAULT_AD 0x070 - -/* Define bit fields within selected registers */ -#define CAM_REVISION_MAJOR (15 << 4) -#define CAM_REVISION_MAJOR_SHIFT 4 -#define CAM_REVISION_MINOR (15 << 0) -#define CAM_REVISION_MINOR_SHIFT 0 - -#define CAM_SYSCONFIG_SOFTRESET (1 << 1) -#define CAM_SYSCONFIG_AUTOIDLE (1 << 0) - -#define CAM_SYSSTATUS_RESETDONE (1 << 0) - -#define CAM_IRQSTATUS_CC_IRQ (1 << 4) -#define CAM_IRQSTATUS_MMU_IRQ (1 << 3) -#define CAM_IRQSTATUS_DMA_IRQ2 (1 << 2) -#define CAM_IRQSTATUS_DMA_IRQ1 (1 << 1) -#define CAM_IRQSTATUS_DMA_IRQ0 (1 << 0) - -#define CAM_GPO_CAM_S_P_EN (1 << 1) -#define CAM_GPO_CAM_CCP_MODE (1 << 0) - -#define CAM_GPI_CC_DMA_REQ1 (1 << 24) -#define CAP_GPI_CC_DMA_REQ0 (1 << 23) -#define CAP_GPI_CAM_MSTANDBY (1 << 21) -#define CAP_GPI_CAM_WAIT (1 << 20) -#define CAP_GPI_CAM_S_DATA (1 << 17) -#define CAP_GPI_CAM_S_CLK (1 << 16) -#define CAP_GPI_CAM_P_DATA (0xFFF << 3) -#define CAP_GPI_CAM_P_DATA_SHIFT 3 -#define CAP_GPI_CAM_P_VS (1 << 2) -#define CAP_GPI_CAM_P_HS (1 << 1) -#define CAP_GPI_CAM_P_CLK (1 << 0) - -#define CC_REVISION_MAJOR (15 << 4) -#define CC_REVISION_MAJOR_SHIFT 4 -#define CC_REVISION_MINOR (15 << 0) -#define CC_REVISION_MINOR_SHIFT 0 - -#define CC_SYSCONFIG_SIDLEMODE (3 << 3) -#define CC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3) -#define CC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3) -#define CC_SYSCONFIG_SOFTRESET (1 << 1) -#define CC_SYSCONFIG_AUTOIDLE (1 << 0) - -#define CC_SYSSTATUS_RESETDONE (1 << 0) - -#define CC_IRQSTATUS_FS_IRQ (1 << 19) -#define CC_IRQSTATUS_LE_IRQ (1 << 18) -#define CC_IRQSTATUS_LS_IRQ (1 << 17) -#define CC_IRQSTATUS_FE_IRQ (1 << 16) -#define CC_IRQSTATUS_FW_ERR_IRQ (1 << 10) -#define CC_IRQSTATUS_FSC_ERR_IRQ (1 << 9) -#define CC_IRQSTATUS_SSC_ERR_IRQ (1 << 8) -#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ (1 << 4) -#define CC_IRQSTATUS_FIFO_FULL_IRQ (1 << 3) -#define CC_IRQSTATUS_FIFO_THR_IRQ (1 << 2) -#define CC_IRQSTATUS_FIFO_OF_IRQ (1 << 1) -#define CC_IRQSTATUS_FIFO_UF_IRQ (1 << 0) - -#define CC_IRQENABLE_FS_IRQ (1 << 19) -#define CC_IRQENABLE_LE_IRQ (1 << 18) -#define CC_IRQENABLE_LS_IRQ (1 << 17) -#define CC_IRQENABLE_FE_IRQ (1 << 16) -#define CC_IRQENABLE_FW_ERR_IRQ (1 << 10) -#define CC_IRQENABLE_FSC_ERR_IRQ (1 << 9) -#define CC_IRQENABLE_SSC_ERR_IRQ (1 << 8) -#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ (1 << 4) -#define CC_IRQENABLE_FIFO_FULL_IRQ (1 << 3) -#define CC_IRQENABLE_FIFO_THR_IRQ (1 << 2) -#define CC_IRQENABLE_FIFO_OF_IRQ (1 << 1) -#define CC_IRQENABLE_FIFO_UF_IRQ (1 << 0) - -#define CC_CTRL_CC_ONE_SHOT (1 << 20) -#define CC_CTRL_CC_IF_SYNCHRO (1 << 19) -#define CC_CTRL_CC_RST (1 << 18) -#define CC_CTRL_CC_FRAME_TRIG (1 << 17) -#define CC_CTRL_CC_EN (1 << 16) -#define CC_CTRL_NOBT_SYNCHRO (1 << 13) -#define CC_CTRL_BT_CORRECT (1 << 12) -#define CC_CTRL_PAR_ORDERCAM (1 << 11) -#define CC_CTRL_PAR_CLK_POL (1 << 10) -#define CC_CTRL_NOBT_HS_POL (1 << 9) -#define CC_CTRL_NOBT_VS_POL (1 << 8) -#define CC_CTRL_PAR_MODE (7 << 1) -#define CC_CTRL_PAR_MODE_SHIFT 1 -#define CC_CTRL_PAR_MODE_NOBT8 (0 << 1) -#define CC_CTRL_PAR_MODE_NOBT10 (1 << 1) -#define CC_CTRL_PAR_MODE_NOBT12 (2 << 1) -#define CC_CTRL_PAR_MODE_BT8 (4 << 1) -#define CC_CTRL_PAR_MODE_BT10 (5 << 1) -#define CC_CTRL_PAR_MODE_FIFOTEST (7 << 1) -#define CC_CTRL_CCP_MODE (1 << 0) - -#define CC_CTRL_DMA_EN (1 << 8) -#define CC_CTRL_DMA_FIFO_THRESHOLD (0x7F << 0) -#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT 0 - -#define CC_CTRL_XCLK_DIV (0x1F << 0) -#define CC_CTRL_XCLK_DIV_SHIFT 0 -#define CC_CTRL_XCLK_DIV_STABLE_LOW (0 << 0) -#define CC_CTRL_XCLK_DIV_STABLE_HIGH (1 << 0) -#define CC_CTRL_XCLK_DIV_BYPASS (31 << 0) - -#define CC_TEST_FIFO_RD_POINTER (0xFF << 24) -#define CC_TEST_FIFO_RD_POINTER_SHIFT 24 -#define CC_TEST_FIFO_WR_POINTER (0xFF << 16) -#define CC_TEST_FIFO_WR_POINTER_SHIFT 16 -#define CC_TEST_FIFO_LEVEL (0xFF << 8) -#define CC_TEST_FIFO_LEVEL_SHIFT 8 -#define CC_TEST_FIFO_LEVEL_PEAK (0xFF << 0) -#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT 0 - -#define CC_GENPAR_FIFO_DEPTH (7 << 0) -#define CC_GENPAR_FIFO_DEPTH_SHIFT 0 - -#define CC_CCPDFR_ALPHA (0xFF << 8) -#define CC_CCPDFR_ALPHA_SHIFT 8 -#define CC_CCPDFR_DATAFORMAT (15 << 0) -#define CC_CCPDFR_DATAFORMAT_SHIFT 0 -#define CC_CCPDFR_DATAFORMAT_YUV422BE (0 << 0) -#define CC_CCPDFR_DATAFORMAT_YUV422 (1 << 0) -#define CC_CCPDFR_DATAFORMAT_YUV420 (2 << 0) -#define CC_CCPDFR_DATAFORMAT_RGB444 (4 << 0) -#define CC_CCPDFR_DATAFORMAT_RGB565 (5 << 0) -#define CC_CCPDFR_DATAFORMAT_RGB888NDE (6 << 0) -#define CC_CCPDFR_DATAFORMAT_RGB888 (7 << 0) -#define CC_CCPDFR_DATAFORMAT_RAW8NDE (8 << 0) -#define CC_CCPDFR_DATAFORMAT_RAW8 (9 << 0) -#define CC_CCPDFR_DATAFORMAT_RAW10NDE (10 << 0) -#define CC_CCPDFR_DATAFORMAT_RAW10 (11 << 0) -#define CC_CCPDFR_DATAFORMAT_RAW12NDE (12 << 0) -#define CC_CCPDFR_DATAFORMAT_RAW12 (13 << 0) -#define CC_CCPDFR_DATAFORMAT_JPEG8 (15 << 0) - -#define CAMDMA_REVISION_MAJOR (15 << 4) -#define CAMDMA_REVISION_MAJOR_SHIFT 4 -#define CAMDMA_REVISION_MINOR (15 << 0) -#define CAMDMA_REVISION_MINOR_SHIFT 0 - -#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE (3 << 12) -#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12) -#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12) -#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12) -#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK (1 << 9) -#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK (1 << 8) -#define CAMDMA_OCP_SYSCONFIG_EMUFREE (1 << 5) -#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE (3 << 3) -#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3) -#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3) -#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3) -#define CAMDMA_OCP_SYSCONFIG_SOFTRESET (1 << 1) -#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE (1 << 0) - -#define CAMDMA_SYSSTATUS_RESETDONE (1 << 0) - -#define CAMDMA_GCR_ARBITRATION_RATE (0xFF << 16) -#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT 16 -#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH (0xFF << 0) -#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT 0 - -#define CAMDMA_CCR_SEL_SRC_DST_SYNC (1 << 24) -#define CAMDMA_CCR_PREFETCH (1 << 23) -#define CAMDMA_CCR_SUPERVISOR (1 << 22) -#define CAMDMA_CCR_SECURE (1 << 21) -#define CAMDMA_CCR_BS (1 << 18) -#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE (1 << 17) -#define CAMDMA_CCR_CONSTANT_FILL_ENABLE (1 << 16) -#define CAMDMA_CCR_DST_AMODE (3 << 14) -#define CAMDMA_CCR_DST_AMODE_CONST_ADDR (0 << 14) -#define CAMDMA_CCR_DST_AMODE_POST_INC (1 << 14) -#define CAMDMA_CCR_DST_AMODE_SGL_IDX (2 << 14) -#define CAMDMA_CCR_DST_AMODE_DBL_IDX (3 << 14) -#define CAMDMA_CCR_SRC_AMODE (3 << 12) -#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR (0 << 12) -#define CAMDMA_CCR_SRC_AMODE_POST_INC (1 << 12) -#define CAMDMA_CCR_SRC_AMODE_SGL_IDX (2 << 12) -#define CAMDMA_CCR_SRC_AMODE_DBL_IDX (3 << 12) -#define CAMDMA_CCR_WR_ACTIVE (1 << 10) -#define CAMDMA_CCR_RD_ACTIVE (1 << 9) -#define CAMDMA_CCR_SUSPEND_SENSITIVE (1 << 8) -#define CAMDMA_CCR_ENABLE (1 << 7) -#define CAMDMA_CCR_PRIO (1 << 6) -#define CAMDMA_CCR_FS (1 << 5) -#define CAMDMA_CCR_SYNCHRO ((3 << 19) | (31 << 0)) -#define CAMDMA_CCR_SYNCHRO_CAMERA 0x01 - -#define CAMDMA_CLNK_CTRL_ENABLE_LNK (1 << 15) -#define CAMDMA_CLNK_CTRL_NEXTLCH_ID (0x1F << 0) -#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT 0 - -#define CAMDMA_CICR_MISALIGNED_ERR_IE (1 << 11) -#define CAMDMA_CICR_SUPERVISOR_ERR_IE (1 << 10) -#define CAMDMA_CICR_SECURE_ERR_IE (1 << 9) -#define CAMDMA_CICR_TRANS_ERR_IE (1 << 8) -#define CAMDMA_CICR_PACKET_IE (1 << 7) -#define CAMDMA_CICR_BLOCK_IE (1 << 5) -#define CAMDMA_CICR_LAST_IE (1 << 4) -#define CAMDMA_CICR_FRAME_IE (1 << 3) -#define CAMDMA_CICR_HALF_IE (1 << 2) -#define CAMDMA_CICR_DROP_IE (1 << 1) - -#define CAMDMA_CSR_MISALIGNED_ERR (1 << 11) -#define CAMDMA_CSR_SUPERVISOR_ERR (1 << 10) -#define CAMDMA_CSR_SECURE_ERR (1 << 9) -#define CAMDMA_CSR_TRANS_ERR (1 << 8) -#define CAMDMA_CSR_PACKET (1 << 7) -#define CAMDMA_CSR_SYNC (1 << 6) -#define CAMDMA_CSR_BLOCK (1 << 5) -#define CAMDMA_CSR_LAST (1 << 4) -#define CAMDMA_CSR_FRAME (1 << 3) -#define CAMDMA_CSR_HALF (1 << 2) -#define CAMDMA_CSR_DROP (1 << 1) - -#define CAMDMA_CSDP_SRC_ENDIANNESS (1 << 21) -#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK (1 << 20) -#define CAMDMA_CSDP_DST_ENDIANNESS (1 << 19) -#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK (1 << 18) -#define CAMDMA_CSDP_WRITE_MODE (3 << 16) -#define CAMDMA_CSDP_WRITE_MODE_WRNP (0 << 16) -#define CAMDMA_CSDP_WRITE_MODE_POSTED (1 << 16) -#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP (2 << 16) -#define CAMDMA_CSDP_DST_BURST_EN (3 << 14) -#define CAMDMA_CSDP_DST_BURST_EN_1 (0 << 14) -#define CAMDMA_CSDP_DST_BURST_EN_16 (1 << 14) -#define CAMDMA_CSDP_DST_BURST_EN_32 (2 << 14) -#define CAMDMA_CSDP_DST_BURST_EN_64 (3 << 14) -#define CAMDMA_CSDP_DST_PACKED (1 << 13) -#define CAMDMA_CSDP_WR_ADD_TRSLT (15 << 9) -#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD (3 << 9) -#define CAMDMA_CSDP_SRC_BURST_EN (3 << 7) -#define CAMDMA_CSDP_SRC_BURST_EN_1 (0 << 7) -#define CAMDMA_CSDP_SRC_BURST_EN_16 (1 << 7) -#define CAMDMA_CSDP_SRC_BURST_EN_32 (2 << 7) -#define CAMDMA_CSDP_SRC_BURST_EN_64 (3 << 7) -#define CAMDMA_CSDP_SRC_PACKED (1 << 6) -#define CAMDMA_CSDP_RD_ADD_TRSLT (15 << 2) -#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD (3 << 2) -#define CAMDMA_CSDP_DATA_TYPE (3 << 0) -#define CAMDMA_CSDP_DATA_TYPE_8BITS (0 << 0) -#define CAMDMA_CSDP_DATA_TYPE_16BITS (1 << 0) -#define CAMDMA_CSDP_DATA_TYPE_32BITS (2 << 0) - -#define CAMMMU_SYSCONFIG_AUTOIDLE (1 << 0) - -/* - * - * Declarations. - * - */ - -/* forward declarations */ -struct omap24xxcam_sgdma; -struct omap24xxcam_dma; - -typedef void (*sgdma_callback_t)(struct omap24xxcam_sgdma *cam, - u32 status, void *arg); -typedef void (*dma_callback_t)(struct omap24xxcam_dma *cam, - u32 status, void *arg); - -struct channel_state { - dma_callback_t callback; - void *arg; -}; - -/* sgdma state for each of the possible videobuf_buffers + 2 overlays */ -struct sgdma_state { - const struct scatterlist *sglist; - int sglen; /* number of sglist entries */ - int next_sglist; /* index of next sglist entry to process */ - unsigned int bytes_read; /* number of bytes read */ - unsigned int len; /* total length of sglist (excluding - * bytes due to page alignment) */ - int queued_sglist; /* number of sglist entries queued for DMA */ - u32 csr; /* DMA return code */ - sgdma_callback_t callback; - void *arg; -}; - -/* physical DMA channel management */ -struct omap24xxcam_dma { - spinlock_t lock; /* Lock for the whole structure. */ - - unsigned long base; /* base address for dma controller */ - - /* While dma_stop!=0, an attempt to start a new DMA transfer will - * fail. - */ - atomic_t dma_stop; - int free_dmach; /* number of dma channels free */ - int next_dmach; /* index of next dma channel to use */ - struct channel_state ch_state[NUM_CAMDMA_CHANNELS]; -}; - -/* scatter-gather DMA (scatterlist stuff) management */ -struct omap24xxcam_sgdma { - struct omap24xxcam_dma dma; - - spinlock_t lock; /* Lock for the fields below. */ - int free_sgdma; /* number of free sg dma slots */ - int next_sgdma; /* index of next sg dma slot to use */ - struct sgdma_state sg_state[NUM_SG_DMA]; - - /* Reset timer data */ - struct timer_list reset_timer; -}; - -/* per-device data structure */ -struct omap24xxcam_device { - /*** mutex ***/ - /* - * mutex serialises access to this structure. Also camera - * opening and releasing is synchronised by this. - */ - struct mutex mutex; - - /*** general driver state information ***/ - atomic_t users; - /* - * Lock to serialise core enabling and disabling and access to - * sgdma_in_queue. - */ - spinlock_t core_enable_disable_lock; - /* - * Number or sgdma requests in scatter-gather queue, protected - * by the lock above. - */ - int sgdma_in_queue; - /* - * Sensor interface parameters: interface type, CC_CTRL - * register value and interface specific data. - */ - int if_type; - union { - struct parallel { - u32 xclk; - } bt656; - } if_u; - u32 cc_ctrl; - - /*** subsystem structures ***/ - struct omap24xxcam_sgdma sgdma; - - /*** hardware resources ***/ - unsigned int irq; - unsigned long mmio_base; - unsigned long mmio_base_phys; - unsigned long mmio_size; - - /*** interfaces and device ***/ - struct v4l2_int_device *sdev; - struct device *dev; - struct video_device *vfd; - - /*** camera and sensor reset related stuff ***/ - struct work_struct sensor_reset_work; - /* - * We're in the middle of a reset. Don't enable core if this - * is non-zero! This exists to help decisionmaking in a case - * where videobuf_qbuf is called while we are in the middle of - * a reset. - */ - atomic_t in_reset; - /* - * Non-zero if we don't want any resets for now. Used to - * prevent reset work to run when we're about to stop - * streaming. - */ - atomic_t reset_disable; - - /*** video device parameters ***/ - int capture_mem; - - /*** camera module clocks ***/ - struct clk *fck; - struct clk *ick; - - /*** capture data ***/ - /* file handle, if streaming is on */ - struct file *streaming; -}; - -/* Per-file handle data. */ -struct omap24xxcam_fh { - spinlock_t vbq_lock; /* spinlock for the videobuf queue */ - struct videobuf_queue vbq; - struct v4l2_pix_format pix; /* serialise pix by vbq->lock */ - atomic_t field_count; /* field counter for videobuf_buffer */ - /* accessing cam here doesn't need serialisation: it's constant */ - struct omap24xxcam_device *cam; -}; - -/* - * - * Register I/O functions. - * - */ - -static inline u32 omap24xxcam_reg_in(unsigned long base, u32 offset) -{ - return readl(base + offset); -} - -static inline u32 omap24xxcam_reg_out(unsigned long base, u32 offset, - u32 val) -{ - writel(val, base + offset); - return val; -} - -static inline u32 omap24xxcam_reg_merge(unsigned long base, u32 offset, - u32 val, u32 mask) -{ - u32 addr = base + offset; - u32 new_val = (readl(addr) & ~mask) | (val & mask); - - writel(new_val, addr); - return new_val; -} - -/* - * - * Function prototypes. - * - */ - -/* dma prototypes */ - -void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma); -void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma); - -/* sgdma prototypes */ - -void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma); -int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma, - const struct scatterlist *sglist, int sglen, - int len, sgdma_callback_t callback, void *arg); -void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma); -void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma, - unsigned long base, - void (*reset_callback)(unsigned long data), - unsigned long reset_callback_data); -void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/cfa_coef_table.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/cfa_coef_table.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/cfa_coef_table.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/cfa_coef_table.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* - * cfa_coef_table.h - * - * TI OMAP3 ISP - CFA coefficients table - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, -248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250, -247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248, -244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, -248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250, -247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248, -244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, -248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250, -247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248, - 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4, - 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0, - 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0, - 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4, - 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0, - 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0, - 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4, - 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0, - 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0, - 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0, - 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12, - 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0, - 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0, - 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12, - 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0, - 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0, - 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12, - 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0, -244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244, -248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247, -250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248, -244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244, -248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247, -250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248, -244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244, -248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247, -250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/gamma_table.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/gamma_table.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/gamma_table.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/gamma_table.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -/* - * gamma_table.h - * - * TI OMAP3 ISP - Default gamma table for all components - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - - 0, 0, 1, 2, 3, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, - 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 36, 37, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 63, 64, 65, 66, 66, 67, 68, 69, 69, 70, - 71, 72, 72, 73, 74, 75, 75, 76, 77, 78, 78, 79, 80, 81, 81, 82, - 83, 84, 84, 85, 86, 87, 88, 88, 89, 90, 91, 91, 92, 93, 94, 94, - 95, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 103, 104, 104, -105, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 114, 114, 115, 116, 117, -117, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, -126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, -134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, -142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149, -150, 150, 151, 151, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, -156, 156, 157, 157, 158, 158, 158, 159, 159, 159, 160, 160, 160, 161, 161, 162, -162, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 167, 167, 168, -168, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 173, 173, 174, -174, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179, -179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183, -183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187, -187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, -191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195, -195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199, -199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 203, 203, -203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207, -207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210, -210, 210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, -211, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, -213, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, -216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219, -219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221, -221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 223, -223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 225, -225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226, -226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228, -228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230, -230, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 232, 232, -232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, -233, 233, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 235, -235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, -236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, -238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, -238, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240, -240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, -240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242, -242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, -242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, -244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, -244, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, -246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, -246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 248, -248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, -248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 250, 250, -250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, -250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, -250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, -252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, -252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, -252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, -252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, -253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, -253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, -253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, -253, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isp.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isp.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isp.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isp.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2220 +0,0 @@ -/* - * isp.c - * - * TI OMAP3 ISP - Core - * - * Copyright (C) 2006-2010 Nokia Corporation - * Copyright (C) 2007-2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * Contributors: - * Laurent Pinchart - * Sakari Ailus - * David Cohen - * Stanimir Varbanov - * Vimarsh Zutshi - * Tuukka Toivonen - * Sergio Aguirre - * Antti Koskipaa - * Ivan T. Ivanov - * RaniSuneela - * Atanas Filipov - * Gjorgji Rosikopulos - * Hiroshi DOYU - * Nayden Kanchev - * Phil Carmody - * Artem Bityutskiy - * Dominic Curran - * Ilkka Myllyperkio - * Pallavi Kulkarni - * Vaibhav Hiremath - * Mohit Jalori - * Sameer Venkatraman - * Senthilvadivu Guruswamy - * Thara Gopinath - * Toni Leinonen - * Troy Laramy - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "isp.h" -#include "ispreg.h" -#include "ispccdc.h" -#include "isppreview.h" -#include "ispresizer.h" -#include "ispcsi2.h" -#include "ispccp2.h" -#include "isph3a.h" -#include "isphist.h" - -static unsigned int autoidle; -module_param(autoidle, int, 0444); -MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support"); - -static void isp_save_ctx(struct isp_device *isp); - -static void isp_restore_ctx(struct isp_device *isp); - -static const struct isp_res_mapping isp_res_maps[] = { - { - .isp_rev = ISP_REVISION_2_0, - .map = 1 << OMAP3_ISP_IOMEM_MAIN | - 1 << OMAP3_ISP_IOMEM_CCP2 | - 1 << OMAP3_ISP_IOMEM_CCDC | - 1 << OMAP3_ISP_IOMEM_HIST | - 1 << OMAP3_ISP_IOMEM_H3A | - 1 << OMAP3_ISP_IOMEM_PREV | - 1 << OMAP3_ISP_IOMEM_RESZ | - 1 << OMAP3_ISP_IOMEM_SBL | - 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 | - 1 << OMAP3_ISP_IOMEM_CSIPHY2, - }, - { - .isp_rev = ISP_REVISION_15_0, - .map = 1 << OMAP3_ISP_IOMEM_MAIN | - 1 << OMAP3_ISP_IOMEM_CCP2 | - 1 << OMAP3_ISP_IOMEM_CCDC | - 1 << OMAP3_ISP_IOMEM_HIST | - 1 << OMAP3_ISP_IOMEM_H3A | - 1 << OMAP3_ISP_IOMEM_PREV | - 1 << OMAP3_ISP_IOMEM_RESZ | - 1 << OMAP3_ISP_IOMEM_SBL | - 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 | - 1 << OMAP3_ISP_IOMEM_CSIPHY2 | - 1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 | - 1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 | - 1 << OMAP3_ISP_IOMEM_CSIPHY1 | - 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2, - }, -}; - -/* Structure for saving/restoring ISP module registers */ -static struct isp_reg isp_reg_list[] = { - {OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG, 0}, - {OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, 0}, - {OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, 0}, - {0, ISP_TOK_TERM, 0} -}; - -/* - * omap3isp_flush - Post pending L3 bus writes by doing a register readback - * @isp: OMAP3 ISP device - * - * In order to force posting of pending writes, we need to write and - * readback the same register, in this case the revision register. - * - * See this link for reference: - * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html - */ -void omap3isp_flush(struct isp_device *isp) -{ - isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); - isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); -} - -/* - * isp_enable_interrupts - Enable ISP interrupts. - * @isp: OMAP3 ISP device - */ -static void isp_enable_interrupts(struct isp_device *isp) -{ - static const u32 irq = IRQ0ENABLE_CSIA_IRQ - | IRQ0ENABLE_CSIB_IRQ - | IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ - | IRQ0ENABLE_CCDC_LSC_DONE_IRQ - | IRQ0ENABLE_CCDC_VD0_IRQ - | IRQ0ENABLE_CCDC_VD1_IRQ - | IRQ0ENABLE_HS_VS_IRQ - | IRQ0ENABLE_HIST_DONE_IRQ - | IRQ0ENABLE_H3A_AWB_DONE_IRQ - | IRQ0ENABLE_H3A_AF_DONE_IRQ - | IRQ0ENABLE_PRV_DONE_IRQ - | IRQ0ENABLE_RSZ_DONE_IRQ; - - isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); - isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE); -} - -/* - * isp_disable_interrupts - Disable ISP interrupts. - * @isp: OMAP3 ISP device - */ -static void isp_disable_interrupts(struct isp_device *isp) -{ - isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE); -} - -/** - * isp_set_xclk - Configures the specified cam_xclk to the desired frequency. - * @isp: OMAP3 ISP device - * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high - * @xclksel: XCLK to configure (0 = A, 1 = B). - * - * Configures the specified MCLK divisor in the ISP timing control register - * (TCTRL_CTRL) to generate the desired xclk clock value. - * - * Divisor = cam_mclk_hz / xclk - * - * Returns the final frequency that is actually being generated - **/ -static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) -{ - u32 divisor; - u32 currentxclk; - unsigned long mclk_hz; - - if (!omap3isp_get(isp)) - return 0; - - mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]); - - if (xclk >= mclk_hz) { - divisor = ISPTCTRL_CTRL_DIV_BYPASS; - currentxclk = mclk_hz; - } else if (xclk >= 2) { - divisor = mclk_hz / xclk; - if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS) - divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1; - currentxclk = mclk_hz / divisor; - } else { - divisor = xclk; - currentxclk = 0; - } - - switch (xclksel) { - case 0: - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, - ISPTCTRL_CTRL_DIVA_MASK, - divisor << ISPTCTRL_CTRL_DIVA_SHIFT); - dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n", - currentxclk); - break; - case 1: - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, - ISPTCTRL_CTRL_DIVB_MASK, - divisor << ISPTCTRL_CTRL_DIVB_SHIFT); - dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n", - currentxclk); - break; - default: - omap3isp_put(isp); - dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested " - "xclk. Must be 0 (A) or 1 (B).\n"); - return -EINVAL; - } - - /* Do we go from stable whatever to clock? */ - if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2) - omap3isp_get(isp); - /* Stopping the clock. */ - else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2) - omap3isp_put(isp); - - isp->xclk_divisor[xclksel] = divisor; - - omap3isp_put(isp); - - return currentxclk; -} - -/* - * isp_power_settings - Sysconfig settings, for Power Management. - * @isp: OMAP3 ISP device - * @idle: Consider idle state. - * - * Sets the power settings for the ISP, and SBL bus. - */ -static void isp_power_settings(struct isp_device *isp, int idle) -{ - isp_reg_writel(isp, - ((idle ? ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY : - ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY) << - ISP_SYSCONFIG_MIDLEMODE_SHIFT) | - ((isp->revision == ISP_REVISION_15_0) ? - ISP_SYSCONFIG_AUTOIDLE : 0), - OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG); - - if (isp->autoidle) - isp_reg_writel(isp, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN, - ISP_CTRL); -} - -/* - * Configure the bridge and lane shifter. Valid inputs are - * - * CCDC_INPUT_PARALLEL: Parallel interface - * CCDC_INPUT_CSI2A: CSI2a receiver - * CCDC_INPUT_CCP2B: CCP2b receiver - * CCDC_INPUT_CSI2C: CSI2c receiver - * - * The bridge and lane shifter are configured according to the selected input - * and the ISP platform data. - */ -void omap3isp_configure_bridge(struct isp_device *isp, - enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata) -{ - u32 ispctrl_val; - - ispctrl_val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL); - ispctrl_val &= ~ISPCTRL_SHIFT_MASK; - ispctrl_val &= ~ISPCTRL_PAR_CLK_POL_INV; - ispctrl_val &= ~ISPCTRL_PAR_SER_CLK_SEL_MASK; - ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_MASK; - - switch (input) { - case CCDC_INPUT_PARALLEL: - ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; - ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT; - ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; - ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT; - break; - - case CCDC_INPUT_CSI2A: - ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIA; - break; - - case CCDC_INPUT_CCP2B: - ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB; - break; - - case CCDC_INPUT_CSI2C: - ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIC; - break; - - default: - return; - } - - ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK; - ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE; - - isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL); -} - -/** - * isp_set_pixel_clock - Configures the ISP pixel clock - * @isp: OMAP3 ISP device - * @pixelclk: Average pixel clock in Hz - * - * Set the average pixel clock required by the sensor. The ISP will use the - * lowest possible memory bandwidth settings compatible with the clock. - **/ -static void isp_set_pixel_clock(struct isp_device *isp, unsigned int pixelclk) -{ - isp->isp_ccdc.vpcfg.pixelclk = pixelclk; -} - -void omap3isp_hist_dma_done(struct isp_device *isp) -{ - if (omap3isp_ccdc_busy(&isp->isp_ccdc) || - omap3isp_stat_pcr_busy(&isp->isp_hist)) { - /* Histogram cannot be enabled in this frame anymore */ - atomic_set(&isp->isp_hist.buf_err, 1); - dev_dbg(isp->dev, "hist: Out of synchronization with " - "CCDC. Ignoring next buffer.\n"); - } -} - -static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus) -{ - static const char *name[] = { - "CSIA_IRQ", - "res1", - "res2", - "CSIB_LCM_IRQ", - "CSIB_IRQ", - "res5", - "res6", - "res7", - "CCDC_VD0_IRQ", - "CCDC_VD1_IRQ", - "CCDC_VD2_IRQ", - "CCDC_ERR_IRQ", - "H3A_AF_DONE_IRQ", - "H3A_AWB_DONE_IRQ", - "res14", - "res15", - "HIST_DONE_IRQ", - "CCDC_LSC_DONE", - "CCDC_LSC_PREFETCH_COMPLETED", - "CCDC_LSC_PREFETCH_ERROR", - "PRV_DONE_IRQ", - "CBUFF_IRQ", - "res22", - "res23", - "RSZ_DONE_IRQ", - "OVF_IRQ", - "res26", - "res27", - "MMU_ERR_IRQ", - "OCP_ERR_IRQ", - "SEC_ERR_IRQ", - "HS_VS_IRQ", - }; - int i; - - dev_dbg(isp->dev, ""); - - for (i = 0; i < ARRAY_SIZE(name); i++) { - if ((1 << i) & irqstatus) - printk(KERN_CONT "%s ", name[i]); - } - printk(KERN_CONT "\n"); -} - -static void isp_isr_sbl(struct isp_device *isp) -{ - struct device *dev = isp->dev; - u32 sbl_pcr; - - /* - * Handle shared buffer logic overflows for video buffers. - * ISPSBL_PCR_CCDCPRV_2_RSZ_OVF can be safely ignored. - */ - sbl_pcr = isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR); - isp_reg_writel(isp, sbl_pcr, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR); - sbl_pcr &= ~ISPSBL_PCR_CCDCPRV_2_RSZ_OVF; - - if (sbl_pcr) - dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr); - - if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF - | ISPSBL_PCR_CSIB_WBL_OVF)) { - isp->isp_ccdc.error = 1; - if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW) - isp->isp_prev.error = 1; - if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER) - isp->isp_res.error = 1; - } - - if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) { - isp->isp_prev.error = 1; - if (isp->isp_res.input == RESIZER_INPUT_VP && - !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)) - isp->isp_res.error = 1; - } - - if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF - | ISPSBL_PCR_RSZ2_WBL_OVF - | ISPSBL_PCR_RSZ3_WBL_OVF - | ISPSBL_PCR_RSZ4_WBL_OVF)) - isp->isp_res.error = 1; - - if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF) - omap3isp_stat_sbl_overflow(&isp->isp_af); - - if (sbl_pcr & ISPSBL_PCR_H3A_AEAWB_WBL_OVF) - omap3isp_stat_sbl_overflow(&isp->isp_aewb); -} - -/* - * isp_isr - Interrupt Service Routine for Camera ISP module. - * @irq: Not used currently. - * @_isp: Pointer to the OMAP3 ISP device - * - * Handles the corresponding callback if plugged in. - * - * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the - * IRQ wasn't handled. - */ -static irqreturn_t isp_isr(int irq, void *_isp) -{ - static const u32 ccdc_events = IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ | - IRQ0STATUS_CCDC_LSC_DONE_IRQ | - IRQ0STATUS_CCDC_VD0_IRQ | - IRQ0STATUS_CCDC_VD1_IRQ | - IRQ0STATUS_HS_VS_IRQ; - struct isp_device *isp = _isp; - u32 irqstatus; - int ret; - - irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); - isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); - - isp_isr_sbl(isp); - - if (irqstatus & IRQ0STATUS_CSIA_IRQ) { - ret = omap3isp_csi2_isr(&isp->isp_csi2a); - if (ret) - isp->isp_ccdc.error = 1; - } - - if (irqstatus & IRQ0STATUS_CSIB_IRQ) { - ret = omap3isp_ccp2_isr(&isp->isp_ccp2); - if (ret) - isp->isp_ccdc.error = 1; - } - - if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) { - if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW) - omap3isp_preview_isr_frame_sync(&isp->isp_prev); - if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER) - omap3isp_resizer_isr_frame_sync(&isp->isp_res); - omap3isp_stat_isr_frame_sync(&isp->isp_aewb); - omap3isp_stat_isr_frame_sync(&isp->isp_af); - omap3isp_stat_isr_frame_sync(&isp->isp_hist); - } - - if (irqstatus & ccdc_events) - omap3isp_ccdc_isr(&isp->isp_ccdc, irqstatus & ccdc_events); - - if (irqstatus & IRQ0STATUS_PRV_DONE_IRQ) { - if (isp->isp_prev.output & PREVIEW_OUTPUT_RESIZER) - omap3isp_resizer_isr_frame_sync(&isp->isp_res); - omap3isp_preview_isr(&isp->isp_prev); - } - - if (irqstatus & IRQ0STATUS_RSZ_DONE_IRQ) - omap3isp_resizer_isr(&isp->isp_res); - - if (irqstatus & IRQ0STATUS_H3A_AWB_DONE_IRQ) - omap3isp_stat_isr(&isp->isp_aewb); - - if (irqstatus & IRQ0STATUS_H3A_AF_DONE_IRQ) - omap3isp_stat_isr(&isp->isp_af); - - if (irqstatus & IRQ0STATUS_HIST_DONE_IRQ) - omap3isp_stat_isr(&isp->isp_hist); - - omap3isp_flush(isp); - -#if defined(DEBUG) && defined(ISP_ISR_DEBUG) - isp_isr_dbg(isp, irqstatus); -#endif - - return IRQ_HANDLED; -} - -/* ----------------------------------------------------------------------------- - * Pipeline power management - * - * Entities must be powered up when part of a pipeline that contains at least - * one open video device node. - * - * To achieve this use the entity use_count field to track the number of users. - * For entities corresponding to video device nodes the use_count field stores - * the users count of the node. For entities corresponding to subdevs the - * use_count field stores the total number of users of all video device nodes - * in the pipeline. - * - * The omap3isp_pipeline_pm_use() function must be called in the open() and - * close() handlers of video device nodes. It increments or decrements the use - * count of all subdev entities in the pipeline. - * - * To react to link management on powered pipelines, the link setup notification - * callback updates the use count of all entities in the source and sink sides - * of the link. - */ - -/* - * isp_pipeline_pm_use_count - Count the number of users of a pipeline - * @entity: The entity - * - * Return the total number of users of all video device nodes in the pipeline. - */ -static int isp_pipeline_pm_use_count(struct media_entity *entity) -{ - struct media_entity_graph graph; - int use = 0; - - media_entity_graph_walk_start(&graph, entity); - - while ((entity = media_entity_graph_walk_next(&graph))) { - if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE) - use += entity->use_count; - } - - return use; -} - -/* - * isp_pipeline_pm_power_one - Apply power change to an entity - * @entity: The entity - * @change: Use count change - * - * Change the entity use count by @change. If the entity is a subdev update its - * power state by calling the core::s_power operation when the use count goes - * from 0 to != 0 or from != 0 to 0. - * - * Return 0 on success or a negative error code on failure. - */ -static int isp_pipeline_pm_power_one(struct media_entity *entity, int change) -{ - struct v4l2_subdev *subdev; - int ret; - - subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV - ? media_entity_to_v4l2_subdev(entity) : NULL; - - if (entity->use_count == 0 && change > 0 && subdev != NULL) { - ret = v4l2_subdev_call(subdev, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - } - - entity->use_count += change; - WARN_ON(entity->use_count < 0); - - if (entity->use_count == 0 && change < 0 && subdev != NULL) - v4l2_subdev_call(subdev, core, s_power, 0); - - return 0; -} - -/* - * isp_pipeline_pm_power - Apply power change to all entities in a pipeline - * @entity: The entity - * @change: Use count change - * - * Walk the pipeline to update the use count and the power state of all non-node - * entities. - * - * Return 0 on success or a negative error code on failure. - */ -static int isp_pipeline_pm_power(struct media_entity *entity, int change) -{ - struct media_entity_graph graph; - struct media_entity *first = entity; - int ret = 0; - - if (!change) - return 0; - - media_entity_graph_walk_start(&graph, entity); - - while (!ret && (entity = media_entity_graph_walk_next(&graph))) - if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE) - ret = isp_pipeline_pm_power_one(entity, change); - - if (!ret) - return 0; - - media_entity_graph_walk_start(&graph, first); - - while ((first = media_entity_graph_walk_next(&graph)) - && first != entity) - if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE) - isp_pipeline_pm_power_one(first, -change); - - return ret; -} - -/* - * omap3isp_pipeline_pm_use - Update the use count of an entity - * @entity: The entity - * @use: Use (1) or stop using (0) the entity - * - * Update the use count of all entities in the pipeline and power entities on or - * off accordingly. - * - * Return 0 on success or a negative error code on failure. Powering entities - * off is assumed to never fail. No failure can occur when the use parameter is - * set to 0. - */ -int omap3isp_pipeline_pm_use(struct media_entity *entity, int use) -{ - int change = use ? 1 : -1; - int ret; - - mutex_lock(&entity->parent->graph_mutex); - - /* Apply use count to node. */ - entity->use_count += change; - WARN_ON(entity->use_count < 0); - - /* Apply power change to connected non-nodes. */ - ret = isp_pipeline_pm_power(entity, change); - - mutex_unlock(&entity->parent->graph_mutex); - - return ret; -} - -/* - * isp_pipeline_link_notify - Link management notification callback - * @source: Pad at the start of the link - * @sink: Pad at the end of the link - * @flags: New link flags that will be applied - * - * React to link management on powered pipelines by updating the use count of - * all entities in the source and sink sides of the link. Entities are powered - * on or off accordingly. - * - * Return 0 on success or a negative error code on failure. Powering entities - * off is assumed to never fail. This function will not fail for disconnection - * events. - */ -static int isp_pipeline_link_notify(struct media_pad *source, - struct media_pad *sink, u32 flags) -{ - int source_use = isp_pipeline_pm_use_count(source->entity); - int sink_use = isp_pipeline_pm_use_count(sink->entity); - int ret; - - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - /* Powering off entities is assumed to never fail. */ - isp_pipeline_pm_power(source->entity, -sink_use); - isp_pipeline_pm_power(sink->entity, -source_use); - return 0; - } - - ret = isp_pipeline_pm_power(source->entity, sink_use); - if (ret < 0) - return ret; - - ret = isp_pipeline_pm_power(sink->entity, source_use); - if (ret < 0) - isp_pipeline_pm_power(source->entity, -sink_use); - - return ret; -} - -/* ----------------------------------------------------------------------------- - * Pipeline stream management - */ - -/* - * isp_pipeline_enable - Enable streaming on a pipeline - * @pipe: ISP pipeline - * @mode: Stream mode (single shot or continuous) - * - * Walk the entities chain starting at the pipeline output video node and start - * all modules in the chain in the given mode. - * - * Return 0 if successfull, or the return value of the failed video::s_stream - * operation otherwise. - */ -static int isp_pipeline_enable(struct isp_pipeline *pipe, - enum isp_pipeline_stream_state mode) -{ - struct isp_device *isp = pipe->output->isp; - struct media_entity *entity; - struct media_pad *pad; - struct v4l2_subdev *subdev; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT); - spin_unlock_irqrestore(&pipe->lock, flags); - - pipe->do_propagation = false; - - entity = &pipe->output->video.entity; - while (1) { - pad = &entity->pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - - entity = pad->entity; - subdev = media_entity_to_v4l2_subdev(entity); - - ret = v4l2_subdev_call(subdev, video, s_stream, mode); - if (ret < 0 && ret != -ENOIOCTLCMD) - break; - - if (subdev == &isp->isp_ccdc.subdev) { - v4l2_subdev_call(&isp->isp_aewb.subdev, video, - s_stream, mode); - v4l2_subdev_call(&isp->isp_af.subdev, video, - s_stream, mode); - v4l2_subdev_call(&isp->isp_hist.subdev, video, - s_stream, mode); - pipe->do_propagation = true; - } - } - - /* Frame number propagation. In continuous streaming mode the number - * is incremented in the frame start ISR. In mem-to-mem mode - * singleshot is used and frame start IRQs are not available. - * Thus we have to increment the number here. - */ - if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT) - atomic_inc(&pipe->frame_number); - - return ret; -} - -static int isp_pipeline_wait_resizer(struct isp_device *isp) -{ - return omap3isp_resizer_busy(&isp->isp_res); -} - -static int isp_pipeline_wait_preview(struct isp_device *isp) -{ - return omap3isp_preview_busy(&isp->isp_prev); -} - -static int isp_pipeline_wait_ccdc(struct isp_device *isp) -{ - return omap3isp_stat_busy(&isp->isp_af) - || omap3isp_stat_busy(&isp->isp_aewb) - || omap3isp_stat_busy(&isp->isp_hist) - || omap3isp_ccdc_busy(&isp->isp_ccdc); -} - -#define ISP_STOP_TIMEOUT msecs_to_jiffies(1000) - -static int isp_pipeline_wait(struct isp_device *isp, - int(*busy)(struct isp_device *isp)) -{ - unsigned long timeout = jiffies + ISP_STOP_TIMEOUT; - - while (!time_after(jiffies, timeout)) { - if (!busy(isp)) - return 0; - } - - return 1; -} - -/* - * isp_pipeline_disable - Disable streaming on a pipeline - * @pipe: ISP pipeline - * - * Walk the entities chain starting at the pipeline output video node and stop - * all modules in the chain. Wait synchronously for the modules to be stopped if - * necessary. - * - * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module - * can't be stopped (in which case a software reset of the ISP is probably - * necessary). - */ -static int isp_pipeline_disable(struct isp_pipeline *pipe) -{ - struct isp_device *isp = pipe->output->isp; - struct media_entity *entity; - struct media_pad *pad; - struct v4l2_subdev *subdev; - int failure = 0; - int ret; - - /* - * We need to stop all the modules after CCDC first or they'll - * never stop since they may not get a full frame from CCDC. - */ - entity = &pipe->output->video.entity; - while (1) { - pad = &entity->pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - - entity = pad->entity; - subdev = media_entity_to_v4l2_subdev(entity); - - if (subdev == &isp->isp_ccdc.subdev) { - v4l2_subdev_call(&isp->isp_aewb.subdev, - video, s_stream, 0); - v4l2_subdev_call(&isp->isp_af.subdev, - video, s_stream, 0); - v4l2_subdev_call(&isp->isp_hist.subdev, - video, s_stream, 0); - } - - v4l2_subdev_call(subdev, video, s_stream, 0); - - if (subdev == &isp->isp_res.subdev) - ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer); - else if (subdev == &isp->isp_prev.subdev) - ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview); - else if (subdev == &isp->isp_ccdc.subdev) - ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc); - else - ret = 0; - - if (ret) { - dev_info(isp->dev, "Unable to stop %s\n", subdev->name); - failure = -ETIMEDOUT; - } - } - - return failure; -} - -/* - * omap3isp_pipeline_set_stream - Enable/disable streaming on a pipeline - * @pipe: ISP pipeline - * @state: Stream state (stopped, single shot or continuous) - * - * Set the pipeline to the given stream state. Pipelines can be started in - * single-shot or continuous mode. - * - * Return 0 if successfull, or the return value of the failed video::s_stream - * operation otherwise. - */ -int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, - enum isp_pipeline_stream_state state) -{ - int ret; - - if (state == ISP_PIPELINE_STREAM_STOPPED) - ret = isp_pipeline_disable(pipe); - else - ret = isp_pipeline_enable(pipe, state); - pipe->stream_state = state; - - return ret; -} - -/* - * isp_pipeline_resume - Resume streaming on a pipeline - * @pipe: ISP pipeline - * - * Resume video output and input and re-enable pipeline. - */ -static void isp_pipeline_resume(struct isp_pipeline *pipe) -{ - int singleshot = pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT; - - omap3isp_video_resume(pipe->output, !singleshot); - if (singleshot) - omap3isp_video_resume(pipe->input, 0); - isp_pipeline_enable(pipe, pipe->stream_state); -} - -/* - * isp_pipeline_suspend - Suspend streaming on a pipeline - * @pipe: ISP pipeline - * - * Suspend pipeline. - */ -static void isp_pipeline_suspend(struct isp_pipeline *pipe) -{ - isp_pipeline_disable(pipe); -} - -/* - * isp_pipeline_is_last - Verify if entity has an enabled link to the output - * video node - * @me: ISP module's media entity - * - * Returns 1 if the entity has an enabled link to the output video node or 0 - * otherwise. It's true only while pipeline can have no more than one output - * node. - */ -static int isp_pipeline_is_last(struct media_entity *me) -{ - struct isp_pipeline *pipe; - struct media_pad *pad; - - if (!me->pipe) - return 0; - pipe = to_isp_pipeline(me); - if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED) - return 0; - pad = media_entity_remote_source(&pipe->output->pad); - return pad->entity == me; -} - -/* - * isp_suspend_module_pipeline - Suspend pipeline to which belongs the module - * @me: ISP module's media entity - * - * Suspend the whole pipeline if module's entity has an enabled link to the - * output video node. It works only while pipeline can have no more than one - * output node. - */ -static void isp_suspend_module_pipeline(struct media_entity *me) -{ - if (isp_pipeline_is_last(me)) - isp_pipeline_suspend(to_isp_pipeline(me)); -} - -/* - * isp_resume_module_pipeline - Resume pipeline to which belongs the module - * @me: ISP module's media entity - * - * Resume the whole pipeline if module's entity has an enabled link to the - * output video node. It works only while pipeline can have no more than one - * output node. - */ -static void isp_resume_module_pipeline(struct media_entity *me) -{ - if (isp_pipeline_is_last(me)) - isp_pipeline_resume(to_isp_pipeline(me)); -} - -/* - * isp_suspend_modules - Suspend ISP submodules. - * @isp: OMAP3 ISP device - * - * Returns 0 if suspend left in idle state all the submodules properly, - * or returns 1 if a general Reset is required to suspend the submodules. - */ -static int isp_suspend_modules(struct isp_device *isp) -{ - unsigned long timeout; - - omap3isp_stat_suspend(&isp->isp_aewb); - omap3isp_stat_suspend(&isp->isp_af); - omap3isp_stat_suspend(&isp->isp_hist); - isp_suspend_module_pipeline(&isp->isp_res.subdev.entity); - isp_suspend_module_pipeline(&isp->isp_prev.subdev.entity); - isp_suspend_module_pipeline(&isp->isp_ccdc.subdev.entity); - isp_suspend_module_pipeline(&isp->isp_csi2a.subdev.entity); - isp_suspend_module_pipeline(&isp->isp_ccp2.subdev.entity); - - timeout = jiffies + ISP_STOP_TIMEOUT; - while (omap3isp_stat_busy(&isp->isp_af) - || omap3isp_stat_busy(&isp->isp_aewb) - || omap3isp_stat_busy(&isp->isp_hist) - || omap3isp_preview_busy(&isp->isp_prev) - || omap3isp_resizer_busy(&isp->isp_res) - || omap3isp_ccdc_busy(&isp->isp_ccdc)) { - if (time_after(jiffies, timeout)) { - dev_info(isp->dev, "can't stop modules.\n"); - return 1; - } - msleep(1); - } - - return 0; -} - -/* - * isp_resume_modules - Resume ISP submodules. - * @isp: OMAP3 ISP device - */ -static void isp_resume_modules(struct isp_device *isp) -{ - omap3isp_stat_resume(&isp->isp_aewb); - omap3isp_stat_resume(&isp->isp_af); - omap3isp_stat_resume(&isp->isp_hist); - isp_resume_module_pipeline(&isp->isp_res.subdev.entity); - isp_resume_module_pipeline(&isp->isp_prev.subdev.entity); - isp_resume_module_pipeline(&isp->isp_ccdc.subdev.entity); - isp_resume_module_pipeline(&isp->isp_csi2a.subdev.entity); - isp_resume_module_pipeline(&isp->isp_ccp2.subdev.entity); -} - -/* - * isp_reset - Reset ISP with a timeout wait for idle. - * @isp: OMAP3 ISP device - */ -static int isp_reset(struct isp_device *isp) -{ - unsigned long timeout = 0; - - isp_reg_writel(isp, - isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG) - | ISP_SYSCONFIG_SOFTRESET, - OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG); - while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, - ISP_SYSSTATUS) & 0x1)) { - if (timeout++ > 10000) { - dev_alert(isp->dev, "cannot reset ISP\n"); - return -ETIMEDOUT; - } - udelay(1); - } - - return 0; -} - -/* - * isp_save_context - Saves the values of the ISP module registers. - * @isp: OMAP3 ISP device - * @reg_list: Structure containing pairs of register address and value to - * modify on OMAP. - */ -static void -isp_save_context(struct isp_device *isp, struct isp_reg *reg_list) -{ - struct isp_reg *next = reg_list; - - for (; next->reg != ISP_TOK_TERM; next++) - next->val = isp_reg_readl(isp, next->mmio_range, next->reg); -} - -/* - * isp_restore_context - Restores the values of the ISP module registers. - * @isp: OMAP3 ISP device - * @reg_list: Structure containing pairs of register address and value to - * modify on OMAP. - */ -static void -isp_restore_context(struct isp_device *isp, struct isp_reg *reg_list) -{ - struct isp_reg *next = reg_list; - - for (; next->reg != ISP_TOK_TERM; next++) - isp_reg_writel(isp, next->val, next->mmio_range, next->reg); -} - -/* - * isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context. - * @isp: OMAP3 ISP device - * - * Routine for saving the context of each module in the ISP. - * CCDC, HIST, H3A, PREV, RESZ and MMU. - */ -static void isp_save_ctx(struct isp_device *isp) -{ - isp_save_context(isp, isp_reg_list); - if (isp->iommu) - iommu_save_ctx(isp->iommu); -} - -/* - * isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context. - * @isp: OMAP3 ISP device - * - * Routine for restoring the context of each module in the ISP. - * CCDC, HIST, H3A, PREV, RESZ and MMU. - */ -static void isp_restore_ctx(struct isp_device *isp) -{ - isp_restore_context(isp, isp_reg_list); - if (isp->iommu) - iommu_restore_ctx(isp->iommu); - omap3isp_ccdc_restore_context(isp); - omap3isp_preview_restore_context(isp); -} - -/* ----------------------------------------------------------------------------- - * SBL resources management - */ -#define OMAP3_ISP_SBL_READ (OMAP3_ISP_SBL_CSI1_READ | \ - OMAP3_ISP_SBL_CCDC_LSC_READ | \ - OMAP3_ISP_SBL_PREVIEW_READ | \ - OMAP3_ISP_SBL_RESIZER_READ) -#define OMAP3_ISP_SBL_WRITE (OMAP3_ISP_SBL_CSI1_WRITE | \ - OMAP3_ISP_SBL_CSI2A_WRITE | \ - OMAP3_ISP_SBL_CSI2C_WRITE | \ - OMAP3_ISP_SBL_CCDC_WRITE | \ - OMAP3_ISP_SBL_PREVIEW_WRITE) - -void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res) -{ - u32 sbl = 0; - - isp->sbl_resources |= res; - - if (isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ) - sbl |= ISPCTRL_SBL_SHARED_RPORTA; - - if (isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ) - sbl |= ISPCTRL_SBL_SHARED_RPORTB; - - if (isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE) - sbl |= ISPCTRL_SBL_SHARED_WPORTC; - - if (isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE) - sbl |= ISPCTRL_SBL_WR0_RAM_EN; - - if (isp->sbl_resources & OMAP3_ISP_SBL_WRITE) - sbl |= ISPCTRL_SBL_WR1_RAM_EN; - - if (isp->sbl_resources & OMAP3_ISP_SBL_READ) - sbl |= ISPCTRL_SBL_RD_RAM_EN; - - isp_reg_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl); -} - -void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res) -{ - u32 sbl = 0; - - isp->sbl_resources &= ~res; - - if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ)) - sbl |= ISPCTRL_SBL_SHARED_RPORTA; - - if (!(isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ)) - sbl |= ISPCTRL_SBL_SHARED_RPORTB; - - if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE)) - sbl |= ISPCTRL_SBL_SHARED_WPORTC; - - if (!(isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE)) - sbl |= ISPCTRL_SBL_WR0_RAM_EN; - - if (!(isp->sbl_resources & OMAP3_ISP_SBL_WRITE)) - sbl |= ISPCTRL_SBL_WR1_RAM_EN; - - if (!(isp->sbl_resources & OMAP3_ISP_SBL_READ)) - sbl |= ISPCTRL_SBL_RD_RAM_EN; - - isp_reg_clr(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl); -} - -/* - * isp_module_sync_idle - Helper to sync module with its idle state - * @me: ISP submodule's media entity - * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization - * @stopping: flag which tells module wants to stop - * - * This function checks if ISP submodule needs to wait for next interrupt. If - * yes, makes the caller to sleep while waiting for such event. - */ -int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, - atomic_t *stopping) -{ - struct isp_pipeline *pipe = to_isp_pipeline(me); - - if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED || - (pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT && - !isp_pipeline_ready(pipe))) - return 0; - - /* - * atomic_set() doesn't include memory barrier on ARM platform for SMP - * scenario. We'll call it here to avoid race conditions. - */ - atomic_set(stopping, 1); - smp_mb(); - - /* - * If module is the last one, it's writing to memory. In this case, - * it's necessary to check if the module is already paused due to - * DMA queue underrun or if it has to wait for next interrupt to be - * idle. - * If it isn't the last one, the function won't sleep but *stopping - * will still be set to warn next submodule caller's interrupt the - * module wants to be idle. - */ - if (isp_pipeline_is_last(me)) { - struct isp_video *video = pipe->output; - unsigned long flags; - spin_lock_irqsave(&video->queue->irqlock, flags); - if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { - spin_unlock_irqrestore(&video->queue->irqlock, flags); - atomic_set(stopping, 0); - smp_mb(); - return 0; - } - spin_unlock_irqrestore(&video->queue->irqlock, flags); - if (!wait_event_timeout(*wait, !atomic_read(stopping), - msecs_to_jiffies(1000))) { - atomic_set(stopping, 0); - smp_mb(); - return -ETIMEDOUT; - } - } - - return 0; -} - -/* - * omap3isp_module_sync_is_stopped - Helper to verify if module was stopping - * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization - * @stopping: flag which tells module wants to stop - * - * This function checks if ISP submodule was stopping. In case of yes, it - * notices the caller by setting stopping to 0 and waking up the wait queue. - * Returns 1 if it was stopping or 0 otherwise. - */ -int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait, - atomic_t *stopping) -{ - if (atomic_cmpxchg(stopping, 1, 0)) { - wake_up(wait); - return 1; - } - - return 0; -} - -/* -------------------------------------------------------------------------- - * Clock management - */ - -#define ISPCTRL_CLKS_MASK (ISPCTRL_H3A_CLK_EN | \ - ISPCTRL_HIST_CLK_EN | \ - ISPCTRL_RSZ_CLK_EN | \ - (ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN) | \ - (ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN)) - -static void __isp_subclk_update(struct isp_device *isp) -{ - u32 clk = 0; - - if (isp->subclk_resources & OMAP3_ISP_SUBCLK_H3A) - clk |= ISPCTRL_H3A_CLK_EN; - - if (isp->subclk_resources & OMAP3_ISP_SUBCLK_HIST) - clk |= ISPCTRL_HIST_CLK_EN; - - if (isp->subclk_resources & OMAP3_ISP_SUBCLK_RESIZER) - clk |= ISPCTRL_RSZ_CLK_EN; - - /* NOTE: For CCDC & Preview submodules, we need to affect internal - * RAM aswell. - */ - if (isp->subclk_resources & OMAP3_ISP_SUBCLK_CCDC) - clk |= ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN; - - if (isp->subclk_resources & OMAP3_ISP_SUBCLK_PREVIEW) - clk |= ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN; - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, - ISPCTRL_CLKS_MASK, clk); -} - -void omap3isp_subclk_enable(struct isp_device *isp, - enum isp_subclk_resource res) -{ - isp->subclk_resources |= res; - - __isp_subclk_update(isp); -} - -void omap3isp_subclk_disable(struct isp_device *isp, - enum isp_subclk_resource res) -{ - isp->subclk_resources &= ~res; - - __isp_subclk_update(isp); -} - -/* - * isp_enable_clocks - Enable ISP clocks - * @isp: OMAP3 ISP device - * - * Return 0 if successful, or clk_enable return value if any of tthem fails. - */ -static int isp_enable_clocks(struct isp_device *isp) -{ - int r; - unsigned long rate; - int divisor; - - /* - * cam_mclk clock chain: - * dpll4 -> dpll4_m5 -> dpll4_m5x2 -> cam_mclk - * - * In OMAP3630 dpll4_m5x2 != 2 x dpll4_m5 but both are - * set to the same value. Hence the rate set for dpll4_m5 - * has to be twice of what is set on OMAP3430 to get - * the required value for cam_mclk - */ - if (cpu_is_omap3630()) - divisor = 1; - else - divisor = 2; - - r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]); - if (r) { - dev_err(isp->dev, "clk_enable cam_ick failed\n"); - goto out_clk_enable_ick; - } - r = clk_set_rate(isp->clock[ISP_CLK_DPLL4_M5_CK], - CM_CAM_MCLK_HZ/divisor); - if (r) { - dev_err(isp->dev, "clk_set_rate for dpll4_m5_ck failed\n"); - goto out_clk_enable_mclk; - } - r = clk_enable(isp->clock[ISP_CLK_CAM_MCLK]); - if (r) { - dev_err(isp->dev, "clk_enable cam_mclk failed\n"); - goto out_clk_enable_mclk; - } - rate = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]); - if (rate != CM_CAM_MCLK_HZ) - dev_warn(isp->dev, "unexpected cam_mclk rate:\n" - " expected : %d\n" - " actual : %ld\n", CM_CAM_MCLK_HZ, rate); - r = clk_enable(isp->clock[ISP_CLK_CSI2_FCK]); - if (r) { - dev_err(isp->dev, "clk_enable csi2_fck failed\n"); - goto out_clk_enable_csi2_fclk; - } - return 0; - -out_clk_enable_csi2_fclk: - clk_disable(isp->clock[ISP_CLK_CAM_MCLK]); -out_clk_enable_mclk: - clk_disable(isp->clock[ISP_CLK_CAM_ICK]); -out_clk_enable_ick: - return r; -} - -/* - * isp_disable_clocks - Disable ISP clocks - * @isp: OMAP3 ISP device - */ -static void isp_disable_clocks(struct isp_device *isp) -{ - clk_disable(isp->clock[ISP_CLK_CAM_ICK]); - clk_disable(isp->clock[ISP_CLK_CAM_MCLK]); - clk_disable(isp->clock[ISP_CLK_CSI2_FCK]); -} - -static const char *isp_clocks[] = { - "cam_ick", - "cam_mclk", - "dpll4_m5_ck", - "csi2_96m_fck", - "l3_ick", -}; - -static void isp_put_clocks(struct isp_device *isp) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) { - if (isp->clock[i]) { - clk_put(isp->clock[i]); - isp->clock[i] = NULL; - } - } -} - -static int isp_get_clocks(struct isp_device *isp) -{ - struct clk *clk; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) { - clk = clk_get(isp->dev, isp_clocks[i]); - if (IS_ERR(clk)) { - dev_err(isp->dev, "clk_get %s failed\n", isp_clocks[i]); - isp_put_clocks(isp); - return PTR_ERR(clk); - } - - isp->clock[i] = clk; - } - - return 0; -} - -/* - * omap3isp_get - Acquire the ISP resource. - * - * Initializes the clocks for the first acquire. - * - * Increment the reference count on the ISP. If the first reference is taken, - * enable clocks and power-up all submodules. - * - * Return a pointer to the ISP device structure, or NULL if an error occured. - */ -struct isp_device *omap3isp_get(struct isp_device *isp) -{ - struct isp_device *__isp = isp; - - if (isp == NULL) - return NULL; - - mutex_lock(&isp->isp_mutex); - if (isp->ref_count > 0) - goto out; - - if (isp_enable_clocks(isp) < 0) { - __isp = NULL; - goto out; - } - - /* We don't want to restore context before saving it! */ - if (isp->has_context) - isp_restore_ctx(isp); - else - isp->has_context = 1; - - isp_enable_interrupts(isp); - -out: - if (__isp != NULL) - isp->ref_count++; - mutex_unlock(&isp->isp_mutex); - - return __isp; -} - -/* - * omap3isp_put - Release the ISP - * - * Decrement the reference count on the ISP. If the last reference is released, - * power-down all submodules, disable clocks and free temporary buffers. - */ -void omap3isp_put(struct isp_device *isp) -{ - if (isp == NULL) - return; - - mutex_lock(&isp->isp_mutex); - BUG_ON(isp->ref_count == 0); - if (--isp->ref_count == 0) { - isp_disable_interrupts(isp); - isp_save_ctx(isp); - isp_disable_clocks(isp); - } - mutex_unlock(&isp->isp_mutex); -} - -/* -------------------------------------------------------------------------- - * Platform device driver - */ - -/* - * omap3isp_print_status - Prints the values of the ISP Control Module registers - * @isp: OMAP3 ISP device - */ -#define ISP_PRINT_REGISTER(isp, name)\ - dev_dbg(isp->dev, "###ISP " #name "=0x%08x\n", \ - isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_##name)) -#define SBL_PRINT_REGISTER(isp, name)\ - dev_dbg(isp->dev, "###SBL " #name "=0x%08x\n", \ - isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_##name)) - -void omap3isp_print_status(struct isp_device *isp) -{ - dev_dbg(isp->dev, "-------------ISP Register dump--------------\n"); - - ISP_PRINT_REGISTER(isp, SYSCONFIG); - ISP_PRINT_REGISTER(isp, SYSSTATUS); - ISP_PRINT_REGISTER(isp, IRQ0ENABLE); - ISP_PRINT_REGISTER(isp, IRQ0STATUS); - ISP_PRINT_REGISTER(isp, TCTRL_GRESET_LENGTH); - ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_REPLAY); - ISP_PRINT_REGISTER(isp, CTRL); - ISP_PRINT_REGISTER(isp, TCTRL_CTRL); - ISP_PRINT_REGISTER(isp, TCTRL_FRAME); - ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_DELAY); - ISP_PRINT_REGISTER(isp, TCTRL_STRB_DELAY); - ISP_PRINT_REGISTER(isp, TCTRL_SHUT_DELAY); - ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_LENGTH); - ISP_PRINT_REGISTER(isp, TCTRL_STRB_LENGTH); - ISP_PRINT_REGISTER(isp, TCTRL_SHUT_LENGTH); - - SBL_PRINT_REGISTER(isp, PCR); - SBL_PRINT_REGISTER(isp, SDR_REQ_EXP); - - dev_dbg(isp->dev, "--------------------------------------------\n"); -} - -#ifdef CONFIG_PM - -/* - * Power management support. - * - * As the ISP can't properly handle an input video stream interruption on a non - * frame boundary, the ISP pipelines need to be stopped before sensors get - * suspended. However, as suspending the sensors can require a running clock, - * which can be provided by the ISP, the ISP can't be completely suspended - * before the sensor. - * - * To solve this problem power management support is split into prepare/complete - * and suspend/resume operations. The pipelines are stopped in prepare() and the - * ISP clocks get disabled in suspend(). Similarly, the clocks are reenabled in - * resume(), and the the pipelines are restarted in complete(). - * - * TODO: PM dependencies between the ISP and sensors are not modeled explicitly - * yet. - */ -static int isp_pm_prepare(struct device *dev) -{ - struct isp_device *isp = dev_get_drvdata(dev); - int reset; - - WARN_ON(mutex_is_locked(&isp->isp_mutex)); - - if (isp->ref_count == 0) - return 0; - - reset = isp_suspend_modules(isp); - isp_disable_interrupts(isp); - isp_save_ctx(isp); - if (reset) - isp_reset(isp); - - return 0; -} - -static int isp_pm_suspend(struct device *dev) -{ - struct isp_device *isp = dev_get_drvdata(dev); - - WARN_ON(mutex_is_locked(&isp->isp_mutex)); - - if (isp->ref_count) - isp_disable_clocks(isp); - - return 0; -} - -static int isp_pm_resume(struct device *dev) -{ - struct isp_device *isp = dev_get_drvdata(dev); - - if (isp->ref_count == 0) - return 0; - - return isp_enable_clocks(isp); -} - -static void isp_pm_complete(struct device *dev) -{ - struct isp_device *isp = dev_get_drvdata(dev); - - if (isp->ref_count == 0) - return; - - isp_restore_ctx(isp); - isp_enable_interrupts(isp); - isp_resume_modules(isp); -} - -#else - -#define isp_pm_prepare NULL -#define isp_pm_suspend NULL -#define isp_pm_resume NULL -#define isp_pm_complete NULL - -#endif /* CONFIG_PM */ - -static void isp_unregister_entities(struct isp_device *isp) -{ - omap3isp_csi2_unregister_entities(&isp->isp_csi2a); - omap3isp_ccp2_unregister_entities(&isp->isp_ccp2); - omap3isp_ccdc_unregister_entities(&isp->isp_ccdc); - omap3isp_preview_unregister_entities(&isp->isp_prev); - omap3isp_resizer_unregister_entities(&isp->isp_res); - omap3isp_stat_unregister_entities(&isp->isp_aewb); - omap3isp_stat_unregister_entities(&isp->isp_af); - omap3isp_stat_unregister_entities(&isp->isp_hist); - - v4l2_device_unregister(&isp->v4l2_dev); - media_device_unregister(&isp->media_dev); -} - -/* - * isp_register_subdev_group - Register a group of subdevices - * @isp: OMAP3 ISP device - * @board_info: I2C subdevs board information array - * - * Register all I2C subdevices in the board_info array. The array must be - * terminated by a NULL entry, and the first entry must be the sensor. - * - * Return a pointer to the sensor media entity if it has been successfully - * registered, or NULL otherwise. - */ -static struct v4l2_subdev * -isp_register_subdev_group(struct isp_device *isp, - struct isp_subdev_i2c_board_info *board_info) -{ - struct v4l2_subdev *sensor = NULL; - unsigned int first; - - if (board_info->board_info == NULL) - return NULL; - - for (first = 1; board_info->board_info; ++board_info, first = 0) { - struct v4l2_subdev *subdev; - struct i2c_adapter *adapter; - - adapter = i2c_get_adapter(board_info->i2c_adapter_id); - if (adapter == NULL) { - printk(KERN_ERR "%s: Unable to get I2C adapter %d for " - "device %s\n", __func__, - board_info->i2c_adapter_id, - board_info->board_info->type); - continue; - } - - subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, - board_info->board_info, NULL); - if (subdev == NULL) { - printk(KERN_ERR "%s: Unable to register subdev %s\n", - __func__, board_info->board_info->type); - continue; - } - - if (first) - sensor = subdev; - } - - return sensor; -} - -static int isp_register_entities(struct isp_device *isp) -{ - struct isp_platform_data *pdata = isp->pdata; - struct isp_v4l2_subdevs_group *subdevs; - int ret; - - isp->media_dev.dev = isp->dev; - strlcpy(isp->media_dev.model, "TI OMAP3 ISP", - sizeof(isp->media_dev.model)); - isp->media_dev.link_notify = isp_pipeline_link_notify; - ret = media_device_register(&isp->media_dev); - if (ret < 0) { - printk(KERN_ERR "%s: Media device registration failed (%d)\n", - __func__, ret); - return ret; - } - - isp->v4l2_dev.mdev = &isp->media_dev; - ret = v4l2_device_register(isp->dev, &isp->v4l2_dev); - if (ret < 0) { - printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n", - __func__, ret); - goto done; - } - - /* Register internal entities */ - ret = omap3isp_ccp2_register_entities(&isp->isp_ccp2, &isp->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap3isp_csi2_register_entities(&isp->isp_csi2a, &isp->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap3isp_ccdc_register_entities(&isp->isp_ccdc, &isp->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap3isp_preview_register_entities(&isp->isp_prev, - &isp->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap3isp_resizer_register_entities(&isp->isp_res, &isp->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap3isp_stat_register_entities(&isp->isp_aewb, &isp->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap3isp_stat_register_entities(&isp->isp_af, &isp->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap3isp_stat_register_entities(&isp->isp_hist, &isp->v4l2_dev); - if (ret < 0) - goto done; - - /* Register external entities */ - for (subdevs = pdata->subdevs; subdevs->subdevs; ++subdevs) { - struct v4l2_subdev *sensor; - struct media_entity *input; - unsigned int flags; - unsigned int pad; - - sensor = isp_register_subdev_group(isp, subdevs->subdevs); - if (sensor == NULL) - continue; - - sensor->host_priv = subdevs; - - /* Connect the sensor to the correct interface module. Parallel - * sensors are connected directly to the CCDC, while serial - * sensors are connected to the CSI2a, CCP2b or CSI2c receiver - * through CSIPHY1 or CSIPHY2. - */ - switch (subdevs->interface) { - case ISP_INTERFACE_PARALLEL: - input = &isp->isp_ccdc.subdev.entity; - pad = CCDC_PAD_SINK; - flags = 0; - break; - - case ISP_INTERFACE_CSI2A_PHY2: - input = &isp->isp_csi2a.subdev.entity; - pad = CSI2_PAD_SINK; - flags = MEDIA_LNK_FL_IMMUTABLE - | MEDIA_LNK_FL_ENABLED; - break; - - case ISP_INTERFACE_CCP2B_PHY1: - case ISP_INTERFACE_CCP2B_PHY2: - input = &isp->isp_ccp2.subdev.entity; - pad = CCP2_PAD_SINK; - flags = 0; - break; - - case ISP_INTERFACE_CSI2C_PHY1: - input = &isp->isp_csi2c.subdev.entity; - pad = CSI2_PAD_SINK; - flags = MEDIA_LNK_FL_IMMUTABLE - | MEDIA_LNK_FL_ENABLED; - break; - - default: - printk(KERN_ERR "%s: invalid interface type %u\n", - __func__, subdevs->interface); - ret = -EINVAL; - goto done; - } - - ret = media_entity_create_link(&sensor->entity, 0, input, pad, - flags); - if (ret < 0) - goto done; - } - - ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); - -done: - if (ret < 0) - isp_unregister_entities(isp); - - return ret; -} - -static void isp_cleanup_modules(struct isp_device *isp) -{ - omap3isp_h3a_aewb_cleanup(isp); - omap3isp_h3a_af_cleanup(isp); - omap3isp_hist_cleanup(isp); - omap3isp_resizer_cleanup(isp); - omap3isp_preview_cleanup(isp); - omap3isp_ccdc_cleanup(isp); - omap3isp_ccp2_cleanup(isp); - omap3isp_csi2_cleanup(isp); -} - -static int isp_initialize_modules(struct isp_device *isp) -{ - int ret; - - ret = omap3isp_csiphy_init(isp); - if (ret < 0) { - dev_err(isp->dev, "CSI PHY initialization failed\n"); - goto error_csiphy; - } - - ret = omap3isp_csi2_init(isp); - if (ret < 0) { - dev_err(isp->dev, "CSI2 initialization failed\n"); - goto error_csi2; - } - - ret = omap3isp_ccp2_init(isp); - if (ret < 0) { - dev_err(isp->dev, "CCP2 initialization failed\n"); - goto error_ccp2; - } - - ret = omap3isp_ccdc_init(isp); - if (ret < 0) { - dev_err(isp->dev, "CCDC initialization failed\n"); - goto error_ccdc; - } - - ret = omap3isp_preview_init(isp); - if (ret < 0) { - dev_err(isp->dev, "Preview initialization failed\n"); - goto error_preview; - } - - ret = omap3isp_resizer_init(isp); - if (ret < 0) { - dev_err(isp->dev, "Resizer initialization failed\n"); - goto error_resizer; - } - - ret = omap3isp_hist_init(isp); - if (ret < 0) { - dev_err(isp->dev, "Histogram initialization failed\n"); - goto error_hist; - } - - ret = omap3isp_h3a_aewb_init(isp); - if (ret < 0) { - dev_err(isp->dev, "H3A AEWB initialization failed\n"); - goto error_h3a_aewb; - } - - ret = omap3isp_h3a_af_init(isp); - if (ret < 0) { - dev_err(isp->dev, "H3A AF initialization failed\n"); - goto error_h3a_af; - } - - /* Connect the submodules. */ - ret = media_entity_create_link( - &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE, - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE, - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, - &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF, - &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE, - &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, - &isp->isp_aewb.subdev.entity, 0, - MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, - &isp->isp_af.subdev.entity, 0, - MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, - &isp->isp_hist.subdev.entity, 0, - MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); - if (ret < 0) - goto error_link; - - return 0; - -error_link: - omap3isp_h3a_af_cleanup(isp); -error_h3a_af: - omap3isp_h3a_aewb_cleanup(isp); -error_h3a_aewb: - omap3isp_hist_cleanup(isp); -error_hist: - omap3isp_resizer_cleanup(isp); -error_resizer: - omap3isp_preview_cleanup(isp); -error_preview: - omap3isp_ccdc_cleanup(isp); -error_ccdc: - omap3isp_ccp2_cleanup(isp); -error_ccp2: - omap3isp_csi2_cleanup(isp); -error_csi2: -error_csiphy: - return ret; -} - -/* - * isp_remove - Remove ISP platform device - * @pdev: Pointer to ISP platform device - * - * Always returns 0. - */ -static int isp_remove(struct platform_device *pdev) -{ - struct isp_device *isp = platform_get_drvdata(pdev); - int i; - - isp_unregister_entities(isp); - isp_cleanup_modules(isp); - - omap3isp_get(isp); - iommu_put(isp->iommu); - omap3isp_put(isp); - - free_irq(isp->irq_num, isp); - isp_put_clocks(isp); - - for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) { - if (isp->mmio_base[i]) { - iounmap(isp->mmio_base[i]); - isp->mmio_base[i] = NULL; - } - - if (isp->mmio_base_phys[i]) { - release_mem_region(isp->mmio_base_phys[i], - isp->mmio_size[i]); - isp->mmio_base_phys[i] = 0; - } - } - - regulator_put(isp->isp_csiphy1.vdd); - regulator_put(isp->isp_csiphy2.vdd); - kfree(isp); - - return 0; -} - -static int isp_map_mem_resource(struct platform_device *pdev, - struct isp_device *isp, - enum isp_mem_resources res) -{ - struct resource *mem; - - /* request the mem region for the camera registers */ - - mem = platform_get_resource(pdev, IORESOURCE_MEM, res); - if (!mem) { - dev_err(isp->dev, "no mem resource?\n"); - return -ENODEV; - } - - if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) { - dev_err(isp->dev, - "cannot reserve camera register I/O region\n"); - return -ENODEV; - } - isp->mmio_base_phys[res] = mem->start; - isp->mmio_size[res] = resource_size(mem); - - /* map the region */ - isp->mmio_base[res] = ioremap_nocache(isp->mmio_base_phys[res], - isp->mmio_size[res]); - if (!isp->mmio_base[res]) { - dev_err(isp->dev, "cannot map camera register I/O region\n"); - return -ENODEV; - } - - return 0; -} - -/* - * isp_probe - Probe ISP platform device - * @pdev: Pointer to ISP platform device - * - * Returns 0 if successful, - * -ENOMEM if no memory available, - * -ENODEV if no platform device resources found - * or no space for remapping registers, - * -EINVAL if couldn't install ISR, - * or clk_get return error value. - */ -static int isp_probe(struct platform_device *pdev) -{ - struct isp_platform_data *pdata = pdev->dev.platform_data; - struct isp_device *isp; - int ret; - int i, m; - - if (pdata == NULL) - return -EINVAL; - - isp = kzalloc(sizeof(*isp), GFP_KERNEL); - if (!isp) { - dev_err(&pdev->dev, "could not allocate memory\n"); - return -ENOMEM; - } - - isp->autoidle = autoidle; - isp->platform_cb.set_xclk = isp_set_xclk; - isp->platform_cb.set_pixel_clock = isp_set_pixel_clock; - - mutex_init(&isp->isp_mutex); - spin_lock_init(&isp->stat_lock); - - isp->dev = &pdev->dev; - isp->pdata = pdata; - isp->ref_count = 0; - - isp->raw_dmamask = DMA_BIT_MASK(32); - isp->dev->dma_mask = &isp->raw_dmamask; - isp->dev->coherent_dma_mask = DMA_BIT_MASK(32); - - platform_set_drvdata(pdev, isp); - - /* Regulators */ - isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1"); - isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2"); - - /* Clocks */ - ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN); - if (ret < 0) - goto error; - - ret = isp_get_clocks(isp); - if (ret < 0) - goto error; - - if (omap3isp_get(isp) == NULL) - goto error; - - ret = isp_reset(isp); - if (ret < 0) - goto error_isp; - - /* Memory resources */ - isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); - dev_info(isp->dev, "Revision %d.%d found\n", - (isp->revision & 0xf0) >> 4, isp->revision & 0x0f); - - for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++) - if (isp->revision == isp_res_maps[m].isp_rev) - break; - - if (m == ARRAY_SIZE(isp_res_maps)) { - dev_err(isp->dev, "No resource map found for ISP rev %d.%d\n", - (isp->revision & 0xf0) >> 4, isp->revision & 0xf); - ret = -ENODEV; - goto error_isp; - } - - for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) { - if (isp_res_maps[m].map & 1 << i) { - ret = isp_map_mem_resource(pdev, isp, i); - if (ret) - goto error_isp; - } - } - - /* IOMMU */ - isp->iommu = iommu_get("isp"); - if (IS_ERR_OR_NULL(isp->iommu)) { - isp->iommu = NULL; - ret = -ENODEV; - goto error_isp; - } - - /* Interrupt */ - isp->irq_num = platform_get_irq(pdev, 0); - if (isp->irq_num <= 0) { - dev_err(isp->dev, "No IRQ resource\n"); - ret = -ENODEV; - goto error_isp; - } - - if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) { - dev_err(isp->dev, "Unable to request IRQ\n"); - ret = -EINVAL; - goto error_isp; - } - - /* Entities */ - ret = isp_initialize_modules(isp); - if (ret < 0) - goto error_irq; - - ret = isp_register_entities(isp); - if (ret < 0) - goto error_modules; - - isp_power_settings(isp, 1); - omap3isp_put(isp); - - return 0; - -error_modules: - isp_cleanup_modules(isp); -error_irq: - free_irq(isp->irq_num, isp); -error_isp: - iommu_put(isp->iommu); - omap3isp_put(isp); -error: - isp_put_clocks(isp); - - for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) { - if (isp->mmio_base[i]) { - iounmap(isp->mmio_base[i]); - isp->mmio_base[i] = NULL; - } - - if (isp->mmio_base_phys[i]) { - release_mem_region(isp->mmio_base_phys[i], - isp->mmio_size[i]); - isp->mmio_base_phys[i] = 0; - } - } - regulator_put(isp->isp_csiphy2.vdd); - regulator_put(isp->isp_csiphy1.vdd); - platform_set_drvdata(pdev, NULL); - kfree(isp); - - return ret; -} - -static const struct dev_pm_ops omap3isp_pm_ops = { - .prepare = isp_pm_prepare, - .suspend = isp_pm_suspend, - .resume = isp_pm_resume, - .complete = isp_pm_complete, -}; - -static struct platform_device_id omap3isp_id_table[] = { - { "omap3isp", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(platform, omap3isp_id_table); - -static struct platform_driver omap3isp_driver = { - .probe = isp_probe, - .remove = isp_remove, - .id_table = omap3isp_id_table, - .driver = { - .owner = THIS_MODULE, - .name = "omap3isp", - .pm = &omap3isp_pm_ops, - }, -}; - -/* - * isp_init - ISP module initialization. - */ -static int __init isp_init(void) -{ - return platform_driver_register(&omap3isp_driver); -} - -/* - * isp_cleanup - ISP module cleanup. - */ -static void __exit isp_cleanup(void) -{ - platform_driver_unregister(&omap3isp_driver); -} - -module_init(isp_init); -module_exit(isp_cleanup); - -MODULE_AUTHOR("Nokia Corporation"); -MODULE_DESCRIPTION("TI OMAP3 ISP driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccdc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccdc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccdc.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccdc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2268 +0,0 @@ -/* - * ispccdc.c - * - * TI OMAP3 ISP - CCDC module - * - * Copyright (C) 2009-2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "isp.h" -#include "ispreg.h" -#include "ispccdc.h" - -static struct v4l2_mbus_framefmt * -__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, - unsigned int pad, enum v4l2_subdev_format_whence which); - -static const unsigned int ccdc_fmts[] = { - V4L2_MBUS_FMT_Y8_1X8, - V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGRBG12_1X12, - V4L2_MBUS_FMT_SRGGB12_1X12, - V4L2_MBUS_FMT_SBGGR12_1X12, - V4L2_MBUS_FMT_SGBRG12_1X12, -}; - -/* - * ccdc_print_status - Print current CCDC Module register values. - * @ccdc: Pointer to ISP CCDC device. - * - * Also prints other debug information stored in the CCDC module. - */ -#define CCDC_PRINT_REGISTER(isp, name)\ - dev_dbg(isp->dev, "###CCDC " #name "=0x%08x\n", \ - isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_##name)) - -static void ccdc_print_status(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - - dev_dbg(isp->dev, "-------------CCDC Register dump-------------\n"); - - CCDC_PRINT_REGISTER(isp, PCR); - CCDC_PRINT_REGISTER(isp, SYN_MODE); - CCDC_PRINT_REGISTER(isp, HD_VD_WID); - CCDC_PRINT_REGISTER(isp, PIX_LINES); - CCDC_PRINT_REGISTER(isp, HORZ_INFO); - CCDC_PRINT_REGISTER(isp, VERT_START); - CCDC_PRINT_REGISTER(isp, VERT_LINES); - CCDC_PRINT_REGISTER(isp, CULLING); - CCDC_PRINT_REGISTER(isp, HSIZE_OFF); - CCDC_PRINT_REGISTER(isp, SDOFST); - CCDC_PRINT_REGISTER(isp, SDR_ADDR); - CCDC_PRINT_REGISTER(isp, CLAMP); - CCDC_PRINT_REGISTER(isp, DCSUB); - CCDC_PRINT_REGISTER(isp, COLPTN); - CCDC_PRINT_REGISTER(isp, BLKCMP); - CCDC_PRINT_REGISTER(isp, FPC); - CCDC_PRINT_REGISTER(isp, FPC_ADDR); - CCDC_PRINT_REGISTER(isp, VDINT); - CCDC_PRINT_REGISTER(isp, ALAW); - CCDC_PRINT_REGISTER(isp, REC656IF); - CCDC_PRINT_REGISTER(isp, CFG); - CCDC_PRINT_REGISTER(isp, FMTCFG); - CCDC_PRINT_REGISTER(isp, FMT_HORZ); - CCDC_PRINT_REGISTER(isp, FMT_VERT); - CCDC_PRINT_REGISTER(isp, PRGEVEN0); - CCDC_PRINT_REGISTER(isp, PRGEVEN1); - CCDC_PRINT_REGISTER(isp, PRGODD0); - CCDC_PRINT_REGISTER(isp, PRGODD1); - CCDC_PRINT_REGISTER(isp, VP_OUT); - CCDC_PRINT_REGISTER(isp, LSC_CONFIG); - CCDC_PRINT_REGISTER(isp, LSC_INITIAL); - CCDC_PRINT_REGISTER(isp, LSC_TABLE_BASE); - CCDC_PRINT_REGISTER(isp, LSC_TABLE_OFFSET); - - dev_dbg(isp->dev, "--------------------------------------------\n"); -} - -/* - * omap3isp_ccdc_busy - Get busy state of the CCDC. - * @ccdc: Pointer to ISP CCDC device. - */ -int omap3isp_ccdc_busy(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - - return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) & - ISPCCDC_PCR_BUSY; -} - -/* ----------------------------------------------------------------------------- - * Lens Shading Compensation - */ - -/* - * ccdc_lsc_validate_config - Check that LSC configuration is valid. - * @ccdc: Pointer to ISP CCDC device. - * @lsc_cfg: the LSC configuration to check. - * - * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid. - */ -static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc, - struct omap3isp_ccdc_lsc_config *lsc_cfg) -{ - struct isp_device *isp = to_isp_device(ccdc); - struct v4l2_mbus_framefmt *format; - unsigned int paxel_width, paxel_height; - unsigned int paxel_shift_x, paxel_shift_y; - unsigned int min_width, min_height, min_size; - unsigned int input_width, input_height; - - paxel_shift_x = lsc_cfg->gain_mode_m; - paxel_shift_y = lsc_cfg->gain_mode_n; - - if ((paxel_shift_x < 2) || (paxel_shift_x > 6) || - (paxel_shift_y < 2) || (paxel_shift_y > 6)) { - dev_dbg(isp->dev, "CCDC: LSC: Invalid paxel size\n"); - return -EINVAL; - } - - if (lsc_cfg->offset & 3) { - dev_dbg(isp->dev, "CCDC: LSC: Offset must be a multiple of " - "4\n"); - return -EINVAL; - } - - if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) { - dev_dbg(isp->dev, "CCDC: LSC: initial_x and y must be even\n"); - return -EINVAL; - } - - format = __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - input_width = format->width; - input_height = format->height; - - /* Calculate minimum bytesize for validation */ - paxel_width = 1 << paxel_shift_x; - min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1) - >> paxel_shift_x) + 1; - - paxel_height = 1 << paxel_shift_y; - min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1) - >> paxel_shift_y) + 1; - - min_size = 4 * min_width * min_height; - if (min_size > lsc_cfg->size) { - dev_dbg(isp->dev, "CCDC: LSC: too small table\n"); - return -EINVAL; - } - if (lsc_cfg->offset < (min_width * 4)) { - dev_dbg(isp->dev, "CCDC: LSC: Offset is too small\n"); - return -EINVAL; - } - if ((lsc_cfg->size / lsc_cfg->offset) < min_height) { - dev_dbg(isp->dev, "CCDC: LSC: Wrong size/offset combination\n"); - return -EINVAL; - } - return 0; -} - -/* - * ccdc_lsc_program_table - Program Lens Shading Compensation table address. - * @ccdc: Pointer to ISP CCDC device. - */ -static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr) -{ - isp_reg_writel(to_isp_device(ccdc), addr, - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE); -} - -/* - * ccdc_lsc_setup_regs - Configures the lens shading compensation module - * @ccdc: Pointer to ISP CCDC device. - */ -static void ccdc_lsc_setup_regs(struct isp_ccdc_device *ccdc, - struct omap3isp_ccdc_lsc_config *cfg) -{ - struct isp_device *isp = to_isp_device(ccdc); - int reg; - - isp_reg_writel(isp, cfg->offset, OMAP3_ISP_IOMEM_CCDC, - ISPCCDC_LSC_TABLE_OFFSET); - - reg = 0; - reg |= cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT; - reg |= cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT; - reg |= cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT; - isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG); - - reg = 0; - reg &= ~ISPCCDC_LSC_INITIAL_X_MASK; - reg |= cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT; - reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK; - reg |= cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT; - isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, - ISPCCDC_LSC_INITIAL); -} - -static int ccdc_lsc_wait_prefetch(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - unsigned int wait; - - isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ, - OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); - - /* timeout 1 ms */ - for (wait = 0; wait < 1000; wait++) { - if (isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS) & - IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ) { - isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ, - OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); - return 0; - } - - rmb(); - udelay(1); - } - - return -ETIMEDOUT; -} - -/* - * __ccdc_lsc_enable - Enables/Disables the Lens Shading Compensation module. - * @ccdc: Pointer to ISP CCDC device. - * @enable: 0 Disables LSC, 1 Enables LSC. - */ -static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable) -{ - struct isp_device *isp = to_isp_device(ccdc); - const struct v4l2_mbus_framefmt *format = - __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - - if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) && - (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) && - (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) && - (format->code != V4L2_MBUS_FMT_SGBRG10_1X10)) - return -EINVAL; - - if (enable) - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_LSC_READ); - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, - ISPCCDC_LSC_ENABLE, enable ? ISPCCDC_LSC_ENABLE : 0); - - if (enable) { - if (ccdc_lsc_wait_prefetch(ccdc) < 0) { - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, - ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE); - ccdc->lsc.state = LSC_STATE_STOPPED; - dev_warn(to_device(ccdc), "LSC prefecth timeout\n"); - return -ETIMEDOUT; - } - ccdc->lsc.state = LSC_STATE_RUNNING; - } else { - ccdc->lsc.state = LSC_STATE_STOPPING; - } - - return 0; -} - -static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - - return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG) & - ISPCCDC_LSC_BUSY; -} - -/* __ccdc_lsc_configure - Apply a new configuration to the LSC engine - * @ccdc: Pointer to ISP CCDC device - * @req: New configuration request - * - * context: in_interrupt() - */ -static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc, - struct ispccdc_lsc_config_req *req) -{ - if (!req->enable) - return -EINVAL; - - if (ccdc_lsc_validate_config(ccdc, &req->config) < 0) { - dev_dbg(to_device(ccdc), "Discard LSC configuration\n"); - return -EINVAL; - } - - if (ccdc_lsc_busy(ccdc)) - return -EBUSY; - - ccdc_lsc_setup_regs(ccdc, &req->config); - ccdc_lsc_program_table(ccdc, req->table); - return 0; -} - -/* - * ccdc_lsc_error_handler - Handle LSC prefetch error scenario. - * @ccdc: Pointer to ISP CCDC device. - * - * Disables LSC, and defers enablement to shadow registers update time. - */ -static void ccdc_lsc_error_handler(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - /* - * From OMAP3 TRM: When this event is pending, the module - * goes into transparent mode (output =input). Normal - * operation can be resumed at the start of the next frame - * after: - * 1) Clearing this event - * 2) Disabling the LSC module - * 3) Enabling it - */ - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, - ISPCCDC_LSC_ENABLE); - ccdc->lsc.state = LSC_STATE_STOPPED; -} - -static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc, - struct ispccdc_lsc_config_req *req) -{ - struct isp_device *isp = to_isp_device(ccdc); - - if (req == NULL) - return; - - if (req->iovm) - dma_unmap_sg(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE); - if (req->table) - iommu_vfree(isp->iommu, req->table); - kfree(req); -} - -static void ccdc_lsc_free_queue(struct isp_ccdc_device *ccdc, - struct list_head *queue) -{ - struct ispccdc_lsc_config_req *req, *n; - unsigned long flags; - - spin_lock_irqsave(&ccdc->lsc.req_lock, flags); - list_for_each_entry_safe(req, n, queue, list) { - list_del(&req->list); - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); - ccdc_lsc_free_request(ccdc, req); - spin_lock_irqsave(&ccdc->lsc.req_lock, flags); - } - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); -} - -static void ccdc_lsc_free_table_work(struct work_struct *work) -{ - struct isp_ccdc_device *ccdc; - struct ispccdc_lsc *lsc; - - lsc = container_of(work, struct ispccdc_lsc, table_work); - ccdc = container_of(lsc, struct isp_ccdc_device, lsc); - - ccdc_lsc_free_queue(ccdc, &lsc->free_queue); -} - -/* - * ccdc_lsc_config - Configure the LSC module from a userspace request - * - * Store the request LSC configuration in the LSC engine request pointer. The - * configuration will be applied to the hardware when the CCDC will be enabled, - * or at the next LSC interrupt if the CCDC is already running. - */ -static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, - struct omap3isp_ccdc_update_config *config) -{ - struct isp_device *isp = to_isp_device(ccdc); - struct ispccdc_lsc_config_req *req; - unsigned long flags; - void *table; - u16 update; - int ret; - - update = config->update & - (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC); - if (!update) - return 0; - - if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) { - dev_dbg(to_device(ccdc), "%s: Both LSC configuration and table " - "need to be supplied\n", __func__); - return -EINVAL; - } - - req = kzalloc(sizeof(*req), GFP_KERNEL); - if (req == NULL) - return -ENOMEM; - - if (config->flag & OMAP3ISP_CCDC_CONFIG_LSC) { - if (copy_from_user(&req->config, config->lsc_cfg, - sizeof(req->config))) { - ret = -EFAULT; - goto done; - } - - req->enable = 1; - - req->table = iommu_vmalloc(isp->iommu, 0, req->config.size, - IOMMU_FLAG); - if (IS_ERR_VALUE(req->table)) { - req->table = 0; - ret = -ENOMEM; - goto done; - } - - req->iovm = find_iovm_area(isp->iommu, req->table); - if (req->iovm == NULL) { - ret = -ENOMEM; - goto done; - } - - if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE)) { - ret = -ENOMEM; - req->iovm = NULL; - goto done; - } - - dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE); - - table = da_to_va(isp->iommu, req->table); - if (copy_from_user(table, config->lsc, req->config.size)) { - ret = -EFAULT; - goto done; - } - - dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE); - } - - spin_lock_irqsave(&ccdc->lsc.req_lock, flags); - if (ccdc->lsc.request) { - list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue); - schedule_work(&ccdc->lsc.table_work); - } - ccdc->lsc.request = req; - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); - - ret = 0; - -done: - if (ret < 0) - ccdc_lsc_free_request(ccdc, req); - - return ret; -} - -static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc) -{ - unsigned long flags; - - spin_lock_irqsave(&ccdc->lsc.req_lock, flags); - if (ccdc->lsc.active) { - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); - return 1; - } - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); - return 0; -} - -static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc) -{ - struct ispccdc_lsc *lsc = &ccdc->lsc; - - if (lsc->state != LSC_STATE_STOPPED) - return -EINVAL; - - if (lsc->active) { - list_add_tail(&lsc->active->list, &lsc->free_queue); - lsc->active = NULL; - } - - if (__ccdc_lsc_configure(ccdc, lsc->request) < 0) { - omap3isp_sbl_disable(to_isp_device(ccdc), - OMAP3_ISP_SBL_CCDC_LSC_READ); - list_add_tail(&lsc->request->list, &lsc->free_queue); - lsc->request = NULL; - goto done; - } - - lsc->active = lsc->request; - lsc->request = NULL; - __ccdc_lsc_enable(ccdc, 1); - -done: - if (!list_empty(&lsc->free_queue)) - schedule_work(&lsc->table_work); - - return 0; -} - -/* ----------------------------------------------------------------------------- - * Parameters configuration - */ - -/* - * ccdc_configure_clamp - Configure optical-black or digital clamping - * @ccdc: Pointer to ISP CCDC device. - * - * The CCDC performs either optical-black or digital clamp. Configure and enable - * the selected clamp method. - */ -static void ccdc_configure_clamp(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - u32 clamp; - - if (ccdc->obclamp) { - clamp = ccdc->clamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT; - clamp |= ccdc->clamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT; - clamp |= ccdc->clamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT; - clamp |= ccdc->clamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT; - isp_reg_writel(isp, clamp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP); - } else { - isp_reg_writel(isp, ccdc->clamp.dcsubval, - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB); - } - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP, - ISPCCDC_CLAMP_CLAMPEN, - ccdc->obclamp ? ISPCCDC_CLAMP_CLAMPEN : 0); -} - -/* - * ccdc_configure_fpc - Configure Faulty Pixel Correction - * @ccdc: Pointer to ISP CCDC device. - */ -static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, ISPCCDC_FPC_FPCEN); - - if (!ccdc->fpc_en) - return; - - isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC, - ISPCCDC_FPC_ADDR); - /* The FPNUM field must be set before enabling FPC. */ - isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC); - isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT) | - ISPCCDC_FPC_FPCEN, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC); -} - -/* - * ccdc_configure_black_comp - Configure Black Level Compensation. - * @ccdc: Pointer to ISP CCDC device. - */ -static void ccdc_configure_black_comp(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - u32 blcomp; - - blcomp = ccdc->blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT; - blcomp |= ccdc->blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT; - blcomp |= ccdc->blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT; - blcomp |= ccdc->blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT; - - isp_reg_writel(isp, blcomp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP); -} - -/* - * ccdc_configure_lpf - Configure Low-Pass Filter (LPF). - * @ccdc: Pointer to ISP CCDC device. - */ -static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE, - ISPCCDC_SYN_MODE_LPF, - ccdc->lpf ? ISPCCDC_SYN_MODE_LPF : 0); -} - -/* - * ccdc_configure_alaw - Configure A-law compression. - * @ccdc: Pointer to ISP CCDC device. - */ -static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - u32 alaw = 0; - - switch (ccdc->syncif.datsz) { - case 8: - return; - - case 10: - alaw = ISPCCDC_ALAW_GWDI_9_0; - break; - case 11: - alaw = ISPCCDC_ALAW_GWDI_10_1; - break; - case 12: - alaw = ISPCCDC_ALAW_GWDI_11_2; - break; - case 13: - alaw = ISPCCDC_ALAW_GWDI_12_3; - break; - } - - if (ccdc->alaw) - alaw |= ISPCCDC_ALAW_CCDTBL; - - isp_reg_writel(isp, alaw, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW); -} - -/* - * ccdc_config_imgattr - Configure sensor image specific attributes. - * @ccdc: Pointer to ISP CCDC device. - * @colptn: Color pattern of the sensor. - */ -static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn) -{ - struct isp_device *isp = to_isp_device(ccdc); - - isp_reg_writel(isp, colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN); -} - -/* - * ccdc_config - Set CCDC configuration from userspace - * @ccdc: Pointer to ISP CCDC device. - * @userspace_add: Structure containing CCDC configuration sent from userspace. - * - * Returns 0 if successful, -EINVAL if the pointer to the configuration - * structure is null, or the copy_from_user function fails to copy user space - * memory to kernel space memory. - */ -static int ccdc_config(struct isp_ccdc_device *ccdc, - struct omap3isp_ccdc_update_config *ccdc_struct) -{ - struct isp_device *isp = to_isp_device(ccdc); - unsigned long flags; - - spin_lock_irqsave(&ccdc->lock, flags); - ccdc->shadow_update = 1; - spin_unlock_irqrestore(&ccdc->lock, flags); - - if (OMAP3ISP_CCDC_ALAW & ccdc_struct->update) { - ccdc->alaw = !!(OMAP3ISP_CCDC_ALAW & ccdc_struct->flag); - ccdc->update |= OMAP3ISP_CCDC_ALAW; - } - - if (OMAP3ISP_CCDC_LPF & ccdc_struct->update) { - ccdc->lpf = !!(OMAP3ISP_CCDC_LPF & ccdc_struct->flag); - ccdc->update |= OMAP3ISP_CCDC_LPF; - } - - if (OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->update) { - if (copy_from_user(&ccdc->clamp, ccdc_struct->bclamp, - sizeof(ccdc->clamp))) { - ccdc->shadow_update = 0; - return -EFAULT; - } - - ccdc->obclamp = !!(OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->flag); - ccdc->update |= OMAP3ISP_CCDC_BLCLAMP; - } - - if (OMAP3ISP_CCDC_BCOMP & ccdc_struct->update) { - if (copy_from_user(&ccdc->blcomp, ccdc_struct->blcomp, - sizeof(ccdc->blcomp))) { - ccdc->shadow_update = 0; - return -EFAULT; - } - - ccdc->update |= OMAP3ISP_CCDC_BCOMP; - } - - ccdc->shadow_update = 0; - - if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) { - u32 table_old = 0; - u32 table_new; - u32 size; - - if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED) - return -EBUSY; - - ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag); - - if (ccdc->fpc_en) { - if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc, - sizeof(ccdc->fpc))) - return -EFAULT; - - /* - * table_new must be 64-bytes aligned, but it's - * already done by iommu_vmalloc(). - */ - size = ccdc->fpc.fpnum * 4; - table_new = iommu_vmalloc(isp->iommu, 0, size, - IOMMU_FLAG); - if (IS_ERR_VALUE(table_new)) - return -ENOMEM; - - if (copy_from_user(da_to_va(isp->iommu, table_new), - (__force void __user *) - ccdc->fpc.fpcaddr, size)) { - iommu_vfree(isp->iommu, table_new); - return -EFAULT; - } - - table_old = ccdc->fpc.fpcaddr; - ccdc->fpc.fpcaddr = table_new; - } - - ccdc_configure_fpc(ccdc); - if (table_old != 0) - iommu_vfree(isp->iommu, table_old); - } - - return ccdc_lsc_config(ccdc, ccdc_struct); -} - -static void ccdc_apply_controls(struct isp_ccdc_device *ccdc) -{ - if (ccdc->update & OMAP3ISP_CCDC_ALAW) { - ccdc_configure_alaw(ccdc); - ccdc->update &= ~OMAP3ISP_CCDC_ALAW; - } - - if (ccdc->update & OMAP3ISP_CCDC_LPF) { - ccdc_configure_lpf(ccdc); - ccdc->update &= ~OMAP3ISP_CCDC_LPF; - } - - if (ccdc->update & OMAP3ISP_CCDC_BLCLAMP) { - ccdc_configure_clamp(ccdc); - ccdc->update &= ~OMAP3ISP_CCDC_BLCLAMP; - } - - if (ccdc->update & OMAP3ISP_CCDC_BCOMP) { - ccdc_configure_black_comp(ccdc); - ccdc->update &= ~OMAP3ISP_CCDC_BCOMP; - } -} - -/* - * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers - * @dev: Pointer to ISP device - */ -void omap3isp_ccdc_restore_context(struct isp_device *isp) -{ - struct isp_ccdc_device *ccdc = &isp->isp_ccdc; - - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC); - - ccdc->update = OMAP3ISP_CCDC_ALAW | OMAP3ISP_CCDC_LPF - | OMAP3ISP_CCDC_BLCLAMP | OMAP3ISP_CCDC_BCOMP; - ccdc_apply_controls(ccdc); - ccdc_configure_fpc(ccdc); -} - -/* ----------------------------------------------------------------------------- - * Format- and pipeline-related configuration helpers - */ - -/* - * ccdc_config_vp - Configure the Video Port. - * @ccdc: Pointer to ISP CCDC device. - */ -static void ccdc_config_vp(struct isp_ccdc_device *ccdc) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); - struct isp_device *isp = to_isp_device(ccdc); - unsigned long l3_ick = pipe->l3_ick; - unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8; - unsigned int div = 0; - u32 fmtcfg_vp; - - fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG) - & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK); - - switch (ccdc->syncif.datsz) { - case 8: - case 10: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0; - break; - case 11: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1; - break; - case 12: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2; - break; - case 13: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3; - break; - }; - - if (pipe->input) - div = DIV_ROUND_UP(l3_ick, pipe->max_rate); - else if (ccdc->vpcfg.pixelclk) - div = l3_ick / ccdc->vpcfg.pixelclk; - - div = clamp(div, 2U, max_div); - fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT; - - isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG); -} - -/* - * ccdc_enable_vp - Enable Video Port. - * @ccdc: Pointer to ISP CCDC device. - * @enable: 0 Disables VP, 1 Enables VP - * - * This is needed for outputting image to Preview, H3A and HIST ISP submodules. - */ -static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable) -{ - struct isp_device *isp = to_isp_device(ccdc); - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG, - ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0); -} - -/* - * ccdc_config_outlineoffset - Configure memory saving output line offset - * @ccdc: Pointer to ISP CCDC device. - * @offset: Address offset to start a new line. Must be twice the - * Output width and aligned on 32 byte boundary - * @oddeven: Specifies the odd/even line pattern to be chosen to store the - * output. - * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines. - * - * - Configures the output line offset when stored in memory - * - Sets the odd/even line pattern to store the output - * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4)) - * - Configures the number of even and odd line fields in case of rearranging - * the lines. - */ -static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc, - u32 offset, u8 oddeven, u8 numlines) -{ - struct isp_device *isp = to_isp_device(ccdc); - - isp_reg_writel(isp, offset & 0xffff, - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF); - - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - ISPCCDC_SDOFST_FINV); - - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - ISPCCDC_SDOFST_FOFST_4L); - - switch (oddeven) { - case EVENEVEN: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT); - break; - case ODDEVEN: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT); - break; - case EVENODD: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT); - break; - case ODDODD: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT); - break; - default: - break; - } -} - -/* - * ccdc_set_outaddr - Set memory address to save output image - * @ccdc: Pointer to ISP CCDC device. - * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary. - * - * Sets the memory address where the output will be saved. - */ -static void ccdc_set_outaddr(struct isp_ccdc_device *ccdc, u32 addr) -{ - struct isp_device *isp = to_isp_device(ccdc); - - isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR); -} - -/* - * omap3isp_ccdc_max_rate - Calculate maximum input data rate based on the input - * @ccdc: Pointer to ISP CCDC device. - * @max_rate: Maximum calculated data rate. - * - * Returns in *max_rate less value between calculated and passed - */ -void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc, - unsigned int *max_rate) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); - unsigned int rate; - - if (pipe == NULL) - return; - - /* - * TRM says that for parallel sensors the maximum data rate - * should be 90% form L3/2 clock, otherwise just L3/2. - */ - if (ccdc->input == CCDC_INPUT_PARALLEL) - rate = pipe->l3_ick / 2 * 9 / 10; - else - rate = pipe->l3_ick / 2; - - *max_rate = min(*max_rate, rate); -} - -/* - * ccdc_config_sync_if - Set CCDC sync interface configuration - * @ccdc: Pointer to ISP CCDC device. - * @syncif: Structure containing the sync parameters like field state, CCDC in - * master/slave mode, raw/yuv data, polarity of data, field, hs, vs - * signals. - */ -static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, - struct ispccdc_syncif *syncif) -{ - struct isp_device *isp = to_isp_device(ccdc); - u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, - ISPCCDC_SYN_MODE); - - syn_mode |= ISPCCDC_SYN_MODE_VDHDEN; - - if (syncif->fldstat) - syn_mode |= ISPCCDC_SYN_MODE_FLDSTAT; - else - syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT; - - syn_mode &= ~ISPCCDC_SYN_MODE_DATSIZ_MASK; - switch (syncif->datsz) { - case 8: - syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8; - break; - case 10: - syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10; - break; - case 11: - syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11; - break; - case 12: - syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12; - break; - }; - - if (syncif->fldmode) - syn_mode |= ISPCCDC_SYN_MODE_FLDMODE; - else - syn_mode &= ~ISPCCDC_SYN_MODE_FLDMODE; - - if (syncif->datapol) - syn_mode |= ISPCCDC_SYN_MODE_DATAPOL; - else - syn_mode &= ~ISPCCDC_SYN_MODE_DATAPOL; - - if (syncif->fldpol) - syn_mode |= ISPCCDC_SYN_MODE_FLDPOL; - else - syn_mode &= ~ISPCCDC_SYN_MODE_FLDPOL; - - if (syncif->hdpol) - syn_mode |= ISPCCDC_SYN_MODE_HDPOL; - else - syn_mode &= ~ISPCCDC_SYN_MODE_HDPOL; - - if (syncif->vdpol) - syn_mode |= ISPCCDC_SYN_MODE_VDPOL; - else - syn_mode &= ~ISPCCDC_SYN_MODE_VDPOL; - - if (syncif->ccdc_mastermode) { - syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT; - isp_reg_writel(isp, - syncif->hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT - | syncif->vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT, - OMAP3_ISP_IOMEM_CCDC, - ISPCCDC_HD_VD_WID); - - isp_reg_writel(isp, - syncif->ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT - | syncif->hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT, - OMAP3_ISP_IOMEM_CCDC, - ISPCCDC_PIX_LINES); - } else - syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT | - ISPCCDC_SYN_MODE_VDHDOUT); - - isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); - - if (!syncif->bt_r656_en) - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, - ISPCCDC_REC656IF_R656ON); -} - -/* CCDC formats descriptions */ -static const u32 ccdc_sgrbg_pattern = - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT; - -static const u32 ccdc_srggb_pattern = - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC0_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC1_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC2_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC3_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC0_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC1_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC2_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC3_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC0_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC1_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC2_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC3_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC0_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC1_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC2_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC3_SHIFT; - -static const u32 ccdc_sbggr_pattern = - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC0_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC1_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC2_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC3_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC0_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC1_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC2_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC3_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC0_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC1_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC2_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC3_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC0_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC1_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC2_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC3_SHIFT; - -static const u32 ccdc_sgbrg_pattern = - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC0_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC1_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC2_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC3_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC0_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC1_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC2_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC3_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC0_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC1_SHIFT | - ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC2_SHIFT | - ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC3_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC0_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC1_SHIFT | - ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC2_SHIFT | - ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC3_SHIFT; - -static void ccdc_configure(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - struct isp_parallel_platform_data *pdata = NULL; - struct v4l2_subdev *sensor; - struct v4l2_mbus_framefmt *format; - struct media_pad *pad; - unsigned long flags; - u32 syn_mode; - u32 ccdc_pattern; - - if (ccdc->input == CCDC_INPUT_PARALLEL) { - pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); - sensor = media_entity_to_v4l2_subdev(pad->entity); - pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) - ->bus.parallel; - } - - omap3isp_configure_bridge(isp, ccdc->input, pdata); - - ccdc->syncif.datsz = pdata ? pdata->width : 10; - ccdc_config_sync_if(ccdc, &ccdc->syncif); - - /* CCDC_PAD_SINK */ - format = &ccdc->formats[CCDC_PAD_SINK]; - - syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); - - /* Use the raw, unprocessed data when writing to memory. The H3A and - * histogram modules are still fed with lens shading corrected data. - */ - syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR; - - if (ccdc->output & CCDC_OUTPUT_MEMORY) - syn_mode |= ISPCCDC_SYN_MODE_WEN; - else - syn_mode &= ~ISPCCDC_SYN_MODE_WEN; - - if (ccdc->output & CCDC_OUTPUT_RESIZER) - syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ; - else - syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ; - - /* Use PACK8 mode for 1byte per pixel formats. */ - if (omap3isp_video_format_info(format->code)->bpp <= 8) - syn_mode |= ISPCCDC_SYN_MODE_PACK8; - else - syn_mode &= ~ISPCCDC_SYN_MODE_PACK8; - - isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); - - /* Mosaic filter */ - switch (format->code) { - case V4L2_MBUS_FMT_SRGGB10_1X10: - case V4L2_MBUS_FMT_SRGGB12_1X12: - ccdc_pattern = ccdc_srggb_pattern; - break; - case V4L2_MBUS_FMT_SBGGR10_1X10: - case V4L2_MBUS_FMT_SBGGR12_1X12: - ccdc_pattern = ccdc_sbggr_pattern; - break; - case V4L2_MBUS_FMT_SGBRG10_1X10: - case V4L2_MBUS_FMT_SGBRG12_1X12: - ccdc_pattern = ccdc_sgbrg_pattern; - break; - default: - /* Use GRBG */ - ccdc_pattern = ccdc_sgrbg_pattern; - break; - } - ccdc_config_imgattr(ccdc, ccdc_pattern); - - /* Generate VD0 on the last line of the image and VD1 on the - * 2/3 height line. - */ - isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) | - ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT); - - /* CCDC_PAD_SOURCE_OF */ - format = &ccdc->formats[CCDC_PAD_SOURCE_OF]; - - isp_reg_writel(isp, (0 << ISPCCDC_HORZ_INFO_SPH_SHIFT) | - ((format->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO); - isp_reg_writel(isp, 0 << ISPCCDC_VERT_START_SLV0_SHIFT, - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START); - isp_reg_writel(isp, (format->height - 1) - << ISPCCDC_VERT_LINES_NLV_SHIFT, - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES); - - ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0); - - /* CCDC_PAD_SOURCE_VP */ - format = &ccdc->formats[CCDC_PAD_SOURCE_VP]; - - isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) | - (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ); - isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) | - ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT); - - isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) | - (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT); - - spin_lock_irqsave(&ccdc->lsc.req_lock, flags); - if (ccdc->lsc.request == NULL) - goto unlock; - - WARN_ON(ccdc->lsc.active); - - /* Get last good LSC configuration. If it is not supported for - * the current active resolution discard it. - */ - if (ccdc->lsc.active == NULL && - __ccdc_lsc_configure(ccdc, ccdc->lsc.request) == 0) { - ccdc->lsc.active = ccdc->lsc.request; - } else { - list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue); - schedule_work(&ccdc->lsc.table_work); - } - - ccdc->lsc.request = NULL; - -unlock: - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); - - ccdc_apply_controls(ccdc); -} - -static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable) -{ - struct isp_device *isp = to_isp_device(ccdc); - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR, - ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0); -} - -static int ccdc_disable(struct isp_ccdc_device *ccdc) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&ccdc->lock, flags); - if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS) - ccdc->stopping = CCDC_STOP_REQUEST; - spin_unlock_irqrestore(&ccdc->lock, flags); - - ret = wait_event_timeout(ccdc->wait, - ccdc->stopping == CCDC_STOP_FINISHED, - msecs_to_jiffies(2000)); - if (ret == 0) { - ret = -ETIMEDOUT; - dev_warn(to_device(ccdc), "CCDC stop timeout!\n"); - } - - omap3isp_sbl_disable(to_isp_device(ccdc), OMAP3_ISP_SBL_CCDC_LSC_READ); - - mutex_lock(&ccdc->ioctl_lock); - ccdc_lsc_free_request(ccdc, ccdc->lsc.request); - ccdc->lsc.request = ccdc->lsc.active; - ccdc->lsc.active = NULL; - cancel_work_sync(&ccdc->lsc.table_work); - ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue); - mutex_unlock(&ccdc->ioctl_lock); - - ccdc->stopping = CCDC_STOP_NOT_REQUESTED; - - return ret > 0 ? 0 : ret; -} - -static void ccdc_enable(struct isp_ccdc_device *ccdc) -{ - if (ccdc_lsc_is_configured(ccdc)) - __ccdc_lsc_enable(ccdc, 1); - __ccdc_enable(ccdc, 1); -} - -/* ----------------------------------------------------------------------------- - * Interrupt handling - */ - -/* - * ccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits - * @ccdc: Pointer to ISP CCDC device. - * - * Returns zero if the CCDC is idle and the image has been written to - * memory, too. - */ -static int ccdc_sbl_busy(struct isp_ccdc_device *ccdc) -{ - struct isp_device *isp = to_isp_device(ccdc); - - return omap3isp_ccdc_busy(ccdc) - | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) & - ISPSBL_CCDC_WR_0_DATA_READY) - | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) & - ISPSBL_CCDC_WR_0_DATA_READY) - | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) & - ISPSBL_CCDC_WR_0_DATA_READY) - | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) & - ISPSBL_CCDC_WR_0_DATA_READY); -} - -/* - * ccdc_sbl_wait_idle - Wait until the CCDC and related SBL are idle - * @ccdc: Pointer to ISP CCDC device. - * @max_wait: Max retry count in us for wait for idle/busy transition. - */ -static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc, - unsigned int max_wait) -{ - unsigned int wait = 0; - - if (max_wait == 0) - max_wait = 10000; /* 10 ms */ - - for (wait = 0; wait <= max_wait; wait++) { - if (!ccdc_sbl_busy(ccdc)) - return 0; - - rmb(); - udelay(1); - } - - return -EBUSY; -} - -/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence - * @ccdc: Pointer to ISP CCDC device. - * @event: Pointing which event trigger handler - * - * Return 1 when the event and stopping request combination is satisfyied, - * zero otherwise. - */ -static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) -{ - int rval = 0; - - switch ((ccdc->stopping & 3) | event) { - case CCDC_STOP_REQUEST | CCDC_EVENT_VD1: - if (ccdc->lsc.state != LSC_STATE_STOPPED) - __ccdc_lsc_enable(ccdc, 0); - __ccdc_enable(ccdc, 0); - ccdc->stopping = CCDC_STOP_EXECUTED; - return 1; - - case CCDC_STOP_EXECUTED | CCDC_EVENT_VD0: - ccdc->stopping |= CCDC_STOP_CCDC_FINISHED; - if (ccdc->lsc.state == LSC_STATE_STOPPED) - ccdc->stopping |= CCDC_STOP_LSC_FINISHED; - rval = 1; - break; - - case CCDC_STOP_EXECUTED | CCDC_EVENT_LSC_DONE: - ccdc->stopping |= CCDC_STOP_LSC_FINISHED; - rval = 1; - break; - - case CCDC_STOP_EXECUTED | CCDC_EVENT_VD1: - return 1; - } - - if (ccdc->stopping == CCDC_STOP_FINISHED) { - wake_up(&ccdc->wait); - rval = 1; - } - - return rval; -} - -static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc) -{ - struct video_device *vdev = &ccdc->subdev.devnode; - struct v4l2_event event; - - memset(&event, 0, sizeof(event)); - event.type = V4L2_EVENT_OMAP3ISP_HS_VS; - - v4l2_event_queue(vdev, &event); -} - -/* - * ccdc_lsc_isr - Handle LSC events - * @ccdc: Pointer to ISP CCDC device. - * @events: LSC events - */ -static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events) -{ - unsigned long flags; - - if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) { - ccdc_lsc_error_handler(ccdc); - ccdc->error = 1; - dev_dbg(to_device(ccdc), "lsc prefetch error\n"); - } - - if (!(events & IRQ0STATUS_CCDC_LSC_DONE_IRQ)) - return; - - /* LSC_DONE interrupt occur, there are two cases - * 1. stopping for reconfiguration - * 2. stopping because of STREAM OFF command - */ - spin_lock_irqsave(&ccdc->lsc.req_lock, flags); - - if (ccdc->lsc.state == LSC_STATE_STOPPING) - ccdc->lsc.state = LSC_STATE_STOPPED; - - if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE)) - goto done; - - if (ccdc->lsc.state != LSC_STATE_RECONFIG) - goto done; - - /* LSC is in STOPPING state, change to the new state */ - ccdc->lsc.state = LSC_STATE_STOPPED; - - /* This is an exception. Start of frame and LSC_DONE interrupt - * have been received on the same time. Skip this event and wait - * for better times. - */ - if (events & IRQ0STATUS_HS_VS_IRQ) - goto done; - - /* The LSC engine is stopped at this point. Enable it if there's a - * pending request. - */ - if (ccdc->lsc.request == NULL) - goto done; - - ccdc_lsc_enable(ccdc); - -done: - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); -} - -static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); - struct isp_device *isp = to_isp_device(ccdc); - struct isp_buffer *buffer; - int restart = 0; - - /* The CCDC generates VD0 interrupts even when disabled (the datasheet - * doesn't explicitly state if that's supposed to happen or not, so it - * can be considered as a hardware bug or as a feature, but we have to - * deal with it anyway). Disabling the CCDC when no buffer is available - * would thus not be enough, we need to handle the situation explicitly. - */ - if (list_empty(&ccdc->video_out.dmaqueue)) - goto done; - - /* We're in continuous mode, and memory writes were disabled due to a - * buffer underrun. Reenable them now that we have a buffer. The buffer - * address has been set in ccdc_video_queue. - */ - if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) { - restart = 1; - ccdc->underrun = 0; - goto done; - } - - if (ccdc_sbl_wait_idle(ccdc, 1000)) { - dev_info(isp->dev, "CCDC won't become idle!\n"); - goto done; - } - - buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error); - if (buffer != NULL) { - ccdc_set_outaddr(ccdc, buffer->isp_addr); - restart = 1; - } - - pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; - - if (ccdc->state == ISP_PIPELINE_STREAM_SINGLESHOT && - isp_pipeline_ready(pipe)) - omap3isp_pipeline_set_stream(pipe, - ISP_PIPELINE_STREAM_SINGLESHOT); - -done: - ccdc->error = 0; - return restart; -} - -/* - * ccdc_vd0_isr - Handle VD0 event - * @ccdc: Pointer to ISP CCDC device. - * - * Executes LSC deferred enablement before next frame starts. - */ -static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc) -{ - unsigned long flags; - int restart = 0; - - if (ccdc->output & CCDC_OUTPUT_MEMORY) - restart = ccdc_isr_buffer(ccdc); - - spin_lock_irqsave(&ccdc->lock, flags); - if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) { - spin_unlock_irqrestore(&ccdc->lock, flags); - return; - } - - if (!ccdc->shadow_update) - ccdc_apply_controls(ccdc); - spin_unlock_irqrestore(&ccdc->lock, flags); - - if (restart) - ccdc_enable(ccdc); -} - -/* - * ccdc_vd1_isr - Handle VD1 event - * @ccdc: Pointer to ISP CCDC device. - */ -static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) -{ - unsigned long flags; - - spin_lock_irqsave(&ccdc->lsc.req_lock, flags); - - /* - * Depending on the CCDC pipeline state, CCDC stopping should be - * handled differently. In SINGLESHOT we emulate an internal CCDC - * stopping because the CCDC hw works only in continuous mode. - * When CONTINUOUS pipeline state is used and the CCDC writes it's - * data to memory the CCDC and LSC are stopped immediately but - * without change the CCDC stopping state machine. The CCDC - * stopping state machine should be used only when user request - * for stopping is received (SINGLESHOT is an exeption). - */ - switch (ccdc->state) { - case ISP_PIPELINE_STREAM_SINGLESHOT: - ccdc->stopping = CCDC_STOP_REQUEST; - break; - - case ISP_PIPELINE_STREAM_CONTINUOUS: - if (ccdc->output & CCDC_OUTPUT_MEMORY) { - if (ccdc->lsc.state != LSC_STATE_STOPPED) - __ccdc_lsc_enable(ccdc, 0); - __ccdc_enable(ccdc, 0); - } - break; - - case ISP_PIPELINE_STREAM_STOPPED: - break; - } - - if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1)) - goto done; - - if (ccdc->lsc.request == NULL) - goto done; - - /* - * LSC need to be reconfigured. Stop it here and on next LSC_DONE IRQ - * do the appropriate changes in registers - */ - if (ccdc->lsc.state == LSC_STATE_RUNNING) { - __ccdc_lsc_enable(ccdc, 0); - ccdc->lsc.state = LSC_STATE_RECONFIG; - goto done; - } - - /* LSC has been in STOPPED state, enable it */ - if (ccdc->lsc.state == LSC_STATE_STOPPED) - ccdc_lsc_enable(ccdc); - -done: - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); -} - -/* - * omap3isp_ccdc_isr - Configure CCDC during interframe time. - * @ccdc: Pointer to ISP CCDC device. - * @events: CCDC events - */ -int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events) -{ - if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) - return 0; - - if (events & IRQ0STATUS_CCDC_VD1_IRQ) - ccdc_vd1_isr(ccdc); - - ccdc_lsc_isr(ccdc, events); - - if (events & IRQ0STATUS_CCDC_VD0_IRQ) - ccdc_vd0_isr(ccdc); - - if (events & IRQ0STATUS_HS_VS_IRQ) - ccdc_hs_vs_isr(ccdc); - - return 0; -} - -/* ----------------------------------------------------------------------------- - * ISP video operations - */ - -static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) -{ - struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc; - - if (!(ccdc->output & CCDC_OUTPUT_MEMORY)) - return -ENODEV; - - ccdc_set_outaddr(ccdc, buffer->isp_addr); - - /* We now have a buffer queued on the output, restart the pipeline in - * on the next CCDC interrupt if running in continuous mode (or when - * starting the stream). - */ - ccdc->underrun = 1; - - return 0; -} - -static const struct isp_video_operations ccdc_video_ops = { - .queue = ccdc_video_queue, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -/* - * ccdc_ioctl - CCDC module private ioctl's - * @sd: ISP CCDC V4L2 subdevice - * @cmd: ioctl command - * @arg: ioctl argument - * - * Return 0 on success or a negative error code otherwise. - */ -static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); - int ret; - - switch (cmd) { - case VIDIOC_OMAP3ISP_CCDC_CFG: - mutex_lock(&ccdc->ioctl_lock); - ret = ccdc_config(ccdc, arg); - mutex_unlock(&ccdc->ioctl_lock); - break; - - default: - return -ENOIOCTLCMD; - } - - return ret; -} - -static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS) - return -EINVAL; - - return v4l2_event_subscribe(fh, sub); -} - -static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return v4l2_event_unsubscribe(fh, sub); -} - -/* - * ccdc_set_stream - Enable/Disable streaming on the CCDC module - * @sd: ISP CCDC V4L2 subdevice - * @enable: Enable/disable stream - * - * When writing to memory, the CCDC hardware can't be enabled without a memory - * buffer to write to. As the s_stream operation is called in response to a - * STREAMON call without any buffer queued yet, just update the enabled field - * and return immediately. The CCDC will be enabled in ccdc_isr_buffer(). - * - * When not writing to memory enable the CCDC immediately. - */ -static int ccdc_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); - struct isp_device *isp = to_isp_device(ccdc); - int ret = 0; - - if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) { - if (enable == ISP_PIPELINE_STREAM_STOPPED) - return 0; - - omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_CCDC); - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, - ISPCCDC_CFG_VDLC); - - ccdc_configure(ccdc); - - /* TODO: Don't configure the video port if all of its output - * links are inactive. - */ - ccdc_config_vp(ccdc); - ccdc_enable_vp(ccdc, 1); - ccdc->error = 0; - ccdc_print_status(ccdc); - } - - switch (enable) { - case ISP_PIPELINE_STREAM_CONTINUOUS: - if (ccdc->output & CCDC_OUTPUT_MEMORY) - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE); - - if (ccdc->underrun || !(ccdc->output & CCDC_OUTPUT_MEMORY)) - ccdc_enable(ccdc); - - ccdc->underrun = 0; - break; - - case ISP_PIPELINE_STREAM_SINGLESHOT: - if (ccdc->output & CCDC_OUTPUT_MEMORY && - ccdc->state != ISP_PIPELINE_STREAM_SINGLESHOT) - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE); - - ccdc_enable(ccdc); - break; - - case ISP_PIPELINE_STREAM_STOPPED: - ret = ccdc_disable(ccdc); - if (ccdc->output & CCDC_OUTPUT_MEMORY) - omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CCDC_WRITE); - omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_CCDC); - ccdc->underrun = 0; - break; - } - - ccdc->state = enable; - return ret; -} - -static struct v4l2_mbus_framefmt * -__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); - else - return &ccdc->formats[pad]; -} - -/* - * ccdc_try_format - Try video format on a pad - * @ccdc: ISP CCDC device - * @fh : V4L2 subdev file handle - * @pad: Pad number - * @fmt: Format - */ -static void -ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, - unsigned int pad, struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - struct v4l2_mbus_framefmt *format; - const struct isp_format_info *info; - unsigned int width = fmt->width; - unsigned int height = fmt->height; - unsigned int i; - - switch (pad) { - case CCDC_PAD_SINK: - /* TODO: If the CCDC output formatter pad is connected directly - * to the resizer, only YUV formats can be used. - */ - for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) { - if (fmt->code == ccdc_fmts[i]) - break; - } - - /* If not found, use SGRBG10 as default */ - if (i >= ARRAY_SIZE(ccdc_fmts)) - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; - - /* Clamp the input size. */ - fmt->width = clamp_t(u32, width, 32, 4096); - fmt->height = clamp_t(u32, height, 32, 4096); - break; - - case CCDC_PAD_SOURCE_OF: - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); - memcpy(fmt, format, sizeof(*fmt)); - - /* The data formatter truncates the number of horizontal output - * pixels to a multiple of 16. To avoid clipping data, allow - * callers to request an output size bigger than the input size - * up to the nearest multiple of 16. - */ - fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); - fmt->width &= ~15; - fmt->height = clamp_t(u32, height, 32, fmt->height); - break; - - case CCDC_PAD_SOURCE_VP: - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); - memcpy(fmt, format, sizeof(*fmt)); - - /* The video port interface truncates the data to 10 bits. */ - info = omap3isp_video_format_info(fmt->code); - fmt->code = info->truncated; - - /* The number of lines that can be clocked out from the video - * port output must be at least one line less than the number - * of input lines. - */ - fmt->width = clamp_t(u32, width, 32, fmt->width); - fmt->height = clamp_t(u32, height, 32, fmt->height - 1); - break; - } - - /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is - * stored on 2 bytes. - */ - fmt->colorspace = V4L2_COLORSPACE_SRGB; - fmt->field = V4L2_FIELD_NONE; -} - -/* - * ccdc_enum_mbus_code - Handle pixel format enumeration - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @code : pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - switch (code->pad) { - case CCDC_PAD_SINK: - if (code->index >= ARRAY_SIZE(ccdc_fmts)) - return -EINVAL; - - code->code = ccdc_fmts[code->index]; - break; - - case CCDC_PAD_SOURCE_OF: - case CCDC_PAD_SOURCE_VP: - /* No format conversion inside CCDC */ - if (code->index != 0) - return -EINVAL; - - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); - - code->code = format->code; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int ccdc_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * ccdc_get_format - Retrieve the video format on a pad - * @sd : ISP CCDC V4L2 subdevice - * @fh : V4L2 subdev file handle - * @fmt: Format - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -/* - * ccdc_set_format - Set the video format on a pad - * @sd : ISP CCDC V4L2 subdevice - * @fh : V4L2 subdev file handle - * @fmt: Format - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - /* Propagate the format from sink to source */ - if (fmt->pad == CCDC_PAD_SINK) { - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, - fmt->which); - *format = fmt->format; - ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, - fmt->which); - - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP, - fmt->which); - *format = fmt->format; - ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format, - fmt->which); - } - - return 0; -} - -/* - * ccdc_init_formats - Initialize formats on all pads - * @sd: ISP CCDC V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. - */ -static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = CCDC_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; - format.format.width = 4096; - format.format.height = 4096; - ccdc_set_format(sd, fh, &format); - - return 0; -} - -/* V4L2 subdev core operations */ -static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = { - .ioctl = ccdc_ioctl, - .subscribe_event = ccdc_subscribe_event, - .unsubscribe_event = ccdc_unsubscribe_event, -}; - -/* V4L2 subdev video operations */ -static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = { - .s_stream = ccdc_set_stream, -}; - -/* V4L2 subdev pad operations */ -static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = { - .enum_mbus_code = ccdc_enum_mbus_code, - .enum_frame_size = ccdc_enum_frame_size, - .get_fmt = ccdc_get_format, - .set_fmt = ccdc_set_format, -}; - -/* V4L2 subdev operations */ -static const struct v4l2_subdev_ops ccdc_v4l2_ops = { - .core = &ccdc_v4l2_core_ops, - .video = &ccdc_v4l2_video_ops, - .pad = &ccdc_v4l2_pad_ops, -}; - -/* V4L2 subdev internal operations */ -static const struct v4l2_subdev_internal_ops ccdc_v4l2_internal_ops = { - .open = ccdc_init_formats, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -/* - * ccdc_link_setup - Setup CCDC connections - * @entity: CCDC media entity - * @local: Pad at the local end of the link - * @remote: Pad at the remote end of the link - * @flags: Link flags - * - * return -EINVAL or zero on success - */ -static int ccdc_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); - struct isp_device *isp = to_isp_device(ccdc); - - switch (local->index | media_entity_type(remote->entity)) { - case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: - /* Read from the sensor (parallel interface), CCP2, CSI2a or - * CSI2c. - */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ccdc->input = CCDC_INPUT_NONE; - break; - } - - if (ccdc->input != CCDC_INPUT_NONE) - return -EBUSY; - - if (remote->entity == &isp->isp_ccp2.subdev.entity) - ccdc->input = CCDC_INPUT_CCP2B; - else if (remote->entity == &isp->isp_csi2a.subdev.entity) - ccdc->input = CCDC_INPUT_CSI2A; - else if (remote->entity == &isp->isp_csi2c.subdev.entity) - ccdc->input = CCDC_INPUT_CSI2C; - else - ccdc->input = CCDC_INPUT_PARALLEL; - - break; - - /* - * The ISP core doesn't support pipelines with multiple video outputs. - * Revisit this when it will be implemented, and return -EBUSY for now. - */ - - case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV: - /* Write to preview engine, histogram and H3A. When none of - * those links are active, the video port can be disabled. - */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (ccdc->output & ~CCDC_OUTPUT_PREVIEW) - return -EBUSY; - ccdc->output |= CCDC_OUTPUT_PREVIEW; - } else { - ccdc->output &= ~CCDC_OUTPUT_PREVIEW; - } - break; - - case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE: - /* Write to memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (ccdc->output & ~CCDC_OUTPUT_MEMORY) - return -EBUSY; - ccdc->output |= CCDC_OUTPUT_MEMORY; - } else { - ccdc->output &= ~CCDC_OUTPUT_MEMORY; - } - break; - - case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV: - /* Write to resizer */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (ccdc->output & ~CCDC_OUTPUT_RESIZER) - return -EBUSY; - ccdc->output |= CCDC_OUTPUT_RESIZER; - } else { - ccdc->output &= ~CCDC_OUTPUT_RESIZER; - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* media operations */ -static const struct media_entity_operations ccdc_media_ops = { - .link_setup = ccdc_link_setup, -}; - -/* - * ccdc_init_entities - Initialize V4L2 subdev and media entity - * @ccdc: ISP CCDC module - * - * Return 0 on success and a negative error code on failure. - */ -static int ccdc_init_entities(struct isp_ccdc_device *ccdc) -{ - struct v4l2_subdev *sd = &ccdc->subdev; - struct media_pad *pads = ccdc->pads; - struct media_entity *me = &sd->entity; - int ret; - - ccdc->input = CCDC_INPUT_NONE; - - v4l2_subdev_init(sd, &ccdc_v4l2_ops); - sd->internal_ops = &ccdc_v4l2_internal_ops; - strlcpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for isp subdevs */ - v4l2_set_subdevdata(sd, ccdc); - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - sd->nevents = OMAP3ISP_CCDC_NEVENTS; - - pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; - pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE; - - me->ops = &ccdc_media_ops; - ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0); - if (ret < 0) - return ret; - - ccdc_init_formats(sd, NULL); - - ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ccdc->video_out.ops = &ccdc_video_ops; - ccdc->video_out.isp = to_isp_device(ccdc); - ccdc->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; - ccdc->video_out.bpl_alignment = 32; - - ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); - if (ret < 0) - return ret; - - /* Connect the CCDC subdev to the video node. */ - ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, - &ccdc->video_out.video.entity, 0, 0); - if (ret < 0) - return ret; - - return 0; -} - -void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) -{ - media_entity_cleanup(&ccdc->subdev.entity); - - v4l2_device_unregister_subdev(&ccdc->subdev); - omap3isp_video_unregister(&ccdc->video_out); -} - -int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video node. */ - ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&ccdc->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_ccdc_unregister_entities(ccdc); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP CCDC initialisation and cleanup - */ - -/* - * omap3isp_ccdc_init - CCDC module initialization. - * @dev: Device pointer specific to the OMAP3 ISP. - * - * TODO: Get the initialisation values from platform data. - * - * Return 0 on success or a negative error code otherwise. - */ -int omap3isp_ccdc_init(struct isp_device *isp) -{ - struct isp_ccdc_device *ccdc = &isp->isp_ccdc; - - spin_lock_init(&ccdc->lock); - init_waitqueue_head(&ccdc->wait); - mutex_init(&ccdc->ioctl_lock); - - ccdc->stopping = CCDC_STOP_NOT_REQUESTED; - - INIT_WORK(&ccdc->lsc.table_work, ccdc_lsc_free_table_work); - ccdc->lsc.state = LSC_STATE_STOPPED; - INIT_LIST_HEAD(&ccdc->lsc.free_queue); - spin_lock_init(&ccdc->lsc.req_lock); - - ccdc->syncif.ccdc_mastermode = 0; - ccdc->syncif.datapol = 0; - ccdc->syncif.datsz = 0; - ccdc->syncif.fldmode = 0; - ccdc->syncif.fldout = 0; - ccdc->syncif.fldpol = 0; - ccdc->syncif.fldstat = 0; - ccdc->syncif.hdpol = 0; - ccdc->syncif.vdpol = 0; - - ccdc->clamp.oblen = 0; - ccdc->clamp.dcsubval = 0; - - ccdc->vpcfg.pixelclk = 0; - - ccdc->update = OMAP3ISP_CCDC_BLCLAMP; - ccdc_apply_controls(ccdc); - - return ccdc_init_entities(ccdc); -} - -/* - * omap3isp_ccdc_cleanup - CCDC module cleanup. - * @dev: Device pointer specific to the OMAP3 ISP. - */ -void omap3isp_ccdc_cleanup(struct isp_device *isp) -{ - struct isp_ccdc_device *ccdc = &isp->isp_ccdc; - - /* Free LSC requests. As the CCDC is stopped there's no active request, - * so only the pending request and the free queue need to be handled. - */ - ccdc_lsc_free_request(ccdc, ccdc->lsc.request); - cancel_work_sync(&ccdc->lsc.table_work); - ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue); - - if (ccdc->fpc.fpcaddr != 0) - iommu_vfree(isp->iommu, ccdc->fpc.fpcaddr); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccdc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccdc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccdc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccdc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,219 +0,0 @@ -/* - * ispccdc.h - * - * TI OMAP3 ISP - CCDC module - * - * Copyright (C) 2009-2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_CCDC_H -#define OMAP3_ISP_CCDC_H - -#include -#include - -#include "ispvideo.h" - -enum ccdc_input_entity { - CCDC_INPUT_NONE, - CCDC_INPUT_PARALLEL, - CCDC_INPUT_CSI2A, - CCDC_INPUT_CCP2B, - CCDC_INPUT_CSI2C -}; - -#define CCDC_OUTPUT_MEMORY (1 << 0) -#define CCDC_OUTPUT_PREVIEW (1 << 1) -#define CCDC_OUTPUT_RESIZER (1 << 2) - -#define OMAP3ISP_CCDC_NEVENTS 16 - -/* - * struct ispccdc_syncif - Structure for Sync Interface between sensor and CCDC - * @ccdc_mastermode: Master mode. 1 - Master, 0 - Slave. - * @fldstat: Field state. 0 - Odd Field, 1 - Even Field. - * @datsz: Data size. - * @fldmode: 0 - Progressive, 1 - Interlaced. - * @datapol: 0 - Positive, 1 - Negative. - * @fldpol: 0 - Positive, 1 - Negative. - * @hdpol: 0 - Positive, 1 - Negative. - * @vdpol: 0 - Positive, 1 - Negative. - * @fldout: 0 - Input, 1 - Output. - * @hs_width: Width of the Horizontal Sync pulse, used for HS/VS Output. - * @vs_width: Width of the Vertical Sync pulse, used for HS/VS Output. - * @ppln: Number of pixels per line, used for HS/VS Output. - * @hlprf: Number of half lines per frame, used for HS/VS Output. - * @bt_r656_en: 1 - Enable ITU-R BT656 mode, 0 - Sync mode. - */ -struct ispccdc_syncif { - u8 ccdc_mastermode; - u8 fldstat; - u8 datsz; - u8 fldmode; - u8 datapol; - u8 fldpol; - u8 hdpol; - u8 vdpol; - u8 fldout; - u8 hs_width; - u8 vs_width; - u8 ppln; - u8 hlprf; - u8 bt_r656_en; -}; - -/* - * struct ispccdc_vp - Structure for Video Port parameters - * @pixelclk: Input pixel clock in Hz - */ -struct ispccdc_vp { - unsigned int pixelclk; -}; - -enum ispccdc_lsc_state { - LSC_STATE_STOPPED = 0, - LSC_STATE_STOPPING = 1, - LSC_STATE_RUNNING = 2, - LSC_STATE_RECONFIG = 3, -}; - -struct ispccdc_lsc_config_req { - struct list_head list; - struct omap3isp_ccdc_lsc_config config; - unsigned char enable; - u32 table; - struct iovm_struct *iovm; -}; - -/* - * ispccdc_lsc - CCDC LSC parameters - * @update_config: Set when user changes config - * @request_enable: Whether LSC is requested to be enabled - * @config: LSC config set by user - * @update_table: Set when user provides a new LSC table to table_new - * @table_new: LSC table set by user, ISP address - * @table_inuse: LSC table currently in use, ISP address - */ -struct ispccdc_lsc { - enum ispccdc_lsc_state state; - struct work_struct table_work; - - /* LSC queue of configurations */ - spinlock_t req_lock; - struct ispccdc_lsc_config_req *request; /* requested configuration */ - struct ispccdc_lsc_config_req *active; /* active configuration */ - struct list_head free_queue; /* configurations for freeing */ -}; - -#define CCDC_STOP_NOT_REQUESTED 0x00 -#define CCDC_STOP_REQUEST 0x01 -#define CCDC_STOP_EXECUTED (0x02 | CCDC_STOP_REQUEST) -#define CCDC_STOP_CCDC_FINISHED 0x04 -#define CCDC_STOP_LSC_FINISHED 0x08 -#define CCDC_STOP_FINISHED \ - (CCDC_STOP_EXECUTED | CCDC_STOP_CCDC_FINISHED | CCDC_STOP_LSC_FINISHED) - -#define CCDC_EVENT_VD1 0x10 -#define CCDC_EVENT_VD0 0x20 -#define CCDC_EVENT_LSC_DONE 0x40 - -/* Sink and source CCDC pads */ -#define CCDC_PAD_SINK 0 -#define CCDC_PAD_SOURCE_OF 1 -#define CCDC_PAD_SOURCE_VP 2 -#define CCDC_PADS_NUM 3 - -/* - * struct isp_ccdc_device - Structure for the CCDC module to store its own - * information - * @subdev: V4L2 subdevice - * @pads: Sink and source media entity pads - * @formats: Active video formats - * @input: Active input - * @output: Active outputs - * @video_out: Output video node - * @error: A hardware error occured during capture - * @alaw: A-law compression enabled (1) or disabled (0) - * @lpf: Low pass filter enabled (1) or disabled (0) - * @obclamp: Optical-black clamp enabled (1) or disabled (0) - * @fpc_en: Faulty pixels correction enabled (1) or disabled (0) - * @blcomp: Black level compensation configuration - * @clamp: Optical-black or digital clamp configuration - * @fpc: Faulty pixels correction configuration - * @lsc: Lens shading compensation configuration - * @update: Bitmask of controls to update during the next interrupt - * @shadow_update: Controls update in progress by userspace - * @syncif: Interface synchronization configuration - * @vpcfg: Video port configuration - * @underrun: A buffer underrun occured and a new buffer has been queued - * @state: Streaming state - * @lock: Serializes shadow_update with interrupt handler - * @wait: Wait queue used to stop the module - * @stopping: Stopping state - * @ioctl_lock: Serializes ioctl calls and LSC requests freeing - */ -struct isp_ccdc_device { - struct v4l2_subdev subdev; - struct media_pad pads[CCDC_PADS_NUM]; - struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM]; - - enum ccdc_input_entity input; - unsigned int output; - struct isp_video video_out; - unsigned int error; - - unsigned int alaw:1, - lpf:1, - obclamp:1, - fpc_en:1; - struct omap3isp_ccdc_blcomp blcomp; - struct omap3isp_ccdc_bclamp clamp; - struct omap3isp_ccdc_fpc fpc; - struct ispccdc_lsc lsc; - unsigned int update; - unsigned int shadow_update; - - struct ispccdc_syncif syncif; - struct ispccdc_vp vpcfg; - - unsigned int underrun:1; - enum isp_pipeline_stream_state state; - spinlock_t lock; - wait_queue_head_t wait; - unsigned int stopping; - struct mutex ioctl_lock; -}; - -struct isp_device; - -int omap3isp_ccdc_init(struct isp_device *isp); -void omap3isp_ccdc_cleanup(struct isp_device *isp); -int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, - struct v4l2_device *vdev); -void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc); - -int omap3isp_ccdc_busy(struct isp_ccdc_device *isp_ccdc); -int omap3isp_ccdc_isr(struct isp_ccdc_device *isp_ccdc, u32 events); -void omap3isp_ccdc_restore_context(struct isp_device *isp); -void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc, - unsigned int *max_rate); - -#endif /* OMAP3_ISP_CCDC_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccp2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccp2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccp2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccp2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1173 +0,0 @@ -/* - * ispccp2.c - * - * TI OMAP3 ISP - CCP2 module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2010 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include - -#include "isp.h" -#include "ispreg.h" -#include "ispccp2.h" - -/* Number of LCX channels */ -#define CCP2_LCx_CHANS_NUM 3 -/* Max/Min size for CCP2 video port */ -#define ISPCCP2_DAT_START_MIN 0 -#define ISPCCP2_DAT_START_MAX 4095 -#define ISPCCP2_DAT_SIZE_MIN 0 -#define ISPCCP2_DAT_SIZE_MAX 4095 -#define ISPCCP2_VPCLK_FRACDIV 65536 -#define ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP 0x12 -#define ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP 0x16 -/* Max/Min size for CCP2 memory channel */ -#define ISPCCP2_LCM_HSIZE_COUNT_MIN 16 -#define ISPCCP2_LCM_HSIZE_COUNT_MAX 8191 -#define ISPCCP2_LCM_HSIZE_SKIP_MIN 0 -#define ISPCCP2_LCM_HSIZE_SKIP_MAX 8191 -#define ISPCCP2_LCM_VSIZE_MIN 1 -#define ISPCCP2_LCM_VSIZE_MAX 8191 -#define ISPCCP2_LCM_HWORDS_MIN 1 -#define ISPCCP2_LCM_HWORDS_MAX 4095 -#define ISPCCP2_LCM_CTRL_BURST_SIZE_32X 5 -#define ISPCCP2_LCM_CTRL_READ_THROTTLE_FULL 0 -#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 2 -#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 2 -#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 3 -#define ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 3 -#define ISPCCP2_LCM_CTRL_DST_PORT_VP 0 -#define ISPCCP2_LCM_CTRL_DST_PORT_MEM 1 - -/* Set only the required bits */ -#define BIT_SET(var, shift, mask, val) \ - do { \ - var = ((var) & ~((mask) << (shift))) \ - | ((val) << (shift)); \ - } while (0) - -/* - * ccp2_print_status - Print current CCP2 module register values. - */ -#define CCP2_PRINT_REGISTER(isp, name)\ - dev_dbg(isp->dev, "###CCP2 " #name "=0x%08x\n", \ - isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_##name)) - -static void ccp2_print_status(struct isp_ccp2_device *ccp2) -{ - struct isp_device *isp = to_isp_device(ccp2); - - dev_dbg(isp->dev, "-------------CCP2 Register dump-------------\n"); - - CCP2_PRINT_REGISTER(isp, SYSCONFIG); - CCP2_PRINT_REGISTER(isp, SYSSTATUS); - CCP2_PRINT_REGISTER(isp, LC01_IRQENABLE); - CCP2_PRINT_REGISTER(isp, LC01_IRQSTATUS); - CCP2_PRINT_REGISTER(isp, LC23_IRQENABLE); - CCP2_PRINT_REGISTER(isp, LC23_IRQSTATUS); - CCP2_PRINT_REGISTER(isp, LCM_IRQENABLE); - CCP2_PRINT_REGISTER(isp, LCM_IRQSTATUS); - CCP2_PRINT_REGISTER(isp, CTRL); - CCP2_PRINT_REGISTER(isp, LCx_CTRL(0)); - CCP2_PRINT_REGISTER(isp, LCx_CODE(0)); - CCP2_PRINT_REGISTER(isp, LCx_STAT_START(0)); - CCP2_PRINT_REGISTER(isp, LCx_STAT_SIZE(0)); - CCP2_PRINT_REGISTER(isp, LCx_SOF_ADDR(0)); - CCP2_PRINT_REGISTER(isp, LCx_EOF_ADDR(0)); - CCP2_PRINT_REGISTER(isp, LCx_DAT_START(0)); - CCP2_PRINT_REGISTER(isp, LCx_DAT_SIZE(0)); - CCP2_PRINT_REGISTER(isp, LCx_DAT_PING_ADDR(0)); - CCP2_PRINT_REGISTER(isp, LCx_DAT_PONG_ADDR(0)); - CCP2_PRINT_REGISTER(isp, LCx_DAT_OFST(0)); - CCP2_PRINT_REGISTER(isp, LCM_CTRL); - CCP2_PRINT_REGISTER(isp, LCM_VSIZE); - CCP2_PRINT_REGISTER(isp, LCM_HSIZE); - CCP2_PRINT_REGISTER(isp, LCM_PREFETCH); - CCP2_PRINT_REGISTER(isp, LCM_SRC_ADDR); - CCP2_PRINT_REGISTER(isp, LCM_SRC_OFST); - CCP2_PRINT_REGISTER(isp, LCM_DST_ADDR); - CCP2_PRINT_REGISTER(isp, LCM_DST_OFST); - - dev_dbg(isp->dev, "--------------------------------------------\n"); -} - -/* - * ccp2_reset - Reset the CCP2 - * @ccp2: pointer to ISP CCP2 device - */ -static void ccp2_reset(struct isp_ccp2_device *ccp2) -{ - struct isp_device *isp = to_isp_device(ccp2); - int i = 0; - - /* Reset the CSI1/CCP2B and wait for reset to complete */ - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG, - ISPCCP2_SYSCONFIG_SOFT_RESET); - while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) & - ISPCCP2_SYSSTATUS_RESET_DONE)) { - udelay(10); - if (i++ > 10) { /* try read 10 times */ - dev_warn(isp->dev, - "omap3_isp: timeout waiting for ccp2 reset\n"); - break; - } - } -} - -/* - * ccp2_pwr_cfg - Configure the power mode settings - * @ccp2: pointer to ISP CCP2 device - */ -static void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2) -{ - struct isp_device *isp = to_isp_device(ccp2); - - isp_reg_writel(isp, ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART | - ((isp->revision == ISP_REVISION_15_0 && isp->autoidle) ? - ISPCCP2_SYSCONFIG_AUTO_IDLE : 0), - OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG); -} - -/* - * ccp2_if_enable - Enable CCP2 interface. - * @ccp2: pointer to ISP CCP2 device - * @enable: enable/disable flag - */ -static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) -{ - struct isp_device *isp = to_isp_device(ccp2); - struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); - int i; - - /* Enable/Disable all the LCx channels */ - for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), - ISPCCP2_LCx_CTRL_CHAN_EN, - enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); - - /* Enable/Disable ccp2 interface in ccp2 mode */ - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, - ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, - enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); - - /* For frame count propagation */ - if (pipe->do_propagation) { - /* We may want the Frame Start IRQ from LC0 */ - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, - ISPCCP2_LC01_IRQENABLE, - ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2, - ISPCCP2_LC01_IRQENABLE, - ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); - } -} - -/* - * ccp2_mem_enable - Enable CCP2 memory interface. - * @ccp2: pointer to ISP CCP2 device - * @enable: enable/disable flag - */ -static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) -{ - struct isp_device *isp = to_isp_device(ccp2); - - if (enable) - ccp2_if_enable(ccp2, 0); - - /* Enable/Disable ccp2 interface in ccp2 mode */ - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, - ISPCCP2_CTRL_MODE, enable ? ISPCCP2_CTRL_MODE : 0); - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL, - ISPCCP2_LCM_CTRL_CHAN_EN, - enable ? ISPCCP2_LCM_CTRL_CHAN_EN : 0); -} - -/* - * ccp2_phyif_config - Initialize CCP2 phy interface config - * @ccp2: Pointer to ISP CCP2 device - * @config: CCP2 platform data - * - * Configure the CCP2 physical interface module from platform data. - * - * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success. - */ -static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, - const struct isp_ccp2_platform_data *pdata) -{ - struct isp_device *isp = to_isp_device(ccp2); - u32 val; - - /* CCP2B mode */ - val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) | - ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE; - /* Data/strobe physical layer */ - BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, - pdata->phy_layer); - BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, - pdata->strobe_clk_pol); - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); - - val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); - if (!(val & ISPCCP2_CTRL_MODE)) { - if (pdata->ccp2_mode) - dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); - if (pdata->phy_layer == ISPCCP2_CTRL_PHY_SEL_STROBE) - /* Strobe mode requires CCP2 */ - return -EIO; - } - - return 0; -} - -/* - * ccp2_vp_config - Initialize CCP2 video port interface. - * @ccp2: Pointer to ISP CCP2 device - * @vpclk_div: Video port divisor - * - * Configure the CCP2 video port with the given clock divisor. The valid divisor - * values depend on the ISP revision: - * - * - revision 1.0 and 2.0 1 to 4 - * - revision 15.0 1 to 65536 - * - * The exact divisor value used might differ from the requested value, as ISP - * revision 15.0 represent the divisor by 65536 divided by an integer. - */ -static void ccp2_vp_config(struct isp_ccp2_device *ccp2, - unsigned int vpclk_div) -{ - struct isp_device *isp = to_isp_device(ccp2); - u32 val; - - /* ISPCCP2_CTRL Video port */ - val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); - val |= ISPCCP2_CTRL_VP_ONLY_EN; /* Disable the memory write port */ - - if (isp->revision == ISP_REVISION_15_0) { - vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 65536); - vpclk_div = min(ISPCCP2_VPCLK_FRACDIV / vpclk_div, 65535U); - BIT_SET(val, ISPCCP2_CTRL_VPCLK_DIV_SHIFT, - ISPCCP2_CTRL_VPCLK_DIV_MASK, vpclk_div); - } else { - vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 4); - BIT_SET(val, ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT, - ISPCCP2_CTRL_VP_OUT_CTRL_MASK, vpclk_div - 1); - } - - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); -} - -/* - * ccp2_lcx_config - Initialize CCP2 logical channel interface. - * @ccp2: Pointer to ISP CCP2 device - * @config: Pointer to ISP LCx config structure. - * - * This will analyze the parameters passed by the interface config - * and configure CSI1/CCP2 logical channel - * - */ -static void ccp2_lcx_config(struct isp_ccp2_device *ccp2, - struct isp_interface_lcx_config *config) -{ - struct isp_device *isp = to_isp_device(ccp2); - u32 val, format; - - switch (config->format) { - case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: - format = ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP; - break; - case V4L2_MBUS_FMT_SGRBG10_1X10: - default: - format = ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP; /* RAW10+VP */ - break; - } - /* ISPCCP2_LCx_CTRL logical channel #0 */ - val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0)) - | (ISPCCP2_LCx_CTRL_REGION_EN); /* Region */ - - if (isp->revision == ISP_REVISION_15_0) { - /* CRC */ - BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0, - ISPCCP2_LCx_CTRL_CRC_MASK, - config->crc); - /* Format = RAW10+VP or RAW8+DPCM10+VP*/ - BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0, - ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0, format); - } else { - BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT, - ISPCCP2_LCx_CTRL_CRC_MASK, - config->crc); - - BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT, - ISPCCP2_LCx_CTRL_FORMAT_MASK, format); - } - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0)); - - /* ISPCCP2_DAT_START for logical channel #0 */ - isp_reg_writel(isp, config->data_start << ISPCCP2_LCx_DAT_SHIFT, - OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_START(0)); - - /* ISPCCP2_DAT_SIZE for logical channel #0 */ - isp_reg_writel(isp, config->data_size << ISPCCP2_LCx_DAT_SHIFT, - OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_SIZE(0)); - - /* Enable error IRQs for logical channel #0 */ - val = ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ; - - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQSTATUS); - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, val); -} - -/* - * ccp2_if_configure - Configure ccp2 with data from sensor - * @ccp2: Pointer to ISP CCP2 device - * - * Return 0 on success or a negative error code - */ -static int ccp2_if_configure(struct isp_ccp2_device *ccp2) -{ - const struct isp_v4l2_subdevs_group *pdata; - struct v4l2_mbus_framefmt *format; - struct media_pad *pad; - struct v4l2_subdev *sensor; - u32 lines = 0; - int ret; - - ccp2_pwr_cfg(ccp2); - - pad = media_entity_remote_source(&ccp2->pads[CCP2_PAD_SINK]); - sensor = media_entity_to_v4l2_subdev(pad->entity); - pdata = sensor->host_priv; - - ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2); - if (ret < 0) - return ret; - - ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1); - - v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines); - - format = &ccp2->formats[CCP2_PAD_SINK]; - - ccp2->if_cfg.data_start = lines; - ccp2->if_cfg.crc = pdata->bus.ccp2.crc; - ccp2->if_cfg.format = format->code; - ccp2->if_cfg.data_size = format->height; - - ccp2_lcx_config(ccp2, &ccp2->if_cfg); - - return 0; -} - -static int ccp2_adjust_bandwidth(struct isp_ccp2_device *ccp2) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); - struct isp_device *isp = to_isp_device(ccp2); - const struct v4l2_mbus_framefmt *ofmt = &ccp2->formats[CCP2_PAD_SOURCE]; - unsigned long l3_ick = pipe->l3_ick; - struct v4l2_fract *timeperframe; - unsigned int vpclk_div = 2; - unsigned int value; - u64 bound; - u64 area; - - /* Compute the minimum clock divisor, based on the pipeline maximum - * data rate. This is an absolute lower bound if we don't want SBL - * overflows, so round the value up. - */ - vpclk_div = max_t(unsigned int, DIV_ROUND_UP(l3_ick, pipe->max_rate), - vpclk_div); - - /* Compute the maximum clock divisor, based on the requested frame rate. - * This is a soft lower bound to achieve a frame rate equal or higher - * than the requested value, so round the value down. - */ - timeperframe = &pipe->max_timeperframe; - - if (timeperframe->numerator) { - area = ofmt->width * ofmt->height; - bound = div_u64(area * timeperframe->denominator, - timeperframe->numerator); - value = min_t(u64, bound, l3_ick); - vpclk_div = max_t(unsigned int, l3_ick / value, vpclk_div); - } - - dev_dbg(isp->dev, "%s: minimum clock divisor = %u\n", __func__, - vpclk_div); - - return vpclk_div; -} - -/* - * ccp2_mem_configure - Initialize CCP2 memory input/output interface - * @ccp2: Pointer to ISP CCP2 device - * @config: Pointer to ISP mem interface config structure - * - * This will analyze the parameters passed by the interface config - * structure, and configure the respective registers for proper - * CSI1/CCP2 memory input. - */ -static void ccp2_mem_configure(struct isp_ccp2_device *ccp2, - struct isp_interface_mem_config *config) -{ - struct isp_device *isp = to_isp_device(ccp2); - u32 sink_pixcode = ccp2->formats[CCP2_PAD_SINK].code; - u32 source_pixcode = ccp2->formats[CCP2_PAD_SOURCE].code; - unsigned int dpcm_decompress = 0; - u32 val, hwords; - - if (sink_pixcode != source_pixcode && - sink_pixcode == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) - dpcm_decompress = 1; - - ccp2_pwr_cfg(ccp2); - - /* Hsize, Skip */ - isp_reg_writel(isp, ISPCCP2_LCM_HSIZE_SKIP_MIN | - (config->hsize_count << ISPCCP2_LCM_HSIZE_SHIFT), - OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_HSIZE); - - /* Vsize, no. of lines */ - isp_reg_writel(isp, config->vsize_count << ISPCCP2_LCM_VSIZE_SHIFT, - OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_VSIZE); - - if (ccp2->video_in.bpl_padding == 0) - config->src_ofst = 0; - else - config->src_ofst = ccp2->video_in.bpl_value; - - isp_reg_writel(isp, config->src_ofst, OMAP3_ISP_IOMEM_CCP2, - ISPCCP2_LCM_SRC_OFST); - - /* Source and Destination formats */ - val = ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 << - ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT; - - if (dpcm_decompress) { - /* source format is RAW8 */ - val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 << - ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT; - - /* RAW8 + DPCM10 - simple predictor */ - val |= ISPCCP2_LCM_CTRL_SRC_DPCM_PRED; - - /* enable source DPCM decompression */ - val |= ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 << - ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT; - } else { - /* source format is RAW10 */ - val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 << - ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT; - } - - /* Burst size to 32x64 */ - val |= ISPCCP2_LCM_CTRL_BURST_SIZE_32X << - ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT; - - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL); - - /* Prefetch setup */ - if (dpcm_decompress) - hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN + - config->hsize_count) >> 3; - else - hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN + - config->hsize_count) >> 2; - - isp_reg_writel(isp, hwords << ISPCCP2_LCM_PREFETCH_SHIFT, - OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_PREFETCH); - - /* Video port */ - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, - ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE); - ccp2_vp_config(ccp2, ccp2_adjust_bandwidth(ccp2)); - - /* Clear LCM interrupts */ - isp_reg_writel(isp, ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ | - ISPCCP2_LCM_IRQSTATUS_EOF_IRQ, - OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQSTATUS); - - /* Enable LCM interupts */ - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQENABLE, - ISPCCP2_LCM_IRQSTATUS_EOF_IRQ | - ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ); -} - -/* - * ccp2_set_inaddr - Sets memory address of input frame. - * @ccp2: Pointer to ISP CCP2 device - * @addr: 32bit memory address aligned on 32byte boundary. - * - * Configures the memory address from which the input frame is to be read. - */ -static void ccp2_set_inaddr(struct isp_ccp2_device *ccp2, u32 addr) -{ - struct isp_device *isp = to_isp_device(ccp2); - - isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_SRC_ADDR); -} - -/* ----------------------------------------------------------------------------- - * Interrupt handling - */ - -static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); - struct isp_buffer *buffer; - - buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error); - if (buffer != NULL) - ccp2_set_inaddr(ccp2, buffer->isp_addr); - - pipe->state |= ISP_PIPELINE_IDLE_INPUT; - - if (ccp2->state == ISP_PIPELINE_STREAM_SINGLESHOT) { - if (isp_pipeline_ready(pipe)) - omap3isp_pipeline_set_stream(pipe, - ISP_PIPELINE_STREAM_SINGLESHOT); - } - - ccp2->error = 0; -} - -/* - * omap3isp_ccp2_isr - Handle ISP CCP2 interrupts - * @ccp2: Pointer to ISP CCP2 device - * - * This will handle the CCP2 interrupts - * - * Returns -EIO in case of error, or 0 on success. - */ -int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) -{ - struct isp_device *isp = to_isp_device(ccp2); - int ret = 0; - static const u32 ISPCCP2_LC01_ERROR = - ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ | - ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ; - u32 lcx_irqstatus, lcm_irqstatus; - - /* First clear the interrupts */ - lcx_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, - ISPCCP2_LC01_IRQSTATUS); - isp_reg_writel(isp, lcx_irqstatus, OMAP3_ISP_IOMEM_CCP2, - ISPCCP2_LC01_IRQSTATUS); - - lcm_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, - ISPCCP2_LCM_IRQSTATUS); - isp_reg_writel(isp, lcm_irqstatus, OMAP3_ISP_IOMEM_CCP2, - ISPCCP2_LCM_IRQSTATUS); - /* Errors */ - if (lcx_irqstatus & ISPCCP2_LC01_ERROR) { - ccp2->error = 1; - dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus); - return -EIO; - } - - if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) { - ccp2->error = 1; - dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus); - ret = -EIO; - } - - if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping)) - return 0; - - /* Frame number propagation */ - if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) { - struct isp_pipeline *pipe = - to_isp_pipeline(&ccp2->subdev.entity); - if (pipe->do_propagation) - atomic_inc(&pipe->frame_number); - } - - /* Handle queued buffers on frame end interrupts */ - if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ) - ccp2_isr_buffer(ccp2); - - return ret; -} - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -static const unsigned int ccp2_fmts[] = { - V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, -}; - -/* - * __ccp2_get_format - helper function for getting ccp2 format - * @ccp2 : Pointer to ISP CCP2 device - * @fh : V4L2 subdev file handle - * @pad : pad number - * @which : wanted subdev format - * return format structure or NULL on error - */ -static struct v4l2_mbus_framefmt * -__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); - else - return &ccp2->formats[pad]; -} - -/* - * ccp2_try_format - Handle try format by pad subdev method - * @ccp2 : Pointer to ISP CCP2 device - * @fh : V4L2 subdev file handle - * @pad : pad num - * @fmt : pointer to v4l2 mbus format structure - * @which : wanted subdev format - */ -static void ccp2_try_format(struct isp_ccp2_device *ccp2, - struct v4l2_subdev_fh *fh, unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - struct v4l2_mbus_framefmt *format; - - switch (pad) { - case CCP2_PAD_SINK: - if (fmt->code != V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; - - if (ccp2->input == CCP2_INPUT_SENSOR) { - fmt->width = clamp_t(u32, fmt->width, - ISPCCP2_DAT_START_MIN, - ISPCCP2_DAT_START_MAX); - fmt->height = clamp_t(u32, fmt->height, - ISPCCP2_DAT_SIZE_MIN, - ISPCCP2_DAT_SIZE_MAX); - } else if (ccp2->input == CCP2_INPUT_MEMORY) { - fmt->width = clamp_t(u32, fmt->width, - ISPCCP2_LCM_HSIZE_COUNT_MIN, - ISPCCP2_LCM_HSIZE_COUNT_MAX); - fmt->height = clamp_t(u32, fmt->height, - ISPCCP2_LCM_VSIZE_MIN, - ISPCCP2_LCM_VSIZE_MAX); - } - break; - - case CCP2_PAD_SOURCE: - /* Source format - copy sink format and change pixel code - * to SGRBG10_1X10 as we don't support CCP2 write to memory. - * When CCP2 write to memory feature will be added this - * should be changed properly. - */ - format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which); - memcpy(fmt, format, sizeof(*fmt)); - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; - break; - } - - fmt->field = V4L2_FIELD_NONE; - fmt->colorspace = V4L2_COLORSPACE_SRGB; -} - -/* - * ccp2_enum_mbus_code - Handle pixel format enumeration - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @code : pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - if (code->pad == CCP2_PAD_SINK) { - if (code->index >= ARRAY_SIZE(ccp2_fmts)) - return -EINVAL; - - code->code = ccp2_fmts[code->index]; - } else { - if (code->index != 0) - return -EINVAL; - - format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); - code->code = format->code; - } - - return 0; -} - -static int ccp2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * ccp2_get_format - Handle get format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @fmt : pointer to v4l2 subdev format structure - * return -EINVAL or zero on sucess - */ -static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -/* - * ccp2_set_format - Handle set format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @fmt : pointer to v4l2 subdev format structure - * returns zero - */ -static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - /* Propagate the format from sink to source */ - if (fmt->pad == CCP2_PAD_SINK) { - format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE, - fmt->which); - *format = fmt->format; - ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which); - } - - return 0; -} - -/* - * ccp2_init_formats - Initialize formats on all pads - * @sd: ISP CCP2 V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. - */ -static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = CCP2_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; - format.format.width = 4096; - format.format.height = 4096; - ccp2_set_format(sd, fh, &format); - - return 0; -} - -/* - * ccp2_s_stream - Enable/Disable streaming on ccp2 subdev - * @sd : pointer to v4l2 subdev structure - * @enable: 1 == Enable, 0 == Disable - * return zero - */ -static int ccp2_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); - struct isp_device *isp = to_isp_device(ccp2); - struct device *dev = to_device(ccp2); - int ret; - - if (ccp2->state == ISP_PIPELINE_STREAM_STOPPED) { - if (enable == ISP_PIPELINE_STREAM_STOPPED) - return 0; - atomic_set(&ccp2->stopping, 0); - ccp2->error = 0; - } - - switch (enable) { - case ISP_PIPELINE_STREAM_CONTINUOUS: - if (ccp2->phy) { - ret = omap3isp_csiphy_acquire(ccp2->phy); - if (ret < 0) - return ret; - } - - ccp2_if_configure(ccp2); - ccp2_print_status(ccp2); - - /* Enable CSI1/CCP2 interface */ - ccp2_if_enable(ccp2, 1); - break; - - case ISP_PIPELINE_STREAM_SINGLESHOT: - if (ccp2->state != ISP_PIPELINE_STREAM_SINGLESHOT) { - struct v4l2_mbus_framefmt *format; - - format = &ccp2->formats[CCP2_PAD_SINK]; - - ccp2->mem_cfg.hsize_count = format->width; - ccp2->mem_cfg.vsize_count = format->height; - ccp2->mem_cfg.src_ofst = 0; - - ccp2_mem_configure(ccp2, &ccp2->mem_cfg); - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI1_READ); - ccp2_print_status(ccp2); - } - ccp2_mem_enable(ccp2, 1); - break; - - case ISP_PIPELINE_STREAM_STOPPED: - if (omap3isp_module_sync_idle(&sd->entity, &ccp2->wait, - &ccp2->stopping)) - dev_dbg(dev, "%s: module stop timeout.\n", sd->name); - if (ccp2->input == CCP2_INPUT_MEMORY) { - ccp2_mem_enable(ccp2, 0); - omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI1_READ); - } else if (ccp2->input == CCP2_INPUT_SENSOR) { - /* Disable CSI1/CCP2 interface */ - ccp2_if_enable(ccp2, 0); - if (ccp2->phy) - omap3isp_csiphy_release(ccp2->phy); - } - break; - } - - ccp2->state = enable; - return 0; -} - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops ccp2_sd_video_ops = { - .s_stream = ccp2_s_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops ccp2_sd_pad_ops = { - .enum_mbus_code = ccp2_enum_mbus_code, - .enum_frame_size = ccp2_enum_frame_size, - .get_fmt = ccp2_get_format, - .set_fmt = ccp2_set_format, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops ccp2_sd_ops = { - .video = &ccp2_sd_video_ops, - .pad = &ccp2_sd_pad_ops, -}; - -/* subdev internal operations */ -static const struct v4l2_subdev_internal_ops ccp2_sd_internal_ops = { - .open = ccp2_init_formats, -}; - -/* -------------------------------------------------------------------------- - * ISP ccp2 video device node - */ - -/* - * ccp2_video_queue - Queue video buffer. - * @video : Pointer to isp video structure - * @buffer: Pointer to isp_buffer structure - * return -EIO or zero on success - */ -static int ccp2_video_queue(struct isp_video *video, struct isp_buffer *buffer) -{ - struct isp_ccp2_device *ccp2 = &video->isp->isp_ccp2; - - ccp2_set_inaddr(ccp2, buffer->isp_addr); - return 0; -} - -static const struct isp_video_operations ccp2_video_ops = { - .queue = ccp2_video_queue, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -/* - * ccp2_link_setup - Setup ccp2 connections. - * @entity : Pointer to media entity structure - * @local : Pointer to local pad array - * @remote : Pointer to remote pad array - * @flags : Link flags - * return -EINVAL on error or zero on success - */ -static int ccp2_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); - - switch (local->index | media_entity_type(remote->entity)) { - case CCP2_PAD_SINK | MEDIA_ENT_T_DEVNODE: - /* read from memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (ccp2->input == CCP2_INPUT_SENSOR) - return -EBUSY; - ccp2->input = CCP2_INPUT_MEMORY; - } else { - if (ccp2->input == CCP2_INPUT_MEMORY) - ccp2->input = CCP2_INPUT_NONE; - } - break; - - case CCP2_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: - /* read from sensor/phy */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (ccp2->input == CCP2_INPUT_MEMORY) - return -EBUSY; - ccp2->input = CCP2_INPUT_SENSOR; - } else { - if (ccp2->input == CCP2_INPUT_SENSOR) - ccp2->input = CCP2_INPUT_NONE; - } break; - - case CCP2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: - /* write to video port/ccdc */ - if (flags & MEDIA_LNK_FL_ENABLED) - ccp2->output = CCP2_OUTPUT_CCDC; - else - ccp2->output = CCP2_OUTPUT_NONE; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* media operations */ -static const struct media_entity_operations ccp2_media_ops = { - .link_setup = ccp2_link_setup, -}; - -/* - * ccp2_init_entities - Initialize ccp2 subdev and media entity. - * @ccp2: Pointer to ISP CCP2 device - * return negative error code or zero on success - */ -static int ccp2_init_entities(struct isp_ccp2_device *ccp2) -{ - struct v4l2_subdev *sd = &ccp2->subdev; - struct media_pad *pads = ccp2->pads; - struct media_entity *me = &sd->entity; - int ret; - - ccp2->input = CCP2_INPUT_NONE; - ccp2->output = CCP2_OUTPUT_NONE; - - v4l2_subdev_init(sd, &ccp2_sd_ops); - sd->internal_ops = &ccp2_sd_internal_ops; - strlcpy(sd->name, "OMAP3 ISP CCP2", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for isp subdevs */ - v4l2_set_subdevdata(sd, ccp2); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - me->ops = &ccp2_media_ops; - ret = media_entity_init(me, CCP2_PADS_NUM, pads, 0); - if (ret < 0) - return ret; - - ccp2_init_formats(sd, NULL); - - /* - * The CCP2 has weird line alignment requirements, possibly caused by - * DPCM8 decompression. Line length for data read from memory must be a - * multiple of 128 bits (16 bytes) in continuous mode (when no padding - * is present at end of lines). Additionally, if padding is used, the - * padded line length must be a multiple of 32 bytes. To simplify the - * implementation we use a fixed 32 bytes alignment regardless of the - * input format and width. If strict 128 bits alignment support is - * required ispvideo will need to be made aware of this special dual - * alignement requirements. - */ - ccp2->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ccp2->video_in.bpl_alignment = 32; - ccp2->video_in.bpl_max = 0xffffffe0; - ccp2->video_in.isp = to_isp_device(ccp2); - ccp2->video_in.ops = &ccp2_video_ops; - ccp2->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; - - ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); - if (ret < 0) - return ret; - - /* Connect the video node to the ccp2 subdev. */ - ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, - &ccp2->subdev.entity, CCP2_PAD_SINK, 0); - if (ret < 0) - return ret; - - return 0; -} - -/* - * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev - * @ccp2: Pointer to ISP CCP2 device - */ -void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) -{ - media_entity_cleanup(&ccp2->subdev.entity); - - v4l2_device_unregister_subdev(&ccp2->subdev); - omap3isp_video_unregister(&ccp2->video_in); -} - -/* - * omap3isp_ccp2_register_entities - Register the subdev media entity - * @ccp2: Pointer to ISP CCP2 device - * @vdev: Pointer to v4l device - * return negative error code or zero on success - */ - -int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&ccp2->video_in, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_ccp2_unregister_entities(ccp2); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP ccp2 initialisation and cleanup - */ - -/* - * omap3isp_ccp2_cleanup - CCP2 un-initialization - * @isp : Pointer to ISP device - */ -void omap3isp_ccp2_cleanup(struct isp_device *isp) -{ -} - -/* - * omap3isp_ccp2_init - CCP2 initialization. - * @isp : Pointer to ISP device - * return negative error code or zero on success - */ -int omap3isp_ccp2_init(struct isp_device *isp) -{ - struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; - int ret; - - init_waitqueue_head(&ccp2->wait); - - /* On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with - * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly - * configured. - * - * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c). - */ - if (isp->revision == ISP_REVISION_15_0) - ccp2->phy = &isp->isp_csiphy1; - - ret = ccp2_init_entities(ccp2); - if (ret < 0) - goto out; - - ccp2_reset(ccp2); -out: - if (ret) - omap3isp_ccp2_cleanup(isp); - - return ret; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccp2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccp2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccp2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispccp2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -/* - * ispccp2.h - * - * TI OMAP3 ISP - CCP2 module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2010 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_CCP2_H -#define OMAP3_ISP_CCP2_H - -#include - -struct isp_device; -struct isp_csiphy; - -/* Sink and source ccp2 pads */ -#define CCP2_PAD_SINK 0 -#define CCP2_PAD_SOURCE 1 -#define CCP2_PADS_NUM 2 - -/* CCP2 input media entity */ -enum ccp2_input_entity { - CCP2_INPUT_NONE, - CCP2_INPUT_SENSOR, - CCP2_INPUT_MEMORY, -}; - -/* CCP2 output media entity */ -enum ccp2_output_entity { - CCP2_OUTPUT_NONE, - CCP2_OUTPUT_CCDC, - CCP2_OUTPUT_MEMORY, -}; - - -/* Logical channel configuration */ -struct isp_interface_lcx_config { - int crc; - u32 data_start; - u32 data_size; - u32 format; -}; - -/* Memory channel configuration */ -struct isp_interface_mem_config { - u32 dst_port; - u32 vsize_count; - u32 hsize_count; - u32 src_ofst; - u32 dst_ofst; -}; - -/* CCP2 device */ -struct isp_ccp2_device { - struct v4l2_subdev subdev; - struct v4l2_mbus_framefmt formats[CCP2_PADS_NUM]; - struct media_pad pads[CCP2_PADS_NUM]; - - enum ccp2_input_entity input; - enum ccp2_output_entity output; - struct isp_interface_lcx_config if_cfg; - struct isp_interface_mem_config mem_cfg; - struct isp_video video_in; - struct isp_csiphy *phy; - unsigned int error; - enum isp_pipeline_stream_state state; - wait_queue_head_t wait; - atomic_t stopping; -}; - -/* Function declarations */ -int omap3isp_ccp2_init(struct isp_device *isp); -void omap3isp_ccp2_cleanup(struct isp_device *isp); -int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, - struct v4l2_device *vdev); -void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2); -int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2); - -#endif /* OMAP3_ISP_CCP2_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsi2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsi2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsi2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsi2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1317 +0,0 @@ -/* - * ispcsi2.c - * - * TI OMAP3 ISP - CSI2 module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ -#include -#include -#include -#include - -#include "isp.h" -#include "ispreg.h" -#include "ispcsi2.h" - -/* - * csi2_if_enable - Enable CSI2 Receiver interface. - * @enable: enable flag - * - */ -static void csi2_if_enable(struct isp_device *isp, - struct isp_csi2_device *csi2, u8 enable) -{ - struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl; - - isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN, - enable ? ISPCSI2_CTRL_IF_EN : 0); - - currctrl->if_enable = enable; -} - -/* - * csi2_recv_config - CSI2 receiver module configuration. - * @currctrl: isp_csi2_ctrl_cfg structure - * - */ -static void csi2_recv_config(struct isp_device *isp, - struct isp_csi2_device *csi2, - struct isp_csi2_ctrl_cfg *currctrl) -{ - u32 reg; - - reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL); - - if (currctrl->frame_mode) - reg |= ISPCSI2_CTRL_FRAME; - else - reg &= ~ISPCSI2_CTRL_FRAME; - - if (currctrl->vp_clk_enable) - reg |= ISPCSI2_CTRL_VP_CLK_EN; - else - reg &= ~ISPCSI2_CTRL_VP_CLK_EN; - - if (currctrl->vp_only_enable) - reg |= ISPCSI2_CTRL_VP_ONLY_EN; - else - reg &= ~ISPCSI2_CTRL_VP_ONLY_EN; - - reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK; - reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT; - - if (currctrl->ecc_enable) - reg |= ISPCSI2_CTRL_ECC_EN; - else - reg &= ~ISPCSI2_CTRL_ECC_EN; - - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL); -} - -static const unsigned int csi2_input_fmts[] = { - V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, - V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, - V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, - V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, -}; - -/* To set the format on the CSI2 requires a mapping function that takes - * the following inputs: - * - 2 different formats (at this time) - * - 2 destinations (mem, vp+mem) (vp only handled separately) - * - 2 decompression options (on, off) - * - 2 isp revisions (certain format must be handled differently on OMAP3630) - * Output should be CSI2 frame format code - * Array indices as follows: [format][dest][decompr][is_3630] - * Not all combinations are valid. 0 means invalid. - */ -static const u16 __csi2_fmt_map[2][2][2][2] = { - /* RAW10 formats */ - { - /* Output to memory */ - { - /* No DPCM decompression */ - { CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 }, - /* DPCM decompression */ - { 0, 0 }, - }, - /* Output to both */ - { - /* No DPCM decompression */ - { CSI2_PIX_FMT_RAW10_EXP16_VP, - CSI2_PIX_FMT_RAW10_EXP16_VP }, - /* DPCM decompression */ - { 0, 0 }, - }, - }, - /* RAW10 DPCM8 formats */ - { - /* Output to memory */ - { - /* No DPCM decompression */ - { CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 }, - /* DPCM decompression */ - { CSI2_PIX_FMT_RAW8_DPCM10_EXP16, - CSI2_USERDEF_8BIT_DATA1_DPCM10 }, - }, - /* Output to both */ - { - /* No DPCM decompression */ - { CSI2_PIX_FMT_RAW8_VP, - CSI2_PIX_FMT_RAW8_VP }, - /* DPCM decompression */ - { CSI2_PIX_FMT_RAW8_DPCM10_VP, - CSI2_USERDEF_8BIT_DATA1_DPCM10_VP }, - }, - }, -}; - -/* - * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID - * @csi2: ISP CSI2 device - * - * Returns CSI2 physical format id - */ -static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2) -{ - const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK]; - int fmtidx, destidx, is_3630; - - switch (fmt->code) { - case V4L2_MBUS_FMT_SGRBG10_1X10: - case V4L2_MBUS_FMT_SRGGB10_1X10: - case V4L2_MBUS_FMT_SBGGR10_1X10: - case V4L2_MBUS_FMT_SGBRG10_1X10: - fmtidx = 0; - break; - case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: - case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8: - case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8: - case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8: - fmtidx = 1; - break; - default: - WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n", - fmt->code); - return 0; - } - - if (!(csi2->output & CSI2_OUTPUT_CCDC) && - !(csi2->output & CSI2_OUTPUT_MEMORY)) { - /* Neither output enabled is a valid combination */ - return CSI2_PIX_FMT_OTHERS; - } - - /* If we need to skip frames at the beginning of the stream disable the - * video port to avoid sending the skipped frames to the CCDC. - */ - destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC); - is_3630 = csi2->isp->revision == ISP_REVISION_15_0; - - return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress][is_3630]; -} - -/* - * csi2_set_outaddr - Set memory address to save output image - * @csi2: Pointer to ISP CSI2a device. - * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary. - * - * Sets the memory address where the output will be saved. - * - * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte - * boundary. - */ -static void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr) -{ - struct isp_device *isp = csi2->isp; - struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0]; - - ctx->ping_addr = addr; - ctx->pong_addr = addr; - isp_reg_writel(isp, ctx->ping_addr, - csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum)); - isp_reg_writel(isp, ctx->pong_addr, - csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum)); -} - -/* - * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should - * be enabled by CSI2. - * @format_id: mapped format id - * - */ -static inline int is_usr_def_mapping(u32 format_id) -{ - return (format_id & 0x40) ? 1 : 0; -} - -/* - * csi2_ctx_enable - Enable specified CSI2 context - * @ctxnum: Context number, valid between 0 and 7 values. - * @enable: enable - * - */ -static void csi2_ctx_enable(struct isp_device *isp, - struct isp_csi2_device *csi2, u8 ctxnum, u8 enable) -{ - struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum]; - unsigned int skip = 0; - u32 reg; - - reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); - - if (enable) { - if (csi2->frame_skip) - skip = csi2->frame_skip; - else if (csi2->output & CSI2_OUTPUT_MEMORY) - skip = 1; - - reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK; - reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK - | (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT) - | ISPCSI2_CTX_CTRL1_CTX_EN; - } else { - reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN; - } - - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); - ctx->enabled = enable; -} - -/* - * csi2_ctx_config - CSI2 context configuration. - * @ctx: context configuration - * - */ -static void csi2_ctx_config(struct isp_device *isp, - struct isp_csi2_device *csi2, - struct isp_csi2_ctx_cfg *ctx) -{ - u32 reg; - - /* Set up CSI2_CTx_CTRL1 */ - reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum)); - - if (ctx->eof_enabled) - reg |= ISPCSI2_CTX_CTRL1_EOF_EN; - else - reg &= ~ISPCSI2_CTX_CTRL1_EOF_EN; - - if (ctx->eol_enabled) - reg |= ISPCSI2_CTX_CTRL1_EOL_EN; - else - reg &= ~ISPCSI2_CTX_CTRL1_EOL_EN; - - if (ctx->checksum_enabled) - reg |= ISPCSI2_CTX_CTRL1_CS_EN; - else - reg &= ~ISPCSI2_CTX_CTRL1_CS_EN; - - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum)); - - /* Set up CSI2_CTx_CTRL2 */ - reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum)); - - reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK); - reg |= ctx->virtual_id << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT; - - reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK); - reg |= ctx->format_id << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT; - - if (ctx->dpcm_decompress) { - if (ctx->dpcm_predictor) - reg |= ISPCSI2_CTX_CTRL2_DPCM_PRED; - else - reg &= ~ISPCSI2_CTX_CTRL2_DPCM_PRED; - } - - if (is_usr_def_mapping(ctx->format_id)) { - reg &= ~ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK; - reg |= 2 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT; - } - - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum)); - - /* Set up CSI2_CTx_CTRL3 */ - reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum)); - reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK); - reg |= (ctx->alpha << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT); - - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum)); - - /* Set up CSI2_CTx_DAT_OFST */ - reg = isp_reg_readl(isp, csi2->regs1, - ISPCSI2_CTX_DAT_OFST(ctx->ctxnum)); - reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK; - reg |= ctx->data_offset << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT; - isp_reg_writel(isp, reg, csi2->regs1, - ISPCSI2_CTX_DAT_OFST(ctx->ctxnum)); - - isp_reg_writel(isp, ctx->ping_addr, - csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum)); - - isp_reg_writel(isp, ctx->pong_addr, - csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum)); -} - -/* - * csi2_timing_config - CSI2 timing configuration. - * @timing: csi2_timing_cfg structure - */ -static void csi2_timing_config(struct isp_device *isp, - struct isp_csi2_device *csi2, - struct isp_csi2_timing_cfg *timing) -{ - u32 reg; - - reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING); - - if (timing->force_rx_mode) - reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); - else - reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); - - if (timing->stop_state_16x) - reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); - else - reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); - - if (timing->stop_state_4x) - reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); - else - reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); - - reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum); - reg |= timing->stop_state_counter << - ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum); - - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING); -} - -/* - * csi2_irq_ctx_set - Enables CSI2 Context IRQs. - * @enable: Enable/disable CSI2 Context interrupts - */ -static void csi2_irq_ctx_set(struct isp_device *isp, - struct isp_csi2_device *csi2, int enable) -{ - u32 reg = ISPCSI2_CTX_IRQSTATUS_FE_IRQ; - int i; - - if (csi2->use_fs_irq) - reg |= ISPCSI2_CTX_IRQSTATUS_FS_IRQ; - - for (i = 0; i < 8; i++) { - isp_reg_writel(isp, reg, csi2->regs1, - ISPCSI2_CTX_IRQSTATUS(i)); - if (enable) - isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), - reg); - else - isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), - reg); - } -} - -/* - * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs. - * @enable: Enable/disable CSI2 ComplexIO #1 interrupts - */ -static void csi2_irq_complexio1_set(struct isp_device *isp, - struct isp_csi2_device *csi2, int enable) -{ - u32 reg; - reg = ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT | - ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER | - ISPCSI2_PHY_IRQENABLE_STATEULPM5 | - ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 | - ISPCSI2_PHY_IRQENABLE_ERRESC5 | - ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 | - ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 | - ISPCSI2_PHY_IRQENABLE_STATEULPM4 | - ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 | - ISPCSI2_PHY_IRQENABLE_ERRESC4 | - ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 | - ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 | - ISPCSI2_PHY_IRQENABLE_STATEULPM3 | - ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 | - ISPCSI2_PHY_IRQENABLE_ERRESC3 | - ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 | - ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 | - ISPCSI2_PHY_IRQENABLE_STATEULPM2 | - ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 | - ISPCSI2_PHY_IRQENABLE_ERRESC2 | - ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 | - ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 | - ISPCSI2_PHY_IRQENABLE_STATEULPM1 | - ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 | - ISPCSI2_PHY_IRQENABLE_ERRESC1 | - ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 | - ISPCSI2_PHY_IRQENABLE_ERRSOTHS1; - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQSTATUS); - if (enable) - reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQENABLE); - else - reg = 0; - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQENABLE); -} - -/* - * csi2_irq_status_set - Enables CSI2 Status IRQs. - * @enable: Enable/disable CSI2 Status interrupts - */ -static void csi2_irq_status_set(struct isp_device *isp, - struct isp_csi2_device *csi2, int enable) -{ - u32 reg; - reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | - ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | - ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ | - ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | - ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | - ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ | - ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ | - ISPCSI2_IRQSTATUS_CONTEXT(0); - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS); - if (enable) - reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE); - else - reg = 0; - - isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE); -} - -/* - * omap3isp_csi2_reset - Resets the CSI2 module. - * - * Must be called with the phy lock held. - * - * Returns 0 if successful, or -EBUSY if power command didn't respond. - */ -int omap3isp_csi2_reset(struct isp_csi2_device *csi2) -{ - struct isp_device *isp = csi2->isp; - u8 soft_reset_retries = 0; - u32 reg; - int i; - - if (!csi2->available) - return -ENODEV; - - if (csi2->phy->phy_in_use) - return -EBUSY; - - isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, - ISPCSI2_SYSCONFIG_SOFT_RESET); - - do { - reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) & - ISPCSI2_SYSSTATUS_RESET_DONE; - if (reg == ISPCSI2_SYSSTATUS_RESET_DONE) - break; - soft_reset_retries++; - if (soft_reset_retries < 5) - udelay(100); - } while (soft_reset_retries < 5); - - if (soft_reset_retries == 5) { - printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n"); - return -EBUSY; - } - - if (isp->revision == ISP_REVISION_15_0) - isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG, - ISPCSI2_PHY_CFG_RESET_CTRL); - - i = 100; - do { - reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1) - & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK; - if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK) - break; - udelay(100); - } while (--i > 0); - - if (i == 0) { - printk(KERN_ERR - "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n"); - return -EBUSY; - } - - if (isp->autoidle) - isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, - ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | - ISPCSI2_SYSCONFIG_AUTO_IDLE, - ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART | - ((isp->revision == ISP_REVISION_15_0) ? - ISPCSI2_SYSCONFIG_AUTO_IDLE : 0)); - else - isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, - ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | - ISPCSI2_SYSCONFIG_AUTO_IDLE, - ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO); - - return 0; -} - -static int csi2_configure(struct isp_csi2_device *csi2) -{ - const struct isp_v4l2_subdevs_group *pdata; - struct isp_device *isp = csi2->isp; - struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; - struct v4l2_subdev *sensor; - struct media_pad *pad; - - /* - * CSI2 fields that can be updated while the context has - * been enabled or the interface has been enabled are not - * updated dynamically currently. So we do not allow to - * reconfigure if either has been enabled - */ - if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) - return -EBUSY; - - pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]); - sensor = media_entity_to_v4l2_subdev(pad->entity); - pdata = sensor->host_priv; - - csi2->frame_skip = 0; - v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); - - csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div; - csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; - csi2->ctrl.ecc_enable = pdata->bus.csi2.crc; - - timing->ionum = 1; - timing->force_rx_mode = 1; - timing->stop_state_16x = 1; - timing->stop_state_4x = 1; - timing->stop_state_counter = 0x1FF; - - /* - * The CSI2 receiver can't do any format conversion except DPCM - * decompression, so every set_format call configures both pads - * and enables DPCM decompression as a special case: - */ - if (csi2->formats[CSI2_PAD_SINK].code != - csi2->formats[CSI2_PAD_SOURCE].code) - csi2->dpcm_decompress = true; - else - csi2->dpcm_decompress = false; - - csi2->contexts[0].format_id = csi2_ctx_map_format(csi2); - - if (csi2->video_out.bpl_padding == 0) - csi2->contexts[0].data_offset = 0; - else - csi2->contexts[0].data_offset = csi2->video_out.bpl_value; - - /* - * Enable end of frame and end of line signals generation for - * context 0. These signals are generated from CSI2 receiver to - * qualify the last pixel of a frame and the last pixel of a line. - * Without enabling the signals CSI2 receiver writes data to memory - * beyond buffer size and/or data line offset is not handled correctly. - */ - csi2->contexts[0].eof_enabled = 1; - csi2->contexts[0].eol_enabled = 1; - - csi2_irq_complexio1_set(isp, csi2, 1); - csi2_irq_ctx_set(isp, csi2, 1); - csi2_irq_status_set(isp, csi2, 1); - - /* Set configuration (timings, format and links) */ - csi2_timing_config(isp, csi2, timing); - csi2_recv_config(isp, csi2, &csi2->ctrl); - csi2_ctx_config(isp, csi2, &csi2->contexts[0]); - - return 0; -} - -/* - * csi2_print_status - Prints CSI2 debug information. - */ -#define CSI2_PRINT_REGISTER(isp, regs, name)\ - dev_dbg(isp->dev, "###CSI2 " #name "=0x%08x\n", \ - isp_reg_readl(isp, regs, ISPCSI2_##name)) - -static void csi2_print_status(struct isp_csi2_device *csi2) -{ - struct isp_device *isp = csi2->isp; - - if (!csi2->available) - return; - - dev_dbg(isp->dev, "-------------CSI2 Register dump-------------\n"); - - CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSCONFIG); - CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSSTATUS); - CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQENABLE); - CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQSTATUS); - CSI2_PRINT_REGISTER(isp, csi2->regs1, CTRL); - CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_H); - CSI2_PRINT_REGISTER(isp, csi2->regs1, GNQ); - CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_CFG); - CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQSTATUS); - CSI2_PRINT_REGISTER(isp, csi2->regs1, SHORT_PACKET); - CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQENABLE); - CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_P); - CSI2_PRINT_REGISTER(isp, csi2->regs1, TIMING); - CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL1(0)); - CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL2(0)); - CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_OFST(0)); - CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PING_ADDR(0)); - CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PONG_ADDR(0)); - CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQENABLE(0)); - CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQSTATUS(0)); - CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL3(0)); - - dev_dbg(isp->dev, "--------------------------------------------\n"); -} - -/* ----------------------------------------------------------------------------- - * Interrupt handling - */ - -/* - * csi2_isr_buffer - Does buffer handling at end-of-frame - * when writing to memory. - */ -static void csi2_isr_buffer(struct isp_csi2_device *csi2) -{ - struct isp_device *isp = csi2->isp; - struct isp_buffer *buffer; - - csi2_ctx_enable(isp, csi2, 0, 0); - - buffer = omap3isp_video_buffer_next(&csi2->video_out, 0); - - /* - * Let video queue operation restart engine if there is an underrun - * condition. - */ - if (buffer == NULL) - return; - - csi2_set_outaddr(csi2, buffer->isp_addr); - csi2_ctx_enable(isp, csi2, 0, 1); -} - -static void csi2_isr_ctx(struct isp_csi2_device *csi2, - struct isp_csi2_ctx_cfg *ctx) -{ - struct isp_device *isp = csi2->isp; - unsigned int n = ctx->ctxnum; - u32 status; - - status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); - isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); - - /* Propagate frame number */ - if (status & ISPCSI2_CTX_IRQSTATUS_FS_IRQ) { - struct isp_pipeline *pipe = - to_isp_pipeline(&csi2->subdev.entity); - if (pipe->do_propagation) - atomic_inc(&pipe->frame_number); - } - - if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ)) - return; - - /* Skip interrupts until we reach the frame skip count. The CSI2 will be - * automatically disabled, as the frame skip count has been programmed - * in the CSI2_CTx_CTRL1::COUNT field, so reenable it. - * - * It would have been nice to rely on the FRAME_NUMBER interrupt instead - * but it turned out that the interrupt is only generated when the CSI2 - * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased - * correctly and reaches 0 when data is forwarded to the video port only - * but no interrupt arrives). Maybe a CSI2 hardware bug. - */ - if (csi2->frame_skip) { - csi2->frame_skip--; - if (csi2->frame_skip == 0) { - ctx->format_id = csi2_ctx_map_format(csi2); - csi2_ctx_config(isp, csi2, ctx); - csi2_ctx_enable(isp, csi2, n, 1); - } - return; - } - - if (csi2->output & CSI2_OUTPUT_MEMORY) - csi2_isr_buffer(csi2); -} - -/* - * omap3isp_csi2_isr - CSI2 interrupt handling. - * - * Return -EIO on Transmission error - */ -int omap3isp_csi2_isr(struct isp_csi2_device *csi2) -{ - u32 csi2_irqstatus, cpxio1_irqstatus; - struct isp_device *isp = csi2->isp; - int retval = 0; - - if (!csi2->available) - return -ENODEV; - - csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS); - isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS); - - /* Failure Cases */ - if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) { - cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1, - ISPCSI2_PHY_IRQSTATUS); - isp_reg_writel(isp, cpxio1_irqstatus, - csi2->regs1, ISPCSI2_PHY_IRQSTATUS); - dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ " - "%x\n", cpxio1_irqstatus); - retval = -EIO; - } - - if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | - ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | - ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | - ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | - ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) { - dev_dbg(isp->dev, "CSI2 Err:" - " OCP:%d," - " Short_pack:%d," - " ECC:%d," - " CPXIO2:%d," - " FIFO_OVF:%d," - "\n", - (csi2_irqstatus & - ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0, - (csi2_irqstatus & - ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0, - (csi2_irqstatus & - ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0, - (csi2_irqstatus & - ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0, - (csi2_irqstatus & - ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0); - retval = -EIO; - } - - if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) - return 0; - - /* Successful cases */ - if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) - csi2_isr_ctx(csi2, &csi2->contexts[0]); - - if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ) - dev_dbg(isp->dev, "CSI2: ECC correction done\n"); - - return retval; -} - -/* ----------------------------------------------------------------------------- - * ISP video operations - */ - -/* - * csi2_queue - Queues the first buffer when using memory output - * @video: The video node - * @buffer: buffer to queue - */ -static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer) -{ - struct isp_device *isp = video->isp; - struct isp_csi2_device *csi2 = &isp->isp_csi2a; - - csi2_set_outaddr(csi2, buffer->isp_addr); - - /* - * If streaming was enabled before there was a buffer queued - * or underrun happened in the ISR, the hardware was not enabled - * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set. - * Enable it now. - */ - if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { - /* Enable / disable context 0 and IRQs */ - csi2_if_enable(isp, csi2, 1); - csi2_ctx_enable(isp, csi2, 0, 1); - isp_video_dmaqueue_flags_clr(&csi2->video_out); - } - - return 0; -} - -static const struct isp_video_operations csi2_ispvideo_ops = { - .queue = csi2_queue, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -static struct v4l2_mbus_framefmt * -__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); - else - return &csi2->formats[pad]; -} - -static void -csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, - unsigned int pad, struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - enum v4l2_mbus_pixelcode pixelcode; - struct v4l2_mbus_framefmt *format; - const struct isp_format_info *info; - unsigned int i; - - switch (pad) { - case CSI2_PAD_SINK: - /* Clamp the width and height to valid range (1-8191). */ - for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) { - if (fmt->code == csi2_input_fmts[i]) - break; - } - - /* If not found, use SGRBG10 as default */ - if (i >= ARRAY_SIZE(csi2_input_fmts)) - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; - - fmt->width = clamp_t(u32, fmt->width, 1, 8191); - fmt->height = clamp_t(u32, fmt->height, 1, 8191); - break; - - case CSI2_PAD_SOURCE: - /* Source format same as sink format, except for DPCM - * compression. - */ - pixelcode = fmt->code; - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which); - memcpy(fmt, format, sizeof(*fmt)); - - /* - * Only Allow DPCM decompression, and check that the - * pattern is preserved - */ - info = omap3isp_video_format_info(fmt->code); - if (info->uncompressed == pixelcode) - fmt->code = pixelcode; - break; - } - - /* RGB, non-interlaced */ - fmt->colorspace = V4L2_COLORSPACE_SRGB; - fmt->field = V4L2_FIELD_NONE; -} - -/* - * csi2_enum_mbus_code - Handle pixel format enumeration - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @code : pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int csi2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - const struct isp_format_info *info; - - if (code->pad == CSI2_PAD_SINK) { - if (code->index >= ARRAY_SIZE(csi2_input_fmts)) - return -EINVAL; - - code->code = csi2_input_fmts[code->index]; - } else { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); - switch (code->index) { - case 0: - /* Passthrough sink pad code */ - code->code = format->code; - break; - case 1: - /* Uncompressed code */ - info = omap3isp_video_format_info(format->code); - if (info->uncompressed == format->code) - return -EINVAL; - - code->code = info->uncompressed; - break; - default: - return -EINVAL; - } - } - - return 0; -} - -static int csi2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * csi2_get_format - Handle get format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on sucess - */ -static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -/* - * csi2_set_format - Handle set format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - /* Propagate the format from sink to source */ - if (fmt->pad == CSI2_PAD_SINK) { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE, - fmt->which); - *format = fmt->format; - csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which); - } - - return 0; -} - -/* - * csi2_init_formats - Initialize formats on all pads - * @sd: ISP CSI2 V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. - */ -static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = CSI2_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; - format.format.width = 4096; - format.format.height = 4096; - csi2_set_format(sd, fh, &format); - - return 0; -} - -/* - * csi2_set_stream - Enable/Disable streaming on the CSI2 module - * @sd: ISP CSI2 V4L2 subdevice - * @enable: ISP pipeline stream state - * - * Return 0 on success or a negative error code otherwise. - */ -static int csi2_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct isp_device *isp = csi2->isp; - struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); - struct isp_video *video_out = &csi2->video_out; - - switch (enable) { - case ISP_PIPELINE_STREAM_CONTINUOUS: - if (omap3isp_csiphy_acquire(csi2->phy) < 0) - return -ENODEV; - csi2->use_fs_irq = pipe->do_propagation; - if (csi2->output & CSI2_OUTPUT_MEMORY) - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); - csi2_configure(csi2); - csi2_print_status(csi2); - - /* - * When outputting to memory with no buffer available, let the - * buffer queue handler start the hardware. A DMA queue flag - * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is - * a buffer available. - */ - if (csi2->output & CSI2_OUTPUT_MEMORY && - !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED)) - break; - /* Enable context 0 and IRQs */ - atomic_set(&csi2->stopping, 0); - csi2_ctx_enable(isp, csi2, 0, 1); - csi2_if_enable(isp, csi2, 1); - isp_video_dmaqueue_flags_clr(video_out); - break; - - case ISP_PIPELINE_STREAM_STOPPED: - if (csi2->state == ISP_PIPELINE_STREAM_STOPPED) - return 0; - if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait, - &csi2->stopping)) - dev_dbg(isp->dev, "%s: module stop timeout.\n", - sd->name); - csi2_ctx_enable(isp, csi2, 0, 0); - csi2_if_enable(isp, csi2, 0); - csi2_irq_ctx_set(isp, csi2, 0); - omap3isp_csiphy_release(csi2->phy); - isp_video_dmaqueue_flags_clr(video_out); - omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); - break; - } - - csi2->state = enable; - return 0; -} - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops csi2_video_ops = { - .s_stream = csi2_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops csi2_pad_ops = { - .enum_mbus_code = csi2_enum_mbus_code, - .enum_frame_size = csi2_enum_frame_size, - .get_fmt = csi2_get_format, - .set_fmt = csi2_set_format, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops csi2_ops = { - .video = &csi2_video_ops, - .pad = &csi2_pad_ops, -}; - -/* subdev internal operations */ -static const struct v4l2_subdev_internal_ops csi2_internal_ops = { - .open = csi2_init_formats, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -/* - * csi2_link_setup - Setup CSI2 connections. - * @entity : Pointer to media entity structure - * @local : Pointer to local pad array - * @remote : Pointer to remote pad array - * @flags : Link flags - * return -EINVAL or zero on success - */ -static int csi2_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl; - - /* - * The ISP core doesn't support pipelines with multiple video outputs. - * Revisit this when it will be implemented, and return -EBUSY for now. - */ - - switch (local->index | media_entity_type(remote->entity)) { - case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: - if (flags & MEDIA_LNK_FL_ENABLED) { - if (csi2->output & ~CSI2_OUTPUT_MEMORY) - return -EBUSY; - csi2->output |= CSI2_OUTPUT_MEMORY; - } else { - csi2->output &= ~CSI2_OUTPUT_MEMORY; - } - break; - - case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: - if (flags & MEDIA_LNK_FL_ENABLED) { - if (csi2->output & ~CSI2_OUTPUT_CCDC) - return -EBUSY; - csi2->output |= CSI2_OUTPUT_CCDC; - } else { - csi2->output &= ~CSI2_OUTPUT_CCDC; - } - break; - - default: - /* Link from camera to CSI2 is fixed... */ - return -EINVAL; - } - - ctrl->vp_only_enable = - (csi2->output & CSI2_OUTPUT_MEMORY) ? false : true; - ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_CCDC); - - return 0; -} - -/* media operations */ -static const struct media_entity_operations csi2_media_ops = { - .link_setup = csi2_link_setup, -}; - -/* - * csi2_init_entities - Initialize subdev and media entity. - * @csi2: Pointer to csi2 structure. - * return -ENOMEM or zero on success - */ -static int csi2_init_entities(struct isp_csi2_device *csi2) -{ - struct v4l2_subdev *sd = &csi2->subdev; - struct media_pad *pads = csi2->pads; - struct media_entity *me = &sd->entity; - int ret; - - v4l2_subdev_init(sd, &csi2_ops); - sd->internal_ops = &csi2_internal_ops; - strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name)); - - sd->grp_id = 1 << 16; /* group ID for isp subdevs */ - v4l2_set_subdevdata(sd, csi2); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - - me->ops = &csi2_media_ops; - ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0); - if (ret < 0) - return ret; - - csi2_init_formats(sd, NULL); - - /* Video device node */ - csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - csi2->video_out.ops = &csi2_ispvideo_ops; - csi2->video_out.bpl_alignment = 32; - csi2->video_out.bpl_zero_padding = 1; - csi2->video_out.bpl_max = 0x1ffe0; - csi2->video_out.isp = csi2->isp; - csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; - - ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); - if (ret < 0) - return ret; - - /* Connect the CSI2 subdev to the video node. */ - ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, - &csi2->video_out.video.entity, 0, 0); - if (ret < 0) - return ret; - - return 0; -} - -void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) -{ - media_entity_cleanup(&csi2->subdev.entity); - - v4l2_device_unregister_subdev(&csi2->subdev); - omap3isp_video_unregister(&csi2->video_out); -} - -int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &csi2->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&csi2->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_csi2_unregister_entities(csi2); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP CSI2 initialisation and cleanup - */ - -/* - * omap3isp_csi2_cleanup - Routine for module driver cleanup - */ -void omap3isp_csi2_cleanup(struct isp_device *isp) -{ -} - -/* - * omap3isp_csi2_init - Routine for module driver init - */ -int omap3isp_csi2_init(struct isp_device *isp) -{ - struct isp_csi2_device *csi2a = &isp->isp_csi2a; - struct isp_csi2_device *csi2c = &isp->isp_csi2c; - int ret; - - csi2a->isp = isp; - csi2a->available = 1; - csi2a->regs1 = OMAP3_ISP_IOMEM_CSI2A_REGS1; - csi2a->regs2 = OMAP3_ISP_IOMEM_CSI2A_REGS2; - csi2a->phy = &isp->isp_csiphy2; - csi2a->state = ISP_PIPELINE_STREAM_STOPPED; - init_waitqueue_head(&csi2a->wait); - - ret = csi2_init_entities(csi2a); - if (ret < 0) - goto fail; - - if (isp->revision == ISP_REVISION_15_0) { - csi2c->isp = isp; - csi2c->available = 1; - csi2c->regs1 = OMAP3_ISP_IOMEM_CSI2C_REGS1; - csi2c->regs2 = OMAP3_ISP_IOMEM_CSI2C_REGS2; - csi2c->phy = &isp->isp_csiphy1; - csi2c->state = ISP_PIPELINE_STREAM_STOPPED; - init_waitqueue_head(&csi2c->wait); - } - - return 0; -fail: - omap3isp_csi2_cleanup(isp); - return ret; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsi2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsi2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsi2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsi2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,166 +0,0 @@ -/* - * ispcsi2.h - * - * TI OMAP3 ISP - CSI2 module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_CSI2_H -#define OMAP3_ISP_CSI2_H - -#include -#include - -struct isp_csiphy; - -/* This is not an exhaustive list */ -enum isp_csi2_pix_formats { - CSI2_PIX_FMT_OTHERS = 0, - CSI2_PIX_FMT_YUV422_8BIT = 0x1e, - CSI2_PIX_FMT_YUV422_8BIT_VP = 0x9e, - CSI2_PIX_FMT_RAW10_EXP16 = 0xab, - CSI2_PIX_FMT_RAW10_EXP16_VP = 0x12f, - CSI2_PIX_FMT_RAW8 = 0x2a, - CSI2_PIX_FMT_RAW8_DPCM10_EXP16 = 0x2aa, - CSI2_PIX_FMT_RAW8_DPCM10_VP = 0x32a, - CSI2_PIX_FMT_RAW8_VP = 0x12a, - CSI2_USERDEF_8BIT_DATA1_DPCM10_VP = 0x340, - CSI2_USERDEF_8BIT_DATA1_DPCM10 = 0x2c0, - CSI2_USERDEF_8BIT_DATA1 = 0x40, -}; - -enum isp_csi2_irqevents { - OCP_ERR_IRQ = 0x4000, - SHORT_PACKET_IRQ = 0x2000, - ECC_CORRECTION_IRQ = 0x1000, - ECC_NO_CORRECTION_IRQ = 0x800, - COMPLEXIO2_ERR_IRQ = 0x400, - COMPLEXIO1_ERR_IRQ = 0x200, - FIFO_OVF_IRQ = 0x100, - CONTEXT7 = 0x80, - CONTEXT6 = 0x40, - CONTEXT5 = 0x20, - CONTEXT4 = 0x10, - CONTEXT3 = 0x8, - CONTEXT2 = 0x4, - CONTEXT1 = 0x2, - CONTEXT0 = 0x1, -}; - -enum isp_csi2_ctx_irqevents { - CTX_ECC_CORRECTION = 0x100, - CTX_LINE_NUMBER = 0x80, - CTX_FRAME_NUMBER = 0x40, - CTX_CS = 0x20, - CTX_LE = 0x8, - CTX_LS = 0x4, - CTX_FE = 0x2, - CTX_FS = 0x1, -}; - -enum isp_csi2_frame_mode { - ISP_CSI2_FRAME_IMMEDIATE, - ISP_CSI2_FRAME_AFTERFEC, -}; - -#define ISP_CSI2_MAX_CTX_NUM 7 - -struct isp_csi2_ctx_cfg { - u8 ctxnum; /* context number 0 - 7 */ - u8 dpcm_decompress; - - /* Fields in CSI2_CTx_CTRL2 - locked by CSI2_CTx_CTRL1.CTX_EN */ - u8 virtual_id; - u16 format_id; /* as in CSI2_CTx_CTRL2[9:0] */ - u8 dpcm_predictor; /* 1: simple, 0: advanced */ - - /* Fields in CSI2_CTx_CTRL1/3 - Shadowed */ - u16 alpha; - u16 data_offset; - u32 ping_addr; - u32 pong_addr; - u8 eof_enabled; - u8 eol_enabled; - u8 checksum_enabled; - u8 enabled; -}; - -struct isp_csi2_timing_cfg { - u8 ionum; /* IO1 or IO2 as in CSI2_TIMING */ - unsigned force_rx_mode:1; - unsigned stop_state_16x:1; - unsigned stop_state_4x:1; - u16 stop_state_counter; -}; - -struct isp_csi2_ctrl_cfg { - bool vp_clk_enable; - bool vp_only_enable; - u8 vp_out_ctrl; - enum isp_csi2_frame_mode frame_mode; - bool ecc_enable; - bool if_enable; -}; - -#define CSI2_PAD_SINK 0 -#define CSI2_PAD_SOURCE 1 -#define CSI2_PADS_NUM 2 - -#define CSI2_OUTPUT_CCDC (1 << 0) -#define CSI2_OUTPUT_MEMORY (1 << 1) - -struct isp_csi2_device { - struct v4l2_subdev subdev; - struct media_pad pads[CSI2_PADS_NUM]; - struct v4l2_mbus_framefmt formats[CSI2_PADS_NUM]; - - struct isp_video video_out; - struct isp_device *isp; - - u8 available; /* Is the IP present on the silicon? */ - - /* mem resources - enums as defined in enum isp_mem_resources */ - u8 regs1; - u8 regs2; - - u32 output; /* output to CCDC, memory or both? */ - bool dpcm_decompress; - unsigned int frame_skip; - bool use_fs_irq; - - struct isp_csiphy *phy; - struct isp_csi2_ctx_cfg contexts[ISP_CSI2_MAX_CTX_NUM + 1]; - struct isp_csi2_timing_cfg timing[2]; - struct isp_csi2_ctrl_cfg ctrl; - enum isp_pipeline_stream_state state; - wait_queue_head_t wait; - atomic_t stopping; -}; - -int omap3isp_csi2_isr(struct isp_csi2_device *csi2); -int omap3isp_csi2_reset(struct isp_csi2_device *csi2); -int omap3isp_csi2_init(struct isp_device *isp); -void omap3isp_csi2_cleanup(struct isp_device *isp); -void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2); -int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, - struct v4l2_device *vdev); -#endif /* OMAP3_ISP_CSI2_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsiphy.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsiphy.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsiphy.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsiphy.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,247 +0,0 @@ -/* - * ispcsiphy.c - * - * TI OMAP3 ISP - CSI PHY module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include - -#include "isp.h" -#include "ispreg.h" -#include "ispcsiphy.h" - -/* - * csiphy_lanes_config - Configuration of CSIPHY lanes. - * - * Updates HW configuration. - * Called with phy->mutex taken. - */ -static void csiphy_lanes_config(struct isp_csiphy *phy) -{ - unsigned int i; - u32 reg; - - reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG); - - for (i = 0; i < phy->num_data_lanes; i++) { - reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) | - ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1)); - reg |= (phy->lanes.data[i].pol << - ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1)); - reg |= (phy->lanes.data[i].pos << - ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1)); - } - - reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK | - ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK); - reg |= phy->lanes.clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT; - reg |= phy->lanes.clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT; - - isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG); -} - -/* - * csiphy_power_autoswitch_enable - * @enable: Sets or clears the autoswitch function enable flag. - */ -static void csiphy_power_autoswitch_enable(struct isp_csiphy *phy, bool enable) -{ - isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG, - ISPCSI2_PHY_CFG_PWR_AUTO, - enable ? ISPCSI2_PHY_CFG_PWR_AUTO : 0); -} - -/* - * csiphy_set_power - * @power: Power state to be set. - * - * Returns 0 if successful, or -EBUSY if the retry count is exceeded. - */ -static int csiphy_set_power(struct isp_csiphy *phy, u32 power) -{ - u32 reg; - u8 retry_count; - - isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG, - ISPCSI2_PHY_CFG_PWR_CMD_MASK, power); - - retry_count = 0; - do { - udelay(50); - reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG) & - ISPCSI2_PHY_CFG_PWR_STATUS_MASK; - - if (reg != power >> 2) - retry_count++; - - } while ((reg != power >> 2) && (retry_count < 100)); - - if (retry_count == 100) { - printk(KERN_ERR "CSI2 CIO set power failed!\n"); - return -EBUSY; - } - - return 0; -} - -/* - * csiphy_dphy_config - Configure CSI2 D-PHY parameters. - * - * Called with phy->mutex taken. - */ -static void csiphy_dphy_config(struct isp_csiphy *phy) -{ - u32 reg; - - /* Set up ISPCSIPHY_REG0 */ - reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0); - - reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK | - ISPCSIPHY_REG0_THS_SETTLE_MASK); - reg |= phy->dphy.ths_term << ISPCSIPHY_REG0_THS_TERM_SHIFT; - reg |= phy->dphy.ths_settle << ISPCSIPHY_REG0_THS_SETTLE_SHIFT; - - isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0); - - /* Set up ISPCSIPHY_REG1 */ - reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1); - - reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK | - ISPCSIPHY_REG1_TCLK_MISS_MASK | - ISPCSIPHY_REG1_TCLK_SETTLE_MASK); - reg |= phy->dphy.tclk_term << ISPCSIPHY_REG1_TCLK_TERM_SHIFT; - reg |= phy->dphy.tclk_miss << ISPCSIPHY_REG1_TCLK_MISS_SHIFT; - reg |= phy->dphy.tclk_settle << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT; - - isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1); -} - -static int csiphy_config(struct isp_csiphy *phy, - struct isp_csiphy_dphy_cfg *dphy, - struct isp_csiphy_lanes_cfg *lanes) -{ - unsigned int used_lanes = 0; - unsigned int i; - - /* Clock and data lanes verification */ - for (i = 0; i < phy->num_data_lanes; i++) { - if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3) - return -EINVAL; - - if (used_lanes & (1 << lanes->data[i].pos)) - return -EINVAL; - - used_lanes |= 1 << lanes->data[i].pos; - } - - if (lanes->clk.pol > 1 || lanes->clk.pos > 3) - return -EINVAL; - - if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos)) - return -EINVAL; - - mutex_lock(&phy->mutex); - phy->dphy = *dphy; - phy->lanes = *lanes; - mutex_unlock(&phy->mutex); - - return 0; -} - -int omap3isp_csiphy_acquire(struct isp_csiphy *phy) -{ - int rval; - - if (phy->vdd == NULL) { - dev_err(phy->isp->dev, "Power regulator for CSI PHY not " - "available\n"); - return -ENODEV; - } - - mutex_lock(&phy->mutex); - - rval = regulator_enable(phy->vdd); - if (rval < 0) - goto done; - - omap3isp_csi2_reset(phy->csi2); - - csiphy_dphy_config(phy); - csiphy_lanes_config(phy); - - rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON); - if (rval) { - regulator_disable(phy->vdd); - goto done; - } - - csiphy_power_autoswitch_enable(phy, true); - phy->phy_in_use = 1; - -done: - mutex_unlock(&phy->mutex); - return rval; -} - -void omap3isp_csiphy_release(struct isp_csiphy *phy) -{ - mutex_lock(&phy->mutex); - if (phy->phy_in_use) { - csiphy_power_autoswitch_enable(phy, false); - csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); - regulator_disable(phy->vdd); - phy->phy_in_use = 0; - } - mutex_unlock(&phy->mutex); -} - -/* - * omap3isp_csiphy_init - Initialize the CSI PHY frontends - */ -int omap3isp_csiphy_init(struct isp_device *isp) -{ - struct isp_csiphy *phy1 = &isp->isp_csiphy1; - struct isp_csiphy *phy2 = &isp->isp_csiphy2; - - isp->platform_cb.csiphy_config = csiphy_config; - - phy2->isp = isp; - phy2->csi2 = &isp->isp_csi2a; - phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES; - phy2->cfg_regs = OMAP3_ISP_IOMEM_CSI2A_REGS1; - phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2; - mutex_init(&phy2->mutex); - - if (isp->revision == ISP_REVISION_15_0) { - phy1->isp = isp; - phy1->csi2 = &isp->isp_csi2c; - phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES; - phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1; - phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1; - mutex_init(&phy1->mutex); - } - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsiphy.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsiphy.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsiphy.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispcsiphy.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -/* - * ispcsiphy.h - * - * TI OMAP3 ISP - CSI PHY module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_CSI_PHY_H -#define OMAP3_ISP_CSI_PHY_H - -struct isp_csi2_device; -struct regulator; - -struct csiphy_lane { - u8 pos; - u8 pol; -}; - -#define ISP_CSIPHY2_NUM_DATA_LANES 2 -#define ISP_CSIPHY1_NUM_DATA_LANES 1 - -struct isp_csiphy_lanes_cfg { - struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES]; - struct csiphy_lane clk; -}; - -struct isp_csiphy_dphy_cfg { - u8 ths_term; - u8 ths_settle; - u8 tclk_term; - unsigned tclk_miss:1; - u8 tclk_settle; -}; - -struct isp_csiphy { - struct isp_device *isp; - struct mutex mutex; /* serialize csiphy configuration */ - u8 phy_in_use; - struct isp_csi2_device *csi2; - struct regulator *vdd; - - /* mem resources - enums as defined in enum isp_mem_resources */ - unsigned int cfg_regs; - unsigned int phy_regs; - - u8 num_data_lanes; /* number of CSI2 Data Lanes supported */ - struct isp_csiphy_lanes_cfg lanes; - struct isp_csiphy_dphy_cfg dphy; -}; - -int omap3isp_csiphy_acquire(struct isp_csiphy *phy); -void omap3isp_csiphy_release(struct isp_csiphy *phy); -int omap3isp_csiphy_init(struct isp_device *isp); - -#endif /* OMAP3_ISP_CSI_PHY_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isp.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isp.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isp.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,431 +0,0 @@ -/* - * isp.h - * - * TI OMAP3 ISP - Core - * - * Copyright (C) 2009-2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_CORE_H -#define OMAP3_ISP_CORE_H - -#include -#include -#include -#include -#include -#include -#include - -#include "ispstat.h" -#include "ispccdc.h" -#include "ispreg.h" -#include "ispresizer.h" -#include "isppreview.h" -#include "ispcsiphy.h" -#include "ispcsi2.h" -#include "ispccp2.h" - -#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8) - -#define ISP_TOK_TERM 0xFFFFFFFF /* - * terminating token for ISP - * modules reg list - */ -#define to_isp_device(ptr_module) \ - container_of(ptr_module, struct isp_device, isp_##ptr_module) -#define to_device(ptr_module) \ - (to_isp_device(ptr_module)->dev) - -enum isp_mem_resources { - OMAP3_ISP_IOMEM_MAIN, - OMAP3_ISP_IOMEM_CCP2, - OMAP3_ISP_IOMEM_CCDC, - OMAP3_ISP_IOMEM_HIST, - OMAP3_ISP_IOMEM_H3A, - OMAP3_ISP_IOMEM_PREV, - OMAP3_ISP_IOMEM_RESZ, - OMAP3_ISP_IOMEM_SBL, - OMAP3_ISP_IOMEM_CSI2A_REGS1, - OMAP3_ISP_IOMEM_CSIPHY2, - OMAP3_ISP_IOMEM_CSI2A_REGS2, - OMAP3_ISP_IOMEM_CSI2C_REGS1, - OMAP3_ISP_IOMEM_CSIPHY1, - OMAP3_ISP_IOMEM_CSI2C_REGS2, - OMAP3_ISP_IOMEM_LAST -}; - -enum isp_sbl_resource { - OMAP3_ISP_SBL_CSI1_READ = 0x1, - OMAP3_ISP_SBL_CSI1_WRITE = 0x2, - OMAP3_ISP_SBL_CSI2A_WRITE = 0x4, - OMAP3_ISP_SBL_CSI2C_WRITE = 0x8, - OMAP3_ISP_SBL_CCDC_LSC_READ = 0x10, - OMAP3_ISP_SBL_CCDC_WRITE = 0x20, - OMAP3_ISP_SBL_PREVIEW_READ = 0x40, - OMAP3_ISP_SBL_PREVIEW_WRITE = 0x80, - OMAP3_ISP_SBL_RESIZER_READ = 0x100, - OMAP3_ISP_SBL_RESIZER_WRITE = 0x200, -}; - -enum isp_subclk_resource { - OMAP3_ISP_SUBCLK_CCDC = (1 << 0), - OMAP3_ISP_SUBCLK_H3A = (1 << 1), - OMAP3_ISP_SUBCLK_HIST = (1 << 2), - OMAP3_ISP_SUBCLK_PREVIEW = (1 << 3), - OMAP3_ISP_SUBCLK_RESIZER = (1 << 4), -}; - -enum isp_interface_type { - ISP_INTERFACE_PARALLEL, - ISP_INTERFACE_CSI2A_PHY2, - ISP_INTERFACE_CCP2B_PHY1, - ISP_INTERFACE_CCP2B_PHY2, - ISP_INTERFACE_CSI2C_PHY1, -}; - -/* ISP: OMAP 34xx ES 1.0 */ -#define ISP_REVISION_1_0 0x10 -/* ISP2: OMAP 34xx ES 2.0, 2.1 and 3.0 */ -#define ISP_REVISION_2_0 0x20 -/* ISP2P: OMAP 36xx */ -#define ISP_REVISION_15_0 0xF0 - -/* - * struct isp_res_mapping - Map ISP io resources to ISP revision. - * @isp_rev: ISP_REVISION_x_x - * @map: bitmap for enum isp_mem_resources - */ -struct isp_res_mapping { - u32 isp_rev; - u32 map; -}; - -/* - * struct isp_reg - Structure for ISP register values. - * @reg: 32-bit Register address. - * @val: 32-bit Register value. - */ -struct isp_reg { - enum isp_mem_resources mmio_range; - u32 reg; - u32 val; -}; - -/** - * struct isp_parallel_platform_data - Parallel interface platform data - * @width: Parallel bus width in bits (8, 10, 11 or 12) - * @data_lane_shift: Data lane shifter - * 0 - CAMEXT[13:0] -> CAM[13:0] - * 1 - CAMEXT[13:2] -> CAM[11:0] - * 2 - CAMEXT[13:4] -> CAM[9:0] - * 3 - CAMEXT[13:6] -> CAM[7:0] - * @clk_pol: Pixel clock polarity - * 0 - Non Inverted, 1 - Inverted - * @bridge: CCDC Bridge input control - * ISPCTRL_PAR_BRIDGE_DISABLE - Disable - * ISPCTRL_PAR_BRIDGE_LENDIAN - Little endian - * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian - */ -struct isp_parallel_platform_data { - unsigned int width; - unsigned int data_lane_shift:2; - unsigned int clk_pol:1; - unsigned int bridge:4; -}; - -/** - * struct isp_ccp2_platform_data - CCP2 interface platform data - * @strobe_clk_pol: Strobe/clock polarity - * 0 - Non Inverted, 1 - Inverted - * @crc: Enable the cyclic redundancy check - * @ccp2_mode: Enable CCP2 compatibility mode - * 0 - MIPI-CSI1 mode, 1 - CCP2 mode - * @phy_layer: Physical layer selection - * ISPCCP2_CTRL_PHY_SEL_CLOCK - Data/clock physical layer - * ISPCCP2_CTRL_PHY_SEL_STROBE - Data/strobe physical layer - * @vpclk_div: Video port output clock control - */ -struct isp_ccp2_platform_data { - unsigned int strobe_clk_pol:1; - unsigned int crc:1; - unsigned int ccp2_mode:1; - unsigned int phy_layer:1; - unsigned int vpclk_div:2; -}; - -/** - * struct isp_csi2_platform_data - CSI2 interface platform data - * @crc: Enable the cyclic redundancy check - * @vpclk_div: Video port output clock control - */ -struct isp_csi2_platform_data { - unsigned crc:1; - unsigned vpclk_div:2; -}; - -struct isp_subdev_i2c_board_info { - struct i2c_board_info *board_info; - int i2c_adapter_id; -}; - -struct isp_v4l2_subdevs_group { - struct isp_subdev_i2c_board_info *subdevs; - enum isp_interface_type interface; - union { - struct isp_parallel_platform_data parallel; - struct isp_ccp2_platform_data ccp2; - struct isp_csi2_platform_data csi2; - } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */ -}; - -struct isp_platform_data { - struct isp_v4l2_subdevs_group *subdevs; - void (*set_constraints)(struct isp_device *isp, bool enable); -}; - -struct isp_platform_callback { - u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel); - int (*csiphy_config)(struct isp_csiphy *phy, - struct isp_csiphy_dphy_cfg *dphy, - struct isp_csiphy_lanes_cfg *lanes); - void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk); -}; - -/* - * struct isp_device - ISP device structure. - * @dev: Device pointer specific to the OMAP3 ISP. - * @revision: Stores current ISP module revision. - * @irq_num: Currently used IRQ number. - * @mmio_base: Array with kernel base addresses for ioremapped ISP register - * regions. - * @mmio_base_phys: Array with physical L4 bus addresses for ISP register - * regions. - * @mmio_size: Array with ISP register regions size in bytes. - * @raw_dmamask: Raw DMA mask - * @stat_lock: Spinlock for handling statistics - * @isp_mutex: Mutex for serializing requests to ISP. - * @has_context: Context has been saved at least once and can be restored. - * @ref_count: Reference count for handling multiple ISP requests. - * @cam_ick: Pointer to camera interface clock structure. - * @cam_mclk: Pointer to camera functional clock structure. - * @dpll4_m5_ck: Pointer to DPLL4 M5 clock structure. - * @csi2_fck: Pointer to camera CSI2 complexIO clock structure. - * @l3_ick: Pointer to OMAP3 L3 bus interface clock. - * @irq: Currently attached ISP ISR callbacks information structure. - * @isp_af: Pointer to current settings for ISP AutoFocus SCM. - * @isp_hist: Pointer to current settings for ISP Histogram SCM. - * @isp_h3a: Pointer to current settings for ISP Auto Exposure and - * White Balance SCM. - * @isp_res: Pointer to current settings for ISP Resizer. - * @isp_prev: Pointer to current settings for ISP Preview. - * @isp_ccdc: Pointer to current settings for ISP CCDC. - * @iommu: Pointer to requested IOMMU instance for ISP. - * @platform_cb: ISP driver callback function pointers for platform code - * - * This structure is used to store the OMAP ISP Information. - */ -struct isp_device { - struct v4l2_device v4l2_dev; - struct media_device media_dev; - struct device *dev; - u32 revision; - - /* platform HW resources */ - struct isp_platform_data *pdata; - unsigned int irq_num; - - void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; - unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST]; - resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST]; - - u64 raw_dmamask; - - /* ISP Obj */ - spinlock_t stat_lock; /* common lock for statistic drivers */ - struct mutex isp_mutex; /* For handling ref_count field */ - int has_context; - int ref_count; - unsigned int autoidle; - u32 xclk_divisor[2]; /* Two clocks, a and b. */ -#define ISP_CLK_CAM_ICK 0 -#define ISP_CLK_CAM_MCLK 1 -#define ISP_CLK_DPLL4_M5_CK 2 -#define ISP_CLK_CSI2_FCK 3 -#define ISP_CLK_L3_ICK 4 - struct clk *clock[5]; - - /* ISP modules */ - struct ispstat isp_af; - struct ispstat isp_aewb; - struct ispstat isp_hist; - struct isp_res_device isp_res; - struct isp_prev_device isp_prev; - struct isp_ccdc_device isp_ccdc; - struct isp_csi2_device isp_csi2a; - struct isp_csi2_device isp_csi2c; - struct isp_ccp2_device isp_ccp2; - struct isp_csiphy isp_csiphy1; - struct isp_csiphy isp_csiphy2; - - unsigned int sbl_resources; - unsigned int subclk_resources; - - struct iommu *iommu; - - struct isp_platform_callback platform_cb; -}; - -#define v4l2_dev_to_isp_device(dev) \ - container_of(dev, struct isp_device, v4l2_dev) - -void omap3isp_hist_dma_done(struct isp_device *isp); - -void omap3isp_flush(struct isp_device *isp); - -int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, - atomic_t *stopping); - -int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait, - atomic_t *stopping); - -int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, - enum isp_pipeline_stream_state state); -void omap3isp_configure_bridge(struct isp_device *isp, - enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata); - -#define ISP_XCLK_NONE -1 -#define ISP_XCLK_A 0 -#define ISP_XCLK_B 1 - -struct isp_device *omap3isp_get(struct isp_device *isp); -void omap3isp_put(struct isp_device *isp); - -void omap3isp_print_status(struct isp_device *isp); - -void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res); -void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res); - -void omap3isp_subclk_enable(struct isp_device *isp, - enum isp_subclk_resource res); -void omap3isp_subclk_disable(struct isp_device *isp, - enum isp_subclk_resource res); - -int omap3isp_pipeline_pm_use(struct media_entity *entity, int use); - -int omap3isp_register_entities(struct platform_device *pdev, - struct v4l2_device *v4l2_dev); -void omap3isp_unregister_entities(struct platform_device *pdev); - -/* - * isp_reg_readl - Read value of an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. - * @isp_mmio_range: Range to which the register offset refers to. - * @reg_offset: Register offset to read from. - * - * Returns an unsigned 32 bit value with the required register contents. - */ -static inline -u32 isp_reg_readl(struct isp_device *isp, enum isp_mem_resources isp_mmio_range, - u32 reg_offset) -{ - return __raw_readl(isp->mmio_base[isp_mmio_range] + reg_offset); -} - -/* - * isp_reg_writel - Write value to an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. - * @reg_value: 32 bit value to write to the register. - * @isp_mmio_range: Range to which the register offset refers to. - * @reg_offset: Register offset to write into. - */ -static inline -void isp_reg_writel(struct isp_device *isp, u32 reg_value, - enum isp_mem_resources isp_mmio_range, u32 reg_offset) -{ - __raw_writel(reg_value, isp->mmio_base[isp_mmio_range] + reg_offset); -} - -/* - * isp_reg_and - Clear individual bits in an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. - * @mmio_range: Range to which the register offset refers to. - * @reg: Register offset to work on. - * @clr_bits: 32 bit value which would be cleared in the register. - */ -static inline -void isp_reg_clr(struct isp_device *isp, enum isp_mem_resources mmio_range, - u32 reg, u32 clr_bits) -{ - u32 v = isp_reg_readl(isp, mmio_range, reg); - - isp_reg_writel(isp, v & ~clr_bits, mmio_range, reg); -} - -/* - * isp_reg_set - Set individual bits in an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. - * @mmio_range: Range to which the register offset refers to. - * @reg: Register offset to work on. - * @set_bits: 32 bit value which would be set in the register. - */ -static inline -void isp_reg_set(struct isp_device *isp, enum isp_mem_resources mmio_range, - u32 reg, u32 set_bits) -{ - u32 v = isp_reg_readl(isp, mmio_range, reg); - - isp_reg_writel(isp, v | set_bits, mmio_range, reg); -} - -/* - * isp_reg_clr_set - Clear and set invidial bits in an OMAP3 ISP register - * @dev: Device pointer specific to the OMAP3 ISP. - * @mmio_range: Range to which the register offset refers to. - * @reg: Register offset to work on. - * @clr_bits: 32 bit value which would be cleared in the register. - * @set_bits: 32 bit value which would be set in the register. - * - * The clear operation is done first, and then the set operation. - */ -static inline -void isp_reg_clr_set(struct isp_device *isp, enum isp_mem_resources mmio_range, - u32 reg, u32 clr_bits, u32 set_bits) -{ - u32 v = isp_reg_readl(isp, mmio_range, reg); - - isp_reg_writel(isp, (v & ~clr_bits) | set_bits, mmio_range, reg); -} - -static inline enum v4l2_buf_type -isp_pad_buffer_type(const struct v4l2_subdev *subdev, int pad) -{ - if (pad >= subdev->entity.num_pads) - return 0; - - if (subdev->entity.pads[pad].flags & MEDIA_PAD_FL_SINK) - return V4L2_BUF_TYPE_VIDEO_OUTPUT; - else - return V4L2_BUF_TYPE_VIDEO_CAPTURE; -} - -#endif /* OMAP3_ISP_CORE_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a_aewb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a_aewb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a_aewb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a_aewb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,374 +0,0 @@ -/* - * isph3a.c - * - * TI OMAP3 ISP - H3A module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: David Cohen - * Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include - -#include "isp.h" -#include "isph3a.h" -#include "ispstat.h" - -/* - * h3a_aewb_update_regs - Helper function to update h3a registers. - */ -static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv) -{ - struct omap3isp_h3a_aewb_config *conf = priv; - u32 pcr; - u32 win1; - u32 start; - u32 blk; - u32 subwin; - - if (aewb->state == ISPSTAT_DISABLED) - return; - - isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr, - OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST); - - if (!aewb->update) - return; - - /* Converting config metadata into reg values */ - pcr = conf->saturation_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT; - pcr |= !!conf->alaw_enable << ISPH3A_PCR_AEW_ALAW_EN_SHIFT; - - win1 = ((conf->win_height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT; - win1 |= ((conf->win_width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT; - win1 |= (conf->ver_win_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT; - win1 |= (conf->hor_win_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT; - - start = conf->hor_win_start << ISPH3A_AEWINSTART_WINSH_SHIFT; - start |= conf->ver_win_start << ISPH3A_AEWINSTART_WINSV_SHIFT; - - blk = conf->blk_ver_win_start << ISPH3A_AEWINBLK_WINSV_SHIFT; - blk |= ((conf->blk_win_height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT; - - subwin = ((conf->subsample_ver_inc >> 1) - 1) << - ISPH3A_AEWSUBWIN_AEWINCV_SHIFT; - subwin |= ((conf->subsample_hor_inc >> 1) - 1) << - ISPH3A_AEWSUBWIN_AEWINCH_SHIFT; - - isp_reg_writel(aewb->isp, win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1); - isp_reg_writel(aewb->isp, start, OMAP3_ISP_IOMEM_H3A, - ISPH3A_AEWINSTART); - isp_reg_writel(aewb->isp, blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK); - isp_reg_writel(aewb->isp, subwin, OMAP3_ISP_IOMEM_H3A, - ISPH3A_AEWSUBWIN); - isp_reg_clr_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, - ISPH3A_PCR_AEW_MASK, pcr); - - aewb->update = 0; - aewb->config_counter += aewb->inc_config; - aewb->inc_config = 0; - aewb->buf_size = conf->buf_size; -} - -static void h3a_aewb_enable(struct ispstat *aewb, int enable) -{ - if (enable) { - isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, - ISPH3A_PCR_AEW_EN); - /* This bit is already set if AF is enabled */ - if (aewb->isp->isp_af.state != ISPSTAT_ENABLED) - isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, - ISPCTRL_H3A_CLK_EN); - } else { - isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, - ISPH3A_PCR_AEW_EN); - /* This bit can't be cleared if AF is enabled */ - if (aewb->isp->isp_af.state != ISPSTAT_ENABLED) - isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, - ISPCTRL_H3A_CLK_EN); - } -} - -static int h3a_aewb_busy(struct ispstat *aewb) -{ - return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR) - & ISPH3A_PCR_BUSYAEAWB; -} - -static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf) -{ - /* Number of configured windows + extra row for black data */ - u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count; - - /* - * Unsaturated block counts for each 8 windows. - * 1 extra for the last (win_count % 8) windows if win_count is not - * divisible by 8. - */ - win_count += (win_count + 7) / 8; - - return win_count * AEWB_PACKET_SIZE; -} - -static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf) -{ - struct omap3isp_h3a_aewb_config *user_cfg = new_conf; - u32 buf_size; - - if (unlikely(user_cfg->saturation_limit > - OMAP3ISP_AEWB_MAX_SATURATION_LIM)) - return -EINVAL; - - if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H || - user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H || - user_cfg->win_height & 0x01)) - return -EINVAL; - - if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W || - user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W || - user_cfg->win_width & 0x01)) - return -EINVAL; - - if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC || - user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC)) - return -EINVAL; - - if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC || - user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC)) - return -EINVAL; - - if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART)) - return -EINVAL; - - if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART)) - return -EINVAL; - - if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART)) - return -EINVAL; - - if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H || - user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H || - user_cfg->blk_win_height & 0x01)) - return -EINVAL; - - if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC || - user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC || - user_cfg->subsample_ver_inc & 0x01)) - return -EINVAL; - - if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC || - user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC || - user_cfg->subsample_hor_inc & 0x01)) - return -EINVAL; - - buf_size = h3a_aewb_get_buf_size(user_cfg); - if (buf_size > user_cfg->buf_size) - user_cfg->buf_size = buf_size; - else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE) - user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE; - - return 0; -} - -/* - * h3a_aewb_set_params - Helper function to check & store user given params. - * @new_conf: Pointer to AE and AWB parameters struct. - * - * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to - * program them during ISR. - */ -static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf) -{ - struct omap3isp_h3a_aewb_config *user_cfg = new_conf; - struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv; - int update = 0; - - if (cur_cfg->saturation_limit != user_cfg->saturation_limit) { - cur_cfg->saturation_limit = user_cfg->saturation_limit; - update = 1; - } - if (cur_cfg->alaw_enable != user_cfg->alaw_enable) { - cur_cfg->alaw_enable = user_cfg->alaw_enable; - update = 1; - } - if (cur_cfg->win_height != user_cfg->win_height) { - cur_cfg->win_height = user_cfg->win_height; - update = 1; - } - if (cur_cfg->win_width != user_cfg->win_width) { - cur_cfg->win_width = user_cfg->win_width; - update = 1; - } - if (cur_cfg->ver_win_count != user_cfg->ver_win_count) { - cur_cfg->ver_win_count = user_cfg->ver_win_count; - update = 1; - } - if (cur_cfg->hor_win_count != user_cfg->hor_win_count) { - cur_cfg->hor_win_count = user_cfg->hor_win_count; - update = 1; - } - if (cur_cfg->ver_win_start != user_cfg->ver_win_start) { - cur_cfg->ver_win_start = user_cfg->ver_win_start; - update = 1; - } - if (cur_cfg->hor_win_start != user_cfg->hor_win_start) { - cur_cfg->hor_win_start = user_cfg->hor_win_start; - update = 1; - } - if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) { - cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start; - update = 1; - } - if (cur_cfg->blk_win_height != user_cfg->blk_win_height) { - cur_cfg->blk_win_height = user_cfg->blk_win_height; - update = 1; - } - if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) { - cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc; - update = 1; - } - if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) { - cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc; - update = 1; - } - - if (update || !aewb->configured) { - aewb->inc_config++; - aewb->update = 1; - cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg); - } -} - -static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct ispstat *stat = v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_OMAP3ISP_AEWB_CFG: - return omap3isp_stat_config(stat, arg); - case VIDIOC_OMAP3ISP_STAT_REQ: - return omap3isp_stat_request_statistics(stat, arg); - case VIDIOC_OMAP3ISP_STAT_EN: { - unsigned long *en = arg; - return omap3isp_stat_enable(stat, !!*en); - } - } - - return -ENOIOCTLCMD; -} - -static const struct ispstat_ops h3a_aewb_ops = { - .validate_params = h3a_aewb_validate_params, - .set_params = h3a_aewb_set_params, - .setup_regs = h3a_aewb_setup_regs, - .enable = h3a_aewb_enable, - .busy = h3a_aewb_busy, -}; - -static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = { - .ioctl = h3a_aewb_ioctl, - .subscribe_event = omap3isp_stat_subscribe_event, - .unsubscribe_event = omap3isp_stat_unsubscribe_event, -}; - -static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = { - .s_stream = omap3isp_stat_s_stream, -}; - -static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = { - .core = &h3a_aewb_subdev_core_ops, - .video = &h3a_aewb_subdev_video_ops, -}; - -/* - * omap3isp_h3a_aewb_init - Module Initialisation. - */ -int omap3isp_h3a_aewb_init(struct isp_device *isp) -{ - struct ispstat *aewb = &isp->isp_aewb; - struct omap3isp_h3a_aewb_config *aewb_cfg; - struct omap3isp_h3a_aewb_config *aewb_recover_cfg; - int ret; - - aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL); - if (!aewb_cfg) - return -ENOMEM; - - memset(aewb, 0, sizeof(*aewb)); - aewb->ops = &h3a_aewb_ops; - aewb->priv = aewb_cfg; - aewb->dma_ch = -1; - aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB; - aewb->isp = isp; - - /* Set recover state configuration */ - aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL); - if (!aewb_recover_cfg) { - dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for " - "recover configuration.\n"); - ret = -ENOMEM; - goto err_recover_alloc; - } - - aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM; - aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H; - aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W; - aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC; - aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC; - aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start + - aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count; - aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H; - aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC; - aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC; - - if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) { - dev_err(aewb->isp->dev, "AEWB: recover configuration is " - "invalid.\n"); - ret = -EINVAL; - goto err_conf; - } - - aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg); - aewb->recover_priv = aewb_recover_cfg; - - ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops); - if (ret) - goto err_conf; - - return 0; - -err_conf: - kfree(aewb_recover_cfg); -err_recover_alloc: - kfree(aewb_cfg); - - return ret; -} - -/* - * omap3isp_h3a_aewb_cleanup - Module exit. - */ -void omap3isp_h3a_aewb_cleanup(struct isp_device *isp) -{ - kfree(isp->isp_aewb.priv); - kfree(isp->isp_aewb.recover_priv); - omap3isp_stat_free(&isp->isp_aewb); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a_af.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a_af.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a_af.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a_af.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,429 +0,0 @@ -/* - * isph3a_af.c - * - * TI OMAP3 ISP - H3A AF module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: David Cohen - * Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -/* Linux specific include files */ -#include -#include - -#include "isp.h" -#include "isph3a.h" -#include "ispstat.h" - -#define IS_OUT_OF_BOUNDS(value, min, max) \ - (((value) < (min)) || ((value) > (max))) - -static void h3a_af_setup_regs(struct ispstat *af, void *priv) -{ - struct omap3isp_h3a_af_config *conf = priv; - u32 pcr; - u32 pax1; - u32 pax2; - u32 paxstart; - u32 coef; - u32 base_coef_set0; - u32 base_coef_set1; - int index; - - if (af->state == ISPSTAT_DISABLED) - return; - - isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A, - ISPH3A_AFBUFST); - - if (!af->update) - return; - - /* Configure Hardware Registers */ - pax1 = ((conf->paxel.width >> 1) - 1) << AF_PAXW_SHIFT; - /* Set height in AFPAX1 */ - pax1 |= (conf->paxel.height >> 1) - 1; - isp_reg_writel(af->isp, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1); - - /* Configure AFPAX2 Register */ - /* Set Line Increment in AFPAX2 Register */ - pax2 = ((conf->paxel.line_inc >> 1) - 1) << AF_LINE_INCR_SHIFT; - /* Set Vertical Count */ - pax2 |= (conf->paxel.v_cnt - 1) << AF_VT_COUNT_SHIFT; - /* Set Horizontal Count */ - pax2 |= (conf->paxel.h_cnt - 1); - isp_reg_writel(af->isp, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2); - - /* Configure PAXSTART Register */ - /*Configure Horizontal Start */ - paxstart = conf->paxel.h_start << AF_HZ_START_SHIFT; - /* Configure Vertical Start */ - paxstart |= conf->paxel.v_start; - isp_reg_writel(af->isp, paxstart, OMAP3_ISP_IOMEM_H3A, - ISPH3A_AFPAXSTART); - - /*SetIIRSH Register */ - isp_reg_writel(af->isp, conf->iir.h_start, - OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH); - - base_coef_set0 = ISPH3A_AFCOEF010; - base_coef_set1 = ISPH3A_AFCOEF110; - for (index = 0; index <= 8; index += 2) { - /*Set IIR Filter0 Coefficients */ - coef = 0; - coef |= conf->iir.coeff_set0[index]; - coef |= conf->iir.coeff_set0[index + 1] << - AF_COEF_SHIFT; - isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A, - base_coef_set0); - base_coef_set0 += AFCOEF_OFFSET; - - /*Set IIR Filter1 Coefficients */ - coef = 0; - coef |= conf->iir.coeff_set1[index]; - coef |= conf->iir.coeff_set1[index + 1] << - AF_COEF_SHIFT; - isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A, - base_coef_set1); - base_coef_set1 += AFCOEF_OFFSET; - } - /* set AFCOEF0010 Register */ - isp_reg_writel(af->isp, conf->iir.coeff_set0[10], - OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010); - /* set AFCOEF1010 Register */ - isp_reg_writel(af->isp, conf->iir.coeff_set1[10], - OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010); - - /* PCR Register */ - /* Set RGB Position */ - pcr = conf->rgb_pos << AF_RGBPOS_SHIFT; - /* Set Accumulator Mode */ - if (conf->fvmode == OMAP3ISP_AF_MODE_PEAK) - pcr |= AF_FVMODE; - /* Set A-law */ - if (conf->alaw_enable) - pcr |= AF_ALAW_EN; - /* HMF Configurations */ - if (conf->hmf.enable) { - /* Enable HMF */ - pcr |= AF_MED_EN; - /* Set Median Threshold */ - pcr |= conf->hmf.threshold << AF_MED_TH_SHIFT; - } - /* Set PCR Register */ - isp_reg_clr_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, - AF_PCR_MASK, pcr); - - af->update = 0; - af->config_counter += af->inc_config; - af->inc_config = 0; - af->buf_size = conf->buf_size; -} - -static void h3a_af_enable(struct ispstat *af, int enable) -{ - if (enable) { - isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, - ISPH3A_PCR_AF_EN); - /* This bit is already set if AEWB is enabled */ - if (af->isp->isp_aewb.state != ISPSTAT_ENABLED) - isp_reg_set(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, - ISPCTRL_H3A_CLK_EN); - } else { - isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, - ISPH3A_PCR_AF_EN); - /* This bit can't be cleared if AEWB is enabled */ - if (af->isp->isp_aewb.state != ISPSTAT_ENABLED) - isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, - ISPCTRL_H3A_CLK_EN); - } -} - -static int h3a_af_busy(struct ispstat *af) -{ - return isp_reg_readl(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR) - & ISPH3A_PCR_BUSYAF; -} - -static u32 h3a_af_get_buf_size(struct omap3isp_h3a_af_config *conf) -{ - return conf->paxel.h_cnt * conf->paxel.v_cnt * OMAP3ISP_AF_PAXEL_SIZE; -} - -/* Function to check paxel parameters */ -static int h3a_af_validate_params(struct ispstat *af, void *new_conf) -{ - struct omap3isp_h3a_af_config *user_cfg = new_conf; - struct omap3isp_h3a_af_paxel *paxel_cfg = &user_cfg->paxel; - struct omap3isp_h3a_af_iir *iir_cfg = &user_cfg->iir; - int index; - u32 buf_size; - - /* Check horizontal Count */ - if (IS_OUT_OF_BOUNDS(paxel_cfg->h_cnt, - OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN, - OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX)) - return -EINVAL; - - /* Check Vertical Count */ - if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt, - OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN, - OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX)) - return -EINVAL; - - if (IS_OUT_OF_BOUNDS(paxel_cfg->height, OMAP3ISP_AF_PAXEL_HEIGHT_MIN, - OMAP3ISP_AF_PAXEL_HEIGHT_MAX) || - paxel_cfg->height % 2) - return -EINVAL; - - /* Check width */ - if (IS_OUT_OF_BOUNDS(paxel_cfg->width, OMAP3ISP_AF_PAXEL_WIDTH_MIN, - OMAP3ISP_AF_PAXEL_WIDTH_MAX) || - paxel_cfg->width % 2) - return -EINVAL; - - /* Check Line Increment */ - if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc, - OMAP3ISP_AF_PAXEL_INCREMENT_MIN, - OMAP3ISP_AF_PAXEL_INCREMENT_MAX) || - paxel_cfg->line_inc % 2) - return -EINVAL; - - /* Check Horizontal Start */ - if ((paxel_cfg->h_start < iir_cfg->h_start) || - IS_OUT_OF_BOUNDS(paxel_cfg->h_start, - OMAP3ISP_AF_PAXEL_HZSTART_MIN, - OMAP3ISP_AF_PAXEL_HZSTART_MAX)) - return -EINVAL; - - /* Check IIR */ - for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) { - if ((iir_cfg->coeff_set0[index]) > OMAP3ISP_AF_COEF_MAX) - return -EINVAL; - - if ((iir_cfg->coeff_set1[index]) > OMAP3ISP_AF_COEF_MAX) - return -EINVAL; - } - - if (IS_OUT_OF_BOUNDS(iir_cfg->h_start, OMAP3ISP_AF_IIRSH_MIN, - OMAP3ISP_AF_IIRSH_MAX)) - return -EINVAL; - - /* Hack: If paxel size is 12, the 10th AF window may be corrupted */ - if ((paxel_cfg->h_cnt * paxel_cfg->v_cnt > 9) && - (paxel_cfg->width * paxel_cfg->height == 12)) - return -EINVAL; - - buf_size = h3a_af_get_buf_size(user_cfg); - if (buf_size > user_cfg->buf_size) - /* User buf_size request wasn't enough */ - user_cfg->buf_size = buf_size; - else if (user_cfg->buf_size > OMAP3ISP_AF_MAX_BUF_SIZE) - user_cfg->buf_size = OMAP3ISP_AF_MAX_BUF_SIZE; - - return 0; -} - -/* Update local parameters */ -static void h3a_af_set_params(struct ispstat *af, void *new_conf) -{ - struct omap3isp_h3a_af_config *user_cfg = new_conf; - struct omap3isp_h3a_af_config *cur_cfg = af->priv; - int update = 0; - int index; - - /* alaw */ - if (cur_cfg->alaw_enable != user_cfg->alaw_enable) { - update = 1; - goto out; - } - - /* hmf */ - if (cur_cfg->hmf.enable != user_cfg->hmf.enable) { - update = 1; - goto out; - } - if (cur_cfg->hmf.threshold != user_cfg->hmf.threshold) { - update = 1; - goto out; - } - - /* rgbpos */ - if (cur_cfg->rgb_pos != user_cfg->rgb_pos) { - update = 1; - goto out; - } - - /* iir */ - if (cur_cfg->iir.h_start != user_cfg->iir.h_start) { - update = 1; - goto out; - } - for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) { - if (cur_cfg->iir.coeff_set0[index] != - user_cfg->iir.coeff_set0[index]) { - update = 1; - goto out; - } - if (cur_cfg->iir.coeff_set1[index] != - user_cfg->iir.coeff_set1[index]) { - update = 1; - goto out; - } - } - - /* paxel */ - if ((cur_cfg->paxel.width != user_cfg->paxel.width) || - (cur_cfg->paxel.height != user_cfg->paxel.height) || - (cur_cfg->paxel.h_start != user_cfg->paxel.h_start) || - (cur_cfg->paxel.v_start != user_cfg->paxel.v_start) || - (cur_cfg->paxel.h_cnt != user_cfg->paxel.h_cnt) || - (cur_cfg->paxel.v_cnt != user_cfg->paxel.v_cnt) || - (cur_cfg->paxel.line_inc != user_cfg->paxel.line_inc)) { - update = 1; - goto out; - } - - /* af_mode */ - if (cur_cfg->fvmode != user_cfg->fvmode) - update = 1; - -out: - if (update || !af->configured) { - memcpy(cur_cfg, user_cfg, sizeof(*cur_cfg)); - af->inc_config++; - af->update = 1; - /* - * User might be asked for a bigger buffer than necessary for - * this configuration. In order to return the right amount of - * data during buffer request, let's calculate the size here - * instead of stick with user_cfg->buf_size. - */ - cur_cfg->buf_size = h3a_af_get_buf_size(cur_cfg); - } -} - -static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct ispstat *stat = v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_OMAP3ISP_AF_CFG: - return omap3isp_stat_config(stat, arg); - case VIDIOC_OMAP3ISP_STAT_REQ: - return omap3isp_stat_request_statistics(stat, arg); - case VIDIOC_OMAP3ISP_STAT_EN: { - int *en = arg; - return omap3isp_stat_enable(stat, !!*en); - } - } - - return -ENOIOCTLCMD; - -} - -static const struct ispstat_ops h3a_af_ops = { - .validate_params = h3a_af_validate_params, - .set_params = h3a_af_set_params, - .setup_regs = h3a_af_setup_regs, - .enable = h3a_af_enable, - .busy = h3a_af_busy, -}; - -static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = { - .ioctl = h3a_af_ioctl, - .subscribe_event = omap3isp_stat_subscribe_event, - .unsubscribe_event = omap3isp_stat_unsubscribe_event, -}; - -static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = { - .s_stream = omap3isp_stat_s_stream, -}; - -static const struct v4l2_subdev_ops h3a_af_subdev_ops = { - .core = &h3a_af_subdev_core_ops, - .video = &h3a_af_subdev_video_ops, -}; - -/* Function to register the AF character device driver. */ -int omap3isp_h3a_af_init(struct isp_device *isp) -{ - struct ispstat *af = &isp->isp_af; - struct omap3isp_h3a_af_config *af_cfg; - struct omap3isp_h3a_af_config *af_recover_cfg; - int ret; - - af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL); - if (af_cfg == NULL) - return -ENOMEM; - - memset(af, 0, sizeof(*af)); - af->ops = &h3a_af_ops; - af->priv = af_cfg; - af->dma_ch = -1; - af->event_type = V4L2_EVENT_OMAP3ISP_AF; - af->isp = isp; - - /* Set recover state configuration */ - af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL); - if (!af_recover_cfg) { - dev_err(af->isp->dev, "AF: cannot allocate memory for recover " - "configuration.\n"); - ret = -ENOMEM; - goto err_recover_alloc; - } - - af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN; - af_recover_cfg->paxel.width = OMAP3ISP_AF_PAXEL_WIDTH_MIN; - af_recover_cfg->paxel.height = OMAP3ISP_AF_PAXEL_HEIGHT_MIN; - af_recover_cfg->paxel.h_cnt = OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN; - af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN; - af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN; - if (h3a_af_validate_params(af, af_recover_cfg)) { - dev_err(af->isp->dev, "AF: recover configuration is " - "invalid.\n"); - ret = -EINVAL; - goto err_conf; - } - - af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg); - af->recover_priv = af_recover_cfg; - - ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops); - if (ret) - goto err_conf; - - return 0; - -err_conf: - kfree(af_recover_cfg); -err_recover_alloc: - kfree(af_cfg); - - return ret; -} - -void omap3isp_h3a_af_cleanup(struct isp_device *isp) -{ - kfree(isp->isp_af.priv); - kfree(isp->isp_af.recover_priv); - omap3isp_stat_free(&isp->isp_af); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isph3a.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -/* - * isph3a.h - * - * TI OMAP3 ISP - H3A AF module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: David Cohen - * Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_H3A_H -#define OMAP3_ISP_H3A_H - -#include - -/* - * ---------- - * -H3A AEWB- - * ---------- - */ - -#define AEWB_PACKET_SIZE 16 -#define AEWB_SATURATION_LIMIT 0x3ff - -/* Flags for changed registers */ -#define PCR_CHNG (1 << 0) -#define AEWWIN1_CHNG (1 << 1) -#define AEWINSTART_CHNG (1 << 2) -#define AEWINBLK_CHNG (1 << 3) -#define AEWSUBWIN_CHNG (1 << 4) -#define PRV_WBDGAIN_CHNG (1 << 5) -#define PRV_WBGAIN_CHNG (1 << 6) - -/* ISPH3A REGISTERS bits */ -#define ISPH3A_PCR_AF_EN (1 << 0) -#define ISPH3A_PCR_AF_ALAW_EN (1 << 1) -#define ISPH3A_PCR_AF_MED_EN (1 << 2) -#define ISPH3A_PCR_AF_BUSY (1 << 15) -#define ISPH3A_PCR_AEW_EN (1 << 16) -#define ISPH3A_PCR_AEW_ALAW_EN (1 << 17) -#define ISPH3A_PCR_AEW_BUSY (1 << 18) -#define ISPH3A_PCR_AEW_MASK (ISPH3A_PCR_AEW_ALAW_EN | \ - ISPH3A_PCR_AEW_AVE2LMT_MASK) - -/* - * -------- - * -H3A AF- - * -------- - */ - -/* Peripheral Revision */ -#define AFPID 0x0 - -#define AFCOEF_OFFSET 0x00000004 /* COEF base address */ - -/* PCR fields */ -#define AF_BUSYAF (1 << 15) -#define AF_FVMODE (1 << 14) -#define AF_RGBPOS (0x7 << 11) -#define AF_MED_TH (0xFF << 3) -#define AF_MED_EN (1 << 2) -#define AF_ALAW_EN (1 << 1) -#define AF_EN (1 << 0) -#define AF_PCR_MASK (AF_FVMODE | AF_RGBPOS | AF_MED_TH | \ - AF_MED_EN | AF_ALAW_EN) - -/* AFPAX1 fields */ -#define AF_PAXW (0x7F << 16) -#define AF_PAXH 0x7F - -/* AFPAX2 fields */ -#define AF_AFINCV (0xF << 13) -#define AF_PAXVC (0x7F << 6) -#define AF_PAXHC 0x3F - -/* AFPAXSTART fields */ -#define AF_PAXSH (0xFFF<<16) -#define AF_PAXSV 0xFFF - -/* COEFFICIENT MASK */ -#define AF_COEF_MASK0 0xFFF -#define AF_COEF_MASK1 (0xFFF<<16) - -/* BIT SHIFTS */ -#define AF_RGBPOS_SHIFT 11 -#define AF_MED_TH_SHIFT 3 -#define AF_PAXW_SHIFT 16 -#define AF_LINE_INCR_SHIFT 13 -#define AF_VT_COUNT_SHIFT 6 -#define AF_HZ_START_SHIFT 16 -#define AF_COEF_SHIFT 16 - -/* Init and cleanup functions */ -int omap3isp_h3a_aewb_init(struct isp_device *isp); -int omap3isp_h3a_af_init(struct isp_device *isp); - -void omap3isp_h3a_aewb_cleanup(struct isp_device *isp); -void omap3isp_h3a_af_cleanup(struct isp_device *isp); - -#endif /* OMAP3_ISP_H3A_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isphist.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isphist.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isphist.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isphist.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,520 +0,0 @@ -/* - * isphist.c - * - * TI OMAP3 ISP - Histogram module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: David Cohen - * Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include - -#include "isp.h" -#include "ispreg.h" -#include "isphist.h" - -#define HIST_CONFIG_DMA 1 - -#define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0) - -/* - * hist_reset_mem - clear Histogram memory before start stats engine. - */ -static void hist_reset_mem(struct ispstat *hist) -{ - struct isp_device *isp = hist->isp; - struct omap3isp_hist_config *conf = hist->priv; - unsigned int i; - - isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); - - /* - * By setting it, the histogram internal buffer is being cleared at the - * same time it's being read. This bit must be cleared afterwards. - */ - isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); - - /* - * We'll clear 4 words at each iteration for optimization. It avoids - * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4. - */ - for (i = OMAP3ISP_HIST_MEM_SIZE / 4; i > 0; i--) { - isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); - isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); - isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); - isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); - } - isp_reg_clr(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); - - hist->wait_acc_frames = conf->num_acc_frames; -} - -static void hist_dma_config(struct ispstat *hist) -{ - hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32; - hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT; - hist->dma_config.frame_count = 1; - hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT; - hist->dma_config.src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA; - hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC; - hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC; -} - -/* - * hist_setup_regs - Helper function to update Histogram registers. - */ -static void hist_setup_regs(struct ispstat *hist, void *priv) -{ - struct isp_device *isp = hist->isp; - struct omap3isp_hist_config *conf = priv; - int c; - u32 cnt; - u32 wb_gain; - u32 reg_hor[OMAP3ISP_HIST_MAX_REGIONS]; - u32 reg_ver[OMAP3ISP_HIST_MAX_REGIONS]; - - if (!hist->update || hist->state == ISPSTAT_DISABLED || - hist->state == ISPSTAT_DISABLING) - return; - - cnt = conf->cfa << ISPHIST_CNT_CFA_SHIFT; - - wb_gain = conf->wg[0] << ISPHIST_WB_GAIN_WG00_SHIFT; - wb_gain |= conf->wg[1] << ISPHIST_WB_GAIN_WG01_SHIFT; - wb_gain |= conf->wg[2] << ISPHIST_WB_GAIN_WG02_SHIFT; - if (conf->cfa == OMAP3ISP_HIST_CFA_BAYER) - wb_gain |= conf->wg[3] << ISPHIST_WB_GAIN_WG03_SHIFT; - - /* Regions size and position */ - for (c = 0; c < OMAP3ISP_HIST_MAX_REGIONS; c++) { - if (c < conf->num_regions) { - reg_hor[c] = conf->region[c].h_start << - ISPHIST_REG_START_SHIFT; - reg_hor[c] = conf->region[c].h_end << - ISPHIST_REG_END_SHIFT; - reg_ver[c] = conf->region[c].v_start << - ISPHIST_REG_START_SHIFT; - reg_ver[c] = conf->region[c].v_end << - ISPHIST_REG_END_SHIFT; - } else { - reg_hor[c] = 0; - reg_ver[c] = 0; - } - } - - cnt |= conf->hist_bins << ISPHIST_CNT_BINS_SHIFT; - switch (conf->hist_bins) { - case OMAP3ISP_HIST_BINS_256: - cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 8) << - ISPHIST_CNT_SHIFT_SHIFT; - break; - case OMAP3ISP_HIST_BINS_128: - cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 7) << - ISPHIST_CNT_SHIFT_SHIFT; - break; - case OMAP3ISP_HIST_BINS_64: - cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 6) << - ISPHIST_CNT_SHIFT_SHIFT; - break; - default: /* OMAP3ISP_HIST_BINS_32 */ - cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 5) << - ISPHIST_CNT_SHIFT_SHIFT; - break; - } - - hist_reset_mem(hist); - - isp_reg_writel(isp, cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT); - isp_reg_writel(isp, wb_gain, OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN); - isp_reg_writel(isp, reg_hor[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ); - isp_reg_writel(isp, reg_ver[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT); - isp_reg_writel(isp, reg_hor[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ); - isp_reg_writel(isp, reg_ver[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT); - isp_reg_writel(isp, reg_hor[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ); - isp_reg_writel(isp, reg_ver[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT); - isp_reg_writel(isp, reg_hor[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ); - isp_reg_writel(isp, reg_ver[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT); - - hist->update = 0; - hist->config_counter += hist->inc_config; - hist->inc_config = 0; - hist->buf_size = conf->buf_size; -} - -static void hist_enable(struct ispstat *hist, int enable) -{ - if (enable) { - isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, - ISPHIST_PCR_ENABLE); - isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, - ISPCTRL_HIST_CLK_EN); - } else { - isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, - ISPHIST_PCR_ENABLE); - isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, - ISPCTRL_HIST_CLK_EN); - } -} - -static int hist_busy(struct ispstat *hist) -{ - return isp_reg_readl(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR) - & ISPHIST_PCR_BUSY; -} - -static void hist_dma_cb(int lch, u16 ch_status, void *data) -{ - struct ispstat *hist = data; - - if (ch_status & ~OMAP_DMA_BLOCK_IRQ) { - dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n", - ch_status); - omap_stop_dma(lch); - hist_reset_mem(hist); - atomic_set(&hist->buf_err, 1); - } - isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, - ISPHIST_CNT_CLEAR); - - omap3isp_stat_dma_isr(hist); - if (hist->state != ISPSTAT_DISABLED) - omap3isp_hist_dma_done(hist->isp); -} - -static int hist_buf_dma(struct ispstat *hist) -{ - dma_addr_t dma_addr = hist->active_buf->dma_addr; - - if (unlikely(!dma_addr)) { - dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n"); - hist_reset_mem(hist); - return STAT_NO_BUF; - } - - isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); - isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, - ISPHIST_CNT_CLEAR); - omap3isp_flush(hist->isp); - hist->dma_config.dst_start = dma_addr; - hist->dma_config.elem_count = hist->buf_size / sizeof(u32); - omap_set_dma_params(hist->dma_ch, &hist->dma_config); - - omap_start_dma(hist->dma_ch); - - return STAT_BUF_WAITING_DMA; -} - -static int hist_buf_pio(struct ispstat *hist) -{ - struct isp_device *isp = hist->isp; - u32 *buf = hist->active_buf->virt_addr; - unsigned int i; - - if (!buf) { - dev_dbg(isp->dev, "hist: invalid PIO buffer address\n"); - hist_reset_mem(hist); - return STAT_NO_BUF; - } - - isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); - - /* - * By setting it, the histogram internal buffer is being cleared at the - * same time it's being read. This bit must be cleared just after all - * data is acquired. - */ - isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); - - /* - * We'll read 4 times a 4-bytes-word at each iteration for - * optimization. It avoids 3/4 of the jumps. We also know buf_size is - * divisible by 16. - */ - for (i = hist->buf_size / 16; i > 0; i--) { - *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); - *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); - *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); - *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); - } - isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, - ISPHIST_CNT_CLEAR); - - return STAT_BUF_DONE; -} - -/* - * hist_buf_process - Callback from ISP driver for HIST interrupt. - */ -static int hist_buf_process(struct ispstat *hist) -{ - struct omap3isp_hist_config *user_cfg = hist->priv; - int ret; - - if (atomic_read(&hist->buf_err) || hist->state != ISPSTAT_ENABLED) { - hist_reset_mem(hist); - return STAT_NO_BUF; - } - - if (--(hist->wait_acc_frames)) - return STAT_NO_BUF; - - if (HIST_USING_DMA(hist)) - ret = hist_buf_dma(hist); - else - ret = hist_buf_pio(hist); - - hist->wait_acc_frames = user_cfg->num_acc_frames; - - return ret; -} - -static u32 hist_get_buf_size(struct omap3isp_hist_config *conf) -{ - return OMAP3ISP_HIST_MEM_SIZE_BINS(conf->hist_bins) * conf->num_regions; -} - -/* - * hist_validate_params - Helper function to check user given params. - * @user_cfg: Pointer to user configuration structure. - * - * Returns 0 on success configuration. - */ -static int hist_validate_params(struct ispstat *hist, void *new_conf) -{ - struct omap3isp_hist_config *user_cfg = new_conf; - int c; - u32 buf_size; - - if (user_cfg->cfa > OMAP3ISP_HIST_CFA_FOVEONX3) - return -EINVAL; - - /* Regions size and position */ - - if ((user_cfg->num_regions < OMAP3ISP_HIST_MIN_REGIONS) || - (user_cfg->num_regions > OMAP3ISP_HIST_MAX_REGIONS)) - return -EINVAL; - - /* Regions */ - for (c = 0; c < user_cfg->num_regions; c++) { - if (user_cfg->region[c].h_start & ~ISPHIST_REG_START_END_MASK) - return -EINVAL; - if (user_cfg->region[c].h_end & ~ISPHIST_REG_START_END_MASK) - return -EINVAL; - if (user_cfg->region[c].v_start & ~ISPHIST_REG_START_END_MASK) - return -EINVAL; - if (user_cfg->region[c].v_end & ~ISPHIST_REG_START_END_MASK) - return -EINVAL; - if (user_cfg->region[c].h_start > user_cfg->region[c].h_end) - return -EINVAL; - if (user_cfg->region[c].v_start > user_cfg->region[c].v_end) - return -EINVAL; - } - - switch (user_cfg->num_regions) { - case 1: - if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_256) - return -EINVAL; - break; - case 2: - if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_128) - return -EINVAL; - break; - default: /* 3 or 4 */ - if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_64) - return -EINVAL; - break; - } - - buf_size = hist_get_buf_size(user_cfg); - if (buf_size > user_cfg->buf_size) - /* User's buf_size request wasn't enoght */ - user_cfg->buf_size = buf_size; - else if (user_cfg->buf_size > OMAP3ISP_HIST_MAX_BUF_SIZE) - user_cfg->buf_size = OMAP3ISP_HIST_MAX_BUF_SIZE; - - return 0; -} - -static int hist_comp_params(struct ispstat *hist, - struct omap3isp_hist_config *user_cfg) -{ - struct omap3isp_hist_config *cur_cfg = hist->priv; - int c; - - if (cur_cfg->cfa != user_cfg->cfa) - return 1; - - if (cur_cfg->num_acc_frames != user_cfg->num_acc_frames) - return 1; - - if (cur_cfg->hist_bins != user_cfg->hist_bins) - return 1; - - for (c = 0; c < OMAP3ISP_HIST_MAX_WG; c++) { - if (c == 3 && user_cfg->cfa == OMAP3ISP_HIST_CFA_FOVEONX3) - break; - else if (cur_cfg->wg[c] != user_cfg->wg[c]) - return 1; - } - - if (cur_cfg->num_regions != user_cfg->num_regions) - return 1; - - /* Regions */ - for (c = 0; c < user_cfg->num_regions; c++) { - if (cur_cfg->region[c].h_start != user_cfg->region[c].h_start) - return 1; - if (cur_cfg->region[c].h_end != user_cfg->region[c].h_end) - return 1; - if (cur_cfg->region[c].v_start != user_cfg->region[c].v_start) - return 1; - if (cur_cfg->region[c].v_end != user_cfg->region[c].v_end) - return 1; - } - - return 0; -} - -/* - * hist_update_params - Helper function to check and store user given params. - * @new_conf: Pointer to user configuration structure. - */ -static void hist_set_params(struct ispstat *hist, void *new_conf) -{ - struct omap3isp_hist_config *user_cfg = new_conf; - struct omap3isp_hist_config *cur_cfg = hist->priv; - - if (!hist->configured || hist_comp_params(hist, user_cfg)) { - memcpy(cur_cfg, user_cfg, sizeof(*user_cfg)); - if (user_cfg->num_acc_frames == 0) - user_cfg->num_acc_frames = 1; - hist->inc_config++; - hist->update = 1; - /* - * User might be asked for a bigger buffer than necessary for - * this configuration. In order to return the right amount of - * data during buffer request, let's calculate the size here - * instead of stick with user_cfg->buf_size. - */ - cur_cfg->buf_size = hist_get_buf_size(cur_cfg); - - } -} - -static long hist_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct ispstat *stat = v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_OMAP3ISP_HIST_CFG: - return omap3isp_stat_config(stat, arg); - case VIDIOC_OMAP3ISP_STAT_REQ: - return omap3isp_stat_request_statistics(stat, arg); - case VIDIOC_OMAP3ISP_STAT_EN: { - int *en = arg; - return omap3isp_stat_enable(stat, !!*en); - } - } - - return -ENOIOCTLCMD; - -} - -static const struct ispstat_ops hist_ops = { - .validate_params = hist_validate_params, - .set_params = hist_set_params, - .setup_regs = hist_setup_regs, - .enable = hist_enable, - .busy = hist_busy, - .buf_process = hist_buf_process, -}; - -static const struct v4l2_subdev_core_ops hist_subdev_core_ops = { - .ioctl = hist_ioctl, - .subscribe_event = omap3isp_stat_subscribe_event, - .unsubscribe_event = omap3isp_stat_unsubscribe_event, -}; - -static const struct v4l2_subdev_video_ops hist_subdev_video_ops = { - .s_stream = omap3isp_stat_s_stream, -}; - -static const struct v4l2_subdev_ops hist_subdev_ops = { - .core = &hist_subdev_core_ops, - .video = &hist_subdev_video_ops, -}; - -/* - * omap3isp_hist_init - Module Initialization. - */ -int omap3isp_hist_init(struct isp_device *isp) -{ - struct ispstat *hist = &isp->isp_hist; - struct omap3isp_hist_config *hist_cfg; - int ret = -1; - - hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL); - if (hist_cfg == NULL) - return -ENOMEM; - - memset(hist, 0, sizeof(*hist)); - if (HIST_CONFIG_DMA) - ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST", - hist_dma_cb, hist, &hist->dma_ch); - if (ret) { - if (HIST_CONFIG_DMA) - dev_warn(isp->dev, "hist: DMA request channel failed. " - "Using PIO only.\n"); - hist->dma_ch = -1; - } else { - dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch); - hist_dma_config(hist); - omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ); - } - - hist->ops = &hist_ops; - hist->priv = hist_cfg; - hist->event_type = V4L2_EVENT_OMAP3ISP_HIST; - hist->isp = isp; - - ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops); - if (ret) { - kfree(hist_cfg); - if (HIST_USING_DMA(hist)) - omap_free_dma(hist->dma_ch); - } - - return ret; -} - -/* - * omap3isp_hist_cleanup - Module cleanup. - */ -void omap3isp_hist_cleanup(struct isp_device *isp) -{ - if (HIST_USING_DMA(&isp->isp_hist)) - omap_free_dma(isp->isp_hist.dma_ch); - kfree(isp->isp_hist.priv); - omap3isp_stat_free(&isp->isp_hist); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isphist.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isphist.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isphist.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isphist.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - * isphist.h - * - * TI OMAP3 ISP - Histogram module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: David Cohen - * Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_HIST_H -#define OMAP3_ISP_HIST_H - -#include - -#define ISPHIST_IN_BIT_WIDTH_CCDC 10 - -struct isp_device; - -int omap3isp_hist_init(struct isp_device *isp); -void omap3isp_hist_cleanup(struct isp_device *isp); - -#endif /* OMAP3_ISP_HIST */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isppreview.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isppreview.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isppreview.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isppreview.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2113 +0,0 @@ -/* - * isppreview.c - * - * TI OMAP3 ISP driver - Preview module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include - -#include "isp.h" -#include "ispreg.h" -#include "isppreview.h" - -/* Default values in Office Flourescent Light for RGBtoRGB Blending */ -static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = { - { /* RGB-RGB Matrix */ - {0x01E2, 0x0F30, 0x0FEE}, - {0x0F9B, 0x01AC, 0x0FB9}, - {0x0FE0, 0x0EC0, 0x0260} - }, /* RGB Offset */ - {0x0000, 0x0000, 0x0000} -}; - -/* Default values in Office Flourescent Light for RGB to YUV Conversion*/ -static struct omap3isp_prev_csc flr_prev_csc = { - { /* CSC Coef Matrix */ - {66, 129, 25}, - {-38, -75, 112}, - {112, -94 , -18} - }, /* CSC Offset */ - {0x0, 0x0, 0x0} -}; - -/* Default values in Office Flourescent Light for CFA Gradient*/ -#define FLR_CFA_GRADTHRS_HORZ 0x28 -#define FLR_CFA_GRADTHRS_VERT 0x28 - -/* Default values in Office Flourescent Light for Chroma Suppression*/ -#define FLR_CSUP_GAIN 0x0D -#define FLR_CSUP_THRES 0xEB - -/* Default values in Office Flourescent Light for Noise Filter*/ -#define FLR_NF_STRGTH 0x03 - -/* Default values for White Balance */ -#define FLR_WBAL_DGAIN 0x100 -#define FLR_WBAL_COEF 0x20 - -/* Default values in Office Flourescent Light for Black Adjustment*/ -#define FLR_BLKADJ_BLUE 0x0 -#define FLR_BLKADJ_GREEN 0x0 -#define FLR_BLKADJ_RED 0x0 - -#define DEF_DETECT_CORRECT_VAL 0xe - -#define PREV_MIN_WIDTH 64 -#define PREV_MIN_HEIGHT 8 -#define PREV_MAX_HEIGHT 16384 - -/* - * Coeficient Tables for the submodules in Preview. - * Array is initialised with the values from.the tables text file. - */ - -/* - * CFA Filter Coefficient Table - * - */ -static u32 cfa_coef_table[] = { -#include "cfa_coef_table.h" -}; - -/* - * Default Gamma Correction Table - All components - */ -static u32 gamma_table[] = { -#include "gamma_table.h" -}; - -/* - * Noise Filter Threshold table - */ -static u32 noise_filter_table[] = { -#include "noise_filter_table.h" -}; - -/* - * Luminance Enhancement Table - */ -static u32 luma_enhance_table[] = { -#include "luma_enhance_table.h" -}; - -/* - * preview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview. - * @enable: 1 - Reverse the A-Law done in CCDC. - */ -static void -preview_enable_invalaw(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW); -} - -/* - * preview_enable_drkframe_capture - Enable/Disable of the darkframe capture. - * @prev - - * @enable: 1 - Enable, 0 - Disable - * - * NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also - * The proccess is applied for each captured frame. - */ -static void -preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_DRKFCAP); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_DRKFCAP); -} - -/* - * preview_enable_drkframe - Enable/Disable of the darkframe subtract. - * @enable: 1 - Acquires memory bandwidth since the pixels in each frame is - * subtracted with the pixels in the current frame. - * - * The proccess is applied for each captured frame. - */ -static void -preview_enable_drkframe(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_DRKFEN); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_DRKFEN); -} - -/* - * preview_config_drkf_shadcomp - Configures shift value in shading comp. - * @scomp_shtval: 3bit value of shift used in shading compensation. - */ -static void -preview_config_drkf_shadcomp(struct isp_prev_device *prev, - const void *scomp_shtval) -{ - struct isp_device *isp = to_isp_device(prev); - const u32 *shtval = scomp_shtval; - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_SCOMP_SFT_MASK, - *shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT); -} - -/* - * preview_enable_hmed - Enables/Disables of the Horizontal Median Filter. - * @enable: 1 - Enables Horizontal Median Filter. - */ -static void -preview_enable_hmed(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_HMEDEN); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_HMEDEN); -} - -/* - * preview_config_hmed - Configures the Horizontal Median Filter. - * @prev_hmed: Structure containing the odd and even distance between the - * pixels in the image along with the filter threshold. - */ -static void -preview_config_hmed(struct isp_prev_device *prev, const void *prev_hmed) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_hmed *hmed = prev_hmed; - - isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) | - (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) | - (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT), - OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED); -} - -/* - * preview_config_noisefilter - Configures the Noise Filter. - * @prev_nf: Structure containing the noisefilter table, strength to be used - * for the noise filter and the defect correction enable flag. - */ -static void -preview_config_noisefilter(struct isp_prev_device *prev, const void *prev_nf) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_nf *nf = prev_nf; - unsigned int i; - - isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF); - isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR, - OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); - for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) { - isp_reg_writel(isp, nf->table[i], - OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA); - } -} - -/* - * preview_config_dcor - Configures the defect correction - * @prev_dcor: Structure containing the defect correct thresholds - */ -static void -preview_config_dcor(struct isp_prev_device *prev, const void *prev_dcor) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_dcor *dcor = prev_dcor; - - isp_reg_writel(isp, dcor->detect_correct[0], - OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0); - isp_reg_writel(isp, dcor->detect_correct[1], - OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1); - isp_reg_writel(isp, dcor->detect_correct[2], - OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2); - isp_reg_writel(isp, dcor->detect_correct[3], - OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3); - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_DCCOUP, - dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0); -} - -/* - * preview_config_cfa - Configures the CFA Interpolation parameters. - * @prev_cfa: Structure containing the CFA interpolation table, CFA format - * in the image, vertical and horizontal gradient threshold. - */ -static void -preview_config_cfa(struct isp_prev_device *prev, const void *prev_cfa) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_cfa *cfa = prev_cfa; - unsigned int i; - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_CFAFMT_MASK, - cfa->format << ISPPRV_PCR_CFAFMT_SHIFT); - - isp_reg_writel(isp, - (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) | - (cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT), - OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA); - - isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR, - OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); - - for (i = 0; i < OMAP3ISP_PREV_CFA_TBL_SIZE; i++) { - isp_reg_writel(isp, cfa->table[i], - OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA); - } -} - -/* - * preview_config_gammacorrn - Configures the Gamma Correction table values - * @gtable: Structure containing the table for red, blue, green gamma table. - */ -static void -preview_config_gammacorrn(struct isp_prev_device *prev, const void *gtable) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_gtables *gt = gtable; - unsigned int i; - - isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR, - OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); - for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++) - isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV, - ISPPRV_SET_TBL_DATA); - - isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR, - OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); - for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++) - isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV, - ISPPRV_SET_TBL_DATA); - - isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR, - OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); - for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++) - isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV, - ISPPRV_SET_TBL_DATA); -} - -/* - * preview_config_luma_enhancement - Sets the Luminance Enhancement table. - * @ytable: Structure containing the table for Luminance Enhancement table. - */ -static void -preview_config_luma_enhancement(struct isp_prev_device *prev, - const void *ytable) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_luma *yt = ytable; - unsigned int i; - - isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR, - OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); - for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) { - isp_reg_writel(isp, yt->table[i], - OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA); - } -} - -/* - * preview_config_chroma_suppression - Configures the Chroma Suppression. - * @csup: Structure containing the threshold value for suppression - * and the hypass filter enable flag. - */ -static void -preview_config_chroma_suppression(struct isp_prev_device *prev, - const void *csup) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_csup *cs = csup; - - isp_reg_writel(isp, - cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) | - (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT), - OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP); -} - -/* - * preview_enable_noisefilter - Enables/Disables the Noise Filter. - * @enable: 1 - Enables the Noise Filter. - */ -static void -preview_enable_noisefilter(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_NFEN); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_NFEN); -} - -/* - * preview_enable_dcor - Enables/Disables the defect correction. - * @enable: 1 - Enables the defect correction. - */ -static void -preview_enable_dcor(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_DCOREN); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_DCOREN); -} - -/* - * preview_enable_cfa - Enable/Disable the CFA Interpolation. - * @enable: 1 - Enables the CFA. - */ -static void -preview_enable_cfa(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_CFAEN); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_CFAEN); -} - -/* - * preview_enable_gammabypass - Enables/Disables the GammaByPass - * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB. - * 0 - Goes through Gamma Correction. input and output is 10bit. - */ -static void -preview_enable_gammabypass(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_GAMMA_BYPASS); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_GAMMA_BYPASS); -} - -/* - * preview_enable_luma_enhancement - Enables/Disables Luminance Enhancement - * @enable: 1 - Enable the Luminance Enhancement. - */ -static void -preview_enable_luma_enhancement(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_YNENHEN); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_YNENHEN); -} - -/* - * preview_enable_chroma_suppression - Enables/Disables Chrominance Suppr. - * @enable: 1 - Enable the Chrominance Suppression. - */ -static void -preview_enable_chroma_suppression(struct isp_prev_device *prev, u8 enable) -{ - struct isp_device *isp = to_isp_device(prev); - - if (enable) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_SUPEN); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_SUPEN); -} - -/* - * preview_config_whitebalance - Configures the White Balance parameters. - * @prev_wbal: Structure containing the digital gain and white balance - * coefficient. - * - * Coefficient matrix always with default values. - */ -static void -preview_config_whitebalance(struct isp_prev_device *prev, const void *prev_wbal) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_wbal *wbal = prev_wbal; - u32 val; - - isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN); - - val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT; - val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT; - val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT; - val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN); - - isp_reg_writel(isp, - ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT | - ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT | - ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT | - ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT | - ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT | - ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT | - ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT | - ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT | - ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT | - ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT | - ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT | - ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT | - ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT | - ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT | - ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT | - ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT, - OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL); -} - -/* - * preview_config_blkadj - Configures the Black Adjustment parameters. - * @prev_blkadj: Structure containing the black adjustment towards red, green, - * blue. - */ -static void -preview_config_blkadj(struct isp_prev_device *prev, const void *prev_blkadj) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_blkadj *blkadj = prev_blkadj; - - isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) | - (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) | - (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT), - OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF); -} - -/* - * preview_config_rgb_blending - Configures the RGB-RGB Blending matrix. - * @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb - * offset. - */ -static void -preview_config_rgb_blending(struct isp_prev_device *prev, const void *rgb2rgb) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_rgbtorgb *rgbrgb = rgb2rgb; - u32 val; - - val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT; - val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1); - - val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT; - val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2); - - val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT; - val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3); - - val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT; - val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4); - - val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5); - - val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT; - val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1); - - val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2); -} - -/* - * Configures the RGB-YCbYCr conversion matrix - * @prev_csc: Structure containing the RGB to YCbYCr matrix and the - * YCbCr offset. - */ -static void -preview_config_rgb_to_ycbcr(struct isp_prev_device *prev, const void *prev_csc) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_csc *csc = prev_csc; - u32 val; - - val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT; - val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT; - val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0); - - val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT; - val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT; - val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1); - - val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT; - val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT; - val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2); - - val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT; - val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT; - val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT; - isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET); -} - -/* - * preview_update_contrast - Updates the contrast. - * @contrast: Pointer to hold the current programmed contrast value. - * - * Value should be programmed before enabling the module. - */ -static void -preview_update_contrast(struct isp_prev_device *prev, u8 contrast) -{ - struct prev_params *params = &prev->params; - - if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) { - params->contrast = contrast * ISPPRV_CONTRAST_UNITS; - prev->update |= PREV_CONTRAST; - } -} - -/* - * preview_config_contrast - Configures the Contrast. - * @params: Contrast value (u8 pointer, U8Q0 format). - * - * Value should be programmed before enabling the module. - */ -static void -preview_config_contrast(struct isp_prev_device *prev, const void *params) -{ - struct isp_device *isp = to_isp_device(prev); - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT, - 0xff << ISPPRV_CNT_BRT_CNT_SHIFT, - *(u8 *)params << ISPPRV_CNT_BRT_CNT_SHIFT); -} - -/* - * preview_update_brightness - Updates the brightness in preview module. - * @brightness: Pointer to hold the current programmed brightness value. - * - */ -static void -preview_update_brightness(struct isp_prev_device *prev, u8 brightness) -{ - struct prev_params *params = &prev->params; - - if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) { - params->brightness = brightness * ISPPRV_BRIGHT_UNITS; - prev->update |= PREV_BRIGHTNESS; - } -} - -/* - * preview_config_brightness - Configures the brightness. - * @params: Brightness value (u8 pointer, U8Q0 format). - */ -static void -preview_config_brightness(struct isp_prev_device *prev, const void *params) -{ - struct isp_device *isp = to_isp_device(prev); - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT, - 0xff << ISPPRV_CNT_BRT_BRT_SHIFT, - *(u8 *)params << ISPPRV_CNT_BRT_BRT_SHIFT); -} - -/* - * preview_config_yc_range - Configures the max and min Y and C values. - * @yclimit: Structure containing the range of Y and C values. - */ -static void -preview_config_yc_range(struct isp_prev_device *prev, const void *yclimit) -{ - struct isp_device *isp = to_isp_device(prev); - const struct omap3isp_prev_yclimit *yc = yclimit; - - isp_reg_writel(isp, - yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT | - yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT | - yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT | - yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT, - OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC); -} - -/* preview parameters update structure */ -struct preview_update { - int cfg_bit; - int feature_bit; - void (*config)(struct isp_prev_device *, const void *); - void (*enable)(struct isp_prev_device *, u8); -}; - -static struct preview_update update_attrs[] = { - {OMAP3ISP_PREV_LUMAENH, PREV_LUMA_ENHANCE, - preview_config_luma_enhancement, - preview_enable_luma_enhancement}, - {OMAP3ISP_PREV_INVALAW, PREV_INVERSE_ALAW, - NULL, - preview_enable_invalaw}, - {OMAP3ISP_PREV_HRZ_MED, PREV_HORZ_MEDIAN_FILTER, - preview_config_hmed, - preview_enable_hmed}, - {OMAP3ISP_PREV_CFA, PREV_CFA, - preview_config_cfa, - preview_enable_cfa}, - {OMAP3ISP_PREV_CHROMA_SUPP, PREV_CHROMA_SUPPRESS, - preview_config_chroma_suppression, - preview_enable_chroma_suppression}, - {OMAP3ISP_PREV_WB, PREV_WB, - preview_config_whitebalance, - NULL}, - {OMAP3ISP_PREV_BLKADJ, PREV_BLKADJ, - preview_config_blkadj, - NULL}, - {OMAP3ISP_PREV_RGB2RGB, PREV_RGB2RGB, - preview_config_rgb_blending, - NULL}, - {OMAP3ISP_PREV_COLOR_CONV, PREV_COLOR_CONV, - preview_config_rgb_to_ycbcr, - NULL}, - {OMAP3ISP_PREV_YC_LIMIT, PREV_YCLIMITS, - preview_config_yc_range, - NULL}, - {OMAP3ISP_PREV_DEFECT_COR, PREV_DEFECT_COR, - preview_config_dcor, - preview_enable_dcor}, - {OMAP3ISP_PREV_GAMMABYPASS, PREV_GAMMA_BYPASS, - NULL, - preview_enable_gammabypass}, - {OMAP3ISP_PREV_DRK_FRM_CAPTURE, PREV_DARK_FRAME_CAPTURE, - NULL, - preview_enable_drkframe_capture}, - {OMAP3ISP_PREV_DRK_FRM_SUBTRACT, PREV_DARK_FRAME_SUBTRACT, - NULL, - preview_enable_drkframe}, - {OMAP3ISP_PREV_LENS_SHADING, PREV_LENS_SHADING, - preview_config_drkf_shadcomp, - preview_enable_drkframe}, - {OMAP3ISP_PREV_NF, PREV_NOISE_FILTER, - preview_config_noisefilter, - preview_enable_noisefilter}, - {OMAP3ISP_PREV_GAMMA, PREV_GAMMA, - preview_config_gammacorrn, - NULL}, - {-1, PREV_CONTRAST, - preview_config_contrast, - NULL}, - {-1, PREV_BRIGHTNESS, - preview_config_brightness, - NULL}, -}; - -/* - * __preview_get_ptrs - helper function which return pointers to members - * of params and config structures. - * @params - pointer to preview_params structure. - * @param - return pointer to appropriate structure field. - * @configs - pointer to update config structure. - * @config - return pointer to appropriate structure field. - * @bit - for which feature to return pointers. - * Return size of coresponding prev_params member - */ -static u32 -__preview_get_ptrs(struct prev_params *params, void **param, - struct omap3isp_prev_update_config *configs, - void __user **config, u32 bit) -{ -#define CHKARG(cfgs, cfg, field) \ - if (cfgs && cfg) { \ - *(cfg) = (cfgs)->field; \ - } - - switch (bit) { - case PREV_HORZ_MEDIAN_FILTER: - *param = ¶ms->hmed; - CHKARG(configs, config, hmed) - return sizeof(params->hmed); - case PREV_NOISE_FILTER: - *param = ¶ms->nf; - CHKARG(configs, config, nf) - return sizeof(params->nf); - break; - case PREV_CFA: - *param = ¶ms->cfa; - CHKARG(configs, config, cfa) - return sizeof(params->cfa); - case PREV_LUMA_ENHANCE: - *param = ¶ms->luma; - CHKARG(configs, config, luma) - return sizeof(params->luma); - case PREV_CHROMA_SUPPRESS: - *param = ¶ms->csup; - CHKARG(configs, config, csup) - return sizeof(params->csup); - case PREV_DEFECT_COR: - *param = ¶ms->dcor; - CHKARG(configs, config, dcor) - return sizeof(params->dcor); - case PREV_BLKADJ: - *param = ¶ms->blk_adj; - CHKARG(configs, config, blkadj) - return sizeof(params->blk_adj); - case PREV_YCLIMITS: - *param = ¶ms->yclimit; - CHKARG(configs, config, yclimit) - return sizeof(params->yclimit); - case PREV_RGB2RGB: - *param = ¶ms->rgb2rgb; - CHKARG(configs, config, rgb2rgb) - return sizeof(params->rgb2rgb); - case PREV_COLOR_CONV: - *param = ¶ms->rgb2ycbcr; - CHKARG(configs, config, csc) - return sizeof(params->rgb2ycbcr); - case PREV_WB: - *param = ¶ms->wbal; - CHKARG(configs, config, wbal) - return sizeof(params->wbal); - case PREV_GAMMA: - *param = ¶ms->gamma; - CHKARG(configs, config, gamma) - return sizeof(params->gamma); - case PREV_CONTRAST: - *param = ¶ms->contrast; - return 0; - case PREV_BRIGHTNESS: - *param = ¶ms->brightness; - return 0; - default: - *param = NULL; - *config = NULL; - break; - } - return 0; -} - -/* - * preview_config - Copy and update local structure with userspace preview - * configuration. - * @prev: ISP preview engine - * @cfg: Configuration - * - * Return zero if success or -EFAULT if the configuration can't be copied from - * userspace. - */ -static int preview_config(struct isp_prev_device *prev, - struct omap3isp_prev_update_config *cfg) -{ - struct prev_params *params; - struct preview_update *attr; - int i, bit, rval = 0; - - params = &prev->params; - - if (prev->state != ISP_PIPELINE_STREAM_STOPPED) { - unsigned long flags; - - spin_lock_irqsave(&prev->lock, flags); - prev->shadow_update = 1; - spin_unlock_irqrestore(&prev->lock, flags); - } - - for (i = 0; i < ARRAY_SIZE(update_attrs); i++) { - attr = &update_attrs[i]; - bit = 0; - - if (!(cfg->update & attr->cfg_bit)) - continue; - - bit = cfg->flag & attr->cfg_bit; - if (bit) { - void *to = NULL, __user *from = NULL; - unsigned long sz = 0; - - sz = __preview_get_ptrs(params, &to, cfg, &from, - bit); - if (to && from && sz) { - if (copy_from_user(to, from, sz)) { - rval = -EFAULT; - break; - } - } - params->features |= attr->feature_bit; - } else { - params->features &= ~attr->feature_bit; - } - - prev->update |= attr->feature_bit; - } - - prev->shadow_update = 0; - return rval; -} - -/* - * preview_setup_hw - Setup preview registers and/or internal memory - * @prev: pointer to preview private structure - * Note: can be called from interrupt context - * Return none - */ -static void preview_setup_hw(struct isp_prev_device *prev) -{ - struct prev_params *params = &prev->params; - struct preview_update *attr; - int i, bit; - void *param_ptr; - - for (i = 0; i < ARRAY_SIZE(update_attrs); i++) { - attr = &update_attrs[i]; - - if (!(prev->update & attr->feature_bit)) - continue; - bit = params->features & attr->feature_bit; - if (bit) { - if (attr->config) { - __preview_get_ptrs(params, ¶m_ptr, NULL, - NULL, bit); - attr->config(prev, param_ptr); - } - if (attr->enable) - attr->enable(prev, 1); - } else - if (attr->enable) - attr->enable(prev, 0); - - prev->update &= ~attr->feature_bit; - } -} - -/* - * preview_config_ycpos - Configure byte layout of YUV image. - * @mode: Indicates the required byte layout. - */ -static void -preview_config_ycpos(struct isp_prev_device *prev, - enum v4l2_mbus_pixelcode pixelcode) -{ - struct isp_device *isp = to_isp_device(prev); - enum preview_ycpos_mode mode; - - switch (pixelcode) { - case V4L2_MBUS_FMT_YUYV8_1X16: - mode = YCPOS_CrYCbY; - break; - case V4L2_MBUS_FMT_UYVY8_1X16: - mode = YCPOS_YCrYCb; - break; - default: - return; - } - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_YCPOS_CrYCbY, - mode << ISPPRV_PCR_YCPOS_SHIFT); -} - -/* - * preview_config_averager - Enable / disable / configure averager - * @average: Average value to be configured. - */ -static void preview_config_averager(struct isp_prev_device *prev, u8 average) -{ - struct isp_device *isp = to_isp_device(prev); - int reg = 0; - - if (prev->params.cfa.format == OMAP3ISP_CFAFMT_BAYER) - reg = ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT | - ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT | - average; - else if (prev->params.cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON) - reg = ISPPRV_AVE_EVENDIST_3 << ISPPRV_AVE_EVENDIST_SHIFT | - ISPPRV_AVE_ODDDIST_3 << ISPPRV_AVE_ODDDIST_SHIFT | - average; - isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE); -} - -/* - * preview_config_input_size - Configure the input frame size - * - * The preview engine crops several rows and columns internally depending on - * which processing blocks are enabled. The driver assumes all those blocks are - * enabled when reporting source pad formats to userspace. If this assumption is - * not true, rows and columns must be manually cropped at the preview engine - * input to avoid overflows at the end of lines and frames. - */ -static void preview_config_input_size(struct isp_prev_device *prev) -{ - struct isp_device *isp = to_isp_device(prev); - struct prev_params *params = &prev->params; - struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; - unsigned int sph = 0; - unsigned int eph = format->width - 1; - unsigned int slv = 0; - unsigned int elv = format->height - 1; - - if (prev->input == PREVIEW_INPUT_CCDC) { - sph += 2; - eph -= 2; - } - - /* - * Median filter 4 pixels - * Noise filter 4 pixels, 4 lines - * or faulty pixels correction - * CFA filter 4 pixels, 4 lines in Bayer mode - * 2 lines in other modes - * Color suppression 2 pixels - * or luma enhancement - * ------------------------------------------------------------- - * Maximum total 14 pixels, 8 lines - */ - - if (!(params->features & PREV_CFA)) { - sph += 2; - eph -= 2; - slv += 2; - elv -= 2; - } - if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) { - sph += 2; - eph -= 2; - slv += 2; - elv -= 2; - } - if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) { - sph += 2; - eph -= 2; - } - if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))) - sph += 2; - - isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, - OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); - isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv, - OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO); -} - -/* - * preview_config_inlineoffset - Configures the Read address line offset. - * @prev: Preview module - * @offset: Line offset - * - * According to the TRM, the line offset must be aligned on a 32 bytes boundary. - * However, a hardware bug requires the memory start address to be aligned on a - * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as - * well. - */ -static void -preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset) -{ - struct isp_device *isp = to_isp_device(prev); - - isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV, - ISPPRV_RADR_OFFSET); -} - -/* - * preview_set_inaddr - Sets memory address of input frame. - * @addr: 32bit memory address aligned on 32byte boundary. - * - * Configures the memory address from which the input frame is to be read. - */ -static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr) -{ - struct isp_device *isp = to_isp_device(prev); - - isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR); -} - -/* - * preview_config_outlineoffset - Configures the Write address line offset. - * @offset: Line Offset for the preview output. - * - * The offset must be a multiple of 32 bytes. - */ -static void preview_config_outlineoffset(struct isp_prev_device *prev, - u32 offset) -{ - struct isp_device *isp = to_isp_device(prev); - - isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV, - ISPPRV_WADD_OFFSET); -} - -/* - * preview_set_outaddr - Sets the memory address to store output frame - * @addr: 32bit memory address aligned on 32byte boundary. - * - * Configures the memory address to which the output frame is written. - */ -static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr) -{ - struct isp_device *isp = to_isp_device(prev); - - isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR); -} - -static void preview_adjust_bandwidth(struct isp_prev_device *prev) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity); - struct isp_device *isp = to_isp_device(prev); - const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK]; - unsigned long l3_ick = pipe->l3_ick; - struct v4l2_fract *timeperframe; - unsigned int cycles_per_frame; - unsigned int requests_per_frame; - unsigned int cycles_per_request; - unsigned int minimum; - unsigned int maximum; - unsigned int value; - - if (prev->input != PREVIEW_INPUT_MEMORY) { - isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, - ISPSBL_SDR_REQ_PRV_EXP_MASK); - return; - } - - /* Compute the minimum number of cycles per request, based on the - * pipeline maximum data rate. This is an absolute lower bound if we - * don't want SBL overflows, so round the value up. - */ - cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1, - pipe->max_rate); - minimum = DIV_ROUND_UP(cycles_per_request, 32); - - /* Compute the maximum number of cycles per request, based on the - * requested frame rate. This is a soft upper bound to achieve a frame - * rate equal or higher than the requested value, so round the value - * down. - */ - timeperframe = &pipe->max_timeperframe; - - requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height; - cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator, - timeperframe->denominator); - cycles_per_request = cycles_per_frame / requests_per_frame; - - maximum = cycles_per_request / 32; - - value = max(minimum, maximum); - - dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value); - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, - ISPSBL_SDR_REQ_PRV_EXP_MASK, - value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT); -} - -/* - * omap3isp_preview_busy - Gets busy state of preview module. - */ -int omap3isp_preview_busy(struct isp_prev_device *prev) -{ - struct isp_device *isp = to_isp_device(prev); - - return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR) - & ISPPRV_PCR_BUSY; -} - -/* - * omap3isp_preview_restore_context - Restores the values of preview registers - */ -void omap3isp_preview_restore_context(struct isp_device *isp) -{ - isp->isp_prev.update = PREV_FEATURES_END - 1; - preview_setup_hw(&isp->isp_prev); -} - -/* - * preview_print_status - Dump preview module registers to the kernel log - */ -#define PREV_PRINT_REGISTER(isp, name)\ - dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \ - isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name)) - -static void preview_print_status(struct isp_prev_device *prev) -{ - struct isp_device *isp = to_isp_device(prev); - - dev_dbg(isp->dev, "-------------Preview Register dump----------\n"); - - PREV_PRINT_REGISTER(isp, PCR); - PREV_PRINT_REGISTER(isp, HORZ_INFO); - PREV_PRINT_REGISTER(isp, VERT_INFO); - PREV_PRINT_REGISTER(isp, RSDR_ADDR); - PREV_PRINT_REGISTER(isp, RADR_OFFSET); - PREV_PRINT_REGISTER(isp, DSDR_ADDR); - PREV_PRINT_REGISTER(isp, DRKF_OFFSET); - PREV_PRINT_REGISTER(isp, WSDR_ADDR); - PREV_PRINT_REGISTER(isp, WADD_OFFSET); - PREV_PRINT_REGISTER(isp, AVE); - PREV_PRINT_REGISTER(isp, HMED); - PREV_PRINT_REGISTER(isp, NF); - PREV_PRINT_REGISTER(isp, WB_DGAIN); - PREV_PRINT_REGISTER(isp, WBGAIN); - PREV_PRINT_REGISTER(isp, WBSEL); - PREV_PRINT_REGISTER(isp, CFA); - PREV_PRINT_REGISTER(isp, BLKADJOFF); - PREV_PRINT_REGISTER(isp, RGB_MAT1); - PREV_PRINT_REGISTER(isp, RGB_MAT2); - PREV_PRINT_REGISTER(isp, RGB_MAT3); - PREV_PRINT_REGISTER(isp, RGB_MAT4); - PREV_PRINT_REGISTER(isp, RGB_MAT5); - PREV_PRINT_REGISTER(isp, RGB_OFF1); - PREV_PRINT_REGISTER(isp, RGB_OFF2); - PREV_PRINT_REGISTER(isp, CSC0); - PREV_PRINT_REGISTER(isp, CSC1); - PREV_PRINT_REGISTER(isp, CSC2); - PREV_PRINT_REGISTER(isp, CSC_OFFSET); - PREV_PRINT_REGISTER(isp, CNT_BRT); - PREV_PRINT_REGISTER(isp, CSUP); - PREV_PRINT_REGISTER(isp, SETUP_YC); - PREV_PRINT_REGISTER(isp, SET_TBL_ADDR); - PREV_PRINT_REGISTER(isp, CDC_THR0); - PREV_PRINT_REGISTER(isp, CDC_THR1); - PREV_PRINT_REGISTER(isp, CDC_THR2); - PREV_PRINT_REGISTER(isp, CDC_THR3); - - dev_dbg(isp->dev, "--------------------------------------------\n"); -} - -/* - * preview_init_params - init image processing parameters. - * @prev: pointer to previewer private structure - * return none - */ -static void preview_init_params(struct isp_prev_device *prev) -{ - struct prev_params *params = &prev->params; - int i = 0; - - /* Init values */ - params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; - params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; - params->average = NO_AVE; - params->cfa.format = OMAP3ISP_CFAFMT_BAYER; - memcpy(params->cfa.table, cfa_coef_table, - sizeof(params->cfa.table)); - params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ; - params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT; - params->csup.gain = FLR_CSUP_GAIN; - params->csup.thres = FLR_CSUP_THRES; - params->csup.hypf_en = 0; - memcpy(params->luma.table, luma_enhance_table, - sizeof(params->luma.table)); - params->nf.spread = FLR_NF_STRGTH; - memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table)); - params->dcor.couplet_mode_en = 1; - for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++) - params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL; - memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue)); - memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green)); - memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red)); - params->wbal.dgain = FLR_WBAL_DGAIN; - params->wbal.coef0 = FLR_WBAL_COEF; - params->wbal.coef1 = FLR_WBAL_COEF; - params->wbal.coef2 = FLR_WBAL_COEF; - params->wbal.coef3 = FLR_WBAL_COEF; - params->blk_adj.red = FLR_BLKADJ_RED; - params->blk_adj.green = FLR_BLKADJ_GREEN; - params->blk_adj.blue = FLR_BLKADJ_BLUE; - params->rgb2rgb = flr_rgb2rgb; - params->rgb2ycbcr = flr_prev_csc; - params->yclimit.minC = ISPPRV_YC_MIN; - params->yclimit.maxC = ISPPRV_YC_MAX; - params->yclimit.minY = ISPPRV_YC_MIN; - params->yclimit.maxY = ISPPRV_YC_MAX; - - params->features = PREV_CFA | PREV_DEFECT_COR | PREV_NOISE_FILTER - | PREV_GAMMA | PREV_BLKADJ | PREV_YCLIMITS - | PREV_RGB2RGB | PREV_COLOR_CONV | PREV_WB - | PREV_BRIGHTNESS | PREV_CONTRAST; - - prev->update = PREV_FEATURES_END - 1; -} - -/* - * preview_max_out_width - Handle previewer hardware ouput limitations - * @isp_revision : ISP revision - * returns maximum width output for current isp revision - */ -static unsigned int preview_max_out_width(struct isp_prev_device *prev) -{ - struct isp_device *isp = to_isp_device(prev); - - switch (isp->revision) { - case ISP_REVISION_1_0: - return ISPPRV_MAXOUTPUT_WIDTH; - - case ISP_REVISION_2_0: - default: - return ISPPRV_MAXOUTPUT_WIDTH_ES2; - - case ISP_REVISION_15_0: - return ISPPRV_MAXOUTPUT_WIDTH_3630; - } -} - -static void preview_configure(struct isp_prev_device *prev) -{ - struct isp_device *isp = to_isp_device(prev); - struct v4l2_mbus_framefmt *format; - unsigned int max_out_width; - unsigned int format_avg; - - preview_setup_hw(prev); - - if (prev->output & PREVIEW_OUTPUT_MEMORY) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_SDRPORT); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_SDRPORT); - - if (prev->output & PREVIEW_OUTPUT_RESIZER) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_RSZPORT); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_RSZPORT); - - /* PREV_PAD_SINK */ - format = &prev->formats[PREV_PAD_SINK]; - - preview_adjust_bandwidth(prev); - - preview_config_input_size(prev); - - if (prev->input == PREVIEW_INPUT_CCDC) - preview_config_inlineoffset(prev, 0); - else - preview_config_inlineoffset(prev, - ALIGN(format->width, 0x20) * 2); - - /* PREV_PAD_SOURCE */ - format = &prev->formats[PREV_PAD_SOURCE]; - - if (prev->output & PREVIEW_OUTPUT_MEMORY) - preview_config_outlineoffset(prev, - ALIGN(format->width, 0x10) * 2); - - max_out_width = preview_max_out_width(prev); - - format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1); - preview_config_averager(prev, format_avg); - preview_config_ycpos(prev, format->code); -} - -/* ----------------------------------------------------------------------------- - * Interrupt handling - */ - -static void preview_enable_oneshot(struct isp_prev_device *prev) -{ - struct isp_device *isp = to_isp_device(prev); - - /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE - * bit is set. As the preview engine is used in single-shot mode, we - * need to set PCR.SOURCE before enabling the preview engine. - */ - if (prev->input == PREVIEW_INPUT_MEMORY) - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_SOURCE); - - isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT); -} - -void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev) -{ - /* - * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun - * condition, the module was paused and now we have a buffer queued - * on the output again. Restart the pipeline if running in continuous - * mode. - */ - if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS && - prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) { - preview_enable_oneshot(prev); - isp_video_dmaqueue_flags_clr(&prev->video_out); - } -} - -static void preview_isr_buffer(struct isp_prev_device *prev) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity); - struct isp_buffer *buffer; - int restart = 0; - - if (prev->input == PREVIEW_INPUT_MEMORY) { - buffer = omap3isp_video_buffer_next(&prev->video_in, - prev->error); - if (buffer != NULL) - preview_set_inaddr(prev, buffer->isp_addr); - pipe->state |= ISP_PIPELINE_IDLE_INPUT; - } - - if (prev->output & PREVIEW_OUTPUT_MEMORY) { - buffer = omap3isp_video_buffer_next(&prev->video_out, - prev->error); - if (buffer != NULL) { - preview_set_outaddr(prev, buffer->isp_addr); - restart = 1; - } - pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; - } - - switch (prev->state) { - case ISP_PIPELINE_STREAM_SINGLESHOT: - if (isp_pipeline_ready(pipe)) - omap3isp_pipeline_set_stream(pipe, - ISP_PIPELINE_STREAM_SINGLESHOT); - break; - - case ISP_PIPELINE_STREAM_CONTINUOUS: - /* If an underrun occurs, the video queue operation handler will - * restart the preview engine. Otherwise restart it immediately. - */ - if (restart) - preview_enable_oneshot(prev); - break; - - case ISP_PIPELINE_STREAM_STOPPED: - default: - return; - } - - prev->error = 0; -} - -/* - * omap3isp_preview_isr - ISP preview engine interrupt handler - * - * Manage the preview engine video buffers and configure shadowed registers. - */ -void omap3isp_preview_isr(struct isp_prev_device *prev) -{ - unsigned long flags; - - if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping)) - return; - - spin_lock_irqsave(&prev->lock, flags); - if (prev->shadow_update) - goto done; - - preview_setup_hw(prev); - preview_config_input_size(prev); - -done: - spin_unlock_irqrestore(&prev->lock, flags); - - if (prev->input == PREVIEW_INPUT_MEMORY || - prev->output & PREVIEW_OUTPUT_MEMORY) - preview_isr_buffer(prev); - else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS) - preview_enable_oneshot(prev); -} - -/* ----------------------------------------------------------------------------- - * ISP video operations - */ - -static int preview_video_queue(struct isp_video *video, - struct isp_buffer *buffer) -{ - struct isp_prev_device *prev = &video->isp->isp_prev; - - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - preview_set_inaddr(prev, buffer->isp_addr); - - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - preview_set_outaddr(prev, buffer->isp_addr); - - return 0; -} - -static const struct isp_video_operations preview_video_ops = { - .queue = preview_video_queue, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -/* - * preview_s_ctrl - Handle set control subdev method - * @ctrl: pointer to v4l2 control structure - */ -static int preview_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct isp_prev_device *prev = - container_of(ctrl->handler, struct isp_prev_device, ctrls); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - preview_update_brightness(prev, ctrl->val); - break; - case V4L2_CID_CONTRAST: - preview_update_contrast(prev, ctrl->val); - break; - } - - return 0; -} - -static const struct v4l2_ctrl_ops preview_ctrl_ops = { - .s_ctrl = preview_s_ctrl, -}; - -/* - * preview_ioctl - Handle preview module private ioctl's - * @prev: pointer to preview context structure - * @cmd: configuration command - * @arg: configuration argument - * return -EINVAL or zero on success - */ -static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct isp_prev_device *prev = v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_OMAP3ISP_PRV_CFG: - return preview_config(prev, arg); - - default: - return -ENOIOCTLCMD; - } -} - -/* - * preview_set_stream - Enable/Disable streaming on preview subdev - * @sd : pointer to v4l2 subdev structure - * @enable: 1 == Enable, 0 == Disable - * return -EINVAL or zero on sucess - */ -static int preview_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct isp_prev_device *prev = v4l2_get_subdevdata(sd); - struct isp_video *video_out = &prev->video_out; - struct isp_device *isp = to_isp_device(prev); - struct device *dev = to_device(prev); - unsigned long flags; - - if (prev->state == ISP_PIPELINE_STREAM_STOPPED) { - if (enable == ISP_PIPELINE_STREAM_STOPPED) - return 0; - - omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW); - preview_configure(prev); - atomic_set(&prev->stopping, 0); - prev->error = 0; - preview_print_status(prev); - } - - switch (enable) { - case ISP_PIPELINE_STREAM_CONTINUOUS: - if (prev->output & PREVIEW_OUTPUT_MEMORY) - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE); - - if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED || - !(prev->output & PREVIEW_OUTPUT_MEMORY)) - preview_enable_oneshot(prev); - - isp_video_dmaqueue_flags_clr(video_out); - break; - - case ISP_PIPELINE_STREAM_SINGLESHOT: - if (prev->input == PREVIEW_INPUT_MEMORY) - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ); - if (prev->output & PREVIEW_OUTPUT_MEMORY) - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE); - - preview_enable_oneshot(prev); - break; - - case ISP_PIPELINE_STREAM_STOPPED: - if (omap3isp_module_sync_idle(&sd->entity, &prev->wait, - &prev->stopping)) - dev_dbg(dev, "%s: stop timeout.\n", sd->name); - spin_lock_irqsave(&prev->lock, flags); - omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ); - omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE); - omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW); - spin_unlock_irqrestore(&prev->lock, flags); - isp_video_dmaqueue_flags_clr(video_out); - break; - } - - prev->state = enable; - return 0; -} - -static struct v4l2_mbus_framefmt * -__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); - else - return &prev->formats[pad]; -} - -/* previewer format descriptions */ -static const unsigned int preview_input_fmts[] = { - V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, -}; - -static const unsigned int preview_output_fmts[] = { - V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, -}; - -/* - * preview_try_format - Handle try format by pad subdev method - * @prev: ISP preview device - * @fh : V4L2 subdev file handle - * @pad: pad num - * @fmt: pointer to v4l2 format structure - */ -static void preview_try_format(struct isp_prev_device *prev, - struct v4l2_subdev_fh *fh, unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - struct v4l2_mbus_framefmt *format; - unsigned int max_out_width; - enum v4l2_mbus_pixelcode pixelcode; - unsigned int i; - - max_out_width = preview_max_out_width(prev); - - switch (pad) { - case PREV_PAD_SINK: - /* When reading data from the CCDC, the input size has already - * been mangled by the CCDC output pad so it can be accepted - * as-is. - * - * When reading data from memory, clamp the requested width and - * height. The TRM doesn't specify a minimum input height, make - * sure we got enough lines to enable the noise filter and color - * filter array interpolation. - */ - if (prev->input == PREVIEW_INPUT_MEMORY) { - fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, - max_out_width * 8); - fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, - PREV_MAX_HEIGHT); - } - - fmt->colorspace = V4L2_COLORSPACE_SRGB; - - for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) { - if (fmt->code == preview_input_fmts[i]) - break; - } - - /* If not found, use SGRBG10 as default */ - if (i >= ARRAY_SIZE(preview_input_fmts)) - fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; - break; - - case PREV_PAD_SOURCE: - pixelcode = fmt->code; - format = __preview_get_format(prev, fh, PREV_PAD_SINK, which); - memcpy(fmt, format, sizeof(*fmt)); - - /* The preview module output size is configurable through the - * input interface (horizontal and vertical cropping) and the - * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In - * spite of this, hardcode the output size to the biggest - * possible value for simplicity reasons. - */ - switch (pixelcode) { - case V4L2_MBUS_FMT_YUYV8_1X16: - case V4L2_MBUS_FMT_UYVY8_1X16: - fmt->code = pixelcode; - break; - - default: - fmt->code = V4L2_MBUS_FMT_YUYV8_1X16; - break; - } - - /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped - * from the left and right sides when the input source is the - * CCDC. This seems not to be needed in practice, investigation - * is required. - */ - if (prev->input == PREVIEW_INPUT_CCDC) - fmt->width -= 4; - - /* The preview module can output a maximum of 3312 pixels - * horizontally due to fixed memory-line sizes. Compute the - * horizontal averaging factor accordingly. Note that the limit - * applies to the noise filter and CFA interpolation blocks, so - * it doesn't take cropping by further blocks into account. - * - * ES 1.0 hardware revision is limited to 1280 pixels - * horizontally. - */ - fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1); - - /* Assume that all blocks are enabled and crop pixels and lines - * accordingly. See preview_config_input_size() for more - * information. - */ - fmt->width -= 14; - fmt->height -= 8; - - fmt->colorspace = V4L2_COLORSPACE_JPEG; - break; - } - - fmt->field = V4L2_FIELD_NONE; -} - -/* - * preview_enum_mbus_code - Handle pixel format enumeration - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @code : pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int preview_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - switch (code->pad) { - case PREV_PAD_SINK: - if (code->index >= ARRAY_SIZE(preview_input_fmts)) - return -EINVAL; - - code->code = preview_input_fmts[code->index]; - break; - case PREV_PAD_SOURCE: - if (code->index >= ARRAY_SIZE(preview_output_fmts)) - return -EINVAL; - - code->code = preview_output_fmts[code->index]; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int preview_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct isp_prev_device *prev = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * preview_get_format - Handle get format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on sucess - */ -static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_prev_device *prev = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __preview_get_format(prev, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -/* - * preview_set_format - Handle set format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_prev_device *prev = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __preview_get_format(prev, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - /* Propagate the format from sink to source */ - if (fmt->pad == PREV_PAD_SINK) { - format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, - fmt->which); - *format = fmt->format; - preview_try_format(prev, fh, PREV_PAD_SOURCE, format, - fmt->which); - } - - return 0; -} - -/* - * preview_init_formats - Initialize formats on all pads - * @sd: ISP preview V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. - */ -static int preview_init_formats(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = PREV_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; - format.format.width = 4096; - format.format.height = 4096; - preview_set_format(sd, fh, &format); - - return 0; -} - -/* subdev core operations */ -static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = { - .ioctl = preview_ioctl, -}; - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = { - .s_stream = preview_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = { - .enum_mbus_code = preview_enum_mbus_code, - .enum_frame_size = preview_enum_frame_size, - .get_fmt = preview_get_format, - .set_fmt = preview_set_format, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops preview_v4l2_ops = { - .core = &preview_v4l2_core_ops, - .video = &preview_v4l2_video_ops, - .pad = &preview_v4l2_pad_ops, -}; - -/* subdev internal operations */ -static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = { - .open = preview_init_formats, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -/* - * preview_link_setup - Setup previewer connections. - * @entity : Pointer to media entity structure - * @local : Pointer to local pad array - * @remote : Pointer to remote pad array - * @flags : Link flags - * return -EINVAL or zero on success - */ -static int preview_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct isp_prev_device *prev = v4l2_get_subdevdata(sd); - - switch (local->index | media_entity_type(remote->entity)) { - case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE: - /* read from memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (prev->input == PREVIEW_INPUT_CCDC) - return -EBUSY; - prev->input = PREVIEW_INPUT_MEMORY; - } else { - if (prev->input == PREVIEW_INPUT_MEMORY) - prev->input = PREVIEW_INPUT_NONE; - } - break; - - case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: - /* read from ccdc */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (prev->input == PREVIEW_INPUT_MEMORY) - return -EBUSY; - prev->input = PREVIEW_INPUT_CCDC; - } else { - if (prev->input == PREVIEW_INPUT_CCDC) - prev->input = PREVIEW_INPUT_NONE; - } - break; - - /* - * The ISP core doesn't support pipelines with multiple video outputs. - * Revisit this when it will be implemented, and return -EBUSY for now. - */ - - case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: - /* write to memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (prev->output & ~PREVIEW_OUTPUT_MEMORY) - return -EBUSY; - prev->output |= PREVIEW_OUTPUT_MEMORY; - } else { - prev->output &= ~PREVIEW_OUTPUT_MEMORY; - } - break; - - case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: - /* write to resizer */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (prev->output & ~PREVIEW_OUTPUT_RESIZER) - return -EBUSY; - prev->output |= PREVIEW_OUTPUT_RESIZER; - } else { - prev->output &= ~PREVIEW_OUTPUT_RESIZER; - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* media operations */ -static const struct media_entity_operations preview_media_ops = { - .link_setup = preview_link_setup, -}; - -/* - * review_init_entities - Initialize subdev and media entity. - * @prev : Pointer to preview structure - * return -ENOMEM or zero on success - */ -static int preview_init_entities(struct isp_prev_device *prev) -{ - struct v4l2_subdev *sd = &prev->subdev; - struct media_pad *pads = prev->pads; - struct media_entity *me = &sd->entity; - int ret; - - prev->input = PREVIEW_INPUT_NONE; - - v4l2_subdev_init(sd, &preview_v4l2_ops); - sd->internal_ops = &preview_v4l2_internal_ops; - strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for isp subdevs */ - v4l2_set_subdevdata(sd, prev); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - v4l2_ctrl_handler_init(&prev->ctrls, 2); - v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS, - ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH, - ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF); - v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST, - ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH, - ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF); - v4l2_ctrl_handler_setup(&prev->ctrls); - sd->ctrl_handler = &prev->ctrls; - - pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - me->ops = &preview_media_ops; - ret = media_entity_init(me, PREV_PADS_NUM, pads, 0); - if (ret < 0) - return ret; - - preview_init_formats(sd, NULL); - - /* According to the OMAP34xx TRM, video buffers need to be aligned on a - * 32 bytes boundary. However, an undocumented hardware bug requires a - * 64 bytes boundary at the preview engine input. - */ - prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - prev->video_in.ops = &preview_video_ops; - prev->video_in.isp = to_isp_device(prev); - prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; - prev->video_in.bpl_alignment = 64; - prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - prev->video_out.ops = &preview_video_ops; - prev->video_out.isp = to_isp_device(prev); - prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; - prev->video_out.bpl_alignment = 32; - - ret = omap3isp_video_init(&prev->video_in, "preview"); - if (ret < 0) - return ret; - - ret = omap3isp_video_init(&prev->video_out, "preview"); - if (ret < 0) - return ret; - - /* Connect the video nodes to the previewer subdev. */ - ret = media_entity_create_link(&prev->video_in.video.entity, 0, - &prev->subdev.entity, PREV_PAD_SINK, 0); - if (ret < 0) - return ret; - - ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, - &prev->video_out.video.entity, 0, 0); - if (ret < 0) - return ret; - - return 0; -} - -void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) -{ - media_entity_cleanup(&prev->subdev.entity); - - v4l2_device_unregister_subdev(&prev->subdev); - v4l2_ctrl_handler_free(&prev->ctrls); - omap3isp_video_unregister(&prev->video_in); - omap3isp_video_unregister(&prev->video_out); -} - -int omap3isp_preview_register_entities(struct isp_prev_device *prev, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &prev->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&prev->video_in, vdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&prev->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_preview_unregister_entities(prev); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP previewer initialisation and cleanup - */ - -void omap3isp_preview_cleanup(struct isp_device *isp) -{ -} - -/* - * isp_preview_init - Previewer initialization. - * @dev : Pointer to ISP device - * return -ENOMEM or zero on success - */ -int omap3isp_preview_init(struct isp_device *isp) -{ - struct isp_prev_device *prev = &isp->isp_prev; - int ret; - - spin_lock_init(&prev->lock); - init_waitqueue_head(&prev->wait); - preview_init_params(prev); - - ret = preview_init_entities(prev); - if (ret < 0) - goto out; - -out: - if (ret) - omap3isp_preview_cleanup(isp); - - return ret; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isppreview.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isppreview.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isppreview.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/isppreview.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,214 +0,0 @@ -/* - * isppreview.h - * - * TI OMAP3 ISP - Preview module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_PREVIEW_H -#define OMAP3_ISP_PREVIEW_H - -#include -#include -#include - -#include "ispvideo.h" - -#define ISPPRV_BRIGHT_STEP 0x1 -#define ISPPRV_BRIGHT_DEF 0x0 -#define ISPPRV_BRIGHT_LOW 0x0 -#define ISPPRV_BRIGHT_HIGH 0xFF -#define ISPPRV_BRIGHT_UNITS 0x1 - -#define ISPPRV_CONTRAST_STEP 0x1 -#define ISPPRV_CONTRAST_DEF 0x10 -#define ISPPRV_CONTRAST_LOW 0x0 -#define ISPPRV_CONTRAST_HIGH 0xFF -#define ISPPRV_CONTRAST_UNITS 0x1 - -#define NO_AVE 0x0 -#define AVE_2_PIX 0x1 -#define AVE_4_PIX 0x2 -#define AVE_8_PIX 0x3 - -/* Features list */ -#define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH -#define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW -#define PREV_HORZ_MEDIAN_FILTER OMAP3ISP_PREV_HRZ_MED -#define PREV_CFA OMAP3ISP_PREV_CFA -#define PREV_CHROMA_SUPPRESS OMAP3ISP_PREV_CHROMA_SUPP -#define PREV_WB OMAP3ISP_PREV_WB -#define PREV_BLKADJ OMAP3ISP_PREV_BLKADJ -#define PREV_RGB2RGB OMAP3ISP_PREV_RGB2RGB -#define PREV_COLOR_CONV OMAP3ISP_PREV_COLOR_CONV -#define PREV_YCLIMITS OMAP3ISP_PREV_YC_LIMIT -#define PREV_DEFECT_COR OMAP3ISP_PREV_DEFECT_COR -#define PREV_GAMMA_BYPASS OMAP3ISP_PREV_GAMMABYPASS -#define PREV_DARK_FRAME_CAPTURE OMAP3ISP_PREV_DRK_FRM_CAPTURE -#define PREV_DARK_FRAME_SUBTRACT OMAP3ISP_PREV_DRK_FRM_SUBTRACT -#define PREV_LENS_SHADING OMAP3ISP_PREV_LENS_SHADING -#define PREV_NOISE_FILTER OMAP3ISP_PREV_NF -#define PREV_GAMMA OMAP3ISP_PREV_GAMMA - -#define PREV_CONTRAST (1 << 17) -#define PREV_BRIGHTNESS (1 << 18) -#define PREV_AVERAGER (1 << 19) -#define PREV_FEATURES_END (1 << 20) - -enum preview_input_entity { - PREVIEW_INPUT_NONE, - PREVIEW_INPUT_CCDC, - PREVIEW_INPUT_MEMORY, -}; - -#define PREVIEW_OUTPUT_RESIZER (1 << 1) -#define PREVIEW_OUTPUT_MEMORY (1 << 2) - -/* Configure byte layout of YUV image */ -enum preview_ycpos_mode { - YCPOS_YCrYCb = 0, - YCPOS_YCbYCr = 1, - YCPOS_CbYCrY = 2, - YCPOS_CrYCbY = 3 -}; - -/* - * struct prev_params - Structure for all configuration - * @features: Set of features enabled. - * @cfa: CFA coefficients. - * @csup: Chroma suppression coefficients. - * @luma: Luma enhancement coefficients. - * @nf: Noise filter coefficients. - * @dcor: Noise filter coefficients. - * @gamma: Gamma coefficients. - * @wbal: White Balance parameters. - * @blk_adj: Black adjustment parameters. - * @rgb2rgb: RGB blending parameters. - * @rgb2ycbcr: RGB to ycbcr parameters. - * @hmed: Horizontal median filter. - * @yclimit: YC limits parameters. - * @average: Downsampling rate for averager. - * @contrast: Contrast. - * @brightness: Brightness. - */ -struct prev_params { - u32 features; - struct omap3isp_prev_cfa cfa; - struct omap3isp_prev_csup csup; - struct omap3isp_prev_luma luma; - struct omap3isp_prev_nf nf; - struct omap3isp_prev_dcor dcor; - struct omap3isp_prev_gtables gamma; - struct omap3isp_prev_wbal wbal; - struct omap3isp_prev_blkadj blk_adj; - struct omap3isp_prev_rgbtorgb rgb2rgb; - struct omap3isp_prev_csc rgb2ycbcr; - struct omap3isp_prev_hmed hmed; - struct omap3isp_prev_yclimit yclimit; - u8 average; - u8 contrast; - u8 brightness; -}; - -/* - * struct isptables_update - Structure for Table Configuration. - * @update: Specifies which tables should be updated. - * @flag: Specifies which tables should be enabled. - * @nf: Pointer to structure for Noise Filter - * @lsc: Pointer to LSC gain table. (currently not used) - * @gamma: Pointer to gamma correction tables. - * @cfa: Pointer to color filter array configuration. - * @wbal: Pointer to colour and digital gain configuration. - */ -struct isptables_update { - u32 update; - u32 flag; - struct omap3isp_prev_nf *nf; - u32 *lsc; - struct omap3isp_prev_gtables *gamma; - struct omap3isp_prev_cfa *cfa; - struct omap3isp_prev_wbal *wbal; -}; - -/* Sink and source previewer pads */ -#define PREV_PAD_SINK 0 -#define PREV_PAD_SOURCE 1 -#define PREV_PADS_NUM 2 - -/* - * struct isp_prev_device - Structure for storing ISP Preview module information - * @subdev: V4L2 subdevice - * @pads: Media entity pads - * @formats: Active formats at the subdev pad - * @input: Module currently connected to the input pad - * @output: Bitmask of the active output - * @video_in: Input video entity - * @video_out: Output video entity - * @error: A hardware error occured during capture - * @params: Module configuration data - * @shadow_update: If set, update the hardware configured in the next interrupt - * @underrun: Whether the preview entity has queued buffers on the output - * @state: Current preview pipeline state - * @lock: Shadow update lock - * @update: Bitmask of the parameters to be updated - * - * This structure is used to store the OMAP ISP Preview module Information. - */ -struct isp_prev_device { - struct v4l2_subdev subdev; - struct media_pad pads[PREV_PADS_NUM]; - struct v4l2_mbus_framefmt formats[PREV_PADS_NUM]; - - struct v4l2_ctrl_handler ctrls; - - enum preview_input_entity input; - unsigned int output; - struct isp_video video_in; - struct isp_video video_out; - unsigned int error; - - struct prev_params params; - unsigned int shadow_update:1; - enum isp_pipeline_stream_state state; - wait_queue_head_t wait; - atomic_t stopping; - spinlock_t lock; - u32 update; -}; - -struct isp_device; - -int omap3isp_preview_init(struct isp_device *isp); -void omap3isp_preview_cleanup(struct isp_device *isp); - -int omap3isp_preview_register_entities(struct isp_prev_device *prv, - struct v4l2_device *vdev); -void omap3isp_preview_unregister_entities(struct isp_prev_device *prv); - -void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev); -void omap3isp_preview_isr(struct isp_prev_device *prev); - -int omap3isp_preview_busy(struct isp_prev_device *isp_prev); - -void omap3isp_preview_restore_context(struct isp_device *isp); - -#endif /* OMAP3_ISP_PREVIEW_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispqueue.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispqueue.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispqueue.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispqueue.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1153 +0,0 @@ -/* - * ispqueue.c - * - * TI OMAP3 ISP - Video buffers queue handling - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ispqueue.h" - -/* ----------------------------------------------------------------------------- - * Video buffers management - */ - -/* - * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP - * - * The typical operation required here is Cache Invalidation across - * the (user space) buffer address range. And this _must_ be done - * at QBUF stage (and *only* at QBUF). - * - * We try to use optimal cache invalidation function: - * - dmac_map_area: - * - used when the number of pages are _low_. - * - it becomes quite slow as the number of pages increase. - * - for 648x492 viewfinder (150 pages) it takes 1.3 ms. - * - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms. - * - * - flush_cache_all: - * - used when the number of pages are _high_. - * - time taken in the range of 500-900 us. - * - has a higher penalty but, as whole dcache + icache is invalidated - */ -/* - * FIXME: dmac_inv_range crashes randomly on the user space buffer - * address. Fall back to flush_cache_all for now. - */ -#define ISP_CACHE_FLUSH_PAGES_MAX 0 - -static void isp_video_buffer_cache_sync(struct isp_video_buffer *buf) -{ - if (buf->skip_cache) - return; - - if (buf->vbuf.m.userptr == 0 || buf->npages == 0 || - buf->npages > ISP_CACHE_FLUSH_PAGES_MAX) - flush_cache_all(); - else { - dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length, - DMA_FROM_DEVICE); - outer_inv_range(buf->vbuf.m.userptr, - buf->vbuf.m.userptr + buf->vbuf.length); - } -} - -/* - * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped - * - * Lock the VMAs underlying the given buffer into memory. This avoids the - * userspace buffer mapping from being swapped out, making VIPT cache handling - * easier. - * - * Note that the pages will not be freed as the buffers have been locked to - * memory using by a call to get_user_pages(), but the userspace mapping could - * still disappear if the VMAs are not locked. This is caused by the memory - * management code trying to be as lock-less as possible, which results in the - * userspace mapping manager not finding out that the pages are locked under - * some conditions. - */ -static int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock) -{ - struct vm_area_struct *vma; - unsigned long start; - unsigned long end; - int ret = 0; - - if (buf->vbuf.memory == V4L2_MEMORY_MMAP) - return 0; - - /* We can be called from workqueue context if the current task dies to - * unlock the VMAs. In that case there's no current memory management - * context so unlocking can't be performed, but the VMAs have been or - * are getting destroyed anyway so it doesn't really matter. - */ - if (!current || !current->mm) - return lock ? -EINVAL : 0; - - start = buf->vbuf.m.userptr; - end = buf->vbuf.m.userptr + buf->vbuf.length - 1; - - down_write(¤t->mm->mmap_sem); - spin_lock(¤t->mm->page_table_lock); - - do { - vma = find_vma(current->mm, start); - if (vma == NULL) { - ret = -EFAULT; - goto out; - } - - if (lock) - vma->vm_flags |= VM_LOCKED; - else - vma->vm_flags &= ~VM_LOCKED; - - start = vma->vm_end + 1; - } while (vma->vm_end < end); - - if (lock) - buf->vm_flags |= VM_LOCKED; - else - buf->vm_flags &= ~VM_LOCKED; - -out: - spin_unlock(¤t->mm->page_table_lock); - up_write(¤t->mm->mmap_sem); - return ret; -} - -/* - * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer - * - * Iterate over the vmalloc'ed area and create a scatter list entry for every - * page. - */ -static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf) -{ - struct scatterlist *sglist; - unsigned int npages; - unsigned int i; - void *addr; - - addr = buf->vaddr; - npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT; - - sglist = vmalloc(npages * sizeof(*sglist)); - if (sglist == NULL) - return -ENOMEM; - - sg_init_table(sglist, npages); - - for (i = 0; i < npages; ++i, addr += PAGE_SIZE) { - struct page *page = vmalloc_to_page(addr); - - if (page == NULL || PageHighMem(page)) { - vfree(sglist); - return -EINVAL; - } - - sg_set_page(&sglist[i], page, PAGE_SIZE, 0); - } - - buf->sglen = npages; - buf->sglist = sglist; - - return 0; -} - -/* - * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer - * - * Walk the buffer pages list and create a 1:1 mapping to a scatter list. - */ -static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf) -{ - struct scatterlist *sglist; - unsigned int offset = buf->offset; - unsigned int i; - - sglist = vmalloc(buf->npages * sizeof(*sglist)); - if (sglist == NULL) - return -ENOMEM; - - sg_init_table(sglist, buf->npages); - - for (i = 0; i < buf->npages; ++i) { - if (PageHighMem(buf->pages[i])) { - vfree(sglist); - return -EINVAL; - } - - sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset, - offset); - offset = 0; - } - - buf->sglen = buf->npages; - buf->sglist = sglist; - - return 0; -} - -/* - * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer - * - * Create a scatter list of physically contiguous pages starting at the buffer - * memory physical address. - */ -static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf) -{ - struct scatterlist *sglist; - unsigned int offset = buf->offset; - unsigned long pfn = buf->paddr >> PAGE_SHIFT; - unsigned int i; - - sglist = vmalloc(buf->npages * sizeof(*sglist)); - if (sglist == NULL) - return -ENOMEM; - - sg_init_table(sglist, buf->npages); - - for (i = 0; i < buf->npages; ++i, ++pfn) { - sg_set_page(&sglist[i], pfn_to_page(pfn), PAGE_SIZE - offset, - offset); - /* PFNMAP buffers will not get DMA-mapped, set the DMA address - * manually. - */ - sg_dma_address(&sglist[i]) = (pfn << PAGE_SHIFT) + offset; - offset = 0; - } - - buf->sglen = buf->npages; - buf->sglist = sglist; - - return 0; -} - -/* - * isp_video_buffer_cleanup - Release pages for a userspace VMA. - * - * Release pages locked by a call isp_video_buffer_prepare_user and free the - * pages table. - */ -static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) -{ - enum dma_data_direction direction; - unsigned int i; - - if (buf->queue->ops->buffer_cleanup) - buf->queue->ops->buffer_cleanup(buf); - - if (!(buf->vm_flags & VM_PFNMAP)) { - direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE - ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - dma_unmap_sg(buf->queue->dev, buf->sglist, buf->sglen, - direction); - } - - vfree(buf->sglist); - buf->sglist = NULL; - buf->sglen = 0; - - if (buf->pages != NULL) { - isp_video_buffer_lock_vma(buf, 0); - - for (i = 0; i < buf->npages; ++i) - page_cache_release(buf->pages[i]); - - vfree(buf->pages); - buf->pages = NULL; - } - - buf->npages = 0; - buf->skip_cache = false; -} - -/* - * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory. - * - * This function creates a list of pages for a userspace VMA. The number of - * pages is first computed based on the buffer size, and pages are then - * retrieved by a call to get_user_pages. - * - * Pages are pinned to memory by get_user_pages, making them available for DMA - * transfers. However, due to memory management optimization, it seems the - * get_user_pages doesn't guarantee that the pinned pages will not be written - * to swap and removed from the userspace mapping(s). When this happens, a page - * fault can be generated when accessing those unmapped pages. - * - * If the fault is triggered by a page table walk caused by VIPT cache - * management operations, the page fault handler might oops if the MM semaphore - * is held, as it can't handle kernel page faults in that case. To fix that, a - * fixup entry needs to be added to the cache management code, or the userspace - * VMA must be locked to avoid removing pages from the userspace mapping in the - * first place. - * - * If the number of pages retrieved is smaller than the number required by the - * buffer size, the function returns -EFAULT. - */ -static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) -{ - unsigned long data; - unsigned int first; - unsigned int last; - int ret; - - data = buf->vbuf.m.userptr; - first = (data & PAGE_MASK) >> PAGE_SHIFT; - last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT; - - buf->offset = data & ~PAGE_MASK; - buf->npages = last - first + 1; - buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0])); - if (buf->pages == NULL) - return -ENOMEM; - - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, data & PAGE_MASK, - buf->npages, - buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, - buf->pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (ret != buf->npages) { - buf->npages = ret; - isp_video_buffer_cleanup(buf); - return -EFAULT; - } - - ret = isp_video_buffer_lock_vma(buf, 1); - if (ret < 0) - isp_video_buffer_cleanup(buf); - - return ret; -} - -/* - * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer - * - * Userspace VM_PFNMAP buffers are supported only if they are contiguous in - * memory and if they span a single VMA. - * - * Return 0 if the buffer is valid, or -EFAULT otherwise. - */ -static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf) -{ - struct vm_area_struct *vma; - unsigned long prev_pfn; - unsigned long this_pfn; - unsigned long start; - unsigned long end; - dma_addr_t pa; - int ret = -EFAULT; - - start = buf->vbuf.m.userptr; - end = buf->vbuf.m.userptr + buf->vbuf.length - 1; - - buf->offset = start & ~PAGE_MASK; - buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1; - buf->pages = NULL; - - down_read(¤t->mm->mmap_sem); - vma = find_vma(current->mm, start); - if (vma == NULL || vma->vm_end < end) - goto done; - - for (prev_pfn = 0; start <= end; start += PAGE_SIZE) { - ret = follow_pfn(vma, start, &this_pfn); - if (ret) - goto done; - - if (prev_pfn == 0) - pa = this_pfn << PAGE_SHIFT; - else if (this_pfn != prev_pfn + 1) { - ret = -EFAULT; - goto done; - } - - prev_pfn = this_pfn; - } - - buf->paddr = pa + buf->offset; - ret = 0; - -done: - up_read(¤t->mm->mmap_sem); - return ret; -} - -/* - * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address - * - * This function locates the VMAs for the buffer's userspace address and checks - * that their flags match. The onlflag that we need to care for at the moment is - * VM_PFNMAP. - * - * The buffer vm_flags field is set to the first VMA flags. - * - * Return -EFAULT if no VMA can be found for part of the buffer, or if the VMAs - * have incompatible flags. - */ -static int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf) -{ - struct vm_area_struct *vma; - pgprot_t vm_page_prot; - unsigned long start; - unsigned long end; - int ret = -EFAULT; - - start = buf->vbuf.m.userptr; - end = buf->vbuf.m.userptr + buf->vbuf.length - 1; - - down_read(¤t->mm->mmap_sem); - - do { - vma = find_vma(current->mm, start); - if (vma == NULL) - goto done; - - if (start == buf->vbuf.m.userptr) { - buf->vm_flags = vma->vm_flags; - vm_page_prot = vma->vm_page_prot; - } - - if ((buf->vm_flags ^ vma->vm_flags) & VM_PFNMAP) - goto done; - - if (vm_page_prot != vma->vm_page_prot) - goto done; - - start = vma->vm_end + 1; - } while (vma->vm_end < end); - - /* Skip cache management to enhance performances for non-cached or - * write-combining buffers. - */ - if (vm_page_prot == pgprot_noncached(vm_page_prot) || - vm_page_prot == pgprot_writecombine(vm_page_prot)) - buf->skip_cache = true; - - ret = 0; - -done: - up_read(¤t->mm->mmap_sem); - return ret; -} - -/* - * isp_video_buffer_prepare - Make a buffer ready for operation - * - * Preparing a buffer involves: - * - * - validating VMAs (userspace buffers only) - * - locking pages and VMAs into memory (userspace buffers only) - * - building page and scatter-gather lists - * - mapping buffers for DMA operation - * - performing driver-specific preparation - * - * The function must be called in userspace context with a valid mm context - * (this excludes cleanup paths such as sys_close when the userspace process - * segfaults). - */ -static int isp_video_buffer_prepare(struct isp_video_buffer *buf) -{ - enum dma_data_direction direction; - int ret; - - switch (buf->vbuf.memory) { - case V4L2_MEMORY_MMAP: - ret = isp_video_buffer_sglist_kernel(buf); - break; - - case V4L2_MEMORY_USERPTR: - ret = isp_video_buffer_prepare_vm_flags(buf); - if (ret < 0) - return ret; - - if (buf->vm_flags & VM_PFNMAP) { - ret = isp_video_buffer_prepare_pfnmap(buf); - if (ret < 0) - return ret; - - ret = isp_video_buffer_sglist_pfnmap(buf); - } else { - ret = isp_video_buffer_prepare_user(buf); - if (ret < 0) - return ret; - - ret = isp_video_buffer_sglist_user(buf); - } - break; - - default: - return -EINVAL; - } - - if (ret < 0) - goto done; - - if (!(buf->vm_flags & VM_PFNMAP)) { - direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE - ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - ret = dma_map_sg(buf->queue->dev, buf->sglist, buf->sglen, - direction); - if (ret != buf->sglen) { - ret = -EFAULT; - goto done; - } - } - - if (buf->queue->ops->buffer_prepare) - ret = buf->queue->ops->buffer_prepare(buf); - -done: - if (ret < 0) { - isp_video_buffer_cleanup(buf); - return ret; - } - - return ret; -} - -/* - * isp_video_queue_query - Query the status of a given buffer - * - * Locking: must be called with the queue lock held. - */ -static void isp_video_buffer_query(struct isp_video_buffer *buf, - struct v4l2_buffer *vbuf) -{ - memcpy(vbuf, &buf->vbuf, sizeof(*vbuf)); - - if (buf->vma_use_count) - vbuf->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (buf->state) { - case ISP_BUF_STATE_ERROR: - vbuf->flags |= V4L2_BUF_FLAG_ERROR; - case ISP_BUF_STATE_DONE: - vbuf->flags |= V4L2_BUF_FLAG_DONE; - case ISP_BUF_STATE_QUEUED: - case ISP_BUF_STATE_ACTIVE: - vbuf->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case ISP_BUF_STATE_IDLE: - default: - break; - } -} - -/* - * isp_video_buffer_wait - Wait for a buffer to be ready - * - * In non-blocking mode, return immediately with 0 if the buffer is ready or - * -EAGAIN if the buffer is in the QUEUED or ACTIVE state. - * - * In blocking mode, wait (interruptibly but with no timeout) on the buffer wait - * queue using the same condition. - */ -static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking) -{ - if (nonblocking) { - return (buf->state != ISP_BUF_STATE_QUEUED && - buf->state != ISP_BUF_STATE_ACTIVE) - ? 0 : -EAGAIN; - } - - return wait_event_interruptible(buf->wait, - buf->state != ISP_BUF_STATE_QUEUED && - buf->state != ISP_BUF_STATE_ACTIVE); -} - -/* ----------------------------------------------------------------------------- - * Queue management - */ - -/* - * isp_video_queue_free - Free video buffers memory - * - * Buffers can only be freed if the queue isn't streaming and if no buffer is - * mapped to userspace. Return -EBUSY if those conditions aren't statisfied. - * - * This function must be called with the queue lock held. - */ -static int isp_video_queue_free(struct isp_video_queue *queue) -{ - unsigned int i; - - if (queue->streaming) - return -EBUSY; - - for (i = 0; i < queue->count; ++i) { - if (queue->buffers[i]->vma_use_count != 0) - return -EBUSY; - } - - for (i = 0; i < queue->count; ++i) { - struct isp_video_buffer *buf = queue->buffers[i]; - - isp_video_buffer_cleanup(buf); - - vfree(buf->vaddr); - buf->vaddr = NULL; - - kfree(buf); - queue->buffers[i] = NULL; - } - - INIT_LIST_HEAD(&queue->queue); - queue->count = 0; - return 0; -} - -/* - * isp_video_queue_alloc - Allocate video buffers memory - * - * This function must be called with the queue lock held. - */ -static int isp_video_queue_alloc(struct isp_video_queue *queue, - unsigned int nbuffers, - unsigned int size, enum v4l2_memory memory) -{ - struct isp_video_buffer *buf; - unsigned int i; - void *mem; - int ret; - - /* Start by freeing the buffers. */ - ret = isp_video_queue_free(queue); - if (ret < 0) - return ret; - - /* Bail out of no buffers should be allocated. */ - if (nbuffers == 0) - return 0; - - /* Initialize the allocated buffers. */ - for (i = 0; i < nbuffers; ++i) { - buf = kzalloc(queue->bufsize, GFP_KERNEL); - if (buf == NULL) - break; - - if (memory == V4L2_MEMORY_MMAP) { - /* Allocate video buffers memory for mmap mode. Align - * the size to the page size. - */ - mem = vmalloc_32_user(PAGE_ALIGN(size)); - if (mem == NULL) { - kfree(buf); - break; - } - - buf->vbuf.m.offset = i * PAGE_ALIGN(size); - buf->vaddr = mem; - } - - buf->vbuf.index = i; - buf->vbuf.length = size; - buf->vbuf.type = queue->type; - buf->vbuf.field = V4L2_FIELD_NONE; - buf->vbuf.memory = memory; - - buf->queue = queue; - init_waitqueue_head(&buf->wait); - - queue->buffers[i] = buf; - } - - if (i == 0) - return -ENOMEM; - - queue->count = i; - return nbuffers; -} - -/** - * omap3isp_video_queue_cleanup - Clean up the video buffers queue - * @queue: Video buffers queue - * - * Free all allocated resources and clean up the video buffers queue. The queue - * must not be busy (no ongoing video stream) and buffers must have been - * unmapped. - * - * Return 0 on success or -EBUSY if the queue is busy or buffers haven't been - * unmapped. - */ -int omap3isp_video_queue_cleanup(struct isp_video_queue *queue) -{ - return isp_video_queue_free(queue); -} - -/** - * omap3isp_video_queue_init - Initialize the video buffers queue - * @queue: Video buffers queue - * @type: V4L2 buffer type (capture or output) - * @ops: Driver-specific queue operations - * @dev: Device used for DMA operations - * @bufsize: Size of the driver-specific buffer structure - * - * Initialize the video buffers queue with the supplied parameters. - * - * The queue type must be one of V4L2_BUF_TYPE_VIDEO_CAPTURE or - * V4L2_BUF_TYPE_VIDEO_OUTPUT. Other buffer types are not supported yet. - * - * Buffer objects will be allocated using the given buffer size to allow room - * for driver-specific fields. Driver-specific buffer structures must start - * with a struct isp_video_buffer field. Drivers with no driver-specific buffer - * structure must pass the size of the isp_video_buffer structure in the bufsize - * parameter. - * - * Return 0 on success. - */ -int omap3isp_video_queue_init(struct isp_video_queue *queue, - enum v4l2_buf_type type, - const struct isp_video_queue_operations *ops, - struct device *dev, unsigned int bufsize) -{ - INIT_LIST_HEAD(&queue->queue); - mutex_init(&queue->lock); - spin_lock_init(&queue->irqlock); - - queue->type = type; - queue->ops = ops; - queue->dev = dev; - queue->bufsize = bufsize; - - return 0; -} - -/* ----------------------------------------------------------------------------- - * V4L2 operations - */ - -/** - * omap3isp_video_queue_reqbufs - Allocate video buffers memory - * - * This function is intended to be used as a VIDIOC_REQBUFS ioctl handler. It - * allocated video buffer objects and, for MMAP buffers, buffer memory. - * - * If the number of buffers is 0, all buffers are freed and the function returns - * without performing any allocation. - * - * If the number of buffers is not 0, currently allocated buffers (if any) are - * freed and the requested number of buffers are allocated. Depending on - * driver-specific requirements and on memory availability, a number of buffer - * smaller or bigger than requested can be allocated. This isn't considered as - * an error. - * - * Return 0 on success or one of the following error codes: - * - * -EINVAL if the buffer type or index are invalid - * -EBUSY if the queue is busy (streaming or buffers mapped) - * -ENOMEM if the buffers can't be allocated due to an out-of-memory condition - */ -int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue, - struct v4l2_requestbuffers *rb) -{ - unsigned int nbuffers = rb->count; - unsigned int size; - int ret; - - if (rb->type != queue->type) - return -EINVAL; - - queue->ops->queue_prepare(queue, &nbuffers, &size); - if (size == 0) - return -EINVAL; - - nbuffers = min_t(unsigned int, nbuffers, ISP_VIDEO_MAX_BUFFERS); - - mutex_lock(&queue->lock); - - ret = isp_video_queue_alloc(queue, nbuffers, size, rb->memory); - if (ret < 0) - goto done; - - rb->count = ret; - ret = 0; - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_querybuf - Query the status of a buffer in a queue - * - * This function is intended to be used as a VIDIOC_QUERYBUF ioctl handler. It - * returns the status of a given video buffer. - * - * Return 0 on success or -EINVAL if the buffer type or index are invalid. - */ -int omap3isp_video_queue_querybuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf) -{ - struct isp_video_buffer *buf; - int ret = 0; - - if (vbuf->type != queue->type) - return -EINVAL; - - mutex_lock(&queue->lock); - - if (vbuf->index >= queue->count) { - ret = -EINVAL; - goto done; - } - - buf = queue->buffers[vbuf->index]; - isp_video_buffer_query(buf, vbuf); - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_qbuf - Queue a buffer - * - * This function is intended to be used as a VIDIOC_QBUF ioctl handler. - * - * The v4l2_buffer structure passed from userspace is first sanity tested. If - * sane, the buffer is then processed and added to the main queue and, if the - * queue is streaming, to the IRQ queue. - * - * Before being enqueued, USERPTR buffers are checked for address changes. If - * the buffer has a different userspace address, the old memory area is unlocked - * and the new memory area is locked. - */ -int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf) -{ - struct isp_video_buffer *buf; - unsigned long flags; - int ret = -EINVAL; - - if (vbuf->type != queue->type) - goto done; - - mutex_lock(&queue->lock); - - if (vbuf->index >= queue->count) - goto done; - - buf = queue->buffers[vbuf->index]; - - if (vbuf->memory != buf->vbuf.memory) - goto done; - - if (buf->state != ISP_BUF_STATE_IDLE) - goto done; - - if (vbuf->memory == V4L2_MEMORY_USERPTR && - vbuf->m.userptr != buf->vbuf.m.userptr) { - isp_video_buffer_cleanup(buf); - buf->vbuf.m.userptr = vbuf->m.userptr; - buf->prepared = 0; - } - - if (!buf->prepared) { - ret = isp_video_buffer_prepare(buf); - if (ret < 0) - goto done; - buf->prepared = 1; - } - - isp_video_buffer_cache_sync(buf); - - buf->state = ISP_BUF_STATE_QUEUED; - list_add_tail(&buf->stream, &queue->queue); - - if (queue->streaming) { - spin_lock_irqsave(&queue->irqlock, flags); - queue->ops->buffer_queue(buf); - spin_unlock_irqrestore(&queue->irqlock, flags); - } - - ret = 0; - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_dqbuf - Dequeue a buffer - * - * This function is intended to be used as a VIDIOC_DQBUF ioctl handler. - * - * The v4l2_buffer structure passed from userspace is first sanity tested. If - * sane, the buffer is then processed and added to the main queue and, if the - * queue is streaming, to the IRQ queue. - * - * Before being enqueued, USERPTR buffers are checked for address changes. If - * the buffer has a different userspace address, the old memory area is unlocked - * and the new memory area is locked. - */ -int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf, int nonblocking) -{ - struct isp_video_buffer *buf; - int ret; - - if (vbuf->type != queue->type) - return -EINVAL; - - mutex_lock(&queue->lock); - - if (list_empty(&queue->queue)) { - ret = -EINVAL; - goto done; - } - - buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream); - ret = isp_video_buffer_wait(buf, nonblocking); - if (ret < 0) - goto done; - - list_del(&buf->stream); - - isp_video_buffer_query(buf, vbuf); - buf->state = ISP_BUF_STATE_IDLE; - vbuf->flags &= ~V4L2_BUF_FLAG_QUEUED; - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_streamon - Start streaming - * - * This function is intended to be used as a VIDIOC_STREAMON ioctl handler. It - * starts streaming on the queue and calls the buffer_queue operation for all - * queued buffers. - * - * Return 0 on success. - */ -int omap3isp_video_queue_streamon(struct isp_video_queue *queue) -{ - struct isp_video_buffer *buf; - unsigned long flags; - - mutex_lock(&queue->lock); - - if (queue->streaming) - goto done; - - queue->streaming = 1; - - spin_lock_irqsave(&queue->irqlock, flags); - list_for_each_entry(buf, &queue->queue, stream) - queue->ops->buffer_queue(buf); - spin_unlock_irqrestore(&queue->irqlock, flags); - -done: - mutex_unlock(&queue->lock); - return 0; -} - -/** - * omap3isp_video_queue_streamoff - Stop streaming - * - * This function is intended to be used as a VIDIOC_STREAMOFF ioctl handler. It - * stops streaming on the queue and wakes up all the buffers. - * - * Drivers must stop the hardware and synchronize with interrupt handlers and/or - * delayed works before calling this function to make sure no buffer will be - * touched by the driver and/or hardware. - */ -void omap3isp_video_queue_streamoff(struct isp_video_queue *queue) -{ - struct isp_video_buffer *buf; - unsigned long flags; - unsigned int i; - - mutex_lock(&queue->lock); - - if (!queue->streaming) - goto done; - - queue->streaming = 0; - - spin_lock_irqsave(&queue->irqlock, flags); - for (i = 0; i < queue->count; ++i) { - buf = queue->buffers[i]; - - if (buf->state == ISP_BUF_STATE_ACTIVE) - wake_up(&buf->wait); - - buf->state = ISP_BUF_STATE_IDLE; - } - spin_unlock_irqrestore(&queue->irqlock, flags); - - INIT_LIST_HEAD(&queue->queue); - -done: - mutex_unlock(&queue->lock); -} - -/** - * omap3isp_video_queue_discard_done - Discard all buffers marked as DONE - * - * This function is intended to be used with suspend/resume operations. It - * discards all 'done' buffers as they would be too old to be requested after - * resume. - * - * Drivers must stop the hardware and synchronize with interrupt handlers and/or - * delayed works before calling this function to make sure no buffer will be - * touched by the driver and/or hardware. - */ -void omap3isp_video_queue_discard_done(struct isp_video_queue *queue) -{ - struct isp_video_buffer *buf; - unsigned int i; - - mutex_lock(&queue->lock); - - if (!queue->streaming) - goto done; - - for (i = 0; i < queue->count; ++i) { - buf = queue->buffers[i]; - - if (buf->state == ISP_BUF_STATE_DONE) - buf->state = ISP_BUF_STATE_ERROR; - } - -done: - mutex_unlock(&queue->lock); -} - -static void isp_video_queue_vm_open(struct vm_area_struct *vma) -{ - struct isp_video_buffer *buf = vma->vm_private_data; - - buf->vma_use_count++; -} - -static void isp_video_queue_vm_close(struct vm_area_struct *vma) -{ - struct isp_video_buffer *buf = vma->vm_private_data; - - buf->vma_use_count--; -} - -static const struct vm_operations_struct isp_video_queue_vm_ops = { - .open = isp_video_queue_vm_open, - .close = isp_video_queue_vm_close, -}; - -/** - * omap3isp_video_queue_mmap - Map buffers to userspace - * - * This function is intended to be used as an mmap() file operation handler. It - * maps a buffer to userspace based on the VMA offset. - * - * Only buffers of memory type MMAP are supported. - */ -int omap3isp_video_queue_mmap(struct isp_video_queue *queue, - struct vm_area_struct *vma) -{ - struct isp_video_buffer *uninitialized_var(buf); - unsigned long size; - unsigned int i; - int ret = 0; - - mutex_lock(&queue->lock); - - for (i = 0; i < queue->count; ++i) { - buf = queue->buffers[i]; - if ((buf->vbuf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - - if (i == queue->count) { - ret = -EINVAL; - goto done; - } - - size = vma->vm_end - vma->vm_start; - - if (buf->vbuf.memory != V4L2_MEMORY_MMAP || - size != PAGE_ALIGN(buf->vbuf.length)) { - ret = -EINVAL; - goto done; - } - - ret = remap_vmalloc_range(vma, buf->vaddr, 0); - if (ret < 0) - goto done; - - vma->vm_ops = &isp_video_queue_vm_ops; - vma->vm_private_data = buf; - isp_video_queue_vm_open(vma); - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_poll - Poll video queue state - * - * This function is intended to be used as a poll() file operation handler. It - * polls the state of the video buffer at the front of the queue and returns an - * events mask. - * - * If no buffer is present at the front of the queue, POLLERR is returned. - */ -unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue, - struct file *file, poll_table *wait) -{ - struct isp_video_buffer *buf; - unsigned int mask = 0; - - mutex_lock(&queue->lock); - if (list_empty(&queue->queue)) { - mask |= POLLERR; - goto done; - } - buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream); - - poll_wait(file, &buf->wait, wait); - if (buf->state == ISP_BUF_STATE_DONE || - buf->state == ISP_BUF_STATE_ERROR) { - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - mask |= POLLIN | POLLRDNORM; - else - mask |= POLLOUT | POLLWRNORM; - } - -done: - mutex_unlock(&queue->lock); - return mask; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispqueue.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispqueue.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispqueue.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispqueue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -/* - * ispqueue.h - * - * TI OMAP3 ISP - Video buffers queue handling - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_QUEUE_H -#define OMAP3_ISP_QUEUE_H - -#include -#include -#include -#include -#include - -struct isp_video_queue; -struct page; -struct scatterlist; - -#define ISP_VIDEO_MAX_BUFFERS 16 - -/** - * enum isp_video_buffer_state - ISP video buffer state - * @ISP_BUF_STATE_IDLE: The buffer is under userspace control (dequeued - * or not queued yet). - * @ISP_BUF_STATE_QUEUED: The buffer has been queued but isn't used by the - * device yet. - * @ISP_BUF_STATE_ACTIVE: The buffer is in use for an active video transfer. - * @ISP_BUF_STATE_ERROR: The device is done with the buffer and an error - * occured. For capture device the buffer likely contains corrupted data or - * no data at all. - * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occured. - * For capture devices the buffer contains valid data. - */ -enum isp_video_buffer_state { - ISP_BUF_STATE_IDLE, - ISP_BUF_STATE_QUEUED, - ISP_BUF_STATE_ACTIVE, - ISP_BUF_STATE_ERROR, - ISP_BUF_STATE_DONE, -}; - -/** - * struct isp_video_buffer - ISP video buffer - * @vma_use_count: Number of times the buffer is mmap'ed to userspace - * @stream: List head for insertion into main queue - * @queue: ISP buffers queue this buffer belongs to - * @prepared: Whether the buffer has been prepared - * @skip_cache: Whether to skip cache management operations for this buffer - * @vaddr: Memory virtual address (for kernel buffers) - * @vm_flags: Buffer VMA flags (for userspace buffers) - * @offset: Offset inside the first page (for userspace buffers) - * @npages: Number of pages (for userspace buffers) - * @pages: Pages table (for userspace non-VM_PFNMAP buffers) - * @paddr: Memory physical address (for userspace VM_PFNMAP buffers) - * @sglen: Number of elements in the scatter list (for non-VM_PFNMAP buffers) - * @sglist: Scatter list (for non-VM_PFNMAP buffers) - * @vbuf: V4L2 buffer - * @irqlist: List head for insertion into IRQ queue - * @state: Current buffer state - * @wait: Wait queue to signal buffer completion - */ -struct isp_video_buffer { - unsigned long vma_use_count; - struct list_head stream; - struct isp_video_queue *queue; - unsigned int prepared:1; - bool skip_cache; - - /* For kernel buffers. */ - void *vaddr; - - /* For userspace buffers. */ - unsigned long vm_flags; - unsigned long offset; - unsigned int npages; - struct page **pages; - dma_addr_t paddr; - - /* For all buffers except VM_PFNMAP. */ - unsigned int sglen; - struct scatterlist *sglist; - - /* Touched by the interrupt handler. */ - struct v4l2_buffer vbuf; - struct list_head irqlist; - enum isp_video_buffer_state state; - wait_queue_head_t wait; -}; - -#define to_isp_video_buffer(vb) container_of(vb, struct isp_video_buffer, vb) - -/** - * struct isp_video_queue_operations - Driver-specific operations - * @queue_prepare: Called before allocating buffers. Drivers should clamp the - * number of buffers according to their requirements, and must return the - * buffer size in bytes. - * @buffer_prepare: Called the first time a buffer is queued, or after changing - * the userspace memory address for a USERPTR buffer, with the queue lock - * held. Drivers should perform device-specific buffer preparation (such as - * mapping the buffer memory in an IOMMU). This operation is optional. - * @buffer_queue: Called when a buffer is being added to the queue with the - * queue irqlock spinlock held. - * @buffer_cleanup: Called before freeing buffers, or before changing the - * userspace memory address for a USERPTR buffer, with the queue lock held. - * Drivers must perform cleanup operations required to undo the - * buffer_prepare call. This operation is optional. - */ -struct isp_video_queue_operations { - void (*queue_prepare)(struct isp_video_queue *queue, - unsigned int *nbuffers, unsigned int *size); - int (*buffer_prepare)(struct isp_video_buffer *buf); - void (*buffer_queue)(struct isp_video_buffer *buf); - void (*buffer_cleanup)(struct isp_video_buffer *buf); -}; - -/** - * struct isp_video_queue - ISP video buffers queue - * @type: Type of video buffers handled by this queue - * @ops: Queue operations - * @dev: Device used for DMA operations - * @bufsize: Size of a driver-specific buffer object - * @count: Number of currently allocated buffers - * @buffers: ISP video buffers - * @lock: Mutex to protect access to the buffers, main queue and state - * @irqlock: Spinlock to protect access to the IRQ queue - * @streaming: Queue state, indicates whether the queue is streaming - * @queue: List of all queued buffers - */ -struct isp_video_queue { - enum v4l2_buf_type type; - const struct isp_video_queue_operations *ops; - struct device *dev; - unsigned int bufsize; - - unsigned int count; - struct isp_video_buffer *buffers[ISP_VIDEO_MAX_BUFFERS]; - struct mutex lock; - spinlock_t irqlock; - - unsigned int streaming:1; - - struct list_head queue; -}; - -int omap3isp_video_queue_cleanup(struct isp_video_queue *queue); -int omap3isp_video_queue_init(struct isp_video_queue *queue, - enum v4l2_buf_type type, - const struct isp_video_queue_operations *ops, - struct device *dev, unsigned int bufsize); - -int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue, - struct v4l2_requestbuffers *rb); -int omap3isp_video_queue_querybuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf); -int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf); -int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf, int nonblocking); -int omap3isp_video_queue_streamon(struct isp_video_queue *queue); -void omap3isp_video_queue_streamoff(struct isp_video_queue *queue); -void omap3isp_video_queue_discard_done(struct isp_video_queue *queue); -int omap3isp_video_queue_mmap(struct isp_video_queue *queue, - struct vm_area_struct *vma); -unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue, - struct file *file, poll_table *wait); - -#endif /* OMAP3_ISP_QUEUE_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispreg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispreg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispreg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispreg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1589 +0,0 @@ -/* - * ispreg.h - * - * TI OMAP3 ISP - Registers definitions - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_REG_H -#define OMAP3_ISP_REG_H - -#include - - -#define CM_CAM_MCLK_HZ 172800000 /* Hz */ - -/* ISP Submodules offset */ - -#define OMAP3ISP_REG_BASE OMAP3430_ISP_BASE -#define OMAP3ISP_REG(offset) (OMAP3ISP_REG_BASE + (offset)) - -#define OMAP3ISP_CCP2_REG_OFFSET 0x0400 -#define OMAP3ISP_CCP2_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CCP2_REG_OFFSET) -#define OMAP3ISP_CCP2_REG(offset) (OMAP3ISP_CCP2_REG_BASE + (offset)) - -#define OMAP3ISP_CCDC_REG_OFFSET 0x0600 -#define OMAP3ISP_CCDC_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CCDC_REG_OFFSET) -#define OMAP3ISP_CCDC_REG(offset) (OMAP3ISP_CCDC_REG_BASE + (offset)) - -#define OMAP3ISP_HIST_REG_OFFSET 0x0A00 -#define OMAP3ISP_HIST_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_HIST_REG_OFFSET) -#define OMAP3ISP_HIST_REG(offset) (OMAP3ISP_HIST_REG_BASE + (offset)) - -#define OMAP3ISP_H3A_REG_OFFSET 0x0C00 -#define OMAP3ISP_H3A_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_H3A_REG_OFFSET) -#define OMAP3ISP_H3A_REG(offset) (OMAP3ISP_H3A_REG_BASE + (offset)) - -#define OMAP3ISP_PREV_REG_OFFSET 0x0E00 -#define OMAP3ISP_PREV_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_PREV_REG_OFFSET) -#define OMAP3ISP_PREV_REG(offset) (OMAP3ISP_PREV_REG_BASE + (offset)) - -#define OMAP3ISP_RESZ_REG_OFFSET 0x1000 -#define OMAP3ISP_RESZ_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_RESZ_REG_OFFSET) -#define OMAP3ISP_RESZ_REG(offset) (OMAP3ISP_RESZ_REG_BASE + (offset)) - -#define OMAP3ISP_SBL_REG_OFFSET 0x1200 -#define OMAP3ISP_SBL_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_SBL_REG_OFFSET) -#define OMAP3ISP_SBL_REG(offset) (OMAP3ISP_SBL_REG_BASE + (offset)) - -#define OMAP3ISP_CSI2A_REGS1_REG_OFFSET 0x1800 -#define OMAP3ISP_CSI2A_REGS1_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSI2A_REGS1_REG_OFFSET) -#define OMAP3ISP_CSI2A_REGS1_REG(offset) \ - (OMAP3ISP_CSI2A_REGS1_REG_BASE + (offset)) - -#define OMAP3ISP_CSIPHY2_REG_OFFSET 0x1970 -#define OMAP3ISP_CSIPHY2_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSIPHY2_REG_OFFSET) -#define OMAP3ISP_CSIPHY2_REG(offset) (OMAP3ISP_CSIPHY2_REG_BASE + (offset)) - -#define OMAP3ISP_CSI2A_REGS2_REG_OFFSET 0x19C0 -#define OMAP3ISP_CSI2A_REGS2_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSI2A_REGS2_REG_OFFSET) -#define OMAP3ISP_CSI2A_REGS2_REG(offset) \ - (OMAP3ISP_CSI2A_REGS2_REG_BASE + (offset)) - -#define OMAP3ISP_CSI2C_REGS1_REG_OFFSET 0x1C00 -#define OMAP3ISP_CSI2C_REGS1_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSI2C_REGS1_REG_OFFSET) -#define OMAP3ISP_CSI2C_REGS1_REG(offset) \ - (OMAP3ISP_CSI2C_REGS1_REG_BASE + (offset)) - -#define OMAP3ISP_CSIPHY1_REG_OFFSET 0x1D70 -#define OMAP3ISP_CSIPHY1_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSIPHY1_REG_OFFSET) -#define OMAP3ISP_CSIPHY1_REG(offset) (OMAP3ISP_CSIPHY1_REG_BASE + (offset)) - -#define OMAP3ISP_CSI2C_REGS2_REG_OFFSET 0x1DC0 -#define OMAP3ISP_CSI2C_REGS2_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSI2C_REGS2_REG_OFFSET) -#define OMAP3ISP_CSI2C_REGS2_REG(offset) \ - (OMAP3ISP_CSI2C_REGS2_REG_BASE + (offset)) - -/* ISP module register offset */ - -#define ISP_REVISION (0x000) -#define ISP_SYSCONFIG (0x004) -#define ISP_SYSSTATUS (0x008) -#define ISP_IRQ0ENABLE (0x00C) -#define ISP_IRQ0STATUS (0x010) -#define ISP_IRQ1ENABLE (0x014) -#define ISP_IRQ1STATUS (0x018) -#define ISP_TCTRL_GRESET_LENGTH (0x030) -#define ISP_TCTRL_PSTRB_REPLAY (0x034) -#define ISP_CTRL (0x040) -#define ISP_SECURE (0x044) -#define ISP_TCTRL_CTRL (0x050) -#define ISP_TCTRL_FRAME (0x054) -#define ISP_TCTRL_PSTRB_DELAY (0x058) -#define ISP_TCTRL_STRB_DELAY (0x05C) -#define ISP_TCTRL_SHUT_DELAY (0x060) -#define ISP_TCTRL_PSTRB_LENGTH (0x064) -#define ISP_TCTRL_STRB_LENGTH (0x068) -#define ISP_TCTRL_SHUT_LENGTH (0x06C) -#define ISP_PING_PONG_ADDR (0x070) -#define ISP_PING_PONG_MEM_RANGE (0x074) -#define ISP_PING_PONG_BUF_SIZE (0x078) - -/* CCP2 receiver registers */ - -#define ISPCCP2_REVISION (0x000) -#define ISPCCP2_SYSCONFIG (0x004) -#define ISPCCP2_SYSCONFIG_SOFT_RESET (1 << 1) -#define ISPCCP2_SYSCONFIG_AUTO_IDLE 0x1 -#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT 12 -#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_FORCE \ - (0x0 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT) -#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_NO \ - (0x1 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT) -#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART \ - (0x2 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT) -#define ISPCCP2_SYSSTATUS (0x008) -#define ISPCCP2_SYSSTATUS_RESET_DONE (1 << 0) -#define ISPCCP2_LC01_IRQENABLE (0x00C) -#define ISPCCP2_LC01_IRQSTATUS (0x010) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ (1 << 11) -#define ISPCCP2_LC01_IRQSTATUS_LC0_LE_IRQ (1 << 10) -#define ISPCCP2_LC01_IRQSTATUS_LC0_LS_IRQ (1 << 9) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FE_IRQ (1 << 8) -#define ISPCCP2_LC01_IRQSTATUS_LC0_COUNT_IRQ (1 << 7) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ (1 << 5) -#define ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ (1 << 4) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ (1 << 3) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ (1 << 2) -#define ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ (1 << 1) -#define ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ (1 << 0) - -#define ISPCCP2_LC23_IRQENABLE (0x014) -#define ISPCCP2_LC23_IRQSTATUS (0x018) -#define ISPCCP2_LCM_IRQENABLE (0x02C) -#define ISPCCP2_LCM_IRQSTATUS_EOF_IRQ (1 << 0) -#define ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ (1 << 1) -#define ISPCCP2_LCM_IRQSTATUS (0x030) -#define ISPCCP2_CTRL (0x040) -#define ISPCCP2_CTRL_IF_EN (1 << 0) -#define ISPCCP2_CTRL_PHY_SEL (1 << 1) -#define ISPCCP2_CTRL_PHY_SEL_CLOCK (0 << 1) -#define ISPCCP2_CTRL_PHY_SEL_STROBE (1 << 1) -#define ISPCCP2_CTRL_PHY_SEL_MASK 0x1 -#define ISPCCP2_CTRL_PHY_SEL_SHIFT 1 -#define ISPCCP2_CTRL_IO_OUT_SEL (1 << 2) -#define ISPCCP2_CTRL_MODE (1 << 4) -#define ISPCCP2_CTRL_VP_CLK_FORCE_ON (1 << 9) -#define ISPCCP2_CTRL_INV (1 << 10) -#define ISPCCP2_CTRL_INV_MASK 0x1 -#define ISPCCP2_CTRL_INV_SHIFT 10 -#define ISPCCP2_CTRL_VP_ONLY_EN (1 << 11) -#define ISPCCP2_CTRL_VP_CLK_POL (1 << 12) -#define ISPCCP2_CTRL_VPCLK_DIV_SHIFT 15 -#define ISPCCP2_CTRL_VPCLK_DIV_MASK 0x1ffff /* [31:15] */ -#define ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT 8 /* 3430 bits */ -#define ISPCCP2_CTRL_VP_OUT_CTRL_MASK 0x3 /* 3430 bits */ -#define ISPCCP2_DBG (0x044) -#define ISPCCP2_GNQ (0x048) -#define ISPCCP2_LCx_CTRL(x) ((0x050)+0x30*(x)) -#define ISPCCP2_LCx_CTRL_CHAN_EN (1 << 0) -#define ISPCCP2_LCx_CTRL_CRC_EN (1 << 19) -#define ISPCCP2_LCx_CTRL_CRC_MASK 0x1 -#define ISPCCP2_LCx_CTRL_CRC_SHIFT 2 -#define ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0 19 -#define ISPCCP2_LCx_CTRL_REGION_EN (1 << 1) -#define ISPCCP2_LCx_CTRL_REGION_MASK 0x1 -#define ISPCCP2_LCx_CTRL_REGION_SHIFT 1 -#define ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0 0x3f -#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0 0x2 -#define ISPCCP2_LCx_CTRL_FORMAT_MASK 0x1f -#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT 0x3 -#define ISPCCP2_LCx_CODE(x) ((0x054)+0x30*(x)) -#define ISPCCP2_LCx_STAT_START(x) ((0x058)+0x30*(x)) -#define ISPCCP2_LCx_STAT_SIZE(x) ((0x05C)+0x30*(x)) -#define ISPCCP2_LCx_SOF_ADDR(x) ((0x060)+0x30*(x)) -#define ISPCCP2_LCx_EOF_ADDR(x) ((0x064)+0x30*(x)) -#define ISPCCP2_LCx_DAT_START(x) ((0x068)+0x30*(x)) -#define ISPCCP2_LCx_DAT_SIZE(x) ((0x06C)+0x30*(x)) -#define ISPCCP2_LCx_DAT_MASK 0xFFF -#define ISPCCP2_LCx_DAT_SHIFT 16 -#define ISPCCP2_LCx_DAT_PING_ADDR(x) ((0x070)+0x30*(x)) -#define ISPCCP2_LCx_DAT_PONG_ADDR(x) ((0x074)+0x30*(x)) -#define ISPCCP2_LCx_DAT_OFST(x) ((0x078)+0x30*(x)) -#define ISPCCP2_LCM_CTRL (0x1D0) -#define ISPCCP2_LCM_CTRL_CHAN_EN (1 << 0) -#define ISPCCP2_LCM_CTRL_DST_PORT (1 << 2) -#define ISPCCP2_LCM_CTRL_DST_PORT_SHIFT 2 -#define ISPCCP2_LCM_CTRL_READ_THROTTLE_SHIFT 3 -#define ISPCCP2_LCM_CTRL_READ_THROTTLE_MASK 0x11 -#define ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT 5 -#define ISPCCP2_LCM_CTRL_BURST_SIZE_MASK 0x7 -#define ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT 16 -#define ISPCCP2_LCM_CTRL_SRC_FORMAT_MASK 0x7 -#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT 20 -#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_MASK 0x3 -#define ISPCCP2_LCM_CTRL_SRC_DPCM_PRED (1 << 22) -#define ISPCCP2_LCM_CTRL_SRC_PACK (1 << 23) -#define ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT 24 -#define ISPCCP2_LCM_CTRL_DST_FORMAT_MASK 0x7 -#define ISPCCP2_LCM_VSIZE (0x1D4) -#define ISPCCP2_LCM_VSIZE_SHIFT 16 -#define ISPCCP2_LCM_HSIZE (0x1D8) -#define ISPCCP2_LCM_HSIZE_SHIFT 16 -#define ISPCCP2_LCM_PREFETCH (0x1DC) -#define ISPCCP2_LCM_PREFETCH_SHIFT 3 -#define ISPCCP2_LCM_SRC_ADDR (0x1E0) -#define ISPCCP2_LCM_SRC_OFST (0x1E4) -#define ISPCCP2_LCM_DST_ADDR (0x1E8) -#define ISPCCP2_LCM_DST_OFST (0x1EC) - -/* CCDC module register offset */ - -#define ISPCCDC_PID (0x000) -#define ISPCCDC_PCR (0x004) -#define ISPCCDC_SYN_MODE (0x008) -#define ISPCCDC_HD_VD_WID (0x00C) -#define ISPCCDC_PIX_LINES (0x010) -#define ISPCCDC_HORZ_INFO (0x014) -#define ISPCCDC_VERT_START (0x018) -#define ISPCCDC_VERT_LINES (0x01C) -#define ISPCCDC_CULLING (0x020) -#define ISPCCDC_HSIZE_OFF (0x024) -#define ISPCCDC_SDOFST (0x028) -#define ISPCCDC_SDR_ADDR (0x02C) -#define ISPCCDC_CLAMP (0x030) -#define ISPCCDC_DCSUB (0x034) -#define ISPCCDC_COLPTN (0x038) -#define ISPCCDC_BLKCMP (0x03C) -#define ISPCCDC_FPC (0x040) -#define ISPCCDC_FPC_ADDR (0x044) -#define ISPCCDC_VDINT (0x048) -#define ISPCCDC_ALAW (0x04C) -#define ISPCCDC_REC656IF (0x050) -#define ISPCCDC_CFG (0x054) -#define ISPCCDC_FMTCFG (0x058) -#define ISPCCDC_FMT_HORZ (0x05C) -#define ISPCCDC_FMT_VERT (0x060) -#define ISPCCDC_FMT_ADDR0 (0x064) -#define ISPCCDC_FMT_ADDR1 (0x068) -#define ISPCCDC_FMT_ADDR2 (0x06C) -#define ISPCCDC_FMT_ADDR3 (0x070) -#define ISPCCDC_FMT_ADDR4 (0x074) -#define ISPCCDC_FMT_ADDR5 (0x078) -#define ISPCCDC_FMT_ADDR6 (0x07C) -#define ISPCCDC_FMT_ADDR7 (0x080) -#define ISPCCDC_PRGEVEN0 (0x084) -#define ISPCCDC_PRGEVEN1 (0x088) -#define ISPCCDC_PRGODD0 (0x08C) -#define ISPCCDC_PRGODD1 (0x090) -#define ISPCCDC_VP_OUT (0x094) - -#define ISPCCDC_LSC_CONFIG (0x098) -#define ISPCCDC_LSC_INITIAL (0x09C) -#define ISPCCDC_LSC_TABLE_BASE (0x0A0) -#define ISPCCDC_LSC_TABLE_OFFSET (0x0A4) - -/* SBL */ -#define ISPSBL_PCR 0x4 -#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF (1 << 16) -#define ISPSBL_PCR_H3A_AF_WBL_OVF (1 << 17) -#define ISPSBL_PCR_RSZ4_WBL_OVF (1 << 18) -#define ISPSBL_PCR_RSZ3_WBL_OVF (1 << 19) -#define ISPSBL_PCR_RSZ2_WBL_OVF (1 << 20) -#define ISPSBL_PCR_RSZ1_WBL_OVF (1 << 21) -#define ISPSBL_PCR_PRV_WBL_OVF (1 << 22) -#define ISPSBL_PCR_CCDC_WBL_OVF (1 << 23) -#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF (1 << 24) -#define ISPSBL_PCR_CSIA_WBL_OVF (1 << 25) -#define ISPSBL_PCR_CSIB_WBL_OVF (1 << 26) -#define ISPSBL_CCDC_WR_0 (0x028) -#define ISPSBL_CCDC_WR_0_DATA_READY (1 << 21) -#define ISPSBL_CCDC_WR_1 (0x02C) -#define ISPSBL_CCDC_WR_2 (0x030) -#define ISPSBL_CCDC_WR_3 (0x034) - -#define ISPSBL_SDR_REQ_EXP 0xF8 -#define ISPSBL_SDR_REQ_HIST_EXP_SHIFT 0 -#define ISPSBL_SDR_REQ_HIST_EXP_MASK (0x3FF) -#define ISPSBL_SDR_REQ_RSZ_EXP_SHIFT 10 -#define ISPSBL_SDR_REQ_RSZ_EXP_MASK (0x3FF << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT) -#define ISPSBL_SDR_REQ_PRV_EXP_SHIFT 20 -#define ISPSBL_SDR_REQ_PRV_EXP_MASK (0x3FF << ISPSBL_SDR_REQ_PRV_EXP_SHIFT) - -/* Histogram registers */ -#define ISPHIST_PID (0x000) -#define ISPHIST_PCR (0x004) -#define ISPHIST_CNT (0x008) -#define ISPHIST_WB_GAIN (0x00C) -#define ISPHIST_R0_HORZ (0x010) -#define ISPHIST_R0_VERT (0x014) -#define ISPHIST_R1_HORZ (0x018) -#define ISPHIST_R1_VERT (0x01C) -#define ISPHIST_R2_HORZ (0x020) -#define ISPHIST_R2_VERT (0x024) -#define ISPHIST_R3_HORZ (0x028) -#define ISPHIST_R3_VERT (0x02C) -#define ISPHIST_ADDR (0x030) -#define ISPHIST_DATA (0x034) -#define ISPHIST_RADD (0x038) -#define ISPHIST_RADD_OFF (0x03C) -#define ISPHIST_H_V_INFO (0x040) - -/* H3A module registers */ -#define ISPH3A_PID (0x000) -#define ISPH3A_PCR (0x004) -#define ISPH3A_AEWWIN1 (0x04C) -#define ISPH3A_AEWINSTART (0x050) -#define ISPH3A_AEWINBLK (0x054) -#define ISPH3A_AEWSUBWIN (0x058) -#define ISPH3A_AEWBUFST (0x05C) -#define ISPH3A_AFPAX1 (0x008) -#define ISPH3A_AFPAX2 (0x00C) -#define ISPH3A_AFPAXSTART (0x010) -#define ISPH3A_AFIIRSH (0x014) -#define ISPH3A_AFBUFST (0x018) -#define ISPH3A_AFCOEF010 (0x01C) -#define ISPH3A_AFCOEF032 (0x020) -#define ISPH3A_AFCOEF054 (0x024) -#define ISPH3A_AFCOEF076 (0x028) -#define ISPH3A_AFCOEF098 (0x02C) -#define ISPH3A_AFCOEF0010 (0x030) -#define ISPH3A_AFCOEF110 (0x034) -#define ISPH3A_AFCOEF132 (0x038) -#define ISPH3A_AFCOEF154 (0x03C) -#define ISPH3A_AFCOEF176 (0x040) -#define ISPH3A_AFCOEF198 (0x044) -#define ISPH3A_AFCOEF1010 (0x048) - -#define ISPPRV_PCR (0x004) -#define ISPPRV_HORZ_INFO (0x008) -#define ISPPRV_VERT_INFO (0x00C) -#define ISPPRV_RSDR_ADDR (0x010) -#define ISPPRV_RADR_OFFSET (0x014) -#define ISPPRV_DSDR_ADDR (0x018) -#define ISPPRV_DRKF_OFFSET (0x01C) -#define ISPPRV_WSDR_ADDR (0x020) -#define ISPPRV_WADD_OFFSET (0x024) -#define ISPPRV_AVE (0x028) -#define ISPPRV_HMED (0x02C) -#define ISPPRV_NF (0x030) -#define ISPPRV_WB_DGAIN (0x034) -#define ISPPRV_WBGAIN (0x038) -#define ISPPRV_WBSEL (0x03C) -#define ISPPRV_CFA (0x040) -#define ISPPRV_BLKADJOFF (0x044) -#define ISPPRV_RGB_MAT1 (0x048) -#define ISPPRV_RGB_MAT2 (0x04C) -#define ISPPRV_RGB_MAT3 (0x050) -#define ISPPRV_RGB_MAT4 (0x054) -#define ISPPRV_RGB_MAT5 (0x058) -#define ISPPRV_RGB_OFF1 (0x05C) -#define ISPPRV_RGB_OFF2 (0x060) -#define ISPPRV_CSC0 (0x064) -#define ISPPRV_CSC1 (0x068) -#define ISPPRV_CSC2 (0x06C) -#define ISPPRV_CSC_OFFSET (0x070) -#define ISPPRV_CNT_BRT (0x074) -#define ISPPRV_CSUP (0x078) -#define ISPPRV_SETUP_YC (0x07C) -#define ISPPRV_SET_TBL_ADDR (0x080) -#define ISPPRV_SET_TBL_DATA (0x084) -#define ISPPRV_CDC_THR0 (0x090) -#define ISPPRV_CDC_THR1 (ISPPRV_CDC_THR0 + (0x4)) -#define ISPPRV_CDC_THR2 (ISPPRV_CDC_THR0 + (0x4) * 2) -#define ISPPRV_CDC_THR3 (ISPPRV_CDC_THR0 + (0x4) * 3) - -#define ISPPRV_REDGAMMA_TABLE_ADDR 0x0000 -#define ISPPRV_GREENGAMMA_TABLE_ADDR 0x0400 -#define ISPPRV_BLUEGAMMA_TABLE_ADDR 0x0800 -#define ISPPRV_NF_TABLE_ADDR 0x0C00 -#define ISPPRV_YENH_TABLE_ADDR 0x1000 -#define ISPPRV_CFA_TABLE_ADDR 0x1400 - -#define ISPPRV_MAXOUTPUT_WIDTH 1280 -#define ISPPRV_MAXOUTPUT_WIDTH_ES2 3300 -#define ISPPRV_MAXOUTPUT_WIDTH_3630 4096 -#define ISPRSZ_MIN_OUTPUT 64 -#define ISPRSZ_MAX_OUTPUT 3312 - -/* Resizer module register offset */ -#define ISPRSZ_PID (0x000) -#define ISPRSZ_PCR (0x004) -#define ISPRSZ_CNT (0x008) -#define ISPRSZ_OUT_SIZE (0x00C) -#define ISPRSZ_IN_START (0x010) -#define ISPRSZ_IN_SIZE (0x014) -#define ISPRSZ_SDR_INADD (0x018) -#define ISPRSZ_SDR_INOFF (0x01C) -#define ISPRSZ_SDR_OUTADD (0x020) -#define ISPRSZ_SDR_OUTOFF (0x024) -#define ISPRSZ_HFILT10 (0x028) -#define ISPRSZ_HFILT32 (0x02C) -#define ISPRSZ_HFILT54 (0x030) -#define ISPRSZ_HFILT76 (0x034) -#define ISPRSZ_HFILT98 (0x038) -#define ISPRSZ_HFILT1110 (0x03C) -#define ISPRSZ_HFILT1312 (0x040) -#define ISPRSZ_HFILT1514 (0x044) -#define ISPRSZ_HFILT1716 (0x048) -#define ISPRSZ_HFILT1918 (0x04C) -#define ISPRSZ_HFILT2120 (0x050) -#define ISPRSZ_HFILT2322 (0x054) -#define ISPRSZ_HFILT2524 (0x058) -#define ISPRSZ_HFILT2726 (0x05C) -#define ISPRSZ_HFILT2928 (0x060) -#define ISPRSZ_HFILT3130 (0x064) -#define ISPRSZ_VFILT10 (0x068) -#define ISPRSZ_VFILT32 (0x06C) -#define ISPRSZ_VFILT54 (0x070) -#define ISPRSZ_VFILT76 (0x074) -#define ISPRSZ_VFILT98 (0x078) -#define ISPRSZ_VFILT1110 (0x07C) -#define ISPRSZ_VFILT1312 (0x080) -#define ISPRSZ_VFILT1514 (0x084) -#define ISPRSZ_VFILT1716 (0x088) -#define ISPRSZ_VFILT1918 (0x08C) -#define ISPRSZ_VFILT2120 (0x090) -#define ISPRSZ_VFILT2322 (0x094) -#define ISPRSZ_VFILT2524 (0x098) -#define ISPRSZ_VFILT2726 (0x09C) -#define ISPRSZ_VFILT2928 (0x0A0) -#define ISPRSZ_VFILT3130 (0x0A4) -#define ISPRSZ_YENH (0x0A8) - -#define ISP_INT_CLR 0xFF113F11 -#define ISPPRV_PCR_EN 1 -#define ISPPRV_PCR_BUSY (1 << 1) -#define ISPPRV_PCR_SOURCE (1 << 2) -#define ISPPRV_PCR_ONESHOT (1 << 3) -#define ISPPRV_PCR_WIDTH (1 << 4) -#define ISPPRV_PCR_INVALAW (1 << 5) -#define ISPPRV_PCR_DRKFEN (1 << 6) -#define ISPPRV_PCR_DRKFCAP (1 << 7) -#define ISPPRV_PCR_HMEDEN (1 << 8) -#define ISPPRV_PCR_NFEN (1 << 9) -#define ISPPRV_PCR_CFAEN (1 << 10) -#define ISPPRV_PCR_CFAFMT_SHIFT 11 -#define ISPPRV_PCR_CFAFMT_MASK 0x7800 -#define ISPPRV_PCR_CFAFMT_BAYER (0 << 11) -#define ISPPRV_PCR_CFAFMT_SONYVGA (1 << 11) -#define ISPPRV_PCR_CFAFMT_RGBFOVEON (2 << 11) -#define ISPPRV_PCR_CFAFMT_DNSPL (3 << 11) -#define ISPPRV_PCR_CFAFMT_HONEYCOMB (4 << 11) -#define ISPPRV_PCR_CFAFMT_RRGGBBFOVEON (5 << 11) -#define ISPPRV_PCR_YNENHEN (1 << 15) -#define ISPPRV_PCR_SUPEN (1 << 16) -#define ISPPRV_PCR_YCPOS_SHIFT 17 -#define ISPPRV_PCR_YCPOS_YCrYCb (0 << 17) -#define ISPPRV_PCR_YCPOS_YCbYCr (1 << 17) -#define ISPPRV_PCR_YCPOS_CbYCrY (2 << 17) -#define ISPPRV_PCR_YCPOS_CrYCbY (3 << 17) -#define ISPPRV_PCR_RSZPORT (1 << 19) -#define ISPPRV_PCR_SDRPORT (1 << 20) -#define ISPPRV_PCR_SCOMP_EN (1 << 21) -#define ISPPRV_PCR_SCOMP_SFT_SHIFT (22) -#define ISPPRV_PCR_SCOMP_SFT_MASK (7 << 22) -#define ISPPRV_PCR_GAMMA_BYPASS (1 << 26) -#define ISPPRV_PCR_DCOREN (1 << 27) -#define ISPPRV_PCR_DCCOUP (1 << 28) -#define ISPPRV_PCR_DRK_FAIL (1 << 31) - -#define ISPPRV_HORZ_INFO_EPH_SHIFT 0 -#define ISPPRV_HORZ_INFO_EPH_MASK 0x3fff -#define ISPPRV_HORZ_INFO_SPH_SHIFT 16 -#define ISPPRV_HORZ_INFO_SPH_MASK 0x3fff0 - -#define ISPPRV_VERT_INFO_ELV_SHIFT 0 -#define ISPPRV_VERT_INFO_ELV_MASK 0x3fff -#define ISPPRV_VERT_INFO_SLV_SHIFT 16 -#define ISPPRV_VERT_INFO_SLV_MASK 0x3fff0 - -#define ISPPRV_AVE_EVENDIST_SHIFT 2 -#define ISPPRV_AVE_EVENDIST_1 0x0 -#define ISPPRV_AVE_EVENDIST_2 0x1 -#define ISPPRV_AVE_EVENDIST_3 0x2 -#define ISPPRV_AVE_EVENDIST_4 0x3 -#define ISPPRV_AVE_ODDDIST_SHIFT 4 -#define ISPPRV_AVE_ODDDIST_1 0x0 -#define ISPPRV_AVE_ODDDIST_2 0x1 -#define ISPPRV_AVE_ODDDIST_3 0x2 -#define ISPPRV_AVE_ODDDIST_4 0x3 - -#define ISPPRV_HMED_THRESHOLD_SHIFT 0 -#define ISPPRV_HMED_EVENDIST (1 << 8) -#define ISPPRV_HMED_ODDDIST (1 << 9) - -#define ISPPRV_WBGAIN_COEF0_SHIFT 0 -#define ISPPRV_WBGAIN_COEF1_SHIFT 8 -#define ISPPRV_WBGAIN_COEF2_SHIFT 16 -#define ISPPRV_WBGAIN_COEF3_SHIFT 24 - -#define ISPPRV_WBSEL_COEF0 0x0 -#define ISPPRV_WBSEL_COEF1 0x1 -#define ISPPRV_WBSEL_COEF2 0x2 -#define ISPPRV_WBSEL_COEF3 0x3 - -#define ISPPRV_WBSEL_N0_0_SHIFT 0 -#define ISPPRV_WBSEL_N0_1_SHIFT 2 -#define ISPPRV_WBSEL_N0_2_SHIFT 4 -#define ISPPRV_WBSEL_N0_3_SHIFT 6 -#define ISPPRV_WBSEL_N1_0_SHIFT 8 -#define ISPPRV_WBSEL_N1_1_SHIFT 10 -#define ISPPRV_WBSEL_N1_2_SHIFT 12 -#define ISPPRV_WBSEL_N1_3_SHIFT 14 -#define ISPPRV_WBSEL_N2_0_SHIFT 16 -#define ISPPRV_WBSEL_N2_1_SHIFT 18 -#define ISPPRV_WBSEL_N2_2_SHIFT 20 -#define ISPPRV_WBSEL_N2_3_SHIFT 22 -#define ISPPRV_WBSEL_N3_0_SHIFT 24 -#define ISPPRV_WBSEL_N3_1_SHIFT 26 -#define ISPPRV_WBSEL_N3_2_SHIFT 28 -#define ISPPRV_WBSEL_N3_3_SHIFT 30 - -#define ISPPRV_CFA_GRADTH_HOR_SHIFT 0 -#define ISPPRV_CFA_GRADTH_VER_SHIFT 8 - -#define ISPPRV_BLKADJOFF_B_SHIFT 0 -#define ISPPRV_BLKADJOFF_G_SHIFT 8 -#define ISPPRV_BLKADJOFF_R_SHIFT 16 - -#define ISPPRV_RGB_MAT1_MTX_RR_SHIFT 0 -#define ISPPRV_RGB_MAT1_MTX_GR_SHIFT 16 - -#define ISPPRV_RGB_MAT2_MTX_BR_SHIFT 0 -#define ISPPRV_RGB_MAT2_MTX_RG_SHIFT 16 - -#define ISPPRV_RGB_MAT3_MTX_GG_SHIFT 0 -#define ISPPRV_RGB_MAT3_MTX_BG_SHIFT 16 - -#define ISPPRV_RGB_MAT4_MTX_RB_SHIFT 0 -#define ISPPRV_RGB_MAT4_MTX_GB_SHIFT 16 - -#define ISPPRV_RGB_MAT5_MTX_BB_SHIFT 0 - -#define ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT 0 -#define ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT 16 - -#define ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT 0 - -#define ISPPRV_CSC0_RY_SHIFT 0 -#define ISPPRV_CSC0_GY_SHIFT 10 -#define ISPPRV_CSC0_BY_SHIFT 20 - -#define ISPPRV_CSC1_RCB_SHIFT 0 -#define ISPPRV_CSC1_GCB_SHIFT 10 -#define ISPPRV_CSC1_BCB_SHIFT 20 - -#define ISPPRV_CSC2_RCR_SHIFT 0 -#define ISPPRV_CSC2_GCR_SHIFT 10 -#define ISPPRV_CSC2_BCR_SHIFT 20 - -#define ISPPRV_CSC_OFFSET_CR_SHIFT 0 -#define ISPPRV_CSC_OFFSET_CB_SHIFT 8 -#define ISPPRV_CSC_OFFSET_Y_SHIFT 16 - -#define ISPPRV_CNT_BRT_BRT_SHIFT 0 -#define ISPPRV_CNT_BRT_CNT_SHIFT 8 - -#define ISPPRV_CONTRAST_MAX 0x10 -#define ISPPRV_CONTRAST_MIN 0xFF -#define ISPPRV_BRIGHT_MIN 0x00 -#define ISPPRV_BRIGHT_MAX 0xFF - -#define ISPPRV_CSUP_CSUPG_SHIFT 0 -#define ISPPRV_CSUP_THRES_SHIFT 8 -#define ISPPRV_CSUP_HPYF_SHIFT 16 - -#define ISPPRV_SETUP_YC_MINC_SHIFT 0 -#define ISPPRV_SETUP_YC_MAXC_SHIFT 8 -#define ISPPRV_SETUP_YC_MINY_SHIFT 16 -#define ISPPRV_SETUP_YC_MAXY_SHIFT 24 -#define ISPPRV_YC_MAX 0xFF -#define ISPPRV_YC_MIN 0x0 - -/* Define bit fields within selected registers */ -#define ISP_REVISION_SHIFT 0 - -#define ISP_SYSCONFIG_AUTOIDLE (1 << 0) -#define ISP_SYSCONFIG_SOFTRESET (1 << 1) -#define ISP_SYSCONFIG_MIDLEMODE_SHIFT 12 -#define ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY 0x0 -#define ISP_SYSCONFIG_MIDLEMODE_NOSTANBY 0x1 -#define ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY 0x2 - -#define ISP_SYSSTATUS_RESETDONE 0 - -#define IRQ0ENABLE_CSIA_IRQ (1 << 0) -#define IRQ0ENABLE_CSIC_IRQ (1 << 1) -#define IRQ0ENABLE_CCP2_LCM_IRQ (1 << 3) -#define IRQ0ENABLE_CCP2_LC0_IRQ (1 << 4) -#define IRQ0ENABLE_CCP2_LC1_IRQ (1 << 5) -#define IRQ0ENABLE_CCP2_LC2_IRQ (1 << 6) -#define IRQ0ENABLE_CCP2_LC3_IRQ (1 << 7) -#define IRQ0ENABLE_CSIB_IRQ (IRQ0ENABLE_CCP2_LCM_IRQ | \ - IRQ0ENABLE_CCP2_LC0_IRQ | \ - IRQ0ENABLE_CCP2_LC1_IRQ | \ - IRQ0ENABLE_CCP2_LC2_IRQ | \ - IRQ0ENABLE_CCP2_LC3_IRQ) - -#define IRQ0ENABLE_CCDC_VD0_IRQ (1 << 8) -#define IRQ0ENABLE_CCDC_VD1_IRQ (1 << 9) -#define IRQ0ENABLE_CCDC_VD2_IRQ (1 << 10) -#define IRQ0ENABLE_CCDC_ERR_IRQ (1 << 11) -#define IRQ0ENABLE_H3A_AF_DONE_IRQ (1 << 12) -#define IRQ0ENABLE_H3A_AWB_DONE_IRQ (1 << 13) -#define IRQ0ENABLE_HIST_DONE_IRQ (1 << 16) -#define IRQ0ENABLE_CCDC_LSC_DONE_IRQ (1 << 17) -#define IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ (1 << 18) -#define IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ (1 << 19) -#define IRQ0ENABLE_PRV_DONE_IRQ (1 << 20) -#define IRQ0ENABLE_RSZ_DONE_IRQ (1 << 24) -#define IRQ0ENABLE_OVF_IRQ (1 << 25) -#define IRQ0ENABLE_PING_IRQ (1 << 26) -#define IRQ0ENABLE_PONG_IRQ (1 << 27) -#define IRQ0ENABLE_MMU_ERR_IRQ (1 << 28) -#define IRQ0ENABLE_OCP_ERR_IRQ (1 << 29) -#define IRQ0ENABLE_SEC_ERR_IRQ (1 << 30) -#define IRQ0ENABLE_HS_VS_IRQ (1 << 31) - -#define IRQ0STATUS_CSIA_IRQ (1 << 0) -#define IRQ0STATUS_CSI2C_IRQ (1 << 1) -#define IRQ0STATUS_CCP2_LCM_IRQ (1 << 3) -#define IRQ0STATUS_CCP2_LC0_IRQ (1 << 4) -#define IRQ0STATUS_CSIB_IRQ (IRQ0STATUS_CCP2_LCM_IRQ | \ - IRQ0STATUS_CCP2_LC0_IRQ) - -#define IRQ0STATUS_CSIB_LC1_IRQ (1 << 5) -#define IRQ0STATUS_CSIB_LC2_IRQ (1 << 6) -#define IRQ0STATUS_CSIB_LC3_IRQ (1 << 7) -#define IRQ0STATUS_CCDC_VD0_IRQ (1 << 8) -#define IRQ0STATUS_CCDC_VD1_IRQ (1 << 9) -#define IRQ0STATUS_CCDC_VD2_IRQ (1 << 10) -#define IRQ0STATUS_CCDC_ERR_IRQ (1 << 11) -#define IRQ0STATUS_H3A_AF_DONE_IRQ (1 << 12) -#define IRQ0STATUS_H3A_AWB_DONE_IRQ (1 << 13) -#define IRQ0STATUS_HIST_DONE_IRQ (1 << 16) -#define IRQ0STATUS_CCDC_LSC_DONE_IRQ (1 << 17) -#define IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ (1 << 18) -#define IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ (1 << 19) -#define IRQ0STATUS_PRV_DONE_IRQ (1 << 20) -#define IRQ0STATUS_RSZ_DONE_IRQ (1 << 24) -#define IRQ0STATUS_OVF_IRQ (1 << 25) -#define IRQ0STATUS_PING_IRQ (1 << 26) -#define IRQ0STATUS_PONG_IRQ (1 << 27) -#define IRQ0STATUS_MMU_ERR_IRQ (1 << 28) -#define IRQ0STATUS_OCP_ERR_IRQ (1 << 29) -#define IRQ0STATUS_SEC_ERR_IRQ (1 << 30) -#define IRQ0STATUS_HS_VS_IRQ (1 << 31) - -#define TCTRL_GRESET_LEN 0 - -#define TCTRL_PSTRB_REPLAY_DELAY 0 -#define TCTRL_PSTRB_REPLAY_COUNTER_SHIFT 25 - -#define ISPCTRL_PAR_SER_CLK_SEL_PARALLEL 0x0 -#define ISPCTRL_PAR_SER_CLK_SEL_CSIA 0x1 -#define ISPCTRL_PAR_SER_CLK_SEL_CSIB 0x2 -#define ISPCTRL_PAR_SER_CLK_SEL_CSIC 0x3 -#define ISPCTRL_PAR_SER_CLK_SEL_MASK 0x3 - -#define ISPCTRL_PAR_BRIDGE_SHIFT 2 -#define ISPCTRL_PAR_BRIDGE_DISABLE (0x0 << 2) -#define ISPCTRL_PAR_BRIDGE_LENDIAN (0x2 << 2) -#define ISPCTRL_PAR_BRIDGE_BENDIAN (0x3 << 2) -#define ISPCTRL_PAR_BRIDGE_MASK (0x3 << 2) - -#define ISPCTRL_PAR_CLK_POL_SHIFT 4 -#define ISPCTRL_PAR_CLK_POL_INV (1 << 4) -#define ISPCTRL_PING_PONG_EN (1 << 5) -#define ISPCTRL_SHIFT_SHIFT 6 -#define ISPCTRL_SHIFT_0 (0x0 << 6) -#define ISPCTRL_SHIFT_2 (0x1 << 6) -#define ISPCTRL_SHIFT_4 (0x2 << 6) -#define ISPCTRL_SHIFT_MASK (0x3 << 6) - -#define ISPCTRL_CCDC_CLK_EN (1 << 8) -#define ISPCTRL_SCMP_CLK_EN (1 << 9) -#define ISPCTRL_H3A_CLK_EN (1 << 10) -#define ISPCTRL_HIST_CLK_EN (1 << 11) -#define ISPCTRL_PREV_CLK_EN (1 << 12) -#define ISPCTRL_RSZ_CLK_EN (1 << 13) -#define ISPCTRL_SYNC_DETECT_SHIFT 14 -#define ISPCTRL_SYNC_DETECT_HSFALL (0x0 << ISPCTRL_SYNC_DETECT_SHIFT) -#define ISPCTRL_SYNC_DETECT_HSRISE (0x1 << ISPCTRL_SYNC_DETECT_SHIFT) -#define ISPCTRL_SYNC_DETECT_VSFALL (0x2 << ISPCTRL_SYNC_DETECT_SHIFT) -#define ISPCTRL_SYNC_DETECT_VSRISE (0x3 << ISPCTRL_SYNC_DETECT_SHIFT) -#define ISPCTRL_SYNC_DETECT_MASK (0x3 << ISPCTRL_SYNC_DETECT_SHIFT) - -#define ISPCTRL_CCDC_RAM_EN (1 << 16) -#define ISPCTRL_PREV_RAM_EN (1 << 17) -#define ISPCTRL_SBL_RD_RAM_EN (1 << 18) -#define ISPCTRL_SBL_WR1_RAM_EN (1 << 19) -#define ISPCTRL_SBL_WR0_RAM_EN (1 << 20) -#define ISPCTRL_SBL_AUTOIDLE (1 << 21) -#define ISPCTRL_SBL_SHARED_WPORTC (1 << 26) -#define ISPCTRL_SBL_SHARED_RPORTA (1 << 27) -#define ISPCTRL_SBL_SHARED_RPORTB (1 << 28) -#define ISPCTRL_JPEG_FLUSH (1 << 30) -#define ISPCTRL_CCDC_FLUSH (1 << 31) - -#define ISPSECURE_SECUREMODE 0 - -#define ISPTCTRL_CTRL_DIV_LOW 0x0 -#define ISPTCTRL_CTRL_DIV_HIGH 0x1 -#define ISPTCTRL_CTRL_DIV_BYPASS 0x1F - -#define ISPTCTRL_CTRL_DIVA_SHIFT 0 -#define ISPTCTRL_CTRL_DIVA_MASK (0x1F << ISPTCTRL_CTRL_DIVA_SHIFT) - -#define ISPTCTRL_CTRL_DIVB_SHIFT 5 -#define ISPTCTRL_CTRL_DIVB_MASK (0x1F << ISPTCTRL_CTRL_DIVB_SHIFT) - -#define ISPTCTRL_CTRL_DIVC_SHIFT 10 -#define ISPTCTRL_CTRL_DIVC_NOCLOCK (0x0 << 10) - -#define ISPTCTRL_CTRL_SHUTEN (1 << 21) -#define ISPTCTRL_CTRL_PSTRBEN (1 << 22) -#define ISPTCTRL_CTRL_STRBEN (1 << 23) -#define ISPTCTRL_CTRL_SHUTPOL (1 << 24) -#define ISPTCTRL_CTRL_STRBPSTRBPOL (1 << 26) - -#define ISPTCTRL_CTRL_INSEL_SHIFT 27 -#define ISPTCTRL_CTRL_INSEL_PARALLEL (0x0 << 27) -#define ISPTCTRL_CTRL_INSEL_CSIA (0x1 << 27) -#define ISPTCTRL_CTRL_INSEL_CSIB (0x2 << 27) - -#define ISPTCTRL_CTRL_GRESETEn (1 << 29) -#define ISPTCTRL_CTRL_GRESETPOL (1 << 30) -#define ISPTCTRL_CTRL_GRESETDIR (1 << 31) - -#define ISPTCTRL_FRAME_SHUT_SHIFT 0 -#define ISPTCTRL_FRAME_PSTRB_SHIFT 6 -#define ISPTCTRL_FRAME_STRB_SHIFT 12 - -#define ISPCCDC_PID_PREV_SHIFT 0 -#define ISPCCDC_PID_CID_SHIFT 8 -#define ISPCCDC_PID_TID_SHIFT 16 - -#define ISPCCDC_PCR_EN 1 -#define ISPCCDC_PCR_BUSY (1 << 1) - -#define ISPCCDC_SYN_MODE_VDHDOUT 0x1 -#define ISPCCDC_SYN_MODE_FLDOUT (1 << 1) -#define ISPCCDC_SYN_MODE_VDPOL (1 << 2) -#define ISPCCDC_SYN_MODE_HDPOL (1 << 3) -#define ISPCCDC_SYN_MODE_FLDPOL (1 << 4) -#define ISPCCDC_SYN_MODE_EXWEN (1 << 5) -#define ISPCCDC_SYN_MODE_DATAPOL (1 << 6) -#define ISPCCDC_SYN_MODE_FLDMODE (1 << 7) -#define ISPCCDC_SYN_MODE_DATSIZ_MASK (0x7 << 8) -#define ISPCCDC_SYN_MODE_DATSIZ_8_16 (0x0 << 8) -#define ISPCCDC_SYN_MODE_DATSIZ_12 (0x4 << 8) -#define ISPCCDC_SYN_MODE_DATSIZ_11 (0x5 << 8) -#define ISPCCDC_SYN_MODE_DATSIZ_10 (0x6 << 8) -#define ISPCCDC_SYN_MODE_DATSIZ_8 (0x7 << 8) -#define ISPCCDC_SYN_MODE_PACK8 (1 << 11) -#define ISPCCDC_SYN_MODE_INPMOD_MASK (3 << 12) -#define ISPCCDC_SYN_MODE_INPMOD_RAW (0 << 12) -#define ISPCCDC_SYN_MODE_INPMOD_YCBCR16 (1 << 12) -#define ISPCCDC_SYN_MODE_INPMOD_YCBCR8 (2 << 12) -#define ISPCCDC_SYN_MODE_LPF (1 << 14) -#define ISPCCDC_SYN_MODE_FLDSTAT (1 << 15) -#define ISPCCDC_SYN_MODE_VDHDEN (1 << 16) -#define ISPCCDC_SYN_MODE_WEN (1 << 17) -#define ISPCCDC_SYN_MODE_VP2SDR (1 << 18) -#define ISPCCDC_SYN_MODE_SDR2RSZ (1 << 19) - -#define ISPCCDC_HD_VD_WID_VDW_SHIFT 0 -#define ISPCCDC_HD_VD_WID_HDW_SHIFT 16 - -#define ISPCCDC_PIX_LINES_HLPRF_SHIFT 0 -#define ISPCCDC_PIX_LINES_PPLN_SHIFT 16 - -#define ISPCCDC_HORZ_INFO_NPH_SHIFT 0 -#define ISPCCDC_HORZ_INFO_NPH_MASK 0x00007fff -#define ISPCCDC_HORZ_INFO_SPH_SHIFT 16 -#define ISPCCDC_HORZ_INFO_SPH_MASK 0x7fff0000 - -#define ISPCCDC_VERT_START_SLV1_SHIFT 0 -#define ISPCCDC_VERT_START_SLV0_SHIFT 16 -#define ISPCCDC_VERT_START_SLV0_MASK 0x7fff0000 - -#define ISPCCDC_VERT_LINES_NLV_SHIFT 0 -#define ISPCCDC_VERT_LINES_NLV_MASK 0x00007fff - -#define ISPCCDC_CULLING_CULV_SHIFT 0 -#define ISPCCDC_CULLING_CULHODD_SHIFT 16 -#define ISPCCDC_CULLING_CULHEVN_SHIFT 24 - -#define ISPCCDC_HSIZE_OFF_SHIFT 0 - -#define ISPCCDC_SDOFST_FINV (1 << 14) -#define ISPCCDC_SDOFST_FOFST_1L 0 -#define ISPCCDC_SDOFST_FOFST_4L (3 << 12) -#define ISPCCDC_SDOFST_LOFST3_SHIFT 0 -#define ISPCCDC_SDOFST_LOFST2_SHIFT 3 -#define ISPCCDC_SDOFST_LOFST1_SHIFT 6 -#define ISPCCDC_SDOFST_LOFST0_SHIFT 9 -#define EVENEVEN 1 -#define ODDEVEN 2 -#define EVENODD 3 -#define ODDODD 4 - -#define ISPCCDC_CLAMP_OBGAIN_SHIFT 0 -#define ISPCCDC_CLAMP_OBST_SHIFT 10 -#define ISPCCDC_CLAMP_OBSLN_SHIFT 25 -#define ISPCCDC_CLAMP_OBSLEN_SHIFT 28 -#define ISPCCDC_CLAMP_CLAMPEN (1 << 31) - -#define ISPCCDC_COLPTN_R_Ye 0x0 -#define ISPCCDC_COLPTN_Gr_Cy 0x1 -#define ISPCCDC_COLPTN_Gb_G 0x2 -#define ISPCCDC_COLPTN_B_Mg 0x3 -#define ISPCCDC_COLPTN_CP0PLC0_SHIFT 0 -#define ISPCCDC_COLPTN_CP0PLC1_SHIFT 2 -#define ISPCCDC_COLPTN_CP0PLC2_SHIFT 4 -#define ISPCCDC_COLPTN_CP0PLC3_SHIFT 6 -#define ISPCCDC_COLPTN_CP1PLC0_SHIFT 8 -#define ISPCCDC_COLPTN_CP1PLC1_SHIFT 10 -#define ISPCCDC_COLPTN_CP1PLC2_SHIFT 12 -#define ISPCCDC_COLPTN_CP1PLC3_SHIFT 14 -#define ISPCCDC_COLPTN_CP2PLC0_SHIFT 16 -#define ISPCCDC_COLPTN_CP2PLC1_SHIFT 18 -#define ISPCCDC_COLPTN_CP2PLC2_SHIFT 20 -#define ISPCCDC_COLPTN_CP2PLC3_SHIFT 22 -#define ISPCCDC_COLPTN_CP3PLC0_SHIFT 24 -#define ISPCCDC_COLPTN_CP3PLC1_SHIFT 26 -#define ISPCCDC_COLPTN_CP3PLC2_SHIFT 28 -#define ISPCCDC_COLPTN_CP3PLC3_SHIFT 30 - -#define ISPCCDC_BLKCMP_B_MG_SHIFT 0 -#define ISPCCDC_BLKCMP_GB_G_SHIFT 8 -#define ISPCCDC_BLKCMP_GR_CY_SHIFT 16 -#define ISPCCDC_BLKCMP_R_YE_SHIFT 24 - -#define ISPCCDC_FPC_FPNUM_SHIFT 0 -#define ISPCCDC_FPC_FPCEN (1 << 15) -#define ISPCCDC_FPC_FPERR (1 << 16) - -#define ISPCCDC_VDINT_1_SHIFT 0 -#define ISPCCDC_VDINT_1_MASK 0x00007fff -#define ISPCCDC_VDINT_0_SHIFT 16 -#define ISPCCDC_VDINT_0_MASK 0x7fff0000 - -#define ISPCCDC_ALAW_GWDI_12_3 (0x3 << 0) -#define ISPCCDC_ALAW_GWDI_11_2 (0x4 << 0) -#define ISPCCDC_ALAW_GWDI_10_1 (0x5 << 0) -#define ISPCCDC_ALAW_GWDI_9_0 (0x6 << 0) -#define ISPCCDC_ALAW_CCDTBL (1 << 3) - -#define ISPCCDC_REC656IF_R656ON 1 -#define ISPCCDC_REC656IF_ECCFVH (1 << 1) - -#define ISPCCDC_CFG_BW656 (1 << 5) -#define ISPCCDC_CFG_FIDMD_SHIFT 6 -#define ISPCCDC_CFG_WENLOG (1 << 8) -#define ISPCCDC_CFG_WENLOG_AND (0 << 8) -#define ISPCCDC_CFG_WENLOG_OR (1 << 8) -#define ISPCCDC_CFG_Y8POS (1 << 11) -#define ISPCCDC_CFG_BSWD (1 << 12) -#define ISPCCDC_CFG_MSBINVI (1 << 13) -#define ISPCCDC_CFG_VDLC (1 << 15) - -#define ISPCCDC_FMTCFG_FMTEN 0x1 -#define ISPCCDC_FMTCFG_LNALT (1 << 1) -#define ISPCCDC_FMTCFG_LNUM_SHIFT 2 -#define ISPCCDC_FMTCFG_PLEN_ODD_SHIFT 4 -#define ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT 8 -#define ISPCCDC_FMTCFG_VPIN_MASK 0x00007000 -#define ISPCCDC_FMTCFG_VPIN_12_3 (0x3 << 12) -#define ISPCCDC_FMTCFG_VPIN_11_2 (0x4 << 12) -#define ISPCCDC_FMTCFG_VPIN_10_1 (0x5 << 12) -#define ISPCCDC_FMTCFG_VPIN_9_0 (0x6 << 12) -#define ISPCCDC_FMTCFG_VPEN (1 << 15) - -#define ISPCCDC_FMTCFG_VPIF_FRQ_MASK 0x003f0000 -#define ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT 16 -#define ISPCCDC_FMTCFG_VPIF_FRQ_BY2 (0x0 << 16) -#define ISPCCDC_FMTCFG_VPIF_FRQ_BY3 (0x1 << 16) -#define ISPCCDC_FMTCFG_VPIF_FRQ_BY4 (0x2 << 16) -#define ISPCCDC_FMTCFG_VPIF_FRQ_BY5 (0x3 << 16) -#define ISPCCDC_FMTCFG_VPIF_FRQ_BY6 (0x4 << 16) - -#define ISPCCDC_FMT_HORZ_FMTLNH_SHIFT 0 -#define ISPCCDC_FMT_HORZ_FMTSPH_SHIFT 16 - -#define ISPCCDC_FMT_VERT_FMTLNV_SHIFT 0 -#define ISPCCDC_FMT_VERT_FMTSLV_SHIFT 16 - -#define ISPCCDC_FMT_HORZ_FMTSPH_MASK 0x1fff0000 -#define ISPCCDC_FMT_HORZ_FMTLNH_MASK 0x00001fff - -#define ISPCCDC_FMT_VERT_FMTSLV_MASK 0x1fff0000 -#define ISPCCDC_FMT_VERT_FMTLNV_MASK 0x00001fff - -#define ISPCCDC_VP_OUT_HORZ_ST_SHIFT 0 -#define ISPCCDC_VP_OUT_HORZ_NUM_SHIFT 4 -#define ISPCCDC_VP_OUT_VERT_NUM_SHIFT 17 - -#define ISPRSZ_PID_PREV_SHIFT 0 -#define ISPRSZ_PID_CID_SHIFT 8 -#define ISPRSZ_PID_TID_SHIFT 16 - -#define ISPRSZ_PCR_ENABLE (1 << 0) -#define ISPRSZ_PCR_BUSY (1 << 1) -#define ISPRSZ_PCR_ONESHOT (1 << 2) - -#define ISPRSZ_CNT_HRSZ_SHIFT 0 -#define ISPRSZ_CNT_HRSZ_MASK \ - (0x3FF << ISPRSZ_CNT_HRSZ_SHIFT) -#define ISPRSZ_CNT_VRSZ_SHIFT 10 -#define ISPRSZ_CNT_VRSZ_MASK \ - (0x3FF << ISPRSZ_CNT_VRSZ_SHIFT) -#define ISPRSZ_CNT_HSTPH_SHIFT 20 -#define ISPRSZ_CNT_HSTPH_MASK (0x7 << ISPRSZ_CNT_HSTPH_SHIFT) -#define ISPRSZ_CNT_VSTPH_SHIFT 23 -#define ISPRSZ_CNT_VSTPH_MASK (0x7 << ISPRSZ_CNT_VSTPH_SHIFT) -#define ISPRSZ_CNT_YCPOS (1 << 26) -#define ISPRSZ_CNT_INPTYP (1 << 27) -#define ISPRSZ_CNT_INPSRC (1 << 28) -#define ISPRSZ_CNT_CBILIN (1 << 29) - -#define ISPRSZ_OUT_SIZE_HORZ_SHIFT 0 -#define ISPRSZ_OUT_SIZE_HORZ_MASK \ - (0xFFF << ISPRSZ_OUT_SIZE_HORZ_SHIFT) -#define ISPRSZ_OUT_SIZE_VERT_SHIFT 16 -#define ISPRSZ_OUT_SIZE_VERT_MASK \ - (0xFFF << ISPRSZ_OUT_SIZE_VERT_SHIFT) - -#define ISPRSZ_IN_START_HORZ_ST_SHIFT 0 -#define ISPRSZ_IN_START_HORZ_ST_MASK \ - (0x1FFF << ISPRSZ_IN_START_HORZ_ST_SHIFT) -#define ISPRSZ_IN_START_VERT_ST_SHIFT 16 -#define ISPRSZ_IN_START_VERT_ST_MASK \ - (0x1FFF << ISPRSZ_IN_START_VERT_ST_SHIFT) - -#define ISPRSZ_IN_SIZE_HORZ_SHIFT 0 -#define ISPRSZ_IN_SIZE_HORZ_MASK \ - (0x1FFF << ISPRSZ_IN_SIZE_HORZ_SHIFT) -#define ISPRSZ_IN_SIZE_VERT_SHIFT 16 -#define ISPRSZ_IN_SIZE_VERT_MASK \ - (0x1FFF << ISPRSZ_IN_SIZE_VERT_SHIFT) - -#define ISPRSZ_SDR_INADD_ADDR_SHIFT 0 -#define ISPRSZ_SDR_INADD_ADDR_MASK 0xFFFFFFFF - -#define ISPRSZ_SDR_INOFF_OFFSET_SHIFT 0 -#define ISPRSZ_SDR_INOFF_OFFSET_MASK \ - (0xFFFF << ISPRSZ_SDR_INOFF_OFFSET_SHIFT) - -#define ISPRSZ_SDR_OUTADD_ADDR_SHIFT 0 -#define ISPRSZ_SDR_OUTADD_ADDR_MASK 0xFFFFFFFF - - -#define ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT 0 -#define ISPRSZ_SDR_OUTOFF_OFFSET_MASK \ - (0xFFFF << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT) - -#define ISPRSZ_HFILT_COEF0_SHIFT 0 -#define ISPRSZ_HFILT_COEF0_MASK \ - (0x3FF << ISPRSZ_HFILT_COEF0_SHIFT) -#define ISPRSZ_HFILT_COEF1_SHIFT 16 -#define ISPRSZ_HFILT_COEF1_MASK \ - (0x3FF << ISPRSZ_HFILT_COEF1_SHIFT) - -#define ISPRSZ_HFILT32_COEF2_SHIFT 0 -#define ISPRSZ_HFILT32_COEF2_MASK 0x3FF -#define ISPRSZ_HFILT32_COEF3_SHIFT 16 -#define ISPRSZ_HFILT32_COEF3_MASK 0x3FF0000 - -#define ISPRSZ_HFILT54_COEF4_SHIFT 0 -#define ISPRSZ_HFILT54_COEF4_MASK 0x3FF -#define ISPRSZ_HFILT54_COEF5_SHIFT 16 -#define ISPRSZ_HFILT54_COEF5_MASK 0x3FF0000 - -#define ISPRSZ_HFILT76_COEFF6_SHIFT 0 -#define ISPRSZ_HFILT76_COEFF6_MASK 0x3FF -#define ISPRSZ_HFILT76_COEFF7_SHIFT 16 -#define ISPRSZ_HFILT76_COEFF7_MASK 0x3FF0000 - -#define ISPRSZ_HFILT98_COEFF8_SHIFT 0 -#define ISPRSZ_HFILT98_COEFF8_MASK 0x3FF -#define ISPRSZ_HFILT98_COEFF9_SHIFT 16 -#define ISPRSZ_HFILT98_COEFF9_MASK 0x3FF0000 - -#define ISPRSZ_HFILT1110_COEF10_SHIFT 0 -#define ISPRSZ_HFILT1110_COEF10_MASK 0x3FF -#define ISPRSZ_HFILT1110_COEF11_SHIFT 16 -#define ISPRSZ_HFILT1110_COEF11_MASK 0x3FF0000 - -#define ISPRSZ_HFILT1312_COEFF12_SHIFT 0 -#define ISPRSZ_HFILT1312_COEFF12_MASK 0x3FF -#define ISPRSZ_HFILT1312_COEFF13_SHIFT 16 -#define ISPRSZ_HFILT1312_COEFF13_MASK 0x3FF0000 - -#define ISPRSZ_HFILT1514_COEFF14_SHIFT 0 -#define ISPRSZ_HFILT1514_COEFF14_MASK 0x3FF -#define ISPRSZ_HFILT1514_COEFF15_SHIFT 16 -#define ISPRSZ_HFILT1514_COEFF15_MASK 0x3FF0000 - -#define ISPRSZ_HFILT1716_COEF16_SHIFT 0 -#define ISPRSZ_HFILT1716_COEF16_MASK 0x3FF -#define ISPRSZ_HFILT1716_COEF17_SHIFT 16 -#define ISPRSZ_HFILT1716_COEF17_MASK 0x3FF0000 - -#define ISPRSZ_HFILT1918_COEF18_SHIFT 0 -#define ISPRSZ_HFILT1918_COEF18_MASK 0x3FF -#define ISPRSZ_HFILT1918_COEF19_SHIFT 16 -#define ISPRSZ_HFILT1918_COEF19_MASK 0x3FF0000 - -#define ISPRSZ_HFILT2120_COEF20_SHIFT 0 -#define ISPRSZ_HFILT2120_COEF20_MASK 0x3FF -#define ISPRSZ_HFILT2120_COEF21_SHIFT 16 -#define ISPRSZ_HFILT2120_COEF21_MASK 0x3FF0000 - -#define ISPRSZ_HFILT2322_COEF22_SHIFT 0 -#define ISPRSZ_HFILT2322_COEF22_MASK 0x3FF -#define ISPRSZ_HFILT2322_COEF23_SHIFT 16 -#define ISPRSZ_HFILT2322_COEF23_MASK 0x3FF0000 - -#define ISPRSZ_HFILT2524_COEF24_SHIFT 0 -#define ISPRSZ_HFILT2524_COEF24_MASK 0x3FF -#define ISPRSZ_HFILT2524_COEF25_SHIFT 16 -#define ISPRSZ_HFILT2524_COEF25_MASK 0x3FF0000 - -#define ISPRSZ_HFILT2726_COEF26_SHIFT 0 -#define ISPRSZ_HFILT2726_COEF26_MASK 0x3FF -#define ISPRSZ_HFILT2726_COEF27_SHIFT 16 -#define ISPRSZ_HFILT2726_COEF27_MASK 0x3FF0000 - -#define ISPRSZ_HFILT2928_COEF28_SHIFT 0 -#define ISPRSZ_HFILT2928_COEF28_MASK 0x3FF -#define ISPRSZ_HFILT2928_COEF29_SHIFT 16 -#define ISPRSZ_HFILT2928_COEF29_MASK 0x3FF0000 - -#define ISPRSZ_HFILT3130_COEF30_SHIFT 0 -#define ISPRSZ_HFILT3130_COEF30_MASK 0x3FF -#define ISPRSZ_HFILT3130_COEF31_SHIFT 16 -#define ISPRSZ_HFILT3130_COEF31_MASK 0x3FF0000 - -#define ISPRSZ_VFILT_COEF0_SHIFT 0 -#define ISPRSZ_VFILT_COEF0_MASK \ - (0x3FF << ISPRSZ_VFILT_COEF0_SHIFT) -#define ISPRSZ_VFILT_COEF1_SHIFT 16 -#define ISPRSZ_VFILT_COEF1_MASK \ - (0x3FF << ISPRSZ_VFILT_COEF1_SHIFT) - -#define ISPRSZ_VFILT10_COEF0_SHIFT 0 -#define ISPRSZ_VFILT10_COEF0_MASK 0x3FF -#define ISPRSZ_VFILT10_COEF1_SHIFT 16 -#define ISPRSZ_VFILT10_COEF1_MASK 0x3FF0000 - -#define ISPRSZ_VFILT32_COEF2_SHIFT 0 -#define ISPRSZ_VFILT32_COEF2_MASK 0x3FF -#define ISPRSZ_VFILT32_COEF3_SHIFT 16 -#define ISPRSZ_VFILT32_COEF3_MASK 0x3FF0000 - -#define ISPRSZ_VFILT54_COEF4_SHIFT 0 -#define ISPRSZ_VFILT54_COEF4_MASK 0x3FF -#define ISPRSZ_VFILT54_COEF5_SHIFT 16 -#define ISPRSZ_VFILT54_COEF5_MASK 0x3FF0000 - -#define ISPRSZ_VFILT76_COEFF6_SHIFT 0 -#define ISPRSZ_VFILT76_COEFF6_MASK 0x3FF -#define ISPRSZ_VFILT76_COEFF7_SHIFT 16 -#define ISPRSZ_VFILT76_COEFF7_MASK 0x3FF0000 - -#define ISPRSZ_VFILT98_COEFF8_SHIFT 0 -#define ISPRSZ_VFILT98_COEFF8_MASK 0x3FF -#define ISPRSZ_VFILT98_COEFF9_SHIFT 16 -#define ISPRSZ_VFILT98_COEFF9_MASK 0x3FF0000 - -#define ISPRSZ_VFILT1110_COEF10_SHIFT 0 -#define ISPRSZ_VFILT1110_COEF10_MASK 0x3FF -#define ISPRSZ_VFILT1110_COEF11_SHIFT 16 -#define ISPRSZ_VFILT1110_COEF11_MASK 0x3FF0000 - -#define ISPRSZ_VFILT1312_COEFF12_SHIFT 0 -#define ISPRSZ_VFILT1312_COEFF12_MASK 0x3FF -#define ISPRSZ_VFILT1312_COEFF13_SHIFT 16 -#define ISPRSZ_VFILT1312_COEFF13_MASK 0x3FF0000 - -#define ISPRSZ_VFILT1514_COEFF14_SHIFT 0 -#define ISPRSZ_VFILT1514_COEFF14_MASK 0x3FF -#define ISPRSZ_VFILT1514_COEFF15_SHIFT 16 -#define ISPRSZ_VFILT1514_COEFF15_MASK 0x3FF0000 - -#define ISPRSZ_VFILT1716_COEF16_SHIFT 0 -#define ISPRSZ_VFILT1716_COEF16_MASK 0x3FF -#define ISPRSZ_VFILT1716_COEF17_SHIFT 16 -#define ISPRSZ_VFILT1716_COEF17_MASK 0x3FF0000 - -#define ISPRSZ_VFILT1918_COEF18_SHIFT 0 -#define ISPRSZ_VFILT1918_COEF18_MASK 0x3FF -#define ISPRSZ_VFILT1918_COEF19_SHIFT 16 -#define ISPRSZ_VFILT1918_COEF19_MASK 0x3FF0000 - -#define ISPRSZ_VFILT2120_COEF20_SHIFT 0 -#define ISPRSZ_VFILT2120_COEF20_MASK 0x3FF -#define ISPRSZ_VFILT2120_COEF21_SHIFT 16 -#define ISPRSZ_VFILT2120_COEF21_MASK 0x3FF0000 - -#define ISPRSZ_VFILT2322_COEF22_SHIFT 0 -#define ISPRSZ_VFILT2322_COEF22_MASK 0x3FF -#define ISPRSZ_VFILT2322_COEF23_SHIFT 16 -#define ISPRSZ_VFILT2322_COEF23_MASK 0x3FF0000 - -#define ISPRSZ_VFILT2524_COEF24_SHIFT 0 -#define ISPRSZ_VFILT2524_COEF24_MASK 0x3FF -#define ISPRSZ_VFILT2524_COEF25_SHIFT 16 -#define ISPRSZ_VFILT2524_COEF25_MASK 0x3FF0000 - -#define ISPRSZ_VFILT2726_COEF26_SHIFT 0 -#define ISPRSZ_VFILT2726_COEF26_MASK 0x3FF -#define ISPRSZ_VFILT2726_COEF27_SHIFT 16 -#define ISPRSZ_VFILT2726_COEF27_MASK 0x3FF0000 - -#define ISPRSZ_VFILT2928_COEF28_SHIFT 0 -#define ISPRSZ_VFILT2928_COEF28_MASK 0x3FF -#define ISPRSZ_VFILT2928_COEF29_SHIFT 16 -#define ISPRSZ_VFILT2928_COEF29_MASK 0x3FF0000 - -#define ISPRSZ_VFILT3130_COEF30_SHIFT 0 -#define ISPRSZ_VFILT3130_COEF30_MASK 0x3FF -#define ISPRSZ_VFILT3130_COEF31_SHIFT 16 -#define ISPRSZ_VFILT3130_COEF31_MASK 0x3FF0000 - -#define ISPRSZ_YENH_CORE_SHIFT 0 -#define ISPRSZ_YENH_CORE_MASK \ - (0xFF << ISPRSZ_YENH_CORE_SHIFT) -#define ISPRSZ_YENH_SLOP_SHIFT 8 -#define ISPRSZ_YENH_SLOP_MASK \ - (0xF << ISPRSZ_YENH_SLOP_SHIFT) -#define ISPRSZ_YENH_GAIN_SHIFT 12 -#define ISPRSZ_YENH_GAIN_MASK \ - (0xF << ISPRSZ_YENH_GAIN_SHIFT) -#define ISPRSZ_YENH_ALGO_SHIFT 16 -#define ISPRSZ_YENH_ALGO_MASK \ - (0x3 << ISPRSZ_YENH_ALGO_SHIFT) - -#define ISPH3A_PCR_AEW_ALAW_EN_SHIFT 1 -#define ISPH3A_PCR_AF_MED_TH_SHIFT 3 -#define ISPH3A_PCR_AF_RGBPOS_SHIFT 11 -#define ISPH3A_PCR_AEW_AVE2LMT_SHIFT 22 -#define ISPH3A_PCR_AEW_AVE2LMT_MASK 0xFFC00000 -#define ISPH3A_PCR_BUSYAF (1 << 15) -#define ISPH3A_PCR_BUSYAEAWB (1 << 18) - -#define ISPH3A_AEWWIN1_WINHC_SHIFT 0 -#define ISPH3A_AEWWIN1_WINHC_MASK 0x3F -#define ISPH3A_AEWWIN1_WINVC_SHIFT 6 -#define ISPH3A_AEWWIN1_WINVC_MASK 0x1FC0 -#define ISPH3A_AEWWIN1_WINW_SHIFT 13 -#define ISPH3A_AEWWIN1_WINW_MASK 0xFE000 -#define ISPH3A_AEWWIN1_WINH_SHIFT 24 -#define ISPH3A_AEWWIN1_WINH_MASK 0x7F000000 - -#define ISPH3A_AEWINSTART_WINSH_SHIFT 0 -#define ISPH3A_AEWINSTART_WINSH_MASK 0x0FFF -#define ISPH3A_AEWINSTART_WINSV_SHIFT 16 -#define ISPH3A_AEWINSTART_WINSV_MASK 0x0FFF0000 - -#define ISPH3A_AEWINBLK_WINH_SHIFT 0 -#define ISPH3A_AEWINBLK_WINH_MASK 0x7F -#define ISPH3A_AEWINBLK_WINSV_SHIFT 16 -#define ISPH3A_AEWINBLK_WINSV_MASK 0x0FFF0000 - -#define ISPH3A_AEWSUBWIN_AEWINCH_SHIFT 0 -#define ISPH3A_AEWSUBWIN_AEWINCH_MASK 0x0F -#define ISPH3A_AEWSUBWIN_AEWINCV_SHIFT 8 -#define ISPH3A_AEWSUBWIN_AEWINCV_MASK 0x0F00 - -#define ISPHIST_PCR_ENABLE_SHIFT 0 -#define ISPHIST_PCR_ENABLE_MASK 0x01 -#define ISPHIST_PCR_ENABLE (1 << ISPHIST_PCR_ENABLE_SHIFT) -#define ISPHIST_PCR_BUSY 0x02 - -#define ISPHIST_CNT_DATASIZE_SHIFT 8 -#define ISPHIST_CNT_DATASIZE_MASK 0x0100 -#define ISPHIST_CNT_CLEAR_SHIFT 7 -#define ISPHIST_CNT_CLEAR_MASK 0x080 -#define ISPHIST_CNT_CLEAR (1 << ISPHIST_CNT_CLEAR_SHIFT) -#define ISPHIST_CNT_CFA_SHIFT 6 -#define ISPHIST_CNT_CFA_MASK 0x040 -#define ISPHIST_CNT_BINS_SHIFT 4 -#define ISPHIST_CNT_BINS_MASK 0x030 -#define ISPHIST_CNT_SOURCE_SHIFT 3 -#define ISPHIST_CNT_SOURCE_MASK 0x08 -#define ISPHIST_CNT_SHIFT_SHIFT 0 -#define ISPHIST_CNT_SHIFT_MASK 0x07 - -#define ISPHIST_WB_GAIN_WG00_SHIFT 24 -#define ISPHIST_WB_GAIN_WG00_MASK 0xFF000000 -#define ISPHIST_WB_GAIN_WG01_SHIFT 16 -#define ISPHIST_WB_GAIN_WG01_MASK 0xFF0000 -#define ISPHIST_WB_GAIN_WG02_SHIFT 8 -#define ISPHIST_WB_GAIN_WG02_MASK 0xFF00 -#define ISPHIST_WB_GAIN_WG03_SHIFT 0 -#define ISPHIST_WB_GAIN_WG03_MASK 0xFF - -#define ISPHIST_REG_START_END_MASK 0x3FFF -#define ISPHIST_REG_START_SHIFT 16 -#define ISPHIST_REG_END_SHIFT 0 -#define ISPHIST_REG_START_MASK (ISPHIST_REG_START_END_MASK << \ - ISPHIST_REG_START_SHIFT) -#define ISPHIST_REG_END_MASK (ISPHIST_REG_START_END_MASK << \ - ISPHIST_REG_END_SHIFT) - -#define ISPHIST_REG_MASK (ISPHIST_REG_START_MASK | \ - ISPHIST_REG_END_MASK) - -#define ISPHIST_ADDR_SHIFT 0 -#define ISPHIST_ADDR_MASK 0x3FF - -#define ISPHIST_DATA_SHIFT 0 -#define ISPHIST_DATA_MASK 0xFFFFF - -#define ISPHIST_RADD_SHIFT 0 -#define ISPHIST_RADD_MASK 0xFFFFFFFF - -#define ISPHIST_RADD_OFF_SHIFT 0 -#define ISPHIST_RADD_OFF_MASK 0xFFFF - -#define ISPHIST_HV_INFO_HSIZE_SHIFT 16 -#define ISPHIST_HV_INFO_HSIZE_MASK 0x3FFF0000 -#define ISPHIST_HV_INFO_VSIZE_SHIFT 0 -#define ISPHIST_HV_INFO_VSIZE_MASK 0x3FFF - -#define ISPHIST_HV_INFO_MASK 0x3FFF3FFF - -#define ISPCCDC_LSC_ENABLE 1 -#define ISPCCDC_LSC_BUSY (1 << 7) -#define ISPCCDC_LSC_GAIN_MODE_N_MASK 0x700 -#define ISPCCDC_LSC_GAIN_MODE_N_SHIFT 8 -#define ISPCCDC_LSC_GAIN_MODE_M_MASK 0x3800 -#define ISPCCDC_LSC_GAIN_MODE_M_SHIFT 12 -#define ISPCCDC_LSC_GAIN_FORMAT_MASK 0xE -#define ISPCCDC_LSC_GAIN_FORMAT_SHIFT 1 -#define ISPCCDC_LSC_AFTER_REFORMATTER_MASK (1<<6) - -#define ISPCCDC_LSC_INITIAL_X_MASK 0x3F -#define ISPCCDC_LSC_INITIAL_X_SHIFT 0 -#define ISPCCDC_LSC_INITIAL_Y_MASK 0x3F0000 -#define ISPCCDC_LSC_INITIAL_Y_SHIFT 16 - -/* ----------------------------------------------------------------------------- - * CSI2 receiver registers (ES2.0) - */ - -#define ISPCSI2_REVISION (0x000) -#define ISPCSI2_SYSCONFIG (0x010) -#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT 12 -#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK \ - (0x3 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) -#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_FORCE \ - (0x0 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) -#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO \ - (0x1 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) -#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART \ - (0x2 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) -#define ISPCSI2_SYSCONFIG_SOFT_RESET (1 << 1) -#define ISPCSI2_SYSCONFIG_AUTO_IDLE (1 << 0) - -#define ISPCSI2_SYSSTATUS (0x014) -#define ISPCSI2_SYSSTATUS_RESET_DONE (1 << 0) - -#define ISPCSI2_IRQSTATUS (0x018) -#define ISPCSI2_IRQSTATUS_OCP_ERR_IRQ (1 << 14) -#define ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ (1 << 13) -#define ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 12) -#define ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ (1 << 11) -#define ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ (1 << 10) -#define ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ (1 << 9) -#define ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ (1 << 8) -#define ISPCSI2_IRQSTATUS_CONTEXT(n) (1 << (n)) - -#define ISPCSI2_IRQENABLE (0x01c) -#define ISPCSI2_CTRL (0x040) -#define ISPCSI2_CTRL_VP_CLK_EN (1 << 15) -#define ISPCSI2_CTRL_VP_ONLY_EN (1 << 11) -#define ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT 8 -#define ISPCSI2_CTRL_VP_OUT_CTRL_MASK \ - (3 << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT) -#define ISPCSI2_CTRL_DBG_EN (1 << 7) -#define ISPCSI2_CTRL_BURST_SIZE_SHIFT 5 -#define ISPCSI2_CTRL_BURST_SIZE_MASK \ - (3 << ISPCSI2_CTRL_BURST_SIZE_SHIFT) -#define ISPCSI2_CTRL_FRAME (1 << 3) -#define ISPCSI2_CTRL_ECC_EN (1 << 2) -#define ISPCSI2_CTRL_SECURE (1 << 1) -#define ISPCSI2_CTRL_IF_EN (1 << 0) - -#define ISPCSI2_DBG_H (0x044) -#define ISPCSI2_GNQ (0x048) -#define ISPCSI2_PHY_CFG (0x050) -#define ISPCSI2_PHY_CFG_RESET_CTRL (1 << 30) -#define ISPCSI2_PHY_CFG_RESET_DONE (1 << 29) -#define ISPCSI2_PHY_CFG_PWR_CMD_SHIFT 27 -#define ISPCSI2_PHY_CFG_PWR_CMD_MASK \ - (0x3 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT) -#define ISPCSI2_PHY_CFG_PWR_CMD_OFF \ - (0x0 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT) -#define ISPCSI2_PHY_CFG_PWR_CMD_ON \ - (0x1 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT) -#define ISPCSI2_PHY_CFG_PWR_CMD_ULPW \ - (0x2 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT) -#define ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT 25 -#define ISPCSI2_PHY_CFG_PWR_STATUS_MASK \ - (0x3 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) -#define ISPCSI2_PHY_CFG_PWR_STATUS_OFF \ - (0x0 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) -#define ISPCSI2_PHY_CFG_PWR_STATUS_ON \ - (0x1 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) -#define ISPCSI2_PHY_CFG_PWR_STATUS_ULPW \ - (0x2 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) -#define ISPCSI2_PHY_CFG_PWR_AUTO (1 << 24) - -#define ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n) (3 + ((n) * 4)) -#define ISPCSI2_PHY_CFG_DATA_POL_MASK(n) \ - (0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n)) -#define ISPCSI2_PHY_CFG_DATA_POL_PN(n) \ - (0x0 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n)) -#define ISPCSI2_PHY_CFG_DATA_POL_NP(n) \ - (0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n)) - -#define ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n) ((n) * 4) -#define ISPCSI2_PHY_CFG_DATA_POSITION_MASK(n) \ - (0x7 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) -#define ISPCSI2_PHY_CFG_DATA_POSITION_NC(n) \ - (0x0 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) -#define ISPCSI2_PHY_CFG_DATA_POSITION_1(n) \ - (0x1 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) -#define ISPCSI2_PHY_CFG_DATA_POSITION_2(n) \ - (0x2 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) -#define ISPCSI2_PHY_CFG_DATA_POSITION_3(n) \ - (0x3 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) -#define ISPCSI2_PHY_CFG_DATA_POSITION_4(n) \ - (0x4 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) -#define ISPCSI2_PHY_CFG_DATA_POSITION_5(n) \ - (0x5 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) - -#define ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT 3 -#define ISPCSI2_PHY_CFG_CLOCK_POL_MASK \ - (0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT) -#define ISPCSI2_PHY_CFG_CLOCK_POL_PN \ - (0x0 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT) -#define ISPCSI2_PHY_CFG_CLOCK_POL_NP \ - (0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT) - -#define ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT 0 -#define ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK \ - (0x7 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) -#define ISPCSI2_PHY_CFG_CLOCK_POSITION_1 \ - (0x1 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) -#define ISPCSI2_PHY_CFG_CLOCK_POSITION_2 \ - (0x2 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) -#define ISPCSI2_PHY_CFG_CLOCK_POSITION_3 \ - (0x3 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) -#define ISPCSI2_PHY_CFG_CLOCK_POSITION_4 \ - (0x4 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) -#define ISPCSI2_PHY_CFG_CLOCK_POSITION_5 \ - (0x5 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) - -#define ISPCSI2_PHY_IRQSTATUS (0x054) -#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMEXIT (1 << 26) -#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMENTER (1 << 25) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM5 (1 << 24) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM4 (1 << 23) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM3 (1 << 22) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM2 (1 << 21) -#define ISPCSI2_PHY_IRQSTATUS_STATEULPM1 (1 << 20) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL5 (1 << 19) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL4 (1 << 18) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL3 (1 << 17) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL2 (1 << 16) -#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL1 (1 << 15) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC5 (1 << 14) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC4 (1 << 13) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC3 (1 << 12) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC2 (1 << 11) -#define ISPCSI2_PHY_IRQSTATUS_ERRESC1 (1 << 10) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS5 (1 << 9) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS4 (1 << 8) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS3 (1 << 7) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS2 (1 << 6) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS1 (1 << 5) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS5 (1 << 4) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS4 (1 << 3) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS3 (1 << 2) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS2 (1 << 1) -#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS1 1 - -#define ISPCSI2_SHORT_PACKET (0x05c) -#define ISPCSI2_PHY_IRQENABLE (0x060) -#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT (1 << 26) -#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER (1 << 25) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM5 (1 << 24) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM4 (1 << 23) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM3 (1 << 22) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM2 (1 << 21) -#define ISPCSI2_PHY_IRQENABLE_STATEULPM1 (1 << 20) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 (1 << 19) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 (1 << 18) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 (1 << 17) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 (1 << 16) -#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 (1 << 15) -#define ISPCSI2_PHY_IRQENABLE_ERRESC5 (1 << 14) -#define ISPCSI2_PHY_IRQENABLE_ERRESC4 (1 << 13) -#define ISPCSI2_PHY_IRQENABLE_ERRESC3 (1 << 12) -#define ISPCSI2_PHY_IRQENABLE_ERRESC2 (1 << 11) -#define ISPCSI2_PHY_IRQENABLE_ERRESC1 (1 << 10) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 (1 << 9) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 (1 << 8) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 (1 << 7) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 (1 << 6) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 (1 << 5) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 (1 << 4) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 (1 << 3) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 (1 << 2) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 (1 << 1) -#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS1 (1 << 0) - -#define ISPCSI2_DBG_P (0x068) -#define ISPCSI2_TIMING (0x06c) -#define ISPCSI2_TIMING_FORCE_RX_MODE_IO(n) (1 << ((16 * ((n) - 1)) + 15)) -#define ISPCSI2_TIMING_STOP_STATE_X16_IO(n) (1 << ((16 * ((n) - 1)) + 14)) -#define ISPCSI2_TIMING_STOP_STATE_X4_IO(n) (1 << ((16 * ((n) - 1)) + 13)) -#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n) (16 * ((n) - 1)) -#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(n) \ - (0x1fff << ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n)) - -#define ISPCSI2_CTX_CTRL1(n) ((0x070) + 0x20 * (n)) -#define ISPCSI2_CTX_CTRL1_COUNT_SHIFT 8 -#define ISPCSI2_CTX_CTRL1_COUNT_MASK \ - (0xff << ISPCSI2_CTX_CTRL1_COUNT_SHIFT) -#define ISPCSI2_CTX_CTRL1_EOF_EN (1 << 7) -#define ISPCSI2_CTX_CTRL1_EOL_EN (1 << 6) -#define ISPCSI2_CTX_CTRL1_CS_EN (1 << 5) -#define ISPCSI2_CTX_CTRL1_COUNT_UNLOCK (1 << 4) -#define ISPCSI2_CTX_CTRL1_PING_PONG (1 << 3) -#define ISPCSI2_CTX_CTRL1_CTX_EN (1 << 0) - -#define ISPCSI2_CTX_CTRL2(n) ((0x074) + 0x20 * (n)) -#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13 -#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK \ - (0x3 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT) -#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT 11 -#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK \ - (0x3 << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT) -#define ISPCSI2_CTX_CTRL2_DPCM_PRED (1 << 10) -#define ISPCSI2_CTX_CTRL2_FORMAT_SHIFT 0 -#define ISPCSI2_CTX_CTRL2_FORMAT_MASK \ - (0x3ff << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT) -#define ISPCSI2_CTX_CTRL2_FRAME_SHIFT 16 -#define ISPCSI2_CTX_CTRL2_FRAME_MASK \ - (0xffff << ISPCSI2_CTX_CTRL2_FRAME_SHIFT) - -#define ISPCSI2_CTX_DAT_OFST(n) ((0x078) + 0x20 * (n)) -#define ISPCSI2_CTX_DAT_OFST_OFST_SHIFT 0 -#define ISPCSI2_CTX_DAT_OFST_OFST_MASK \ - (0x1ffe0 << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT) - -#define ISPCSI2_CTX_DAT_PING_ADDR(n) ((0x07c) + 0x20 * (n)) -#define ISPCSI2_CTX_DAT_PONG_ADDR(n) ((0x080) + 0x20 * (n)) -#define ISPCSI2_CTX_IRQENABLE(n) ((0x084) + 0x20 * (n)) -#define ISPCSI2_CTX_IRQENABLE_ECC_CORRECTION_IRQ (1 << 8) -#define ISPCSI2_CTX_IRQENABLE_LINE_NUMBER_IRQ (1 << 7) -#define ISPCSI2_CTX_IRQENABLE_FRAME_NUMBER_IRQ (1 << 6) -#define ISPCSI2_CTX_IRQENABLE_CS_IRQ (1 << 5) -#define ISPCSI2_CTX_IRQENABLE_LE_IRQ (1 << 3) -#define ISPCSI2_CTX_IRQENABLE_LS_IRQ (1 << 2) -#define ISPCSI2_CTX_IRQENABLE_FE_IRQ (1 << 1) -#define ISPCSI2_CTX_IRQENABLE_FS_IRQ (1 << 0) - -#define ISPCSI2_CTX_IRQSTATUS(n) ((0x088) + 0x20 * (n)) -#define ISPCSI2_CTX_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 8) -#define ISPCSI2_CTX_IRQSTATUS_LINE_NUMBER_IRQ (1 << 7) -#define ISPCSI2_CTX_IRQSTATUS_FRAME_NUMBER_IRQ (1 << 6) -#define ISPCSI2_CTX_IRQSTATUS_CS_IRQ (1 << 5) -#define ISPCSI2_CTX_IRQSTATUS_LE_IRQ (1 << 3) -#define ISPCSI2_CTX_IRQSTATUS_LS_IRQ (1 << 2) -#define ISPCSI2_CTX_IRQSTATUS_FE_IRQ (1 << 1) -#define ISPCSI2_CTX_IRQSTATUS_FS_IRQ (1 << 0) - -#define ISPCSI2_CTX_CTRL3(n) ((0x08c) + 0x20 * (n)) -#define ISPCSI2_CTX_CTRL3_ALPHA_SHIFT 5 -#define ISPCSI2_CTX_CTRL3_ALPHA_MASK \ - (0x3fff << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT) - -/* This instance is for OMAP3630 only */ -#define ISPCSI2_CTX_TRANSCODEH(n) (0x000 + 0x8 * (n)) -#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT 16 -#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_MASK \ - (0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT) -#define ISPCSI2_CTX_TRANSCODEH_HSKIP_SHIFT 0 -#define ISPCSI2_CTX_TRANSCODEH_HSKIP_MASK \ - (0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT) -#define ISPCSI2_CTX_TRANSCODEV(n) (0x004 + 0x8 * (n)) -#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT 16 -#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_MASK \ - (0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT) -#define ISPCSI2_CTX_TRANSCODEV_VSKIP_SHIFT 0 -#define ISPCSI2_CTX_TRANSCODEV_VSKIP_MASK \ - (0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT) - -/* ----------------------------------------------------------------------------- - * CSI PHY registers - */ - -#define ISPCSIPHY_REG0 (0x000) -#define ISPCSIPHY_REG0_THS_TERM_SHIFT 8 -#define ISPCSIPHY_REG0_THS_TERM_MASK \ - (0xff << ISPCSIPHY_REG0_THS_TERM_SHIFT) -#define ISPCSIPHY_REG0_THS_SETTLE_SHIFT 0 -#define ISPCSIPHY_REG0_THS_SETTLE_MASK \ - (0xff << ISPCSIPHY_REG0_THS_SETTLE_SHIFT) - -#define ISPCSIPHY_REG1 (0x004) -#define ISPCSIPHY_REG1_RESET_DONE_CTRLCLK (1 << 29) -/* This field is for OMAP3630 only */ -#define ISPCSIPHY_REG1_CLOCK_MISS_DETECTOR_STATUS (1 << 25) -#define ISPCSIPHY_REG1_TCLK_TERM_SHIFT 18 -#define ISPCSIPHY_REG1_TCLK_TERM_MASK \ - (0x7f << ISPCSIPHY_REG1_TCLK_TERM_SHIFT) -#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_SHIFT 10 -#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_MASK \ - (0xff << ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN) -/* This field is for OMAP3430 only */ -#define ISPCSIPHY_REG1_TCLK_MISS_SHIFT 8 -#define ISPCSIPHY_REG1_TCLK_MISS_MASK \ - (0x3 << ISPCSIPHY_REG1_TCLK_MISS_SHIFT) -/* This field is for OMAP3630 only */ -#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT 8 -#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_MASK \ - (0x3 << ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT) -#define ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT 0 -#define ISPCSIPHY_REG1_TCLK_SETTLE_MASK \ - (0xff << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT) - -/* This register is for OMAP3630 only */ -#define ISPCSIPHY_REG2 (0x008) -#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT 30 -#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_MASK \ - (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT) -#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT 28 -#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_MASK \ - (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT) -#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT 26 -#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_MASK \ - (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT) -#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT 24 -#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_MASK \ - (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT) -#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT 0 -#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_MASK \ - (0x7fffff << ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT) - -#endif /* OMAP3_ISP_REG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispresizer.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispresizer.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispresizer.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispresizer.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1693 +0,0 @@ -/* - * ispresizer.c - * - * TI OMAP3 ISP - Resizer module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include - -#include "isp.h" -#include "ispreg.h" -#include "ispresizer.h" - -/* - * Resizer Constants - */ -#define MIN_RESIZE_VALUE 64 -#define MID_RESIZE_VALUE 512 -#define MAX_RESIZE_VALUE 1024 - -#define MIN_IN_WIDTH 32 -#define MIN_IN_HEIGHT 32 -#define MAX_IN_WIDTH_MEMORY_MODE 4095 -#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280 -#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095 -#define MAX_IN_HEIGHT 4095 - -#define MIN_OUT_WIDTH 16 -#define MIN_OUT_HEIGHT 2 -#define MAX_OUT_HEIGHT 4095 - -/* - * Resizer Use Constraints - * "TRM ES3.1, table 12-46" - */ -#define MAX_4TAP_OUT_WIDTH_ES1 1280 -#define MAX_7TAP_OUT_WIDTH_ES1 640 -#define MAX_4TAP_OUT_WIDTH_ES2 3312 -#define MAX_7TAP_OUT_WIDTH_ES2 1650 -#define MAX_4TAP_OUT_WIDTH_3630 4096 -#define MAX_7TAP_OUT_WIDTH_3630 2048 - -/* - * Constants for ratio calculation - */ -#define RESIZE_DIVISOR 256 -#define DEFAULT_PHASE 1 - -/* - * Default (and only) configuration of filter coefficients. - * 7-tap mode is for scale factors 0.25x to 0.5x. - * 4-tap mode is for scale factors 0.5x to 4.0x. - * There shouldn't be any reason to recalculate these, EVER. - */ -static const struct isprsz_coef filter_coefs = { - /* For 8-phase 4-tap horizontal filter: */ - { - 0x0000, 0x0100, 0x0000, 0x0000, - 0x03FA, 0x00F6, 0x0010, 0x0000, - 0x03F9, 0x00DB, 0x002C, 0x0000, - 0x03FB, 0x00B3, 0x0053, 0x03FF, - 0x03FD, 0x0082, 0x0084, 0x03FD, - 0x03FF, 0x0053, 0x00B3, 0x03FB, - 0x0000, 0x002C, 0x00DB, 0x03F9, - 0x0000, 0x0010, 0x00F6, 0x03FA - }, - /* For 8-phase 4-tap vertical filter: */ - { - 0x0000, 0x0100, 0x0000, 0x0000, - 0x03FA, 0x00F6, 0x0010, 0x0000, - 0x03F9, 0x00DB, 0x002C, 0x0000, - 0x03FB, 0x00B3, 0x0053, 0x03FF, - 0x03FD, 0x0082, 0x0084, 0x03FD, - 0x03FF, 0x0053, 0x00B3, 0x03FB, - 0x0000, 0x002C, 0x00DB, 0x03F9, - 0x0000, 0x0010, 0x00F6, 0x03FA - }, - /* For 4-phase 7-tap horizontal filter: */ - #define DUMMY 0 - { - 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY, - 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY, - 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY, - 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY - }, - /* For 4-phase 7-tap vertical filter: */ - { - 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY, - 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY, - 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY, - 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY - } - /* - * The dummy padding is required in 7-tap mode because of how the - * registers are arranged physically. - */ - #undef DUMMY -}; - -/* - * __resizer_get_format - helper function for getting resizer format - * @res : pointer to resizer private structure - * @pad : pad number - * @fh : V4L2 subdev file handle - * @which : wanted subdev format - * return zero - */ -static struct v4l2_mbus_framefmt * -__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); - else - return &res->formats[pad]; -} - -/* - * __resizer_get_crop - helper function for getting resizer crop rectangle - * @res : pointer to resizer private structure - * @fh : V4L2 subdev file handle - * @which : wanted subdev crop rectangle - */ -static struct v4l2_rect * -__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK); - else - return &res->crop.request; -} - -/* - * resizer_set_filters - Set resizer filters - * @res: Device context. - * @h_coeff: horizontal coefficient - * @v_coeff: vertical coefficient - * Return none - */ -static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff, - const u16 *v_coeff) -{ - struct isp_device *isp = to_isp_device(res); - u32 startaddr_h, startaddr_v, tmp_h, tmp_v; - int i; - - startaddr_h = ISPRSZ_HFILT10; - startaddr_v = ISPRSZ_VFILT10; - - for (i = 0; i < COEFF_CNT; i += 2) { - tmp_h = h_coeff[i] | - (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT); - tmp_v = v_coeff[i] | - (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT); - isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h); - isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v); - startaddr_h += 4; - startaddr_v += 4; - } -} - -/* - * resizer_set_bilinear - Chrominance horizontal algorithm select - * @res: Device context. - * @type: Filtering interpolation type. - * - * Filtering that is same as luminance processing is - * intended only for downsampling, and bilinear interpolation - * is intended only for upsampling. - */ -static void resizer_set_bilinear(struct isp_res_device *res, - enum resizer_chroma_algo type) -{ - struct isp_device *isp = to_isp_device(res); - - if (type == RSZ_BILINEAR) - isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, - ISPRSZ_CNT_CBILIN); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, - ISPRSZ_CNT_CBILIN); -} - -/* - * resizer_set_ycpos - Luminance and chrominance order - * @res: Device context. - * @order: order type. - */ -static void resizer_set_ycpos(struct isp_res_device *res, - enum v4l2_mbus_pixelcode pixelcode) -{ - struct isp_device *isp = to_isp_device(res); - - switch (pixelcode) { - case V4L2_MBUS_FMT_YUYV8_1X16: - isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, - ISPRSZ_CNT_YCPOS); - break; - case V4L2_MBUS_FMT_UYVY8_1X16: - isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, - ISPRSZ_CNT_YCPOS); - break; - default: - return; - } -} - -/* - * resizer_set_phase - Setup horizontal and vertical starting phase - * @res: Device context. - * @h_phase: horizontal phase parameters. - * @v_phase: vertical phase parameters. - * - * Horizontal and vertical phase range is 0 to 7 - */ -static void resizer_set_phase(struct isp_res_device *res, u32 h_phase, - u32 v_phase) -{ - struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; - - rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & - ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK); - rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK; - rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK; - - isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT); -} - -/* - * resizer_set_luma - Setup luminance enhancer parameters - * @res: Device context. - * @luma: Structure for luminance enhancer parameters. - * - * Algorithm select: - * 0x0: Disable - * 0x1: [-1 2 -1]/2 high-pass filter - * 0x2: [-1 -2 6 -2 -1]/4 high-pass filter - * - * Maximum gain: - * The data is coded in U4Q4 representation. - * - * Slope: - * The data is coded in U4Q4 representation. - * - * Coring offset: - * The data is coded in U8Q0 representation. - * - * The new luminance value is computed as: - * Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4. - */ -static void resizer_set_luma(struct isp_res_device *res, - struct resizer_luma_yenh *luma) -{ - struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; - - rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT) - & ISPRSZ_YENH_ALGO_MASK; - rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT) - & ISPRSZ_YENH_GAIN_MASK; - rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT) - & ISPRSZ_YENH_SLOP_MASK; - rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT) - & ISPRSZ_YENH_CORE_MASK; - - isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH); -} - -/* - * resizer_set_source - Input source select - * @res: Device context. - * @source: Input source type - * - * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from - * Preview/CCDC engine, otherwise from memory. - */ -static void resizer_set_source(struct isp_res_device *res, - enum resizer_input_entity source) -{ - struct isp_device *isp = to_isp_device(res); - - if (source == RESIZER_INPUT_MEMORY) - isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, - ISPRSZ_CNT_INPSRC); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, - ISPRSZ_CNT_INPSRC); -} - -/* - * resizer_set_ratio - Setup horizontal and vertical resizing value - * @res: Device context. - * @ratio: Structure for ratio parameters. - * - * Resizing range from 64 to 1024 - */ -static void resizer_set_ratio(struct isp_res_device *res, - const struct resizer_ratio *ratio) -{ - struct isp_device *isp = to_isp_device(res); - const u16 *h_filter, *v_filter; - u32 rgval = 0; - - rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & - ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK); - rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT) - & ISPRSZ_CNT_HRSZ_MASK; - rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT) - & ISPRSZ_CNT_VRSZ_MASK; - isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT); - - /* prepare horizontal filter coefficients */ - if (ratio->horz > MID_RESIZE_VALUE) - h_filter = &filter_coefs.h_filter_coef_7tap[0]; - else - h_filter = &filter_coefs.h_filter_coef_4tap[0]; - - /* prepare vertical filter coefficients */ - if (ratio->vert > MID_RESIZE_VALUE) - v_filter = &filter_coefs.v_filter_coef_7tap[0]; - else - v_filter = &filter_coefs.v_filter_coef_4tap[0]; - - resizer_set_filters(res, h_filter, v_filter); -} - -/* - * resizer_set_dst_size - Setup the output height and width - * @res: Device context. - * @width: Output width. - * @height: Output height. - * - * Width : - * The value must be EVEN. - * - * Height: - * The number of bytes written to SDRAM must be - * a multiple of 16-bytes if the vertical resizing factor - * is greater than 1x (upsizing) - */ -static void resizer_set_output_size(struct isp_res_device *res, - u32 width, u32 height) -{ - struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; - - dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height); - rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT) - & ISPRSZ_OUT_SIZE_HORZ_MASK; - rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT) - & ISPRSZ_OUT_SIZE_VERT_MASK; - isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE); -} - -/* - * resizer_set_output_offset - Setup memory offset for the output lines. - * @res: Device context. - * @offset: Memory offset. - * - * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte - * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth, - * the SDRAM line offset must be set on a 256-byte boundary - */ -static void resizer_set_output_offset(struct isp_res_device *res, u32 offset) -{ - struct isp_device *isp = to_isp_device(res); - - isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF); -} - -/* - * resizer_set_start - Setup vertical and horizontal start position - * @res: Device context. - * @left: Horizontal start position. - * @top: Vertical start position. - * - * Vertical start line: - * This field makes sense only when the resizer obtains its input - * from the preview engine/CCDC - * - * Horizontal start pixel: - * Pixels are coded on 16 bits for YUV and 8 bits for color separate data. - * When the resizer gets its input from SDRAM, this field must be set - * to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data - */ -static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top) -{ - struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; - - rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT) - & ISPRSZ_IN_START_HORZ_ST_MASK; - rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT) - & ISPRSZ_IN_START_VERT_ST_MASK; - - isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START); -} - -/* - * resizer_set_input_size - Setup the input size - * @res: Device context. - * @width: The range is 0 to 4095 pixels - * @height: The range is 0 to 4095 lines - */ -static void resizer_set_input_size(struct isp_res_device *res, - u32 width, u32 height) -{ - struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; - - dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height); - - rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT) - & ISPRSZ_IN_SIZE_HORZ_MASK; - rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT) - & ISPRSZ_IN_SIZE_VERT_MASK; - - isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE); -} - -/* - * resizer_set_src_offs - Setup the memory offset for the input lines - * @res: Device context. - * @offset: Memory offset. - * - * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte - * boundary; the 5 LSBs are read-only. This field must be programmed to be - * 0x0 if the resizer input is from preview engine/CCDC. - */ -static void resizer_set_input_offset(struct isp_res_device *res, u32 offset) -{ - struct isp_device *isp = to_isp_device(res); - - isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF); -} - -/* - * resizer_set_intype - Input type select - * @res: Device context. - * @type: Pixel format type. - */ -static void resizer_set_intype(struct isp_res_device *res, - enum resizer_colors_type type) -{ - struct isp_device *isp = to_isp_device(res); - - if (type == RSZ_COLOR8) - isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, - ISPRSZ_CNT_INPTYP); - else - isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, - ISPRSZ_CNT_INPTYP); -} - -/* - * __resizer_set_inaddr - Helper function for set input address - * @res : pointer to resizer private data structure - * @addr: input address - * return none - */ -static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr) -{ - struct isp_device *isp = to_isp_device(res); - - isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD); -} - -/* - * The data rate at the horizontal resizer output must not exceed half the - * functional clock or 100 MP/s, whichever is lower. According to the TRM - * there's no similar requirement for the vertical resizer output. However - * experience showed that vertical upscaling by 4 leads to SBL overflows (with - * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer - * output data rate to the functional clock or 200 MP/s, whichever is lower, - * seems to get rid of SBL overflows. - * - * The maximum data rate at the output of the horizontal resizer can thus be - * computed with - * - * max intermediate rate <= L3 clock * input height / output height - * max intermediate rate <= L3 clock / 2 - * - * The maximum data rate at the resizer input is then - * - * max input rate <= max intermediate rate * input width / output width - * - * where the input width and height are the resizer input crop rectangle size. - * The TRM doesn't clearly explain if that's a maximum instant data rate or a - * maximum average data rate. - */ -void omap3isp_resizer_max_rate(struct isp_res_device *res, - unsigned int *max_rate) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity); - const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE]; - unsigned long limit = min(pipe->l3_ick, 200000000UL); - unsigned long clock; - - clock = div_u64((u64)limit * res->crop.active.height, ofmt->height); - clock = min(clock, limit / 2); - *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width); -} - -/* - * When the resizer processes images from memory, the driver must slow down read - * requests on the input to at least comply with the internal data rate - * requirements. If the application real-time requirements can cope with slower - * processing, the resizer can be slowed down even more to put less pressure on - * the overall system. - * - * When the resizer processes images on the fly (either from the CCDC or the - * preview module), the same data rate requirements apply but they can't be - * enforced at the resizer level. The image input module (sensor, CCP2 or - * preview module) must not provide image data faster than the resizer can - * process. - * - * For live image pipelines, the data rate is set by the frame format, size and - * rate. The sensor output frame rate must not exceed the maximum resizer data - * rate. - * - * The resizer slows down read requests by inserting wait cycles in the SBL - * requests. The maximum number of 256-byte requests per second can be computed - * as (the data rate is multiplied by 2 to convert from pixels per second to - * bytes per second) - * - * request per second = data rate * 2 / 256 - * cycles per request = cycles per second / requests per second - * - * The number of cycles per second is controlled by the L3 clock, leading to - * - * cycles per request = L3 frequency / 2 * 256 / data rate - */ -static void resizer_adjust_bandwidth(struct isp_res_device *res) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity); - struct isp_device *isp = to_isp_device(res); - unsigned long l3_ick = pipe->l3_ick; - struct v4l2_fract *timeperframe; - unsigned int cycles_per_frame; - unsigned int requests_per_frame; - unsigned int cycles_per_request; - unsigned int granularity; - unsigned int minimum; - unsigned int maximum; - unsigned int value; - - if (res->input != RESIZER_INPUT_MEMORY) { - isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, - ISPSBL_SDR_REQ_RSZ_EXP_MASK); - return; - } - - switch (isp->revision) { - case ISP_REVISION_1_0: - case ISP_REVISION_2_0: - default: - granularity = 1024; - break; - - case ISP_REVISION_15_0: - granularity = 32; - break; - } - - /* Compute the minimum number of cycles per request, based on the - * pipeline maximum data rate. This is an absolute lower bound if we - * don't want SBL overflows, so round the value up. - */ - cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1, - pipe->max_rate); - minimum = DIV_ROUND_UP(cycles_per_request, granularity); - - /* Compute the maximum number of cycles per request, based on the - * requested frame rate. This is a soft upper bound to achieve a frame - * rate equal or higher than the requested value, so round the value - * down. - */ - timeperframe = &pipe->max_timeperframe; - - requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256) - * res->crop.active.height; - cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator, - timeperframe->denominator); - cycles_per_request = cycles_per_frame / requests_per_frame; - - maximum = cycles_per_request / granularity; - - value = max(minimum, maximum); - - dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value); - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, - ISPSBL_SDR_REQ_RSZ_EXP_MASK, - value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT); -} - -/* - * omap3isp_resizer_busy - Checks if ISP resizer is busy. - * - * Returns busy field from ISPRSZ_PCR register. - */ -int omap3isp_resizer_busy(struct isp_res_device *res) -{ - struct isp_device *isp = to_isp_device(res); - - return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) & - ISPRSZ_PCR_BUSY; -} - -/* - * resizer_set_inaddr - Sets the memory address of the input frame. - * @addr: 32bit memory address aligned on 32byte boundary. - */ -static void resizer_set_inaddr(struct isp_res_device *res, u32 addr) -{ - res->addr_base = addr; - - /* This will handle crop settings in stream off state */ - if (res->crop_offset) - addr += res->crop_offset & ~0x1f; - - __resizer_set_inaddr(res, addr); -} - -/* - * Configures the memory address to which the output frame is written. - * @addr: 32bit memory address aligned on 32byte boundary. - * Note: For SBL efficiency reasons the address should be on a 256-byte - * boundary. - */ -static void resizer_set_outaddr(struct isp_res_device *res, u32 addr) -{ - struct isp_device *isp = to_isp_device(res); - - /* - * Set output address. This needs to be in its own function - * because it changes often. - */ - isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT, - OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD); -} - -/* - * resizer_print_status - Prints the values of the resizer module registers. - */ -#define RSZ_PRINT_REGISTER(isp, name)\ - dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \ - isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name)) - -static void resizer_print_status(struct isp_res_device *res) -{ - struct isp_device *isp = to_isp_device(res); - - dev_dbg(isp->dev, "-------------Resizer Register dump----------\n"); - - RSZ_PRINT_REGISTER(isp, PCR); - RSZ_PRINT_REGISTER(isp, CNT); - RSZ_PRINT_REGISTER(isp, OUT_SIZE); - RSZ_PRINT_REGISTER(isp, IN_START); - RSZ_PRINT_REGISTER(isp, IN_SIZE); - RSZ_PRINT_REGISTER(isp, SDR_INADD); - RSZ_PRINT_REGISTER(isp, SDR_INOFF); - RSZ_PRINT_REGISTER(isp, SDR_OUTADD); - RSZ_PRINT_REGISTER(isp, SDR_OUTOFF); - RSZ_PRINT_REGISTER(isp, YENH); - - dev_dbg(isp->dev, "--------------------------------------------\n"); -} - -/* - * resizer_calc_ratios - Helper function for calculate resizer ratios - * @res: pointer to resizer private data structure - * @input: input frame size - * @output: output frame size - * @ratio : return calculated ratios - * return none - * - * The resizer uses a polyphase sample rate converter. The upsampling filter - * has a fixed number of phases that depend on the resizing ratio. As the ratio - * computation depends on the number of phases, we need to compute a first - * approximation and then refine it. - * - * The input/output/ratio relationship is given by the OMAP34xx TRM: - * - * - 8-phase, 4-tap mode (RSZ = 64 ~ 512) - * iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7 - * ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4 - * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024) - * iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7 - * ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7 - * - * iw and ih are the input width and height after cropping. Those equations need - * to be satisfied exactly for the resizer to work correctly. - * - * Reverting the equations, we can compute the resizing ratios with - * - * - 8-phase, 4-tap mode - * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1) - * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1) - * - 4-phase, 7-tap mode - * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1) - * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1) - * - * The ratios are integer values, and must be rounded down to ensure that the - * cropped input size is not bigger than the uncropped input size. As the ratio - * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the - * 7-tap mode equations to compute a ratio approximation. - * - * We first clamp the output size according to the hardware capabilitie to avoid - * auto-cropping the input more than required to satisfy the TRM equations. The - * minimum output size is achieved with a scaling factor of 1024. It is thus - * computed using the 7-tap equations. - * - * min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1 - * min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1 - * - * Similarly, the maximum output size is achieved with a scaling factor of 64 - * and computed using the 4-tap equations. - * - * max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1 - * max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1 - * - * The additional +255 term compensates for the round down operation performed - * by the TRM equations when shifting the value right by 8 bits. - * - * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to - * the maximum value guarantees that the ratio value will never be smaller than - * the minimum, but it could still slightly exceed the maximum. Clamping the - * ratio will thus result in a resizing factor slightly larger than the - * requested value. - * - * To accomodate that, and make sure the TRM equations are satisfied exactly, we - * compute the input crop rectangle as the last step. - * - * As if the situation wasn't complex enough, the maximum output width depends - * on the vertical resizing ratio. Fortunately, the output height doesn't - * depend on the horizontal resizing ratio. We can then start by computing the - * output height and the vertical ratio, and then move to computing the output - * width and the horizontal ratio. - */ -static void resizer_calc_ratios(struct isp_res_device *res, - struct v4l2_rect *input, - struct v4l2_mbus_framefmt *output, - struct resizer_ratio *ratio) -{ - struct isp_device *isp = to_isp_device(res); - const unsigned int spv = DEFAULT_PHASE; - const unsigned int sph = DEFAULT_PHASE; - unsigned int upscaled_width; - unsigned int upscaled_height; - unsigned int min_width; - unsigned int min_height; - unsigned int max_width; - unsigned int max_height; - unsigned int width_alignment; - - /* - * Clamp the output height based on the hardware capabilities and - * compute the vertical resizing ratio. - */ - min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1; - min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT); - max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1; - max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); - output->height = clamp(output->height, min_height, max_height); - - ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) - / (output->height - 1); - ratio->vert = clamp_t(unsigned int, ratio->vert, - MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); - - if (ratio->vert <= MID_RESIZE_VALUE) { - upscaled_height = (output->height - 1) * ratio->vert - + 32 * spv + 16; - input->height = (upscaled_height >> 8) + 4; - } else { - upscaled_height = (output->height - 1) * ratio->vert - + 64 * spv + 32; - input->height = (upscaled_height >> 8) + 7; - } - - /* - * Compute the minimum and maximum output widths based on the hardware - * capabilities. The maximum depends on the vertical resizing ratio. - */ - min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1; - min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH); - - if (ratio->vert <= MID_RESIZE_VALUE) { - switch (isp->revision) { - case ISP_REVISION_1_0: - max_width = MAX_4TAP_OUT_WIDTH_ES1; - break; - - case ISP_REVISION_2_0: - default: - max_width = MAX_4TAP_OUT_WIDTH_ES2; - break; - - case ISP_REVISION_15_0: - max_width = MAX_4TAP_OUT_WIDTH_3630; - break; - } - } else { - switch (isp->revision) { - case ISP_REVISION_1_0: - max_width = MAX_7TAP_OUT_WIDTH_ES1; - break; - - case ISP_REVISION_2_0: - default: - max_width = MAX_7TAP_OUT_WIDTH_ES2; - break; - - case ISP_REVISION_15_0: - max_width = MAX_7TAP_OUT_WIDTH_3630; - break; - } - } - max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64 - + 1, max_width); - - /* - * The output width must be even, and must be a multiple of 16 bytes - * when upscaling vertically. Clamp the output width to the valid range. - * Take the alignment into account (the maximum width in 7-tap mode on - * ES2 isn't a multiple of 8) and align the result up to make sure it - * won't be smaller than the minimum. - */ - width_alignment = ratio->vert < 256 ? 8 : 2; - output->width = clamp(output->width, min_width, - max_width & ~(width_alignment - 1)); - output->width = ALIGN(output->width, width_alignment); - - ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) - / (output->width - 1); - ratio->horz = clamp_t(unsigned int, ratio->horz, - MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); - - if (ratio->horz <= MID_RESIZE_VALUE) { - upscaled_width = (output->width - 1) * ratio->horz - + 32 * sph + 16; - input->width = (upscaled_width >> 8) + 7; - } else { - upscaled_width = (output->width - 1) * ratio->horz - + 64 * sph + 32; - input->width = (upscaled_width >> 8) + 7; - } -} - -/* - * resizer_set_crop_params - Setup hardware with cropping parameters - * @res : resizer private structure - * @crop_rect : current crop rectangle - * @ratio : resizer ratios - * return none - */ -static void resizer_set_crop_params(struct isp_res_device *res, - const struct v4l2_mbus_framefmt *input, - const struct v4l2_mbus_framefmt *output) -{ - resizer_set_ratio(res, &res->ratio); - - /* Set chrominance horizontal algorithm */ - if (res->ratio.horz >= RESIZE_DIVISOR) - resizer_set_bilinear(res, RSZ_THE_SAME); - else - resizer_set_bilinear(res, RSZ_BILINEAR); - - resizer_adjust_bandwidth(res); - - if (res->input == RESIZER_INPUT_MEMORY) { - /* Calculate additional offset for crop */ - res->crop_offset = (res->crop.active.top * input->width + - res->crop.active.left) * 2; - /* - * Write lowest 4 bits of horizontal pixel offset (in pixels), - * vertical start must be 0. - */ - resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0); - - /* - * Set start (read) address for cropping, in bytes. - * Lowest 5 bits must be zero. - */ - __resizer_set_inaddr(res, - res->addr_base + (res->crop_offset & ~0x1f)); - } else { - /* - * Set vertical start line and horizontal starting pixel. - * If the input is from CCDC/PREV, horizontal start field is - * in bytes (twice number of pixels). - */ - resizer_set_start(res, res->crop.active.left * 2, - res->crop.active.top); - /* Input address and offset must be 0 for preview/ccdc input */ - __resizer_set_inaddr(res, 0); - resizer_set_input_offset(res, 0); - } - - /* Set the input size */ - resizer_set_input_size(res, res->crop.active.width, - res->crop.active.height); -} - -static void resizer_configure(struct isp_res_device *res) -{ - struct v4l2_mbus_framefmt *informat, *outformat; - struct resizer_luma_yenh luma = {0, 0, 0, 0}; - - resizer_set_source(res, res->input); - - informat = &res->formats[RESZ_PAD_SINK]; - outformat = &res->formats[RESZ_PAD_SOURCE]; - - /* RESZ_PAD_SINK */ - if (res->input == RESIZER_INPUT_VP) - resizer_set_input_offset(res, 0); - else - resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2); - - /* YUV422 interleaved, default phase, no luma enhancement */ - resizer_set_intype(res, RSZ_YUV422); - resizer_set_ycpos(res, informat->code); - resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE); - resizer_set_luma(res, &luma); - - /* RESZ_PAD_SOURCE */ - resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32)); - resizer_set_output_size(res, outformat->width, outformat->height); - - resizer_set_crop_params(res, informat, outformat); -} - -/* ----------------------------------------------------------------------------- - * Interrupt handling - */ - -static void resizer_enable_oneshot(struct isp_res_device *res) -{ - struct isp_device *isp = to_isp_device(res); - - isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR, - ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT); -} - -void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res) -{ - /* - * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun - * condition, the module was paused and now we have a buffer queued - * on the output again. Restart the pipeline if running in continuous - * mode. - */ - if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS && - res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) { - resizer_enable_oneshot(res); - isp_video_dmaqueue_flags_clr(&res->video_out); - } -} - -static void resizer_isr_buffer(struct isp_res_device *res) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity); - struct isp_buffer *buffer; - int restart = 0; - - if (res->state == ISP_PIPELINE_STREAM_STOPPED) - return; - - /* Complete the output buffer and, if reading from memory, the input - * buffer. - */ - buffer = omap3isp_video_buffer_next(&res->video_out, res->error); - if (buffer != NULL) { - resizer_set_outaddr(res, buffer->isp_addr); - restart = 1; - } - - pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; - - if (res->input == RESIZER_INPUT_MEMORY) { - buffer = omap3isp_video_buffer_next(&res->video_in, 0); - if (buffer != NULL) - resizer_set_inaddr(res, buffer->isp_addr); - pipe->state |= ISP_PIPELINE_IDLE_INPUT; - } - - if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) { - if (isp_pipeline_ready(pipe)) - omap3isp_pipeline_set_stream(pipe, - ISP_PIPELINE_STREAM_SINGLESHOT); - } else { - /* If an underrun occurs, the video queue operation handler will - * restart the resizer. Otherwise restart it immediately. - */ - if (restart) - resizer_enable_oneshot(res); - } - - res->error = 0; -} - -/* - * omap3isp_resizer_isr - ISP resizer interrupt handler - * - * Manage the resizer video buffers and configure shadowed and busy-locked - * registers. - */ -void omap3isp_resizer_isr(struct isp_res_device *res) -{ - struct v4l2_mbus_framefmt *informat, *outformat; - - if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping)) - return; - - if (res->applycrop) { - outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE, - V4L2_SUBDEV_FORMAT_ACTIVE); - informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - resizer_set_crop_params(res, informat, outformat); - res->applycrop = 0; - } - - resizer_isr_buffer(res); -} - -/* ----------------------------------------------------------------------------- - * ISP video operations - */ - -static int resizer_video_queue(struct isp_video *video, - struct isp_buffer *buffer) -{ - struct isp_res_device *res = &video->isp->isp_res; - - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - resizer_set_inaddr(res, buffer->isp_addr); - - /* - * We now have a buffer queued on the output. Despite what the - * TRM says, the resizer can't be restarted immediately. - * Enabling it in one shot mode in the middle of a frame (or at - * least asynchronously to the frame) results in the output - * being shifted randomly left/right and up/down, as if the - * hardware didn't synchronize itself to the beginning of the - * frame correctly. - * - * Restart the resizer on the next sync interrupt if running in - * continuous mode or when starting the stream. - */ - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - resizer_set_outaddr(res, buffer->isp_addr); - - return 0; -} - -static const struct isp_video_operations resizer_video_ops = { - .queue = resizer_video_queue, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -/* - * resizer_set_stream - Enable/Disable streaming on resizer subdev - * @sd: ISP resizer V4L2 subdev - * @enable: 1 == Enable, 0 == Disable - * - * The resizer hardware can't be enabled without a memory buffer to write to. - * As the s_stream operation is called in response to a STREAMON call without - * any buffer queued yet, just update the state field and return immediately. - * The resizer will be enabled in resizer_video_queue(). - */ -static int resizer_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct isp_res_device *res = v4l2_get_subdevdata(sd); - struct isp_video *video_out = &res->video_out; - struct isp_device *isp = to_isp_device(res); - struct device *dev = to_device(res); - - if (res->state == ISP_PIPELINE_STREAM_STOPPED) { - if (enable == ISP_PIPELINE_STREAM_STOPPED) - return 0; - - omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER); - resizer_configure(res); - res->error = 0; - resizer_print_status(res); - } - - switch (enable) { - case ISP_PIPELINE_STREAM_CONTINUOUS: - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE); - if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) { - resizer_enable_oneshot(res); - isp_video_dmaqueue_flags_clr(video_out); - } - break; - - case ISP_PIPELINE_STREAM_SINGLESHOT: - if (res->input == RESIZER_INPUT_MEMORY) - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ); - omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE); - - resizer_enable_oneshot(res); - break; - - case ISP_PIPELINE_STREAM_STOPPED: - if (omap3isp_module_sync_idle(&sd->entity, &res->wait, - &res->stopping)) - dev_dbg(dev, "%s: module stop timeout.\n", sd->name); - omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ | - OMAP3_ISP_SBL_RESIZER_WRITE); - omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER); - isp_video_dmaqueue_flags_clr(video_out); - break; - } - - res->state = enable; - return 0; -} - -/* - * resizer_g_crop - handle get crop subdev operation - * @sd : pointer to v4l2 subdev structure - * @pad : subdev pad - * @crop : pointer to crop structure - * @which : active or try format - * return zero - */ -static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) -{ - struct isp_res_device *res = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - struct resizer_ratio ratio; - - /* Only sink pad has crop capability */ - if (crop->pad != RESZ_PAD_SINK) - return -EINVAL; - - format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which); - crop->rect = *__resizer_get_crop(res, fh, crop->which); - resizer_calc_ratios(res, &crop->rect, format, &ratio); - - return 0; -} - -/* - * resizer_try_crop - mangles crop parameters. - */ -static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink, - const struct v4l2_mbus_framefmt *source, - struct v4l2_rect *crop) -{ - const unsigned int spv = DEFAULT_PHASE; - const unsigned int sph = DEFAULT_PHASE; - - /* Crop rectangle is constrained to the output size so that zoom ratio - * cannot exceed +/-4.0. - */ - unsigned int min_width = - ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7; - unsigned int min_height = - ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4; - unsigned int max_width = - ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7; - unsigned int max_height = - ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7; - - crop->width = clamp_t(u32, crop->width, min_width, max_width); - crop->height = clamp_t(u32, crop->height, min_height, max_height); - - /* Crop can not go beyond of the input rectangle */ - crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH); - crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH, - sink->width - crop->left); - crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT); - crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT, - sink->height - crop->top); -} - -/* - * resizer_s_crop - handle set crop subdev operation - * @sd : pointer to v4l2 subdev structure - * @pad : subdev pad - * @crop : pointer to crop structure - * @which : active or try format - * return -EINVAL or zero when succeed - */ -static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) -{ - struct isp_res_device *res = v4l2_get_subdevdata(sd); - struct isp_device *isp = to_isp_device(res); - struct v4l2_mbus_framefmt *format_sink, *format_source; - struct resizer_ratio ratio; - - /* Only sink pad has crop capability */ - if (crop->pad != RESZ_PAD_SINK) - return -EINVAL; - - format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, - crop->which); - format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, - crop->which); - - dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__, - crop->rect.left, crop->rect.top, crop->rect.width, - crop->rect.height, crop->which); - - dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__, - format_sink->width, format_sink->height, - format_source->width, format_source->height); - - resizer_try_crop(format_sink, format_source, &crop->rect); - *__resizer_get_crop(res, fh, crop->which) = crop->rect; - resizer_calc_ratios(res, &crop->rect, format_source, &ratio); - - if (crop->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - - res->ratio = ratio; - res->crop.active = crop->rect; - - /* - * s_crop can be called while streaming is on. In this case - * the crop values will be set in the next IRQ. - */ - if (res->state != ISP_PIPELINE_STREAM_STOPPED) - res->applycrop = 1; - - return 0; -} - -/* resizer pixel formats */ -static const unsigned int resizer_formats[] = { - V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, -}; - -static unsigned int resizer_max_in_width(struct isp_res_device *res) -{ - struct isp_device *isp = to_isp_device(res); - - if (res->input == RESIZER_INPUT_MEMORY) { - return MAX_IN_WIDTH_MEMORY_MODE; - } else { - if (isp->revision == ISP_REVISION_1_0) - return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1; - else - return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2; - } -} - -/* - * resizer_try_format - Handle try format by pad subdev method - * @res : ISP resizer device - * @fh : V4L2 subdev file handle - * @pad : pad num - * @fmt : pointer to v4l2 format structure - * @which : wanted subdev format - */ -static void resizer_try_format(struct isp_res_device *res, - struct v4l2_subdev_fh *fh, unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - struct v4l2_mbus_framefmt *format; - struct resizer_ratio ratio; - struct v4l2_rect crop; - - switch (pad) { - case RESZ_PAD_SINK: - if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 && - fmt->code != V4L2_MBUS_FMT_UYVY8_1X16) - fmt->code = V4L2_MBUS_FMT_YUYV8_1X16; - - fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH, - resizer_max_in_width(res)); - fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT, - MAX_IN_HEIGHT); - break; - - case RESZ_PAD_SOURCE: - format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which); - fmt->code = format->code; - - crop = *__resizer_get_crop(res, fh, which); - resizer_calc_ratios(res, &crop, fmt, &ratio); - break; - } - - fmt->colorspace = V4L2_COLORSPACE_JPEG; - fmt->field = V4L2_FIELD_NONE; -} - -/* - * resizer_enum_mbus_code - Handle pixel format enumeration - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @code : pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct isp_res_device *res = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - if (code->pad == RESZ_PAD_SINK) { - if (code->index >= ARRAY_SIZE(resizer_formats)) - return -EINVAL; - - code->code = resizer_formats[code->index]; - } else { - if (code->index != 0) - return -EINVAL; - - format = __resizer_get_format(res, fh, RESZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); - code->code = format->code; - } - - return 0; -} - -static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct isp_res_device *res = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * resizer_get_format - Handle get format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @fmt : pointer to v4l2 subdev format structure - * return -EINVAL or zero on sucess - */ -static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_res_device *res = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __resizer_get_format(res, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -/* - * resizer_set_format - Handle set format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle - * @fmt : pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct isp_res_device *res = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - struct v4l2_rect *crop; - - format = __resizer_get_format(res, fh, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - if (fmt->pad == RESZ_PAD_SINK) { - /* reset crop rectangle */ - crop = __resizer_get_crop(res, fh, fmt->which); - crop->left = 0; - crop->top = 0; - crop->width = fmt->format.width; - crop->height = fmt->format.height; - - /* Propagate the format from sink to source */ - format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, - fmt->which); - *format = fmt->format; - resizer_try_format(res, fh, RESZ_PAD_SOURCE, format, - fmt->which); - } - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Compute and store the active crop rectangle and resizer - * ratios. format already points to the source pad active - * format. - */ - res->crop.active = res->crop.request; - resizer_calc_ratios(res, &res->crop.active, format, - &res->ratio); - } - - return 0; -} - -/* - * resizer_init_formats - Initialize formats on all pads - * @sd: ISP resizer V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. - */ -static int resizer_init_formats(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = RESZ_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = V4L2_MBUS_FMT_YUYV8_1X16; - format.format.width = 4096; - format.format.height = 4096; - resizer_set_format(sd, fh, &format); - - return 0; -} - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = { - .s_stream = resizer_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = { - .enum_mbus_code = resizer_enum_mbus_code, - .enum_frame_size = resizer_enum_frame_size, - .get_fmt = resizer_get_format, - .set_fmt = resizer_set_format, - .get_crop = resizer_g_crop, - .set_crop = resizer_s_crop, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops resizer_v4l2_ops = { - .video = &resizer_v4l2_video_ops, - .pad = &resizer_v4l2_pad_ops, -}; - -/* subdev internal operations */ -static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = { - .open = resizer_init_formats, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -/* - * resizer_link_setup - Setup resizer connections. - * @entity : Pointer to media entity structure - * @local : Pointer to local pad array - * @remote : Pointer to remote pad array - * @flags : Link flags - * return -EINVAL or zero on success - */ -static int resizer_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct isp_res_device *res = v4l2_get_subdevdata(sd); - - switch (local->index | media_entity_type(remote->entity)) { - case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE: - /* read from memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (res->input == RESIZER_INPUT_VP) - return -EBUSY; - res->input = RESIZER_INPUT_MEMORY; - } else { - if (res->input == RESIZER_INPUT_MEMORY) - res->input = RESIZER_INPUT_NONE; - } - break; - - case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: - /* read from ccdc or previewer */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (res->input == RESIZER_INPUT_MEMORY) - return -EBUSY; - res->input = RESIZER_INPUT_VP; - } else { - if (res->input == RESIZER_INPUT_VP) - res->input = RESIZER_INPUT_NONE; - } - break; - - case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: - /* resizer always write to memory */ - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* media operations */ -static const struct media_entity_operations resizer_media_ops = { - .link_setup = resizer_link_setup, -}; - -/* - * resizer_init_entities - Initialize resizer subdev and media entity. - * @res : Pointer to resizer device structure - * return -ENOMEM or zero on success - */ -static int resizer_init_entities(struct isp_res_device *res) -{ - struct v4l2_subdev *sd = &res->subdev; - struct media_pad *pads = res->pads; - struct media_entity *me = &sd->entity; - int ret; - - res->input = RESIZER_INPUT_NONE; - - v4l2_subdev_init(sd, &resizer_v4l2_ops); - sd->internal_ops = &resizer_v4l2_internal_ops; - strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for isp subdevs */ - v4l2_set_subdevdata(sd, res); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - me->ops = &resizer_media_ops; - ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0); - if (ret < 0) - return ret; - - resizer_init_formats(sd, NULL); - - res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - res->video_in.ops = &resizer_video_ops; - res->video_in.isp = to_isp_device(res); - res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; - res->video_in.bpl_alignment = 32; - res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - res->video_out.ops = &resizer_video_ops; - res->video_out.isp = to_isp_device(res); - res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; - res->video_out.bpl_alignment = 32; - - ret = omap3isp_video_init(&res->video_in, "resizer"); - if (ret < 0) - return ret; - - ret = omap3isp_video_init(&res->video_out, "resizer"); - if (ret < 0) - return ret; - - /* Connect the video nodes to the resizer subdev. */ - ret = media_entity_create_link(&res->video_in.video.entity, 0, - &res->subdev.entity, RESZ_PAD_SINK, 0); - if (ret < 0) - return ret; - - ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, - &res->video_out.video.entity, 0, 0); - if (ret < 0) - return ret; - - return 0; -} - -void omap3isp_resizer_unregister_entities(struct isp_res_device *res) -{ - media_entity_cleanup(&res->subdev.entity); - - v4l2_device_unregister_subdev(&res->subdev); - omap3isp_video_unregister(&res->video_in); - omap3isp_video_unregister(&res->video_out); -} - -int omap3isp_resizer_register_entities(struct isp_res_device *res, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &res->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&res->video_in, vdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&res->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_resizer_unregister_entities(res); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP resizer initialization and cleanup - */ - -void omap3isp_resizer_cleanup(struct isp_device *isp) -{ -} - -/* - * isp_resizer_init - Resizer initialization. - * @isp : Pointer to ISP device - * return -ENOMEM or zero on success - */ -int omap3isp_resizer_init(struct isp_device *isp) -{ - struct isp_res_device *res = &isp->isp_res; - int ret; - - init_waitqueue_head(&res->wait); - atomic_set(&res->stopping, 0); - ret = resizer_init_entities(res); - if (ret < 0) - goto out; - -out: - if (ret) - omap3isp_resizer_cleanup(isp); - - return ret; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispresizer.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispresizer.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispresizer.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispresizer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -/* - * ispresizer.h - * - * TI OMAP3 ISP - Resizer module - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_RESIZER_H -#define OMAP3_ISP_RESIZER_H - -#include - -/* - * Constants for filter coefficents count - */ -#define COEFF_CNT 32 - -/* - * struct isprsz_coef - Structure for resizer filter coeffcients. - * @h_filter_coef_4tap: Horizontal filter coefficients for 8-phase/4-tap - * mode (.5x-4x) - * @v_filter_coef_4tap: Vertical filter coefficients for 8-phase/4-tap - * mode (.5x-4x) - * @h_filter_coef_7tap: Horizontal filter coefficients for 4-phase/7-tap - * mode (.25x-.5x) - * @v_filter_coef_7tap: Vertical filter coefficients for 4-phase/7-tap - * mode (.25x-.5x) - */ -struct isprsz_coef { - u16 h_filter_coef_4tap[32]; - u16 v_filter_coef_4tap[32]; - /* Every 8th value is a dummy value in the following arrays: */ - u16 h_filter_coef_7tap[32]; - u16 v_filter_coef_7tap[32]; -}; - -/* Chrominance horizontal algorithm */ -enum resizer_chroma_algo { - RSZ_THE_SAME = 0, /* Chrominance the same as Luminance */ - RSZ_BILINEAR = 1, /* Chrominance uses bilinear interpolation */ -}; - -/* Resizer input type select */ -enum resizer_colors_type { - RSZ_YUV422 = 0, /* YUV422 color is interleaved */ - RSZ_COLOR8 = 1, /* Color separate data on 8 bits */ -}; - -/* - * Structure for horizontal and vertical resizing value - */ -struct resizer_ratio { - u32 horz; - u32 vert; -}; - -/* - * Structure for luminance enhancer parameters. - */ -struct resizer_luma_yenh { - u8 algo; /* algorithm select. */ - u8 gain; /* maximum gain. */ - u8 slope; /* slope. */ - u8 core; /* core offset. */ -}; - -enum resizer_input_entity { - RESIZER_INPUT_NONE, - RESIZER_INPUT_VP, /* input video port - prev or ccdc */ - RESIZER_INPUT_MEMORY, -}; - -/* Sink and source resizer pads */ -#define RESZ_PAD_SINK 0 -#define RESZ_PAD_SOURCE 1 -#define RESZ_PADS_NUM 2 - -/* - * struct isp_res_device - OMAP3 ISP resizer module - * @crop.request: Crop rectangle requested by the user - * @crop.active: Active crop rectangle (based on hardware requirements) - */ -struct isp_res_device { - struct v4l2_subdev subdev; - struct media_pad pads[RESZ_PADS_NUM]; - struct v4l2_mbus_framefmt formats[RESZ_PADS_NUM]; - - enum resizer_input_entity input; - struct isp_video video_in; - struct isp_video video_out; - unsigned int error; - - u32 addr_base; /* stored source buffer address in memory mode */ - u32 crop_offset; /* additional offset for crop in memory mode */ - struct resizer_ratio ratio; - int pm_state; - unsigned int applycrop:1; - enum isp_pipeline_stream_state state; - wait_queue_head_t wait; - atomic_t stopping; - - struct { - struct v4l2_rect request; - struct v4l2_rect active; - } crop; -}; - -struct isp_device; - -int omap3isp_resizer_init(struct isp_device *isp); -void omap3isp_resizer_cleanup(struct isp_device *isp); - -int omap3isp_resizer_register_entities(struct isp_res_device *res, - struct v4l2_device *vdev); -void omap3isp_resizer_unregister_entities(struct isp_res_device *res); -void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res); -void omap3isp_resizer_isr(struct isp_res_device *isp_res); - -void omap3isp_resizer_max_rate(struct isp_res_device *res, - unsigned int *max_rate); - -void omap3isp_resizer_suspend(struct isp_res_device *isp_res); - -void omap3isp_resizer_resume(struct isp_res_device *isp_res); - -int omap3isp_resizer_busy(struct isp_res_device *isp_res); - -#endif /* OMAP3_ISP_RESIZER_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispstat.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispstat.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispstat.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispstat.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1092 +0,0 @@ -/* - * ispstat.c - * - * TI OMAP3 ISP - Statistics core - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc - * - * Contacts: David Cohen - * Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include - -#include "isp.h" - -#define IS_COHERENT_BUF(stat) ((stat)->dma_ch >= 0) - -/* - * MAGIC_SIZE must always be the greatest common divisor of - * AEWB_PACKET_SIZE and AF_PAXEL_SIZE. - */ -#define MAGIC_SIZE 16 -#define MAGIC_NUM 0x55 - -/* HACK: AF module seems to be writing one more paxel data than it should. */ -#define AF_EXTRA_DATA OMAP3ISP_AF_PAXEL_SIZE - -/* - * HACK: H3A modules go to an invalid state after have a SBL overflow. It makes - * the next buffer to start to be written in the same point where the overflow - * occurred instead of the configured address. The only known way to make it to - * go back to a valid state is having a valid buffer processing. Of course it - * requires at least a doubled buffer size to avoid an access to invalid memory - * region. But it does not fix everything. It may happen more than one - * consecutive SBL overflows. In that case, it might be unpredictable how many - * buffers the allocated memory should fit. For that case, a recover - * configuration was created. It produces the minimum buffer size for each H3A - * module and decrease the change for more SBL overflows. This recover state - * will be enabled every time a SBL overflow occur. As the output buffer size - * isn't big, it's possible to have an extra size able to fit many recover - * buffers making it extreamily unlikely to have an access to invalid memory - * region. - */ -#define NUM_H3A_RECOVER_BUFS 10 - -/* - * HACK: Because of HW issues the generic layer sometimes need to have - * different behaviour for different statistic modules. - */ -#define IS_H3A_AF(stat) ((stat) == &(stat)->isp->isp_af) -#define IS_H3A_AEWB(stat) ((stat) == &(stat)->isp->isp_aewb) -#define IS_H3A(stat) (IS_H3A_AF(stat) || IS_H3A_AEWB(stat)) - -static void __isp_stat_buf_sync_magic(struct ispstat *stat, - struct ispstat_buffer *buf, - u32 buf_size, enum dma_data_direction dir, - void (*dma_sync)(struct device *, - dma_addr_t, unsigned long, size_t, - enum dma_data_direction)) -{ - struct device *dev = stat->isp->dev; - struct page *pg; - dma_addr_t dma_addr; - u32 offset; - - /* Initial magic words */ - pg = vmalloc_to_page(buf->virt_addr); - dma_addr = pfn_to_dma(dev, page_to_pfn(pg)); - dma_sync(dev, dma_addr, 0, MAGIC_SIZE, dir); - - /* Final magic words */ - pg = vmalloc_to_page(buf->virt_addr + buf_size); - dma_addr = pfn_to_dma(dev, page_to_pfn(pg)); - offset = ((u32)buf->virt_addr + buf_size) & ~PAGE_MASK; - dma_sync(dev, dma_addr, offset, MAGIC_SIZE, dir); -} - -static void isp_stat_buf_sync_magic_for_device(struct ispstat *stat, - struct ispstat_buffer *buf, - u32 buf_size, - enum dma_data_direction dir) -{ - if (IS_COHERENT_BUF(stat)) - return; - - __isp_stat_buf_sync_magic(stat, buf, buf_size, dir, - dma_sync_single_range_for_device); -} - -static void isp_stat_buf_sync_magic_for_cpu(struct ispstat *stat, - struct ispstat_buffer *buf, - u32 buf_size, - enum dma_data_direction dir) -{ - if (IS_COHERENT_BUF(stat)) - return; - - __isp_stat_buf_sync_magic(stat, buf, buf_size, dir, - dma_sync_single_range_for_cpu); -} - -static int isp_stat_buf_check_magic(struct ispstat *stat, - struct ispstat_buffer *buf) -{ - const u32 buf_size = IS_H3A_AF(stat) ? - buf->buf_size + AF_EXTRA_DATA : buf->buf_size; - u8 *w; - u8 *end; - int ret = -EINVAL; - - isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE); - - /* Checking initial magic numbers. They shouldn't be here anymore. */ - for (w = buf->virt_addr, end = w + MAGIC_SIZE; w < end; w++) - if (likely(*w != MAGIC_NUM)) - ret = 0; - - if (ret) { - dev_dbg(stat->isp->dev, "%s: beginning magic check does not " - "match.\n", stat->subdev.name); - return ret; - } - - /* Checking magic numbers at the end. They must be still here. */ - for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE; - w < end; w++) { - if (unlikely(*w != MAGIC_NUM)) { - dev_dbg(stat->isp->dev, "%s: endding magic check does " - "not match.\n", stat->subdev.name); - return -EINVAL; - } - } - - isp_stat_buf_sync_magic_for_device(stat, buf, buf_size, - DMA_FROM_DEVICE); - - return 0; -} - -static void isp_stat_buf_insert_magic(struct ispstat *stat, - struct ispstat_buffer *buf) -{ - const u32 buf_size = IS_H3A_AF(stat) ? - stat->buf_size + AF_EXTRA_DATA : stat->buf_size; - - isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE); - - /* - * Inserting MAGIC_NUM at the beginning and end of the buffer. - * buf->buf_size is set only after the buffer is queued. For now the - * right buf_size for the current configuration is pointed by - * stat->buf_size. - */ - memset(buf->virt_addr, MAGIC_NUM, MAGIC_SIZE); - memset(buf->virt_addr + buf_size, MAGIC_NUM, MAGIC_SIZE); - - isp_stat_buf_sync_magic_for_device(stat, buf, buf_size, - DMA_BIDIRECTIONAL); -} - -static void isp_stat_buf_sync_for_device(struct ispstat *stat, - struct ispstat_buffer *buf) -{ - if (IS_COHERENT_BUF(stat)) - return; - - dma_sync_sg_for_device(stat->isp->dev, buf->iovm->sgt->sgl, - buf->iovm->sgt->nents, DMA_FROM_DEVICE); -} - -static void isp_stat_buf_sync_for_cpu(struct ispstat *stat, - struct ispstat_buffer *buf) -{ - if (IS_COHERENT_BUF(stat)) - return; - - dma_sync_sg_for_cpu(stat->isp->dev, buf->iovm->sgt->sgl, - buf->iovm->sgt->nents, DMA_FROM_DEVICE); -} - -static void isp_stat_buf_clear(struct ispstat *stat) -{ - int i; - - for (i = 0; i < STAT_MAX_BUFS; i++) - stat->buf[i].empty = 1; -} - -static struct ispstat_buffer * -__isp_stat_buf_find(struct ispstat *stat, int look_empty) -{ - struct ispstat_buffer *found = NULL; - int i; - - for (i = 0; i < STAT_MAX_BUFS; i++) { - struct ispstat_buffer *curr = &stat->buf[i]; - - /* - * Don't select the buffer which is being copied to - * userspace or used by the module. - */ - if (curr == stat->locked_buf || curr == stat->active_buf) - continue; - - /* Don't select uninitialised buffers if it's not required */ - if (!look_empty && curr->empty) - continue; - - /* Pick uninitialised buffer over anything else if look_empty */ - if (curr->empty) { - found = curr; - break; - } - - /* Choose the oldest buffer */ - if (!found || - (s32)curr->frame_number - (s32)found->frame_number < 0) - found = curr; - } - - return found; -} - -static inline struct ispstat_buffer * -isp_stat_buf_find_oldest(struct ispstat *stat) -{ - return __isp_stat_buf_find(stat, 0); -} - -static inline struct ispstat_buffer * -isp_stat_buf_find_oldest_or_empty(struct ispstat *stat) -{ - return __isp_stat_buf_find(stat, 1); -} - -static int isp_stat_buf_queue(struct ispstat *stat) -{ - if (!stat->active_buf) - return STAT_NO_BUF; - - do_gettimeofday(&stat->active_buf->ts); - - stat->active_buf->buf_size = stat->buf_size; - if (isp_stat_buf_check_magic(stat, stat->active_buf)) { - dev_dbg(stat->isp->dev, "%s: data wasn't properly written.\n", - stat->subdev.name); - return STAT_NO_BUF; - } - stat->active_buf->config_counter = stat->config_counter; - stat->active_buf->frame_number = stat->frame_number; - stat->active_buf->empty = 0; - stat->active_buf = NULL; - - return STAT_BUF_DONE; -} - -/* Get next free buffer to write the statistics to and mark it active. */ -static void isp_stat_buf_next(struct ispstat *stat) -{ - if (unlikely(stat->active_buf)) - /* Overwriting unused active buffer */ - dev_dbg(stat->isp->dev, "%s: new buffer requested without " - "queuing active one.\n", - stat->subdev.name); - else - stat->active_buf = isp_stat_buf_find_oldest_or_empty(stat); -} - -static void isp_stat_buf_release(struct ispstat *stat) -{ - unsigned long flags; - - isp_stat_buf_sync_for_device(stat, stat->locked_buf); - spin_lock_irqsave(&stat->isp->stat_lock, flags); - stat->locked_buf = NULL; - spin_unlock_irqrestore(&stat->isp->stat_lock, flags); -} - -/* Get buffer to userspace. */ -static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat, - struct omap3isp_stat_data *data) -{ - int rval = 0; - unsigned long flags; - struct ispstat_buffer *buf; - - spin_lock_irqsave(&stat->isp->stat_lock, flags); - - while (1) { - buf = isp_stat_buf_find_oldest(stat); - if (!buf) { - spin_unlock_irqrestore(&stat->isp->stat_lock, flags); - dev_dbg(stat->isp->dev, "%s: cannot find a buffer.\n", - stat->subdev.name); - return ERR_PTR(-EBUSY); - } - if (isp_stat_buf_check_magic(stat, buf)) { - dev_dbg(stat->isp->dev, "%s: current buffer has " - "corrupted data\n.", stat->subdev.name); - /* Mark empty because it doesn't have valid data. */ - buf->empty = 1; - } else { - /* Buffer isn't corrupted. */ - break; - } - } - - stat->locked_buf = buf; - - spin_unlock_irqrestore(&stat->isp->stat_lock, flags); - - if (buf->buf_size > data->buf_size) { - dev_warn(stat->isp->dev, "%s: userspace's buffer size is " - "not enough.\n", stat->subdev.name); - isp_stat_buf_release(stat); - return ERR_PTR(-EINVAL); - } - - isp_stat_buf_sync_for_cpu(stat, buf); - - rval = copy_to_user(data->buf, - buf->virt_addr, - buf->buf_size); - - if (rval) { - dev_info(stat->isp->dev, - "%s: failed copying %d bytes of stat data\n", - stat->subdev.name, rval); - buf = ERR_PTR(-EFAULT); - isp_stat_buf_release(stat); - } - - return buf; -} - -static void isp_stat_bufs_free(struct ispstat *stat) -{ - struct isp_device *isp = stat->isp; - int i; - - for (i = 0; i < STAT_MAX_BUFS; i++) { - struct ispstat_buffer *buf = &stat->buf[i]; - - if (!IS_COHERENT_BUF(stat)) { - if (IS_ERR_OR_NULL((void *)buf->iommu_addr)) - continue; - if (buf->iovm) - dma_unmap_sg(isp->dev, buf->iovm->sgt->sgl, - buf->iovm->sgt->nents, - DMA_FROM_DEVICE); - iommu_vfree(isp->iommu, buf->iommu_addr); - } else { - if (!buf->virt_addr) - continue; - dma_free_coherent(stat->isp->dev, stat->buf_alloc_size, - buf->virt_addr, buf->dma_addr); - } - buf->iommu_addr = 0; - buf->iovm = NULL; - buf->dma_addr = 0; - buf->virt_addr = NULL; - buf->empty = 1; - } - - dev_dbg(stat->isp->dev, "%s: all buffers were freed.\n", - stat->subdev.name); - - stat->buf_alloc_size = 0; - stat->active_buf = NULL; -} - -static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size) -{ - struct isp_device *isp = stat->isp; - int i; - - stat->buf_alloc_size = size; - - for (i = 0; i < STAT_MAX_BUFS; i++) { - struct ispstat_buffer *buf = &stat->buf[i]; - struct iovm_struct *iovm; - - WARN_ON(buf->dma_addr); - buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size, - IOMMU_FLAG); - if (IS_ERR((void *)buf->iommu_addr)) { - dev_err(stat->isp->dev, - "%s: Can't acquire memory for " - "buffer %d\n", stat->subdev.name, i); - isp_stat_bufs_free(stat); - return -ENOMEM; - } - - iovm = find_iovm_area(isp->iommu, buf->iommu_addr); - if (!iovm || - !dma_map_sg(isp->dev, iovm->sgt->sgl, iovm->sgt->nents, - DMA_FROM_DEVICE)) { - isp_stat_bufs_free(stat); - return -ENOMEM; - } - buf->iovm = iovm; - - buf->virt_addr = da_to_va(stat->isp->iommu, - (u32)buf->iommu_addr); - buf->empty = 1; - dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated." - "iommu_addr=0x%08lx virt_addr=0x%08lx", - stat->subdev.name, i, buf->iommu_addr, - (unsigned long)buf->virt_addr); - } - - return 0; -} - -static int isp_stat_bufs_alloc_dma(struct ispstat *stat, unsigned int size) -{ - int i; - - stat->buf_alloc_size = size; - - for (i = 0; i < STAT_MAX_BUFS; i++) { - struct ispstat_buffer *buf = &stat->buf[i]; - - WARN_ON(buf->iommu_addr); - buf->virt_addr = dma_alloc_coherent(stat->isp->dev, size, - &buf->dma_addr, GFP_KERNEL | GFP_DMA); - - if (!buf->virt_addr || !buf->dma_addr) { - dev_info(stat->isp->dev, - "%s: Can't acquire memory for " - "DMA buffer %d\n", stat->subdev.name, i); - isp_stat_bufs_free(stat); - return -ENOMEM; - } - buf->empty = 1; - - dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated." - "dma_addr=0x%08lx virt_addr=0x%08lx\n", - stat->subdev.name, i, (unsigned long)buf->dma_addr, - (unsigned long)buf->virt_addr); - } - - return 0; -} - -static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size) -{ - unsigned long flags; - - spin_lock_irqsave(&stat->isp->stat_lock, flags); - - BUG_ON(stat->locked_buf != NULL); - - /* Are the old buffers big enough? */ - if (stat->buf_alloc_size >= size) { - spin_unlock_irqrestore(&stat->isp->stat_lock, flags); - return 0; - } - - if (stat->state != ISPSTAT_DISABLED || stat->buf_processing) { - dev_info(stat->isp->dev, - "%s: trying to allocate memory when busy\n", - stat->subdev.name); - spin_unlock_irqrestore(&stat->isp->stat_lock, flags); - return -EBUSY; - } - - spin_unlock_irqrestore(&stat->isp->stat_lock, flags); - - isp_stat_bufs_free(stat); - - if (IS_COHERENT_BUF(stat)) - return isp_stat_bufs_alloc_dma(stat, size); - else - return isp_stat_bufs_alloc_iommu(stat, size); -} - -static void isp_stat_queue_event(struct ispstat *stat, int err) -{ - struct video_device *vdev = &stat->subdev.devnode; - struct v4l2_event event; - struct omap3isp_stat_event_status *status = (void *)event.u.data; - - memset(&event, 0, sizeof(event)); - if (!err) { - status->frame_number = stat->frame_number; - status->config_counter = stat->config_counter; - } else { - status->buf_err = 1; - } - event.type = stat->event_type; - v4l2_event_queue(vdev, &event); -} - - -/* - * omap3isp_stat_request_statistics - Request statistics. - * @data: Pointer to return statistics data. - * - * Returns 0 if successful. - */ -int omap3isp_stat_request_statistics(struct ispstat *stat, - struct omap3isp_stat_data *data) -{ - struct ispstat_buffer *buf; - - if (stat->state != ISPSTAT_ENABLED) { - dev_dbg(stat->isp->dev, "%s: engine not enabled.\n", - stat->subdev.name); - return -EINVAL; - } - - mutex_lock(&stat->ioctl_lock); - buf = isp_stat_buf_get(stat, data); - if (IS_ERR(buf)) { - mutex_unlock(&stat->ioctl_lock); - return PTR_ERR(buf); - } - - data->ts = buf->ts; - data->config_counter = buf->config_counter; - data->frame_number = buf->frame_number; - data->buf_size = buf->buf_size; - - buf->empty = 1; - isp_stat_buf_release(stat); - mutex_unlock(&stat->ioctl_lock); - - return 0; -} - -/* - * omap3isp_stat_config - Receives new statistic engine configuration. - * @new_conf: Pointer to config structure. - * - * Returns 0 if successful, -EINVAL if new_conf pointer is NULL, -ENOMEM if - * was unable to allocate memory for the buffer, or other errors if parameters - * are invalid. - */ -int omap3isp_stat_config(struct ispstat *stat, void *new_conf) -{ - int ret; - unsigned long irqflags; - struct ispstat_generic_config *user_cfg = new_conf; - u32 buf_size = user_cfg->buf_size; - - if (!new_conf) { - dev_dbg(stat->isp->dev, "%s: configuration is NULL\n", - stat->subdev.name); - return -EINVAL; - } - - mutex_lock(&stat->ioctl_lock); - - dev_dbg(stat->isp->dev, "%s: configuring module with buffer " - "size=0x%08lx\n", stat->subdev.name, (unsigned long)buf_size); - - ret = stat->ops->validate_params(stat, new_conf); - if (ret) { - mutex_unlock(&stat->ioctl_lock); - dev_dbg(stat->isp->dev, "%s: configuration values are " - "invalid.\n", stat->subdev.name); - return ret; - } - - if (buf_size != user_cfg->buf_size) - dev_dbg(stat->isp->dev, "%s: driver has corrected buffer size " - "request to 0x%08lx\n", stat->subdev.name, - (unsigned long)user_cfg->buf_size); - - /* - * Hack: H3A modules may need a doubled buffer size to avoid access - * to a invalid memory address after a SBL overflow. - * The buffer size is always PAGE_ALIGNED. - * Hack 2: MAGIC_SIZE is added to buf_size so a magic word can be - * inserted at the end to data integrity check purpose. - * Hack 3: AF module writes one paxel data more than it should, so - * the buffer allocation must consider it to avoid invalid memory - * access. - * Hack 4: H3A need to allocate extra space for the recover state. - */ - if (IS_H3A(stat)) { - buf_size = user_cfg->buf_size * 2 + MAGIC_SIZE; - if (IS_H3A_AF(stat)) - /* - * Adding one extra paxel data size for each recover - * buffer + 2 regular ones. - */ - buf_size += AF_EXTRA_DATA * (NUM_H3A_RECOVER_BUFS + 2); - if (stat->recover_priv) { - struct ispstat_generic_config *recover_cfg = - stat->recover_priv; - buf_size += recover_cfg->buf_size * - NUM_H3A_RECOVER_BUFS; - } - buf_size = PAGE_ALIGN(buf_size); - } else { /* Histogram */ - buf_size = PAGE_ALIGN(user_cfg->buf_size + MAGIC_SIZE); - } - - ret = isp_stat_bufs_alloc(stat, buf_size); - if (ret) { - mutex_unlock(&stat->ioctl_lock); - return ret; - } - - spin_lock_irqsave(&stat->isp->stat_lock, irqflags); - stat->ops->set_params(stat, new_conf); - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - - /* - * Returning the right future config_counter for this setup, so - * userspace can *know* when it has been applied. - */ - user_cfg->config_counter = stat->config_counter + stat->inc_config; - - /* Module has a valid configuration. */ - stat->configured = 1; - dev_dbg(stat->isp->dev, "%s: module has been successfully " - "configured.\n", stat->subdev.name); - - mutex_unlock(&stat->ioctl_lock); - - return 0; -} - -/* - * isp_stat_buf_process - Process statistic buffers. - * @buf_state: points out if buffer is ready to be processed. It's necessary - * because histogram needs to copy the data from internal memory - * before be able to process the buffer. - */ -static int isp_stat_buf_process(struct ispstat *stat, int buf_state) -{ - int ret = STAT_NO_BUF; - - if (!atomic_add_unless(&stat->buf_err, -1, 0) && - buf_state == STAT_BUF_DONE && stat->state == ISPSTAT_ENABLED) { - ret = isp_stat_buf_queue(stat); - isp_stat_buf_next(stat); - } - - return ret; -} - -int omap3isp_stat_pcr_busy(struct ispstat *stat) -{ - return stat->ops->busy(stat); -} - -int omap3isp_stat_busy(struct ispstat *stat) -{ - return omap3isp_stat_pcr_busy(stat) | stat->buf_processing | - (stat->state != ISPSTAT_DISABLED); -} - -/* - * isp_stat_pcr_enable - Disables/Enables statistic engines. - * @pcr_enable: 0/1 - Disables/Enables the engine. - * - * Must be called from ISP driver when the module is idle and synchronized - * with CCDC. - */ -static void isp_stat_pcr_enable(struct ispstat *stat, u8 pcr_enable) -{ - if ((stat->state != ISPSTAT_ENABLING && - stat->state != ISPSTAT_ENABLED) && pcr_enable) - /* Userspace has disabled the module. Aborting. */ - return; - - stat->ops->enable(stat, pcr_enable); - if (stat->state == ISPSTAT_DISABLING && !pcr_enable) - stat->state = ISPSTAT_DISABLED; - else if (stat->state == ISPSTAT_ENABLING && pcr_enable) - stat->state = ISPSTAT_ENABLED; -} - -void omap3isp_stat_suspend(struct ispstat *stat) -{ - unsigned long flags; - - spin_lock_irqsave(&stat->isp->stat_lock, flags); - - if (stat->state != ISPSTAT_DISABLED) - stat->ops->enable(stat, 0); - if (stat->state == ISPSTAT_ENABLED) - stat->state = ISPSTAT_SUSPENDED; - - spin_unlock_irqrestore(&stat->isp->stat_lock, flags); -} - -void omap3isp_stat_resume(struct ispstat *stat) -{ - /* Module will be re-enabled with its pipeline */ - if (stat->state == ISPSTAT_SUSPENDED) - stat->state = ISPSTAT_ENABLING; -} - -static void isp_stat_try_enable(struct ispstat *stat) -{ - unsigned long irqflags; - - if (stat->priv == NULL) - /* driver wasn't initialised */ - return; - - spin_lock_irqsave(&stat->isp->stat_lock, irqflags); - if (stat->state == ISPSTAT_ENABLING && !stat->buf_processing && - stat->buf_alloc_size) { - /* - * Userspace's requested to enable the engine but it wasn't yet. - * Let's do that now. - */ - stat->update = 1; - isp_stat_buf_next(stat); - stat->ops->setup_regs(stat, stat->priv); - isp_stat_buf_insert_magic(stat, stat->active_buf); - - /* - * H3A module has some hw issues which forces the driver to - * ignore next buffers even if it was disabled in the meantime. - * On the other hand, Histogram shouldn't ignore buffers anymore - * if it's being enabled. - */ - if (!IS_H3A(stat)) - atomic_set(&stat->buf_err, 0); - - isp_stat_pcr_enable(stat, 1); - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - dev_dbg(stat->isp->dev, "%s: module is enabled.\n", - stat->subdev.name); - } else { - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - } -} - -void omap3isp_stat_isr_frame_sync(struct ispstat *stat) -{ - isp_stat_try_enable(stat); -} - -void omap3isp_stat_sbl_overflow(struct ispstat *stat) -{ - unsigned long irqflags; - - spin_lock_irqsave(&stat->isp->stat_lock, irqflags); - /* - * Due to a H3A hw issue which prevents the next buffer to start from - * the correct memory address, 2 buffers must be ignored. - */ - atomic_set(&stat->buf_err, 2); - - /* - * If more than one SBL overflow happen in a row, H3A module may access - * invalid memory region. - * stat->sbl_ovl_recover is set to tell to the driver to temporarily use - * a soft configuration which helps to avoid consecutive overflows. - */ - if (stat->recover_priv) - stat->sbl_ovl_recover = 1; - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); -} - -/* - * omap3isp_stat_enable - Disable/Enable statistic engine as soon as possible - * @enable: 0/1 - Disables/Enables the engine. - * - * Client should configure all the module registers before this. - * This function can be called from a userspace request. - */ -int omap3isp_stat_enable(struct ispstat *stat, u8 enable) -{ - unsigned long irqflags; - - dev_dbg(stat->isp->dev, "%s: user wants to %s module.\n", - stat->subdev.name, enable ? "enable" : "disable"); - - /* Prevent enabling while configuring */ - mutex_lock(&stat->ioctl_lock); - - spin_lock_irqsave(&stat->isp->stat_lock, irqflags); - - if (!stat->configured && enable) { - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - mutex_unlock(&stat->ioctl_lock); - dev_dbg(stat->isp->dev, "%s: cannot enable module as it's " - "never been successfully configured so far.\n", - stat->subdev.name); - return -EINVAL; - } - - if (enable) { - if (stat->state == ISPSTAT_DISABLING) - /* Previous disabling request wasn't done yet */ - stat->state = ISPSTAT_ENABLED; - else if (stat->state == ISPSTAT_DISABLED) - /* Module is now being enabled */ - stat->state = ISPSTAT_ENABLING; - } else { - if (stat->state == ISPSTAT_ENABLING) { - /* Previous enabling request wasn't done yet */ - stat->state = ISPSTAT_DISABLED; - } else if (stat->state == ISPSTAT_ENABLED) { - /* Module is now being disabled */ - stat->state = ISPSTAT_DISABLING; - isp_stat_buf_clear(stat); - } - } - - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - mutex_unlock(&stat->ioctl_lock); - - return 0; -} - -int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable) -{ - struct ispstat *stat = v4l2_get_subdevdata(subdev); - - if (enable) { - /* - * Only set enable PCR bit if the module was previously - * enabled through ioct. - */ - isp_stat_try_enable(stat); - } else { - unsigned long flags; - /* Disable PCR bit and config enable field */ - omap3isp_stat_enable(stat, 0); - spin_lock_irqsave(&stat->isp->stat_lock, flags); - stat->ops->enable(stat, 0); - spin_unlock_irqrestore(&stat->isp->stat_lock, flags); - - /* - * If module isn't busy, a new interrupt may come or not to - * set the state to DISABLED. As Histogram needs to read its - * internal memory to clear it, let interrupt handler - * responsible of changing state to DISABLED. If the last - * interrupt is coming, it's still safe as the handler will - * ignore the second time when state is already set to DISABLED. - * It's necessary to synchronize Histogram with streamoff, once - * the module may be considered idle before last SDMA transfer - * starts if we return here. - */ - if (!omap3isp_stat_pcr_busy(stat)) - omap3isp_stat_isr(stat); - - dev_dbg(stat->isp->dev, "%s: module is being disabled\n", - stat->subdev.name); - } - - return 0; -} - -/* - * __stat_isr - Interrupt handler for statistic drivers - */ -static void __stat_isr(struct ispstat *stat, int from_dma) -{ - int ret = STAT_BUF_DONE; - int buf_processing; - unsigned long irqflags; - struct isp_pipeline *pipe; - - /* - * stat->buf_processing must be set before disable module. It's - * necessary to not inform too early the buffers aren't busy in case - * of SDMA is going to be used. - */ - spin_lock_irqsave(&stat->isp->stat_lock, irqflags); - if (stat->state == ISPSTAT_DISABLED) { - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - return; - } - buf_processing = stat->buf_processing; - stat->buf_processing = 1; - stat->ops->enable(stat, 0); - - if (buf_processing && !from_dma) { - if (stat->state == ISPSTAT_ENABLED) { - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - dev_err(stat->isp->dev, - "%s: interrupt occurred when module was still " - "processing a buffer.\n", stat->subdev.name); - ret = STAT_NO_BUF; - goto out; - } else { - /* - * Interrupt handler was called from streamoff when - * the module wasn't busy anymore to ensure it is being - * disabled after process last buffer. If such buffer - * processing has already started, no need to do - * anything else. - */ - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - return; - } - } - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - - /* If it's busy we can't process this buffer anymore */ - if (!omap3isp_stat_pcr_busy(stat)) { - if (!from_dma && stat->ops->buf_process) - /* Module still need to copy data to buffer. */ - ret = stat->ops->buf_process(stat); - if (ret == STAT_BUF_WAITING_DMA) - /* Buffer is not ready yet */ - return; - - spin_lock_irqsave(&stat->isp->stat_lock, irqflags); - - /* - * Histogram needs to read its internal memory to clear it - * before be disabled. For that reason, common statistic layer - * can return only after call stat's buf_process() operator. - */ - if (stat->state == ISPSTAT_DISABLING) { - stat->state = ISPSTAT_DISABLED; - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - stat->buf_processing = 0; - return; - } - pipe = to_isp_pipeline(&stat->subdev.entity); - stat->frame_number = atomic_read(&pipe->frame_number); - - /* - * Before this point, 'ret' stores the buffer's status if it's - * ready to be processed. Afterwards, it holds the status if - * it was processed successfully. - */ - ret = isp_stat_buf_process(stat, ret); - - if (likely(!stat->sbl_ovl_recover)) { - stat->ops->setup_regs(stat, stat->priv); - } else { - /* - * Using recover config to increase the chance to have - * a good buffer processing and make the H3A module to - * go back to a valid state. - */ - stat->update = 1; - stat->ops->setup_regs(stat, stat->recover_priv); - stat->sbl_ovl_recover = 0; - - /* - * Set 'update' in case of the module needs to use - * regular configuration after next buffer. - */ - stat->update = 1; - } - - isp_stat_buf_insert_magic(stat, stat->active_buf); - - /* - * Hack: H3A modules may access invalid memory address or send - * corrupted data to userspace if more than 1 SBL overflow - * happens in a row without re-writing its buffer's start memory - * address in the meantime. Such situation is avoided if the - * module is not immediately re-enabled when the ISR misses the - * timing to process the buffer and to setup the registers. - * Because of that, pcr_enable(1) was moved to inside this 'if' - * block. But the next interruption will still happen as during - * pcr_enable(0) the module was busy. - */ - isp_stat_pcr_enable(stat, 1); - spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); - } else { - /* - * If a SBL overflow occurs and the H3A driver misses the timing - * to process the buffer, stat->buf_err is set and won't be - * cleared now. So the next buffer will be correctly ignored. - * It's necessary due to a hw issue which makes the next H3A - * buffer to start from the memory address where the previous - * one stopped, instead of start where it was configured to. - * Do not "stat->buf_err = 0" here. - */ - - if (stat->ops->buf_process) - /* - * Driver may need to erase current data prior to - * process a new buffer. If it misses the timing, the - * next buffer might be wrong. So should be ignored. - * It happens only for Histogram. - */ - atomic_set(&stat->buf_err, 1); - - ret = STAT_NO_BUF; - dev_dbg(stat->isp->dev, "%s: cannot process buffer, " - "device is busy.\n", stat->subdev.name); - } - -out: - stat->buf_processing = 0; - isp_stat_queue_event(stat, ret != STAT_BUF_DONE); -} - -void omap3isp_stat_isr(struct ispstat *stat) -{ - __stat_isr(stat, 0); -} - -void omap3isp_stat_dma_isr(struct ispstat *stat) -{ - __stat_isr(stat, 1); -} - -static int isp_stat_init_entities(struct ispstat *stat, const char *name, - const struct v4l2_subdev_ops *sd_ops) -{ - struct v4l2_subdev *subdev = &stat->subdev; - struct media_entity *me = &subdev->entity; - - v4l2_subdev_init(subdev, sd_ops); - snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); - subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ - subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - subdev->nevents = STAT_NEVENTS; - v4l2_set_subdevdata(subdev, stat); - - stat->pad.flags = MEDIA_PAD_FL_SINK; - me->ops = NULL; - - return media_entity_init(me, 1, &stat->pad, 0); -} - -int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, - struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - struct ispstat *stat = v4l2_get_subdevdata(subdev); - - if (sub->type != stat->event_type) - return -EINVAL; - - return v4l2_event_subscribe(fh, sub); -} - -int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, - struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return v4l2_event_unsubscribe(fh, sub); -} - -void omap3isp_stat_unregister_entities(struct ispstat *stat) -{ - media_entity_cleanup(&stat->subdev.entity); - v4l2_device_unregister_subdev(&stat->subdev); -} - -int omap3isp_stat_register_entities(struct ispstat *stat, - struct v4l2_device *vdev) -{ - return v4l2_device_register_subdev(vdev, &stat->subdev); -} - -int omap3isp_stat_init(struct ispstat *stat, const char *name, - const struct v4l2_subdev_ops *sd_ops) -{ - stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL); - if (!stat->buf) - return -ENOMEM; - isp_stat_buf_clear(stat); - mutex_init(&stat->ioctl_lock); - atomic_set(&stat->buf_err, 0); - - return isp_stat_init_entities(stat, name, sd_ops); -} - -void omap3isp_stat_free(struct ispstat *stat) -{ - isp_stat_bufs_free(stat); - kfree(stat->buf); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispstat.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispstat.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispstat.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispstat.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -/* - * ispstat.h - * - * TI OMAP3 ISP - Statistics core - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc - * - * Contacts: David Cohen - * Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_STAT_H -#define OMAP3_ISP_STAT_H - -#include -#include -#include -#include - -#include "isp.h" -#include "ispvideo.h" - -#define STAT_MAX_BUFS 5 -#define STAT_NEVENTS 8 - -#define STAT_BUF_DONE 0 /* Buffer is ready */ -#define STAT_NO_BUF 1 /* An error has occurred */ -#define STAT_BUF_WAITING_DMA 2 /* Histogram only: DMA is running */ - -struct ispstat; - -struct ispstat_buffer { - unsigned long iommu_addr; - struct iovm_struct *iovm; - void *virt_addr; - dma_addr_t dma_addr; - struct timeval ts; - u32 buf_size; - u32 frame_number; - u16 config_counter; - u8 empty; -}; - -struct ispstat_ops { - /* - * Validate new params configuration. - * new_conf->buf_size value must be changed to the exact buffer size - * necessary for the new configuration if it's smaller. - */ - int (*validate_params)(struct ispstat *stat, void *new_conf); - - /* - * Save new params configuration. - * stat->priv->buf_size value must be set to the exact buffer size for - * the new configuration. - * stat->update is set to 1 if new configuration is different than - * current one. - */ - void (*set_params)(struct ispstat *stat, void *new_conf); - - /* Apply stored configuration. */ - void (*setup_regs)(struct ispstat *stat, void *priv); - - /* Enable/Disable module. */ - void (*enable)(struct ispstat *stat, int enable); - - /* Verify is module is busy. */ - int (*busy)(struct ispstat *stat); - - /* Used for specific operations during generic buf process task. */ - int (*buf_process)(struct ispstat *stat); -}; - -enum ispstat_state_t { - ISPSTAT_DISABLED = 0, - ISPSTAT_DISABLING, - ISPSTAT_ENABLED, - ISPSTAT_ENABLING, - ISPSTAT_SUSPENDED, -}; - -struct ispstat { - struct v4l2_subdev subdev; - struct media_pad pad; /* sink pad */ - - /* Control */ - unsigned configured:1; - unsigned update:1; - unsigned buf_processing:1; - unsigned sbl_ovl_recover:1; - u8 inc_config; - atomic_t buf_err; - enum ispstat_state_t state; /* enabling/disabling state */ - struct omap_dma_channel_params dma_config; - struct isp_device *isp; - void *priv; /* pointer to priv config struct */ - void *recover_priv; /* pointer to recover priv configuration */ - struct mutex ioctl_lock; /* serialize private ioctl */ - - const struct ispstat_ops *ops; - - /* Buffer */ - u8 wait_acc_frames; - u16 config_counter; - u32 frame_number; - u32 buf_size; - u32 buf_alloc_size; - int dma_ch; - unsigned long event_type; - struct ispstat_buffer *buf; - struct ispstat_buffer *active_buf; - struct ispstat_buffer *locked_buf; -}; - -struct ispstat_generic_config { - /* - * Fields must be in the same order as in: - * - isph3a_aewb_config - * - isph3a_af_config - * - isphist_config - */ - u32 buf_size; - u16 config_counter; -}; - -int omap3isp_stat_config(struct ispstat *stat, void *new_conf); -int omap3isp_stat_request_statistics(struct ispstat *stat, - struct omap3isp_stat_data *data); -int omap3isp_stat_init(struct ispstat *stat, const char *name, - const struct v4l2_subdev_ops *sd_ops); -void omap3isp_stat_free(struct ispstat *stat); -int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, - struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); -int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, - struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); -int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable); - -int omap3isp_stat_busy(struct ispstat *stat); -int omap3isp_stat_pcr_busy(struct ispstat *stat); -void omap3isp_stat_suspend(struct ispstat *stat); -void omap3isp_stat_resume(struct ispstat *stat); -int omap3isp_stat_enable(struct ispstat *stat, u8 enable); -void omap3isp_stat_sbl_overflow(struct ispstat *stat); -void omap3isp_stat_isr(struct ispstat *stat); -void omap3isp_stat_isr_frame_sync(struct ispstat *stat); -void omap3isp_stat_dma_isr(struct ispstat *stat); -int omap3isp_stat_register_entities(struct ispstat *stat, - struct v4l2_device *vdev); -void omap3isp_stat_unregister_entities(struct ispstat *stat); - -#endif /* OMAP3_ISP_STAT_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispvideo.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispvideo.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispvideo.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispvideo.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1255 +0,0 @@ -/* - * ispvideo.c - * - * TI OMAP3 ISP - Generic video node - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ispvideo.h" -#include "isp.h" - - -/* ----------------------------------------------------------------------------- - * Helper functions - */ - -static struct isp_format_info formats[] = { - { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, - V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, }, - { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, - { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, }, - { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, }, - { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, }, - { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, }, - { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, }, - { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, }, - { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, }, - { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, }, - { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, }, - { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, }, -}; - -const struct isp_format_info * -omap3isp_video_format_info(enum v4l2_mbus_pixelcode code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (formats[i].code == code) - return &formats[i]; - } - - return NULL; -} - -/* - * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format - * @video: ISP video instance - * @mbus: v4l2_mbus_framefmt format (input) - * @pix: v4l2_pix_format format (output) - * - * Fill the output pix structure with information from the input mbus format. - * The bytesperline and sizeimage fields are computed from the requested bytes - * per line value in the pix format and information from the video instance. - * - * Return the number of padding bytes at end of line. - */ -static unsigned int isp_video_mbus_to_pix(const struct isp_video *video, - const struct v4l2_mbus_framefmt *mbus, - struct v4l2_pix_format *pix) -{ - unsigned int bpl = pix->bytesperline; - unsigned int min_bpl; - unsigned int i; - - memset(pix, 0, sizeof(*pix)); - pix->width = mbus->width; - pix->height = mbus->height; - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (formats[i].code == mbus->code) - break; - } - - if (WARN_ON(i == ARRAY_SIZE(formats))) - return 0; - - min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8; - - /* Clamp the requested bytes per line value. If the maximum bytes per - * line value is zero, the module doesn't support user configurable line - * sizes. Override the requested value with the minimum in that case. - */ - if (video->bpl_max) - bpl = clamp(bpl, min_bpl, video->bpl_max); - else - bpl = min_bpl; - - if (!video->bpl_zero_padding || bpl != min_bpl) - bpl = ALIGN(bpl, video->bpl_alignment); - - pix->pixelformat = formats[i].pixelformat; - pix->bytesperline = bpl; - pix->sizeimage = pix->bytesperline * pix->height; - pix->colorspace = mbus->colorspace; - pix->field = mbus->field; - - return bpl - min_bpl; -} - -static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix, - struct v4l2_mbus_framefmt *mbus) -{ - unsigned int i; - - memset(mbus, 0, sizeof(*mbus)); - mbus->width = pix->width; - mbus->height = pix->height; - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (formats[i].pixelformat == pix->pixelformat) - break; - } - - if (WARN_ON(i == ARRAY_SIZE(formats))) - return; - - mbus->code = formats[i].code; - mbus->colorspace = pix->colorspace; - mbus->field = pix->field; -} - -static struct v4l2_subdev * -isp_video_remote_subdev(struct isp_video *video, u32 *pad) -{ - struct media_pad *remote; - - remote = media_entity_remote_source(&video->pad); - - if (remote == NULL || - media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - return NULL; - - if (pad) - *pad = remote->index; - - return media_entity_to_v4l2_subdev(remote->entity); -} - -/* Return a pointer to the ISP video instance at the far end of the pipeline. */ -static struct isp_video * -isp_video_far_end(struct isp_video *video) -{ - struct media_entity_graph graph; - struct media_entity *entity = &video->video.entity; - struct media_device *mdev = entity->parent; - struct isp_video *far_end = NULL; - - mutex_lock(&mdev->graph_mutex); - media_entity_graph_walk_start(&graph, entity); - - while ((entity = media_entity_graph_walk_next(&graph))) { - if (entity == &video->video.entity) - continue; - - if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE) - continue; - - far_end = to_isp_video(media_entity_to_video_device(entity)); - if (far_end->type != video->type) - break; - - far_end = NULL; - } - - mutex_unlock(&mdev->graph_mutex); - return far_end; -} - -/* - * Validate a pipeline by checking both ends of all links for format - * discrepancies. - * - * Compute the minimum time per frame value as the maximum of time per frame - * limits reported by every block in the pipeline. - * - * Return 0 if all formats match, or -EPIPE if at least one link is found with - * different formats on its two ends. - */ -static int isp_video_validate_pipeline(struct isp_pipeline *pipe) -{ - struct isp_device *isp = pipe->output->isp; - struct v4l2_subdev_format fmt_source; - struct v4l2_subdev_format fmt_sink; - struct media_pad *pad; - struct v4l2_subdev *subdev; - int ret; - - pipe->max_rate = pipe->l3_ick; - - subdev = isp_video_remote_subdev(pipe->output, NULL); - if (subdev == NULL) - return -EPIPE; - - while (1) { - /* Retrieve the sink format */ - pad = &subdev->entity.pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - fmt_sink.pad = pad->index; - fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_sink); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - /* Update the maximum frame rate */ - if (subdev == &isp->isp_res.subdev) - omap3isp_resizer_max_rate(&isp->isp_res, - &pipe->max_rate); - - /* Check ccdc maximum data rate when data comes from sensor - * TODO: Include ccdc rate in pipe->max_rate and compare the - * total pipe rate with the input data rate from sensor. - */ - if (subdev == &isp->isp_ccdc.subdev && pipe->input == NULL) { - unsigned int rate = UINT_MAX; - - omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate); - if (isp->isp_ccdc.vpcfg.pixelclk > rate) - return -ENOSPC; - } - - /* Retrieve the source format */ - pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - - subdev = media_entity_to_v4l2_subdev(pad->entity); - - fmt_source.pad = pad->index; - fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - /* Check if the two ends match */ - if (fmt_source.format.code != fmt_sink.format.code || - fmt_source.format.width != fmt_sink.format.width || - fmt_source.format.height != fmt_sink.format.height) - return -EPIPE; - } - - return 0; -} - -static int -__isp_video_get_format(struct isp_video *video, struct v4l2_format *format) -{ - struct v4l2_subdev_format fmt; - struct v4l2_subdev *subdev; - u32 pad; - int ret; - - subdev = isp_video_remote_subdev(video, &pad); - if (subdev == NULL) - return -EINVAL; - - mutex_lock(&video->mutex); - - fmt.pad = pad; - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); - if (ret == -ENOIOCTLCMD) - ret = -EINVAL; - - mutex_unlock(&video->mutex); - - if (ret) - return ret; - - format->type = video->type; - return isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix); -} - -static int -isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) -{ - struct v4l2_format format; - int ret; - - memcpy(&format, &vfh->format, sizeof(format)); - ret = __isp_video_get_format(video, &format); - if (ret < 0) - return ret; - - if (vfh->format.fmt.pix.pixelformat != format.fmt.pix.pixelformat || - vfh->format.fmt.pix.height != format.fmt.pix.height || - vfh->format.fmt.pix.width != format.fmt.pix.width || - vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline || - vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage) - return -EINVAL; - - return ret; -} - -/* ----------------------------------------------------------------------------- - * IOMMU management - */ - -#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8) - -/* - * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list - * @dev: Device pointer specific to the OMAP3 ISP. - * @sglist: Pointer to source Scatter gather list to allocate. - * @sglen: Number of elements of the scatter-gatter list. - * - * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if - * we ran out of memory. - */ -static dma_addr_t -ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen) -{ - struct sg_table *sgt; - u32 da; - - sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); - if (sgt == NULL) - return -ENOMEM; - - sgt->sgl = (struct scatterlist *)sglist; - sgt->nents = sglen; - sgt->orig_nents = sglen; - - da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG); - if (IS_ERR_VALUE(da)) - kfree(sgt); - - return da; -} - -/* - * ispmmu_vunmap - Unmap a device address from the ISP MMU - * @dev: Device pointer specific to the OMAP3 ISP. - * @da: Device address generated from a ispmmu_vmap call. - */ -static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da) -{ - struct sg_table *sgt; - - sgt = iommu_vunmap(isp->iommu, (u32)da); - kfree(sgt); -} - -/* ----------------------------------------------------------------------------- - * Video queue operations - */ - -static void isp_video_queue_prepare(struct isp_video_queue *queue, - unsigned int *nbuffers, unsigned int *size) -{ - struct isp_video_fh *vfh = - container_of(queue, struct isp_video_fh, queue); - struct isp_video *video = vfh->video; - - *size = vfh->format.fmt.pix.sizeimage; - if (*size == 0) - return; - - *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size)); -} - -static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) -{ - struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); - struct isp_buffer *buffer = to_isp_buffer(buf); - struct isp_video *video = vfh->video; - - if (buffer->isp_addr) { - ispmmu_vunmap(video->isp, buffer->isp_addr); - buffer->isp_addr = 0; - } -} - -static int isp_video_buffer_prepare(struct isp_video_buffer *buf) -{ - struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); - struct isp_buffer *buffer = to_isp_buffer(buf); - struct isp_video *video = vfh->video; - unsigned long addr; - - addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); - if (IS_ERR_VALUE(addr)) - return -EIO; - - if (!IS_ALIGNED(addr, 32)) { - dev_dbg(video->isp->dev, "Buffer address must be " - "aligned to 32 bytes boundary.\n"); - ispmmu_vunmap(video->isp, buffer->isp_addr); - return -EINVAL; - } - - buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage; - buffer->isp_addr = addr; - return 0; -} - -/* - * isp_video_buffer_queue - Add buffer to streaming queue - * @buf: Video buffer - * - * In memory-to-memory mode, start streaming on the pipeline if buffers are - * queued on both the input and the output, if the pipeline isn't already busy. - * If the pipeline is busy, it will be restarted in the output module interrupt - * handler. - */ -static void isp_video_buffer_queue(struct isp_video_buffer *buf) -{ - struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); - struct isp_buffer *buffer = to_isp_buffer(buf); - struct isp_video *video = vfh->video; - struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); - enum isp_pipeline_state state; - unsigned long flags; - unsigned int empty; - unsigned int start; - - empty = list_empty(&video->dmaqueue); - list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue); - - if (empty) { - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - state = ISP_PIPELINE_QUEUE_OUTPUT; - else - state = ISP_PIPELINE_QUEUE_INPUT; - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state |= state; - video->ops->queue(video, buffer); - video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED; - - start = isp_pipeline_ready(pipe); - if (start) - pipe->state |= ISP_PIPELINE_STREAM; - spin_unlock_irqrestore(&pipe->lock, flags); - - if (start) - omap3isp_pipeline_set_stream(pipe, - ISP_PIPELINE_STREAM_SINGLESHOT); - } -} - -static const struct isp_video_queue_operations isp_video_queue_ops = { - .queue_prepare = &isp_video_queue_prepare, - .buffer_prepare = &isp_video_buffer_prepare, - .buffer_queue = &isp_video_buffer_queue, - .buffer_cleanup = &isp_video_buffer_cleanup, -}; - -/* - * omap3isp_video_buffer_next - Complete the current buffer and return the next - * @video: ISP video object - * @error: Whether an error occured during capture - * - * Remove the current video buffer from the DMA queue and fill its timestamp, - * field count and state fields before waking up its completion handler. - * - * The buffer state is set to VIDEOBUF_DONE if no error occured (@error is 0) - * or VIDEOBUF_ERROR otherwise (@error is non-zero). - * - * The DMA queue is expected to contain at least one buffer. - * - * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is - * empty. - */ -struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, - unsigned int error) -{ - struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); - struct isp_video_queue *queue = video->queue; - enum isp_pipeline_state state; - struct isp_video_buffer *buf; - unsigned long flags; - struct timespec ts; - - spin_lock_irqsave(&queue->irqlock, flags); - if (WARN_ON(list_empty(&video->dmaqueue))) { - spin_unlock_irqrestore(&queue->irqlock, flags); - return NULL; - } - - buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, - irqlist); - list_del(&buf->irqlist); - spin_unlock_irqrestore(&queue->irqlock, flags); - - ktime_get_ts(&ts); - buf->vbuf.timestamp.tv_sec = ts.tv_sec; - buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; - - /* Do frame number propagation only if this is the output video node. - * Frame number either comes from the CSI receivers or it gets - * incremented here if H3A is not active. - * Note: There is no guarantee that the output buffer will finish - * first, so the input number might lag behind by 1 in some cases. - */ - if (video == pipe->output && !pipe->do_propagation) - buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number); - else - buf->vbuf.sequence = atomic_read(&pipe->frame_number); - - buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE; - - wake_up(&buf->wait); - - if (list_empty(&video->dmaqueue)) { - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - state = ISP_PIPELINE_QUEUE_OUTPUT - | ISP_PIPELINE_STREAM; - else - state = ISP_PIPELINE_QUEUE_INPUT - | ISP_PIPELINE_STREAM; - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state &= ~state; - if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS) - video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; - spin_unlock_irqrestore(&pipe->lock, flags); - return NULL; - } - - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) { - spin_lock_irqsave(&pipe->lock, flags); - pipe->state &= ~ISP_PIPELINE_STREAM; - spin_unlock_irqrestore(&pipe->lock, flags); - } - - buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, - irqlist); - buf->state = ISP_BUF_STATE_ACTIVE; - return to_isp_buffer(buf); -} - -/* - * omap3isp_video_resume - Perform resume operation on the buffers - * @video: ISP video object - * @continuous: Pipeline is in single shot mode if 0 or continous mode otherwise - * - * This function is intended to be used on suspend/resume scenario. It - * requests video queue layer to discard buffers marked as DONE if it's in - * continuous mode and requests ISP modules to queue again the ACTIVE buffer - * if there's any. - */ -void omap3isp_video_resume(struct isp_video *video, int continuous) -{ - struct isp_buffer *buf = NULL; - - if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - omap3isp_video_queue_discard_done(video->queue); - - if (!list_empty(&video->dmaqueue)) { - buf = list_first_entry(&video->dmaqueue, - struct isp_buffer, buffer.irqlist); - video->ops->queue(video, buf); - video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED; - } else { - if (continuous) - video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; - } -} - -/* ----------------------------------------------------------------------------- - * V4L2 ioctls - */ - -static int -isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) -{ - struct isp_video *video = video_drvdata(file); - - strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver)); - strlcpy(cap->card, video->video.name, sizeof(cap->card)); - strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); - cap->version = ISP_VIDEO_DRIVER_VERSION; - - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - else - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - - return 0; -} - -static int -isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - struct isp_video *video = video_drvdata(file); - - if (format->type != video->type) - return -EINVAL; - - mutex_lock(&video->mutex); - *format = vfh->format; - mutex_unlock(&video->mutex); - - return 0; -} - -static int -isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - struct isp_video *video = video_drvdata(file); - struct v4l2_mbus_framefmt fmt; - - if (format->type != video->type) - return -EINVAL; - - mutex_lock(&video->mutex); - - /* Fill the bytesperline and sizeimage fields by converting to media bus - * format and back to pixel format. - */ - isp_video_pix_to_mbus(&format->fmt.pix, &fmt); - isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix); - - vfh->format = *format; - - mutex_unlock(&video->mutex); - return 0; -} - -static int -isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format) -{ - struct isp_video *video = video_drvdata(file); - struct v4l2_subdev_format fmt; - struct v4l2_subdev *subdev; - u32 pad; - int ret; - - if (format->type != video->type) - return -EINVAL; - - subdev = isp_video_remote_subdev(video, &pad); - if (subdev == NULL) - return -EINVAL; - - isp_video_pix_to_mbus(&format->fmt.pix, &fmt.format); - - fmt.pad = pad; - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); - if (ret) - return ret == -ENOIOCTLCMD ? -EINVAL : ret; - - isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix); - return 0; -} - -static int -isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) -{ - struct isp_video *video = video_drvdata(file); - struct v4l2_subdev *subdev; - int ret; - - subdev = isp_video_remote_subdev(video, NULL); - if (subdev == NULL) - return -EINVAL; - - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, video, cropcap, cropcap); - mutex_unlock(&video->mutex); - - return ret == -ENOIOCTLCMD ? -EINVAL : ret; -} - -static int -isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct isp_video *video = video_drvdata(file); - struct v4l2_subdev_format format; - struct v4l2_subdev *subdev; - u32 pad; - int ret; - - subdev = isp_video_remote_subdev(video, &pad); - if (subdev == NULL) - return -EINVAL; - - /* Try the get crop operation first and fallback to get format if not - * implemented. - */ - ret = v4l2_subdev_call(subdev, video, g_crop, crop); - if (ret != -ENOIOCTLCMD) - return ret; - - format.pad = pad; - format.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format); - if (ret < 0) - return ret == -ENOIOCTLCMD ? -EINVAL : ret; - - crop->c.left = 0; - crop->c.top = 0; - crop->c.width = format.format.width; - crop->c.height = format.format.height; - - return 0; -} - -static int -isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct isp_video *video = video_drvdata(file); - struct v4l2_subdev *subdev; - int ret; - - subdev = isp_video_remote_subdev(video, NULL); - if (subdev == NULL) - return -EINVAL; - - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, video, s_crop, crop); - mutex_unlock(&video->mutex); - - return ret == -ENOIOCTLCMD ? -EINVAL : ret; -} - -static int -isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - struct isp_video *video = video_drvdata(file); - - if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - video->type != a->type) - return -EINVAL; - - memset(a, 0, sizeof(*a)); - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; - a->parm.output.timeperframe = vfh->timeperframe; - - return 0; -} - -static int -isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - struct isp_video *video = video_drvdata(file); - - if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - video->type != a->type) - return -EINVAL; - - if (a->parm.output.timeperframe.denominator == 0) - a->parm.output.timeperframe.denominator = 1; - - vfh->timeperframe = a->parm.output.timeperframe; - - return 0; -} - -static int -isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - - return omap3isp_video_queue_reqbufs(&vfh->queue, rb); -} - -static int -isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - - return omap3isp_video_queue_querybuf(&vfh->queue, b); -} - -static int -isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - - return omap3isp_video_queue_qbuf(&vfh->queue, b); -} - -static int -isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - - return omap3isp_video_queue_dqbuf(&vfh->queue, b, - file->f_flags & O_NONBLOCK); -} - -/* - * Stream management - * - * Every ISP pipeline has a single input and a single output. The input can be - * either a sensor or a video node. The output is always a video node. - * - * As every pipeline has an output video node, the ISP video objects at the - * pipeline output stores the pipeline state. It tracks the streaming state of - * both the input and output, as well as the availability of buffers. - * - * In sensor-to-memory mode, frames are always available at the pipeline input. - * Starting the sensor usually requires I2C transfers and must be done in - * interruptible context. The pipeline is started and stopped synchronously - * to the stream on/off commands. All modules in the pipeline will get their - * subdev set stream handler called. The module at the end of the pipeline must - * delay starting the hardware until buffers are available at its output. - * - * In memory-to-memory mode, starting/stopping the stream requires - * synchronization between the input and output. ISP modules can't be stopped - * in the middle of a frame, and at least some of the modules seem to become - * busy as soon as they're started, even if they don't receive a frame start - * event. For that reason frames need to be processed in single-shot mode. The - * driver needs to wait until a frame is completely processed and written to - * memory before restarting the pipeline for the next frame. Pipelined - * processing might be possible but requires more testing. - * - * Stream start must be delayed until buffers are available at both the input - * and output. The pipeline must be started in the videobuf queue callback with - * the buffers queue spinlock held. The modules subdev set stream operation must - * not sleep. - */ -static int -isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - struct isp_video *video = video_drvdata(file); - enum isp_pipeline_state state; - struct isp_pipeline *pipe; - struct isp_video *far_end; - unsigned long flags; - int ret; - - if (type != video->type) - return -EINVAL; - - mutex_lock(&video->stream_lock); - - if (video->streaming) { - mutex_unlock(&video->stream_lock); - return -EBUSY; - } - - /* Start streaming on the pipeline. No link touching an entity in the - * pipeline can be activated or deactivated once streaming is started. - */ - pipe = video->video.entity.pipe - ? to_isp_pipeline(&video->video.entity) : &video->pipe; - media_entity_pipeline_start(&video->video.entity, &pipe->pipe); - - /* Verify that the currently configured format matches the output of - * the connected subdev. - */ - ret = isp_video_check_format(video, vfh); - if (ret < 0) - goto error; - - video->bpl_padding = ret; - video->bpl_value = vfh->format.fmt.pix.bytesperline; - - /* Find the ISP video node connected at the far end of the pipeline and - * update the pipeline. - */ - far_end = isp_video_far_end(video); - - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT; - pipe->input = far_end; - pipe->output = video; - } else { - if (far_end == NULL) { - ret = -EPIPE; - goto error; - } - - state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT; - pipe->input = video; - pipe->output = far_end; - } - - if (video->isp->pdata->set_constraints) - video->isp->pdata->set_constraints(video->isp, true); - pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]); - - /* Validate the pipeline and update its state. */ - ret = isp_video_validate_pipeline(pipe); - if (ret < 0) - goto error; - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state &= ~ISP_PIPELINE_STREAM; - pipe->state |= state; - spin_unlock_irqrestore(&pipe->lock, flags); - - /* Set the maximum time per frame as the value requested by userspace. - * This is a soft limit that can be overridden if the hardware doesn't - * support the request limit. - */ - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - pipe->max_timeperframe = vfh->timeperframe; - - video->queue = &vfh->queue; - INIT_LIST_HEAD(&video->dmaqueue); - atomic_set(&pipe->frame_number, -1); - - ret = omap3isp_video_queue_streamon(&vfh->queue); - if (ret < 0) - goto error; - - /* In sensor-to-memory mode, the stream can be started synchronously - * to the stream on command. In memory-to-memory mode, it will be - * started when buffers are queued on both the input and output. - */ - if (pipe->input == NULL) { - ret = omap3isp_pipeline_set_stream(pipe, - ISP_PIPELINE_STREAM_CONTINUOUS); - if (ret < 0) - goto error; - spin_lock_irqsave(&video->queue->irqlock, flags); - if (list_empty(&video->dmaqueue)) - video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; - spin_unlock_irqrestore(&video->queue->irqlock, flags); - } - -error: - if (ret < 0) { - omap3isp_video_queue_streamoff(&vfh->queue); - if (video->isp->pdata->set_constraints) - video->isp->pdata->set_constraints(video->isp, false); - media_entity_pipeline_stop(&video->video.entity); - video->queue = NULL; - } - - if (!ret) - video->streaming = 1; - - mutex_unlock(&video->stream_lock); - return ret; -} - -static int -isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) -{ - struct isp_video_fh *vfh = to_isp_video_fh(fh); - struct isp_video *video = video_drvdata(file); - struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); - enum isp_pipeline_state state; - unsigned int streaming; - unsigned long flags; - - if (type != video->type) - return -EINVAL; - - mutex_lock(&video->stream_lock); - - /* Make sure we're not streaming yet. */ - mutex_lock(&vfh->queue.lock); - streaming = vfh->queue.streaming; - mutex_unlock(&vfh->queue.lock); - - if (!streaming) - goto done; - - /* Update the pipeline state. */ - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - state = ISP_PIPELINE_STREAM_OUTPUT - | ISP_PIPELINE_QUEUE_OUTPUT; - else - state = ISP_PIPELINE_STREAM_INPUT - | ISP_PIPELINE_QUEUE_INPUT; - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state &= ~state; - spin_unlock_irqrestore(&pipe->lock, flags); - - /* Stop the stream. */ - omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED); - omap3isp_video_queue_streamoff(&vfh->queue); - video->queue = NULL; - video->streaming = 0; - - if (video->isp->pdata->set_constraints) - video->isp->pdata->set_constraints(video->isp, false); - media_entity_pipeline_stop(&video->video.entity); - -done: - mutex_unlock(&video->stream_lock); - return 0; -} - -static int -isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input) -{ - if (input->index > 0) - return -EINVAL; - - strlcpy(input->name, "camera", sizeof(input->name)); - input->type = V4L2_INPUT_TYPE_CAMERA; - - return 0; -} - -static int -isp_video_g_input(struct file *file, void *fh, unsigned int *input) -{ - *input = 0; - - return 0; -} - -static int -isp_video_s_input(struct file *file, void *fh, unsigned int input) -{ - return input == 0 ? 0 : -EINVAL; -} - -static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { - .vidioc_querycap = isp_video_querycap, - .vidioc_g_fmt_vid_cap = isp_video_get_format, - .vidioc_s_fmt_vid_cap = isp_video_set_format, - .vidioc_try_fmt_vid_cap = isp_video_try_format, - .vidioc_g_fmt_vid_out = isp_video_get_format, - .vidioc_s_fmt_vid_out = isp_video_set_format, - .vidioc_try_fmt_vid_out = isp_video_try_format, - .vidioc_cropcap = isp_video_cropcap, - .vidioc_g_crop = isp_video_get_crop, - .vidioc_s_crop = isp_video_set_crop, - .vidioc_g_parm = isp_video_get_param, - .vidioc_s_parm = isp_video_set_param, - .vidioc_reqbufs = isp_video_reqbufs, - .vidioc_querybuf = isp_video_querybuf, - .vidioc_qbuf = isp_video_qbuf, - .vidioc_dqbuf = isp_video_dqbuf, - .vidioc_streamon = isp_video_streamon, - .vidioc_streamoff = isp_video_streamoff, - .vidioc_enum_input = isp_video_enum_input, - .vidioc_g_input = isp_video_g_input, - .vidioc_s_input = isp_video_s_input, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 file operations - */ - -static int isp_video_open(struct file *file) -{ - struct isp_video *video = video_drvdata(file); - struct isp_video_fh *handle; - int ret = 0; - - handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (handle == NULL) - return -ENOMEM; - - v4l2_fh_init(&handle->vfh, &video->video); - v4l2_fh_add(&handle->vfh); - - /* If this is the first user, initialise the pipeline. */ - if (omap3isp_get(video->isp) == NULL) { - ret = -EBUSY; - goto done; - } - - ret = omap3isp_pipeline_pm_use(&video->video.entity, 1); - if (ret < 0) { - omap3isp_put(video->isp); - goto done; - } - - omap3isp_video_queue_init(&handle->queue, video->type, - &isp_video_queue_ops, video->isp->dev, - sizeof(struct isp_buffer)); - - memset(&handle->format, 0, sizeof(handle->format)); - handle->format.type = video->type; - handle->timeperframe.denominator = 1; - - handle->video = video; - file->private_data = &handle->vfh; - -done: - if (ret < 0) { - v4l2_fh_del(&handle->vfh); - kfree(handle); - } - - return ret; -} - -static int isp_video_release(struct file *file) -{ - struct isp_video *video = video_drvdata(file); - struct v4l2_fh *vfh = file->private_data; - struct isp_video_fh *handle = to_isp_video_fh(vfh); - - /* Disable streaming and free the buffers queue resources. */ - isp_video_streamoff(file, vfh, video->type); - - mutex_lock(&handle->queue.lock); - omap3isp_video_queue_cleanup(&handle->queue); - mutex_unlock(&handle->queue.lock); - - omap3isp_pipeline_pm_use(&video->video.entity, 0); - - /* Release the file handle. */ - v4l2_fh_del(vfh); - kfree(handle); - file->private_data = NULL; - - omap3isp_put(video->isp); - - return 0; -} - -static unsigned int isp_video_poll(struct file *file, poll_table *wait) -{ - struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); - struct isp_video_queue *queue = &vfh->queue; - - return omap3isp_video_queue_poll(queue, file, wait); -} - -static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); - - return omap3isp_video_queue_mmap(&vfh->queue, vma); -} - -static struct v4l2_file_operations isp_video_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - .open = isp_video_open, - .release = isp_video_release, - .poll = isp_video_poll, - .mmap = isp_video_mmap, -}; - -/* ----------------------------------------------------------------------------- - * ISP video core - */ - -static const struct isp_video_operations isp_video_dummy_ops = { -}; - -int omap3isp_video_init(struct isp_video *video, const char *name) -{ - const char *direction; - int ret; - - switch (video->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - direction = "output"; - video->pad.flags = MEDIA_PAD_FL_SINK; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - direction = "input"; - video->pad.flags = MEDIA_PAD_FL_SOURCE; - break; - - default: - return -EINVAL; - } - - ret = media_entity_init(&video->video.entity, 1, &video->pad, 0); - if (ret < 0) - return ret; - - mutex_init(&video->mutex); - atomic_set(&video->active, 0); - - spin_lock_init(&video->pipe.lock); - mutex_init(&video->stream_lock); - - /* Initialize the video device. */ - if (video->ops == NULL) - video->ops = &isp_video_dummy_ops; - - video->video.fops = &isp_video_fops; - snprintf(video->video.name, sizeof(video->video.name), - "OMAP3 ISP %s %s", name, direction); - video->video.vfl_type = VFL_TYPE_GRABBER; - video->video.release = video_device_release_empty; - video->video.ioctl_ops = &isp_video_ioctl_ops; - video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED; - - video_set_drvdata(&video->video, video); - - return 0; -} - -int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) -{ - int ret; - - video->video.v4l2_dev = vdev; - - ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1); - if (ret < 0) - printk(KERN_ERR "%s: could not register video device (%d)\n", - __func__, ret); - - return ret; -} - -void omap3isp_video_unregister(struct isp_video *video) -{ - if (video_is_registered(&video->video)) { - media_entity_cleanup(&video->video.entity); - video_unregister_device(&video->video); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispvideo.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispvideo.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispvideo.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/ispvideo.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,202 +0,0 @@ -/* - * ispvideo.h - * - * TI OMAP3 ISP - Generic video node - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_VIDEO_H -#define OMAP3_ISP_VIDEO_H - -#include -#include -#include -#include -#include - -#include "ispqueue.h" - -#define ISP_VIDEO_DRIVER_NAME "ispvideo" -#define ISP_VIDEO_DRIVER_VERSION KERNEL_VERSION(0, 0, 1) - -struct isp_device; -struct isp_video; -struct v4l2_mbus_framefmt; -struct v4l2_pix_format; - -/* - * struct isp_format_info - ISP media bus format information - * @code: V4L2 media bus format code - * @truncated: V4L2 media bus format code for the same format truncated to 10 - * bits. Identical to @code if the format is 10 bits wide or less. - * @uncompressed: V4L2 media bus format code for the corresponding uncompressed - * format. Identical to @code if the format is not DPCM compressed. - * @pixelformat: V4L2 pixel format FCC identifier - * @bpp: Bits per pixel - */ -struct isp_format_info { - enum v4l2_mbus_pixelcode code; - enum v4l2_mbus_pixelcode truncated; - enum v4l2_mbus_pixelcode uncompressed; - u32 pixelformat; - unsigned int bpp; -}; - -enum isp_pipeline_stream_state { - ISP_PIPELINE_STREAM_STOPPED = 0, - ISP_PIPELINE_STREAM_CONTINUOUS = 1, - ISP_PIPELINE_STREAM_SINGLESHOT = 2, -}; - -enum isp_pipeline_state { - /* The stream has been started on the input video node. */ - ISP_PIPELINE_STREAM_INPUT = 1, - /* The stream has been started on the output video node. */ - ISP_PIPELINE_STREAM_OUTPUT = 2, - /* At least one buffer is queued on the input video node. */ - ISP_PIPELINE_QUEUE_INPUT = 4, - /* At least one buffer is queued on the output video node. */ - ISP_PIPELINE_QUEUE_OUTPUT = 8, - /* The input entity is idle, ready to be started. */ - ISP_PIPELINE_IDLE_INPUT = 16, - /* The output entity is idle, ready to be started. */ - ISP_PIPELINE_IDLE_OUTPUT = 32, - /* The pipeline is currently streaming. */ - ISP_PIPELINE_STREAM = 64, -}; - -struct isp_pipeline { - struct media_pipeline pipe; - spinlock_t lock; /* Pipeline state and queue flags */ - unsigned int state; - enum isp_pipeline_stream_state stream_state; - struct isp_video *input; - struct isp_video *output; - unsigned long l3_ick; - unsigned int max_rate; - atomic_t frame_number; - bool do_propagation; /* of frame number */ - struct v4l2_fract max_timeperframe; -}; - -#define to_isp_pipeline(__e) \ - container_of((__e)->pipe, struct isp_pipeline, pipe) - -static inline int isp_pipeline_ready(struct isp_pipeline *pipe) -{ - return pipe->state == (ISP_PIPELINE_STREAM_INPUT | - ISP_PIPELINE_STREAM_OUTPUT | - ISP_PIPELINE_QUEUE_INPUT | - ISP_PIPELINE_QUEUE_OUTPUT | - ISP_PIPELINE_IDLE_INPUT | - ISP_PIPELINE_IDLE_OUTPUT); -} - -/* - * struct isp_buffer - ISP buffer - * @buffer: ISP video buffer - * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer. - */ -struct isp_buffer { - struct isp_video_buffer buffer; - dma_addr_t isp_addr; -}; - -#define to_isp_buffer(buf) container_of(buf, struct isp_buffer, buffer) - -enum isp_video_dmaqueue_flags { - /* Set if DMA queue becomes empty when ISP_PIPELINE_STREAM_CONTINUOUS */ - ISP_VIDEO_DMAQUEUE_UNDERRUN = (1 << 0), - /* Set when queuing buffer to an empty DMA queue */ - ISP_VIDEO_DMAQUEUE_QUEUED = (1 << 1), -}; - -#define isp_video_dmaqueue_flags_clr(video) \ - ({ (video)->dmaqueue_flags = 0; }) - -/* - * struct isp_video_operations - ISP video operations - * @queue: Resume streaming when a buffer is queued. Called on VIDIOC_QBUF - * if there was no buffer previously queued. - */ -struct isp_video_operations { - int(*queue)(struct isp_video *video, struct isp_buffer *buffer); -}; - -struct isp_video { - struct video_device video; - enum v4l2_buf_type type; - struct media_pad pad; - - struct mutex mutex; /* format and crop settings */ - atomic_t active; - - struct isp_device *isp; - - unsigned int capture_mem; - unsigned int bpl_alignment; /* alignment value */ - unsigned int bpl_zero_padding; /* whether the alignment is optional */ - unsigned int bpl_max; /* maximum bytes per line value */ - unsigned int bpl_value; /* bytes per line value */ - unsigned int bpl_padding; /* padding at end of line */ - - /* Entity video node streaming */ - unsigned int streaming:1; - - /* Pipeline state */ - struct isp_pipeline pipe; - struct mutex stream_lock; /* pipeline and stream states */ - - /* Video buffers queue */ - struct isp_video_queue *queue; - struct list_head dmaqueue; - enum isp_video_dmaqueue_flags dmaqueue_flags; - - const struct isp_video_operations *ops; -}; - -#define to_isp_video(vdev) container_of(vdev, struct isp_video, video) - -struct isp_video_fh { - struct v4l2_fh vfh; - struct isp_video *video; - struct isp_video_queue queue; - struct v4l2_format format; - struct v4l2_fract timeperframe; -}; - -#define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh) -#define isp_video_queue_to_isp_video_fh(q) \ - container_of(q, struct isp_video_fh, queue) - -int omap3isp_video_init(struct isp_video *video, const char *name); -int omap3isp_video_register(struct isp_video *video, - struct v4l2_device *vdev); -void omap3isp_video_unregister(struct isp_video *video); -struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, - unsigned int error); -void omap3isp_video_resume(struct isp_video *video, int continuous); -struct media_pad *omap3isp_video_remote_pad(struct isp_video *video); - -const struct isp_format_info * -omap3isp_video_format_info(enum v4l2_mbus_pixelcode code); - -#endif /* OMAP3_ISP_VIDEO_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/luma_enhance_table.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/luma_enhance_table.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/luma_enhance_table.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/luma_enhance_table.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * luma_enhance_table.h - * - * TI OMAP3 ISP - Luminance enhancement table - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, -1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, -1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, -1047552, 1047552, 1047552, 1047552, 1048575, 1047551, 1046527, 1045503, -1044479, 1043455, 1042431, 1041407, 1040383, 1039359, 1038335, 1037311, -1036287, 1035263, 1034239, 1033215, 1032191, 1031167, 1030143, 1028096, -1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, -1028096, 1028100, 1032196, 1036292, 1040388, 1044484, 0, 0, - 0, 5, 5125, 10245, 15365, 20485, 25605, 30720, - 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, - 30720, 30720, 31743, 30719, 29695, 28671, 27647, 26623, - 25599, 24575, 23551, 22527, 21503, 20479, 19455, 18431, - 17407, 16383, 15359, 14335, 13311, 12287, 11263, 10239, - 9215, 8191, 7167, 6143, 5119, 4095, 3071, 1024, - 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, - 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -# Makefile for OMAP3 ISP driver - -ifdef CONFIG_VIDEO_OMAP3_DEBUG -EXTRA_CFLAGS += -DDEBUG -endif - -omap3-isp-objs += \ - isp.o ispqueue.o ispvideo.o \ - ispcsiphy.o ispccp2.o ispcsi2.o \ - ispccdc.o isppreview.o ispresizer.o \ - ispstat.o isph3a_aewb.o isph3a_af.o isphist.o - -obj-$(CONFIG_VIDEO_OMAP3) += omap3-isp.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/noise_filter_table.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/noise_filter_table.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/noise_filter_table.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/omap3isp/noise_filter_table.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - * noise_filter_table.h - * - * TI OMAP3 ISP - Noise filter table - * - * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2009 Texas Instruments, Inc. - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, -31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov2640.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov2640.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov2640.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov2640.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1205 +0,0 @@ -/* - * ov2640 Camera Driver - * - * Copyright (C) 2010 Alberto Panizzo - * - * Based on ov772x, ov9640 drivers and previous non merged implementations. - * - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2006, OmniVision - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VAL_SET(x, mask, rshift, lshift) \ - ((((x) >> rshift) & mask) << lshift) -/* - * DSP registers - * register offset for BANK_SEL == BANK_SEL_DSP - */ -#define R_BYPASS 0x05 /* Bypass DSP */ -#define R_BYPASS_DSP_BYPAS 0x01 /* Bypass DSP, sensor out directly */ -#define R_BYPASS_USE_DSP 0x00 /* Use the internal DSP */ -#define QS 0x44 /* Quantization Scale Factor */ -#define CTRLI 0x50 -#define CTRLI_LP_DP 0x80 -#define CTRLI_ROUND 0x40 -#define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3) -#define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0) -#define HSIZE 0x51 /* H_SIZE[7:0] (real/4) */ -#define HSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0) -#define VSIZE 0x52 /* V_SIZE[7:0] (real/4) */ -#define VSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0) -#define XOFFL 0x53 /* OFFSET_X[7:0] */ -#define XOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0) -#define YOFFL 0x54 /* OFFSET_Y[7:0] */ -#define YOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0) -#define VHYX 0x55 /* Offset and size completion */ -#define VHYX_VSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 7) -#define VHYX_HSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 3) -#define VHYX_YOFF_SET(x) VAL_SET(x, 0x3, 8, 4) -#define VHYX_XOFF_SET(x) VAL_SET(x, 0x3, 8, 0) -#define DPRP 0x56 -#define TEST 0x57 /* Horizontal size completion */ -#define TEST_HSIZE_SET(x) VAL_SET(x, 0x1, (9+2), 7) -#define ZMOW 0x5A /* Zoom: Out Width OUTW[7:0] (real/4) */ -#define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0) -#define ZMOH 0x5B /* Zoom: Out Height OUTH[7:0] (real/4) */ -#define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0) -#define ZMHH 0x5C /* Zoom: Speed and H&W completion */ -#define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4) -#define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8+2), 2) -#define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8+2), 0) -#define BPADDR 0x7C /* SDE Indirect Register Access: Address */ -#define BPDATA 0x7D /* SDE Indirect Register Access: Data */ -#define CTRL2 0x86 /* DSP Module enable 2 */ -#define CTRL2_DCW_EN 0x20 -#define CTRL2_SDE_EN 0x10 -#define CTRL2_UV_ADJ_EN 0x08 -#define CTRL2_UV_AVG_EN 0x04 -#define CTRL2_CMX_EN 0x01 -#define CTRL3 0x87 /* DSP Module enable 3 */ -#define CTRL3_BPC_EN 0x80 -#define CTRL3_WPC_EN 0x40 -#define SIZEL 0x8C /* Image Size Completion */ -#define SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6) -#define SIZEL_HSIZE8_SET(x) VAL_SET(x, 0x7, 0, 3) -#define SIZEL_VSIZE8_SET(x) VAL_SET(x, 0x7, 0, 0) -#define HSIZE8 0xC0 /* Image Horizontal Size HSIZE[10:3] */ -#define HSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0) -#define VSIZE8 0xC1 /* Image Vertical Size VSIZE[10:3] */ -#define VSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0) -#define CTRL0 0xC2 /* DSP Module enable 0 */ -#define CTRL0_AEC_EN 0x80 -#define CTRL0_AEC_SEL 0x40 -#define CTRL0_STAT_SEL 0x20 -#define CTRL0_VFIRST 0x10 -#define CTRL0_YUV422 0x08 -#define CTRL0_YUV_EN 0x04 -#define CTRL0_RGB_EN 0x02 -#define CTRL0_RAW_EN 0x01 -#define CTRL1 0xC3 /* DSP Module enable 1 */ -#define CTRL1_CIP 0x80 -#define CTRL1_DMY 0x40 -#define CTRL1_RAW_GMA 0x20 -#define CTRL1_DG 0x10 -#define CTRL1_AWB 0x08 -#define CTRL1_AWB_GAIN 0x04 -#define CTRL1_LENC 0x02 -#define CTRL1_PRE 0x01 -#define R_DVP_SP 0xD3 /* DVP output speed control */ -#define R_DVP_SP_AUTO_MODE 0x80 -#define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0); - * = sysclk (48)/(2*[6:0]) (RAW);*/ -#define IMAGE_MODE 0xDA /* Image Output Format Select */ -#define IMAGE_MODE_Y8_DVP_EN 0x40 -#define IMAGE_MODE_JPEG_EN 0x10 -#define IMAGE_MODE_YUV422 0x00 -#define IMAGE_MODE_RAW10 0x04 /* (DVP) */ -#define IMAGE_MODE_RGB565 0x08 -#define IMAGE_MODE_HREF_VSYNC 0x02 /* HREF timing select in DVP JPEG output - * mode (0 for HREF is same as sensor) */ -#define IMAGE_MODE_LBYTE_FIRST 0x01 /* Byte swap enable for DVP - * 1: Low byte first UYVY (C2[4] =0) - * VYUY (C2[4] =1) - * 0: High byte first YUYV (C2[4]=0) - * YVYU (C2[4] = 1) */ -#define RESET 0xE0 /* Reset */ -#define RESET_MICROC 0x40 -#define RESET_SCCB 0x20 -#define RESET_JPEG 0x10 -#define RESET_DVP 0x04 -#define RESET_IPU 0x02 -#define RESET_CIF 0x01 -#define REGED 0xED /* Register ED */ -#define REGED_CLK_OUT_DIS 0x10 -#define MS_SP 0xF0 /* SCCB Master Speed */ -#define SS_ID 0xF7 /* SCCB Slave ID */ -#define SS_CTRL 0xF8 /* SCCB Slave Control */ -#define SS_CTRL_ADD_AUTO_INC 0x20 -#define SS_CTRL_EN 0x08 -#define SS_CTRL_DELAY_CLK 0x04 -#define SS_CTRL_ACC_EN 0x02 -#define SS_CTRL_SEN_PASS_THR 0x01 -#define MC_BIST 0xF9 /* Microcontroller misc register */ -#define MC_BIST_RESET 0x80 /* Microcontroller Reset */ -#define MC_BIST_BOOT_ROM_SEL 0x40 -#define MC_BIST_12KB_SEL 0x20 -#define MC_BIST_12KB_MASK 0x30 -#define MC_BIST_512KB_SEL 0x08 -#define MC_BIST_512KB_MASK 0x0C -#define MC_BIST_BUSY_BIT_R 0x02 -#define MC_BIST_MC_RES_ONE_SH_W 0x02 -#define MC_BIST_LAUNCH 0x01 -#define BANK_SEL 0xFF /* Register Bank Select */ -#define BANK_SEL_DSP 0x00 -#define BANK_SEL_SENS 0x01 - -/* - * Sensor registers - * register offset for BANK_SEL == BANK_SEL_SENS - */ -#define GAIN 0x00 /* AGC - Gain control gain setting */ -#define COM1 0x03 /* Common control 1 */ -#define COM1_1_DUMMY_FR 0x40 -#define COM1_3_DUMMY_FR 0x80 -#define COM1_7_DUMMY_FR 0xC0 -#define COM1_VWIN_LSB_UXGA 0x0F -#define COM1_VWIN_LSB_SVGA 0x0A -#define COM1_VWIN_LSB_CIF 0x06 -#define REG04 0x04 /* Register 04 */ -#define REG04_DEF 0x20 /* Always set */ -#define REG04_HFLIP_IMG 0x80 /* Horizontal mirror image ON/OFF */ -#define REG04_VFLIP_IMG 0x40 /* Vertical flip image ON/OFF */ -#define REG04_VREF_EN 0x10 -#define REG04_HREF_EN 0x08 -#define REG04_AEC_SET(x) VAL_SET(x, 0x3, 0, 0) -#define REG08 0x08 /* Frame Exposure One-pin Control Pre-charge Row Num */ -#define COM2 0x09 /* Common control 2 */ -#define COM2_SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */ - /* Output drive capability */ -#define COM2_OCAP_Nx_SET(N) (((N) - 1) & 0x03) /* N = [1x .. 4x] */ -#define PID 0x0A /* Product ID Number MSB */ -#define VER 0x0B /* Product ID Number LSB */ -#define COM3 0x0C /* Common control 3 */ -#define COM3_BAND_50H 0x04 /* 0 For Banding at 60H */ -#define COM3_BAND_AUTO 0x02 /* Auto Banding */ -#define COM3_SING_FR_SNAPSH 0x01 /* 0 For enable live video output after the - * snapshot sequence*/ -#define AEC 0x10 /* AEC[9:2] Exposure Value */ -#define CLKRC 0x11 /* Internal clock */ -#define CLKRC_EN 0x80 -#define CLKRC_DIV_SET(x) (((x) - 1) & 0x1F) /* CLK = XVCLK/(x) */ -#define COM7 0x12 /* Common control 7 */ -#define COM7_SRST 0x80 /* Initiates system reset. All registers are - * set to factory default values after which - * the chip resumes normal operation */ -#define COM7_RES_UXGA 0x00 /* Resolution selectors for UXGA */ -#define COM7_RES_SVGA 0x40 /* SVGA */ -#define COM7_RES_CIF 0x20 /* CIF */ -#define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */ -#define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */ -#define COM8 0x13 /* Common control 8 */ -#define COM8_DEF 0xC0 /* Banding filter ON/OFF */ -#define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */ -#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ -#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ -#define COM9 0x14 /* Common control 9 - * Automatic gain ceiling - maximum AGC value [7:5]*/ -#define COM9_AGC_GAIN_2x 0x00 /* 000 : 2x */ -#define COM9_AGC_GAIN_4x 0x20 /* 001 : 4x */ -#define COM9_AGC_GAIN_8x 0x40 /* 010 : 8x */ -#define COM9_AGC_GAIN_16x 0x60 /* 011 : 16x */ -#define COM9_AGC_GAIN_32x 0x80 /* 100 : 32x */ -#define COM9_AGC_GAIN_64x 0xA0 /* 101 : 64x */ -#define COM9_AGC_GAIN_128x 0xC0 /* 110 : 128x */ -#define COM10 0x15 /* Common control 10 */ -#define COM10_PCLK_HREF 0x20 /* PCLK output qualified by HREF */ -#define COM10_PCLK_RISE 0x10 /* Data is updated at the rising edge of - * PCLK (user can latch data at the next - * falling edge of PCLK). - * 0 otherwise. */ -#define COM10_HREF_INV 0x08 /* Invert HREF polarity: - * HREF negative for valid data*/ -#define COM10_VSINC_INV 0x02 /* Invert VSYNC polarity */ -#define HSTART 0x17 /* Horizontal Window start MSB 8 bit */ -#define HEND 0x18 /* Horizontal Window end MSB 8 bit */ -#define VSTART 0x19 /* Vertical Window start MSB 8 bit */ -#define VEND 0x1A /* Vertical Window end MSB 8 bit */ -#define MIDH 0x1C /* Manufacturer ID byte - high */ -#define MIDL 0x1D /* Manufacturer ID byte - low */ -#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */ -#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */ -#define VV 0x26 /* AGC/AEC Fast mode operating region */ -#define VV_HIGH_TH_SET(x) VAL_SET(x, 0xF, 0, 4) -#define VV_LOW_TH_SET(x) VAL_SET(x, 0xF, 0, 0) -#define REG2A 0x2A /* Dummy pixel insert MSB */ -#define FRARL 0x2B /* Dummy pixel insert LSB */ -#define ADDVFL 0x2D /* LSB of insert dummy lines in Vertical direction */ -#define ADDVFH 0x2E /* MSB of insert dummy lines in Vertical direction */ -#define YAVG 0x2F /* Y/G Channel Average value */ -#define REG32 0x32 /* Common Control 32 */ -#define REG32_PCLK_DIV_2 0x80 /* PCLK freq divided by 2 */ -#define REG32_PCLK_DIV_4 0xC0 /* PCLK freq divided by 4 */ -#define ARCOM2 0x34 /* Zoom: Horizontal start point */ -#define REG45 0x45 /* Register 45 */ -#define FLL 0x46 /* Frame Length Adjustment LSBs */ -#define FLH 0x47 /* Frame Length Adjustment MSBs */ -#define COM19 0x48 /* Zoom: Vertical start point */ -#define ZOOMS 0x49 /* Zoom: Vertical start point */ -#define COM22 0x4B /* Flash light control */ -#define COM25 0x4E /* For Banding operations */ -#define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */ -#define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */ -#define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */ -#define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */ -#define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */ -#define REG60 0x60 /* AVGsel[31:24], 16-zone average weight option */ -#define HISTO_LOW 0x61 /* Histogram Algorithm Low Level */ -#define HISTO_HIGH 0x62 /* Histogram Algorithm High Level */ - -/* - * ID - */ -#define MANUFACTURER_ID 0x7FA2 -#define PID_OV2640 0x2642 -#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF)) - -/* - * Struct - */ -struct regval_list { - u8 reg_num; - u8 value; -}; - -/* Supported resolutions */ -enum ov2640_width { - W_QCIF = 176, - W_QVGA = 320, - W_CIF = 352, - W_VGA = 640, - W_SVGA = 800, - W_XGA = 1024, - W_SXGA = 1280, - W_UXGA = 1600, -}; - -enum ov2640_height { - H_QCIF = 144, - H_QVGA = 240, - H_CIF = 288, - H_VGA = 480, - H_SVGA = 600, - H_XGA = 768, - H_SXGA = 1024, - H_UXGA = 1200, -}; - -struct ov2640_win_size { - char *name; - enum ov2640_width width; - enum ov2640_height height; - const struct regval_list *regs; -}; - - -struct ov2640_priv { - struct v4l2_subdev subdev; - struct ov2640_camera_info *info; - enum v4l2_mbus_pixelcode cfmt_code; - const struct ov2640_win_size *win; - int model; - u16 flag_vflip:1; - u16 flag_hflip:1; -}; - -/* - * Registers settings - */ - -#define ENDMARKER { 0xff, 0xff } - -static const struct regval_list ov2640_init_regs[] = { - { BANK_SEL, BANK_SEL_DSP }, - { 0x2c, 0xff }, - { 0x2e, 0xdf }, - { BANK_SEL, BANK_SEL_SENS }, - { 0x3c, 0x32 }, - { CLKRC, CLKRC_DIV_SET(1) }, - { COM2, COM2_OCAP_Nx_SET(3) }, - { REG04, REG04_DEF | REG04_HREF_EN }, - { COM8, COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN }, - { COM9, COM9_AGC_GAIN_8x | 0x08}, - { 0x2c, 0x0c }, - { 0x33, 0x78 }, - { 0x3a, 0x33 }, - { 0x3b, 0xfb }, - { 0x3e, 0x00 }, - { 0x43, 0x11 }, - { 0x16, 0x10 }, - { 0x39, 0x02 }, - { 0x35, 0x88 }, - { 0x22, 0x0a }, - { 0x37, 0x40 }, - { 0x23, 0x00 }, - { ARCOM2, 0xa0 }, - { 0x06, 0x02 }, - { 0x06, 0x88 }, - { 0x07, 0xc0 }, - { 0x0d, 0xb7 }, - { 0x0e, 0x01 }, - { 0x4c, 0x00 }, - { 0x4a, 0x81 }, - { 0x21, 0x99 }, - { AEW, 0x40 }, - { AEB, 0x38 }, - { VV, VV_HIGH_TH_SET(0x08) | VV_LOW_TH_SET(0x02) }, - { 0x5c, 0x00 }, - { 0x63, 0x00 }, - { FLL, 0x22 }, - { COM3, 0x38 | COM3_BAND_AUTO }, - { REG5D, 0x55 }, - { REG5E, 0x7d }, - { REG5F, 0x7d }, - { REG60, 0x55 }, - { HISTO_LOW, 0x70 }, - { HISTO_HIGH, 0x80 }, - { 0x7c, 0x05 }, - { 0x20, 0x80 }, - { 0x28, 0x30 }, - { 0x6c, 0x00 }, - { 0x6d, 0x80 }, - { 0x6e, 0x00 }, - { 0x70, 0x02 }, - { 0x71, 0x94 }, - { 0x73, 0xc1 }, - { 0x3d, 0x34 }, - { COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, - { 0x5a, 0x57 }, - { BD50, 0xbb }, - { BD60, 0x9c }, - { BANK_SEL, BANK_SEL_DSP }, - { 0xe5, 0x7f }, - { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, - { 0x41, 0x24 }, - { RESET, RESET_JPEG | RESET_DVP }, - { 0x76, 0xff }, - { 0x33, 0xa0 }, - { 0x42, 0x20 }, - { 0x43, 0x18 }, - { 0x4c, 0x00 }, - { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, - { 0x88, 0x3f }, - { 0xd7, 0x03 }, - { 0xd9, 0x10 }, - { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 }, - { 0xc8, 0x08 }, - { 0xc9, 0x80 }, - { BPADDR, 0x00 }, - { BPDATA, 0x00 }, - { BPADDR, 0x03 }, - { BPDATA, 0x48 }, - { BPDATA, 0x48 }, - { BPADDR, 0x08 }, - { BPDATA, 0x20 }, - { BPDATA, 0x10 }, - { BPDATA, 0x0e }, - { 0x90, 0x00 }, - { 0x91, 0x0e }, - { 0x91, 0x1a }, - { 0x91, 0x31 }, - { 0x91, 0x5a }, - { 0x91, 0x69 }, - { 0x91, 0x75 }, - { 0x91, 0x7e }, - { 0x91, 0x88 }, - { 0x91, 0x8f }, - { 0x91, 0x96 }, - { 0x91, 0xa3 }, - { 0x91, 0xaf }, - { 0x91, 0xc4 }, - { 0x91, 0xd7 }, - { 0x91, 0xe8 }, - { 0x91, 0x20 }, - { 0x92, 0x00 }, - { 0x93, 0x06 }, - { 0x93, 0xe3 }, - { 0x93, 0x03 }, - { 0x93, 0x03 }, - { 0x93, 0x00 }, - { 0x93, 0x02 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x96, 0x00 }, - { 0x97, 0x08 }, - { 0x97, 0x19 }, - { 0x97, 0x02 }, - { 0x97, 0x0c }, - { 0x97, 0x24 }, - { 0x97, 0x30 }, - { 0x97, 0x28 }, - { 0x97, 0x26 }, - { 0x97, 0x02 }, - { 0x97, 0x98 }, - { 0x97, 0x80 }, - { 0x97, 0x00 }, - { 0x97, 0x00 }, - { 0xa4, 0x00 }, - { 0xa8, 0x00 }, - { 0xc5, 0x11 }, - { 0xc6, 0x51 }, - { 0xbf, 0x80 }, - { 0xc7, 0x10 }, - { 0xb6, 0x66 }, - { 0xb8, 0xA5 }, - { 0xb7, 0x64 }, - { 0xb9, 0x7C }, - { 0xb3, 0xaf }, - { 0xb4, 0x97 }, - { 0xb5, 0xFF }, - { 0xb0, 0xC5 }, - { 0xb1, 0x94 }, - { 0xb2, 0x0f }, - { 0xc4, 0x5c }, - { 0xa6, 0x00 }, - { 0xa7, 0x20 }, - { 0xa7, 0xd8 }, - { 0xa7, 0x1b }, - { 0xa7, 0x31 }, - { 0xa7, 0x00 }, - { 0xa7, 0x18 }, - { 0xa7, 0x20 }, - { 0xa7, 0xd8 }, - { 0xa7, 0x19 }, - { 0xa7, 0x31 }, - { 0xa7, 0x00 }, - { 0xa7, 0x18 }, - { 0xa7, 0x20 }, - { 0xa7, 0xd8 }, - { 0xa7, 0x19 }, - { 0xa7, 0x31 }, - { 0xa7, 0x00 }, - { 0xa7, 0x18 }, - { 0x7f, 0x00 }, - { 0xe5, 0x1f }, - { 0xe1, 0x77 }, - { 0xdd, 0x7f }, - { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN }, - ENDMARKER, -}; - -/* - * Register settings for window size - * The preamble, setup the internal DSP to input an UXGA (1600x1200) image. - * Then the different zooming configurations will setup the output image size. - */ -static const struct regval_list ov2640_size_change_preamble_regs[] = { - { BANK_SEL, BANK_SEL_DSP }, - { RESET, RESET_DVP }, - { HSIZE8, HSIZE8_SET(W_UXGA) }, - { VSIZE8, VSIZE8_SET(H_UXGA) }, - { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | - CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, - { HSIZE, HSIZE_SET(W_UXGA) }, - { VSIZE, VSIZE_SET(H_UXGA) }, - { XOFFL, XOFFL_SET(0) }, - { YOFFL, YOFFL_SET(0) }, - { VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) | - VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)}, - { TEST, TEST_HSIZE_SET(W_UXGA) }, - ENDMARKER, -}; - -#define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div) \ - { CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) | \ - CTRLI_H_DIV_SET(h_div)}, \ - { ZMOW, ZMOW_OUTW_SET(x) }, \ - { ZMOH, ZMOH_OUTH_SET(y) }, \ - { ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y) }, \ - { R_DVP_SP, pclk_div }, \ - { RESET, 0x00} - -static const struct regval_list ov2640_qcif_regs[] = { - PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4), - ENDMARKER, -}; - -static const struct regval_list ov2640_qvga_regs[] = { - PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4), - ENDMARKER, -}; - -static const struct regval_list ov2640_cif_regs[] = { - PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8), - ENDMARKER, -}; - -static const struct regval_list ov2640_vga_regs[] = { - PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2), - ENDMARKER, -}; - -static const struct regval_list ov2640_svga_regs[] = { - PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2), - ENDMARKER, -}; - -static const struct regval_list ov2640_xga_regs[] = { - PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2), - { CTRLI, 0x00}, - ENDMARKER, -}; - -static const struct regval_list ov2640_sxga_regs[] = { - PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2), - { CTRLI, 0x00}, - { R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE }, - ENDMARKER, -}; - -static const struct regval_list ov2640_uxga_regs[] = { - PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0), - { CTRLI, 0x00}, - { R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE }, - ENDMARKER, -}; - -#define OV2640_SIZE(n, w, h, r) \ - {.name = n, .width = w , .height = h, .regs = r } - -static const struct ov2640_win_size ov2640_supported_win_sizes[] = { - OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs), - OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs), - OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs), - OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs), - OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs), - OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs), - OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs), - OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs), -}; - -/* - * Register settings for pixel formats - */ -static const struct regval_list ov2640_format_change_preamble_regs[] = { - { BANK_SEL, BANK_SEL_DSP }, - { R_BYPASS, R_BYPASS_USE_DSP }, - ENDMARKER, -}; - -static const struct regval_list ov2640_yuv422_regs[] = { - { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 }, - { 0xD7, 0x01 }, - { 0x33, 0xa0 }, - { 0xe1, 0x67 }, - { RESET, 0x00 }, - { R_BYPASS, R_BYPASS_USE_DSP }, - ENDMARKER, -}; - -static const struct regval_list ov2640_rgb565_regs[] = { - { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 }, - { 0xd7, 0x03 }, - { RESET, 0x00 }, - { R_BYPASS, R_BYPASS_USE_DSP }, - ENDMARKER, -}; - -static enum v4l2_mbus_pixelcode ov2640_codes[] = { - V4L2_MBUS_FMT_UYVY8_2X8, - V4L2_MBUS_FMT_RGB565_2X8_LE, -}; - -/* - * Supported controls - */ -static const struct v4l2_queryctrl ov2640_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - -/* - * General functions - */ -static struct ov2640_priv *to_ov2640(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct ov2640_priv, - subdev); -} - -static int ov2640_write_array(struct i2c_client *client, - const struct regval_list *vals) -{ - int ret; - - while ((vals->reg_num != 0xff) || (vals->value != 0xff)) { - ret = i2c_smbus_write_byte_data(client, - vals->reg_num, vals->value); - dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", - vals->reg_num, vals->value); - - if (ret < 0) - return ret; - vals++; - } - return 0; -} - -static int ov2640_mask_set(struct i2c_client *client, - u8 reg, u8 mask, u8 set) -{ - s32 val = i2c_smbus_read_byte_data(client, reg); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); - - return i2c_smbus_write_byte_data(client, reg, val); -} - -static int ov2640_reset(struct i2c_client *client) -{ - int ret; - const struct regval_list reset_seq[] = { - {BANK_SEL, BANK_SEL_SENS}, - {COM7, COM7_SRST}, - ENDMARKER, - }; - - ret = ov2640_write_array(client, reset_seq); - if (ret) - goto err; - - msleep(5); -err: - dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret); - return ret; -} - -/* - * soc_camera_ops functions - */ -static int ov2640_s_stream(struct v4l2_subdev *sd, int enable) -{ - return 0; -} - -static int ov2640_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; - - /* Only one width bit may be set */ - if (!is_power_of_2(width_flag)) - return -EINVAL; - - if (icl->set_bus_param) - return icl->set_bus_param(icl, width_flag); - - /* - * Without board specific bus width settings we support only the - * sensors native bus width witch are tested working - */ - if (width_flag & (SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8)) - return 0; - - return 0; -} - -static unsigned long ov2640_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH; - - if (icl->query_bus_param) - flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static int ov2640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2640_priv *priv = to_ov2640(client); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - } - return 0; -} - -static int ov2640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2640_priv *priv = to_ov2640(client); - int ret = 0; - u8 val; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - val = ctrl->value ? REG04_VFLIP_IMG : 0x00; - priv->flag_vflip = ctrl->value ? 1 : 0; - ret = ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); - break; - case V4L2_CID_HFLIP: - val = ctrl->value ? REG04_HFLIP_IMG : 0x00; - priv->flag_hflip = ctrl->value ? 1 : 0; - ret = ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); - break; - } - - return ret; -} - -static int ov2640_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2640_priv *priv = to_ov2640(client); - - id->ident = priv->model; - id->revision = 0; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov2640_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - reg->size = 1; - if (reg->reg > 0xff) - return -EINVAL; - - ret = i2c_smbus_read_byte_data(client, reg->reg); - if (ret < 0) - return ret; - - reg->val = ret; - - return 0; -} - -static int ov2640_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff || - reg->val > 0xff) - return -EINVAL; - - return i2c_smbus_write_byte_data(client, reg->reg, reg->val); -} -#endif - -/* Select the nearest higher resolution for capture */ -static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height) -{ - int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1; - - for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) { - if (ov2640_supported_win_sizes[i].width >= *width && - ov2640_supported_win_sizes[i].height >= *height) { - *width = ov2640_supported_win_sizes[i].width; - *height = ov2640_supported_win_sizes[i].height; - return &ov2640_supported_win_sizes[i]; - } - } - - *width = ov2640_supported_win_sizes[default_size].width; - *height = ov2640_supported_win_sizes[default_size].height; - return &ov2640_supported_win_sizes[default_size]; -} - -static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, - enum v4l2_mbus_pixelcode code) -{ - struct ov2640_priv *priv = to_ov2640(client); - const struct regval_list *selected_cfmt_regs; - int ret; - - /* select win */ - priv->win = ov2640_select_win(width, height); - - /* select format */ - priv->cfmt_code = 0; - switch (code) { - case V4L2_MBUS_FMT_RGB565_2X8_LE: - dev_dbg(&client->dev, "%s: Selected cfmt RGB565", __func__); - selected_cfmt_regs = ov2640_rgb565_regs; - break; - default: - case V4L2_MBUS_FMT_UYVY8_2X8: - dev_dbg(&client->dev, "%s: Selected cfmt YUV422", __func__); - selected_cfmt_regs = ov2640_yuv422_regs; - } - - /* reset hardware */ - ov2640_reset(client); - - /* initialize the sensor with default data */ - dev_dbg(&client->dev, "%s: Init default", __func__); - ret = ov2640_write_array(client, ov2640_init_regs); - if (ret < 0) - goto err; - - /* select preamble */ - dev_dbg(&client->dev, "%s: Set size to %s", __func__, priv->win->name); - ret = ov2640_write_array(client, ov2640_size_change_preamble_regs); - if (ret < 0) - goto err; - - /* set size win */ - ret = ov2640_write_array(client, priv->win->regs); - if (ret < 0) - goto err; - - /* cfmt preamble */ - dev_dbg(&client->dev, "%s: Set cfmt", __func__); - ret = ov2640_write_array(client, ov2640_format_change_preamble_regs); - if (ret < 0) - goto err; - - /* set cfmt */ - ret = ov2640_write_array(client, selected_cfmt_regs); - if (ret < 0) - goto err; - - priv->cfmt_code = code; - *width = priv->win->width; - *height = priv->win->height; - - return 0; - -err: - dev_err(&client->dev, "%s: Error %d", __func__, ret); - ov2640_reset(client); - priv->win = NULL; - - return ret; -} - -static int ov2640_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2640_priv *priv = to_ov2640(client); - - if (!priv->win) { - u32 width = W_SVGA, height = H_SVGA; - int ret = ov2640_set_params(client, &width, &height, - V4L2_MBUS_FMT_UYVY8_2X8); - if (ret < 0) - return ret; - } - - mf->width = priv->win->width; - mf->height = priv->win->height; - mf->code = priv->cfmt_code; - - switch (mf->code) { - case V4L2_MBUS_FMT_RGB565_2X8_LE: - mf->colorspace = V4L2_COLORSPACE_SRGB; - break; - default: - case V4L2_MBUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; - } - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int ov2640_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - - switch (mf->code) { - case V4L2_MBUS_FMT_RGB565_2X8_LE: - mf->colorspace = V4L2_COLORSPACE_SRGB; - break; - default: - mf->code = V4L2_MBUS_FMT_UYVY8_2X8; - case V4L2_MBUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; - } - - ret = ov2640_set_params(client, &mf->width, &mf->height, mf->code); - - return ret; -} - -static int ov2640_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - const struct ov2640_win_size *win; - - /* - * select suitable win - */ - win = ov2640_select_win(&mf->width, &mf->height); - - mf->field = V4L2_FIELD_NONE; - - switch (mf->code) { - case V4L2_MBUS_FMT_RGB565_2X8_LE: - mf->colorspace = V4L2_COLORSPACE_SRGB; - break; - default: - mf->code = V4L2_MBUS_FMT_UYVY8_2X8; - case V4L2_MBUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; - } - - return 0; -} - -static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index >= ARRAY_SIZE(ov2640_codes)) - return -EINVAL; - - *code = ov2640_codes[index]; - return 0; -} - -static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - a->c.left = 0; - a->c.top = 0; - a->c.width = W_UXGA; - a->c.height = H_UXGA; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = W_UXGA; - a->bounds.height = H_UXGA; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int ov2640_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - struct ov2640_priv *priv = to_ov2640(client); - u8 pid, ver, midh, midl; - const char *devname; - int ret; - - /* - * we must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) { - dev_err(&client->dev, "Parent missing or invalid!\n"); - ret = -ENODEV; - goto err; - } - - /* - * check and show product ID and manufacturer ID - */ - i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS); - pid = i2c_smbus_read_byte_data(client, PID); - ver = i2c_smbus_read_byte_data(client, VER); - midh = i2c_smbus_read_byte_data(client, MIDH); - midl = i2c_smbus_read_byte_data(client, MIDL); - - switch (VERSION(pid, ver)) { - case PID_OV2640: - devname = "ov2640"; - priv->model = V4L2_IDENT_OV2640; - break; - default: - dev_err(&client->dev, - "Product ID error %x:%x\n", pid, ver); - ret = -ENODEV; - goto err; - } - - dev_info(&client->dev, - "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", - devname, pid, ver, midh, midl); - - return 0; - -err: - return ret; -} - -static struct soc_camera_ops ov2640_ops = { - .set_bus_param = ov2640_set_bus_param, - .query_bus_param = ov2640_query_bus_param, - .controls = ov2640_controls, - .num_controls = ARRAY_SIZE(ov2640_controls), -}; - -static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { - .g_ctrl = ov2640_g_ctrl, - .s_ctrl = ov2640_s_ctrl, - .g_chip_ident = ov2640_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov2640_g_register, - .s_register = ov2640_s_register, -#endif -}; - -static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { - .s_stream = ov2640_s_stream, - .g_mbus_fmt = ov2640_g_fmt, - .s_mbus_fmt = ov2640_s_fmt, - .try_mbus_fmt = ov2640_try_fmt, - .cropcap = ov2640_cropcap, - .g_crop = ov2640_g_crop, - .enum_mbus_fmt = ov2640_enum_fmt, -}; - -static struct v4l2_subdev_ops ov2640_subdev_ops = { - .core = &ov2640_subdev_core_ops, - .video = &ov2640_subdev_video_ops, -}; - -/* - * i2c_driver functions - */ -static int ov2640_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct ov2640_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&adapter->dev, "OV2640: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&adapter->dev, - "OV2640: Missing platform_data for driver\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&adapter->dev, - "OV2640: I2C-Adapter doesn't support SMBUS\n"); - return -EIO; - } - - priv = kzalloc(sizeof(struct ov2640_priv), GFP_KERNEL); - if (!priv) { - dev_err(&adapter->dev, - "Failed to allocate memory for private data!\n"); - return -ENOMEM; - } - - priv->info = icl->priv; - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); - - icd->ops = &ov2640_ops; - - ret = ov2640_video_probe(icd, client); - if (ret) { - icd->ops = NULL; - kfree(priv); - } else { - dev_info(&adapter->dev, "OV2640 Probed\n"); - } - - return ret; -} - -static int ov2640_remove(struct i2c_client *client) -{ - struct ov2640_priv *priv = to_ov2640(client); - struct soc_camera_device *icd = client->dev.platform_data; - - icd->ops = NULL; - kfree(priv); - return 0; -} - -static const struct i2c_device_id ov2640_id[] = { - { "ov2640", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov2640_id); - -static struct i2c_driver ov2640_i2c_driver = { - .driver = { - .name = "ov2640", - }, - .probe = ov2640_probe, - .remove = ov2640_remove, - .id_table = ov2640_id, -}; - -/* - * Module functions - */ -static int __init ov2640_module_init(void) -{ - return i2c_add_driver(&ov2640_i2c_driver); -} - -static void __exit ov2640_module_exit(void) -{ - i2c_del_driver(&ov2640_i2c_driver); -} - -module_init(ov2640_module_init); -module_exit(ov2640_module_exit); - -MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor"); -MODULE_AUTHOR("Alberto Panizzo"); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov6650.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov6650.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov6650.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov6650.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1221 +0,0 @@ -/* - * V4L2 SoC Camera driver for OmniVision OV6650 Camera Sensor - * - * Copyright (C) 2010 Janusz Krzysztofik - * - * Based on OmniVision OV96xx Camera Driver - * Copyright (C) 2009 Marek Vasut - * - * Based on ov772x camera driver: - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto - * - * Based on ov7670 and soc_camera_platform driver, - * Copyright 2006-7 Jonathan Corbet - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski - * - * Hardware specific bits initialy based on former work by Matt Callow - * drivers/media/video/omap/sensor_ov6650.c - * Copyright (C) 2006 Matt Callow - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include -#include - - -/* Register definitions */ -#define REG_GAIN 0x00 /* range 00 - 3F */ -#define REG_BLUE 0x01 -#define REG_RED 0x02 -#define REG_SAT 0x03 /* [7:4] saturation [0:3] reserved */ -#define REG_HUE 0x04 /* [7:6] rsrvd [5] hue en [4:0] hue */ - -#define REG_BRT 0x06 - -#define REG_PIDH 0x0a -#define REG_PIDL 0x0b - -#define REG_AECH 0x10 -#define REG_CLKRC 0x11 /* Data Format and Internal Clock */ - /* [7:6] Input system clock (MHz)*/ - /* 00=8, 01=12, 10=16, 11=24 */ - /* [5:0]: Internal Clock Pre-Scaler */ -#define REG_COMA 0x12 /* [7] Reset */ -#define REG_COMB 0x13 -#define REG_COMC 0x14 -#define REG_COMD 0x15 -#define REG_COML 0x16 -#define REG_HSTRT 0x17 -#define REG_HSTOP 0x18 -#define REG_VSTRT 0x19 -#define REG_VSTOP 0x1a -#define REG_PSHFT 0x1b -#define REG_MIDH 0x1c -#define REG_MIDL 0x1d -#define REG_HSYNS 0x1e -#define REG_HSYNE 0x1f -#define REG_COME 0x20 -#define REG_YOFF 0x21 -#define REG_UOFF 0x22 -#define REG_VOFF 0x23 -#define REG_AEW 0x24 -#define REG_AEB 0x25 -#define REG_COMF 0x26 -#define REG_COMG 0x27 -#define REG_COMH 0x28 -#define REG_COMI 0x29 - -#define REG_FRARL 0x2b -#define REG_COMJ 0x2c -#define REG_COMK 0x2d -#define REG_AVGY 0x2e -#define REG_REF0 0x2f -#define REG_REF1 0x30 -#define REG_REF2 0x31 -#define REG_FRAJH 0x32 -#define REG_FRAJL 0x33 -#define REG_FACT 0x34 -#define REG_L1AEC 0x35 -#define REG_AVGU 0x36 -#define REG_AVGV 0x37 - -#define REG_SPCB 0x60 -#define REG_SPCC 0x61 -#define REG_GAM1 0x62 -#define REG_GAM2 0x63 -#define REG_GAM3 0x64 -#define REG_SPCD 0x65 - -#define REG_SPCE 0x68 -#define REG_ADCL 0x69 - -#define REG_RMCO 0x6c -#define REG_GMCO 0x6d -#define REG_BMCO 0x6e - - -/* Register bits, values, etc. */ -#define OV6650_PIDH 0x66 /* high byte of product ID number */ -#define OV6650_PIDL 0x50 /* low byte of product ID number */ -#define OV6650_MIDH 0x7F /* high byte of mfg ID */ -#define OV6650_MIDL 0xA2 /* low byte of mfg ID */ - -#define DEF_GAIN 0x00 -#define DEF_BLUE 0x80 -#define DEF_RED 0x80 - -#define SAT_SHIFT 4 -#define SAT_MASK (0xf << SAT_SHIFT) -#define SET_SAT(x) (((x) << SAT_SHIFT) & SAT_MASK) - -#define HUE_EN BIT(5) -#define HUE_MASK 0x1f -#define DEF_HUE 0x10 -#define SET_HUE(x) (HUE_EN | ((x) & HUE_MASK)) - -#define DEF_AECH 0x4D - -#define CLKRC_6MHz 0x00 -#define CLKRC_12MHz 0x40 -#define CLKRC_16MHz 0x80 -#define CLKRC_24MHz 0xc0 -#define CLKRC_DIV_MASK 0x3f -#define GET_CLKRC_DIV(x) (((x) & CLKRC_DIV_MASK) + 1) - -#define COMA_RESET BIT(7) -#define COMA_QCIF BIT(5) -#define COMA_RAW_RGB BIT(4) -#define COMA_RGB BIT(3) -#define COMA_BW BIT(2) -#define COMA_WORD_SWAP BIT(1) -#define COMA_BYTE_SWAP BIT(0) -#define DEF_COMA 0x00 - -#define COMB_FLIP_V BIT(7) -#define COMB_FLIP_H BIT(5) -#define COMB_BAND_FILTER BIT(4) -#define COMB_AWB BIT(2) -#define COMB_AGC BIT(1) -#define COMB_AEC BIT(0) -#define DEF_COMB 0x5f - -#define COML_ONE_CHANNEL BIT(7) - -#define DEF_HSTRT 0x24 -#define DEF_HSTOP 0xd4 -#define DEF_VSTRT 0x04 -#define DEF_VSTOP 0x94 - -#define COMF_HREF_LOW BIT(4) - -#define COMJ_PCLK_RISING BIT(4) -#define COMJ_VSYNC_HIGH BIT(0) - -/* supported resolutions */ -#define W_QCIF (DEF_HSTOP - DEF_HSTRT) -#define W_CIF (W_QCIF << 1) -#define H_QCIF (DEF_VSTOP - DEF_VSTRT) -#define H_CIF (H_QCIF << 1) - -#define FRAME_RATE_MAX 30 - - -struct ov6650_reg { - u8 reg; - u8 val; -}; - -struct ov6650 { - struct v4l2_subdev subdev; - - int gain; - int blue; - int red; - int saturation; - int hue; - int brightness; - int exposure; - int gamma; - int aec; - bool vflip; - bool hflip; - bool awb; - bool agc; - bool half_scale; /* scale down output by 2 */ - struct v4l2_rect rect; /* sensor cropping window */ - unsigned long pclk_limit; /* from host */ - unsigned long pclk_max; /* from resolution and format */ - struct v4l2_fract tpf; /* as requested with s_parm */ - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; -}; - - -static enum v4l2_mbus_pixelcode ov6650_codes[] = { - V4L2_MBUS_FMT_YUYV8_2X8, - V4L2_MBUS_FMT_UYVY8_2X8, - V4L2_MBUS_FMT_YVYU8_2X8, - V4L2_MBUS_FMT_VYUY8_2X8, - V4L2_MBUS_FMT_SBGGR8_1X8, - V4L2_MBUS_FMT_Y8_1X8, -}; - -static const struct v4l2_queryctrl ov6650_controls[] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "AGC", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = DEF_GAIN, - }, - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "AWB", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = DEF_BLUE, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = DEF_RED, - }, - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 0xf, - .step = 1, - .default_value = 0x8, - }, - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = HUE_MASK, - .step = 1, - .default_value = DEF_HUE, - }, - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x80, - }, - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "AEC", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = DEF_AECH, - }, - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x12, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - -/* read a register */ -static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) -{ - int ret; - u8 data = reg; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - msg.flags = I2C_M_RD; - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - *val = data; - return 0; - -err: - dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg); - return ret; -} - -/* write a register */ -static int ov6650_reg_write(struct i2c_client *client, u8 reg, u8 val) -{ - int ret; - unsigned char data[2] = { reg, val }; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - udelay(100); - - if (ret < 0) { - dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg); - return ret; - } - return 0; -} - - -/* Read a register, alter its bits, write it back */ -static int ov6650_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 mask) -{ - u8 val; - int ret; - - ret = ov6650_reg_read(client, reg, &val); - if (ret) { - dev_err(&client->dev, - "[Read]-Modify-Write of register 0x%02x failed!\n", - reg); - return ret; - } - - val &= ~mask; - val |= set; - - ret = ov6650_reg_write(client, reg, val); - if (ret) - dev_err(&client->dev, - "Read-Modify-[Write] of register 0x%02x failed!\n", - reg); - - return ret; -} - -static struct ov6650 *to_ov6650(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct ov6650, subdev); -} - -/* Start/Stop streaming from the device */ -static int ov6650_s_stream(struct v4l2_subdev *sd, int enable) -{ - return 0; -} - -/* Alter bus settings on camera side */ -static int ov6650_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - int ret; - - flags = soc_camera_apply_sensor_flags(icl, flags); - - if (flags & SOCAM_PCLK_SAMPLE_RISING) - ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); - else - ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); - if (ret) - return ret; - - if (flags & SOCAM_HSYNC_ACTIVE_LOW) - ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); - else - ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); - if (ret) - return ret; - - if (flags & SOCAM_VSYNC_ACTIVE_HIGH) - ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); - else - ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); - - return ret; -} - -/* Request bus settings on camera side */ -static unsigned long ov6650_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - unsigned long flags = SOCAM_MASTER | - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -/* Get status of additional camera capabilities */ -static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - uint8_t reg; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - ctrl->value = priv->agc; - break; - case V4L2_CID_GAIN: - if (priv->agc) { - ret = ov6650_reg_read(client, REG_GAIN, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->gain; - } - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = priv->awb; - break; - case V4L2_CID_BLUE_BALANCE: - if (priv->awb) { - ret = ov6650_reg_read(client, REG_BLUE, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->blue; - } - break; - case V4L2_CID_RED_BALANCE: - if (priv->awb) { - ret = ov6650_reg_read(client, REG_RED, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->red; - } - break; - case V4L2_CID_SATURATION: - ctrl->value = priv->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = priv->hue; - break; - case V4L2_CID_BRIGHTNESS: - ctrl->value = priv->brightness; - break; - case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = priv->aec; - break; - case V4L2_CID_EXPOSURE: - if (priv->aec) { - ret = ov6650_reg_read(client, REG_AECH, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->exposure; - } - break; - case V4L2_CID_GAMMA: - ctrl->value = priv->gamma; - break; - case V4L2_CID_VFLIP: - ctrl->value = priv->vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->hflip; - break; - } - return ret; -} - -/* Set status of additional camera capabilities */ -static int ov6650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_AGC : 0, COMB_AGC); - if (!ret) - priv->agc = ctrl->value; - break; - case V4L2_CID_GAIN: - ret = ov6650_reg_write(client, REG_GAIN, ctrl->value); - if (!ret) - priv->gain = ctrl->value; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_AWB : 0, COMB_AWB); - if (!ret) - priv->awb = ctrl->value; - break; - case V4L2_CID_BLUE_BALANCE: - ret = ov6650_reg_write(client, REG_BLUE, ctrl->value); - if (!ret) - priv->blue = ctrl->value; - break; - case V4L2_CID_RED_BALANCE: - ret = ov6650_reg_write(client, REG_RED, ctrl->value); - if (!ret) - priv->red = ctrl->value; - break; - case V4L2_CID_SATURATION: - ret = ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->value), - SAT_MASK); - if (!ret) - priv->saturation = ctrl->value; - break; - case V4L2_CID_HUE: - ret = ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->value), - HUE_MASK); - if (!ret) - priv->hue = ctrl->value; - break; - case V4L2_CID_BRIGHTNESS: - ret = ov6650_reg_write(client, REG_BRT, ctrl->value); - if (!ret) - priv->brightness = ctrl->value; - break; - case V4L2_CID_EXPOSURE_AUTO: - switch (ctrl->value) { - case V4L2_EXPOSURE_AUTO: - ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); - break; - default: - ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); - break; - } - if (!ret) - priv->aec = ctrl->value; - break; - case V4L2_CID_EXPOSURE: - ret = ov6650_reg_write(client, REG_AECH, ctrl->value); - if (!ret) - priv->exposure = ctrl->value; - break; - case V4L2_CID_GAMMA: - ret = ov6650_reg_write(client, REG_GAM1, ctrl->value); - if (!ret) - priv->gamma = ctrl->value; - break; - case V4L2_CID_VFLIP: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_FLIP_V : 0, COMB_FLIP_V); - if (!ret) - priv->vflip = ctrl->value; - break; - case V4L2_CID_HFLIP: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_FLIP_H : 0, COMB_FLIP_H); - if (!ret) - priv->hflip = ctrl->value; - break; - } - - return ret; -} - -/* Get chip identification */ -static int ov6650_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - id->ident = V4L2_IDENT_OV6650; - id->revision = 0; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov6650_get_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 val; - - if (reg->reg & ~0xff) - return -EINVAL; - - reg->size = 1; - - ret = ov6650_reg_read(client, reg->reg, &val); - if (!ret) - reg->val = (__u64)val; - - return ret; -} - -static int ov6650_set_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg & ~0xff || reg->val & ~0xff) - return -EINVAL; - - return ov6650_reg_write(client, reg->reg, reg->val); -} -#endif - -static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->c = priv->rect; - - return 0; -} - -static int ov6650_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - struct v4l2_rect *rect = &a->c; - int ret; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - rect->left = ALIGN(rect->left, 2); - rect->width = ALIGN(rect->width, 2); - rect->top = ALIGN(rect->top, 2); - rect->height = ALIGN(rect->height, 2); - soc_camera_limit_side(&rect->left, &rect->width, - DEF_HSTRT << 1, 2, W_CIF); - soc_camera_limit_side(&rect->top, &rect->height, - DEF_VSTRT << 1, 2, H_CIF); - - ret = ov6650_reg_write(client, REG_HSTRT, rect->left >> 1); - if (!ret) { - priv->rect.left = rect->left; - ret = ov6650_reg_write(client, REG_HSTOP, - (rect->left + rect->width) >> 1); - } - if (!ret) { - priv->rect.width = rect->width; - ret = ov6650_reg_write(client, REG_VSTRT, rect->top >> 1); - } - if (!ret) { - priv->rect.top = rect->top; - ret = ov6650_reg_write(client, REG_VSTOP, - (rect->top + rect->height) >> 1); - } - if (!ret) - priv->rect.height = rect->height; - - return ret; -} - -static int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - a->bounds.left = DEF_HSTRT << 1; - a->bounds.top = DEF_VSTRT << 1; - a->bounds.width = W_CIF; - a->bounds.height = H_CIF; - a->defrect = a->bounds; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int ov6650_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - - mf->width = priv->rect.width >> priv->half_scale; - mf->height = priv->rect.height >> priv->half_scale; - mf->code = priv->code; - mf->colorspace = priv->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect) -{ - return width > rect->width >> 1 || height > rect->height >> 1; -} - -static u8 to_clkrc(struct v4l2_fract *timeperframe, - unsigned long pclk_limit, unsigned long pclk_max) -{ - unsigned long pclk; - - if (timeperframe->numerator && timeperframe->denominator) - pclk = pclk_max * timeperframe->denominator / - (FRAME_RATE_MAX * timeperframe->numerator); - else - pclk = pclk_max; - - if (pclk_limit && pclk_limit < pclk) - pclk = pclk_limit; - - return (pclk_max - 1) / pclk; -} - -/* set the format we will capture in */ -static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_sense *sense = icd->sense; - struct ov6650 *priv = to_ov6650(client); - bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); - struct v4l2_crop a = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .c = { - .left = priv->rect.left + (priv->rect.width >> 1) - - (mf->width >> (1 - half_scale)), - .top = priv->rect.top + (priv->rect.height >> 1) - - (mf->height >> (1 - half_scale)), - .width = mf->width << half_scale, - .height = mf->height << half_scale, - }, - }; - enum v4l2_mbus_pixelcode code = mf->code; - unsigned long mclk, pclk; - u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc; - int ret; - - /* select color matrix configuration for given color encoding */ - switch (code) { - case V4L2_MBUS_FMT_Y8_1X8: - dev_dbg(&client->dev, "pixel format GREY8_1X8\n"); - coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP; - coma_set |= COMA_BW; - break; - case V4L2_MBUS_FMT_YUYV8_2X8: - dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n"); - coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP; - coma_set |= COMA_WORD_SWAP; - break; - case V4L2_MBUS_FMT_YVYU8_2X8: - dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n"); - coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP | - COMA_BYTE_SWAP; - break; - case V4L2_MBUS_FMT_UYVY8_2X8: - dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n"); - if (half_scale) { - coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP; - coma_set |= COMA_BYTE_SWAP; - } else { - coma_mask |= COMA_RGB | COMA_BW; - coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP; - } - break; - case V4L2_MBUS_FMT_VYUY8_2X8: - dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n"); - if (half_scale) { - coma_mask |= COMA_RGB | COMA_BW; - coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP; - } else { - coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP; - coma_set |= COMA_BYTE_SWAP; - } - break; - case V4L2_MBUS_FMT_SBGGR8_1X8: - dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n"); - coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP; - coma_set |= COMA_RAW_RGB | COMA_RGB; - break; - default: - dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code); - return -EINVAL; - } - priv->code = code; - - if (code == V4L2_MBUS_FMT_Y8_1X8 || - code == V4L2_MBUS_FMT_SBGGR8_1X8) { - coml_mask = COML_ONE_CHANNEL; - coml_set = 0; - priv->pclk_max = 4000000; - } else { - coml_mask = 0; - coml_set = COML_ONE_CHANNEL; - priv->pclk_max = 8000000; - } - - if (code == V4L2_MBUS_FMT_SBGGR8_1X8) - priv->colorspace = V4L2_COLORSPACE_SRGB; - else if (code != 0) - priv->colorspace = V4L2_COLORSPACE_JPEG; - - if (half_scale) { - dev_dbg(&client->dev, "max resolution: QCIF\n"); - coma_set |= COMA_QCIF; - priv->pclk_max /= 2; - } else { - dev_dbg(&client->dev, "max resolution: CIF\n"); - coma_mask |= COMA_QCIF; - } - priv->half_scale = half_scale; - - if (sense) { - if (sense->master_clock == 8000000) { - dev_dbg(&client->dev, "8MHz input clock\n"); - clkrc = CLKRC_6MHz; - } else if (sense->master_clock == 12000000) { - dev_dbg(&client->dev, "12MHz input clock\n"); - clkrc = CLKRC_12MHz; - } else if (sense->master_clock == 16000000) { - dev_dbg(&client->dev, "16MHz input clock\n"); - clkrc = CLKRC_16MHz; - } else if (sense->master_clock == 24000000) { - dev_dbg(&client->dev, "24MHz input clock\n"); - clkrc = CLKRC_24MHz; - } else { - dev_err(&client->dev, - "unspported input clock, check platform data\n"); - return -EINVAL; - } - mclk = sense->master_clock; - priv->pclk_limit = sense->pixel_clock_max; - } else { - clkrc = CLKRC_24MHz; - mclk = 24000000; - priv->pclk_limit = 0; - dev_dbg(&client->dev, "using default 24MHz input clock\n"); - } - - clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max); - - pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc); - dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n", - mclk / pclk, 10 * mclk % pclk / pclk); - - ret = ov6650_s_crop(sd, &a); - if (!ret) - ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); - if (!ret) - ret = ov6650_reg_write(client, REG_CLKRC, clkrc); - if (!ret) - ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask); - - if (!ret) { - mf->colorspace = priv->colorspace; - mf->width = priv->rect.width >> half_scale; - mf->height = priv->rect.height >> half_scale; - } - - return ret; -} - -static int ov6650_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - - if (is_unscaled_ok(mf->width, mf->height, &priv->rect)) - v4l_bound_align_image(&mf->width, 2, W_CIF, 1, - &mf->height, 2, H_CIF, 1, 0); - - mf->field = V4L2_FIELD_NONE; - - switch (mf->code) { - case V4L2_MBUS_FMT_Y10_1X10: - mf->code = V4L2_MBUS_FMT_Y8_1X8; - case V4L2_MBUS_FMT_Y8_1X8: - case V4L2_MBUS_FMT_YVYU8_2X8: - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_VYUY8_2X8: - case V4L2_MBUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; - break; - default: - mf->code = V4L2_MBUS_FMT_SBGGR8_1X8; - case V4L2_MBUS_FMT_SBGGR8_1X8: - mf->colorspace = V4L2_COLORSPACE_SRGB; - break; - } - - return 0; -} - -static int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index >= ARRAY_SIZE(ov6650_codes)) - return -EINVAL; - - *code = ov6650_codes[index]; - return 0; -} - -static int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - struct v4l2_captureparm *cp = &parms->parm.capture; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(*cp)); - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf, - priv->pclk_limit, priv->pclk_max)); - cp->timeperframe.denominator = FRAME_RATE_MAX; - - dev_dbg(&client->dev, "Frame interval: %u/%u s\n", - cp->timeperframe.numerator, cp->timeperframe.denominator); - - return 0; -} - -static int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; - int div, ret; - u8 clkrc; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cp->extendedmode != 0) - return -EINVAL; - - if (tpf->numerator == 0 || tpf->denominator == 0) - div = 1; /* Reset to full rate */ - else - div = (tpf->numerator * FRAME_RATE_MAX) / tpf->denominator; - - if (div == 0) - div = 1; - else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK)) - div = GET_CLKRC_DIV(CLKRC_DIV_MASK); - - /* - * Keep result to be used as tpf limit - * for subseqent clock divider calculations - */ - priv->tpf.numerator = div; - priv->tpf.denominator = FRAME_RATE_MAX; - - clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max); - - ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK); - if (!ret) { - tpf->numerator = GET_CLKRC_DIV(clkrc); - tpf->denominator = FRAME_RATE_MAX; - } - - return ret; -} - -/* Soft reset the camera. This has nothing to do with the RESET pin! */ -static int ov6650_reset(struct i2c_client *client) -{ - int ret; - - dev_dbg(&client->dev, "reset\n"); - - ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0); - if (ret) - dev_err(&client->dev, - "An error occured while entering soft reset!\n"); - - return ret; -} - -/* program default register values */ -static int ov6650_prog_dflt(struct i2c_client *client) -{ - int ret; - - dev_dbg(&client->dev, "initializing\n"); - - ret = ov6650_reg_write(client, REG_COMA, 0); /* ~COMA_RESET */ - if (!ret) - ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER); - - return ret; -} - -static int ov6650_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - u8 pidh, pidl, midh, midl; - int ret = 0; - - /* - * check and show product ID and manufacturer ID - */ - ret = ov6650_reg_read(client, REG_PIDH, &pidh); - if (!ret) - ret = ov6650_reg_read(client, REG_PIDL, &pidl); - if (!ret) - ret = ov6650_reg_read(client, REG_MIDH, &midh); - if (!ret) - ret = ov6650_reg_read(client, REG_MIDL, &midl); - - if (ret) - return ret; - - if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) { - dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n", - pidh, pidl); - return -ENODEV; - } - - dev_info(&client->dev, - "ov6650 Product ID 0x%02x:0x%02x Manufacturer ID 0x%02x:0x%02x\n", - pidh, pidl, midh, midl); - - ret = ov6650_reset(client); - if (!ret) - ret = ov6650_prog_dflt(client); - - return ret; -} - -static struct soc_camera_ops ov6650_ops = { - .set_bus_param = ov6650_set_bus_param, - .query_bus_param = ov6650_query_bus_param, - .controls = ov6650_controls, - .num_controls = ARRAY_SIZE(ov6650_controls), -}; - -static struct v4l2_subdev_core_ops ov6650_core_ops = { - .g_ctrl = ov6650_g_ctrl, - .s_ctrl = ov6650_s_ctrl, - .g_chip_ident = ov6650_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov6650_get_register, - .s_register = ov6650_set_register, -#endif -}; - -static struct v4l2_subdev_video_ops ov6650_video_ops = { - .s_stream = ov6650_s_stream, - .g_mbus_fmt = ov6650_g_fmt, - .s_mbus_fmt = ov6650_s_fmt, - .try_mbus_fmt = ov6650_try_fmt, - .enum_mbus_fmt = ov6650_enum_fmt, - .cropcap = ov6650_cropcap, - .g_crop = ov6650_g_crop, - .s_crop = ov6650_s_crop, - .g_parm = ov6650_g_parm, - .s_parm = ov6650_s_parm, -}; - -static struct v4l2_subdev_ops ov6650_subdev_ops = { - .core = &ov6650_core_ops, - .video = &ov6650_video_ops, -}; - -/* - * i2c_driver function - */ -static int ov6650_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct ov6650 *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "Missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "Missing platform_data for driver\n"); - return -EINVAL; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&client->dev, - "Failed to allocate memory for private data!\n"); - return -ENOMEM; - } - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); - - icd->ops = &ov6650_ops; - - priv->rect.left = DEF_HSTRT << 1; - priv->rect.top = DEF_VSTRT << 1; - priv->rect.width = W_CIF; - priv->rect.height = H_CIF; - priv->half_scale = false; - priv->code = V4L2_MBUS_FMT_YUYV8_2X8; - priv->colorspace = V4L2_COLORSPACE_JPEG; - - ret = ov6650_video_probe(icd, client); - - if (ret) { - icd->ops = NULL; - kfree(priv); - } - - return ret; -} - -static int ov6650_remove(struct i2c_client *client) -{ - struct ov6650 *priv = to_ov6650(client); - - kfree(priv); - return 0; -} - -static const struct i2c_device_id ov6650_id[] = { - { "ov6650", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov6650_id); - -static struct i2c_driver ov6650_i2c_driver = { - .driver = { - .name = "ov6650", - }, - .probe = ov6650_probe, - .remove = ov6650_remove, - .id_table = ov6650_id, -}; - -static int __init ov6650_module_init(void) -{ - return i2c_add_driver(&ov6650_i2c_driver); -} - -static void __exit ov6650_module_exit(void) -{ - i2c_del_driver(&ov6650_i2c_driver); -} - -module_init(ov6650_module_init); -module_exit(ov6650_module_exit); - -MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650"); -MODULE_AUTHOR("Janusz Krzysztofik "); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov7670.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov7670.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov7670.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov7670.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1598 +0,0 @@ -/* - * A V4L2 driver for OmniVision OV7670 cameras. - * - * Copyright 2006 One Laptop Per Child Association, Inc. Written - * by Jonathan Corbet with substantial inspiration from Mark - * McClelland's ovcamchip code. - * - * Copyright 2006-7 Jonathan Corbet - * - * This file may be distributed under the terms of the GNU General - * Public License, version 2. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ov7670.h" - -MODULE_AUTHOR("Jonathan Corbet "); -MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -/* - * Basic window sizes. These probably belong somewhere more globally - * useful. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 -#define CIF_WIDTH 352 -#define CIF_HEIGHT 288 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 - -/* - * The 7670 sits on i2c with ID 0x42 - */ -#define OV7670_I2C_ADDR 0x42 - -/* Registers */ -#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ -#define REG_BLUE 0x01 /* blue gain */ -#define REG_RED 0x02 /* red gain */ -#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ -#define REG_COM1 0x04 /* Control 1 */ -#define COM1_CCIR656 0x40 /* CCIR656 enable */ -#define REG_BAVE 0x05 /* U/B Average level */ -#define REG_GbAVE 0x06 /* Y/Gb Average level */ -#define REG_AECHH 0x07 /* AEC MS 5 bits */ -#define REG_RAVE 0x08 /* V/R Average level */ -#define REG_COM2 0x09 /* Control 2 */ -#define COM2_SSLEEP 0x10 /* Soft sleep mode */ -#define REG_PID 0x0a /* Product ID MSB */ -#define REG_VER 0x0b /* Product ID LSB */ -#define REG_COM3 0x0c /* Control 3 */ -#define COM3_SWAP 0x40 /* Byte swap */ -#define COM3_SCALEEN 0x08 /* Enable scaling */ -#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */ -#define REG_COM4 0x0d /* Control 4 */ -#define REG_COM5 0x0e /* All "reserved" */ -#define REG_COM6 0x0f /* Control 6 */ -#define REG_AECH 0x10 /* More bits of AEC value */ -#define REG_CLKRC 0x11 /* Clocl control */ -#define CLK_EXT 0x40 /* Use external clock directly */ -#define CLK_SCALE 0x3f /* Mask for internal clock scale */ -#define REG_COM7 0x12 /* Control 7 */ -#define COM7_RESET 0x80 /* Register reset */ -#define COM7_FMT_MASK 0x38 -#define COM7_FMT_VGA 0x00 -#define COM7_FMT_CIF 0x20 /* CIF format */ -#define COM7_FMT_QVGA 0x10 /* QVGA format */ -#define COM7_FMT_QCIF 0x08 /* QCIF format */ -#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */ -#define COM7_YUV 0x00 /* YUV */ -#define COM7_BAYER 0x01 /* Bayer format */ -#define COM7_PBAYER 0x05 /* "Processed bayer" */ -#define REG_COM8 0x13 /* Control 8 */ -#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ -#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ -#define COM8_BFILT 0x20 /* Band filter enable */ -#define COM8_AGC 0x04 /* Auto gain enable */ -#define COM8_AWB 0x02 /* White balance enable */ -#define COM8_AEC 0x01 /* Auto exposure enable */ -#define REG_COM9 0x14 /* Control 9 - gain ceiling */ -#define REG_COM10 0x15 /* Control 10 */ -#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ -#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ -#define COM10_HREF_REV 0x08 /* Reverse HREF */ -#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ -#define COM10_VS_NEG 0x02 /* VSYNC negative */ -#define COM10_HS_NEG 0x01 /* HSYNC negative */ -#define REG_HSTART 0x17 /* Horiz start high bits */ -#define REG_HSTOP 0x18 /* Horiz stop high bits */ -#define REG_VSTART 0x19 /* Vert start high bits */ -#define REG_VSTOP 0x1a /* Vert stop high bits */ -#define REG_PSHFT 0x1b /* Pixel delay after HREF */ -#define REG_MIDH 0x1c /* Manuf. ID high */ -#define REG_MIDL 0x1d /* Manuf. ID low */ -#define REG_MVFP 0x1e /* Mirror / vflip */ -#define MVFP_MIRROR 0x20 /* Mirror image */ -#define MVFP_FLIP 0x10 /* Vertical flip */ - -#define REG_AEW 0x24 /* AGC upper limit */ -#define REG_AEB 0x25 /* AGC lower limit */ -#define REG_VPT 0x26 /* AGC/AEC fast mode op region */ -#define REG_HSYST 0x30 /* HSYNC rising edge delay */ -#define REG_HSYEN 0x31 /* HSYNC falling edge delay */ -#define REG_HREF 0x32 /* HREF pieces */ -#define REG_TSLB 0x3a /* lots of stuff */ -#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */ -#define REG_COM11 0x3b /* Control 11 */ -#define COM11_NIGHT 0x80 /* NIght mode enable */ -#define COM11_NMFR 0x60 /* Two bit NM frame rate */ -#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ -#define COM11_50HZ 0x08 /* Manual 50Hz select */ -#define COM11_EXP 0x02 -#define REG_COM12 0x3c /* Control 12 */ -#define COM12_HREF 0x80 /* HREF always */ -#define REG_COM13 0x3d /* Control 13 */ -#define COM13_GAMMA 0x80 /* Gamma enable */ -#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ -#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ -#define REG_COM14 0x3e /* Control 14 */ -#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */ -#define REG_EDGE 0x3f /* Edge enhancement factor */ -#define REG_COM15 0x40 /* Control 15 */ -#define COM15_R10F0 0x00 /* Data range 10 to F0 */ -#define COM15_R01FE 0x80 /* 01 to FE */ -#define COM15_R00FF 0xc0 /* 00 to FF */ -#define COM15_RGB565 0x10 /* RGB565 output */ -#define COM15_RGB555 0x30 /* RGB555 output */ -#define REG_COM16 0x41 /* Control 16 */ -#define COM16_AWBGAIN 0x08 /* AWB gain enable */ -#define REG_COM17 0x42 /* Control 17 */ -#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ -#define COM17_CBAR 0x08 /* DSP Color bar */ - -/* - * This matrix defines how the colors are generated, must be - * tweaked to adjust hue and saturation. - * - * Order: v-red, v-green, v-blue, u-red, u-green, u-blue - * - * They are nine-bit signed quantities, with the sign bit - * stored in 0x58. Sign for v-red is bit 0, and up from there. - */ -#define REG_CMATRIX_BASE 0x4f -#define CMATRIX_LEN 6 -#define REG_CMATRIX_SIGN 0x58 - - -#define REG_BRIGHT 0x55 /* Brightness */ -#define REG_CONTRAS 0x56 /* Contrast control */ - -#define REG_GFIX 0x69 /* Fix gain control */ - -#define REG_REG76 0x76 /* OV's name */ -#define R76_BLKPCOR 0x80 /* Black pixel correction enable */ -#define R76_WHTPCOR 0x40 /* White pixel correction enable */ - -#define REG_RGB444 0x8c /* RGB 444 control */ -#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ -#define R444_RGBX 0x01 /* Empty nibble at end */ - -#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ -#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ - -#define REG_BD50MAX 0xa5 /* 50hz banding step limit */ -#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ -#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ -#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ -#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ -#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ -#define REG_BD60MAX 0xab /* 60hz banding step limit */ - - -/* - * Information we maintain about a known sensor. - */ -struct ov7670_format_struct; /* coming later */ -struct ov7670_info { - struct v4l2_subdev sd; - struct ov7670_format_struct *fmt; /* Current format */ - unsigned char sat; /* Saturation value */ - int hue; /* Hue value */ - int min_width; /* Filter out smaller sizes */ - int min_height; /* Filter out smaller sizes */ - int clock_speed; /* External clock speed (MHz) */ - u8 clkrc; /* Clock divider value */ - bool use_smbus; /* Use smbus I/O instead of I2C */ -}; - -static inline struct ov7670_info *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct ov7670_info, sd); -} - - - -/* - * The default register settings, as obtained from OmniVision. There - * is really no making sense of most of these - lots of "reserved" values - * and such. - * - * These settings give VGA YUYV. - */ - -struct regval_list { - unsigned char reg_num; - unsigned char value; -}; - -static struct regval_list ov7670_default_regs[] = { - { REG_COM7, COM7_RESET }, -/* - * Clock scale: 3 = 15fps - * 2 = 20fps - * 1 = 30fps - */ - { REG_CLKRC, 0x1 }, /* OV: clock scale (30 fps) */ - { REG_TSLB, 0x04 }, /* OV */ - { REG_COM7, 0 }, /* VGA */ - /* - * Set the hardware window. These values from OV don't entirely - * make sense - hstop is less than hstart. But they work... - */ - { REG_HSTART, 0x13 }, { REG_HSTOP, 0x01 }, - { REG_HREF, 0xb6 }, { REG_VSTART, 0x02 }, - { REG_VSTOP, 0x7a }, { REG_VREF, 0x0a }, - - { REG_COM3, 0 }, { REG_COM14, 0 }, - /* Mystery scaling numbers */ - { 0x70, 0x3a }, { 0x71, 0x35 }, - { 0x72, 0x11 }, { 0x73, 0xf0 }, - { 0xa2, 0x02 }, { REG_COM10, 0x0 }, - - /* Gamma curve values */ - { 0x7a, 0x20 }, { 0x7b, 0x10 }, - { 0x7c, 0x1e }, { 0x7d, 0x35 }, - { 0x7e, 0x5a }, { 0x7f, 0x69 }, - { 0x80, 0x76 }, { 0x81, 0x80 }, - { 0x82, 0x88 }, { 0x83, 0x8f }, - { 0x84, 0x96 }, { 0x85, 0xa3 }, - { 0x86, 0xaf }, { 0x87, 0xc4 }, - { 0x88, 0xd7 }, { 0x89, 0xe8 }, - - /* AGC and AEC parameters. Note we start by disabling those features, - then turn them only after tweaking the values. */ - { REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT }, - { REG_GAIN, 0 }, { REG_AECH, 0 }, - { REG_COM4, 0x40 }, /* magic reserved bit */ - { REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ - { REG_BD50MAX, 0x05 }, { REG_BD60MAX, 0x07 }, - { REG_AEW, 0x95 }, { REG_AEB, 0x33 }, - { REG_VPT, 0xe3 }, { REG_HAECC1, 0x78 }, - { REG_HAECC2, 0x68 }, { 0xa1, 0x03 }, /* magic */ - { REG_HAECC3, 0xd8 }, { REG_HAECC4, 0xd8 }, - { REG_HAECC5, 0xf0 }, { REG_HAECC6, 0x90 }, - { REG_HAECC7, 0x94 }, - { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC }, - - /* Almost all of these are magic "reserved" values. */ - { REG_COM5, 0x61 }, { REG_COM6, 0x4b }, - { 0x16, 0x02 }, { REG_MVFP, 0x07 }, - { 0x21, 0x02 }, { 0x22, 0x91 }, - { 0x29, 0x07 }, { 0x33, 0x0b }, - { 0x35, 0x0b }, { 0x37, 0x1d }, - { 0x38, 0x71 }, { 0x39, 0x2a }, - { REG_COM12, 0x78 }, { 0x4d, 0x40 }, - { 0x4e, 0x20 }, { REG_GFIX, 0 }, - { 0x6b, 0x4a }, { 0x74, 0x10 }, - { 0x8d, 0x4f }, { 0x8e, 0 }, - { 0x8f, 0 }, { 0x90, 0 }, - { 0x91, 0 }, { 0x96, 0 }, - { 0x9a, 0 }, { 0xb0, 0x84 }, - { 0xb1, 0x0c }, { 0xb2, 0x0e }, - { 0xb3, 0x82 }, { 0xb8, 0x0a }, - - /* More reserved magic, some of which tweaks white balance */ - { 0x43, 0x0a }, { 0x44, 0xf0 }, - { 0x45, 0x34 }, { 0x46, 0x58 }, - { 0x47, 0x28 }, { 0x48, 0x3a }, - { 0x59, 0x88 }, { 0x5a, 0x88 }, - { 0x5b, 0x44 }, { 0x5c, 0x67 }, - { 0x5d, 0x49 }, { 0x5e, 0x0e }, - { 0x6c, 0x0a }, { 0x6d, 0x55 }, - { 0x6e, 0x11 }, { 0x6f, 0x9f }, /* "9e for advance AWB" */ - { 0x6a, 0x40 }, { REG_BLUE, 0x40 }, - { REG_RED, 0x60 }, - { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC|COM8_AWB }, - - /* Matrix coefficients */ - { 0x4f, 0x80 }, { 0x50, 0x80 }, - { 0x51, 0 }, { 0x52, 0x22 }, - { 0x53, 0x5e }, { 0x54, 0x80 }, - { 0x58, 0x9e }, - - { REG_COM16, COM16_AWBGAIN }, { REG_EDGE, 0 }, - { 0x75, 0x05 }, { 0x76, 0xe1 }, - { 0x4c, 0 }, { 0x77, 0x01 }, - { REG_COM13, 0xc3 }, { 0x4b, 0x09 }, - { 0xc9, 0x60 }, { REG_COM16, 0x38 }, - { 0x56, 0x40 }, - - { 0x34, 0x11 }, { REG_COM11, COM11_EXP|COM11_HZAUTO }, - { 0xa4, 0x88 }, { 0x96, 0 }, - { 0x97, 0x30 }, { 0x98, 0x20 }, - { 0x99, 0x30 }, { 0x9a, 0x84 }, - { 0x9b, 0x29 }, { 0x9c, 0x03 }, - { 0x9d, 0x4c }, { 0x9e, 0x3f }, - { 0x78, 0x04 }, - - /* Extra-weird stuff. Some sort of multiplexor register */ - { 0x79, 0x01 }, { 0xc8, 0xf0 }, - { 0x79, 0x0f }, { 0xc8, 0x00 }, - { 0x79, 0x10 }, { 0xc8, 0x7e }, - { 0x79, 0x0a }, { 0xc8, 0x80 }, - { 0x79, 0x0b }, { 0xc8, 0x01 }, - { 0x79, 0x0c }, { 0xc8, 0x0f }, - { 0x79, 0x0d }, { 0xc8, 0x20 }, - { 0x79, 0x09 }, { 0xc8, 0x80 }, - { 0x79, 0x02 }, { 0xc8, 0xc0 }, - { 0x79, 0x03 }, { 0xc8, 0x40 }, - { 0x79, 0x05 }, { 0xc8, 0x30 }, - { 0x79, 0x26 }, - - { 0xff, 0xff }, /* END MARKER */ -}; - - -/* - * Here we'll try to encapsulate the changes for just the output - * video format. - * - * RGB656 and YUV422 come from OV; RGB444 is homebrewed. - * - * IMPORTANT RULE: the first entry must be for COM7, see ov7670_s_fmt for why. - */ - - -static struct regval_list ov7670_fmt_yuv422[] = { - { REG_COM7, 0x0 }, /* Selects YUV mode */ - { REG_RGB444, 0 }, /* No RGB444 please */ - { REG_COM1, 0 }, /* CCIR601 */ - { REG_COM15, COM15_R00FF }, - { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0x80 }, /* "matrix coefficient 1" */ - { 0x50, 0x80 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x22 }, /* "matrix coefficient 4" */ - { 0x53, 0x5e }, /* "matrix coefficient 5" */ - { 0x54, 0x80 }, /* "matrix coefficient 6" */ - { REG_COM13, COM13_GAMMA|COM13_UVSAT }, - { 0xff, 0xff }, -}; - -static struct regval_list ov7670_fmt_rgb565[] = { - { REG_COM7, COM7_RGB }, /* Selects RGB mode */ - { REG_RGB444, 0 }, /* No RGB444 please */ - { REG_COM1, 0x0 }, /* CCIR601 */ - { REG_COM15, COM15_RGB565 }, - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ - { REG_COM13, COM13_GAMMA|COM13_UVSAT }, - { 0xff, 0xff }, -}; - -static struct regval_list ov7670_fmt_rgb444[] = { - { REG_COM7, COM7_RGB }, /* Selects RGB mode */ - { REG_RGB444, R444_ENABLE }, /* Enable xxxxrrrr ggggbbbb */ - { REG_COM1, 0x0 }, /* CCIR601 */ - { REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */ - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ - { REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2 }, /* Magic rsvd bit */ - { 0xff, 0xff }, -}; - -static struct regval_list ov7670_fmt_raw[] = { - { REG_COM7, COM7_BAYER }, - { REG_COM13, 0x08 }, /* No gamma, magic rsvd bit */ - { REG_COM16, 0x3d }, /* Edge enhancement, denoise */ - { REG_REG76, 0xe1 }, /* Pix correction, magic rsvd */ - { 0xff, 0xff }, -}; - - - -/* - * Low-level register I/O. - * - * Note that there are two versions of these. On the XO 1, the - * i2c controller only does SMBUS, so that's what we use. The - * ov7670 is not really an SMBUS device, though, so the communication - * is not always entirely reliable. - */ -static int ov7670_read_smbus(struct v4l2_subdev *sd, unsigned char reg, - unsigned char *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - ret = i2c_smbus_read_byte_data(client, reg); - if (ret >= 0) { - *value = (unsigned char)ret; - ret = 0; - } - return ret; -} - - -static int ov7670_write_smbus(struct v4l2_subdev *sd, unsigned char reg, - unsigned char value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = i2c_smbus_write_byte_data(client, reg, value); - - if (reg == REG_COM7 && (value & COM7_RESET)) - msleep(5); /* Wait for reset to run */ - return ret; -} - -/* - * On most platforms, we'd rather do straight i2c I/O. - */ -static int ov7670_read_i2c(struct v4l2_subdev *sd, unsigned char reg, - unsigned char *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 data = reg; - struct i2c_msg msg; - int ret; - - /* - * Send out the register address... - */ - msg.addr = client->addr; - msg.flags = 0; - msg.len = 1; - msg.buf = &data; - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - printk(KERN_ERR "Error %d on register write\n", ret); - return ret; - } - /* - * ...then read back the result. - */ - msg.flags = I2C_M_RD; - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret >= 0) { - *value = data; - ret = 0; - } - return ret; -} - - -static int ov7670_write_i2c(struct v4l2_subdev *sd, unsigned char reg, - unsigned char value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct i2c_msg msg; - unsigned char data[2] = { reg, value }; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 2; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret > 0) - ret = 0; - if (reg == REG_COM7 && (value & COM7_RESET)) - msleep(5); /* Wait for reset to run */ - return ret; -} - -static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg, - unsigned char *value) -{ - struct ov7670_info *info = to_state(sd); - if (info->use_smbus) - return ov7670_read_smbus(sd, reg, value); - else - return ov7670_read_i2c(sd, reg, value); -} - -static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg, - unsigned char value) -{ - struct ov7670_info *info = to_state(sd); - if (info->use_smbus) - return ov7670_write_smbus(sd, reg, value); - else - return ov7670_write_i2c(sd, reg, value); -} - -/* - * Write a list of register settings; ff/ff stops the process. - */ -static int ov7670_write_array(struct v4l2_subdev *sd, struct regval_list *vals) -{ - while (vals->reg_num != 0xff || vals->value != 0xff) { - int ret = ov7670_write(sd, vals->reg_num, vals->value); - if (ret < 0) - return ret; - vals++; - } - return 0; -} - - -/* - * Stuff that knows about the sensor. - */ -static int ov7670_reset(struct v4l2_subdev *sd, u32 val) -{ - ov7670_write(sd, REG_COM7, COM7_RESET); - msleep(1); - return 0; -} - - -static int ov7670_init(struct v4l2_subdev *sd, u32 val) -{ - return ov7670_write_array(sd, ov7670_default_regs); -} - - - -static int ov7670_detect(struct v4l2_subdev *sd) -{ - unsigned char v; - int ret; - - ret = ov7670_init(sd, 0); - if (ret < 0) - return ret; - ret = ov7670_read(sd, REG_MIDH, &v); - if (ret < 0) - return ret; - if (v != 0x7f) /* OV manuf. id. */ - return -ENODEV; - ret = ov7670_read(sd, REG_MIDL, &v); - if (ret < 0) - return ret; - if (v != 0xa2) - return -ENODEV; - /* - * OK, we know we have an OmniVision chip...but which one? - */ - ret = ov7670_read(sd, REG_PID, &v); - if (ret < 0) - return ret; - if (v != 0x76) /* PID + VER = 0x76 / 0x73 */ - return -ENODEV; - ret = ov7670_read(sd, REG_VER, &v); - if (ret < 0) - return ret; - if (v != 0x73) /* PID + VER = 0x76 / 0x73 */ - return -ENODEV; - return 0; -} - - -/* - * Store information about the video data format. The color matrix - * is deeply tied into the format, so keep the relevant values here. - * The magic matrix numbers come from OmniVision. - */ -static struct ov7670_format_struct { - enum v4l2_mbus_pixelcode mbus_code; - enum v4l2_colorspace colorspace; - struct regval_list *regs; - int cmatrix[CMATRIX_LEN]; -} ov7670_formats[] = { - { - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .regs = ov7670_fmt_yuv422, - .cmatrix = { 128, -128, 0, -34, -94, 128 }, - }, - { - .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .regs = ov7670_fmt_rgb444, - .cmatrix = { 179, -179, 0, -61, -176, 228 }, - }, - { - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .regs = ov7670_fmt_rgb565, - .cmatrix = { 179, -179, 0, -61, -176, 228 }, - }, - { - .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .regs = ov7670_fmt_raw, - .cmatrix = { 0, 0, 0, 0, 0, 0 }, - }, -}; -#define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats) - - -/* - * Then there is the issue of window sizes. Try to capture the info here. - */ - -/* - * QCIF mode is done (by OV) in a very strange way - it actually looks like - * VGA with weird scaling options - they do *not* use the canned QCIF mode - * which is allegedly provided by the sensor. So here's the weird register - * settings. - */ -static struct regval_list ov7670_qcif_regs[] = { - { REG_COM3, COM3_SCALEEN|COM3_DCWEN }, - { REG_COM3, COM3_DCWEN }, - { REG_COM14, COM14_DCWEN | 0x01}, - { 0x73, 0xf1 }, - { 0xa2, 0x52 }, - { 0x7b, 0x1c }, - { 0x7c, 0x28 }, - { 0x7d, 0x3c }, - { 0x7f, 0x69 }, - { REG_COM9, 0x38 }, - { 0xa1, 0x0b }, - { 0x74, 0x19 }, - { 0x9a, 0x80 }, - { 0x43, 0x14 }, - { REG_COM13, 0xc0 }, - { 0xff, 0xff }, -}; - -static struct ov7670_win_size { - int width; - int height; - unsigned char com7_bit; - int hstart; /* Start/stop values for the camera. Note */ - int hstop; /* that they do not always make complete */ - int vstart; /* sense to humans, but evidently the sensor */ - int vstop; /* will do the right thing... */ - struct regval_list *regs; /* Regs to tweak */ -/* h/vref stuff */ -} ov7670_win_sizes[] = { - /* VGA */ - { - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .com7_bit = COM7_FMT_VGA, - .hstart = 158, /* These values from */ - .hstop = 14, /* Omnivision */ - .vstart = 10, - .vstop = 490, - .regs = NULL, - }, - /* CIF */ - { - .width = CIF_WIDTH, - .height = CIF_HEIGHT, - .com7_bit = COM7_FMT_CIF, - .hstart = 170, /* Empirically determined */ - .hstop = 90, - .vstart = 14, - .vstop = 494, - .regs = NULL, - }, - /* QVGA */ - { - .width = QVGA_WIDTH, - .height = QVGA_HEIGHT, - .com7_bit = COM7_FMT_QVGA, - .hstart = 168, /* Empirically determined */ - .hstop = 24, - .vstart = 12, - .vstop = 492, - .regs = NULL, - }, - /* QCIF */ - { - .width = QCIF_WIDTH, - .height = QCIF_HEIGHT, - .com7_bit = COM7_FMT_VGA, /* see comment above */ - .hstart = 456, /* Empirically determined */ - .hstop = 24, - .vstart = 14, - .vstop = 494, - .regs = ov7670_qcif_regs, - }, -}; - -#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes)) - - -/* - * Store a set of start/stop values into the camera. - */ -static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop, - int vstart, int vstop) -{ - int ret; - unsigned char v; -/* - * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of - * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is - * a mystery "edge offset" value in the top two bits of href. - */ - ret = ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff); - ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff); - ret += ov7670_read(sd, REG_HREF, &v); - v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); - msleep(10); - ret += ov7670_write(sd, REG_HREF, v); -/* - * Vertical: similar arrangement, but only 10 bits. - */ - ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff); - ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff); - ret += ov7670_read(sd, REG_VREF, &v); - v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); - msleep(10); - ret += ov7670_write(sd, REG_VREF, v); - return ret; -} - - -static int ov7670_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - enum v4l2_mbus_pixelcode *code) -{ - if (index >= N_OV7670_FMTS) - return -EINVAL; - - *code = ov7670_formats[index].mbus_code; - return 0; -} - -static int ov7670_try_fmt_internal(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt, - struct ov7670_format_struct **ret_fmt, - struct ov7670_win_size **ret_wsize) -{ - int index; - struct ov7670_win_size *wsize; - - for (index = 0; index < N_OV7670_FMTS; index++) - if (ov7670_formats[index].mbus_code == fmt->code) - break; - if (index >= N_OV7670_FMTS) { - /* default to first format */ - index = 0; - fmt->code = ov7670_formats[0].mbus_code; - } - if (ret_fmt != NULL) - *ret_fmt = ov7670_formats + index; - /* - * Fields: the OV devices claim to be progressive. - */ - fmt->field = V4L2_FIELD_NONE; - /* - * Round requested image size down to the nearest - * we support, but not below the smallest. - */ - for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES; - wsize++) - if (fmt->width >= wsize->width && fmt->height >= wsize->height) - break; - if (wsize >= ov7670_win_sizes + N_WIN_SIZES) - wsize--; /* Take the smallest one */ - if (ret_wsize != NULL) - *ret_wsize = wsize; - /* - * Note the size we'll actually handle. - */ - fmt->width = wsize->width; - fmt->height = wsize->height; - fmt->colorspace = ov7670_formats[index].colorspace; - return 0; -} - -static int ov7670_try_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) -{ - return ov7670_try_fmt_internal(sd, fmt, NULL, NULL); -} - -/* - * Set a format. - */ -static int ov7670_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) -{ - struct ov7670_format_struct *ovfmt; - struct ov7670_win_size *wsize; - struct ov7670_info *info = to_state(sd); - unsigned char com7; - int ret; - - ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize); - - if (ret) - return ret; - /* - * COM7 is a pain in the ass, it doesn't like to be read then - * quickly written afterward. But we have everything we need - * to set it absolutely here, as long as the format-specific - * register sets list it first. - */ - com7 = ovfmt->regs[0].value; - com7 |= wsize->com7_bit; - ov7670_write(sd, REG_COM7, com7); - /* - * Now write the rest of the array. Also store start/stops - */ - ov7670_write_array(sd, ovfmt->regs + 1); - ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart, - wsize->vstop); - ret = 0; - if (wsize->regs) - ret = ov7670_write_array(sd, wsize->regs); - info->fmt = ovfmt; - - /* - * If we're running RGB565, we must rewrite clkrc after setting - * the other parameters or the image looks poor. If we're *not* - * doing RGB565, we must not rewrite clkrc or the image looks - * *really* poor. - * - * (Update) Now that we retain clkrc state, we should be able - * to write it unconditionally, and that will make the frame - * rate persistent too. - */ - if (ret == 0) - ret = ov7670_write(sd, REG_CLKRC, info->clkrc); - return 0; -} - -/* - * Implement G/S_PARM. There is a "high quality" mode we could try - * to do someday; for now, we just do the frame rate tweak. - */ -static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -{ - struct v4l2_captureparm *cp = &parms->parm.capture; - struct ov7670_info *info = to_state(sd); - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(struct v4l2_captureparm)); - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = 1; - cp->timeperframe.denominator = info->clock_speed; - if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1) - cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE); - return 0; -} - -static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -{ - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; - struct ov7670_info *info = to_state(sd); - int div; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (cp->extendedmode != 0) - return -EINVAL; - - if (tpf->numerator == 0 || tpf->denominator == 0) - div = 1; /* Reset to full rate */ - else - div = (tpf->numerator * info->clock_speed) / tpf->denominator; - if (div == 0) - div = 1; - else if (div > CLK_SCALE) - div = CLK_SCALE; - info->clkrc = (info->clkrc & 0x80) | div; - tpf->numerator = 1; - tpf->denominator = info->clock_speed / div; - return ov7670_write(sd, REG_CLKRC, info->clkrc); -} - - -/* - * Frame intervals. Since frame rates are controlled with the clock - * divider, we can only do 30/n for integer n values. So no continuous - * or stepwise options. Here we just pick a handful of logical values. - */ - -static int ov7670_frame_rates[] = { 30, 15, 10, 5, 1 }; - -static int ov7670_enum_frameintervals(struct v4l2_subdev *sd, - struct v4l2_frmivalenum *interval) -{ - if (interval->index >= ARRAY_SIZE(ov7670_frame_rates)) - return -EINVAL; - interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; - interval->discrete.numerator = 1; - interval->discrete.denominator = ov7670_frame_rates[interval->index]; - return 0; -} - -/* - * Frame size enumeration - */ -static int ov7670_enum_framesizes(struct v4l2_subdev *sd, - struct v4l2_frmsizeenum *fsize) -{ - struct ov7670_info *info = to_state(sd); - int i; - int num_valid = -1; - __u32 index = fsize->index; - - /* - * If a minimum width/height was requested, filter out the capture - * windows that fall outside that. - */ - for (i = 0; i < N_WIN_SIZES; i++) { - struct ov7670_win_size *win = &ov7670_win_sizes[index]; - if (info->min_width && win->width < info->min_width) - continue; - if (info->min_height && win->height < info->min_height) - continue; - if (index == ++num_valid) { - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = win->width; - fsize->discrete.height = win->height; - return 0; - } - } - - return -EINVAL; -} - -/* - * Code for dealing with controls. - */ - -static int ov7670_store_cmatrix(struct v4l2_subdev *sd, - int matrix[CMATRIX_LEN]) -{ - int i, ret; - unsigned char signbits = 0; - - /* - * Weird crap seems to exist in the upper part of - * the sign bits register, so let's preserve it. - */ - ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits); - signbits &= 0xc0; - - for (i = 0; i < CMATRIX_LEN; i++) { - unsigned char raw; - - if (matrix[i] < 0) { - signbits |= (1 << i); - if (matrix[i] < -255) - raw = 0xff; - else - raw = (-1 * matrix[i]) & 0xff; - } - else { - if (matrix[i] > 255) - raw = 0xff; - else - raw = matrix[i] & 0xff; - } - ret += ov7670_write(sd, REG_CMATRIX_BASE + i, raw); - } - ret += ov7670_write(sd, REG_CMATRIX_SIGN, signbits); - return ret; -} - - -/* - * Hue also requires messing with the color matrix. It also requires - * trig functions, which tend not to be well supported in the kernel. - * So here is a simple table of sine values, 0-90 degrees, in steps - * of five degrees. Values are multiplied by 1000. - * - * The following naive approximate trig functions require an argument - * carefully limited to -180 <= theta <= 180. - */ -#define SIN_STEP 5 -static const int ov7670_sin_table[] = { - 0, 87, 173, 258, 342, 422, - 499, 573, 642, 707, 766, 819, - 866, 906, 939, 965, 984, 996, - 1000 -}; - -static int ov7670_sine(int theta) -{ - int chs = 1; - int sine; - - if (theta < 0) { - theta = -theta; - chs = -1; - } - if (theta <= 90) - sine = ov7670_sin_table[theta/SIN_STEP]; - else { - theta -= 90; - sine = 1000 - ov7670_sin_table[theta/SIN_STEP]; - } - return sine*chs; -} - -static int ov7670_cosine(int theta) -{ - theta = 90 - theta; - if (theta > 180) - theta -= 360; - else if (theta < -180) - theta += 360; - return ov7670_sine(theta); -} - - - - -static void ov7670_calc_cmatrix(struct ov7670_info *info, - int matrix[CMATRIX_LEN]) -{ - int i; - /* - * Apply the current saturation setting first. - */ - for (i = 0; i < CMATRIX_LEN; i++) - matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7; - /* - * Then, if need be, rotate the hue value. - */ - if (info->hue != 0) { - int sinth, costh, tmpmatrix[CMATRIX_LEN]; - - memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int)); - sinth = ov7670_sine(info->hue); - costh = ov7670_cosine(info->hue); - - matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000; - matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000; - matrix[2] = (matrix[5]*sinth + matrix[2]*costh)/1000; - matrix[3] = (matrix[3]*costh - matrix[0]*sinth)/1000; - matrix[4] = (matrix[4]*costh - matrix[1]*sinth)/1000; - matrix[5] = (matrix[5]*costh - matrix[2]*sinth)/1000; - } -} - - - -static int ov7670_s_sat(struct v4l2_subdev *sd, int value) -{ - struct ov7670_info *info = to_state(sd); - int matrix[CMATRIX_LEN]; - int ret; - - info->sat = value; - ov7670_calc_cmatrix(info, matrix); - ret = ov7670_store_cmatrix(sd, matrix); - return ret; -} - -static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value) -{ - struct ov7670_info *info = to_state(sd); - - *value = info->sat; - return 0; -} - -static int ov7670_s_hue(struct v4l2_subdev *sd, int value) -{ - struct ov7670_info *info = to_state(sd); - int matrix[CMATRIX_LEN]; - int ret; - - if (value < -180 || value > 180) - return -EINVAL; - info->hue = value; - ov7670_calc_cmatrix(info, matrix); - ret = ov7670_store_cmatrix(sd, matrix); - return ret; -} - - -static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value) -{ - struct ov7670_info *info = to_state(sd); - - *value = info->hue; - return 0; -} - - -/* - * Some weird registers seem to store values in a sign/magnitude format! - */ -static unsigned char ov7670_sm_to_abs(unsigned char v) -{ - if ((v & 0x80) == 0) - return v + 128; - return 128 - (v & 0x7f); -} - - -static unsigned char ov7670_abs_to_sm(unsigned char v) -{ - if (v > 127) - return v & 0x7f; - return (128 - v) | 0x80; -} - -static int ov7670_s_brightness(struct v4l2_subdev *sd, int value) -{ - unsigned char com8 = 0, v; - int ret; - - ov7670_read(sd, REG_COM8, &com8); - com8 &= ~COM8_AEC; - ov7670_write(sd, REG_COM8, com8); - v = ov7670_abs_to_sm(value); - ret = ov7670_write(sd, REG_BRIGHT, v); - return ret; -} - -static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value) -{ - unsigned char v = 0; - int ret = ov7670_read(sd, REG_BRIGHT, &v); - - *value = ov7670_sm_to_abs(v); - return ret; -} - -static int ov7670_s_contrast(struct v4l2_subdev *sd, int value) -{ - return ov7670_write(sd, REG_CONTRAS, (unsigned char) value); -} - -static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value) -{ - unsigned char v = 0; - int ret = ov7670_read(sd, REG_CONTRAS, &v); - - *value = v; - return ret; -} - -static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value) -{ - int ret; - unsigned char v = 0; - - ret = ov7670_read(sd, REG_MVFP, &v); - *value = (v & MVFP_MIRROR) == MVFP_MIRROR; - return ret; -} - - -static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) -{ - unsigned char v = 0; - int ret; - - ret = ov7670_read(sd, REG_MVFP, &v); - if (value) - v |= MVFP_MIRROR; - else - v &= ~MVFP_MIRROR; - msleep(10); /* FIXME */ - ret += ov7670_write(sd, REG_MVFP, v); - return ret; -} - - - -static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value) -{ - int ret; - unsigned char v = 0; - - ret = ov7670_read(sd, REG_MVFP, &v); - *value = (v & MVFP_FLIP) == MVFP_FLIP; - return ret; -} - - -static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) -{ - unsigned char v = 0; - int ret; - - ret = ov7670_read(sd, REG_MVFP, &v); - if (value) - v |= MVFP_FLIP; - else - v &= ~MVFP_FLIP; - msleep(10); /* FIXME */ - ret += ov7670_write(sd, REG_MVFP, v); - return ret; -} - -/* - * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes - * the data sheet, the VREF parts should be the most significant, but - * experience shows otherwise. There seems to be little value in - * messing with the VREF bits, so we leave them alone. - */ -static int ov7670_g_gain(struct v4l2_subdev *sd, __s32 *value) -{ - int ret; - unsigned char gain; - - ret = ov7670_read(sd, REG_GAIN, &gain); - *value = gain; - return ret; -} - -static int ov7670_s_gain(struct v4l2_subdev *sd, int value) -{ - int ret; - unsigned char com8; - - ret = ov7670_write(sd, REG_GAIN, value & 0xff); - /* Have to turn off AGC as well */ - if (ret == 0) { - ret = ov7670_read(sd, REG_COM8, &com8); - ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AGC); - } - return ret; -} - -/* - * Tweak autogain. - */ -static int ov7670_g_autogain(struct v4l2_subdev *sd, __s32 *value) -{ - int ret; - unsigned char com8; - - ret = ov7670_read(sd, REG_COM8, &com8); - *value = (com8 & COM8_AGC) != 0; - return ret; -} - -static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) -{ - int ret; - unsigned char com8; - - ret = ov7670_read(sd, REG_COM8, &com8); - if (ret == 0) { - if (value) - com8 |= COM8_AGC; - else - com8 &= ~COM8_AGC; - ret = ov7670_write(sd, REG_COM8, com8); - } - return ret; -} - -/* - * Exposure is spread all over the place: top 6 bits in AECHH, middle - * 8 in AECH, and two stashed in COM1 just for the hell of it. - */ -static int ov7670_g_exp(struct v4l2_subdev *sd, __s32 *value) -{ - int ret; - unsigned char com1, aech, aechh; - - ret = ov7670_read(sd, REG_COM1, &com1) + - ov7670_read(sd, REG_AECH, &aech) + - ov7670_read(sd, REG_AECHH, &aechh); - *value = ((aechh & 0x3f) << 10) | (aech << 2) | (com1 & 0x03); - return ret; -} - -static int ov7670_s_exp(struct v4l2_subdev *sd, int value) -{ - int ret; - unsigned char com1, com8, aech, aechh; - - ret = ov7670_read(sd, REG_COM1, &com1) + - ov7670_read(sd, REG_COM8, &com8); - ov7670_read(sd, REG_AECHH, &aechh); - if (ret) - return ret; - - com1 = (com1 & 0xfc) | (value & 0x03); - aech = (value >> 2) & 0xff; - aechh = (aechh & 0xc0) | ((value >> 10) & 0x3f); - ret = ov7670_write(sd, REG_COM1, com1) + - ov7670_write(sd, REG_AECH, aech) + - ov7670_write(sd, REG_AECHH, aechh); - /* Have to turn off AEC as well */ - if (ret == 0) - ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AEC); - return ret; -} - -/* - * Tweak autoexposure. - */ -static int ov7670_g_autoexp(struct v4l2_subdev *sd, __s32 *value) -{ - int ret; - unsigned char com8; - enum v4l2_exposure_auto_type *atype = (enum v4l2_exposure_auto_type *) value; - - ret = ov7670_read(sd, REG_COM8, &com8); - if (com8 & COM8_AEC) - *atype = V4L2_EXPOSURE_AUTO; - else - *atype = V4L2_EXPOSURE_MANUAL; - return ret; -} - -static int ov7670_s_autoexp(struct v4l2_subdev *sd, - enum v4l2_exposure_auto_type value) -{ - int ret; - unsigned char com8; - - ret = ov7670_read(sd, REG_COM8, &com8); - if (ret == 0) { - if (value == V4L2_EXPOSURE_AUTO) - com8 |= COM8_AEC; - else - com8 &= ~COM8_AEC; - ret = ov7670_write(sd, REG_COM8, com8); - } - return ret; -} - - - -static int ov7670_queryctrl(struct v4l2_subdev *sd, - struct v4l2_queryctrl *qc) -{ - /* Fill in min, max, step and default value for these controls. */ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); - case V4L2_CID_VFLIP: - case V4L2_CID_HFLIP: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0); - case V4L2_CID_GAIN: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); - case V4L2_CID_AUTOGAIN: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_EXPOSURE: - return v4l2_ctrl_query_fill(qc, 0, 65535, 1, 500); - case V4L2_CID_EXPOSURE_AUTO: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - } - return -EINVAL; -} - -static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - return ov7670_g_brightness(sd, &ctrl->value); - case V4L2_CID_CONTRAST: - return ov7670_g_contrast(sd, &ctrl->value); - case V4L2_CID_SATURATION: - return ov7670_g_sat(sd, &ctrl->value); - case V4L2_CID_HUE: - return ov7670_g_hue(sd, &ctrl->value); - case V4L2_CID_VFLIP: - return ov7670_g_vflip(sd, &ctrl->value); - case V4L2_CID_HFLIP: - return ov7670_g_hflip(sd, &ctrl->value); - case V4L2_CID_GAIN: - return ov7670_g_gain(sd, &ctrl->value); - case V4L2_CID_AUTOGAIN: - return ov7670_g_autogain(sd, &ctrl->value); - case V4L2_CID_EXPOSURE: - return ov7670_g_exp(sd, &ctrl->value); - case V4L2_CID_EXPOSURE_AUTO: - return ov7670_g_autoexp(sd, &ctrl->value); - } - return -EINVAL; -} - -static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - return ov7670_s_brightness(sd, ctrl->value); - case V4L2_CID_CONTRAST: - return ov7670_s_contrast(sd, ctrl->value); - case V4L2_CID_SATURATION: - return ov7670_s_sat(sd, ctrl->value); - case V4L2_CID_HUE: - return ov7670_s_hue(sd, ctrl->value); - case V4L2_CID_VFLIP: - return ov7670_s_vflip(sd, ctrl->value); - case V4L2_CID_HFLIP: - return ov7670_s_hflip(sd, ctrl->value); - case V4L2_CID_GAIN: - return ov7670_s_gain(sd, ctrl->value); - case V4L2_CID_AUTOGAIN: - return ov7670_s_autogain(sd, ctrl->value); - case V4L2_CID_EXPOSURE: - return ov7670_s_exp(sd, ctrl->value); - case V4L2_CID_EXPOSURE_AUTO: - return ov7670_s_autoexp(sd, - (enum v4l2_exposure_auto_type) ctrl->value); - } - return -EINVAL; -} - -static int ov7670_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned char val = 0; - int ret; - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - ret = ov7670_read(sd, reg->reg & 0xff, &val); - reg->val = val; - reg->size = 1; - return ret; -} - -static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - ov7670_write(sd, reg->reg & 0xff, reg->val & 0xff); - return 0; -} -#endif - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops ov7670_core_ops = { - .g_chip_ident = ov7670_g_chip_ident, - .g_ctrl = ov7670_g_ctrl, - .s_ctrl = ov7670_s_ctrl, - .queryctrl = ov7670_queryctrl, - .reset = ov7670_reset, - .init = ov7670_init, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov7670_g_register, - .s_register = ov7670_s_register, -#endif -}; - -static const struct v4l2_subdev_video_ops ov7670_video_ops = { - .enum_mbus_fmt = ov7670_enum_mbus_fmt, - .try_mbus_fmt = ov7670_try_mbus_fmt, - .s_mbus_fmt = ov7670_s_mbus_fmt, - .s_parm = ov7670_s_parm, - .g_parm = ov7670_g_parm, - .enum_frameintervals = ov7670_enum_frameintervals, - .enum_framesizes = ov7670_enum_framesizes, -}; - -static const struct v4l2_subdev_ops ov7670_ops = { - .core = &ov7670_core_ops, - .video = &ov7670_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int ov7670_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct v4l2_subdev *sd; - struct ov7670_info *info; - int ret; - - info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL); - if (info == NULL) - return -ENOMEM; - sd = &info->sd; - v4l2_i2c_subdev_init(sd, client, &ov7670_ops); - - info->clock_speed = 30; /* default: a guess */ - if (client->dev.platform_data) { - struct ov7670_config *config = client->dev.platform_data; - - /* - * Must apply configuration before initializing device, because it - * selects I/O method. - */ - info->min_width = config->min_width; - info->min_height = config->min_height; - info->use_smbus = config->use_smbus; - - if (config->clock_speed) - info->clock_speed = config->clock_speed; - } - - /* Make sure it's an ov7670 */ - ret = ov7670_detect(sd); - if (ret) { - v4l_dbg(1, debug, client, - "chip found @ 0x%x (%s) is not an ov7670 chip.\n", - client->addr << 1, client->adapter->name); - kfree(info); - return ret; - } - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr << 1, client->adapter->name); - - info->fmt = &ov7670_formats[0]; - info->sat = 128; /* Review this */ - info->clkrc = info->clock_speed / 30; - return 0; -} - - -static int ov7670_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id ov7670_id[] = { - { "ov7670", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov7670_id); - -static struct i2c_driver ov7670_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "ov7670", - }, - .probe = ov7670_probe, - .remove = ov7670_remove, - .id_table = ov7670_id, -}; - -static __init int init_ov7670(void) -{ - return i2c_add_driver(&ov7670_driver); -} - -static __exit void exit_ov7670(void) -{ - i2c_del_driver(&ov7670_driver); -} - -module_init(init_ov7670); -module_exit(exit_ov7670); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov7670.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov7670.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov7670.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov7670.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -/* - * A V4L2 driver for OmniVision OV7670 cameras. - * - * Copyright 2010 One Laptop Per Child - * - * This file may be distributed under the terms of the GNU General - * Public License, version 2. - */ - -#ifndef __OV7670_H -#define __OV7670_H - -struct ov7670_config { - int min_width; /* Filter out smaller sizes */ - int min_height; /* Filter out smaller sizes */ - int clock_speed; /* External clock speed (MHz) */ - bool use_smbus; /* Use smbus I/O instead of I2C */ -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov772x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov772x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov772x.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov772x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1209 +0,0 @@ -/* - * ov772x Camera Driver - * - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto - * - * Based on ov7670 and soc_camera_platform driver, - * - * Copyright 2006-7 Jonathan Corbet - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * register offset - */ -#define GAIN 0x00 /* AGC - Gain control gain setting */ -#define BLUE 0x01 /* AWB - Blue channel gain setting */ -#define RED 0x02 /* AWB - Red channel gain setting */ -#define GREEN 0x03 /* AWB - Green channel gain setting */ -#define COM1 0x04 /* Common control 1 */ -#define BAVG 0x05 /* U/B Average Level */ -#define GAVG 0x06 /* Y/Gb Average Level */ -#define RAVG 0x07 /* V/R Average Level */ -#define AECH 0x08 /* Exposure Value - AEC MSBs */ -#define COM2 0x09 /* Common control 2 */ -#define PID 0x0A /* Product ID Number MSB */ -#define VER 0x0B /* Product ID Number LSB */ -#define COM3 0x0C /* Common control 3 */ -#define COM4 0x0D /* Common control 4 */ -#define COM5 0x0E /* Common control 5 */ -#define COM6 0x0F /* Common control 6 */ -#define AEC 0x10 /* Exposure Value */ -#define CLKRC 0x11 /* Internal clock */ -#define COM7 0x12 /* Common control 7 */ -#define COM8 0x13 /* Common control 8 */ -#define COM9 0x14 /* Common control 9 */ -#define COM10 0x15 /* Common control 10 */ -#define REG16 0x16 /* Register 16 */ -#define HSTART 0x17 /* Horizontal sensor size */ -#define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */ -#define VSTART 0x19 /* Vertical frame (row) start high 8-bit */ -#define VSIZE 0x1A /* Vertical sensor size */ -#define PSHFT 0x1B /* Data format - pixel delay select */ -#define MIDH 0x1C /* Manufacturer ID byte - high */ -#define MIDL 0x1D /* Manufacturer ID byte - low */ -#define LAEC 0x1F /* Fine AEC value */ -#define COM11 0x20 /* Common control 11 */ -#define BDBASE 0x22 /* Banding filter Minimum AEC value */ -#define DBSTEP 0x23 /* Banding filter Maximum Setp */ -#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */ -#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */ -#define VPT 0x26 /* AGC/AEC Fast mode operating region */ -#define REG28 0x28 /* Register 28 */ -#define HOUTSIZE 0x29 /* Horizontal data output size MSBs */ -#define EXHCH 0x2A /* Dummy pixel insert MSB */ -#define EXHCL 0x2B /* Dummy pixel insert LSB */ -#define VOUTSIZE 0x2C /* Vertical data output size MSBs */ -#define ADVFL 0x2D /* LSB of insert dummy lines in Vertical direction */ -#define ADVFH 0x2E /* MSG of insert dummy lines in Vertical direction */ -#define YAVE 0x2F /* Y/G Channel Average value */ -#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance high level threshold */ -#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance low level threshold */ -#define HREF 0x32 /* Image start and size control */ -#define DM_LNL 0x33 /* Dummy line low 8 bits */ -#define DM_LNH 0x34 /* Dummy line high 8 bits */ -#define ADOFF_B 0x35 /* AD offset compensation value for B channel */ -#define ADOFF_R 0x36 /* AD offset compensation value for R channel */ -#define ADOFF_GB 0x37 /* AD offset compensation value for Gb channel */ -#define ADOFF_GR 0x38 /* AD offset compensation value for Gr channel */ -#define OFF_B 0x39 /* Analog process B channel offset value */ -#define OFF_R 0x3A /* Analog process R channel offset value */ -#define OFF_GB 0x3B /* Analog process Gb channel offset value */ -#define OFF_GR 0x3C /* Analog process Gr channel offset value */ -#define COM12 0x3D /* Common control 12 */ -#define COM13 0x3E /* Common control 13 */ -#define COM14 0x3F /* Common control 14 */ -#define COM15 0x40 /* Common control 15*/ -#define COM16 0x41 /* Common control 16 */ -#define TGT_B 0x42 /* BLC blue channel target value */ -#define TGT_R 0x43 /* BLC red channel target value */ -#define TGT_GB 0x44 /* BLC Gb channel target value */ -#define TGT_GR 0x45 /* BLC Gr channel target value */ -/* for ov7720 */ -#define LCC0 0x46 /* Lens correction control 0 */ -#define LCC1 0x47 /* Lens correction option 1 - X coordinate */ -#define LCC2 0x48 /* Lens correction option 2 - Y coordinate */ -#define LCC3 0x49 /* Lens correction option 3 */ -#define LCC4 0x4A /* Lens correction option 4 - radius of the circular */ -#define LCC5 0x4B /* Lens correction option 5 */ -#define LCC6 0x4C /* Lens correction option 6 */ -/* for ov7725 */ -#define LC_CTR 0x46 /* Lens correction control */ -#define LC_XC 0x47 /* X coordinate of lens correction center relative */ -#define LC_YC 0x48 /* Y coordinate of lens correction center relative */ -#define LC_COEF 0x49 /* Lens correction coefficient */ -#define LC_RADI 0x4A /* Lens correction radius */ -#define LC_COEFB 0x4B /* Lens B channel compensation coefficient */ -#define LC_COEFR 0x4C /* Lens R channel compensation coefficient */ - -#define FIXGAIN 0x4D /* Analog fix gain amplifer */ -#define AREF0 0x4E /* Sensor reference control */ -#define AREF1 0x4F /* Sensor reference current control */ -#define AREF2 0x50 /* Analog reference control */ -#define AREF3 0x51 /* ADC reference control */ -#define AREF4 0x52 /* ADC reference control */ -#define AREF5 0x53 /* ADC reference control */ -#define AREF6 0x54 /* Analog reference control */ -#define AREF7 0x55 /* Analog reference control */ -#define UFIX 0x60 /* U channel fixed value output */ -#define VFIX 0x61 /* V channel fixed value output */ -#define AWBB_BLK 0x62 /* AWB option for advanced AWB */ -#define AWB_CTRL0 0x63 /* AWB control byte 0 */ -#define DSP_CTRL1 0x64 /* DSP control byte 1 */ -#define DSP_CTRL2 0x65 /* DSP control byte 2 */ -#define DSP_CTRL3 0x66 /* DSP control byte 3 */ -#define DSP_CTRL4 0x67 /* DSP control byte 4 */ -#define AWB_BIAS 0x68 /* AWB BLC level clip */ -#define AWB_CTRL1 0x69 /* AWB control 1 */ -#define AWB_CTRL2 0x6A /* AWB control 2 */ -#define AWB_CTRL3 0x6B /* AWB control 3 */ -#define AWB_CTRL4 0x6C /* AWB control 4 */ -#define AWB_CTRL5 0x6D /* AWB control 5 */ -#define AWB_CTRL6 0x6E /* AWB control 6 */ -#define AWB_CTRL7 0x6F /* AWB control 7 */ -#define AWB_CTRL8 0x70 /* AWB control 8 */ -#define AWB_CTRL9 0x71 /* AWB control 9 */ -#define AWB_CTRL10 0x72 /* AWB control 10 */ -#define AWB_CTRL11 0x73 /* AWB control 11 */ -#define AWB_CTRL12 0x74 /* AWB control 12 */ -#define AWB_CTRL13 0x75 /* AWB control 13 */ -#define AWB_CTRL14 0x76 /* AWB control 14 */ -#define AWB_CTRL15 0x77 /* AWB control 15 */ -#define AWB_CTRL16 0x78 /* AWB control 16 */ -#define AWB_CTRL17 0x79 /* AWB control 17 */ -#define AWB_CTRL18 0x7A /* AWB control 18 */ -#define AWB_CTRL19 0x7B /* AWB control 19 */ -#define AWB_CTRL20 0x7C /* AWB control 20 */ -#define AWB_CTRL21 0x7D /* AWB control 21 */ -#define GAM1 0x7E /* Gamma Curve 1st segment input end point */ -#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */ -#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */ -#define GAM4 0x81 /* Gamma Curve 4th segment input end point */ -#define GAM5 0x82 /* Gamma Curve 5th segment input end point */ -#define GAM6 0x83 /* Gamma Curve 6th segment input end point */ -#define GAM7 0x84 /* Gamma Curve 7th segment input end point */ -#define GAM8 0x85 /* Gamma Curve 8th segment input end point */ -#define GAM9 0x86 /* Gamma Curve 9th segment input end point */ -#define GAM10 0x87 /* Gamma Curve 10th segment input end point */ -#define GAM11 0x88 /* Gamma Curve 11th segment input end point */ -#define GAM12 0x89 /* Gamma Curve 12th segment input end point */ -#define GAM13 0x8A /* Gamma Curve 13th segment input end point */ -#define GAM14 0x8B /* Gamma Curve 14th segment input end point */ -#define GAM15 0x8C /* Gamma Curve 15th segment input end point */ -#define SLOP 0x8D /* Gamma curve highest segment slope */ -#define DNSTH 0x8E /* De-noise threshold */ -#define EDGE_STRNGT 0x8F /* Edge strength control when manual mode */ -#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */ -#define DNSOFF 0x91 /* Auto De-noise threshold control */ -#define EDGE_UPPER 0x92 /* Edge strength upper limit when Auto mode */ -#define EDGE_LOWER 0x93 /* Edge strength lower limit when Auto mode */ -#define MTX1 0x94 /* Matrix coefficient 1 */ -#define MTX2 0x95 /* Matrix coefficient 2 */ -#define MTX3 0x96 /* Matrix coefficient 3 */ -#define MTX4 0x97 /* Matrix coefficient 4 */ -#define MTX5 0x98 /* Matrix coefficient 5 */ -#define MTX6 0x99 /* Matrix coefficient 6 */ -#define MTX_CTRL 0x9A /* Matrix control */ -#define BRIGHT 0x9B /* Brightness control */ -#define CNTRST 0x9C /* Contrast contrast */ -#define CNTRST_CTRL 0x9D /* Contrast contrast center */ -#define UVAD_J0 0x9E /* Auto UV adjust contrast 0 */ -#define UVAD_J1 0x9F /* Auto UV adjust contrast 1 */ -#define SCAL0 0xA0 /* Scaling control 0 */ -#define SCAL1 0xA1 /* Scaling control 1 */ -#define SCAL2 0xA2 /* Scaling control 2 */ -#define FIFODLYM 0xA3 /* FIFO manual mode delay control */ -#define FIFODLYA 0xA4 /* FIFO auto mode delay control */ -#define SDE 0xA6 /* Special digital effect control */ -#define USAT 0xA7 /* U component saturation control */ -#define VSAT 0xA8 /* V component saturation control */ -/* for ov7720 */ -#define HUE0 0xA9 /* Hue control 0 */ -#define HUE1 0xAA /* Hue control 1 */ -/* for ov7725 */ -#define HUECOS 0xA9 /* Cosine value */ -#define HUESIN 0xAA /* Sine value */ - -#define SIGN 0xAB /* Sign bit for Hue and contrast */ -#define DSPAUTO 0xAC /* DSP auto function ON/OFF control */ - -/* - * register detail - */ - -/* COM2 */ -#define SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */ - /* Output drive capability */ -#define OCAP_1x 0x00 /* 1x */ -#define OCAP_2x 0x01 /* 2x */ -#define OCAP_3x 0x02 /* 3x */ -#define OCAP_4x 0x03 /* 4x */ - -/* COM3 */ -#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML) -#define IMG_MASK (VFLIP_IMG | HFLIP_IMG) - -#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */ -#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */ -#define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */ -#define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */ -#define SWAP_ML 0x08 /* Swap output MSB/LSB */ - /* Tri-state option for output clock */ -#define NOTRI_CLOCK 0x04 /* 0: Tri-state at this period */ - /* 1: No tri-state at this period */ - /* Tri-state option for output data */ -#define NOTRI_DATA 0x02 /* 0: Tri-state at this period */ - /* 1: No tri-state at this period */ -#define SCOLOR_TEST 0x01 /* Sensor color bar test pattern */ - -/* COM4 */ - /* PLL frequency control */ -#define PLL_BYPASS 0x00 /* 00: Bypass PLL */ -#define PLL_4x 0x40 /* 01: PLL 4x */ -#define PLL_6x 0x80 /* 10: PLL 6x */ -#define PLL_8x 0xc0 /* 11: PLL 8x */ - /* AEC evaluate window */ -#define AEC_FULL 0x00 /* 00: Full window */ -#define AEC_1p2 0x10 /* 01: 1/2 window */ -#define AEC_1p4 0x20 /* 10: 1/4 window */ -#define AEC_2p3 0x30 /* 11: Low 2/3 window */ - -/* COM5 */ -#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */ -#define AFR_SPPED 0x40 /* Auto frame rate control speed selection */ - /* Auto frame rate max rate control */ -#define AFR_NO_RATE 0x00 /* No reduction of frame rate */ -#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */ -#define AFR_1p4 0x20 /* Max reduction to 1/4 frame rate */ -#define AFR_1p8 0x30 /* Max reduction to 1/8 frame rate */ - /* Auto frame rate active point control */ -#define AF_2x 0x00 /* Add frame when AGC reaches 2x gain */ -#define AF_4x 0x04 /* Add frame when AGC reaches 4x gain */ -#define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */ -#define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */ - /* AEC max step control */ -#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */ - /* 1 : No limit to AEC increase step */ - -/* COM7 */ - /* SCCB Register Reset */ -#define SCCB_RESET 0x80 /* 0 : No change */ - /* 1 : Resets all registers to default */ - /* Resolution selection */ -#define SLCT_MASK 0x40 /* Mask of VGA or QVGA */ -#define SLCT_VGA 0x00 /* 0 : VGA */ -#define SLCT_QVGA 0x40 /* 1 : QVGA */ -#define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */ - /* RGB output format control */ -#define FMT_MASK 0x0c /* Mask of color format */ -#define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */ -#define FMT_RGB565 0x04 /* 01 : RGB 565 */ -#define FMT_RGB555 0x08 /* 10 : RGB 555 */ -#define FMT_RGB444 0x0c /* 11 : RGB 444 */ - /* Output format control */ -#define OFMT_MASK 0x03 /* Mask of output format */ -#define OFMT_YUV 0x00 /* 00 : YUV */ -#define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */ -#define OFMT_RGB 0x02 /* 10 : RGB */ -#define OFMT_BRAW 0x03 /* 11 : Bayer RAW */ - -/* COM8 */ -#define FAST_ALGO 0x80 /* Enable fast AGC/AEC algorithm */ - /* AEC Setp size limit */ -#define UNLMT_STEP 0x40 /* 0 : Step size is limited */ - /* 1 : Unlimited step size */ -#define BNDF_ON_OFF 0x20 /* Banding filter ON/OFF */ -#define AEC_BND 0x10 /* Enable AEC below banding value */ -#define AEC_ON_OFF 0x08 /* Fine AEC ON/OFF control */ -#define AGC_ON 0x04 /* AGC Enable */ -#define AWB_ON 0x02 /* AWB Enable */ -#define AEC_ON 0x01 /* AEC Enable */ - -/* COM9 */ -#define BASE_AECAGC 0x80 /* Histogram or average based AEC/AGC */ - /* Automatic gain ceiling - maximum AGC value */ -#define GAIN_2x 0x00 /* 000 : 2x */ -#define GAIN_4x 0x10 /* 001 : 4x */ -#define GAIN_8x 0x20 /* 010 : 8x */ -#define GAIN_16x 0x30 /* 011 : 16x */ -#define GAIN_32x 0x40 /* 100 : 32x */ -#define GAIN_64x 0x50 /* 101 : 64x */ -#define GAIN_128x 0x60 /* 110 : 128x */ -#define DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */ -#define DROP_HREF 0x02 /* Drop HREF output of corrupt frame */ - -/* COM11 */ -#define SGLF_ON_OFF 0x02 /* Single frame ON/OFF selection */ -#define SGLF_TRIG 0x01 /* Single frame transfer trigger */ - -/* EXHCH */ -#define VSIZE_LSB 0x04 /* Vertical data output size LSB */ - -/* DSP_CTRL1 */ -#define FIFO_ON 0x80 /* FIFO enable/disable selection */ -#define UV_ON_OFF 0x40 /* UV adjust function ON/OFF selection */ -#define YUV444_2_422 0x20 /* YUV444 to 422 UV channel option selection */ -#define CLR_MTRX_ON_OFF 0x10 /* Color matrix ON/OFF selection */ -#define INTPLT_ON_OFF 0x08 /* Interpolation ON/OFF selection */ -#define GMM_ON_OFF 0x04 /* Gamma function ON/OFF selection */ -#define AUTO_BLK_ON_OFF 0x02 /* Black defect auto correction ON/OFF */ -#define AUTO_WHT_ON_OFF 0x01 /* White define auto correction ON/OFF */ - -/* DSP_CTRL3 */ -#define UV_MASK 0x80 /* UV output sequence option */ -#define UV_ON 0x80 /* ON */ -#define UV_OFF 0x00 /* OFF */ -#define CBAR_MASK 0x20 /* DSP Color bar mask */ -#define CBAR_ON 0x20 /* ON */ -#define CBAR_OFF 0x00 /* OFF */ - -/* HSTART */ -#define HST_VGA 0x23 -#define HST_QVGA 0x3F - -/* HSIZE */ -#define HSZ_VGA 0xA0 -#define HSZ_QVGA 0x50 - -/* VSTART */ -#define VST_VGA 0x07 -#define VST_QVGA 0x03 - -/* VSIZE */ -#define VSZ_VGA 0xF0 -#define VSZ_QVGA 0x78 - -/* HOUTSIZE */ -#define HOSZ_VGA 0xA0 -#define HOSZ_QVGA 0x50 - -/* VOUTSIZE */ -#define VOSZ_VGA 0xF0 -#define VOSZ_QVGA 0x78 - -/* DSPAUTO (DSP Auto Function ON/OFF Control) */ -#define AWB_ACTRL 0x80 /* AWB auto threshold control */ -#define DENOISE_ACTRL 0x40 /* De-noise auto threshold control */ -#define EDGE_ACTRL 0x20 /* Edge enhancement auto strength control */ -#define UV_ACTRL 0x10 /* UV adjust auto slope control */ -#define SCAL0_ACTRL 0x08 /* Auto scaling factor control */ -#define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */ - -/* - * ID - */ -#define OV7720 0x7720 -#define OV7725 0x7721 -#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF)) - -/* - * struct - */ -struct regval_list { - unsigned char reg_num; - unsigned char value; -}; - -struct ov772x_color_format { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; - u8 dsp3; - u8 com3; - u8 com7; -}; - -struct ov772x_win_size { - char *name; - __u32 width; - __u32 height; - unsigned char com7_bit; - const struct regval_list *regs; -}; - -struct ov772x_priv { - struct v4l2_subdev subdev; - struct ov772x_camera_info *info; - const struct ov772x_color_format *cfmt; - const struct ov772x_win_size *win; - int model; - unsigned short flag_vflip:1; - unsigned short flag_hflip:1; - /* band_filter = COM8[5] ? 256 - BDBASE : 0 */ - unsigned short band_filter; -}; - -#define ENDMARKER { 0xff, 0xff } - -/* - * register setting for window size - */ -static const struct regval_list ov772x_qvga_regs[] = { - { HSTART, HST_QVGA }, - { HSIZE, HSZ_QVGA }, - { VSTART, VST_QVGA }, - { VSIZE, VSZ_QVGA }, - { HOUTSIZE, HOSZ_QVGA }, - { VOUTSIZE, VOSZ_QVGA }, - ENDMARKER, -}; - -static const struct regval_list ov772x_vga_regs[] = { - { HSTART, HST_VGA }, - { HSIZE, HSZ_VGA }, - { VSTART, VST_VGA }, - { VSIZE, VSZ_VGA }, - { HOUTSIZE, HOSZ_VGA }, - { VOUTSIZE, VOSZ_VGA }, - ENDMARKER, -}; - -/* - * supported color format list - */ -static const struct ov772x_color_format ov772x_cfmts[] = { - { - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .dsp3 = 0x0, - .com3 = SWAP_YUV, - .com7 = OFMT_YUV, - }, - { - .code = V4L2_MBUS_FMT_YVYU8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .dsp3 = UV_ON, - .com3 = SWAP_YUV, - .com7 = OFMT_YUV, - }, - { - .code = V4L2_MBUS_FMT_UYVY8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .dsp3 = 0x0, - .com3 = 0x0, - .com7 = OFMT_YUV, - }, - { - .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .dsp3 = 0x0, - .com3 = SWAP_RGB, - .com7 = FMT_RGB555 | OFMT_RGB, - }, - { - .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, - .colorspace = V4L2_COLORSPACE_SRGB, - .dsp3 = 0x0, - .com3 = 0x0, - .com7 = FMT_RGB555 | OFMT_RGB, - }, - { - .code = V4L2_MBUS_FMT_RGB565_2X8_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .dsp3 = 0x0, - .com3 = SWAP_RGB, - .com7 = FMT_RGB565 | OFMT_RGB, - }, - { - .code = V4L2_MBUS_FMT_RGB565_2X8_BE, - .colorspace = V4L2_COLORSPACE_SRGB, - .dsp3 = 0x0, - .com3 = 0x0, - .com7 = FMT_RGB565 | OFMT_RGB, - }, -}; - - -/* - * window size list - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 -#define MAX_WIDTH VGA_WIDTH -#define MAX_HEIGHT VGA_HEIGHT - -static const struct ov772x_win_size ov772x_win_vga = { - .name = "VGA", - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .com7_bit = SLCT_VGA, - .regs = ov772x_vga_regs, -}; - -static const struct ov772x_win_size ov772x_win_qvga = { - .name = "QVGA", - .width = QVGA_WIDTH, - .height = QVGA_HEIGHT, - .com7_bit = SLCT_QVGA, - .regs = ov772x_qvga_regs, -}; - -static const struct v4l2_queryctrl ov772x_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_BAND_STOP_FILTER, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Band-stop filter", - .minimum = 0, - .maximum = 256, - .step = 1, - .default_value = 0, - }, -}; - -/* - * general function - */ - -static struct ov772x_priv *to_ov772x(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct ov772x_priv, - subdev); -} - -static int ov772x_write_array(struct i2c_client *client, - const struct regval_list *vals) -{ - while (vals->reg_num != 0xff) { - int ret = i2c_smbus_write_byte_data(client, - vals->reg_num, - vals->value); - if (ret < 0) - return ret; - vals++; - } - return 0; -} - -static int ov772x_mask_set(struct i2c_client *client, - u8 command, - u8 mask, - u8 set) -{ - s32 val = i2c_smbus_read_byte_data(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return i2c_smbus_write_byte_data(client, command, val); -} - -static int ov772x_reset(struct i2c_client *client) -{ - int ret = i2c_smbus_write_byte_data(client, COM7, SCCB_RESET); - msleep(1); - return ret; -} - -/* - * soc_camera_ops function - */ - -static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); - - if (!enable) { - ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); - return 0; - } - - if (!priv->win || !priv->cfmt) { - dev_err(&client->dev, "norm or win select error\n"); - return -EPERM; - } - - ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0); - - dev_dbg(&client->dev, "format %d, win %s\n", - priv->cfmt->code, priv->win->name); - - return 0; -} - -static int ov772x_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct ov772x_priv *priv = i2c_get_clientdata(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH; - - if (priv->info->flags & OV772X_FLAG_8BIT) - flags |= SOCAM_DATAWIDTH_8; - else - flags |= SOCAM_DATAWIDTH_10; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - case V4L2_CID_BAND_STOP_FILTER: - ctrl->value = priv->band_filter; - break; - } - return 0; -} - -static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); - int ret = 0; - u8 val; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - val = ctrl->value ? VFLIP_IMG : 0x00; - priv->flag_vflip = ctrl->value; - if (priv->info->flags & OV772X_FLAG_VFLIP) - val ^= VFLIP_IMG; - ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val); - break; - case V4L2_CID_HFLIP: - val = ctrl->value ? HFLIP_IMG : 0x00; - priv->flag_hflip = ctrl->value; - if (priv->info->flags & OV772X_FLAG_HFLIP) - val ^= HFLIP_IMG; - ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val); - break; - case V4L2_CID_BAND_STOP_FILTER: - if ((unsigned)ctrl->value > 256) - ctrl->value = 256; - if (ctrl->value == priv->band_filter) - break; - if (!ctrl->value) { - /* Switch the filter off, it is on now */ - ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); - if (!ret) - ret = ov772x_mask_set(client, COM8, - BNDF_ON_OFF, 0); - } else { - /* Switch the filter on, set AEC low limit */ - val = 256 - ctrl->value; - ret = ov772x_mask_set(client, COM8, - BNDF_ON_OFF, BNDF_ON_OFF); - if (!ret) - ret = ov772x_mask_set(client, BDBASE, - 0xff, val); - } - if (!ret) - priv->band_filter = ctrl->value; - break; - } - - return ret; -} - -static int ov772x_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); - - id->ident = priv->model; - id->revision = 0; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov772x_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - reg->size = 1; - if (reg->reg > 0xff) - return -EINVAL; - - ret = i2c_smbus_read_byte_data(client, reg->reg); - if (ret < 0) - return ret; - - reg->val = (__u64)ret; - - return 0; -} - -static int ov772x_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff || - reg->val > 0xff) - return -EINVAL; - - return i2c_smbus_write_byte_data(client, reg->reg, reg->val); -} -#endif - -static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) -{ - __u32 diff; - const struct ov772x_win_size *win; - - /* default is QVGA */ - diff = abs(width - ov772x_win_qvga.width) + - abs(height - ov772x_win_qvga.height); - win = &ov772x_win_qvga; - - /* VGA */ - if (diff > - abs(width - ov772x_win_vga.width) + - abs(height - ov772x_win_vga.height)) - win = &ov772x_win_vga; - - return win; -} - -static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height, - enum v4l2_mbus_pixelcode code) -{ - struct ov772x_priv *priv = to_ov772x(client); - int ret = -EINVAL; - u8 val; - int i; - - /* - * select format - */ - priv->cfmt = NULL; - for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { - if (code == ov772x_cfmts[i].code) { - priv->cfmt = ov772x_cfmts + i; - break; - } - } - if (!priv->cfmt) - goto ov772x_set_fmt_error; - - /* - * select win - */ - priv->win = ov772x_select_win(*width, *height); - - /* - * reset hardware - */ - ov772x_reset(client); - - /* - * Edge Ctrl - */ - if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) { - - /* - * Manual Edge Control Mode - * - * Edge auto strength bit is set by default. - * Remove it when manual mode. - */ - - ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00); - if (ret < 0) - goto ov772x_set_fmt_error; - - ret = ov772x_mask_set(client, - EDGE_TRSHLD, EDGE_THRESHOLD_MASK, - priv->info->edgectrl.threshold); - if (ret < 0) - goto ov772x_set_fmt_error; - - ret = ov772x_mask_set(client, - EDGE_STRNGT, EDGE_STRENGTH_MASK, - priv->info->edgectrl.strength); - if (ret < 0) - goto ov772x_set_fmt_error; - - } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) { - /* - * Auto Edge Control Mode - * - * set upper and lower limit - */ - ret = ov772x_mask_set(client, - EDGE_UPPER, EDGE_UPPER_MASK, - priv->info->edgectrl.upper); - if (ret < 0) - goto ov772x_set_fmt_error; - - ret = ov772x_mask_set(client, - EDGE_LOWER, EDGE_LOWER_MASK, - priv->info->edgectrl.lower); - if (ret < 0) - goto ov772x_set_fmt_error; - } - - /* - * set size format - */ - ret = ov772x_write_array(client, priv->win->regs); - if (ret < 0) - goto ov772x_set_fmt_error; - - /* - * set DSP_CTRL3 - */ - val = priv->cfmt->dsp3; - if (val) { - ret = ov772x_mask_set(client, - DSP_CTRL3, UV_MASK, val); - if (ret < 0) - goto ov772x_set_fmt_error; - } - - /* - * set COM3 - */ - val = priv->cfmt->com3; - if (priv->info->flags & OV772X_FLAG_VFLIP) - val |= VFLIP_IMG; - if (priv->info->flags & OV772X_FLAG_HFLIP) - val |= HFLIP_IMG; - if (priv->flag_vflip) - val ^= VFLIP_IMG; - if (priv->flag_hflip) - val ^= HFLIP_IMG; - - ret = ov772x_mask_set(client, - COM3, SWAP_MASK | IMG_MASK, val); - if (ret < 0) - goto ov772x_set_fmt_error; - - /* - * set COM7 - */ - val = priv->win->com7_bit | priv->cfmt->com7; - ret = ov772x_mask_set(client, - COM7, SLCT_MASK | FMT_MASK | OFMT_MASK, - val); - if (ret < 0) - goto ov772x_set_fmt_error; - - /* - * set COM8 - */ - if (priv->band_filter) { - ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1); - if (!ret) - ret = ov772x_mask_set(client, BDBASE, - 0xff, 256 - priv->band_filter); - if (ret < 0) - goto ov772x_set_fmt_error; - } - - *width = priv->win->width; - *height = priv->win->height; - - return ret; - -ov772x_set_fmt_error: - - ov772x_reset(client); - priv->win = NULL; - priv->cfmt = NULL; - - return ret; -} - -static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - a->c.left = 0; - a->c.top = 0; - a->c.width = VGA_WIDTH; - a->c.height = VGA_HEIGHT; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = VGA_WIDTH; - a->bounds.height = VGA_HEIGHT; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int ov772x_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); - - if (!priv->win || !priv->cfmt) { - u32 width = VGA_WIDTH, height = VGA_HEIGHT; - int ret = ov772x_set_params(client, &width, &height, - V4L2_MBUS_FMT_YUYV8_2X8); - if (ret < 0) - return ret; - } - - mf->width = priv->win->width; - mf->height = priv->win->height; - mf->code = priv->cfmt->code; - mf->colorspace = priv->cfmt->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int ov772x_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); - int ret = ov772x_set_params(client, &mf->width, &mf->height, - mf->code); - - if (!ret) - mf->colorspace = priv->cfmt->colorspace; - - return ret; -} - -static int ov772x_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); - const struct ov772x_win_size *win; - int i; - - /* - * select suitable win - */ - win = ov772x_select_win(mf->width, mf->height); - - mf->width = win->width; - mf->height = win->height; - mf->field = V4L2_FIELD_NONE; - - for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) - if (mf->code == ov772x_cfmts[i].code) - break; - - if (i == ARRAY_SIZE(ov772x_cfmts)) { - /* Unsupported format requested. Propose either */ - if (priv->cfmt) { - /* the current one or */ - mf->colorspace = priv->cfmt->colorspace; - mf->code = priv->cfmt->code; - } else { - /* the default one */ - mf->colorspace = ov772x_cfmts[0].colorspace; - mf->code = ov772x_cfmts[0].code; - } - } else { - /* Also return the colorspace */ - mf->colorspace = ov772x_cfmts[i].colorspace; - } - - return 0; -} - -static int ov772x_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - struct ov772x_priv *priv = to_ov772x(client); - u8 pid, ver; - const char *devname; - - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; - - /* - * check and show product ID and manufacturer ID - */ - pid = i2c_smbus_read_byte_data(client, PID); - ver = i2c_smbus_read_byte_data(client, VER); - - switch (VERSION(pid, ver)) { - case OV7720: - devname = "ov7720"; - priv->model = V4L2_IDENT_OV7720; - break; - case OV7725: - devname = "ov7725"; - priv->model = V4L2_IDENT_OV7725; - break; - default: - dev_err(&client->dev, - "Product ID error %x:%x\n", pid, ver); - return -ENODEV; - } - - dev_info(&client->dev, - "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", - devname, - pid, - ver, - i2c_smbus_read_byte_data(client, MIDH), - i2c_smbus_read_byte_data(client, MIDL)); - - return 0; -} - -static struct soc_camera_ops ov772x_ops = { - .set_bus_param = ov772x_set_bus_param, - .query_bus_param = ov772x_query_bus_param, - .controls = ov772x_controls, - .num_controls = ARRAY_SIZE(ov772x_controls), -}; - -static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { - .g_ctrl = ov772x_g_ctrl, - .s_ctrl = ov772x_s_ctrl, - .g_chip_ident = ov772x_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov772x_g_register, - .s_register = ov772x_s_register, -#endif -}; - -static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index >= ARRAY_SIZE(ov772x_cfmts)) - return -EINVAL; - - *code = ov772x_cfmts[index].code; - return 0; -} - -static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { - .s_stream = ov772x_s_stream, - .g_mbus_fmt = ov772x_g_fmt, - .s_mbus_fmt = ov772x_s_fmt, - .try_mbus_fmt = ov772x_try_fmt, - .cropcap = ov772x_cropcap, - .g_crop = ov772x_g_crop, - .enum_mbus_fmt = ov772x_enum_fmt, -}; - -static struct v4l2_subdev_ops ov772x_subdev_ops = { - .core = &ov772x_subdev_core_ops, - .video = &ov772x_subdev_video_ops, -}; - -/* - * i2c_driver function - */ - -static int ov772x_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct ov772x_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "OV772X: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) - return -EINVAL; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&adapter->dev, - "I2C-Adapter doesn't support " - "I2C_FUNC_SMBUS_BYTE_DATA\n"); - return -EIO; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->info = icl->priv; - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); - - icd->ops = &ov772x_ops; - - ret = ov772x_video_probe(icd, client); - if (ret) { - icd->ops = NULL; - kfree(priv); - } - - return ret; -} - -static int ov772x_remove(struct i2c_client *client) -{ - struct ov772x_priv *priv = to_ov772x(client); - struct soc_camera_device *icd = client->dev.platform_data; - - icd->ops = NULL; - kfree(priv); - return 0; -} - -static const struct i2c_device_id ov772x_id[] = { - { "ov772x", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov772x_id); - -static struct i2c_driver ov772x_i2c_driver = { - .driver = { - .name = "ov772x", - }, - .probe = ov772x_probe, - .remove = ov772x_remove, - .id_table = ov772x_id, -}; - -/* - * module function - */ - -static int __init ov772x_module_init(void) -{ - return i2c_add_driver(&ov772x_i2c_driver); -} - -static void __exit ov772x_module_exit(void) -{ - i2c_del_driver(&ov772x_i2c_driver); -} - -module_init(ov772x_module_init); -module_exit(ov772x_module_exit); - -MODULE_DESCRIPTION("SoC Camera driver for ov772x"); -MODULE_AUTHOR("Kuninori Morimoto"); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9640.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9640.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9640.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9640.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,829 +0,0 @@ -/* - * OmniVision OV96xx Camera Driver - * - * Copyright (C) 2009 Marek Vasut - * - * Based on ov772x camera driver: - * - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto - * - * Based on ov7670 and soc_camera_platform driver, - * - * Copyright 2006-7 Jonathan Corbet - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ov9640.h" - -#define to_ov9640_sensor(sd) container_of(sd, struct ov9640_priv, subdev) - -/* default register setup */ -static const struct ov9640_reg ov9640_regs_dflt[] = { - { OV9640_COM5, OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP }, - { OV9640_COM6, OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS | - OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN }, - { OV9640_PSHFT, OV9640_PSHFT_VAL(0x01) }, - { OV9640_ACOM, OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD }, - { OV9640_TSLB, OV9640_TSLB_YUYV_UYVY }, - { OV9640_COM16, OV9640_COM16_RB_AVG }, - - /* Gamma curve P */ - { 0x6c, 0x40 }, { 0x6d, 0x30 }, { 0x6e, 0x4b }, { 0x6f, 0x60 }, - { 0x70, 0x70 }, { 0x71, 0x70 }, { 0x72, 0x70 }, { 0x73, 0x70 }, - { 0x74, 0x60 }, { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 }, - { 0x78, 0x3a }, { 0x79, 0x2e }, { 0x7a, 0x28 }, { 0x7b, 0x22 }, - - /* Gamma curve T */ - { 0x7c, 0x04 }, { 0x7d, 0x07 }, { 0x7e, 0x10 }, { 0x7f, 0x28 }, - { 0x80, 0x36 }, { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 }, - { 0x84, 0x6c }, { 0x85, 0x78 }, { 0x86, 0x8c }, { 0x87, 0x9e }, - { 0x88, 0xbb }, { 0x89, 0xd2 }, { 0x8a, 0xe6 }, -}; - -/* Configurations - * NOTE: for YUV, alter the following registers: - * COM12 |= OV9640_COM12_YUV_AVG - * - * for RGB, alter the following registers: - * COM7 |= OV9640_COM7_RGB - * COM13 |= OV9640_COM13_RGB_AVG - * COM15 |= proper RGB color encoding mode - */ -static const struct ov9640_reg ov9640_regs_qqcif[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) }, - { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP }, - { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, - { OV9640_COM7, OV9640_COM7_QCIF }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_qqvga[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) }, - { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP }, - { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, - { OV9640_COM7, OV9640_COM7_QVGA }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_qcif[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) }, - { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, - { OV9640_COM7, OV9640_COM7_QCIF }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_qvga[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) }, - { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, - { OV9640_COM7, OV9640_COM7_QVGA }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_cif[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) }, - { OV9640_COM3, OV9640_COM3_VP }, - { OV9640_COM7, OV9640_COM7_CIF }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_vga[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) }, - { OV9640_COM3, OV9640_COM3_VP }, - { OV9640_COM7, OV9640_COM7_VGA }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_sxga[] = { - { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) }, - { OV9640_COM3, OV9640_COM3_VP }, - { OV9640_COM7, 0 }, - { OV9640_COM12, OV9640_COM12_RSVD }, - { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, - { OV9640_COM15, OV9640_COM15_OR_10F0 }, -}; - -static const struct ov9640_reg ov9640_regs_yuv[] = { - { OV9640_MTX1, 0x58 }, - { OV9640_MTX2, 0x48 }, - { OV9640_MTX3, 0x10 }, - { OV9640_MTX4, 0x28 }, - { OV9640_MTX5, 0x48 }, - { OV9640_MTX6, 0x70 }, - { OV9640_MTX7, 0x40 }, - { OV9640_MTX8, 0x40 }, - { OV9640_MTX9, 0x40 }, - { OV9640_MTXS, 0x0f }, -}; - -static const struct ov9640_reg ov9640_regs_rgb[] = { - { OV9640_MTX1, 0x71 }, - { OV9640_MTX2, 0x3e }, - { OV9640_MTX3, 0x0c }, - { OV9640_MTX4, 0x33 }, - { OV9640_MTX5, 0x72 }, - { OV9640_MTX6, 0x00 }, - { OV9640_MTX7, 0x2b }, - { OV9640_MTX8, 0x66 }, - { OV9640_MTX9, 0xd2 }, - { OV9640_MTXS, 0x65 }, -}; - -static enum v4l2_mbus_pixelcode ov9640_codes[] = { - V4L2_MBUS_FMT_UYVY8_2X8, - V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, - V4L2_MBUS_FMT_RGB565_2X8_LE, -}; - -static const struct v4l2_queryctrl ov9640_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - -/* read a register */ -static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) -{ - int ret; - u8 data = reg; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - msg.flags = I2C_M_RD; - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - *val = data; - return 0; - -err: - dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg); - return ret; -} - -/* write a register */ -static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val) -{ - int ret; - u8 _val; - unsigned char data[2] = { reg, val }; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg); - return ret; - } - - /* we have to read the register back ... no idea why, maybe HW bug */ - ret = ov9640_reg_read(client, reg, &_val); - if (ret) - dev_err(&client->dev, - "Failed reading back register 0x%02x!\n", reg); - - return 0; -} - - -/* Read a register, alter its bits, write it back */ -static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset) -{ - u8 val; - int ret; - - ret = ov9640_reg_read(client, reg, &val); - if (ret) { - dev_err(&client->dev, - "[Read]-Modify-Write of register %02x failed!\n", reg); - return val; - } - - val |= set; - val &= ~unset; - - ret = ov9640_reg_write(client, reg, val); - if (ret) - dev_err(&client->dev, - "Read-Modify-[Write] of register %02x failed!\n", reg); - - return ret; -} - -/* Soft reset the camera. This has nothing to do with the RESET pin! */ -static int ov9640_reset(struct i2c_client *client) -{ - int ret; - - ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET); - if (ret) - dev_err(&client->dev, - "An error occured while entering soft reset!\n"); - - return ret; -} - -/* Start/Stop streaming from the device */ -static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) -{ - return 0; -} - -/* Alter bus settings on camera side */ -static int ov9640_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -/* Request bus settings on camera side */ -static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - /* - * REVISIT: the camera probably can do 10 bit transfers, but I don't - * have those pins connected on my hardware. - */ - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -/* Get status of additional camera capabilities */ -static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - } - return 0; -} - -/* Set status of additional camera capabilities */ -static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - priv->flag_vflip = ctrl->value; - if (ctrl->value) - ret = ov9640_reg_rmw(client, OV9640_MVFP, - OV9640_MVFP_V, 0); - else - ret = ov9640_reg_rmw(client, OV9640_MVFP, - 0, OV9640_MVFP_V); - break; - case V4L2_CID_HFLIP: - priv->flag_hflip = ctrl->value; - if (ctrl->value) - ret = ov9640_reg_rmw(client, OV9640_MVFP, - OV9640_MVFP_H, 0); - else - ret = ov9640_reg_rmw(client, OV9640_MVFP, - 0, OV9640_MVFP_H); - break; - } - - return ret; -} - -/* Get chip identification */ -static int ov9640_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - id->ident = priv->model; - id->revision = priv->revision; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov9640_get_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 val; - - if (reg->reg & ~0xff) - return -EINVAL; - - reg->size = 1; - - ret = ov9640_reg_read(client, reg->reg, &val); - if (ret) - return ret; - - reg->val = (__u64)val; - - return 0; -} - -static int ov9640_set_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg & ~0xff || reg->val & ~0xff) - return -EINVAL; - - return ov9640_reg_write(client, reg->reg, reg->val); -} -#endif - -/* select nearest higher resolution for capture */ -static void ov9640_res_roundup(u32 *width, u32 *height) -{ - int i; - enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA }; - int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; - int res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; - - for (i = 0; i < ARRAY_SIZE(res_x); i++) { - if (res_x[i] >= *width && res_y[i] >= *height) { - *width = res_x[i]; - *height = res_y[i]; - return; - } - } - - *width = res_x[SXGA]; - *height = res_y[SXGA]; -} - -/* Prepare necessary register changes depending on color encoding */ -static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code, - struct ov9640_reg_alt *alt) -{ - switch (code) { - default: - case V4L2_MBUS_FMT_UYVY8_2X8: - alt->com12 = OV9640_COM12_YUV_AVG; - alt->com13 = OV9640_COM13_Y_DELAY_EN | - OV9640_COM13_YUV_DLY(0x01); - break; - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: - alt->com7 = OV9640_COM7_RGB; - alt->com13 = OV9640_COM13_RGB_AVG; - alt->com15 = OV9640_COM15_RGB_555; - break; - case V4L2_MBUS_FMT_RGB565_2X8_LE: - alt->com7 = OV9640_COM7_RGB; - alt->com13 = OV9640_COM13_RGB_AVG; - alt->com15 = OV9640_COM15_RGB_565; - break; - }; -} - -/* Setup registers according to resolution and color encoding */ -static int ov9640_write_regs(struct i2c_client *client, u32 width, - enum v4l2_mbus_pixelcode code, struct ov9640_reg_alt *alts) -{ - const struct ov9640_reg *ov9640_regs, *matrix_regs; - int ov9640_regs_len, matrix_regs_len; - int i, ret; - u8 val; - - /* select register configuration for given resolution */ - switch (width) { - case W_QQCIF: - ov9640_regs = ov9640_regs_qqcif; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif); - break; - case W_QQVGA: - ov9640_regs = ov9640_regs_qqvga; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga); - break; - case W_QCIF: - ov9640_regs = ov9640_regs_qcif; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif); - break; - case W_QVGA: - ov9640_regs = ov9640_regs_qvga; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga); - break; - case W_CIF: - ov9640_regs = ov9640_regs_cif; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif); - break; - case W_VGA: - ov9640_regs = ov9640_regs_vga; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga); - break; - case W_SXGA: - ov9640_regs = ov9640_regs_sxga; - ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga); - break; - default: - dev_err(&client->dev, "Failed to select resolution!\n"); - return -EINVAL; - } - - /* select color matrix configuration for given color encoding */ - if (code == V4L2_MBUS_FMT_UYVY8_2X8) { - matrix_regs = ov9640_regs_yuv; - matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv); - } else { - matrix_regs = ov9640_regs_rgb; - matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb); - } - - /* write register settings into the module */ - for (i = 0; i < ov9640_regs_len; i++) { - val = ov9640_regs[i].val; - - switch (ov9640_regs[i].reg) { - case OV9640_COM7: - val |= alts->com7; - break; - case OV9640_COM12: - val |= alts->com12; - break; - case OV9640_COM13: - val |= alts->com13; - break; - case OV9640_COM15: - val |= alts->com15; - break; - } - - ret = ov9640_reg_write(client, ov9640_regs[i].reg, val); - if (ret) - return ret; - } - - /* write color matrix configuration into the module */ - for (i = 0; i < matrix_regs_len; i++) { - ret = ov9640_reg_write(client, matrix_regs[i].reg, - matrix_regs[i].val); - if (ret) - return ret; - } - - return 0; -} - -/* program default register values */ -static int ov9640_prog_dflt(struct i2c_client *client) -{ - int i, ret; - - for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) { - ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg, - ov9640_regs_dflt[i].val); - if (ret) - return ret; - } - - /* wait for the changes to actually happen, 140ms are not enough yet */ - mdelay(150); - - return 0; -} - -/* set the format we will capture in */ -static int ov9640_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov9640_reg_alt alts = {0}; - enum v4l2_colorspace cspace; - enum v4l2_mbus_pixelcode code = mf->code; - int ret; - - ov9640_res_roundup(&mf->width, &mf->height); - ov9640_alter_regs(mf->code, &alts); - - ov9640_reset(client); - - ret = ov9640_prog_dflt(client); - if (ret) - return ret; - - switch (code) { - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: - case V4L2_MBUS_FMT_RGB565_2X8_LE: - cspace = V4L2_COLORSPACE_SRGB; - break; - default: - code = V4L2_MBUS_FMT_UYVY8_2X8; - case V4L2_MBUS_FMT_UYVY8_2X8: - cspace = V4L2_COLORSPACE_JPEG; - } - - ret = ov9640_write_regs(client, mf->width, code, &alts); - if (!ret) { - mf->code = code; - mf->colorspace = cspace; - } - - return ret; -} - -static int ov9640_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - ov9640_res_roundup(&mf->width, &mf->height); - - mf->field = V4L2_FIELD_NONE; - - switch (mf->code) { - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: - case V4L2_MBUS_FMT_RGB565_2X8_LE: - mf->colorspace = V4L2_COLORSPACE_SRGB; - break; - default: - mf->code = V4L2_MBUS_FMT_UYVY8_2X8; - case V4L2_MBUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; - } - - return 0; -} - -static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index >= ARRAY_SIZE(ov9640_codes)) - return -EINVAL; - - *code = ov9640_codes[index]; - return 0; -} - -static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - a->c.left = 0; - a->c.top = 0; - a->c.width = W_SXGA; - a->c.height = H_SXGA; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = W_SXGA; - a->bounds.height = H_SXGA; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - - - -static int ov9640_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9640_priv *priv = to_ov9640_sensor(sd); - u8 pid, ver, midh, midl; - const char *devname; - int ret = 0; - - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) { - dev_err(&client->dev, "Parent missing or invalid!\n"); - ret = -ENODEV; - goto err; - } - - /* - * check and show product ID and manufacturer ID - */ - - ret = ov9640_reg_read(client, OV9640_PID, &pid); - if (ret) - goto err; - - ret = ov9640_reg_read(client, OV9640_VER, &ver); - if (ret) - goto err; - - ret = ov9640_reg_read(client, OV9640_MIDH, &midh); - if (ret) - goto err; - - ret = ov9640_reg_read(client, OV9640_MIDL, &midl); - if (ret) - goto err; - - switch (VERSION(pid, ver)) { - case OV9640_V2: - devname = "ov9640"; - priv->model = V4L2_IDENT_OV9640; - priv->revision = 2; - case OV9640_V3: - devname = "ov9640"; - priv->model = V4L2_IDENT_OV9640; - priv->revision = 3; - break; - default: - dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); - ret = -ENODEV; - goto err; - } - - dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", - devname, pid, ver, midh, midl); - -err: - return ret; -} - -static struct soc_camera_ops ov9640_ops = { - .set_bus_param = ov9640_set_bus_param, - .query_bus_param = ov9640_query_bus_param, - .controls = ov9640_controls, - .num_controls = ARRAY_SIZE(ov9640_controls), -}; - -static struct v4l2_subdev_core_ops ov9640_core_ops = { - .g_ctrl = ov9640_g_ctrl, - .s_ctrl = ov9640_s_ctrl, - .g_chip_ident = ov9640_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov9640_get_register, - .s_register = ov9640_set_register, -#endif - -}; - -static struct v4l2_subdev_video_ops ov9640_video_ops = { - .s_stream = ov9640_s_stream, - .s_mbus_fmt = ov9640_s_fmt, - .try_mbus_fmt = ov9640_try_fmt, - .enum_mbus_fmt = ov9640_enum_fmt, - .cropcap = ov9640_cropcap, - .g_crop = ov9640_g_crop, - -}; - -static struct v4l2_subdev_ops ov9640_subdev_ops = { - .core = &ov9640_core_ops, - .video = &ov9640_video_ops, -}; - -/* - * i2c_driver function - */ -static int ov9640_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct ov9640_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "Missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "Missing platform_data for driver\n"); - return -EINVAL; - } - - priv = kzalloc(sizeof(struct ov9640_priv), GFP_KERNEL); - if (!priv) { - dev_err(&client->dev, - "Failed to allocate memory for private data!\n"); - return -ENOMEM; - } - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); - - icd->ops = &ov9640_ops; - - ret = ov9640_video_probe(icd, client); - - if (ret) { - icd->ops = NULL; - kfree(priv); - } - - return ret; -} - -static int ov9640_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - kfree(priv); - return 0; -} - -static const struct i2c_device_id ov9640_id[] = { - { "ov9640", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov9640_id); - -static struct i2c_driver ov9640_i2c_driver = { - .driver = { - .name = "ov9640", - }, - .probe = ov9640_probe, - .remove = ov9640_remove, - .id_table = ov9640_id, -}; - -static int __init ov9640_module_init(void) -{ - return i2c_add_driver(&ov9640_i2c_driver); -} - -static void __exit ov9640_module_exit(void) -{ - i2c_del_driver(&ov9640_i2c_driver); -} - -module_init(ov9640_module_init); -module_exit(ov9640_module_exit); - -MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx"); -MODULE_AUTHOR("Marek Vasut "); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9640.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9640.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9640.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9640.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,209 +0,0 @@ -/* - * OmniVision OV96xx Camera Header File - * - * Copyright (C) 2009 Marek Vasut - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __DRIVERS_MEDIA_VIDEO_OV9640_H__ -#define __DRIVERS_MEDIA_VIDEO_OV9640_H__ - -/* Register definitions */ -#define OV9640_GAIN 0x00 -#define OV9640_BLUE 0x01 -#define OV9640_RED 0x02 -#define OV9640_VFER 0x03 -#define OV9640_COM1 0x04 -#define OV9640_BAVE 0x05 -#define OV9640_GEAVE 0x06 -#define OV9640_RSID 0x07 -#define OV9640_RAVE 0x08 -#define OV9640_COM2 0x09 -#define OV9640_PID 0x0a -#define OV9640_VER 0x0b -#define OV9640_COM3 0x0c -#define OV9640_COM4 0x0d -#define OV9640_COM5 0x0e -#define OV9640_COM6 0x0f -#define OV9640_AECH 0x10 -#define OV9640_CLKRC 0x11 -#define OV9640_COM7 0x12 -#define OV9640_COM8 0x13 -#define OV9640_COM9 0x14 -#define OV9640_COM10 0x15 -/* 0x16 - RESERVED */ -#define OV9640_HSTART 0x17 -#define OV9640_HSTOP 0x18 -#define OV9640_VSTART 0x19 -#define OV9640_VSTOP 0x1a -#define OV9640_PSHFT 0x1b -#define OV9640_MIDH 0x1c -#define OV9640_MIDL 0x1d -#define OV9640_MVFP 0x1e -#define OV9640_LAEC 0x1f -#define OV9640_BOS 0x20 -#define OV9640_GBOS 0x21 -#define OV9640_GROS 0x22 -#define OV9640_ROS 0x23 -#define OV9640_AEW 0x24 -#define OV9640_AEB 0x25 -#define OV9640_VPT 0x26 -#define OV9640_BBIAS 0x27 -#define OV9640_GBBIAS 0x28 -/* 0x29 - RESERVED */ -#define OV9640_EXHCH 0x2a -#define OV9640_EXHCL 0x2b -#define OV9640_RBIAS 0x2c -#define OV9640_ADVFL 0x2d -#define OV9640_ADVFH 0x2e -#define OV9640_YAVE 0x2f -#define OV9640_HSYST 0x30 -#define OV9640_HSYEN 0x31 -#define OV9640_HREF 0x32 -#define OV9640_CHLF 0x33 -#define OV9640_ARBLM 0x34 -/* 0x35..0x36 - RESERVED */ -#define OV9640_ADC 0x37 -#define OV9640_ACOM 0x38 -#define OV9640_OFON 0x39 -#define OV9640_TSLB 0x3a -#define OV9640_COM11 0x3b -#define OV9640_COM12 0x3c -#define OV9640_COM13 0x3d -#define OV9640_COM14 0x3e -#define OV9640_EDGE 0x3f -#define OV9640_COM15 0x40 -#define OV9640_COM16 0x41 -#define OV9640_COM17 0x42 -/* 0x43..0x4e - RESERVED */ -#define OV9640_MTX1 0x4f -#define OV9640_MTX2 0x50 -#define OV9640_MTX3 0x51 -#define OV9640_MTX4 0x52 -#define OV9640_MTX5 0x53 -#define OV9640_MTX6 0x54 -#define OV9640_MTX7 0x55 -#define OV9640_MTX8 0x56 -#define OV9640_MTX9 0x57 -#define OV9640_MTXS 0x58 -/* 0x59..0x61 - RESERVED */ -#define OV9640_LCC1 0x62 -#define OV9640_LCC2 0x63 -#define OV9640_LCC3 0x64 -#define OV9640_LCC4 0x65 -#define OV9640_LCC5 0x66 -#define OV9640_MANU 0x67 -#define OV9640_MANV 0x68 -#define OV9640_HV 0x69 -#define OV9640_MBD 0x6a -#define OV9640_DBLV 0x6b -#define OV9640_GSP 0x6c /* ... till 0x7b */ -#define OV9640_GST 0x7c /* ... till 0x8a */ - -#define OV9640_CLKRC_DPLL_EN 0x80 -#define OV9640_CLKRC_DIRECT 0x40 -#define OV9640_CLKRC_DIV(x) ((x) & 0x3f) - -#define OV9640_PSHFT_VAL(x) ((x) & 0xff) - -#define OV9640_ACOM_2X_ANALOG 0x80 -#define OV9640_ACOM_RSVD 0x12 - -#define OV9640_MVFP_V 0x10 -#define OV9640_MVFP_H 0x20 - -#define OV9640_COM1_HREF_NOSKIP 0x00 -#define OV9640_COM1_HREF_2SKIP 0x04 -#define OV9640_COM1_HREF_3SKIP 0x08 -#define OV9640_COM1_QQFMT 0x20 - -#define OV9640_COM2_SSM 0x10 - -#define OV9640_COM3_VP 0x04 - -#define OV9640_COM4_QQ_VP 0x80 -#define OV9640_COM4_RSVD 0x40 - -#define OV9640_COM5_SYSCLK 0x80 -#define OV9640_COM5_LONGEXP 0x01 - -#define OV9640_COM6_OPT_BLC 0x40 -#define OV9640_COM6_ADBLC_BIAS 0x08 -#define OV9640_COM6_FMT_RST 0x82 -#define OV9640_COM6_ADBLC_OPTEN 0x01 - -#define OV9640_COM7_RAW_RGB 0x01 -#define OV9640_COM7_RGB 0x04 -#define OV9640_COM7_QCIF 0x08 -#define OV9640_COM7_QVGA 0x10 -#define OV9640_COM7_CIF 0x20 -#define OV9640_COM7_VGA 0x40 -#define OV9640_COM7_SCCB_RESET 0x80 - -#define OV9640_TSLB_YVYU_YUYV 0x04 -#define OV9640_TSLB_YUYV_UYVY 0x08 - -#define OV9640_COM12_YUV_AVG 0x04 -#define OV9640_COM12_RSVD 0x40 - -#define OV9640_COM13_GAMMA_NONE 0x00 -#define OV9640_COM13_GAMMA_Y 0x40 -#define OV9640_COM13_GAMMA_RAW 0x80 -#define OV9640_COM13_RGB_AVG 0x20 -#define OV9640_COM13_MATRIX_EN 0x10 -#define OV9640_COM13_Y_DELAY_EN 0x08 -#define OV9640_COM13_YUV_DLY(x) ((x) & 0x07) - -#define OV9640_COM15_OR_00FF 0x00 -#define OV9640_COM15_OR_01FE 0x40 -#define OV9640_COM15_OR_10F0 0xc0 -#define OV9640_COM15_RGB_NORM 0x00 -#define OV9640_COM15_RGB_565 0x10 -#define OV9640_COM15_RGB_555 0x30 - -#define OV9640_COM16_RB_AVG 0x01 - -/* IDs */ -#define OV9640_V2 0x9648 -#define OV9640_V3 0x9649 -#define VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xFF)) - -/* supported resolutions */ -enum { - W_QQCIF = 88, - W_QQVGA = 160, - W_QCIF = 176, - W_QVGA = 320, - W_CIF = 352, - W_VGA = 640, - W_SXGA = 1280 -}; -#define H_SXGA 960 - -/* Misc. structures */ -struct ov9640_reg_alt { - u8 com7; - u8 com12; - u8 com13; - u8 com15; -}; - -struct ov9640_reg { - u8 reg; - u8 val; -}; - -struct ov9640_priv { - struct v4l2_subdev subdev; - - int model; - int revision; - - bool flag_vflip; - bool flag_hflip; -}; - -#endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9740.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9740.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9740.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ov9740.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1009 +0,0 @@ -/* - * OmniVision OV9740 Camera Driver - * - * Copyright (C) 2011 NVIDIA Corporation - * - * Based on ov9640 camera driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) - -/* General Status Registers */ -#define OV9740_MODEL_ID_HI 0x0000 -#define OV9740_MODEL_ID_LO 0x0001 -#define OV9740_REVISION_NUMBER 0x0002 -#define OV9740_MANUFACTURER_ID 0x0003 -#define OV9740_SMIA_VERSION 0x0004 - -/* General Setup Registers */ -#define OV9740_MODE_SELECT 0x0100 -#define OV9740_IMAGE_ORT 0x0101 -#define OV9740_SOFTWARE_RESET 0x0103 -#define OV9740_GRP_PARAM_HOLD 0x0104 -#define OV9740_MSK_CORRUP_FM 0x0105 - -/* Timing Setting */ -#define OV9740_FRM_LENGTH_LN_HI 0x0340 /* VTS */ -#define OV9740_FRM_LENGTH_LN_LO 0x0341 /* VTS */ -#define OV9740_LN_LENGTH_PCK_HI 0x0342 /* HTS */ -#define OV9740_LN_LENGTH_PCK_LO 0x0343 /* HTS */ -#define OV9740_X_ADDR_START_HI 0x0344 -#define OV9740_X_ADDR_START_LO 0x0345 -#define OV9740_Y_ADDR_START_HI 0x0346 -#define OV9740_Y_ADDR_START_LO 0x0347 -#define OV9740_X_ADDR_END_HI 0x0348 -#define OV9740_X_ADDR_END_LO 0x0349 -#define OV9740_Y_ADDR_END_HI 0x034A -#define OV9740_Y_ADDR_END_LO 0x034B -#define OV9740_X_OUTPUT_SIZE_HI 0x034C -#define OV9740_X_OUTPUT_SIZE_LO 0x034D -#define OV9740_Y_OUTPUT_SIZE_HI 0x034E -#define OV9740_Y_OUTPUT_SIZE_LO 0x034F - -/* IO Control Registers */ -#define OV9740_IO_CREL00 0x3002 -#define OV9740_IO_CREL01 0x3004 -#define OV9740_IO_CREL02 0x3005 -#define OV9740_IO_OUTPUT_SEL01 0x3026 -#define OV9740_IO_OUTPUT_SEL02 0x3027 - -/* AWB Registers */ -#define OV9740_AWB_MANUAL_CTRL 0x3406 - -/* Analog Control Registers */ -#define OV9740_ANALOG_CTRL01 0x3601 -#define OV9740_ANALOG_CTRL02 0x3602 -#define OV9740_ANALOG_CTRL03 0x3603 -#define OV9740_ANALOG_CTRL04 0x3604 -#define OV9740_ANALOG_CTRL10 0x3610 -#define OV9740_ANALOG_CTRL12 0x3612 -#define OV9740_ANALOG_CTRL20 0x3620 -#define OV9740_ANALOG_CTRL21 0x3621 -#define OV9740_ANALOG_CTRL22 0x3622 -#define OV9740_ANALOG_CTRL30 0x3630 -#define OV9740_ANALOG_CTRL31 0x3631 -#define OV9740_ANALOG_CTRL32 0x3632 -#define OV9740_ANALOG_CTRL33 0x3633 - -/* Sensor Control */ -#define OV9740_SENSOR_CTRL03 0x3703 -#define OV9740_SENSOR_CTRL04 0x3704 -#define OV9740_SENSOR_CTRL05 0x3705 -#define OV9740_SENSOR_CTRL07 0x3707 - -/* Timing Control */ -#define OV9740_TIMING_CTRL17 0x3817 -#define OV9740_TIMING_CTRL19 0x3819 -#define OV9740_TIMING_CTRL33 0x3833 -#define OV9740_TIMING_CTRL35 0x3835 - -/* Banding Filter */ -#define OV9740_AEC_MAXEXPO_60_H 0x3A02 -#define OV9740_AEC_MAXEXPO_60_L 0x3A03 -#define OV9740_AEC_B50_STEP_HI 0x3A08 -#define OV9740_AEC_B50_STEP_LO 0x3A09 -#define OV9740_AEC_B60_STEP_HI 0x3A0A -#define OV9740_AEC_B60_STEP_LO 0x3A0B -#define OV9740_AEC_CTRL0D 0x3A0D -#define OV9740_AEC_CTRL0E 0x3A0E -#define OV9740_AEC_MAXEXPO_50_H 0x3A14 -#define OV9740_AEC_MAXEXPO_50_L 0x3A15 - -/* AEC/AGC Control */ -#define OV9740_AEC_ENABLE 0x3503 -#define OV9740_GAIN_CEILING_01 0x3A18 -#define OV9740_GAIN_CEILING_02 0x3A19 -#define OV9740_AEC_HI_THRESHOLD 0x3A11 -#define OV9740_AEC_3A1A 0x3A1A -#define OV9740_AEC_CTRL1B_WPT2 0x3A1B -#define OV9740_AEC_CTRL0F_WPT 0x3A0F -#define OV9740_AEC_CTRL10_BPT 0x3A10 -#define OV9740_AEC_CTRL1E_BPT2 0x3A1E -#define OV9740_AEC_LO_THRESHOLD 0x3A1F - -/* BLC Control */ -#define OV9740_BLC_AUTO_ENABLE 0x4002 -#define OV9740_BLC_MODE 0x4005 - -/* VFIFO */ -#define OV9740_VFIFO_READ_START_HI 0x4608 -#define OV9740_VFIFO_READ_START_LO 0x4609 - -/* DVP Control */ -#define OV9740_DVP_VSYNC_CTRL02 0x4702 -#define OV9740_DVP_VSYNC_MODE 0x4704 -#define OV9740_DVP_VSYNC_CTRL06 0x4706 - -/* PLL Setting */ -#define OV9740_PLL_MODE_CTRL01 0x3104 -#define OV9740_PRE_PLL_CLK_DIV 0x0305 -#define OV9740_PLL_MULTIPLIER 0x0307 -#define OV9740_VT_SYS_CLK_DIV 0x0303 -#define OV9740_VT_PIX_CLK_DIV 0x0301 -#define OV9740_PLL_CTRL3010 0x3010 -#define OV9740_VFIFO_CTRL00 0x460E - -/* ISP Control */ -#define OV9740_ISP_CTRL00 0x5000 -#define OV9740_ISP_CTRL01 0x5001 -#define OV9740_ISP_CTRL03 0x5003 -#define OV9740_ISP_CTRL05 0x5005 -#define OV9740_ISP_CTRL12 0x5012 -#define OV9740_ISP_CTRL19 0x5019 -#define OV9740_ISP_CTRL1A 0x501A -#define OV9740_ISP_CTRL1E 0x501E -#define OV9740_ISP_CTRL1F 0x501F -#define OV9740_ISP_CTRL20 0x5020 -#define OV9740_ISP_CTRL21 0x5021 - -/* AWB */ -#define OV9740_AWB_CTRL00 0x5180 -#define OV9740_AWB_CTRL01 0x5181 -#define OV9740_AWB_CTRL02 0x5182 -#define OV9740_AWB_CTRL03 0x5183 -#define OV9740_AWB_ADV_CTRL01 0x5184 -#define OV9740_AWB_ADV_CTRL02 0x5185 -#define OV9740_AWB_ADV_CTRL03 0x5186 -#define OV9740_AWB_ADV_CTRL04 0x5187 -#define OV9740_AWB_ADV_CTRL05 0x5188 -#define OV9740_AWB_ADV_CTRL06 0x5189 -#define OV9740_AWB_ADV_CTRL07 0x518A -#define OV9740_AWB_ADV_CTRL08 0x518B -#define OV9740_AWB_ADV_CTRL09 0x518C -#define OV9740_AWB_ADV_CTRL10 0x518D -#define OV9740_AWB_ADV_CTRL11 0x518E -#define OV9740_AWB_CTRL0F 0x518F -#define OV9740_AWB_CTRL10 0x5190 -#define OV9740_AWB_CTRL11 0x5191 -#define OV9740_AWB_CTRL12 0x5192 -#define OV9740_AWB_CTRL13 0x5193 -#define OV9740_AWB_CTRL14 0x5194 - -/* MIPI Control */ -#define OV9740_MIPI_CTRL00 0x4800 -#define OV9740_MIPI_3837 0x3837 -#define OV9740_MIPI_CTRL01 0x4801 -#define OV9740_MIPI_CTRL03 0x4803 -#define OV9740_MIPI_CTRL05 0x4805 -#define OV9740_VFIFO_RD_CTRL 0x4601 -#define OV9740_MIPI_CTRL_3012 0x3012 -#define OV9740_SC_CMMM_MIPI_CTR 0x3014 - -/* supported resolutions */ -enum { - OV9740_VGA, - OV9740_720P, -}; - -struct ov9740_resolution { - unsigned int width; - unsigned int height; -}; - -static struct ov9740_resolution ov9740_resolutions[] = { - [OV9740_VGA] = { - .width = 640, - .height = 480, - }, - [OV9740_720P] = { - .width = 1280, - .height = 720, - }, -}; - -/* Misc. structures */ -struct ov9740_reg { - u16 reg; - u8 val; -}; - -struct ov9740_priv { - struct v4l2_subdev subdev; - - int ident; - u16 model; - u8 revision; - u8 manid; - u8 smiaver; - - bool flag_vflip; - bool flag_hflip; -}; - -static const struct ov9740_reg ov9740_defaults[] = { - /* Banding Filter */ - { OV9740_AEC_B50_STEP_HI, 0x00 }, - { OV9740_AEC_B50_STEP_LO, 0xe8 }, - { OV9740_AEC_CTRL0E, 0x03 }, - { OV9740_AEC_MAXEXPO_50_H, 0x15 }, - { OV9740_AEC_MAXEXPO_50_L, 0xc6 }, - { OV9740_AEC_B60_STEP_HI, 0x00 }, - { OV9740_AEC_B60_STEP_LO, 0xc0 }, - { OV9740_AEC_CTRL0D, 0x04 }, - { OV9740_AEC_MAXEXPO_60_H, 0x18 }, - { OV9740_AEC_MAXEXPO_60_L, 0x20 }, - - /* LC */ - { 0x5842, 0x02 }, { 0x5843, 0x5e }, { 0x5844, 0x04 }, { 0x5845, 0x32 }, - { 0x5846, 0x03 }, { 0x5847, 0x29 }, { 0x5848, 0x02 }, { 0x5849, 0xcc }, - - /* Un-documented OV9740 registers */ - { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 }, - { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c }, - { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580A, 0x0e }, { 0x580B, 0x16 }, - { 0x580C, 0x06 }, { 0x580D, 0x02 }, { 0x580E, 0x00 }, { 0x580F, 0x00 }, - { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 }, - { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 }, - { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581A, 0x07 }, { 0x581B, 0x08 }, - { 0x581C, 0x0b }, { 0x581D, 0x14 }, { 0x581E, 0x28 }, { 0x581F, 0x23 }, - { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a }, - { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f }, - { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582A, 0x8f }, { 0x582B, 0x9e }, - { 0x582C, 0x8f }, { 0x582D, 0x9f }, { 0x582E, 0x4f }, { 0x582F, 0x87 }, - { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f }, - { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf }, - { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583A, 0x9f }, { 0x583B, 0x7f }, - { 0x583C, 0x5f }, - - /* Y Gamma */ - { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e }, - { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 }, - { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548A, 0xa4 }, { 0x548B, 0xb1 }, - { 0x548C, 0xc6 }, { 0x548D, 0xd8 }, { 0x548E, 0xe9 }, - - /* UV Gamma */ - { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 }, - { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 }, - { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549A, 0x02 }, { 0x549B, 0xeb }, - { 0x549C, 0x02 }, { 0x549D, 0xa0 }, { 0x549E, 0x02 }, { 0x549F, 0x67 }, - { 0x54A0, 0x02 }, { 0x54A1, 0x3b }, { 0x54A2, 0x02 }, { 0x54A3, 0x18 }, - { 0x54A4, 0x01 }, { 0x54A5, 0xe7 }, { 0x54A6, 0x01 }, { 0x54A7, 0xc3 }, - { 0x54A8, 0x01 }, { 0x54A9, 0x94 }, { 0x54AA, 0x01 }, { 0x54AB, 0x72 }, - { 0x54AC, 0x01 }, { 0x54AD, 0x57 }, - - /* AWB */ - { OV9740_AWB_CTRL00, 0xf0 }, - { OV9740_AWB_CTRL01, 0x00 }, - { OV9740_AWB_CTRL02, 0x41 }, - { OV9740_AWB_CTRL03, 0x42 }, - { OV9740_AWB_ADV_CTRL01, 0x8a }, - { OV9740_AWB_ADV_CTRL02, 0x61 }, - { OV9740_AWB_ADV_CTRL03, 0xce }, - { OV9740_AWB_ADV_CTRL04, 0xa8 }, - { OV9740_AWB_ADV_CTRL05, 0x17 }, - { OV9740_AWB_ADV_CTRL06, 0x1f }, - { OV9740_AWB_ADV_CTRL07, 0x27 }, - { OV9740_AWB_ADV_CTRL08, 0x41 }, - { OV9740_AWB_ADV_CTRL09, 0x34 }, - { OV9740_AWB_ADV_CTRL10, 0xf0 }, - { OV9740_AWB_ADV_CTRL11, 0x10 }, - { OV9740_AWB_CTRL0F, 0xff }, - { OV9740_AWB_CTRL10, 0x00 }, - { OV9740_AWB_CTRL11, 0xff }, - { OV9740_AWB_CTRL12, 0x00 }, - { OV9740_AWB_CTRL13, 0xff }, - { OV9740_AWB_CTRL14, 0x00 }, - - /* CIP */ - { 0x530D, 0x12 }, - - /* CMX */ - { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 }, - { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 }, - { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538A, 0x00 }, { 0x538B, 0x20 }, - { 0x538C, 0x00 }, { 0x538D, 0x00 }, { 0x538E, 0x00 }, { 0x538F, 0x16 }, - { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 }, - { 0x5394, 0x18 }, - - /* 50/60 Detection */ - { 0x3C0A, 0x9c }, { 0x3C0B, 0x3f }, - - /* Output Select */ - { OV9740_IO_OUTPUT_SEL01, 0x00 }, - { OV9740_IO_OUTPUT_SEL02, 0x00 }, - { OV9740_IO_CREL00, 0x00 }, - { OV9740_IO_CREL01, 0x00 }, - { OV9740_IO_CREL02, 0x00 }, - - /* AWB Control */ - { OV9740_AWB_MANUAL_CTRL, 0x00 }, - - /* Analog Control */ - { OV9740_ANALOG_CTRL03, 0xaa }, - { OV9740_ANALOG_CTRL32, 0x2f }, - { OV9740_ANALOG_CTRL20, 0x66 }, - { OV9740_ANALOG_CTRL21, 0xc0 }, - { OV9740_ANALOG_CTRL31, 0x52 }, - { OV9740_ANALOG_CTRL33, 0x50 }, - { OV9740_ANALOG_CTRL30, 0xca }, - { OV9740_ANALOG_CTRL04, 0x0c }, - { OV9740_ANALOG_CTRL01, 0x40 }, - { OV9740_ANALOG_CTRL02, 0x16 }, - { OV9740_ANALOG_CTRL10, 0xa1 }, - { OV9740_ANALOG_CTRL12, 0x24 }, - { OV9740_ANALOG_CTRL22, 0x9f }, - - /* Sensor Control */ - { OV9740_SENSOR_CTRL03, 0x42 }, - { OV9740_SENSOR_CTRL04, 0x10 }, - { OV9740_SENSOR_CTRL05, 0x45 }, - { OV9740_SENSOR_CTRL07, 0x14 }, - - /* Timing Control */ - { OV9740_TIMING_CTRL33, 0x04 }, - { OV9740_TIMING_CTRL35, 0x02 }, - { OV9740_TIMING_CTRL19, 0x6e }, - { OV9740_TIMING_CTRL17, 0x94 }, - - /* AEC/AGC Control */ - { OV9740_AEC_ENABLE, 0x10 }, - { OV9740_GAIN_CEILING_01, 0x00 }, - { OV9740_GAIN_CEILING_02, 0x7f }, - { OV9740_AEC_HI_THRESHOLD, 0xa0 }, - { OV9740_AEC_3A1A, 0x05 }, - { OV9740_AEC_CTRL1B_WPT2, 0x50 }, - { OV9740_AEC_CTRL0F_WPT, 0x50 }, - { OV9740_AEC_CTRL10_BPT, 0x4c }, - { OV9740_AEC_CTRL1E_BPT2, 0x4c }, - { OV9740_AEC_LO_THRESHOLD, 0x26 }, - - /* BLC Control */ - { OV9740_BLC_AUTO_ENABLE, 0x45 }, - { OV9740_BLC_MODE, 0x18 }, - - /* DVP Control */ - { OV9740_DVP_VSYNC_CTRL02, 0x04 }, - { OV9740_DVP_VSYNC_MODE, 0x00 }, - { OV9740_DVP_VSYNC_CTRL06, 0x08 }, - - /* PLL Setting */ - { OV9740_PLL_MODE_CTRL01, 0x20 }, - { OV9740_PRE_PLL_CLK_DIV, 0x03 }, - { OV9740_PLL_MULTIPLIER, 0x4c }, - { OV9740_VT_SYS_CLK_DIV, 0x01 }, - { OV9740_VT_PIX_CLK_DIV, 0x08 }, - { OV9740_PLL_CTRL3010, 0x01 }, - { OV9740_VFIFO_CTRL00, 0x82 }, - - /* Timing Setting */ - /* VTS */ - { OV9740_FRM_LENGTH_LN_HI, 0x03 }, - { OV9740_FRM_LENGTH_LN_LO, 0x07 }, - /* HTS */ - { OV9740_LN_LENGTH_PCK_HI, 0x06 }, - { OV9740_LN_LENGTH_PCK_LO, 0x62 }, - - /* MIPI Control */ - { OV9740_MIPI_CTRL00, 0x44 }, - { OV9740_MIPI_3837, 0x01 }, - { OV9740_MIPI_CTRL01, 0x0f }, - { OV9740_MIPI_CTRL03, 0x05 }, - { OV9740_MIPI_CTRL05, 0x10 }, - { OV9740_VFIFO_RD_CTRL, 0x16 }, - { OV9740_MIPI_CTRL_3012, 0x70 }, - { OV9740_SC_CMMM_MIPI_CTR, 0x01 }, -}; - -static const struct ov9740_reg ov9740_regs_vga[] = { - { OV9740_X_ADDR_START_HI, 0x00 }, - { OV9740_X_ADDR_START_LO, 0xa0 }, - { OV9740_Y_ADDR_START_HI, 0x00 }, - { OV9740_Y_ADDR_START_LO, 0x00 }, - { OV9740_X_ADDR_END_HI, 0x04 }, - { OV9740_X_ADDR_END_LO, 0x63 }, - { OV9740_Y_ADDR_END_HI, 0x02 }, - { OV9740_Y_ADDR_END_LO, 0xd3 }, - { OV9740_X_OUTPUT_SIZE_HI, 0x02 }, - { OV9740_X_OUTPUT_SIZE_LO, 0x80 }, - { OV9740_Y_OUTPUT_SIZE_HI, 0x01 }, - { OV9740_Y_OUTPUT_SIZE_LO, 0xe0 }, - { OV9740_ISP_CTRL1E, 0x03 }, - { OV9740_ISP_CTRL1F, 0xc0 }, - { OV9740_ISP_CTRL20, 0x02 }, - { OV9740_ISP_CTRL21, 0xd0 }, - { OV9740_VFIFO_READ_START_HI, 0x01 }, - { OV9740_VFIFO_READ_START_LO, 0x40 }, - { OV9740_ISP_CTRL00, 0xff }, - { OV9740_ISP_CTRL01, 0xff }, - { OV9740_ISP_CTRL03, 0xff }, -}; - -static const struct ov9740_reg ov9740_regs_720p[] = { - { OV9740_X_ADDR_START_HI, 0x00 }, - { OV9740_X_ADDR_START_LO, 0x00 }, - { OV9740_Y_ADDR_START_HI, 0x00 }, - { OV9740_Y_ADDR_START_LO, 0x00 }, - { OV9740_X_ADDR_END_HI, 0x05 }, - { OV9740_X_ADDR_END_LO, 0x03 }, - { OV9740_Y_ADDR_END_HI, 0x02 }, - { OV9740_Y_ADDR_END_LO, 0xd3 }, - { OV9740_X_OUTPUT_SIZE_HI, 0x05 }, - { OV9740_X_OUTPUT_SIZE_LO, 0x00 }, - { OV9740_Y_OUTPUT_SIZE_HI, 0x02 }, - { OV9740_Y_OUTPUT_SIZE_LO, 0xd0 }, - { OV9740_ISP_CTRL1E, 0x05 }, - { OV9740_ISP_CTRL1F, 0x00 }, - { OV9740_ISP_CTRL20, 0x02 }, - { OV9740_ISP_CTRL21, 0xd0 }, - { OV9740_VFIFO_READ_START_HI, 0x02 }, - { OV9740_VFIFO_READ_START_LO, 0x30 }, - { OV9740_ISP_CTRL00, 0xff }, - { OV9740_ISP_CTRL01, 0xef }, - { OV9740_ISP_CTRL03, 0xff }, -}; - -static enum v4l2_mbus_pixelcode ov9740_codes[] = { - V4L2_MBUS_FMT_YUYV8_2X8, -}; - -static const struct v4l2_queryctrl ov9740_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - -/* read a register */ -static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) -{ - int ret; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = (u8 *)®, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = 1, - .buf = val, - }, - }; - - reg = swab16(reg); - - ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) { - dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg); - return ret; - } - - return 0; -} - -/* write a register */ -static int ov9740_reg_write(struct i2c_client *client, u16 reg, u8 val) -{ - struct i2c_msg msg; - struct { - u16 reg; - u8 val; - } __packed buf; - int ret; - - reg = swab16(reg); - - buf.reg = reg; - buf.val = val; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 3; - msg.buf = (u8 *)&buf; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg); - return ret; - } - - return 0; -} - - -/* Read a register, alter its bits, write it back */ -static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset) -{ - u8 val; - int ret; - - ret = ov9740_reg_read(client, reg, &val); - if (ret < 0) { - dev_err(&client->dev, - "[Read]-Modify-Write of register %02x failed!\n", reg); - return ret; - } - - val |= set; - val &= ~unset; - - ret = ov9740_reg_write(client, reg, val); - if (ret < 0) { - dev_err(&client->dev, - "Read-Modify-[Write] of register %02x failed!\n", reg); - return ret; - } - - return 0; -} - -static int ov9740_reg_write_array(struct i2c_client *client, - const struct ov9740_reg *regarray, - int regarraylen) -{ - int i; - int ret; - - for (i = 0; i < regarraylen; i++) { - ret = ov9740_reg_write(client, - regarray[i].reg, regarray[i].val); - if (ret < 0) - return ret; - } - - return 0; -} - -/* Start/Stop streaming from the device */ -static int ov9740_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov9740_priv *priv = to_ov9740(sd); - int ret; - - /* Program orientation register. */ - if (priv->flag_vflip) - ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x2, 0); - else - ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x2); - if (ret < 0) - return ret; - - if (priv->flag_hflip) - ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x1, 0); - else - ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x1); - if (ret < 0) - return ret; - - if (enable) { - dev_dbg(&client->dev, "Enabling Streaming\n"); - /* Start Streaming */ - ret = ov9740_reg_write(client, OV9740_MODE_SELECT, 0x01); - - } else { - dev_dbg(&client->dev, "Disabling Streaming\n"); - /* Software Reset */ - ret = ov9740_reg_write(client, OV9740_SOFTWARE_RESET, 0x01); - if (!ret) - /* Setting Streaming to Standby */ - ret = ov9740_reg_write(client, OV9740_MODE_SELECT, - 0x00); - } - - return ret; -} - -/* Alter bus settings on camera side */ -static int ov9740_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -/* Request bus settings on camera side */ -static unsigned long ov9740_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -/* Get status of additional camera capabilities */ -static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov9740_priv *priv = to_ov9740(sd); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - default: - return -EINVAL; - } - - return 0; -} - -/* Set status of additional camera capabilities */ -static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov9740_priv *priv = to_ov9740(sd); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - priv->flag_vflip = ctrl->value; - break; - case V4L2_CID_HFLIP: - priv->flag_hflip = ctrl->value; - break; - default: - return -EINVAL; - } - - return 0; -} - -/* Get chip identification */ -static int ov9740_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct ov9740_priv *priv = to_ov9740(sd); - - id->ident = priv->ident; - id->revision = priv->revision; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov9740_get_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 val; - - if (reg->reg & ~0xffff) - return -EINVAL; - - reg->size = 2; - - ret = ov9740_reg_read(client, reg->reg, &val); - if (ret) - return ret; - - reg->val = (__u64)val; - - return ret; -} - -static int ov9740_set_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg & ~0xffff || reg->val & ~0xff) - return -EINVAL; - - return ov9740_reg_write(client, reg->reg, reg->val); -} -#endif - -/* select nearest higher resolution for capture */ -static void ov9740_res_roundup(u32 *width, u32 *height) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ov9740_resolutions); i++) - if ((ov9740_resolutions[i].width >= *width) && - (ov9740_resolutions[i].height >= *height)) { - *width = ov9740_resolutions[i].width; - *height = ov9740_resolutions[i].height; - return; - } - - *width = ov9740_resolutions[OV9740_720P].width; - *height = ov9740_resolutions[OV9740_720P].height; -} - -/* Setup registers according to resolution and color encoding */ -static int ov9740_set_res(struct i2c_client *client, u32 width) -{ - int ret; - - /* select register configuration for given resolution */ - if (width == ov9740_resolutions[OV9740_VGA].width) { - dev_dbg(&client->dev, "Setting image size to 640x480\n"); - ret = ov9740_reg_write_array(client, ov9740_regs_vga, - ARRAY_SIZE(ov9740_regs_vga)); - } else if (width == ov9740_resolutions[OV9740_720P].width) { - dev_dbg(&client->dev, "Setting image size to 1280x720\n"); - ret = ov9740_reg_write_array(client, ov9740_regs_720p, - ARRAY_SIZE(ov9740_regs_720p)); - } else { - dev_err(&client->dev, "Failed to select resolution!\n"); - return -EINVAL; - } - - return ret; -} - -/* set the format we will capture in */ -static int ov9740_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - enum v4l2_colorspace cspace; - enum v4l2_mbus_pixelcode code = mf->code; - int ret; - - ov9740_res_roundup(&mf->width, &mf->height); - - switch (code) { - case V4L2_MBUS_FMT_YUYV8_2X8: - cspace = V4L2_COLORSPACE_SRGB; - break; - default: - return -EINVAL; - } - - ret = ov9740_reg_write_array(client, ov9740_defaults, - ARRAY_SIZE(ov9740_defaults)); - if (ret < 0) - return ret; - - ret = ov9740_set_res(client, mf->width); - if (ret < 0) - return ret; - - mf->code = code; - mf->colorspace = cspace; - - return ret; -} - -static int ov9740_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - ov9740_res_roundup(&mf->width, &mf->height); - - mf->field = V4L2_FIELD_NONE; - mf->code = V4L2_MBUS_FMT_YUYV8_2X8; - mf->colorspace = V4L2_COLORSPACE_SRGB; - - return 0; -} - -static int ov9740_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index >= ARRAY_SIZE(ov9740_codes)) - return -EINVAL; - - *code = ov9740_codes[index]; - - return 0; -} - -static int ov9740_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = ov9740_resolutions[OV9740_720P].width; - a->bounds.height = ov9740_resolutions[OV9740_720P].height; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - a->c.left = 0; - a->c.top = 0; - a->c.width = ov9740_resolutions[OV9740_720P].width; - a->c.height = ov9740_resolutions[OV9740_720P].height; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int ov9740_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9740_priv *priv = to_ov9740(sd); - u8 modelhi, modello; - int ret; - - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) { - dev_err(&client->dev, "Parent missing or invalid!\n"); - ret = -ENODEV; - goto err; - } - - /* - * check and show product ID and manufacturer ID - */ - ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi); - if (ret < 0) - goto err; - - ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello); - if (ret < 0) - goto err; - - priv->model = (modelhi << 8) | modello; - - ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision); - if (ret < 0) - goto err; - - ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid); - if (ret < 0) - goto err; - - ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver); - if (ret < 0) - goto err; - - if (priv->model != 0x9740) { - ret = -ENODEV; - goto err; - } - - priv->ident = V4L2_IDENT_OV9740; - - dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, " - "Manufacturer 0x%02x, SMIA Version 0x%02x\n", - priv->model, priv->revision, priv->manid, priv->smiaver); - -err: - return ret; -} - -static struct soc_camera_ops ov9740_ops = { - .set_bus_param = ov9740_set_bus_param, - .query_bus_param = ov9740_query_bus_param, - .controls = ov9740_controls, - .num_controls = ARRAY_SIZE(ov9740_controls), -}; - -static struct v4l2_subdev_core_ops ov9740_core_ops = { - .g_ctrl = ov9740_g_ctrl, - .s_ctrl = ov9740_s_ctrl, - .g_chip_ident = ov9740_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov9740_get_register, - .s_register = ov9740_set_register, -#endif - -}; - -static struct v4l2_subdev_video_ops ov9740_video_ops = { - .s_stream = ov9740_s_stream, - .s_mbus_fmt = ov9740_s_fmt, - .try_mbus_fmt = ov9740_try_fmt, - .enum_mbus_fmt = ov9740_enum_fmt, - .cropcap = ov9740_cropcap, - .g_crop = ov9740_g_crop, -}; - -static struct v4l2_subdev_ops ov9740_subdev_ops = { - .core = &ov9740_core_ops, - .video = &ov9740_video_ops, -}; - -/* - * i2c_driver function - */ -static int ov9740_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct ov9740_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "Missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "Missing platform_data for driver\n"); - return -EINVAL; - } - - priv = kzalloc(sizeof(struct ov9740_priv), GFP_KERNEL); - if (!priv) { - dev_err(&client->dev, "Failed to allocate private data!\n"); - return -ENOMEM; - } - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); - - icd->ops = &ov9740_ops; - - ret = ov9740_video_probe(icd, client); - if (ret < 0) { - icd->ops = NULL; - kfree(priv); - } - - return ret; -} - -static int ov9740_remove(struct i2c_client *client) -{ - struct ov9740_priv *priv = i2c_get_clientdata(client); - - kfree(priv); - - return 0; -} - -static const struct i2c_device_id ov9740_id[] = { - { "ov9740", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov9740_id); - -static struct i2c_driver ov9740_i2c_driver = { - .driver = { - .name = "ov9740", - }, - .probe = ov9740_probe, - .remove = ov9740_remove, - .id_table = ov9740_id, -}; - -static int __init ov9740_module_init(void) -{ - return i2c_add_driver(&ov9740_i2c_driver); -} - -static void __exit ov9740_module_exit(void) -{ - i2c_del_driver(&ov9740_i2c_driver); -} - -module_init(ov9740_module_init); -module_exit(ov9740_module_exit); - -MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740"); -MODULE_AUTHOR("Andrew Chew "); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pms.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pms.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pms.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pms.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1146 +0,0 @@ -/* - * Media Vision Pro Movie Studio - * or - * "all you need is an I2C bus some RAM and a prayer" - * - * This draws heavily on code - * - * (c) Wolfgang Koehler, wolf@first.gmd.de, Dec. 1994 - * Kiefernring 15 - * 14478 Potsdam, Germany - * - * Most of this code is directly derived from his userspace driver. - * His driver works so send any reports to alan@lxorguk.ukuu.org.uk - * unless the userspace driver also doesn't work for you... - * - * Changes: - * 25-11-2009 Hans Verkuil - * - converted to version 2 of the V4L API. - * 08/07/2003 Daniele Bellucci - * - pms_capture: report back -EFAULT - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); - - -#define MOTOROLA 1 -#define PHILIPS2 2 /* SAA7191 */ -#define PHILIPS1 3 -#define MVVMEMORYWIDTH 0x40 /* 512 bytes */ - -struct i2c_info { - u8 slave; - u8 sub; - u8 data; - u8 hits; -}; - -struct pms { - struct v4l2_device v4l2_dev; - struct video_device vdev; - int height; - int width; - int depth; - int input; - s32 brightness, saturation, hue, contrast; - struct mutex lock; - int i2c_count; - struct i2c_info i2cinfo[64]; - - int decoder; - int standard; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */ - v4l2_std_id std; - int io; - int data; - void __iomem *mem; -}; - -static struct pms pms_card; - -/* - * I/O ports and Shared Memory - */ - -static int io_port = 0x250; -module_param(io_port, int, 0); - -static int mem_base = 0xc8000; -module_param(mem_base, int, 0); - -static int video_nr = -1; -module_param(video_nr, int, 0); - - -static inline void mvv_write(struct pms *dev, u8 index, u8 value) -{ - outw(index | (value << 8), dev->io); -} - -static inline u8 mvv_read(struct pms *dev, u8 index) -{ - outb(index, dev->io); - return inb(dev->data); -} - -static int pms_i2c_stat(struct pms *dev, u8 slave) -{ - int counter = 0; - int i; - - outb(0x28, dev->io); - - while ((inb(dev->data) & 0x01) == 0) - if (counter++ == 256) - break; - - while ((inb(dev->data) & 0x01) != 0) - if (counter++ == 256) - break; - - outb(slave, dev->io); - - counter = 0; - while ((inb(dev->data) & 0x01) == 0) - if (counter++ == 256) - break; - - while ((inb(dev->data) & 0x01) != 0) - if (counter++ == 256) - break; - - for (i = 0; i < 12; i++) { - char st = inb(dev->data); - - if ((st & 2) != 0) - return -1; - if ((st & 1) == 0) - break; - } - outb(0x29, dev->io); - return inb(dev->data); -} - -static int pms_i2c_write(struct pms *dev, u16 slave, u16 sub, u16 data) -{ - int skip = 0; - int count; - int i; - - for (i = 0; i < dev->i2c_count; i++) { - if ((dev->i2cinfo[i].slave == slave) && - (dev->i2cinfo[i].sub == sub)) { - if (dev->i2cinfo[i].data == data) - skip = 1; - dev->i2cinfo[i].data = data; - i = dev->i2c_count + 1; - } - } - - if (i == dev->i2c_count && dev->i2c_count < 64) { - dev->i2cinfo[dev->i2c_count].slave = slave; - dev->i2cinfo[dev->i2c_count].sub = sub; - dev->i2cinfo[dev->i2c_count].data = data; - dev->i2c_count++; - } - - if (skip) - return 0; - - mvv_write(dev, 0x29, sub); - mvv_write(dev, 0x2A, data); - mvv_write(dev, 0x28, slave); - - outb(0x28, dev->io); - - count = 0; - while ((inb(dev->data) & 1) == 0) - if (count > 255) - break; - while ((inb(dev->data) & 1) != 0) - if (count > 255) - break; - - count = inb(dev->data); - - if (count & 2) - return -1; - return count; -} - -static int pms_i2c_read(struct pms *dev, int slave, int sub) -{ - int i; - - for (i = 0; i < dev->i2c_count; i++) { - if (dev->i2cinfo[i].slave == slave && dev->i2cinfo[i].sub == sub) - return dev->i2cinfo[i].data; - } - return 0; -} - - -static void pms_i2c_andor(struct pms *dev, int slave, int sub, int and, int or) -{ - u8 tmp; - - tmp = pms_i2c_read(dev, slave, sub); - tmp = (tmp & and) | or; - pms_i2c_write(dev, slave, sub, tmp); -} - -/* - * Control functions - */ - - -static void pms_videosource(struct pms *dev, short source) -{ - switch (dev->decoder) { - case MOTOROLA: - break; - case PHILIPS2: - pms_i2c_andor(dev, 0x8a, 0x06, 0x7f, source ? 0x80 : 0); - break; - case PHILIPS1: - break; - } - mvv_write(dev, 0x2E, 0x31); - /* Was: mvv_write(dev, 0x2E, source ? 0x31 : 0x30); - But could not make this work correctly. Only Composite input - worked for me. */ -} - -static void pms_hue(struct pms *dev, short hue) -{ - switch (dev->decoder) { - case MOTOROLA: - pms_i2c_write(dev, 0x8a, 0x00, hue); - break; - case PHILIPS2: - pms_i2c_write(dev, 0x8a, 0x07, hue); - break; - case PHILIPS1: - pms_i2c_write(dev, 0x42, 0x07, hue); - break; - } -} - -static void pms_saturation(struct pms *dev, short sat) -{ - switch (dev->decoder) { - case MOTOROLA: - pms_i2c_write(dev, 0x8a, 0x00, sat); - break; - case PHILIPS1: - pms_i2c_write(dev, 0x42, 0x12, sat); - break; - } -} - - -static void pms_contrast(struct pms *dev, short contrast) -{ - switch (dev->decoder) { - case MOTOROLA: - pms_i2c_write(dev, 0x8a, 0x00, contrast); - break; - case PHILIPS1: - pms_i2c_write(dev, 0x42, 0x13, contrast); - break; - } -} - -static void pms_brightness(struct pms *dev, short brightness) -{ - switch (dev->decoder) { - case MOTOROLA: - pms_i2c_write(dev, 0x8a, 0x00, brightness); - pms_i2c_write(dev, 0x8a, 0x00, brightness); - pms_i2c_write(dev, 0x8a, 0x00, brightness); - break; - case PHILIPS1: - pms_i2c_write(dev, 0x42, 0x19, brightness); - break; - } -} - - -static void pms_format(struct pms *dev, short format) -{ - int target; - - dev->standard = format; - - if (dev->decoder == PHILIPS1) - target = 0x42; - else if (dev->decoder == PHILIPS2) - target = 0x8a; - else - return; - - switch (format) { - case 0: /* Auto */ - pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00); - pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x80); - break; - case 1: /* NTSC */ - pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00); - pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x40); - break; - case 2: /* PAL */ - pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00); - pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00); - break; - case 3: /* SECAM */ - pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x01); - pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00); - break; - } -} - -#ifdef FOR_FUTURE_EXPANSION - -/* - * These features of the PMS card are not currently exposes. They - * could become a private v4l ioctl for PMSCONFIG or somesuch if - * people need it. We also don't yet use the PMS interrupt. - */ - -static void pms_hstart(struct pms *dev, short start) -{ - switch (dev->decoder) { - case PHILIPS1: - pms_i2c_write(dev, 0x8a, 0x05, start); - pms_i2c_write(dev, 0x8a, 0x18, start); - break; - case PHILIPS2: - pms_i2c_write(dev, 0x42, 0x05, start); - pms_i2c_write(dev, 0x42, 0x18, start); - break; - } -} - -/* - * Bandpass filters - */ - -static void pms_bandpass(struct pms *dev, short pass) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x06, 0xcf, (pass & 0x03) << 4); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x06, 0xcf, (pass & 0x03) << 4); -} - -static void pms_antisnow(struct pms *dev, short snow) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x06, 0xf3, (snow & 0x03) << 2); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x06, 0xf3, (snow & 0x03) << 2); -} - -static void pms_sharpness(struct pms *dev, short sharp) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x06, 0xfc, sharp & 0x03); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x06, 0xfc, sharp & 0x03); -} - -static void pms_chromaagc(struct pms *dev, short agc) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x0c, 0x9f, (agc & 0x03) << 5); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x0c, 0x9f, (agc & 0x03) << 5); -} - -static void pms_vertnoise(struct pms *dev, short noise) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x10, 0xfc, noise & 3); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x10, 0xfc, noise & 3); -} - -static void pms_forcecolour(struct pms *dev, short colour) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x0c, 0x7f, (colour & 1) << 7); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x0c, 0x7, (colour & 1) << 7); -} - -static void pms_antigamma(struct pms *dev, short gamma) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0xb8, 0x00, 0x7f, (gamma & 1) << 7); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x20, 0x7, (gamma & 1) << 7); -} - -static void pms_prefilter(struct pms *dev, short filter) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x06, 0xbf, (filter & 1) << 6); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x06, 0xbf, (filter & 1) << 6); -} - -static void pms_hfilter(struct pms *dev, short filter) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0xb8, 0x04, 0x1f, (filter & 7) << 5); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x24, 0x1f, (filter & 7) << 5); -} - -static void pms_vfilter(struct pms *dev, short filter) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0xb8, 0x08, 0x9f, (filter & 3) << 5); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x28, 0x9f, (filter & 3) << 5); -} - -static void pms_killcolour(struct pms *dev, short colour) -{ - if (dev->decoder == PHILIPS2) { - pms_i2c_andor(dev, 0x8a, 0x08, 0x07, (colour & 0x1f) << 3); - pms_i2c_andor(dev, 0x8a, 0x09, 0x07, (colour & 0x1f) << 3); - } else if (dev->decoder == PHILIPS1) { - pms_i2c_andor(dev, 0x42, 0x08, 0x07, (colour & 0x1f) << 3); - pms_i2c_andor(dev, 0x42, 0x09, 0x07, (colour & 0x1f) << 3); - } -} - -static void pms_chromagain(struct pms *dev, short chroma) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_write(dev, 0x8a, 0x11, chroma); - else if (dev->decoder == PHILIPS1) - pms_i2c_write(dev, 0x42, 0x11, chroma); -} - - -static void pms_spacialcompl(struct pms *dev, short data) -{ - mvv_write(dev, 0x3b, data); -} - -static void pms_spacialcomph(struct pms *dev, short data) -{ - mvv_write(dev, 0x3a, data); -} - -static void pms_vstart(struct pms *dev, short start) -{ - mvv_write(dev, 0x16, start); - mvv_write(dev, 0x17, (start >> 8) & 0x01); -} - -#endif - -static void pms_secamcross(struct pms *dev, short cross) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x0f, 0xdf, (cross & 1) << 5); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x0f, 0xdf, (cross & 1) << 5); -} - - -static void pms_swsense(struct pms *dev, short sense) -{ - if (dev->decoder == PHILIPS2) { - pms_i2c_write(dev, 0x8a, 0x0a, sense); - pms_i2c_write(dev, 0x8a, 0x0b, sense); - } else if (dev->decoder == PHILIPS1) { - pms_i2c_write(dev, 0x42, 0x0a, sense); - pms_i2c_write(dev, 0x42, 0x0b, sense); - } -} - - -static void pms_framerate(struct pms *dev, short frr) -{ - int fps = (dev->std & V4L2_STD_525_60) ? 30 : 25; - - if (frr == 0) - return; - fps = fps/frr; - mvv_write(dev, 0x14, 0x80 | fps); - mvv_write(dev, 0x15, 1); -} - -static void pms_vert(struct pms *dev, u8 deciden, u8 decinum) -{ - mvv_write(dev, 0x1c, deciden); /* Denominator */ - mvv_write(dev, 0x1d, decinum); /* Numerator */ -} - -/* - * Turn 16bit ratios into best small ratio the chipset can grok - */ - -static void pms_vertdeci(struct pms *dev, unsigned short decinum, unsigned short deciden) -{ - /* Knock it down by / 5 once */ - if (decinum % 5 == 0) { - deciden /= 5; - decinum /= 5; - } - /* - * 3's - */ - while (decinum % 3 == 0 && deciden % 3 == 0) { - deciden /= 3; - decinum /= 3; - } - /* - * 2's - */ - while (decinum % 2 == 0 && deciden % 2 == 0) { - decinum /= 2; - deciden /= 2; - } - /* - * Fudgyify - */ - while (deciden > 32) { - deciden /= 2; - decinum = (decinum + 1) / 2; - } - if (deciden == 32) - deciden--; - pms_vert(dev, deciden, decinum); -} - -static void pms_horzdeci(struct pms *dev, short decinum, short deciden) -{ - if (decinum <= 512) { - if (decinum % 5 == 0) { - decinum /= 5; - deciden /= 5; - } - } else { - decinum = 512; - deciden = 640; /* 768 would be ideal */ - } - - while (((decinum | deciden) & 1) == 0) { - decinum >>= 1; - deciden >>= 1; - } - while (deciden > 32) { - deciden >>= 1; - decinum = (decinum + 1) >> 1; - } - if (deciden == 32) - deciden--; - - mvv_write(dev, 0x24, 0x80 | deciden); - mvv_write(dev, 0x25, decinum); -} - -static void pms_resolution(struct pms *dev, short width, short height) -{ - int fg_height; - - fg_height = height; - if (fg_height > 280) - fg_height = 280; - - mvv_write(dev, 0x18, fg_height); - mvv_write(dev, 0x19, fg_height >> 8); - - if (dev->std & V4L2_STD_525_60) { - mvv_write(dev, 0x1a, 0xfc); - mvv_write(dev, 0x1b, 0x00); - if (height > fg_height) - pms_vertdeci(dev, 240, 240); - else - pms_vertdeci(dev, fg_height, 240); - } else { - mvv_write(dev, 0x1a, 0x1a); - mvv_write(dev, 0x1b, 0x01); - if (fg_height > 256) - pms_vertdeci(dev, 270, 270); - else - pms_vertdeci(dev, fg_height, 270); - } - mvv_write(dev, 0x12, 0); - mvv_write(dev, 0x13, MVVMEMORYWIDTH); - mvv_write(dev, 0x42, 0x00); - mvv_write(dev, 0x43, 0x00); - mvv_write(dev, 0x44, MVVMEMORYWIDTH); - - mvv_write(dev, 0x22, width + 8); - mvv_write(dev, 0x23, (width + 8) >> 8); - - if (dev->std & V4L2_STD_525_60) - pms_horzdeci(dev, width, 640); - else - pms_horzdeci(dev, width + 8, 768); - - mvv_write(dev, 0x30, mvv_read(dev, 0x30) & 0xfe); - mvv_write(dev, 0x08, mvv_read(dev, 0x08) | 0x01); - mvv_write(dev, 0x01, mvv_read(dev, 0x01) & 0xfd); - mvv_write(dev, 0x32, 0x00); - mvv_write(dev, 0x33, MVVMEMORYWIDTH); -} - - -/* - * Set Input - */ - -static void pms_vcrinput(struct pms *dev, short input) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x0d, 0x7f, (input & 1) << 7); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x0d, 0x7f, (input & 1) << 7); -} - - -static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count) -{ - int y; - int dw = 2 * dev->width; - char tmp[dw + 32]; /* using a temp buffer is faster than direct */ - int cnt = 0; - int len = 0; - unsigned char r8 = 0x5; /* value for reg8 */ - - if (rgb555) - r8 |= 0x20; /* else use untranslated rgb = 565 */ - mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */ - -/* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */ - - for (y = 0; y < dev->height; y++) { - writeb(0, dev->mem); /* synchronisiert neue Zeile */ - - /* - * This is in truth a fifo, be very careful as if you - * forgot this odd things will occur 8) - */ - - memcpy_fromio(tmp, dev->mem, dw + 32); /* discard 16 word */ - cnt -= dev->height; - while (cnt <= 0) { - /* - * Don't copy too far - */ - int dt = dw; - if (dt + len > count) - dt = count - len; - cnt += dev->height; - if (copy_to_user(buf, tmp + 32, dt)) - return len ? len : -EFAULT; - buf += dt; - len += dt; - } - } - return len; -} - - -/* - * Video4linux interfacing - */ - -static int pms_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct pms *dev = video_drvdata(file); - - strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card)); - strlcpy(vcap->bus_info, "ISA", sizeof(vcap->bus_info)); - vcap->version = KERNEL_VERSION(0, 0, 3); - vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - return 0; -} - -static int pms_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - static const char *inputs[4] = { - "Composite", - "S-Video", - "Composite (VCR)", - "S-Video (VCR)" - }; - - if (vin->index > 3) - return -EINVAL; - strlcpy(vin->name, inputs[vin->index], sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = V4L2_STD_ALL; - vin->status = 0; - return 0; -} - -static int pms_g_input(struct file *file, void *fh, unsigned int *inp) -{ - struct pms *dev = video_drvdata(file); - - *inp = dev->input; - return 0; -} - -static int pms_s_input(struct file *file, void *fh, unsigned int inp) -{ - struct pms *dev = video_drvdata(file); - - if (inp > 3) - return -EINVAL; - - mutex_lock(&dev->lock); - dev->input = inp; - pms_videosource(dev, inp & 1); - pms_vcrinput(dev, inp >> 1); - mutex_unlock(&dev->lock); - return 0; -} - -static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std) -{ - struct pms *dev = video_drvdata(file); - - *std = dev->std; - return 0; -} - -static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std) -{ - struct pms *dev = video_drvdata(file); - int ret = 0; - - dev->std = *std; - mutex_lock(&dev->lock); - if (dev->std & V4L2_STD_NTSC) { - pms_framerate(dev, 30); - pms_secamcross(dev, 0); - pms_format(dev, 1); - } else if (dev->std & V4L2_STD_PAL) { - pms_framerate(dev, 25); - pms_secamcross(dev, 0); - pms_format(dev, 2); - } else if (dev->std & V4L2_STD_SECAM) { - pms_framerate(dev, 25); - pms_secamcross(dev, 1); - pms_format(dev, 2); - } else { - ret = -EINVAL; - } - /* - switch (v->mode) { - case VIDEO_MODE_AUTO: - pms_framerate(dev, 25); - pms_secamcross(dev, 0); - pms_format(dev, 0); - break; - }*/ - mutex_unlock(&dev->lock); - return 0; -} - -static int pms_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 139); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 70); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 64); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0); - } - return -EINVAL; -} - -static int pms_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct pms *dev = video_drvdata(file); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dev->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dev->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = dev->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = dev->hue; - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static int pms_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct pms *dev = video_drvdata(file); - int ret = 0; - - mutex_lock(&dev->lock); - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - dev->brightness = ctrl->value; - pms_brightness(dev, dev->brightness); - break; - case V4L2_CID_CONTRAST: - dev->contrast = ctrl->value; - pms_contrast(dev, dev->contrast); - break; - case V4L2_CID_SATURATION: - dev->saturation = ctrl->value; - pms_saturation(dev, dev->saturation); - break; - case V4L2_CID_HUE: - dev->hue = ctrl->value; - pms_hue(dev, dev->hue); - break; - default: - ret = -EINVAL; - break; - } - mutex_unlock(&dev->lock); - return ret; -} - -static int pms_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct pms *dev = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = dev->width; - pix->height = dev->height; - pix->pixelformat = dev->width == 15 ? - V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB565; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 2 * dev->width; - pix->sizeimage = 2 * dev->width * dev->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int pms_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->height < 16 || pix->height > 480) - return -EINVAL; - if (pix->width < 16 || pix->width > 640) - return -EINVAL; - if (pix->pixelformat != V4L2_PIX_FMT_RGB555 && - pix->pixelformat != V4L2_PIX_FMT_RGB565) - return -EINVAL; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 2 * pix->width; - pix->sizeimage = 2 * pix->width * pix->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int pms_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct pms *dev = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = pms_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - mutex_lock(&dev->lock); - dev->width = pix->width; - dev->height = pix->height; - dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16; - pms_resolution(dev, dev->width, dev->height); - /* Ok we figured out what to use from our wide choice */ - mutex_unlock(&dev->lock); - return 0; -} - -static int pms_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "RGB 5:5:5", V4L2_PIX_FMT_RGB555, - { 0, 0, 0, 0 } - }, - { 0, 0, 0, - "RGB 5:6:5", V4L2_PIX_FMT_RGB565, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 1) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -static ssize_t pms_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct pms *dev = video_drvdata(file); - int len; - - mutex_lock(&dev->lock); - len = pms_capture(dev, buf, (dev->depth == 15), count); - mutex_unlock(&dev->lock); - return len; -} - -static const struct v4l2_file_operations pms_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - .read = pms_read, -}; - -static const struct v4l2_ioctl_ops pms_ioctl_ops = { - .vidioc_querycap = pms_querycap, - .vidioc_g_input = pms_g_input, - .vidioc_s_input = pms_s_input, - .vidioc_enum_input = pms_enum_input, - .vidioc_g_std = pms_g_std, - .vidioc_s_std = pms_s_std, - .vidioc_queryctrl = pms_queryctrl, - .vidioc_g_ctrl = pms_g_ctrl, - .vidioc_s_ctrl = pms_s_ctrl, - .vidioc_enum_fmt_vid_cap = pms_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = pms_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = pms_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = pms_try_fmt_vid_cap, -}; - -/* - * Probe for and initialise the Mediavision PMS - */ - -static int init_mediavision(struct pms *dev) -{ - int id; - int idec, decst; - int i; - static const unsigned char i2c_defs[] = { - 0x4c, 0x30, 0x00, 0xe8, - 0xb6, 0xe2, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x78, 0x98, - 0x00, 0x00, 0x00, 0x00, - 0x34, 0x0a, 0xf4, 0xce, - 0xe4 - }; - - dev->mem = ioremap(mem_base, 0x800); - if (!dev->mem) - return -ENOMEM; - - if (!request_region(0x9a01, 1, "Mediavision PMS config")) { - printk(KERN_WARNING "mediavision: unable to detect: 0x9a01 in use.\n"); - iounmap(dev->mem); - return -EBUSY; - } - if (!request_region(dev->io, 3, "Mediavision PMS")) { - printk(KERN_WARNING "mediavision: I/O port %d in use.\n", dev->io); - release_region(0x9a01, 1); - iounmap(dev->mem); - return -EBUSY; - } - outb(0xb8, 0x9a01); /* Unlock */ - outb(dev->io >> 4, 0x9a01); /* Set IO port */ - - - id = mvv_read(dev, 3); - decst = pms_i2c_stat(dev, 0x43); - - if (decst != -1) - idec = 2; - else if (pms_i2c_stat(dev, 0xb9) != -1) - idec = 3; - else if (pms_i2c_stat(dev, 0x8b) != -1) - idec = 1; - else - idec = 0; - - printk(KERN_INFO "PMS type is %d\n", idec); - if (idec == 0) { - release_region(dev->io, 3); - release_region(0x9a01, 1); - iounmap(dev->mem); - return -ENODEV; - } - - /* - * Ok we have a PMS of some sort - */ - - mvv_write(dev, 0x04, mem_base >> 12); /* Set the memory area */ - - /* Ok now load the defaults */ - - for (i = 0; i < 0x19; i++) { - if (i2c_defs[i] == 0xff) - pms_i2c_andor(dev, 0x8a, i, 0x07, 0x00); - else - pms_i2c_write(dev, 0x8a, i, i2c_defs[i]); - } - - pms_i2c_write(dev, 0xb8, 0x00, 0x12); - pms_i2c_write(dev, 0xb8, 0x04, 0x00); - pms_i2c_write(dev, 0xb8, 0x07, 0x00); - pms_i2c_write(dev, 0xb8, 0x08, 0x00); - pms_i2c_write(dev, 0xb8, 0x09, 0xff); - pms_i2c_write(dev, 0xb8, 0x0a, 0x00); - pms_i2c_write(dev, 0xb8, 0x0b, 0x10); - pms_i2c_write(dev, 0xb8, 0x10, 0x03); - - mvv_write(dev, 0x01, 0x00); - mvv_write(dev, 0x05, 0xa0); - mvv_write(dev, 0x08, 0x25); - mvv_write(dev, 0x09, 0x00); - mvv_write(dev, 0x0a, 0x20 | MVVMEMORYWIDTH); - - mvv_write(dev, 0x10, 0x02); - mvv_write(dev, 0x1e, 0x0c); - mvv_write(dev, 0x1f, 0x03); - mvv_write(dev, 0x26, 0x06); - - mvv_write(dev, 0x2b, 0x00); - mvv_write(dev, 0x2c, 0x20); - mvv_write(dev, 0x2d, 0x00); - mvv_write(dev, 0x2f, 0x70); - mvv_write(dev, 0x32, 0x00); - mvv_write(dev, 0x33, MVVMEMORYWIDTH); - mvv_write(dev, 0x34, 0x00); - mvv_write(dev, 0x35, 0x00); - mvv_write(dev, 0x3a, 0x80); - mvv_write(dev, 0x3b, 0x10); - mvv_write(dev, 0x20, 0x00); - mvv_write(dev, 0x21, 0x00); - mvv_write(dev, 0x30, 0x22); - return 0; -} - -/* - * Initialization and module stuff - */ - -#ifndef MODULE -static int enable; -module_param(enable, int, 0); -#endif - -static int __init pms_init(void) -{ - struct pms *dev = &pms_card; - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - int res; - - strlcpy(v4l2_dev->name, "pms", sizeof(v4l2_dev->name)); - - v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.03\n"); - -#ifndef MODULE - if (!enable) { - v4l2_err(v4l2_dev, - "PMS: not enabled, use pms.enable=1 to probe\n"); - return -ENODEV; - } -#endif - - dev->decoder = PHILIPS2; - dev->io = io_port; - dev->data = io_port + 1; - - if (init_mediavision(dev)) { - v4l2_err(v4l2_dev, "Board not found.\n"); - return -ENODEV; - } - - res = v4l2_device_register(NULL, v4l2_dev); - if (res < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return res; - } - - strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; - dev->vdev.fops = &pms_fops; - dev->vdev.ioctl_ops = &pms_ioctl_ops; - dev->vdev.release = video_device_release_empty; - video_set_drvdata(&dev->vdev, dev); - mutex_init(&dev->lock); - dev->std = V4L2_STD_NTSC_M; - dev->height = 240; - dev->width = 320; - dev->depth = 15; - dev->brightness = 139; - dev->contrast = 70; - dev->hue = 0; - dev->saturation = 64; - pms_swsense(dev, 75); - pms_resolution(dev, 320, 240); - pms_videosource(dev, 0); - pms_vcrinput(dev, 0); - if (video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - v4l2_device_unregister(&dev->v4l2_dev); - release_region(dev->io, 3); - release_region(0x9a01, 1); - iounmap(dev->mem); - return -EINVAL; - } - return 0; -} - -static void __exit pms_exit(void) -{ - struct pms *dev = &pms_card; - - video_unregister_device(&dev->vdev); - release_region(dev->io, 3); - release_region(0x9a01, 1); - iounmap(dev->mem); -} - -module_init(pms_init); -module_exit(pms_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -config VIDEO_PVRUSB2 - tristate "Hauppauge WinTV-PVR USB2 support" - depends on VIDEO_V4L2 && I2C - depends on VIDEO_MEDIA # Avoids pvrusb = Y / DVB = M - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_CX2341X - select VIDEO_SAA711X - select VIDEO_CX25840 - select VIDEO_MSP3400 - select VIDEO_WM8775 - select VIDEO_CS53L32A - ---help--- - This is a video4linux driver for Conexant 23416 based - usb2 personal video recorder devices. - - To compile this driver as a module, choose M here: the - module will be called pvrusb2 - -config VIDEO_PVRUSB2_SYSFS - bool "pvrusb2 sysfs support (EXPERIMENTAL)" - default y - depends on VIDEO_PVRUSB2 && SYSFS && EXPERIMENTAL - ---help--- - This option enables the operation of a sysfs based - interface for query and control of the pvrusb2 driver. - - This is not generally needed for v4l applications, - although certain applications are optimized to take - advantage of this feature. - - If you are in doubt, say Y. - - Note: This feature is experimental and subject to change. - -config VIDEO_PVRUSB2_DVB - bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)" - default y - depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_S5H1409 if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select DVB_TDA10048 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - ---help--- - - This option enables a DVB interface for the pvrusb2 driver. - If your device does not support digital television, this - feature will have no affect on the driver's operation. - - If you are in doubt, say Y. - -config VIDEO_PVRUSB2_DEBUGIFC - bool "pvrusb2 debug interface" - depends on VIDEO_PVRUSB2_SYSFS - ---help--- - This option enables the inclusion of a debug interface - in the pvrusb2 driver, hosted through sysfs. - - You do not need to select this option unless you plan - on debugging the driver or performing a manual firmware - extraction. - - If you are in doubt, say N. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o -obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o -obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o - -pvrusb2-objs := pvrusb2-i2c-core.o \ - pvrusb2-audio.o \ - pvrusb2-encoder.o pvrusb2-video-v4l.o \ - pvrusb2-eeprom.o \ - pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \ - pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \ - pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \ - pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \ - pvrusb2-cs53l32a.o \ - $(obj-pvrusb2-dvb-y) \ - $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y) - -obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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-audio.h" -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-debug.h" -#include -#include -#include - - -struct routing_scheme { - const int *def; - unsigned int cnt; -}; - -static const int routing_scheme0[] = { - [PVR2_CVAL_INPUT_TV] = MSP_INPUT_DEFAULT, - [PVR2_CVAL_INPUT_RADIO] = MSP_INPUT(MSP_IN_SCART2, - MSP_IN_TUNER1, - MSP_DSP_IN_SCART, - MSP_DSP_IN_SCART), - [PVR2_CVAL_INPUT_COMPOSITE] = MSP_INPUT(MSP_IN_SCART1, - MSP_IN_TUNER1, - MSP_DSP_IN_SCART, - MSP_DSP_IN_SCART), - [PVR2_CVAL_INPUT_SVIDEO] = MSP_INPUT(MSP_IN_SCART1, - MSP_IN_TUNER1, - MSP_DSP_IN_SCART, - MSP_DSP_IN_SCART), -}; - -static const struct routing_scheme routing_def0 = { - .def = routing_scheme0, - .cnt = ARRAY_SIZE(routing_scheme0), -}; - -static const struct routing_scheme *routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, -}; - -void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) -{ - if (hdw->input_dirty || hdw->force_dirty) { - const struct routing_scheme *sp; - unsigned int sid = hdw->hdw_desc->signal_routing_scheme; - u32 input; - - pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo"); - sp = (sid < ARRAY_SIZE(routing_schemes)) ? - routing_schemes[sid] : NULL; - - if ((sp != NULL) && - (hdw->input_val >= 0) && - (hdw->input_val < sp->cnt)) { - input = sp->def[hdw->input_val]; - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** subdev msp3400 set_input:" - " Invalid routing scheme (%u)" - " and/or input (%d)", - sid, hdw->input_val); - return; - } - sd->ops->audio->s_routing(sd, input, - MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0); - } -} - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -#ifndef __PVRUSB2_AUDIO_H -#define __PVRUSB2_AUDIO_H - -#include "pvrusb2-hdw-internal.h" -void pvr2_msp3400_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *); -#endif /* __PVRUSB2_AUDIO_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-context.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-context.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-context.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-context.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,431 +0,0 @@ -/* - * - * Copyright (C) 2005 Mike Isely - * - * 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-context.h" -#include "pvrusb2-io.h" -#include "pvrusb2-ioread.h" -#include "pvrusb2-hdw.h" -#include "pvrusb2-debug.h" -#include -#include -#include -#include -#include - -static struct pvr2_context *pvr2_context_exist_first; -static struct pvr2_context *pvr2_context_exist_last; -static struct pvr2_context *pvr2_context_notify_first; -static struct pvr2_context *pvr2_context_notify_last; -static DEFINE_MUTEX(pvr2_context_mutex); -static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data); -static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data); -static int pvr2_context_cleanup_flag; -static int pvr2_context_cleaned_flag; -static struct task_struct *pvr2_context_thread_ptr; - - -static void pvr2_context_set_notify(struct pvr2_context *mp, int fl) -{ - int signal_flag = 0; - mutex_lock(&pvr2_context_mutex); - if (fl) { - if (!mp->notify_flag) { - signal_flag = (pvr2_context_notify_first == NULL); - mp->notify_prev = pvr2_context_notify_last; - mp->notify_next = NULL; - pvr2_context_notify_last = mp; - if (mp->notify_prev) { - mp->notify_prev->notify_next = mp; - } else { - pvr2_context_notify_first = mp; - } - mp->notify_flag = !0; - } - } else { - if (mp->notify_flag) { - mp->notify_flag = 0; - if (mp->notify_next) { - mp->notify_next->notify_prev = mp->notify_prev; - } else { - pvr2_context_notify_last = mp->notify_prev; - } - if (mp->notify_prev) { - mp->notify_prev->notify_next = mp->notify_next; - } else { - pvr2_context_notify_first = mp->notify_next; - } - } - } - mutex_unlock(&pvr2_context_mutex); - if (signal_flag) wake_up(&pvr2_context_sync_data); -} - - -static void pvr2_context_destroy(struct pvr2_context *mp) -{ - pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp); - if (mp->hdw) pvr2_hdw_destroy(mp->hdw); - pvr2_context_set_notify(mp, 0); - mutex_lock(&pvr2_context_mutex); - if (mp->exist_next) { - mp->exist_next->exist_prev = mp->exist_prev; - } else { - pvr2_context_exist_last = mp->exist_prev; - } - if (mp->exist_prev) { - mp->exist_prev->exist_next = mp->exist_next; - } else { - pvr2_context_exist_first = mp->exist_next; - } - if (!pvr2_context_exist_first) { - /* Trigger wakeup on control thread in case it is waiting - for an exit condition. */ - wake_up(&pvr2_context_sync_data); - } - mutex_unlock(&pvr2_context_mutex); - kfree(mp); -} - - -static void pvr2_context_notify(struct pvr2_context *mp) -{ - pvr2_context_set_notify(mp,!0); -} - - -static void pvr2_context_check(struct pvr2_context *mp) -{ - struct pvr2_channel *ch1, *ch2; - pvr2_trace(PVR2_TRACE_CTXT, - "pvr2_context %p (notify)", mp); - if (!mp->initialized_flag && !mp->disconnect_flag) { - mp->initialized_flag = !0; - pvr2_trace(PVR2_TRACE_CTXT, - "pvr2_context %p (initialize)", mp); - /* Finish hardware initialization */ - if (pvr2_hdw_initialize(mp->hdw, - (void (*)(void *))pvr2_context_notify, - mp)) { - mp->video_stream.stream = - pvr2_hdw_get_video_stream(mp->hdw); - /* Trigger interface initialization. By doing this - here initialization runs in our own safe and - cozy thread context. */ - if (mp->setup_func) mp->setup_func(mp); - } else { - pvr2_trace(PVR2_TRACE_CTXT, - "pvr2_context %p (thread skipping setup)", - mp); - /* Even though initialization did not succeed, - we're still going to continue anyway. We need - to do this in order to await the expected - disconnect (which we will detect in the normal - course of operation). */ - } - } - - for (ch1 = mp->mc_first; ch1; ch1 = ch2) { - ch2 = ch1->mc_next; - if (ch1->check_func) ch1->check_func(ch1); - } - - if (mp->disconnect_flag && !mp->mc_first) { - /* Go away... */ - pvr2_context_destroy(mp); - return; - } -} - - -static int pvr2_context_shutok(void) -{ - return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL); -} - - -static int pvr2_context_thread_func(void *foo) -{ - struct pvr2_context *mp; - - pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start"); - - do { - while ((mp = pvr2_context_notify_first) != NULL) { - pvr2_context_set_notify(mp, 0); - pvr2_context_check(mp); - } - wait_event_interruptible( - pvr2_context_sync_data, - ((pvr2_context_notify_first != NULL) || - pvr2_context_shutok())); - } while (!pvr2_context_shutok()); - - pvr2_context_cleaned_flag = !0; - wake_up(&pvr2_context_cleanup_data); - - pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up"); - - wait_event_interruptible( - pvr2_context_sync_data, - kthread_should_stop()); - - pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end"); - - return 0; -} - - -int pvr2_context_global_init(void) -{ - pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func, - NULL, - "pvrusb2-context"); - return (pvr2_context_thread_ptr ? 0 : -ENOMEM); -} - - -void pvr2_context_global_done(void) -{ - pvr2_context_cleanup_flag = !0; - wake_up(&pvr2_context_sync_data); - wait_event_interruptible( - pvr2_context_cleanup_data, - pvr2_context_cleaned_flag); - kthread_stop(pvr2_context_thread_ptr); -} - - -struct pvr2_context *pvr2_context_create( - struct usb_interface *intf, - const struct usb_device_id *devid, - void (*setup_func)(struct pvr2_context *)) -{ - struct pvr2_context *mp = NULL; - mp = kzalloc(sizeof(*mp),GFP_KERNEL); - if (!mp) goto done; - pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp); - mp->setup_func = setup_func; - mutex_init(&mp->mutex); - mutex_lock(&pvr2_context_mutex); - mp->exist_prev = pvr2_context_exist_last; - mp->exist_next = NULL; - pvr2_context_exist_last = mp; - if (mp->exist_prev) { - mp->exist_prev->exist_next = mp; - } else { - pvr2_context_exist_first = mp; - } - mutex_unlock(&pvr2_context_mutex); - mp->hdw = pvr2_hdw_create(intf,devid); - if (!mp->hdw) { - pvr2_context_destroy(mp); - mp = NULL; - goto done; - } - pvr2_context_set_notify(mp, !0); - done: - return mp; -} - - -static void pvr2_context_reset_input_limits(struct pvr2_context *mp) -{ - unsigned int tmsk,mmsk; - struct pvr2_channel *cp; - struct pvr2_hdw *hdw = mp->hdw; - mmsk = pvr2_hdw_get_input_available(hdw); - tmsk = mmsk; - for (cp = mp->mc_first; cp; cp = cp->mc_next) { - if (!cp->input_mask) continue; - tmsk &= cp->input_mask; - } - pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk); - pvr2_hdw_commit_ctl(hdw); -} - - -static void pvr2_context_enter(struct pvr2_context *mp) -{ - mutex_lock(&mp->mutex); -} - - -static void pvr2_context_exit(struct pvr2_context *mp) -{ - int destroy_flag = 0; - if (!(mp->mc_first || !mp->disconnect_flag)) { - destroy_flag = !0; - } - mutex_unlock(&mp->mutex); - if (destroy_flag) pvr2_context_notify(mp); -} - - -void pvr2_context_disconnect(struct pvr2_context *mp) -{ - pvr2_hdw_disconnect(mp->hdw); - mp->disconnect_flag = !0; - pvr2_context_notify(mp); -} - - -void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp) -{ - pvr2_context_enter(mp); - cp->hdw = mp->hdw; - cp->mc_head = mp; - cp->mc_next = NULL; - cp->mc_prev = mp->mc_last; - if (mp->mc_last) { - mp->mc_last->mc_next = cp; - } else { - mp->mc_first = cp; - } - mp->mc_last = cp; - pvr2_context_exit(mp); -} - - -static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp) -{ - if (!cp->stream) return; - pvr2_stream_kill(cp->stream->stream); - cp->stream->user = NULL; - cp->stream = NULL; -} - - -void pvr2_channel_done(struct pvr2_channel *cp) -{ - struct pvr2_context *mp = cp->mc_head; - pvr2_context_enter(mp); - cp->input_mask = 0; - pvr2_channel_disclaim_stream(cp); - pvr2_context_reset_input_limits(mp); - if (cp->mc_next) { - cp->mc_next->mc_prev = cp->mc_prev; - } else { - mp->mc_last = cp->mc_prev; - } - if (cp->mc_prev) { - cp->mc_prev->mc_next = cp->mc_next; - } else { - mp->mc_first = cp->mc_next; - } - cp->hdw = NULL; - pvr2_context_exit(mp); -} - - -int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk) -{ - unsigned int tmsk,mmsk; - int ret = 0; - struct pvr2_channel *p2; - struct pvr2_hdw *hdw = cp->hdw; - - mmsk = pvr2_hdw_get_input_available(hdw); - cmsk &= mmsk; - if (cmsk == cp->input_mask) { - /* No change; nothing to do */ - return 0; - } - - pvr2_context_enter(cp->mc_head); - do { - if (!cmsk) { - cp->input_mask = 0; - pvr2_context_reset_input_limits(cp->mc_head); - break; - } - tmsk = mmsk; - for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) { - if (p2 == cp) continue; - if (!p2->input_mask) continue; - tmsk &= p2->input_mask; - } - if (!(tmsk & cmsk)) { - ret = -EPERM; - break; - } - tmsk &= cmsk; - if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) { - /* Internal failure changing allowed list; probably - should not happen, but react if it does. */ - break; - } - cp->input_mask = cmsk; - pvr2_hdw_commit_ctl(hdw); - } while (0); - pvr2_context_exit(cp->mc_head); - return ret; -} - - -unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp) -{ - return cp->input_mask; -} - - -int pvr2_channel_claim_stream(struct pvr2_channel *cp, - struct pvr2_context_stream *sp) -{ - int code = 0; - pvr2_context_enter(cp->mc_head); do { - if (sp == cp->stream) break; - if (sp && sp->user) { - code = -EBUSY; - break; - } - pvr2_channel_disclaim_stream(cp); - if (!sp) break; - sp->user = cp; - cp->stream = sp; - } while (0); pvr2_context_exit(cp->mc_head); - return code; -} - - -// This is the marker for the real beginning of a legitimate mpeg2 stream. -static char stream_sync_key[] = { - 0x00, 0x00, 0x01, 0xba, -}; - -struct pvr2_ioread *pvr2_channel_create_mpeg_stream( - struct pvr2_context_stream *sp) -{ - struct pvr2_ioread *cp; - cp = pvr2_ioread_create(); - if (!cp) return NULL; - pvr2_ioread_setup(cp,sp->stream); - pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key)); - return cp; -} - - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-context.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-context.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-context.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-context.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -/* - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_CONTEXT_H -#define __PVRUSB2_CONTEXT_H - -#include -#include -#include - -struct pvr2_hdw; /* hardware interface - defined elsewhere */ -struct pvr2_stream; /* stream interface - defined elsewhere */ - -struct pvr2_context; /* All central state */ -struct pvr2_channel; /* One I/O pathway to a user */ -struct pvr2_context_stream; /* Wrapper for a stream */ -struct pvr2_ioread; /* Low level stream structure */ - -struct pvr2_context_stream { - struct pvr2_channel *user; - struct pvr2_stream *stream; -}; - -struct pvr2_context { - struct pvr2_channel *mc_first; - struct pvr2_channel *mc_last; - struct pvr2_context *exist_next; - struct pvr2_context *exist_prev; - struct pvr2_context *notify_next; - struct pvr2_context *notify_prev; - struct pvr2_hdw *hdw; - struct pvr2_context_stream video_stream; - struct mutex mutex; - int notify_flag; - int initialized_flag; - int disconnect_flag; - - /* Called after pvr2_context initialization is complete */ - void (*setup_func)(struct pvr2_context *); - -}; - -struct pvr2_channel { - struct pvr2_context *mc_head; - struct pvr2_channel *mc_next; - struct pvr2_channel *mc_prev; - struct pvr2_context_stream *stream; - struct pvr2_hdw *hdw; - unsigned int input_mask; - void (*check_func)(struct pvr2_channel *); -}; - -struct pvr2_context *pvr2_context_create(struct usb_interface *intf, - const struct usb_device_id *devid, - void (*setup_func)(struct pvr2_context *)); -void pvr2_context_disconnect(struct pvr2_context *); - -void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *); -void pvr2_channel_done(struct pvr2_channel *); -int pvr2_channel_limit_inputs(struct pvr2_channel *,unsigned int); -unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *); -int pvr2_channel_claim_stream(struct pvr2_channel *, - struct pvr2_context_stream *); -struct pvr2_ioread *pvr2_channel_create_mpeg_stream( - struct pvr2_context_stream *); - -int pvr2_context_global_init(void); -void pvr2_context_global_done(void); - -#endif /* __PVRUSB2_CONTEXT_H */ -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -/* - - This source file is specifically designed to interface with the - v4l-dvb cs53l32a module. - -*/ - -#include "pvrusb2-cs53l32a.h" - - -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-debug.h" -#include -#include -#include - -struct routing_scheme { - const int *def; - unsigned int cnt; -}; - - -static const int routing_scheme1[] = { - [PVR2_CVAL_INPUT_TV] = 2, /* 1 or 2 seems to work here */ - [PVR2_CVAL_INPUT_RADIO] = 2, - [PVR2_CVAL_INPUT_COMPOSITE] = 0, - [PVR2_CVAL_INPUT_SVIDEO] = 0, -}; - -static const struct routing_scheme routing_def1 = { - .def = routing_scheme1, - .cnt = ARRAY_SIZE(routing_scheme1), -}; - -static const struct routing_scheme *routing_schemes[] = { - [PVR2_ROUTING_SCHEME_ONAIR] = &routing_def1, -}; - - -void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) -{ - if (hdw->input_dirty || hdw->force_dirty) { - const struct routing_scheme *sp; - unsigned int sid = hdw->hdw_desc->signal_routing_scheme; - u32 input; - pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)", - hdw->input_val); - sp = (sid < ARRAY_SIZE(routing_schemes)) ? - routing_schemes[sid] : NULL; - if ((sp == NULL) || - (hdw->input_val < 0) || - (hdw->input_val >= sp->cnt)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** subdev v4l2 set_input:" - " Invalid routing scheme (%u)" - " and/or input (%d)", - sid, hdw->input_val); - return; - } - input = sp->def[hdw->input_val]; - sd->ops->audio->s_routing(sd, input, 0, 0); - } -} - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -#ifndef __PVRUSB2_CS53L32A_H -#define __PVRUSB2_CS53L32A_H - -/* - - This module connects the pvrusb2 driver to the I2C chip level - driver which handles device video processing. This interface is - used internally by the driver; higher level code should only - interact through the interface provided by pvrusb2-hdw.h. - -*/ - - -#include "pvrusb2-hdw-internal.h" -void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *); - -#endif /* __PVRUSB2_AUDIO_CS53L32A_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,609 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 -#include -#include - - -static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val) -{ - if (cptr->info->check_value) { - if (!cptr->info->check_value(cptr,val)) return -ERANGE; - } else if (cptr->info->type == pvr2_ctl_enum) { - if (val < 0) return -ERANGE; - if (val >= cptr->info->def.type_enum.count) return -ERANGE; - } else { - int lim; - lim = cptr->info->def.type_int.min_value; - if (cptr->info->get_min_value) { - cptr->info->get_min_value(cptr,&lim); - } - if (val < lim) return -ERANGE; - lim = cptr->info->def.type_int.max_value; - if (cptr->info->get_max_value) { - cptr->info->get_max_value(cptr,&lim); - } - if (val > lim) return -ERANGE; - } - return 0; -} - - -/* 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) { - if (cptr->info->type == pvr2_ctl_bitmask) { - mask &= cptr->info->def.type_bitmask.valid_bits; - } else if ((cptr->info->type == pvr2_ctl_int)|| - (cptr->info->type == pvr2_ctl_enum)) { - ret = pvr2_ctrl_range_check(cptr,val); - if (ret < 0) break; - } else if (cptr->info->type != pvr2_ctl_bool) { - 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->get_max_value) { - cptr->info->get_max_value(cptr,&ret); - } else 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->get_min_value) { - cptr->info->get_min_value(cptr,&ret); - } else 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 *valptr) -{ - int ret = 0; - if (!cptr) return -EINVAL; - LOCK_TAKE(cptr->hdw->big_lock); do { - if (cptr->info->get_def_value) { - ret = cptr->info->get_def_value(cptr, valptr); - } else { - *valptr = 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 NULL; - return cptr->info->name; -} - - -/* Retrieve the control's desc */ -const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr) -{ - if (!cptr) return NULL; - 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 * const *names; - names = cptr->info->def.type_enum.value_names; - if (pvr2_ctrl_range_check(cptr,val) == 0) { - 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 V4L ID for this control or zero if none */ -int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr) -{ - if (!cptr) return 0; - return cptr->info->v4l_id; -} - - -unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr) -{ - unsigned int flags = 0; - - if (cptr->info->get_v4lflags) { - flags = cptr->info->get_v4lflags(cptr); - } - - if (cptr->info->set_value) { - flags &= ~V4L2_CTRL_FLAG_READ_ONLY; - } else { - flags |= V4L2_CTRL_FLAG_READ_ONLY; - } - - return flags; -} - - -/* Return true if control is writable */ -int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr) -{ - if (!cptr) return 0; - return cptr->info->set_value != NULL; -} - - -/* 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 const char *boolNames[] = { - "false", - "true", - "no", - "yes", -}; - - -static int parse_token(const char *ptr,unsigned int len, - int *valptr, - const char * const *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 1; -} - - -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,NULL,0); - if (ret >= 0) { - ret = pvr2_ctrl_range_check(cptr,*valptr); - } - *maskptr = ~0; - } else if (cptr->info->type == pvr2_ctl_bool) { - ret = parse_token(ptr,len,valptr,boolNames, - ARRAY_SIZE(boolNames)); - if (ret == 1) { - *valptr = *valptr ? !0 : 0; - } else if (ret == 0) { - *valptr = (*valptr & 1) ? !0 : 0; - } - *maskptr = 1; - } 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) { - ret = pvr2_ctrl_range_check(cptr,*valptr); - } - *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_bool) { - *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false"); - ret = 0; - } else if (cptr->info->type == pvr2_ctl_enum) { - const char * const *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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_CTRL_H -#define __PVRUSB2_CTRL_H - -struct pvr2_ctrl; - -enum pvr2_ctl_type { - pvr2_ctl_int = 0, - pvr2_ctl_enum = 1, - pvr2_ctl_bitmask = 2, - pvr2_ctl_bool = 3, -}; - - -/* Set the given control. */ -int pvr2_ctrl_set_value(struct pvr2_ctrl *,int val); - -/* Set/clear specific bits of the given control. */ -int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *,int mask,int val); - -/* Get the current value of the given control. */ -int pvr2_ctrl_get_value(struct pvr2_ctrl *,int *valptr); - -/* Retrieve control's type */ -enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *); - -/* Retrieve control's maximum value (int type) */ -int pvr2_ctrl_get_max(struct pvr2_ctrl *); - -/* Retrieve control's minimum value (int type) */ -int pvr2_ctrl_get_min(struct pvr2_ctrl *); - -/* Retrieve control's default value (any type) */ -int pvr2_ctrl_get_def(struct pvr2_ctrl *, int *valptr); - -/* Retrieve control's enumeration count (enum only) */ -int pvr2_ctrl_get_cnt(struct pvr2_ctrl *); - -/* Retrieve control's valid mask bits (bit mask only) */ -int pvr2_ctrl_get_mask(struct pvr2_ctrl *); - -/* Retrieve the control's name */ -const char *pvr2_ctrl_get_name(struct pvr2_ctrl *); - -/* Retrieve the control's desc */ -const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *); - -/* Retrieve a control enumeration or bit mask value */ -int pvr2_ctrl_get_valname(struct pvr2_ctrl *,int,char *,unsigned int, - unsigned int *); - -/* Return true if control is writable */ -int pvr2_ctrl_is_writable(struct pvr2_ctrl *); - -/* Return V4L flags value for control (or zero if there is no v4l control - actually under this control) */ -unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *); - -/* Return V4L ID for this control or zero if none */ -int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *); - -/* Return true if control has custom symbolic representation */ -int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *); - -/* Convert a given mask/val to a custom symbolic value */ -int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *, - int mask,int val, - char *buf,unsigned int maxlen, - unsigned int *len); - -/* Convert a symbolic value to a mask/value pair */ -int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *, - const char *buf,unsigned int len, - int *maskptr,int *valptr); - -/* Convert a given mask/val to a symbolic value */ -int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *, - int mask,int val, - char *buf,unsigned int maxlen, - unsigned int *len); - -/* Convert a symbolic value to a mask/value pair */ -int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *, - const char *buf,unsigned int len, - int *maskptr,int *valptr); - -/* Convert a given mask/val to a symbolic value - must already be - inside of critical region. */ -int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *, - int mask,int val, - char *buf,unsigned int maxlen, - unsigned int *len); - -#endif /* __PVRUSB2_CTRL_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,166 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -/* - - This source file is specifically designed to interface with the - cx2584x, in kernels 2.6.16 or newer. - -*/ - -#include "pvrusb2-cx2584x-v4l.h" -#include "pvrusb2-video-v4l.h" - - -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-debug.h" -#include -#include -#include -#include - - -struct routing_scheme_item { - int vid; - int aud; -}; - -struct routing_scheme { - const struct routing_scheme_item *def; - unsigned int cnt; -}; - -static const struct routing_scheme_item routing_scheme0[] = { - [PVR2_CVAL_INPUT_TV] = { - .vid = CX25840_COMPOSITE7, - .aud = CX25840_AUDIO8, - }, - [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */ - .vid = CX25840_COMPOSITE3, - .aud = CX25840_AUDIO_SERIAL, - }, - [PVR2_CVAL_INPUT_COMPOSITE] = { - .vid = CX25840_COMPOSITE3, - .aud = CX25840_AUDIO_SERIAL, - }, - [PVR2_CVAL_INPUT_SVIDEO] = { - .vid = CX25840_SVIDEO1, - .aud = CX25840_AUDIO_SERIAL, - }, -}; - -static const struct routing_scheme routing_def0 = { - .def = routing_scheme0, - .cnt = ARRAY_SIZE(routing_scheme0), -}; - -/* Specific to gotview device */ -static const struct routing_scheme_item routing_schemegv[] = { - [PVR2_CVAL_INPUT_TV] = { - .vid = CX25840_COMPOSITE2, - .aud = CX25840_AUDIO5, - }, - [PVR2_CVAL_INPUT_RADIO] = { - /* line-in is used for radio and composite. A GPIO is - used to switch between the two choices. */ - .vid = CX25840_COMPOSITE1, - .aud = CX25840_AUDIO_SERIAL, - }, - [PVR2_CVAL_INPUT_COMPOSITE] = { - .vid = CX25840_COMPOSITE1, - .aud = CX25840_AUDIO_SERIAL, - }, - [PVR2_CVAL_INPUT_SVIDEO] = { - .vid = (CX25840_SVIDEO_LUMA3|CX25840_SVIDEO_CHROMA4), - .aud = CX25840_AUDIO_SERIAL, - }, -}; - -static const struct routing_scheme routing_defgv = { - .def = routing_schemegv, - .cnt = ARRAY_SIZE(routing_schemegv), -}; - -/* Specific to grabster av400 device */ -static const struct routing_scheme_item routing_schemeav400[] = { - [PVR2_CVAL_INPUT_COMPOSITE] = { - .vid = CX25840_COMPOSITE1, - .aud = CX25840_AUDIO_SERIAL, - }, - [PVR2_CVAL_INPUT_SVIDEO] = { - .vid = (CX25840_SVIDEO_LUMA2|CX25840_SVIDEO_CHROMA4), - .aud = CX25840_AUDIO_SERIAL, - }, -}; - -static const struct routing_scheme routing_defav400 = { - .def = routing_schemeav400, - .cnt = ARRAY_SIZE(routing_schemeav400), -}; - -static const struct routing_scheme *routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, - [PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv, - [PVR2_ROUTING_SCHEME_AV400] = &routing_defav400, -}; - -void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) -{ - pvr2_trace(PVR2_TRACE_CHIPS, "subdev cx2584x update..."); - if (hdw->input_dirty || hdw->force_dirty) { - enum cx25840_video_input vid_input; - enum cx25840_audio_input aud_input; - const struct routing_scheme *sp; - unsigned int sid = hdw->hdw_desc->signal_routing_scheme; - - sp = (sid < ARRAY_SIZE(routing_schemes)) ? - routing_schemes[sid] : NULL; - if ((sp == NULL) || - (hdw->input_val < 0) || - (hdw->input_val >= sp->cnt)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** subdev cx2584x set_input:" - " Invalid routing scheme (%u)" - " and/or input (%d)", - sid, hdw->input_val); - return; - } - vid_input = sp->def[hdw->input_val].vid; - aud_input = sp->def[hdw->input_val].aud; - pvr2_trace(PVR2_TRACE_CHIPS, - "subdev cx2584x set_input vid=0x%x aud=0x%x", - vid_input, aud_input); - sd->ops->video->s_routing(sd, (u32)vid_input, 0, 0); - sd->ops->audio->s_routing(sd, (u32)aud_input, 0, 0); - } -} - - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -#ifndef __PVRUSB2_CX2584X_V4L_H -#define __PVRUSB2_CX2584X_V4L_H - -/* - - This module connects the pvrusb2 driver to the I2C chip level - driver which handles combined device audio & video processing. - This interface is used internally by the driver; higher level code - should only interact through the interface provided by - pvrusb2-hdw.h. - -*/ - - - -#include "pvrusb2-hdw-internal.h" - -void pvr2_cx25840_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd); - - -#endif /* __PVRUSB2_CX2584X_V4L_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_DEBUG_H -#define __PVRUSB2_DEBUG_H - -extern int pvrusb2_debug; - -#define pvr2_trace(msk, fmt, arg...) do {if(msk & pvrusb2_debug) printk(KERN_INFO "pvrusb2: " fmt "\n", ##arg); } while (0) - -/* These are listed in *rough* order of decreasing usefulness and - increasing noise level. */ -#define PVR2_TRACE_INFO (1 << 0) /* Normal messages */ -#define PVR2_TRACE_ERROR_LEGS (1 << 1) /* error messages */ -#define PVR2_TRACE_TOLERANCE (1 << 2) /* track tolerance-affected errors */ -#define PVR2_TRACE_TRAP (1 << 3) /* Trap & report app misbehavior */ -#define PVR2_TRACE_STD (1 << 4) /* Log video standard stuff */ -#define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */ -#define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */ -#define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */ -#define PVR2_TRACE_STATE (1 << 8) /* Device state changes */ -#define PVR2_TRACE_STBITS (1 << 9) /* Individual bit state changes */ -#define PVR2_TRACE_EEPROM (1 << 10) /* eeprom parsing / report */ -#define PVR2_TRACE_STRUCT (1 << 11) /* internal struct creation */ -#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */ -#define PVR2_TRACE_CTXT (1 << 13) /* Main context tracking */ -#define PVR2_TRACE_SYSFS (1 << 14) /* Sysfs driven I/O */ -#define PVR2_TRACE_FIRMWARE (1 << 15) /* firmware upload actions */ -#define PVR2_TRACE_CHIPS (1 << 16) /* chip broadcast operation */ -#define PVR2_TRACE_I2C (1 << 17) /* I2C related stuff */ -#define PVR2_TRACE_I2C_CMD (1 << 18) /* Software commands to I2C modules */ -#define PVR2_TRACE_I2C_CORE (1 << 19) /* I2C core debugging */ -#define PVR2_TRACE_I2C_TRAF (1 << 20) /* I2C traffic through the adapter */ -#define PVR2_TRACE_V4LIOCTL (1 << 21) /* v4l ioctl details */ -#define PVR2_TRACE_ENCODER (1 << 22) /* mpeg2 encoder operation */ -#define PVR2_TRACE_BUF_POOL (1 << 23) /* Track buffer pool management */ -#define PVR2_TRACE_BUF_FLOW (1 << 24) /* Track buffer flow in system */ -#define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */ -#define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */ -#define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */ -#define PVR2_TRACE_DVB_FEED (1 << 28) /* DVB transport feed debug */ - - -#endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,335 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 -#include "pvrusb2-debugifc.h" -#include "pvrusb2-hdw.h" -#include "pvrusb2-debug.h" - -struct debugifc_mask_item { - const char *name; - unsigned long msk; -}; - - -static unsigned int debugifc_count_whitespace(const char *buf, - unsigned int count) -{ - unsigned int scnt; - char ch; - - for (scnt = 0; scnt < count; scnt++) { - ch = buf[scnt]; - if (ch == ' ') continue; - if (ch == '\t') continue; - if (ch == '\n') continue; - break; - } - return scnt; -} - - -static unsigned int debugifc_count_nonwhitespace(const char *buf, - unsigned int count) -{ - unsigned int scnt; - char ch; - - for (scnt = 0; scnt < count; scnt++) { - ch = buf[scnt]; - if (ch == ' ') break; - if (ch == '\t') break; - if (ch == '\n') break; - } - return scnt; -} - - -static unsigned int debugifc_isolate_word(const char *buf,unsigned int count, - const char **wstrPtr, - unsigned int *wlenPtr) -{ - const char *wptr; - unsigned int consume_cnt = 0; - unsigned int wlen; - unsigned int scnt; - - wptr = NULL; - wlen = 0; - scnt = debugifc_count_whitespace(buf,count); - consume_cnt += scnt; count -= scnt; buf += scnt; - if (!count) goto done; - - scnt = debugifc_count_nonwhitespace(buf,count); - if (!scnt) goto done; - wptr = buf; - wlen = scnt; - consume_cnt += scnt; count -= scnt; buf += scnt; - - done: - *wstrPtr = wptr; - *wlenPtr = wlen; - return consume_cnt; -} - - -static int debugifc_parse_unsigned_number(const char *buf,unsigned int count, - u32 *num_ptr) -{ - u32 result = 0; - int radix = 10; - if ((count >= 2) && (buf[0] == '0') && - ((buf[1] == 'x') || (buf[1] == 'X'))) { - radix = 16; - count -= 2; - buf += 2; - } else if ((count >= 1) && (buf[0] == '0')) { - radix = 8; - } - - while (count--) { - int val = hex_to_bin(*buf++); - if (val < 0 || val >= radix) - return -EINVAL; - result *= radix; - result += val; - } - *num_ptr = result; - return 0; -} - - -static int debugifc_match_keyword(const char *buf,unsigned int count, - const char *keyword) -{ - unsigned int kl; - if (!keyword) return 0; - kl = strlen(keyword); - if (kl != count) return 0; - return !memcmp(buf,keyword,kl); -} - - -int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt) -{ - int bcnt = 0; - int ccnt; - ccnt = scnprintf(buf, acnt, "Driver hardware description: %s\n", - pvr2_hdw_get_desc(hdw)); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"Driver state info:\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = pvr2_hdw_state_report(hdw,buf,acnt); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - - return bcnt; -} - - -int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, - char *buf,unsigned int acnt) -{ - int bcnt = 0; - int ccnt; - int ret; - u32 gpio_dir,gpio_in,gpio_out; - struct pvr2_stream_stats stats; - struct pvr2_stream *sp; - - ret = pvr2_hdw_is_hsm(hdw); - ccnt = scnprintf(buf,acnt,"USB link speed: %s\n", - (ret < 0 ? "FAIL" : (ret ? "high" : "full"))); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - - gpio_dir = 0; gpio_in = 0; gpio_out = 0; - pvr2_hdw_gpio_get_dir(hdw,&gpio_dir); - pvr2_hdw_gpio_get_out(hdw,&gpio_out); - pvr2_hdw_gpio_get_in(hdw,&gpio_in); - ccnt = scnprintf(buf,acnt,"GPIO state: dir=0x%x in=0x%x out=0x%x\n", - gpio_dir,gpio_in,gpio_out); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - - ccnt = scnprintf(buf,acnt,"Streaming is %s\n", - pvr2_hdw_get_streaming(hdw) ? "on" : "off"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - - - sp = pvr2_hdw_get_video_stream(hdw); - if (sp) { - pvr2_stream_get_stats(sp, &stats, 0); - ccnt = scnprintf( - buf,acnt, - "Bytes streamed=%u" - " URBs: queued=%u idle=%u ready=%u" - " processed=%u failed=%u\n", - stats.bytes_processed, - stats.buffers_in_queue, - stats.buffers_in_idle, - stats.buffers_in_ready, - stats.buffers_processed, - stats.buffers_failed); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - } - - return bcnt; -} - - -static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, - unsigned int count) -{ - const char *wptr; - unsigned int wlen; - unsigned int scnt; - - scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); - if (!scnt) return 0; - count -= scnt; buf += scnt; - if (!wptr) return 0; - - pvr2_trace(PVR2_TRACE_DEBUGIFC,"debugifc cmd: \"%.*s\"",wlen,wptr); - if (debugifc_match_keyword(wptr,wlen,"reset")) { - scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); - if (!scnt) return -EINVAL; - count -= scnt; buf += scnt; - if (!wptr) return -EINVAL; - if (debugifc_match_keyword(wptr,wlen,"cpu")) { - pvr2_hdw_cpureset_assert(hdw,!0); - pvr2_hdw_cpureset_assert(hdw,0); - return 0; - } else if (debugifc_match_keyword(wptr,wlen,"bus")) { - pvr2_hdw_device_reset(hdw); - } else if (debugifc_match_keyword(wptr,wlen,"soft")) { - return pvr2_hdw_cmd_powerup(hdw); - } else if (debugifc_match_keyword(wptr,wlen,"deep")) { - return pvr2_hdw_cmd_deep_reset(hdw); - } else if (debugifc_match_keyword(wptr,wlen,"firmware")) { - return pvr2_upload_firmware2(hdw); - } else if (debugifc_match_keyword(wptr,wlen,"decoder")) { - return pvr2_hdw_cmd_decoder_reset(hdw); - } else if (debugifc_match_keyword(wptr,wlen,"worker")) { - return pvr2_hdw_untrip(hdw); - } else if (debugifc_match_keyword(wptr,wlen,"usbstats")) { - pvr2_stream_get_stats(pvr2_hdw_get_video_stream(hdw), - NULL, !0); - return 0; - } - return -EINVAL; - } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) { - scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); - if (!scnt) return -EINVAL; - count -= scnt; buf += scnt; - if (!wptr) return -EINVAL; - if (debugifc_match_keyword(wptr,wlen,"fetch")) { - scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); - if (scnt && wptr) { - count -= scnt; buf += scnt; - if (debugifc_match_keyword(wptr, wlen, - "prom")) { - pvr2_hdw_cpufw_set_enabled(hdw, 2, !0); - } else if (debugifc_match_keyword(wptr, wlen, - "ram8k")) { - pvr2_hdw_cpufw_set_enabled(hdw, 0, !0); - } else if (debugifc_match_keyword(wptr, wlen, - "ram16k")) { - pvr2_hdw_cpufw_set_enabled(hdw, 1, !0); - } else { - return -EINVAL; - } - } - pvr2_hdw_cpufw_set_enabled(hdw,0,!0); - return 0; - } else if (debugifc_match_keyword(wptr,wlen,"done")) { - pvr2_hdw_cpufw_set_enabled(hdw,0,0); - return 0; - } else { - return -EINVAL; - } - } else if (debugifc_match_keyword(wptr,wlen,"gpio")) { - int dir_fl = 0; - int ret; - u32 msk,val; - scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); - if (!scnt) return -EINVAL; - count -= scnt; buf += scnt; - if (!wptr) return -EINVAL; - if (debugifc_match_keyword(wptr,wlen,"dir")) { - dir_fl = !0; - } else if (!debugifc_match_keyword(wptr,wlen,"out")) { - return -EINVAL; - } - scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); - if (!scnt) return -EINVAL; - count -= scnt; buf += scnt; - if (!wptr) return -EINVAL; - ret = debugifc_parse_unsigned_number(wptr,wlen,&msk); - if (ret) return ret; - scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); - if (wptr) { - ret = debugifc_parse_unsigned_number(wptr,wlen,&val); - if (ret) return ret; - } else { - val = msk; - msk = 0xffffffff; - } - if (dir_fl) { - ret = pvr2_hdw_gpio_chg_dir(hdw,msk,val); - } else { - ret = pvr2_hdw_gpio_chg_out(hdw,msk,val); - } - return ret; - } - pvr2_trace(PVR2_TRACE_DEBUGIFC, - "debugifc failed to recognize cmd: \"%.*s\"",wlen,wptr); - return -EINVAL; -} - - -int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf, - unsigned int count) -{ - unsigned int bcnt = 0; - int ret; - - while (count) { - for (bcnt = 0; bcnt < count; bcnt++) { - if (buf[bcnt] == '\n') break; - } - - ret = pvr2_debugifc_do1cmd(hdw,buf,bcnt); - if (ret < 0) return ret; - if (bcnt < count) bcnt++; - buf += bcnt; - count -= bcnt; - } - - return 0; -} - - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_DEBUGIFC_H -#define __PVRUSB2_DEBUGIFC_H - -struct pvr2_hdw; - -/* Print general status of driver. This will also trigger a probe of - the USB link. Unlike print_info(), this one synchronizes with the - driver so the information should be self-consistent (but it will - hang if the driver is wedged). */ -int pvr2_debugifc_print_info(struct pvr2_hdw *, - char *buf_ptr, unsigned int buf_size); - -/* Non-intrusively print some useful debugging info from inside the - driver. This should work even if the driver appears to be - wedged. */ -int pvr2_debugifc_print_status(struct pvr2_hdw *, - char *buf_ptr,unsigned int buf_size); - -/* Parse a string command into a driver action. */ -int pvr2_debugifc_docmd(struct pvr2_hdw *, - const char *buf_ptr,unsigned int buf_size); - -#endif /* __PVRUSB2_DEBUGIFC_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,558 +0,0 @@ -/* - * - * - * Copyright (C) 2007 Mike Isely - * - * 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 - * - */ - -/* - -This source file should encompass ALL per-device type information for the -driver. To define a new device, add elements to the pvr2_device_table and -pvr2_device_desc structures. - -*/ - -#include "pvrusb2-devattr.h" -#include -/* This is needed in order to pull in tuner type ids... */ -#include -#include -#ifdef CONFIG_VIDEO_PVRUSB2_DVB -#include "pvrusb2-hdw-internal.h" -#include "lgdt330x.h" -#include "s5h1409.h" -#include "s5h1411.h" -#include "tda10048.h" -#include "tda18271.h" -#include "tda8290.h" -#include "tuner-simple.h" -#endif - - -/*------------------------------------------------------------------------*/ -/* Hauppauge PVR-USB2 Model 29xxx */ - -static const struct pvr2_device_client_desc pvr2_cli_29xxx[] = { - { .module_id = PVR2_CLIENT_ID_SAA7115 }, - { .module_id = PVR2_CLIENT_ID_MSP3400 }, - { .module_id = PVR2_CLIENT_ID_TUNER }, - { .module_id = PVR2_CLIENT_ID_DEMOD }, -}; - -static const char *pvr2_fw1_names_29xxx[] = { - "v4l-pvrusb2-29xxx-01.fw", -}; - -static const struct pvr2_device_desc pvr2_device_29xxx = { - .description = "WinTV PVR USB2 Model 29xxx", - .shortname = "29xxx", - .client_table.lst = pvr2_cli_29xxx, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_29xxx), - .fx2_firmware.lst = pvr2_fw1_names_29xxx, - .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx), - .flag_has_hauppauge_rom = !0, - .flag_has_analogtuner = !0, - .flag_has_fmradio = !0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, - .ir_scheme = PVR2_IR_SCHEME_29XXX, -}; - - - -/*------------------------------------------------------------------------*/ -/* Hauppauge PVR-USB2 Model 24xxx */ - -static const struct pvr2_device_client_desc pvr2_cli_24xxx[] = { - { .module_id = PVR2_CLIENT_ID_CX25840 }, - { .module_id = PVR2_CLIENT_ID_TUNER }, - { .module_id = PVR2_CLIENT_ID_WM8775 }, - { .module_id = PVR2_CLIENT_ID_DEMOD }, -}; - -static const char *pvr2_fw1_names_24xxx[] = { - "v4l-pvrusb2-24xxx-01.fw", -}; - -static const struct pvr2_device_desc pvr2_device_24xxx = { - .description = "WinTV PVR USB2 Model 24xxx", - .shortname = "24xxx", - .client_table.lst = pvr2_cli_24xxx, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_24xxx), - .fx2_firmware.lst = pvr2_fw1_names_24xxx, - .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx), - .flag_has_cx25840 = !0, - .flag_has_wm8775 = !0, - .flag_has_hauppauge_rom = !0, - .flag_has_analogtuner = !0, - .flag_has_fmradio = !0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, - .ir_scheme = PVR2_IR_SCHEME_24XXX, -}; - - - -/*------------------------------------------------------------------------*/ -/* GOTVIEW USB2.0 DVD2 */ - -static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = { - { .module_id = PVR2_CLIENT_ID_CX25840 }, - { .module_id = PVR2_CLIENT_ID_TUNER }, - { .module_id = PVR2_CLIENT_ID_DEMOD }, -}; - -static const struct pvr2_device_desc pvr2_device_gotview_2 = { - .description = "Gotview USB 2.0 DVD 2", - .shortname = "gv2", - .client_table.lst = pvr2_cli_gotview_2, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2), - .flag_has_cx25840 = !0, - .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .flag_has_analogtuner = !0, - .flag_has_fmradio = !0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW, -}; - - - -/*------------------------------------------------------------------------*/ -/* GOTVIEW USB2.0 DVD Deluxe */ - -/* (same module list as gotview_2) */ - -static const struct pvr2_device_desc pvr2_device_gotview_2d = { - .description = "Gotview USB 2.0 DVD Deluxe", - .shortname = "gv2d", - .client_table.lst = pvr2_cli_gotview_2, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_gotview_2), - .flag_has_cx25840 = !0, - .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .flag_has_analogtuner = !0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW, -}; - - - -/*------------------------------------------------------------------------*/ -/* Terratec Grabster AV400 */ - -static const struct pvr2_device_client_desc pvr2_cli_av400[] = { - { .module_id = PVR2_CLIENT_ID_CX25840 }, -}; - -static const struct pvr2_device_desc pvr2_device_av400 = { - .description = "Terratec Grabster AV400", - .shortname = "av400", - .flag_is_experimental = 1, - .client_table.lst = pvr2_cli_av400, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_av400), - .flag_has_cx25840 = !0, - .flag_has_analogtuner = 0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_AV400, -}; - - - -/*------------------------------------------------------------------------*/ -/* OnAir Creator */ - -#ifdef CONFIG_VIDEO_PVRUSB2_DVB -static struct lgdt330x_config pvr2_lgdt3303_config = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, - .clock_polarity_flip = 1, -}; - -static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap) -{ - adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) - return 0; - - return -EIO; -} - -static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap) -{ - dvb_attach(simple_tuner_attach, adap->fe, - &adap->channel.hdw->i2c_adap, 0x61, - TUNER_LG_TDVS_H06XF); - - return 0; -} - -static const struct pvr2_dvb_props pvr2_onair_creator_fe_props = { - .frontend_attach = pvr2_lgdt3303_attach, - .tuner_attach = pvr2_lgh06xf_attach, -}; -#endif - -static const struct pvr2_device_client_desc pvr2_cli_onair_creator[] = { - { .module_id = PVR2_CLIENT_ID_SAA7115 }, - { .module_id = PVR2_CLIENT_ID_CS53L32A }, - { .module_id = PVR2_CLIENT_ID_TUNER }, -}; - -static const struct pvr2_device_desc pvr2_device_onair_creator = { - .description = "OnAir Creator Hybrid USB tuner", - .shortname = "oac", - .client_table.lst = pvr2_cli_onair_creator, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_creator), - .default_tuner_type = TUNER_LG_TDVS_H06XF, - .flag_has_analogtuner = !0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .flag_digital_requires_cx23416 = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR, - .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR, - .default_std_mask = V4L2_STD_NTSC_M, -#ifdef CONFIG_VIDEO_PVRUSB2_DVB - .dvb_props = &pvr2_onair_creator_fe_props, -#endif -}; - - - -/*------------------------------------------------------------------------*/ -/* OnAir USB 2.0 */ - -#ifdef CONFIG_VIDEO_PVRUSB2_DVB -static struct lgdt330x_config pvr2_lgdt3302_config = { - .demod_address = 0x0e, - .demod_chip = LGDT3302, -}; - -static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap) -{ - adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) - return 0; - - return -EIO; -} - -static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap) -{ - dvb_attach(simple_tuner_attach, adap->fe, - &adap->channel.hdw->i2c_adap, 0x61, - TUNER_PHILIPS_FCV1236D); - - return 0; -} - -static const struct pvr2_dvb_props pvr2_onair_usb2_fe_props = { - .frontend_attach = pvr2_lgdt3302_attach, - .tuner_attach = pvr2_fcv1236d_attach, -}; -#endif - -static const struct pvr2_device_client_desc pvr2_cli_onair_usb2[] = { - { .module_id = PVR2_CLIENT_ID_SAA7115 }, - { .module_id = PVR2_CLIENT_ID_CS53L32A }, - { .module_id = PVR2_CLIENT_ID_TUNER }, -}; - -static const struct pvr2_device_desc pvr2_device_onair_usb2 = { - .description = "OnAir USB2 Hybrid USB tuner", - .shortname = "oa2", - .client_table.lst = pvr2_cli_onair_usb2, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_onair_usb2), - .default_tuner_type = TUNER_PHILIPS_FCV1236D, - .flag_has_analogtuner = !0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .flag_digital_requires_cx23416 = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_ONAIR, - .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR, - .default_std_mask = V4L2_STD_NTSC_M, -#ifdef CONFIG_VIDEO_PVRUSB2_DVB - .dvb_props = &pvr2_onair_usb2_fe_props, -#endif -}; - - - -/*------------------------------------------------------------------------*/ -/* Hauppauge PVR-USB2 Model 73xxx */ - -#ifdef CONFIG_VIDEO_PVRUSB2_DVB -static struct tda10048_config hauppauge_tda10048_config = { - .demod_address = 0x10 >> 1, - .output_mode = TDA10048_PARALLEL_OUTPUT, - .fwbulkwritelen = TDA10048_BULKWRITE_50, - .inversion = TDA10048_INVERSION_ON, - .dtv6_if_freq_khz = TDA10048_IF_3300, - .dtv7_if_freq_khz = TDA10048_IF_3800, - .dtv8_if_freq_khz = TDA10048_IF_4300, - .clk_freq_khz = TDA10048_CLK_16000, - .disable_gate_access = 1, -}; - -static struct tda829x_config tda829x_no_probe = { - .probe_tuner = TDA829X_DONT_PROBE, -}; - -static struct tda18271_config hauppauge_tda18271_dvb_config = { - .gate = TDA18271_GATE_ANALOG, - .output_opt = TDA18271_OUTPUT_LT_OFF, -}; - -static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap) -{ - adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) - return 0; - - return -EIO; -} - -static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) -{ - dvb_attach(tda829x_attach, adap->fe, - &adap->channel.hdw->i2c_adap, 0x42, - &tda829x_no_probe); - dvb_attach(tda18271_attach, adap->fe, 0x60, - &adap->channel.hdw->i2c_adap, - &hauppauge_tda18271_dvb_config); - - return 0; -} - -static const struct pvr2_dvb_props pvr2_73xxx_dvb_props = { - .frontend_attach = pvr2_tda10048_attach, - .tuner_attach = pvr2_73xxx_tda18271_8295_attach, -}; -#endif - -static const struct pvr2_device_client_desc pvr2_cli_73xxx[] = { - { .module_id = PVR2_CLIENT_ID_CX25840 }, - { .module_id = PVR2_CLIENT_ID_TUNER, - .i2c_address_list = "\x42"}, -}; - -static const char *pvr2_fw1_names_73xxx[] = { - "v4l-pvrusb2-73xxx-01.fw", -}; - -static const struct pvr2_device_desc pvr2_device_73xxx = { - .description = "WinTV HVR-1900 Model 73xxx", - .shortname = "73xxx", - .client_table.lst = pvr2_cli_73xxx, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx), - .fx2_firmware.lst = pvr2_fw1_names_73xxx, - .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_73xxx), - .flag_has_cx25840 = !0, - .flag_has_hauppauge_rom = !0, - .flag_has_analogtuner = !0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .flag_fx2_16kb = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, - .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, - .ir_scheme = PVR2_IR_SCHEME_ZILOG, -#ifdef CONFIG_VIDEO_PVRUSB2_DVB - .dvb_props = &pvr2_73xxx_dvb_props, -#endif -}; - - - -/*------------------------------------------------------------------------*/ -/* Hauppauge PVR-USB2 Model 75xxx */ - -#ifdef CONFIG_VIDEO_PVRUSB2_DVB -static struct s5h1409_config pvr2_s5h1409_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_PARALLEL_OUTPUT, - .gpio = S5H1409_GPIO_OFF, - .qam_if = 4000, - .inversion = S5H1409_INVERSION_ON, - .status_mode = S5H1409_DEMODLOCKING, -}; - -static struct s5h1411_config pvr2_s5h1411_config = { - .output_mode = S5H1411_PARALLEL_OUTPUT, - .gpio = S5H1411_GPIO_OFF, - .vsb_if = S5H1411_IF_44000, - .qam_if = S5H1411_IF_4000, - .inversion = S5H1411_INVERSION_ON, - .status_mode = S5H1411_DEMODLOCKING, -}; - -static struct tda18271_std_map hauppauge_tda18271_std_map = { - .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, - .if_lvl = 6, .rfagc_top = 0x37, }, - .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, - .if_lvl = 6, .rfagc_top = 0x37, }, -}; - -static struct tda18271_config hauppauge_tda18271_config = { - .std_map = &hauppauge_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, - .output_opt = TDA18271_OUTPUT_LT_OFF, -}; - -static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap) -{ - adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) - return 0; - - return -EIO; -} - -static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap) -{ - adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) - return 0; - - return -EIO; -} - -static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) -{ - dvb_attach(tda829x_attach, adap->fe, - &adap->channel.hdw->i2c_adap, 0x42, - &tda829x_no_probe); - dvb_attach(tda18271_attach, adap->fe, 0x60, - &adap->channel.hdw->i2c_adap, - &hauppauge_tda18271_config); - - return 0; -} - -static const struct pvr2_dvb_props pvr2_750xx_dvb_props = { - .frontend_attach = pvr2_s5h1409_attach, - .tuner_attach = pvr2_tda18271_8295_attach, -}; - -static const struct pvr2_dvb_props pvr2_751xx_dvb_props = { - .frontend_attach = pvr2_s5h1411_attach, - .tuner_attach = pvr2_tda18271_8295_attach, -}; -#endif - -static const char *pvr2_fw1_names_75xxx[] = { - "v4l-pvrusb2-73xxx-01.fw", -}; - -static const struct pvr2_device_desc pvr2_device_750xx = { - .description = "WinTV HVR-1950 Model 750xx", - .shortname = "750xx", - .client_table.lst = pvr2_cli_73xxx, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx), - .fx2_firmware.lst = pvr2_fw1_names_75xxx, - .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx), - .flag_has_cx25840 = !0, - .flag_has_hauppauge_rom = !0, - .flag_has_analogtuner = !0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .flag_fx2_16kb = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, - .default_std_mask = V4L2_STD_NTSC_M, - .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, - .ir_scheme = PVR2_IR_SCHEME_ZILOG, -#ifdef CONFIG_VIDEO_PVRUSB2_DVB - .dvb_props = &pvr2_750xx_dvb_props, -#endif -}; - -static const struct pvr2_device_desc pvr2_device_751xx = { - .description = "WinTV HVR-1950 Model 751xx", - .shortname = "751xx", - .client_table.lst = pvr2_cli_73xxx, - .client_table.cnt = ARRAY_SIZE(pvr2_cli_73xxx), - .fx2_firmware.lst = pvr2_fw1_names_75xxx, - .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx), - .flag_has_cx25840 = !0, - .flag_has_hauppauge_rom = !0, - .flag_has_analogtuner = !0, - .flag_has_composite = !0, - .flag_has_svideo = !0, - .flag_fx2_16kb = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, - .default_std_mask = V4L2_STD_NTSC_M, - .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, - .ir_scheme = PVR2_IR_SCHEME_ZILOG, -#ifdef CONFIG_VIDEO_PVRUSB2_DVB - .dvb_props = &pvr2_751xx_dvb_props, -#endif -}; - - - -/*------------------------------------------------------------------------*/ - -struct usb_device_id pvr2_device_table[] = { - { USB_DEVICE(0x2040, 0x2900), - .driver_info = (kernel_ulong_t)&pvr2_device_29xxx}, - { USB_DEVICE(0x2040, 0x2950), /* Logically identical to 2900 */ - .driver_info = (kernel_ulong_t)&pvr2_device_29xxx}, - { USB_DEVICE(0x2040, 0x2400), - .driver_info = (kernel_ulong_t)&pvr2_device_24xxx}, - { USB_DEVICE(0x1164, 0x0622), - .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2}, - { USB_DEVICE(0x1164, 0x0602), - .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d}, - { USB_DEVICE(0x11ba, 0x1003), - .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator}, - { USB_DEVICE(0x11ba, 0x1001), - .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2}, - { USB_DEVICE(0x2040, 0x7300), - .driver_info = (kernel_ulong_t)&pvr2_device_73xxx}, - { USB_DEVICE(0x2040, 0x7500), - .driver_info = (kernel_ulong_t)&pvr2_device_750xx}, - { USB_DEVICE(0x2040, 0x7501), - .driver_info = (kernel_ulong_t)&pvr2_device_751xx}, - { USB_DEVICE(0x0ccd, 0x0039), - .driver_info = (kernel_ulong_t)&pvr2_device_av400}, - { } -}; - -MODULE_DEVICE_TABLE(usb, pvr2_device_table); - - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,199 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_DEVATTR_H -#define __PVRUSB2_DEVATTR_H - -#include -#include -#ifdef CONFIG_VIDEO_PVRUSB2_DVB -#include "pvrusb2-dvb.h" -#endif - -/* - - This header defines structures used to describe attributes of a device. - -*/ - - -#define PVR2_CLIENT_ID_NULL 0 -#define PVR2_CLIENT_ID_MSP3400 1 -#define PVR2_CLIENT_ID_CX25840 2 -#define PVR2_CLIENT_ID_SAA7115 3 -#define PVR2_CLIENT_ID_TUNER 4 -#define PVR2_CLIENT_ID_CS53L32A 5 -#define PVR2_CLIENT_ID_WM8775 6 -#define PVR2_CLIENT_ID_DEMOD 7 - -struct pvr2_device_client_desc { - /* One ovr PVR2_CLIENT_ID_xxxx */ - unsigned char module_id; - - /* Null-terminated array of I2C addresses to try in order - initialize the module. It's safe to make this null terminated - since we're never going to encounter an i2c device with an - address of zero. If this is a null pointer or zero-length, - then no I2C addresses have been specified, in which case we'll - try some compiled in defaults for now. */ - unsigned char *i2c_address_list; -}; - -struct pvr2_device_client_table { - const struct pvr2_device_client_desc *lst; - unsigned char cnt; -}; - - -struct pvr2_string_table { - const char **lst; - unsigned int cnt; -}; - -#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0 -#define PVR2_ROUTING_SCHEME_GOTVIEW 1 -#define PVR2_ROUTING_SCHEME_ONAIR 2 -#define PVR2_ROUTING_SCHEME_AV400 3 - -#define PVR2_DIGITAL_SCHEME_NONE 0 -#define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1 -#define PVR2_DIGITAL_SCHEME_ONAIR 2 - -#define PVR2_LED_SCHEME_NONE 0 -#define PVR2_LED_SCHEME_HAUPPAUGE 1 - -#define PVR2_IR_SCHEME_NONE 0 -#define PVR2_IR_SCHEME_24XXX 1 /* FX2-controlled IR */ -#define PVR2_IR_SCHEME_ZILOG 2 /* HVR-1950 style (must be taken out of reset) */ -#define PVR2_IR_SCHEME_24XXX_MCE 3 /* 24xxx MCE device */ -#define PVR2_IR_SCHEME_29XXX 4 /* Original 29xxx device */ - -/* This describes a particular hardware type (except for the USB device ID - which must live in a separate structure due to environmental - constraints). See the top of pvrusb2-hdw.c for where this is - instantiated. */ -struct pvr2_device_desc { - /* Single line text description of hardware */ - const char *description; - - /* Single token identifier for hardware */ - const char *shortname; - - /* List of additional client modules we need to load */ - struct pvr2_string_table client_modules; - - /* List of defined client modules we need to load */ - struct pvr2_device_client_table client_table; - - /* List of FX2 firmware file names we should search; if empty then - FX2 firmware check / load is skipped and we assume the device - was initialized from internal ROM. */ - struct pvr2_string_table fx2_firmware; - -#ifdef CONFIG_VIDEO_PVRUSB2_DVB - /* callback functions to handle attachment of digital tuner & demod */ - const struct pvr2_dvb_props *dvb_props; - -#endif - /* Initial standard bits to use for this device, if not zero. - Anything set here is also implied as an available standard. - Note: This is ignored if overridden on the module load line via - the video_std module option. */ - v4l2_std_id default_std_mask; - - /* V4L tuner type ID to use with this device (only used if the - driver could not discover the type any other way). */ - int default_tuner_type; - - /* Signal routing scheme used by device, contains one of - PVR2_ROUTING_SCHEME_XXX. Schemes have to be defined as we - encounter them. This is an arbitrary integer scheme id; its - meaning is contained entirely within the driver and is - interpreted by logic which must send commands to the chip-level - drivers (search for things which touch this field). */ - unsigned char signal_routing_scheme; - - /* Indicates scheme for controlling device's LED (if any). The - driver will turn on the LED when streaming is underway. This - contains one of PVR2_LED_SCHEME_XXX. */ - unsigned char led_scheme; - - /* Control scheme to use if there is a digital tuner. This - contains one of PVR2_DIGITAL_SCHEME_XXX. This is an arbitrary - integer scheme id; its meaning is contained entirely within the - driver and is interpreted by logic which must control the - streaming pathway (search for things which touch this field). */ - unsigned char digital_control_scheme; - - /* If set, we don't bother trying to load cx23416 firmware. */ - unsigned int flag_skip_cx23416_firmware:1; - - /* If set, the encoder must be healthy in order for digital mode to - work (otherwise we assume that digital streaming will work even - if we fail to locate firmware for the encoder). If the device - doesn't support digital streaming then this flag has no - effect. */ - unsigned int flag_digital_requires_cx23416:1; - - /* Device has a hauppauge eeprom which we can interrogate. */ - unsigned int flag_has_hauppauge_rom:1; - - /* Device does not require a powerup command to be issued. */ - unsigned int flag_no_powerup:1; - - /* Device has a cx25840 - this enables special additional logic to - handle it. */ - unsigned int flag_has_cx25840:1; - - /* Device has a wm8775 - this enables special additional logic to - ensure that it is found. */ - unsigned int flag_has_wm8775:1; - - /* Indicate IR scheme of hardware. If not set, then it is assumed - that IR can work without any help from the driver. */ - unsigned int ir_scheme:3; - - /* These bits define which kinds of sources the device can handle. - Note: Digital tuner presence is inferred by the - digital_control_scheme enumeration. */ - unsigned int flag_has_fmradio:1; /* Has FM radio receiver */ - unsigned int flag_has_analogtuner:1; /* Has analog tuner */ - unsigned int flag_has_composite:1; /* Has composite input */ - unsigned int flag_has_svideo:1; /* Has s-video input */ - unsigned int flag_fx2_16kb:1; /* 16KB FX2 firmware OK here */ - - /* If this driver is considered experimental, i.e. not all aspects - are working correctly and/or it is untested, mark that fact - with this flag. */ - unsigned int flag_is_experimental:1; -}; - -extern struct usb_device_id pvr2_device_table[]; - -#endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,435 +0,0 @@ -/* - * pvrusb2-dvb.c - linux-dvb api interface to the pvrusb2 driver. - * - * Copyright (C) 2007, 2008 Michael Krufky - * - * 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 -#include -#include -#include -#include "dvbdev.h" -#include "pvrusb2-debug.h" -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-hdw.h" -#include "pvrusb2-io.h" -#include "pvrusb2-dvb.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) -{ - int ret; - unsigned int count; - struct pvr2_buffer *bp; - struct pvr2_stream *stream; - - pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread started"); - set_freezable(); - - stream = adap->channel.stream->stream; - - for (;;) { - if (kthread_should_stop()) break; - - /* Not sure about this... */ - try_to_freeze(); - - bp = pvr2_stream_get_ready_buffer(stream); - if (bp != NULL) { - count = pvr2_buffer_get_count(bp); - if (count) { - dvb_dmx_swfilter( - &adap->demux, - adap->buffer_storage[ - pvr2_buffer_get_id(bp)], - count); - } else { - ret = pvr2_buffer_get_status(bp); - if (ret < 0) break; - } - ret = pvr2_buffer_queue(bp); - if (ret < 0) break; - - /* Since we know we did something to a buffer, - just go back and try again. No point in - blocking unless we really ran out of - buffers to process. */ - continue; - } - - - /* Wait until more buffers become available or we're - told not to wait any longer. */ - ret = wait_event_interruptible( - adap->buffer_wait_data, - (pvr2_stream_get_ready_count(stream) > 0) || - kthread_should_stop()); - if (ret < 0) break; - } - - /* If we get here and ret is < 0, then an error has occurred. - Probably would be a good idea to communicate that to DVB core... */ - - pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread stopped"); - - return 0; -} - -static int pvr2_dvb_feed_thread(void *data) -{ - int stat = pvr2_dvb_feed_func(data); - /* from videobuf-dvb.c: */ - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - return stat; -} - -static void pvr2_dvb_notify(struct pvr2_dvb_adapter *adap) -{ - wake_up(&adap->buffer_wait_data); -} - -static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap) -{ - unsigned int idx; - struct pvr2_stream *stream; - - if (adap->thread) { - kthread_stop(adap->thread); - adap->thread = NULL; - } - - if (adap->channel.stream) { - stream = adap->channel.stream->stream; - } else { - stream = NULL; - } - if (stream) { - pvr2_hdw_set_streaming(adap->channel.hdw, 0); - pvr2_stream_set_callback(stream, NULL, NULL); - pvr2_stream_kill(stream); - pvr2_stream_set_buffer_count(stream, 0); - pvr2_channel_claim_stream(&adap->channel, NULL); - } - - if (adap->stream_run) { - for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { - if (!(adap->buffer_storage[idx])) continue; - kfree(adap->buffer_storage[idx]); - adap->buffer_storage[idx] = NULL; - } - adap->stream_run = 0; - } -} - -static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) -{ - struct pvr2_context *pvr = adap->channel.mc_head; - unsigned int idx; - int ret; - struct pvr2_buffer *bp; - struct pvr2_stream *stream = NULL; - - if (adap->stream_run) return -EIO; - - ret = pvr2_channel_claim_stream(&adap->channel, &pvr->video_stream); - /* somebody else already has the stream */ - if (ret < 0) return ret; - - stream = adap->channel.stream->stream; - - for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { - adap->buffer_storage[idx] = kmalloc(PVR2_DVB_BUFFER_SIZE, - GFP_KERNEL); - if (!(adap->buffer_storage[idx])) return -ENOMEM; - } - - pvr2_stream_set_callback(pvr->video_stream.stream, - (pvr2_stream_callback) pvr2_dvb_notify, adap); - - ret = pvr2_stream_set_buffer_count(stream, PVR2_DVB_BUFFER_COUNT); - if (ret < 0) return ret; - - for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { - bp = pvr2_stream_get_buffer(stream, idx); - pvr2_buffer_set_buffer(bp, - adap->buffer_storage[idx], - PVR2_DVB_BUFFER_SIZE); - } - - ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1); - if (ret < 0) return ret; - - while ((bp = pvr2_stream_get_idle_buffer(stream)) != NULL) { - ret = pvr2_buffer_queue(bp); - if (ret < 0) return ret; - } - - adap->thread = kthread_run(pvr2_dvb_feed_thread, adap, "pvrusb2-dvb"); - - if (IS_ERR(adap->thread)) { - ret = PTR_ERR(adap->thread); - adap->thread = NULL; - return ret; - } - - adap->stream_run = !0; - - return 0; -} - -static int pvr2_dvb_stream_start(struct pvr2_dvb_adapter *adap) -{ - int ret = pvr2_dvb_stream_do_start(adap); - if (ret < 0) pvr2_dvb_stream_end(adap); - return ret; -} - -static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) -{ - struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv; - int ret = 0; - - if (adap == NULL) return -ENODEV; - - mutex_lock(&adap->lock); - do { - if (onoff) { - if (!adap->feedcount) { - pvr2_trace(PVR2_TRACE_DVB_FEED, - "start feeding demux"); - ret = pvr2_dvb_stream_start(adap); - if (ret < 0) break; - } - (adap->feedcount)++; - } else if (adap->feedcount > 0) { - (adap->feedcount)--; - if (!adap->feedcount) { - pvr2_trace(PVR2_TRACE_DVB_FEED, - "stop feeding demux"); - pvr2_dvb_stream_end(adap); - } - } - } while (0); - mutex_unlock(&adap->lock); - - return ret; -} - -static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - pvr2_trace(PVR2_TRACE_DVB_FEED, "start pid: 0x%04x", dvbdmxfeed->pid); - return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1); -} - -static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - pvr2_trace(PVR2_TRACE_DVB_FEED, "stop pid: 0x%04x", dvbdmxfeed->pid); - return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0); -} - -static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct pvr2_dvb_adapter *adap = fe->dvb->priv; - return pvr2_channel_limit_inputs( - &adap->channel, - (acquire ? (1 << PVR2_CVAL_INPUT_DTV) : 0)); -} - -static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) -{ - int ret; - - ret = dvb_register_adapter(&adap->dvb_adap, "pvrusb2-dvb", - THIS_MODULE/*&hdw->usb_dev->owner*/, - &adap->channel.hdw->usb_dev->dev, - adapter_nr); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "dvb_register_adapter failed: error %d", ret); - goto err; - } - adap->dvb_adap.priv = adap; - - adap->demux.dmx.capabilities = DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - adap->demux.priv = adap; - adap->demux.filternum = 256; - adap->demux.feednum = 256; - adap->demux.start_feed = pvr2_dvb_start_feed; - adap->demux.stop_feed = pvr2_dvb_stop_feed; - adap->demux.write_to_decoder = NULL; - - ret = dvb_dmx_init(&adap->demux); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "dvb_dmx_init failed: error %d", ret); - goto err_dmx; - } - - adap->dmxdev.filternum = adap->demux.filternum; - adap->dmxdev.demux = &adap->demux.dmx; - adap->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "dvb_dmxdev_init failed: error %d", ret); - goto err_dmx_dev; - } - - dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); - - return 0; - -err_dmx_dev: - dvb_dmx_release(&adap->demux); -err_dmx: - dvb_unregister_adapter(&adap->dvb_adap); -err: - return ret; -} - -static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap) -{ - pvr2_trace(PVR2_TRACE_INFO, "unregistering DVB devices"); - dvb_net_release(&adap->dvb_net); - adap->demux.dmx.close(&adap->demux.dmx); - dvb_dmxdev_release(&adap->dmxdev); - dvb_dmx_release(&adap->demux); - dvb_unregister_adapter(&adap->dvb_adap); - return 0; -} - -static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) -{ - struct pvr2_hdw *hdw = adap->channel.hdw; - const struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props; - int ret = 0; - - if (dvb_props == NULL) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, "fe_props not defined!"); - return -EINVAL; - } - - ret = pvr2_channel_limit_inputs( - &adap->channel, - (1 << PVR2_CVAL_INPUT_DTV)); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "failed to grab control of dtv input (code=%d)", - ret); - return ret; - } - - if (dvb_props->frontend_attach == NULL) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "frontend_attach not defined!"); - ret = -EINVAL; - goto done; - } - - if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { - - if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "frontend registration failed!"); - dvb_frontend_detach(adap->fe); - adap->fe = NULL; - ret = -ENODEV; - goto done; - } - - if (dvb_props->tuner_attach) - dvb_props->tuner_attach(adap); - - if (adap->fe->ops.analog_ops.standby) - adap->fe->ops.analog_ops.standby(adap->fe); - - /* Ensure all frontends negotiate bus access */ - adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; - - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "no frontend was attached!"); - ret = -ENODEV; - return ret; - } - - done: - pvr2_channel_limit_inputs(&adap->channel, 0); - return ret; -} - -static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) -{ - if (adap->fe != NULL) { - dvb_unregister_frontend(adap->fe); - dvb_frontend_detach(adap->fe); - } - return 0; -} - -static void pvr2_dvb_destroy(struct pvr2_dvb_adapter *adap) -{ - pvr2_dvb_stream_end(adap); - pvr2_dvb_frontend_exit(adap); - pvr2_dvb_adapter_exit(adap); - pvr2_channel_done(&adap->channel); - kfree(adap); -} - -static void pvr2_dvb_internal_check(struct pvr2_channel *chp) -{ - struct pvr2_dvb_adapter *adap; - adap = container_of(chp, struct pvr2_dvb_adapter, channel); - if (!adap->channel.mc_head->disconnect_flag) return; - pvr2_dvb_destroy(adap); -} - -struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr) -{ - int ret = 0; - struct pvr2_dvb_adapter *adap; - if (!pvr->hdw->hdw_desc->dvb_props) { - /* Device lacks a digital interface so don't set up - the DVB side of the driver either. For now. */ - return NULL; - } - adap = kzalloc(sizeof(*adap), GFP_KERNEL); - if (!adap) return adap; - pvr2_channel_init(&adap->channel, pvr); - adap->channel.check_func = pvr2_dvb_internal_check; - init_waitqueue_head(&adap->buffer_wait_data); - mutex_init(&adap->lock); - ret = pvr2_dvb_adapter_init(adap); - if (ret < 0) goto fail1; - ret = pvr2_dvb_frontend_init(adap); - if (ret < 0) goto fail2; - return adap; - -fail2: - pvr2_dvb_adapter_exit(adap); -fail1: - pvr2_channel_done(&adap->channel); - return NULL; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#ifndef __PVRUSB2_DVB_H__ -#define __PVRUSB2_DVB_H__ - -#include "dvb_frontend.h" -#include "dvb_demux.h" -#include "dvb_net.h" -#include "dmxdev.h" -#include "pvrusb2-context.h" - -#define PVR2_DVB_BUFFER_COUNT 32 -#define PVR2_DVB_BUFFER_SIZE PAGE_ALIGN(0x4000) - -struct pvr2_dvb_adapter { - struct pvr2_channel channel; - - struct dvb_adapter dvb_adap; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvb_net; - struct dvb_frontend *fe; - - int feedcount; - int max_feed_count; - - struct task_struct *thread; - struct mutex lock; - - unsigned int stream_run:1; - - wait_queue_head_t buffer_wait_data; - char *buffer_storage[PVR2_DVB_BUFFER_COUNT]; -}; - -struct pvr2_dvb_props { - int (*frontend_attach) (struct pvr2_dvb_adapter *); - int (*tuner_attach) (struct pvr2_dvb_adapter *); -}; - -struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr); - -#endif /* __PVRUSB2_DVB_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,164 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 -#include "pvrusb2-eeprom.h" -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-debug.h" - -#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__) - - - -/* - - Read and analyze data in the eeprom. Use tveeprom to figure out - the packet structure, since this is another Hauppauge device and - internally it has a family resemblence to ivtv-type devices - -*/ - -#include - -/* We seem to only be interested in the last 128 bytes of the EEPROM */ -#define EEPROM_SIZE 128 - -/* Grab EEPROM contents, needed for direct method. */ -static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw) -{ - struct i2c_msg msg[2]; - u8 *eeprom; - u8 iadd[2]; - u8 addr; - u16 eepromSize; - unsigned int offs; - int ret; - int mode16 = 0; - unsigned pcnt,tcnt; - eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); - if (!eeprom) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to allocate memory" - " required to read eeprom"); - return NULL; - } - - trace_eeprom("Value for eeprom addr from controller was 0x%x", - hdw->eeprom_addr); - addr = hdw->eeprom_addr; - /* Seems that if the high bit is set, then the *real* eeprom - address is shifted right now bit position (noticed this in - newer PVR USB2 hardware) */ - if (addr & 0x80) addr >>= 1; - - /* FX2 documentation states that a 16bit-addressed eeprom is - expected if the I2C address is an odd number (yeah, this is - strange but it's what they do) */ - mode16 = (addr & 1); - eepromSize = (mode16 ? 4096 : 256); - trace_eeprom("Examining %d byte eeprom at location 0x%x" - " using %d bit addressing",eepromSize,addr, - mode16 ? 16 : 8); - - msg[0].addr = addr; - msg[0].flags = 0; - msg[0].len = mode16 ? 2 : 1; - msg[0].buf = iadd; - msg[1].addr = addr; - msg[1].flags = I2C_M_RD; - - /* We have to do the actual eeprom data fetch ourselves, because - (1) we're only fetching part of the eeprom, and (2) if we were - getting the whole thing our I2C driver can't grab it in one - pass - which is what tveeprom is otherwise going to attempt */ - memset(eeprom,0,EEPROM_SIZE); - for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { - pcnt = 16; - if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; - offs = tcnt + (eepromSize - EEPROM_SIZE); - if (mode16) { - iadd[0] = offs >> 8; - iadd[1] = offs; - } else { - iadd[0] = offs; - } - msg[1].len = pcnt; - msg[1].buf = eeprom+tcnt; - if ((ret = i2c_transfer(&hdw->i2c_adap, - msg,ARRAY_SIZE(msg))) != 2) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "eeprom fetch set offs err=%d",ret); - kfree(eeprom); - return NULL; - } - } - return eeprom; -} - - -/* Directly call eeprom analysis function within tveeprom. */ -int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) -{ - u8 *eeprom; - struct tveeprom tvdata; - - memset(&tvdata,0,sizeof(tvdata)); - - eeprom = pvr2_eeprom_fetch(hdw); - if (!eeprom) return -EINVAL; - - { - struct i2c_client fake_client; - /* Newer version expects a useless client interface */ - fake_client.addr = hdw->eeprom_addr; - fake_client.adapter = &hdw->i2c_adap; - tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom); - } - - trace_eeprom("eeprom assumed v4l tveeprom module"); - trace_eeprom("eeprom direct call results:"); - trace_eeprom("has_radio=%d",tvdata.has_radio); - trace_eeprom("tuner_type=%d",tvdata.tuner_type); - trace_eeprom("tuner_formats=0x%x",tvdata.tuner_formats); - trace_eeprom("audio_processor=%d",tvdata.audio_processor); - trace_eeprom("model=%d",tvdata.model); - trace_eeprom("revision=%d",tvdata.revision); - trace_eeprom("serial_number=%d",tvdata.serial_number); - trace_eeprom("rev_str=%s",tvdata.rev_str); - hdw->tuner_type = tvdata.tuner_type; - hdw->tuner_updated = !0; - hdw->serial_number = tvdata.serial_number; - hdw->std_mask_eeprom = tvdata.tuner_formats; - - kfree(eeprom); - - return 0; -} - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -#ifndef __PVRUSB2_EEPROM_H -#define __PVRUSB2_EEPROM_H - -struct pvr2_hdw; - -int pvr2_eeprom_analyze(struct pvr2_hdw *); - -#endif /* __PVRUSB2_EEPROM_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,552 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 // for linux/firmware.h -#include -#include "pvrusb2-util.h" -#include "pvrusb2-encoder.h" -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-debug.h" -#include "pvrusb2-fx2-cmd.h" - - - -/* Firmware mailbox flags - definitions found from ivtv */ -#define IVTV_MBOX_FIRMWARE_DONE 0x00000004 -#define IVTV_MBOX_DRIVER_DONE 0x00000002 -#define IVTV_MBOX_DRIVER_BUSY 0x00000001 - -#define MBOX_BASE 0x44 - - -static int pvr2_encoder_write_words(struct pvr2_hdw *hdw, - unsigned int offs, - const u32 *data, unsigned int dlen) -{ - unsigned int idx,addr; - unsigned int bAddr; - int ret; - unsigned int chunkCnt; - - /* - - Format: First byte must be 0x01. Remaining 32 bit words are - spread out into chunks of 7 bytes each, with the first 4 bytes - being the data word (little endian), and the next 3 bytes - being the address where that data word is to be written (big - endian). Repeat request for additional words, with offset - adjusted accordingly. - - */ - while (dlen) { - chunkCnt = 8; - if (chunkCnt > dlen) chunkCnt = dlen; - memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer)); - bAddr = 0; - hdw->cmd_buffer[bAddr++] = FX2CMD_MEM_WRITE_DWORD; - for (idx = 0; idx < chunkCnt; idx++) { - addr = idx + offs; - hdw->cmd_buffer[bAddr+6] = (addr & 0xffu); - hdw->cmd_buffer[bAddr+5] = ((addr>>8) & 0xffu); - hdw->cmd_buffer[bAddr+4] = ((addr>>16) & 0xffu); - PVR2_DECOMPOSE_LE(hdw->cmd_buffer, bAddr,data[idx]); - bAddr += 7; - } - ret = pvr2_send_request(hdw, - hdw->cmd_buffer,1+(chunkCnt*7), - NULL,0); - if (ret) return ret; - data += chunkCnt; - dlen -= chunkCnt; - offs += chunkCnt; - } - - return 0; -} - - -static int pvr2_encoder_read_words(struct pvr2_hdw *hdw, - unsigned int offs, - u32 *data, unsigned int dlen) -{ - unsigned int idx; - int ret; - unsigned int chunkCnt; - - /* - - Format: First byte must be 0x02 (status check) or 0x28 (read - back block of 32 bit words). Next 6 bytes must be zero, - followed by a single byte of MBOX_BASE+offset for portion to - be read. Returned data is packed set of 32 bits words that - were read. - - */ - - while (dlen) { - chunkCnt = 16; - if (chunkCnt > dlen) chunkCnt = dlen; - if (chunkCnt < 16) chunkCnt = 1; - hdw->cmd_buffer[0] = - ((chunkCnt == 1) ? - FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES); - hdw->cmd_buffer[1] = 0; - hdw->cmd_buffer[2] = 0; - hdw->cmd_buffer[3] = 0; - hdw->cmd_buffer[4] = 0; - hdw->cmd_buffer[5] = ((offs>>16) & 0xffu); - hdw->cmd_buffer[6] = ((offs>>8) & 0xffu); - hdw->cmd_buffer[7] = (offs & 0xffu); - ret = pvr2_send_request(hdw, - hdw->cmd_buffer,8, - hdw->cmd_buffer, - (chunkCnt == 1 ? 4 : 16 * 4)); - if (ret) return ret; - - for (idx = 0; idx < chunkCnt; idx++) { - data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4); - } - data += chunkCnt; - dlen -= chunkCnt; - offs += chunkCnt; - } - - return 0; -} - - -/* This prototype is set up to be compatible with the - cx2341x_mbox_func prototype in cx2341x.h, which should be in - kernels 2.6.18 or later. We do this so that we can enable - cx2341x.ko to write to our encoder (by handing it a pointer to this - function). For earlier kernels this doesn't really matter. */ -static int pvr2_encoder_cmd(void *ctxt, - u32 cmd, - int arg_cnt_send, - int arg_cnt_recv, - u32 *argp) -{ - unsigned int poll_count; - unsigned int try_count = 0; - int retry_flag; - int ret = 0; - unsigned int idx; - /* These sizes look to be limited by the FX2 firmware implementation */ - u32 wrData[16]; - u32 rdData[16]; - struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt; - - - /* - - The encoder seems to speak entirely using blocks 32 bit words. - In ivtv driver terms, this is a mailbox at MBOX_BASE which we - populate with data and watch what the hardware does with it. - The first word is a set of flags used to control the - transaction, the second word is the command to execute, the - third byte is zero (ivtv driver suggests that this is some - kind of return value), and the fourth byte is a specified - timeout (windows driver always uses 0x00060000 except for one - case when it is zero). All successive words are the argument - words for the command. - - First, write out the entire set of words, with the first word - being zero. - - Next, write out just the first word again, but set it to - IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which - probably means "go"). - - Next, read back the return count words. Check the first word, - which should have IVTV_MBOX_FIRMWARE_DONE set. If however - that bit is not set, then the command isn't done so repeat the - read until it is set. - - Finally, write out just the first word again, but set it to - 0x0 this time (which probably means "idle"). - - */ - - if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Failed to write cx23416 command" - " - too many input arguments" - " (was given %u limit %lu)", - arg_cnt_send, (long unsigned) ARRAY_SIZE(wrData) - 4); - return -EINVAL; - } - - if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Failed to write cx23416 command" - " - too many return arguments" - " (was given %u limit %lu)", - arg_cnt_recv, (long unsigned) ARRAY_SIZE(rdData) - 4); - return -EINVAL; - } - - - LOCK_TAKE(hdw->ctl_lock); do { - - if (!hdw->state_encoder_ok) { - ret = -EIO; - break; - } - - retry_flag = 0; - try_count++; - ret = 0; - wrData[0] = 0; - wrData[1] = cmd; - wrData[2] = 0; - wrData[3] = 0x00060000; - for (idx = 0; idx < arg_cnt_send; idx++) { - wrData[idx+4] = argp[idx]; - } - for (; idx < ARRAY_SIZE(wrData) - 4; idx++) { - wrData[idx+4] = 0; - } - - ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,idx); - if (ret) break; - wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY; - ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1); - if (ret) break; - poll_count = 0; - while (1) { - poll_count++; - ret = pvr2_encoder_read_words(hdw,MBOX_BASE,rdData, - arg_cnt_recv+4); - if (ret) { - break; - } - if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) { - break; - } - if (rdData[0] && (poll_count < 1000)) continue; - if (!rdData[0]) { - retry_flag = !0; - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Encoder timed out waiting for us" - "; arranging to retry"); - } else { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "***WARNING*** device's encoder" - " appears to be stuck" - " (status=0x%08x)",rdData[0]); - } - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Encoder command: 0x%02x",cmd); - for (idx = 4; idx < arg_cnt_send; idx++) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Encoder arg%d: 0x%08x", - idx-3,wrData[idx]); - } - ret = -EBUSY; - break; - } - if (retry_flag) { - if (try_count < 20) continue; - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Too many retries..."); - ret = -EBUSY; - } - if (ret) { - del_timer_sync(&hdw->encoder_run_timer); - hdw->state_encoder_ok = 0; - pvr2_trace(PVR2_TRACE_STBITS, - "State bit %s <-- %s", - "state_encoder_ok", - (hdw->state_encoder_ok ? "true" : "false")); - if (hdw->state_encoder_runok) { - hdw->state_encoder_runok = 0; - pvr2_trace(PVR2_TRACE_STBITS, - "State bit %s <-- %s", - "state_encoder_runok", - (hdw->state_encoder_runok ? - "true" : "false")); - } - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Giving up on command." - " This is normally recovered via a firmware" - " reload and re-initialization; concern" - " is only warranted if this happens repeatedly" - " and rapidly."); - break; - } - wrData[0] = 0x7; - for (idx = 0; idx < arg_cnt_recv; idx++) { - argp[idx] = rdData[idx+4]; - } - - wrData[0] = 0x0; - ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1); - if (ret) break; - - } while(0); LOCK_GIVE(hdw->ctl_lock); - - return ret; -} - - -static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd, - int args, ...) -{ - va_list vl; - unsigned int idx; - u32 data[12]; - - if (args > ARRAY_SIZE(data)) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Failed to write cx23416 command" - " - too many arguments" - " (was given %u limit %lu)", - args, (long unsigned) ARRAY_SIZE(data)); - return -EINVAL; - } - - va_start(vl, args); - for (idx = 0; idx < args; idx++) { - data[idx] = va_arg(vl, u32); - } - va_end(vl); - - return pvr2_encoder_cmd(hdw,cmd,args,0,data); -} - - -/* This implements some extra setup for the encoder that seems to be - specific to the PVR USB2 hardware. */ -static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) -{ - int ret = 0; - int encMisc3Arg = 0; - -#if 0 - /* This inexplicable bit happens in the Hauppauge windows - driver (for both 24xxx and 29xxx devices). However I - currently see no difference in behavior with or without - this stuff. Leave this here as a note of its existence, - but don't use it. */ - LOCK_TAKE(hdw->ctl_lock); do { - u32 dat[1]; - dat[0] = 0x80000640; - pvr2_encoder_write_words(hdw,0x01fe,dat,1); - pvr2_encoder_write_words(hdw,0x023e,dat,1); - } while(0); LOCK_GIVE(hdw->ctl_lock); -#endif - - /* Mike Isely 26-Jan-2006 The windows driver - sends the following list of ENC_MISC commands (for both - 24xxx and 29xxx devices). Meanings are not entirely clear, - however without the ENC_MISC(3,1) command then we risk - random perpetual video corruption whenever the video input - breaks up for a moment (like when switching channels). */ - - -#if 0 - /* This ENC_MISC(5,0) command seems to hurt 29xxx sync - performance on channel changes, but is not a problem on - 24xxx devices. */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0); -#endif - - /* This ENC_MISC(3,encMisc3Arg) command is critical - without - it there will eventually be video corruption. Also, the - saa7115 case is strange - the Windows driver is passing 1 - regardless of device type but if we have 1 for saa7115 - devices the video turns sluggish. */ - if (hdw->hdw_desc->flag_has_cx25840) { - encMisc3Arg = 1; - } else { - encMisc3Arg = 0; - } - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3, - encMisc3Arg,0,0); - - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0); - -#if 0 - /* This ENC_MISC(4,1) command is poisonous, so it is commented - out. But I'm leaving it here anyway to document its - existence in the Windows driver. The effect of this - command is that apps displaying the stream become sluggish - with stuttering video. */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0); -#endif - - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0); - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0); - - /* prevent the PTSs from slowly drifting away in the generated - MPEG stream */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC, 2, 4, 1); - - return ret; -} - -int pvr2_encoder_adjust(struct pvr2_hdw *hdw) -{ - int ret; - ret = cx2341x_update(hdw,pvr2_encoder_cmd, - (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL), - &hdw->enc_ctl_state); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Error from cx2341x module code=%d",ret); - } else { - memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state, - sizeof(struct cx2341x_mpeg_params)); - hdw->enc_cur_valid = !0; - } - return ret; -} - - -int pvr2_encoder_configure(struct pvr2_hdw *hdw) -{ - int ret; - int val; - pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure" - " (cx2341x module)"); - hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING; - hdw->enc_ctl_state.width = hdw->res_hor_val; - hdw->enc_ctl_state.height = hdw->res_ver_val; - hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur & V4L2_STD_525_60) ? - 0 : 1); - - ret = 0; - - ret |= pvr2_encoder_prep_config(hdw); - - /* saa7115: 0xf0 */ - val = 0xf0; - if (hdw->hdw_desc->flag_has_cx25840) { - /* ivtv cx25840: 0x140 */ - val = 0x140; - } - - if (!ret) ret = pvr2_encoder_vcmd( - hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, - val, val); - - /* setup firmware to notify us about some events (don't know why...) */ - if (!ret) ret = pvr2_encoder_vcmd( - hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, - 0, 0, 0x10000000, 0xffffffff); - - if (!ret) ret = pvr2_encoder_vcmd( - hdw,CX2341X_ENC_SET_VBI_LINE, 5, - 0xffffffff,0,0,0,0); - - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to configure cx23416"); - return ret; - } - - ret = pvr2_encoder_adjust(hdw); - if (ret) return ret; - - ret = pvr2_encoder_vcmd( - hdw, CX2341X_ENC_INITIALIZE_INPUT, 0); - - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to initialize cx23416 video input"); - return ret; - } - - return 0; -} - - -int pvr2_encoder_start(struct pvr2_hdw *hdw) -{ - int status; - - /* unmask some interrupts */ - pvr2_write_register(hdw, 0x0048, 0xbfffffff); - - pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1, - hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0); - - switch (hdw->active_stream_type) { - case pvr2_config_vbi: - status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, - 0x01,0x14); - break; - case pvr2_config_mpeg: - status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, - 0,0x13); - break; - default: /* Unhandled cases for now */ - status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, - 0,0x13); - break; - } - return status; -} - -int pvr2_encoder_stop(struct pvr2_hdw *hdw) -{ - int status; - - /* mask all interrupts */ - pvr2_write_register(hdw, 0x0048, 0xffffffff); - - switch (hdw->active_stream_type) { - case pvr2_config_vbi: - status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, - 0x01,0x01,0x14); - break; - case pvr2_config_mpeg: - status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, - 0x01,0,0x13); - break; - default: /* Unhandled cases for now */ - status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, - 0x01,0,0x13); - break; - } - - return status; -} - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -#ifndef __PVRUSB2_ENCODER_H -#define __PVRUSB2_ENCODER_H - -struct pvr2_hdw; - -int pvr2_encoder_adjust(struct pvr2_hdw *); -int pvr2_encoder_configure(struct pvr2_hdw *); -int pvr2_encoder_start(struct pvr2_hdw *); -int pvr2_encoder_stop(struct pvr2_hdw *); - -#endif /* __PVRUSB2_ENCODER_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/* - * - * - * Copyright (C) 2007 Michael Krufky - * - * 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 - * - */ - -#ifndef _PVRUSB2_FX2_CMD_H_ -#define _PVRUSB2_FX2_CMD_H_ - -#define FX2CMD_MEM_WRITE_DWORD 0x01u -#define FX2CMD_MEM_READ_DWORD 0x02u - -#define FX2CMD_HCW_ZILOG_RESET 0x10u /* 1=reset 0=release */ - -#define FX2CMD_MEM_READ_64BYTES 0x28u - -#define FX2CMD_REG_WRITE 0x04u -#define FX2CMD_REG_READ 0x05u -#define FX2CMD_MEMSEL 0x06u - -#define FX2CMD_I2C_WRITE 0x08u -#define FX2CMD_I2C_READ 0x09u - -#define FX2CMD_GET_USB_SPEED 0x0bu - -#define FX2CMD_STREAMING_ON 0x36u -#define FX2CMD_STREAMING_OFF 0x37u - -#define FX2CMD_FWPOST1 0x52u - -#define FX2CMD_POWER_OFF 0xdcu -#define FX2CMD_POWER_ON 0xdeu - -#define FX2CMD_DEEP_RESET 0xddu - -#define FX2CMD_GET_EEPROM_ADDR 0xebu -#define FX2CMD_GET_IR_CODE 0xecu - -#define FX2CMD_HCW_DEMOD_RESETIN 0xf0u -#define FX2CMD_HCW_DTV_STREAMING_ON 0xf1u -#define FX2CMD_HCW_DTV_STREAMING_OFF 0xf2u - -#define FX2CMD_ONAIR_DTV_STREAMING_ON 0xa0u -#define FX2CMD_ONAIR_DTV_STREAMING_OFF 0xa1u -#define FX2CMD_ONAIR_DTV_POWER_ON 0xa2u -#define FX2CMD_ONAIR_DTV_POWER_OFF 0xa3u - -#endif /* _PVRUSB2_FX2_CMD_H_ */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -#ifndef __PVRUSB2_H -#define __PVRUSB2_H - -/* Maximum number of pvrusb2 instances we can track at once. You - might want to increase this - however the driver operation will not - be impaired if it is too small. Instead additional units just - won't have an ID assigned and it might not be possible to specify - module parameters for those extra units. */ -#define PVR_NUM 20 - -#endif /* __PVRUSB2_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,5318 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 -#include -#include -#include -#include -#include -#include -#include "pvrusb2.h" -#include "pvrusb2-std.h" -#include "pvrusb2-util.h" -#include "pvrusb2-hdw.h" -#include "pvrusb2-i2c-core.h" -#include "pvrusb2-eeprom.h" -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-encoder.h" -#include "pvrusb2-debug.h" -#include "pvrusb2-fx2-cmd.h" -#include "pvrusb2-wm8775.h" -#include "pvrusb2-video-v4l.h" -#include "pvrusb2-cx2584x-v4l.h" -#include "pvrusb2-cs53l32a.h" -#include "pvrusb2-audio.h" - -#define TV_MIN_FREQ 55250000L -#define TV_MAX_FREQ 850000000L - -/* This defines a minimum interval that the decoder must remain quiet - before we are allowed to start it running. */ -#define TIME_MSEC_DECODER_WAIT 50 - -/* This defines a minimum interval that the decoder must be allowed to run - before we can safely begin using its streaming output. */ -#define TIME_MSEC_DECODER_STABILIZATION_WAIT 300 - -/* This defines a minimum interval that the encoder must remain quiet - before we are allowed to configure it. */ -#define TIME_MSEC_ENCODER_WAIT 50 - -/* This defines the minimum interval that the encoder must successfully run - before we consider that the encoder has run at least once since its - firmware has been loaded. This measurement is in important for cases - where we can't do something until we know that the encoder has been run - at least once. */ -#define TIME_MSEC_ENCODER_OK 250 - -static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL}; -static DEFINE_MUTEX(pvr2_unit_mtx); - -static int ctlchg; -static int procreload; -static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 }; -static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; -static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; -static int init_pause_msec; - -module_param(ctlchg, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value"); -module_param(init_pause_msec, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay"); -module_param(procreload, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(procreload, - "Attempt init failure recovery with firmware reload"); -module_param_array(tuner, int, NULL, 0444); -MODULE_PARM_DESC(tuner,"specify installed tuner type"); -module_param_array(video_std, int, NULL, 0444); -MODULE_PARM_DESC(video_std,"specify initial video standard"); -module_param_array(tolerance, int, NULL, 0444); -MODULE_PARM_DESC(tolerance,"specify stream error tolerance"); - -/* US Broadcast channel 3 (61.25 MHz), to help with testing */ -static int default_tv_freq = 61250000L; -/* 104.3 MHz, a usable FM station for my area */ -static int default_radio_freq = 104300000L; - -module_param_named(tv_freq, default_tv_freq, int, 0444); -MODULE_PARM_DESC(tv_freq, "specify initial television frequency"); -module_param_named(radio_freq, default_radio_freq, int, 0444); -MODULE_PARM_DESC(radio_freq, "specify initial radio frequency"); - -#define PVR2_CTL_WRITE_ENDPOINT 0x01 -#define PVR2_CTL_READ_ENDPOINT 0x81 - -#define PVR2_GPIO_IN 0x9008 -#define PVR2_GPIO_OUT 0x900c -#define PVR2_GPIO_DIR 0x9020 - -#define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__) - -#define PVR2_FIRMWARE_ENDPOINT 0x02 - -/* size of a firmware chunk */ -#define FIRMWARE_CHUNK_SIZE 0x2000 - -typedef void (*pvr2_subdev_update_func)(struct pvr2_hdw *, - struct v4l2_subdev *); - -static const pvr2_subdev_update_func pvr2_module_update_functions[] = { - [PVR2_CLIENT_ID_WM8775] = pvr2_wm8775_subdev_update, - [PVR2_CLIENT_ID_SAA7115] = pvr2_saa7115_subdev_update, - [PVR2_CLIENT_ID_MSP3400] = pvr2_msp3400_subdev_update, - [PVR2_CLIENT_ID_CX25840] = pvr2_cx25840_subdev_update, - [PVR2_CLIENT_ID_CS53L32A] = pvr2_cs53l32a_subdev_update, -}; - -static const char *module_names[] = { - [PVR2_CLIENT_ID_MSP3400] = "msp3400", - [PVR2_CLIENT_ID_CX25840] = "cx25840", - [PVR2_CLIENT_ID_SAA7115] = "saa7115", - [PVR2_CLIENT_ID_TUNER] = "tuner", - [PVR2_CLIENT_ID_DEMOD] = "tuner", - [PVR2_CLIENT_ID_CS53L32A] = "cs53l32a", - [PVR2_CLIENT_ID_WM8775] = "wm8775", -}; - - -static const unsigned char *module_i2c_addresses[] = { - [PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63", - [PVR2_CLIENT_ID_DEMOD] = "\x43", - [PVR2_CLIENT_ID_MSP3400] = "\x40", - [PVR2_CLIENT_ID_SAA7115] = "\x21", - [PVR2_CLIENT_ID_WM8775] = "\x1b", - [PVR2_CLIENT_ID_CX25840] = "\x44", - [PVR2_CLIENT_ID_CS53L32A] = "\x11", -}; - - -static const char *ir_scheme_names[] = { - [PVR2_IR_SCHEME_NONE] = "none", - [PVR2_IR_SCHEME_29XXX] = "29xxx", - [PVR2_IR_SCHEME_24XXX] = "24xxx (29xxx emulation)", - [PVR2_IR_SCHEME_24XXX_MCE] = "24xxx (MCE device)", - [PVR2_IR_SCHEME_ZILOG] = "Zilog", -}; - - -/* Define the list of additional controls we'll dynamically construct based - on query of the cx2341x module. */ -struct pvr2_mpeg_ids { - const char *strid; - int id; -}; -static const struct pvr2_mpeg_ids mpeg_ids[] = { - { - .strid = "audio_layer", - .id = V4L2_CID_MPEG_AUDIO_ENCODING, - },{ - .strid = "audio_bitrate", - .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE, - },{ - /* Already using audio_mode elsewhere :-( */ - .strid = "mpeg_audio_mode", - .id = V4L2_CID_MPEG_AUDIO_MODE, - },{ - .strid = "mpeg_audio_mode_extension", - .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, - },{ - .strid = "audio_emphasis", - .id = V4L2_CID_MPEG_AUDIO_EMPHASIS, - },{ - .strid = "audio_crc", - .id = V4L2_CID_MPEG_AUDIO_CRC, - },{ - .strid = "video_aspect", - .id = V4L2_CID_MPEG_VIDEO_ASPECT, - },{ - .strid = "video_b_frames", - .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, - },{ - .strid = "video_gop_size", - .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, - },{ - .strid = "video_gop_closure", - .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, - },{ - .strid = "video_bitrate_mode", - .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE, - },{ - .strid = "video_bitrate", - .id = V4L2_CID_MPEG_VIDEO_BITRATE, - },{ - .strid = "video_bitrate_peak", - .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, - },{ - .strid = "video_temporal_decimation", - .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, - },{ - .strid = "stream_type", - .id = V4L2_CID_MPEG_STREAM_TYPE, - },{ - .strid = "video_spatial_filter_mode", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, - },{ - .strid = "video_spatial_filter", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, - },{ - .strid = "video_luma_spatial_filter_type", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, - },{ - .strid = "video_chroma_spatial_filter_type", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, - },{ - .strid = "video_temporal_filter_mode", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, - },{ - .strid = "video_temporal_filter", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, - },{ - .strid = "video_median_filter_type", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, - },{ - .strid = "video_luma_median_filter_top", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, - },{ - .strid = "video_luma_median_filter_bottom", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, - },{ - .strid = "video_chroma_median_filter_top", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, - },{ - .strid = "video_chroma_median_filter_bottom", - .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, - } -}; -#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids) - - -static const char *control_values_srate[] = { - [V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100] = "44.1 kHz", - [V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000] = "48 kHz", - [V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000] = "32 kHz", -}; - - - -static const char *control_values_input[] = { - [PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/ - [PVR2_CVAL_INPUT_DTV] = "dtv", - [PVR2_CVAL_INPUT_RADIO] = "radio", - [PVR2_CVAL_INPUT_SVIDEO] = "s-video", - [PVR2_CVAL_INPUT_COMPOSITE] = "composite", -}; - - -static const char *control_values_audiomode[] = { - [V4L2_TUNER_MODE_MONO] = "Mono", - [V4L2_TUNER_MODE_STEREO] = "Stereo", - [V4L2_TUNER_MODE_LANG1] = "Lang1", - [V4L2_TUNER_MODE_LANG2] = "Lang2", - [V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2", -}; - - -static const char *control_values_hsm[] = { - [PVR2_CVAL_HSM_FAIL] = "Fail", - [PVR2_CVAL_HSM_HIGH] = "High", - [PVR2_CVAL_HSM_FULL] = "Full", -}; - - -static const char *pvr2_state_names[] = { - [PVR2_STATE_NONE] = "none", - [PVR2_STATE_DEAD] = "dead", - [PVR2_STATE_COLD] = "cold", - [PVR2_STATE_WARM] = "warm", - [PVR2_STATE_ERROR] = "error", - [PVR2_STATE_READY] = "ready", - [PVR2_STATE_RUN] = "run", -}; - - -struct pvr2_fx2cmd_descdef { - unsigned char id; - unsigned char *desc; -}; - -static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { - {FX2CMD_MEM_WRITE_DWORD, "write encoder dword"}, - {FX2CMD_MEM_READ_DWORD, "read encoder dword"}, - {FX2CMD_HCW_ZILOG_RESET, "zilog IR reset control"}, - {FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"}, - {FX2CMD_REG_WRITE, "write encoder register"}, - {FX2CMD_REG_READ, "read encoder register"}, - {FX2CMD_MEMSEL, "encoder memsel"}, - {FX2CMD_I2C_WRITE, "i2c write"}, - {FX2CMD_I2C_READ, "i2c read"}, - {FX2CMD_GET_USB_SPEED, "get USB speed"}, - {FX2CMD_STREAMING_ON, "stream on"}, - {FX2CMD_STREAMING_OFF, "stream off"}, - {FX2CMD_FWPOST1, "fwpost1"}, - {FX2CMD_POWER_OFF, "power off"}, - {FX2CMD_POWER_ON, "power on"}, - {FX2CMD_DEEP_RESET, "deep reset"}, - {FX2CMD_GET_EEPROM_ADDR, "get rom addr"}, - {FX2CMD_GET_IR_CODE, "get IR code"}, - {FX2CMD_HCW_DEMOD_RESETIN, "hcw demod resetin"}, - {FX2CMD_HCW_DTV_STREAMING_ON, "hcw dtv stream on"}, - {FX2CMD_HCW_DTV_STREAMING_OFF, "hcw dtv stream off"}, - {FX2CMD_ONAIR_DTV_STREAMING_ON, "onair dtv stream on"}, - {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"}, - {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"}, - {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"}, -}; - - -static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v); -static void pvr2_hdw_state_sched(struct pvr2_hdw *); -static int pvr2_hdw_state_eval(struct pvr2_hdw *); -static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); -static void pvr2_hdw_worker_poll(struct work_struct *work); -static int pvr2_hdw_wait(struct pvr2_hdw *,int state); -static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *); -static void pvr2_hdw_state_log_state(struct pvr2_hdw *); -static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl); -static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw); -static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw); -static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw); -static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw); -static void pvr2_hdw_quiescent_timeout(unsigned long); -static void pvr2_hdw_decoder_stabilization_timeout(unsigned long); -static void pvr2_hdw_encoder_wait_timeout(unsigned long); -static void pvr2_hdw_encoder_run_timeout(unsigned long); -static int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32); -static int pvr2_send_request_ex(struct pvr2_hdw *hdw, - unsigned int timeout,int probe_fl, - void *write_data,unsigned int write_len, - void *read_data,unsigned int read_len); -static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw); - - -static void trace_stbit(const char *name,int val) -{ - pvr2_trace(PVR2_TRACE_STBITS, - "State bit %s <-- %s", - name,(val ? "true" : "false")); -} - -static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp) -{ - struct pvr2_hdw *hdw = cptr->hdw; - if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) { - *vp = hdw->freqTable[hdw->freqProgSlot-1]; - } else { - *vp = 0; - } - return 0; -} - -static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v) -{ - struct pvr2_hdw *hdw = cptr->hdw; - unsigned int slotId = hdw->freqProgSlot; - if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) { - hdw->freqTable[slotId-1] = v; - /* Handle side effects correctly - if we're tuned to this - slot, then forgot the slot id relation since the stored - frequency has been changed. */ - if (hdw->freqSelector) { - if (hdw->freqSlotRadio == slotId) { - hdw->freqSlotRadio = 0; - } - } else { - if (hdw->freqSlotTelevision == slotId) { - hdw->freqSlotTelevision = 0; - } - } - } - return 0; -} - -static int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->freqProgSlot; - return 0; -} - -static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v) -{ - struct pvr2_hdw *hdw = cptr->hdw; - if ((v >= 0) && (v <= FREQTABLE_SIZE)) { - hdw->freqProgSlot = v; - } - return 0; -} - -static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp) -{ - struct pvr2_hdw *hdw = cptr->hdw; - *vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision; - return 0; -} - -static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId) -{ - unsigned freq = 0; - struct pvr2_hdw *hdw = cptr->hdw; - if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0; - if (slotId > 0) { - freq = hdw->freqTable[slotId-1]; - if (!freq) return 0; - pvr2_hdw_set_cur_freq(hdw,freq); - } - if (hdw->freqSelector) { - hdw->freqSlotRadio = slotId; - } else { - hdw->freqSlotTelevision = slotId; - } - return 0; -} - -static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = pvr2_hdw_get_cur_freq(cptr->hdw); - return 0; -} - -static int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr) -{ - return cptr->hdw->freqDirty != 0; -} - -static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr) -{ - cptr->hdw->freqDirty = 0; -} - -static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v) -{ - pvr2_hdw_set_cur_freq(cptr->hdw,v); - return 0; -} - -static int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *left = cap->bounds.left; - return 0; -} - -static int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *left = cap->bounds.left; - if (cap->bounds.width > cptr->hdw->cropw_val) { - *left += cap->bounds.width - cptr->hdw->cropw_val; - } - return 0; -} - -static int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *top = cap->bounds.top; - return 0; -} - -static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *top = cap->bounds.top; - if (cap->bounds.height > cptr->hdw->croph_val) { - *top += cap->bounds.height - cptr->hdw->croph_val; - } - return 0; -} - -static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *width) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat, bleftend, cleft; - - stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - bleftend = cap->bounds.left+cap->bounds.width; - cleft = cptr->hdw->cropl_val; - - *width = cleft < bleftend ? bleftend-cleft : 0; - return 0; -} - -static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *height) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat, btopend, ctop; - - stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - btopend = cap->bounds.top+cap->bounds.height; - ctop = cptr->hdw->cropt_val; - - *height = ctop < btopend ? btopend-ctop : 0; - return 0; -} - -static int ctrl_get_cropcapbl(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->bounds.left; - return 0; -} - -static int ctrl_get_cropcapbt(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->bounds.top; - return 0; -} - -static int ctrl_get_cropcapbw(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->bounds.width; - return 0; -} - -static int ctrl_get_cropcapbh(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->bounds.height; - return 0; -} - -static int ctrl_get_cropcapdl(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->defrect.left; - return 0; -} - -static int ctrl_get_cropcapdt(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->defrect.top; - return 0; -} - -static int ctrl_get_cropcapdw(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->defrect.width; - return 0; -} - -static int ctrl_get_cropcapdh(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->defrect.height; - return 0; -} - -static int ctrl_get_cropcappan(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->pixelaspect.numerator; - return 0; -} - -static int ctrl_get_cropcappad(struct pvr2_ctrl *cptr, int *val) -{ - struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); - if (stat != 0) { - return stat; - } - *val = cap->pixelaspect.denominator; - return 0; -} - -static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) -{ - /* Actual maximum depends on the video standard in effect. */ - if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) { - *vp = 480; - } else { - *vp = 576; - } - return 0; -} - -static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp) -{ - /* Actual minimum depends on device digitizer type. */ - if (cptr->hdw->hdw_desc->flag_has_cx25840) { - *vp = 75; - } else { - *vp = 17; - } - return 0; -} - -static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->input_val; - return 0; -} - -static int ctrl_check_input(struct pvr2_ctrl *cptr,int v) -{ - return ((1 << v) & cptr->hdw->input_allowed_mask) != 0; -} - -static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v) -{ - return pvr2_hdw_set_input(cptr->hdw,v); -} - -static int ctrl_isdirty_input(struct pvr2_ctrl *cptr) -{ - return cptr->hdw->input_dirty != 0; -} - -static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr) -{ - cptr->hdw->input_dirty = 0; -} - - -static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp) -{ - unsigned long fv; - struct pvr2_hdw *hdw = cptr->hdw; - if (hdw->tuner_signal_stale) { - pvr2_hdw_status_poll(hdw); - } - fv = hdw->tuner_signal_info.rangehigh; - if (!fv) { - /* Safety fallback */ - *vp = TV_MAX_FREQ; - return 0; - } - if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) { - fv = (fv * 125) / 2; - } else { - fv = fv * 62500; - } - *vp = fv; - return 0; -} - -static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp) -{ - unsigned long fv; - struct pvr2_hdw *hdw = cptr->hdw; - if (hdw->tuner_signal_stale) { - pvr2_hdw_status_poll(hdw); - } - fv = hdw->tuner_signal_info.rangelow; - if (!fv) { - /* Safety fallback */ - *vp = TV_MIN_FREQ; - return 0; - } - if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) { - fv = (fv * 125) / 2; - } else { - fv = fv * 62500; - } - *vp = fv; - return 0; -} - -static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr) -{ - return cptr->hdw->enc_stale != 0; -} - -static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr) -{ - cptr->hdw->enc_stale = 0; - cptr->hdw->enc_unsafe_stale = 0; -} - -static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) -{ - int ret; - struct v4l2_ext_controls cs; - struct v4l2_ext_control c1; - memset(&cs,0,sizeof(cs)); - memset(&c1,0,sizeof(c1)); - cs.controls = &c1; - cs.count = 1; - c1.id = cptr->info->v4l_id; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, - VIDIOC_G_EXT_CTRLS); - if (ret) return ret; - *vp = c1.value; - return 0; -} - -static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) -{ - int ret; - struct pvr2_hdw *hdw = cptr->hdw; - struct v4l2_ext_controls cs; - struct v4l2_ext_control c1; - memset(&cs,0,sizeof(cs)); - memset(&c1,0,sizeof(c1)); - cs.controls = &c1; - cs.count = 1; - c1.id = cptr->info->v4l_id; - c1.value = v; - ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, - hdw->state_encoder_run, &cs, - VIDIOC_S_EXT_CTRLS); - if (ret == -EBUSY) { - /* Oops. cx2341x is telling us it's not safe to change - this control while we're capturing. Make a note of this - fact so that the pipeline will be stopped the next time - controls are committed. Then go on ahead and store this - change anyway. */ - ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, - 0, &cs, - VIDIOC_S_EXT_CTRLS); - if (!ret) hdw->enc_unsafe_stale = !0; - } - if (ret) return ret; - hdw->enc_stale = !0; - return 0; -} - -static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr) -{ - struct v4l2_queryctrl qctrl; - struct pvr2_ctl_info *info; - qctrl.id = cptr->info->v4l_id; - cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl); - /* Strip out the const so we can adjust a function pointer. It's - OK to do this here because we know this is a dynamically created - control, so the underlying storage for the info pointer is (a) - private to us, and (b) not in read-only storage. Either we do - this or we significantly complicate the underlying control - implementation. */ - info = (struct pvr2_ctl_info *)(cptr->info); - if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { - if (info->set_value) { - info->set_value = NULL; - } - } else { - if (!(info->set_value)) { - info->set_value = ctrl_cx2341x_set; - } - } - return qctrl.flags; -} - -static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->state_pipeline_req; - return 0; -} - -static int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->master_state; - return 0; -} - -static int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp) -{ - int result = pvr2_hdw_is_hsm(cptr->hdw); - *vp = PVR2_CVAL_HSM_FULL; - if (result < 0) *vp = PVR2_CVAL_HSM_FAIL; - if (result) *vp = PVR2_CVAL_HSM_HIGH; - return 0; -} - -static int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->std_mask_avail; - return 0; -} - -static int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v) -{ - struct pvr2_hdw *hdw = cptr->hdw; - v4l2_std_id ns; - ns = hdw->std_mask_avail; - ns = (ns & ~m) | (v & m); - if (ns == hdw->std_mask_avail) return 0; - hdw->std_mask_avail = ns; - pvr2_hdw_internal_set_std_avail(hdw); - pvr2_hdw_internal_find_stdenum(hdw); - return 0; -} - -static int ctrl_std_val_to_sym(struct pvr2_ctrl *cptr,int msk,int val, - char *bufPtr,unsigned int bufSize, - unsigned int *len) -{ - *len = pvr2_std_id_to_str(bufPtr,bufSize,msk & val); - return 0; -} - -static int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr, - const char *bufPtr,unsigned int bufSize, - int *mskp,int *valp) -{ - int ret; - v4l2_std_id id; - ret = pvr2_std_str_to_id(&id,bufPtr,bufSize); - if (ret < 0) return ret; - if (mskp) *mskp = id; - if (valp) *valp = id; - return 0; -} - -static int ctrl_stdcur_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->std_mask_cur; - return 0; -} - -static int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v) -{ - struct pvr2_hdw *hdw = cptr->hdw; - v4l2_std_id ns; - ns = hdw->std_mask_cur; - ns = (ns & ~m) | (v & m); - if (ns == hdw->std_mask_cur) return 0; - hdw->std_mask_cur = ns; - hdw->std_dirty = !0; - pvr2_hdw_internal_find_stdenum(hdw); - return 0; -} - -static int ctrl_stdcur_is_dirty(struct pvr2_ctrl *cptr) -{ - return cptr->hdw->std_dirty != 0; -} - -static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr) -{ - cptr->hdw->std_dirty = 0; -} - -static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp) -{ - struct pvr2_hdw *hdw = cptr->hdw; - pvr2_hdw_status_poll(hdw); - *vp = hdw->tuner_signal_info.signal; - return 0; -} - -static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp) -{ - int val = 0; - unsigned int subchan; - struct pvr2_hdw *hdw = cptr->hdw; - pvr2_hdw_status_poll(hdw); - subchan = hdw->tuner_signal_info.rxsubchans; - if (subchan & V4L2_TUNER_SUB_MONO) { - val |= (1 << V4L2_TUNER_MODE_MONO); - } - if (subchan & V4L2_TUNER_SUB_STEREO) { - val |= (1 << V4L2_TUNER_MODE_STEREO); - } - if (subchan & V4L2_TUNER_SUB_LANG1) { - val |= (1 << V4L2_TUNER_MODE_LANG1); - } - if (subchan & V4L2_TUNER_SUB_LANG2) { - val |= (1 << V4L2_TUNER_MODE_LANG2); - } - *vp = val; - return 0; -} - - -static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v) -{ - struct pvr2_hdw *hdw = cptr->hdw; - if (v < 0) return -EINVAL; - if (v > hdw->std_enum_cnt) return -EINVAL; - hdw->std_enum_cur = v; - if (!v) return 0; - v--; - if (hdw->std_mask_cur == hdw->std_defs[v].id) return 0; - hdw->std_mask_cur = hdw->std_defs[v].id; - hdw->std_dirty = !0; - return 0; -} - - -static int ctrl_stdenumcur_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->std_enum_cur; - return 0; -} - - -static int ctrl_stdenumcur_is_dirty(struct pvr2_ctrl *cptr) -{ - return cptr->hdw->std_dirty != 0; -} - - -static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr) -{ - cptr->hdw->std_dirty = 0; -} - - -#define DEFINT(vmin,vmax) \ - .type = pvr2_ctl_int, \ - .def.type_int.min_value = vmin, \ - .def.type_int.max_value = vmax - -#define DEFENUM(tab) \ - .type = pvr2_ctl_enum, \ - .def.type_enum.count = ARRAY_SIZE(tab), \ - .def.type_enum.value_names = tab - -#define DEFBOOL \ - .type = pvr2_ctl_bool - -#define DEFMASK(msk,tab) \ - .type = pvr2_ctl_bitmask, \ - .def.type_bitmask.valid_bits = msk, \ - .def.type_bitmask.bit_names = tab - -#define DEFREF(vname) \ - .set_value = ctrl_set_##vname, \ - .get_value = ctrl_get_##vname, \ - .is_dirty = ctrl_isdirty_##vname, \ - .clear_dirty = ctrl_cleardirty_##vname - - -#define VCREATE_FUNCS(vname) \ -static int ctrl_get_##vname(struct pvr2_ctrl *cptr,int *vp) \ -{*vp = cptr->hdw->vname##_val; return 0;} \ -static int ctrl_set_##vname(struct pvr2_ctrl *cptr,int m,int v) \ -{cptr->hdw->vname##_val = v; cptr->hdw->vname##_dirty = !0; return 0;} \ -static int ctrl_isdirty_##vname(struct pvr2_ctrl *cptr) \ -{return cptr->hdw->vname##_dirty != 0;} \ -static void ctrl_cleardirty_##vname(struct pvr2_ctrl *cptr) \ -{cptr->hdw->vname##_dirty = 0;} - -VCREATE_FUNCS(brightness) -VCREATE_FUNCS(contrast) -VCREATE_FUNCS(saturation) -VCREATE_FUNCS(hue) -VCREATE_FUNCS(volume) -VCREATE_FUNCS(balance) -VCREATE_FUNCS(bass) -VCREATE_FUNCS(treble) -VCREATE_FUNCS(mute) -VCREATE_FUNCS(cropl) -VCREATE_FUNCS(cropt) -VCREATE_FUNCS(cropw) -VCREATE_FUNCS(croph) -VCREATE_FUNCS(audiomode) -VCREATE_FUNCS(res_hor) -VCREATE_FUNCS(res_ver) -VCREATE_FUNCS(srate) - -/* Table definition of all controls which can be manipulated */ -static const struct pvr2_ctl_info control_defs[] = { - { - .v4l_id = V4L2_CID_BRIGHTNESS, - .desc = "Brightness", - .name = "brightness", - .default_value = 128, - DEFREF(brightness), - DEFINT(0,255), - },{ - .v4l_id = V4L2_CID_CONTRAST, - .desc = "Contrast", - .name = "contrast", - .default_value = 68, - DEFREF(contrast), - DEFINT(0,127), - },{ - .v4l_id = V4L2_CID_SATURATION, - .desc = "Saturation", - .name = "saturation", - .default_value = 64, - DEFREF(saturation), - DEFINT(0,127), - },{ - .v4l_id = V4L2_CID_HUE, - .desc = "Hue", - .name = "hue", - .default_value = 0, - DEFREF(hue), - DEFINT(-128,127), - },{ - .v4l_id = V4L2_CID_AUDIO_VOLUME, - .desc = "Volume", - .name = "volume", - .default_value = 62000, - DEFREF(volume), - DEFINT(0,65535), - },{ - .v4l_id = V4L2_CID_AUDIO_BALANCE, - .desc = "Balance", - .name = "balance", - .default_value = 0, - DEFREF(balance), - DEFINT(-32768,32767), - },{ - .v4l_id = V4L2_CID_AUDIO_BASS, - .desc = "Bass", - .name = "bass", - .default_value = 0, - DEFREF(bass), - DEFINT(-32768,32767), - },{ - .v4l_id = V4L2_CID_AUDIO_TREBLE, - .desc = "Treble", - .name = "treble", - .default_value = 0, - DEFREF(treble), - DEFINT(-32768,32767), - },{ - .v4l_id = V4L2_CID_AUDIO_MUTE, - .desc = "Mute", - .name = "mute", - .default_value = 0, - DEFREF(mute), - DEFBOOL, - }, { - .desc = "Capture crop left margin", - .name = "crop_left", - .internal_id = PVR2_CID_CROPL, - .default_value = 0, - DEFREF(cropl), - DEFINT(-129, 340), - .get_min_value = ctrl_cropl_min_get, - .get_max_value = ctrl_cropl_max_get, - .get_def_value = ctrl_get_cropcapdl, - }, { - .desc = "Capture crop top margin", - .name = "crop_top", - .internal_id = PVR2_CID_CROPT, - .default_value = 0, - DEFREF(cropt), - DEFINT(-35, 544), - .get_min_value = ctrl_cropt_min_get, - .get_max_value = ctrl_cropt_max_get, - .get_def_value = ctrl_get_cropcapdt, - }, { - .desc = "Capture crop width", - .name = "crop_width", - .internal_id = PVR2_CID_CROPW, - .default_value = 720, - DEFREF(cropw), - DEFINT(0, 864), - .get_max_value = ctrl_cropw_max_get, - .get_def_value = ctrl_get_cropcapdw, - }, { - .desc = "Capture crop height", - .name = "crop_height", - .internal_id = PVR2_CID_CROPH, - .default_value = 480, - DEFREF(croph), - DEFINT(0, 576), - .get_max_value = ctrl_croph_max_get, - .get_def_value = ctrl_get_cropcapdh, - }, { - .desc = "Capture capability pixel aspect numerator", - .name = "cropcap_pixel_numerator", - .internal_id = PVR2_CID_CROPCAPPAN, - .get_value = ctrl_get_cropcappan, - }, { - .desc = "Capture capability pixel aspect denominator", - .name = "cropcap_pixel_denominator", - .internal_id = PVR2_CID_CROPCAPPAD, - .get_value = ctrl_get_cropcappad, - }, { - .desc = "Capture capability bounds top", - .name = "cropcap_bounds_top", - .internal_id = PVR2_CID_CROPCAPBT, - .get_value = ctrl_get_cropcapbt, - }, { - .desc = "Capture capability bounds left", - .name = "cropcap_bounds_left", - .internal_id = PVR2_CID_CROPCAPBL, - .get_value = ctrl_get_cropcapbl, - }, { - .desc = "Capture capability bounds width", - .name = "cropcap_bounds_width", - .internal_id = PVR2_CID_CROPCAPBW, - .get_value = ctrl_get_cropcapbw, - }, { - .desc = "Capture capability bounds height", - .name = "cropcap_bounds_height", - .internal_id = PVR2_CID_CROPCAPBH, - .get_value = ctrl_get_cropcapbh, - },{ - .desc = "Video Source", - .name = "input", - .internal_id = PVR2_CID_INPUT, - .default_value = PVR2_CVAL_INPUT_TV, - .check_value = ctrl_check_input, - DEFREF(input), - DEFENUM(control_values_input), - },{ - .desc = "Audio Mode", - .name = "audio_mode", - .internal_id = PVR2_CID_AUDIOMODE, - .default_value = V4L2_TUNER_MODE_STEREO, - DEFREF(audiomode), - DEFENUM(control_values_audiomode), - },{ - .desc = "Horizontal capture resolution", - .name = "resolution_hor", - .internal_id = PVR2_CID_HRES, - .default_value = 720, - DEFREF(res_hor), - DEFINT(19,720), - },{ - .desc = "Vertical capture resolution", - .name = "resolution_ver", - .internal_id = PVR2_CID_VRES, - .default_value = 480, - DEFREF(res_ver), - DEFINT(17,576), - /* Hook in check for video standard and adjust maximum - depending on the standard. */ - .get_max_value = ctrl_vres_max_get, - .get_min_value = ctrl_vres_min_get, - },{ - .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, - .default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, - .desc = "Audio Sampling Frequency", - .name = "srate", - DEFREF(srate), - DEFENUM(control_values_srate), - },{ - .desc = "Tuner Frequency (Hz)", - .name = "frequency", - .internal_id = PVR2_CID_FREQUENCY, - .default_value = 0, - .set_value = ctrl_freq_set, - .get_value = ctrl_freq_get, - .is_dirty = ctrl_freq_is_dirty, - .clear_dirty = ctrl_freq_clear_dirty, - DEFINT(0,0), - /* Hook in check for input value (tv/radio) and adjust - max/min values accordingly */ - .get_max_value = ctrl_freq_max_get, - .get_min_value = ctrl_freq_min_get, - },{ - .desc = "Channel", - .name = "channel", - .set_value = ctrl_channel_set, - .get_value = ctrl_channel_get, - DEFINT(0,FREQTABLE_SIZE), - },{ - .desc = "Channel Program Frequency", - .name = "freq_table_value", - .set_value = ctrl_channelfreq_set, - .get_value = ctrl_channelfreq_get, - DEFINT(0,0), - /* Hook in check for input value (tv/radio) and adjust - max/min values accordingly */ - .get_max_value = ctrl_freq_max_get, - .get_min_value = ctrl_freq_min_get, - },{ - .desc = "Channel Program ID", - .name = "freq_table_channel", - .set_value = ctrl_channelprog_set, - .get_value = ctrl_channelprog_get, - DEFINT(0,FREQTABLE_SIZE), - },{ - .desc = "Streaming Enabled", - .name = "streaming_enabled", - .get_value = ctrl_streamingenabled_get, - DEFBOOL, - },{ - .desc = "USB Speed", - .name = "usb_speed", - .get_value = ctrl_hsm_get, - DEFENUM(control_values_hsm), - },{ - .desc = "Master State", - .name = "master_state", - .get_value = ctrl_masterstate_get, - DEFENUM(pvr2_state_names), - },{ - .desc = "Signal Present", - .name = "signal_present", - .get_value = ctrl_signal_get, - DEFINT(0,65535), - },{ - .desc = "Audio Modes Present", - .name = "audio_modes_present", - .get_value = ctrl_audio_modes_present_get, - /* For this type we "borrow" the V4L2_TUNER_MODE enum from - v4l. Nothing outside of this module cares about this, - but I reuse it in order to also reuse the - control_values_audiomode string table. */ - DEFMASK(((1 << V4L2_TUNER_MODE_MONO)| - (1 << V4L2_TUNER_MODE_STEREO)| - (1 << V4L2_TUNER_MODE_LANG1)| - (1 << V4L2_TUNER_MODE_LANG2)), - control_values_audiomode), - },{ - .desc = "Video Standards Available Mask", - .name = "video_standard_mask_available", - .internal_id = PVR2_CID_STDAVAIL, - .skip_init = !0, - .get_value = ctrl_stdavail_get, - .set_value = ctrl_stdavail_set, - .val_to_sym = ctrl_std_val_to_sym, - .sym_to_val = ctrl_std_sym_to_val, - .type = pvr2_ctl_bitmask, - },{ - .desc = "Video Standards In Use Mask", - .name = "video_standard_mask_active", - .internal_id = PVR2_CID_STDCUR, - .skip_init = !0, - .get_value = ctrl_stdcur_get, - .set_value = ctrl_stdcur_set, - .is_dirty = ctrl_stdcur_is_dirty, - .clear_dirty = ctrl_stdcur_clear_dirty, - .val_to_sym = ctrl_std_val_to_sym, - .sym_to_val = ctrl_std_sym_to_val, - .type = pvr2_ctl_bitmask, - },{ - .desc = "Video Standard Name", - .name = "video_standard", - .internal_id = PVR2_CID_STDENUM, - .skip_init = !0, - .get_value = ctrl_stdenumcur_get, - .set_value = ctrl_stdenumcur_set, - .is_dirty = ctrl_stdenumcur_is_dirty, - .clear_dirty = ctrl_stdenumcur_clear_dirty, - .type = pvr2_ctl_enum, - } -}; - -#define CTRLDEF_COUNT ARRAY_SIZE(control_defs) - - -const char *pvr2_config_get_name(enum pvr2_config cfg) -{ - switch (cfg) { - case pvr2_config_empty: return "empty"; - case pvr2_config_mpeg: return "mpeg"; - case pvr2_config_vbi: return "vbi"; - case pvr2_config_pcm: return "pcm"; - case pvr2_config_rawvideo: return "raw video"; - } - return ""; -} - - -struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *hdw) -{ - return hdw->usb_dev; -} - - -unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw) -{ - return hdw->serial_number; -} - - -const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw) -{ - return hdw->bus_info; -} - - -const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *hdw) -{ - return hdw->identifier; -} - - -unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw) -{ - return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio; -} - -/* Set the currently tuned frequency and account for all possible - driver-core side effects of this action. */ -static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val) -{ - if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { - if (hdw->freqSelector) { - /* Swing over to radio frequency selection */ - hdw->freqSelector = 0; - hdw->freqDirty = !0; - } - if (hdw->freqValRadio != val) { - hdw->freqValRadio = val; - hdw->freqSlotRadio = 0; - hdw->freqDirty = !0; - } - } else { - if (!(hdw->freqSelector)) { - /* Swing over to television frequency selection */ - hdw->freqSelector = 1; - hdw->freqDirty = !0; - } - if (hdw->freqValTelevision != val) { - hdw->freqValTelevision = val; - hdw->freqSlotTelevision = 0; - hdw->freqDirty = !0; - } - } -} - -int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw) -{ - return hdw->unit_number; -} - - -/* Attempt to locate one of the given set of files. Messages are logged - appropriate to what has been found. The return value will be 0 or - greater on success (it will be the index of the file name found) and - fw_entry will be filled in. Otherwise a negative error is returned on - failure. If the return value is -ENOENT then no viable firmware file - could be located. */ -static int pvr2_locate_firmware(struct pvr2_hdw *hdw, - const struct firmware **fw_entry, - const char *fwtypename, - unsigned int fwcount, - const char *fwnames[]) -{ - unsigned int idx; - int ret = -EINVAL; - for (idx = 0; idx < fwcount; idx++) { - ret = request_firmware(fw_entry, - fwnames[idx], - &hdw->usb_dev->dev); - if (!ret) { - trace_firmware("Located %s firmware: %s;" - " uploading...", - fwtypename, - fwnames[idx]); - return idx; - } - if (ret == -ENOENT) continue; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "request_firmware fatal error with code=%d",ret); - return ret; - } - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "***WARNING***" - " Device %s firmware" - " seems to be missing.", - fwtypename); - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Did you install the pvrusb2 firmware files" - " in their proper location?"); - if (fwcount == 1) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "request_firmware unable to locate %s file %s", - fwtypename,fwnames[0]); - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "request_firmware unable to locate" - " one of the following %s files:", - fwtypename); - for (idx = 0; idx < fwcount; idx++) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "request_firmware: Failed to find %s", - fwnames[idx]); - } - } - return ret; -} - - -/* - * pvr2_upload_firmware1(). - * - * Send the 8051 firmware to the device. After the upload, arrange for - * device to re-enumerate. - * - * NOTE : the pointer to the firmware data given by request_firmware() - * is not suitable for an usb transaction. - * - */ -static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) -{ - const struct firmware *fw_entry = NULL; - void *fw_ptr; - unsigned int pipe; - unsigned int fwsize; - int ret; - u16 address; - - if (!hdw->hdw_desc->fx2_firmware.cnt) { - hdw->fw1_state = FW1_STATE_OK; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Connected device type defines" - " no firmware to upload; ignoring firmware"); - return -ENOTTY; - } - - hdw->fw1_state = FW1_STATE_FAILED; // default result - - trace_firmware("pvr2_upload_firmware1"); - - ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller", - hdw->hdw_desc->fx2_firmware.cnt, - hdw->hdw_desc->fx2_firmware.lst); - if (ret < 0) { - if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING; - return ret; - } - - usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f)); - - pipe = usb_sndctrlpipe(hdw->usb_dev, 0); - fwsize = fw_entry->size; - - if ((fwsize != 0x2000) && - (!(hdw->hdw_desc->flag_fx2_16kb && (fwsize == 0x4000)))) { - if (hdw->hdw_desc->flag_fx2_16kb) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Wrong fx2 firmware size" - " (expected 8192 or 16384, got %u)", - fwsize); - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Wrong fx2 firmware size" - " (expected 8192, got %u)", - fwsize); - } - release_firmware(fw_entry); - return -ENOMEM; - } - - fw_ptr = kmalloc(0x800, GFP_KERNEL); - if (fw_ptr == NULL){ - release_firmware(fw_entry); - return -ENOMEM; - } - - /* We have to hold the CPU during firmware upload. */ - pvr2_hdw_cpureset_assert(hdw,1); - - /* upload the firmware to address 0000-1fff in 2048 (=0x800) bytes - chunk. */ - - ret = 0; - for (address = 0; address < fwsize; address += 0x800) { - memcpy(fw_ptr, fw_entry->data + address, 0x800); - ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address, - 0, fw_ptr, 0x800, HZ); - } - - trace_firmware("Upload done, releasing device's CPU"); - - /* Now release the CPU. It will disconnect and reconnect later. */ - pvr2_hdw_cpureset_assert(hdw,0); - - kfree(fw_ptr); - release_firmware(fw_entry); - - trace_firmware("Upload done (%d bytes sent)",ret); - - /* We should have written fwsize bytes */ - if (ret == fwsize) { - hdw->fw1_state = FW1_STATE_RELOAD; - return 0; - } - - return -EIO; -} - - -/* - * pvr2_upload_firmware2() - * - * This uploads encoder firmware on endpoint 2. - * - */ - -int pvr2_upload_firmware2(struct pvr2_hdw *hdw) -{ - const struct firmware *fw_entry = NULL; - void *fw_ptr; - unsigned int pipe, fw_len, fw_done, bcnt, icnt; - int actual_length; - int ret = 0; - int fwidx; - static const char *fw_files[] = { - CX2341X_FIRM_ENC_FILENAME, - }; - - if (hdw->hdw_desc->flag_skip_cx23416_firmware) { - return 0; - } - - trace_firmware("pvr2_upload_firmware2"); - - ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder", - ARRAY_SIZE(fw_files), fw_files); - if (ret < 0) return ret; - fwidx = ret; - ret = 0; - /* Since we're about to completely reinitialize the encoder, - invalidate our cached copy of its configuration state. Next - time we configure the encoder, then we'll fully configure it. */ - hdw->enc_cur_valid = 0; - - /* Encoder is about to be reset so note that as far as we're - concerned now, the encoder has never been run. */ - del_timer_sync(&hdw->encoder_run_timer); - if (hdw->state_encoder_runok) { - hdw->state_encoder_runok = 0; - trace_stbit("state_encoder_runok",hdw->state_encoder_runok); - } - - /* First prepare firmware loading */ - ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/ - ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/ - ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/ - ret |= pvr2_hdw_cmd_deep_reset(hdw); - ret |= pvr2_write_register(hdw, 0xa064, 0x00000000); /*APU command*/ - ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000408); /*gpio dir*/ - ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/ - ret |= pvr2_write_register(hdw, 0x9058, 0xffffffed); /*VPU ctrl*/ - ret |= pvr2_write_register(hdw, 0x9054, 0xfffffffd); /*reset hw blocks*/ - ret |= pvr2_write_register(hdw, 0x07f8, 0x80000800); /*encoder SDRAM refresh*/ - ret |= pvr2_write_register(hdw, 0x07fc, 0x0000001a); /*encoder SDRAM pre-charge*/ - ret |= pvr2_write_register(hdw, 0x0700, 0x00000000); /*I2C clock*/ - ret |= pvr2_write_register(hdw, 0xaa00, 0x00000000); /*unknown*/ - ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/ - ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/ - ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/ - ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_FWPOST1); - ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16)); - - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "firmware2 upload prep failed, ret=%d",ret); - release_firmware(fw_entry); - goto done; - } - - /* Now send firmware */ - - fw_len = fw_entry->size; - - if (fw_len % sizeof(u32)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "size of %s firmware" - " must be a multiple of %zu bytes", - fw_files[fwidx],sizeof(u32)); - release_firmware(fw_entry); - ret = -EINVAL; - goto done; - } - - fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL); - if (fw_ptr == NULL){ - release_firmware(fw_entry); - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "failed to allocate memory for firmware2 upload"); - ret = -ENOMEM; - goto done; - } - - pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT); - - fw_done = 0; - for (fw_done = 0; fw_done < fw_len;) { - bcnt = fw_len - fw_done; - if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE; - memcpy(fw_ptr, fw_entry->data + fw_done, bcnt); - /* Usbsnoop log shows that we must swap bytes... */ - /* Some background info: The data being swapped here is a - firmware image destined for the mpeg encoder chip that - lives at the other end of a USB endpoint. The encoder - chip always talks in 32 bit chunks and its storage is - organized into 32 bit words. However from the file - system to the encoder chip everything is purely a byte - stream. The firmware file's contents are always 32 bit - swapped from what the encoder expects. Thus the need - always exists to swap the bytes regardless of the endian - type of the host processor and therefore swab32() makes - the most sense. */ - for (icnt = 0; icnt < bcnt/4 ; icnt++) - ((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]); - - ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt, - &actual_length, HZ); - ret |= (actual_length != bcnt); - if (ret) break; - fw_done += bcnt; - } - - trace_firmware("upload of %s : %i / %i ", - fw_files[fwidx],fw_done,fw_len); - - kfree(fw_ptr); - release_firmware(fw_entry); - - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "firmware2 upload transfer failure"); - goto done; - } - - /* Finish upload */ - - ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/ - ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/ - ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16)); - - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "firmware2 upload post-proc failure"); - } - - done: - if (hdw->hdw_desc->signal_routing_scheme == - PVR2_ROUTING_SCHEME_GOTVIEW) { - /* Ensure that GPIO 11 is set to output for GOTVIEW - hardware. */ - pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0); - } - return ret; -} - - -static const char *pvr2_get_state_name(unsigned int st) -{ - if (st < ARRAY_SIZE(pvr2_state_names)) { - return pvr2_state_names[st]; - } - return "???"; -} - -static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl) -{ - /* Even though we really only care about the video decoder chip at - this point, we'll broadcast stream on/off to all sub-devices - anyway, just in case somebody else wants to hear the - command... */ - pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s", - (enablefl ? "on" : "off")); - v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl); - v4l2_device_call_all(&hdw->v4l2_dev, 0, audio, s_stream, enablefl); - if (hdw->decoder_client_id) { - /* We get here if the encoder has been noticed. Otherwise - we'll issue a warning to the user (which should - normally never happen). */ - return 0; - } - if (!hdw->flag_decoder_missed) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: No decoder present"); - hdw->flag_decoder_missed = !0; - trace_stbit("flag_decoder_missed", - hdw->flag_decoder_missed); - } - return -EIO; -} - - -int pvr2_hdw_get_state(struct pvr2_hdw *hdw) -{ - return hdw->master_state; -} - - -static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw) -{ - if (!hdw->flag_tripped) return 0; - hdw->flag_tripped = 0; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Clearing driver error statuss"); - return !0; -} - - -int pvr2_hdw_untrip(struct pvr2_hdw *hdw) -{ - int fl; - LOCK_TAKE(hdw->big_lock); do { - fl = pvr2_hdw_untrip_unlocked(hdw); - } while (0); LOCK_GIVE(hdw->big_lock); - if (fl) pvr2_hdw_state_sched(hdw); - return 0; -} - - - - -int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw) -{ - return hdw->state_pipeline_req != 0; -} - - -int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag) -{ - int ret,st; - LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_untrip_unlocked(hdw); - if ((!enable_flag) != !(hdw->state_pipeline_req)) { - hdw->state_pipeline_req = enable_flag != 0; - pvr2_trace(PVR2_TRACE_START_STOP, - "/*--TRACE_STREAM--*/ %s", - enable_flag ? "enable" : "disable"); - } - pvr2_hdw_state_sched(hdw); - } while (0); LOCK_GIVE(hdw->big_lock); - if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret; - if (enable_flag) { - while ((st = hdw->master_state) != PVR2_STATE_RUN) { - if (st != PVR2_STATE_READY) return -EIO; - if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret; - } - } - return 0; -} - - -int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config) -{ - int fl; - LOCK_TAKE(hdw->big_lock); - if ((fl = (hdw->desired_stream_type != config)) != 0) { - hdw->desired_stream_type = config; - hdw->state_pipeline_config = 0; - trace_stbit("state_pipeline_config", - hdw->state_pipeline_config); - pvr2_hdw_state_sched(hdw); - } - LOCK_GIVE(hdw->big_lock); - if (fl) return 0; - return pvr2_hdw_wait(hdw,0); -} - - -static int get_default_tuner_type(struct pvr2_hdw *hdw) -{ - int unit_number = hdw->unit_number; - int tp = -1; - if ((unit_number >= 0) && (unit_number < PVR_NUM)) { - tp = tuner[unit_number]; - } - if (tp < 0) return -EINVAL; - hdw->tuner_type = tp; - hdw->tuner_updated = !0; - return 0; -} - - -static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw) -{ - int unit_number = hdw->unit_number; - int tp = 0; - if ((unit_number >= 0) && (unit_number < PVR_NUM)) { - tp = video_std[unit_number]; - if (tp) return tp; - } - return 0; -} - - -static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw) -{ - int unit_number = hdw->unit_number; - int tp = 0; - if ((unit_number >= 0) && (unit_number < PVR_NUM)) { - tp = tolerance[unit_number]; - } - return tp; -} - - -static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw) -{ - /* Try a harmless request to fetch the eeprom's address over - endpoint 1. See what happens. Only the full FX2 image can - respond to this. If this probe fails then likely the FX2 - firmware needs be loaded. */ - int result; - LOCK_TAKE(hdw->ctl_lock); do { - hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR; - result = pvr2_send_request_ex(hdw,HZ*1,!0, - hdw->cmd_buffer,1, - hdw->cmd_buffer,1); - if (result < 0) break; - } while(0); LOCK_GIVE(hdw->ctl_lock); - if (result) { - pvr2_trace(PVR2_TRACE_INIT, - "Probe of device endpoint 1 result status %d", - result); - } else { - pvr2_trace(PVR2_TRACE_INIT, - "Probe of device endpoint 1 succeeded"); - } - return result == 0; -} - -struct pvr2_std_hack { - v4l2_std_id pat; /* Pattern to match */ - v4l2_std_id msk; /* Which bits we care about */ - v4l2_std_id std; /* What additional standards or default to set */ -}; - -/* This data structure labels specific combinations of standards from - tveeprom that we'll try to recognize. If we recognize one, then assume - a specified default standard to use. This is here because tveeprom only - tells us about available standards not the intended default standard (if - any) for the device in question. We guess the default based on what has - been reported as available. Note that this is only for guessing a - default - which can always be overridden explicitly - and if the user - has otherwise named a default then that default will always be used in - place of this table. */ -static const struct pvr2_std_hack std_eeprom_maps[] = { - { /* PAL(B/G) */ - .pat = V4L2_STD_B|V4L2_STD_GH, - .std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G, - }, - { /* NTSC(M) */ - .pat = V4L2_STD_MN, - .std = V4L2_STD_NTSC_M, - }, - { /* PAL(I) */ - .pat = V4L2_STD_PAL_I, - .std = V4L2_STD_PAL_I, - }, - { /* SECAM(L/L') */ - .pat = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, - .std = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, - }, - { /* PAL(D/D1/K) */ - .pat = V4L2_STD_DK, - .std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K, - }, -}; - -static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) -{ - char buf[40]; - unsigned int bcnt; - v4l2_std_id std1,std2,std3; - - std1 = get_default_standard(hdw); - std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask; - - bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); - pvr2_trace(PVR2_TRACE_STD, - "Supported video standard(s) reported available" - " in hardware: %.*s", - bcnt,buf); - - hdw->std_mask_avail = hdw->std_mask_eeprom; - - std2 = (std1|std3) & ~hdw->std_mask_avail; - if (std2) { - bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); - pvr2_trace(PVR2_TRACE_STD, - "Expanding supported video standards" - " to include: %.*s", - bcnt,buf); - hdw->std_mask_avail |= std2; - } - - pvr2_hdw_internal_set_std_avail(hdw); - - if (std1) { - bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1); - pvr2_trace(PVR2_TRACE_STD, - "Initial video standard forced to %.*s", - bcnt,buf); - hdw->std_mask_cur = std1; - hdw->std_dirty = !0; - pvr2_hdw_internal_find_stdenum(hdw); - return; - } - if (std3) { - bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3); - pvr2_trace(PVR2_TRACE_STD, - "Initial video standard" - " (determined by device type): %.*s",bcnt,buf); - hdw->std_mask_cur = std3; - hdw->std_dirty = !0; - pvr2_hdw_internal_find_stdenum(hdw); - return; - } - - { - unsigned int idx; - for (idx = 0; idx < ARRAY_SIZE(std_eeprom_maps); idx++) { - if (std_eeprom_maps[idx].msk ? - ((std_eeprom_maps[idx].pat ^ - hdw->std_mask_eeprom) & - std_eeprom_maps[idx].msk) : - (std_eeprom_maps[idx].pat != - hdw->std_mask_eeprom)) continue; - bcnt = pvr2_std_id_to_str(buf,sizeof(buf), - std_eeprom_maps[idx].std); - pvr2_trace(PVR2_TRACE_STD, - "Initial video standard guessed as %.*s", - bcnt,buf); - hdw->std_mask_cur = std_eeprom_maps[idx].std; - hdw->std_dirty = !0; - pvr2_hdw_internal_find_stdenum(hdw); - return; - } - } - - if (hdw->std_enum_cnt > 1) { - // Autoselect the first listed standard - hdw->std_enum_cur = 1; - hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id; - hdw->std_dirty = !0; - pvr2_trace(PVR2_TRACE_STD, - "Initial video standard auto-selected to %s", - hdw->std_defs[hdw->std_enum_cur-1].name); - return; - } - - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Unable to select a viable initial video standard"); -} - - -static unsigned int pvr2_copy_i2c_addr_list( - unsigned short *dst, const unsigned char *src, - unsigned int dst_max) -{ - unsigned int cnt = 0; - if (!src) return 0; - while (src[cnt] && (cnt + 1) < dst_max) { - dst[cnt] = src[cnt]; - cnt++; - } - dst[cnt] = I2C_CLIENT_END; - return cnt; -} - - -static void pvr2_hdw_cx25840_vbi_hack(struct pvr2_hdw *hdw) -{ - /* - Mike Isely 19-Nov-2006 - This bit of nuttiness - for cx25840 causes that module to correctly set up its video - scaling. This is really a problem in the cx25840 module itself, - but we work around it here. The problem has not been seen in - ivtv because there VBI is supported and set up. We don't do VBI - here (at least not yet) and thus we never attempted to even set - it up. - */ - struct v4l2_format fmt; - if (hdw->decoder_client_id != PVR2_CLIENT_ID_CX25840) { - /* We're not using a cx25840 so don't enable the hack */ - return; - } - - pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u:" - " Executing cx25840 VBI hack", - hdw->decoder_client_id); - memset(&fmt, 0, sizeof(fmt)); - fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - fmt.fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525; - fmt.fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525; - v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id, - vbi, s_sliced_fmt, &fmt.fmt.sliced); -} - - -static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, - const struct pvr2_device_client_desc *cd) -{ - const char *fname; - unsigned char mid; - struct v4l2_subdev *sd; - unsigned int i2ccnt; - const unsigned char *p; - /* Arbitrary count - max # i2c addresses we will probe */ - unsigned short i2caddr[25]; - - mid = cd->module_id; - fname = (mid < ARRAY_SIZE(module_names)) ? module_names[mid] : NULL; - if (!fname) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Module ID %u for device %s has no name?" - " The driver might have a configuration problem.", - mid, - hdw->hdw_desc->description); - return -EINVAL; - } - pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u (%s) for device %s being loaded...", - mid, fname, - hdw->hdw_desc->description); - - i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, cd->i2c_address_list, - ARRAY_SIZE(i2caddr)); - if (!i2ccnt && ((p = (mid < ARRAY_SIZE(module_i2c_addresses)) ? - module_i2c_addresses[mid] : NULL) != NULL)) { - /* Second chance: Try default i2c address list */ - i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, p, - ARRAY_SIZE(i2caddr)); - if (i2ccnt) { - pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u:" - " Using default i2c address list", - mid); - } - } - - if (!i2ccnt) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Module ID %u (%s) for device %s:" - " No i2c addresses." - " The driver might have a configuration problem.", - mid, fname, hdw->hdw_desc->description); - return -EINVAL; - } - - if (i2ccnt == 1) { - pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u:" - " Setting up with specified i2c address 0x%x", - mid, i2caddr[0]); - sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, - fname, i2caddr[0], NULL); - } else { - pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u:" - " Setting up with address probe list", - mid); - sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, - fname, 0, i2caddr); - } - - if (!sd) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Module ID %u (%s) for device %s failed to load." - " Possible missing sub-device kernel module or" - " initialization failure within module.", - mid, fname, hdw->hdw_desc->description); - return -EIO; - } - - /* Tag this sub-device instance with the module ID we know about. - In other places we'll use that tag to determine if the instance - requires special handling. */ - sd->grp_id = mid; - - pvr2_trace(PVR2_TRACE_INFO, "Attached sub-driver %s", fname); - - - /* client-specific setup... */ - switch (mid) { - case PVR2_CLIENT_ID_CX25840: - case PVR2_CLIENT_ID_SAA7115: - hdw->decoder_client_id = mid; - break; - default: break; - } - - return 0; -} - - -static void pvr2_hdw_load_modules(struct pvr2_hdw *hdw) -{ - unsigned int idx; - const struct pvr2_string_table *cm; - const struct pvr2_device_client_table *ct; - int okFl = !0; - - cm = &hdw->hdw_desc->client_modules; - for (idx = 0; idx < cm->cnt; idx++) { - request_module(cm->lst[idx]); - } - - ct = &hdw->hdw_desc->client_table; - for (idx = 0; idx < ct->cnt; idx++) { - if (pvr2_hdw_load_subdev(hdw, &ct->lst[idx]) < 0) okFl = 0; - } - if (!okFl) { - hdw->flag_modulefail = !0; - pvr2_hdw_render_useless(hdw); - } -} - - -static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) -{ - int ret; - unsigned int idx; - struct pvr2_ctrl *cptr; - int reloadFl = 0; - if (hdw->hdw_desc->fx2_firmware.cnt) { - if (!reloadFl) { - reloadFl = - (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints - == 0); - if (reloadFl) { - pvr2_trace(PVR2_TRACE_INIT, - "USB endpoint config looks strange" - "; possibly firmware needs to be" - " loaded"); - } - } - if (!reloadFl) { - reloadFl = !pvr2_hdw_check_firmware(hdw); - if (reloadFl) { - pvr2_trace(PVR2_TRACE_INIT, - "Check for FX2 firmware failed" - "; possibly firmware needs to be" - " loaded"); - } - } - if (reloadFl) { - if (pvr2_upload_firmware1(hdw) != 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failure uploading firmware1"); - } - return; - } - } - hdw->fw1_state = FW1_STATE_OK; - - if (!pvr2_hdw_dev_ok(hdw)) return; - - hdw->force_dirty = !0; - - if (!hdw->hdw_desc->flag_no_powerup) { - pvr2_hdw_cmd_powerup(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - } - - /* Take the IR chip out of reset, if appropriate */ - if (hdw->ir_scheme_active == PVR2_IR_SCHEME_ZILOG) { - pvr2_issue_simple_cmd(hdw, - FX2CMD_HCW_ZILOG_RESET | - (1 << 8) | - ((0) << 16)); - } - - // This step MUST happen after the earlier powerup step. - pvr2_i2c_core_init(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - - pvr2_hdw_load_modules(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - - v4l2_device_call_all(&hdw->v4l2_dev, 0, core, load_fw); - - for (idx = 0; idx < CTRLDEF_COUNT; idx++) { - cptr = hdw->controls + idx; - if (cptr->info->skip_init) continue; - if (!cptr->info->set_value) continue; - cptr->info->set_value(cptr,~0,cptr->info->default_value); - } - - pvr2_hdw_cx25840_vbi_hack(hdw); - - /* Set up special default values for the television and radio - frequencies here. It's not really important what these defaults - are, but I set them to something usable in the Chicago area just - to make driver testing a little easier. */ - - hdw->freqValTelevision = default_tv_freq; - hdw->freqValRadio = default_radio_freq; - - // Do not use pvr2_reset_ctl_endpoints() here. It is not - // thread-safe against the normal pvr2_send_request() mechanism. - // (We should make it thread safe). - - if (hdw->hdw_desc->flag_has_hauppauge_rom) { - ret = pvr2_hdw_get_eeprom_addr(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Unable to determine location of eeprom," - " skipping"); - } else { - hdw->eeprom_addr = ret; - pvr2_eeprom_analyze(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - } - } else { - hdw->tuner_type = hdw->hdw_desc->default_tuner_type; - hdw->tuner_updated = !0; - hdw->std_mask_eeprom = V4L2_STD_ALL; - } - - if (hdw->serial_number) { - idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, - "sn-%lu", hdw->serial_number); - } else if (hdw->unit_number >= 0) { - idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, - "unit-%c", - hdw->unit_number + 'a'); - } else { - idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, - "unit-??"); - } - hdw->identifier[idx] = 0; - - pvr2_hdw_setup_std(hdw); - - if (!get_default_tuner_type(hdw)) { - pvr2_trace(PVR2_TRACE_INIT, - "pvr2_hdw_setup: Tuner type overridden to %d", - hdw->tuner_type); - } - - - if (!pvr2_hdw_dev_ok(hdw)) return; - - if (hdw->hdw_desc->signal_routing_scheme == - PVR2_ROUTING_SCHEME_GOTVIEW) { - /* Ensure that GPIO 11 is set to output for GOTVIEW - hardware. */ - pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0); - } - - pvr2_hdw_commit_setup(hdw); - - hdw->vid_stream = pvr2_stream_create(); - if (!pvr2_hdw_dev_ok(hdw)) return; - pvr2_trace(PVR2_TRACE_INIT, - "pvr2_hdw_setup: video stream is %p",hdw->vid_stream); - if (hdw->vid_stream) { - idx = get_default_error_tolerance(hdw); - if (idx) { - pvr2_trace(PVR2_TRACE_INIT, - "pvr2_hdw_setup: video stream %p" - " setting tolerance %u", - hdw->vid_stream,idx); - } - pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev, - PVR2_VID_ENDPOINT,idx); - } - - if (!pvr2_hdw_dev_ok(hdw)) return; - - hdw->flag_init_ok = !0; - - pvr2_hdw_state_sched(hdw); -} - - -/* Set up the structure and attempt to put the device into a usable state. - This can be a time-consuming operation, which is why it is not done - internally as part of the create() step. */ -static void pvr2_hdw_setup(struct pvr2_hdw *hdw) -{ - pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw); - do { - pvr2_hdw_setup_low(hdw); - pvr2_trace(PVR2_TRACE_INIT, - "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d", - hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok); - if (pvr2_hdw_dev_ok(hdw)) { - if (hdw->flag_init_ok) { - pvr2_trace( - PVR2_TRACE_INFO, - "Device initialization" - " completed successfully."); - break; - } - if (hdw->fw1_state == FW1_STATE_RELOAD) { - pvr2_trace( - PVR2_TRACE_INFO, - "Device microcontroller firmware" - " (re)loaded; it should now reset" - " and reconnect."); - break; - } - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Device initialization was not successful."); - if (hdw->fw1_state == FW1_STATE_MISSING) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Giving up since device" - " microcontroller firmware" - " appears to be missing."); - break; - } - } - if (hdw->flag_modulefail) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "***WARNING*** pvrusb2 driver initialization" - " failed due to the failure of one or more" - " sub-device kernel modules."); - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "You need to resolve the failing condition" - " before this driver can function. There" - " should be some earlier messages giving more" - " information about the problem."); - break; - } - if (procreload) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Attempting pvrusb2 recovery by reloading" - " primary firmware."); - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "If this works, device should disconnect" - " and reconnect in a sane state."); - hdw->fw1_state = FW1_STATE_UNKNOWN; - pvr2_upload_firmware1(hdw); - } else { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "***WARNING*** pvrusb2 device hardware" - " appears to be jammed" - " and I can't clear it."); - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "You might need to power cycle" - " the pvrusb2 device" - " in order to recover."); - } - } while (0); - pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); -} - - -/* Perform second stage initialization. Set callback pointer first so that - we can avoid a possible initialization race (if the kernel thread runs - before the callback has been set). */ -int pvr2_hdw_initialize(struct pvr2_hdw *hdw, - void (*callback_func)(void *), - void *callback_data) -{ - LOCK_TAKE(hdw->big_lock); do { - if (hdw->flag_disconnected) { - /* Handle a race here: If we're already - disconnected by this point, then give up. If we - get past this then we'll remain connected for - the duration of initialization since the entire - initialization sequence is now protected by the - big_lock. */ - break; - } - hdw->state_data = callback_data; - hdw->state_func = callback_func; - pvr2_hdw_setup(hdw); - } while (0); LOCK_GIVE(hdw->big_lock); - return hdw->flag_init_ok; -} - - -/* Create, set up, and return a structure for interacting with the - underlying hardware. */ -struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, - const struct usb_device_id *devid) -{ - unsigned int idx,cnt1,cnt2,m; - struct pvr2_hdw *hdw = NULL; - int valid_std_mask; - struct pvr2_ctrl *cptr; - struct usb_device *usb_dev; - const struct pvr2_device_desc *hdw_desc; - __u8 ifnum; - struct v4l2_queryctrl qctrl; - struct pvr2_ctl_info *ciptr; - - usb_dev = interface_to_usbdev(intf); - - hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info); - - if (hdw_desc == NULL) { - pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create:" - " No device description pointer," - " unable to continue."); - pvr2_trace(PVR2_TRACE_INIT, "If you have a new device type," - " please contact Mike Isely " - " to get it included in the driver\n"); - goto fail; - } - - hdw = kzalloc(sizeof(*hdw),GFP_KERNEL); - pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", - hdw,hdw_desc->description); - pvr2_trace(PVR2_TRACE_INFO, "Hardware description: %s", - hdw_desc->description); - if (hdw_desc->flag_is_experimental) { - pvr2_trace(PVR2_TRACE_INFO, "**********"); - pvr2_trace(PVR2_TRACE_INFO, - "WARNING: Support for this device (%s) is" - " experimental.", hdw_desc->description); - pvr2_trace(PVR2_TRACE_INFO, - "Important functionality might not be" - " entirely working."); - pvr2_trace(PVR2_TRACE_INFO, - "Please consider contacting the driver author to" - " help with further stabilization of the driver."); - pvr2_trace(PVR2_TRACE_INFO, "**********"); - } - if (!hdw) goto fail; - - init_timer(&hdw->quiescent_timer); - hdw->quiescent_timer.data = (unsigned long)hdw; - hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout; - - init_timer(&hdw->decoder_stabilization_timer); - hdw->decoder_stabilization_timer.data = (unsigned long)hdw; - hdw->decoder_stabilization_timer.function = - pvr2_hdw_decoder_stabilization_timeout; - - init_timer(&hdw->encoder_wait_timer); - hdw->encoder_wait_timer.data = (unsigned long)hdw; - hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout; - - init_timer(&hdw->encoder_run_timer); - hdw->encoder_run_timer.data = (unsigned long)hdw; - hdw->encoder_run_timer.function = pvr2_hdw_encoder_run_timeout; - - hdw->master_state = PVR2_STATE_DEAD; - - init_waitqueue_head(&hdw->state_wait_data); - - hdw->tuner_signal_stale = !0; - cx2341x_fill_defaults(&hdw->enc_ctl_state); - - /* Calculate which inputs are OK */ - m = 0; - if (hdw_desc->flag_has_analogtuner) m |= 1 << PVR2_CVAL_INPUT_TV; - if (hdw_desc->digital_control_scheme != PVR2_DIGITAL_SCHEME_NONE) { - m |= 1 << PVR2_CVAL_INPUT_DTV; - } - if (hdw_desc->flag_has_svideo) m |= 1 << PVR2_CVAL_INPUT_SVIDEO; - if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE; - if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO; - hdw->input_avail_mask = m; - hdw->input_allowed_mask = hdw->input_avail_mask; - - /* If not a hybrid device, pathway_state never changes. So - initialize it here to what it should forever be. */ - if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_DTV))) { - hdw->pathway_state = PVR2_PATHWAY_ANALOG; - } else if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_TV))) { - hdw->pathway_state = PVR2_PATHWAY_DIGITAL; - } - - hdw->control_cnt = CTRLDEF_COUNT; - hdw->control_cnt += MPEGDEF_COUNT; - hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt, - GFP_KERNEL); - if (!hdw->controls) goto fail; - hdw->hdw_desc = hdw_desc; - hdw->ir_scheme_active = hdw->hdw_desc->ir_scheme; - for (idx = 0; idx < hdw->control_cnt; idx++) { - cptr = hdw->controls + idx; - cptr->hdw = hdw; - } - for (idx = 0; idx < 32; idx++) { - hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx]; - } - for (idx = 0; idx < CTRLDEF_COUNT; idx++) { - cptr = hdw->controls + idx; - cptr->info = control_defs+idx; - } - - /* Ensure that default input choice is a valid one. */ - m = hdw->input_avail_mask; - if (m) for (idx = 0; idx < (sizeof(m) << 3); idx++) { - if (!((1 << idx) & m)) continue; - hdw->input_val = idx; - break; - } - - /* Define and configure additional controls from cx2341x module. */ - hdw->mpeg_ctrl_info = kzalloc( - sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL); - if (!hdw->mpeg_ctrl_info) goto fail; - for (idx = 0; idx < MPEGDEF_COUNT; idx++) { - cptr = hdw->controls + idx + CTRLDEF_COUNT; - ciptr = &(hdw->mpeg_ctrl_info[idx].info); - ciptr->desc = hdw->mpeg_ctrl_info[idx].desc; - ciptr->name = mpeg_ids[idx].strid; - ciptr->v4l_id = mpeg_ids[idx].id; - ciptr->skip_init = !0; - ciptr->get_value = ctrl_cx2341x_get; - ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags; - ciptr->is_dirty = ctrl_cx2341x_is_dirty; - if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty; - qctrl.id = ciptr->v4l_id; - cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl); - if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) { - ciptr->set_value = ctrl_cx2341x_set; - } - strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name, - PVR2_CTLD_INFO_DESC_SIZE); - hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0; - ciptr->default_value = qctrl.default_value; - switch (qctrl.type) { - default: - case V4L2_CTRL_TYPE_INTEGER: - ciptr->type = pvr2_ctl_int; - ciptr->def.type_int.min_value = qctrl.minimum; - ciptr->def.type_int.max_value = qctrl.maximum; - break; - case V4L2_CTRL_TYPE_BOOLEAN: - ciptr->type = pvr2_ctl_bool; - break; - case V4L2_CTRL_TYPE_MENU: - ciptr->type = pvr2_ctl_enum; - ciptr->def.type_enum.value_names = - cx2341x_ctrl_get_menu(&hdw->enc_ctl_state, - ciptr->v4l_id); - for (cnt1 = 0; - ciptr->def.type_enum.value_names[cnt1] != NULL; - cnt1++) { } - ciptr->def.type_enum.count = cnt1; - break; - } - cptr->info = ciptr; - } - - // Initialize video standard enum dynamic control - cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM); - if (cptr) { - memcpy(&hdw->std_info_enum,cptr->info, - sizeof(hdw->std_info_enum)); - cptr->info = &hdw->std_info_enum; - - } - // Initialize control data regarding video standard masks - valid_std_mask = pvr2_std_get_usable(); - for (idx = 0; idx < 32; idx++) { - if (!(valid_std_mask & (1 << idx))) continue; - cnt1 = pvr2_std_id_to_str( - hdw->std_mask_names[idx], - sizeof(hdw->std_mask_names[idx])-1, - 1 << idx); - hdw->std_mask_names[idx][cnt1] = 0; - } - cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL); - if (cptr) { - memcpy(&hdw->std_info_avail,cptr->info, - sizeof(hdw->std_info_avail)); - cptr->info = &hdw->std_info_avail; - hdw->std_info_avail.def.type_bitmask.bit_names = - hdw->std_mask_ptrs; - hdw->std_info_avail.def.type_bitmask.valid_bits = - valid_std_mask; - } - cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR); - if (cptr) { - memcpy(&hdw->std_info_cur,cptr->info, - sizeof(hdw->std_info_cur)); - cptr->info = &hdw->std_info_cur; - hdw->std_info_cur.def.type_bitmask.bit_names = - hdw->std_mask_ptrs; - hdw->std_info_avail.def.type_bitmask.valid_bits = - valid_std_mask; - } - - hdw->cropcap_stale = !0; - hdw->eeprom_addr = -1; - hdw->unit_number = -1; - hdw->v4l_minor_number_video = -1; - hdw->v4l_minor_number_vbi = -1; - hdw->v4l_minor_number_radio = -1; - hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); - if (!hdw->ctl_write_buffer) goto fail; - hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); - if (!hdw->ctl_read_buffer) goto fail; - hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL); - if (!hdw->ctl_write_urb) goto fail; - hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL); - if (!hdw->ctl_read_urb) goto fail; - - if (v4l2_device_register(&intf->dev, &hdw->v4l2_dev) != 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Error registering with v4l core, giving up"); - goto fail; - } - mutex_lock(&pvr2_unit_mtx); do { - for (idx = 0; idx < PVR_NUM; idx++) { - if (unit_pointers[idx]) continue; - hdw->unit_number = idx; - unit_pointers[idx] = hdw; - break; - } - } while (0); mutex_unlock(&pvr2_unit_mtx); - - cnt1 = 0; - cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2"); - cnt1 += cnt2; - if (hdw->unit_number >= 0) { - cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c", - ('a' + hdw->unit_number)); - cnt1 += cnt2; - } - if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; - hdw->name[cnt1] = 0; - - hdw->workqueue = create_singlethread_workqueue(hdw->name); - INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll); - - pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", - hdw->unit_number,hdw->name); - - hdw->tuner_type = -1; - hdw->flag_ok = !0; - - hdw->usb_intf = intf; - hdw->usb_dev = usb_dev; - - usb_make_path(hdw->usb_dev, hdw->bus_info, sizeof(hdw->bus_info)); - - ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; - usb_set_interface(hdw->usb_dev,ifnum,0); - - mutex_init(&hdw->ctl_lock_mutex); - mutex_init(&hdw->big_lock_mutex); - - return hdw; - fail: - if (hdw) { - del_timer_sync(&hdw->quiescent_timer); - del_timer_sync(&hdw->decoder_stabilization_timer); - del_timer_sync(&hdw->encoder_run_timer); - del_timer_sync(&hdw->encoder_wait_timer); - if (hdw->workqueue) { - flush_workqueue(hdw->workqueue); - destroy_workqueue(hdw->workqueue); - hdw->workqueue = NULL; - } - usb_free_urb(hdw->ctl_read_urb); - usb_free_urb(hdw->ctl_write_urb); - kfree(hdw->ctl_read_buffer); - kfree(hdw->ctl_write_buffer); - kfree(hdw->controls); - kfree(hdw->mpeg_ctrl_info); - kfree(hdw->std_defs); - kfree(hdw->std_enum_names); - kfree(hdw); - } - return NULL; -} - - -/* Remove _all_ associations between this driver and the underlying USB - layer. */ -static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) -{ - if (hdw->flag_disconnected) return; - pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_remove_usb_stuff: hdw=%p",hdw); - if (hdw->ctl_read_urb) { - usb_kill_urb(hdw->ctl_read_urb); - usb_free_urb(hdw->ctl_read_urb); - hdw->ctl_read_urb = NULL; - } - if (hdw->ctl_write_urb) { - usb_kill_urb(hdw->ctl_write_urb); - usb_free_urb(hdw->ctl_write_urb); - hdw->ctl_write_urb = NULL; - } - if (hdw->ctl_read_buffer) { - kfree(hdw->ctl_read_buffer); - hdw->ctl_read_buffer = NULL; - } - if (hdw->ctl_write_buffer) { - kfree(hdw->ctl_write_buffer); - hdw->ctl_write_buffer = NULL; - } - hdw->flag_disconnected = !0; - /* If we don't do this, then there will be a dangling struct device - reference to our disappearing device persisting inside the V4L - core... */ - v4l2_device_disconnect(&hdw->v4l2_dev); - hdw->usb_dev = NULL; - hdw->usb_intf = NULL; - pvr2_hdw_render_useless(hdw); -} - - -/* Destroy hardware interaction structure */ -void pvr2_hdw_destroy(struct pvr2_hdw *hdw) -{ - if (!hdw) return; - pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); - if (hdw->workqueue) { - flush_workqueue(hdw->workqueue); - destroy_workqueue(hdw->workqueue); - hdw->workqueue = NULL; - } - del_timer_sync(&hdw->quiescent_timer); - del_timer_sync(&hdw->decoder_stabilization_timer); - del_timer_sync(&hdw->encoder_run_timer); - del_timer_sync(&hdw->encoder_wait_timer); - if (hdw->fw_buffer) { - kfree(hdw->fw_buffer); - hdw->fw_buffer = NULL; - } - if (hdw->vid_stream) { - pvr2_stream_destroy(hdw->vid_stream); - hdw->vid_stream = NULL; - } - pvr2_i2c_core_done(hdw); - v4l2_device_unregister(&hdw->v4l2_dev); - pvr2_hdw_remove_usb_stuff(hdw); - mutex_lock(&pvr2_unit_mtx); do { - if ((hdw->unit_number >= 0) && - (hdw->unit_number < PVR_NUM) && - (unit_pointers[hdw->unit_number] == hdw)) { - unit_pointers[hdw->unit_number] = NULL; - } - } while (0); mutex_unlock(&pvr2_unit_mtx); - kfree(hdw->controls); - kfree(hdw->mpeg_ctrl_info); - kfree(hdw->std_defs); - kfree(hdw->std_enum_names); - kfree(hdw); -} - - -int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw) -{ - return (hdw && hdw->flag_ok); -} - - -/* Called when hardware has been unplugged */ -void pvr2_hdw_disconnect(struct pvr2_hdw *hdw) -{ - pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw); - LOCK_TAKE(hdw->big_lock); - LOCK_TAKE(hdw->ctl_lock); - pvr2_hdw_remove_usb_stuff(hdw); - LOCK_GIVE(hdw->ctl_lock); - LOCK_GIVE(hdw->big_lock); -} - - -// Attempt to autoselect an appropriate value for std_enum_cur given -// whatever is currently in std_mask_cur -static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw) -{ - unsigned int idx; - for (idx = 1; idx < hdw->std_enum_cnt; idx++) { - if (hdw->std_defs[idx-1].id == hdw->std_mask_cur) { - hdw->std_enum_cur = idx; - return; - } - } - hdw->std_enum_cur = 0; -} - - -// Calculate correct set of enumerated standards based on currently known -// set of available standards bits. -static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw) -{ - struct v4l2_standard *newstd; - unsigned int std_cnt; - unsigned int idx; - - newstd = pvr2_std_create_enum(&std_cnt,hdw->std_mask_avail); - - if (hdw->std_defs) { - kfree(hdw->std_defs); - hdw->std_defs = NULL; - } - hdw->std_enum_cnt = 0; - if (hdw->std_enum_names) { - kfree(hdw->std_enum_names); - hdw->std_enum_names = NULL; - } - - if (!std_cnt) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "WARNING: Failed to identify any viable standards"); - } - - /* Set up the dynamic control for this standard */ - hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL); - if (hdw->std_enum_names) { - hdw->std_enum_names[0] = "none"; - for (idx = 0; idx < std_cnt; idx++) - hdw->std_enum_names[idx+1] = newstd[idx].name; - hdw->std_info_enum.def.type_enum.value_names = - hdw->std_enum_names; - hdw->std_info_enum.def.type_enum.count = std_cnt+1; - } else { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "WARNING: Failed to alloc memory for names"); - hdw->std_info_enum.def.type_enum.value_names = NULL; - hdw->std_info_enum.def.type_enum.count = 0; - } - hdw->std_defs = newstd; - hdw->std_enum_cnt = std_cnt+1; - hdw->std_enum_cur = 0; - hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail; -} - - -int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw, - struct v4l2_standard *std, - unsigned int idx) -{ - int ret = -EINVAL; - if (!idx) return ret; - LOCK_TAKE(hdw->big_lock); do { - if (idx >= hdw->std_enum_cnt) break; - idx--; - memcpy(std,hdw->std_defs+idx,sizeof(*std)); - ret = 0; - } while (0); LOCK_GIVE(hdw->big_lock); - return ret; -} - - -/* Get the number of defined controls */ -unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw) -{ - return hdw->control_cnt; -} - - -/* Retrieve a control handle given its index (0..count-1) */ -struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw, - unsigned int idx) -{ - if (idx >= hdw->control_cnt) return NULL; - return hdw->controls + idx; -} - - -/* Retrieve a control handle given its index (0..count-1) */ -struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw, - unsigned int ctl_id) -{ - struct pvr2_ctrl *cptr; - unsigned int idx; - int i; - - /* This could be made a lot more efficient, but for now... */ - for (idx = 0; idx < hdw->control_cnt; idx++) { - cptr = hdw->controls + idx; - i = cptr->info->internal_id; - if (i && (i == ctl_id)) return cptr; - } - return NULL; -} - - -/* Given a V4L ID, retrieve the control structure associated with it. */ -struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id) -{ - struct pvr2_ctrl *cptr; - unsigned int idx; - int i; - - /* This could be made a lot more efficient, but for now... */ - for (idx = 0; idx < hdw->control_cnt; idx++) { - cptr = hdw->controls + idx; - i = cptr->info->v4l_id; - if (i && (i == ctl_id)) return cptr; - } - return NULL; -} - - -/* Given a V4L ID for its immediate predecessor, retrieve the control - structure associated with it. */ -struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *hdw, - unsigned int ctl_id) -{ - struct pvr2_ctrl *cptr,*cp2; - unsigned int idx; - int i; - - /* This could be made a lot more efficient, but for now... */ - cp2 = NULL; - for (idx = 0; idx < hdw->control_cnt; idx++) { - cptr = hdw->controls + idx; - i = cptr->info->v4l_id; - if (!i) continue; - if (i <= ctl_id) continue; - if (cp2 && (cp2->info->v4l_id < i)) continue; - cp2 = cptr; - } - return cp2; - return NULL; -} - - -static const char *get_ctrl_typename(enum pvr2_ctl_type tp) -{ - switch (tp) { - case pvr2_ctl_int: return "integer"; - case pvr2_ctl_enum: return "enum"; - case pvr2_ctl_bool: return "boolean"; - case pvr2_ctl_bitmask: return "bitmask"; - } - return ""; -} - - -static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id, - const char *name, int val) -{ - struct v4l2_control ctrl; - pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 %s=%d", name, val); - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = id; - ctrl.value = val; - v4l2_device_call_all(&hdw->v4l2_dev, 0, core, s_ctrl, &ctrl); -} - -#define PVR2_SUBDEV_SET_CONTROL(hdw, id, lab) \ - if ((hdw)->lab##_dirty || (hdw)->force_dirty) { \ - pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \ - } - -/* Execute whatever commands are required to update the state of all the - sub-devices so that they match our current control values. */ -static void pvr2_subdev_update(struct pvr2_hdw *hdw) -{ - struct v4l2_subdev *sd; - unsigned int id; - pvr2_subdev_update_func fp; - - pvr2_trace(PVR2_TRACE_CHIPS, "subdev update..."); - - if (hdw->tuner_updated || hdw->force_dirty) { - struct tuner_setup setup; - pvr2_trace(PVR2_TRACE_CHIPS, "subdev tuner set_type(%d)", - hdw->tuner_type); - if (((int)(hdw->tuner_type)) >= 0) { - memset(&setup, 0, sizeof(setup)); - setup.addr = ADDR_UNSET; - setup.type = hdw->tuner_type; - setup.mode_mask = T_RADIO | T_ANALOG_TV; - v4l2_device_call_all(&hdw->v4l2_dev, 0, - tuner, s_type_addr, &setup); - } - } - - if (hdw->input_dirty || hdw->std_dirty || hdw->force_dirty) { - pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_standard"); - if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { - v4l2_device_call_all(&hdw->v4l2_dev, 0, - tuner, s_radio); - } else { - v4l2_std_id vs; - vs = hdw->std_mask_cur; - v4l2_device_call_all(&hdw->v4l2_dev, 0, - core, s_std, vs); - pvr2_hdw_cx25840_vbi_hack(hdw); - } - hdw->tuner_signal_stale = !0; - hdw->cropcap_stale = !0; - } - - PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_BRIGHTNESS, brightness); - PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_CONTRAST, contrast); - PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_SATURATION, saturation); - PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_HUE, hue); - PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_MUTE, mute); - PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_VOLUME, volume); - PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BALANCE, balance); - PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BASS, bass); - PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_TREBLE, treble); - - if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) { - struct v4l2_tuner vt; - memset(&vt, 0, sizeof(vt)); - vt.audmode = hdw->audiomode_val; - v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt); - } - - if (hdw->freqDirty || hdw->force_dirty) { - unsigned long fv; - struct v4l2_frequency freq; - fv = pvr2_hdw_get_cur_freq(hdw); - pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_freq(%lu)", fv); - if (hdw->tuner_signal_stale) pvr2_hdw_status_poll(hdw); - memset(&freq, 0, sizeof(freq)); - if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) { - /* ((fv * 1000) / 62500) */ - freq.frequency = (fv * 2) / 125; - } else { - freq.frequency = fv / 62500; - } - /* tuner-core currently doesn't seem to care about this, but - let's set it anyway for completeness. */ - if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { - freq.type = V4L2_TUNER_RADIO; - } else { - freq.type = V4L2_TUNER_ANALOG_TV; - } - freq.tuner = 0; - v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, - s_frequency, &freq); - } - - if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) { - struct v4l2_mbus_framefmt fmt; - memset(&fmt, 0, sizeof(fmt)); - fmt.width = hdw->res_hor_val; - fmt.height = hdw->res_ver_val; - fmt.code = V4L2_MBUS_FMT_FIXED; - pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)", - fmt.width, fmt.height); - v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_mbus_fmt, &fmt); - } - - if (hdw->srate_dirty || hdw->force_dirty) { - u32 val; - pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_audio %d", - hdw->srate_val); - switch (hdw->srate_val) { - default: - case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000: - val = 48000; - break; - case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100: - val = 44100; - break; - case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000: - val = 32000; - break; - } - v4l2_device_call_all(&hdw->v4l2_dev, 0, - audio, s_clock_freq, val); - } - - /* Unable to set crop parameters; there is apparently no equivalent - for VIDIOC_S_CROP */ - - v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { - id = sd->grp_id; - if (id >= ARRAY_SIZE(pvr2_module_update_functions)) continue; - fp = pvr2_module_update_functions[id]; - if (!fp) continue; - (*fp)(hdw, sd); - } - - if (hdw->tuner_signal_stale || hdw->cropcap_stale) { - pvr2_hdw_status_poll(hdw); - } -} - - -/* Figure out if we need to commit control changes. If so, mark internal - state flags to indicate this fact and return true. Otherwise do nothing - else and return false. */ -static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw) -{ - unsigned int idx; - struct pvr2_ctrl *cptr; - int value; - int commit_flag = hdw->force_dirty; - char buf[100]; - unsigned int bcnt,ccnt; - - for (idx = 0; idx < hdw->control_cnt; idx++) { - cptr = hdw->controls + idx; - if (!cptr->info->is_dirty) continue; - if (!cptr->info->is_dirty(cptr)) continue; - commit_flag = !0; - - if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue; - bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ", - cptr->info->name); - value = 0; - cptr->info->get_value(cptr,&value); - pvr2_ctrl_value_to_sym_internal(cptr,~0,value, - buf+bcnt, - sizeof(buf)-bcnt,&ccnt); - bcnt += ccnt; - bcnt += scnprintf(buf+bcnt,sizeof(buf)-bcnt," <%s>", - get_ctrl_typename(cptr->info->type)); - pvr2_trace(PVR2_TRACE_CTL, - "/*--TRACE_COMMIT--*/ %.*s", - bcnt,buf); - } - - if (!commit_flag) { - /* Nothing has changed */ - return 0; - } - - hdw->state_pipeline_config = 0; - trace_stbit("state_pipeline_config",hdw->state_pipeline_config); - pvr2_hdw_state_sched(hdw); - - return !0; -} - - -/* Perform all operations needed to commit all control changes. This must - be performed in synchronization with the pipeline state and is thus - expected to be called as part of the driver's worker thread. Return - true if commit successful, otherwise return false to indicate that - commit isn't possible at this time. */ -static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) -{ - unsigned int idx; - struct pvr2_ctrl *cptr; - int disruptive_change; - - if (hdw->input_dirty && hdw->state_pathway_ok && - (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ? - PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) != - hdw->pathway_state)) { - /* Change of mode being asked for... */ - hdw->state_pathway_ok = 0; - trace_stbit("state_pathway_ok", hdw->state_pathway_ok); - } - if (!hdw->state_pathway_ok) { - /* Can't commit anything until pathway is ok. */ - return 0; - } - - /* Handle some required side effects when the video standard is - changed.... */ - if (hdw->std_dirty) { - int nvres; - int gop_size; - if (hdw->std_mask_cur & V4L2_STD_525_60) { - nvres = 480; - gop_size = 15; - } else { - nvres = 576; - gop_size = 12; - } - /* Rewrite the vertical resolution to be appropriate to the - video standard that has been selected. */ - if (nvres != hdw->res_ver_val) { - hdw->res_ver_val = nvres; - hdw->res_ver_dirty = !0; - } - /* Rewrite the GOP size to be appropriate to the video - standard that has been selected. */ - if (gop_size != hdw->enc_ctl_state.video_gop_size) { - struct v4l2_ext_controls cs; - struct v4l2_ext_control c1; - memset(&cs, 0, sizeof(cs)); - memset(&c1, 0, sizeof(c1)); - cs.controls = &c1; - cs.count = 1; - c1.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE; - c1.value = gop_size; - cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs, - VIDIOC_S_EXT_CTRLS); - } - } - - /* The broadcast decoder can only scale down, so if - * res_*_dirty && crop window < output format ==> enlarge crop. - * - * The mpeg encoder receives fields of res_hor_val dots and - * res_ver_val halflines. Limits: hor<=720, ver<=576. - */ - if (hdw->res_hor_dirty && hdw->cropw_val < hdw->res_hor_val) { - hdw->cropw_val = hdw->res_hor_val; - hdw->cropw_dirty = !0; - } else if (hdw->cropw_dirty) { - hdw->res_hor_dirty = !0; /* must rescale */ - hdw->res_hor_val = min(720, hdw->cropw_val); - } - if (hdw->res_ver_dirty && hdw->croph_val < hdw->res_ver_val) { - hdw->croph_val = hdw->res_ver_val; - hdw->croph_dirty = !0; - } else if (hdw->croph_dirty) { - int nvres = hdw->std_mask_cur & V4L2_STD_525_60 ? 480 : 576; - hdw->res_ver_dirty = !0; - hdw->res_ver_val = min(nvres, hdw->croph_val); - } - - /* If any of the below has changed, then we can't do the update - while the pipeline is running. Pipeline must be paused first - and decoder -> encoder connection be made quiescent before we - can proceed. */ - disruptive_change = - (hdw->std_dirty || - hdw->enc_unsafe_stale || - hdw->srate_dirty || - hdw->res_ver_dirty || - hdw->res_hor_dirty || - hdw->cropw_dirty || - hdw->croph_dirty || - hdw->input_dirty || - (hdw->active_stream_type != hdw->desired_stream_type)); - if (disruptive_change && !hdw->state_pipeline_idle) { - /* Pipeline is not idle; we can't proceed. Arrange to - cause pipeline to stop so that we can try this again - later.... */ - hdw->state_pipeline_pause = !0; - return 0; - } - - if (hdw->srate_dirty) { - /* Write new sample rate into control structure since - * the master copy is stale. We must track srate - * separate from the mpeg control structure because - * other logic also uses this value. */ - struct v4l2_ext_controls cs; - struct v4l2_ext_control c1; - memset(&cs,0,sizeof(cs)); - memset(&c1,0,sizeof(c1)); - cs.controls = &c1; - cs.count = 1; - c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ; - c1.value = hdw->srate_val; - cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS); - } - - if (hdw->active_stream_type != hdw->desired_stream_type) { - /* Handle any side effects of stream config here */ - hdw->active_stream_type = hdw->desired_stream_type; - } - - if (hdw->hdw_desc->signal_routing_scheme == - PVR2_ROUTING_SCHEME_GOTVIEW) { - u32 b; - /* Handle GOTVIEW audio switching */ - pvr2_hdw_gpio_get_out(hdw,&b); - if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { - /* Set GPIO 11 */ - pvr2_hdw_gpio_chg_out(hdw,(1 << 11),~0); - } else { - /* Clear GPIO 11 */ - pvr2_hdw_gpio_chg_out(hdw,(1 << 11),0); - } - } - - /* Check and update state for all sub-devices. */ - pvr2_subdev_update(hdw); - - hdw->tuner_updated = 0; - hdw->force_dirty = 0; - for (idx = 0; idx < hdw->control_cnt; idx++) { - cptr = hdw->controls + idx; - if (!cptr->info->clear_dirty) continue; - cptr->info->clear_dirty(cptr); - } - - if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) && - hdw->state_encoder_run) { - /* If encoder isn't running or it can't be touched, then - this will get worked out later when we start the - encoder. */ - if (pvr2_encoder_adjust(hdw) < 0) return !0; - } - - hdw->state_pipeline_config = !0; - /* Hardware state may have changed in a way to cause the cropping - capabilities to have changed. So mark it stale, which will - cause a later re-fetch. */ - trace_stbit("state_pipeline_config",hdw->state_pipeline_config); - return !0; -} - - -int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw) -{ - int fl; - LOCK_TAKE(hdw->big_lock); - fl = pvr2_hdw_commit_setup(hdw); - LOCK_GIVE(hdw->big_lock); - if (!fl) return 0; - return pvr2_hdw_wait(hdw,0); -} - - -static void pvr2_hdw_worker_poll(struct work_struct *work) -{ - int fl = 0; - struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll); - LOCK_TAKE(hdw->big_lock); do { - fl = pvr2_hdw_state_eval(hdw); - } while (0); LOCK_GIVE(hdw->big_lock); - if (fl && hdw->state_func) { - hdw->state_func(hdw->state_data); - } -} - - -static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state) -{ - return wait_event_interruptible( - hdw->state_wait_data, - (hdw->state_stale == 0) && - (!state || (hdw->master_state != state))); -} - - -/* Return name for this driver instance */ -const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) -{ - return hdw->name; -} - - -const char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw) -{ - return hdw->hdw_desc->description; -} - - -const char *pvr2_hdw_get_type(struct pvr2_hdw *hdw) -{ - return hdw->hdw_desc->shortname; -} - - -int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw) -{ - int result; - LOCK_TAKE(hdw->ctl_lock); do { - hdw->cmd_buffer[0] = FX2CMD_GET_USB_SPEED; - result = pvr2_send_request(hdw, - hdw->cmd_buffer,1, - hdw->cmd_buffer,1); - if (result < 0) break; - result = (hdw->cmd_buffer[0] != 0); - } while(0); LOCK_GIVE(hdw->ctl_lock); - return result; -} - - -/* Execute poll of tuner status */ -void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw) -{ - LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_status_poll(hdw); - } while (0); LOCK_GIVE(hdw->big_lock); -} - - -static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw) -{ - if (!hdw->cropcap_stale) { - return 0; - } - pvr2_hdw_status_poll(hdw); - if (hdw->cropcap_stale) { - return -EIO; - } - return 0; -} - - -/* Return information about cropping capabilities */ -int pvr2_hdw_get_cropcap(struct pvr2_hdw *hdw, struct v4l2_cropcap *pp) -{ - int stat = 0; - LOCK_TAKE(hdw->big_lock); - stat = pvr2_hdw_check_cropcap(hdw); - if (!stat) { - memcpy(pp, &hdw->cropcap_info, sizeof(hdw->cropcap_info)); - } - LOCK_GIVE(hdw->big_lock); - return stat; -} - - -/* Return information about the tuner */ -int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp) -{ - LOCK_TAKE(hdw->big_lock); do { - if (hdw->tuner_signal_stale) { - pvr2_hdw_status_poll(hdw); - } - memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner)); - } while (0); LOCK_GIVE(hdw->big_lock); - return 0; -} - - -/* Get handle to video output stream */ -struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp) -{ - return hp->vid_stream; -} - - -void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) -{ - int nr = pvr2_hdw_get_unit_number(hdw); - LOCK_TAKE(hdw->big_lock); do { - printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr); - v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status); - pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:"); - cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2"); - pvr2_hdw_state_log_state(hdw); - printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr); - } while (0); LOCK_GIVE(hdw->big_lock); -} - - -/* Grab EEPROM contents, needed for direct method. */ -#define EEPROM_SIZE 8192 -#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__) -static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) -{ - struct i2c_msg msg[2]; - u8 *eeprom; - u8 iadd[2]; - u8 addr; - u16 eepromSize; - unsigned int offs; - int ret; - int mode16 = 0; - unsigned pcnt,tcnt; - eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); - if (!eeprom) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to allocate memory" - " required to read eeprom"); - return NULL; - } - - trace_eeprom("Value for eeprom addr from controller was 0x%x", - hdw->eeprom_addr); - addr = hdw->eeprom_addr; - /* Seems that if the high bit is set, then the *real* eeprom - address is shifted right now bit position (noticed this in - newer PVR USB2 hardware) */ - if (addr & 0x80) addr >>= 1; - - /* FX2 documentation states that a 16bit-addressed eeprom is - expected if the I2C address is an odd number (yeah, this is - strange but it's what they do) */ - mode16 = (addr & 1); - eepromSize = (mode16 ? EEPROM_SIZE : 256); - trace_eeprom("Examining %d byte eeprom at location 0x%x" - " using %d bit addressing",eepromSize,addr, - mode16 ? 16 : 8); - - msg[0].addr = addr; - msg[0].flags = 0; - msg[0].len = mode16 ? 2 : 1; - msg[0].buf = iadd; - msg[1].addr = addr; - msg[1].flags = I2C_M_RD; - - /* We have to do the actual eeprom data fetch ourselves, because - (1) we're only fetching part of the eeprom, and (2) if we were - getting the whole thing our I2C driver can't grab it in one - pass - which is what tveeprom is otherwise going to attempt */ - memset(eeprom,0,EEPROM_SIZE); - for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { - pcnt = 16; - if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; - offs = tcnt + (eepromSize - EEPROM_SIZE); - if (mode16) { - iadd[0] = offs >> 8; - iadd[1] = offs; - } else { - iadd[0] = offs; - } - msg[1].len = pcnt; - msg[1].buf = eeprom+tcnt; - if ((ret = i2c_transfer(&hdw->i2c_adap, - msg,ARRAY_SIZE(msg))) != 2) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "eeprom fetch set offs err=%d",ret); - kfree(eeprom); - return NULL; - } - } - return eeprom; -} - - -void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, - int mode, - int enable_flag) -{ - int ret; - u16 address; - unsigned int pipe; - LOCK_TAKE(hdw->big_lock); do { - if ((hdw->fw_buffer == NULL) == !enable_flag) break; - - if (!enable_flag) { - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Cleaning up after CPU firmware fetch"); - kfree(hdw->fw_buffer); - hdw->fw_buffer = NULL; - hdw->fw_size = 0; - if (hdw->fw_cpu_flag) { - /* Now release the CPU. It will disconnect - and reconnect later. */ - pvr2_hdw_cpureset_assert(hdw,0); - } - break; - } - - hdw->fw_cpu_flag = (mode != 2); - if (hdw->fw_cpu_flag) { - hdw->fw_size = (mode == 1) ? 0x4000 : 0x2000; - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Preparing to suck out CPU firmware" - " (size=%u)", hdw->fw_size); - hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); - if (!hdw->fw_buffer) { - hdw->fw_size = 0; - break; - } - - /* We have to hold the CPU during firmware upload. */ - pvr2_hdw_cpureset_assert(hdw,1); - - /* download the firmware from address 0000-1fff in 2048 - (=0x800) bytes chunk. */ - - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Grabbing CPU firmware"); - pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); - for(address = 0; address < hdw->fw_size; - address += 0x800) { - ret = usb_control_msg(hdw->usb_dev,pipe, - 0xa0,0xc0, - address,0, - hdw->fw_buffer+address, - 0x800,HZ); - if (ret < 0) break; - } - - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Done grabbing CPU firmware"); - } else { - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Sucking down EEPROM contents"); - hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw); - if (!hdw->fw_buffer) { - pvr2_trace(PVR2_TRACE_FIRMWARE, - "EEPROM content suck failed."); - break; - } - hdw->fw_size = EEPROM_SIZE; - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Done sucking down EEPROM contents"); - } - - } while (0); LOCK_GIVE(hdw->big_lock); -} - - -/* Return true if we're in a mode for retrieval CPU firmware */ -int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw) -{ - return hdw->fw_buffer != NULL; -} - - -int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs, - char *buf,unsigned int cnt) -{ - int ret = -EINVAL; - LOCK_TAKE(hdw->big_lock); do { - if (!buf) break; - if (!cnt) break; - - if (!hdw->fw_buffer) { - ret = -EIO; - break; - } - - if (offs >= hdw->fw_size) { - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Read firmware data offs=%d EOF", - offs); - ret = 0; - break; - } - - if (offs + cnt > hdw->fw_size) cnt = hdw->fw_size - offs; - - memcpy(buf,hdw->fw_buffer+offs,cnt); - - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Read firmware data offs=%d cnt=%d", - offs,cnt); - ret = cnt; - } while (0); LOCK_GIVE(hdw->big_lock); - - return ret; -} - - -int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw, - enum pvr2_v4l_type index) -{ - switch (index) { - case pvr2_v4l_type_video: return hdw->v4l_minor_number_video; - case pvr2_v4l_type_vbi: return hdw->v4l_minor_number_vbi; - case pvr2_v4l_type_radio: return hdw->v4l_minor_number_radio; - default: return -1; - } -} - - -/* Store a v4l minor device number */ -void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw, - enum pvr2_v4l_type index,int v) -{ - switch (index) { - case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v; - case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v; - case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v; - default: break; - } -} - - -static void pvr2_ctl_write_complete(struct urb *urb) -{ - struct pvr2_hdw *hdw = urb->context; - hdw->ctl_write_pend_flag = 0; - if (hdw->ctl_read_pend_flag) return; - complete(&hdw->ctl_done); -} - - -static void pvr2_ctl_read_complete(struct urb *urb) -{ - struct pvr2_hdw *hdw = urb->context; - hdw->ctl_read_pend_flag = 0; - if (hdw->ctl_write_pend_flag) return; - complete(&hdw->ctl_done); -} - - -static void pvr2_ctl_timeout(unsigned long data) -{ - struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; - if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { - hdw->ctl_timeout_flag = !0; - if (hdw->ctl_write_pend_flag) - usb_unlink_urb(hdw->ctl_write_urb); - if (hdw->ctl_read_pend_flag) - usb_unlink_urb(hdw->ctl_read_urb); - } -} - - -/* Issue a command and get a response from the device. This extended - version includes a probe flag (which if set means that device errors - should not be logged or treated as fatal) and a timeout in jiffies. - This can be used to non-lethally probe the health of endpoint 1. */ -static int pvr2_send_request_ex(struct pvr2_hdw *hdw, - unsigned int timeout,int probe_fl, - void *write_data,unsigned int write_len, - void *read_data,unsigned int read_len) -{ - unsigned int idx; - int status = 0; - struct timer_list timer; - if (!hdw->ctl_lock_held) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Attempted to execute control transfer" - " without lock!!"); - return -EDEADLK; - } - if (!hdw->flag_ok && !probe_fl) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Attempted to execute control transfer" - " when device not ok"); - return -EIO; - } - if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) { - if (!probe_fl) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Attempted to execute control transfer" - " when USB is disconnected"); - } - return -ENOTTY; - } - - /* Ensure that we have sane parameters */ - if (!write_data) write_len = 0; - if (!read_data) read_len = 0; - if (write_len > PVR2_CTL_BUFFSIZE) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Attempted to execute %d byte" - " control-write transfer (limit=%d)", - write_len,PVR2_CTL_BUFFSIZE); - return -EINVAL; - } - if (read_len > PVR2_CTL_BUFFSIZE) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Attempted to execute %d byte" - " control-read transfer (limit=%d)", - write_len,PVR2_CTL_BUFFSIZE); - return -EINVAL; - } - if ((!write_len) && (!read_len)) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Attempted to execute null control transfer?"); - return -EINVAL; - } - - - hdw->cmd_debug_state = 1; - if (write_len) { - hdw->cmd_debug_code = ((unsigned char *)write_data)[0]; - } else { - hdw->cmd_debug_code = 0; - } - hdw->cmd_debug_write_len = write_len; - hdw->cmd_debug_read_len = read_len; - - /* Initialize common stuff */ - init_completion(&hdw->ctl_done); - hdw->ctl_timeout_flag = 0; - hdw->ctl_write_pend_flag = 0; - hdw->ctl_read_pend_flag = 0; - init_timer(&timer); - timer.expires = jiffies + timeout; - timer.data = (unsigned long)hdw; - timer.function = pvr2_ctl_timeout; - - if (write_len) { - hdw->cmd_debug_state = 2; - /* Transfer write data to internal buffer */ - for (idx = 0; idx < write_len; idx++) { - hdw->ctl_write_buffer[idx] = - ((unsigned char *)write_data)[idx]; - } - /* Initiate a write request */ - usb_fill_bulk_urb(hdw->ctl_write_urb, - hdw->usb_dev, - usb_sndbulkpipe(hdw->usb_dev, - PVR2_CTL_WRITE_ENDPOINT), - hdw->ctl_write_buffer, - write_len, - pvr2_ctl_write_complete, - hdw); - hdw->ctl_write_urb->actual_length = 0; - hdw->ctl_write_pend_flag = !0; - status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL); - if (status < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to submit write-control" - " URB status=%d",status); - hdw->ctl_write_pend_flag = 0; - goto done; - } - } - - if (read_len) { - hdw->cmd_debug_state = 3; - memset(hdw->ctl_read_buffer,0x43,read_len); - /* Initiate a read request */ - usb_fill_bulk_urb(hdw->ctl_read_urb, - hdw->usb_dev, - usb_rcvbulkpipe(hdw->usb_dev, - PVR2_CTL_READ_ENDPOINT), - hdw->ctl_read_buffer, - read_len, - pvr2_ctl_read_complete, - hdw); - hdw->ctl_read_urb->actual_length = 0; - hdw->ctl_read_pend_flag = !0; - status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL); - if (status < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to submit read-control" - " URB status=%d",status); - hdw->ctl_read_pend_flag = 0; - goto done; - } - } - - /* Start timer */ - add_timer(&timer); - - /* Now wait for all I/O to complete */ - hdw->cmd_debug_state = 4; - while (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { - wait_for_completion(&hdw->ctl_done); - } - hdw->cmd_debug_state = 5; - - /* Stop timer */ - del_timer_sync(&timer); - - hdw->cmd_debug_state = 6; - status = 0; - - if (hdw->ctl_timeout_flag) { - status = -ETIMEDOUT; - if (!probe_fl) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Timed out control-write"); - } - goto done; - } - - if (write_len) { - /* Validate results of write request */ - if ((hdw->ctl_write_urb->status != 0) && - (hdw->ctl_write_urb->status != -ENOENT) && - (hdw->ctl_write_urb->status != -ESHUTDOWN) && - (hdw->ctl_write_urb->status != -ECONNRESET)) { - /* USB subsystem is reporting some kind of failure - on the write */ - status = hdw->ctl_write_urb->status; - if (!probe_fl) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-write URB failure," - " status=%d", - status); - } - goto done; - } - if (hdw->ctl_write_urb->actual_length < write_len) { - /* Failed to write enough data */ - status = -EIO; - if (!probe_fl) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-write URB short," - " expected=%d got=%d", - write_len, - hdw->ctl_write_urb->actual_length); - } - goto done; - } - } - if (read_len) { - /* Validate results of read request */ - if ((hdw->ctl_read_urb->status != 0) && - (hdw->ctl_read_urb->status != -ENOENT) && - (hdw->ctl_read_urb->status != -ESHUTDOWN) && - (hdw->ctl_read_urb->status != -ECONNRESET)) { - /* USB subsystem is reporting some kind of failure - on the read */ - status = hdw->ctl_read_urb->status; - if (!probe_fl) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-read URB failure," - " status=%d", - status); - } - goto done; - } - if (hdw->ctl_read_urb->actual_length < read_len) { - /* Failed to read enough data */ - status = -EIO; - if (!probe_fl) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-read URB short," - " expected=%d got=%d", - read_len, - hdw->ctl_read_urb->actual_length); - } - goto done; - } - /* Transfer retrieved data out from internal buffer */ - for (idx = 0; idx < read_len; idx++) { - ((unsigned char *)read_data)[idx] = - hdw->ctl_read_buffer[idx]; - } - } - - done: - - hdw->cmd_debug_state = 0; - if ((status < 0) && (!probe_fl)) { - pvr2_hdw_render_useless(hdw); - } - return status; -} - - -int pvr2_send_request(struct pvr2_hdw *hdw, - void *write_data,unsigned int write_len, - void *read_data,unsigned int read_len) -{ - return pvr2_send_request_ex(hdw,HZ*4,0, - write_data,write_len, - read_data,read_len); -} - - -static int pvr2_issue_simple_cmd(struct pvr2_hdw *hdw,u32 cmdcode) -{ - int ret; - unsigned int cnt = 1; - unsigned int args = 0; - LOCK_TAKE(hdw->ctl_lock); - hdw->cmd_buffer[0] = cmdcode & 0xffu; - args = (cmdcode >> 8) & 0xffu; - args = (args > 2) ? 2 : args; - if (args) { - cnt += args; - hdw->cmd_buffer[1] = (cmdcode >> 16) & 0xffu; - if (args > 1) { - hdw->cmd_buffer[2] = (cmdcode >> 24) & 0xffu; - } - } - if (pvrusb2_debug & PVR2_TRACE_INIT) { - unsigned int idx; - unsigned int ccnt,bcnt; - char tbuf[50]; - cmdcode &= 0xffu; - bcnt = 0; - ccnt = scnprintf(tbuf+bcnt, - sizeof(tbuf)-bcnt, - "Sending FX2 command 0x%x",cmdcode); - bcnt += ccnt; - for (idx = 0; idx < ARRAY_SIZE(pvr2_fx2cmd_desc); idx++) { - if (pvr2_fx2cmd_desc[idx].id == cmdcode) { - ccnt = scnprintf(tbuf+bcnt, - sizeof(tbuf)-bcnt, - " \"%s\"", - pvr2_fx2cmd_desc[idx].desc); - bcnt += ccnt; - break; - } - } - if (args) { - ccnt = scnprintf(tbuf+bcnt, - sizeof(tbuf)-bcnt, - " (%u",hdw->cmd_buffer[1]); - bcnt += ccnt; - if (args > 1) { - ccnt = scnprintf(tbuf+bcnt, - sizeof(tbuf)-bcnt, - ",%u",hdw->cmd_buffer[2]); - bcnt += ccnt; - } - ccnt = scnprintf(tbuf+bcnt, - sizeof(tbuf)-bcnt, - ")"); - bcnt += ccnt; - } - pvr2_trace(PVR2_TRACE_INIT,"%.*s",bcnt,tbuf); - } - ret = pvr2_send_request(hdw,hdw->cmd_buffer,cnt,NULL,0); - LOCK_GIVE(hdw->ctl_lock); - return ret; -} - - -int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data) -{ - int ret; - - LOCK_TAKE(hdw->ctl_lock); - - hdw->cmd_buffer[0] = FX2CMD_REG_WRITE; /* write register prefix */ - PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data); - hdw->cmd_buffer[5] = 0; - hdw->cmd_buffer[6] = (reg >> 8) & 0xff; - hdw->cmd_buffer[7] = reg & 0xff; - - - ret = pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 0); - - LOCK_GIVE(hdw->ctl_lock); - - return ret; -} - - -static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data) -{ - int ret = 0; - - LOCK_TAKE(hdw->ctl_lock); - - hdw->cmd_buffer[0] = FX2CMD_REG_READ; /* read register prefix */ - hdw->cmd_buffer[1] = 0; - hdw->cmd_buffer[2] = 0; - hdw->cmd_buffer[3] = 0; - hdw->cmd_buffer[4] = 0; - hdw->cmd_buffer[5] = 0; - hdw->cmd_buffer[6] = (reg >> 8) & 0xff; - hdw->cmd_buffer[7] = reg & 0xff; - - ret |= pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 4); - *data = PVR2_COMPOSE_LE(hdw->cmd_buffer,0); - - LOCK_GIVE(hdw->ctl_lock); - - return ret; -} - - -void pvr2_hdw_render_useless(struct pvr2_hdw *hdw) -{ - if (!hdw->flag_ok) return; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Device being rendered inoperable"); - if (hdw->vid_stream) { - pvr2_stream_setup(hdw->vid_stream,NULL,0,0); - } - hdw->flag_ok = 0; - trace_stbit("flag_ok",hdw->flag_ok); - pvr2_hdw_state_sched(hdw); -} - - -void pvr2_hdw_device_reset(struct pvr2_hdw *hdw) -{ - int ret; - pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset..."); - ret = usb_lock_device_for_reset(hdw->usb_dev,NULL); - if (ret == 0) { - ret = usb_reset_device(hdw->usb_dev); - usb_unlock_device(hdw->usb_dev); - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to lock USB device ret=%d",ret); - } - if (init_pause_msec) { - pvr2_trace(PVR2_TRACE_INFO, - "Waiting %u msec for hardware to settle", - init_pause_msec); - msleep(init_pause_msec); - } - -} - - -void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val) -{ - char *da; - unsigned int pipe; - int ret; - - if (!hdw->usb_dev) return; - - da = kmalloc(16, GFP_KERNEL); - - if (da == NULL) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Unable to allocate memory to control CPU reset"); - return; - } - - pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val); - - da[0] = val ? 0x01 : 0x00; - - /* Write the CPUCS register on the 8051. The lsb of the register - is the reset bit; a 1 asserts reset while a 0 clears it. */ - pipe = usb_sndctrlpipe(hdw->usb_dev, 0); - ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,HZ); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "cpureset_assert(%d) error=%d",val,ret); - pvr2_hdw_render_useless(hdw); - } - - kfree(da); -} - - -int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw) -{ - return pvr2_issue_simple_cmd(hdw,FX2CMD_DEEP_RESET); -} - - -int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw) -{ - return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_ON); -} - - -int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw) -{ - return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_OFF); -} - - -int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) -{ - pvr2_trace(PVR2_TRACE_INIT, - "Requesting decoder reset"); - if (hdw->decoder_client_id) { - v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id, - core, reset, 0); - pvr2_hdw_cx25840_vbi_hack(hdw); - return 0; - } - pvr2_trace(PVR2_TRACE_INIT, - "Unable to reset decoder: nothing attached"); - return -ENOTTY; -} - - -static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff) -{ - hdw->flag_ok = !0; - return pvr2_issue_simple_cmd(hdw, - FX2CMD_HCW_DEMOD_RESETIN | - (1 << 8) | - ((onoff ? 1 : 0) << 16)); -} - - -static int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff) -{ - hdw->flag_ok = !0; - return pvr2_issue_simple_cmd(hdw,(onoff ? - FX2CMD_ONAIR_DTV_POWER_ON : - FX2CMD_ONAIR_DTV_POWER_OFF)); -} - - -static int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw, - int onoff) -{ - return pvr2_issue_simple_cmd(hdw,(onoff ? - FX2CMD_ONAIR_DTV_STREAMING_ON : - FX2CMD_ONAIR_DTV_STREAMING_OFF)); -} - - -static void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl) -{ - int cmode; - /* Compare digital/analog desired setting with current setting. If - they don't match, fix it... */ - cmode = (digitalFl ? PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG); - if (cmode == hdw->pathway_state) { - /* They match; nothing to do */ - return; - } - - switch (hdw->hdw_desc->digital_control_scheme) { - case PVR2_DIGITAL_SCHEME_HAUPPAUGE: - pvr2_hdw_cmd_hcw_demod_reset(hdw,digitalFl); - if (cmode == PVR2_PATHWAY_ANALOG) { - /* If moving to analog mode, also force the decoder - to reset. If no decoder is attached, then it's - ok to ignore this because if/when the decoder - attaches, it will reset itself at that time. */ - pvr2_hdw_cmd_decoder_reset(hdw); - } - break; - case PVR2_DIGITAL_SCHEME_ONAIR: - /* Supposedly we should always have the power on whether in - digital or analog mode. But for now do what appears to - work... */ - pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,digitalFl); - break; - default: break; - } - - pvr2_hdw_untrip_unlocked(hdw); - hdw->pathway_state = cmode; -} - - -static void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff) -{ - /* change some GPIO data - * - * note: bit d7 of dir appears to control the LED, - * so we shut it off here. - * - */ - if (onoff) { - pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000481); - } else { - pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000401); - } - pvr2_hdw_gpio_chg_out(hdw, 0xffffffff, 0x00000000); -} - - -typedef void (*led_method_func)(struct pvr2_hdw *,int); - -static led_method_func led_methods[] = { - [PVR2_LED_SCHEME_HAUPPAUGE] = pvr2_led_ctrl_hauppauge, -}; - - -/* Toggle LED */ -static void pvr2_led_ctrl(struct pvr2_hdw *hdw,int onoff) -{ - unsigned int scheme_id; - led_method_func fp; - - if ((!onoff) == (!hdw->led_on)) return; - - hdw->led_on = onoff != 0; - - scheme_id = hdw->hdw_desc->led_scheme; - if (scheme_id < ARRAY_SIZE(led_methods)) { - fp = led_methods[scheme_id]; - } else { - fp = NULL; - } - - if (fp) (*fp)(hdw,onoff); -} - - -/* Stop / start video stream transport */ -static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl) -{ - int ret; - - /* If we're in analog mode, then just issue the usual analog - command. */ - if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) { - return pvr2_issue_simple_cmd(hdw, - (runFl ? - FX2CMD_STREAMING_ON : - FX2CMD_STREAMING_OFF)); - /*Note: Not reached */ - } - - if (hdw->pathway_state != PVR2_PATHWAY_DIGITAL) { - /* Whoops, we don't know what mode we're in... */ - return -EINVAL; - } - - /* To get here we have to be in digital mode. The mechanism here - is unfortunately different for different vendors. So we switch - on the device's digital scheme attribute in order to figure out - what to do. */ - switch (hdw->hdw_desc->digital_control_scheme) { - case PVR2_DIGITAL_SCHEME_HAUPPAUGE: - return pvr2_issue_simple_cmd(hdw, - (runFl ? - FX2CMD_HCW_DTV_STREAMING_ON : - FX2CMD_HCW_DTV_STREAMING_OFF)); - case PVR2_DIGITAL_SCHEME_ONAIR: - ret = pvr2_issue_simple_cmd(hdw, - (runFl ? - FX2CMD_STREAMING_ON : - FX2CMD_STREAMING_OFF)); - if (ret) return ret; - return pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,runFl); - default: - return -EINVAL; - } -} - - -/* Evaluate whether or not state_pathway_ok can change */ -static int state_eval_pathway_ok(struct pvr2_hdw *hdw) -{ - if (hdw->state_pathway_ok) { - /* Nothing to do if pathway is already ok */ - return 0; - } - if (!hdw->state_pipeline_idle) { - /* Not allowed to change anything if pipeline is not idle */ - return 0; - } - pvr2_hdw_cmd_modeswitch(hdw,hdw->input_val == PVR2_CVAL_INPUT_DTV); - hdw->state_pathway_ok = !0; - trace_stbit("state_pathway_ok",hdw->state_pathway_ok); - return !0; -} - - -/* Evaluate whether or not state_encoder_ok can change */ -static int state_eval_encoder_ok(struct pvr2_hdw *hdw) -{ - if (hdw->state_encoder_ok) return 0; - if (hdw->flag_tripped) return 0; - if (hdw->state_encoder_run) return 0; - if (hdw->state_encoder_config) return 0; - if (hdw->state_decoder_run) return 0; - if (hdw->state_usbstream_run) return 0; - if (hdw->pathway_state == PVR2_PATHWAY_DIGITAL) { - if (!hdw->hdw_desc->flag_digital_requires_cx23416) return 0; - } else if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) { - return 0; - } - - if (pvr2_upload_firmware2(hdw) < 0) { - hdw->flag_tripped = !0; - trace_stbit("flag_tripped",hdw->flag_tripped); - return !0; - } - hdw->state_encoder_ok = !0; - trace_stbit("state_encoder_ok",hdw->state_encoder_ok); - return !0; -} - - -/* Evaluate whether or not state_encoder_config can change */ -static int state_eval_encoder_config(struct pvr2_hdw *hdw) -{ - if (hdw->state_encoder_config) { - if (hdw->state_encoder_ok) { - if (hdw->state_pipeline_req && - !hdw->state_pipeline_pause) return 0; - } - hdw->state_encoder_config = 0; - hdw->state_encoder_waitok = 0; - trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); - /* paranoia - solve race if timer just completed */ - del_timer_sync(&hdw->encoder_wait_timer); - } else { - if (!hdw->state_pathway_ok || - (hdw->pathway_state != PVR2_PATHWAY_ANALOG) || - !hdw->state_encoder_ok || - !hdw->state_pipeline_idle || - hdw->state_pipeline_pause || - !hdw->state_pipeline_req || - !hdw->state_pipeline_config) { - /* We must reset the enforced wait interval if - anything has happened that might have disturbed - the encoder. This should be a rare case. */ - if (timer_pending(&hdw->encoder_wait_timer)) { - del_timer_sync(&hdw->encoder_wait_timer); - } - if (hdw->state_encoder_waitok) { - /* Must clear the state - therefore we did - something to a state bit and must also - return true. */ - hdw->state_encoder_waitok = 0; - trace_stbit("state_encoder_waitok", - hdw->state_encoder_waitok); - return !0; - } - return 0; - } - if (!hdw->state_encoder_waitok) { - if (!timer_pending(&hdw->encoder_wait_timer)) { - /* waitok flag wasn't set and timer isn't - running. Check flag once more to avoid - a race then start the timer. This is - the point when we measure out a minimal - quiet interval before doing something to - the encoder. */ - if (!hdw->state_encoder_waitok) { - hdw->encoder_wait_timer.expires = - jiffies + - (HZ * TIME_MSEC_ENCODER_WAIT - / 1000); - add_timer(&hdw->encoder_wait_timer); - } - } - /* We can't continue until we know we have been - quiet for the interval measured by this - timer. */ - return 0; - } - pvr2_encoder_configure(hdw); - if (hdw->state_encoder_ok) hdw->state_encoder_config = !0; - } - trace_stbit("state_encoder_config",hdw->state_encoder_config); - return !0; -} - - -/* Return true if the encoder should not be running. */ -static int state_check_disable_encoder_run(struct pvr2_hdw *hdw) -{ - if (!hdw->state_encoder_ok) { - /* Encoder isn't healthy at the moment, so stop it. */ - return !0; - } - if (!hdw->state_pathway_ok) { - /* Mode is not understood at the moment (i.e. it wants to - change), so encoder must be stopped. */ - return !0; - } - - switch (hdw->pathway_state) { - case PVR2_PATHWAY_ANALOG: - if (!hdw->state_decoder_run) { - /* We're in analog mode and the decoder is not - running; thus the encoder should be stopped as - well. */ - return !0; - } - break; - case PVR2_PATHWAY_DIGITAL: - if (hdw->state_encoder_runok) { - /* This is a funny case. We're in digital mode so - really the encoder should be stopped. However - if it really is running, only kill it after - runok has been set. This gives a chance for the - onair quirk to function (encoder must run - briefly first, at least once, before onair - digital streaming can work). */ - return !0; - } - break; - default: - /* Unknown mode; so encoder should be stopped. */ - return !0; - } - - /* If we get here, we haven't found a reason to stop the - encoder. */ - return 0; -} - - -/* Return true if the encoder should be running. */ -static int state_check_enable_encoder_run(struct pvr2_hdw *hdw) -{ - if (!hdw->state_encoder_ok) { - /* Don't run the encoder if it isn't healthy... */ - return 0; - } - if (!hdw->state_pathway_ok) { - /* Don't run the encoder if we don't (yet) know what mode - we need to be in... */ - return 0; - } - - switch (hdw->pathway_state) { - case PVR2_PATHWAY_ANALOG: - if (hdw->state_decoder_run && hdw->state_decoder_ready) { - /* In analog mode, if the decoder is running, then - run the encoder. */ - return !0; - } - break; - case PVR2_PATHWAY_DIGITAL: - if ((hdw->hdw_desc->digital_control_scheme == - PVR2_DIGITAL_SCHEME_ONAIR) && - !hdw->state_encoder_runok) { - /* This is a quirk. OnAir hardware won't stream - digital until the encoder has been run at least - once, for a minimal period of time (empiricially - measured to be 1/4 second). So if we're on - OnAir hardware and the encoder has never been - run at all, then start the encoder. Normal - state machine logic in the driver will - automatically handle the remaining bits. */ - return !0; - } - break; - default: - /* For completeness (unknown mode; encoder won't run ever) */ - break; - } - /* If we get here, then we haven't found any reason to run the - encoder, so don't run it. */ - return 0; -} - - -/* Evaluate whether or not state_encoder_run can change */ -static int state_eval_encoder_run(struct pvr2_hdw *hdw) -{ - if (hdw->state_encoder_run) { - if (!state_check_disable_encoder_run(hdw)) return 0; - if (hdw->state_encoder_ok) { - del_timer_sync(&hdw->encoder_run_timer); - if (pvr2_encoder_stop(hdw) < 0) return !0; - } - hdw->state_encoder_run = 0; - } else { - if (!state_check_enable_encoder_run(hdw)) return 0; - if (pvr2_encoder_start(hdw) < 0) return !0; - hdw->state_encoder_run = !0; - if (!hdw->state_encoder_runok) { - hdw->encoder_run_timer.expires = - jiffies + (HZ * TIME_MSEC_ENCODER_OK / 1000); - add_timer(&hdw->encoder_run_timer); - } - } - trace_stbit("state_encoder_run",hdw->state_encoder_run); - return !0; -} - - -/* Timeout function for quiescent timer. */ -static void pvr2_hdw_quiescent_timeout(unsigned long data) -{ - struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; - hdw->state_decoder_quiescent = !0; - trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); - hdw->state_stale = !0; - queue_work(hdw->workqueue,&hdw->workpoll); -} - - -/* Timeout function for decoder stabilization timer. */ -static void pvr2_hdw_decoder_stabilization_timeout(unsigned long data) -{ - struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; - hdw->state_decoder_ready = !0; - trace_stbit("state_decoder_ready", hdw->state_decoder_ready); - hdw->state_stale = !0; - queue_work(hdw->workqueue, &hdw->workpoll); -} - - -/* Timeout function for encoder wait timer. */ -static void pvr2_hdw_encoder_wait_timeout(unsigned long data) -{ - struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; - hdw->state_encoder_waitok = !0; - trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); - hdw->state_stale = !0; - queue_work(hdw->workqueue,&hdw->workpoll); -} - - -/* Timeout function for encoder run timer. */ -static void pvr2_hdw_encoder_run_timeout(unsigned long data) -{ - struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; - if (!hdw->state_encoder_runok) { - hdw->state_encoder_runok = !0; - trace_stbit("state_encoder_runok",hdw->state_encoder_runok); - hdw->state_stale = !0; - queue_work(hdw->workqueue,&hdw->workpoll); - } -} - - -/* Evaluate whether or not state_decoder_run can change */ -static int state_eval_decoder_run(struct pvr2_hdw *hdw) -{ - if (hdw->state_decoder_run) { - if (hdw->state_encoder_ok) { - if (hdw->state_pipeline_req && - !hdw->state_pipeline_pause && - hdw->state_pathway_ok) return 0; - } - if (!hdw->flag_decoder_missed) { - pvr2_decoder_enable(hdw,0); - } - hdw->state_decoder_quiescent = 0; - hdw->state_decoder_run = 0; - /* paranoia - solve race if timer(s) just completed */ - del_timer_sync(&hdw->quiescent_timer); - /* Kill the stabilization timer, in case we're killing the - encoder before the previous stabilization interval has - been properly timed. */ - del_timer_sync(&hdw->decoder_stabilization_timer); - hdw->state_decoder_ready = 0; - } else { - if (!hdw->state_decoder_quiescent) { - if (!timer_pending(&hdw->quiescent_timer)) { - /* We don't do something about the - quiescent timer until right here because - we also want to catch cases where the - decoder was already not running (like - after initialization) as opposed to - knowing that we had just stopped it. - The second flag check is here to cover a - race - the timer could have run and set - this flag just after the previous check - but before we did the pending check. */ - if (!hdw->state_decoder_quiescent) { - hdw->quiescent_timer.expires = - jiffies + - (HZ * TIME_MSEC_DECODER_WAIT - / 1000); - add_timer(&hdw->quiescent_timer); - } - } - /* Don't allow decoder to start again until it has - been quiesced first. This little detail should - hopefully further stabilize the encoder. */ - return 0; - } - if (!hdw->state_pathway_ok || - (hdw->pathway_state != PVR2_PATHWAY_ANALOG) || - !hdw->state_pipeline_req || - hdw->state_pipeline_pause || - !hdw->state_pipeline_config || - !hdw->state_encoder_config || - !hdw->state_encoder_ok) return 0; - del_timer_sync(&hdw->quiescent_timer); - if (hdw->flag_decoder_missed) return 0; - if (pvr2_decoder_enable(hdw,!0) < 0) return 0; - hdw->state_decoder_quiescent = 0; - hdw->state_decoder_ready = 0; - hdw->state_decoder_run = !0; - if (hdw->decoder_client_id == PVR2_CLIENT_ID_SAA7115) { - hdw->decoder_stabilization_timer.expires = - jiffies + - (HZ * TIME_MSEC_DECODER_STABILIZATION_WAIT / - 1000); - add_timer(&hdw->decoder_stabilization_timer); - } else { - hdw->state_decoder_ready = !0; - } - } - trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); - trace_stbit("state_decoder_run",hdw->state_decoder_run); - trace_stbit("state_decoder_ready", hdw->state_decoder_ready); - return !0; -} - - -/* Evaluate whether or not state_usbstream_run can change */ -static int state_eval_usbstream_run(struct pvr2_hdw *hdw) -{ - if (hdw->state_usbstream_run) { - int fl = !0; - if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) { - fl = (hdw->state_encoder_ok && - hdw->state_encoder_run); - } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) && - (hdw->hdw_desc->flag_digital_requires_cx23416)) { - fl = hdw->state_encoder_ok; - } - if (fl && - hdw->state_pipeline_req && - !hdw->state_pipeline_pause && - hdw->state_pathway_ok) { - return 0; - } - pvr2_hdw_cmd_usbstream(hdw,0); - hdw->state_usbstream_run = 0; - } else { - if (!hdw->state_pipeline_req || - hdw->state_pipeline_pause || - !hdw->state_pathway_ok) return 0; - if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) { - if (!hdw->state_encoder_ok || - !hdw->state_encoder_run) return 0; - } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) && - (hdw->hdw_desc->flag_digital_requires_cx23416)) { - if (!hdw->state_encoder_ok) return 0; - if (hdw->state_encoder_run) return 0; - if (hdw->hdw_desc->digital_control_scheme == - PVR2_DIGITAL_SCHEME_ONAIR) { - /* OnAir digital receivers won't stream - unless the analog encoder has run first. - Why? I have no idea. But don't even - try until we know the analog side is - known to have run. */ - if (!hdw->state_encoder_runok) return 0; - } - } - if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0; - hdw->state_usbstream_run = !0; - } - trace_stbit("state_usbstream_run",hdw->state_usbstream_run); - return !0; -} - - -/* Attempt to configure pipeline, if needed */ -static int state_eval_pipeline_config(struct pvr2_hdw *hdw) -{ - if (hdw->state_pipeline_config || - hdw->state_pipeline_pause) return 0; - pvr2_hdw_commit_execute(hdw); - return !0; -} - - -/* Update pipeline idle and pipeline pause tracking states based on other - inputs. This must be called whenever the other relevant inputs have - changed. */ -static int state_update_pipeline_state(struct pvr2_hdw *hdw) -{ - unsigned int st; - int updatedFl = 0; - /* Update pipeline state */ - st = !(hdw->state_encoder_run || - hdw->state_decoder_run || - hdw->state_usbstream_run || - (!hdw->state_decoder_quiescent)); - if (!st != !hdw->state_pipeline_idle) { - hdw->state_pipeline_idle = st; - updatedFl = !0; - } - if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) { - hdw->state_pipeline_pause = 0; - updatedFl = !0; - } - return updatedFl; -} - - -typedef int (*state_eval_func)(struct pvr2_hdw *); - -/* Set of functions to be run to evaluate various states in the driver. */ -static const state_eval_func eval_funcs[] = { - state_eval_pathway_ok, - state_eval_pipeline_config, - state_eval_encoder_ok, - state_eval_encoder_config, - state_eval_decoder_run, - state_eval_encoder_run, - state_eval_usbstream_run, -}; - - -/* Process various states and return true if we did anything interesting. */ -static int pvr2_hdw_state_update(struct pvr2_hdw *hdw) -{ - unsigned int i; - int state_updated = 0; - int check_flag; - - if (!hdw->state_stale) return 0; - if ((hdw->fw1_state != FW1_STATE_OK) || - !hdw->flag_ok) { - hdw->state_stale = 0; - return !0; - } - /* This loop is the heart of the entire driver. It keeps trying to - evaluate various bits of driver state until nothing changes for - one full iteration. Each "bit of state" tracks some global - aspect of the driver, e.g. whether decoder should run, if - pipeline is configured, usb streaming is on, etc. We separately - evaluate each of those questions based on other driver state to - arrive at the correct running configuration. */ - do { - check_flag = 0; - state_update_pipeline_state(hdw); - /* Iterate over each bit of state */ - for (i = 0; (iflag_ok; i++) { - if ((*eval_funcs[i])(hdw)) { - check_flag = !0; - state_updated = !0; - state_update_pipeline_state(hdw); - } - } - } while (check_flag && hdw->flag_ok); - hdw->state_stale = 0; - trace_stbit("state_stale",hdw->state_stale); - return state_updated; -} - - -static unsigned int print_input_mask(unsigned int msk, - char *buf,unsigned int acnt) -{ - unsigned int idx,ccnt; - unsigned int tcnt = 0; - for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) { - if (!((1 << idx) & msk)) continue; - ccnt = scnprintf(buf+tcnt, - acnt-tcnt, - "%s%s", - (tcnt ? ", " : ""), - control_values_input[idx]); - tcnt += ccnt; - } - return tcnt; -} - - -static const char *pvr2_pathway_state_name(int id) -{ - switch (id) { - case PVR2_PATHWAY_ANALOG: return "analog"; - case PVR2_PATHWAY_DIGITAL: return "digital"; - default: return "unknown"; - } -} - - -static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, - char *buf,unsigned int acnt) -{ - switch (which) { - case 0: - return scnprintf( - buf,acnt, - "driver:%s%s%s%s%s ", - (hdw->flag_ok ? " " : " "), - (hdw->flag_init_ok ? " " : " "), - (hdw->flag_disconnected ? " " : - " "), - (hdw->flag_tripped ? " " : ""), - (hdw->flag_decoder_missed ? " " : ""), - pvr2_pathway_state_name(hdw->pathway_state)); - - case 1: - return scnprintf( - buf,acnt, - "pipeline:%s%s%s%s", - (hdw->state_pipeline_idle ? " " : ""), - (hdw->state_pipeline_config ? - " " : " "), - (hdw->state_pipeline_req ? " " : ""), - (hdw->state_pipeline_pause ? " " : "")); - case 2: - return scnprintf( - buf,acnt, - "worker:%s%s%s%s%s%s%s", - (hdw->state_decoder_run ? - (hdw->state_decoder_ready ? - "" : " ") : - (hdw->state_decoder_quiescent ? - "" : " ")), - (hdw->state_decoder_quiescent ? - " " : ""), - (hdw->state_encoder_ok ? - "" : " "), - (hdw->state_encoder_run ? - (hdw->state_encoder_runok ? - " " : - " ") : - (hdw->state_encoder_runok ? - " " : - " ")), - (hdw->state_encoder_config ? - " " : - (hdw->state_encoder_waitok ? - "" : " ")), - (hdw->state_usbstream_run ? - " " : " "), - (hdw->state_pathway_ok ? - " " : "")); - case 3: - return scnprintf( - buf,acnt, - "state: %s", - pvr2_get_state_name(hdw->master_state)); - case 4: { - unsigned int tcnt = 0; - unsigned int ccnt; - - ccnt = scnprintf(buf, - acnt, - "Hardware supported inputs: "); - tcnt += ccnt; - tcnt += print_input_mask(hdw->input_avail_mask, - buf+tcnt, - acnt-tcnt); - if (hdw->input_avail_mask != hdw->input_allowed_mask) { - ccnt = scnprintf(buf+tcnt, - acnt-tcnt, - "; allowed inputs: "); - tcnt += ccnt; - tcnt += print_input_mask(hdw->input_allowed_mask, - buf+tcnt, - acnt-tcnt); - } - return tcnt; - } - case 5: { - struct pvr2_stream_stats stats; - if (!hdw->vid_stream) break; - pvr2_stream_get_stats(hdw->vid_stream, - &stats, - 0); - return scnprintf( - buf,acnt, - "Bytes streamed=%u" - " URBs: queued=%u idle=%u ready=%u" - " processed=%u failed=%u", - stats.bytes_processed, - stats.buffers_in_queue, - stats.buffers_in_idle, - stats.buffers_in_ready, - stats.buffers_processed, - stats.buffers_failed); - } - case 6: { - unsigned int id = hdw->ir_scheme_active; - return scnprintf(buf, acnt, "ir scheme: id=%d %s", id, - (id >= ARRAY_SIZE(ir_scheme_names) ? - "?" : ir_scheme_names[id])); - } - default: break; - } - return 0; -} - - -/* Generate report containing info about attached sub-devices and attached - i2c clients, including an indication of which attached i2c clients are - actually sub-devices. */ -static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw, - char *buf, unsigned int acnt) -{ - struct v4l2_subdev *sd; - unsigned int tcnt = 0; - unsigned int ccnt; - struct i2c_client *client; - const char *p; - unsigned int id; - - ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers and I2C clients:\n"); - tcnt += ccnt; - v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { - id = sd->grp_id; - p = NULL; - if (id < ARRAY_SIZE(module_names)) p = module_names[id]; - if (p) { - ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s:", p); - tcnt += ccnt; - } else { - ccnt = scnprintf(buf + tcnt, acnt - tcnt, - " (unknown id=%u):", id); - tcnt += ccnt; - } - client = v4l2_get_subdevdata(sd); - if (client) { - ccnt = scnprintf(buf + tcnt, acnt - tcnt, - " %s @ %02x\n", client->name, - client->addr); - tcnt += ccnt; - } else { - ccnt = scnprintf(buf + tcnt, acnt - tcnt, - " no i2c client\n"); - tcnt += ccnt; - } - } - return tcnt; -} - - -unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, - char *buf,unsigned int acnt) -{ - unsigned int bcnt,ccnt,idx; - bcnt = 0; - LOCK_TAKE(hdw->big_lock); - for (idx = 0; ; idx++) { - ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt); - if (!ccnt) break; - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - if (!acnt) break; - buf[0] = '\n'; ccnt = 1; - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - } - ccnt = pvr2_hdw_report_clients(hdw, buf, acnt); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - LOCK_GIVE(hdw->big_lock); - return bcnt; -} - - -static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw) -{ - char buf[256]; - unsigned int idx, ccnt; - unsigned int lcnt, ucnt; - - for (idx = 0; ; idx++) { - ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf)); - if (!ccnt) break; - printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf); - } - ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf)); - ucnt = 0; - while (ucnt < ccnt) { - lcnt = 0; - while ((lcnt + ucnt < ccnt) && (buf[lcnt + ucnt] != '\n')) { - lcnt++; - } - printk(KERN_INFO "%s %.*s\n", hdw->name, lcnt, buf + ucnt); - ucnt += lcnt + 1; - } -} - - -/* Evaluate and update the driver's current state, taking various actions - as appropriate for the update. */ -static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw) -{ - unsigned int st; - int state_updated = 0; - int callback_flag = 0; - int analog_mode; - - pvr2_trace(PVR2_TRACE_STBITS, - "Drive state check START"); - if (pvrusb2_debug & PVR2_TRACE_STBITS) { - pvr2_hdw_state_log_state(hdw); - } - - /* Process all state and get back over disposition */ - state_updated = pvr2_hdw_state_update(hdw); - - analog_mode = (hdw->pathway_state != PVR2_PATHWAY_DIGITAL); - - /* Update master state based upon all other states. */ - if (!hdw->flag_ok) { - st = PVR2_STATE_DEAD; - } else if (hdw->fw1_state != FW1_STATE_OK) { - st = PVR2_STATE_COLD; - } else if ((analog_mode || - hdw->hdw_desc->flag_digital_requires_cx23416) && - !hdw->state_encoder_ok) { - st = PVR2_STATE_WARM; - } else if (hdw->flag_tripped || - (analog_mode && hdw->flag_decoder_missed)) { - st = PVR2_STATE_ERROR; - } else if (hdw->state_usbstream_run && - (!analog_mode || - (hdw->state_encoder_run && hdw->state_decoder_run))) { - st = PVR2_STATE_RUN; - } else { - st = PVR2_STATE_READY; - } - if (hdw->master_state != st) { - pvr2_trace(PVR2_TRACE_STATE, - "Device state change from %s to %s", - pvr2_get_state_name(hdw->master_state), - pvr2_get_state_name(st)); - pvr2_led_ctrl(hdw,st == PVR2_STATE_RUN); - hdw->master_state = st; - state_updated = !0; - callback_flag = !0; - } - if (state_updated) { - /* Trigger anyone waiting on any state changes here. */ - wake_up(&hdw->state_wait_data); - } - - if (pvrusb2_debug & PVR2_TRACE_STBITS) { - pvr2_hdw_state_log_state(hdw); - } - pvr2_trace(PVR2_TRACE_STBITS, - "Drive state check DONE callback=%d",callback_flag); - - return callback_flag; -} - - -/* Cause kernel thread to check / update driver state */ -static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw) -{ - if (hdw->state_stale) return; - hdw->state_stale = !0; - trace_stbit("state_stale",hdw->state_stale); - queue_work(hdw->workqueue,&hdw->workpoll); -} - - -int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp) -{ - return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp); -} - - -int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *dp) -{ - return pvr2_read_register(hdw,PVR2_GPIO_OUT,dp); -} - - -int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *dp) -{ - return pvr2_read_register(hdw,PVR2_GPIO_IN,dp); -} - - -int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val) -{ - u32 cval,nval; - int ret; - if (~msk) { - ret = pvr2_read_register(hdw,PVR2_GPIO_DIR,&cval); - if (ret) return ret; - nval = (cval & ~msk) | (val & msk); - pvr2_trace(PVR2_TRACE_GPIO, - "GPIO direction changing 0x%x:0x%x" - " from 0x%x to 0x%x", - msk,val,cval,nval); - } else { - nval = val; - pvr2_trace(PVR2_TRACE_GPIO, - "GPIO direction changing to 0x%x",nval); - } - return pvr2_write_register(hdw,PVR2_GPIO_DIR,nval); -} - - -int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val) -{ - u32 cval,nval; - int ret; - if (~msk) { - ret = pvr2_read_register(hdw,PVR2_GPIO_OUT,&cval); - if (ret) return ret; - nval = (cval & ~msk) | (val & msk); - pvr2_trace(PVR2_TRACE_GPIO, - "GPIO output changing 0x%x:0x%x from 0x%x to 0x%x", - msk,val,cval,nval); - } else { - nval = val; - pvr2_trace(PVR2_TRACE_GPIO, - "GPIO output changing to 0x%x",nval); - } - return pvr2_write_register(hdw,PVR2_GPIO_OUT,nval); -} - - -void pvr2_hdw_status_poll(struct pvr2_hdw *hdw) -{ - struct v4l2_tuner *vtp = &hdw->tuner_signal_info; - memset(vtp, 0, sizeof(*vtp)); - hdw->tuner_signal_stale = 0; - /* Note: There apparently is no replacement for VIDIOC_CROPCAP - using v4l2-subdev - therefore we can't support that AT ALL right - now. (Of course, no sub-drivers seem to implement it either. - But now it's a a chicken and egg problem...) */ - v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner, vtp); - pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll" - " type=%u strength=%u audio=0x%x cap=0x%x" - " low=%u hi=%u", - vtp->type, - vtp->signal, vtp->rxsubchans, vtp->capability, - vtp->rangelow, vtp->rangehigh); - - /* We have to do this to avoid getting into constant polling if - there's nobody to answer a poll of cropcap info. */ - hdw->cropcap_stale = 0; -} - - -unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw) -{ - return hdw->input_avail_mask; -} - - -unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw) -{ - return hdw->input_allowed_mask; -} - - -static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v) -{ - if (hdw->input_val != v) { - hdw->input_val = v; - hdw->input_dirty = !0; - } - - /* Handle side effects - if we switch to a mode that needs the RF - tuner, then select the right frequency choice as well and mark - it dirty. */ - if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { - hdw->freqSelector = 0; - hdw->freqDirty = !0; - } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) || - (hdw->input_val == PVR2_CVAL_INPUT_DTV)) { - hdw->freqSelector = 1; - hdw->freqDirty = !0; - } - return 0; -} - - -int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw, - unsigned int change_mask, - unsigned int change_val) -{ - int ret = 0; - unsigned int nv,m,idx; - LOCK_TAKE(hdw->big_lock); - do { - nv = hdw->input_allowed_mask & ~change_mask; - nv |= (change_val & change_mask); - nv &= hdw->input_avail_mask; - if (!nv) { - /* No legal modes left; return error instead. */ - ret = -EPERM; - break; - } - hdw->input_allowed_mask = nv; - if ((1 << hdw->input_val) & hdw->input_allowed_mask) { - /* Current mode is still in the allowed mask, so - we're done. */ - break; - } - /* Select and switch to a mode that is still in the allowed - mask */ - if (!hdw->input_allowed_mask) { - /* Nothing legal; give up */ - break; - } - m = hdw->input_allowed_mask; - for (idx = 0; idx < (sizeof(m) << 3); idx++) { - if (!((1 << idx) & m)) continue; - pvr2_hdw_set_input(hdw,idx); - break; - } - } while (0); - LOCK_GIVE(hdw->big_lock); - return ret; -} - - -/* Find I2C address of eeprom */ -static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) -{ - int result; - LOCK_TAKE(hdw->ctl_lock); do { - hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR; - result = pvr2_send_request(hdw, - hdw->cmd_buffer,1, - hdw->cmd_buffer,1); - if (result < 0) break; - result = hdw->cmd_buffer[0]; - } while(0); LOCK_GIVE(hdw->ctl_lock); - return result; -} - - -int pvr2_hdw_register_access(struct pvr2_hdw *hdw, - struct v4l2_dbg_match *match, u64 reg_id, - int setFl, u64 *val_ptr) -{ -#ifdef CONFIG_VIDEO_ADV_DEBUG - struct v4l2_dbg_register req; - int stat = 0; - int okFl = 0; - - if (!capable(CAP_SYS_ADMIN)) return -EPERM; - - req.match = *match; - req.reg = reg_id; - if (setFl) req.val = *val_ptr; - /* It would be nice to know if a sub-device answered the request */ - v4l2_device_call_all(&hdw->v4l2_dev, 0, core, g_register, &req); - if (!setFl) *val_ptr = req.val; - if (okFl) { - return stat; - } - return -EINVAL; -#else - return -ENOSYS; -#endif -} - - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,364 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_HDW_H -#define __PVRUSB2_HDW_H - -#include -#include -#include "pvrusb2-io.h" -#include "pvrusb2-ctrl.h" - - -/* Private internal control ids, look these up with - pvr2_hdw_get_ctrl_by_id() - these are NOT visible in V4L */ -#define PVR2_CID_STDENUM 1 -#define PVR2_CID_STDCUR 2 -#define PVR2_CID_STDAVAIL 3 -#define PVR2_CID_INPUT 4 -#define PVR2_CID_AUDIOMODE 5 -#define PVR2_CID_FREQUENCY 6 -#define PVR2_CID_HRES 7 -#define PVR2_CID_VRES 8 -#define PVR2_CID_CROPL 9 -#define PVR2_CID_CROPT 10 -#define PVR2_CID_CROPW 11 -#define PVR2_CID_CROPH 12 -#define PVR2_CID_CROPCAPPAN 13 -#define PVR2_CID_CROPCAPPAD 14 -#define PVR2_CID_CROPCAPBL 15 -#define PVR2_CID_CROPCAPBT 16 -#define PVR2_CID_CROPCAPBW 17 -#define PVR2_CID_CROPCAPBH 18 - -/* Legal values for the INPUT state variable */ -#define PVR2_CVAL_INPUT_TV 0 -#define PVR2_CVAL_INPUT_DTV 1 -#define PVR2_CVAL_INPUT_COMPOSITE 2 -#define PVR2_CVAL_INPUT_SVIDEO 3 -#define PVR2_CVAL_INPUT_RADIO 4 - -enum pvr2_config { - pvr2_config_empty, /* No configuration */ - pvr2_config_mpeg, /* Encoded / compressed video */ - pvr2_config_vbi, /* Standard vbi info */ - pvr2_config_pcm, /* Audio raw pcm stream */ - pvr2_config_rawvideo, /* Video raw frames */ -}; - -enum pvr2_v4l_type { - pvr2_v4l_type_video, - pvr2_v4l_type_vbi, - pvr2_v4l_type_radio, -}; - -/* Major states that we can be in: - * - * DEAD - Device is in an unusable state and cannot be recovered. This - * can happen if we completely lose the ability to communicate with it - * (but it might still on the bus). In this state there's nothing we can - * do; it must be replugged in order to recover. - * - * COLD - Device is in an unusuable state, needs microcontroller firmware. - * - * WARM - We can communicate with the device and the proper - * microcontroller firmware is running, but other device initialization is - * still needed (e.g. encoder firmware). - * - * ERROR - A problem prevents capture operation (e.g. encoder firmware - * missing). - * - * READY - Device is operational, but not streaming. - * - * RUN - Device is streaming. - * - */ -#define PVR2_STATE_NONE 0 -#define PVR2_STATE_DEAD 1 -#define PVR2_STATE_COLD 2 -#define PVR2_STATE_WARM 3 -#define PVR2_STATE_ERROR 4 -#define PVR2_STATE_READY 5 -#define PVR2_STATE_RUN 6 - -/* Translate configuration enum to a string label */ -const char *pvr2_config_get_name(enum pvr2_config); - -struct pvr2_hdw; - -/* Create and return a structure for interacting with the underlying - hardware */ -struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, - const struct usb_device_id *devid); - -/* Perform second stage initialization, passing in a notification callback - for when the master state changes. */ -int pvr2_hdw_initialize(struct pvr2_hdw *, - void (*callback_func)(void *), - void *callback_data); - -/* Destroy hardware interaction structure */ -void pvr2_hdw_destroy(struct pvr2_hdw *); - -/* Return true if in the ready (normal) state */ -int pvr2_hdw_dev_ok(struct pvr2_hdw *); - -/* Return small integer number [1..N] for logical instance number of this - device. This is useful for indexing array-valued module parameters. */ -int pvr2_hdw_get_unit_number(struct pvr2_hdw *); - -/* Get pointer to underlying USB device */ -struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *); - -/* Retrieve serial number of device */ -unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *); - -/* Retrieve bus location info of device */ -const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *); - -/* Retrieve per-instance string identifier for this specific device */ -const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *); - -/* Called when hardware has been unplugged */ -void pvr2_hdw_disconnect(struct pvr2_hdw *); - -/* Get the number of defined controls */ -unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *); - -/* Retrieve a control handle given its index (0..count-1) */ -struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *,unsigned int); - -/* Retrieve a control handle given its internal ID (if any) */ -struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *,unsigned int); - -/* Retrieve a control handle given its V4L ID (if any) */ -struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *,unsigned int ctl_id); - -/* Retrieve a control handle given its immediate predecessor V4L ID (if any) */ -struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *, - unsigned int ctl_id); - -/* Commit all control changes made up to this point */ -int pvr2_hdw_commit_ctl(struct pvr2_hdw *); - -/* Return a bit mask of valid input selections for this device. Mask bits - * will be according to PVR_CVAL_INPUT_xxxx definitions. */ -unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *); - -/* Return a bit mask of allowed input selections for this device. Mask bits - * will be according to PVR_CVAL_INPUT_xxxx definitions. */ -unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *); - -/* Change the set of allowed input selections for this device. Both - change_mask and change_valu are mask bits according to - PVR_CVAL_INPUT_xxxx definitions. The change_mask parameter indicate - which settings are being changed and the change_val parameter indicates - whether corresponding settings are being set or cleared. */ -int pvr2_hdw_set_input_allowed(struct pvr2_hdw *, - unsigned int change_mask, - unsigned int change_val); - -/* Return name for this driver instance */ -const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *); - -/* Mark tuner status stale so that it will be re-fetched */ -void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *); - -/* Return information about the tuner */ -int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *); - -/* Return information about cropping capabilities */ -int pvr2_hdw_get_cropcap(struct pvr2_hdw *, struct v4l2_cropcap *); - -/* Query device and see if it thinks it is on a high-speed USB link */ -int pvr2_hdw_is_hsm(struct pvr2_hdw *); - -/* Return a string token representative of the hardware type */ -const char *pvr2_hdw_get_type(struct pvr2_hdw *); - -/* Return a single line description of the hardware type */ -const char *pvr2_hdw_get_desc(struct pvr2_hdw *); - -/* Turn streaming on/off */ -int pvr2_hdw_set_streaming(struct pvr2_hdw *,int); - -/* Find out if streaming is on */ -int pvr2_hdw_get_streaming(struct pvr2_hdw *); - -/* Retrieve driver overall state */ -int pvr2_hdw_get_state(struct pvr2_hdw *); - -/* Configure the type of stream to generate */ -int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config); - -/* Get handle to video output stream */ -struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *); - -/* Emit a video standard struct */ -int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std, - unsigned int idx); - -/* Enable / disable retrieval of CPU firmware or prom contents. This must - be enabled before pvr2_hdw_cpufw_get() will function. Note that doing - this may prevent the device from running (and leaving this mode may - imply a device reset). */ -void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, - int mode, /* 0=8KB FX2, 1=16KB FX2, 2=PROM */ - int enable_flag); - -/* Return true if we're in a mode for retrieval CPU firmware */ -int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *); - -/* Retrieve a piece of the CPU's firmware at the given offset. Return - value is the number of bytes retrieved or zero if we're past the end or - an error otherwise (e.g. if firmware retrieval is not enabled). */ -int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs, - char *buf,unsigned int cnt); - -/* Retrieve a previously stored v4l minor device number */ -int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *,enum pvr2_v4l_type index); - -/* Store a v4l minor device number */ -void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *, - enum pvr2_v4l_type index,int); - -/* Direct read/write access to chip's registers: - match - specify criteria to identify target chip (this is a v4l dbg struct) - reg_id - register number to access - setFl - true to set the register, false to read it - val_ptr - storage location for source / result. */ -int pvr2_hdw_register_access(struct pvr2_hdw *, - struct v4l2_dbg_match *match, u64 reg_id, - int setFl, u64 *val_ptr); - -/* The following entry points are all lower level things you normally don't - want to worry about. */ - -/* Issue a command and get a response from the device. LOTS of higher - level stuff is built on this. */ -int pvr2_send_request(struct pvr2_hdw *, - void *write_ptr,unsigned int write_len, - void *read_ptr,unsigned int read_len); - -/* Slightly higher level device communication functions. */ -int pvr2_write_register(struct pvr2_hdw *, u16, u32); - -/* Call if for any reason we can't talk to the hardware anymore - this will - cause the driver to stop flailing on the device. */ -void pvr2_hdw_render_useless(struct pvr2_hdw *); - -/* Set / clear 8051's reset bit */ -void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int); - -/* Execute a USB-commanded device reset */ -void pvr2_hdw_device_reset(struct pvr2_hdw *); - -/* Reset worker's error trapping circuit breaker */ -int pvr2_hdw_untrip(struct pvr2_hdw *); - -/* Execute hard reset command (after this point it's likely that the - encoder will have to be reconfigured). This also clears the "useless" - state. */ -int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *); - -/* Execute simple reset command */ -int pvr2_hdw_cmd_powerup(struct pvr2_hdw *); - -/* suspend */ -int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *); - -/* Order decoder to reset */ -int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *); - -/* Direct manipulation of GPIO bits */ -int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *); -int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *); -int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *); -int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val); -int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val); - -/* This data structure is specifically for the next function... */ -struct pvr2_hdw_debug_info { - int big_lock_held; - int ctl_lock_held; - int flag_disconnected; - int flag_init_ok; - int flag_ok; - int fw1_state; - int flag_decoder_missed; - int flag_tripped; - int state_encoder_ok; - int state_encoder_run; - int state_decoder_run; - int state_decoder_ready; - int state_usbstream_run; - int state_decoder_quiescent; - int state_pipeline_config; - int state_pipeline_req; - int state_pipeline_pause; - int state_pipeline_idle; - int cmd_debug_state; - int cmd_debug_write_len; - int cmd_debug_read_len; - int cmd_debug_write_pend; - int cmd_debug_read_pend; - int cmd_debug_timeout; - int cmd_debug_rstatus; - int cmd_debug_wstatus; - unsigned char cmd_code; -}; - -/* Non-intrusively retrieve internal state info - this is useful for - diagnosing lockups. Note that this operation is completed without any - kind of locking and so it is not atomic and may yield inconsistent - results. This is *purely* a debugging aid. */ -void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *); - -/* Intrusively retrieve internal state info - this is useful for - diagnosing overall driver state. This operation synchronizes against - the overall driver mutex - so if there are locking problems this will - likely hang! This is *purely* a debugging aid. */ -void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *); - -/* Report out several lines of text that describes driver internal state. - Results are written into the passed-in buffer. */ -unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, - char *buf_ptr,unsigned int buf_size); - -/* Cause modules to log their state once */ -void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); - -/* Cause encoder firmware to be uploaded into the device. This is normally - done autonomously, but the interface is exported here because it is also - a debugging aid. */ -int pvr2_upload_firmware2(struct pvr2_hdw *hdw); - -#endif /* __PVRUSB2_HDW_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,408 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_HDW_INTERNAL_H -#define __PVRUSB2_HDW_INTERNAL_H - -/* - - This header sets up all the internal structures and definitions needed to - track and coordinate the driver's interaction with the hardware. ONLY - source files which actually implement part of that whole circus should be - including this header. Higher levels, like the external layers to the - various public APIs (V4L, sysfs, etc) should NOT ever include this - private, internal header. This means that pvrusb2-hdw, pvrusb2-encoder, - etc will include this, but pvrusb2-v4l should not. - -*/ - -#include -#include -#include -#include -#include "pvrusb2-hdw.h" -#include "pvrusb2-io.h" -#include -#include -#include -#include "pvrusb2-devattr.h" - -/* Legal values for PVR2_CID_HSM */ -#define PVR2_CVAL_HSM_FAIL 0 -#define PVR2_CVAL_HSM_FULL 1 -#define PVR2_CVAL_HSM_HIGH 2 - -#define PVR2_VID_ENDPOINT 0x84 -#define PVR2_UNK_ENDPOINT 0x86 /* maybe raw yuv ? */ -#define PVR2_VBI_ENDPOINT 0x88 - -#define PVR2_CTL_BUFFSIZE 64 - -#define FREQTABLE_SIZE 500 - -#define LOCK_TAKE(x) do { mutex_lock(&x##_mutex); x##_held = !0; } while (0) -#define LOCK_GIVE(x) do { x##_held = 0; mutex_unlock(&x##_mutex); } while (0) - -typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *); -typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *); -typedef int (*pvr2_ctlf_check_value)(struct pvr2_ctrl *,int); -typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *); -typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val); -typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val, - char *,unsigned int,unsigned int *); -typedef int (*pvr2_ctlf_sym_to_val)(struct pvr2_ctrl *, - const char *,unsigned int, - int *mskp,int *valp); -typedef unsigned int (*pvr2_ctlf_get_v4lflags)(struct pvr2_ctrl *); - -/* This structure describes a specific control. A table of these is set up - in pvrusb2-hdw.c. */ -struct pvr2_ctl_info { - /* Control's name suitable for use as an identifier */ - const char *name; - - /* Short description of control */ - const char *desc; - - /* Control's implementation */ - pvr2_ctlf_get_value get_value; /* Get its value */ - pvr2_ctlf_get_value get_def_value; /* Get its default value */ - pvr2_ctlf_get_value get_min_value; /* Get minimum allowed value */ - pvr2_ctlf_get_value get_max_value; /* Get maximum allowed value */ - pvr2_ctlf_set_value set_value; /* Set its value */ - pvr2_ctlf_check_value check_value; /* Check that value is valid */ - pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */ - pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */ - pvr2_ctlf_is_dirty is_dirty; /* Return true if dirty */ - pvr2_ctlf_clear_dirty clear_dirty; /* Clear dirty state */ - pvr2_ctlf_get_v4lflags get_v4lflags;/* Retrieve v4l flags */ - - /* Control's type (int, enum, bitmask) */ - enum pvr2_ctl_type type; - - /* Associated V4L control ID, if any */ - int v4l_id; - - /* Associated driver internal ID, if any */ - int internal_id; - - /* Don't implicitly initialize this control's value */ - int skip_init; - - /* Starting value for this control */ - int default_value; - - /* Type-specific control information */ - union { - struct { /* Integer control */ - long min_value; /* lower limit */ - long max_value; /* upper limit */ - } type_int; - struct { /* enumerated control */ - unsigned int count; /* enum value count */ - const char * const *value_names; /* symbol names */ - } type_enum; - struct { /* bitmask control */ - unsigned int valid_bits; /* bits in use */ - const char **bit_names; /* symbol name/bit */ - } type_bitmask; - } def; -}; - - -/* Same as pvr2_ctl_info, but includes storage for the control description */ -#define PVR2_CTLD_INFO_DESC_SIZE 32 -struct pvr2_ctld_info { - struct pvr2_ctl_info info; - char desc[PVR2_CTLD_INFO_DESC_SIZE]; -}; - -struct pvr2_ctrl { - const struct pvr2_ctl_info *info; - struct pvr2_hdw *hdw; -}; - - - -/* Disposition of firmware1 loading situation */ -#define FW1_STATE_UNKNOWN 0 -#define FW1_STATE_MISSING 1 -#define FW1_STATE_FAILED 2 -#define FW1_STATE_RELOAD 3 -#define FW1_STATE_OK 4 - -/* What state the device is in if it is a hybrid */ -#define PVR2_PATHWAY_UNKNOWN 0 -#define PVR2_PATHWAY_ANALOG 1 -#define PVR2_PATHWAY_DIGITAL 2 - -typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16); -#define PVR2_I2C_FUNC_CNT 128 - -/* This structure contains all state data directly needed to - manipulate the hardware (as opposed to complying with a kernel - interface) */ -struct pvr2_hdw { - /* Underlying USB device handle */ - struct usb_device *usb_dev; - struct usb_interface *usb_intf; - - /* Our handle into the v4l2 sub-device architecture */ - struct v4l2_device v4l2_dev; - /* Device description, anything that must adjust behavior based on - device specific info will use information held here. */ - const struct pvr2_device_desc *hdw_desc; - - /* Kernel worker thread handling */ - struct workqueue_struct *workqueue; - struct work_struct workpoll; /* Update driver state */ - - /* Video spigot */ - struct pvr2_stream *vid_stream; - - /* Mutex for all hardware state control */ - struct mutex big_lock_mutex; - int big_lock_held; /* For debugging */ - - /* This is a simple string which identifies the instance of this - driver. It is unique within the set of existing devices, but - there is no attempt to keep the name consistent with the same - physical device each time. */ - char name[32]; - - /* This is a simple string which identifies the physical device - instance itself - if possible. (If not possible, then it is - based on the specific driver instance, similar to name above.) - The idea here is that userspace might hopefully be able to use - this recognize specific tuners. It will encode a serial number, - if available. */ - char identifier[32]; - - /* I2C stuff */ - struct i2c_adapter i2c_adap; - struct i2c_algorithm i2c_algo; - pvr2_i2c_func i2c_func[PVR2_I2C_FUNC_CNT]; - int i2c_cx25840_hack_state; - int i2c_linked; - - /* IR related */ - unsigned int ir_scheme_active; /* IR scheme as seen from the outside */ - struct IR_i2c_init_data ir_init_data; /* params passed to IR modules */ - - /* Frequency table */ - unsigned int freqTable[FREQTABLE_SIZE]; - unsigned int freqProgSlot; - - /* Stuff for handling low level control interaction with device */ - struct mutex ctl_lock_mutex; - int ctl_lock_held; /* For debugging */ - struct urb *ctl_write_urb; - struct urb *ctl_read_urb; - unsigned char *ctl_write_buffer; - unsigned char *ctl_read_buffer; - int ctl_write_pend_flag; - int ctl_read_pend_flag; - int ctl_timeout_flag; - struct completion ctl_done; - unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE]; - int cmd_debug_state; // Low level command debugging info - unsigned char cmd_debug_code; // - unsigned int cmd_debug_write_len; // - unsigned int cmd_debug_read_len; // - - /* Bits of state that describe what is going on with various parts - of the driver. */ - int state_pathway_ok; /* Pathway config is ok */ - int state_encoder_ok; /* Encoder is operational */ - int state_encoder_run; /* Encoder is running */ - int state_encoder_config; /* Encoder is configured */ - int state_encoder_waitok; /* Encoder pre-wait done */ - int state_encoder_runok; /* Encoder has run for >= .25 sec */ - int state_decoder_run; /* Decoder is running */ - int state_decoder_ready; /* Decoder is stabilized & streamable */ - int state_usbstream_run; /* FX2 is streaming */ - int state_decoder_quiescent; /* Decoder idle for minimal interval */ - int state_pipeline_config; /* Pipeline is configured */ - int state_pipeline_req; /* Somebody wants to stream */ - int state_pipeline_pause; /* Pipeline must be paused */ - int state_pipeline_idle; /* Pipeline not running */ - - /* This is the master state of the driver. It is the combined - result of other bits of state. Examining this will indicate the - overall state of the driver. Values here are one of - PVR2_STATE_xxxx */ - unsigned int master_state; - - /* True if device led is currently on */ - int led_on; - - /* True if states must be re-evaluated */ - int state_stale; - - void (*state_func)(void *); - void *state_data; - - /* Timer for measuring required decoder settling time before we're - allowed to fire it up again. */ - struct timer_list quiescent_timer; - - /* Timer for measuring decoder stabilization time, which is the - amount of time we need to let the decoder run before we can - trust its output (otherwise the encoder might see garbage and - then fail to start correctly). */ - struct timer_list decoder_stabilization_timer; - - /* Timer for measuring encoder pre-wait time */ - struct timer_list encoder_wait_timer; - - /* Timer for measuring encoder minimum run time */ - struct timer_list encoder_run_timer; - - /* Place to block while waiting for state changes */ - wait_queue_head_t state_wait_data; - - - int force_dirty; /* consider all controls dirty if true */ - int flag_ok; /* device in known good state */ - int flag_modulefail; /* true if at least one module failed to load */ - int flag_disconnected; /* flag_ok == 0 due to disconnect */ - int flag_init_ok; /* true if structure is fully initialized */ - int fw1_state; /* current situation with fw1 */ - int pathway_state; /* one of PVR2_PATHWAY_xxx */ - int flag_decoder_missed;/* We've noticed missing decoder */ - int flag_tripped; /* Indicates overall failure to start */ - - unsigned int decoder_client_id; - - // CPU firmware info (used to help find / save firmware data) - char *fw_buffer; - unsigned int fw_size; - int fw_cpu_flag; /* True if we are dealing with the CPU */ - - /* Tuner / frequency control stuff */ - unsigned int tuner_type; - int tuner_updated; - unsigned int freqValTelevision; /* Current freq for tv mode */ - unsigned int freqValRadio; /* Current freq for radio mode */ - unsigned int freqSlotTelevision; /* Current slot for tv mode */ - unsigned int freqSlotRadio; /* Current slot for radio mode */ - unsigned int freqSelector; /* 0=radio 1=television */ - int freqDirty; - - /* Current tuner info - this information is polled from the I2C bus */ - struct v4l2_tuner tuner_signal_info; - int tuner_signal_stale; - - /* Cropping capability info */ - struct v4l2_cropcap cropcap_info; - int cropcap_stale; - - /* Video standard handling */ - v4l2_std_id std_mask_eeprom; // Hardware supported selections - v4l2_std_id std_mask_avail; // Which standards we may select from - v4l2_std_id std_mask_cur; // Currently selected standard(s) - unsigned int std_enum_cnt; // # of enumerated standards - int std_enum_cur; // selected standard enumeration value - int std_dirty; // True if std_mask_cur has changed - struct pvr2_ctl_info std_info_enum; - struct pvr2_ctl_info std_info_avail; - struct pvr2_ctl_info std_info_cur; - struct v4l2_standard *std_defs; - const char **std_enum_names; - - // Generated string names, one per actual V4L2 standard - const char *std_mask_ptrs[32]; - char std_mask_names[32][10]; - - int unit_number; /* ID for driver instance */ - unsigned long serial_number; /* ID for hardware itself */ - - char bus_info[32]; /* Bus location info */ - - /* Minor numbers used by v4l logic (yes, this is a hack, as there - should be no v4l junk here). Probably a better way to do this. */ - int v4l_minor_number_video; - int v4l_minor_number_vbi; - int v4l_minor_number_radio; - - /* Bit mask of PVR2_CVAL_INPUT choices which are valid for the hardware */ - unsigned int input_avail_mask; - /* Bit mask of PVR2_CVAL_INPUT choices which are currently allowed */ - unsigned int input_allowed_mask; - - /* Location of eeprom or a negative number if none */ - int eeprom_addr; - - enum pvr2_config active_stream_type; - enum pvr2_config desired_stream_type; - - /* Control state needed for cx2341x module */ - struct cx2341x_mpeg_params enc_cur_state; - struct cx2341x_mpeg_params enc_ctl_state; - /* True if an encoder attribute has changed */ - int enc_stale; - /* True if an unsafe encoder attribute has changed */ - int enc_unsafe_stale; - /* True if enc_cur_state is valid */ - int enc_cur_valid; - - /* Control state */ -#define VCREATE_DATA(lab) int lab##_val; int lab##_dirty - VCREATE_DATA(brightness); - VCREATE_DATA(contrast); - VCREATE_DATA(saturation); - VCREATE_DATA(hue); - VCREATE_DATA(volume); - VCREATE_DATA(balance); - VCREATE_DATA(bass); - VCREATE_DATA(treble); - VCREATE_DATA(mute); - VCREATE_DATA(cropl); - VCREATE_DATA(cropt); - VCREATE_DATA(cropw); - VCREATE_DATA(croph); - VCREATE_DATA(input); - VCREATE_DATA(audiomode); - VCREATE_DATA(res_hor); - VCREATE_DATA(res_ver); - VCREATE_DATA(srate); -#undef VCREATE_DATA - - struct pvr2_ctld_info *mpeg_ctrl_info; - - struct pvr2_ctrl *controls; - unsigned int control_cnt; -}; - -/* This function gets the current frequency */ -unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *); - -void pvr2_hdw_status_poll(struct pvr2_hdw *); - -#endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,697 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 -#include -#include "pvrusb2-i2c-core.h" -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-debug.h" -#include "pvrusb2-fx2-cmd.h" -#include "pvrusb2.h" - -#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__) - -/* - - This module attempts to implement a compliant I2C adapter for the pvrusb2 - device. - -*/ - -static unsigned int i2c_scan; -module_param(i2c_scan, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); - -static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 }; -module_param_array(ir_mode, int, NULL, 0444); -MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR"); - -static int pvr2_disable_ir_video; -module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video, - int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(disable_autoload_ir_video, - "1=do not try to autoload ir_video IR receiver"); - -static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ - u8 i2c_addr, /* I2C address we're talking to */ - u8 *data, /* Data to write */ - u16 length) /* Size of data to write */ -{ - /* Return value - default 0 means success */ - int ret; - - - if (!data) length = 0; - if (length > (sizeof(hdw->cmd_buffer) - 3)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Killing an I2C write to %u that is too large" - " (desired=%u limit=%u)", - i2c_addr, - length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3)); - return -ENOTSUPP; - } - - LOCK_TAKE(hdw->ctl_lock); - - /* Clear the command buffer (likely to be paranoia) */ - memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer)); - - /* Set up command buffer for an I2C write */ - hdw->cmd_buffer[0] = FX2CMD_I2C_WRITE; /* write prefix */ - hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */ - hdw->cmd_buffer[2] = length; /* length of what follows */ - if (length) memcpy(hdw->cmd_buffer + 3, data, length); - - /* Do the operation */ - ret = pvr2_send_request(hdw, - hdw->cmd_buffer, - length + 3, - hdw->cmd_buffer, - 1); - if (!ret) { - if (hdw->cmd_buffer[0] != 8) { - ret = -EIO; - if (hdw->cmd_buffer[0] != 7) { - trace_i2c("unexpected status" - " from i2_write[%d]: %d", - i2c_addr,hdw->cmd_buffer[0]); - } - } - } - - LOCK_GIVE(hdw->ctl_lock); - - return ret; -} - -static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */ - u8 i2c_addr, /* I2C address we're talking to */ - u8 *data, /* Data to write */ - u16 dlen, /* Size of data to write */ - u8 *res, /* Where to put data we read */ - u16 rlen) /* Amount of data to read */ -{ - /* Return value - default 0 means success */ - int ret; - - - if (!data) dlen = 0; - if (dlen > (sizeof(hdw->cmd_buffer) - 4)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Killing an I2C read to %u that has wlen too large" - " (desired=%u limit=%u)", - i2c_addr, - dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4)); - return -ENOTSUPP; - } - if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Killing an I2C read to %u that has rlen too large" - " (desired=%u limit=%u)", - i2c_addr, - rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1)); - return -ENOTSUPP; - } - - LOCK_TAKE(hdw->ctl_lock); - - /* Clear the command buffer (likely to be paranoia) */ - memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer)); - - /* Set up command buffer for an I2C write followed by a read */ - hdw->cmd_buffer[0] = FX2CMD_I2C_READ; /* read prefix */ - hdw->cmd_buffer[1] = dlen; /* arg length */ - hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one - more byte (status). */ - hdw->cmd_buffer[3] = i2c_addr; /* i2c addr of chip */ - if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen); - - /* Do the operation */ - ret = pvr2_send_request(hdw, - hdw->cmd_buffer, - 4 + dlen, - hdw->cmd_buffer, - rlen + 1); - if (!ret) { - if (hdw->cmd_buffer[0] != 8) { - ret = -EIO; - if (hdw->cmd_buffer[0] != 7) { - trace_i2c("unexpected status" - " from i2_read[%d]: %d", - i2c_addr,hdw->cmd_buffer[0]); - } - } - } - - /* Copy back the result */ - if (res && rlen) { - if (ret) { - /* Error, just blank out the return buffer */ - memset(res, 0, rlen); - } else { - memcpy(res, hdw->cmd_buffer + 1, rlen); - } - } - - LOCK_GIVE(hdw->ctl_lock); - - return ret; -} - -/* This is the common low level entry point for doing I2C operations to the - hardware. */ -static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw, - u8 i2c_addr, - u8 *wdata, - u16 wlen, - u8 *rdata, - u16 rlen) -{ - if (!rdata) rlen = 0; - if (!wdata) wlen = 0; - if (rlen || !wlen) { - return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen); - } else { - return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen); - } -} - - -/* This is a special entry point for cases of I2C transaction attempts to - the IR receiver. The implementation here simulates the IR receiver by - issuing a command to the FX2 firmware and using that response to return - what the real I2C receiver would have returned. We use this for 24xxx - devices, where the IR receiver chip has been removed and replaced with - FX2 related logic. */ -static int i2c_24xxx_ir(struct pvr2_hdw *hdw, - u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen) -{ - u8 dat[4]; - unsigned int stat; - - if (!(rlen || wlen)) { - /* This is a probe attempt. Just let it succeed. */ - return 0; - } - - /* We don't understand this kind of transaction */ - if ((wlen != 0) || (rlen == 0)) return -EIO; - - if (rlen < 3) { - /* Mike Isely Appears to be a probe - attempt from lirc. Just fill in zeroes and return. If - we try instead to do the full transaction here, then bad - things seem to happen within the lirc driver module - (version 0.8.0-7 sources from Debian, when run under - vanilla 2.6.17.6 kernel) - and I don't have the patience - to chase it down. */ - if (rlen > 0) rdata[0] = 0; - if (rlen > 1) rdata[1] = 0; - return 0; - } - - /* Issue a command to the FX2 to read the IR receiver. */ - LOCK_TAKE(hdw->ctl_lock); do { - hdw->cmd_buffer[0] = FX2CMD_GET_IR_CODE; - stat = pvr2_send_request(hdw, - hdw->cmd_buffer,1, - hdw->cmd_buffer,4); - dat[0] = hdw->cmd_buffer[0]; - dat[1] = hdw->cmd_buffer[1]; - dat[2] = hdw->cmd_buffer[2]; - dat[3] = hdw->cmd_buffer[3]; - } while (0); LOCK_GIVE(hdw->ctl_lock); - - /* Give up if that operation failed. */ - if (stat != 0) return stat; - - /* Mangle the results into something that looks like the real IR - receiver. */ - rdata[2] = 0xc1; - if (dat[0] != 1) { - /* No code received. */ - rdata[0] = 0; - rdata[1] = 0; - } else { - u16 val; - /* Mash the FX2 firmware-provided IR code into something - that the normal i2c chip-level driver expects. */ - val = dat[1]; - val <<= 8; - val |= dat[2]; - val >>= 1; - val &= ~0x0003; - val |= 0x8000; - rdata[0] = (val >> 8) & 0xffu; - rdata[1] = val & 0xffu; - } - - return 0; -} - -/* This is a special entry point that is entered if an I2C operation is - attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this - part doesn't work, but we know it is really there. So let's look for - the autodetect attempt and just return success if we see that. */ -static int i2c_hack_wm8775(struct pvr2_hdw *hdw, - u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen) -{ - if (!(rlen || wlen)) { - // This is a probe attempt. Just let it succeed. - return 0; - } - return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen); -} - -/* This is an entry point designed to always fail any attempt to perform a - transfer. We use this to cause certain I2C addresses to not be - probed. */ -static int i2c_black_hole(struct pvr2_hdw *hdw, - u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen) -{ - return -EIO; -} - -/* This is a special entry point that is entered if an I2C operation is - attempted to a cx25840 chip on model 24xxx hardware. This chip can - sometimes wedge itself. Worse still, when this happens msp3400 can - falsely detect this part and then the system gets hosed up after msp3400 - gets confused and dies. What we want to do here is try to keep msp3400 - away and also try to notice if the chip is wedged and send a warning to - the system log. */ -static int i2c_hack_cx25840(struct pvr2_hdw *hdw, - u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen) -{ - int ret; - unsigned int subaddr; - u8 wbuf[2]; - int state = hdw->i2c_cx25840_hack_state; - - if (!(rlen || wlen)) { - // Probe attempt - always just succeed and don't bother the - // hardware (this helps to make the state machine further - // down somewhat easier). - return 0; - } - - if (state == 3) { - return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen); - } - - /* We're looking for the exact pattern where the revision register - is being read. The cx25840 module will always look at the - revision register first. Any other pattern of access therefore - has to be a probe attempt from somebody else so we'll reject it. - Normally we could just let each client just probe the part - anyway, but when the cx25840 is wedged, msp3400 will get a false - positive and that just screws things up... */ - - if (wlen == 0) { - switch (state) { - case 1: subaddr = 0x0100; break; - case 2: subaddr = 0x0101; break; - default: goto fail; - } - } else if (wlen == 2) { - subaddr = (wdata[0] << 8) | wdata[1]; - switch (subaddr) { - case 0x0100: state = 1; break; - case 0x0101: state = 2; break; - default: goto fail; - } - } else { - goto fail; - } - if (!rlen) goto success; - state = 0; - if (rlen != 1) goto fail; - - /* If we get to here then we have a legitimate read for one of the - two revision bytes, so pass it through. */ - wbuf[0] = subaddr >> 8; - wbuf[1] = subaddr; - ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen); - - if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Detected a wedged cx25840 chip;" - " the device will not work."); - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Try power cycling the pvrusb2 device."); - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Disabling further access to the device" - " to prevent other foul-ups."); - // This blocks all further communication with the part. - hdw->i2c_func[0x44] = NULL; - pvr2_hdw_render_useless(hdw); - goto fail; - } - - /* Success! */ - pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK."); - state = 3; - - success: - hdw->i2c_cx25840_hack_state = state; - return 0; - - fail: - hdw->i2c_cx25840_hack_state = state; - return -EIO; -} - -/* This is a very, very limited I2C adapter implementation. We can only - support what we actually know will work on the device... */ -static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], - int num) -{ - int ret = -ENOTSUPP; - pvr2_i2c_func funcp = NULL; - struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data); - - if (!num) { - ret = -EINVAL; - goto done; - } - if (msgs[0].addr < PVR2_I2C_FUNC_CNT) { - funcp = hdw->i2c_func[msgs[0].addr]; - } - if (!funcp) { - ret = -EIO; - goto done; - } - - if (num == 1) { - if (msgs[0].flags & I2C_M_RD) { - /* Simple read */ - u16 tcnt,bcnt,offs; - if (!msgs[0].len) { - /* Length == 0 read. This is a probe. */ - if (funcp(hdw,msgs[0].addr,NULL,0,NULL,0)) { - ret = -EIO; - goto done; - } - ret = 1; - goto done; - } - /* If the read is short enough we'll do the whole - thing atomically. Otherwise we have no choice - but to break apart the reads. */ - tcnt = msgs[0].len; - offs = 0; - while (tcnt) { - bcnt = tcnt; - if (bcnt > sizeof(hdw->cmd_buffer)-1) { - bcnt = sizeof(hdw->cmd_buffer)-1; - } - if (funcp(hdw,msgs[0].addr,NULL,0, - msgs[0].buf+offs,bcnt)) { - ret = -EIO; - goto done; - } - offs += bcnt; - tcnt -= bcnt; - } - ret = 1; - goto done; - } else { - /* Simple write */ - ret = 1; - if (funcp(hdw,msgs[0].addr, - msgs[0].buf,msgs[0].len,NULL,0)) { - ret = -EIO; - } - goto done; - } - } else if (num == 2) { - if (msgs[0].addr != msgs[1].addr) { - trace_i2c("i2c refusing 2 phase transfer with" - " conflicting target addresses"); - ret = -ENOTSUPP; - goto done; - } - if ((!((msgs[0].flags & I2C_M_RD))) && - (msgs[1].flags & I2C_M_RD)) { - u16 tcnt,bcnt,wcnt,offs; - /* Write followed by atomic read. If the read - portion is short enough we'll do the whole thing - atomically. Otherwise we have no choice but to - break apart the reads. */ - tcnt = msgs[1].len; - wcnt = msgs[0].len; - offs = 0; - while (tcnt || wcnt) { - bcnt = tcnt; - if (bcnt > sizeof(hdw->cmd_buffer)-1) { - bcnt = sizeof(hdw->cmd_buffer)-1; - } - if (funcp(hdw,msgs[0].addr, - msgs[0].buf,wcnt, - msgs[1].buf+offs,bcnt)) { - ret = -EIO; - goto done; - } - offs += bcnt; - tcnt -= bcnt; - wcnt = 0; - } - ret = 2; - goto done; - } else { - trace_i2c("i2c refusing complex transfer" - " read0=%d read1=%d", - (msgs[0].flags & I2C_M_RD), - (msgs[1].flags & I2C_M_RD)); - } - } else { - trace_i2c("i2c refusing %d phase transfer",num); - } - - done: - if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) { - unsigned int idx,offs,cnt; - for (idx = 0; idx < num; idx++) { - cnt = msgs[idx].len; - printk(KERN_INFO - "pvrusb2 i2c xfer %u/%u:" - " addr=0x%x len=%d %s", - idx+1,num, - msgs[idx].addr, - cnt, - (msgs[idx].flags & I2C_M_RD ? - "read" : "write")); - if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) { - if (cnt > 8) cnt = 8; - printk(" ["); - for (offs = 0; offs < (cnt>8?8:cnt); offs++) { - if (offs) printk(" "); - printk("%02x",msgs[idx].buf[offs]); - } - if (offs < cnt) printk(" ..."); - printk("]"); - } - if (idx+1 == num) { - printk(" result=%d",ret); - } - printk("\n"); - } - if (!num) { - printk(KERN_INFO - "pvrusb2 i2c xfer null transfer result=%d\n", - ret); - } - } - return ret; -} - -static u32 pvr2_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; -} - -static struct i2c_algorithm pvr2_i2c_algo_template = { - .master_xfer = pvr2_i2c_xfer, - .functionality = pvr2_i2c_functionality, -}; - -static struct i2c_adapter pvr2_i2c_adap_template = { - .owner = THIS_MODULE, - .class = 0, -}; - - -/* Return true if device exists at given address */ -static int do_i2c_probe(struct pvr2_hdw *hdw, int addr) -{ - struct i2c_msg msg[1]; - int rc; - msg[0].addr = 0; - msg[0].flags = I2C_M_RD; - msg[0].len = 0; - msg[0].buf = NULL; - msg[0].addr = addr; - rc = i2c_transfer(&hdw->i2c_adap, msg, ARRAY_SIZE(msg)); - return rc == 1; -} - -static void do_i2c_scan(struct pvr2_hdw *hdw) -{ - int i; - printk(KERN_INFO "%s: i2c scan beginning\n", hdw->name); - for (i = 0; i < 128; i++) { - if (do_i2c_probe(hdw, i)) { - printk(KERN_INFO "%s: i2c scan: found device @ 0x%x\n", - hdw->name, i); - } - } - printk(KERN_INFO "%s: i2c scan done.\n", hdw->name); -} - -static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) -{ - struct i2c_board_info info; - struct IR_i2c_init_data *init_data = &hdw->ir_init_data; - if (pvr2_disable_ir_video) { - pvr2_trace(PVR2_TRACE_INFO, - "Automatic binding of ir_video has been disabled."); - return; - } - memset(&info, 0, sizeof(struct i2c_board_info)); - switch (hdw->ir_scheme_active) { - case PVR2_IR_SCHEME_24XXX: /* FX2-controlled IR */ - case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */ - init_data->ir_codes = RC_MAP_HAUPPAUGE; - init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; - init_data->type = RC_TYPE_RC5; - init_data->name = hdw->hdw_desc->description; - init_data->polling_interval = 100; /* ms From ir-kbd-i2c */ - /* IR Receiver */ - info.addr = 0x18; - info.platform_data = init_data; - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.", - info.type, info.addr); - i2c_new_device(&hdw->i2c_adap, &info); - break; - case PVR2_IR_SCHEME_ZILOG: /* HVR-1950 style */ - case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */ - init_data->ir_codes = RC_MAP_HAUPPAUGE; - init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; - init_data->name = hdw->hdw_desc->description; - /* IR Receiver */ - info.addr = 0x71; - info.platform_data = init_data; - strlcpy(info.type, "ir_rx_z8f0811_haup", I2C_NAME_SIZE); - pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.", - info.type, info.addr); - i2c_new_device(&hdw->i2c_adap, &info); - /* IR Trasmitter */ - info.addr = 0x70; - info.platform_data = init_data; - strlcpy(info.type, "ir_tx_z8f0811_haup", I2C_NAME_SIZE); - pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.", - info.type, info.addr); - i2c_new_device(&hdw->i2c_adap, &info); - break; - default: - /* The device either doesn't support I2C-based IR or we - don't know (yet) how to operate IR on the device. */ - break; - } -} - -void pvr2_i2c_core_init(struct pvr2_hdw *hdw) -{ - unsigned int idx; - - /* The default action for all possible I2C addresses is just to do - the transfer normally. */ - for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) { - hdw->i2c_func[idx] = pvr2_i2c_basic_op; - } - - /* However, deal with various special cases for 24xxx hardware. */ - if (ir_mode[hdw->unit_number] == 0) { - printk(KERN_INFO "%s: IR disabled\n",hdw->name); - hdw->i2c_func[0x18] = i2c_black_hole; - } else if (ir_mode[hdw->unit_number] == 1) { - if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) { - /* Set up translation so that our IR looks like a - 29xxx device */ - hdw->i2c_func[0x18] = i2c_24xxx_ir; - } - } - if (hdw->hdw_desc->flag_has_cx25840) { - hdw->i2c_func[0x44] = i2c_hack_cx25840; - } - if (hdw->hdw_desc->flag_has_wm8775) { - hdw->i2c_func[0x1b] = i2c_hack_wm8775; - } - - // Configure the adapter and set up everything else related to it. - memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap)); - memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo)); - strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name)); - hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev; - hdw->i2c_adap.algo = &hdw->i2c_algo; - hdw->i2c_adap.algo_data = hdw; - hdw->i2c_linked = !0; - i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev); - i2c_add_adapter(&hdw->i2c_adap); - if (hdw->i2c_func[0x18] == i2c_24xxx_ir) { - /* Probe for a different type of IR receiver on this - device. This is really the only way to differentiate - older 24xxx devices from 24xxx variants that include an - IR blaster. If the IR blaster is present, the IR - receiver is part of that chip and thus we must disable - the emulated IR receiver. */ - if (do_i2c_probe(hdw, 0x71)) { - pvr2_trace(PVR2_TRACE_INFO, - "Device has newer IR hardware;" - " disabling unneeded virtual IR device"); - hdw->i2c_func[0x18] = NULL; - /* Remember that this is a different device... */ - hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE; - } - } - if (i2c_scan) do_i2c_scan(hdw); - - pvr2_i2c_register_ir(hdw); -} - -void pvr2_i2c_core_done(struct pvr2_hdw *hdw) -{ - if (hdw->i2c_linked) { - i2c_del_adapter(&hdw->i2c_adap); - hdw->i2c_linked = 0; - } -} - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_I2C_CORE_H -#define __PVRUSB2_I2C_CORE_H - -struct pvr2_hdw; - -void pvr2_i2c_core_init(struct pvr2_hdw *); -void pvr2_i2c_core_done(struct pvr2_hdw *); - - -#endif /* __PVRUSB2_I2C_ADAPTER_H */ - - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-io.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-io.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-io.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-io.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,695 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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-io.h" -#include "pvrusb2-debug.h" -#include -#include -#include -#include - -static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state); - -#define BUFFER_SIG 0x47653271 - -// #define SANITY_CHECK_BUFFERS - - -#ifdef SANITY_CHECK_BUFFERS -#define BUFFER_CHECK(bp) do { \ - if ((bp)->signature != BUFFER_SIG) { \ - pvr2_trace(PVR2_TRACE_ERROR_LEGS, \ - "Buffer %p is bad at %s:%d", \ - (bp),__FILE__,__LINE__); \ - pvr2_buffer_describe(bp,"BadSig"); \ - BUG(); \ - } \ -} while (0) -#else -#define BUFFER_CHECK(bp) do {} while(0) -#endif - -struct pvr2_stream { - /* Buffers queued for reading */ - struct list_head queued_list; - unsigned int q_count; - unsigned int q_bcount; - /* Buffers with retrieved data */ - struct list_head ready_list; - unsigned int r_count; - unsigned int r_bcount; - /* Buffers available for use */ - struct list_head idle_list; - unsigned int i_count; - unsigned int i_bcount; - /* Pointers to all buffers */ - struct pvr2_buffer **buffers; - /* Array size of buffers */ - unsigned int buffer_slot_count; - /* Total buffers actually in circulation */ - unsigned int buffer_total_count; - /* Designed number of buffers to be in circulation */ - unsigned int buffer_target_count; - /* Executed when ready list become non-empty */ - pvr2_stream_callback callback_func; - void *callback_data; - /* Context for transfer endpoint */ - struct usb_device *dev; - int endpoint; - /* Overhead for mutex enforcement */ - spinlock_t list_lock; - struct mutex mutex; - /* Tracking state for tolerating errors */ - unsigned int fail_count; - unsigned int fail_tolerance; - - unsigned int buffers_processed; - unsigned int buffers_failed; - unsigned int bytes_processed; -}; - -struct pvr2_buffer { - int id; - int signature; - enum pvr2_buffer_state state; - void *ptr; /* Pointer to storage area */ - unsigned int max_count; /* Size of storage area */ - unsigned int used_count; /* Amount of valid data in storage area */ - int status; /* Transfer result status */ - struct pvr2_stream *stream; - struct list_head list_overhead; - struct urb *purb; -}; - -static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st) -{ - switch (st) { - case pvr2_buffer_state_none: return "none"; - case pvr2_buffer_state_idle: return "idle"; - case pvr2_buffer_state_queued: return "queued"; - case pvr2_buffer_state_ready: return "ready"; - } - return "unknown"; -} - -#ifdef SANITY_CHECK_BUFFERS -static void pvr2_buffer_describe(struct pvr2_buffer *bp,const char *msg) -{ - pvr2_trace(PVR2_TRACE_INFO, - "buffer%s%s %p state=%s id=%d status=%d" - " stream=%p purb=%p sig=0x%x", - (msg ? " " : ""), - (msg ? msg : ""), - bp, - (bp ? pvr2_buffer_state_decode(bp->state) : "(invalid)"), - (bp ? bp->id : 0), - (bp ? bp->status : 0), - (bp ? bp->stream : NULL), - (bp ? bp->purb : NULL), - (bp ? bp->signature : 0)); -} -#endif /* SANITY_CHECK_BUFFERS */ - -static void pvr2_buffer_remove(struct pvr2_buffer *bp) -{ - unsigned int *cnt; - unsigned int *bcnt; - unsigned int ccnt; - struct pvr2_stream *sp = bp->stream; - switch (bp->state) { - case pvr2_buffer_state_idle: - cnt = &sp->i_count; - bcnt = &sp->i_bcount; - ccnt = bp->max_count; - break; - case pvr2_buffer_state_queued: - cnt = &sp->q_count; - bcnt = &sp->q_bcount; - ccnt = bp->max_count; - break; - case pvr2_buffer_state_ready: - cnt = &sp->r_count; - bcnt = &sp->r_bcount; - ccnt = bp->used_count; - break; - default: - return; - } - list_del_init(&bp->list_overhead); - (*cnt)--; - (*bcnt) -= ccnt; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/" - " bufferPool %8s dec cap=%07d cnt=%02d", - pvr2_buffer_state_decode(bp->state),*bcnt,*cnt); - bp->state = pvr2_buffer_state_none; -} - -static void pvr2_buffer_set_none(struct pvr2_buffer *bp) -{ - unsigned long irq_flags; - struct pvr2_stream *sp; - BUFFER_CHECK(bp); - sp = bp->stream; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", - bp, - pvr2_buffer_state_decode(bp->state), - pvr2_buffer_state_decode(pvr2_buffer_state_none)); - spin_lock_irqsave(&sp->list_lock,irq_flags); - pvr2_buffer_remove(bp); - spin_unlock_irqrestore(&sp->list_lock,irq_flags); -} - -static int pvr2_buffer_set_ready(struct pvr2_buffer *bp) -{ - int fl; - unsigned long irq_flags; - struct pvr2_stream *sp; - BUFFER_CHECK(bp); - sp = bp->stream; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", - bp, - pvr2_buffer_state_decode(bp->state), - pvr2_buffer_state_decode(pvr2_buffer_state_ready)); - spin_lock_irqsave(&sp->list_lock,irq_flags); - fl = (sp->r_count == 0); - pvr2_buffer_remove(bp); - list_add_tail(&bp->list_overhead,&sp->ready_list); - bp->state = pvr2_buffer_state_ready; - (sp->r_count)++; - sp->r_bcount += bp->used_count; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/" - " bufferPool %8s inc cap=%07d cnt=%02d", - pvr2_buffer_state_decode(bp->state), - sp->r_bcount,sp->r_count); - spin_unlock_irqrestore(&sp->list_lock,irq_flags); - return fl; -} - -static void pvr2_buffer_set_idle(struct pvr2_buffer *bp) -{ - unsigned long irq_flags; - struct pvr2_stream *sp; - BUFFER_CHECK(bp); - sp = bp->stream; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", - bp, - pvr2_buffer_state_decode(bp->state), - pvr2_buffer_state_decode(pvr2_buffer_state_idle)); - spin_lock_irqsave(&sp->list_lock,irq_flags); - pvr2_buffer_remove(bp); - list_add_tail(&bp->list_overhead,&sp->idle_list); - bp->state = pvr2_buffer_state_idle; - (sp->i_count)++; - sp->i_bcount += bp->max_count; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/" - " bufferPool %8s inc cap=%07d cnt=%02d", - pvr2_buffer_state_decode(bp->state), - sp->i_bcount,sp->i_count); - spin_unlock_irqrestore(&sp->list_lock,irq_flags); -} - -static void pvr2_buffer_set_queued(struct pvr2_buffer *bp) -{ - unsigned long irq_flags; - struct pvr2_stream *sp; - BUFFER_CHECK(bp); - sp = bp->stream; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", - bp, - pvr2_buffer_state_decode(bp->state), - pvr2_buffer_state_decode(pvr2_buffer_state_queued)); - spin_lock_irqsave(&sp->list_lock,irq_flags); - pvr2_buffer_remove(bp); - list_add_tail(&bp->list_overhead,&sp->queued_list); - bp->state = pvr2_buffer_state_queued; - (sp->q_count)++; - sp->q_bcount += bp->max_count; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/" - " bufferPool %8s inc cap=%07d cnt=%02d", - pvr2_buffer_state_decode(bp->state), - sp->q_bcount,sp->q_count); - spin_unlock_irqrestore(&sp->list_lock,irq_flags); -} - -static void pvr2_buffer_wipe(struct pvr2_buffer *bp) -{ - if (bp->state == pvr2_buffer_state_queued) { - usb_kill_urb(bp->purb); - } -} - -static int pvr2_buffer_init(struct pvr2_buffer *bp, - struct pvr2_stream *sp, - unsigned int id) -{ - memset(bp,0,sizeof(*bp)); - bp->signature = BUFFER_SIG; - bp->id = id; - pvr2_trace(PVR2_TRACE_BUF_POOL, - "/*---TRACE_FLOW---*/ bufferInit %p stream=%p",bp,sp); - bp->stream = sp; - bp->state = pvr2_buffer_state_none; - INIT_LIST_HEAD(&bp->list_overhead); - bp->purb = usb_alloc_urb(0,GFP_KERNEL); - if (! bp->purb) return -ENOMEM; -#ifdef SANITY_CHECK_BUFFERS - pvr2_buffer_describe(bp,"create"); -#endif - return 0; -} - -static void pvr2_buffer_done(struct pvr2_buffer *bp) -{ -#ifdef SANITY_CHECK_BUFFERS - pvr2_buffer_describe(bp,"delete"); -#endif - pvr2_buffer_wipe(bp); - pvr2_buffer_set_none(bp); - bp->signature = 0; - bp->stream = NULL; - usb_free_urb(bp->purb); - pvr2_trace(PVR2_TRACE_BUF_POOL,"/*---TRACE_FLOW---*/" - " bufferDone %p",bp); -} - -static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt) -{ - int ret; - unsigned int scnt; - - /* Allocate buffers pointer array in multiples of 32 entries */ - if (cnt == sp->buffer_total_count) return 0; - - pvr2_trace(PVR2_TRACE_BUF_POOL, - "/*---TRACE_FLOW---*/ poolResize " - " stream=%p cur=%d adj=%+d", - sp, - sp->buffer_total_count, - cnt-sp->buffer_total_count); - - scnt = cnt & ~0x1f; - if (cnt > scnt) scnt += 0x20; - - if (cnt > sp->buffer_total_count) { - if (scnt > sp->buffer_slot_count) { - struct pvr2_buffer **nb; - nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL); - if (!nb) return -ENOMEM; - if (sp->buffer_slot_count) { - memcpy(nb,sp->buffers, - sp->buffer_slot_count * sizeof(*nb)); - kfree(sp->buffers); - } - sp->buffers = nb; - sp->buffer_slot_count = scnt; - } - while (sp->buffer_total_count < cnt) { - struct pvr2_buffer *bp; - bp = kmalloc(sizeof(*bp),GFP_KERNEL); - if (!bp) return -ENOMEM; - ret = pvr2_buffer_init(bp,sp,sp->buffer_total_count); - if (ret) { - kfree(bp); - return -ENOMEM; - } - sp->buffers[sp->buffer_total_count] = bp; - (sp->buffer_total_count)++; - pvr2_buffer_set_idle(bp); - } - } else { - while (sp->buffer_total_count > cnt) { - struct pvr2_buffer *bp; - bp = sp->buffers[sp->buffer_total_count - 1]; - /* Paranoia */ - sp->buffers[sp->buffer_total_count - 1] = NULL; - (sp->buffer_total_count)--; - pvr2_buffer_done(bp); - kfree(bp); - } - if (scnt < sp->buffer_slot_count) { - struct pvr2_buffer **nb = NULL; - if (scnt) { - nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL); - if (!nb) return -ENOMEM; - memcpy(nb,sp->buffers,scnt * sizeof(*nb)); - } - kfree(sp->buffers); - sp->buffers = nb; - sp->buffer_slot_count = scnt; - } - } - return 0; -} - -static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp) -{ - struct pvr2_buffer *bp; - unsigned int cnt; - - if (sp->buffer_total_count == sp->buffer_target_count) return 0; - - pvr2_trace(PVR2_TRACE_BUF_POOL, - "/*---TRACE_FLOW---*/" - " poolCheck stream=%p cur=%d tgt=%d", - sp,sp->buffer_total_count,sp->buffer_target_count); - - if (sp->buffer_total_count < sp->buffer_target_count) { - return pvr2_stream_buffer_count(sp,sp->buffer_target_count); - } - - cnt = 0; - while ((sp->buffer_total_count - cnt) > sp->buffer_target_count) { - bp = sp->buffers[sp->buffer_total_count - (cnt + 1)]; - if (bp->state != pvr2_buffer_state_idle) break; - cnt++; - } - if (cnt) { - pvr2_stream_buffer_count(sp,sp->buffer_total_count - cnt); - } - - return 0; -} - -static void pvr2_stream_internal_flush(struct pvr2_stream *sp) -{ - struct list_head *lp; - struct pvr2_buffer *bp1; - while ((lp = sp->queued_list.next) != &sp->queued_list) { - bp1 = list_entry(lp,struct pvr2_buffer,list_overhead); - pvr2_buffer_wipe(bp1); - /* At this point, we should be guaranteed that no - completion callback may happen on this buffer. But it's - possible that it might have completed after we noticed - it but before we wiped it. So double check its status - here first. */ - if (bp1->state != pvr2_buffer_state_queued) continue; - pvr2_buffer_set_idle(bp1); - } - if (sp->buffer_total_count != sp->buffer_target_count) { - pvr2_stream_achieve_buffer_count(sp); - } -} - -static void pvr2_stream_init(struct pvr2_stream *sp) -{ - spin_lock_init(&sp->list_lock); - mutex_init(&sp->mutex); - INIT_LIST_HEAD(&sp->queued_list); - INIT_LIST_HEAD(&sp->ready_list); - INIT_LIST_HEAD(&sp->idle_list); -} - -static void pvr2_stream_done(struct pvr2_stream *sp) -{ - mutex_lock(&sp->mutex); do { - pvr2_stream_internal_flush(sp); - pvr2_stream_buffer_count(sp,0); - } while (0); mutex_unlock(&sp->mutex); -} - -static void buffer_complete(struct urb *urb) -{ - struct pvr2_buffer *bp = urb->context; - struct pvr2_stream *sp; - unsigned long irq_flags; - BUFFER_CHECK(bp); - sp = bp->stream; - bp->used_count = 0; - bp->status = 0; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/ bufferComplete %p stat=%d cnt=%d", - bp,urb->status,urb->actual_length); - spin_lock_irqsave(&sp->list_lock,irq_flags); - if ((!(urb->status)) || - (urb->status == -ENOENT) || - (urb->status == -ECONNRESET) || - (urb->status == -ESHUTDOWN)) { - (sp->buffers_processed)++; - sp->bytes_processed += urb->actual_length; - bp->used_count = urb->actual_length; - if (sp->fail_count) { - pvr2_trace(PVR2_TRACE_TOLERANCE, - "stream %p transfer ok" - " - fail count reset",sp); - sp->fail_count = 0; - } - } else if (sp->fail_count < sp->fail_tolerance) { - // We can tolerate this error, because we're below the - // threshold... - (sp->fail_count)++; - (sp->buffers_failed)++; - pvr2_trace(PVR2_TRACE_TOLERANCE, - "stream %p ignoring error %d" - " - fail count increased to %u", - sp,urb->status,sp->fail_count); - } else { - (sp->buffers_failed)++; - bp->status = urb->status; - } - spin_unlock_irqrestore(&sp->list_lock,irq_flags); - pvr2_buffer_set_ready(bp); - if (sp && sp->callback_func) { - sp->callback_func(sp->callback_data); - } -} - -struct pvr2_stream *pvr2_stream_create(void) -{ - struct pvr2_stream *sp; - sp = kzalloc(sizeof(*sp),GFP_KERNEL); - if (!sp) return sp; - pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp); - pvr2_stream_init(sp); - return sp; -} - -void pvr2_stream_destroy(struct pvr2_stream *sp) -{ - if (!sp) return; - pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_destroy: sp=%p",sp); - pvr2_stream_done(sp); - kfree(sp); -} - -void pvr2_stream_setup(struct pvr2_stream *sp, - struct usb_device *dev, - int endpoint, - unsigned int tolerance) -{ - mutex_lock(&sp->mutex); do { - pvr2_stream_internal_flush(sp); - sp->dev = dev; - sp->endpoint = endpoint; - sp->fail_tolerance = tolerance; - } while(0); mutex_unlock(&sp->mutex); -} - -void pvr2_stream_set_callback(struct pvr2_stream *sp, - pvr2_stream_callback func, - void *data) -{ - unsigned long irq_flags; - mutex_lock(&sp->mutex); do { - spin_lock_irqsave(&sp->list_lock,irq_flags); - sp->callback_data = data; - sp->callback_func = func; - spin_unlock_irqrestore(&sp->list_lock,irq_flags); - } while(0); mutex_unlock(&sp->mutex); -} - -void pvr2_stream_get_stats(struct pvr2_stream *sp, - struct pvr2_stream_stats *stats, - int zero_counts) -{ - unsigned long irq_flags; - spin_lock_irqsave(&sp->list_lock,irq_flags); - if (stats) { - stats->buffers_in_queue = sp->q_count; - stats->buffers_in_idle = sp->i_count; - stats->buffers_in_ready = sp->r_count; - stats->buffers_processed = sp->buffers_processed; - stats->buffers_failed = sp->buffers_failed; - stats->bytes_processed = sp->bytes_processed; - } - if (zero_counts) { - sp->buffers_processed = 0; - sp->buffers_failed = 0; - sp->bytes_processed = 0; - } - spin_unlock_irqrestore(&sp->list_lock,irq_flags); -} - -/* Query / set the nominal buffer count */ -int pvr2_stream_get_buffer_count(struct pvr2_stream *sp) -{ - return sp->buffer_target_count; -} - -int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt) -{ - int ret; - if (sp->buffer_target_count == cnt) return 0; - mutex_lock(&sp->mutex); do { - sp->buffer_target_count = cnt; - ret = pvr2_stream_achieve_buffer_count(sp); - } while(0); mutex_unlock(&sp->mutex); - return ret; -} - -struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *sp) -{ - struct list_head *lp = sp->idle_list.next; - if (lp == &sp->idle_list) return NULL; - return list_entry(lp,struct pvr2_buffer,list_overhead); -} - -struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *sp) -{ - struct list_head *lp = sp->ready_list.next; - if (lp == &sp->ready_list) return NULL; - return list_entry(lp,struct pvr2_buffer,list_overhead); -} - -struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id) -{ - if (id < 0) return NULL; - if (id >= sp->buffer_total_count) return NULL; - return sp->buffers[id]; -} - -int pvr2_stream_get_ready_count(struct pvr2_stream *sp) -{ - return sp->r_count; -} - -void pvr2_stream_kill(struct pvr2_stream *sp) -{ - struct pvr2_buffer *bp; - mutex_lock(&sp->mutex); do { - pvr2_stream_internal_flush(sp); - while ((bp = pvr2_stream_get_ready_buffer(sp)) != NULL) { - pvr2_buffer_set_idle(bp); - } - if (sp->buffer_total_count != sp->buffer_target_count) { - pvr2_stream_achieve_buffer_count(sp); - } - } while(0); mutex_unlock(&sp->mutex); -} - -int pvr2_buffer_queue(struct pvr2_buffer *bp) -{ -#undef SEED_BUFFER -#ifdef SEED_BUFFER - unsigned int idx; - unsigned int val; -#endif - int ret = 0; - struct pvr2_stream *sp; - if (!bp) return -EINVAL; - sp = bp->stream; - mutex_lock(&sp->mutex); do { - pvr2_buffer_wipe(bp); - if (!sp->dev) { - ret = -EIO; - break; - } - pvr2_buffer_set_queued(bp); -#ifdef SEED_BUFFER - for (idx = 0; idx < (bp->max_count) / 4; idx++) { - val = bp->id << 24; - val |= idx; - ((unsigned int *)(bp->ptr))[idx] = val; - } -#endif - bp->status = -EINPROGRESS; - usb_fill_bulk_urb(bp->purb, // struct urb *urb - sp->dev, // struct usb_device *dev - // endpoint (below) - usb_rcvbulkpipe(sp->dev,sp->endpoint), - bp->ptr, // void *transfer_buffer - bp->max_count, // int buffer_length - buffer_complete, - bp); - usb_submit_urb(bp->purb,GFP_KERNEL); - } while(0); mutex_unlock(&sp->mutex); - return ret; -} - -int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt) -{ - int ret = 0; - unsigned long irq_flags; - struct pvr2_stream *sp; - if (!bp) return -EINVAL; - sp = bp->stream; - mutex_lock(&sp->mutex); do { - spin_lock_irqsave(&sp->list_lock,irq_flags); - if (bp->state != pvr2_buffer_state_idle) { - ret = -EPERM; - } else { - bp->ptr = ptr; - bp->stream->i_bcount -= bp->max_count; - bp->max_count = cnt; - bp->stream->i_bcount += bp->max_count; - pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/ bufferPool " - " %8s cap cap=%07d cnt=%02d", - pvr2_buffer_state_decode( - pvr2_buffer_state_idle), - bp->stream->i_bcount,bp->stream->i_count); - } - spin_unlock_irqrestore(&sp->list_lock,irq_flags); - } while(0); mutex_unlock(&sp->mutex); - return ret; -} - -unsigned int pvr2_buffer_get_count(struct pvr2_buffer *bp) -{ - return bp->used_count; -} - -int pvr2_buffer_get_status(struct pvr2_buffer *bp) -{ - return bp->status; -} - -int pvr2_buffer_get_id(struct pvr2_buffer *bp) -{ - return bp->id; -} - - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-io.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-io.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-io.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-io.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_IO_H -#define __PVRUSB2_IO_H - -#include -#include - -typedef void (*pvr2_stream_callback)(void *); - -enum pvr2_buffer_state { - pvr2_buffer_state_none = 0, // Not on any list - pvr2_buffer_state_idle = 1, // Buffer is ready to be used again - pvr2_buffer_state_queued = 2, // Buffer has been queued for filling - pvr2_buffer_state_ready = 3, // Buffer has data available -}; - -struct pvr2_stream; -struct pvr2_buffer; - -struct pvr2_stream_stats { - unsigned int buffers_in_queue; - unsigned int buffers_in_idle; - unsigned int buffers_in_ready; - unsigned int buffers_processed; - unsigned int buffers_failed; - unsigned int bytes_processed; -}; - -/* Initialize / tear down stream structure */ -struct pvr2_stream *pvr2_stream_create(void); -void pvr2_stream_destroy(struct pvr2_stream *); -void pvr2_stream_setup(struct pvr2_stream *, - struct usb_device *dev,int endpoint, - unsigned int tolerance); -void pvr2_stream_set_callback(struct pvr2_stream *, - pvr2_stream_callback func, - void *data); -void pvr2_stream_get_stats(struct pvr2_stream *, - struct pvr2_stream_stats *, - int zero_counts); - -/* Query / set the nominal buffer count */ -int pvr2_stream_get_buffer_count(struct pvr2_stream *); -int pvr2_stream_set_buffer_count(struct pvr2_stream *,unsigned int); - -/* Get a pointer to a buffer that is either idle, ready, or is specified - named. */ -struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *); -struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *); -struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id); - -/* Find out how many buffers are idle or ready */ -int pvr2_stream_get_ready_count(struct pvr2_stream *); - - -/* Kill all pending buffers and throw away any ready buffers as well */ -void pvr2_stream_kill(struct pvr2_stream *); - -/* Set up the actual storage for a buffer */ -int pvr2_buffer_set_buffer(struct pvr2_buffer *,void *ptr,unsigned int cnt); - -/* Find out size of data in the given ready buffer */ -unsigned int pvr2_buffer_get_count(struct pvr2_buffer *); - -/* Retrieve completion code for given ready buffer */ -int pvr2_buffer_get_status(struct pvr2_buffer *); - -/* Retrieve ID of given buffer */ -int pvr2_buffer_get_id(struct pvr2_buffer *); - -/* Start reading into given buffer (kill it if needed) */ -int pvr2_buffer_queue(struct pvr2_buffer *); - -#endif /* __PVRUSB2_IO_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,512 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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-ioread.h" -#include "pvrusb2-debug.h" -#include -#include -#include -#include -#include -#include - -#define BUFFER_COUNT 32 -#define BUFFER_SIZE PAGE_ALIGN(0x4000) - -struct pvr2_ioread { - struct pvr2_stream *stream; - char *buffer_storage[BUFFER_COUNT]; - char *sync_key_ptr; - unsigned int sync_key_len; - unsigned int sync_buf_offs; - unsigned int sync_state; - unsigned int sync_trashed_count; - int enabled; // Streaming is on - int spigot_open; // OK to pass data to client - int stream_running; // Passing data to client now - - /* State relevant to current buffer being read */ - struct pvr2_buffer *c_buf; - char *c_data_ptr; - unsigned int c_data_len; - unsigned int c_data_offs; - struct mutex mutex; -}; - -static int pvr2_ioread_init(struct pvr2_ioread *cp) -{ - unsigned int idx; - - cp->stream = NULL; - mutex_init(&cp->mutex); - - for (idx = 0; idx < BUFFER_COUNT; idx++) { - cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL); - if (!(cp->buffer_storage[idx])) break; - } - - if (idx < BUFFER_COUNT) { - // An allocation appears to have failed - for (idx = 0; idx < BUFFER_COUNT; idx++) { - if (!(cp->buffer_storage[idx])) continue; - kfree(cp->buffer_storage[idx]); - } - return -ENOMEM; - } - return 0; -} - -static void pvr2_ioread_done(struct pvr2_ioread *cp) -{ - unsigned int idx; - - pvr2_ioread_setup(cp,NULL); - for (idx = 0; idx < BUFFER_COUNT; idx++) { - if (!(cp->buffer_storage[idx])) continue; - kfree(cp->buffer_storage[idx]); - } -} - -struct pvr2_ioread *pvr2_ioread_create(void) -{ - struct pvr2_ioread *cp; - cp = kzalloc(sizeof(*cp),GFP_KERNEL); - if (!cp) return NULL; - pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp); - if (pvr2_ioread_init(cp) < 0) { - kfree(cp); - return NULL; - } - return cp; -} - -void pvr2_ioread_destroy(struct pvr2_ioread *cp) -{ - if (!cp) return; - pvr2_ioread_done(cp); - pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp); - if (cp->sync_key_ptr) { - kfree(cp->sync_key_ptr); - cp->sync_key_ptr = NULL; - } - kfree(cp); -} - -void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp, - const char *sync_key_ptr, - unsigned int sync_key_len) -{ - if (!cp) return; - - if (!sync_key_ptr) sync_key_len = 0; - if ((sync_key_len == cp->sync_key_len) && - ((!sync_key_len) || - (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return; - - if (sync_key_len != cp->sync_key_len) { - if (cp->sync_key_ptr) { - kfree(cp->sync_key_ptr); - cp->sync_key_ptr = NULL; - } - cp->sync_key_len = 0; - if (sync_key_len) { - cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL); - if (cp->sync_key_ptr) { - cp->sync_key_len = sync_key_len; - } - } - } - if (!cp->sync_key_len) return; - memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len); -} - -static void pvr2_ioread_stop(struct pvr2_ioread *cp) -{ - if (!(cp->enabled)) return; - pvr2_trace(PVR2_TRACE_START_STOP, - "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp); - pvr2_stream_kill(cp->stream); - cp->c_buf = NULL; - cp->c_data_ptr = NULL; - cp->c_data_len = 0; - cp->c_data_offs = 0; - cp->enabled = 0; - cp->stream_running = 0; - cp->spigot_open = 0; - if (cp->sync_state) { - pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/ sync_state <== 0"); - cp->sync_state = 0; - } -} - -static int pvr2_ioread_start(struct pvr2_ioread *cp) -{ - int stat; - struct pvr2_buffer *bp; - if (cp->enabled) return 0; - if (!(cp->stream)) return 0; - pvr2_trace(PVR2_TRACE_START_STOP, - "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp); - while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) { - stat = pvr2_buffer_queue(bp); - if (stat < 0) { - pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " pvr2_ioread_start id=%p" - " error=%d", - cp,stat); - pvr2_ioread_stop(cp); - return stat; - } - } - cp->enabled = !0; - cp->c_buf = NULL; - cp->c_data_ptr = NULL; - cp->c_data_len = 0; - cp->c_data_offs = 0; - cp->stream_running = 0; - if (cp->sync_key_len) { - pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/ sync_state <== 1"); - cp->sync_state = 1; - cp->sync_trashed_count = 0; - cp->sync_buf_offs = 0; - } - cp->spigot_open = 0; - return 0; -} - -struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp) -{ - return cp->stream; -} - -int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) -{ - int ret; - unsigned int idx; - struct pvr2_buffer *bp; - - mutex_lock(&cp->mutex); do { - if (cp->stream) { - pvr2_trace(PVR2_TRACE_START_STOP, - "/*---TRACE_READ---*/" - " pvr2_ioread_setup (tear-down) id=%p",cp); - pvr2_ioread_stop(cp); - pvr2_stream_kill(cp->stream); - if (pvr2_stream_get_buffer_count(cp->stream)) { - pvr2_stream_set_buffer_count(cp->stream,0); - } - cp->stream = NULL; - } - if (sp) { - pvr2_trace(PVR2_TRACE_START_STOP, - "/*---TRACE_READ---*/" - " pvr2_ioread_setup (setup) id=%p",cp); - pvr2_stream_kill(sp); - ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT); - if (ret < 0) { - mutex_unlock(&cp->mutex); - return ret; - } - for (idx = 0; idx < BUFFER_COUNT; idx++) { - bp = pvr2_stream_get_buffer(sp,idx); - pvr2_buffer_set_buffer(bp, - cp->buffer_storage[idx], - BUFFER_SIZE); - } - cp->stream = sp; - } - } while (0); mutex_unlock(&cp->mutex); - - return 0; -} - -int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl) -{ - int ret = 0; - if ((!fl) == (!(cp->enabled))) return ret; - - mutex_lock(&cp->mutex); do { - if (fl) { - ret = pvr2_ioread_start(cp); - } else { - pvr2_ioread_stop(cp); - } - } while (0); mutex_unlock(&cp->mutex); - return ret; -} - -static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp) -{ - int stat; - - while (cp->c_data_len <= cp->c_data_offs) { - if (cp->c_buf) { - // Flush out current buffer first. - stat = pvr2_buffer_queue(cp->c_buf); - if (stat < 0) { - // Streaming error... - pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " pvr2_ioread_read id=%p" - " queue_error=%d", - cp,stat); - pvr2_ioread_stop(cp); - return 0; - } - cp->c_buf = NULL; - cp->c_data_ptr = NULL; - cp->c_data_len = 0; - cp->c_data_offs = 0; - } - // Now get a freshly filled buffer. - cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream); - if (!cp->c_buf) break; // Nothing ready; done. - cp->c_data_len = pvr2_buffer_get_count(cp->c_buf); - if (!cp->c_data_len) { - // Nothing transferred. Was there an error? - stat = pvr2_buffer_get_status(cp->c_buf); - if (stat < 0) { - // Streaming error... - pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " pvr2_ioread_read id=%p" - " buffer_error=%d", - cp,stat); - pvr2_ioread_stop(cp); - // Give up. - return 0; - } - // Start over... - continue; - } - cp->c_data_offs = 0; - cp->c_data_ptr = cp->buffer_storage[ - pvr2_buffer_get_id(cp->c_buf)]; - } - return !0; -} - -static void pvr2_ioread_filter(struct pvr2_ioread *cp) -{ - unsigned int idx; - if (!cp->enabled) return; - if (cp->sync_state != 1) return; - - // Search the stream for our synchronization key. This is made - // complicated by the fact that in order to be honest with - // ourselves here we must search across buffer boundaries... - mutex_lock(&cp->mutex); while (1) { - // Ensure we have a buffer - if (!pvr2_ioread_get_buffer(cp)) break; - if (!cp->c_data_len) break; - - // Now walk the buffer contents until we match the key or - // run out of buffer data. - for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) { - if (cp->sync_buf_offs >= cp->sync_key_len) break; - if (cp->c_data_ptr[idx] == - cp->sync_key_ptr[cp->sync_buf_offs]) { - // Found the next key byte - (cp->sync_buf_offs)++; - } else { - // Whoops, mismatched. Start key over... - cp->sync_buf_offs = 0; - } - } - - // Consume what we've walked through - cp->c_data_offs += idx; - cp->sync_trashed_count += idx; - - // If we've found the key, then update state and get out. - if (cp->sync_buf_offs >= cp->sync_key_len) { - cp->sync_trashed_count -= cp->sync_key_len; - pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " sync_state <== 2 (skipped %u bytes)", - cp->sync_trashed_count); - cp->sync_state = 2; - cp->sync_buf_offs = 0; - break; - } - - if (cp->c_data_offs < cp->c_data_len) { - // Sanity check - should NEVER get here - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "ERROR: pvr2_ioread filter sync problem" - " len=%u offs=%u", - cp->c_data_len,cp->c_data_offs); - // Get out so we don't get stuck in an infinite - // loop. - break; - } - - continue; // (for clarity) - } mutex_unlock(&cp->mutex); -} - -int pvr2_ioread_avail(struct pvr2_ioread *cp) -{ - int ret; - if (!(cp->enabled)) { - // Stream is not enabled; so this is an I/O error - return -EIO; - } - - if (cp->sync_state == 1) { - pvr2_ioread_filter(cp); - if (cp->sync_state == 1) return -EAGAIN; - } - - ret = 0; - if (cp->stream_running) { - if (!pvr2_stream_get_ready_count(cp->stream)) { - // No data available at all right now. - ret = -EAGAIN; - } - } else { - if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) { - // Haven't buffered up enough yet; try again later - ret = -EAGAIN; - } - } - - if ((!(cp->spigot_open)) != (!(ret == 0))) { - cp->spigot_open = (ret == 0); - pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/ data is %s", - cp->spigot_open ? "available" : "pending"); - } - - return ret; -} - -int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) -{ - unsigned int copied_cnt; - unsigned int bcnt; - const char *src; - int stat; - int ret = 0; - unsigned int req_cnt = cnt; - - if (!cnt) { - pvr2_trace(PVR2_TRACE_TRAP, - "/*---TRACE_READ---*/ pvr2_ioread_read id=%p" - " ZERO Request? Returning zero.",cp); - return 0; - } - - stat = pvr2_ioread_avail(cp); - if (stat < 0) return stat; - - cp->stream_running = !0; - - mutex_lock(&cp->mutex); do { - - // Suck data out of the buffers and copy to the user - copied_cnt = 0; - if (!buf) cnt = 0; - while (1) { - if (!pvr2_ioread_get_buffer(cp)) { - ret = -EIO; - break; - } - - if (!cnt) break; - - if (cp->sync_state == 2) { - // We're repeating the sync key data into - // the stream. - src = cp->sync_key_ptr + cp->sync_buf_offs; - bcnt = cp->sync_key_len - cp->sync_buf_offs; - } else { - // Normal buffer copy - src = cp->c_data_ptr + cp->c_data_offs; - bcnt = cp->c_data_len - cp->c_data_offs; - } - - if (!bcnt) break; - - // Don't run past user's buffer - if (bcnt > cnt) bcnt = cnt; - - if (copy_to_user(buf,src,bcnt)) { - // User supplied a bad pointer? - // Give up - this *will* cause data - // to be lost. - ret = -EFAULT; - break; - } - cnt -= bcnt; - buf += bcnt; - copied_cnt += bcnt; - - if (cp->sync_state == 2) { - // Update offset inside sync key that we're - // repeating back out. - cp->sync_buf_offs += bcnt; - if (cp->sync_buf_offs >= cp->sync_key_len) { - // Consumed entire key; switch mode - // to normal. - pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " sync_state <== 0"); - cp->sync_state = 0; - } - } else { - // Update buffer offset. - cp->c_data_offs += bcnt; - } - } - - } while (0); mutex_unlock(&cp->mutex); - - if (!ret) { - if (copied_cnt) { - // If anything was copied, return that count - ret = copied_cnt; - } else { - // Nothing copied; suggest to caller that another - // attempt should be tried again later - ret = -EAGAIN; - } - } - - pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/ pvr2_ioread_read" - " id=%p request=%d result=%d", - cp,req_cnt,ret); - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_IOREAD_H -#define __PVRUSB2_IOREAD_H - -#include "pvrusb2-io.h" - -struct pvr2_ioread; - -struct pvr2_ioread *pvr2_ioread_create(void); -void pvr2_ioread_destroy(struct pvr2_ioread *); -int pvr2_ioread_setup(struct pvr2_ioread *,struct pvr2_stream *); -struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *); -void pvr2_ioread_set_sync_key(struct pvr2_ioread *, - const char *sync_key_ptr, - unsigned int sync_key_len); -int pvr2_ioread_set_enabled(struct pvr2_ioread *,int fl); -int pvr2_ioread_read(struct pvr2_ioread *,void __user *buf,unsigned int cnt); -int pvr2_ioread_avail(struct pvr2_ioread *); - -#endif /* __PVRUSB2_IOREAD_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-main.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-main.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-main.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-main.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,181 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 -#include -#include -#include -#include - -#include "pvrusb2-hdw.h" -#include "pvrusb2-devattr.h" -#include "pvrusb2-context.h" -#include "pvrusb2-debug.h" -#include "pvrusb2-v4l2.h" -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS -#include "pvrusb2-sysfs.h" -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ - -#define DRIVER_AUTHOR "Mike Isely " -#define DRIVER_DESC "Hauppauge WinTV-PVR-USB2 MPEG2 Encoder/Tuner" -#define DRIVER_VERSION "V4L in-tree version" - -#define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \ - PVR2_TRACE_INFO| \ - PVR2_TRACE_STD| \ - PVR2_TRACE_TOLERANCE| \ - PVR2_TRACE_TRAP| \ - 0) - -int pvrusb2_debug = DEFAULT_DEBUG_MASK; - -module_param_named(debug,pvrusb2_debug,int,S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(debug, "Debug trace mask"); - -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS -static struct pvr2_sysfs_class *class_ptr = NULL; -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ - -static void pvr_setup_attach(struct pvr2_context *pvr) -{ - /* Create association with v4l layer */ - pvr2_v4l2_create(pvr); -#ifdef CONFIG_VIDEO_PVRUSB2_DVB - /* Create association with dvb layer */ - pvr2_dvb_create(pvr); -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS - pvr2_sysfs_create(pvr,class_ptr); -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ -} - -static int pvr_probe(struct usb_interface *intf, - const struct usb_device_id *devid) -{ - struct pvr2_context *pvr; - - /* Create underlying hardware interface */ - pvr = pvr2_context_create(intf,devid,pvr_setup_attach); - if (!pvr) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to create hdw handler"); - return -ENOMEM; - } - - pvr2_trace(PVR2_TRACE_INIT,"pvr_probe(pvr=%p)",pvr); - - usb_set_intfdata(intf, pvr); - - return 0; -} - -/* - * pvr_disconnect() - * - */ -static void pvr_disconnect(struct usb_interface *intf) -{ - struct pvr2_context *pvr = usb_get_intfdata(intf); - - pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) BEGIN",pvr); - - usb_set_intfdata (intf, NULL); - pvr2_context_disconnect(pvr); - - pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) DONE",pvr); - -} - -static struct usb_driver pvr_driver = { - .name = "pvrusb2", - .id_table = pvr2_device_table, - .probe = pvr_probe, - .disconnect = pvr_disconnect -}; - -/* - * pvr_init() / pvr_exit() - * - * This code is run to initialize/exit the driver. - * - */ -static int __init pvr_init(void) -{ - int ret; - - pvr2_trace(PVR2_TRACE_INIT,"pvr_init"); - - ret = pvr2_context_global_init(); - if (ret != 0) { - pvr2_trace(PVR2_TRACE_INIT,"pvr_init failure code=%d",ret); - return ret; - } - -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS - class_ptr = pvr2_sysfs_class_create(); -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ - - ret = usb_register(&pvr_driver); - - if (ret == 0) - printk(KERN_INFO "pvrusb2: " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - if (pvrusb2_debug) - printk(KERN_INFO "pvrusb2: Debug mask is %d (0x%x)\n", - pvrusb2_debug,pvrusb2_debug); - - pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete"); - - return ret; -} - -static void __exit pvr_exit(void) -{ - pvr2_trace(PVR2_TRACE_INIT,"pvr_exit"); - - usb_deregister(&pvr_driver); - - pvr2_context_global_done(); - -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS - pvr2_sysfs_class_destroy(class_ptr); -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ - - pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete"); -} - -module_init(pvr_init); -module_exit(pvr_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-std.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-std.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-std.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-std.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,409 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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-std.h" -#include "pvrusb2-debug.h" -#include -#include - -struct std_name { - const char *name; - v4l2_std_id id; -}; - - -#define CSTD_PAL \ - (V4L2_STD_PAL_B| \ - V4L2_STD_PAL_B1| \ - V4L2_STD_PAL_G| \ - V4L2_STD_PAL_H| \ - V4L2_STD_PAL_I| \ - V4L2_STD_PAL_D| \ - V4L2_STD_PAL_D1| \ - V4L2_STD_PAL_K| \ - V4L2_STD_PAL_M| \ - V4L2_STD_PAL_N| \ - V4L2_STD_PAL_Nc| \ - V4L2_STD_PAL_60) - -#define CSTD_NTSC \ - (V4L2_STD_NTSC_M| \ - V4L2_STD_NTSC_M_JP| \ - V4L2_STD_NTSC_M_KR| \ - V4L2_STD_NTSC_443) - -#define CSTD_ATSC \ - (V4L2_STD_ATSC_8_VSB| \ - V4L2_STD_ATSC_16_VSB) - -#define CSTD_SECAM \ - (V4L2_STD_SECAM_B| \ - V4L2_STD_SECAM_D| \ - V4L2_STD_SECAM_G| \ - V4L2_STD_SECAM_H| \ - V4L2_STD_SECAM_K| \ - V4L2_STD_SECAM_K1| \ - V4L2_STD_SECAM_L| \ - V4L2_STD_SECAM_LC) - -#define TSTD_B (V4L2_STD_PAL_B|V4L2_STD_SECAM_B) -#define TSTD_B1 (V4L2_STD_PAL_B1) -#define TSTD_D (V4L2_STD_PAL_D|V4L2_STD_SECAM_D) -#define TSTD_D1 (V4L2_STD_PAL_D1) -#define TSTD_G (V4L2_STD_PAL_G|V4L2_STD_SECAM_G) -#define TSTD_H (V4L2_STD_PAL_H|V4L2_STD_SECAM_H) -#define TSTD_I (V4L2_STD_PAL_I) -#define TSTD_K (V4L2_STD_PAL_K|V4L2_STD_SECAM_K) -#define TSTD_K1 (V4L2_STD_SECAM_K1) -#define TSTD_L (V4L2_STD_SECAM_L) -#define TSTD_M (V4L2_STD_PAL_M|V4L2_STD_NTSC_M) -#define TSTD_N (V4L2_STD_PAL_N) -#define TSTD_Nc (V4L2_STD_PAL_Nc) -#define TSTD_60 (V4L2_STD_PAL_60) - -#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_ATSC|CSTD_SECAM) - -/* Mapping of standard bits to color system */ -static const struct std_name std_groups[] = { - {"PAL",CSTD_PAL}, - {"NTSC",CSTD_NTSC}, - {"SECAM",CSTD_SECAM}, - {"ATSC",CSTD_ATSC}, -}; - -/* Mapping of standard bits to modulation system */ -static const struct std_name std_items[] = { - {"B",TSTD_B}, - {"B1",TSTD_B1}, - {"D",TSTD_D}, - {"D1",TSTD_D1}, - {"G",TSTD_G}, - {"H",TSTD_H}, - {"I",TSTD_I}, - {"K",TSTD_K}, - {"K1",TSTD_K1}, - {"L",TSTD_L}, - {"LC",V4L2_STD_SECAM_LC}, - {"M",TSTD_M}, - {"Mj",V4L2_STD_NTSC_M_JP}, - {"443",V4L2_STD_NTSC_443}, - {"Mk",V4L2_STD_NTSC_M_KR}, - {"N",TSTD_N}, - {"Nc",TSTD_Nc}, - {"60",TSTD_60}, - {"8VSB",V4L2_STD_ATSC_8_VSB}, - {"16VSB",V4L2_STD_ATSC_16_VSB}, -}; - - -// Search an array of std_name structures and return a pointer to the -// element with the matching name. -static const struct std_name *find_std_name(const struct std_name *arrPtr, - unsigned int arrSize, - const char *bufPtr, - unsigned int bufSize) -{ - unsigned int idx; - const struct std_name *p; - for (idx = 0; idx < arrSize; idx++) { - p = arrPtr + idx; - if (strlen(p->name) != bufSize) continue; - if (!memcmp(bufPtr,p->name,bufSize)) return p; - } - return NULL; -} - - -int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr, - unsigned int bufSize) -{ - v4l2_std_id id = 0; - v4l2_std_id cmsk = 0; - v4l2_std_id t; - int mMode = 0; - unsigned int cnt; - char ch; - const struct std_name *sp; - - while (bufSize) { - if (!mMode) { - cnt = 0; - while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++; - if (cnt >= bufSize) return 0; // No more characters - sp = find_std_name(std_groups, ARRAY_SIZE(std_groups), - bufPtr,cnt); - if (!sp) return 0; // Illegal color system name - cnt++; - bufPtr += cnt; - bufSize -= cnt; - mMode = !0; - cmsk = sp->id; - continue; - } - cnt = 0; - while (cnt < bufSize) { - ch = bufPtr[cnt]; - if (ch == ';') { - mMode = 0; - break; - } - if (ch == '/') break; - cnt++; - } - sp = find_std_name(std_items, ARRAY_SIZE(std_items), - bufPtr,cnt); - if (!sp) return 0; // Illegal modulation system ID - t = sp->id & cmsk; - if (!t) return 0; // Specific color + modulation system illegal - id |= t; - if (cnt < bufSize) cnt++; - bufPtr += cnt; - bufSize -= cnt; - } - - if (idPtr) *idPtr = id; - return !0; -} - - -unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize, - v4l2_std_id id) -{ - unsigned int idx1,idx2; - const struct std_name *ip,*gp; - int gfl,cfl; - unsigned int c1,c2; - cfl = 0; - c1 = 0; - for (idx1 = 0; idx1 < ARRAY_SIZE(std_groups); idx1++) { - gp = std_groups + idx1; - gfl = 0; - for (idx2 = 0; idx2 < ARRAY_SIZE(std_items); idx2++) { - ip = std_items + idx2; - if (!(gp->id & ip->id & id)) continue; - if (!gfl) { - if (cfl) { - c2 = scnprintf(bufPtr,bufSize,";"); - c1 += c2; - bufSize -= c2; - bufPtr += c2; - } - cfl = !0; - c2 = scnprintf(bufPtr,bufSize, - "%s-",gp->name); - gfl = !0; - } else { - c2 = scnprintf(bufPtr,bufSize,"/"); - } - c1 += c2; - bufSize -= c2; - bufPtr += c2; - c2 = scnprintf(bufPtr,bufSize, - ip->name); - c1 += c2; - bufSize -= c2; - bufPtr += c2; - } - } - return c1; -} - - -// Template data for possible enumerated video standards. Here we group -// standards which share common frame rates and resolution. -static struct v4l2_standard generic_standards[] = { - { - .id = (TSTD_B|TSTD_B1| - TSTD_D|TSTD_D1| - TSTD_G| - TSTD_H| - TSTD_I| - TSTD_K|TSTD_K1| - TSTD_L| - V4L2_STD_SECAM_LC | - TSTD_N|TSTD_Nc), - .frameperiod = - { - .numerator = 1, - .denominator= 25 - }, - .framelines = 625, - .reserved = {0,0,0,0} - }, { - .id = (TSTD_M| - V4L2_STD_NTSC_M_JP| - V4L2_STD_NTSC_M_KR), - .frameperiod = - { - .numerator = 1001, - .denominator= 30000 - }, - .framelines = 525, - .reserved = {0,0,0,0} - }, { // This is a total wild guess - .id = (TSTD_60), - .frameperiod = - { - .numerator = 1001, - .denominator= 30000 - }, - .framelines = 525, - .reserved = {0,0,0,0} - }, { // This is total wild guess - .id = V4L2_STD_NTSC_443, - .frameperiod = - { - .numerator = 1001, - .denominator= 30000 - }, - .framelines = 525, - .reserved = {0,0,0,0} - } -}; - -#define generic_standards_cnt ARRAY_SIZE(generic_standards) - -static struct v4l2_standard *match_std(v4l2_std_id id) -{ - unsigned int idx; - for (idx = 0; idx < generic_standards_cnt; idx++) { - if (generic_standards[idx].id & id) { - return generic_standards + idx; - } - } - return NULL; -} - -static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id) -{ - struct v4l2_standard *template; - int idx; - unsigned int bcnt; - template = match_std(id); - if (!template) return 0; - idx = std->index; - memcpy(std,template,sizeof(*template)); - std->index = idx; - std->id = id; - bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id); - std->name[bcnt] = 0; - pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s", - std->index,std->name); - return !0; -} - -/* These are special cases of combined standards that we should enumerate - separately if the component pieces are present. */ -static v4l2_std_id std_mixes[] = { - V4L2_STD_PAL_B | V4L2_STD_PAL_G, - V4L2_STD_PAL_D | V4L2_STD_PAL_K, - V4L2_STD_SECAM_B | V4L2_STD_SECAM_G, - V4L2_STD_SECAM_D | V4L2_STD_SECAM_K, -}; - -struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, - v4l2_std_id id) -{ - unsigned int std_cnt = 0; - unsigned int idx,bcnt,idx2; - v4l2_std_id idmsk,cmsk,fmsk; - struct v4l2_standard *stddefs; - - if (pvrusb2_debug & PVR2_TRACE_STD) { - char buf[100]; - bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id); - pvr2_trace( - PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)", - (int)id,bcnt,buf); - } - - *countptr = 0; - std_cnt = 0; - fmsk = 0; - for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) { - if (!(idmsk & cmsk)) continue; - cmsk &= ~idmsk; - if (match_std(idmsk)) { - std_cnt++; - continue; - } - fmsk |= idmsk; - } - - for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) { - if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++; - } - - /* Don't complain about ATSC standard values */ - fmsk &= ~CSTD_ATSC; - - if (fmsk) { - char buf[100]; - bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk); - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "WARNING:" - " Failed to classify the following standard(s): %.*s", - bcnt,buf); - } - - pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)", - std_cnt); - if (!std_cnt) return NULL; // paranoia - - stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt, - GFP_KERNEL); - for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx; - - idx = 0; - - /* Enumerate potential special cases */ - for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt); - idx2++) { - if (!(id & std_mixes[idx2])) continue; - if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++; - } - /* Now enumerate individual pieces */ - for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) { - if (!(idmsk & cmsk)) continue; - cmsk &= ~idmsk; - if (!pvr2_std_fill(stddefs+idx,idmsk)) continue; - idx++; - } - - *countptr = std_cnt; - return stddefs; -} - -v4l2_std_id pvr2_std_get_usable(void) -{ - return CSTD_ALL; -} - - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-std.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-std.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-std.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-std.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_STD_H -#define __PVRUSB2_STD_H - -#include - -// Convert string describing one or more video standards into a mask of V4L -// standard bits. Return true if conversion succeeds otherwise return -// false. String is expected to be of the form: C1-x/y;C2-a/b where C1 and -// C2 are color system names (e.g. "PAL", "NTSC") and x, y, a, and b are -// modulation schemes (e.g. "M", "B", "G", etc). -int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr, - unsigned int bufSize); - -// Convert any arbitrary set of video standard bits into an unambiguous -// readable string. Return value is the number of bytes consumed in the -// buffer. The formatted string is of a form that can be parsed by our -// sibling std_std_to_id() function. -unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize, - v4l2_std_id id); - -// Create an array of suitable v4l2_standard structures given a bit mask of -// video standards to support. The array is allocated from the heap, and -// the number of elements is returned in the first argument. -struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, - v4l2_std_id id); - -// Return mask of which video standard bits are valid -v4l2_std_id pvr2_std_get_usable(void); - -#endif /* __PVRUSB2_STD_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,861 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 -#include -#include "pvrusb2-sysfs.h" -#include "pvrusb2-hdw.h" -#include "pvrusb2-debug.h" -#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -#include "pvrusb2-debugifc.h" -#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ - -#define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__) - -struct pvr2_sysfs { - struct pvr2_channel channel; - struct device *class_dev; -#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC - struct pvr2_sysfs_debugifc *debugifc; -#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ - struct pvr2_sysfs_ctl_item *item_first; - struct pvr2_sysfs_ctl_item *item_last; - struct device_attribute attr_v4l_minor_number; - struct device_attribute attr_v4l_radio_minor_number; - struct device_attribute attr_unit_number; - struct device_attribute attr_bus_info; - struct device_attribute attr_hdw_name; - struct device_attribute attr_hdw_desc; - int v4l_minor_number_created_ok; - int v4l_radio_minor_number_created_ok; - int unit_number_created_ok; - int bus_info_created_ok; - int hdw_name_created_ok; - int hdw_desc_created_ok; -}; - -#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -struct pvr2_sysfs_debugifc { - struct device_attribute attr_debugcmd; - struct device_attribute attr_debuginfo; - int debugcmd_created_ok; - int debuginfo_created_ok; -}; -#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ - -struct pvr2_sysfs_ctl_item { - struct device_attribute attr_name; - struct device_attribute attr_type; - struct device_attribute attr_min; - struct device_attribute attr_max; - struct device_attribute attr_def; - struct device_attribute attr_enum; - struct device_attribute attr_bits; - struct device_attribute attr_val; - struct device_attribute attr_custom; - struct pvr2_ctrl *cptr; - int ctl_id; - struct pvr2_sysfs *chptr; - struct pvr2_sysfs_ctl_item *item_next; - struct attribute *attr_gen[8]; - struct attribute_group grp; - int created_ok; - char name[80]; -}; - -struct pvr2_sysfs_class { - struct class class; -}; - -static ssize_t show_name(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs_ctl_item *cip; - const char *name; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_name); - name = pvr2_ctrl_get_desc(cip->cptr); - pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s", - cip->chptr, cip->ctl_id, name); - if (!name) return -EINVAL; - return scnprintf(buf, PAGE_SIZE, "%s\n", name); -} - -static ssize_t show_type(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs_ctl_item *cip; - const char *name; - enum pvr2_ctl_type tp; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_type); - tp = pvr2_ctrl_get_type(cip->cptr); - switch (tp) { - case pvr2_ctl_int: name = "integer"; break; - case pvr2_ctl_enum: name = "enum"; break; - case pvr2_ctl_bitmask: name = "bitmask"; break; - case pvr2_ctl_bool: name = "boolean"; break; - default: name = "?"; break; - } - pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s", - cip->chptr, cip->ctl_id, name); - if (!name) return -EINVAL; - return scnprintf(buf, PAGE_SIZE, "%s\n", name); -} - -static ssize_t show_min(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs_ctl_item *cip; - long val; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_min); - val = pvr2_ctrl_get_min(cip->cptr); - pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld", - cip->chptr, cip->ctl_id, val); - return scnprintf(buf, PAGE_SIZE, "%ld\n", val); -} - -static ssize_t show_max(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs_ctl_item *cip; - long val; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_max); - val = pvr2_ctrl_get_max(cip->cptr); - pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld", - cip->chptr, cip->ctl_id, val); - return scnprintf(buf, PAGE_SIZE, "%ld\n", val); -} - -static ssize_t show_def(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs_ctl_item *cip; - int val; - int ret; - unsigned int cnt = 0; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_def); - ret = pvr2_ctrl_get_def(cip->cptr, &val); - if (ret < 0) return ret; - ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val, - buf, PAGE_SIZE - 1, &cnt); - pvr2_sysfs_trace("pvr2_sysfs(%p) show_def(cid=%d) is %.*s (%d)", - cip->chptr, cip->ctl_id, cnt, buf, val); - buf[cnt] = '\n'; - return cnt + 1; -} - -static ssize_t show_val_norm(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs_ctl_item *cip; - int val; - int ret; - unsigned int cnt = 0; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val); - ret = pvr2_ctrl_get_value(cip->cptr, &val); - if (ret < 0) return ret; - ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val, - buf, PAGE_SIZE - 1, &cnt); - pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)", - cip->chptr, cip->ctl_id, cnt, buf, val); - buf[cnt] = '\n'; - return cnt+1; -} - -static ssize_t show_val_custom(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs_ctl_item *cip; - int val; - int ret; - unsigned int cnt = 0; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom); - ret = pvr2_ctrl_get_value(cip->cptr, &val); - if (ret < 0) return ret; - ret = pvr2_ctrl_custom_value_to_sym(cip->cptr, ~0, val, - buf, PAGE_SIZE - 1, &cnt); - pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)", - cip->chptr, cip->ctl_id, cnt, buf, val); - buf[cnt] = '\n'; - return cnt+1; -} - -static ssize_t show_enum(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs_ctl_item *cip; - long val; - unsigned int bcnt, ccnt, ecnt; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_enum); - ecnt = pvr2_ctrl_get_cnt(cip->cptr); - bcnt = 0; - for (val = 0; val < ecnt; val++) { - pvr2_ctrl_get_valname(cip->cptr, val, buf + bcnt, - PAGE_SIZE - bcnt, &ccnt); - if (!ccnt) continue; - bcnt += ccnt; - if (bcnt >= PAGE_SIZE) break; - buf[bcnt] = '\n'; - bcnt++; - } - pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)", - cip->chptr, cip->ctl_id); - return bcnt; -} - -static ssize_t show_bits(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs_ctl_item *cip; - int valid_bits, msk; - unsigned int bcnt, ccnt; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_bits); - valid_bits = pvr2_ctrl_get_mask(cip->cptr); - bcnt = 0; - for (msk = 1; valid_bits; msk <<= 1) { - if (!(msk & valid_bits)) continue; - valid_bits &= ~msk; - pvr2_ctrl_get_valname(cip->cptr, msk, buf + bcnt, - PAGE_SIZE - bcnt, &ccnt); - bcnt += ccnt; - if (bcnt >= PAGE_SIZE) break; - buf[bcnt] = '\n'; - bcnt++; - } - pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)", - cip->chptr, cip->ctl_id); - return bcnt; -} - -static int store_val_any(struct pvr2_sysfs_ctl_item *cip, int customfl, - const char *buf,unsigned int count) -{ - int ret; - int mask,val; - if (customfl) { - ret = pvr2_ctrl_custom_sym_to_value(cip->cptr, buf, count, - &mask, &val); - } else { - ret = pvr2_ctrl_sym_to_value(cip->cptr, buf, count, - &mask, &val); - } - if (ret < 0) return ret; - ret = pvr2_ctrl_set_mask_value(cip->cptr, mask, val); - pvr2_hdw_commit_ctl(cip->chptr->channel.hdw); - return ret; -} - -static ssize_t store_val_norm(struct device *class_dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pvr2_sysfs_ctl_item *cip; - int ret; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val); - pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"", - cip->chptr, cip->ctl_id, (int)count, buf); - ret = store_val_any(cip, 0, buf, count); - if (!ret) ret = count; - return ret; -} - -static ssize_t store_val_custom(struct device *class_dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pvr2_sysfs_ctl_item *cip; - int ret; - cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom); - pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"", - cip->chptr, cip->ctl_id, (int)count, buf); - ret = store_val_any(cip, 1, buf, count); - if (!ret) ret = count; - return ret; -} - -static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) -{ - struct pvr2_sysfs_ctl_item *cip; - struct pvr2_ctrl *cptr; - unsigned int cnt,acnt; - int ret; - - cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id); - if (!cptr) return; - - cip = kzalloc(sizeof(*cip),GFP_KERNEL); - if (!cip) return; - pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip); - - cip->cptr = cptr; - cip->ctl_id = ctl_id; - - cip->chptr = sfp; - cip->item_next = NULL; - if (sfp->item_last) { - sfp->item_last->item_next = cip; - } else { - sfp->item_first = cip; - } - sfp->item_last = cip; - - sysfs_attr_init(&cip->attr_name.attr); - cip->attr_name.attr.name = "name"; - cip->attr_name.attr.mode = S_IRUGO; - cip->attr_name.show = show_name; - - sysfs_attr_init(&cip->attr_type.attr); - cip->attr_type.attr.name = "type"; - cip->attr_type.attr.mode = S_IRUGO; - cip->attr_type.show = show_type; - - sysfs_attr_init(&cip->attr_min.attr); - cip->attr_min.attr.name = "min_val"; - cip->attr_min.attr.mode = S_IRUGO; - cip->attr_min.show = show_min; - - sysfs_attr_init(&cip->attr_max.attr); - cip->attr_max.attr.name = "max_val"; - cip->attr_max.attr.mode = S_IRUGO; - cip->attr_max.show = show_max; - - sysfs_attr_init(&cip->attr_def.attr); - cip->attr_def.attr.name = "def_val"; - cip->attr_def.attr.mode = S_IRUGO; - cip->attr_def.show = show_def; - - sysfs_attr_init(&cip->attr_val.attr); - cip->attr_val.attr.name = "cur_val"; - cip->attr_val.attr.mode = S_IRUGO; - - sysfs_attr_init(&cip->attr_custom.attr); - cip->attr_custom.attr.name = "custom_val"; - cip->attr_custom.attr.mode = S_IRUGO; - - sysfs_attr_init(&cip->attr_enum.attr); - cip->attr_enum.attr.name = "enum_val"; - cip->attr_enum.attr.mode = S_IRUGO; - cip->attr_enum.show = show_enum; - - sysfs_attr_init(&cip->attr_bits.attr); - cip->attr_bits.attr.name = "bit_val"; - cip->attr_bits.attr.mode = S_IRUGO; - cip->attr_bits.show = show_bits; - - if (pvr2_ctrl_is_writable(cptr)) { - cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP; - cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP; - } - - acnt = 0; - cip->attr_gen[acnt++] = &cip->attr_name.attr; - cip->attr_gen[acnt++] = &cip->attr_type.attr; - cip->attr_gen[acnt++] = &cip->attr_val.attr; - cip->attr_gen[acnt++] = &cip->attr_def.attr; - cip->attr_val.show = show_val_norm; - cip->attr_val.store = store_val_norm; - if (pvr2_ctrl_has_custom_symbols(cptr)) { - cip->attr_gen[acnt++] = &cip->attr_custom.attr; - cip->attr_custom.show = show_val_custom; - cip->attr_custom.store = store_val_custom; - } - switch (pvr2_ctrl_get_type(cptr)) { - case pvr2_ctl_enum: - // Control is an enumeration - cip->attr_gen[acnt++] = &cip->attr_enum.attr; - break; - case pvr2_ctl_int: - // Control is an integer - cip->attr_gen[acnt++] = &cip->attr_min.attr; - cip->attr_gen[acnt++] = &cip->attr_max.attr; - break; - case pvr2_ctl_bitmask: - // Control is an bitmask - cip->attr_gen[acnt++] = &cip->attr_bits.attr; - break; - default: break; - } - - cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s", - pvr2_ctrl_get_name(cptr)); - cip->name[cnt] = 0; - cip->grp.name = cip->name; - cip->grp.attrs = cip->attr_gen; - - ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "sysfs_create_group error: %d", - ret); - return; - } - cip->created_ok = !0; -} - -#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct device *, struct device_attribute *, - char *); -static ssize_t debugcmd_show(struct device *, struct device_attribute *, - char *); -static ssize_t debugcmd_store(struct device *, struct device_attribute *, - const char *, size_t count); - -static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) -{ - struct pvr2_sysfs_debugifc *dip; - int ret; - - dip = kzalloc(sizeof(*dip),GFP_KERNEL); - if (!dip) return; - sysfs_attr_init(&dip->attr_debugcmd.attr); - dip->attr_debugcmd.attr.name = "debugcmd"; - dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP; - dip->attr_debugcmd.show = debugcmd_show; - dip->attr_debugcmd.store = debugcmd_store; - sysfs_attr_init(&dip->attr_debuginfo.attr); - dip->attr_debuginfo.attr.name = "debuginfo"; - dip->attr_debuginfo.attr.mode = S_IRUGO; - dip->attr_debuginfo.show = debuginfo_show; - sfp->debugifc = dip; - ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "device_create_file error: %d", - ret); - } else { - dip->debugcmd_created_ok = !0; - } - ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "device_create_file error: %d", - ret); - } else { - dip->debuginfo_created_ok = !0; - } -} - - -static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) -{ - if (!sfp->debugifc) return; - if (sfp->debugifc->debuginfo_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->debugifc->attr_debuginfo); - } - if (sfp->debugifc->debugcmd_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->debugifc->attr_debugcmd); - } - kfree(sfp->debugifc); - sfp->debugifc = NULL; -} -#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ - - -static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp) -{ - unsigned int idx,cnt; - cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw); - for (idx = 0; idx < cnt; idx++) { - pvr2_sysfs_add_control(sfp,idx); - } -} - - -static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp) -{ - struct pvr2_sysfs_ctl_item *cip1,*cip2; - for (cip1 = sfp->item_first; cip1; cip1 = cip2) { - cip2 = cip1->item_next; - if (cip1->created_ok) { - sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp); - } - pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1); - kfree(cip1); - } -} - - -static void pvr2_sysfs_class_release(struct class *class) -{ - struct pvr2_sysfs_class *clp; - clp = container_of(class,struct pvr2_sysfs_class,class); - pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp); - kfree(clp); -} - - -static void pvr2_sysfs_release(struct device *class_dev) -{ - pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); - kfree(class_dev); -} - - -static void class_dev_destroy(struct pvr2_sysfs *sfp) -{ - struct device *dev; - if (!sfp->class_dev) return; -#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC - pvr2_sysfs_tear_down_debugifc(sfp); -#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ - pvr2_sysfs_tear_down_controls(sfp); - if (sfp->hdw_desc_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->attr_hdw_desc); - } - if (sfp->hdw_name_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->attr_hdw_name); - } - if (sfp->bus_info_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->attr_bus_info); - } - if (sfp->v4l_minor_number_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->attr_v4l_minor_number); - } - if (sfp->v4l_radio_minor_number_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->attr_v4l_radio_minor_number); - } - if (sfp->unit_number_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->attr_unit_number); - } - pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); - dev_set_drvdata(sfp->class_dev, NULL); - dev = sfp->class_dev->parent; - sfp->class_dev->parent = NULL; - put_device(dev); - device_unregister(sfp->class_dev); - sfp->class_dev = NULL; -} - - -static ssize_t v4l_minor_number_show(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = dev_get_drvdata(class_dev); - if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%d\n", - pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, - pvr2_v4l_type_video)); -} - - -static ssize_t bus_info_show(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = dev_get_drvdata(class_dev); - if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%s\n", - pvr2_hdw_get_bus_info(sfp->channel.hdw)); -} - - -static ssize_t hdw_name_show(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = dev_get_drvdata(class_dev); - if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%s\n", - pvr2_hdw_get_type(sfp->channel.hdw)); -} - - -static ssize_t hdw_desc_show(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = dev_get_drvdata(class_dev); - if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%s\n", - pvr2_hdw_get_desc(sfp->channel.hdw)); -} - - -static ssize_t v4l_radio_minor_number_show(struct device *class_dev, - struct device_attribute *attr, - char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = dev_get_drvdata(class_dev); - if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%d\n", - pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, - pvr2_v4l_type_radio)); -} - - -static ssize_t unit_number_show(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = dev_get_drvdata(class_dev); - if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%d\n", - pvr2_hdw_get_unit_number(sfp->channel.hdw)); -} - - -static void class_dev_create(struct pvr2_sysfs *sfp, - struct pvr2_sysfs_class *class_ptr) -{ - struct usb_device *usb_dev; - struct device *class_dev; - int ret; - - usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); - if (!usb_dev) return; - class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL); - if (!class_dev) return; - - pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); - - class_dev->class = &class_ptr->class; - - dev_set_name(class_dev, "%s", - pvr2_hdw_get_device_identifier(sfp->channel.hdw)); - - class_dev->parent = get_device(&usb_dev->dev); - - sfp->class_dev = class_dev; - dev_set_drvdata(class_dev, sfp); - ret = device_register(class_dev); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "device_register failed"); - put_device(class_dev); - return; - } - - sysfs_attr_init(&sfp->attr_v4l_minor_number.attr); - sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number"; - sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; - sfp->attr_v4l_minor_number.show = v4l_minor_number_show; - sfp->attr_v4l_minor_number.store = NULL; - ret = device_create_file(sfp->class_dev, - &sfp->attr_v4l_minor_number); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "device_create_file error: %d", - ret); - } else { - sfp->v4l_minor_number_created_ok = !0; - } - - sysfs_attr_init(&sfp->attr_v4l_radio_minor_number.attr); - sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number"; - sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; - sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; - sfp->attr_v4l_radio_minor_number.store = NULL; - ret = device_create_file(sfp->class_dev, - &sfp->attr_v4l_radio_minor_number); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "device_create_file error: %d", - ret); - } else { - sfp->v4l_radio_minor_number_created_ok = !0; - } - - sysfs_attr_init(&sfp->attr_unit_number.attr); - sfp->attr_unit_number.attr.name = "unit_number"; - sfp->attr_unit_number.attr.mode = S_IRUGO; - sfp->attr_unit_number.show = unit_number_show; - sfp->attr_unit_number.store = NULL; - ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "device_create_file error: %d", - ret); - } else { - sfp->unit_number_created_ok = !0; - } - - sysfs_attr_init(&sfp->attr_bus_info.attr); - sfp->attr_bus_info.attr.name = "bus_info_str"; - sfp->attr_bus_info.attr.mode = S_IRUGO; - sfp->attr_bus_info.show = bus_info_show; - sfp->attr_bus_info.store = NULL; - ret = device_create_file(sfp->class_dev, - &sfp->attr_bus_info); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "device_create_file error: %d", - ret); - } else { - sfp->bus_info_created_ok = !0; - } - - sysfs_attr_init(&sfp->attr_hdw_name.attr); - sfp->attr_hdw_name.attr.name = "device_hardware_type"; - sfp->attr_hdw_name.attr.mode = S_IRUGO; - sfp->attr_hdw_name.show = hdw_name_show; - sfp->attr_hdw_name.store = NULL; - ret = device_create_file(sfp->class_dev, - &sfp->attr_hdw_name); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "device_create_file error: %d", - ret); - } else { - sfp->hdw_name_created_ok = !0; - } - - sysfs_attr_init(&sfp->attr_hdw_desc.attr); - sfp->attr_hdw_desc.attr.name = "device_hardware_description"; - sfp->attr_hdw_desc.attr.mode = S_IRUGO; - sfp->attr_hdw_desc.show = hdw_desc_show; - sfp->attr_hdw_desc.store = NULL; - ret = device_create_file(sfp->class_dev, - &sfp->attr_hdw_desc); - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "device_create_file error: %d", - ret); - } else { - sfp->hdw_desc_created_ok = !0; - } - - pvr2_sysfs_add_controls(sfp); -#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC - pvr2_sysfs_add_debugifc(sfp); -#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ -} - - -static void pvr2_sysfs_internal_check(struct pvr2_channel *chp) -{ - struct pvr2_sysfs *sfp; - sfp = container_of(chp,struct pvr2_sysfs,channel); - if (!sfp->channel.mc_head->disconnect_flag) return; - pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp); - class_dev_destroy(sfp); - pvr2_channel_done(&sfp->channel); - kfree(sfp); -} - - -struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, - struct pvr2_sysfs_class *class_ptr) -{ - struct pvr2_sysfs *sfp; - sfp = kzalloc(sizeof(*sfp),GFP_KERNEL); - if (!sfp) return sfp; - pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp); - pvr2_channel_init(&sfp->channel,mp); - sfp->channel.check_func = pvr2_sysfs_internal_check; - - class_dev_create(sfp,class_ptr); - return sfp; -} - - - -struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) -{ - struct pvr2_sysfs_class *clp; - clp = kzalloc(sizeof(*clp),GFP_KERNEL); - if (!clp) return clp; - pvr2_sysfs_trace("Creating and registering pvr2_sysfs_class id=%p", - clp); - clp->class.name = "pvrusb2"; - clp->class.class_release = pvr2_sysfs_class_release; - clp->class.dev_release = pvr2_sysfs_release; - if (class_register(&clp->class)) { - pvr2_sysfs_trace( - "Registration failed for pvr2_sysfs_class id=%p",clp); - kfree(clp); - clp = NULL; - } - return clp; -} - - -void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) -{ - pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp); - class_unregister(&clp->class); -} - - -#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = dev_get_drvdata(class_dev); - if (!sfp) return -EINVAL; - pvr2_hdw_trigger_module_log(sfp->channel.hdw); - return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); -} - - -static ssize_t debugcmd_show(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = dev_get_drvdata(class_dev); - if (!sfp) return -EINVAL; - return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); -} - - -static ssize_t debugcmd_store(struct device *class_dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pvr2_sysfs *sfp; - int ret; - - sfp = dev_get_drvdata(class_dev); - if (!sfp) return -EINVAL; - - ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); - if (ret < 0) return ret; - return count; -} -#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ - - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_SYSFS_H -#define __PVRUSB2_SYSFS_H - -#include -#include -#include "pvrusb2-context.h" - -struct pvr2_sysfs; -struct pvr2_sysfs_class; - -struct pvr2_sysfs_class *pvr2_sysfs_class_create(void); -void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *); - -struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *, - struct pvr2_sysfs_class *); - -#endif /* __PVRUSB2_SYSFS_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-util.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-util.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-util.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-util.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_UTIL_H -#define __PVRUSB2_UTIL_H - -#define PVR2_DECOMPOSE_LE(t,i,d) \ - do { \ - (t)[i] = (d) & 0xff;\ - (t)[i+1] = ((d) >> 8) & 0xff;\ - (t)[i+2] = ((d) >> 16) & 0xff;\ - (t)[i+3] = ((d) >> 24) & 0xff;\ - } while(0) - -#define PVR2_DECOMPOSE_BE(t,i,d) \ - do { \ - (t)[i+3] = (d) & 0xff;\ - (t)[i+2] = ((d) >> 8) & 0xff;\ - (t)[i+1] = ((d) >> 16) & 0xff;\ - (t)[i] = ((d) >> 24) & 0xff;\ - } while(0) - -#define PVR2_COMPOSE_LE(t,i) \ - ((((u32)((t)[i+3])) << 24) | \ - (((u32)((t)[i+2])) << 16) | \ - (((u32)((t)[i+1])) << 8) | \ - ((u32)((t)[i]))) - -#define PVR2_COMPOSE_BE(t,i) \ - ((((u32)((t)[i])) << 24) | \ - (((u32)((t)[i+1])) << 16) | \ - (((u32)((t)[i+2])) << 8) | \ - ((u32)((t)[i+3]))) - - -#endif /* __PVRUSB2_UTIL_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1361 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 -#include -#include -#include "pvrusb2-context.h" -#include "pvrusb2-hdw.h" -#include "pvrusb2.h" -#include "pvrusb2-debug.h" -#include "pvrusb2-v4l2.h" -#include "pvrusb2-ioread.h" -#include -#include -#include -#include - -struct pvr2_v4l2_dev; -struct pvr2_v4l2_fh; -struct pvr2_v4l2; - -struct pvr2_v4l2_dev { - struct video_device devbase; /* MUST be first! */ - struct pvr2_v4l2 *v4lp; - struct pvr2_context_stream *stream; - /* Information about this device: */ - enum pvr2_config config; /* Expected stream format */ - int v4l_type; /* V4L defined type for this device node */ - enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */ -}; - -struct pvr2_v4l2_fh { - struct pvr2_channel channel; - struct pvr2_v4l2_dev *pdi; - enum v4l2_priority prio; - struct pvr2_ioread *rhp; - struct file *file; - struct pvr2_v4l2 *vhead; - struct pvr2_v4l2_fh *vnext; - struct pvr2_v4l2_fh *vprev; - wait_queue_head_t wait_data; - int fw_mode_flag; - /* Map contiguous ordinal value to input id */ - unsigned char *input_map; - unsigned int input_cnt; -}; - -struct pvr2_v4l2 { - struct pvr2_channel channel; - struct pvr2_v4l2_fh *vfirst; - struct pvr2_v4l2_fh *vlast; - - struct v4l2_prio_state prio; - - /* streams - Note that these must be separately, individually, - * allocated pointers. This is because the v4l core is going to - * manage their deletion - separately, individually... */ - struct pvr2_v4l2_dev *dev_video; - struct pvr2_v4l2_dev *dev_radio; -}; - -static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; -module_param_array(video_nr, int, NULL, 0444); -MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor"); -static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; -module_param_array(radio_nr, int, NULL, 0444); -MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor"); -static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; -module_param_array(vbi_nr, int, NULL, 0444); -MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor"); - -static struct v4l2_capability pvr_capability ={ - .driver = "pvrusb2", - .card = "Hauppauge WinTV pvr-usb2", - .bus_info = "usb", - .version = KERNEL_VERSION(0, 9, 0), - .capabilities = (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | - V4L2_CAP_READWRITE), - .reserved = {0,0,0,0} -}; - -static struct v4l2_fmtdesc pvr_fmtdesc [] = { - { - .index = 0, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .description = "MPEG1/2", - // This should really be V4L2_PIX_FMT_MPEG, but xawtv - // breaks when I do that. - .pixelformat = 0, // V4L2_PIX_FMT_MPEG, - .reserved = { 0, 0, 0, 0 } - } -}; - -#define PVR_FORMAT_PIX 0 -#define PVR_FORMAT_VBI 1 - -static struct v4l2_format pvr_format [] = { - [PVR_FORMAT_PIX] = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .fmt = { - .pix = { - .width = 720, - .height = 576, - // This should really be V4L2_PIX_FMT_MPEG, - // but xawtv breaks when I do that. - .pixelformat = 0, // V4L2_PIX_FMT_MPEG, - .field = V4L2_FIELD_INTERLACED, - .bytesperline = 0, // doesn't make sense - // here - //FIXME : Don't know what to put here... - .sizeimage = (32*1024), - .colorspace = 0, // doesn't make sense here - .priv = 0 - } - } - }, - [PVR_FORMAT_VBI] = { - .type = V4L2_BUF_TYPE_VBI_CAPTURE, - .fmt = { - .vbi = { - .sampling_rate = 27000000, - .offset = 248, - .samples_per_line = 1443, - .sample_format = V4L2_PIX_FMT_GREY, - .start = { 0, 0 }, - .count = { 0, 0 }, - .flags = 0, - .reserved = { 0, 0 } - } - } - } -}; - - -/* - * pvr_ioctl() - * - * This is part of Video 4 Linux API. The procedure handles ioctl() calls. - * - */ -static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) -{ - struct pvr2_v4l2_fh *fh = file->private_data; - struct pvr2_v4l2 *vp = fh->vhead; - struct pvr2_v4l2_dev *pdi = fh->pdi; - struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; - long ret = -EINVAL; - - if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { - v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd); - } - - if (!pvr2_hdw_dev_ok(hdw)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "ioctl failed - bad or no context"); - return -EFAULT; - } - - /* check priority */ - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - ret = v4l2_prio_check(&vp->prio, fh->prio); - if (ret) - return ret; - } - - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); - strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw), - sizeof(cap->bus_info)); - strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card)); - - ret = 0; - break; - } - - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; - - *p = v4l2_prio_max(&vp->prio); - ret = 0; - break; - } - - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; - - ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio); - break; - } - - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *vs = (struct v4l2_standard *)arg; - int idx = vs->index; - ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1); - break; - } - - case VIDIOC_G_STD: - { - int val = 0; - ret = pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val); - *(v4l2_std_id *)arg = val; - break; - } - - case VIDIOC_S_STD: - { - ret = pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR), - *(v4l2_std_id *)arg); - break; - } - - case VIDIOC_ENUMINPUT: - { - struct pvr2_ctrl *cptr; - struct v4l2_input *vi = (struct v4l2_input *)arg; - struct v4l2_input tmp; - unsigned int cnt; - int val; - - cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); - - memset(&tmp,0,sizeof(tmp)); - tmp.index = vi->index; - ret = 0; - if (vi->index >= fh->input_cnt) { - ret = -EINVAL; - break; - } - val = fh->input_map[vi->index]; - switch (val) { - case PVR2_CVAL_INPUT_TV: - case PVR2_CVAL_INPUT_DTV: - case PVR2_CVAL_INPUT_RADIO: - tmp.type = V4L2_INPUT_TYPE_TUNER; - break; - case PVR2_CVAL_INPUT_SVIDEO: - case PVR2_CVAL_INPUT_COMPOSITE: - tmp.type = V4L2_INPUT_TYPE_CAMERA; - break; - default: - ret = -EINVAL; - break; - } - if (ret < 0) break; - - cnt = 0; - pvr2_ctrl_get_valname(cptr,val, - tmp.name,sizeof(tmp.name)-1,&cnt); - tmp.name[cnt] = 0; - - /* Don't bother with audioset, since this driver currently - always switches the audio whenever the video is - switched. */ - - /* Handling std is a tougher problem. It doesn't make - sense in cases where a device might be multi-standard. - We could just copy out the current value for the - standard, but it can change over time. For now just - leave it zero. */ - - memcpy(vi, &tmp, sizeof(tmp)); - - ret = 0; - break; - } - - case VIDIOC_G_INPUT: - { - unsigned int idx; - struct pvr2_ctrl *cptr; - struct v4l2_input *vi = (struct v4l2_input *)arg; - int val; - cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); - val = 0; - ret = pvr2_ctrl_get_value(cptr,&val); - vi->index = 0; - for (idx = 0; idx < fh->input_cnt; idx++) { - if (fh->input_map[idx] == val) { - vi->index = idx; - break; - } - } - break; - } - - case VIDIOC_S_INPUT: - { - struct v4l2_input *vi = (struct v4l2_input *)arg; - if (vi->index >= fh->input_cnt) { - ret = -ERANGE; - break; - } - ret = pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT), - fh->input_map[vi->index]); - break; - } - - case VIDIOC_ENUMAUDIO: - { - /* pkt: FIXME: We are returning one "fake" input here - which could very well be called "whatever_we_like". - This is for apps that want to see an audio input - just to feel comfortable, as well as to test if - it can do stereo or sth. There is actually no guarantee - that the actual audio input cannot change behind the app's - back, but most applications should not mind that either. - - Hopefully, mplayer people will work with us on this (this - whole mess is to support mplayer pvr://), or Hans will come - up with a more standard way to say "we have inputs but we - don 't want you to change them independent of video" which - will sort this mess. - */ - struct v4l2_audio *vin = arg; - ret = -EINVAL; - if (vin->index > 0) break; - strncpy(vin->name, "PVRUSB2 Audio",14); - vin->capability = V4L2_AUDCAP_STEREO; - ret = 0; - break; - break; - } - - case VIDIOC_G_AUDIO: - { - /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */ - struct v4l2_audio *vin = arg; - memset(vin,0,sizeof(*vin)); - vin->index = 0; - strncpy(vin->name, "PVRUSB2 Audio",14); - vin->capability = V4L2_AUDCAP_STEREO; - ret = 0; - break; - } - - case VIDIOC_S_AUDIO: - { - ret = -EINVAL; - break; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; - - if (vt->index != 0) break; /* Only answer for the 1st tuner */ - - pvr2_hdw_execute_tuner_poll(hdw); - ret = pvr2_hdw_get_tuner_status(hdw,vt); - break; - } - - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; - - if (vt->index != 0) - break; - - ret = pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE), - vt->audmode); - break; - } - - case VIDIOC_S_FREQUENCY: - { - const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; - unsigned long fv; - struct v4l2_tuner vt; - int cur_input; - struct pvr2_ctrl *ctrlp; - ret = pvr2_hdw_get_tuner_status(hdw,&vt); - if (ret != 0) break; - ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); - ret = pvr2_ctrl_get_value(ctrlp,&cur_input); - if (ret != 0) break; - if (vf->type == V4L2_TUNER_RADIO) { - if (cur_input != PVR2_CVAL_INPUT_RADIO) { - pvr2_ctrl_set_value(ctrlp, - PVR2_CVAL_INPUT_RADIO); - } - } else { - if (cur_input == PVR2_CVAL_INPUT_RADIO) { - pvr2_ctrl_set_value(ctrlp, - PVR2_CVAL_INPUT_TV); - } - } - fv = vf->frequency; - if (vt.capability & V4L2_TUNER_CAP_LOW) { - fv = (fv * 125) / 2; - } else { - fv = fv * 62500; - } - ret = pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv); - break; - } - - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; - int val = 0; - int cur_input; - struct v4l2_tuner vt; - ret = pvr2_hdw_get_tuner_status(hdw,&vt); - if (ret != 0) break; - ret = pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY), - &val); - if (ret != 0) break; - pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT), - &cur_input); - if (cur_input == PVR2_CVAL_INPUT_RADIO) { - vf->type = V4L2_TUNER_RADIO; - } else { - vf->type = V4L2_TUNER_ANALOG_TV; - } - if (vt.capability & V4L2_TUNER_CAP_LOW) { - val = (val * 2) / 125; - } else { - val /= 62500; - } - vf->frequency = val; - break; - } - - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg; - - /* Only one format is supported : mpeg.*/ - if (fd->index != 0) - break; - - memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc)); - ret = 0; - break; - } - - case VIDIOC_G_FMT: - { - struct v4l2_format *vf = (struct v4l2_format *)arg; - int val; - switch(vf->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - memcpy(vf, &pvr_format[PVR_FORMAT_PIX], - sizeof(struct v4l2_format)); - val = 0; - pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES), - &val); - vf->fmt.pix.width = val; - val = 0; - pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES), - &val); - vf->fmt.pix.height = val; - ret = 0; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - // ????? Still need to figure out to do VBI correctly - ret = -EINVAL; - break; - default: - ret = -EINVAL; - break; - } - break; - } - - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - { - struct v4l2_format *vf = (struct v4l2_format *)arg; - - ret = 0; - switch(vf->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: { - int lmin,lmax,ldef; - struct pvr2_ctrl *hcp,*vcp; - int h = vf->fmt.pix.height; - int w = vf->fmt.pix.width; - hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES); - vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES); - - lmin = pvr2_ctrl_get_min(hcp); - lmax = pvr2_ctrl_get_max(hcp); - pvr2_ctrl_get_def(hcp, &ldef); - if (w == -1) { - w = ldef; - } else if (w < lmin) { - w = lmin; - } else if (w > lmax) { - w = lmax; - } - lmin = pvr2_ctrl_get_min(vcp); - lmax = pvr2_ctrl_get_max(vcp); - pvr2_ctrl_get_def(vcp, &ldef); - if (h == -1) { - h = ldef; - } else if (h < lmin) { - h = lmin; - } else if (h > lmax) { - h = lmax; - } - - memcpy(vf, &pvr_format[PVR_FORMAT_PIX], - sizeof(struct v4l2_format)); - vf->fmt.pix.width = w; - vf->fmt.pix.height = h; - - if (cmd == VIDIOC_S_FMT) { - pvr2_ctrl_set_value(hcp,vf->fmt.pix.width); - pvr2_ctrl_set_value(vcp,vf->fmt.pix.height); - } - } break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - // ????? Still need to figure out to do VBI correctly - ret = -EINVAL; - break; - default: - ret = -EINVAL; - break; - } - break; - } - - case VIDIOC_STREAMON: - { - if (!fh->pdi->stream) { - /* No stream defined for this node. This means - that we're not currently allowed to stream from - this node. */ - ret = -EPERM; - break; - } - ret = pvr2_hdw_set_stream_type(hdw,pdi->config); - if (ret < 0) return ret; - ret = pvr2_hdw_set_streaming(hdw,!0); - break; - } - - case VIDIOC_STREAMOFF: - { - if (!fh->pdi->stream) { - /* No stream defined for this node. This means - that we're not currently allowed to stream from - this node. */ - ret = -EPERM; - break; - } - ret = pvr2_hdw_set_streaming(hdw,0); - break; - } - - case VIDIOC_QUERYCTRL: - { - struct pvr2_ctrl *cptr; - int val; - struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg; - ret = 0; - if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) { - cptr = pvr2_hdw_get_ctrl_nextv4l( - hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL)); - if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr); - } else { - cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id); - } - if (!cptr) { - pvr2_trace(PVR2_TRACE_V4LIOCTL, - "QUERYCTRL id=0x%x not implemented here", - vc->id); - ret = -EINVAL; - break; - } - - pvr2_trace(PVR2_TRACE_V4LIOCTL, - "QUERYCTRL id=0x%x mapping name=%s (%s)", - vc->id,pvr2_ctrl_get_name(cptr), - pvr2_ctrl_get_desc(cptr)); - strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name)); - vc->flags = pvr2_ctrl_get_v4lflags(cptr); - pvr2_ctrl_get_def(cptr, &val); - vc->default_value = val; - switch (pvr2_ctrl_get_type(cptr)) { - case pvr2_ctl_enum: - vc->type = V4L2_CTRL_TYPE_MENU; - vc->minimum = 0; - vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1; - vc->step = 1; - break; - case pvr2_ctl_bool: - vc->type = V4L2_CTRL_TYPE_BOOLEAN; - vc->minimum = 0; - vc->maximum = 1; - vc->step = 1; - break; - case pvr2_ctl_int: - vc->type = V4L2_CTRL_TYPE_INTEGER; - vc->minimum = pvr2_ctrl_get_min(cptr); - vc->maximum = pvr2_ctrl_get_max(cptr); - vc->step = 1; - break; - default: - pvr2_trace(PVR2_TRACE_V4LIOCTL, - "QUERYCTRL id=0x%x name=%s not mappable", - vc->id,pvr2_ctrl_get_name(cptr)); - ret = -EINVAL; - break; - } - break; - } - - case VIDIOC_QUERYMENU: - { - struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg; - unsigned int cnt = 0; - ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id), - vm->index, - vm->name,sizeof(vm->name)-1, - &cnt); - vm->name[cnt] = 0; - break; - } - - case VIDIOC_G_CTRL: - { - struct v4l2_control *vc = (struct v4l2_control *)arg; - int val = 0; - ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id), - &val); - vc->value = val; - break; - } - - case VIDIOC_S_CTRL: - { - struct v4l2_control *vc = (struct v4l2_control *)arg; - ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id), - vc->value); - break; - } - - case VIDIOC_G_EXT_CTRLS: - { - struct v4l2_ext_controls *ctls = - (struct v4l2_ext_controls *)arg; - struct v4l2_ext_control *ctrl; - unsigned int idx; - int val; - ret = 0; - for (idx = 0; idx < ctls->count; idx++) { - ctrl = ctls->controls + idx; - ret = pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val); - if (ret) { - ctls->error_idx = idx; - break; - } - /* Ensure that if read as a 64 bit value, the user - will still get a hopefully sane value */ - ctrl->value64 = 0; - ctrl->value = val; - } - break; - } - - case VIDIOC_S_EXT_CTRLS: - { - struct v4l2_ext_controls *ctls = - (struct v4l2_ext_controls *)arg; - struct v4l2_ext_control *ctrl; - unsigned int idx; - ret = 0; - for (idx = 0; idx < ctls->count; idx++) { - ctrl = ctls->controls + idx; - ret = pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id), - ctrl->value); - if (ret) { - ctls->error_idx = idx; - break; - } - } - break; - } - - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *ctls = - (struct v4l2_ext_controls *)arg; - struct v4l2_ext_control *ctrl; - struct pvr2_ctrl *pctl; - unsigned int idx; - /* For the moment just validate that the requested control - actually exists. */ - ret = 0; - for (idx = 0; idx < ctls->count; idx++) { - ctrl = ctls->controls + idx; - pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id); - if (!pctl) { - ret = -EINVAL; - ctls->error_idx = idx; - break; - } - } - break; - } - - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg; - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - ret = -EINVAL; - break; - } - ret = pvr2_hdw_get_cropcap(hdw, cap); - cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */ - break; - } - case VIDIOC_G_CROP: - { - struct v4l2_crop *crop = (struct v4l2_crop *)arg; - int val = 0; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - ret = -EINVAL; - break; - } - ret = pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val); - if (ret != 0) { - ret = -EINVAL; - break; - } - crop->c.left = val; - ret = pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val); - if (ret != 0) { - ret = -EINVAL; - break; - } - crop->c.top = val; - ret = pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val); - if (ret != 0) { - ret = -EINVAL; - break; - } - crop->c.width = val; - ret = pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val); - if (ret != 0) { - ret = -EINVAL; - break; - } - crop->c.height = val; - } - case VIDIOC_S_CROP: - { - struct v4l2_crop *crop = (struct v4l2_crop *)arg; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - ret = -EINVAL; - break; - } - ret = pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), - crop->c.left); - if (ret != 0) { - ret = -EINVAL; - break; - } - ret = pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), - crop->c.top); - if (ret != 0) { - ret = -EINVAL; - break; - } - ret = pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), - crop->c.width); - if (ret != 0) { - ret = -EINVAL; - break; - } - ret = pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), - crop->c.height); - if (ret != 0) { - ret = -EINVAL; - break; - } - } - case VIDIOC_LOG_STATUS: - { - pvr2_hdw_trigger_module_log(hdw); - ret = 0; - break; - } -#ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_S_REGISTER: - case VIDIOC_DBG_G_REGISTER: - { - u64 val; - struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg; - if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val; - ret = pvr2_hdw_register_access( - hdw, &req->match, req->reg, - cmd == VIDIOC_DBG_S_REGISTER, &val); - if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val; - break; - } -#endif - - default : - ret = -EINVAL; - break; - } - - pvr2_hdw_commit_ctl(hdw); - - if (ret < 0) { - if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { - pvr2_trace(PVR2_TRACE_V4LIOCTL, - "pvr2_v4l2_do_ioctl failure, ret=%ld", ret); - } else { - if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { - pvr2_trace(PVR2_TRACE_V4LIOCTL, - "pvr2_v4l2_do_ioctl failure, ret=%ld" - " command was:", ret); - v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), - cmd); - } - } - } else { - pvr2_trace(PVR2_TRACE_V4LIOCTL, - "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)", - ret, ret); - } - return ret; -} - -static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) -{ - struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw; - enum pvr2_config cfg = dip->config; - char msg[80]; - unsigned int mcnt; - - /* Construct the unregistration message *before* we actually - perform the unregistration step. By doing it this way we don't - have to worry about potentially touching deleted resources. */ - mcnt = scnprintf(msg, sizeof(msg) - 1, - "pvrusb2: unregistered device %s [%s]", - video_device_node_name(&dip->devbase), - pvr2_config_get_name(cfg)); - msg[mcnt] = 0; - - pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1); - - /* Paranoia */ - dip->v4lp = NULL; - dip->stream = NULL; - - /* Actual deallocation happens later when all internal references - are gone. */ - video_unregister_device(&dip->devbase); - - printk(KERN_INFO "%s\n", msg); - -} - - -static void pvr2_v4l2_dev_disassociate_parent(struct pvr2_v4l2_dev *dip) -{ - if (!dip) return; - if (!dip->devbase.parent) return; - dip->devbase.parent = NULL; - device_move(&dip->devbase.dev, NULL, DPM_ORDER_NONE); -} - - -static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp) -{ - if (vp->dev_video) { - pvr2_v4l2_dev_destroy(vp->dev_video); - vp->dev_video = NULL; - } - if (vp->dev_radio) { - pvr2_v4l2_dev_destroy(vp->dev_radio); - vp->dev_radio = NULL; - } - - pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp); - pvr2_channel_done(&vp->channel); - kfree(vp); -} - - -static void pvr2_video_device_release(struct video_device *vdev) -{ - struct pvr2_v4l2_dev *dev; - dev = container_of(vdev,struct pvr2_v4l2_dev,devbase); - kfree(dev); -} - - -static void pvr2_v4l2_internal_check(struct pvr2_channel *chp) -{ - struct pvr2_v4l2 *vp; - vp = container_of(chp,struct pvr2_v4l2,channel); - if (!vp->channel.mc_head->disconnect_flag) return; - pvr2_v4l2_dev_disassociate_parent(vp->dev_video); - pvr2_v4l2_dev_disassociate_parent(vp->dev_radio); - if (vp->vfirst) return; - pvr2_v4l2_destroy_no_lock(vp); -} - - -static long pvr2_v4l2_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - - return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl); -} - - -static int pvr2_v4l2_release(struct file *file) -{ - struct pvr2_v4l2_fh *fhp = file->private_data; - struct pvr2_v4l2 *vp = fhp->vhead; - struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw; - - pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release"); - - if (fhp->rhp) { - struct pvr2_stream *sp; - pvr2_hdw_set_streaming(hdw,0); - sp = pvr2_ioread_get_stream(fhp->rhp); - if (sp) pvr2_stream_set_callback(sp,NULL,NULL); - pvr2_ioread_destroy(fhp->rhp); - fhp->rhp = NULL; - } - - v4l2_prio_close(&vp->prio, fhp->prio); - file->private_data = NULL; - - if (fhp->vnext) { - fhp->vnext->vprev = fhp->vprev; - } else { - vp->vlast = fhp->vprev; - } - if (fhp->vprev) { - fhp->vprev->vnext = fhp->vnext; - } else { - vp->vfirst = fhp->vnext; - } - fhp->vnext = NULL; - fhp->vprev = NULL; - fhp->vhead = NULL; - pvr2_channel_done(&fhp->channel); - pvr2_trace(PVR2_TRACE_STRUCT, - "Destroying pvr_v4l2_fh id=%p",fhp); - if (fhp->input_map) { - kfree(fhp->input_map); - fhp->input_map = NULL; - } - kfree(fhp); - if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) { - pvr2_v4l2_destroy_no_lock(vp); - } - return 0; -} - - -static int pvr2_v4l2_open(struct file *file) -{ - struct pvr2_v4l2_dev *dip; /* Our own context pointer */ - struct pvr2_v4l2_fh *fhp; - struct pvr2_v4l2 *vp; - struct pvr2_hdw *hdw; - unsigned int input_mask = 0; - unsigned int input_cnt,idx; - int ret = 0; - - dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase); - - vp = dip->v4lp; - hdw = vp->channel.hdw; - - pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open"); - - if (!pvr2_hdw_dev_ok(hdw)) { - pvr2_trace(PVR2_TRACE_OPEN_CLOSE, - "pvr2_v4l2_open: hardware not ready"); - return -EIO; - } - - fhp = kzalloc(sizeof(*fhp),GFP_KERNEL); - if (!fhp) { - return -ENOMEM; - } - - init_waitqueue_head(&fhp->wait_data); - fhp->pdi = dip; - - pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp); - pvr2_channel_init(&fhp->channel,vp->channel.mc_head); - - if (dip->v4l_type == VFL_TYPE_RADIO) { - /* Opening device as a radio, legal input selection subset - is just the radio. */ - input_mask = (1 << PVR2_CVAL_INPUT_RADIO); - } else { - /* Opening the main V4L device, legal input selection - subset includes all analog inputs. */ - input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) | - (1 << PVR2_CVAL_INPUT_TV) | - (1 << PVR2_CVAL_INPUT_COMPOSITE) | - (1 << PVR2_CVAL_INPUT_SVIDEO)); - } - ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask); - if (ret) { - pvr2_channel_done(&fhp->channel); - pvr2_trace(PVR2_TRACE_STRUCT, - "Destroying pvr_v4l2_fh id=%p (input mask error)", - fhp); - - kfree(fhp); - return ret; - } - - input_mask &= pvr2_hdw_get_input_available(hdw); - input_cnt = 0; - for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) { - if (input_mask & (1 << idx)) input_cnt++; - } - fhp->input_cnt = input_cnt; - fhp->input_map = kzalloc(input_cnt,GFP_KERNEL); - if (!fhp->input_map) { - pvr2_channel_done(&fhp->channel); - pvr2_trace(PVR2_TRACE_STRUCT, - "Destroying pvr_v4l2_fh id=%p (input map failure)", - fhp); - kfree(fhp); - return -ENOMEM; - } - input_cnt = 0; - for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) { - if (!(input_mask & (1 << idx))) continue; - fhp->input_map[input_cnt++] = idx; - } - - fhp->vnext = NULL; - fhp->vprev = vp->vlast; - if (vp->vlast) { - vp->vlast->vnext = fhp; - } else { - vp->vfirst = fhp; - } - vp->vlast = fhp; - fhp->vhead = vp; - - fhp->file = file; - file->private_data = fhp; - v4l2_prio_open(&vp->prio, &fhp->prio); - - fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw); - - return 0; -} - - -static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp) -{ - wake_up(&fhp->wait_data); -} - -static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) -{ - int ret; - struct pvr2_stream *sp; - struct pvr2_hdw *hdw; - if (fh->rhp) return 0; - - if (!fh->pdi->stream) { - /* No stream defined for this node. This means that we're - not currently allowed to stream from this node. */ - return -EPERM; - } - - /* First read() attempt. Try to claim the stream and start - it... */ - if ((ret = pvr2_channel_claim_stream(&fh->channel, - fh->pdi->stream)) != 0) { - /* Someone else must already have it */ - return ret; - } - - fh->rhp = pvr2_channel_create_mpeg_stream(fh->pdi->stream); - if (!fh->rhp) { - pvr2_channel_claim_stream(&fh->channel,NULL); - return -ENOMEM; - } - - hdw = fh->channel.mc_head->hdw; - sp = fh->pdi->stream->stream; - pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh); - pvr2_hdw_set_stream_type(hdw,fh->pdi->config); - if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret; - return pvr2_ioread_set_enabled(fh->rhp,!0); -} - - -static ssize_t pvr2_v4l2_read(struct file *file, - char __user *buff, size_t count, loff_t *ppos) -{ - struct pvr2_v4l2_fh *fh = file->private_data; - int ret; - - if (fh->fw_mode_flag) { - struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; - char *tbuf; - int c1,c2; - int tcnt = 0; - unsigned int offs = *ppos; - - tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL); - if (!tbuf) return -ENOMEM; - - while (count) { - c1 = count; - if (c1 > PAGE_SIZE) c1 = PAGE_SIZE; - c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1); - if (c2 < 0) { - tcnt = c2; - break; - } - if (!c2) break; - if (copy_to_user(buff,tbuf,c2)) { - tcnt = -EFAULT; - break; - } - offs += c2; - tcnt += c2; - buff += c2; - count -= c2; - *ppos += c2; - } - kfree(tbuf); - return tcnt; - } - - if (!fh->rhp) { - ret = pvr2_v4l2_iosetup(fh); - if (ret) { - return ret; - } - } - - for (;;) { - ret = pvr2_ioread_read(fh->rhp,buff,count); - if (ret >= 0) break; - if (ret != -EAGAIN) break; - if (file->f_flags & O_NONBLOCK) break; - /* Doing blocking I/O. Wait here. */ - ret = wait_event_interruptible( - fh->wait_data, - pvr2_ioread_avail(fh->rhp) >= 0); - if (ret < 0) break; - } - - return ret; -} - - -static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait) -{ - unsigned int mask = 0; - struct pvr2_v4l2_fh *fh = file->private_data; - int ret; - - if (fh->fw_mode_flag) { - mask |= POLLIN | POLLRDNORM; - return mask; - } - - if (!fh->rhp) { - ret = pvr2_v4l2_iosetup(fh); - if (ret) return POLLERR; - } - - poll_wait(file,&fh->wait_data,wait); - - if (pvr2_ioread_avail(fh->rhp) >= 0) { - mask |= POLLIN | POLLRDNORM; - } - - return mask; -} - - -static const struct v4l2_file_operations vdev_fops = { - .owner = THIS_MODULE, - .open = pvr2_v4l2_open, - .release = pvr2_v4l2_release, - .read = pvr2_v4l2_read, - .ioctl = pvr2_v4l2_ioctl, - .poll = pvr2_v4l2_poll, -}; - - -static struct video_device vdev_template = { - .fops = &vdev_fops, -}; - - -static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, - struct pvr2_v4l2 *vp, - int v4l_type) -{ - struct usb_device *usbdev; - int mindevnum; - int unit_number; - int *nr_ptr = NULL; - dip->v4lp = vp; - - usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw); - dip->v4l_type = v4l_type; - switch (v4l_type) { - case VFL_TYPE_GRABBER: - dip->stream = &vp->channel.mc_head->video_stream; - dip->config = pvr2_config_mpeg; - dip->minor_type = pvr2_v4l_type_video; - nr_ptr = video_nr; - if (!dip->stream) { - pr_err(KBUILD_MODNAME - ": Failed to set up pvrusb2 v4l video dev" - " due to missing stream instance\n"); - return; - } - break; - case VFL_TYPE_VBI: - dip->config = pvr2_config_vbi; - dip->minor_type = pvr2_v4l_type_vbi; - nr_ptr = vbi_nr; - break; - case VFL_TYPE_RADIO: - dip->stream = &vp->channel.mc_head->video_stream; - dip->config = pvr2_config_mpeg; - dip->minor_type = pvr2_v4l_type_radio; - nr_ptr = radio_nr; - break; - default: - /* Bail out (this should be impossible) */ - pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev" - " due to unrecognized config\n"); - return; - } - - memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template)); - dip->devbase.release = pvr2_video_device_release; - - mindevnum = -1; - unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw); - if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) { - mindevnum = nr_ptr[unit_number]; - } - dip->devbase.parent = &usbdev->dev; - if ((video_register_device(&dip->devbase, - dip->v4l_type, mindevnum) < 0) && - (video_register_device(&dip->devbase, - dip->v4l_type, -1) < 0)) { - pr_err(KBUILD_MODNAME - ": Failed to register pvrusb2 v4l device\n"); - } - - printk(KERN_INFO "pvrusb2: registered device %s [%s]\n", - video_device_node_name(&dip->devbase), - pvr2_config_get_name(dip->config)); - - pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, - dip->minor_type,dip->devbase.minor); -} - - -struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) -{ - struct pvr2_v4l2 *vp; - - vp = kzalloc(sizeof(*vp),GFP_KERNEL); - if (!vp) return vp; - pvr2_channel_init(&vp->channel,mnp); - pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp); - - vp->channel.check_func = pvr2_v4l2_internal_check; - - /* register streams */ - vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL); - if (!vp->dev_video) goto fail; - pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER); - if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) & - (1 << PVR2_CVAL_INPUT_RADIO)) { - vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL); - if (!vp->dev_radio) goto fail; - pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO); - } - - return vp; - fail: - pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp); - pvr2_v4l2_destroy_no_lock(vp); - return NULL; -} - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - */ -#ifndef __PVRUSB2_V4L2_H -#define __PVRUSB2_V4L2_H - -#include "pvrusb2-context.h" - -struct pvr2_v4l2; - -struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *); - -#endif /* __PVRUSB2_V4L2_H */ - -/* - 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: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -/* - - This source file is specifically designed to interface with the - saa711x support that is available in the v4l available starting - with linux 2.6.15. - -*/ - -#include "pvrusb2-video-v4l.h" - - - -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-debug.h" -#include -#include -#include -#include - -struct routing_scheme { - const int *def; - unsigned int cnt; -}; - - -static const int routing_scheme0[] = { - [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4, - /* In radio mode, we mute the video, but point at one - spot just to stay consistent */ - [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5, - [PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE5, - [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, -}; - -static const struct routing_scheme routing_def0 = { - .def = routing_scheme0, - .cnt = ARRAY_SIZE(routing_scheme0), -}; - -static const int routing_scheme1[] = { - [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4, - [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5, - [PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE3, - [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, /* or SVIDEO0, it seems */ -}; - -static const struct routing_scheme routing_def1 = { - .def = routing_scheme1, - .cnt = ARRAY_SIZE(routing_scheme1), -}; - -static const struct routing_scheme *routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, - [PVR2_ROUTING_SCHEME_ONAIR] = &routing_def1, -}; - -void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) -{ - if (hdw->input_dirty || hdw->force_dirty) { - const struct routing_scheme *sp; - unsigned int sid = hdw->hdw_desc->signal_routing_scheme; - u32 input; - - pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)", - hdw->input_val); - - sp = (sid < ARRAY_SIZE(routing_schemes)) ? - routing_schemes[sid] : NULL; - if ((sp == NULL) || - (hdw->input_val < 0) || - (hdw->input_val >= sp->cnt)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** subdev v4l2 set_input:" - " Invalid routing scheme (%u)" - " and/or input (%d)", - sid, hdw->input_val); - return; - } - input = sp->def[hdw->input_val]; - sd->ops->video->s_routing(sd, input, 0, 0); - } -} - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -#ifndef __PVRUSB2_VIDEO_V4L_H -#define __PVRUSB2_VIDEO_V4L_H - -/* - - This module connects the pvrusb2 driver to the I2C chip level - driver which handles device video processing. This interface is - used internally by the driver; higher level code should only - interact through the interface provided by pvrusb2-hdw.h. - -*/ - - -#include "pvrusb2-hdw-internal.h" -void pvr2_saa7115_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *); - -#endif /* __PVRUSB2_VIDEO_V4L_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -/* - - This source file is specifically designed to interface with the - wm8775. - -*/ - -#include "pvrusb2-wm8775.h" - - -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-debug.h" -#include -#include -#include - -void pvr2_wm8775_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) -{ - if (hdw->input_dirty || hdw->force_dirty) { - u32 input; - - switch (hdw->input_val) { - case PVR2_CVAL_INPUT_RADIO: - input = 1; - break; - default: - /* All other cases just use the second input */ - input = 2; - break; - } - pvr2_trace(PVR2_TRACE_CHIPS, "subdev wm8775" - " set_input(val=%d route=0x%x)", - hdw->input_val, input); - - sd->ops->audio->s_routing(sd, input, 0, 0); - } -} - - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * - * - * Copyright (C) 2005 Mike Isely - * Copyright (C) 2004 Aurelien Alleaume - * - * 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 - * - */ - -#ifndef __PVRUSB2_WM8775_H -#define __PVRUSB2_WM8775_H - -/* - - This module connects the pvrusb2 driver to the I2C chip level - driver which performs analog -> digital audio conversion for - external audio inputs. This interface is used internally by the - driver; higher level code should only interact through the - interface provided by pvrusb2-hdw.h. - -*/ - - - -#include "pvrusb2-hdw-internal.h" - -void pvr2_wm8775_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd); - - -#endif /* __PVRUSB2_WM8775_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -config USB_PWC - tristate "USB Philips Cameras" - depends on VIDEO_V4L2 - ---help--- - Say Y or M here if you want to use one of these Philips & OEM - webcams: - * Philips PCA645, PCA646 - * Philips PCVC675, PCVC680, PCVC690 - * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 - * Philips SPC900NC - * Askey VC010 - * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' - and 'Orbit'/'Sphere' - * Samsung MPC-C10, MPC-C30 - * Creative Webcam 5, Pro Ex - * SOTEC Afina Eye - * Visionite VCS-UC300, VCS-UM100 - - The PCA635, PCVC665 and PCVC720/20 are not supported by this driver - and never will be, but the 665 and 720/20 are supported by other - drivers. - - Some newer logitech webcams are not handled by this driver but by the - Usb Video Class driver (linux-uvc). - - The built-in microphone is enabled by selecting USB Audio support. - - To compile this driver as a module, choose M here: the - module will be called pwc. - -config USB_PWC_DEBUG - bool "USB Philips Cameras verbose debug" - depends on USB_PWC - help - Say Y here in order to have the pwc driver generate verbose debugging - messages. - A special module options 'trace' is used to control the verbosity. - -config USB_PWC_INPUT_EVDEV - bool "USB Philips Cameras input events device support" - default y - depends on USB_PWC && (USB_PWC=INPUT || INPUT=y) - ---help--- - This option makes USB Philips cameras register the snapshot button as - an input device to report button events. - - If you are in doubt, say Y. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o -pwc-objs += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o - -obj-$(CONFIG_USB_PWC) += pwc.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-ctrl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-ctrl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-ctrl.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-ctrl.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1765 +0,0 @@ -/* Driver for Philips webcam - Functions that send various control messages to the webcam, including - video modes. - (C) 1999-2003 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - -/* - Changes - 2001/08/03 Alvarado Added methods for changing white balance and - red/green gains - */ - -/* Control functions for the cam; brightness, contrast, video mode, etc. */ - -#ifdef __KERNEL__ -#include -#endif -#include - -#include "pwc.h" -#include "pwc-uncompress.h" -#include "pwc-kiara.h" -#include "pwc-timon.h" -#include "pwc-dec1.h" -#include "pwc-dec23.h" - -/* Request types: video */ -#define SET_LUM_CTL 0x01 -#define GET_LUM_CTL 0x02 -#define SET_CHROM_CTL 0x03 -#define GET_CHROM_CTL 0x04 -#define SET_STATUS_CTL 0x05 -#define GET_STATUS_CTL 0x06 -#define SET_EP_STREAM_CTL 0x07 -#define GET_EP_STREAM_CTL 0x08 -#define GET_XX_CTL 0x09 -#define SET_XX_CTL 0x0A -#define GET_XY_CTL 0x0B -#define SET_XY_CTL 0x0C -#define SET_MPT_CTL 0x0D -#define GET_MPT_CTL 0x0E - -/* Selectors for the Luminance controls [GS]ET_LUM_CTL */ -#define AGC_MODE_FORMATTER 0x2000 -#define PRESET_AGC_FORMATTER 0x2100 -#define SHUTTER_MODE_FORMATTER 0x2200 -#define PRESET_SHUTTER_FORMATTER 0x2300 -#define PRESET_CONTOUR_FORMATTER 0x2400 -#define AUTO_CONTOUR_FORMATTER 0x2500 -#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 -#define CONTRAST_FORMATTER 0x2700 -#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 -#define FLICKERLESS_MODE_FORMATTER 0x2900 -#define AE_CONTROL_SPEED 0x2A00 -#define BRIGHTNESS_FORMATTER 0x2B00 -#define GAMMA_FORMATTER 0x2C00 - -/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ -#define WB_MODE_FORMATTER 0x1000 -#define AWB_CONTROL_SPEED_FORMATTER 0x1100 -#define AWB_CONTROL_DELAY_FORMATTER 0x1200 -#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 -#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 -#define COLOUR_MODE_FORMATTER 0x1500 -#define SATURATION_MODE_FORMATTER1 0x1600 -#define SATURATION_MODE_FORMATTER2 0x1700 - -/* Selectors for the Status controls [GS]ET_STATUS_CTL */ -#define SAVE_USER_DEFAULTS_FORMATTER 0x0200 -#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 -#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 -#define READ_AGC_FORMATTER 0x0500 -#define READ_SHUTTER_FORMATTER 0x0600 -#define READ_RED_GAIN_FORMATTER 0x0700 -#define READ_BLUE_GAIN_FORMATTER 0x0800 -#define GET_STATUS_B00 0x0B00 -#define SENSOR_TYPE_FORMATTER1 0x0C00 -#define GET_STATUS_3000 0x3000 -#define READ_RAW_Y_MEAN_FORMATTER 0x3100 -#define SET_POWER_SAVE_MODE_FORMATTER 0x3200 -#define MIRROR_IMAGE_FORMATTER 0x3300 -#define LED_FORMATTER 0x3400 -#define LOWLIGHT 0x3500 -#define GET_STATUS_3600 0x3600 -#define SENSOR_TYPE_FORMATTER2 0x3700 -#define GET_STATUS_3800 0x3800 -#define GET_STATUS_4000 0x4000 -#define GET_STATUS_4100 0x4100 /* Get */ -#define CTL_STATUS_4200 0x4200 /* [GS] 1 */ - -/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ -#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 - -/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ -#define PT_RELATIVE_CONTROL_FORMATTER 0x01 -#define PT_RESET_CONTROL_FORMATTER 0x02 -#define PT_STATUS_FORMATTER 0x03 - -static const char *size2name[PSZ_MAX] = -{ - "subQCIF", - "QSIF", - "QCIF", - "SIF", - "CIF", - "VGA", -}; - -/********/ - -/* Entries for the Nala (645/646) camera; the Nala doesn't have compression - preferences, so you either get compressed or non-compressed streams. - - An alternate value of 0 means this mode is not available at all. - */ - -#define PWC_FPS_MAX_NALA 8 - -struct Nala_table_entry { - char alternate; /* USB alternate setting */ - int compressed; /* Compressed yes/no */ - - unsigned char mode[3]; /* precomputed mode table */ -}; - -static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 }; - -static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = -{ -#include "pwc-nala.h" -}; - -static void pwc_set_image_buffer_size(struct pwc_device *pdev); - -/****************************************************************************/ - -static int _send_control_msg(struct pwc_device *pdev, - u8 request, u16 value, int index, void *buf, int buflen, int timeout) -{ - int rc; - void *kbuf = NULL; - - if (buflen) { - kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */ - if (kbuf == NULL) - return -ENOMEM; - memcpy(kbuf, buf, buflen); - } - - rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - kbuf, buflen, timeout); - - kfree(kbuf); - return rc; -} - -static int recv_control_msg(struct pwc_device *pdev, - u8 request, u16 value, void *buf, int buflen) -{ - int rc; - void *kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */ - - if (kbuf == NULL) - return -ENOMEM; - - rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - request, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - pdev->vcinterface, - kbuf, buflen, 500); - memcpy(buf, kbuf, buflen); - kfree(kbuf); - return rc; -} - -static inline int send_video_command(struct pwc_device *pdev, - int index, void *buf, int buflen) -{ - return _send_control_msg(pdev, - SET_EP_STREAM_CTL, - VIDEO_OUTPUT_CONTROL_FORMATTER, - index, - buf, buflen, 1000); -} - -static inline int send_control_msg(struct pwc_device *pdev, - u8 request, u16 value, void *buf, int buflen) -{ - return _send_control_msg(pdev, - request, value, pdev->vcinterface, buf, buflen, 500); -} - - - -static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) -{ - unsigned char buf[3]; - int ret, fps; - struct Nala_table_entry *pEntry; - int frames2frames[31] = - { /* closest match of framerate */ - 0, 0, 0, 0, 4, /* 0-4 */ - 5, 5, 7, 7, 10, /* 5-9 */ - 10, 10, 12, 12, 15, /* 10-14 */ - 15, 15, 15, 20, 20, /* 15-19 */ - 20, 20, 20, 24, 24, /* 20-24 */ - 24, 24, 24, 24, 24, /* 25-29 */ - 24 /* 30 */ - }; - int frames2table[31] = - { 0, 0, 0, 0, 0, /* 0-4 */ - 1, 1, 1, 2, 2, /* 5-9 */ - 3, 3, 4, 4, 4, /* 10-14 */ - 5, 5, 5, 5, 5, /* 15-19 */ - 6, 6, 6, 6, 7, /* 20-24 */ - 7, 7, 7, 7, 7, /* 25-29 */ - 7 /* 30 */ - }; - - if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) - return -EINVAL; - frames = frames2frames[frames]; - fps = frames2table[frames]; - pEntry = &Nala_table[size][fps]; - if (pEntry->alternate == 0) - return -EINVAL; - - memcpy(buf, pEntry->mode, 3); - ret = send_video_command(pdev, pdev->vendpoint, buf, 3); - if (ret < 0) { - PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret); - return ret; - } - if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) - pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); - - pdev->cmd_len = 3; - memcpy(pdev->cmd_buf, buf, 3); - - /* Set various parameters */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->valternate = pEntry->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; - if (pEntry->compressed) { - if (pdev->release < 5) { /* 4 fold compression */ - pdev->vbandlength = 528; - pdev->frame_size /= 4; - } - else { - pdev->vbandlength = 704; - pdev->frame_size /= 3; - } - } - else - pdev->vbandlength = 0; - return 0; -} - - -static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) -{ - unsigned char buf[13]; - const struct Timon_table_entry *pChoose; - int ret, fps; - - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) - return -EINVAL; - fps = (frames / 5) - 1; - - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - */ - pChoose = NULL; - while (compression <= 3) { - pChoose = &Timon_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; - } - if (pChoose == NULL || pChoose->alternate == 0) - return -ENOENT; /* Not supported. */ - - memcpy(buf, pChoose->mode, 13); - if (snapshot) - buf[0] |= 0x80; - ret = send_video_command(pdev, pdev->vendpoint, buf, 13); - if (ret < 0) - return ret; - - if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) - pwc_dec23_init(pdev, pdev->type, buf); - - pdev->cmd_len = 13; - memcpy(pdev->cmd_buf, buf, 13); - - /* Set various parameters */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; - pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->vbandlength = pChoose->bandlength; - if (pChoose->bandlength > 0) - pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; - else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; - return 0; -} - - -static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) -{ - const struct Kiara_table_entry *pChoose = NULL; - int fps, ret; - unsigned char buf[12]; - struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; - - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) - return -EINVAL; - fps = (frames / 5) - 1; - - /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ - if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420) - { - /* Only available in case the raw palette is selected or - we have the decompressor available. This mode is - only available in compressed form - */ - PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n"); - pChoose = &RawEntry; - } - else - { - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - Skip this step when using RAW modes. - */ - snapshot = 0; - while (compression <= 3) { - pChoose = &Kiara_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; - } - } - if (pChoose == NULL || pChoose->alternate == 0) - return -ENOENT; /* Not supported. */ - - PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate); - - /* usb_control_msg won't take staticly allocated arrays as argument?? */ - memcpy(buf, pChoose->mode, 12); - if (snapshot) - buf[0] |= 0x80; - - /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ - ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12); - if (ret < 0) - return ret; - - if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) - pwc_dec23_init(pdev, pdev->type, buf); - - pdev->cmd_len = 12; - memcpy(pdev->cmd_buf, buf, 12); - /* All set and go */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; - pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->vbandlength = pChoose->bandlength; - if (pdev->vbandlength > 0) - pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; - else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; - PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n", - pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength); - return 0; -} - - - -/** - @pdev: device structure - @width: viewport width - @height: viewport height - @frame: framerate, in fps - @compression: preferred compression ratio - @snapshot: snapshot mode or streaming - */ -int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) -{ - int ret, size; - - PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt); - size = pwc_decode_size(pdev, width, height); - if (size < 0) { - PWC_DEBUG_MODULE("Could not find suitable size.\n"); - return -ERANGE; - } - PWC_TRACE("decode_size = %d.\n", size); - - if (DEVICE_USE_CODEC1(pdev->type)) { - ret = set_video_mode_Nala(pdev, size, frames); - - } else if (DEVICE_USE_CODEC3(pdev->type)) { - ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); - - } else { - ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); - } - if (ret < 0) { - PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); - return ret; - } - pdev->view.x = width; - pdev->view.y = height; - pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; - pwc_set_image_buffer_size(pdev); - PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); - return 0; -} - -static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size) -{ - unsigned int i; - - for (i = 0; i < PWC_FPS_MAX_NALA; i++) { - if (Nala_table[size][i].alternate) { - if (index--==0) return Nala_fps_vector[i]; - } - } - return 0; -} - -static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size) -{ - unsigned int i; - - for (i = 0; i < PWC_FPS_MAX_KIARA; i++) { - if (Kiara_table[size][i][3].alternate) { - if (index--==0) return Kiara_fps_vector[i]; - } - } - return 0; -} - -static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size) -{ - unsigned int i; - - for (i=0; i < PWC_FPS_MAX_TIMON; i++) { - if (Timon_table[size][i][3].alternate) { - if (index--==0) return Timon_fps_vector[i]; - } - } - return 0; -} - -unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) -{ - unsigned int ret; - - if (DEVICE_USE_CODEC1(pdev->type)) { - ret = pwc_get_fps_Nala(pdev, index, size); - - } else if (DEVICE_USE_CODEC3(pdev->type)) { - ret = pwc_get_fps_Kiara(pdev, index, size); - - } else { - ret = pwc_get_fps_Timon(pdev, index, size); - } - - return ret; -} - -#define BLACK_Y 0 -#define BLACK_U 128 -#define BLACK_V 128 - -static void pwc_set_image_buffer_size(struct pwc_device *pdev) -{ - int i, factor = 0; - - /* for V4L2_PIX_FMT_YUV420 */ - switch (pdev->pixfmt) { - case V4L2_PIX_FMT_YUV420: - factor = 6; - break; - case V4L2_PIX_FMT_PWC1: - case V4L2_PIX_FMT_PWC2: - factor = 6; /* can be uncompressed YUV420P */ - break; - } - - /* Set sizes in bytes */ - pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; - pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; - - /* Align offset, or you'll get some very weird results in - YUV420 mode... x must be multiple of 4 (to get the Y's in - place), and y even (or you'll mixup U & V). This is less of a - problem for YUV420P. - */ - pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; - pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; - - /* Fill buffers with black colors */ - for (i = 0; i < pwc_mbufs; i++) { - unsigned char *p = pdev->image_data + pdev->images[i].offset; - memset(p, BLACK_Y, pdev->view.x * pdev->view.y); - p += pdev->view.x * pdev->view.y; - memset(p, BLACK_U, pdev->view.x * pdev->view.y/4); - p += pdev->view.x * pdev->view.y/4; - memset(p, BLACK_V, pdev->view.x * pdev->view.y/4); - } -} - - - -/* BRIGHTNESS */ - -int pwc_get_brightness(struct pwc_device *pdev) -{ - char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - return buf; -} - -int pwc_set_brightness(struct pwc_device *pdev, int value) -{ - char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 9) & 0x7f; - return send_control_msg(pdev, - SET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf)); -} - -/* CONTRAST */ - -int pwc_get_contrast(struct pwc_device *pdev) -{ - char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - return buf; -} - -int pwc_set_contrast(struct pwc_device *pdev, int value) -{ - char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 10) & 0x3f; - return send_control_msg(pdev, - SET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf)); -} - -/* GAMMA */ - -int pwc_get_gamma(struct pwc_device *pdev) -{ - char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - return buf; -} - -int pwc_set_gamma(struct pwc_device *pdev, int value) -{ - char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 11) & 0x1f; - return send_control_msg(pdev, - SET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf)); -} - - -/* SATURATION */ - -/* return a value between [-100 , 100] */ -int pwc_get_saturation(struct pwc_device *pdev, int *value) -{ - char buf; - int ret, saturation_register; - - if (pdev->type < 675) - return -EINVAL; - if (pdev->type < 730) - saturation_register = SATURATION_MODE_FORMATTER2; - else - saturation_register = SATURATION_MODE_FORMATTER1; - ret = recv_control_msg(pdev, - GET_CHROM_CTL, saturation_register, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = (signed)buf; - return 0; -} - -/* @param value saturation color between [-100 , 100] */ -int pwc_set_saturation(struct pwc_device *pdev, int value) -{ - char buf; - int saturation_register; - - if (pdev->type < 675) - return -EINVAL; - if (value < -100) - value = -100; - if (value > 100) - value = 100; - if (pdev->type < 730) - saturation_register = SATURATION_MODE_FORMATTER2; - else - saturation_register = SATURATION_MODE_FORMATTER1; - return send_control_msg(pdev, - SET_CHROM_CTL, saturation_register, &buf, sizeof(buf)); -} - -/* AGC */ - -int pwc_set_agc(struct pwc_device *pdev, int mode, int value) -{ - char buf; - int ret; - - if (mode) - buf = 0x0; /* auto */ - else - buf = 0xff; /* fixed */ - - ret = send_control_msg(pdev, - SET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf)); - - if (!mode && ret >= 0) { - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 10) & 0x3F; - ret = send_control_msg(pdev, - SET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf)); - } - if (ret < 0) - return ret; - return 0; -} - -int pwc_get_agc(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - - if (buf != 0) { /* fixed */ - ret = recv_control_msg(pdev, - GET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - if (buf > 0x3F) - buf = 0x3F; - *value = (buf << 10); - } - else { /* auto */ - ret = recv_control_msg(pdev, - GET_STATUS_CTL, READ_AGC_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - /* Gah... this value ranges from 0x00 ... 0x9F */ - if (buf > 0x9F) - buf = 0x9F; - *value = -(48 + buf * 409); - } - - return 0; -} - -int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) -{ - char buf[2]; - int speed, ret; - - - if (mode) - buf[0] = 0x0; /* auto */ - else - buf[0] = 0xff; /* fixed */ - - ret = send_control_msg(pdev, - SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, 1); - - if (!mode && ret >= 0) { - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - - if (DEVICE_USE_CODEC2(pdev->type)) { - /* speed ranges from 0x0 to 0x290 (656) */ - speed = (value / 100); - buf[1] = speed >> 8; - buf[0] = speed & 0xff; - } else if (DEVICE_USE_CODEC3(pdev->type)) { - /* speed seems to range from 0x0 to 0xff */ - buf[1] = 0; - buf[0] = value >> 8; - } - - ret = send_control_msg(pdev, - SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, - &buf, sizeof(buf)); - } - return ret; -} - -/* This function is not exported to v4l1, so output values between 0 -> 256 */ -int pwc_get_shutter_speed(struct pwc_device *pdev, int *value) -{ - unsigned char buf[2]; - int ret; - - ret = recv_control_msg(pdev, - GET_STATUS_CTL, READ_SHUTTER_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf[0] + (buf[1] << 8); - if (DEVICE_USE_CODEC2(pdev->type)) { - /* speed ranges from 0x0 to 0x290 (656) */ - *value *= 256/656; - } else if (DEVICE_USE_CODEC3(pdev->type)) { - /* speed seems to range from 0x0 to 0xff */ - } - return 0; -} - - -/* POWER */ - -int pwc_camera_power(struct pwc_device *pdev, int power) -{ - char buf; - - if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) - return 0; /* Not supported by Nala or Timon < release 6 */ - - if (power) - buf = 0x00; /* active */ - else - buf = 0xFF; /* power save */ - return send_control_msg(pdev, - SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, - &buf, sizeof(buf)); -} - - - -/* private calls */ - -int pwc_restore_user(struct pwc_device *pdev) -{ - return send_control_msg(pdev, - SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, NULL, 0); -} - -int pwc_save_user(struct pwc_device *pdev) -{ - return send_control_msg(pdev, - SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, NULL, 0); -} - -int pwc_restore_factory(struct pwc_device *pdev) -{ - return send_control_msg(pdev, - SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, NULL, 0); -} - - /* ************************************************* */ - /* Patch by Alvarado: (not in the original version */ - - /* - * the camera recognizes modes from 0 to 4: - * - * 00: indoor (incandescant lighting) - * 01: outdoor (sunlight) - * 02: fluorescent lighting - * 03: manual - * 04: auto - */ -int pwc_set_awb(struct pwc_device *pdev, int mode) -{ - char buf; - int ret; - - if (mode < 0) - mode = 0; - - if (mode > 4) - mode = 4; - - buf = mode & 0x07; /* just the lowest three bits */ - - ret = send_control_msg(pdev, - SET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf)); - - if (ret < 0) - return ret; - return 0; -} - -int pwc_get_awb(struct pwc_device *pdev) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf)); - - if (ret < 0) - return ret; - return buf; -} - -int pwc_set_red_gain(struct pwc_device *pdev, int value) -{ - unsigned char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - /* only the msb is considered */ - buf = value >> 8; - return send_control_msg(pdev, - SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, - &buf, sizeof(buf)); -} - -int pwc_get_red_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, - &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - - -int pwc_set_blue_gain(struct pwc_device *pdev, int value) -{ - unsigned char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - /* only the msb is considered */ - buf = value >> 8; - return send_control_msg(pdev, - SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, - &buf, sizeof(buf)); -} - -int pwc_get_blue_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, - &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - - -/* The following two functions are different, since they only read the - internal red/blue gains, which may be different from the manual - gains set or read above. - */ -static int pwc_read_red_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - -static int pwc_read_blue_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - - -static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) -{ - unsigned char buf; - - /* useful range is 0x01..0x20 */ - buf = speed / 0x7f0; - return send_control_msg(pdev, - SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf)); -} - -static int pwc_get_wb_speed(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf * 0x7f0; - return 0; -} - - -static int pwc_set_wb_delay(struct pwc_device *pdev, int delay) -{ - unsigned char buf; - - /* useful range is 0x01..0x3F */ - buf = (delay >> 10); - return send_control_msg(pdev, - SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf)); -} - -static int pwc_get_wb_delay(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf << 10; - return 0; -} - - -int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) -{ - unsigned char buf[2]; - - if (pdev->type < 730) - return 0; - on_value /= 100; - off_value /= 100; - if (on_value < 0) - on_value = 0; - if (on_value > 0xff) - on_value = 0xff; - if (off_value < 0) - off_value = 0; - if (off_value > 0xff) - off_value = 0xff; - - buf[0] = on_value; - buf[1] = off_value; - - return send_control_msg(pdev, - SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf)); -} - -static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) -{ - unsigned char buf[2]; - int ret; - - if (pdev->type < 730) { - *on_value = -1; - *off_value = -1; - return 0; - } - - ret = recv_control_msg(pdev, - GET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *on_value = buf[0] * 100; - *off_value = buf[1] * 100; - return 0; -} - -int pwc_set_contour(struct pwc_device *pdev, int contour) -{ - unsigned char buf; - int ret; - - if (contour < 0) - buf = 0xff; /* auto contour on */ - else - buf = 0x0; /* auto contour off */ - ret = send_control_msg(pdev, - SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - - if (contour < 0) - return 0; - if (contour > 0xffff) - contour = 0xffff; - - buf = (contour >> 10); /* contour preset is [0..3f] */ - ret = send_control_msg(pdev, - SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - return 0; -} - -int pwc_get_contour(struct pwc_device *pdev, int *contour) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - - if (buf == 0) { - /* auto mode off, query current preset value */ - ret = recv_control_msg(pdev, - GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, - &buf, sizeof(buf)); - if (ret < 0) - return ret; - *contour = buf << 10; - } - else - *contour = -1; - return 0; -} - - -int pwc_set_backlight(struct pwc_device *pdev, int backlight) -{ - unsigned char buf; - - if (backlight) - buf = 0xff; - else - buf = 0x0; - return send_control_msg(pdev, - SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, - &buf, sizeof(buf)); -} - -int pwc_get_backlight(struct pwc_device *pdev, int *backlight) -{ - int ret; - unsigned char buf; - - ret = recv_control_msg(pdev, - GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, - &buf, sizeof(buf)); - if (ret < 0) - return ret; - *backlight = !!buf; - return 0; -} - -int pwc_set_colour_mode(struct pwc_device *pdev, int colour) -{ - unsigned char buf; - - if (colour) - buf = 0xff; - else - buf = 0x0; - return send_control_msg(pdev, - SET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf)); -} - -int pwc_get_colour_mode(struct pwc_device *pdev, int *colour) -{ - int ret; - unsigned char buf; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *colour = !!buf; - return 0; -} - - -int pwc_set_flicker(struct pwc_device *pdev, int flicker) -{ - unsigned char buf; - - if (flicker) - buf = 0xff; - else - buf = 0x0; - return send_control_msg(pdev, - SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf)); -} - -int pwc_get_flicker(struct pwc_device *pdev, int *flicker) -{ - int ret; - unsigned char buf; - - ret = recv_control_msg(pdev, - GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *flicker = !!buf; - return 0; -} - -int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) -{ - unsigned char buf; - - if (noise < 0) - noise = 0; - if (noise > 3) - noise = 3; - buf = noise; - return send_control_msg(pdev, - SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, - &buf, sizeof(buf)); -} - -int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) -{ - int ret; - unsigned char buf; - - ret = recv_control_msg(pdev, - GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, - &buf, sizeof(buf)); - if (ret < 0) - return ret; - *noise = buf; - return 0; -} - -static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) -{ - unsigned char buf; - - buf = flags & 0x03; // only lower two bits are currently used - return send_control_msg(pdev, - SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, &buf, sizeof(buf)); -} - -int pwc_mpt_reset(struct pwc_device *pdev, int flags) -{ - int ret; - ret = _pwc_mpt_reset(pdev, flags); - if (ret >= 0) { - pdev->pan_angle = 0; - pdev->tilt_angle = 0; - } - return ret; -} - -static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) -{ - unsigned char buf[4]; - - /* set new relative angle; angles are expressed in degrees * 100, - but cam as .5 degree resolution, hence divide by 200. Also - the angle must be multiplied by 64 before it's send to - the cam (??) - */ - pan = 64 * pan / 100; - tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ - buf[0] = pan & 0xFF; - buf[1] = (pan >> 8) & 0xFF; - buf[2] = tilt & 0xFF; - buf[3] = (tilt >> 8) & 0xFF; - return send_control_msg(pdev, - SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, &buf, sizeof(buf)); -} - -int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) -{ - int ret; - - /* check absolute ranges */ - if (pan < pdev->angle_range.pan_min || - pan > pdev->angle_range.pan_max || - tilt < pdev->angle_range.tilt_min || - tilt > pdev->angle_range.tilt_max) - return -ERANGE; - - /* go to relative range, check again */ - pan -= pdev->pan_angle; - tilt -= pdev->tilt_angle; - /* angles are specified in degrees * 100, thus the limit = 36000 */ - if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000) - return -ERANGE; - - ret = _pwc_mpt_set_angle(pdev, pan, tilt); - if (ret >= 0) { - pdev->pan_angle += pan; - pdev->tilt_angle += tilt; - } - if (ret == -EPIPE) /* stall -> out of range */ - ret = -ERANGE; - return ret; -} - -static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) -{ - int ret; - unsigned char buf[5]; - - ret = recv_control_msg(pdev, - GET_MPT_CTL, PT_STATUS_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - status->status = buf[0] & 0x7; // 3 bits are used for reporting - status->time_pan = (buf[1] << 8) + buf[2]; - status->time_tilt = (buf[3] << 8) + buf[4]; - return 0; -} - - -int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) -{ - unsigned char buf; - int ret = -1, request; - - if (pdev->type < 675) - request = SENSOR_TYPE_FORMATTER1; - else if (pdev->type < 730) - return -1; /* The Vesta series doesn't have this call */ - else - request = SENSOR_TYPE_FORMATTER2; - - ret = recv_control_msg(pdev, - GET_STATUS_CTL, request, &buf, sizeof(buf)); - if (ret < 0) - return ret; - if (pdev->type < 675) - *sensor = buf | 0x100; - else - *sensor = buf; - return 0; -} - - - /* End of Add-Ons */ - /* ************************************************* */ - -/* Linux 2.5.something and 2.6 pass direct pointers to arguments of - ioctl() calls. With 2.4, you have to do tedious copy_from_user() - and copy_to_user() calls. With these macros we circumvent this, - and let me maintain only one source file. The functionality is - exactly the same otherwise. - */ - -/* define local variable for arg */ -#define ARG_DEF(ARG_type, ARG_name)\ - ARG_type *ARG_name = arg; -/* copy arg to local variable */ -#define ARG_IN(ARG_name) /* nothing */ -/* argument itself (referenced) */ -#define ARGR(ARG_name) (*ARG_name) -/* argument address */ -#define ARGA(ARG_name) ARG_name -/* copy local variable to arg */ -#define ARG_OUT(ARG_name) /* nothing */ - -long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) -{ - long ret = 0; - - switch(cmd) { - case VIDIOCPWCRUSER: - { - if (pwc_restore_user(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCSUSER: - { - if (pwc_save_user(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCFACTORY: - { - if (pwc_restore_factory(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCSCQUAL: - { - ARG_DEF(int, qual) - - if (pdev->iso_init) { - ret = -EBUSY; - break; - } - - ARG_IN(qual) - if (ARGR(qual) < 0 || ARGR(qual) > 3) - ret = -EINVAL; - else - ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); - if (ret >= 0) - pdev->vcompression = ARGR(qual); - break; - } - - case VIDIOCPWCGCQUAL: - { - ARG_DEF(int, qual) - - ARGR(qual) = pdev->vcompression; - ARG_OUT(qual) - break; - } - - case VIDIOCPWCPROBE: - { - ARG_DEF(struct pwc_probe, probe) - - strcpy(ARGR(probe).name, pdev->vdev->name); - ARGR(probe).type = pdev->type; - ARG_OUT(probe) - break; - } - - case VIDIOCPWCGSERIAL: - { - ARG_DEF(struct pwc_serial, serial) - - strcpy(ARGR(serial).serial, pdev->serial); - ARG_OUT(serial) - break; - } - - case VIDIOCPWCSAGC: - { - ARG_DEF(int, agc) - - ARG_IN(agc) - if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) - ret = -EINVAL; - break; - } - - case VIDIOCPWCGAGC: - { - ARG_DEF(int, agc) - - if (pwc_get_agc(pdev, ARGA(agc))) - ret = -EINVAL; - ARG_OUT(agc) - break; - } - - case VIDIOCPWCSSHUTTER: - { - ARG_DEF(int, shutter_speed) - - ARG_IN(shutter_speed) - ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); - break; - } - - case VIDIOCPWCSAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) - - ARG_IN(wb) - ret = pwc_set_awb(pdev, ARGR(wb).mode); - if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { - pwc_set_red_gain(pdev, ARGR(wb).manual_red); - pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); - } - break; - } - - case VIDIOCPWCGAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) - - memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); - ARGR(wb).mode = pwc_get_awb(pdev); - if (ARGR(wb).mode < 0) - ret = -EINVAL; - else { - if (ARGR(wb).mode == PWC_WB_MANUAL) { - ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); - if (ret < 0) - break; - ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); - if (ret < 0) - break; - } - if (ARGR(wb).mode == PWC_WB_AUTO) { - ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); - if (ret < 0) - break; - ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); - if (ret < 0) - break; - } - } - ARG_OUT(wb) - break; - } - - case VIDIOCPWCSAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - if (ARGR(wbs).control_speed > 0) { - ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); - } - if (ARGR(wbs).control_delay > 0) { - ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); - } - break; - } - - case VIDIOCPWCGAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); - if (ret < 0) - break; - ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); - if (ret < 0) - break; - ARG_OUT(wbs) - break; - } - - case VIDIOCPWCSLED: - { - ARG_DEF(struct pwc_leds, leds) - - ARG_IN(leds) - ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); - break; - } - - - case VIDIOCPWCGLED: - { - ARG_DEF(struct pwc_leds, leds) - - ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); - ARG_OUT(leds) - break; - } - - case VIDIOCPWCSCONTOUR: - { - ARG_DEF(int, contour) - - ARG_IN(contour) - ret = pwc_set_contour(pdev, ARGR(contour)); - break; - } - - case VIDIOCPWCGCONTOUR: - { - ARG_DEF(int, contour) - - ret = pwc_get_contour(pdev, ARGA(contour)); - ARG_OUT(contour) - break; - } - - case VIDIOCPWCSBACKLIGHT: - { - ARG_DEF(int, backlight) - - ARG_IN(backlight) - ret = pwc_set_backlight(pdev, ARGR(backlight)); - break; - } - - case VIDIOCPWCGBACKLIGHT: - { - ARG_DEF(int, backlight) - - ret = pwc_get_backlight(pdev, ARGA(backlight)); - ARG_OUT(backlight) - break; - } - - case VIDIOCPWCSFLICKER: - { - ARG_DEF(int, flicker) - - ARG_IN(flicker) - ret = pwc_set_flicker(pdev, ARGR(flicker)); - break; - } - - case VIDIOCPWCGFLICKER: - { - ARG_DEF(int, flicker) - - ret = pwc_get_flicker(pdev, ARGA(flicker)); - ARG_OUT(flicker) - break; - } - - case VIDIOCPWCSDYNNOISE: - { - ARG_DEF(int, dynnoise) - - ARG_IN(dynnoise) - ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); - break; - } - - case VIDIOCPWCGDYNNOISE: - { - ARG_DEF(int, dynnoise) - - ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); - ARG_OUT(dynnoise); - break; - } - - case VIDIOCPWCGREALSIZE: - { - ARG_DEF(struct pwc_imagesize, size) - - ARGR(size).width = pdev->image.x; - ARGR(size).height = pdev->image.y; - ARG_OUT(size) - break; - } - - case VIDIOCPWCMPTRESET: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(int, flags) - - ARG_IN(flags) - ret = pwc_mpt_reset(pdev, ARGR(flags)); - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGRANGE: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_range, range) - - ARGR(range) = pdev->angle_range; - ARG_OUT(range) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSANGLE: - { - int new_pan, new_tilt; - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARG_IN(angles) - /* The camera can only set relative angles, so - do some calculations when getting an absolute angle . - */ - if (ARGR(angles).absolute) - { - new_pan = ARGR(angles).pan; - new_tilt = ARGR(angles).tilt; - } - else - { - new_pan = pdev->pan_angle + ARGR(angles).pan; - new_tilt = pdev->tilt_angle + ARGR(angles).tilt; - } - ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGANGLE: - { - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARGR(angles).absolute = 1; - ARGR(angles).pan = pdev->pan_angle; - ARGR(angles).tilt = pdev->tilt_angle; - ARG_OUT(angles) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSTATUS: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_status, status) - - ret = pwc_mpt_get_status(pdev, ARGA(status)); - ARG_OUT(status) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCGVIDCMD: - { - ARG_DEF(struct pwc_video_command, vcmd); - - ARGR(vcmd).type = pdev->type; - ARGR(vcmd).release = pdev->release; - ARGR(vcmd).command_len = pdev->cmd_len; - memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len); - ARGR(vcmd).bandlength = pdev->vbandlength; - ARGR(vcmd).frame_size = pdev->frame_size; - ARG_OUT(vcmd) - break; - } - /* - case VIDIOCPWCGVIDTABLE: - { - ARG_DEF(struct pwc_table_init_buffer, table); - ARGR(table).len = pdev->cmd_len; - memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); - ARG_OUT(table) - break; - } - */ - - default: - ret = -ENOIOCTLCMD; - break; - } - - if (ret > 0) - return 0; - return ret; -} - - -/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec1.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec1.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec1.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec1.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* Linux driver for Philips webcam - Decompression for chipset version 1 - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 "pwc-dec1.h" - - -void pwc_dec1_init(int type, int release, void *buffer, void *table) -{ - -} - -void pwc_dec1_exit(void) -{ - - - -} - -int pwc_dec1_alloc(struct pwc_device *pwc) -{ - pwc->decompress_data = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL); - if (pwc->decompress_data == NULL) - return -ENOMEM; - return 0; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec1.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec1.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec1.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec1.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - - - -#ifndef PWC_DEC1_H -#define PWC_DEC1_H - -#include "pwc.h" - -struct pwc_dec1_private -{ - int version; - -}; - -int pwc_dec1_alloc(struct pwc_device *pwc); -void pwc_dec1_init(int type, int release, void *buffer, void *private_data); -void pwc_dec1_exit(void); - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec23.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec23.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec23.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec23.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,942 +0,0 @@ -/* Linux driver for Philips webcam - Decompression for chipset version 2 et 3 - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 "pwc-timon.h" -#include "pwc-kiara.h" -#include "pwc-dec23.h" -#include - -#include -#include - -/* - * USE_LOOKUP_TABLE_TO_CLAMP - * 0: use a C version of this tests: { a<0?0:(a>255?255:a) } - * 1: use a faster lookup table for cpu with a big cache (intel) - */ -#define USE_LOOKUP_TABLE_TO_CLAMP 1 -/* - * UNROLL_LOOP_FOR_COPYING_BLOCK - * 0: use a loop for a smaller code (but little slower) - * 1: when unrolling the loop, gcc produces some faster code (perhaps only - * valid for intel processor class). Activating this option, automaticaly - * activate USE_LOOKUP_TABLE_TO_CLAMP - */ -#define UNROLL_LOOP_FOR_COPY 1 -#if UNROLL_LOOP_FOR_COPY -# undef USE_LOOKUP_TABLE_TO_CLAMP -# define USE_LOOKUP_TABLE_TO_CLAMP 1 -#endif - -/* - * ENABLE_BAYER_DECODER - * 0: bayer decoder is not build (save some space) - * 1: bayer decoder is build and can be used - */ -#define ENABLE_BAYER_DECODER 0 - -static void build_subblock_pattern(struct pwc_dec23_private *pdec) -{ - static const unsigned int initial_values[12] = { - -0x526500, -0x221200, 0x221200, 0x526500, - -0x3de200, 0x3de200, - -0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480, - -0x12c200, 0x12c200 - - }; - static const unsigned int values_derivated[12] = { - 0xa4ca, 0x4424, -0x4424, -0xa4ca, - 0x7bc4, -0x7bc4, - 0xdb69, 0x5aba, -0x5aba, -0xdb69, - 0x2584, -0x2584 - }; - unsigned int temp_values[12]; - int i, j; - - memcpy(temp_values, initial_values, sizeof(initial_values)); - for (i = 0; i < 256; i++) { - for (j = 0; j < 12; j++) { - pdec->table_subblock[i][j] = temp_values[j]; - temp_values[j] += values_derivated[j]; - } - } -} - -static void build_bit_powermask_table(struct pwc_dec23_private *pdec) -{ - unsigned char *p; - unsigned int bit, byte, mask, val; - unsigned int bitpower = 1; - - for (bit = 0; bit < 8; bit++) { - mask = bitpower - 1; - p = pdec->table_bitpowermask[bit]; - for (byte = 0; byte < 256; byte++) { - val = (byte & mask); - if (byte & bitpower) - val = -val; - *p++ = val; - } - bitpower<<=1; - } -} - - -static void build_table_color(const unsigned int romtable[16][8], - unsigned char p0004[16][1024], - unsigned char p8004[16][256]) -{ - int compression_mode, j, k, bit, pw; - unsigned char *p0, *p8; - const unsigned int *r; - - /* We have 16 compressions tables */ - for (compression_mode = 0; compression_mode < 16; compression_mode++) { - p0 = p0004[compression_mode]; - p8 = p8004[compression_mode]; - r = romtable[compression_mode]; - - for (j = 0; j < 8; j++, r++, p0 += 128) { - - for (k = 0; k < 16; k++) { - if (k == 0) - bit = 1; - else if (k >= 1 && k < 3) - bit = (r[0] >> 15) & 7; - else if (k >= 3 && k < 6) - bit = (r[0] >> 12) & 7; - else if (k >= 6 && k < 10) - bit = (r[0] >> 9) & 7; - else if (k >= 10 && k < 13) - bit = (r[0] >> 6) & 7; - else if (k >= 13 && k < 15) - bit = (r[0] >> 3) & 7; - else - bit = (r[0]) & 7; - if (k == 0) - *p8++ = 8; - else - *p8++ = j - bit; - *p8++ = bit; - - pw = 1 << bit; - p0[k + 0x00] = (1 * pw) + 0x80; - p0[k + 0x10] = (2 * pw) + 0x80; - p0[k + 0x20] = (3 * pw) + 0x80; - p0[k + 0x30] = (4 * pw) + 0x80; - p0[k + 0x40] = (-1 * pw) + 0x80; - p0[k + 0x50] = (-2 * pw) + 0x80; - p0[k + 0x60] = (-3 * pw) + 0x80; - p0[k + 0x70] = (-4 * pw) + 0x80; - } /* end of for (k=0; k<16; k++, p8++) */ - } /* end of for (j=0; j<8; j++ , table++) */ - } /* end of foreach compression_mode */ -} - -/* - * - */ -static void fill_table_dc00_d800(struct pwc_dec23_private *pdec) -{ -#define SCALEBITS 15 -#define ONE_HALF (1UL << (SCALEBITS - 1)) - int i; - unsigned int offset1 = ONE_HALF; - unsigned int offset2 = 0x0000; - - for (i=0; i<256; i++) { - pdec->table_dc00[i] = offset1 & ~(ONE_HALF); - pdec->table_d800[i] = offset2; - - offset1 += 0x7bc4; - offset2 += 0x7bc4; - } -} - -/* - * To decode the stream: - * if look_bits(2) == 0: # op == 2 in the lookup table - * skip_bits(2) - * end of the stream - * elif look_bits(3) == 7: # op == 1 in the lookup table - * skip_bits(3) - * yyyy = get_bits(4) - * xxxx = get_bits(8) - * else: # op == 0 in the lookup table - * skip_bits(x) - * - * For speedup processing, we build a lookup table and we takes the first 6 bits. - * - * struct { - * unsigned char op; // operation to execute - * unsigned char bits; // bits use to perform operation - * unsigned char offset1; // offset to add to access in the table_0004 % 16 - * unsigned char offset2; // offset to add to access in the table_0004 - * } - * - * How to build this table ? - * op == 2 when (i%4)==0 - * op == 1 when (i%8)==7 - * op == 0 otherwise - * - */ -static const unsigned char hash_table_ops[64*4] = { - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x00, - 0x00, 0x04, 0x01, 0x10, - 0x00, 0x06, 0x01, 0x30, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x40, - 0x00, 0x05, 0x01, 0x20, - 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x00, - 0x00, 0x04, 0x01, 0x50, - 0x00, 0x05, 0x02, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x40, - 0x00, 0x05, 0x03, 0x00, - 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x00, - 0x00, 0x04, 0x01, 0x10, - 0x00, 0x06, 0x02, 0x10, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x40, - 0x00, 0x05, 0x01, 0x60, - 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x00, - 0x00, 0x04, 0x01, 0x50, - 0x00, 0x05, 0x02, 0x40, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x40, - 0x00, 0x05, 0x03, 0x40, - 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x00, - 0x00, 0x04, 0x01, 0x10, - 0x00, 0x06, 0x01, 0x70, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x40, - 0x00, 0x05, 0x01, 0x20, - 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x00, - 0x00, 0x04, 0x01, 0x50, - 0x00, 0x05, 0x02, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x40, - 0x00, 0x05, 0x03, 0x00, - 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x00, - 0x00, 0x04, 0x01, 0x10, - 0x00, 0x06, 0x02, 0x50, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x40, - 0x00, 0x05, 0x01, 0x60, - 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x00, - 0x00, 0x04, 0x01, 0x50, - 0x00, 0x05, 0x02, 0x40, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x01, 0x40, - 0x00, 0x05, 0x03, 0x40, - 0x01, 0x00, 0x00, 0x00 -}; - -/* - * - */ -static const unsigned int MulIdx[16][16] = { - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, - {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,}, - {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,}, - {4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,}, - {6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,}, - {4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,}, - {1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,}, - {0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,}, - {0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,}, - {1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,}, - {7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,}, - {4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,}, - {7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,}, - {1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,}, - {1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,}, - {10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10} -}; - -#if USE_LOOKUP_TABLE_TO_CLAMP -#define MAX_OUTER_CROP_VALUE (512) -static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE]; -#define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)]) -#else -#define CLAMP(x) ((x)>255?255:((x)<0?0:x)) -#endif - - -/* If the type or the command change, we rebuild the lookup table */ -int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd) -{ - int flags, version, shift, i; - struct pwc_dec23_private *pdec; - - if (pwc->decompress_data == NULL) { - pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); - if (pdec == NULL) - return -ENOMEM; - pwc->decompress_data = pdec; - } - pdec = pwc->decompress_data; - - if (DEVICE_USE_CODEC3(type)) { - flags = cmd[2] & 0x18; - if (flags == 8) - pdec->nbits = 7; /* More bits, mean more bits to encode the stream, but better quality */ - else if (flags == 0x10) - pdec->nbits = 8; - else - pdec->nbits = 6; - - version = cmd[2] >> 5; - build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1); - build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2); - - } else { - - flags = cmd[2] & 6; - if (flags == 2) - pdec->nbits = 7; - else if (flags == 4) - pdec->nbits = 8; - else - pdec->nbits = 6; - - version = cmd[2] >> 3; - build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1); - build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2); - } - - /* Informations can be coded on a variable number of bits but never less than 8 */ - shift = 8 - pdec->nbits; - pdec->scalebits = SCALEBITS - shift; - pdec->nbitsmask = 0xFF >> shift; - - fill_table_dc00_d800(pdec); - build_subblock_pattern(pdec); - build_bit_powermask_table(pdec); - -#if USE_LOOKUP_TABLE_TO_CLAMP - /* Build the static table to clamp value [0-255] */ - for (i=0;i> scalebits]; - *d++ = cm[c[1] >> scalebits]; - *d++ = cm[c[2] >> scalebits]; - *d++ = cm[c[3] >> scalebits]; - - d = dst + bytes_per_line; - *d++ = cm[c[4] >> scalebits]; - *d++ = cm[c[5] >> scalebits]; - *d++ = cm[c[6] >> scalebits]; - *d++ = cm[c[7] >> scalebits]; - - d = dst + bytes_per_line*2; - *d++ = cm[c[8] >> scalebits]; - *d++ = cm[c[9] >> scalebits]; - *d++ = cm[c[10] >> scalebits]; - *d++ = cm[c[11] >> scalebits]; - - d = dst + bytes_per_line*3; - *d++ = cm[c[12] >> scalebits]; - *d++ = cm[c[13] >> scalebits]; - *d++ = cm[c[14] >> scalebits]; - *d++ = cm[c[15] >> scalebits]; -#else - int i; - const int *c = src; - unsigned char *d = dst; - for (i = 0; i < 4; i++, c++) - *d++ = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line; - for (i = 0; i < 4; i++, c++) - *d++ = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line*2; - for (i = 0; i < 4; i++, c++) - *d++ = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line*3; - for (i = 0; i < 4; i++, c++) - *d++ = CLAMP((*c) >> scalebits); -#endif -} - -/* - * Copy the 4x4 image block to a CrCb plane buffer - * - */ -static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) -{ -#if UNROLL_LOOP_FOR_COPY - /* Unroll all loops */ - const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; - const int *c = src; - unsigned char *d = dst; - - *d++ = cm[c[0] >> scalebits]; - *d++ = cm[c[4] >> scalebits]; - *d++ = cm[c[1] >> scalebits]; - *d++ = cm[c[5] >> scalebits]; - *d++ = cm[c[2] >> scalebits]; - *d++ = cm[c[6] >> scalebits]; - *d++ = cm[c[3] >> scalebits]; - *d++ = cm[c[7] >> scalebits]; - - d = dst + bytes_per_line; - *d++ = cm[c[12] >> scalebits]; - *d++ = cm[c[8] >> scalebits]; - *d++ = cm[c[13] >> scalebits]; - *d++ = cm[c[9] >> scalebits]; - *d++ = cm[c[14] >> scalebits]; - *d++ = cm[c[10] >> scalebits]; - *d++ = cm[c[15] >> scalebits]; - *d++ = cm[c[11] >> scalebits]; -#else - int i; - const int *c1 = src; - const int *c2 = src + 4; - unsigned char *d = dst; - - for (i = 0; i < 4; i++, c1++, c2++) { - *d++ = CLAMP((*c1) >> scalebits); - *d++ = CLAMP((*c2) >> scalebits); - } - c1 = src + 12; - d = dst + bytes_per_line; - for (i = 0; i < 4; i++, c1++, c2++) { - *d++ = CLAMP((*c1) >> scalebits); - *d++ = CLAMP((*c2) >> scalebits); - } -#endif -} - -#if ENABLE_BAYER_DECODER -/* - * Format: 8x2 pixels - * . G . G . G . G . G . G . G - * . . . . . . . . . . . . . . - * . G . G . G . G . G . G . G - * . . . . . . . . . . . . . . - * or - * . . . . . . . . . . . . . . - * G . G . G . G . G . G . G . - * . . . . . . . . . . . . . . - * G . G . G . G . G . G . G . -*/ -static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) -{ -#if UNROLL_LOOP_FOR_COPY - /* Unroll all loops */ - const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; - unsigned char *d = dst; - const int *c = src; - - d[0] = cm[c[0] >> scalebits]; - d[2] = cm[c[1] >> scalebits]; - d[4] = cm[c[2] >> scalebits]; - d[6] = cm[c[3] >> scalebits]; - d[8] = cm[c[4] >> scalebits]; - d[10] = cm[c[5] >> scalebits]; - d[12] = cm[c[6] >> scalebits]; - d[14] = cm[c[7] >> scalebits]; - - d = dst + bytes_per_line; - d[0] = cm[c[8] >> scalebits]; - d[2] = cm[c[9] >> scalebits]; - d[4] = cm[c[10] >> scalebits]; - d[6] = cm[c[11] >> scalebits]; - d[8] = cm[c[12] >> scalebits]; - d[10] = cm[c[13] >> scalebits]; - d[12] = cm[c[14] >> scalebits]; - d[14] = cm[c[15] >> scalebits]; -#else - int i; - unsigned char *d; - const int *c = src; - - d = dst; - for (i = 0; i < 8; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line; - for (i = 0; i < 8; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); -#endif -} -#endif - -#if ENABLE_BAYER_DECODER -/* - * Format: 4x4 pixels - * R . R . R . R - * . B . B . B . - * R . R . R . R - * . B . B . B . - */ -static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) -{ -#if UNROLL_LOOP_FOR_COPY - /* Unroll all loops */ - const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; - unsigned char *d = dst; - const int *c = src; - - d[0] = cm[c[0] >> scalebits]; - d[2] = cm[c[1] >> scalebits]; - d[4] = cm[c[2] >> scalebits]; - d[6] = cm[c[3] >> scalebits]; - - d = dst + bytes_per_line; - d[1] = cm[c[4] >> scalebits]; - d[3] = cm[c[5] >> scalebits]; - d[5] = cm[c[6] >> scalebits]; - d[7] = cm[c[7] >> scalebits]; - - d = dst + bytes_per_line*2; - d[0] = cm[c[8] >> scalebits]; - d[2] = cm[c[9] >> scalebits]; - d[4] = cm[c[10] >> scalebits]; - d[6] = cm[c[11] >> scalebits]; - - d = dst + bytes_per_line*3; - d[1] = cm[c[12] >> scalebits]; - d[3] = cm[c[13] >> scalebits]; - d[5] = cm[c[14] >> scalebits]; - d[7] = cm[c[15] >> scalebits]; -#else - int i; - unsigned char *d; - const int *c = src; - - d = dst; - for (i = 0; i < 4; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line; - for (i = 0; i < 4; i++, c++) - d[i*2+1] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line*2; - for (i = 0; i < 4; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line*3; - for (i = 0; i < 4; i++, c++) - d[i*2+1] = CLAMP((*c) >> scalebits); -#endif -} -#endif - -/* - * To manage the stream, we keep bits in a 32 bits register. - * fill_nbits(n): fill the reservoir with at least n bits - * skip_bits(n): discard n bits from the reservoir - * get_bits(n): fill the reservoir, returns the first n bits and discard the - * bits from the reservoir. - * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir - * contains at least n bits. bits returned is discarded. - */ -#define fill_nbits(pdec, nbits_wanted) do { \ - while (pdec->nbits_in_reservoir<(nbits_wanted)) \ - { \ - pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \ - pdec->nbits_in_reservoir += 8; \ - } \ -} while(0); - -#define skip_nbits(pdec, nbits_to_skip) do { \ - pdec->reservoir >>= (nbits_to_skip); \ - pdec->nbits_in_reservoir -= (nbits_to_skip); \ -} while(0); - -#define get_nbits(pdec, nbits_wanted, result) do { \ - fill_nbits(pdec, nbits_wanted); \ - result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \ - skip_nbits(pdec, nbits_wanted); \ -} while(0); - -#define __get_nbits(pdec, nbits_wanted, result) do { \ - result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \ - skip_nbits(pdec, nbits_wanted); \ -} while(0); - -#define look_nbits(pdec, nbits_wanted) \ - ((pdec->reservoir) & ((1U<<(nbits_wanted))-1)) - -/* - * Decode a 4x4 pixel block - */ -static void decode_block(struct pwc_dec23_private *pdec, - const unsigned char *ptable0004, - const unsigned char *ptable8004) -{ - unsigned int primary_color; - unsigned int channel_v, offset1, op; - int i; - - fill_nbits(pdec, 16); - __get_nbits(pdec, pdec->nbits, primary_color); - - if (look_nbits(pdec,2) == 0) { - skip_nbits(pdec, 2); - /* Very simple, the color is the same for all pixels of the square */ - for (i = 0; i < 16; i++) - pdec->temp_colors[i] = pdec->table_dc00[primary_color]; - - return; - } - - /* This block is encoded with small pattern */ - for (i = 0; i < 16; i++) - pdec->temp_colors[i] = pdec->table_d800[primary_color]; - - __get_nbits(pdec, 3, channel_v); - channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2); - - ptable0004 += (channel_v * 128); - ptable8004 += (channel_v * 32); - - offset1 = 0; - do - { - unsigned int htable_idx, rows = 0; - const unsigned int *block; - - /* [ zzzz y x x ] - * xx == 00 :=> end of the block def, remove the two bits from the stream - * yxx == 111 - * yxx == any other value - * - */ - fill_nbits(pdec, 16); - htable_idx = look_nbits(pdec, 6); - op = hash_table_ops[htable_idx * 4]; - - if (op == 2) { - skip_nbits(pdec, 2); - - } else if (op == 1) { - /* 15bits [ xxxx xxxx yyyy 111 ] - * yyy => offset in the table8004 - * xxx => offset in the tabled004 (tree) - */ - unsigned int mask, shift; - unsigned int nbits, col1; - unsigned int yyyy; - - skip_nbits(pdec, 3); - /* offset1 += yyyy */ - __get_nbits(pdec, 4, yyyy); - offset1 += 1 + yyyy; - offset1 &= 0x0F; - nbits = ptable8004[offset1 * 2]; - - /* col1 = xxxx xxxx */ - __get_nbits(pdec, nbits+1, col1); - - /* Bit mask table */ - mask = pdec->table_bitpowermask[nbits][col1]; - shift = ptable8004[offset1 * 2 + 1]; - rows = ((mask << shift) + 0x80) & 0xFF; - - block = pdec->table_subblock[rows]; - for (i = 0; i < 16; i++) - pdec->temp_colors[i] += block[MulIdx[offset1][i]]; - - } else { - /* op == 0 - * offset1 is coded on 3 bits - */ - unsigned int shift; - - offset1 += hash_table_ops [htable_idx * 4 + 2]; - offset1 &= 0x0F; - - rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]]; - block = pdec->table_subblock[rows]; - for (i = 0; i < 16; i++) - pdec->temp_colors[i] += block[MulIdx[offset1][i]]; - - shift = hash_table_ops[htable_idx * 4 + 1]; - skip_nbits(pdec, shift); - } - - } while (op != 2); - -} - -static void DecompressBand23(struct pwc_dec23_private *pdec, - const unsigned char *rawyuv, - unsigned char *planar_y, - unsigned char *planar_u, - unsigned char *planar_v, - unsigned int compressed_image_width, - unsigned int real_image_width) -{ - int compression_index, nblocks; - const unsigned char *ptable0004; - const unsigned char *ptable8004; - - pdec->reservoir = 0; - pdec->nbits_in_reservoir = 0; - pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */ - - get_nbits(pdec, 4, compression_index); - - /* pass 1: uncompress Y component */ - nblocks = compressed_image_width / 4; - - ptable0004 = pdec->table_0004_pass1[compression_index]; - ptable8004 = pdec->table_8004_pass1[compression_index]; - - /* Each block decode a square of 4x4 */ - while (nblocks) { - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits); - planar_y += 4; - nblocks--; - } - - /* pass 2: uncompress UV component */ - nblocks = compressed_image_width / 8; - - ptable0004 = pdec->table_0004_pass2[compression_index]; - ptable8004 = pdec->table_8004_pass2[compression_index]; - - /* Each block decode a square of 4x4 */ - while (nblocks) { - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits); - - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits); - - planar_v += 8; - planar_u += 8; - nblocks -= 2; - } - -} - -#if ENABLE_BAYER_DECODER -/* - * Size need to be a multiple of 8 in width - * - * Return a block of four line encoded like this: - * - * G R G R G R G R G R G R G R G R - * B G B G B G B G B G B G B G B G - * G R G R G R G R G R G R G R G R - * B G B G B G B G B G B G B G B G - * - */ -static void DecompressBandBayer(struct pwc_dec23_private *pdec, - const unsigned char *rawyuv, - unsigned char *rgbbayer, - unsigned int compressed_image_width, - unsigned int real_image_width) -{ - int compression_index, nblocks; - const unsigned char *ptable0004; - const unsigned char *ptable8004; - unsigned char *dest; - - pdec->reservoir = 0; - pdec->nbits_in_reservoir = 0; - pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */ - - get_nbits(pdec, 4, compression_index); - - /* pass 1: uncompress RB component */ - nblocks = compressed_image_width / 4; - - ptable0004 = pdec->table_0004_pass1[compression_index]; - ptable8004 = pdec->table_8004_pass1[compression_index]; - dest = rgbbayer; - - /* Each block decode a square of 4x4 */ - while (nblocks) { - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits); - dest += 8; - nblocks--; - } - - /* pass 2: uncompress G component */ - nblocks = compressed_image_width / 8; - - ptable0004 = pdec->table_0004_pass2[compression_index]; - ptable8004 = pdec->table_8004_pass2[compression_index]; - - /* Each block decode a square of 4x4 */ - while (nblocks) { - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits); - - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits); - - rgbbayer += 16; - nblocks -= 2; - } -} -#endif - - -/** - * - * Uncompress a pwc23 buffer. - * - * pwc.view: size of the image wanted - * pwc.image: size of the image returned by the camera - * pwc.offset: (x,y) to displayer image in the view - * - * src: raw data - * dst: image output - * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER - */ -void pwc_dec23_decompress(const struct pwc_device *pwc, - const void *src, - void *dst, - int flags) -{ - int bandlines_left, stride, bytes_per_block; - - bandlines_left = pwc->image.y / 4; - bytes_per_block = pwc->view.x * 4; - - if (flags & PWCX_FLAG_BAYER) { -#if ENABLE_BAYER_DECODER - /* RGB Bayer format */ - unsigned char *rgbout; - - stride = pwc->view.x * pwc->offset.y; - rgbout = dst + stride + pwc->offset.x; - - - while (bandlines_left--) { - - DecompressBandBayer(pwc->decompress_data, - src, - rgbout, - pwc->image.x, pwc->view.x); - - src += pwc->vbandlength; - rgbout += bytes_per_block; - - } -#else - memset(dst, 0, pwc->view.x * pwc->view.y); -#endif - - } else { - /* YUV420P image format */ - unsigned char *pout_planar_y; - unsigned char *pout_planar_u; - unsigned char *pout_planar_v; - unsigned int plane_size; - - plane_size = pwc->view.x * pwc->view.y; - - /* offset in Y plane */ - stride = pwc->view.x * pwc->offset.y; - pout_planar_y = dst + stride + pwc->offset.x; - - /* offsets in U/V planes */ - stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2; - pout_planar_u = dst + plane_size + stride; - pout_planar_v = dst + plane_size + plane_size / 4 + stride; - - while (bandlines_left--) { - - DecompressBand23(pwc->decompress_data, - src, - pout_planar_y, pout_planar_u, pout_planar_v, - pwc->image.x, pwc->view.x); - src += pwc->vbandlength; - pout_planar_y += bytes_per_block; - pout_planar_u += pwc->view.x; - pout_planar_v += pwc->view.x; - - } - - } - -} - -void pwc_dec23_exit(void) -{ - /* Do nothing */ - -} - -/** - * Allocate a private structure used by lookup table. - * You must call kfree() to free the memory allocated. - */ -int pwc_dec23_alloc(struct pwc_device *pwc) -{ - pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); - if (pwc->decompress_data == NULL) - return -ENOMEM; - return 0; -} - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec23.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec23.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec23.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-dec23.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - -#ifndef PWC_DEC23_H -#define PWC_DEC23_H - -#include "pwc.h" - -struct pwc_dec23_private -{ - unsigned int scalebits; - unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */ - - unsigned int reservoir; - unsigned int nbits_in_reservoir; - const unsigned char *stream; - int temp_colors[16]; - - unsigned char table_0004_pass1[16][1024]; - unsigned char table_0004_pass2[16][1024]; - unsigned char table_8004_pass1[16][256]; - unsigned char table_8004_pass2[16][256]; - unsigned int table_subblock[256][12]; - - unsigned char table_bitpowermask[8][256]; - unsigned int table_d800[256]; - unsigned int table_dc00[256]; - -}; - - -int pwc_dec23_alloc(struct pwc_device *pwc); -int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd); -void pwc_dec23_exit(void); -void pwc_dec23_decompress(const struct pwc_device *pwc, - const void *src, - void *dst, - int flags); - - - -#endif - - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,354 +0,0 @@ -/* (C) 1999-2003 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - -#ifndef PWC_H -#define PWC_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_USB_PWC_INPUT_EVDEV -#include -#endif - -#include "pwc-uncompress.h" -#include - -/* Version block */ -#define PWC_MAJOR 10 -#define PWC_MINOR 0 -#define PWC_EXTRAMINOR 12 -#define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR) -#define PWC_VERSION "10.0.14" -#define PWC_NAME "pwc" -#define PFX PWC_NAME ": " - - -/* Trace certain actions in the driver */ -#define PWC_DEBUG_LEVEL_MODULE (1<<0) -#define PWC_DEBUG_LEVEL_PROBE (1<<1) -#define PWC_DEBUG_LEVEL_OPEN (1<<2) -#define PWC_DEBUG_LEVEL_READ (1<<3) -#define PWC_DEBUG_LEVEL_MEMORY (1<<4) -#define PWC_DEBUG_LEVEL_FLOW (1<<5) -#define PWC_DEBUG_LEVEL_SIZE (1<<6) -#define PWC_DEBUG_LEVEL_IOCTL (1<<7) -#define PWC_DEBUG_LEVEL_TRACE (1<<8) - -#define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args) -#define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args) -#define PWC_DEBUG_OPEN(fmt, args...) PWC_DEBUG(OPEN, fmt, ##args) -#define PWC_DEBUG_READ(fmt, args...) PWC_DEBUG(READ, fmt, ##args) -#define PWC_DEBUG_MEMORY(fmt, args...) PWC_DEBUG(MEMORY, fmt, ##args) -#define PWC_DEBUG_FLOW(fmt, args...) PWC_DEBUG(FLOW, fmt, ##args) -#define PWC_DEBUG_SIZE(fmt, args...) PWC_DEBUG(SIZE, fmt, ##args) -#define PWC_DEBUG_IOCTL(fmt, args...) PWC_DEBUG(IOCTL, fmt, ##args) -#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args) - - -#ifdef CONFIG_USB_PWC_DEBUG - -#define PWC_DEBUG_LEVEL (PWC_DEBUG_LEVEL_MODULE) - -#define PWC_DEBUG(level, fmt, args...) do {\ - if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \ - printk(KERN_DEBUG PFX fmt, ##args); \ - } while(0) - -#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) -#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) -#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args) -#define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args) - -#else /* if ! CONFIG_USB_PWC_DEBUG */ - -#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) -#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) -#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args) -#define PWC_TRACE(fmt, args...) do { } while(0) -#define PWC_DEBUG(level, fmt, args...) do { } while(0) - -#define pwc_trace 0 - -#endif - -/* Defines for ToUCam cameras */ -#define TOUCAM_HEADER_SIZE 8 -#define TOUCAM_TRAILER_SIZE 4 - -#define FEATURE_MOTOR_PANTILT 0x0001 -#define FEATURE_CODEC1 0x0002 -#define FEATURE_CODEC2 0x0004 - -/* Turn certain features on/off */ -#define PWC_INT_PIPE 0 - -/* Ignore errors in the first N frames, to allow for startup delays */ -#define FRAME_LOWMARK 5 - -/* Size and number of buffers for the ISO pipe. */ -#define MAX_ISO_BUFS 2 -#define ISO_FRAMES_PER_DESC 10 -#define ISO_MAX_FRAME_SIZE 960 -#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) - -/* Frame buffers: contains compressed or uncompressed video data. */ -#define MAX_FRAMES 5 -/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ -#define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) - -/* Absolute maximum number of buffers available for mmap() */ -#define MAX_IMAGES 10 - -/* Some macros to quickly find the type of a webcam */ -#define DEVICE_USE_CODEC1(x) ((x)<675) -#define DEVICE_USE_CODEC2(x) ((x)>=675 && (x)<700) -#define DEVICE_USE_CODEC3(x) ((x)>=700) -#define DEVICE_USE_CODEC23(x) ((x)>=675) - -/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ -struct pwc_iso_buf -{ - void *data; - int length; - int read; - struct urb *urb; -}; - -/* intermediate buffers with raw data from the USB cam */ -struct pwc_frame_buf -{ - void *data; - volatile int filled; /* number of bytes filled */ - struct pwc_frame_buf *next; /* list */ -}; - -/* additionnal informations used when dealing image between kernel and userland */ -struct pwc_imgbuf -{ - unsigned long offset; /* offset of this buffer in the big array of image_data */ - int vma_use_count; /* count the number of time this memory is mapped */ -}; - -struct pwc_device -{ - struct video_device *vdev; - - /* Pointer to our usb_device */ - struct usb_device *udev; - - int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ - int release; /* release number */ - int features; /* feature bits */ - char serial[30]; /* serial number (string) */ - int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ - int usb_init; /* set when the cam has been initialized over USB */ - - /*** Video data ***/ - int vopen; /* flag */ - int vendpoint; /* video isoc endpoint */ - int vcinterface; /* video control interface */ - int valternate; /* alternate interface needed */ - int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ - int pixfmt; /* pixelformat: V4L2_PIX_FMT_YUV420 or raw: _PWC1, _PWC2 */ - int vframe_count; /* received frames */ - int vframes_dumped; /* counter for dumped frames */ - int vframes_error; /* frames received in error */ - int vmax_packet_size; /* USB maxpacket size */ - int vlast_packet_size; /* for frame synchronisation */ - int visoc_errors; /* number of contiguous ISOC errors */ - int vcompression; /* desired compression factor */ - int vbandlength; /* compressed band length; 0 is uncompressed */ - char vsnapshot; /* snapshot mode */ - char vsync; /* used by isoc handler */ - char vmirror; /* for ToUCaM series */ - char unplugged; - - int cmd_len; - unsigned char cmd_buf[13]; - - /* The image acquisition requires 3 to 4 steps: - 1. data is gathered in short packets from the USB controller - 2. data is synchronized and packed into a frame buffer - 3a. in case data is compressed, decompress it directly into image buffer - 3b. in case data is uncompressed, copy into image buffer with viewport - 4. data is transferred to the user process - - Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... - We have in effect a back-to-back-double-buffer system. - */ - /* 1: isoc */ - struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; - char iso_init; - - /* 2: frame */ - struct pwc_frame_buf *fbuf; /* all frames */ - struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ - struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ - struct pwc_frame_buf *fill_frame; /* frame currently being filled */ - struct pwc_frame_buf *read_frame; /* frame currently read by user process */ - int frame_header_size, frame_trailer_size; - int frame_size; - int frame_total_size; /* including header & trailer */ - int drop_frames; - - /* 3: decompression */ - void *decompress_data; /* private data for decompression engine */ - - /* 4: image */ - /* We have an 'image' and a 'view', where 'image' is the fixed-size image - as delivered by the camera, and 'view' is the size requested by the - program. The camera image is centered in this viewport, laced with - a gray or black border. view_min <= image <= view <= view_max; - */ - int image_mask; /* bitmask of supported sizes */ - struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ - struct pwc_coord abs_max; /* maximum supported size with compression */ - struct pwc_coord image, view; /* image and viewport size */ - struct pwc_coord offset; /* offset within the viewport */ - - void *image_data; /* total buffer, which is subdivided into ... */ - struct pwc_imgbuf images[MAX_IMAGES];/* ...several images... */ - int fill_image; /* ...which are rotated. */ - int len_per_image; /* length per image */ - int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ - int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ - - struct mutex modlock; /* to prevent races in video_open(), etc */ - spinlock_t ptrlock; /* for manipulating the buffer pointers */ - - /*** motorized pan/tilt feature */ - struct pwc_mpt_range angle_range; - int pan_angle; /* in degrees * 100 */ - int tilt_angle; /* absolute angle; 0,0 is home position */ - int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */ -#ifdef CONFIG_USB_PWC_INPUT_EVDEV - struct input_dev *button_dev; /* webcam snapshot button input */ - char button_phys[64]; -#endif - - /*** Misc. data ***/ - wait_queue_head_t frameq; /* When waiting for a frame to finish... */ -#if PWC_INT_PIPE - void *usb_int_handler; /* for the interrupt endpoint */ -#endif -}; - -#ifdef __cplusplus -extern "C" { -#endif - -/* Global variables */ -#ifdef CONFIG_USB_PWC_DEBUG -extern int pwc_trace; -#endif -extern int pwc_mbufs; - -/** functions in pwc-if.c */ -int pwc_handle_frame(struct pwc_device *pdev); -void pwc_next_image(struct pwc_device *pdev); -int pwc_isoc_init(struct pwc_device *pdev); -void pwc_isoc_cleanup(struct pwc_device *pdev); - -/** Functions in pwc-misc.c */ -/* sizes in pixels */ -extern const struct pwc_coord pwc_image_sizes[PSZ_MAX]; - -int pwc_decode_size(struct pwc_device *pdev, int width, int height); -void pwc_construct(struct pwc_device *pdev); - -/** Functions in pwc-ctrl.c */ -/* Request a certain video mode. Returns < 0 if not possible */ -extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); -extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); -/* Calculate the number of bytes per image (not frame) */ -extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); -extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); - -/* Various controls; should be obvious. Value 0..65535, or < 0 on error */ -extern int pwc_get_brightness(struct pwc_device *pdev); -extern int pwc_set_brightness(struct pwc_device *pdev, int value); -extern int pwc_get_contrast(struct pwc_device *pdev); -extern int pwc_set_contrast(struct pwc_device *pdev, int value); -extern int pwc_get_gamma(struct pwc_device *pdev); -extern int pwc_set_gamma(struct pwc_device *pdev, int value); -extern int pwc_get_saturation(struct pwc_device *pdev, int *value); -extern int pwc_set_saturation(struct pwc_device *pdev, int value); -extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); -extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); -extern int pwc_restore_user(struct pwc_device *pdev); -extern int pwc_save_user(struct pwc_device *pdev); -extern int pwc_restore_factory(struct pwc_device *pdev); - -/* exported for use by v4l2 controls */ -extern int pwc_get_red_gain(struct pwc_device *pdev, int *value); -extern int pwc_set_red_gain(struct pwc_device *pdev, int value); -extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value); -extern int pwc_set_blue_gain(struct pwc_device *pdev, int value); -extern int pwc_get_awb(struct pwc_device *pdev); -extern int pwc_set_awb(struct pwc_device *pdev, int mode); -extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value); -extern int pwc_get_agc(struct pwc_device *pdev, int *value); -extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value); -extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value); - -extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour); -extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour); -extern int pwc_set_contour(struct pwc_device *pdev, int contour); -extern int pwc_get_contour(struct pwc_device *pdev, int *contour); -extern int pwc_set_backlight(struct pwc_device *pdev, int backlight); -extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight); -extern int pwc_set_flicker(struct pwc_device *pdev, int flicker); -extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker); -extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise); -extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise); - -/* Power down or up the camera; not supported by all models */ -extern int pwc_camera_power(struct pwc_device *pdev, int power); - -/* Private ioctl()s; see pwc-ioctl.h */ -extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); - -extern const struct v4l2_ioctl_ops pwc_ioctl_ops; - -/** pwc-uncompress.c */ -/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ -extern int pwc_decompress(struct pwc_device *pdev); - -#ifdef __cplusplus -} -#endif - - -#endif -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-if.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-if.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-if.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-if.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2061 +0,0 @@ -/* Linux driver for Philips webcam - USB and Video4Linux interface part. - (C) 1999-2004 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 - -*/ - -/* - This code forms the interface between the USB layers and the Philips - specific stuff. Some adanved stuff of the driver falls under an - NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and - is thus not distributed in source form. The binary pwcx.o module - contains the code that falls under the NDA. - - In case you're wondering: 'pwc' stands for "Philips WebCam", but - I really didn't want to type 'philips_web_cam' every time (I'm lazy as - any Linux kernel hacker, but I don't like uncomprehensible abbreviations - without explanation). - - Oh yes, convention: to disctinguish between all the various pointers to - device-structures, I use these names for the pointer variables: - udev: struct usb_device * - vdev: struct video_device * - pdev: struct pwc_devive * -*/ - -/* Contributors: - - Alvarado: adding whitebalance code - - Alistar Moire: QuickCam 3000 Pro device/product ID - - Tony Hoyle: Creative Labs Webcam 5 device/product ID - - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged - - Jk Fang: Sotec Afina Eye ID - - Xavier Roche: QuickCam Pro 4000 ID - - Jens Knudsen: QuickCam Zoom ID - - J. Debert: QuickCam for Notebooks ID - - Pham Thanh Nam: webcam snapshot button as an event input device -*/ - -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_USB_PWC_INPUT_EVDEV -#include -#endif -#include -#include -#include /* simple_strtol() */ - -#include "pwc.h" -#include "pwc-kiara.h" -#include "pwc-timon.h" -#include "pwc-dec23.h" -#include "pwc-dec1.h" -#include "pwc-uncompress.h" - -/* Function prototypes and driver templates */ - -/* hotplug device table support */ -static const struct usb_device_id pwc_device_table [] = { - { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ - { USB_DEVICE(0x0471, 0x0303) }, - { USB_DEVICE(0x0471, 0x0304) }, - { USB_DEVICE(0x0471, 0x0307) }, - { USB_DEVICE(0x0471, 0x0308) }, - { USB_DEVICE(0x0471, 0x030C) }, - { USB_DEVICE(0x0471, 0x0310) }, - { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */ - { USB_DEVICE(0x0471, 0x0312) }, - { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ - { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */ - { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ - { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ - { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ - { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ - { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ - { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ - { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ - { USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */ - { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */ - { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ - { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */ - { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */ - { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */ - { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ - { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ - { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ - { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ - { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ - { USB_DEVICE(0x0d81, 0x1900) }, - { } -}; -MODULE_DEVICE_TABLE(usb, pwc_device_table); - -static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); -static void usb_pwc_disconnect(struct usb_interface *intf); - -static struct usb_driver pwc_driver = { - .name = "Philips webcam", /* name */ - .id_table = pwc_device_table, - .probe = usb_pwc_probe, /* probe() */ - .disconnect = usb_pwc_disconnect, /* disconnect() */ -}; - -#define MAX_DEV_HINTS 20 -#define MAX_ISOC_ERRORS 20 - -static int default_size = PSZ_QCIF; -static int default_fps = 10; -static int default_fbufs = 3; /* Default number of frame buffers */ - int pwc_mbufs = 2; /* Default number of mmap() buffers */ -#ifdef CONFIG_USB_PWC_DEBUG - int pwc_trace = PWC_DEBUG_LEVEL; -#endif -static int power_save; -static int led_on = 100, led_off; /* defaults to LED that is on while in use */ -static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */ -static struct { - int type; - char serial_number[30]; - int device_node; - struct pwc_device *pdev; -} device_hint[MAX_DEV_HINTS]; - -/***/ - -static int pwc_video_open(struct file *file); -static int pwc_video_close(struct file *file); -static ssize_t pwc_video_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos); -static unsigned int pwc_video_poll(struct file *file, poll_table *wait); -static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); - -static const struct v4l2_file_operations pwc_fops = { - .owner = THIS_MODULE, - .open = pwc_video_open, - .release = pwc_video_close, - .read = pwc_video_read, - .poll = pwc_video_poll, - .mmap = pwc_video_mmap, - .unlocked_ioctl = video_ioctl2, -}; -static struct video_device pwc_template = { - .name = "Philips Webcam", /* Filled in later */ - .release = video_device_release, - .fops = &pwc_fops, -}; - -/***************************************************************************/ - -/* Okay, this is some magic that I worked out and the reasoning behind it... - - The biggest problem with any USB device is of course: "what to do - when the user unplugs the device while it is in use by an application?" - We have several options: - 1) Curse them with the 7 plagues when they do (requires divine intervention) - 2) Tell them not to (won't work: they'll do it anyway) - 3) Oops the kernel (this will have a negative effect on a user's uptime) - 4) Do something sensible. - - Of course, we go for option 4. - - It happens that this device will be linked to two times, once from - usb_device and once from the video_device in their respective 'private' - pointers. This is done when the device is probed() and all initialization - succeeded. The pwc_device struct links back to both structures. - - When a device is unplugged while in use it will be removed from the - list of known USB devices; I also de-register it as a V4L device, but - unfortunately I can't free the memory since the struct is still in use - by the file descriptor. This free-ing is then deferend until the first - opportunity. Crude, but it works. - - A small 'advantage' is that if a user unplugs the cam and plugs it back - in, it should get assigned the same video device minor, but unfortunately - it's non-trivial to re-link the cam back to the video device... (that - would surely be magic! :)) -*/ - -/***************************************************************************/ -/* Private functions */ - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ - - - -static void *pwc_rvmalloc(unsigned long size) -{ - void * mem; - unsigned long adr; - - mem=vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - return mem; -} - -static void pwc_rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr=(unsigned long) mem; - while ((long) size > 0) - { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - - - - -static int pwc_allocate_buffers(struct pwc_device *pdev) -{ - int i, err; - void *kbuf; - - PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); - - if (pdev == NULL) - return -ENXIO; - - /* Allocate Isochronuous pipe buffers */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (pdev->sbuf[i].data == NULL) { - kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL); - if (kbuf == NULL) { - PWC_ERROR("Failed to allocate iso buffer %d.\n", i); - return -ENOMEM; - } - PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf); - pdev->sbuf[i].data = kbuf; - } - } - - /* Allocate frame buffer structure */ - if (pdev->fbuf == NULL) { - kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); - if (kbuf == NULL) { - PWC_ERROR("Failed to allocate frame buffer structure.\n"); - return -ENOMEM; - } - PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf); - pdev->fbuf = kbuf; - } - - /* create frame buffers, and make circular ring */ - for (i = 0; i < default_fbufs; i++) { - if (pdev->fbuf[i].data == NULL) { - kbuf = vzalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ - if (kbuf == NULL) { - PWC_ERROR("Failed to allocate frame buffer %d.\n", i); - return -ENOMEM; - } - PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf); - pdev->fbuf[i].data = kbuf; - } - } - - /* Allocate decompressor table space */ - if (DEVICE_USE_CODEC1(pdev->type)) - err = pwc_dec1_alloc(pdev); - else - err = pwc_dec23_alloc(pdev); - - if (err) { - PWC_ERROR("Failed to allocate decompress table.\n"); - return err; - } - - /* Allocate image buffer; double buffer for mmap() */ - kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image); - if (kbuf == NULL) { - PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n", - pwc_mbufs * pdev->len_per_image); - return -ENOMEM; - } - PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf); - pdev->image_data = kbuf; - for (i = 0; i < pwc_mbufs; i++) { - pdev->images[i].offset = i * pdev->len_per_image; - pdev->images[i].vma_use_count = 0; - } - for (; i < MAX_IMAGES; i++) { - pdev->images[i].offset = 0; - } - - kbuf = NULL; - - PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n"); - return 0; -} - -static void pwc_free_buffers(struct pwc_device *pdev) -{ - int i; - - PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev); - - if (pdev == NULL) - return; - /* Release Iso-pipe buffers */ - for (i = 0; i < MAX_ISO_BUFS; i++) - if (pdev->sbuf[i].data != NULL) { - PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); - kfree(pdev->sbuf[i].data); - pdev->sbuf[i].data = NULL; - } - - /* The same for frame buffers */ - if (pdev->fbuf != NULL) { - for (i = 0; i < default_fbufs; i++) { - if (pdev->fbuf[i].data != NULL) { - PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); - vfree(pdev->fbuf[i].data); - pdev->fbuf[i].data = NULL; - } - } - kfree(pdev->fbuf); - pdev->fbuf = NULL; - } - - /* Intermediate decompression buffer & tables */ - if (pdev->decompress_data != NULL) { - PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data); - kfree(pdev->decompress_data); - pdev->decompress_data = NULL; - } - - /* Release image buffers */ - if (pdev->image_data != NULL) { - PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data); - pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image); - } - pdev->image_data = NULL; - - PWC_DEBUG_MEMORY("Leaving free_buffers().\n"); -} - -/* The frame & image buffer mess. - - Yes, this is a mess. Well, it used to be simple, but alas... In this - module, 3 buffers schemes are used to get the data from the USB bus to - the user program. The first scheme involves the ISO buffers (called thus - since they transport ISO data from the USB controller), and not really - interesting. Suffices to say the data from this buffer is quickly - gathered in an interrupt handler (pwc_isoc_handler) and placed into the - frame buffer. - - The frame buffer is the second scheme, and is the central element here. - It collects the data from a single frame from the camera (hence, the - name). Frames are delimited by the USB camera with a short USB packet, - so that's easy to detect. The frame buffers form a list that is filled - by the camera+USB controller and drained by the user process through - either read() or mmap(). - - The image buffer is the third scheme, in which frames are decompressed - and converted into planar format. For mmap() there is more than - one image buffer available. - - The frame buffers provide the image buffering. In case the user process - is a bit slow, this introduces lag and some undesired side-effects. - The problem arises when the frame buffer is full. I used to drop the last - frame, which makes the data in the queue stale very quickly. But dropping - the frame at the head of the queue proved to be a litte bit more difficult. - I tried a circular linked scheme, but this introduced more problems than - it solved. - - Because filling and draining are completely asynchronous processes, this - requires some fiddling with pointers and mutexes. - - Eventually, I came up with a system with 2 lists: an 'empty' frame list - and a 'full' frame list: - * Initially, all frame buffers but one are on the 'empty' list; the one - remaining buffer is our initial fill frame. - * If a frame is needed for filling, we try to take it from the 'empty' - list, unless that list is empty, in which case we take the buffer at - the head of the 'full' list. - * When our fill buffer has been filled, it is appended to the 'full' - list. - * If a frame is needed by read() or mmap(), it is taken from the head of - the 'full' list, handled, and then appended to the 'empty' list. If no - buffer is present on the 'full' list, we wait. - The advantage is that the buffer that is currently being decompressed/ - converted, is on neither list, and thus not in our way (any other scheme - I tried had the problem of old data lingering in the queue). - - Whatever strategy you choose, it always remains a tradeoff: with more - frame buffers the chances of a missed frame are reduced. On the other - hand, on slower machines it introduces lag because the queue will - always be full. - */ - -/** - \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. - */ -static int pwc_next_fill_frame(struct pwc_device *pdev) -{ - int ret; - unsigned long flags; - - ret = 0; - spin_lock_irqsave(&pdev->ptrlock, flags); - if (pdev->fill_frame != NULL) { - /* append to 'full' list */ - if (pdev->full_frames == NULL) { - pdev->full_frames = pdev->fill_frame; - pdev->full_frames_tail = pdev->full_frames; - } - else { - pdev->full_frames_tail->next = pdev->fill_frame; - pdev->full_frames_tail = pdev->fill_frame; - } - } - if (pdev->empty_frames != NULL) { - /* We have empty frames available. That's easy */ - pdev->fill_frame = pdev->empty_frames; - pdev->empty_frames = pdev->empty_frames->next; - } - else { - /* Hmm. Take it from the full list */ - /* sanity check */ - if (pdev->full_frames == NULL) { - PWC_ERROR("Neither empty or full frames available!\n"); - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return -EINVAL; - } - pdev->fill_frame = pdev->full_frames; - pdev->full_frames = pdev->full_frames->next; - ret = 1; - } - pdev->fill_frame->next = NULL; - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return ret; -} - - -/** - \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. - - If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. - */ -static void pwc_reset_buffers(struct pwc_device *pdev) -{ - int i; - unsigned long flags; - - PWC_DEBUG_MEMORY(">> %s __enter__\n", __func__); - - spin_lock_irqsave(&pdev->ptrlock, flags); - pdev->full_frames = NULL; - pdev->full_frames_tail = NULL; - for (i = 0; i < default_fbufs; i++) { - pdev->fbuf[i].filled = 0; - if (i > 0) - pdev->fbuf[i].next = &pdev->fbuf[i - 1]; - else - pdev->fbuf->next = NULL; - } - pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; - pdev->empty_frames_tail = pdev->fbuf; - pdev->read_frame = NULL; - pdev->fill_frame = pdev->empty_frames; - pdev->empty_frames = pdev->empty_frames->next; - - pdev->image_read_pos = 0; - pdev->fill_image = 0; - spin_unlock_irqrestore(&pdev->ptrlock, flags); - - PWC_DEBUG_MEMORY("<< %s __leaving__\n", __func__); -} - - -/** - \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. - */ -int pwc_handle_frame(struct pwc_device *pdev) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&pdev->ptrlock, flags); - /* First grab our read_frame; this is removed from all lists, so - we can release the lock after this without problems */ - if (pdev->read_frame != NULL) { - /* This can't theoretically happen */ - PWC_ERROR("Huh? Read frame still in use?\n"); - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return ret; - } - - - if (pdev->full_frames == NULL) { - PWC_ERROR("Woops. No frames ready.\n"); - } - else { - pdev->read_frame = pdev->full_frames; - pdev->full_frames = pdev->full_frames->next; - pdev->read_frame->next = NULL; - } - - if (pdev->read_frame != NULL) { - /* Decompression is a lengthy process, so it's outside of the lock. - This gives the isoc_handler the opportunity to fill more frames - in the mean time. - */ - spin_unlock_irqrestore(&pdev->ptrlock, flags); - ret = pwc_decompress(pdev); - spin_lock_irqsave(&pdev->ptrlock, flags); - - /* We're done with read_buffer, tack it to the end of the empty buffer list */ - if (pdev->empty_frames == NULL) { - pdev->empty_frames = pdev->read_frame; - pdev->empty_frames_tail = pdev->empty_frames; - } - else { - pdev->empty_frames_tail->next = pdev->read_frame; - pdev->empty_frames_tail = pdev->read_frame; - } - pdev->read_frame = NULL; - } - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return ret; -} - -/** - \brief Advance pointers of image buffer (after each user request) -*/ -void pwc_next_image(struct pwc_device *pdev) -{ - pdev->image_used[pdev->fill_image] = 0; - pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs; -} - -/** - * Print debug information when a frame is discarded because all of our buffer - * is full - */ -static void pwc_frame_dumped(struct pwc_device *pdev) -{ - pdev->vframes_dumped++; - if (pdev->vframe_count < FRAME_LOWMARK) - return; - - if (pdev->vframes_dumped < 20) - PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count); - else if (pdev->vframes_dumped == 20) - PWC_DEBUG_FLOW("Dumping frame %d (last message)\n", - pdev->vframe_count); -} - -static void pwc_snapshot_button(struct pwc_device *pdev, int down) -{ - if (down) { - PWC_TRACE("Snapshot button pressed.\n"); - pdev->snapshot_button_status = 1; - } else { - PWC_TRACE("Snapshot button released.\n"); - } - -#ifdef CONFIG_USB_PWC_INPUT_EVDEV - if (pdev->button_dev) { - input_report_key(pdev->button_dev, KEY_CAMERA, down); - input_sync(pdev->button_dev); - } -#endif -} - -static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf) -{ - int awake = 0; - - /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus - frames on the USB wire after an exposure change. This conditition is - however detected in the cam and a bit is set in the header. - */ - if (pdev->type == 730) { - unsigned char *ptr = (unsigned char *)fbuf->data; - - if (ptr[1] == 1 && ptr[0] & 0x10) { - PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n"); - pdev->drop_frames += 2; - pdev->vframes_error++; - } - if ((ptr[0] ^ pdev->vmirror) & 0x01) { - pwc_snapshot_button(pdev, ptr[0] & 0x01); - } - if ((ptr[0] ^ pdev->vmirror) & 0x02) { - if (ptr[0] & 0x02) - PWC_TRACE("Image is mirrored.\n"); - else - PWC_TRACE("Image is normal.\n"); - } - pdev->vmirror = ptr[0] & 0x03; - /* Sometimes the trailer of the 730 is still sent as a 4 byte packet - after a short frame; this condition is filtered out specifically. A 4 byte - frame doesn't make sense anyway. - So we get either this sequence: - drop_bit set -> 4 byte frame -> short frame -> good frame - Or this one: - drop_bit set -> short frame -> good frame - So we drop either 3 or 2 frames in all! - */ - if (fbuf->filled == 4) - pdev->drop_frames++; - } - else if (pdev->type == 740 || pdev->type == 720) { - unsigned char *ptr = (unsigned char *)fbuf->data; - if ((ptr[0] ^ pdev->vmirror) & 0x01) { - pwc_snapshot_button(pdev, ptr[0] & 0x01); - } - pdev->vmirror = ptr[0] & 0x03; - } - - /* In case we were instructed to drop the frame, do so silently. - The buffer pointers are not updated either (but the counters are reset below). - */ - if (pdev->drop_frames > 0) - pdev->drop_frames--; - else { - /* Check for underflow first */ - if (fbuf->filled < pdev->frame_total_size) { - PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);" - " discarded.\n", fbuf->filled); - pdev->vframes_error++; - } - else { - /* Send only once per EOF */ - awake = 1; /* delay wake_ups */ - - /* Find our next frame to fill. This will always succeed, since we - * nick a frame from either empty or full list, but if we had to - * take it from the full list, it means a frame got dropped. - */ - if (pwc_next_fill_frame(pdev)) - pwc_frame_dumped(pdev); - - } - } /* !drop_frames */ - pdev->vframe_count++; - return awake; -} - -/* This gets called for the Isochronous pipe (video). This is done in - * interrupt time, so it has to be fast, not crash, and not stall. Neat. - */ -static void pwc_isoc_handler(struct urb *urb) -{ - struct pwc_device *pdev; - int i, fst, flen; - int awake; - struct pwc_frame_buf *fbuf; - unsigned char *fillptr = NULL, *iso_buf = NULL; - - awake = 0; - pdev = (struct pwc_device *)urb->context; - if (pdev == NULL) { - PWC_ERROR("isoc_handler() called with NULL device?!\n"); - return; - } - - if (urb->status == -ENOENT || urb->status == -ECONNRESET) { - PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); - return; - } - if (urb->status != -EINPROGRESS && urb->status != 0) { - const char *errmsg; - - errmsg = "Unknown"; - switch(urb->status) { - case -ENOSR: errmsg = "Buffer error (overrun)"; break; - case -EPIPE: errmsg = "Stalled (device not responding)"; break; - case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; - case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; - case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; - case -ETIME: errmsg = "Device does not respond"; break; - } - PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); - /* Give up after a number of contiguous errors on the USB bus. - Appearantly something is wrong so we simulate an unplug event. - */ - if (++pdev->visoc_errors > MAX_ISOC_ERRORS) - { - PWC_INFO("Too many ISOC errors, bailing out.\n"); - pdev->error_status = EIO; - awake = 1; - wake_up_interruptible(&pdev->frameq); - } - goto handler_end; // ugly, but practical - } - - fbuf = pdev->fill_frame; - if (fbuf == NULL) { - PWC_ERROR("pwc_isoc_handler without valid fill frame.\n"); - awake = 1; - goto handler_end; - } - else { - fillptr = fbuf->data + fbuf->filled; - } - - /* Reset ISOC error counter. We did get here, after all. */ - pdev->visoc_errors = 0; - - /* vsync: 0 = don't copy data - 1 = sync-hunt - 2 = synched - */ - /* Compact data */ - for (i = 0; i < urb->number_of_packets; i++) { - fst = urb->iso_frame_desc[i].status; - flen = urb->iso_frame_desc[i].actual_length; - iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - if (fst == 0) { - if (flen > 0) { /* if valid data... */ - if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ - pdev->vsync = 2; - - /* ...copy data to frame buffer, if possible */ - if (flen + fbuf->filled > pdev->frame_total_size) { - PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); - pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ - pdev->vframes_error++; - } - else { - memmove(fillptr, iso_buf, flen); - fillptr += flen; - } - } - fbuf->filled += flen; - } /* ..flen > 0 */ - - if (flen < pdev->vlast_packet_size) { - /* Shorter packet... We probably have the end of an image-frame; - wake up read() process and let select()/poll() do something. - Decompression is done in user time over there. - */ - if (pdev->vsync == 2) { - if (pwc_rcv_short_packet(pdev, fbuf)) { - awake = 1; - fbuf = pdev->fill_frame; - } - } - fbuf->filled = 0; - fillptr = fbuf->data; - pdev->vsync = 1; - } - - pdev->vlast_packet_size = flen; - } /* ..status == 0 */ - else { - /* This is normally not interesting to the user, unless - * you are really debugging something, default = 0 */ - static int iso_error; - iso_error++; - if (iso_error < 20) - PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst); - } - } - -handler_end: - if (awake) - wake_up_interruptible(&pdev->frameq); - - urb->dev = pdev->udev; - i = usb_submit_urb(urb, GFP_ATOMIC); - if (i != 0) - PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); -} - - -int pwc_isoc_init(struct pwc_device *pdev) -{ - struct usb_device *udev; - struct urb *urb; - int i, j, ret; - - struct usb_interface *intf; - struct usb_host_interface *idesc = NULL; - - if (pdev == NULL) - return -EFAULT; - if (pdev->iso_init) - return 0; - pdev->vsync = 0; - udev = pdev->udev; - - /* Get the current alternate interface, adjust packet size */ - if (!udev->actconfig) - return -EFAULT; - intf = usb_ifnum_to_if(udev, 0); - if (intf) - idesc = usb_altnum_to_altsetting(intf, pdev->valternate); - - if (!idesc) - return -EFAULT; - - /* Search video endpoint */ - pdev->vmax_packet_size = -1; - for (i = 0; i < idesc->desc.bNumEndpoints; i++) { - if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { - pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize); - break; - } - } - - if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { - PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n"); - return -ENFILE; /* Odd error, that should be noticeable */ - } - - /* Set alternate interface */ - ret = 0; - PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate); - ret = usb_set_interface(pdev->udev, 0, pdev->valternate); - if (ret < 0) - return ret; - - for (i = 0; i < MAX_ISO_BUFS; i++) { - urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); - if (urb == NULL) { - PWC_ERROR("Failed to allocate urb %d\n", i); - ret = -ENOMEM; - break; - } - pdev->sbuf[i].urb = urb; - PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb); - } - if (ret) { - /* De-allocate in reverse order */ - while (i--) { - usb_free_urb(pdev->sbuf[i].urb); - pdev->sbuf[i].urb = NULL; - } - return ret; - } - - /* init URB structure */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - urb = pdev->sbuf[i].urb; - - urb->interval = 1; // devik - urb->dev = udev; - urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = pdev->sbuf[i].data; - urb->transfer_buffer_length = ISO_BUFFER_SIZE; - urb->complete = pwc_isoc_handler; - urb->context = pdev; - urb->start_frame = 0; - urb->number_of_packets = ISO_FRAMES_PER_DESC; - for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { - urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; - urb->iso_frame_desc[j].length = pdev->vmax_packet_size; - } - } - - /* link */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); - if (ret) { - PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret); - pdev->iso_init = 1; - pwc_isoc_cleanup(pdev); - return ret; - } - PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb); - } - - /* All is done... */ - pdev->iso_init = 1; - PWC_DEBUG_OPEN("<< pwc_isoc_init()\n"); - return 0; -} - -static void pwc_iso_stop(struct pwc_device *pdev) -{ - int i; - - /* Unlinking ISOC buffers one by one */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - struct urb *urb; - - urb = pdev->sbuf[i].urb; - if (urb) { - PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); - usb_kill_urb(urb); - } - } -} - -static void pwc_iso_free(struct pwc_device *pdev) -{ - int i; - - /* Freeing ISOC buffers one by one */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - struct urb *urb; - - urb = pdev->sbuf[i].urb; - if (urb) { - PWC_DEBUG_MEMORY("Freeing URB\n"); - usb_free_urb(urb); - pdev->sbuf[i].urb = NULL; - } - } -} - -void pwc_isoc_cleanup(struct pwc_device *pdev) -{ - PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); - if (pdev == NULL) - return; - if (pdev->iso_init == 0) - return; - - pwc_iso_stop(pdev); - pwc_iso_free(pdev); - - /* Stop camera, but only if we are sure the camera is still there (unplug - is signalled by EPIPE) - */ - if (pdev->error_status != EPIPE) { - PWC_DEBUG_OPEN("Setting alternate interface 0.\n"); - usb_set_interface(pdev->udev, 0, 0); - } - - pdev->iso_init = 0; - PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n"); -} - -/********* - * sysfs - *********/ -static struct pwc_device *cd_to_pwc(struct device *cd) -{ - struct video_device *vdev = to_video_device(cd); - return video_get_drvdata(vdev); -} - -static ssize_t show_pan_tilt(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle); -} - -static ssize_t store_pan_tilt(struct device *class_dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - int pan, tilt; - int ret = -EINVAL; - - if (strncmp(buf, "reset", 5) == 0) - ret = pwc_mpt_reset(pdev, 0x3); - - else if (sscanf(buf, "%d %d", &pan, &tilt) > 0) - ret = pwc_mpt_set_angle(pdev, pan, tilt); - - if (ret < 0) - return ret; - return strlen(buf); -} -static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, - store_pan_tilt); - -static ssize_t show_snapshot_button_status(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - int status = pdev->snapshot_button_status; - pdev->snapshot_button_status = 0; - return sprintf(buf, "%d\n", status); -} - -static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, - NULL); - -static int pwc_create_sysfs_files(struct video_device *vdev) -{ - struct pwc_device *pdev = video_get_drvdata(vdev); - int rc; - - rc = device_create_file(&vdev->dev, &dev_attr_button); - if (rc) - goto err; - if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt); - if (rc) - goto err_button; - } - - return 0; - -err_button: - device_remove_file(&vdev->dev, &dev_attr_button); -err: - PWC_ERROR("Could not create sysfs files.\n"); - return rc; -} - -static void pwc_remove_sysfs_files(struct video_device *vdev) -{ - struct pwc_device *pdev = video_get_drvdata(vdev); - - if (pdev->features & FEATURE_MOTOR_PANTILT) - device_remove_file(&vdev->dev, &dev_attr_pan_tilt); - device_remove_file(&vdev->dev, &dev_attr_button); -} - -#ifdef CONFIG_USB_PWC_DEBUG -static const char *pwc_sensor_type_to_string(unsigned int sensor_type) -{ - switch(sensor_type) { - case 0x00: - return "Hyundai CMOS sensor"; - case 0x20: - return "Sony CCD sensor + TDA8787"; - case 0x2E: - return "Sony CCD sensor + Exas 98L59"; - case 0x2F: - return "Sony CCD sensor + ADI 9804"; - case 0x30: - return "Sharp CCD sensor + TDA8787"; - case 0x3E: - return "Sharp CCD sensor + Exas 98L59"; - case 0x3F: - return "Sharp CCD sensor + ADI 9804"; - case 0x40: - return "UPA 1021 sensor"; - case 0x100: - return "VGA sensor"; - case 0x101: - return "PAL MR sensor"; - default: - return "unknown type of sensor"; - } -} -#endif - -/***************************************************************************/ -/* Video4Linux functions */ - -static int pwc_video_open(struct file *file) -{ - int i, ret; - struct video_device *vdev = video_devdata(file); - struct pwc_device *pdev; - - PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev); - - pdev = video_get_drvdata(vdev); - BUG_ON(!pdev); - if (pdev->vopen) { - PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n"); - return -EBUSY; - } - - pwc_construct(pdev); /* set min/max sizes correct */ - if (!pdev->usb_init) { - PWC_DEBUG_OPEN("Doing first time initialization.\n"); - pdev->usb_init = 1; - - /* Query sensor type */ - ret = pwc_get_cmos_sensor(pdev, &i); - if (ret >= 0) - { - PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n", - pdev->vdev->name, - pwc_sensor_type_to_string(i), i); - } - } - - /* Turn on camera */ - if (power_save) { - i = pwc_camera_power(pdev, 1); - if (i < 0) - PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i); - } - /* Set LED on/off time */ - if (pwc_set_leds(pdev, led_on, led_off) < 0) - PWC_DEBUG_OPEN("Failed to set LED on/off time.\n"); - - - /* So far, so good. Allocate memory. */ - i = pwc_allocate_buffers(pdev); - if (i < 0) { - PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n"); - pwc_free_buffers(pdev); - return i; - } - - /* Reset buffers & parameters */ - pwc_reset_buffers(pdev); - for (i = 0; i < pwc_mbufs; i++) - pdev->image_used[i] = 0; - pdev->vframe_count = 0; - pdev->vframes_dumped = 0; - pdev->vframes_error = 0; - pdev->visoc_errors = 0; - pdev->error_status = 0; - pwc_construct(pdev); /* set min/max sizes correct */ - - /* Set some defaults */ - pdev->vsnapshot = 0; - - /* Set video size, first try the last used video size - (or the default one); if that fails try QCIF/10 or QSIF/10; - it that fails too, give up. - */ - i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); - if (i) { - unsigned int default_resolution; - PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n"); - if (pdev->type>= 730) - default_resolution = PSZ_QSIF; - else - default_resolution = PSZ_QCIF; - - i = pwc_set_video_mode(pdev, - pwc_image_sizes[default_resolution].x, - pwc_image_sizes[default_resolution].y, - 10, - pdev->vcompression, - 0); - } - if (i) { - PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n"); - pwc_free_buffers(pdev); - return i; - } - - /* Initialize the webcam to sane value */ - pwc_set_brightness(pdev, 0x7fff); - pwc_set_agc(pdev, 1, 0); - - pdev->vopen++; - file->private_data = vdev; - PWC_DEBUG_OPEN("<< video_open() returns 0.\n"); - return 0; -} - - -static void pwc_cleanup(struct pwc_device *pdev) -{ - pwc_remove_sysfs_files(pdev->vdev); - video_unregister_device(pdev->vdev); - -#ifdef CONFIG_USB_PWC_INPUT_EVDEV - if (pdev->button_dev) - input_unregister_device(pdev->button_dev); -#endif - - kfree(pdev); -} - -/* Note that all cleanup is done in the reverse order as in _open */ -static int pwc_video_close(struct file *file) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - int i, hint; - - PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); - - pdev = video_get_drvdata(vdev); - if (pdev->vopen == 0) - PWC_DEBUG_MODULE("video_close() called on closed device?\n"); - - /* Dump statistics, but only if a reasonable amount of frames were - processed (to prevent endless log-entries in case of snap-shot - programs) - */ - if (pdev->vframe_count > 20) - PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); - - if (DEVICE_USE_CODEC1(pdev->type)) - pwc_dec1_exit(); - else - pwc_dec23_exit(); - - pwc_isoc_cleanup(pdev); - pwc_free_buffers(pdev); - - /* Turn off LEDS and power down camera, but only when not unplugged */ - if (!pdev->unplugged) { - /* Turn LEDs off */ - if (pwc_set_leds(pdev, 0, 0) < 0) - PWC_DEBUG_MODULE("Failed to set LED on/off time.\n"); - if (power_save) { - i = pwc_camera_power(pdev, 0); - if (i < 0) - PWC_ERROR("Failed to power down camera (%d)\n", i); - } - pdev->vopen--; - PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen); - } else { - pwc_cleanup(pdev); - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; - } - - return 0; -} - -/* - * FIXME: what about two parallel reads ???? - * ANSWER: Not supported. You can't open the device more than once, - despite what the V4L1 interface says. First, I don't see - the need, second there's no mechanism of alerting the - 2nd/3rd/... process of events like changing image size. - And I don't see the point of blocking that for the - 2nd/3rd/... process. - In multi-threaded environments reading parallel from any - device is tricky anyhow. - */ - -static ssize_t pwc_video_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - int noblock = file->f_flags & O_NONBLOCK; - DECLARE_WAITQUEUE(wait, current); - int bytes_to_read, rv = 0; - void *image_buffer_addr; - - PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n", - vdev, buf, count); - if (vdev == NULL) - return -EFAULT; - pdev = video_get_drvdata(vdev); - if (pdev == NULL) - return -EFAULT; - - if (pdev->error_status) { - rv = -pdev->error_status; /* Something happened, report what. */ - goto err_out; - } - - /* Start the stream (if not already started) */ - rv = pwc_isoc_init(pdev); - if (rv) - goto err_out; - - /* In case we're doing partial reads, we don't have to wait for a frame */ - if (pdev->image_read_pos == 0) { - /* Do wait queueing according to the (doc)book */ - add_wait_queue(&pdev->frameq, &wait); - while (pdev->full_frames == NULL) { - /* Check for unplugged/etc. here */ - if (pdev->error_status) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - rv = -pdev->error_status ; - goto err_out; - } - if (noblock) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - rv = -EWOULDBLOCK; - goto err_out; - } - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - rv = -ERESTARTSYS; - goto err_out; - } - mutex_unlock(&pdev->modlock); - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - mutex_lock(&pdev->modlock); - } - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - - /* Decompress and release frame */ - if (pwc_handle_frame(pdev)) { - rv = -EFAULT; - goto err_out; - } - } - - PWC_DEBUG_READ("Copying data to user space.\n"); - if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) - bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame); - else - bytes_to_read = pdev->view.size; - - /* copy bytes to user space; we allow for partial reads */ - if (count + pdev->image_read_pos > bytes_to_read) - count = bytes_to_read - pdev->image_read_pos; - image_buffer_addr = pdev->image_data; - image_buffer_addr += pdev->images[pdev->fill_image].offset; - image_buffer_addr += pdev->image_read_pos; - if (copy_to_user(buf, image_buffer_addr, count)) { - rv = -EFAULT; - goto err_out; - } - pdev->image_read_pos += count; - if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ - pdev->image_read_pos = 0; - pwc_next_image(pdev); - } - return count; -err_out: - return rv; -} - -static unsigned int pwc_video_poll(struct file *file, poll_table *wait) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - int ret; - - if (vdev == NULL) - return -EFAULT; - pdev = video_get_drvdata(vdev); - if (pdev == NULL) - return -EFAULT; - - /* Start the stream (if not already started) */ - ret = pwc_isoc_init(pdev); - if (ret) - return ret; - - poll_wait(file, &pdev->frameq, wait); - if (pdev->error_status) - return POLLERR; - if (pdev->full_frames != NULL) /* we have frames waiting */ - return (POLLIN | POLLRDNORM); - - return 0; -} - -static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - unsigned long start; - unsigned long size; - unsigned long page, pos = 0; - int index; - - PWC_DEBUG_MEMORY(">> %s\n", __func__); - pdev = video_get_drvdata(vdev); - size = vma->vm_end - vma->vm_start; - start = vma->vm_start; - - /* Find the idx buffer for this mapping */ - for (index = 0; index < pwc_mbufs; index++) { - pos = pdev->images[index].offset; - if ((pos>>PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (index == MAX_IMAGES) - return -EINVAL; - if (index == 0) { - /* - * Special case for v4l1. In v4l1, we map only one big buffer, - * but in v4l2 each buffer is mapped - */ - unsigned long total_size; - total_size = pwc_mbufs * pdev->len_per_image; - if (size != pdev->len_per_image && size != total_size) { - PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n", - size, pdev->len_per_image, total_size); - return -EINVAL; - } - } else if (size > pdev->len_per_image) - return -EINVAL; - - vma->vm_flags |= VM_IO; /* from 2.6.9-acX */ - - pos += (unsigned long)pdev->image_data; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - return 0; -} - -/***************************************************************************/ -/* USB functions */ - -/* This function gets called when a new device is plugged in or the usb core - * is loaded. - */ - -static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct pwc_device *pdev = NULL; - int vendor_id, product_id, type_id; - int hint, rc; - int features = 0; - int video_nr = -1; /* default: use next available device */ - char serial_number[30], *name; - - vendor_id = le16_to_cpu(udev->descriptor.idVendor); - product_id = le16_to_cpu(udev->descriptor.idProduct); - - /* Check if we can handle this device */ - PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n", - vendor_id, product_id, - intf->altsetting->desc.bInterfaceNumber); - - /* the interfaces are probed one by one. We are only interested in the - video interface (0) now. - Interface 1 is the Audio Control, and interface 2 Audio itself. - */ - if (intf->altsetting->desc.bInterfaceNumber > 0) - return -ENODEV; - - if (vendor_id == 0x0471) { - switch (product_id) { - case 0x0302: - PWC_INFO("Philips PCA645VC USB webcam detected.\n"); - name = "Philips 645 webcam"; - type_id = 645; - break; - case 0x0303: - PWC_INFO("Philips PCA646VC USB webcam detected.\n"); - name = "Philips 646 webcam"; - type_id = 646; - break; - case 0x0304: - PWC_INFO("Askey VC010 type 2 USB webcam detected.\n"); - name = "Askey VC010 webcam"; - type_id = 646; - break; - case 0x0307: - PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n"); - name = "Philips 675 webcam"; - type_id = 675; - break; - case 0x0308: - PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); - name = "Philips 680 webcam"; - type_id = 680; - break; - case 0x030C: - PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); - name = "Philips 690 webcam"; - type_id = 690; - break; - case 0x0310: - PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); - name = "Philips 730 webcam"; - type_id = 730; - break; - case 0x0311: - PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); - name = "Philips 740 webcam"; - type_id = 740; - break; - case 0x0312: - PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); - name = "Philips 750 webcam"; - type_id = 750; - break; - case 0x0313: - PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); - name = "Philips 720K/40 webcam"; - type_id = 720; - break; - case 0x0329: - PWC_INFO("Philips SPC 900NC USB webcam detected.\n"); - name = "Philips SPC 900NC webcam"; - type_id = 740; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x069A) { - switch(product_id) { - case 0x0001: - PWC_INFO("Askey VC010 type 1 USB webcam detected.\n"); - name = "Askey VC010 webcam"; - type_id = 645; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x046d) { - switch(product_id) { - case 0x08b0: - PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n"); - name = "Logitech QuickCam Pro 3000"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b1: - PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n"); - name = "Logitech QuickCam Notebook Pro"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b2: - PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n"); - name = "Logitech QuickCam Pro 4000"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b3: - PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n"); - name = "Logitech QuickCam Zoom"; - type_id = 740; /* CCD sensor */ - break; - case 0x08B4: - PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); - name = "Logitech QuickCam Zoom"; - type_id = 740; /* CCD sensor */ - power_save = 1; - break; - case 0x08b5: - PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); - name = "Logitech QuickCam Orbit"; - type_id = 740; /* CCD sensor */ - features |= FEATURE_MOTOR_PANTILT; - break; - case 0x08b6: - PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n"); - name = "Cisco VT Camera"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b7: - PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n"); - name = "Logitech ViewPort AV 100"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b8: /* Where this released? */ - PWC_INFO("Logitech QuickCam detected (reserved ID).\n"); - name = "Logitech QuickCam (res.)"; - type_id = 730; /* Assuming CMOS */ - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x055d) { - /* I don't know the difference between the C10 and the C30; - I suppose the difference is the sensor, but both cameras - work equally well with a type_id of 675 - */ - switch(product_id) { - case 0x9000: - PWC_INFO("Samsung MPC-C10 USB webcam detected.\n"); - name = "Samsung MPC-C10"; - type_id = 675; - break; - case 0x9001: - PWC_INFO("Samsung MPC-C30 USB webcam detected.\n"); - name = "Samsung MPC-C30"; - type_id = 675; - break; - case 0x9002: - PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n"); - name = "Samsung MPC-C30"; - type_id = 740; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x041e) { - switch(product_id) { - case 0x400c: - PWC_INFO("Creative Labs Webcam 5 detected.\n"); - name = "Creative Labs Webcam 5"; - type_id = 730; - break; - case 0x4011: - PWC_INFO("Creative Labs Webcam Pro Ex detected.\n"); - name = "Creative Labs Webcam Pro Ex"; - type_id = 740; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x04cc) { - switch(product_id) { - case 0x8116: - PWC_INFO("Sotec Afina Eye USB webcam detected.\n"); - name = "Sotec Afina Eye"; - type_id = 730; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x06be) { - switch(product_id) { - case 0x8116: - /* This is essentially the same cam as the Sotec Afina Eye */ - PWC_INFO("AME Co. Afina Eye USB webcam detected.\n"); - name = "AME Co. Afina Eye"; - type_id = 750; - break; - default: - return -ENODEV; - break; - } - - } - else if (vendor_id == 0x0d81) { - switch(product_id) { - case 0x1900: - PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n"); - name = "Visionite VCS-UC300"; - type_id = 740; /* CCD sensor */ - break; - case 0x1910: - PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n"); - name = "Visionite VCS-UM100"; - type_id = 730; /* CMOS sensor */ - break; - default: - return -ENODEV; - break; - } - } - else - return -ENODEV; /* Not any of the know types; but the list keeps growing. */ - - memset(serial_number, 0, 30); - usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); - PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number); - - if (udev->descriptor.bNumConfigurations > 1) - PWC_WARNING("Warning: more than 1 configuration available.\n"); - - /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ - pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL); - if (pdev == NULL) { - PWC_ERROR("Oops, could not allocate memory for pwc_device.\n"); - return -ENOMEM; - } - pdev->type = type_id; - pdev->vsize = default_size; - pdev->vframes = default_fps; - strcpy(pdev->serial, serial_number); - pdev->features = features; - if (vendor_id == 0x046D && product_id == 0x08B5) { - /* Logitech QuickCam Orbit - The ranges have been determined experimentally; they may differ from cam to cam. - Also, the exact ranges left-right and up-down are different for my cam - */ - pdev->angle_range.pan_min = -7000; - pdev->angle_range.pan_max = 7000; - pdev->angle_range.tilt_min = -3000; - pdev->angle_range.tilt_max = 2500; - } - - mutex_init(&pdev->modlock); - spin_lock_init(&pdev->ptrlock); - - pdev->udev = udev; - init_waitqueue_head(&pdev->frameq); - pdev->vcompression = pwc_preferred_compression; - - /* Allocate video_device structure */ - pdev->vdev = video_device_alloc(); - if (!pdev->vdev) { - PWC_ERROR("Err, cannot allocate video_device struture. Failing probe."); - rc = -ENOMEM; - goto err_free_mem; - } - memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); - pdev->vdev->parent = &intf->dev; - pdev->vdev->lock = &pdev->modlock; - pdev->vdev->ioctl_ops = &pwc_ioctl_ops; - strcpy(pdev->vdev->name, name); - video_set_drvdata(pdev->vdev, pdev); - - pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); - PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); - - /* Now search device_hint[] table for a match, so we can hint a node number. */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) { - if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && - (device_hint[hint].pdev == NULL)) { - /* so far, so good... try serial number */ - if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { - /* match! */ - video_nr = device_hint[hint].device_node; - PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr); - break; - } - } - } - - pdev->vdev->release = video_device_release; - - /* occupy slot */ - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = pdev; - - PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); - usb_set_intfdata(intf, pdev); - - /* Set the leds off */ - pwc_set_leds(pdev, 0, 0); - pwc_camera_power(pdev, 0); - - rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); - if (rc < 0) { - PWC_ERROR("Failed to register as video device (%d).\n", rc); - goto err_video_release; - } - rc = pwc_create_sysfs_files(pdev->vdev); - if (rc) - goto err_video_unreg; - - PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev)); - -#ifdef CONFIG_USB_PWC_INPUT_EVDEV - /* register webcam snapshot button input device */ - pdev->button_dev = input_allocate_device(); - if (!pdev->button_dev) { - PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); - rc = -ENOMEM; - pwc_remove_sysfs_files(pdev->vdev); - goto err_video_unreg; - } - - usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys)); - strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys)); - - pdev->button_dev->name = "PWC snapshot button"; - pdev->button_dev->phys = pdev->button_phys; - usb_to_input_id(pdev->udev, &pdev->button_dev->id); - pdev->button_dev->dev.parent = &pdev->udev->dev; - pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY); - pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA); - - rc = input_register_device(pdev->button_dev); - if (rc) { - input_free_device(pdev->button_dev); - pdev->button_dev = NULL; - pwc_remove_sysfs_files(pdev->vdev); - goto err_video_unreg; - } -#endif - - return 0; - -err_video_unreg: - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = NULL; - video_unregister_device(pdev->vdev); - pdev->vdev = NULL; /* So we don't try to release it below */ -err_video_release: - video_device_release(pdev->vdev); -err_free_mem: - kfree(pdev); - return rc; -} - -/* The user yanked out the cable... */ -static void usb_pwc_disconnect(struct usb_interface *intf) -{ - struct pwc_device *pdev; - int hint; - - pdev = usb_get_intfdata (intf); - mutex_lock(&pdev->modlock); - usb_set_intfdata (intf, NULL); - if (pdev == NULL) { - PWC_ERROR("pwc_disconnect() Called without private pointer.\n"); - goto disconnect_out; - } - if (pdev->udev == NULL) { - PWC_ERROR("pwc_disconnect() already called for %p\n", pdev); - goto disconnect_out; - } - if (pdev->udev != interface_to_usbdev(intf)) { - PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); - goto disconnect_out; - } - - /* We got unplugged; this is signalled by an EPIPE error code */ - if (pdev->vopen) { - PWC_INFO("Disconnected while webcam is in use!\n"); - pdev->error_status = EPIPE; - } - - /* Alert waiting processes */ - wake_up_interruptible(&pdev->frameq); - /* Wait until device is closed */ - if (pdev->vopen) { - pdev->unplugged = 1; - pwc_iso_stop(pdev); - } else { - /* Device is closed, so we can safely unregister it */ - PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); - pwc_cleanup(pdev); - -disconnect_out: - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; - } - - mutex_unlock(&pdev->modlock); -} - - -/* - * Initialization code & module stuff - */ - -static char *size; -static int fps; -static int fbufs; -static int mbufs; -static int compression = -1; -static int leds[2] = { -1, -1 }; -static unsigned int leds_nargs; -static char *dev_hint[MAX_DEV_HINTS]; -static unsigned int dev_hint_nargs; - -module_param(size, charp, 0444); -module_param(fps, int, 0444); -module_param(fbufs, int, 0444); -module_param(mbufs, int, 0444); -#ifdef CONFIG_USB_PWC_DEBUG -module_param_named(trace, pwc_trace, int, 0644); -#endif -module_param(power_save, int, 0444); -module_param(compression, int, 0444); -module_param_array(leds, int, &leds_nargs, 0444); -module_param_array(dev_hint, charp, &dev_hint_nargs, 0444); - -MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); -MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); -MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); -MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); -#ifdef CONFIG_USB_PWC_DEBUG -MODULE_PARM_DESC(trace, "For debugging purposes"); -#endif -MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); -MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); -MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); -MODULE_PARM_DESC(dev_hint, "Device node hints"); - -MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); -MODULE_AUTHOR("Luc Saillard "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("pwcx"); - -static int __init usb_pwc_init(void) -{ - int i, sz; - char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; - - PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n"); - PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); - PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); - PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); - - if (fps) { - if (fps < 4 || fps > 30) { - PWC_ERROR("Framerate out of bounds (4-30).\n"); - return -EINVAL; - } - default_fps = fps; - PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps); - } - - if (size) { - /* string; try matching with array */ - for (sz = 0; sz < PSZ_MAX; sz++) { - if (!strcmp(sizenames[sz], size)) { /* Found! */ - default_size = sz; - break; - } - } - if (sz == PSZ_MAX) { - PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); - return -EINVAL; - } - PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); - } - if (mbufs) { - if (mbufs < 1 || mbufs > MAX_IMAGES) { - PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); - return -EINVAL; - } - pwc_mbufs = mbufs; - PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs); - } - if (fbufs) { - if (fbufs < 2 || fbufs > MAX_FRAMES) { - PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); - return -EINVAL; - } - default_fbufs = fbufs; - PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs); - } -#ifdef CONFIG_USB_PWC_DEBUG - if (pwc_trace >= 0) { - PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace); - } -#endif - if (compression >= 0) { - if (compression > 3) { - PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); - return -EINVAL; - } - pwc_preferred_compression = compression; - PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression); - } - if (power_save) - PWC_DEBUG_MODULE("Enabling power save on open/close.\n"); - if (leds[0] >= 0) - led_on = leds[0]; - if (leds[1] >= 0) - led_off = leds[1]; - - /* Big device node whoopla. Basically, it allows you to assign a - device node (/dev/videoX) to a camera, based on its type - & serial number. The format is [type[.serialnumber]:]node. - - Any camera that isn't matched by these rules gets the next - available free device node. - */ - for (i = 0; i < MAX_DEV_HINTS; i++) { - char *s, *colon, *dot; - - /* This loop also initializes the array */ - device_hint[i].pdev = NULL; - s = dev_hint[i]; - if (s != NULL && *s != '\0') { - device_hint[i].type = -1; /* wildcard */ - strcpy(device_hint[i].serial_number, "*"); - - /* parse string: chop at ':' & '/' */ - colon = dot = s; - while (*colon != '\0' && *colon != ':') - colon++; - while (*dot != '\0' && *dot != '.') - dot++; - /* Few sanity checks */ - if (*dot != '\0' && dot > colon) { - PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n"); - return -EINVAL; - } - - if (*colon == '\0') { - /* No colon */ - if (*dot != '\0') { - PWC_ERROR("Malformed camera hint: no colon + device node given.\n"); - return -EINVAL; - } - else { - /* No type or serial number specified, just a number. */ - device_hint[i].device_node = - simple_strtol(s, NULL, 10); - } - } - else { - /* There's a colon, so we have at least a type and a device node */ - device_hint[i].type = - simple_strtol(s, NULL, 10); - device_hint[i].device_node = - simple_strtol(colon + 1, NULL, 10); - if (*dot != '\0') { - /* There's a serial number as well */ - int k; - - dot++; - k = 0; - while (*dot != ':' && k < 29) { - device_hint[i].serial_number[k++] = *dot; - dot++; - } - device_hint[i].serial_number[k] = '\0'; - } - } - PWC_TRACE("device_hint[%d]:\n", i); - PWC_TRACE(" type : %d\n", device_hint[i].type); - PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number); - PWC_TRACE(" node : %d\n", device_hint[i].device_node); - } - else - device_hint[i].type = 0; /* not filled */ - } /* ..for MAX_DEV_HINTS */ - - PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver); - return usb_register(&pwc_driver); -} - -static void __exit usb_pwc_exit(void) -{ - PWC_DEBUG_MODULE("Deregistering driver.\n"); - usb_deregister(&pwc_driver); - PWC_INFO("Philips webcam module removed.\n"); -} - -module_init(usb_pwc_init); -module_exit(usb_pwc_exit); - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-ioctl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-ioctl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-ioctl.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-ioctl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,323 +0,0 @@ -#ifndef PWC_IOCTL_H -#define PWC_IOCTL_H - -/* (C) 2001-2004 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - -/* This is pwc-ioctl.h belonging to PWC 10.0.10 - It contains structures and defines to communicate from user space - directly to the driver. - */ - -/* - Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for - changing white balance and red/blue gains - 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE - 2003/12/13 Nemosft Unv. Some modifications to make interfacing to - PWCX easier - */ - -/* These are private ioctl() commands, specific for the Philips webcams. - They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - - The #define names are built up like follows: - VIDIOC VIDeo IOCtl prefix - PWC Philps WebCam - G optional: Get - S optional: Set - ... the function - */ - -#include -#include - - /* Enumeration of image sizes */ -#define PSZ_SQCIF 0x00 -#define PSZ_QSIF 0x01 -#define PSZ_QCIF 0x02 -#define PSZ_SIF 0x03 -#define PSZ_CIF 0x04 -#define PSZ_VGA 0x05 -#define PSZ_MAX 6 - - -/* The frame rate is encoded in the video_window.flags parameter using - the upper 16 bits, since some flags are defined nowadays. The following - defines provide a mask and shift to filter out this value. - This value can also be passing using the private flag when using v4l2 and - VIDIOC_S_FMT ioctl. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour - balance controls. - */ -#define PWC_FPS_SHIFT 16 -#define PWC_FPS_MASK 0x00FF0000 -#define PWC_FPS_FRMASK 0x003F0000 -#define PWC_FPS_SNAPSHOT 0x00400000 -#define PWC_QLT_MASK 0x03000000 -#define PWC_QLT_SHIFT 24 - - -/* structure for transferring x & y coordinates */ -struct pwc_coord -{ - int x, y; /* guess what */ - int size; /* size, or offset */ -}; - - -/* Used with VIDIOCPWCPROBE */ -struct pwc_probe -{ - char name[32]; - int type; -}; - -struct pwc_serial -{ - char serial[30]; /* String with serial number. Contains terminating 0 */ -}; - -/* pwc_whitebalance.mode values */ -#define PWC_WB_INDOOR 0 -#define PWC_WB_OUTDOOR 1 -#define PWC_WB_FL 2 -#define PWC_WB_MANUAL 3 -#define PWC_WB_AUTO 4 - -/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). - Set mode to one of the PWC_WB_* values above. - *red and *blue are the respective gains of these colour components inside - the camera; range 0..65535 - When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; - otherwise undefined. - 'read_red' and 'read_blue' are read-only. -*/ -struct pwc_whitebalance -{ - int mode; - int manual_red, manual_blue; /* R/W */ - int read_red, read_blue; /* R/O */ -}; - -/* - 'control_speed' and 'control_delay' are used in automatic whitebalance mode, - and tell the camera how fast it should react to changes in lighting, and - with how much delay. Valid values are 0..65535. -*/ -struct pwc_wb_speed -{ - int control_speed; - int control_delay; - -}; - -/* Used with VIDIOCPWC[SG]LED */ -struct pwc_leds -{ - int led_on; /* Led on-time; range = 0..25000 */ - int led_off; /* Led off-time; range = 0..25000 */ -}; - -/* Image size (used with GREALSIZE) */ -struct pwc_imagesize -{ - int width; - int height; -}; - -/* Defines and structures for Motorized Pan & Tilt */ -#define PWC_MPT_PAN 0x01 -#define PWC_MPT_TILT 0x02 -#define PWC_MPT_TIMEOUT 0x04 /* for status */ - -/* Set angles; when absolute != 0, the angle is absolute and the - driver calculates the relative offset for you. This can only - be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns - absolute angles. - */ -struct pwc_mpt_angles -{ - int absolute; /* write-only */ - int pan; /* degrees * 100 */ - int tilt; /* degress * 100 */ -}; - -/* Range of angles of the camera, both horizontally and vertically. - */ -struct pwc_mpt_range -{ - int pan_min, pan_max; /* degrees * 100 */ - int tilt_min, tilt_max; -}; - -struct pwc_mpt_status -{ - int status; - int time_pan; - int time_tilt; -}; - - -/* This is used for out-of-kernel decompression. With it, you can get - all the necessary information to initialize and use the decompressor - routines in standalone applications. - */ -struct pwc_video_command -{ - int type; /* camera type (645, 675, 730, etc.) */ - int release; /* release number */ - - int size; /* one of PSZ_* */ - int alternate; - int command_len; /* length of USB video command */ - unsigned char command_buf[13]; /* Actual USB video command */ - int bandlength; /* >0 = compressed */ - int frame_size; /* Size of one (un)compressed frame */ -}; - -/* Flags for PWCX subroutines. Not all modules honour all flags. */ -#define PWCX_FLAG_PLANAR 0x0001 -#define PWCX_FLAG_BAYER 0x0008 - - -/* IOCTL definitions */ - - /* Restore user settings */ -#define VIDIOCPWCRUSER _IO('v', 192) - /* Save user settings */ -#define VIDIOCPWCSUSER _IO('v', 193) - /* Restore factory settings */ -#define VIDIOCPWCFACTORY _IO('v', 194) - - /* You can manipulate the compression factor. A compression preference of 0 - means use uncompressed modes when available; 1 is low compression, 2 is - medium and 3 is high compression preferred. Of course, the higher the - compression, the lower the bandwidth used but more chance of artefacts - in the image. The driver automatically chooses a higher compression when - the preferred mode is not available. - */ - /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ -#define VIDIOCPWCSCQUAL _IOW('v', 195, int) - /* Get preferred compression quality */ -#define VIDIOCPWCGCQUAL _IOR('v', 195, int) - - -/* Retrieve serial number of camera */ -#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) - - /* This is a probe function; since so many devices are supported, it - becomes difficult to include all the names in programs that want to - check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding - Philips type. - To use, fill the structure with zeroes, call PROBE and if that succeeds, - compare the name with that returned from VIDIOCGCAP; they should be the - same. If so, you can be assured it is a Philips (OEM) cam and the type - is valid. - */ -#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) - - /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ -#define VIDIOCPWCSAGC _IOW('v', 200, int) - /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCGAGC _IOR('v', 200, int) - /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) - - /* Color compensation (Auto White Balance) */ -#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) -#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - - /* Auto WB speed */ -#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) -#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) - - /* LEDs on/off/blink; int range 0..65535 */ -#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) -#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) - - /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ -#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) -#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) - - /* Backlight compensation; 0 = off, otherwise on */ -#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) -#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) - - /* Flickerless mode; = 0 off, otherwise on */ -#define VIDIOCPWCSFLICKER _IOW('v', 208, int) -#define VIDIOCPWCGFLICKER _IOR('v', 208, int) - - /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ -#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) -#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) - - /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ -#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) - - /* Motorized pan & tilt functions */ -#define VIDIOCPWCMPTRESET _IOW('v', 211, int) -#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) -#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - - /* Get the USB set-video command; needed for initializing libpwcx */ -#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) -struct pwc_table_init_buffer { - int len; - char *buffer; - -}; -#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) - -/* - * This is private command used when communicating with v4l2. - * In the future all private ioctl will be remove/replace to - * use interface offer by v4l2. - */ - -#define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4) -#define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6) -#define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8) - -struct pwc_raw_frame { - __le16 type; /* type of the webcam */ - __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */ - __u8 cmd[4]; /* the four byte of the command (in case of nala, - only the first 3 bytes is filled) */ - __u8 rawframe[0]; /* frame_size = H/4*vbandlength */ -} __attribute__ ((packed)); - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-kiara.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-kiara.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-kiara.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-kiara.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,893 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - - -/* This tables contains entries for the 730/740/750 (Kiara) camera, with - 4 different qualities (no compression, low, medium, high). - It lists the bandwidth requirements for said mode by its alternate interface - number. An alternate of 0 means that the mode is unavailable. - - There are 6 * 4 * 4 entries: - 6 different resolutions subqcif, qsif, qcif, sif, cif, vga - 6 framerates: 5, 10, 15, 20, 25, 30 - 4 compression modi: none, low, medium, high - - When an uncompressed mode is not available, the next available compressed mode - will be chosen (unless the decompressor is absent). Sometimes there are only - 1 or 2 compressed modes available; in that case entries are duplicated. -*/ - - -#include "pwc-kiara.h" -#include "pwc-uncompress.h" - -const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 }; - -const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = -{ - /* SQCIF */ - { - /* 5 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 10 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 15 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, - /* QSIF */ - { - /* 5 fps */ - { - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - }, - /* 10 fps */ - { - {2, 291, 0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}}, - {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, - {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, - {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, - }, - /* 15 fps */ - { - {3, 437, 0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}}, - {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, - {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, - {1, 192, 420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, - }, - /* 20 fps */ - { - {4, 589, 0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}}, - {3, 448, 730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}}, - {2, 292, 476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}}, - {1, 192, 312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, - }, - /* 25 fps */ - { - {5, 703, 0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}}, - {3, 447, 610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}}, - {2, 292, 398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}}, - {1, 193, 262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}}, - }, - /* 30 fps */ - { - {8, 874, 0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}}, - {5, 704, 730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}}, - {3, 448, 492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}}, - {2, 292, 320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}}, - }, - }, - /* QCIF */ - { - /* 5 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 10 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 15 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, - /* SIF */ - { - /* 5 fps */ - { - {4, 582, 0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}}, - {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}}, - {2, 291, 960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}}, - {1, 191, 630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}}, - }, - /* 10 fps */ - { - {0, }, - {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}}, - {3, 447, 736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}}, - {2, 292, 480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}}, - }, - /* 15 fps */ - { - {0, }, - {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}}, - {4, 592, 650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}}, - {3, 448, 492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}}, - }, - /* 20 fps */ - { - {0, }, - {9, 958, 782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}}, - {5, 703, 574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}}, - {3, 446, 364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}}, - }, - /* 25 fps */ - { - {0, }, - {9, 958, 654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}}, - {6, 776, 530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}}, - {4, 592, 404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}}, - }, - /* 30 fps */ - { - {0, }, - {9, 957, 526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}}, - {6, 775, 426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}}, - {4, 590, 324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}}, - }, - }, - /* CIF */ - { - /* 5 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 10 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 15 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, - /* VGA */ - { - /* 5 fps */ - { - {0, }, - {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}, - {4, 592, 976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}}, - {3, 448, 738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}}, - }, - /* 10 fps */ - { - {0, }, - {9, 956, 788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}}, - {6, 776, 640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}}, - {4, 592, 488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}}, - }, - /* 15 fps */ - { - {0, }, - {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, - {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, - {8, 895, 492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}}, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, -}; - - -/* - * Rom table for kiara chips - * - * 32 roms tables (one for each resolution ?) - * 2 tables per roms (one for each passes) (Y, and U&V) - * 128 bytes per passes - */ - -const unsigned int KiaraRomTable [8][2][16][8] = -{ - { /* version 0 */ - { /* version 0, passes 0 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000001,0x00000001}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000009,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000009,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000249,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000249,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x00000249,0x0000124a,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x0000124a,0x00009252,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00009252,0x00009292,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009292,0x00009292,0x00009493,0x000124db}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x0000a493,0x000124db,0x000124db,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x000124db,0x000126dc,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000124db,0x000136e4,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 0, passes 1 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000001,0x00000009, - 0x00000009,0x00000009,0x00000009,0x00000001}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000249,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00001252}, - {0x00000000,0x00000000,0x00000049,0x00001249, - 0x0000124a,0x0000124a,0x00001252,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009252,0x00009292,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009292,0x00009292,0x00009292,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x00009292, - 0x00009492,0x00009493,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x000124db,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00009252,0x00009493, - 0x000126dc,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000136e4,0x000136e4,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 1 */ - { /* version 1, passes 0 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000001}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000009,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00001252}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x0000124a,0x00009252,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009292,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009252,0x00009493,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009292,0x00009493,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x00009252, - 0x00009492,0x00009493,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x000124db,0x000124db,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000126dc,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 1, passes 1 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000049,0x00000009, - 0x00000049,0x00000009,0x00000001,0x00000000}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000000}, - {0x00000000,0x00000000,0x00000249,0x00000049, - 0x00000249,0x00000049,0x0000024a,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x0000024a,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x0000024a,0x00000009}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00009252,0x00001252,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00009292,0x00001252,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00009292,0x00001252,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009292,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x0000924a,0x0000924a, - 0x00009492,0x00009493,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 2 */ - { /* version 2, passes 0 */ - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x00001252,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x00009252,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x0000124a,0x00009292,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009493,0x00009493,0x0000a49b}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009292,0x00009493,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x000124db,0x000124db,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x000124db,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000136e4,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x00009252,0x000124db, - 0x000126dc,0x0001b724,0x0001b725,0x0001b925}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 2, passes 1 */ - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00000249, - 0x0000124a,0x0000124a,0x00001252,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00009292,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x0000a49b,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x0000a49b,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x0000a49b,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x0000a49b,0x0000a49b,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x00009252,0x0000a49b, - 0x0001249b,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 3 */ - { /* version 3, passes 0 */ - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x000124db,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000136e4,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000136e4,0x0001b725,0x0001b925}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 3, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00000249, - 0x0000124a,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x00009493,0x0000a49b,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x000126dc,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00009492,0x0000a49b, - 0x000136e4,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001b724,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 4 */ - { /* version 4, passes 0 */ - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000249,0x00000049, - 0x00000249,0x00000249,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x00009252,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009493,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009292,0x00009493,0x00009493,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0001249b,0x000126dc,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00009252,0x00009493, - 0x000124db,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009252,0x0000a49b, - 0x000124db,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 4, passes 1 */ - {0x00000000,0x00000000,0x00000249,0x00000049, - 0x00000009,0x00000009,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000049,0x00000049,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00000249,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x0000124a,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009252,0x0000124a,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x00009252,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x00009292,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x00009292,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x00009493,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009252,0x000124db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 5 */ - { /* version 5, passes 0 */ - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b725,0x000136e4}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 5, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009252,0x00009252,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000124db,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000124db,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000126dc,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009292,0x000124db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 6 */ - { /* version 6, passes 0 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, - {0x00000000,0x00000000,0x00012492,0x000126db, - 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 6, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x00009252,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x00009292,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x0000a49b,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000124db,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 7 */ - { /* version 7, passes 0 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x0000a49b, - 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x0001b725,0x000124db}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x000124db, - 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, - {0x00000000,0x00000000,0x00012492,0x000136db, - 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 7, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x00009492,0x00009292,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x0000a49b,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000124db,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000136db, - 0x0001b724,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000136db, - 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00009292,0x000136db, - 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009492,0x000136db, - 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00012492,0x0001b6db, - 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - } -}; - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-kiara.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-kiara.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-kiara.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-kiara.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - -/* Entries for the Kiara (730/740/750) camera */ - -#ifndef PWC_KIARA_H -#define PWC_KIARA_H - -#include - -#define PWC_FPS_MAX_KIARA 6 - -struct Kiara_table_entry -{ - char alternate; /* USB alternate interface */ - unsigned short packetsize; /* Normal packet size */ - unsigned short bandlength; /* Bandlength when decompressing */ - unsigned char mode[12]; /* precomputed mode settings for cam */ -}; - -extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][PWC_FPS_MAX_KIARA][4]; -extern const unsigned int KiaraRomTable[8][2][16][8]; -extern const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA]; - -#endif - - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-misc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-misc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-misc.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-misc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -/* Linux driver for Philips webcam - Various miscellaneous functions and tables. - (C) 1999-2003 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 "pwc.h" - -const struct pwc_coord pwc_image_sizes[PSZ_MAX] = -{ - { 128, 96, 0 }, /* sqcif */ - { 160, 120, 0 }, /* qsif */ - { 176, 144, 0 }, /* qcif */ - { 320, 240, 0 }, /* sif */ - { 352, 288, 0 }, /* cif */ - { 640, 480, 0 }, /* vga */ -}; - -/* x,y -> PSZ_ */ -int pwc_decode_size(struct pwc_device *pdev, int width, int height) -{ - int i, find; - - /* Make sure we don't go beyond our max size. - NB: we have different limits for RAW and normal modes. In case - you don't have the decompressor loaded or use RAW mode, - the maximum viewable size is smaller. - */ - if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) - { - if (width > pdev->abs_max.x || height > pdev->abs_max.y) - { - PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); - return -1; - } - } - else - { - if (width > pdev->view_max.x || height > pdev->view_max.y) - { - PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n"); - return -1; - } - } - - /* Find the largest size supported by the camera that fits into the - requested size. - */ - find = -1; - for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1 << i)) { - if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) - find = i; - } - } - return find; -} - -/* initialize variables depending on type and decompressor*/ -void pwc_construct(struct pwc_device *pdev) -{ - if (DEVICE_USE_CODEC1(pdev->type)) { - - pdev->view_min.x = 128; - pdev->view_min.y = 96; - pdev->view_max.x = 352; - pdev->view_max.y = 288; - pdev->abs_max.x = 352; - pdev->abs_max.y = 288; - pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; - pdev->vcinterface = 2; - pdev->vendpoint = 4; - pdev->frame_header_size = 0; - pdev->frame_trailer_size = 0; - - } else if (DEVICE_USE_CODEC3(pdev->type)) { - - pdev->view_min.x = 160; - pdev->view_min.y = 120; - pdev->view_max.x = 640; - pdev->view_max.y = 480; - pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; - pdev->vcinterface = 3; - pdev->vendpoint = 5; - pdev->frame_header_size = TOUCAM_HEADER_SIZE; - pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; - - } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ { - - pdev->view_min.x = 128; - pdev->view_min.y = 96; - /* Anthill bug #38: PWC always reports max size, even without PWCX */ - pdev->view_max.x = 640; - pdev->view_max.y = 480; - pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; - pdev->vcinterface = 3; - pdev->vendpoint = 4; - pdev->frame_header_size = 0; - pdev->frame_trailer_size = 0; - } - pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */ - pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; - pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; - /* length of image, in YUV format; always allocate enough memory. */ - pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2); -} - - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-nala.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-nala.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-nala.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-nala.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ - /* SQCIF */ - { - {0, 0, {0x04, 0x01, 0x03}}, - {8, 0, {0x05, 0x01, 0x03}}, - {7, 0, {0x08, 0x01, 0x03}}, - {7, 0, {0x0A, 0x01, 0x03}}, - {6, 0, {0x0C, 0x01, 0x03}}, - {5, 0, {0x0F, 0x01, 0x03}}, - {4, 0, {0x14, 0x01, 0x03}}, - {3, 0, {0x18, 0x01, 0x03}}, - }, - /* QSIF */ - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - }, - /* QCIF */ - { - {0, 0, {0x04, 0x01, 0x02}}, - {8, 0, {0x05, 0x01, 0x02}}, - {7, 0, {0x08, 0x01, 0x02}}, - {6, 0, {0x0A, 0x01, 0x02}}, - {5, 0, {0x0C, 0x01, 0x02}}, - {4, 0, {0x0F, 0x01, 0x02}}, - {1, 0, {0x14, 0x01, 0x02}}, - {1, 0, {0x18, 0x01, 0x02}}, - }, - /* SIF */ - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - }, - /* CIF */ - { - {4, 0, {0x04, 0x01, 0x01}}, - {7, 1, {0x05, 0x03, 0x01}}, - {6, 1, {0x08, 0x03, 0x01}}, - {4, 1, {0x0A, 0x03, 0x01}}, - {3, 1, {0x0C, 0x03, 0x01}}, - {2, 1, {0x0F, 0x03, 0x01}}, - {0}, - {0}, - }, - /* VGA */ - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - }, diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-timon.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-timon.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-timon.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-timon.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1448 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - - -/* This tables contains entries for the 675/680/690 (Timon) camera, with - 4 different qualities (no compression, low, medium, high). - It lists the bandwidth requirements for said mode by its alternate interface - number. An alternate of 0 means that the mode is unavailable. - - There are 6 * 4 * 4 entries: - 6 different resolutions subqcif, qsif, qcif, sif, cif, vga - 6 framerates: 5, 10, 15, 20, 25, 30 - 4 compression modi: none, low, medium, high - - When an uncompressed mode is not available, the next available compressed mode - will be chosen (unless the decompressor is absent). Sometimes there are only - 1 or 2 compressed modes available; in that case entries are duplicated. -*/ - -#include "pwc-timon.h" - -const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON] = { 5, 10, 15, 20, 25, 30 }; - -const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4] = -{ - /* SQCIF */ - { - /* 5 fps */ - { - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - }, - /* 10 fps */ - { - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - }, - /* 15 fps */ - { - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - }, - /* 20 fps */ - { - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - }, - /* 25 fps */ - { - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - }, - /* 30 fps */ - { - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - }, - }, - /* QSIF */ - { - /* 5 fps */ - { - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - }, - /* 10 fps */ - { - {2, 291, 0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}}, - {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - }, - /* 15 fps */ - { - {3, 437, 0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}}, - {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {1, 191, 420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - }, - /* 20 fps */ - { - {4, 588, 0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}}, - {3, 447, 730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, - {1, 192, 312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, - }, - /* 25 fps */ - { - {5, 703, 0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}}, - {3, 447, 610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, - {1, 192, 262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, - }, - /* 30 fps */ - { - {8, 873, 0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}}, - {5, 704, 774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}}, - {3, 448, 492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}}, - {2, 291, 320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, - }, - }, - /* QCIF */ - { - /* 5 fps */ - { - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - }, - /* 10 fps */ - { - {3, 385, 0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}}, - {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {1, 194, 532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}}, - }, - /* 15 fps */ - { - {4, 577, 0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}}, - {3, 447, 818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}}, - {1, 195, 356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}}, - }, - /* 20 fps */ - { - {6, 776, 0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}}, - {4, 591, 804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}}, - {3, 447, 608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 291, 396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, - }, - /* 25 fps */ - { - {9, 928, 0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}}, - {5, 703, 800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}}, - {3, 447, 508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, - }, - /* 30 fps */ - { - {0, }, - {9, 956, 876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}}, - {4, 592, 542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}}, - {2, 291, 266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}}, - }, - }, - /* SIF */ - { - /* 5 fps */ - { - {4, 582, 0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}}, - {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}}, - {2, 291, 960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}}, - {1, 191, 630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}}, - }, - /* 10 fps */ - { - {0, }, - {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}}, - {3, 447, 736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}}, - {2, 291, 480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}}, - }, - /* 15 fps */ - { - {0, }, - {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}}, - {4, 591, 650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}}, - {3, 448, 492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}}, - }, - /* 20 fps */ - { - {0, }, - {9, 958, 782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}}, - {5, 703, 574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}}, - {3, 446, 364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}}, - }, - /* 25 fps */ - { - {0, }, - {9, 958, 654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}}, - {6, 776, 530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}}, - {4, 592, 404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}}, - }, - /* 30 fps */ - { - {0, }, - {9, 957, 526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}}, - {6, 775, 426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}}, - {4, 590, 324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}}, - }, - }, - /* CIF */ - { - /* 5 fps */ - { - {6, 771, 0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}}, - {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}}, - {2, 291, 800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}}, - {1, 193, 528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}}, - }, - /* 10 fps */ - { - {0, }, - {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}}, - {4, 591, 812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}}, - {2, 291, 400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}}, - }, - /* 15 fps */ - { - {0, }, - {9, 956, 876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}}, - {5, 703, 644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}}, - {3, 448, 410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}}, - }, - /* 20 fps */ - { - {0, }, - {9, 956, 650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}}, - {6, 776, 528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}}, - {4, 591, 402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}}, - }, - /* 25 fps */ - { - {0, }, - {9, 956, 544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}}, - {7, 840, 478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}}, - {5, 703, 400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}}, - }, - /* 30 fps */ - { - {0, }, - {9, 956, 438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}}, - {7, 838, 384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}}, - {6, 773, 354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}}, - }, - }, - /* VGA */ - { - /* 5 fps */ - { - {0, }, - {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}}, - {4, 592, 976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}}, - {3, 448, 738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}}, - }, - /* 10 fps */ - { - {0, }, - {9, 956, 788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}}, - {6, 776, 640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}}, - {4, 592, 488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}}, - }, - /* 15 fps */ - { - {0, }, - {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, - {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, - {8, 895, 492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}}, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, -}; - -/* - * 16 versions: - * 2 tables (one for Y, and one for U&V) - * 16 levels of details per tables - * 8 blocs - */ - -const unsigned int TimonRomTable [16][2][16][8] = -{ - { /* version 0 */ - { /* version 0, passes 0 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000001}, - {0x00000000,0x00000000,0x00000001,0x00000001, - 0x00000001,0x00000001,0x00000001,0x00000001}, - {0x00000000,0x00000000,0x00000001,0x00000001, - 0x00000001,0x00000009,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000009,0x00000001, - 0x00000009,0x00000009,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000009,0x00000049,0x00000009}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000009,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000249,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000249,0x00000249,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000249,0x0000124a,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x00000249,0x0000124a,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x0000124a,0x00009252,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 0, passes 1 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000001,0x00000001, - 0x00000001,0x00000001,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000009,0x00000001, - 0x00000001,0x00000009,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000009,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000009,0x00000001,0x00000000}, - {0x00000000,0x00000000,0x00000049,0x00000009, - 0x00000009,0x00000049,0x00000001,0x00000001}, - {0x00000000,0x00000000,0x00000049,0x00000009, - 0x00000009,0x00000049,0x00000001,0x00000001}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000009,0x00000001}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000009,0x00000001}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000009,0x00000001}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000249,0x00000049,0x00000009}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000249,0x00000049,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000049, - 0x00000249,0x00000249,0x00000049,0x00000009}, - {0x00000000,0x00000000,0x00001249,0x00000249, - 0x0000124a,0x0000124a,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 1 */ - { /* version 1, passes 0 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000001}, - {0x00000000,0x00000000,0x00000001,0x00000001, - 0x00000001,0x00000009,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000009,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000009,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000249,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00001252}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x00000249,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x0000124a,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x0000124a,0x00009252,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009252,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009292,0x00009493,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 1, passes 1 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000001,0x00000001,0x00000000}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000009,0x00000001,0x00000000}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000009,0x00000001,0x00000000}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000001,0x00000001}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000009,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000049, - 0x00000049,0x00000249,0x00000009,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000049, - 0x00000249,0x00000249,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x00000049,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x00000049,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x00000049,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009252,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 2 */ - { /* version 2, passes 0 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000001}, - {0x00000000,0x00000000,0x00000009,0x00000009, - 0x00000009,0x00000009,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00001252}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x0000124a,0x00009252,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009292,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009252,0x00009493,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009292,0x00009493,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x00009252, - 0x00009492,0x00009493,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x000124db,0x000124db,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000126dc,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 2, passes 1 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000049,0x00000009, - 0x00000049,0x00000009,0x00000001,0x00000000}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000000}, - {0x00000000,0x00000000,0x00000249,0x00000049, - 0x00000249,0x00000049,0x0000024a,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x0000024a,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x0000024a,0x00000009}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00009252,0x00001252,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00009292,0x00001252,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00009292,0x00001252,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009292,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x0000924a,0x0000924a, - 0x00009492,0x00009493,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 3 */ - { /* version 3, passes 0 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000001}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000049,0x00000249, - 0x00000249,0x00000249,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x00009252,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x0000124a,0x00009292,0x00009292,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009292,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009292,0x00009493,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x00009252, - 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009292,0x0000a49b,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x000124db,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x0000a49b,0x000124db,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0001249b,0x000126dc,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000136e4,0x0001b725,0x000136e4}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 3, passes 1 */ - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}, - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000001,0x00000000}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x00000049,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x00001252,0x00000001}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x00001252,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x0000124a,0x00009252,0x00009292,0x00000009}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00009252,0x00009292,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009252,0x00009292,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009493,0x00009292,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009493,0x00009292,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009493,0x00009493,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009292,0x00009493,0x00009493,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x00009493,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x0000a49b,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x00009292, - 0x0000a493,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 4 */ - { /* version 4, passes 0 */ - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x00001252,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x00009252,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x0000124a,0x00009292,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009493,0x00009493,0x0000a49b}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009292,0x00009493,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x000124db,0x000124db,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x000124db,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000136e4,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x00009252,0x000124db, - 0x000126dc,0x0001b724,0x0001b725,0x0001b925}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 4, passes 1 */ - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00000249, - 0x0000124a,0x0000124a,0x00001252,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00009292,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x0000a49b,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x0000a49b,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x0000a49b,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x0000a49b,0x0000a49b,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x00009252,0x0000a49b, - 0x0001249b,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 5 */ - { /* version 5, passes 0 */ - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x0000124a,0x00001252,0x00009292}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x0000124a,0x00009292,0x00009292,0x00009493}, - {0x00000000,0x00000000,0x00000249,0x0000924a, - 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x000124db,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x000124db,0x000124db,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0001249b,0x000126dc,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000126dc,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b724,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 5, passes 1 */ - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x00009493,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x00009493,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x0000a49b,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x00009493,0x000124db,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x00009493,0x000124db,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x000124db,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x000124db,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009252,0x000124db, - 0x000126dc,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 6 */ - { /* version 6, passes 0 */ - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x0000124a,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x000124db,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000136e4,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000136e4,0x0001b725,0x0001b925}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 6, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00000249, - 0x0000124a,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x00009493,0x0000a49b,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x000126dc,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00009492,0x0000a49b, - 0x000136e4,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001b724,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 7 */ - { /* version 7, passes 0 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x0000a49b,0x000124db,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000136e4,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x0001b725,0x0001b925}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x00009292,0x000124db, - 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b724,0x0001c96e,0x0002496e}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x000136e4,0x0001b925,0x0001c96e,0x0002496e}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x0002496d,0x00025bb6,0x00025bbf}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 7, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x00009493,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x000124db,0x000136e4,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x000124db,0x000136e4,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000124db,0x000136e4,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x000136e4,0x0001b724,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00012492,0x000126db, - 0x0001b724,0x0001b925,0x0001b725,0x000136e4}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 8 */ - { /* version 8, passes 0 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009292,0x00009493,0x0000a49b,0x000124db}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x000124db,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x000136e4}, - {0x00000000,0x00000000,0x00001249,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000136e4,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x0001b725,0x0001b925}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, - {0x00000000,0x00000000,0x00009252,0x000124db, - 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, - {0x00000000,0x00000000,0x00009292,0x000124db, - 0x000126dc,0x0001b925,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b925,0x00024b76,0x00024b77}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x000136e4,0x0001b925,0x00024b76,0x00025bbf}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x000136e4,0x0001c92d,0x00024b76,0x00025bbf}, - {0x00000000,0x00000000,0x00012492,0x000136db, - 0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 8, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009493,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x000124db,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000126dc,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00009292,0x000124db, - 0x000136e4,0x0001b724,0x0001b725,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x000136e4,0x0001b925,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x000136e4,0x0001b925,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x0002496d,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 9 */ - { /* version 9, passes 0 */ - {0x00000000,0x00000000,0x00000049,0x00000049, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00000249,0x00000049, - 0x00000249,0x00000249,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x0000124a,0x00009252,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009493,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009292,0x00009493,0x00009493,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0001249b,0x000126dc,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00009252,0x00009493, - 0x000124db,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009252,0x0000a49b, - 0x000124db,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 9, passes 1 */ - {0x00000000,0x00000000,0x00000249,0x00000049, - 0x00000009,0x00000009,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000049,0x00000049,0x00000009,0x00000009}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00000249,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x0000124a,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009252,0x0000124a,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x00009252,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x00009292,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x00009292,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x00009493,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009252,0x000124db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 10 */ - { /* version 10, passes 0 */ - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00000249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x00009493,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x000124db,0x000124db,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0001249b,0x000126dc,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000126dc,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009252,0x0000a49b, - 0x000124db,0x000136e4,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b92d,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000126dc,0x0001b925,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x000136e4,0x0002496d,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 10, passes 1 */ - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000049,0x00000049,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00000249,0x00000049,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x00009252,0x0000024a,0x00000049}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009493,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00009252, - 0x00009492,0x00009493,0x00001252,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x00009493,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x00009492,0x00009493,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x00009493,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009252,0x000126db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 11 */ - { /* version 11, passes 0 */ - {0x00000000,0x00000000,0x00000249,0x00000249, - 0x00000249,0x00000249,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x000124db,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b725,0x000136e4}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 11, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00000249, - 0x00000249,0x00000249,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009252,0x00009252,0x0000024a,0x0000024a}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x0000a49b,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x0000a49b,0x00009292,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000124db,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000124db,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000126dc,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009292,0x000124db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 12 */ - { /* version 12, passes 0 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, - {0x00000000,0x00000000,0x00012492,0x000126db, - 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 12, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x00001249,0x00009292, - 0x00009492,0x00009252,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x00009292,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x0000a49b,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000124db,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000124db,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00009492,0x000126db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 13 */ - { /* version 13, passes 0 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x00009252,0x00009292,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x000124db,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x0000a49b, - 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x000136e4,0x0001b725,0x000124db}, - {0x00000000,0x00000000,0x00009292,0x0000a49b, - 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, - {0x00000000,0x00000000,0x00009292,0x000124db, - 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, - {0x00000000,0x00000000,0x00012492,0x000136db, - 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 13, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x00009492,0x00009292,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x0000a49b,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000124db,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000136db, - 0x0001b724,0x000124db,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000136db, - 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00009292,0x000136db, - 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x00009492,0x000136db, - 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00012492,0x0001b6db, - 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 14 */ - { /* version 14, passes 0 */ - {0x00000000,0x00000000,0x00001249,0x0000924a, - 0x00009292,0x00009493,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00001249,0x0000a49b, - 0x0000a493,0x000124db,0x000126dc,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x000136e4,0x0001b725,0x000124db}, - {0x00000000,0x00000000,0x00009292,0x000124db, - 0x000126dc,0x0001b724,0x0001b92d,0x000126dc}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001c92d,0x0001c96e,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001c92d,0x00024b76,0x0001b925}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b924,0x0002496d,0x00024b76,0x00024b77}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf}, - {0x00000000,0x00000000,0x00012492,0x0001b6db, - 0x00024924,0x0002db6d,0x00036db6,0x0002efff}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 14, passes 1 */ - {0x00000000,0x00000000,0x00001249,0x00001249, - 0x0000124a,0x0000124a,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x00009493, - 0x0000a493,0x00009292,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x0000a49b,0x00001252,0x00001252}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000136e4,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000136e4,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x000136e4,0x00009493,0x00009292}, - {0x00000000,0x00000000,0x00009492,0x000136db, - 0x0001b724,0x000136e4,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x00009492,0x000136db, - 0x0001b724,0x000136e4,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x00009492,0x000136db, - 0x0001b724,0x000136e4,0x0000a49b,0x00009493}, - {0x00000000,0x00000000,0x00009492,0x000136db, - 0x0001b724,0x000136e4,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x000136e4,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x000136e4,0x000124db,0x0000a49b}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b724,0x000136e4,0x000126dc,0x000124db}, - {0x00000000,0x00000000,0x00012492,0x0001b6db, - 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - }, - { /* version 15 */ - { /* version 15, passes 0 */ - {0x00000000,0x00000000,0x00001249,0x00009493, - 0x0000a493,0x0000a49b,0x000124db,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0001249b,0x000126dc,0x000136e4,0x000124db}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x000136e4,0x0001b925,0x0001c96e,0x000136e4}, - {0x00000000,0x00000000,0x00009492,0x000124db, - 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000124db, - 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, - {0x00000000,0x00000000,0x0000a492,0x000126db, - 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001b924,0x0002496d,0x00024b76,0x0002496e}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001c924,0x00024b6d,0x00025bb6,0x00024b77}, - {0x00000000,0x00000000,0x00012492,0x000136db, - 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, - {0x00000000,0x00000000,0x00012492,0x0001b6db, - 0x00024924,0x0002db6d,0x00036db6,0x0002efff}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - }, - { /* version 15, passes 1 */ - {0x00000000,0x00000000,0x0000924a,0x0000924a, - 0x00009292,0x00009292,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x0000a49b, - 0x0000a493,0x000124db,0x00009292,0x00009292}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000124db,0x0001b724,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000126dc,0x0001b724,0x00009493,0x00009493}, - {0x00000000,0x00000000,0x0000924a,0x000124db, - 0x000136e4,0x0001b724,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00009292,0x000136db, - 0x0001b724,0x0001b724,0x0000a49b,0x0000a49b}, - {0x00000000,0x00000000,0x00009492,0x000136db, - 0x0001c924,0x0001b724,0x000124db,0x000124db}, - {0x00000000,0x00000000,0x00009492,0x000136db, - 0x0001c924,0x0001b724,0x000124db,0x000124db}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001c924,0x0001b724,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001c924,0x0001b925,0x000126dc,0x000126dc}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001c924,0x0001b925,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001c924,0x0001b925,0x000136e4,0x000136e4}, - {0x00000000,0x00000000,0x0000a492,0x000136db, - 0x0001c924,0x0001b925,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x00012492,0x000136db, - 0x0001c924,0x0001b925,0x0001b725,0x0001b724}, - {0x00000000,0x00000000,0x00012492,0x0001b6db, - 0x00024924,0x0002496d,0x0001b92d,0x0001b925}, - {0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000} - } - } -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-timon.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-timon.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-timon.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-timon.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - - - -/* This tables contains entries for the 675/680/690 (Timon) camera, with - 4 different qualities (no compression, low, medium, high). - It lists the bandwidth requirements for said mode by its alternate interface - number. An alternate of 0 means that the mode is unavailable. - - There are 6 * 4 * 4 entries: - 6 different resolutions subqcif, qsif, qcif, sif, cif, vga - 6 framerates: 5, 10, 15, 20, 25, 30 - 4 compression modi: none, low, medium, high - - When an uncompressed mode is not available, the next available compressed mode - will be chosen (unless the decompressor is absent). Sometimes there are only - 1 or 2 compressed modes available; in that case entries are duplicated. -*/ - -#ifndef PWC_TIMON_H -#define PWC_TIMON_H - -#include - -#define PWC_FPS_MAX_TIMON 6 - -struct Timon_table_entry -{ - char alternate; /* USB alternate interface */ - unsigned short packetsize; /* Normal packet size */ - unsigned short bandlength; /* Bandlength when decompressing */ - unsigned char mode[13]; /* precomputed mode settings for cam */ -}; - -extern const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4]; -extern const unsigned int TimonRomTable [16][2][16][8]; -extern const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON]; - -#endif - - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-uncompress.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-uncompress.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-uncompress.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-uncompress.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,138 +0,0 @@ -/* Linux driver for Philips webcam - Decompression frontend. - (C) 1999-2003 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 - - vim: set ts=8: -*/ - -#include -#include - -#include "pwc.h" -#include "pwc-uncompress.h" -#include "pwc-dec1.h" -#include "pwc-dec23.h" - -int pwc_decompress(struct pwc_device *pdev) -{ - struct pwc_frame_buf *fbuf; - int n, line, col, stride; - void *yuv, *image; - u16 *src; - u16 *dsty, *dstu, *dstv; - - if (pdev == NULL) - return -EFAULT; - - fbuf = pdev->read_frame; - if (fbuf == NULL) - return -EFAULT; - image = pdev->image_data; - image += pdev->images[pdev->fill_image].offset; - - yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ - - /* Raw format; that's easy... */ - if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) - { - struct pwc_raw_frame *raw_frame = image; - raw_frame->type = cpu_to_le16(pdev->type); - raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength); - /* cmd_buf is always 4 bytes, but sometimes, only the - * first 3 bytes is filled (Nala case). We can - * determine this using the type of the webcam */ - memcpy(raw_frame->cmd, pdev->cmd_buf, 4); - memcpy(raw_frame+1, yuv, pdev->frame_size); - return 0; - } - - if (pdev->vbandlength == 0) { - /* Uncompressed mode. - * We copy the data into the output buffer, using the viewport - * size (which may be larger than the image size). - * Unfortunately we have to do a bit of byte stuffing to get - * the desired output format/size. - * - * We do some byte shuffling here to go from the - * native format to YUV420P. - */ - src = (u16 *)yuv; - n = pdev->view.x * pdev->view.y; - - /* offset in Y plane */ - stride = pdev->view.x * pdev->offset.y + pdev->offset.x; - dsty = (u16 *)(image + stride); - - /* offsets in U/V planes */ - stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; - dstu = (u16 *)(image + n + stride); - dstv = (u16 *)(image + n + n / 4 + stride); - - /* increment after each line */ - stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ - - for (line = 0; line < pdev->image.y; line++) { - for (col = 0; col < pdev->image.x; col += 4) { - *dsty++ = *src++; - *dsty++ = *src++; - if (line & 1) - *dstv++ = *src++; - else - *dstu++ = *src++; - } - dsty += stride; - if (line & 1) - dstv += (stride >> 1); - else - dstu += (stride >> 1); - } - - return 0; - } - - /* - * Compressed; - * the decompressor routines will write the data in planar format - * immediately. - */ - if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) { - PWC_ERROR("Mode Bayer is not supported for now\n"); - /* flags |= PWCX_FLAG_BAYER; */ - return -ENXIO; /* No such device or address: missing decompressor */ - } - - if (DEVICE_USE_CODEC1(pdev->type)) { - - /* TODO & FIXME */ - PWC_ERROR("This chipset is not supported for now\n"); - return -ENXIO; /* No such device or address: missing decompressor */ - - } else { - pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR); - } - return 0; -} - - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-uncompress.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-uncompress.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-uncompress.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-uncompress.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* (C) 1999-2003 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - -/* This file is the bridge between the kernel module and the plugin; it - describes the structures and datatypes used in both modules. Any - significant change should be reflected by increasing the - pwc_decompressor_version major number. - */ -#ifndef PWC_UNCOMPRESS_H -#define PWC_UNCOMPRESS_H - - -#include - -/* from pwc-dec.h */ -#define PWCX_FLAG_PLANAR 0x0001 -/* */ - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-v4l.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-v4l.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-v4l.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pwc/pwc-v4l.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,895 +0,0 @@ -/* Linux driver for Philips webcam - USB and Video4Linux interface part. - (C) 1999-2004 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -#include -#include -#include -#include -#include -#include - -#include "pwc.h" - -static struct v4l2_queryctrl pwc_controls[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 128, - .step = 1, - .default_value = 64, - }, - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 64, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = -100, - .maximum = 100, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 32, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Gain", - .minimum = 0, - .maximum = 256, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Gain", - .minimum = 0, - .maximum = 256, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto White Balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Shutter Speed (Exposure)", - .minimum = 0, - .maximum = 256, - .step = 1, - .default_value = 200, - }, - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain Enabled", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain Level", - .minimum = 0, - .maximum = 256, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_PRIVATE_SAVE_USER, - .type = V4L2_CTRL_TYPE_BUTTON, - .name = "Save User Settings", - .minimum = 0, - .maximum = 0, - .step = 0, - .default_value = 0, - }, - { - .id = V4L2_CID_PRIVATE_RESTORE_USER, - .type = V4L2_CTRL_TYPE_BUTTON, - .name = "Restore User Settings", - .minimum = 0, - .maximum = 0, - .step = 0, - .default_value = 0, - }, - { - .id = V4L2_CID_PRIVATE_RESTORE_FACTORY, - .type = V4L2_CTRL_TYPE_BUTTON, - .name = "Restore Factory Settings", - .minimum = 0, - .maximum = 0, - .step = 0, - .default_value = 0, - }, - { - .id = V4L2_CID_PRIVATE_COLOUR_MODE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Colour mode", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_PRIVATE_AUTOCONTOUR, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto contour", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_PRIVATE_CONTOUR, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contour", - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_PRIVATE_BACKLIGHT, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Backlight compensation", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_PRIVATE_FLICKERLESS, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flickerless", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_PRIVATE_NOISE_REDUCTION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Noise reduction", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 0, - }, -}; - - -static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) -{ - memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); - f->fmt.pix.width = pdev->view.x; - f->fmt.pix.height = pdev->view.y; - f->fmt.pix.field = V4L2_FIELD_NONE; - if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) { - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; - f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - } else { - /* vbandlength contains 4 lines ... */ - f->fmt.pix.bytesperline = pdev->vbandlength/4; - f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame); - if (DEVICE_USE_CODEC1(pdev->type)) - f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1; - else - f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2; - } - PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() " - "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n", - f->fmt.pix.width, - f->fmt.pix.height, - f->fmt.pix.bytesperline, - f->fmt.pix.sizeimage, - (f->fmt.pix.pixelformat)&255, - (f->fmt.pix.pixelformat>>8)&255, - (f->fmt.pix.pixelformat>>16)&255, - (f->fmt.pix.pixelformat>>24)&255); -} - -/* ioctl(VIDIOC_TRY_FMT) */ -static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) -{ - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); - return -EINVAL; - } - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_YUV420: - break; - case V4L2_PIX_FMT_PWC1: - if (DEVICE_USE_CODEC23(pdev->type)) { - PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n"); - return -EINVAL; - } - break; - case V4L2_PIX_FMT_PWC2: - if (DEVICE_USE_CODEC1(pdev->type)) { - PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n"); - return -EINVAL; - } - break; - default: - PWC_DEBUG_IOCTL("Unsupported pixel format\n"); - return -EINVAL; - - } - - if (f->fmt.pix.width > pdev->view_max.x) - f->fmt.pix.width = pdev->view_max.x; - else if (f->fmt.pix.width < pdev->view_min.x) - f->fmt.pix.width = pdev->view_min.x; - - if (f->fmt.pix.height > pdev->view_max.y) - f->fmt.pix.height = pdev->view_max.y; - else if (f->fmt.pix.height < pdev->view_min.y) - f->fmt.pix.height = pdev->view_min.y; - - return 0; -} - -/* ioctl(VIDIOC_SET_FMT) */ -static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) -{ - int ret, fps, snapshot, compression, pixelformat; - - ret = pwc_vidioc_try_fmt(pdev, f); - if (ret<0) - return ret; - - pixelformat = f->fmt.pix.pixelformat; - compression = pdev->vcompression; - snapshot = 0; - fps = pdev->vframes; - if (f->fmt.pix.priv) { - compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT; - snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT); - fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; - if (fps == 0) - fps = pdev->vframes; - } - - if (pixelformat != V4L2_PIX_FMT_YUV420 && - pixelformat != V4L2_PIX_FMT_PWC1 && - pixelformat != V4L2_PIX_FMT_PWC2) - return -EINVAL; - - if (pdev->iso_init) - return -EBUSY; - - PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d " - "compression=%d snapshot=%d format=%c%c%c%c\n", - f->fmt.pix.width, f->fmt.pix.height, fps, - compression, snapshot, - (pixelformat)&255, - (pixelformat>>8)&255, - (pixelformat>>16)&255, - (pixelformat>>24)&255); - - ret = pwc_set_video_mode(pdev, - f->fmt.pix.width, - f->fmt.pix.height, - fps, - compression, - snapshot); - - PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret); - - if (ret) - return ret; - - pdev->pixfmt = pixelformat; - - pwc_vidioc_fill_fmt(pdev, f); - - return 0; - -} - -static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) -{ - struct video_device *vdev = video_devdata(file); - struct pwc_device *pdev = video_drvdata(file); - - strcpy(cap->driver, PWC_NAME); - strlcpy(cap->card, vdev->name, sizeof(cap->card)); - usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = PWC_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - return 0; -} - -static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - if (i->index) /* Only one INPUT is supported */ - return -EINVAL; - - strcpy(i->name, "usb"); - return 0; -} - -static int pwc_g_input(struct file *file, void *fh, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int pwc_s_input(struct file *file, void *fh, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) -{ - int i; - - for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) { - if (pwc_controls[i].id == c->id) { - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n"); - memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl)); - return 0; - } - } - return -EINVAL; -} - -static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) -{ - struct pwc_device *pdev = video_drvdata(file); - int ret; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = pwc_get_brightness(pdev); - if (c->value < 0) - return -EINVAL; - return 0; - case V4L2_CID_CONTRAST: - c->value = pwc_get_contrast(pdev); - if (c->value < 0) - return -EINVAL; - return 0; - case V4L2_CID_SATURATION: - ret = pwc_get_saturation(pdev, &c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_GAMMA: - c->value = pwc_get_gamma(pdev); - if (c->value < 0) - return -EINVAL; - return 0; - case V4L2_CID_RED_BALANCE: - ret = pwc_get_red_gain(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value >>= 8; - return 0; - case V4L2_CID_BLUE_BALANCE: - ret = pwc_get_blue_gain(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value >>= 8; - return 0; - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = pwc_get_awb(pdev); - if (ret < 0) - return -EINVAL; - c->value = (ret == PWC_WB_MANUAL) ? 0 : 1; - return 0; - case V4L2_CID_GAIN: - ret = pwc_get_agc(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value >>= 8; - return 0; - case V4L2_CID_AUTOGAIN: - ret = pwc_get_agc(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value = (c->value < 0) ? 1 : 0; - return 0; - case V4L2_CID_EXPOSURE: - ret = pwc_get_shutter_speed(pdev, &c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_COLOUR_MODE: - ret = pwc_get_colour_mode(pdev, &c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_AUTOCONTOUR: - ret = pwc_get_contour(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value = (c->value == -1 ? 1 : 0); - return 0; - case V4L2_CID_PRIVATE_CONTOUR: - ret = pwc_get_contour(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value >>= 10; - return 0; - case V4L2_CID_PRIVATE_BACKLIGHT: - ret = pwc_get_backlight(pdev, &c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_FLICKERLESS: - ret = pwc_get_flicker(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value = (c->value ? 1 : 0); - return 0; - case V4L2_CID_PRIVATE_NOISE_REDUCTION: - ret = pwc_get_dynamic_noise(pdev, &c->value); - if (ret < 0) - return -EINVAL; - return 0; - - case V4L2_CID_PRIVATE_SAVE_USER: - case V4L2_CID_PRIVATE_RESTORE_USER: - case V4L2_CID_PRIVATE_RESTORE_FACTORY: - return -EINVAL; - } - return -EINVAL; -} - -static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) -{ - struct pwc_device *pdev = video_drvdata(file); - int ret; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value <<= 9; - ret = pwc_set_brightness(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_CONTRAST: - c->value <<= 10; - ret = pwc_set_contrast(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_SATURATION: - ret = pwc_set_saturation(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_GAMMA: - c->value <<= 11; - ret = pwc_set_gamma(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_RED_BALANCE: - c->value <<= 8; - ret = pwc_set_red_gain(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_BLUE_BALANCE: - c->value <<= 8; - ret = pwc_set_blue_gain(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_AUTO_WHITE_BALANCE: - c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO; - ret = pwc_set_awb(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_EXPOSURE: - c->value <<= 8; - ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_AUTOGAIN: - /* autogain off means nothing without a gain */ - if (c->value == 0) - return 0; - ret = pwc_set_agc(pdev, c->value, 0); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_GAIN: - c->value <<= 8; - ret = pwc_set_agc(pdev, 0, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_SAVE_USER: - if (pwc_save_user(pdev)) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_RESTORE_USER: - if (pwc_restore_user(pdev)) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_RESTORE_FACTORY: - if (pwc_restore_factory(pdev)) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_COLOUR_MODE: - ret = pwc_set_colour_mode(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_AUTOCONTOUR: - c->value = (c->value == 1) ? -1 : 0; - ret = pwc_set_contour(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_CONTOUR: - c->value <<= 10; - ret = pwc_set_contour(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_BACKLIGHT: - ret = pwc_set_backlight(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_FLICKERLESS: - ret = pwc_set_flicker(pdev, c->value); - if (ret < 0) - return -EINVAL; - case V4L2_CID_PRIVATE_NOISE_REDUCTION: - ret = pwc_set_dynamic_noise(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - - } - return -EINVAL; -} - -static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) -{ - struct pwc_device *pdev = video_drvdata(file); - - /* We only support two format: the raw format, and YUV */ - switch (f->index) { - case 0: - /* RAW format */ - f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2; - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description)); - break; - case 1: - f->pixelformat = V4L2_PIX_FMT_YUV420; - strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description)); - break; - default: - return -EINVAL; - } - return 0; -} - -static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) -{ - struct pwc_device *pdev = video_drvdata(file); - - PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n", - pdev->image.x, pdev->image.y); - pwc_vidioc_fill_fmt(pdev, f); - return 0; -} - -static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) -{ - struct pwc_device *pdev = video_drvdata(file); - - return pwc_vidioc_try_fmt(pdev, f); -} - -static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) -{ - struct pwc_device *pdev = video_drvdata(file); - - return pwc_vidioc_set_fmt(pdev, f); -} - -static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) -{ - int nbuffers; - - PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count); - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - nbuffers = rb->count; - if (nbuffers < 2) - nbuffers = 2; - else if (nbuffers > pwc_mbufs) - nbuffers = pwc_mbufs; - /* Force to use our # of buffers */ - rb->count = pwc_mbufs; - return 0; -} - -static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct pwc_device *pdev = video_drvdata(file); - int index; - - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index); - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n"); - return -EINVAL; - } - index = buf->index; - if (index < 0 || index >= pwc_mbufs) { - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index); - return -EINVAL; - } - - buf->m.offset = index * pdev->len_per_image; - if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) - buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); - else - buf->bytesused = pdev->view.size; - buf->field = V4L2_FIELD_NONE; - buf->memory = V4L2_MEMORY_MMAP; - /*buf->flags = V4L2_BUF_FLAG_MAPPED;*/ - buf->length = pdev->len_per_image; - - PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index); - PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n", buf->m.offset); - PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n", buf->bytesused); - - return 0; -} - -static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index); - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - if (buf->index >= pwc_mbufs) - return -EINVAL; - - buf->flags |= V4L2_BUF_FLAG_QUEUED; - buf->flags &= ~V4L2_BUF_FLAG_DONE; - - return 0; -} - -static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - DECLARE_WAITQUEUE(wait, current); - struct pwc_device *pdev = video_drvdata(file); - int ret; - - PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n"); - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - add_wait_queue(&pdev->frameq, &wait); - while (pdev->full_frames == NULL) { - if (pdev->error_status) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -pdev->error_status; - } - - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - mutex_unlock(&pdev->modlock); - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - mutex_lock(&pdev->modlock); - } - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n"); - /* Decompress data in pdev->images[pdev->fill_image] */ - ret = pwc_handle_frame(pdev); - if (ret) - return -EFAULT; - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); - - buf->index = pdev->fill_image; - if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) - buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); - else - buf->bytesused = pdev->view.size; - buf->flags = V4L2_BUF_FLAG_MAPPED; - buf->field = V4L2_FIELD_NONE; - do_gettimeofday(&buf->timestamp); - buf->sequence = 0; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = pdev->fill_image * pdev->len_per_image; - buf->length = pdev->len_per_image; - pwc_next_image(pdev); - - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n", buf->index); - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n", buf->length); - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n", buf->m.offset); - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n", buf->bytesused); - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n"); - return 0; - -} - -static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) -{ - struct pwc_device *pdev = video_drvdata(file); - - return pwc_isoc_init(pdev); -} - -static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) -{ - struct pwc_device *pdev = video_drvdata(file); - - pwc_isoc_cleanup(pdev); - return 0; -} - -static int pwc_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - struct pwc_device *pdev = video_drvdata(file); - unsigned int i = 0, index = fsize->index; - - if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { - for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1UL << i)) { - if (!index--) { - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pwc_image_sizes[i].x; - fsize->discrete.height = pwc_image_sizes[i].y; - return 0; - } - } - } - } else if (fsize->index == 0 && - ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || - (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pdev->abs_max.x; - fsize->discrete.height = pdev->abs_max.y; - return 0; - } - return -EINVAL; -} - -static int pwc_enum_frameintervals(struct file *file, void *fh, - struct v4l2_frmivalenum *fival) -{ - struct pwc_device *pdev = video_drvdata(file); - int size = -1; - unsigned int i; - - for (i = 0; i < PSZ_MAX; i++) { - if (pwc_image_sizes[i].x == fival->width && - pwc_image_sizes[i].y == fival->height) { - size = i; - break; - } - } - - /* TODO: Support raw format */ - if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) - return -EINVAL; - - i = pwc_get_fps(pdev, fival->index, size); - if (!i) - return -EINVAL; - - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete.numerator = 1; - fival->discrete.denominator = i; - - return 0; -} - -static long pwc_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) -{ - struct pwc_device *pdev = video_drvdata(file); - - return pwc_ioctl(pdev, cmd, arg); -} - -const struct v4l2_ioctl_ops pwc_ioctl_ops = { - .vidioc_querycap = pwc_querycap, - .vidioc_enum_input = pwc_enum_input, - .vidioc_g_input = pwc_g_input, - .vidioc_s_input = pwc_s_input, - .vidioc_enum_fmt_vid_cap = pwc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap, - .vidioc_queryctrl = pwc_queryctrl, - .vidioc_g_ctrl = pwc_g_ctrl, - .vidioc_s_ctrl = pwc_s_ctrl, - .vidioc_reqbufs = pwc_reqbufs, - .vidioc_querybuf = pwc_querybuf, - .vidioc_qbuf = pwc_qbuf, - .vidioc_dqbuf = pwc_dqbuf, - .vidioc_streamon = pwc_streamon, - .vidioc_streamoff = pwc_streamoff, - .vidioc_enum_framesizes = pwc_enum_framesizes, - .vidioc_enum_frameintervals = pwc_enum_frameintervals, - .vidioc_default = pwc_default, -}; - - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pxa_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pxa_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pxa_camera.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/pxa_camera.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1850 +0,0 @@ -/* - * V4L2 Driver for PXA camera host - * - * Copyright (C) 2006, Sascha Hauer, Pengutronix - * Copyright (C) 2008, Guennadi Liakhovetski - * - * 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, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) -#define PXA_CAM_DRV_NAME "pxa27x-camera" - -/* Camera Interface */ -#define CICR0 0x0000 -#define CICR1 0x0004 -#define CICR2 0x0008 -#define CICR3 0x000C -#define CICR4 0x0010 -#define CISR 0x0014 -#define CIFR 0x0018 -#define CITOR 0x001C -#define CIBR0 0x0028 -#define CIBR1 0x0030 -#define CIBR2 0x0038 - -#define CICR0_DMAEN (1 << 31) /* DMA request enable */ -#define CICR0_PAR_EN (1 << 30) /* Parity enable */ -#define CICR0_SL_CAP_EN (1 << 29) /* Capture enable for slave mode */ -#define CICR0_ENB (1 << 28) /* Camera interface enable */ -#define CICR0_DIS (1 << 27) /* Camera interface disable */ -#define CICR0_SIM (0x7 << 24) /* Sensor interface mode mask */ -#define CICR0_TOM (1 << 9) /* Time-out mask */ -#define CICR0_RDAVM (1 << 8) /* Receive-data-available mask */ -#define CICR0_FEM (1 << 7) /* FIFO-empty mask */ -#define CICR0_EOLM (1 << 6) /* End-of-line mask */ -#define CICR0_PERRM (1 << 5) /* Parity-error mask */ -#define CICR0_QDM (1 << 4) /* Quick-disable mask */ -#define CICR0_CDM (1 << 3) /* Disable-done mask */ -#define CICR0_SOFM (1 << 2) /* Start-of-frame mask */ -#define CICR0_EOFM (1 << 1) /* End-of-frame mask */ -#define CICR0_FOM (1 << 0) /* FIFO-overrun mask */ - -#define CICR1_TBIT (1 << 31) /* Transparency bit */ -#define CICR1_RGBT_CONV (0x3 << 29) /* RGBT conversion mask */ -#define CICR1_PPL (0x7ff << 15) /* Pixels per line mask */ -#define CICR1_RGB_CONV (0x7 << 12) /* RGB conversion mask */ -#define CICR1_RGB_F (1 << 11) /* RGB format */ -#define CICR1_YCBCR_F (1 << 10) /* YCbCr format */ -#define CICR1_RGB_BPP (0x7 << 7) /* RGB bis per pixel mask */ -#define CICR1_RAW_BPP (0x3 << 5) /* Raw bis per pixel mask */ -#define CICR1_COLOR_SP (0x3 << 3) /* Color space mask */ -#define CICR1_DW (0x7 << 0) /* Data width mask */ - -#define CICR2_BLW (0xff << 24) /* Beginning-of-line pixel clock - wait count mask */ -#define CICR2_ELW (0xff << 16) /* End-of-line pixel clock - wait count mask */ -#define CICR2_HSW (0x3f << 10) /* Horizontal sync pulse width mask */ -#define CICR2_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock - wait count mask */ -#define CICR2_FSW (0x7 << 0) /* Frame stabilization - wait count mask */ - -#define CICR3_BFW (0xff << 24) /* Beginning-of-frame line clock - wait count mask */ -#define CICR3_EFW (0xff << 16) /* End-of-frame line clock - wait count mask */ -#define CICR3_VSW (0x3f << 10) /* Vertical sync pulse width mask */ -#define CICR3_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock - wait count mask */ -#define CICR3_LPF (0x7ff << 0) /* Lines per frame mask */ - -#define CICR4_MCLK_DLY (0x3 << 24) /* MCLK Data Capture Delay mask */ -#define CICR4_PCLK_EN (1 << 23) /* Pixel clock enable */ -#define CICR4_PCP (1 << 22) /* Pixel clock polarity */ -#define CICR4_HSP (1 << 21) /* Horizontal sync polarity */ -#define CICR4_VSP (1 << 20) /* Vertical sync polarity */ -#define CICR4_MCLK_EN (1 << 19) /* MCLK enable */ -#define CICR4_FR_RATE (0x7 << 8) /* Frame rate mask */ -#define CICR4_DIV (0xff << 0) /* Clock divisor mask */ - -#define CISR_FTO (1 << 15) /* FIFO time-out */ -#define CISR_RDAV_2 (1 << 14) /* Channel 2 receive data available */ -#define CISR_RDAV_1 (1 << 13) /* Channel 1 receive data available */ -#define CISR_RDAV_0 (1 << 12) /* Channel 0 receive data available */ -#define CISR_FEMPTY_2 (1 << 11) /* Channel 2 FIFO empty */ -#define CISR_FEMPTY_1 (1 << 10) /* Channel 1 FIFO empty */ -#define CISR_FEMPTY_0 (1 << 9) /* Channel 0 FIFO empty */ -#define CISR_EOL (1 << 8) /* End of line */ -#define CISR_PAR_ERR (1 << 7) /* Parity error */ -#define CISR_CQD (1 << 6) /* Camera interface quick disable */ -#define CISR_CDD (1 << 5) /* Camera interface disable done */ -#define CISR_SOF (1 << 4) /* Start of frame */ -#define CISR_EOF (1 << 3) /* End of frame */ -#define CISR_IFO_2 (1 << 2) /* FIFO overrun for Channel 2 */ -#define CISR_IFO_1 (1 << 1) /* FIFO overrun for Channel 1 */ -#define CISR_IFO_0 (1 << 0) /* FIFO overrun for Channel 0 */ - -#define CIFR_FLVL2 (0x7f << 23) /* FIFO 2 level mask */ -#define CIFR_FLVL1 (0x7f << 16) /* FIFO 1 level mask */ -#define CIFR_FLVL0 (0xff << 8) /* FIFO 0 level mask */ -#define CIFR_THL_0 (0x3 << 4) /* Threshold Level for Channel 0 FIFO */ -#define CIFR_RESET_F (1 << 3) /* Reset input FIFOs */ -#define CIFR_FEN2 (1 << 2) /* FIFO enable for channel 2 */ -#define CIFR_FEN1 (1 << 1) /* FIFO enable for channel 1 */ -#define CIFR_FEN0 (1 << 0) /* FIFO enable for channel 0 */ - -#define CICR0_SIM_MP (0 << 24) -#define CICR0_SIM_SP (1 << 24) -#define CICR0_SIM_MS (2 << 24) -#define CICR0_SIM_EP (3 << 24) -#define CICR0_SIM_ES (4 << 24) - -#define CICR1_DW_VAL(x) ((x) & CICR1_DW) /* Data bus width */ -#define CICR1_PPL_VAL(x) (((x) << 15) & CICR1_PPL) /* Pixels per line */ -#define CICR1_COLOR_SP_VAL(x) (((x) << 3) & CICR1_COLOR_SP) /* color space */ -#define CICR1_RGB_BPP_VAL(x) (((x) << 7) & CICR1_RGB_BPP) /* bpp for rgb */ -#define CICR1_RGBT_CONV_VAL(x) (((x) << 29) & CICR1_RGBT_CONV) /* rgbt conv */ - -#define CICR2_BLW_VAL(x) (((x) << 24) & CICR2_BLW) /* Beginning-of-line pixel clock wait count */ -#define CICR2_ELW_VAL(x) (((x) << 16) & CICR2_ELW) /* End-of-line pixel clock wait count */ -#define CICR2_HSW_VAL(x) (((x) << 10) & CICR2_HSW) /* Horizontal sync pulse width */ -#define CICR2_BFPW_VAL(x) (((x) << 3) & CICR2_BFPW) /* Beginning-of-frame pixel clock wait count */ -#define CICR2_FSW_VAL(x) (((x) << 0) & CICR2_FSW) /* Frame stabilization wait count */ - -#define CICR3_BFW_VAL(x) (((x) << 24) & CICR3_BFW) /* Beginning-of-frame line clock wait count */ -#define CICR3_EFW_VAL(x) (((x) << 16) & CICR3_EFW) /* End-of-frame line clock wait count */ -#define CICR3_VSW_VAL(x) (((x) << 11) & CICR3_VSW) /* Vertical sync pulse width */ -#define CICR3_LPF_VAL(x) (((x) << 0) & CICR3_LPF) /* Lines per frame */ - -#define CICR0_IRQ_MASK (CICR0_TOM | CICR0_RDAVM | CICR0_FEM | CICR0_EOLM | \ - CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \ - CICR0_EOFM | CICR0_FOM) - -/* - * Structures - */ -enum pxa_camera_active_dma { - DMA_Y = 0x1, - DMA_U = 0x2, - DMA_V = 0x4, -}; - -/* descriptor needed for the PXA DMA engine */ -struct pxa_cam_dma { - dma_addr_t sg_dma; - struct pxa_dma_desc *sg_cpu; - size_t sg_size; - int sglen; -}; - -/* buffer for one video frame */ -struct pxa_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - enum v4l2_mbus_pixelcode code; - /* our descriptor lists for Y, U and V channels */ - struct pxa_cam_dma dmas[3]; - int inwork; - enum pxa_camera_active_dma active_dma; -}; - -struct pxa_camera_dev { - struct soc_camera_host soc_host; - /* - * PXA27x is only supposed to handle one camera on its Quick Capture - * interface. If anyone ever builds hardware to enable more than - * one camera, they will have to modify this driver too - */ - struct soc_camera_device *icd; - struct clk *clk; - - unsigned int irq; - void __iomem *base; - - int channels; - unsigned int dma_chans[3]; - - struct pxacamera_platform_data *pdata; - struct resource *res; - unsigned long platform_flags; - unsigned long ciclk; - unsigned long mclk; - u32 mclk_divisor; - - struct list_head capture; - - spinlock_t lock; - - struct pxa_buffer *active; - struct pxa_dma_desc *sg_tail[3]; - - u32 save_cicr[5]; -}; - -struct pxa_cam { - unsigned long flags; -}; - -static const char *pxa_cam_driver_description = "PXA_Camera"; - -static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ - -/* - * Videobuf operations - */ -static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct soc_camera_device *icd = vq->priv_data; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - if (bytes_per_line < 0) - return bytes_per_line; - - dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); - - *size = bytes_per_line * icd->user_height; - - if (0 == *count) - *count = 32; - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) -{ - struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - int i; - - BUG_ON(in_interrupt()); - - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - &buf->vb, buf->vb.baddr, buf->vb.bsize); - - /* - * This waits until this buffer is out of danger, i.e., until it is no - * longer in STATE_QUEUED or STATE_ACTIVE - */ - videobuf_waiton(vq, &buf->vb, 0, 0); - videobuf_dma_unmap(vq->dev, dma); - videobuf_dma_free(dma); - - for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) { - if (buf->dmas[i].sg_cpu) - dma_free_coherent(ici->v4l2_dev.dev, - buf->dmas[i].sg_size, - buf->dmas[i].sg_cpu, - buf->dmas[i].sg_dma); - buf->dmas[i].sg_cpu = NULL; - } - - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int calculate_dma_sglen(struct scatterlist *sglist, int sglen, - int sg_first_ofs, int size) -{ - int i, offset, dma_len, xfer_len; - struct scatterlist *sg; - - offset = sg_first_ofs; - for_each_sg(sglist, sg, sglen, i) { - dma_len = sg_dma_len(sg); - - /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */ - xfer_len = roundup(min(dma_len - offset, size), 8); - - size = max(0, size - xfer_len); - offset = 0; - if (size == 0) - break; - } - - BUG_ON(size != 0); - return i + 1; -} - -/** - * pxa_init_dma_channel - init dma descriptors - * @pcdev: pxa camera device - * @buf: pxa buffer to find pxa dma channel - * @dma: dma video buffer - * @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V') - * @cibr: camera Receive Buffer Register - * @size: bytes to transfer - * @sg_first: first element of sg_list - * @sg_first_ofs: offset in first element of sg_list - * - * Prepares the pxa dma descriptors to transfer one camera channel. - * Beware sg_first and sg_first_ofs are both input and output parameters. - * - * Returns 0 or -ENOMEM if no coherent memory is available - */ -static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, - struct pxa_buffer *buf, - struct videobuf_dmabuf *dma, int channel, - int cibr, int size, - struct scatterlist **sg_first, int *sg_first_ofs) -{ - struct pxa_cam_dma *pxa_dma = &buf->dmas[channel]; - struct device *dev = pcdev->soc_host.v4l2_dev.dev; - struct scatterlist *sg; - int i, offset, sglen; - int dma_len = 0, xfer_len = 0; - - if (pxa_dma->sg_cpu) - dma_free_coherent(dev, pxa_dma->sg_size, - pxa_dma->sg_cpu, pxa_dma->sg_dma); - - sglen = calculate_dma_sglen(*sg_first, dma->sglen, - *sg_first_ofs, size); - - pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc); - pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size, - &pxa_dma->sg_dma, GFP_KERNEL); - if (!pxa_dma->sg_cpu) - return -ENOMEM; - - pxa_dma->sglen = sglen; - offset = *sg_first_ofs; - - dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n", - *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma); - - - for_each_sg(*sg_first, sg, sglen, i) { - dma_len = sg_dma_len(sg); - - /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */ - xfer_len = roundup(min(dma_len - offset, size), 8); - - size = max(0, size - xfer_len); - - pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr; - pxa_dma->sg_cpu[i].dtadr = sg_dma_address(sg) + offset; - pxa_dma->sg_cpu[i].dcmd = - DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len; -#ifdef DEBUG - if (!i) - pxa_dma->sg_cpu[i].dcmd |= DCMD_STARTIRQEN; -#endif - pxa_dma->sg_cpu[i].ddadr = - pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); - - dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n", - pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc), - sg_dma_address(sg) + offset, xfer_len); - offset = 0; - - if (size == 0) - break; - } - - pxa_dma->sg_cpu[sglen].ddadr = DDADR_STOP; - pxa_dma->sg_cpu[sglen].dcmd = DCMD_FLOWSRC | DCMD_BURST8 | DCMD_ENDIRQEN; - - /* - * Handle 1 special case : - * - in 3 planes (YUV422P format), we might finish with xfer_len equal - * to dma_len (end on PAGE boundary). In this case, the sg element - * for next plane should be the next after the last used to store the - * last scatter gather RAM page - */ - if (xfer_len >= dma_len) { - *sg_first_ofs = xfer_len - dma_len; - *sg_first = sg_next(sg); - } else { - *sg_first_ofs = xfer_len; - *sg_first = sg; - } - - return 0; -} - -static void pxa_videobuf_set_actdma(struct pxa_camera_dev *pcdev, - struct pxa_buffer *buf) -{ - buf->active_dma = DMA_Y; - if (pcdev->channels == 3) - buf->active_dma |= DMA_U | DMA_V; -} - -/* - * Please check the DMA prepared buffer structure in : - * Documentation/video4linux/pxa_camera.txt - * Please check also in pxa_camera_check_link_miss() to understand why DMA chain - * modification while DMA chain is running will work anyway. - */ -static int pxa_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - struct device *dev = pcdev->soc_host.v4l2_dev.dev; - struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); - int ret; - int size_y, size_u = 0, size_v = 0; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - if (bytes_per_line < 0) - return bytes_per_line; - - dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - /* Added list head initialization on alloc */ - WARN_ON(!list_empty(&vb->queue)); - -#ifdef DEBUG - /* - * This can be useful if you want to see if we actually fill - * the buffer with something - */ - memset((void *)vb->baddr, 0xaa, vb->bsize); -#endif - - BUG_ON(NULL == icd->current_fmt); - - /* - * I think, in buf_prepare you only have to protect global data, - * the actual buffer is yours - */ - buf->inwork = 1; - - if (buf->code != icd->current_fmt->code || - vb->width != icd->user_width || - vb->height != icd->user_height || - vb->field != field) { - buf->code = icd->current_fmt->code; - vb->width = icd->user_width; - vb->height = icd->user_height; - vb->field = field; - vb->state = VIDEOBUF_NEEDS_INIT; - } - - vb->size = bytes_per_line * vb->height; - if (0 != vb->baddr && vb->bsize < vb->size) { - ret = -EINVAL; - goto out; - } - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - int size = vb->size; - int next_ofs = 0; - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - struct scatterlist *sg; - - ret = videobuf_iolock(vq, vb, NULL); - if (ret) - goto fail; - - if (pcdev->channels == 3) { - size_y = size / 2; - size_u = size_v = size / 4; - } else { - size_y = size; - } - - sg = dma->sglist; - - /* init DMA for Y channel */ - ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y, - &sg, &next_ofs); - if (ret) { - dev_err(dev, "DMA initialization for Y/RGB failed\n"); - goto fail; - } - - /* init DMA for U channel */ - if (size_u) - ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1, - size_u, &sg, &next_ofs); - if (ret) { - dev_err(dev, "DMA initialization for U failed\n"); - goto fail_u; - } - - /* init DMA for V channel */ - if (size_v) - ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2, - size_v, &sg, &next_ofs); - if (ret) { - dev_err(dev, "DMA initialization for V failed\n"); - goto fail_v; - } - - vb->state = VIDEOBUF_PREPARED; - } - - buf->inwork = 0; - pxa_videobuf_set_actdma(pcdev, buf); - - return 0; - -fail_v: - dma_free_coherent(dev, buf->dmas[1].sg_size, - buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma); -fail_u: - dma_free_coherent(dev, buf->dmas[0].sg_size, - buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma); -fail: - free_buffer(vq, buf); -out: - buf->inwork = 0; - return ret; -} - -/** - * pxa_dma_start_channels - start DMA channel for active buffer - * @pcdev: pxa camera device - * - * Initialize DMA channels to the beginning of the active video buffer, and - * start these channels. - */ -static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) -{ - int i; - struct pxa_buffer *active; - - active = pcdev->active; - - for (i = 0; i < pcdev->channels; i++) { - dev_dbg(pcdev->soc_host.v4l2_dev.dev, - "%s (channel=%d) ddadr=%08x\n", __func__, - i, active->dmas[i].sg_dma); - DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma; - DCSR(pcdev->dma_chans[i]) = DCSR_RUN; - } -} - -static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev) -{ - int i; - - for (i = 0; i < pcdev->channels; i++) { - dev_dbg(pcdev->soc_host.v4l2_dev.dev, - "%s (channel=%d)\n", __func__, i); - DCSR(pcdev->dma_chans[i]) = 0; - } -} - -static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev, - struct pxa_buffer *buf) -{ - int i; - struct pxa_dma_desc *buf_last_desc; - - for (i = 0; i < pcdev->channels; i++) { - buf_last_desc = buf->dmas[i].sg_cpu + buf->dmas[i].sglen; - buf_last_desc->ddadr = DDADR_STOP; - - if (pcdev->sg_tail[i]) - /* Link the new buffer to the old tail */ - pcdev->sg_tail[i]->ddadr = buf->dmas[i].sg_dma; - - /* Update the channel tail */ - pcdev->sg_tail[i] = buf_last_desc; - } -} - -/** - * pxa_camera_start_capture - start video capturing - * @pcdev: camera device - * - * Launch capturing. DMA channels should not be active yet. They should get - * activated at the end of frame interrupt, to capture only whole frames, and - * never begin the capture of a partial frame. - */ -static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev) -{ - unsigned long cicr0; - - dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__); - /* Enable End-Of-Frame Interrupt */ - cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB; - cicr0 &= ~CICR0_EOFM; - __raw_writel(cicr0, pcdev->base + CICR0); -} - -static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) -{ - unsigned long cicr0; - - pxa_dma_stop_channels(pcdev); - - cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB; - __raw_writel(cicr0, pcdev->base + CICR0); - - pcdev->active = NULL; - dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__); -} - -/* Called under spinlock_irqsave(&pcdev->lock, ...) */ -static void pxa_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); - - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n", - __func__, vb, vb->baddr, vb->bsize, pcdev->active); - - list_add_tail(&vb->queue, &pcdev->capture); - - vb->state = VIDEOBUF_ACTIVE; - pxa_dma_add_tail_buf(pcdev, buf); - - if (!pcdev->active) - pxa_camera_start_capture(pcdev); -} - -static void pxa_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); -#ifdef DEBUG - struct soc_camera_device *icd = vq->priv_data; - struct device *dev = icd->dev.parent; - - dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - switch (vb->state) { - case VIDEOBUF_ACTIVE: - dev_dbg(dev, "%s (active)\n", __func__); - break; - case VIDEOBUF_QUEUED: - dev_dbg(dev, "%s (queued)\n", __func__); - break; - case VIDEOBUF_PREPARED: - dev_dbg(dev, "%s (prepared)\n", __func__); - break; - default: - dev_dbg(dev, "%s (unknown)\n", __func__); - break; - } -#endif - - free_buffer(vq, buf); -} - -static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, - struct videobuf_buffer *vb, - struct pxa_buffer *buf) -{ - int i; - - /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ - list_del_init(&vb->queue); - vb->state = VIDEOBUF_DONE; - do_gettimeofday(&vb->ts); - vb->field_count++; - wake_up(&vb->done); - dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s dequeud buffer (vb=0x%p)\n", - __func__, vb); - - if (list_empty(&pcdev->capture)) { - pxa_camera_stop_capture(pcdev); - for (i = 0; i < pcdev->channels; i++) - pcdev->sg_tail[i] = NULL; - return; - } - - pcdev->active = list_entry(pcdev->capture.next, - struct pxa_buffer, vb.queue); -} - -/** - * pxa_camera_check_link_miss - check missed DMA linking - * @pcdev: camera device - * - * The DMA chaining is done with DMA running. This means a tiny temporal window - * remains, where a buffer is queued on the chain, while the chain is already - * stopped. This means the tailed buffer would never be transfered by DMA. - * This function restarts the capture for this corner case, where : - * - DADR() == DADDR_STOP - * - a videobuffer is queued on the pcdev->capture list - * - * Please check the "DMA hot chaining timeslice issue" in - * Documentation/video4linux/pxa_camera.txt - * - * Context: should only be called within the dma irq handler - */ -static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev) -{ - int i, is_dma_stopped = 1; - - for (i = 0; i < pcdev->channels; i++) - if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP) - is_dma_stopped = 0; - dev_dbg(pcdev->soc_host.v4l2_dev.dev, - "%s : top queued buffer=%p, dma_stopped=%d\n", - __func__, pcdev->active, is_dma_stopped); - if (pcdev->active && is_dma_stopped) - pxa_camera_start_capture(pcdev); -} - -static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, - enum pxa_camera_active_dma act_dma) -{ - struct device *dev = pcdev->soc_host.v4l2_dev.dev; - struct pxa_buffer *buf; - unsigned long flags; - u32 status, camera_status, overrun; - struct videobuf_buffer *vb; - - spin_lock_irqsave(&pcdev->lock, flags); - - status = DCSR(channel); - DCSR(channel) = status; - - camera_status = __raw_readl(pcdev->base + CISR); - overrun = CISR_IFO_0; - if (pcdev->channels == 3) - overrun |= CISR_IFO_1 | CISR_IFO_2; - - if (status & DCSR_BUSERR) { - dev_err(dev, "DMA Bus Error IRQ!\n"); - goto out; - } - - if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) { - dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n", - status); - goto out; - } - - /* - * pcdev->active should not be NULL in DMA irq handler. - * - * But there is one corner case : if capture was stopped due to an - * overrun of channel 1, and at that same channel 2 was completed. - * - * When handling the overrun in DMA irq for channel 1, we'll stop the - * capture and restart it (and thus set pcdev->active to NULL). But the - * DMA irq handler will already be pending for channel 2. So on entering - * the DMA irq handler for channel 2 there will be no active buffer, yet - * that is normal. - */ - if (!pcdev->active) - goto out; - - vb = &pcdev->active->vb; - buf = container_of(vb, struct pxa_buffer, vb); - WARN_ON(buf->inwork || list_empty(&vb->queue)); - - dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", - __func__, channel, status & DCSR_STARTINTR ? "SOF " : "", - status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel)); - - if (status & DCSR_ENDINTR) { - /* - * It's normal if the last frame creates an overrun, as there - * are no more DMA descriptors to fetch from QCI fifos - */ - if (camera_status & overrun && - !list_is_last(pcdev->capture.next, &pcdev->capture)) { - dev_dbg(dev, "FIFO overrun! CISR: %x\n", - camera_status); - pxa_camera_stop_capture(pcdev); - pxa_camera_start_capture(pcdev); - goto out; - } - buf->active_dma &= ~act_dma; - if (!buf->active_dma) { - pxa_camera_wakeup(pcdev, vb, buf); - pxa_camera_check_link_miss(pcdev); - } - } - -out: - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static void pxa_camera_dma_irq_y(int channel, void *data) -{ - struct pxa_camera_dev *pcdev = data; - pxa_camera_dma_irq(channel, pcdev, DMA_Y); -} - -static void pxa_camera_dma_irq_u(int channel, void *data) -{ - struct pxa_camera_dev *pcdev = data; - pxa_camera_dma_irq(channel, pcdev, DMA_U); -} - -static void pxa_camera_dma_irq_v(int channel, void *data) -{ - struct pxa_camera_dev *pcdev = data; - pxa_camera_dma_irq(channel, pcdev, DMA_V); -} - -static struct videobuf_queue_ops pxa_videobuf_ops = { - .buf_setup = pxa_videobuf_setup, - .buf_prepare = pxa_videobuf_prepare, - .buf_queue = pxa_videobuf_queue, - .buf_release = pxa_videobuf_release, -}; - -static void pxa_camera_init_videobuf(struct videobuf_queue *q, - struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - - /* - * We must pass NULL as dev pointer, then all pci_* dma operations - * transform to normal dma_* ones. - */ - videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct pxa_buffer), icd, &icd->video_lock); -} - -static u32 mclk_get_divisor(struct platform_device *pdev, - struct pxa_camera_dev *pcdev) -{ - unsigned long mclk = pcdev->mclk; - struct device *dev = &pdev->dev; - u32 div; - unsigned long lcdclk; - - lcdclk = clk_get_rate(pcdev->clk); - pcdev->ciclk = lcdclk; - - /* mclk <= ciclk / 4 (27.4.2) */ - if (mclk > lcdclk / 4) { - mclk = lcdclk / 4; - dev_warn(dev, "Limiting master clock to %lu\n", mclk); - } - - /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ - div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; - - /* If we're not supplying MCLK, leave it at 0 */ - if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) - pcdev->mclk = lcdclk / (2 * (div + 1)); - - dev_dbg(dev, "LCD clock %luHz, target freq %luHz, divisor %u\n", - lcdclk, mclk, div); - - return div; -} - -static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev, - unsigned long pclk) -{ - /* We want a timeout > 1 pixel time, not ">=" */ - u32 ciclk_per_pixel = pcdev->ciclk / pclk + 1; - - __raw_writel(ciclk_per_pixel, pcdev->base + CITOR); -} - -static void pxa_camera_activate(struct pxa_camera_dev *pcdev) -{ - u32 cicr4 = 0; - - /* disable all interrupts */ - __raw_writel(0x3ff, pcdev->base + CICR0); - - if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) - cicr4 |= CICR4_PCLK_EN; - if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) - cicr4 |= CICR4_MCLK_EN; - if (pcdev->platform_flags & PXA_CAMERA_PCP) - cicr4 |= CICR4_PCP; - if (pcdev->platform_flags & PXA_CAMERA_HSP) - cicr4 |= CICR4_HSP; - if (pcdev->platform_flags & PXA_CAMERA_VSP) - cicr4 |= CICR4_VSP; - - __raw_writel(pcdev->mclk_divisor | cicr4, pcdev->base + CICR4); - - if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) - /* Initialise the timeout under the assumption pclk = mclk */ - recalculate_fifo_timeout(pcdev, pcdev->mclk); - else - /* "Safe default" - 13MHz */ - recalculate_fifo_timeout(pcdev, 13000000); - - clk_enable(pcdev->clk); -} - -static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) -{ - clk_disable(pcdev->clk); -} - -static irqreturn_t pxa_camera_irq(int irq, void *data) -{ - struct pxa_camera_dev *pcdev = data; - unsigned long status, cifr, cicr0; - struct pxa_buffer *buf; - struct videobuf_buffer *vb; - - status = __raw_readl(pcdev->base + CISR); - dev_dbg(pcdev->soc_host.v4l2_dev.dev, - "Camera interrupt status 0x%lx\n", status); - - if (!status) - return IRQ_NONE; - - __raw_writel(status, pcdev->base + CISR); - - if (status & CISR_EOF) { - /* Reset the FIFOs */ - cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; - __raw_writel(cifr, pcdev->base + CIFR); - - pcdev->active = list_first_entry(&pcdev->capture, - struct pxa_buffer, vb.queue); - vb = &pcdev->active->vb; - buf = container_of(vb, struct pxa_buffer, vb); - pxa_videobuf_set_actdma(pcdev, buf); - - pxa_dma_start_channels(pcdev); - - cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; - __raw_writel(cicr0, pcdev->base + CICR0); - } - - return IRQ_HANDLED; -} - -/* - * The following two functions absolutely depend on the fact, that - * there can be only one camera on PXA quick capture interface - * Called with .video_lock held - */ -static int pxa_camera_add_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - - if (pcdev->icd) - return -EBUSY; - - pxa_camera_activate(pcdev); - - pcdev->icd = icd; - - dev_info(icd->dev.parent, "PXA Camera driver attached to camera %d\n", - icd->devnum); - - return 0; -} - -/* Called with .video_lock held */ -static void pxa_camera_remove_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - - BUG_ON(icd != pcdev->icd); - - dev_info(icd->dev.parent, "PXA Camera driver detached from camera %d\n", - icd->devnum); - - /* disable capture, disable interrupts */ - __raw_writel(0x3ff, pcdev->base + CICR0); - - /* Stop DMA engine */ - DCSR(pcdev->dma_chans[0]) = 0; - DCSR(pcdev->dma_chans[1]) = 0; - DCSR(pcdev->dma_chans[2]) = 0; - - pxa_camera_deactivate(pcdev); - - pcdev->icd = NULL; -} - -static int test_platform_param(struct pxa_camera_dev *pcdev, - unsigned char buswidth, unsigned long *flags) -{ - /* - * Platform specified synchronization and pixel clock polarities are - * only a recommendation and are only used during probing. The PXA270 - * quick capture interface supports both. - */ - *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? - SOCAM_MASTER : SOCAM_SLAVE) | - SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH | - SOCAM_PCLK_SAMPLE_RISING | - SOCAM_PCLK_SAMPLE_FALLING; - - /* If requested data width is supported by the platform, use it */ - switch (buswidth) { - case 10: - if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)) - return -EINVAL; - *flags |= SOCAM_DATAWIDTH_10; - break; - case 9: - if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9)) - return -EINVAL; - *flags |= SOCAM_DATAWIDTH_9; - break; - case 8: - if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) - return -EINVAL; - *flags |= SOCAM_DATAWIDTH_8; - break; - default: - return -EINVAL; - } - - return 0; -} - -static void pxa_camera_setup_cicr(struct soc_camera_device *icd, - unsigned long flags, __u32 pixfmt) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - unsigned long dw, bpp; - u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0, y_skip_top; - int ret = v4l2_subdev_call(sd, sensor, g_skip_top_lines, &y_skip_top); - - if (ret < 0) - y_skip_top = 0; - - /* - * Datawidth is now guaranteed to be equal to one of the three values. - * We fix bit-per-pixel equal to data-width... - */ - switch (flags & SOCAM_DATAWIDTH_MASK) { - case SOCAM_DATAWIDTH_10: - dw = 4; - bpp = 0x40; - break; - case SOCAM_DATAWIDTH_9: - dw = 3; - bpp = 0x20; - break; - default: - /* - * Actually it can only be 8 now, - * default is just to silence compiler warnings - */ - case SOCAM_DATAWIDTH_8: - dw = 2; - bpp = 0; - } - - if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) - cicr4 |= CICR4_PCLK_EN; - if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) - cicr4 |= CICR4_MCLK_EN; - if (flags & SOCAM_PCLK_SAMPLE_FALLING) - cicr4 |= CICR4_PCP; - if (flags & SOCAM_HSYNC_ACTIVE_LOW) - cicr4 |= CICR4_HSP; - if (flags & SOCAM_VSYNC_ACTIVE_LOW) - cicr4 |= CICR4_VSP; - - cicr0 = __raw_readl(pcdev->base + CICR0); - if (cicr0 & CICR0_ENB) - __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0); - - cicr1 = CICR1_PPL_VAL(icd->user_width - 1) | bpp | dw; - - switch (pixfmt) { - case V4L2_PIX_FMT_YUV422P: - pcdev->channels = 3; - cicr1 |= CICR1_YCBCR_F; - /* - * Normally, pxa bus wants as input UYVY format. We allow all - * reorderings of the YUV422 format, as no processing is done, - * and the YUV stream is just passed through without any - * transformation. Note that UYVY is the only format that - * should be used if pxa framebuffer Overlay2 is used. - */ - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - cicr1 |= CICR1_COLOR_SP_VAL(2); - break; - case V4L2_PIX_FMT_RGB555: - cicr1 |= CICR1_RGB_BPP_VAL(1) | CICR1_RGBT_CONV_VAL(2) | - CICR1_TBIT | CICR1_COLOR_SP_VAL(1); - break; - case V4L2_PIX_FMT_RGB565: - cicr1 |= CICR1_COLOR_SP_VAL(1) | CICR1_RGB_BPP_VAL(2); - break; - } - - cicr2 = 0; - cicr3 = CICR3_LPF_VAL(icd->user_height - 1) | - CICR3_BFW_VAL(min((u32)255, y_skip_top)); - cicr4 |= pcdev->mclk_divisor; - - __raw_writel(cicr1, pcdev->base + CICR1); - __raw_writel(cicr2, pcdev->base + CICR2); - __raw_writel(cicr3, pcdev->base + CICR3); - __raw_writel(cicr4, pcdev->base + CICR4); - - /* CIF interrupts are not used, only DMA */ - cicr0 = (cicr0 & CICR0_ENB) | (pcdev->platform_flags & PXA_CAMERA_MASTER ? - CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)); - cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK; - __raw_writel(cicr0, pcdev->base + CICR0); -} - -static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - unsigned long bus_flags, camera_flags, common_flags; - const struct soc_mbus_pixelfmt *fmt; - int ret; - struct pxa_cam *cam = icd->host_priv; - - fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); - if (!fmt) - return -EINVAL; - - ret = test_platform_param(pcdev, fmt->bits_per_sample, &bus_flags); - if (ret < 0) - return ret; - - camera_flags = icd->ops->query_bus_param(icd); - - common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); - if (!common_flags) - return -EINVAL; - - pcdev->channels = 1; - - /* Make choises, based on platform preferences */ - if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { - if (pcdev->platform_flags & PXA_CAMERA_HSP) - common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; - else - common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; - } - - if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { - if (pcdev->platform_flags & PXA_CAMERA_VSP) - common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; - else - common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; - } - - if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && - (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { - if (pcdev->platform_flags & PXA_CAMERA_PCP) - common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; - else - common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; - } - - cam->flags = common_flags; - - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) - return ret; - - pxa_camera_setup_cicr(icd, common_flags, pixfmt); - - return 0; -} - -static int pxa_camera_try_bus_param(struct soc_camera_device *icd, - unsigned char buswidth) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - unsigned long bus_flags, camera_flags; - int ret = test_platform_param(pcdev, buswidth, &bus_flags); - - if (ret < 0) - return ret; - - camera_flags = icd->ops->query_bus_param(icd); - - return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; -} - -static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { - { - .fourcc = V4L2_PIX_FMT_YUV422P, - .name = "Planar YUV422 16 bit", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, -}; - -/* This will be corrected as we get more formats */ -static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) -{ - return fmt->packing == SOC_MBUS_PACKING_NONE || - (fmt->bits_per_sample == 8 && - fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || - (fmt->bits_per_sample > 8 && - fmt->packing == SOC_MBUS_PACKING_EXTEND16); -} - -static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, - struct soc_camera_format_xlate *xlate) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->dev.parent; - int formats = 0, ret; - struct pxa_cam *cam; - enum v4l2_mbus_pixelcode code; - const struct soc_mbus_pixelfmt *fmt; - - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); - if (ret < 0) - /* No more formats */ - return 0; - - fmt = soc_mbus_get_fmtdesc(code); - if (!fmt) { - dev_err(dev, "Invalid format code #%u: %d\n", idx, code); - return 0; - } - - /* This also checks support for the requested bits-per-sample */ - ret = pxa_camera_try_bus_param(icd, fmt->bits_per_sample); - if (ret < 0) - return 0; - - if (!icd->host_priv) { - cam = kzalloc(sizeof(*cam), GFP_KERNEL); - if (!cam) - return -ENOMEM; - - icd->host_priv = cam; - } else { - cam = icd->host_priv; - } - - switch (code) { - case V4L2_MBUS_FMT_UYVY8_2X8: - formats++; - if (xlate) { - xlate->host_fmt = &pxa_camera_formats[0]; - xlate->code = code; - xlate++; - dev_dbg(dev, "Providing format %s using code %d\n", - pxa_camera_formats[0].name, code); - } - case V4L2_MBUS_FMT_VYUY8_2X8: - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_YVYU8_2X8: - case V4L2_MBUS_FMT_RGB565_2X8_LE: - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: - if (xlate) - dev_dbg(dev, "Providing format %s packed\n", - fmt->name); - break; - default: - if (!pxa_camera_packing_supported(fmt)) - return 0; - if (xlate) - dev_dbg(dev, - "Providing format %s in pass-through mode\n", - fmt->name); - } - - /* Generic pass-through */ - formats++; - if (xlate) { - xlate->host_fmt = fmt; - xlate->code = code; - xlate++; - } - - return formats; -} - -static void pxa_camera_put_formats(struct soc_camera_device *icd) -{ - kfree(icd->host_priv); - icd->host_priv = NULL; -} - -static int pxa_camera_check_frame(u32 width, u32 height) -{ - /* limit to pxa hardware capabilities */ - return height < 32 || height > 2048 || width < 48 || width > 2048 || - (width & 0x01); -} - -static int pxa_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) -{ - struct v4l2_rect *rect = &a->c; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - struct device *dev = icd->dev.parent; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct soc_camera_sense sense = { - .master_clock = pcdev->mclk, - .pixel_clock_max = pcdev->ciclk / 4, - }; - struct v4l2_mbus_framefmt mf; - struct pxa_cam *cam = icd->host_priv; - u32 fourcc = icd->current_fmt->host_fmt->fourcc; - int ret; - - /* If PCLK is used to latch data from the sensor, check sense */ - if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) - icd->sense = &sense; - - ret = v4l2_subdev_call(sd, video, s_crop, a); - - icd->sense = NULL; - - if (ret < 0) { - dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n", - rect->width, rect->height, rect->left, rect->top); - return ret; - } - - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); - if (ret < 0) - return ret; - - if (pxa_camera_check_frame(mf.width, mf.height)) { - /* - * Camera cropping produced a frame beyond our capabilities. - * FIXME: just extract a subframe, that we can process. - */ - v4l_bound_align_image(&mf.width, 48, 2048, 1, - &mf.height, 32, 2048, 0, - fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); - if (ret < 0) - return ret; - - if (pxa_camera_check_frame(mf.width, mf.height)) { - dev_warn(icd->dev.parent, - "Inconsistent state. Use S_FMT to repair\n"); - return -EINVAL; - } - } - - if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { - if (sense.pixel_clock > sense.pixel_clock_max) { - dev_err(dev, - "pixel clock %lu set by the camera too high!", - sense.pixel_clock); - return -EIO; - } - recalculate_fifo_timeout(pcdev, sense.pixel_clock); - } - - icd->user_width = mf.width; - icd->user_height = mf.height; - - pxa_camera_setup_cicr(icd, cam->flags, fourcc); - - return ret; -} - -static int pxa_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - struct device *dev = icd->dev.parent; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate = NULL; - struct soc_camera_sense sense = { - .master_clock = pcdev->mclk, - .pixel_clock_max = pcdev->ciclk / 4, - }; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(dev, "Format %x not found\n", pix->pixelformat); - return -EINVAL; - } - - /* If PCLK is used to latch data from the sensor, check sense */ - if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) - /* The caller holds a mutex. */ - icd->sense = &sense; - - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); - - if (mf.code != xlate->code) - return -EINVAL; - - icd->sense = NULL; - - if (ret < 0) { - dev_warn(dev, "Failed to configure for format %x\n", - pix->pixelformat); - } else if (pxa_camera_check_frame(mf.width, mf.height)) { - dev_warn(dev, - "Camera driver produced an unsupported frame %dx%d\n", - mf.width, mf.height); - ret = -EINVAL; - } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { - if (sense.pixel_clock > sense.pixel_clock_max) { - dev_err(dev, - "pixel clock %lu set by the camera too high!", - sense.pixel_clock); - return -EIO; - } - recalculate_fifo_timeout(pcdev, sense.pixel_clock); - } - - if (ret < 0) - return ret; - - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; - icd->current_fmt = xlate; - - return ret; -} - -static int pxa_camera_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - __u32 pixfmt = pix->pixelformat; - int ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - /* - * Limit to pxa hardware capabilities. YUV422P planar format requires - * images size to be a multiple of 16 bytes. If not, zeros will be - * inserted between Y and U planes, and U and V planes, which violates - * the YUV422P standard. - */ - v4l_bound_align_image(&pix->width, 48, 2048, 1, - &pix->height, 32, 2048, 0, - pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); - - pix->bytesperline = soc_mbus_bytes_per_line(pix->width, - xlate->host_fmt); - if (pix->bytesperline < 0) - return pix->bytesperline; - pix->sizeimage = pix->height * pix->bytesperline; - - /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); - if (ret < 0) - return ret; - - pix->width = mf.width; - pix->height = mf.height; - pix->colorspace = mf.colorspace; - - switch (mf.field) { - case V4L2_FIELD_ANY: - case V4L2_FIELD_NONE: - pix->field = V4L2_FIELD_NONE; - break; - default: - /* TODO: support interlaced at least in pass-through mode */ - dev_err(icd->dev.parent, "Field type %d unsupported.\n", - mf.field); - return -EINVAL; - } - - return ret; -} - -static int pxa_camera_reqbufs(struct soc_camera_device *icd, - struct v4l2_requestbuffers *p) -{ - int i; - - /* - * This is for locking debugging only. I removed spinlocks and now I - * check whether .prepare is ever called on a linked buffer, or whether - * a dma IRQ can occur for an in-work or unlinked buffer. Until now - * it hadn't triggered - */ - for (i = 0; i < p->count; i++) { - struct pxa_buffer *buf = container_of(icd->vb_vidq.bufs[i], - struct pxa_buffer, vb); - buf->inwork = 0; - INIT_LIST_HEAD(&buf->vb.queue); - } - - return 0; -} - -static unsigned int pxa_camera_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - struct pxa_buffer *buf; - - buf = list_entry(icd->vb_vidq.stream.next, struct pxa_buffer, - vb.stream); - - poll_wait(file, &buf->vb.done, pt); - - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; - - return 0; -} - -static int pxa_camera_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - /* cap->name is set by the firendly caller:-> */ - strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); - cap->version = PXA_CAM_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - - return 0; -} - -static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - int i = 0, ret = 0; - - pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0); - pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR1); - pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR2); - pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3); - pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4); - - if ((pcdev->icd) && (pcdev->icd->ops->suspend)) - ret = pcdev->icd->ops->suspend(pcdev->icd, state); - - return ret; -} - -static int pxa_camera_resume(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - int i = 0, ret = 0; - - DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD; - DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; - DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD; - - __raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0); - __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR1); - __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR2); - __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3); - __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4); - - if ((pcdev->icd) && (pcdev->icd->ops->resume)) - ret = pcdev->icd->ops->resume(pcdev->icd); - - /* Restart frame capture if active buffer exists */ - if (!ret && pcdev->active) - pxa_camera_start_capture(pcdev); - - return ret; -} - -static struct soc_camera_host_ops pxa_soc_camera_host_ops = { - .owner = THIS_MODULE, - .add = pxa_camera_add_device, - .remove = pxa_camera_remove_device, - .suspend = pxa_camera_suspend, - .resume = pxa_camera_resume, - .set_crop = pxa_camera_set_crop, - .get_formats = pxa_camera_get_formats, - .put_formats = pxa_camera_put_formats, - .set_fmt = pxa_camera_set_fmt, - .try_fmt = pxa_camera_try_fmt, - .init_videobuf = pxa_camera_init_videobuf, - .reqbufs = pxa_camera_reqbufs, - .poll = pxa_camera_poll, - .querycap = pxa_camera_querycap, - .set_bus_param = pxa_camera_set_bus_param, -}; - -static int __devinit pxa_camera_probe(struct platform_device *pdev) -{ - struct pxa_camera_dev *pcdev; - struct resource *res; - void __iomem *base; - int irq; - int err = 0; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!res || irq < 0) { - err = -ENODEV; - goto exit; - } - - pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); - if (!pcdev) { - dev_err(&pdev->dev, "Could not allocate pcdev\n"); - err = -ENOMEM; - goto exit; - } - - pcdev->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(pcdev->clk)) { - err = PTR_ERR(pcdev->clk); - goto exit_kfree; - } - - pcdev->res = res; - - pcdev->pdata = pdev->dev.platform_data; - pcdev->platform_flags = pcdev->pdata->flags; - if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | - PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) { - /* - * Platform hasn't set available data widths. This is bad. - * Warn and use a default. - */ - dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " - "data widths, using default 10 bit\n"); - pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; - } - pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; - if (!pcdev->mclk) { - dev_warn(&pdev->dev, - "mclk == 0! Please, fix your platform data. " - "Using default 20MHz\n"); - pcdev->mclk = 20000000; - } - - pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev); - - INIT_LIST_HEAD(&pcdev->capture); - spin_lock_init(&pcdev->lock); - - /* - * Request the regions. - */ - if (!request_mem_region(res->start, resource_size(res), - PXA_CAM_DRV_NAME)) { - err = -EBUSY; - goto exit_clk; - } - - base = ioremap(res->start, resource_size(res)); - if (!base) { - err = -ENOMEM; - goto exit_release; - } - pcdev->irq = irq; - pcdev->base = base; - - /* request dma */ - err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH, - pxa_camera_dma_irq_y, pcdev); - if (err < 0) { - dev_err(&pdev->dev, "Can't request DMA for Y\n"); - goto exit_iounmap; - } - pcdev->dma_chans[0] = err; - dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]); - - err = pxa_request_dma("CI_U", DMA_PRIO_HIGH, - pxa_camera_dma_irq_u, pcdev); - if (err < 0) { - dev_err(&pdev->dev, "Can't request DMA for U\n"); - goto exit_free_dma_y; - } - pcdev->dma_chans[1] = err; - dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]); - - err = pxa_request_dma("CI_V", DMA_PRIO_HIGH, - pxa_camera_dma_irq_v, pcdev); - if (err < 0) { - dev_err(&pdev->dev, "Can't request DMA for V\n"); - goto exit_free_dma_u; - } - pcdev->dma_chans[2] = err; - dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); - - DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD; - DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; - DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD; - - /* request irq */ - err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME, - pcdev); - if (err) { - dev_err(&pdev->dev, "Camera interrupt register failed \n"); - goto exit_free_dma; - } - - pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME; - pcdev->soc_host.ops = &pxa_soc_camera_host_ops; - pcdev->soc_host.priv = pcdev; - pcdev->soc_host.v4l2_dev.dev = &pdev->dev; - pcdev->soc_host.nr = pdev->id; - - err = soc_camera_host_register(&pcdev->soc_host); - if (err) - goto exit_free_irq; - - return 0; - -exit_free_irq: - free_irq(pcdev->irq, pcdev); -exit_free_dma: - pxa_free_dma(pcdev->dma_chans[2]); -exit_free_dma_u: - pxa_free_dma(pcdev->dma_chans[1]); -exit_free_dma_y: - pxa_free_dma(pcdev->dma_chans[0]); -exit_iounmap: - iounmap(base); -exit_release: - release_mem_region(res->start, resource_size(res)); -exit_clk: - clk_put(pcdev->clk); -exit_kfree: - kfree(pcdev); -exit: - return err; -} - -static int __devexit pxa_camera_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - struct pxa_camera_dev *pcdev = container_of(soc_host, - struct pxa_camera_dev, soc_host); - struct resource *res; - - clk_put(pcdev->clk); - - pxa_free_dma(pcdev->dma_chans[0]); - pxa_free_dma(pcdev->dma_chans[1]); - pxa_free_dma(pcdev->dma_chans[2]); - free_irq(pcdev->irq, pcdev); - - soc_camera_host_unregister(soc_host); - - iounmap(pcdev->base); - - res = pcdev->res; - release_mem_region(res->start, resource_size(res)); - - kfree(pcdev); - - dev_info(&pdev->dev, "PXA Camera driver unloaded\n"); - - return 0; -} - -static struct platform_driver pxa_camera_driver = { - .driver = { - .name = PXA_CAM_DRV_NAME, - }, - .probe = pxa_camera_probe, - .remove = __devexit_p(pxa_camera_remove), -}; - - -static int __init pxa_camera_init(void) -{ - return platform_driver_register(&pxa_camera_driver); -} - -static void __exit pxa_camera_exit(void) -{ - platform_driver_unregister(&pxa_camera_driver); -} - -module_init(pxa_camera_init); -module_exit(pxa_camera_exit); - -MODULE_DESCRIPTION("PXA27x SoC Camera Host driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/rj54n1cb0c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/rj54n1cb0c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/rj54n1cb0c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/rj54n1cb0c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1498 +0,0 @@ -/* - * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp - * - * Copyright (C) 2009, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define RJ54N1_DEV_CODE 0x0400 -#define RJ54N1_DEV_CODE2 0x0401 -#define RJ54N1_OUT_SEL 0x0403 -#define RJ54N1_XY_OUTPUT_SIZE_S_H 0x0404 -#define RJ54N1_X_OUTPUT_SIZE_S_L 0x0405 -#define RJ54N1_Y_OUTPUT_SIZE_S_L 0x0406 -#define RJ54N1_XY_OUTPUT_SIZE_P_H 0x0407 -#define RJ54N1_X_OUTPUT_SIZE_P_L 0x0408 -#define RJ54N1_Y_OUTPUT_SIZE_P_L 0x0409 -#define RJ54N1_LINE_LENGTH_PCK_S_H 0x040a -#define RJ54N1_LINE_LENGTH_PCK_S_L 0x040b -#define RJ54N1_LINE_LENGTH_PCK_P_H 0x040c -#define RJ54N1_LINE_LENGTH_PCK_P_L 0x040d -#define RJ54N1_RESIZE_N 0x040e -#define RJ54N1_RESIZE_N_STEP 0x040f -#define RJ54N1_RESIZE_STEP 0x0410 -#define RJ54N1_RESIZE_HOLD_H 0x0411 -#define RJ54N1_RESIZE_HOLD_L 0x0412 -#define RJ54N1_H_OBEN_OFS 0x0413 -#define RJ54N1_V_OBEN_OFS 0x0414 -#define RJ54N1_RESIZE_CONTROL 0x0415 -#define RJ54N1_STILL_CONTROL 0x0417 -#define RJ54N1_INC_USE_SEL_H 0x0425 -#define RJ54N1_INC_USE_SEL_L 0x0426 -#define RJ54N1_MIRROR_STILL_MODE 0x0427 -#define RJ54N1_INIT_START 0x0428 -#define RJ54N1_SCALE_1_2_LEV 0x0429 -#define RJ54N1_SCALE_4_LEV 0x042a -#define RJ54N1_Y_GAIN 0x04d8 -#define RJ54N1_APT_GAIN_UP 0x04fa -#define RJ54N1_RA_SEL_UL 0x0530 -#define RJ54N1_BYTE_SWAP 0x0531 -#define RJ54N1_OUT_SIGPO 0x053b -#define RJ54N1_WB_SEL_WEIGHT_I 0x054e -#define RJ54N1_BIT8_WB 0x0569 -#define RJ54N1_HCAPS_WB 0x056a -#define RJ54N1_VCAPS_WB 0x056b -#define RJ54N1_HCAPE_WB 0x056c -#define RJ54N1_VCAPE_WB 0x056d -#define RJ54N1_EXPOSURE_CONTROL 0x058c -#define RJ54N1_FRAME_LENGTH_S_H 0x0595 -#define RJ54N1_FRAME_LENGTH_S_L 0x0596 -#define RJ54N1_FRAME_LENGTH_P_H 0x0597 -#define RJ54N1_FRAME_LENGTH_P_L 0x0598 -#define RJ54N1_PEAK_H 0x05b7 -#define RJ54N1_PEAK_50 0x05b8 -#define RJ54N1_PEAK_60 0x05b9 -#define RJ54N1_PEAK_DIFF 0x05ba -#define RJ54N1_IOC 0x05ef -#define RJ54N1_TG_BYPASS 0x0700 -#define RJ54N1_PLL_L 0x0701 -#define RJ54N1_PLL_N 0x0702 -#define RJ54N1_PLL_EN 0x0704 -#define RJ54N1_RATIO_TG 0x0706 -#define RJ54N1_RATIO_T 0x0707 -#define RJ54N1_RATIO_R 0x0708 -#define RJ54N1_RAMP_TGCLK_EN 0x0709 -#define RJ54N1_OCLK_DSP 0x0710 -#define RJ54N1_RATIO_OP 0x0711 -#define RJ54N1_RATIO_O 0x0712 -#define RJ54N1_OCLK_SEL_EN 0x0713 -#define RJ54N1_CLK_RST 0x0717 -#define RJ54N1_RESET_STANDBY 0x0718 -#define RJ54N1_FWFLG 0x07fe - -#define E_EXCLK (1 << 7) -#define SOFT_STDBY (1 << 4) -#define SEN_RSTX (1 << 2) -#define TG_RSTX (1 << 1) -#define DSP_RSTX (1 << 0) - -#define RESIZE_HOLD_SEL (1 << 2) -#define RESIZE_GO (1 << 1) - -/* - * When cropping, the camera automatically centers the cropped region, there - * doesn't seem to be a way to specify an explicit location of the rectangle. - */ -#define RJ54N1_COLUMN_SKIP 0 -#define RJ54N1_ROW_SKIP 0 -#define RJ54N1_MAX_WIDTH 1600 -#define RJ54N1_MAX_HEIGHT 1200 - -#define PLL_L 2 -#define PLL_N 0x31 - -/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */ - -/* RJ54N1CB0C has only one fixed colorspace per pixelcode */ -struct rj54n1_datafmt { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; -}; - -/* Find a data format by a pixel code in an array */ -static const struct rj54n1_datafmt *rj54n1_find_datafmt( - enum v4l2_mbus_pixelcode code, const struct rj54n1_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - -static const struct rj54n1_datafmt rj54n1_colour_fmts[] = { - {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB}, - {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, -}; - -struct rj54n1_clock_div { - u8 ratio_tg; /* can be 0 or an odd number */ - u8 ratio_t; - u8 ratio_r; - u8 ratio_op; - u8 ratio_o; -}; - -struct rj54n1 { - struct v4l2_subdev subdev; - struct rj54n1_clock_div clk_div; - const struct rj54n1_datafmt *fmt; - struct v4l2_rect rect; /* Sensor window */ - unsigned int tgclk_mhz; - bool auto_wb; - unsigned short width; /* Output window */ - unsigned short height; - unsigned short resize; /* Sensor * 1024 / resize = Output */ - unsigned short scale; - u8 bank; -}; - -struct rj54n1_reg_val { - u16 reg; - u8 val; -}; - -static const struct rj54n1_reg_val bank_4[] = { - {0x417, 0}, - {0x42c, 0}, - {0x42d, 0xf0}, - {0x42e, 0}, - {0x42f, 0x50}, - {0x430, 0xf5}, - {0x431, 0x16}, - {0x432, 0x20}, - {0x433, 0}, - {0x434, 0xc8}, - {0x43c, 8}, - {0x43e, 0x90}, - {0x445, 0x83}, - {0x4ba, 0x58}, - {0x4bb, 4}, - {0x4bc, 0x20}, - {0x4db, 4}, - {0x4fe, 2}, -}; - -static const struct rj54n1_reg_val bank_5[] = { - {0x514, 0}, - {0x516, 0}, - {0x518, 0}, - {0x51a, 0}, - {0x51d, 0xff}, - {0x56f, 0x28}, - {0x575, 0x40}, - {0x5bc, 0x48}, - {0x5c1, 6}, - {0x5e5, 0x11}, - {0x5e6, 0x43}, - {0x5e7, 0x33}, - {0x5e8, 0x21}, - {0x5e9, 0x30}, - {0x5ea, 0x0}, - {0x5eb, 0xa5}, - {0x5ec, 0xff}, - {0x5fe, 2}, -}; - -static const struct rj54n1_reg_val bank_7[] = { - {0x70a, 0}, - {0x714, 0xff}, - {0x715, 0xff}, - {0x716, 0x1f}, - {0x7FE, 2}, -}; - -static const struct rj54n1_reg_val bank_8[] = { - {0x800, 0x00}, - {0x801, 0x01}, - {0x802, 0x61}, - {0x805, 0x00}, - {0x806, 0x00}, - {0x807, 0x00}, - {0x808, 0x00}, - {0x809, 0x01}, - {0x80A, 0x61}, - {0x80B, 0x00}, - {0x80C, 0x01}, - {0x80D, 0x00}, - {0x80E, 0x00}, - {0x80F, 0x00}, - {0x810, 0x00}, - {0x811, 0x01}, - {0x812, 0x61}, - {0x813, 0x00}, - {0x814, 0x11}, - {0x815, 0x00}, - {0x816, 0x41}, - {0x817, 0x00}, - {0x818, 0x51}, - {0x819, 0x01}, - {0x81A, 0x1F}, - {0x81B, 0x00}, - {0x81C, 0x01}, - {0x81D, 0x00}, - {0x81E, 0x11}, - {0x81F, 0x00}, - {0x820, 0x41}, - {0x821, 0x00}, - {0x822, 0x51}, - {0x823, 0x00}, - {0x824, 0x00}, - {0x825, 0x00}, - {0x826, 0x47}, - {0x827, 0x01}, - {0x828, 0x4F}, - {0x829, 0x00}, - {0x82A, 0x00}, - {0x82B, 0x00}, - {0x82C, 0x30}, - {0x82D, 0x00}, - {0x82E, 0x40}, - {0x82F, 0x00}, - {0x830, 0xB3}, - {0x831, 0x00}, - {0x832, 0xE3}, - {0x833, 0x00}, - {0x834, 0x00}, - {0x835, 0x00}, - {0x836, 0x00}, - {0x837, 0x00}, - {0x838, 0x00}, - {0x839, 0x01}, - {0x83A, 0x61}, - {0x83B, 0x00}, - {0x83C, 0x01}, - {0x83D, 0x00}, - {0x83E, 0x00}, - {0x83F, 0x00}, - {0x840, 0x00}, - {0x841, 0x01}, - {0x842, 0x61}, - {0x843, 0x00}, - {0x844, 0x1D}, - {0x845, 0x00}, - {0x846, 0x00}, - {0x847, 0x00}, - {0x848, 0x00}, - {0x849, 0x01}, - {0x84A, 0x1F}, - {0x84B, 0x00}, - {0x84C, 0x05}, - {0x84D, 0x00}, - {0x84E, 0x19}, - {0x84F, 0x01}, - {0x850, 0x21}, - {0x851, 0x01}, - {0x852, 0x5D}, - {0x853, 0x00}, - {0x854, 0x00}, - {0x855, 0x00}, - {0x856, 0x19}, - {0x857, 0x01}, - {0x858, 0x21}, - {0x859, 0x00}, - {0x85A, 0x00}, - {0x85B, 0x00}, - {0x85C, 0x00}, - {0x85D, 0x00}, - {0x85E, 0x00}, - {0x85F, 0x00}, - {0x860, 0xB3}, - {0x861, 0x00}, - {0x862, 0xE3}, - {0x863, 0x00}, - {0x864, 0x00}, - {0x865, 0x00}, - {0x866, 0x00}, - {0x867, 0x00}, - {0x868, 0x00}, - {0x869, 0xE2}, - {0x86A, 0x00}, - {0x86B, 0x01}, - {0x86C, 0x06}, - {0x86D, 0x00}, - {0x86E, 0x00}, - {0x86F, 0x00}, - {0x870, 0x60}, - {0x871, 0x8C}, - {0x872, 0x10}, - {0x873, 0x00}, - {0x874, 0xE0}, - {0x875, 0x00}, - {0x876, 0x27}, - {0x877, 0x01}, - {0x878, 0x00}, - {0x879, 0x00}, - {0x87A, 0x00}, - {0x87B, 0x03}, - {0x87C, 0x00}, - {0x87D, 0x00}, - {0x87E, 0x00}, - {0x87F, 0x00}, - {0x880, 0x00}, - {0x881, 0x00}, - {0x882, 0x00}, - {0x883, 0x00}, - {0x884, 0x00}, - {0x885, 0x00}, - {0x886, 0xF8}, - {0x887, 0x00}, - {0x888, 0x03}, - {0x889, 0x00}, - {0x88A, 0x64}, - {0x88B, 0x00}, - {0x88C, 0x03}, - {0x88D, 0x00}, - {0x88E, 0xB1}, - {0x88F, 0x00}, - {0x890, 0x03}, - {0x891, 0x01}, - {0x892, 0x1D}, - {0x893, 0x00}, - {0x894, 0x03}, - {0x895, 0x01}, - {0x896, 0x4B}, - {0x897, 0x00}, - {0x898, 0xE5}, - {0x899, 0x00}, - {0x89A, 0x01}, - {0x89B, 0x00}, - {0x89C, 0x01}, - {0x89D, 0x04}, - {0x89E, 0xC8}, - {0x89F, 0x00}, - {0x8A0, 0x01}, - {0x8A1, 0x01}, - {0x8A2, 0x61}, - {0x8A3, 0x00}, - {0x8A4, 0x01}, - {0x8A5, 0x00}, - {0x8A6, 0x00}, - {0x8A7, 0x00}, - {0x8A8, 0x00}, - {0x8A9, 0x00}, - {0x8AA, 0x7F}, - {0x8AB, 0x03}, - {0x8AC, 0x00}, - {0x8AD, 0x00}, - {0x8AE, 0x00}, - {0x8AF, 0x00}, - {0x8B0, 0x00}, - {0x8B1, 0x00}, - {0x8B6, 0x00}, - {0x8B7, 0x01}, - {0x8B8, 0x00}, - {0x8B9, 0x00}, - {0x8BA, 0x02}, - {0x8BB, 0x00}, - {0x8BC, 0xFF}, - {0x8BD, 0x00}, - {0x8FE, 2}, -}; - -static const struct rj54n1_reg_val bank_10[] = { - {0x10bf, 0x69} -}; - -/* Clock dividers - these are default register values, divider = register + 1 */ -static const struct rj54n1_clock_div clk_div = { - .ratio_tg = 3 /* default: 5 */, - .ratio_t = 4 /* default: 1 */, - .ratio_r = 4 /* default: 0 */, - .ratio_op = 1 /* default: 5 */, - .ratio_o = 9 /* default: 0 */, -}; - -static struct rj54n1 *to_rj54n1(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct rj54n1, subdev); -} - -static int reg_read(struct i2c_client *client, const u16 reg) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - int ret; - - /* set bank */ - if (rj54n1->bank != reg >> 8) { - dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8); - ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8); - if (ret < 0) - return ret; - rj54n1->bank = reg >> 8; - } - return i2c_smbus_read_byte_data(client, reg & 0xff); -} - -static int reg_write(struct i2c_client *client, const u16 reg, - const u8 data) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - int ret; - - /* set bank */ - if (rj54n1->bank != reg >> 8) { - dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8); - ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8); - if (ret < 0) - return ret; - rj54n1->bank = reg >> 8; - } - dev_dbg(&client->dev, "[0x%x] = 0x%x\n", reg & 0xff, data); - return i2c_smbus_write_byte_data(client, reg & 0xff, data); -} - -static int reg_set(struct i2c_client *client, const u16 reg, - const u8 data, const u8 mask) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, (ret & ~mask) | (data & mask)); -} - -static int reg_write_multiple(struct i2c_client *client, - const struct rj54n1_reg_val *rv, const int n) -{ - int i, ret; - - for (i = 0; i < n; i++) { - ret = reg_write(client, rv->reg, rv->val); - if (ret < 0) - return ret; - rv++; - } - - return 0; -} - -static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index >= ARRAY_SIZE(rj54n1_colour_fmts)) - return -EINVAL; - - *code = rj54n1_colour_fmts[index].code; - return 0; -} - -static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* Switch between preview and still shot modes */ - return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80); -} - -static int rj54n1_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ - - if (flags & SOCAM_PCLK_SAMPLE_RISING) - return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); - else - return reg_write(client, RJ54N1_OUT_SIGPO, 0); -} - -static unsigned long rj54n1_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - const unsigned long flags = - SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | - SOCAM_MASTER | SOCAM_DATAWIDTH_8 | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_DATA_ACTIVE_HIGH; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static int rj54n1_set_rect(struct i2c_client *client, - u16 reg_x, u16 reg_y, u16 reg_xy, - u32 width, u32 height) -{ - int ret; - - ret = reg_write(client, reg_xy, - ((width >> 4) & 0x70) | - ((height >> 8) & 7)); - - if (!ret) - ret = reg_write(client, reg_x, width & 0xff); - if (!ret) - ret = reg_write(client, reg_y, height & 0xff); - - return ret; -} - -/* - * Some commands, specifically certain initialisation sequences, require - * a commit operation. - */ -static int rj54n1_commit(struct i2c_client *client) -{ - int ret = reg_write(client, RJ54N1_INIT_START, 1); - msleep(10); - if (!ret) - ret = reg_write(client, RJ54N1_INIT_START, 0); - return ret; -} - -static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h, - s32 *out_w, s32 *out_h); - -static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - struct v4l2_rect *rect = &a->c; - int dummy = 0, output_w, output_h, - input_w = rect->width, input_h = rect->height; - int ret; - - /* arbitrary minimum width and height, edges unimportant */ - soc_camera_limit_side(&dummy, &input_w, - RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH); - - soc_camera_limit_side(&dummy, &input_h, - RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT); - - output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize; - output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize; - - dev_dbg(&client->dev, "Scaling for %dx%d : %u = %dx%d\n", - input_w, input_h, rj54n1->resize, output_w, output_h); - - ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); - if (ret < 0) - return ret; - - rj54n1->width = output_w; - rj54n1->height = output_h; - rj54n1->resize = ret; - rj54n1->rect.width = input_w; - rj54n1->rect.height = input_h; - - return 0; -} - -static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - - a->c = rj54n1->rect; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = RJ54N1_COLUMN_SKIP; - a->bounds.top = RJ54N1_ROW_SKIP; - a->bounds.width = RJ54N1_MAX_WIDTH; - a->bounds.height = RJ54N1_MAX_HEIGHT; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int rj54n1_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - - mf->code = rj54n1->fmt->code; - mf->colorspace = rj54n1->fmt->colorspace; - mf->field = V4L2_FIELD_NONE; - mf->width = rj54n1->width; - mf->height = rj54n1->height; - - return 0; -} - -/* - * The actual geometry configuration routine. It scales the input window into - * the output one, updates the window sizes and returns an error or the resize - * coefficient on success. Note: we only use the "Fixed Scaling" on this camera. - */ -static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h, - s32 *out_w, s32 *out_h) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - unsigned int skip, resize, input_w = *in_w, input_h = *in_h, - output_w = *out_w, output_h = *out_h; - u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom; - unsigned int peak, peak_50, peak_60; - int ret; - - /* - * We have a problem with crops, where the window is larger than 512x384 - * and output window is larger than a half of the input one. In this - * case we have to either reduce the input window to equal or below - * 512x384 or the output window to equal or below 1/2 of the input. - */ - if (output_w > max(512U, input_w / 2)) { - if (2 * output_w > RJ54N1_MAX_WIDTH) { - input_w = RJ54N1_MAX_WIDTH; - output_w = RJ54N1_MAX_WIDTH / 2; - } else { - input_w = output_w * 2; - } - - dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n", - input_w, output_w); - } - - if (output_h > max(384U, input_h / 2)) { - if (2 * output_h > RJ54N1_MAX_HEIGHT) { - input_h = RJ54N1_MAX_HEIGHT; - output_h = RJ54N1_MAX_HEIGHT / 2; - } else { - input_h = output_h * 2; - } - - dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n", - input_h, output_h); - } - - /* Idea: use the read mode for snapshots, handle separate geometries */ - ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L, - RJ54N1_Y_OUTPUT_SIZE_S_L, - RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h); - if (!ret) - ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_P_L, - RJ54N1_Y_OUTPUT_SIZE_P_L, - RJ54N1_XY_OUTPUT_SIZE_P_H, output_w, output_h); - - if (ret < 0) - return ret; - - if (output_w > input_w && output_h > input_h) { - input_w = output_w; - input_h = output_h; - - resize = 1024; - } else { - unsigned int resize_x, resize_y; - resize_x = (input_w * 1024 + output_w / 2) / output_w; - resize_y = (input_h * 1024 + output_h / 2) / output_h; - - /* We want max(resize_x, resize_y), check if it still fits */ - if (resize_x > resize_y && - (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT) - resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) / - output_h; - else if (resize_y > resize_x && - (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH) - resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) / - output_w; - else - resize = max(resize_x, resize_y); - - /* Prohibited value ranges */ - switch (resize) { - case 2040 ... 2047: - resize = 2039; - break; - case 4080 ... 4095: - resize = 4079; - break; - case 8160 ... 8191: - resize = 8159; - break; - case 16320 ... 16384: - resize = 16319; - } - } - - /* Set scaling */ - ret = reg_write(client, RJ54N1_RESIZE_HOLD_L, resize & 0xff); - if (!ret) - ret = reg_write(client, RJ54N1_RESIZE_HOLD_H, resize >> 8); - - if (ret < 0) - return ret; - - /* - * Configure a skipping bitmask. The sensor will select a skipping value - * among set bits automatically. This is very unclear in the datasheet - * too. I was told, in this register one enables all skipping values, - * that are required for a specific resize, and the camera selects - * automatically, which ones to use. But it is unclear how to identify, - * which cropping values are needed. Secondly, why don't we just set all - * bits and let the camera choose? Would it increase processing time and - * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to - * improve the image quality or stability for larger frames (see comment - * above), but I didn't check the framerate. - */ - skip = min(resize / 1024, 15U); - - inc_sel = 1 << skip; - - if (inc_sel <= 2) - inc_sel = 0xc; - else if (resize & 1023 && skip < 15) - inc_sel |= 1 << (skip + 1); - - ret = reg_write(client, RJ54N1_INC_USE_SEL_L, inc_sel & 0xfc); - if (!ret) - ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8); - - if (!rj54n1->auto_wb) { - /* Auto white balance window */ - wb_left = output_w / 16; - wb_right = (3 * output_w / 4 - 3) / 4; - wb_top = output_h / 16; - wb_bottom = (3 * output_h / 4 - 3) / 4; - wb_bit8 = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) | - ((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1); - - if (!ret) - ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8); - if (!ret) - ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left); - if (!ret) - ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top); - if (!ret) - ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right); - if (!ret) - ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom); - } - - /* Antiflicker */ - peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz / - 10000; - peak_50 = peak / 6; - peak_60 = peak / 5; - - if (!ret) - ret = reg_write(client, RJ54N1_PEAK_H, - ((peak_50 >> 4) & 0xf0) | (peak_60 >> 8)); - if (!ret) - ret = reg_write(client, RJ54N1_PEAK_50, peak_50); - if (!ret) - ret = reg_write(client, RJ54N1_PEAK_60, peak_60); - if (!ret) - ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150); - - /* Start resizing */ - if (!ret) - ret = reg_write(client, RJ54N1_RESIZE_CONTROL, - RESIZE_HOLD_SEL | RESIZE_GO | 1); - - if (ret < 0) - return ret; - - /* Constant taken from manufacturer's example */ - msleep(230); - - ret = reg_write(client, RJ54N1_RESIZE_CONTROL, RESIZE_HOLD_SEL | 1); - if (ret < 0) - return ret; - - *in_w = (output_w * resize + 512) / 1024; - *in_h = (output_h * resize + 512) / 1024; - *out_w = output_w; - *out_h = output_h; - - dev_dbg(&client->dev, "Scaled for %dx%d : %u = %ux%u, skip %u\n", - *in_w, *in_h, resize, output_w, output_h, skip); - - return resize; -} - -static int rj54n1_set_clock(struct i2c_client *client) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - int ret; - - /* Enable external clock */ - ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY); - /* Leave stand-by. Note: use this when implementing suspend / resume */ - if (!ret) - ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK); - - if (!ret) - ret = reg_write(client, RJ54N1_PLL_L, PLL_L); - if (!ret) - ret = reg_write(client, RJ54N1_PLL_N, PLL_N); - - /* TGCLK dividers */ - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_TG, - rj54n1->clk_div.ratio_tg); - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_T, - rj54n1->clk_div.ratio_t); - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_R, - rj54n1->clk_div.ratio_r); - - /* Enable TGCLK & RAMP */ - if (!ret) - ret = reg_write(client, RJ54N1_RAMP_TGCLK_EN, 3); - - /* Disable clock output */ - if (!ret) - ret = reg_write(client, RJ54N1_OCLK_DSP, 0); - - /* Set divisors */ - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_OP, - rj54n1->clk_div.ratio_op); - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_O, - rj54n1->clk_div.ratio_o); - - /* Enable OCLK */ - if (!ret) - ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1); - - /* Use PLL for Timing Generator, write 2 to reserved bits */ - if (!ret) - ret = reg_write(client, RJ54N1_TG_BYPASS, 2); - - /* Take sensor out of reset */ - if (!ret) - ret = reg_write(client, RJ54N1_RESET_STANDBY, - E_EXCLK | SEN_RSTX); - /* Enable PLL */ - if (!ret) - ret = reg_write(client, RJ54N1_PLL_EN, 1); - - /* Wait for PLL to stabilise */ - msleep(10); - - /* Enable clock to frequency divider */ - if (!ret) - ret = reg_write(client, RJ54N1_CLK_RST, 1); - - if (!ret) - ret = reg_read(client, RJ54N1_CLK_RST); - if (ret != 1) { - dev_err(&client->dev, - "Resetting RJ54N1CB0C clock failed: %d!\n", ret); - return -EIO; - } - - /* Start the PLL */ - ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1); - - /* Enable OCLK */ - if (!ret) - ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1); - - return ret; -} - -static int rj54n1_reg_init(struct i2c_client *client) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - int ret = rj54n1_set_clock(client); - - if (!ret) - ret = reg_write_multiple(client, bank_7, ARRAY_SIZE(bank_7)); - if (!ret) - ret = reg_write_multiple(client, bank_10, ARRAY_SIZE(bank_10)); - - /* Set binning divisors */ - if (!ret) - ret = reg_write(client, RJ54N1_SCALE_1_2_LEV, 3 | (7 << 4)); - if (!ret) - ret = reg_write(client, RJ54N1_SCALE_4_LEV, 0xf); - - /* Switch to fixed resize mode */ - if (!ret) - ret = reg_write(client, RJ54N1_RESIZE_CONTROL, - RESIZE_HOLD_SEL | 1); - - /* Set gain */ - if (!ret) - ret = reg_write(client, RJ54N1_Y_GAIN, 0x84); - - /* - * Mirror the image back: default is upside down and left-to-right... - * Set manual preview / still shot switching - */ - if (!ret) - ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27); - - if (!ret) - ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4)); - - /* Auto exposure area */ - if (!ret) - ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80); - /* Check current auto WB config */ - if (!ret) - ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I); - if (ret >= 0) { - rj54n1->auto_wb = ret & 0x80; - ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5)); - } - if (!ret) - ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8)); - - if (!ret) - ret = reg_write(client, RJ54N1_RESET_STANDBY, - E_EXCLK | DSP_RSTX | SEN_RSTX); - - /* Commit init */ - if (!ret) - ret = rj54n1_commit(client); - - /* Take DSP, TG, sensor out of reset */ - if (!ret) - ret = reg_write(client, RJ54N1_RESET_STANDBY, - E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX); - - /* Start register update? Same register as 0x?FE in many bank_* sets */ - if (!ret) - ret = reg_write(client, RJ54N1_FWFLG, 2); - - /* Constant taken from manufacturer's example */ - msleep(700); - - return ret; -} - -static int rj54n1_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - const struct rj54n1_datafmt *fmt; - int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 || - mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE || - mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE || - mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE || - mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE; - - dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", - __func__, mf->code, mf->width, mf->height); - - fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, - ARRAY_SIZE(rj54n1_colour_fmts)); - if (!fmt) { - fmt = rj54n1->fmt; - mf->code = fmt->code; - } - - mf->field = V4L2_FIELD_NONE; - mf->colorspace = fmt->colorspace; - - v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align, - &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); - - return 0; -} - -static int rj54n1_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - const struct rj54n1_datafmt *fmt; - int output_w, output_h, max_w, max_h, - input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; - int ret; - - /* - * The host driver can call us without .try_fmt(), so, we have to take - * care ourseleves - */ - rj54n1_try_fmt(sd, mf); - - /* - * Verify if the sensor has just been powered on. TODO: replace this - * with proper PM, when a suitable API is available. - */ - ret = reg_read(client, RJ54N1_RESET_STANDBY); - if (ret < 0) - return ret; - - if (!(ret & E_EXCLK)) { - ret = rj54n1_reg_init(client); - if (ret < 0) - return ret; - } - - dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", - __func__, mf->code, mf->width, mf->height); - - /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ - switch (mf->code) { - case V4L2_MBUS_FMT_YUYV8_2X8: - ret = reg_write(client, RJ54N1_OUT_SEL, 0); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); - break; - case V4L2_MBUS_FMT_YVYU8_2X8: - ret = reg_write(client, RJ54N1_OUT_SEL, 0); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); - break; - case V4L2_MBUS_FMT_RGB565_2X8_LE: - ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); - break; - case V4L2_MBUS_FMT_RGB565_2X8_BE: - ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); - break; - case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE: - ret = reg_write(client, RJ54N1_OUT_SEL, 4); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); - if (!ret) - ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); - break; - case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: - ret = reg_write(client, RJ54N1_OUT_SEL, 4); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); - if (!ret) - ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); - break; - case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE: - ret = reg_write(client, RJ54N1_OUT_SEL, 4); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); - if (!ret) - ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); - break; - case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE: - ret = reg_write(client, RJ54N1_OUT_SEL, 4); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); - if (!ret) - ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); - break; - case V4L2_MBUS_FMT_SBGGR10_1X10: - ret = reg_write(client, RJ54N1_OUT_SEL, 5); - break; - default: - ret = -EINVAL; - } - - /* Special case: a raw mode with 10 bits of data per clock tick */ - if (!ret) - ret = reg_set(client, RJ54N1_OCLK_SEL_EN, - (mf->code == V4L2_MBUS_FMT_SBGGR10_1X10) << 1, 2); - - if (ret < 0) - return ret; - - /* Supported scales 1:1 >= scale > 1:16 */ - max_w = mf->width * (16 * 1024 - 1) / 1024; - if (input_w > max_w) - input_w = max_w; - max_h = mf->height * (16 * 1024 - 1) / 1024; - if (input_h > max_h) - input_h = max_h; - - output_w = mf->width; - output_h = mf->height; - - ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); - if (ret < 0) - return ret; - - fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, - ARRAY_SIZE(rj54n1_colour_fmts)); - - rj54n1->fmt = fmt; - rj54n1->resize = ret; - rj54n1->rect.width = input_w; - rj54n1->rect.height = input_h; - rj54n1->width = output_w; - rj54n1->height = output_h; - - mf->width = output_w; - mf->height = output_h; - mf->field = V4L2_FIELD_NONE; - mf->colorspace = fmt->colorspace; - - return 0; -} - -static int rj54n1_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) - return -EINVAL; - - if (id->match.addr != client->addr) - return -ENODEV; - - id->ident = V4L2_IDENT_RJ54N1CB0C; - id->revision = 0; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int rj54n1_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || - reg->reg < 0x400 || reg->reg > 0x1fff) - /* Registers > 0x0800 are only available from Sharp support */ - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - reg->size = 1; - reg->val = reg_read(client, reg->reg); - - if (reg->val > 0xff) - return -EIO; - - return 0; -} - -static int rj54n1_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || - reg->reg < 0x400 || reg->reg > 0x1fff) - /* Registers >= 0x0800 are only available from Sharp support */ - return -EINVAL; - - if (reg->match.addr != client->addr) - return -ENODEV; - - if (reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static const struct v4l2_queryctrl rj54n1_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 66, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, -}; - -static struct soc_camera_ops rj54n1_ops = { - .set_bus_param = rj54n1_set_bus_param, - .query_bus_param = rj54n1_query_bus_param, - .controls = rj54n1_controls, - .num_controls = ARRAY_SIZE(rj54n1_controls), -}; - -static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - int data; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); - if (data < 0) - return -EIO; - ctrl->value = !(data & 1); - break; - case V4L2_CID_HFLIP: - data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); - if (data < 0) - return -EIO; - ctrl->value = !(data & 2); - break; - case V4L2_CID_GAIN: - data = reg_read(client, RJ54N1_Y_GAIN); - if (data < 0) - return -EIO; - - ctrl->value = data / 2; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = rj54n1->auto_wb; - break; - } - - return 0; -} - -static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - int data; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - const struct v4l2_queryctrl *qctrl; - - qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id); - if (!qctrl) - return -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->value) - data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1); - else - data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1); - if (data < 0) - return -EIO; - break; - case V4L2_CID_HFLIP: - if (ctrl->value) - data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2); - else - data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2); - if (data < 0) - return -EIO; - break; - case V4L2_CID_GAIN: - if (ctrl->value > qctrl->maximum || - ctrl->value < qctrl->minimum) - return -EINVAL; - else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0) - return -EIO; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - /* Auto WB area - whole image */ - if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->value << 7, - 0x80) < 0) - return -EIO; - rj54n1->auto_wb = ctrl->value; - break; - } - - return 0; -} - -static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { - .g_ctrl = rj54n1_g_ctrl, - .s_ctrl = rj54n1_s_ctrl, - .g_chip_ident = rj54n1_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = rj54n1_g_register, - .s_register = rj54n1_s_register, -#endif -}; - -static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { - .s_stream = rj54n1_s_stream, - .s_mbus_fmt = rj54n1_s_fmt, - .g_mbus_fmt = rj54n1_g_fmt, - .try_mbus_fmt = rj54n1_try_fmt, - .enum_mbus_fmt = rj54n1_enum_fmt, - .g_crop = rj54n1_g_crop, - .s_crop = rj54n1_s_crop, - .cropcap = rj54n1_cropcap, -}; - -static struct v4l2_subdev_ops rj54n1_subdev_ops = { - .core = &rj54n1_subdev_core_ops, - .video = &rj54n1_subdev_video_ops, -}; - -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int rj54n1_video_probe(struct soc_camera_device *icd, - struct i2c_client *client, - struct rj54n1_pdata *priv) -{ - int data1, data2; - int ret; - - /* This could be a BUG_ON() or a WARN_ON(), or remove it completely */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; - - /* Read out the chip version register */ - data1 = reg_read(client, RJ54N1_DEV_CODE); - data2 = reg_read(client, RJ54N1_DEV_CODE2); - - if (data1 != 0x51 || data2 != 0x10) { - ret = -ENODEV; - dev_info(&client->dev, "No RJ54N1CB0C found, read 0x%x:0x%x\n", - data1, data2); - goto ei2c; - } - - /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */ - ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7); - if (ret < 0) - goto ei2c; - - dev_info(&client->dev, "Detected a RJ54N1CB0C chip ID 0x%x:0x%x\n", - data1, data2); - -ei2c: - return ret; -} - -static int rj54n1_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct rj54n1 *rj54n1; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - struct rj54n1_pdata *rj54n1_priv; - int ret; - - if (!icd) { - dev_err(&client->dev, "RJ54N1CB0C: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) { - dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); - return -EINVAL; - } - - rj54n1_priv = icl->priv; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); - return -EIO; - } - - rj54n1 = kzalloc(sizeof(struct rj54n1), GFP_KERNEL); - if (!rj54n1) - return -ENOMEM; - - v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops); - - icd->ops = &rj54n1_ops; - - rj54n1->clk_div = clk_div; - rj54n1->rect.left = RJ54N1_COLUMN_SKIP; - rj54n1->rect.top = RJ54N1_ROW_SKIP; - rj54n1->rect.width = RJ54N1_MAX_WIDTH; - rj54n1->rect.height = RJ54N1_MAX_HEIGHT; - rj54n1->width = RJ54N1_MAX_WIDTH; - rj54n1->height = RJ54N1_MAX_HEIGHT; - rj54n1->fmt = &rj54n1_colour_fmts[0]; - rj54n1->resize = 1024; - rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / - (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); - - ret = rj54n1_video_probe(icd, client, rj54n1_priv); - if (ret < 0) { - icd->ops = NULL; - kfree(rj54n1); - return ret; - } - - return ret; -} - -static int rj54n1_remove(struct i2c_client *client) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); - - icd->ops = NULL; - if (icl->free_bus) - icl->free_bus(icl); - kfree(rj54n1); - - return 0; -} - -static const struct i2c_device_id rj54n1_id[] = { - { "rj54n1cb0c", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, rj54n1_id); - -static struct i2c_driver rj54n1_i2c_driver = { - .driver = { - .name = "rj54n1cb0c", - }, - .probe = rj54n1_probe, - .remove = rj54n1_remove, - .id_table = rj54n1_id, -}; - -static int __init rj54n1_mod_init(void) -{ - return i2c_add_driver(&rj54n1_i2c_driver); -} - -static void __exit rj54n1_mod_exit(void) -{ - i2c_del_driver(&rj54n1_i2c_driver); -} - -module_init(rj54n1_mod_init); -module_exit(rj54n1_mod_exit); - -MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s2255drv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s2255drv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s2255drv.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s2255drv.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2706 +0,0 @@ -/* - * s2255drv.c - a driver for the Sensoray 2255 USB video capture device - * - * Copyright (C) 2007-2010 by Sensoray Company Inc. - * Dean Anderson - * - * Some video buffer code based on vivi driver: - * - * Sensoray 2255 device supports 4 simultaneous channels. - * The channels are not "crossbar" inputs, they are physically - * attached to separate video decoders. - * - * Because of USB2.0 bandwidth limitations. There is only a - * certain amount of data which may be transferred at one time. - * - * Example maximum bandwidth utilization: - * - * -full size, color mode YUYV or YUV422P: 2 channels at once - * - * -full or half size Grey scale: all 4 channels at once - * - * -half size, color mode YUYV or YUV422P: all 4 channels at once - * - * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels - * at once. - * (TODO: Incorporate videodev2 frame rate(FR) enumeration, - * which is currently experimental.) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define S2255_MAJOR_VERSION 1 -#define S2255_MINOR_VERSION 21 -#define S2255_RELEASE 0 -#define S2255_VERSION KERNEL_VERSION(S2255_MAJOR_VERSION, \ - S2255_MINOR_VERSION, \ - S2255_RELEASE) -#define FIRMWARE_FILE_NAME "f2255usb.bin" - -/* default JPEG quality */ -#define S2255_DEF_JPEG_QUAL 50 -/* vendor request in */ -#define S2255_VR_IN 0 -/* vendor request out */ -#define S2255_VR_OUT 1 -/* firmware query */ -#define S2255_VR_FW 0x30 -/* USB endpoint number for configuring the device */ -#define S2255_CONFIG_EP 2 -/* maximum time for DSP to start responding after last FW word loaded(ms) */ -#define S2255_DSP_BOOTTIME 800 -/* maximum time to wait for firmware to load (ms) */ -#define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME) -#define S2255_DEF_BUFS 16 -#define S2255_SETMODE_TIMEOUT 500 -#define S2255_VIDSTATUS_TIMEOUT 350 -#define S2255_MARKER_FRAME cpu_to_le32(0x2255DA4AL) -#define S2255_MARKER_RESPONSE cpu_to_le32(0x2255ACACL) -#define S2255_RESPONSE_SETMODE cpu_to_le32(0x01) -#define S2255_RESPONSE_FW cpu_to_le32(0x10) -#define S2255_RESPONSE_STATUS cpu_to_le32(0x20) -#define S2255_USB_XFER_SIZE (16 * 1024) -#define MAX_CHANNELS 4 -#define SYS_FRAMES 4 -/* maximum size is PAL full size plus room for the marker header(s) */ -#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096) -#define DEF_USB_BLOCK S2255_USB_XFER_SIZE -#define LINE_SZ_4CIFS_NTSC 640 -#define LINE_SZ_2CIFS_NTSC 640 -#define LINE_SZ_1CIFS_NTSC 320 -#define LINE_SZ_4CIFS_PAL 704 -#define LINE_SZ_2CIFS_PAL 704 -#define LINE_SZ_1CIFS_PAL 352 -#define NUM_LINES_4CIFS_NTSC 240 -#define NUM_LINES_2CIFS_NTSC 240 -#define NUM_LINES_1CIFS_NTSC 240 -#define NUM_LINES_4CIFS_PAL 288 -#define NUM_LINES_2CIFS_PAL 288 -#define NUM_LINES_1CIFS_PAL 288 -#define LINE_SZ_DEF 640 -#define NUM_LINES_DEF 240 - - -/* predefined settings */ -#define FORMAT_NTSC 1 -#define FORMAT_PAL 2 - -#define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */ -#define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */ -#define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */ -/* SCALE_4CIFSI is the 2 fields interpolated into one */ -#define SCALE_4CIFSI 4 /* 640x480(NTSC) or 704x576(PAL) high quality */ - -#define COLOR_YUVPL 1 /* YUV planar */ -#define COLOR_YUVPK 2 /* YUV packed */ -#define COLOR_Y8 4 /* monochrome */ -#define COLOR_JPG 5 /* JPEG */ - -#define MASK_COLOR 0x000000ff -#define MASK_JPG_QUALITY 0x0000ff00 -#define MASK_INPUT_TYPE 0x000f0000 -/* frame decimation. Not implemented by V4L yet(experimental in V4L) */ -#define FDEC_1 1 /* capture every frame. default */ -#define FDEC_2 2 /* capture every 2nd frame */ -#define FDEC_3 3 /* capture every 3rd frame */ -#define FDEC_5 5 /* capture every 5th frame */ - -/*------------------------------------------------------- - * Default mode parameters. - *-------------------------------------------------------*/ -#define DEF_SCALE SCALE_4CIFS -#define DEF_COLOR COLOR_YUVPL -#define DEF_FDEC FDEC_1 -#define DEF_BRIGHT 0 -#define DEF_CONTRAST 0x5c -#define DEF_SATURATION 0x80 -#define DEF_HUE 0 - -/* usb config commands */ -#define IN_DATA_TOKEN cpu_to_le32(0x2255c0de) -#define CMD_2255 cpu_to_le32(0xc2255000) -#define CMD_SET_MODE cpu_to_le32((CMD_2255 | 0x10)) -#define CMD_START cpu_to_le32((CMD_2255 | 0x20)) -#define CMD_STOP cpu_to_le32((CMD_2255 | 0x30)) -#define CMD_STATUS cpu_to_le32((CMD_2255 | 0x40)) - -struct s2255_mode { - u32 format; /* input video format (NTSC, PAL) */ - u32 scale; /* output video scale */ - u32 color; /* output video color format */ - u32 fdec; /* frame decimation */ - u32 bright; /* brightness */ - u32 contrast; /* contrast */ - u32 saturation; /* saturation */ - u32 hue; /* hue (NTSC only)*/ - u32 single; /* capture 1 frame at a time (!=0), continuously (==0)*/ - u32 usb_block; /* block size. should be 4096 of DEF_USB_BLOCK */ - u32 restart; /* if DSP requires restart */ -}; - - -#define S2255_READ_IDLE 0 -#define S2255_READ_FRAME 1 - -/* frame structure */ -struct s2255_framei { - unsigned long size; - unsigned long ulState; /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/ - void *lpvbits; /* image data */ - unsigned long cur_size; /* current data copied to it */ -}; - -/* image buffer structure */ -struct s2255_bufferi { - unsigned long dwFrames; /* number of frames in buffer */ - struct s2255_framei frame[SYS_FRAMES]; /* array of FRAME structures */ -}; - -#define DEF_MODEI_NTSC_CONT {FORMAT_NTSC, DEF_SCALE, DEF_COLOR, \ - DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \ - DEF_HUE, 0, DEF_USB_BLOCK, 0} - -struct s2255_dmaqueue { - struct list_head active; - struct s2255_dev *dev; -}; - -/* for firmware loading, fw_state */ -#define S2255_FW_NOTLOADED 0 -#define S2255_FW_LOADED_DSPWAIT 1 -#define S2255_FW_SUCCESS 2 -#define S2255_FW_FAILED 3 -#define S2255_FW_DISCONNECTING 4 -#define S2255_FW_MARKER cpu_to_le32(0x22552f2f) -/* 2255 read states */ -#define S2255_READ_IDLE 0 -#define S2255_READ_FRAME 1 -struct s2255_fw { - int fw_loaded; - int fw_size; - struct urb *fw_urb; - atomic_t fw_state; - void *pfw_data; - wait_queue_head_t wait_fw; - const struct firmware *fw; -}; - -struct s2255_pipeinfo { - u32 max_transfer_size; - u32 cur_transfer_size; - u8 *transfer_buffer; - u32 state; - void *stream_urb; - void *dev; /* back pointer to s2255_dev struct*/ - u32 err_count; - u32 idx; -}; - -struct s2255_fmt; /*forward declaration */ -struct s2255_dev; - -struct s2255_channel { - struct video_device vdev; - int resources; - struct s2255_dmaqueue vidq; - struct s2255_bufferi buffer; - struct s2255_mode mode; - /* jpeg compression */ - struct v4l2_jpegcompression jc; - /* capture parameters (for high quality mode full size) */ - struct v4l2_captureparm cap_parm; - int cur_frame; - int last_frame; - - int b_acquire; - /* allocated image size */ - unsigned long req_image_size; - /* received packet size */ - unsigned long pkt_size; - int bad_payload; - unsigned long frame_count; - /* if JPEG image */ - int jpg_size; - /* if channel configured to default state */ - int configured; - wait_queue_head_t wait_setmode; - int setmode_ready; - /* video status items */ - int vidstatus; - wait_queue_head_t wait_vidstatus; - int vidstatus_ready; - unsigned int width; - unsigned int height; - const struct s2255_fmt *fmt; - int idx; /* channel number on device, 0-3 */ -}; - - -struct s2255_dev { - struct s2255_channel channel[MAX_CHANNELS]; - struct v4l2_device v4l2_dev; - atomic_t num_channels; - int frames; - struct mutex lock; /* channels[].vdev.lock */ - struct mutex open_lock; - struct usb_device *udev; - struct usb_interface *interface; - u8 read_endpoint; - struct timer_list timer; - struct s2255_fw *fw_data; - struct s2255_pipeinfo pipe; - u32 cc; /* current channel */ - int frame_ready; - int chn_ready; - spinlock_t slock; - /* dsp firmware version (f2255usb.bin) */ - int dsp_fw_ver; - u16 pid; /* product id */ -}; - -static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct s2255_dev, v4l2_dev); -} - -struct s2255_fmt { - char *name; - u32 fourcc; - int depth; -}; - -/* buffer for one video frame */ -struct s2255_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - const struct s2255_fmt *fmt; -}; - -struct s2255_fh { - struct s2255_dev *dev; - struct videobuf_queue vb_vidq; - enum v4l2_buf_type type; - struct s2255_channel *channel; - int resources; -}; - -/* current cypress EEPROM firmware version */ -#define S2255_CUR_USB_FWVER ((3 << 8) | 11) -/* current DSP FW version */ -#define S2255_CUR_DSP_FWVER 10102 -/* Need DSP version 5+ for video status feature */ -#define S2255_MIN_DSP_STATUS 5 -#define S2255_MIN_DSP_COLORFILTER 8 -#define S2255_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC) - -/* private V4L2 controls */ - -/* - * The following chart displays how COLORFILTER should be set - * ========================================================= - * = fourcc = COLORFILTER = - * = =============================== - * = = 0 = 1 = - * ========================================================= - * = V4L2_PIX_FMT_GREY(Y8) = monochrome from = monochrome= - * = = s-video or = composite = - * = = B/W camera = input = - * ========================================================= - * = other = color, svideo = color, = - * = = = composite = - * ========================================================= - * - * Notes: - * channels 0-3 on 2255 are composite - * channels 0-1 on 2257 are composite, 2-3 are s-video - * If COLORFILTER is 0 with a composite color camera connected, - * the output will appear monochrome but hatching - * will occur. - * COLORFILTER is different from "color killer" and "color effects" - * for reasons above. - */ -#define S2255_V4L2_YC_ON 1 -#define S2255_V4L2_YC_OFF 0 -#define V4L2_CID_PRIVATE_COLORFILTER (V4L2_CID_PRIVATE_BASE + 0) - -/* frame prefix size (sent once every frame) */ -#define PREFIX_SIZE 512 - -/* Channels on box are in reverse order */ -static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0}; - -static int debug; -static int *s2255_debug = &debug; - -static int s2255_start_readpipe(struct s2255_dev *dev); -static void s2255_stop_readpipe(struct s2255_dev *dev); -static int s2255_start_acquire(struct s2255_channel *channel); -static int s2255_stop_acquire(struct s2255_channel *channel); -static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf, - int jpgsize); -static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode); -static int s2255_board_shutdown(struct s2255_dev *dev); -static void s2255_fwload_start(struct s2255_dev *dev, int reset); -static void s2255_destroy(struct s2255_dev *dev); -static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, - u16 index, u16 value, void *buf, - s32 buf_len, int bOut); - -/* dev_err macro with driver name */ -#define S2255_DRIVER_NAME "s2255" -#define s2255_dev_err(dev, fmt, arg...) \ - dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg) - -#define dprintk(level, fmt, arg...) \ - do { \ - if (*s2255_debug >= (level)) { \ - printk(KERN_DEBUG S2255_DRIVER_NAME \ - ": " fmt, ##arg); \ - } \ - } while (0) - -static struct usb_driver s2255_driver; - -/* Declare static vars that will be used as parameters */ -static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ - -/* start video number */ -static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level(0-100) default 0"); -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)"); -module_param(video_nr, int, 0644); -MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)"); - -/* USB device table */ -#define USB_SENSORAY_VID 0x1943 -static struct usb_device_id s2255_table[] = { - {USB_DEVICE(USB_SENSORAY_VID, 0x2255)}, - {USB_DEVICE(USB_SENSORAY_VID, 0x2257)}, /*same family as 2255*/ - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, s2255_table); - -#define BUFFER_TIMEOUT msecs_to_jiffies(400) - -/* image formats. */ -static const struct s2255_fmt formats[] = { - { - .name = "4:2:2, planar, YUV422P", - .fourcc = V4L2_PIX_FMT_YUV422P, - .depth = 16 - - }, { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16 - - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16 - }, { - .name = "JPG", - .fourcc = V4L2_PIX_FMT_JPEG, - .depth = 24 - }, { - .name = "8bpp GREY", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8 - } -}; - -static int norm_maxw(struct video_device *vdev) -{ - return (vdev->current_norm & V4L2_STD_NTSC) ? - LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL; -} - -static int norm_maxh(struct video_device *vdev) -{ - return (vdev->current_norm & V4L2_STD_NTSC) ? - (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2); -} - -static int norm_minw(struct video_device *vdev) -{ - return (vdev->current_norm & V4L2_STD_NTSC) ? - LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL; -} - -static int norm_minh(struct video_device *vdev) -{ - return (vdev->current_norm & V4L2_STD_NTSC) ? - (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL); -} - - -/* - * TODO: fixme: move YUV reordering to hardware - * converts 2255 planar format to yuyv or uyvy - */ -static void planar422p_to_yuv_packed(const unsigned char *in, - unsigned char *out, - int width, int height, - int fmt) -{ - unsigned char *pY; - unsigned char *pCb; - unsigned char *pCr; - unsigned long size = height * width; - unsigned int i; - pY = (unsigned char *)in; - pCr = (unsigned char *)in + height * width; - pCb = (unsigned char *)in + height * width + (height * width / 2); - for (i = 0; i < size * 2; i += 4) { - out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++; - out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++; - out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++; - out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++; - } - return; -} - -static void s2255_reset_dsppower(struct s2255_dev *dev) -{ - s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b01, NULL, 0, 1); - msleep(10); - s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1); - msleep(600); - s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1); - return; -} - -/* kickstarts the firmware loading. from probe - */ -static void s2255_timer(unsigned long user_data) -{ - struct s2255_fw *data = (struct s2255_fw *)user_data; - dprintk(100, "%s\n", __func__); - if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { - printk(KERN_ERR "s2255: can't submit urb\n"); - atomic_set(&data->fw_state, S2255_FW_FAILED); - /* wake up anything waiting for the firmware */ - wake_up(&data->wait_fw); - return; - } -} - - -/* this loads the firmware asynchronously. - Originally this was done synchroously in probe. - But it is better to load it asynchronously here than block - inside the probe function. Blocking inside probe affects boot time. - FW loading is triggered by the timer in the probe function -*/ -static void s2255_fwchunk_complete(struct urb *urb) -{ - struct s2255_fw *data = urb->context; - struct usb_device *udev = urb->dev; - int len; - dprintk(100, "%s: udev %p urb %p", __func__, udev, urb); - if (urb->status) { - dev_err(&udev->dev, "URB failed with status %d\n", urb->status); - atomic_set(&data->fw_state, S2255_FW_FAILED); - /* wake up anything waiting for the firmware */ - wake_up(&data->wait_fw); - return; - } - if (data->fw_urb == NULL) { - s2255_dev_err(&udev->dev, "disconnected\n"); - atomic_set(&data->fw_state, S2255_FW_FAILED); - /* wake up anything waiting for the firmware */ - wake_up(&data->wait_fw); - return; - } -#define CHUNK_SIZE 512 - /* all USB transfers must be done with continuous kernel memory. - can't allocate more than 128k in current linux kernel, so - upload the firmware in chunks - */ - if (data->fw_loaded < data->fw_size) { - len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ? - data->fw_size % CHUNK_SIZE : CHUNK_SIZE; - - if (len < CHUNK_SIZE) - memset(data->pfw_data, 0, CHUNK_SIZE); - - dprintk(100, "completed len %d, loaded %d \n", len, - data->fw_loaded); - - memcpy(data->pfw_data, - (char *) data->fw->data + data->fw_loaded, len); - - usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2), - data->pfw_data, CHUNK_SIZE, - s2255_fwchunk_complete, data); - if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { - dev_err(&udev->dev, "failed submit URB\n"); - atomic_set(&data->fw_state, S2255_FW_FAILED); - /* wake up anything waiting for the firmware */ - wake_up(&data->wait_fw); - return; - } - data->fw_loaded += len; - } else { - atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT); - dprintk(100, "%s: firmware upload complete\n", __func__); - } - return; - -} - -static int s2255_got_frame(struct s2255_channel *channel, int jpgsize) -{ - struct s2255_dmaqueue *dma_q = &channel->vidq; - struct s2255_buffer *buf; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); - unsigned long flags = 0; - int rc = 0; - spin_lock_irqsave(&dev->slock, flags); - if (list_empty(&dma_q->active)) { - dprintk(1, "No active queue to serve\n"); - rc = -1; - goto unlock; - } - buf = list_entry(dma_q->active.next, - struct s2255_buffer, vb.queue); - list_del(&buf->vb.queue); - do_gettimeofday(&buf->vb.ts); - s2255_fillbuff(channel, buf, jpgsize); - wake_up(&buf->vb.done); - dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i); -unlock: - spin_unlock_irqrestore(&dev->slock, flags); - return rc; -} - -static const struct s2255_fmt *format_by_fourcc(int fourcc) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(formats); i++) { - if (-1 == formats[i].fourcc) - continue; - if (formats[i].fourcc == fourcc) - return formats + i; - } - return NULL; -} - -/* video buffer vmalloc implementation based partly on VIVI driver which is - * Copyright (c) 2006 by - * Mauro Carvalho Chehab - * Ted Walther - * John Sokol - * http://v4l.videotechnology.com/ - * - */ -static void s2255_fillbuff(struct s2255_channel *channel, - struct s2255_buffer *buf, int jpgsize) -{ - int pos = 0; - struct timeval ts; - const char *tmpbuf; - char *vbuf = videobuf_to_vmalloc(&buf->vb); - unsigned long last_frame; - struct s2255_framei *frm; - - if (!vbuf) - return; - last_frame = channel->last_frame; - if (last_frame != -1) { - frm = &channel->buffer.frame[last_frame]; - tmpbuf = - (const char *)channel->buffer.frame[last_frame].lpvbits; - switch (buf->fmt->fourcc) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - planar422p_to_yuv_packed((const unsigned char *)tmpbuf, - vbuf, buf->vb.width, - buf->vb.height, - buf->fmt->fourcc); - break; - case V4L2_PIX_FMT_GREY: - memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height); - break; - case V4L2_PIX_FMT_JPEG: - buf->vb.size = jpgsize; - memcpy(vbuf, tmpbuf, buf->vb.size); - break; - case V4L2_PIX_FMT_YUV422P: - memcpy(vbuf, tmpbuf, - buf->vb.width * buf->vb.height * 2); - break; - default: - printk(KERN_DEBUG "s2255: unknown format?\n"); - } - channel->last_frame = -1; - } else { - printk(KERN_ERR "s2255: =======no frame\n"); - return; - - } - dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n", - (unsigned long)vbuf, pos); - /* tell v4l buffer was filled */ - - buf->vb.field_count = channel->frame_count * 2; - do_gettimeofday(&ts); - buf->vb.ts = ts; - buf->vb.state = VIDEOBUF_DONE; -} - - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ - -static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct s2255_fh *fh = vq->priv_data; - struct s2255_channel *channel = fh->channel; - *size = channel->width * channel->height * (channel->fmt->depth >> 3); - - if (0 == *count) - *count = S2255_DEF_BUFS; - - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf) -{ - dprintk(4, "%s\n", __func__); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct s2255_fh *fh = vq->priv_data; - struct s2255_channel *channel = fh->channel; - struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); - int rc; - int w = channel->width; - int h = channel->height; - dprintk(4, "%s, field=%d\n", __func__, field); - if (channel->fmt == NULL) - return -EINVAL; - - if ((w < norm_minw(&channel->vdev)) || - (w > norm_maxw(&channel->vdev)) || - (h < norm_minh(&channel->vdev)) || - (h > norm_maxh(&channel->vdev))) { - dprintk(4, "invalid buffer prepare\n"); - return -EINVAL; - } - buf->vb.size = w * h * (channel->fmt->depth >> 3); - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) { - dprintk(4, "invalid buffer prepare\n"); - return -EINVAL; - } - - buf->fmt = channel->fmt; - buf->vb.width = w; - buf->vb.height = h; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; -fail: - free_buffer(vq, buf); - return rc; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); - struct s2255_fh *fh = vq->priv_data; - struct s2255_channel *channel = fh->channel; - struct s2255_dmaqueue *vidq = &channel->vidq; - dprintk(1, "%s\n", __func__); - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); - struct s2255_fh *fh = vq->priv_data; - dprintk(4, "%s %d\n", __func__, fh->channel->idx); - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops s2255_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - - -static int res_get(struct s2255_fh *fh) -{ - struct s2255_channel *channel = fh->channel; - /* is it free? */ - if (channel->resources) - return 0; /* no, someone else uses it */ - /* it's free, grab it */ - channel->resources = 1; - fh->resources = 1; - dprintk(1, "s2255: res: get\n"); - return 1; -} - -static int res_locked(struct s2255_fh *fh) -{ - return fh->channel->resources; -} - -static int res_check(struct s2255_fh *fh) -{ - return fh->resources; -} - - -static void res_free(struct s2255_fh *fh) -{ - struct s2255_channel *channel = fh->channel; - channel->resources = 0; - fh->resources = 0; - dprintk(1, "res: put\n"); -} - -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *qmenu) -{ - static const char *colorfilter[] = { - "Off", - "On", - NULL - }; - if (qmenu->id == V4L2_CID_PRIVATE_COLORFILTER) { - int i; - const char **menu_items = colorfilter; - for (i = 0; i < qmenu->index && menu_items[i]; i++) - ; /* do nothing (from v4l2-common.c) */ - if (menu_items[i] == NULL || menu_items[i][0] == '\0') - return -EINVAL; - strlcpy(qmenu->name, menu_items[qmenu->index], - sizeof(qmenu->name)); - return 0; - } - return v4l2_ctrl_query_menu(qmenu, NULL, NULL); -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct s2255_fh *fh = file->private_data; - struct s2255_dev *dev = fh->dev; - strlcpy(cap->driver, "s2255", sizeof(cap->driver)); - strlcpy(cap->card, "s2255", sizeof(cap->card)); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = S2255_VERSION; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - int index = 0; - if (f) - index = f->index; - - if (index >= ARRAY_SIZE(formats)) - return -EINVAL; - - dprintk(4, "name %s\n", formats[index].name); - strlcpy(f->description, formats[index].name, sizeof(f->description)); - f->pixelformat = formats[index].fourcc; - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - - f->fmt.pix.width = channel->width; - f->fmt.pix.height = channel->height; - f->fmt.pix.field = fh->vb_vidq.field; - f->fmt.pix.pixelformat = channel->fmt->fourcc; - f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3); - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - const struct s2255_fmt *fmt; - enum v4l2_field field; - int b_any_field = 0; - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - int is_ntsc; - is_ntsc = - (channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - - if (fmt == NULL) - return -EINVAL; - - field = f->fmt.pix.field; - if (field == V4L2_FIELD_ANY) - b_any_field = 1; - - dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n", - __func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height); - if (is_ntsc) { - /* NTSC */ - if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) { - f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2; - if (b_any_field) { - field = V4L2_FIELD_SEQ_TB; - } else if (!((field == V4L2_FIELD_INTERLACED) || - (field == V4L2_FIELD_SEQ_TB) || - (field == V4L2_FIELD_INTERLACED_TB))) { - dprintk(1, "unsupported field setting\n"); - return -EINVAL; - } - } else { - f->fmt.pix.height = NUM_LINES_1CIFS_NTSC; - if (b_any_field) { - field = V4L2_FIELD_TOP; - } else if (!((field == V4L2_FIELD_TOP) || - (field == V4L2_FIELD_BOTTOM))) { - dprintk(1, "unsupported field setting\n"); - return -EINVAL; - } - - } - if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC) - f->fmt.pix.width = LINE_SZ_4CIFS_NTSC; - else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC) - f->fmt.pix.width = LINE_SZ_2CIFS_NTSC; - else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC) - f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; - else - f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; - } else { - /* PAL */ - if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) { - f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2; - if (b_any_field) { - field = V4L2_FIELD_SEQ_TB; - } else if (!((field == V4L2_FIELD_INTERLACED) || - (field == V4L2_FIELD_SEQ_TB) || - (field == V4L2_FIELD_INTERLACED_TB))) { - dprintk(1, "unsupported field setting\n"); - return -EINVAL; - } - } else { - f->fmt.pix.height = NUM_LINES_1CIFS_PAL; - if (b_any_field) { - field = V4L2_FIELD_TOP; - } else if (!((field == V4L2_FIELD_TOP) || - (field == V4L2_FIELD_BOTTOM))) { - dprintk(1, "unsupported field setting\n"); - return -EINVAL; - } - } - if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) { - f->fmt.pix.width = LINE_SZ_4CIFS_PAL; - field = V4L2_FIELD_SEQ_TB; - } else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) { - f->fmt.pix.width = LINE_SZ_2CIFS_PAL; - field = V4L2_FIELD_TOP; - } else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) { - f->fmt.pix.width = LINE_SZ_1CIFS_PAL; - field = V4L2_FIELD_TOP; - } else { - f->fmt.pix.width = LINE_SZ_1CIFS_PAL; - field = V4L2_FIELD_TOP; - } - } - f->fmt.pix.field = field; - f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - dprintk(50, "%s: set width %d height %d field %d\n", __func__, - f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - const struct s2255_fmt *fmt; - struct videobuf_queue *q = &fh->vb_vidq; - struct s2255_mode mode; - int ret; - int norm; - - ret = vidioc_try_fmt_vid_cap(file, fh, f); - - if (ret < 0) - return ret; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - - if (fmt == NULL) - return -EINVAL; - - mutex_lock(&q->vb_lock); - - if (videobuf_queue_is_busy(&fh->vb_vidq)) { - dprintk(1, "queue busy\n"); - ret = -EBUSY; - goto out_s_fmt; - } - - if (res_locked(fh)) { - dprintk(1, "%s: channel busy\n", __func__); - ret = -EBUSY; - goto out_s_fmt; - } - mode = channel->mode; - channel->fmt = fmt; - channel->width = f->fmt.pix.width; - channel->height = f->fmt.pix.height; - fh->vb_vidq.field = f->fmt.pix.field; - fh->type = f->type; - norm = norm_minw(&channel->vdev); - if (channel->width > norm_minw(&channel->vdev)) { - if (channel->height > norm_minh(&channel->vdev)) { - if (channel->cap_parm.capturemode & - V4L2_MODE_HIGHQUALITY) - mode.scale = SCALE_4CIFSI; - else - mode.scale = SCALE_4CIFS; - } else - mode.scale = SCALE_2CIFS; - - } else { - mode.scale = SCALE_1CIFS; - } - /* color mode */ - switch (channel->fmt->fourcc) { - case V4L2_PIX_FMT_GREY: - mode.color &= ~MASK_COLOR; - mode.color |= COLOR_Y8; - break; - case V4L2_PIX_FMT_JPEG: - mode.color &= ~MASK_COLOR; - mode.color |= COLOR_JPG; - mode.color |= (channel->jc.quality << 8); - break; - case V4L2_PIX_FMT_YUV422P: - mode.color &= ~MASK_COLOR; - mode.color |= COLOR_YUVPL; - break; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - default: - mode.color &= ~MASK_COLOR; - mode.color |= COLOR_YUVPK; - break; - } - if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR)) - mode.restart = 1; - else if (mode.scale != channel->mode.scale) - mode.restart = 1; - else if (mode.format != channel->mode.format) - mode.restart = 1; - channel->mode = mode; - (void) s2255_set_mode(channel, &mode); - ret = 0; -out_s_fmt: - mutex_unlock(&q->vb_lock); - return ret; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - int rc; - struct s2255_fh *fh = priv; - rc = videobuf_reqbufs(&fh->vb_vidq, p); - return rc; -} - -static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - int rc; - struct s2255_fh *fh = priv; - rc = videobuf_querybuf(&fh->vb_vidq, p); - return rc; -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - int rc; - struct s2255_fh *fh = priv; - rc = videobuf_qbuf(&fh->vb_vidq, p); - return rc; -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - int rc; - struct s2255_fh *fh = priv; - rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK); - return rc; -} - -/* write to the configuration pipe, synchronously */ -static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, - int size) -{ - int pipe; - int done; - long retval = -1; - if (udev) { - pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP); - retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500); - } - return retval; -} - -static u32 get_transfer_size(struct s2255_mode *mode) -{ - int linesPerFrame = LINE_SZ_DEF; - int pixelsPerLine = NUM_LINES_DEF; - u32 outImageSize; - u32 usbInSize; - unsigned int mask_mult; - - if (mode == NULL) - return 0; - - if (mode->format == FORMAT_NTSC) { - switch (mode->scale) { - case SCALE_4CIFS: - case SCALE_4CIFSI: - linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; - pixelsPerLine = LINE_SZ_4CIFS_NTSC; - break; - case SCALE_2CIFS: - linesPerFrame = NUM_LINES_2CIFS_NTSC; - pixelsPerLine = LINE_SZ_2CIFS_NTSC; - break; - case SCALE_1CIFS: - linesPerFrame = NUM_LINES_1CIFS_NTSC; - pixelsPerLine = LINE_SZ_1CIFS_NTSC; - break; - default: - break; - } - } else if (mode->format == FORMAT_PAL) { - switch (mode->scale) { - case SCALE_4CIFS: - case SCALE_4CIFSI: - linesPerFrame = NUM_LINES_4CIFS_PAL * 2; - pixelsPerLine = LINE_SZ_4CIFS_PAL; - break; - case SCALE_2CIFS: - linesPerFrame = NUM_LINES_2CIFS_PAL; - pixelsPerLine = LINE_SZ_2CIFS_PAL; - break; - case SCALE_1CIFS: - linesPerFrame = NUM_LINES_1CIFS_PAL; - pixelsPerLine = LINE_SZ_1CIFS_PAL; - break; - default: - break; - } - } - outImageSize = linesPerFrame * pixelsPerLine; - if ((mode->color & MASK_COLOR) != COLOR_Y8) { - /* 2 bytes/pixel if not monochrome */ - outImageSize *= 2; - } - - /* total bytes to send including prefix and 4K padding; - must be a multiple of USB_READ_SIZE */ - usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */ - mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1; - /* if size not a multiple of USB_READ_SIZE */ - if (usbInSize & ~mask_mult) - usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK); - return usbInSize; -} - -static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode) -{ - struct device *dev = &sdev->udev->dev; - dev_info(dev, "------------------------------------------------\n"); - dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale); - dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color); - dev_info(dev, "bright: 0x%x\n", mode->bright); - dev_info(dev, "------------------------------------------------\n"); -} - -/* - * set mode is the function which controls the DSP. - * the restart parameter in struct s2255_mode should be set whenever - * the image size could change via color format, video system or image - * size. - * When the restart parameter is set, we sleep for ONE frame to allow the - * DSP time to get the new frame - */ -static int s2255_set_mode(struct s2255_channel *channel, - struct s2255_mode *mode) -{ - int res; - __le32 *buffer; - unsigned long chn_rev; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); - chn_rev = G_chnmap[channel->idx]; - dprintk(3, "%s channel: %d\n", __func__, channel->idx); - /* if JPEG, set the quality */ - if ((mode->color & MASK_COLOR) == COLOR_JPG) { - mode->color &= ~MASK_COLOR; - mode->color |= COLOR_JPG; - mode->color &= ~MASK_JPG_QUALITY; - mode->color |= (channel->jc.quality << 8); - } - /* save the mode */ - channel->mode = *mode; - channel->req_image_size = get_transfer_size(mode); - dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size); - buffer = kzalloc(512, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&dev->udev->dev, "out of mem\n"); - return -ENOMEM; - } - /* set the mode */ - buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); - buffer[2] = CMD_SET_MODE; - memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode)); - channel->setmode_ready = 0; - res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); - if (debug) - s2255_print_cfg(dev, mode); - kfree(buffer); - /* wait at least 3 frames before continuing */ - if (mode->restart) { - wait_event_timeout(channel->wait_setmode, - (channel->setmode_ready != 0), - msecs_to_jiffies(S2255_SETMODE_TIMEOUT)); - if (channel->setmode_ready != 1) { - printk(KERN_DEBUG "s2255: no set mode response\n"); - res = -EFAULT; - } - } - /* clear the restart flag */ - channel->mode.restart = 0; - dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res); - return res; -} - -static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus) -{ - int res; - __le32 *buffer; - u32 chn_rev; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); - chn_rev = G_chnmap[channel->idx]; - dprintk(4, "%s chan %d\n", __func__, channel->idx); - buffer = kzalloc(512, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&dev->udev->dev, "out of mem\n"); - return -ENOMEM; - } - /* form the get vid status command */ - buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); - buffer[2] = CMD_STATUS; - *pstatus = 0; - channel->vidstatus_ready = 0; - res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); - kfree(buffer); - wait_event_timeout(channel->wait_vidstatus, - (channel->vidstatus_ready != 0), - msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT)); - if (channel->vidstatus_ready != 1) { - printk(KERN_DEBUG "s2255: no vidstatus response\n"); - res = -EFAULT; - } - *pstatus = channel->vidstatus; - dprintk(4, "%s, vid status %d\n", __func__, *pstatus); - return res; -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - int res; - struct s2255_fh *fh = priv; - struct s2255_dev *dev = fh->dev; - struct s2255_channel *channel = fh->channel; - int j; - dprintk(4, "%s\n", __func__); - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&dev->udev->dev, "invalid fh type0\n"); - return -EINVAL; - } - if (i != fh->type) { - dev_err(&dev->udev->dev, "invalid fh type1\n"); - return -EINVAL; - } - - if (!res_get(fh)) { - s2255_dev_err(&dev->udev->dev, "stream busy\n"); - return -EBUSY; - } - channel->last_frame = -1; - channel->bad_payload = 0; - channel->cur_frame = 0; - channel->frame_count = 0; - for (j = 0; j < SYS_FRAMES; j++) { - channel->buffer.frame[j].ulState = S2255_READ_IDLE; - channel->buffer.frame[j].cur_size = 0; - } - res = videobuf_streamon(&fh->vb_vidq); - if (res == 0) { - s2255_start_acquire(channel); - channel->b_acquire = 1; - } else - res_free(fh); - - return res; -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct s2255_fh *fh = priv; - dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx); - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - printk(KERN_ERR "invalid fh type0\n"); - return -EINVAL; - } - if (i != fh->type) { - printk(KERN_ERR "invalid type i\n"); - return -EINVAL; - } - s2255_stop_acquire(fh->channel); - videobuf_streamoff(&fh->vb_vidq); - res_free(fh); - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) -{ - struct s2255_fh *fh = priv; - struct s2255_mode mode; - struct videobuf_queue *q = &fh->vb_vidq; - int ret = 0; - mutex_lock(&q->vb_lock); - if (videobuf_queue_is_busy(q)) { - dprintk(1, "queue busy\n"); - ret = -EBUSY; - goto out_s_std; - } - if (res_locked(fh)) { - dprintk(1, "can't change standard after started\n"); - ret = -EBUSY; - goto out_s_std; - } - mode = fh->channel->mode; - if (*i & V4L2_STD_NTSC) { - dprintk(4, "%s NTSC\n", __func__); - /* if changing format, reset frame decimation/intervals */ - if (mode.format != FORMAT_NTSC) { - mode.restart = 1; - mode.format = FORMAT_NTSC; - mode.fdec = FDEC_1; - } - } else if (*i & V4L2_STD_PAL) { - dprintk(4, "%s PAL\n", __func__); - if (mode.format != FORMAT_PAL) { - mode.restart = 1; - mode.format = FORMAT_PAL; - mode.fdec = FDEC_1; - } - } else { - ret = -EINVAL; - } - if (mode.restart) - s2255_set_mode(fh->channel, &mode); -out_s_std: - mutex_unlock(&q->vb_lock); - return ret; -} - -/* Sensoray 2255 is a multiple channel capture device. - It does not have a "crossbar" of inputs. - We use one V4L device per channel. The user must - be aware that certain combinations are not allowed. - For instance, you cannot do full FPS on more than 2 channels(2 videodevs) - at once in color(you can do full fps on 4 channels with greyscale. -*/ -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct s2255_fh *fh = priv; - struct s2255_dev *dev = fh->dev; - struct s2255_channel *channel = fh->channel; - u32 status = 0; - if (inp->index != 0) - return -EINVAL; - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = S2255_NORMS; - inp->status = 0; - if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) { - int rc; - rc = s2255_cmd_status(fh->channel, &status); - dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status); - if (rc == 0) - inp->status = (status & 0x01) ? 0 - : V4L2_IN_ST_NO_SIGNAL; - } - switch (dev->pid) { - case 0x2255: - default: - strlcpy(inp->name, "Composite", sizeof(inp->name)); - break; - case 0x2257: - strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video", - sizeof(inp->name)); - break; - } - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i > 0) - return -EINVAL; - return 0; -} - -/* --- controls ---------------------------------------------- */ -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - struct s2255_dev *dev = fh->dev; - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - v4l2_ctrl_query_fill(qc, -127, 127, 1, DEF_BRIGHT); - break; - case V4L2_CID_CONTRAST: - v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_CONTRAST); - break; - case V4L2_CID_SATURATION: - v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_SATURATION); - break; - case V4L2_CID_HUE: - v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_HUE); - break; - case V4L2_CID_PRIVATE_COLORFILTER: - if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - return -EINVAL; - if ((dev->pid == 0x2257) && (channel->idx > 1)) - return -EINVAL; - strlcpy(qc->name, "Color Filter", sizeof(qc->name)); - qc->type = V4L2_CTRL_TYPE_MENU; - qc->minimum = 0; - qc->maximum = 1; - qc->step = 1; - qc->default_value = 1; - qc->flags = 0; - break; - default: - return -EINVAL; - } - dprintk(4, "%s, id %d\n", __func__, qc->id); - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct s2255_fh *fh = priv; - struct s2255_dev *dev = fh->dev; - struct s2255_channel *channel = fh->channel; - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = channel->mode.bright; - break; - case V4L2_CID_CONTRAST: - ctrl->value = channel->mode.contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = channel->mode.saturation; - break; - case V4L2_CID_HUE: - ctrl->value = channel->mode.hue; - break; - case V4L2_CID_PRIVATE_COLORFILTER: - if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - return -EINVAL; - if ((dev->pid == 0x2257) && (channel->idx > 1)) - return -EINVAL; - ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16); - break; - default: - return -EINVAL; - } - dprintk(4, "%s, id %d val %d\n", __func__, ctrl->id, ctrl->value); - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); - struct s2255_mode mode; - mode = channel->mode; - dprintk(4, "%s\n", __func__); - /* update the mode to the corresponding value */ - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - mode.bright = ctrl->value; - break; - case V4L2_CID_CONTRAST: - mode.contrast = ctrl->value; - break; - case V4L2_CID_HUE: - mode.hue = ctrl->value; - break; - case V4L2_CID_SATURATION: - mode.saturation = ctrl->value; - break; - case V4L2_CID_PRIVATE_COLORFILTER: - if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - return -EINVAL; - if ((dev->pid == 0x2257) && (channel->idx > 1)) - return -EINVAL; - mode.color &= ~MASK_INPUT_TYPE; - mode.color |= ((ctrl->value ? 0 : 1) << 16); - break; - default: - return -EINVAL; - } - mode.restart = 0; - /* set mode here. Note: stream does not need restarted. - some V4L programs restart stream unnecessarily - after a s_crtl. - */ - s2255_set_mode(fh->channel, &mode); - return 0; -} - -static int vidioc_g_jpegcomp(struct file *file, void *priv, - struct v4l2_jpegcompression *jc) -{ - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - *jc = channel->jc; - dprintk(2, "%s: quality %d\n", __func__, jc->quality); - return 0; -} - -static int vidioc_s_jpegcomp(struct file *file, void *priv, - struct v4l2_jpegcompression *jc) -{ - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - if (jc->quality < 0 || jc->quality > 100) - return -EINVAL; - channel->jc.quality = jc->quality; - dprintk(2, "%s: quality %d\n", __func__, jc->quality); - return 0; -} - -static int vidioc_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *sp) -{ - struct s2255_fh *fh = priv; - __u32 def_num, def_dem; - struct s2255_channel *channel = fh->channel; - if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - memset(sp, 0, sizeof(struct v4l2_streamparm)); - sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - sp->parm.capture.capturemode = channel->cap_parm.capturemode; - def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000; - def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000; - sp->parm.capture.timeperframe.denominator = def_dem; - switch (channel->mode.fdec) { - default: - case FDEC_1: - sp->parm.capture.timeperframe.numerator = def_num; - break; - case FDEC_2: - sp->parm.capture.timeperframe.numerator = def_num * 2; - break; - case FDEC_3: - sp->parm.capture.timeperframe.numerator = def_num * 3; - break; - case FDEC_5: - sp->parm.capture.timeperframe.numerator = def_num * 5; - break; - } - dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__, - sp->parm.capture.capturemode, - sp->parm.capture.timeperframe.numerator, - sp->parm.capture.timeperframe.denominator); - return 0; -} - -static int vidioc_s_parm(struct file *file, void *priv, - struct v4l2_streamparm *sp) -{ - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - struct s2255_mode mode; - int fdec = FDEC_1; - __u32 def_num, def_dem; - if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - mode = channel->mode; - /* high quality capture mode requires a stream restart */ - if (channel->cap_parm.capturemode - != sp->parm.capture.capturemode && res_locked(fh)) - return -EBUSY; - def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000; - def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000; - if (def_dem != sp->parm.capture.timeperframe.denominator) - sp->parm.capture.timeperframe.numerator = def_num; - else if (sp->parm.capture.timeperframe.numerator <= def_num) - sp->parm.capture.timeperframe.numerator = def_num; - else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) { - sp->parm.capture.timeperframe.numerator = def_num * 2; - fdec = FDEC_2; - } else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) { - sp->parm.capture.timeperframe.numerator = def_num * 3; - fdec = FDEC_3; - } else { - sp->parm.capture.timeperframe.numerator = def_num * 5; - fdec = FDEC_5; - } - mode.fdec = fdec; - sp->parm.capture.timeperframe.denominator = def_dem; - s2255_set_mode(channel, &mode); - dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n", - __func__, - sp->parm.capture.capturemode, - sp->parm.capture.timeperframe.numerator, - sp->parm.capture.timeperframe.denominator, fdec); - return 0; -} - -static int vidioc_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fe) -{ - int is_ntsc = 0; -#define NUM_FRAME_ENUMS 4 - int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5}; - if (fe->index < 0 || fe->index >= NUM_FRAME_ENUMS) - return -EINVAL; - switch (fe->width) { - case 640: - if (fe->height != 240 && fe->height != 480) - return -EINVAL; - is_ntsc = 1; - break; - case 320: - if (fe->height != 240) - return -EINVAL; - is_ntsc = 1; - break; - case 704: - if (fe->height != 288 && fe->height != 576) - return -EINVAL; - break; - case 352: - if (fe->height != 288) - return -EINVAL; - break; - default: - return -EINVAL; - } - fe->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fe->discrete.denominator = is_ntsc ? 30000 : 25000; - fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index]; - dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator, - fe->discrete.denominator); - return 0; -} - -static int s2255_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct s2255_channel *channel = video_drvdata(file); - struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev); - struct s2255_fh *fh; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - int state; - dprintk(1, "s2255: open called (dev=%s)\n", - video_device_node_name(vdev)); - /* - * open lock necessary to prevent multiple instances - * of v4l-conf (or other programs) from simultaneously - * reloading firmware. - */ - mutex_lock(&dev->open_lock); - state = atomic_read(&dev->fw_data->fw_state); - switch (state) { - case S2255_FW_DISCONNECTING: - mutex_unlock(&dev->open_lock); - return -ENODEV; - case S2255_FW_FAILED: - s2255_dev_err(&dev->udev->dev, - "firmware load failed. retrying.\n"); - s2255_fwload_start(dev, 1); - wait_event_timeout(dev->fw_data->wait_fw, - ((atomic_read(&dev->fw_data->fw_state) - == S2255_FW_SUCCESS) || - (atomic_read(&dev->fw_data->fw_state) - == S2255_FW_DISCONNECTING)), - msecs_to_jiffies(S2255_LOAD_TIMEOUT)); - /* state may have changed, re-read */ - state = atomic_read(&dev->fw_data->fw_state); - break; - case S2255_FW_NOTLOADED: - case S2255_FW_LOADED_DSPWAIT: - /* give S2255_LOAD_TIMEOUT time for firmware to load in case - driver loaded and then device immediately opened */ - printk(KERN_INFO "%s waiting for firmware load\n", __func__); - wait_event_timeout(dev->fw_data->wait_fw, - ((atomic_read(&dev->fw_data->fw_state) - == S2255_FW_SUCCESS) || - (atomic_read(&dev->fw_data->fw_state) - == S2255_FW_DISCONNECTING)), - msecs_to_jiffies(S2255_LOAD_TIMEOUT)); - /* state may have changed, re-read */ - state = atomic_read(&dev->fw_data->fw_state); - break; - case S2255_FW_SUCCESS: - default: - break; - } - /* state may have changed in above switch statement */ - switch (state) { - case S2255_FW_SUCCESS: - break; - case S2255_FW_FAILED: - printk(KERN_INFO "2255 firmware load failed.\n"); - mutex_unlock(&dev->open_lock); - return -ENODEV; - case S2255_FW_DISCONNECTING: - printk(KERN_INFO "%s: disconnecting\n", __func__); - mutex_unlock(&dev->open_lock); - return -ENODEV; - case S2255_FW_LOADED_DSPWAIT: - case S2255_FW_NOTLOADED: - printk(KERN_INFO "%s: firmware not loaded yet" - "please try again later\n", - __func__); - /* - * Timeout on firmware load means device unusable. - * Set firmware failure state. - * On next s2255_open the firmware will be reloaded. - */ - atomic_set(&dev->fw_data->fw_state, - S2255_FW_FAILED); - mutex_unlock(&dev->open_lock); - return -EAGAIN; - default: - printk(KERN_INFO "%s: unknown state\n", __func__); - mutex_unlock(&dev->open_lock); - return -EFAULT; - } - mutex_unlock(&dev->open_lock); - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - file->private_data = fh; - fh->dev = dev; - fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fh->channel = channel; - if (!channel->configured) { - /* configure channel to default state */ - channel->fmt = &formats[0]; - s2255_set_mode(channel, &channel->mode); - channel->configured = 1; - } - dprintk(1, "%s: dev=%s type=%s\n", __func__, - video_device_node_name(vdev), v4l2_type_names[type]); - dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__, - (unsigned long)fh, (unsigned long)dev, - (unsigned long)&channel->vidq); - dprintk(4, "%s: list_empty active=%d\n", __func__, - list_empty(&channel->vidq.active)); - videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops, - NULL, &dev->slock, - fh->type, - V4L2_FIELD_INTERLACED, - sizeof(struct s2255_buffer), - fh, vdev->lock); - return 0; -} - - -static unsigned int s2255_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct s2255_fh *fh = file->private_data; - int rc; - dprintk(100, "%s\n", __func__); - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) - return POLLERR; - rc = videobuf_poll_stream(file, &fh->vb_vidq, wait); - return rc; -} - -static void s2255_destroy(struct s2255_dev *dev) -{ - /* board shutdown stops the read pipe if it is running */ - s2255_board_shutdown(dev); - /* make sure firmware still not trying to load */ - del_timer(&dev->timer); /* only started in .probe and .open */ - if (dev->fw_data->fw_urb) { - usb_kill_urb(dev->fw_data->fw_urb); - usb_free_urb(dev->fw_data->fw_urb); - dev->fw_data->fw_urb = NULL; - } - if (dev->fw_data->fw) - release_firmware(dev->fw_data->fw); - kfree(dev->fw_data->pfw_data); - kfree(dev->fw_data); - /* reset the DSP so firmware can be reloaded next time */ - s2255_reset_dsppower(dev); - mutex_destroy(&dev->open_lock); - mutex_destroy(&dev->lock); - usb_put_dev(dev->udev); - v4l2_device_unregister(&dev->v4l2_dev); - dprintk(1, "%s", __func__); - kfree(dev); -} - -static int s2255_release(struct file *file) -{ - struct s2255_fh *fh = file->private_data; - struct s2255_dev *dev = fh->dev; - struct video_device *vdev = video_devdata(file); - struct s2255_channel *channel = fh->channel; - if (!dev) - return -ENODEV; - /* turn off stream */ - if (res_check(fh)) { - if (channel->b_acquire) - s2255_stop_acquire(fh->channel); - videobuf_streamoff(&fh->vb_vidq); - res_free(fh); - } - videobuf_mmap_free(&fh->vb_vidq); - dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev)); - kfree(fh); - return 0; -} - -static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma) -{ - struct s2255_fh *fh = file->private_data; - int ret; - - if (!fh) - return -ENODEV; - dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma); - ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); - dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__, - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret); - return ret; -} - -static const struct v4l2_file_operations s2255_fops_v4l = { - .owner = THIS_MODULE, - .open = s2255_open, - .release = s2255_release, - .poll = s2255_poll, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = s2255_mmap_v4l, -}; - -static const struct v4l2_ioctl_ops s2255_ioctl_ops = { - .vidioc_querymenu = vidioc_querymenu, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_s_jpegcomp = vidioc_s_jpegcomp, - .vidioc_g_jpegcomp = vidioc_g_jpegcomp, - .vidioc_s_parm = vidioc_s_parm, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_enum_frameintervals = vidioc_enum_frameintervals, -}; - -static void s2255_video_device_release(struct video_device *vdev) -{ - struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev); - dprintk(4, "%s, chnls: %d \n", __func__, - atomic_read(&dev->num_channels)); - if (atomic_dec_and_test(&dev->num_channels)) - s2255_destroy(dev); - return; -} - -static struct video_device template = { - .name = "s2255v", - .fops = &s2255_fops_v4l, - .ioctl_ops = &s2255_ioctl_ops, - .release = s2255_video_device_release, - .tvnorms = S2255_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; - -static int s2255_probe_v4l(struct s2255_dev *dev) -{ - int ret; - int i; - int cur_nr = video_nr; - struct s2255_channel *channel; - ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev); - if (ret) - return ret; - /* initialize all video 4 linux */ - /* register 4 video devices */ - for (i = 0; i < MAX_CHANNELS; i++) { - channel = &dev->channel[i]; - INIT_LIST_HEAD(&channel->vidq.active); - channel->vidq.dev = dev; - /* register 4 video devices */ - channel->vdev = template; - channel->vdev.lock = &dev->lock; - channel->vdev.v4l2_dev = &dev->v4l2_dev; - video_set_drvdata(&channel->vdev, channel); - if (video_nr == -1) - ret = video_register_device(&channel->vdev, - VFL_TYPE_GRABBER, - video_nr); - else - ret = video_register_device(&channel->vdev, - VFL_TYPE_GRABBER, - cur_nr + i); - - if (ret) { - dev_err(&dev->udev->dev, - "failed to register video device!\n"); - break; - } - atomic_inc(&dev->num_channels); - v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", - video_device_node_name(&channel->vdev)); - - } - printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n", - S2255_MAJOR_VERSION, - S2255_MINOR_VERSION); - /* if no channels registered, return error and probe will fail*/ - if (atomic_read(&dev->num_channels) == 0) { - v4l2_device_unregister(&dev->v4l2_dev); - return ret; - } - if (atomic_read(&dev->num_channels) != MAX_CHANNELS) - printk(KERN_WARNING "s2255: Not all channels available.\n"); - return 0; -} - -/* this function moves the usb stream read pipe data - * into the system buffers. - * returns 0 on success, EAGAIN if more data to process( call this - * function again). - * - * Received frame structure: - * bytes 0-3: marker : 0x2255DA4AL (S2255_MARKER_FRAME) - * bytes 4-7: channel: 0-3 - * bytes 8-11: payload size: size of the frame - * bytes 12-payloadsize+12: frame data - */ -static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) -{ - char *pdest; - u32 offset = 0; - int bframe = 0; - char *psrc; - unsigned long copy_size; - unsigned long size; - s32 idx = -1; - struct s2255_framei *frm; - unsigned char *pdata; - struct s2255_channel *channel; - dprintk(100, "buffer to user\n"); - channel = &dev->channel[dev->cc]; - idx = channel->cur_frame; - frm = &channel->buffer.frame[idx]; - if (frm->ulState == S2255_READ_IDLE) { - int jj; - unsigned int cc; - __le32 *pdword; /*data from dsp is little endian */ - int payload; - /* search for marker codes */ - pdata = (unsigned char *)pipe_info->transfer_buffer; - pdword = (__le32 *)pdata; - for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) { - switch (*pdword) { - case S2255_MARKER_FRAME: - dprintk(4, "found frame marker at offset:" - " %d [%x %x]\n", jj, pdata[0], - pdata[1]); - offset = jj + PREFIX_SIZE; - bframe = 1; - cc = pdword[1]; - if (cc >= MAX_CHANNELS) { - printk(KERN_ERR - "bad channel\n"); - return -EINVAL; - } - /* reverse it */ - dev->cc = G_chnmap[cc]; - channel = &dev->channel[dev->cc]; - payload = pdword[3]; - if (payload > channel->req_image_size) { - channel->bad_payload++; - /* discard the bad frame */ - return -EINVAL; - } - channel->pkt_size = payload; - channel->jpg_size = pdword[4]; - break; - case S2255_MARKER_RESPONSE: - - pdata += DEF_USB_BLOCK; - jj += DEF_USB_BLOCK; - if (pdword[1] >= MAX_CHANNELS) - break; - cc = G_chnmap[pdword[1]]; - if (cc >= MAX_CHANNELS) - break; - channel = &dev->channel[cc]; - switch (pdword[2]) { - case S2255_RESPONSE_SETMODE: - /* check if channel valid */ - /* set mode ready */ - channel->setmode_ready = 1; - wake_up(&channel->wait_setmode); - dprintk(5, "setmode ready %d\n", cc); - break; - case S2255_RESPONSE_FW: - dev->chn_ready |= (1 << cc); - if ((dev->chn_ready & 0x0f) != 0x0f) - break; - /* all channels ready */ - printk(KERN_INFO "s2255: fw loaded\n"); - atomic_set(&dev->fw_data->fw_state, - S2255_FW_SUCCESS); - wake_up(&dev->fw_data->wait_fw); - break; - case S2255_RESPONSE_STATUS: - channel->vidstatus = pdword[3]; - channel->vidstatus_ready = 1; - wake_up(&channel->wait_vidstatus); - dprintk(5, "got vidstatus %x chan %d\n", - pdword[3], cc); - break; - default: - printk(KERN_INFO "s2255 unknown resp\n"); - } - default: - pdata++; - break; - } - if (bframe) - break; - } /* for */ - if (!bframe) - return -EINVAL; - } - channel = &dev->channel[dev->cc]; - idx = channel->cur_frame; - frm = &channel->buffer.frame[idx]; - /* search done. now find out if should be acquiring on this channel */ - if (!channel->b_acquire) { - /* we found a frame, but this channel is turned off */ - frm->ulState = S2255_READ_IDLE; - return -EINVAL; - } - - if (frm->ulState == S2255_READ_IDLE) { - frm->ulState = S2255_READ_FRAME; - frm->cur_size = 0; - } - - /* skip the marker 512 bytes (and offset if out of sync) */ - psrc = (u8 *)pipe_info->transfer_buffer + offset; - - - if (frm->lpvbits == NULL) { - dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d", - frm, dev, dev->cc, idx); - return -ENOMEM; - } - - pdest = frm->lpvbits + frm->cur_size; - - copy_size = (pipe_info->cur_transfer_size - offset); - - size = channel->pkt_size - PREFIX_SIZE; - - /* sanity check on pdest */ - if ((copy_size + frm->cur_size) < channel->req_image_size) - memcpy(pdest, psrc, copy_size); - - frm->cur_size += copy_size; - dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size); - - if (frm->cur_size >= size) { - dprintk(2, "****************[%d]Buffer[%d]full*************\n", - dev->cc, idx); - channel->last_frame = channel->cur_frame; - channel->cur_frame++; - /* end of system frame ring buffer, start at zero */ - if ((channel->cur_frame == SYS_FRAMES) || - (channel->cur_frame == channel->buffer.dwFrames)) - channel->cur_frame = 0; - /* frame ready */ - if (channel->b_acquire) - s2255_got_frame(channel, channel->jpg_size); - channel->frame_count++; - frm->ulState = S2255_READ_IDLE; - frm->cur_size = 0; - - } - /* done successfully */ - return 0; -} - -static void s2255_read_video_callback(struct s2255_dev *dev, - struct s2255_pipeinfo *pipe_info) -{ - int res; - dprintk(50, "callback read video \n"); - - if (dev->cc >= MAX_CHANNELS) { - dev->cc = 0; - dev_err(&dev->udev->dev, "invalid channel\n"); - return; - } - /* otherwise copy to the system buffers */ - res = save_frame(dev, pipe_info); - if (res != 0) - dprintk(4, "s2255: read callback failed\n"); - - dprintk(50, "callback read video done\n"); - return; -} - -static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, - u16 Index, u16 Value, void *TransferBuffer, - s32 TransferBufferLength, int bOut) -{ - int r; - if (!bOut) { - r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), - Request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - Value, Index, TransferBuffer, - TransferBufferLength, HZ * 5); - } else { - r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE, - Value, Index, TransferBuffer, - TransferBufferLength, HZ * 5); - } - return r; -} - -/* - * retrieve FX2 firmware version. future use. - * @param dev pointer to device extension - * @return -1 for fail, else returns firmware version as an int(16 bits) - */ -static int s2255_get_fx2fw(struct s2255_dev *dev) -{ - int fw; - int ret; - unsigned char transBuffer[64]; - ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2, - S2255_VR_IN); - if (ret < 0) - dprintk(2, "get fw error: %x\n", ret); - fw = transBuffer[0] + (transBuffer[1] << 8); - dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); - return fw; -} - -/* - * Create the system ring buffer to copy frames into from the - * usb read pipe. - */ -static int s2255_create_sys_buffers(struct s2255_channel *channel) -{ - unsigned long i; - unsigned long reqsize; - dprintk(1, "create sys buffers\n"); - channel->buffer.dwFrames = SYS_FRAMES; - /* always allocate maximum size(PAL) for system buffers */ - reqsize = SYS_FRAMES_MAXSIZE; - - if (reqsize > SYS_FRAMES_MAXSIZE) - reqsize = SYS_FRAMES_MAXSIZE; - - for (i = 0; i < SYS_FRAMES; i++) { - /* allocate the frames */ - channel->buffer.frame[i].lpvbits = vmalloc(reqsize); - dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n", - &channel->buffer.frame[i], channel->idx, i, - channel->buffer.frame[i].lpvbits); - channel->buffer.frame[i].size = reqsize; - if (channel->buffer.frame[i].lpvbits == NULL) { - printk(KERN_INFO "out of memory. using less frames\n"); - channel->buffer.dwFrames = i; - break; - } - } - - /* make sure internal states are set */ - for (i = 0; i < SYS_FRAMES; i++) { - channel->buffer.frame[i].ulState = 0; - channel->buffer.frame[i].cur_size = 0; - } - - channel->cur_frame = 0; - channel->last_frame = -1; - return 0; -} - -static int s2255_release_sys_buffers(struct s2255_channel *channel) -{ - unsigned long i; - dprintk(1, "release sys buffers\n"); - for (i = 0; i < SYS_FRAMES; i++) { - if (channel->buffer.frame[i].lpvbits) { - dprintk(1, "vfree %p\n", - channel->buffer.frame[i].lpvbits); - vfree(channel->buffer.frame[i].lpvbits); - } - channel->buffer.frame[i].lpvbits = NULL; - } - return 0; -} - -static int s2255_board_init(struct s2255_dev *dev) -{ - struct s2255_mode mode_def = DEF_MODEI_NTSC_CONT; - int fw_ver; - int j; - struct s2255_pipeinfo *pipe = &dev->pipe; - dprintk(4, "board init: %p", dev); - memset(pipe, 0, sizeof(*pipe)); - pipe->dev = dev; - pipe->cur_transfer_size = S2255_USB_XFER_SIZE; - pipe->max_transfer_size = S2255_USB_XFER_SIZE; - - pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, - GFP_KERNEL); - if (pipe->transfer_buffer == NULL) { - dprintk(1, "out of memory!\n"); - return -ENOMEM; - } - /* query the firmware */ - fw_ver = s2255_get_fx2fw(dev); - - printk(KERN_INFO "2255 usb firmware version %d.%d\n", - (fw_ver >> 8) & 0xff, - fw_ver & 0xff); - - if (fw_ver < S2255_CUR_USB_FWVER) - dev_err(&dev->udev->dev, - "usb firmware not up to date %d.%d\n", - (fw_ver >> 8) & 0xff, - fw_ver & 0xff); - - for (j = 0; j < MAX_CHANNELS; j++) { - struct s2255_channel *channel = &dev->channel[j]; - channel->b_acquire = 0; - channel->mode = mode_def; - if (dev->pid == 0x2257 && j > 1) - channel->mode.color |= (1 << 16); - channel->jc.quality = S2255_DEF_JPEG_QUAL; - channel->width = LINE_SZ_4CIFS_NTSC; - channel->height = NUM_LINES_4CIFS_NTSC * 2; - channel->fmt = &formats[0]; - channel->mode.restart = 1; - channel->req_image_size = get_transfer_size(&mode_def); - channel->frame_count = 0; - /* create the system buffers */ - s2255_create_sys_buffers(channel); - } - /* start read pipe */ - s2255_start_readpipe(dev); - dprintk(1, "%s: success\n", __func__); - return 0; -} - -static int s2255_board_shutdown(struct s2255_dev *dev) -{ - u32 i; - dprintk(1, "%s: dev: %p", __func__, dev); - - for (i = 0; i < MAX_CHANNELS; i++) { - if (dev->channel[i].b_acquire) - s2255_stop_acquire(&dev->channel[i]); - } - s2255_stop_readpipe(dev); - for (i = 0; i < MAX_CHANNELS; i++) - s2255_release_sys_buffers(&dev->channel[i]); - /* release transfer buffer */ - kfree(dev->pipe.transfer_buffer); - return 0; -} - -static void read_pipe_completion(struct urb *purb) -{ - struct s2255_pipeinfo *pipe_info; - struct s2255_dev *dev; - int status; - int pipe; - pipe_info = purb->context; - dprintk(100, "%s: urb:%p, status %d\n", __func__, purb, - purb->status); - if (pipe_info == NULL) { - dev_err(&purb->dev->dev, "no context!\n"); - return; - } - - dev = pipe_info->dev; - if (dev == NULL) { - dev_err(&purb->dev->dev, "no context!\n"); - return; - } - status = purb->status; - /* if shutting down, do not resubmit, exit immediately */ - if (status == -ESHUTDOWN) { - dprintk(2, "%s: err shutdown\n", __func__); - pipe_info->err_count++; - return; - } - - if (pipe_info->state == 0) { - dprintk(2, "%s: exiting USB pipe", __func__); - return; - } - - if (status == 0) - s2255_read_video_callback(dev, pipe_info); - else { - pipe_info->err_count++; - dprintk(1, "%s: failed URB %d\n", __func__, status); - } - - pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); - /* reuse urb */ - usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, - pipe, - pipe_info->transfer_buffer, - pipe_info->cur_transfer_size, - read_pipe_completion, pipe_info); - - if (pipe_info->state != 0) { - if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) { - dev_err(&dev->udev->dev, "error submitting urb\n"); - } - } else { - dprintk(2, "%s :complete state 0\n", __func__); - } - return; -} - -static int s2255_start_readpipe(struct s2255_dev *dev) -{ - int pipe; - int retval; - struct s2255_pipeinfo *pipe_info = &dev->pipe; - pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); - dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint); - pipe_info->state = 1; - pipe_info->err_count = 0; - pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pipe_info->stream_urb) { - dev_err(&dev->udev->dev, - "ReadStream: Unable to alloc URB\n"); - return -ENOMEM; - } - /* transfer buffer allocated in board_init */ - usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, - pipe, - pipe_info->transfer_buffer, - pipe_info->cur_transfer_size, - read_pipe_completion, pipe_info); - retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); - if (retval) { - printk(KERN_ERR "s2255: start read pipe failed\n"); - return retval; - } - return 0; -} - -/* starts acquisition process */ -static int s2255_start_acquire(struct s2255_channel *channel) -{ - unsigned char *buffer; - int res; - unsigned long chn_rev; - int j; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); - chn_rev = G_chnmap[channel->idx]; - buffer = kzalloc(512, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&dev->udev->dev, "out of mem\n"); - return -ENOMEM; - } - - channel->last_frame = -1; - channel->bad_payload = 0; - channel->cur_frame = 0; - for (j = 0; j < SYS_FRAMES; j++) { - channel->buffer.frame[j].ulState = 0; - channel->buffer.frame[j].cur_size = 0; - } - - /* send the start command */ - *(__le32 *) buffer = IN_DATA_TOKEN; - *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev); - *((__le32 *) buffer + 2) = CMD_START; - res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); - if (res != 0) - dev_err(&dev->udev->dev, "CMD_START error\n"); - - dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res); - kfree(buffer); - return 0; -} - -static int s2255_stop_acquire(struct s2255_channel *channel) -{ - unsigned char *buffer; - int res; - unsigned long chn_rev; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); - chn_rev = G_chnmap[channel->idx]; - buffer = kzalloc(512, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&dev->udev->dev, "out of mem\n"); - return -ENOMEM; - } - /* send the stop command */ - *(__le32 *) buffer = IN_DATA_TOKEN; - *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev); - *((__le32 *) buffer + 2) = CMD_STOP; - res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); - if (res != 0) - dev_err(&dev->udev->dev, "CMD_STOP error\n"); - kfree(buffer); - channel->b_acquire = 0; - dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res); - return res; -} - -static void s2255_stop_readpipe(struct s2255_dev *dev) -{ - struct s2255_pipeinfo *pipe = &dev->pipe; - - pipe->state = 0; - if (pipe->stream_urb) { - /* cancel urb */ - usb_kill_urb(pipe->stream_urb); - usb_free_urb(pipe->stream_urb); - pipe->stream_urb = NULL; - } - dprintk(4, "%s", __func__); - return; -} - -static void s2255_fwload_start(struct s2255_dev *dev, int reset) -{ - if (reset) - s2255_reset_dsppower(dev); - dev->fw_data->fw_size = dev->fw_data->fw->size; - atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED); - memcpy(dev->fw_data->pfw_data, - dev->fw_data->fw->data, CHUNK_SIZE); - dev->fw_data->fw_loaded = CHUNK_SIZE; - usb_fill_bulk_urb(dev->fw_data->fw_urb, dev->udev, - usb_sndbulkpipe(dev->udev, 2), - dev->fw_data->pfw_data, - CHUNK_SIZE, s2255_fwchunk_complete, - dev->fw_data); - mod_timer(&dev->timer, jiffies + HZ); -} - -/* standard usb probe function */ -static int s2255_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct s2255_dev *dev = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int i; - int retval = -ENOMEM; - __le32 *pdata; - int fw_size; - dprintk(2, "%s\n", __func__); - /* allocate memory for our device state and initialize it to zero */ - dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL); - if (dev == NULL) { - s2255_dev_err(&interface->dev, "out of memory\n"); - return -ENOMEM; - } - atomic_set(&dev->num_channels, 0); - dev->pid = id->idProduct; - dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); - if (!dev->fw_data) - goto errorFWDATA1; - mutex_init(&dev->lock); - mutex_init(&dev->open_lock); - /* grab usb_device and save it */ - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - if (dev->udev == NULL) { - dev_err(&interface->dev, "null usb device\n"); - retval = -ENODEV; - goto errorUDEV; - } - dprintk(1, "dev: %p, udev %p interface %p\n", dev, - dev->udev, interface); - dev->interface = interface; - /* set up the endpoint information */ - iface_desc = interface->cur_altsetting; - dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints); - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { - /* we found the bulk in endpoint */ - dev->read_endpoint = endpoint->bEndpointAddress; - } - } - - if (!dev->read_endpoint) { - dev_err(&interface->dev, "Could not find bulk-in endpoint\n"); - goto errorEP; - } - init_timer(&dev->timer); - dev->timer.function = s2255_timer; - dev->timer.data = (unsigned long)dev->fw_data; - init_waitqueue_head(&dev->fw_data->wait_fw); - for (i = 0; i < MAX_CHANNELS; i++) { - struct s2255_channel *channel = &dev->channel[i]; - dev->channel[i].idx = i; - init_waitqueue_head(&channel->wait_setmode); - init_waitqueue_head(&channel->wait_vidstatus); - } - - dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->fw_data->fw_urb) { - dev_err(&interface->dev, "out of memory!\n"); - goto errorFWURB; - } - - dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); - if (!dev->fw_data->pfw_data) { - dev_err(&interface->dev, "out of memory!\n"); - goto errorFWDATA2; - } - /* load the first chunk */ - if (request_firmware(&dev->fw_data->fw, - FIRMWARE_FILE_NAME, &dev->udev->dev)) { - printk(KERN_ERR "sensoray 2255 failed to get firmware\n"); - goto errorREQFW; - } - /* check the firmware is valid */ - fw_size = dev->fw_data->fw->size; - pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8]; - - if (*pdata != S2255_FW_MARKER) { - printk(KERN_INFO "Firmware invalid.\n"); - retval = -ENODEV; - goto errorFWMARKER; - } else { - /* make sure firmware is the latest */ - __le32 *pRel; - pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; - printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel); - dev->dsp_fw_ver = *pRel; - if (*pRel < S2255_CUR_DSP_FWVER) - printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); - if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER) - printk(KERN_WARNING "s2255: 2257 requires firmware %d" - " or above.\n", S2255_MIN_DSP_COLORFILTER); - } - usb_reset_device(dev->udev); - /* load 2255 board specific */ - retval = s2255_board_init(dev); - if (retval) - goto errorBOARDINIT; - spin_lock_init(&dev->slock); - s2255_fwload_start(dev, 0); - /* loads v4l specific */ - retval = s2255_probe_v4l(dev); - if (retval) - goto errorBOARDINIT; - dev_info(&interface->dev, "Sensoray 2255 detected\n"); - return 0; -errorBOARDINIT: - s2255_board_shutdown(dev); -errorFWMARKER: - release_firmware(dev->fw_data->fw); -errorREQFW: - kfree(dev->fw_data->pfw_data); -errorFWDATA2: - usb_free_urb(dev->fw_data->fw_urb); -errorFWURB: - del_timer(&dev->timer); -errorEP: - usb_put_dev(dev->udev); -errorUDEV: - kfree(dev->fw_data); - mutex_destroy(&dev->open_lock); - mutex_destroy(&dev->lock); -errorFWDATA1: - kfree(dev); - printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval); - return retval; -} - -/* disconnect routine. when board is removed physically or with rmmod */ -static void s2255_disconnect(struct usb_interface *interface) -{ - struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface)); - int i; - int channels = atomic_read(&dev->num_channels); - mutex_lock(&dev->lock); - v4l2_device_disconnect(&dev->v4l2_dev); - mutex_unlock(&dev->lock); - /*see comments in the uvc_driver.c usb disconnect function */ - atomic_inc(&dev->num_channels); - /* unregister each video device. */ - for (i = 0; i < channels; i++) - video_unregister_device(&dev->channel[i].vdev); - /* wake up any of our timers */ - atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); - wake_up(&dev->fw_data->wait_fw); - for (i = 0; i < MAX_CHANNELS; i++) { - dev->channel[i].setmode_ready = 1; - wake_up(&dev->channel[i].wait_setmode); - dev->channel[i].vidstatus_ready = 1; - wake_up(&dev->channel[i].wait_vidstatus); - } - if (atomic_dec_and_test(&dev->num_channels)) - s2255_destroy(dev); - dev_info(&interface->dev, "%s\n", __func__); -} - -static struct usb_driver s2255_driver = { - .name = S2255_DRIVER_NAME, - .probe = s2255_probe, - .disconnect = s2255_disconnect, - .id_table = s2255_table, -}; - -static int __init usb_s2255_init(void) -{ - int result; - /* register this driver with the USB subsystem */ - result = usb_register(&s2255_driver); - if (result) - pr_err(KBUILD_MODNAME - ": usb_register failed. Error number %d\n", result); - dprintk(2, "%s\n", __func__); - return result; -} - -static void __exit usb_s2255_exit(void) -{ - usb_deregister(&s2255_driver); -} - -module_init(usb_s2255_init); -module_exit(usb_s2255_exit); - -MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver"); -MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-capture.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-capture.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-capture.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-capture.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,916 +0,0 @@ -/* - * Samsung S5P SoC series camera interface (camera capture) driver - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd - * Author: Sylwester Nawrocki, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "fimc-core.h" - -static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc, - struct s5p_fimc_isp_info *isp_info) -{ - struct i2c_adapter *i2c_adap; - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct v4l2_subdev *sd = NULL; - - i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num); - if (!i2c_adap) - return ERR_PTR(-ENOMEM); - - sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap, - isp_info->board_info, NULL); - if (!sd) { - v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n"); - return NULL; - } - - v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly\n", - isp_info->board_info->type); - - return sd; -} - -static void fimc_subdev_unregister(struct fimc_dev *fimc) -{ - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct i2c_client *client; - - if (vid_cap->input_index < 0) - return; /* Subdevice already released or not registered. */ - - if (vid_cap->sd) { - v4l2_device_unregister_subdev(vid_cap->sd); - client = v4l2_get_subdevdata(vid_cap->sd); - i2c_unregister_device(client); - i2c_put_adapter(client->adapter); - vid_cap->sd = NULL; - } - - vid_cap->input_index = -1; -} - -/** - * fimc_subdev_attach - attach v4l2_subdev to camera host interface - * - * @fimc: FIMC device information - * @index: index to the array of available subdevices, - * -1 for full array search or non negative value - * to select specific subdevice - */ -static int fimc_subdev_attach(struct fimc_dev *fimc, int index) -{ - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct s5p_platform_fimc *pdata = fimc->pdata; - struct s5p_fimc_isp_info *isp_info; - struct v4l2_subdev *sd; - int i; - - for (i = 0; i < pdata->num_clients; ++i) { - isp_info = &pdata->isp_info[i]; - - if (index >= 0 && i != index) - continue; - - sd = fimc_subdev_register(fimc, isp_info); - if (!IS_ERR_OR_NULL(sd)) { - vid_cap->sd = sd; - vid_cap->input_index = i; - - return 0; - } - } - - vid_cap->input_index = -1; - vid_cap->sd = NULL; - v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed\n", - fimc->id); - return -ENODEV; -} - -static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index) -{ - struct s5p_fimc_isp_info *isp_info; - struct s5p_platform_fimc *pdata = fimc->pdata; - int ret; - - if (index >= pdata->num_clients) - return -EINVAL; - - isp_info = &pdata->isp_info[index]; - - if (isp_info->clk_frequency) - clk_set_rate(fimc->clock[CLK_CAM], isp_info->clk_frequency); - - ret = clk_enable(fimc->clock[CLK_CAM]); - if (ret) - return ret; - - ret = fimc_subdev_attach(fimc, index); - if (ret) - return ret; - - ret = fimc_hw_set_camera_polarity(fimc, isp_info); - if (ret) - return ret; - - ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 1); - if (!ret) - return ret; - - /* enabling power failed so unregister subdev */ - fimc_subdev_unregister(fimc); - - v4l2_err(&fimc->vid_cap.v4l2_dev, "ISP initialization failed: %d\n", - ret); - - return ret; -} - -static int fimc_stop_capture(struct fimc_dev *fimc) -{ - unsigned long flags; - struct fimc_vid_cap *cap; - struct fimc_vid_buffer *buf; - - cap = &fimc->vid_cap; - - if (!fimc_capture_active(fimc)) - return 0; - - spin_lock_irqsave(&fimc->slock, flags); - set_bit(ST_CAPT_SHUT, &fimc->state); - fimc_deactivate_capture(fimc); - spin_unlock_irqrestore(&fimc->slock, flags); - - wait_event_timeout(fimc->irq_queue, - !test_bit(ST_CAPT_SHUT, &fimc->state), - FIMC_SHUTDOWN_TIMEOUT); - - v4l2_subdev_call(cap->sd, video, s_stream, 0); - - spin_lock_irqsave(&fimc->slock, flags); - fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | - 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM); - - fimc->vid_cap.active_buf_cnt = 0; - - /* Release buffers that were enqueued in the driver by videobuf2. */ - while (!list_empty(&cap->pending_buf_q)) { - buf = pending_queue_pop(cap); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - } - - while (!list_empty(&cap->active_buf_q)) { - buf = active_queue_pop(cap); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - } - - spin_unlock_irqrestore(&fimc->slock, flags); - - dbg("state: 0x%lx", fimc->state); - return 0; -} - -static int start_streaming(struct vb2_queue *q) -{ - struct fimc_ctx *ctx = q->drv_priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct s5p_fimc_isp_info *isp_info; - int ret; - - fimc_hw_reset(fimc); - - ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); - if (ret && ret != -ENOIOCTLCMD) - return ret; - - ret = fimc_prepare_config(ctx, ctx->state); - if (ret) - return ret; - - isp_info = &fimc->pdata->isp_info[fimc->vid_cap.input_index]; - fimc_hw_set_camera_type(fimc, isp_info); - fimc_hw_set_camera_source(fimc, isp_info); - fimc_hw_set_camera_offset(fimc, &ctx->s_frame); - - if (ctx->state & FIMC_PARAMS) { - ret = fimc_set_scaler_info(ctx); - if (ret) { - err("Scaler setup error"); - return ret; - } - fimc_hw_set_input_path(ctx); - fimc_hw_set_prescaler(ctx); - fimc_hw_set_mainscaler(ctx); - fimc_hw_set_target_format(ctx); - fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); - } - - fimc_hw_set_output_path(ctx); - fimc_hw_set_out_dma(ctx); - - INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q); - INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); - fimc->vid_cap.active_buf_cnt = 0; - fimc->vid_cap.frame_count = 0; - fimc->vid_cap.buf_index = 0; - - set_bit(ST_CAPT_PEND, &fimc->state); - - return 0; -} - -static int stop_streaming(struct vb2_queue *q) -{ - struct fimc_ctx *ctx = q->drv_priv; - struct fimc_dev *fimc = ctx->fimc_dev; - - if (!fimc_capture_active(fimc)) - return -EINVAL; - - return fimc_stop_capture(fimc); -} - -static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) -{ - if (!fr || plane >= fr->fmt->memplanes) - return 0; - - dbg("%s: w: %d. h: %d. depth[%d]: %d", - __func__, fr->width, fr->height, plane, fr->fmt->depth[plane]); - - return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; - -} - -static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned long sizes[], - void *allocators[]) -{ - struct fimc_ctx *ctx = vq->drv_priv; - struct fimc_fmt *fmt = ctx->d_frame.fmt; - int i; - - if (!fmt) - return -EINVAL; - - *num_planes = fmt->memplanes; - - dbg("%s, buffer count=%d, plane count=%d", - __func__, *num_buffers, *num_planes); - - for (i = 0; i < fmt->memplanes; i++) { - sizes[i] = get_plane_size(&ctx->d_frame, i); - dbg("plane: %u, plane_size: %lu", i, sizes[i]); - allocators[i] = ctx->fimc_dev->alloc_ctx; - } - - return 0; -} - -static int buffer_init(struct vb2_buffer *vb) -{ - /* TODO: */ - return 0; -} - -static int buffer_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct fimc_ctx *ctx = vq->drv_priv; - struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev; - int i; - - if (!ctx->d_frame.fmt || vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; - - for (i = 0; i < ctx->d_frame.fmt->memplanes; i++) { - unsigned long size = get_plane_size(&ctx->d_frame, i); - - if (vb2_plane_size(vb, i) < size) { - v4l2_err(v4l2_dev, "User buffer too small (%ld < %ld)\n", - vb2_plane_size(vb, i), size); - return -EINVAL; - } - - vb2_set_plane_payload(vb, i, size); - } - - return 0; -} - -static void buffer_queue(struct vb2_buffer *vb) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_vid_buffer *buf - = container_of(vb, struct fimc_vid_buffer, vb); - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - unsigned long flags; - int min_bufs; - - spin_lock_irqsave(&fimc->slock, flags); - fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr); - - if (!test_bit(ST_CAPT_STREAM, &fimc->state) - && vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) { - /* Setup the buffer directly for processing. */ - int buf_id = (vid_cap->reqbufs_count == 1) ? -1 : - vid_cap->buf_index; - - fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id); - buf->index = vid_cap->buf_index; - active_queue_add(vid_cap, buf); - - if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS) - vid_cap->buf_index = 0; - } else { - fimc_pending_queue_add(vid_cap, buf); - } - - min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1; - - if (vid_cap->active_buf_cnt >= min_bufs && - !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) - fimc_activate_capture(ctx); - - spin_unlock_irqrestore(&fimc->slock, flags); -} - -static void fimc_lock(struct vb2_queue *vq) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_lock(&ctx->fimc_dev->lock); -} - -static void fimc_unlock(struct vb2_queue *vq) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_unlock(&ctx->fimc_dev->lock); -} - -static struct vb2_ops fimc_capture_qops = { - .queue_setup = queue_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_init = buffer_init, - .wait_prepare = fimc_unlock, - .wait_finish = fimc_lock, - .start_streaming = start_streaming, - .stop_streaming = stop_streaming, -}; - -static int fimc_capture_open(struct file *file) -{ - struct fimc_dev *fimc = video_drvdata(file); - int ret = 0; - - dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); - - /* Return if the corresponding video mem2mem node is already opened. */ - if (fimc_m2m_active(fimc)) - return -EBUSY; - - if (++fimc->vid_cap.refcnt == 1) { - ret = fimc_isp_subdev_init(fimc, 0); - if (ret) { - fimc->vid_cap.refcnt--; - return -EIO; - } - } - - file->private_data = fimc->vid_cap.ctx; - - return 0; -} - -static int fimc_capture_close(struct file *file) -{ - struct fimc_dev *fimc = video_drvdata(file); - - dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); - - if (--fimc->vid_cap.refcnt == 0) { - fimc_stop_capture(fimc); - vb2_queue_release(&fimc->vid_cap.vbq); - - v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n"); - - v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); - clk_disable(fimc->clock[CLK_CAM]); - fimc_subdev_unregister(fimc); - } - - return 0; -} - -static unsigned int fimc_capture_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; - - return vb2_poll(&fimc->vid_cap.vbq, file, wait); -} - -static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; - - return vb2_mmap(&fimc->vid_cap.vbq, vma); -} - -/* video device file operations */ -static const struct v4l2_file_operations fimc_capture_fops = { - .owner = THIS_MODULE, - .open = fimc_capture_open, - .release = fimc_capture_close, - .poll = fimc_capture_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = fimc_capture_mmap, -}; - -static int fimc_vidioc_querycap_capture(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; - - strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); - strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); - cap->bus_info[0] = 0; - cap->version = KERNEL_VERSION(1, 0, 0); - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE_MPLANE; - - return 0; -} - -/* Synchronize formats of the camera interface input and attached sensor. */ -static int sync_capture_fmt(struct fimc_ctx *ctx) -{ - struct fimc_frame *frame = &ctx->s_frame; - struct fimc_dev *fimc = ctx->fimc_dev; - struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt; - int ret; - - fmt->width = ctx->d_frame.o_width; - fmt->height = ctx->d_frame.o_height; - - ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt); - if (ret == -ENOIOCTLCMD) { - err("s_mbus_fmt failed"); - return ret; - } - dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code); - - frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM); - if (!frame->fmt) { - err("fimc source format not found\n"); - return -EINVAL; - } - - frame->f_width = fmt->width; - frame->f_height = fmt->height; - frame->width = fmt->width; - frame->height = fmt->height; - frame->o_width = fmt->width; - frame->o_height = fmt->height; - frame->offs_h = 0; - frame->offs_v = 0; - - return 0; -} - -static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_frame *frame; - struct v4l2_pix_format_mplane *pix; - int ret; - int i; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; - - ret = fimc_vidioc_try_fmt_mplane(file, priv, f); - if (ret) - return ret; - - if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) - return -EBUSY; - - frame = &ctx->d_frame; - - pix = &f->fmt.pix_mp; - frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM); - if (!frame->fmt) { - err("fimc target format not found\n"); - return -EINVAL; - } - - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; - - /* Output DMA frame pixel size and offsets. */ - frame->f_width = pix->plane_fmt[0].bytesperline * 8 - / frame->fmt->depth[0]; - frame->f_height = pix->height; - frame->width = pix->width; - frame->height = pix->height; - frame->o_width = pix->width; - frame->o_height = pix->height; - frame->offs_h = 0; - frame->offs_v = 0; - - ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT); - - ret = sync_capture_fmt(ctx); - return ret; -} - -static int fimc_cap_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct fimc_ctx *ctx = priv; - struct s5p_platform_fimc *pldata = ctx->fimc_dev->pdata; - struct s5p_fimc_isp_info *isp_info; - - if (i->index >= pldata->num_clients) - return -EINVAL; - - isp_info = &pldata->isp_info[i->index]; - - i->type = V4L2_INPUT_TYPE_CAMERA; - strncpy(i->name, isp_info->board_info->type, 32); - return 0; -} - -static int fimc_cap_s_input(struct file *file, void *priv, - unsigned int i) -{ - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct s5p_platform_fimc *pdata = fimc->pdata; - - if (fimc_capture_active(ctx->fimc_dev)) - return -EBUSY; - - if (i >= pdata->num_clients) - return -EINVAL; - - - if (fimc->vid_cap.sd) { - int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); - if (ret) - err("s_power failed: %d", ret); - - clk_disable(fimc->clock[CLK_CAM]); - } - - /* Release the attached sensor subdevice. */ - fimc_subdev_unregister(fimc); - - return fimc_isp_subdev_init(fimc, i); -} - -static int fimc_cap_g_input(struct file *file, void *priv, - unsigned int *i) -{ - struct fimc_ctx *ctx = priv; - struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; - - *i = cap->input_index; - return 0; -} - -static int fimc_cap_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - - if (fimc_capture_active(fimc) || !fimc->vid_cap.sd) - return -EBUSY; - - if (!(ctx->state & FIMC_DST_FMT)) { - v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n"); - return -EINVAL; - } - - return vb2_streamon(&fimc->vid_cap.vbq, type); -} - -static int fimc_cap_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - - return vb2_streamoff(&fimc->vid_cap.vbq, type); -} - -static int fimc_cap_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct fimc_ctx *ctx = priv; - struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; - int ret; - - - ret = vb2_reqbufs(&cap->vbq, reqbufs); - if (!ret) - cap->reqbufs_count = reqbufs->count; - - return ret; -} - -static int fimc_cap_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_ctx *ctx = priv; - struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; - - return vb2_querybuf(&cap->vbq, buf); -} - -static int fimc_cap_qbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_ctx *ctx = priv; - struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; - return vb2_qbuf(&cap->vbq, buf); -} - -static int fimc_cap_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_ctx *ctx = priv; - return vb2_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf, - file->f_flags & O_NONBLOCK); -} - -static int fimc_cap_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fimc_ctx *ctx = priv; - int ret = -EINVAL; - - /* Allow any controls but 90/270 rotation while streaming */ - if (!fimc_capture_active(ctx->fimc_dev) || - ctrl->id != V4L2_CID_ROTATE || - (ctrl->value != 90 && ctrl->value != 270)) { - ret = check_ctrl_val(ctx, ctrl); - if (!ret) { - ret = fimc_s_ctrl(ctx, ctrl); - if (!ret) - ctx->state |= FIMC_PARAMS; - } - } - if (ret == -EINVAL) - ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, - core, s_ctrl, ctrl); - return ret; -} - -static int fimc_cap_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cr) -{ - struct fimc_frame *f; - struct fimc_ctx *ctx = fh; - - if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; - - f = &ctx->s_frame; - - cr->bounds.left = 0; - cr->bounds.top = 0; - cr->bounds.width = f->o_width; - cr->bounds.height = f->o_height; - cr->defrect = cr->bounds; - - return 0; -} - -static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) -{ - struct fimc_frame *f; - struct fimc_ctx *ctx = file->private_data; - - f = &ctx->s_frame; - - cr->c.left = f->offs_h; - cr->c.top = f->offs_v; - cr->c.width = f->width; - cr->c.height = f->height; - - return 0; -} - -static int fimc_cap_s_crop(struct file *file, void *fh, - struct v4l2_crop *cr) -{ - struct fimc_frame *f; - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; - int ret = -EINVAL; - - if (fimc_capture_active(fimc)) - return -EBUSY; - - ret = fimc_try_crop(ctx, cr); - if (ret) - return ret; - - if (!(ctx->state & FIMC_DST_FMT)) { - v4l2_err(&fimc->vid_cap.v4l2_dev, - "Capture color format not set\n"); - return -EINVAL; /* TODO: make sure this is the right value */ - } - - f = &ctx->s_frame; - /* Check for the pixel scaling ratio when cropping input image. */ - ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, - ctx->d_frame.width, ctx->d_frame.height, - ctx->rotation); - if (ret) { - v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range\n"); - return ret; - } - - f->offs_h = cr->c.left; - f->offs_v = cr->c.top; - f->width = cr->c.width; - f->height = cr->c.height; - - return 0; -} - - -static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { - .vidioc_querycap = fimc_vidioc_querycap_capture, - - .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane, - .vidioc_try_fmt_vid_cap_mplane = fimc_vidioc_try_fmt_mplane, - .vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane, - .vidioc_g_fmt_vid_cap_mplane = fimc_vidioc_g_fmt_mplane, - - .vidioc_reqbufs = fimc_cap_reqbufs, - .vidioc_querybuf = fimc_cap_querybuf, - - .vidioc_qbuf = fimc_cap_qbuf, - .vidioc_dqbuf = fimc_cap_dqbuf, - - .vidioc_streamon = fimc_cap_streamon, - .vidioc_streamoff = fimc_cap_streamoff, - - .vidioc_queryctrl = fimc_vidioc_queryctrl, - .vidioc_g_ctrl = fimc_vidioc_g_ctrl, - .vidioc_s_ctrl = fimc_cap_s_ctrl, - - .vidioc_g_crop = fimc_cap_g_crop, - .vidioc_s_crop = fimc_cap_s_crop, - .vidioc_cropcap = fimc_cap_cropcap, - - .vidioc_enum_input = fimc_cap_enum_input, - .vidioc_s_input = fimc_cap_s_input, - .vidioc_g_input = fimc_cap_g_input, -}; - -/* fimc->lock must be already initialized */ -int fimc_register_capture_device(struct fimc_dev *fimc) -{ - struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev; - struct video_device *vfd; - struct fimc_vid_cap *vid_cap; - struct fimc_ctx *ctx; - struct v4l2_format f; - struct fimc_frame *fr; - struct vb2_queue *q; - int ret; - - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->fimc_dev = fimc; - ctx->in_path = FIMC_CAMERA; - ctx->out_path = FIMC_DMA; - ctx->state = FIMC_CTX_CAP; - - /* Default format of the output frames */ - f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; - fr = &ctx->d_frame; - fr->fmt = find_format(&f, FMT_FLAGS_M2M); - fr->width = fr->f_width = fr->o_width = 640; - fr->height = fr->f_height = fr->o_height = 480; - - if (!v4l2_dev->name[0]) - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), - "%s.capture", dev_name(&fimc->pdev->dev)); - - ret = v4l2_device_register(NULL, v4l2_dev); - if (ret) - goto err_info; - - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(v4l2_dev, "Failed to allocate video device\n"); - goto err_v4l2_reg; - } - - snprintf(vfd->name, sizeof(vfd->name), "%s:cap", - dev_name(&fimc->pdev->dev)); - - vfd->fops = &fimc_capture_fops; - vfd->ioctl_ops = &fimc_capture_ioctl_ops; - vfd->minor = -1; - vfd->release = video_device_release; - vfd->lock = &fimc->lock; - video_set_drvdata(vfd, fimc); - - vid_cap = &fimc->vid_cap; - vid_cap->vfd = vfd; - vid_cap->active_buf_cnt = 0; - vid_cap->reqbufs_count = 0; - vid_cap->refcnt = 0; - /* Default color format for image sensor */ - vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8; - - INIT_LIST_HEAD(&vid_cap->pending_buf_q); - INIT_LIST_HEAD(&vid_cap->active_buf_q); - spin_lock_init(&ctx->slock); - vid_cap->ctx = ctx; - - q = &fimc->vid_cap.vbq; - memset(q, 0, sizeof(*q)); - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->drv_priv = fimc->vid_cap.ctx; - q->ops = &fimc_capture_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct fimc_vid_buffer); - - vb2_queue_init(q); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); - if (ret) { - v4l2_err(v4l2_dev, "Failed to register video device\n"); - goto err_vd_reg; - } - - v4l2_info(v4l2_dev, - "FIMC capture driver registered as /dev/video%d\n", - vfd->num); - - return 0; - -err_vd_reg: - video_device_release(vfd); -err_v4l2_reg: - v4l2_device_unregister(v4l2_dev); -err_info: - dev_err(&fimc->pdev->dev, "failed to install\n"); - return ret; -} - -void fimc_unregister_capture_device(struct fimc_dev *fimc) -{ - struct fimc_vid_cap *capture = &fimc->vid_cap; - - if (capture->vfd) - video_unregister_device(capture->vfd); - - kfree(capture->ctx); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-core.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1931 +0,0 @@ -/* - * S5P camera interface (video postprocessor) driver - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd - * - * Sylwester Nawrocki, - * - * 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, - * or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fimc-core.h" - -static char *fimc_clocks[MAX_FIMC_CLOCKS] = { - "sclk_fimc", "fimc", "sclk_cam" -}; - -static struct fimc_fmt fimc_formats[] = { - { - .name = "RGB565", - .fourcc = V4L2_PIX_FMT_RGB565X, - .depth = { 16 }, - .color = S5P_FIMC_RGB565, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE, - .flags = FMT_FLAGS_M2M, - }, { - .name = "BGR666", - .fourcc = V4L2_PIX_FMT_BGR666, - .depth = { 32 }, - .color = S5P_FIMC_RGB666, - .memplanes = 1, - .colplanes = 1, - .flags = FMT_FLAGS_M2M, - }, { - .name = "XRGB-8-8-8-8, 32 bpp", - .fourcc = V4L2_PIX_FMT_RGB32, - .depth = { 32 }, - .color = S5P_FIMC_RGB888, - .memplanes = 1, - .colplanes = 1, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:2 packed, YCbYCr", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = { 16 }, - .color = S5P_FIMC_YCBYCR422, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, - }, { - .name = "YUV 4:2:2 packed, CbYCrY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = { 16 }, - .color = S5P_FIMC_CBYCRY422, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, - }, { - .name = "YUV 4:2:2 packed, CrYCbY", - .fourcc = V4L2_PIX_FMT_VYUY, - .depth = { 16 }, - .color = S5P_FIMC_CRYCBY422, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, - }, { - .name = "YUV 4:2:2 packed, YCrYCb", - .fourcc = V4L2_PIX_FMT_YVYU, - .depth = { 16 }, - .color = S5P_FIMC_YCRYCB422, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, - }, { - .name = "YUV 4:2:2 planar, Y/Cb/Cr", - .fourcc = V4L2_PIX_FMT_YUV422P, - .depth = { 12 }, - .color = S5P_FIMC_YCBYCR422, - .memplanes = 1, - .colplanes = 3, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:2 planar, Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV16, - .depth = { 16 }, - .color = S5P_FIMC_YCBYCR422, - .memplanes = 1, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:2 planar, Y/CrCb", - .fourcc = V4L2_PIX_FMT_NV61, - .depth = { 16 }, - .color = S5P_FIMC_YCRYCB422, - .memplanes = 1, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV420, - .depth = { 12 }, - .color = S5P_FIMC_YCBCR420, - .memplanes = 1, - .colplanes = 3, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 planar, Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12, - .depth = { 12 }, - .color = S5P_FIMC_YCBCR420, - .memplanes = 1, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12M, - .color = S5P_FIMC_YCBCR420, - .depth = { 8, 4 }, - .memplanes = 2, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr", - .fourcc = V4L2_PIX_FMT_YUV420M, - .color = S5P_FIMC_YCBCR420, - .depth = { 8, 2, 2 }, - .memplanes = 3, - .colplanes = 3, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled", - .fourcc = V4L2_PIX_FMT_NV12MT, - .color = S5P_FIMC_YCBCR420, - .depth = { 8, 4 }, - .memplanes = 2, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, -}; - -static struct v4l2_queryctrl fimc_ctrls[] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Horizontal flip", - .minimum = 0, - .maximum = 1, - .default_value = 0, - }, { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vertical flip", - .minimum = 0, - .maximum = 1, - .default_value = 0, - }, { - .id = V4L2_CID_ROTATE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Rotation (CCW)", - .minimum = 0, - .maximum = 270, - .step = 90, - .default_value = 0, - }, -}; - - -static struct v4l2_queryctrl *get_ctrl(int id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(fimc_ctrls); ++i) - if (id == fimc_ctrls[i].id) - return &fimc_ctrls[i]; - return NULL; -} - -int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot) -{ - int tx, ty; - - if (rot == 90 || rot == 270) { - ty = dw; - tx = dh; - } else { - tx = dw; - ty = dh; - } - - if ((sw >= SCALER_MAX_HRATIO * tx) || (sh >= SCALER_MAX_VRATIO * ty)) - return -EINVAL; - - return 0; -} - -static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) -{ - u32 sh = 6; - - if (src >= 64 * tar) - return -EINVAL; - - while (sh--) { - u32 tmp = 1 << sh; - if (src >= tar * tmp) { - *shift = sh, *ratio = tmp; - return 0; - } - } - - *shift = 0, *ratio = 1; - - dbg("s: %d, t: %d, shift: %d, ratio: %d", - src, tar, *shift, *ratio); - return 0; -} - -int fimc_set_scaler_info(struct fimc_ctx *ctx) -{ - struct fimc_scaler *sc = &ctx->scaler; - struct fimc_frame *s_frame = &ctx->s_frame; - struct fimc_frame *d_frame = &ctx->d_frame; - struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; - int tx, ty, sx, sy; - int ret; - - if (ctx->rotation == 90 || ctx->rotation == 270) { - ty = d_frame->width; - tx = d_frame->height; - } else { - tx = d_frame->width; - ty = d_frame->height; - } - if (tx <= 0 || ty <= 0) { - v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, - "invalid target size: %d x %d", tx, ty); - return -EINVAL; - } - - sx = s_frame->width; - sy = s_frame->height; - if (sx <= 0 || sy <= 0) { - err("invalid source size: %d x %d", sx, sy); - return -EINVAL; - } - - sc->real_width = sx; - sc->real_height = sy; - dbg("sx= %d, sy= %d, tx= %d, ty= %d", sx, sy, tx, ty); - - ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor); - if (ret) - return ret; - - ret = fimc_get_scaler_factor(sy, ty, &sc->pre_vratio, &sc->vfactor); - if (ret) - return ret; - - sc->pre_dst_width = sx / sc->pre_hratio; - sc->pre_dst_height = sy / sc->pre_vratio; - - if (variant->has_mainscaler_ext) { - sc->main_hratio = (sx << 14) / (tx << sc->hfactor); - sc->main_vratio = (sy << 14) / (ty << sc->vfactor); - } else { - sc->main_hratio = (sx << 8) / (tx << sc->hfactor); - sc->main_vratio = (sy << 8) / (ty << sc->vfactor); - - } - - sc->scaleup_h = (tx >= sx) ? 1 : 0; - sc->scaleup_v = (ty >= sy) ? 1 : 0; - - /* check to see if input and output size/format differ */ - if (s_frame->fmt->color == d_frame->fmt->color - && s_frame->width == d_frame->width - && s_frame->height == d_frame->height) - sc->copy_mode = 1; - else - sc->copy_mode = 0; - - return 0; -} - -static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) -{ - struct vb2_buffer *src_vb, *dst_vb; - struct fimc_dev *fimc = ctx->fimc_dev; - - if (!ctx || !ctx->m2m_ctx) - return; - - src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - - if (src_vb && dst_vb) { - v4l2_m2m_buf_done(src_vb, vb_state); - v4l2_m2m_buf_done(dst_vb, vb_state); - v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); - } -} - -/* Complete the transaction which has been scheduled for execution. */ -static void fimc_m2m_shutdown(struct fimc_ctx *ctx) -{ - struct fimc_dev *fimc = ctx->fimc_dev; - int ret; - - if (!fimc_m2m_pending(fimc)) - return; - - fimc_ctx_state_lock_set(FIMC_CTX_SHUT, ctx); - - ret = wait_event_timeout(fimc->irq_queue, - !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), - FIMC_SHUTDOWN_TIMEOUT); - /* - * In case of a timeout the buffers are not released in the interrupt - * handler so return them here with the error flag set, if there are - * any on the queue. - */ - if (ret == 0) - fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); -} - -static int stop_streaming(struct vb2_queue *q) -{ - struct fimc_ctx *ctx = q->drv_priv; - - fimc_m2m_shutdown(ctx); - - return 0; -} - -static void fimc_capture_irq_handler(struct fimc_dev *fimc) -{ - struct fimc_vid_cap *cap = &fimc->vid_cap; - struct fimc_vid_buffer *v_buf; - - if (!list_empty(&cap->active_buf_q) && - test_bit(ST_CAPT_RUN, &fimc->state)) { - v_buf = active_queue_pop(cap); - vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); - } - - if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { - wake_up(&fimc->irq_queue); - return; - } - - if (!list_empty(&cap->pending_buf_q)) { - - v_buf = pending_queue_pop(cap); - fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); - v_buf->index = cap->buf_index; - - /* Move the buffer to the capture active queue */ - active_queue_add(cap, v_buf); - - dbg("next frame: %d, done frame: %d", - fimc_hw_get_frame_index(fimc), v_buf->index); - - if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) - cap->buf_index = 0; - } - - if (cap->active_buf_cnt == 0) { - clear_bit(ST_CAPT_RUN, &fimc->state); - - if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) - cap->buf_index = 0; - } else { - set_bit(ST_CAPT_RUN, &fimc->state); - } - - dbg("frame: %d, active_buf_cnt: %d", - fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); -} - -static irqreturn_t fimc_isr(int irq, void *priv) -{ - struct fimc_dev *fimc = priv; - struct fimc_vid_cap *cap = &fimc->vid_cap; - struct fimc_ctx *ctx; - - fimc_hw_clear_irq(fimc); - - if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { - ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); - if (ctx != NULL) { - fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE); - - spin_lock(&ctx->slock); - if (ctx->state & FIMC_CTX_SHUT) { - ctx->state &= ~FIMC_CTX_SHUT; - wake_up(&fimc->irq_queue); - } - spin_unlock(&ctx->slock); - } - - return IRQ_HANDLED; - } - - spin_lock(&fimc->slock); - - if (test_bit(ST_CAPT_PEND, &fimc->state)) { - fimc_capture_irq_handler(fimc); - - if (cap->active_buf_cnt == 1) { - fimc_deactivate_capture(fimc); - clear_bit(ST_CAPT_STREAM, &fimc->state); - } - } - - spin_unlock(&fimc->slock); - return IRQ_HANDLED; -} - -/* The color format (colplanes, memplanes) must be already configured. */ -int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, - struct fimc_frame *frame, struct fimc_addr *paddr) -{ - int ret = 0; - u32 pix_size; - - if (vb == NULL || frame == NULL) - return -EINVAL; - - pix_size = frame->width * frame->height; - - dbg("memplanes= %d, colplanes= %d, pix_size= %d", - frame->fmt->memplanes, frame->fmt->colplanes, pix_size); - - paddr->y = vb2_dma_contig_plane_paddr(vb, 0); - - if (frame->fmt->memplanes == 1) { - switch (frame->fmt->colplanes) { - case 1: - paddr->cb = 0; - paddr->cr = 0; - break; - case 2: - /* decompose Y into Y/Cb */ - paddr->cb = (u32)(paddr->y + pix_size); - paddr->cr = 0; - break; - case 3: - paddr->cb = (u32)(paddr->y + pix_size); - /* decompose Y into Y/Cb/Cr */ - if (S5P_FIMC_YCBCR420 == frame->fmt->color) - paddr->cr = (u32)(paddr->cb - + (pix_size >> 2)); - else /* 422 */ - paddr->cr = (u32)(paddr->cb - + (pix_size >> 1)); - break; - default: - return -EINVAL; - } - } else { - if (frame->fmt->memplanes >= 2) - paddr->cb = vb2_dma_contig_plane_paddr(vb, 1); - - if (frame->fmt->memplanes == 3) - paddr->cr = vb2_dma_contig_plane_paddr(vb, 2); - } - - dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", - paddr->y, paddr->cb, paddr->cr, ret); - - return ret; -} - -/* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */ -static void fimc_set_yuv_order(struct fimc_ctx *ctx) -{ - /* The one only mode supported in SoC. */ - ctx->in_order_2p = S5P_FIMC_LSB_CRCB; - ctx->out_order_2p = S5P_FIMC_LSB_CRCB; - - /* Set order for 1 plane input formats. */ - switch (ctx->s_frame.fmt->color) { - case S5P_FIMC_YCRYCB422: - ctx->in_order_1p = S5P_MSCTRL_ORDER422_CBYCRY; - break; - case S5P_FIMC_CBYCRY422: - ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCRYCB; - break; - case S5P_FIMC_CRYCBY422: - ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCBYCR; - break; - case S5P_FIMC_YCBYCR422: - default: - ctx->in_order_1p = S5P_MSCTRL_ORDER422_CRYCBY; - break; - } - dbg("ctx->in_order_1p= %d", ctx->in_order_1p); - - switch (ctx->d_frame.fmt->color) { - case S5P_FIMC_YCRYCB422: - ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CBYCRY; - break; - case S5P_FIMC_CBYCRY422: - ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCRYCB; - break; - case S5P_FIMC_CRYCBY422: - ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCBYCR; - break; - case S5P_FIMC_YCBYCR422: - default: - ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CRYCBY; - break; - } - dbg("ctx->out_order_1p= %d", ctx->out_order_1p); -} - -static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) -{ - struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; - u32 i, depth = 0; - - for (i = 0; i < f->fmt->colplanes; i++) - depth += f->fmt->depth[i]; - - f->dma_offset.y_h = f->offs_h; - if (!variant->pix_hoff) - f->dma_offset.y_h *= (depth >> 3); - - f->dma_offset.y_v = f->offs_v; - - f->dma_offset.cb_h = f->offs_h; - f->dma_offset.cb_v = f->offs_v; - - f->dma_offset.cr_h = f->offs_h; - f->dma_offset.cr_v = f->offs_v; - - if (!variant->pix_hoff) { - if (f->fmt->colplanes == 3) { - f->dma_offset.cb_h >>= 1; - f->dma_offset.cr_h >>= 1; - } - if (f->fmt->color == S5P_FIMC_YCBCR420) { - f->dma_offset.cb_v >>= 1; - f->dma_offset.cr_v >>= 1; - } - } - - dbg("in_offset: color= %d, y_h= %d, y_v= %d", - f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v); -} - -/** - * fimc_prepare_config - check dimensions, operation and color mode - * and pre-calculate offset and the scaling coefficients. - * - * @ctx: hardware context information - * @flags: flags indicating which parameters to check/update - * - * Return: 0 if dimensions are valid or non zero otherwise. - */ -int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) -{ - struct fimc_frame *s_frame, *d_frame; - struct vb2_buffer *vb = NULL; - int ret = 0; - - s_frame = &ctx->s_frame; - d_frame = &ctx->d_frame; - - if (flags & FIMC_PARAMS) { - /* Prepare the DMA offset ratios for scaler. */ - fimc_prepare_dma_offset(ctx, &ctx->s_frame); - fimc_prepare_dma_offset(ctx, &ctx->d_frame); - - if (s_frame->height > (SCALER_MAX_VRATIO * d_frame->height) || - s_frame->width > (SCALER_MAX_HRATIO * d_frame->width)) { - err("out of scaler range"); - return -EINVAL; - } - fimc_set_yuv_order(ctx); - } - - /* Input DMA mode is not allowed when the scaler is disabled. */ - ctx->scaler.enabled = 1; - - if (flags & FIMC_SRC_ADDR) { - vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - ret = fimc_prepare_addr(ctx, vb, s_frame, &s_frame->paddr); - if (ret) - return ret; - } - - if (flags & FIMC_DST_ADDR) { - vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - ret = fimc_prepare_addr(ctx, vb, d_frame, &d_frame->paddr); - } - - return ret; -} - -static void fimc_dma_run(void *priv) -{ - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc; - unsigned long flags; - u32 ret; - - if (WARN(!ctx, "null hardware context\n")) - return; - - fimc = ctx->fimc_dev; - - spin_lock_irqsave(&ctx->slock, flags); - set_bit(ST_M2M_PEND, &fimc->state); - - ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR); - ret = fimc_prepare_config(ctx, ctx->state); - if (ret) - goto dma_unlock; - - /* Reconfigure hardware if the context has changed. */ - if (fimc->m2m.ctx != ctx) { - ctx->state |= FIMC_PARAMS; - fimc->m2m.ctx = ctx; - } - - spin_lock(&fimc->slock); - fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr); - - if (ctx->state & FIMC_PARAMS) { - fimc_hw_set_input_path(ctx); - fimc_hw_set_in_dma(ctx); - ret = fimc_set_scaler_info(ctx); - if (ret) { - spin_unlock(&fimc->slock); - goto dma_unlock; - } - fimc_hw_set_prescaler(ctx); - fimc_hw_set_mainscaler(ctx); - fimc_hw_set_target_format(ctx); - fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); - } - - fimc_hw_set_output_path(ctx); - if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS)) - fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1); - - if (ctx->state & FIMC_PARAMS) - fimc_hw_set_out_dma(ctx); - - fimc_activate_capture(ctx); - - ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP | - FIMC_SRC_FMT | FIMC_DST_FMT); - fimc_hw_activate_input_dma(fimc, true); - spin_unlock(&fimc->slock); - -dma_unlock: - spin_unlock_irqrestore(&ctx->slock, flags); -} - -static void fimc_job_abort(void *priv) -{ - fimc_m2m_shutdown(priv); -} - -static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned long sizes[], - void *allocators[]) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - struct fimc_frame *f; - int i; - - f = ctx_get_frame(ctx, vq->type); - if (IS_ERR(f)) - return PTR_ERR(f); - - /* - * Return number of non-contigous planes (plane buffers) - * depending on the configured color format. - */ - if (f->fmt) - *num_planes = f->fmt->memplanes; - - for (i = 0; i < f->fmt->memplanes; i++) { - sizes[i] = (f->width * f->height * f->fmt->depth[i]) >> 3; - allocators[i] = ctx->fimc_dev->alloc_ctx; - } - - if (*num_buffers == 0) - *num_buffers = 1; - - return 0; -} - -static int fimc_buf_prepare(struct vb2_buffer *vb) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct fimc_frame *frame; - int i; - - frame = ctx_get_frame(ctx, vb->vb2_queue->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); - - for (i = 0; i < frame->fmt->memplanes; i++) - vb2_set_plane_payload(vb, i, frame->payload[i]); - - return 0; -} - -static void fimc_buf_queue(struct vb2_buffer *vb) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state); - - if (ctx->m2m_ctx) - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); -} - -static void fimc_lock(struct vb2_queue *vq) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_lock(&ctx->fimc_dev->lock); -} - -static void fimc_unlock(struct vb2_queue *vq) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_unlock(&ctx->fimc_dev->lock); -} - -struct vb2_ops fimc_qops = { - .queue_setup = fimc_queue_setup, - .buf_prepare = fimc_buf_prepare, - .buf_queue = fimc_buf_queue, - .wait_prepare = fimc_unlock, - .wait_finish = fimc_lock, - .stop_streaming = stop_streaming, -}; - -static int fimc_m2m_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; - - strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); - strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); - cap->bus_info[0] = 0; - cap->version = KERNEL_VERSION(1, 0, 0); - cap->capabilities = V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; - - return 0; -} - -int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct fimc_fmt *fmt; - - if (f->index >= ARRAY_SIZE(fimc_formats)) - return -EINVAL; - - fmt = &fimc_formats[f->index]; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); - f->pixelformat = fmt->fourcc; - - return 0; -} - -int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct fimc_ctx *ctx = priv; - struct fimc_frame *frame; - struct v4l2_pix_format_mplane *pixm; - int i; - - frame = ctx_get_frame(ctx, f->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); - - pixm = &f->fmt.pix_mp; - - pixm->width = frame->width; - pixm->height = frame->height; - pixm->field = V4L2_FIELD_NONE; - pixm->pixelformat = frame->fmt->fourcc; - pixm->colorspace = V4L2_COLORSPACE_JPEG; - pixm->num_planes = frame->fmt->memplanes; - - for (i = 0; i < pixm->num_planes; ++i) { - int bpl = frame->o_width; - - if (frame->fmt->colplanes == 1) /* packed formats */ - bpl = (bpl * frame->fmt->depth[0]) / 8; - - pixm->plane_fmt[i].bytesperline = bpl; - - pixm->plane_fmt[i].sizeimage = (frame->o_width * - frame->o_height * frame->fmt->depth[i]) / 8; - } - - return 0; -} - -struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask) -{ - struct fimc_fmt *fmt; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { - fmt = &fimc_formats[i]; - if (fmt->fourcc == f->fmt.pix.pixelformat && - (fmt->flags & mask)) - break; - } - - return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt; -} - -struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, - unsigned int mask) -{ - struct fimc_fmt *fmt; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { - fmt = &fimc_formats[i]; - if (fmt->mbus_code == f->code && (fmt->flags & mask)) - break; - } - - return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt; -} - - -int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct samsung_fimc_variant *variant = fimc->variant; - struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct fimc_fmt *fmt; - u32 max_width, mod_x, mod_y, mask; - int i, is_output = 0; - - - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) - return -EINVAL; - is_output = 1; - } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - return -EINVAL; - } - - dbg("w: %d, h: %d", pix->width, pix->height); - - mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM; - fmt = find_format(f, mask); - if (!fmt) { - v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n", - pix->pixelformat); - return -EINVAL; - } - - if (pix->field == V4L2_FIELD_ANY) - pix->field = V4L2_FIELD_NONE; - else if (V4L2_FIELD_NONE != pix->field) - return -EINVAL; - - if (is_output) { - max_width = variant->pix_limit->scaler_dis_w; - mod_x = ffs(variant->min_inp_pixsize) - 1; - } else { - max_width = variant->pix_limit->out_rot_dis_w; - mod_x = ffs(variant->min_out_pixsize) - 1; - } - - if (tiled_fmt(fmt)) { - mod_x = 6; /* 64 x 32 pixels tile */ - mod_y = 5; - } else { - if (fimc->id == 1 && variant->pix_hoff) - mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; - else - mod_y = mod_x; - } - - dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_width); - - v4l_bound_align_image(&pix->width, 16, max_width, mod_x, - &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); - - pix->num_planes = fmt->memplanes; - pix->colorspace = V4L2_COLORSPACE_JPEG; - - for (i = 0; i < pix->num_planes; ++i) { - int bpl = pix->plane_fmt[i].bytesperline; - - dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d", - i, bpl, fmt->depth[i], pix->width, pix->height); - - if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width) - bpl = (pix->width * fmt->depth[0]) >> 3; - - if (!pix->plane_fmt[i].sizeimage) - pix->plane_fmt[i].sizeimage = pix->height * bpl; - - pix->plane_fmt[i].bytesperline = bpl; - - dbg("[%d]: bpl: %d, sizeimage: %d", - i, pix->plane_fmt[i].bytesperline, - pix->plane_fmt[i].sizeimage); - } - - return 0; -} - -static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct vb2_queue *vq; - struct fimc_frame *frame; - struct v4l2_pix_format_mplane *pix; - int i, ret = 0; - - ret = fimc_vidioc_try_fmt_mplane(file, priv, f); - if (ret) - return ret; - - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - - if (vb2_is_streaming(vq)) { - v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type); - return -EBUSY; - } - - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - frame = &ctx->s_frame; - } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - frame = &ctx->d_frame; - } else { - v4l2_err(&fimc->m2m.v4l2_dev, - "Wrong buffer/video queue type (%d)\n", f->type); - return -EINVAL; - } - - pix = &f->fmt.pix_mp; - frame->fmt = find_format(f, FMT_FLAGS_M2M); - if (!frame->fmt) - return -EINVAL; - - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; - - frame->f_width = pix->plane_fmt[0].bytesperline * 8 / - frame->fmt->depth[0]; - frame->f_height = pix->height; - frame->width = pix->width; - frame->height = pix->height; - frame->o_width = pix->width; - frame->o_height = pix->height; - frame->offs_h = 0; - frame->offs_v = 0; - - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx); - else - fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx); - - dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height); - - return 0; -} - -static int fimc_m2m_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct fimc_ctx *ctx = priv; - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); -} - -static int fimc_m2m_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_ctx *ctx = priv; - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); -} - -static int fimc_m2m_qbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_ctx *ctx = priv; - - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); -} - -static int fimc_m2m_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_ctx *ctx = priv; - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); -} - -static int fimc_m2m_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_ctx *ctx = priv; - - /* The source and target color format need to be set */ - if (V4L2_TYPE_IS_OUTPUT(type)) { - if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx)) - return -EINVAL; - } else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) { - return -EINVAL; - } - - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); -} - -static int fimc_m2m_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_ctx *ctx = priv; - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); -} - -int fimc_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct fimc_ctx *ctx = priv; - struct v4l2_queryctrl *c; - int ret = -EINVAL; - - c = get_ctrl(qc->id); - if (c) { - *qc = *c; - return 0; - } - - if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) { - return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, - core, queryctrl, qc); - } - return ret; -} - -int fimc_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - ctrl->value = (FLIP_X_AXIS & ctx->flip) ? 1 : 0; - break; - case V4L2_CID_VFLIP: - ctrl->value = (FLIP_Y_AXIS & ctx->flip) ? 1 : 0; - break; - case V4L2_CID_ROTATE: - ctrl->value = ctx->rotation; - break; - default: - if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) { - return v4l2_subdev_call(fimc->vid_cap.sd, core, - g_ctrl, ctrl); - } else { - v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); - return -EINVAL; - } - } - dbg("ctrl->value= %d", ctrl->value); - - return 0; -} - -int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl) -{ - struct v4l2_queryctrl *c; - c = get_ctrl(ctrl->id); - if (!c) - return -EINVAL; - - if (ctrl->value < c->minimum || ctrl->value > c->maximum - || (c->step != 0 && ctrl->value % c->step != 0)) { - v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, - "Invalid control value\n"); - return -ERANGE; - } - - return 0; -} - -int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) -{ - struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; - struct fimc_dev *fimc = ctx->fimc_dev; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - if (ctrl->value) - ctx->flip |= FLIP_X_AXIS; - else - ctx->flip &= ~FLIP_X_AXIS; - break; - - case V4L2_CID_VFLIP: - if (ctrl->value) - ctx->flip |= FLIP_Y_AXIS; - else - ctx->flip &= ~FLIP_Y_AXIS; - break; - - case V4L2_CID_ROTATE: - if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { - ret = fimc_check_scaler_ratio(ctx->s_frame.width, - ctx->s_frame.height, ctx->d_frame.width, - ctx->d_frame.height, ctrl->value); - } - - if (ret) { - v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n"); - return -EINVAL; - } - - /* Check for the output rotator availability */ - if ((ctrl->value == 90 || ctrl->value == 270) && - (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) - return -EINVAL; - ctx->rotation = ctrl->value; - break; - - default: - v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); - return -EINVAL; - } - - fimc_ctx_state_lock_set(FIMC_PARAMS, ctx); - - return 0; -} - -static int fimc_m2m_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fimc_ctx *ctx = priv; - int ret = 0; - - ret = check_ctrl_val(ctx, ctrl); - if (ret) - return ret; - - ret = fimc_s_ctrl(ctx, ctrl); - return 0; -} - -static int fimc_m2m_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cr) -{ - struct fimc_frame *frame; - struct fimc_ctx *ctx = fh; - - frame = ctx_get_frame(ctx, cr->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); - - cr->bounds.left = 0; - cr->bounds.top = 0; - cr->bounds.width = frame->f_width; - cr->bounds.height = frame->f_height; - cr->defrect = cr->bounds; - - return 0; -} - -static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) -{ - struct fimc_frame *frame; - struct fimc_ctx *ctx = file->private_data; - - frame = ctx_get_frame(ctx, cr->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); - - cr->c.left = frame->offs_h; - cr->c.top = frame->offs_v; - cr->c.width = frame->width; - cr->c.height = frame->height; - - return 0; -} - -int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) -{ - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_frame *f; - u32 min_size, halign, depth = 0; - bool is_capture_ctx; - int i; - - if (cr->c.top < 0 || cr->c.left < 0) { - v4l2_err(&fimc->m2m.v4l2_dev, - "doesn't support negative values for top & left\n"); - return -EINVAL; - } - - is_capture_ctx = fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx); - - if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - f = is_capture_ctx ? &ctx->s_frame : &ctx->d_frame; - else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - !is_capture_ctx) - f = &ctx->s_frame; - else - return -EINVAL; - - min_size = (f == &ctx->s_frame) ? - fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; - - /* Get pixel alignment constraints. */ - if (is_capture_ctx) { - min_size = 16; - halign = 4; - } else { - if (fimc->id == 1 && fimc->variant->pix_hoff) - halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; - else - halign = ffs(min_size) - 1; - } - - for (i = 0; i < f->fmt->colplanes; i++) - depth += f->fmt->depth[i]; - - v4l_bound_align_image(&cr->c.width, min_size, f->o_width, - ffs(min_size) - 1, - &cr->c.height, min_size, f->o_height, - halign, 64/(ALIGN(depth, 8))); - - /* adjust left/top if cropping rectangle is out of bounds */ - if (cr->c.left + cr->c.width > f->o_width) - cr->c.left = f->o_width - cr->c.width; - if (cr->c.top + cr->c.height > f->o_height) - cr->c.top = f->o_height - cr->c.height; - - cr->c.left = round_down(cr->c.left, min_size); - cr->c.top = round_down(cr->c.top, is_capture_ctx ? 16 : 8); - - dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", - cr->c.left, cr->c.top, cr->c.width, cr->c.height, - f->f_width, f->f_height); - - return 0; -} - -static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) -{ - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_frame *f; - int ret; - - ret = fimc_try_crop(ctx, cr); - if (ret) - return ret; - - f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? - &ctx->s_frame : &ctx->d_frame; - - /* Check to see if scaling ratio is within supported range */ - if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { - if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, - ctx->d_frame.width, - ctx->d_frame.height, - ctx->rotation); - } else { - ret = fimc_check_scaler_ratio(ctx->s_frame.width, - ctx->s_frame.height, - cr->c.width, cr->c.height, - ctx->rotation); - } - if (ret) { - v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n"); - return -EINVAL; - } - } - - f->offs_h = cr->c.left; - f->offs_v = cr->c.top; - f->width = cr->c.width; - f->height = cr->c.height; - - fimc_ctx_state_lock_set(FIMC_PARAMS, ctx); - - return 0; -} - -static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { - .vidioc_querycap = fimc_m2m_querycap, - - .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane, - .vidioc_enum_fmt_vid_out_mplane = fimc_vidioc_enum_fmt_mplane, - - .vidioc_g_fmt_vid_cap_mplane = fimc_vidioc_g_fmt_mplane, - .vidioc_g_fmt_vid_out_mplane = fimc_vidioc_g_fmt_mplane, - - .vidioc_try_fmt_vid_cap_mplane = fimc_vidioc_try_fmt_mplane, - .vidioc_try_fmt_vid_out_mplane = fimc_vidioc_try_fmt_mplane, - - .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane, - .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane, - - .vidioc_reqbufs = fimc_m2m_reqbufs, - .vidioc_querybuf = fimc_m2m_querybuf, - - .vidioc_qbuf = fimc_m2m_qbuf, - .vidioc_dqbuf = fimc_m2m_dqbuf, - - .vidioc_streamon = fimc_m2m_streamon, - .vidioc_streamoff = fimc_m2m_streamoff, - - .vidioc_queryctrl = fimc_vidioc_queryctrl, - .vidioc_g_ctrl = fimc_vidioc_g_ctrl, - .vidioc_s_ctrl = fimc_m2m_s_ctrl, - - .vidioc_g_crop = fimc_m2m_g_crop, - .vidioc_s_crop = fimc_m2m_s_crop, - .vidioc_cropcap = fimc_m2m_cropcap - -}; - -static int queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - struct fimc_ctx *ctx = priv; - int ret; - - memset(src_vq, 0, sizeof(*src_vq)); - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_USERPTR; - src_vq->drv_priv = ctx; - src_vq->ops = &fimc_qops; - src_vq->mem_ops = &vb2_dma_contig_memops; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - memset(dst_vq, 0, sizeof(*dst_vq)); - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; - dst_vq->drv_priv = ctx; - dst_vq->ops = &fimc_qops; - dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - - return vb2_queue_init(dst_vq); -} - -static int fimc_m2m_open(struct file *file) -{ - struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx = NULL; - - dbg("pid: %d, state: 0x%lx, refcnt: %d", - task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt); - - /* - * Return if the corresponding video capture node - * is already opened. - */ - if (fimc->vid_cap.refcnt > 0) - return -EBUSY; - - fimc->m2m.refcnt++; - set_bit(ST_OUTDMA_RUN, &fimc->state); - - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - file->private_data = ctx; - ctx->fimc_dev = fimc; - /* Default color format */ - ctx->s_frame.fmt = &fimc_formats[0]; - ctx->d_frame.fmt = &fimc_formats[0]; - /* Setup the device context for mem2mem mode. */ - ctx->state = FIMC_CTX_M2M; - ctx->flags = 0; - ctx->in_path = FIMC_DMA; - ctx->out_path = FIMC_DMA; - spin_lock_init(&ctx->slock); - - ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); - if (IS_ERR(ctx->m2m_ctx)) { - int err = PTR_ERR(ctx->m2m_ctx); - kfree(ctx); - return err; - } - - return 0; -} - -static int fimc_m2m_release(struct file *file) -{ - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; - - dbg("pid: %d, state: 0x%lx, refcnt= %d", - task_pid_nr(current), fimc->state, fimc->m2m.refcnt); - - v4l2_m2m_ctx_release(ctx->m2m_ctx); - kfree(ctx); - if (--fimc->m2m.refcnt <= 0) - clear_bit(ST_OUTDMA_RUN, &fimc->state); - - return 0; -} - -static unsigned int fimc_m2m_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct fimc_ctx *ctx = file->private_data; - - return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); -} - - -static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct fimc_ctx *ctx = file->private_data; - - return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); -} - -static const struct v4l2_file_operations fimc_m2m_fops = { - .owner = THIS_MODULE, - .open = fimc_m2m_open, - .release = fimc_m2m_release, - .poll = fimc_m2m_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = fimc_m2m_mmap, -}; - -static struct v4l2_m2m_ops m2m_ops = { - .device_run = fimc_dma_run, - .job_abort = fimc_job_abort, -}; - -static int fimc_register_m2m_device(struct fimc_dev *fimc) -{ - struct video_device *vfd; - struct platform_device *pdev; - struct v4l2_device *v4l2_dev; - int ret = 0; - - if (!fimc) - return -ENODEV; - - pdev = fimc->pdev; - v4l2_dev = &fimc->m2m.v4l2_dev; - - /* set name if it is empty */ - if (!v4l2_dev->name[0]) - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), - "%s.m2m", dev_name(&pdev->dev)); - - ret = v4l2_device_register(&pdev->dev, v4l2_dev); - if (ret) - goto err_m2m_r1; - - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(v4l2_dev, "Failed to allocate video device\n"); - goto err_m2m_r1; - } - - vfd->fops = &fimc_m2m_fops; - vfd->ioctl_ops = &fimc_m2m_ioctl_ops; - vfd->minor = -1; - vfd->release = video_device_release; - vfd->lock = &fimc->lock; - - snprintf(vfd->name, sizeof(vfd->name), "%s:m2m", dev_name(&pdev->dev)); - - video_set_drvdata(vfd, fimc); - platform_set_drvdata(pdev, fimc); - - fimc->m2m.vfd = vfd; - fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(fimc->m2m.m2m_dev)) { - v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n"); - ret = PTR_ERR(fimc->m2m.m2m_dev); - goto err_m2m_r2; - } - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); - if (ret) { - v4l2_err(v4l2_dev, - "%s(): failed to register video device\n", __func__); - goto err_m2m_r3; - } - v4l2_info(v4l2_dev, - "FIMC m2m driver registered as /dev/video%d\n", vfd->num); - - return 0; - -err_m2m_r3: - v4l2_m2m_release(fimc->m2m.m2m_dev); -err_m2m_r2: - video_device_release(fimc->m2m.vfd); -err_m2m_r1: - v4l2_device_unregister(v4l2_dev); - - return ret; -} - -static void fimc_unregister_m2m_device(struct fimc_dev *fimc) -{ - if (fimc) { - v4l2_m2m_release(fimc->m2m.m2m_dev); - video_unregister_device(fimc->m2m.vfd); - - v4l2_device_unregister(&fimc->m2m.v4l2_dev); - } -} - -static void fimc_clk_release(struct fimc_dev *fimc) -{ - int i; - for (i = 0; i < fimc->num_clocks; i++) { - if (fimc->clock[i]) { - clk_disable(fimc->clock[i]); - clk_put(fimc->clock[i]); - } - } -} - -static int fimc_clk_get(struct fimc_dev *fimc) -{ - int i; - for (i = 0; i < fimc->num_clocks; i++) { - fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); - - if (!IS_ERR_OR_NULL(fimc->clock[i])) { - clk_enable(fimc->clock[i]); - continue; - } - dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n", - fimc_clocks[i]); - return -ENXIO; - } - return 0; -} - -static int fimc_probe(struct platform_device *pdev) -{ - struct fimc_dev *fimc; - struct resource *res; - struct samsung_fimc_driverdata *drv_data; - struct s5p_platform_fimc *pdata; - int ret = 0; - int cap_input_index = -1; - - dev_dbg(&pdev->dev, "%s():\n", __func__); - - drv_data = (struct samsung_fimc_driverdata *) - platform_get_device_id(pdev)->driver_data; - - if (pdev->id >= drv_data->num_entities) { - dev_err(&pdev->dev, "Invalid platform device id: %d\n", - pdev->id); - return -EINVAL; - } - - fimc = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL); - if (!fimc) - return -ENOMEM; - - fimc->id = pdev->id; - fimc->variant = drv_data->variant[fimc->id]; - fimc->pdev = pdev; - pdata = pdev->dev.platform_data; - fimc->pdata = pdata; - fimc->state = ST_IDLE; - - init_waitqueue_head(&fimc->irq_queue); - spin_lock_init(&fimc->slock); - - mutex_init(&fimc->lock); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to find the registers\n"); - ret = -ENOENT; - goto err_info; - } - - fimc->regs_res = request_mem_region(res->start, resource_size(res), - dev_name(&pdev->dev)); - if (!fimc->regs_res) { - dev_err(&pdev->dev, "failed to obtain register region\n"); - ret = -ENOENT; - goto err_info; - } - - fimc->regs = ioremap(res->start, resource_size(res)); - if (!fimc->regs) { - dev_err(&pdev->dev, "failed to map registers\n"); - ret = -ENXIO; - goto err_req_region; - } - - fimc->num_clocks = MAX_FIMC_CLOCKS - 1; - - /* Check if a video capture node needs to be registered. */ - if (pdata && pdata->num_clients > 0) { - cap_input_index = 0; - fimc->num_clocks++; - } - - ret = fimc_clk_get(fimc); - if (ret) - goto err_regs_unmap; - clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get IRQ resource\n"); - ret = -ENXIO; - goto err_clk; - } - fimc->irq = res->start; - - fimc_hw_reset(fimc); - - ret = request_irq(fimc->irq, fimc_isr, 0, pdev->name, fimc); - if (ret) { - dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); - goto err_clk; - } - - /* Initialize contiguous memory allocator */ - fimc->alloc_ctx = vb2_dma_contig_init_ctx(&fimc->pdev->dev); - if (IS_ERR(fimc->alloc_ctx)) { - ret = PTR_ERR(fimc->alloc_ctx); - goto err_irq; - } - - ret = fimc_register_m2m_device(fimc); - if (ret) - goto err_irq; - - /* At least one camera sensor is required to register capture node */ - if (cap_input_index >= 0) { - ret = fimc_register_capture_device(fimc); - if (ret) - goto err_m2m; - clk_disable(fimc->clock[CLK_CAM]); - } - /* - * Exclude the additional output DMA address registers by masking - * them out on HW revisions that provide extended capabilites. - */ - if (fimc->variant->out_buf_count > 4) - fimc_hw_set_dma_seq(fimc, 0xF); - - dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n", - __func__, fimc->id); - - return 0; - -err_m2m: - fimc_unregister_m2m_device(fimc); -err_irq: - free_irq(fimc->irq, fimc); -err_clk: - fimc_clk_release(fimc); -err_regs_unmap: - iounmap(fimc->regs); -err_req_region: - release_resource(fimc->regs_res); - kfree(fimc->regs_res); -err_info: - kfree(fimc); - - return ret; -} - -static int __devexit fimc_remove(struct platform_device *pdev) -{ - struct fimc_dev *fimc = - (struct fimc_dev *)platform_get_drvdata(pdev); - - free_irq(fimc->irq, fimc); - fimc_hw_reset(fimc); - - fimc_unregister_m2m_device(fimc); - fimc_unregister_capture_device(fimc); - - fimc_clk_release(fimc); - - vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); - - iounmap(fimc->regs); - release_resource(fimc->regs_res); - kfree(fimc->regs_res); - kfree(fimc); - - dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name); - return 0; -} - -/* Image pixel limits, similar across several FIMC HW revisions. */ -static struct fimc_pix_limit s5p_pix_limit[3] = { - [0] = { - .scaler_en_w = 3264, - .scaler_dis_w = 8192, - .in_rot_en_h = 1920, - .in_rot_dis_w = 8192, - .out_rot_en_w = 1920, - .out_rot_dis_w = 4224, - }, - [1] = { - .scaler_en_w = 4224, - .scaler_dis_w = 8192, - .in_rot_en_h = 1920, - .in_rot_dis_w = 8192, - .out_rot_en_w = 1920, - .out_rot_dis_w = 4224, - }, - [2] = { - .scaler_en_w = 1920, - .scaler_dis_w = 8192, - .in_rot_en_h = 1280, - .in_rot_dis_w = 8192, - .out_rot_en_w = 1280, - .out_rot_dis_w = 1920, - }, -}; - -static struct samsung_fimc_variant fimc0_variant_s5p = { - .has_inp_rot = 1, - .has_out_rot = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[0], -}; - -static struct samsung_fimc_variant fimc2_variant_s5p = { - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[1], -}; - -static struct samsung_fimc_variant fimc0_variant_s5pv210 = { - .pix_hoff = 1, - .has_inp_rot = 1, - .has_out_rot = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[1], -}; - -static struct samsung_fimc_variant fimc1_variant_s5pv210 = { - .pix_hoff = 1, - .has_inp_rot = 1, - .has_out_rot = 1, - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 1, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[2], -}; - -static struct samsung_fimc_variant fimc2_variant_s5pv210 = { - .pix_hoff = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .out_buf_count = 4, - .pix_limit = &s5p_pix_limit[2], -}; - -static struct samsung_fimc_variant fimc0_variant_s5pv310 = { - .pix_hoff = 1, - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cistatus2 = 1, - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 1, - .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[1], -}; - -static struct samsung_fimc_variant fimc2_variant_s5pv310 = { - .pix_hoff = 1, - .has_cistatus2 = 1, - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 1, - .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[2], -}; - -/* S5PC100 */ -static struct samsung_fimc_driverdata fimc_drvdata_s5p = { - .variant = { - [0] = &fimc0_variant_s5p, - [1] = &fimc0_variant_s5p, - [2] = &fimc2_variant_s5p, - }, - .num_entities = 3, - .lclk_frequency = 133000000UL, -}; - -/* S5PV210, S5PC110 */ -static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = { - .variant = { - [0] = &fimc0_variant_s5pv210, - [1] = &fimc1_variant_s5pv210, - [2] = &fimc2_variant_s5pv210, - }, - .num_entities = 3, - .lclk_frequency = 166000000UL, -}; - -/* S5PV310, S5PC210 */ -static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = { - .variant = { - [0] = &fimc0_variant_s5pv310, - [1] = &fimc0_variant_s5pv310, - [2] = &fimc0_variant_s5pv310, - [3] = &fimc2_variant_s5pv310, - }, - .num_entities = 4, - .lclk_frequency = 166000000UL, -}; - -static struct platform_device_id fimc_driver_ids[] = { - { - .name = "s5p-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5p, - }, { - .name = "s5pv210-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5pv210, - }, { - .name = "s5pv310-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5pv310, - }, - {}, -}; -MODULE_DEVICE_TABLE(platform, fimc_driver_ids); - -static struct platform_driver fimc_driver = { - .probe = fimc_probe, - .remove = __devexit_p(fimc_remove), - .id_table = fimc_driver_ids, - .driver = { - .name = MODULE_NAME, - .owner = THIS_MODULE, - } -}; - -static int __init fimc_init(void) -{ - int ret = platform_driver_register(&fimc_driver); - if (ret) - err("platform_driver_register failed: %d\n", ret); - return ret; -} - -static void __exit fimc_exit(void) -{ - platform_driver_unregister(&fimc_driver); -} - -module_init(fimc_init); -module_exit(fimc_exit); - -MODULE_AUTHOR("Sylwester Nawrocki "); -MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-core.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-core.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,710 +0,0 @@ -/* - * Copyright (c) 2010 Samsung Electronics - * - * Sylwester Nawrocki, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef FIMC_CORE_H_ -#define FIMC_CORE_H_ - -/*#define DEBUG*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "regs-fimc.h" - -#define err(fmt, args...) \ - printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args) - -#define dbg(fmt, args...) \ - pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args) - -/* Time to wait for next frame VSYNC interrupt while stopping operation. */ -#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) -#define MAX_FIMC_CLOCKS 3 -#define MODULE_NAME "s5p-fimc" -#define FIMC_MAX_DEVS 4 -#define FIMC_MAX_OUT_BUFS 4 -#define SCALER_MAX_HRATIO 64 -#define SCALER_MAX_VRATIO 64 -#define DMA_MIN_SIZE 8 - -/* indices to the clocks array */ -enum { - CLK_BUS, - CLK_GATE, - CLK_CAM, -}; - -enum fimc_dev_flags { - /* for m2m node */ - ST_IDLE, - ST_OUTDMA_RUN, - ST_M2M_PEND, - /* for capture node */ - ST_CAPT_PEND, - ST_CAPT_RUN, - ST_CAPT_STREAM, - ST_CAPT_SHUT, -}; - -#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state) -#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state) - -#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state) -#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state) - -enum fimc_datapath { - FIMC_CAMERA, - FIMC_DMA, - FIMC_LCDFIFO, - FIMC_WRITEBACK -}; - -enum fimc_color_fmt { - S5P_FIMC_RGB565 = 0x10, - S5P_FIMC_RGB666, - S5P_FIMC_RGB888, - S5P_FIMC_RGB30_LOCAL, - S5P_FIMC_YCBCR420 = 0x20, - S5P_FIMC_YCBYCR422, - S5P_FIMC_YCRYCB422, - S5P_FIMC_CBYCRY422, - S5P_FIMC_CRYCBY422, - S5P_FIMC_YCBCR444_LOCAL, -}; - -#define fimc_fmt_is_rgb(x) ((x) & 0x10) - -/* Cb/Cr chrominance components order for 2 plane Y/CbCr 4:2:2 formats. */ -#define S5P_FIMC_LSB_CRCB S5P_CIOCTRL_ORDER422_2P_LSB_CRCB - -/* The embedded image effect selection */ -#define S5P_FIMC_EFFECT_ORIGINAL S5P_CIIMGEFF_FIN_BYPASS -#define S5P_FIMC_EFFECT_ARBITRARY S5P_CIIMGEFF_FIN_ARBITRARY -#define S5P_FIMC_EFFECT_NEGATIVE S5P_CIIMGEFF_FIN_NEGATIVE -#define S5P_FIMC_EFFECT_ARTFREEZE S5P_CIIMGEFF_FIN_ARTFREEZE -#define S5P_FIMC_EFFECT_EMBOSSING S5P_CIIMGEFF_FIN_EMBOSSING -#define S5P_FIMC_EFFECT_SIKHOUETTE S5P_CIIMGEFF_FIN_SILHOUETTE - -/* The hardware context state. */ -#define FIMC_PARAMS (1 << 0) -#define FIMC_SRC_ADDR (1 << 1) -#define FIMC_DST_ADDR (1 << 2) -#define FIMC_SRC_FMT (1 << 3) -#define FIMC_DST_FMT (1 << 4) -#define FIMC_CTX_M2M (1 << 5) -#define FIMC_CTX_CAP (1 << 6) -#define FIMC_CTX_SHUT (1 << 7) - -/* Image conversion flags */ -#define FIMC_IN_DMA_ACCESS_TILED (1 << 0) -#define FIMC_IN_DMA_ACCESS_LINEAR (0 << 0) -#define FIMC_OUT_DMA_ACCESS_TILED (1 << 1) -#define FIMC_OUT_DMA_ACCESS_LINEAR (0 << 1) -#define FIMC_SCAN_MODE_PROGRESSIVE (0 << 2) -#define FIMC_SCAN_MODE_INTERLACED (1 << 2) -/* - * YCbCr data dynamic range for RGB-YUV color conversion. - * Y/Cb/Cr: (0 ~ 255) */ -#define FIMC_COLOR_RANGE_WIDE (0 << 3) -/* Y (16 ~ 235), Cb/Cr (16 ~ 240) */ -#define FIMC_COLOR_RANGE_NARROW (1 << 3) - -#define FLIP_NONE 0 -#define FLIP_X_AXIS 1 -#define FLIP_Y_AXIS 2 -#define FLIP_XY_AXIS (FLIP_X_AXIS | FLIP_Y_AXIS) - -/** - * struct fimc_fmt - the driver's internal color format data - * @mbus_code: Media Bus pixel code, -1 if not applicable - * @name: format description - * @fourcc: the fourcc code for this format, 0 if not applicable - * @color: the corresponding fimc_color_fmt - * @depth: per plane driver's private 'number of bits per pixel' - * @memplanes: number of physically non-contiguous data planes - * @colplanes: number of physically contiguous data planes - */ -struct fimc_fmt { - enum v4l2_mbus_pixelcode mbus_code; - char *name; - u32 fourcc; - u32 color; - u16 memplanes; - u16 colplanes; - u8 depth[VIDEO_MAX_PLANES]; - u16 flags; -#define FMT_FLAGS_CAM (1 << 0) -#define FMT_FLAGS_M2M (1 << 1) -}; - -/** - * struct fimc_dma_offset - pixel offset information for DMA - * @y_h: y value horizontal offset - * @y_v: y value vertical offset - * @cb_h: cb value horizontal offset - * @cb_v: cb value vertical offset - * @cr_h: cr value horizontal offset - * @cr_v: cr value vertical offset - */ -struct fimc_dma_offset { - int y_h; - int y_v; - int cb_h; - int cb_v; - int cr_h; - int cr_v; -}; - -/** - * struct fimc_effect - the configuration data for the "Arbitrary" image effect - * @type: effect type - * @pat_cb: cr value when type is "arbitrary" - * @pat_cr: cr value when type is "arbitrary" - */ -struct fimc_effect { - u32 type; - u8 pat_cb; - u8 pat_cr; -}; - -/** - * struct fimc_scaler - the configuration data for FIMC inetrnal scaler - * - * @scaleup_h: flag indicating scaling up horizontally - * @scaleup_v: flag indicating scaling up vertically - * @copy_mode: flag indicating transparent DMA transfer (no scaling - * and color format conversion) - * @enabled: flag indicating if the scaler is used - * @hfactor: horizontal shift factor - * @vfactor: vertical shift factor - * @pre_hratio: horizontal ratio of the prescaler - * @pre_vratio: vertical ratio of the prescaler - * @pre_dst_width: the prescaler's destination width - * @pre_dst_height: the prescaler's destination height - * @main_hratio: the main scaler's horizontal ratio - * @main_vratio: the main scaler's vertical ratio - * @real_width: source pixel (width - offset) - * @real_height: source pixel (height - offset) - */ -struct fimc_scaler { - unsigned int scaleup_h:1; - unsigned int scaleup_v:1; - unsigned int copy_mode:1; - unsigned int enabled:1; - u32 hfactor; - u32 vfactor; - u32 pre_hratio; - u32 pre_vratio; - u32 pre_dst_width; - u32 pre_dst_height; - u32 main_hratio; - u32 main_vratio; - u32 real_width; - u32 real_height; -}; - -/** - * struct fimc_addr - the FIMC physical address set for DMA - * - * @y: luminance plane physical address - * @cb: Cb plane physical address - * @cr: Cr plane physical address - */ -struct fimc_addr { - u32 y; - u32 cb; - u32 cr; -}; - -/** - * struct fimc_vid_buffer - the driver's video buffer - * @vb: v4l videobuf buffer - * @paddr: precalculated physical address set - * @index: buffer index for the output DMA engine - */ -struct fimc_vid_buffer { - struct vb2_buffer vb; - struct list_head list; - struct fimc_addr paddr; - int index; -}; - -/** - * struct fimc_frame - source/target frame properties - * @f_width: image full width (virtual screen size) - * @f_height: image full height (virtual screen size) - * @o_width: original image width as set by S_FMT - * @o_height: original image height as set by S_FMT - * @offs_h: image horizontal pixel offset - * @offs_v: image vertical pixel offset - * @width: image pixel width - * @height: image pixel weight - * @paddr: image frame buffer physical addresses - * @buf_cnt: number of buffers depending on a color format - * @payload: image size in bytes (w x h x bpp) - * @color: color format - * @dma_offset: DMA offset in bytes - */ -struct fimc_frame { - u32 f_width; - u32 f_height; - u32 o_width; - u32 o_height; - u32 offs_h; - u32 offs_v; - u32 width; - u32 height; - unsigned long payload[VIDEO_MAX_PLANES]; - struct fimc_addr paddr; - struct fimc_dma_offset dma_offset; - struct fimc_fmt *fmt; -}; - -/** - * struct fimc_m2m_device - v4l2 memory-to-memory device data - * @vfd: the video device node for v4l2 m2m mode - * @v4l2_dev: v4l2 device for m2m mode - * @m2m_dev: v4l2 memory-to-memory device data - * @ctx: hardware context data - * @refcnt: the reference counter - */ -struct fimc_m2m_device { - struct video_device *vfd; - struct v4l2_device v4l2_dev; - struct v4l2_m2m_dev *m2m_dev; - struct fimc_ctx *ctx; - int refcnt; -}; - -/** - * struct fimc_vid_cap - camera capture device information - * @ctx: hardware context data - * @vfd: video device node for camera capture mode - * @v4l2_dev: v4l2_device struct to manage subdevs - * @sd: pointer to camera sensor subdevice currently in use - * @fmt: Media Bus format configured at selected image sensor - * @pending_buf_q: the pending buffer queue head - * @active_buf_q: the queue head of buffers scheduled in hardware - * @vbq: the capture am video buffer queue - * @active_buf_cnt: number of video buffers scheduled in hardware - * @buf_index: index for managing the output DMA buffers - * @frame_count: the frame counter for statistics - * @reqbufs_count: the number of buffers requested in REQBUFS ioctl - * @input_index: input (camera sensor) index - * @refcnt: driver's private reference counter - */ -struct fimc_vid_cap { - struct fimc_ctx *ctx; - struct vb2_alloc_ctx *alloc_ctx; - struct video_device *vfd; - struct v4l2_device v4l2_dev; - struct v4l2_subdev *sd;; - struct v4l2_mbus_framefmt fmt; - struct list_head pending_buf_q; - struct list_head active_buf_q; - struct vb2_queue vbq; - int active_buf_cnt; - int buf_index; - unsigned int frame_count; - unsigned int reqbufs_count; - int input_index; - int refcnt; -}; - -/** - * struct fimc_pix_limit - image pixel size limits in various IP configurations - * - * @scaler_en_w: max input pixel width when the scaler is enabled - * @scaler_dis_w: max input pixel width when the scaler is disabled - * @in_rot_en_h: max input width with the input rotator is on - * @in_rot_dis_w: max input width with the input rotator is off - * @out_rot_en_w: max output width with the output rotator on - * @out_rot_dis_w: max output width with the output rotator off - */ -struct fimc_pix_limit { - u16 scaler_en_w; - u16 scaler_dis_w; - u16 in_rot_en_h; - u16 in_rot_dis_w; - u16 out_rot_en_w; - u16 out_rot_dis_w; -}; - -/** - * struct samsung_fimc_variant - camera interface variant information - * - * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes - * @has_inp_rot: set if has input rotator - * @has_out_rot: set if has output rotator - * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision - * @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register - * are present in this IP revision - * @pix_limit: pixel size constraints for the scaler - * @min_inp_pixsize: minimum input pixel size - * @min_out_pixsize: minimum output pixel size - * @hor_offs_align: horizontal pixel offset aligment - * @out_buf_count: the number of buffers in output DMA sequence - */ -struct samsung_fimc_variant { - unsigned int pix_hoff:1; - unsigned int has_inp_rot:1; - unsigned int has_out_rot:1; - unsigned int has_cistatus2:1; - unsigned int has_mainscaler_ext:1; - struct fimc_pix_limit *pix_limit; - u16 min_inp_pixsize; - u16 min_out_pixsize; - u16 hor_offs_align; - u16 out_buf_count; -}; - -/** - * struct samsung_fimc_driverdata - per device type driver data for init time. - * - * @variant: the variant information for this driver. - * @dev_cnt: number of fimc sub-devices available in SoC - * @lclk_frequency: fimc bus clock frequency - */ -struct samsung_fimc_driverdata { - struct samsung_fimc_variant *variant[FIMC_MAX_DEVS]; - unsigned long lclk_frequency; - int num_entities; -}; - -struct fimc_ctx; - -/** - * struct fimc_dev - abstraction for FIMC entity - * - * @slock: the spinlock protecting this data structure - * @lock: the mutex protecting this data structure - * @pdev: pointer to the FIMC platform device - * @pdata: pointer to the device platform data - * @id: FIMC device index (0..FIMC_MAX_DEVS) - * @num_clocks: the number of clocks managed by this device instance - * @clock[]: the clocks required for FIMC operation - * @regs: the mapped hardware registers - * @regs_res: the resource claimed for IO registers - * @irq: interrupt number of the FIMC subdevice - * @irq_queue: - * @m2m: memory-to-memory V4L2 device information - * @vid_cap: camera capture device information - * @state: flags used to synchronize m2m and capture mode operation - */ -struct fimc_dev { - spinlock_t slock; - struct mutex lock; - struct platform_device *pdev; - struct s5p_platform_fimc *pdata; - struct samsung_fimc_variant *variant; - u16 id; - u16 num_clocks; - struct clk *clock[MAX_FIMC_CLOCKS]; - void __iomem *regs; - struct resource *regs_res; - int irq; - wait_queue_head_t irq_queue; - struct fimc_m2m_device m2m; - struct fimc_vid_cap vid_cap; - unsigned long state; - struct vb2_alloc_ctx *alloc_ctx; -}; - -/** - * fimc_ctx - the device context data - * - * @lock: mutex protecting this data structure - * @s_frame: source frame properties - * @d_frame: destination frame properties - * @out_order_1p: output 1-plane YCBCR order - * @out_order_2p: output 2-plane YCBCR order - * @in_order_1p input 1-plane YCBCR order - * @in_order_2p: input 2-plane YCBCR order - * @in_path: input mode (DMA or camera) - * @out_path: output mode (DMA or FIFO) - * @scaler: image scaler properties - * @effect: image effect - * @rotation: image clockwise rotation in degrees - * @flip: image flip mode - * @flags: additional flags for image conversion - * @state: flags to keep track of user configuration - * @fimc_dev: the FIMC device this context applies to - * @m2m_ctx: memory-to-memory device context - */ -struct fimc_ctx { - spinlock_t slock; - struct fimc_frame s_frame; - struct fimc_frame d_frame; - u32 out_order_1p; - u32 out_order_2p; - u32 in_order_1p; - u32 in_order_2p; - enum fimc_datapath in_path; - enum fimc_datapath out_path; - struct fimc_scaler scaler; - struct fimc_effect effect; - int rotation; - u32 flip; - u32 flags; - u32 state; - struct fimc_dev *fimc_dev; - struct v4l2_m2m_ctx *m2m_ctx; -}; - -static inline bool fimc_capture_active(struct fimc_dev *fimc) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&fimc->slock, flags); - ret = !!(fimc->state & (1 << ST_CAPT_RUN) || - fimc->state & (1 << ST_CAPT_PEND)); - spin_unlock_irqrestore(&fimc->slock, flags); - return ret; -} - -static inline void fimc_ctx_state_lock_set(u32 state, struct fimc_ctx *ctx) -{ - unsigned long flags; - - spin_lock_irqsave(&ctx->slock, flags); - ctx->state |= state; - spin_unlock_irqrestore(&ctx->slock, flags); -} - -static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&ctx->slock, flags); - ret = (ctx->state & mask) == mask; - spin_unlock_irqrestore(&ctx->slock, flags); - return ret; -} - -static inline int tiled_fmt(struct fimc_fmt *fmt) -{ - return fmt->fourcc == V4L2_PIX_FMT_NV12MT; -} - -static inline void fimc_hw_clear_irq(struct fimc_dev *dev) -{ - u32 cfg = readl(dev->regs + S5P_CIGCTRL); - cfg |= S5P_CIGCTRL_IRQ_CLR; - writel(cfg, dev->regs + S5P_CIGCTRL); -} - -static inline void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on) -{ - u32 cfg = readl(dev->regs + S5P_CISCCTRL); - if (on) - cfg |= S5P_CISCCTRL_SCALERSTART; - else - cfg &= ~S5P_CISCCTRL_SCALERSTART; - writel(cfg, dev->regs + S5P_CISCCTRL); -} - -static inline void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on) -{ - u32 cfg = readl(dev->regs + S5P_MSCTRL); - if (on) - cfg |= S5P_MSCTRL_ENVID; - else - cfg &= ~S5P_MSCTRL_ENVID; - writel(cfg, dev->regs + S5P_MSCTRL); -} - -static inline void fimc_hw_dis_capture(struct fimc_dev *dev) -{ - u32 cfg = readl(dev->regs + S5P_CIIMGCPT); - cfg &= ~(S5P_CIIMGCPT_IMGCPTEN | S5P_CIIMGCPT_IMGCPTEN_SC); - writel(cfg, dev->regs + S5P_CIIMGCPT); -} - -/** - * fimc_hw_set_dma_seq - configure output DMA buffer sequence - * @mask: each bit corresponds to one of 32 output buffer registers set - * 1 to include buffer in the sequence, 0 to disable - * - * This function mask output DMA ring buffers, i.e. it allows to configure - * which of the output buffer address registers will be used by the DMA - * engine. - */ -static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask) -{ - writel(mask, dev->regs + S5P_CIFCNTSEQ); -} - -static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, - enum v4l2_buf_type type) -{ - struct fimc_frame *frame; - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) { - if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx)) - frame = &ctx->s_frame; - else - return ERR_PTR(-EINVAL); - } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) { - frame = &ctx->d_frame; - } else { - v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, - "Wrong buffer/video queue type (%d)\n", type); - return ERR_PTR(-EINVAL); - } - - return frame; -} - -/* Return an index to the buffer actually being written. */ -static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev) -{ - u32 reg; - - if (dev->variant->has_cistatus2) { - reg = readl(dev->regs + S5P_CISTATUS2) & 0x3F; - return reg > 0 ? --reg : reg; - } else { - reg = readl(dev->regs + S5P_CISTATUS); - return (reg & S5P_CISTATUS_FRAMECNT_MASK) >> - S5P_CISTATUS_FRAMECNT_SHIFT; - } -} - -/* -----------------------------------------------------*/ -/* fimc-reg.c */ -void fimc_hw_reset(struct fimc_dev *fimc); -void fimc_hw_set_rotation(struct fimc_ctx *ctx); -void fimc_hw_set_target_format(struct fimc_ctx *ctx); -void fimc_hw_set_out_dma(struct fimc_ctx *ctx); -void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable); -void fimc_hw_en_irq(struct fimc_dev *fimc, int enable); -void fimc_hw_set_prescaler(struct fimc_ctx *ctx); -void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); -void fimc_hw_en_capture(struct fimc_ctx *ctx); -void fimc_hw_set_effect(struct fimc_ctx *ctx); -void fimc_hw_set_in_dma(struct fimc_ctx *ctx); -void fimc_hw_set_input_path(struct fimc_ctx *ctx); -void fimc_hw_set_output_path(struct fimc_ctx *ctx); -void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr); -void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr, - int index); -int fimc_hw_set_camera_source(struct fimc_dev *fimc, - struct s5p_fimc_isp_info *cam); -int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f); -int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, - struct s5p_fimc_isp_info *cam); -int fimc_hw_set_camera_type(struct fimc_dev *fimc, - struct s5p_fimc_isp_info *cam); - -/* -----------------------------------------------------*/ -/* fimc-core.c */ -int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f); -int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f); -int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f); -int fimc_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc); -int fimc_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl); - -int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr); -int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl); -int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl); - -struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask); -struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, - unsigned int mask); - -int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot); -int fimc_set_scaler_info(struct fimc_ctx *ctx); -int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); -int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, - struct fimc_frame *frame, struct fimc_addr *paddr); - -/* -----------------------------------------------------*/ -/* fimc-capture.c */ -int fimc_register_capture_device(struct fimc_dev *fimc); -void fimc_unregister_capture_device(struct fimc_dev *fimc); -int fimc_sensor_sd_init(struct fimc_dev *fimc, int index); -int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, - struct fimc_vid_buffer *fimc_vb); - -/* Locking: the caller holds fimc->slock */ -static inline void fimc_activate_capture(struct fimc_ctx *ctx) -{ - fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled); - fimc_hw_en_capture(ctx); -} - -static inline void fimc_deactivate_capture(struct fimc_dev *fimc) -{ - fimc_hw_en_lastirq(fimc, true); - fimc_hw_dis_capture(fimc); - fimc_hw_enable_scaler(fimc, false); - fimc_hw_en_lastirq(fimc, false); -} - -/* - * Add buf to the capture active buffers queue. - * Locking: Need to be called with fimc_dev::slock held. - */ -static inline void active_queue_add(struct fimc_vid_cap *vid_cap, - struct fimc_vid_buffer *buf) -{ - list_add_tail(&buf->list, &vid_cap->active_buf_q); - vid_cap->active_buf_cnt++; -} - -/* - * Pop a video buffer from the capture active buffers queue - * Locking: Need to be called with fimc_dev::slock held. - */ -static inline struct fimc_vid_buffer * -active_queue_pop(struct fimc_vid_cap *vid_cap) -{ - struct fimc_vid_buffer *buf; - buf = list_entry(vid_cap->active_buf_q.next, - struct fimc_vid_buffer, list); - list_del(&buf->list); - vid_cap->active_buf_cnt--; - return buf; -} - -/* Add video buffer to the capture pending buffers queue */ -static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap, - struct fimc_vid_buffer *buf) -{ - list_add_tail(&buf->list, &vid_cap->pending_buf_q); -} - -/* Add video buffer to the capture pending buffers queue */ -static inline struct fimc_vid_buffer * -pending_queue_pop(struct fimc_vid_cap *vid_cap) -{ - struct fimc_vid_buffer *buf; - buf = list_entry(vid_cap->pending_buf_q.next, - struct fimc_vid_buffer, list); - list_del(&buf->list); - return buf; -} - -#endif /* FIMC_CORE_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-reg.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-reg.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-reg.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/fimc-reg.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,685 +0,0 @@ -/* - * Register interface file for Samsung Camera Interface (FIMC) driver - * - * Copyright (c) 2010 Samsung Electronics - * - * Sylwester Nawrocki, s.nawrocki@samsung.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include -#include -#include -#include - -#include "fimc-core.h" - - -void fimc_hw_reset(struct fimc_dev *dev) -{ - u32 cfg; - - cfg = readl(dev->regs + S5P_CISRCFMT); - cfg |= S5P_CISRCFMT_ITU601_8BIT; - writel(cfg, dev->regs + S5P_CISRCFMT); - - /* Software reset. */ - cfg = readl(dev->regs + S5P_CIGCTRL); - cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL); - writel(cfg, dev->regs + S5P_CIGCTRL); - udelay(1000); - - cfg = readl(dev->regs + S5P_CIGCTRL); - cfg &= ~S5P_CIGCTRL_SWRST; - writel(cfg, dev->regs + S5P_CIGCTRL); -} - -static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) -{ - u32 flip = S5P_MSCTRL_FLIP_NORMAL; - - switch (ctx->flip) { - case FLIP_X_AXIS: - flip = S5P_MSCTRL_FLIP_X_MIRROR; - break; - case FLIP_Y_AXIS: - flip = S5P_MSCTRL_FLIP_Y_MIRROR; - break; - case FLIP_XY_AXIS: - flip = S5P_MSCTRL_FLIP_180; - break; - default: - break; - } - if (ctx->rotation <= 90) - return flip; - - return (flip ^ S5P_MSCTRL_FLIP_180) & S5P_MSCTRL_FLIP_180; -} - -static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx) -{ - u32 flip = S5P_CITRGFMT_FLIP_NORMAL; - - switch (ctx->flip) { - case FLIP_X_AXIS: - flip = S5P_CITRGFMT_FLIP_X_MIRROR; - break; - case FLIP_Y_AXIS: - flip = S5P_CITRGFMT_FLIP_Y_MIRROR; - break; - case FLIP_XY_AXIS: - flip = S5P_CITRGFMT_FLIP_180; - break; - default: - break; - } - if (ctx->rotation <= 90) - return flip; - - return (flip ^ S5P_CITRGFMT_FLIP_180) & S5P_CITRGFMT_FLIP_180; -} - -void fimc_hw_set_rotation(struct fimc_ctx *ctx) -{ - u32 cfg, flip; - struct fimc_dev *dev = ctx->fimc_dev; - - cfg = readl(dev->regs + S5P_CITRGFMT); - cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 | - S5P_CITRGFMT_FLIP_180); - - /* - * The input and output rotator cannot work simultaneously. - * Use the output rotator in output DMA mode or the input rotator - * in direct fifo output mode. - */ - if (ctx->rotation == 90 || ctx->rotation == 270) { - if (ctx->out_path == FIMC_LCDFIFO) - cfg |= S5P_CITRGFMT_INROT90; - else - cfg |= S5P_CITRGFMT_OUTROT90; - } - - if (ctx->out_path == FIMC_DMA) { - cfg |= fimc_hw_get_target_flip(ctx); - writel(cfg, dev->regs + S5P_CITRGFMT); - } else { - /* LCD FIFO path */ - flip = readl(dev->regs + S5P_MSCTRL); - flip &= ~S5P_MSCTRL_FLIP_MASK; - flip |= fimc_hw_get_in_flip(ctx); - writel(flip, dev->regs + S5P_MSCTRL); - } -} - -void fimc_hw_set_target_format(struct fimc_ctx *ctx) -{ - u32 cfg; - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; - - dbg("w= %d, h= %d color: %d", frame->width, - frame->height, frame->fmt->color); - - cfg = readl(dev->regs + S5P_CITRGFMT); - cfg &= ~(S5P_CITRGFMT_FMT_MASK | S5P_CITRGFMT_HSIZE_MASK | - S5P_CITRGFMT_VSIZE_MASK); - - switch (frame->fmt->color) { - case S5P_FIMC_RGB565...S5P_FIMC_RGB888: - cfg |= S5P_CITRGFMT_RGB; - break; - case S5P_FIMC_YCBCR420: - cfg |= S5P_CITRGFMT_YCBCR420; - break; - case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422: - if (frame->fmt->colplanes == 1) - cfg |= S5P_CITRGFMT_YCBCR422_1P; - else - cfg |= S5P_CITRGFMT_YCBCR422; - break; - default: - break; - } - - if (ctx->rotation == 90 || ctx->rotation == 270) { - cfg |= S5P_CITRGFMT_HSIZE(frame->height); - cfg |= S5P_CITRGFMT_VSIZE(frame->width); - } else { - - cfg |= S5P_CITRGFMT_HSIZE(frame->width); - cfg |= S5P_CITRGFMT_VSIZE(frame->height); - } - - writel(cfg, dev->regs + S5P_CITRGFMT); - - cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK; - cfg |= (frame->width * frame->height); - writel(cfg, dev->regs + S5P_CITAREA); -} - -static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; - u32 cfg; - - cfg = S5P_ORIG_SIZE_HOR(frame->f_width); - cfg |= S5P_ORIG_SIZE_VER(frame->f_height); - writel(cfg, dev->regs + S5P_ORGOSIZE); - - /* Select color space conversion equation (HD/SD size).*/ - cfg = readl(dev->regs + S5P_CIGCTRL); - if (frame->f_width >= 1280) /* HD */ - cfg |= S5P_CIGCTRL_CSC_ITU601_709; - else /* SD */ - cfg &= ~S5P_CIGCTRL_CSC_ITU601_709; - writel(cfg, dev->regs + S5P_CIGCTRL); - -} - -void fimc_hw_set_out_dma(struct fimc_ctx *ctx) -{ - u32 cfg; - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; - struct fimc_dma_offset *offset = &frame->dma_offset; - - /* Set the input dma offsets. */ - cfg = 0; - cfg |= S5P_CIO_OFFS_HOR(offset->y_h); - cfg |= S5P_CIO_OFFS_VER(offset->y_v); - writel(cfg, dev->regs + S5P_CIOYOFF); - - cfg = 0; - cfg |= S5P_CIO_OFFS_HOR(offset->cb_h); - cfg |= S5P_CIO_OFFS_VER(offset->cb_v); - writel(cfg, dev->regs + S5P_CIOCBOFF); - - cfg = 0; - cfg |= S5P_CIO_OFFS_HOR(offset->cr_h); - cfg |= S5P_CIO_OFFS_VER(offset->cr_v); - writel(cfg, dev->regs + S5P_CIOCROFF); - - fimc_hw_set_out_dma_size(ctx); - - /* Configure chroma components order. */ - cfg = readl(dev->regs + S5P_CIOCTRL); - - cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK | - S5P_CIOCTRL_YCBCR_PLANE_MASK); - - if (frame->fmt->colplanes == 1) - cfg |= ctx->out_order_1p; - else if (frame->fmt->colplanes == 2) - cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE; - else if (frame->fmt->colplanes == 3) - cfg |= S5P_CIOCTRL_YCBCR_3PLANE; - - writel(cfg, dev->regs + S5P_CIOCTRL); -} - -static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable) -{ - u32 cfg = readl(dev->regs + S5P_ORGISIZE); - if (enable) - cfg |= S5P_CIREAL_ISIZE_AUTOLOAD_EN; - else - cfg &= ~S5P_CIREAL_ISIZE_AUTOLOAD_EN; - writel(cfg, dev->regs + S5P_ORGISIZE); -} - -void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) -{ - u32 cfg = readl(dev->regs + S5P_CIOCTRL); - if (enable) - cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE; - else - cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE; - writel(cfg, dev->regs + S5P_CIOCTRL); -} - -void fimc_hw_set_prescaler(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_scaler *sc = &ctx->scaler; - u32 cfg, shfactor; - - shfactor = 10 - (sc->hfactor + sc->vfactor); - - cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor); - cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio); - cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio); - writel(cfg, dev->regs + S5P_CISCPRERATIO); - - cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width); - cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height); - writel(cfg, dev->regs + S5P_CISCPREDST); -} - -static void fimc_hw_set_scaler(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_scaler *sc = &ctx->scaler; - struct fimc_frame *src_frame = &ctx->s_frame; - struct fimc_frame *dst_frame = &ctx->d_frame; - u32 cfg = 0; - - if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) - cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE); - - if (!sc->enabled) - cfg |= S5P_CISCCTRL_SCALERBYPASS; - - if (sc->scaleup_h) - cfg |= S5P_CISCCTRL_SCALEUP_H; - - if (sc->scaleup_v) - cfg |= S5P_CISCCTRL_SCALEUP_V; - - if (sc->copy_mode) - cfg |= S5P_CISCCTRL_ONE2ONE; - - - if (ctx->in_path == FIMC_DMA) { - if (src_frame->fmt->color == S5P_FIMC_RGB565) - cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565; - else if (src_frame->fmt->color == S5P_FIMC_RGB666) - cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666; - else if (src_frame->fmt->color == S5P_FIMC_RGB888) - cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888; - } - - if (ctx->out_path == FIMC_DMA) { - if (dst_frame->fmt->color == S5P_FIMC_RGB565) - cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565; - else if (dst_frame->fmt->color == S5P_FIMC_RGB666) - cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666; - else if (dst_frame->fmt->color == S5P_FIMC_RGB888) - cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; - } else { - cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; - - if (ctx->flags & FIMC_SCAN_MODE_INTERLACED) - cfg |= S5P_CISCCTRL_INTERLACE; - } - - writel(cfg, dev->regs + S5P_CISCCTRL); -} - -void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct samsung_fimc_variant *variant = dev->variant; - struct fimc_scaler *sc = &ctx->scaler; - u32 cfg; - - dbg("main_hratio= 0x%X main_vratio= 0x%X", - sc->main_hratio, sc->main_vratio); - - fimc_hw_set_scaler(ctx); - - cfg = readl(dev->regs + S5P_CISCCTRL); - - if (variant->has_mainscaler_ext) { - cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); - cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio); - cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio); - writel(cfg, dev->regs + S5P_CISCCTRL); - - cfg = readl(dev->regs + S5P_CIEXTEN); - - cfg &= ~(S5P_CIEXTEN_MVRATIO_EXT_MASK | - S5P_CIEXTEN_MHRATIO_EXT_MASK); - cfg |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio); - cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio); - writel(cfg, dev->regs + S5P_CIEXTEN); - } else { - cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); - cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio); - cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio); - writel(cfg, dev->regs + S5P_CISCCTRL); - } -} - -void fimc_hw_en_capture(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - - u32 cfg = readl(dev->regs + S5P_CIIMGCPT); - - if (ctx->out_path == FIMC_DMA) { - /* one shot mode */ - cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN; - } else { - /* Continous frame capture mode (freerun). */ - cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE | - S5P_CIIMGCPT_CPT_FRMOD_CNT); - cfg |= S5P_CIIMGCPT_IMGCPTEN; - } - - if (ctx->scaler.enabled) - cfg |= S5P_CIIMGCPT_IMGCPTEN_SC; - - writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT); -} - -void fimc_hw_set_effect(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_effect *effect = &ctx->effect; - u32 cfg = (S5P_CIIMGEFF_IE_ENABLE | S5P_CIIMGEFF_IE_SC_AFTER); - - cfg |= effect->type; - - if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) { - cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb); - cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr); - } - - writel(cfg, dev->regs + S5P_CIIMGEFF); -} - -static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->s_frame; - u32 cfg_o = 0; - u32 cfg_r = 0; - - if (FIMC_LCDFIFO == ctx->out_path) - cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN; - - cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width); - cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height); - cfg_r |= S5P_CIREAL_ISIZE_WIDTH(frame->width); - cfg_r |= S5P_CIREAL_ISIZE_HEIGHT(frame->height); - - writel(cfg_o, dev->regs + S5P_ORGISIZE); - writel(cfg_r, dev->regs + S5P_CIREAL_ISIZE); -} - -void fimc_hw_set_in_dma(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->s_frame; - struct fimc_dma_offset *offset = &frame->dma_offset; - u32 cfg; - - /* Set the pixel offsets. */ - cfg = S5P_CIO_OFFS_HOR(offset->y_h); - cfg |= S5P_CIO_OFFS_VER(offset->y_v); - writel(cfg, dev->regs + S5P_CIIYOFF); - - cfg = S5P_CIO_OFFS_HOR(offset->cb_h); - cfg |= S5P_CIO_OFFS_VER(offset->cb_v); - writel(cfg, dev->regs + S5P_CIICBOFF); - - cfg = S5P_CIO_OFFS_HOR(offset->cr_h); - cfg |= S5P_CIO_OFFS_VER(offset->cr_v); - writel(cfg, dev->regs + S5P_CIICROFF); - - /* Input original and real size. */ - fimc_hw_set_in_dma_size(ctx); - - /* Use DMA autoload only in FIFO mode. */ - fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO); - - /* Set the input DMA to process single frame only. */ - cfg = readl(dev->regs + S5P_MSCTRL); - cfg &= ~(S5P_MSCTRL_INFORMAT_MASK - | S5P_MSCTRL_IN_BURST_COUNT_MASK - | S5P_MSCTRL_INPUT_MASK - | S5P_MSCTRL_C_INT_IN_MASK - | S5P_MSCTRL_2P_IN_ORDER_MASK); - - cfg |= (S5P_MSCTRL_IN_BURST_COUNT(4) - | S5P_MSCTRL_INPUT_MEMORY - | S5P_MSCTRL_FIFO_CTRL_FULL); - - switch (frame->fmt->color) { - case S5P_FIMC_RGB565...S5P_FIMC_RGB888: - cfg |= S5P_MSCTRL_INFORMAT_RGB; - break; - case S5P_FIMC_YCBCR420: - cfg |= S5P_MSCTRL_INFORMAT_YCBCR420; - - if (frame->fmt->colplanes == 2) - cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE; - else - cfg |= S5P_MSCTRL_C_INT_IN_3PLANE; - - break; - case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422: - if (frame->fmt->colplanes == 1) { - cfg |= ctx->in_order_1p - | S5P_MSCTRL_INFORMAT_YCBCR422_1P; - } else { - cfg |= S5P_MSCTRL_INFORMAT_YCBCR422; - - if (frame->fmt->colplanes == 2) - cfg |= ctx->in_order_2p - | S5P_MSCTRL_C_INT_IN_2PLANE; - else - cfg |= S5P_MSCTRL_C_INT_IN_3PLANE; - } - break; - default: - break; - } - - writel(cfg, dev->regs + S5P_MSCTRL); - - /* Input/output DMA linear/tiled mode. */ - cfg = readl(dev->regs + S5P_CIDMAPARAM); - cfg &= ~S5P_CIDMAPARAM_TILE_MASK; - - if (tiled_fmt(ctx->s_frame.fmt)) - cfg |= S5P_CIDMAPARAM_R_64X32; - - if (tiled_fmt(ctx->d_frame.fmt)) - cfg |= S5P_CIDMAPARAM_W_64X32; - - writel(cfg, dev->regs + S5P_CIDMAPARAM); -} - - -void fimc_hw_set_input_path(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - - u32 cfg = readl(dev->regs + S5P_MSCTRL); - cfg &= ~S5P_MSCTRL_INPUT_MASK; - - if (ctx->in_path == FIMC_DMA) - cfg |= S5P_MSCTRL_INPUT_MEMORY; - else - cfg |= S5P_MSCTRL_INPUT_EXTCAM; - - writel(cfg, dev->regs + S5P_MSCTRL); -} - -void fimc_hw_set_output_path(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - - u32 cfg = readl(dev->regs + S5P_CISCCTRL); - cfg &= ~S5P_CISCCTRL_LCDPATHEN_FIFO; - if (ctx->out_path == FIMC_LCDFIFO) - cfg |= S5P_CISCCTRL_LCDPATHEN_FIFO; - writel(cfg, dev->regs + S5P_CISCCTRL); -} - -void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr) -{ - u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE); - cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS; - writel(cfg, dev->regs + S5P_CIREAL_ISIZE); - - writel(paddr->y, dev->regs + S5P_CIIYSA(0)); - writel(paddr->cb, dev->regs + S5P_CIICBSA(0)); - writel(paddr->cr, dev->regs + S5P_CIICRSA(0)); - - cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS; - writel(cfg, dev->regs + S5P_CIREAL_ISIZE); -} - -void fimc_hw_set_output_addr(struct fimc_dev *dev, - struct fimc_addr *paddr, int index) -{ - int i = (index == -1) ? 0 : index; - do { - writel(paddr->y, dev->regs + S5P_CIOYSA(i)); - writel(paddr->cb, dev->regs + S5P_CIOCBSA(i)); - writel(paddr->cr, dev->regs + S5P_CIOCRSA(i)); - dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", - i, paddr->y, paddr->cb, paddr->cr); - } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); -} - -int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, - struct s5p_fimc_isp_info *cam) -{ - u32 cfg = readl(fimc->regs + S5P_CIGCTRL); - - cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC | - S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC); - - if (cam->flags & FIMC_CLK_INV_PCLK) - cfg |= S5P_CIGCTRL_INVPOLPCLK; - - if (cam->flags & FIMC_CLK_INV_VSYNC) - cfg |= S5P_CIGCTRL_INVPOLVSYNC; - - if (cam->flags & FIMC_CLK_INV_HREF) - cfg |= S5P_CIGCTRL_INVPOLHREF; - - if (cam->flags & FIMC_CLK_INV_HSYNC) - cfg |= S5P_CIGCTRL_INVPOLHSYNC; - - writel(cfg, fimc->regs + S5P_CIGCTRL); - - return 0; -} - -int fimc_hw_set_camera_source(struct fimc_dev *fimc, - struct s5p_fimc_isp_info *cam) -{ - struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; - u32 cfg = 0; - u32 bus_width; - int i; - - static const struct { - u32 pixelcode; - u32 cisrcfmt; - u16 bus_width; - } pix_desc[] = { - { V4L2_MBUS_FMT_YUYV8_2X8, S5P_CISRCFMT_ORDER422_YCBYCR, 8 }, - { V4L2_MBUS_FMT_YVYU8_2X8, S5P_CISRCFMT_ORDER422_YCRYCB, 8 }, - { V4L2_MBUS_FMT_VYUY8_2X8, S5P_CISRCFMT_ORDER422_CRYCBY, 8 }, - { V4L2_MBUS_FMT_UYVY8_2X8, S5P_CISRCFMT_ORDER422_CBYCRY, 8 }, - /* TODO: Add pixel codes for 16-bit bus width */ - }; - - if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) { - for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { - if (fimc->vid_cap.fmt.code == pix_desc[i].pixelcode) { - cfg = pix_desc[i].cisrcfmt; - bus_width = pix_desc[i].bus_width; - break; - } - } - - if (i == ARRAY_SIZE(pix_desc)) { - v4l2_err(&fimc->vid_cap.v4l2_dev, - "Camera color format not supported: %d\n", - fimc->vid_cap.fmt.code); - return -EINVAL; - } - - if (cam->bus_type == FIMC_ITU_601) { - if (bus_width == 8) - cfg |= S5P_CISRCFMT_ITU601_8BIT; - else if (bus_width == 16) - cfg |= S5P_CISRCFMT_ITU601_16BIT; - } /* else defaults to ITU-R BT.656 8-bit */ - } - - cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height); - writel(cfg, fimc->regs + S5P_CISRCFMT); - return 0; -} - - -int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) -{ - u32 hoff2, voff2; - - u32 cfg = readl(fimc->regs + S5P_CIWDOFST); - - cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK); - cfg |= S5P_CIWDOFST_OFF_EN | - S5P_CIWDOFST_HOROFF(f->offs_h) | - S5P_CIWDOFST_VEROFF(f->offs_v); - - writel(cfg, fimc->regs + S5P_CIWDOFST); - - /* See CIWDOFSTn register description in the datasheet for details. */ - hoff2 = f->o_width - f->width - f->offs_h; - voff2 = f->o_height - f->height - f->offs_v; - cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2); - - writel(cfg, fimc->regs + S5P_CIWDOFST2); - return 0; -} - -int fimc_hw_set_camera_type(struct fimc_dev *fimc, - struct s5p_fimc_isp_info *cam) -{ - u32 cfg, tmp; - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - - cfg = readl(fimc->regs + S5P_CIGCTRL); - - /* Select ITU B interface, disable Writeback path and test pattern. */ - cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A | - S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB | - S5P_CIGCTRL_SELCAM_MIPI_A); - - if (cam->bus_type == FIMC_MIPI_CSI2) { - cfg |= S5P_CIGCTRL_SELCAM_MIPI; - - if (cam->mux_id == 0) - cfg |= S5P_CIGCTRL_SELCAM_MIPI_A; - - /* TODO: add remaining supported formats. */ - if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) { - tmp = S5P_CSIIMGFMT_YCBCR422_8BIT; - } else { - err("camera image format not supported: %d", - vid_cap->fmt.code); - return -EINVAL; - } - tmp |= (cam->csi_data_align == 32) << 8; - - writel(tmp, fimc->regs + S5P_CSIIMGFMT); - - } else if (cam->bus_type == FIMC_ITU_601 || - cam->bus_type == FIMC_ITU_656) { - if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ - cfg |= S5P_CIGCTRL_SELCAM_ITU_A; - } else if (cam->bus_type == FIMC_LCD_WB) { - cfg |= S5P_CIGCTRL_CAMIF_SELWB; - } else { - err("invalid camera bus type selected\n"); - return -EINVAL; - } - writel(cfg, fimc->regs + S5P_CIGCTRL); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ - -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o -s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/regs-fimc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/regs-fimc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/regs-fimc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/s5p-fimc/regs-fimc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,297 +0,0 @@ -/* - * Register definition file for Samsung Camera Interface (FIMC) driver - * - * Copyright (c) 2010 Samsung Electronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef REGS_FIMC_H_ -#define REGS_FIMC_H_ - -/* Input source format */ -#define S5P_CISRCFMT 0x00 -#define S5P_CISRCFMT_ITU601_8BIT (1 << 31) -#define S5P_CISRCFMT_ITU601_16BIT (1 << 29) -#define S5P_CISRCFMT_ORDER422_YCBYCR (0 << 14) -#define S5P_CISRCFMT_ORDER422_YCRYCB (1 << 14) -#define S5P_CISRCFMT_ORDER422_CBYCRY (2 << 14) -#define S5P_CISRCFMT_ORDER422_CRYCBY (3 << 14) -#define S5P_CISRCFMT_HSIZE(x) ((x) << 16) -#define S5P_CISRCFMT_VSIZE(x) ((x) << 0) - -/* Window offset */ -#define S5P_CIWDOFST 0x04 -#define S5P_CIWDOFST_OFF_EN (1 << 31) -#define S5P_CIWDOFST_CLROVFIY (1 << 30) -#define S5P_CIWDOFST_CLROVRLB (1 << 29) -#define S5P_CIWDOFST_HOROFF_MASK (0x7ff << 16) -#define S5P_CIWDOFST_CLROVFICB (1 << 15) -#define S5P_CIWDOFST_CLROVFICR (1 << 14) -#define S5P_CIWDOFST_HOROFF(x) ((x) << 16) -#define S5P_CIWDOFST_VEROFF(x) ((x) << 0) -#define S5P_CIWDOFST_VEROFF_MASK (0xfff << 0) - -/* Global control */ -#define S5P_CIGCTRL 0x08 -#define S5P_CIGCTRL_SWRST (1 << 31) -#define S5P_CIGCTRL_CAMRST_A (1 << 30) -#define S5P_CIGCTRL_SELCAM_ITU_A (1 << 29) -#define S5P_CIGCTRL_TESTPAT_NORMAL (0 << 27) -#define S5P_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27) -#define S5P_CIGCTRL_TESTPAT_HOR_INC (2 << 27) -#define S5P_CIGCTRL_TESTPAT_VER_INC (3 << 27) -#define S5P_CIGCTRL_TESTPAT_MASK (3 << 27) -#define S5P_CIGCTRL_TESTPAT_SHIFT (27) -#define S5P_CIGCTRL_INVPOLPCLK (1 << 26) -#define S5P_CIGCTRL_INVPOLVSYNC (1 << 25) -#define S5P_CIGCTRL_INVPOLHREF (1 << 24) -#define S5P_CIGCTRL_IRQ_OVFEN (1 << 22) -#define S5P_CIGCTRL_HREF_MASK (1 << 21) -#define S5P_CIGCTRL_IRQ_LEVEL (1 << 20) -#define S5P_CIGCTRL_IRQ_CLR (1 << 19) -#define S5P_CIGCTRL_IRQ_ENABLE (1 << 16) -#define S5P_CIGCTRL_SHDW_DISABLE (1 << 12) -#define S5P_CIGCTRL_SELCAM_MIPI_A (1 << 7) -#define S5P_CIGCTRL_CAMIF_SELWB (1 << 6) -/* 0 - ITU601; 1 - ITU709 */ -#define S5P_CIGCTRL_CSC_ITU601_709 (1 << 5) -#define S5P_CIGCTRL_INVPOLHSYNC (1 << 4) -#define S5P_CIGCTRL_SELCAM_MIPI (1 << 3) -#define S5P_CIGCTRL_INTERLACE (1 << 0) - -/* Window offset 2 */ -#define S5P_CIWDOFST2 0x14 -#define S5P_CIWDOFST2_HOROFF_MASK (0xfff << 16) -#define S5P_CIWDOFST2_VEROFF_MASK (0xfff << 0) -#define S5P_CIWDOFST2_HOROFF(x) ((x) << 16) -#define S5P_CIWDOFST2_VEROFF(x) ((x) << 0) - -/* Output DMA Y/Cb/Cr plane start addresses */ -#define S5P_CIOYSA(n) (0x18 + (n) * 4) -#define S5P_CIOCBSA(n) (0x28 + (n) * 4) -#define S5P_CIOCRSA(n) (0x38 + (n) * 4) - -/* Target image format */ -#define S5P_CITRGFMT 0x48 -#define S5P_CITRGFMT_INROT90 (1 << 31) -#define S5P_CITRGFMT_YCBCR420 (0 << 29) -#define S5P_CITRGFMT_YCBCR422 (1 << 29) -#define S5P_CITRGFMT_YCBCR422_1P (2 << 29) -#define S5P_CITRGFMT_RGB (3 << 29) -#define S5P_CITRGFMT_FMT_MASK (3 << 29) -#define S5P_CITRGFMT_HSIZE_MASK (0xfff << 16) -#define S5P_CITRGFMT_FLIP_SHIFT (14) -#define S5P_CITRGFMT_FLIP_NORMAL (0 << 14) -#define S5P_CITRGFMT_FLIP_X_MIRROR (1 << 14) -#define S5P_CITRGFMT_FLIP_Y_MIRROR (2 << 14) -#define S5P_CITRGFMT_FLIP_180 (3 << 14) -#define S5P_CITRGFMT_FLIP_MASK (3 << 14) -#define S5P_CITRGFMT_OUTROT90 (1 << 13) -#define S5P_CITRGFMT_VSIZE_MASK (0xfff << 0) -#define S5P_CITRGFMT_HSIZE(x) ((x) << 16) -#define S5P_CITRGFMT_VSIZE(x) ((x) << 0) - -/* Output DMA control */ -#define S5P_CIOCTRL 0x4c -#define S5P_CIOCTRL_ORDER422_MASK (3 << 0) -#define S5P_CIOCTRL_ORDER422_CRYCBY (0 << 0) -#define S5P_CIOCTRL_ORDER422_CBYCRY (1 << 0) -#define S5P_CIOCTRL_ORDER422_YCRYCB (2 << 0) -#define S5P_CIOCTRL_ORDER422_YCBYCR (3 << 0) -#define S5P_CIOCTRL_LASTIRQ_ENABLE (1 << 2) -#define S5P_CIOCTRL_YCBCR_3PLANE (0 << 3) -#define S5P_CIOCTRL_YCBCR_2PLANE (1 << 3) -#define S5P_CIOCTRL_YCBCR_PLANE_MASK (1 << 3) -#define S5P_CIOCTRL_ORDER2P_SHIFT (24) -#define S5P_CIOCTRL_ORDER2P_MASK (3 << 24) -#define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24) - -/* Pre-scaler control 1 */ -#define S5P_CISCPRERATIO 0x50 -#define S5P_CISCPRERATIO_SHFACTOR(x) ((x) << 28) -#define S5P_CISCPRERATIO_HOR(x) ((x) << 16) -#define S5P_CISCPRERATIO_VER(x) ((x) << 0) - -#define S5P_CISCPREDST 0x54 -#define S5P_CISCPREDST_WIDTH(x) ((x) << 16) -#define S5P_CISCPREDST_HEIGHT(x) ((x) << 0) - -/* Main scaler control */ -#define S5P_CISCCTRL 0x58 -#define S5P_CISCCTRL_SCALERBYPASS (1 << 31) -#define S5P_CISCCTRL_SCALEUP_H (1 << 30) -#define S5P_CISCCTRL_SCALEUP_V (1 << 29) -#define S5P_CISCCTRL_CSCR2Y_WIDE (1 << 28) -#define S5P_CISCCTRL_CSCY2R_WIDE (1 << 27) -#define S5P_CISCCTRL_LCDPATHEN_FIFO (1 << 26) -#define S5P_CISCCTRL_INTERLACE (1 << 25) -#define S5P_CISCCTRL_SCALERSTART (1 << 15) -#define S5P_CISCCTRL_INRGB_FMT_RGB565 (0 << 13) -#define S5P_CISCCTRL_INRGB_FMT_RGB666 (1 << 13) -#define S5P_CISCCTRL_INRGB_FMT_RGB888 (2 << 13) -#define S5P_CISCCTRL_INRGB_FMT_MASK (3 << 13) -#define S5P_CISCCTRL_OUTRGB_FMT_RGB565 (0 << 11) -#define S5P_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11) -#define S5P_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11) -#define S5P_CISCCTRL_OUTRGB_FMT_MASK (3 << 11) -#define S5P_CISCCTRL_RGB_EXT (1 << 10) -#define S5P_CISCCTRL_ONE2ONE (1 << 9) -#define S5P_CISCCTRL_MHRATIO(x) ((x) << 16) -#define S5P_CISCCTRL_MVRATIO(x) ((x) << 0) -#define S5P_CISCCTRL_MHRATIO_MASK (0x1ff << 16) -#define S5P_CISCCTRL_MVRATIO_MASK (0x1ff << 0) -#define S5P_CISCCTRL_MHRATIO_EXT(x) (((x) >> 6) << 16) -#define S5P_CISCCTRL_MVRATIO_EXT(x) (((x) >> 6) << 0) - -/* Target area */ -#define S5P_CITAREA 0x5c -#define S5P_CITAREA_MASK 0x0fffffff - -/* General status */ -#define S5P_CISTATUS 0x64 -#define S5P_CISTATUS_OVFIY (1 << 31) -#define S5P_CISTATUS_OVFICB (1 << 30) -#define S5P_CISTATUS_OVFICR (1 << 29) -#define S5P_CISTATUS_VSYNC (1 << 28) -#define S5P_CISTATUS_FRAMECNT_MASK (3 << 26) -#define S5P_CISTATUS_FRAMECNT_SHIFT 26 -#define S5P_CISTATUS_WINOFF_EN (1 << 25) -#define S5P_CISTATUS_IMGCPT_EN (1 << 22) -#define S5P_CISTATUS_IMGCPT_SCEN (1 << 21) -#define S5P_CISTATUS_VSYNC_A (1 << 20) -#define S5P_CISTATUS_VSYNC_B (1 << 19) -#define S5P_CISTATUS_OVRLB (1 << 18) -#define S5P_CISTATUS_FRAME_END (1 << 17) -#define S5P_CISTATUS_LASTCAPT_END (1 << 16) -#define S5P_CISTATUS_VVALID_A (1 << 15) -#define S5P_CISTATUS_VVALID_B (1 << 14) - -/* Indexes to the last and the currently processed buffer. */ -#define S5P_CISTATUS2 0x68 - -/* Image capture control */ -#define S5P_CIIMGCPT 0xc0 -#define S5P_CIIMGCPT_IMGCPTEN (1 << 31) -#define S5P_CIIMGCPT_IMGCPTEN_SC (1 << 30) -#define S5P_CIIMGCPT_CPT_FREN_ENABLE (1 << 25) -#define S5P_CIIMGCPT_CPT_FRMOD_CNT (1 << 18) - -/* Frame capture sequence */ -#define S5P_CICPTSEQ 0xc4 - -/* Image effect */ -#define S5P_CIIMGEFF 0xd0 -#define S5P_CIIMGEFF_IE_DISABLE (0 << 30) -#define S5P_CIIMGEFF_IE_ENABLE (1 << 30) -#define S5P_CIIMGEFF_IE_SC_BEFORE (0 << 29) -#define S5P_CIIMGEFF_IE_SC_AFTER (1 << 29) -#define S5P_CIIMGEFF_FIN_BYPASS (0 << 26) -#define S5P_CIIMGEFF_FIN_ARBITRARY (1 << 26) -#define S5P_CIIMGEFF_FIN_NEGATIVE (2 << 26) -#define S5P_CIIMGEFF_FIN_ARTFREEZE (3 << 26) -#define S5P_CIIMGEFF_FIN_EMBOSSING (4 << 26) -#define S5P_CIIMGEFF_FIN_SILHOUETTE (5 << 26) -#define S5P_CIIMGEFF_FIN_MASK (7 << 26) -#define S5P_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0)) -#define S5P_CIIMGEFF_PAT_CB(x) ((x) << 13) -#define S5P_CIIMGEFF_PAT_CR(x) ((x) << 0) - -/* Input DMA Y/Cb/Cr plane start address 0/1 */ -#define S5P_CIIYSA(n) (0xd4 + (n) * 0x70) -#define S5P_CIICBSA(n) (0xd8 + (n) * 0x70) -#define S5P_CIICRSA(n) (0xdc + (n) * 0x70) - -/* Real input DMA image size */ -#define S5P_CIREAL_ISIZE 0xf8 -#define S5P_CIREAL_ISIZE_AUTOLOAD_EN (1 << 31) -#define S5P_CIREAL_ISIZE_ADDR_CH_DIS (1 << 30) -#define S5P_CIREAL_ISIZE_HEIGHT(x) ((x) << 16) -#define S5P_CIREAL_ISIZE_WIDTH(x) ((x) << 0) - - -/* Input DMA control */ -#define S5P_MSCTRL 0xfc -#define S5P_MSCTRL_IN_BURST_COUNT_MASK (0xF << 24) -#define S5P_MSCTRL_2P_IN_ORDER_MASK (3 << 16) -#define S5P_MSCTRL_2P_IN_ORDER_SHIFT 16 -#define S5P_MSCTRL_C_INT_IN_3PLANE (0 << 15) -#define S5P_MSCTRL_C_INT_IN_2PLANE (1 << 15) -#define S5P_MSCTRL_C_INT_IN_MASK (1 << 15) -#define S5P_MSCTRL_FLIP_SHIFT 13 -#define S5P_MSCTRL_FLIP_MASK (3 << 13) -#define S5P_MSCTRL_FLIP_NORMAL (0 << 13) -#define S5P_MSCTRL_FLIP_X_MIRROR (1 << 13) -#define S5P_MSCTRL_FLIP_Y_MIRROR (2 << 13) -#define S5P_MSCTRL_FLIP_180 (3 << 13) -#define S5P_MSCTRL_FIFO_CTRL_FULL (1 << 12) -#define S5P_MSCTRL_ORDER422_SHIFT 4 -#define S5P_MSCTRL_ORDER422_YCBYCR (0 << 4) -#define S5P_MSCTRL_ORDER422_CBYCRY (1 << 4) -#define S5P_MSCTRL_ORDER422_YCRYCB (2 << 4) -#define S5P_MSCTRL_ORDER422_CRYCBY (3 << 4) -#define S5P_MSCTRL_ORDER422_MASK (3 << 4) -#define S5P_MSCTRL_INPUT_EXTCAM (0 << 3) -#define S5P_MSCTRL_INPUT_MEMORY (1 << 3) -#define S5P_MSCTRL_INPUT_MASK (1 << 3) -#define S5P_MSCTRL_INFORMAT_YCBCR420 (0 << 1) -#define S5P_MSCTRL_INFORMAT_YCBCR422 (1 << 1) -#define S5P_MSCTRL_INFORMAT_YCBCR422_1P (2 << 1) -#define S5P_MSCTRL_INFORMAT_RGB (3 << 1) -#define S5P_MSCTRL_INFORMAT_MASK (3 << 1) -#define S5P_MSCTRL_ENVID (1 << 0) -#define S5P_MSCTRL_IN_BURST_COUNT(x) ((x) << 24) - -/* Output DMA Y/Cb/Cr offset */ -#define S5P_CIOYOFF 0x168 -#define S5P_CIOCBOFF 0x16c -#define S5P_CIOCROFF 0x170 - -/* Input DMA Y/Cb/Cr offset */ -#define S5P_CIIYOFF 0x174 -#define S5P_CIICBOFF 0x178 -#define S5P_CIICROFF 0x17c - -#define S5P_CIO_OFFS_VER(x) ((x) << 16) -#define S5P_CIO_OFFS_HOR(x) ((x) << 0) - -/* Input DMA original image size */ -#define S5P_ORGISIZE 0x180 - -/* Output DMA original image size */ -#define S5P_ORGOSIZE 0x184 - -#define S5P_ORIG_SIZE_VER(x) ((x) << 16) -#define S5P_ORIG_SIZE_HOR(x) ((x) << 0) - -/* Real output DMA image size (extension register) */ -#define S5P_CIEXTEN 0x188 -#define S5P_CIEXTEN_MHRATIO_EXT(x) (((x) & 0x3f) << 10) -#define S5P_CIEXTEN_MVRATIO_EXT(x) ((x) & 0x3f) -#define S5P_CIEXTEN_MHRATIO_EXT_MASK (0x3f << 10) -#define S5P_CIEXTEN_MVRATIO_EXT_MASK 0x3f - -#define S5P_CIDMAPARAM 0x18c -#define S5P_CIDMAPARAM_R_LINEAR (0 << 29) -#define S5P_CIDMAPARAM_R_64X32 (3 << 29) -#define S5P_CIDMAPARAM_W_LINEAR (0 << 13) -#define S5P_CIDMAPARAM_W_64X32 (3 << 13) -#define S5P_CIDMAPARAM_TILE_MASK ((3 << 29) | (3 << 13)) - -/* MIPI CSI image format */ -#define S5P_CSIIMGFMT 0x194 -#define S5P_CSIIMGFMT_YCBCR422_8BIT 0x1e -#define S5P_CSIIMGFMT_RAW8 0x2a -#define S5P_CSIIMGFMT_RAW10 0x2b -#define S5P_CSIIMGFMT_RAW12 0x2c -#define S5P_CSIIMGFMT_USER1 0x30 -#define S5P_CSIIMGFMT_USER2 0x31 -#define S5P_CSIIMGFMT_USER3 0x32 -#define S5P_CSIIMGFMT_USER4 0x33 - -/* Output frame buffer sequence mask */ -#define S5P_CIFCNTSEQ 0x1FC - -#endif /* REGS_FIMC_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa6588.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa6588.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa6588.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa6588.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,553 +0,0 @@ -/* - Driver for SAA6588 RDS decoder - - (c) 2005 Hans J. Koch - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -/* insmod options */ -static unsigned int debug; -static unsigned int xtal; -static unsigned int mmbs; -static unsigned int plvl; -static unsigned int bufblocks = 100; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); -module_param(xtal, int, 0); -MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0"); -module_param(mmbs, int, 0); -MODULE_PARM_DESC(mmbs, "enable MMBS mode: 0=off (default), 1=on"); -module_param(plvl, int, 0); -MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0"); -module_param(bufblocks, int, 0); -MODULE_PARM_DESC(bufblocks, "number of buffered blocks, default 100"); - -MODULE_DESCRIPTION("v4l2 driver module for SAA6588 RDS decoder"); -MODULE_AUTHOR("Hans J. Koch "); - -MODULE_LICENSE("GPL"); - -/* ---------------------------------------------------------------------- */ - -#define UNSET (-1U) -#define PREFIX "saa6588: " -#define dprintk if (debug) printk - -struct saa6588 { - struct v4l2_subdev sd; - struct delayed_work work; - spinlock_t lock; - unsigned char *buffer; - unsigned int buf_size; - unsigned int rd_index; - unsigned int wr_index; - unsigned int block_count; - unsigned char last_blocknum; - wait_queue_head_t read_queue; - int data_available_for_read; - u8 sync; -}; - -static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa6588, sd); -} - -/* ---------------------------------------------------------------------- */ - -/* - * SAA6588 defines - */ - -/* Initialization and mode control byte (0w) */ - -/* bit 0+1 (DAC0/DAC1) */ -#define cModeStandard 0x00 -#define cModeFastPI 0x01 -#define cModeReducedRequest 0x02 -#define cModeInvalid 0x03 - -/* bit 2 (RBDS) */ -#define cProcessingModeRDS 0x00 -#define cProcessingModeRBDS 0x04 - -/* bit 3+4 (SYM0/SYM1) */ -#define cErrCorrectionNone 0x00 -#define cErrCorrection2Bits 0x08 -#define cErrCorrection5Bits 0x10 -#define cErrCorrectionNoneRBDS 0x18 - -/* bit 5 (NWSY) */ -#define cSyncNormal 0x00 -#define cSyncRestart 0x20 - -/* bit 6 (TSQD) */ -#define cSigQualityDetectOFF 0x00 -#define cSigQualityDetectON 0x40 - -/* bit 7 (SQCM) */ -#define cSigQualityTriggered 0x00 -#define cSigQualityContinous 0x80 - -/* Pause level and flywheel control byte (1w) */ - -/* bits 0..5 (FEB0..FEB5) */ -#define cFlywheelMaxBlocksMask 0x3F -#define cFlywheelDefault 0x20 - -/* bits 6+7 (PL0/PL1) */ -#define cPauseLevel_11mV 0x00 -#define cPauseLevel_17mV 0x40 -#define cPauseLevel_27mV 0x80 -#define cPauseLevel_43mV 0xC0 - -/* Pause time/oscillator frequency/quality detector control byte (1w) */ - -/* bits 0..4 (SQS0..SQS4) */ -#define cQualityDetectSensMask 0x1F -#define cQualityDetectDefault 0x0F - -/* bit 5 (SOSC) */ -#define cSelectOscFreqOFF 0x00 -#define cSelectOscFreqON 0x20 - -/* bit 6+7 (PTF0/PTF1) */ -#define cOscFreq_4332kHz 0x00 -#define cOscFreq_8664kHz 0x40 -#define cOscFreq_12996kHz 0x80 -#define cOscFreq_17328kHz 0xC0 - -/* ---------------------------------------------------------------------- */ - -static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf) -{ - int i; - - if (s->rd_index == s->wr_index) { - if (debug > 2) - dprintk(PREFIX "Read: buffer empty.\n"); - return 0; - } - - if (debug > 2) { - dprintk(PREFIX "Read: "); - for (i = s->rd_index; i < s->rd_index + 3; i++) - dprintk("0x%02x ", s->buffer[i]); - } - - if (copy_to_user(user_buf, &s->buffer[s->rd_index], 3)) - return -EFAULT; - - s->rd_index += 3; - if (s->rd_index >= s->buf_size) - s->rd_index = 0; - s->block_count--; - - if (debug > 2) - dprintk("%d blocks total.\n", s->block_count); - - return 1; -} - -static void read_from_buf(struct saa6588 *s, struct saa6588_command *a) -{ - unsigned long flags; - - unsigned char __user *buf_ptr = a->buffer; - unsigned int i; - unsigned int rd_blocks; - - a->result = 0; - if (!a->buffer) - return; - - while (!s->data_available_for_read) { - int ret = wait_event_interruptible(s->read_queue, - s->data_available_for_read); - if (ret == -ERESTARTSYS) { - a->result = -EINTR; - return; - } - } - - spin_lock_irqsave(&s->lock, flags); - rd_blocks = a->block_count; - if (rd_blocks > s->block_count) - rd_blocks = s->block_count; - - if (!rd_blocks) { - spin_unlock_irqrestore(&s->lock, flags); - return; - } - - for (i = 0; i < rd_blocks; i++) { - if (block_to_user_buf(s, buf_ptr)) { - buf_ptr += 3; - a->result++; - } else - break; - } - a->result *= 3; - s->data_available_for_read = (s->block_count > 0); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf) -{ - unsigned int i; - - if (debug > 3) - dprintk(PREFIX "New block: "); - - for (i = 0; i < 3; ++i) { - if (debug > 3) - dprintk("0x%02x ", blockbuf[i]); - s->buffer[s->wr_index] = blockbuf[i]; - s->wr_index++; - } - - if (s->wr_index >= s->buf_size) - s->wr_index = 0; - - if (s->wr_index == s->rd_index) { - s->rd_index += 3; - if (s->rd_index >= s->buf_size) - s->rd_index = 0; - } else - s->block_count++; - - if (debug > 3) - dprintk("%d blocks total.\n", s->block_count); -} - -static void saa6588_i2c_poll(struct saa6588 *s) -{ - struct i2c_client *client = v4l2_get_subdevdata(&s->sd); - unsigned long flags; - unsigned char tmpbuf[6]; - unsigned char blocknum; - unsigned char tmp; - - /* Although we only need 3 bytes, we have to read at least 6. - SAA6588 returns garbage otherwise. */ - if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) { - if (debug > 1) - dprintk(PREFIX "read error!\n"); - return; - } - - s->sync = tmpbuf[0] & 0x10; - if (!s->sync) - return; - blocknum = tmpbuf[0] >> 5; - if (blocknum == s->last_blocknum) { - if (debug > 3) - dprintk("Saw block %d again.\n", blocknum); - return; - } - - s->last_blocknum = blocknum; - - /* - Byte order according to v4l2 specification: - - Byte 0: Least Significant Byte of RDS Block - Byte 1: Most Significant Byte of RDS Block - Byte 2 Bit 7: Error bit. Indicates that an uncorrectable error - occurred during reception of this block. - Bit 6: Corrected bit. Indicates that an error was - corrected for this data block. - Bits 5-3: Same as bits 0-2. - Bits 2-0: Block number. - - SAA6588 byte order is Status-MSB-LSB, so we have to swap the - first and the last of the 3 bytes block. - */ - - tmp = tmpbuf[2]; - tmpbuf[2] = tmpbuf[0]; - tmpbuf[0] = tmp; - - /* Map 'Invalid block E' to 'Invalid Block' */ - if (blocknum == 6) - blocknum = V4L2_RDS_BLOCK_INVALID; - /* And if are not in mmbs mode, then 'Block E' is also mapped - to 'Invalid Block'. As far as I can tell MMBS is discontinued, - and if there is ever a need to support E blocks, then please - contact the linux-media mailinglist. */ - else if (!mmbs && blocknum == 5) - blocknum = V4L2_RDS_BLOCK_INVALID; - tmp = blocknum; - tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */ - if ((tmpbuf[2] & 0x03) == 0x03) - tmp |= V4L2_RDS_BLOCK_ERROR; /* uncorrectable error */ - else if ((tmpbuf[2] & 0x03) != 0x00) - tmp |= V4L2_RDS_BLOCK_CORRECTED; /* corrected error */ - tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */ - - spin_lock_irqsave(&s->lock, flags); - block_to_buf(s, tmpbuf); - spin_unlock_irqrestore(&s->lock, flags); - s->data_available_for_read = 1; - wake_up_interruptible(&s->read_queue); -} - -static void saa6588_work(struct work_struct *work) -{ - struct saa6588 *s = container_of(work, struct saa6588, work.work); - - saa6588_i2c_poll(s); - schedule_delayed_work(&s->work, msecs_to_jiffies(20)); -} - -static void saa6588_configure(struct saa6588 *s) -{ - struct i2c_client *client = v4l2_get_subdevdata(&s->sd); - unsigned char buf[3]; - int rc; - - buf[0] = cSyncRestart; - if (mmbs) - buf[0] |= cProcessingModeRBDS; - - buf[1] = cFlywheelDefault; - switch (plvl) { - case 0: - buf[1] |= cPauseLevel_11mV; - break; - case 1: - buf[1] |= cPauseLevel_17mV; - break; - case 2: - buf[1] |= cPauseLevel_27mV; - break; - case 3: - buf[1] |= cPauseLevel_43mV; - break; - default: /* nothing */ - break; - } - - buf[2] = cQualityDetectDefault | cSelectOscFreqON; - - switch (xtal) { - case 0: - buf[2] |= cOscFreq_4332kHz; - break; - case 1: - buf[2] |= cOscFreq_8664kHz; - break; - case 2: - buf[2] |= cOscFreq_12996kHz; - break; - case 3: - buf[2] |= cOscFreq_17328kHz; - break; - default: /* nothing */ - break; - } - - dprintk(PREFIX "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n", - buf[0], buf[1], buf[2]); - - rc = i2c_master_send(client, buf, 3); - if (rc != 3) - printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc); -} - -/* ---------------------------------------------------------------------- */ - -static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct saa6588 *s = to_saa6588(sd); - struct saa6588_command *a = arg; - - switch (cmd) { - /* --- open() for /dev/radio --- */ - case SAA6588_CMD_OPEN: - a->result = 0; /* return error if chip doesn't work ??? */ - break; - /* --- close() for /dev/radio --- */ - case SAA6588_CMD_CLOSE: - s->data_available_for_read = 1; - wake_up_interruptible(&s->read_queue); - a->result = 0; - break; - /* --- read() for /dev/radio --- */ - case SAA6588_CMD_READ: - read_from_buf(s, a); - break; - /* --- poll() for /dev/radio --- */ - case SAA6588_CMD_POLL: - a->result = 0; - if (s->data_available_for_read) { - a->result |= POLLIN | POLLRDNORM; - } - poll_wait(a->instance, &s->read_queue, a->event_list); - break; - - default: - /* nothing */ - return -ENOIOCTLCMD; - } - return 0; -} - -static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct saa6588 *s = to_saa6588(sd); - - vt->capability |= V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; - if (s->sync) - vt->rxsubchans |= V4L2_TUNER_SUB_RDS; - return 0; -} - -static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct saa6588 *s = to_saa6588(sd); - - saa6588_configure(s); - return 0; -} - -static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA6588, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops saa6588_core_ops = { - .g_chip_ident = saa6588_g_chip_ident, - .ioctl = saa6588_ioctl, -}; - -static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = { - .g_tuner = saa6588_g_tuner, - .s_tuner = saa6588_s_tuner, -}; - -static const struct v4l2_subdev_ops saa6588_ops = { - .core = &saa6588_core_ops, - .tuner = &saa6588_tuner_ops, -}; - -/* ---------------------------------------------------------------------- */ - -static int saa6588_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct saa6588 *s; - struct v4l2_subdev *sd; - - v4l_info(client, "saa6588 found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (s == NULL) - return -ENOMEM; - - s->buf_size = bufblocks * 3; - - s->buffer = kmalloc(s->buf_size, GFP_KERNEL); - if (s->buffer == NULL) { - kfree(s); - return -ENOMEM; - } - sd = &s->sd; - v4l2_i2c_subdev_init(sd, client, &saa6588_ops); - spin_lock_init(&s->lock); - s->block_count = 0; - s->wr_index = 0; - s->rd_index = 0; - s->last_blocknum = 0xff; - init_waitqueue_head(&s->read_queue); - s->data_available_for_read = 0; - - saa6588_configure(s); - - /* start polling via eventd */ - INIT_DELAYED_WORK(&s->work, saa6588_work); - schedule_delayed_work(&s->work, 0); - return 0; -} - -static int saa6588_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct saa6588 *s = to_saa6588(sd); - - v4l2_device_unregister_subdev(sd); - - cancel_delayed_work_sync(&s->work); - - kfree(s->buffer); - kfree(s); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id saa6588_id[] = { - { "saa6588", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, saa6588_id); - -static struct i2c_driver saa6588_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "saa6588", - }, - .probe = saa6588_probe, - .remove = saa6588_remove, - .id_table = saa6588_id, -}; - -static __init int init_saa6588(void) -{ - return i2c_add_driver(&saa6588_driver); -} - -static __exit void exit_saa6588(void) -{ - i2c_del_driver(&saa6588_driver); -} - -module_init(init_saa6588); -module_exit(exit_saa6588); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7110.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7110.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7110.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7110.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,505 +0,0 @@ -/* - * saa7110 - Philips SAA7110(A) video decoder driver - * - * Copyright (C) 1998 Pauline Middelink - * - * Copyright (C) 1999 Wolfgang Scherr - * Copyright (C) 2000 Serguei Miridonov - * - some corrections for Pinnacle Systems Inc. DC10plus card. - * - * Changes by Ronald Bultje - * - moved over to linux>=2.4.x i2c protocol (1/1/2003) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("Philips SAA7110 video decoder driver"); -MODULE_AUTHOR("Pauline Middelink"); -MODULE_LICENSE("GPL"); - - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -#define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */ -#define SAA7110_MAX_OUTPUT 1 /* 1 YUV */ - -#define SAA7110_NR_REG 0x35 - -struct saa7110 { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - u8 reg[SAA7110_NR_REG]; - - v4l2_std_id norm; - int input; - int enable; - - wait_queue_head_t wq; -}; - -static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa7110, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct saa7110, hdl)->sd; -} - -/* ----------------------------------------------------------------------- */ -/* I2C support functions */ -/* ----------------------------------------------------------------------- */ - -static int saa7110_write(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct saa7110 *decoder = to_saa7110(sd); - - decoder->reg[reg] = value; - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int saa7110_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct saa7110 *decoder = to_saa7110(sd); - int ret = -1; - u8 reg = *data; /* first register to write to */ - - /* Sanity check */ - if (reg + (len - 1) > SAA7110_NR_REG) - return ret; - - /* the saa7110 has an autoincrement function, use it if - * the adapter understands raw I2C */ - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - ret = i2c_master_send(client, data, len); - - /* Cache the written data */ - memcpy(decoder->reg + reg, data + 1, len - 1); - } else { - for (++data, --len; len; len--) { - ret = saa7110_write(sd, reg++, *data++); - if (ret < 0) - break; - } - } - - return ret; -} - -static inline int saa7110_read(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_read_byte(client); -} - -/* ----------------------------------------------------------------------- */ -/* SAA7110 functions */ -/* ----------------------------------------------------------------------- */ - -#define FRESP_06H_COMPST 0x03 /*0x13*/ -#define FRESP_06H_SVIDEO 0x83 /*0xC0*/ - - -static int saa7110_selmux(struct v4l2_subdev *sd, int chan) -{ - static const unsigned char modes[9][8] = { - /* mode 0 */ - {FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03, - 0x44, 0x75, 0x16}, - /* mode 1 */ - {FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03, - 0x44, 0x75, 0x16}, - /* mode 2 */ - {FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03, - 0x60, 0xB5, 0x05}, - /* mode 3 */ - {FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03, - 0x60, 0xB5, 0x05}, - /* mode 4 */ - {FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83, - 0x60, 0xB5, 0x03}, - /* mode 5 */ - {FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83, - 0x60, 0xB5, 0x03}, - /* mode 6 */ - {FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3, - 0x44, 0x75, 0x12}, - /* mode 7 */ - {FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13, - 0x60, 0xB5, 0x14}, - /* mode 8 */ - {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23, - 0x44, 0x75, 0x21} - }; - struct saa7110 *decoder = to_saa7110(sd); - const unsigned char *ptr = modes[chan]; - - saa7110_write(sd, 0x06, ptr[0]); /* Luminance control */ - saa7110_write(sd, 0x20, ptr[1]); /* Analog Control #1 */ - saa7110_write(sd, 0x21, ptr[2]); /* Analog Control #2 */ - saa7110_write(sd, 0x22, ptr[3]); /* Mixer Control #1 */ - saa7110_write(sd, 0x2C, ptr[4]); /* Mixer Control #2 */ - saa7110_write(sd, 0x30, ptr[5]); /* ADCs gain control */ - saa7110_write(sd, 0x31, ptr[6]); /* Mixer Control #3 */ - saa7110_write(sd, 0x21, ptr[7]); /* Analog Control #2 */ - decoder->input = chan; - - return 0; -} - -static const unsigned char initseq[1 + SAA7110_NR_REG] = { - 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00, - /* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90, - /* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA, - /* 0x18 */ 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x20 */ 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, - /* 0x28 */ 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C, - /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02 -}; - -static v4l2_std_id determine_norm(struct v4l2_subdev *sd) -{ - DEFINE_WAIT(wait); - struct saa7110 *decoder = to_saa7110(sd); - int status; - - /* mode changed, start automatic detection */ - saa7110_write_block(sd, initseq, sizeof(initseq)); - saa7110_selmux(sd, decoder->input); - prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(250)); - finish_wait(&decoder->wq, &wait); - status = saa7110_read(sd); - if (status & 0x40) { - v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status); - return decoder->norm; /* no change*/ - } - if ((status & 3) == 0) { - saa7110_write(sd, 0x06, 0x83); - if (status & 0x20) { - v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC/no color)\n", status); - /*saa7110_write(sd,0x2E,0x81);*/ - return V4L2_STD_NTSC; - } - v4l2_dbg(1, debug, sd, "status=0x%02x (PAL/no color)\n", status); - /*saa7110_write(sd,0x2E,0x9A);*/ - return V4L2_STD_PAL; - } - /*saa7110_write(sd,0x06,0x03);*/ - if (status & 0x20) { /* 60Hz */ - v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC)\n", status); - saa7110_write(sd, 0x0D, 0x86); - saa7110_write(sd, 0x0F, 0x50); - saa7110_write(sd, 0x11, 0x2C); - /*saa7110_write(sd,0x2E,0x81);*/ - return V4L2_STD_NTSC; - } - - /* 50Hz -> PAL/SECAM */ - saa7110_write(sd, 0x0D, 0x86); - saa7110_write(sd, 0x0F, 0x10); - saa7110_write(sd, 0x11, 0x59); - /*saa7110_write(sd,0x2E,0x9A);*/ - - prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(250)); - finish_wait(&decoder->wq, &wait); - - status = saa7110_read(sd); - if ((status & 0x03) == 0x01) { - v4l2_dbg(1, debug, sd, "status=0x%02x (SECAM)\n", status); - saa7110_write(sd, 0x0D, 0x87); - return V4L2_STD_SECAM; - } - v4l2_dbg(1, debug, sd, "status=0x%02x (PAL)\n", status); - return V4L2_STD_PAL; -} - -static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus) -{ - struct saa7110 *decoder = to_saa7110(sd); - int res = V4L2_IN_ST_NO_SIGNAL; - int status = saa7110_read(sd); - - v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n", - status, (unsigned long long)decoder->norm); - if (!(status & 0x40)) - res = 0; - if (!(status & 0x03)) - res |= V4L2_IN_ST_NO_COLOR; - - *pstatus = res; - return 0; -} - -static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) -{ - *(v4l2_std_id *)std = determine_norm(sd); - return 0; -} - -static int saa7110_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct saa7110 *decoder = to_saa7110(sd); - - if (decoder->norm != std) { - decoder->norm = std; - /*saa7110_write(sd, 0x06, 0x03);*/ - if (std & V4L2_STD_NTSC) { - saa7110_write(sd, 0x0D, 0x86); - saa7110_write(sd, 0x0F, 0x50); - saa7110_write(sd, 0x11, 0x2C); - /*saa7110_write(sd, 0x2E, 0x81);*/ - v4l2_dbg(1, debug, sd, "switched to NTSC\n"); - } else if (std & V4L2_STD_PAL) { - saa7110_write(sd, 0x0D, 0x86); - saa7110_write(sd, 0x0F, 0x10); - saa7110_write(sd, 0x11, 0x59); - /*saa7110_write(sd, 0x2E, 0x9A);*/ - v4l2_dbg(1, debug, sd, "switched to PAL\n"); - } else if (std & V4L2_STD_SECAM) { - saa7110_write(sd, 0x0D, 0x87); - saa7110_write(sd, 0x0F, 0x10); - saa7110_write(sd, 0x11, 0x59); - /*saa7110_write(sd, 0x2E, 0x9A);*/ - v4l2_dbg(1, debug, sd, "switched to SECAM\n"); - } else { - return -EINVAL; - } - } - return 0; -} - -static int saa7110_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct saa7110 *decoder = to_saa7110(sd); - - if (input >= SAA7110_MAX_INPUT) { - v4l2_dbg(1, debug, sd, "input=%d not available\n", input); - return -EINVAL; - } - if (decoder->input != input) { - saa7110_selmux(sd, input); - v4l2_dbg(1, debug, sd, "switched to input=%d\n", input); - } - return 0; -} - -static int saa7110_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct saa7110 *decoder = to_saa7110(sd); - - if (decoder->enable != enable) { - decoder->enable = enable; - saa7110_write(sd, 0x0E, enable ? 0x18 : 0x80); - v4l2_dbg(1, debug, sd, "YUV %s\n", enable ? "on" : "off"); - } - return 0; -} - -static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - saa7110_write(sd, 0x19, ctrl->val); - break; - case V4L2_CID_CONTRAST: - saa7110_write(sd, 0x13, ctrl->val); - break; - case V4L2_CID_SATURATION: - saa7110_write(sd, 0x12, ctrl->val); - break; - case V4L2_CID_HUE: - saa7110_write(sd, 0x07, ctrl->val); - break; - default: - return -EINVAL; - } - return 0; -} - -static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7110, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops saa7110_ctrl_ops = { - .s_ctrl = saa7110_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops saa7110_core_ops = { - .g_chip_ident = saa7110_g_chip_ident, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = saa7110_s_std, -}; - -static const struct v4l2_subdev_video_ops saa7110_video_ops = { - .s_routing = saa7110_s_routing, - .s_stream = saa7110_s_stream, - .querystd = saa7110_querystd, - .g_input_status = saa7110_g_input_status, -}; - -static const struct v4l2_subdev_ops saa7110_ops = { - .core = &saa7110_core_ops, - .video = &saa7110_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int saa7110_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct saa7110 *decoder; - struct v4l2_subdev *sd; - int rv; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - return -ENODEV; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL); - if (!decoder) - return -ENOMEM; - sd = &decoder->sd; - v4l2_i2c_subdev_init(sd, client, &saa7110_ops); - decoder->norm = V4L2_STD_PAL; - decoder->input = 0; - decoder->enable = 1; - v4l2_ctrl_handler_init(&decoder->hdl, 2); - v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, - V4L2_CID_CONTRAST, 0, 127, 1, 64); - v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, - V4L2_CID_SATURATION, 0, 127, 1, 64); - v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - sd->ctrl_handler = &decoder->hdl; - if (decoder->hdl.error) { - int err = decoder->hdl.error; - - v4l2_ctrl_handler_free(&decoder->hdl); - kfree(decoder); - return err; - } - v4l2_ctrl_handler_setup(&decoder->hdl); - - init_waitqueue_head(&decoder->wq); - - rv = saa7110_write_block(sd, initseq, sizeof(initseq)); - if (rv < 0) { - v4l2_dbg(1, debug, sd, "init status %d\n", rv); - } else { - int ver, status; - saa7110_write(sd, 0x21, 0x10); - saa7110_write(sd, 0x0e, 0x18); - saa7110_write(sd, 0x0D, 0x04); - ver = saa7110_read(sd); - saa7110_write(sd, 0x0D, 0x06); - /*mdelay(150);*/ - status = saa7110_read(sd); - v4l2_dbg(1, debug, sd, "version %x, status=0x%02x\n", - ver, status); - saa7110_write(sd, 0x0D, 0x86); - saa7110_write(sd, 0x0F, 0x10); - saa7110_write(sd, 0x11, 0x59); - /*saa7110_write(sd, 0x2E, 0x9A);*/ - } - - /*saa7110_selmux(sd,0);*/ - /*determine_norm(sd);*/ - /* setup and implicit mode 0 select has been performed */ - - return 0; -} - -static int saa7110_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct saa7110 *decoder = to_saa7110(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&decoder->hdl); - kfree(decoder); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id saa7110_id[] = { - { "saa7110", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, saa7110_id); - -static struct i2c_driver saa7110_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "saa7110", - }, - .probe = saa7110_probe, - .remove = saa7110_remove, - .id_table = saa7110_id, -}; - -static __init int init_saa7110(void) -{ - return i2c_add_driver(&saa7110_driver); -} - -static __exit void exit_saa7110(void) -{ - i2c_del_driver(&saa7110_driver); -} - -module_init(init_saa7110); -module_exit(exit_saa7110); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7115.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7115.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7115.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7115.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1719 +0,0 @@ -/* saa711x - Philips SAA711x video decoder driver - * This driver can work with saa7111, saa7111a, saa7113, saa7114, - * saa7115 and saa7118. - * - * Based on saa7114 driver by Maxim Yevtyushkin, which is based on - * the saa7111 driver by Dave Perks. - * - * Copyright (C) 1998 Dave Perks - * Copyright (C) 2002 Maxim Yevtyushkin - * - * Slight changes for video timing and attachment output by - * Wolfgang Scherr - * - * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003) - * by Ronald Bultje - * - * Added saa7115 support by Kevin Thayer - * (2/17/2003) - * - * VBI support (2004) and cleanups (2005) by Hans Verkuil - * - * Copyright (c) 2005-2006 Mauro Carvalho Chehab - * SAA7111, SAA7113 and SAA7118 support - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "saa711x_regs.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VRES_60HZ (480+16) - -MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver"); -MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, " - "Hans Verkuil, Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, bool, 0644); - -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -struct saa711x_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - - struct { - /* chroma gain control cluster */ - struct v4l2_ctrl *agc; - struct v4l2_ctrl *gain; - }; - - v4l2_std_id std; - int input; - int output; - int enable; - int radio; - int width; - int height; - u32 ident; - u32 audclk_freq; - u32 crystal_freq; - u8 ucgc; - u8 cgcdiv; - u8 apll; -}; - -static inline struct saa711x_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa711x_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct saa711x_state, hdl)->sd; -} - -/* ----------------------------------------------------------------------- */ - -static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Sanity routine to check if a register is present */ -static int saa711x_has_reg(const int id, const u8 reg) -{ - if (id == V4L2_IDENT_SAA7111) - return reg < 0x20 && reg != 0x01 && reg != 0x0f && - (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e; - if (id == V4L2_IDENT_SAA7111A) - return reg < 0x20 && reg != 0x01 && reg != 0x0f && - reg != 0x14 && reg != 0x18 && reg != 0x19 && - reg != 0x1d && reg != 0x1e; - - /* common for saa7113/4/5/8 */ - if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f || - reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) || - reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) || - reg == 0x82 || (reg >= 0x89 && reg <= 0x8e))) - return 0; - - switch (id) { - case V4L2_IDENT_SAA7113: - return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) && - reg != 0x5d && reg < 0x63; - case V4L2_IDENT_SAA7114: - return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) && - (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 && - reg != 0x81 && reg < 0xf0; - case V4L2_IDENT_SAA7115: - return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe); - case V4L2_IDENT_SAA7118: - return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) && - (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 && - (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0; - } - return 1; -} - -static int saa711x_writeregs(struct v4l2_subdev *sd, const unsigned char *regs) -{ - struct saa711x_state *state = to_state(sd); - unsigned char reg, data; - - while (*regs != 0x00) { - reg = *(regs++); - data = *(regs++); - - /* According with datasheets, reserved regs should be - filled with 0 - seems better not to touch on they */ - if (saa711x_has_reg(state->ident, reg)) { - if (saa711x_write(sd, reg, data) < 0) - return -1; - } else { - v4l2_dbg(1, debug, sd, "tried to access reserved reg 0x%02x\n", reg); - } - } - return 0; -} - -static inline int saa711x_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_read_byte_data(client, reg); -} - -/* ----------------------------------------------------------------------- */ - -/* SAA7111 initialization table */ -static const unsigned char saa7111_init[] = { - R_01_INC_DELAY, 0x00, /* reserved */ - - /*front end */ - R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */ - R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, - * GAFIX=0, GAI1=256, GAI2=256 */ - R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */ - R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */ - - /* decoder */ - R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz) - * pixels after end of last line */ - R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to - * work with NTSC, too */ - R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0, - * VTRC=1, HPLL=0, VNOI=0 */ - R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0, - * VBLB=0, UPTCV=0, APER=1 */ - R_0A_LUMA_BRIGHT_CNTL, 0x80, - R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */ - R_0C_CHROMA_SAT_CNTL, 0x40, - R_0D_CHROMA_HUE_CNTL, 0x00, - R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, - * FCTC=0, CHBW=1 */ - R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */ - R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */ - R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, - * OEYC=1, OEHV=1, VIPB=0, COLO=0 */ - R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */ - R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */ - R_14_ANAL_ADC_COMPAT_CNTL, 0x00, - R_15_VGATE_START_FID_CHG, 0x00, - R_16_VGATE_STOP, 0x00, - R_17_MISC_VGATE_CONF_AND_MSB, 0x00, - - 0x00, 0x00 -}; - -/* SAA7113 init codes */ -static const unsigned char saa7113_init[] = { - R_01_INC_DELAY, 0x08, - R_02_INPUT_CNTL_1, 0xc2, - R_03_INPUT_CNTL_2, 0x30, - R_04_INPUT_CNTL_3, 0x00, - R_05_INPUT_CNTL_4, 0x00, - R_06_H_SYNC_START, 0x89, - R_07_H_SYNC_STOP, 0x0d, - R_08_SYNC_CNTL, 0x88, - R_09_LUMA_CNTL, 0x01, - R_0A_LUMA_BRIGHT_CNTL, 0x80, - R_0B_LUMA_CONTRAST_CNTL, 0x47, - R_0C_CHROMA_SAT_CNTL, 0x40, - R_0D_CHROMA_HUE_CNTL, 0x00, - R_0E_CHROMA_CNTL_1, 0x01, - R_0F_CHROMA_GAIN_CNTL, 0x2a, - R_10_CHROMA_CNTL_2, 0x08, - R_11_MODE_DELAY_CNTL, 0x0c, - R_12_RT_SIGNAL_CNTL, 0x07, - R_13_RT_X_PORT_OUT_CNTL, 0x00, - R_14_ANAL_ADC_COMPAT_CNTL, 0x00, - R_15_VGATE_START_FID_CHG, 0x00, - R_16_VGATE_STOP, 0x00, - R_17_MISC_VGATE_CONF_AND_MSB, 0x00, - - 0x00, 0x00 -}; - -/* If a value differs from the Hauppauge driver values, then the comment starts with - 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the - Hauppauge driver sets. */ - -/* SAA7114 and SAA7115 initialization table */ -static const unsigned char saa7115_init_auto_input[] = { - /* Front-End Part */ - R_01_INC_DELAY, 0x48, /* white peak control disabled */ - R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */ - R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */ - R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */ - /* Decoder Part */ - R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */ - R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */ - R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */ - R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */ - R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */ - R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */ - R_0D_CHROMA_HUE_CNTL, 0x00, - R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */ - R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */ - R_11_MODE_DELAY_CNTL, 0x00, - R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */ - R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */ - R_14_ANAL_ADC_COMPAT_CNTL, 0x00, - R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */ - R_19_RAW_DATA_OFF_CNTL, 0x80, - R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */ - R_1B_MISC_TVVCRDET, 0x42, /* recommended value */ - R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */ - R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */ - - - R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */ - - /* Power Device Control */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */ - 0x00, 0x00 -}; - -/* Used to reset saa7113, saa7114 and saa7115 */ -static const unsigned char saa7115_cfg_reset_scaler[] = { - R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */ - R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */ - 0x00, 0x00 -}; - -/* ============== SAA7715 VIDEO templates ============= */ - -static const unsigned char saa7115_cfg_60hz_video[] = { - R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ - - R_15_VGATE_START_FID_CHG, 0x03, - R_16_VGATE_STOP, 0x11, - R_17_MISC_VGATE_CONF_AND_MSB, 0x9c, - - R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */ - R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */ - - R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */ - - /* Task A */ - R_90_A_TASK_HANDLING_CNTL, 0x80, - R_91_A_X_PORT_FORMATS_AND_CONF, 0x48, - R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40, - R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84, - - /* hoffset low (input), 0x0002 is minimum */ - R_94_A_HORIZ_INPUT_WINDOW_START, 0x01, - R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00, - - /* hsize low (input), 0x02d0 = 720 */ - R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0, - R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02, - - R_98_A_VERT_INPUT_WINDOW_START, 0x05, - R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00, - - R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c, - R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00, - - R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0, - R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, - - R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c, - R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, - - /* Task B */ - R_C0_B_TASK_HANDLING_CNTL, 0x00, - R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08, - R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00, - R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80, - - /* 0x0002 is minimum */ - R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02, - R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00, - - /* 0x02d0 = 720 */ - R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0, - R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02, - - /* vwindow start 0x12 = 18 */ - R_C8_B_VERT_INPUT_WINDOW_START, 0x12, - R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00, - - /* vwindow length 0xf8 = 248 */ - R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1, - R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9, - - /* hwindow 0x02d0 = 720 */ - R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0, - R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02, - - R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */ - R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */ - R_F5_PULSGEN_LINE_LENGTH, 0xad, - R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01, - - 0x00, 0x00 -}; - -static const unsigned char saa7115_cfg_50hz_video[] = { - R_80_GLOBAL_CNTL_1, 0x00, - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ - - R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */ - R_16_VGATE_STOP, 0x16, - R_17_MISC_VGATE_CONF_AND_MSB, 0x99, - - R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */ - R_0E_CHROMA_CNTL_1, 0x07, - - R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */ - - /* Task A */ - R_90_A_TASK_HANDLING_CNTL, 0x81, - R_91_A_X_PORT_FORMATS_AND_CONF, 0x48, - R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40, - R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84, - - /* This is weird: the datasheet says that you should use 2 as the minimum value, */ - /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */ - /* hoffset low (input), 0x0002 is minimum */ - R_94_A_HORIZ_INPUT_WINDOW_START, 0x00, - R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00, - - /* hsize low (input), 0x02d0 = 720 */ - R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0, - R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02, - - R_98_A_VERT_INPUT_WINDOW_START, 0x03, - R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00, - - /* vsize 0x12 = 18 */ - R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12, - R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00, - - /* hsize 0x05a0 = 1440 */ - R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0, - R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */ - R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */ - R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */ - - /* Task B */ - R_C0_B_TASK_HANDLING_CNTL, 0x00, - R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08, - R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00, - R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80, - - /* This is weird: the datasheet says that you should use 2 as the minimum value, */ - /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */ - /* hoffset low (input), 0x0002 is minimum. See comment above. */ - R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00, - R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00, - - /* hsize 0x02d0 = 720 */ - R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0, - R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02, - - /* voffset 0x16 = 22 */ - R_C8_B_VERT_INPUT_WINDOW_START, 0x16, - R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00, - - /* vsize 0x0120 = 288 */ - R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20, - R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01, - - /* hsize 0x02d0 = 720 */ - R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0, - R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02, - - R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */ - R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */ - R_F5_PULSGEN_LINE_LENGTH, 0xb0, - R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01, - - 0x00, 0x00 -}; - -/* ============== SAA7715 VIDEO templates (end) ======= */ - -static const unsigned char saa7115_cfg_vbi_on[] = { - R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ - R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */ - R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */ - - 0x00, 0x00 -}; - -static const unsigned char saa7115_cfg_vbi_off[] = { - R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ - R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */ - R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */ - - 0x00, 0x00 -}; - - -static const unsigned char saa7115_init_misc[] = { - R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01, - R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01, - R_84_I_PORT_SIGNAL_DEF, 0x20, - R_85_I_PORT_SIGNAL_POLAR, 0x21, - R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5, - R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, - - /* Task A */ - R_A0_A_HORIZ_PRESCALING, 0x01, - R_A1_A_ACCUMULATION_LENGTH, 0x00, - R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00, - - /* Configure controls at nominal value*/ - R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80, - R_A5_A_LUMA_CONTRAST_CNTL, 0x40, - R_A6_A_CHROMA_SATURATION_CNTL, 0x40, - - /* note: 2 x zoom ensures that VBI lines have same length as video lines. */ - R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00, - R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02, - - R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00, - - /* must be horiz lum scaling / 2 */ - R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00, - R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01, - - /* must be offset luma / 2 */ - R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00, - - R_B0_A_VERT_LUMA_SCALING_INC, 0x00, - R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04, - - R_B2_A_VERT_CHROMA_SCALING_INC, 0x00, - R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04, - - R_B4_A_VERT_SCALING_MODE_CNTL, 0x01, - - R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00, - R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00, - R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00, - R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00, - - R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00, - R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00, - R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00, - R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00, - - /* Task B */ - R_D0_B_HORIZ_PRESCALING, 0x01, - R_D1_B_ACCUMULATION_LENGTH, 0x00, - R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00, - - /* Configure controls at nominal value*/ - R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80, - R_D5_B_LUMA_CONTRAST_CNTL, 0x40, - R_D6_B_CHROMA_SATURATION_CNTL, 0x40, - - /* hor lum scaling 0x0400 = 1 */ - R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00, - R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04, - - R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00, - - /* must be hor lum scaling / 2 */ - R_DC_B_HORIZ_CHROMA_SCALING, 0x00, - R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02, - - /* must be offset luma / 2 */ - R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00, - - R_E0_B_VERT_LUMA_SCALING_INC, 0x00, - R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04, - - R_E2_B_VERT_CHROMA_SCALING_INC, 0x00, - R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04, - - R_E4_B_VERT_SCALING_MODE_CNTL, 0x01, - - R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00, - R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00, - R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00, - R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00, - - R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00, - R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00, - R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00, - R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00, - - R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */ - R_F3_PLL_INCREMENT, 0x46, - R_F4_PLL2_STATUS, 0x00, - R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */ - R_F8_PULSE_B_POS, 0x00, - R_F9_PULSE_B_POS_MSB, 0x4b, - R_FA_PULSE_C_POS, 0x00, - R_FB_PULSE_C_POS_MSB, 0x4b, - - /* PLL2 lock detection settings: 71 lines 50% phase error */ - R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88, - - /* Turn off VBI */ - R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */ - R_41_LCR_BASE, 0xff, - R_41_LCR_BASE+1, 0xff, - R_41_LCR_BASE+2, 0xff, - R_41_LCR_BASE+3, 0xff, - R_41_LCR_BASE+4, 0xff, - R_41_LCR_BASE+5, 0xff, - R_41_LCR_BASE+6, 0xff, - R_41_LCR_BASE+7, 0xff, - R_41_LCR_BASE+8, 0xff, - R_41_LCR_BASE+9, 0xff, - R_41_LCR_BASE+10, 0xff, - R_41_LCR_BASE+11, 0xff, - R_41_LCR_BASE+12, 0xff, - R_41_LCR_BASE+13, 0xff, - R_41_LCR_BASE+14, 0xff, - R_41_LCR_BASE+15, 0xff, - R_41_LCR_BASE+16, 0xff, - R_41_LCR_BASE+17, 0xff, - R_41_LCR_BASE+18, 0xff, - R_41_LCR_BASE+19, 0xff, - R_41_LCR_BASE+20, 0xff, - R_41_LCR_BASE+21, 0xff, - R_41_LCR_BASE+22, 0xff, - R_58_PROGRAM_FRAMING_CODE, 0x40, - R_59_H_OFF_FOR_SLICER, 0x47, - R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83, - R_5D_DID, 0xbd, - R_5E_SDID, 0x35, - - R_02_INPUT_CNTL_1, 0xc4, /* input tuner -> input 4, amplifier active */ - - R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */ - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, - R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, - 0x00, 0x00 -}; - -static int saa711x_odd_parity(u8 c) -{ - c ^= (c >> 4); - c ^= (c >> 2); - c ^= (c >> 1); - - return c & 1; -} - -static int saa711x_decode_vps(u8 *dst, u8 *p) -{ - static const u8 biphase_tbl[] = { - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, - 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, - 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, - 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, - 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, - 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, - 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, - 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, - 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, - 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, - 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, - 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, - 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, - 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, - 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, - 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, - 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, - 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, - 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, - 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, - 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, - 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - }; - int i; - u8 c, err = 0; - - for (i = 0; i < 2 * 13; i += 2) { - err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; - c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4); - dst[i / 2] = c; - } - return err & 0xf0; -} - -static int saa711x_decode_wss(u8 *p) -{ - static const int wss_bits[8] = { - 0, 0, 0, 1, 0, 1, 1, 1 - }; - unsigned char parity; - int wss = 0; - int i; - - for (i = 0; i < 16; i++) { - int b1 = wss_bits[p[i] & 7]; - int b2 = wss_bits[(p[i] >> 3) & 7]; - - if (b1 == b2) - return -1; - wss |= b2 << i; - } - parity = wss & 15; - parity ^= parity >> 2; - parity ^= parity >> 1; - - if (!(parity & 1)) - return -1; - - return wss; -} - -static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq) -{ - struct saa711x_state *state = to_state(sd); - u32 acpf; - u32 acni; - u32 hz; - u64 f; - u8 acc = 0; /* reg 0x3a, audio clock control */ - - /* Checks for chips that don't have audio clock (saa7111, saa7113) */ - if (!saa711x_has_reg(state->ident, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD)) - return 0; - - v4l2_dbg(1, debug, sd, "set audio clock freq: %d\n", freq); - - /* sanity check */ - if (freq < 32000 || freq > 48000) - return -EINVAL; - - /* hz is the refresh rate times 100 */ - hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000; - /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */ - acpf = (25600 * freq) / hz; - /* acni = (256 * freq * 2^23) / crystal_frequency = - (freq * 2^(8+23)) / crystal_frequency = - (freq << 31) / crystal_frequency */ - f = freq; - f = f << 31; - do_div(f, state->crystal_freq); - acni = f; - if (state->ucgc) { - acpf = acpf * state->cgcdiv / 16; - acni = acni * state->cgcdiv / 16; - acc = 0x80; - if (state->cgcdiv == 3) - acc |= 0x40; - } - if (state->apll) - acc |= 0x08; - - saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03); - saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10); - saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc); - - saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff); - saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1, - (acpf >> 8) & 0xff); - saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2, - (acpf >> 16) & 0x03); - - saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff); - saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff); - saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f); - state->audclk_freq = freq; - return 0; -} - -static int saa711x_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct saa711x_state *state = to_state(sd); - - switch (ctrl->id) { - case V4L2_CID_CHROMA_AGC: - /* chroma gain cluster */ - if (state->agc->cur.val) - state->gain->cur.val = - saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f; - break; - } - return 0; -} - -static int saa711x_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct saa711x_state *state = to_state(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, ctrl->val); - break; - - case V4L2_CID_CONTRAST: - saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, ctrl->val); - break; - - case V4L2_CID_SATURATION: - saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, ctrl->val); - break; - - case V4L2_CID_HUE: - saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, ctrl->val); - break; - - case V4L2_CID_CHROMA_AGC: - /* chroma gain cluster */ - if (state->agc->val) - saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val); - else - saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val | 0x80); - v4l2_ctrl_activate(state->gain, !state->agc->val); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int saa711x_set_size(struct v4l2_subdev *sd, int width, int height) -{ - struct saa711x_state *state = to_state(sd); - int HPSC, HFSC; - int VSCY; - int res; - int is_50hz = state->std & V4L2_STD_625_50; - int Vsrc = is_50hz ? 576 : 480; - - v4l2_dbg(1, debug, sd, "decoder set size to %ix%i\n", width, height); - - /* FIXME need better bounds checking here */ - if ((width < 1) || (width > 1440)) - return -EINVAL; - if ((height < 1) || (height > Vsrc)) - return -EINVAL; - - if (!saa711x_has_reg(state->ident, R_D0_B_HORIZ_PRESCALING)) { - /* Decoder only supports 720 columns and 480 or 576 lines */ - if (width != 720) - return -EINVAL; - if (height != Vsrc) - return -EINVAL; - } - - state->width = width; - state->height = height; - - if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH)) - return 0; - - /* probably have a valid size, let's set it */ - /* Set output width/height */ - /* width */ - - saa711x_write(sd, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, - (u8) (width & 0xff)); - saa711x_write(sd, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, - (u8) ((width >> 8) & 0xff)); - - /* Vertical Scaling uses height/2 */ - res = height / 2; - - /* On 60Hz, it is using a higher Vertical Output Size */ - if (!is_50hz) - res += (VRES_60HZ - 480) >> 1; - - /* height */ - saa711x_write(sd, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, - (u8) (res & 0xff)); - saa711x_write(sd, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, - (u8) ((res >> 8) & 0xff)); - - /* Scaling settings */ - /* Hprescaler is floor(inres/outres) */ - HPSC = (int)(720 / width); - /* 0 is not allowed (div. by zero) */ - HPSC = HPSC ? HPSC : 1; - HFSC = (int)((1024 * 720) / (HPSC * width)); - /* FIXME hardcodes to "Task B" - * write H prescaler integer */ - saa711x_write(sd, R_D0_B_HORIZ_PRESCALING, - (u8) (HPSC & 0x3f)); - - v4l2_dbg(1, debug, sd, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC); - /* write H fine-scaling (luminance) */ - saa711x_write(sd, R_D8_B_HORIZ_LUMA_SCALING_INC, - (u8) (HFSC & 0xff)); - saa711x_write(sd, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, - (u8) ((HFSC >> 8) & 0xff)); - /* write H fine-scaling (chrominance) - * must be lum/2, so i'll just bitshift :) */ - saa711x_write(sd, R_DC_B_HORIZ_CHROMA_SCALING, - (u8) ((HFSC >> 1) & 0xff)); - saa711x_write(sd, R_DD_B_HORIZ_CHROMA_SCALING_MSB, - (u8) ((HFSC >> 9) & 0xff)); - - VSCY = (int)((1024 * Vsrc) / height); - v4l2_dbg(1, debug, sd, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY); - - /* Correct Contrast and Luminance */ - saa711x_write(sd, R_D5_B_LUMA_CONTRAST_CNTL, - (u8) (64 * 1024 / VSCY)); - saa711x_write(sd, R_D6_B_CHROMA_SATURATION_CNTL, - (u8) (64 * 1024 / VSCY)); - - /* write V fine-scaling (luminance) */ - saa711x_write(sd, R_E0_B_VERT_LUMA_SCALING_INC, - (u8) (VSCY & 0xff)); - saa711x_write(sd, R_E1_B_VERT_LUMA_SCALING_INC_MSB, - (u8) ((VSCY >> 8) & 0xff)); - /* write V fine-scaling (chrominance) */ - saa711x_write(sd, R_E2_B_VERT_CHROMA_SCALING_INC, - (u8) (VSCY & 0xff)); - saa711x_write(sd, R_E3_B_VERT_CHROMA_SCALING_INC_MSB, - (u8) ((VSCY >> 8) & 0xff)); - - saa711x_writeregs(sd, saa7115_cfg_reset_scaler); - - /* Activates task "B" */ - saa711x_write(sd, R_80_GLOBAL_CNTL_1, - saa711x_read(sd, R_80_GLOBAL_CNTL_1) | 0x20); - - return 0; -} - -static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct saa711x_state *state = to_state(sd); - - /* Prevent unnecessary standard changes. During a standard - change the I-Port is temporarily disabled. Any devices - reading from that port can get confused. - Note that s_std is also used to switch from - radio to TV mode, so if a s_std is broadcast to - all I2C devices then you do not want to have an unwanted - side-effect here. */ - if (std == state->std) - return; - - state->std = std; - - // This works for NTSC-M, SECAM-L and the 50Hz PAL variants. - if (std & V4L2_STD_525_60) { - v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n"); - saa711x_writeregs(sd, saa7115_cfg_60hz_video); - saa711x_set_size(sd, 720, 480); - } else { - v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n"); - saa711x_writeregs(sd, saa7115_cfg_50hz_video); - saa711x_set_size(sd, 720, 576); - } - - /* Register 0E - Bits D6-D4 on NO-AUTO mode - (SAA7111 and SAA7113 doesn't have auto mode) - 50 Hz / 625 lines 60 Hz / 525 lines - 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz) - 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz) - 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz) - 011 NTSC N (3.58MHz) PAL M (3.58MHz) - 100 reserved NTSC-Japan (3.58MHz) - */ - if (state->ident <= V4L2_IDENT_SAA7113) { - u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f; - - if (std == V4L2_STD_PAL_M) { - reg |= 0x30; - } else if (std == V4L2_STD_PAL_Nc) { - reg |= 0x20; - } else if (std == V4L2_STD_PAL_60) { - reg |= 0x10; - } else if (std == V4L2_STD_NTSC_M_JP) { - reg |= 0x40; - } else if (std & V4L2_STD_SECAM) { - reg |= 0x50; - } - saa711x_write(sd, R_0E_CHROMA_CNTL_1, reg); - } else { - /* restart task B if needed */ - int taskb = saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10; - - if (taskb && state->ident == V4L2_IDENT_SAA7114) { - saa711x_writeregs(sd, saa7115_cfg_vbi_on); - } - - /* switch audio mode too! */ - saa711x_s_clock_freq(sd, state->audclk_freq); - } -} - -/* setup the sliced VBI lcr registers according to the sliced VBI format */ -static void saa711x_set_lcr(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt) -{ - struct saa711x_state *state = to_state(sd); - int is_50hz = (state->std & V4L2_STD_625_50); - u8 lcr[24]; - int i, x; - -#if 1 - /* saa7113/7114/7118 VBI support are experimental */ - if (!saa711x_has_reg(state->ident, R_41_LCR_BASE)) - return; - -#else - /* SAA7113 and SAA7118 also should support VBI - Need testing */ - if (state->ident != V4L2_IDENT_SAA7115) - return; -#endif - - for (i = 0; i <= 23; i++) - lcr[i] = 0xff; - - if (fmt == NULL) { - /* raw VBI */ - if (is_50hz) - for (i = 6; i <= 23; i++) - lcr[i] = 0xdd; - else - for (i = 10; i <= 21; i++) - lcr[i] = 0xdd; - } else { - /* sliced VBI */ - /* first clear lines that cannot be captured */ - if (is_50hz) { - for (i = 0; i <= 5; i++) - fmt->service_lines[0][i] = - fmt->service_lines[1][i] = 0; - } - else { - for (i = 0; i <= 9; i++) - fmt->service_lines[0][i] = - fmt->service_lines[1][i] = 0; - for (i = 22; i <= 23; i++) - fmt->service_lines[0][i] = - fmt->service_lines[1][i] = 0; - } - - /* Now set the lcr values according to the specified service */ - for (i = 6; i <= 23; i++) { - lcr[i] = 0; - for (x = 0; x <= 1; x++) { - switch (fmt->service_lines[1-x][i]) { - case 0: - lcr[i] |= 0xf << (4 * x); - break; - case V4L2_SLICED_TELETEXT_B: - lcr[i] |= 1 << (4 * x); - break; - case V4L2_SLICED_CAPTION_525: - lcr[i] |= 4 << (4 * x); - break; - case V4L2_SLICED_WSS_625: - lcr[i] |= 5 << (4 * x); - break; - case V4L2_SLICED_VPS: - lcr[i] |= 7 << (4 * x); - break; - } - } - } - } - - /* write the lcr registers */ - for (i = 2; i <= 23; i++) { - saa711x_write(sd, i - 2 + R_41_LCR_BASE, lcr[i]); - } - - /* enable/disable raw VBI capturing */ - saa711x_writeregs(sd, fmt == NULL ? - saa7115_cfg_vbi_on : - saa7115_cfg_vbi_off); -} - -static int saa711x_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *sliced) -{ - static u16 lcr2vbi[] = { - 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ - 0, V4L2_SLICED_CAPTION_525, /* 4 */ - V4L2_SLICED_WSS_625, 0, /* 5 */ - V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */ - 0, 0, 0, 0 - }; - int i; - - memset(sliced, 0, sizeof(*sliced)); - /* done if using raw VBI */ - if (saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10) - return 0; - for (i = 2; i <= 23; i++) { - u8 v = saa711x_read(sd, i - 2 + R_41_LCR_BASE); - - sliced->service_lines[0][i] = lcr2vbi[v >> 4]; - sliced->service_lines[1][i] = lcr2vbi[v & 0xf]; - sliced->service_set |= - sliced->service_lines[0][i] | sliced->service_lines[1][i]; - } - return 0; -} - -static int saa711x_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) -{ - saa711x_set_lcr(sd, NULL); - return 0; -} - -static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt) -{ - saa711x_set_lcr(sd, fmt); - return 0; -} - -static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) -{ - if (fmt->code != V4L2_MBUS_FMT_FIXED) - return -EINVAL; - fmt->field = V4L2_FIELD_INTERLACED; - fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - return saa711x_set_size(sd, fmt->width, fmt->height); -} - -/* Decode the sliced VBI data stream as created by the saa7115. - The format is described in the saa7115 datasheet in Tables 25 and 26 - and in Figure 33. - The current implementation uses SAV/EAV codes and not the ancillary data - headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV - code. */ -static int saa711x_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi) -{ - struct saa711x_state *state = to_state(sd); - static const char vbi_no_data_pattern[] = { - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0 - }; - u8 *p = vbi->p; - u32 wss; - int id1, id2; /* the ID1 and ID2 bytes from the internal header */ - - vbi->type = 0; /* mark result as a failure */ - id1 = p[2]; - id2 = p[3]; - /* Note: the field bit is inverted for 60 Hz video */ - if (state->std & V4L2_STD_525_60) - id1 ^= 0x40; - - /* Skip internal header, p now points to the start of the payload */ - p += 4; - vbi->p = p; - - /* calculate field and line number of the VBI packet (1-23) */ - vbi->is_second_field = ((id1 & 0x40) != 0); - vbi->line = (id1 & 0x3f) << 3; - vbi->line |= (id2 & 0x70) >> 4; - - /* Obtain data type */ - id2 &= 0xf; - - /* If the VBI slicer does not detect any signal it will fill up - the payload buffer with 0xa0 bytes. */ - if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern))) - return 0; - - /* decode payloads */ - switch (id2) { - case 1: - vbi->type = V4L2_SLICED_TELETEXT_B; - break; - case 4: - if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1])) - return 0; - vbi->type = V4L2_SLICED_CAPTION_525; - break; - case 5: - wss = saa711x_decode_wss(p); - if (wss == -1) - return 0; - p[0] = wss & 0xff; - p[1] = wss >> 8; - vbi->type = V4L2_SLICED_WSS_625; - break; - case 7: - if (saa711x_decode_vps(p, p) != 0) - return 0; - vbi->type = V4L2_SLICED_VPS; - break; - default: - break; - } - return 0; -} - -/* ============ SAA7115 AUDIO settings (end) ============= */ - -static int saa711x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct saa711x_state *state = to_state(sd); - int status; - - if (state->radio) - return 0; - status = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC); - - v4l2_dbg(1, debug, sd, "status: 0x%02x\n", status); - vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0; - return 0; -} - -static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct saa711x_state *state = to_state(sd); - - state->radio = 0; - saa711x_set_v4lstd(sd, std); - return 0; -} - -static int saa711x_s_radio(struct v4l2_subdev *sd) -{ - struct saa711x_state *state = to_state(sd); - - state->radio = 1; - return 0; -} - -static int saa711x_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct saa711x_state *state = to_state(sd); - u8 mask = (state->ident <= V4L2_IDENT_SAA7111A) ? 0xf8 : 0xf0; - - v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n", - input, output); - - /* saa7111/3 does not have these inputs */ - if (state->ident <= V4L2_IDENT_SAA7113 && - (input == SAA7115_COMPOSITE4 || - input == SAA7115_COMPOSITE5)) { - return -EINVAL; - } - if (input > SAA7115_SVIDEO3) - return -EINVAL; - if (state->input == input && state->output == output) - return 0; - v4l2_dbg(1, debug, sd, "now setting %s input %s output\n", - (input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", - (output == SAA7115_IPORT_ON) ? "iport on" : "iport off"); - state->input = input; - - /* saa7111 has slightly different input numbering */ - if (state->ident <= V4L2_IDENT_SAA7111A) { - if (input >= SAA7115_COMPOSITE4) - input -= 2; - /* saa7111 specific */ - saa711x_write(sd, R_10_CHROMA_CNTL_2, - (saa711x_read(sd, R_10_CHROMA_CNTL_2) & 0x3f) | - ((output & 0xc0) ^ 0x40)); - saa711x_write(sd, R_13_RT_X_PORT_OUT_CNTL, - (saa711x_read(sd, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) | - ((output & 2) ? 0x0a : 0)); - } - - /* select mode */ - saa711x_write(sd, R_02_INPUT_CNTL_1, - (saa711x_read(sd, R_02_INPUT_CNTL_1) & mask) | - input); - - /* bypass chrominance trap for S-Video modes */ - saa711x_write(sd, R_09_LUMA_CNTL, - (saa711x_read(sd, R_09_LUMA_CNTL) & 0x7f) | - (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0)); - - state->output = output; - if (state->ident == V4L2_IDENT_SAA7114 || - state->ident == V4L2_IDENT_SAA7115) { - saa711x_write(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK, - (saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) | - (state->output & 0x01)); - } - return 0; -} - -static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val) -{ - struct saa711x_state *state = to_state(sd); - - if (state->ident > V4L2_IDENT_SAA7111A) - return -EINVAL; - saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) | - (val ? 0x80 : 0)); - return 0; -} - -static int saa711x_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct saa711x_state *state = to_state(sd); - - v4l2_dbg(1, debug, sd, "%s output\n", - enable ? "enable" : "disable"); - - if (state->enable == enable) - return 0; - state->enable = enable; - if (!saa711x_has_reg(state->ident, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED)) - return 0; - saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, state->enable); - return 0; -} - -static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, u32 freq, u32 flags) -{ - struct saa711x_state *state = to_state(sd); - - if (freq != SAA7115_FREQ_32_11_MHZ && freq != SAA7115_FREQ_24_576_MHZ) - return -EINVAL; - state->crystal_freq = freq; - state->cgcdiv = (flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4; - state->ucgc = (flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0; - state->apll = (flags & SAA7115_FREQ_FL_APLL) ? 1 : 0; - saa711x_s_clock_freq(sd, state->audclk_freq); - return 0; -} - -static int saa711x_reset(struct v4l2_subdev *sd, u32 val) -{ - v4l2_dbg(1, debug, sd, "decoder RESET\n"); - saa711x_writeregs(sd, saa7115_cfg_reset_scaler); - return 0; -} - -static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *data) -{ - /* Note: the internal field ID is inverted for NTSC, - so data->field 0 maps to the saa7115 even field, - whereas for PAL it maps to the saa7115 odd field. */ - switch (data->id) { - case V4L2_SLICED_WSS_625: - if (saa711x_read(sd, 0x6b) & 0xc0) - return -EIO; - data->data[0] = saa711x_read(sd, 0x6c); - data->data[1] = saa711x_read(sd, 0x6d); - return 0; - case V4L2_SLICED_CAPTION_525: - if (data->field == 0) { - /* CC */ - if (saa711x_read(sd, 0x66) & 0x30) - return -EIO; - data->data[0] = saa711x_read(sd, 0x69); - data->data[1] = saa711x_read(sd, 0x6a); - return 0; - } - /* XDS */ - if (saa711x_read(sd, 0x66) & 0xc0) - return -EIO; - data->data[0] = saa711x_read(sd, 0x67); - data->data[1] = saa711x_read(sd, 0x68); - return 0; - default: - return -EINVAL; - } -} - -static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) -{ - struct saa711x_state *state = to_state(sd); - int reg1e; - - *std = V4L2_STD_ALL; - if (state->ident != V4L2_IDENT_SAA7115) { - int reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC); - - if (reg1f & 0x20) - *std = V4L2_STD_525_60; - else - *std = V4L2_STD_625_50; - - return 0; - } - - reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC); - - switch (reg1e & 0x03) { - case 1: - *std = V4L2_STD_NTSC; - break; - case 2: - *std = V4L2_STD_PAL; - break; - case 3: - *std = V4L2_STD_SECAM; - break; - default: - break; - } - return 0; -} - -static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status) -{ - struct saa711x_state *state = to_state(sd); - int reg1e = 0x80; - int reg1f; - - *status = V4L2_IN_ST_NO_SIGNAL; - if (state->ident == V4L2_IDENT_SAA7115) - reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC); - reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC); - if ((reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80) - *status = 0; - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->val = saa711x_read(sd, reg->reg & 0xff); - reg->size = 1; - return 0; -} - -static int saa711x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - saa711x_write(sd, reg->reg & 0xff, reg->val & 0xff); - return 0; -} -#endif - -static int saa711x_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct saa711x_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0); -} - -static int saa711x_log_status(struct v4l2_subdev *sd) -{ - struct saa711x_state *state = to_state(sd); - int reg1e, reg1f; - int signalOk; - int vcr; - - v4l2_info(sd, "Audio frequency: %d Hz\n", state->audclk_freq); - if (state->ident != V4L2_IDENT_SAA7115) { - /* status for the saa7114 */ - reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC); - signalOk = (reg1f & 0xc1) == 0x81; - v4l2_info(sd, "Video signal: %s\n", signalOk ? "ok" : "bad"); - v4l2_info(sd, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); - return 0; - } - - /* status for the saa7115 */ - reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC); - reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC); - - signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80; - vcr = !(reg1f & 0x10); - - if (state->input >= 6) - v4l2_info(sd, "Input: S-Video %d\n", state->input - 6); - else - v4l2_info(sd, "Input: Composite %d\n", state->input); - v4l2_info(sd, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad"); - v4l2_info(sd, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); - - switch (reg1e & 0x03) { - case 1: - v4l2_info(sd, "Detected format: NTSC\n"); - break; - case 2: - v4l2_info(sd, "Detected format: PAL\n"); - break; - case 3: - v4l2_info(sd, "Detected format: SECAM\n"); - break; - default: - v4l2_info(sd, "Detected format: BW/No color\n"); - break; - } - v4l2_info(sd, "Width, Height: %d, %d\n", state->width, state->height); - v4l2_ctrl_handler_log_status(&state->hdl, sd->name); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops saa711x_ctrl_ops = { - .s_ctrl = saa711x_s_ctrl, - .g_volatile_ctrl = saa711x_g_volatile_ctrl, -}; - -static const struct v4l2_subdev_core_ops saa711x_core_ops = { - .log_status = saa711x_log_status, - .g_chip_ident = saa711x_g_chip_ident, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = saa711x_s_std, - .reset = saa711x_reset, - .s_gpio = saa711x_s_gpio, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = saa711x_g_register, - .s_register = saa711x_s_register, -#endif -}; - -static const struct v4l2_subdev_tuner_ops saa711x_tuner_ops = { - .s_radio = saa711x_s_radio, - .g_tuner = saa711x_g_tuner, -}; - -static const struct v4l2_subdev_audio_ops saa711x_audio_ops = { - .s_clock_freq = saa711x_s_clock_freq, -}; - -static const struct v4l2_subdev_video_ops saa711x_video_ops = { - .s_routing = saa711x_s_routing, - .s_crystal_freq = saa711x_s_crystal_freq, - .s_mbus_fmt = saa711x_s_mbus_fmt, - .s_stream = saa711x_s_stream, - .querystd = saa711x_querystd, - .g_input_status = saa711x_g_input_status, -}; - -static const struct v4l2_subdev_vbi_ops saa711x_vbi_ops = { - .g_vbi_data = saa711x_g_vbi_data, - .decode_vbi_line = saa711x_decode_vbi_line, - .g_sliced_fmt = saa711x_g_sliced_fmt, - .s_sliced_fmt = saa711x_s_sliced_fmt, - .s_raw_fmt = saa711x_s_raw_fmt, -}; - -static const struct v4l2_subdev_ops saa711x_ops = { - .core = &saa711x_core_ops, - .tuner = &saa711x_tuner_ops, - .audio = &saa711x_audio_ops, - .video = &saa711x_video_ops, - .vbi = &saa711x_vbi_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int saa711x_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct saa711x_state *state; - struct v4l2_subdev *sd; - struct v4l2_ctrl_handler *hdl; - int i; - char name[17]; - char chip_id; - int autodetect = !id || id->driver_data == 1; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - for (i = 0; i < 0x0f; i++) { - i2c_smbus_write_byte_data(client, 0, i); - name[i] = (i2c_smbus_read_byte_data(client, 0) & 0x0f) + '0'; - if (name[i] > '9') - name[i] += 'a' - '9' - 1; - } - name[i] = '\0'; - - chip_id = name[5]; - - /* Check whether this chip is part of the saa711x series */ - if (memcmp(name + 1, "f711", 4)) { - v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", - client->addr << 1, name); - return -ENODEV; - } - - /* Safety check */ - if (!autodetect && id->name[6] != chip_id) { - v4l_warn(client, "found saa711%c while %s was expected\n", - chip_id, id->name); - } - snprintf(client->name, sizeof(client->name), "saa711%c", chip_id); - v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name, - client->addr << 1, client->adapter->name); - - state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &saa711x_ops); - - hdl = &state->hdl; - v4l2_ctrl_handler_init(hdl, 6); - /* add in ascending ID order */ - v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, - V4L2_CID_CONTRAST, 0, 127, 1, 64); - v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, - V4L2_CID_SATURATION, 0, 127, 1, 64); - v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - state->agc = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, - V4L2_CID_CHROMA_AGC, 0, 1, 1, 1); - state->gain = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, - V4L2_CID_CHROMA_GAIN, 0, 127, 1, 40); - state->gain->is_volatile = 1; - sd->ctrl_handler = hdl; - if (hdl->error) { - int err = hdl->error; - - v4l2_ctrl_handler_free(hdl); - kfree(state); - return err; - } - state->agc->flags |= V4L2_CTRL_FLAG_UPDATE; - v4l2_ctrl_cluster(2, &state->agc); - - state->input = -1; - state->output = SAA7115_IPORT_ON; - state->enable = 1; - state->radio = 0; - switch (chip_id) { - case '1': - state->ident = V4L2_IDENT_SAA7111; - if (saa711x_read(sd, R_00_CHIP_VERSION) & 0xf0) { - v4l_info(client, "saa7111a variant found\n"); - state->ident = V4L2_IDENT_SAA7111A; - } - break; - case '3': - state->ident = V4L2_IDENT_SAA7113; - break; - case '4': - state->ident = V4L2_IDENT_SAA7114; - break; - case '5': - state->ident = V4L2_IDENT_SAA7115; - break; - case '8': - state->ident = V4L2_IDENT_SAA7118; - break; - default: - state->ident = V4L2_IDENT_SAA7111; - v4l2_info(sd, "WARNING: Chip is not known - Falling back to saa7111\n"); - break; - } - - state->audclk_freq = 48000; - - v4l2_dbg(1, debug, sd, "writing init values\n"); - - /* init to 60hz/48khz */ - state->crystal_freq = SAA7115_FREQ_24_576_MHZ; - switch (state->ident) { - case V4L2_IDENT_SAA7111: - case V4L2_IDENT_SAA7111A: - saa711x_writeregs(sd, saa7111_init); - break; - case V4L2_IDENT_SAA7113: - saa711x_writeregs(sd, saa7113_init); - break; - default: - state->crystal_freq = SAA7115_FREQ_32_11_MHZ; - saa711x_writeregs(sd, saa7115_init_auto_input); - } - if (state->ident > V4L2_IDENT_SAA7111A) - saa711x_writeregs(sd, saa7115_init_misc); - saa711x_set_v4lstd(sd, V4L2_STD_NTSC); - v4l2_ctrl_handler_setup(hdl); - - v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n", - saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC), - saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa711x_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(sd->ctrl_handler); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id saa711x_id[] = { - { "saa7115_auto", 1 }, /* autodetect */ - { "saa7111", 0 }, - { "saa7113", 0 }, - { "saa7114", 0 }, - { "saa7115", 0 }, - { "saa7118", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, saa711x_id); - -static struct i2c_driver saa711x_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "saa7115", - }, - .probe = saa711x_probe, - .remove = saa711x_remove, - .id_table = saa711x_id, -}; - -static __init int init_saa711x(void) -{ - return i2c_add_driver(&saa711x_driver); -} - -static __exit void exit_saa711x(void) -{ - i2c_del_driver(&saa711x_driver); -} - -module_init(init_saa711x); -module_exit(exit_saa711x); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa711x_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa711x_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa711x_regs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa711x_regs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,549 +0,0 @@ -/* saa711x - Philips SAA711x video decoder register specifications - * - * Copyright (c) 2006 Mauro Carvalho Chehab - * - * 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, or (at your option) any later version. - * - * 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. - */ - -#define R_00_CHIP_VERSION 0x00 -/* Video Decoder */ - /* Video Decoder - Frontend part */ -#define R_01_INC_DELAY 0x01 -#define R_02_INPUT_CNTL_1 0x02 -#define R_03_INPUT_CNTL_2 0x03 -#define R_04_INPUT_CNTL_3 0x04 -#define R_05_INPUT_CNTL_4 0x05 - /* Video Decoder - Decoder part */ -#define R_06_H_SYNC_START 0x06 -#define R_07_H_SYNC_STOP 0x07 -#define R_08_SYNC_CNTL 0x08 -#define R_09_LUMA_CNTL 0x09 -#define R_0A_LUMA_BRIGHT_CNTL 0x0a -#define R_0B_LUMA_CONTRAST_CNTL 0x0b -#define R_0C_CHROMA_SAT_CNTL 0x0c -#define R_0D_CHROMA_HUE_CNTL 0x0d -#define R_0E_CHROMA_CNTL_1 0x0e -#define R_0F_CHROMA_GAIN_CNTL 0x0f -#define R_10_CHROMA_CNTL_2 0x10 -#define R_11_MODE_DELAY_CNTL 0x11 -#define R_12_RT_SIGNAL_CNTL 0x12 -#define R_13_RT_X_PORT_OUT_CNTL 0x13 -#define R_14_ANAL_ADC_COMPAT_CNTL 0x14 -#define R_15_VGATE_START_FID_CHG 0x15 -#define R_16_VGATE_STOP 0x16 -#define R_17_MISC_VGATE_CONF_AND_MSB 0x17 -#define R_18_RAW_DATA_GAIN_CNTL 0x18 -#define R_19_RAW_DATA_OFF_CNTL 0x19 -#define R_1A_COLOR_KILL_LVL_CNTL 0x1a -#define R_1B_MISC_TVVCRDET 0x1b -#define R_1C_ENHAN_COMB_CTRL1 0x1c -#define R_1D_ENHAN_COMB_CTRL2 0x1d -#define R_1E_STATUS_BYTE_1_VD_DEC 0x1e -#define R_1F_STATUS_BYTE_2_VD_DEC 0x1f - -/* Component processing and interrupt masking part */ -#define R_23_INPUT_CNTL_5 0x23 -#define R_24_INPUT_CNTL_6 0x24 -#define R_25_INPUT_CNTL_7 0x25 -#define R_29_COMP_DELAY 0x29 -#define R_2A_COMP_BRIGHT_CNTL 0x2a -#define R_2B_COMP_CONTRAST_CNTL 0x2b -#define R_2C_COMP_SAT_CNTL 0x2c -#define R_2D_INTERRUPT_MASK_1 0x2d -#define R_2E_INTERRUPT_MASK_2 0x2e -#define R_2F_INTERRUPT_MASK_3 0x2f - -/* Audio clock generator part */ -#define R_30_AUD_MAST_CLK_CYCLES_PER_FIELD 0x30 -#define R_34_AUD_MAST_CLK_NOMINAL_INC 0x34 -#define R_38_CLK_RATIO_AMXCLK_TO_ASCLK 0x38 -#define R_39_CLK_RATIO_ASCLK_TO_ALRCLK 0x39 -#define R_3A_AUD_CLK_GEN_BASIC_SETUP 0x3a - -/* General purpose VBI data slicer part */ -#define R_40_SLICER_CNTL_1 0x40 -#define R_41_LCR_BASE 0x41 -#define R_58_PROGRAM_FRAMING_CODE 0x58 -#define R_59_H_OFF_FOR_SLICER 0x59 -#define R_5A_V_OFF_FOR_SLICER 0x5a -#define R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF 0x5b -#define R_5D_DID 0x5d -#define R_5E_SDID 0x5e -#define R_60_SLICER_STATUS_BYTE_0 0x60 -#define R_61_SLICER_STATUS_BYTE_1 0x61 -#define R_62_SLICER_STATUS_BYTE_2 0x62 - -/* X port, I port and the scaler part */ - /* Task independent global settings */ -#define R_80_GLOBAL_CNTL_1 0x80 -#define R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F 0x81 -#define R_83_X_PORT_I_O_ENA_AND_OUT_CLK 0x83 -#define R_84_I_PORT_SIGNAL_DEF 0x84 -#define R_85_I_PORT_SIGNAL_POLAR 0x85 -#define R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT 0x86 -#define R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED 0x87 -#define R_88_POWER_SAVE_ADC_PORT_CNTL 0x88 -#define R_8F_STATUS_INFO_SCALER 0x8f - /* Task A definition */ - /* Basic settings and acquisition window definition */ -#define R_90_A_TASK_HANDLING_CNTL 0x90 -#define R_91_A_X_PORT_FORMATS_AND_CONF 0x91 -#define R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL 0x92 -#define R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF 0x93 -#define R_94_A_HORIZ_INPUT_WINDOW_START 0x94 -#define R_95_A_HORIZ_INPUT_WINDOW_START_MSB 0x95 -#define R_96_A_HORIZ_INPUT_WINDOW_LENGTH 0x96 -#define R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB 0x97 -#define R_98_A_VERT_INPUT_WINDOW_START 0x98 -#define R_99_A_VERT_INPUT_WINDOW_START_MSB 0x99 -#define R_9A_A_VERT_INPUT_WINDOW_LENGTH 0x9a -#define R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB 0x9b -#define R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH 0x9c -#define R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB 0x9d -#define R_9E_A_VERT_OUTPUT_WINDOW_LENGTH 0x9e -#define R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB 0x9f - /* FIR filtering and prescaling */ -#define R_A0_A_HORIZ_PRESCALING 0xa0 -#define R_A1_A_ACCUMULATION_LENGTH 0xa1 -#define R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER 0xa2 -#define R_A4_A_LUMA_BRIGHTNESS_CNTL 0xa4 -#define R_A5_A_LUMA_CONTRAST_CNTL 0xa5 -#define R_A6_A_CHROMA_SATURATION_CNTL 0xa6 - /* Horizontal phase scaling */ -#define R_A8_A_HORIZ_LUMA_SCALING_INC 0xa8 -#define R_A9_A_HORIZ_LUMA_SCALING_INC_MSB 0xa9 -#define R_AA_A_HORIZ_LUMA_PHASE_OFF 0xaa -#define R_AC_A_HORIZ_CHROMA_SCALING_INC 0xac -#define R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB 0xad -#define R_AE_A_HORIZ_CHROMA_PHASE_OFF 0xae -#define R_AF_A_HORIZ_CHROMA_PHASE_OFF_MSB 0xaf - /* Vertical scaling */ -#define R_B0_A_VERT_LUMA_SCALING_INC 0xb0 -#define R_B1_A_VERT_LUMA_SCALING_INC_MSB 0xb1 -#define R_B2_A_VERT_CHROMA_SCALING_INC 0xb2 -#define R_B3_A_VERT_CHROMA_SCALING_INC_MSB 0xb3 -#define R_B4_A_VERT_SCALING_MODE_CNTL 0xb4 -#define R_B8_A_VERT_CHROMA_PHASE_OFF_00 0xb8 -#define R_B9_A_VERT_CHROMA_PHASE_OFF_01 0xb9 -#define R_BA_A_VERT_CHROMA_PHASE_OFF_10 0xba -#define R_BB_A_VERT_CHROMA_PHASE_OFF_11 0xbb -#define R_BC_A_VERT_LUMA_PHASE_OFF_00 0xbc -#define R_BD_A_VERT_LUMA_PHASE_OFF_01 0xbd -#define R_BE_A_VERT_LUMA_PHASE_OFF_10 0xbe -#define R_BF_A_VERT_LUMA_PHASE_OFF_11 0xbf - /* Task B definition */ - /* Basic settings and acquisition window definition */ -#define R_C0_B_TASK_HANDLING_CNTL 0xc0 -#define R_C1_B_X_PORT_FORMATS_AND_CONF 0xc1 -#define R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION 0xc2 -#define R_C3_B_I_PORT_FORMATS_AND_CONF 0xc3 -#define R_C4_B_HORIZ_INPUT_WINDOW_START 0xc4 -#define R_C5_B_HORIZ_INPUT_WINDOW_START_MSB 0xc5 -#define R_C6_B_HORIZ_INPUT_WINDOW_LENGTH 0xc6 -#define R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB 0xc7 -#define R_C8_B_VERT_INPUT_WINDOW_START 0xc8 -#define R_C9_B_VERT_INPUT_WINDOW_START_MSB 0xc9 -#define R_CA_B_VERT_INPUT_WINDOW_LENGTH 0xca -#define R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB 0xcb -#define R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH 0xcc -#define R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB 0xcd -#define R_CE_B_VERT_OUTPUT_WINDOW_LENGTH 0xce -#define R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB 0xcf - /* FIR filtering and prescaling */ -#define R_D0_B_HORIZ_PRESCALING 0xd0 -#define R_D1_B_ACCUMULATION_LENGTH 0xd1 -#define R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER 0xd2 -#define R_D4_B_LUMA_BRIGHTNESS_CNTL 0xd4 -#define R_D5_B_LUMA_CONTRAST_CNTL 0xd5 -#define R_D6_B_CHROMA_SATURATION_CNTL 0xd6 - /* Horizontal phase scaling */ -#define R_D8_B_HORIZ_LUMA_SCALING_INC 0xd8 -#define R_D9_B_HORIZ_LUMA_SCALING_INC_MSB 0xd9 -#define R_DA_B_HORIZ_LUMA_PHASE_OFF 0xda -#define R_DC_B_HORIZ_CHROMA_SCALING 0xdc -#define R_DD_B_HORIZ_CHROMA_SCALING_MSB 0xdd -#define R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA 0xde - /* Vertical scaling */ -#define R_E0_B_VERT_LUMA_SCALING_INC 0xe0 -#define R_E1_B_VERT_LUMA_SCALING_INC_MSB 0xe1 -#define R_E2_B_VERT_CHROMA_SCALING_INC 0xe2 -#define R_E3_B_VERT_CHROMA_SCALING_INC_MSB 0xe3 -#define R_E4_B_VERT_SCALING_MODE_CNTL 0xe4 -#define R_E8_B_VERT_CHROMA_PHASE_OFF_00 0xe8 -#define R_E9_B_VERT_CHROMA_PHASE_OFF_01 0xe9 -#define R_EA_B_VERT_CHROMA_PHASE_OFF_10 0xea -#define R_EB_B_VERT_CHROMA_PHASE_OFF_11 0xeb -#define R_EC_B_VERT_LUMA_PHASE_OFF_00 0xec -#define R_ED_B_VERT_LUMA_PHASE_OFF_01 0xed -#define R_EE_B_VERT_LUMA_PHASE_OFF_10 0xee -#define R_EF_B_VERT_LUMA_PHASE_OFF_11 0xef - -/* second PLL (PLL2) and Pulsegenerator Programming */ -#define R_F0_LFCO_PER_LINE 0xf0 -#define R_F1_P_I_PARAM_SELECT 0xf1 -#define R_F2_NOMINAL_PLL2_DTO 0xf2 -#define R_F3_PLL_INCREMENT 0xf3 -#define R_F4_PLL2_STATUS 0xf4 -#define R_F5_PULSGEN_LINE_LENGTH 0xf5 -#define R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG 0xf6 -#define R_F7_PULSE_A_POS_MSB 0xf7 -#define R_F8_PULSE_B_POS 0xf8 -#define R_F9_PULSE_B_POS_MSB 0xf9 -#define R_FA_PULSE_C_POS 0xfa -#define R_FB_PULSE_C_POS_MSB 0xfb -#define R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES 0xff - -#if 0 -/* Those structs will be used in the future for debug purposes */ -struct saa711x_reg_descr { - u8 reg; - int count; - char *name; -}; - -struct saa711x_reg_descr saa711x_regs[] = { - /* REG COUNT NAME */ - {R_00_CHIP_VERSION,1, - "Chip version"}, - - /* Video Decoder: R_01_INC_DELAY to R_1F_STATUS_BYTE_2_VD_DEC */ - - /* Video Decoder - Frontend part: R_01_INC_DELAY to R_05_INPUT_CNTL_4 */ - {R_01_INC_DELAY,1, - "Increment delay"}, - {R_02_INPUT_CNTL_1,1, - "Analog input control 1"}, - {R_03_INPUT_CNTL_2,1, - "Analog input control 2"}, - {R_04_INPUT_CNTL_3,1, - "Analog input control 3"}, - {R_05_INPUT_CNTL_4,1, - "Analog input control 4"}, - - /* Video Decoder - Decoder part: R_06_H_SYNC_START to R_1F_STATUS_BYTE_2_VD_DEC */ - {R_06_H_SYNC_START,1, - "Horizontal sync start"}, - {R_07_H_SYNC_STOP,1, - "Horizontal sync stop"}, - {R_08_SYNC_CNTL,1, - "Sync control"}, - {R_09_LUMA_CNTL,1, - "Luminance control"}, - {R_0A_LUMA_BRIGHT_CNTL,1, - "Luminance brightness control"}, - {R_0B_LUMA_CONTRAST_CNTL,1, - "Luminance contrast control"}, - {R_0C_CHROMA_SAT_CNTL,1, - "Chrominance saturation control"}, - {R_0D_CHROMA_HUE_CNTL,1, - "Chrominance hue control"}, - {R_0E_CHROMA_CNTL_1,1, - "Chrominance control 1"}, - {R_0F_CHROMA_GAIN_CNTL,1, - "Chrominance gain control"}, - {R_10_CHROMA_CNTL_2,1, - "Chrominance control 2"}, - {R_11_MODE_DELAY_CNTL,1, - "Mode/delay control"}, - {R_12_RT_SIGNAL_CNTL,1, - "RT signal control"}, - {R_13_RT_X_PORT_OUT_CNTL,1, - "RT/X port output control"}, - {R_14_ANAL_ADC_COMPAT_CNTL,1, - "Analog/ADC/compatibility control"}, - {R_15_VGATE_START_FID_CHG, 1, - "VGATE start FID change"}, - {R_16_VGATE_STOP,1, - "VGATE stop"}, - {R_17_MISC_VGATE_CONF_AND_MSB, 1, - "Miscellaneous VGATE configuration and MSBs"}, - {R_18_RAW_DATA_GAIN_CNTL,1, - "Raw data gain control",}, - {R_19_RAW_DATA_OFF_CNTL,1, - "Raw data offset control",}, - {R_1A_COLOR_KILL_LVL_CNTL,1, - "Color Killer Level Control"}, - { R_1B_MISC_TVVCRDET, 1, - "MISC /TVVCRDET"}, - { R_1C_ENHAN_COMB_CTRL1, 1, - "Enhanced comb ctrl1"}, - { R_1D_ENHAN_COMB_CTRL2, 1, - "Enhanced comb ctrl1"}, - {R_1E_STATUS_BYTE_1_VD_DEC,1, - "Status byte 1 video decoder"}, - {R_1F_STATUS_BYTE_2_VD_DEC,1, - "Status byte 2 video decoder"}, - - /* Component processing and interrupt masking part: 0x20h to R_2F_INTERRUPT_MASK_3 */ - /* 0x20 to 0x22 - Reserved */ - {R_23_INPUT_CNTL_5,1, - "Analog input control 5"}, - {R_24_INPUT_CNTL_6,1, - "Analog input control 6"}, - {R_25_INPUT_CNTL_7,1, - "Analog input control 7"}, - /* 0x26 to 0x28 - Reserved */ - {R_29_COMP_DELAY,1, - "Component delay"}, - {R_2A_COMP_BRIGHT_CNTL,1, - "Component brightness control"}, - {R_2B_COMP_CONTRAST_CNTL,1, - "Component contrast control"}, - {R_2C_COMP_SAT_CNTL,1, - "Component saturation control"}, - {R_2D_INTERRUPT_MASK_1,1, - "Interrupt mask 1"}, - {R_2E_INTERRUPT_MASK_2,1, - "Interrupt mask 2"}, - {R_2F_INTERRUPT_MASK_3,1, - "Interrupt mask 3"}, - - /* Audio clock generator part: R_30_AUD_MAST_CLK_CYCLES_PER_FIELD to 0x3f */ - {R_30_AUD_MAST_CLK_CYCLES_PER_FIELD,3, - "Audio master clock cycles per field"}, - /* 0x33 - Reserved */ - {R_34_AUD_MAST_CLK_NOMINAL_INC,3, - "Audio master clock nominal increment"}, - /* 0x37 - Reserved */ - {R_38_CLK_RATIO_AMXCLK_TO_ASCLK,1, - "Clock ratio AMXCLK to ASCLK"}, - {R_39_CLK_RATIO_ASCLK_TO_ALRCLK,1, - "Clock ratio ASCLK to ALRCLK"}, - {R_3A_AUD_CLK_GEN_BASIC_SETUP,1, - "Audio clock generator basic setup"}, - /* 0x3b-0x3f - Reserved */ - - /* General purpose VBI data slicer part: R_40_SLICER_CNTL_1 to 0x7f */ - {R_40_SLICER_CNTL_1,1, - "Slicer control 1"}, - {R_41_LCR,23, - "R_41_LCR"}, - {R_58_PROGRAM_FRAMING_CODE,1, - "Programmable framing code"}, - {R_59_H_OFF_FOR_SLICER,1, - "Horizontal offset for slicer"}, - {R_5A_V_OFF_FOR_SLICER,1, - "Vertical offset for slicer"}, - {R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF,1, - "Field offset and MSBs for horizontal and vertical offset"}, - {R_5D_DID,1, - "Header and data identification (R_5D_DID)"}, - {R_5E_SDID,1, - "Sliced data identification (R_5E_SDID) code"}, - {R_60_SLICER_STATUS_BYTE_0,1, - "Slicer status byte 0"}, - {R_61_SLICER_STATUS_BYTE_1,1, - "Slicer status byte 1"}, - {R_62_SLICER_STATUS_BYTE_2,1, - "Slicer status byte 2"}, - /* 0x63-0x7f - Reserved */ - - /* X port, I port and the scaler part: R_80_GLOBAL_CNTL_1 to R_EF_B_VERT_LUMA_PHASE_OFF_11 */ - /* Task independent global settings: R_80_GLOBAL_CNTL_1 to R_8F_STATUS_INFO_SCALER */ - {R_80_GLOBAL_CNTL_1,1, - "Global control 1"}, - {R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F,1, - "Vertical sync and Field ID source selection, retimed V and F signals"}, - /* 0x82 - Reserved */ - {R_83_X_PORT_I_O_ENA_AND_OUT_CLK,1, - "X port I/O enable and output clock"}, - {R_84_I_PORT_SIGNAL_DEF,1, - "I port signal definitions"}, - {R_85_I_PORT_SIGNAL_POLAR,1, - "I port signal polarities"}, - {R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT,1, - "I port FIFO flag control and arbitration"}, - {R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 1, - "I port I/O enable output clock and gated"}, - {R_88_POWER_SAVE_ADC_PORT_CNTL,1, - "Power save/ADC port control"}, - /* 089-0x8e - Reserved */ - {R_8F_STATUS_INFO_SCALER,1, - "Status information scaler part"}, - - /* Task A definition: R_90_A_TASK_HANDLING_CNTL to R_BF_A_VERT_LUMA_PHASE_OFF_11 */ - /* Task A: Basic settings and acquisition window definition */ - {R_90_A_TASK_HANDLING_CNTL,1, - "Task A: Task handling control"}, - {R_91_A_X_PORT_FORMATS_AND_CONF,1, - "Task A: X port formats and configuration"}, - {R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL,1, - "Task A: X port input reference signal definition"}, - {R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF,1, - "Task A: I port output formats and configuration"}, - {R_94_A_HORIZ_INPUT_WINDOW_START,2, - "Task A: Horizontal input window start"}, - {R_96_A_HORIZ_INPUT_WINDOW_LENGTH,2, - "Task A: Horizontal input window length"}, - {R_98_A_VERT_INPUT_WINDOW_START,2, - "Task A: Vertical input window start"}, - {R_9A_A_VERT_INPUT_WINDOW_LENGTH,2, - "Task A: Vertical input window length"}, - {R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH,2, - "Task A: Horizontal output window length"}, - {R_9E_A_VERT_OUTPUT_WINDOW_LENGTH,2, - "Task A: Vertical output window length"}, - - /* Task A: FIR filtering and prescaling */ - {R_A0_A_HORIZ_PRESCALING,1, - "Task A: Horizontal prescaling"}, - {R_A1_A_ACCUMULATION_LENGTH,1, - "Task A: Accumulation length"}, - {R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1, - "Task A: Prescaler DC gain and FIR prefilter"}, - /* 0xa3 - Reserved */ - {R_A4_A_LUMA_BRIGHTNESS_CNTL,1, - "Task A: Luminance brightness control"}, - {R_A5_A_LUMA_CONTRAST_CNTL,1, - "Task A: Luminance contrast control"}, - {R_A6_A_CHROMA_SATURATION_CNTL,1, - "Task A: Chrominance saturation control"}, - /* 0xa7 - Reserved */ - - /* Task A: Horizontal phase scaling */ - {R_A8_A_HORIZ_LUMA_SCALING_INC,2, - "Task A: Horizontal luminance scaling increment"}, - {R_AA_A_HORIZ_LUMA_PHASE_OFF,1, - "Task A: Horizontal luminance phase offset"}, - /* 0xab - Reserved */ - {R_AC_A_HORIZ_CHROMA_SCALING_INC,2, - "Task A: Horizontal chrominance scaling increment"}, - {R_AE_A_HORIZ_CHROMA_PHASE_OFF,1, - "Task A: Horizontal chrominance phase offset"}, - /* 0xaf - Reserved */ - - /* Task A: Vertical scaling */ - {R_B0_A_VERT_LUMA_SCALING_INC,2, - "Task A: Vertical luminance scaling increment"}, - {R_B2_A_VERT_CHROMA_SCALING_INC,2, - "Task A: Vertical chrominance scaling increment"}, - {R_B4_A_VERT_SCALING_MODE_CNTL,1, - "Task A: Vertical scaling mode control"}, - /* 0xb5-0xb7 - Reserved */ - {R_B8_A_VERT_CHROMA_PHASE_OFF_00,1, - "Task A: Vertical chrominance phase offset '00'"}, - {R_B9_A_VERT_CHROMA_PHASE_OFF_01,1, - "Task A: Vertical chrominance phase offset '01'"}, - {R_BA_A_VERT_CHROMA_PHASE_OFF_10,1, - "Task A: Vertical chrominance phase offset '10'"}, - {R_BB_A_VERT_CHROMA_PHASE_OFF_11,1, - "Task A: Vertical chrominance phase offset '11'"}, - {R_BC_A_VERT_LUMA_PHASE_OFF_00,1, - "Task A: Vertical luminance phase offset '00'"}, - {R_BD_A_VERT_LUMA_PHASE_OFF_01,1, - "Task A: Vertical luminance phase offset '01'"}, - {R_BE_A_VERT_LUMA_PHASE_OFF_10,1, - "Task A: Vertical luminance phase offset '10'"}, - {R_BF_A_VERT_LUMA_PHASE_OFF_11,1, - "Task A: Vertical luminance phase offset '11'"}, - - /* Task B definition: R_C0_B_TASK_HANDLING_CNTL to R_EF_B_VERT_LUMA_PHASE_OFF_11 */ - /* Task B: Basic settings and acquisition window definition */ - {R_C0_B_TASK_HANDLING_CNTL,1, - "Task B: Task handling control"}, - {R_C1_B_X_PORT_FORMATS_AND_CONF,1, - "Task B: X port formats and configuration"}, - {R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION,1, - "Task B: Input reference signal definition"}, - {R_C3_B_I_PORT_FORMATS_AND_CONF,1, - "Task B: I port formats and configuration"}, - {R_C4_B_HORIZ_INPUT_WINDOW_START,2, - "Task B: Horizontal input window start"}, - {R_C6_B_HORIZ_INPUT_WINDOW_LENGTH,2, - "Task B: Horizontal input window length"}, - {R_C8_B_VERT_INPUT_WINDOW_START,2, - "Task B: Vertical input window start"}, - {R_CA_B_VERT_INPUT_WINDOW_LENGTH,2, - "Task B: Vertical input window length"}, - {R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,2, - "Task B: Horizontal output window length"}, - {R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,2, - "Task B: Vertical output window length"}, - - /* Task B: FIR filtering and prescaling */ - {R_D0_B_HORIZ_PRESCALING,1, - "Task B: Horizontal prescaling"}, - {R_D1_B_ACCUMULATION_LENGTH,1, - "Task B: Accumulation length"}, - {R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1, - "Task B: Prescaler DC gain and FIR prefilter"}, - /* 0xd3 - Reserved */ - {R_D4_B_LUMA_BRIGHTNESS_CNTL,1, - "Task B: Luminance brightness control"}, - {R_D5_B_LUMA_CONTRAST_CNTL,1, - "Task B: Luminance contrast control"}, - {R_D6_B_CHROMA_SATURATION_CNTL,1, - "Task B: Chrominance saturation control"}, - /* 0xd7 - Reserved */ - - /* Task B: Horizontal phase scaling */ - {R_D8_B_HORIZ_LUMA_SCALING_INC,2, - "Task B: Horizontal luminance scaling increment"}, - {R_DA_B_HORIZ_LUMA_PHASE_OFF,1, - "Task B: Horizontal luminance phase offset"}, - /* 0xdb - Reserved */ - {R_DC_B_HORIZ_CHROMA_SCALING,2, - "Task B: Horizontal chrominance scaling"}, - {R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA,1, - "Task B: Horizontal Phase Offset Chroma"}, - /* 0xdf - Reserved */ - - /* Task B: Vertical scaling */ - {R_E0_B_VERT_LUMA_SCALING_INC,2, - "Task B: Vertical luminance scaling increment"}, - {R_E2_B_VERT_CHROMA_SCALING_INC,2, - "Task B: Vertical chrominance scaling increment"}, - {R_E4_B_VERT_SCALING_MODE_CNTL,1, - "Task B: Vertical scaling mode control"}, - /* 0xe5-0xe7 - Reserved */ - {R_E8_B_VERT_CHROMA_PHASE_OFF_00,1, - "Task B: Vertical chrominance phase offset '00'"}, - {R_E9_B_VERT_CHROMA_PHASE_OFF_01,1, - "Task B: Vertical chrominance phase offset '01'"}, - {R_EA_B_VERT_CHROMA_PHASE_OFF_10,1, - "Task B: Vertical chrominance phase offset '10'"}, - {R_EB_B_VERT_CHROMA_PHASE_OFF_11,1, - "Task B: Vertical chrominance phase offset '11'"}, - {R_EC_B_VERT_LUMA_PHASE_OFF_00,1, - "Task B: Vertical luminance phase offset '00'"}, - {R_ED_B_VERT_LUMA_PHASE_OFF_01,1, - "Task B: Vertical luminance phase offset '01'"}, - {R_EE_B_VERT_LUMA_PHASE_OFF_10,1, - "Task B: Vertical luminance phase offset '10'"}, - {R_EF_B_VERT_LUMA_PHASE_OFF_11,1, - "Task B: Vertical luminance phase offset '11'"}, - - /* second PLL (PLL2) and Pulsegenerator Programming */ - { R_F0_LFCO_PER_LINE, 1, - "LFCO's per line"}, - { R_F1_P_I_PARAM_SELECT,1, - "P-/I- Param. Select., PLL Mode, PLL H-Src., LFCO's per line"}, - { R_F2_NOMINAL_PLL2_DTO,1, - "Nominal PLL2 DTO"}, - {R_F3_PLL_INCREMENT,1, - "PLL2 Increment"}, - {R_F4_PLL2_STATUS,1, - "PLL2 Status"}, - {R_F5_PULSGEN_LINE_LENGTH,1, - "Pulsgen. line length"}, - {R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG,1, - "Pulse A Position, Pulsgen Resync., Pulsgen. H-Src., Pulsgen. line length"}, - {R_F7_PULSE_A_POS_MSB,1, - "Pulse A Position"}, - {R_F8_PULSE_B_POS,2, - "Pulse B Position"}, - {R_FA_PULSE_C_POS,2, - "Pulse C Position"}, - /* 0xfc to 0xfe - Reserved */ - {R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES,1, - "S_PLL max. phase, error threshold, PLL2 no. of lines, threshold"}, -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7121.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7121.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7121.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7121.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,132 +0,0 @@ -/* saa7121.h - saa7121 initializations - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ -#ifndef __SAA7121_H__ -#define __SAA7121_H__ - -#define NTSC_BURST_START 0x19 /* 28 */ -#define NTSC_BURST_END 0x1d /* 29 */ -#define NTSC_CHROMA_PHASE 0x67 /* 5a */ -#define NTSC_GAINU 0x76 /* 5b */ -#define NTSC_GAINV 0xa5 /* 5c */ -#define NTSC_BLACK_LEVEL 0x2a /* 5d */ -#define NTSC_BLANKING_LEVEL 0x2e /* 5e */ -#define NTSC_VBI_BLANKING 0x2e /* 5f */ -#define NTSC_DAC_CONTROL 0x11 /* 61 */ -#define NTSC_BURST_AMP 0x3f /* 62 */ -#define NTSC_SUBC3 0x1f /* 63 */ -#define NTSC_SUBC2 0x7c /* 64 */ -#define NTSC_SUBC1 0xf0 /* 65 */ -#define NTSC_SUBC0 0x21 /* 66 */ -#define NTSC_HTRIG 0x72 /* 6c */ -#define NTSC_VTRIG 0x00 /* 6c */ -#define NTSC_MULTI 0x30 /* 6e */ -#define NTSC_CCTTX 0x11 /* 6f */ -#define NTSC_FIRST_ACTIVE 0x12 /* 7a */ -#define NTSC_LAST_ACTIVE 0x02 /* 7b */ -#define NTSC_MSB_VERTICAL 0x40 /* 7c */ - -#define PAL_BURST_START 0x21 /* 28 */ -#define PAL_BURST_END 0x1d /* 29 */ -#define PAL_CHROMA_PHASE 0x3f /* 5a */ -#define PAL_GAINU 0x7d /* 5b */ -#define PAL_GAINV 0xaf /* 5c */ -#define PAL_BLACK_LEVEL 0x23 /* 5d */ -#define PAL_BLANKING_LEVEL 0x35 /* 5e */ -#define PAL_VBI_BLANKING 0x35 /* 5f */ -#define PAL_DAC_CONTROL 0x02 /* 61 */ -#define PAL_BURST_AMP 0x2f /* 62 */ -#define PAL_SUBC3 0xcb /* 63 */ -#define PAL_SUBC2 0x8a /* 64 */ -#define PAL_SUBC1 0x09 /* 65 */ -#define PAL_SUBC0 0x2a /* 66 */ -#define PAL_HTRIG 0x86 /* 6c */ -#define PAL_VTRIG 0x04 /* 6d */ -#define PAL_MULTI 0x20 /* 6e */ -#define PAL_CCTTX 0x15 /* 6f */ -#define PAL_FIRST_ACTIVE 0x16 /* 7a */ -#define PAL_LAST_ACTIVE 0x36 /* 7b */ -#define PAL_MSB_VERTICAL 0x40 /* 7c */ - -/* Initialization Sequence */ - -static __u8 init7121ntsc[] = { - 0x26, 0x0, 0x27, 0x0, - 0x28, NTSC_BURST_START, 0x29, NTSC_BURST_END, - 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, - 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x31, 0x0, - 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, - 0x36, 0x0, 0x37, 0x0, 0x38, 0x0, 0x39, 0x0, - 0x3a, 0x03, 0x3b, 0x0, 0x3c, 0x0, 0x3d, 0x0, - 0x3e, 0x0, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, - 0x42, 0x0, 0x43, 0x0, 0x44, 0x0, 0x45, 0x0, - 0x46, 0x0, 0x47, 0x0, 0x48, 0x0, 0x49, 0x0, - 0x4a, 0x0, 0x4b, 0x0, 0x4c, 0x0, 0x4d, 0x0, - 0x4e, 0x0, 0x4f, 0x0, 0x50, 0x0, 0x51, 0x0, - 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x55, 0x0, - 0x56, 0x0, 0x57, 0x0, 0x58, 0x0, 0x59, 0x0, - 0x5a, NTSC_CHROMA_PHASE, 0x5b, NTSC_GAINU, - 0x5c, NTSC_GAINV, 0x5d, NTSC_BLACK_LEVEL, - 0x5e, NTSC_BLANKING_LEVEL, 0x5f, NTSC_VBI_BLANKING, - 0x60, 0x0, 0x61, NTSC_DAC_CONTROL, - 0x62, NTSC_BURST_AMP, 0x63, NTSC_SUBC3, - 0x64, NTSC_SUBC2, 0x65, NTSC_SUBC1, - 0x66, NTSC_SUBC0, 0x67, 0x80, 0x68, 0x80, - 0x69, 0x80, 0x6a, 0x80, 0x6b, 0x29, - 0x6c, NTSC_HTRIG, 0x6d, NTSC_VTRIG, - 0x6e, NTSC_MULTI, 0x6f, NTSC_CCTTX, - 0x70, 0xc9, 0x71, 0x68, 0x72, 0x60, 0x73, 0x0, - 0x74, 0x0, 0x75, 0x0, 0x76, 0x0, 0x77, 0x0, - 0x78, 0x0, 0x79, 0x0, 0x7a, NTSC_FIRST_ACTIVE, - 0x7b, NTSC_LAST_ACTIVE, 0x7c, NTSC_MSB_VERTICAL, - 0x7d, 0x0, 0x7e, 0x0, 0x7f, 0x0 -}; -#define INIT7121LEN (sizeof(init7121ntsc)/2) - -static __u8 init7121pal[] = { - 0x26, 0x0, 0x27, 0x0, - 0x28, PAL_BURST_START, 0x29, PAL_BURST_END, - 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, - 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x31, 0x0, - 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, - 0x36, 0x0, 0x37, 0x0, 0x38, 0x0, 0x39, 0x0, - 0x3a, 0x03, 0x3b, 0x0, 0x3c, 0x0, 0x3d, 0x0, - 0x3e, 0x0, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, - 0x42, 0x0, 0x43, 0x0, 0x44, 0x0, 0x45, 0x0, - 0x46, 0x0, 0x47, 0x0, 0x48, 0x0, 0x49, 0x0, - 0x4a, 0x0, 0x4b, 0x0, 0x4c, 0x0, 0x4d, 0x0, - 0x4e, 0x0, 0x4f, 0x0, 0x50, 0x0, 0x51, 0x0, - 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x55, 0x0, - 0x56, 0x0, 0x57, 0x0, 0x58, 0x0, 0x59, 0x0, - 0x5a, PAL_CHROMA_PHASE, 0x5b, PAL_GAINU, - 0x5c, PAL_GAINV, 0x5d, PAL_BLACK_LEVEL, - 0x5e, PAL_BLANKING_LEVEL, 0x5f, PAL_VBI_BLANKING, - 0x60, 0x0, 0x61, PAL_DAC_CONTROL, - 0x62, PAL_BURST_AMP, 0x63, PAL_SUBC3, - 0x64, PAL_SUBC2, 0x65, PAL_SUBC1, - 0x66, PAL_SUBC0, 0x67, 0x80, 0x68, 0x80, - 0x69, 0x80, 0x6a, 0x80, 0x6b, 0x29, - 0x6c, PAL_HTRIG, 0x6d, PAL_VTRIG, - 0x6e, PAL_MULTI, 0x6f, PAL_CCTTX, - 0x70, 0xc9, 0x71, 0x68, 0x72, 0x60, 0x73, 0x0, - 0x74, 0x0, 0x75, 0x0, 0x76, 0x0, 0x77, 0x0, - 0x78, 0x0, 0x79, 0x0, 0x7a, PAL_FIRST_ACTIVE, - 0x7b, PAL_LAST_ACTIVE, 0x7c, PAL_MSB_VERTICAL, - 0x7d, 0x0, 0x7e, 0x0, 0x7f, 0x0 -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7127.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7127.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7127.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7127.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,866 +0,0 @@ -/* - * saa7127 - Philips SAA7127/SAA7129 video encoder driver - * - * Copyright (C) 2003 Roy Bulter - * - * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter - * - * Copyright (C) 2000-2001 Gillem - * Copyright (C) 2002 Andreas Oberritter - * - * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo - * - * Copyright (C) 1999 Nathan Laredo - * - * This driver is designed for the Hauppauge 250/350 Linux driver - * from the ivtv Project - * - * Copyright (C) 2003 Kevin Thayer - * - * Dual output support: - * Copyright (C) 2004 Eric Varsanyi - * - * NTSC Tuning and 7.5 IRE Setup - * Copyright (C) 2004 Chris Kennedy - * - * VBI additions & cleanup: - * Copyright (C) 2004, 2005 Hans Verkuil - * - * Note: the saa7126 is identical to the saa7127, and the saa7128 is - * identical to the saa7129, except that the saa7126 and saa7128 have - * macrovision anti-taping support. This driver will almost certainly - * work fine for those chips, except of course for the missing anti-taping - * support. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -static int debug; -static int test_image; - -MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver"); -MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); -MODULE_LICENSE("GPL"); -module_param(debug, int, 0644); -module_param(test_image, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-2)"); -MODULE_PARM_DESC(test_image, "test_image (0-1)"); - - -/* - * SAA7127 registers - */ - -#define SAA7127_REG_STATUS 0x00 -#define SAA7127_REG_WIDESCREEN_CONFIG 0x26 -#define SAA7127_REG_WIDESCREEN_ENABLE 0x27 -#define SAA7127_REG_BURST_START 0x28 -#define SAA7127_REG_BURST_END 0x29 -#define SAA7127_REG_COPYGEN_0 0x2a -#define SAA7127_REG_COPYGEN_1 0x2b -#define SAA7127_REG_COPYGEN_2 0x2c -#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d -#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38 -#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39 -#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a -#define SAA7129_REG_FADE_KEY_COL2 0x4f -#define SAA7127_REG_CHROMA_PHASE 0x5a -#define SAA7127_REG_GAINU 0x5b -#define SAA7127_REG_GAINV 0x5c -#define SAA7127_REG_BLACK_LEVEL 0x5d -#define SAA7127_REG_BLANKING_LEVEL 0x5e -#define SAA7127_REG_VBI_BLANKING 0x5f -#define SAA7127_REG_DAC_CONTROL 0x61 -#define SAA7127_REG_BURST_AMP 0x62 -#define SAA7127_REG_SUBC3 0x63 -#define SAA7127_REG_SUBC2 0x64 -#define SAA7127_REG_SUBC1 0x65 -#define SAA7127_REG_SUBC0 0x66 -#define SAA7127_REG_LINE_21_ODD_0 0x67 -#define SAA7127_REG_LINE_21_ODD_1 0x68 -#define SAA7127_REG_LINE_21_EVEN_0 0x69 -#define SAA7127_REG_LINE_21_EVEN_1 0x6a -#define SAA7127_REG_RCV_PORT_CONTROL 0x6b -#define SAA7127_REG_VTRIG 0x6c -#define SAA7127_REG_HTRIG_HI 0x6d -#define SAA7127_REG_MULTI 0x6e -#define SAA7127_REG_CLOSED_CAPTION 0x6f -#define SAA7127_REG_RCV2_OUTPUT_START 0x70 -#define SAA7127_REG_RCV2_OUTPUT_END 0x71 -#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72 -#define SAA7127_REG_TTX_REQUEST_H_START 0x73 -#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74 -#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75 -#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76 -#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77 -#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78 -#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79 -#define SAA7127_REG_FIRST_ACTIVE 0x7a -#define SAA7127_REG_LAST_ACTIVE 0x7b -#define SAA7127_REG_MSB_VERTICAL 0x7c -#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e -#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f - -/* - ********************************************************************** - * - * Arrays with configuration parameters for the SAA7127 - * - ********************************************************************** - */ - -struct i2c_reg_value { - unsigned char reg; - unsigned char value; -}; - -static const struct i2c_reg_value saa7129_init_config_extra[] = { - { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 }, - { SAA7127_REG_VTRIG, 0xfa }, - { 0, 0 } -}; - -static const struct i2c_reg_value saa7127_init_config_common[] = { - { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d }, - { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 }, - { SAA7127_REG_COPYGEN_0, 0x77 }, - { SAA7127_REG_COPYGEN_1, 0x41 }, - { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */ - { SAA7127_REG_OUTPUT_PORT_CONTROL, 0xbf }, - { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 }, - { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 }, - { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */ - { SAA7127_REG_LINE_21_ODD_0, 0x77 }, - { SAA7127_REG_LINE_21_ODD_1, 0x41 }, - { SAA7127_REG_LINE_21_EVEN_0, 0x88 }, - { SAA7127_REG_LINE_21_EVEN_1, 0x41 }, - { SAA7127_REG_RCV_PORT_CONTROL, 0x12 }, - { SAA7127_REG_VTRIG, 0xf9 }, - { SAA7127_REG_HTRIG_HI, 0x00 }, - { SAA7127_REG_RCV2_OUTPUT_START, 0x41 }, - { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 }, - { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 }, - { SAA7127_REG_TTX_REQUEST_H_START, 0x3e }, - { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 }, - { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 }, - { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 }, - { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 }, - { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 }, - { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 }, - { SAA7127_REG_FIRST_ACTIVE, 0x1a }, - { SAA7127_REG_LAST_ACTIVE, 0x01 }, - { SAA7127_REG_MSB_VERTICAL, 0xc0 }, - { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 }, - { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 }, - { 0, 0 } -}; - -#define SAA7127_60HZ_DAC_CONTROL 0x15 -static const struct i2c_reg_value saa7127_init_config_60hz[] = { - { SAA7127_REG_BURST_START, 0x19 }, - /* BURST_END is also used as a chip ID in saa7127_probe */ - { SAA7127_REG_BURST_END, 0x1d }, - { SAA7127_REG_CHROMA_PHASE, 0xa3 }, - { SAA7127_REG_GAINU, 0x98 }, - { SAA7127_REG_GAINV, 0xd3 }, - { SAA7127_REG_BLACK_LEVEL, 0x39 }, - { SAA7127_REG_BLANKING_LEVEL, 0x2e }, - { SAA7127_REG_VBI_BLANKING, 0x2e }, - { SAA7127_REG_DAC_CONTROL, 0x15 }, - { SAA7127_REG_BURST_AMP, 0x4d }, - { SAA7127_REG_SUBC3, 0x1f }, - { SAA7127_REG_SUBC2, 0x7c }, - { SAA7127_REG_SUBC1, 0xf0 }, - { SAA7127_REG_SUBC0, 0x21 }, - { SAA7127_REG_MULTI, 0x90 }, - { SAA7127_REG_CLOSED_CAPTION, 0x11 }, - { 0, 0 } -}; - -#define SAA7127_50HZ_PAL_DAC_CONTROL 0x02 -static struct i2c_reg_value saa7127_init_config_50hz_pal[] = { - { SAA7127_REG_BURST_START, 0x21 }, - /* BURST_END is also used as a chip ID in saa7127_probe */ - { SAA7127_REG_BURST_END, 0x1d }, - { SAA7127_REG_CHROMA_PHASE, 0x3f }, - { SAA7127_REG_GAINU, 0x7d }, - { SAA7127_REG_GAINV, 0xaf }, - { SAA7127_REG_BLACK_LEVEL, 0x33 }, - { SAA7127_REG_BLANKING_LEVEL, 0x35 }, - { SAA7127_REG_VBI_BLANKING, 0x35 }, - { SAA7127_REG_DAC_CONTROL, 0x02 }, - { SAA7127_REG_BURST_AMP, 0x2f }, - { SAA7127_REG_SUBC3, 0xcb }, - { SAA7127_REG_SUBC2, 0x8a }, - { SAA7127_REG_SUBC1, 0x09 }, - { SAA7127_REG_SUBC0, 0x2a }, - { SAA7127_REG_MULTI, 0xa0 }, - { SAA7127_REG_CLOSED_CAPTION, 0x00 }, - { 0, 0 } -}; - -#define SAA7127_50HZ_SECAM_DAC_CONTROL 0x08 -static struct i2c_reg_value saa7127_init_config_50hz_secam[] = { - { SAA7127_REG_BURST_START, 0x21 }, - /* BURST_END is also used as a chip ID in saa7127_probe */ - { SAA7127_REG_BURST_END, 0x1d }, - { SAA7127_REG_CHROMA_PHASE, 0x3f }, - { SAA7127_REG_GAINU, 0x6a }, - { SAA7127_REG_GAINV, 0x81 }, - { SAA7127_REG_BLACK_LEVEL, 0x33 }, - { SAA7127_REG_BLANKING_LEVEL, 0x35 }, - { SAA7127_REG_VBI_BLANKING, 0x35 }, - { SAA7127_REG_DAC_CONTROL, 0x08 }, - { SAA7127_REG_BURST_AMP, 0x2f }, - { SAA7127_REG_SUBC3, 0xb2 }, - { SAA7127_REG_SUBC2, 0x3b }, - { SAA7127_REG_SUBC1, 0xa3 }, - { SAA7127_REG_SUBC0, 0x28 }, - { SAA7127_REG_MULTI, 0x90 }, - { SAA7127_REG_CLOSED_CAPTION, 0x00 }, - { 0, 0 } -}; - -/* - ********************************************************************** - * - * Encoder Struct, holds the configuration state of the encoder - * - ********************************************************************** - */ - -struct saa7127_state { - struct v4l2_subdev sd; - v4l2_std_id std; - u32 ident; - enum saa7127_input_type input_type; - enum saa7127_output_type output_type; - int video_enable; - int wss_enable; - u16 wss_mode; - int cc_enable; - u16 cc_data; - int xds_enable; - u16 xds_data; - int vps_enable; - u8 vps_data[5]; - u8 reg_2d; - u8 reg_3a; - u8 reg_3a_cb; /* colorbar bit */ - u8 reg_61; -}; - -static inline struct saa7127_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa7127_state, sd); -} - -static const char * const output_strs[] = -{ - "S-Video + Composite", - "Composite", - "S-Video", - "RGB", - "YUV C", - "YUV V" -}; - -static const char * const wss_strs[] = { - "invalid", - "letterbox 14:9 center", - "letterbox 14:9 top", - "invalid", - "letterbox 16:9 top", - "invalid", - "invalid", - "16:9 full format anamorphic", - "4:3 full format", - "invalid", - "invalid", - "letterbox 16:9 center", - "invalid", - "letterbox >16:9 center", - "14:9 full format center", - "invalid", -}; - -/* ----------------------------------------------------------------------- */ - -static int saa7127_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_read_byte_data(client, reg); -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int i; - - for (i = 0; i < 3; i++) { - if (i2c_smbus_write_byte_data(client, reg, val) == 0) - return 0; - } - v4l2_err(sd, "I2C Write Problem\n"); - return -1; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_write_inittab(struct v4l2_subdev *sd, - const struct i2c_reg_value *regs) -{ - while (regs->reg != 0) { - saa7127_write(sd, regs->reg, regs->value); - regs++; - } - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) -{ - struct saa7127_state *state = to_state(sd); - int enable = (data->line != 0); - - if (enable && (data->field != 0 || data->line != 16)) - return -EINVAL; - if (state->vps_enable != enable) { - v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off"); - saa7127_write(sd, 0x54, enable << 7); - state->vps_enable = enable; - } - if (!enable) - return 0; - - state->vps_data[0] = data->data[2]; - state->vps_data[1] = data->data[8]; - state->vps_data[2] = data->data[9]; - state->vps_data[3] = data->data[10]; - state->vps_data[4] = data->data[11]; - v4l2_dbg(1, debug, sd, "Set VPS data %02x %02x %02x %02x %02x\n", - state->vps_data[0], state->vps_data[1], - state->vps_data[2], state->vps_data[3], - state->vps_data[4]); - saa7127_write(sd, 0x55, state->vps_data[0]); - saa7127_write(sd, 0x56, state->vps_data[1]); - saa7127_write(sd, 0x57, state->vps_data[2]); - saa7127_write(sd, 0x58, state->vps_data[3]); - saa7127_write(sd, 0x59, state->vps_data[4]); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) -{ - struct saa7127_state *state = to_state(sd); - u16 cc = data->data[1] << 8 | data->data[0]; - int enable = (data->line != 0); - - if (enable && (data->field != 0 || data->line != 21)) - return -EINVAL; - if (state->cc_enable != enable) { - v4l2_dbg(1, debug, sd, - "Turn CC %s\n", enable ? "on" : "off"); - saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION, - (state->xds_enable << 7) | (enable << 6) | 0x11); - state->cc_enable = enable; - } - if (!enable) - return 0; - - v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc); - saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff); - saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8); - state->cc_data = cc; - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) -{ - struct saa7127_state *state = to_state(sd); - u16 xds = data->data[1] << 8 | data->data[0]; - int enable = (data->line != 0); - - if (enable && (data->field != 1 || data->line != 21)) - return -EINVAL; - if (state->xds_enable != enable) { - v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off"); - saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION, - (enable << 7) | (state->cc_enable << 6) | 0x11); - state->xds_enable = enable; - } - if (!enable) - return 0; - - v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds); - saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff); - saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8); - state->xds_data = xds; - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) -{ - struct saa7127_state *state = to_state(sd); - int enable = (data->line != 0); - - if (enable && (data->field != 0 || data->line != 23)) - return -EINVAL; - if (state->wss_enable != enable) { - v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off"); - saa7127_write(sd, 0x27, enable << 7); - state->wss_enable = enable; - } - if (!enable) - return 0; - - saa7127_write(sd, 0x26, data->data[0]); - saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f)); - v4l2_dbg(1, debug, sd, - "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); - state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0]; - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable) -{ - struct saa7127_state *state = to_state(sd); - - if (enable) { - v4l2_dbg(1, debug, sd, "Enable Video Output\n"); - saa7127_write(sd, 0x2d, state->reg_2d); - saa7127_write(sd, 0x61, state->reg_61); - } else { - v4l2_dbg(1, debug, sd, "Disable Video Output\n"); - saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0)); - saa7127_write(sd, 0x61, (state->reg_61 | 0xc0)); - } - state->video_enable = enable; - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct saa7127_state *state = to_state(sd); - const struct i2c_reg_value *inittab; - - if (std & V4L2_STD_525_60) { - v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n"); - inittab = saa7127_init_config_60hz; - state->reg_61 = SAA7127_60HZ_DAC_CONTROL; - - } else if (state->ident == V4L2_IDENT_SAA7129 && - (std & V4L2_STD_SECAM) && - !(std & (V4L2_STD_625_50 & ~V4L2_STD_SECAM))) { - - /* If and only if SECAM, with a SAA712[89] */ - v4l2_dbg(1, debug, sd, - "Selecting 50 Hz SECAM video Standard\n"); - inittab = saa7127_init_config_50hz_secam; - state->reg_61 = SAA7127_50HZ_SECAM_DAC_CONTROL; - - } else { - v4l2_dbg(1, debug, sd, "Selecting 50 Hz PAL video Standard\n"); - inittab = saa7127_init_config_50hz_pal; - state->reg_61 = SAA7127_50HZ_PAL_DAC_CONTROL; - } - - /* Write Table */ - saa7127_write_inittab(sd, inittab); - state->std = std; - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_set_output_type(struct v4l2_subdev *sd, int output) -{ - struct saa7127_state *state = to_state(sd); - - switch (output) { - case SAA7127_OUTPUT_TYPE_RGB: - state->reg_2d = 0x0f; /* RGB + CVBS (for sync) */ - state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ - break; - - case SAA7127_OUTPUT_TYPE_COMPOSITE: - if (state->ident == V4L2_IDENT_SAA7129) - state->reg_2d = 0x20; /* CVBS only */ - else - state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */ - state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ - break; - - case SAA7127_OUTPUT_TYPE_SVIDEO: - if (state->ident == V4L2_IDENT_SAA7129) - state->reg_2d = 0x18; /* Y + C */ - else - state->reg_2d = 0xff; /*11111111 croma -> R, luma -> CVBS + G + B */ - state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ - break; - - case SAA7127_OUTPUT_TYPE_YUV_V: - state->reg_2d = 0x4f; /* reg 2D = 01001111, all DAC's on, RGB + VBS */ - state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */ - break; - - case SAA7127_OUTPUT_TYPE_YUV_C: - state->reg_2d = 0x0f; /* reg 2D = 00001111, all DAC's on, RGB + CVBS */ - state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */ - break; - - case SAA7127_OUTPUT_TYPE_BOTH: - if (state->ident == V4L2_IDENT_SAA7129) - state->reg_2d = 0x38; - else - state->reg_2d = 0xbf; - state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ - break; - - default: - return -EINVAL; - } - v4l2_dbg(1, debug, sd, - "Selecting %s output type\n", output_strs[output]); - - /* Configure Encoder */ - saa7127_write(sd, 0x2d, state->reg_2d); - saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb); - state->output_type = output; - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_set_input_type(struct v4l2_subdev *sd, int input) -{ - struct saa7127_state *state = to_state(sd); - - switch (input) { - case SAA7127_INPUT_TYPE_NORMAL: /* avia */ - v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n"); - state->reg_3a_cb = 0; - break; - - case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */ - v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n"); - state->reg_3a_cb = 0x80; - break; - - default: - return -EINVAL; - } - saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb); - state->input_type = input; - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct saa7127_state *state = to_state(sd); - - if (state->std == std) - return 0; - return saa7127_set_std(sd, std); -} - -static int saa7127_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct saa7127_state *state = to_state(sd); - int rc = 0; - - if (state->input_type != input) - rc = saa7127_set_input_type(sd, input); - if (rc == 0 && state->output_type != output) - rc = saa7127_set_output_type(sd, output); - return rc; -} - -static int saa7127_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct saa7127_state *state = to_state(sd); - - if (state->video_enable == enable) - return 0; - return saa7127_set_video_enable(sd, enable); -} - -static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt) -{ - struct saa7127_state *state = to_state(sd); - - memset(fmt, 0, sizeof(*fmt)); - if (state->vps_enable) - fmt->service_lines[0][16] = V4L2_SLICED_VPS; - if (state->wss_enable) - fmt->service_lines[0][23] = V4L2_SLICED_WSS_625; - if (state->cc_enable) { - fmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - fmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } - fmt->service_set = - (state->vps_enable ? V4L2_SLICED_VPS : 0) | - (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) | - (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0); - return 0; -} - -static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) -{ - switch (data->id) { - case V4L2_SLICED_WSS_625: - return saa7127_set_wss(sd, data); - case V4L2_SLICED_VPS: - return saa7127_set_vps(sd, data); - case V4L2_SLICED_CAPTION_525: - if (data->field == 0) - return saa7127_set_cc(sd, data); - return saa7127_set_xds(sd, data); - default: - return -EINVAL; - } - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->val = saa7127_read(sd, reg->reg & 0xff); - reg->size = 1; - return 0; -} - -static int saa7127_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff); - return 0; -} -#endif - -static int saa7127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct saa7127_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0); -} - -static int saa7127_log_status(struct v4l2_subdev *sd) -{ - struct saa7127_state *state = to_state(sd); - - v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz"); - v4l2_info(sd, "Input: %s\n", state->input_type ? "color bars" : "normal"); - v4l2_info(sd, "Output: %s\n", state->video_enable ? - output_strs[state->output_type] : "disabled"); - v4l2_info(sd, "WSS: %s\n", state->wss_enable ? - wss_strs[state->wss_mode] : "disabled"); - v4l2_info(sd, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled"); - v4l2_info(sd, "CC: %s\n", state->cc_enable ? "enabled" : "disabled"); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops saa7127_core_ops = { - .log_status = saa7127_log_status, - .g_chip_ident = saa7127_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = saa7127_g_register, - .s_register = saa7127_s_register, -#endif -}; - -static const struct v4l2_subdev_video_ops saa7127_video_ops = { - .s_std_output = saa7127_s_std_output, - .s_routing = saa7127_s_routing, - .s_stream = saa7127_s_stream, -}; - -static const struct v4l2_subdev_vbi_ops saa7127_vbi_ops = { - .s_vbi_data = saa7127_s_vbi_data, - .g_sliced_fmt = saa7127_g_sliced_fmt, -}; - -static const struct v4l2_subdev_ops saa7127_ops = { - .core = &saa7127_core_ops, - .video = &saa7127_video_ops, - .vbi = &saa7127_vbi_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int saa7127_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct saa7127_state *state; - struct v4l2_subdev *sd; - struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", - client->addr << 1); - - state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &saa7127_ops); - - /* First test register 0: Bits 5-7 are a version ID (should be 0), - and bit 2 should also be 0. - This is rather general, so the second test is more specific and - looks at the 'ending point of burst in clock cycles' which is - 0x1d after a reset and not expected to ever change. */ - if ((saa7127_read(sd, 0) & 0xe4) != 0 || - (saa7127_read(sd, 0x29) & 0x3f) != 0x1d) { - v4l2_dbg(1, debug, sd, "saa7127 not found\n"); - kfree(state); - return -ENODEV; - } - - if (id->driver_data) { /* Chip type is already known */ - state->ident = id->driver_data; - } else { /* Needs detection */ - int read_result; - - /* Detect if it's an saa7129 */ - read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2); - saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa); - if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { - saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, - read_result); - state->ident = V4L2_IDENT_SAA7129; - strlcpy(client->name, "saa7129", I2C_NAME_SIZE); - } else { - state->ident = V4L2_IDENT_SAA7127; - strlcpy(client->name, "saa7127", I2C_NAME_SIZE); - } - } - - v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, - client->addr << 1, client->adapter->name); - - v4l2_dbg(1, debug, sd, "Configuring encoder\n"); - saa7127_write_inittab(sd, saa7127_init_config_common); - saa7127_set_std(sd, V4L2_STD_NTSC); - saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH); - saa7127_set_vps(sd, &vbi); - saa7127_set_wss(sd, &vbi); - saa7127_set_cc(sd, &vbi); - saa7127_set_xds(sd, &vbi); - if (test_image == 1) - /* The Encoder has an internal Colorbar generator */ - /* This can be used for debugging */ - saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE); - else - saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL); - saa7127_set_video_enable(sd, 1); - - if (state->ident == V4L2_IDENT_SAA7129) - saa7127_write_inittab(sd, saa7129_init_config_extra); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - /* Turn off TV output */ - saa7127_set_video_enable(sd, 0); - kfree(to_state(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct i2c_device_id saa7127_id[] = { - { "saa7127_auto", 0 }, /* auto-detection */ - { "saa7126", V4L2_IDENT_SAA7127 }, - { "saa7127", V4L2_IDENT_SAA7127 }, - { "saa7128", V4L2_IDENT_SAA7129 }, - { "saa7129", V4L2_IDENT_SAA7129 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, saa7127_id); - -static struct i2c_driver saa7127_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "saa7127", - }, - .probe = saa7127_probe, - .remove = saa7127_remove, - .id_table = saa7127_id, -}; - -static __init int init_saa7127(void) -{ - return i2c_add_driver(&saa7127_driver); -} - -static __exit void exit_saa7127(void) -{ - i2c_del_driver(&saa7127_driver); -} - -module_init(init_saa7127); -module_exit(exit_saa7127); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -config VIDEO_SAA7134 - tristate "Philips SAA7134 support" - depends on VIDEO_DEV && PCI && I2C - select VIDEOBUF_DMA_SG - select VIDEO_TUNER - select VIDEO_TVEEPROM - select CRC32 - select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO - ---help--- - This is a video4linux driver for Philips SAA713x based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called saa7134. - -config VIDEO_SAA7134_ALSA - tristate "Philips SAA7134 DMA audio support" - depends on VIDEO_SAA7134 && SND - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio in - Philips SAA713x based TV cards using ALSA - - To compile this driver as a module, choose M here: the - module will be called saa7134-alsa. - -config VIDEO_SAA7134_RC - bool "Philips SAA7134 Remote Controller support" - depends on RC_CORE - depends on VIDEO_SAA7134 - depends on !(RC_CORE=m && VIDEO_SAA7134=y) - default y - ---help--- - Enables Remote Controller support on saa7134 driver. - -config VIDEO_SAA7134_DVB - tristate "DVB/ATSC Support for saa7134 based TV cards" - depends on VIDEO_SAA7134 && DVB_CORE - select VIDEOBUF_DVB - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_TDA1004X if !DVB_FE_CUSTOMISE - select DVB_NXT200X if !DVB_FE_CUSTOMISE - select DVB_TDA10086 if !DVB_FE_CUSTOMISE - select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select DVB_ISL6405 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select DVB_ZL10036 if !DVB_FE_CUSTOMISE - select DVB_MT312 if !DVB_FE_CUSTOMISE - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_LGDT3305 if !DVB_FE_CUSTOMISE - select DVB_TDA10048 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select DVB_ZL10039 if !DVB_FE_CUSTOMISE - ---help--- - This adds support for DVB cards based on the - Philips saa7134 chip. - - To compile this driver as a module, choose M here: the - module will be called saa7134-dvb. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ - -saa7134-y := saa7134-cards.o saa7134-core.o saa7134-i2c.o -saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o -saa7134-y += saa7134-video.o -saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o - -obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o - -obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o - -obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa6752hs.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa6752hs.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa6752hs.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa6752hs.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1023 +0,0 @@ - /* - saa6752hs - i2c-driver for the saa6752hs by Philips - - Copyright (C) 2004 Andrew de Quincey - - AC-3 support: - - Copyright (C) 2008 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License vs published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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., 675 Mvss Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MPEG_VIDEO_TARGET_BITRATE_MAX 27000 -#define MPEG_VIDEO_MAX_BITRATE_MAX 27000 -#define MPEG_TOTAL_TARGET_BITRATE_MAX 27000 -#define MPEG_PID_MAX ((1 << 14) - 1) - - -MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); -MODULE_AUTHOR("Andrew de Quincey"); -MODULE_LICENSE("GPL"); - -enum saa6752hs_videoformat { - SAA6752HS_VF_D1 = 0, /* standard D1 video format: 720x576 */ - SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */ - SAA6752HS_VF_1_2_D1 = 2,/* 1/2D1 video format: 352x576 */ - SAA6752HS_VF_SIF = 3, /* SIF video format: 352x288 */ - SAA6752HS_VF_UNKNOWN, -}; - -struct saa6752hs_mpeg_params { - /* transport streams */ - __u16 ts_pid_pmt; - __u16 ts_pid_audio; - __u16 ts_pid_video; - __u16 ts_pid_pcr; - - /* audio */ - enum v4l2_mpeg_audio_encoding au_encoding; - enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate; - enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate; - - /* video */ - enum v4l2_mpeg_video_aspect vi_aspect; - enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode; - __u32 vi_bitrate; - __u32 vi_bitrate_peak; -}; - -static const struct v4l2_format v4l2_format_table[] = -{ - [SAA6752HS_VF_D1] = - { .fmt = { .pix = { .width = 720, .height = 576 }}}, - [SAA6752HS_VF_2_3_D1] = - { .fmt = { .pix = { .width = 480, .height = 576 }}}, - [SAA6752HS_VF_1_2_D1] = - { .fmt = { .pix = { .width = 352, .height = 576 }}}, - [SAA6752HS_VF_SIF] = - { .fmt = { .pix = { .width = 352, .height = 288 }}}, - [SAA6752HS_VF_UNKNOWN] = - { .fmt = { .pix = { .width = 0, .height = 0}}}, -}; - -struct saa6752hs_state { - struct v4l2_subdev sd; - int chip; - u32 revision; - int has_ac3; - struct saa6752hs_mpeg_params params; - enum saa6752hs_videoformat video_format; - v4l2_std_id standard; -}; - -enum saa6752hs_command { - SAA6752HS_COMMAND_RESET = 0, - SAA6752HS_COMMAND_STOP = 1, - SAA6752HS_COMMAND_START = 2, - SAA6752HS_COMMAND_PAUSE = 3, - SAA6752HS_COMMAND_RECONFIGURE = 4, - SAA6752HS_COMMAND_SLEEP = 5, - SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6, - - SAA6752HS_COMMAND_MAX -}; - -static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa6752hs_state, sd); -} - -/* ---------------------------------------------------------------------- */ - -static u8 PAT[] = { - 0xc2, /* i2c register */ - 0x00, /* table number for encoder */ - - 0x47, /* sync */ - 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */ - 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */ - - 0x00, /* PSI pointer to start of table */ - - 0x00, /* tid(0) */ - 0xb0, 0x0d, /* section_syntax_indicator(1), section_length(13) */ - - 0x00, 0x01, /* transport_stream_id(1) */ - - 0xc1, /* version_number(0), current_next_indicator(1) */ - - 0x00, 0x00, /* section_number(0), last_section_number(0) */ - - 0x00, 0x01, /* program_number(1) */ - - 0xe0, 0x00, /* PMT PID */ - - 0x00, 0x00, 0x00, 0x00 /* CRC32 */ -}; - -static u8 PMT[] = { - 0xc2, /* i2c register */ - 0x01, /* table number for encoder */ - - 0x47, /* sync */ - 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */ - 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */ - - 0x00, /* PSI pointer to start of table */ - - 0x02, /* tid(2) */ - 0xb0, 0x17, /* section_syntax_indicator(1), section_length(23) */ - - 0x00, 0x01, /* program_number(1) */ - - 0xc1, /* version_number(0), current_next_indicator(1) */ - - 0x00, 0x00, /* section_number(0), last_section_number(0) */ - - 0xe0, 0x00, /* PCR_PID */ - - 0xf0, 0x00, /* program_info_length(0) */ - - 0x02, 0xe0, 0x00, 0xf0, 0x00, /* video stream type(2), pid */ - 0x04, 0xe0, 0x00, 0xf0, 0x00, /* audio stream type(4), pid */ - - 0x00, 0x00, 0x00, 0x00 /* CRC32 */ -}; - -static u8 PMT_AC3[] = { - 0xc2, /* i2c register */ - 0x01, /* table number for encoder(1) */ - 0x47, /* sync */ - - 0x40, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */ - 0x10, /* PMT PID (0x0010) */ - 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */ - - 0x00, /* PSI pointer to start of table */ - - 0x02, /* TID (2) */ - 0xb0, 0x1a, /* section_syntax_indicator(1), section_length(26) */ - - 0x00, 0x01, /* program_number(1) */ - - 0xc1, /* version_number(0), current_next_indicator(1) */ - - 0x00, 0x00, /* section_number(0), last_section_number(0) */ - - 0xe1, 0x04, /* PCR_PID (0x0104) */ - - 0xf0, 0x00, /* program_info_length(0) */ - - 0x02, 0xe1, 0x00, 0xf0, 0x00, /* video stream type(2), pid */ - 0x06, 0xe1, 0x03, 0xf0, 0x03, /* audio stream type(6), pid */ - 0x6a, /* AC3 */ - 0x01, /* Descriptor_length(1) */ - 0x00, /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */ - - 0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */ -}; - -static struct saa6752hs_mpeg_params param_defaults = -{ - .ts_pid_pmt = 16, - .ts_pid_video = 260, - .ts_pid_audio = 256, - .ts_pid_pcr = 259, - - .vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3, - .vi_bitrate = 4000, - .vi_bitrate_peak = 6000, - .vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - - .au_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - .au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K, - .au_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_256K, -}; - -/* ---------------------------------------------------------------------- */ - -static int saa6752hs_chip_command(struct i2c_client *client, - enum saa6752hs_command command) -{ - unsigned char buf[3]; - unsigned long timeout; - int status = 0; - - /* execute the command */ - switch(command) { - case SAA6752HS_COMMAND_RESET: - buf[0] = 0x00; - break; - - case SAA6752HS_COMMAND_STOP: - buf[0] = 0x03; - break; - - case SAA6752HS_COMMAND_START: - buf[0] = 0x02; - break; - - case SAA6752HS_COMMAND_PAUSE: - buf[0] = 0x04; - break; - - case SAA6752HS_COMMAND_RECONFIGURE: - buf[0] = 0x05; - break; - - case SAA6752HS_COMMAND_SLEEP: - buf[0] = 0x06; - break; - - case SAA6752HS_COMMAND_RECONFIGURE_FORCE: - buf[0] = 0x07; - break; - - default: - return -EINVAL; - } - - /* set it and wait for it to be so */ - i2c_master_send(client, buf, 1); - timeout = jiffies + HZ * 3; - for (;;) { - /* get the current status */ - buf[0] = 0x10; - i2c_master_send(client, buf, 1); - i2c_master_recv(client, buf, 1); - - if (!(buf[0] & 0x20)) - break; - if (time_after(jiffies,timeout)) { - status = -ETIMEDOUT; - break; - } - - msleep(10); - } - - /* delay a bit to let encoder settle */ - msleep(50); - - return status; -} - - -static inline void set_reg8(struct i2c_client *client, uint8_t reg, uint8_t val) -{ - u8 buf[2]; - - buf[0] = reg; - buf[1] = val; - i2c_master_send(client, buf, 2); -} - -static inline void set_reg16(struct i2c_client *client, uint8_t reg, uint16_t val) -{ - u8 buf[3]; - - buf[0] = reg; - buf[1] = val >> 8; - buf[2] = val & 0xff; - i2c_master_send(client, buf, 3); -} - -static int saa6752hs_set_bitrate(struct i2c_client *client, - struct saa6752hs_state *h) -{ - struct saa6752hs_mpeg_params *params = &h->params; - int tot_bitrate; - int is_384k; - - /* set the bitrate mode */ - set_reg8(client, 0x71, - params->vi_bitrate_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); - - /* set the video bitrate */ - if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) { - /* set the target bitrate */ - set_reg16(client, 0x80, params->vi_bitrate); - - /* set the max bitrate */ - set_reg16(client, 0x81, params->vi_bitrate_peak); - tot_bitrate = params->vi_bitrate_peak; - } else { - /* set the target bitrate (no max bitrate for CBR) */ - set_reg16(client, 0x81, params->vi_bitrate); - tot_bitrate = params->vi_bitrate; - } - - /* set the audio encoding */ - set_reg8(client, 0x93, - params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3); - - /* set the audio bitrate */ - if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) - is_384k = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate; - else - is_384k = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate; - set_reg8(client, 0x94, is_384k); - tot_bitrate += is_384k ? 384 : 256; - - /* Note: the total max bitrate is determined by adding the video and audio - bitrates together and also adding an extra 768kbit/s to stay on the - safe side. If more control should be required, then an extra MPEG control - should be added. */ - tot_bitrate += 768; - if (tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX) - tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX; - - /* set the total bitrate */ - set_reg16(client, 0xb1, tot_bitrate); - return 0; -} - - -static int get_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params, - struct v4l2_ext_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; - break; - case V4L2_CID_MPEG_STREAM_PID_PMT: - ctrl->value = params->ts_pid_pmt; - break; - case V4L2_CID_MPEG_STREAM_PID_AUDIO: - ctrl->value = params->ts_pid_audio; - break; - case V4L2_CID_MPEG_STREAM_PID_VIDEO: - ctrl->value = params->ts_pid_video; - break; - case V4L2_CID_MPEG_STREAM_PID_PCR: - ctrl->value = params->ts_pid_pcr; - break; - case V4L2_CID_MPEG_AUDIO_ENCODING: - ctrl->value = params->au_encoding; - break; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - ctrl->value = params->au_l2_bitrate; - break; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - if (!has_ac3) - return -EINVAL; - ctrl->value = params->au_ac3_bitrate; - break; - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - ctrl->value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - ctrl->value = params->vi_aspect; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - ctrl->value = params->vi_bitrate * 1000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - ctrl->value = params->vi_bitrate_peak * 1000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - ctrl->value = params->vi_bitrate_mode; - break; - default: - return -EINVAL; - } - return 0; -} - -static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params, - struct v4l2_ext_control *ctrl, int set) -{ - int old = 0, new; - - new = ctrl->value; - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; - if (set && new != old) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_STREAM_PID_PMT: - old = params->ts_pid_pmt; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_pmt = new; - break; - case V4L2_CID_MPEG_STREAM_PID_AUDIO: - old = params->ts_pid_audio; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_audio = new; - break; - case V4L2_CID_MPEG_STREAM_PID_VIDEO: - old = params->ts_pid_video; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_video = new; - break; - case V4L2_CID_MPEG_STREAM_PID_PCR: - old = params->ts_pid_pcr; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_pcr = new; - break; - case V4L2_CID_MPEG_AUDIO_ENCODING: - old = params->au_encoding; - if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && - (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3)) - return -ERANGE; - params->au_encoding = new; - break; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - old = params->au_l2_bitrate; - if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K && - new != V4L2_MPEG_AUDIO_L2_BITRATE_384K) - return -ERANGE; - if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K) - new = V4L2_MPEG_AUDIO_L2_BITRATE_256K; - else - new = V4L2_MPEG_AUDIO_L2_BITRATE_384K; - params->au_l2_bitrate = new; - break; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - if (!has_ac3) - return -EINVAL; - old = params->au_ac3_bitrate; - if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K && - new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K) - return -ERANGE; - if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K) - new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K; - else - new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K; - params->au_ac3_bitrate = new; - break; - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; - if (set && new != old) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - if (set && new != old) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - old = params->vi_aspect; - if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 && - new != V4L2_MPEG_VIDEO_ASPECT_4x3) - return -ERANGE; - if (new != V4L2_MPEG_VIDEO_ASPECT_16x9) - new = V4L2_MPEG_VIDEO_ASPECT_4x3; - params->vi_aspect = new; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - old = params->vi_bitrate * 1000; - new = 1000 * (new / 1000); - if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - return -ERANGE; - if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; - params->vi_bitrate = new / 1000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - old = params->vi_bitrate_peak * 1000; - new = 1000 * (new / 1000); - if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - return -ERANGE; - if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; - params->vi_bitrate_peak = new / 1000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - old = params->vi_bitrate_mode; - params->vi_bitrate_mode = new; - break; - default: - return -EINVAL; - } - ctrl->value = new; - return 0; -} - - -static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) -{ - struct saa6752hs_state *h = to_state(sd); - struct saa6752hs_mpeg_params *params = &h->params; - int err; - - switch (qctrl->id) { - case V4L2_CID_MPEG_AUDIO_ENCODING: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : - V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2); - - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_L2_BITRATE_256K, - V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, - V4L2_MPEG_AUDIO_L2_BITRATE_256K); - - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - if (!h->has_ac3) - return -EINVAL; - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_AC3_BITRATE_256K, - V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1, - V4L2_MPEG_AUDIO_AC3_BITRATE_256K); - - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); - - case V4L2_CID_MPEG_VIDEO_ENCODING: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2); - - case V4L2_CID_MPEG_VIDEO_ASPECT: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_VIDEO_ASPECT_4x3, - V4L2_MPEG_VIDEO_ASPECT_16x9, 1, - V4L2_MPEG_VIDEO_ASPECT_4x3); - - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); - if (err == 0 && - params->vi_bitrate_mode == - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return err; - - case V4L2_CID_MPEG_STREAM_TYPE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_STREAM_TYPE_MPEG2_TS, - V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1, - V4L2_MPEG_STREAM_TYPE_MPEG2_TS); - - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); - case V4L2_CID_MPEG_VIDEO_BITRATE: - return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000); - case V4L2_CID_MPEG_STREAM_PID_PMT: - return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16); - case V4L2_CID_MPEG_STREAM_PID_AUDIO: - return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260); - case V4L2_CID_MPEG_STREAM_PID_VIDEO: - return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256); - case V4L2_CID_MPEG_STREAM_PID_PCR: - return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259); - - default: - break; - } - return -EINVAL; -} - -static int saa6752hs_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qmenu) -{ - static const u32 mpeg_audio_encoding[] = { - V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - V4L2_CTRL_MENU_IDS_END - }; - static const u32 mpeg_audio_ac3_encoding[] = { - V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - V4L2_MPEG_AUDIO_ENCODING_AC3, - V4L2_CTRL_MENU_IDS_END - }; - static u32 mpeg_audio_l2_bitrate[] = { - V4L2_MPEG_AUDIO_L2_BITRATE_256K, - V4L2_MPEG_AUDIO_L2_BITRATE_384K, - V4L2_CTRL_MENU_IDS_END - }; - static u32 mpeg_audio_ac3_bitrate[] = { - V4L2_MPEG_AUDIO_AC3_BITRATE_256K, - V4L2_MPEG_AUDIO_AC3_BITRATE_384K, - V4L2_CTRL_MENU_IDS_END - }; - struct saa6752hs_state *h = to_state(sd); - struct v4l2_queryctrl qctrl; - int err; - - qctrl.id = qmenu->id; - err = saa6752hs_queryctrl(sd, &qctrl); - if (err) - return err; - switch (qmenu->id) { - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - return v4l2_ctrl_query_menu_valid_items(qmenu, - mpeg_audio_l2_bitrate); - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - if (!h->has_ac3) - return -EINVAL; - return v4l2_ctrl_query_menu_valid_items(qmenu, - mpeg_audio_ac3_bitrate); - case V4L2_CID_MPEG_AUDIO_ENCODING: - return v4l2_ctrl_query_menu_valid_items(qmenu, - h->has_ac3 ? mpeg_audio_ac3_encoding : - mpeg_audio_encoding); - } - return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); -} - -static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes) -{ - unsigned char buf[9], buf2[4]; - struct saa6752hs_state *h = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned size; - u32 crc; - unsigned char localPAT[256]; - unsigned char localPMT[256]; - - /* Set video format - must be done first as it resets other settings */ - set_reg8(client, 0x41, h->video_format); - - /* Set number of lines in input signal */ - set_reg8(client, 0x40, (h->standard & V4L2_STD_525_60) ? 1 : 0); - - /* set bitrate */ - saa6752hs_set_bitrate(client, h); - - /* Set GOP structure {3, 13} */ - set_reg16(client, 0x72, 0x030d); - - /* Set minimum Q-scale {4} */ - set_reg8(client, 0x82, 0x04); - - /* Set maximum Q-scale {12} */ - set_reg8(client, 0x83, 0x0c); - - /* Set Output Protocol */ - set_reg8(client, 0xd0, 0x81); - - /* Set video output stream format {TS} */ - set_reg8(client, 0xb0, 0x05); - - /* Set leading null byte for TS */ - set_reg16(client, 0xf6, leading_null_bytes); - - /* compute PAT */ - memcpy(localPAT, PAT, sizeof(PAT)); - localPAT[17] = 0xe0 | ((h->params.ts_pid_pmt >> 8) & 0x0f); - localPAT[18] = h->params.ts_pid_pmt & 0xff; - crc = crc32_be(~0, &localPAT[7], sizeof(PAT) - 7 - 4); - localPAT[sizeof(PAT) - 4] = (crc >> 24) & 0xFF; - localPAT[sizeof(PAT) - 3] = (crc >> 16) & 0xFF; - localPAT[sizeof(PAT) - 2] = (crc >> 8) & 0xFF; - localPAT[sizeof(PAT) - 1] = crc & 0xFF; - - /* compute PMT */ - if (h->params.au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) { - size = sizeof(PMT_AC3); - memcpy(localPMT, PMT_AC3, size); - } else { - size = sizeof(PMT); - memcpy(localPMT, PMT, size); - } - localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f); - localPMT[4] = h->params.ts_pid_pmt & 0xff; - localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F); - localPMT[16] = h->params.ts_pid_pcr & 0xFF; - localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F); - localPMT[21] = h->params.ts_pid_video & 0xFF; - localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F); - localPMT[26] = h->params.ts_pid_audio & 0xFF; - crc = crc32_be(~0, &localPMT[7], size - 7 - 4); - localPMT[size - 4] = (crc >> 24) & 0xFF; - localPMT[size - 3] = (crc >> 16) & 0xFF; - localPMT[size - 2] = (crc >> 8) & 0xFF; - localPMT[size - 1] = crc & 0xFF; - - /* Set Audio PID */ - set_reg16(client, 0xc1, h->params.ts_pid_audio); - - /* Set Video PID */ - set_reg16(client, 0xc0, h->params.ts_pid_video); - - /* Set PCR PID */ - set_reg16(client, 0xc4, h->params.ts_pid_pcr); - - /* Send SI tables */ - i2c_master_send(client, localPAT, sizeof(PAT)); - i2c_master_send(client, localPMT, size); - - /* mute then unmute audio. This removes buzzing artefacts */ - set_reg8(client, 0xa4, 1); - set_reg8(client, 0xa4, 0); - - /* start it going */ - saa6752hs_chip_command(client, SAA6752HS_COMMAND_START); - - /* readout current state */ - buf[0] = 0xE1; - buf[1] = 0xA7; - buf[2] = 0xFE; - buf[3] = 0x82; - buf[4] = 0xB0; - i2c_master_send(client, buf, 5); - i2c_master_recv(client, buf2, 4); - - /* change aspect ratio */ - buf[0] = 0xE0; - buf[1] = 0xA7; - buf[2] = 0xFE; - buf[3] = 0x82; - buf[4] = 0xB0; - buf[5] = buf2[0]; - switch (h->params.vi_aspect) { - case V4L2_MPEG_VIDEO_ASPECT_16x9: - buf[6] = buf2[1] | 0x40; - break; - case V4L2_MPEG_VIDEO_ASPECT_4x3: - default: - buf[6] = buf2[1] & 0xBF; - break; - } - buf[7] = buf2[2]; - buf[8] = buf2[3]; - i2c_master_send(client, buf, 9); - - return 0; -} - -static int saa6752hs_do_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls, int set) -{ - struct saa6752hs_state *h = to_state(sd); - struct saa6752hs_mpeg_params params; - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - params = h->params; - for (i = 0; i < ctrls->count; i++) { - int err = handle_ctrl(h->has_ac3, ¶ms, ctrls->controls + i, set); - - if (err) { - ctrls->error_idx = i; - return err; - } - } - if (set) - h->params = params; - return 0; -} - -static int saa6752hs_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls) -{ - return saa6752hs_do_ext_ctrls(sd, ctrls, 1); -} - -static int saa6752hs_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls) -{ - return saa6752hs_do_ext_ctrls(sd, ctrls, 0); -} - -static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls) -{ - struct saa6752hs_state *h = to_state(sd); - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - int err = get_ctrl(h->has_ac3, &h->params, ctrls->controls + i); - - if (err) { - ctrls->error_idx = i; - return err; - } - } - return 0; -} - -static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct saa6752hs_state *h = to_state(sd); - - if (h->video_format == SAA6752HS_VF_UNKNOWN) - h->video_format = SAA6752HS_VF_D1; - f->width = v4l2_format_table[h->video_format].fmt.pix.width; - f->height = v4l2_format_table[h->video_format].fmt.pix.height; - f->code = V4L2_MBUS_FMT_FIXED; - f->field = V4L2_FIELD_INTERLACED; - f->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct saa6752hs_state *h = to_state(sd); - int dist_352, dist_480, dist_720; - - if (f->code != V4L2_MBUS_FMT_FIXED) - return -EINVAL; - - /* - FIXME: translate and round width/height into EMPRESS - subsample type: - - type | PAL | NTSC - --------------------------- - SIF | 352x288 | 352x240 - 1/2 D1 | 352x576 | 352x480 - 2/3 D1 | 480x576 | 480x480 - D1 | 720x576 | 720x480 - */ - - dist_352 = abs(f->width - 352); - dist_480 = abs(f->width - 480); - dist_720 = abs(f->width - 720); - if (dist_720 < dist_480) { - f->width = 720; - f->height = 576; - h->video_format = SAA6752HS_VF_D1; - } else if (dist_480 < dist_352) { - f->width = 480; - f->height = 576; - h->video_format = SAA6752HS_VF_2_3_D1; - } else { - f->width = 352; - if (abs(f->height - 576) < - abs(f->height - 288)) { - f->height = 576; - h->video_format = SAA6752HS_VF_1_2_D1; - } else { - f->height = 288; - h->video_format = SAA6752HS_VF_SIF; - } - } - f->field = V4L2_FIELD_INTERLACED; - f->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct saa6752hs_state *h = to_state(sd); - - h->standard = std; - return 0; -} - -static int saa6752hs_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct saa6752hs_state *h = to_state(sd); - - return v4l2_chip_ident_i2c_client(client, - chip, h->chip, h->revision); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { - .g_chip_ident = saa6752hs_g_chip_ident, - .init = saa6752hs_init, - .queryctrl = saa6752hs_queryctrl, - .querymenu = saa6752hs_querymenu, - .g_ext_ctrls = saa6752hs_g_ext_ctrls, - .s_ext_ctrls = saa6752hs_s_ext_ctrls, - .try_ext_ctrls = saa6752hs_try_ext_ctrls, - .s_std = saa6752hs_s_std, -}; - -static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { - .s_mbus_fmt = saa6752hs_s_mbus_fmt, - .g_mbus_fmt = saa6752hs_g_mbus_fmt, -}; - -static const struct v4l2_subdev_ops saa6752hs_ops = { - .core = &saa6752hs_core_ops, - .video = &saa6752hs_video_ops, -}; - -static int saa6752hs_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL); - struct v4l2_subdev *sd; - u8 addr = 0x13; - u8 data[12]; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - if (h == NULL) - return -ENOMEM; - sd = &h->sd; - v4l2_i2c_subdev_init(sd, client, &saa6752hs_ops); - - i2c_master_send(client, &addr, 1); - i2c_master_recv(client, data, sizeof(data)); - h->chip = V4L2_IDENT_SAA6752HS; - h->revision = (data[8] << 8) | data[9]; - h->has_ac3 = 0; - if (h->revision == 0x0206) { - h->chip = V4L2_IDENT_SAA6752HS_AC3; - h->has_ac3 = 1; - v4l_info(client, "support AC-3\n"); - } - h->params = param_defaults; - h->standard = 0; /* Assume 625 input lines */ - return 0; -} - -static int saa6752hs_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id saa6752hs_id[] = { - { "saa6752hs", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, saa6752hs_id); - -static struct i2c_driver saa6752hs_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "saa6752hs", - }, - .probe = saa6752hs_probe, - .remove = saa6752hs_remove, - .id_table = saa6752hs_id, -}; - -static __init int init_saa6752hs(void) -{ - return i2c_add_driver(&saa6752hs_driver); -} - -static __exit void exit_saa6752hs(void) -{ - i2c_del_driver(&saa6752hs_driver); -} - -module_init(init_saa6752hs); -module_exit(exit_saa6752hs); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-alsa.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-alsa.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-alsa.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-alsa.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1209 +0,0 @@ -/* - * SAA713x ALSA support for V4L - * - * 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, version 2 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "saa7134.h" -#include "saa7134-reg.h" - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [alsa]"); - -/* - * Configuration macros - */ - -/* defaults */ -#define MIXER_ADDR_UNSELECTED -1 -#define MIXER_ADDR_TVTUNER 0 -#define MIXER_ADDR_LINE1 1 -#define MIXER_ADDR_LINE2 2 -#define MIXER_ADDR_LAST 2 - - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; - -module_param_array(index, int, NULL, 0444); -module_param_array(enable, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s)."); -MODULE_PARM_DESC(enable, "Enable (or not) the SAA7134 capture interface(s)."); - -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ##arg) - - - -/* - * Main chip structure - */ - -typedef struct snd_card_saa7134 { - struct snd_card *card; - spinlock_t mixer_lock; - int mixer_volume[MIXER_ADDR_LAST+1][2]; - int capture_source_addr; - int capture_source[2]; - struct snd_kcontrol *capture_ctl[MIXER_ADDR_LAST+1]; - struct pci_dev *pci; - struct saa7134_dev *dev; - - unsigned long iobase; - s16 irq; - u16 mute_was_on; - - spinlock_t lock; -} snd_card_saa7134_t; - - -/* - * PCM structure - */ - -typedef struct snd_card_saa7134_pcm { - struct saa7134_dev *dev; - - spinlock_t lock; - - struct snd_pcm_substream *substream; -} snd_card_saa7134_pcm_t; - -static struct snd_card *snd_saa7134_cards[SNDRV_CARDS]; - - -/* - * saa7134 DMA audio stop - * - * Called when the capture device is released or the buffer overflows - * - * - Copied verbatim from saa7134-oss's dsp_dma_stop. - * - */ - -static void saa7134_dma_stop(struct saa7134_dev *dev) -{ - dev->dmasound.dma_blk = -1; - dev->dmasound.dma_running = 0; - saa7134_set_dmabits(dev); -} - -/* - * saa7134 DMA audio start - * - * Called when preparing the capture device for use - * - * - Copied verbatim from saa7134-oss's dsp_dma_start. - * - */ - -static void saa7134_dma_start(struct saa7134_dev *dev) -{ - dev->dmasound.dma_blk = 0; - dev->dmasound.dma_running = 1; - saa7134_set_dmabits(dev); -} - -/* - * saa7134 audio DMA IRQ handler - * - * Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt - * Handles shifting between the 2 buffers, manages the read counters, - * and notifies ALSA when periods elapse - * - * - Mostly copied from saa7134-oss's saa7134_irq_oss_done. - * - */ - -static void saa7134_irq_alsa_done(struct saa7134_dev *dev, - unsigned long status) -{ - int next_blk, reg = 0; - - spin_lock(&dev->slock); - if (UNSET == dev->dmasound.dma_blk) { - dprintk("irq: recording stopped\n"); - goto done; - } - if (0 != (status & 0x0f000000)) - dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); - if (0 == (status & 0x10000000)) { - /* odd */ - if (0 == (dev->dmasound.dma_blk & 0x01)) - reg = SAA7134_RS_BA1(6); - } else { - /* even */ - if (1 == (dev->dmasound.dma_blk & 0x01)) - reg = SAA7134_RS_BA2(6); - } - if (0 == reg) { - dprintk("irq: field oops [%s]\n", - (status & 0x10000000) ? "even" : "odd"); - goto done; - } - - if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { - dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count, - dev->dmasound.bufsize, dev->dmasound.blocks); - spin_unlock(&dev->slock); - snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN); - return; - } - - /* next block addr */ - next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; - saa_writel(reg,next_blk * dev->dmasound.blksize); - if (debug > 2) - dprintk("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n", - (status & 0x10000000) ? "even" : "odd ", next_blk, - next_blk * dev->dmasound.blksize, dev->dmasound.blocks, dev->dmasound.blksize, dev->dmasound.read_count); - - /* update status & wake waiting readers */ - dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks; - dev->dmasound.read_count += dev->dmasound.blksize; - - dev->dmasound.recording_on = reg; - - if (dev->dmasound.read_count >= snd_pcm_lib_period_bytes(dev->dmasound.substream)) { - spin_unlock(&dev->slock); - snd_pcm_period_elapsed(dev->dmasound.substream); - spin_lock(&dev->slock); - } - - done: - spin_unlock(&dev->slock); - -} - -/* - * IRQ request handler - * - * Runs along with saa7134's IRQ handler, discards anything that isn't - * DMA sound - * - */ - -static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id) -{ - struct saa7134_dmasound *dmasound = dev_id; - struct saa7134_dev *dev = dmasound->priv_data; - - unsigned long report, status; - int loop, handled = 0; - - for (loop = 0; loop < 10; loop++) { - report = saa_readl(SAA7134_IRQ_REPORT); - status = saa_readl(SAA7134_IRQ_STATUS); - - if (report & SAA7134_IRQ_REPORT_DONE_RA3) { - handled = 1; - saa_writel(SAA7134_IRQ_REPORT, - SAA7134_IRQ_REPORT_DONE_RA3); - saa7134_irq_alsa_done(dev, status); - } else { - goto out; - } - } - - if (loop == 10) { - dprintk("error! looping IRQ!"); - } - -out: - return IRQ_RETVAL(handled); -} - -/* - * ALSA capture trigger - * - * - One of the ALSA capture callbacks. - * - * Called whenever a capture is started or stopped. Must be defined, - * but there's nothing we want to do here - * - */ - -static int snd_card_saa7134_capture_trigger(struct snd_pcm_substream * substream, - int cmd) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_card_saa7134_pcm_t *pcm = runtime->private_data; - struct saa7134_dev *dev=pcm->dev; - int err = 0; - - spin_lock(&dev->slock); - if (cmd == SNDRV_PCM_TRIGGER_START) { - /* start dma */ - saa7134_dma_start(dev); - } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { - /* stop dma */ - saa7134_dma_stop(dev); - } else { - err = -EINVAL; - } - spin_unlock(&dev->slock); - - return err; -} - -/* - * DMA buffer initialization - * - * Uses V4L functions to initialize the DMA. Shouldn't be necessary in - * ALSA, but I was unable to use ALSA's own DMA, and had to force the - * usage of V4L's - * - * - Copied verbatim from saa7134-oss. - * - */ - -static int dsp_buffer_init(struct saa7134_dev *dev) -{ - int err; - - BUG_ON(!dev->dmasound.bufsize); - - videobuf_dma_init(&dev->dmasound.dma); - err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, - (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); - if (0 != err) - return err; - return 0; -} - -/* - * DMA buffer release - * - * Called after closing the device, during snd_card_saa7134_capture_close - * - */ - -static int dsp_buffer_free(struct saa7134_dev *dev) -{ - BUG_ON(!dev->dmasound.blksize); - - videobuf_dma_free(&dev->dmasound.dma); - - dev->dmasound.blocks = 0; - dev->dmasound.blksize = 0; - dev->dmasound.bufsize = 0; - - return 0; -} - -/* - * Setting the capture source and updating the ALSA controls - */ -static int snd_saa7134_capsrc_set(struct snd_kcontrol *kcontrol, - int left, int right, bool force_notify) -{ - snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); - int change = 0, addr = kcontrol->private_value; - int active, old_addr; - u32 anabar, xbarin; - int analog_io, rate; - struct saa7134_dev *dev; - - dev = chip->dev; - - spin_lock_irq(&chip->mixer_lock); - - active = left != 0 || right != 0; - old_addr = chip->capture_source_addr; - - /* The active capture source cannot be deactivated */ - if (active) { - change = old_addr != addr || - chip->capture_source[0] != left || - chip->capture_source[1] != right; - - chip->capture_source[0] = left; - chip->capture_source[1] = right; - chip->capture_source_addr = addr; - dev->dmasound.input = addr; - } - spin_unlock_irq(&chip->mixer_lock); - - if (change) { - switch (dev->pci->device) { - - case PCI_DEVICE_ID_PHILIPS_SAA7134: - switch (addr) { - case MIXER_ADDR_TVTUNER: - saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, - 0xc0, 0xc0); - saa_andorb(SAA7134_SIF_SAMPLE_FREQ, - 0x03, 0x00); - break; - case MIXER_ADDR_LINE1: - case MIXER_ADDR_LINE2: - analog_io = (MIXER_ADDR_LINE1 == addr) ? - 0x00 : 0x08; - rate = (32000 == dev->dmasound.rate) ? - 0x01 : 0x03; - saa_andorb(SAA7134_ANALOG_IO_SELECT, - 0x08, analog_io); - saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, - 0xc0, 0x80); - saa_andorb(SAA7134_SIF_SAMPLE_FREQ, - 0x03, rate); - break; - } - - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - xbarin = 0x03; /* adc */ - anabar = 0; - switch (addr) { - case MIXER_ADDR_TVTUNER: - xbarin = 0; /* Demodulator */ - anabar = 2; /* DACs */ - break; - case MIXER_ADDR_LINE1: - anabar = 0; /* aux1, aux1 */ - break; - case MIXER_ADDR_LINE2: - anabar = 9; /* aux2, aux2 */ - break; - } - - /* output xbar always main channel */ - saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, - 0xbbbb10); - - if (left || right) { - /* We've got data, turn the input on */ - saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, - xbarin); - saa_writel(SAA7133_ANALOG_IO_SELECT, anabar); - } else { - saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, - 0); - saa_writel(SAA7133_ANALOG_IO_SELECT, 0); - } - break; - } - } - - if (change) { - if (force_notify) - snd_ctl_notify(chip->card, - SNDRV_CTL_EVENT_MASK_VALUE, - &chip->capture_ctl[addr]->id); - - if (old_addr != MIXER_ADDR_UNSELECTED && old_addr != addr) - snd_ctl_notify(chip->card, - SNDRV_CTL_EVENT_MASK_VALUE, - &chip->capture_ctl[old_addr]->id); - } - - return change; -} - -/* - * ALSA PCM preparation - * - * - One of the ALSA capture callbacks. - * - * Called right after the capture device is opened, this function configures - * the buffer using the previously defined functions, allocates the memory, - * sets up the hardware registers, and then starts the DMA. When this function - * returns, the audio should be flowing. - * - */ - -static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int bswap, sign; - u32 fmt, control; - snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); - struct saa7134_dev *dev; - snd_card_saa7134_pcm_t *pcm = runtime->private_data; - - pcm->dev->dmasound.substream = substream; - - dev = saa7134->dev; - - if (snd_pcm_format_width(runtime->format) == 8) - fmt = 0x00; - else - fmt = 0x01; - - if (snd_pcm_format_signed(runtime->format)) - sign = 1; - else - sign = 0; - - if (snd_pcm_format_big_endian(runtime->format)) - bswap = 1; - else - bswap = 0; - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - if (1 == runtime->channels) - fmt |= (1 << 3); - if (2 == runtime->channels) - fmt |= (3 << 3); - if (sign) - fmt |= 0x04; - - fmt |= (MIXER_ADDR_TVTUNER == dev->dmasound.input) ? 0xc0 : 0x80; - saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff)); - saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8); - saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16); - saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt); - - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - if (1 == runtime->channels) - fmt |= (1 << 4); - if (2 == runtime->channels) - fmt |= (2 << 4); - if (!sign) - fmt |= 0x04; - saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1); - saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24)); - break; - } - - dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", - runtime->format, runtime->channels, fmt, - bswap ? 'b' : '-'); - /* dma: setup channel 6 (= AUDIO) */ - control = SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (dev->dmasound.pt.dma >> 12); - if (bswap) - control |= SAA7134_RS_CONTROL_BSWAP; - - saa_writel(SAA7134_RS_BA1(6),0); - saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize); - saa_writel(SAA7134_RS_PITCH(6),0); - saa_writel(SAA7134_RS_CONTROL(6),control); - - dev->dmasound.rate = runtime->rate; - - /* Setup and update the card/ALSA controls */ - snd_saa7134_capsrc_set(saa7134->capture_ctl[dev->dmasound.input], 1, 1, - true); - - return 0; - -} - -/* - * ALSA pointer fetching - * - * - One of the ALSA capture callbacks. - * - * Called whenever a period elapses, it must return the current hardware - * position of the buffer. - * Also resets the read counter used to prevent overruns - * - */ - -static snd_pcm_uframes_t -snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_card_saa7134_pcm_t *pcm = runtime->private_data; - struct saa7134_dev *dev=pcm->dev; - - if (dev->dmasound.read_count) { - dev->dmasound.read_count -= snd_pcm_lib_period_bytes(substream); - dev->dmasound.read_offset += snd_pcm_lib_period_bytes(substream); - if (dev->dmasound.read_offset == dev->dmasound.bufsize) - dev->dmasound.read_offset = 0; - } - - return bytes_to_frames(runtime, dev->dmasound.read_offset); -} - -/* - * ALSA hardware capabilities definition - * - * Report only 32kHz for ALSA: - * - * - SAA7133/35 uses DDEP (DemDec Easy Programming mode), which works in 32kHz - * only - * - SAA7134 for TV mode uses DemDec mode (32kHz) - * - Radio works in 32kHz only - * - When recording 48kHz from Line1/Line2, switching of capture source to TV - * means - * switching to 32kHz without any frequency translation - */ - -static struct snd_pcm_hardware snd_card_saa7134_capture = -{ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_U8 | \ - SNDRV_PCM_FMTBIT_U16_LE | \ - SNDRV_PCM_FMTBIT_U16_BE, - .rates = SNDRV_PCM_RATE_32000, - .rate_min = 32000, - .rate_max = 32000, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = (256*1024), - .period_bytes_min = 64, - .period_bytes_max = (256*1024), - .periods_min = 4, - .periods_max = 1024, -}; - -static void snd_card_saa7134_runtime_free(struct snd_pcm_runtime *runtime) -{ - snd_card_saa7134_pcm_t *pcm = runtime->private_data; - - kfree(pcm); -} - - -/* - * ALSA hardware params - * - * - One of the ALSA capture callbacks. - * - * Called on initialization, right before the PCM preparation - * - */ - -static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream, - struct snd_pcm_hw_params * hw_params) -{ - snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); - struct saa7134_dev *dev; - unsigned int period_size, periods; - int err; - - period_size = params_period_bytes(hw_params); - periods = params_periods(hw_params); - - if (period_size < 0x100 || period_size > 0x10000) - return -EINVAL; - if (periods < 4) - return -EINVAL; - if (period_size * periods > 1024 * 1024) - return -EINVAL; - - dev = saa7134->dev; - - if (dev->dmasound.blocks == periods && - dev->dmasound.blksize == period_size) - return 0; - - /* release the old buffer */ - if (substream->runtime->dma_area) { - saa7134_pgtable_free(dev->pci, &dev->dmasound.pt); - videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma); - dsp_buffer_free(dev); - substream->runtime->dma_area = NULL; - } - dev->dmasound.blocks = periods; - dev->dmasound.blksize = period_size; - dev->dmasound.bufsize = period_size * periods; - - err = dsp_buffer_init(dev); - if (0 != err) { - dev->dmasound.blocks = 0; - dev->dmasound.blksize = 0; - dev->dmasound.bufsize = 0; - return err; - } - - if (0 != (err = videobuf_dma_map(&dev->pci->dev, &dev->dmasound.dma))) { - dsp_buffer_free(dev); - return err; - } - if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) { - videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma); - dsp_buffer_free(dev); - return err; - } - if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt, - dev->dmasound.dma.sglist, - dev->dmasound.dma.sglen, - 0))) { - saa7134_pgtable_free(dev->pci, &dev->dmasound.pt); - videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma); - dsp_buffer_free(dev); - return err; - } - - /* I should be able to use runtime->dma_addr in the control - byte, but it doesn't work. So I allocate the DMA using the - V4L functions, and force ALSA to use that as the DMA area */ - - substream->runtime->dma_area = dev->dmasound.dma.vaddr; - substream->runtime->dma_bytes = dev->dmasound.bufsize; - substream->runtime->dma_addr = 0; - - return 0; - -} - -/* - * ALSA hardware release - * - * - One of the ALSA capture callbacks. - * - * Called after closing the device, but before snd_card_saa7134_capture_close - * It stops the DMA audio and releases the buffers. - * - */ - -static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream) -{ - snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); - struct saa7134_dev *dev; - - dev = saa7134->dev; - - if (substream->runtime->dma_area) { - saa7134_pgtable_free(dev->pci, &dev->dmasound.pt); - videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma); - dsp_buffer_free(dev); - substream->runtime->dma_area = NULL; - } - - return 0; -} - -/* - * ALSA capture finish - * - * - One of the ALSA capture callbacks. - * - * Called after closing the device. - * - */ - -static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream) -{ - snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); - struct saa7134_dev *dev = saa7134->dev; - - if (saa7134->mute_was_on) { - dev->ctl_mute = 1; - saa7134_tvaudio_setmute(dev); - } - return 0; -} - -/* - * ALSA capture start - * - * - One of the ALSA capture callbacks. - * - * Called when opening the device. It creates and populates the PCM - * structure - * - */ - -static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - snd_card_saa7134_pcm_t *pcm; - snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); - struct saa7134_dev *dev; - int amux, err; - - if (!saa7134) { - printk(KERN_ERR "BUG: saa7134 can't find device struct." - " Can't proceed with open\n"); - return -ENODEV; - } - dev = saa7134->dev; - mutex_lock(&dev->dmasound.lock); - - dev->dmasound.read_count = 0; - dev->dmasound.read_offset = 0; - - amux = dev->input->amux; - if ((amux < 1) || (amux > 3)) - amux = 1; - dev->dmasound.input = amux - 1; - - mutex_unlock(&dev->dmasound.lock); - - pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); - if (pcm == NULL) - return -ENOMEM; - - pcm->dev=saa7134->dev; - - spin_lock_init(&pcm->lock); - - pcm->substream = substream; - runtime->private_data = pcm; - runtime->private_free = snd_card_saa7134_runtime_free; - runtime->hw = snd_card_saa7134_capture; - - if (dev->ctl_mute != 0) { - saa7134->mute_was_on = 1; - dev->ctl_mute = 0; - saa7134_tvaudio_setmute(dev); - } - - err = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) - return err; - - err = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIODS, 2); - if (err < 0) - return err; - - return 0; -} - -/* - * page callback (needed for mmap) - */ - -static struct page *snd_card_saa7134_page(struct snd_pcm_substream *substream, - unsigned long offset) -{ - void *pageptr = substream->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -/* - * ALSA capture callbacks definition - */ - -static struct snd_pcm_ops snd_card_saa7134_capture_ops = { - .open = snd_card_saa7134_capture_open, - .close = snd_card_saa7134_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_card_saa7134_hw_params, - .hw_free = snd_card_saa7134_hw_free, - .prepare = snd_card_saa7134_capture_prepare, - .trigger = snd_card_saa7134_capture_trigger, - .pointer = snd_card_saa7134_capture_pointer, - .page = snd_card_saa7134_page, -}; - -/* - * ALSA PCM setup - * - * Called when initializing the board. Sets up the name and hooks up - * the callbacks - * - */ - -static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device) -{ - struct snd_pcm *pcm; - int err; - - if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0) - return err; - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_saa7134_capture_ops); - pcm->private_data = saa7134; - pcm->info_flags = 0; - strcpy(pcm->name, "SAA7134 PCM"); - return 0; -} - -#define SAA713x_VOLUME(xname, xindex, addr) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_saa7134_volume_info, \ - .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \ - .private_value = addr } - -static int snd_saa7134_volume_info(struct snd_kcontrol * kcontrol, - struct snd_ctl_elem_info * uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 20; - return 0; -} - -static int snd_saa7134_volume_get(struct snd_kcontrol * kcontrol, - struct snd_ctl_elem_value * ucontrol) -{ - snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); - int addr = kcontrol->private_value; - - ucontrol->value.integer.value[0] = chip->mixer_volume[addr][0]; - ucontrol->value.integer.value[1] = chip->mixer_volume[addr][1]; - return 0; -} - -static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol, - struct snd_ctl_elem_value * ucontrol) -{ - snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); - struct saa7134_dev *dev = chip->dev; - - int change, addr = kcontrol->private_value; - int left, right; - - left = ucontrol->value.integer.value[0]; - if (left < 0) - left = 0; - if (left > 20) - left = 20; - right = ucontrol->value.integer.value[1]; - if (right < 0) - right = 0; - if (right > 20) - right = 20; - spin_lock_irq(&chip->mixer_lock); - change = 0; - if (chip->mixer_volume[addr][0] != left) { - change = 1; - right = left; - } - if (chip->mixer_volume[addr][1] != right) { - change = 1; - left = right; - } - if (change) { - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - switch (addr) { - case MIXER_ADDR_TVTUNER: - left = 20; - break; - case MIXER_ADDR_LINE1: - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10, - (left > 10) ? 0x00 : 0x10); - break; - case MIXER_ADDR_LINE2: - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20, - (left > 10) ? 0x00 : 0x20); - break; - } - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - switch (addr) { - case MIXER_ADDR_TVTUNER: - left = 20; - break; - case MIXER_ADDR_LINE1: - saa_andorb(0x0594, 0x10, - (left > 10) ? 0x00 : 0x10); - break; - case MIXER_ADDR_LINE2: - saa_andorb(0x0594, 0x20, - (left > 10) ? 0x00 : 0x20); - break; - } - break; - } - chip->mixer_volume[addr][0] = left; - chip->mixer_volume[addr][1] = right; - } - spin_unlock_irq(&chip->mixer_lock); - return change; -} - -#define SAA713x_CAPSRC(xname, xindex, addr) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_saa7134_capsrc_info, \ - .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \ - .private_value = addr } - -static int snd_saa7134_capsrc_info(struct snd_kcontrol * kcontrol, - struct snd_ctl_elem_info * uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol, - struct snd_ctl_elem_value * ucontrol) -{ - snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); - int addr = kcontrol->private_value; - - spin_lock_irq(&chip->mixer_lock); - if (chip->capture_source_addr == addr) { - ucontrol->value.integer.value[0] = chip->capture_source[0]; - ucontrol->value.integer.value[1] = chip->capture_source[1]; - } else { - ucontrol->value.integer.value[0] = 0; - ucontrol->value.integer.value[1] = 0; - } - spin_unlock_irq(&chip->mixer_lock); - - return 0; -} - -static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol, - struct snd_ctl_elem_value * ucontrol) -{ - int left, right; - left = ucontrol->value.integer.value[0] & 1; - right = ucontrol->value.integer.value[1] & 1; - - return snd_saa7134_capsrc_set(kcontrol, left, right, false); -} - -static struct snd_kcontrol_new snd_saa7134_volume_controls[] = { -SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER), -SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1), -SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2), -}; - -static struct snd_kcontrol_new snd_saa7134_capture_controls[] = { -SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER), -SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1), -SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2), -}; - -/* - * ALSA mixer setup - * - * Called when initializing the board. Sets up the name and hooks up - * the callbacks - * - */ - -static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip) -{ - struct snd_card *card = chip->card; - struct snd_kcontrol *kcontrol; - unsigned int idx; - int err, addr; - - strcpy(card->mixername, "SAA7134 Mixer"); - - for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) { - kcontrol = snd_ctl_new1(&snd_saa7134_volume_controls[idx], - chip); - err = snd_ctl_add(card, kcontrol); - if (err < 0) - return err; - } - - for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_capture_controls); idx++) { - kcontrol = snd_ctl_new1(&snd_saa7134_capture_controls[idx], - chip); - addr = snd_saa7134_capture_controls[idx].private_value; - chip->capture_ctl[addr] = kcontrol; - err = snd_ctl_add(card, kcontrol); - if (err < 0) - return err; - } - - chip->capture_source_addr = MIXER_ADDR_UNSELECTED; - return 0; -} - -static void snd_saa7134_free(struct snd_card * card) -{ - snd_card_saa7134_t *chip = card->private_data; - - if (chip->dev->dmasound.priv_data == NULL) - return; - - if (chip->irq >= 0) - free_irq(chip->irq, &chip->dev->dmasound); - - chip->dev->dmasound.priv_data = NULL; - -} - -/* - * ALSA initialization - * - * Called by the init routine, once for each saa7134 device present, - * it creates the basic structures and registers the ALSA devices - * - */ - -static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) -{ - - struct snd_card *card; - snd_card_saa7134_t *chip; - int err; - - - if (devnum >= SNDRV_CARDS) - return -ENODEV; - if (!enable[devnum]) - return -ENODEV; - - err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, - sizeof(snd_card_saa7134_t), &card); - if (err < 0) - return err; - - strcpy(card->driver, "SAA7134"); - - /* Card "creation" */ - - card->private_free = snd_saa7134_free; - chip = card->private_data; - - spin_lock_init(&chip->lock); - spin_lock_init(&chip->mixer_lock); - - chip->dev = dev; - - chip->card = card; - - chip->pci = dev->pci; - chip->iobase = pci_resource_start(dev->pci, 0); - - - err = request_irq(dev->pci->irq, saa7134_alsa_irq, - IRQF_SHARED | IRQF_DISABLED, dev->name, - (void*) &dev->dmasound); - - if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n", - dev->name, dev->pci->irq); - goto __nodev; - } - - chip->irq = dev->pci->irq; - - mutex_init(&dev->dmasound.lock); - - if ((err = snd_card_saa7134_new_mixer(chip)) < 0) - goto __nodev; - - if ((err = snd_card_saa7134_pcm(chip, 0)) < 0) - goto __nodev; - - snd_card_set_dev(card, &chip->pci->dev); - - /* End of "creation" */ - - strcpy(card->shortname, "SAA7134"); - sprintf(card->longname, "%s at 0x%lx irq %d", - chip->dev->name, chip->iobase, chip->irq); - - printk(KERN_INFO "%s/alsa: %s registered as card %d\n",dev->name,card->longname,index[devnum]); - - if ((err = snd_card_register(card)) == 0) { - snd_saa7134_cards[devnum] = card; - return 0; - } - -__nodev: - snd_card_free(card); - return err; -} - - -static int alsa_device_init(struct saa7134_dev *dev) -{ - dev->dmasound.priv_data = dev; - alsa_card_saa7134_create(dev,dev->nr); - return 1; -} - -static int alsa_device_exit(struct saa7134_dev *dev) -{ - - snd_card_free(snd_saa7134_cards[dev->nr]); - snd_saa7134_cards[dev->nr] = NULL; - return 1; -} - -/* - * Module initializer - * - * Loops through present saa7134 cards, and assigns an ALSA device - * to each one - * - */ - -static int saa7134_alsa_init(void) -{ - struct saa7134_dev *dev = NULL; - struct list_head *list; - - saa7134_dmasound_init = alsa_device_init; - saa7134_dmasound_exit = alsa_device_exit; - - printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); - - list_for_each(list,&saa7134_devlist) { - dev = list_entry(list, struct saa7134_dev, devlist); - if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) - printk(KERN_INFO "%s/alsa: %s doesn't support digital audio\n", - dev->name, saa7134_boards[dev->board].name); - else - alsa_device_init(dev); - } - - if (dev == NULL) - printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n"); - - return 0; - -} - -/* - * Module destructor - */ - -static void saa7134_alsa_exit(void) -{ - int idx; - - for (idx = 0; idx < SNDRV_CARDS; idx++) { - snd_card_free(snd_saa7134_cards[idx]); - } - - saa7134_dmasound_init = NULL; - saa7134_dmasound_exit = NULL; - printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n"); - - return; -} - -/* We initialize this late, to make sure the sound system is up and running */ -late_initcall(saa7134_alsa_init); -module_exit(saa7134_alsa_exit); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ricardo Cerqueira"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-cards.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,7753 +0,0 @@ -/* - * - * device driver for philips saa7134 based TV cards - * card-specific stuff. - * - * (c) 2001-04 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" -#include "tuner-xc2028.h" -#include -#include -#include "tea5767.h" -#include "tda18271.h" -#include "xc5000.h" - -/* commly used strings */ -static char name_mute[] = "mute"; -static char name_radio[] = "Radio"; -static char name_tv[] = "Television"; -static char name_tv_mono[] = "TV (mono only)"; -static char name_comp[] = "Composite"; -static char name_comp1[] = "Composite1"; -static char name_comp2[] = "Composite2"; -static char name_comp3[] = "Composite3"; -static char name_comp4[] = "Composite4"; -static char name_svideo[] = "S-Video"; - -/* ------------------------------------------------------------------ */ -/* board config info */ - -/* If radio_type !=UNSET, radio_addr should be specified - */ - -struct saa7134_board saa7134_boards[] = { - [SAA7134_BOARD_UNKNOWN] = { - .name = "UNKNOWN/GENERIC", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .inputs = {{ - .name = "default", - .vmux = 0, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_PROTEUS_PRO] = { - /* /me */ - .name = "Proteus Pro [philips reference design]", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .inputs = {{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_FLYVIDEO3000] = { - /* "Marco d'Itri" */ - .name = "LifeView FlyVIDEO3000", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .gpiomask = 0xe000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .gpio = 0x8000, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .gpio = 0x0000, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - .gpio = 0x4000, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - .gpio = 0x4000, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - .gpio = 0x4000, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x2000, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x8000, - }, - }, - [SAA7134_BOARD_FLYVIDEO2000] = { - /* "TC Wan" */ - .name = "LifeView/Typhoon FlyVIDEO2000", - .audio_clock = 0x00200000, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .gpiomask = 0xe000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .gpio = 0x0000, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - .gpio = 0x4000, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - .gpio = 0x4000, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - .gpio = 0x4000, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x2000, - }, - .mute = { - .name = name_mute, - .amux = LINE2, - .gpio = 0x8000, - }, - }, - [SAA7134_BOARD_FLYTVPLATINUM_MINI] = { - /* "Arnaud Quette" */ - .name = "LifeView FlyTV Platinum Mini", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, /* Composite signal on S-Video input */ - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, /* Composite input */ - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_FLYTVPLATINUM_FM] = { - /* LifeView FlyTV Platinum FM (LR214WF) */ - /* "Peter Missel */ - .name = "LifeView FlyTV Platinum FM / Gold", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .gpiomask = 0x1E000, /* Set GP16 and unused 15,14,13 to Output */ - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .gpio = 0x10000, /* GP16=1 selects TV input */ - .tv = 1, - },{ -/* .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .gpio = 0x0000, - .tv = 1, - },{ -*/ .name = name_comp1, /* Composite signal on S-Video input */ - .vmux = 0, - .amux = LINE2, -/* .gpio = 0x4000, */ - },{ - .name = name_comp2, /* Composite input */ - .vmux = 3, - .amux = LINE2, -/* .gpio = 0x4000, */ - },{ - .name = name_svideo, /* S-Video signal on S-Video input */ - .vmux = 8, - .amux = LINE2, -/* .gpio = 0x4000, */ - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x00000, /* GP16=0 selects FM radio antenna */ - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x10000, - }, - }, - [SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM] = { - /* RoverMedia TV Link Pro FM (LR138 REV:I) */ - /* Eugene Yudin */ - .name = "RoverMedia TV Link Pro FM", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MFPE05 2 */ - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0xe000, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = TV, - .gpio = 0x8000, - .tv = 1, - }, { - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .gpio = 0x0000, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - .gpio = 0x4000, - }, { - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - .gpio = 0x4000, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - .gpio = 0x4000, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x2000, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x8000, - }, - }, - [SAA7134_BOARD_EMPRESS] = { - /* "Gert Vervoort" */ - .name = "EMPRESS", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .empress_addr = 0x20, - - .inputs = {{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - .mpeg = SAA7134_MPEG_EMPRESS, - .video_out = CCIR656, - }, - [SAA7134_BOARD_MONSTERTV] = { - /* "K.Ohta" */ - .name = "SKNet Monster TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_MD9717] = { - .name = "Tevion MD 9717", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - /* workaround for problems with normal TV sound */ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - .mute = { - .name = name_mute, - .amux = TV, - }, - }, - [SAA7134_BOARD_TVSTATION_RDS] = { - /* Typhoon TV Tuner RDS: Art.Nr. 50694 */ - .name = "KNC One TV-Station RDS / Typhoon TV Tuner RDS", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - - .name = "CVid over SVid", - .vmux = 0, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_TVSTATION_DVR] = { - .name = "KNC One TV-Station DVR", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .empress_addr = 0x20, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x820000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x20000, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x20000, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x20000, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x20000, - }, - .mpeg = SAA7134_MPEG_EMPRESS, - .video_out = CCIR656, - }, - [SAA7134_BOARD_CINERGY400] = { - .name = "Terratec Cinergy 400 TV", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, /* CVideo over SVideo Connector */ - .vmux = 0, - .amux = LINE1, - }} - }, - [SAA7134_BOARD_MD5044] = { - .name = "Medion 5044", - .audio_clock = 0x00187de7, /* was: 0x00200000, */ - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - /* workaround for problems with normal TV sound */ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_KWORLD] = { - .name = "Kworld/KuroutoShikou SAA7130-TVPCI", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_CINERGY600] = { - .name = "Terratec Cinergy 600 TV", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, /* CVideo over SVideo Connector */ - .vmux = 0, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_MD7134] = { - .name = "Medion 7134", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - .mute = { - .name = name_mute, - .amux = TV, - }, - }, - [SAA7134_BOARD_TYPHOON_90031] = { - /* aka Typhoon "TV+Radio", Art.Nr 90031 */ - /* Tom Zoerner */ - .name = "Typhoon TV+Radio 90031", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_ELSA] = { - .name = "ELSA EX-VISION 300TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_HITACHI_NTSC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 4, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_ELSA_500TV] = { - .name = "ELSA EX-VISION 500TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_HITACHI_NTSC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 7, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 8, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 8, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_ELSA_700TV] = { - .name = "ELSA EX-VISION 700TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_HITACHI_NTSC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 4, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 6, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 7, - .amux = LINE1, - }}, - .mute = { - .name = name_mute, - .amux = TV, - }, - }, - [SAA7134_BOARD_ASUSTeK_TVFM7134] = { - .name = "ASUS TV-FM 7134", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_ASUSTeK_TVFM7135] = { - .name = "ASUS TV-FM 7135", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .gpio = 0x0000, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, - .gpio = 0x0000, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - .gpio = 0x0000, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x200000, - }, - .mute = { - .name = name_mute, - .gpio = 0x0000, - }, - - }, - [SAA7134_BOARD_VA1000POWER] = { - .name = "AOPEN VA1000 POWER", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_10MOONSTVMASTER] = { - /* "lilicheng" */ - .name = "10MOONS PCI TV CAPTURE CARD", - .audio_clock = 0x00200000, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0xe000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .gpio = 0x0000, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - .gpio = 0x4000, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - .gpio = 0x4000, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - .gpio = 0x4000, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x2000, - }, - .mute = { - .name = name_mute, - .amux = LINE2, - .gpio = 0x8000, - }, - }, - [SAA7134_BOARD_BMK_MPEX_NOTUNER] = { - /* "Andrew de Quincey" */ - .name = "BMK MPEX No Tuner", - .audio_clock = 0x200000, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .empress_addr = 0x20, - .inputs = {{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_comp3, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_comp4, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .mpeg = SAA7134_MPEG_EMPRESS, - .video_out = CCIR656, - }, - [SAA7134_BOARD_VIDEOMATE_TV] = { - .name = "Compro VideoMate TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = { - .name = "Compro VideoMate TV Gold+", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .gpiomask = 0x800c0000, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x06c00012, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x0ac20012, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .gpio = 0x08c20012, - .tv = 1, - }}, /* radio and probably mute is missing */ - }, - [SAA7134_BOARD_CRONOS_PLUS] = { - /* - gpio pins: - 0 .. 3 BASE_ID - 4 .. 7 PROTECT_ID - 8 .. 11 USER_OUT - 12 .. 13 USER_IN - 14 .. 15 VIDIN_SEL - */ - .name = "Matrox CronosPlus", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0xcf00, - .inputs = {{ - .name = name_comp1, - .vmux = 0, - .gpio = 2 << 14, - },{ - .name = name_comp2, - .vmux = 0, - .gpio = 1 << 14, - },{ - .name = name_comp3, - .vmux = 0, - .gpio = 0 << 14, - },{ - .name = name_comp4, - .vmux = 0, - .gpio = 3 << 14, - },{ - .name = name_svideo, - .vmux = 8, - .gpio = 2 << 14, - }}, - }, - [SAA7134_BOARD_MD2819] = { - .name = "AverMedia M156 / Medion 2819", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x03, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x00, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x02, - }, { - .name = name_comp2, - .vmux = 0, - .amux = LINE1, - .gpio = 0x02, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x02, - } }, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x01, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x00, - }, - }, - [SAA7134_BOARD_BMK_MPEX_TUNER] = { - /* "Greg Wickham */ - .name = "BMK MPEX Tuner", - .audio_clock = 0x200000, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .empress_addr = 0x20, - .inputs = {{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }}, - .mpeg = SAA7134_MPEG_EMPRESS, - .video_out = CCIR656, - }, - [SAA7134_BOARD_ASUSTEK_TVFM7133] = { - .name = "ASUS TV-FM 7133", - .audio_clock = 0x00187de7, - /* probably wrong, the 7133 one is the NTSC version ... - * .tuner_type = TUNER_PHILIPS_FM1236_MK3 */ - .tuner_type = TUNER_LG_NTSC_NEW_TAPC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_PINNACLE_PCTV_STEREO] = { - .name = "Pinnacle PCTV Stereo (saa7134)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_MT2032, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER | TDA9887_PORT2_INACTIVE, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_MANLI_MTV002] = { - /* Ognjen Nastic */ - .name = "Manli MuchTV M-TV002", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_MANLI_MTV001] = { - /* Ognjen Nastic UNTESTED */ - .name = "Manli MuchTV M-TV001", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_TG3000TV] = { - /* TransGear 3000TV */ - .name = "Nagase Sangyo TransGear 3000TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_ECS_TVP3XP] = { - .name = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ", - .audio_clock = 0x187de7, /* xtal 32.1 MHz */ - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = "CVid over SVid", - .vmux = 0, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_ECS_TVP3XP_4CB5] = { - .name = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)", - .audio_clock = 0x187de7, - .tuner_type = TUNER_PHILIPS_NTSC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = "CVid over SVid", - .vmux = 0, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_ECS_TVP3XP_4CB6] = { - /* Barry Scott */ - .name = "Elitegroup ECS TVP3XP FM1246 Tuner Card (PAL,FM)", - .audio_clock = 0x187de7, - .tuner_type = TUNER_PHILIPS_PAL_I, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = "CVid over SVid", - .vmux = 0, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_AVACSSMARTTV] = { - /* Roman Pszonczenko */ - .name = "AVACS SmartTV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x200000, - }, - }, - [SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER] = { - /* Michael Smith */ - .name = "AVerMedia DVD EZMaker", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_comp1, - .vmux = 3, - },{ - .name = name_svideo, - .vmux = 8, - }}, - }, - [SAA7134_BOARD_AVERMEDIA_M103] = { - /* Massimo Piccioni */ - .name = "AVerMedia MiniPCI DVB-T Hybrid M103", - .audio_clock = 0x187de7, - .tuner_type = TUNER_XC2028, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - } }, - }, - [SAA7134_BOARD_NOVAC_PRIMETV7133] = { - /* toshii@netbsd.org */ - .name = "Noval Prime TV 7133", - .audio_clock = 0x00200000, - .tuner_type = TUNER_ALPS_TSBH1_NTSC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_comp1, - .vmux = 3, - },{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_svideo, - .vmux = 8, - }}, - }, - [SAA7134_BOARD_AVERMEDIA_STUDIO_305] = { - .name = "AverMedia AverTV Studio 305", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1256_IH3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_AVERMEDIA_STUDIO_505] = { - /* Vasiliy Temnikov */ - .name = "AverMedia AverTV Studio 505", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - }, { - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_UPMOST_PURPLE_TV] = { - .name = "UPMOST PURPLE TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 7, - .amux = TV, - .tv = 1, - },{ - .name = name_svideo, - .vmux = 7, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_ITEMS_MTV005] = { - /* Norman Jonas */ - .name = "Items MuchTV Plus / IT-005", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_CINERGY200] = { - .name = "Terratec Cinergy 200 TV", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, /* CVideo over SVideo Connector */ - .vmux = 0, - .amux = LINE1, - }}, - .mute = { - .name = name_mute, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_VIDEOMATE_TV_PVR] = { - /* Alain St-Denis */ - .name = "Compro VideoMate TV PVR/FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x808c0080, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x00080, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x00080, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2_LEFT, - .tv = 1, - .gpio = 0x00080, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x80000, - }, - .mute = { - .name = name_mute, - .amux = LINE2, - .gpio = 0x40000, - }, - }, - [SAA7134_BOARD_SABRENT_SBTTVFM] = { - /* Michael Rodriguez-Torrent */ - .name = "Sabrent SBT-TVFM (saa7130)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_ZOLID_XPERT_TV7134] = { - /* Helge Jensen */ - .name = ":Zolid Xpert TV7134", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE] = { - /* "Matteo Az" ;-) */ - .name = "Empire PCI TV-Radio LE", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x4000, - .inputs = {{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .gpio = 0x8000, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x8000, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE1, - .gpio = 0x8000, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x8000, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio =0x8000, - } - }, - [SAA7134_BOARD_AVERMEDIA_STUDIO_307] = { - /* - Nickolay V. Shmyrev - Lots of thanks to Andrey Zolotarev - */ - .name = "Avermedia AVerTV Studio 307", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1256_IH3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x03, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x00, - },{ - .name = name_comp, - .vmux = 3, - .amux = LINE1, - .gpio = 0x02, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x02, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x01, - }, - .mute = { - .name = name_mute, - .amux = LINE1, - .gpio = 0x00, - }, - }, - [SAA7134_BOARD_AVERMEDIA_GO_007_FM] = { - .name = "Avermedia AVerTV GO 007 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x00300003, - /* .gpiomask = 0x8c240003, */ - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x01, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - .gpio = 0x02, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE1, - .gpio = 0x02, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x00300001, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x01, - }, - }, - [SAA7134_BOARD_AVERMEDIA_CARDBUS] = { - /* Kees.Blom@cwi.nl */ - .name = "AVerMedia Cardbus TV/Radio (E500)", - .audio_clock = 0x187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_AVERMEDIA_CARDBUS_501] = { - /* Oldrich Jedlicka */ - .name = "AVerMedia Cardbus TV/Radio (E501R)", - .audio_clock = 0x187de7, - .tuner_type = TUNER_ALPS_TSBE5_PAL, - .radio_type = TUNER_TEA5767, - .tuner_addr = 0x61, - .radio_addr = 0x60, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x08000000, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x08000000, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x08000000, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x08000000, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x00000000, - }, - }, - [SAA7134_BOARD_CINERGY400_CARDBUS] = { - .name = "Terratec Cinergy 400 mobile", - .audio_clock = 0x187de7, - .tuner_type = TUNER_ALPS_TSBE5_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_CINERGY600_MK3] = { - .name = "Terratec Cinergy 600 TV MK3", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, /* CVideo over SVideo Connector */ - .vmux = 0, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = { - /* Dylan Walkden */ - .name = "Compro VideoMate Gold+ Pal", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x1ce780, - .inputs = {{ - .name = name_svideo, - .vmux = 0, /* CVideo over SVideo Connector - ok? */ - .amux = LINE1, - .gpio = 0x008080, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x008080, - },{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x008080, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x80000, - }, - .mute = { - .name = name_mute, - .amux = LINE2, - .gpio = 0x0c8000, - }, - }, - [SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = { - .name = "Pinnacle PCTV 300i DVB-T + PAL", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_MT2032, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER | TDA9887_PORT2_INACTIVE, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_PROVIDEO_PV952] = { - /* andreas.kretschmer@web.de */ - .name = "ProVideo PV952", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_AVERMEDIA_305] = { - /* much like the "studio" version but without radio - * and another tuner (sirspiritus@yandex.ru) */ - .name = "AverMedia AverTV/305", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_FLYDVBTDUO] = { - /* LifeView FlyDVB-T DUO */ - /* "Nico Sabbi Hartmut Hackmann hartmut.hackmann@t-online.de*/ - .name = "LifeView FlyDVB-T DUO / MSI TV@nywhere Duo", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x00200000, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .gpio = 0x200000, /* GPIO21=High for TV input */ - .tv = 1, - },{ - .name = name_comp1, /* Composite signal on S-Video input */ - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, /* Composite input */ - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, /* S-Video signal on S-Video input */ - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ - }, - }, - [SAA7134_BOARD_PHILIPS_TOUGH] = { - .name = "Philips TOUGH DVB-T reference design", - .tuner_type = TUNER_ABSENT, - .audio_clock = 0x00187de7, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_AVERMEDIA_307] = { - /* - Davydov Vladimir - */ - .name = "Avermedia AVerTV 307", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_ADS_INSTANT_TV] = { - .name = "ADS Tech Instant TV (saa7135)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_KWORLD_VSTREAM_XPERT] = { - .name = "Kworld/Tevion V-Stream Xpert TV PVR7134", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL_I, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x0700, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x000, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x200, /* gpio by DScaler */ - },{ - .name = name_svideo, - .vmux = 0, - .amux = LINE1, - .gpio = 0x200, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x100, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x000, - }, - }, - [SAA7134_BOARD_FLYDVBT_DUO_CARDBUS] = { - .name = "LifeView/Typhoon/Genius FlyDVB-T Duo Cardbus", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x00200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .gpio = 0x200000, /* GPIO21=High for TV input */ - .tv = 1, - },{ - .name = name_svideo, /* S-Video signal on S-Video input */ - .vmux = 8, - .amux = LINE2, - },{ - .name = name_comp1, /* Composite signal on S-Video input */ - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, /* Composite input */ - .vmux = 3, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ - }, - }, - [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII] = { - .name = "Compro VideoMate TV Gold+II", - .audio_clock = 0x002187de7, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .radio_type = TUNER_TEA5767, - .tuner_addr = 0x63, - .radio_addr = 0x60, - .gpiomask = 0x8c1880, - .inputs = {{ - .name = name_svideo, - .vmux = 0, - .amux = LINE1, - .gpio = 0x800800, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x801000, - },{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x800000, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x880000, - }, - .mute = { - .name = name_mute, - .amux = LINE2, - .gpio = 0x840000, - }, - }, - [SAA7134_BOARD_KWORLD_XPERT] = { - /* - FIXME: - - Remote control doesn't initialize properly. - - Audio volume starts muted, - then gradually increases after channel change. - - Overlay scaling problems (application error?) - - Composite S-Video untested. - From: Konrad Rzepecki - */ - .name = "Kworld Xpert TV PVR7134", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_TENA_9533_DI, - .radio_type = TUNER_TEA5767, - .tuner_addr = 0x61, - .radio_addr = 0x60, - .gpiomask = 0x0700, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x000, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x200, /* gpio by DScaler */ - },{ - .name = name_svideo, - .vmux = 0, - .amux = LINE1, - .gpio = 0x200, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x100, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x000, - }, - }, - [SAA7134_BOARD_FLYTV_DIGIMATRIX] = { - .name = "FlyTV mini Asus Digimatrix", - .audio_clock = 0x00200000, - .tuner_type = TUNER_LG_TALN, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, /* radio unconfirmed */ - .amux = LINE2, - }, - }, - [SAA7134_BOARD_KWORLD_TERMINATOR] = { - /* Kworld V-Stream Studio TV Terminator */ - /* "James Webb */ - .name = "V-Stream Studio TV Terminator", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 1 << 21, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .gpio = 0x0000000, - .tv = 1, - },{ - .name = name_comp1, /* Composite input */ - .vmux = 3, - .amux = LINE2, - .gpio = 0x0000000, - },{ - .name = name_svideo, /* S-Video input */ - .vmux = 8, - .amux = LINE2, - .gpio = 0x0000000, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_YUAN_TUN900] = { - /* FIXME: - * S-Video and composite sources untested. - * Radio not working. - * Remote control not yet implemented. - * From : codemaster@webgeeks.be */ - .name = "Yuan TUN-900 (saa7135)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr= ADDR_UNSET, - .radio_addr= ADDR_UNSET, - .gpiomask = 0x00010003, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x01, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - .gpio = 0x02, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - .gpio = 0x02, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x00010003, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x01, - }, - }, - [SAA7134_BOARD_BEHOLD_409FM] = { - /* , Sergey */ - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 409 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_GOTVIEW_7135] = { - /* Mike Baikov */ - /* Andrey Cvetcov */ - .name = "GoTView 7135 PCI", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00200003, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x00200003, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .gpio = 0x00200003, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x00200003, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x00200003, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x00200003, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x00200003, - }, - }, - [SAA7134_BOARD_PHILIPS_EUROPA] = { - .name = "Philips EUROPA V3 reference design", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TD1316, - .radio_type = UNSET, - .tuner_addr = 0x61, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_VIDEOMATE_DVBT_300] = { - .name = "Compro Videomate DVB-T300", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TD1316, - .radio_type = UNSET, - .tuner_addr = 0x61, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_VIDEOMATE_DVBT_200] = { - .name = "Compro Videomate DVB-T200", - .tuner_type = TUNER_ABSENT, - .audio_clock = 0x00187de7, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_RTD_VFG7350] = { - .name = "RTD Embedded Technologies VFG7350", - .audio_clock = 0x00200000, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .empress_addr = 0x21, - .inputs = {{ - .name = "Composite 0", - .vmux = 0, - .amux = LINE1, - },{ - .name = "Composite 1", - .vmux = 1, - .amux = LINE2, - },{ - .name = "Composite 2", - .vmux = 2, - .amux = LINE1, - },{ - .name = "Composite 3", - .vmux = 3, - .amux = LINE2, - },{ - .name = "S-Video 0", - .vmux = 8, - .amux = LINE1, - },{ - .name = "S-Video 1", - .vmux = 9, - .amux = LINE2, - }}, - .mpeg = SAA7134_MPEG_EMPRESS, - .video_out = CCIR656, - .vid_port_opts = ( SET_T_CODE_POLARITY_NON_INVERTED | - SET_CLOCK_NOT_DELAYED | - SET_CLOCK_INVERTED | - SET_VSYNC_OFF ), - }, - [SAA7134_BOARD_RTD_VFG7330] = { - .name = "RTD Embedded Technologies VFG7330", - .audio_clock = 0x00200000, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = "Composite 0", - .vmux = 0, - .amux = LINE1, - },{ - .name = "Composite 1", - .vmux = 1, - .amux = LINE2, - },{ - .name = "Composite 2", - .vmux = 2, - .amux = LINE1, - },{ - .name = "Composite 3", - .vmux = 3, - .amux = LINE2, - },{ - .name = "S-Video 0", - .vmux = 8, - .amux = LINE1, - },{ - .name = "S-Video 1", - .vmux = 9, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_FLYTVPLATINUM_MINI2] = { - .name = "LifeView FlyTV Platinum Mini2", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, /* Composite signal on S-Video input */ - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, /* Composite input */ - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180] = { - /* Michael Krufky - * Uses Alps Electric TDHU2, containing NXT2004 ATSC Decoder - * AFAIK, there is no analog demod, thus, - * no support for analog television. - */ - .name = "AVerMedia AVerTVHD MCE A180", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_MONSTERTV_MOBILE] = { - .name = "SKNet MonsterTV Mobile", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_PINNACLE_PCTV_110i] = { - .name = "Pinnacle PCTV 40i/50i/110i (saa7133)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x080200000, - .inputs = { { - .name = name_tv, - .vmux = 4, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE2, - }, { - .name = name_comp2, - .vmux = 0, - .amux = LINE2, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_ASUSTeK_P7131_DUAL] = { - .name = "ASUSTeK P7131 Dual", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 1 << 21, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x0000000, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - .gpio = 0x0200000, - },{ - .name = name_comp2, - .vmux = 0, - .amux = LINE2, - .gpio = 0x0200000, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - .gpio = 0x0200000, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_SEDNA_PC_TV_CARDBUS] = { - /* Paul Tom Zalac */ - /* Pavel Mihaylov */ - .name = "Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)", - /* Sedna/MuchTV (OEM) Cardbus TV Tuner */ - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0xe880c0, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV] = { - /* "Cyril Lacoux (Yack)" */ - .name = "ASUS Digimatrix TV", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .tda9887_conf = TDA9887_PRESENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_PHILIPS_TIGER] = { - .name = "Philips Tiger reference design", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 0, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_MSI_TVATANYWHERE_PLUS] = { - .name = "MSI TV@Anywhere plus", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 1 << 21, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, /* unconfirmed, taken from Philips driver */ - },{ - .name = name_comp2, - .vmux = 0, /* untested, Composite over S-Video */ - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_CINERGY250PCI] = { - /* remote-control does not work. The signal about a - key press comes in via gpio, but the key code - doesn't. Neither does it have an i2c remote control - interface. */ - .name = "Terratec Cinergy 250 PCI TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x80200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_svideo, /* NOT tested */ - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_FLYDVB_TRIO] = { - /* LifeView LR319 FlyDVB Trio */ - /* Peter Missel */ - .name = "LifeView FlyDVB Trio", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x00200000, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, /* Analog broadcast/cable TV */ - .vmux = 1, - .amux = TV, - .gpio = 0x200000, /* GPIO21=High for TV input */ - .tv = 1, - },{ - .name = name_svideo, /* S-Video signal on S-Video input */ - .vmux = 8, - .amux = LINE2, - },{ - .name = name_comp1, /* Composite signal on S-Video input */ - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, /* Composite input */ - .vmux = 3, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ - }, - }, - [SAA7134_BOARD_AVERMEDIA_777] = { - .name = "AverTV DVB-T 777", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_FLYDVBT_LR301] = { - /* LifeView FlyDVB-T */ - /* Giampiero Giancipoli */ - .name = "LifeView FlyDVB-T / Genius VideoWonder DVB-T", - .audio_clock = 0x00200000, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_comp1, /* Composite input */ - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, /* S-Video signal on S-Video input */ - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331] = { - .name = "ADS Instant TV Duo Cardbus PTV331", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */ - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x00200000, - }}, - }, - [SAA7134_BOARD_TEVION_DVBT_220RF] = { - .name = "Tevion/KWorld DVB-T 220RF", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 1 << 21, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_comp2, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_KWORLD_DVBT_210] = { - .name = "KWorld DVB-T 210", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 1 << 21, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_KWORLD_ATSC110] = { - .name = "Kworld ATSC110/115", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TUV1236D, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_AVERMEDIA_A169_B] = { - /* AVerMedia A169 */ - /* Rickard Osser */ - /* This card has two saa7134 chips on it, - but only one of them is currently working. */ - .name = "AVerMedia A169 B", - .audio_clock = 0x02187de7, - .tuner_type = TUNER_LG_TALN, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x0a60000, - }, - [SAA7134_BOARD_AVERMEDIA_A169_B1] = { - /* AVerMedia A169 */ - /* Rickard Osser */ - .name = "AVerMedia A169 B1", - .audio_clock = 0x02187de7, - .tuner_type = TUNER_LG_TALN, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0xca60000, - .inputs = {{ - .name = name_tv, - .vmux = 4, - .amux = TV, - .tv = 1, - .gpio = 0x04a61000, - },{ - .name = name_comp2, /* Composite SVIDEO (B/W if signal is carried with SVIDEO) */ - .vmux = 1, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 9, /* 9 is correct as S-VIDEO1 according to a169.inf! */ - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_MD7134_BRIDGE_2] = { - /* The second saa7134 on this card only serves as DVB-S host bridge */ - .name = "Medion 7134 Bridge #2", - .audio_clock = 0x00187de7, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - }, - [SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = { - .name = "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */ - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .gpio = 0x200000, /* GPIO21=High for TV input */ - .tv = 1, - },{ - .name = name_svideo, /* S-Video signal on S-Video input */ - .vmux = 8, - .amux = LINE2, - },{ - .name = name_comp1, /* Composite signal on S-Video input */ - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, /* Composite input */ - .vmux = 3, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ - }, - }, - [SAA7134_BOARD_FLYVIDEO3000_NTSC] = { - /* "Zac Bowling" */ - .name = "LifeView FlyVIDEO3000 (NTSC)", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_NTSC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .gpiomask = 0xe000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .gpio = 0x8000, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .gpio = 0x0000, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - .gpio = 0x4000, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - .gpio = 0x4000, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - .gpio = 0x4000, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x2000, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x8000, - }, - }, - [SAA7134_BOARD_MEDION_MD8800_QUADRO] = { - .name = "Medion Md8800 Quadro", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_FLYDVBS_LR300] = { - /* LifeView FlyDVB-s */ - /* Igor M. Liplianin */ - .name = "LifeView FlyDVB-S /Acorp TV134DS", - .audio_clock = 0x00200000, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_comp1, /* Composite input */ - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, /* S-Video signal on S-Video input */ - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_PROTEUS_2309] = { - .name = "Proteus Pro 2309", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_AVERMEDIA_A16AR] = { - /* Petr Baudis */ - .name = "AVerMedia TV Hybrid A16AR", - .audio_clock = 0x187de7, - .tuner_type = TUNER_PHILIPS_TD1316, /* untested */ - .radio_type = TUNER_TEA5767, /* untested */ - .tuner_addr = ADDR_UNSET, - .radio_addr = 0x60, - .tda9887_conf = TDA9887_PRESENT, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_ASUS_EUROPA2_HYBRID] = { - .name = "Asus Europa2 OEM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT| TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_PINNACLE_PCTV_310i] = { - .name = "Pinnacle PCTV 310i", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 1, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x000200000, - .inputs = {{ - .name = name_tv, - .vmux = 4, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_AVERMEDIA_STUDIO_507] = { - /* Mikhail Fedotov */ - .name = "Avermedia AVerTV Studio 507", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1256_IH3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x03, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x00, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - .gpio = 0x00, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE2, - .gpio = 0x00, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - .gpio = 0x00, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x01, - }, - .mute = { - .name = name_mute, - .amux = LINE1, - .gpio = 0x00, - }, - }, - [SAA7134_BOARD_VIDEOMATE_DVBT_200A] = { - /* Francis Barber */ - .name = "Compro Videomate DVB-T200A", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_HAUPPAUGE_HVR1110] = { - /* Thomas Genty */ - /* David Bentham */ - .name = "Hauppauge WinTV-HVR1110 DVB-T/Hybrid", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 1, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200100, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x0000100, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200100, - }, - }, - [SAA7134_BOARD_HAUPPAUGE_HVR1150] = { - .name = "Hauppauge WinTV-HVR1150 ATSC/QAM-Hybrid", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 3, - .mpeg = SAA7134_MPEG_DVB, - .ts_type = SAA7134_MPEG_TS_SERIAL, - .ts_force_val = 1, - .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */ - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x0000100, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0800100, /* GPIO 23 HI for FM */ - }, - }, - [SAA7134_BOARD_HAUPPAUGE_HVR1120] = { - .name = "Hauppauge WinTV-HVR1120 DVB-T/Hybrid", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 3, - .mpeg = SAA7134_MPEG_DVB, - .ts_type = SAA7134_MPEG_TS_SERIAL, - .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */ - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x0000100, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0800100, /* GPIO 23 HI for FM */ - }, - }, - [SAA7134_BOARD_CINERGY_HT_PCMCIA] = { - .name = "Terratec Cinergy HT PCMCIA", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_ENCORE_ENLTV] = { - /* Steven Walter - Juan Pablo Sormani */ - .name = "Encore ENLTV", - .audio_clock = 0x00200000, - .tuner_type = TUNER_TNF_5335MF, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = 3, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 7, - .amux = 4, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = 2, - },{ - .name = name_svideo, - .vmux = 0, - .amux = 2, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, -/* .gpio = 0x00300001,*/ - .gpio = 0x20000, - - }, - .mute = { - .name = name_mute, - .amux = 0, - }, - }, - [SAA7134_BOARD_ENCORE_ENLTV_FM] = { - /* Juan Pablo Sormani */ - .name = "Encore ENLTV-FM", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FCV1236D, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = 3, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 7, - .amux = 4, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = 2, - },{ - .name = name_svideo, - .vmux = 0, - .amux = 2, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x20000, - - }, - .mute = { - .name = name_mute, - .amux = 0, - }, - }, - [SAA7134_BOARD_ENCORE_ENLTV_FM53] = { - .name = "Encore ENLTV-FM v5.3", - .audio_clock = 0x00200000, - .tuner_type = TUNER_TNF_5335MF, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x7000, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = 1, - .tv = 1, - .gpio = 0x50000, - }, { - .name = name_comp1, - .vmux = 3, - .amux = 2, - .gpio = 0x2000, - }, { - .name = name_svideo, - .vmux = 8, - .amux = 2, - .gpio = 0x2000, - } }, - .radio = { - .name = name_radio, - .vmux = 1, - .amux = 1, - }, - .mute = { - .name = name_mute, - .gpio = 0xf000, - .amux = 0, - }, - }, - [SAA7134_BOARD_ENCORE_ENLTV_FM3] = { - .name = "Encore ENLTV-FM 3", - .audio_clock = 0x02187de7, - .tuner_type = TUNER_TENA_TNF_5337, - .radio_type = TUNER_TEA5767, - .tuner_addr = 0x61, - .radio_addr = 0x60, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .vmux = 1, - .amux = LINE1, - }, - .mute = { - .name = name_mute, - .amux = LINE1, - .gpio = 0x43000, - }, - }, - [SAA7134_BOARD_CINERGY_HT_PCI] = { - .name = "Terratec Cinergy HT PCI", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_PHILIPS_TIGER_S] = { - .name = "Philips Tiger - S Reference design", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_AVERMEDIA_M102] = { - .name = "Avermedia M102", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 1<<21, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_ASUS_P7131_4871] = { - .name = "ASUS P7131 4871", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x0200000, - }}, - }, - [SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA] = { - .name = "ASUSTeK P7131 Hybrid", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .gpiomask = 1 << 21, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x0000000, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - .gpio = 0x0200000, - },{ - .name = name_comp2, - .vmux = 0, - .amux = LINE2, - .gpio = 0x0200000, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - .gpio = 0x0200000, - }}, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = { - .name = "ASUSTeK P7131 Analog", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 1 << 21, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x0000000, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - }, { - .name = name_comp2, - .vmux = 0, - .amux = LINE2, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_SABRENT_TV_PCB05] = { - .name = "Sabrent PCMCIA TV-PCB05", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_comp2, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .mute = { - .name = name_mute, - .amux = TV, - }, - }, - [SAA7134_BOARD_10MOONSTVMASTER3] = { - /* Tony Wan */ - .name = "10MOONS TM300 TV Card", - .audio_clock = 0x00200000, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x7000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .gpio = 0x0000, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x2000, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x2000, - }}, - .mute = { - .name = name_mute, - .amux = LINE2, - .gpio = 0x3000, - }, - }, - [SAA7134_BOARD_AVERMEDIA_SUPER_007] = { - .name = "Avermedia Super 007", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 0, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, /* FIXME: analog tv untested */ - .vmux = 1, - .amux = TV, - .tv = 1, - }}, - }, - [SAA7134_BOARD_AVERMEDIA_M135A] = { - .name = "Avermedia PCI pure analog (M135A)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .gpiomask = 0x020200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x00200000, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x01, - }, - }, - [SAA7134_BOARD_AVERMEDIA_M733A] = { - .name = "Avermedia PCI M733A", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 0, - .gpiomask = 0x020200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x00200000, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x01, - }, - }, - [SAA7134_BOARD_BEHOLD_401] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 401", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_BEHOLD_403] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 403", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_BEHOLD_403FM] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 403 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_405] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 405", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_BEHOLD_405FM] = { - /* Sergey */ - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 405 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_407] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 407", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0xc0c000, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - .gpio = 0xc0c000, - },{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - .gpio = 0xc0c000, - }}, - }, - [SAA7134_BOARD_BEHOLD_407FM] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 407 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0xc0c000, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - .gpio = 0xc0c000, - },{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - .gpio = 0xc0c000, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0xc0c000, - }, - }, - [SAA7134_BOARD_BEHOLD_409] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 409", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_BEHOLD_505FM] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 505 FM", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_505RDS_MK5] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 505 RDS", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FM1216MK5, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_507_9FM] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 507 FM / BeholdTV 509 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_507RDS_MK5] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 507 RDS", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216MK5, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_507RDS_MK3] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 507 RDS", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = { - /* Beholder Intl. Ltd. 2008 */ - /* Dmitry Belimov */ - .name = "Beholder BeholdTV Columbus TV/FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_ALPS_TSBE5_PAL, - .radio_type = TUNER_TEA5767, - .tuner_addr = 0xc2 >> 1, - .radio_addr = 0xc0 >> 1, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x000A8004, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - .gpio = 0x000A8004, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - .gpio = 0x000A8000, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x000A8000, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x000A8000, - }, - }, - [SAA7134_BOARD_BEHOLD_607FM_MK3] = { - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 607 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_609FM_MK3] = { - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 609 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_607FM_MK5] = { - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 607 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216MK5, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_609FM_MK5] = { - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 609 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216MK5, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_607RDS_MK3] = { - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 607 RDS", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_609RDS_MK3] = { - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 609 RDS", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_607RDS_MK5] = { - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 607 RDS", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216MK5, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_609RDS_MK5] = { - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 609 RDS", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216MK5, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_M6] = { - /* Igor Kuznetsov */ - /* Andrey Melnikoff */ - /* Beholder Intl. Ltd. Dmitry Belimov */ - /* Alexey Osipov */ - .name = "Beholder BeholdTV M6", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .empress_addr = 0x20, - .tda9887_conf = TDA9887_PRESENT, - .inputs = { { - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - .mpeg = SAA7134_MPEG_EMPRESS, - .video_out = CCIR656, - .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED | - SET_CLOCK_NOT_DELAYED | - SET_CLOCK_INVERTED | - SET_VSYNC_OFF), - }, - [SAA7134_BOARD_BEHOLD_M63] = { - /* Igor Kuznetsov */ - /* Andrey Melnikoff */ - /* Beholder Intl. Ltd. Dmitry Belimov */ - .name = "Beholder BeholdTV M63", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .empress_addr = 0x20, - .tda9887_conf = TDA9887_PRESENT, - .inputs = { { - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - .mpeg = SAA7134_MPEG_EMPRESS, - .video_out = CCIR656, - .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED | - SET_CLOCK_NOT_DELAYED | - SET_CLOCK_INVERTED | - SET_VSYNC_OFF), - }, - [SAA7134_BOARD_BEHOLD_M6_EXTRA] = { - /* Igor Kuznetsov */ - /* Andrey Melnikoff */ - /* Beholder Intl. Ltd. Dmitry Belimov */ - /* Alexey Osipov */ - .name = "Beholder BeholdTV M6 Extra", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216MK5, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .empress_addr = 0x20, - .tda9887_conf = TDA9887_PRESENT, - .inputs = { { - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - .mpeg = SAA7134_MPEG_EMPRESS, - .video_out = CCIR656, - .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED | - SET_CLOCK_NOT_DELAYED | - SET_CLOCK_INVERTED | - SET_VSYNC_OFF), - }, - [SAA7134_BOARD_TWINHAN_DTV_DVB_3056] = { - .name = "Twinhan Hybrid DTV-DVB 3056 PCI", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, /* untested */ - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_GENIUS_TVGO_A11MCE] = { - /* Adrian Pardini */ - .name = "Genius TVGO AM11MCE", - .audio_clock = 0x00200000, - .tuner_type = TUNER_TNF_5335MF, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0xf000, - .inputs = {{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .gpio = 0x0000, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x2000, - .tv = 1 - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x2000, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x1000, - }, - .mute = { - .name = name_mute, - .amux = LINE2, - .gpio = 0x6000, - }, - }, - [SAA7134_BOARD_PHILIPS_SNAKE] = { - .name = "NXP Snake DVB-S reference design", - .audio_clock = 0x00200000, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - }, - [SAA7134_BOARD_CREATIX_CTX953] = { - .name = "Medion/Creatix CTX953 Hybrid", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 0, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - }, - [SAA7134_BOARD_MSI_TVANYWHERE_AD11] = { - .name = "MSI TV@nywhere A/D v1.1", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200000, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_AVERMEDIA_CARDBUS_506] = { - .name = "AVerMedia Cardbus TV/Radio (E506R)", - .audio_clock = 0x187de7, - .tuner_type = TUNER_XC2028, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - .radio = { - .name = name_radio, - .amux = TV, - }, - }, - [SAA7134_BOARD_AVERMEDIA_A16D] = { - .name = "AVerMedia Hybrid TV/Radio (A16D)", - .audio_clock = 0x187de7, - .tuner_type = TUNER_XC2028, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }, { - .name = name_comp, - .vmux = 0, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - }, - }, - [SAA7134_BOARD_AVERMEDIA_M115] = { - .name = "Avermedia M115", - .audio_clock = 0x187de7, - .tuner_type = TUNER_XC2028, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - }, - [SAA7134_BOARD_VIDEOMATE_T750] = { - /* John Newbigin */ - .name = "Compro VideoMate T750", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_XC2028, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE2, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - .radio = { - .name = name_radio, - .amux = TV, - } - }, - [SAA7134_BOARD_AVERMEDIA_A700_PRO] = { - /* Matthias Schwarzott */ - .name = "Avermedia DVB-S Pro A700", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = { { - .name = name_comp, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 6, - .amux = LINE1, - } }, - }, - [SAA7134_BOARD_AVERMEDIA_A700_HYBRID] = { - /* Matthias Schwarzott */ - .name = "Avermedia DVB-S Hybrid+FM A700", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_XC2028, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = { { - .name = name_tv, - .vmux = 4, - .amux = TV, - .tv = 1, - }, { - .name = name_comp, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 6, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - }, - }, - [SAA7134_BOARD_BEHOLD_H6] = { - /* Igor Kuznetsov */ - .name = "Beholder BeholdTV H6", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FMD1216MEX_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_ASUSTeK_TIGER_3IN1] = { - .name = "Asus Tiger 3in1", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 2, - .gpiomask = 1 << 21, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp, - .vmux = 0, - .amux = LINE2, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_REAL_ANGEL_220] = { - .name = "Zogis Real Angel 220", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_TNF_5335MF, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x801a8087, - .inputs = { { - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - .gpio = 0x624000, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - .gpio = 0x624000, - }, { - .name = name_svideo, - .vmux = 1, - .amux = LINE1, - .gpio = 0x624000, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x624001, - }, - .mute = { - .name = name_mute, - .amux = TV, - }, - }, - [SAA7134_BOARD_ADS_INSTANT_HDTV_PCI] = { - .name = "ADS Tech Instant HDTV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TUV1236D, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .mpeg = SAA7134_MPEG_DVB, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp, - .vmux = 4, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - }, - [SAA7134_BOARD_ASUSTeK_TIGER] = { - .name = "Asus Tiger Rev:1.00", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 0, - .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x0200000, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - }, { - .name = name_comp2, - .vmux = 0, - .amux = LINE2, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x0200000, - }, - }, - [SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG] = { - .name = "Kworld Plus TV Analog Lite PCI", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_YMEC_TVF_5533MF, - .radio_type = TUNER_TEA5767, - .tuner_addr = ADDR_UNSET, - .radio_addr = 0x60, - .gpiomask = 0x80000700, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - .gpio = 0x100, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x200, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x200, - } }, - .radio = { - .name = name_radio, - .vmux = 1, - .amux = LINE1, - .gpio = 0x100, - }, - .mute = { - .name = name_mute, - .vmux = 8, - .amux = 2, - }, - }, - [SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = { - .name = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .tuner_addr = ADDR_UNSET, - .radio_type = UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x8e054000, - .mpeg = SAA7134_MPEG_DVB, - .ts_type = SAA7134_MPEG_TS_PARALLEL, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, -#if 0 /* FIXME */ - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x200, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x200, -#endif - } }, -#if 0 - .radio = { - .name = name_radio, - .vmux = 1, - .amux = LINE1, - .gpio = 0x100, - }, -#endif - .mute = { - .name = name_mute, - .vmux = 0, - .amux = TV, - }, - }, - [SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS] = { - .name = "Avermedia AVerTV GO 007 FM Plus", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x00300003, - /* .gpiomask = 0x8c240003, */ - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x01, - }, { - .name = name_svideo, - .vmux = 6, - .amux = LINE1, - .gpio = 0x02, - } }, - .radio = { - .name = name_radio, - .amux = TV, - .gpio = 0x00300001, - }, - .mute = { - .name = name_mute, - .amux = TV, - .gpio = 0x01, - }, - }, - [SAA7134_BOARD_AVERMEDIA_STUDIO_507UA] = { - /* Andy Shevchenko */ - .name = "Avermedia AVerTV Studio 507UA", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* Should be MK5 */ - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x03, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x00, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x00, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x00, - } }, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x01, - }, - .mute = { - .name = name_mute, - .amux = LINE1, - .gpio = 0x00, - }, - }, - [SAA7134_BOARD_VIDEOMATE_S350] = { - /* Jan D. Louw */ - .name = "Beholder BeholdTV X7", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_XC5000, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = { { - .name = name_tv, - .vmux = 2, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 9, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - }, - }, - [SAA7134_BOARD_ZOLID_HYBRID_PCI] = { - .name = "Zolid Hybrid TV Tuner PCI", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tuner_config = 0, - .mpeg = SAA7134_MPEG_DVB, - .ts_type = SAA7134_MPEG_TS_PARALLEL, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - } }, - .radio = { /* untested */ - .name = name_radio, - .amux = TV, - }, - }, - [SAA7134_BOARD_ASUS_EUROPA_HYBRID] = { - .name = "Asus Europa Hybrid OEM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TD1316, - .radio_type = UNSET, - .tuner_addr = 0x61, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE, - .mpeg = SAA7134_MPEG_DVB, - .inputs = { { - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 4, - .amux = LINE2, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - }, - [SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S] = { - .name = "Leadtek Winfast DTV1000S", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .inputs = { { - .name = name_comp1, - .vmux = 3, - }, { - .name = name_svideo, - .vmux = 8, - } }, - }, - [SAA7134_BOARD_BEHOLD_505RDS_MK3] = { - /* Beholder Intl. Ltd. 2008 */ - /*Dmitry Belimov */ - .name = "Beholder BeholdTV 505 RDS", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .rds_addr = 0x10, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0x00008000, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - } }, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_HAWELL_HW_404M7] = { - /* Hawell HW-404M7 & Hawell HW-808M7 */ - /* Bogoslovskiy Viktor */ - .name = "Hawell HW-404M7", - .audio_clock = 0x00200000, - .tuner_type = UNSET, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .gpiomask = 0x389c00, - .inputs = {{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x01fc00, - } }, - }, - [SAA7134_BOARD_BEHOLD_H7] = { - /* Beholder Intl. Ltd. Dmitry Belimov */ - .name = "Beholder BeholdTV H7", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_XC5000, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, - .ts_type = SAA7134_MPEG_TS_PARALLEL, - .inputs = { { - .name = name_tv, - .vmux = 2, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 9, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - }, - }, - [SAA7134_BOARD_BEHOLD_A7] = { - /* Beholder Intl. Ltd. Dmitry Belimov */ - .name = "Beholder BeholdTV A7", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_XC5000, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = { { - .name = name_tv, - .vmux = 2, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - }, { - .name = name_svideo, - .vmux = 9, - .amux = LINE1, - } }, - .radio = { - .name = name_radio, - .amux = TV, - }, - }, - [SAA7134_BOARD_TECHNOTREND_BUDGET_T3000] = { - .name = "TechoTrend TT-budget T-3000", - .tuner_type = TUNER_PHILIPS_TD1316, - .audio_clock = 0x00187de7, - .radio_type = UNSET, - .tuner_addr = 0x63, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE, - .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - }, - [SAA7134_BOARD_VIDEOMATE_M1F] = { - /* Pavel Osnova */ - .name = "Compro VideoMate Vista M1F", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .radio_type = TUNER_TEA5767, - .tuner_addr = ADDR_UNSET, - .radio_addr = 0x60, - .inputs = { { - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - }, { - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - }, { - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - } }, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - .mute = { - .name = name_mute, - .amux = TV, - }, - }, - -}; - -const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); - -/* ------------------------------------------------------------------ */ -/* PCI ids + subsystem IDs */ - -struct pci_device_id saa7134_pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, - .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, - .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x6752, - .driver_data = SAA7134_BOARD_EMPRESS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x4e85, - .driver_data = SAA7134_BOARD_MONSTERTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153b, - .subdevice = 0x1142, - .driver_data = SAA7134_BOARD_CINERGY400, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153b, - .subdevice = 0x1143, - .driver_data = SAA7134_BOARD_CINERGY600, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153b, - .subdevice = 0x1158, - .driver_data = SAA7134_BOARD_CINERGY600_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1162, - .driver_data = SAA7134_BOARD_CINERGY400_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5169, - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000_NTSC, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5168, - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x4e42, /* "Typhoon PCI Capture TV Card" Art.No. 50673 */ - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x5168, - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO2000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x4e42, /* Typhoon */ - .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */ - .driver_data = SAA7134_BOARD_FLYVIDEO2000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x0212, /* minipci, LR212 */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x14c0, - .subdevice = 0x1212, /* minipci, LR1212 */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI2, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4e42, - .subdevice = 0x0212, /* OEM minipci, LR212 */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, /* Animation Technologies (LifeView) */ - .subdevice = 0x0214, /* Standard PCI, LR214 Rev E and earlier (SAA7135) */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, /* Animation Technologies (LifeView) */ - .subdevice = 0x5214, /* Standard PCI, LR214 Rev F onwards (SAA7131) */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1489, /* KYE */ - .subdevice = 0x0214, /* Genius VideoWonder ProTV */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */ - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x16be, - .subdevice = 0x0003, - .driver_data = SAA7134_BOARD_MD7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x16be, /* CTX946 analog TV, HW mpeg, DVB-T */ - .subdevice = 0x5000, /* only analog TV and DVB-T for now */ - .driver_data = SAA7134_BOARD_MD7134, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1048, - .subdevice = 0x226b, - .driver_data = SAA7134_BOARD_ELSA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1048, - .subdevice = 0x226a, - .driver_data = SAA7134_BOARD_ELSA_500TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1048, - .subdevice = 0x226c, - .driver_data = SAA7134_BOARD_ELSA_700TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4842, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4845, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7135, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4830, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4843, - .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4840, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0xfe01, - .driver_data = SAA7134_BOARD_TVSTATION_RDS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1894, - .subdevice = 0xfe01, - .driver_data = SAA7134_BOARD_TVSTATION_RDS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1894, - .subdevice = 0xa006, - .driver_data = SAA7134_BOARD_TVSTATION_DVR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x7133, - .driver_data = SAA7134_BOARD_VA1000POWER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, - .driver_data = SAA7134_BOARD_10MOONSTVMASTER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, - .driver_data = SAA7134_BOARD_VIDEOMATE_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, - .driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_MATROX, - .subdevice = 0x48d0, - .driver_data = SAA7134_BOARD_CRONOS_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa70b, - .driver_data = SAA7134_BOARD_MD2819, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa7a1, - .driver_data = SAA7134_BOARD_AVERMEDIA_A700_PRO, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa7a2, - .driver_data = SAA7134_BOARD_AVERMEDIA_A700_HYBRID, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2115, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa115, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_505, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2108, - .driver_data = SAA7134_BOARD_AVERMEDIA_305, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x10ff, - .driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER, - },{ - /* AVerMedia CardBus */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xd6ee, - .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS, - },{ - /* AVerMedia CardBus */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xb7e9, - .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_501, - }, { - /* TransGear 3000TV */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x050c, - .driver_data = SAA7134_BOARD_TG3000TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002b, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002d, - .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1019, - .subdevice = 0x4cb4, - .driver_data = SAA7134_BOARD_ECS_TVP3XP, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1019, - .subdevice = 0x4cb5, - .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1019, - .subdevice = 0x4cb6, - .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB6, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x12ab, - .subdevice = 0x0800, - .driver_data = SAA7134_BOARD_UPMOST_PURPLE_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x153b, - .subdevice = 0x1152, - .driver_data = SAA7134_BOARD_CINERGY200, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc100, - .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x9715, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_307, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa70a, - .driver_data = SAA7134_BOARD_AVERMEDIA_307, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x185b, - .subdevice = 0xc200, - .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1540, - .subdevice = 0x9524, - .driver_data = SAA7134_BOARD_PROVIDEO_PV952, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x0502, /* Cardbus version */ - .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x0306, /* PCI version */ - .driver_data = SAA7134_BOARD_FLYDVBTDUO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31f, - .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf11d, - .driver_data = SAA7134_BOARD_AVERMEDIA_M135A, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x4155, - .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x4255, - .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_PHILIPS_TOUGH, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x0350, /* PCI version */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x0351, /* PCI version, new revision */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x0370, /* cardbus version */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x1370, /* cardbus version */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4e42, /* Typhoon */ - .subdevice = 0x0502, /* LifeView LR502 OEM */ - .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x0210, /* mini pci NTSC version */ - .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1043, - .subdevice = 0x0210, /* mini pci PAL/SECAM version */ - .driver_data = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */ - .subdevice = 0x4091, - .driver_data = SAA7134_BOARD_BEHOLD_409FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5456, /* GoTView */ - .subdevice = 0x7135, - .driver_data = SAA7134_BOARD_GOTVIEW_7135, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_PHILIPS_EUROPA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_300, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc901, - .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_200, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1435, - .subdevice = 0x7350, - .driver_data = SAA7134_BOARD_RTD_VFG7350, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1435, - .subdevice = 0x7330, - .driver_data = SAA7134_BOARD_RTD_VFG7330, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, - .subdevice = 0x1044, - .driver_data = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1131, - .subdevice = 0x4ee9, - .driver_data = SAA7134_BOARD_MONSTERTV_MOBILE, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x11bd, - .subdevice = 0x002e, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_110i, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4862, - .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2018, - .driver_data = SAA7134_BOARD_PHILIPS_TIGER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, - .subdevice = 0x6231, /* tda8275a, ks003 IR */ - .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, - .subdevice = 0x8624, /* tda8275, ks003 IR */ - .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1160, - .driver_data = SAA7134_BOARD_CINERGY250PCI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA 7131E */ - .subvendor = 0x5168, - .subdevice = 0x0319, - .driver_data = SAA7134_BOARD_FLYDVB_TRIO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x2c05, - .driver_data = SAA7134_BOARD_AVERMEDIA_777, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5168, - .subdevice = 0x0301, - .driver_data = SAA7134_BOARD_FLYDVBT_LR301, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0331, - .subdevice = 0x1421, - .driver_data = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x17de, - .subdevice = 0x7201, - .driver_data = SAA7134_BOARD_TEVION_DVBT_220RF, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x17de, - .subdevice = 0x7250, - .driver_data = SAA7134_BOARD_KWORLD_DVBT_210, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x17de, - .subdevice = 0x7350, - .driver_data = SAA7134_BOARD_KWORLD_ATSC110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x17de, - .subdevice = 0x7352, - .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x7360, - .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x6360, - .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B1, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x16be, - .subdevice = 0x0005, - .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5168, - .subdevice = 0x0300, - .driver_data = SAA7134_BOARD_FLYDVBS_LR300, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x4e42, - .subdevice = 0x0300,/* LR300 */ - .driver_data = SAA7134_BOARD_FLYDVBS_LR300, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1489, - .subdevice = 0x0301, - .driver_data = SAA7134_BOARD_FLYDVBT_LR301, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, /* Animation Technologies (LifeView) */ - .subdevice = 0x0304, - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x3306, - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x3502, /* whats the difference to 0x3306 ?*/ - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x3307, /* FlyDVB-T Hybrid Mini PCI */ - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x0007, - .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x0008, - .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x000d, /* triple CTX948_V1.1.1 */ - .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, - .subdevice = 0x2c05, - .driver_data = SAA7134_BOARD_AVERMEDIA_777, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1489, - .subdevice = 0x0502, /* Cardbus version */ - .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0919, /* Philips Proteus PRO 2309 */ - .subdevice = 0x2003, - .driver_data = SAA7134_BOARD_PROTEUS_2309, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x2c00, - .driver_data = SAA7134_BOARD_AVERMEDIA_A16AR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1043, - .subdevice = 0x4860, - .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x11bd, - .subdevice = 0x002f, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_310i, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x9715, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa11b, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4876, - .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6700, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6701, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6702, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6703, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6704, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6705, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6706, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6707, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6708, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6709, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x670a, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1172, - .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2342, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0x2341, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x3016, - .subdevice = 0x2344, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0x230f, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1a7f, - .subdevice = 0x2008, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM53, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1a7f, - .subdevice = 0x2108, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM3, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1175, - .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31e, - .driver_data = SAA7134_BOARD_AVERMEDIA_M102, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4E42, /* MSI */ - .subdevice = 0x0306, /* TV@nywhere DUO */ - .driver_data = SAA7134_BOARD_FLYDVBTDUO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4871, - .driver_data = SAA7134_BOARD_ASUS_P7131_4871, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4857, /* REV:1.00 */ - .driver_data = SAA7134_BOARD_ASUSTeK_TIGER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0919, /* SinoVideo PCI 2309 Proteus (7134) */ - .subdevice = 0x2003, /* OEM cardbus */ - .driver_data = SAA7134_BOARD_SABRENT_TV_PCB05, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2304, - .driver_data = SAA7134_BOARD_10MOONSTVMASTER3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ - .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4016, - .driver_data = SAA7134_BOARD_BEHOLD_401, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4036, - .driver_data = SAA7134_BOARD_BEHOLD_403, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4037, - .driver_data = SAA7134_BOARD_BEHOLD_403FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4050, - .driver_data = SAA7134_BOARD_BEHOLD_405, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4051, - .driver_data = SAA7134_BOARD_BEHOLD_405FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4070, - .driver_data = SAA7134_BOARD_BEHOLD_407, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4071, - .driver_data = SAA7134_BOARD_BEHOLD_407FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x4090, - .driver_data = SAA7134_BOARD_BEHOLD_409, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x505B, - .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK5, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x5051, - .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x5ace, - .subdevice = 0x5050, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x5071, - .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x507B, - .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x5070, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x5090, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x5201, - .driver_data = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6070, - .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6071, - .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6072, - .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6073, - .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6090, - .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6091, - .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6092, - .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6093, - .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6190, - .driver_data = SAA7134_BOARD_BEHOLD_M6, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6193, - .driver_data = SAA7134_BOARD_BEHOLD_M6_EXTRA, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6191, - .driver_data = SAA7134_BOARD_BEHOLD_M63, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4e42, - .subdevice = 0x3502, - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1822, /*Twinhan Technology Co. Ltd*/ - .subdevice = 0x0022, - .driver_data = SAA7134_BOARD_TWINHAN_DTV_DVB_3056, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x0010, /* Medion version CTX953_V.1.4.3 */ - .driver_data = SAA7134_BOARD_CREATIX_CTX953, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, /* MSI */ - .subdevice = 0x8625, /* TV@nywhere A/D v1.1 */ - .driver_data = SAA7134_BOARD_MSI_TVANYWHERE_AD11, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf436, - .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_506, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf936, - .driver_data = SAA7134_BOARD_AVERMEDIA_A16D, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa836, - .driver_data = SAA7134_BOARD_AVERMEDIA_M115, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_T750, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x1421, - .subdevice = 0x0380, - .driver_data = SAA7134_BOARD_ADS_INSTANT_HDTV_PCI, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5169, - .subdevice = 0x1502, - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6290, - .driver_data = SAA7134_BOARD_BEHOLD_H6, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf636, - .driver_data = SAA7134_BOARD_AVERMEDIA_M103, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf736, - .driver_data = SAA7134_BOARD_AVERMEDIA_M103, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4878, /* REV:1.02G */ - .driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x17de, - .subdevice = 0x7128, - .driver_data = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x17de, - .subdevice = 0xb136, - .driver_data = SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31d, - .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_S350, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ - .subdevice = 0x7595, - .driver_data = SAA7134_BOARD_BEHOLD_X7, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x19d1, /* RoverMedia */ - .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */ - .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1043, - .subdevice = 0x4847, - .driver_data = SAA7134_BOARD_ASUS_EUROPA_HYBRID, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x107d, - .subdevice = 0x6655, - .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x13c2, - .subdevice = 0x2804, - .driver_data = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ - .subdevice = 0x7190, - .driver_data = SAA7134_BOARD_BEHOLD_H7, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ - .subdevice = 0x7090, - .driver_data = SAA7134_BOARD_BEHOLD_A7, - }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_M1F, - }, { - /* --- boards without eeprom + subsystem ID --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0, - .driver_data = SAA7134_BOARD_NOAUTO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0, - .driver_data = SAA7134_BOARD_NOAUTO, - },{ - /* --- default catch --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - /* --- end of list --- */ - } -}; -MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl); - -/* ----------------------------------------------------------- */ -/* flyvideo tweaks */ - - -static void board_flyvideo(struct saa7134_dev *dev) -{ - printk("%s: there are different flyvideo cards with different tuners\n" - "%s: out there, you might have to use the tuner= insmod\n" - "%s: option to override the default value.\n", - dev->name, dev->name, dev->name); -} - -static int saa7134_xc2028_callback(struct saa7134_dev *dev, - int command, int arg) -{ - switch (command) { - case XC2028_TUNER_RESET: - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00000000); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000); - switch (dev->board) { - case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: - case SAA7134_BOARD_AVERMEDIA_M103: - saa7134_set_gpio(dev, 23, 0); - msleep(10); - saa7134_set_gpio(dev, 23, 1); - break; - case SAA7134_BOARD_AVERMEDIA_A16D: - saa7134_set_gpio(dev, 21, 0); - msleep(10); - saa7134_set_gpio(dev, 21, 1); - break; - case SAA7134_BOARD_AVERMEDIA_A700_HYBRID: - saa7134_set_gpio(dev, 18, 0); - msleep(10); - saa7134_set_gpio(dev, 18, 1); - break; - } - return 0; - } - return -EINVAL; -} - -static int saa7134_xc5000_callback(struct saa7134_dev *dev, - int command, int arg) -{ - switch (dev->board) { - case SAA7134_BOARD_BEHOLD_X7: - case SAA7134_BOARD_BEHOLD_H7: - case SAA7134_BOARD_BEHOLD_A7: - if (command == XC5000_TUNER_RESET) { - /* Down and UP pheripherial RESET pin for reset all chips */ - saa_writeb(SAA7134_SPECIAL_MODE, 0x00); - msleep(10); - saa_writeb(SAA7134_SPECIAL_MODE, 0x01); - msleep(10); - } - break; - default: - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000); - saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02); - saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81); - saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7); - saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03); - saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2, - 0x0001e000, 0x0001e000); - break; - } - return 0; -} - -static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev, - int command, int arg) -{ - u8 sync_control; - - switch (command) { - case 0: /* switch LNA gain through GPIO 22*/ - saa7134_set_gpio(dev, 22, arg) ; - break; - case 1: /* vsync output at GPIO22. 50 / 60Hz */ - saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80); - saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03); - if (arg == 1) - sync_control = 11; - else - sync_control = 17; - saa_writeb(SAA7134_VGATE_START, sync_control); - saa_writeb(SAA7134_VGATE_STOP, sync_control + 1); - saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00); - break; - default: - return -EINVAL; - } - - return 0; -} - -static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev, - enum tda18271_mode mode) -{ - /* toggle AGC switch through GPIO 26 */ - switch (mode) { - case TDA18271_ANALOG: - saa7134_set_gpio(dev, 26, 0); - break; - case TDA18271_DIGITAL: - saa7134_set_gpio(dev, 26, 1); - break; - default: - return -EINVAL; - } - return 0; -} - -static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev, - enum tda18271_mode mode) -{ - /* toggle AGC switch through GPIO 27 */ - switch (mode) { - case TDA18271_ANALOG: - saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000); - saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000); - msleep(20); - break; - case TDA18271_DIGITAL: - saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000); - saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000); - msleep(20); - saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000); - saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000); - msleep(30); - break; - default: - return -EINVAL; - } - return 0; -} - -static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, - int command, int arg) -{ - int ret = 0; - - switch (command) { - case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */ - switch (dev->board) { - case SAA7134_BOARD_HAUPPAUGE_HVR1150: - case SAA7134_BOARD_HAUPPAUGE_HVR1120: - ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg); - break; - case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: - ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg); - break; - default: - break; - } - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static int saa7134_tda8290_callback(struct saa7134_dev *dev, - int command, int arg) -{ - int ret; - - switch (dev->board) { - case SAA7134_BOARD_HAUPPAUGE_HVR1150: - case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_AVERMEDIA_M733A: - case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: - /* tda8290 + tda18271 */ - ret = saa7134_tda8290_18271_callback(dev, command, arg); - break; - default: - /* tda8290 + tda827x */ - ret = saa7134_tda8290_827x_callback(dev, command, arg); - break; - } - return ret; -} - -int saa7134_tuner_callback(void *priv, int component, int command, int arg) -{ - struct saa7134_dev *dev = priv; - - if (dev != NULL) { - switch (dev->tuner_type) { - case TUNER_PHILIPS_TDA8290: - return saa7134_tda8290_callback(dev, command, arg); - case TUNER_XC2028: - return saa7134_xc2028_callback(dev, command, arg); - case TUNER_XC5000: - return saa7134_xc5000_callback(dev, command, arg); - } - } else { - printk(KERN_ERR "saa7134: Error - device struct undefined.\n"); - return -EINVAL; - } - return -EINVAL; -} -EXPORT_SYMBOL(saa7134_tuner_callback); - -/* ----------------------------------------------------------- */ - -static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) -{ - struct tveeprom tv; - - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); - - /* Make sure we support the board model */ - switch (tv.model) { - case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */ - case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ - case 67201: /* WinTV-HVR1150 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ - case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ - case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ - case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ - case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */ - case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */ - case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ - case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ - case 67651: /* WinTV-HVR1150 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ - case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ - break; - default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", dev->name, tv.model); - break; - } - - printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", - dev->name, tv.model); -} - -/* ----------------------------------------------------------- */ - -int saa7134_board_init1(struct saa7134_dev *dev) -{ - /* Always print gpio, often manufacturers encode tuner type and other info. */ - saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0); - dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - printk(KERN_INFO "%s: board init: gpio is %x\n", dev->name, dev->gpio_value); - - switch (dev->board) { - case SAA7134_BOARD_FLYVIDEO2000: - case SAA7134_BOARD_FLYVIDEO3000: - case SAA7134_BOARD_FLYVIDEO3000_NTSC: - dev->has_remote = SAA7134_REMOTE_GPIO; - board_flyvideo(dev); - break; - case SAA7134_BOARD_FLYTVPLATINUM_MINI2: - case SAA7134_BOARD_FLYTVPLATINUM_FM: - case SAA7134_BOARD_CINERGY400: - case SAA7134_BOARD_CINERGY600: - case SAA7134_BOARD_CINERGY600_MK3: - case SAA7134_BOARD_ECS_TVP3XP: - case SAA7134_BOARD_ECS_TVP3XP_4CB5: - case SAA7134_BOARD_ECS_TVP3XP_4CB6: - case SAA7134_BOARD_MD2819: - case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: - case SAA7134_BOARD_KWORLD_XPERT: - case SAA7134_BOARD_AVERMEDIA_STUDIO_305: - case SAA7134_BOARD_AVERMEDIA_STUDIO_505: - case SAA7134_BOARD_AVERMEDIA_305: - case SAA7134_BOARD_AVERMEDIA_STUDIO_307: - case SAA7134_BOARD_AVERMEDIA_307: - case SAA7134_BOARD_AVERMEDIA_STUDIO_507: - case SAA7134_BOARD_AVERMEDIA_GO_007_FM: - case SAA7134_BOARD_AVERMEDIA_777: - case SAA7134_BOARD_AVERMEDIA_M135A: -/* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */ - case SAA7134_BOARD_VIDEOMATE_TV_PVR: - case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS: - case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: - case SAA7134_BOARD_VIDEOMATE_M1F: - case SAA7134_BOARD_VIDEOMATE_DVBT_300: - case SAA7134_BOARD_VIDEOMATE_DVBT_200: - case SAA7134_BOARD_VIDEOMATE_DVBT_200A: - case SAA7134_BOARD_MANLI_MTV001: - case SAA7134_BOARD_MANLI_MTV002: - case SAA7134_BOARD_BEHOLD_409FM: - case SAA7134_BOARD_AVACSSMARTTV: - case SAA7134_BOARD_GOTVIEW_7135: - case SAA7134_BOARD_KWORLD_TERMINATOR: - case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: - case SAA7134_BOARD_FLYDVBT_LR301: - case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: - case SAA7134_BOARD_ASUSTeK_P7131_ANALOG: - case SAA7134_BOARD_FLYDVBTDUO: - case SAA7134_BOARD_PROTEUS_2309: - case SAA7134_BOARD_AVERMEDIA_A16AR: - case SAA7134_BOARD_ENCORE_ENLTV: - case SAA7134_BOARD_ENCORE_ENLTV_FM: - case SAA7134_BOARD_ENCORE_ENLTV_FM53: - case SAA7134_BOARD_ENCORE_ENLTV_FM3: - case SAA7134_BOARD_10MOONSTVMASTER3: - case SAA7134_BOARD_BEHOLD_401: - case SAA7134_BOARD_BEHOLD_403: - case SAA7134_BOARD_BEHOLD_403FM: - case SAA7134_BOARD_BEHOLD_405: - case SAA7134_BOARD_BEHOLD_405FM: - case SAA7134_BOARD_BEHOLD_407: - case SAA7134_BOARD_BEHOLD_407FM: - case SAA7134_BOARD_BEHOLD_409: - case SAA7134_BOARD_BEHOLD_505FM: - case SAA7134_BOARD_BEHOLD_505RDS_MK5: - case SAA7134_BOARD_BEHOLD_505RDS_MK3: - case SAA7134_BOARD_BEHOLD_507_9FM: - case SAA7134_BOARD_BEHOLD_507RDS_MK3: - case SAA7134_BOARD_BEHOLD_507RDS_MK5: - case SAA7134_BOARD_GENIUS_TVGO_A11MCE: - case SAA7134_BOARD_REAL_ANGEL_220: - case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG: - case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS: - case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM: - case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S: - dev->has_remote = SAA7134_REMOTE_GPIO; - break; - case SAA7134_BOARD_FLYDVBS_LR300: - saa_writeb(SAA7134_GPIO_GPMODE3, 0x80); - saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x40); - dev->has_remote = SAA7134_REMOTE_GPIO; - break; - case SAA7134_BOARD_MD5044: - printk("%s: seems there are two different versions of the MD5044\n" - "%s: (with the same ID) out there. If sound doesn't work for\n" - "%s: you try the audio_clock_override=0x200000 insmod option.\n", - dev->name,dev->name,dev->name); - break; - case SAA7134_BOARD_CINERGY400_CARDBUS: - /* power-up tuner chip */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000); - break; - case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: - /* this turns the remote control chip off to work around a bug in it */ - saa_writeb(SAA7134_GPIO_GPMODE1, 0x80); - saa_writeb(SAA7134_GPIO_GPSTATUS1, 0x80); - break; - case SAA7134_BOARD_MONSTERTV_MOBILE: - /* power-up tuner chip */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000004); - break; - case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS: - /* turn the fan on */ - saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); - saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06); - break; - case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: - case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08000000, 0x08000000); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000); - break; - case SAA7134_BOARD_AVERMEDIA_CARDBUS: - case SAA7134_BOARD_AVERMEDIA_M115: - /* power-down tuner chip */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0); - msleep(10); - /* power-up tuner chip */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff); - msleep(10); - break; - case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: - /* power-down tuner chip */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08400000, 0x08400000); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0); - msleep(10); - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08400000, 0x08400000); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0x08400000); - msleep(10); - dev->has_remote = SAA7134_REMOTE_I2C; - break; - case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: - saa7134_set_gpio(dev, 23, 0); - msleep(10); - saa7134_set_gpio(dev, 23, 1); - dev->has_remote = SAA7134_REMOTE_I2C; - break; - case SAA7134_BOARD_AVERMEDIA_M103: - saa7134_set_gpio(dev, 23, 0); - msleep(10); - saa7134_set_gpio(dev, 23, 1); - break; - case SAA7134_BOARD_AVERMEDIA_A16D: - saa7134_set_gpio(dev, 21, 0); - msleep(10); - saa7134_set_gpio(dev, 21, 1); - msleep(1); - dev->has_remote = SAA7134_REMOTE_GPIO; - break; - case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: - /* power-down tuner chip */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x000A8004, 0x000A8004); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0); - msleep(10); - /* power-up tuner chip */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x000A8004, 0x000A8004); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0x000A8004); - msleep(10); - /* remote via GPIO */ - dev->has_remote = SAA7134_REMOTE_GPIO; - break; - case SAA7134_BOARD_RTD_VFG7350: - - /* - * Make sure Production Test Register at offset 0x1D1 is cleared - * to take chip out of test mode. Clearing bit 4 (TST_EN_AOUT) - * prevents pin 105 from remaining low; keeping pin 105 low - * continually resets the SAA6752 chip. - */ - - saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00); - break; - case SAA7134_BOARD_HAUPPAUGE_HVR1150: - case SAA7134_BOARD_HAUPPAUGE_HVR1120: - /* GPIO 26 high for digital, low for analog */ - saa7134_set_gpio(dev, 26, 0); - msleep(1); - - saa7134_set_gpio(dev, 22, 0); - msleep(10); - saa7134_set_gpio(dev, 22, 1); - break; - /* i2c remotes */ - case SAA7134_BOARD_PINNACLE_PCTV_110i: - case SAA7134_BOARD_PINNACLE_PCTV_310i: - case SAA7134_BOARD_UPMOST_PURPLE_TV: - case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: - case SAA7134_BOARD_HAUPPAUGE_HVR1110: - case SAA7134_BOARD_BEHOLD_607FM_MK3: - case SAA7134_BOARD_BEHOLD_607FM_MK5: - case SAA7134_BOARD_BEHOLD_609FM_MK3: - case SAA7134_BOARD_BEHOLD_609FM_MK5: - case SAA7134_BOARD_BEHOLD_607RDS_MK3: - case SAA7134_BOARD_BEHOLD_607RDS_MK5: - case SAA7134_BOARD_BEHOLD_609RDS_MK3: - case SAA7134_BOARD_BEHOLD_609RDS_MK5: - case SAA7134_BOARD_BEHOLD_M6: - case SAA7134_BOARD_BEHOLD_M63: - case SAA7134_BOARD_BEHOLD_M6_EXTRA: - case SAA7134_BOARD_BEHOLD_H6: - case SAA7134_BOARD_BEHOLD_X7: - case SAA7134_BOARD_BEHOLD_H7: - case SAA7134_BOARD_BEHOLD_A7: - dev->has_remote = SAA7134_REMOTE_I2C; - break; - case SAA7134_BOARD_AVERMEDIA_A169_B: - printk("%s: %s: dual saa713x broadcast decoders\n" - "%s: Sorry, none of the inputs to this chip are supported yet.\n" - "%s: Dual decoder functionality is disabled for now, use the other chip.\n", - dev->name,card(dev).name,dev->name,dev->name); - break; - case SAA7134_BOARD_AVERMEDIA_M102: - /* enable tuner */ - dev->has_remote = SAA7134_REMOTE_GPIO; - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd); - break; - case SAA7134_BOARD_AVERMEDIA_A700_HYBRID: - case SAA7134_BOARD_AVERMEDIA_A700_PRO: - /* write windows gpio values */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100); - break; - case SAA7134_BOARD_VIDEOMATE_S350: - dev->has_remote = SAA7134_REMOTE_GPIO; - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0000C000, 0x0000C000); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0000C000, 0x0000C000); - break; - case SAA7134_BOARD_AVERMEDIA_M733A: - saa7134_set_gpio(dev, 1, 1); - msleep(10); - saa7134_set_gpio(dev, 1, 0); - msleep(10); - saa7134_set_gpio(dev, 1, 1); - dev->has_remote = SAA7134_REMOTE_GPIO; - break; - } - return 0; -} - -static void saa7134_tuner_setup(struct saa7134_dev *dev) -{ - struct tuner_setup tun_setup; - unsigned int mode_mask = T_RADIO | T_ANALOG_TV; - - memset(&tun_setup, 0, sizeof(tun_setup)); - tun_setup.tuner_callback = saa7134_tuner_callback; - - if (saa7134_boards[dev->board].radio_type != UNSET) { - tun_setup.type = saa7134_boards[dev->board].radio_type; - tun_setup.addr = saa7134_boards[dev->board].radio_addr; - - tun_setup.mode_mask = T_RADIO; - - saa_call_all(dev, tuner, s_type_addr, &tun_setup); - mode_mask &= ~T_RADIO; - } - - if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) { - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - tun_setup.config = saa7134_boards[dev->board].tuner_config; - tun_setup.tuner_callback = saa7134_tuner_callback; - - tun_setup.mode_mask = mode_mask; - - saa_call_all(dev, tuner, s_type_addr, &tun_setup); - } - - if (dev->tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - saa_call_all(dev, tuner, s_config, &tda9887_cfg); - } - - if (dev->tuner_type == TUNER_XC2028) { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); - memset(&ctl, 0, sizeof(ctl)); - - ctl.fname = XC2028_DEFAULT_FIRMWARE; - ctl.max_len = 64; - - switch (dev->board) { - case SAA7134_BOARD_AVERMEDIA_A16D: - case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: - case SAA7134_BOARD_AVERMEDIA_M103: - case SAA7134_BOARD_AVERMEDIA_A700_HYBRID: - ctl.demod = XC3028_FE_ZARLINK456; - break; - default: - ctl.demod = XC3028_FE_OREN538; - ctl.mts = 1; - } - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - saa_call_all(dev, tuner, s_config, &xc2028_cfg); - } -} - -/* stuff which needs working i2c */ -int saa7134_board_init2(struct saa7134_dev *dev) -{ - unsigned char buf; - int board; - - /* Put here the code that enables the chips that are needed - for analog mode and doesn't depend on the tuner attachment. - It is also a good idea to get tuner type from eeprom, etc before - initializing tuner, since we can avoid loading tuner driver - on devices that has TUNER_ABSENT - */ - switch (dev->board) { - case SAA7134_BOARD_BMK_MPEX_NOTUNER: - case SAA7134_BOARD_BMK_MPEX_TUNER: - /* Checks if the device has a tuner at 0x60 addr - If the device doesn't have a tuner, TUNER_ABSENT - will be used at tuner_type, avoiding loading tuner - without needing it - */ - dev->i2c_client.addr = 0x60; - board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0) - ? SAA7134_BOARD_BMK_MPEX_NOTUNER - : SAA7134_BOARD_BMK_MPEX_TUNER; - if (board == dev->board) - break; - dev->board = board; - printk("%s: board type fixup: %s\n", dev->name, - saa7134_boards[dev->board].name); - dev->tuner_type = saa7134_boards[dev->board].tuner_type; - - break; - case SAA7134_BOARD_MD7134: - { - u8 subaddr; - u8 data[3]; - int ret, tuner_t; - struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1}, - {.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}}; - - subaddr= 0x14; - tuner_t = 0; - - /* Retrieve device data from eeprom, checking for the - proper tuner_type. - */ - ret = i2c_transfer(&dev->i2c_adap, msg, 2); - if (ret != 2) { - printk(KERN_ERR "EEPROM read failure\n"); - } else if ((data[0] != 0) && (data[0] != 0xff)) { - /* old config structure */ - subaddr = data[0] + 2; - msg[1].len = 2; - i2c_transfer(&dev->i2c_adap, msg, 2); - tuner_t = (data[0] << 8) + data[1]; - switch (tuner_t){ - case 0x0103: - dev->tuner_type = TUNER_PHILIPS_PAL; - break; - case 0x010C: - dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3; - break; - default: - printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t); - } - } else if ((data[1] != 0) && (data[1] != 0xff)) { - /* new config structure */ - subaddr = data[1] + 1; - msg[1].len = 1; - i2c_transfer(&dev->i2c_adap, msg, 2); - subaddr = data[0] + 1; - msg[1].len = 2; - i2c_transfer(&dev->i2c_adap, msg, 2); - tuner_t = (data[1] << 8) + data[0]; - switch (tuner_t) { - case 0x0005: - dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3; - break; - case 0x001d: - dev->tuner_type = TUNER_PHILIPS_FMD1216ME_MK3; - printk(KERN_INFO "%s Board has DVB-T\n", dev->name); - break; - default: - printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t); - } - } else { - printk(KERN_ERR "%s unexpected config structure\n", dev->name); - } - - printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); - break; - } - case SAA7134_BOARD_PHILIPS_EUROPA: - if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) { - /* Reconfigure board as Snake reference design */ - dev->board = SAA7134_BOARD_PHILIPS_SNAKE; - dev->tuner_type = saa7134_boards[dev->board].tuner_type; - printk(KERN_INFO "%s: Reconfigured board as %s\n", - dev->name, saa7134_boards[dev->board].name); - break; - } - /* break intentionally omitted */ - case SAA7134_BOARD_VIDEOMATE_DVBT_300: - case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: - case SAA7134_BOARD_ASUS_EUROPA_HYBRID: - case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000: - { - - /* The Philips EUROPA based hybrid boards have the tuner - connected through the channel decoder. We have to make it - transparent to find it - */ - u8 data[] = { 0x07, 0x02}; - struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - i2c_transfer(&dev->i2c_adap, &msg, 1); - - break; - } - case SAA7134_BOARD_PHILIPS_TIGER: - case SAA7134_BOARD_PHILIPS_TIGER_S: - { - u8 data[] = { 0x3c, 0x33, 0x60}; - struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - if (dev->autodetected && (dev->eedata[0x49] == 0x50)) { - dev->board = SAA7134_BOARD_PHILIPS_TIGER_S; - printk(KERN_INFO "%s: Reconfigured board as %s\n", - dev->name, saa7134_boards[dev->board].name); - } - if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { - dev->tuner_type = TUNER_PHILIPS_TDA8290; - - data[2] = 0x68; - i2c_transfer(&dev->i2c_adap, &msg, 1); - break; - } - i2c_transfer(&dev->i2c_adap, &msg, 1); - break; - } - case SAA7134_BOARD_ASUSTeK_TVFM7135: - /* The card below is detected as card=53, but is different */ - if (dev->autodetected && (dev->eedata[0x27] == 0x03)) { - dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG; - printk(KERN_INFO "%s: P7131 analog only, using " - "entry of %s\n", - dev->name, saa7134_boards[dev->board].name); - - /* IR init has already happened for other cards, so - * we have to catch up. */ - dev->has_remote = SAA7134_REMOTE_GPIO; - saa7134_input_init1(dev); - } - break; - case SAA7134_BOARD_HAUPPAUGE_HVR1150: - case SAA7134_BOARD_HAUPPAUGE_HVR1120: - hauppauge_eeprom(dev, dev->eedata+0x80); - break; - case SAA7134_BOARD_HAUPPAUGE_HVR1110: - hauppauge_eeprom(dev, dev->eedata+0x80); - /* break intentionally omitted */ - case SAA7134_BOARD_PINNACLE_PCTV_310i: - case SAA7134_BOARD_KWORLD_DVBT_210: - case SAA7134_BOARD_TEVION_DVBT_220RF: - case SAA7134_BOARD_ASUSTeK_TIGER: - case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: - case SAA7134_BOARD_MEDION_MD8800_QUADRO: - case SAA7134_BOARD_AVERMEDIA_SUPER_007: - case SAA7134_BOARD_TWINHAN_DTV_DVB_3056: - case SAA7134_BOARD_CREATIX_CTX953: - { - /* this is a hybrid board, initialize to analog mode - * and configure firmware eeprom address - */ - u8 data[] = { 0x3c, 0x33, 0x60}; - struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - i2c_transfer(&dev->i2c_adap, &msg, 1); - break; - } - case SAA7134_BOARD_ASUSTeK_TIGER_3IN1: - { - u8 data[] = { 0x3c, 0x33, 0x60}; - struct i2c_msg msg = {.addr = 0x0b, .flags = 0, .buf = data, - .len = sizeof(data)}; - i2c_transfer(&dev->i2c_adap, &msg, 1); - break; - } - case SAA7134_BOARD_FLYDVB_TRIO: - { - u8 temp = 0; - int rc; - u8 data[] = { 0x3c, 0x33, 0x62}; - struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)}; - i2c_transfer(&dev->i2c_adap, &msg, 1); - - /* - * send weak up message to pic16C505 chip - * @ LifeView FlyDVB Trio - */ - msg.buf = &temp; - msg.addr = 0x0b; - msg.len = 1; - if (1 != i2c_transfer(&dev->i2c_adap, &msg, 1)) { - printk(KERN_WARNING "%s: send wake up byte to pic16C505" - "(IR chip) failed\n", dev->name); - } else { - msg.flags = I2C_M_RD; - rc = i2c_transfer(&dev->i2c_adap, &msg, 1); - printk(KERN_INFO "%s: probe IR chip @ i2c 0x%02x: %s\n", - dev->name, msg.addr, - (1 == rc) ? "yes" : "no"); - if (rc == 1) - dev->has_remote = SAA7134_REMOTE_I2C; - } - break; - } - case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: - case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: - { - /* initialize analog mode */ - u8 data[] = { 0x3c, 0x33, 0x6a}; - struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - i2c_transfer(&dev->i2c_adap, &msg, 1); - break; - } - case SAA7134_BOARD_CINERGY_HT_PCMCIA: - case SAA7134_BOARD_CINERGY_HT_PCI: - { - /* initialize analog mode */ - u8 data[] = { 0x3c, 0x33, 0x68}; - struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - i2c_transfer(&dev->i2c_adap, &msg, 1); - break; - } - case SAA7134_BOARD_VIDEOMATE_DVBT_200: - case SAA7134_BOARD_VIDEOMATE_DVBT_200A: - /* The T200 and the T200A share the same pci id. Consequently, - * we are going to query eeprom to try to find out which one we - * are actually looking at. */ - - /* Don't do this if the board was specifically selected with an - * insmod option or if we have the default configuration T200*/ - if (!dev->autodetected || (dev->eedata[0x41] == 0xd0)) - break; - if (dev->eedata[0x41] == 0x02) { - /* Reconfigure board as T200A */ - dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A; - dev->tuner_type = saa7134_boards[dev->board].tuner_type; - dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; - printk(KERN_INFO "%s: Reconfigured board as %s\n", - dev->name, saa7134_boards[dev->board].name); - } else { - printk(KERN_WARNING "%s: Unexpected tuner type info: %x in eeprom\n", - dev->name, dev->eedata[0x41]); - break; - } - break; - case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI: - case SAA7134_BOARD_KWORLD_ATSC110: - { - struct i2c_msg msg = { .addr = 0x0a, .flags = 0 }; - int i; - static u8 buffer[][2] = { - { 0x10, 0x12 }, - { 0x13, 0x04 }, - { 0x16, 0x00 }, - { 0x14, 0x04 }, - { 0x17, 0x00 }, - }; - - for (i = 0; i < ARRAY_SIZE(buffer); i++) { - msg.buf = &buffer[i][0]; - msg.len = ARRAY_SIZE(buffer[0]); - if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) - printk(KERN_WARNING - "%s: Unable to enable tuner(%i).\n", - dev->name, i); - } - break; - } - case SAA7134_BOARD_BEHOLD_H6: - { - u8 data[] = { 0x09, 0x9f, 0x86, 0x11}; - struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = data, - .len = sizeof(data)}; - - /* The tuner TUNER_PHILIPS_FMD1216MEX_MK3 after hardware */ - /* start has disabled IF and enabled DVB-T. When saa7134 */ - /* scan I2C devices it not detect IF tda9887 and can`t */ - /* watch TV without software reboot. For solve this problem */ - /* switch the tuner to analog TV mode manually. */ - if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) - printk(KERN_WARNING - "%s: Unable to enable IF of the tuner.\n", - dev->name); - break; - } - case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: - saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000); - saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000); - - saa7134_set_gpio(dev, 27, 0); - break; - } /* switch() */ - - /* initialize tuner */ - if (TUNER_ABSENT != dev->tuner_type) { - int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); - - /* Note: radio tuner address is always filled in, - so we do not need to probe for a radio tuner device. */ - if (dev->radio_type != UNSET) - v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "tuner", - dev->radio_addr, NULL); - if (has_demod) - v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); - if (dev->tuner_addr == ADDR_UNSET) { - enum v4l2_i2c_tuner_type type = - has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; - - v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(type)); - } else { - v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "tuner", - dev->tuner_addr, NULL); - } - } - - saa7134_tuner_setup(dev); - - switch (dev->board) { - case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: - case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: - { - struct v4l2_priv_tun_config tea5767_cfg; - struct tea5767_ctrl ctl; - - dev->i2c_client.addr = 0xC0; - /* set TEA5767(analog FM) defines */ - memset(&ctl, 0, sizeof(ctl)); - ctl.xtal_freq = TEA5767_HIGH_LO_13MHz; - tea5767_cfg.tuner = TUNER_TEA5767; - tea5767_cfg.priv = &ctl; - saa_call_all(dev, tuner, s_config, &tea5767_cfg); - break; - } - } /* switch() */ - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1373 +0,0 @@ -/* - * - * device driver for philips saa7134 based TV cards - * driver core - * - * (c) 2001-03 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" - -MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards"); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------------ */ - -static unsigned int irq_debug; -module_param(irq_debug, int, 0644); -MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); - -static unsigned int core_debug; -module_param(core_debug, int, 0644); -MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); - -static unsigned int gpio_tracking; -module_param(gpio_tracking, int, 0644); -MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]"); - -static unsigned int alsa = 1; -module_param(alsa, int, 0644); -MODULE_PARM_DESC(alsa,"enable/disable ALSA DMA sound [dmasound]"); - -static unsigned int latency = UNSET; -module_param(latency, int, 0444); -MODULE_PARM_DESC(latency,"pci latency timer"); - -int saa7134_no_overlay=-1; -module_param_named(no_overlay, saa7134_no_overlay, int, 0444); -MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" - " [some VIA/SIS chipsets are known to have problem with overlay]"); - -static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; - - -module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); -module_param_array(tuner, int, NULL, 0444); -module_param_array(card, int, NULL, 0444); - -MODULE_PARM_DESC(video_nr, "video device number"); -MODULE_PARM_DESC(vbi_nr, "vbi device number"); -MODULE_PARM_DESC(radio_nr, "radio device number"); -MODULE_PARM_DESC(tuner, "tuner type"); -MODULE_PARM_DESC(card, "card type"); - -DEFINE_MUTEX(saa7134_devlist_lock); -EXPORT_SYMBOL(saa7134_devlist_lock); -LIST_HEAD(saa7134_devlist); -EXPORT_SYMBOL(saa7134_devlist); -static LIST_HEAD(mops_list); -static unsigned int saa7134_devcount; - -int (*saa7134_dmasound_init)(struct saa7134_dev *dev); -int (*saa7134_dmasound_exit)(struct saa7134_dev *dev); - -#define dprintk(fmt, arg...) if (core_debug) \ - printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg) - -void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) -{ - unsigned long mode,status; - - if (!gpio_tracking) - return; - /* rising SAA7134_GPIO_GPRESCAN reads the status */ - saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,0); - saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN); - mode = saa_readl(SAA7134_GPIO_GPMODE0 >> 2) & 0xfffffff; - status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff; - printk(KERN_DEBUG - "%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n", - dev->name, mode, (~mode) & status, mode & status, msg); -} - -void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value) -{ - u32 index, bitval; - - index = 1 << bit_no; - switch (value) { - case 0: /* static value */ - case 1: dprintk("setting GPIO%d to static %d\n", bit_no, value); - /* turn sync mode off if necessary */ - if (index & 0x00c00000) - saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00); - if (value) - bitval = index; - else - bitval = 0; - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, index); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval); - break; - case 3: /* tristate */ - dprintk("setting GPIO%d to tristate\n", bit_no); - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0); - break; - } -} - -/* ------------------------------------------------------------------ */ - - -/* ----------------------------------------------------------- */ -/* delayed request_module */ - -#if defined(CONFIG_MODULES) && defined(MODULE) - -static void request_module_async(struct work_struct *work){ - struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk); - if (card_is_empress(dev)) - request_module("saa7134-empress"); - if (card_is_dvb(dev)) - request_module("saa7134-dvb"); - if (alsa) { - if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130) - request_module("saa7134-alsa"); - } -} - -static void request_submodules(struct saa7134_dev *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} - -static void flush_request_submodules(struct saa7134_dev *dev) -{ - flush_work_sync(&dev->request_module_wk); -} - -#else -#define request_submodules(dev) -#define flush_request_submodules(dev) -#endif /* CONFIG_MODULES */ - -/* ------------------------------------------------------------------ */ - -/* nr of (saa7134-)pages for the given buffer size */ -static int saa7134_buffer_pages(int size) -{ - size = PAGE_ALIGN(size); - size += PAGE_SIZE; /* for non-page-aligned buffers */ - size /= 4096; - return size; -} - -/* calc max # of buffers from size (must not exceed the 4MB virtual - * address space per DMA channel) */ -int saa7134_buffer_count(unsigned int size, unsigned int count) -{ - unsigned int maxcount; - - maxcount = 1024 / saa7134_buffer_pages(size); - if (count > maxcount) - count = maxcount; - return count; -} - -int saa7134_buffer_startpage(struct saa7134_buf *buf) -{ - return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i; -} - -unsigned long saa7134_buffer_base(struct saa7134_buf *buf) -{ - unsigned long base; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - base = saa7134_buffer_startpage(buf) * 4096; - base += dma->sglist[0].offset; - return base; -} - -/* ------------------------------------------------------------------ */ - -int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt) -{ - __le32 *cpu; - dma_addr_t dma_addr = 0; - - cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr); - if (NULL == cpu) - return -ENOMEM; - pt->size = SAA7134_PGTABLE_SIZE; - pt->cpu = cpu; - pt->dma = dma_addr; - return 0; -} - -int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, - struct scatterlist *list, unsigned int length, - unsigned int startpage) -{ - __le32 *ptr; - unsigned int i,p; - - BUG_ON(NULL == pt || NULL == pt->cpu); - - ptr = pt->cpu + startpage; - for (i = 0; i < length; i++, list++) - for (p = 0; p * 4096 < list->length; p++, ptr++) - *ptr = cpu_to_le32(sg_dma_address(list) - list->offset); - return 0; -} - -void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) -{ - if (NULL == pt->cpu) - return; - pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); - pt->cpu = NULL; -} - -/* ------------------------------------------------------------------ */ - -void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) -{ - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - BUG_ON(in_interrupt()); - - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -/* ------------------------------------------------------------------ */ - -int saa7134_buffer_queue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q, - struct saa7134_buf *buf) -{ - struct saa7134_buf *next = NULL; - - assert_spin_locked(&dev->slock); - dprintk("buffer_queue %p\n",buf); - if (NULL == q->curr) { - if (!q->need_two) { - q->curr = buf; - buf->activate(dev,buf,NULL); - } else if (list_empty(&q->queue)) { - list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = VIDEOBUF_QUEUED; - } else { - next = list_entry(q->queue.next,struct saa7134_buf, - vb.queue); - q->curr = buf; - buf->activate(dev,buf,next); - } - } else { - list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = VIDEOBUF_QUEUED; - } - return 0; -} - -void saa7134_buffer_finish(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q, - unsigned int state) -{ - assert_spin_locked(&dev->slock); - dprintk("buffer_finish %p\n",q->curr); - - /* finish current buffer */ - q->curr->vb.state = state; - do_gettimeofday(&q->curr->vb.ts); - wake_up(&q->curr->vb.done); - q->curr = NULL; -} - -void saa7134_buffer_next(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q) -{ - struct saa7134_buf *buf,*next = NULL; - - assert_spin_locked(&dev->slock); - BUG_ON(NULL != q->curr); - - if (!list_empty(&q->queue)) { - /* activate next one from queue */ - buf = list_entry(q->queue.next,struct saa7134_buf,vb.queue); - dprintk("buffer_next %p [prev=%p/next=%p]\n", - buf,q->queue.prev,q->queue.next); - list_del(&buf->vb.queue); - if (!list_empty(&q->queue)) - next = list_entry(q->queue.next,struct saa7134_buf, - vb.queue); - q->curr = buf; - buf->activate(dev,buf,next); - dprintk("buffer_next #2 prev=%p/next=%p\n", - q->queue.prev,q->queue.next); - } else { - /* nothing to do -- just stop DMA */ - dprintk("buffer_next %p\n",NULL); - saa7134_set_dmabits(dev); - del_timer(&q->timeout); - - if (card_has_mpeg(dev)) - if (dev->ts_started) - saa7134_ts_stop(dev); - } -} - -void saa7134_buffer_timeout(unsigned long data) -{ - struct saa7134_dmaqueue *q = (struct saa7134_dmaqueue*)data; - struct saa7134_dev *dev = q->dev; - unsigned long flags; - - spin_lock_irqsave(&dev->slock,flags); - - /* try to reset the hardware (SWRST) */ - saa_writeb(SAA7134_REGION_ENABLE, 0x00); - saa_writeb(SAA7134_REGION_ENABLE, 0x80); - saa_writeb(SAA7134_REGION_ENABLE, 0x00); - - /* flag current buffer as failed, - try to start over with the next one. */ - if (q->curr) { - dprintk("timeout on %p\n",q->curr); - saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR); - } - saa7134_buffer_next(dev,q); - spin_unlock_irqrestore(&dev->slock,flags); -} - -/* ------------------------------------------------------------------ */ - -int saa7134_set_dmabits(struct saa7134_dev *dev) -{ - u32 split, task=0, ctrl=0, irq=0; - enum v4l2_field cap = V4L2_FIELD_ANY; - enum v4l2_field ov = V4L2_FIELD_ANY; - - assert_spin_locked(&dev->slock); - - if (dev->insuspend) - return 0; - - /* video capture -- dma 0 + video task A */ - if (dev->video_q.curr) { - task |= 0x01; - ctrl |= SAA7134_MAIN_CTRL_TE0; - irq |= SAA7134_IRQ1_INTE_RA0_1 | - SAA7134_IRQ1_INTE_RA0_0; - cap = dev->video_q.curr->vb.field; - } - - /* video capture -- dma 1+2 (planar modes) */ - if (dev->video_q.curr && - dev->video_q.curr->fmt->planar) { - ctrl |= SAA7134_MAIN_CTRL_TE4 | - SAA7134_MAIN_CTRL_TE5; - } - - /* screen overlay -- dma 0 + video task B */ - if (dev->ovenable) { - task |= 0x10; - ctrl |= SAA7134_MAIN_CTRL_TE1; - ov = dev->ovfield; - } - - /* vbi capture -- dma 0 + vbi task A+B */ - if (dev->vbi_q.curr) { - task |= 0x22; - ctrl |= SAA7134_MAIN_CTRL_TE2 | - SAA7134_MAIN_CTRL_TE3; - irq |= SAA7134_IRQ1_INTE_RA0_7 | - SAA7134_IRQ1_INTE_RA0_6 | - SAA7134_IRQ1_INTE_RA0_5 | - SAA7134_IRQ1_INTE_RA0_4; - } - - /* audio capture -- dma 3 */ - if (dev->dmasound.dma_running) { - ctrl |= SAA7134_MAIN_CTRL_TE6; - irq |= SAA7134_IRQ1_INTE_RA3_1 | - SAA7134_IRQ1_INTE_RA3_0; - } - - /* TS capture -- dma 5 */ - if (dev->ts_q.curr) { - ctrl |= SAA7134_MAIN_CTRL_TE5; - irq |= SAA7134_IRQ1_INTE_RA2_1 | - SAA7134_IRQ1_INTE_RA2_0; - } - - /* set task conditions + field handling */ - if (V4L2_FIELD_HAS_BOTH(cap) || V4L2_FIELD_HAS_BOTH(ov) || cap == ov) { - /* default config -- use full frames */ - saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d); - saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d); - saa_writeb(SAA7134_FIELD_HANDLING(TASK_A), 0x02); - saa_writeb(SAA7134_FIELD_HANDLING(TASK_B), 0x02); - split = 0; - } else { - /* split fields between tasks */ - if (V4L2_FIELD_TOP == cap) { - /* odd A, even B, repeat */ - saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d); - saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0e); - } else { - /* odd B, even A, repeat */ - saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0e); - saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d); - } - saa_writeb(SAA7134_FIELD_HANDLING(TASK_A), 0x01); - saa_writeb(SAA7134_FIELD_HANDLING(TASK_B), 0x01); - split = 1; - } - - /* irqs */ - saa_writeb(SAA7134_REGION_ENABLE, task); - saa_writel(SAA7134_IRQ1, irq); - saa_andorl(SAA7134_MAIN_CTRL, - SAA7134_MAIN_CTRL_TE0 | - SAA7134_MAIN_CTRL_TE1 | - SAA7134_MAIN_CTRL_TE2 | - SAA7134_MAIN_CTRL_TE3 | - SAA7134_MAIN_CTRL_TE4 | - SAA7134_MAIN_CTRL_TE5 | - SAA7134_MAIN_CTRL_TE6, - ctrl); - dprintk("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n", - task, ctrl, irq, split ? "no" : "yes"); - - return 0; -} - -/* ------------------------------------------------------------------ */ -/* IRQ handler + helpers */ - -static char *irqbits[] = { - "DONE_RA0", "DONE_RA1", "DONE_RA2", "DONE_RA3", - "AR", "PE", "PWR_ON", "RDCAP", "INTL", "FIDT", "MMC", - "TRIG_ERR", "CONF_ERR", "LOAD_ERR", - "GPIO16", "GPIO18", "GPIO22", "GPIO23" -}; -#define IRQBITS ARRAY_SIZE(irqbits) - -static void print_irqstatus(struct saa7134_dev *dev, int loop, - unsigned long report, unsigned long status) -{ - unsigned int i; - - printk(KERN_DEBUG "%s/irq[%d,%ld]: r=0x%lx s=0x%02lx", - dev->name,loop,jiffies,report,status); - for (i = 0; i < IRQBITS; i++) { - if (!(report & (1 << i))) - continue; - printk(" %s",irqbits[i]); - } - if (report & SAA7134_IRQ_REPORT_DONE_RA0) { - printk(" | RA0=%s,%s,%s,%ld", - (status & 0x40) ? "vbi" : "video", - (status & 0x20) ? "b" : "a", - (status & 0x10) ? "odd" : "even", - (status & 0x0f)); - } - printk("\n"); -} - -static irqreturn_t saa7134_irq(int irq, void *dev_id) -{ - struct saa7134_dev *dev = (struct saa7134_dev*) dev_id; - unsigned long report,status; - int loop, handled = 0; - - if (dev->insuspend) - goto out; - - for (loop = 0; loop < 10; loop++) { - report = saa_readl(SAA7134_IRQ_REPORT); - status = saa_readl(SAA7134_IRQ_STATUS); - - /* If dmasound support is active and we get a sound report, - * mask out the report and let the saa7134-alsa module deal - * with it */ - if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && - (dev->dmasound.priv_data != NULL) ) - { - if (irq_debug > 1) - printk(KERN_DEBUG "%s/irq: preserving DMA sound interrupt\n", - dev->name); - report &= ~SAA7134_IRQ_REPORT_DONE_RA3; - } - - if (0 == report) { - if (irq_debug > 1) - printk(KERN_DEBUG "%s/irq: no (more) work\n", - dev->name); - goto out; - } - - handled = 1; - saa_writel(SAA7134_IRQ_REPORT,report); - if (irq_debug) - print_irqstatus(dev,loop,report,status); - - - if ((report & SAA7134_IRQ_REPORT_RDCAP) || - (report & SAA7134_IRQ_REPORT_INTL)) - saa7134_irq_video_signalchange(dev); - - - if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && - (status & 0x60) == 0) - saa7134_irq_video_done(dev,status); - - if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && - (status & 0x40) == 0x40) - saa7134_irq_vbi_done(dev,status); - - if ((report & SAA7134_IRQ_REPORT_DONE_RA2) && - card_has_mpeg(dev)) - saa7134_irq_ts_done(dev,status); - - if (report & SAA7134_IRQ_REPORT_GPIO16) { - switch (dev->has_remote) { - case SAA7134_REMOTE_GPIO: - if (!dev->remote) - break; - if (dev->remote->mask_keydown & 0x10000) { - saa7134_input_irq(dev); - } - break; - - case SAA7134_REMOTE_I2C: - break; /* FIXME: invoke I2C get_key() */ - - default: /* GPIO16 not used by IR remote */ - break; - } - } - - if (report & SAA7134_IRQ_REPORT_GPIO18) { - switch (dev->has_remote) { - case SAA7134_REMOTE_GPIO: - if (!dev->remote) - break; - if ((dev->remote->mask_keydown & 0x40000) || - (dev->remote->mask_keyup & 0x40000)) { - saa7134_input_irq(dev); - } - break; - - case SAA7134_REMOTE_I2C: - break; /* FIXME: invoke I2C get_key() */ - - default: /* GPIO18 not used by IR remote */ - break; - } - } - } - - if (10 == loop) { - print_irqstatus(dev,loop,report,status); - if (report & SAA7134_IRQ_REPORT_PE) { - /* disable all parity error */ - printk(KERN_WARNING "%s/irq: looping -- " - "clearing PE (parity error!) enable bit\n",dev->name); - saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE); - } else if (report & SAA7134_IRQ_REPORT_GPIO16) { - /* disable gpio16 IRQ */ - printk(KERN_WARNING "%s/irq: looping -- " - "clearing GPIO16 enable bit\n",dev->name); - saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_P); - saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_N); - } else if (report & SAA7134_IRQ_REPORT_GPIO18) { - /* disable gpio18 IRQs */ - printk(KERN_WARNING "%s/irq: looping -- " - "clearing GPIO18 enable bit\n",dev->name); - saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P); - saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_N); - } else { - /* disable all irqs */ - printk(KERN_WARNING "%s/irq: looping -- " - "clearing all enable bits\n",dev->name); - saa_writel(SAA7134_IRQ1,0); - saa_writel(SAA7134_IRQ2,0); - } - } - - out: - return IRQ_RETVAL(handled); -} - -/* ------------------------------------------------------------------ */ - -/* early init (no i2c, no irq) */ - -static int saa7134_hw_enable1(struct saa7134_dev *dev) -{ - /* RAM FIFO config */ - saa_writel(SAA7134_FIFO_SIZE, 0x08070503); - saa_writel(SAA7134_THRESHOULD, 0x02020202); - - /* enable audio + video processing */ - saa_writel(SAA7134_MAIN_CTRL, - SAA7134_MAIN_CTRL_VPLLE | - SAA7134_MAIN_CTRL_APLLE | - SAA7134_MAIN_CTRL_EXOSC | - SAA7134_MAIN_CTRL_EVFE1 | - SAA7134_MAIN_CTRL_EVFE2 | - SAA7134_MAIN_CTRL_ESFE | - SAA7134_MAIN_CTRL_EBDAC); - - /* - * Initialize OSS _after_ enabling audio clock PLL and audio processing. - * OSS initialization writes to registers via the audio DSP; these - * writes will fail unless the audio clock has been started. At worst, - * audio will not work. - */ - - /* enable peripheral devices */ - saa_writeb(SAA7134_SPECIAL_MODE, 0x01); - - /* set vertical line numbering start (vbi needs this) */ - saa_writeb(SAA7134_SOURCE_TIMING2, 0x20); - - return 0; -} - -static int saa7134_hwinit1(struct saa7134_dev *dev) -{ - dprintk("hwinit1\n"); - - saa_writel(SAA7134_IRQ1, 0); - saa_writel(SAA7134_IRQ2, 0); - - /* Clear any stale IRQ reports */ - saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT)); - - mutex_init(&dev->lock); - spin_lock_init(&dev->slock); - - saa7134_track_gpio(dev,"pre-init"); - saa7134_video_init1(dev); - saa7134_vbi_init1(dev); - if (card_has_mpeg(dev)) - saa7134_ts_init1(dev); - saa7134_input_init1(dev); - - saa7134_hw_enable1(dev); - - return 0; -} - -/* late init (with i2c + irq) */ -static int saa7134_hw_enable2(struct saa7134_dev *dev) -{ - - unsigned int irq2_mask; - - /* enable IRQ's */ - irq2_mask = - SAA7134_IRQ2_INTE_DEC3 | - SAA7134_IRQ2_INTE_DEC2 | - SAA7134_IRQ2_INTE_DEC1 | - SAA7134_IRQ2_INTE_DEC0 | - SAA7134_IRQ2_INTE_PE | - SAA7134_IRQ2_INTE_AR; - - if (dev->has_remote == SAA7134_REMOTE_GPIO && dev->remote) { - if (dev->remote->mask_keydown & 0x10000) - irq2_mask |= SAA7134_IRQ2_INTE_GPIO16_N; - else { /* Allow enabling both IRQ edge triggers */ - if (dev->remote->mask_keydown & 0x40000) - irq2_mask |= SAA7134_IRQ2_INTE_GPIO18_P; - if (dev->remote->mask_keyup & 0x40000) - irq2_mask |= SAA7134_IRQ2_INTE_GPIO18_N; - } - } - - if (dev->has_remote == SAA7134_REMOTE_I2C) { - request_module("ir-kbd-i2c"); - } - - saa_writel(SAA7134_IRQ1, 0); - saa_writel(SAA7134_IRQ2, irq2_mask); - - return 0; -} - -static int saa7134_hwinit2(struct saa7134_dev *dev) -{ - - dprintk("hwinit2\n"); - - saa7134_video_init2(dev); - saa7134_tvaudio_init2(dev); - - saa7134_hw_enable2(dev); - - return 0; -} - - -/* shutdown */ -static int saa7134_hwfini(struct saa7134_dev *dev) -{ - dprintk("hwfini\n"); - - if (card_has_mpeg(dev)) - saa7134_ts_fini(dev); - saa7134_input_fini(dev); - saa7134_vbi_fini(dev); - saa7134_tvaudio_fini(dev); - return 0; -} - -static void __devinit must_configure_manually(int has_eeprom) -{ - unsigned int i,p; - - if (!has_eeprom) - printk(KERN_WARNING - "saa7134: \n" - "saa7134: Congratulations! Your TV card vendor saved a few\n" - "saa7134: cents for a eeprom, thus your pci board has no\n" - "saa7134: subsystem ID and I can't identify it automatically\n" - "saa7134: \n" - "saa7134: I feel better now. Ok, here are the good news:\n" - "saa7134: You can use the card= insmod option to specify\n" - "saa7134: which board do you have. The list:\n"); - else - printk(KERN_WARNING - "saa7134: Board is currently unknown. You might try to use the card=\n" - "saa7134: insmod option to specify which board do you have, but this is\n" - "saa7134: somewhat risky, as might damage your card. It is better to ask\n" - "saa7134: for support at linux-media@vger.kernel.org.\n" - "saa7134: The supported cards are:\n"); - - for (i = 0; i < saa7134_bcount; i++) { - printk(KERN_WARNING "saa7134: card=%d -> %-40.40s", - i,saa7134_boards[i].name); - for (p = 0; saa7134_pci_tbl[p].driver_data; p++) { - if (saa7134_pci_tbl[p].driver_data != i) - continue; - printk(" %04x:%04x", - saa7134_pci_tbl[p].subvendor, - saa7134_pci_tbl[p].subdevice); - } - printk("\n"); - } -} - -static struct video_device *vdev_init(struct saa7134_dev *dev, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; - vfd->debug = video_debug; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - dev->name, type, saa7134_boards[dev->board].name); - video_set_drvdata(vfd, dev); - return vfd; -} - -static void saa7134_unregister_video(struct saa7134_dev *dev) -{ - if (dev->video_dev) { - if (video_is_registered(dev->video_dev)) - video_unregister_device(dev->video_dev); - else - video_device_release(dev->video_dev); - dev->video_dev = NULL; - } - if (dev->vbi_dev) { - if (video_is_registered(dev->vbi_dev)) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } -} - -static void mpeg_ops_attach(struct saa7134_mpeg_ops *ops, - struct saa7134_dev *dev) -{ - int err; - - if (NULL != dev->mops) - return; - if (saa7134_boards[dev->board].mpeg != ops->type) - return; - err = ops->init(dev); - if (0 != err) - return; - dev->mops = ops; -} - -static void mpeg_ops_detach(struct saa7134_mpeg_ops *ops, - struct saa7134_dev *dev) -{ - if (NULL == dev->mops) - return; - if (dev->mops != ops) - return; - dev->mops->fini(dev); - dev->mops = NULL; -} - -static int __devinit saa7134_initdev(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - struct saa7134_dev *dev; - struct saa7134_mpeg_ops *mops; - int err; - - if (saa7134_devcount == SAA7134_MAXBOARDS) - return -ENOMEM; - - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) - return -ENOMEM; - - err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); - if (err) - goto fail0; - - /* pci init */ - dev->pci = pci_dev; - if (pci_enable_device(pci_dev)) { - err = -EIO; - goto fail1; - } - - dev->nr = saa7134_devcount; - sprintf(dev->name,"saa%x[%d]",pci_dev->device,dev->nr); - - /* pci quirks */ - if (pci_pci_problems) { - if (pci_pci_problems & PCIPCI_TRITON) - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", dev->name); - if (pci_pci_problems & PCIPCI_NATOMA) - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", dev->name); - if (pci_pci_problems & PCIPCI_VIAETBF) - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", dev->name); - if (pci_pci_problems & PCIPCI_VSFX) - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n",dev->name); -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", - dev->name); - latency = 0x0A; - } -#endif - if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) { - printk(KERN_INFO "%s: quirk: this driver and your " - "chipset may not work together" - " in overlay mode.\n",dev->name); - if (!saa7134_no_overlay) { - printk(KERN_INFO "%s: quirk: overlay " - "mode will be disabled.\n", - dev->name); - saa7134_no_overlay = 1; - } else { - printk(KERN_INFO "%s: quirk: overlay " - "mode will be forced. Use this" - " option at your own risk.\n", - dev->name); - } - } - } - if (UNSET != latency) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", - dev->name,latency); - pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); - } - - /* print pci info */ - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->name, - pci_name(pci_dev), dev->pci_rev, pci_dev->irq, - dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); - pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { - printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name); - err = -EIO; - goto fail1; - } - - /* board config */ - dev->board = pci_id->driver_data; - if (card[dev->nr] >= 0 && - card[dev->nr] < saa7134_bcount) - dev->board = card[dev->nr]; - if (SAA7134_BOARD_UNKNOWN == dev->board) - must_configure_manually(0); - else if (SAA7134_BOARD_NOAUTO == dev->board) { - must_configure_manually(1); - dev->board = SAA7134_BOARD_UNKNOWN; - } - dev->autodetected = card[dev->nr] != dev->board; - dev->tuner_type = saa7134_boards[dev->board].tuner_type; - dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; - dev->radio_type = saa7134_boards[dev->board].radio_type; - dev->radio_addr = saa7134_boards[dev->board].radio_addr; - dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; - if (UNSET != tuner[dev->nr]) - dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name,pci_dev->subsystem_vendor, - pci_dev->subsystem_device,saa7134_boards[dev->board].name, - dev->board, dev->autodetected ? - "autodetected" : "insmod option"); - - /* get mmio */ - if (!request_mem_region(pci_resource_start(pci_dev,0), - pci_resource_len(pci_dev,0), - dev->name)) { - err = -EBUSY; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", - dev->name,(unsigned long long)pci_resource_start(pci_dev,0)); - goto fail1; - } - dev->lmmio = ioremap(pci_resource_start(pci_dev, 0), - pci_resource_len(pci_dev, 0)); - dev->bmmio = (__u8 __iomem *)dev->lmmio; - if (NULL == dev->lmmio) { - err = -EIO; - printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", - dev->name); - goto fail2; - } - - /* initialize hardware #1 */ - saa7134_board_init1(dev); - saa7134_hwinit1(dev); - - /* get irq */ - err = request_irq(pci_dev->irq, saa7134_irq, - IRQF_SHARED | IRQF_DISABLED, dev->name, dev); - if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", - dev->name,pci_dev->irq); - goto fail3; - } - - /* wait a bit, register i2c bus */ - msleep(100); - saa7134_i2c_register(dev); - saa7134_board_init2(dev); - - saa7134_hwinit2(dev); - - /* load i2c helpers */ - if (card_is_empress(dev)) { - struct v4l2_subdev *sd = - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "saa6752hs", - saa7134_boards[dev->board].empress_addr, NULL); - - if (sd) - sd->grp_id = GRP_EMPRESS; - } - - if (saa7134_boards[dev->board].rds_addr) { - struct v4l2_subdev *sd; - - sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "saa6588", - 0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr)); - if (sd) { - printk(KERN_INFO "%s: found RDS decoder\n", dev->name); - dev->has_rds = 1; - } - } - - v4l2_prio_init(&dev->prio); - - mutex_lock(&saa7134_devlist_lock); - list_for_each_entry(mops, &mops_list, next) - mpeg_ops_attach(mops, dev); - list_add_tail(&dev->devlist, &saa7134_devlist); - mutex_unlock(&saa7134_devlist_lock); - - /* check for signal */ - saa7134_irq_video_signalchange(dev); - - if (TUNER_ABSENT != dev->tuner_type) - saa_call_all(dev, core, s_power, 0); - - /* register v4l devices */ - if (saa7134_no_overlay > 0) - printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name); - - dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); - err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, - video_nr[dev->nr]); - if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - goto fail4; - } - printk(KERN_INFO "%s: registered device %s [v4l2]\n", - dev->name, video_device_node_name(dev->video_dev)); - - dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); - - err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, - vbi_nr[dev->nr]); - if (err < 0) - goto fail4; - printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(dev->vbi_dev)); - - if (card_has_radio(dev)) { - dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); - err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, - radio_nr[dev->nr]); - if (err < 0) - goto fail4; - printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(dev->radio_dev)); - } - - /* everything worked */ - saa7134_devcount++; - - if (saa7134_dmasound_init && !dev->dmasound.priv_data) - saa7134_dmasound_init(dev); - - request_submodules(dev); - return 0; - - fail4: - saa7134_unregister_video(dev); - saa7134_i2c_unregister(dev); - free_irq(pci_dev->irq, dev); - fail3: - saa7134_hwfini(dev); - iounmap(dev->lmmio); - fail2: - release_mem_region(pci_resource_start(pci_dev,0), - pci_resource_len(pci_dev,0)); - fail1: - v4l2_device_unregister(&dev->v4l2_dev); - fail0: - kfree(dev); - return err; -} - -static void __devexit saa7134_finidev(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev); - struct saa7134_mpeg_ops *mops; - - flush_request_submodules(dev); - - /* Release DMA sound modules if present */ - if (saa7134_dmasound_exit && dev->dmasound.priv_data) { - saa7134_dmasound_exit(dev); - } - - /* debugging ... */ - if (irq_debug) { - u32 report = saa_readl(SAA7134_IRQ_REPORT); - u32 status = saa_readl(SAA7134_IRQ_STATUS); - print_irqstatus(dev,42,report,status); - } - - /* disable peripheral devices */ - saa_writeb(SAA7134_SPECIAL_MODE,0); - - /* shutdown hardware */ - saa_writel(SAA7134_IRQ1,0); - saa_writel(SAA7134_IRQ2,0); - saa_writel(SAA7134_MAIN_CTRL,0); - - /* shutdown subsystems */ - saa7134_hwfini(dev); - - /* unregister */ - mutex_lock(&saa7134_devlist_lock); - list_del(&dev->devlist); - list_for_each_entry(mops, &mops_list, next) - mpeg_ops_detach(mops, dev); - mutex_unlock(&saa7134_devlist_lock); - saa7134_devcount--; - - saa7134_i2c_unregister(dev); - saa7134_unregister_video(dev); - - - /* the DMA sound modules should be unloaded before reaching - this, but just in case they are still present... */ - if (dev->dmasound.priv_data != NULL) { - free_irq(pci_dev->irq, &dev->dmasound); - dev->dmasound.priv_data = NULL; - } - - - /* release resources */ - free_irq(pci_dev->irq, dev); - iounmap(dev->lmmio); - release_mem_region(pci_resource_start(pci_dev,0), - pci_resource_len(pci_dev,0)); - - - v4l2_device_unregister(&dev->v4l2_dev); - - /* free memory */ - kfree(dev); -} - -#ifdef CONFIG_PM - -/* resends a current buffer in queue after resume */ -static int saa7134_buffer_requeue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q) -{ - struct saa7134_buf *buf, *next; - - assert_spin_locked(&dev->slock); - - buf = q->curr; - next = buf; - dprintk("buffer_requeue\n"); - - if (!buf) - return 0; - - dprintk("buffer_requeue : resending active buffers \n"); - - if (!list_empty(&q->queue)) - next = list_entry(q->queue.next, struct saa7134_buf, - vb.queue); - buf->activate(dev, buf, next); - - return 0; -} - -static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev); - - /* disable overlay - apps should enable it explicitly on resume*/ - dev->ovenable = 0; - - /* Disable interrupts, DMA, and rest of the chip*/ - saa_writel(SAA7134_IRQ1, 0); - saa_writel(SAA7134_IRQ2, 0); - saa_writel(SAA7134_MAIN_CTRL, 0); - - dev->insuspend = 1; - synchronize_irq(pci_dev->irq); - - /* ACK interrupts once more, just in case, - since the IRQ handler won't ack them anymore*/ - - saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT)); - - /* Disable timeout timers - if we have active buffers, we will - fill them on resume*/ - - del_timer(&dev->video_q.timeout); - del_timer(&dev->vbi_q.timeout); - del_timer(&dev->ts_q.timeout); - - if (dev->remote) - saa7134_ir_stop(dev); - - pci_save_state(pci_dev); - pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); - - return 0; -} - -static int saa7134_resume(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev); - unsigned long flags; - - pci_set_power_state(pci_dev, PCI_D0); - pci_restore_state(pci_dev); - - /* Do things that are done in saa7134_initdev , - except of initializing memory structures.*/ - - saa7134_board_init1(dev); - - /* saa7134_hwinit1 */ - if (saa7134_boards[dev->board].video_out) - saa7134_videoport_init(dev); - if (card_has_mpeg(dev)) - saa7134_ts_init_hw(dev); - if (dev->remote) - saa7134_ir_start(dev); - saa7134_hw_enable1(dev); - - msleep(100); - - saa7134_board_init2(dev); - - /*saa7134_hwinit2*/ - saa7134_set_tvnorm_hw(dev); - saa7134_tvaudio_setmute(dev); - saa7134_tvaudio_setvolume(dev, dev->ctl_volume); - saa7134_tvaudio_init(dev); - saa7134_tvaudio_do_scan(dev); - saa7134_enable_i2s(dev); - saa7134_hw_enable2(dev); - - saa7134_irq_video_signalchange(dev); - - /*resume unfinished buffer(s)*/ - spin_lock_irqsave(&dev->slock, flags); - saa7134_buffer_requeue(dev, &dev->video_q); - saa7134_buffer_requeue(dev, &dev->vbi_q); - saa7134_buffer_requeue(dev, &dev->ts_q); - - /* FIXME: Disable DMA audio sound - temporary till proper support - is implemented*/ - - dev->dmasound.dma_running = 0; - - /* start DMA now*/ - dev->insuspend = 0; - smp_wmb(); - saa7134_set_dmabits(dev); - spin_unlock_irqrestore(&dev->slock, flags); - - return 0; -} -#endif - -/* ----------------------------------------------------------- */ - -int saa7134_ts_register(struct saa7134_mpeg_ops *ops) -{ - struct saa7134_dev *dev; - - mutex_lock(&saa7134_devlist_lock); - list_for_each_entry(dev, &saa7134_devlist, devlist) - mpeg_ops_attach(ops, dev); - list_add_tail(&ops->next,&mops_list); - mutex_unlock(&saa7134_devlist_lock); - return 0; -} - -void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops) -{ - struct saa7134_dev *dev; - - mutex_lock(&saa7134_devlist_lock); - list_del(&ops->next); - list_for_each_entry(dev, &saa7134_devlist, devlist) - mpeg_ops_detach(ops, dev); - mutex_unlock(&saa7134_devlist_lock); -} - -EXPORT_SYMBOL(saa7134_ts_register); -EXPORT_SYMBOL(saa7134_ts_unregister); - -/* ----------------------------------------------------------- */ - -static struct pci_driver saa7134_pci_driver = { - .name = "saa7134", - .id_table = saa7134_pci_tbl, - .probe = saa7134_initdev, - .remove = __devexit_p(saa7134_finidev), -#ifdef CONFIG_PM - .suspend = saa7134_suspend, - .resume = saa7134_resume -#endif -}; - -static int __init saa7134_init(void) -{ - INIT_LIST_HEAD(&saa7134_devlist); - printk(KERN_INFO "saa7130/34: v4l2 driver version %d.%d.%d loaded\n", - (SAA7134_VERSION_CODE >> 16) & 0xff, - (SAA7134_VERSION_CODE >> 8) & 0xff, - SAA7134_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return pci_register_driver(&saa7134_pci_driver); -} - -static void __exit saa7134_fini(void) -{ - pci_unregister_driver(&saa7134_pci_driver); -} - -module_init(saa7134_init); -module_exit(saa7134_fini); - -/* ----------------------------------------------------------- */ - -EXPORT_SYMBOL(saa7134_set_gpio); -EXPORT_SYMBOL(saa7134_boards); - -/* ----------------- for the DMA sound modules --------------- */ - -EXPORT_SYMBOL(saa7134_dmasound_init); -EXPORT_SYMBOL(saa7134_dmasound_exit); -EXPORT_SYMBOL(saa7134_pgtable_free); -EXPORT_SYMBOL(saa7134_pgtable_build); -EXPORT_SYMBOL(saa7134_pgtable_alloc); -EXPORT_SYMBOL(saa7134_set_dmabits); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-dvb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1793 +0,0 @@ -/* - * - * (c) 2004 Gerd Knorr [SuSE Labs] - * - * Extended 3 / 2005 by Hartmut Hackmann to support various - * cards with the tda10046 DVB-T channel decoder - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" -#include -#include "dvb-pll.h" -#include - -#include "mt352.h" -#include "mt352_priv.h" /* FIXME */ -#include "tda1004x.h" -#include "nxt200x.h" -#include "tuner-xc2028.h" -#include "xc5000.h" - -#include "tda10086.h" -#include "tda826x.h" -#include "tda827x.h" -#include "isl6421.h" -#include "isl6405.h" -#include "lnbp21.h" -#include "tuner-simple.h" -#include "tda10048.h" -#include "tda18271.h" -#include "lgdt3305.h" -#include "tda8290.h" -#include "mb86a20s.h" - -#include "zl10353.h" - -#include "zl10036.h" -#include "zl10039.h" -#include "mt312.h" - -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -static unsigned int antenna_pwr; - -module_param(antenna_pwr, int, 0444); -MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)"); - -static int use_frontend; -module_param(use_frontend, int, 0644); -MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off)."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk(fmt, arg...) do { if (debug) \ - printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0) - -/* Print a warning */ -#define wprintk(fmt, arg...) \ - printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg) - -/* ------------------------------------------------------------------ - * mt352 based DVB-T cards - */ - -static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) -{ - u32 ok; - - if (!on) { - saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26)); - saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); - return 0; - } - - saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26)); - saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); - udelay(10); - - saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 28)); - saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); - udelay(10); - saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); - udelay(10); - ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); - dprintk("%s %s\n", __func__, ok ? "on" : "off"); - - if (!ok) - saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); - return ok; -} - -static int mt352_pinnacle_init(struct dvb_frontend* fe) -{ - static u8 clock_config [] = { CLOCK_CTL, 0x3d, 0x28 }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x31 }; - static u8 fsm_ctl_cfg[] = { 0x7b, 0x04 }; - static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x0f }; - static u8 scan_ctl_cfg [] = { SCAN_CTL, 0x0d }; - static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; - struct saa7134_dev *dev= fe->dvb->priv; - - dprintk("%s called\n", __func__); - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); - - mt352_write(fe, fsm_ctl_cfg, sizeof(fsm_ctl_cfg)); - mt352_write(fe, scan_ctl_cfg, sizeof(scan_ctl_cfg)); - mt352_write(fe, irq_cfg, sizeof(irq_cfg)); - - return 0; -} - -static int mt352_aver777_init(struct dvb_frontend* fe) -{ - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - - return 0; -} - -static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe) -{ - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0xe }; - static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 }; - - mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); - mt352_write(fe, reset, sizeof(reset)); - mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); - mt352_write(fe, agc_cfg, sizeof(agc_cfg)); - mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); - return 0; -} - -static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) -{ - u8 off[] = { 0x00, 0xf1}; - u8 on[] = { 0x00, 0x71}; - struct i2c_msg msg = {.addr=0x43, .flags=0, .buf=off, .len = sizeof(off)}; - - struct saa7134_dev *dev = fe->dvb->priv; - struct v4l2_frequency f; - - /* set frequency (mt2050) */ - f.tuner = 0; - f.type = V4L2_TUNER_DIGITAL_TV; - f.frequency = params->frequency / 1000 * 16 / 1000; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(&dev->i2c_adap, &msg, 1); - saa_call_all(dev, tuner, s_frequency, &f); - msg.buf = on; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(&dev->i2c_adap, &msg, 1); - - pinnacle_antenna_pwr(dev, antenna_pwr); - - /* mt352 setup */ - return mt352_pinnacle_init(fe); -} - -static struct mt352_config pinnacle_300i = { - .demod_address = 0x3c >> 1, - .adc_clock = 20333, - .if2 = 36150, - .no_tuner = 1, - .demod_init = mt352_pinnacle_init, -}; - -static struct mt352_config avermedia_777 = { - .demod_address = 0xf, - .demod_init = mt352_aver777_init, -}; - -static struct mt352_config avermedia_xc3028_mt352_dev = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, - .demod_init = mt352_avermedia_xc3028_init, -}; - -static struct tda18271_std_map mb86a20s_tda18271_std_map = { - .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, - .if_lvl = 7, .rfagc_top = 0x37, }, -}; - -static struct tda18271_config kworld_tda18271_config = { - .std_map = &mb86a20s_tda18271_std_map, - .gate = TDA18271_GATE_DIGITAL, - .config = 3, /* Use tuner callback for AGC */ - -}; - -static const struct mb86a20s_config kworld_mb86a20s_config = { - .demod_address = 0x10, -}; - -static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable) -{ - struct saa7134_dev *dev = fe->dvb->priv; - - unsigned char initmsg[] = {0x45, 0x97}; - unsigned char msg_enable[] = {0x45, 0xc1}; - unsigned char msg_disable[] = {0x45, 0x81}; - struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2}; - - if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { - wprintk("could not access the I2C gate\n"); - return -EIO; - } - if (enable) - msg.buf = msg_enable; - else - msg.buf = msg_disable; - if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { - wprintk("could not access the I2C gate\n"); - return -EIO; - } - msleep(20); - return 0; -} - -/* ================================================================== - * tda1004x based DVB-T cards, helper functions - */ - -static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct saa7134_dev *dev = fe->dvb->priv; - return request_firmware(fw, name, &dev->pci->dev); -} - -/* ------------------------------------------------------------------ - * these tuners are tu1216, td1316(a) - */ - -static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = - sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - /* determine charge pump */ - tuner_frequency = params->frequency + 36166000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) - cp = 3; - else if (tuner_frequency < 160000000) - cp = 5; - else if (tuner_frequency < 200000000) - cp = 6; - else if (tuner_frequency < 290000000) - cp = 3; - else if (tuner_frequency < 420000000) - cp = 5; - else if (tuner_frequency < 480000000) - cp = 6; - else if (tuner_frequency < 620000000) - cp = 3; - else if (tuner_frequency < 830000000) - cp = 5; - else if (tuner_frequency < 895000000) - cp = 7; - else - return -EINVAL; - - /* determine band */ - if (params->frequency < 49000000) - return -EINVAL; - else if (params->frequency < 161000000) - band = 1; - else if (params->frequency < 444000000) - band = 2; - else if (params->frequency < 861000000) - band = 4; - else - return -EINVAL; - - /* setup PLL filter */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - filter = 0; - break; - - case BANDWIDTH_7_MHZ: - filter = 0; - break; - - case BANDWIDTH_8_MHZ: - filter = 1; - break; - - default: - return -EINVAL; - } - - /* calculate divisor - * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) - */ - tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; - - /* setup tuner buffer */ - tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { - wprintk("could not write to tuner at addr: 0x%02x\n", - addr << 1); - return -EIO; - } - msleep(1); - return 0; -} - -static int philips_tu1216_init(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; - static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; - - /* setup PLL configuration */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - msleep(1); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static struct tda1004x_config philips_tu1216_60_config = { - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config philips_tu1216_61_config = { - - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware -}; - -/* ------------------------------------------------------------------ */ - -static int philips_td1316_tuner_init(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; - static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab }; - struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) }; - - /* setup PLL configuration */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) - return -EIO; - return 0; -} - -static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - return philips_tda6651_pll_set(fe, params); -} - -static int philips_td1316_tuner_sleep(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; - static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 }; - struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) }; - - /* switch the tuner to analog mode */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1) - return -EIO; - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int philips_europa_tuner_init(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - static u8 msg[] = { 0x00, 0x40}; - struct i2c_msg init_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) }; - - - if (philips_td1316_tuner_init(fe)) - return -EIO; - msleep(1); - if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) - return -EIO; - - return 0; -} - -static int philips_europa_tuner_sleep(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - - static u8 msg[] = { 0x00, 0x14 }; - struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) }; - - if (philips_td1316_tuner_sleep(fe)) - return -EIO; - - /* switch the board to analog mode */ - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(&dev->i2c_adap, &analog_msg, 1); - return 0; -} - -static int philips_europa_demod_sleep(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - - if (dev->original_demod_sleep) - dev->original_demod_sleep(fe); - fe->ops.i2c_gate_ctrl(fe, 1); - return 0; -} - -static struct tda1004x_config philips_europa_config = { - - .demod_address = 0x8, - .invert = 0, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_IFO_AUTO_POS, - .if_freq = TDA10046_FREQ_052, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config medion_cardbus = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_IFO_AUTO_NEG, - .if_freq = TDA10046_FREQ_3613, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config technotrend_budget_t3000_config = { - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .tuner_address = 0x63, - .request_firmware = philips_tda1004x_request_firmware -}; - -/* ------------------------------------------------------------------ - * tda 1004x based cards with philips silicon tuner - */ - -static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable) -{ - struct tda1004x_state *state = fe->demodulator_priv; - - u8 addr = state->config->i2c_gate; - static u8 tda8290_close[] = { 0x21, 0xc0}; - static u8 tda8290_open[] = { 0x21, 0x80}; - struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2}; - if (enable) { - tda8290_msg.buf = tda8290_close; - } else { - tda8290_msg.buf = tda8290_open; - } - if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) { - struct saa7134_dev *dev = fe->dvb->priv; - wprintk("could not access tda8290 I2C gate\n"); - return -EIO; - } - msleep(20); - return 0; -} - -static int philips_tda827x_tuner_init(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - - switch (state->config->antenna_switch) { - case 0: break; - case 1: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); - saa7134_set_gpio(dev, 21, 0); - break; - case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); - saa7134_set_gpio(dev, 21, 1); - break; - } - return 0; -} - -static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - - switch (state->config->antenna_switch) { - case 0: break; - case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); - saa7134_set_gpio(dev, 21, 1); - break; - case 2: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); - saa7134_set_gpio(dev, 21, 0); - break; - } - return 0; -} - -static int configure_tda827x_fe(struct saa7134_dev *dev, - struct tda1004x_config *cdec_conf, - struct tda827x_config *tuner_conf) -{ - struct videobuf_dvb_frontend *fe0; - - /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); - - fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap); - if (fe0->dvb.frontend) { - if (cdec_conf->i2c_gate) - fe0->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; - if (dvb_attach(tda827x_attach, fe0->dvb.frontend, - cdec_conf->tuner_address, - &dev->i2c_adap, tuner_conf)) - return 0; - - wprintk("no tda827x tuner found at addr: %02x\n", - cdec_conf->tuner_address); - } - return -EINVAL; -} - -/* ------------------------------------------------------------------ */ - -static struct tda827x_config tda827x_cfg_0 = { - .init = philips_tda827x_tuner_init, - .sleep = philips_tda827x_tuner_sleep, - .config = 0, - .switch_addr = 0 -}; - -static struct tda827x_config tda827x_cfg_1 = { - .init = philips_tda827x_tuner_init, - .sleep = philips_tda827x_tuner_sleep, - .config = 1, - .switch_addr = 0x4b -}; - -static struct tda827x_config tda827x_cfg_2 = { - .init = philips_tda827x_tuner_init, - .sleep = philips_tda827x_tuner_sleep, - .config = 2, - .switch_addr = 0x4b -}; - -static struct tda827x_config tda827x_cfg_2_sw42 = { - .init = philips_tda827x_tuner_init, - .sleep = philips_tda827x_tuner_sleep, - .config = 2, - .switch_addr = 0x42 -}; - -/* ------------------------------------------------------------------ */ - -static struct tda1004x_config tda827x_lifeview_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config philips_tiger_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .antenna_switch= 1, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config cinergy_ht_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config cinergy_ht_pci_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config philips_tiger_s_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .antenna_switch= 1, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config pinnacle_pctv_310i_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config hauppauge_hvr_1110_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config asus_p7131_dual_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .antenna_switch= 2, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config lifeview_trio_config = { - .demod_address = 0x09, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP00_I, - .if_freq = TDA10046_FREQ_045, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config tevion_dvbt220rf_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config md8800_dvbt_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x60, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config asus_p7131_4871_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .antenna_switch= 2, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config asus_p7131_hybrid_lna_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .antenna_switch= 2, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config kworld_dvb_t_210_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .antenna_switch= 1, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config avermedia_super_007_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x60, - .antenna_switch= 1, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config twinhan_dtv_dvb_3056_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP01_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x42, - .tuner_address = 0x61, - .antenna_switch = 1, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct tda1004x_config asus_tiger_3in1_config = { - .demod_address = 0x0b, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP11_I, - .if_freq = TDA10046_FREQ_045, - .i2c_gate = 0x4b, - .tuner_address = 0x61, - .antenna_switch = 1, - .request_firmware = philips_tda1004x_request_firmware -}; - -/* ------------------------------------------------------------------ - * special case: this card uses saa713x GPIO22 for the mode switch - */ - -static int ads_duo_tuner_init(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - philips_tda827x_tuner_init(fe); - /* route TDA8275a AGC input to the channel decoder */ - saa7134_set_gpio(dev, 22, 1); - return 0; -} - -static int ads_duo_tuner_sleep(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - /* route TDA8275a AGC input to the analog IF chip*/ - saa7134_set_gpio(dev, 22, 0); - philips_tda827x_tuner_sleep(fe); - return 0; -} - -static struct tda827x_config ads_duo_cfg = { - .init = ads_duo_tuner_init, - .sleep = ads_duo_tuner_sleep, - .config = 0 -}; - -static struct tda1004x_config ads_tech_duo_config = { - .demod_address = 0x08, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, - .gpio_config = TDA10046_GP00_I, - .if_freq = TDA10046_FREQ_045, - .tuner_address = 0x61, - .request_firmware = philips_tda1004x_request_firmware -}; - -static struct zl10353_config behold_h6_config = { - .demod_address = 0x1e>>1, - .no_tuner = 1, - .parallel_ts = 1, - .disable_i2c_gate_ctrl = 1, -}; - -static struct xc5000_config behold_x7_tunerconfig = { - .i2c_address = 0xc2>>1, - .if_khz = 4560, - .radio_input = XC5000_RADIO_FM1, -}; - -static struct zl10353_config behold_x7_config = { - .demod_address = 0x1e>>1, - .if2 = 45600, - .no_tuner = 1, - .parallel_ts = 1, - .disable_i2c_gate_ctrl = 1, -}; - -/* ================================================================== - * tda10086 based DVB-S cards, helper functions - */ - -static struct tda10086_config flydvbs = { - .demod_address = 0x0e, - .invert = 0, - .diseqc_tone = 0, - .xtal_freq = TDA10086_XTAL_16M, -}; - -static struct tda10086_config sd1878_4m = { - .demod_address = 0x0e, - .invert = 0, - .diseqc_tone = 0, - .xtal_freq = TDA10086_XTAL_4M, -}; - -/* ------------------------------------------------------------------ - * special case: lnb supply is connected to the gated i2c - */ - -static int md8800_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - int res = -EIO; - struct saa7134_dev *dev = fe->dvb->priv; - if (fe->ops.i2c_gate_ctrl) { - fe->ops.i2c_gate_ctrl(fe, 1); - if (dev->original_set_voltage) - res = dev->original_set_voltage(fe, voltage); - fe->ops.i2c_gate_ctrl(fe, 0); - } - return res; -}; - -static int md8800_set_high_voltage(struct dvb_frontend *fe, long arg) -{ - int res = -EIO; - struct saa7134_dev *dev = fe->dvb->priv; - if (fe->ops.i2c_gate_ctrl) { - fe->ops.i2c_gate_ctrl(fe, 1); - if (dev->original_set_high_voltage) - res = dev->original_set_high_voltage(fe, arg); - fe->ops.i2c_gate_ctrl(fe, 0); - } - return res; -}; - -static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct saa7134_dev *dev = fe->dvb->priv; - u8 wbuf[2] = { 0x1f, 00 }; - u8 rbuf; - struct i2c_msg msg[] = { { .addr = 0x08, .flags = 0, .buf = wbuf, .len = 1 }, - { .addr = 0x08, .flags = I2C_M_RD, .buf = &rbuf, .len = 1 } }; - - if (i2c_transfer(&dev->i2c_adap, msg, 2) != 2) - return -EIO; - /* NOTE: this assumes that gpo1 is used, it might be bit 5 (gpo2) */ - if (voltage == SEC_VOLTAGE_18) - wbuf[1] = rbuf | 0x10; - else - wbuf[1] = rbuf & 0xef; - msg[0].len = 2; - i2c_transfer(&dev->i2c_adap, msg, 1); - return 0; -} - -static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg) -{ - struct saa7134_dev *dev = fe->dvb->priv; - wprintk("%s: sorry can't set high LNB supply voltage from here\n", __func__); - return -EIO; -} - -/* ================================================================== - * nxt200x based ATSC cards, helper functions - */ - -static struct nxt200x_config avertvhda180 = { - .demod_address = 0x0a, -}; - -static struct nxt200x_config kworldatsc110 = { - .demod_address = 0x0a, -}; - -/* ------------------------------------------------------------------ */ - -static struct mt312_config avertv_a700_mt312 = { - .demod_address = 0x0e, - .voltage_inverted = 1, -}; - -static struct zl10036_config avertv_a700_tuner = { - .tuner_address = 0x60, -}; - -static struct mt312_config zl10313_compro_s350_config = { - .demod_address = 0x0e, -}; - -static struct lgdt3305_config hcw_lgdt3305_config = { - .i2c_addr = 0x0e, - .mpeg_mode = LGDT3305_MPEG_SERIAL, - .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE, - .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, - .deny_i2c_rptr = 1, - .spectral_inversion = 1, - .qam_if_khz = 4000, - .vsb_if_khz = 3250, -}; - -static struct tda10048_config hcw_tda10048_config = { - .demod_address = 0x10 >> 1, - .output_mode = TDA10048_SERIAL_OUTPUT, - .fwbulkwritelen = TDA10048_BULKWRITE_200, - .inversion = TDA10048_INVERSION_ON, - .dtv6_if_freq_khz = TDA10048_IF_3300, - .dtv7_if_freq_khz = TDA10048_IF_3500, - .dtv8_if_freq_khz = TDA10048_IF_4000, - .clk_freq_khz = TDA10048_CLK_16000, - .disable_gate_access = 1, -}; - -static struct tda18271_std_map hauppauge_tda18271_std_map = { - .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x58, }, - .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x58, }, -}; - -static struct tda18271_config hcw_tda18271_config = { - .std_map = &hauppauge_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, - .config = 3, - .output_opt = TDA18271_OUTPUT_LT_OFF, -}; - -static struct tda829x_config tda829x_no_probe = { - .probe_tuner = TDA829X_DONT_PROBE, -}; - -static struct tda10048_config zolid_tda10048_config = { - .demod_address = 0x10 >> 1, - .output_mode = TDA10048_PARALLEL_OUTPUT, - .fwbulkwritelen = TDA10048_BULKWRITE_200, - .inversion = TDA10048_INVERSION_ON, - .dtv6_if_freq_khz = TDA10048_IF_3300, - .dtv7_if_freq_khz = TDA10048_IF_3500, - .dtv8_if_freq_khz = TDA10048_IF_4000, - .clk_freq_khz = TDA10048_CLK_16000, - .disable_gate_access = 1, -}; - -static struct tda18271_config zolid_tda18271_config = { - .gate = TDA18271_GATE_ANALOG, -}; - -static struct tda10048_config dtv1000s_tda10048_config = { - .demod_address = 0x10 >> 1, - .output_mode = TDA10048_PARALLEL_OUTPUT, - .fwbulkwritelen = TDA10048_BULKWRITE_200, - .inversion = TDA10048_INVERSION_ON, - .dtv6_if_freq_khz = TDA10048_IF_3300, - .dtv7_if_freq_khz = TDA10048_IF_3800, - .dtv8_if_freq_khz = TDA10048_IF_4300, - .clk_freq_khz = TDA10048_CLK_16000, - .disable_gate_access = 1, -}; - -static struct tda18271_std_map dtv1000s_tda18271_std_map = { - .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, - .if_lvl = 1, .rfagc_top = 0x37, }, - .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5, - .if_lvl = 1, .rfagc_top = 0x37, }, - .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6, - .if_lvl = 1, .rfagc_top = 0x37, }, -}; - -static struct tda18271_config dtv1000s_tda18271_config = { - .std_map = &dtv1000s_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, -}; - -/* ================================================================== - * Core code - */ - -static int dvb_init(struct saa7134_dev *dev) -{ - int ret; - int attach_xc3028 = 0; - struct videobuf_dvb_frontend *fe0; - - /* FIXME: add support for multi-frontend */ - mutex_init(&dev->frontends.lock); - INIT_LIST_HEAD(&dev->frontends.felist); - - printk(KERN_INFO "%s() allocating 1 frontend\n", __func__); - fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1); - if (!fe0) { - printk(KERN_ERR "%s() failed to alloc\n", __func__); - return -ENOMEM; - } - - /* init struct videobuf_dvb */ - dev->ts.nr_bufs = 32; - dev->ts.nr_packets = 32*4; - fe0->dvb.name = dev->name; - videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_ALTERNATE, - sizeof(struct saa7134_buf), - dev, NULL); - - switch (dev->board) { - case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: - dprintk("pinnacle 300i dvb setup\n"); - fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - fe0->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params; - } - break; - case SAA7134_BOARD_AVERMEDIA_777: - case SAA7134_BOARD_AVERMEDIA_A16AR: - dprintk("avertv 777 dvb setup\n"); - fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x61, - TUNER_PHILIPS_TD1316); - } - break; - case SAA7134_BOARD_AVERMEDIA_A16D: - dprintk("AverMedia A16D dvb setup\n"); - fe0->dvb.frontend = dvb_attach(mt352_attach, - &avermedia_xc3028_mt352_dev, - &dev->i2c_adap); - attach_xc3028 = 1; - break; - case SAA7134_BOARD_MD7134: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &medion_cardbus, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &dev->i2c_adap, medion_cardbus.tuner_address, - TUNER_PHILIPS_FMD1216ME_MK3); - } - break; - case SAA7134_BOARD_PHILIPS_TOUGH: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &philips_tu1216_60_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init; - fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set; - } - break; - case SAA7134_BOARD_FLYDVBTDUO: - case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS: - if (configure_tda827x_fe(dev, &tda827x_lifeview_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_PHILIPS_EUROPA: - case SAA7134_BOARD_VIDEOMATE_DVBT_300: - case SAA7134_BOARD_ASUS_EUROPA_HYBRID: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &philips_europa_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep; - fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep; - fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init; - fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep; - fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; - } - break; - case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &technotrend_budget_t3000_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep; - fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep; - fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init; - fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep; - fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; - } - break; - case SAA7134_BOARD_VIDEOMATE_DVBT_200: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &philips_tu1216_61_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init; - fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set; - } - break; - case SAA7134_BOARD_KWORLD_DVBT_210: - if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config, - &tda827x_cfg_2) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_HAUPPAUGE_HVR1120: - fe0->dvb.frontend = dvb_attach(tda10048_attach, - &hcw_tda10048_config, - &dev->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(tda829x_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x4b, - &tda829x_no_probe); - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_adap, - &hcw_tda18271_config); - } - break; - case SAA7134_BOARD_PHILIPS_TIGER: - if (configure_tda827x_fe(dev, &philips_tiger_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_PINNACLE_PCTV_310i: - if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, - &tda827x_cfg_1) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_HAUPPAUGE_HVR1110: - if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, - &tda827x_cfg_1) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_HAUPPAUGE_HVR1150: - fe0->dvb.frontend = dvb_attach(lgdt3305_attach, - &hcw_lgdt3305_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - dvb_attach(tda829x_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x4b, - &tda829x_no_probe); - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_adap, - &hcw_tda18271_config); - } - break; - case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - if (configure_tda827x_fe(dev, &asus_p7131_dual_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_FLYDVBT_LR301: - if (configure_tda827x_fe(dev, &tda827x_lifeview_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_FLYDVB_TRIO: - if (!use_frontend) { /* terrestrial */ - if (configure_tda827x_fe(dev, &lifeview_trio_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - } else { /* satellite */ - fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); - if (fe0->dvb.frontend) { - if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63, - &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__); - goto dettach_frontend; - } - if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap, - 0x08, 0, 0) == NULL) { - wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__); - goto dettach_frontend; - } - } - } - break; - case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: - case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &ads_tech_duo_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - if (dvb_attach(tda827x_attach,fe0->dvb.frontend, - ads_tech_duo_config.tuner_address, &dev->i2c_adap, - &ads_duo_cfg) == NULL) { - wprintk("no tda827x tuner found at addr: %02x\n", - ads_tech_duo_config.tuner_address); - goto dettach_frontend; - } - } else - wprintk("failed to attach tda10046\n"); - break; - case SAA7134_BOARD_TEVION_DVBT_220RF: - if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_MEDION_MD8800_QUADRO: - if (!use_frontend) { /* terrestrial */ - if (configure_tda827x_fe(dev, &md8800_dvbt_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - } else { /* satellite */ - fe0->dvb.frontend = dvb_attach(tda10086_attach, - &flydvbs, &dev->i2c_adap); - if (fe0->dvb.frontend) { - struct dvb_frontend *fe = fe0->dvb.frontend; - u8 dev_id = dev->eedata[2]; - u8 data = 0xc4; - struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1}; - - if (dvb_attach(tda826x_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Medion Quadro, no tda826x " - "found !\n", __func__); - goto dettach_frontend; - } - if (dev_id != 0x08) { - /* we need to open the i2c gate (we know it exists) */ - fe->ops.i2c_gate_ctrl(fe, 1); - if (dvb_attach(isl6405_attach, fe, - &dev->i2c_adap, 0x08, 0, 0) == NULL) { - wprintk("%s: Medion Quadro, no ISL6405 " - "found !\n", __func__); - goto dettach_frontend; - } - if (dev_id == 0x07) { - /* fire up the 2nd section of the LNB supply since - we can't do this from the other section */ - msg.buf = &data; - i2c_transfer(&dev->i2c_adap, &msg, 1); - } - fe->ops.i2c_gate_ctrl(fe, 0); - dev->original_set_voltage = fe->ops.set_voltage; - fe->ops.set_voltage = md8800_set_voltage; - dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage; - fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage; - } else { - fe->ops.set_voltage = md8800_set_voltage2; - fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage2; - } - } - } - break; - case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: - fe0->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180, - &dev->i2c_adap); - if (fe0->dvb.frontend) - dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61, - NULL, DVB_PLL_TDHU2); - break; - case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI: - case SAA7134_BOARD_KWORLD_ATSC110: - fe0->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110, - &dev->i2c_adap); - if (fe0->dvb.frontend) - dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x61, - TUNER_PHILIPS_TUV1236D); - break; - case SAA7134_BOARD_FLYDVBS_LR300: - fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, - &dev->i2c_adap, 0) == NULL) { - wprintk("%s: No tda826x found!\n", __func__); - goto dettach_frontend; - } - if (dvb_attach(isl6421_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x08, 0, 0) == NULL) { - wprintk("%s: No ISL6421 found!\n", __func__); - goto dettach_frontend; - } - } - break; - case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &medion_cardbus, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep; - fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep; - - dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &dev->i2c_adap, medion_cardbus.tuner_address, - TUNER_PHILIPS_FMD1216ME_MK3); - } - break; - case SAA7134_BOARD_VIDEOMATE_DVBT_200A: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &philips_europa_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - fe0->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init; - fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; - } - break; - case SAA7134_BOARD_CINERGY_HT_PCMCIA: - if (configure_tda827x_fe(dev, &cinergy_ht_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_CINERGY_HT_PCI: - if (configure_tda827x_fe(dev, &cinergy_ht_pci_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_PHILIPS_TIGER_S: - if (configure_tda827x_fe(dev, &philips_tiger_s_config, - &tda827x_cfg_2) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_ASUS_P7131_4871: - if (configure_tda827x_fe(dev, &asus_p7131_4871_config, - &tda827x_cfg_2) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: - if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config, - &tda827x_cfg_2) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_AVERMEDIA_SUPER_007: - if (configure_tda827x_fe(dev, &avermedia_super_007_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_TWINHAN_DTV_DVB_3056: - if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config, - &tda827x_cfg_2_sw42) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_PHILIPS_SNAKE: - fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, - &dev->i2c_adap, 0) == NULL) { - wprintk("%s: No tda826x found!\n", __func__); - goto dettach_frontend; - } - if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0, 0) == NULL) { - wprintk("%s: No lnbp21 found!\n", __func__); - goto dettach_frontend; - } - } - break; - case SAA7134_BOARD_CREATIX_CTX953: - if (configure_tda827x_fe(dev, &md8800_dvbt_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_MSI_TVANYWHERE_AD11: - if (configure_tda827x_fe(dev, &philips_tiger_s_config, - &tda827x_cfg_2) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: - dprintk("AverMedia E506R dvb setup\n"); - saa7134_set_gpio(dev, 25, 0); - msleep(10); - saa7134_set_gpio(dev, 25, 1); - fe0->dvb.frontend = dvb_attach(mt352_attach, - &avermedia_xc3028_mt352_dev, - &dev->i2c_adap); - attach_xc3028 = 1; - break; - case SAA7134_BOARD_MD7134_BRIDGE_2: - fe0->dvb.frontend = dvb_attach(tda10086_attach, - &sd1878_4m, &dev->i2c_adap); - if (fe0->dvb.frontend) { - struct dvb_frontend *fe; - if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, - &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) { - wprintk("%s: MD7134 DVB-S, no SD1878 " - "found !\n", __func__); - goto dettach_frontend; - } - /* we need to open the i2c gate (we know it exists) */ - fe = fe0->dvb.frontend; - fe->ops.i2c_gate_ctrl(fe, 1); - if (dvb_attach(isl6405_attach, fe, - &dev->i2c_adap, 0x08, 0, 0) == NULL) { - wprintk("%s: MD7134 DVB-S, no ISL6405 " - "found !\n", __func__); - goto dettach_frontend; - } - fe->ops.i2c_gate_ctrl(fe, 0); - dev->original_set_voltage = fe->ops.set_voltage; - fe->ops.set_voltage = md8800_set_voltage; - dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage; - fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage; - } - break; - case SAA7134_BOARD_AVERMEDIA_M103: - saa7134_set_gpio(dev, 25, 0); - msleep(10); - saa7134_set_gpio(dev, 25, 1); - fe0->dvb.frontend = dvb_attach(mt352_attach, - &avermedia_xc3028_mt352_dev, - &dev->i2c_adap); - attach_xc3028 = 1; - break; - case SAA7134_BOARD_ASUSTeK_TIGER_3IN1: - if (!use_frontend) { /* terrestrial */ - if (configure_tda827x_fe(dev, &asus_tiger_3in1_config, - &tda827x_cfg_2) < 0) - goto dettach_frontend; - } else { /* satellite */ - fe0->dvb.frontend = dvb_attach(tda10086_attach, - &flydvbs, &dev->i2c_adap); - if (fe0->dvb.frontend) { - if (dvb_attach(tda826x_attach, - fe0->dvb.frontend, 0x60, - &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Asus Tiger 3in1, no " - "tda826x found!\n", __func__); - goto dettach_frontend; - } - if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0, 0) == NULL) { - wprintk("%s: Asus Tiger 3in1, no lnbp21" - " found!\n", __func__); - goto dettach_frontend; - } - } - } - break; - case SAA7134_BOARD_ASUSTeK_TIGER: - if (configure_tda827x_fe(dev, &philips_tiger_config, - &tda827x_cfg_0) < 0) - goto dettach_frontend; - break; - case SAA7134_BOARD_BEHOLD_H6: - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &behold_h6_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216MEX_MK3); - } - break; - case SAA7134_BOARD_BEHOLD_X7: - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &behold_x7_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - dvb_attach(xc5000_attach, fe0->dvb.frontend, - &dev->i2c_adap, &behold_x7_tunerconfig); - } - break; - case SAA7134_BOARD_BEHOLD_H7: - fe0->dvb.frontend = dvb_attach(zl10353_attach, - &behold_x7_config, - &dev->i2c_adap); - if (fe0->dvb.frontend) { - dvb_attach(xc5000_attach, fe0->dvb.frontend, - &dev->i2c_adap, &behold_x7_tunerconfig); - } - break; - case SAA7134_BOARD_AVERMEDIA_A700_PRO: - case SAA7134_BOARD_AVERMEDIA_A700_HYBRID: - /* Zarlink ZL10313 */ - fe0->dvb.frontend = dvb_attach(mt312_attach, - &avertv_a700_mt312, &dev->i2c_adap); - if (fe0->dvb.frontend) { - if (dvb_attach(zl10036_attach, fe0->dvb.frontend, - &avertv_a700_tuner, &dev->i2c_adap) == NULL) { - wprintk("%s: No zl10036 found!\n", - __func__); - } - } - break; - case SAA7134_BOARD_VIDEOMATE_S350: - fe0->dvb.frontend = dvb_attach(mt312_attach, - &zl10313_compro_s350_config, &dev->i2c_adap); - if (fe0->dvb.frontend) - if (dvb_attach(zl10039_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_adap) == NULL) - wprintk("%s: No zl10039 found!\n", - __func__); - - break; - case SAA7134_BOARD_ZOLID_HYBRID_PCI: - fe0->dvb.frontend = dvb_attach(tda10048_attach, - &zolid_tda10048_config, - &dev->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(tda829x_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x4b, - &tda829x_no_probe); - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_adap, - &zolid_tda18271_config); - } - break; - case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S: - fe0->dvb.frontend = dvb_attach(tda10048_attach, - &dtv1000s_tda10048_config, - &dev->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(tda829x_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x4b, - &tda829x_no_probe); - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_adap, - &dtv1000s_tda18271_config); - } - break; - case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: - /* Switch to digital mode */ - saa7134_tuner_callback(dev, 0, - TDA18271_CALLBACK_CMD_AGC_ENABLE, 1); - fe0->dvb.frontend = dvb_attach(mb86a20s_attach, - &kworld_mb86a20s_config, - &dev->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(tda829x_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x4b, - &tda829x_no_probe); - dvb_attach(tda18271_attach, fe0->dvb.frontend, - 0x60, &dev->i2c_adap, - &kworld_tda18271_config); - fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_gate_ctrl; - } - - /* mb86a20s need to use the I2C gateway */ - break; - default: - wprintk("Huh? unknown DVB card?\n"); - break; - } - - if (attach_xc3028) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &dev->i2c_adap, - .i2c_addr = 0x61, - }; - - if (!fe0->dvb.frontend) - goto dettach_frontend; - - fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); - if (!fe) { - printk(KERN_ERR "%s/2: xc3028 attach failed\n", - dev->name); - goto dettach_frontend; - } - } - - if (NULL == fe0->dvb.frontend) { - printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); - goto dettach_frontend; - } - /* define general-purpose callback pointer */ - fe0->dvb.frontend->callback = saa7134_tuner_callback; - - /* register everything else */ - ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, - &dev->pci->dev, adapter_nr, 0, NULL); - - /* this sequence is necessary to make the tda1004x load its firmware - * and to enter analog mode of hybrid boards - */ - if (!ret) { - if (fe0->dvb.frontend->ops.init) - fe0->dvb.frontend->ops.init(fe0->dvb.frontend); - if (fe0->dvb.frontend->ops.sleep) - fe0->dvb.frontend->ops.sleep(fe0->dvb.frontend); - if (fe0->dvb.frontend->ops.tuner_ops.sleep) - fe0->dvb.frontend->ops.tuner_ops.sleep(fe0->dvb.frontend); - } - return ret; - -dettach_frontend: - videobuf_dvb_dealloc_frontends(&dev->frontends); - return -EINVAL; -} - -static int dvb_fini(struct saa7134_dev *dev) -{ - struct videobuf_dvb_frontend *fe0; - - /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); - if (!fe0) - return -EINVAL; - - /* FIXME: I suspect that this code is bogus, since the entry for - Pinnacle 300I DVB-T PAL already defines the proper init to allow - the detection of mt2032 (TDA9887_PORT2_INACTIVE) - */ - if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) { - struct v4l2_priv_tun_config tda9887_cfg; - static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &on; - - /* otherwise we don't detect the tuner on next insmod */ - saa_call_all(dev, tuner, s_config, &tda9887_cfg); - } else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) { - if ((dev->eedata[2] == 0x07) && use_frontend) { - /* turn off the 2nd lnb supply */ - u8 data = 0x80; - struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1}; - struct dvb_frontend *fe; - fe = fe0->dvb.frontend; - if (fe->ops.i2c_gate_ctrl) { - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(&dev->i2c_adap, &msg, 1); - fe->ops.i2c_gate_ctrl(fe, 0); - } - } - } - videobuf_dvb_unregister_bus(&dev->frontends); - return 0; -} - -static struct saa7134_mpeg_ops dvb_ops = { - .type = SAA7134_MPEG_DVB, - .init = dvb_init, - .fini = dvb_fini, -}; - -static int __init dvb_register(void) -{ - return saa7134_ts_register(&dvb_ops); -} - -static void __exit dvb_unregister(void) -{ - saa7134_ts_unregister(&dvb_ops); -} - -module_init(dvb_register); -module_exit(dvb_unregister); - -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-empress.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-empress.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-empress.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-empress.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,591 +0,0 @@ -/* - * - * (c) 2004 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" - -#include -#include -#include - -/* ------------------------------------------------------------------ */ - -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; - -module_param_array(empress_nr, int, NULL, 0444); -MODULE_PARM_DESC(empress_nr,"ts device number"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages"); - -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/empress: " fmt, dev->name , ## arg) - -/* ------------------------------------------------------------------ */ - -static void ts_reset_encoder(struct saa7134_dev* dev) -{ - if (!dev->empress_started) - return; - - saa_writeb(SAA7134_SPECIAL_MODE, 0x00); - msleep(10); - saa_writeb(SAA7134_SPECIAL_MODE, 0x01); - msleep(100); - dev->empress_started = 0; -} - -static int ts_init_encoder(struct saa7134_dev* dev) -{ - u32 leading_null_bytes = 0; - - /* If more cards start to need this, then this - should probably be added to the card definitions. */ - switch (dev->board) { - case SAA7134_BOARD_BEHOLD_M6: - case SAA7134_BOARD_BEHOLD_M63: - case SAA7134_BOARD_BEHOLD_M6_EXTRA: - leading_null_bytes = 1; - break; - } - ts_reset_encoder(dev); - saa_call_all(dev, core, init, leading_null_bytes); - dev->empress_started = 1; - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int ts_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct saa7134_dev *dev = video_drvdata(file); - int err; - - dprintk("open dev=%s\n", video_device_node_name(vdev)); - err = -EBUSY; - if (!mutex_trylock(&dev->empress_tsq.vb_lock)) - return err; - if (atomic_read(&dev->empress_users)) - goto done; - - /* Unmute audio */ - saa_writeb(SAA7134_AUDIO_MUTE_CTRL, - saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6)); - - atomic_inc(&dev->empress_users); - file->private_data = dev; - err = 0; - -done: - mutex_unlock(&dev->empress_tsq.vb_lock); - return err; -} - -static int ts_release(struct file *file) -{ - struct saa7134_dev *dev = file->private_data; - - videobuf_stop(&dev->empress_tsq); - videobuf_mmap_free(&dev->empress_tsq); - - /* stop the encoder */ - ts_reset_encoder(dev); - - /* Mute audio */ - saa_writeb(SAA7134_AUDIO_MUTE_CTRL, - saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); - - atomic_dec(&dev->empress_users); - - return 0; -} - -static ssize_t -ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct saa7134_dev *dev = file->private_data; - - if (!dev->empress_started) - ts_init_encoder(dev); - - return videobuf_read_stream(&dev->empress_tsq, - data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static unsigned int -ts_poll(struct file *file, struct poll_table_struct *wait) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_poll_stream(file, &dev->empress_tsq, wait); -} - - -static int -ts_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_mmap_mapper(&dev->empress_tsq, vma); -} - -/* - * This function is _not_ called directly, but from - * video_generic_ioctl (and maybe others). userspace - * copying is done already, arg is a kernel pointer. - */ - -static int empress_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct saa7134_dev *dev = file->private_data; - - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - return 0; -} - -static int empress_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, "CCIR656"); - - return 0; -} - -static int empress_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int empress_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - - return 0; -} - -static int empress_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index != 0) - return -EINVAL; - - strlcpy(f->description, "MPEG TS", sizeof(f->description)); - f->pixelformat = V4L2_PIX_FMT_MPEG; - - return 0; -} - -static int empress_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_dev *dev = file->private_data; - struct v4l2_mbus_framefmt mbus_fmt; - - saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt); - - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - - return 0; -} - -static int empress_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_dev *dev = file->private_data; - struct v4l2_mbus_framefmt mbus_fmt; - - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); - saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - - return 0; -} - -static int empress_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_dev *dev = file->private_data; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - - return 0; -} - -static int empress_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_reqbufs(&dev->empress_tsq, p); -} - -static int empress_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_querybuf(&dev->empress_tsq, b); -} - -static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_qbuf(&dev->empress_tsq, b); -} - -static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_dqbuf(&dev->empress_tsq, b, - file->f_flags & O_NONBLOCK); -} - -static int empress_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_streamon(&dev->empress_tsq); -} - -static int empress_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_streamoff(&dev->empress_tsq); -} - -static int empress_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct saa7134_dev *dev = file->private_data; - int err; - - /* count == 0 is abused in saa6752hs.c, so that special - case is handled here explicitly. */ - if (ctrls->count == 0) - return 0; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - err = saa_call_empress(dev, core, s_ext_ctrls, ctrls); - ts_init_encoder(dev); - - return err; -} - -static int empress_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct saa7134_dev *dev = file->private_data; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return saa_call_empress(dev, core, g_ext_ctrls, ctrls); -} - -static int empress_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct saa7134_dev *dev = file->private_data; - - return saa7134_g_ctrl_internal(dev, NULL, c); -} - -static int empress_s_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct saa7134_dev *dev = file->private_data; - - return saa7134_s_ctrl_internal(dev, NULL, c); -} - -static int empress_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - /* Must be sorted from low to high control ID! */ - static const u32 user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_MUTE, - V4L2_CID_HFLIP, - 0 - }; - - /* Must be sorted from low to high control ID! */ - static const u32 mpeg_ctrls[] = { - V4L2_CID_MPEG_CLASS, - V4L2_CID_MPEG_STREAM_TYPE, - V4L2_CID_MPEG_STREAM_PID_PMT, - V4L2_CID_MPEG_STREAM_PID_AUDIO, - V4L2_CID_MPEG_STREAM_PID_VIDEO, - V4L2_CID_MPEG_STREAM_PID_PCR, - V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, - V4L2_CID_MPEG_AUDIO_ENCODING, - V4L2_CID_MPEG_AUDIO_L2_BITRATE, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_CID_MPEG_VIDEO_ASPECT, - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, - V4L2_CID_MPEG_VIDEO_BITRATE, - V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, - 0 - }; - static const u32 *ctrl_classes[] = { - user_ctrls, - mpeg_ctrls, - NULL - }; - struct saa7134_dev *dev = file->private_data; - - c->id = v4l2_ctrl_next(ctrl_classes, c->id); - if (c->id == 0) - return -EINVAL; - if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS) - return v4l2_ctrl_query_fill(c, 0, 0, 0, 0); - if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) - return saa7134_queryctrl(file, priv, c); - return saa_call_empress(dev, core, queryctrl, c); -} - -static int empress_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *c) -{ - struct saa7134_dev *dev = file->private_data; - - if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return saa_call_empress(dev, core, querymenu, c); -} - -static int empress_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) -{ - struct saa7134_dev *dev = file->private_data; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER && - !strcmp(chip->match.name, "saa6752hs")) - return saa_call_empress(dev, core, g_chip_ident, chip); - if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR) - return saa_call_empress(dev, core, g_chip_ident, chip); - return -EINVAL; -} - -static int empress_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct saa7134_dev *dev = file->private_data; - - return saa7134_s_std_internal(dev, NULL, id); -} - -static int empress_g_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct saa7134_dev *dev = file->private_data; - - *id = dev->tvnorm->id; - return 0; -} - -static const struct v4l2_file_operations ts_fops = -{ - .owner = THIS_MODULE, - .open = ts_open, - .release = ts_release, - .read = ts_read, - .poll = ts_poll, - .mmap = ts_mmap, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops ts_ioctl_ops = { - .vidioc_querycap = empress_querycap, - .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = empress_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap, - .vidioc_reqbufs = empress_reqbufs, - .vidioc_querybuf = empress_querybuf, - .vidioc_qbuf = empress_qbuf, - .vidioc_dqbuf = empress_dqbuf, - .vidioc_streamon = empress_streamon, - .vidioc_streamoff = empress_streamoff, - .vidioc_s_ext_ctrls = empress_s_ext_ctrls, - .vidioc_g_ext_ctrls = empress_g_ext_ctrls, - .vidioc_enum_input = empress_enum_input, - .vidioc_g_input = empress_g_input, - .vidioc_s_input = empress_s_input, - .vidioc_queryctrl = empress_queryctrl, - .vidioc_querymenu = empress_querymenu, - .vidioc_g_ctrl = empress_g_ctrl, - .vidioc_s_ctrl = empress_s_ctrl, - .vidioc_g_chip_ident = empress_g_chip_ident, - .vidioc_s_std = empress_s_std, - .vidioc_g_std = empress_g_std, -}; - -/* ----------------------------------------------------------- */ - -static struct video_device saa7134_empress_template = { - .name = "saa7134-empress", - .fops = &ts_fops, - .ioctl_ops = &ts_ioctl_ops, - - .tvnorms = SAA7134_NORMS, - .current_norm = V4L2_STD_PAL, -}; - -static void empress_signal_update(struct work_struct *work) -{ - struct saa7134_dev* dev = - container_of(work, struct saa7134_dev, empress_workqueue); - - if (dev->nosignal) { - dprintk("no video signal\n"); - } else { - dprintk("video signal acquired\n"); - } -} - -static void empress_signal_change(struct saa7134_dev *dev) -{ - schedule_work(&dev->empress_workqueue); -} - - -static int empress_init(struct saa7134_dev *dev) -{ - int err; - - dprintk("%s: %s\n",dev->name,__func__); - dev->empress_dev = video_device_alloc(); - if (NULL == dev->empress_dev) - return -ENOMEM; - *(dev->empress_dev) = saa7134_empress_template; - dev->empress_dev->parent = &dev->pci->dev; - dev->empress_dev->release = video_device_release; - snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name), - "%s empress (%s)", dev->name, - saa7134_boards[dev->board].name); - - INIT_WORK(&dev->empress_workqueue, empress_signal_update); - - video_set_drvdata(dev->empress_dev, dev); - err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, - empress_nr[dev->nr]); - if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - video_device_release(dev->empress_dev); - dev->empress_dev = NULL; - return err; - } - printk(KERN_INFO "%s: registered device %s [mpeg]\n", - dev->name, video_device_node_name(dev->empress_dev)); - - videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_ALTERNATE, - sizeof(struct saa7134_buf), - dev, NULL); - - empress_signal_update(&dev->empress_workqueue); - return 0; -} - -static int empress_fini(struct saa7134_dev *dev) -{ - dprintk("%s: %s\n",dev->name,__func__); - - if (NULL == dev->empress_dev) - return 0; - flush_work_sync(&dev->empress_workqueue); - video_unregister_device(dev->empress_dev); - dev->empress_dev = NULL; - return 0; -} - -static struct saa7134_mpeg_ops empress_ops = { - .type = SAA7134_MPEG_EMPRESS, - .init = empress_init, - .fini = empress_fini, - .signal_change = empress_signal_change, -}; - -static int __init empress_register(void) -{ - return saa7134_ts_register(&empress_ops); -} - -static void __exit empress_unregister(void) -{ - saa7134_ts_unregister(&empress_ops); -} - -module_init(empress_register); -module_exit(empress_unregister); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,850 +0,0 @@ -/* - * - * v4l2 device driver for philips saa7134 based TV cards - * - * (c) 2001,02 Gerd Knorr - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#define SAA7134_VERSION_CODE KERNEL_VERSION(0, 2, 16) - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE) -#include -#endif - -#define UNSET (-1U) - -/* ----------------------------------------------------------- */ -/* enums */ - -enum saa7134_tvaudio_mode { - TVAUDIO_FM_MONO = 1, - TVAUDIO_FM_BG_STEREO = 2, - TVAUDIO_FM_SAT_STEREO = 3, - TVAUDIO_FM_K_STEREO = 4, - TVAUDIO_NICAM_AM = 5, - TVAUDIO_NICAM_FM = 6, -}; - -enum saa7134_audio_in { - TV = 1, - LINE1 = 2, - LINE2 = 3, - LINE2_LEFT, -}; - -enum saa7134_video_out { - CCIR656 = 1, -}; - -/* ----------------------------------------------------------- */ -/* static data */ - -struct saa7134_tvnorm { - char *name; - v4l2_std_id id; - - /* video decoder */ - unsigned int sync_control; - unsigned int luma_control; - unsigned int chroma_ctrl1; - unsigned int chroma_gain; - unsigned int chroma_ctrl2; - unsigned int vgate_misc; - - /* video scaler */ - unsigned int h_start; - unsigned int h_stop; - unsigned int video_v_start; - unsigned int video_v_stop; - unsigned int vbi_v_start_0; - unsigned int vbi_v_stop_0; - unsigned int src_timing; - unsigned int vbi_v_start_1; -}; - -struct saa7134_tvaudio { - char *name; - v4l2_std_id std; - enum saa7134_tvaudio_mode mode; - int carr1; - int carr2; -}; - -struct saa7134_format { - char *name; - unsigned int fourcc; - unsigned int depth; - unsigned int pm; - unsigned int vshift; /* vertical downsampling (for planar yuv) */ - unsigned int hshift; /* horizontal downsampling (for planar yuv) */ - unsigned int bswap:1; - unsigned int wswap:1; - unsigned int yuv:1; - unsigned int planar:1; - unsigned int uvswap:1; -}; - -struct saa7134_card_ir { - struct rc_dev *dev; - - char name[32]; - char phys[32]; - unsigned users; - - u32 polling; - u32 last_gpio; - u32 mask_keycode, mask_keydown, mask_keyup; - - bool running; - bool active; - - struct timer_list timer; - - /* IR core raw decoding */ - u32 raw_decode; -}; - -/* ----------------------------------------------------------- */ -/* card configuration */ - -#define SAA7134_BOARD_NOAUTO UNSET -#define SAA7134_BOARD_UNKNOWN 0 -#define SAA7134_BOARD_PROTEUS_PRO 1 -#define SAA7134_BOARD_FLYVIDEO3000 2 -#define SAA7134_BOARD_FLYVIDEO2000 3 -#define SAA7134_BOARD_EMPRESS 4 -#define SAA7134_BOARD_MONSTERTV 5 -#define SAA7134_BOARD_MD9717 6 -#define SAA7134_BOARD_TVSTATION_RDS 7 -#define SAA7134_BOARD_CINERGY400 8 -#define SAA7134_BOARD_MD5044 9 -#define SAA7134_BOARD_KWORLD 10 -#define SAA7134_BOARD_CINERGY600 11 -#define SAA7134_BOARD_MD7134 12 -#define SAA7134_BOARD_TYPHOON_90031 13 -#define SAA7134_BOARD_ELSA 14 -#define SAA7134_BOARD_ELSA_500TV 15 -#define SAA7134_BOARD_ASUSTeK_TVFM7134 16 -#define SAA7134_BOARD_VA1000POWER 17 -#define SAA7134_BOARD_BMK_MPEX_NOTUNER 18 -#define SAA7134_BOARD_VIDEOMATE_TV 19 -#define SAA7134_BOARD_CRONOS_PLUS 20 -#define SAA7134_BOARD_10MOONSTVMASTER 21 -#define SAA7134_BOARD_MD2819 22 -#define SAA7134_BOARD_BMK_MPEX_TUNER 23 -#define SAA7134_BOARD_TVSTATION_DVR 24 -#define SAA7134_BOARD_ASUSTEK_TVFM7133 25 -#define SAA7134_BOARD_PINNACLE_PCTV_STEREO 26 -#define SAA7134_BOARD_MANLI_MTV002 27 -#define SAA7134_BOARD_MANLI_MTV001 28 -#define SAA7134_BOARD_TG3000TV 29 -#define SAA7134_BOARD_ECS_TVP3XP 30 -#define SAA7134_BOARD_ECS_TVP3XP_4CB5 31 -#define SAA7134_BOARD_AVACSSMARTTV 32 -#define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33 -#define SAA7134_BOARD_NOVAC_PRIMETV7133 34 -#define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35 -#define SAA7134_BOARD_UPMOST_PURPLE_TV 36 -#define SAA7134_BOARD_ITEMS_MTV005 37 -#define SAA7134_BOARD_CINERGY200 38 -#define SAA7134_BOARD_FLYTVPLATINUM_MINI 39 -#define SAA7134_BOARD_VIDEOMATE_TV_PVR 40 -#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS 41 -#define SAA7134_BOARD_SABRENT_SBTTVFM 42 -#define SAA7134_BOARD_ZOLID_XPERT_TV7134 43 -#define SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE 44 -#define SAA7134_BOARD_AVERMEDIA_STUDIO_307 45 -#define SAA7134_BOARD_AVERMEDIA_CARDBUS 46 -#define SAA7134_BOARD_CINERGY400_CARDBUS 47 -#define SAA7134_BOARD_CINERGY600_MK3 48 -#define SAA7134_BOARD_VIDEOMATE_GOLD_PLUS 49 -#define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50 -#define SAA7134_BOARD_PROVIDEO_PV952 51 -#define SAA7134_BOARD_AVERMEDIA_305 52 -#define SAA7134_BOARD_ASUSTeK_TVFM7135 53 -#define SAA7134_BOARD_FLYTVPLATINUM_FM 54 -#define SAA7134_BOARD_FLYDVBTDUO 55 -#define SAA7134_BOARD_AVERMEDIA_307 56 -#define SAA7134_BOARD_AVERMEDIA_GO_007_FM 57 -#define SAA7134_BOARD_ADS_INSTANT_TV 58 -#define SAA7134_BOARD_KWORLD_VSTREAM_XPERT 59 -#define SAA7134_BOARD_FLYDVBT_DUO_CARDBUS 60 -#define SAA7134_BOARD_PHILIPS_TOUGH 61 -#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62 -#define SAA7134_BOARD_KWORLD_XPERT 63 -#define SAA7134_BOARD_FLYTV_DIGIMATRIX 64 -#define SAA7134_BOARD_KWORLD_TERMINATOR 65 -#define SAA7134_BOARD_YUAN_TUN900 66 -#define SAA7134_BOARD_BEHOLD_409FM 67 -#define SAA7134_BOARD_GOTVIEW_7135 68 -#define SAA7134_BOARD_PHILIPS_EUROPA 69 -#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70 -#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71 -#define SAA7134_BOARD_RTD_VFG7350 72 -#define SAA7134_BOARD_RTD_VFG7330 73 -#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74 -#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75 -#define SAA7134_BOARD_MONSTERTV_MOBILE 76 -#define SAA7134_BOARD_PINNACLE_PCTV_110i 77 -#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78 -#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79 -#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80 -#define SAA7134_BOARD_PHILIPS_TIGER 81 -#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82 -#define SAA7134_BOARD_CINERGY250PCI 83 -#define SAA7134_BOARD_FLYDVB_TRIO 84 -#define SAA7134_BOARD_AVERMEDIA_777 85 -#define SAA7134_BOARD_FLYDVBT_LR301 86 -#define SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331 87 -#define SAA7134_BOARD_TEVION_DVBT_220RF 88 -#define SAA7134_BOARD_ELSA_700TV 89 -#define SAA7134_BOARD_KWORLD_ATSC110 90 -#define SAA7134_BOARD_AVERMEDIA_A169_B 91 -#define SAA7134_BOARD_AVERMEDIA_A169_B1 92 -#define SAA7134_BOARD_MD7134_BRIDGE_2 93 -#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94 -#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95 -#define SAA7134_BOARD_MEDION_MD8800_QUADRO 96 -#define SAA7134_BOARD_FLYDVBS_LR300 97 -#define SAA7134_BOARD_PROTEUS_2309 98 -#define SAA7134_BOARD_AVERMEDIA_A16AR 99 -#define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100 -#define SAA7134_BOARD_PINNACLE_PCTV_310i 101 -#define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102 -#define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103 -#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104 -#define SAA7134_BOARD_CINERGY_HT_PCMCIA 105 -#define SAA7134_BOARD_ENCORE_ENLTV 106 -#define SAA7134_BOARD_ENCORE_ENLTV_FM 107 -#define SAA7134_BOARD_CINERGY_HT_PCI 108 -#define SAA7134_BOARD_PHILIPS_TIGER_S 109 -#define SAA7134_BOARD_AVERMEDIA_M102 110 -#define SAA7134_BOARD_ASUS_P7131_4871 111 -#define SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA 112 -#define SAA7134_BOARD_ECS_TVP3XP_4CB6 113 -#define SAA7134_BOARD_KWORLD_DVBT_210 114 -#define SAA7134_BOARD_SABRENT_TV_PCB05 115 -#define SAA7134_BOARD_10MOONSTVMASTER3 116 -#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117 -#define SAA7134_BOARD_BEHOLD_401 118 -#define SAA7134_BOARD_BEHOLD_403 119 -#define SAA7134_BOARD_BEHOLD_403FM 120 -#define SAA7134_BOARD_BEHOLD_405 121 -#define SAA7134_BOARD_BEHOLD_405FM 122 -#define SAA7134_BOARD_BEHOLD_407 123 -#define SAA7134_BOARD_BEHOLD_407FM 124 -#define SAA7134_BOARD_BEHOLD_409 125 -#define SAA7134_BOARD_BEHOLD_505FM 126 -#define SAA7134_BOARD_BEHOLD_507_9FM 127 -#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128 -#define SAA7134_BOARD_BEHOLD_607FM_MK3 129 -#define SAA7134_BOARD_BEHOLD_M6 130 -#define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131 -#define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132 -#define SAA7134_BOARD_PHILIPS_SNAKE 133 -#define SAA7134_BOARD_CREATIX_CTX953 134 -#define SAA7134_BOARD_MSI_TVANYWHERE_AD11 135 -#define SAA7134_BOARD_AVERMEDIA_CARDBUS_506 136 -#define SAA7134_BOARD_AVERMEDIA_A16D 137 -#define SAA7134_BOARD_AVERMEDIA_M115 138 -#define SAA7134_BOARD_VIDEOMATE_T750 139 -#define SAA7134_BOARD_AVERMEDIA_A700_PRO 140 -#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141 -#define SAA7134_BOARD_BEHOLD_H6 142 -#define SAA7134_BOARD_BEHOLD_M63 143 -#define SAA7134_BOARD_BEHOLD_M6_EXTRA 144 -#define SAA7134_BOARD_AVERMEDIA_M103 145 -#define SAA7134_BOARD_ASUSTeK_P7131_ANALOG 146 -#define SAA7134_BOARD_ASUSTeK_TIGER_3IN1 147 -#define SAA7134_BOARD_ENCORE_ENLTV_FM53 148 -#define SAA7134_BOARD_AVERMEDIA_M135A 149 -#define SAA7134_BOARD_REAL_ANGEL_220 150 -#define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI 151 -#define SAA7134_BOARD_ASUSTeK_TIGER 152 -#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153 -#define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154 -#define SAA7134_BOARD_HAUPPAUGE_HVR1150 155 -#define SAA7134_BOARD_HAUPPAUGE_HVR1120 156 -#define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157 -#define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158 -#define SAA7134_BOARD_BEHOLD_505RDS_MK5 159 -#define SAA7134_BOARD_BEHOLD_507RDS_MK3 160 -#define SAA7134_BOARD_BEHOLD_507RDS_MK5 161 -#define SAA7134_BOARD_BEHOLD_607FM_MK5 162 -#define SAA7134_BOARD_BEHOLD_609FM_MK3 163 -#define SAA7134_BOARD_BEHOLD_609FM_MK5 164 -#define SAA7134_BOARD_BEHOLD_607RDS_MK3 165 -#define SAA7134_BOARD_BEHOLD_607RDS_MK5 166 -#define SAA7134_BOARD_BEHOLD_609RDS_MK3 167 -#define SAA7134_BOARD_BEHOLD_609RDS_MK5 168 -#define SAA7134_BOARD_VIDEOMATE_S350 169 -#define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170 -#define SAA7134_BOARD_BEHOLD_X7 171 -#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172 -#define SAA7134_BOARD_ZOLID_HYBRID_PCI 173 -#define SAA7134_BOARD_ASUS_EUROPA_HYBRID 174 -#define SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S 175 -#define SAA7134_BOARD_BEHOLD_505RDS_MK3 176 -#define SAA7134_BOARD_HAWELL_HW_404M7 177 -#define SAA7134_BOARD_BEHOLD_H7 178 -#define SAA7134_BOARD_BEHOLD_A7 179 -#define SAA7134_BOARD_AVERMEDIA_M733A 180 -#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181 -#define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182 -#define SAA7134_BOARD_VIDEOMATE_M1F 183 -#define SAA7134_BOARD_ENCORE_ENLTV_FM3 184 - -#define SAA7134_MAXBOARDS 32 -#define SAA7134_INPUT_MAX 8 - -/* ----------------------------------------------------------- */ -/* Since we support 2 remote types, lets tell them apart */ - -#define SAA7134_REMOTE_GPIO 1 -#define SAA7134_REMOTE_I2C 2 - -/* ----------------------------------------------------------- */ -/* Video Output Port Register Initialization Options */ - -#define SET_T_CODE_POLARITY_NON_INVERTED (1 << 0) -#define SET_CLOCK_NOT_DELAYED (1 << 1) -#define SET_CLOCK_INVERTED (1 << 2) -#define SET_VSYNC_OFF (1 << 3) - -struct saa7134_input { - char *name; - unsigned int vmux; - enum saa7134_audio_in amux; - unsigned int gpio; - unsigned int tv:1; -}; - -enum saa7134_mpeg_type { - SAA7134_MPEG_UNUSED, - SAA7134_MPEG_EMPRESS, - SAA7134_MPEG_DVB, -}; - -enum saa7134_mpeg_ts_type { - SAA7134_MPEG_TS_PARALLEL = 0, - SAA7134_MPEG_TS_SERIAL, -}; - -struct saa7134_board { - char *name; - unsigned int audio_clock; - - /* input switching */ - unsigned int gpiomask; - struct saa7134_input inputs[SAA7134_INPUT_MAX]; - struct saa7134_input radio; - struct saa7134_input mute; - - /* i2c chip info */ - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - unsigned char empress_addr; - unsigned char rds_addr; - - unsigned int tda9887_conf; - unsigned int tuner_config; - - /* peripheral I/O */ - enum saa7134_video_out video_out; - enum saa7134_mpeg_type mpeg; - enum saa7134_mpeg_ts_type ts_type; - unsigned int vid_port_opts; - unsigned int ts_force_val:1; -}; - -#define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name) -#define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg) -#define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg) -#define card_has_mpeg(dev) (SAA7134_MPEG_UNUSED != saa7134_boards[dev->board].mpeg) -#define card(dev) (saa7134_boards[dev->board]) -#define card_in(dev,n) (saa7134_boards[dev->board].inputs[n]) - -/* ----------------------------------------------------------- */ -/* device / file handle status */ - -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 - -#define INTERLACE_AUTO 0 -#define INTERLACE_ON 1 -#define INTERLACE_OFF 2 - -#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ -#define TS_BUFFER_TIMEOUT msecs_to_jiffies(1000) /* 1 second */ - -struct saa7134_dev; -struct saa7134_dma; - -/* saa7134 page table */ -struct saa7134_pgtable { - unsigned int size; - __le32 *cpu; - dma_addr_t dma; -}; - -/* tvaudio thread status */ -struct saa7134_thread { - struct task_struct *thread; - unsigned int scan1; - unsigned int scan2; - unsigned int mode; - unsigned int stopped; -}; - -/* buffer for one video/vbi/ts frame */ -struct saa7134_buf { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* saa7134 specific */ - struct saa7134_format *fmt; - unsigned int top_seen; - int (*activate)(struct saa7134_dev *dev, - struct saa7134_buf *buf, - struct saa7134_buf *next); - - /* page tables */ - struct saa7134_pgtable *pt; -}; - -struct saa7134_dmaqueue { - struct saa7134_dev *dev; - struct saa7134_buf *curr; - struct list_head queue; - struct timer_list timeout; - unsigned int need_two; -}; - -/* video filehandle status */ -struct saa7134_fh { - struct saa7134_dev *dev; - unsigned int radio; - enum v4l2_buf_type type; - unsigned int resources; - enum v4l2_priority prio; - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip clips[8]; - unsigned int nclips; - - /* video capture */ - struct saa7134_format *fmt; - unsigned int width,height; - struct videobuf_queue cap; - struct saa7134_pgtable pt_cap; - - /* vbi capture */ - struct videobuf_queue vbi; - struct saa7134_pgtable pt_vbi; -}; - -/* dmasound dsp status */ -struct saa7134_dmasound { - struct mutex lock; - int minor_mixer; - int minor_dsp; - unsigned int users_dsp; - - /* mixer */ - enum saa7134_audio_in input; - unsigned int count; - unsigned int line1; - unsigned int line2; - - /* dsp */ - unsigned int afmt; - unsigned int rate; - unsigned int channels; - unsigned int recording_on; - unsigned int dma_running; - unsigned int blocks; - unsigned int blksize; - unsigned int bufsize; - struct saa7134_pgtable pt; - struct videobuf_dmabuf dma; - unsigned int dma_blk; - unsigned int read_offset; - unsigned int read_count; - void * priv_data; - struct snd_pcm_substream *substream; -}; - -/* ts/mpeg status */ -struct saa7134_ts { - /* TS capture */ - struct saa7134_pgtable pt_ts; - int nr_packets; - int nr_bufs; -}; - -/* ts/mpeg ops */ -struct saa7134_mpeg_ops { - enum saa7134_mpeg_type type; - struct list_head next; - int (*init)(struct saa7134_dev *dev); - int (*fini)(struct saa7134_dev *dev); - void (*signal_change)(struct saa7134_dev *dev); -}; - -/* global device status */ -struct saa7134_dev { - struct list_head devlist; - struct mutex lock; - spinlock_t slock; - struct v4l2_prio_state prio; - struct v4l2_device v4l2_dev; - /* workstruct for loading modules */ - struct work_struct request_module_wk; - - /* insmod option/autodetected */ - int autodetected; - - /* various device info */ - unsigned int resources; - struct video_device *video_dev; - struct video_device *radio_dev; - struct video_device *vbi_dev; - struct saa7134_dmasound dmasound; - - /* infrared remote */ - int has_remote; - struct saa7134_card_ir *remote; - - /* pci i/o */ - char name[32]; - int nr; - struct pci_dev *pci; - unsigned char pci_rev,pci_lat; - __u32 __iomem *lmmio; - __u8 __iomem *bmmio; - - /* config info */ - unsigned int board; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - - unsigned int tda9887_conf; - unsigned int gpio_value; - - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; - unsigned char eedata[256]; - int has_rds; - - /* video overlay */ - struct v4l2_framebuffer ovbuf; - struct saa7134_format *ovfmt; - unsigned int ovenable; - enum v4l2_field ovfield; - - /* video+ts+vbi capture */ - struct saa7134_dmaqueue video_q; - struct saa7134_dmaqueue vbi_q; - unsigned int video_fieldcount; - unsigned int vbi_fieldcount; - - /* various v4l controls */ - struct saa7134_tvnorm *tvnorm; /* video */ - struct saa7134_tvaudio *tvaudio; - unsigned int ctl_input; - int ctl_bright; - int ctl_contrast; - int ctl_hue; - int ctl_saturation; - int ctl_freq; - int ctl_mute; /* audio */ - int ctl_volume; - int ctl_invert; /* private */ - int ctl_mirror; - int ctl_y_odd; - int ctl_y_even; - int ctl_automute; - - /* crop */ - struct v4l2_rect crop_bounds; - struct v4l2_rect crop_defrect; - struct v4l2_rect crop_current; - - /* other global state info */ - unsigned int automute; - struct saa7134_thread thread; - struct saa7134_input *input; - struct saa7134_input *hw_input; - unsigned int hw_mute; - int last_carrier; - int nosignal; - unsigned int insuspend; - - /* I2C keyboard data */ - struct IR_i2c_init_data init_data; - - /* SAA7134_MPEG_* */ - struct saa7134_ts ts; - struct saa7134_dmaqueue ts_q; - int ts_started; - struct saa7134_mpeg_ops *mops; - - /* SAA7134_MPEG_EMPRESS only */ - struct video_device *empress_dev; - struct videobuf_queue empress_tsq; - atomic_t empress_users; - struct work_struct empress_workqueue; - int empress_started; - -#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE) - /* SAA7134_MPEG_DVB only */ - struct videobuf_dvb_frontends frontends; - int (*original_demod_sleep)(struct dvb_frontend *fe); - int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); - int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg); -#endif - void (*gate_ctrl)(struct saa7134_dev *dev, int open); -}; - -/* ----------------------------------------------------------- */ - -#define saa_readl(reg) readl(dev->lmmio + (reg)) -#define saa_writel(reg,value) writel((value), dev->lmmio + (reg)); -#define saa_andorl(reg,mask,value) \ - writel((readl(dev->lmmio+(reg)) & ~(mask)) |\ - ((value) & (mask)), dev->lmmio+(reg)) -#define saa_setl(reg,bit) saa_andorl((reg),(bit),(bit)) -#define saa_clearl(reg,bit) saa_andorl((reg),(bit),0) - -#define saa_readb(reg) readb(dev->bmmio + (reg)) -#define saa_writeb(reg,value) writeb((value), dev->bmmio + (reg)); -#define saa_andorb(reg,mask,value) \ - writeb((readb(dev->bmmio+(reg)) & ~(mask)) |\ - ((value) & (mask)), dev->bmmio+(reg)) -#define saa_setb(reg,bit) saa_andorb((reg),(bit),(bit)) -#define saa_clearb(reg,bit) saa_andorb((reg),(bit),0) - -#define saa_wait(us) { udelay(us); } - -#define SAA7134_NORMS (\ - V4L2_STD_PAL | V4L2_STD_PAL_N | \ - V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ - V4L2_STD_NTSC | V4L2_STD_PAL_M | \ - V4L2_STD_PAL_60) - -#define GRP_EMPRESS (1) -#define saa_call_all(dev, o, f, args...) do { \ - if (dev->gate_ctrl) \ - dev->gate_ctrl(dev, 1); \ - v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \ - if (dev->gate_ctrl) \ - dev->gate_ctrl(dev, 0); \ -} while (0) - -#define saa_call_empress(dev, o, f, args...) ({ \ - long _rc; \ - if (dev->gate_ctrl) \ - dev->gate_ctrl(dev, 1); \ - _rc = v4l2_device_call_until_err(&(dev)->v4l2_dev, \ - GRP_EMPRESS, o, f , ##args); \ - if (dev->gate_ctrl) \ - dev->gate_ctrl(dev, 0); \ - _rc; \ -}) - -/* ----------------------------------------------------------- */ -/* saa7134-core.c */ - -extern struct list_head saa7134_devlist; -extern struct mutex saa7134_devlist_lock; -extern int saa7134_no_overlay; - -void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); -void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value); - -#define SAA7134_PGTABLE_SIZE 4096 - -int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt); -int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, - struct scatterlist *list, unsigned int length, - unsigned int startpage); -void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt); - -int saa7134_buffer_count(unsigned int size, unsigned int count); -int saa7134_buffer_startpage(struct saa7134_buf *buf); -unsigned long saa7134_buffer_base(struct saa7134_buf *buf); - -int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, - struct saa7134_buf *buf); -void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, - unsigned int state); -void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); -void saa7134_buffer_timeout(unsigned long data); -void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf); - -int saa7134_set_dmabits(struct saa7134_dev *dev); - -extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev); -extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev); - - -/* ----------------------------------------------------------- */ -/* saa7134-cards.c */ - -extern struct saa7134_board saa7134_boards[]; -extern const unsigned int saa7134_bcount; -extern struct pci_device_id __devinitdata saa7134_pci_tbl[]; - -extern int saa7134_board_init1(struct saa7134_dev *dev); -extern int saa7134_board_init2(struct saa7134_dev *dev); -int saa7134_tuner_callback(void *priv, int component, int command, int arg); - - -/* ----------------------------------------------------------- */ -/* saa7134-i2c.c */ - -int saa7134_i2c_register(struct saa7134_dev *dev); -int saa7134_i2c_unregister(struct saa7134_dev *dev); - - -/* ----------------------------------------------------------- */ -/* saa7134-video.c */ - -extern unsigned int video_debug; -extern struct video_device saa7134_video_template; -extern struct video_device saa7134_radio_template; - -int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); -int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); -int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c); -int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id); - -int saa7134_videoport_init(struct saa7134_dev *dev); -void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); - -int saa7134_video_init1(struct saa7134_dev *dev); -int saa7134_video_init2(struct saa7134_dev *dev); -void saa7134_irq_video_signalchange(struct saa7134_dev *dev); -void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); - - -/* ----------------------------------------------------------- */ -/* saa7134-ts.c */ - -#define TS_PACKET_SIZE 188 /* TS packets 188 bytes */ - -extern struct videobuf_queue_ops saa7134_ts_qops; - -int saa7134_ts_init1(struct saa7134_dev *dev); -int saa7134_ts_fini(struct saa7134_dev *dev); -void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status); - -int saa7134_ts_register(struct saa7134_mpeg_ops *ops); -void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops); - -int saa7134_ts_init_hw(struct saa7134_dev *dev); - -int saa7134_ts_start(struct saa7134_dev *dev); -int saa7134_ts_stop(struct saa7134_dev *dev); - -/* ----------------------------------------------------------- */ -/* saa7134-vbi.c */ - -extern struct videobuf_queue_ops saa7134_vbi_qops; -extern struct video_device saa7134_vbi_template; - -int saa7134_vbi_init1(struct saa7134_dev *dev); -int saa7134_vbi_fini(struct saa7134_dev *dev); -void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status); - - -/* ----------------------------------------------------------- */ -/* saa7134-tvaudio.c */ - -int saa7134_tvaudio_rx2mode(u32 rx); - -void saa7134_tvaudio_setmute(struct saa7134_dev *dev); -void saa7134_tvaudio_setinput(struct saa7134_dev *dev, - struct saa7134_input *in); -void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level); -int saa7134_tvaudio_getstereo(struct saa7134_dev *dev); - -void saa7134_tvaudio_init(struct saa7134_dev *dev); -int saa7134_tvaudio_init2(struct saa7134_dev *dev); -int saa7134_tvaudio_fini(struct saa7134_dev *dev); -int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); - -int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value); - -void saa7134_enable_i2s(struct saa7134_dev *dev); - -/* ----------------------------------------------------------- */ -/* saa7134-oss.c */ - -extern const struct file_operations saa7134_dsp_fops; -extern const struct file_operations saa7134_mixer_fops; - -int saa7134_oss_init1(struct saa7134_dev *dev); -int saa7134_oss_fini(struct saa7134_dev *dev); -void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status); - -/* ----------------------------------------------------------- */ -/* saa7134-input.c */ - -#if defined(CONFIG_VIDEO_SAA7134_RC) -int saa7134_input_init1(struct saa7134_dev *dev); -void saa7134_input_fini(struct saa7134_dev *dev); -void saa7134_input_irq(struct saa7134_dev *dev); -void saa7134_probe_i2c_ir(struct saa7134_dev *dev); -int saa7134_ir_start(struct saa7134_dev *dev); -void saa7134_ir_stop(struct saa7134_dev *dev); -#else -#define saa7134_input_init1(dev) (0) -#define saa7134_input_fini(dev) (0) -#define saa7134_input_irq(dev) (0) -#define saa7134_probe_i2c_ir(dev) (0) -#define saa7134_ir_start(dev) (0) -#define saa7134_ir_stop(dev) (0) -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,423 +0,0 @@ -/* - * - * device driver for philips saa7134 based TV cards - * i2c interface support - * - * (c) 2001,02 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" -#include - -/* ----------------------------------------------------------- */ - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); - -static unsigned int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); - -#define d1printk if (1 == i2c_debug) printk -#define d2printk if (2 == i2c_debug) printk - -#define I2C_WAIT_DELAY 32 -#define I2C_WAIT_RETRY 16 - -/* ----------------------------------------------------------- */ - -static char *str_i2c_status[] = { - "IDLE", "DONE_STOP", "BUSY", "TO_SCL", "TO_ARB", "DONE_WRITE", - "DONE_READ", "DONE_WRITE_TO", "DONE_READ_TO", "NO_DEVICE", - "NO_ACKN", "BUS_ERR", "ARB_LOST", "SEQ_ERR", "ST_ERR", "SW_ERR" -}; - -enum i2c_status { - IDLE = 0, // no I2C command pending - DONE_STOP = 1, // I2C command done and STOP executed - BUSY = 2, // executing I2C command - TO_SCL = 3, // executing I2C command, time out on clock stretching - TO_ARB = 4, // time out on arbitration trial, still trying - DONE_WRITE = 5, // I2C command done and awaiting next write command - DONE_READ = 6, // I2C command done and awaiting next read command - DONE_WRITE_TO = 7, // see 5, and time out on status echo - DONE_READ_TO = 8, // see 6, and time out on status echo - NO_DEVICE = 9, // no acknowledge on device slave address - NO_ACKN = 10, // no acknowledge after data byte transfer - BUS_ERR = 11, // bus error - ARB_LOST = 12, // arbitration lost during transfer - SEQ_ERR = 13, // erroneous programming sequence - ST_ERR = 14, // wrong status echoing - SW_ERR = 15 // software error -}; - -static char *str_i2c_attr[] = { - "NOP", "STOP", "CONTINUE", "START" -}; - -enum i2c_attr { - NOP = 0, // no operation on I2C bus - STOP = 1, // stop condition, no associated byte transfer - CONTINUE = 2, // continue with byte transfer - START = 3 // start condition with byte transfer -}; - -static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev) -{ - enum i2c_status status; - - status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f; - d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name, - str_i2c_status[status]); - return status; -} - -static inline void i2c_set_status(struct saa7134_dev *dev, - enum i2c_status status) -{ - d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name, - str_i2c_status[status]); - saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status); -} - -static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr) -{ - d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name, - str_i2c_attr[attr]); - saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6); -} - -static inline int i2c_is_error(enum i2c_status status) -{ - switch (status) { - case NO_DEVICE: - case NO_ACKN: - case BUS_ERR: - case ARB_LOST: - case SEQ_ERR: - case ST_ERR: - return true; - default: - return false; - } -} - -static inline int i2c_is_idle(enum i2c_status status) -{ - switch (status) { - case IDLE: - case DONE_STOP: - return true; - default: - return false; - } -} - -static inline int i2c_is_busy(enum i2c_status status) -{ - switch (status) { - case BUSY: - case TO_SCL: - case TO_ARB: - return true; - default: - return false; - } -} - -static int i2c_is_busy_wait(struct saa7134_dev *dev) -{ - enum i2c_status status; - int count; - - for (count = 0; count < I2C_WAIT_RETRY; count++) { - status = i2c_get_status(dev); - if (!i2c_is_busy(status)) - break; - saa_wait(I2C_WAIT_DELAY); - } - if (I2C_WAIT_RETRY == count) - return false; - return true; -} - -static int i2c_reset(struct saa7134_dev *dev) -{ - enum i2c_status status; - int count; - - d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name); - status = i2c_get_status(dev); - if (!i2c_is_error(status)) - return true; - i2c_set_status(dev,status); - - for (count = 0; count < I2C_WAIT_RETRY; count++) { - status = i2c_get_status(dev); - if (!i2c_is_error(status)) - break; - udelay(I2C_WAIT_DELAY); - } - if (I2C_WAIT_RETRY == count) - return false; - - if (!i2c_is_idle(status)) - return false; - - i2c_set_attr(dev,NOP); - return true; -} - -static inline int i2c_send_byte(struct saa7134_dev *dev, - enum i2c_attr attr, - unsigned char data) -{ - enum i2c_status status; - __u32 dword; - - /* have to write both attr + data in one 32bit word */ - dword = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2); - dword &= 0x0f; - dword |= (attr << 6); - dword |= ((__u32)data << 8); - dword |= 0x00 << 16; /* 100 kHz */ -// dword |= 0x40 << 16; /* 400 kHz */ - dword |= 0xf0 << 24; - saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); - d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data); - - if (!i2c_is_busy_wait(dev)) - return -EIO; - status = i2c_get_status(dev); - if (i2c_is_error(status)) - return -EIO; - return 0; -} - -static inline int i2c_recv_byte(struct saa7134_dev *dev) -{ - enum i2c_status status; - unsigned char data; - - i2c_set_attr(dev,CONTINUE); - if (!i2c_is_busy_wait(dev)) - return -EIO; - status = i2c_get_status(dev); - if (i2c_is_error(status)) - return -EIO; - data = saa_readb(SAA7134_I2C_DATA); - d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data); - return data; -} - -static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, int num) -{ - struct saa7134_dev *dev = i2c_adap->algo_data; - enum i2c_status status; - unsigned char data; - int addr,rc,i,byte; - - status = i2c_get_status(dev); - if (!i2c_is_idle(status)) - if (!i2c_reset(dev)) - return -EIO; - - d2printk("start xfer\n"); - d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name); - for (i = 0; i < num; i++) { - if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) { - /* send address */ - d2printk("send address\n"); - addr = msgs[i].addr << 1; - if (msgs[i].flags & I2C_M_RD) - addr |= 1; - if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) { - /* workaround for a saa7134 i2c bug - * needed to talk to the mt352 demux - * thanks to pinnacle for the hint */ - int quirk = 0xfe; - d1printk(" [%02x quirk]",quirk); - i2c_send_byte(dev,START,quirk); - i2c_recv_byte(dev); - } - d1printk(" < %02x", addr); - rc = i2c_send_byte(dev,START,addr); - if (rc < 0) - goto err; - } - if (msgs[i].flags & I2C_M_RD) { - /* read bytes */ - d2printk("read bytes\n"); - for (byte = 0; byte < msgs[i].len; byte++) { - d1printk(" ="); - rc = i2c_recv_byte(dev); - if (rc < 0) - goto err; - d1printk("%02x", rc); - msgs[i].buf[byte] = rc; - } - } else { - /* write bytes */ - d2printk("write bytes\n"); - for (byte = 0; byte < msgs[i].len; byte++) { - data = msgs[i].buf[byte]; - d1printk(" %02x", data); - rc = i2c_send_byte(dev,CONTINUE,data); - if (rc < 0) - goto err; - } - } - } - d2printk("xfer done\n"); - d1printk(" >"); - i2c_set_attr(dev,STOP); - rc = -EIO; - if (!i2c_is_busy_wait(dev)) - goto err; - status = i2c_get_status(dev); - if (i2c_is_error(status)) - goto err; - /* ensure that the bus is idle for at least one bit slot */ - msleep(1); - - d1printk("\n"); - return num; - err: - if (1 == i2c_debug) { - status = i2c_get_status(dev); - printk(" ERROR: %s\n",str_i2c_status[status]); - } - return rc; -} - -/* ----------------------------------------------------------- */ - -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm saa7134_algo = { - .master_xfer = saa7134_i2c_xfer, - .functionality = functionality, -}; - -static struct i2c_adapter saa7134_adap_template = { - .owner = THIS_MODULE, - .name = "saa7134", - .algo = &saa7134_algo, -}; - -static struct i2c_client saa7134_client_template = { - .name = "saa7134 internal", -}; - -/* ----------------------------------------------------------- */ - -static int -saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len) -{ - unsigned char buf; - int i,err; - - dev->i2c_client.addr = 0xa0 >> 1; - buf = 0; - if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) { - printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", - dev->name,err); - return -1; - } - if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) { - printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", - dev->name,err); - return -1; - } - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:",dev->name,i); - printk(" %02x",eedata[i]); - if (15 == (i % 16)) - printk("\n"); - } - return 0; -} - -static char *i2c_devs[128] = { - [ 0x20 ] = "mpeg encoder (saa6752hs)", - [ 0xa0 >> 1 ] = "eeprom", - [ 0xc0 >> 1 ] = "tuner (analog)", - [ 0x86 >> 1 ] = "tda9887", - [ 0x5a >> 1 ] = "remote control", -}; - -static void do_i2c_scan(char *name, struct i2c_client *c) -{ - unsigned char buf; - int i,rc; - - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - c->addr = i; - rc = i2c_master_recv(c,&buf,0); - if (rc < 0) - continue; - printk("%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); - } -} - -int saa7134_i2c_register(struct saa7134_dev *dev) -{ - dev->i2c_adap = saa7134_adap_template; - dev->i2c_adap.dev.parent = &dev->pci->dev; - strcpy(dev->i2c_adap.name,dev->name); - dev->i2c_adap.algo_data = dev; - i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); - i2c_add_adapter(&dev->i2c_adap); - - dev->i2c_client = saa7134_client_template; - dev->i2c_client.adapter = &dev->i2c_adap; - - saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata)); - if (i2c_scan) - do_i2c_scan(dev->name,&dev->i2c_client); - - /* Instantiate the IR receiver device, if present */ - saa7134_probe_i2c_ir(dev); - return 0; -} - -int saa7134_i2c_unregister(struct saa7134_dev *dev) -{ - i2c_del_adapter(&dev->i2c_adap); - return 0; -} - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-input.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-input.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,964 +0,0 @@ -/* - * - * handle saa7134 IR remotes via linux kernel input layer. - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" - -#define MODULE_NAME "saa7134" - -static unsigned int disable_ir; -module_param(disable_ir, int, 0444); -MODULE_PARM_DESC(disable_ir,"disable infrared remote support"); - -static unsigned int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); - -static int pinnacle_remote; -module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */ -MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)"); - -#define dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) -#define i2cdprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg) - -/* Helper function for raw decoding at GPIO16 or GPIO18 */ -static int saa7134_raw_decode_irq(struct saa7134_dev *dev); - -/* -------------------- GPIO generic keycode builder -------------------- */ - -static int build_key(struct saa7134_dev *dev) -{ - struct saa7134_card_ir *ir = dev->remote; - u32 gpio, data; - - /* here comes the additional handshake steps for some cards */ - switch (dev->board) { - case SAA7134_BOARD_GOTVIEW_7135: - saa_setb(SAA7134_GPIO_GPSTATUS1, 0x80); - saa_clearb(SAA7134_GPIO_GPSTATUS1, 0x80); - break; - } - /* rising SAA7134_GPIO_GPRESCAN reads the status */ - saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN); - - gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - if (ir->polling) { - if (ir->last_gpio == gpio) - return 0; - ir->last_gpio = gpio; - } - - data = ir_extract_bits(gpio, ir->mask_keycode); - dprintk("build_key gpio=0x%x mask=0x%x data=%d\n", - gpio, ir->mask_keycode, data); - - switch (dev->board) { - case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG: - if (data == ir->mask_keycode) - rc_keyup(ir->dev); - else - rc_keydown_notimeout(ir->dev, data, 0); - return 0; - } - - if (ir->polling) { - if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || - (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { - rc_keydown_notimeout(ir->dev, data, 0); - } else { - rc_keyup(ir->dev); - } - } - else { /* IRQ driven mode - handle key press and release in one go */ - if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || - (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { - rc_keydown_notimeout(ir->dev, data, 0); - rc_keyup(ir->dev); - } - } - - return 0; -} - -/* --------------------- Chip specific I2C key builders ----------------- */ - -static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - int gpio; - int attempt = 0; - unsigned char b; - - /* We need this to access GPI Used by the saa_readl macro. */ - struct saa7134_dev *dev = ir->c->adapter->algo_data; - - if (dev == NULL) { - i2cdprintk("get_key_flydvb_trio: " - "ir->c->adapter->algo_data is NULL!\n"); - return -EIO; - } - - /* rising SAA7134_GPIGPRESCAN reads the status */ - saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - - gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - - if (0x40000 & ~gpio) - return 0; /* No button press */ - - /* No button press - only before first key pressed */ - if (b == 0xFF) - return 0; - - /* poll IR chip */ - /* weak up the IR chip */ - b = 0; - - while (1 != i2c_master_send(ir->c, &b, 1)) { - if ((attempt++) < 10) { - /* - * wait a bit for next attempt - - * I don't know how make it better - */ - msleep(10); - continue; - } - i2cdprintk("send wake up byte to pic16C505 (IR chip)" - "failed %dx\n", attempt); - return -EIO; - } - if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); - return -EIO; - } - - *ir_key = b; - *ir_raw = b; - return 1; -} - -static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, - u32 *ir_raw) -{ - unsigned char b; - int gpio; - - /* is needed to access GPIO. Used by the saa_readl macro. */ - struct saa7134_dev *dev = ir->c->adapter->algo_data; - if (dev == NULL) { - i2cdprintk("get_key_msi_tvanywhere_plus: " - "ir->c->adapter->algo_data is NULL!\n"); - return -EIO; - } - - /* rising SAA7134_GPIO_GPRESCAN reads the status */ - - saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - - gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - - /* GPIO&0x40 is pulsed low when a button is pressed. Don't do - I2C receive if gpio&0x40 is not low. */ - - if (gpio & 0x40) - return 0; /* No button press */ - - /* GPIO says there is a button press. Get it. */ - - if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); - return -EIO; - } - - /* No button press */ - - if (b == 0xff) - return 0; - - /* Button pressed */ - - dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b); - *ir_key = b; - *ir_raw = b; - return 1; -} - -static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char b; - - /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); - return -EIO; - } - - /* no button press */ - if (b==0) - return 0; - - /* repeating */ - if (b & 0x80) - return 1; - - *ir_key = b; - *ir_raw = b; - return 1; -} - -static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char buf[5], cod4, code3, code4; - - /* poll IR chip */ - if (5 != i2c_master_recv(ir->c, buf, 5)) - return -EIO; - - cod4 = buf[4]; - code4 = (cod4 >> 2); - code3 = buf[3]; - if (code3 == 0) - /* no key pressed */ - return 0; - - /* return key */ - *ir_key = code4; - *ir_raw = code4; - return 1; -} - - -static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char data[12]; - u32 gpio; - - struct saa7134_dev *dev = ir->c->adapter->algo_data; - - /* rising SAA7134_GPIO_GPRESCAN reads the status */ - saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - - gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - - if (0x400000 & ~gpio) - return 0; /* No button press */ - - ir->c->addr = 0x5a >> 1; - - if (12 != i2c_master_recv(ir->c, data, 12)) { - i2cdprintk("read error\n"); - return -EIO; - } - - if (data[9] != (unsigned char)(~data[8])) - return 0; - - *ir_raw = ((data[10] << 16) | (data[11] << 8) | (data[9] << 0)); - *ir_key = *ir_raw; - - return 1; -} - -/* Common (grey or coloured) pinnacle PCTV remote handling - * - */ -static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, - int parity_offset, int marker, int code_modulo) -{ - unsigned char b[4]; - unsigned int start = 0,parity = 0,code = 0; - - /* poll IR chip */ - if (4 != i2c_master_recv(ir->c, b, 4)) { - i2cdprintk("read error\n"); - return -EIO; - } - - for (start = 0; start < ARRAY_SIZE(b); start++) { - if (b[start] == marker) { - code=b[(start+parity_offset + 1) % 4]; - parity=b[(start+parity_offset) % 4]; - } - } - - /* Empty Request */ - if (parity == 0) - return 0; - - /* Repeating... */ - if (ir->old == parity) - return 0; - - ir->old = parity; - - /* drop special codes when a key is held down a long time for the grey controller - In this case, the second bit of the code is asserted */ - if (marker == 0xfe && (code & 0x40)) - return 0; - - code %= code_modulo; - - *ir_raw = code; - *ir_key = code; - - i2cdprintk("Pinnacle PCTV key %02x\n", code); - - return 1; -} - -/* The grey pinnacle PCTV remote - * - * There are one issue with this remote: - * - I2c packet does not change when the same key is pressed quickly. The workaround - * is to hold down each key for about half a second, so that another code is generated - * in the i2c packet, and the function can distinguish key presses. - * - * Sylvain Pasche - */ -static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - - return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff); -} - - -/* The new pinnacle PCTV remote (with the colored buttons) - * - * Ricardo Cerqueira - */ -static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE - * - * this is the only value that results in 42 unique - * codes < 128 - */ - - return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88); -} - -void saa7134_input_irq(struct saa7134_dev *dev) -{ - struct saa7134_card_ir *ir; - - if (!dev || !dev->remote) - return; - - ir = dev->remote; - if (!ir->running) - return; - - if (!ir->polling && !ir->raw_decode) { - build_key(dev); - } else if (ir->raw_decode) { - saa7134_raw_decode_irq(dev); - } -} - -static void saa7134_input_timer(unsigned long data) -{ - struct saa7134_dev *dev = (struct saa7134_dev *)data; - struct saa7134_card_ir *ir = dev->remote; - - build_key(dev); - mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); -} - -static void ir_raw_decode_timer_end(unsigned long data) -{ - struct saa7134_dev *dev = (struct saa7134_dev *)data; - struct saa7134_card_ir *ir = dev->remote; - - ir_raw_event_handle(dev->remote->dev); - - ir->active = false; -} - -static int __saa7134_ir_start(void *priv) -{ - struct saa7134_dev *dev = priv; - struct saa7134_card_ir *ir; - - if (!dev || !dev->remote) - return -EINVAL; - - ir = dev->remote; - if (ir->running) - return 0; - - /* Moved here from saa7134_input_init1() because the latter - * is not called on device resume */ - switch (dev->board) { - case SAA7134_BOARD_MD2819: - case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: - case SAA7134_BOARD_AVERMEDIA_305: - case SAA7134_BOARD_AVERMEDIA_307: - case SAA7134_BOARD_AVERMEDIA_STUDIO_305: - case SAA7134_BOARD_AVERMEDIA_STUDIO_505: - case SAA7134_BOARD_AVERMEDIA_STUDIO_307: - case SAA7134_BOARD_AVERMEDIA_STUDIO_507: - case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA: - case SAA7134_BOARD_AVERMEDIA_GO_007_FM: - case SAA7134_BOARD_AVERMEDIA_M102: - case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS: - /* Without this we won't receive key up events */ - saa_setb(SAA7134_GPIO_GPMODE0, 0x4); - saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); - break; - case SAA7134_BOARD_AVERMEDIA_777: - case SAA7134_BOARD_AVERMEDIA_A16AR: - /* Without this we won't receive key up events */ - saa_setb(SAA7134_GPIO_GPMODE1, 0x1); - saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); - break; - case SAA7134_BOARD_AVERMEDIA_A16D: - /* Without this we won't receive key up events */ - saa_setb(SAA7134_GPIO_GPMODE1, 0x1); - saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); - break; - case SAA7134_BOARD_GOTVIEW_7135: - saa_setb(SAA7134_GPIO_GPMODE1, 0x80); - break; - } - - ir->running = true; - ir->active = false; - - if (ir->polling) { - setup_timer(&ir->timer, saa7134_input_timer, - (unsigned long)dev); - ir->timer.expires = jiffies + HZ; - add_timer(&ir->timer); - } else if (ir->raw_decode) { - /* set timer_end for code completion */ - setup_timer(&ir->timer, ir_raw_decode_timer_end, - (unsigned long)dev); - } - - return 0; -} - -static void __saa7134_ir_stop(void *priv) -{ - struct saa7134_dev *dev = priv; - struct saa7134_card_ir *ir; - - if (!dev || !dev->remote) - return; - - ir = dev->remote; - if (!ir->running) - return; - - if (ir->polling || ir->raw_decode) - del_timer_sync(&ir->timer); - - ir->active = false; - ir->running = false; - - return; -} - -int saa7134_ir_start(struct saa7134_dev *dev) -{ - if (dev->remote->users) - return __saa7134_ir_start(dev); - - return 0; -} - -void saa7134_ir_stop(struct saa7134_dev *dev) -{ - if (dev->remote->users) - __saa7134_ir_stop(dev); -} - -static int saa7134_ir_open(struct rc_dev *rc) -{ - struct saa7134_dev *dev = rc->priv; - - dev->remote->users++; - return __saa7134_ir_start(dev); -} - -static void saa7134_ir_close(struct rc_dev *rc) -{ - struct saa7134_dev *dev = rc->priv; - - dev->remote->users--; - if (!dev->remote->users) - __saa7134_ir_stop(dev); -} - -int saa7134_input_init1(struct saa7134_dev *dev) -{ - struct saa7134_card_ir *ir; - struct rc_dev *rc; - char *ir_codes = NULL; - u32 mask_keycode = 0; - u32 mask_keydown = 0; - u32 mask_keyup = 0; - unsigned polling = 0; - bool raw_decode = false; - int err; - - if (dev->has_remote != SAA7134_REMOTE_GPIO) - return -ENODEV; - if (disable_ir) - return -ENODEV; - - /* detect & configure */ - switch (dev->board) { - case SAA7134_BOARD_FLYVIDEO2000: - case SAA7134_BOARD_FLYVIDEO3000: - case SAA7134_BOARD_FLYTVPLATINUM_FM: - case SAA7134_BOARD_FLYTVPLATINUM_MINI2: - case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM: - ir_codes = RC_MAP_FLYVIDEO; - mask_keycode = 0xEC00000; - mask_keydown = 0x0040000; - break; - case SAA7134_BOARD_CINERGY400: - case SAA7134_BOARD_CINERGY600: - case SAA7134_BOARD_CINERGY600_MK3: - ir_codes = RC_MAP_CINERGY; - mask_keycode = 0x00003f; - mask_keyup = 0x040000; - break; - case SAA7134_BOARD_ECS_TVP3XP: - case SAA7134_BOARD_ECS_TVP3XP_4CB5: - ir_codes = RC_MAP_EZTV; - mask_keycode = 0x00017c; - mask_keyup = 0x000002; - polling = 50; // ms - break; - case SAA7134_BOARD_KWORLD_XPERT: - case SAA7134_BOARD_AVACSSMARTTV: - ir_codes = RC_MAP_PIXELVIEW; - mask_keycode = 0x00001F; - mask_keyup = 0x000020; - polling = 50; // ms - break; - case SAA7134_BOARD_MD2819: - case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: - case SAA7134_BOARD_AVERMEDIA_305: - case SAA7134_BOARD_AVERMEDIA_307: - case SAA7134_BOARD_AVERMEDIA_STUDIO_305: - case SAA7134_BOARD_AVERMEDIA_STUDIO_505: - case SAA7134_BOARD_AVERMEDIA_STUDIO_307: - case SAA7134_BOARD_AVERMEDIA_STUDIO_507: - case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA: - case SAA7134_BOARD_AVERMEDIA_GO_007_FM: - case SAA7134_BOARD_AVERMEDIA_M102: - case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS: - ir_codes = RC_MAP_AVERMEDIA; - mask_keycode = 0x0007C8; - mask_keydown = 0x000010; - polling = 50; // ms - /* GPIO stuff moved to __saa7134_ir_start() */ - break; - case SAA7134_BOARD_AVERMEDIA_M135A: - ir_codes = RC_MAP_AVERMEDIA_M135A; - mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */ - mask_keyup = 0x0040000; - mask_keycode = 0xffff; - raw_decode = true; - break; - case SAA7134_BOARD_AVERMEDIA_M733A: - ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6; - mask_keydown = 0x0040000; - mask_keyup = 0x0040000; - mask_keycode = 0xffff; - raw_decode = true; - break; - case SAA7134_BOARD_AVERMEDIA_777: - case SAA7134_BOARD_AVERMEDIA_A16AR: - ir_codes = RC_MAP_AVERMEDIA; - mask_keycode = 0x02F200; - mask_keydown = 0x000400; - polling = 50; // ms - /* GPIO stuff moved to __saa7134_ir_start() */ - break; - case SAA7134_BOARD_AVERMEDIA_A16D: - ir_codes = RC_MAP_AVERMEDIA_A16D; - mask_keycode = 0x02F200; - mask_keydown = 0x000400; - polling = 50; /* ms */ - /* GPIO stuff moved to __saa7134_ir_start() */ - break; - case SAA7134_BOARD_KWORLD_TERMINATOR: - ir_codes = RC_MAP_PIXELVIEW; - mask_keycode = 0x00001f; - mask_keyup = 0x000060; - polling = 50; // ms - break; - case SAA7134_BOARD_MANLI_MTV001: - case SAA7134_BOARD_MANLI_MTV002: - ir_codes = RC_MAP_MANLI; - mask_keycode = 0x001f00; - mask_keyup = 0x004000; - polling = 50; /* ms */ - break; - case SAA7134_BOARD_BEHOLD_409FM: - case SAA7134_BOARD_BEHOLD_401: - case SAA7134_BOARD_BEHOLD_403: - case SAA7134_BOARD_BEHOLD_403FM: - case SAA7134_BOARD_BEHOLD_405: - case SAA7134_BOARD_BEHOLD_405FM: - case SAA7134_BOARD_BEHOLD_407: - case SAA7134_BOARD_BEHOLD_407FM: - case SAA7134_BOARD_BEHOLD_409: - case SAA7134_BOARD_BEHOLD_505FM: - case SAA7134_BOARD_BEHOLD_505RDS_MK5: - case SAA7134_BOARD_BEHOLD_505RDS_MK3: - case SAA7134_BOARD_BEHOLD_507_9FM: - case SAA7134_BOARD_BEHOLD_507RDS_MK3: - case SAA7134_BOARD_BEHOLD_507RDS_MK5: - ir_codes = RC_MAP_MANLI; - mask_keycode = 0x003f00; - mask_keyup = 0x004000; - polling = 50; /* ms */ - break; - case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: - ir_codes = RC_MAP_BEHOLD_COLUMBUS; - mask_keycode = 0x003f00; - mask_keyup = 0x004000; - polling = 50; // ms - break; - case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: - ir_codes = RC_MAP_PCTV_SEDNA; - mask_keycode = 0x001f00; - mask_keyup = 0x004000; - polling = 50; // ms - break; - case SAA7134_BOARD_GOTVIEW_7135: - ir_codes = RC_MAP_GOTVIEW7135; - mask_keycode = 0x0003CC; - mask_keydown = 0x000010; - polling = 5; /* ms */ - /* GPIO stuff moved to __saa7134_ir_start() */ - break; - case SAA7134_BOARD_VIDEOMATE_TV_PVR: - case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS: - case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: - ir_codes = RC_MAP_VIDEOMATE_TV_PVR; - mask_keycode = 0x00003F; - mask_keyup = 0x400000; - polling = 50; // ms - break; - case SAA7134_BOARD_PROTEUS_2309: - ir_codes = RC_MAP_PROTEUS_2309; - mask_keycode = 0x00007F; - mask_keyup = 0x000080; - polling = 50; // ms - break; - case SAA7134_BOARD_VIDEOMATE_DVBT_300: - case SAA7134_BOARD_VIDEOMATE_DVBT_200: - ir_codes = RC_MAP_VIDEOMATE_TV_PVR; - mask_keycode = 0x003F00; - mask_keyup = 0x040000; - break; - case SAA7134_BOARD_FLYDVBS_LR300: - case SAA7134_BOARD_FLYDVBT_LR301: - case SAA7134_BOARD_FLYDVBTDUO: - ir_codes = RC_MAP_FLYDVB; - mask_keycode = 0x0001F00; - mask_keydown = 0x0040000; - break; - case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: - case SAA7134_BOARD_ASUSTeK_P7131_ANALOG: - ir_codes = RC_MAP_ASUS_PC39; - mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */ - mask_keyup = 0x0040000; - mask_keycode = 0xffff; - raw_decode = true; - break; - case SAA7134_BOARD_ENCORE_ENLTV: - case SAA7134_BOARD_ENCORE_ENLTV_FM: - ir_codes = RC_MAP_ENCORE_ENLTV; - mask_keycode = 0x00007f; - mask_keyup = 0x040000; - polling = 50; // ms - break; - case SAA7134_BOARD_ENCORE_ENLTV_FM53: - case SAA7134_BOARD_ENCORE_ENLTV_FM3: - ir_codes = RC_MAP_ENCORE_ENLTV_FM53; - mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */ - mask_keyup = 0x0040000; - mask_keycode = 0xffff; - raw_decode = true; - break; - case SAA7134_BOARD_10MOONSTVMASTER3: - ir_codes = RC_MAP_ENCORE_ENLTV; - mask_keycode = 0x5f80000; - mask_keyup = 0x8000000; - polling = 50; //ms - break; - case SAA7134_BOARD_GENIUS_TVGO_A11MCE: - ir_codes = RC_MAP_GENIUS_TVGO_A11MCE; - mask_keycode = 0xff; - mask_keydown = 0xf00000; - polling = 50; /* ms */ - break; - case SAA7134_BOARD_REAL_ANGEL_220: - ir_codes = RC_MAP_REAL_AUDIO_220_32_KEYS; - mask_keycode = 0x3f00; - mask_keyup = 0x4000; - polling = 50; /* ms */ - break; - case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG: - ir_codes = RC_MAP_KWORLD_PLUS_TV_ANALOG; - mask_keycode = 0x7f; - polling = 40; /* ms */ - break; - case SAA7134_BOARD_VIDEOMATE_S350: - ir_codes = RC_MAP_VIDEOMATE_S350; - mask_keycode = 0x003f00; - mask_keydown = 0x040000; - break; - case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S: - ir_codes = RC_MAP_WINFAST; - mask_keycode = 0x5f00; - mask_keyup = 0x020000; - polling = 50; /* ms */ - break; - case SAA7134_BOARD_VIDEOMATE_M1F: - ir_codes = RC_MAP_VIDEOMATE_M1F; - mask_keycode = 0x0ff00; - mask_keyup = 0x040000; - break; - } - if (NULL == ir_codes) { - printk("%s: Oops: IR config error [card=%d]\n", - dev->name, dev->board); - return -ENODEV; - } - - ir = kzalloc(sizeof(*ir), GFP_KERNEL); - rc = rc_allocate_device(); - if (!ir || !rc) { - err = -ENOMEM; - goto err_out_free; - } - - ir->dev = rc; - dev->remote = ir; - - /* init hardware-specific stuff */ - ir->mask_keycode = mask_keycode; - ir->mask_keydown = mask_keydown; - ir->mask_keyup = mask_keyup; - ir->polling = polling; - ir->raw_decode = raw_decode; - - /* init input device */ - snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)", - saa7134_boards[dev->board].name); - snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", - pci_name(dev->pci)); - - rc->priv = dev; - rc->open = saa7134_ir_open; - rc->close = saa7134_ir_close; - if (raw_decode) - rc->driver_type = RC_DRIVER_IR_RAW; - - rc->input_name = ir->name; - rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_PCI; - rc->input_id.version = 1; - if (dev->pci->subsystem_vendor) { - rc->input_id.vendor = dev->pci->subsystem_vendor; - rc->input_id.product = dev->pci->subsystem_device; - } else { - rc->input_id.vendor = dev->pci->vendor; - rc->input_id.product = dev->pci->device; - } - rc->dev.parent = &dev->pci->dev; - rc->map_name = ir_codes; - rc->driver_name = MODULE_NAME; - - err = rc_register_device(rc); - if (err) - goto err_out_free; - - return 0; - -err_out_free: - rc_free_device(rc); - dev->remote = NULL; - kfree(ir); - return err; -} - -void saa7134_input_fini(struct saa7134_dev *dev) -{ - if (NULL == dev->remote) - return; - - saa7134_ir_stop(dev); - rc_unregister_device(dev->remote->dev); - kfree(dev->remote); - dev->remote = NULL; -} - -void saa7134_probe_i2c_ir(struct saa7134_dev *dev) -{ - struct i2c_board_info info; - struct i2c_msg msg_msi = { - .addr = 0x50, - .flags = I2C_M_RD, - .len = 0, - .buf = NULL, - }; - int rc; - - if (disable_ir) { - dprintk("IR has been disabled, not probing for i2c remote\n"); - return; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - memset(&dev->init_data, 0, sizeof(dev->init_data)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - - switch (dev->board) { - case SAA7134_BOARD_PINNACLE_PCTV_110i: - case SAA7134_BOARD_PINNACLE_PCTV_310i: - dev->init_data.name = "Pinnacle PCTV"; - if (pinnacle_remote == 0) { - dev->init_data.get_key = get_key_pinnacle_color; - dev->init_data.ir_codes = RC_MAP_PINNACLE_COLOR; - info.addr = 0x47; - } else { - dev->init_data.get_key = get_key_pinnacle_grey; - dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY; - info.addr = 0x47; - } - break; - case SAA7134_BOARD_UPMOST_PURPLE_TV: - dev->init_data.name = "Purple TV"; - dev->init_data.get_key = get_key_purpletv; - dev->init_data.ir_codes = RC_MAP_PURPLETV; - info.addr = 0x7a; - break; - case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: - dev->init_data.name = "MSI TV@nywhere Plus"; - dev->init_data.get_key = get_key_msi_tvanywhere_plus; - dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS; - /* - * MSI TV@nyware Plus requires more frequent polling - * otherwise it will miss some keypresses - */ - dev->init_data.polling_interval = 50; - info.addr = 0x30; - /* MSI TV@nywhere Plus controller doesn't seem to - respond to probes unless we read something from - an existing device. Weird... - REVISIT: might no longer be needed */ - rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); - dprintk("probe 0x%02x @ %s: %s\n", - msg_msi.addr, dev->i2c_adap.name, - (1 == rc) ? "yes" : "no"); - break; - case SAA7134_BOARD_HAUPPAUGE_HVR1110: - dev->init_data.name = "HVR 1110"; - dev->init_data.get_key = get_key_hvr1110; - dev->init_data.ir_codes = RC_MAP_HAUPPAUGE; - info.addr = 0x71; - break; - case SAA7134_BOARD_BEHOLD_607FM_MK3: - case SAA7134_BOARD_BEHOLD_607FM_MK5: - case SAA7134_BOARD_BEHOLD_609FM_MK3: - case SAA7134_BOARD_BEHOLD_609FM_MK5: - case SAA7134_BOARD_BEHOLD_607RDS_MK3: - case SAA7134_BOARD_BEHOLD_607RDS_MK5: - case SAA7134_BOARD_BEHOLD_609RDS_MK3: - case SAA7134_BOARD_BEHOLD_609RDS_MK5: - case SAA7134_BOARD_BEHOLD_M6: - case SAA7134_BOARD_BEHOLD_M63: - case SAA7134_BOARD_BEHOLD_M6_EXTRA: - case SAA7134_BOARD_BEHOLD_H6: - case SAA7134_BOARD_BEHOLD_X7: - case SAA7134_BOARD_BEHOLD_H7: - case SAA7134_BOARD_BEHOLD_A7: - dev->init_data.name = "BeholdTV"; - dev->init_data.get_key = get_key_beholdm6xx; - dev->init_data.ir_codes = RC_MAP_BEHOLD; - dev->init_data.type = RC_TYPE_NEC; - info.addr = 0x2d; - break; - case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: - case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: - info.addr = 0x40; - break; - case SAA7134_BOARD_FLYDVB_TRIO: - dev->init_data.name = "FlyDVB Trio"; - dev->init_data.get_key = get_key_flydvb_trio; - dev->init_data.ir_codes = RC_MAP_FLYDVB; - info.addr = 0x0b; - break; - default: - dprintk("No I2C IR support for board %x\n", dev->board); - return; - } - - if (dev->init_data.name) - info.platform_data = &dev->init_data; - i2c_new_device(&dev->i2c_adap, &info); -} - -static int saa7134_raw_decode_irq(struct saa7134_dev *dev) -{ - struct saa7134_card_ir *ir = dev->remote; - unsigned long timeout; - int space; - - /* Generate initial event */ - saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown; - ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE); - - /* - * Wait 15 ms from the start of the first IR event before processing - * the event. This time is enough for NEC protocol. May need adjustments - * to work with other protocols. - */ - if (!ir->active) { - timeout = jiffies + jiffies_to_msecs(15); - mod_timer(&ir->timer, timeout); - ir->active = true; - } - - return 1; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,378 +0,0 @@ -/* - * - * philips saa7134 registers - */ - -/* ------------------------------------------------------------------ */ -/* - * PCI ID's - */ -#ifndef PCI_DEVICE_ID_PHILIPS_SAA7130 -# define PCI_DEVICE_ID_PHILIPS_SAA7130 0x7130 -#endif -#ifndef PCI_DEVICE_ID_PHILIPS_SAA7133 -# define PCI_DEVICE_ID_PHILIPS_SAA7133 0x7133 -#endif -#ifndef PCI_DEVICE_ID_PHILIPS_SAA7134 -# define PCI_DEVICE_ID_PHILIPS_SAA7134 0x7134 -#endif -#ifndef PCI_DEVICE_ID_PHILIPS_SAA7135 -# define PCI_DEVICE_ID_PHILIPS_SAA7135 0x7135 -#endif - -/* ------------------------------------------------------------------ */ -/* - * registers -- 32 bit - */ - -/* DMA channels, n = 0 ... 6 */ -#define SAA7134_RS_BA1(n) ((0x200 >> 2) + 4*n) -#define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n) -#define SAA7134_RS_PITCH(n) ((0x208 >> 2) + 4*n) -#define SAA7134_RS_CONTROL(n) ((0x20c >> 2) + 4*n) -#define SAA7134_RS_CONTROL_WSWAP (0x01 << 25) -#define SAA7134_RS_CONTROL_BSWAP (0x01 << 24) -#define SAA7134_RS_CONTROL_BURST_2 (0x01 << 21) -#define SAA7134_RS_CONTROL_BURST_4 (0x02 << 21) -#define SAA7134_RS_CONTROL_BURST_8 (0x03 << 21) -#define SAA7134_RS_CONTROL_BURST_16 (0x04 << 21) -#define SAA7134_RS_CONTROL_BURST_32 (0x05 << 21) -#define SAA7134_RS_CONTROL_BURST_64 (0x06 << 21) -#define SAA7134_RS_CONTROL_BURST_MAX (0x07 << 21) -#define SAA7134_RS_CONTROL_ME (0x01 << 20) -#define SAA7134_FIFO_SIZE (0x2a0 >> 2) -#define SAA7134_THRESHOULD (0x2a4 >> 2) - -#define SAA7133_NUM_SAMPLES (0x588 >> 2) -#define SAA7133_AUDIO_CHANNEL (0x58c >> 2) -#define SAA7133_AUDIO_FORMAT (0x58f >> 2) -#define SAA7133_DIGITAL_OUTPUT_SEL1 (0x46c >> 2) -#define SAA7133_DIGITAL_OUTPUT_SEL2 (0x470 >> 2) -#define SAA7133_DIGITAL_INPUT_XBAR1 (0x464 >> 2) -#define SAA7133_ANALOG_IO_SELECT (0x594 >> 2) - -/* main control */ -#define SAA7134_MAIN_CTRL (0x2a8 >> 2) -#define SAA7134_MAIN_CTRL_VPLLE (1 << 15) -#define SAA7134_MAIN_CTRL_APLLE (1 << 14) -#define SAA7134_MAIN_CTRL_EXOSC (1 << 13) -#define SAA7134_MAIN_CTRL_EVFE1 (1 << 12) -#define SAA7134_MAIN_CTRL_EVFE2 (1 << 11) -#define SAA7134_MAIN_CTRL_ESFE (1 << 10) -#define SAA7134_MAIN_CTRL_EBADC (1 << 9) -#define SAA7134_MAIN_CTRL_EBDAC (1 << 8) -#define SAA7134_MAIN_CTRL_TE6 (1 << 6) -#define SAA7134_MAIN_CTRL_TE5 (1 << 5) -#define SAA7134_MAIN_CTRL_TE4 (1 << 4) -#define SAA7134_MAIN_CTRL_TE3 (1 << 3) -#define SAA7134_MAIN_CTRL_TE2 (1 << 2) -#define SAA7134_MAIN_CTRL_TE1 (1 << 1) -#define SAA7134_MAIN_CTRL_TE0 (1 << 0) - -/* DMA status */ -#define SAA7134_DMA_STATUS (0x2ac >> 2) - -/* audio / video status */ -#define SAA7134_AV_STATUS (0x2c0 >> 2) -#define SAA7134_AV_STATUS_STEREO (1 << 17) -#define SAA7134_AV_STATUS_DUAL (1 << 16) -#define SAA7134_AV_STATUS_PILOT (1 << 15) -#define SAA7134_AV_STATUS_SMB (1 << 14) -#define SAA7134_AV_STATUS_DMB (1 << 13) -#define SAA7134_AV_STATUS_VDSP (1 << 12) -#define SAA7134_AV_STATUS_IIC_STATUS (3 << 10) -#define SAA7134_AV_STATUS_MVM (7 << 7) -#define SAA7134_AV_STATUS_FIDT (1 << 6) -#define SAA7134_AV_STATUS_INTL (1 << 5) -#define SAA7134_AV_STATUS_RDCAP (1 << 4) -#define SAA7134_AV_STATUS_PWR_ON (1 << 3) -#define SAA7134_AV_STATUS_LOAD_ERR (1 << 2) -#define SAA7134_AV_STATUS_TRIG_ERR (1 << 1) -#define SAA7134_AV_STATUS_CONF_ERR (1 << 0) - -/* interrupt */ -#define SAA7134_IRQ1 (0x2c4 >> 2) -#define SAA7134_IRQ1_INTE_RA3_1 (1 << 25) -#define SAA7134_IRQ1_INTE_RA3_0 (1 << 24) -#define SAA7134_IRQ1_INTE_RA2_3 (1 << 19) -#define SAA7134_IRQ1_INTE_RA2_2 (1 << 18) -#define SAA7134_IRQ1_INTE_RA2_1 (1 << 17) -#define SAA7134_IRQ1_INTE_RA2_0 (1 << 16) -#define SAA7134_IRQ1_INTE_RA1_3 (1 << 11) -#define SAA7134_IRQ1_INTE_RA1_2 (1 << 10) -#define SAA7134_IRQ1_INTE_RA1_1 (1 << 9) -#define SAA7134_IRQ1_INTE_RA1_0 (1 << 8) -#define SAA7134_IRQ1_INTE_RA0_7 (1 << 7) -#define SAA7134_IRQ1_INTE_RA0_6 (1 << 6) -#define SAA7134_IRQ1_INTE_RA0_5 (1 << 5) -#define SAA7134_IRQ1_INTE_RA0_4 (1 << 4) -#define SAA7134_IRQ1_INTE_RA0_3 (1 << 3) -#define SAA7134_IRQ1_INTE_RA0_2 (1 << 2) -#define SAA7134_IRQ1_INTE_RA0_1 (1 << 1) -#define SAA7134_IRQ1_INTE_RA0_0 (1 << 0) - -#define SAA7134_IRQ2 (0x2c8 >> 2) -#define SAA7134_IRQ2_INTE_GPIO23_N (1 << 17) /* negative edge */ -#define SAA7134_IRQ2_INTE_GPIO23_P (1 << 16) /* positive edge */ -#define SAA7134_IRQ2_INTE_GPIO22_N (1 << 15) /* negative edge */ -#define SAA7134_IRQ2_INTE_GPIO22_P (1 << 14) /* positive edge */ -#define SAA7134_IRQ2_INTE_GPIO18_N (1 << 13) /* negative edge */ -#define SAA7134_IRQ2_INTE_GPIO18_P (1 << 12) /* positive edge */ -#define SAA7134_IRQ2_INTE_GPIO16_N (1 << 11) /* negative edge */ -#define SAA7134_IRQ2_INTE_GPIO16_P (1 << 10) /* positive edge */ -#define SAA7134_IRQ2_INTE_SC2 (1 << 9) -#define SAA7134_IRQ2_INTE_SC1 (1 << 8) -#define SAA7134_IRQ2_INTE_SC0 (1 << 7) -#define SAA7134_IRQ2_INTE_DEC4 (1 << 6) -#define SAA7134_IRQ2_INTE_DEC3 (1 << 5) -#define SAA7134_IRQ2_INTE_DEC2 (1 << 4) -#define SAA7134_IRQ2_INTE_DEC1 (1 << 3) -#define SAA7134_IRQ2_INTE_DEC0 (1 << 2) -#define SAA7134_IRQ2_INTE_PE (1 << 1) -#define SAA7134_IRQ2_INTE_AR (1 << 0) - -#define SAA7134_IRQ_REPORT (0x2cc >> 2) -#define SAA7134_IRQ_REPORT_GPIO23 (1 << 17) -#define SAA7134_IRQ_REPORT_GPIO22 (1 << 16) -#define SAA7134_IRQ_REPORT_GPIO18 (1 << 15) -#define SAA7134_IRQ_REPORT_GPIO16 (1 << 14) -#define SAA7134_IRQ_REPORT_LOAD_ERR (1 << 13) -#define SAA7134_IRQ_REPORT_CONF_ERR (1 << 12) -#define SAA7134_IRQ_REPORT_TRIG_ERR (1 << 11) -#define SAA7134_IRQ_REPORT_MMC (1 << 10) -#define SAA7134_IRQ_REPORT_FIDT (1 << 9) -#define SAA7134_IRQ_REPORT_INTL (1 << 8) -#define SAA7134_IRQ_REPORT_RDCAP (1 << 7) -#define SAA7134_IRQ_REPORT_PWR_ON (1 << 6) -#define SAA7134_IRQ_REPORT_PE (1 << 5) -#define SAA7134_IRQ_REPORT_AR (1 << 4) -#define SAA7134_IRQ_REPORT_DONE_RA3 (1 << 3) -#define SAA7134_IRQ_REPORT_DONE_RA2 (1 << 2) -#define SAA7134_IRQ_REPORT_DONE_RA1 (1 << 1) -#define SAA7134_IRQ_REPORT_DONE_RA0 (1 << 0) -#define SAA7134_IRQ_STATUS (0x2d0 >> 2) - - -/* ------------------------------------------------------------------ */ -/* - * registers -- 8 bit - */ - -/* video decoder */ -#define SAA7134_INCR_DELAY 0x101 -#define SAA7134_ANALOG_IN_CTRL1 0x102 -#define SAA7134_ANALOG_IN_CTRL2 0x103 -#define SAA7134_ANALOG_IN_CTRL3 0x104 -#define SAA7134_ANALOG_IN_CTRL4 0x105 -#define SAA7134_HSYNC_START 0x106 -#define SAA7134_HSYNC_STOP 0x107 -#define SAA7134_SYNC_CTRL 0x108 -#define SAA7134_LUMA_CTRL 0x109 -#define SAA7134_DEC_LUMA_BRIGHT 0x10a -#define SAA7134_DEC_LUMA_CONTRAST 0x10b -#define SAA7134_DEC_CHROMA_SATURATION 0x10c -#define SAA7134_DEC_CHROMA_HUE 0x10d -#define SAA7134_CHROMA_CTRL1 0x10e -#define SAA7134_CHROMA_GAIN 0x10f -#define SAA7134_CHROMA_CTRL2 0x110 -#define SAA7134_MODE_DELAY_CTRL 0x111 - -#define SAA7134_ANALOG_ADC 0x114 -#define SAA7134_VGATE_START 0x115 -#define SAA7134_VGATE_STOP 0x116 -#define SAA7134_MISC_VGATE_MSB 0x117 -#define SAA7134_RAW_DATA_GAIN 0x118 -#define SAA7134_RAW_DATA_OFFSET 0x119 -#define SAA7134_STATUS_VIDEO1 0x11e -#define SAA7134_STATUS_VIDEO2 0x11f - -/* video scaler */ -#define SAA7134_SOURCE_TIMING1 0x000 -#define SAA7134_SOURCE_TIMING2 0x001 -#define SAA7134_REGION_ENABLE 0x004 -#define SAA7134_SCALER_STATUS0 0x006 -#define SAA7134_SCALER_STATUS1 0x007 -#define SAA7134_START_GREEN 0x00c -#define SAA7134_START_BLUE 0x00d -#define SAA7134_START_RED 0x00e -#define SAA7134_GREEN_PATH(x) (0x010 +x) -#define SAA7134_BLUE_PATH(x) (0x020 +x) -#define SAA7134_RED_PATH(x) (0x030 +x) - -#define TASK_A 0x040 -#define TASK_B 0x080 -#define SAA7134_TASK_CONDITIONS(t) (0x000 +t) -#define SAA7134_FIELD_HANDLING(t) (0x001 +t) -#define SAA7134_DATA_PATH(t) (0x002 +t) -#define SAA7134_VBI_H_START1(t) (0x004 +t) -#define SAA7134_VBI_H_START2(t) (0x005 +t) -#define SAA7134_VBI_H_STOP1(t) (0x006 +t) -#define SAA7134_VBI_H_STOP2(t) (0x007 +t) -#define SAA7134_VBI_V_START1(t) (0x008 +t) -#define SAA7134_VBI_V_START2(t) (0x009 +t) -#define SAA7134_VBI_V_STOP1(t) (0x00a +t) -#define SAA7134_VBI_V_STOP2(t) (0x00b +t) -#define SAA7134_VBI_H_LEN1(t) (0x00c +t) -#define SAA7134_VBI_H_LEN2(t) (0x00d +t) -#define SAA7134_VBI_V_LEN1(t) (0x00e +t) -#define SAA7134_VBI_V_LEN2(t) (0x00f +t) - -#define SAA7134_VIDEO_H_START1(t) (0x014 +t) -#define SAA7134_VIDEO_H_START2(t) (0x015 +t) -#define SAA7134_VIDEO_H_STOP1(t) (0x016 +t) -#define SAA7134_VIDEO_H_STOP2(t) (0x017 +t) -#define SAA7134_VIDEO_V_START1(t) (0x018 +t) -#define SAA7134_VIDEO_V_START2(t) (0x019 +t) -#define SAA7134_VIDEO_V_STOP1(t) (0x01a +t) -#define SAA7134_VIDEO_V_STOP2(t) (0x01b +t) -#define SAA7134_VIDEO_PIXELS1(t) (0x01c +t) -#define SAA7134_VIDEO_PIXELS2(t) (0x01d +t) -#define SAA7134_VIDEO_LINES1(t) (0x01e +t) -#define SAA7134_VIDEO_LINES2(t) (0x01f +t) - -#define SAA7134_H_PRESCALE(t) (0x020 +t) -#define SAA7134_ACC_LENGTH(t) (0x021 +t) -#define SAA7134_LEVEL_CTRL(t) (0x022 +t) -#define SAA7134_FIR_PREFILTER_CTRL(t) (0x023 +t) -#define SAA7134_LUMA_BRIGHT(t) (0x024 +t) -#define SAA7134_LUMA_CONTRAST(t) (0x025 +t) -#define SAA7134_CHROMA_SATURATION(t) (0x026 +t) -#define SAA7134_VBI_H_SCALE_INC1(t) (0x028 +t) -#define SAA7134_VBI_H_SCALE_INC2(t) (0x029 +t) -#define SAA7134_VBI_PHASE_OFFSET_LUMA(t) (0x02a +t) -#define SAA7134_VBI_PHASE_OFFSET_CHROMA(t) (0x02b +t) -#define SAA7134_H_SCALE_INC1(t) (0x02c +t) -#define SAA7134_H_SCALE_INC2(t) (0x02d +t) -#define SAA7134_H_PHASE_OFF_LUMA(t) (0x02e +t) -#define SAA7134_H_PHASE_OFF_CHROMA(t) (0x02f +t) -#define SAA7134_V_SCALE_RATIO1(t) (0x030 +t) -#define SAA7134_V_SCALE_RATIO2(t) (0x031 +t) -#define SAA7134_V_FILTER(t) (0x032 +t) -#define SAA7134_V_PHASE_OFFSET0(t) (0x034 +t) -#define SAA7134_V_PHASE_OFFSET1(t) (0x035 +t) -#define SAA7134_V_PHASE_OFFSET2(t) (0x036 +t) -#define SAA7134_V_PHASE_OFFSET3(t) (0x037 +t) - -/* clipping & dma */ -#define SAA7134_OFMT_VIDEO_A 0x300 -#define SAA7134_OFMT_DATA_A 0x301 -#define SAA7134_OFMT_VIDEO_B 0x302 -#define SAA7134_OFMT_DATA_B 0x303 -#define SAA7134_ALPHA_NOCLIP 0x304 -#define SAA7134_ALPHA_CLIP 0x305 -#define SAA7134_UV_PIXEL 0x308 -#define SAA7134_CLIP_RED 0x309 -#define SAA7134_CLIP_GREEN 0x30a -#define SAA7134_CLIP_BLUE 0x30b - -/* i2c bus */ -#define SAA7134_I2C_ATTR_STATUS 0x180 -#define SAA7134_I2C_DATA 0x181 -#define SAA7134_I2C_CLOCK_SELECT 0x182 -#define SAA7134_I2C_TIMER 0x183 - -/* audio */ -#define SAA7134_NICAM_ADD_DATA1 0x140 -#define SAA7134_NICAM_ADD_DATA2 0x141 -#define SAA7134_NICAM_STATUS 0x142 -#define SAA7134_AUDIO_STATUS 0x143 -#define SAA7134_NICAM_ERROR_COUNT 0x144 -#define SAA7134_IDENT_SIF 0x145 -#define SAA7134_LEVEL_READOUT1 0x146 -#define SAA7134_LEVEL_READOUT2 0x147 -#define SAA7134_NICAM_ERROR_LOW 0x148 -#define SAA7134_NICAM_ERROR_HIGH 0x149 -#define SAA7134_DCXO_IDENT_CTRL 0x14a -#define SAA7134_DEMODULATOR 0x14b -#define SAA7134_AGC_GAIN_SELECT 0x14c -#define SAA7134_CARRIER1_FREQ0 0x150 -#define SAA7134_CARRIER1_FREQ1 0x151 -#define SAA7134_CARRIER1_FREQ2 0x152 -#define SAA7134_CARRIER2_FREQ0 0x154 -#define SAA7134_CARRIER2_FREQ1 0x155 -#define SAA7134_CARRIER2_FREQ2 0x156 -#define SAA7134_NUM_SAMPLES0 0x158 -#define SAA7134_NUM_SAMPLES1 0x159 -#define SAA7134_NUM_SAMPLES2 0x15a -#define SAA7134_AUDIO_FORMAT_CTRL 0x15b -#define SAA7134_MONITOR_SELECT 0x160 -#define SAA7134_FM_DEEMPHASIS 0x161 -#define SAA7134_FM_DEMATRIX 0x162 -#define SAA7134_CHANNEL1_LEVEL 0x163 -#define SAA7134_CHANNEL2_LEVEL 0x164 -#define SAA7134_NICAM_CONFIG 0x165 -#define SAA7134_NICAM_LEVEL_ADJUST 0x166 -#define SAA7134_STEREO_DAC_OUTPUT_SELECT 0x167 -#define SAA7134_I2S_OUTPUT_FORMAT 0x168 -#define SAA7134_I2S_OUTPUT_SELECT 0x169 -#define SAA7134_I2S_OUTPUT_LEVEL 0x16a -#define SAA7134_DSP_OUTPUT_SELECT 0x16b -#define SAA7134_AUDIO_MUTE_CTRL 0x16c -#define SAA7134_SIF_SAMPLE_FREQ 0x16d -#define SAA7134_ANALOG_IO_SELECT 0x16e -#define SAA7134_AUDIO_CLOCK0 0x170 -#define SAA7134_AUDIO_CLOCK1 0x171 -#define SAA7134_AUDIO_CLOCK2 0x172 -#define SAA7134_AUDIO_PLL_CTRL 0x173 -#define SAA7134_AUDIO_CLOCKS_PER_FIELD0 0x174 -#define SAA7134_AUDIO_CLOCKS_PER_FIELD1 0x175 -#define SAA7134_AUDIO_CLOCKS_PER_FIELD2 0x176 - -/* video port output */ -#define SAA7134_VIDEO_PORT_CTRL0 0x190 -#define SAA7134_VIDEO_PORT_CTRL1 0x191 -#define SAA7134_VIDEO_PORT_CTRL2 0x192 -#define SAA7134_VIDEO_PORT_CTRL3 0x193 -#define SAA7134_VIDEO_PORT_CTRL4 0x194 -#define SAA7134_VIDEO_PORT_CTRL5 0x195 -#define SAA7134_VIDEO_PORT_CTRL6 0x196 -#define SAA7134_VIDEO_PORT_CTRL7 0x197 -#define SAA7134_VIDEO_PORT_CTRL8 0x198 - -/* transport stream interface */ -#define SAA7134_TS_PARALLEL 0x1a0 -#define SAA7134_TS_PARALLEL_SERIAL 0x1a1 -#define SAA7134_TS_SERIAL0 0x1a2 -#define SAA7134_TS_SERIAL1 0x1a3 -#define SAA7134_TS_DMA0 0x1a4 -#define SAA7134_TS_DMA1 0x1a5 -#define SAA7134_TS_DMA2 0x1a6 - -/* GPIO Controls */ -#define SAA7134_GPIO_GPRESCAN 0x80 -#define SAA7134_GPIO_27_25 0x0E - -#define SAA7134_GPIO_GPMODE0 0x1B0 -#define SAA7134_GPIO_GPMODE1 0x1B1 -#define SAA7134_GPIO_GPMODE2 0x1B2 -#define SAA7134_GPIO_GPMODE3 0x1B3 -#define SAA7134_GPIO_GPSTATUS0 0x1B4 -#define SAA7134_GPIO_GPSTATUS1 0x1B5 -#define SAA7134_GPIO_GPSTATUS2 0x1B6 -#define SAA7134_GPIO_GPSTATUS3 0x1B7 - -/* I2S output */ -#define SAA7134_I2S_AUDIO_OUTPUT 0x1c0 - -/* test modes */ -#define SAA7134_SPECIAL_MODE 0x1d0 -#define SAA7134_PRODUCTION_TEST_MODE 0x1d1 - -/* audio -- saa7133 + saa7135 only */ -#define SAA7135_DSP_RWSTATE 0x580 -#define SAA7135_DSP_RWSTATE_ERR (1 << 3) -#define SAA7135_DSP_RWSTATE_IDA (1 << 2) -#define SAA7135_DSP_RWSTATE_RDB (1 << 1) -#define SAA7135_DSP_RWSTATE_WRR (1 << 0) - -#define SAA7135_DSP_RWCLEAR 0x586 -#define SAA7135_DSP_RWCLEAR_RERR 1 - -#define SAA7133_I2S_AUDIO_CONTROL 0x591 -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-ts.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-ts.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-ts.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-ts.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,327 +0,0 @@ -/* - * - * device driver for philips saa7134 based TV cards - * video4linux video interface - * - * (c) 2001,02 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" - -/* ------------------------------------------------------------------ */ - -static unsigned int ts_debug; -module_param(ts_debug, int, 0644); -MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]"); - -#define dprintk(fmt, arg...) if (ts_debug) \ - printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg) - -/* ------------------------------------------------------------------ */ - -static int buffer_activate(struct saa7134_dev *dev, - struct saa7134_buf *buf, - struct saa7134_buf *next) -{ - - dprintk("buffer_activate [%p]",buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->top_seen = 0; - - if (NULL == next) - next = buf; - if (V4L2_FIELD_TOP == buf->vb.field) { - dprintk("- [top] buf=%p next=%p\n",buf,next); - saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf)); - saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next)); - } else { - dprintk("- [bottom] buf=%p next=%p\n",buf,next); - saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next)); - saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf)); - } - - /* start DMA */ - saa7134_set_dmabits(dev); - - mod_timer(&dev->ts_q.timeout, jiffies+TS_BUFFER_TIMEOUT); - - if (!dev->ts_started) - saa7134_ts_start(dev); - - return 0; -} - -static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct saa7134_dev *dev = q->priv_data; - struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); - unsigned int lines, llength, size; - int err; - - dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]); - - llength = TS_PACKET_SIZE; - lines = dev->ts.nr_packets; - - size = lines * llength; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - - if (buf->vb.size != size) { - saa7134_dma_free(q,buf); - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - dprintk("buffer_prepare: needs_init\n"); - - buf->vb.width = llength; - buf->vb.height = lines; - buf->vb.size = size; - buf->pt = &dev->ts.pt_ts; - - err = videobuf_iolock(q,&buf->vb,NULL); - if (err) - goto oops; - err = saa7134_pgtable_build(dev->pci,buf->pt, - dma->sglist, - dma->sglen, - saa7134_buffer_startpage(buf)); - if (err) - goto oops; - } - - buf->vb.state = VIDEOBUF_PREPARED; - buf->activate = buffer_activate; - buf->vb.field = field; - return 0; - - oops: - saa7134_dma_free(q,buf); - return err; -} - -static int -buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct saa7134_dev *dev = q->priv_data; - - *size = TS_PACKET_SIZE * dev->ts.nr_packets; - if (0 == *count) - *count = dev->ts.nr_bufs; - *count = saa7134_buffer_count(*size,*count); - - return 0; -} - -static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct saa7134_dev *dev = q->priv_data; - struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); - - saa7134_buffer_queue(dev,&dev->ts_q,buf); -} - -static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); - struct saa7134_dev *dev = q->priv_data; - - if (dev->ts_started) - saa7134_ts_stop(dev); - - saa7134_dma_free(q,buf); -} - -struct videobuf_queue_ops saa7134_ts_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; -EXPORT_SYMBOL_GPL(saa7134_ts_qops); - -/* ----------------------------------------------------------- */ -/* exported stuff */ - -static unsigned int tsbufs = 8; -module_param(tsbufs, int, 0444); -MODULE_PARM_DESC(tsbufs, "number of ts buffers for read/write IO, range 2-32"); - -static unsigned int ts_nr_packets = 64; -module_param(ts_nr_packets, int, 0444); -MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)"); - -int saa7134_ts_init_hw(struct saa7134_dev *dev) -{ - /* deactivate TS softreset */ - saa_writeb(SAA7134_TS_SERIAL1, 0x00); - /* TSSOP high active, TSVAL high active, TSLOCK ignored */ - saa_writeb(SAA7134_TS_PARALLEL, 0x6c); - saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); - saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff)); - saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff)); - /* TSNOPIT=0, TSCOLAP=0 */ - saa_writeb(SAA7134_TS_DMA2, - ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); - - return 0; -} - -int saa7134_ts_init1(struct saa7134_dev *dev) -{ - /* sanitycheck insmod options */ - if (tsbufs < 2) - tsbufs = 2; - if (tsbufs > VIDEO_MAX_FRAME) - tsbufs = VIDEO_MAX_FRAME; - if (ts_nr_packets < 4) - ts_nr_packets = 4; - if (ts_nr_packets > 312) - ts_nr_packets = 312; - dev->ts.nr_bufs = tsbufs; - dev->ts.nr_packets = ts_nr_packets; - - INIT_LIST_HEAD(&dev->ts_q.queue); - init_timer(&dev->ts_q.timeout); - dev->ts_q.timeout.function = saa7134_buffer_timeout; - dev->ts_q.timeout.data = (unsigned long)(&dev->ts_q); - dev->ts_q.dev = dev; - dev->ts_q.need_two = 1; - dev->ts_started = 0; - saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts); - - /* init TS hw */ - saa7134_ts_init_hw(dev); - - return 0; -} - -/* Function for stop TS */ -int saa7134_ts_stop(struct saa7134_dev *dev) -{ - dprintk("TS stop\n"); - - BUG_ON(!dev->ts_started); - - /* Stop TS stream */ - switch (saa7134_boards[dev->board].ts_type) { - case SAA7134_MPEG_TS_PARALLEL: - saa_writeb(SAA7134_TS_PARALLEL, 0x6c); - dev->ts_started = 0; - break; - case SAA7134_MPEG_TS_SERIAL: - saa_writeb(SAA7134_TS_SERIAL0, 0x40); - dev->ts_started = 0; - break; - } - return 0; -} - -/* Function for start TS */ -int saa7134_ts_start(struct saa7134_dev *dev) -{ - dprintk("TS start\n"); - - BUG_ON(dev->ts_started); - - /* dma: setup channel 5 (= TS) */ - saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff); - saa_writeb(SAA7134_TS_DMA1, - ((dev->ts.nr_packets - 1) >> 8) & 0xff); - /* TSNOPIT=0, TSCOLAP=0 */ - saa_writeb(SAA7134_TS_DMA2, - (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00); - saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE); - saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (dev->ts.pt_ts.dma >> 12)); - - /* reset hardware TS buffers */ - saa_writeb(SAA7134_TS_SERIAL1, 0x00); - saa_writeb(SAA7134_TS_SERIAL1, 0x03); - saa_writeb(SAA7134_TS_SERIAL1, 0x00); - saa_writeb(SAA7134_TS_SERIAL1, 0x01); - - /* TS clock non-inverted */ - saa_writeb(SAA7134_TS_SERIAL1, 0x00); - - /* Start TS stream */ - switch (saa7134_boards[dev->board].ts_type) { - case SAA7134_MPEG_TS_PARALLEL: - saa_writeb(SAA7134_TS_SERIAL0, 0x40); - saa_writeb(SAA7134_TS_PARALLEL, 0xec | - (saa7134_boards[dev->board].ts_force_val << 4)); - break; - case SAA7134_MPEG_TS_SERIAL: - saa_writeb(SAA7134_TS_SERIAL0, 0xd8); - saa_writeb(SAA7134_TS_PARALLEL, 0x6c | - (saa7134_boards[dev->board].ts_force_val << 4)); - saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc); - saa_writeb(SAA7134_TS_SERIAL1, 0x02); - break; - } - - dev->ts_started = 1; - - return 0; -} - -int saa7134_ts_fini(struct saa7134_dev *dev) -{ - saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts); - return 0; -} - -void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) -{ - enum v4l2_field field; - - spin_lock(&dev->slock); - if (dev->ts_q.curr) { - field = dev->ts_q.curr->vb.field; - if (field == V4L2_FIELD_TOP) { - if ((status & 0x100000) != 0x000000) - goto done; - } else { - if ((status & 0x100000) != 0x100000) - goto done; - } - saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE); - } - saa7134_buffer_next(dev,&dev->ts_q); - - done: - spin_unlock(&dev->slock); -} - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-tvaudio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-tvaudio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-tvaudio.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-tvaudio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1076 +0,0 @@ -/* - * - * device driver for philips saa7134 based TV cards - * tv audio decoder (fm stereo, nicam, ...) - * - * (c) 2001-03 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" - -/* ------------------------------------------------------------------ */ - -static unsigned int audio_debug; -module_param(audio_debug, int, 0644); -MODULE_PARM_DESC(audio_debug,"enable debug messages [tv audio]"); - -static unsigned int audio_ddep; -module_param(audio_ddep, int, 0644); -MODULE_PARM_DESC(audio_ddep,"audio ddep overwrite"); - -static int audio_clock_override = UNSET; -module_param(audio_clock_override, int, 0644); - -static int audio_clock_tweak; -module_param(audio_clock_tweak, int, 0644); -MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])"); - -#define dprintk(fmt, arg...) if (audio_debug) \ - printk(KERN_DEBUG "%s/audio: " fmt, dev->name , ## arg) -#define d2printk(fmt, arg...) if (audio_debug > 1) \ - printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg) - -#define print_regb(reg) printk("%s: reg 0x%03x [%-16s]: 0x%02x\n", \ - dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg))) - -/* msecs */ -#define SCAN_INITIAL_DELAY 1000 -#define SCAN_SAMPLE_DELAY 200 -#define SCAN_SUBCARRIER_DELAY 2000 - -/* ------------------------------------------------------------------ */ -/* saa7134 code */ - -static struct mainscan { - char *name; - v4l2_std_id std; - int carr; -} mainscan[] = { - { - .name = "MN", - .std = V4L2_STD_MN, - .carr = 4500, - },{ - .name = "BGH", - .std = V4L2_STD_B | V4L2_STD_GH, - .carr = 5500, - },{ - .name = "I", - .std = V4L2_STD_PAL_I, - .carr = 6000, - },{ - .name = "DKL", - .std = V4L2_STD_DK | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC, - .carr = 6500, - } -}; - -static struct saa7134_tvaudio tvaudio[] = { - { - .name = "PAL-B/G FM-stereo", - .std = V4L2_STD_PAL_BG, - .mode = TVAUDIO_FM_BG_STEREO, - .carr1 = 5500, - .carr2 = 5742, - },{ - .name = "PAL-D/K1 FM-stereo", - .std = V4L2_STD_PAL_DK, - .carr1 = 6500, - .carr2 = 6258, - .mode = TVAUDIO_FM_BG_STEREO, - },{ - .name = "PAL-D/K2 FM-stereo", - .std = V4L2_STD_PAL_DK, - .carr1 = 6500, - .carr2 = 6742, - .mode = TVAUDIO_FM_BG_STEREO, - },{ - .name = "PAL-D/K3 FM-stereo", - .std = V4L2_STD_PAL_DK, - .carr1 = 6500, - .carr2 = 5742, - .mode = TVAUDIO_FM_BG_STEREO, - },{ - .name = "PAL-B/G NICAM", - .std = V4L2_STD_PAL_BG, - .carr1 = 5500, - .carr2 = 5850, - .mode = TVAUDIO_NICAM_FM, - },{ - .name = "PAL-I NICAM", - .std = V4L2_STD_PAL_I, - .carr1 = 6000, - .carr2 = 6552, - .mode = TVAUDIO_NICAM_FM, - },{ - .name = "PAL-D/K NICAM", - .std = V4L2_STD_PAL_DK, - .carr1 = 6500, - .carr2 = 5850, - .mode = TVAUDIO_NICAM_FM, - },{ - .name = "SECAM-L NICAM", - .std = V4L2_STD_SECAM_L, - .carr1 = 6500, - .carr2 = 5850, - .mode = TVAUDIO_NICAM_AM, - },{ - .name = "SECAM-D/K NICAM", - .std = V4L2_STD_SECAM_DK, - .carr1 = 6500, - .carr2 = 5850, - .mode = TVAUDIO_NICAM_FM, - },{ - .name = "NTSC-A2 FM-stereo", - .std = V4L2_STD_NTSC, - .carr1 = 4500, - .carr2 = 4724, - .mode = TVAUDIO_FM_K_STEREO, - },{ - .name = "NTSC-M", - .std = V4L2_STD_NTSC, - .carr1 = 4500, - .carr2 = -1, - .mode = TVAUDIO_FM_MONO, - } -}; -#define TVAUDIO ARRAY_SIZE(tvaudio) - -/* ------------------------------------------------------------------ */ - -static u32 tvaudio_carr2reg(u32 carrier) -{ - u64 a = carrier; - - a <<= 24; - do_div(a,12288); - return a; -} - -static void tvaudio_setcarrier(struct saa7134_dev *dev, - int primary, int secondary) -{ - if (-1 == secondary) - secondary = primary; - saa_writel(SAA7134_CARRIER1_FREQ0 >> 2, tvaudio_carr2reg(primary)); - saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary)); -} - -#define SAA7134_MUTE_MASK 0xbb -#define SAA7134_MUTE_ANALOG 0x04 -#define SAA7134_MUTE_I2S 0x40 - -static void mute_input_7134(struct saa7134_dev *dev) -{ - unsigned int mute; - struct saa7134_input *in; - int ausel=0, ics=0, ocs=0; - int mask; - - /* look what is to do ... */ - in = dev->input; - mute = (dev->ctl_mute || - (dev->automute && (&card(dev).radio) != in)); - if (card(dev).mute.name) { - /* - * 7130 - we'll mute using some unconnected audio input - * 7134 - we'll probably should switch external mux with gpio - */ - if (mute) - in = &card(dev).mute; - } - - if (dev->hw_mute == mute && - dev->hw_input == in && !dev->insuspend) { - dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", - mute,in->name); - return; - } - - dprintk("ctl_mute=%d automute=%d input=%s => mute=%d input=%s\n", - dev->ctl_mute,dev->automute,dev->input->name,mute,in->name); - dev->hw_mute = mute; - dev->hw_input = in; - - if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device) - /* 7134 mute */ - saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? - SAA7134_MUTE_MASK | - SAA7134_MUTE_ANALOG | - SAA7134_MUTE_I2S : - SAA7134_MUTE_MASK); - - /* switch internal audio mux */ - switch (in->amux) { - case TV: ausel=0xc0; ics=0x00; ocs=0x02; break; - case LINE1: ausel=0x80; ics=0x00; ocs=0x00; break; - case LINE2: ausel=0x80; ics=0x08; ocs=0x01; break; - case LINE2_LEFT: ausel=0x80; ics=0x08; ocs=0x05; break; - } - saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, ausel); - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, ics); - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, ocs); - // for oss, we need to change the clock configuration - if (in->amux == TV) - saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00); - else - saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x01); - - /* switch gpio-connected external audio mux */ - if (0 == card(dev).gpiomask) - return; - - mask = card(dev).gpiomask; - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); - saa7134_track_gpio(dev,in->name); -} - -static void tvaudio_setmode(struct saa7134_dev *dev, - struct saa7134_tvaudio *audio, - char *note) -{ - int acpf, tweak = 0; - - if (dev->tvnorm->id == V4L2_STD_NTSC) { - acpf = 0x19066; - } else { - acpf = 0x1e000; - } - if (audio_clock_tweak > -1024 && audio_clock_tweak < 1024) - tweak = audio_clock_tweak; - - if (note) - dprintk("tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz] acpf=%d%+d\n", - note,audio->name, - audio->carr1 / 1000, audio->carr1 % 1000, - audio->carr2 / 1000, audio->carr2 % 1000, - acpf, tweak); - - acpf += tweak; - saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD0, (acpf & 0x0000ff) >> 0); - saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD1, (acpf & 0x00ff00) >> 8); - saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD2, (acpf & 0x030000) >> 16); - tvaudio_setcarrier(dev,audio->carr1,audio->carr2); - - switch (audio->mode) { - case TVAUDIO_FM_MONO: - case TVAUDIO_FM_BG_STEREO: - saa_writeb(SAA7134_DEMODULATOR, 0x00); - saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); - saa_writeb(SAA7134_FM_DEEMPHASIS, 0x22); - saa_writeb(SAA7134_FM_DEMATRIX, 0x80); - saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0); - break; - case TVAUDIO_FM_K_STEREO: - saa_writeb(SAA7134_DEMODULATOR, 0x00); - saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x01); - saa_writeb(SAA7134_FM_DEEMPHASIS, 0x22); - saa_writeb(SAA7134_FM_DEMATRIX, 0x80); - saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0); - break; - case TVAUDIO_NICAM_FM: - saa_writeb(SAA7134_DEMODULATOR, 0x10); - saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); - saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); - saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); - saa_writeb(SAA7134_NICAM_CONFIG, 0x00); - break; - case TVAUDIO_NICAM_AM: - saa_writeb(SAA7134_DEMODULATOR, 0x12); - saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); - saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); - saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); - saa_writeb(SAA7134_NICAM_CONFIG, 0x00); - break; - case TVAUDIO_FM_SAT_STEREO: - /* not implemented (yet) */ - break; - } -} - -static int tvaudio_sleep(struct saa7134_dev *dev, int timeout) -{ - if (dev->thread.scan1 == dev->thread.scan2 && - !kthread_should_stop()) { - if (timeout < 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } else { - schedule_timeout_interruptible - (msecs_to_jiffies(timeout)); - } - } - return dev->thread.scan1 != dev->thread.scan2; -} - -static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) -{ - __s32 left,right,value; - - if (audio_debug > 1) { - int i; - dprintk("debug %d:",scan->carr); - for (i = -150; i <= 150; i += 30) { - tvaudio_setcarrier(dev,scan->carr+i,scan->carr+i); - saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) - return -1; - value = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - if (0 == i) - printk(" # %6d # ",value >> 16); - else - printk(" %6d",value >> 16); - } - printk("\n"); - } - if (dev->tvnorm->id & scan->std) { - tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90); - saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) - return -1; - left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - - tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90); - saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) - return -1; - right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - - left >>= 16; - right >>= 16; - value = left > right ? left - right : right - left; - dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", - scan->carr / 1000, scan->carr % 1000, - scan->name, value, left, right); - } else { - value = 0; - dprintk("skipping %d.%03d MHz [%4s]\n", - scan->carr / 1000, scan->carr % 1000, scan->name); - } - return value; -} - - -static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio) -{ - __u32 idp, nicam, nicam_status; - int retval = -1; - - switch (audio->mode) { - case TVAUDIO_FM_MONO: - return V4L2_TUNER_SUB_MONO; - case TVAUDIO_FM_K_STEREO: - case TVAUDIO_FM_BG_STEREO: - idp = (saa_readb(SAA7134_IDENT_SIF) & 0xe0) >> 5; - dprintk("getstereo: fm/stereo: idp=0x%x\n",idp); - if (0x03 == (idp & 0x03)) - retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - else if (0x05 == (idp & 0x05)) - retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - else if (0x01 == (idp & 0x01)) - retval = V4L2_TUNER_SUB_MONO; - break; - case TVAUDIO_FM_SAT_STEREO: - /* not implemented (yet) */ - break; - case TVAUDIO_NICAM_FM: - case TVAUDIO_NICAM_AM: - nicam = saa_readb(SAA7134_AUDIO_STATUS); - dprintk("getstereo: nicam=0x%x\n",nicam); - if (nicam & 0x1) { - nicam_status = saa_readb(SAA7134_NICAM_STATUS); - dprintk("getstereo: nicam_status=0x%x\n", nicam_status); - - switch (nicam_status & 0x03) { - case 0x01: - retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - break; - case 0x02: - retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - break; - default: - retval = V4L2_TUNER_SUB_MONO; - } - } else { - /* No nicam detected */ - } - break; - } - if (retval != -1) - dprintk("found audio subchannels:%s%s%s%s\n", - (retval & V4L2_TUNER_SUB_MONO) ? " mono" : "", - (retval & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", - (retval & V4L2_TUNER_SUB_LANG1) ? " lang1" : "", - (retval & V4L2_TUNER_SUB_LANG2) ? " lang2" : ""); - return retval; -} - -static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio, - u32 mode) -{ - static char *name[] = { - [ V4L2_TUNER_MODE_MONO ] = "mono", - [ V4L2_TUNER_MODE_STEREO ] = "stereo", - [ V4L2_TUNER_MODE_LANG1 ] = "lang1", - [ V4L2_TUNER_MODE_LANG2 ] = "lang2", - [ V4L2_TUNER_MODE_LANG1_LANG2 ] = "lang1+lang2", - }; - static u32 fm[] = { - [ V4L2_TUNER_MODE_MONO ] = 0x00, /* ch1 */ - [ V4L2_TUNER_MODE_STEREO ] = 0x80, /* auto */ - [ V4L2_TUNER_MODE_LANG1 ] = 0x00, /* ch1 */ - [ V4L2_TUNER_MODE_LANG2 ] = 0x01, /* ch2 */ - [ V4L2_TUNER_MODE_LANG1_LANG2 ] = 0x80, /* auto */ - }; - u32 reg; - - switch (audio->mode) { - case TVAUDIO_FM_MONO: - /* nothing to do ... */ - break; - case TVAUDIO_FM_K_STEREO: - case TVAUDIO_FM_BG_STEREO: - case TVAUDIO_NICAM_AM: - case TVAUDIO_NICAM_FM: - dprintk("setstereo [fm] => %s\n", - name[ mode % ARRAY_SIZE(name) ]); - reg = fm[ mode % ARRAY_SIZE(fm) ]; - saa_writeb(SAA7134_FM_DEMATRIX, reg); - break; - case TVAUDIO_FM_SAT_STEREO: - /* Not implemented */ - break; - } - return 0; -} - -static int tvaudio_thread(void *data) -{ - struct saa7134_dev *dev = data; - int carr_vals[ARRAY_SIZE(mainscan)]; - unsigned int i, audio, nscan; - int max1,max2,carrier,rx,mode,lastmode,default_carrier; - - set_freezable(); - - for (;;) { - tvaudio_sleep(dev,-1); - if (kthread_should_stop()) - goto done; - - restart: - try_to_freeze(); - - dev->thread.scan1 = dev->thread.scan2; - dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); - dev->tvaudio = NULL; - - saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); - saa_writeb(SAA7134_FM_DEMATRIX, 0x80); - - if (dev->ctl_automute) - dev->automute = 1; - - mute_input_7134(dev); - - /* give the tuner some time */ - if (tvaudio_sleep(dev,SCAN_INITIAL_DELAY)) - goto restart; - - max1 = 0; - max2 = 0; - nscan = 0; - carrier = 0; - default_carrier = 0; - for (i = 0; i < ARRAY_SIZE(mainscan); i++) { - if (!(dev->tvnorm->id & mainscan[i].std)) - continue; - if (!default_carrier) - default_carrier = mainscan[i].carr; - nscan++; - } - - if (1 == nscan) { - /* only one candidate -- skip scan ;) */ - dprintk("only one main carrier candidate - skipping scan\n"); - max1 = 12345; - carrier = default_carrier; - } else { - /* scan for the main carrier */ - saa_writeb(SAA7134_MONITOR_SELECT,0x00); - tvaudio_setmode(dev,&tvaudio[0],NULL); - for (i = 0; i < ARRAY_SIZE(mainscan); i++) { - carr_vals[i] = tvaudio_checkcarrier(dev, mainscan+i); - if (dev->thread.scan1 != dev->thread.scan2) - goto restart; - } - for (max1 = 0, max2 = 0, i = 0; i < ARRAY_SIZE(mainscan); i++) { - if (max1 < carr_vals[i]) { - max2 = max1; - max1 = carr_vals[i]; - carrier = mainscan[i].carr; - } else if (max2 < carr_vals[i]) { - max2 = carr_vals[i]; - } - } - } - - if (0 != carrier && max1 > 2000 && max1 > max2*3) { - /* found good carrier */ - dprintk("found %s main sound carrier @ %d.%03d MHz [%d/%d]\n", - dev->tvnorm->name, carrier/1000, carrier%1000, - max1, max2); - dev->last_carrier = carrier; - - } else if (0 != dev->last_carrier) { - /* no carrier -- try last detected one as fallback */ - carrier = dev->last_carrier; - dprintk("audio carrier scan failed, " - "using %d.%03d MHz [last detected]\n", - carrier/1000, carrier%1000); - - } else { - /* no carrier + no fallback -- use default */ - carrier = default_carrier; - dprintk("audio carrier scan failed, " - "using %d.%03d MHz [default]\n", - carrier/1000, carrier%1000); - } - tvaudio_setcarrier(dev,carrier,carrier); - dev->automute = 0; - saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00); - saa7134_tvaudio_setmute(dev); - /* find the exact tv audio norm */ - for (audio = UNSET, i = 0; i < TVAUDIO; i++) { - if (dev->tvnorm->id != UNSET && - !(dev->tvnorm->id & tvaudio[i].std)) - continue; - if (tvaudio[i].carr1 != carrier) - continue; - /* Note: at least the primary carrier is right here */ - if (UNSET == audio) - audio = i; - tvaudio_setmode(dev,&tvaudio[i],"trying"); - if (tvaudio_sleep(dev,SCAN_SUBCARRIER_DELAY)) - goto restart; - if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) { - audio = i; - break; - } - } - saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x30); - if (UNSET == audio) - continue; - tvaudio_setmode(dev,&tvaudio[audio],"using"); - - tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO); - dev->tvaudio = &tvaudio[audio]; - - lastmode = 42; - for (;;) { - - try_to_freeze(); - - if (tvaudio_sleep(dev,5000)) - goto restart; - if (kthread_should_stop()) - break; - if (UNSET == dev->thread.mode) { - rx = tvaudio_getstereo(dev,&tvaudio[i]); - mode = saa7134_tvaudio_rx2mode(rx); - } else { - mode = dev->thread.mode; - } - if (lastmode != mode) { - tvaudio_setstereo(dev,&tvaudio[audio],mode); - lastmode = mode; - } - } - } - - done: - dev->thread.stopped = 1; - return 0; -} - -/* ------------------------------------------------------------------ */ -/* saa7133 / saa7135 code */ - -static char *stdres[0x20] = { - [0x00] = "no standard detected", - [0x01] = "B/G (in progress)", - [0x02] = "D/K (in progress)", - [0x03] = "M (in progress)", - - [0x04] = "B/G A2", - [0x05] = "B/G NICAM", - [0x06] = "D/K A2 (1)", - [0x07] = "D/K A2 (2)", - [0x08] = "D/K A2 (3)", - [0x09] = "D/K NICAM", - [0x0a] = "L NICAM", - [0x0b] = "I NICAM", - - [0x0c] = "M Korea", - [0x0d] = "M BTSC ", - [0x0e] = "M EIAJ", - - [0x0f] = "FM radio / IF 10.7 / 50 deemp", - [0x10] = "FM radio / IF 10.7 / 75 deemp", - [0x11] = "FM radio / IF sel / 50 deemp", - [0x12] = "FM radio / IF sel / 75 deemp", - - [0x13 ... 0x1e ] = "unknown", - [0x1f] = "??? [in progress]", -}; - -#define DSP_RETRY 32 -#define DSP_DELAY 16 -#define SAA7135_DSP_RWCLEAR_RERR 1 - -static inline int saa_dsp_reset_error_bit(struct saa7134_dev *dev) -{ - int state = saa_readb(SAA7135_DSP_RWSTATE); - if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) { - d2printk("%s: resetting error bit\n", dev->name); - saa_writeb(SAA7135_DSP_RWCLEAR, SAA7135_DSP_RWCLEAR_RERR); - } - return 0; -} - -static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit) -{ - int state, count = DSP_RETRY; - - state = saa_readb(SAA7135_DSP_RWSTATE); - if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) { - printk(KERN_WARNING "%s: dsp access error\n", dev->name); - saa_dsp_reset_error_bit(dev); - return -EIO; - } - while (0 == (state & bit)) { - if (unlikely(0 == count)) { - printk("%s: dsp access wait timeout [bit=%s]\n", - dev->name, - (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" : - (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" : - (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" : - "???"); - return -EIO; - } - saa_wait(DSP_DELAY); - state = saa_readb(SAA7135_DSP_RWSTATE); - count--; - } - return 0; -} - - -int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value) -{ - int err; - - d2printk("dsp write reg 0x%x = 0x%06x\n",reg<<2,value); - err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR); - if (err < 0) - return err; - saa_writel(reg,value); - err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR); - if (err < 0) - return err; - return 0; -} - -static int getstereo_7133(struct saa7134_dev *dev) -{ - int retval = V4L2_TUNER_SUB_MONO; - u32 value; - - value = saa_readl(0x528 >> 2); - if (value & 0x20) - retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - if (value & 0x40) - retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - return retval; -} - -static int mute_input_7133(struct saa7134_dev *dev) -{ - u32 reg = 0; - u32 xbarin, xbarout; - int mask; - struct saa7134_input *in; - - xbarin = 0x03; - switch (dev->input->amux) { - case TV: - reg = 0x02; - xbarin = 0; - break; - case LINE1: - reg = 0x00; - break; - case LINE2: - case LINE2_LEFT: - reg = 0x09; - break; - } - saa_dsp_writel(dev, 0x464 >> 2, xbarin); - if (dev->ctl_mute) { - reg = 0x07; - xbarout = 0xbbbbbb; - } else - xbarout = 0xbbbb10; - saa_dsp_writel(dev, 0x46c >> 2, xbarout); - - saa_writel(0x594 >> 2, reg); - - - /* switch gpio-connected external audio mux */ - if (0 != card(dev).gpiomask) { - mask = card(dev).gpiomask; - - if (card(dev).mute.name && dev->ctl_mute) - in = &card(dev).mute; - else - in = dev->input; - - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); - saa7134_track_gpio(dev,in->name); - } - - return 0; -} - -static int tvaudio_thread_ddep(void *data) -{ - struct saa7134_dev *dev = data; - u32 value, norms; - - set_freezable(); - for (;;) { - tvaudio_sleep(dev,-1); - if (kthread_should_stop()) - goto done; - restart: - try_to_freeze(); - - dev->thread.scan1 = dev->thread.scan2; - dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); - - if (audio_ddep >= 0x04 && audio_ddep <= 0x0e) { - /* insmod option override */ - norms = (audio_ddep << 2) | 0x01; - dprintk("ddep override: %s\n",stdres[audio_ddep]); - } else if (&card(dev).radio == dev->input) { - dprintk("FM Radio\n"); - if (dev->tuner_type == TUNER_PHILIPS_TDA8290) { - norms = (0x11 << 2) | 0x01; - saa_dsp_writel(dev, 0x42c >> 2, 0x729555); - } else { - norms = (0x0f << 2) | 0x01; - } - } else { - /* (let chip) scan for sound carrier */ - norms = 0; - if (dev->tvnorm->id & (V4L2_STD_B | V4L2_STD_GH)) - norms |= 0x04; - if (dev->tvnorm->id & V4L2_STD_PAL_I) - norms |= 0x20; - if (dev->tvnorm->id & V4L2_STD_DK) - norms |= 0x08; - if (dev->tvnorm->id & V4L2_STD_MN) - norms |= 0x40; - if (dev->tvnorm->id & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) - norms |= 0x10; - if (0 == norms) - norms = 0x7c; /* all */ - dprintk("scanning:%s%s%s%s%s\n", - (norms & 0x04) ? " B/G" : "", - (norms & 0x08) ? " D/K" : "", - (norms & 0x10) ? " L/L'" : "", - (norms & 0x20) ? " I" : "", - (norms & 0x40) ? " M" : ""); - } - - /* kick automatic standard detection */ - saa_dsp_writel(dev, 0x454 >> 2, 0); - saa_dsp_writel(dev, 0x454 >> 2, norms | 0x80); - - /* setup crossbars */ - saa_dsp_writel(dev, 0x464 >> 2, 0x000000); - saa_dsp_writel(dev, 0x470 >> 2, 0x101010); - - if (tvaudio_sleep(dev,3000)) - goto restart; - value = saa_readl(0x528 >> 2) & 0xffffff; - - dprintk("tvaudio thread status: 0x%x [%s%s%s]\n", - value, stdres[value & 0x1f], - (value & 0x000020) ? ",stereo" : "", - (value & 0x000040) ? ",dual" : ""); - dprintk("detailed status: " - "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n", - (value & 0x000080) ? " A2/EIAJ pilot tone " : "", - (value & 0x000100) ? " A2/EIAJ dual " : "", - (value & 0x000200) ? " A2/EIAJ stereo " : "", - (value & 0x000400) ? " A2/EIAJ noise mute " : "", - - (value & 0x000800) ? " BTSC/FM radio pilot " : "", - (value & 0x001000) ? " SAP carrier " : "", - (value & 0x002000) ? " BTSC stereo noise mute " : "", - (value & 0x004000) ? " SAP noise mute " : "", - (value & 0x008000) ? " VDSP " : "", - - (value & 0x010000) ? " NICST " : "", - (value & 0x020000) ? " NICDU " : "", - (value & 0x040000) ? " NICAM muted " : "", - (value & 0x080000) ? " NICAM reserve sound " : "", - - (value & 0x100000) ? " init done " : ""); - } - - done: - dev->thread.stopped = 1; - return 0; -} - -/* ------------------------------------------------------------------ */ -/* common stuff + external entry points */ - -void saa7134_enable_i2s(struct saa7134_dev *dev) -{ - int i2s_format; - - if (!card_is_empress(dev)) - return; - - if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) - return; - - /* configure GPIO for out */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0E000000, 0x00000000); - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - /* Set I2S format (SONY)  */ - saa_writeb(SAA7133_I2S_AUDIO_CONTROL, 0x00); - /* Start I2S */ - saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11); - break; - - case PCI_DEVICE_ID_PHILIPS_SAA7134: - i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01; - - /* enable I2S audio output for the mpeg encoder */ - saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); - saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format); - saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F); - saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01); - - default: - break; - } -} - -int saa7134_tvaudio_rx2mode(u32 rx) -{ - u32 mode; - - mode = V4L2_TUNER_MODE_MONO; - if (rx & V4L2_TUNER_SUB_STEREO) - mode = V4L2_TUNER_MODE_STEREO; - else if (rx & V4L2_TUNER_SUB_LANG1) - mode = V4L2_TUNER_MODE_LANG1; - else if (rx & V4L2_TUNER_SUB_LANG2) - mode = V4L2_TUNER_MODE_LANG2; - return mode; -} - -void saa7134_tvaudio_setmute(struct saa7134_dev *dev) -{ - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7130: - case PCI_DEVICE_ID_PHILIPS_SAA7134: - mute_input_7134(dev); - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - mute_input_7133(dev); - break; - } -} - -void saa7134_tvaudio_setinput(struct saa7134_dev *dev, - struct saa7134_input *in) -{ - dev->input = in; - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7130: - case PCI_DEVICE_ID_PHILIPS_SAA7134: - mute_input_7134(dev); - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - mute_input_7133(dev); - break; - } - saa7134_enable_i2s(dev); -} - -void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level) -{ - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - saa_writeb(SAA7134_CHANNEL1_LEVEL, level & 0x1f); - saa_writeb(SAA7134_CHANNEL2_LEVEL, level & 0x1f); - saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f); - break; - } -} - -int saa7134_tvaudio_getstereo(struct saa7134_dev *dev) -{ - int retval = V4L2_TUNER_SUB_MONO; - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - if (dev->tvaudio) - retval = tvaudio_getstereo(dev,dev->tvaudio); - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - retval = getstereo_7133(dev); - break; - } - return retval; -} - -void saa7134_tvaudio_init(struct saa7134_dev *dev) -{ - int clock = saa7134_boards[dev->board].audio_clock; - - if (UNSET != audio_clock_override) - clock = audio_clock_override; - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - /* init all audio registers */ - saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); - if (need_resched()) - schedule(); - else - udelay(10); - - saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff); - saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff); - saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff); - /* frame locked audio is mandatory for NICAM */ - saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01); - saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14); - saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50); - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - saa_writel(0x598 >> 2, clock); - saa_dsp_writel(dev, 0x474 >> 2, 0x00); - saa_dsp_writel(dev, 0x450 >> 2, 0x00); - } -} - -int saa7134_tvaudio_init2(struct saa7134_dev *dev) -{ - int (*my_thread)(void *data) = NULL; - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - my_thread = tvaudio_thread; - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - my_thread = tvaudio_thread_ddep; - break; - } - - dev->thread.thread = NULL; - if (my_thread) { - saa7134_tvaudio_init(dev); - /* start tvaudio thread */ - dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name); - if (IS_ERR(dev->thread.thread)) { - printk(KERN_WARNING "%s: kernel_thread() failed\n", - dev->name); - /* XXX: missing error handling here */ - } - saa7134_tvaudio_do_scan(dev); - } - - saa7134_enable_i2s(dev); - return 0; -} - -int saa7134_tvaudio_fini(struct saa7134_dev *dev) -{ - /* shutdown tvaudio thread */ - if (dev->thread.thread && !dev->thread.stopped) - kthread_stop(dev->thread.thread); - - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */ - return 0; -} - -int saa7134_tvaudio_do_scan(struct saa7134_dev *dev) -{ - if (dev->input->amux != TV) { - dprintk("sound IF not in use, skipping scan\n"); - dev->automute = 0; - saa7134_tvaudio_setmute(dev); - } else if (dev->thread.thread) { - dev->thread.mode = UNSET; - dev->thread.scan2++; - - if (!dev->insuspend && !dev->thread.stopped) - wake_up_process(dev->thread.thread); - } else { - dev->automute = 0; - saa7134_tvaudio_setmute(dev); - } - return 0; -} - -EXPORT_SYMBOL(saa_dsp_writel); -EXPORT_SYMBOL(saa7134_tvaudio_setmute); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-vbi.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,255 +0,0 @@ -/* - * - * device driver for philips saa7134 based TV cards - * video4linux video interface - * - * (c) 2001,02 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" - -/* ------------------------------------------------------------------ */ - -static unsigned int vbi_debug; -module_param(vbi_debug, int, 0644); -MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); - -static unsigned int vbibufs = 4; -module_param(vbibufs, int, 0444); -MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); - -#define dprintk(fmt, arg...) if (vbi_debug) \ - printk(KERN_DEBUG "%s/vbi: " fmt, dev->name , ## arg) - -/* ------------------------------------------------------------------ */ - -#define VBI_LINE_COUNT 16 -#define VBI_LINE_LENGTH 2048 -#define VBI_SCALE 0x200 - -static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf, - int task) -{ - struct saa7134_tvnorm *norm = dev->tvnorm; - - /* setup video scaler */ - saa_writeb(SAA7134_VBI_H_START1(task), norm->h_start & 0xff); - saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start >> 8); - saa_writeb(SAA7134_VBI_H_STOP1(task), norm->h_stop & 0xff); - saa_writeb(SAA7134_VBI_H_STOP2(task), norm->h_stop >> 8); - saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start_0 & 0xff); - saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start_0 >> 8); - saa_writeb(SAA7134_VBI_V_STOP1(task), norm->vbi_v_stop_0 & 0xff); - saa_writeb(SAA7134_VBI_V_STOP2(task), norm->vbi_v_stop_0 >> 8); - - saa_writeb(SAA7134_VBI_H_SCALE_INC1(task), VBI_SCALE & 0xff); - saa_writeb(SAA7134_VBI_H_SCALE_INC2(task), VBI_SCALE >> 8); - saa_writeb(SAA7134_VBI_PHASE_OFFSET_LUMA(task), 0x00); - saa_writeb(SAA7134_VBI_PHASE_OFFSET_CHROMA(task), 0x00); - - saa_writeb(SAA7134_VBI_H_LEN1(task), buf->vb.width & 0xff); - saa_writeb(SAA7134_VBI_H_LEN2(task), buf->vb.width >> 8); - saa_writeb(SAA7134_VBI_V_LEN1(task), buf->vb.height & 0xff); - saa_writeb(SAA7134_VBI_V_LEN2(task), buf->vb.height >> 8); - - saa_andorb(SAA7134_DATA_PATH(task), 0xc0, 0x00); -} - -/* ------------------------------------------------------------------ */ - -static int buffer_activate(struct saa7134_dev *dev, - struct saa7134_buf *buf, - struct saa7134_buf *next) -{ - unsigned long control,base; - - dprintk("buffer_activate [%p]\n",buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->top_seen = 0; - - task_init(dev,buf,TASK_A); - task_init(dev,buf,TASK_B); - saa_writeb(SAA7134_OFMT_DATA_A, 0x06); - saa_writeb(SAA7134_OFMT_DATA_B, 0x06); - - /* DMA: setup channel 2+3 (= VBI Task A+B) */ - base = saa7134_buffer_base(buf); - control = SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (buf->pt->dma >> 12); - saa_writel(SAA7134_RS_BA1(2),base); - saa_writel(SAA7134_RS_BA2(2),base + buf->vb.size/2); - saa_writel(SAA7134_RS_PITCH(2),buf->vb.width); - saa_writel(SAA7134_RS_CONTROL(2),control); - saa_writel(SAA7134_RS_BA1(3),base); - saa_writel(SAA7134_RS_BA2(3),base + buf->vb.size/2); - saa_writel(SAA7134_RS_PITCH(3),buf->vb.width); - saa_writel(SAA7134_RS_CONTROL(3),control); - - /* start DMA */ - saa7134_set_dmabits(dev); - mod_timer(&dev->vbi_q.timeout, jiffies+BUFFER_TIMEOUT); - - return 0; -} - -static int buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct saa7134_fh *fh = q->priv_data; - struct saa7134_dev *dev = fh->dev; - struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); - struct saa7134_tvnorm *norm = dev->tvnorm; - unsigned int lines, llength, size; - int err; - - lines = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1; - if (lines > VBI_LINE_COUNT) - lines = VBI_LINE_COUNT; - llength = VBI_LINE_LENGTH; - size = lines * llength * 2; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - - if (buf->vb.size != size) - saa7134_dma_free(q,buf); - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - buf->vb.width = llength; - buf->vb.height = lines; - buf->vb.size = size; - buf->pt = &fh->pt_vbi; - - err = videobuf_iolock(q,&buf->vb,NULL); - if (err) - goto oops; - err = saa7134_pgtable_build(dev->pci,buf->pt, - dma->sglist, - dma->sglen, - saa7134_buffer_startpage(buf)); - if (err) - goto oops; - } - buf->vb.state = VIDEOBUF_PREPARED; - buf->activate = buffer_activate; - buf->vb.field = field; - return 0; - - oops: - saa7134_dma_free(q,buf); - return err; -} - -static int -buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct saa7134_fh *fh = q->priv_data; - struct saa7134_dev *dev = fh->dev; - int llength,lines; - - lines = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1; - llength = VBI_LINE_LENGTH; - *size = lines * llength * 2; - if (0 == *count) - *count = vbibufs; - *count = saa7134_buffer_count(*size,*count); - return 0; -} - -static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct saa7134_fh *fh = q->priv_data; - struct saa7134_dev *dev = fh->dev; - struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); - - saa7134_buffer_queue(dev,&dev->vbi_q,buf); -} - -static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); - - saa7134_dma_free(q,buf); -} - -struct videobuf_queue_ops saa7134_vbi_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ */ - -int saa7134_vbi_init1(struct saa7134_dev *dev) -{ - INIT_LIST_HEAD(&dev->vbi_q.queue); - init_timer(&dev->vbi_q.timeout); - dev->vbi_q.timeout.function = saa7134_buffer_timeout; - dev->vbi_q.timeout.data = (unsigned long)(&dev->vbi_q); - dev->vbi_q.dev = dev; - - if (vbibufs < 2) - vbibufs = 2; - if (vbibufs > VIDEO_MAX_FRAME) - vbibufs = VIDEO_MAX_FRAME; - return 0; -} - -int saa7134_vbi_fini(struct saa7134_dev *dev) -{ - /* nothing */ - return 0; -} - -void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status) -{ - spin_lock(&dev->slock); - if (dev->vbi_q.curr) { - dev->vbi_fieldcount++; - /* make sure we have seen both fields */ - if ((status & 0x10) == 0x00) { - dev->vbi_q.curr->top_seen = 1; - goto done; - } - if (!dev->vbi_q.curr->top_seen) - goto done; - - dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount; - saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE); - } - saa7134_buffer_next(dev,&dev->vbi_q); - - done: - spin_unlock(&dev->slock); -} - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7134/saa7134-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2661 +0,0 @@ -/* - * - * device driver for philips saa7134 based TV cards - * video4linux video interface - * - * (c) 2001-03 Gerd Knorr [SuSE Labs] - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" -#include -#include - -/* ------------------------------------------------------------------ */ - -unsigned int video_debug; -static unsigned int gbuffers = 8; -static unsigned int noninterlaced; /* 0 */ -static unsigned int gbufsize = 720*576*4; -static unsigned int gbufsize_max = 720*576*4; -static char secam[] = "--"; -module_param(video_debug, int, 0644); -MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); -module_param(gbuffers, int, 0444); -MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); -module_param(noninterlaced, int, 0644); -MODULE_PARM_DESC(noninterlaced,"capture non interlaced video"); -module_param_string(secam, secam, sizeof(secam), 0644); -MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); - - -#define dprintk(fmt, arg...) if (video_debug&0x04) \ - printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) - -/* ------------------------------------------------------------------ */ -/* Defines for Video Output Port Register at address 0x191 */ - -/* Bit 0: VIP code T bit polarity */ - -#define VP_T_CODE_P_NON_INVERTED 0x00 -#define VP_T_CODE_P_INVERTED 0x01 - -/* ------------------------------------------------------------------ */ -/* Defines for Video Output Port Register at address 0x195 */ - -/* Bit 2: Video output clock delay control */ - -#define VP_CLK_CTRL2_NOT_DELAYED 0x00 -#define VP_CLK_CTRL2_DELAYED 0x04 - -/* Bit 1: Video output clock invert control */ - -#define VP_CLK_CTRL1_NON_INVERTED 0x00 -#define VP_CLK_CTRL1_INVERTED 0x02 - -/* ------------------------------------------------------------------ */ -/* Defines for Video Output Port Register at address 0x196 */ - -/* Bits 2 to 0: VSYNC pin video vertical sync type */ - -#define VP_VS_TYPE_MASK 0x07 - -#define VP_VS_TYPE_OFF 0x00 -#define VP_VS_TYPE_V123 0x01 -#define VP_VS_TYPE_V_ITU 0x02 -#define VP_VS_TYPE_VGATE_L 0x03 -#define VP_VS_TYPE_RESERVED1 0x04 -#define VP_VS_TYPE_RESERVED2 0x05 -#define VP_VS_TYPE_F_ITU 0x06 -#define VP_VS_TYPE_SC_FID 0x07 - -/* ------------------------------------------------------------------ */ -/* data structs for video */ - -static int video_out[][9] = { - [CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 }, -}; - -static struct saa7134_format formats[] = { - { - .name = "8 bpp gray", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8, - .pm = 0x06, - },{ - .name = "15 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .depth = 16, - .pm = 0x13 | 0x80, - },{ - .name = "15 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB555X, - .depth = 16, - .pm = 0x13 | 0x80, - .bswap = 1, - },{ - .name = "16 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB565, - .depth = 16, - .pm = 0x10 | 0x80, - },{ - .name = "16 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB565X, - .depth = 16, - .pm = 0x10 | 0x80, - .bswap = 1, - },{ - .name = "24 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR24, - .depth = 24, - .pm = 0x11, - },{ - .name = "24 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB24, - .depth = 24, - .pm = 0x11, - .bswap = 1, - },{ - .name = "32 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR32, - .depth = 32, - .pm = 0x12, - },{ - .name = "32 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB32, - .depth = 32, - .pm = 0x12, - .bswap = 1, - .wswap = 1, - },{ - .name = "4:2:2 packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .pm = 0x00, - .bswap = 1, - .yuv = 1, - },{ - .name = "4:2:2 packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .pm = 0x00, - .yuv = 1, - },{ - .name = "4:2:2 planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV422P, - .depth = 16, - .pm = 0x09, - .yuv = 1, - .planar = 1, - .hshift = 1, - .vshift = 0, - },{ - .name = "4:2:0 planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV420, - .depth = 12, - .pm = 0x0a, - .yuv = 1, - .planar = 1, - .hshift = 1, - .vshift = 1, - },{ - .name = "4:2:0 planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YVU420, - .depth = 12, - .pm = 0x0a, - .yuv = 1, - .planar = 1, - .uvswap = 1, - .hshift = 1, - .vshift = 1, - } -}; -#define FORMATS ARRAY_SIZE(formats) - -#define NORM_625_50 \ - .h_start = 0, \ - .h_stop = 719, \ - .video_v_start = 24, \ - .video_v_stop = 311, \ - .vbi_v_start_0 = 7, \ - .vbi_v_stop_0 = 22, \ - .vbi_v_start_1 = 319, \ - .src_timing = 4 - -#define NORM_525_60 \ - .h_start = 0, \ - .h_stop = 719, \ - .video_v_start = 23, \ - .video_v_stop = 262, \ - .vbi_v_start_0 = 10, \ - .vbi_v_stop_0 = 21, \ - .vbi_v_start_1 = 273, \ - .src_timing = 7 - -static struct saa7134_tvnorm tvnorms[] = { - { - .name = "PAL", /* autodetect */ - .id = V4L2_STD_PAL, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - - },{ - .name = "PAL-BG", - .id = V4L2_STD_PAL_BG, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - - },{ - .name = "PAL-I", - .id = V4L2_STD_PAL_I, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - - },{ - .name = "PAL-DK", - .id = V4L2_STD_PAL_DK, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - - },{ - .name = "NTSC", - .id = V4L2_STD_NTSC, - NORM_525_60, - - .sync_control = 0x59, - .luma_control = 0x40, - .chroma_ctrl1 = 0x89, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x0e, - .vgate_misc = 0x18, - - },{ - .name = "SECAM", - .id = V4L2_STD_SECAM, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - - },{ - .name = "SECAM-DK", - .id = V4L2_STD_SECAM_DK, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - - },{ - .name = "SECAM-L", - .id = V4L2_STD_SECAM_L, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - - },{ - .name = "SECAM-Lc", - .id = V4L2_STD_SECAM_LC, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - - },{ - .name = "PAL-M", - .id = V4L2_STD_PAL_M, - NORM_525_60, - - .sync_control = 0x59, - .luma_control = 0x40, - .chroma_ctrl1 = 0xb9, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x0e, - .vgate_misc = 0x18, - - },{ - .name = "PAL-Nc", - .id = V4L2_STD_PAL_Nc, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0xa1, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - - },{ - .name = "PAL-60", - .id = V4L2_STD_PAL_60, - - .h_start = 0, - .h_stop = 719, - .video_v_start = 23, - .video_v_stop = 262, - .vbi_v_start_0 = 10, - .vbi_v_stop_0 = 21, - .vbi_v_start_1 = 273, - .src_timing = 7, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - } -}; -#define TVNORMS ARRAY_SIZE(tvnorms) - -#define V4L2_CID_PRIVATE_INVERT (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 4) - -static const struct v4l2_queryctrl no_ctrl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; -static const struct v4l2_queryctrl video_ctrls[] = { - /* --- video --- */ - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 68, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = -128, - .maximum = 127, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_HFLIP, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - /* --- audio --- */ - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = -15, - .maximum = 15, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - /* --- private --- */ - { - .id = V4L2_CID_PRIVATE_INVERT, - .name = "Invert", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_Y_ODD, - .name = "y offset odd field", - .minimum = 0, - .maximum = 128, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_Y_EVEN, - .name = "y offset even field", - .minimum = 0, - .maximum = 128, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_AUTOMUTE, - .name = "automute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - } -}; -static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); - -static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id) -{ - unsigned int i; - - for (i = 0; i < CTRLS; i++) - if (video_ctrls[i].id == id) - return video_ctrls+i; - return NULL; -} - -static struct saa7134_format* format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < FORMATS; i++) - if (formats[i].fourcc == fourcc) - return formats+i; - return NULL; -} - -/* ----------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit) -{ - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources & bit) { - /* no, someone else uses it */ - mutex_unlock(&dev->lock); - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk("res: get %d\n",bit); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_check(struct saa7134_fh *fh, unsigned int bit) -{ - return (fh->resources & bit); -} - -static int res_locked(struct saa7134_dev *dev, unsigned int bit) -{ - return (dev->resources & bit); -} - -static -void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) -{ - BUG_ON((fh->resources & bits) != bits); - - mutex_lock(&dev->lock); - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk("res: put %d\n",bits); - mutex_unlock(&dev->lock); -} - -/* ------------------------------------------------------------------ */ - -static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) -{ - dprintk("set tv norm = %s\n",norm->name); - dev->tvnorm = norm; - - /* setup cropping */ - dev->crop_bounds.left = norm->h_start; - dev->crop_defrect.left = norm->h_start; - dev->crop_bounds.width = norm->h_stop - norm->h_start +1; - dev->crop_defrect.width = norm->h_stop - norm->h_start +1; - - dev->crop_bounds.top = (norm->vbi_v_stop_0+1)*2; - dev->crop_defrect.top = norm->video_v_start*2; - dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624) - - dev->crop_bounds.top; - dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2; - - dev->crop_current = dev->crop_defrect; - - saa7134_set_tvnorm_hw(dev); -} - -static void video_mux(struct saa7134_dev *dev, int input) -{ - dprintk("video input = %d [%s]\n", input, card_in(dev, input).name); - dev->ctl_input = input; - set_tvnorm(dev, dev->tvnorm); - saa7134_tvaudio_setinput(dev, &card_in(dev, input)); -} - - -static void saa7134_set_decoder(struct saa7134_dev *dev) -{ - int luma_control, sync_control, mux; - - struct saa7134_tvnorm *norm = dev->tvnorm; - mux = card_in(dev, dev->ctl_input).vmux; - - luma_control = norm->luma_control; - sync_control = norm->sync_control; - - if (mux > 5) - luma_control |= 0x80; /* svideo */ - if (noninterlaced || dev->nosignal) - sync_control |= 0x20; - - /* setup video decoder */ - saa_writeb(SAA7134_INCR_DELAY, 0x08); - saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); - saa_writeb(SAA7134_ANALOG_IN_CTRL2, 0x00); - - saa_writeb(SAA7134_ANALOG_IN_CTRL3, 0x90); - saa_writeb(SAA7134_ANALOG_IN_CTRL4, 0x90); - saa_writeb(SAA7134_HSYNC_START, 0xeb); - saa_writeb(SAA7134_HSYNC_STOP, 0xe0); - saa_writeb(SAA7134_SOURCE_TIMING1, norm->src_timing); - - saa_writeb(SAA7134_SYNC_CTRL, sync_control); - saa_writeb(SAA7134_LUMA_CTRL, luma_control); - saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); - - saa_writeb(SAA7134_DEC_LUMA_CONTRAST, - dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); - - saa_writeb(SAA7134_DEC_CHROMA_SATURATION, - dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); - - saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); - saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); - saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); - - saa_writeb(SAA7134_CHROMA_CTRL2, norm->chroma_ctrl2); - saa_writeb(SAA7134_MODE_DELAY_CTRL, 0x00); - - saa_writeb(SAA7134_ANALOG_ADC, 0x01); - saa_writeb(SAA7134_VGATE_START, 0x11); - saa_writeb(SAA7134_VGATE_STOP, 0xfe); - saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc); - saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); - saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); -} - -void saa7134_set_tvnorm_hw(struct saa7134_dev *dev) -{ - saa7134_set_decoder(dev); - - if (card_in(dev, dev->ctl_input).tv) - saa_call_all(dev, core, s_std, dev->tvnorm->id); - /* Set the correct norm for the saa6752hs. This function - does nothing if there is no saa6752hs. */ - saa_call_empress(dev, core, s_std, dev->tvnorm->id); -} - -static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) -{ - static const struct { - int xpsc; - int xacl; - int xc2_1; - int xdcg; - int vpfy; - } vals[] = { - /* XPSC XACL XC2_1 XDCG VPFY */ - { 1, 0, 0, 0, 0 }, - { 2, 2, 1, 2, 2 }, - { 3, 4, 1, 3, 2 }, - { 4, 8, 1, 4, 2 }, - { 5, 8, 1, 4, 2 }, - { 6, 8, 1, 4, 3 }, - { 7, 8, 1, 4, 3 }, - { 8, 15, 0, 4, 3 }, - { 9, 15, 0, 4, 3 }, - { 10, 16, 1, 5, 3 }, - }; - static const int count = ARRAY_SIZE(vals); - int i; - - for (i = 0; i < count; i++) - if (vals[i].xpsc == prescale) - break; - if (i == count) - return; - - saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc); - saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl); - saa_writeb(SAA7134_LEVEL_CTRL(task), - (vals[i].xc2_1 << 3) | (vals[i].xdcg)); - saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f, - (vals[i].vpfy << 2) | vals[i].vpfy); -} - -static void set_v_scale(struct saa7134_dev *dev, int task, int yscale) -{ - int val,mirror; - - saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale & 0xff); - saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8); - - mirror = (dev->ctl_mirror) ? 0x02 : 0x00; - if (yscale < 2048) { - /* LPI */ - dprintk("yscale LPI yscale=%d\n",yscale); - saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror); - saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40); - saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40); - } else { - /* ACM */ - val = 0x40 * 1024 / yscale; - dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val); - saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror); - saa_writeb(SAA7134_LUMA_CONTRAST(task), val); - saa_writeb(SAA7134_CHROMA_SATURATION(task), val); - } - saa_writeb(SAA7134_LUMA_BRIGHT(task), 0x80); -} - -static void set_size(struct saa7134_dev *dev, int task, - int width, int height, int interlace) -{ - int prescale,xscale,yscale,y_even,y_odd; - int h_start, h_stop, v_start, v_stop; - int div = interlace ? 2 : 1; - - /* setup video scaler */ - h_start = dev->crop_current.left; - v_start = dev->crop_current.top/2; - h_stop = (dev->crop_current.left + dev->crop_current.width -1); - v_stop = (dev->crop_current.top + dev->crop_current.height -1)/2; - - saa_writeb(SAA7134_VIDEO_H_START1(task), h_start & 0xff); - saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8); - saa_writeb(SAA7134_VIDEO_H_STOP1(task), h_stop & 0xff); - saa_writeb(SAA7134_VIDEO_H_STOP2(task), h_stop >> 8); - saa_writeb(SAA7134_VIDEO_V_START1(task), v_start & 0xff); - saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8); - saa_writeb(SAA7134_VIDEO_V_STOP1(task), v_stop & 0xff); - saa_writeb(SAA7134_VIDEO_V_STOP2(task), v_stop >> 8); - - prescale = dev->crop_current.width / width; - if (0 == prescale) - prescale = 1; - xscale = 1024 * dev->crop_current.width / prescale / width; - yscale = 512 * div * dev->crop_current.height / height; - dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); - set_h_prescale(dev,task,prescale); - saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); - saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); - set_v_scale(dev,task,yscale); - - saa_writeb(SAA7134_VIDEO_PIXELS1(task), width & 0xff); - saa_writeb(SAA7134_VIDEO_PIXELS2(task), width >> 8); - saa_writeb(SAA7134_VIDEO_LINES1(task), height/div & 0xff); - saa_writeb(SAA7134_VIDEO_LINES2(task), height/div >> 8); - - /* deinterlace y offsets */ - y_odd = dev->ctl_y_odd; - y_even = dev->ctl_y_even; - saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd); - saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even); - saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd); - saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even); -} - -/* ------------------------------------------------------------------ */ - -struct cliplist { - __u16 position; - __u8 enable; - __u8 disable; -}; - -static void set_cliplist(struct saa7134_dev *dev, int reg, - struct cliplist *cl, int entries, char *name) -{ - __u8 winbits = 0; - int i; - - for (i = 0; i < entries; i++) { - winbits |= cl[i].enable; - winbits &= ~cl[i].disable; - if (i < 15 && cl[i].position == cl[i+1].position) - continue; - saa_writeb(reg + 0, winbits); - saa_writeb(reg + 2, cl[i].position & 0xff); - saa_writeb(reg + 3, cl[i].position >> 8); - dprintk("clip: %s winbits=%02x pos=%d\n", - name,winbits,cl[i].position); - reg += 8; - } - for (; reg < 0x400; reg += 8) { - saa_writeb(reg+ 0, 0); - saa_writeb(reg + 1, 0); - saa_writeb(reg + 2, 0); - saa_writeb(reg + 3, 0); - } -} - -static int clip_range(int val) -{ - if (val < 0) - val = 0; - return val; -} - -/* Sort into smallest position first order */ -static int cliplist_cmp(const void *a, const void *b) -{ - const struct cliplist *cla = a; - const struct cliplist *clb = b; - if (cla->position < clb->position) - return -1; - if (cla->position > clb->position) - return 1; - return 0; -} - -static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, - int nclips, int interlace) -{ - struct cliplist col[16], row[16]; - int cols = 0, rows = 0, i; - int div = interlace ? 2 : 1; - - memset(col, 0, sizeof(col)); - memset(row, 0, sizeof(row)); - for (i = 0; i < nclips && i < 8; i++) { - col[cols].position = clip_range(clips[i].c.left); - col[cols].enable = (1 << i); - cols++; - col[cols].position = clip_range(clips[i].c.left+clips[i].c.width); - col[cols].disable = (1 << i); - cols++; - row[rows].position = clip_range(clips[i].c.top / div); - row[rows].enable = (1 << i); - rows++; - row[rows].position = clip_range((clips[i].c.top + clips[i].c.height) - / div); - row[rows].disable = (1 << i); - rows++; - } - sort(col, cols, sizeof col[0], cliplist_cmp, NULL); - sort(row, rows, sizeof row[0], cliplist_cmp, NULL); - set_cliplist(dev,0x380,col,cols,"cols"); - set_cliplist(dev,0x384,row,rows,"rows"); - return 0; -} - -static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win) -{ - enum v4l2_field field; - int maxw, maxh; - - if (NULL == dev->ovbuf.base) - return -EINVAL; - if (NULL == dev->ovfmt) - return -EINVAL; - if (win->w.width < 48 || win->w.height < 32) - return -EINVAL; - if (win->clipcount > 2048) - return -EINVAL; - - field = win->field; - maxw = dev->crop_current.width; - maxh = dev->crop_current.height; - - if (V4L2_FIELD_ANY == field) { - field = (win->w.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - win->field = field; - if (win->w.width > maxw) - win->w.width = maxw; - if (win->w.height > maxh) - win->w.height = maxh; - return 0; -} - -static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) -{ - unsigned long base,control,bpl; - int err; - - err = verify_preview(dev,&fh->win); - if (0 != err) - return err; - - dev->ovfield = fh->win.field; - dprintk("start_preview %dx%d+%d+%d %s field=%s\n", - fh->win.w.width,fh->win.w.height, - fh->win.w.left,fh->win.w.top, - dev->ovfmt->name,v4l2_field_names[dev->ovfield]); - - /* setup window + clipping */ - set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height, - V4L2_FIELD_HAS_BOTH(dev->ovfield)); - setup_clipping(dev,fh->clips,fh->nclips, - V4L2_FIELD_HAS_BOTH(dev->ovfield)); - if (dev->ovfmt->yuv) - saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03); - else - saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01); - saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20); - - /* dma: setup channel 1 (= Video Task B) */ - base = (unsigned long)dev->ovbuf.base; - base += dev->ovbuf.fmt.bytesperline * fh->win.w.top; - base += dev->ovfmt->depth/8 * fh->win.w.left; - bpl = dev->ovbuf.fmt.bytesperline; - control = SAA7134_RS_CONTROL_BURST_16; - if (dev->ovfmt->bswap) - control |= SAA7134_RS_CONTROL_BSWAP; - if (dev->ovfmt->wswap) - control |= SAA7134_RS_CONTROL_WSWAP; - if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) { - saa_writel(SAA7134_RS_BA1(1),base); - saa_writel(SAA7134_RS_BA2(1),base+bpl); - saa_writel(SAA7134_RS_PITCH(1),bpl*2); - saa_writel(SAA7134_RS_CONTROL(1),control); - } else { - saa_writel(SAA7134_RS_BA1(1),base); - saa_writel(SAA7134_RS_BA2(1),base); - saa_writel(SAA7134_RS_PITCH(1),bpl); - saa_writel(SAA7134_RS_CONTROL(1),control); - } - - /* start dma */ - dev->ovenable = 1; - saa7134_set_dmabits(dev); - - return 0; -} - -static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) -{ - dev->ovenable = 0; - saa7134_set_dmabits(dev); - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int buffer_activate(struct saa7134_dev *dev, - struct saa7134_buf *buf, - struct saa7134_buf *next) -{ - unsigned long base,control,bpl; - unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ - - dprintk("buffer_activate buf=%p\n",buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->top_seen = 0; - - set_size(dev,TASK_A,buf->vb.width,buf->vb.height, - V4L2_FIELD_HAS_BOTH(buf->vb.field)); - if (buf->fmt->yuv) - saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03); - else - saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01); - saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm); - - /* DMA: setup channel 0 (= Video Task A0) */ - base = saa7134_buffer_base(buf); - if (buf->fmt->planar) - bpl = buf->vb.width; - else - bpl = (buf->vb.width * buf->fmt->depth) / 8; - control = SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (buf->pt->dma >> 12); - if (buf->fmt->bswap) - control |= SAA7134_RS_CONTROL_BSWAP; - if (buf->fmt->wswap) - control |= SAA7134_RS_CONTROL_WSWAP; - if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { - /* interlaced */ - saa_writel(SAA7134_RS_BA1(0),base); - saa_writel(SAA7134_RS_BA2(0),base+bpl); - saa_writel(SAA7134_RS_PITCH(0),bpl*2); - } else { - /* non-interlaced */ - saa_writel(SAA7134_RS_BA1(0),base); - saa_writel(SAA7134_RS_BA2(0),base); - saa_writel(SAA7134_RS_PITCH(0),bpl); - } - saa_writel(SAA7134_RS_CONTROL(0),control); - - if (buf->fmt->planar) { - /* DMA: setup channel 4+5 (= planar task A) */ - bpl_uv = bpl >> buf->fmt->hshift; - lines_uv = buf->vb.height >> buf->fmt->vshift; - base2 = base + bpl * buf->vb.height; - base3 = base2 + bpl_uv * lines_uv; - if (buf->fmt->uvswap) - tmp = base2, base2 = base3, base3 = tmp; - dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", - bpl_uv,lines_uv,base2,base3); - if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { - /* interlaced */ - saa_writel(SAA7134_RS_BA1(4),base2); - saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv); - saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2); - saa_writel(SAA7134_RS_BA1(5),base3); - saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv); - saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2); - } else { - /* non-interlaced */ - saa_writel(SAA7134_RS_BA1(4),base2); - saa_writel(SAA7134_RS_BA2(4),base2); - saa_writel(SAA7134_RS_PITCH(4),bpl_uv); - saa_writel(SAA7134_RS_BA1(5),base3); - saa_writel(SAA7134_RS_BA2(5),base3); - saa_writel(SAA7134_RS_PITCH(5),bpl_uv); - } - saa_writel(SAA7134_RS_CONTROL(4),control); - saa_writel(SAA7134_RS_CONTROL(5),control); - } - - /* start DMA */ - saa7134_set_dmabits(dev); - mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); - return 0; -} - -static int buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct saa7134_fh *fh = q->priv_data; - struct saa7134_dev *dev = fh->dev; - struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); - unsigned int size; - int err; - - /* sanity checks */ - if (NULL == fh->fmt) - return -EINVAL; - if (fh->width < 48 || - fh->height < 32 || - fh->width/4 > dev->crop_current.width || - fh->height/4 > dev->crop_current.height || - fh->width > dev->crop_bounds.width || - fh->height > dev->crop_bounds.height) - return -EINVAL; - size = (fh->width * fh->height * fh->fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - - dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n", - vb->i,fh->width,fh->height,size,v4l2_field_names[field], - fh->fmt->name); - if (buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.size != size || - buf->vb.field != field || - buf->fmt != fh->fmt) { - saa7134_dma_free(q,buf); - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.size = size; - buf->vb.field = field; - buf->fmt = fh->fmt; - buf->pt = &fh->pt_cap; - dev->video_q.curr = NULL; - - err = videobuf_iolock(q,&buf->vb,&dev->ovbuf); - if (err) - goto oops; - err = saa7134_pgtable_build(dev->pci,buf->pt, - dma->sglist, - dma->sglen, - saa7134_buffer_startpage(buf)); - if (err) - goto oops; - } - buf->vb.state = VIDEOBUF_PREPARED; - buf->activate = buffer_activate; - return 0; - - oops: - saa7134_dma_free(q,buf); - return err; -} - -static int -buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct saa7134_fh *fh = q->priv_data; - - *size = fh->fmt->depth * fh->width * fh->height >> 3; - if (0 == *count) - *count = gbuffers; - *count = saa7134_buffer_count(*size,*count); - return 0; -} - -static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct saa7134_fh *fh = q->priv_data; - struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); - - saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf); -} - -static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); - - saa7134_dma_free(q,buf); -} - -static struct videobuf_queue_ops video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ */ - -int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) -{ - const struct v4l2_queryctrl* ctrl; - - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) - return -EINVAL; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = dev->ctl_bright; - break; - case V4L2_CID_HUE: - c->value = dev->ctl_hue; - break; - case V4L2_CID_CONTRAST: - c->value = dev->ctl_contrast; - break; - case V4L2_CID_SATURATION: - c->value = dev->ctl_saturation; - break; - case V4L2_CID_AUDIO_MUTE: - c->value = dev->ctl_mute; - break; - case V4L2_CID_AUDIO_VOLUME: - c->value = dev->ctl_volume; - break; - case V4L2_CID_PRIVATE_INVERT: - c->value = dev->ctl_invert; - break; - case V4L2_CID_HFLIP: - c->value = dev->ctl_mirror; - break; - case V4L2_CID_PRIVATE_Y_EVEN: - c->value = dev->ctl_y_even; - break; - case V4L2_CID_PRIVATE_Y_ODD: - c->value = dev->ctl_y_odd; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - c->value = dev->ctl_automute; - break; - default: - return -EINVAL; - } - return 0; -} -EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal); - -static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) -{ - struct saa7134_fh *fh = priv; - - return saa7134_g_ctrl_internal(fh->dev, fh, c); -} - -int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) -{ - const struct v4l2_queryctrl* ctrl; - unsigned long flags; - int restart_overlay = 0; - int err; - - /* When called from the empress code fh == NULL. - That needs to be fixed somehow, but for now this is - good enough. */ - if (fh) { - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; - } - err = -EINVAL; - - mutex_lock(&dev->lock); - - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) - goto error; - - dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); - switch (ctrl->type) { - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER: - if (c->value < ctrl->minimum) - c->value = ctrl->minimum; - if (c->value > ctrl->maximum) - c->value = ctrl->maximum; - break; - default: - /* nothing */; - }; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - dev->ctl_bright = c->value; - saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); - break; - case V4L2_CID_HUE: - dev->ctl_hue = c->value; - saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); - break; - case V4L2_CID_CONTRAST: - dev->ctl_contrast = c->value; - saa_writeb(SAA7134_DEC_LUMA_CONTRAST, - dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); - break; - case V4L2_CID_SATURATION: - dev->ctl_saturation = c->value; - saa_writeb(SAA7134_DEC_CHROMA_SATURATION, - dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); - break; - case V4L2_CID_AUDIO_MUTE: - dev->ctl_mute = c->value; - saa7134_tvaudio_setmute(dev); - break; - case V4L2_CID_AUDIO_VOLUME: - dev->ctl_volume = c->value; - saa7134_tvaudio_setvolume(dev,dev->ctl_volume); - break; - case V4L2_CID_PRIVATE_INVERT: - dev->ctl_invert = c->value; - saa_writeb(SAA7134_DEC_LUMA_CONTRAST, - dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); - saa_writeb(SAA7134_DEC_CHROMA_SATURATION, - dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); - break; - case V4L2_CID_HFLIP: - dev->ctl_mirror = c->value; - restart_overlay = 1; - break; - case V4L2_CID_PRIVATE_Y_EVEN: - dev->ctl_y_even = c->value; - restart_overlay = 1; - break; - case V4L2_CID_PRIVATE_Y_ODD: - dev->ctl_y_odd = c->value; - restart_overlay = 1; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - dev->ctl_automute = c->value; - if (dev->tda9887_conf) { - if (dev->ctl_automute) - dev->tda9887_conf |= TDA9887_AUTOMUTE; - else - dev->tda9887_conf &= ~TDA9887_AUTOMUTE; - - saa_call_all(dev, tuner, s_config, &tda9887_cfg); - } - break; - } - default: - goto error; - } - if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock,flags); - stop_preview(dev,fh); - start_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - } - err = 0; - -error: - mutex_unlock(&dev->lock); - return err; -} -EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal); - -static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) -{ - struct saa7134_fh *fh = f; - - return saa7134_s_ctrl_internal(fh->dev, fh, c); -} - -/* ------------------------------------------------------------------ */ - -static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) -{ - struct videobuf_queue* q = NULL; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - q = &fh->cap; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - q = &fh->vbi; - break; - default: - BUG(); - } - return q; -} - -static int saa7134_resource(struct saa7134_fh *fh) -{ - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return RESOURCE_VIDEO; - - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - return RESOURCE_VBI; - - BUG(); - return 0; -} - -static int video_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct saa7134_dev *dev = video_drvdata(file); - struct saa7134_fh *fh; - enum v4l2_buf_type type = 0; - int radio = 0; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - } - - dprintk("open dev=%s radio=%d type=%s\n", video_device_node_name(vdev), - radio, v4l2_type_names[type]); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - fh->type = type; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - fh->width = 720; - fh->height = 576; - v4l2_prio_open(&dev->prio, &fh->prio); - - videobuf_queue_sg_init(&fh->cap, &video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct saa7134_buf), - fh, NULL); - videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct saa7134_buf), - fh, NULL); - saa7134_pgtable_alloc(dev->pci,&fh->pt_cap); - saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi); - - if (fh->radio) { - /* switch to radio mode */ - saa7134_tvaudio_setinput(dev,&card(dev).radio); - saa_call_all(dev, tuner, s_radio); - } else { - /* switch to video/vbi mode */ - video_mux(dev,dev->ctl_input); - } - return 0; -} - -static ssize_t -video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct saa7134_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (res_locked(fh->dev,RESOURCE_VIDEO)) - return -EBUSY; - return videobuf_read_one(saa7134_queue(fh), - data, count, ppos, - file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (!res_get(fh->dev,fh,RESOURCE_VBI)) - return -EBUSY; - return videobuf_read_stream(saa7134_queue(fh), - data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - break; - default: - BUG(); - return 0; - } -} - -static unsigned int -video_poll(struct file *file, struct poll_table_struct *wait) -{ - struct saa7134_fh *fh = file->private_data; - struct videobuf_buffer *buf = NULL; - unsigned int rc = 0; - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) - return videobuf_poll_stream(file, &fh->vbi, wait); - - if (res_check(fh,RESOURCE_VIDEO)) { - mutex_lock(&fh->cap.vb_lock); - if (!list_empty(&fh->cap.stream)) - buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); - } else { - mutex_lock(&fh->cap.vb_lock); - if (UNSET == fh->cap.read_off) { - /* need to capture a new frame */ - if (res_locked(fh->dev,RESOURCE_VIDEO)) - goto err; - if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) - goto err; - fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); - fh->cap.read_off = 0; - } - buf = fh->cap.read_buf; - } - - if (!buf) - goto err; - - poll_wait(file, &buf->done, wait); - if (buf->state == VIDEOBUF_DONE || - buf->state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - mutex_unlock(&fh->cap.vb_lock); - return rc; - -err: - mutex_unlock(&fh->cap.vb_lock); - return POLLERR; -} - -static int video_release(struct file *file) -{ - struct saa7134_fh *fh = file->private_data; - struct saa7134_dev *dev = fh->dev; - struct saa6588_command cmd; - unsigned long flags; - - /* turn off overlay */ - if (res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock,flags); - stop_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - res_free(dev,fh,RESOURCE_OVERLAY); - } - - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_streamoff(&fh->cap); - res_free(dev,fh,RESOURCE_VIDEO); - } - if (fh->cap.read_buf) { - buffer_release(&fh->cap,fh->cap.read_buf); - kfree(fh->cap.read_buf); - } - - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - videobuf_stop(&fh->vbi); - res_free(dev,fh,RESOURCE_VBI); - } - - /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ - saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0); - saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0); - saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); - saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); - - saa_call_all(dev, core, s_power, 0); - if (fh->radio) - saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd); - - /* free stuff */ - videobuf_mmap_free(&fh->cap); - videobuf_mmap_free(&fh->vbi); - saa7134_pgtable_free(dev->pci,&fh->pt_cap); - saa7134_pgtable_free(dev->pci,&fh->pt_vbi); - - v4l2_prio_close(&dev->prio, fh->prio); - file->private_data = NULL; - kfree(fh); - return 0; -} - -static int video_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct saa7134_fh *fh = file->private_data; - - return videobuf_mmap_mapper(saa7134_queue(fh), vma); -} - -static ssize_t radio_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct saa7134_fh *fh = file->private_data; - struct saa7134_dev *dev = fh->dev; - struct saa6588_command cmd; - - cmd.block_count = count/3; - cmd.buffer = data; - cmd.instance = file; - cmd.result = -ENODEV; - - saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd); - - return cmd.result; -} - -static unsigned int radio_poll(struct file *file, poll_table *wait) -{ - struct saa7134_fh *fh = file->private_data; - struct saa7134_dev *dev = fh->dev; - struct saa6588_command cmd; - - cmd.instance = file; - cmd.event_list = wait; - cmd.result = -ENODEV; - saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd); - - return cmd.result; -} - -/* ------------------------------------------------------------------ */ - -static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - struct saa7134_tvnorm *norm = dev->tvnorm; - - f->fmt.vbi.sampling_rate = 6750000 * 4; - f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; - f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 64 * 4; - f->fmt.vbi.start[0] = norm->vbi_v_start_0; - f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1; - f->fmt.vbi.start[1] = norm->vbi_v_start_1; - f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; - f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ - - return 0; -} - -static int saa7134_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; -} - -static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - - if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - f->fmt.win = fh->win; - - return 0; -} - -static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - struct saa7134_format *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); - maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); - - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - f->fmt.pix.field = field; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - - return verify_preview(dev, &f->fmt.win); -} - -static int saa7134_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - int err; - - err = saa7134_try_fmt_vid_cap(file, priv, f); - if (0 != err) - return err; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->cap.field = f->fmt.pix.field; - return 0; -} - -static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int err; - unsigned long flags; - - if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - err = verify_preview(dev, &f->fmt.win); - if (0 != err) - return err; - - mutex_lock(&dev->lock); - - fh->win = f->fmt.win; - fh->nclips = f->fmt.win.clipcount; - - if (fh->nclips > 8) - fh->nclips = 8; - - if (copy_from_user(fh->clips, f->fmt.win.clips, - sizeof(struct v4l2_clip)*fh->nclips)) { - mutex_unlock(&dev->lock); - return -EFAULT; - } - - if (res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock, flags); - stop_preview(dev, fh); - start_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - } - - mutex_unlock(&dev->lock); - return 0; -} - -int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - ctrl = ctrl_by_id(c->id); - *c = (NULL != ctrl) ? *ctrl : no_ctrl; - return 0; -} -EXPORT_SYMBOL_GPL(saa7134_queryctrl); - -static int saa7134_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - unsigned int n; - - n = i->index; - if (n >= SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev, i->index).name) - return -EINVAL; - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, card_in(dev, n).name); - if (card_in(dev, n).tv) - i->type = V4L2_INPUT_TYPE_TUNER; - i->audioset = 1; - if (n == dev->ctl_input) { - int v1 = saa_readb(SAA7134_STATUS_VIDEO1); - int v2 = saa_readb(SAA7134_STATUS_VIDEO2); - - if (0 != (v1 & 0x40)) - i->status |= V4L2_IN_ST_NO_H_LOCK; - if (0 != (v2 & 0x40)) - i->status |= V4L2_IN_ST_NO_SYNC; - if (0 != (v2 & 0x0e)) - i->status |= V4L2_IN_ST_MACROVISION; - } - i->std = SAA7134_NORMS; - return 0; -} - -static int saa7134_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - *i = dev->ctl_input; - return 0; -} - -static int saa7134_s_input(struct file *file, void *priv, unsigned int i) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int err; - - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; - - if (i >= SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev, i).name) - return -EINVAL; - mutex_lock(&dev->lock); - video_mux(dev, i); - mutex_unlock(&dev->lock); - return 0; -} - -static int saa7134_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - unsigned int tuner_type = dev->tuner_type; - - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; - if (dev->has_rds) - cap->capabilities |= V4L2_CAP_RDS_CAPTURE; - if (saa7134_no_overlay <= 0) - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - - if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) - cap->capabilities &= ~V4L2_CAP_TUNER; - return 0; -} - -int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id) -{ - unsigned long flags; - unsigned int i; - v4l2_std_id fixup; - int err; - - /* When called from the empress code fh == NULL. - That needs to be fixed somehow, but for now this is - good enough. */ - if (fh) { - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; - } else if (res_locked(dev, RESOURCE_OVERLAY)) { - /* Don't change the std from the mpeg device - if overlay is active. */ - return -EBUSY; - } - - for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) - break; - - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) - break; - if (i == TVNORMS) - return -EINVAL; - - if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { - if (secam[0] == 'L' || secam[0] == 'l') { - if (secam[1] == 'C' || secam[1] == 'c') - fixup = V4L2_STD_SECAM_LC; - else - fixup = V4L2_STD_SECAM_L; - } else { - if (secam[0] == 'D' || secam[0] == 'd') - fixup = V4L2_STD_SECAM_DK; - else - fixup = V4L2_STD_SECAM; - } - for (i = 0; i < TVNORMS; i++) { - if (fixup == tvnorms[i].id) - break; - } - if (i == TVNORMS) - return -EINVAL; - } - - *id = tvnorms[i].id; - - mutex_lock(&dev->lock); - if (fh && res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock, flags); - stop_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - - set_tvnorm(dev, &tvnorms[i]); - - spin_lock_irqsave(&dev->slock, flags); - start_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - } else - set_tvnorm(dev, &tvnorms[i]); - - saa7134_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; -} -EXPORT_SYMBOL_GPL(saa7134_s_std_internal); - -static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct saa7134_fh *fh = priv; - - return saa7134_s_std_internal(fh->dev, fh, id); -} - -static int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - *id = dev->tvnorm->id; - return 0; -} - -static int saa7134_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cap) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - cap->bounds = dev->crop_bounds; - cap->defrect = dev->crop_defrect; - cap->pixelaspect.numerator = 1; - cap->pixelaspect.denominator = 1; - if (dev->tvnorm->id & V4L2_STD_525_60) { - cap->pixelaspect.numerator = 11; - cap->pixelaspect.denominator = 10; - } - if (dev->tvnorm->id & V4L2_STD_625_50) { - cap->pixelaspect.numerator = 54; - cap->pixelaspect.denominator = 59; - } - return 0; -} - -static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - crop->c = dev->crop_current; - return 0; -} - -static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - struct v4l2_rect *b = &dev->crop_bounds; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - if (crop->c.height < 0) - return -EINVAL; - if (crop->c.width < 0) - return -EINVAL; - - if (res_locked(fh->dev, RESOURCE_OVERLAY)) - return -EBUSY; - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - - if (crop->c.top < b->top) - crop->c.top = b->top; - if (crop->c.top > b->top + b->height) - crop->c.top = b->top + b->height; - if (crop->c.height > b->top - crop->c.top + b->height) - crop->c.height = b->top - crop->c.top + b->height; - - if (crop->c.left < b->left) - crop->c.left = b->left; - if (crop->c.left > b->left + b->width) - crop->c.left = b->left + b->width; - if (crop->c.width > b->left - crop->c.left + b->width) - crop->c.width = b->left - crop->c.left + b->width; - - dev->crop_current = crop->c; - return 0; -} - -static int saa7134_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int n; - - if (0 != t->index) - return -EINVAL; - memset(t, 0, sizeof(*t)); - for (n = 0; n < SAA7134_INPUT_MAX; n++) { - if (card_in(dev, n).tv) - break; - } - if (n == SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL != card_in(dev, n).name) { - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | - V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2; - t->rangehigh = 0xffffffffUL; - t->rxsubchans = saa7134_tvaudio_getstereo(dev); - t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); - } - if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) - t->signal = 0xffff; - return 0; -} - -static int saa7134_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int rx, mode, err; - - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; - - mode = dev->thread.mode; - if (UNSET == mode) { - rx = saa7134_tvaudio_getstereo(dev); - mode = saa7134_tvaudio_rx2mode(t->rxsubchans); - } - if (mode != t->audmode) - dev->thread.mode = t->audmode; - - return 0; -} - -static int saa7134_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - - return 0; -} - -static int saa7134_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int err; - - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; - - if (0 != f->tuner) - return -EINVAL; - if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) - return -EINVAL; - mutex_lock(&dev->lock); - dev->ctl_freq = f->frequency; - - saa_call_all(dev, tuner, s_frequency, f); - - saa7134_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; -} - -static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - strcpy(a->name, "audio"); - return 0; -} - -static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - return 0; -} - -static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - - *p = v4l2_prio_max(&dev->prio); - return 0; -} - -static int saa7134_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - - return v4l2_prio_change(&dev->prio, &fh->prio, prio); -} - -static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index >= FORMATS) - return -EINVAL; - - strlcpy(f->description, formats[f->index].name, - sizeof(f->description)); - - f->pixelformat = formats[f->index].fourcc; - - return 0; -} - -static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - - if ((f->index >= FORMATS) || formats[f->index].planar) - return -EINVAL; - - strlcpy(f->description, formats[f->index].name, - sizeof(f->description)); - - f->pixelformat = formats[f->index].fourcc; - - return 0; -} - -static int saa7134_g_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - - *fb = dev->ovbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - - return 0; -} - -static int saa7134_s_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - struct saa7134_format *fmt; - - if (!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; - - /* ok, accept it */ - dev->ovbuf = *fb; - dev->ovfmt = fmt; - if (0 == dev->ovbuf.fmt.bytesperline) - dev->ovbuf.fmt.bytesperline = - dev->ovbuf.fmt.width*fmt->depth/8; - return 0; -} - -static int saa7134_overlay(struct file *file, void *f, unsigned int on) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - unsigned long flags; - - if (on) { - if (saa7134_no_overlay > 0) { - dprintk("no_overlay\n"); - return -EINVAL; - } - - if (!res_get(dev, fh, RESOURCE_OVERLAY)) - return -EBUSY; - spin_lock_irqsave(&dev->slock, flags); - start_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - } - if (!on) { - if (!res_check(fh, RESOURCE_OVERLAY)) - return -EINVAL; - spin_lock_irqsave(&dev->slock, flags); - stop_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - res_free(dev, fh, RESOURCE_OVERLAY); - } - return 0; -} - -static int saa7134_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct saa7134_fh *fh = priv; - return videobuf_reqbufs(saa7134_queue(fh), p); -} - -static int saa7134_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - return videobuf_querybuf(saa7134_queue(fh), b); -} - -static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - return videobuf_qbuf(saa7134_queue(fh), b); -} - -static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - return videobuf_dqbuf(saa7134_queue(fh), b, - file->f_flags & O_NONBLOCK); -} - -static int saa7134_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int res = saa7134_resource(fh); - - if (!res_get(dev, fh, res)) - return -EBUSY; - - return videobuf_streamon(saa7134_queue(fh)); -} - -static int saa7134_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - int err; - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int res = saa7134_resource(fh); - - err = videobuf_streamoff(saa7134_queue(fh)); - if (err < 0) - return err; - res_free(dev, fh, res); - return 0; -} - -static int saa7134_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register (struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - reg->val = saa_readb(reg->reg); - reg->size = 1; - return 0; -} - -static int vidioc_s_register (struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - saa_writeb(reg->reg&0xffffff, reg->val); - return 0; -} -#endif - -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct saa7134_fh *fh = file->private_data; - struct saa7134_dev *dev = fh->dev; - - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7134_fh *fh = file->private_data; - struct saa7134_dev *dev = fh->dev; - - if (0 != t->index) - return -EINVAL; - - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - saa_call_all(dev, tuner, g_tuner, t); - if (dev->input->amux == TV) { - t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); - t->rxsubchans = (saa_readb(0x529) & 0x08) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - } - return 0; -} -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7134_fh *fh = file->private_data; - struct saa7134_dev *dev = fh->dev; - - if (0 != t->index) - return -EINVAL; - - saa_call_all(dev, tuner, s_tuner, t); - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - memset(a, 0, sizeof(*a)); - strcpy(a->name, "Radio"); - return 0; -} - -static int radio_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input(struct file *filp, void *priv, unsigned int i) -{ - return 0; -} - -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - return 0; -} - -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctrl; - return 0; -} - -static const struct v4l2_file_operations video_fops = -{ - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = video_mmap, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = saa7134_querycap, - .vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = saa7134_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = saa7134_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_overlay = saa7134_enum_fmt_vid_overlay, - .vidioc_g_fmt_vid_overlay = saa7134_g_fmt_vid_overlay, - .vidioc_try_fmt_vid_overlay = saa7134_try_fmt_vid_overlay, - .vidioc_s_fmt_vid_overlay = saa7134_s_fmt_vid_overlay, - .vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, - .vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, - .vidioc_g_audio = saa7134_g_audio, - .vidioc_s_audio = saa7134_s_audio, - .vidioc_cropcap = saa7134_cropcap, - .vidioc_reqbufs = saa7134_reqbufs, - .vidioc_querybuf = saa7134_querybuf, - .vidioc_qbuf = saa7134_qbuf, - .vidioc_dqbuf = saa7134_dqbuf, - .vidioc_s_std = saa7134_s_std, - .vidioc_g_std = saa7134_g_std, - .vidioc_enum_input = saa7134_enum_input, - .vidioc_g_input = saa7134_g_input, - .vidioc_s_input = saa7134_s_input, - .vidioc_queryctrl = saa7134_queryctrl, - .vidioc_g_ctrl = saa7134_g_ctrl, - .vidioc_s_ctrl = saa7134_s_ctrl, - .vidioc_streamon = saa7134_streamon, - .vidioc_streamoff = saa7134_streamoff, - .vidioc_g_tuner = saa7134_g_tuner, - .vidioc_s_tuner = saa7134_s_tuner, - .vidioc_g_crop = saa7134_g_crop, - .vidioc_s_crop = saa7134_s_crop, - .vidioc_g_fbuf = saa7134_g_fbuf, - .vidioc_s_fbuf = saa7134_s_fbuf, - .vidioc_overlay = saa7134_overlay, - .vidioc_g_priority = saa7134_g_priority, - .vidioc_s_priority = saa7134_s_priority, - .vidioc_g_parm = saa7134_g_parm, - .vidioc_g_frequency = saa7134_g_frequency, - .vidioc_s_frequency = saa7134_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif -}; - -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = video_open, - .read = radio_read, - .release = video_release, - .ioctl = video_ioctl2, - .poll = radio_poll, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_s_std = radio_s_std, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_input = radio_g_input, - .vidioc_g_ctrl = saa7134_g_ctrl, - .vidioc_s_ctrl = saa7134_s_ctrl, - .vidioc_g_frequency = saa7134_g_frequency, - .vidioc_s_frequency = saa7134_s_frequency, -}; - -/* ----------------------------------------------------------- */ -/* exported stuff */ - -struct video_device saa7134_video_template = { - .name = "saa7134-video", - .fops = &video_fops, - .ioctl_ops = &video_ioctl_ops, - .tvnorms = SAA7134_NORMS, - .current_norm = V4L2_STD_PAL, -}; - -struct video_device saa7134_radio_template = { - .name = "saa7134-radio", - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, -}; - -int saa7134_video_init1(struct saa7134_dev *dev) -{ - /* sanitycheck insmod options */ - if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) - gbuffers = 2; - if (gbufsize < 0 || gbufsize > gbufsize_max) - gbufsize = gbufsize_max; - gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; - - /* put some sensible defaults into the data structures ... */ - dev->ctl_bright = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value; - dev->ctl_contrast = ctrl_by_id(V4L2_CID_CONTRAST)->default_value; - dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; - dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; - dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; - dev->ctl_mute = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; - dev->ctl_invert = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value; - dev->ctl_automute = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value; - - if (dev->tda9887_conf && dev->ctl_automute) - dev->tda9887_conf |= TDA9887_AUTOMUTE; - dev->automute = 0; - - INIT_LIST_HEAD(&dev->video_q.queue); - init_timer(&dev->video_q.timeout); - dev->video_q.timeout.function = saa7134_buffer_timeout; - dev->video_q.timeout.data = (unsigned long)(&dev->video_q); - dev->video_q.dev = dev; - - if (saa7134_boards[dev->board].video_out) - saa7134_videoport_init(dev); - - return 0; -} - -int saa7134_videoport_init(struct saa7134_dev *dev) -{ - /* enable video output */ - int vo = saa7134_boards[dev->board].video_out; - int video_reg; - unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; - - /* Configure videoport */ - saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); - video_reg = video_out[vo][1]; - if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) - video_reg &= ~VP_T_CODE_P_INVERTED; - saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); - saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); - video_reg = video_out[vo][5]; - if (vid_port_opts & SET_CLOCK_NOT_DELAYED) - video_reg &= ~VP_CLK_CTRL2_DELAYED; - if (vid_port_opts & SET_CLOCK_INVERTED) - video_reg |= VP_CLK_CTRL1_INVERTED; - saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); - video_reg = video_out[vo][6]; - if (vid_port_opts & SET_VSYNC_OFF) { - video_reg &= ~VP_VS_TYPE_MASK; - video_reg |= VP_VS_TYPE_OFF; - } - saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); - saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); - - /* Start videoport */ - saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); - - return 0; -} - -int saa7134_video_init2(struct saa7134_dev *dev) -{ - /* init video hw */ - set_tvnorm(dev,&tvnorms[0]); - video_mux(dev,0); - saa7134_tvaudio_setmute(dev); - saa7134_tvaudio_setvolume(dev,dev->ctl_volume); - return 0; -} - -void saa7134_irq_video_signalchange(struct saa7134_dev *dev) -{ - static const char *st[] = { - "(no signal)", "NTSC", "PAL", "SECAM" }; - u32 st1,st2; - - st1 = saa_readb(SAA7134_STATUS_VIDEO1); - st2 = saa_readb(SAA7134_STATUS_VIDEO2); - dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n", - (st1 & 0x40) ? "not locked" : "locked", - (st2 & 0x40) ? "no" : "yes", - st[st1 & 0x03]); - dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1); - - if (dev->nosignal) { - /* no video signal -> mute audio */ - if (dev->ctl_automute) - dev->automute = 1; - saa7134_tvaudio_setmute(dev); - } else { - /* wake up tvaudio audio carrier scan thread */ - saa7134_tvaudio_do_scan(dev); - } - - if ((st2 & 0x80) && !noninterlaced && !dev->nosignal) - saa_clearb(SAA7134_SYNC_CTRL, 0x20); - else - saa_setb(SAA7134_SYNC_CTRL, 0x20); - - if (dev->mops && dev->mops->signal_change) - dev->mops->signal_change(dev); -} - - -void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) -{ - enum v4l2_field field; - - spin_lock(&dev->slock); - if (dev->video_q.curr) { - dev->video_fieldcount++; - field = dev->video_q.curr->vb.field; - if (V4L2_FIELD_HAS_BOTH(field)) { - /* make sure we have seen both fields */ - if ((status & 0x10) == 0x00) { - dev->video_q.curr->top_seen = 1; - goto done; - } - if (!dev->video_q.curr->top_seen) - goto done; - } else if (field == V4L2_FIELD_TOP) { - if ((status & 0x10) != 0x10) - goto done; - } else if (field == V4L2_FIELD_BOTTOM) { - if ((status & 0x10) != 0x00) - goto done; - } - dev->video_q.curr->vb.field_count = dev->video_fieldcount; - saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE); - } - saa7134_buffer_next(dev,&dev->video_q); - - done: - spin_unlock(&dev->slock); -} - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7146.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7146.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7146.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7146.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/* - saa7146.h - definitions philips saa7146 based cards - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __SAA7146__ -#define __SAA7146__ - -#define SAA7146_VERSION_CODE 0x000101 - -#include -#include - -#ifndef O_NONCAP -#define O_NONCAP O_TRUNC -#endif - -#define MAX_GBUFFERS 2 -#define FBUF_SIZE 0x190000 - -#ifdef __KERNEL__ - -struct saa7146_window -{ - int x, y; - ushort width, height; - ushort bpp, bpl; - ushort swidth, sheight; - short cropx, cropy; - ushort cropwidth, cropheight; - unsigned long vidadr; - int color_fmt; - ushort depth; -}; - -/* Per-open data for handling multiple opens on one device */ -struct device_open -{ - int isopen; - int noncapturing; - struct saa7146 *dev; -}; -#define MAX_OPENS 3 - -struct saa7146 -{ - struct video_device video_dev; - struct video_picture picture; - struct video_audio audio_dev; - struct video_info vidinfo; - int user; - int cap; - int capuser; - int irqstate; /* irq routine is state driven */ - int writemode; - int playmode; - unsigned int nr; - unsigned long irq; /* IRQ used by SAA7146 card */ - unsigned short id; - unsigned char revision; - unsigned char boardcfg[64]; /* 64 bytes of config from eeprom */ - unsigned long saa7146_adr; /* bus address of IO mem from PCI BIOS */ - struct saa7146_window win; - unsigned char __iomem *saa7146_mem; /* pointer to mapped IO memory */ - struct device_open open_data[MAX_OPENS]; -#define MAX_MARKS 16 - /* for a/v sync */ - int endmark[MAX_MARKS], endmarkhead, endmarktail; - u32 *dmaRPS1, *pageRPS1, *dmaRPS2, *pageRPS2, *dmavid1, *dmavid2, - *dmavid3, *dmaa1in, *dmaa1out, *dmaa2in, *dmaa2out, - *pagedebi, *pagevid1, *pagevid2, *pagevid3, *pagea1in, - *pagea1out, *pagea2in, *pagea2out; - wait_queue_head_t i2cq, debiq, audq, vidq; - u8 *vidbuf, *audbuf, *osdbuf, *dmadebi; - int audhead, vidhead, osdhead, audtail, vidtail, osdtail; - spinlock_t lock; /* the device lock */ -}; -#endif - -#ifdef _ALPHA_SAA7146 -#define saawrite(dat,adr) writel((dat), saa->saa7146_adr+(adr)) -#define saaread(adr) readl(saa->saa7146_adr+(adr)) -#else -#define saawrite(dat,adr) writel((dat), saa->saa7146_mem+(adr)) -#define saaread(adr) readl(saa->saa7146_mem+(adr)) -#endif - -#define saaand(dat,adr) saawrite((dat) & saaread(adr), adr) -#define saaor(dat,adr) saawrite((dat) | saaread(adr), adr) -#define saaaor(dat,mask,adr) saawrite((dat) | ((mask) & saaread(adr)), adr) - -/* bitmask of attached hardware found */ -#define SAA7146_UNKNOWN 0x00000000 -#define SAA7146_SAA7111 0x00000001 -#define SAA7146_SAA7121 0x00000002 -#define SAA7146_IBMMPEG 0x00000004 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7146reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7146reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7146reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7146reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,283 +0,0 @@ -/* - saa7146.h - definitions philips saa7146 based cards - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __SAA7146_REG__ -#define __SAA7146_REG__ -#define SAA7146_BASE_ODD1 0x00 -#define SAA7146_BASE_EVEN1 0x04 -#define SAA7146_PROT_ADDR1 0x08 -#define SAA7146_PITCH1 0x0c -#define SAA7146_PAGE1 0x10 -#define SAA7146_NUM_LINE_BYTE1 0x14 -#define SAA7146_BASE_ODD2 0x18 -#define SAA7146_BASE_EVEN2 0x1c -#define SAA7146_PROT_ADDR2 0x20 -#define SAA7146_PITCH2 0x24 -#define SAA7146_PAGE2 0x28 -#define SAA7146_NUM_LINE_BYTE2 0x2c -#define SAA7146_BASE_ODD3 0x30 -#define SAA7146_BASE_EVEN3 0x34 -#define SAA7146_PROT_ADDR3 0x38 -#define SAA7146_PITCH3 0x3c -#define SAA7146_PAGE3 0x40 -#define SAA7146_NUM_LINE_BYTE3 0x44 -#define SAA7146_PCI_BT_V1 0x48 -#define SAA7146_PCI_BT_V2 0x49 -#define SAA7146_PCI_BT_V3 0x4a -#define SAA7146_PCI_BT_DEBI 0x4b -#define SAA7146_PCI_BT_A 0x4c -#define SAA7146_DD1_INIT 0x50 -#define SAA7146_DD1_STREAM_B 0x54 -#define SAA7146_DD1_STREAM_A 0x56 -#define SAA7146_BRS_CTRL 0x58 -#define SAA7146_HPS_CTRL 0x5c -#define SAA7146_HPS_V_SCALE 0x60 -#define SAA7146_HPS_V_GAIN 0x64 -#define SAA7146_HPS_H_PRESCALE 0x68 -#define SAA7146_HPS_H_SCALE 0x6c -#define SAA7146_BCS_CTRL 0x70 -#define SAA7146_CHROMA_KEY_RANGE 0x74 -#define SAA7146_CLIP_FORMAT_CTRL 0x78 -#define SAA7146_DEBI_CONFIG 0x7c -#define SAA7146_DEBI_COMMAND 0x80 -#define SAA7146_DEBI_PAGE 0x84 -#define SAA7146_DEBI_AD 0x88 -#define SAA7146_I2C_TRANSFER 0x8c -#define SAA7146_I2C_STATUS 0x90 -#define SAA7146_BASE_A1_IN 0x94 -#define SAA7146_PROT_A1_IN 0x98 -#define SAA7146_PAGE_A1_IN 0x9C -#define SAA7146_BASE_A1_OUT 0xa0 -#define SAA7146_PROT_A1_OUT 0xa4 -#define SAA7146_PAGE_A1_OUT 0xa8 -#define SAA7146_BASE_A2_IN 0xac -#define SAA7146_PROT_A2_IN 0xb0 -#define SAA7146_PAGE_A2_IN 0xb4 -#define SAA7146_BASE_A2_OUT 0xb8 -#define SAA7146_PROT_A2_OUT 0xbc -#define SAA7146_PAGE_A2_OUT 0xc0 -#define SAA7146_RPS_PAGE0 0xc4 -#define SAA7146_RPS_PAGE1 0xc8 -#define SAA7146_RPS_THRESH0 0xcc -#define SAA7146_RPS_THRESH1 0xd0 -#define SAA7146_RPS_TOV0 0xd4 -#define SAA7146_RPS_TOV1 0xd8 -#define SAA7146_IER 0xdc -#define SAA7146_GPIO_CTRL 0xe0 -#define SAA7146_EC1SSR 0xe4 -#define SAA7146_EC2SSR 0xe8 -#define SAA7146_ECT1R 0xec -#define SAA7146_ECT2R 0xf0 -#define SAA7146_ACON1 0xf4 -#define SAA7146_ACON2 0xf8 -#define SAA7146_MC1 0xfc -#define SAA7146_MC2 0x100 -#define SAA7146_RPS_ADDR0 0x104 -#define SAA7146_RPS_ADDR1 0x108 -#define SAA7146_ISR 0x10c -#define SAA7146_PSR 0x110 -#define SAA7146_SSR 0x114 -#define SAA7146_EC1R 0x118 -#define SAA7146_EC2R 0x11c -#define SAA7146_VDP1 0x120 -#define SAA7146_VDP2 0x124 -#define SAA7146_VDP3 0x128 -#define SAA7146_ADP1 0x12c -#define SAA7146_ADP2 0x130 -#define SAA7146_ADP3 0x134 -#define SAA7146_ADP4 0x138 -#define SAA7146_DDP 0x13c -#define SAA7146_LEVEL_REP 0x140 -#define SAA7146_FB_BUFFER1 0x144 -#define SAA7146_FB_BUFFER2 0x148 -#define SAA7146_A_TIME_SLOT1 0x180 -#define SAA7146_A_TIME_SLOT2 0x1C0 - -/* bitfield defines */ -#define MASK_31 0x80000000 -#define MASK_30 0x40000000 -#define MASK_29 0x20000000 -#define MASK_28 0x10000000 -#define MASK_27 0x08000000 -#define MASK_26 0x04000000 -#define MASK_25 0x02000000 -#define MASK_24 0x01000000 -#define MASK_23 0x00800000 -#define MASK_22 0x00400000 -#define MASK_21 0x00200000 -#define MASK_20 0x00100000 -#define MASK_19 0x00080000 -#define MASK_18 0x00040000 -#define MASK_17 0x00020000 -#define MASK_16 0x00010000 -#define MASK_15 0x00008000 -#define MASK_14 0x00004000 -#define MASK_13 0x00002000 -#define MASK_12 0x00001000 -#define MASK_11 0x00000800 -#define MASK_10 0x00000400 -#define MASK_09 0x00000200 -#define MASK_08 0x00000100 -#define MASK_07 0x00000080 -#define MASK_06 0x00000040 -#define MASK_05 0x00000020 -#define MASK_04 0x00000010 -#define MASK_03 0x00000008 -#define MASK_02 0x00000004 -#define MASK_01 0x00000002 -#define MASK_00 0x00000001 -#define MASK_B0 0x000000ff -#define MASK_B1 0x0000ff00 -#define MASK_B2 0x00ff0000 -#define MASK_B3 0xff000000 -#define MASK_W0 0x0000ffff -#define MASK_W1 0xffff0000 -#define MASK_PA 0xfffffffc -#define MASK_PR 0xfffffffe -#define MASK_ER 0xffffffff -#define MASK_NONE 0x00000000 - -#define SAA7146_PAGE_MAP_EN MASK_11 -/* main control register 1 */ -#define SAA7146_MC1_MRST_N MASK_15 -#define SAA7146_MC1_ERPS1 MASK_13 -#define SAA7146_MC1_ERPS0 MASK_12 -#define SAA7146_MC1_EDP MASK_11 -#define SAA7146_MC1_EVP MASK_10 -#define SAA7146_MC1_EAP MASK_09 -#define SAA7146_MC1_EI2C MASK_08 -#define SAA7146_MC1_TR_E_DEBI MASK_07 -#define SAA7146_MC1_TR_E_1 MASK_06 -#define SAA7146_MC1_TR_E_2 MASK_05 -#define SAA7146_MC1_TR_E_3 MASK_04 -#define SAA7146_MC1_TR_E_A2_OUT MASK_03 -#define SAA7146_MC1_TR_E_A2_IN MASK_02 -#define SAA7146_MC1_TR_E_A1_OUT MASK_01 -#define SAA7146_MC1_TR_E_A1_IN MASK_00 -/* main control register 2 */ -#define SAA7146_MC2_RPS_SIG4 MASK_15 -#define SAA7146_MC2_RPS_SIG3 MASK_14 -#define SAA7146_MC2_RPS_SIG2 MASK_13 -#define SAA7146_MC2_RPS_SIG1 MASK_12 -#define SAA7146_MC2_RPS_SIG0 MASK_11 -#define SAA7146_MC2_UPLD_D1_B MASK_10 -#define SAA7146_MC2_UPLD_D1_A MASK_09 -#define SAA7146_MC2_UPLD_BRS MASK_08 -#define SAA7146_MC2_UPLD_HPS_H MASK_06 -#define SAA7146_MC2_UPLD_HPS_V MASK_05 -#define SAA7146_MC2_UPLD_DMA3 MASK_04 -#define SAA7146_MC2_UPLD_DMA2 MASK_03 -#define SAA7146_MC2_UPLD_DMA1 MASK_02 -#define SAA7146_MC2_UPLD_DEBI MASK_01 -#define SAA7146_MC2_UPLD_I2C MASK_00 -/* Primary Status Register and Interrupt Enable/Status Registers */ -#define SAA7146_PSR_PPEF MASK_31 -#define SAA7146_PSR_PABO MASK_30 -#define SAA7146_PSR_PPED MASK_29 -#define SAA7146_PSR_RPS_I1 MASK_28 -#define SAA7146_PSR_RPS_I0 MASK_27 -#define SAA7146_PSR_RPS_LATE1 MASK_26 -#define SAA7146_PSR_RPS_LATE0 MASK_25 -#define SAA7146_PSR_RPS_E1 MASK_24 -#define SAA7146_PSR_RPS_E0 MASK_23 -#define SAA7146_PSR_RPS_TO1 MASK_22 -#define SAA7146_PSR_RPS_TO0 MASK_21 -#define SAA7146_PSR_UPLD MASK_20 -#define SAA7146_PSR_DEBI_S MASK_19 -#define SAA7146_PSR_DEBI_E MASK_18 -#define SAA7146_PSR_I2C_S MASK_17 -#define SAA7146_PSR_I2C_E MASK_16 -#define SAA7146_PSR_A2_IN MASK_15 -#define SAA7146_PSR_A2_OUT MASK_14 -#define SAA7146_PSR_A1_IN MASK_13 -#define SAA7146_PSR_A1_OUT MASK_12 -#define SAA7146_PSR_AFOU MASK_11 -#define SAA7146_PSR_V_PE MASK_10 -#define SAA7146_PSR_VFOU MASK_09 -#define SAA7146_PSR_FIDA MASK_08 -#define SAA7146_PSR_FIDB MASK_07 -#define SAA7146_PSR_PIN3 MASK_06 -#define SAA7146_PSR_PIN2 MASK_05 -#define SAA7146_PSR_PIN1 MASK_04 -#define SAA7146_PSR_PIN0 MASK_03 -#define SAA7146_PSR_ECS MASK_02 -#define SAA7146_PSR_EC3S MASK_01 -#define SAA7146_PSR_EC0S MASK_00 -/* Secondary Status Register */ -#define SAA7146_SSR_PRQ MASK_31 -#define SAA7146_SSR_PMA MASK_30 -#define SAA7146_SSR_RPS_RE1 MASK_29 -#define SAA7146_SSR_RPS_PE1 MASK_28 -#define SAA7146_SSR_RPS_A1 MASK_27 -#define SAA7146_SSR_RPS_RE0 MASK_26 -#define SAA7146_SSR_RPS_PE0 MASK_25 -#define SAA7146_SSR_RPS_A0 MASK_24 -#define SAA7146_SSR_DEBI_TO MASK_23 -#define SAA7146_SSR_DEBI_EF MASK_22 -#define SAA7146_SSR_I2C_EA MASK_21 -#define SAA7146_SSR_I2C_EW MASK_20 -#define SAA7146_SSR_I2C_ER MASK_19 -#define SAA7146_SSR_I2C_EL MASK_18 -#define SAA7146_SSR_I2C_EF MASK_17 -#define SAA7146_SSR_V3P MASK_16 -#define SAA7146_SSR_V2P MASK_15 -#define SAA7146_SSR_V1P MASK_14 -#define SAA7146_SSR_VF3 MASK_13 -#define SAA7146_SSR_VF2 MASK_12 -#define SAA7146_SSR_VF1 MASK_11 -#define SAA7146_SSR_AF2_IN MASK_10 -#define SAA7146_SSR_AF2_OUT MASK_09 -#define SAA7146_SSR_AF1_IN MASK_08 -#define SAA7146_SSR_AF1_OUT MASK_07 -#define SAA7146_SSR_VGT MASK_05 -#define SAA7146_SSR_LNQG MASK_04 -#define SAA7146_SSR_EC5S MASK_03 -#define SAA7146_SSR_EC4S MASK_02 -#define SAA7146_SSR_EC2S MASK_01 -#define SAA7146_SSR_EC1S MASK_00 -/* I2C status register */ -#define SAA7146_I2C_ABORT MASK_07 -#define SAA7146_I2C_SPERR MASK_06 -#define SAA7146_I2C_APERR MASK_05 -#define SAA7146_I2C_DTERR MASK_04 -#define SAA7146_I2C_DRERR MASK_03 -#define SAA7146_I2C_AL MASK_02 -#define SAA7146_I2C_ERR MASK_01 -#define SAA7146_I2C_BUSY MASK_00 -/* output formats */ -#define SAA7146_YUV422 0 -#define SAA7146_RGB16 0 -#define SAA7146_YUV444 1 -#define SAA7146_RGB24 1 -#define SAA7146_ARGB32 2 -#define SAA7146_YUV411 3 -#define SAA7146_ARGB15 3 -#define SAA7146_YUV2 4 -#define SAA7146_RGAB15 4 -#define SAA7146_Y8 6 -#define SAA7146_YUV8 7 -#define SAA7146_RGB8 7 -#define SAA7146_YUV444p 8 -#define SAA7146_YUV422p 9 -#define SAA7146_YUV420p 10 -#define SAA7146_YUV1620 11 -#define SAA7146_Y1 13 -#define SAA7146_Y2 14 -#define SAA7146_YUV1 15 -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -config VIDEO_SAA7164 - tristate "NXP SAA7164 support" - depends on DVB_CORE && PCI && I2C - select I2C_ALGOBIT - select FW_LOADER - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEOBUF_DVB - select DVB_TDA10048 if !DVB_FE_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - ---help--- - This is a video4linux driver for NXP SAA7164 based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called saa7164 - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \ - saa7164-fw.o saa7164-bus.o saa7164-cmd.o saa7164-api.o \ - saa7164-buffer.o saa7164-encoder.o saa7164-vbi.o - -obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends - -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-api.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-api.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-api.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-api.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1533 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#include "saa7164.h" - -int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i) -{ - int ret; - - if (!(saa_debug & DBGLVL_CPU)) - return 0; - - dprintk(DBGLVL_API, "%s()\n", __func__); - - i->deviceinst = 0; - i->devicespec = 0; - i->mode = 0; - i->status = 0; - - ret = saa7164_cmd_send(dev, 0, GET_CUR, - GET_FW_STATUS_CONTROL, sizeof(struct tmFwInfoStruct), i); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - printk(KERN_INFO "saa7164[%d]-CPU: %d percent", dev->nr, i->CPULoad); - - return ret; -} - -int saa7164_api_collect_debug(struct saa7164_dev *dev) -{ - struct tmComResDebugGetData d; - u8 more = 255; - int ret; - - dprintk(DBGLVL_API, "%s()\n", __func__); - - while (more--) { - - memset(&d, 0, sizeof(d)); - - ret = saa7164_cmd_send(dev, 0, GET_CUR, - GET_DEBUG_DATA_CONTROL, sizeof(d), &d); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", - __func__, ret); - - if (d.dwResult != SAA_OK) - break; - - printk(KERN_INFO "saa7164[%d]-FWMSG: %s", dev->nr, - d.ucDebugData); - } - - return 0; -} - -int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level) -{ - struct tmComResDebugSetLevel lvl; - int ret; - - dprintk(DBGLVL_API, "%s(level=%d)\n", __func__, level); - - /* Retrieve current state */ - ret = saa7164_cmd_send(dev, 0, GET_CUR, - SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - dprintk(DBGLVL_API, "%s() Was %d\n", __func__, lvl.dwDebugLevel); - - lvl.dwDebugLevel = level; - - /* set new state */ - ret = saa7164_cmd_send(dev, 0, SET_CUR, - SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - return ret; -} - -int saa7164_api_set_vbi_format(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct tmComResProbeCommit fmt, rsp; - int ret; - - dprintk(DBGLVL_API, "%s(nr=%d, unitid=0x%x)\n", __func__, - port->nr, port->hwcfg.unitid); - - fmt.bmHint = 0; - fmt.bFormatIndex = 1; - fmt.bFrameIndex = 1; - - /* Probe, see if it can support this format */ - ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, - SET_CUR, SAA_PROBE_CONTROL, sizeof(fmt), &fmt); - if (ret != SAA_OK) - printk(KERN_ERR "%s() set error, ret = 0x%x\n", __func__, ret); - - /* See of the format change was successful */ - ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, - GET_CUR, SAA_PROBE_CONTROL, sizeof(rsp), &rsp); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() get error, ret = 0x%x\n", __func__, ret); - } else { - /* Compare requested vs received, should be same */ - if (memcmp(&fmt, &rsp, sizeof(rsp)) == 0) { - dprintk(DBGLVL_API, "SET/PROBE Verified\n"); - - /* Ask the device to select the negotiated format */ - ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, - SET_CUR, SAA_COMMIT_CONTROL, sizeof(fmt), &fmt); - if (ret != SAA_OK) - printk(KERN_ERR "%s() commit error, ret = 0x%x\n", - __func__, ret); - - ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, - GET_CUR, SAA_COMMIT_CONTROL, sizeof(rsp), &rsp); - if (ret != SAA_OK) - printk(KERN_ERR "%s() GET commit error, ret = 0x%x\n", - __func__, ret); - - if (memcmp(&fmt, &rsp, sizeof(rsp)) != 0) { - printk(KERN_ERR "%s() memcmp error, ret = 0x%x\n", - __func__, ret); - } else - dprintk(DBGLVL_API, "SET/COMMIT Verified\n"); - - dprintk(DBGLVL_API, "rsp.bmHint = 0x%x\n", rsp.bmHint); - dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n", - rsp.bFormatIndex); - dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n", - rsp.bFrameIndex); - } else - printk(KERN_ERR "%s() compare failed\n", __func__); - } - - if (ret == SAA_OK) - dprintk(DBGLVL_API, "%s(nr=%d) Success\n", __func__, port->nr); - - return ret; -} - -int saa7164_api_set_gop_size(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct tmComResEncVideoGopStructure gs; - int ret; - - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - gs.ucRefFrameDist = port->encoder_params.refdist; - gs.ucGOPSize = port->encoder_params.gop_size; - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, - EU_VIDEO_GOP_STRUCTURE_CONTROL, - sizeof(gs), &gs); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - return ret; -} - -int saa7164_api_set_encoder(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct tmComResEncVideoBitRate vb; - struct tmComResEncAudioBitRate ab; - int ret; - - dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__, - port->hwcfg.sourceid); - - if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) - port->encoder_profile = EU_PROFILE_PS_DVD; - else - port->encoder_profile = EU_PROFILE_TS_HQ; - - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, - EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - /* Resolution */ - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, - EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - /* Establish video bitrates */ - if (port->encoder_params.bitrate_mode == - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) - vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_CONSTANT; - else - vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK; - vb.dwVideoBitRate = port->encoder_params.bitrate; - vb.dwVideoBitRatePeak = port->encoder_params.bitrate_peak; - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, - EU_VIDEO_BIT_RATE_CONTROL, - sizeof(struct tmComResEncVideoBitRate), - &vb); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - /* Establish audio bitrates */ - ab.ucAudioBitRateMode = 0; - ab.dwAudioBitRate = 384000; - ab.dwAudioBitRatePeak = ab.dwAudioBitRate; - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, - EU_AUDIO_BIT_RATE_CONTROL, - sizeof(struct tmComResEncAudioBitRate), - &ab); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, - ret); - - saa7164_api_set_aspect_ratio(port); - saa7164_api_set_gop_size(port); - - return ret; -} - -int saa7164_api_get_encoder(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct tmComResEncVideoBitRate v; - struct tmComResEncAudioBitRate a; - struct tmComResEncVideoInputAspectRatio ar; - int ret; - - dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__, - port->hwcfg.sourceid); - - port->encoder_profile = 0; - port->video_format = 0; - port->video_resolution = 0; - port->audio_format = 0; - - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, - EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, - EU_VIDEO_RESOLUTION_CONTROL, sizeof(u8), - &port->video_resolution); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, - EU_VIDEO_FORMAT_CONTROL, sizeof(u8), &port->video_format); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, - EU_VIDEO_BIT_RATE_CONTROL, sizeof(v), &v); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, - EU_AUDIO_FORMAT_CONTROL, sizeof(u8), &port->audio_format); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, - EU_AUDIO_BIT_RATE_CONTROL, sizeof(a), &a); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - /* Aspect Ratio */ - ar.width = 0; - ar.height = 0; - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR, - EU_VIDEO_INPUT_ASPECT_CONTROL, - sizeof(struct tmComResEncVideoInputAspectRatio), &ar); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - dprintk(DBGLVL_ENC, "encoder_profile = %d\n", port->encoder_profile); - dprintk(DBGLVL_ENC, "video_format = %d\n", port->video_format); - dprintk(DBGLVL_ENC, "audio_format = %d\n", port->audio_format); - dprintk(DBGLVL_ENC, "video_resolution= %d\n", port->video_resolution); - dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n", - v.ucVideoBitRateMode); - dprintk(DBGLVL_ENC, "v.dwVideoBitRate = %d\n", - v.dwVideoBitRate); - dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n", - v.dwVideoBitRatePeak); - dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n", - a.ucAudioBitRateMode); - dprintk(DBGLVL_ENC, "a.dwVideoBitRate = %d\n", - a.dwAudioBitRate); - dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n", - a.dwAudioBitRatePeak); - dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n", - ar.width, ar.height); - - return ret; -} - -int saa7164_api_set_aspect_ratio(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct tmComResEncVideoInputAspectRatio ar; - int ret; - - dprintk(DBGLVL_ENC, "%s(%d)\n", __func__, - port->encoder_params.ctl_aspect); - - switch (port->encoder_params.ctl_aspect) { - case V4L2_MPEG_VIDEO_ASPECT_1x1: - ar.width = 1; - ar.height = 1; - break; - case V4L2_MPEG_VIDEO_ASPECT_4x3: - ar.width = 4; - ar.height = 3; - break; - case V4L2_MPEG_VIDEO_ASPECT_16x9: - ar.width = 16; - ar.height = 9; - break; - case V4L2_MPEG_VIDEO_ASPECT_221x100: - ar.width = 221; - ar.height = 100; - break; - default: - BUG(); - } - - dprintk(DBGLVL_ENC, "%s(%d) now %d:%d\n", __func__, - port->encoder_params.ctl_aspect, - ar.width, ar.height); - - /* Aspect Ratio */ - ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR, - EU_VIDEO_INPUT_ASPECT_CONTROL, - sizeof(struct tmComResEncVideoInputAspectRatio), &ar); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - return ret; -} - -int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl) -{ - struct saa7164_dev *dev = port->dev; - int ret; - u16 val; - - if (ctl == PU_BRIGHTNESS_CONTROL) - val = port->ctl_brightness; - else - if (ctl == PU_CONTRAST_CONTROL) - val = port->ctl_contrast; - else - if (ctl == PU_HUE_CONTROL) - val = port->ctl_hue; - else - if (ctl == PU_SATURATION_CONTROL) - val = port->ctl_saturation; - else - if (ctl == PU_SHARPNESS_CONTROL) - val = port->ctl_sharpness; - else - return -EINVAL; - - dprintk(DBGLVL_ENC, "%s() unitid=0x%x ctl=%d, val=%d\n", - __func__, port->encunit.vsourceid, ctl, val); - - ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, SET_CUR, - ctl, sizeof(u16), &val); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - return ret; -} - -int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl) -{ - struct saa7164_dev *dev = port->dev; - int ret; - u16 val; - - ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, GET_CUR, - ctl, sizeof(u16), &val); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - return ret; - } - - dprintk(DBGLVL_ENC, "%s() ctl=%d, val=%d\n", - __func__, ctl, val); - - if (ctl == PU_BRIGHTNESS_CONTROL) - port->ctl_brightness = val; - else - if (ctl == PU_CONTRAST_CONTROL) - port->ctl_contrast = val; - else - if (ctl == PU_HUE_CONTROL) - port->ctl_hue = val; - else - if (ctl == PU_SATURATION_CONTROL) - port->ctl_saturation = val; - else - if (ctl == PU_SHARPNESS_CONTROL) - port->ctl_sharpness = val; - - return ret; -} - -int saa7164_api_set_videomux(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - u8 inputs[] = { 1, 2, 2, 2, 5, 5, 5 }; - int ret; - - dprintk(DBGLVL_ENC, "%s() v_mux=%d a_mux=%d\n", - __func__, port->mux_input, inputs[port->mux_input - 1]); - - /* Audio Mute */ - ret = saa7164_api_audio_mute(port, 1); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - /* Video Mux */ - ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, SET_CUR, - SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - /* Audio Mux */ - ret = saa7164_cmd_send(port->dev, port->audfeat.sourceid, SET_CUR, - SU_INPUT_SELECT_CONTROL, sizeof(u8), - &inputs[port->mux_input - 1]); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - /* Audio UnMute */ - ret = saa7164_api_audio_mute(port, 0); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - return ret; -} - -int saa7164_api_audio_mute(struct saa7164_port *port, int mute) -{ - struct saa7164_dev *dev = port->dev; - u8 v = mute; - int ret; - - dprintk(DBGLVL_API, "%s(%d)\n", __func__, mute); - - ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR, - MUTE_CONTROL, sizeof(u8), &v); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - return ret; -} - -/* 0 = silence, 0xff = full */ -int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level) -{ - struct saa7164_dev *dev = port->dev; - s16 v, min, max; - int ret; - - dprintk(DBGLVL_API, "%s(%d)\n", __func__, level); - - /* Obtain the min/max ranges */ - ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MIN, - VOLUME_CONTROL, sizeof(u16), &min); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MAX, - VOLUME_CONTROL, sizeof(u16), &max); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR, - (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__, - level, min, max, v); - - v = level; - if (v < min) - v = min; - if (v > max) - v = max; - - /* Left */ - ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR, - (0x01 << 8) | VOLUME_CONTROL, sizeof(s16), &v); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - /* Right */ - ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR, - (0x02 << 8) | VOLUME_CONTROL, sizeof(s16), &v); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR, - (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__, - level, min, max, v); - - return ret; -} - -int saa7164_api_set_audio_std(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct tmComResAudioDefaults lvl; - struct tmComResTunerStandard tvaudio; - int ret; - - dprintk(DBGLVL_API, "%s()\n", __func__); - - /* Establish default levels */ - lvl.ucDecoderLevel = TMHW_LEV_ADJ_DECLEV_DEFAULT; - lvl.ucDecoderFM_Level = TMHW_LEV_ADJ_DECLEV_DEFAULT; - lvl.ucMonoLevel = TMHW_LEV_ADJ_MONOLEV_DEFAULT; - lvl.ucNICAM_Level = TMHW_LEV_ADJ_NICLEV_DEFAULT; - lvl.ucSAP_Level = TMHW_LEV_ADJ_SAPLEV_DEFAULT; - lvl.ucADC_Level = TMHW_LEV_ADJ_ADCLEV_DEFAULT; - ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR, - AUDIO_DEFAULT_CONTROL, sizeof(struct tmComResAudioDefaults), - &lvl); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - /* Manually select the appropriate TV audio standard */ - if (port->encodernorm.id & V4L2_STD_NTSC) { - tvaudio.std = TU_STANDARD_NTSC_M; - tvaudio.country = 1; - } else { - tvaudio.std = TU_STANDARD_PAL_I; - tvaudio.country = 44; - } - - ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR, - TU_STANDARD_CONTROL, sizeof(tvaudio), &tvaudio); - if (ret != SAA_OK) - printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n", - __func__, ret); - return ret; -} - -int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect) -{ - struct saa7164_dev *dev = port->dev; - struct tmComResTunerStandardAuto p; - int ret; - - dprintk(DBGLVL_API, "%s(%d)\n", __func__, autodetect); - - /* Disable TV Audio autodetect if not already set (buggy) */ - if (autodetect) - p.mode = TU_STANDARD_AUTO; - else - p.mode = TU_STANDARD_MANUAL; - ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR, - TU_STANDARD_AUTO_CONTROL, sizeof(p), &p); - if (ret != SAA_OK) - printk(KERN_ERR - "%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n", - __func__, ret); - - return ret; -} - -int saa7164_api_get_videomux(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, GET_CUR, - SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - dprintk(DBGLVL_ENC, "%s() v_mux=%d\n", - __func__, port->mux_input); - - return ret; -} - -int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val) -{ - struct saa7164_dev *dev = port->dev; - - u16 len = 0; - u8 buf[256]; - int ret; - u8 mas; - - dprintk(DBGLVL_API, "%s(nr=%d type=%d val=%x)\n", __func__, - port->nr, port->type, val); - - if (port->nr == 0) - mas = 0xd0; - else - mas = 0xe0; - - memset(buf, 0, sizeof(buf)); - - buf[0x00] = 0x04; - buf[0x01] = 0x00; - buf[0x02] = 0x00; - buf[0x03] = 0x00; - - buf[0x04] = 0x04; - buf[0x05] = 0x00; - buf[0x06] = 0x00; - buf[0x07] = 0x00; - - buf[0x08] = reg; - buf[0x09] = 0x26; - buf[0x0a] = mas; - buf[0x0b] = 0xb0; - - buf[0x0c] = val; - buf[0x0d] = 0x00; - buf[0x0e] = 0x00; - buf[0x0f] = 0x00; - - ret = saa7164_cmd_send(dev, port->ifunit.unitid, GET_LEN, - EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret); - return -EIO; - } - - ret = saa7164_cmd_send(dev, port->ifunit.unitid, SET_CUR, - EXU_REGISTER_ACCESS_CONTROL, len, &buf); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret); -#if 0 - saa7164_dumphex16(dev, buf, 16); -#endif - return ret == SAA_OK ? 0 : -EIO; -} - -/* Disable the IF block AGC controls */ -int saa7164_api_configure_dif(struct saa7164_port *port, u32 std) -{ - struct saa7164_dev *dev = port->dev; - int ret = 0; - u8 agc_disable; - - dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std); - - if (std & V4L2_STD_NTSC) { - dprintk(DBGLVL_API, " NTSC\n"); - saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */ - agc_disable = 0; - } else if (std & V4L2_STD_PAL_I) { - dprintk(DBGLVL_API, " PAL-I\n"); - saa7164_api_set_dif(port, 0x00, 0x08); /* Video Standard */ - agc_disable = 0; - } else if (std & V4L2_STD_PAL_M) { - dprintk(DBGLVL_API, " PAL-M\n"); - saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */ - agc_disable = 0; - } else if (std & V4L2_STD_PAL_N) { - dprintk(DBGLVL_API, " PAL-N\n"); - saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */ - agc_disable = 0; - } else if (std & V4L2_STD_PAL_Nc) { - dprintk(DBGLVL_API, " PAL-Nc\n"); - saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */ - agc_disable = 0; - } else if (std & V4L2_STD_PAL_B) { - dprintk(DBGLVL_API, " PAL-B\n"); - saa7164_api_set_dif(port, 0x00, 0x02); /* Video Standard */ - agc_disable = 0; - } else if (std & V4L2_STD_PAL_DK) { - dprintk(DBGLVL_API, " PAL-DK\n"); - saa7164_api_set_dif(port, 0x00, 0x10); /* Video Standard */ - agc_disable = 0; - } else if (std & V4L2_STD_SECAM_L) { - dprintk(DBGLVL_API, " SECAM-L\n"); - saa7164_api_set_dif(port, 0x00, 0x20); /* Video Standard */ - agc_disable = 0; - } else { - /* Unknown standard, assume DTV */ - dprintk(DBGLVL_API, " Unknown (assuming DTV)\n"); - /* Undefinded Video Standard */ - saa7164_api_set_dif(port, 0x00, 0x80); - agc_disable = 1; - } - - saa7164_api_set_dif(port, 0x48, 0xa0); /* AGC Functions 1 */ - saa7164_api_set_dif(port, 0xc0, agc_disable); /* AGC Output Disable */ - saa7164_api_set_dif(port, 0x7c, 0x04); /* CVBS EQ */ - saa7164_api_set_dif(port, 0x04, 0x01); /* Active */ - msleep(100); - saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */ - msleep(100); - - return ret; -} - -/* Ensure the dif is in the correct state for the operating mode - * (analog / dtv). We only configure the diff through the analog encoder - * so when we're in digital mode we need to find the appropriate encoder - * and use it to configure the DIF. - */ -int saa7164_api_initialize_dif(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct saa7164_port *p = NULL; - int ret = -EINVAL; - u32 std = 0; - - dprintk(DBGLVL_API, "%s(nr=%d type=%d)\n", __func__, - port->nr, port->type); - - if (port->type == SAA7164_MPEG_ENCODER) { - /* Pick any analog standard to init the diff. - * we'll come back during encoder_init' - * and set the correct standard if requried. - */ - std = V4L2_STD_NTSC; - } else - if (port->type == SAA7164_MPEG_DVB) { - if (port->nr == SAA7164_PORT_TS1) - p = &dev->ports[SAA7164_PORT_ENC1]; - else - p = &dev->ports[SAA7164_PORT_ENC2]; - } else - if (port->type == SAA7164_MPEG_VBI) { - std = V4L2_STD_NTSC; - if (port->nr == SAA7164_PORT_VBI1) - p = &dev->ports[SAA7164_PORT_ENC1]; - else - p = &dev->ports[SAA7164_PORT_ENC2]; - } else - BUG(); - - if (p) - ret = saa7164_api_configure_dif(p, std); - - return ret; -} - -int saa7164_api_transition_port(struct saa7164_port *port, u8 mode) -{ - struct saa7164_dev *dev = port->dev; - - int ret; - - dprintk(DBGLVL_API, "%s(nr=%d unitid=0x%x,%d)\n", - __func__, port->nr, port->hwcfg.unitid, mode); - - ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR, - SAA_STATE_CONTROL, sizeof(mode), &mode); - if (ret != SAA_OK) - printk(KERN_ERR "%s(portnr %d unitid 0x%x) error, ret = 0x%x\n", - __func__, port->nr, port->hwcfg.unitid, ret); - - return ret; -} - -int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version) -{ - int ret; - - ret = saa7164_cmd_send(dev, 0, GET_CUR, - GET_FW_VERSION_CONTROL, sizeof(u32), version); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - return ret; -} - -int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen) -{ - u8 reg[] = { 0x0f, 0x00 }; - - if (buflen < 128) - return -ENOMEM; - - /* Assumption: Hauppauge eeprom is at 0xa0 on on bus 0 */ - /* TODO: Pull the details from the boards struct */ - return saa7164_api_i2c_read(&dev->i2c_bus[0], 0xa0 >> 1, sizeof(reg), - ®[0], 128, buf); -} - -int saa7164_api_configure_port_vbi(struct saa7164_dev *dev, - struct saa7164_port *port) -{ - struct tmComResVBIFormatDescrHeader *fmt = &port->vbi_fmt_ntsc; - - dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex); - dprintk(DBGLVL_API, " VideoStandard = 0x%x\n", fmt->VideoStandard); - dprintk(DBGLVL_API, " StartLine = %d\n", fmt->StartLine); - dprintk(DBGLVL_API, " EndLine = %d\n", fmt->EndLine); - dprintk(DBGLVL_API, " FieldRate = %d\n", fmt->FieldRate); - dprintk(DBGLVL_API, " bNumLines = %d\n", fmt->bNumLines); - - /* Cache the hardware configuration in the port */ - - port->bufcounter = port->hwcfg.BARLocation; - port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32)); - port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32)); - port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32)); - port->bufptr32l = port->hwcfg.BARLocation + - (4 * sizeof(u32)) + - (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32); - port->bufptr32h = port->hwcfg.BARLocation + - (4 * sizeof(u32)) + - (sizeof(u32) * port->hwcfg.buffercount); - port->bufptr64 = port->hwcfg.BARLocation + - (4 * sizeof(u32)) + - (sizeof(u32) * port->hwcfg.buffercount); - dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n", - port->hwcfg.BARLocation); - - dprintk(DBGLVL_API, " = VS_FORMAT_VBI (becomes dev->en[%d])\n", - port->nr); - - return 0; -} - -int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev, - struct saa7164_port *port, - struct tmComResTSFormatDescrHeader *tsfmt) -{ - dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex); - dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset); - dprintk(DBGLVL_API, " bPacketLength= 0x%x\n", tsfmt->bPacketLength); - dprintk(DBGLVL_API, " bStrideLength= 0x%x\n", tsfmt->bStrideLength); - dprintk(DBGLVL_API, " bguid = (....)\n"); - - /* Cache the hardware configuration in the port */ - - port->bufcounter = port->hwcfg.BARLocation; - port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32)); - port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32)); - port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32)); - port->bufptr32l = port->hwcfg.BARLocation + - (4 * sizeof(u32)) + - (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32); - port->bufptr32h = port->hwcfg.BARLocation + - (4 * sizeof(u32)) + - (sizeof(u32) * port->hwcfg.buffercount); - port->bufptr64 = port->hwcfg.BARLocation + - (4 * sizeof(u32)) + - (sizeof(u32) * port->hwcfg.buffercount); - dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n", - port->hwcfg.BARLocation); - - dprintk(DBGLVL_API, " = VS_FORMAT_MPEGTS (becomes dev->ts[%d])\n", - port->nr); - - return 0; -} - -int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev, - struct saa7164_port *port, - struct tmComResPSFormatDescrHeader *fmt) -{ - dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex); - dprintk(DBGLVL_API, " wPacketLength= 0x%x\n", fmt->wPacketLength); - dprintk(DBGLVL_API, " wPackLength= 0x%x\n", fmt->wPackLength); - dprintk(DBGLVL_API, " bPackDataType= 0x%x\n", fmt->bPackDataType); - - /* Cache the hardware configuration in the port */ - /* TODO: CHECK THIS in the port config */ - port->bufcounter = port->hwcfg.BARLocation; - port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32)); - port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32)); - port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32)); - port->bufptr32l = port->hwcfg.BARLocation + - (4 * sizeof(u32)) + - (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32); - port->bufptr32h = port->hwcfg.BARLocation + - (4 * sizeof(u32)) + - (sizeof(u32) * port->hwcfg.buffercount); - port->bufptr64 = port->hwcfg.BARLocation + - (4 * sizeof(u32)) + - (sizeof(u32) * port->hwcfg.buffercount); - dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n", - port->hwcfg.BARLocation); - - dprintk(DBGLVL_API, " = VS_FORMAT_MPEGPS (becomes dev->enc[%d])\n", - port->nr); - - return 0; -} - -int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) -{ - struct saa7164_port *tsport = NULL; - struct saa7164_port *encport = NULL; - struct saa7164_port *vbiport = NULL; - u32 idx, next_offset; - int i; - struct tmComResDescrHeader *hdr, *t; - struct tmComResExtDevDescrHeader *exthdr; - struct tmComResPathDescrHeader *pathhdr; - struct tmComResAntTermDescrHeader *anttermhdr; - struct tmComResTunerDescrHeader *tunerunithdr; - struct tmComResDMATermDescrHeader *vcoutputtermhdr; - struct tmComResTSFormatDescrHeader *tsfmt; - struct tmComResPSFormatDescrHeader *psfmt; - struct tmComResSelDescrHeader *psel; - struct tmComResProcDescrHeader *pdh; - struct tmComResAFeatureDescrHeader *afd; - struct tmComResEncoderDescrHeader *edh; - struct tmComResVBIFormatDescrHeader *vbifmt; - u32 currpath = 0; - - dprintk(DBGLVL_API, - "%s(?,?,%d) sizeof(struct tmComResDescrHeader) = %d bytes\n", - __func__, len, (u32)sizeof(struct tmComResDescrHeader)); - - for (idx = 0; idx < (len - sizeof(struct tmComResDescrHeader));) { - - hdr = (struct tmComResDescrHeader *)(buf + idx); - - if (hdr->type != CS_INTERFACE) - return SAA_ERR_NOT_SUPPORTED; - - dprintk(DBGLVL_API, "@ 0x%x =\n", idx); - switch (hdr->subtype) { - case GENERAL_REQUEST: - dprintk(DBGLVL_API, " GENERAL_REQUEST\n"); - break; - case VC_TUNER_PATH: - dprintk(DBGLVL_API, " VC_TUNER_PATH\n"); - pathhdr = (struct tmComResPathDescrHeader *)(buf + idx); - dprintk(DBGLVL_API, " pathid = 0x%x\n", - pathhdr->pathid); - currpath = pathhdr->pathid; - break; - case VC_INPUT_TERMINAL: - dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n"); - anttermhdr = - (struct tmComResAntTermDescrHeader *)(buf + idx); - dprintk(DBGLVL_API, " terminalid = 0x%x\n", - anttermhdr->terminalid); - dprintk(DBGLVL_API, " terminaltype = 0x%x\n", - anttermhdr->terminaltype); - switch (anttermhdr->terminaltype) { - case ITT_ANTENNA: - dprintk(DBGLVL_API, " = ITT_ANTENNA\n"); - break; - case LINE_CONNECTOR: - dprintk(DBGLVL_API, " = LINE_CONNECTOR\n"); - break; - case SPDIF_CONNECTOR: - dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n"); - break; - case COMPOSITE_CONNECTOR: - dprintk(DBGLVL_API, - " = COMPOSITE_CONNECTOR\n"); - break; - case SVIDEO_CONNECTOR: - dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n"); - break; - case COMPONENT_CONNECTOR: - dprintk(DBGLVL_API, - " = COMPONENT_CONNECTOR\n"); - break; - case STANDARD_DMA: - dprintk(DBGLVL_API, " = STANDARD_DMA\n"); - break; - default: - dprintk(DBGLVL_API, " = undefined (0x%x)\n", - anttermhdr->terminaltype); - } - dprintk(DBGLVL_API, " assocterminal= 0x%x\n", - anttermhdr->assocterminal); - dprintk(DBGLVL_API, " iterminal = 0x%x\n", - anttermhdr->iterminal); - dprintk(DBGLVL_API, " controlsize = 0x%x\n", - anttermhdr->controlsize); - break; - case VC_OUTPUT_TERMINAL: - dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n"); - vcoutputtermhdr = - (struct tmComResDMATermDescrHeader *)(buf + idx); - dprintk(DBGLVL_API, " unitid = 0x%x\n", - vcoutputtermhdr->unitid); - dprintk(DBGLVL_API, " terminaltype = 0x%x\n", - vcoutputtermhdr->terminaltype); - switch (vcoutputtermhdr->terminaltype) { - case ITT_ANTENNA: - dprintk(DBGLVL_API, " = ITT_ANTENNA\n"); - break; - case LINE_CONNECTOR: - dprintk(DBGLVL_API, " = LINE_CONNECTOR\n"); - break; - case SPDIF_CONNECTOR: - dprintk(DBGLVL_API, " = SPDIF_CONNECTOR\n"); - break; - case COMPOSITE_CONNECTOR: - dprintk(DBGLVL_API, - " = COMPOSITE_CONNECTOR\n"); - break; - case SVIDEO_CONNECTOR: - dprintk(DBGLVL_API, " = SVIDEO_CONNECTOR\n"); - break; - case COMPONENT_CONNECTOR: - dprintk(DBGLVL_API, - " = COMPONENT_CONNECTOR\n"); - break; - case STANDARD_DMA: - dprintk(DBGLVL_API, " = STANDARD_DMA\n"); - break; - default: - dprintk(DBGLVL_API, " = undefined (0x%x)\n", - vcoutputtermhdr->terminaltype); - } - dprintk(DBGLVL_API, " assocterminal= 0x%x\n", - vcoutputtermhdr->assocterminal); - dprintk(DBGLVL_API, " sourceid = 0x%x\n", - vcoutputtermhdr->sourceid); - dprintk(DBGLVL_API, " iterminal = 0x%x\n", - vcoutputtermhdr->iterminal); - dprintk(DBGLVL_API, " BARLocation = 0x%x\n", - vcoutputtermhdr->BARLocation); - dprintk(DBGLVL_API, " flags = 0x%x\n", - vcoutputtermhdr->flags); - dprintk(DBGLVL_API, " interruptid = 0x%x\n", - vcoutputtermhdr->interruptid); - dprintk(DBGLVL_API, " buffercount = 0x%x\n", - vcoutputtermhdr->buffercount); - dprintk(DBGLVL_API, " metadatasize = 0x%x\n", - vcoutputtermhdr->metadatasize); - dprintk(DBGLVL_API, " controlsize = 0x%x\n", - vcoutputtermhdr->controlsize); - dprintk(DBGLVL_API, " numformats = 0x%x\n", - vcoutputtermhdr->numformats); - - t = (struct tmComResDescrHeader *) - ((struct tmComResDMATermDescrHeader *)(buf + idx)); - next_offset = idx + (vcoutputtermhdr->len); - for (i = 0; i < vcoutputtermhdr->numformats; i++) { - t = (struct tmComResDescrHeader *) - (buf + next_offset); - switch (t->subtype) { - case VS_FORMAT_MPEG2TS: - tsfmt = - (struct tmComResTSFormatDescrHeader *)t; - if (currpath == 1) - tsport = &dev->ports[SAA7164_PORT_TS1]; - else - tsport = &dev->ports[SAA7164_PORT_TS2]; - memcpy(&tsport->hwcfg, vcoutputtermhdr, - sizeof(*vcoutputtermhdr)); - saa7164_api_configure_port_mpeg2ts(dev, - tsport, tsfmt); - break; - case VS_FORMAT_MPEG2PS: - psfmt = - (struct tmComResPSFormatDescrHeader *)t; - if (currpath == 1) - encport = &dev->ports[SAA7164_PORT_ENC1]; - else - encport = &dev->ports[SAA7164_PORT_ENC2]; - memcpy(&encport->hwcfg, vcoutputtermhdr, - sizeof(*vcoutputtermhdr)); - saa7164_api_configure_port_mpeg2ps(dev, - encport, psfmt); - break; - case VS_FORMAT_VBI: - vbifmt = - (struct tmComResVBIFormatDescrHeader *)t; - if (currpath == 1) - vbiport = &dev->ports[SAA7164_PORT_VBI1]; - else - vbiport = &dev->ports[SAA7164_PORT_VBI2]; - memcpy(&vbiport->hwcfg, vcoutputtermhdr, - sizeof(*vcoutputtermhdr)); - memcpy(&vbiport->vbi_fmt_ntsc, vbifmt, - sizeof(*vbifmt)); - saa7164_api_configure_port_vbi(dev, - vbiport); - break; - case VS_FORMAT_RDS: - dprintk(DBGLVL_API, - " = VS_FORMAT_RDS\n"); - break; - case VS_FORMAT_UNCOMPRESSED: - dprintk(DBGLVL_API, - " = VS_FORMAT_UNCOMPRESSED\n"); - break; - case VS_FORMAT_TYPE: - dprintk(DBGLVL_API, - " = VS_FORMAT_TYPE\n"); - break; - default: - dprintk(DBGLVL_API, - " = undefined (0x%x)\n", - t->subtype); - } - next_offset += t->len; - } - - break; - case TUNER_UNIT: - dprintk(DBGLVL_API, " TUNER_UNIT\n"); - tunerunithdr = - (struct tmComResTunerDescrHeader *)(buf + idx); - dprintk(DBGLVL_API, " unitid = 0x%x\n", - tunerunithdr->unitid); - dprintk(DBGLVL_API, " sourceid = 0x%x\n", - tunerunithdr->sourceid); - dprintk(DBGLVL_API, " iunit = 0x%x\n", - tunerunithdr->iunit); - dprintk(DBGLVL_API, " tuningstandards = 0x%x\n", - tunerunithdr->tuningstandards); - dprintk(DBGLVL_API, " controlsize = 0x%x\n", - tunerunithdr->controlsize); - dprintk(DBGLVL_API, " controls = 0x%x\n", - tunerunithdr->controls); - - if (tunerunithdr->unitid == tunerunithdr->iunit) { - if (currpath == 1) - encport = &dev->ports[SAA7164_PORT_ENC1]; - else - encport = &dev->ports[SAA7164_PORT_ENC2]; - memcpy(&encport->tunerunit, tunerunithdr, - sizeof(struct tmComResTunerDescrHeader)); - dprintk(DBGLVL_API, - " (becomes dev->enc[%d] tuner)\n", - encport->nr); - } - break; - case VC_SELECTOR_UNIT: - psel = (struct tmComResSelDescrHeader *)(buf + idx); - dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n"); - dprintk(DBGLVL_API, " unitid = 0x%x\n", - psel->unitid); - dprintk(DBGLVL_API, " nrinpins = 0x%x\n", - psel->nrinpins); - dprintk(DBGLVL_API, " sourceid = 0x%x\n", - psel->sourceid); - break; - case VC_PROCESSING_UNIT: - pdh = (struct tmComResProcDescrHeader *)(buf + idx); - dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n"); - dprintk(DBGLVL_API, " unitid = 0x%x\n", - pdh->unitid); - dprintk(DBGLVL_API, " sourceid = 0x%x\n", - pdh->sourceid); - dprintk(DBGLVL_API, " controlsize = 0x%x\n", - pdh->controlsize); - if (pdh->controlsize == 0x04) { - if (currpath == 1) - encport = &dev->ports[SAA7164_PORT_ENC1]; - else - encport = &dev->ports[SAA7164_PORT_ENC2]; - memcpy(&encport->vidproc, pdh, - sizeof(struct tmComResProcDescrHeader)); - dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", - encport->nr); - } - break; - case FEATURE_UNIT: - afd = (struct tmComResAFeatureDescrHeader *)(buf + idx); - dprintk(DBGLVL_API, " FEATURE_UNIT\n"); - dprintk(DBGLVL_API, " unitid = 0x%x\n", - afd->unitid); - dprintk(DBGLVL_API, " sourceid = 0x%x\n", - afd->sourceid); - dprintk(DBGLVL_API, " controlsize = 0x%x\n", - afd->controlsize); - if (currpath == 1) - encport = &dev->ports[SAA7164_PORT_ENC1]; - else - encport = &dev->ports[SAA7164_PORT_ENC2]; - memcpy(&encport->audfeat, afd, - sizeof(struct tmComResAFeatureDescrHeader)); - dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n", - encport->nr); - break; - case ENCODER_UNIT: - edh = (struct tmComResEncoderDescrHeader *)(buf + idx); - dprintk(DBGLVL_API, " ENCODER_UNIT\n"); - dprintk(DBGLVL_API, " subtype = 0x%x\n", edh->subtype); - dprintk(DBGLVL_API, " unitid = 0x%x\n", edh->unitid); - dprintk(DBGLVL_API, " vsourceid = 0x%x\n", - edh->vsourceid); - dprintk(DBGLVL_API, " asourceid = 0x%x\n", - edh->asourceid); - dprintk(DBGLVL_API, " iunit = 0x%x\n", edh->iunit); - if (edh->iunit == edh->unitid) { - if (currpath == 1) - encport = &dev->ports[SAA7164_PORT_ENC1]; - else - encport = &dev->ports[SAA7164_PORT_ENC2]; - memcpy(&encport->encunit, edh, - sizeof(struct tmComResEncoderDescrHeader)); - dprintk(DBGLVL_API, - " (becomes dev->enc[%d])\n", - encport->nr); - } - break; - case EXTENSION_UNIT: - dprintk(DBGLVL_API, " EXTENSION_UNIT\n"); - exthdr = (struct tmComResExtDevDescrHeader *)(buf + idx); - dprintk(DBGLVL_API, " unitid = 0x%x\n", - exthdr->unitid); - dprintk(DBGLVL_API, " deviceid = 0x%x\n", - exthdr->deviceid); - dprintk(DBGLVL_API, " devicetype = 0x%x\n", - exthdr->devicetype); - if (exthdr->devicetype & 0x1) - dprintk(DBGLVL_API, " = Decoder Device\n"); - if (exthdr->devicetype & 0x2) - dprintk(DBGLVL_API, " = GPIO Source\n"); - if (exthdr->devicetype & 0x4) - dprintk(DBGLVL_API, " = Video Decoder\n"); - if (exthdr->devicetype & 0x8) - dprintk(DBGLVL_API, " = Audio Decoder\n"); - if (exthdr->devicetype & 0x20) - dprintk(DBGLVL_API, " = Crossbar\n"); - if (exthdr->devicetype & 0x40) - dprintk(DBGLVL_API, " = Tuner\n"); - if (exthdr->devicetype & 0x80) - dprintk(DBGLVL_API, " = IF PLL\n"); - if (exthdr->devicetype & 0x100) - dprintk(DBGLVL_API, " = Demodulator\n"); - if (exthdr->devicetype & 0x200) - dprintk(DBGLVL_API, " = RDS Decoder\n"); - if (exthdr->devicetype & 0x400) - dprintk(DBGLVL_API, " = Encoder\n"); - if (exthdr->devicetype & 0x800) - dprintk(DBGLVL_API, " = IR Decoder\n"); - if (exthdr->devicetype & 0x1000) - dprintk(DBGLVL_API, " = EEPROM\n"); - if (exthdr->devicetype & 0x2000) - dprintk(DBGLVL_API, - " = VBI Decoder\n"); - if (exthdr->devicetype & 0x10000) - dprintk(DBGLVL_API, - " = Streaming Device\n"); - if (exthdr->devicetype & 0x20000) - dprintk(DBGLVL_API, - " = DRM Device\n"); - if (exthdr->devicetype & 0x40000000) - dprintk(DBGLVL_API, - " = Generic Device\n"); - if (exthdr->devicetype & 0x80000000) - dprintk(DBGLVL_API, - " = Config Space Device\n"); - dprintk(DBGLVL_API, " numgpiopins = 0x%x\n", - exthdr->numgpiopins); - dprintk(DBGLVL_API, " numgpiogroups = 0x%x\n", - exthdr->numgpiogroups); - dprintk(DBGLVL_API, " controlsize = 0x%x\n", - exthdr->controlsize); - if (exthdr->devicetype & 0x80) { - if (currpath == 1) - encport = &dev->ports[SAA7164_PORT_ENC1]; - else - encport = &dev->ports[SAA7164_PORT_ENC2]; - memcpy(&encport->ifunit, exthdr, - sizeof(struct tmComResExtDevDescrHeader)); - dprintk(DBGLVL_API, - " (becomes dev->enc[%d])\n", - encport->nr); - } - break; - case PVC_INFRARED_UNIT: - dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n"); - break; - case DRM_UNIT: - dprintk(DBGLVL_API, " DRM_UNIT\n"); - break; - default: - dprintk(DBGLVL_API, "default %d\n", hdr->subtype); - } - - dprintk(DBGLVL_API, " 1.%x\n", hdr->len); - dprintk(DBGLVL_API, " 2.%x\n", hdr->type); - dprintk(DBGLVL_API, " 3.%x\n", hdr->subtype); - dprintk(DBGLVL_API, " 4.%x\n", hdr->unitid); - - idx += hdr->len; - } - - return 0; -} - -int saa7164_api_enum_subdevs(struct saa7164_dev *dev) -{ - int ret; - u32 buflen = 0; - u8 *buf; - - dprintk(DBGLVL_API, "%s()\n", __func__); - - /* Get the total descriptor length */ - ret = saa7164_cmd_send(dev, 0, GET_LEN, - GET_DESCRIPTORS_CONTROL, sizeof(buflen), &buflen); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - - dprintk(DBGLVL_API, "%s() total descriptor size = %d bytes.\n", - __func__, buflen); - - /* Allocate enough storage for all of the descs */ - buf = kzalloc(buflen, GFP_KERNEL); - if (!buf) - return SAA_ERR_NO_RESOURCES; - - /* Retrieve them */ - ret = saa7164_cmd_send(dev, 0, GET_CUR, - GET_DESCRIPTORS_CONTROL, buflen, buf); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret); - goto out; - } - - if (saa_debug & DBGLVL_API) - saa7164_dumphex16(dev, buf, (buflen/16)*16); - - saa7164_api_dump_subdevs(dev, buf, buflen); - -out: - kfree(buf); - return ret; -} - -int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg, - u32 datalen, u8 *data) -{ - struct saa7164_dev *dev = bus->dev; - u16 len = 0; - int unitid; - u32 regval; - u8 buf[256]; - int ret; - - dprintk(DBGLVL_API, "%s()\n", __func__); - - if (reglen > 4) - return -EIO; - - if (reglen == 1) - regval = *(reg); - else - if (reglen == 2) - regval = ((*(reg) << 8) || *(reg+1)); - else - if (reglen == 3) - regval = ((*(reg) << 16) | (*(reg+1) << 8) | *(reg+2)); - else - if (reglen == 4) - regval = ((*(reg) << 24) | (*(reg+1) << 16) | - (*(reg+2) << 8) | *(reg+3)); - - /* Prepare the send buffer */ - /* Bytes 00-03 source register length - * 04-07 source bytes to read - * 08... register address - */ - memset(buf, 0, sizeof(buf)); - memcpy((buf + 2 * sizeof(u32) + 0), reg, reglen); - *((u32 *)(buf + 0 * sizeof(u32))) = reglen; - *((u32 *)(buf + 1 * sizeof(u32))) = datalen; - - unitid = saa7164_i2caddr_to_unitid(bus, addr); - if (unitid < 0) { - printk(KERN_ERR - "%s() error, cannot translate regaddr 0x%x to unitid\n", - __func__, addr); - return -EIO; - } - - ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN, - EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret); - return -EIO; - } - - dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len); - - if (saa_debug & DBGLVL_I2C) - saa7164_dumphex16(dev, buf, 2 * 16); - - ret = saa7164_cmd_send(bus->dev, unitid, GET_CUR, - EXU_REGISTER_ACCESS_CONTROL, len, &buf); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret); - else { - if (saa_debug & DBGLVL_I2C) - saa7164_dumphex16(dev, buf, sizeof(buf)); - memcpy(data, (buf + 2 * sizeof(u32) + reglen), datalen); - } - - return ret == SAA_OK ? 0 : -EIO; -} - -/* For a given 8 bit i2c address device, write the buffer */ -int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen, - u8 *data) -{ - struct saa7164_dev *dev = bus->dev; - u16 len = 0; - int unitid; - int reglen; - u8 buf[256]; - int ret; - - dprintk(DBGLVL_API, "%s()\n", __func__); - - if ((datalen == 0) || (datalen > 232)) - return -EIO; - - memset(buf, 0, sizeof(buf)); - - unitid = saa7164_i2caddr_to_unitid(bus, addr); - if (unitid < 0) { - printk(KERN_ERR - "%s() error, cannot translate regaddr 0x%x to unitid\n", - __func__, addr); - return -EIO; - } - - reglen = saa7164_i2caddr_to_reglen(bus, addr); - if (reglen < 0) { - printk(KERN_ERR - "%s() error, cannot translate regaddr to reglen\n", - __func__); - return -EIO; - } - - ret = saa7164_cmd_send(bus->dev, unitid, GET_LEN, - EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret); - return -EIO; - } - - dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len); - - /* Prepare the send buffer */ - /* Bytes 00-03 dest register length - * 04-07 dest bytes to write - * 08... register address - */ - *((u32 *)(buf + 0 * sizeof(u32))) = reglen; - *((u32 *)(buf + 1 * sizeof(u32))) = datalen - reglen; - memcpy((buf + 2 * sizeof(u32)), data, datalen); - - if (saa_debug & DBGLVL_I2C) - saa7164_dumphex16(dev, buf, sizeof(buf)); - - ret = saa7164_cmd_send(bus->dev, unitid, SET_CUR, - EXU_REGISTER_ACCESS_CONTROL, len, &buf); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret); - - return ret == SAA_OK ? 0 : -EIO; -} - -int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid, - u8 pin, u8 state) -{ - int ret; - struct tmComResGPIO t; - - dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n", - __func__, unitid, pin, state); - - if ((pin > 7) || (state > 2)) - return SAA_ERR_BAD_PARAMETER; - - t.pin = pin; - t.state = state; - - ret = saa7164_cmd_send(dev, unitid, SET_CUR, - EXU_GPIO_CONTROL, sizeof(t), &t); - if (ret != SAA_OK) - printk(KERN_ERR "%s() error, ret = 0x%x\n", - __func__, ret); - - return ret; -} - -int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, - u8 pin) -{ - return saa7164_api_modify_gpio(dev, unitid, pin, 1); -} - -int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, - u8 pin) -{ - return saa7164_api_modify_gpio(dev, unitid, pin, 0); -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-buffer.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-buffer.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-buffer.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-buffer.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,322 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#include "saa7164.h" - -/* The PCI address space for buffer handling looks like this: - * - * +-u32 wide-------------+ - * | + - * +-u64 wide------------------------------------+ - * + + - * +----------------------+ - * | CurrentBufferPtr + Pointer to current PCI buffer >-+ - * +----------------------+ | - * | Unused + | - * +----------------------+ | - * | Pitch + = 188 (bytes) | - * +----------------------+ | - * | PCI buffer size + = pitch * number of lines (312) | - * +----------------------+ | - * |0| Buf0 Write Offset + | - * +----------------------+ v - * |1| Buf1 Write Offset + | - * +----------------------+ | - * |2| Buf2 Write Offset + | - * +----------------------+ | - * |3| Buf3 Write Offset + | - * +----------------------+ | - * ... More write offsets | - * +---------------------------------------------+ | - * +0| set of ptrs to PCI pagetables + | - * +---------------------------------------------+ | - * +1| set of ptrs to PCI pagetables + <--------+ - * +---------------------------------------------+ - * +2| set of ptrs to PCI pagetables + - * +---------------------------------------------+ - * +3| set of ptrs to PCI pagetables + >--+ - * +---------------------------------------------+ | - * ... More buffer pointers | +----------------+ - * +->| pt[0] TS data | - * | +----------------+ - * | - * | +----------------+ - * +->| pt[1] TS data | - * | +----------------+ - * | etc - */ - -void saa7164_buffer_display(struct saa7164_buffer *buf) -{ - struct saa7164_dev *dev = buf->port->dev; - int i; - - dprintk(DBGLVL_BUF, "%s() buffer @ 0x%p nr=%d\n", - __func__, buf, buf->idx); - dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08llx len = 0x%x\n", - buf->cpu, (long long)buf->dma, buf->pci_size); - dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08llx len = 0x%x\n", - buf->pt_cpu, (long long)buf->pt_dma, buf->pt_size); - - /* Format the Page Table Entries to point into the data buffer */ - for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) { - - dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n", - i, buf->pt_cpu, (u64)*(buf->pt_cpu)); - - } -} -/* Allocate a new buffer structure and associated PCI space in bytes. - * len must be a multiple of sizeof(u64) - */ -struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, - u32 len) -{ - struct tmHWStreamParameters *params = &port->hw_streamingparams; - struct saa7164_buffer *buf = NULL; - struct saa7164_dev *dev = port->dev; - int i; - - if ((len == 0) || (len >= 65536) || (len % sizeof(u64))) { - log_warn("%s() SAA_ERR_BAD_PARAMETER\n", __func__); - goto ret; - } - - buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL); - if (!buf) { - log_warn("%s() SAA_ERR_NO_RESOURCES\n", __func__); - goto ret; - } - - buf->idx = -1; - buf->port = port; - buf->flags = SAA7164_BUFFER_FREE; - buf->pos = 0; - buf->actual_size = params->pitch * params->numberoflines; - buf->crc = 0; - /* TODO: arg len is being ignored */ - buf->pci_size = SAA7164_PT_ENTRIES * 0x1000; - buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000; - - /* Allocate contiguous memory */ - buf->cpu = pci_alloc_consistent(port->dev->pci, buf->pci_size, - &buf->dma); - if (!buf->cpu) - goto fail1; - - buf->pt_cpu = pci_alloc_consistent(port->dev->pci, buf->pt_size, - &buf->pt_dma); - if (!buf->pt_cpu) - goto fail2; - - /* init the buffers to a known pattern, easier during debugging */ - memset_io(buf->cpu, 0xff, buf->pci_size); - buf->crc = crc32(0, buf->cpu, buf->actual_size); - memset_io(buf->pt_cpu, 0xff, buf->pt_size); - - dprintk(DBGLVL_BUF, "%s() allocated buffer @ 0x%p (%d pageptrs)\n", - __func__, buf, params->numpagetables); - dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08lx len = 0x%x\n", - buf->cpu, (long)buf->dma, buf->pci_size); - dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08lx len = 0x%x\n", - buf->pt_cpu, (long)buf->pt_dma, buf->pt_size); - - /* Format the Page Table Entries to point into the data buffer */ - for (i = 0 ; i < params->numpagetables; i++) { - - *(buf->pt_cpu + i) = buf->dma + (i * 0x1000); /* TODO */ - dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n", - i, buf->pt_cpu, (u64)*(buf->pt_cpu)); - - } - - goto ret; - -fail2: - pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma); -fail1: - kfree(buf); - - buf = NULL; -ret: - return buf; -} - -int saa7164_buffer_dealloc(struct saa7164_buffer *buf) -{ - struct saa7164_dev *dev; - - if (!buf || !buf->port) - return SAA_ERR_BAD_PARAMETER; - dev = buf->port->dev; - - dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n", - __func__, buf); - - if (buf->flags != SAA7164_BUFFER_FREE) - log_warn(" freeing a non-free buffer\n"); - - pci_free_consistent(dev->pci, buf->pci_size, buf->cpu, buf->dma); - pci_free_consistent(dev->pci, buf->pt_size, buf->pt_cpu, buf->pt_dma); - - kfree(buf); - - return SAA_OK; -} - -int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i) -{ - struct saa7164_dev *dev = port->dev; - - if ((i < 0) || (i >= port->hwcfg.buffercount)) - return -EINVAL; - - dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i); - - saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0); - - return 0; -} - -/* Write a buffer into the hardware */ -int saa7164_buffer_activate(struct saa7164_buffer *buf, int i) -{ - struct saa7164_port *port = buf->port; - struct saa7164_dev *dev = port->dev; - - if ((i < 0) || (i >= port->hwcfg.buffercount)) - return -EINVAL; - - dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i); - - buf->idx = i; /* Note of which buffer list index position we occupy */ - buf->flags = SAA7164_BUFFER_BUSY; - buf->pos = 0; - - /* TODO: Review this in light of 32v64 assignments */ - saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0); - saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), buf->pt_dma); - saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0); - - dprintk(DBGLVL_BUF, " buf[%d] offset 0x%llx (0x%x) " - "buf 0x%llx/%llx (0x%x/%x) nr=%d\n", - buf->idx, - (u64)port->bufoffset + (i * sizeof(u32)), - saa7164_readl(port->bufoffset + (sizeof(u32) * i)), - (u64)port->bufptr32h + ((sizeof(u32) * 2) * i), - (u64)port->bufptr32l + ((sizeof(u32) * 2) * i), - saa7164_readl(port->bufptr32h + ((sizeof(u32) * i) * 2)), - saa7164_readl(port->bufptr32l + ((sizeof(u32) * i) * 2)), - buf->idx); - - return 0; -} - -int saa7164_buffer_cfg_port(struct saa7164_port *port) -{ - struct tmHWStreamParameters *params = &port->hw_streamingparams; - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - struct list_head *c, *n; - int i = 0; - - dprintk(DBGLVL_BUF, "%s(port=%d)\n", __func__, port->nr); - - saa7164_writel(port->bufcounter, 0); - saa7164_writel(port->pitch, params->pitch); - saa7164_writel(port->bufsize, params->pitch * params->numberoflines); - - dprintk(DBGLVL_BUF, " configured:\n"); - dprintk(DBGLVL_BUF, " lmmio 0x%p\n", dev->lmmio); - dprintk(DBGLVL_BUF, " bufcounter 0x%x = 0x%x\n", port->bufcounter, - saa7164_readl(port->bufcounter)); - - dprintk(DBGLVL_BUF, " pitch 0x%x = %d\n", port->pitch, - saa7164_readl(port->pitch)); - - dprintk(DBGLVL_BUF, " bufsize 0x%x = %d\n", port->bufsize, - saa7164_readl(port->bufsize)); - - dprintk(DBGLVL_BUF, " buffercount = %d\n", port->hwcfg.buffercount); - dprintk(DBGLVL_BUF, " bufoffset = 0x%x\n", port->bufoffset); - dprintk(DBGLVL_BUF, " bufptr32h = 0x%x\n", port->bufptr32h); - dprintk(DBGLVL_BUF, " bufptr32l = 0x%x\n", port->bufptr32l); - - /* Poke the buffers and offsets into PCI space */ - mutex_lock(&port->dmaqueue_lock); - list_for_each_safe(c, n, &port->dmaqueue.list) { - buf = list_entry(c, struct saa7164_buffer, list); - - if (buf->flags != SAA7164_BUFFER_FREE) - BUG(); - - /* Place the buffer in the h/w queue */ - saa7164_buffer_activate(buf, i); - - /* Don't exceed the device maximum # bufs */ - if (i++ > port->hwcfg.buffercount) - BUG(); - - } - mutex_unlock(&port->dmaqueue_lock); - - return 0; -} - -struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev, - u32 len) -{ - struct saa7164_user_buffer *buf; - - buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL); - if (!buf) - return NULL; - - buf->data = kzalloc(len, GFP_KERNEL); - - if (!buf->data) { - kfree(buf); - return NULL; - } - - buf->actual_size = len; - buf->pos = 0; - buf->crc = 0; - - dprintk(DBGLVL_BUF, "%s() allocated user buffer @ 0x%p\n", - __func__, buf); - - return buf; -} - -void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf) -{ - if (!buf) - return; - - kfree(buf->data); - buf->data = NULL; - - kfree(buf); -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-bus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-bus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-bus.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-bus.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,475 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "saa7164.h" - -/* The message bus to/from the firmware is a ring buffer in PCI address - * space. Establish the defaults. - */ -int saa7164_bus_setup(struct saa7164_dev *dev) -{ - struct tmComResBusInfo *b = &dev->bus; - - mutex_init(&b->lock); - - b->Type = TYPE_BUS_PCIe; - b->m_wMaxReqSize = SAA_DEVICE_MAXREQUESTSIZE; - - b->m_pdwSetRing = (u8 *)(dev->bmmio + - ((u32)dev->busdesc.CommandRing)); - - b->m_dwSizeSetRing = SAA_DEVICE_BUFFERBLOCKSIZE; - - b->m_pdwGetRing = (u8 *)(dev->bmmio + - ((u32)dev->busdesc.ResponseRing)); - - b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE; - - b->m_dwSetWritePos = ((u32)dev->intfdesc.BARLocation) + - (2 * sizeof(u64)); - b->m_dwSetReadPos = b->m_dwSetWritePos + (1 * sizeof(u32)); - - b->m_dwGetWritePos = b->m_dwSetWritePos + (2 * sizeof(u32)); - b->m_dwGetReadPos = b->m_dwSetWritePos + (3 * sizeof(u32)); - - return 0; -} - -void saa7164_bus_dump(struct saa7164_dev *dev) -{ - struct tmComResBusInfo *b = &dev->bus; - - dprintk(DBGLVL_BUS, "Dumping the bus structure:\n"); - dprintk(DBGLVL_BUS, " .type = %d\n", b->Type); - dprintk(DBGLVL_BUS, " .dev->bmmio = 0x%p\n", dev->bmmio); - dprintk(DBGLVL_BUS, " .m_wMaxReqSize = 0x%x\n", b->m_wMaxReqSize); - dprintk(DBGLVL_BUS, " .m_pdwSetRing = 0x%p\n", b->m_pdwSetRing); - dprintk(DBGLVL_BUS, " .m_dwSizeSetRing = 0x%x\n", b->m_dwSizeSetRing); - dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing); - dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing); - - dprintk(DBGLVL_BUS, " .m_dwSetReadPos = 0x%x (0x%08x)\n", - b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos)); - - dprintk(DBGLVL_BUS, " .m_dwSetWritePos = 0x%x (0x%08x)\n", - b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos)); - - dprintk(DBGLVL_BUS, " .m_dwGetReadPos = 0x%x (0x%08x)\n", - b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos)); - - dprintk(DBGLVL_BUS, " .m_dwGetWritePos = 0x%x (0x%08x)\n", - b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos)); - -} - -/* Intensionally throw a BUG() if the state of the message bus looks corrupt */ -void saa7164_bus_verify(struct saa7164_dev *dev) -{ - struct tmComResBusInfo *b = &dev->bus; - int bug = 0; - - if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing) - bug++; - - if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing) - bug++; - - if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing) - bug++; - - if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing) - bug++; - - if (bug) { - saa_debug = 0xffff; /* Ensure we get the bus dump */ - saa7164_bus_dump(dev); - saa_debug = 1024; /* Ensure we get the bus dump */ - BUG(); - } -} - -void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m, - void *buf) -{ - dprintk(DBGLVL_BUS, "Dumping msg structure:\n"); - dprintk(DBGLVL_BUS, " .id = %d\n", m->id); - dprintk(DBGLVL_BUS, " .flags = 0x%x\n", m->flags); - dprintk(DBGLVL_BUS, " .size = 0x%x\n", m->size); - dprintk(DBGLVL_BUS, " .command = 0x%x\n", m->command); - dprintk(DBGLVL_BUS, " .controlselector = 0x%x\n", m->controlselector); - dprintk(DBGLVL_BUS, " .seqno = %d\n", m->seqno); - if (buf) - dprintk(DBGLVL_BUS, " .buffer (ignored)\n"); -} - -/* - * Places a command or a response on the bus. The implementation does not - * know if it is a command or a response it just places the data on the - * bus depending on the bus information given in the struct tmComResBusInfo - * structure. If the command or response does not fit into the bus ring - * buffer it will be refused. - * - * Return Value: - * SAA_OK The function executed successfully. - * < 0 One or more members are not initialized. - */ -int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, - void *buf) -{ - struct tmComResBusInfo *bus = &dev->bus; - u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp; - u32 new_swp, space_rem; - int ret = SAA_ERR_BAD_PARAMETER; - - if (!msg) { - printk(KERN_ERR "%s() !msg\n", __func__); - return SAA_ERR_BAD_PARAMETER; - } - - dprintk(DBGLVL_BUS, "%s()\n", __func__); - - saa7164_bus_verify(dev); - - msg->size = cpu_to_le16(msg->size); - msg->command = cpu_to_le16(msg->command); - msg->controlselector = cpu_to_le16(msg->controlselector); - - if (msg->size > dev->bus.m_wMaxReqSize) { - printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", - __func__); - return SAA_ERR_BAD_PARAMETER; - } - - if ((msg->size > 0) && (buf == NULL)) { - printk(KERN_ERR "%s() Missing message buffer\n", __func__); - return SAA_ERR_BAD_PARAMETER; - } - - /* Lock the bus from any other access */ - mutex_lock(&bus->lock); - - bytes_to_write = sizeof(*msg) + msg->size; - free_write_space = 0; - timeout = SAA_BUS_TIMEOUT; - curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos)); - curr_swp = le32_to_cpu(saa7164_readl(bus->m_dwSetWritePos)); - - /* Deal with ring wrapping issues */ - if (curr_srp > curr_swp) - /* Deal with the wrapped ring */ - free_write_space = curr_srp - curr_swp; - else - /* The ring has not wrapped yet */ - free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp; - - dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__, - bytes_to_write); - - dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__, - free_write_space); - - dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp); - dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp); - - /* Process the msg and write the content onto the bus */ - while (bytes_to_write >= free_write_space) { - - if (timeout-- == 0) { - printk(KERN_ERR "%s() bus timeout\n", __func__); - ret = SAA_ERR_NO_RESOURCES; - goto out; - } - - /* TODO: Review this delay, efficient? */ - /* Wait, allowing the hardware fetch time */ - mdelay(1); - - /* Check the space usage again */ - curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos)); - - /* Deal with ring wrapping issues */ - if (curr_srp > curr_swp) - /* Deal with the wrapped ring */ - free_write_space = curr_srp - curr_swp; - else - /* Read didn't wrap around the buffer */ - free_write_space = (curr_srp + bus->m_dwSizeSetRing) - - curr_swp; - - } - - /* Calculate the new write position */ - new_swp = curr_swp + bytes_to_write; - - dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); - dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__, - bus->m_dwSizeSetRing); - - /* Mental Note: line 462 tmmhComResBusPCIe.cpp */ - - /* Check if we're going to wrap again */ - if (new_swp > bus->m_dwSizeSetRing) { - - /* Ring wraps */ - new_swp -= bus->m_dwSizeSetRing; - - space_rem = bus->m_dwSizeSetRing - curr_swp; - - dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__, - space_rem); - - dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__, - (u32)sizeof(*msg)); - - if (space_rem < sizeof(*msg)) { - dprintk(DBGLVL_BUS, "%s() tr4\n", __func__); - - /* Split the msg into pieces as the ring wraps */ - memcpy(bus->m_pdwSetRing + curr_swp, msg, space_rem); - memcpy(bus->m_pdwSetRing, (u8 *)msg + space_rem, - sizeof(*msg) - space_rem); - - memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem, - buf, msg->size); - - } else if (space_rem == sizeof(*msg)) { - dprintk(DBGLVL_BUS, "%s() tr5\n", __func__); - - /* Additional data at the beginning of the ring */ - memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); - memcpy(bus->m_pdwSetRing, buf, msg->size); - - } else { - /* Additional data wraps around the ring */ - memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); - if (msg->size > 0) { - memcpy(bus->m_pdwSetRing + curr_swp + - sizeof(*msg), buf, space_rem - - sizeof(*msg)); - memcpy(bus->m_pdwSetRing, (u8 *)buf + - space_rem - sizeof(*msg), - bytes_to_write - space_rem); - } - - } - - } /* (new_swp > bus->m_dwSizeSetRing) */ - else { - dprintk(DBGLVL_BUS, "%s() tr6\n", __func__); - - /* The ring buffer doesn't wrap, two simple copies */ - memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); - memcpy(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf, - msg->size); - } - - dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); - - /* Update the bus write position */ - saa7164_writel(bus->m_dwSetWritePos, cpu_to_le32(new_swp)); - ret = SAA_OK; - -out: - saa7164_bus_dump(dev); - mutex_unlock(&bus->lock); - saa7164_bus_verify(dev); - return ret; -} - -/* - * Receive a command or a response from the bus. The implementation does not - * know if it is a command or a response it simply dequeues the data, - * depending on the bus information given in the struct tmComResBusInfo - * structure. - * - * Return Value: - * 0 The function executed successfully. - * < 0 One or more members are not initialized. - */ -int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, - void *buf, int peekonly) -{ - struct tmComResBusInfo *bus = &dev->bus; - u32 bytes_to_read, write_distance, curr_grp, curr_gwp, - new_grp, buf_size, space_rem; - struct tmComResInfo msg_tmp; - int ret = SAA_ERR_BAD_PARAMETER; - - saa7164_bus_verify(dev); - - if (msg == NULL) - return ret; - - if (msg->size > dev->bus.m_wMaxReqSize) { - printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", - __func__); - return ret; - } - - if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) { - printk(KERN_ERR - "%s() Missing msg buf, size should be %d bytes\n", - __func__, msg->size); - return ret; - } - - mutex_lock(&bus->lock); - - /* Peek the bus to see if a msg exists, if it's not what we're expecting - * then return cleanly else read the message from the bus. - */ - curr_gwp = le32_to_cpu(saa7164_readl(bus->m_dwGetWritePos)); - curr_grp = le32_to_cpu(saa7164_readl(bus->m_dwGetReadPos)); - - if (curr_gwp == curr_grp) { - ret = SAA_ERR_EMPTY; - goto out; - } - - bytes_to_read = sizeof(*msg); - - /* Calculate write distance to current read position */ - write_distance = 0; - if (curr_gwp >= curr_grp) - /* Write doesn't wrap around the ring */ - write_distance = curr_gwp - curr_grp; - else - /* Write wraps around the ring */ - write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; - - if (bytes_to_read > write_distance) { - printk(KERN_ERR "%s() No message/response found\n", __func__); - ret = SAA_ERR_INVALID_COMMAND; - goto out; - } - - /* Calculate the new read position */ - new_grp = curr_grp + bytes_to_read; - if (new_grp > bus->m_dwSizeGetRing) { - - /* Ring wraps */ - new_grp -= bus->m_dwSizeGetRing; - space_rem = bus->m_dwSizeGetRing - curr_grp; - - memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem); - memcpy((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing, - bytes_to_read - space_rem); - - } else { - /* No wrapping */ - memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read); - } - - /* No need to update the read positions, because this was a peek */ - /* If the caller specifically want to peek, return */ - if (peekonly) { - memcpy(msg, &msg_tmp, sizeof(*msg)); - goto peekout; - } - - /* Check if the command/response matches what is expected */ - if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) || - (msg_tmp.controlselector != msg->controlselector) || - (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) { - - printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__); - saa7164_bus_dumpmsg(dev, msg, buf); - saa7164_bus_dumpmsg(dev, &msg_tmp, NULL); - ret = SAA_ERR_INVALID_COMMAND; - goto out; - } - - /* Get the actual command and response from the bus */ - buf_size = msg->size; - - bytes_to_read = sizeof(*msg) + msg->size; - /* Calculate write distance to current read position */ - write_distance = 0; - if (curr_gwp >= curr_grp) - /* Write doesn't wrap around the ring */ - write_distance = curr_gwp - curr_grp; - else - /* Write wraps around the ring */ - write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; - - if (bytes_to_read > write_distance) { - printk(KERN_ERR "%s() Invalid bus state, missing msg " - "or mangled ring, faulty H/W / bad code?\n", __func__); - ret = SAA_ERR_INVALID_COMMAND; - goto out; - } - - /* Calculate the new read position */ - new_grp = curr_grp + bytes_to_read; - if (new_grp > bus->m_dwSizeGetRing) { - - /* Ring wraps */ - new_grp -= bus->m_dwSizeGetRing; - space_rem = bus->m_dwSizeGetRing - curr_grp; - - if (space_rem < sizeof(*msg)) { - /* msg wraps around the ring */ - memcpy(msg, bus->m_pdwGetRing + curr_grp, space_rem); - memcpy((u8 *)msg + space_rem, bus->m_pdwGetRing, - sizeof(*msg) - space_rem); - if (buf) - memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) - - space_rem, buf_size); - - } else if (space_rem == sizeof(*msg)) { - memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); - if (buf) - memcpy(buf, bus->m_pdwGetRing, buf_size); - } else { - /* Additional data wraps around the ring */ - memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); - if (buf) { - memcpy(buf, bus->m_pdwGetRing + curr_grp + - sizeof(*msg), space_rem - sizeof(*msg)); - memcpy(buf + space_rem - sizeof(*msg), - bus->m_pdwGetRing, bytes_to_read - - space_rem); - } - - } - - } else { - /* No wrapping */ - memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); - if (buf) - memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), - buf_size); - } - - /* Update the read positions, adjusting the ring */ - saa7164_writel(bus->m_dwGetReadPos, cpu_to_le32(new_grp)); - -peekout: - msg->size = le16_to_cpu(msg->size); - msg->command = le16_to_cpu(msg->command); - msg->controlselector = le16_to_cpu(msg->controlselector); - ret = SAA_OK; -out: - mutex_unlock(&bus->lock); - saa7164_bus_verify(dev); - return ret; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-cards.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,649 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "saa7164.h" - -/* The Bridge API needs to understand register widths (in bytes) for the - * attached I2C devices, so we can simplify the virtual i2c mechansms - * and keep the -i2c.c implementation clean. - */ -#define REGLEN_8bit 1 -#define REGLEN_16bit 2 - -struct saa7164_board saa7164_boards[] = { - [SAA7164_BOARD_UNKNOWN] = { - /* Bridge will not load any firmware, without knowing - * the rev this would be fatal. */ - .name = "Unknown", - }, - [SAA7164_BOARD_UNKNOWN_REV2] = { - /* Bridge will load the v2 f/w and dump descriptors */ - /* Required during new board bringup */ - .name = "Generic Rev2", - .chiprev = SAA7164_CHIP_REV2, - }, - [SAA7164_BOARD_UNKNOWN_REV3] = { - /* Bridge will load the v2 f/w and dump descriptors */ - /* Required during new board bringup */ - .name = "Generic Rev3", - .chiprev = SAA7164_CHIP_REV3, - }, - [SAA7164_BOARD_HAUPPAUGE_HVR2200] = { - .name = "Hauppauge WinTV-HVR2200", - .porta = SAA7164_MPEG_DVB, - .portb = SAA7164_MPEG_DVB, - .portc = SAA7164_MPEG_ENCODER, - .portd = SAA7164_MPEG_ENCODER, - .porte = SAA7164_MPEG_VBI, - .portf = SAA7164_MPEG_VBI, - .chiprev = SAA7164_CHIP_REV3, - .unit = {{ - .id = 0x1d, - .type = SAA7164_UNIT_EEPROM, - .name = "4K EEPROM", - .i2c_bus_nr = SAA7164_I2C_BUS_0, - .i2c_bus_addr = 0xa0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x04, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1b, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1e, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "TDA10048-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x10 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1f, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "TDA10048-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x12 >> 1, - .i2c_reg_len = REGLEN_8bit, - } }, - }, - [SAA7164_BOARD_HAUPPAUGE_HVR2200_2] = { - .name = "Hauppauge WinTV-HVR2200", - .porta = SAA7164_MPEG_DVB, - .portb = SAA7164_MPEG_DVB, - .portc = SAA7164_MPEG_ENCODER, - .portd = SAA7164_MPEG_ENCODER, - .porte = SAA7164_MPEG_VBI, - .portf = SAA7164_MPEG_VBI, - .chiprev = SAA7164_CHIP_REV2, - .unit = {{ - .id = 0x06, - .type = SAA7164_UNIT_EEPROM, - .name = "4K EEPROM", - .i2c_bus_nr = SAA7164_I2C_BUS_0, - .i2c_bus_addr = 0xa0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x04, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x05, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "TDA10048-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x10 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1e, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1f, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "TDA10048-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x12 >> 1, - .i2c_reg_len = REGLEN_8bit, - } }, - }, - [SAA7164_BOARD_HAUPPAUGE_HVR2200_3] = { - .name = "Hauppauge WinTV-HVR2200", - .porta = SAA7164_MPEG_DVB, - .portb = SAA7164_MPEG_DVB, - .portc = SAA7164_MPEG_ENCODER, - .portd = SAA7164_MPEG_ENCODER, - .porte = SAA7164_MPEG_VBI, - .portf = SAA7164_MPEG_VBI, - .chiprev = SAA7164_CHIP_REV2, - .unit = {{ - .id = 0x1d, - .type = SAA7164_UNIT_EEPROM, - .name = "4K EEPROM", - .i2c_bus_nr = SAA7164_I2C_BUS_0, - .i2c_bus_addr = 0xa0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x04, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x05, - .type = SAA7164_UNIT_ANALOG_DEMODULATOR, - .name = "TDA8290-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x84 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1b, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1c, - .type = SAA7164_UNIT_ANALOG_DEMODULATOR, - .name = "TDA8290-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x84 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1e, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "TDA10048-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x10 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1f, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "TDA10048-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x12 >> 1, - .i2c_reg_len = REGLEN_8bit, - } }, - }, - [SAA7164_BOARD_HAUPPAUGE_HVR2250] = { - .name = "Hauppauge WinTV-HVR2250", - .porta = SAA7164_MPEG_DVB, - .portb = SAA7164_MPEG_DVB, - .portc = SAA7164_MPEG_ENCODER, - .portd = SAA7164_MPEG_ENCODER, - .portc = SAA7164_MPEG_ENCODER, - .portd = SAA7164_MPEG_ENCODER, - .porte = SAA7164_MPEG_VBI, - .portf = SAA7164_MPEG_VBI, - .chiprev = SAA7164_CHIP_REV3, - .unit = {{ - .id = 0x22, - .type = SAA7164_UNIT_EEPROM, - .name = "4K EEPROM", - .i2c_bus_nr = SAA7164_I2C_BUS_0, - .i2c_bus_addr = 0xa0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x04, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x07, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-1 (TOP)", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x32 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x08, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-1 (QAM)", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x34 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x1e, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x20, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-2 (TOP)", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x32 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x23, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-2 (QAM)", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x34 >> 1, - .i2c_reg_len = REGLEN_8bit, - } }, - }, - [SAA7164_BOARD_HAUPPAUGE_HVR2250_2] = { - .name = "Hauppauge WinTV-HVR2250", - .porta = SAA7164_MPEG_DVB, - .portb = SAA7164_MPEG_DVB, - .portc = SAA7164_MPEG_ENCODER, - .portd = SAA7164_MPEG_ENCODER, - .porte = SAA7164_MPEG_VBI, - .portf = SAA7164_MPEG_VBI, - .porte = SAA7164_MPEG_VBI, - .portf = SAA7164_MPEG_VBI, - .chiprev = SAA7164_CHIP_REV3, - .unit = {{ - .id = 0x28, - .type = SAA7164_UNIT_EEPROM, - .name = "4K EEPROM", - .i2c_bus_nr = SAA7164_I2C_BUS_0, - .i2c_bus_addr = 0xa0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x04, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x07, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-1 (TOP)", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x32 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x08, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-1 (QAM)", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x34 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x24, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x26, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-2 (TOP)", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x32 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x29, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-2 (QAM)", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x34 >> 1, - .i2c_reg_len = REGLEN_8bit, - } }, - }, - [SAA7164_BOARD_HAUPPAUGE_HVR2250_3] = { - .name = "Hauppauge WinTV-HVR2250", - .porta = SAA7164_MPEG_DVB, - .portb = SAA7164_MPEG_DVB, - .portc = SAA7164_MPEG_ENCODER, - .portd = SAA7164_MPEG_ENCODER, - .porte = SAA7164_MPEG_VBI, - .portf = SAA7164_MPEG_VBI, - .chiprev = SAA7164_CHIP_REV3, - .unit = {{ - .id = 0x26, - .type = SAA7164_UNIT_EEPROM, - .name = "4K EEPROM", - .i2c_bus_nr = SAA7164_I2C_BUS_0, - .i2c_bus_addr = 0xa0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x04, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-1", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x07, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-1 (TOP)", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x32 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x08, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-1 (QAM)", - .i2c_bus_nr = SAA7164_I2C_BUS_1, - .i2c_bus_addr = 0x34 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x22, - .type = SAA7164_UNIT_TUNER, - .name = "TDA18271-2", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0xc0 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x24, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-2 (TOP)", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x32 >> 1, - .i2c_reg_len = REGLEN_8bit, - }, { - .id = 0x27, - .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, - .name = "CX24228/S5H1411-2 (QAM)", - .i2c_bus_nr = SAA7164_I2C_BUS_2, - .i2c_bus_addr = 0x34 >> 1, - .i2c_reg_len = REGLEN_8bit, - } }, - }, -}; -const unsigned int saa7164_bcount = ARRAY_SIZE(saa7164_boards); - -/* ------------------------------------------------------------------ */ -/* PCI subsystem IDs */ - -struct saa7164_subid saa7164_subids[] = { - { - .subvendor = 0x0070, - .subdevice = 0x8880, - .card = SAA7164_BOARD_HAUPPAUGE_HVR2250, - }, { - .subvendor = 0x0070, - .subdevice = 0x8810, - .card = SAA7164_BOARD_HAUPPAUGE_HVR2250, - }, { - .subvendor = 0x0070, - .subdevice = 0x8980, - .card = SAA7164_BOARD_HAUPPAUGE_HVR2200, - }, { - .subvendor = 0x0070, - .subdevice = 0x8900, - .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_2, - }, { - .subvendor = 0x0070, - .subdevice = 0x8901, - .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_3, - }, { - .subvendor = 0x0070, - .subdevice = 0x88A1, - .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_3, - }, { - .subvendor = 0x0070, - .subdevice = 0x8891, - .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, - }, { - .subvendor = 0x0070, - .subdevice = 0x8851, - .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, - }, -}; -const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids); - -void saa7164_card_list(struct saa7164_dev *dev) -{ - int i; - - if (0 == dev->pci->subsystem_vendor && - 0 == dev->pci->subsystem_device) { - printk(KERN_ERR - "%s: Board has no valid PCIe Subsystem ID and can't\n" - "%s: be autodetected. Pass card= insmod option to\n" - "%s: workaround that. Send complaints to the vendor\n" - "%s: of the TV card. Best regards,\n" - "%s: -- tux\n", - dev->name, dev->name, dev->name, dev->name, dev->name); - } else { - printk(KERN_ERR - "%s: Your board isn't known (yet) to the driver.\n" - "%s: Try to pick one of the existing card configs via\n" - "%s: card= insmod option. Updating to the latest\n" - "%s: version might help as well.\n", - dev->name, dev->name, dev->name, dev->name); - } - - printk(KERN_ERR "%s: Here are valid choices for the card= insmod " - "option:\n", dev->name); - - for (i = 0; i < saa7164_bcount; i++) - printk(KERN_ERR "%s: card=%d -> %s\n", - dev->name, i, saa7164_boards[i].name); -} - -/* TODO: clean this define up into the -cards.c structs */ -#define PCIEBRIDGE_UNITID 2 - -void saa7164_gpio_setup(struct saa7164_dev *dev) -{ - switch (dev->board) { - case SAA7164_BOARD_HAUPPAUGE_HVR2200: - case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: - case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: - case SAA7164_BOARD_HAUPPAUGE_HVR2250: - case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: - case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: - /* - GPIO 2: s5h1411 / tda10048-1 demod reset - GPIO 3: s5h1411 / tda10048-2 demod reset - GPIO 7: IRBlaster Zilog reset - */ - - /* Reset parts by going in and out of reset */ - saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 2); - saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 3); - - msleep(20); - - saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 2); - saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 3); - break; - } -} - -static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data) -{ - struct tveeprom tv; - - /* TODO: Assumption: eeprom on bus 0 */ - tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, - eeprom_data); - - /* Make sure we support the board model */ - switch (tv.model) { - case 88001: - /* Development board - Limit circulation */ - /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) - * ATSC/QAM (TDA18271/S5H1411) and basic analog, no IR, FM */ - case 88021: - /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) - * ATSC/QAM (TDA18271/S5H1411) and basic analog, MCE CIR, FM */ - break; - case 88041: - /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) - * ATSC/QAM (TDA18271/S5H1411) and basic analog, no IR, FM */ - break; - case 88061: - /* WinTV-HVR2250 (PCIe, Retail, full-height bracket) - * ATSC/QAM (TDA18271/S5H1411) and basic analog, FM */ - break; - case 89519: - case 89609: - /* WinTV-HVR2200 (PCIe, Retail, full-height) - * DVB-T (TDA18271/TDA10048) and basic analog, no IR */ - break; - case 89619: - /* WinTV-HVR2200 (PCIe, Retail, half-height) - * DVB-T (TDA18271/TDA10048) and basic analog, no IR */ - break; - default: - printk(KERN_ERR "%s: Warning: Unknown Hauppauge model #%d\n", - dev->name, tv.model); - break; - } - - printk(KERN_INFO "%s: Hauppauge eeprom: model=%d\n", dev->name, - tv.model); -} - -void saa7164_card_setup(struct saa7164_dev *dev) -{ - static u8 eeprom[256]; - - if (dev->i2c_bus[0].i2c_rc == 0) { - if (saa7164_api_read_eeprom(dev, &eeprom[0], - sizeof(eeprom)) < 0) - return; - } - - switch (dev->board) { - case SAA7164_BOARD_HAUPPAUGE_HVR2200: - case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: - case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: - case SAA7164_BOARD_HAUPPAUGE_HVR2250: - case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: - case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: - hauppauge_eeprom(dev, &eeprom[0]); - break; - } -} - -/* With most other drivers, the kernel expects to communicate with subdrivers - * through i2c. This bridge does not allow that, it does not expose any direct - * access to I2C. Instead we have to communicate through the device f/w for - * register access to 'processing units'. Each unit has a unique - * id, regardless of how the physical implementation occurs across - * the three physical i2c busses. The being said if we want leverge of - * the existing kernel drivers for tuners and demods we have to 'speak i2c', - * to this bridge implements 3 virtual i2c buses. This is a helper function - * for those. - * - * Description: Translate the kernels notion of an i2c address and bus into - * the appropriate unitid. - */ -int saa7164_i2caddr_to_unitid(struct saa7164_i2c *bus, int addr) -{ - /* For a given bus and i2c device address, return the saa7164 unique - * unitid. < 0 on error */ - - struct saa7164_dev *dev = bus->dev; - struct saa7164_unit *unit; - int i; - - for (i = 0; i < SAA7164_MAX_UNITS; i++) { - unit = &saa7164_boards[dev->board].unit[i]; - - if (unit->type == SAA7164_UNIT_UNDEFINED) - continue; - if ((bus->nr == unit->i2c_bus_nr) && - (addr == unit->i2c_bus_addr)) - return unit->id; - } - - return -1; -} - -/* The 7164 API needs to know the i2c register length in advance. - * this is a helper function. Based on a specific chip addr and bus return the - * reg length. - */ -int saa7164_i2caddr_to_reglen(struct saa7164_i2c *bus, int addr) -{ - /* For a given bus and i2c device address, return the - * saa7164 registry address width. < 0 on error - */ - - struct saa7164_dev *dev = bus->dev; - struct saa7164_unit *unit; - int i; - - for (i = 0; i < SAA7164_MAX_UNITS; i++) { - unit = &saa7164_boards[dev->board].unit[i]; - - if (unit->type == SAA7164_UNIT_UNDEFINED) - continue; - - if ((bus->nr == unit->i2c_bus_nr) && - (addr == unit->i2c_bus_addr)) - return unit->i2c_reg_len; - } - - return -1; -} -/* TODO: implement a 'findeeprom' functio like the above and fix any other - * eeprom related todo's in -api.c. - */ - -/* Translate a unitid into a x readable device name, for display purposes. */ -char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid) -{ - char *undefed = "UNDEFINED"; - char *bridge = "BRIDGE"; - struct saa7164_unit *unit; - int i; - - if (unitid == 0) - return bridge; - - for (i = 0; i < SAA7164_MAX_UNITS; i++) { - unit = &saa7164_boards[dev->board].unit[i]; - - if (unit->type == SAA7164_UNIT_UNDEFINED) - continue; - - if (unitid == unit->id) - return unit->name; - } - - return undefed; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-cmd.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-cmd.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-cmd.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-cmd.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,589 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#include "saa7164.h" - -int saa7164_cmd_alloc_seqno(struct saa7164_dev *dev) -{ - int i, ret = -1; - - mutex_lock(&dev->lock); - for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { - if (dev->cmds[i].inuse == 0) { - dev->cmds[i].inuse = 1; - dev->cmds[i].signalled = 0; - dev->cmds[i].timeout = 0; - ret = dev->cmds[i].seqno; - break; - } - } - mutex_unlock(&dev->lock); - - return ret; -} - -void saa7164_cmd_free_seqno(struct saa7164_dev *dev, u8 seqno) -{ - mutex_lock(&dev->lock); - if ((dev->cmds[seqno].inuse == 1) && - (dev->cmds[seqno].seqno == seqno)) { - dev->cmds[seqno].inuse = 0; - dev->cmds[seqno].signalled = 0; - dev->cmds[seqno].timeout = 0; - } - mutex_unlock(&dev->lock); -} - -void saa7164_cmd_timeout_seqno(struct saa7164_dev *dev, u8 seqno) -{ - mutex_lock(&dev->lock); - if ((dev->cmds[seqno].inuse == 1) && - (dev->cmds[seqno].seqno == seqno)) { - dev->cmds[seqno].timeout = 1; - } - mutex_unlock(&dev->lock); -} - -u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno) -{ - int ret = 0; - - mutex_lock(&dev->lock); - if ((dev->cmds[seqno].inuse == 1) && - (dev->cmds[seqno].seqno == seqno)) { - ret = dev->cmds[seqno].timeout; - } - mutex_unlock(&dev->lock); - - return ret; -} - -/* Commands to the f/w get marshelled to/from this code then onto the PCI - * -bus/c running buffer. */ -int saa7164_irq_dequeue(struct saa7164_dev *dev) -{ - int ret = SAA_OK, i = 0; - u32 timeout; - wait_queue_head_t *q = NULL; - u8 tmp[512]; - dprintk(DBGLVL_CMD, "%s()\n", __func__); - - /* While any outstand message on the bus exists... */ - do { - - /* Peek the msg bus */ - struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 }; - ret = saa7164_bus_get(dev, &tRsp, NULL, 1); - if (ret != SAA_OK) - break; - - q = &dev->cmds[tRsp.seqno].wait; - timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno); - dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout); - if (!timeout) { - dprintk(DBGLVL_CMD, - "%s() signalled seqno(%d) (for dequeue)\n", - __func__, tRsp.seqno); - dev->cmds[tRsp.seqno].signalled = 1; - wake_up(q); - } else { - printk(KERN_ERR - "%s() found timed out command on the bus\n", - __func__); - - /* Clean the bus */ - ret = saa7164_bus_get(dev, &tRsp, &tmp, 0); - printk(KERN_ERR "%s() ret = %x\n", __func__, ret); - if (ret == SAA_ERR_EMPTY) - /* Someone else already fetched the response */ - return SAA_OK; - - if (ret != SAA_OK) - return ret; - } - - /* It's unlikely to have more than 4 or 5 pending messages, - * ensure we exit at some point regardless. - */ - } while (i++ < 32); - - return ret; -} - -/* Commands to the f/w get marshelled to/from this code then onto the PCI - * -bus/c running buffer. */ -int saa7164_cmd_dequeue(struct saa7164_dev *dev) -{ - int loop = 1; - int ret; - u32 timeout; - wait_queue_head_t *q = NULL; - u8 tmp[512]; - dprintk(DBGLVL_CMD, "%s()\n", __func__); - - while (loop) { - - struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 }; - ret = saa7164_bus_get(dev, &tRsp, NULL, 1); - if (ret == SAA_ERR_EMPTY) - return SAA_OK; - - if (ret != SAA_OK) - return ret; - - q = &dev->cmds[tRsp.seqno].wait; - timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno); - dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout); - if (timeout) { - printk(KERN_ERR "found timed out command on the bus\n"); - - /* Clean the bus */ - ret = saa7164_bus_get(dev, &tRsp, &tmp, 0); - printk(KERN_ERR "ret = %x\n", ret); - if (ret == SAA_ERR_EMPTY) - /* Someone else already fetched the response */ - return SAA_OK; - - if (ret != SAA_OK) - return ret; - - if (tRsp.flags & PVC_CMDFLAG_CONTINUE) - printk(KERN_ERR "split response\n"); - else - saa7164_cmd_free_seqno(dev, tRsp.seqno); - - printk(KERN_ERR " timeout continue\n"); - continue; - } - - dprintk(DBGLVL_CMD, "%s() signalled seqno(%d) (for dequeue)\n", - __func__, tRsp.seqno); - dev->cmds[tRsp.seqno].signalled = 1; - wake_up(q); - return SAA_OK; - } - - return SAA_OK; -} - -int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg, - void *buf) -{ - struct tmComResBusInfo *bus = &dev->bus; - u8 cmd_sent; - u16 size, idx; - u32 cmds; - void *tmp; - int ret = -1; - - if (!msg) { - printk(KERN_ERR "%s() !msg\n", __func__); - return SAA_ERR_BAD_PARAMETER; - } - - mutex_lock(&dev->cmds[msg->id].lock); - - size = msg->size; - idx = 0; - cmds = size / bus->m_wMaxReqSize; - if (size % bus->m_wMaxReqSize == 0) - cmds -= 1; - - cmd_sent = 0; - - /* Split the request into smaller chunks */ - for (idx = 0; idx < cmds; idx++) { - - msg->flags |= SAA_CMDFLAG_CONTINUE; - msg->size = bus->m_wMaxReqSize; - tmp = buf + idx * bus->m_wMaxReqSize; - - ret = saa7164_bus_set(dev, msg, tmp); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() set failed %d\n", __func__, ret); - - if (cmd_sent) { - ret = SAA_ERR_BUSY; - goto out; - } - ret = SAA_ERR_OVERFLOW; - goto out; - } - cmd_sent = 1; - } - - /* If not the last command... */ - if (idx != 0) - msg->flags &= ~SAA_CMDFLAG_CONTINUE; - - msg->size = size - idx * bus->m_wMaxReqSize; - - ret = saa7164_bus_set(dev, msg, buf + idx * bus->m_wMaxReqSize); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() set last failed %d\n", __func__, ret); - - if (cmd_sent) { - ret = SAA_ERR_BUSY; - goto out; - } - ret = SAA_ERR_OVERFLOW; - goto out; - } - ret = SAA_OK; - -out: - mutex_unlock(&dev->cmds[msg->id].lock); - return ret; -} - -/* Wait for a signal event, without holding a mutex. Either return TIMEOUT if - * the event never occured, or SAA_OK if it was signaled during the wait. - */ -int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno) -{ - wait_queue_head_t *q = NULL; - int ret = SAA_BUS_TIMEOUT; - unsigned long stamp; - int r; - - if (saa_debug >= 4) - saa7164_bus_dump(dev); - - dprintk(DBGLVL_CMD, "%s(seqno=%d)\n", __func__, seqno); - - mutex_lock(&dev->lock); - if ((dev->cmds[seqno].inuse == 1) && - (dev->cmds[seqno].seqno == seqno)) { - q = &dev->cmds[seqno].wait; - } - mutex_unlock(&dev->lock); - - if (q) { - /* If we haven't been signalled we need to wait */ - if (dev->cmds[seqno].signalled == 0) { - stamp = jiffies; - dprintk(DBGLVL_CMD, - "%s(seqno=%d) Waiting (signalled=%d)\n", - __func__, seqno, dev->cmds[seqno].signalled); - - /* Wait for signalled to be flagged or timeout */ - /* In a highly stressed system this can easily extend - * into multiple seconds before the deferred worker - * is scheduled, and we're woken up via signal. - * We typically are signalled in < 50ms but it can - * take MUCH longer. - */ - wait_event_timeout(*q, dev->cmds[seqno].signalled, - (HZ * waitsecs)); - r = time_before(jiffies, stamp + (HZ * waitsecs)); - if (r) - ret = SAA_OK; - else - saa7164_cmd_timeout_seqno(dev, seqno); - - dprintk(DBGLVL_CMD, "%s(seqno=%d) Waiting res = %d " - "(signalled=%d)\n", __func__, seqno, r, - dev->cmds[seqno].signalled); - } else - ret = SAA_OK; - } else - printk(KERN_ERR "%s(seqno=%d) seqno is invalid\n", - __func__, seqno); - - return ret; -} - -void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno) -{ - int i; - dprintk(DBGLVL_CMD, "%s()\n", __func__); - - mutex_lock(&dev->lock); - for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { - if (dev->cmds[i].inuse == 1) { - dprintk(DBGLVL_CMD, - "seqno %d inuse, sig = %d, t/out = %d\n", - dev->cmds[i].seqno, - dev->cmds[i].signalled, - dev->cmds[i].timeout); - } - } - - for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { - if ((dev->cmds[i].inuse == 1) && ((i == 0) || - (dev->cmds[i].signalled) || (dev->cmds[i].timeout))) { - dprintk(DBGLVL_CMD, "%s(seqno=%d) calling wake_up\n", - __func__, i); - dev->cmds[i].signalled = 1; - wake_up(&dev->cmds[i].wait); - } - } - mutex_unlock(&dev->lock); -} - -int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, - u16 controlselector, u16 size, void *buf) -{ - struct tmComResInfo command_t, *pcommand_t; - struct tmComResInfo response_t, *presponse_t; - u8 errdata[256]; - u16 resp_dsize; - u16 data_recd; - u32 loop; - int ret; - int safety = 0; - - dprintk(DBGLVL_CMD, "%s(unitid = %s (%d) , command = 0x%x, " - "sel = 0x%x)\n", __func__, saa7164_unitid_name(dev, id), id, - command, controlselector); - - if ((size == 0) || (buf == NULL)) { - printk(KERN_ERR "%s() Invalid param\n", __func__); - return SAA_ERR_BAD_PARAMETER; - } - - /* Prepare some basic command/response structures */ - memset(&command_t, 0, sizeof(command_t)); - memset(&response_t, 0, sizeof(response_t)); - pcommand_t = &command_t; - presponse_t = &response_t; - command_t.id = id; - command_t.command = command; - command_t.controlselector = controlselector; - command_t.size = size; - - /* Allocate a unique sequence number */ - ret = saa7164_cmd_alloc_seqno(dev); - if (ret < 0) { - printk(KERN_ERR "%s() No free sequences\n", __func__); - ret = SAA_ERR_NO_RESOURCES; - goto out; - } - - command_t.seqno = (u8)ret; - - /* Send Command */ - resp_dsize = size; - pcommand_t->size = size; - - dprintk(DBGLVL_CMD, "%s() pcommand_t.seqno = %d\n", - __func__, pcommand_t->seqno); - - dprintk(DBGLVL_CMD, "%s() pcommand_t.size = %d\n", - __func__, pcommand_t->size); - - ret = saa7164_cmd_set(dev, pcommand_t, buf); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() set command failed %d\n", __func__, ret); - - if (ret != SAA_ERR_BUSY) - saa7164_cmd_free_seqno(dev, pcommand_t->seqno); - else - /* Flag a timeout, because at least one - * command was sent */ - saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno); - - goto out; - } - - /* With split responses we have to collect the msgs piece by piece */ - data_recd = 0; - loop = 1; - while (loop) { - dprintk(DBGLVL_CMD, "%s() loop\n", __func__); - - ret = saa7164_cmd_wait(dev, pcommand_t->seqno); - dprintk(DBGLVL_CMD, "%s() loop ret = %d\n", __func__, ret); - - /* if power is down and this is not a power command ... */ - - if (ret == SAA_BUS_TIMEOUT) { - printk(KERN_ERR "Event timed out\n"); - saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno); - return ret; - } - - if (ret != SAA_OK) { - printk(KERN_ERR "spurious error\n"); - return ret; - } - - /* Peek response */ - ret = saa7164_bus_get(dev, presponse_t, NULL, 1); - if (ret == SAA_ERR_EMPTY) { - dprintk(4, "%s() SAA_ERR_EMPTY\n", __func__); - continue; - } - if (ret != SAA_OK) { - printk(KERN_ERR "peek failed\n"); - return ret; - } - - dprintk(DBGLVL_CMD, "%s() presponse_t->seqno = %d\n", - __func__, presponse_t->seqno); - - dprintk(DBGLVL_CMD, "%s() presponse_t->flags = 0x%x\n", - __func__, presponse_t->flags); - - dprintk(DBGLVL_CMD, "%s() presponse_t->size = %d\n", - __func__, presponse_t->size); - - /* Check if the response was for our command */ - if (presponse_t->seqno != pcommand_t->seqno) { - - dprintk(DBGLVL_CMD, - "wrong event: seqno = %d, " - "expected seqno = %d, " - "will dequeue regardless\n", - presponse_t->seqno, pcommand_t->seqno); - - ret = saa7164_cmd_dequeue(dev); - if (ret != SAA_OK) { - printk(KERN_ERR "dequeue failed, ret = %d\n", - ret); - if (safety++ > 16) { - printk(KERN_ERR - "dequeue exceeded, safety exit\n"); - return SAA_ERR_BUSY; - } - } - - continue; - } - - if ((presponse_t->flags & PVC_RESPONSEFLAG_ERROR) != 0) { - - memset(&errdata[0], 0, sizeof(errdata)); - - ret = saa7164_bus_get(dev, presponse_t, &errdata[0], 0); - if (ret != SAA_OK) { - printk(KERN_ERR "get error(2)\n"); - return ret; - } - - saa7164_cmd_free_seqno(dev, pcommand_t->seqno); - - dprintk(DBGLVL_CMD, "%s() errdata %02x%02x%02x%02x\n", - __func__, errdata[0], errdata[1], errdata[2], - errdata[3]); - - /* Map error codes */ - dprintk(DBGLVL_CMD, "%s() cmd, error code = 0x%x\n", - __func__, errdata[0]); - - switch (errdata[0]) { - case PVC_ERRORCODE_INVALID_COMMAND: - dprintk(DBGLVL_CMD, "%s() INVALID_COMMAND\n", - __func__); - ret = SAA_ERR_INVALID_COMMAND; - break; - case PVC_ERRORCODE_INVALID_DATA: - dprintk(DBGLVL_CMD, "%s() INVALID_DATA\n", - __func__); - ret = SAA_ERR_BAD_PARAMETER; - break; - case PVC_ERRORCODE_TIMEOUT: - dprintk(DBGLVL_CMD, "%s() TIMEOUT\n", __func__); - ret = SAA_ERR_TIMEOUT; - break; - case PVC_ERRORCODE_NAK: - dprintk(DBGLVL_CMD, "%s() NAK\n", __func__); - ret = SAA_ERR_NULL_PACKET; - break; - case PVC_ERRORCODE_UNKNOWN: - case PVC_ERRORCODE_INVALID_CONTROL: - dprintk(DBGLVL_CMD, - "%s() UNKNOWN OR INVALID CONTROL\n", - __func__); - default: - dprintk(DBGLVL_CMD, "%s() UNKNOWN\n", __func__); - ret = SAA_ERR_NOT_SUPPORTED; - } - - /* See of other commands are on the bus */ - if (saa7164_cmd_dequeue(dev) != SAA_OK) - printk(KERN_ERR "dequeue(2) failed\n"); - - return ret; - } - - /* If response is invalid */ - if ((presponse_t->id != pcommand_t->id) || - (presponse_t->command != pcommand_t->command) || - (presponse_t->controlselector != - pcommand_t->controlselector) || - (((resp_dsize - data_recd) != presponse_t->size) && - !(presponse_t->flags & PVC_CMDFLAG_CONTINUE)) || - ((resp_dsize - data_recd) < presponse_t->size)) { - - /* Invalid */ - dprintk(DBGLVL_CMD, "%s() Invalid\n", __func__); - ret = saa7164_bus_get(dev, presponse_t, NULL, 0); - if (ret != SAA_OK) { - printk(KERN_ERR "get failed\n"); - return ret; - } - - /* See of other commands are on the bus */ - if (saa7164_cmd_dequeue(dev) != SAA_OK) - printk(KERN_ERR "dequeue(3) failed\n"); - continue; - } - - /* OK, now we're actually getting out correct response */ - ret = saa7164_bus_get(dev, presponse_t, buf + data_recd, 0); - if (ret != SAA_OK) { - printk(KERN_ERR "get failed\n"); - return ret; - } - - data_recd = presponse_t->size + data_recd; - if (resp_dsize == data_recd) { - dprintk(DBGLVL_CMD, "%s() Resp recd\n", __func__); - break; - } - - /* See of other commands are on the bus */ - if (saa7164_cmd_dequeue(dev) != SAA_OK) - printk(KERN_ERR "dequeue(3) failed\n"); - - continue; - - } /* (loop) */ - - /* Release the sequence number allocation */ - saa7164_cmd_free_seqno(dev, pcommand_t->seqno); - - /* if powerdown signal all pending commands */ - - dprintk(DBGLVL_CMD, "%s() Calling dequeue then exit\n", __func__); - - /* See of other commands are on the bus */ - if (saa7164_cmd_dequeue(dev) != SAA_OK) - printk(KERN_ERR "dequeue(4) failed\n"); - - ret = SAA_OK; -out: - return ret; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1526 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_PROC_FS -#include -#endif -#include "saa7164.h" - -MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards"); -MODULE_AUTHOR("Steven Toth "); -MODULE_LICENSE("GPL"); - -/* - * 1 Basic - * 2 - * 4 i2c - * 8 api - * 16 cmd - * 32 bus - */ - -unsigned int saa_debug; -module_param_named(debug, saa_debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); - -unsigned int fw_debug; -module_param(fw_debug, int, 0644); -MODULE_PARM_DESC(fw_debug, "Firware debug level def:2"); - -unsigned int encoder_buffers = SAA7164_MAX_ENCODER_BUFFERS; -module_param(encoder_buffers, int, 0644); -MODULE_PARM_DESC(encoder_buffers, "Total buffers in read queue 16-512 def:64"); - -unsigned int vbi_buffers = SAA7164_MAX_VBI_BUFFERS; -module_param(vbi_buffers, int, 0644); -MODULE_PARM_DESC(vbi_buffers, "Total buffers in read queue 16-512 def:64"); - -unsigned int waitsecs = 10; -module_param(waitsecs, int, 0644); -MODULE_PARM_DESC(waitsecs, "timeout on firmware messages"); - -static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET }; -module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card, "card type"); - -unsigned int print_histogram = 64; -module_param(print_histogram, int, 0644); -MODULE_PARM_DESC(print_histogram, "print histogram values once"); - -unsigned int crc_checking = 1; -module_param(crc_checking, int, 0644); -MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers"); - -unsigned int guard_checking = 1; -module_param(guard_checking, int, 0644); -MODULE_PARM_DESC(guard_checking, - "enable dma sanity checking for buffer overruns"); - -static unsigned int saa7164_devcount; - -static DEFINE_MUTEX(devlist); -LIST_HEAD(saa7164_devlist); - -#define INT_SIZE 16 - -void saa7164_dumphex16FF(struct saa7164_dev *dev, u8 *buf, int len) -{ - int i; - u8 tmp[16]; - memset(&tmp[0], 0xff, sizeof(tmp)); - - printk(KERN_INFO "--------------------> " - "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); - - for (i = 0; i < len; i += 16) { - if (memcmp(&tmp, buf + i, sizeof(tmp)) != 0) { - printk(KERN_INFO " [0x%08x] " - "%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, - *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3), - *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7), - *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11), - *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15)); - } - } -} - -static void saa7164_pack_verifier(struct saa7164_buffer *buf) -{ - u8 *p = (u8 *)buf->cpu; - int i; - - for (i = 0; i < buf->actual_size; i += 2048) { - - if ((*(p + i + 0) != 0x00) || (*(p + i + 1) != 0x00) || - (*(p + i + 2) != 0x01) || (*(p + i + 3) != 0xBA)) { - printk(KERN_ERR "No pack at 0x%x\n", i); -#if 0 - saa7164_dumphex16FF(buf->port->dev, (p + i), 32); -#endif - } - } -} - -#define FIXED_VIDEO_PID 0xf1 -#define FIXED_AUDIO_PID 0xf2 - -static void saa7164_ts_verifier(struct saa7164_buffer *buf) -{ - struct saa7164_port *port = buf->port; - u32 i; - u8 cc, a; - u16 pid; - u8 __iomem *bufcpu = (u8 *)buf->cpu; - - port->sync_errors = 0; - port->v_cc_errors = 0; - port->a_cc_errors = 0; - - for (i = 0; i < buf->actual_size; i += 188) { - if (*(bufcpu + i) != 0x47) - port->sync_errors++; - - /* TODO: Query pid lower 8 bits, ignoring upper bits intensionally */ - pid = ((*(bufcpu + i + 1) & 0x1f) << 8) | *(bufcpu + i + 2); - cc = *(bufcpu + i + 3) & 0x0f; - - if (pid == FIXED_VIDEO_PID) { - a = ((port->last_v_cc + 1) & 0x0f); - if (a != cc) { - printk(KERN_ERR "video cc last = %x current = %x i = %d\n", - port->last_v_cc, cc, i); - port->v_cc_errors++; - } - - port->last_v_cc = cc; - } else - if (pid == FIXED_AUDIO_PID) { - a = ((port->last_a_cc + 1) & 0x0f); - if (a != cc) { - printk(KERN_ERR "audio cc last = %x current = %x i = %d\n", - port->last_a_cc, cc, i); - port->a_cc_errors++; - } - - port->last_a_cc = cc; - } - - } - - /* Only report errors if we've been through this function atleast - * once already and the cached cc values are primed. First time through - * always generates errors. - */ - if (port->v_cc_errors && (port->done_first_interrupt > 1)) - printk(KERN_ERR "video pid cc, %d errors\n", port->v_cc_errors); - - if (port->a_cc_errors && (port->done_first_interrupt > 1)) - printk(KERN_ERR "audio pid cc, %d errors\n", port->a_cc_errors); - - if (port->sync_errors && (port->done_first_interrupt > 1)) - printk(KERN_ERR "sync_errors = %d\n", port->sync_errors); - - if (port->done_first_interrupt == 1) - port->done_first_interrupt++; -} - -static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name) -{ - int i; - - memset(hg, 0, sizeof(struct saa7164_histogram)); - strcpy(hg->name, name); - - /* First 30ms x 1ms */ - for (i = 0; i < 30; i++) - hg->counter1[0 + i].val = i; - - /* 30 - 200ms x 10ms */ - for (i = 0; i < 18; i++) - hg->counter1[30 + i].val = 30 + (i * 10); - - /* 200 - 2000ms x 100ms */ - for (i = 0; i < 15; i++) - hg->counter1[48 + i].val = 200 + (i * 200); - - /* Catch all massive value (2secs) */ - hg->counter1[55].val = 2000; - - /* Catch all massive value (4secs) */ - hg->counter1[56].val = 4000; - - /* Catch all massive value (8secs) */ - hg->counter1[57].val = 8000; - - /* Catch all massive value (15secs) */ - hg->counter1[58].val = 15000; - - /* Catch all massive value (30secs) */ - hg->counter1[59].val = 30000; - - /* Catch all massive value (60secs) */ - hg->counter1[60].val = 60000; - - /* Catch all massive value (5mins) */ - hg->counter1[61].val = 300000; - - /* Catch all massive value (15mins) */ - hg->counter1[62].val = 900000; - - /* Catch all massive values (1hr) */ - hg->counter1[63].val = 3600000; -} - -void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val) -{ - int i; - for (i = 0; i < 64; i++) { - if (val <= hg->counter1[i].val) { - hg->counter1[i].count++; - hg->counter1[i].update_time = jiffies; - break; - } - } -} - -static void saa7164_histogram_print(struct saa7164_port *port, - struct saa7164_histogram *hg) -{ - u32 entries = 0; - int i; - - printk(KERN_ERR "Histogram named %s (ms, count, last_update_jiffy)\n", hg->name); - for (i = 0; i < 64; i++) { - if (hg->counter1[i].count == 0) - continue; - - printk(KERN_ERR " %4d %12d %Ld\n", - hg->counter1[i].val, - hg->counter1[i].count, - hg->counter1[i].update_time); - - entries++; - } - printk(KERN_ERR "Total: %d\n", entries); -} - -static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr) -{ - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf = NULL; - struct saa7164_user_buffer *ubuf = NULL; - struct list_head *c, *n; - int i = 0; - u8 __iomem *p; - - mutex_lock(&port->dmaqueue_lock); - list_for_each_safe(c, n, &port->dmaqueue.list) { - - buf = list_entry(c, struct saa7164_buffer, list); - if (i++ > port->hwcfg.buffercount) { - printk(KERN_ERR "%s() illegal i count %d\n", - __func__, i); - break; - } - - if (buf->idx == bufnr) { - - /* Found the buffer, deal with it */ - dprintk(DBGLVL_IRQ, "%s() bufnr: %d\n", __func__, bufnr); - - if (crc_checking) { - /* Throw a new checksum on the dma buffer */ - buf->crc = crc32(0, buf->cpu, buf->actual_size); - } - - if (guard_checking) { - p = (u8 *)buf->cpu; - if ((*(p + buf->actual_size + 0) != 0xff) || - (*(p + buf->actual_size + 1) != 0xff) || - (*(p + buf->actual_size + 2) != 0xff) || - (*(p + buf->actual_size + 3) != 0xff) || - (*(p + buf->actual_size + 0x10) != 0xff) || - (*(p + buf->actual_size + 0x11) != 0xff) || - (*(p + buf->actual_size + 0x12) != 0xff) || - (*(p + buf->actual_size + 0x13) != 0xff)) { - printk(KERN_ERR "%s() buf %p guard buffer breach\n", - __func__, buf); -#if 0 - saa7164_dumphex16FF(dev, (p + buf->actual_size) - 32 , 64); -#endif - } - } - - if ((port->nr != SAA7164_PORT_VBI1) && (port->nr != SAA7164_PORT_VBI2)) { - /* Validate the incoming buffer content */ - if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) - saa7164_ts_verifier(buf); - else if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) - saa7164_pack_verifier(buf); - } - - /* find a free user buffer and clone to it */ - if (!list_empty(&port->list_buf_free.list)) { - - /* Pull the first buffer from the used list */ - ubuf = list_first_entry(&port->list_buf_free.list, - struct saa7164_user_buffer, list); - - if (buf->actual_size <= ubuf->actual_size) { - - memcpy_fromio(ubuf->data, buf->cpu, - ubuf->actual_size); - - if (crc_checking) { - /* Throw a new checksum on the read buffer */ - ubuf->crc = crc32(0, ubuf->data, ubuf->actual_size); - } - - /* Requeue the buffer on the free list */ - ubuf->pos = 0; - - list_move_tail(&ubuf->list, - &port->list_buf_used.list); - - /* Flag any userland waiters */ - wake_up_interruptible(&port->wait_read); - - } else { - printk(KERN_ERR "buf %p bufsize fails match\n", buf); - } - - } else - printk(KERN_ERR "encirq no free buffers, increase param encoder_buffers\n"); - - /* Ensure offset into buffer remains 0, fill buffer - * with known bad data. We check for this data at a later point - * in time. */ - saa7164_buffer_zero_offsets(port, bufnr); - memset_io(buf->cpu, 0xff, buf->pci_size); - if (crc_checking) { - /* Throw yet aanother new checksum on the dma buffer */ - buf->crc = crc32(0, buf->cpu, buf->actual_size); - } - - break; - } - } - mutex_unlock(&port->dmaqueue_lock); -} - -static void saa7164_work_enchandler(struct work_struct *w) -{ - struct saa7164_port *port = - container_of(w, struct saa7164_port, workenc); - struct saa7164_dev *dev = port->dev; - - u32 wp, mcb, rp, cnt = 0; - - port->last_svc_msecs_diff = port->last_svc_msecs; - port->last_svc_msecs = jiffies_to_msecs(jiffies); - - port->last_svc_msecs_diff = port->last_svc_msecs - - port->last_svc_msecs_diff; - - saa7164_histogram_update(&port->svc_interval, - port->last_svc_msecs_diff); - - port->last_irq_svc_msecs_diff = port->last_svc_msecs - - port->last_irq_msecs; - - saa7164_histogram_update(&port->irq_svc_interval, - port->last_irq_svc_msecs_diff); - - dprintk(DBGLVL_IRQ, - "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n", - __func__, - port->last_svc_msecs_diff, - port->last_irq_svc_msecs_diff, - port->last_svc_wp, - port->last_svc_rp - ); - - /* Current write position */ - wp = saa7164_readl(port->bufcounter); - if (wp > (port->hwcfg.buffercount - 1)) { - printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp); - return; - } - - /* Most current complete buffer */ - if (wp == 0) - mcb = (port->hwcfg.buffercount - 1); - else - mcb = wp - 1; - - while (1) { - if (port->done_first_interrupt == 0) { - port->done_first_interrupt++; - rp = mcb; - } else - rp = (port->last_svc_rp + 1) % 8; - - if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) { - printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp); - break; - } - - saa7164_work_enchandler_helper(port, rp); - port->last_svc_rp = rp; - cnt++; - - if (rp == mcb) - break; - } - - /* TODO: Convert this into a /proc/saa7164 style readable file */ - if (print_histogram == port->nr) { - saa7164_histogram_print(port, &port->irq_interval); - saa7164_histogram_print(port, &port->svc_interval); - saa7164_histogram_print(port, &port->irq_svc_interval); - saa7164_histogram_print(port, &port->read_interval); - saa7164_histogram_print(port, &port->poll_interval); - /* TODO: fix this to preserve any previous state */ - print_histogram = 64 + port->nr; - } -} - -static void saa7164_work_vbihandler(struct work_struct *w) -{ - struct saa7164_port *port = - container_of(w, struct saa7164_port, workenc); - struct saa7164_dev *dev = port->dev; - - u32 wp, mcb, rp, cnt = 0; - - port->last_svc_msecs_diff = port->last_svc_msecs; - port->last_svc_msecs = jiffies_to_msecs(jiffies); - port->last_svc_msecs_diff = port->last_svc_msecs - - port->last_svc_msecs_diff; - - saa7164_histogram_update(&port->svc_interval, - port->last_svc_msecs_diff); - - port->last_irq_svc_msecs_diff = port->last_svc_msecs - - port->last_irq_msecs; - - saa7164_histogram_update(&port->irq_svc_interval, - port->last_irq_svc_msecs_diff); - - dprintk(DBGLVL_IRQ, - "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n", - __func__, - port->last_svc_msecs_diff, - port->last_irq_svc_msecs_diff, - port->last_svc_wp, - port->last_svc_rp - ); - - /* Current write position */ - wp = saa7164_readl(port->bufcounter); - if (wp > (port->hwcfg.buffercount - 1)) { - printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp); - return; - } - - /* Most current complete buffer */ - if (wp == 0) - mcb = (port->hwcfg.buffercount - 1); - else - mcb = wp - 1; - - while (1) { - if (port->done_first_interrupt == 0) { - port->done_first_interrupt++; - rp = mcb; - } else - rp = (port->last_svc_rp + 1) % 8; - - if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) { - printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp); - break; - } - - saa7164_work_enchandler_helper(port, rp); - port->last_svc_rp = rp; - cnt++; - - if (rp == mcb) - break; - } - - /* TODO: Convert this into a /proc/saa7164 style readable file */ - if (print_histogram == port->nr) { - saa7164_histogram_print(port, &port->irq_interval); - saa7164_histogram_print(port, &port->svc_interval); - saa7164_histogram_print(port, &port->irq_svc_interval); - saa7164_histogram_print(port, &port->read_interval); - saa7164_histogram_print(port, &port->poll_interval); - /* TODO: fix this to preserve any previous state */ - print_histogram = 64 + port->nr; - } -} - -static void saa7164_work_cmdhandler(struct work_struct *w) -{ - struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd); - - /* Wake up any complete commands */ - saa7164_irq_dequeue(dev); -} - -static void saa7164_buffer_deliver(struct saa7164_buffer *buf) -{ - struct saa7164_port *port = buf->port; - - /* Feed the transport payload into the kernel demux */ - dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu, - SAA7164_TS_NUMBER_OF_LINES); - -} - -static irqreturn_t saa7164_irq_vbi(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - - /* Store old time */ - port->last_irq_msecs_diff = port->last_irq_msecs; - - /* Collect new stats */ - port->last_irq_msecs = jiffies_to_msecs(jiffies); - - /* Calculate stats */ - port->last_irq_msecs_diff = port->last_irq_msecs - - port->last_irq_msecs_diff; - - saa7164_histogram_update(&port->irq_interval, - port->last_irq_msecs_diff); - - dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__, - port->last_irq_msecs_diff); - - /* Tis calls the vbi irq handler */ - schedule_work(&port->workenc); - return 0; -} - -static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - - /* Store old time */ - port->last_irq_msecs_diff = port->last_irq_msecs; - - /* Collect new stats */ - port->last_irq_msecs = jiffies_to_msecs(jiffies); - - /* Calculate stats */ - port->last_irq_msecs_diff = port->last_irq_msecs - - port->last_irq_msecs_diff; - - saa7164_histogram_update(&port->irq_interval, - port->last_irq_msecs_diff); - - dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__, - port->last_irq_msecs_diff); - - schedule_work(&port->workenc); - return 0; -} - -static irqreturn_t saa7164_irq_ts(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - struct list_head *c, *n; - int wp, i = 0, rp; - - /* Find the current write point from the hardware */ - wp = saa7164_readl(port->bufcounter); - if (wp > (port->hwcfg.buffercount - 1)) - BUG(); - - /* Find the previous buffer to the current write point */ - if (wp == 0) - rp = (port->hwcfg.buffercount - 1); - else - rp = wp - 1; - - /* Lookup the WP in the buffer list */ - /* TODO: turn this into a worker thread */ - list_for_each_safe(c, n, &port->dmaqueue.list) { - buf = list_entry(c, struct saa7164_buffer, list); - if (i++ > port->hwcfg.buffercount) - BUG(); - - if (buf->idx == rp) { - /* Found the buffer, deal with it */ - dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n", - __func__, wp, rp); - saa7164_buffer_deliver(buf); - break; - } - - } - return 0; -} - -/* Primary IRQ handler and dispatch mechanism */ -static irqreturn_t saa7164_irq(int irq, void *dev_id) -{ - struct saa7164_dev *dev = dev_id; - struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1]; - struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2]; - struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1]; - struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2]; - struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1]; - struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2]; - - u32 intid, intstat[INT_SIZE/4]; - int i, handled = 0, bit; - - if (dev == NULL) { - printk(KERN_ERR "%s() No device specified\n", __func__); - handled = 0; - goto out; - } - - /* Check that the hardware is accessible. If the status bytes are - * 0xFF then the device is not accessible, the the IRQ belongs - * to another driver. - * 4 x u32 interrupt registers. - */ - for (i = 0; i < INT_SIZE/4; i++) { - - /* TODO: Convert into saa7164_readl() */ - /* Read the 4 hardware interrupt registers */ - intstat[i] = saa7164_readl(dev->int_status + (i * 4)); - - if (intstat[i]) - handled = 1; - } - if (handled == 0) - goto out; - - /* For each of the HW interrupt registers */ - for (i = 0; i < INT_SIZE/4; i++) { - - if (intstat[i]) { - /* Each function of the board has it's own interruptid. - * Find the function that triggered then call - * it's handler. - */ - for (bit = 0; bit < 32; bit++) { - - if (((intstat[i] >> bit) & 0x00000001) == 0) - continue; - - /* Calculate the interrupt id (0x00 to 0x7f) */ - - intid = (i * 32) + bit; - if (intid == dev->intfdesc.bInterruptId) { - /* A response to an cmd/api call */ - schedule_work(&dev->workcmd); - } else if (intid == porta->hwcfg.interruptid) { - - /* Transport path 1 */ - saa7164_irq_ts(porta); - - } else if (intid == portb->hwcfg.interruptid) { - - /* Transport path 2 */ - saa7164_irq_ts(portb); - - } else if (intid == portc->hwcfg.interruptid) { - - /* Encoder path 1 */ - saa7164_irq_encoder(portc); - - } else if (intid == portd->hwcfg.interruptid) { - - /* Encoder path 2 */ - saa7164_irq_encoder(portd); - - } else if (intid == porte->hwcfg.interruptid) { - - /* VBI path 1 */ - saa7164_irq_vbi(porte); - - } else if (intid == portf->hwcfg.interruptid) { - - /* VBI path 2 */ - saa7164_irq_vbi(portf); - - } else { - /* Find the function */ - dprintk(DBGLVL_IRQ, - "%s() unhandled interrupt " - "reg 0x%x bit 0x%x " - "intid = 0x%x\n", - __func__, i, bit, intid); - } - } - - /* Ack it */ - saa7164_writel(dev->int_ack + (i * 4), intstat[i]); - - } - } -out: - return IRQ_RETVAL(handled); -} - -void saa7164_getfirmwarestatus(struct saa7164_dev *dev) -{ - struct saa7164_fw_status *s = &dev->fw_status; - - dev->fw_status.status = saa7164_readl(SAA_DEVICE_SYSINIT_STATUS); - dev->fw_status.mode = saa7164_readl(SAA_DEVICE_SYSINIT_MODE); - dev->fw_status.spec = saa7164_readl(SAA_DEVICE_SYSINIT_SPEC); - dev->fw_status.inst = saa7164_readl(SAA_DEVICE_SYSINIT_INST); - dev->fw_status.cpuload = saa7164_readl(SAA_DEVICE_SYSINIT_CPULOAD); - dev->fw_status.remainheap = - saa7164_readl(SAA_DEVICE_SYSINIT_REMAINHEAP); - - dprintk(1, "Firmware status:\n"); - dprintk(1, " .status = 0x%08x\n", s->status); - dprintk(1, " .mode = 0x%08x\n", s->mode); - dprintk(1, " .spec = 0x%08x\n", s->spec); - dprintk(1, " .inst = 0x%08x\n", s->inst); - dprintk(1, " .cpuload = 0x%08x\n", s->cpuload); - dprintk(1, " .remainheap = 0x%08x\n", s->remainheap); -} - -u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev) -{ - u32 reg; - - reg = saa7164_readl(SAA_DEVICE_VERSION); - dprintk(1, "Device running firmware version %d.%d.%d.%d (0x%x)\n", - (reg & 0x0000fc00) >> 10, - (reg & 0x000003e0) >> 5, - (reg & 0x0000001f), - (reg & 0xffff0000) >> 16, - reg); - - return reg; -} - -/* TODO: Debugging func, remove */ -void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len) -{ - int i; - - printk(KERN_INFO "--------------------> " - "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); - - for (i = 0; i < len; i += 16) - printk(KERN_INFO " [0x%08x] " - "%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, - *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3), - *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7), - *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11), - *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15)); -} - -/* TODO: Debugging func, remove */ -void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr) -{ - int i; - - dprintk(1, "--------------------> " - "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); - - for (i = 0; i < 0x100; i += 16) - dprintk(1, "region0[0x%08x] = " - "%02x %02x %02x %02x %02x %02x %02x %02x" - " %02x %02x %02x %02x %02x %02x %02x %02x\n", i, - (u8)saa7164_readb(addr + i + 0), - (u8)saa7164_readb(addr + i + 1), - (u8)saa7164_readb(addr + i + 2), - (u8)saa7164_readb(addr + i + 3), - (u8)saa7164_readb(addr + i + 4), - (u8)saa7164_readb(addr + i + 5), - (u8)saa7164_readb(addr + i + 6), - (u8)saa7164_readb(addr + i + 7), - (u8)saa7164_readb(addr + i + 8), - (u8)saa7164_readb(addr + i + 9), - (u8)saa7164_readb(addr + i + 10), - (u8)saa7164_readb(addr + i + 11), - (u8)saa7164_readb(addr + i + 12), - (u8)saa7164_readb(addr + i + 13), - (u8)saa7164_readb(addr + i + 14), - (u8)saa7164_readb(addr + i + 15) - ); -} - -static void saa7164_dump_hwdesc(struct saa7164_dev *dev) -{ - dprintk(1, "@0x%p hwdesc sizeof(struct tmComResHWDescr) = %d bytes\n", - &dev->hwdesc, (u32)sizeof(struct tmComResHWDescr)); - - dprintk(1, " .bLength = 0x%x\n", dev->hwdesc.bLength); - dprintk(1, " .bDescriptorType = 0x%x\n", dev->hwdesc.bDescriptorType); - dprintk(1, " .bDescriptorSubtype = 0x%x\n", - dev->hwdesc.bDescriptorSubtype); - - dprintk(1, " .bcdSpecVersion = 0x%x\n", dev->hwdesc.bcdSpecVersion); - dprintk(1, " .dwClockFrequency = 0x%x\n", dev->hwdesc.dwClockFrequency); - dprintk(1, " .dwClockUpdateRes = 0x%x\n", dev->hwdesc.dwClockUpdateRes); - dprintk(1, " .bCapabilities = 0x%x\n", dev->hwdesc.bCapabilities); - dprintk(1, " .dwDeviceRegistersLocation = 0x%x\n", - dev->hwdesc.dwDeviceRegistersLocation); - - dprintk(1, " .dwHostMemoryRegion = 0x%x\n", - dev->hwdesc.dwHostMemoryRegion); - - dprintk(1, " .dwHostMemoryRegionSize = 0x%x\n", - dev->hwdesc.dwHostMemoryRegionSize); - - dprintk(1, " .dwHostHibernatMemRegion = 0x%x\n", - dev->hwdesc.dwHostHibernatMemRegion); - - dprintk(1, " .dwHostHibernatMemRegionSize = 0x%x\n", - dev->hwdesc.dwHostHibernatMemRegionSize); -} - -static void saa7164_dump_intfdesc(struct saa7164_dev *dev) -{ - dprintk(1, "@0x%p intfdesc " - "sizeof(struct tmComResInterfaceDescr) = %d bytes\n", - &dev->intfdesc, (u32)sizeof(struct tmComResInterfaceDescr)); - - dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength); - dprintk(1, " .bDescriptorType = 0x%x\n", dev->intfdesc.bDescriptorType); - dprintk(1, " .bDescriptorSubtype = 0x%x\n", - dev->intfdesc.bDescriptorSubtype); - - dprintk(1, " .bFlags = 0x%x\n", dev->intfdesc.bFlags); - dprintk(1, " .bInterfaceType = 0x%x\n", dev->intfdesc.bInterfaceType); - dprintk(1, " .bInterfaceId = 0x%x\n", dev->intfdesc.bInterfaceId); - dprintk(1, " .bBaseInterface = 0x%x\n", dev->intfdesc.bBaseInterface); - dprintk(1, " .bInterruptId = 0x%x\n", dev->intfdesc.bInterruptId); - dprintk(1, " .bDebugInterruptId = 0x%x\n", - dev->intfdesc.bDebugInterruptId); - - dprintk(1, " .BARLocation = 0x%x\n", dev->intfdesc.BARLocation); -} - -static void saa7164_dump_busdesc(struct saa7164_dev *dev) -{ - dprintk(1, "@0x%p busdesc sizeof(struct tmComResBusDescr) = %d bytes\n", - &dev->busdesc, (u32)sizeof(struct tmComResBusDescr)); - - dprintk(1, " .CommandRing = 0x%016Lx\n", dev->busdesc.CommandRing); - dprintk(1, " .ResponseRing = 0x%016Lx\n", dev->busdesc.ResponseRing); - dprintk(1, " .CommandWrite = 0x%x\n", dev->busdesc.CommandWrite); - dprintk(1, " .CommandRead = 0x%x\n", dev->busdesc.CommandRead); - dprintk(1, " .ResponseWrite = 0x%x\n", dev->busdesc.ResponseWrite); - dprintk(1, " .ResponseRead = 0x%x\n", dev->busdesc.ResponseRead); -} - -/* Much of the hardware configuration and PCI registers are configured - * dynamically depending on firmware. We have to cache some initial - * structures then use these to locate other important structures - * from PCI space. - */ -static void saa7164_get_descriptors(struct saa7164_dev *dev) -{ - memcpy_fromio(&dev->hwdesc, dev->bmmio, sizeof(struct tmComResHWDescr)); - memcpy_fromio(&dev->intfdesc, dev->bmmio + sizeof(struct tmComResHWDescr), - sizeof(struct tmComResInterfaceDescr)); - memcpy_fromio(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation, - sizeof(struct tmComResBusDescr)); - - if (dev->hwdesc.bLength != sizeof(struct tmComResHWDescr)) { - printk(KERN_ERR "Structure struct tmComResHWDescr is mangled\n"); - printk(KERN_ERR "Need %x got %d\n", dev->hwdesc.bLength, - (u32)sizeof(struct tmComResHWDescr)); - } else - saa7164_dump_hwdesc(dev); - - if (dev->intfdesc.bLength != sizeof(struct tmComResInterfaceDescr)) { - printk(KERN_ERR "struct struct tmComResInterfaceDescr is mangled\n"); - printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength, - (u32)sizeof(struct tmComResInterfaceDescr)); - } else - saa7164_dump_intfdesc(dev); - - saa7164_dump_busdesc(dev); -} - -static int saa7164_pci_quirks(struct saa7164_dev *dev) -{ - return 0; -} - -static int get_resources(struct saa7164_dev *dev) -{ - if (request_mem_region(pci_resource_start(dev->pci, 0), - pci_resource_len(dev->pci, 0), dev->name)) { - - if (request_mem_region(pci_resource_start(dev->pci, 2), - pci_resource_len(dev->pci, 2), dev->name)) - return 0; - } - - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx or 0x%llx\n", - dev->name, - (u64)pci_resource_start(dev->pci, 0), - (u64)pci_resource_start(dev->pci, 2)); - - return -EBUSY; -} - -static int saa7164_port_init(struct saa7164_dev *dev, int portnr) -{ - struct saa7164_port *port = NULL; - - if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS)) - BUG(); - - port = &dev->ports[portnr]; - - port->dev = dev; - port->nr = portnr; - - if ((portnr == SAA7164_PORT_TS1) || (portnr == SAA7164_PORT_TS2)) - port->type = SAA7164_MPEG_DVB; - else - if ((portnr == SAA7164_PORT_ENC1) || (portnr == SAA7164_PORT_ENC2)) { - port->type = SAA7164_MPEG_ENCODER; - - /* We need a deferred interrupt handler for cmd handling */ - INIT_WORK(&port->workenc, saa7164_work_enchandler); - } else if ((portnr == SAA7164_PORT_VBI1) || (portnr == SAA7164_PORT_VBI2)) { - port->type = SAA7164_MPEG_VBI; - - /* We need a deferred interrupt handler for cmd handling */ - INIT_WORK(&port->workenc, saa7164_work_vbihandler); - } else - BUG(); - - /* Init all the critical resources */ - mutex_init(&port->dvb.lock); - INIT_LIST_HEAD(&port->dmaqueue.list); - mutex_init(&port->dmaqueue_lock); - - INIT_LIST_HEAD(&port->list_buf_used.list); - INIT_LIST_HEAD(&port->list_buf_free.list); - init_waitqueue_head(&port->wait_read); - - - saa7164_histogram_reset(&port->irq_interval, "irq intervals"); - saa7164_histogram_reset(&port->svc_interval, "deferred intervals"); - saa7164_histogram_reset(&port->irq_svc_interval, - "irq to deferred intervals"); - saa7164_histogram_reset(&port->read_interval, - "encoder/vbi read() intervals"); - saa7164_histogram_reset(&port->poll_interval, - "encoder/vbi poll() intervals"); - - return 0; -} - -static int saa7164_dev_setup(struct saa7164_dev *dev) -{ - int i; - - mutex_init(&dev->lock); - atomic_inc(&dev->refcount); - dev->nr = saa7164_devcount++; - - snprintf(dev->name, sizeof(dev->name), "saa7164[%d]", dev->nr); - - mutex_lock(&devlist); - list_add_tail(&dev->devlist, &saa7164_devlist); - mutex_unlock(&devlist); - - /* board config */ - dev->board = UNSET; - if (card[dev->nr] < saa7164_bcount) - dev->board = card[dev->nr]; - - for (i = 0; UNSET == dev->board && i < saa7164_idcount; i++) - if (dev->pci->subsystem_vendor == saa7164_subids[i].subvendor && - dev->pci->subsystem_device == - saa7164_subids[i].subdevice) - dev->board = saa7164_subids[i].card; - - if (UNSET == dev->board) { - dev->board = SAA7164_BOARD_UNKNOWN; - saa7164_card_list(dev); - } - - dev->pci_bus = dev->pci->bus->number; - dev->pci_slot = PCI_SLOT(dev->pci->devfn); - - /* I2C Defaults / setup */ - dev->i2c_bus[0].dev = dev; - dev->i2c_bus[0].nr = 0; - dev->i2c_bus[1].dev = dev; - dev->i2c_bus[1].nr = 1; - dev->i2c_bus[2].dev = dev; - dev->i2c_bus[2].nr = 2; - - /* Transport + Encoder ports 1, 2, 3, 4 - Defaults / setup */ - saa7164_port_init(dev, SAA7164_PORT_TS1); - saa7164_port_init(dev, SAA7164_PORT_TS2); - saa7164_port_init(dev, SAA7164_PORT_ENC1); - saa7164_port_init(dev, SAA7164_PORT_ENC2); - saa7164_port_init(dev, SAA7164_PORT_VBI1); - saa7164_port_init(dev, SAA7164_PORT_VBI2); - - if (get_resources(dev) < 0) { - printk(KERN_ERR "CORE %s No more PCIe resources for " - "subsystem: %04x:%04x\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device); - - saa7164_devcount--; - return -ENODEV; - } - - /* PCI/e allocations */ - dev->lmmio = ioremap(pci_resource_start(dev->pci, 0), - pci_resource_len(dev->pci, 0)); - - dev->lmmio2 = ioremap(pci_resource_start(dev->pci, 2), - pci_resource_len(dev->pci, 2)); - - dev->bmmio = (u8 __iomem *)dev->lmmio; - dev->bmmio2 = (u8 __iomem *)dev->lmmio2; - - /* Inerrupt and ack register locations offset of bmmio */ - dev->int_status = 0x183000 + 0xf80; - dev->int_ack = 0x183000 + 0xf90; - - printk(KERN_INFO - "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, saa7164_boards[dev->board].name, - dev->board, card[dev->nr] == dev->board ? - "insmod option" : "autodetected"); - - saa7164_pci_quirks(dev); - - return 0; -} - -static void saa7164_dev_unregister(struct saa7164_dev *dev) -{ - dprintk(1, "%s()\n", __func__); - - release_mem_region(pci_resource_start(dev->pci, 0), - pci_resource_len(dev->pci, 0)); - - release_mem_region(pci_resource_start(dev->pci, 2), - pci_resource_len(dev->pci, 2)); - - if (!atomic_dec_and_test(&dev->refcount)) - return; - - iounmap(dev->lmmio); - iounmap(dev->lmmio2); - - return; -} - -#ifdef CONFIG_PROC_FS -static int saa7164_proc_show(struct seq_file *m, void *v) -{ - struct saa7164_dev *dev; - struct tmComResBusInfo *b; - struct list_head *list; - int i, c; - - if (saa7164_devcount == 0) - return 0; - - list_for_each(list, &saa7164_devlist) { - dev = list_entry(list, struct saa7164_dev, devlist); - seq_printf(m, "%s = %p\n", dev->name, dev); - - /* Lock the bus from any other access */ - b = &dev->bus; - mutex_lock(&b->lock); - - seq_printf(m, " .m_pdwSetWritePos = 0x%x (0x%08x)\n", - b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos)); - - seq_printf(m, " .m_pdwSetReadPos = 0x%x (0x%08x)\n", - b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos)); - - seq_printf(m, " .m_pdwGetWritePos = 0x%x (0x%08x)\n", - b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos)); - - seq_printf(m, " .m_pdwGetReadPos = 0x%x (0x%08x)\n", - b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos)); - c = 0; - seq_printf(m, "\n Set Ring:\n"); - seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); - for (i = 0; i < b->m_dwSizeSetRing; i++) { - if (c == 0) - seq_printf(m, " %04x:", i); - - seq_printf(m, " %02x", *(b->m_pdwSetRing + i)); - - if (++c == 16) { - seq_printf(m, "\n"); - c = 0; - } - } - - c = 0; - seq_printf(m, "\n Get Ring:\n"); - seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); - for (i = 0; i < b->m_dwSizeGetRing; i++) { - if (c == 0) - seq_printf(m, " %04x:", i); - - seq_printf(m, " %02x", *(b->m_pdwGetRing + i)); - - if (++c == 16) { - seq_printf(m, "\n"); - c = 0; - } - } - - mutex_unlock(&b->lock); - - } - - return 0; -} - -static int saa7164_proc_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, saa7164_proc_show, NULL); -} - -static const struct file_operations saa7164_proc_fops = { - .open = saa7164_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int saa7164_proc_create(void) -{ - struct proc_dir_entry *pe; - - pe = proc_create("saa7164", S_IRUGO, NULL, &saa7164_proc_fops); - if (!pe) - return -ENOMEM; - - return 0; -} -#endif - -static int saa7164_thread_function(void *data) -{ - struct saa7164_dev *dev = data; - struct tmFwInfoStruct fwinfo; - u64 last_poll_time = 0; - - dprintk(DBGLVL_THR, "thread started\n"); - - set_freezable(); - - while (1) { - msleep_interruptible(100); - if (kthread_should_stop()) - break; - try_to_freeze(); - - dprintk(DBGLVL_THR, "thread running\n"); - - /* Dump the firmware debug message to console */ - /* Polling this costs us 1-2% of the arm CPU */ - /* convert this into a respnde to interrupt 0x7a */ - saa7164_api_collect_debug(dev); - - /* Monitor CPU load every 1 second */ - if ((last_poll_time + 1000 /* ms */) < jiffies_to_msecs(jiffies)) { - saa7164_api_get_load_info(dev, &fwinfo); - last_poll_time = jiffies_to_msecs(jiffies); - } - - } - - dprintk(DBGLVL_THR, "thread exiting\n"); - return 0; -} - -static int __devinit saa7164_initdev(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - struct saa7164_dev *dev; - int err, i; - u32 version; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (NULL == dev) - return -ENOMEM; - - /* pci init */ - dev->pci = pci_dev; - if (pci_enable_device(pci_dev)) { - err = -EIO; - goto fail_free; - } - - if (saa7164_dev_setup(dev) < 0) { - err = -EINVAL; - goto fail_free; - } - - /* print pci info */ - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->name, - pci_name(pci_dev), dev->pci_rev, pci_dev->irq, - dev->pci_lat, - (unsigned long long)pci_resource_start(pci_dev, 0)); - - pci_set_master(pci_dev); - /* TODO */ - if (!pci_dma_supported(pci_dev, 0xffffffff)) { - printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); - err = -EIO; - goto fail_irq; - } - - err = request_irq(pci_dev->irq, saa7164_irq, - IRQF_SHARED | IRQF_DISABLED, dev->name, dev); - if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, - pci_dev->irq); - err = -EIO; - goto fail_irq; - } - - pci_set_drvdata(pci_dev, dev); - - /* Init the internal command list */ - for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { - dev->cmds[i].seqno = i; - dev->cmds[i].inuse = 0; - mutex_init(&dev->cmds[i].lock); - init_waitqueue_head(&dev->cmds[i].wait); - } - - /* We need a deferred interrupt handler for cmd handling */ - INIT_WORK(&dev->workcmd, saa7164_work_cmdhandler); - - /* Only load the firmware if we know the board */ - if (dev->board != SAA7164_BOARD_UNKNOWN) { - - err = saa7164_downloadfirmware(dev); - if (err < 0) { - printk(KERN_ERR - "Failed to boot firmware, no features " - "registered\n"); - goto fail_fw; - } - - saa7164_get_descriptors(dev); - saa7164_dumpregs(dev, 0); - saa7164_getcurrentfirmwareversion(dev); - saa7164_getfirmwarestatus(dev); - err = saa7164_bus_setup(dev); - if (err < 0) - printk(KERN_ERR - "Failed to setup the bus, will continue\n"); - saa7164_bus_dump(dev); - - /* Ping the running firmware via the command bus and get the - * firmware version, this checks the bus is running OK. - */ - version = 0; - if (saa7164_api_get_fw_version(dev, &version) == SAA_OK) - dprintk(1, "Bus is operating correctly using " - "version %d.%d.%d.%d (0x%x)\n", - (version & 0x0000fc00) >> 10, - (version & 0x000003e0) >> 5, - (version & 0x0000001f), - (version & 0xffff0000) >> 16, - version); - else - printk(KERN_ERR - "Failed to communicate with the firmware\n"); - - /* Bring up the I2C buses */ - saa7164_i2c_register(&dev->i2c_bus[0]); - saa7164_i2c_register(&dev->i2c_bus[1]); - saa7164_i2c_register(&dev->i2c_bus[2]); - saa7164_gpio_setup(dev); - saa7164_card_setup(dev); - - /* Parse the dynamic device configuration, find various - * media endpoints (MPEG, WMV, PS, TS) and cache their - * configuration details into the driver, so we can - * reference them later during simething_register() func, - * interrupt handlers, deferred work handlers etc. - */ - saa7164_api_enum_subdevs(dev); - - /* Begin to create the video sub-systems and register funcs */ - if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) { - if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS1]) < 0) { - printk(KERN_ERR "%s() Failed to register " - "dvb adapters on porta\n", - __func__); - } - } - - if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) { - if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS2]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "dvb adapters on portb\n", - __func__); - } - } - - if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) { - if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC1]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "mpeg encoder\n", __func__); - } - } - - if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) { - if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC2]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "mpeg encoder\n", __func__); - } - } - - if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) { - if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI1]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "vbi device\n", __func__); - } - } - - if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) { - if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI2]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "vbi device\n", __func__); - } - } - saa7164_api_set_debug(dev, fw_debug); - - if (fw_debug) { - dev->kthread = kthread_run(saa7164_thread_function, dev, - "saa7164 debug"); - if (!dev->kthread) - printk(KERN_ERR "%s() Failed to create " - "debug kernel thread\n", __func__); - } - - } /* != BOARD_UNKNOWN */ - else - printk(KERN_ERR "%s() Unsupported board detected, " - "registering without firmware\n", __func__); - - dprintk(1, "%s() parameter debug = %d\n", __func__, saa_debug); - dprintk(1, "%s() parameter waitsecs = %d\n", __func__, waitsecs); - -fail_fw: - return 0; - -fail_irq: - saa7164_dev_unregister(dev); -fail_free: - kfree(dev); - return err; -} - -static void saa7164_shutdown(struct saa7164_dev *dev) -{ - dprintk(1, "%s()\n", __func__); -} - -static void __devexit saa7164_finidev(struct pci_dev *pci_dev) -{ - struct saa7164_dev *dev = pci_get_drvdata(pci_dev); - - if (dev->board != SAA7164_BOARD_UNKNOWN) { - if (fw_debug && dev->kthread) { - kthread_stop(dev->kthread); - dev->kthread = NULL; - } - if (dev->firmwareloaded) - saa7164_api_set_debug(dev, 0x00); - } - - saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], - &dev->ports[SAA7164_PORT_ENC1].irq_interval); - saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], - &dev->ports[SAA7164_PORT_ENC1].svc_interval); - saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], - &dev->ports[SAA7164_PORT_ENC1].irq_svc_interval); - saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], - &dev->ports[SAA7164_PORT_ENC1].read_interval); - saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1], - &dev->ports[SAA7164_PORT_ENC1].poll_interval); - saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI1], - &dev->ports[SAA7164_PORT_VBI1].read_interval); - saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI2], - &dev->ports[SAA7164_PORT_VBI2].poll_interval); - - saa7164_shutdown(dev); - - if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) - saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS1]); - - if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) - saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS2]); - - if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) - saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC1]); - - if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) - saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC2]); - - if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) - saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI1]); - - if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) - saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI2]); - - saa7164_i2c_unregister(&dev->i2c_bus[0]); - saa7164_i2c_unregister(&dev->i2c_bus[1]); - saa7164_i2c_unregister(&dev->i2c_bus[2]); - - pci_disable_device(pci_dev); - - /* unregister stuff */ - free_irq(pci_dev->irq, dev); - pci_set_drvdata(pci_dev, NULL); - - mutex_lock(&devlist); - list_del(&dev->devlist); - mutex_unlock(&devlist); - - saa7164_dev_unregister(dev); - kfree(dev); -} - -static struct pci_device_id saa7164_pci_tbl[] = { - { - /* SAA7164 */ - .vendor = 0x1131, - .device = 0x7164, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { - /* --- end of list --- */ - } -}; -MODULE_DEVICE_TABLE(pci, saa7164_pci_tbl); - -static struct pci_driver saa7164_pci_driver = { - .name = "saa7164", - .id_table = saa7164_pci_tbl, - .probe = saa7164_initdev, - .remove = __devexit_p(saa7164_finidev), - /* TODO */ - .suspend = NULL, - .resume = NULL, -}; - -static int __init saa7164_init(void) -{ - printk(KERN_INFO "saa7164 driver loaded\n"); - -#ifdef CONFIG_PROC_FS - saa7164_proc_create(); -#endif - return pci_register_driver(&saa7164_pci_driver); -} - -static void __exit saa7164_fini(void) -{ -#ifdef CONFIG_PROC_FS - remove_proc_entry("saa7164", NULL); -#endif - pci_unregister_driver(&saa7164_pci_driver); -} - -module_init(saa7164_init); -module_exit(saa7164_fini); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-dvb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,554 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "saa7164.h" - -#include "tda10048.h" -#include "tda18271.h" -#include "s5h1411.h" - -#define DRIVER_NAME "saa7164" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -/* addr is in the card struct, get it from there */ -static struct tda10048_config hauppauge_hvr2200_1_config = { - .demod_address = 0x10 >> 1, - .output_mode = TDA10048_SERIAL_OUTPUT, - .fwbulkwritelen = TDA10048_BULKWRITE_200, - .inversion = TDA10048_INVERSION_ON, - .dtv6_if_freq_khz = TDA10048_IF_3300, - .dtv7_if_freq_khz = TDA10048_IF_3500, - .dtv8_if_freq_khz = TDA10048_IF_4000, - .clk_freq_khz = TDA10048_CLK_16000, -}; -static struct tda10048_config hauppauge_hvr2200_2_config = { - .demod_address = 0x12 >> 1, - .output_mode = TDA10048_SERIAL_OUTPUT, - .fwbulkwritelen = TDA10048_BULKWRITE_200, - .inversion = TDA10048_INVERSION_ON, - .dtv6_if_freq_khz = TDA10048_IF_3300, - .dtv7_if_freq_khz = TDA10048_IF_3500, - .dtv8_if_freq_khz = TDA10048_IF_4000, - .clk_freq_khz = TDA10048_CLK_16000, -}; - -static struct tda18271_std_map hauppauge_tda18271_std_map = { - .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3, - .if_lvl = 6, .rfagc_top = 0x37 }, - .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, - .if_lvl = 6, .rfagc_top = 0x37 }, -}; - -static struct tda18271_config hauppauge_hvr22x0_tuner_config = { - .std_map = &hauppauge_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, - .role = TDA18271_MASTER, -}; - -static struct tda18271_config hauppauge_hvr22x0s_tuner_config = { - .std_map = &hauppauge_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, - .role = TDA18271_SLAVE, - .output_opt = TDA18271_OUTPUT_LT_OFF, - .rf_cal_on_startup = 1 -}; - -static struct s5h1411_config hauppauge_s5h1411_config = { - .output_mode = S5H1411_SERIAL_OUTPUT, - .gpio = S5H1411_GPIO_ON, - .qam_if = S5H1411_IF_4000, - .vsb_if = S5H1411_IF_3250, - .inversion = S5H1411_INVERSION_ON, - .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static int saa7164_dvb_stop_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); - if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", - __func__, ret); - ret = -EIO; - } else { - dprintk(DBGLVL_DVB, "%s() Stopped\n", __func__); - ret = 0; - } - - return ret; -} - -static int saa7164_dvb_acquire_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); - if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", - __func__, ret); - ret = -EIO; - } else { - dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__); - ret = 0; - } - - return ret; -} - -static int saa7164_dvb_pause_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); - if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", - __func__, ret); - ret = -EIO; - } else { - dprintk(DBGLVL_DVB, "%s() Paused\n", __func__); - ret = 0; - } - - return ret; -} - -/* Firmware is very windows centric, meaning you have to transition - * the part through AVStream / KS Windows stages, forwards or backwards. - * States are: stopped, acquired (h/w), paused, started. - */ -static int saa7164_dvb_stop_streaming(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - struct list_head *p, *q; - int ret; - - dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); - - ret = saa7164_dvb_pause_port(port); - ret = saa7164_dvb_acquire_port(port); - ret = saa7164_dvb_stop_port(port); - - /* Mark the hardware buffers as free */ - mutex_lock(&port->dmaqueue_lock); - list_for_each_safe(p, q, &port->dmaqueue.list) { - buf = list_entry(p, struct saa7164_buffer, list); - buf->flags = SAA7164_BUFFER_FREE; - } - mutex_unlock(&port->dmaqueue_lock); - - return ret; -} - -static int saa7164_dvb_start_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret = 0, result; - - dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); - - saa7164_buffer_cfg_port(port); - - /* Acquire the hardware */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", - __func__, result); - - /* Stop the hardware, regardless */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire/forced stop transition " - "failed, res = 0x%x\n", __func__, result); - } - ret = -EIO; - goto out; - } else - dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__); - - /* Pause the hardware */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", - __func__, result); - - /* Stop the hardware, regardless */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause/forced stop transition " - "failed, res = 0x%x\n", __func__, result); - } - - ret = -EIO; - goto out; - } else - dprintk(DBGLVL_DVB, "%s() Paused\n", __func__); - - /* Start the hardware */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", - __func__, result); - - /* Stop the hardware, regardless */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() run/forced stop transition " - "failed, res = 0x%x\n", __func__, result); - } - - ret = -EIO; - } else - dprintk(DBGLVL_DVB, "%s() Running\n", __func__); - -out: - return ret; -} - -static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct saa7164_port *port = (struct saa7164_port *) demux->priv; - struct saa7164_dvb *dvb = &port->dvb; - struct saa7164_dev *dev = port->dev; - int ret = 0; - - dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); - - if (!demux->dmx.frontend) - return -EINVAL; - - if (dvb) { - mutex_lock(&dvb->lock); - if (dvb->feeding++ == 0) { - /* Start transport */ - ret = saa7164_dvb_start_port(port); - } - mutex_unlock(&dvb->lock); - dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", - __func__, port->nr, dvb->feeding); - } - - return ret; -} - -static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct saa7164_port *port = (struct saa7164_port *) demux->priv; - struct saa7164_dvb *dvb = &port->dvb; - struct saa7164_dev *dev = port->dev; - int ret = 0; - - dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); - - if (dvb) { - mutex_lock(&dvb->lock); - if (--dvb->feeding == 0) { - /* Stop transport */ - ret = saa7164_dvb_stop_streaming(port); - } - mutex_unlock(&dvb->lock); - dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", - __func__, port->nr, dvb->feeding); - } - - return ret; -} - -static int dvb_register(struct saa7164_port *port) -{ - struct saa7164_dvb *dvb = &port->dvb; - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - int result, i; - - dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); - - if (port->type != SAA7164_MPEG_DVB) - BUG(); - - /* Sanity check that the PCI configuration space is active */ - if (port->hwcfg.BARLocation == 0) { - result = -ENOMEM; - printk(KERN_ERR "%s: dvb_register_adapter failed " - "(errno = %d), NO PCI configuration\n", - DRIVER_NAME, result); - goto fail_adapter; - } - - /* Init and establish defaults */ - port->hw_streamingparams.bitspersample = 8; - port->hw_streamingparams.samplesperline = 188; - port->hw_streamingparams.numberoflines = - (SAA7164_TS_NUMBER_OF_LINES * 188) / 188; - - port->hw_streamingparams.pitch = 188; - port->hw_streamingparams.linethreshold = 0; - port->hw_streamingparams.pagetablelistvirt = NULL; - port->hw_streamingparams.pagetablelistphys = NULL; - port->hw_streamingparams.numpagetables = 2 + - ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE); - - port->hw_streamingparams.numpagetableentries = port->hwcfg.buffercount; - - /* Allocate the PCI resources */ - for (i = 0; i < port->hwcfg.buffercount; i++) { - buf = saa7164_buffer_alloc(port, - port->hw_streamingparams.numberoflines * - port->hw_streamingparams.pitch); - - if (!buf) { - result = -ENOMEM; - printk(KERN_ERR "%s: dvb_register_adapter failed " - "(errno = %d), unable to allocate buffers\n", - DRIVER_NAME, result); - goto fail_adapter; - } - - mutex_lock(&port->dmaqueue_lock); - list_add_tail(&buf->list, &port->dmaqueue.list); - mutex_unlock(&port->dmaqueue_lock); - } - - /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, - &dev->pci->dev, adapter_nr); - if (result < 0) { - printk(KERN_ERR "%s: dvb_register_adapter failed " - "(errno = %d)\n", DRIVER_NAME, result); - goto fail_adapter; - } - dvb->adapter.priv = port; - - /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (result < 0) { - printk(KERN_ERR "%s: dvb_register_frontend failed " - "(errno = %d)\n", DRIVER_NAME, result); - goto fail_frontend; - } - - /* register demux stuff */ - dvb->demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = port; - dvb->demux.filternum = 256; - dvb->demux.feednum = 256; - dvb->demux.start_feed = saa7164_dvb_start_feed; - dvb->demux.stop_feed = saa7164_dvb_stop_feed; - result = dvb_dmx_init(&dvb->demux); - if (result < 0) { - printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n", - DRIVER_NAME, result); - goto fail_dmx; - } - - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = &dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (result < 0) { - printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n", - DRIVER_NAME, result); - goto fail_dmxdev; - } - - dvb->fe_hw.source = DMX_FRONTEND_0; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_ERR "%s: add_frontend failed " - "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result); - goto fail_fe_hw; - } - - dvb->fe_mem.source = DMX_MEMORY_FE; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); - if (result < 0) { - printk(KERN_ERR "%s: add_frontend failed " - "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result); - goto fail_fe_mem; - } - - result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", - DRIVER_NAME, result); - goto fail_fe_conn; - } - - /* register network adapter */ - dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); - return 0; - -fail_fe_conn: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); -fail_fe_mem: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); -fail_fe_hw: - dvb_dmxdev_release(&dvb->dmxdev); -fail_dmxdev: - dvb_dmx_release(&dvb->demux); -fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -fail_adapter: - return result; -} - -int saa7164_dvb_unregister(struct saa7164_port *port) -{ - struct saa7164_dvb *dvb = &port->dvb; - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *b; - struct list_head *c, *n; - - dprintk(DBGLVL_DVB, "%s()\n", __func__); - - if (port->type != SAA7164_MPEG_DVB) - BUG(); - - /* Remove any allocated buffers */ - mutex_lock(&port->dmaqueue_lock); - list_for_each_safe(c, n, &port->dmaqueue.list) { - b = list_entry(c, struct saa7164_buffer, list); - list_del(c); - saa7164_buffer_dealloc(b); - } - mutex_unlock(&port->dmaqueue_lock); - - if (dvb->frontend == NULL) - return 0; - - dvb_net_release(&dvb->net); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); - return 0; -} - -/* All the DVB attach calls go here, this function get's modified - * for each new card. - */ -int saa7164_dvb_register(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct saa7164_dvb *dvb = &port->dvb; - struct saa7164_i2c *i2c_bus = NULL; - int ret; - - dprintk(DBGLVL_DVB, "%s()\n", __func__); - - /* init frontend */ - switch (dev->board) { - case SAA7164_BOARD_HAUPPAUGE_HVR2200: - case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: - case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: - i2c_bus = &dev->i2c_bus[port->nr + 1]; - switch (port->nr) { - case 0: - port->dvb.frontend = dvb_attach(tda10048_attach, - &hauppauge_hvr2200_1_config, - &i2c_bus->i2c_adap); - - if (port->dvb.frontend != NULL) { - /* TODO: addr is in the card struct */ - dvb_attach(tda18271_attach, port->dvb.frontend, - 0xc0 >> 1, &i2c_bus->i2c_adap, - &hauppauge_hvr22x0_tuner_config); - } - - break; - case 1: - port->dvb.frontend = dvb_attach(tda10048_attach, - &hauppauge_hvr2200_2_config, - &i2c_bus->i2c_adap); - - if (port->dvb.frontend != NULL) { - /* TODO: addr is in the card struct */ - dvb_attach(tda18271_attach, port->dvb.frontend, - 0xc0 >> 1, &i2c_bus->i2c_adap, - &hauppauge_hvr22x0s_tuner_config); - } - - break; - } - break; - case SAA7164_BOARD_HAUPPAUGE_HVR2250: - case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: - case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: - i2c_bus = &dev->i2c_bus[port->nr + 1]; - - port->dvb.frontend = dvb_attach(s5h1411_attach, - &hauppauge_s5h1411_config, - &i2c_bus->i2c_adap); - - if (port->dvb.frontend != NULL) { - if (port->nr == 0) { - /* Master TDA18271 */ - /* TODO: addr is in the card struct */ - dvb_attach(tda18271_attach, port->dvb.frontend, - 0xc0 >> 1, &i2c_bus->i2c_adap, - &hauppauge_hvr22x0_tuner_config); - } else { - /* Slave TDA18271 */ - dvb_attach(tda18271_attach, port->dvb.frontend, - 0xc0 >> 1, &i2c_bus->i2c_adap, - &hauppauge_hvr22x0s_tuner_config); - } - } - - break; - default: - printk(KERN_ERR "%s: The frontend isn't supported\n", - dev->name); - break; - } - if (NULL == dvb->frontend) { - printk(KERN_ERR "%s() Frontend initialization failed\n", - __func__); - return -1; - } - - /* register everything */ - ret = dvb_register(port); - if (ret < 0) { - if (dvb->frontend->ops.release) - dvb->frontend->ops.release(dvb->frontend); - return ret; - } - - return 0; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-encoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-encoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-encoder.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-encoder.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1510 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "saa7164.h" - -#define ENCODER_MAX_BITRATE 6500000 -#define ENCODER_MIN_BITRATE 1000000 -#define ENCODER_DEF_BITRATE 5000000 - -static struct saa7164_tvnorm saa7164_tvnorms[] = { - { - .name = "NTSC-M", - .id = V4L2_STD_NTSC_M, - }, { - .name = "NTSC-JP", - .id = V4L2_STD_NTSC_M_JP, - } -}; - -static const u32 saa7164_v4l2_ctrls[] = { - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_SHARPNESS, - V4L2_CID_MPEG_STREAM_TYPE, - V4L2_CID_MPEG_VIDEO_ASPECT, - V4L2_CID_MPEG_VIDEO_B_FRAMES, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, - V4L2_CID_MPEG_AUDIO_MUTE, - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, - V4L2_CID_MPEG_VIDEO_BITRATE, - V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, - 0 -}; - -/* Take the encoder configuration form the port struct and - * flush it to the hardware. - */ -static void saa7164_encoder_configure(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - port->encoder_params.width = port->width; - port->encoder_params.height = port->height; - port->encoder_params.is_50hz = - (port->encodernorm.id & V4L2_STD_625_50) != 0; - - /* Set up the DIF (enable it) for analog mode by default */ - saa7164_api_initialize_dif(port); - - /* Configure the correct video standard */ - saa7164_api_configure_dif(port, port->encodernorm.id); - - /* Ensure the audio decoder is correct configured */ - saa7164_api_set_audio_std(port); -} - -static int saa7164_encoder_buffers_dealloc(struct saa7164_port *port) -{ - struct list_head *c, *n, *p, *q, *l, *v; - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - struct saa7164_user_buffer *ubuf; - - /* Remove any allocated buffers */ - mutex_lock(&port->dmaqueue_lock); - - dprintk(DBGLVL_ENC, "%s(port=%d) dmaqueue\n", __func__, port->nr); - list_for_each_safe(c, n, &port->dmaqueue.list) { - buf = list_entry(c, struct saa7164_buffer, list); - list_del(c); - saa7164_buffer_dealloc(buf); - } - - dprintk(DBGLVL_ENC, "%s(port=%d) used\n", __func__, port->nr); - list_for_each_safe(p, q, &port->list_buf_used.list) { - ubuf = list_entry(p, struct saa7164_user_buffer, list); - list_del(p); - saa7164_buffer_dealloc_user(ubuf); - } - - dprintk(DBGLVL_ENC, "%s(port=%d) free\n", __func__, port->nr); - list_for_each_safe(l, v, &port->list_buf_free.list) { - ubuf = list_entry(l, struct saa7164_user_buffer, list); - list_del(l); - saa7164_buffer_dealloc_user(ubuf); - } - - mutex_unlock(&port->dmaqueue_lock); - dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr); - - return 0; -} - -/* Dynamic buffer switch at encoder start time */ -static int saa7164_encoder_buffers_alloc(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - struct saa7164_user_buffer *ubuf; - struct tmHWStreamParameters *params = &port->hw_streamingparams; - int result = -ENODEV, i; - int len = 0; - - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - if (port->encoder_params.stream_type == - V4L2_MPEG_STREAM_TYPE_MPEG2_PS) { - dprintk(DBGLVL_ENC, - "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n", - __func__); - params->samplesperline = 128; - params->numberoflines = 256; - params->pitch = 128; - params->numpagetables = 2 + - ((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE); - } else - if (port->encoder_params.stream_type == - V4L2_MPEG_STREAM_TYPE_MPEG2_TS) { - dprintk(DBGLVL_ENC, - "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n", - __func__); - params->samplesperline = 188; - params->numberoflines = 312; - params->pitch = 188; - params->numpagetables = 2 + - ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE); - } else - BUG(); - - /* Init and establish defaults */ - params->bitspersample = 8; - params->linethreshold = 0; - params->pagetablelistvirt = NULL; - params->pagetablelistphys = NULL; - params->numpagetableentries = port->hwcfg.buffercount; - - /* Allocate the PCI resources, buffers (hard) */ - for (i = 0; i < port->hwcfg.buffercount; i++) { - buf = saa7164_buffer_alloc(port, - params->numberoflines * - params->pitch); - - if (!buf) { - printk(KERN_ERR "%s() failed " - "(errno = %d), unable to allocate buffer\n", - __func__, result); - result = -ENOMEM; - goto failed; - } else { - - mutex_lock(&port->dmaqueue_lock); - list_add_tail(&buf->list, &port->dmaqueue.list); - mutex_unlock(&port->dmaqueue_lock); - - } - } - - /* Allocate some kenrel kernel buffers for copying - * to userpsace. - */ - len = params->numberoflines * params->pitch; - - if (encoder_buffers < 16) - encoder_buffers = 16; - if (encoder_buffers > 512) - encoder_buffers = 512; - - for (i = 0; i < encoder_buffers; i++) { - - ubuf = saa7164_buffer_alloc_user(dev, len); - if (ubuf) { - mutex_lock(&port->dmaqueue_lock); - list_add_tail(&ubuf->list, &port->list_buf_free.list); - mutex_unlock(&port->dmaqueue_lock); - } - - } - - result = 0; - -failed: - return result; -} - -static int saa7164_encoder_initialize(struct saa7164_port *port) -{ - saa7164_encoder_configure(port); - return 0; -} - -/* -- V4L2 --------------------------------------------------------- */ -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - unsigned int i; - - dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)*id); - - for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) { - if (*id & saa7164_tvnorms[i].id) - break; - } - if (i == ARRAY_SIZE(saa7164_tvnorms)) - return -EINVAL; - - port->encodernorm = saa7164_tvnorms[i]; - - /* Update the audio decoder while is not running in - * auto detect mode. - */ - saa7164_api_set_audio_std(port); - - dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)*id); - - return 0; -} - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - int n; - - char *inputs[] = { "tuner", "composite", "svideo", "aux", - "composite 2", "svideo 2", "aux 2" }; - - if (i->index >= 7) - return -EINVAL; - - strcpy(i->name, inputs[i->index]); - - if (i->index == 0) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - - for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++) - i->std |= saa7164_tvnorms[n].id; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - if (saa7164_api_get_videomux(port) != SAA_OK) - return -EIO; - - *i = (port->mux_input - 1); - - dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, *i); - - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, i); - - if (i >= 7) - return -EINVAL; - - port->mux_input = i + 1; - - if (saa7164_api_set_videomux(port) != SAA_OK) - return -EIO; - - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "tuner"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO; - - dprintk(DBGLVL_ENC, "VIDIOC_G_TUNER: tuner type %d\n", t->type); - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - /* Update the A/V core */ - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = port->freq; - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - struct saa7164_port *tsport; - struct dvb_frontend *fe; - - /* TODO: Pull this for the std */ - struct analog_parameters params = { - .mode = V4L2_TUNER_ANALOG_TV, - .audmode = V4L2_TUNER_MODE_STEREO, - .std = port->encodernorm.id, - .frequency = f->frequency - }; - - /* Stop the encoder */ - dprintk(DBGLVL_ENC, "%s() frequency=%d tuner=%d\n", __func__, - f->frequency, f->tuner); - - if (f->tuner != 0) - return -EINVAL; - - if (f->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - - port->freq = f->frequency; - - /* Update the hardware */ - if (port->nr == SAA7164_PORT_ENC1) - tsport = &dev->ports[SAA7164_PORT_TS1]; - else - if (port->nr == SAA7164_PORT_ENC2) - tsport = &dev->ports[SAA7164_PORT_TS2]; - else - BUG(); - - fe = tsport->dvb.frontend; - - if (fe && fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, ¶ms); - else - printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); - - saa7164_encoder_initialize(port); - - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__, - ctl->id, ctl->value); - - switch (ctl->id) { - case V4L2_CID_BRIGHTNESS: - ctl->value = port->ctl_brightness; - break; - case V4L2_CID_CONTRAST: - ctl->value = port->ctl_contrast; - break; - case V4L2_CID_SATURATION: - ctl->value = port->ctl_saturation; - break; - case V4L2_CID_HUE: - ctl->value = port->ctl_hue; - break; - case V4L2_CID_SHARPNESS: - ctl->value = port->ctl_sharpness; - break; - case V4L2_CID_AUDIO_VOLUME: - ctl->value = port->ctl_volume; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - int ret = 0; - - dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__, - ctl->id, ctl->value); - - switch (ctl->id) { - case V4L2_CID_BRIGHTNESS: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_brightness = ctl->value; - saa7164_api_set_usercontrol(port, - PU_BRIGHTNESS_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_CONTRAST: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_contrast = ctl->value; - saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_SATURATION: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_saturation = ctl->value; - saa7164_api_set_usercontrol(port, - PU_SATURATION_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_HUE: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_hue = ctl->value; - saa7164_api_set_usercontrol(port, PU_HUE_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_SHARPNESS: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_sharpness = ctl->value; - saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_AUDIO_VOLUME: - if ((ctl->value >= -83) && (ctl->value <= 24)) { - port->ctl_volume = ctl->value; - saa7164_api_set_audio_volume(port, port->ctl_volume); - } else - ret = -EINVAL; - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int saa7164_get_ctrl(struct saa7164_port *port, - struct v4l2_ext_control *ctrl) -{ - struct saa7164_encoder_params *params = &port->encoder_params; - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_BITRATE: - ctrl->value = params->bitrate; - break; - case V4L2_CID_MPEG_STREAM_TYPE: - ctrl->value = params->stream_type; - break; - case V4L2_CID_MPEG_AUDIO_MUTE: - ctrl->value = params->ctl_mute; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - ctrl->value = params->ctl_aspect; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - ctrl->value = params->bitrate_mode; - break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - ctrl->value = params->refdist; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - ctrl->value = params->bitrate_peak; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - ctrl->value = params->gop_size; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = saa7164_get_ctrl(port, ctrl); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - - } - - return -EINVAL; -} - -static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3) -{ - int ret = -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_BITRATE: - if ((ctrl->value >= ENCODER_MIN_BITRATE) && - (ctrl->value <= ENCODER_MAX_BITRATE)) - ret = 0; - break; - case V4L2_CID_MPEG_STREAM_TYPE: - if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) || - (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)) - ret = 0; - break; - case V4L2_CID_MPEG_AUDIO_MUTE: - if ((ctrl->value >= 0) && - (ctrl->value <= 1)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) && - (ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - if ((ctrl->value >= 0) && - (ctrl->value <= 255)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - if ((ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) || - (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - if ((ctrl->value >= 1) && - (ctrl->value <= 3)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - if ((ctrl->value >= ENCODER_MIN_BITRATE) && - (ctrl->value <= ENCODER_MAX_BITRATE)) - ret = 0; - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int vidioc_try_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = saa7164_try_ctrl(ctrl, 0); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - } - - return -EINVAL; -} - -static int saa7164_set_ctrl(struct saa7164_port *port, - struct v4l2_ext_control *ctrl) -{ - struct saa7164_encoder_params *params = &port->encoder_params; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_BITRATE: - params->bitrate = ctrl->value; - break; - case V4L2_CID_MPEG_STREAM_TYPE: - params->stream_type = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_MUTE: - params->ctl_mute = ctrl->value; - ret = saa7164_api_audio_mute(port, params->ctl_mute); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, - ret); - ret = -EIO; - } - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - params->ctl_aspect = ctrl->value; - ret = saa7164_api_set_aspect_ratio(port); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, - ret); - ret = -EIO; - } - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - params->bitrate_mode = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - params->refdist = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - params->bitrate_peak = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - params->gop_size = ctrl->value; - break; - default: - return -EINVAL; - } - - /* TODO: Update the hardware */ - - return ret; -} - -static int vidioc_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = saa7164_try_ctrl(ctrl, 0); - if (err) { - ctrls->error_idx = i; - break; - } - err = saa7164_set_ctrl(port, ctrl); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - - } - - return -EINVAL; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - strcpy(cap->driver, dev->name); - strlcpy(cap->card, saa7164_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - 0; - - cap->capabilities |= V4L2_CAP_TUNER; - cap->version = 0; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index != 0) - return -EINVAL; - - strlcpy(f->description, "MPEG", sizeof(f->description)); - f->pixelformat = V4L2_PIX_FMT_MPEG; - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - port->ts_packet_size * port->ts_packet_count; - f->fmt.pix.colorspace = 0; - f->fmt.pix.width = port->width; - f->fmt.pix.height = port->height; - - dprintk(DBGLVL_ENC, "VIDIOC_G_FMT: w: %d, h: %d\n", - port->width, port->height); - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - port->ts_packet_size * port->ts_packet_count; - f->fmt.pix.colorspace = 0; - dprintk(DBGLVL_ENC, "VIDIOC_TRY_FMT: w: %d, h: %d\n", - port->width, port->height); - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - port->ts_packet_size * port->ts_packet_count; - f->fmt.pix.colorspace = 0; - - dprintk(DBGLVL_ENC, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", - f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); - - return 0; -} - -static int vidioc_log_status(struct file *file, void *priv) -{ - return 0; -} - -static int fill_queryctrl(struct saa7164_encoder_params *params, - struct v4l2_queryctrl *c) -{ - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128); - case V4L2_CID_SHARPNESS: - return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8); - case V4L2_CID_MPEG_AUDIO_MUTE: - return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(c, -83, 24, 1, 20); - case V4L2_CID_MPEG_VIDEO_BITRATE: - return v4l2_ctrl_query_fill(c, - ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE, - 100000, ENCODER_DEF_BITRATE); - case V4L2_CID_MPEG_STREAM_TYPE: - return v4l2_ctrl_query_fill(c, - V4L2_MPEG_STREAM_TYPE_MPEG2_PS, - V4L2_MPEG_STREAM_TYPE_MPEG2_TS, - 1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS); - case V4L2_CID_MPEG_VIDEO_ASPECT: - return v4l2_ctrl_query_fill(c, - V4L2_MPEG_VIDEO_ASPECT_1x1, - V4L2_MPEG_VIDEO_ASPECT_221x100, - 1, V4L2_MPEG_VIDEO_ASPECT_4x3); - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - return v4l2_ctrl_query_fill(c, 1, 255, 1, 15); - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - return v4l2_ctrl_query_fill(c, - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, - 1, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - return v4l2_ctrl_query_fill(c, - 1, 3, 1, 1); - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - return v4l2_ctrl_query_fill(c, - ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE, - 100000, ENCODER_DEF_BITRATE); - default: - return -EINVAL; - } -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct saa7164_encoder_fh *fh = priv; - struct saa7164_port *port = fh->port; - int i, next; - u32 id = c->id; - - memset(c, 0, sizeof(*c)); - - next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL); - c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL; - - for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) { - if (next) { - if (c->id < saa7164_v4l2_ctrls[i]) - c->id = saa7164_v4l2_ctrls[i]; - else - continue; - } - - if (c->id == saa7164_v4l2_ctrls[i]) - return fill_queryctrl(&port->encoder_params, c); - - if (c->id < saa7164_v4l2_ctrls[i]) - break; - } - - return -EINVAL; -} - -static int saa7164_encoder_stop_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); - if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", - __func__, ret); - ret = -EIO; - } else { - dprintk(DBGLVL_ENC, "%s() Stopped\n", __func__); - ret = 0; - } - - return ret; -} - -static int saa7164_encoder_acquire_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); - if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", - __func__, ret); - ret = -EIO; - } else { - dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__); - ret = 0; - } - - return ret; -} - -static int saa7164_encoder_pause_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); - if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", - __func__, ret); - ret = -EIO; - } else { - dprintk(DBGLVL_ENC, "%s() Paused\n", __func__); - ret = 0; - } - - return ret; -} - -/* Firmware is very windows centric, meaning you have to transition - * the part through AVStream / KS Windows stages, forwards or backwards. - * States are: stopped, acquired (h/w), paused, started. - * We have to leave here will all of the soft buffers on the free list, - * else the cfg_post() func won't have soft buffers to correctly configure. - */ -static int saa7164_encoder_stop_streaming(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - struct saa7164_user_buffer *ubuf; - struct list_head *c, *n; - int ret; - - dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr); - - ret = saa7164_encoder_pause_port(port); - ret = saa7164_encoder_acquire_port(port); - ret = saa7164_encoder_stop_port(port); - - dprintk(DBGLVL_ENC, "%s(port=%d) Hardware stopped\n", __func__, - port->nr); - - /* Reset the state of any allocated buffer resources */ - mutex_lock(&port->dmaqueue_lock); - - /* Reset the hard and soft buffer state */ - list_for_each_safe(c, n, &port->dmaqueue.list) { - buf = list_entry(c, struct saa7164_buffer, list); - buf->flags = SAA7164_BUFFER_FREE; - buf->pos = 0; - } - - list_for_each_safe(c, n, &port->list_buf_used.list) { - ubuf = list_entry(c, struct saa7164_user_buffer, list); - ubuf->pos = 0; - list_move_tail(&ubuf->list, &port->list_buf_free.list); - } - - mutex_unlock(&port->dmaqueue_lock); - - /* Free any allocated resources */ - saa7164_encoder_buffers_dealloc(port); - - dprintk(DBGLVL_ENC, "%s(port=%d) Released\n", __func__, port->nr); - - return ret; -} - -static int saa7164_encoder_start_streaming(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int result, ret = 0; - - dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr); - - port->done_first_interrupt = 0; - - /* allocate all of the PCIe DMA buffer resources on the fly, - * allowing switching between TS and PS payloads without - * requiring a complete driver reload. - */ - saa7164_encoder_buffers_alloc(port); - - /* Configure the encoder with any cache values */ - saa7164_api_set_encoder(port); - saa7164_api_get_encoder(port); - - /* Place the empty buffers on the hardware */ - saa7164_buffer_cfg_port(port); - - /* Acquire the hardware */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", - __func__, result); - - /* Stop the hardware, regardless */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire/forced stop transition " - "failed, res = 0x%x\n", __func__, result); - } - ret = -EIO; - goto out; - } else - dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__); - - /* Pause the hardware */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", - __func__, result); - - /* Stop the hardware, regardless */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause/forced stop transition " - "failed, res = 0x%x\n", __func__, result); - } - - ret = -EIO; - goto out; - } else - dprintk(DBGLVL_ENC, "%s() Paused\n", __func__); - - /* Start the hardware */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", - __func__, result); - - /* Stop the hardware, regardless */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() run/forced stop transition " - "failed, res = 0x%x\n", __func__, result); - } - - ret = -EIO; - } else - dprintk(DBGLVL_ENC, "%s() Running\n", __func__); - -out: - return ret; -} - -static int fops_open(struct file *file) -{ - struct saa7164_dev *dev; - struct saa7164_port *port; - struct saa7164_encoder_fh *fh; - - port = (struct saa7164_port *)video_get_drvdata(video_devdata(file)); - if (!port) - return -ENODEV; - - dev = port->dev; - - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - file->private_data = fh; - fh->port = port; - - return 0; -} - -static int fops_release(struct file *file) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - /* Shut device down on last close */ - if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { - if (atomic_dec_return(&port->v4l_reader_count) == 0) { - /* stop mpeg capture then cancel buffers */ - saa7164_encoder_stop_streaming(port); - } - } - - file->private_data = NULL; - kfree(fh); - - return 0; -} - -struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port) -{ - struct saa7164_user_buffer *ubuf = NULL; - struct saa7164_dev *dev = port->dev; - u32 crc; - - mutex_lock(&port->dmaqueue_lock); - if (!list_empty(&port->list_buf_used.list)) { - ubuf = list_first_entry(&port->list_buf_used.list, - struct saa7164_user_buffer, list); - - if (crc_checking) { - crc = crc32(0, ubuf->data, ubuf->actual_size); - if (crc != ubuf->crc) { - printk(KERN_ERR - "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", - __func__, - ubuf, ubuf->crc, crc); - } - } - - } - mutex_unlock(&port->dmaqueue_lock); - - dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, ubuf); - - return ubuf; -} - -static ssize_t fops_read(struct file *file, char __user *buffer, - size_t count, loff_t *pos) -{ - struct saa7164_encoder_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_user_buffer *ubuf = NULL; - struct saa7164_dev *dev = port->dev; - int ret = 0; - int rem, cnt; - u8 *p; - - port->last_read_msecs_diff = port->last_read_msecs; - port->last_read_msecs = jiffies_to_msecs(jiffies); - port->last_read_msecs_diff = port->last_read_msecs - - port->last_read_msecs_diff; - - saa7164_histogram_update(&port->read_interval, - port->last_read_msecs_diff); - - if (*pos) { - printk(KERN_ERR "%s() ESPIPE\n", __func__); - return -ESPIPE; - } - - if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { - if (atomic_inc_return(&port->v4l_reader_count) == 1) { - - if (saa7164_encoder_initialize(port) < 0) { - printk(KERN_ERR "%s() EINVAL\n", __func__); - return -EINVAL; - } - - saa7164_encoder_start_streaming(port); - msleep(200); - } - } - - /* blocking wait for buffer */ - if ((file->f_flags & O_NONBLOCK) == 0) { - if (wait_event_interruptible(port->wait_read, - saa7164_enc_next_buf(port))) { - printk(KERN_ERR "%s() ERESTARTSYS\n", __func__); - return -ERESTARTSYS; - } - } - - /* Pull the first buffer from the used list */ - ubuf = saa7164_enc_next_buf(port); - - while ((count > 0) && ubuf) { - - /* set remaining bytes to copy */ - rem = ubuf->actual_size - ubuf->pos; - cnt = rem > count ? count : rem; - - p = ubuf->data + ubuf->pos; - - dprintk(DBGLVL_ENC, - "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n", - __func__, (int)count, cnt, rem, ubuf, ubuf->pos); - - if (copy_to_user(buffer, p, cnt)) { - printk(KERN_ERR "%s() copy_to_user failed\n", __func__); - if (!ret) { - printk(KERN_ERR "%s() EFAULT\n", __func__); - ret = -EFAULT; - } - goto err; - } - - ubuf->pos += cnt; - count -= cnt; - buffer += cnt; - ret += cnt; - - if (ubuf->pos > ubuf->actual_size) - printk(KERN_ERR "read() pos > actual, huh?\n"); - - if (ubuf->pos == ubuf->actual_size) { - - /* finished with current buffer, take next buffer */ - - /* Requeue the buffer on the free list */ - ubuf->pos = 0; - - mutex_lock(&port->dmaqueue_lock); - list_move_tail(&ubuf->list, &port->list_buf_free.list); - mutex_unlock(&port->dmaqueue_lock); - - /* Dequeue next */ - if ((file->f_flags & O_NONBLOCK) == 0) { - if (wait_event_interruptible(port->wait_read, - saa7164_enc_next_buf(port))) { - break; - } - } - ubuf = saa7164_enc_next_buf(port); - } - } -err: - if (!ret && !ubuf) - ret = -EAGAIN; - - return ret; -} - -static unsigned int fops_poll(struct file *file, poll_table *wait) -{ - struct saa7164_encoder_fh *fh = - (struct saa7164_encoder_fh *)file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_user_buffer *ubuf; - unsigned int mask = 0; - - port->last_poll_msecs_diff = port->last_poll_msecs; - port->last_poll_msecs = jiffies_to_msecs(jiffies); - port->last_poll_msecs_diff = port->last_poll_msecs - - port->last_poll_msecs_diff; - - saa7164_histogram_update(&port->poll_interval, - port->last_poll_msecs_diff); - - if (!video_is_registered(port->v4l_device)) - return -EIO; - - if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { - if (atomic_inc_return(&port->v4l_reader_count) == 1) { - if (saa7164_encoder_initialize(port) < 0) - return -EINVAL; - saa7164_encoder_start_streaming(port); - msleep(200); - } - } - - /* blocking wait for buffer */ - if ((file->f_flags & O_NONBLOCK) == 0) { - if (wait_event_interruptible(port->wait_read, - saa7164_enc_next_buf(port))) { - return -ERESTARTSYS; - } - } - - /* Pull the first buffer from the used list */ - ubuf = list_first_entry(&port->list_buf_used.list, - struct saa7164_user_buffer, list); - - if (ubuf) - mask |= POLLIN | POLLRDNORM; - - return mask; -} - -static const struct v4l2_file_operations mpeg_fops = { - .owner = THIS_MODULE, - .open = fops_open, - .release = fops_release, - .read = fops_read, - .poll = fops_poll, - .unlocked_ioctl = video_ioctl2, -}; - -int saa7164_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) -{ - struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; - struct saa7164_dev *dev = port->dev; - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - return 0; -} - -int saa7164_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; - struct saa7164_dev *dev = port->dev; - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - return 0; -} - -int saa7164_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; - struct saa7164_dev *dev = port->dev; - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - return 0; -} - -static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, - .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_chip_ident = saa7164_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = saa7164_g_register, - .vidioc_s_register = saa7164_s_register, -#endif -}; - -static struct video_device saa7164_mpeg_template = { - .name = "saa7164", - .fops = &mpeg_fops, - .ioctl_ops = &mpeg_ioctl_ops, - .minor = -1, - .tvnorms = SAA7164_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; - -static struct video_device *saa7164_encoder_alloc( - struct saa7164_port *port, - struct pci_dev *pci, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - - *vfd = *template; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, - type, saa7164_boards[dev->board].name); - - vfd->parent = &pci->dev; - vfd->release = video_device_release; - return vfd; -} - -int saa7164_encoder_register(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int result = -ENODEV; - - dprintk(DBGLVL_ENC, "%s()\n", __func__); - - if (port->type != SAA7164_MPEG_ENCODER) - BUG(); - - /* Sanity check that the PCI configuration space is active */ - if (port->hwcfg.BARLocation == 0) { - printk(KERN_ERR "%s() failed " - "(errno = %d), NO PCI configuration\n", - __func__, result); - result = -ENOMEM; - goto failed; - } - - /* Establish encoder defaults here */ - /* Set default TV standard */ - port->encodernorm = saa7164_tvnorms[0]; - port->width = 720; - port->mux_input = 1; /* Composite */ - port->video_format = EU_VIDEO_FORMAT_MPEG_2; - port->audio_format = 0; - port->video_resolution = 0; - port->ctl_brightness = 127; - port->ctl_contrast = 66; - port->ctl_hue = 128; - port->ctl_saturation = 62; - port->ctl_sharpness = 8; - port->encoder_params.bitrate = ENCODER_DEF_BITRATE; - port->encoder_params.bitrate_peak = ENCODER_DEF_BITRATE; - port->encoder_params.bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; - port->encoder_params.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS; - port->encoder_params.ctl_mute = 0; - port->encoder_params.ctl_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3; - port->encoder_params.refdist = 1; - port->encoder_params.gop_size = SAA7164_ENCODER_DEFAULT_GOP_SIZE; - - if (port->encodernorm.id & V4L2_STD_525_60) - port->height = 480; - else - port->height = 576; - - /* Allocate and register the video device node */ - port->v4l_device = saa7164_encoder_alloc(port, - dev->pci, &saa7164_mpeg_template, "mpeg"); - - if (!port->v4l_device) { - printk(KERN_INFO "%s: can't allocate mpeg device\n", - dev->name); - result = -ENOMEM; - goto failed; - } - - video_set_drvdata(port->v4l_device, port); - result = video_register_device(port->v4l_device, - VFL_TYPE_GRABBER, -1); - if (result < 0) { - printk(KERN_INFO "%s: can't register mpeg device\n", - dev->name); - /* TODO: We're going to leak here if we don't dealloc - The buffers above. The unreg function can't deal wit it. - */ - goto failed; - } - - printk(KERN_INFO "%s: registered device video%d [mpeg]\n", - dev->name, port->v4l_device->num); - - /* Configure the hardware defaults */ - saa7164_api_set_videomux(port); - saa7164_api_set_usercontrol(port, PU_BRIGHTNESS_CONTROL); - saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL); - saa7164_api_set_usercontrol(port, PU_HUE_CONTROL); - saa7164_api_set_usercontrol(port, PU_SATURATION_CONTROL); - saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL); - saa7164_api_audio_mute(port, 0); - saa7164_api_set_audio_volume(port, 20); - saa7164_api_set_aspect_ratio(port); - - /* Disable audio standard detection, it's buggy */ - saa7164_api_set_audio_detection(port, 0); - - saa7164_api_set_encoder(port); - saa7164_api_get_encoder(port); - - result = 0; -failed: - return result; -} - -void saa7164_encoder_unregister(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr); - - if (port->type != SAA7164_MPEG_ENCODER) - BUG(); - - if (port->v4l_device) { - if (port->v4l_device->minor != -1) - video_unregister_device(port->v4l_device); - else - video_device_release(port->v4l_device); - - port->v4l_device = NULL; - } - - dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr); -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-fw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-fw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-fw.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-fw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,613 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#include "saa7164.h" - -#define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw" -#define SAA7164_REV2_FIRMWARE_SIZE 4019072 - -#define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw" -#define SAA7164_REV3_FIRMWARE_SIZE 4019072 - -struct fw_header { - u32 firmwaresize; - u32 bslsize; - u32 reserved; - u32 version; -}; - -int saa7164_dl_wait_ack(struct saa7164_dev *dev, u32 reg) -{ - u32 timeout = SAA_DEVICE_TIMEOUT; - while ((saa7164_readl(reg) & 0x01) == 0) { - timeout -= 10; - if (timeout == 0) { - printk(KERN_ERR "%s() timeout (no d/l ack)\n", - __func__); - return -EBUSY; - } - msleep(100); - } - - return 0; -} - -int saa7164_dl_wait_clr(struct saa7164_dev *dev, u32 reg) -{ - u32 timeout = SAA_DEVICE_TIMEOUT; - while (saa7164_readl(reg) & 0x01) { - timeout -= 10; - if (timeout == 0) { - printk(KERN_ERR "%s() timeout (no d/l clr)\n", - __func__); - return -EBUSY; - } - msleep(100); - } - - return 0; -} - -/* TODO: move dlflags into dev-> and change to write/readl/b */ -/* TODO: Excessive levels of debug */ -int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize, - u32 dlflags, u8 *dst, u32 dstsize) -{ - u32 reg, timeout, offset; - u8 *srcbuf = NULL; - int ret; - - u32 dlflag = dlflags; - u32 dlflag_ack = dlflag + 4; - u32 drflag = dlflag_ack + 4; - u32 drflag_ack = drflag + 4; - u32 bleflag = drflag_ack + 4; - - dprintk(DBGLVL_FW, - "%s(image=%p, size=%d, flags=0x%x, dst=%p, dstsize=0x%x)\n", - __func__, src, srcsize, dlflags, dst, dstsize); - - if ((src == NULL) || (dst == NULL)) { - ret = -EIO; - goto out; - } - - srcbuf = kzalloc(4 * 1048576, GFP_KERNEL); - if (NULL == srcbuf) { - ret = -ENOMEM; - goto out; - } - - if (srcsize > (4*1048576)) { - ret = -ENOMEM; - goto out; - } - - memcpy(srcbuf, src, srcsize); - - dprintk(DBGLVL_FW, "%s() dlflag = 0x%x\n", __func__, dlflag); - dprintk(DBGLVL_FW, "%s() dlflag_ack = 0x%x\n", __func__, dlflag_ack); - dprintk(DBGLVL_FW, "%s() drflag = 0x%x\n", __func__, drflag); - dprintk(DBGLVL_FW, "%s() drflag_ack = 0x%x\n", __func__, drflag_ack); - dprintk(DBGLVL_FW, "%s() bleflag = 0x%x\n", __func__, bleflag); - - reg = saa7164_readl(dlflag); - dprintk(DBGLVL_FW, "%s() dlflag (0x%x)= 0x%x\n", __func__, dlflag, reg); - if (reg == 1) - dprintk(DBGLVL_FW, - "%s() Download flag already set, please reboot\n", - __func__); - - /* Indicate download start */ - saa7164_writel(dlflag, 1); - ret = saa7164_dl_wait_ack(dev, dlflag_ack); - if (ret < 0) - goto out; - - /* Ack download start, then wait for wait */ - saa7164_writel(dlflag, 0); - ret = saa7164_dl_wait_clr(dev, dlflag_ack); - if (ret < 0) - goto out; - - /* Deal with the raw firmware, in the appropriate chunk size */ - for (offset = 0; srcsize > dstsize; - srcsize -= dstsize, offset += dstsize) { - - dprintk(DBGLVL_FW, "%s() memcpy %d\n", __func__, dstsize); - memcpy(dst, srcbuf + offset, dstsize); - - /* Flag the data as ready */ - saa7164_writel(drflag, 1); - ret = saa7164_dl_wait_ack(dev, drflag_ack); - if (ret < 0) - goto out; - - /* Wait for indication data was received */ - saa7164_writel(drflag, 0); - ret = saa7164_dl_wait_clr(dev, drflag_ack); - if (ret < 0) - goto out; - - } - - dprintk(DBGLVL_FW, "%s() memcpy(l) %d\n", __func__, dstsize); - /* Write last block to the device */ - memcpy(dst, srcbuf+offset, srcsize); - - /* Flag the data as ready */ - saa7164_writel(drflag, 1); - ret = saa7164_dl_wait_ack(dev, drflag_ack); - if (ret < 0) - goto out; - - saa7164_writel(drflag, 0); - timeout = 0; - while (saa7164_readl(bleflag) != SAA_DEVICE_IMAGE_BOOTING) { - if (saa7164_readl(bleflag) & SAA_DEVICE_IMAGE_CORRUPT) { - printk(KERN_ERR "%s() image corrupt\n", __func__); - ret = -EBUSY; - goto out; - } - - if (saa7164_readl(bleflag) & SAA_DEVICE_MEMORY_CORRUPT) { - printk(KERN_ERR "%s() device memory corrupt\n", - __func__); - ret = -EBUSY; - goto out; - } - - msleep(10); /* Checkpatch throws a < 20ms warning */ - if (timeout++ > 60) - break; - } - - printk(KERN_INFO "%s() Image downloaded, booting...\n", __func__); - - ret = saa7164_dl_wait_clr(dev, drflag_ack); - if (ret < 0) - goto out; - - printk(KERN_INFO "%s() Image booted successfully.\n", __func__); - ret = 0; - -out: - kfree(srcbuf); - return ret; -} - -/* TODO: Excessive debug */ -/* Load the firmware. Optionally it can be in ROM or newer versions - * can be on disk, saving the expense of the ROM hardware. */ -int saa7164_downloadfirmware(struct saa7164_dev *dev) -{ - /* u32 second_timeout = 60 * SAA_DEVICE_TIMEOUT; */ - u32 tmp, filesize, version, err_flags, first_timeout, fwlength; - u32 second_timeout, updatebootloader = 1, bootloadersize = 0; - const struct firmware *fw = NULL; - struct fw_header *hdr, *boothdr = NULL, *fwhdr; - u32 bootloaderversion = 0, fwloadersize; - u8 *bootloaderoffset = NULL, *fwloaderoffset; - char *fwname; - int ret; - - dprintk(DBGLVL_FW, "%s()\n", __func__); - - if (saa7164_boards[dev->board].chiprev == SAA7164_CHIP_REV2) { - fwname = SAA7164_REV2_FIRMWARE; - fwlength = SAA7164_REV2_FIRMWARE_SIZE; - } else { - fwname = SAA7164_REV3_FIRMWARE; - fwlength = SAA7164_REV3_FIRMWARE_SIZE; - } - - version = saa7164_getcurrentfirmwareversion(dev); - - if (version == 0x00) { - - second_timeout = 100; - first_timeout = 100; - err_flags = saa7164_readl(SAA_BOOTLOADERERROR_FLAGS); - dprintk(DBGLVL_FW, "%s() err_flags = %x\n", - __func__, err_flags); - - while (err_flags != SAA_DEVICE_IMAGE_BOOTING) { - dprintk(DBGLVL_FW, "%s() err_flags = %x\n", - __func__, err_flags); - msleep(10); /* Checkpatch throws a < 20ms warning */ - - if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) { - printk(KERN_ERR "%s() firmware corrupt\n", - __func__); - break; - } - if (err_flags & SAA_DEVICE_MEMORY_CORRUPT) { - printk(KERN_ERR "%s() device memory corrupt\n", - __func__); - break; - } - if (err_flags & SAA_DEVICE_NO_IMAGE) { - printk(KERN_ERR "%s() no first image\n", - __func__); - break; - } - if (err_flags & SAA_DEVICE_IMAGE_SEARCHING) { - first_timeout -= 10; - if (first_timeout == 0) { - printk(KERN_ERR - "%s() no first image\n", - __func__); - break; - } - } else if (err_flags & SAA_DEVICE_IMAGE_LOADING) { - second_timeout -= 10; - if (second_timeout == 0) { - printk(KERN_ERR - "%s() FW load time exceeded\n", - __func__); - break; - } - } else { - second_timeout -= 10; - if (second_timeout == 0) { - printk(KERN_ERR - "%s() Unknown bootloader flags 0x%x\n", - __func__, err_flags); - break; - } - } - - err_flags = saa7164_readl(SAA_BOOTLOADERERROR_FLAGS); - } /* While != Booting */ - - if (err_flags == SAA_DEVICE_IMAGE_BOOTING) { - dprintk(DBGLVL_FW, "%s() Loader 1 has loaded.\n", - __func__); - first_timeout = SAA_DEVICE_TIMEOUT; - second_timeout = 60 * SAA_DEVICE_TIMEOUT; - second_timeout = 100; - - err_flags = saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS); - dprintk(DBGLVL_FW, "%s() err_flags2 = %x\n", - __func__, err_flags); - while (err_flags != SAA_DEVICE_IMAGE_BOOTING) { - dprintk(DBGLVL_FW, "%s() err_flags2 = %x\n", - __func__, err_flags); - msleep(10); /* Checkpatch throws a < 20ms warning */ - - if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) { - printk(KERN_ERR - "%s() firmware corrupt\n", - __func__); - break; - } - if (err_flags & SAA_DEVICE_MEMORY_CORRUPT) { - printk(KERN_ERR - "%s() device memory corrupt\n", - __func__); - break; - } - if (err_flags & SAA_DEVICE_NO_IMAGE) { - printk(KERN_ERR "%s() no first image\n", - __func__); - break; - } - if (err_flags & SAA_DEVICE_IMAGE_SEARCHING) { - first_timeout -= 10; - if (first_timeout == 0) { - printk(KERN_ERR - "%s() no second image\n", - __func__); - break; - } - } else if (err_flags & - SAA_DEVICE_IMAGE_LOADING) { - second_timeout -= 10; - if (second_timeout == 0) { - printk(KERN_ERR - "%s() FW load time exceeded\n", - __func__); - break; - } - } else { - second_timeout -= 10; - if (second_timeout == 0) { - printk(KERN_ERR - "%s() Unknown bootloader flags 0x%x\n", - __func__, err_flags); - break; - } - } - - err_flags = - saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS); - } /* err_flags != SAA_DEVICE_IMAGE_BOOTING */ - - dprintk(DBGLVL_FW, "%s() Loader flags 1:0x%x 2:0x%x.\n", - __func__, - saa7164_readl(SAA_BOOTLOADERERROR_FLAGS), - saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS)); - - } /* err_flags == SAA_DEVICE_IMAGE_BOOTING */ - - /* It's possible for both firmwares to have booted, - * but that doesn't mean they've finished booting yet. - */ - if ((saa7164_readl(SAA_BOOTLOADERERROR_FLAGS) == - SAA_DEVICE_IMAGE_BOOTING) && - (saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS) == - SAA_DEVICE_IMAGE_BOOTING)) { - - - dprintk(DBGLVL_FW, "%s() Loader 2 has loaded.\n", - __func__); - - first_timeout = SAA_DEVICE_TIMEOUT; - while (first_timeout) { - msleep(10); /* Checkpatch throws a < 20ms warning */ - - version = - saa7164_getcurrentfirmwareversion(dev); - if (version) { - dprintk(DBGLVL_FW, - "%s() All f/w loaded successfully\n", - __func__); - break; - } else { - first_timeout -= 10; - if (first_timeout == 0) { - printk(KERN_ERR - "%s() FW did not boot\n", - __func__); - break; - } - } - } - } - version = saa7164_getcurrentfirmwareversion(dev); - } /* version == 0 */ - - /* Has the firmware really booted? */ - if ((saa7164_readl(SAA_BOOTLOADERERROR_FLAGS) == - SAA_DEVICE_IMAGE_BOOTING) && - (saa7164_readl(SAA_SECONDSTAGEERROR_FLAGS) == - SAA_DEVICE_IMAGE_BOOTING) && (version == 0)) { - - printk(KERN_ERR - "%s() The firmware hung, probably bad firmware\n", - __func__); - - /* Tell the second stage loader we have a deadlock */ - saa7164_writel(SAA_DEVICE_DEADLOCK_DETECTED_OFFSET, - SAA_DEVICE_DEADLOCK_DETECTED); - - saa7164_getfirmwarestatus(dev); - - return -ENOMEM; - } - - dprintk(DBGLVL_FW, "Device has Firmware Version %d.%d.%d.%d\n", - (version & 0x0000fc00) >> 10, - (version & 0x000003e0) >> 5, - (version & 0x0000001f), - (version & 0xffff0000) >> 16); - - /* Load the firmwware from the disk if required */ - if (version == 0) { - - printk(KERN_INFO "%s() Waiting for firmware upload (%s)\n", - __func__, fwname); - - ret = request_firmware(&fw, fwname, &dev->pci->dev); - if (ret) { - printk(KERN_ERR "%s() Upload failed. " - "(file not found?)\n", __func__); - return -ENOMEM; - } - - printk(KERN_INFO "%s() firmware read %Zu bytes.\n", - __func__, fw->size); - - if (fw->size != fwlength) { - printk(KERN_ERR "xc5000: firmware incorrect size\n"); - ret = -ENOMEM; - goto out; - } - - printk(KERN_INFO "%s() firmware loaded.\n", __func__); - - hdr = (struct fw_header *)fw->data; - printk(KERN_INFO "Firmware file header part 1:\n"); - printk(KERN_INFO " .FirmwareSize = 0x%x\n", hdr->firmwaresize); - printk(KERN_INFO " .BSLSize = 0x%x\n", hdr->bslsize); - printk(KERN_INFO " .Reserved = 0x%x\n", hdr->reserved); - printk(KERN_INFO " .Version = 0x%x\n", hdr->version); - - /* Retreive bootloader if reqd */ - if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0)) - /* Second bootloader in the firmware file */ - filesize = hdr->reserved * 16; - else - filesize = (hdr->firmwaresize + hdr->bslsize) * - 16 + sizeof(struct fw_header); - - printk(KERN_INFO "%s() SecBootLoader.FileSize = %d\n", - __func__, filesize); - - /* Get bootloader (if reqd) and firmware header */ - if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0)) { - /* Second boot loader is required */ - - /* Get the loader header */ - boothdr = (struct fw_header *)(fw->data + - sizeof(struct fw_header)); - - bootloaderversion = - saa7164_readl(SAA_DEVICE_2ND_VERSION); - dprintk(DBGLVL_FW, "Onboard BootLoader:\n"); - dprintk(DBGLVL_FW, "->Flag 0x%x\n", - saa7164_readl(SAA_BOOTLOADERERROR_FLAGS)); - dprintk(DBGLVL_FW, "->Ack 0x%x\n", - saa7164_readl(SAA_DATAREADY_FLAG_ACK)); - dprintk(DBGLVL_FW, "->FW Version 0x%x\n", version); - dprintk(DBGLVL_FW, "->Loader Version 0x%x\n", - bootloaderversion); - - if ((saa7164_readl(SAA_BOOTLOADERERROR_FLAGS) == - 0x03) && (saa7164_readl(SAA_DATAREADY_FLAG_ACK) - == 0x00) && (version == 0x00)) { - - dprintk(DBGLVL_FW, "BootLoader version in " - "rom %d.%d.%d.%d\n", - (bootloaderversion & 0x0000fc00) >> 10, - (bootloaderversion & 0x000003e0) >> 5, - (bootloaderversion & 0x0000001f), - (bootloaderversion & 0xffff0000) >> 16 - ); - dprintk(DBGLVL_FW, "BootLoader version " - "in file %d.%d.%d.%d\n", - (boothdr->version & 0x0000fc00) >> 10, - (boothdr->version & 0x000003e0) >> 5, - (boothdr->version & 0x0000001f), - (boothdr->version & 0xffff0000) >> 16 - ); - - if (bootloaderversion == boothdr->version) - updatebootloader = 0; - } - - /* Calculate offset to firmware header */ - tmp = (boothdr->firmwaresize + boothdr->bslsize) * 16 + - (sizeof(struct fw_header) + - sizeof(struct fw_header)); - - fwhdr = (struct fw_header *)(fw->data+tmp); - } else { - /* No second boot loader */ - fwhdr = hdr; - } - - dprintk(DBGLVL_FW, "Firmware version in file %d.%d.%d.%d\n", - (fwhdr->version & 0x0000fc00) >> 10, - (fwhdr->version & 0x000003e0) >> 5, - (fwhdr->version & 0x0000001f), - (fwhdr->version & 0xffff0000) >> 16 - ); - - if (version == fwhdr->version) { - /* No download, firmware already on board */ - ret = 0; - goto out; - } - - if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0)) { - if (updatebootloader) { - /* Get ready to upload the bootloader */ - bootloadersize = (boothdr->firmwaresize + - boothdr->bslsize) * 16 + - sizeof(struct fw_header); - - bootloaderoffset = (u8 *)(fw->data + - sizeof(struct fw_header)); - - dprintk(DBGLVL_FW, "bootloader d/l starts.\n"); - printk(KERN_INFO "%s() FirmwareSize = 0x%x\n", - __func__, boothdr->firmwaresize); - printk(KERN_INFO "%s() BSLSize = 0x%x\n", - __func__, boothdr->bslsize); - printk(KERN_INFO "%s() Reserved = 0x%x\n", - __func__, boothdr->reserved); - printk(KERN_INFO "%s() Version = 0x%x\n", - __func__, boothdr->version); - ret = saa7164_downloadimage( - dev, - bootloaderoffset, - bootloadersize, - SAA_DOWNLOAD_FLAGS, - dev->bmmio + SAA_DEVICE_DOWNLOAD_OFFSET, - SAA_DEVICE_BUFFERBLOCKSIZE); - if (ret < 0) { - printk(KERN_ERR - "bootloader d/l has failed\n"); - goto out; - } - dprintk(DBGLVL_FW, - "bootloader download complete.\n"); - - } - - printk(KERN_ERR "starting firmware download(2)\n"); - bootloadersize = (boothdr->firmwaresize + - boothdr->bslsize) * 16 + - sizeof(struct fw_header); - - bootloaderoffset = - (u8 *)(fw->data + sizeof(struct fw_header)); - - fwloaderoffset = bootloaderoffset + bootloadersize; - - /* TODO: fix this bounds overrun here with old f/ws */ - fwloadersize = (fwhdr->firmwaresize + fwhdr->bslsize) * - 16 + sizeof(struct fw_header); - - ret = saa7164_downloadimage( - dev, - fwloaderoffset, - fwloadersize, - SAA_DEVICE_2ND_DOWNLOADFLAG_OFFSET, - dev->bmmio + SAA_DEVICE_2ND_DOWNLOAD_OFFSET, - SAA_DEVICE_2ND_BUFFERBLOCKSIZE); - if (ret < 0) { - printk(KERN_ERR "firmware download failed\n"); - goto out; - } - printk(KERN_ERR "firmware download complete.\n"); - - } else { - - /* No bootloader update reqd, download firmware only */ - printk(KERN_ERR "starting firmware download(3)\n"); - - ret = saa7164_downloadimage( - dev, - (u8 *)fw->data, - fw->size, - SAA_DOWNLOAD_FLAGS, - dev->bmmio + SAA_DEVICE_DOWNLOAD_OFFSET, - SAA_DEVICE_BUFFERBLOCKSIZE); - if (ret < 0) { - printk(KERN_ERR "firmware download failed\n"); - goto out; - } - printk(KERN_ERR "firmware download complete.\n"); - } - } - - dev->firmwareloaded = 1; - ret = 0; - -out: - release_firmware(fw); - return ret; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,623 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - Driver architecture - ******************* - - saa7164_core.c/buffer.c/cards.c/i2c.c/dvb.c - | : Standard Linux driver framework for creating - | : exposing and managing interfaces to the rest - | : of the kernel or userland. Also uses _fw.c to load - | : firmware direct into the PCIe bus, bypassing layers. - V - saa7164_api..() : Translate kernel specific functions/features - | : into command buffers. - V - saa7164_cmd..() : Manages the flow of command packets on/off, - | : the bus. Deal with bus errors, timeouts etc. - V - saa7164_bus..() : Manage a read/write memory ring buffer in the - | : PCIe Address space. - | - | saa7164_fw...() : Load any frimware - | | : direct into the device - V V - <- ----------------- PCIe address space -------------------- -> -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "saa7164-reg.h" -#include "saa7164-types.h" - -#define SAA7164_MAXBOARDS 8 - -#define UNSET (-1U) -#define SAA7164_BOARD_NOAUTO UNSET -#define SAA7164_BOARD_UNKNOWN 0 -#define SAA7164_BOARD_UNKNOWN_REV2 1 -#define SAA7164_BOARD_UNKNOWN_REV3 2 -#define SAA7164_BOARD_HAUPPAUGE_HVR2250 3 -#define SAA7164_BOARD_HAUPPAUGE_HVR2200 4 -#define SAA7164_BOARD_HAUPPAUGE_HVR2200_2 5 -#define SAA7164_BOARD_HAUPPAUGE_HVR2200_3 6 -#define SAA7164_BOARD_HAUPPAUGE_HVR2250_2 7 -#define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8 - -#define SAA7164_MAX_UNITS 8 -#define SAA7164_TS_NUMBER_OF_LINES 312 -#define SAA7164_PS_NUMBER_OF_LINES 256 -#define SAA7164_PT_ENTRIES 16 /* (312 * 188) / 4096 */ -#define SAA7164_MAX_ENCODER_BUFFERS 64 /* max 5secs of latency at 6Mbps */ -#define SAA7164_MAX_VBI_BUFFERS 64 - -/* Port related defines */ -#define SAA7164_PORT_TS1 (0) -#define SAA7164_PORT_TS2 (SAA7164_PORT_TS1 + 1) -#define SAA7164_PORT_ENC1 (SAA7164_PORT_TS2 + 1) -#define SAA7164_PORT_ENC2 (SAA7164_PORT_ENC1 + 1) -#define SAA7164_PORT_VBI1 (SAA7164_PORT_ENC2 + 1) -#define SAA7164_PORT_VBI2 (SAA7164_PORT_VBI1 + 1) -#define SAA7164_MAX_PORTS (SAA7164_PORT_VBI2 + 1) - -#define DBGLVL_FW 4 -#define DBGLVL_DVB 8 -#define DBGLVL_I2C 16 -#define DBGLVL_API 32 -#define DBGLVL_CMD 64 -#define DBGLVL_BUS 128 -#define DBGLVL_IRQ 256 -#define DBGLVL_BUF 512 -#define DBGLVL_ENC 1024 -#define DBGLVL_VBI 2048 -#define DBGLVL_THR 4096 -#define DBGLVL_CPU 8192 - -#define SAA7164_NORMS \ - (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443) - -enum port_t { - SAA7164_MPEG_UNDEFINED = 0, - SAA7164_MPEG_DVB, - SAA7164_MPEG_ENCODER, - SAA7164_MPEG_VBI, -}; - -enum saa7164_i2c_bus_nr { - SAA7164_I2C_BUS_0 = 0, - SAA7164_I2C_BUS_1, - SAA7164_I2C_BUS_2, -}; - -enum saa7164_buffer_flags { - SAA7164_BUFFER_UNDEFINED = 0, - SAA7164_BUFFER_FREE, - SAA7164_BUFFER_BUSY, - SAA7164_BUFFER_FULL -}; - -enum saa7164_unit_type { - SAA7164_UNIT_UNDEFINED = 0, - SAA7164_UNIT_DIGITAL_DEMODULATOR, - SAA7164_UNIT_ANALOG_DEMODULATOR, - SAA7164_UNIT_TUNER, - SAA7164_UNIT_EEPROM, - SAA7164_UNIT_ZILOG_IRBLASTER, - SAA7164_UNIT_ENCODER, -}; - -/* The PCIe bridge doesn't grant direct access to i2c. - * Instead, you address i2c devices using a uniqely - * allocated 'unitid' value via a messaging API. This - * is a problem. The kernel and existing demod/tuner - * drivers expect to talk 'i2c', so we have to maintain - * a translation layer, and a series of functions to - * convert i2c bus + device address into a unit id. - */ -struct saa7164_unit { - enum saa7164_unit_type type; - u8 id; - char *name; - enum saa7164_i2c_bus_nr i2c_bus_nr; - u8 i2c_bus_addr; - u8 i2c_reg_len; -}; - -struct saa7164_board { - char *name; - enum port_t porta, portb, portc, - portd, porte, portf; - enum { - SAA7164_CHIP_UNDEFINED = 0, - SAA7164_CHIP_REV2, - SAA7164_CHIP_REV3, - } chiprev; - struct saa7164_unit unit[SAA7164_MAX_UNITS]; -}; - -struct saa7164_subid { - u16 subvendor; - u16 subdevice; - u32 card; -}; - -struct saa7164_encoder_fh { - struct saa7164_port *port; - atomic_t v4l_reading; -}; - -struct saa7164_vbi_fh { - struct saa7164_port *port; - atomic_t v4l_reading; -}; - -struct saa7164_histogram_bucket { - u32 val; - u32 count; - u64 update_time; -}; - -struct saa7164_histogram { - char name[32]; - struct saa7164_histogram_bucket counter1[64]; -}; - -struct saa7164_user_buffer { - struct list_head list; - - /* Attributes */ - u8 *data; - u32 pos; - u32 actual_size; - - u32 crc; -}; - -struct saa7164_fw_status { - - /* RISC Core details */ - u32 status; - u32 mode; - u32 spec; - u32 inst; - u32 cpuload; - u32 remainheap; - - /* Firmware version */ - u32 version; - u32 major; - u32 sub; - u32 rel; - u32 buildnr; -}; - -struct saa7164_dvb { - struct mutex lock; - struct dvb_adapter adapter; - struct dvb_frontend *frontend; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net net; - int feeding; -}; - -struct saa7164_i2c { - struct saa7164_dev *dev; - - enum saa7164_i2c_bus_nr nr; - - /* I2C I/O */ - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - u32 i2c_rc; -}; - -struct saa7164_ctrl { - struct v4l2_queryctrl v; -}; - -struct saa7164_tvnorm { - char *name; - v4l2_std_id id; -}; - -struct saa7164_encoder_params { - struct saa7164_tvnorm encodernorm; - u32 height; - u32 width; - u32 is_50hz; - u32 bitrate; /* bps */ - u32 bitrate_peak; /* bps */ - u32 bitrate_mode; - u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */ - - u32 audio_sampling_freq; - u32 ctl_mute; - u32 ctl_aspect; - u32 refdist; - u32 gop_size; -}; - -struct saa7164_vbi_params { - struct saa7164_tvnorm encodernorm; - u32 height; - u32 width; - u32 is_50hz; - u32 bitrate; /* bps */ - u32 bitrate_peak; /* bps */ - u32 bitrate_mode; - u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */ - - u32 audio_sampling_freq; - u32 ctl_mute; - u32 ctl_aspect; - u32 refdist; - u32 gop_size; -}; - -struct saa7164_port; - -struct saa7164_buffer { - struct list_head list; - - /* Note of which h/w buffer list index position we occupy */ - int idx; - - struct saa7164_port *port; - - /* Hardware Specific */ - /* PCI Memory allocations */ - enum saa7164_buffer_flags flags; /* Free, Busy, Full */ - - /* A block of page align PCI memory */ - u32 pci_size; /* PCI allocation size in bytes */ - u64 __iomem *cpu; /* Virtual address */ - dma_addr_t dma; /* Physical address */ - u32 crc; /* Checksum for the entire buffer data */ - - /* A page table that splits the block into a number of entries */ - u32 pt_size; /* PCI allocation size in bytes */ - u64 __iomem *pt_cpu; /* Virtual address */ - dma_addr_t pt_dma; /* Physical address */ - - /* Encoder fops */ - u32 pos; - u32 actual_size; -}; - -struct saa7164_port { - - struct saa7164_dev *dev; - enum port_t type; - int nr; - - /* --- Generic port attributes --- */ - - /* HW stream parameters */ - struct tmHWStreamParameters hw_streamingparams; - - /* DMA configuration values, is seeded during initialization */ - struct tmComResDMATermDescrHeader hwcfg; - - /* hardware specific registers */ - u32 bufcounter; - u32 pitch; - u32 bufsize; - u32 bufoffset; - u32 bufptr32l; - u32 bufptr32h; - u64 bufptr64; - - u32 numpte; /* Number of entries in array, only valid in head */ - - struct mutex dmaqueue_lock; - struct saa7164_buffer dmaqueue; - - u64 last_irq_msecs, last_svc_msecs; - u64 last_irq_msecs_diff, last_svc_msecs_diff; - u32 last_svc_wp; - u32 last_svc_rp; - u64 last_irq_svc_msecs_diff; - u64 last_read_msecs, last_read_msecs_diff; - u64 last_poll_msecs, last_poll_msecs_diff; - - struct saa7164_histogram irq_interval; - struct saa7164_histogram svc_interval; - struct saa7164_histogram irq_svc_interval; - struct saa7164_histogram read_interval; - struct saa7164_histogram poll_interval; - - /* --- DVB Transport Specific --- */ - struct saa7164_dvb dvb; - - /* --- Encoder/V4L related attributes --- */ - /* Encoder */ - /* Defaults established in saa7164-encoder.c */ - struct saa7164_tvnorm encodernorm; - u32 height; - u32 width; - u32 freq; - u32 ts_packet_size; - u32 ts_packet_count; - u8 mux_input; - u8 encoder_profile; - u8 video_format; - u8 audio_format; - u8 video_resolution; - u16 ctl_brightness; - u16 ctl_contrast; - u16 ctl_hue; - u16 ctl_saturation; - u16 ctl_sharpness; - s8 ctl_volume; - - struct tmComResAFeatureDescrHeader audfeat; - struct tmComResEncoderDescrHeader encunit; - struct tmComResProcDescrHeader vidproc; - struct tmComResExtDevDescrHeader ifunit; - struct tmComResTunerDescrHeader tunerunit; - - struct work_struct workenc; - - /* V4L Encoder Video */ - struct saa7164_encoder_params encoder_params; - struct video_device *v4l_device; - atomic_t v4l_reader_count; - - struct saa7164_buffer list_buf_used; - struct saa7164_buffer list_buf_free; - wait_queue_head_t wait_read; - - /* V4L VBI */ - struct tmComResVBIFormatDescrHeader vbi_fmt_ntsc; - struct saa7164_vbi_params vbi_params; - - /* Debug */ - u32 sync_errors; - u32 v_cc_errors; - u32 a_cc_errors; - u8 last_v_cc; - u8 last_a_cc; - u32 done_first_interrupt; -}; - -struct saa7164_dev { - struct list_head devlist; - atomic_t refcount; - - /* pci stuff */ - struct pci_dev *pci; - unsigned char pci_rev, pci_lat; - int pci_bus, pci_slot; - u32 __iomem *lmmio; - u8 __iomem *bmmio; - u32 __iomem *lmmio2; - u8 __iomem *bmmio2; - int pci_irqmask; - - /* board details */ - int nr; - int hwrevision; - u32 board; - char name[16]; - - /* firmware status */ - struct saa7164_fw_status fw_status; - u32 firmwareloaded; - - struct tmComResHWDescr hwdesc; - struct tmComResInterfaceDescr intfdesc; - struct tmComResBusDescr busdesc; - - struct tmComResBusInfo bus; - - /* Interrupt status and ack registers */ - u32 int_status; - u32 int_ack; - - struct cmd cmds[SAA_CMD_MAX_MSG_UNITS]; - struct mutex lock; - - /* I2c related */ - struct saa7164_i2c i2c_bus[3]; - - /* Transport related */ - struct saa7164_port ports[SAA7164_MAX_PORTS]; - - /* Deferred command/api interrupts handling */ - struct work_struct workcmd; - - /* A kernel thread to monitor the firmware log, used - * only in debug mode. - */ - struct task_struct *kthread; - -}; - -extern struct list_head saa7164_devlist; -extern unsigned int waitsecs; -extern unsigned int encoder_buffers; -extern unsigned int vbi_buffers; - -/* ----------------------------------------------------------- */ -/* saa7164-core.c */ -void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr); -void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len); -void saa7164_getfirmwarestatus(struct saa7164_dev *dev); -u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev); -void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val); - -/* ----------------------------------------------------------- */ -/* saa7164-fw.c */ -int saa7164_downloadfirmware(struct saa7164_dev *dev); - -/* ----------------------------------------------------------- */ -/* saa7164-i2c.c */ -extern int saa7164_i2c_register(struct saa7164_i2c *bus); -extern int saa7164_i2c_unregister(struct saa7164_i2c *bus); -extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus, - unsigned int cmd, void *arg); - -/* ----------------------------------------------------------- */ -/* saa7164-bus.c */ -int saa7164_bus_setup(struct saa7164_dev *dev); -void saa7164_bus_dump(struct saa7164_dev *dev); -int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, - void *buf); -int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, - void *buf, int peekonly); - -/* ----------------------------------------------------------- */ -/* saa7164-cmd.c */ -int saa7164_cmd_send(struct saa7164_dev *dev, - u8 id, enum tmComResCmd command, u16 controlselector, - u16 size, void *buf); -void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno); -int saa7164_irq_dequeue(struct saa7164_dev *dev); - -/* ----------------------------------------------------------- */ -/* saa7164-api.c */ -int saa7164_api_get_fw_version(struct saa7164_dev *dev, u32 *version); -int saa7164_api_enum_subdevs(struct saa7164_dev *dev); -int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg, - u32 datalen, u8 *data); -int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, - u32 datalen, u8 *data); -int saa7164_api_dif_write(struct saa7164_i2c *bus, u8 addr, - u32 datalen, u8 *data); -int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen); -int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin); -int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin); -int saa7164_api_transition_port(struct saa7164_port *port, u8 mode); -int saa7164_api_initialize_dif(struct saa7164_port *port); -int saa7164_api_configure_dif(struct saa7164_port *port, u32 std); -int saa7164_api_set_encoder(struct saa7164_port *port); -int saa7164_api_get_encoder(struct saa7164_port *port); -int saa7164_api_set_aspect_ratio(struct saa7164_port *port); -int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl); -int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl); -int saa7164_api_set_videomux(struct saa7164_port *port); -int saa7164_api_audio_mute(struct saa7164_port *port, int mute); -int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level); -int saa7164_api_set_audio_std(struct saa7164_port *port); -int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect); -int saa7164_api_get_videomux(struct saa7164_port *port); -int saa7164_api_set_vbi_format(struct saa7164_port *port); -int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level); -int saa7164_api_collect_debug(struct saa7164_dev *dev); -int saa7164_api_get_load_info(struct saa7164_dev *dev, - struct tmFwInfoStruct *i); - -/* ----------------------------------------------------------- */ -/* saa7164-cards.c */ -extern struct saa7164_board saa7164_boards[]; -extern const unsigned int saa7164_bcount; - -extern struct saa7164_subid saa7164_subids[]; -extern const unsigned int saa7164_idcount; - -extern void saa7164_card_list(struct saa7164_dev *dev); -extern void saa7164_gpio_setup(struct saa7164_dev *dev); -extern void saa7164_card_setup(struct saa7164_dev *dev); - -extern int saa7164_i2caddr_to_reglen(struct saa7164_i2c *bus, int addr); -extern int saa7164_i2caddr_to_unitid(struct saa7164_i2c *bus, int addr); -extern char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid); - -/* ----------------------------------------------------------- */ -/* saa7164-dvb.c */ -extern int saa7164_dvb_register(struct saa7164_port *port); -extern int saa7164_dvb_unregister(struct saa7164_port *port); - -/* ----------------------------------------------------------- */ -/* saa7164-buffer.c */ -extern struct saa7164_buffer *saa7164_buffer_alloc( - struct saa7164_port *port, u32 len); -extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf); -extern void saa7164_buffer_display(struct saa7164_buffer *buf); -extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i); -extern int saa7164_buffer_cfg_port(struct saa7164_port *port); -extern struct saa7164_user_buffer *saa7164_buffer_alloc_user( - struct saa7164_dev *dev, u32 len); -extern void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf); -extern int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i); - -/* ----------------------------------------------------------- */ -/* saa7164-encoder.c */ -int saa7164_encoder_register(struct saa7164_port *port); -void saa7164_encoder_unregister(struct saa7164_port *port); - -/* ----------------------------------------------------------- */ -/* saa7164-vbi.c */ -int saa7164_vbi_register(struct saa7164_port *port); -void saa7164_vbi_unregister(struct saa7164_port *port); - -/* ----------------------------------------------------------- */ - -extern unsigned int crc_checking; - -extern unsigned int saa_debug; -#define dprintk(level, fmt, arg...)\ - do { if (saa_debug & level)\ - printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\ - } while (0) - -#define log_warn(fmt, arg...)\ - do { \ - printk(KERN_WARNING "%s: " fmt, dev->name, ## arg);\ - } while (0) - -#define log_err(fmt, arg...)\ - do { \ - printk(KERN_ERROR "%s: " fmt, dev->name, ## arg);\ - } while (0) - -#define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2)) -#define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2)) - -#define saa7164_readb(reg) readl(dev->bmmio + (reg)) -#define saa7164_writeb(reg, value) writel((value), dev->bmmio + (reg)) - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "saa7164.h" - -static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) -{ - struct saa7164_i2c *bus = i2c_adap->algo_data; - struct saa7164_dev *dev = bus->dev; - int i, retval = 0; - - dprintk(DBGLVL_I2C, "%s(num = %d)\n", __func__, num); - - for (i = 0 ; i < num; i++) { - dprintk(DBGLVL_I2C, "%s(num = %d) addr = 0x%02x len = 0x%x\n", - __func__, num, msgs[i].addr, msgs[i].len); - if (msgs[i].flags & I2C_M_RD) { - /* Unsupported - Yet*/ - printk(KERN_ERR "%s() Unsupported - Yet\n", __func__); - continue; - } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && - msgs[i].addr == msgs[i + 1].addr) { - /* write then read from same address */ - - retval = saa7164_api_i2c_read(bus, msgs[i].addr, - msgs[i].len, msgs[i].buf, - msgs[i+1].len, msgs[i+1].buf - ); - - i++; - - if (retval < 0) - goto err; - } else { - /* write */ - retval = saa7164_api_i2c_write(bus, msgs[i].addr, - msgs[i].len, msgs[i].buf); - } - if (retval < 0) - goto err; - } - return num; - -err: - return retval; -} - -void saa7164_call_i2c_clients(struct saa7164_i2c *bus, unsigned int cmd, - void *arg) -{ - if (bus->i2c_rc != 0) - return; - - i2c_clients_command(&bus->i2c_adap, cmd, arg); -} - -static u32 saa7164_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm saa7164_i2c_algo_template = { - .master_xfer = i2c_xfer, - .functionality = saa7164_functionality, -}; - -/* ----------------------------------------------------------------------- */ - -static struct i2c_adapter saa7164_i2c_adap_template = { - .name = "saa7164", - .owner = THIS_MODULE, - .algo = &saa7164_i2c_algo_template, -}; - -static struct i2c_client saa7164_i2c_client_template = { - .name = "saa7164 internal", -}; - -int saa7164_i2c_register(struct saa7164_i2c *bus) -{ - struct saa7164_dev *dev = bus->dev; - - dprintk(DBGLVL_I2C, "%s(bus = %d)\n", __func__, bus->nr); - - memcpy(&bus->i2c_adap, &saa7164_i2c_adap_template, - sizeof(bus->i2c_adap)); - - memcpy(&bus->i2c_algo, &saa7164_i2c_algo_template, - sizeof(bus->i2c_algo)); - - memcpy(&bus->i2c_client, &saa7164_i2c_client_template, - sizeof(bus->i2c_client)); - - bus->i2c_adap.dev.parent = &dev->pci->dev; - - strlcpy(bus->i2c_adap.name, bus->dev->name, - sizeof(bus->i2c_adap.name)); - - bus->i2c_algo.data = bus; - bus->i2c_adap.algo_data = bus; - i2c_set_adapdata(&bus->i2c_adap, bus); - i2c_add_adapter(&bus->i2c_adap); - - bus->i2c_client.adapter = &bus->i2c_adap; - - if (0 != bus->i2c_rc) - printk(KERN_ERR "%s: i2c bus %d register FAILED\n", - dev->name, bus->nr); - - return bus->i2c_rc; -} - -int saa7164_i2c_unregister(struct saa7164_i2c *bus) -{ - i2c_del_adapter(&bus->i2c_adap); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,219 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* TODO: Retest the driver with errors expressed as negatives */ - -/* Result codes */ -#define SAA_OK 0 -#define SAA_ERR_BAD_PARAMETER 0x09 -#define SAA_ERR_NO_RESOURCES 0x0c -#define SAA_ERR_NOT_SUPPORTED 0x13 -#define SAA_ERR_BUSY 0x15 -#define SAA_ERR_READ 0x17 -#define SAA_ERR_TIMEOUT 0x1f -#define SAA_ERR_OVERFLOW 0x20 -#define SAA_ERR_EMPTY 0x22 -#define SAA_ERR_NOT_STARTED 0x23 -#define SAA_ERR_ALREADY_STARTED 0x24 -#define SAA_ERR_NOT_STOPPED 0x25 -#define SAA_ERR_ALREADY_STOPPED 0x26 -#define SAA_ERR_INVALID_COMMAND 0x3e -#define SAA_ERR_NULL_PACKET 0x59 - -/* Errors and flags from the silicon */ -#define PVC_ERRORCODE_UNKNOWN 0x00 -#define PVC_ERRORCODE_INVALID_COMMAND 0x01 -#define PVC_ERRORCODE_INVALID_CONTROL 0x02 -#define PVC_ERRORCODE_INVALID_DATA 0x03 -#define PVC_ERRORCODE_TIMEOUT 0x04 -#define PVC_ERRORCODE_NAK 0x05 -#define PVC_RESPONSEFLAG_ERROR 0x01 -#define PVC_RESPONSEFLAG_OVERFLOW 0x02 -#define PVC_RESPONSEFLAG_RESET 0x04 -#define PVC_RESPONSEFLAG_INTERFACE 0x08 -#define PVC_RESPONSEFLAG_CONTINUED 0x10 -#define PVC_CMDFLAG_INTERRUPT 0x02 -#define PVC_CMDFLAG_INTERFACE 0x04 -#define PVC_CMDFLAG_SERIALIZE 0x08 -#define PVC_CMDFLAG_CONTINUE 0x10 - -/* Silicon Commands */ -#define GET_DESCRIPTORS_CONTROL 0x01 -#define GET_STRING_CONTROL 0x03 -#define GET_LANGUAGE_CONTROL 0x05 -#define SET_POWER_CONTROL 0x07 -#define GET_FW_STATUS_CONTROL 0x08 -#define GET_FW_VERSION_CONTROL 0x09 -#define SET_DEBUG_LEVEL_CONTROL 0x0B -#define GET_DEBUG_DATA_CONTROL 0x0C -#define GET_PRODUCTION_INFO_CONTROL 0x0D - -/* cmd defines */ -#define SAA_CMDFLAG_CONTINUE 0x10 -#define SAA_CMD_MAX_MSG_UNITS 256 - -/* Some defines */ -#define SAA_BUS_TIMEOUT 50 -#define SAA_DEVICE_TIMEOUT 5000 -#define SAA_DEVICE_MAXREQUESTSIZE 256 - -/* Register addresses */ -#define SAA_DEVICE_VERSION 0x30 -#define SAA_DOWNLOAD_FLAGS 0x34 -#define SAA_DOWNLOAD_FLAG 0x34 -#define SAA_DOWNLOAD_FLAG_ACK 0x38 -#define SAA_DATAREADY_FLAG 0x3C -#define SAA_DATAREADY_FLAG_ACK 0x40 - -/* Boot loader register and bit definitions */ -#define SAA_BOOTLOADERERROR_FLAGS 0x44 -#define SAA_DEVICE_IMAGE_SEARCHING 0x01 -#define SAA_DEVICE_IMAGE_LOADING 0x02 -#define SAA_DEVICE_IMAGE_BOOTING 0x03 -#define SAA_DEVICE_IMAGE_CORRUPT 0x04 -#define SAA_DEVICE_MEMORY_CORRUPT 0x08 -#define SAA_DEVICE_NO_IMAGE 0x10 - -/* Register addresses */ -#define SAA_DEVICE_2ND_VERSION 0x50 -#define SAA_DEVICE_2ND_DOWNLOADFLAG_OFFSET 0x54 - -/* Register addresses */ -#define SAA_SECONDSTAGEERROR_FLAGS 0x64 - -/* Bootloader regs and flags */ -#define SAA_DEVICE_DEADLOCK_DETECTED_OFFSET 0x6C -#define SAA_DEVICE_DEADLOCK_DETECTED 0xDEADDEAD - -/* Basic firmware status registers */ -#define SAA_DEVICE_SYSINIT_STATUS_OFFSET 0x70 -#define SAA_DEVICE_SYSINIT_STATUS 0x70 -#define SAA_DEVICE_SYSINIT_MODE 0x74 -#define SAA_DEVICE_SYSINIT_SPEC 0x78 -#define SAA_DEVICE_SYSINIT_INST 0x7C -#define SAA_DEVICE_SYSINIT_CPULOAD 0x80 -#define SAA_DEVICE_SYSINIT_REMAINHEAP 0x84 - -#define SAA_DEVICE_DOWNLOAD_OFFSET 0x1000 -#define SAA_DEVICE_BUFFERBLOCKSIZE 0x1000 - -#define SAA_DEVICE_2ND_BUFFERBLOCKSIZE 0x100000 -#define SAA_DEVICE_2ND_DOWNLOAD_OFFSET 0x200000 - -/* Descriptors */ -#define CS_INTERFACE 0x24 - -/* Descriptor subtypes */ -#define VC_INPUT_TERMINAL 0x02 -#define VC_OUTPUT_TERMINAL 0x03 -#define VC_SELECTOR_UNIT 0x04 -#define VC_PROCESSING_UNIT 0x05 -#define FEATURE_UNIT 0x06 -#define TUNER_UNIT 0x09 -#define ENCODER_UNIT 0x0A -#define EXTENSION_UNIT 0x0B -#define VC_TUNER_PATH 0xF0 -#define PVC_HARDWARE_DESCRIPTOR 0xF1 -#define PVC_INTERFACE_DESCRIPTOR 0xF2 -#define PVC_INFRARED_UNIT 0xF3 -#define DRM_UNIT 0xF4 -#define GENERAL_REQUEST 0xF5 - -/* Format Types */ -#define VS_FORMAT_TYPE 0x02 -#define VS_FORMAT_TYPE_I 0x01 -#define VS_FORMAT_UNCOMPRESSED 0x04 -#define VS_FRAME_UNCOMPRESSED 0x05 -#define VS_FORMAT_MPEG2PS 0x09 -#define VS_FORMAT_MPEG2TS 0x0A -#define VS_FORMAT_MPEG4SL 0x0B -#define VS_FORMAT_WM9 0x0C -#define VS_FORMAT_DIVX 0x0D -#define VS_FORMAT_VBI 0x0E -#define VS_FORMAT_RDS 0x0F - -/* Device extension commands */ -#define EXU_REGISTER_ACCESS_CONTROL 0x00 -#define EXU_GPIO_CONTROL 0x01 -#define EXU_GPIO_GROUP_CONTROL 0x02 -#define EXU_INTERRUPT_CONTROL 0x03 - -/* State Transition and args */ -#define SAA_PROBE_CONTROL 0x01 -#define SAA_COMMIT_CONTROL 0x02 -#define SAA_STATE_CONTROL 0x03 -#define SAA_DMASTATE_STOP 0x00 -#define SAA_DMASTATE_ACQUIRE 0x01 -#define SAA_DMASTATE_PAUSE 0x02 -#define SAA_DMASTATE_RUN 0x03 - -/* A/V Mux Input Selector */ -#define SU_INPUT_SELECT_CONTROL 0x01 - -/* Encoder Profiles */ -#define EU_PROFILE_PS_DVD 0x06 -#define EU_PROFILE_TS_HQ 0x09 -#define EU_VIDEO_FORMAT_MPEG_2 0x02 - -/* Tuner */ -#define TU_AUDIO_MODE_CONTROL 0x17 - -/* Video Formats */ -#define TU_STANDARD_CONTROL 0x00 -#define TU_STANDARD_AUTO_CONTROL 0x01 -#define TU_STANDARD_NONE 0x00 -#define TU_STANDARD_NTSC_M 0x01 -#define TU_STANDARD_PAL_I 0x08 -#define TU_STANDARD_MANUAL 0x00 -#define TU_STANDARD_AUTO 0x01 - -/* Video Controls */ -#define PU_BRIGHTNESS_CONTROL 0x02 -#define PU_CONTRAST_CONTROL 0x03 -#define PU_HUE_CONTROL 0x06 -#define PU_SATURATION_CONTROL 0x07 -#define PU_SHARPNESS_CONTROL 0x08 - -/* Audio Controls */ -#define MUTE_CONTROL 0x01 -#define VOLUME_CONTROL 0x02 -#define AUDIO_DEFAULT_CONTROL 0x0D - -/* Default Volume Levels */ -#define TMHW_LEV_ADJ_DECLEV_DEFAULT 0x00 -#define TMHW_LEV_ADJ_MONOLEV_DEFAULT 0x00 -#define TMHW_LEV_ADJ_NICLEV_DEFAULT 0x00 -#define TMHW_LEV_ADJ_SAPLEV_DEFAULT 0x00 -#define TMHW_LEV_ADJ_ADCLEV_DEFAULT 0x00 - -/* Encoder Related Commands */ -#define EU_PROFILE_CONTROL 0x00 -#define EU_VIDEO_FORMAT_CONTROL 0x01 -#define EU_VIDEO_BIT_RATE_CONTROL 0x02 -#define EU_VIDEO_RESOLUTION_CONTROL 0x03 -#define EU_VIDEO_GOP_STRUCTURE_CONTROL 0x04 -#define EU_VIDEO_INPUT_ASPECT_CONTROL 0x0A -#define EU_AUDIO_FORMAT_CONTROL 0x0C -#define EU_AUDIO_BIT_RATE_CONTROL 0x0D - -/* Firmware Debugging */ -#define SET_DEBUG_LEVEL_CONTROL 0x0B -#define GET_DEBUG_DATA_CONTROL 0x0C diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-types.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-types.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-types.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-types.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,442 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* TODO: Cleanup and shorten the namespace */ - -/* Some structues are passed directly to/from the firmware and - * have strict alignment requirements. This is one of them. - */ -struct tmComResHWDescr { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubtype; - u16 bcdSpecVersion; - u32 dwClockFrequency; - u32 dwClockUpdateRes; - u8 bCapabilities; - u32 dwDeviceRegistersLocation; - u32 dwHostMemoryRegion; - u32 dwHostMemoryRegionSize; - u32 dwHostHibernatMemRegion; - u32 dwHostHibernatMemRegionSize; -} __attribute__((packed)); - -/* This is DWORD aligned on windows but I can't find the right - * gcc syntax to match the binary data from the device. - * I've manually padded with Reserved[3] bytes to match the hardware, - * but this could break if GCC decies to pack in a different way. - */ -struct tmComResInterfaceDescr { - u8 bLength; - u8 bDescriptorType; - u8 bDescriptorSubtype; - u8 bFlags; - u8 bInterfaceType; - u8 bInterfaceId; - u8 bBaseInterface; - u8 bInterruptId; - u8 bDebugInterruptId; - u8 BARLocation; - u8 Reserved[3]; -}; - -struct tmComResBusDescr { - u64 CommandRing; - u64 ResponseRing; - u32 CommandWrite; - u32 CommandRead; - u32 ResponseWrite; - u32 ResponseRead; -}; - -enum tmBusType { - NONE = 0, - TYPE_BUS_PCI = 1, - TYPE_BUS_PCIe = 2, - TYPE_BUS_USB = 3, - TYPE_BUS_I2C = 4 -}; - -struct tmComResBusInfo { - enum tmBusType Type; - u16 m_wMaxReqSize; - u8 *m_pdwSetRing; - u32 m_dwSizeSetRing; - u8 *m_pdwGetRing; - u32 m_dwSizeGetRing; - u32 m_dwSetWritePos; - u32 m_dwSetReadPos; - u32 m_dwGetWritePos; - u32 m_dwGetReadPos; - - /* All access is protected */ - struct mutex lock; - -}; - -struct tmComResInfo { - u8 id; - u8 flags; - u16 size; - u32 command; - u16 controlselector; - u8 seqno; -} __attribute__((packed)); - -enum tmComResCmd { - SET_CUR = 0x01, - GET_CUR = 0x81, - GET_MIN = 0x82, - GET_MAX = 0x83, - GET_RES = 0x84, - GET_LEN = 0x85, - GET_INFO = 0x86, - GET_DEF = 0x87 -}; - -struct cmd { - u8 seqno; - u32 inuse; - u32 timeout; - u32 signalled; - struct mutex lock; - wait_queue_head_t wait; -}; - -struct tmDescriptor { - u32 pathid; - u32 size; - void *descriptor; -}; - -struct tmComResDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 unitid; -} __attribute__((packed)); - -struct tmComResExtDevDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 unitid; - u32 devicetype; - u16 deviceid; - u32 numgpiopins; - u8 numgpiogroups; - u8 controlsize; -} __attribute__((packed)); - -struct tmComResGPIO { - u32 pin; - u8 state; -} __attribute__((packed)); - -struct tmComResPathDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 pathid; -} __attribute__((packed)); - -/* terminaltype */ -enum tmComResTermType { - ITT_ANTENNA = 0x0203, - LINE_CONNECTOR = 0x0603, - SPDIF_CONNECTOR = 0x0605, - COMPOSITE_CONNECTOR = 0x0401, - SVIDEO_CONNECTOR = 0x0402, - COMPONENT_CONNECTOR = 0x0403, - STANDARD_DMA = 0xF101 -}; - -struct tmComResAntTermDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 terminalid; - u16 terminaltype; - u8 assocterminal; - u8 iterminal; - u8 controlsize; -} __attribute__((packed)); - -struct tmComResTunerDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 unitid; - u8 sourceid; - u8 iunit; - u32 tuningstandards; - u8 controlsize; - u32 controls; -} __attribute__((packed)); - -enum tmBufferFlag { - /* the buffer does not contain any valid data */ - TM_BUFFER_FLAG_EMPTY, - - /* the buffer is filled with valid data */ - TM_BUFFER_FLAG_DONE, - - /* the buffer is the dummy buffer - TODO??? */ - TM_BUFFER_FLAG_DUMMY_BUFFER -}; - -struct tmBuffer { - u64 *pagetablevirt; - u64 pagetablephys; - u16 offset; - u8 *context; - u64 timestamp; - enum tmBufferFlag BufferFlag; - u32 lostbuffers; - u32 validbuffers; - u64 *dummypagevirt; - u64 dummypagephys; - u64 *addressvirt; -}; - -struct tmHWStreamParameters { - u32 bitspersample; - u32 samplesperline; - u32 numberoflines; - u32 pitch; - u32 linethreshold; - u64 **pagetablelistvirt; - u64 *pagetablelistphys; - u32 numpagetables; - u32 numpagetableentries; -}; - -struct tmStreamParameters { - struct tmHWStreamParameters HWStreamParameters; - u64 qwDummyPageTablePhys; - u64 *pDummyPageTableVirt; -}; - -struct tmComResDMATermDescrHeader { - u8 len; - u8 type; - u8 subtyle; - u8 unitid; - u16 terminaltype; - u8 assocterminal; - u8 sourceid; - u8 iterminal; - u32 BARLocation; - u8 flags; - u8 interruptid; - u8 buffercount; - u8 metadatasize; - u8 numformats; - u8 controlsize; -} __attribute__((packed)); - -/* - * - * Description: - * This is the transport stream format header. - * - * Settings: - * bLength - The size of this descriptor in bytes. - * bDescriptorType - CS_INTERFACE. - * bDescriptorSubtype - VS_FORMAT_MPEG2TS descriptor subtype. - * bFormatIndex - A non-zero constant that uniquely identifies the - * format. - * bDataOffset - Offset to TSP packet within MPEG-2 TS transport - * stride, in bytes. - * bPacketLength - Length of TSP packet, in bytes (typically 188). - * bStrideLength - Length of MPEG-2 TS transport stride. - * guidStrideFormat - A Globally Unique Identifier indicating the - * format of the stride data (if any). Set to zeros - * if there is no Stride Data, or if the Stride - * Data is to be ignored by the application. - * - */ -struct tmComResTSFormatDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 bFormatIndex; - u8 bDataOffset; - u8 bPacketLength; - u8 bStrideLength; - u8 guidStrideFormat[16]; -} __attribute__((packed)); - -/* Encoder related structures */ - -/* A/V Mux Selector */ -struct tmComResSelDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 unitid; - u8 nrinpins; - u8 sourceid; -} __attribute__((packed)); - -/* A/V Audio processor definitions */ -struct tmComResProcDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 unitid; - u8 sourceid; - u16 wreserved; - u8 controlsize; -} __attribute__((packed)); - -/* Video bitrate control message */ -#define EU_VIDEO_BIT_RATE_MODE_CONSTANT (0) -#define EU_VIDEO_BIT_RATE_MODE_VARIABLE_AVERAGE (1) -#define EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK (2) -struct tmComResEncVideoBitRate { - u8 ucVideoBitRateMode; - u32 dwVideoBitRate; - u32 dwVideoBitRatePeak; -} __attribute__((packed)); - -/* Video Encoder Aspect Ratio message */ -struct tmComResEncVideoInputAspectRatio { - u8 width; - u8 height; -} __attribute__((packed)); - -/* Video Encoder GOP IBP message */ -/* 1. IPPPPPPPPPPPPPP */ -/* 2. IBPBPBPBPBPBPBP */ -/* 3. IBBPBBPBBPBBP */ -#define SAA7164_ENCODER_DEFAULT_GOP_DIST (1) -#define SAA7164_ENCODER_DEFAULT_GOP_SIZE (15) -struct tmComResEncVideoGopStructure { - u8 ucGOPSize; /* GOP Size 12, 15 */ - u8 ucRefFrameDist; /* Reference Frame Distance */ -} __attribute__((packed)); - -/* Encoder processor definition */ -struct tmComResEncoderDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 unitid; - u8 vsourceid; - u8 asourceid; - u8 iunit; - u32 dwmControlCap; - u32 dwmProfileCap; - u32 dwmVidFormatCap; - u8 bmVidBitrateCap; - u16 wmVidResolutionsCap; - u16 wmVidFrmRateCap; - u32 dwmAudFormatCap; - u8 bmAudBitrateCap; -} __attribute__((packed)); - -/* Audio processor definition */ -struct tmComResAFeatureDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 unitid; - u8 sourceid; - u8 controlsize; -} __attribute__((packed)); - -/* Audio control messages */ -struct tmComResAudioDefaults { - u8 ucDecoderLevel; - u8 ucDecoderFM_Level; - u8 ucMonoLevel; - u8 ucNICAM_Level; - u8 ucSAP_Level; - u8 ucADC_Level; -} __attribute__((packed)); - -/* Audio bitrate control message */ -struct tmComResEncAudioBitRate { - u8 ucAudioBitRateMode; - u32 dwAudioBitRate; - u32 dwAudioBitRatePeak; -} __attribute__((packed)); - -/* Tuner / AV Decoder messages */ -struct tmComResTunerStandard { - u8 std; - u32 country; -} __attribute__((packed)); - -struct tmComResTunerStandardAuto { - u8 mode; -} __attribute__((packed)); - -/* EEPROM definition for PS stream types */ -struct tmComResPSFormatDescrHeader { - u8 len; - u8 type; - u8 subtype; - u8 bFormatIndex; - u16 wPacketLength; - u16 wPackLength; - u8 bPackDataType; -} __attribute__((packed)); - -/* VBI control structure */ -struct tmComResVBIFormatDescrHeader { - u8 len; - u8 type; - u8 subtype; /* VS_FORMAT_VBI */ - u8 bFormatIndex; - u32 VideoStandard; /* See KS_AnalogVideoStandard, NTSC = 1 */ - u8 StartLine; /* NTSC Start = 10 */ - u8 EndLine; /* NTSC = 21 */ - u8 FieldRate; /* 60 for NTSC */ - u8 bNumLines; /* Unsed - scheduled for removal */ -} __attribute__((packed)); - -struct tmComResProbeCommit { - u16 bmHint; - u8 bFormatIndex; - u8 bFrameIndex; -} __attribute__((packed)); - -struct tmComResDebugSetLevel { - u32 dwDebugLevel; -} __attribute__((packed)); - -struct tmComResDebugGetData { - u32 dwResult; - u8 ucDebugData[256]; -} __attribute__((packed)); - -struct tmFwInfoStruct { - u32 status; - u32 mode; - u32 devicespec; - u32 deviceinst; - u32 CPULoad; - u32 RemainHeap; - u32 CPUClock; - u32 RAMSpeed; -} __attribute__((packed)); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-vbi.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7164/saa7164-vbi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1384 +0,0 @@ -/* - * Driver for the NXP SAA7164 PCIe bridge - * - * Copyright (c) 2010 Steven Toth - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "saa7164.h" - -static struct saa7164_tvnorm saa7164_tvnorms[] = { - { - .name = "NTSC-M", - .id = V4L2_STD_NTSC_M, - }, { - .name = "NTSC-JP", - .id = V4L2_STD_NTSC_M_JP, - } -}; - -static const u32 saa7164_v4l2_ctrls[] = { - 0 -}; - -/* Take the encoder configuration from the port struct and - * flush it to the hardware. - */ -static void saa7164_vbi_configure(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - dprintk(DBGLVL_VBI, "%s()\n", __func__); - - port->vbi_params.width = port->width; - port->vbi_params.height = port->height; - port->vbi_params.is_50hz = - (port->encodernorm.id & V4L2_STD_625_50) != 0; - - /* Set up the DIF (enable it) for analog mode by default */ - saa7164_api_initialize_dif(port); - - /* Configure the correct video standard */ -#if 0 - saa7164_api_configure_dif(port, port->encodernorm.id); -#endif - -#if 0 - /* Ensure the audio decoder is correct configured */ - saa7164_api_set_audio_std(port); -#endif - dprintk(DBGLVL_VBI, "%s() ends\n", __func__); -} - -static int saa7164_vbi_buffers_dealloc(struct saa7164_port *port) -{ - struct list_head *c, *n, *p, *q, *l, *v; - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - struct saa7164_user_buffer *ubuf; - - /* Remove any allocated buffers */ - mutex_lock(&port->dmaqueue_lock); - - dprintk(DBGLVL_VBI, "%s(port=%d) dmaqueue\n", __func__, port->nr); - list_for_each_safe(c, n, &port->dmaqueue.list) { - buf = list_entry(c, struct saa7164_buffer, list); - list_del(c); - saa7164_buffer_dealloc(buf); - } - - dprintk(DBGLVL_VBI, "%s(port=%d) used\n", __func__, port->nr); - list_for_each_safe(p, q, &port->list_buf_used.list) { - ubuf = list_entry(p, struct saa7164_user_buffer, list); - list_del(p); - saa7164_buffer_dealloc_user(ubuf); - } - - dprintk(DBGLVL_VBI, "%s(port=%d) free\n", __func__, port->nr); - list_for_each_safe(l, v, &port->list_buf_free.list) { - ubuf = list_entry(l, struct saa7164_user_buffer, list); - list_del(l); - saa7164_buffer_dealloc_user(ubuf); - } - - mutex_unlock(&port->dmaqueue_lock); - dprintk(DBGLVL_VBI, "%s(port=%d) done\n", __func__, port->nr); - - return 0; -} - -/* Dynamic buffer switch at vbi start time */ -static int saa7164_vbi_buffers_alloc(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - struct saa7164_user_buffer *ubuf; - struct tmHWStreamParameters *params = &port->hw_streamingparams; - int result = -ENODEV, i; - int len = 0; - - dprintk(DBGLVL_VBI, "%s()\n", __func__); - - /* TODO: NTSC SPECIFIC */ - /* Init and establish defaults */ - params->samplesperline = 1440; - params->numberoflines = 12; - params->numberoflines = 18; - params->pitch = 1600; - params->pitch = 1440; - params->numpagetables = 2 + - ((params->numberoflines * params->pitch) / PAGE_SIZE); - params->bitspersample = 8; - params->linethreshold = 0; - params->pagetablelistvirt = NULL; - params->pagetablelistphys = NULL; - params->numpagetableentries = port->hwcfg.buffercount; - - /* Allocate the PCI resources, buffers (hard) */ - for (i = 0; i < port->hwcfg.buffercount; i++) { - buf = saa7164_buffer_alloc(port, - params->numberoflines * - params->pitch); - - if (!buf) { - printk(KERN_ERR "%s() failed " - "(errno = %d), unable to allocate buffer\n", - __func__, result); - result = -ENOMEM; - goto failed; - } else { - - mutex_lock(&port->dmaqueue_lock); - list_add_tail(&buf->list, &port->dmaqueue.list); - mutex_unlock(&port->dmaqueue_lock); - - } - } - - /* Allocate some kenrel kernel buffers for copying - * to userpsace. - */ - len = params->numberoflines * params->pitch; - - if (vbi_buffers < 16) - vbi_buffers = 16; - if (vbi_buffers > 512) - vbi_buffers = 512; - - for (i = 0; i < vbi_buffers; i++) { - - ubuf = saa7164_buffer_alloc_user(dev, len); - if (ubuf) { - mutex_lock(&port->dmaqueue_lock); - list_add_tail(&ubuf->list, &port->list_buf_free.list); - mutex_unlock(&port->dmaqueue_lock); - } - - } - - result = 0; - -failed: - return result; -} - - -static int saa7164_vbi_initialize(struct saa7164_port *port) -{ - saa7164_vbi_configure(port); - return 0; -} - -/* -- V4L2 --------------------------------------------------------- */ -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - unsigned int i; - - dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)*id); - - for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) { - if (*id & saa7164_tvnorms[i].id) - break; - } - if (i == ARRAY_SIZE(saa7164_tvnorms)) - return -EINVAL; - - port->encodernorm = saa7164_tvnorms[i]; - - /* Update the audio decoder while is not running in - * auto detect mode. - */ - saa7164_api_set_audio_std(port); - - dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)*id); - - return 0; -} - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - int n; - - char *inputs[] = { "tuner", "composite", "svideo", "aux", - "composite 2", "svideo 2", "aux 2" }; - - if (i->index >= 7) - return -EINVAL; - - strcpy(i->name, inputs[i->index]); - - if (i->index == 0) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - - for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++) - i->std |= saa7164_tvnorms[n].id; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - if (saa7164_api_get_videomux(port) != SAA_OK) - return -EIO; - - *i = (port->mux_input - 1); - - dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, *i); - - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, i); - - if (i >= 7) - return -EINVAL; - - port->mux_input = i + 1; - - if (saa7164_api_set_videomux(port) != SAA_OK) - return -EIO; - - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "tuner"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO; - - dprintk(DBGLVL_VBI, "VIDIOC_G_TUNER: tuner type %d\n", t->type); - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - /* Update the A/V core */ - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = port->freq; - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - struct saa7164_port *tsport; - struct dvb_frontend *fe; - - /* TODO: Pull this for the std */ - struct analog_parameters params = { - .mode = V4L2_TUNER_ANALOG_TV, - .audmode = V4L2_TUNER_MODE_STEREO, - .std = port->encodernorm.id, - .frequency = f->frequency - }; - - /* Stop the encoder */ - dprintk(DBGLVL_VBI, "%s() frequency=%d tuner=%d\n", __func__, - f->frequency, f->tuner); - - if (f->tuner != 0) - return -EINVAL; - - if (f->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - - port->freq = f->frequency; - - /* Update the hardware */ - if (port->nr == SAA7164_PORT_VBI1) - tsport = &dev->ports[SAA7164_PORT_TS1]; - else - if (port->nr == SAA7164_PORT_VBI2) - tsport = &dev->ports[SAA7164_PORT_TS2]; - else - BUG(); - - fe = tsport->dvb.frontend; - - if (fe && fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, ¶ms); - else - printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); - - saa7164_vbi_initialize(port); - - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__, - ctl->id, ctl->value); - - switch (ctl->id) { - case V4L2_CID_BRIGHTNESS: - ctl->value = port->ctl_brightness; - break; - case V4L2_CID_CONTRAST: - ctl->value = port->ctl_contrast; - break; - case V4L2_CID_SATURATION: - ctl->value = port->ctl_saturation; - break; - case V4L2_CID_HUE: - ctl->value = port->ctl_hue; - break; - case V4L2_CID_SHARPNESS: - ctl->value = port->ctl_sharpness; - break; - case V4L2_CID_AUDIO_VOLUME: - ctl->value = port->ctl_volume; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - int ret = 0; - - dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__, - ctl->id, ctl->value); - - switch (ctl->id) { - case V4L2_CID_BRIGHTNESS: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_brightness = ctl->value; - saa7164_api_set_usercontrol(port, - PU_BRIGHTNESS_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_CONTRAST: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_contrast = ctl->value; - saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_SATURATION: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_saturation = ctl->value; - saa7164_api_set_usercontrol(port, - PU_SATURATION_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_HUE: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_hue = ctl->value; - saa7164_api_set_usercontrol(port, PU_HUE_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_SHARPNESS: - if ((ctl->value >= 0) && (ctl->value <= 255)) { - port->ctl_sharpness = ctl->value; - saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL); - } else - ret = -EINVAL; - break; - case V4L2_CID_AUDIO_VOLUME: - if ((ctl->value >= -83) && (ctl->value <= 24)) { - port->ctl_volume = ctl->value; - saa7164_api_set_audio_volume(port, port->ctl_volume); - } else - ret = -EINVAL; - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int saa7164_get_ctrl(struct saa7164_port *port, - struct v4l2_ext_control *ctrl) -{ - struct saa7164_vbi_params *params = &port->vbi_params; - - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - ctrl->value = params->stream_type; - break; - case V4L2_CID_MPEG_AUDIO_MUTE: - ctrl->value = params->ctl_mute; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - ctrl->value = params->ctl_aspect; - break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - ctrl->value = params->refdist; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - ctrl->value = params->gop_size; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = saa7164_get_ctrl(port, ctrl); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - - } - - return -EINVAL; -} - -static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3) -{ - int ret = -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) || - (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)) - ret = 0; - break; - case V4L2_CID_MPEG_AUDIO_MUTE: - if ((ctrl->value >= 0) && - (ctrl->value <= 1)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) && - (ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - if ((ctrl->value >= 0) && - (ctrl->value <= 255)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - if ((ctrl->value >= 1) && - (ctrl->value <= 3)) - ret = 0; - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int vidioc_try_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = saa7164_try_ctrl(ctrl, 0); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - } - - return -EINVAL; -} - -static int saa7164_set_ctrl(struct saa7164_port *port, - struct v4l2_ext_control *ctrl) -{ - struct saa7164_vbi_params *params = &port->vbi_params; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - params->stream_type = ctrl->value; - break; - case V4L2_CID_MPEG_AUDIO_MUTE: - params->ctl_mute = ctrl->value; - ret = saa7164_api_audio_mute(port, params->ctl_mute); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, - ret); - ret = -EIO; - } - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - params->ctl_aspect = ctrl->value; - ret = saa7164_api_set_aspect_ratio(port); - if (ret != SAA_OK) { - printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, - ret); - ret = -EIO; - } - break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - params->refdist = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - params->gop_size = ctrl->value; - break; - default: - return -EINVAL; - } - - /* TODO: Update the hardware */ - - return ret; -} - -static int vidioc_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = saa7164_try_ctrl(ctrl, 0); - if (err) { - ctrls->error_idx = i; - break; - } - err = saa7164_set_ctrl(port, ctrl); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - - } - - return -EINVAL; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - strcpy(cap->driver, dev->name); - strlcpy(cap->card, saa7164_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - - cap->capabilities = - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - 0; - - cap->capabilities |= V4L2_CAP_TUNER; - cap->version = 0; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index != 0) - return -EINVAL; - - strlcpy(f->description, "VBI", sizeof(f->description)); - f->pixelformat = V4L2_PIX_FMT_MPEG; - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - port->ts_packet_size * port->ts_packet_count; - f->fmt.pix.colorspace = 0; - f->fmt.pix.width = port->width; - f->fmt.pix.height = port->height; - - dprintk(DBGLVL_VBI, "VIDIOC_G_FMT: w: %d, h: %d\n", - port->width, port->height); - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - port->ts_packet_size * port->ts_packet_count; - f->fmt.pix.colorspace = 0; - dprintk(DBGLVL_VBI, "VIDIOC_TRY_FMT: w: %d, h: %d\n", - port->width, port->height); - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - port->ts_packet_size * port->ts_packet_count; - f->fmt.pix.colorspace = 0; - - dprintk(DBGLVL_VBI, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", - f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); - - return 0; -} - -static int vidioc_log_status(struct file *file, void *priv) -{ - return 0; -} - -static int fill_queryctrl(struct saa7164_vbi_params *params, - struct v4l2_queryctrl *c) -{ - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128); - case V4L2_CID_SHARPNESS: - return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8); - case V4L2_CID_MPEG_AUDIO_MUTE: - return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(c, -83, 24, 1, 20); - case V4L2_CID_MPEG_STREAM_TYPE: - return v4l2_ctrl_query_fill(c, - V4L2_MPEG_STREAM_TYPE_MPEG2_PS, - V4L2_MPEG_STREAM_TYPE_MPEG2_TS, - 1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS); - case V4L2_CID_MPEG_VIDEO_ASPECT: - return v4l2_ctrl_query_fill(c, - V4L2_MPEG_VIDEO_ASPECT_1x1, - V4L2_MPEG_VIDEO_ASPECT_221x100, - 1, V4L2_MPEG_VIDEO_ASPECT_4x3); - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - return v4l2_ctrl_query_fill(c, 1, 255, 1, 15); - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - return v4l2_ctrl_query_fill(c, - 1, 3, 1, 1); - default: - return -EINVAL; - } -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct saa7164_vbi_fh *fh = priv; - struct saa7164_port *port = fh->port; - int i, next; - u32 id = c->id; - - memset(c, 0, sizeof(*c)); - - next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL); - c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL; - - for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) { - if (next) { - if (c->id < saa7164_v4l2_ctrls[i]) - c->id = saa7164_v4l2_ctrls[i]; - else - continue; - } - - if (c->id == saa7164_v4l2_ctrls[i]) - return fill_queryctrl(&port->vbi_params, c); - - if (c->id < saa7164_v4l2_ctrls[i]) - break; - } - - return -EINVAL; -} - -static int saa7164_vbi_stop_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); - if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", - __func__, ret); - ret = -EIO; - } else { - dprintk(DBGLVL_VBI, "%s() Stopped\n", __func__); - ret = 0; - } - - return ret; -} - -static int saa7164_vbi_acquire_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); - if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", - __func__, ret); - ret = -EIO; - } else { - dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__); - ret = 0; - } - - return ret; -} - -static int saa7164_vbi_pause_port(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int ret; - - ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); - if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", - __func__, ret); - ret = -EIO; - } else { - dprintk(DBGLVL_VBI, "%s() Paused\n", __func__); - ret = 0; - } - - return ret; -} - -/* Firmware is very windows centric, meaning you have to transition - * the part through AVStream / KS Windows stages, forwards or backwards. - * States are: stopped, acquired (h/w), paused, started. - * We have to leave here will all of the soft buffers on the free list, - * else the cfg_post() func won't have soft buffers to correctly configure. - */ -static int saa7164_vbi_stop_streaming(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf; - struct saa7164_user_buffer *ubuf; - struct list_head *c, *n; - int ret; - - dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); - - ret = saa7164_vbi_pause_port(port); - ret = saa7164_vbi_acquire_port(port); - ret = saa7164_vbi_stop_port(port); - - dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__, - port->nr); - - /* Reset the state of any allocated buffer resources */ - mutex_lock(&port->dmaqueue_lock); - - /* Reset the hard and soft buffer state */ - list_for_each_safe(c, n, &port->dmaqueue.list) { - buf = list_entry(c, struct saa7164_buffer, list); - buf->flags = SAA7164_BUFFER_FREE; - buf->pos = 0; - } - - list_for_each_safe(c, n, &port->list_buf_used.list) { - ubuf = list_entry(c, struct saa7164_user_buffer, list); - ubuf->pos = 0; - list_move_tail(&ubuf->list, &port->list_buf_free.list); - } - - mutex_unlock(&port->dmaqueue_lock); - - /* Free any allocated resources */ - saa7164_vbi_buffers_dealloc(port); - - dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr); - - return ret; -} - -static int saa7164_vbi_start_streaming(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int result, ret = 0; - - dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); - - port->done_first_interrupt = 0; - - /* allocate all of the PCIe DMA buffer resources on the fly, - * allowing switching between TS and PS payloads without - * requiring a complete driver reload. - */ - saa7164_vbi_buffers_alloc(port); - - /* Configure the encoder with any cache values */ -#if 0 - saa7164_api_set_encoder(port); - saa7164_api_get_encoder(port); -#endif - - /* Place the empty buffers on the hardware */ - saa7164_buffer_cfg_port(port); - - /* Negotiate format */ - if (saa7164_api_set_vbi_format(port) != SAA_OK) { - printk(KERN_ERR "%s() No supported VBI format\n", __func__); - ret = -EIO; - goto out; - } - - /* Acquire the hardware */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", - __func__, result); - - ret = -EIO; - goto out; - } else - dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__); - - /* Pause the hardware */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", - __func__, result); - - /* Stop the hardware, regardless */ - result = saa7164_vbi_stop_port(port); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause/forced stop transition " - "failed, res = 0x%x\n", __func__, result); - } - - ret = -EIO; - goto out; - } else - dprintk(DBGLVL_VBI, "%s() Paused\n", __func__); - - /* Start the hardware */ - result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", - __func__, result); - - /* Stop the hardware, regardless */ - result = saa7164_vbi_acquire_port(port); - result = saa7164_vbi_stop_port(port); - if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() run/forced stop transition " - "failed, res = 0x%x\n", __func__, result); - } - - ret = -EIO; - } else - dprintk(DBGLVL_VBI, "%s() Running\n", __func__); - -out: - return ret; -} - -int saa7164_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - /* ntsc */ - f->fmt.vbi.samples_per_line = 1600; - f->fmt.vbi.samples_per_line = 1440; - f->fmt.vbi.sampling_rate = 27000000; - f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 0; - f->fmt.vbi.flags = 0; - f->fmt.vbi.start[0] = 10; - f->fmt.vbi.count[0] = 18; - f->fmt.vbi.start[1] = 263 + 10 + 1; - f->fmt.vbi.count[1] = 18; - return 0; -} - -static int fops_open(struct file *file) -{ - struct saa7164_dev *dev; - struct saa7164_port *port; - struct saa7164_vbi_fh *fh; - - port = (struct saa7164_port *)video_get_drvdata(video_devdata(file)); - if (!port) - return -ENODEV; - - dev = port->dev; - - dprintk(DBGLVL_VBI, "%s()\n", __func__); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - file->private_data = fh; - fh->port = port; - - return 0; -} - -static int fops_release(struct file *file) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_VBI, "%s()\n", __func__); - - /* Shut device down on last close */ - if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { - if (atomic_dec_return(&port->v4l_reader_count) == 0) { - /* stop vbi capture then cancel buffers */ - saa7164_vbi_stop_streaming(port); - } - } - - file->private_data = NULL; - kfree(fh); - - return 0; -} - -struct saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port) -{ - struct saa7164_user_buffer *ubuf = NULL; - struct saa7164_dev *dev = port->dev; - u32 crc; - - mutex_lock(&port->dmaqueue_lock); - if (!list_empty(&port->list_buf_used.list)) { - ubuf = list_first_entry(&port->list_buf_used.list, - struct saa7164_user_buffer, list); - - if (crc_checking) { - crc = crc32(0, ubuf->data, ubuf->actual_size); - if (crc != ubuf->crc) { - printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n", - __func__, - ubuf, ubuf->crc, crc); - } - } - - } - mutex_unlock(&port->dmaqueue_lock); - - dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf); - - return ubuf; -} - -static ssize_t fops_read(struct file *file, char __user *buffer, - size_t count, loff_t *pos) -{ - struct saa7164_vbi_fh *fh = file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_user_buffer *ubuf = NULL; - struct saa7164_dev *dev = port->dev; - int ret = 0; - int rem, cnt; - u8 *p; - - port->last_read_msecs_diff = port->last_read_msecs; - port->last_read_msecs = jiffies_to_msecs(jiffies); - port->last_read_msecs_diff = port->last_read_msecs - - port->last_read_msecs_diff; - - saa7164_histogram_update(&port->read_interval, - port->last_read_msecs_diff); - - if (*pos) { - printk(KERN_ERR "%s() ESPIPE\n", __func__); - return -ESPIPE; - } - - if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { - if (atomic_inc_return(&port->v4l_reader_count) == 1) { - - if (saa7164_vbi_initialize(port) < 0) { - printk(KERN_ERR "%s() EINVAL\n", __func__); - return -EINVAL; - } - - saa7164_vbi_start_streaming(port); - msleep(200); - } - } - - /* blocking wait for buffer */ - if ((file->f_flags & O_NONBLOCK) == 0) { - if (wait_event_interruptible(port->wait_read, - saa7164_vbi_next_buf(port))) { - printk(KERN_ERR "%s() ERESTARTSYS\n", __func__); - return -ERESTARTSYS; - } - } - - /* Pull the first buffer from the used list */ - ubuf = saa7164_vbi_next_buf(port); - - while ((count > 0) && ubuf) { - - /* set remaining bytes to copy */ - rem = ubuf->actual_size - ubuf->pos; - cnt = rem > count ? count : rem; - - p = ubuf->data + ubuf->pos; - - dprintk(DBGLVL_VBI, - "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n", - __func__, (int)count, cnt, rem, ubuf, ubuf->pos); - - if (copy_to_user(buffer, p, cnt)) { - printk(KERN_ERR "%s() copy_to_user failed\n", __func__); - if (!ret) { - printk(KERN_ERR "%s() EFAULT\n", __func__); - ret = -EFAULT; - } - goto err; - } - - ubuf->pos += cnt; - count -= cnt; - buffer += cnt; - ret += cnt; - - if (ubuf->pos > ubuf->actual_size) - printk(KERN_ERR "read() pos > actual, huh?\n"); - - if (ubuf->pos == ubuf->actual_size) { - - /* finished with current buffer, take next buffer */ - - /* Requeue the buffer on the free list */ - ubuf->pos = 0; - - mutex_lock(&port->dmaqueue_lock); - list_move_tail(&ubuf->list, &port->list_buf_free.list); - mutex_unlock(&port->dmaqueue_lock); - - /* Dequeue next */ - if ((file->f_flags & O_NONBLOCK) == 0) { - if (wait_event_interruptible(port->wait_read, - saa7164_vbi_next_buf(port))) { - break; - } - } - ubuf = saa7164_vbi_next_buf(port); - } - } -err: - if (!ret && !ubuf) { - printk(KERN_ERR "%s() EAGAIN\n", __func__); - ret = -EAGAIN; - } - - return ret; -} - -static unsigned int fops_poll(struct file *file, poll_table *wait) -{ - struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data; - struct saa7164_port *port = fh->port; - struct saa7164_user_buffer *ubuf; - unsigned int mask = 0; - - port->last_poll_msecs_diff = port->last_poll_msecs; - port->last_poll_msecs = jiffies_to_msecs(jiffies); - port->last_poll_msecs_diff = port->last_poll_msecs - - port->last_poll_msecs_diff; - - saa7164_histogram_update(&port->poll_interval, - port->last_poll_msecs_diff); - - if (!video_is_registered(port->v4l_device)) - return -EIO; - - if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { - if (atomic_inc_return(&port->v4l_reader_count) == 1) { - if (saa7164_vbi_initialize(port) < 0) - return -EINVAL; - saa7164_vbi_start_streaming(port); - msleep(200); - } - } - - /* blocking wait for buffer */ - if ((file->f_flags & O_NONBLOCK) == 0) { - if (wait_event_interruptible(port->wait_read, - saa7164_vbi_next_buf(port))) { - return -ERESTARTSYS; - } - } - - /* Pull the first buffer from the used list */ - ubuf = list_first_entry(&port->list_buf_used.list, - struct saa7164_user_buffer, list); - - if (ubuf) - mask |= POLLIN | POLLRDNORM; - - return mask; -} -static const struct v4l2_file_operations vbi_fops = { - .owner = THIS_MODULE, - .open = fops_open, - .release = fops_release, - .read = fops_read, - .poll = fops_poll, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops vbi_ioctl_ops = { - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, - .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, -#if 0 - .vidioc_g_chip_ident = saa7164_g_chip_ident, -#endif -#ifdef CONFIG_VIDEO_ADV_DEBUG -#if 0 - .vidioc_g_register = saa7164_g_register, - .vidioc_s_register = saa7164_s_register, -#endif -#endif - .vidioc_g_fmt_vbi_cap = saa7164_vbi_fmt, - .vidioc_try_fmt_vbi_cap = saa7164_vbi_fmt, - .vidioc_s_fmt_vbi_cap = saa7164_vbi_fmt, -}; - -static struct video_device saa7164_vbi_template = { - .name = "saa7164", - .fops = &vbi_fops, - .ioctl_ops = &vbi_ioctl_ops, - .minor = -1, - .tvnorms = SAA7164_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; - -static struct video_device *saa7164_vbi_alloc( - struct saa7164_port *port, - struct pci_dev *pci, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_VBI, "%s()\n", __func__); - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - - *vfd = *template; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, - type, saa7164_boards[dev->board].name); - - vfd->parent = &pci->dev; - vfd->release = video_device_release; - return vfd; -} - -int saa7164_vbi_register(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - int result = -ENODEV; - - dprintk(DBGLVL_VBI, "%s()\n", __func__); - - if (port->type != SAA7164_MPEG_VBI) - BUG(); - - /* Sanity check that the PCI configuration space is active */ - if (port->hwcfg.BARLocation == 0) { - printk(KERN_ERR "%s() failed " - "(errno = %d), NO PCI configuration\n", - __func__, result); - result = -ENOMEM; - goto failed; - } - - /* Establish VBI defaults here */ - - /* Allocate and register the video device node */ - port->v4l_device = saa7164_vbi_alloc(port, - dev->pci, &saa7164_vbi_template, "vbi"); - - if (!port->v4l_device) { - printk(KERN_INFO "%s: can't allocate vbi device\n", - dev->name); - result = -ENOMEM; - goto failed; - } - - video_set_drvdata(port->v4l_device, port); - result = video_register_device(port->v4l_device, - VFL_TYPE_VBI, -1); - if (result < 0) { - printk(KERN_INFO "%s: can't register vbi device\n", - dev->name); - /* TODO: We're going to leak here if we don't dealloc - The buffers above. The unreg function can't deal wit it. - */ - goto failed; - } - - printk(KERN_INFO "%s: registered device vbi%d [vbi]\n", - dev->name, port->v4l_device->num); - - /* Configure the hardware defaults */ - - result = 0; -failed: - return result; -} - -void saa7164_vbi_unregister(struct saa7164_port *port) -{ - struct saa7164_dev *dev = port->dev; - - dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr); - - if (port->type != SAA7164_MPEG_VBI) - BUG(); - - if (port->v4l_device) { - if (port->v4l_device->minor != -1) - video_unregister_device(port->v4l_device); - else - video_device_release(port->v4l_device); - - port->v4l_device = NULL; - } - -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa717x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa717x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa717x.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa717x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1389 +0,0 @@ -/* - * saa717x - Philips SAA717xHL video decoder driver - * - * Based on the saa7115 driver - * - * Changes by Ohta Kyuma - * - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004) - * - * Changes by T.Adachi (tadachi@tadachi-net.com) - * - support audio, video scaler etc, and checked the initialize sequence. - * - * Cleaned up by Hans Verkuil - * - * Note: this is a reversed engineered driver based on captures from - * the I2C bus under Windows. This chip is very similar to the saa7134, - * though. Unfortunately, this driver is currently only working for NTSC. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver"); -MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -/* - * Generic i2c probe - * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' - */ - -struct saa717x_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - v4l2_std_id std; - int input; - int enable; - int radio; - int playback; - int audio; - int tuner_audio_mode; - int audio_main_mute; - int audio_main_vol_r; - int audio_main_vol_l; - u16 audio_main_bass; - u16 audio_main_treble; - u16 audio_main_volume; - u16 audio_main_balance; - int audio_input; -}; - -static inline struct saa717x_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa717x_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct saa717x_state, hdl)->sd; -} - -/* ----------------------------------------------------------------------- */ - -/* for audio mode */ -#define TUNER_AUDIO_MONO 0 /* LL */ -#define TUNER_AUDIO_STEREO 1 /* LR */ -#define TUNER_AUDIO_LANG1 2 /* LL */ -#define TUNER_AUDIO_LANG2 3 /* RR */ - -#define SAA717X_NTSC_WIDTH (704) -#define SAA717X_NTSC_HEIGHT (480) - -/* ----------------------------------------------------------------------- */ - -static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct i2c_adapter *adap = client->adapter; - int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488; - unsigned char mm1[6]; - struct i2c_msg msg; - - msg.flags = 0; - msg.addr = client->addr; - mm1[0] = (reg >> 8) & 0xff; - mm1[1] = reg & 0xff; - - if (fw_addr) { - mm1[4] = (value >> 16) & 0xff; - mm1[3] = (value >> 8) & 0xff; - mm1[2] = value & 0xff; - } else { - mm1[2] = value & 0xff; - } - msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */ - msg.buf = mm1; - v4l2_dbg(2, debug, sd, "wrote: reg 0x%03x=%08x\n", reg, value); - return i2c_transfer(adap, &msg, 1) == 1; -} - -static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data) -{ - while (data[0] || data[1]) { - saa717x_write(sd, data[0], data[1]); - data += 2; - } -} - -static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct i2c_adapter *adap = client->adapter; - int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528; - unsigned char mm1[2]; - unsigned char mm2[4] = { 0, 0, 0, 0 }; - struct i2c_msg msgs[2]; - u32 value; - - msgs[0].flags = 0; - msgs[1].flags = I2C_M_RD; - msgs[0].addr = msgs[1].addr = client->addr; - mm1[0] = (reg >> 8) & 0xff; - mm1[1] = reg & 0xff; - msgs[0].len = 2; - msgs[0].buf = mm1; - msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */ - msgs[1].buf = mm2; - i2c_transfer(adap, msgs, 2); - - if (fw_addr) - value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16); - else - value = mm2[0] & 0xff; - - v4l2_dbg(2, debug, sd, "read: reg 0x%03x=0x%08x\n", reg, value); - return value; -} - -/* ----------------------------------------------------------------------- */ - -static u32 reg_init_initialize[] = -{ - /* from linux driver */ - 0x101, 0x008, /* Increment delay */ - - 0x103, 0x000, /* Analog input control 2 */ - 0x104, 0x090, /* Analog input control 3 */ - 0x105, 0x090, /* Analog input control 4 */ - 0x106, 0x0eb, /* Horizontal sync start */ - 0x107, 0x0e0, /* Horizontal sync stop */ - 0x109, 0x055, /* Luminance control */ - - 0x10f, 0x02a, /* Chroma gain control */ - 0x110, 0x000, /* Chroma control 2 */ - - 0x114, 0x045, /* analog/ADC */ - - 0x118, 0x040, /* RAW data gain */ - 0x119, 0x080, /* RAW data offset */ - - 0x044, 0x000, /* VBI horizontal input window start (L) TASK A */ - 0x045, 0x000, /* VBI horizontal input window start (H) TASK A */ - 0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */ - 0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */ - - 0x049, 0x000, /* VBI vertical input window start (H) TASK A */ - - 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */ - 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */ - - 0x064, 0x080, /* Lumina brightness TASK A */ - 0x065, 0x040, /* Luminance contrast TASK A */ - 0x066, 0x040, /* Chroma saturation TASK A */ - /* 067H: Reserved */ - 0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */ - 0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */ - 0x06a, 0x000, /* VBI phase offset TASK A */ - - 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */ - 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */ - - 0x072, 0x000, /* Vertical filter mode TASK A */ - - 0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */ - 0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */ - 0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */ - 0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */ - - 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */ - - 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */ - 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */ - - 0x0a4, 0x080, /* Lumina brightness TASK B */ - 0x0a5, 0x040, /* Luminance contrast TASK B */ - 0x0a6, 0x040, /* Chroma saturation TASK B */ - /* 0A7H reserved */ - 0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */ - 0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */ - 0x0aa, 0x000, /* VBI phase offset TASK B */ - - 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */ - 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */ - - 0x0b2, 0x000, /* Vertical filter mode TASK B */ - - 0x00c, 0x000, /* Start point GREEN path */ - 0x00d, 0x000, /* Start point BLUE path */ - 0x00e, 0x000, /* Start point RED path */ - - 0x010, 0x010, /* GREEN path gamma curve --- */ - 0x011, 0x020, - 0x012, 0x030, - 0x013, 0x040, - 0x014, 0x050, - 0x015, 0x060, - 0x016, 0x070, - 0x017, 0x080, - 0x018, 0x090, - 0x019, 0x0a0, - 0x01a, 0x0b0, - 0x01b, 0x0c0, - 0x01c, 0x0d0, - 0x01d, 0x0e0, - 0x01e, 0x0f0, - 0x01f, 0x0ff, /* --- GREEN path gamma curve */ - - 0x020, 0x010, /* BLUE path gamma curve --- */ - 0x021, 0x020, - 0x022, 0x030, - 0x023, 0x040, - 0x024, 0x050, - 0x025, 0x060, - 0x026, 0x070, - 0x027, 0x080, - 0x028, 0x090, - 0x029, 0x0a0, - 0x02a, 0x0b0, - 0x02b, 0x0c0, - 0x02c, 0x0d0, - 0x02d, 0x0e0, - 0x02e, 0x0f0, - 0x02f, 0x0ff, /* --- BLUE path gamma curve */ - - 0x030, 0x010, /* RED path gamma curve --- */ - 0x031, 0x020, - 0x032, 0x030, - 0x033, 0x040, - 0x034, 0x050, - 0x035, 0x060, - 0x036, 0x070, - 0x037, 0x080, - 0x038, 0x090, - 0x039, 0x0a0, - 0x03a, 0x0b0, - 0x03b, 0x0c0, - 0x03c, 0x0d0, - 0x03d, 0x0e0, - 0x03e, 0x0f0, - 0x03f, 0x0ff, /* --- RED path gamma curve */ - - 0x109, 0x085, /* Luminance control */ - - /**** from app start ****/ - 0x584, 0x000, /* AGC gain control */ - 0x585, 0x000, /* Program count */ - 0x586, 0x003, /* Status reset */ - 0x588, 0x0ff, /* Number of audio samples (L) */ - 0x589, 0x00f, /* Number of audio samples (M) */ - 0x58a, 0x000, /* Number of audio samples (H) */ - 0x58b, 0x000, /* Audio select */ - 0x58c, 0x010, /* Audio channel assign1 */ - 0x58d, 0x032, /* Audio channel assign2 */ - 0x58e, 0x054, /* Audio channel assign3 */ - 0x58f, 0x023, /* Audio format */ - 0x590, 0x000, /* SIF control */ - - 0x595, 0x000, /* ?? */ - 0x596, 0x000, /* ?? */ - 0x597, 0x000, /* ?? */ - - 0x464, 0x00, /* Digital input crossbar1 */ - - 0x46c, 0xbbbb10, /* Digital output selection1-3 */ - 0x470, 0x101010, /* Digital output selection4-6 */ - - 0x478, 0x00, /* Sound feature control */ - - 0x474, 0x18, /* Softmute control */ - - 0x454, 0x0425b9, /* Sound Easy programming(reset) */ - 0x454, 0x042539, /* Sound Easy programming(reset) */ - - - /**** common setting( of DVD play, including scaler commands) ****/ - 0x042, 0x003, /* Data path configuration for VBI (TASK A) */ - - 0x082, 0x003, /* Data path configuration for VBI (TASK B) */ - - 0x108, 0x0f8, /* Sync control */ - 0x2a9, 0x0fd, /* ??? */ - 0x102, 0x089, /* select video input "mode 9" */ - 0x111, 0x000, /* Mode/delay control */ - - 0x10e, 0x00a, /* Chroma control 1 */ - - 0x594, 0x002, /* SIF, analog I/O select */ - - 0x454, 0x0425b9, /* Sound */ - 0x454, 0x042539, - - 0x111, 0x000, - 0x10e, 0x00a, - 0x464, 0x000, - 0x300, 0x000, - 0x301, 0x006, - 0x302, 0x000, - 0x303, 0x006, - 0x308, 0x040, - 0x309, 0x000, - 0x30a, 0x000, - 0x30b, 0x000, - 0x000, 0x002, - 0x001, 0x000, - 0x002, 0x000, - 0x003, 0x000, - 0x004, 0x033, - 0x040, 0x01d, - 0x041, 0x001, - 0x042, 0x004, - 0x043, 0x000, - 0x080, 0x01e, - 0x081, 0x001, - 0x082, 0x004, - 0x083, 0x000, - 0x190, 0x018, - 0x115, 0x000, - 0x116, 0x012, - 0x117, 0x018, - 0x04a, 0x011, - 0x08a, 0x011, - 0x04b, 0x000, - 0x08b, 0x000, - 0x048, 0x000, - 0x088, 0x000, - 0x04e, 0x012, - 0x08e, 0x012, - 0x058, 0x012, - 0x098, 0x012, - 0x059, 0x000, - 0x099, 0x000, - 0x05a, 0x003, - 0x09a, 0x003, - 0x05b, 0x001, - 0x09b, 0x001, - 0x054, 0x008, - 0x094, 0x008, - 0x055, 0x000, - 0x095, 0x000, - 0x056, 0x0c7, - 0x096, 0x0c7, - 0x057, 0x002, - 0x097, 0x002, - 0x0ff, 0x0ff, - 0x060, 0x001, - 0x0a0, 0x001, - 0x061, 0x000, - 0x0a1, 0x000, - 0x062, 0x000, - 0x0a2, 0x000, - 0x063, 0x000, - 0x0a3, 0x000, - 0x070, 0x000, - 0x0b0, 0x000, - 0x071, 0x004, - 0x0b1, 0x004, - 0x06c, 0x0e9, - 0x0ac, 0x0e9, - 0x06d, 0x003, - 0x0ad, 0x003, - 0x05c, 0x0d0, - 0x09c, 0x0d0, - 0x05d, 0x002, - 0x09d, 0x002, - 0x05e, 0x0f2, - 0x09e, 0x0f2, - 0x05f, 0x000, - 0x09f, 0x000, - 0x074, 0x000, - 0x0b4, 0x000, - 0x075, 0x000, - 0x0b5, 0x000, - 0x076, 0x000, - 0x0b6, 0x000, - 0x077, 0x000, - 0x0b7, 0x000, - 0x195, 0x008, - 0x0ff, 0x0ff, - 0x108, 0x0f8, - 0x111, 0x000, - 0x10e, 0x00a, - 0x2a9, 0x0fd, - 0x464, 0x001, - 0x454, 0x042135, - 0x598, 0x0e7, - 0x599, 0x07d, - 0x59a, 0x018, - 0x59c, 0x066, - 0x59d, 0x090, - 0x59e, 0x001, - 0x584, 0x000, - 0x585, 0x000, - 0x586, 0x003, - 0x588, 0x0ff, - 0x589, 0x00f, - 0x58a, 0x000, - 0x58b, 0x000, - 0x58c, 0x010, - 0x58d, 0x032, - 0x58e, 0x054, - 0x58f, 0x023, - 0x590, 0x000, - 0x595, 0x000, - 0x596, 0x000, - 0x597, 0x000, - 0x464, 0x000, - 0x46c, 0xbbbb10, - 0x470, 0x101010, - - - 0x478, 0x000, - 0x474, 0x018, - 0x454, 0x042135, - 0x598, 0x0e7, - 0x599, 0x07d, - 0x59a, 0x018, - 0x59c, 0x066, - 0x59d, 0x090, - 0x59e, 0x001, - 0x584, 0x000, - 0x585, 0x000, - 0x586, 0x003, - 0x588, 0x0ff, - 0x589, 0x00f, - 0x58a, 0x000, - 0x58b, 0x000, - 0x58c, 0x010, - 0x58d, 0x032, - 0x58e, 0x054, - 0x58f, 0x023, - 0x590, 0x000, - 0x595, 0x000, - 0x596, 0x000, - 0x597, 0x000, - 0x464, 0x000, - 0x46c, 0xbbbb10, - 0x470, 0x101010, - - 0x478, 0x000, - 0x474, 0x018, - 0x454, 0x042135, - 0x598, 0x0e7, - 0x599, 0x07d, - 0x59a, 0x018, - 0x59c, 0x066, - 0x59d, 0x090, - 0x59e, 0x001, - 0x584, 0x000, - 0x585, 0x000, - 0x586, 0x003, - 0x588, 0x0ff, - 0x589, 0x00f, - 0x58a, 0x000, - 0x58b, 0x000, - 0x58c, 0x010, - 0x58d, 0x032, - 0x58e, 0x054, - 0x58f, 0x023, - 0x590, 0x000, - 0x595, 0x000, - 0x596, 0x000, - 0x597, 0x000, - 0x464, 0x000, - 0x46c, 0xbbbb10, - 0x470, 0x101010, - 0x478, 0x000, - 0x474, 0x018, - 0x454, 0x042135, - 0x193, 0x000, - 0x300, 0x000, - 0x301, 0x006, - 0x302, 0x000, - 0x303, 0x006, - 0x308, 0x040, - 0x309, 0x000, - 0x30a, 0x000, - 0x30b, 0x000, - 0x000, 0x002, - 0x001, 0x000, - 0x002, 0x000, - 0x003, 0x000, - 0x004, 0x033, - 0x040, 0x01d, - 0x041, 0x001, - 0x042, 0x004, - 0x043, 0x000, - 0x080, 0x01e, - 0x081, 0x001, - 0x082, 0x004, - 0x083, 0x000, - 0x190, 0x018, - 0x115, 0x000, - 0x116, 0x012, - 0x117, 0x018, - 0x04a, 0x011, - 0x08a, 0x011, - 0x04b, 0x000, - 0x08b, 0x000, - 0x048, 0x000, - 0x088, 0x000, - 0x04e, 0x012, - 0x08e, 0x012, - 0x058, 0x012, - 0x098, 0x012, - 0x059, 0x000, - 0x099, 0x000, - 0x05a, 0x003, - 0x09a, 0x003, - 0x05b, 0x001, - 0x09b, 0x001, - 0x054, 0x008, - 0x094, 0x008, - 0x055, 0x000, - 0x095, 0x000, - 0x056, 0x0c7, - 0x096, 0x0c7, - 0x057, 0x002, - 0x097, 0x002, - 0x060, 0x001, - 0x0a0, 0x001, - 0x061, 0x000, - 0x0a1, 0x000, - 0x062, 0x000, - 0x0a2, 0x000, - 0x063, 0x000, - 0x0a3, 0x000, - 0x070, 0x000, - 0x0b0, 0x000, - 0x071, 0x004, - 0x0b1, 0x004, - 0x06c, 0x0e9, - 0x0ac, 0x0e9, - 0x06d, 0x003, - 0x0ad, 0x003, - 0x05c, 0x0d0, - 0x09c, 0x0d0, - 0x05d, 0x002, - 0x09d, 0x002, - 0x05e, 0x0f2, - 0x09e, 0x0f2, - 0x05f, 0x000, - 0x09f, 0x000, - 0x074, 0x000, - 0x0b4, 0x000, - 0x075, 0x000, - 0x0b5, 0x000, - 0x076, 0x000, - 0x0b6, 0x000, - 0x077, 0x000, - 0x0b7, 0x000, - 0x195, 0x008, - 0x598, 0x0e7, - 0x599, 0x07d, - 0x59a, 0x018, - 0x59c, 0x066, - 0x59d, 0x090, - 0x59e, 0x001, - 0x584, 0x000, - 0x585, 0x000, - 0x586, 0x003, - 0x588, 0x0ff, - 0x589, 0x00f, - 0x58a, 0x000, - 0x58b, 0x000, - 0x58c, 0x010, - 0x58d, 0x032, - 0x58e, 0x054, - 0x58f, 0x023, - 0x590, 0x000, - 0x595, 0x000, - 0x596, 0x000, - 0x597, 0x000, - 0x464, 0x000, - 0x46c, 0xbbbb10, - 0x470, 0x101010, - 0x478, 0x000, - 0x474, 0x018, - 0x454, 0x042135, - 0x193, 0x0a6, - 0x108, 0x0f8, - 0x042, 0x003, - 0x082, 0x003, - 0x454, 0x0425b9, - 0x454, 0x042539, - 0x193, 0x000, - 0x193, 0x0a6, - 0x464, 0x000, - - 0, 0 -}; - -/* Tuner */ -static u32 reg_init_tuner_input[] = { - 0x108, 0x0f8, /* Sync control */ - 0x111, 0x000, /* Mode/delay control */ - 0x10e, 0x00a, /* Chroma control 1 */ - 0, 0 -}; - -/* Composite */ -static u32 reg_init_composite_input[] = { - 0x108, 0x0e8, /* Sync control */ - 0x111, 0x000, /* Mode/delay control */ - 0x10e, 0x04a, /* Chroma control 1 */ - 0, 0 -}; - -/* S-Video */ -static u32 reg_init_svideo_input[] = { - 0x108, 0x0e8, /* Sync control */ - 0x111, 0x000, /* Mode/delay control */ - 0x10e, 0x04a, /* Chroma control 1 */ - 0, 0 -}; - -static u32 reg_set_audio_template[4][2] = -{ - { /* for MONO - tadachi 6/29 DMA audio output select? - Register 0x46c - 7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1 - 0: MAIN left, 1: MAIN right - 2: AUX1 left, 3: AUX1 right - 4: AUX2 left, 5: AUX2 right - 6: DPL left, 7: DPL right - 8: DPL center, 9: DPL surround - A: monitor output, B: digital sense */ - 0xbbbb00, - - /* tadachi 6/29 DAC and I2S output select? - Register 0x470 - 7-4:DAC right ch. 3-0:DAC left ch. - I2S1 right,left I2S2 right,left */ - 0x00, - }, - { /* for STEREO */ - 0xbbbb10, 0x101010, - }, - { /* for LANG1 */ - 0xbbbb00, 0x00, - }, - { /* for LANG2/SAP */ - 0xbbbb11, 0x111111, - } -}; - - -/* Get detected audio flags (from saa7134 driver) */ -static void get_inf_dev_status(struct v4l2_subdev *sd, - int *dual_flag, int *stereo_flag) -{ - u32 reg_data3; - - static char *stdres[0x20] = { - [0x00] = "no standard detected", - [0x01] = "B/G (in progress)", - [0x02] = "D/K (in progress)", - [0x03] = "M (in progress)", - - [0x04] = "B/G A2", - [0x05] = "B/G NICAM", - [0x06] = "D/K A2 (1)", - [0x07] = "D/K A2 (2)", - [0x08] = "D/K A2 (3)", - [0x09] = "D/K NICAM", - [0x0a] = "L NICAM", - [0x0b] = "I NICAM", - - [0x0c] = "M Korea", - [0x0d] = "M BTSC ", - [0x0e] = "M EIAJ", - - [0x0f] = "FM radio / IF 10.7 / 50 deemp", - [0x10] = "FM radio / IF 10.7 / 75 deemp", - [0x11] = "FM radio / IF sel / 50 deemp", - [0x12] = "FM radio / IF sel / 75 deemp", - - [0x13 ... 0x1e] = "unknown", - [0x1f] = "??? [in progress]", - }; - - - *dual_flag = *stereo_flag = 0; - - /* (demdec status: 0x528) */ - - /* read current status */ - reg_data3 = saa717x_read(sd, 0x0528); - - v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n", - reg_data3, stdres[reg_data3 & 0x1f], - (reg_data3 & 0x000020) ? ",stereo" : "", - (reg_data3 & 0x000040) ? ",dual" : ""); - v4l2_dbg(1, debug, sd, "detailed status: " - "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n", - (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "", - (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "", - (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "", - (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "", - - (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "", - (reg_data3 & 0x001000) ? " SAP carrier " : "", - (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "", - (reg_data3 & 0x004000) ? " SAP noise mute " : "", - (reg_data3 & 0x008000) ? " VDSP " : "", - - (reg_data3 & 0x010000) ? " NICST " : "", - (reg_data3 & 0x020000) ? " NICDU " : "", - (reg_data3 & 0x040000) ? " NICAM muted " : "", - (reg_data3 & 0x080000) ? " NICAM reserve sound " : "", - - (reg_data3 & 0x100000) ? " init done " : ""); - - if (reg_data3 & 0x000220) { - v4l2_dbg(1, debug, sd, "ST!!!\n"); - *stereo_flag = 1; - } - - if (reg_data3 & 0x000140) { - v4l2_dbg(1, debug, sd, "DUAL!!!\n"); - *dual_flag = 1; - } -} - -/* regs write to set audio mode */ -static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode) -{ - v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n", - audio_mode); - - saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]); - saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]); -} - -/* write regs to set audio volume, bass and treble */ -static int set_audio_regs(struct v4l2_subdev *sd, - struct saa717x_state *decoder) -{ - u8 mute = 0xac; /* -84 dB */ - u32 val; - unsigned int work_l, work_r; - - /* set SIF analog I/O select */ - saa717x_write(sd, 0x0594, decoder->audio_input); - v4l2_dbg(1, debug, sd, "set audio input %d\n", - decoder->audio_input); - - /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */ - work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768; - work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768; - decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40; - decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40; - - /* set main volume */ - /* main volume L[7-0],R[7-0],0x00 24=24dB,-83dB, -84(mute) */ - /* def:0dB->6dB(MPG600GR) */ - /* if mute is on, set mute */ - if (decoder->audio_main_mute) { - val = mute | (mute << 8); - } else { - val = (u8)decoder->audio_main_vol_l | - ((u8)decoder->audio_main_vol_r << 8); - } - - saa717x_write(sd, 0x480, val); - - /* set bass and treble */ - val = decoder->audio_main_bass & 0x1f; - val |= (decoder->audio_main_treble & 0x1f) << 5; - saa717x_write(sd, 0x488, val); - return 0; -} - -/********** scaling staff ***********/ -static void set_h_prescale(struct v4l2_subdev *sd, - int task, int prescale) -{ - static const struct { - int xpsc; - int xacl; - int xc2_1; - int xdcg; - int vpfy; - } vals[] = { - /* XPSC XACL XC2_1 XDCG VPFY */ - { 1, 0, 0, 0, 0 }, - { 2, 2, 1, 2, 2 }, - { 3, 4, 1, 3, 2 }, - { 4, 8, 1, 4, 2 }, - { 5, 8, 1, 4, 2 }, - { 6, 8, 1, 4, 3 }, - { 7, 8, 1, 4, 3 }, - { 8, 15, 0, 4, 3 }, - { 9, 15, 0, 4, 3 }, - { 10, 16, 1, 5, 3 }, - }; - static const int count = ARRAY_SIZE(vals); - int i, task_shift; - - task_shift = task * 0x40; - for (i = 0; i < count; i++) - if (vals[i].xpsc == prescale) - break; - if (i == count) - return; - - /* horizonal prescaling */ - saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc); - /* accumulation length */ - saa717x_write(sd, 0x61 + task_shift, vals[i].xacl); - /* level control */ - saa717x_write(sd, 0x62 + task_shift, - (vals[i].xc2_1 << 3) | vals[i].xdcg); - /*FIR prefilter control */ - saa717x_write(sd, 0x63 + task_shift, - (vals[i].vpfy << 2) | vals[i].vpfy); -} - -/********** scaling staff ***********/ -static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale) -{ - int task_shift; - - task_shift = task * 0x40; - /* Vertical scaling ratio (LOW) */ - saa717x_write(sd, 0x70 + task_shift, yscale & 0xff); - /* Vertical scaling ratio (HI) */ - saa717x_write(sd, 0x71 + task_shift, yscale >> 8); -} - -static int saa717x_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct saa717x_state *state = to_state(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - saa717x_write(sd, 0x10a, ctrl->val); - return 0; - - case V4L2_CID_CONTRAST: - saa717x_write(sd, 0x10b, ctrl->val); - return 0; - - case V4L2_CID_SATURATION: - saa717x_write(sd, 0x10c, ctrl->val); - return 0; - - case V4L2_CID_HUE: - saa717x_write(sd, 0x10d, ctrl->val); - return 0; - - case V4L2_CID_AUDIO_MUTE: - state->audio_main_mute = ctrl->val; - break; - - case V4L2_CID_AUDIO_VOLUME: - state->audio_main_volume = ctrl->val; - break; - - case V4L2_CID_AUDIO_BALANCE: - state->audio_main_balance = ctrl->val; - break; - - case V4L2_CID_AUDIO_TREBLE: - state->audio_main_treble = ctrl->val; - break; - - case V4L2_CID_AUDIO_BASS: - state->audio_main_bass = ctrl->val; - break; - - default: - return 0; - } - set_audio_regs(sd, state); - return 0; -} - -static int saa717x_s_video_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct saa717x_state *decoder = to_state(sd); - int is_tuner = input & 0x80; /* tuner input flag */ - - input &= 0x7f; - - v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", input); - /* inputs from 0-9 are available*/ - /* saa717x have mode0-mode9 but mode5 is reserved. */ - if (input > 9 || input == 5) - return -EINVAL; - - if (decoder->input != input) { - int input_line = input; - - decoder->input = input_line; - v4l2_dbg(1, debug, sd, "now setting %s input %d\n", - input_line >= 6 ? "S-Video" : "Composite", - input_line); - - /* select mode */ - saa717x_write(sd, 0x102, - (saa717x_read(sd, 0x102) & 0xf0) | - input_line); - - /* bypass chrominance trap for modes 6..9 */ - saa717x_write(sd, 0x109, - (saa717x_read(sd, 0x109) & 0x7f) | - (input_line < 6 ? 0x0 : 0x80)); - - /* change audio_mode */ - if (is_tuner) { - /* tuner */ - set_audio_mode(sd, decoder->tuner_audio_mode); - } else { - /* Force to STEREO mode if Composite or - * S-Video were chosen */ - set_audio_mode(sd, TUNER_AUDIO_STEREO); - } - /* change initialize procedure (Composite/S-Video) */ - if (is_tuner) - saa717x_write_regs(sd, reg_init_tuner_input); - else if (input_line >= 6) - saa717x_write_regs(sd, reg_init_svideo_input); - else - saa717x_write_regs(sd, reg_init_composite_input); - } - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->val = saa717x_read(sd, reg->reg); - reg->size = 1; - return 0; -} - -static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 addr = reg->reg & 0xffff; - u8 val = reg->val & 0xff; - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - saa717x_write(sd, addr, val); - return 0; -} -#endif - -static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) -{ - int prescale, h_scale, v_scale; - - v4l2_dbg(1, debug, sd, "decoder set size\n"); - - if (fmt->code != V4L2_MBUS_FMT_FIXED) - return -EINVAL; - - /* FIXME need better bounds checking here */ - if (fmt->width < 1 || fmt->width > 1440) - return -EINVAL; - if (fmt->height < 1 || fmt->height > 960) - return -EINVAL; - - fmt->field = V4L2_FIELD_INTERLACED; - fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - - /* scaling setting */ - /* NTSC and interlace only */ - prescale = SAA717X_NTSC_WIDTH / fmt->width; - if (prescale == 0) - prescale = 1; - h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width; - /* interlace */ - v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height; - - /* Horizontal prescaling etc */ - set_h_prescale(sd, 0, prescale); - set_h_prescale(sd, 1, prescale); - - /* Horizontal scaling increment */ - /* TASK A */ - saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF)); - saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF)); - /* TASK B */ - saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF)); - saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF)); - - /* Vertical prescaling etc */ - set_v_scale(sd, 0, v_scale); - set_v_scale(sd, 1, v_scale); - - /* set video output size */ - /* video number of pixels at output */ - /* TASK A */ - saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF)); - saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF)); - /* TASK B */ - saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF)); - saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF)); - - /* video number of lines at output */ - /* TASK A */ - saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF)); - saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF)); - /* TASK B */ - saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF)); - saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF)); - return 0; -} - -static int saa717x_s_radio(struct v4l2_subdev *sd) -{ - struct saa717x_state *decoder = to_state(sd); - - decoder->radio = 1; - return 0; -} - -static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct saa717x_state *decoder = to_state(sd); - - v4l2_dbg(1, debug, sd, "decoder set norm "); - v4l2_dbg(1, debug, sd, "(not yet implementd)\n"); - - decoder->radio = 0; - decoder->std = std; - return 0; -} - -static int saa717x_s_audio_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct saa717x_state *decoder = to_state(sd); - - if (input < 3) { /* FIXME! --tadachi */ - decoder->audio_input = input; - v4l2_dbg(1, debug, sd, - "set decoder audio input to %d\n", - decoder->audio_input); - set_audio_regs(sd, decoder); - return 0; - } - return -ERANGE; -} - -static int saa717x_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct saa717x_state *decoder = to_state(sd); - - v4l2_dbg(1, debug, sd, "decoder %s output\n", - enable ? "enable" : "disable"); - decoder->enable = enable; - saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26); - return 0; -} - -/* change audio mode */ -static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct saa717x_state *decoder = to_state(sd); - int audio_mode; - char *mes[4] = { - "MONO", "STEREO", "LANG1", "LANG2/SAP" - }; - - audio_mode = TUNER_AUDIO_STEREO; - - switch (vt->audmode) { - case V4L2_TUNER_MODE_MONO: - audio_mode = TUNER_AUDIO_MONO; - break; - case V4L2_TUNER_MODE_STEREO: - audio_mode = TUNER_AUDIO_STEREO; - break; - case V4L2_TUNER_MODE_LANG2: - audio_mode = TUNER_AUDIO_LANG2; - break; - case V4L2_TUNER_MODE_LANG1: - audio_mode = TUNER_AUDIO_LANG1; - break; - } - - v4l2_dbg(1, debug, sd, "change audio mode to %s\n", - mes[audio_mode]); - decoder->tuner_audio_mode = audio_mode; - /* The registers are not changed here. */ - /* See DECODER_ENABLE_OUTPUT section. */ - set_audio_mode(sd, decoder->tuner_audio_mode); - return 0; -} - -static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct saa717x_state *decoder = to_state(sd); - int dual_f, stereo_f; - - if (decoder->radio) - return 0; - get_inf_dev_status(sd, &dual_f, &stereo_f); - - v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n", - stereo_f, dual_f); - - /* mono */ - if ((dual_f == 0) && (stereo_f == 0)) { - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - v4l2_dbg(1, debug, sd, "DETECT==MONO\n"); - } - - /* stereo */ - if (stereo_f == 1) { - if (vt->audmode == V4L2_TUNER_MODE_STEREO || - vt->audmode == V4L2_TUNER_MODE_LANG1) { - vt->rxsubchans = V4L2_TUNER_SUB_STEREO; - v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n"); - } else { - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n"); - } - } - - /* dual */ - if (dual_f == 1) { - if (vt->audmode == V4L2_TUNER_MODE_LANG2) { - vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO; - v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n"); - } else { - vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO; - v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n"); - } - } - return 0; -} - -static int saa717x_log_status(struct v4l2_subdev *sd) -{ - struct saa717x_state *state = to_state(sd); - - v4l2_ctrl_handler_log_status(&state->hdl, sd->name); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops saa717x_ctrl_ops = { - .s_ctrl = saa717x_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops saa717x_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = saa717x_g_register, - .s_register = saa717x_s_register, -#endif - .s_std = saa717x_s_std, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .log_status = saa717x_log_status, -}; - -static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = { - .g_tuner = saa717x_g_tuner, - .s_tuner = saa717x_s_tuner, - .s_radio = saa717x_s_radio, -}; - -static const struct v4l2_subdev_video_ops saa717x_video_ops = { - .s_routing = saa717x_s_video_routing, - .s_mbus_fmt = saa717x_s_mbus_fmt, - .s_stream = saa717x_s_stream, -}; - -static const struct v4l2_subdev_audio_ops saa717x_audio_ops = { - .s_routing = saa717x_s_audio_routing, -}; - -static const struct v4l2_subdev_ops saa717x_ops = { - .core = &saa717x_core_ops, - .tuner = &saa717x_tuner_ops, - .audio = &saa717x_audio_ops, - .video = &saa717x_video_ops, -}; - -/* ----------------------------------------------------------------------- */ - - -/* i2c implementation */ - -/* ----------------------------------------------------------------------- */ -static int saa717x_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct saa717x_state *decoder; - struct v4l2_ctrl_handler *hdl; - struct v4l2_subdev *sd; - u8 id = 0; - char *p = ""; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL); - if (decoder == NULL) - return -ENOMEM; - - sd = &decoder->sd; - v4l2_i2c_subdev_init(sd, client, &saa717x_ops); - - if (saa717x_write(sd, 0x5a4, 0xfe) && - saa717x_write(sd, 0x5a5, 0x0f) && - saa717x_write(sd, 0x5a6, 0x00) && - saa717x_write(sd, 0x5a7, 0x01)) - id = saa717x_read(sd, 0x5a0); - if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) { - v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id); - kfree(decoder); - return -ENODEV; - } - if (id == 0xc2) - p = "saa7173"; - else if (id == 0x32) - p = "saa7174A"; - else if (id == 0x6c) - p = "saa7174HL"; - else - p = "saa7171"; - v4l2_info(sd, "%s found @ 0x%x (%s)\n", p, - client->addr << 1, client->adapter->name); - - hdl = &decoder->hdl; - v4l2_ctrl_handler_init(hdl, 9); - /* add in ascending ID order */ - v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 68); - v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 64); - v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 42000); - v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768); - v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops, - V4L2_CID_AUDIO_BASS, -16, 15, 1, 0); - v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops, - V4L2_CID_AUDIO_TREBLE, -16, 15, 1, 0); - v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - sd->ctrl_handler = hdl; - if (hdl->error) { - int err = hdl->error; - - v4l2_ctrl_handler_free(hdl); - kfree(decoder); - return err; - } - - decoder->std = V4L2_STD_NTSC; - decoder->input = -1; - decoder->enable = 1; - - /* FIXME!! */ - decoder->playback = 0; /* initially capture mode used */ - decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */ - - decoder->audio_input = 2; /* FIXME!! */ - - decoder->tuner_audio_mode = TUNER_AUDIO_STEREO; - /* set volume, bass and treble */ - decoder->audio_main_vol_l = 6; - decoder->audio_main_vol_r = 6; - - v4l2_dbg(1, debug, sd, "writing init values\n"); - - /* FIXME!! */ - saa717x_write_regs(sd, reg_init_initialize); - - v4l2_ctrl_handler_setup(hdl); - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(2*HZ); - return 0; -} - -static int saa717x_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(sd->ctrl_handler); - kfree(to_state(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id saa717x_id[] = { - { "saa717x", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, saa717x_id); - -static struct i2c_driver saa717x_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "saa717x", - }, - .probe = saa717x_probe, - .remove = saa717x_remove, - .id_table = saa717x_id, -}; - -static __init int init_saa717x(void) -{ - return i2c_add_driver(&saa717x_driver); -} - -static __exit void exit_saa717x(void) -{ - i2c_del_driver(&saa717x_driver); -} - -module_init(init_saa717x); -module_exit(exit_saa717x); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7185.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7185.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7185.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7185.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,388 +0,0 @@ -/* - * saa7185 - Philips SAA7185B video encoder driver version 0.0.3 - * - * Copyright (C) 1998 Dave Perks - * - * Slight changes for video timing and attachment output by - * Wolfgang Scherr - * - * Changes by Ronald Bultje - * - moved over to linux>=2.4.x i2c protocol (1/1/2003) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("Philips SAA7185 video encoder driver"); -MODULE_AUTHOR("Dave Perks"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -/* ----------------------------------------------------------------------- */ - -struct saa7185 { - struct v4l2_subdev sd; - unsigned char reg[128]; - - v4l2_std_id norm; -}; - -static inline struct saa7185 *to_saa7185(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa7185, sd); -} - -/* ----------------------------------------------------------------------- */ - -static inline int saa7185_read(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_read_byte(client); -} - -static int saa7185_write(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct saa7185 *encoder = to_saa7185(sd); - - v4l2_dbg(1, debug, sd, "%02x set to %02x\n", reg, value); - encoder->reg[reg] = value; - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int saa7185_write_block(struct v4l2_subdev *sd, - const u8 *data, unsigned int len) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct saa7185 *encoder = to_saa7185(sd); - int ret = -1; - u8 reg; - - /* the adv7175 has an autoincrement function, use it if - * the adapter understands raw I2C */ - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - /* do raw I2C, not smbus compatible */ - u8 block_data[32]; - int block_len; - - while (len >= 2) { - block_len = 0; - block_data[block_len++] = reg = data[0]; - do { - block_data[block_len++] = - encoder->reg[reg++] = data[1]; - len -= 2; - data += 2; - } while (len >= 2 && data[0] == reg && block_len < 32); - ret = i2c_master_send(client, block_data, block_len); - if (ret < 0) - break; - } - } else { - /* do some slow I2C emulation kind of thing */ - while (len >= 2) { - reg = *data++; - ret = saa7185_write(sd, reg, *data++); - if (ret < 0) - break; - len -= 2; - } - } - - return ret; -} - -/* ----------------------------------------------------------------------- */ - -static const unsigned char init_common[] = { - 0x3a, 0x0f, /* CBENB=0, V656=0, VY2C=1, - * YUV2C=1, MY2C=1, MUV2C=1 */ - - 0x42, 0x6b, /* OVLY0=107 */ - 0x43, 0x00, /* OVLU0=0 white */ - 0x44, 0x00, /* OVLV0=0 */ - 0x45, 0x22, /* OVLY1=34 */ - 0x46, 0xac, /* OVLU1=172 yellow */ - 0x47, 0x0e, /* OVLV1=14 */ - 0x48, 0x03, /* OVLY2=3 */ - 0x49, 0x1d, /* OVLU2=29 cyan */ - 0x4a, 0xac, /* OVLV2=172 */ - 0x4b, 0xf0, /* OVLY3=240 */ - 0x4c, 0xc8, /* OVLU3=200 green */ - 0x4d, 0xb9, /* OVLV3=185 */ - 0x4e, 0xd4, /* OVLY4=212 */ - 0x4f, 0x38, /* OVLU4=56 magenta */ - 0x50, 0x47, /* OVLV4=71 */ - 0x51, 0xc1, /* OVLY5=193 */ - 0x52, 0xe3, /* OVLU5=227 red */ - 0x53, 0x54, /* OVLV5=84 */ - 0x54, 0xa3, /* OVLY6=163 */ - 0x55, 0x54, /* OVLU6=84 blue */ - 0x56, 0xf2, /* OVLV6=242 */ - 0x57, 0x90, /* OVLY7=144 */ - 0x58, 0x00, /* OVLU7=0 black */ - 0x59, 0x00, /* OVLV7=0 */ - - 0x5a, 0x00, /* CHPS=0 */ - 0x5b, 0x76, /* GAINU=118 */ - 0x5c, 0xa5, /* GAINV=165 */ - 0x5d, 0x3c, /* BLCKL=60 */ - 0x5e, 0x3a, /* BLNNL=58 */ - 0x5f, 0x3a, /* CCRS=0, BLNVB=58 */ - 0x60, 0x00, /* NULL */ - - /* 0x61 - 0x66 set according to norm */ - - 0x67, 0x00, /* 0 : caption 1st byte odd field */ - 0x68, 0x00, /* 0 : caption 2nd byte odd field */ - 0x69, 0x00, /* 0 : caption 1st byte even field */ - 0x6a, 0x00, /* 0 : caption 2nd byte even field */ - - 0x6b, 0x91, /* MODIN=2, PCREF=0, SCCLN=17 */ - 0x6c, 0x20, /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, - * CBLF=0, ORCV2=0, PRCV2=0 */ - 0x6d, 0x00, /* SRCM1=0, CCEN=0 */ - - 0x6e, 0x0e, /* HTRIG=0x005, approx. centered, at - * least for PAL */ - 0x6f, 0x00, /* HTRIG upper bits */ - 0x70, 0x20, /* PHRES=0, SBLN=1, VTRIG=0 */ - - /* The following should not be needed */ - - 0x71, 0x15, /* BMRQ=0x115 */ - 0x72, 0x90, /* EMRQ=0x690 */ - 0x73, 0x61, /* EMRQ=0x690, BMRQ=0x115 */ - 0x74, 0x00, /* NULL */ - 0x75, 0x00, /* NULL */ - 0x76, 0x00, /* NULL */ - 0x77, 0x15, /* BRCV=0x115 */ - 0x78, 0x90, /* ERCV=0x690 */ - 0x79, 0x61, /* ERCV=0x690, BRCV=0x115 */ - - /* Field length controls */ - - 0x7a, 0x70, /* FLC=0 */ - - /* The following should not be needed if SBLN = 1 */ - - 0x7b, 0x16, /* FAL=22 */ - 0x7c, 0x35, /* LAL=244 */ - 0x7d, 0x20, /* LAL=244, FAL=22 */ -}; - -static const unsigned char init_pal[] = { - 0x61, 0x1e, /* FISE=0, PAL=1, SCBW=1, RTCE=1, - * YGS=1, INPI=0, DOWN=0 */ - 0x62, 0xc8, /* DECTYP=1, BSTA=72 */ - 0x63, 0xcb, /* FSC0 */ - 0x64, 0x8a, /* FSC1 */ - 0x65, 0x09, /* FSC2 */ - 0x66, 0x2a, /* FSC3 */ -}; - -static const unsigned char init_ntsc[] = { - 0x61, 0x1d, /* FISE=1, PAL=0, SCBW=1, RTCE=1, - * YGS=1, INPI=0, DOWN=0 */ - 0x62, 0xe6, /* DECTYP=1, BSTA=102 */ - 0x63, 0x1f, /* FSC0 */ - 0x64, 0x7c, /* FSC1 */ - 0x65, 0xf0, /* FSC2 */ - 0x66, 0x21, /* FSC3 */ -}; - - -static int saa7185_init(struct v4l2_subdev *sd, u32 val) -{ - struct saa7185 *encoder = to_saa7185(sd); - - saa7185_write_block(sd, init_common, sizeof(init_common)); - if (encoder->norm & V4L2_STD_NTSC) - saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc)); - else - saa7185_write_block(sd, init_pal, sizeof(init_pal)); - return 0; -} - -static int saa7185_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct saa7185 *encoder = to_saa7185(sd); - - if (std & V4L2_STD_NTSC) - saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc)); - else if (std & V4L2_STD_PAL) - saa7185_write_block(sd, init_pal, sizeof(init_pal)); - else - return -EINVAL; - encoder->norm = std; - return 0; -} - -static int saa7185_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct saa7185 *encoder = to_saa7185(sd); - - /* RJ: input = 0: input is from SA7111 - input = 1: input is from ZR36060 */ - - switch (input) { - case 0: - /* turn off colorbar */ - saa7185_write(sd, 0x3a, 0x0f); - /* Switch RTCE to 1 */ - saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); - saa7185_write(sd, 0x6e, 0x01); - break; - - case 1: - /* turn off colorbar */ - saa7185_write(sd, 0x3a, 0x0f); - /* Switch RTCE to 0 */ - saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00); - /* SW: a slight sync problem... */ - saa7185_write(sd, 0x6e, 0x00); - break; - - case 2: - /* turn on colorbar */ - saa7185_write(sd, 0x3a, 0x8f); - /* Switch RTCE to 0 */ - saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); - /* SW: a slight sync problem... */ - saa7185_write(sd, 0x6e, 0x01); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int saa7185_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7185, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops saa7185_core_ops = { - .g_chip_ident = saa7185_g_chip_ident, - .init = saa7185_init, -}; - -static const struct v4l2_subdev_video_ops saa7185_video_ops = { - .s_std_output = saa7185_s_std_output, - .s_routing = saa7185_s_routing, -}; - -static const struct v4l2_subdev_ops saa7185_ops = { - .core = &saa7185_core_ops, - .video = &saa7185_video_ops, -}; - - -/* ----------------------------------------------------------------------- */ - -static int saa7185_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int i; - struct saa7185 *encoder; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL); - if (encoder == NULL) - return -ENOMEM; - encoder->norm = V4L2_STD_NTSC; - sd = &encoder->sd; - v4l2_i2c_subdev_init(sd, client, &saa7185_ops); - - i = saa7185_write_block(sd, init_common, sizeof(init_common)); - if (i >= 0) - i = saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc)); - if (i < 0) - v4l2_dbg(1, debug, sd, "init error %d\n", i); - else - v4l2_dbg(1, debug, sd, "revision 0x%x\n", - saa7185_read(sd) >> 5); - return 0; -} - -static int saa7185_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct saa7185 *encoder = to_saa7185(sd); - - v4l2_device_unregister_subdev(sd); - /* SW: output off is active */ - saa7185_write(sd, 0x61, (encoder->reg[0x61]) | 0x40); - kfree(encoder); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id saa7185_id[] = { - { "saa7185", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, saa7185_id); - -static struct i2c_driver saa7185_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "saa7185", - }, - .probe = saa7185_probe, - .remove = saa7185_remove, - .id_table = saa7185_id, -}; - -static __init int init_saa7185(void) -{ - return i2c_add_driver(&saa7185_driver); -} - -static __exit void exit_saa7185(void) -{ - i2c_del_driver(&saa7185_driver); -} - -module_init(init_saa7185); -module_exit(exit_saa7185); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7191.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7191.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7191.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7191.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,669 +0,0 @@ -/* - * saa7191.c - Philips SAA7191 video decoder driver - * - * Copyright (C) 2003 Ladislav Michl - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "saa7191.h" - -#define SAA7191_MODULE_VERSION "0.0.5" - -MODULE_DESCRIPTION("Philips SAA7191 video decoder driver"); -MODULE_AUTHOR("Mikael Nousiainen "); -MODULE_LICENSE("GPL"); - - -// #define SAA7191_DEBUG - -#ifdef SAA7191_DEBUG -#define dprintk(x...) printk("SAA7191: " x); -#else -#define dprintk(x...) -#endif - -#define SAA7191_SYNC_COUNT 30 -#define SAA7191_SYNC_DELAY 100 /* milliseconds */ - -struct saa7191 { - struct v4l2_subdev sd; - - /* the register values are stored here as the actual - * I2C-registers are write-only */ - u8 reg[25]; - - int input; - v4l2_std_id norm; -}; - -static inline struct saa7191 *to_saa7191(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa7191, sd); -} - -static const u8 initseq[] = { - 0, /* Subaddress */ - - 0x50, /* (0x50) SAA7191_REG_IDEL */ - - /* 50 Hz signal timing */ - 0x30, /* (0x30) SAA7191_REG_HSYB */ - 0x00, /* (0x00) SAA7191_REG_HSYS */ - 0xe8, /* (0xe8) SAA7191_REG_HCLB */ - 0xb6, /* (0xb6) SAA7191_REG_HCLS */ - 0xf4, /* (0xf4) SAA7191_REG_HPHI */ - - /* control */ - SAA7191_LUMA_APER_1, /* (0x01) SAA7191_REG_LUMA - CVBS mode */ - 0x00, /* (0x00) SAA7191_REG_HUEC */ - 0xf8, /* (0xf8) SAA7191_REG_CKTQ */ - 0xf8, /* (0xf8) SAA7191_REG_CKTS */ - 0x90, /* (0x90) SAA7191_REG_PLSE */ - 0x90, /* (0x90) SAA7191_REG_SESE */ - 0x00, /* (0x00) SAA7191_REG_GAIN */ - SAA7191_STDC_NFEN | SAA7191_STDC_HRMV, /* (0x0c) SAA7191_REG_STDC - * - not SECAM, - * slow time constant */ - SAA7191_IOCK_OEDC | SAA7191_IOCK_OEHS | SAA7191_IOCK_OEVS - | SAA7191_IOCK_OEDY, /* (0x78) SAA7191_REG_IOCK - * - chroma from CVBS, GPSW1 & 2 off */ - SAA7191_CTL3_AUFD | SAA7191_CTL3_SCEN | SAA7191_CTL3_OFTS - | SAA7191_CTL3_YDEL0, /* (0x99) SAA7191_REG_CTL3 - * - automatic field detection */ - 0x00, /* (0x00) SAA7191_REG_CTL4 */ - 0x2c, /* (0x2c) SAA7191_REG_CHCV - PAL nominal value */ - 0x00, /* unused */ - 0x00, /* unused */ - - /* 60 Hz signal timing */ - 0x34, /* (0x34) SAA7191_REG_HS6B */ - 0x0a, /* (0x0a) SAA7191_REG_HS6S */ - 0xf4, /* (0xf4) SAA7191_REG_HC6B */ - 0xce, /* (0xce) SAA7191_REG_HC6S */ - 0xf4, /* (0xf4) SAA7191_REG_HP6I */ -}; - -/* SAA7191 register handling */ - -static u8 saa7191_read_reg(struct v4l2_subdev *sd, u8 reg) -{ - return to_saa7191(sd)->reg[reg]; -} - -static int saa7191_read_status(struct v4l2_subdev *sd, u8 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - ret = i2c_master_recv(client, value, 1); - if (ret < 0) { - printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed\n"); - return ret; - } - - return 0; -} - - -static int saa7191_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - to_saa7191(sd)->reg[reg] = value; - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* the first byte of data must be the first subaddress number (register) */ -static int saa7191_write_block(struct v4l2_subdev *sd, - u8 length, const u8 *data) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct saa7191 *decoder = to_saa7191(sd); - int i; - int ret; - - for (i = 0; i < (length - 1); i++) { - decoder->reg[data[0] + i] = data[i + 1]; - } - - ret = i2c_master_send(client, data, length); - if (ret < 0) { - printk(KERN_ERR "SAA7191: saa7191_write_block(): " - "write failed\n"); - return ret; - } - - return 0; -} - -/* Helper functions */ - -static int saa7191_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct saa7191 *decoder = to_saa7191(sd); - u8 luma = saa7191_read_reg(sd, SAA7191_REG_LUMA); - u8 iock = saa7191_read_reg(sd, SAA7191_REG_IOCK); - int err; - - switch (input) { - case SAA7191_INPUT_COMPOSITE: /* Set Composite input */ - iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1 - | SAA7191_IOCK_GPSW2); - /* Chrominance trap active */ - luma &= ~SAA7191_LUMA_BYPS; - break; - case SAA7191_INPUT_SVIDEO: /* Set S-Video input */ - iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2; - /* Chrominance trap bypassed */ - luma |= SAA7191_LUMA_BYPS; - break; - default: - return -EINVAL; - } - - err = saa7191_write_reg(sd, SAA7191_REG_LUMA, luma); - if (err) - return -EIO; - err = saa7191_write_reg(sd, SAA7191_REG_IOCK, iock); - if (err) - return -EIO; - - decoder->input = input; - - return 0; -} - -static int saa7191_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - struct saa7191 *decoder = to_saa7191(sd); - u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC); - u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3); - u8 chcv = saa7191_read_reg(sd, SAA7191_REG_CHCV); - int err; - - if (norm & V4L2_STD_PAL) { - stdc &= ~SAA7191_STDC_SECS; - ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); - chcv = SAA7191_CHCV_PAL; - } else if (norm & V4L2_STD_NTSC) { - stdc &= ~SAA7191_STDC_SECS; - ctl3 &= ~SAA7191_CTL3_AUFD; - ctl3 |= SAA7191_CTL3_FSEL; - chcv = SAA7191_CHCV_NTSC; - } else if (norm & V4L2_STD_SECAM) { - stdc |= SAA7191_STDC_SECS; - ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); - chcv = SAA7191_CHCV_PAL; - } else { - return -EINVAL; - } - - err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3); - if (err) - return -EIO; - err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc); - if (err) - return -EIO; - err = saa7191_write_reg(sd, SAA7191_REG_CHCV, chcv); - if (err) - return -EIO; - - decoder->norm = norm; - - dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3, - stdc, chcv); - dprintk("norm: %llx\n", norm); - - return 0; -} - -static int saa7191_wait_for_signal(struct v4l2_subdev *sd, u8 *status) -{ - int i = 0; - - dprintk("Checking for signal...\n"); - - for (i = 0; i < SAA7191_SYNC_COUNT; i++) { - if (saa7191_read_status(sd, status)) - return -EIO; - - if (((*status) & SAA7191_STATUS_HLCK) == 0) { - dprintk("Signal found\n"); - return 0; - } - - msleep(SAA7191_SYNC_DELAY); - } - - dprintk("No signal\n"); - - return -EBUSY; -} - -static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm) -{ - struct saa7191 *decoder = to_saa7191(sd); - u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC); - u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3); - u8 status; - v4l2_std_id old_norm = decoder->norm; - int err = 0; - - dprintk("SAA7191 extended signal auto-detection...\n"); - - *norm = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; - stdc &= ~SAA7191_STDC_SECS; - ctl3 &= ~(SAA7191_CTL3_FSEL); - - err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc); - if (err) { - err = -EIO; - goto out; - } - err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3); - if (err) { - err = -EIO; - goto out; - } - - ctl3 |= SAA7191_CTL3_AUFD; - err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3); - if (err) { - err = -EIO; - goto out; - } - - msleep(SAA7191_SYNC_DELAY); - - err = saa7191_wait_for_signal(sd, &status); - if (err) - goto out; - - if (status & SAA7191_STATUS_FIDT) { - /* 60Hz signal -> NTSC */ - dprintk("60Hz signal: NTSC\n"); - *norm = V4L2_STD_NTSC; - return 0; - } - - /* 50Hz signal */ - dprintk("50Hz signal: Trying PAL...\n"); - - /* try PAL first */ - err = saa7191_s_std(sd, V4L2_STD_PAL); - if (err) - goto out; - - msleep(SAA7191_SYNC_DELAY); - - err = saa7191_wait_for_signal(sd, &status); - if (err) - goto out; - - /* not 50Hz ? */ - if (status & SAA7191_STATUS_FIDT) { - dprintk("No 50Hz signal\n"); - saa7191_s_std(sd, old_norm); - return -EAGAIN; - } - - if (status & SAA7191_STATUS_CODE) { - dprintk("PAL\n"); - *norm = V4L2_STD_PAL; - return saa7191_s_std(sd, old_norm); - } - - dprintk("No color detected with PAL - Trying SECAM...\n"); - - /* no color detected ? -> try SECAM */ - err = saa7191_s_std(sd, V4L2_STD_SECAM); - if (err) - goto out; - - msleep(SAA7191_SYNC_DELAY); - - err = saa7191_wait_for_signal(sd, &status); - if (err) - goto out; - - /* not 50Hz ? */ - if (status & SAA7191_STATUS_FIDT) { - dprintk("No 50Hz signal\n"); - err = -EAGAIN; - goto out; - } - - if (status & SAA7191_STATUS_CODE) { - /* Color detected -> SECAM */ - dprintk("SECAM\n"); - *norm = V4L2_STD_SECAM; - return saa7191_s_std(sd, old_norm); - } - - dprintk("No color detected with SECAM - Going back to PAL.\n"); - -out: - return saa7191_s_std(sd, old_norm); -} - -static int saa7191_autodetect_norm(struct v4l2_subdev *sd) -{ - u8 status; - - dprintk("SAA7191 signal auto-detection...\n"); - - dprintk("Reading status...\n"); - - if (saa7191_read_status(sd, &status)) - return -EIO; - - dprintk("Checking for signal...\n"); - - /* no signal ? */ - if (status & SAA7191_STATUS_HLCK) { - dprintk("No signal\n"); - return -EBUSY; - } - - dprintk("Signal found\n"); - - if (status & SAA7191_STATUS_FIDT) { - /* 60hz signal -> NTSC */ - dprintk("NTSC\n"); - return saa7191_s_std(sd, V4L2_STD_NTSC); - } else { - /* 50hz signal -> PAL */ - dprintk("PAL\n"); - return saa7191_s_std(sd, V4L2_STD_PAL); - } -} - -static int saa7191_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - u8 reg; - int ret = 0; - - switch (ctrl->id) { - case SAA7191_CONTROL_BANDPASS: - case SAA7191_CONTROL_BANDPASS_WEIGHT: - case SAA7191_CONTROL_CORING: - reg = saa7191_read_reg(sd, SAA7191_REG_LUMA); - switch (ctrl->id) { - case SAA7191_CONTROL_BANDPASS: - ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK) - >> SAA7191_LUMA_BPSS_SHIFT; - break; - case SAA7191_CONTROL_BANDPASS_WEIGHT: - ctrl->value = ((s32)reg & SAA7191_LUMA_APER_MASK) - >> SAA7191_LUMA_APER_SHIFT; - break; - case SAA7191_CONTROL_CORING: - ctrl->value = ((s32)reg & SAA7191_LUMA_CORI_MASK) - >> SAA7191_LUMA_CORI_SHIFT; - break; - } - break; - case SAA7191_CONTROL_FORCE_COLOUR: - case SAA7191_CONTROL_CHROMA_GAIN: - reg = saa7191_read_reg(sd, SAA7191_REG_GAIN); - if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) - ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0; - else - ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK) - >> SAA7191_GAIN_LFIS_SHIFT; - break; - case V4L2_CID_HUE: - reg = saa7191_read_reg(sd, SAA7191_REG_HUEC); - if (reg < 0x80) - reg += 0x80; - else - reg -= 0x80; - ctrl->value = (s32)reg; - break; - case SAA7191_CONTROL_VTRC: - reg = saa7191_read_reg(sd, SAA7191_REG_STDC); - ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0; - break; - case SAA7191_CONTROL_LUMA_DELAY: - reg = saa7191_read_reg(sd, SAA7191_REG_CTL3); - ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK) - >> SAA7191_CTL3_YDEL_SHIFT; - if (ctrl->value >= 4) - ctrl->value -= 8; - break; - case SAA7191_CONTROL_VNR: - reg = saa7191_read_reg(sd, SAA7191_REG_CTL4); - ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK) - >> SAA7191_CTL4_VNOI_SHIFT; - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int saa7191_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - u8 reg; - int ret = 0; - - switch (ctrl->id) { - case SAA7191_CONTROL_BANDPASS: - case SAA7191_CONTROL_BANDPASS_WEIGHT: - case SAA7191_CONTROL_CORING: - reg = saa7191_read_reg(sd, SAA7191_REG_LUMA); - switch (ctrl->id) { - case SAA7191_CONTROL_BANDPASS: - reg &= ~SAA7191_LUMA_BPSS_MASK; - reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT) - & SAA7191_LUMA_BPSS_MASK; - break; - case SAA7191_CONTROL_BANDPASS_WEIGHT: - reg &= ~SAA7191_LUMA_APER_MASK; - reg |= (ctrl->value << SAA7191_LUMA_APER_SHIFT) - & SAA7191_LUMA_APER_MASK; - break; - case SAA7191_CONTROL_CORING: - reg &= ~SAA7191_LUMA_CORI_MASK; - reg |= (ctrl->value << SAA7191_LUMA_CORI_SHIFT) - & SAA7191_LUMA_CORI_MASK; - break; - } - ret = saa7191_write_reg(sd, SAA7191_REG_LUMA, reg); - break; - case SAA7191_CONTROL_FORCE_COLOUR: - case SAA7191_CONTROL_CHROMA_GAIN: - reg = saa7191_read_reg(sd, SAA7191_REG_GAIN); - if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) { - if (ctrl->value) - reg |= SAA7191_GAIN_COLO; - else - reg &= ~SAA7191_GAIN_COLO; - } else { - reg &= ~SAA7191_GAIN_LFIS_MASK; - reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT) - & SAA7191_GAIN_LFIS_MASK; - } - ret = saa7191_write_reg(sd, SAA7191_REG_GAIN, reg); - break; - case V4L2_CID_HUE: - reg = ctrl->value & 0xff; - if (reg < 0x80) - reg += 0x80; - else - reg -= 0x80; - ret = saa7191_write_reg(sd, SAA7191_REG_HUEC, reg); - break; - case SAA7191_CONTROL_VTRC: - reg = saa7191_read_reg(sd, SAA7191_REG_STDC); - if (ctrl->value) - reg |= SAA7191_STDC_VTRC; - else - reg &= ~SAA7191_STDC_VTRC; - ret = saa7191_write_reg(sd, SAA7191_REG_STDC, reg); - break; - case SAA7191_CONTROL_LUMA_DELAY: { - s32 value = ctrl->value; - if (value < 0) - value += 8; - reg = saa7191_read_reg(sd, SAA7191_REG_CTL3); - reg &= ~SAA7191_CTL3_YDEL_MASK; - reg |= (value << SAA7191_CTL3_YDEL_SHIFT) - & SAA7191_CTL3_YDEL_MASK; - ret = saa7191_write_reg(sd, SAA7191_REG_CTL3, reg); - break; - } - case SAA7191_CONTROL_VNR: - reg = saa7191_read_reg(sd, SAA7191_REG_CTL4); - reg &= ~SAA7191_CTL4_VNOI_MASK; - reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT) - & SAA7191_CTL4_VNOI_MASK; - ret = saa7191_write_reg(sd, SAA7191_REG_CTL4, reg); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -/* I2C-interface */ - -static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status) -{ - u8 status_reg; - int res = V4L2_IN_ST_NO_SIGNAL; - - if (saa7191_read_status(sd, &status_reg)) - return -EIO; - if ((status_reg & SAA7191_STATUS_HLCK) == 0) - res = 0; - if (!(status_reg & SAA7191_STATUS_CODE)) - res |= V4L2_IN_ST_NO_COLOR; - *status = res; - return 0; -} - - -static int saa7191_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7191, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops saa7191_core_ops = { - .g_chip_ident = saa7191_g_chip_ident, - .g_ctrl = saa7191_g_ctrl, - .s_ctrl = saa7191_s_ctrl, - .s_std = saa7191_s_std, -}; - -static const struct v4l2_subdev_video_ops saa7191_video_ops = { - .s_routing = saa7191_s_routing, - .querystd = saa7191_querystd, - .g_input_status = saa7191_g_input_status, -}; - -static const struct v4l2_subdev_ops saa7191_ops = { - .core = &saa7191_core_ops, - .video = &saa7191_video_ops, -}; - -static int saa7191_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int err = 0; - struct saa7191 *decoder; - struct v4l2_subdev *sd; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - decoder = kzalloc(sizeof(*decoder), GFP_KERNEL); - if (!decoder) - return -ENOMEM; - - sd = &decoder->sd; - v4l2_i2c_subdev_init(sd, client, &saa7191_ops); - - err = saa7191_write_block(sd, sizeof(initseq), initseq); - if (err) { - printk(KERN_ERR "SAA7191 initialization failed\n"); - kfree(decoder); - return err; - } - - printk(KERN_INFO "SAA7191 initialized\n"); - - decoder->input = SAA7191_INPUT_COMPOSITE; - decoder->norm = V4L2_STD_PAL; - - err = saa7191_autodetect_norm(sd); - if (err && (err != -EBUSY)) - printk(KERN_ERR "SAA7191: Signal auto-detection failed\n"); - - return 0; -} - -static int saa7191_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_saa7191(sd)); - return 0; -} - -static const struct i2c_device_id saa7191_id[] = { - { "saa7191", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, saa7191_id); - -static struct i2c_driver saa7191_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "saa7191", - }, - .probe = saa7191_probe, - .remove = saa7191_remove, - .id_table = saa7191_id, -}; - -static __init int init_saa7191(void) -{ - return i2c_add_driver(&saa7191_driver); -} - -static __exit void exit_saa7191(void) -{ - i2c_del_driver(&saa7191_driver); -} - -module_init(init_saa7191); -module_exit(exit_saa7191); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7191.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7191.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7191.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/saa7191.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -/* - * saa7191.h - Philips SAA7191 video decoder driver - * - * Copyright (C) 2003 Ladislav Michl - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _SAA7191_H_ -#define _SAA7191_H_ - -/* Philips SAA7191 DMSD I2C bus address */ -#define SAA7191_ADDR 0x8a - -/* Register subaddresses. */ -#define SAA7191_REG_IDEL 0x00 -#define SAA7191_REG_HSYB 0x01 -#define SAA7191_REG_HSYS 0x02 -#define SAA7191_REG_HCLB 0x03 -#define SAA7191_REG_HCLS 0x04 -#define SAA7191_REG_HPHI 0x05 -#define SAA7191_REG_LUMA 0x06 -#define SAA7191_REG_HUEC 0x07 -#define SAA7191_REG_CKTQ 0x08 /* bits 3-7 */ -#define SAA7191_REG_CKTS 0x09 /* bits 3-7 */ -#define SAA7191_REG_PLSE 0x0a -#define SAA7191_REG_SESE 0x0b -#define SAA7191_REG_GAIN 0x0c -#define SAA7191_REG_STDC 0x0d -#define SAA7191_REG_IOCK 0x0e -#define SAA7191_REG_CTL3 0x0f -#define SAA7191_REG_CTL4 0x10 -#define SAA7191_REG_CHCV 0x11 -#define SAA7191_REG_HS6B 0x14 -#define SAA7191_REG_HS6S 0x15 -#define SAA7191_REG_HC6B 0x16 -#define SAA7191_REG_HC6S 0x17 -#define SAA7191_REG_HP6I 0x18 -#define SAA7191_REG_STATUS 0xff /* not really a subaddress */ - -/* Status Register definitions */ -#define SAA7191_STATUS_CODE 0x01 /* color detected flag */ -#define SAA7191_STATUS_FIDT 0x20 /* signal type 50/60 Hz */ -#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked(1)/locked(0) */ -#define SAA7191_STATUS_STTC 0x80 /* tv/vtr time constant */ - -/* Luminance Control Register definitions */ -/* input mode select bit: - * 0=CVBS (chrominance trap active), 1=S-Video (trap bypassed) */ -#define SAA7191_LUMA_BYPS 0x80 -/* pre-filter (only when chrominance trap is active) */ -#define SAA7191_LUMA_PREF 0x40 -/* aperture bandpass to select different characteristics with maximums - * (bits 4-5) */ -#define SAA7191_LUMA_BPSS_MASK 0x30 -#define SAA7191_LUMA_BPSS_SHIFT 4 -#define SAA7191_LUMA_BPSS_3 0x30 -#define SAA7191_LUMA_BPSS_2 0x20 -#define SAA7191_LUMA_BPSS_1 0x10 -#define SAA7191_LUMA_BPSS_0 0x00 -/* coring range for high frequency components according to 8-bit luminance - * (bits 2-3) - * 0=coring off, n= (+-)n LSB */ -#define SAA7191_LUMA_CORI_MASK 0x0c -#define SAA7191_LUMA_CORI_SHIFT 2 -#define SAA7191_LUMA_CORI_3 0x0c -#define SAA7191_LUMA_CORI_2 0x08 -#define SAA7191_LUMA_CORI_1 0x04 -#define SAA7191_LUMA_CORI_0 0x00 -/* aperture bandpass filter weights high frequency components of luminance - * signal (bits 0-1) - * 0=factor 0, 1=0.25, 2=0.5, 3=1 */ -#define SAA7191_LUMA_APER_MASK 0x03 -#define SAA7191_LUMA_APER_SHIFT 0 -#define SAA7191_LUMA_APER_3 0x03 -#define SAA7191_LUMA_APER_2 0x02 -#define SAA7191_LUMA_APER_1 0x01 -#define SAA7191_LUMA_APER_0 0x00 - -/* Chrominance Gain Control Settings Register definitions */ -/* colour on: 0=automatic colour-killer enabled, 1=forced colour on */ -#define SAA7191_GAIN_COLO 0x80 -/* chrominance gain control (AGC filter) - * 0=loop filter time constant slow, 1=medium, 2=fast, 3=actual gain */ -#define SAA7191_GAIN_LFIS_MASK 0x60 -#define SAA7191_GAIN_LFIS_SHIFT 5 -#define SAA7191_GAIN_LFIS_3 0x60 -#define SAA7191_GAIN_LFIS_2 0x40 -#define SAA7191_GAIN_LFIS_1 0x20 -#define SAA7191_GAIN_LFIS_0 0x00 - -/* Standard/Mode Control Register definitions */ -/* tv/vtr mode bit: 0=TV mode (slow time constant), - * 1=VTR mode (fast time constant) */ -#define SAA7191_STDC_VTRC 0x80 -/* SAA7191B-specific functions enable (RTCO, ODD and GPSW0 outputs) - * 0=outputs set to high-impedance (circuit equals SAA7191), 1=enabled */ -#define SAA7191_STDC_NFEN 0x08 -/* HREF generation: 0=like SAA7191, 1=HREF is 8xLLC2 clocks earlier */ -#define SAA7191_STDC_HRMV 0x04 -/* general purpose switch 0 - * (not used with VINO afaik) */ -#define SAA7191_STDC_GPSW0 0x02 -/* SECAM mode bit: 0=other standards, 1=SECAM */ -#define SAA7191_STDC_SECS 0x01 - -/* I/O and Clock Control Register definitions */ -/* horizontal clock PLL: 0=PLL closed, - * 1=PLL circuit open and horizontal freq fixed */ -#define SAA7191_IOCK_HPLL 0x80 -/* colour-difference output enable (outputs UV0-UV7) */ -#define SAA7191_IOCK_OEDC 0x40 -/* H-sync output enable */ -#define SAA7191_IOCK_OEHS 0x20 -/* V-sync output enable */ -#define SAA7191_IOCK_OEVS 0x10 -/* luminance output enable (outputs Y0-Y7) */ -#define SAA7191_IOCK_OEDY 0x08 -/* S-VHS bit (chrominance from CVBS or from chrominance input): - * 0=controlled by BYPS-bit, 1=from chrominance input */ -#define SAA7191_IOCK_CHRS 0x04 -/* general purpose switch 2 - * VINO-specific: 0=used with CVBS, 1=used with S-Video */ -#define SAA7191_IOCK_GPSW2 0x02 -/* general purpose switch 1 */ -/* VINO-specific: 0=always, 1=not used!*/ -#define SAA7191_IOCK_GPSW1 0x01 - -/* Miscellaneous Control #1 Register definitions */ -/* automatic field detection (50/60Hz standard) */ -#define SAA7191_CTL3_AUFD 0x80 -/* field select: (if AUFD=0) - * 0=50Hz (625 lines), 1=60Hz (525 lines) */ -#define SAA7191_CTL3_FSEL 0x40 -/* SECAM cross-colour reduction enable */ -#define SAA7191_CTL3_SXCR 0x20 -/* sync and clamping pulse enable (HCL and HSY outputs) */ -#define SAA7191_CTL3_SCEN 0x10 -/* output format: 0=4:1:1, 1=4:2:2 (4:2:2 for VINO) */ -#define SAA7191_CTL3_OFTS 0x08 -/* luminance delay compensation - * 0=0*2/LLC, 1=+1*2/LLC, 2=+2*2/LLC, 3=+3*2/LLC, - * 4=-4*2/LLC, 5=-3*2/LLC, 6=-2*2/LLC, 7=-1*2/LLC - * step size = 2/LLC = 67.8ns for 50Hz, 81.5ns for 60Hz */ -#define SAA7191_CTL3_YDEL_MASK 0x07 -#define SAA7191_CTL3_YDEL_SHIFT 0 -#define SAA7191_CTL3_YDEL2 0x04 -#define SAA7191_CTL3_YDEL1 0x02 -#define SAA7191_CTL3_YDEL0 0x01 - -/* Miscellaneous Control #2 Register definitions */ -/* select HREF position - * 0=normal, HREF is matched to YUV output port, - * 1=HREF is matched to CVBS input port */ -#define SAA7191_CTL4_HRFS 0x04 -/* vertical noise reduction - * 0=normal, 1=searching window, 2=auto-deflection, 3=reduction bypassed */ -#define SAA7191_CTL4_VNOI_MASK 0x03 -#define SAA7191_CTL4_VNOI_SHIFT 0 -#define SAA7191_CTL4_VNOI_3 0x03 -#define SAA7191_CTL4_VNOI_2 0x02 -#define SAA7191_CTL4_VNOI_1 0x01 -#define SAA7191_CTL4_VNOI_0 0x00 - -/* Chrominance Gain Control Register definitions - * - for QAM-modulated input signals, effects output amplitude - * (SECAM gain fixed) - * (nominal values for UV CCIR level) */ -#define SAA7191_CHCV_NTSC 0x2c -#define SAA7191_CHCV_PAL 0x59 - -/* Driver interface definitions */ -#define SAA7191_INPUT_COMPOSITE 0 -#define SAA7191_INPUT_SVIDEO 1 - -#define SAA7191_NORM_PAL 1 -#define SAA7191_NORM_NTSC 2 -#define SAA7191_NORM_SECAM 3 - -struct saa7191_status { - /* 0=no signal, 1=signal detected */ - int signal; - /* 0=50hz (pal) signal, 1=60hz (ntsc) signal */ - int signal_60hz; - /* 0=no color detected, 1=color detected */ - int color; - - /* current SAA7191_INPUT_ */ - int input; - /* current SAA7191_NORM_ */ - int norm; -}; - -#define SAA7191_BANDPASS_MIN 0x00 -#define SAA7191_BANDPASS_MAX 0x03 -#define SAA7191_BANDPASS_DEFAULT 0x00 - -#define SAA7191_BANDPASS_WEIGHT_MIN 0x00 -#define SAA7191_BANDPASS_WEIGHT_MAX 0x03 -#define SAA7191_BANDPASS_WEIGHT_DEFAULT 0x01 - -#define SAA7191_CORING_MIN 0x00 -#define SAA7191_CORING_MAX 0x03 -#define SAA7191_CORING_DEFAULT 0x00 - -#define SAA7191_HUE_MIN 0x00 -#define SAA7191_HUE_MAX 0xff -#define SAA7191_HUE_DEFAULT 0x80 - -#define SAA7191_VTRC_MIN 0x00 -#define SAA7191_VTRC_MAX 0x01 -#define SAA7191_VTRC_DEFAULT 0x00 - -#define SAA7191_FORCE_COLOUR_MIN 0x00 -#define SAA7191_FORCE_COLOUR_MAX 0x01 -#define SAA7191_FORCE_COLOUR_DEFAULT 0x00 - -#define SAA7191_CHROMA_GAIN_MIN 0x00 -#define SAA7191_CHROMA_GAIN_MAX 0x03 -#define SAA7191_CHROMA_GAIN_DEFAULT 0x00 - -#define SAA7191_LUMA_DELAY_MIN -0x04 -#define SAA7191_LUMA_DELAY_MAX 0x03 -#define SAA7191_LUMA_DELAY_DEFAULT 0x01 - -#define SAA7191_VNR_MIN 0x00 -#define SAA7191_VNR_MAX 0x03 -#define SAA7191_VNR_DEFAULT 0x00 - -#define SAA7191_CONTROL_BANDPASS (V4L2_CID_PRIVATE_BASE + 0) -#define SAA7191_CONTROL_BANDPASS_WEIGHT (V4L2_CID_PRIVATE_BASE + 1) -#define SAA7191_CONTROL_CORING (V4L2_CID_PRIVATE_BASE + 2) -#define SAA7191_CONTROL_FORCE_COLOUR (V4L2_CID_PRIVATE_BASE + 3) -#define SAA7191_CONTROL_CHROMA_GAIN (V4L2_CID_PRIVATE_BASE + 4) -#define SAA7191_CONTROL_VTRC (V4L2_CID_PRIVATE_BASE + 5) -#define SAA7191_CONTROL_LUMA_DELAY (V4L2_CID_PRIVATE_BASE + 6) -#define SAA7191_CONTROL_VNR (V4L2_CID_PRIVATE_BASE + 7) - -#define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status) -#define DECODER_SAA7191_SET_NORM _IOW('d', 196, int) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_mobile_ceu_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_mobile_ceu_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_mobile_ceu_camera.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_mobile_ceu_camera.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2047 +0,0 @@ -/* - * V4L2 Driver for SuperH Mobile CEU interface - * - * Copyright (C) 2008 Magnus Damm - * - * Based on V4L2 Driver for PXA camera host - "pxa_camera.c", - * - * Copyright (C) 2006, Sascha Hauer, Pengutronix - * Copyright (C) 2008, Guennadi Liakhovetski - * - * 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, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* register offsets for sh7722 / sh7723 */ - -#define CAPSR 0x00 /* Capture start register */ -#define CAPCR 0x04 /* Capture control register */ -#define CAMCR 0x08 /* Capture interface control register */ -#define CMCYR 0x0c /* Capture interface cycle register */ -#define CAMOR 0x10 /* Capture interface offset register */ -#define CAPWR 0x14 /* Capture interface width register */ -#define CAIFR 0x18 /* Capture interface input format register */ -#define CSTCR 0x20 /* Camera strobe control register (<= sh7722) */ -#define CSECR 0x24 /* Camera strobe emission count register (<= sh7722) */ -#define CRCNTR 0x28 /* CEU register control register */ -#define CRCMPR 0x2c /* CEU register forcible control register */ -#define CFLCR 0x30 /* Capture filter control register */ -#define CFSZR 0x34 /* Capture filter size clip register */ -#define CDWDR 0x38 /* Capture destination width register */ -#define CDAYR 0x3c /* Capture data address Y register */ -#define CDACR 0x40 /* Capture data address C register */ -#define CDBYR 0x44 /* Capture data bottom-field address Y register */ -#define CDBCR 0x48 /* Capture data bottom-field address C register */ -#define CBDSR 0x4c /* Capture bundle destination size register */ -#define CFWCR 0x5c /* Firewall operation control register */ -#define CLFCR 0x60 /* Capture low-pass filter control register */ -#define CDOCR 0x64 /* Capture data output control register */ -#define CDDCR 0x68 /* Capture data complexity level register */ -#define CDDAR 0x6c /* Capture data complexity level address register */ -#define CEIER 0x70 /* Capture event interrupt enable register */ -#define CETCR 0x74 /* Capture event flag clear register */ -#define CSTSR 0x7c /* Capture status register */ -#define CSRTR 0x80 /* Capture software reset register */ -#define CDSSR 0x84 /* Capture data size register */ -#define CDAYR2 0x90 /* Capture data address Y register 2 */ -#define CDACR2 0x94 /* Capture data address C register 2 */ -#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */ -#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */ - -#undef DEBUG_GEOMETRY -#ifdef DEBUG_GEOMETRY -#define dev_geo dev_info -#else -#define dev_geo dev_dbg -#endif - -/* per video frame buffer */ -struct sh_mobile_ceu_buffer { - struct vb2_buffer vb; /* v4l buffer must be first */ - struct list_head queue; - enum v4l2_mbus_pixelcode code; -}; - -struct sh_mobile_ceu_dev { - struct soc_camera_host ici; - struct soc_camera_device *icd; - - unsigned int irq; - void __iomem *base; - unsigned long video_limit; - - spinlock_t lock; /* Protects video buffer lists */ - struct list_head capture; - struct vb2_buffer *active; - struct vb2_alloc_ctx *alloc_ctx; - - struct sh_mobile_ceu_info *pdata; - - u32 cflcr; - - enum v4l2_field field; - int sequence; - - unsigned int image_mode:1; - unsigned int is_16bit:1; -}; - -struct sh_mobile_ceu_cam { - /* CEU offsets within scaled by the CEU camera output */ - unsigned int ceu_left; - unsigned int ceu_top; - /* Client output, as seen by the CEU */ - unsigned int width; - unsigned int height; - /* - * User window from S_CROP / G_CROP, produced by client cropping and - * scaling, CEU scaling and CEU cropping, mapped back onto the client - * input window - */ - struct v4l2_rect subrect; - /* Camera cropping rectangle */ - struct v4l2_rect rect; - const struct soc_mbus_pixelfmt *extra_fmt; - enum v4l2_mbus_pixelcode code; -}; - -static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb) -{ - return container_of(vb, struct sh_mobile_ceu_buffer, vb); -} - -static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) -{ - unsigned long flags; - - flags = SOCAM_MASTER | - SOCAM_PCLK_SAMPLE_RISING | - SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH; - - if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS) - flags |= SOCAM_DATAWIDTH_8; - - if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS) - flags |= SOCAM_DATAWIDTH_16; - - if (flags & SOCAM_DATAWIDTH_MASK) - return flags; - - return 0; -} - -static void ceu_write(struct sh_mobile_ceu_dev *priv, - unsigned long reg_offs, u32 data) -{ - iowrite32(data, priv->base + reg_offs); -} - -static u32 ceu_read(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs) -{ - return ioread32(priv->base + reg_offs); -} - -static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) -{ - int i, success = 0; - struct soc_camera_device *icd = pcdev->icd; - - ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ - - /* wait CSTSR.CPTON bit */ - for (i = 0; i < 1000; i++) { - if (!(ceu_read(pcdev, CSTSR) & 1)) { - success++; - break; - } - udelay(1); - } - - /* wait CAPSR.CPKIL bit */ - for (i = 0; i < 1000; i++) { - if (!(ceu_read(pcdev, CAPSR) & (1 << 16))) { - success++; - break; - } - udelay(1); - } - - - if (2 != success) { - dev_warn(&icd->dev, "soft reset time out\n"); - return -EIO; - } - - return 0; -} - -/* - * Videobuf operations - */ -static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, - unsigned int *count, unsigned int *num_planes, - unsigned long sizes[], void *alloc_ctxs[]) -{ - struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - if (bytes_per_line < 0) - return bytes_per_line; - - *num_planes = 1; - - pcdev->sequence = 0; - sizes[0] = bytes_per_line * icd->user_height; - alloc_ctxs[0] = pcdev->alloc_ctx; - - if (!*count) - *count = 2; - - if (pcdev->video_limit) { - if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit) - *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]); - } - - dev_dbg(icd->dev.parent, "count=%d, size=%lu\n", *count, sizes[0]); - - return 0; -} - -#define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */ -#define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */ -#define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */ -#define CEU_CEIER_VBP (1 << 20) /* vbp error */ -#define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */ -#define CEU_CEIER_MASK (CEU_CEIER_CPEIE | CEU_CEIER_VBP) - - -/* - * return value doesn't reflex the success/failure to queue the new buffer, - * but rather the status of the previous buffer. - */ -static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) -{ - struct soc_camera_device *icd = pcdev->icd; - dma_addr_t phys_addr_top, phys_addr_bottom; - unsigned long top1, top2; - unsigned long bottom1, bottom2; - u32 status; - int ret = 0; - - /* - * The hardware is _very_ picky about this sequence. Especially - * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge - * several not-so-well documented interrupt sources in CETCR. - */ - ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK); - status = ceu_read(pcdev, CETCR); - ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC); - ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK); - ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP); - ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW); - - /* - * When a VBP interrupt occurs, a capture end interrupt does not occur - * and the image of that frame is not captured correctly. So, soft reset - * is needed here. - */ - if (status & CEU_CEIER_VBP) { - sh_mobile_ceu_soft_reset(pcdev); - ret = -EIO; - } - - if (!pcdev->active) - return ret; - - if (V4L2_FIELD_INTERLACED_BT == pcdev->field) { - top1 = CDBYR; - top2 = CDBCR; - bottom1 = CDAYR; - bottom2 = CDACR; - } else { - top1 = CDAYR; - top2 = CDACR; - bottom1 = CDBYR; - bottom2 = CDBCR; - } - - phys_addr_top = vb2_dma_contig_plane_paddr(pcdev->active, 0); - - ceu_write(pcdev, top1, phys_addr_top); - if (V4L2_FIELD_NONE != pcdev->field) { - phys_addr_bottom = phys_addr_top + icd->user_width; - ceu_write(pcdev, bottom1, phys_addr_bottom); - } - - switch (icd->current_fmt->host_fmt->fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - phys_addr_top += icd->user_width * - icd->user_height; - ceu_write(pcdev, top2, phys_addr_top); - if (V4L2_FIELD_NONE != pcdev->field) { - phys_addr_bottom = phys_addr_top + icd->user_width; - ceu_write(pcdev, bottom2, phys_addr_bottom); - } - } - - ceu_write(pcdev, CAPSR, 0x1); /* start capture */ - - return ret; -} - -static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); - struct sh_mobile_ceu_buffer *buf; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - unsigned long size; - - if (bytes_per_line < 0) - return bytes_per_line; - - buf = to_ceu_vb(vb); - - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, - vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - - /* Added list head initialization on alloc */ - WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); - -#ifdef DEBUG - /* - * This can be useful if you want to see if we actually fill - * the buffer with something - */ - if (vb2_plane_vaddr(vb, 0)) - memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); -#endif - - BUG_ON(NULL == icd->current_fmt); - - size = icd->user_height * bytes_per_line; - - if (vb2_plane_size(vb, 0) < size) { - dev_err(icd->dev.parent, "Buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); - return -ENOBUFS; - } - - vb2_set_plane_payload(vb, 0, size); - - return 0; -} - -static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); - unsigned long flags; - - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, - vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - - spin_lock_irqsave(&pcdev->lock, flags); - list_add_tail(&buf->queue, &pcdev->capture); - - if (!pcdev->active) { - /* - * Because there were no active buffer at this moment, - * we are not interested in the return value of - * sh_mobile_ceu_capture here. - */ - pcdev->active = vb; - sh_mobile_ceu_capture(pcdev); - } - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - unsigned long flags; - - spin_lock_irqsave(&pcdev->lock, flags); - - if (pcdev->active == vb) { - /* disable capture (release DMA buffer), reset */ - ceu_write(pcdev, CAPSR, 1 << 16); - pcdev->active = NULL; - } - - /* Doesn't hurt also if the list is empty */ - list_del_init(&buf->queue); - - spin_unlock_irqrestore(&pcdev->lock, flags); -} - -static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) -{ - /* This is for locking debugging only */ - INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); - return 0; -} - -static struct vb2_ops sh_mobile_ceu_videobuf_ops = { - .queue_setup = sh_mobile_ceu_videobuf_setup, - .buf_prepare = sh_mobile_ceu_videobuf_prepare, - .buf_queue = sh_mobile_ceu_videobuf_queue, - .buf_cleanup = sh_mobile_ceu_videobuf_release, - .buf_init = sh_mobile_ceu_videobuf_init, - .wait_prepare = soc_camera_unlock, - .wait_finish = soc_camera_lock, -}; - -static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) -{ - struct sh_mobile_ceu_dev *pcdev = data; - struct vb2_buffer *vb; - int ret; - - spin_lock(&pcdev->lock); - - vb = pcdev->active; - if (!vb) - /* Stale interrupt from a released buffer */ - goto out; - - list_del_init(&to_ceu_vb(vb)->queue); - - if (!list_empty(&pcdev->capture)) - pcdev->active = &list_entry(pcdev->capture.next, - struct sh_mobile_ceu_buffer, queue)->vb; - else - pcdev->active = NULL; - - ret = sh_mobile_ceu_capture(pcdev); - do_gettimeofday(&vb->v4l2_buf.timestamp); - if (!ret) { - vb->v4l2_buf.field = pcdev->field; - vb->v4l2_buf.sequence = pcdev->sequence++; - } - vb2_buffer_done(vb, ret < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - -out: - spin_unlock(&pcdev->lock); - - return IRQ_HANDLED; -} - -/* Called with .video_lock held */ -static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - int ret; - - if (pcdev->icd) - return -EBUSY; - - dev_info(icd->dev.parent, - "SuperH Mobile CEU driver attached to camera %d\n", - icd->devnum); - - pm_runtime_get_sync(ici->v4l2_dev.dev); - - ret = sh_mobile_ceu_soft_reset(pcdev); - if (!ret) - pcdev->icd = icd; - - return ret; -} - -/* Called with .video_lock held */ -static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - unsigned long flags; - - BUG_ON(icd != pcdev->icd); - - /* disable capture, disable interrupts */ - ceu_write(pcdev, CEIER, 0); - sh_mobile_ceu_soft_reset(pcdev); - - /* make sure active buffer is canceled */ - spin_lock_irqsave(&pcdev->lock, flags); - if (pcdev->active) { - list_del_init(&to_ceu_vb(pcdev->active)->queue); - vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR); - pcdev->active = NULL; - } - spin_unlock_irqrestore(&pcdev->lock, flags); - - pm_runtime_put_sync(ici->v4l2_dev.dev); - - dev_info(icd->dev.parent, - "SuperH Mobile CEU driver detached from camera %d\n", - icd->devnum); - - pcdev->icd = NULL; -} - -/* - * See chapter 29.4.12 "Capture Filter Control Register (CFLCR)" - * in SH7722 Hardware Manual - */ -static unsigned int size_dst(unsigned int src, unsigned int scale) -{ - unsigned int mant_pre = scale >> 12; - if (!src || !scale) - return src; - return ((mant_pre + 2 * (src - 1)) / (2 * mant_pre) - 1) * - mant_pre * 4096 / scale + 1; -} - -static u16 calc_scale(unsigned int src, unsigned int *dst) -{ - u16 scale; - - if (src == *dst) - return 0; - - scale = (src * 4096 / *dst) & ~7; - - while (scale > 4096 && size_dst(src, scale) < *dst) - scale -= 8; - - *dst = size_dst(src, scale); - - return scale; -} - -/* rect is guaranteed to not exceed the scaled camera rectangle */ -static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct sh_mobile_ceu_dev *pcdev = ici->priv; - unsigned int height, width, cdwdr_width, in_width, in_height; - unsigned int left_offset, top_offset; - u32 camor; - - dev_geo(icd->dev.parent, "Crop %ux%u@%u:%u\n", - icd->user_width, icd->user_height, cam->ceu_left, cam->ceu_top); - - left_offset = cam->ceu_left; - top_offset = cam->ceu_top; - - /* CEU cropping (CFSZR) is applied _after_ the scaling filter (CFLCR) */ - if (pcdev->image_mode) { - in_width = cam->width; - if (!pcdev->is_16bit) { - in_width *= 2; - left_offset *= 2; - } - width = icd->user_width; - cdwdr_width = icd->user_width; - } else { - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - unsigned int w_factor; - - width = icd->user_width; - - switch (icd->current_fmt->host_fmt->packing) { - case SOC_MBUS_PACKING_2X8_PADHI: - w_factor = 2; - break; - default: - w_factor = 1; - } - - in_width = cam->width * w_factor; - left_offset = left_offset * w_factor; - - if (bytes_per_line < 0) - cdwdr_width = icd->user_width; - else - cdwdr_width = bytes_per_line; - } - - height = icd->user_height; - in_height = cam->height; - if (V4L2_FIELD_NONE != pcdev->field) { - height /= 2; - in_height /= 2; - top_offset /= 2; - cdwdr_width *= 2; - } - - /* CSI2 special configuration */ - if (pcdev->pdata->csi2_dev) { - in_width = ((in_width - 2) * 2); - left_offset *= 2; - } - - /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */ - camor = left_offset | (top_offset << 16); - - dev_geo(icd->dev.parent, - "CAMOR 0x%x, CAPWR 0x%x, CFSZR 0x%x, CDWDR 0x%x\n", camor, - (in_height << 16) | in_width, (height << 16) | width, - cdwdr_width); - - ceu_write(pcdev, CAMOR, camor); - ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); - ceu_write(pcdev, CFSZR, (height << 16) | width); - ceu_write(pcdev, CDWDR, cdwdr_width); -} - -static u32 capture_save_reset(struct sh_mobile_ceu_dev *pcdev) -{ - u32 capsr = ceu_read(pcdev, CAPSR); - ceu_write(pcdev, CAPSR, 1 << 16); /* reset, stop capture */ - return capsr; -} - -static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) -{ - unsigned long timeout = jiffies + 10 * HZ; - - /* - * Wait until the end of the current frame. It can take a long time, - * but if it has been aborted by a CAPSR reset, it shoule exit sooner. - */ - while ((ceu_read(pcdev, CSTSR) & 1) && time_before(jiffies, timeout)) - msleep(1); - - if (time_after(jiffies, timeout)) { - dev_err(pcdev->ici.v4l2_dev.dev, - "Timeout waiting for frame end! Interface problem?\n"); - return; - } - - /* Wait until reset clears, this shall not hang... */ - while (ceu_read(pcdev, CAPSR) & (1 << 16)) - udelay(10); - - /* Anything to restore? */ - if (capsr & ~(1 << 16)) - ceu_write(pcdev, CAPSR, capsr); -} - -/* Capture is not running, no interrupts, no locking needed */ -static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, - __u32 pixfmt) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - int ret; - unsigned long camera_flags, common_flags, value; - int yuv_lineskip; - struct sh_mobile_ceu_cam *cam = icd->host_priv; - u32 capsr = capture_save_reset(pcdev); - - camera_flags = icd->ops->query_bus_param(icd); - common_flags = soc_camera_bus_param_compatible(camera_flags, - make_bus_param(pcdev)); - if (!common_flags) - return -EINVAL; - - /* Make choises, based on platform preferences */ - if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { - if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) - common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; - else - common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; - } - - if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && - (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { - if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) - common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; - else - common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; - } - - ret = icd->ops->set_bus_param(icd, common_flags); - if (ret < 0) - return ret; - - switch (common_flags & SOCAM_DATAWIDTH_MASK) { - case SOCAM_DATAWIDTH_8: - pcdev->is_16bit = 0; - break; - case SOCAM_DATAWIDTH_16: - pcdev->is_16bit = 1; - break; - default: - return -EINVAL; - } - - ceu_write(pcdev, CRCNTR, 0); - ceu_write(pcdev, CRCMPR, 0); - - value = 0x00000010; /* data fetch by default */ - yuv_lineskip = 0; - - switch (icd->current_fmt->host_fmt->fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */ - /* fall-through */ - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - switch (cam->code) { - case V4L2_MBUS_FMT_UYVY8_2X8: - value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ - break; - case V4L2_MBUS_FMT_VYUY8_2X8: - value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */ - break; - case V4L2_MBUS_FMT_YUYV8_2X8: - value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */ - break; - case V4L2_MBUS_FMT_YVYU8_2X8: - value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */ - break; - default: - BUG(); - } - } - - if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV21 || - icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) - value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ - - value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; - value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; - value |= pcdev->is_16bit ? 1 << 12 : 0; - - /* CSI2 mode */ - if (pcdev->pdata->csi2_dev) - value |= 3 << 12; - - ceu_write(pcdev, CAMCR, value); - - ceu_write(pcdev, CAPCR, 0x00300000); - - switch (pcdev->field) { - case V4L2_FIELD_INTERLACED_TB: - value = 0x101; - break; - case V4L2_FIELD_INTERLACED_BT: - value = 0x102; - break; - default: - value = 0; - break; - } - ceu_write(pcdev, CAIFR, value); - - sh_mobile_ceu_set_rect(icd); - mdelay(1); - - dev_geo(icd->dev.parent, "CFLCR 0x%x\n", pcdev->cflcr); - ceu_write(pcdev, CFLCR, pcdev->cflcr); - - /* - * A few words about byte order (observed in Big Endian mode) - * - * In data fetch mode bytes are received in chunks of 8 bytes. - * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) - * - * The data is however by default written to memory in reverse order: - * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte) - * - * The lowest three bits of CDOCR allows us to do swapping, - * using 7 we swap the data bytes to match the incoming order: - * D0, D1, D2, D3, D4, D5, D6, D7 - */ - value = 0x00000017; - if (yuv_lineskip) - value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */ - - ceu_write(pcdev, CDOCR, value); - ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ - - dev_dbg(icd->dev.parent, "S_FMT successful for %c%c%c%c %ux%u\n", - pixfmt & 0xff, (pixfmt >> 8) & 0xff, - (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff, - icd->user_width, icd->user_height); - - capture_restore(pcdev, capsr); - - /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ - return 0; -} - -static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, - unsigned char buswidth) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - unsigned long camera_flags, common_flags; - - camera_flags = icd->ops->query_bus_param(icd); - common_flags = soc_camera_bus_param_compatible(camera_flags, - make_bus_param(pcdev)); - if (!common_flags || buswidth > 16 || - (buswidth > 8 && !(common_flags & SOCAM_DATAWIDTH_16))) - return -EINVAL; - - return 0; -} - -static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { - { - .fourcc = V4L2_PIX_FMT_NV12, - .name = "NV12", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - }, { - .fourcc = V4L2_PIX_FMT_NV21, - .name = "NV21", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - }, { - .fourcc = V4L2_PIX_FMT_NV16, - .name = "NV16", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - }, { - .fourcc = V4L2_PIX_FMT_NV61, - .name = "NV61", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - }, -}; - -/* This will be corrected as we get more formats */ -static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) -{ - return fmt->packing == SOC_MBUS_PACKING_NONE || - (fmt->bits_per_sample == 8 && - fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || - (fmt->bits_per_sample > 8 && - fmt->packing == SOC_MBUS_PACKING_EXTEND16); -} - -static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); - -static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, - struct soc_camera_format_xlate *xlate) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->dev.parent; - struct soc_camera_host *ici = to_soc_camera_host(dev); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - int ret, k, n; - int formats = 0; - struct sh_mobile_ceu_cam *cam; - enum v4l2_mbus_pixelcode code; - const struct soc_mbus_pixelfmt *fmt; - - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); - if (ret < 0) - /* No more formats */ - return 0; - - fmt = soc_mbus_get_fmtdesc(code); - if (!fmt) { - dev_err(dev, "Invalid format code #%u: %d\n", idx, code); - return -EINVAL; - } - - if (!pcdev->pdata->csi2_dev) { - ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); - if (ret < 0) - return 0; - } - - if (!icd->host_priv) { - struct v4l2_mbus_framefmt mf; - struct v4l2_rect rect; - int shift = 0; - - /* FIXME: subwindow is lost between close / open */ - - /* Cache current client geometry */ - ret = client_g_rect(sd, &rect); - if (ret < 0) - return ret; - - /* First time */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); - if (ret < 0) - return ret; - - while ((mf.width > 2560 || mf.height > 1920) && shift < 4) { - /* Try 2560x1920, 1280x960, 640x480, 320x240 */ - mf.width = 2560 >> shift; - mf.height = 1920 >> shift; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, - s_mbus_fmt, &mf); - if (ret < 0) - return ret; - shift++; - } - - if (shift == 4) { - dev_err(dev, "Failed to configure the client below %ux%x\n", - mf.width, mf.height); - return -EIO; - } - - dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height); - - cam = kzalloc(sizeof(*cam), GFP_KERNEL); - if (!cam) - return -ENOMEM; - - /* We are called with current camera crop, initialise subrect with it */ - cam->rect = rect; - cam->subrect = rect; - - cam->width = mf.width; - cam->height = mf.height; - - cam->width = mf.width; - cam->height = mf.height; - - icd->host_priv = cam; - } else { - cam = icd->host_priv; - } - - /* Beginning of a pass */ - if (!idx) - cam->extra_fmt = NULL; - - switch (code) { - case V4L2_MBUS_FMT_UYVY8_2X8: - case V4L2_MBUS_FMT_VYUY8_2X8: - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_YVYU8_2X8: - if (cam->extra_fmt) - break; - - /* - * Our case is simple so far: for any of the above four camera - * formats we add all our four synthesized NV* formats, so, - * just marking the device with a single flag suffices. If - * the format generation rules are more complex, you would have - * to actually hang your already added / counted formats onto - * the host_priv pointer and check whether the format you're - * going to add now is already there. - */ - cam->extra_fmt = sh_mobile_ceu_formats; - - n = ARRAY_SIZE(sh_mobile_ceu_formats); - formats += n; - for (k = 0; xlate && k < n; k++) { - xlate->host_fmt = &sh_mobile_ceu_formats[k]; - xlate->code = code; - xlate++; - dev_dbg(dev, "Providing format %s using code %d\n", - sh_mobile_ceu_formats[k].name, code); - } - break; - default: - if (!sh_mobile_ceu_packing_supported(fmt)) - return 0; - } - - /* Generic pass-through */ - formats++; - if (xlate) { - xlate->host_fmt = fmt; - xlate->code = code; - xlate++; - dev_dbg(dev, "Providing format %s in pass-through mode\n", - fmt->name); - } - - return formats; -} - -static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd) -{ - kfree(icd->host_priv); - icd->host_priv = NULL; -} - -/* Check if any dimension of r1 is smaller than respective one of r2 */ -static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2) -{ - return r1->width < r2->width || r1->height < r2->height; -} - -/* Check if r1 fails to cover r2 */ -static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2) -{ - return r1->left > r2->left || r1->top > r2->top || - r1->left + r1->width < r2->left + r2->width || - r1->top + r1->height < r2->top + r2->height; -} - -static unsigned int scale_down(unsigned int size, unsigned int scale) -{ - return (size * 4096 + scale / 2) / scale; -} - -static unsigned int calc_generic_scale(unsigned int input, unsigned int output) -{ - return (input * 4096 + output / 2) / output; -} - -/* Get and store current client crop */ -static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) -{ - struct v4l2_crop crop; - struct v4l2_cropcap cap; - int ret; - - crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - ret = v4l2_subdev_call(sd, video, g_crop, &crop); - if (!ret) { - *rect = crop.c; - return ret; - } - - /* Camera driver doesn't support .g_crop(), assume default rectangle */ - cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - ret = v4l2_subdev_call(sd, video, cropcap, &cap); - if (!ret) - *rect = cap.defrect; - - return ret; -} - -/* Client crop has changed, update our sub-rectangle to remain within the area */ -static void update_subrect(struct sh_mobile_ceu_cam *cam) -{ - struct v4l2_rect *rect = &cam->rect, *subrect = &cam->subrect; - - if (rect->width < subrect->width) - subrect->width = rect->width; - - if (rect->height < subrect->height) - subrect->height = rect->height; - - if (rect->left > subrect->left) - subrect->left = rect->left; - else if (rect->left + rect->width > - subrect->left + subrect->width) - subrect->left = rect->left + rect->width - - subrect->width; - - if (rect->top > subrect->top) - subrect->top = rect->top; - else if (rect->top + rect->height > - subrect->top + subrect->height) - subrect->top = rect->top + rect->height - - subrect->height; -} - -/* - * The common for both scaling and cropping iterative approach is: - * 1. try if the client can produce exactly what requested by the user - * 2. if (1) failed, try to double the client image until we get one big enough - * 3. if (2) failed, try to request the maximum image - */ -static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, - struct v4l2_crop *cam_crop) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c; - struct device *dev = sd->v4l2_dev->dev; - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct v4l2_cropcap cap; - int ret; - unsigned int width, height; - - v4l2_subdev_call(sd, video, s_crop, crop); - ret = client_g_rect(sd, cam_rect); - if (ret < 0) - return ret; - - /* - * Now cam_crop contains the current camera input rectangle, and it must - * be within camera cropcap bounds - */ - if (!memcmp(rect, cam_rect, sizeof(*rect))) { - /* Even if camera S_CROP failed, but camera rectangle matches */ - dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n", - rect->width, rect->height, rect->left, rect->top); - cam->rect = *cam_rect; - return 0; - } - - /* Try to fix cropping, that camera hasn't managed to set */ - dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n", - cam_rect->width, cam_rect->height, - cam_rect->left, cam_rect->top, - rect->width, rect->height, rect->left, rect->top); - - /* We need sensor maximum rectangle */ - ret = v4l2_subdev_call(sd, video, cropcap, &cap); - if (ret < 0) - return ret; - - /* Put user requested rectangle within sensor bounds */ - soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2, - cap.bounds.width); - soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4, - cap.bounds.height); - - /* - * Popular special case - some cameras can only handle fixed sizes like - * QVGA, VGA,... Take care to avoid infinite loop. - */ - width = max(cam_rect->width, 2); - height = max(cam_rect->height, 2); - - /* - * Loop as long as sensor is not covering the requested rectangle and - * is still within its bounds - */ - while (!ret && (is_smaller(cam_rect, rect) || - is_inside(cam_rect, rect)) && - (cap.bounds.width > width || cap.bounds.height > height)) { - - width *= 2; - height *= 2; - - cam_rect->width = width; - cam_rect->height = height; - - /* - * We do not know what capabilities the camera has to set up - * left and top borders. We could try to be smarter in iterating - * them, e.g., if camera current left is to the right of the - * target left, set it to the middle point between the current - * left and minimum left. But that would add too much - * complexity: we would have to iterate each border separately. - * Instead we just drop to the left and top bounds. - */ - if (cam_rect->left > rect->left) - cam_rect->left = cap.bounds.left; - - if (cam_rect->left + cam_rect->width < rect->left + rect->width) - cam_rect->width = rect->left + rect->width - - cam_rect->left; - - if (cam_rect->top > rect->top) - cam_rect->top = cap.bounds.top; - - if (cam_rect->top + cam_rect->height < rect->top + rect->height) - cam_rect->height = rect->top + rect->height - - cam_rect->top; - - v4l2_subdev_call(sd, video, s_crop, cam_crop); - ret = client_g_rect(sd, cam_rect); - dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret, - cam_rect->width, cam_rect->height, - cam_rect->left, cam_rect->top); - } - - /* S_CROP must not modify the rectangle */ - if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) { - /* - * The camera failed to configure a suitable cropping, - * we cannot use the current rectangle, set to max - */ - *cam_rect = cap.bounds; - v4l2_subdev_call(sd, video, s_crop, cam_crop); - ret = client_g_rect(sd, cam_rect); - dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret, - cam_rect->width, cam_rect->height, - cam_rect->left, cam_rect->top); - } - - if (!ret) { - cam->rect = *cam_rect; - update_subrect(cam); - } - - return ret; -} - -/* Iterative s_mbus_fmt, also updates cached client crop on success */ -static int client_s_fmt(struct soc_camera_device *icd, - struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) -{ - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->dev.parent; - unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; - unsigned int max_width, max_height; - struct v4l2_cropcap cap; - int ret; - - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, - s_mbus_fmt, mf); - if (ret < 0) - return ret; - - dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); - - if ((width == mf->width && height == mf->height) || !ceu_can_scale) - goto update_cache; - - cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - ret = v4l2_subdev_call(sd, video, cropcap, &cap); - if (ret < 0) - return ret; - - max_width = min(cap.bounds.width, 2560); - max_height = min(cap.bounds.height, 1920); - - /* Camera set a format, but geometry is not precise, try to improve */ - tmp_w = mf->width; - tmp_h = mf->height; - - /* width <= max_width && height <= max_height - guaranteed by try_fmt */ - while ((width > tmp_w || height > tmp_h) && - tmp_w < max_width && tmp_h < max_height) { - tmp_w = min(2 * tmp_w, max_width); - tmp_h = min(2 * tmp_h, max_height); - mf->width = tmp_w; - mf->height = tmp_h; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, - s_mbus_fmt, mf); - dev_geo(dev, "Camera scaled to %ux%u\n", - mf->width, mf->height); - if (ret < 0) { - /* This shouldn't happen */ - dev_err(dev, "Client failed to set format: %d\n", ret); - return ret; - } - } - -update_cache: - /* Update cache */ - ret = client_g_rect(sd, &cam->rect); - if (ret < 0) - return ret; - - update_subrect(cam); - - return 0; -} - -/** - * @width - on output: user width, mapped back to input - * @height - on output: user height, mapped back to input - * @mf - in- / output camera output window - */ -static int client_scale(struct soc_camera_device *icd, - struct v4l2_mbus_framefmt *mf, - unsigned int *width, unsigned int *height, - bool ceu_can_scale) -{ - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct device *dev = icd->dev.parent; - struct v4l2_mbus_framefmt mf_tmp = *mf; - unsigned int scale_h, scale_v; - int ret; - - /* - * 5. Apply iterative camera S_FMT for camera user window (also updates - * client crop cache and the imaginary sub-rectangle). - */ - ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale); - if (ret < 0) - return ret; - - dev_geo(dev, "5: camera scaled to %ux%u\n", - mf_tmp.width, mf_tmp.height); - - /* 6. Retrieve camera output window (g_fmt) */ - - /* unneeded - it is already in "mf_tmp" */ - - /* 7. Calculate new client scales. */ - scale_h = calc_generic_scale(cam->rect.width, mf_tmp.width); - scale_v = calc_generic_scale(cam->rect.height, mf_tmp.height); - - mf->width = mf_tmp.width; - mf->height = mf_tmp.height; - mf->colorspace = mf_tmp.colorspace; - - /* - * 8. Calculate new CEU crop - apply camera scales to previously - * updated "effective" crop. - */ - *width = scale_down(cam->subrect.width, scale_h); - *height = scale_down(cam->subrect.height, scale_v); - - dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height); - - return 0; -} - -/* - * CEU can scale and crop, but we don't want to waste bandwidth and kill the - * framerate by always requesting the maximum image from the client. See - * Documentation/video4linux/sh_mobile_camera_ceu.txt for a description of - * scaling and cropping algorithms and for the meaning of referenced here steps. - */ -static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) -{ - struct v4l2_rect *rect = &a->c; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct v4l2_crop cam_crop; - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct v4l2_rect *cam_rect = &cam_crop.c; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->dev.parent; - struct v4l2_mbus_framefmt mf; - unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v, - out_width, out_height; - int interm_width, interm_height; - u32 capsr, cflcr; - int ret; - - dev_geo(dev, "S_CROP(%ux%u@%u:%u)\n", rect->width, rect->height, - rect->left, rect->top); - - /* During camera cropping its output window can change too, stop CEU */ - capsr = capture_save_reset(pcdev); - dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); - - /* 1. - 2. Apply iterative camera S_CROP for new input window. */ - ret = client_s_crop(icd, a, &cam_crop); - if (ret < 0) - return ret; - - dev_geo(dev, "1-2: camera cropped to %ux%u@%u:%u\n", - cam_rect->width, cam_rect->height, - cam_rect->left, cam_rect->top); - - /* On success cam_crop contains current camera crop */ - - /* 3. Retrieve camera output window */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); - if (ret < 0) - return ret; - - if (mf.width > 2560 || mf.height > 1920) - return -EINVAL; - - /* Cache camera output window */ - cam->width = mf.width; - cam->height = mf.height; - - /* 4. Calculate camera scales */ - scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); - scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); - - /* Calculate intermediate window */ - interm_width = scale_down(rect->width, scale_cam_h); - interm_height = scale_down(rect->height, scale_cam_v); - - if (pcdev->image_mode) { - out_width = min(interm_width, icd->user_width); - out_height = min(interm_height, icd->user_height); - } else { - out_width = interm_width; - out_height = interm_height; - } - - /* - * 5. Calculate CEU scales from camera scales from results of (5) and - * the user window - */ - scale_ceu_h = calc_scale(interm_width, &out_width); - scale_ceu_v = calc_scale(interm_height, &out_height); - - dev_geo(dev, "5: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v); - - /* Apply CEU scales. */ - cflcr = scale_ceu_h | (scale_ceu_v << 16); - if (cflcr != pcdev->cflcr) { - pcdev->cflcr = cflcr; - ceu_write(pcdev, CFLCR, cflcr); - } - - icd->user_width = out_width; - icd->user_height = out_height; - cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; - cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; - - /* 6. Use CEU cropping to crop to the new window. */ - sh_mobile_ceu_set_rect(icd); - - cam->subrect = *rect; - - dev_geo(dev, "6: CEU cropped to %ux%u@%u:%u\n", - icd->user_width, icd->user_height, - cam->ceu_left, cam->ceu_top); - - /* Restore capture. The CE bit can be cleared by the hardware */ - if (pcdev->active) - capsr |= 1; - capture_restore(pcdev, capsr); - - /* Even if only camera cropping succeeded */ - return ret; -} - -static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) -{ - struct sh_mobile_ceu_cam *cam = icd->host_priv; - - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->c = cam->subrect; - - return 0; -} - -/* - * Calculate real client output window by applying new scales to the current - * client crop. New scales are calculated from the requested output format and - * CEU crop, mapped backed onto the client input (subrect). - */ -static void calculate_client_output(struct soc_camera_device *icd, - struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) -{ - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct device *dev = icd->dev.parent; - struct v4l2_rect *cam_subrect = &cam->subrect; - unsigned int scale_v, scale_h; - - if (cam_subrect->width == cam->rect.width && - cam_subrect->height == cam->rect.height) { - /* No sub-cropping */ - mf->width = pix->width; - mf->height = pix->height; - return; - } - - /* 1.-2. Current camera scales and subwin - cached. */ - - dev_geo(dev, "2: subwin %ux%u@%u:%u\n", - cam_subrect->width, cam_subrect->height, - cam_subrect->left, cam_subrect->top); - - /* - * 3. Calculate new combined scales from input sub-window to requested - * user window. - */ - - /* - * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF - * (128x96) or larger than VGA - */ - scale_h = calc_generic_scale(cam_subrect->width, pix->width); - scale_v = calc_generic_scale(cam_subrect->height, pix->height); - - dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); - - /* - * 4. Calculate client output window by applying combined scales to real - * input window. - */ - mf->width = scale_down(cam->rect.width, scale_h); - mf->height = scale_down(cam->rect.height, scale_v); -} - -/* Similar to set_crop multistage iterative algorithm */ -static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - struct device *dev = icd->dev.parent; - __u32 pixfmt = pix->pixelformat; - const struct soc_camera_format_xlate *xlate; - /* Keep Compiler Happy */ - unsigned int ceu_sub_width = 0, ceu_sub_height = 0; - u16 scale_v, scale_h; - int ret; - bool image_mode; - enum v4l2_field field; - - dev_geo(dev, "S_FMT(pix=0x%x, %ux%u)\n", pixfmt, pix->width, pix->height); - - switch (pix->field) { - default: - pix->field = V4L2_FIELD_NONE; - /* fall-through */ - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: - case V4L2_FIELD_NONE: - field = pix->field; - break; - case V4L2_FIELD_INTERLACED: - field = V4L2_FIELD_INTERLACED_TB; - break; - } - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - dev_warn(dev, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - /* 1.-4. Calculate client output geometry */ - calculate_client_output(icd, &f->fmt.pix, &mf); - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - switch (pixfmt) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - image_mode = true; - break; - default: - image_mode = false; - } - - dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); - - /* 5. - 9. */ - ret = client_scale(icd, &mf, &ceu_sub_width, &ceu_sub_height, - image_mode && V4L2_FIELD_NONE == field); - - dev_geo(dev, "5-9: client scale return %d\n", ret); - - /* Done with the camera. Now see if we can improve the result */ - - dev_geo(dev, "fmt %ux%u, requested %ux%u\n", - mf.width, mf.height, pix->width, pix->height); - if (ret < 0) - return ret; - - if (mf.code != xlate->code) - return -EINVAL; - - /* 9. Prepare CEU crop */ - cam->width = mf.width; - cam->height = mf.height; - - /* 10. Use CEU scaling to scale to the requested user window. */ - - /* We cannot scale up */ - if (pix->width > ceu_sub_width) - ceu_sub_width = pix->width; - - if (pix->height > ceu_sub_height) - ceu_sub_height = pix->height; - - pix->colorspace = mf.colorspace; - - if (image_mode) { - /* Scale pix->{width x height} down to width x height */ - scale_h = calc_scale(ceu_sub_width, &pix->width); - scale_v = calc_scale(ceu_sub_height, &pix->height); - } else { - pix->width = ceu_sub_width; - pix->height = ceu_sub_height; - scale_h = 0; - scale_v = 0; - } - - pcdev->cflcr = scale_h | (scale_v << 16); - - /* - * We have calculated CFLCR, the actual configuration will be performed - * in sh_mobile_ceu_set_bus_param() - */ - - dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n", - ceu_sub_width, scale_h, pix->width, - ceu_sub_height, scale_v, pix->height); - - cam->code = xlate->code; - icd->current_fmt = xlate; - - pcdev->field = field; - pcdev->image_mode = image_mode; - - return 0; -} - -static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; - __u32 pixfmt = pix->pixelformat; - int width, height; - int ret; - - dev_geo(icd->dev.parent, "TRY_FMT(pix=0x%x, %ux%u)\n", - pixfmt, pix->width, pix->height); - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - /* FIXME: calculate using depth and bus width */ - - v4l_bound_align_image(&pix->width, 2, 2560, 1, - &pix->height, 4, 1920, 2, 0); - - width = pix->width; - height = pix->height; - - pix->bytesperline = soc_mbus_bytes_per_line(width, xlate->host_fmt); - if ((int)pix->bytesperline < 0) - return pix->bytesperline; - pix->sizeimage = height * pix->bytesperline; - - /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.code = xlate->code; - mf.colorspace = pix->colorspace; - - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf); - if (ret < 0) - return ret; - - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; - - switch (pixfmt) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - /* FIXME: check against rect_max after converting soc-camera */ - /* We can scale precisely, need a bigger image from camera */ - if (pix->width < width || pix->height < height) { - /* - * We presume, the sensor behaves sanely, i.e., if - * requested a bigger rectangle, it will not return a - * smaller one. - */ - mf.width = 2560; - mf.height = 1920; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, - try_mbus_fmt, &mf); - if (ret < 0) { - /* Shouldn't actually happen... */ - dev_err(icd->dev.parent, - "FIXME: client try_fmt() = %d\n", ret); - return ret; - } - } - /* We will scale exactly */ - if (mf.width > width) - pix->width = width; - if (mf.height > height) - pix->height = height; - } - - dev_geo(icd->dev.parent, "%s(): return %d, fmt 0x%x, %ux%u\n", - __func__, ret, pix->pixelformat, pix->width, pix->height); - - return ret; -} - -static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - - return vb2_poll(&icd->vb2_vidq, file, pt); -} - -static int sh_mobile_ceu_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card)); - cap->version = KERNEL_VERSION(0, 0, 5); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - return 0; -} - -static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, - struct soc_camera_device *icd) -{ - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->drv_priv = icd; - q->ops = &sh_mobile_ceu_videobuf_ops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer); - - return vb2_queue_init(q); -} - -static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd, - struct v4l2_control *ctrl) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - u32 val; - - switch (ctrl->id) { - case V4L2_CID_SHARPNESS: - val = ceu_read(pcdev, CLFCR); - ctrl->value = val ^ 1; - return 0; - } - return -ENOIOCTLCMD; -} - -static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd, - struct v4l2_control *ctrl) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - switch (ctrl->id) { - case V4L2_CID_SHARPNESS: - switch (icd->current_fmt->host_fmt->fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - ceu_write(pcdev, CLFCR, !ctrl->value); - return 0; - } - return -EINVAL; - } - return -ENOIOCTLCMD; -} - -static const struct v4l2_queryctrl sh_mobile_ceu_controls[] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Low-pass filter", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - -static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { - .owner = THIS_MODULE, - .add = sh_mobile_ceu_add_device, - .remove = sh_mobile_ceu_remove_device, - .get_formats = sh_mobile_ceu_get_formats, - .put_formats = sh_mobile_ceu_put_formats, - .get_crop = sh_mobile_ceu_get_crop, - .set_crop = sh_mobile_ceu_set_crop, - .set_fmt = sh_mobile_ceu_set_fmt, - .try_fmt = sh_mobile_ceu_try_fmt, - .set_ctrl = sh_mobile_ceu_set_ctrl, - .get_ctrl = sh_mobile_ceu_get_ctrl, - .poll = sh_mobile_ceu_poll, - .querycap = sh_mobile_ceu_querycap, - .set_bus_param = sh_mobile_ceu_set_bus_param, - .init_videobuf2 = sh_mobile_ceu_init_videobuf, - .controls = sh_mobile_ceu_controls, - .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls), -}; - -struct bus_wait { - struct notifier_block notifier; - struct completion completion; - struct device *dev; -}; - -static int bus_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct bus_wait *wait = container_of(nb, struct bus_wait, notifier); - - if (wait->dev != dev) - return NOTIFY_DONE; - - switch (action) { - case BUS_NOTIFY_UNBOUND_DRIVER: - /* Protect from module unloading */ - wait_for_completion(&wait->completion); - return NOTIFY_OK; - } - return NOTIFY_DONE; -} - -static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) -{ - struct sh_mobile_ceu_dev *pcdev; - struct resource *res; - void __iomem *base; - unsigned int irq; - int err = 0; - struct bus_wait wait = { - .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion), - .notifier.notifier_call = bus_notify, - }; - struct device *csi2; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!res || (int)irq <= 0) { - dev_err(&pdev->dev, "Not enough CEU platform resources.\n"); - err = -ENODEV; - goto exit; - } - - pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); - if (!pcdev) { - dev_err(&pdev->dev, "Could not allocate pcdev\n"); - err = -ENOMEM; - goto exit; - } - - INIT_LIST_HEAD(&pcdev->capture); - spin_lock_init(&pcdev->lock); - - pcdev->pdata = pdev->dev.platform_data; - if (!pcdev->pdata) { - err = -EINVAL; - dev_err(&pdev->dev, "CEU platform data not set.\n"); - goto exit_kfree; - } - - base = ioremap_nocache(res->start, resource_size(res)); - if (!base) { - err = -ENXIO; - dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n"); - goto exit_kfree; - } - - pcdev->irq = irq; - pcdev->base = base; - pcdev->video_limit = 0; /* only enabled if second resource exists */ - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res) { - err = dma_declare_coherent_memory(&pdev->dev, res->start, - res->start, - resource_size(res), - DMA_MEMORY_MAP | - DMA_MEMORY_EXCLUSIVE); - if (!err) { - dev_err(&pdev->dev, "Unable to declare CEU memory.\n"); - err = -ENXIO; - goto exit_iounmap; - } - - pcdev->video_limit = resource_size(res); - } - - /* request irq */ - err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED, - dev_name(&pdev->dev), pcdev); - if (err) { - dev_err(&pdev->dev, "Unable to register CEU interrupt.\n"); - goto exit_release_mem; - } - - pm_suspend_ignore_children(&pdev->dev, true); - pm_runtime_enable(&pdev->dev); - pm_runtime_resume(&pdev->dev); - - pcdev->ici.priv = pcdev; - pcdev->ici.v4l2_dev.dev = &pdev->dev; - pcdev->ici.nr = pdev->id; - pcdev->ici.drv_name = dev_name(&pdev->dev); - pcdev->ici.ops = &sh_mobile_ceu_host_ops; - - /* CSI2 interfacing */ - csi2 = pcdev->pdata->csi2_dev; - if (csi2) { - wait.dev = csi2; - - err = bus_register_notifier(&platform_bus_type, &wait.notifier); - if (err < 0) - goto exit_free_clk; - - /* - * From this point the driver module will not unload, until - * we complete the completion. - */ - - if (!csi2->driver) { - complete(&wait.completion); - /* Either too late, or probing failed */ - bus_unregister_notifier(&platform_bus_type, &wait.notifier); - err = -ENXIO; - goto exit_free_clk; - } - - /* - * The module is still loaded, in the worst case it is hanging - * in device release on our completion. So, _now_ dereferencing - * the "owner" is safe! - */ - - err = try_module_get(csi2->driver->owner); - - /* Let notifier complete, if it has been locked */ - complete(&wait.completion); - bus_unregister_notifier(&platform_bus_type, &wait.notifier); - if (!err) { - err = -ENODEV; - goto exit_free_clk; - } - } - - pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); - if (IS_ERR(pcdev->alloc_ctx)) { - err = PTR_ERR(pcdev->alloc_ctx); - goto exit_module_put; - } - - err = soc_camera_host_register(&pcdev->ici); - if (err) - goto exit_free_ctx; - - return 0; - -exit_free_ctx: - vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); -exit_module_put: - if (csi2 && csi2->driver) - module_put(csi2->driver->owner); -exit_free_clk: - pm_runtime_disable(&pdev->dev); - free_irq(pcdev->irq, pcdev); -exit_release_mem: - if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) - dma_release_declared_memory(&pdev->dev); -exit_iounmap: - iounmap(base); -exit_kfree: - kfree(pcdev); -exit: - return err; -} - -static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, - struct sh_mobile_ceu_dev, ici); - struct device *csi2 = pcdev->pdata->csi2_dev; - - soc_camera_host_unregister(soc_host); - pm_runtime_disable(&pdev->dev); - free_irq(pcdev->irq, pcdev); - if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) - dma_release_declared_memory(&pdev->dev); - iounmap(pcdev->base); - vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); - if (csi2 && csi2->driver) - module_put(csi2->driver->owner); - kfree(pcdev); - - return 0; -} - -static int sh_mobile_ceu_runtime_nop(struct device *dev) -{ - /* Runtime PM callback shared between ->runtime_suspend() - * and ->runtime_resume(). Simply returns success. - * - * This driver re-initializes all registers after - * pm_runtime_get_sync() anyway so there is no need - * to save and restore registers here. - */ - return 0; -} - -static const struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = { - .runtime_suspend = sh_mobile_ceu_runtime_nop, - .runtime_resume = sh_mobile_ceu_runtime_nop, -}; - -static struct platform_driver sh_mobile_ceu_driver = { - .driver = { - .name = "sh_mobile_ceu", - .pm = &sh_mobile_ceu_dev_pm_ops, - }, - .probe = sh_mobile_ceu_probe, - .remove = __devexit_p(sh_mobile_ceu_remove), -}; - -static int __init sh_mobile_ceu_init(void) -{ - /* Whatever return code */ - request_module("sh_mobile_csi2"); - return platform_driver_register(&sh_mobile_ceu_driver); -} - -static void __exit sh_mobile_ceu_exit(void) -{ - platform_driver_unregister(&sh_mobile_ceu_driver); -} - -module_init(sh_mobile_ceu_init); -module_exit(sh_mobile_ceu_exit); - -MODULE_DESCRIPTION("SuperH Mobile CEU driver"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:sh_mobile_ceu"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_mobile_csi2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_mobile_csi2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_mobile_csi2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_mobile_csi2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,354 +0,0 @@ -/* - * Driver for the SH-Mobile MIPI CSI-2 unit - * - * Copyright (C) 2010, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define SH_CSI2_TREF 0x00 -#define SH_CSI2_SRST 0x04 -#define SH_CSI2_PHYCNT 0x08 -#define SH_CSI2_CHKSUM 0x0C -#define SH_CSI2_VCDT 0x10 - -struct sh_csi2 { - struct v4l2_subdev subdev; - struct list_head list; - struct notifier_block notifier; - unsigned int irq; - void __iomem *base; - struct platform_device *pdev; - struct sh_csi2_client_config *client; -}; - -static int sh_csi2_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); - struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; - - if (mf->width > 8188) - mf->width = 8188; - else if (mf->width & 1) - mf->width &= ~1; - - switch (pdata->type) { - case SH_CSI2C: - switch (mf->code) { - case V4L2_MBUS_FMT_UYVY8_2X8: /* YUV422 */ - case V4L2_MBUS_FMT_YUYV8_1_5X8: /* YUV420 */ - case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ - case V4L2_MBUS_FMT_SBGGR8_1X8: - case V4L2_MBUS_FMT_SGRBG8_1X8: - break; - default: - /* All MIPI CSI-2 devices must support one of primary formats */ - mf->code = V4L2_MBUS_FMT_YUYV8_2X8; - } - break; - case SH_CSI2I: - switch (mf->code) { - case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ - case V4L2_MBUS_FMT_SBGGR8_1X8: - case V4L2_MBUS_FMT_SGRBG8_1X8: - case V4L2_MBUS_FMT_SBGGR10_1X10: /* RAW10 */ - case V4L2_MBUS_FMT_SBGGR12_1X12: /* RAW12 */ - break; - default: - /* All MIPI CSI-2 devices must support one of primary formats */ - mf->code = V4L2_MBUS_FMT_SBGGR8_1X8; - } - break; - } - - return 0; -} - -/* - * We have done our best in try_fmt to try and tell the sensor, which formats - * we support. If now the configuration is unsuitable for us we can only - * error out. - */ -static int sh_csi2_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); - u32 tmp = (priv->client->channel & 3) << 8; - - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); - if (mf->width > 8188 || mf->width & 1) - return -EINVAL; - - switch (mf->code) { - case V4L2_MBUS_FMT_UYVY8_2X8: - tmp |= 0x1e; /* YUV422 8 bit */ - break; - case V4L2_MBUS_FMT_YUYV8_1_5X8: - tmp |= 0x18; /* YUV420 8 bit */ - break; - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: - tmp |= 0x21; /* RGB555 */ - break; - case V4L2_MBUS_FMT_RGB565_2X8_BE: - tmp |= 0x22; /* RGB565 */ - break; - case V4L2_MBUS_FMT_Y8_1X8: - case V4L2_MBUS_FMT_SBGGR8_1X8: - case V4L2_MBUS_FMT_SGRBG8_1X8: - tmp |= 0x2a; /* RAW8 */ - break; - default: - return -EINVAL; - } - - iowrite32(tmp, priv->base + SH_CSI2_VCDT); - - return 0; -} - -static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { - .s_mbus_fmt = sh_csi2_s_fmt, - .try_mbus_fmt = sh_csi2_try_fmt, -}; - -static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops; - -static struct v4l2_subdev_ops sh_csi2_subdev_ops = { - .core = &sh_csi2_subdev_core_ops, - .video = &sh_csi2_subdev_video_ops, -}; - -static void sh_csi2_hwinit(struct sh_csi2 *priv) -{ - struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; - __u32 tmp = 0x10; /* Enable MIPI CSI clock lane */ - - /* Reflect registers immediately */ - iowrite32(0x00000001, priv->base + SH_CSI2_TREF); - /* reset CSI2 harware */ - iowrite32(0x00000001, priv->base + SH_CSI2_SRST); - udelay(5); - iowrite32(0x00000000, priv->base + SH_CSI2_SRST); - - if (priv->client->lanes & 3) - tmp |= priv->client->lanes & 3; - else - /* Default - both lanes */ - tmp |= 3; - - if (priv->client->phy == SH_CSI2_PHY_MAIN) - tmp |= 0x8000; - - iowrite32(tmp, priv->base + SH_CSI2_PHYCNT); - - tmp = 0; - if (pdata->flags & SH_CSI2_ECC) - tmp |= 2; - if (pdata->flags & SH_CSI2_CRC) - tmp |= 1; - iowrite32(tmp, priv->base + SH_CSI2_CHKSUM); -} - -static int sh_csi2_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - const unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | - SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static int sh_csi2_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct soc_camera_device *icd = to_soc_camera_dev(dev); - struct v4l2_device *v4l2_dev = dev_get_drvdata(dev->parent); - struct sh_csi2 *priv = - container_of(nb, struct sh_csi2, notifier); - struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; - int ret, i; - - for (i = 0; i < pdata->num_clients; i++) - if (&pdata->clients[i].pdev->dev == icd->pdev) - break; - - dev_dbg(dev, "%s(%p): action = %lu, found #%d\n", __func__, dev, action, i); - - if (i == pdata->num_clients) - return NOTIFY_DONE; - - switch (action) { - case BUS_NOTIFY_BOUND_DRIVER: - snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s", - dev_name(v4l2_dev->dev), ".mipi-csi"); - ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev); - dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret); - if (ret < 0) - return NOTIFY_DONE; - - priv->client = pdata->clients + i; - - icd->ops->set_bus_param = sh_csi2_set_bus_param; - icd->ops->query_bus_param = sh_csi2_query_bus_param; - - pm_runtime_get_sync(v4l2_get_subdevdata(&priv->subdev)); - - sh_csi2_hwinit(priv); - break; - case BUS_NOTIFY_UNBIND_DRIVER: - priv->client = NULL; - - /* Driver is about to be unbound */ - icd->ops->set_bus_param = NULL; - icd->ops->query_bus_param = NULL; - - v4l2_device_unregister_subdev(&priv->subdev); - - pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); - break; - } - - return NOTIFY_OK; -} - -static __devinit int sh_csi2_probe(struct platform_device *pdev) -{ - struct resource *res; - unsigned int irq; - int ret; - struct sh_csi2 *priv; - /* Platform data specify the PHY, lanes, ECC, CRC */ - struct sh_csi2_pdata *pdata = pdev->dev.platform_data; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - /* Interrupt unused so far */ - irq = platform_get_irq(pdev, 0); - - if (!res || (int)irq <= 0 || !pdata) { - dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n"); - return -ENODEV; - } - - /* TODO: Add support for CSI2I. Careful: different register layout! */ - if (pdata->type != SH_CSI2C) { - dev_err(&pdev->dev, "Only CSI2C supported ATM.\n"); - return -EINVAL; - } - - priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->irq = irq; - priv->notifier.notifier_call = sh_csi2_notify; - - /* We MUST attach after the MIPI sensor */ - ret = bus_register_notifier(&soc_camera_bus_type, &priv->notifier); - if (ret < 0) { - dev_err(&pdev->dev, "CSI2 cannot register notifier\n"); - goto ernotify; - } - - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "CSI2 register region already claimed\n"); - ret = -EBUSY; - goto ereqreg; - } - - priv->base = ioremap(res->start, resource_size(res)); - if (!priv->base) { - ret = -ENXIO; - dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n"); - goto eremap; - } - - priv->pdev = pdev; - - v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops); - v4l2_set_subdevdata(&priv->subdev, &pdev->dev); - - platform_set_drvdata(pdev, priv); - - pm_runtime_enable(&pdev->dev); - - dev_dbg(&pdev->dev, "CSI2 probed.\n"); - - return 0; - -eremap: - release_mem_region(res->start, resource_size(res)); -ereqreg: - bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier); -ernotify: - kfree(priv); - - return ret; -} - -static __devexit int sh_csi2_remove(struct platform_device *pdev) -{ - struct sh_csi2 *priv = platform_get_drvdata(pdev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier); - pm_runtime_disable(&pdev->dev); - iounmap(priv->base); - release_mem_region(res->start, resource_size(res)); - platform_set_drvdata(pdev, NULL); - kfree(priv); - - return 0; -} - -static struct platform_driver __refdata sh_csi2_pdrv = { - .remove = __devexit_p(sh_csi2_remove), - .driver = { - .name = "sh-mobile-csi2", - .owner = THIS_MODULE, - }, -}; - -static int __init sh_csi2_init(void) -{ - return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe); -} - -static void __exit sh_csi2_exit(void) -{ - platform_driver_unregister(&sh_csi2_pdrv); -} - -module_init(sh_csi2_init); -module_exit(sh_csi2_exit); - -MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sh-mobile-csi2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_vou.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_vou.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_vou.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sh_vou.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1493 +0,0 @@ -/* - * SuperH Video Output Unit (VOU) driver - * - * Copyright (C) 2010, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* Mirror addresses are not available for all registers */ -#define VOUER 0 -#define VOUCR 4 -#define VOUSTR 8 -#define VOUVCR 0xc -#define VOUISR 0x10 -#define VOUBCR 0x14 -#define VOUDPR 0x18 -#define VOUDSR 0x1c -#define VOUVPR 0x20 -#define VOUIR 0x24 -#define VOUSRR 0x28 -#define VOUMSR 0x2c -#define VOUHIR 0x30 -#define VOUDFR 0x34 -#define VOUAD1R 0x38 -#define VOUAD2R 0x3c -#define VOUAIR 0x40 -#define VOUSWR 0x44 -#define VOURCR 0x48 -#define VOURPR 0x50 - -enum sh_vou_status { - SH_VOU_IDLE, - SH_VOU_INITIALISING, - SH_VOU_RUNNING, -}; - -#define VOU_MAX_IMAGE_WIDTH 720 -#define VOU_MAX_IMAGE_HEIGHT 576 - -struct sh_vou_device { - struct v4l2_device v4l2_dev; - struct video_device *vdev; - atomic_t use_count; - struct sh_vou_pdata *pdata; - spinlock_t lock; - void __iomem *base; - /* State information */ - struct v4l2_pix_format pix; - struct v4l2_rect rect; - struct list_head queue; - v4l2_std_id std; - int pix_idx; - struct videobuf_buffer *active; - enum sh_vou_status status; - struct mutex fop_lock; -}; - -struct sh_vou_file { - struct videobuf_queue vbq; -}; - -/* Register access routines for sides A, B and mirror addresses */ -static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg, - u32 value) -{ - __raw_writel(value, vou_dev->base + reg); -} - -static void sh_vou_reg_ab_write(struct sh_vou_device *vou_dev, unsigned int reg, - u32 value) -{ - __raw_writel(value, vou_dev->base + reg); - __raw_writel(value, vou_dev->base + reg + 0x1000); -} - -static void sh_vou_reg_m_write(struct sh_vou_device *vou_dev, unsigned int reg, - u32 value) -{ - __raw_writel(value, vou_dev->base + reg + 0x2000); -} - -static u32 sh_vou_reg_a_read(struct sh_vou_device *vou_dev, unsigned int reg) -{ - return __raw_readl(vou_dev->base + reg); -} - -static void sh_vou_reg_a_set(struct sh_vou_device *vou_dev, unsigned int reg, - u32 value, u32 mask) -{ - u32 old = __raw_readl(vou_dev->base + reg); - - value = (value & mask) | (old & ~mask); - __raw_writel(value, vou_dev->base + reg); -} - -static void sh_vou_reg_b_set(struct sh_vou_device *vou_dev, unsigned int reg, - u32 value, u32 mask) -{ - sh_vou_reg_a_set(vou_dev, reg + 0x1000, value, mask); -} - -static void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg, - u32 value, u32 mask) -{ - sh_vou_reg_a_set(vou_dev, reg, value, mask); - sh_vou_reg_b_set(vou_dev, reg, value, mask); -} - -struct sh_vou_fmt { - u32 pfmt; - char *desc; - unsigned char bpp; - unsigned char rgb; - unsigned char yf; - unsigned char pkf; -}; - -/* Further pixel formats can be added */ -static struct sh_vou_fmt vou_fmt[] = { - { - .pfmt = V4L2_PIX_FMT_NV12, - .bpp = 12, - .desc = "YVU420 planar", - .yf = 0, - .rgb = 0, - }, - { - .pfmt = V4L2_PIX_FMT_NV16, - .bpp = 16, - .desc = "YVYU planar", - .yf = 1, - .rgb = 0, - }, - { - .pfmt = V4L2_PIX_FMT_RGB24, - .bpp = 24, - .desc = "RGB24", - .pkf = 2, - .rgb = 1, - }, - { - .pfmt = V4L2_PIX_FMT_RGB565, - .bpp = 16, - .desc = "RGB565", - .pkf = 3, - .rgb = 1, - }, - { - .pfmt = V4L2_PIX_FMT_RGB565X, - .bpp = 16, - .desc = "RGB565 byteswapped", - .pkf = 3, - .rgb = 1, - }, -}; - -static void sh_vou_schedule_next(struct sh_vou_device *vou_dev, - struct videobuf_buffer *vb) -{ - dma_addr_t addr1, addr2; - - addr1 = videobuf_to_dma_contig(vb); - switch (vou_dev->pix.pixelformat) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV16: - addr2 = addr1 + vou_dev->pix.width * vou_dev->pix.height; - break; - default: - addr2 = 0; - } - - sh_vou_reg_m_write(vou_dev, VOUAD1R, addr1); - sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2); -} - -static void sh_vou_stream_start(struct sh_vou_device *vou_dev, - struct videobuf_buffer *vb) -{ - unsigned int row_coeff; -#ifdef __LITTLE_ENDIAN - u32 dataswap = 7; -#else - u32 dataswap = 0; -#endif - - switch (vou_dev->pix.pixelformat) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV16: - row_coeff = 1; - break; - case V4L2_PIX_FMT_RGB565: - dataswap ^= 1; - case V4L2_PIX_FMT_RGB565X: - row_coeff = 2; - break; - case V4L2_PIX_FMT_RGB24: - row_coeff = 3; - break; - } - - sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap); - sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff); - sh_vou_schedule_next(vou_dev, vb); -} - -static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - BUG_ON(in_interrupt()); - - /* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(vq, vb, 0, 0); - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -/* Locking: caller holds fop_lock mutex */ -static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - *size = vou_fmt[vou_dev->pix_idx].bpp * vou_dev->pix.width * - vou_dev->pix.height / 8; - - if (*count < 2) - *count = 2; - - /* Taking into account maximum frame size, *count will stay >= 2 */ - if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024) - *count = 4 * 1024 * 1024 / PAGE_ALIGN(*size); - - dev_dbg(vq->dev, "%s(): count=%d, size=%d\n", __func__, *count, *size); - - return 0; -} - -/* Locking: caller holds fop_lock mutex */ -static int sh_vou_buf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - struct v4l2_pix_format *pix = &vou_dev->pix; - int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; - int ret; - - dev_dbg(vq->dev, "%s()\n", __func__); - - if (vb->width != pix->width || - vb->height != pix->height || - vb->field != pix->field) { - vb->width = pix->width; - vb->height = pix->height; - vb->field = field; - if (vb->state != VIDEOBUF_NEEDS_INIT) - free_buffer(vq, vb); - } - - vb->size = vb->height * bytes_per_line; - if (vb->baddr && vb->bsize < vb->size) { - /* User buffer too small */ - dev_warn(vq->dev, "User buffer too small: [%u] @ %lx\n", - vb->bsize, vb->baddr); - return -EINVAL; - } - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret < 0) { - dev_warn(vq->dev, "IOLOCK buf-type %d: %d\n", - vb->memory, ret); - return ret; - } - vb->state = VIDEOBUF_PREPARED; - } - - dev_dbg(vq->dev, - "%s(): fmt #%d, %u bytes per line, phys 0x%x, type %d, state %d\n", - __func__, vou_dev->pix_idx, bytes_per_line, - videobuf_to_dma_contig(vb), vb->memory, vb->state); - - return 0; -} - -/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */ -static void sh_vou_buf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - dev_dbg(vq->dev, "%s()\n", __func__); - - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &vou_dev->queue); - - if (vou_dev->status == SH_VOU_RUNNING) { - return; - } else if (!vou_dev->active) { - vou_dev->active = vb; - /* Start from side A: we use mirror addresses, so, set B */ - sh_vou_reg_a_write(vou_dev, VOURPR, 1); - dev_dbg(vq->dev, "%s: first buffer status 0x%x\n", __func__, - sh_vou_reg_a_read(vou_dev, VOUSTR)); - sh_vou_schedule_next(vou_dev, vb); - /* Only activate VOU after the second buffer */ - } else if (vou_dev->active->queue.next == &vb->queue) { - /* Second buffer - initialise register side B */ - sh_vou_reg_a_write(vou_dev, VOURPR, 0); - sh_vou_stream_start(vou_dev, vb); - - /* Register side switching with frame VSYNC */ - sh_vou_reg_a_write(vou_dev, VOURCR, 5); - dev_dbg(vq->dev, "%s: second buffer status 0x%x\n", __func__, - sh_vou_reg_a_read(vou_dev, VOUSTR)); - - /* Enable End-of-Frame (VSYNC) interrupts */ - sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004); - /* Two buffers on the queue - activate the hardware */ - - vou_dev->status = SH_VOU_RUNNING; - sh_vou_reg_a_write(vou_dev, VOUER, 0x107); - } -} - -static void sh_vou_buf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - unsigned long flags; - - dev_dbg(vq->dev, "%s()\n", __func__); - - spin_lock_irqsave(&vou_dev->lock, flags); - - if (vou_dev->active == vb) { - /* disable output */ - sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); - /* ...but the current frame will complete */ - sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); - vou_dev->active = NULL; - } - - if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED)) { - vb->state = VIDEOBUF_ERROR; - list_del(&vb->queue); - } - - spin_unlock_irqrestore(&vou_dev->lock, flags); - - free_buffer(vq, vb); -} - -static struct videobuf_queue_ops sh_vou_video_qops = { - .buf_setup = sh_vou_buf_setup, - .buf_prepare = sh_vou_buf_prepare, - .buf_queue = sh_vou_buf_queue, - .buf_release = sh_vou_buf_release, -}; - -/* Video IOCTLs */ -static int sh_vou_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - strlcpy(cap->card, "SuperH VOU", sizeof(cap->card)); - cap->version = KERNEL_VERSION(0, 1, 0); - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - return 0; -} - -/* Enumerate formats, that the device can accept from the user */ -static int sh_vou_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct sh_vou_file *vou_file = priv; - - if (fmt->index >= ARRAY_SIZE(vou_fmt)) - return -EINVAL; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - strlcpy(fmt->description, vou_fmt[fmt->index].desc, - sizeof(fmt->description)); - fmt->pixelformat = vou_fmt[fmt->index].pfmt; - - return 0; -} - -static int sh_vou_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - fmt->fmt.pix = vou_dev->pix; - - return 0; -} - -static const unsigned char vou_scale_h_num[] = {1, 9, 2, 9, 4}; -static const unsigned char vou_scale_h_den[] = {1, 8, 1, 4, 1}; -static const unsigned char vou_scale_h_fld[] = {0, 2, 1, 3}; -static const unsigned char vou_scale_v_num[] = {1, 2, 4}; -static const unsigned char vou_scale_v_den[] = {1, 1, 1}; -static const unsigned char vou_scale_v_fld[] = {0, 1}; - -static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev, - int pix_idx, int w_idx, int h_idx) -{ - struct sh_vou_fmt *fmt = vou_fmt + pix_idx; - unsigned int black_left, black_top, width_max, height_max, - frame_in_height, frame_out_height, frame_out_top; - struct v4l2_rect *rect = &vou_dev->rect; - struct v4l2_pix_format *pix = &vou_dev->pix; - u32 vouvcr = 0, dsr_h, dsr_v; - - if (vou_dev->std & V4L2_STD_525_60) { - width_max = 858; - height_max = 262; - } else { - width_max = 864; - height_max = 312; - } - - frame_in_height = pix->height / 2; - frame_out_height = rect->height / 2; - frame_out_top = rect->top / 2; - - /* - * Cropping scheme: max useful image is 720x480, and the total video - * area is 858x525 (NTSC) or 864x625 (PAL). AK8813 / 8814 starts - * sampling data beginning with fixed 276th (NTSC) / 288th (PAL) clock, - * of which the first 33 / 25 clocks HSYNC must be held active. This - * has to be configured in CR[HW]. 1 pixel equals 2 clock periods. - * This gives CR[HW] = 16 / 12, VPR[HVP] = 138 / 144, which gives - * exactly 858 - 138 = 864 - 144 = 720! We call the out-of-display area, - * beyond DSR, specified on the left and top by the VPR register "black - * pixels" and out-of-image area (DPR) "background pixels." We fix VPR - * at 138 / 144 : 20, because that's the HSYNC timing, that our first - * client requires, and that's exactly what leaves us 720 pixels for the - * image; we leave VPR[VVP] at default 20 for now, because the client - * doesn't seem to have any special requirements for it. Otherwise we - * could also set it to max - 240 = 22 / 72. Thus VPR depends only on - * the selected standard, and DPR and DSR are selected according to - * cropping. Q: how does the client detect the first valid line? Does - * HSYNC stay inactive during invalid (black) lines? - */ - black_left = width_max - VOU_MAX_IMAGE_WIDTH; - black_top = 20; - - dsr_h = rect->width + rect->left; - dsr_v = frame_out_height + frame_out_top; - - dev_dbg(vou_dev->v4l2_dev.dev, - "image %ux%u, black %u:%u, offset %u:%u, display %ux%u\n", - pix->width, frame_in_height, black_left, black_top, - rect->left, frame_out_top, dsr_h, dsr_v); - - /* VOUISR height - half of a frame height in frame mode */ - sh_vou_reg_ab_write(vou_dev, VOUISR, (pix->width << 16) | frame_in_height); - sh_vou_reg_ab_write(vou_dev, VOUVPR, (black_left << 16) | black_top); - sh_vou_reg_ab_write(vou_dev, VOUDPR, (rect->left << 16) | frame_out_top); - sh_vou_reg_ab_write(vou_dev, VOUDSR, (dsr_h << 16) | dsr_v); - - /* - * if necessary, we could set VOUHIR to - * max(black_left + dsr_h, width_max) here - */ - - if (w_idx) - vouvcr |= (1 << 15) | (vou_scale_h_fld[w_idx - 1] << 4); - if (h_idx) - vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1]; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s: scaling 0x%x\n", fmt->desc, vouvcr); - - /* To produce a colour bar for testing set bit 23 of VOUVCR */ - sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr); - sh_vou_reg_ab_write(vou_dev, VOUDFR, - fmt->pkf | (fmt->yf << 8) | (fmt->rgb << 16)); -} - -struct sh_vou_geometry { - struct v4l2_rect output; - unsigned int in_width; - unsigned int in_height; - int scale_idx_h; - int scale_idx_v; -}; - -/* - * Find input geometry, that we can use to produce output, closest to the - * requested rectangle, using VOU scaling - */ -static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std) -{ - /* The compiler cannot know, that best and idx will indeed be set */ - unsigned int best_err = UINT_MAX, best = 0, img_height_max; - int i, idx = 0; - - if (std & V4L2_STD_525_60) - img_height_max = 480; - else - img_height_max = 576; - - /* Image width must be a multiple of 4 */ - v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2, - &geo->in_height, 0, img_height_max, 1, 0); - - /* Select scales to come as close as possible to the output image */ - for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) { - unsigned int err; - unsigned int found = geo->output.width * vou_scale_h_den[i] / - vou_scale_h_num[i]; - - if (found > VOU_MAX_IMAGE_WIDTH) - /* scales increase */ - break; - - err = abs(found - geo->in_width); - if (err < best_err) { - best_err = err; - idx = i; - best = found; - } - if (!err) - break; - } - - geo->in_width = best; - geo->scale_idx_h = idx; - - best_err = UINT_MAX; - - /* This loop can be replaced with one division */ - for (i = ARRAY_SIZE(vou_scale_v_num) - 1; i >= 0; i--) { - unsigned int err; - unsigned int found = geo->output.height * vou_scale_v_den[i] / - vou_scale_v_num[i]; - - if (found > img_height_max) - /* scales increase */ - break; - - err = abs(found - geo->in_height); - if (err < best_err) { - best_err = err; - idx = i; - best = found; - } - if (!err) - break; - } - - geo->in_height = best; - geo->scale_idx_v = idx; -} - -/* - * Find output geometry, that we can produce, using VOU scaling, closest to - * the requested rectangle - */ -static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) -{ - unsigned int best_err = UINT_MAX, best, width_max, height_max, - img_height_max; - int i, idx; - - if (std & V4L2_STD_525_60) { - width_max = 858; - height_max = 262 * 2; - img_height_max = 480; - } else { - width_max = 864; - height_max = 312 * 2; - img_height_max = 576; - } - - /* Select scales to come as close as possible to the output image */ - for (i = 0; i < ARRAY_SIZE(vou_scale_h_num); i++) { - unsigned int err; - unsigned int found = geo->in_width * vou_scale_h_num[i] / - vou_scale_h_den[i]; - - if (found > VOU_MAX_IMAGE_WIDTH) - /* scales increase */ - break; - - err = abs(found - geo->output.width); - if (err < best_err) { - best_err = err; - idx = i; - best = found; - } - if (!err) - break; - } - - geo->output.width = best; - geo->scale_idx_h = idx; - if (geo->output.left + best > width_max) - geo->output.left = width_max - best; - - pr_debug("%s(): W %u * %u/%u = %u\n", __func__, geo->in_width, - vou_scale_h_num[idx], vou_scale_h_den[idx], best); - - best_err = UINT_MAX; - - /* This loop can be replaced with one division */ - for (i = 0; i < ARRAY_SIZE(vou_scale_v_num); i++) { - unsigned int err; - unsigned int found = geo->in_height * vou_scale_v_num[i] / - vou_scale_v_den[i]; - - if (found > img_height_max) - /* scales increase */ - break; - - err = abs(found - geo->output.height); - if (err < best_err) { - best_err = err; - idx = i; - best = found; - } - if (!err) - break; - } - - geo->output.height = best; - geo->scale_idx_v = idx; - if (geo->output.top + best > height_max) - geo->output.top = height_max - best; - - pr_debug("%s(): H %u * %u/%u = %u\n", __func__, geo->in_height, - vou_scale_v_num[idx], vou_scale_v_den[idx], best); -} - -static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - unsigned int img_height_max; - int pix_idx; - struct sh_vou_geometry geo; - struct v4l2_mbus_framefmt mbfmt = { - /* Revisit: is this the correct code? */ - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .field = V4L2_FIELD_INTERLACED, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - }; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, - vou_dev->rect.width, vou_dev->rect.height, - pix->width, pix->height); - - if (pix->field == V4L2_FIELD_ANY) - pix->field = V4L2_FIELD_NONE; - - if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - pix->field != V4L2_FIELD_NONE) - return -EINVAL; - - for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) - if (vou_fmt[pix_idx].pfmt == pix->pixelformat) - break; - - if (pix_idx == ARRAY_SIZE(vou_fmt)) - return -EINVAL; - - if (vou_dev->std & V4L2_STD_525_60) - img_height_max = 480; - else - img_height_max = 576; - - /* Image width must be a multiple of 4 */ - v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2, - &pix->height, 0, img_height_max, 1, 0); - - geo.in_width = pix->width; - geo.in_height = pix->height; - geo.output = vou_dev->rect; - - vou_adjust_output(&geo, vou_dev->std); - - mbfmt.width = geo.output.width; - mbfmt.height = geo.output.height; - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_mbus_fmt, &mbfmt); - /* Must be implemented, so, don't check for -ENOIOCTLCMD */ - if (ret < 0) - return ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, - geo.output.width, geo.output.height, mbfmt.width, mbfmt.height); - - /* Sanity checks */ - if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH || - (unsigned)mbfmt.height > img_height_max || - mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8) - return -EIO; - - if (mbfmt.width != geo.output.width || - mbfmt.height != geo.output.height) { - geo.output.width = mbfmt.width; - geo.output.height = mbfmt.height; - - vou_adjust_input(&geo, vou_dev->std); - } - - /* We tried to preserve output rectangle, but it could have changed */ - vou_dev->rect = geo.output; - pix->width = geo.in_width; - pix->height = geo.in_height; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u\n", __func__, - pix->width, pix->height); - - vou_dev->pix_idx = pix_idx; - - vou_dev->pix = *pix; - - sh_vou_configure_geometry(vou_dev, pix_idx, - geo.scale_idx_h, geo.scale_idx_v); - - return 0; -} - -static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct sh_vou_file *vou_file = priv; - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int i; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - pix->field = V4L2_FIELD_NONE; - - v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1, - &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0); - - for (i = 0; ARRAY_SIZE(vou_fmt); i++) - if (vou_fmt[i].pfmt == pix->pixelformat) - return 0; - - pix->pixelformat = vou_fmt[0].pfmt; - - return 0; -} - -static int sh_vou_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req) -{ - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - return videobuf_reqbufs(&vou_file->vbq, req); -} - -static int sh_vou_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - return videobuf_querybuf(&vou_file->vbq, b); -} - -static int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - return videobuf_qbuf(&vou_file->vbq, b); -} - -static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK); -} - -static int sh_vou_streamon(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - struct sh_vou_file *vou_file = priv; - int ret; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, - video, s_stream, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - - /* This calls our .buf_queue() (== sh_vou_buf_queue) */ - return videobuf_streamon(&vou_file->vbq); -} - -static int sh_vou_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - /* - * This calls buf_release from host driver's videobuf_queue_ops for all - * remaining buffers. When the last buffer is freed, stop streaming - */ - videobuf_streamoff(&vou_file->vbq); - v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_stream, 0); - - return 0; -} - -static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt) -{ - switch (bus_fmt) { - default: - pr_warning("%s(): Invalid bus-format code %d, using default 8-bit\n", - __func__, bus_fmt); - case SH_VOU_BUS_8BIT: - return 1; - case SH_VOU_BUS_16BIT: - return 0; - case SH_VOU_BUS_BT656: - return 3; - } -} - -static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id); - - if (*std_id & ~vdev->tvnorms) - return -EINVAL; - - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_std_output, *std_id); - /* Shall we continue, if the subdev doesn't support .s_std_output()? */ - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - - if (*std_id & V4L2_STD_525_60) - sh_vou_reg_ab_set(vou_dev, VOUCR, - sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29); - else - sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29); - - vou_dev->std = *std_id; - - return 0; -} - -static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - *std = vou_dev->std; - - return 0; -} - -static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->c = vou_dev->rect; - - return 0; -} - -/* Assume a dull encoder, do all the work ourselves. */ -static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - struct v4l2_rect *rect = &a->c; - struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT}; - struct v4l2_pix_format *pix = &vou_dev->pix; - struct sh_vou_geometry geo; - struct v4l2_mbus_framefmt mbfmt = { - /* Revisit: is this the correct code? */ - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .field = V4L2_FIELD_INTERLACED, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - }; - unsigned int img_height_max; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__, - rect->width, rect->height, rect->left, rect->top); - - if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - if (vou_dev->std & V4L2_STD_525_60) - img_height_max = 480; - else - img_height_max = 576; - - v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1, - &rect->height, 0, img_height_max, 1, 0); - - if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH) - rect->left = VOU_MAX_IMAGE_WIDTH - rect->width; - - if (rect->height + rect->top > img_height_max) - rect->top = img_height_max - rect->height; - - geo.output = *rect; - geo.in_width = pix->width; - geo.in_height = pix->height; - - /* Configure the encoder one-to-one, position at 0, ignore errors */ - sd_crop.c.width = geo.output.width; - sd_crop.c.height = geo.output.height; - /* - * We first issue a S_CROP, so that the subsequent S_FMT delivers the - * final encoder configuration. - */ - v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_crop, &sd_crop); - mbfmt.width = geo.output.width; - mbfmt.height = geo.output.height; - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_mbus_fmt, &mbfmt); - /* Must be implemented, so, don't check for -ENOIOCTLCMD */ - if (ret < 0) - return ret; - - /* Sanity checks */ - if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH || - (unsigned)mbfmt.height > img_height_max || - mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8) - return -EIO; - - geo.output.width = mbfmt.width; - geo.output.height = mbfmt.height; - - /* - * No down-scaling. According to the API, current call has precedence: - * http://v4l2spec.bytesex.org/spec/x1904.htm#AEN1954 paragraph two. - */ - vou_adjust_input(&geo, vou_dev->std); - - /* We tried to preserve output rectangle, but it could have changed */ - vou_dev->rect = geo.output; - pix->width = geo.in_width; - pix->height = geo.in_height; - - sh_vou_configure_geometry(vou_dev, vou_dev->pix_idx, - geo.scale_idx_h, geo.scale_idx_v); - - return 0; -} - -/* - * Total field: NTSC 858 x 2 * 262/263, PAL 864 x 2 * 312/313, default rectangle - * is the initial register values, height takes the interlaced format into - * account. The actual image can only go up to 720 x 2 * 240, So, VOUVPR can - * actually only meaningfully contain values <= 720 and <= 240 respectively, and - * not <= 864 and <= 312. - */ -static int sh_vou_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *a) -{ - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = VOU_MAX_IMAGE_WIDTH; - a->bounds.height = VOU_MAX_IMAGE_HEIGHT; - /* Default = max, set VOUDPR = 0, which is not hardware default */ - a->defrect.left = 0; - a->defrect.top = 0; - a->defrect.width = VOU_MAX_IMAGE_WIDTH; - a->defrect.height = VOU_MAX_IMAGE_HEIGHT; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static irqreturn_t sh_vou_isr(int irq, void *dev_id) -{ - struct sh_vou_device *vou_dev = dev_id; - static unsigned long j; - struct videobuf_buffer *vb; - static int cnt; - static int side; - u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked; - u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR); - - if (!(irq_status & 0x300)) { - if (printk_timed_ratelimit(&j, 500)) - dev_warn(vou_dev->v4l2_dev.dev, "IRQ status 0x%x!\n", - irq_status); - return IRQ_NONE; - } - - spin_lock(&vou_dev->lock); - if (!vou_dev->active || list_empty(&vou_dev->queue)) { - if (printk_timed_ratelimit(&j, 500)) - dev_warn(vou_dev->v4l2_dev.dev, - "IRQ without active buffer: %x!\n", irq_status); - /* Just ack: buf_release will disable further interrupts */ - sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x300); - spin_unlock(&vou_dev->lock); - return IRQ_HANDLED; - } - - masked = ~(0x300 & irq_status) & irq_status & 0x30304; - dev_dbg(vou_dev->v4l2_dev.dev, - "IRQ status 0x%x -> 0x%x, VOU status 0x%x, cnt %d\n", - irq_status, masked, vou_status, cnt); - - cnt++; - side = vou_status & 0x10000; - - /* Clear only set interrupts */ - sh_vou_reg_a_write(vou_dev, VOUIR, masked); - - vb = vou_dev->active; - list_del(&vb->queue); - - vb->state = VIDEOBUF_DONE; - do_gettimeofday(&vb->ts); - vb->field_count++; - wake_up(&vb->done); - - if (list_empty(&vou_dev->queue)) { - /* Stop VOU */ - dev_dbg(vou_dev->v4l2_dev.dev, "%s: queue empty after %d\n", - __func__, cnt); - sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); - vou_dev->active = NULL; - vou_dev->status = SH_VOU_INITIALISING; - /* Disable End-of-Frame (VSYNC) interrupts */ - sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); - spin_unlock(&vou_dev->lock); - return IRQ_HANDLED; - } - - vou_dev->active = list_entry(vou_dev->queue.next, - struct videobuf_buffer, queue); - - if (vou_dev->active->queue.next != &vou_dev->queue) { - struct videobuf_buffer *new = list_entry(vou_dev->active->queue.next, - struct videobuf_buffer, queue); - sh_vou_schedule_next(vou_dev, new); - } - - spin_unlock(&vou_dev->lock); - - return IRQ_HANDLED; -} - -static int sh_vou_hw_init(struct sh_vou_device *vou_dev) -{ - struct sh_vou_pdata *pdata = vou_dev->pdata; - u32 voucr = sh_vou_ntsc_mode(pdata->bus_fmt) << 29; - int i = 100; - - /* Disable all IRQs */ - sh_vou_reg_a_write(vou_dev, VOUIR, 0); - - /* Reset VOU interfaces - registers unaffected */ - sh_vou_reg_a_write(vou_dev, VOUSRR, 0x101); - while (--i && (sh_vou_reg_a_read(vou_dev, VOUSRR) & 0x101)) - udelay(1); - - if (!i) - return -ETIMEDOUT; - - dev_dbg(vou_dev->v4l2_dev.dev, "Reset took %dus\n", 100 - i); - - if (pdata->flags & SH_VOU_PCLK_FALLING) - voucr |= 1 << 28; - if (pdata->flags & SH_VOU_HSYNC_LOW) - voucr |= 1 << 27; - if (pdata->flags & SH_VOU_VSYNC_LOW) - voucr |= 1 << 26; - sh_vou_reg_ab_set(vou_dev, VOUCR, voucr, 0xfc000000); - - /* Manual register side switching at first */ - sh_vou_reg_a_write(vou_dev, VOURCR, 4); - /* Default - fixed HSYNC length, can be made configurable is required */ - sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000); - - return 0; -} - -/* File operations */ -static int sh_vou_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file), - GFP_KERNEL); - - if (!vou_file) - return -ENOMEM; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - file->private_data = vou_file; - - if (atomic_inc_return(&vou_dev->use_count) == 1) { - int ret; - /* First open */ - vou_dev->status = SH_VOU_INITIALISING; - pm_runtime_get_sync(vdev->v4l2_dev->dev); - ret = sh_vou_hw_init(vou_dev); - if (ret < 0) { - atomic_dec(&vou_dev->use_count); - pm_runtime_put(vdev->v4l2_dev->dev); - vou_dev->status = SH_VOU_IDLE; - return ret; - } - } - - videobuf_queue_dma_contig_init(&vou_file->vbq, &sh_vou_video_qops, - vou_dev->v4l2_dev.dev, &vou_dev->lock, - V4L2_BUF_TYPE_VIDEO_OUTPUT, - V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), vdev, - &vou_dev->fop_lock); - - return 0; -} - -static int sh_vou_release(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - struct sh_vou_file *vou_file = file->private_data; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - if (!atomic_dec_return(&vou_dev->use_count)) { - /* Last close */ - vou_dev->status = SH_VOU_IDLE; - sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101); - pm_runtime_put(vdev->v4l2_dev->dev); - } - - file->private_data = NULL; - kfree(vou_file); - - return 0; -} - -static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct sh_vou_file *vou_file = file->private_data; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - return videobuf_mmap_mapper(&vou_file->vbq, vma); -} - -static unsigned int sh_vou_poll(struct file *file, poll_table *wait) -{ - struct sh_vou_file *vou_file = file->private_data; - - dev_dbg(vou_file->vbq.dev, "%s()\n", __func__); - - return videobuf_poll_stream(file, &vou_file->vbq, wait); -} - -static int sh_vou_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *id) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_chip_ident, id); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int sh_vou_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_register, reg); -} - -static int sh_vou_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct video_device *vdev = video_devdata(file); - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, s_register, reg); -} -#endif - -/* sh_vou display ioctl operations */ -static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { - .vidioc_querycap = sh_vou_querycap, - .vidioc_enum_fmt_vid_out = sh_vou_enum_fmt_vid_out, - .vidioc_g_fmt_vid_out = sh_vou_g_fmt_vid_out, - .vidioc_s_fmt_vid_out = sh_vou_s_fmt_vid_out, - .vidioc_try_fmt_vid_out = sh_vou_try_fmt_vid_out, - .vidioc_reqbufs = sh_vou_reqbufs, - .vidioc_querybuf = sh_vou_querybuf, - .vidioc_qbuf = sh_vou_qbuf, - .vidioc_dqbuf = sh_vou_dqbuf, - .vidioc_streamon = sh_vou_streamon, - .vidioc_streamoff = sh_vou_streamoff, - .vidioc_s_std = sh_vou_s_std, - .vidioc_g_std = sh_vou_g_std, - .vidioc_cropcap = sh_vou_cropcap, - .vidioc_g_crop = sh_vou_g_crop, - .vidioc_s_crop = sh_vou_s_crop, - .vidioc_g_chip_ident = sh_vou_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = sh_vou_g_register, - .vidioc_s_register = sh_vou_s_register, -#endif -}; - -static const struct v4l2_file_operations sh_vou_fops = { - .owner = THIS_MODULE, - .open = sh_vou_open, - .release = sh_vou_release, - .unlocked_ioctl = video_ioctl2, - .mmap = sh_vou_mmap, - .poll = sh_vou_poll, -}; - -static const struct video_device sh_vou_video_template = { - .name = "sh_vou", - .fops = &sh_vou_fops, - .ioctl_ops = &sh_vou_ioctl_ops, - .tvnorms = V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */ - .current_norm = V4L2_STD_NTSC_M, -}; - -static int __devinit sh_vou_probe(struct platform_device *pdev) -{ - struct sh_vou_pdata *vou_pdata = pdev->dev.platform_data; - struct v4l2_rect *rect; - struct v4l2_pix_format *pix; - struct i2c_adapter *i2c_adap; - struct video_device *vdev; - struct sh_vou_device *vou_dev; - struct resource *reg_res, *region; - struct v4l2_subdev *subdev; - int irq, ret; - - reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - - if (!vou_pdata || !reg_res || irq <= 0) { - dev_err(&pdev->dev, "Insufficient VOU platform information.\n"); - return -ENODEV; - } - - vou_dev = kzalloc(sizeof(*vou_dev), GFP_KERNEL); - if (!vou_dev) - return -ENOMEM; - - INIT_LIST_HEAD(&vou_dev->queue); - spin_lock_init(&vou_dev->lock); - mutex_init(&vou_dev->fop_lock); - atomic_set(&vou_dev->use_count, 0); - vou_dev->pdata = vou_pdata; - vou_dev->status = SH_VOU_IDLE; - - rect = &vou_dev->rect; - pix = &vou_dev->pix; - - /* Fill in defaults */ - vou_dev->std = sh_vou_video_template.current_norm; - rect->left = 0; - rect->top = 0; - rect->width = VOU_MAX_IMAGE_WIDTH; - rect->height = 480; - pix->width = VOU_MAX_IMAGE_WIDTH; - pix->height = 480; - pix->pixelformat = V4L2_PIX_FMT_YVYU; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2; - pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - - region = request_mem_region(reg_res->start, resource_size(reg_res), - pdev->name); - if (!region) { - dev_err(&pdev->dev, "VOU region already claimed\n"); - ret = -EBUSY; - goto ereqmemreg; - } - - vou_dev->base = ioremap(reg_res->start, resource_size(reg_res)); - if (!vou_dev->base) { - ret = -ENOMEM; - goto emap; - } - - ret = request_irq(irq, sh_vou_isr, 0, "vou", vou_dev); - if (ret < 0) - goto ereqirq; - - ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev); - if (ret < 0) { - dev_err(&pdev->dev, "Error registering v4l2 device\n"); - goto ev4l2devreg; - } - - /* Allocate memory for video device */ - vdev = video_device_alloc(); - if (vdev == NULL) { - ret = -ENOMEM; - goto evdevalloc; - } - - *vdev = sh_vou_video_template; - if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT) - vdev->tvnorms |= V4L2_STD_PAL; - vdev->v4l2_dev = &vou_dev->v4l2_dev; - vdev->release = video_device_release; - vdev->lock = &vou_dev->fop_lock; - - vou_dev->vdev = vdev; - video_set_drvdata(vdev, vou_dev); - - pm_runtime_enable(&pdev->dev); - pm_runtime_resume(&pdev->dev); - - i2c_adap = i2c_get_adapter(vou_pdata->i2c_adap); - if (!i2c_adap) { - ret = -ENODEV; - goto ei2cgadap; - } - - ret = sh_vou_hw_init(vou_dev); - if (ret < 0) - goto ereset; - - subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap, - vou_pdata->board_info, NULL); - if (!subdev) { - ret = -ENOMEM; - goto ei2cnd; - } - - ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); - if (ret < 0) - goto evregdev; - - return 0; - -evregdev: -ei2cnd: -ereset: - i2c_put_adapter(i2c_adap); -ei2cgadap: - video_device_release(vdev); - pm_runtime_disable(&pdev->dev); -evdevalloc: - v4l2_device_unregister(&vou_dev->v4l2_dev); -ev4l2devreg: - free_irq(irq, vou_dev); -ereqirq: - iounmap(vou_dev->base); -emap: - release_mem_region(reg_res->start, resource_size(reg_res)); -ereqmemreg: - kfree(vou_dev); - return ret; -} - -static int __devexit sh_vou_remove(struct platform_device *pdev) -{ - int irq = platform_get_irq(pdev, 0); - struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); - struct sh_vou_device *vou_dev = container_of(v4l2_dev, - struct sh_vou_device, v4l2_dev); - struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next, - struct v4l2_subdev, list); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct resource *reg_res; - - if (irq > 0) - free_irq(irq, vou_dev); - pm_runtime_disable(&pdev->dev); - video_unregister_device(vou_dev->vdev); - i2c_put_adapter(client->adapter); - v4l2_device_unregister(&vou_dev->v4l2_dev); - iounmap(vou_dev->base); - reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (reg_res) - release_mem_region(reg_res->start, resource_size(reg_res)); - kfree(vou_dev); - return 0; -} - -static struct platform_driver __refdata sh_vou = { - .remove = __devexit_p(sh_vou_remove), - .driver = { - .name = "sh-vou", - .owner = THIS_MODULE, - }, -}; - -static int __init sh_vou_init(void) -{ - return platform_driver_probe(&sh_vou, sh_vou_probe); -} - -static void __exit sh_vou_exit(void) -{ - platform_driver_unregister(&sh_vou); -} - -module_init(sh_vou_init); -module_exit(sh_vou_exit); - -MODULE_DESCRIPTION("SuperH VOU driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sh-vou"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -config USB_SN9C102 - tristate "USB SN9C1xx PC Camera Controller support (DEPRECATED)" - depends on VIDEO_V4L2 - ---help--- - This driver is DEPRECATED please use the gspca sonixb and - sonixj modules instead. - - Say Y here if you want support for cameras based on SONiX SN9C101, - SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers. - - See for more info. - - To compile this driver as a module, choose M here: the - module will be called sn9c102. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -sn9c102-objs := sn9c102_core.o \ - sn9c102_hv7131d.o \ - sn9c102_hv7131r.o \ - sn9c102_mi0343.o \ - sn9c102_mi0360.o \ - sn9c102_mt9v111.o \ - sn9c102_ov7630.o \ - sn9c102_ov7660.o \ - sn9c102_pas106b.o \ - sn9c102_pas202bcb.o \ - sn9c102_tas5110c1b.o \ - sn9c102_tas5110d.o \ - sn9c102_tas5130d1b.o - -obj-$(CONFIG_USB_SN9C102) += sn9c102.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_config.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_config.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_config.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_config.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -/*************************************************************************** - * Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_CONFIG_H_ -#define _SN9C102_CONFIG_H_ - -#include -#include - -#define SN9C102_DEBUG -#define SN9C102_DEBUG_LEVEL 2 -#define SN9C102_MAX_DEVICES 64 -#define SN9C102_PRESERVE_IMGSCALE 0 -#define SN9C102_FORCE_MUNMAP 0 -#define SN9C102_MAX_FRAMES 32 -#define SN9C102_URBS 2 -#define SN9C102_ISO_PACKETS 7 -#define SN9C102_ALTERNATE_SETTING 8 -#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS) -#define SN9C102_CTRL_TIMEOUT 300 -#define SN9C102_FRAME_TIMEOUT 0 - -/*****************************************************************************/ - -static const u8 SN9C102_Y_QTABLE0[64] = { - 8, 5, 5, 8, 12, 20, 25, 30, - 6, 6, 7, 9, 13, 29, 30, 27, - 7, 6, 8, 12, 20, 28, 34, 28, - 7, 8, 11, 14, 25, 43, 40, 31, - 9, 11, 18, 28, 34, 54, 51, 38, - 12, 17, 27, 32, 40, 52, 56, 46, - 24, 32, 39, 43, 51, 60, 60, 50, - 36, 46, 47, 49, 56, 50, 51, 49 -}; - -static const u8 SN9C102_UV_QTABLE0[64] = { - 8, 9, 12, 23, 49, 49, 49, 49, - 9, 10, 13, 33, 49, 49, 49, 49, - 12, 13, 28, 49, 49, 49, 49, 49, - 23, 33, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49 -}; - -static const u8 SN9C102_Y_QTABLE1[64] = { - 16, 11, 10, 16, 24, 40, 51, 61, - 12, 12, 14, 19, 26, 58, 60, 55, - 14, 13, 16, 24, 40, 57, 69, 56, - 14, 17, 22, 29, 51, 87, 80, 62, - 18, 22, 37, 56, 68, 109, 103, 77, - 24, 35, 55, 64, 81, 104, 113, 92, - 49, 64, 78, 87, 103, 121, 120, 101, - 72, 92, 95, 98, 112, 100, 103, 99 -}; - -static const u8 SN9C102_UV_QTABLE1[64] = { - 17, 18, 24, 47, 99, 99, 99, 99, - 18, 21, 26, 66, 99, 99, 99, 99, - 24, 26, 56, 99, 99, 99, 99, 99, - 47, 66, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99 -}; - -#endif /* _SN9C102_CONFIG_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3453 +0,0 @@ -/*************************************************************************** - * V4L2 driver for SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sn9c102.h" - -/*****************************************************************************/ - -#define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" -#define SN9C102_MODULE_ALIAS "sn9c1xx" -#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" -#define SN9C102_AUTHOR_EMAIL "" -#define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.47pre49" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47) - -/*****************************************************************************/ - -MODULE_DEVICE_TABLE(usb, sn9c102_id_table); - -MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); -MODULE_DESCRIPTION(SN9C102_MODULE_NAME); -MODULE_ALIAS(SN9C102_MODULE_ALIAS); -MODULE_LICENSE(SN9C102_MODULE_LICENSE); - -static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1}; -module_param_array(video_nr, short, NULL, 0444); -MODULE_PARM_DESC(video_nr, - " <-1|n[,...]>" - "\nSpecify V4L2 minor mode number." - "\n-1 = use next available (default)" - "\n n = use minor number n (integer >= 0)" - "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES) - " cameras this way." - "\nFor example:" - "\nvideo_nr=-1,2,-1 would assign minor number 2 to" - "\nthe second camera and use auto for the first" - "\none and for every other camera." - "\n"); - -static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = - SN9C102_FORCE_MUNMAP}; -module_param_array(force_munmap, bool, NULL, 0444); -MODULE_PARM_DESC(force_munmap, - " <0|1[,...]>" - "\nForce the application to unmap previously" - "\nmapped buffer memory before calling any VIDIOC_S_CROP or" - "\nVIDIOC_S_FMT ioctl's. Not all the applications support" - "\nthis feature. This parameter is specific for each" - "\ndetected camera." - "\n0 = do not force memory unmapping" - "\n1 = force memory unmapping (save memory)" - "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." - "\n"); - -static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] = - SN9C102_FRAME_TIMEOUT}; -module_param_array(frame_timeout, uint, NULL, 0644); -MODULE_PARM_DESC(frame_timeout, - " <0|n[,...]>" - "\nTimeout for a video frame in seconds before" - "\nreturning an I/O error; 0 for infinity." - "\nThis parameter is specific for each detected camera." - "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." - "\n"); - -#ifdef SN9C102_DEBUG -static unsigned short debug = SN9C102_DEBUG_LEVEL; -module_param(debug, ushort, 0644); -MODULE_PARM_DESC(debug, - " " - "\nDebugging information level, from 0 to 3:" - "\n0 = none (use carefully)" - "\n1 = critical errors" - "\n2 = significant informations" - "\n3 = more verbose messages" - "\nLevel 3 is useful for testing only." - "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." - "\n"); -#endif - -/* - Add the probe entries to this table. Be sure to add the entry in the right - place, since, on failure, the next probing routine is called according to - the order of the list below, from top to bottom. -*/ -static int (*sn9c102_sensor_table[])(struct sn9c102_device *) = { - &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ - &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */ - &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ - &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ - &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ - &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ - &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ - &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */ - &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ -}; - -/*****************************************************************************/ - -static u32 -sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, - enum sn9c102_io_method io) -{ - struct v4l2_pix_format* p = &(cam->sensor.pix_format); - struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); - size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? - (p->width * p->height * p->priv) / 8 : - (r->width * r->height * p->priv) / 8; - void* buff = NULL; - u32 i; - - if (count > SN9C102_MAX_FRAMES) - count = SN9C102_MAX_FRAMES; - - if (cam->bridge == BRIDGE_SN9C105 || cam->bridge == BRIDGE_SN9C120) - imagesize += 589 + 2; /* length of JPEG header + EOI marker */ - - cam->nbuffers = count; - while (cam->nbuffers > 0) { - if ((buff = vmalloc_32_user(cam->nbuffers * - PAGE_ALIGN(imagesize)))) - break; - cam->nbuffers--; - } - - for (i = 0; i < cam->nbuffers; i++) { - cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.index = i; - cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.length = imagesize; - cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cam->frame[i].buf.sequence = 0; - cam->frame[i].buf.field = V4L2_FIELD_NONE; - cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; - cam->frame[i].buf.flags = 0; - } - - return cam->nbuffers; -} - - -static void sn9c102_release_buffers(struct sn9c102_device* cam) -{ - if (cam->nbuffers) { - vfree(cam->frame[0].bufmem); - cam->nbuffers = 0; - } - cam->frame_current = NULL; -} - - -static void sn9c102_empty_framequeues(struct sn9c102_device* cam) -{ - u32 i; - - INIT_LIST_HEAD(&cam->inqueue); - INIT_LIST_HEAD(&cam->outqueue); - - for (i = 0; i < SN9C102_MAX_FRAMES; i++) { - cam->frame[i].state = F_UNUSED; - cam->frame[i].buf.bytesused = 0; - } -} - - -static void sn9c102_requeue_outqueue(struct sn9c102_device* cam) -{ - struct sn9c102_frame_t *i; - - list_for_each_entry(i, &cam->outqueue, frame) { - i->state = F_QUEUED; - list_add(&i->frame, &cam->inqueue); - } - - INIT_LIST_HEAD(&cam->outqueue); -} - - -static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) -{ - unsigned long lock_flags; - u32 i; - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].state == F_UNUSED) { - cam->frame[i].state = F_QUEUED; - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[i].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - } -} - -/*****************************************************************************/ - -/* - Write a sequence of count value/register pairs. Returns -1 after the first - failed write, or 0 for no errors. -*/ -int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2], - int count) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int i, res; - - for (i = 0; i < count; i++) { - u8 index = valreg[i][1]; - - /* - index is a u8, so it must be <256 and can't be out of range. - If we put in a check anyway, gcc annoys us with a warning - hat our check is useless. People get all uppity when they - see warnings in the kernel compile. - */ - - *buff = valreg[i][0]; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, - 0x41, index, 0, buff, 1, - SN9C102_CTRL_TIMEOUT); - - if (res < 0) { - DBG(3, "Failed to write a register (value 0x%02X, " - "index 0x%02X, error %d)", *buff, index, res); - return -1; - } - - cam->reg[index] = *buff; - } - - return 0; -} - - -int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - if (index >= ARRAY_SIZE(cam->reg)) - return -1; - - *buff = value; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); - if (res < 0) { - DBG(3, "Failed to write a register (value 0x%02X, index " - "0x%02X, error %d)", value, index, res); - return -1; - } - - cam->reg[index] = value; - - return 0; -} - - -/* NOTE: with the SN9C10[123] reading some registers always returns 0 */ -int sn9c102_read_reg(struct sn9c102_device* cam, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); - if (res < 0) - DBG(3, "Failed to read a register (index 0x%02X, error %d)", - index, res); - - return (res >= 0) ? (int)(*buff) : -1; -} - - -int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index) -{ - if (index >= ARRAY_SIZE(cam->reg)) - return -1; - - return cam->reg[index]; -} - - -static int -sn9c102_i2c_wait(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor) -{ - int i, r; - - for (i = 1; i <= 5; i++) { - r = sn9c102_read_reg(cam, 0x08); - if (r < 0) - return -EIO; - if (r & 0x04) - return 0; - if (sensor->frequency & SN9C102_I2C_400KHZ) - udelay(5*16); - else - udelay(16*16); - } - return -EBUSY; -} - - -static int -sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor) -{ - int r , err = 0; - - r = sn9c102_read_reg(cam, 0x08); - if (r < 0) - err += r; - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if (!(r & 0x08)) - err += -1; - } else { - if (r & 0x08) - err += -1; - } - - return err ? -EIO : 0; -} - - -static int -sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor) -{ - int r; - r = sn9c102_read_reg(cam, 0x08); - return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0; -} - - -int -sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, u8 data0, - u8 data1, u8 n, u8 buffer[]) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int i = 0, err = 0, res; - - /* Write cycle */ - data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | - ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10; - data[1] = data0; /* I2C slave id */ - data[2] = data1; /* address */ - data[7] = 0x10; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_wait(cam, sensor); - - /* Read cycle - n bytes */ - data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | - ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | - (n << 4) | 0x02; - data[1] = data0; - data[7] = 0x10; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_wait(cam, sensor); - - /* The first read byte will be placed in data[4] */ - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_detect_read_error(cam, sensor); - - PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1, - data[4]); - - if (err) { - DBG(3, "I2C read failed for %s image sensor", sensor->name); - return -1; - } - - if (buffer) - for (i = 0; i < n && i < 5; i++) - buffer[n-i-1] = data[4-i]; - - return (int)data[4]; -} - - -int -sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, u8 n, u8 data0, - u8 data1, u8 data2, u8 data3, u8 data4, u8 data5) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - /* Write cycle. It usually is address + value */ - data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | - ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) - | ((n - 1) << 4); - data[1] = data0; - data[2] = data1; - data[3] = data2; - data[4] = data3; - data[5] = data4; - data[6] = data5; - data[7] = 0x17; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_wait(cam, sensor); - err += sn9c102_i2c_detect_write_error(cam, sensor); - - if (err) - DBG(3, "I2C write failed for %s image sensor", sensor->name); - - PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " - "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X", - n, data0, data1, data2, data3, data4, data5); - - return err ? -1 : 0; -} - - -int -sn9c102_i2c_try_read(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, u8 address) -{ - return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id, - address, 1, NULL); -} - - -static int sn9c102_i2c_try_write(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, - u8 address, u8 value) -{ - return sn9c102_i2c_try_raw_write(cam, sensor, 3, - sensor->i2c_slave_id, address, - value, 0, 0, 0); -} - - -int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address) -{ - return sn9c102_i2c_try_read(cam, &cam->sensor, address); -} - - -int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) -{ - return sn9c102_i2c_try_write(cam, &cam->sensor, address, value); -} - -/*****************************************************************************/ - -static size_t sn9c102_sof_length(struct sn9c102_device* cam) -{ - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - return 12; - case BRIDGE_SN9C103: - return 18; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - return 62; - } - - return 0; -} - - -static void* -sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) -{ - static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; - const char *m = mem; - size_t soflen = 0, i, j; - - soflen = sn9c102_sof_length(cam); - - for (i = 0; i < len; i++) { - size_t b; - - /* Read the variable part of the header */ - if (unlikely(cam->sof.bytesread >= sizeof(marker))) { - cam->sof.header[cam->sof.bytesread] = *(m+i); - if (++cam->sof.bytesread == soflen) { - cam->sof.bytesread = 0; - return mem + i; - } - continue; - } - - /* Search for the SOF marker (fixed part) in the header */ - for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) { - if (unlikely(i+j == len)) - return NULL; - if (*(m+i+j) == marker[cam->sof.bytesread]) { - cam->sof.header[cam->sof.bytesread] = *(m+i+j); - if (++cam->sof.bytesread == sizeof(marker)) { - PDBGG("Bytes to analyze: %zd. SOF " - "starts at byte #%zd", len, i); - i += j+1; - break; - } - } else { - cam->sof.bytesread = 0; - break; - } - } - } - - return NULL; -} - - -static void* -sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) -{ - static const u8 eof_header[4][4] = { - {0x00, 0x00, 0x00, 0x00}, - {0x40, 0x00, 0x00, 0x00}, - {0x80, 0x00, 0x00, 0x00}, - {0xc0, 0x00, 0x00, 0x00}, - }; - size_t i, j; - - /* The EOF header does not exist in compressed data */ - if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || - cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - return NULL; - - /* - The EOF header might cross the packet boundary, but this is not a - problem, since the end of a frame is determined by checking its size - in the first place. - */ - for (i = 0; (len >= 4) && (i <= len - 4); i++) - for (j = 0; j < ARRAY_SIZE(eof_header); j++) - if (!memcmp(mem + i, eof_header[j], 4)) - return mem + i; - - return NULL; -} - - -static void -sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f) -{ - static const u8 jpeg_header[589] = { - 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05, - 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06, - 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, - 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16, - 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16, - 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29, - 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29, - 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a, - 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2, - 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, - 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, - 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, - 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, - 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, - 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, - 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, - 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, - 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, - 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, - 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, - 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, - 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, - 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, - 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, - 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, - 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, - 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, - 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, - 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, - 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, - 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, - 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, - 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, - 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, - 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, - 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, - 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, - 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11, - 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02, - 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, - 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 - }; - u8 *pos = f->bufmem; - - memcpy(pos, jpeg_header, sizeof(jpeg_header)); - *(pos + 6) = 0x00; - *(pos + 7 + 64) = 0x01; - if (cam->compression.quality == 0) { - memcpy(pos + 7, SN9C102_Y_QTABLE0, 64); - memcpy(pos + 8 + 64, SN9C102_UV_QTABLE0, 64); - } else if (cam->compression.quality == 1) { - memcpy(pos + 7, SN9C102_Y_QTABLE1, 64); - memcpy(pos + 8 + 64, SN9C102_UV_QTABLE1, 64); - } - *(pos + 564) = cam->sensor.pix_format.width & 0xFF; - *(pos + 563) = (cam->sensor.pix_format.width >> 8) & 0xFF; - *(pos + 562) = cam->sensor.pix_format.height & 0xFF; - *(pos + 561) = (cam->sensor.pix_format.height >> 8) & 0xFF; - *(pos + 567) = 0x21; - - f->buf.bytesused += sizeof(jpeg_header); -} - - -static void sn9c102_urb_complete(struct urb *urb) -{ - struct sn9c102_device* cam = urb->context; - struct sn9c102_frame_t** f; - size_t imagesize, soflen; - u8 i; - int err = 0; - - if (urb->status == -ENOENT) - return; - - f = &cam->frame_current; - - if (cam->stream == STREAM_INTERRUPT) { - cam->stream = STREAM_OFF; - if ((*f)) - (*f)->state = F_QUEUED; - cam->sof.bytesread = 0; - DBG(3, "Stream interrupted by application"); - wake_up(&cam->wait_stream); - } - - if (cam->state & DEV_DISCONNECTED) - return; - - if (cam->state & DEV_MISCONFIGURED) { - wake_up_interruptible(&cam->wait_frame); - return; - } - - if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) - goto resubmit_urb; - - if (!(*f)) - (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t, - frame); - - imagesize = (cam->sensor.pix_format.width * - cam->sensor.pix_format.height * - cam->sensor.pix_format.priv) / 8; - if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - imagesize += 589; /* length of jpeg header */ - soflen = sn9c102_sof_length(cam); - - for (i = 0; i < urb->number_of_packets; i++) { - unsigned int img, len, status; - void *pos, *sof, *eof; - - len = urb->iso_frame_desc[i].actual_length; - status = urb->iso_frame_desc[i].status; - pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; - - if (status) { - DBG(3, "Error in isochronous frame"); - (*f)->state = F_ERROR; - cam->sof.bytesread = 0; - continue; - } - - PDBGG("Isochrnous frame: length %u, #%u i", len, i); - -redo: - sof = sn9c102_find_sof_header(cam, pos, len); - if (likely(!sof)) { - eof = sn9c102_find_eof_header(cam, pos, len); - if ((*f)->state == F_GRABBING) { -end_of_frame: - img = len; - - if (eof) - img = (eof > pos) ? eof - pos - 1 : 0; - - if ((*f)->buf.bytesused + img > imagesize) { - u32 b; - b = (*f)->buf.bytesused + img - - imagesize; - img = imagesize - (*f)->buf.bytesused; - PDBGG("Expected EOF not found: video " - "frame cut"); - if (eof) - DBG(3, "Exceeded limit: +%u " - "bytes", (unsigned)(b)); - } - - memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, - img); - - if ((*f)->buf.bytesused == 0) - do_gettimeofday(&(*f)->buf.timestamp); - - (*f)->buf.bytesused += img; - - if ((*f)->buf.bytesused == imagesize || - ((cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_SN9C10X || - cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_JPEG) && eof)) { - u32 b; - - b = (*f)->buf.bytesused; - (*f)->state = F_DONE; - (*f)->buf.sequence= ++cam->frame_count; - - spin_lock(&cam->queue_lock); - list_move_tail(&(*f)->frame, - &cam->outqueue); - if (!list_empty(&cam->inqueue)) - (*f) = list_entry( - cam->inqueue.next, - struct sn9c102_frame_t, - frame ); - else - (*f) = NULL; - spin_unlock(&cam->queue_lock); - - memcpy(cam->sysfs.frame_header, - cam->sof.header, soflen); - - DBG(3, "Video frame captured: %lu " - "bytes", (unsigned long)(b)); - - if (!(*f)) - goto resubmit_urb; - - } else if (eof) { - (*f)->state = F_ERROR; - DBG(3, "Not expected EOF after %lu " - "bytes of image data", - (unsigned long) - ((*f)->buf.bytesused)); - } - - if (sof) /* (1) */ - goto start_of_frame; - - } else if (eof) { - DBG(3, "EOF without SOF"); - continue; - - } else { - PDBGG("Ignoring pointless isochronous frame"); - continue; - } - - } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) { -start_of_frame: - (*f)->state = F_GRABBING; - (*f)->buf.bytesused = 0; - len -= (sof - pos); - pos = sof; - if (cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_JPEG) - sn9c102_write_jpegheader(cam, (*f)); - DBG(3, "SOF detected: new video frame"); - if (len) - goto redo; - - } else if ((*f)->state == F_GRABBING) { - eof = sn9c102_find_eof_header(cam, pos, len); - if (eof && eof < sof) - goto end_of_frame; /* (1) */ - else { - if (cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_SN9C10X || - cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_JPEG) { - if (sof - pos >= soflen) { - eof = sof - soflen; - } else { /* remove header */ - eof = pos; - (*f)->buf.bytesused -= - (soflen - (sof - pos)); - } - goto end_of_frame; - } else { - DBG(3, "SOF before expected EOF after " - "%lu bytes of image data", - (unsigned long) - ((*f)->buf.bytesused)); - goto start_of_frame; - } - } - } - } - -resubmit_urb: - urb->dev = cam->usbdev; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0 && err != -EPERM) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "usb_submit_urb() failed"); - } - - wake_up_interruptible(&cam->wait_frame); -} - - -static int sn9c102_start_transfer(struct sn9c102_device* cam) -{ - struct usb_device *udev = cam->usbdev; - struct urb* urb; - struct usb_host_interface* altsetting = usb_altnum_to_altsetting( - usb_ifnum_to_if(udev, 0), - SN9C102_ALTERNATE_SETTING); - const unsigned int psz = le16_to_cpu(altsetting-> - endpoint[0].desc.wMaxPacketSize); - s8 i, j; - int err = 0; - - for (i = 0; i < SN9C102_URBS; i++) { - cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz, - GFP_KERNEL); - if (!cam->transfer_buffer[i]) { - err = -ENOMEM; - DBG(1, "Not enough memory"); - goto free_buffers; - } - } - - for (i = 0; i < SN9C102_URBS; i++) { - urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL); - cam->urb[i] = urb; - if (!urb) { - err = -ENOMEM; - DBG(1, "usb_alloc_urb() failed"); - goto free_urbs; - } - urb->dev = udev; - urb->context = cam; - urb->pipe = usb_rcvisocpipe(udev, 1); - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = SN9C102_ISO_PACKETS; - urb->complete = sn9c102_urb_complete; - urb->transfer_buffer = cam->transfer_buffer[i]; - urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS; - urb->interval = 1; - for (j = 0; j < SN9C102_ISO_PACKETS; j++) { - urb->iso_frame_desc[j].offset = psz * j; - urb->iso_frame_desc[j].length = psz; - } - } - - /* Enable video */ - if (!(cam->reg[0x01] & 0x04)) { - err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01); - if (err) { - err = -EIO; - DBG(1, "I/O hardware error"); - goto free_urbs; - } - } - - err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING); - if (err) { - DBG(1, "usb_set_interface() failed"); - goto free_urbs; - } - - cam->frame_current = NULL; - cam->sof.bytesread = 0; - - for (i = 0; i < SN9C102_URBS; i++) { - err = usb_submit_urb(cam->urb[i], GFP_KERNEL); - if (err) { - for (j = i-1; j >= 0; j--) - usb_kill_urb(cam->urb[j]); - DBG(1, "usb_submit_urb() failed, error %d", err); - goto free_urbs; - } - } - - return 0; - -free_urbs: - for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) - usb_free_urb(cam->urb[i]); - -free_buffers: - for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++) - kfree(cam->transfer_buffer[i]); - - return err; -} - - -static int sn9c102_stop_transfer(struct sn9c102_device* cam) -{ - struct usb_device *udev = cam->usbdev; - s8 i; - int err = 0; - - if (cam->state & DEV_DISCONNECTED) - return 0; - - for (i = SN9C102_URBS-1; i >= 0; i--) { - usb_kill_urb(cam->urb[i]); - usb_free_urb(cam->urb[i]); - kfree(cam->transfer_buffer[i]); - } - - err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ - if (err) - DBG(3, "usb_set_interface() failed"); - - return err; -} - - -static int sn9c102_stream_interrupt(struct sn9c102_device* cam) -{ - long timeout; - - cam->stream = STREAM_INTERRUPT; - timeout = wait_event_timeout(cam->wait_stream, - (cam->stream == STREAM_OFF) || - (cam->state & DEV_DISCONNECTED), - SN9C102_URB_TIMEOUT); - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - else if (cam->stream != STREAM_OFF) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "URB timeout reached. The camera is misconfigured. " - "To use it, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - return 0; -} - -/*****************************************************************************/ - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) -{ - char str[7]; - char* endp; - unsigned long val; - - if (len < 6) { - strncpy(str, buff, len); - str[len] = '\0'; - } else { - strncpy(str, buff, 6); - str[6] = '\0'; - } - - val = simple_strtoul(str, &endp, 0); - - *count = 0; - if (val <= 0xffff) - *count = (ssize_t)(endp - str); - if ((*count) && (len == *count+1) && (buff[*count] == '\n')) - *count += 1; - - return (u16)val; -} - -/* - NOTE 1: being inside one of the following methods implies that the v4l - device exists for sure (see kobjects and reference counters) - NOTE 2: buffers are PAGE_SIZE long -*/ - -static ssize_t sn9c102_show_reg(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.reg); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_reg(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u16 index; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - index = sn9c102_strtou16(buf, len, &count); - if (index >= ARRAY_SIZE(cam->reg) || !count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.reg = index; - - DBG(2, "Moved SN9C1XX register index to 0x%02X", cam->sysfs.reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t sn9c102_show_val(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd, value: %d", count, val); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_val(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u16 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - value = sn9c102_strtou16(buf, len, &count); - if (!count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - err = sn9c102_write_reg(cam, value, cam->sysfs.reg); - if (err) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - DBG(2, "Written SN9C1XX reg. 0x%02X, val. 0x%02X", - cam->sysfs.reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t sn9c102_show_i2c_reg(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u16 index; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - index = sn9c102_strtou16(buf, len, &count); - if (!count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.i2c_reg = index; - - DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t sn9c102_show_i2c_val(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENOSYS; - } - - if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd, value: %d", count, val); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u16 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENOSYS; - } - - value = sn9c102_strtou16(buf, len, &count); - if (!count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); - if (err) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", - cam->sysfs.i2c_reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_green(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - enum sn9c102_bridge bridge; - ssize_t res = 0; - u16 value; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - bridge = cam->bridge; - - mutex_unlock(&sn9c102_sysfs_lock); - - value = sn9c102_strtou16(buf, len, &count); - if (!count) - return -EINVAL; - - switch (bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - if (value > 0x0f) - return -EINVAL; - if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0) - res = sn9c102_store_val(cd, attr, buf, len); - break; - case BRIDGE_SN9C103: - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (value > 0x7f) - return -EINVAL; - if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0) - res = sn9c102_store_val(cd, attr, buf, len); - break; - } - - return res; -} - - -static ssize_t -sn9c102_store_blue(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - ssize_t res = 0; - u16 value; - ssize_t count; - - value = sn9c102_strtou16(buf, len, &count); - if (!count || value > 0x7f) - return -EINVAL; - - if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0) - res = sn9c102_store_val(cd, attr, buf, len); - - return res; -} - - -static ssize_t -sn9c102_store_red(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - ssize_t res = 0; - u16 value; - ssize_t count; - - value = sn9c102_strtou16(buf, len, &count); - if (!count || value > 0x7f) - return -EINVAL; - - if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0) - res = sn9c102_store_val(cd, attr, buf, len); - - return res; -} - - -static ssize_t sn9c102_show_frame_header(struct device* cd, - struct device_attribute *attr, - char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) - return -ENODEV; - - count = sizeof(cam->sysfs.frame_header); - memcpy(buf, cam->sysfs.frame_header, count); - - DBG(3, "Frame header, read bytes: %zd", count); - - return count; -} - - -static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg); -static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val); -static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); -static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static DEVICE_ATTR(green, S_IWUSR, NULL, sn9c102_store_green); -static DEVICE_ATTR(blue, S_IWUSR, NULL, sn9c102_store_blue); -static DEVICE_ATTR(red, S_IWUSR, NULL, sn9c102_store_red); -static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); - - -static int sn9c102_create_sysfs(struct sn9c102_device* cam) -{ - struct device *dev = &(cam->v4ldev->dev); - int err = 0; - - if ((err = device_create_file(dev, &dev_attr_reg))) - goto err_out; - if ((err = device_create_file(dev, &dev_attr_val))) - goto err_reg; - if ((err = device_create_file(dev, &dev_attr_frame_header))) - goto err_val; - - if (cam->sensor.sysfs_ops) { - if ((err = device_create_file(dev, &dev_attr_i2c_reg))) - goto err_frame_header; - if ((err = device_create_file(dev, &dev_attr_i2c_val))) - goto err_i2c_reg; - } - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if ((err = device_create_file(dev, &dev_attr_green))) - goto err_i2c_val; - } else { - if ((err = device_create_file(dev, &dev_attr_blue))) - goto err_i2c_val; - if ((err = device_create_file(dev, &dev_attr_red))) - goto err_blue; - } - - return 0; - -err_blue: - device_remove_file(dev, &dev_attr_blue); -err_i2c_val: - if (cam->sensor.sysfs_ops) - device_remove_file(dev, &dev_attr_i2c_val); -err_i2c_reg: - if (cam->sensor.sysfs_ops) - device_remove_file(dev, &dev_attr_i2c_reg); -err_frame_header: - device_remove_file(dev, &dev_attr_frame_header); -err_val: - device_remove_file(dev, &dev_attr_val); -err_reg: - device_remove_file(dev, &dev_attr_reg); -err_out: - return err; -} -#endif /* CONFIG_VIDEO_ADV_DEBUG */ - -/*****************************************************************************/ - -static int -sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || - pix->pixelformat == V4L2_PIX_FMT_JPEG) { - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, - 0x18); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, - 0x18); - break; - } - } else { - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, - 0x18); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, - 0x18); - break; - } - } - - return err ? -EIO : 0; -} - - -static int -sn9c102_set_compression(struct sn9c102_device* cam, - struct v4l2_jpegcompression* compression) -{ - int i, err = 0; - - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - if (compression->quality == 0) - err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, - 0x17); - else if (compression->quality == 1) - err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, - 0x17); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (compression->quality == 0) { - for (i = 0; i <= 63; i++) { - err += sn9c102_write_reg(cam, - SN9C102_Y_QTABLE1[i], - 0x100 + i); - err += sn9c102_write_reg(cam, - SN9C102_UV_QTABLE1[i], - 0x140 + i); - } - err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, - 0x18); - } else if (compression->quality == 1) { - for (i = 0; i <= 63; i++) { - err += sn9c102_write_reg(cam, - SN9C102_Y_QTABLE1[i], - 0x100 + i); - err += sn9c102_write_reg(cam, - SN9C102_UV_QTABLE1[i], - 0x140 + i); - } - err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40, - 0x18); - } - break; - } - - return err ? -EIO : 0; -} - - -static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale) -{ - u8 r = 0; - int err = 0; - - if (scale == 1) - r = cam->reg[0x18] & 0xcf; - else if (scale == 2) { - r = cam->reg[0x18] & 0xcf; - r |= 0x10; - } else if (scale == 4) - r = cam->reg[0x18] | 0x20; - - err += sn9c102_write_reg(cam, r, 0x18); - if (err) - return -EIO; - - PDBGG("Scaling factor: %u", scale); - - return 0; -} - - -static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &cam->sensor; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), - v_start = (u8)(rect->top - s->cropcap.bounds.top), - h_size = (u8)(rect->width / 16), - v_size = (u8)(rect->height / 16); - int err = 0; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - err += sn9c102_write_reg(cam, h_size, 0x15); - err += sn9c102_write_reg(cam, v_size, 0x16); - if (err) - return -EIO; - - PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " - "%u %u %u %u", h_start, v_start, h_size, v_size); - - return 0; -} - - -static int sn9c102_init(struct sn9c102_device* cam) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - struct v4l2_queryctrl *qctrl; - struct v4l2_rect* rect; - u8 i = 0; - int err = 0; - - if (!(cam->state & DEV_INITIALIZED)) { - mutex_init(&cam->open_mutex); - init_waitqueue_head(&cam->wait_open); - qctrl = s->qctrl; - rect = &(s->cropcap.defrect); - } else { /* use current values */ - qctrl = s->_qctrl; - rect = &(s->_rect); - } - - err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); - err += sn9c102_set_crop(cam, rect); - if (err) - return err; - - if (s->init) { - err = s->init(cam); - if (err) { - DBG(3, "Sensor initialization failed"); - return err; - } - } - - if (!(cam->state & DEV_INITIALIZED)) - if (cam->bridge == BRIDGE_SN9C101 || - cam->bridge == BRIDGE_SN9C102 || - cam->bridge == BRIDGE_SN9C103) { - if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8; - cam->compression.quality = cam->reg[0x17] & 0x01 ? - 0 : 1; - } else { - if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) - s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG; - cam->compression.quality = cam->reg[0x18] & 0x40 ? - 0 : 1; - err += sn9c102_set_compression(cam, &cam->compression); - } - else - err += sn9c102_set_compression(cam, &cam->compression); - err += sn9c102_set_pix_format(cam, &s->pix_format); - if (s->set_pix_format) - err += s->set_pix_format(cam, &s->pix_format); - if (err) - return err; - - if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || - s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - DBG(3, "Compressed video format is active, quality %d", - cam->compression.quality); - else - DBG(3, "Uncompressed video format is active"); - - if (s->set_crop) - if ((err = s->set_crop(cam, rect))) { - DBG(3, "set_crop() failed"); - return err; - } - - if (s->set_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (s->qctrl[i].id != 0 && - !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl.id = s->qctrl[i].id; - ctrl.value = qctrl[i].default_value; - err = s->set_ctrl(cam, &ctrl); - if (err) { - DBG(3, "Set %s control failed", - s->qctrl[i].name); - return err; - } - DBG(3, "Image sensor supports '%s' control", - s->qctrl[i].name); - } - } - - if (!(cam->state & DEV_INITIALIZED)) { - mutex_init(&cam->fileop_mutex); - spin_lock_init(&cam->queue_lock); - init_waitqueue_head(&cam->wait_frame); - init_waitqueue_head(&cam->wait_stream); - cam->nreadbuffers = 2; - memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); - memcpy(&(s->_rect), &(s->cropcap.defrect), - sizeof(struct v4l2_rect)); - cam->state |= DEV_INITIALIZED; - } - - DBG(2, "Initialization succeeded"); - return 0; -} - -/*****************************************************************************/ - -static void sn9c102_release_resources(struct kref *kref) -{ - struct sn9c102_device *cam; - - mutex_lock(&sn9c102_sysfs_lock); - - cam = container_of(kref, struct sn9c102_device, kref); - - DBG(2, "V4L2 device %s deregistered", - video_device_node_name(cam->v4ldev)); - video_set_drvdata(cam->v4ldev, NULL); - video_unregister_device(cam->v4ldev); - usb_put_dev(cam->usbdev); - kfree(cam->control_buffer); - kfree(cam); - - mutex_unlock(&sn9c102_sysfs_lock); - -} - - -static int sn9c102_open(struct file *filp) -{ - struct sn9c102_device* cam; - int err = 0; - - /* - A read_trylock() in open() is the only safe way to prevent race - conditions with disconnect(), one close() and multiple (not - necessarily simultaneous) attempts to open(). For example, it - prevents from waiting for a second access, while the device - structure is being deallocated, after a possible disconnect() and - during a following close() holding the write lock: given that, after - this deallocation, no access will be possible anymore, using the - non-trylock version would have let open() gain the access to the - device structure improperly. - For this reason the lock must also not be per-device. - */ - if (!down_read_trylock(&sn9c102_dev_lock)) - return -ERESTARTSYS; - - cam = video_drvdata(filp); - - if (wait_for_completion_interruptible(&cam->probe)) { - up_read(&sn9c102_dev_lock); - return -ERESTARTSYS; - } - - kref_get(&cam->kref); - - /* - Make sure to isolate all the simultaneous opens. - */ - if (mutex_lock_interruptible(&cam->open_mutex)) { - kref_put(&cam->kref, sn9c102_release_resources); - up_read(&sn9c102_dev_lock); - return -ERESTARTSYS; - } - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - err = -ENODEV; - goto out; - } - - if (cam->users) { - DBG(2, "Device %s is already in use", - video_device_node_name(cam->v4ldev)); - DBG(3, "Simultaneous opens are not supported"); - /* - open() must follow the open flags and should block - eventually while the device is in use. - */ - if ((filp->f_flags & O_NONBLOCK) || - (filp->f_flags & O_NDELAY)) { - err = -EWOULDBLOCK; - goto out; - } - DBG(2, "A blocking open() has been requested. Wait for the " - "device to be released..."); - up_read(&sn9c102_dev_lock); - /* - We will not release the "open_mutex" lock, so that only one - process can be in the wait queue below. This way the process - will be sleeping while holding the lock, without loosing its - priority after any wake_up(). - */ - err = wait_event_interruptible_exclusive(cam->wait_open, - (cam->state & DEV_DISCONNECTED) - || !cam->users); - down_read(&sn9c102_dev_lock); - if (err) - goto out; - if (cam->state & DEV_DISCONNECTED) { - err = -ENODEV; - goto out; - } - } - - if (cam->state & DEV_MISCONFIGURED) { - err = sn9c102_init(cam); - if (err) { - DBG(1, "Initialization failed again. " - "I will retry on next open()."); - goto out; - } - cam->state &= ~DEV_MISCONFIGURED; - } - - if ((err = sn9c102_start_transfer(cam))) - goto out; - - filp->private_data = cam; - cam->users++; - cam->io = IO_NONE; - cam->stream = STREAM_OFF; - cam->nbuffers = 0; - cam->frame_count = 0; - sn9c102_empty_framequeues(cam); - - DBG(3, "Video device %s is open", video_device_node_name(cam->v4ldev)); - -out: - mutex_unlock(&cam->open_mutex); - if (err) - kref_put(&cam->kref, sn9c102_release_resources); - - up_read(&sn9c102_dev_lock); - return err; -} - - -static int sn9c102_release(struct file *filp) -{ - struct sn9c102_device* cam; - - down_write(&sn9c102_dev_lock); - - cam = video_drvdata(filp); - - sn9c102_stop_transfer(cam); - sn9c102_release_buffers(cam); - cam->users--; - wake_up_interruptible_nr(&cam->wait_open, 1); - - DBG(3, "Video device %s closed", video_device_node_name(cam->v4ldev)); - - kref_put(&cam->kref, sn9c102_release_resources); - - up_write(&sn9c102_dev_lock); - - return 0; -} - - -static ssize_t -sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) -{ - struct sn9c102_device *cam = video_drvdata(filp); - struct sn9c102_frame_t* f, * i; - unsigned long lock_flags; - long timeout; - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (cam->io == IO_MMAP) { - DBG(3, "Close and open the device again to choose " - "the read method"); - mutex_unlock(&cam->fileop_mutex); - return -EBUSY; - } - - if (cam->io == IO_NONE) { - if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { - DBG(1, "read() failed, not enough memory"); - mutex_unlock(&cam->fileop_mutex); - return -ENOMEM; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (list_empty(&cam->inqueue)) { - if (!list_empty(&cam->outqueue)) - sn9c102_empty_framequeues(cam); - sn9c102_queue_unusedframes(cam); - } - - if (!count) { - mutex_unlock(&cam->fileop_mutex); - return 0; - } - - if (list_empty(&cam->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - if (!cam->module_param.frame_timeout) { - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) { - mutex_unlock(&cam->fileop_mutex); - return err; - } - } else { - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - msecs_to_jiffies( - cam->module_param.frame_timeout * 1000 - ) - ); - if (timeout < 0) { - mutex_unlock(&cam->fileop_mutex); - return timeout; - } else if (timeout == 0 && - !(cam->state & DEV_DISCONNECTED)) { - DBG(1, "Video frame timeout elapsed"); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - } - if (cam->state & DEV_DISCONNECTED) { - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - if (cam->state & DEV_MISCONFIGURED) { - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - } - - f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); - - if (count > f->buf.bytesused) - count = f->buf.bytesused; - - if (copy_to_user(buf, f->bufmem, count)) { - err = -EFAULT; - goto exit; - } - *f_pos += count; - -exit: - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(i, &cam->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - sn9c102_queue_unusedframes(cam); - - PDBGG("Frame #%lu, bytes read: %zu", - (unsigned long)f->buf.index, count); - - mutex_unlock(&cam->fileop_mutex); - - return count; -} - - -static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) -{ - struct sn9c102_device *cam = video_drvdata(filp); - struct sn9c102_frame_t* f; - unsigned long lock_flags; - unsigned int mask = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return POLLERR; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - goto error; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - goto error; - } - - if (cam->io == IO_NONE) { - if (!sn9c102_request_buffers(cam, cam->nreadbuffers, - IO_READ)) { - DBG(1, "poll() failed, not enough memory"); - goto error; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (cam->io == IO_READ) { - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(f, &cam->outqueue, frame) - f->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - sn9c102_queue_unusedframes(cam); - } - - poll_wait(filp, &cam->wait_frame, wait); - - if (!list_empty(&cam->outqueue)) - mask |= POLLIN | POLLRDNORM; - - mutex_unlock(&cam->fileop_mutex); - - return mask; - -error: - mutex_unlock(&cam->fileop_mutex); - return POLLERR; -} - - -static void sn9c102_vm_open(struct vm_area_struct* vma) -{ - struct sn9c102_frame_t* f = vma->vm_private_data; - f->vma_use_count++; -} - - -static void sn9c102_vm_close(struct vm_area_struct* vma) -{ - /* NOTE: buffers are not freed here */ - struct sn9c102_frame_t* f = vma->vm_private_data; - f->vma_use_count--; -} - - -static const struct vm_operations_struct sn9c102_vm_ops = { - .open = sn9c102_vm_open, - .close = sn9c102_vm_close, -}; - - -static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) -{ - struct sn9c102_device *cam = video_drvdata(filp); - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { - mutex_unlock(&cam->fileop_mutex); - return -EACCES; - } - - if (cam->io != IO_MMAP || - size != PAGE_ALIGN(cam->frame[0].buf.length)) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - for (i = 0; i < cam->nbuffers; i++) { - if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == cam->nbuffers) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; - - pos = cam->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &sn9c102_vm_ops; - vma->vm_private_data = &cam->frame[i]; - sn9c102_vm_open(vma); - - mutex_unlock(&cam->fileop_mutex); - - return 0; -} - -/*****************************************************************************/ - -static int -sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_capability cap = { - .driver = "sn9c102", - .version = SN9C102_MODULE_VERSION_CODE, - .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING, - }; - - strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); - if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) - strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev), - sizeof(cap.bus_info)); - - if (copy_to_user(arg, &cap, sizeof(cap))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_input i; - - if (copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - - if (i.index) - return -EINVAL; - - memset(&i, 0, sizeof(i)); - strcpy(i.name, "Camera"); - i.type = V4L2_INPUT_TYPE_CAMERA; - i.capabilities = V4L2_IN_CAP_STD; - - if (copy_to_user(arg, &i, sizeof(i))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg) -{ - int index = 0; - - if (copy_to_user(arg, &index, sizeof(index))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg) -{ - int index; - - if (copy_from_user(&index, arg, sizeof(index))) - return -EFAULT; - - if (index != 0) - return -EINVAL; - - return 0; -} - - -static int -sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_queryctrl qc; - u8 i; - - if (copy_from_user(&qc, arg, sizeof(qc))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (qc.id && qc.id == s->qctrl[i].id) { - memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); - if (copy_to_user(arg, &qc, sizeof(qc))) - return -EFAULT; - return 0; - } - - return -EINVAL; -} - - -static int -sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - int err = 0; - u8 i; - - if (!s->get_ctrl && !s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - if (!s->get_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (ctrl.id && ctrl.id == s->qctrl[i].id) { - ctrl.value = s->_qctrl[i].default_value; - goto exit; - } - return -EINVAL; - } else - err = s->get_ctrl(cam, &ctrl); - -exit: - if (copy_to_user(arg, &ctrl, sizeof(ctrl))) - return -EFAULT; - - PDBGG("VIDIOC_G_CTRL: id %lu, value %lu", - (unsigned long)ctrl.id, (unsigned long)ctrl.value); - - return err; -} - - -static int -sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - u8 i; - int err = 0; - - if (!s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) { - if (ctrl.id == s->qctrl[i].id) { - if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) - return -EINVAL; - if (ctrl.value < s->qctrl[i].minimum || - ctrl.value > s->qctrl[i].maximum) - return -ERANGE; - ctrl.value -= ctrl.value % s->qctrl[i].step; - break; - } - } - if (i == ARRAY_SIZE(s->qctrl)) - return -EINVAL; - if ((err = s->set_ctrl(cam, &ctrl))) - return err; - - s->_qctrl[i].default_value = ctrl.value; - - PDBGG("VIDIOC_S_CTRL: id %lu, value %lu", - (unsigned long)ctrl.id, (unsigned long)ctrl.value); - - return 0; -} - - -static int -sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_cropcap* cc = &(cam->sensor.cropcap); - - cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cc->pixelaspect.numerator = 1; - cc->pixelaspect.denominator = 1; - - if (copy_to_user(arg, cc, sizeof(*cc))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_crop crop = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - }; - - memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); - - if (copy_to_user(arg, &crop, sizeof(crop))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_crop crop; - struct v4l2_rect* rect; - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_pix_format* pix_format = &(s->pix_format); - u8 scale; - const enum sn9c102_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&crop, arg, sizeof(crop))) - return -EFAULT; - - rect = &(crop.c); - - if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_CROP failed. " - "Unmap the buffers first."); - return -EBUSY; - } - - /* Preserve R,G or B origin */ - rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; - rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; - - if (rect->width < 16) - rect->width = 16; - if (rect->height < 16) - rect->height = 16; - if (rect->width > bounds->width) - rect->width = bounds->width; - if (rect->height > bounds->height) - rect->height = bounds->height; - if (rect->left < bounds->left) - rect->left = bounds->left; - if (rect->top < bounds->top) - rect->top = bounds->top; - if (rect->left + rect->width > bounds->left + bounds->width) - rect->left = bounds->left+bounds->width - rect->width; - if (rect->top + rect->height > bounds->top + bounds->height) - rect->top = bounds->top+bounds->height - rect->height; - - rect->width &= ~15L; - rect->height &= ~15L; - - if (SN9C102_PRESERVE_IMGSCALE) { - /* Calculate the actual scaling factor */ - u32 a, b; - a = rect->width * rect->height; - b = pix_format->width * pix_format->height; - scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; - } else - scale = 1; - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &crop, sizeof(crop))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - sn9c102_release_buffers(cam); - - err = sn9c102_set_crop(cam, rect); - if (s->set_crop) - err += s->set_crop(cam, rect); - err += sn9c102_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - s->pix_format.width = rect->width/scale; - s->pix_format.height = rect->height/scale; - memcpy(&(s->_rect), rect, sizeof(*rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -ENOMEM; - } - - if (cam->io == IO_READ) - sn9c102_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - sn9c102_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_frmsizeenum frmsize; - - if (copy_from_user(&frmsize, arg, sizeof(frmsize))) - return -EFAULT; - - if (frmsize.index != 0) - return -EINVAL; - - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X && - frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) - return -EINVAL; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG && - frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) - return -EINVAL; - } - - frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE; - frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16; - frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16; - frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width; - frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height; - memset(&frmsize.reserved, 0, sizeof(frmsize.reserved)); - - if (copy_to_user(arg, &frmsize, sizeof(frmsize))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_fmtdesc fmtd; - - if (copy_from_user(&fmtd, arg, sizeof(fmtd))) - return -EFAULT; - - if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (fmtd.index == 0) { - strcpy(fmtd.description, "bayer rgb"); - fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; - } else if (fmtd.index == 1) { - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - strcpy(fmtd.description, "compressed"); - fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - strcpy(fmtd.description, "JPEG"); - fmtd.pixelformat = V4L2_PIX_FMT_JPEG; - break; - } - fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; - } else - return -EINVAL; - - fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); - - if (copy_to_user(arg, &fmtd, sizeof(fmtd))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ? - V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; - pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X || - pfmt->pixelformat == V4L2_PIX_FMT_JPEG) - ? 0 : (pfmt->width * pfmt->priv) / 8; - pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); - pfmt->field = V4L2_FIELD_NONE; - memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); - - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, - void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_format format; - struct v4l2_pix_format* pix; - struct v4l2_pix_format* pfmt = &(s->pix_format); - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_rect rect; - u8 scale; - const enum sn9c102_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - pix = &(format.fmt.pix); - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memcpy(&rect, &(s->_rect), sizeof(rect)); - - { /* calculate the actual scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; - } - - rect.width = scale * pix->width; - rect.height = scale * pix->height; - - if (rect.width < 16) - rect.width = 16; - if (rect.height < 16) - rect.height = 16; - if (rect.width > bounds->left + bounds->width - rect.left) - rect.width = bounds->left + bounds->width - rect.left; - if (rect.height > bounds->top + bounds->height - rect.top) - rect.height = bounds->top + bounds->height - rect.top; - - rect.width &= ~15L; - rect.height &= ~15L; - - { /* adjust the scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; - } - - pix->width = rect.width / scale; - pix->height = rect.height / scale; - - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && - pix->pixelformat != V4L2_PIX_FMT_SBGGR8) - pix->pixelformat = pfmt->pixelformat; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (pix->pixelformat != V4L2_PIX_FMT_JPEG && - pix->pixelformat != V4L2_PIX_FMT_SBGGR8) - pix->pixelformat = pfmt->pixelformat; - break; - } - pix->priv = pfmt->priv; /* bpp */ - pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ? - V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; - pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || - pix->pixelformat == V4L2_PIX_FMT_JPEG) - ? 0 : (pix->width * pix->priv) / 8; - pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); - pix->field = V4L2_FIELD_NONE; - - if (cmd == VIDIOC_TRY_FMT) { - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - return 0; - } - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_FMT failed. Unmap the " - "buffers first."); - return -EBUSY; - } - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &format, sizeof(format))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - sn9c102_release_buffers(cam); - - err += sn9c102_set_pix_format(cam, pix); - err += sn9c102_set_crop(cam, &rect); - if (s->set_pix_format) - err += s->set_pix_format(cam, pix); - if (s->set_crop) - err += s->set_crop(cam, &rect); - err += sn9c102_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - memcpy(pfmt, pix, sizeof(*pix)); - memcpy(&(s->_rect), &rect, sizeof(rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -ENOMEM; - } - - if (cam->io == IO_READ) - sn9c102_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - sn9c102_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg) -{ - if (copy_to_user(arg, &cam->compression, sizeof(cam->compression))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_jpegcompression jc; - const enum sn9c102_stream_state stream = cam->stream; - int err = 0; - - if (copy_from_user(&jc, arg, sizeof(jc))) - return -EFAULT; - - if (jc.quality != 0 && jc.quality != 1) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - err += sn9c102_set_compression(cam, &jc); - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware problems. " - "To use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - cam->compression.quality = jc.quality; - - cam->stream = stream; - - return 0; -} - - -static int -sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_requestbuffers rb; - u32 i; - int err; - - if (copy_from_user(&rb, arg, sizeof(rb))) - return -EFAULT; - - if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb.memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (cam->io == IO_READ) { - DBG(3, "Close and open the device again to choose the mmap " - "I/O method"); - return -EBUSY; - } - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " - "still mapped."); - return -EBUSY; - } - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - sn9c102_empty_framequeues(cam); - - sn9c102_release_buffers(cam); - if (rb.count) - rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP); - - if (copy_to_user(arg, &rb, sizeof(rb))) { - sn9c102_release_buffers(cam); - cam->io = IO_NONE; - return -EFAULT; - } - - cam->io = rb.count ? IO_MMAP : IO_NONE; - - return 0; -} - - -static int -sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); - - if (cam->frame[b.index].vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (cam->frame[b.index].state == F_DONE) - b.flags |= V4L2_BUF_FLAG_DONE; - else if (cam->frame[b.index].state != F_UNUSED) - b.flags |= V4L2_BUF_FLAG_QUEUED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - unsigned long lock_flags; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->frame[b.index].state != F_UNUSED) - return -EINVAL; - - cam->frame[b.index].state = F_QUEUED; - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - PDBGG("Frame #%lu queued", (unsigned long)b.index); - - return 0; -} - - -static int -sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, - void __user * arg) -{ - struct v4l2_buffer b; - struct sn9c102_frame_t *f; - unsigned long lock_flags; - long timeout; - int err = 0; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&cam->outqueue)) { - if (cam->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - if (!cam->module_param.frame_timeout) { - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) - return err; - } else { - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) - return timeout; - else if (timeout == 0 && - !(cam->state & DEV_DISCONNECTED)) { - DBG(1, "Video frame timeout elapsed"); - return -EIO; - } - } - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - if (cam->state & DEV_MISCONFIGURED) - return -EIO; - } - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); - list_del(cam->outqueue.next); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - f->state = F_UNUSED; - - memcpy(&b, &f->buf, sizeof(b)); - if (f->vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); - - return 0; -} - - -static int -sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) -{ - int type; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - cam->stream = STREAM_ON; - - DBG(3, "Stream on"); - - return 0; -} - - -static int -sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg) -{ - int type, err; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - sn9c102_empty_framequeues(cam); - - DBG(3, "Stream off"); - - return 0; -} - - -static int -sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - - if (sp.parm.capture.readbuffers == 0) - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES) - sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - cam->nreadbuffers = sp.parm.capture.readbuffers; - - return 0; -} - - -static int -sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_audio audio; - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - return -EINVAL; - - if (copy_from_user(&audio, arg, sizeof(audio))) - return -EFAULT; - - if (audio.index != 0) - return -EINVAL; - - strcpy(audio.name, "Microphone"); - audio.capability = 0; - audio.mode = 0; - - if (copy_to_user(arg, &audio, sizeof(audio))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_audio audio; - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - return -EINVAL; - - if (copy_from_user(&audio, arg, sizeof(audio))) - return -EFAULT; - - memset(&audio, 0, sizeof(audio)); - strcpy(audio.name, "Microphone"); - - if (copy_to_user(arg, &audio, sizeof(audio))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_audio audio; - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - return -EINVAL; - - if (copy_from_user(&audio, arg, sizeof(audio))) - return -EFAULT; - - if (audio.index != 0) - return -EINVAL; - - return 0; -} - - -static long sn9c102_ioctl_v4l2(struct file *filp, - unsigned int cmd, void __user *arg) -{ - struct sn9c102_device *cam = video_drvdata(filp); - - switch (cmd) { - - case VIDIOC_QUERYCAP: - return sn9c102_vidioc_querycap(cam, arg); - - case VIDIOC_ENUMINPUT: - return sn9c102_vidioc_enuminput(cam, arg); - - case VIDIOC_G_INPUT: - return sn9c102_vidioc_g_input(cam, arg); - - case VIDIOC_S_INPUT: - return sn9c102_vidioc_s_input(cam, arg); - - case VIDIOC_QUERYCTRL: - return sn9c102_vidioc_query_ctrl(cam, arg); - - case VIDIOC_G_CTRL: - return sn9c102_vidioc_g_ctrl(cam, arg); - - case VIDIOC_S_CTRL: - return sn9c102_vidioc_s_ctrl(cam, arg); - - case VIDIOC_CROPCAP: - return sn9c102_vidioc_cropcap(cam, arg); - - case VIDIOC_G_CROP: - return sn9c102_vidioc_g_crop(cam, arg); - - case VIDIOC_S_CROP: - return sn9c102_vidioc_s_crop(cam, arg); - - case VIDIOC_ENUM_FRAMESIZES: - return sn9c102_vidioc_enum_framesizes(cam, arg); - - case VIDIOC_ENUM_FMT: - return sn9c102_vidioc_enum_fmt(cam, arg); - - case VIDIOC_G_FMT: - return sn9c102_vidioc_g_fmt(cam, arg); - - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - return sn9c102_vidioc_try_s_fmt(cam, cmd, arg); - - case VIDIOC_G_JPEGCOMP: - return sn9c102_vidioc_g_jpegcomp(cam, arg); - - case VIDIOC_S_JPEGCOMP: - return sn9c102_vidioc_s_jpegcomp(cam, arg); - - case VIDIOC_REQBUFS: - return sn9c102_vidioc_reqbufs(cam, arg); - - case VIDIOC_QUERYBUF: - return sn9c102_vidioc_querybuf(cam, arg); - - case VIDIOC_QBUF: - return sn9c102_vidioc_qbuf(cam, arg); - - case VIDIOC_DQBUF: - return sn9c102_vidioc_dqbuf(cam, filp, arg); - - case VIDIOC_STREAMON: - return sn9c102_vidioc_streamon(cam, arg); - - case VIDIOC_STREAMOFF: - return sn9c102_vidioc_streamoff(cam, arg); - - case VIDIOC_G_PARM: - return sn9c102_vidioc_g_parm(cam, arg); - - case VIDIOC_S_PARM: - return sn9c102_vidioc_s_parm(cam, arg); - - case VIDIOC_ENUMAUDIO: - return sn9c102_vidioc_enumaudio(cam, arg); - - case VIDIOC_G_AUDIO: - return sn9c102_vidioc_g_audio(cam, arg); - - case VIDIOC_S_AUDIO: - return sn9c102_vidioc_s_audio(cam, arg); - - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_QUERYSTD: - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYMENU: - case VIDIOC_ENUM_FRAMEINTERVALS: - return -EINVAL; - - default: - return -EINVAL; - - } -} - - -static long sn9c102_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct sn9c102_device *cam = video_drvdata(filp); - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - V4LDBG(3, "sn9c102", cmd); - - err = sn9c102_ioctl_v4l2(filp, cmd, (void __user *)arg); - - mutex_unlock(&cam->fileop_mutex); - - return err; -} - -/*****************************************************************************/ - -static const struct v4l2_file_operations sn9c102_fops = { - .owner = THIS_MODULE, - .open = sn9c102_open, - .release = sn9c102_release, - .unlocked_ioctl = sn9c102_ioctl, - .read = sn9c102_read, - .poll = sn9c102_poll, - .mmap = sn9c102_mmap, -}; - -/*****************************************************************************/ - -/* It exists a single interface only. We do not need to validate anything. */ -static int -sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct sn9c102_device* cam; - static unsigned int dev_nr; - unsigned int i; - int err = 0, r; - - if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL))) - return -ENOMEM; - - cam->usbdev = udev; - - if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { - DBG(1, "kzalloc() failed"); - err = -ENOMEM; - goto fail; - } - - if (!(cam->v4ldev = video_device_alloc())) { - DBG(1, "video_device_alloc() failed"); - err = -ENOMEM; - goto fail; - } - - r = sn9c102_read_reg(cam, 0x00); - if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { - DBG(1, "Sorry, this is not a SN9C1xx-based camera " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - err = -ENODEV; - goto fail; - } - - cam->bridge = id->driver_info; - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - DBG(2, "SN9C10[12] PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - break; - case BRIDGE_SN9C103: - DBG(2, "SN9C103 PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - break; - case BRIDGE_SN9C105: - DBG(2, "SN9C105 PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - break; - case BRIDGE_SN9C120: - DBG(2, "SN9C120 PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - break; - } - - for (i = 0; i < ARRAY_SIZE(sn9c102_sensor_table); i++) { - err = sn9c102_sensor_table[i](cam); - if (!err) - break; - } - - if (!err) { - DBG(2, "%s image sensor detected", cam->sensor.name); - DBG(3, "Support for %s maintained by %s", - cam->sensor.name, cam->sensor.maintainer); - } else { - DBG(1, "No supported image sensor detected for this bridge"); - err = -ENODEV; - goto fail; - } - - if (!(cam->bridge & cam->sensor.supported_bridge)) { - DBG(1, "Bridge not supported"); - err = -ENODEV; - goto fail; - } - - if (sn9c102_init(cam)) { - DBG(1, "Initialization failed. I will retry on open()."); - cam->state |= DEV_MISCONFIGURED; - } - - strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); - cam->v4ldev->fops = &sn9c102_fops; - cam->v4ldev->release = video_device_release; - cam->v4ldev->parent = &udev->dev; - - init_completion(&cam->probe); - - err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, - video_nr[dev_nr]); - if (err) { - DBG(1, "V4L2 device registration failed"); - if (err == -ENFILE && video_nr[dev_nr] == -1) - DBG(1, "Free /dev/videoX node not found"); - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - complete_all(&cam->probe); - goto fail; - } - - DBG(2, "V4L2 device registered as %s", - video_device_node_name(cam->v4ldev)); - - video_set_drvdata(cam->v4ldev, cam); - cam->module_param.force_munmap = force_munmap[dev_nr]; - cam->module_param.frame_timeout = frame_timeout[dev_nr]; - - dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - -#ifdef CONFIG_VIDEO_ADV_DEBUG - err = sn9c102_create_sysfs(cam); - if (!err) - DBG(2, "Optional device control through 'sysfs' " - "interface ready"); - else - DBG(2, "Failed to create optional 'sysfs' interface for " - "device controlling. Error #%d", err); -#else - DBG(2, "Optional device control through 'sysfs' interface disabled"); - DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " - "configuration option to enable it."); -#endif - - usb_set_intfdata(intf, cam); - kref_init(&cam->kref); - usb_get_dev(cam->usbdev); - - complete_all(&cam->probe); - - return 0; - -fail: - if (cam) { - kfree(cam->control_buffer); - if (cam->v4ldev) - video_device_release(cam->v4ldev); - kfree(cam); - } - return err; -} - - -static void sn9c102_usb_disconnect(struct usb_interface* intf) -{ - struct sn9c102_device* cam; - - down_write(&sn9c102_dev_lock); - - cam = usb_get_intfdata(intf); - - DBG(2, "Disconnecting %s...", cam->v4ldev->name); - - if (cam->users) { - DBG(2, "Device %s is open! Deregistration and memory " - "deallocation are deferred.", - video_device_node_name(cam->v4ldev)); - cam->state |= DEV_MISCONFIGURED; - sn9c102_stop_transfer(cam); - cam->state |= DEV_DISCONNECTED; - wake_up_interruptible(&cam->wait_frame); - wake_up(&cam->wait_stream); - } else - cam->state |= DEV_DISCONNECTED; - - wake_up_interruptible_all(&cam->wait_open); - - kref_put(&cam->kref, sn9c102_release_resources); - - up_write(&sn9c102_dev_lock); -} - - -static struct usb_driver sn9c102_usb_driver = { - .name = "sn9c102", - .id_table = sn9c102_id_table, - .probe = sn9c102_usb_probe, - .disconnect = sn9c102_usb_disconnect, -}; - -/*****************************************************************************/ - -static int __init sn9c102_module_init(void) -{ - int err = 0; - - KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION); - KDBG(3, SN9C102_MODULE_AUTHOR); - - if ((err = usb_register(&sn9c102_usb_driver))) - KDBG(1, "usb_register() failed"); - - return err; -} - - -static void __exit sn9c102_module_exit(void) -{ - usb_deregister(&sn9c102_usb_driver); -} - - -module_init(sn9c102_module_init); -module_exit(sn9c102_module_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_devtable.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_devtable.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_devtable.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_devtable.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -/*************************************************************************** - * Table of device identifiers of the SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_DEVTABLE_H_ -#define _SN9C102_DEVTABLE_H_ - -#include - -struct sn9c102_device; - -/* - Each SN9C1xx camera has proper PID/VID identifiers. - SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to - handle the video class interface. -*/ -#define SN9C102_USB_DEVICE(vend, prod, bridge) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_INT_CLASS, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bInterfaceClass = 0xff, \ - .driver_info = (bridge) - -static const struct usb_device_id sn9c102_id_table[] = { - /* SN9C101 and SN9C102 */ -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE - { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */ - { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), }, -#endif - { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), }, -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE - { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, -#endif - { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, /* not in sonixb */ -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE - { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ - { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, -#endif - { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* not in sonixb */ - /* SN9C103 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */ - { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */ -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE -/* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */ - { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */ - { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5110, non existent */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */ - { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */ -#endif - /* SN9C105 */ -#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE - { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, PO1030 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, OM6801 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, HV7131GP */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, MO4000 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */ - { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, - /* SN9C120 */ - { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */ - { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */ - { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), }, -#endif - { } -}; - -/* - Probing functions: on success, you must attach the sensor to the camera - by calling sn9c102_attach_sensor(). - To enable the I2C communication, you might need to perform a really basic - initialization of the SN9C1XX chip. - Functions must return 0 on success, the appropriate error otherwise. -*/ -extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); -extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); -extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); -extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); -extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam); -extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); -extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); -extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); -extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); -extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); -extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam); -extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); - -#endif /* _SN9C102_DEVTABLE_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -/*************************************************************************** - * V4L2 driver for SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_H_ -#define _SN9C102_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sn9c102_config.h" -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -enum sn9c102_frame_state { - F_UNUSED, - F_QUEUED, - F_GRABBING, - F_DONE, - F_ERROR, -}; - -struct sn9c102_frame_t { - void* bufmem; - struct v4l2_buffer buf; - enum sn9c102_frame_state state; - struct list_head frame; - unsigned long vma_use_count; -}; - -enum sn9c102_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -enum sn9c102_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -enum sn9c102_stream_state { - STREAM_OFF, - STREAM_INTERRUPT, - STREAM_ON, -}; - -typedef char sn9c102_sof_header_t[62]; - -struct sn9c102_sof_t { - sn9c102_sof_header_t header; - u16 bytesread; -}; - -struct sn9c102_sysfs_attr { - u16 reg, i2c_reg; - sn9c102_sof_header_t frame_header; -}; - -struct sn9c102_module_param { - u8 force_munmap; - u16 frame_timeout; -}; - -static DEFINE_MUTEX(sn9c102_sysfs_lock); -static DECLARE_RWSEM(sn9c102_dev_lock); - -struct sn9c102_device { - struct video_device* v4ldev; - - enum sn9c102_bridge bridge; - struct sn9c102_sensor sensor; - - struct usb_device* usbdev; - struct urb* urb[SN9C102_URBS]; - void* transfer_buffer[SN9C102_URBS]; - u8* control_buffer; - - struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES]; - struct list_head inqueue, outqueue; - u32 frame_count, nbuffers, nreadbuffers; - - enum sn9c102_io_method io; - enum sn9c102_stream_state stream; - - struct v4l2_jpegcompression compression; - - struct sn9c102_sysfs_attr sysfs; - struct sn9c102_sof_t sof; - u16 reg[384]; - - struct sn9c102_module_param module_param; - - struct kref kref; - enum sn9c102_dev_state state; - u8 users; - - struct completion probe; - struct mutex open_mutex, fileop_mutex; - spinlock_t queue_lock; - wait_queue_head_t wait_open, wait_frame, wait_stream; -}; - -/*****************************************************************************/ - -struct sn9c102_device* -sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id) -{ - return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; -} - - -void -sn9c102_attach_sensor(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor) -{ - memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor)); -} - - -enum sn9c102_bridge -sn9c102_get_bridge(struct sn9c102_device* cam) -{ - return cam->bridge; -} - - -struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam) -{ - return &cam->sensor; -} - -/*****************************************************************************/ - -#undef DBG -#undef KDBG -#ifdef SN9C102_DEBUG -# define DBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1) \ - dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) == 2) \ - dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __func__, __LINE__ , ## args); \ - } \ -} while (0) -# define V4LDBG(level, name, cmd) \ -do { \ - if (debug >= (level)) \ - v4l_print_ioctl(name, cmd); \ -} while (0) -# define KDBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1 || (level) == 2) \ - pr_info("sn9c102: " fmt "\n", ## args); \ - else if ((level) == 3) \ - pr_debug("sn9c102: [%s:%d] " fmt "\n", \ - __func__, __LINE__ , ## args); \ - } \ -} while (0) -#else -# define DBG(level, fmt, args...) do {;} while(0) -# define V4LDBG(level, name, cmd) do {;} while(0) -# define KDBG(level, fmt, args...) do {;} while(0) -#endif - -#undef PDBG -#define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \ - __LINE__ , ## args) - -#undef PDBGG -#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ - -#endif /* _SN9C102_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,264 +0,0 @@ -/*************************************************************************** - * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int hv7131d_init(struct sn9c102_device* cam) -{ - int err; - - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x60, 0x17}, - {0x0e, 0x18}, {0xf2, 0x19}); - - err += sn9c102_i2c_write(cam, 0x01, 0x04); - err += sn9c102_i2c_write(cam, 0x02, 0x00); - err += sn9c102_i2c_write(cam, 0x28, 0x00); - - return err; -} - - -static int hv7131d_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = sn9c102_i2c_read(cam, 0x26), - r2 = sn9c102_i2c_read(cam, 0x27); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 8) | (r2 & 0xff); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) - return -EIO; - ctrl->value = 0x3f - (ctrl->value & 0x3f); - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) - return -EIO; - ctrl->value = 0x3f - (ctrl->value & 0x3f); - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) - return -EIO; - ctrl->value = 0x3f - (ctrl->value & 0x3f); - return 0; - case SN9C102_V4L2_CID_RESET_LEVEL: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) - return -EIO; - ctrl->value &= 0x3f; - return 0; - case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0) - return -EIO; - ctrl->value &= 0x07; - return 0; - default: - return -EINVAL; - } -} - - -static int hv7131d_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8); - err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value); - break; - case SN9C102_V4L2_CID_RESET_LEVEL: - err += sn9c102_i2c_write(cam, 0x30, ctrl->value); - break; - case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: - err += sn9c102_i2c_write(cam, 0x34, ctrl->value); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int hv7131d_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int hv7131d_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x42, 0x19); - else - err += sn9c102_write_reg(cam, 0xf2, 0x19); - - return err; -} - - -static const struct sn9c102_sensor hv7131d = { - .name = "HV7131D", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x11, - .init = &hv7131d_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x0250, - .maximum = 0xffff, - .step = 0x0001, - .default_value = 0x0250, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x1e, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_RESET_LEVEL, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "reset level", - .minimum = 0x19, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x30, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "pixel bias voltage", - .minimum = 0x00, - .maximum = 0x07, - .step = 0x01, - .default_value = 0x02, - .flags = 0, - }, - }, - .get_ctrl = &hv7131d_get_ctrl, - .set_ctrl = &hv7131d_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &hv7131d_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &hv7131d_set_pix_format -}; - - -int sn9c102_probe_hv7131d(struct sn9c102_device* cam) -{ - int r0 = 0, r1 = 0, err; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); - - r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00); - r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01); - if (err || r0 < 0 || r1 < 0) - return -EIO; - - if ((r0 != 0x00 && r0 != 0x01) || r1 != 0x04) - return -ENODEV; - - sn9c102_attach_sensor(cam, &hv7131d); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,363 +0,0 @@ -/*************************************************************************** - * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int hv7131r_init(struct sn9c102_device* cam) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04}, - {0x20, 0x05}, {0x20, 0x06}, - {0x03, 0x10}, {0x00, 0x14}, - {0x60, 0x17}, {0x0a, 0x18}, - {0xf0, 0x19}, {0x1d, 0x1a}, - {0x10, 0x1b}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, - {0x00, 0x03}, {0x1a, 0x04}, - {0x44, 0x05}, {0x3e, 0x06}, - {0x1a, 0x07}, {0x03, 0x10}, - {0x08, 0x14}, {0xa3, 0x17}, - {0x4b, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x29, 0x21}, - {0x40, 0x22}, {0x54, 0x23}, - {0x66, 0x24}, {0x76, 0x25}, - {0x85, 0x26}, {0x94, 0x27}, - {0xa1, 0x28}, {0xae, 0x29}, - {0xbb, 0x2a}, {0xc7, 0x2b}, - {0xd3, 0x2c}, {0xde, 0x2d}, - {0xea, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3F}, - {0xC7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xC7, 0x48}, {0x01, 0x49}, - {0xC7, 0x4A}, {0x01, 0x4B}, - {0xC7, 0x4C}, {0x01, 0x4D}, - {0x44, 0x4E}, {0x00, 0x4F}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xC7, 0x54}, {0x01, 0x55}, - {0xC7, 0x56}, {0x01, 0x57}, - {0xC7, 0x58}, {0x01, 0x59}, - {0x44, 0x5A}, {0x00, 0x5B}, - {0x44, 0x5C}, {0x00, 0x5D}, - {0x44, 0x5E}, {0x00, 0x5F}, - {0xC7, 0x60}, {0x01, 0x61}, - {0xC7, 0x62}, {0x01, 0x63}, - {0xC7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6A}, {0x00, 0x6B}, - {0xC7, 0x6C}, {0x01, 0x6D}, - {0xC7, 0x6E}, {0x01, 0x6F}, - {0xC7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xC7, 0x78}, {0x01, 0x79}, - {0xC7, 0x7A}, {0x01, 0x7B}, - {0xC7, 0x7C}, {0x01, 0x7D}, - {0x44, 0x7E}, {0x00, 0x7F}, - {0x14, 0x84}, {0x00, 0x85}, - {0x27, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xEC, 0x8A}, {0x0f, 0x8B}, - {0xD8, 0x8C}, {0x0f, 0x8D}, - {0x3D, 0x8E}, {0x00, 0x8F}, - {0x3D, 0x90}, {0x00, 0x91}, - {0xCD, 0x92}, {0x0f, 0x93}, - {0xf7, 0x94}, {0x0f, 0x95}, - {0x0C, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x05, 0x9A}, {0x00, 0x9B}, - {0x04, 0x9C}, {0x00, 0x9D}, - {0x08, 0x9E}, {0x00, 0x9F}, - {0x2D, 0xC0}, {0x2D, 0xC1}, - {0x3A, 0xC2}, {0x05, 0xC3}, - {0x04, 0xC4}, {0x3F, 0xC5}, - {0x00, 0xC6}, {0x00, 0xC7}, - {0x50, 0xC8}, {0x3C, 0xC9}, - {0x28, 0xCA}, {0xD8, 0xCB}, - {0x14, 0xCC}, {0xEC, 0xCD}, - {0x32, 0xCE}, {0xDD, 0xCF}, - {0x32, 0xD0}, {0xDD, 0xD1}, - {0x6A, 0xD2}, {0x50, 0xD3}, - {0x00, 0xD4}, {0x00, 0xD5}, - {0x00, 0xD6}); - break; - default: - break; - } - - err += sn9c102_i2c_write(cam, 0x20, 0x00); - err += sn9c102_i2c_write(cam, 0x21, 0xd6); - err += sn9c102_i2c_write(cam, 0x25, 0x06); - - return err; -} - - -static int hv7131r_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) - return -EIO; - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) - return -EIO; - ctrl->value = ctrl->value & 0x3f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) - return -EIO; - ctrl->value = ctrl->value & 0x3f; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) - return -EIO; - ctrl->value = ctrl->value & 0x3f; - return 0; - case V4L2_CID_BLACK_LEVEL: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x08) ? 1 : 0; - return 0; - default: - return -EINVAL; - } -} - - -static int hv7131r_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x30, ctrl->value); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x31, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x33, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x32, ctrl->value); - break; - case V4L2_CID_BLACK_LEVEL: - { - int r = sn9c102_i2c_read(cam, 0x01); - if (r < 0) - return -EIO; - err += sn9c102_i2c_write(cam, 0x01, - (ctrl->value<<3) | (r&0xf7)); - } - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int hv7131r_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int hv7131r_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xa0, 0x19); - err += sn9c102_i2c_write(cam, 0x01, 0x04); - } else { - err += sn9c102_write_reg(cam, 0x30, 0x19); - err += sn9c102_i2c_write(cam, 0x01, 0x04); - } - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xa5, 0x17); - err += sn9c102_i2c_write(cam, 0x01, 0x24); - } else { - err += sn9c102_write_reg(cam, 0xa3, 0x17); - err += sn9c102_i2c_write(cam, 0x01, 0x04); - } - break; - default: - break; - } - - return err; -} - - -static const struct sn9c102_sensor hv7131r = { - .name = "HV7131R", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x11, - .init = &hv7131r_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x40, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x08, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x1a, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x2f, - .flags = 0, - }, - { - .id = V4L2_CID_BLACK_LEVEL, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto black level compensation", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &hv7131r_get_ctrl, - .set_ctrl = &hv7131r_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &hv7131r_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &hv7131r_set_pix_format -}; - - -int sn9c102_probe_hv7131r(struct sn9c102_device* cam) -{ - int devid, err; - - err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02}, - {0x34, 0x01}, {0x20, 0x17}, - {0x34, 0x01}, {0x46, 0x01}); - - devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00); - if (err || devid < 0) - return -EIO; - - if (devid != 0x02) - return -ENODEV; - - sn9c102_attach_sensor(cam, &hv7131r); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,352 +0,0 @@ -/*************************************************************************** - * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int mi0343_init(struct sn9c102_device* cam) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x0a, 0x14}, {0x40, 0x01}, - {0x20, 0x17}, {0x07, 0x18}, - {0xa0, 0x19}); - - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, - 0x01, 0xe1, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, - 0x02, 0x81, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, - 0x00, 0x17, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, - 0x00, 0x11, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, - 0x04, 0x9a, 0, 0); - - return err; -} - - -static int mi0343_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u8 data[2]; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2, - data) < 0) - return -EIO; - ctrl->value = data[0]; - return 0; - case V4L2_CID_GAIN: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2, - data) < 0) - return -EIO; - break; - case V4L2_CID_HFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x20 ? 1 : 0; - return 0; - case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x80 ? 1 : 0; - return 0; - case V4L2_CID_RED_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2, - data) < 0) - return -EIO; - break; - case V4L2_CID_BLUE_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2, - data) < 0) - return -EIO; - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2, - data) < 0) - return -EIO; - break; - default: - return -EINVAL; - } - - switch (ctrl->id) { - case V4L2_CID_GAIN: - case V4L2_CID_RED_BALANCE: - case V4L2_CID_BLUE_BALANCE: - case SN9C102_V4L2_CID_GREEN_BALANCE: - ctrl->value = data[1] | (data[0] << 8); - if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) - ctrl->value -= 0x10; - else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) - ctrl->value -= 0x60; - else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff) - ctrl->value -= 0xe0; - } - - return 0; -} - - -static int mi0343_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u16 reg = 0; - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - case V4L2_CID_RED_BALANCE: - case V4L2_CID_BLUE_BALANCE: - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (ctrl->value <= (0x3f-0x10)) - reg = 0x10 + ctrl->value; - else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60))) - reg = 0x60 + (ctrl->value - (0x3f-0x10)); - else - reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60)); - break; - } - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x09, ctrl->value, 0x00, - 0, 0); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x35, reg >> 8, reg & 0xff, - 0, 0); - break; - case V4L2_CID_HFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x40:0x00, - ctrl->value ? 0x20:0x00, - 0, 0); - break; - case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x80:0x00, - ctrl->value ? 0x80:0x00, - 0, 0); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2d, reg >> 8, reg & 0xff, - 0, 0); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2c, reg >> 8, reg & 0xff, - 0, 0); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2b, reg >> 8, reg & 0xff, - 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2e, reg >> 8, reg & 0xff, - 0, 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int mi0343_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int mi0343_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x03, 0, 0); - err += sn9c102_write_reg(cam, 0x20, 0x19); - } else { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x05, 0, 0); - err += sn9c102_write_reg(cam, 0xa0, 0x19); - } - - return err; -} - - -static const struct sn9c102_sensor mi0343 = { - .name = "MI-0343", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x5d, - .init = &mi0343_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x06, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/ - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)), - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &mi0343_get_ctrl, - .set_ctrl = &mi0343_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &mi0343_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &mi0343_set_pix_format -}; - - -int sn9c102_probe_mi0343(struct sn9c102_device* cam) -{ - u8 data[2]; - - if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17})) - return -EIO; - - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, - 2, data) < 0) - return -EIO; - - if (data[1] != 0x42 || data[0] != 0xe3) - return -ENODEV; - - sn9c102_attach_sensor(cam, &mi0343); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,453 +0,0 @@ -/*************************************************************************** - * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int mi0360_init(struct sn9c102_device* cam) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x0a, 0x14}, {0x40, 0x01}, - {0x20, 0x17}, {0x07, 0x18}, - {0xa0, 0x19}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, - {0x00, 0x03}, {0x1a, 0x04}, - {0x50, 0x05}, {0x20, 0x06}, - {0x10, 0x07}, {0x03, 0x10}, - {0x08, 0x14}, {0xa2, 0x17}, - {0x47, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x29, 0x21}, - {0x40, 0x22}, {0x54, 0x23}, - {0x66, 0x24}, {0x76, 0x25}, - {0x85, 0x26}, {0x94, 0x27}, - {0xa1, 0x28}, {0xae, 0x29}, - {0xbb, 0x2a}, {0xc7, 0x2b}, - {0xd3, 0x2c}, {0xde, 0x2d}, - {0xea, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3F}, - {0xC7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xC7, 0x48}, {0x01, 0x49}, - {0xC7, 0x4A}, {0x01, 0x4B}, - {0xC7, 0x4C}, {0x01, 0x4D}, - {0x44, 0x4E}, {0x00, 0x4F}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xC7, 0x54}, {0x01, 0x55}, - {0xC7, 0x56}, {0x01, 0x57}, - {0xC7, 0x58}, {0x01, 0x59}, - {0x44, 0x5A}, {0x00, 0x5B}, - {0x44, 0x5C}, {0x00, 0x5D}, - {0x44, 0x5E}, {0x00, 0x5F}, - {0xC7, 0x60}, {0x01, 0x61}, - {0xC7, 0x62}, {0x01, 0x63}, - {0xC7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6A}, {0x00, 0x6B}, - {0xC7, 0x6C}, {0x01, 0x6D}, - {0xC7, 0x6E}, {0x01, 0x6F}, - {0xC7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xC7, 0x78}, {0x01, 0x79}, - {0xC7, 0x7A}, {0x01, 0x7B}, - {0xC7, 0x7C}, {0x01, 0x7D}, - {0x44, 0x7E}, {0x00, 0x7F}, - {0x14, 0x84}, {0x00, 0x85}, - {0x27, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xEC, 0x8A}, {0x0f, 0x8B}, - {0xD8, 0x8C}, {0x0f, 0x8D}, - {0x3D, 0x8E}, {0x00, 0x8F}, - {0x3D, 0x90}, {0x00, 0x91}, - {0xCD, 0x92}, {0x0f, 0x93}, - {0xf7, 0x94}, {0x0f, 0x95}, - {0x0C, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x05, 0x9A}, {0x00, 0x9B}, - {0x04, 0x9C}, {0x00, 0x9D}, - {0x08, 0x9E}, {0x00, 0x9F}, - {0x2D, 0xC0}, {0x2D, 0xC1}, - {0x3A, 0xC2}, {0x05, 0xC3}, - {0x04, 0xC4}, {0x3F, 0xC5}, - {0x00, 0xC6}, {0x00, 0xC7}, - {0x50, 0xC8}, {0x3C, 0xC9}, - {0x28, 0xCA}, {0xD8, 0xCB}, - {0x14, 0xCC}, {0xEC, 0xCD}, - {0x32, 0xCE}, {0xDD, 0xCF}, - {0x32, 0xD0}, {0xDD, 0xD1}, - {0x6A, 0xD2}, {0x50, 0xD3}, - {0x00, 0xD4}, {0x00, 0xD5}, - {0x00, 0xD6}); - break; - default: - break; - } - - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, - 0x01, 0xe1, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, - 0x02, 0x81, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, - 0x00, 0x17, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, - 0x00, 0x11, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, - 0x04, 0x9a, 0, 0); - - return err; -} - - -static int mi0360_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u8 data[2]; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2, - data) < 0) - return -EIO; - ctrl->value = data[0]; - return 0; - case V4L2_CID_GAIN: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2, - data) < 0) - return -EIO; - ctrl->value = data[1]; - return 0; - case V4L2_CID_RED_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2, - data) < 0) - return -EIO; - ctrl->value = data[1]; - return 0; - case V4L2_CID_BLUE_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2, - data) < 0) - return -EIO; - ctrl->value = data[1]; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2, - data) < 0) - return -EIO; - ctrl->value = data[1]; - return 0; - case V4L2_CID_HFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x20 ? 1 : 0; - return 0; - case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x80 ? 1 : 0; - return 0; - default: - return -EINVAL; - } - - return 0; -} - - -static int mi0360_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x09, ctrl->value, 0x00, - 0, 0); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x35, 0x03, ctrl->value, - 0, 0); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2c, 0x03, ctrl->value, - 0, 0); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2d, 0x03, ctrl->value, - 0, 0); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2b, 0x03, ctrl->value, - 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2e, 0x03, ctrl->value, - 0, 0); - break; - case V4L2_CID_HFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x40:0x00, - ctrl->value ? 0x20:0x00, - 0, 0); - break; - case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x80:0x00, - ctrl->value ? 0x80:0x00, - 0, 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int mi0360_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1; - break; - default: - break; - } - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int mi0360_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x05, 0, 0); - err += sn9c102_write_reg(cam, 0x60, 0x19); - if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 || - sn9c102_get_bridge(cam) == BRIDGE_SN9C120) - err += sn9c102_write_reg(cam, 0xa6, 0x17); - } else { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x02, 0, 0); - err += sn9c102_write_reg(cam, 0x20, 0x19); - if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 || - sn9c102_get_bridge(cam) == BRIDGE_SN9C120) - err += sn9c102_write_reg(cam, 0xa2, 0x17); - } - - return err; -} - - -static const struct sn9c102_sensor mi0360 = { - .name = "MI-0360", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x5d, - .init = &mi0360_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x05, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x25, - .flags = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x0f, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x32, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x25, - .flags = 0, - }, - }, - .get_ctrl = &mi0360_get_ctrl, - .set_ctrl = &mi0360_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &mi0360_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &mi0360_set_pix_format -}; - - -int sn9c102_probe_mi0360(struct sn9c102_device* cam) -{ - - u8 data[2]; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17})) - return -EIO; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17})) - return -EIO; - break; - default: - break; - } - - if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00, - 2, data) < 0) - return -EIO; - - if (data[0] != 0x82 || data[1] != 0x43) - return -ENODEV; - - sn9c102_attach_sensor(cam, &mi0360); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mt9v111.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mt9v111.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mt9v111.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_mt9v111.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,260 +0,0 @@ -/*************************************************************************** - * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int mt9v111_init(struct sn9c102_device *cam) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, - {0x00, 0x03}, {0x1a, 0x04}, - {0x1f, 0x05}, {0x20, 0x06}, - {0x1f, 0x07}, {0x81, 0x08}, - {0x5c, 0x09}, {0x00, 0x0a}, - {0x00, 0x0b}, {0x00, 0x0c}, - {0x00, 0x0d}, {0x00, 0x0e}, - {0x00, 0x0f}, {0x03, 0x10}, - {0x00, 0x11}, {0x00, 0x12}, - {0x02, 0x13}, {0x14, 0x14}, - {0x28, 0x15}, {0x1e, 0x16}, - {0xe2, 0x17}, {0x06, 0x18}, - {0x00, 0x19}, {0x00, 0x1a}, - {0x00, 0x1b}, {0x08, 0x20}, - {0x39, 0x21}, {0x51, 0x22}, - {0x63, 0x23}, {0x73, 0x24}, - {0x82, 0x25}, {0x8f, 0x26}, - {0x9b, 0x27}, {0xa7, 0x28}, - {0xb1, 0x29}, {0xbc, 0x2a}, - {0xc6, 0x2b}, {0xcf, 0x2c}, - {0xd8, 0x2d}, {0xe1, 0x2e}, - {0xea, 0x2f}, {0xf2, 0x30}, - {0x13, 0x84}, {0x00, 0x85}, - {0x25, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xee, 0x8a}, {0x0f, 0x8b}, - {0xe5, 0x8c}, {0x0f, 0x8d}, - {0x2e, 0x8e}, {0x00, 0x8f}, - {0x30, 0x90}, {0x00, 0x91}, - {0xd4, 0x92}, {0x0f, 0x93}, - {0xfc, 0x94}, {0x0f, 0x95}, - {0x14, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x60, 0x99}, - {0x07, 0x9a}, {0x40, 0x9b}, - {0x20, 0x9c}, {0x00, 0x9d}, - {0x00, 0x9e}, {0x00, 0x9f}, - {0x2d, 0xc0}, {0x2d, 0xc1}, - {0x3a, 0xc2}, {0x05, 0xc3}, - {0x04, 0xc4}, {0x3f, 0xc5}, - {0x00, 0xc6}, {0x00, 0xc7}, - {0x50, 0xc8}, {0x3c, 0xc9}, - {0x28, 0xca}, {0xd8, 0xcb}, - {0x14, 0xcc}, {0xec, 0xcd}, - {0x32, 0xce}, {0xdd, 0xcf}, - {0x2d, 0xd0}, {0xdd, 0xd1}, - {0x6a, 0xd2}, {0x50, 0xd3}, - {0x60, 0xd4}, {0x00, 0xd5}, - {0x00, 0xd6}); - - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, - 0x04, 0x80, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, - 0x00, 0x04, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, - 0x00, 0x08, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02, - 0x00, 0x16, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, - 0x01, 0xe7, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, - 0x02, 0x87, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, - 0x00, 0x40, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, - 0x00, 0x09, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07, - 0x30, 0x02, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12, - 0x00, 0xb0, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13, - 0x00, 0x7c, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, - 0x00, 0x04, 0, 0); - - return err; -} - -static int mt9v111_get_ctrl(struct sn9c102_device *cam, - struct v4l2_control *ctrl) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - u8 data[2]; - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x80 ? 1 : 0; - return 0; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - -static int mt9v111_set_ctrl(struct sn9c102_device *cam, - const struct v4l2_control *ctrl) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, - ctrl->value ? 0x80 : 0x00, - ctrl->value ? 0x80 : 0x00, 0, - 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - -static int mt9v111_set_crop(struct sn9c102_device *cam, - const struct v4l2_rect *rect) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - int err = 0; - u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2; - - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - -static int mt9v111_set_pix_format(struct sn9c102_device *cam, - const struct v4l2_pix_format *pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xb4, 0x17); - } else { - err += sn9c102_write_reg(cam, 0xe2, 0x17); - } - - return err; -} - - -static const struct sn9c102_sensor mt9v111 = { - .name = "MT9V111", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x5c, - .init = &mt9v111_init, - .qctrl = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - }, - .get_ctrl = &mt9v111_get_ctrl, - .set_ctrl = &mt9v111_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &mt9v111_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &mt9v111_set_pix_format -}; - - -int sn9c102_probe_mt9v111(struct sn9c102_device *cam) -{ - u8 data[2]; - int err = 0; - - err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x29, 0x01}, {0x42, 0x17}, - {0x62, 0x17}, {0x08, 0x01}); - err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4, - mt9v111.i2c_slave_id, 0x01, 0x00, - 0x04, 0, 0); - if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111, - mt9v111.i2c_slave_id, 0x36, 2, - data) < 0) - return -EIO; - - if (data[0] != 0x82 || data[1] != 0x3a) - return -ENODEV; - - sn9c102_attach_sensor(cam, &mt9v111); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,626 +0,0 @@ -/*************************************************************************** - * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2006-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int ov7630_init(struct sn9c102_device* cam) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, - {0x0f, 0x18}, {0x50, 0x19}); - - err += sn9c102_i2c_write(cam, 0x12, 0x8d); - err += sn9c102_i2c_write(cam, 0x12, 0x0d); - err += sn9c102_i2c_write(cam, 0x11, 0x00); - err += sn9c102_i2c_write(cam, 0x15, 0x35); - err += sn9c102_i2c_write(cam, 0x16, 0x03); - err += sn9c102_i2c_write(cam, 0x17, 0x1c); - err += sn9c102_i2c_write(cam, 0x18, 0xbd); - err += sn9c102_i2c_write(cam, 0x19, 0x06); - err += sn9c102_i2c_write(cam, 0x1a, 0xf6); - err += sn9c102_i2c_write(cam, 0x1b, 0x04); - err += sn9c102_i2c_write(cam, 0x20, 0x44); - err += sn9c102_i2c_write(cam, 0x23, 0xee); - err += sn9c102_i2c_write(cam, 0x26, 0xa0); - err += sn9c102_i2c_write(cam, 0x27, 0x9a); - err += sn9c102_i2c_write(cam, 0x28, 0x20); - err += sn9c102_i2c_write(cam, 0x29, 0x30); - err += sn9c102_i2c_write(cam, 0x2f, 0x3d); - err += sn9c102_i2c_write(cam, 0x30, 0x24); - err += sn9c102_i2c_write(cam, 0x32, 0x86); - err += sn9c102_i2c_write(cam, 0x60, 0xa9); - err += sn9c102_i2c_write(cam, 0x61, 0x42); - err += sn9c102_i2c_write(cam, 0x65, 0x00); - err += sn9c102_i2c_write(cam, 0x69, 0x38); - err += sn9c102_i2c_write(cam, 0x6f, 0x88); - err += sn9c102_i2c_write(cam, 0x70, 0x0b); - err += sn9c102_i2c_write(cam, 0x71, 0x00); - err += sn9c102_i2c_write(cam, 0x74, 0x21); - err += sn9c102_i2c_write(cam, 0x7d, 0xf7); - break; - case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x20, 0x05}, - {0x20, 0x06}, {0x20, 0x07}, - {0x03, 0x10}, {0x0a, 0x14}, - {0x60, 0x17}, {0x0f, 0x18}, - {0x50, 0x19}, {0x1d, 0x1a}, - {0x10, 0x1b}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); - - err += sn9c102_i2c_write(cam, 0x12, 0x8d); - err += sn9c102_i2c_write(cam, 0x12, 0x0d); - err += sn9c102_i2c_write(cam, 0x15, 0x34); - err += sn9c102_i2c_write(cam, 0x11, 0x01); - err += sn9c102_i2c_write(cam, 0x1b, 0x04); - err += sn9c102_i2c_write(cam, 0x20, 0x44); - err += sn9c102_i2c_write(cam, 0x23, 0xee); - err += sn9c102_i2c_write(cam, 0x26, 0xa0); - err += sn9c102_i2c_write(cam, 0x27, 0x9a); - err += sn9c102_i2c_write(cam, 0x28, 0x20); - err += sn9c102_i2c_write(cam, 0x29, 0x30); - err += sn9c102_i2c_write(cam, 0x2f, 0x3d); - err += sn9c102_i2c_write(cam, 0x30, 0x24); - err += sn9c102_i2c_write(cam, 0x32, 0x86); - err += sn9c102_i2c_write(cam, 0x60, 0xa9); - err += sn9c102_i2c_write(cam, 0x61, 0x42); - err += sn9c102_i2c_write(cam, 0x65, 0x00); - err += sn9c102_i2c_write(cam, 0x69, 0x38); - err += sn9c102_i2c_write(cam, 0x6f, 0x88); - err += sn9c102_i2c_write(cam, 0x70, 0x0b); - err += sn9c102_i2c_write(cam, 0x71, 0x00); - err += sn9c102_i2c_write(cam, 0x74, 0x21); - err += sn9c102_i2c_write(cam, 0x7d, 0xf7); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x03, 0x10}, - {0x0a, 0x14}, {0xe2, 0x17}, - {0x0b, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x24, 0x21}, - {0x3b, 0x22}, {0x47, 0x23}, - {0x60, 0x24}, {0x71, 0x25}, - {0x80, 0x26}, {0x8f, 0x27}, - {0x9d, 0x28}, {0xaa, 0x29}, - {0xb8, 0x2a}, {0xc4, 0x2b}, - {0xd1, 0x2c}, {0xdd, 0x2d}, - {0xe8, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3f}, - {0xc7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xc7, 0x48}, {0x01, 0x49}, - {0xc7, 0x4a}, {0x01, 0x4b}, - {0xc7, 0x4c}, {0x01, 0x4d}, - {0x44, 0x4e}, {0x00, 0x4f}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xc7, 0x54}, {0x01, 0x55}, - {0xc7, 0x56}, {0x01, 0x57}, - {0xc7, 0x58}, {0x01, 0x59}, - {0x44, 0x5a}, {0x00, 0x5b}, - {0x44, 0x5c}, {0x00, 0x5d}, - {0x44, 0x5e}, {0x00, 0x5f}, - {0xc7, 0x60}, {0x01, 0x61}, - {0xc7, 0x62}, {0x01, 0x63}, - {0xc7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6a}, {0x00, 0x6b}, - {0xc7, 0x6c}, {0x01, 0x6d}, - {0xc7, 0x6e}, {0x01, 0x6f}, - {0xc7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xc7, 0x78}, {0x01, 0x79}, - {0xc7, 0x7a}, {0x01, 0x7b}, - {0xc7, 0x7c}, {0x01, 0x7d}, - {0x44, 0x7e}, {0x00, 0x7f}, - {0x17, 0x84}, {0x00, 0x85}, - {0x2e, 0x86}, {0x00, 0x87}, - {0x09, 0x88}, {0x00, 0x89}, - {0xe8, 0x8a}, {0x0f, 0x8b}, - {0xda, 0x8c}, {0x0f, 0x8d}, - {0x40, 0x8e}, {0x00, 0x8f}, - {0x37, 0x90}, {0x00, 0x91}, - {0xcf, 0x92}, {0x0f, 0x93}, - {0xfa, 0x94}, {0x0f, 0x95}, - {0x00, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x00, 0x9a}, {0x40, 0x9b}, - {0x20, 0x9c}, {0x00, 0x9d}, - {0x00, 0x9e}, {0x00, 0x9f}, - {0x2d, 0xc0}, {0x2d, 0xc1}, - {0x3a, 0xc2}, {0x00, 0xc3}, - {0x04, 0xc4}, {0x3f, 0xc5}, - {0x00, 0xc6}, {0x00, 0xc7}, - {0x50, 0xc8}, {0x3c, 0xc9}, - {0x28, 0xca}, {0xd8, 0xcb}, - {0x14, 0xcc}, {0xec, 0xcd}, - {0x32, 0xce}, {0xdd, 0xcf}, - {0x32, 0xd0}, {0xdd, 0xd1}, - {0x6a, 0xd2}, {0x50, 0xd3}, - {0x60, 0xd4}, {0x00, 0xd5}, - {0x00, 0xd6}); - - err += sn9c102_i2c_write(cam, 0x12, 0x80); - err += sn9c102_i2c_write(cam, 0x12, 0x48); - err += sn9c102_i2c_write(cam, 0x01, 0x80); - err += sn9c102_i2c_write(cam, 0x02, 0x80); - err += sn9c102_i2c_write(cam, 0x03, 0x80); - err += sn9c102_i2c_write(cam, 0x04, 0x10); - err += sn9c102_i2c_write(cam, 0x05, 0x20); - err += sn9c102_i2c_write(cam, 0x06, 0x80); - err += sn9c102_i2c_write(cam, 0x11, 0x00); - err += sn9c102_i2c_write(cam, 0x0c, 0x20); - err += sn9c102_i2c_write(cam, 0x0d, 0x20); - err += sn9c102_i2c_write(cam, 0x15, 0x80); - err += sn9c102_i2c_write(cam, 0x16, 0x03); - err += sn9c102_i2c_write(cam, 0x17, 0x1b); - err += sn9c102_i2c_write(cam, 0x18, 0xbd); - err += sn9c102_i2c_write(cam, 0x19, 0x05); - err += sn9c102_i2c_write(cam, 0x1a, 0xf6); - err += sn9c102_i2c_write(cam, 0x1b, 0x04); - err += sn9c102_i2c_write(cam, 0x21, 0x1b); - err += sn9c102_i2c_write(cam, 0x22, 0x00); - err += sn9c102_i2c_write(cam, 0x23, 0xde); - err += sn9c102_i2c_write(cam, 0x24, 0x10); - err += sn9c102_i2c_write(cam, 0x25, 0x8a); - err += sn9c102_i2c_write(cam, 0x26, 0xa0); - err += sn9c102_i2c_write(cam, 0x27, 0xca); - err += sn9c102_i2c_write(cam, 0x28, 0xa2); - err += sn9c102_i2c_write(cam, 0x29, 0x74); - err += sn9c102_i2c_write(cam, 0x2a, 0x88); - err += sn9c102_i2c_write(cam, 0x2b, 0x34); - err += sn9c102_i2c_write(cam, 0x2c, 0x88); - err += sn9c102_i2c_write(cam, 0x2e, 0x00); - err += sn9c102_i2c_write(cam, 0x2f, 0x00); - err += sn9c102_i2c_write(cam, 0x30, 0x00); - err += sn9c102_i2c_write(cam, 0x32, 0xc2); - err += sn9c102_i2c_write(cam, 0x33, 0x08); - err += sn9c102_i2c_write(cam, 0x4c, 0x40); - err += sn9c102_i2c_write(cam, 0x4d, 0xf3); - err += sn9c102_i2c_write(cam, 0x60, 0x05); - err += sn9c102_i2c_write(cam, 0x61, 0x40); - err += sn9c102_i2c_write(cam, 0x62, 0x12); - err += sn9c102_i2c_write(cam, 0x63, 0x57); - err += sn9c102_i2c_write(cam, 0x64, 0x73); - err += sn9c102_i2c_write(cam, 0x65, 0x00); - err += sn9c102_i2c_write(cam, 0x66, 0x55); - err += sn9c102_i2c_write(cam, 0x67, 0x01); - err += sn9c102_i2c_write(cam, 0x68, 0xac); - err += sn9c102_i2c_write(cam, 0x69, 0x38); - err += sn9c102_i2c_write(cam, 0x6f, 0x1f); - err += sn9c102_i2c_write(cam, 0x70, 0x01); - err += sn9c102_i2c_write(cam, 0x71, 0x00); - err += sn9c102_i2c_write(cam, 0x72, 0x10); - err += sn9c102_i2c_write(cam, 0x73, 0x50); - err += sn9c102_i2c_write(cam, 0x74, 0x20); - err += sn9c102_i2c_write(cam, 0x76, 0x01); - err += sn9c102_i2c_write(cam, 0x77, 0xf3); - err += sn9c102_i2c_write(cam, 0x78, 0x90); - err += sn9c102_i2c_write(cam, 0x79, 0x98); - err += sn9c102_i2c_write(cam, 0x7a, 0x98); - err += sn9c102_i2c_write(cam, 0x7b, 0x00); - err += sn9c102_i2c_write(cam, 0x7c, 0x38); - err += sn9c102_i2c_write(cam, 0x7d, 0xff); - break; - default: - break; - } - - return err; -} - - -static int ov7630_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - enum sn9c102_bridge bridge = sn9c102_get_bridge(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) - return -EIO; - break; - case V4L2_CID_RED_BALANCE: - if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) - ctrl->value = sn9c102_pread_reg(cam, 0x05); - else - ctrl->value = sn9c102_pread_reg(cam, 0x07); - break; - case V4L2_CID_BLUE_BALANCE: - ctrl->value = sn9c102_pread_reg(cam, 0x06); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) - ctrl->value = sn9c102_pread_reg(cam, 0x07); - else - ctrl->value = sn9c102_pread_reg(cam, 0x05); - break; - break; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0) - return -EIO; - ctrl->value &= 0x3f; - break; - case V4L2_CID_DO_WHITE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) - return -EIO; - ctrl->value &= 0x3f; - break; - case V4L2_CID_WHITENESS: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0) - return -EIO; - ctrl->value &= 0x3f; - break; - case V4L2_CID_AUTOGAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0) - return -EIO; - ctrl->value &= 0x01; - break; - case V4L2_CID_VFLIP: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x80) ? 1 : 0; - break; - case SN9C102_V4L2_CID_GAMMA: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x02) ? 1 : 0; - break; - case SN9C102_V4L2_CID_BAND_FILTER: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x02) ? 1 : 0; - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int ov7630_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - enum sn9c102_bridge bridge = sn9c102_get_bridge(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value); - break; - case V4L2_CID_RED_BALANCE: - if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) - err += sn9c102_write_reg(cam, ctrl->value, 0x05); - else - err += sn9c102_write_reg(cam, ctrl->value, 0x07); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x06); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) - err += sn9c102_write_reg(cam, ctrl->value, 0x07); - else - err += sn9c102_write_reg(cam, ctrl->value, 0x05); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x00, ctrl->value); - break; - case V4L2_CID_DO_WHITE_BALANCE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - case V4L2_CID_WHITENESS: - err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); - break; - case V4L2_CID_AUTOGAIN: - err += sn9c102_i2c_write(cam, 0x13, ctrl->value | - (ctrl->value << 1)); - break; - case V4L2_CID_VFLIP: - err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); - break; - case SN9C102_V4L2_CID_GAMMA: - err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2); - break; - case SN9C102_V4L2_CID_BAND_FILTER: - err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int ov7630_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4; - break; - default: - break; - } - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int ov7630_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) - err += sn9c102_write_reg(cam, 0x50, 0x19); - else - err += sn9c102_write_reg(cam, 0x20, 0x19); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xe5, 0x17); - err += sn9c102_i2c_write(cam, 0x11, 0x04); - } else { - err += sn9c102_write_reg(cam, 0xe2, 0x17); - err += sn9c102_i2c_write(cam, 0x11, 0x02); - } - break; - default: - break; - } - - return err; -} - - -static const struct sn9c102_sensor ov7630 = { - .name = "OV7630", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 | - BRIDGE_SN9C105 | BRIDGE_SN9C120, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x21, - .init = &ov7630_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x14, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x60, - .flags = 0, - }, - { - .id = V4L2_CID_WHITENESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "white balance background: red", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_DO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "white balance background: blue", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto adjust", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_BAND_FILTER, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "band filter", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "rgb gamma", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &ov7630_get_ctrl, - .set_ctrl = &ov7630_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &ov7630_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SN9C10X, - .priv = 8, - }, - .set_pix_format = &ov7630_set_pix_format -}; - - -int sn9c102_probe_ov7630(struct sn9c102_device* cam) -{ - int pid, ver, err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); - break; - case BRIDGE_SN9C103: /* do _not_ change anything! */ - err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x42, 0x01}, - {0x28, 0x17}, {0x44, 0x02}); - pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); - if (err || pid < 0) /* try a different initialization */ - err += sn9c102_write_const_regs(cam, {0x01, 0x01}, - {0x00, 0x01}); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x29, 0x01}, {0x74, 0x02}, - {0x0e, 0x01}, {0x44, 0x01}); - break; - default: - break; - } - - pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); - ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b); - if (err || pid < 0 || ver < 0) - return -EIO; - if (pid != 0x76 || ver != 0x31) - return -ENODEV; - sn9c102_attach_sensor(cam, &ov7630); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,538 +0,0 @@ -/*************************************************************************** - * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int ov7660_init(struct sn9c102_device* cam) -{ - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x03, 0x10}, - {0x08, 0x14}, {0x20, 0x17}, - {0x8b, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x29, 0x21}, - {0x40, 0x22}, {0x54, 0x23}, - {0x66, 0x24}, {0x76, 0x25}, - {0x85, 0x26}, {0x94, 0x27}, - {0xa1, 0x28}, {0xae, 0x29}, - {0xbb, 0x2a}, {0xc7, 0x2b}, - {0xd3, 0x2c}, {0xde, 0x2d}, - {0xea, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3f}, - {0xc7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xc7, 0x48}, {0x01, 0x49}, - {0xc7, 0x4a}, {0x01, 0x4b}, - {0xc7, 0x4c}, {0x01, 0x4d}, - {0x44, 0x4e}, {0x00, 0x4f}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xc7, 0x54}, {0x01, 0x55}, - {0xc7, 0x56}, {0x01, 0x57}, - {0xc7, 0x58}, {0x01, 0x59}, - {0x44, 0x5a}, {0x00, 0x5b}, - {0x44, 0x5c}, {0x00, 0x5d}, - {0x44, 0x5e}, {0x00, 0x5f}, - {0xc7, 0x60}, {0x01, 0x61}, - {0xc7, 0x62}, {0x01, 0x63}, - {0xc7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6a}, {0x00, 0x6b}, - {0xc7, 0x6c}, {0x01, 0x6d}, - {0xc7, 0x6e}, {0x01, 0x6f}, - {0xc7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xc7, 0x78}, {0x01, 0x79}, - {0xc7, 0x7a}, {0x01, 0x7b}, - {0xc7, 0x7c}, {0x01, 0x7d}, - {0x44, 0x7e}, {0x00, 0x7f}, - {0x14, 0x84}, {0x00, 0x85}, - {0x27, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xec, 0x8a}, {0x0f, 0x8b}, - {0xd8, 0x8c}, {0x0f, 0x8d}, - {0x3d, 0x8e}, {0x00, 0x8f}, - {0x3d, 0x90}, {0x00, 0x91}, - {0xcd, 0x92}, {0x0f, 0x93}, - {0xf7, 0x94}, {0x0f, 0x95}, - {0x0c, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x05, 0x9a}, {0x00, 0x9b}, - {0x04, 0x9c}, {0x00, 0x9d}, - {0x08, 0x9e}, {0x00, 0x9f}, - {0x2d, 0xc0}, {0x2d, 0xc1}, - {0x3a, 0xc2}, {0x05, 0xc3}, - {0x04, 0xc4}, {0x3f, 0xc5}, - {0x00, 0xc6}, {0x00, 0xc7}, - {0x50, 0xc8}, {0x3C, 0xc9}, - {0x28, 0xca}, {0xd8, 0xcb}, - {0x14, 0xcc}, {0xec, 0xcd}, - {0x32, 0xce}, {0xdd, 0xcf}, - {0x32, 0xd0}, {0xdd, 0xd1}, - {0x6a, 0xd2}, {0x50, 0xd3}, - {0x00, 0xd4}, {0x00, 0xd5}, - {0x00, 0xd6}); - - err += sn9c102_i2c_write(cam, 0x12, 0x80); - err += sn9c102_i2c_write(cam, 0x11, 0x09); - err += sn9c102_i2c_write(cam, 0x00, 0x0A); - err += sn9c102_i2c_write(cam, 0x01, 0x80); - err += sn9c102_i2c_write(cam, 0x02, 0x80); - err += sn9c102_i2c_write(cam, 0x03, 0x00); - err += sn9c102_i2c_write(cam, 0x04, 0x00); - err += sn9c102_i2c_write(cam, 0x05, 0x08); - err += sn9c102_i2c_write(cam, 0x06, 0x0B); - err += sn9c102_i2c_write(cam, 0x07, 0x00); - err += sn9c102_i2c_write(cam, 0x08, 0x1C); - err += sn9c102_i2c_write(cam, 0x09, 0x01); - err += sn9c102_i2c_write(cam, 0x0A, 0x76); - err += sn9c102_i2c_write(cam, 0x0B, 0x60); - err += sn9c102_i2c_write(cam, 0x0C, 0x00); - err += sn9c102_i2c_write(cam, 0x0D, 0x08); - err += sn9c102_i2c_write(cam, 0x0E, 0x04); - err += sn9c102_i2c_write(cam, 0x0F, 0x6F); - err += sn9c102_i2c_write(cam, 0x10, 0x20); - err += sn9c102_i2c_write(cam, 0x11, 0x03); - err += sn9c102_i2c_write(cam, 0x12, 0x05); - err += sn9c102_i2c_write(cam, 0x13, 0xC7); - err += sn9c102_i2c_write(cam, 0x14, 0x2C); - err += sn9c102_i2c_write(cam, 0x15, 0x00); - err += sn9c102_i2c_write(cam, 0x16, 0x02); - err += sn9c102_i2c_write(cam, 0x17, 0x10); - err += sn9c102_i2c_write(cam, 0x18, 0x60); - err += sn9c102_i2c_write(cam, 0x19, 0x02); - err += sn9c102_i2c_write(cam, 0x1A, 0x7B); - err += sn9c102_i2c_write(cam, 0x1B, 0x02); - err += sn9c102_i2c_write(cam, 0x1C, 0x7F); - err += sn9c102_i2c_write(cam, 0x1D, 0xA2); - err += sn9c102_i2c_write(cam, 0x1E, 0x01); - err += sn9c102_i2c_write(cam, 0x1F, 0x0E); - err += sn9c102_i2c_write(cam, 0x20, 0x05); - err += sn9c102_i2c_write(cam, 0x21, 0x05); - err += sn9c102_i2c_write(cam, 0x22, 0x05); - err += sn9c102_i2c_write(cam, 0x23, 0x05); - err += sn9c102_i2c_write(cam, 0x24, 0x68); - err += sn9c102_i2c_write(cam, 0x25, 0x58); - err += sn9c102_i2c_write(cam, 0x26, 0xD4); - err += sn9c102_i2c_write(cam, 0x27, 0x80); - err += sn9c102_i2c_write(cam, 0x28, 0x80); - err += sn9c102_i2c_write(cam, 0x29, 0x30); - err += sn9c102_i2c_write(cam, 0x2A, 0x00); - err += sn9c102_i2c_write(cam, 0x2B, 0x00); - err += sn9c102_i2c_write(cam, 0x2C, 0x80); - err += sn9c102_i2c_write(cam, 0x2D, 0x00); - err += sn9c102_i2c_write(cam, 0x2E, 0x00); - err += sn9c102_i2c_write(cam, 0x2F, 0x0E); - err += sn9c102_i2c_write(cam, 0x30, 0x08); - err += sn9c102_i2c_write(cam, 0x31, 0x30); - err += sn9c102_i2c_write(cam, 0x32, 0xB4); - err += sn9c102_i2c_write(cam, 0x33, 0x00); - err += sn9c102_i2c_write(cam, 0x34, 0x07); - err += sn9c102_i2c_write(cam, 0x35, 0x84); - err += sn9c102_i2c_write(cam, 0x36, 0x00); - err += sn9c102_i2c_write(cam, 0x37, 0x0C); - err += sn9c102_i2c_write(cam, 0x38, 0x02); - err += sn9c102_i2c_write(cam, 0x39, 0x43); - err += sn9c102_i2c_write(cam, 0x3A, 0x00); - err += sn9c102_i2c_write(cam, 0x3B, 0x0A); - err += sn9c102_i2c_write(cam, 0x3C, 0x6C); - err += sn9c102_i2c_write(cam, 0x3D, 0x99); - err += sn9c102_i2c_write(cam, 0x3E, 0x0E); - err += sn9c102_i2c_write(cam, 0x3F, 0x41); - err += sn9c102_i2c_write(cam, 0x40, 0xC1); - err += sn9c102_i2c_write(cam, 0x41, 0x22); - err += sn9c102_i2c_write(cam, 0x42, 0x08); - err += sn9c102_i2c_write(cam, 0x43, 0xF0); - err += sn9c102_i2c_write(cam, 0x44, 0x10); - err += sn9c102_i2c_write(cam, 0x45, 0x78); - err += sn9c102_i2c_write(cam, 0x46, 0xA8); - err += sn9c102_i2c_write(cam, 0x47, 0x60); - err += sn9c102_i2c_write(cam, 0x48, 0x80); - err += sn9c102_i2c_write(cam, 0x49, 0x00); - err += sn9c102_i2c_write(cam, 0x4A, 0x00); - err += sn9c102_i2c_write(cam, 0x4B, 0x00); - err += sn9c102_i2c_write(cam, 0x4C, 0x00); - err += sn9c102_i2c_write(cam, 0x4D, 0x00); - err += sn9c102_i2c_write(cam, 0x4E, 0x00); - err += sn9c102_i2c_write(cam, 0x4F, 0x46); - err += sn9c102_i2c_write(cam, 0x50, 0x36); - err += sn9c102_i2c_write(cam, 0x51, 0x0F); - err += sn9c102_i2c_write(cam, 0x52, 0x17); - err += sn9c102_i2c_write(cam, 0x53, 0x7F); - err += sn9c102_i2c_write(cam, 0x54, 0x96); - err += sn9c102_i2c_write(cam, 0x55, 0x40); - err += sn9c102_i2c_write(cam, 0x56, 0x40); - err += sn9c102_i2c_write(cam, 0x57, 0x40); - err += sn9c102_i2c_write(cam, 0x58, 0x0F); - err += sn9c102_i2c_write(cam, 0x59, 0xBA); - err += sn9c102_i2c_write(cam, 0x5A, 0x9A); - err += sn9c102_i2c_write(cam, 0x5B, 0x22); - err += sn9c102_i2c_write(cam, 0x5C, 0xB9); - err += sn9c102_i2c_write(cam, 0x5D, 0x9B); - err += sn9c102_i2c_write(cam, 0x5E, 0x10); - err += sn9c102_i2c_write(cam, 0x5F, 0xF0); - err += sn9c102_i2c_write(cam, 0x60, 0x05); - err += sn9c102_i2c_write(cam, 0x61, 0x60); - err += sn9c102_i2c_write(cam, 0x62, 0x00); - err += sn9c102_i2c_write(cam, 0x63, 0x00); - err += sn9c102_i2c_write(cam, 0x64, 0x50); - err += sn9c102_i2c_write(cam, 0x65, 0x30); - err += sn9c102_i2c_write(cam, 0x66, 0x00); - err += sn9c102_i2c_write(cam, 0x67, 0x80); - err += sn9c102_i2c_write(cam, 0x68, 0x7A); - err += sn9c102_i2c_write(cam, 0x69, 0x90); - err += sn9c102_i2c_write(cam, 0x6A, 0x80); - err += sn9c102_i2c_write(cam, 0x6B, 0x0A); - err += sn9c102_i2c_write(cam, 0x6C, 0x30); - err += sn9c102_i2c_write(cam, 0x6D, 0x48); - err += sn9c102_i2c_write(cam, 0x6E, 0x80); - err += sn9c102_i2c_write(cam, 0x6F, 0x74); - err += sn9c102_i2c_write(cam, 0x70, 0x64); - err += sn9c102_i2c_write(cam, 0x71, 0x60); - err += sn9c102_i2c_write(cam, 0x72, 0x5C); - err += sn9c102_i2c_write(cam, 0x73, 0x58); - err += sn9c102_i2c_write(cam, 0x74, 0x54); - err += sn9c102_i2c_write(cam, 0x75, 0x4C); - err += sn9c102_i2c_write(cam, 0x76, 0x40); - err += sn9c102_i2c_write(cam, 0x77, 0x38); - err += sn9c102_i2c_write(cam, 0x78, 0x34); - err += sn9c102_i2c_write(cam, 0x79, 0x30); - err += sn9c102_i2c_write(cam, 0x7A, 0x2F); - err += sn9c102_i2c_write(cam, 0x7B, 0x2B); - err += sn9c102_i2c_write(cam, 0x7C, 0x03); - err += sn9c102_i2c_write(cam, 0x7D, 0x07); - err += sn9c102_i2c_write(cam, 0x7E, 0x17); - err += sn9c102_i2c_write(cam, 0x7F, 0x34); - err += sn9c102_i2c_write(cam, 0x80, 0x41); - err += sn9c102_i2c_write(cam, 0x81, 0x4D); - err += sn9c102_i2c_write(cam, 0x82, 0x58); - err += sn9c102_i2c_write(cam, 0x83, 0x63); - err += sn9c102_i2c_write(cam, 0x84, 0x6E); - err += sn9c102_i2c_write(cam, 0x85, 0x77); - err += sn9c102_i2c_write(cam, 0x86, 0x87); - err += sn9c102_i2c_write(cam, 0x87, 0x95); - err += sn9c102_i2c_write(cam, 0x88, 0xAF); - err += sn9c102_i2c_write(cam, 0x89, 0xC7); - err += sn9c102_i2c_write(cam, 0x8A, 0xDF); - err += sn9c102_i2c_write(cam, 0x8B, 0x99); - err += sn9c102_i2c_write(cam, 0x8C, 0x99); - err += sn9c102_i2c_write(cam, 0x8D, 0xCF); - err += sn9c102_i2c_write(cam, 0x8E, 0x20); - err += sn9c102_i2c_write(cam, 0x8F, 0x26); - err += sn9c102_i2c_write(cam, 0x90, 0x10); - err += sn9c102_i2c_write(cam, 0x91, 0x0C); - err += sn9c102_i2c_write(cam, 0x92, 0x25); - err += sn9c102_i2c_write(cam, 0x93, 0x00); - err += sn9c102_i2c_write(cam, 0x94, 0x50); - err += sn9c102_i2c_write(cam, 0x95, 0x50); - err += sn9c102_i2c_write(cam, 0x96, 0x00); - err += sn9c102_i2c_write(cam, 0x97, 0x01); - err += sn9c102_i2c_write(cam, 0x98, 0x10); - err += sn9c102_i2c_write(cam, 0x99, 0x40); - err += sn9c102_i2c_write(cam, 0x9A, 0x40); - err += sn9c102_i2c_write(cam, 0x9B, 0x20); - err += sn9c102_i2c_write(cam, 0x9C, 0x00); - err += sn9c102_i2c_write(cam, 0x9D, 0x99); - err += sn9c102_i2c_write(cam, 0x9E, 0x7F); - err += sn9c102_i2c_write(cam, 0x9F, 0x00); - err += sn9c102_i2c_write(cam, 0xA0, 0x00); - err += sn9c102_i2c_write(cam, 0xA1, 0x00); - - return err; -} - - -static int ov7660_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) - return -EIO; - break; - case V4L2_CID_DO_WHITE_BALANCE: - if ((ctrl->value = sn9c102_read_reg(cam, 0x02)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x04) ? 1 : 0; - break; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_read_reg(cam, 0x05)) < 0) - return -EIO; - ctrl->value &= 0x7f; - break; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_read_reg(cam, 0x06)) < 0) - return -EIO; - ctrl->value &= 0x7f; - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_read_reg(cam, 0x07)) < 0) - return -EIO; - ctrl->value &= 0x7f; - break; - case SN9C102_V4L2_CID_BAND_FILTER: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x3b)) < 0) - return -EIO; - ctrl->value &= 0x08; - break; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0) - return -EIO; - ctrl->value &= 0x1f; - break; - case V4L2_CID_AUTOGAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0) - return -EIO; - ctrl->value &= 0x01; - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int ov7660_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value); - break; - case V4L2_CID_DO_WHITE_BALANCE: - err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x05); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x06); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x07); - break; - case SN9C102_V4L2_CID_BAND_FILTER: - err += sn9c102_i2c_write(cam, ctrl->value << 3, 0x3b); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x00, 0x60 + ctrl->value); - break; - case V4L2_CID_AUTOGAIN: - err += sn9c102_i2c_write(cam, 0x13, 0xc0 | - (ctrl->value * 0x07)); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int ov7660_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int ov7660_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int r0, err = 0; - - r0 = sn9c102_pread_reg(cam, 0x01); - - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { - err += sn9c102_write_reg(cam, r0 | 0x40, 0x01); - err += sn9c102_write_reg(cam, 0xa2, 0x17); - err += sn9c102_i2c_write(cam, 0x11, 0x00); - } else { - err += sn9c102_write_reg(cam, r0 | 0x40, 0x01); - err += sn9c102_write_reg(cam, 0xa2, 0x17); - err += sn9c102_i2c_write(cam, 0x11, 0x0d); - } - - return err; -} - - -static const struct sn9c102_sensor ov7660 = { - .name = "OV7660", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x21, - .init = &ov7660_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x09, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x27, - .flags = 0, - }, - { - .id = V4L2_CID_DO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "night mode", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x14, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x14, - .flags = 0, - }, - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto adjust", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x14, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_BAND_FILTER, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "band filter", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &ov7660_get_ctrl, - .set_ctrl = &ov7660_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &ov7660_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_JPEG, - .priv = 8, - }, - .set_pix_format = &ov7660_set_pix_format -}; - - -int sn9c102_probe_ov7660(struct sn9c102_device* cam) -{ - int pid, ver, err; - - err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); - - pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a); - ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b); - if (err || pid < 0 || ver < 0) - return -EIO; - if (pid != 0x76 || ver != 0x60) - return -ENODEV; - - sn9c102_attach_sensor(cam, &ov7660); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,302 +0,0 @@ -/*************************************************************************** - * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int pas106b_init(struct sn9c102_device* cam) -{ - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x20, 0x17}, - {0x20, 0x19}, {0x09, 0x18}); - - err += sn9c102_i2c_write(cam, 0x02, 0x0c); - err += sn9c102_i2c_write(cam, 0x05, 0x5a); - err += sn9c102_i2c_write(cam, 0x06, 0x88); - err += sn9c102_i2c_write(cam, 0x07, 0x80); - err += sn9c102_i2c_write(cam, 0x10, 0x06); - err += sn9c102_i2c_write(cam, 0x11, 0x06); - err += sn9c102_i2c_write(cam, 0x12, 0x00); - err += sn9c102_i2c_write(cam, 0x14, 0x02); - err += sn9c102_i2c_write(cam, 0x13, 0x01); - - msleep(400); - - return err; -} - - -static int pas106b_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = sn9c102_i2c_read(cam, 0x03), - r2 = sn9c102_i2c_read(cam, 0x04); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 4) | (r2 & 0x0f); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case V4L2_CID_CONTRAST: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) - return -EIO; - ctrl->value &= 0x07; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x1f) << 1; - return 0; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) - return -EIO; - ctrl->value &= 0xf8; - return 0; - default: - return -EINVAL; - } -} - - -static int pas106b_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4); - err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x09, ctrl->value); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x0e, ctrl->value); - break; - case V4L2_CID_CONTRAST: - err += sn9c102_i2c_write(cam, 0x0f, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1); - err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1); - break; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3); - break; - default: - return -EINVAL; - } - err += sn9c102_i2c_write(cam, 0x13, 0x01); - - return err ? -EIO : 0; -} - - -static int pas106b_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int pas106b_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x2c, 0x17); - else - err += sn9c102_write_reg(cam, 0x20, 0x17); - - return err; -} - - -static const struct sn9c102_sensor pas106b = { - .name = "PAS106B", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x40, - .init = &pas106b_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x125, - .maximum = 0xfff, - .step = 0x001, - .default_value = 0x140, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x0d, - .flags = 0, - }, - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "contrast", - .minimum = 0x00, - .maximum = 0x07, - .step = 0x01, - .default_value = 0x00, /* 0x00~0x03 have same effect */ - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x04, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x06, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x3e, - .step = 0x02, - .default_value = 0x02, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "DAC magnitude", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - }, - .get_ctrl = &pas106b_get_ctrl, - .set_ctrl = &pas106b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - }, - .set_crop = &pas106b_set_crop, - .pix_format = { - .width = 352, - .height = 288, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, /* we use this field as 'bits per pixel' */ - }, - .set_pix_format = &pas106b_set_pix_format -}; - - -int sn9c102_probe_pas106b(struct sn9c102_device* cam) -{ - int r0 = 0, r1 = 0; - unsigned int pid = 0; - - /* - Minimal initialization to enable the I2C communication - NOTE: do NOT change the values! - */ - if (sn9c102_write_const_regs(cam, - {0x01, 0x01}, /* sensor power down */ - {0x00, 0x01}, /* sensor power on */ - {0x28, 0x17})) /* sensor clock at 24 MHz */ - return -EIO; - - r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00); - r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01); - if (r0 < 0 || r1 < 0) - return -EIO; - - pid = (r0 << 11) | ((r1 & 0xf0) >> 4); - if (pid != 0x007) - return -ENODEV; - - sn9c102_attach_sensor(cam, &pas106b); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,335 +0,0 @@ -/*************************************************************************** - * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * - * * - * * - * Support for SN9C103, DAC Magnitude, exposure and green gain controls * - * added by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int pas202bcb_init(struct sn9c102_device* cam) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x20, 0x17}, - {0x30, 0x19}, {0x09, 0x18}); - break; - case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x20, 0x05}, - {0x20, 0x06}, {0x20, 0x07}, - {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x20, 0x17}, - {0x30, 0x19}, {0x09, 0x18}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x10, 0x21}, - {0x20, 0x22}, {0x30, 0x23}, - {0x40, 0x24}, {0x50, 0x25}, - {0x60, 0x26}, {0x70, 0x27}, - {0x80, 0x28}, {0x90, 0x29}, - {0xa0, 0x2a}, {0xb0, 0x2b}, - {0xc0, 0x2c}, {0xd0, 0x2d}, - {0xe0, 0x2e}, {0xf0, 0x2f}, - {0xff, 0x30}); - break; - default: - break; - } - - err += sn9c102_i2c_write(cam, 0x02, 0x14); - err += sn9c102_i2c_write(cam, 0x03, 0x40); - err += sn9c102_i2c_write(cam, 0x0d, 0x2c); - err += sn9c102_i2c_write(cam, 0x0e, 0x01); - err += sn9c102_i2c_write(cam, 0x0f, 0xa9); - err += sn9c102_i2c_write(cam, 0x10, 0x08); - err += sn9c102_i2c_write(cam, 0x13, 0x63); - err += sn9c102_i2c_write(cam, 0x15, 0x70); - err += sn9c102_i2c_write(cam, 0x11, 0x01); - - msleep(400); - - return err; -} - - -static int pas202bcb_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = sn9c102_i2c_read(cam, 0x04), - r2 = sn9c102_i2c_read(cam, 0x05); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 6) | (r2 & 0x3f); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) - return -EIO; - return 0; - default: - return -EINVAL; - } -} - - -static int pas202bcb_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x28, 0x17); - else - err += sn9c102_write_reg(cam, 0x20, 0x17); - - return err; -} - - -static int pas202bcb_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); - err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x09, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x07, ctrl->value); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x08, ctrl->value); - break; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - default: - return -EINVAL; - } - err += sn9c102_i2c_write(cam, 0x11, 0x01); - - return err ? -EIO : 0; -} - - -static int pas202bcb_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = 0, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4; - break; - case BRIDGE_SN9C103: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3; - break; - default: - break; - } - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static const struct sn9c102_sensor pas202bcb = { - .name = "PAS202BCB", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x40, - .init = &pas202bcb_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x01e5, - .maximum = 0x3fff, - .step = 0x0001, - .default_value = 0x01e5, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x0b, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x05, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "DAC magnitude", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x04, - .flags = 0, - }, - }, - .get_ctrl = &pas202bcb_get_ctrl, - .set_ctrl = &pas202bcb_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &pas202bcb_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &pas202bcb_set_pix_format -}; - - -int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) -{ - int r0 = 0, r1 = 0, err = 0; - unsigned int pid = 0; - - /* - * Minimal initialization to enable the I2C communication - * NOTE: do NOT change the values! - */ - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, - {0x01, 0x01}, /* power down */ - {0x40, 0x01}, /* power on */ - {0x28, 0x17});/* clock 24 MHz */ - break; - case BRIDGE_SN9C103: /* do _not_ change anything! */ - err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x01}, - {0x44, 0x02}, {0x29, 0x17}); - break; - default: - break; - } - - r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); - r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); - - if (err || r0 < 0 || r1 < 0) - return -EIO; - - pid = (r0 << 4) | ((r1 & 0xf0) >> 4); - if (pid != 0x017) - return -ENODEV; - - sn9c102_attach_sensor(cam, &pas202bcb); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_sensor.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_sensor.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_sensor.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_sensor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,307 +0,0 @@ -/*************************************************************************** - * API for image sensors connected to the SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_SENSOR_H_ -#define _SN9C102_SENSOR_H_ - -#include -#include -#include -#include -#include -#include - -struct sn9c102_device; -struct sn9c102_sensor; - -/*****************************************************************************/ - -/* - OVERVIEW. - This is a small interface that allows you to add support for any CCD/CMOS - image sensors connected to the SN9C1XX bridges. The entire API is documented - below. In the most general case, to support a sensor there are three steps - you have to follow: - 1) define the main "sn9c102_sensor" structure by setting the basic fields; - 2) write a probing function to be called by the core module when the USB - camera is recognized, then add both the USB ids and the name of that - function to the two corresponding tables in sn9c102_devtable.h; - 3) implement the methods that you want/need (and fill the rest of the main - structure accordingly). - "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do - NOT need to touch the source code of the core module for the things to work - properly, unless you find bugs or flaws in it. Finally, do not forget to - read the V4L2 API for completeness. -*/ - -/*****************************************************************************/ - -enum sn9c102_bridge { - BRIDGE_SN9C101 = 0x01, - BRIDGE_SN9C102 = 0x02, - BRIDGE_SN9C103 = 0x04, - BRIDGE_SN9C105 = 0x08, - BRIDGE_SN9C120 = 0x10, -}; - -/* Return the bridge name */ -enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam); - -/* Return a pointer the sensor struct attached to the camera */ -struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam); - -/* Identify a device */ -extern struct sn9c102_device* -sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id); - -/* Attach a probed sensor to the camera. */ -extern void -sn9c102_attach_sensor(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor); - -/* - Read/write routines: they always return -1 on error, 0 or the read value - otherwise. NOTE that a real read operation is not supported by the SN9C1XX - chip for some of its registers. To work around this problem, a pseudo-read - call is provided instead: it returns the last successfully written value - on the register (0 if it has never been written), the usual -1 on error. -*/ - -/* The "try" I2C I/O versions are used when probing the sensor */ -extern int sn9c102_i2c_try_read(struct sn9c102_device*, - const struct sn9c102_sensor*, u8 address); - -/* - These must be used if and only if the sensor doesn't implement the standard - I2C protocol. There are a number of good reasons why you must use the - single-byte versions of these functions: do not abuse. The first function - writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX - chip. The second one programs the registers 0x09 and 0x10 with data0 and - data1, and places the n bytes read from the sensor register table in the - buffer pointed by 'buffer'. Both the functions return -1 on error; the write - version returns 0 on success, while the read version returns the first read - byte. -*/ -extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, u8 n, - u8 data0, u8 data1, u8 data2, u8 data3, - u8 data4, u8 data5); -extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, - u8 data0, u8 data1, u8 n, u8 buffer[]); - -/* To be used after the sensor struct has been attached to the camera struct */ -extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); -extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); - -/* I/O on registers in the bridge. Could be used by the sensor methods too */ -extern int sn9c102_read_reg(struct sn9c102_device*, u16 index); -extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); -extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); -extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2], - int count); -/* - Write multiple registers with constant values. For example: - sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18}); - Register addresses must be < 256. -*/ -#define sn9c102_write_const_regs(sn9c102_device, data...) \ - ({ static const u8 _valreg[][2] = {data}; \ - sn9c102_write_regs(sn9c102_device, _valreg, ARRAY_SIZE(_valreg)); }) - -/*****************************************************************************/ - -enum sn9c102_i2c_sysfs_ops { - SN9C102_I2C_READ = 0x01, - SN9C102_I2C_WRITE = 0x02, -}; - -enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */ - SN9C102_I2C_100KHZ = 0x01, - SN9C102_I2C_400KHZ = 0x02, -}; - -enum sn9c102_i2c_interface { - SN9C102_I2C_2WIRES, - SN9C102_I2C_3WIRES, -}; - -#define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10) - -struct sn9c102_sensor { - char name[32], /* sensor name */ - maintainer[64]; /* name of the maintainer */ - - enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */ - - /* Supported operations through the 'sysfs' interface */ - enum sn9c102_i2c_sysfs_ops sysfs_ops; - - /* - These sensor capabilities must be provided if the SN9C1XX controller - needs to communicate through the sensor serial interface by using - at least one of the i2c functions available. - */ - enum sn9c102_i2c_frequency frequency; - enum sn9c102_i2c_interface interface; - - /* - This identifier must be provided if the image sensor implements - the standard I2C protocol. - */ - u8 i2c_slave_id; /* reg. 0x09 */ - - /* - NOTE: Where not noted,most of the functions below are not mandatory. - Set to null if you do not implement them. If implemented, - they must return 0 on success, the proper error otherwise. - */ - - int (*init)(struct sn9c102_device* cam); - /* - This function will be called after the sensor has been attached. - It should be used to initialize the sensor only, but may also - configure part of the SN9C1XX chip if necessary. You don't need to - setup picture settings like brightness, contrast, etc.. here, if - the corrisponding controls are implemented (see below), since - they are adjusted in the core driver by calling the set_ctrl() - method after init(), where the arguments are the default values - specified in the v4l2_queryctrl list of supported controls; - Same suggestions apply for other settings, _if_ the corresponding - methods are present; if not, the initialization must configure the - sensor according to the default configuration structures below. - */ - - struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS]; - /* - Optional list of default controls, defined as indicated in the - V4L2 API. Menu type controls are not handled by this interface. - */ - - int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); - int (*set_ctrl)(struct sn9c102_device* cam, - const struct v4l2_control* ctrl); - /* - You must implement at least the set_ctrl method if you have defined - the list above. The returned value must follow the V4L2 - specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER - are not supported by this driver, so do not implement them. Also, - you don't have to check whether the passed values are out of bounds, - given that this is done by the core module. - */ - - struct v4l2_cropcap cropcap; - /* - Think the image sensor as a grid of R,G,B monochromatic pixels - disposed according to a particular Bayer pattern, which describes - the complete array of pixels, from (0,0) to (xmax, ymax). We will - use this coordinate system from now on. It is assumed the sensor - chip can be programmed to capture/transmit a subsection of that - array of pixels: we will call this subsection "active window". - It is not always true that the largest achievable active window can - cover the whole array of pixels. The V4L2 API defines another - area called "source rectangle", which, in turn, is a subrectangle of - the active window. The SN9C1XX chip is always programmed to read the - source rectangle. - The bounds of both the active window and the source rectangle are - specified in the cropcap substructures 'bounds' and 'defrect'. - By default, the source rectangle should cover the largest possible - area. Again, it is not always true that the largest source rectangle - can cover the entire active window, although it is a rare case for - the hardware we have. The bounds of the source rectangle _must_ be - multiple of 16 and must use the same coordinate system as indicated - before; their centers shall align initially. - If necessary, the sensor chip must be initialized during init() to - set the bounds of the active sensor window; however, by default, it - usually covers the largest achievable area (maxwidth x maxheight) - of pixels, so no particular initialization is needed, if you have - defined the correct default bounds in the structures. - See the V4L2 API for further details. - NOTE: once you have defined the bounds of the active window - (struct cropcap.bounds) you must not change them.anymore. - Only 'bounds' and 'defrect' fields are mandatory, other fields - will be ignored. - */ - - int (*set_crop)(struct sn9c102_device* cam, - const struct v4l2_rect* rect); - /* - To be called on VIDIOC_C_SETCROP. The core module always calls a - default routine which configures the appropriate SN9C1XX regs (also - scaling), but you may need to override/adjust specific stuff. - 'rect' contains width and height values that are multiple of 16: in - case you override the default function, you always have to program - the chip to match those values; on error return the corresponding - error code without rolling back. - NOTE: in case, you must program the SN9C1XX chip to get rid of - blank pixels or blank lines at the _start_ of each line or - frame after each HSYNC or VSYNC, so that the image starts with - real RGB data (see regs 0x12, 0x13) (having set H_SIZE and, - V_SIZE you don't have to care about blank pixels or blank - lines at the end of each line or frame). - */ - - struct v4l2_pix_format pix_format; - /* - What you have to define here are: 1) initial 'width' and 'height' of - the target rectangle 2) the initial 'pixelformat', which can be - either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video) - or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate - the number of bits per pixel for uncompressed video, 8 or 9 (despite - the current value of 'pixelformat'). - NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4 - of cropcap.defrect.width and cropcap.defrect.height. I - suggest 1/1. - NOTE 2: The initial compression quality is defined by the first bit - of reg 0x17 during the initialization of the image sensor. - NOTE 3: as said above, you have to program the SN9C1XX chip to get - rid of any blank pixels, so that the output of the sensor - matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). - */ - - int (*set_pix_format)(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix); - /* - To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to - SN9C10X pixel format or viceversa. On error return the corresponding - error code without rolling back. - */ - - /* - Do NOT write to the data below, it's READ ONLY. It is used by the - core module to store successfully updated values of the above - settings, for rollbacks..etc..in case of errors during atomic I/O - */ - struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS]; - struct v4l2_rect _rect; -}; - -/*****************************************************************************/ - -/* Private ioctl's for control settings supported by some image sensors */ -#define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0) -#define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1) -#define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2) -#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3) -#define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4) -#define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5) -#define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6) - -#endif /* _SN9C102_SENSOR_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int tas5110c1b_init(struct sn9c102_device* cam) -{ - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01}, - {0x00, 0x10}, {0x00, 0x11}, - {0x0a, 0x14}, {0x60, 0x17}, - {0x06, 0x18}, {0xfb, 0x19}); - - err += sn9c102_i2c_write(cam, 0xc0, 0x80); - - return err; -} - - -static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int tas5110c1b_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - /* Don't change ! */ - err += sn9c102_write_reg(cam, 0x14, 0x1a); - err += sn9c102_write_reg(cam, 0x0a, 0x1b); - err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); - - return err; -} - - -static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x2b, 0x19); - else - err += sn9c102_write_reg(cam, 0xfb, 0x19); - - return err; -} - - -static const struct sn9c102_sensor tas5110c1b = { - .name = "TAS5110C1B", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_3WIRES, - .init = &tas5110c1b_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xf6, - .step = 0x01, - .default_value = 0x40, - .flags = 0, - }, - }, - .set_ctrl = &tas5110c1b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - }, - .set_crop = &tas5110c1b_set_crop, - .pix_format = { - .width = 352, - .height = 288, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &tas5110c1b_set_pix_format -}; - - -int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) -{ - const struct usb_device_id tas5110c1b_id_table[] = { - { USB_DEVICE(0x0c45, 0x6001), }, - { USB_DEVICE(0x0c45, 0x6005), }, - { USB_DEVICE(0x0c45, 0x60ab), }, - { } - }; - - /* Sensor detection is based on USB pid/vid */ - if (!sn9c102_match_id(cam, tas5110c1b_id_table)) - return -ENODEV; - - sn9c102_attach_sensor(cam, &tas5110c1b); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,119 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int tas5110d_init(struct sn9c102_device* cam) -{ - int err; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x04, 0x01}, - {0x0a, 0x14}, {0x60, 0x17}, - {0x06, 0x18}, {0xfb, 0x19}); - - err += sn9c102_i2c_write(cam, 0x9a, 0xca); - - return err; -} - - -static int tas5110d_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - err += sn9c102_write_reg(cam, 0x14, 0x1a); - err += sn9c102_write_reg(cam, 0x0a, 0x1b); - - return err; -} - - -static int tas5110d_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x3b, 0x19); - else - err += sn9c102_write_reg(cam, 0xfb, 0x19); - - return err; -} - - -static const struct sn9c102_sensor tas5110d = { - .name = "TAS5110D", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x61, - .init = &tas5110d_init, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - }, - .set_crop = &tas5110d_set_crop, - .pix_format = { - .width = 352, - .height = 288, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &tas5110d_set_pix_format -}; - - -int sn9c102_probe_tas5110d(struct sn9c102_device* cam) -{ - const struct usb_device_id tas5110d_id_table[] = { - { USB_DEVICE(0x0c45, 0x6007), }, - { } - }; - - if (!sn9c102_match_id(cam, tas5110d_id_table)) - return -ENODEV; - - sn9c102_attach_sensor(cam, &tas5110d); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia * - * * - * 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, or * - * (at your option) any later version. * - * * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int tas5130d1b_init(struct sn9c102_device* cam) -{ - int err; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x20, 0x17}, - {0x04, 0x01}, {0x01, 0x10}, - {0x00, 0x11}, {0x00, 0x14}, - {0x60, 0x17}, {0x07, 0x18}); - - return err; -} - - -static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); - break; - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int tas5130d1b_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; - int err = 0; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - /* Do NOT change! */ - err += sn9c102_write_reg(cam, 0x1f, 0x1a); - err += sn9c102_write_reg(cam, 0x1a, 0x1b); - err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); - - return err; -} - - -static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x63, 0x19); - else - err += sn9c102_write_reg(cam, 0xf3, 0x19); - - return err; -} - - -static const struct sn9c102_sensor tas5130d1b = { - .name = "TAS5130D1B", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_3WIRES, - .init = &tas5130d1b_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xf6, - .step = 0x02, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x47, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .set_ctrl = &tas5130d1b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &tas5130d1b_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &tas5130d1b_set_pix_format -}; - - -int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) -{ - const struct usb_device_id tas5130d1b_id_table[] = { - { USB_DEVICE(0x0c45, 0x6024), }, - { USB_DEVICE(0x0c45, 0x6025), }, - { USB_DEVICE(0x0c45, 0x60aa), }, - { } - }; - - /* Sensor detection is based on USB pid/vid */ - if (!sn9c102_match_id(cam, tas5130d1b_id_table)) - return -ENODEV; - - sn9c102_attach_sensor(cam, &tas5130d1b); - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_camera.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_camera.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1588 +0,0 @@ -/* - * camera image capture (abstract) bus driver - * - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This driver provides an interface between platform-specific camera - * busses and camera devices. It should be used if the camera is - * connected not over a "proper" bus like PCI or USB, but over a - * special bus, like, for example, the Quick Capture interface on PXA270 - * SoCs. Later it should also be used for i.MX31 SoCs from Freescale. - * It can handle multiple cameras and / or multiple busses, which can - * be used, e.g., in stereo-vision applications. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* Default to VGA resolution */ -#define DEFAULT_WIDTH 640 -#define DEFAULT_HEIGHT 480 - -static LIST_HEAD(hosts); -static LIST_HEAD(devices); -static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ - -static int soc_camera_power_set(struct soc_camera_device *icd, - struct soc_camera_link *icl, - int power_on) -{ - int ret; - - if (power_on) { - ret = regulator_bulk_enable(icl->num_regulators, - icl->regulators); - if (ret < 0) { - dev_err(&icd->dev, "Cannot enable regulators\n"); - return ret; - } - - if (icl->power) - ret = icl->power(icd->pdev, power_on); - if (ret < 0) { - dev_err(&icd->dev, - "Platform failed to power-on the camera.\n"); - - regulator_bulk_disable(icl->num_regulators, - icl->regulators); - return ret; - } - } else { - ret = 0; - if (icl->power) - ret = icl->power(icd->pdev, 0); - if (ret < 0) { - dev_err(&icd->dev, - "Platform failed to power-off the camera.\n"); - return ret; - } - - ret = regulator_bulk_disable(icl->num_regulators, - icl->regulators); - if (ret < 0) { - dev_err(&icd->dev, "Cannot disable regulators\n"); - return ret; - } - } - - return 0; -} - -const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( - struct soc_camera_device *icd, unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < icd->num_user_formats; i++) - if (icd->user_formats[i].host_fmt->fourcc == fourcc) - return icd->user_formats + i; - return NULL; -} -EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); - -/** - * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags - * @icl: camera platform parameters - * @flags: flags to be inverted according to platform configuration - * @return: resulting flags - */ -unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, - unsigned long flags) -{ - unsigned long f; - - /* If only one of the two polarities is supported, switch to the opposite */ - if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { - f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW); - if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW) - flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW; - } - - if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { - f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW); - if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW) - flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW; - } - - if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { - f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING); - if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING) - flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING; - } - - return flags; -} -EXPORT_SYMBOL(soc_camera_apply_sensor_flags); - -static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - WARN_ON(priv != file->private_data); - - /* Only single-plane capture is supported so far */ - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - /* limit format to hardware capabilities */ - return ici->ops->try_fmt(icd, f); -} - -static int soc_camera_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct soc_camera_device *icd = file->private_data; - int ret = 0; - - if (inp->index != 0) - return -EINVAL; - - if (icd->ops->enum_input) - ret = icd->ops->enum_input(icd, inp); - else { - /* default is camera */ - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = V4L2_STD_UNKNOWN; - strcpy(inp->name, "Camera"); - } - - return ret; -} - -static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - - return 0; -} - -static int soc_camera_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i > 0) - return -EINVAL; - - return 0; -} - -static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_subdev_call(sd, core, s_std, *a); -} - -static int soc_camera_enum_fsizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - return ici->ops->enum_fsizes(icd, fsize); -} - -static int soc_camera_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - int ret; - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - WARN_ON(priv != file->private_data); - - if (icd->streamer && icd->streamer != file) - return -EBUSY; - - if (ici->ops->init_videobuf) { - ret = videobuf_reqbufs(&icd->vb_vidq, p); - if (ret < 0) - return ret; - - ret = ici->ops->reqbufs(icd, p); - } else { - ret = vb2_reqbufs(&icd->vb2_vidq, p); - } - - if (!ret && !icd->streamer) - icd->streamer = file; - - return ret; -} - -static int soc_camera_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - WARN_ON(priv != file->private_data); - - if (ici->ops->init_videobuf) - return videobuf_querybuf(&icd->vb_vidq, p); - else - return vb2_querybuf(&icd->vb2_vidq, p); -} - -static int soc_camera_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - WARN_ON(priv != file->private_data); - - if (icd->streamer != file) - return -EBUSY; - - if (ici->ops->init_videobuf) - return videobuf_qbuf(&icd->vb_vidq, p); - else - return vb2_qbuf(&icd->vb2_vidq, p); -} - -static int soc_camera_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - WARN_ON(priv != file->private_data); - - if (icd->streamer != file) - return -EBUSY; - - if (ici->ops->init_videobuf) - return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK); - else - return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); -} - -/* Always entered with .video_lock held */ -static int soc_camera_init_user_formats(struct soc_camera_device *icd) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - unsigned int i, fmts = 0, raw_fmts = 0; - int ret; - enum v4l2_mbus_pixelcode code; - - while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) - raw_fmts++; - - if (!ici->ops->get_formats) - /* - * Fallback mode - the host will have to serve all - * sensor-provided formats one-to-one to the user - */ - fmts = raw_fmts; - else - /* - * First pass - only count formats this host-sensor - * configuration can provide - */ - for (i = 0; i < raw_fmts; i++) { - ret = ici->ops->get_formats(icd, i, NULL); - if (ret < 0) - return ret; - fmts += ret; - } - - if (!fmts) - return -ENXIO; - - icd->user_formats = - vmalloc(fmts * sizeof(struct soc_camera_format_xlate)); - if (!icd->user_formats) - return -ENOMEM; - - icd->num_user_formats = fmts; - - dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts); - - /* Second pass - actually fill data formats */ - fmts = 0; - for (i = 0; i < raw_fmts; i++) - if (!ici->ops->get_formats) { - v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code); - icd->user_formats[i].host_fmt = - soc_mbus_get_fmtdesc(code); - icd->user_formats[i].code = code; - } else { - ret = ici->ops->get_formats(icd, i, - &icd->user_formats[fmts]); - if (ret < 0) - goto egfmt; - fmts += ret; - } - - icd->current_fmt = &icd->user_formats[0]; - - return 0; - -egfmt: - icd->num_user_formats = 0; - vfree(icd->user_formats); - return ret; -} - -/* Always entered with .video_lock held */ -static void soc_camera_free_user_formats(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - if (ici->ops->put_formats) - ici->ops->put_formats(icd); - icd->current_fmt = NULL; - icd->num_user_formats = 0; - vfree(icd->user_formats); - icd->user_formats = NULL; -} - -#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ - ((x) >> 24) & 0xff - -/* Called with .vb_lock held, or from the first open(2), see comment there */ -static int soc_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct v4l2_pix_format *pix = &f->fmt.pix; - int ret; - - dev_dbg(&icd->dev, "S_FMT(%c%c%c%c, %ux%u)\n", - pixfmtstr(pix->pixelformat), pix->width, pix->height); - - /* We always call try_fmt() before set_fmt() or set_crop() */ - ret = ici->ops->try_fmt(icd, f); - if (ret < 0) - return ret; - - ret = ici->ops->set_fmt(icd, f); - if (ret < 0) { - return ret; - } else if (!icd->current_fmt || - icd->current_fmt->host_fmt->fourcc != pix->pixelformat) { - dev_err(&icd->dev, - "Host driver hasn't set up current format correctly!\n"); - return -EINVAL; - } - - icd->user_width = pix->width; - icd->user_height = pix->height; - icd->bytesperline = pix->bytesperline; - icd->sizeimage = pix->sizeimage; - icd->colorspace = pix->colorspace; - icd->field = pix->field; - if (ici->ops->init_videobuf) - icd->vb_vidq.field = pix->field; - - dev_dbg(&icd->dev, "set width: %d height: %d\n", - icd->user_width, icd->user_height); - - /* set physical bus parameters */ - return ici->ops->set_bus_param(icd, pix->pixelformat); -} - -static int soc_camera_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct soc_camera_device *icd = container_of(vdev->parent, - struct soc_camera_device, - dev); - struct soc_camera_link *icl = to_soc_camera_link(icd); - struct soc_camera_host *ici; - int ret; - - if (!icd->ops) - /* No device driver attached */ - return -ENODEV; - - ici = to_soc_camera_host(icd->dev.parent); - - if (!try_module_get(ici->ops->owner)) { - dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); - return -EINVAL; - } - - icd->use_count++; - - /* Now we really have to activate the camera */ - if (icd->use_count == 1) { - /* Restore parameters before the last close() per V4L2 API */ - struct v4l2_format f = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .fmt.pix = { - .width = icd->user_width, - .height = icd->user_height, - .field = icd->field, - .colorspace = icd->colorspace, - .pixelformat = - icd->current_fmt->host_fmt->fourcc, - }, - }; - - ret = soc_camera_power_set(icd, icl, 1); - if (ret < 0) - goto epower; - - /* The camera could have been already on, try to reset */ - if (icl->reset) - icl->reset(icd->pdev); - - ret = ici->ops->add(icd); - if (ret < 0) { - dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); - goto eiciadd; - } - - pm_runtime_enable(&icd->vdev->dev); - ret = pm_runtime_resume(&icd->vdev->dev); - if (ret < 0 && ret != -ENOSYS) - goto eresume; - - /* - * Try to configure with default parameters. Notice: this is the - * very first open, so, we cannot race against other calls, - * apart from someone else calling open() simultaneously, but - * .video_lock is protecting us against it. - */ - ret = soc_camera_set_fmt(icd, &f); - if (ret < 0) - goto esfmt; - - if (ici->ops->init_videobuf) { - ici->ops->init_videobuf(&icd->vb_vidq, icd); - } else { - ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd); - if (ret < 0) - goto einitvb; - } - } - - file->private_data = icd; - dev_dbg(&icd->dev, "camera device open\n"); - - return 0; - - /* - * First four errors are entered with the .video_lock held - * and use_count == 1 - */ -einitvb: -esfmt: - pm_runtime_disable(&icd->vdev->dev); -eresume: - ici->ops->remove(icd); -eiciadd: - soc_camera_power_set(icd, icl, 0); -epower: - icd->use_count--; - module_put(ici->ops->owner); - - return ret; -} - -static int soc_camera_close(struct file *file) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - icd->use_count--; - if (!icd->use_count) { - struct soc_camera_link *icl = to_soc_camera_link(icd); - - pm_runtime_suspend(&icd->vdev->dev); - pm_runtime_disable(&icd->vdev->dev); - - ici->ops->remove(icd); - if (ici->ops->init_videobuf2) - vb2_queue_release(&icd->vb2_vidq); - - soc_camera_power_set(icd, icl, 0); - } - - if (icd->streamer == file) - icd->streamer = NULL; - - module_put(ici->ops->owner); - - dev_dbg(&icd->dev, "camera device close\n"); - - return 0; -} - -static ssize_t soc_camera_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct soc_camera_device *icd = file->private_data; - int err = -EINVAL; - - dev_err(&icd->dev, "camera device read not implemented\n"); - - return err; -} - -static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - int err; - - dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma); - - if (icd->streamer != file) - return -EBUSY; - - if (ici->ops->init_videobuf) - err = videobuf_mmap_mapper(&icd->vb_vidq, vma); - else - err = vb2_mmap(&icd->vb2_vidq, vma); - - dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, - err); - - return err; -} - -static unsigned int soc_camera_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - if (icd->streamer != file) - return -EBUSY; - - if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) { - dev_err(&icd->dev, "Trying to poll with no queued buffers!\n"); - return POLLERR; - } - - return ici->ops->poll(file, pt); -} - -void soc_camera_lock(struct vb2_queue *vq) -{ - struct soc_camera_device *icd = vb2_get_drv_priv(vq); - mutex_lock(&icd->video_lock); -} -EXPORT_SYMBOL(soc_camera_lock); - -void soc_camera_unlock(struct vb2_queue *vq) -{ - struct soc_camera_device *icd = vb2_get_drv_priv(vq); - mutex_unlock(&icd->video_lock); -} -EXPORT_SYMBOL(soc_camera_unlock); - -static struct v4l2_file_operations soc_camera_fops = { - .owner = THIS_MODULE, - .open = soc_camera_open, - .release = soc_camera_close, - .unlocked_ioctl = video_ioctl2, - .read = soc_camera_read, - .mmap = soc_camera_mmap, - .poll = soc_camera_poll, -}; - -static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct soc_camera_device *icd = file->private_data; - int ret; - - WARN_ON(priv != file->private_data); - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_warn(&icd->dev, "Wrong buf-type %d\n", f->type); - return -EINVAL; - } - - if (icd->streamer && icd->streamer != file) - return -EBUSY; - - if (icd->vb_vidq.bufs[0]) { - dev_err(&icd->dev, "S_FMT denied: queue initialised\n"); - return -EBUSY; - } - - ret = soc_camera_set_fmt(icd, f); - - if (!ret && !icd->streamer) - icd->streamer = file; - - return ret; -} - -static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct soc_camera_device *icd = file->private_data; - const struct soc_mbus_pixelfmt *format; - - WARN_ON(priv != file->private_data); - - if (f->index >= icd->num_user_formats) - return -EINVAL; - - format = icd->user_formats[f->index].host_fmt; - - if (format->name) - strlcpy(f->description, format->name, sizeof(f->description)); - f->pixelformat = format->fourcc; - return 0; -} - -static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_pix_format *pix = &f->fmt.pix; - - WARN_ON(priv != file->private_data); - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - pix->width = icd->user_width; - pix->height = icd->user_height; - pix->bytesperline = icd->bytesperline; - pix->sizeimage = icd->sizeimage; - pix->field = icd->field; - pix->pixelformat = icd->current_fmt->host_fmt->fourcc; - pix->colorspace = icd->colorspace; - dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", - icd->current_fmt->host_fmt->fourcc); - return 0; -} - -static int soc_camera_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - WARN_ON(priv != file->private_data); - - strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver)); - return ici->ops->querycap(ici, cap); -} - -static int soc_camera_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - WARN_ON(priv != file->private_data); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (icd->streamer != file) - return -EBUSY; - - /* This calls buf_queue from host driver's videobuf_queue_ops */ - if (ici->ops->init_videobuf) - ret = videobuf_streamon(&icd->vb_vidq); - else - ret = vb2_streamon(&icd->vb2_vidq, i); - - if (!ret) - v4l2_subdev_call(sd, video, s_stream, 1); - - return ret; -} - -static int soc_camera_streamoff(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - WARN_ON(priv != file->private_data); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (icd->streamer != file) - return -EBUSY; - - /* - * This calls buf_release from host driver's videobuf_queue_ops for all - * remaining buffers. When the last buffer is freed, stop capture - */ - if (ici->ops->init_videobuf) - videobuf_streamoff(&icd->vb_vidq); - else - vb2_streamoff(&icd->vb2_vidq, i); - - v4l2_subdev_call(sd, video, s_stream, 0); - - return 0; -} - -static int soc_camera_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - int i; - - WARN_ON(priv != file->private_data); - - if (!qc->id) - return -EINVAL; - - /* First check host controls */ - for (i = 0; i < ici->ops->num_controls; i++) - if (qc->id == ici->ops->controls[i].id) { - memcpy(qc, &(ici->ops->controls[i]), - sizeof(*qc)); - return 0; - } - - /* Then device controls */ - for (i = 0; i < icd->ops->num_controls; i++) - if (qc->id == icd->ops->controls[i].id) { - memcpy(qc, &(icd->ops->controls[i]), - sizeof(*qc)); - return 0; - } - - return -EINVAL; -} - -static int soc_camera_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - WARN_ON(priv != file->private_data); - - if (ici->ops->get_ctrl) { - ret = ici->ops->get_ctrl(icd, ctrl); - if (ret != -ENOIOCTLCMD) - return ret; - } - - return v4l2_subdev_call(sd, core, g_ctrl, ctrl); -} - -static int soc_camera_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - WARN_ON(priv != file->private_data); - - if (ici->ops->set_ctrl) { - ret = ici->ops->set_ctrl(icd, ctrl); - if (ret != -ENOIOCTLCMD) - return ret; - } - - return v4l2_subdev_call(sd, core, s_ctrl, ctrl); -} - -static int soc_camera_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *a) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - return ici->ops->cropcap(icd, a); -} - -static int soc_camera_g_crop(struct file *file, void *fh, - struct v4l2_crop *a) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - int ret; - - ret = ici->ops->get_crop(icd, a); - - return ret; -} - -/* - * According to the V4L2 API, drivers shall not update the struct v4l2_crop - * argument with the actual geometry, instead, the user shall use G_CROP to - * retrieve it. - */ -static int soc_camera_s_crop(struct file *file, void *fh, - struct v4l2_crop *a) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct v4l2_rect *rect = &a->c; - struct v4l2_crop current_crop; - int ret; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n", - rect->width, rect->height, rect->left, rect->top); - - /* If get_crop fails, we'll let host and / or client drivers decide */ - ret = ici->ops->get_crop(icd, ¤t_crop); - - /* Prohibit window size change with initialised buffers */ - if (ret < 0) { - dev_err(&icd->dev, - "S_CROP denied: getting current crop failed\n"); - } else if (icd->vb_vidq.bufs[0] && - (a->c.width != current_crop.c.width || - a->c.height != current_crop.c.height)) { - dev_err(&icd->dev, - "S_CROP denied: queue initialised and sizes differ\n"); - ret = -EBUSY; - } else { - ret = ici->ops->set_crop(icd, a); - } - - return ret; -} - -static int soc_camera_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - if (ici->ops->get_parm) - return ici->ops->get_parm(icd, a); - - return -ENOIOCTLCMD; -} - -static int soc_camera_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - - if (ici->ops->set_parm) - return ici->ops->set_parm(icd, a); - - return -ENOIOCTLCMD; -} - -static int soc_camera_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *id) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_subdev_call(sd, core, g_chip_ident, id); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int soc_camera_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_subdev_call(sd, core, g_register, reg); -} - -static int soc_camera_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_subdev_call(sd, core, s_register, reg); -} -#endif - -/* So far this function cannot fail */ -static void scan_add_host(struct soc_camera_host *ici) -{ - struct soc_camera_device *icd; - - mutex_lock(&list_lock); - - list_for_each_entry(icd, &devices, list) { - if (icd->iface == ici->nr) { - int ret; - icd->dev.parent = ici->v4l2_dev.dev; - dev_set_name(&icd->dev, "%u-%u", icd->iface, - icd->devnum); - ret = device_register(&icd->dev); - if (ret < 0) { - icd->dev.parent = NULL; - dev_err(&icd->dev, - "Cannot register device: %d\n", ret); - } - } - } - - mutex_unlock(&list_lock); -} - -#ifdef CONFIG_I2C_BOARDINFO -static int soc_camera_init_i2c(struct soc_camera_device *icd, - struct soc_camera_link *icl) -{ - struct i2c_client *client; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id); - struct v4l2_subdev *subdev; - - if (!adap) { - dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n", - icl->i2c_adapter_id); - goto ei2cga; - } - - icl->board_info->platform_data = icd; - - subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, - icl->board_info, NULL); - if (!subdev) - goto ei2cnd; - - client = v4l2_get_subdevdata(subdev); - - /* Use to_i2c_client(dev) to recover the i2c client */ - dev_set_drvdata(&icd->dev, &client->dev); - - return 0; -ei2cnd: - i2c_put_adapter(adap); -ei2cga: - return -ENODEV; -} - -static void soc_camera_free_i2c(struct soc_camera_device *icd) -{ - struct i2c_client *client = - to_i2c_client(to_soc_camera_control(icd)); - dev_set_drvdata(&icd->dev, NULL); - v4l2_device_unregister_subdev(i2c_get_clientdata(client)); - i2c_unregister_device(client); - i2c_put_adapter(client->adapter); -} -#else -#define soc_camera_init_i2c(icd, icl) (-ENODEV) -#define soc_camera_free_i2c(icd) do {} while (0) -#endif - -static int soc_camera_video_start(struct soc_camera_device *icd); -static int video_dev_create(struct soc_camera_device *icd); -/* Called during host-driver probe */ -static int soc_camera_probe(struct device *dev) -{ - struct soc_camera_device *icd = to_soc_camera_dev(dev); - struct soc_camera_host *ici = to_soc_camera_host(dev->parent); - struct soc_camera_link *icl = to_soc_camera_link(icd); - struct device *control = NULL; - struct v4l2_subdev *sd; - struct v4l2_mbus_framefmt mf; - int ret; - - dev_info(dev, "Probing %s\n", dev_name(dev)); - - ret = regulator_bulk_get(icd->pdev, icl->num_regulators, - icl->regulators); - if (ret < 0) - goto ereg; - - ret = soc_camera_power_set(icd, icl, 1); - if (ret < 0) - goto epower; - - /* The camera could have been already on, try to reset */ - if (icl->reset) - icl->reset(icd->pdev); - - ret = ici->ops->add(icd); - if (ret < 0) - goto eadd; - - /* Must have icd->vdev before registering the device */ - ret = video_dev_create(icd); - if (ret < 0) - goto evdc; - - /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */ - if (icl->board_info) { - ret = soc_camera_init_i2c(icd, icl); - if (ret < 0) - goto eadddev; - } else if (!icl->add_device || !icl->del_device) { - ret = -EINVAL; - goto eadddev; - } else { - if (icl->module_name) - ret = request_module(icl->module_name); - - ret = icl->add_device(icl, &icd->dev); - if (ret < 0) - goto eadddev; - - /* - * FIXME: this is racy, have to use driver-binding notification, - * when it is available - */ - control = to_soc_camera_control(icd); - if (!control || !control->driver || !dev_get_drvdata(control) || - !try_module_get(control->driver->owner)) { - icl->del_device(icl); - goto enodrv; - } - } - - /* At this point client .probe() should have run already */ - ret = soc_camera_init_user_formats(icd); - if (ret < 0) - goto eiufmt; - - icd->field = V4L2_FIELD_ANY; - - icd->vdev->lock = &icd->video_lock; - - /* - * ..._video_start() will create a device node, video_register_device() - * itself is protected against concurrent open() calls, but we also have - * to protect our data. - */ - mutex_lock(&icd->video_lock); - - ret = soc_camera_video_start(icd); - if (ret < 0) - goto evidstart; - - /* Try to improve our guess of a reasonable window format */ - sd = soc_camera_to_subdev(icd); - if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { - icd->user_width = mf.width; - icd->user_height = mf.height; - icd->colorspace = mf.colorspace; - icd->field = mf.field; - } - - /* Do we have to sysfs_remove_link() before device_unregister()? */ - if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj, - "control")) - dev_warn(&icd->dev, "Failed creating the control symlink\n"); - - ici->ops->remove(icd); - - soc_camera_power_set(icd, icl, 0); - - mutex_unlock(&icd->video_lock); - - return 0; - -evidstart: - mutex_unlock(&icd->video_lock); - soc_camera_free_user_formats(icd); -eiufmt: - if (icl->board_info) { - soc_camera_free_i2c(icd); - } else { - icl->del_device(icl); - module_put(control->driver->owner); - } -enodrv: -eadddev: - video_device_release(icd->vdev); -evdc: - ici->ops->remove(icd); -eadd: - soc_camera_power_set(icd, icl, 0); -epower: - regulator_bulk_free(icl->num_regulators, icl->regulators); -ereg: - return ret; -} - -/* - * This is called on device_unregister, which only means we have to disconnect - * from the host, but not remove ourselves from the device list - */ -static int soc_camera_remove(struct device *dev) -{ - struct soc_camera_device *icd = to_soc_camera_dev(dev); - struct soc_camera_link *icl = to_soc_camera_link(icd); - struct video_device *vdev = icd->vdev; - - BUG_ON(!dev->parent); - - if (vdev) { - video_unregister_device(vdev); - icd->vdev = NULL; - } - - if (icl->board_info) { - soc_camera_free_i2c(icd); - } else { - struct device_driver *drv = to_soc_camera_control(icd) ? - to_soc_camera_control(icd)->driver : NULL; - if (drv) { - icl->del_device(icl); - module_put(drv->owner); - } - } - soc_camera_free_user_formats(icd); - - regulator_bulk_free(icl->num_regulators, icl->regulators); - - return 0; -} - -static int soc_camera_suspend(struct device *dev, pm_message_t state) -{ - struct soc_camera_device *icd = to_soc_camera_dev(dev); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - int ret = 0; - - if (ici->ops->suspend) - ret = ici->ops->suspend(icd, state); - - return ret; -} - -static int soc_camera_resume(struct device *dev) -{ - struct soc_camera_device *icd = to_soc_camera_dev(dev); - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - int ret = 0; - - if (ici->ops->resume) - ret = ici->ops->resume(icd); - - return ret; -} - -struct bus_type soc_camera_bus_type = { - .name = "soc-camera", - .probe = soc_camera_probe, - .remove = soc_camera_remove, - .suspend = soc_camera_suspend, - .resume = soc_camera_resume, -}; -EXPORT_SYMBOL_GPL(soc_camera_bus_type); - -static struct device_driver ic_drv = { - .name = "camera", - .bus = &soc_camera_bus_type, - .owner = THIS_MODULE, -}; - -static void dummy_release(struct device *dev) -{ -} - -static int default_cropcap(struct soc_camera_device *icd, - struct v4l2_cropcap *a) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, cropcap, a); -} - -static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, g_crop, a); -} - -static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, s_crop, a); -} - -static int default_g_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *parm) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, g_parm, parm); -} - -static int default_s_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *parm) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, s_parm, parm); -} - -static int default_enum_fsizes(struct soc_camera_device *icd, - struct v4l2_frmsizeenum *fsize) -{ - int ret; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - __u32 pixfmt = fsize->pixel_format; - struct v4l2_frmsizeenum fsize_mbus = *fsize; - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) - return -EINVAL; - /* map xlate-code to pixel_format, sensor only handle xlate-code*/ - fsize_mbus.pixel_format = xlate->code; - - ret = v4l2_subdev_call(sd, video, enum_mbus_fsizes, &fsize_mbus); - if (ret < 0) - return ret; - - *fsize = fsize_mbus; - fsize->pixel_format = pixfmt; - - return 0; -} - -static void soc_camera_device_init(struct device *dev, void *pdata) -{ - dev->platform_data = pdata; - dev->bus = &soc_camera_bus_type; - dev->release = dummy_release; -} - -int soc_camera_host_register(struct soc_camera_host *ici) -{ - struct soc_camera_host *ix; - int ret; - - if (!ici || !ici->ops || - !ici->ops->try_fmt || - !ici->ops->set_fmt || - !ici->ops->set_bus_param || - !ici->ops->querycap || - ((!ici->ops->init_videobuf || - !ici->ops->reqbufs) && - !ici->ops->init_videobuf2) || - !ici->ops->add || - !ici->ops->remove || - !ici->ops->poll || - !ici->v4l2_dev.dev) - return -EINVAL; - - if (!ici->ops->set_crop) - ici->ops->set_crop = default_s_crop; - if (!ici->ops->get_crop) - ici->ops->get_crop = default_g_crop; - if (!ici->ops->cropcap) - ici->ops->cropcap = default_cropcap; - if (!ici->ops->set_parm) - ici->ops->set_parm = default_s_parm; - if (!ici->ops->get_parm) - ici->ops->get_parm = default_g_parm; - if (!ici->ops->enum_fsizes) - ici->ops->enum_fsizes = default_enum_fsizes; - - mutex_lock(&list_lock); - list_for_each_entry(ix, &hosts, list) { - if (ix->nr == ici->nr) { - ret = -EBUSY; - goto edevreg; - } - } - - ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev); - if (ret < 0) - goto edevreg; - - list_add_tail(&ici->list, &hosts); - mutex_unlock(&list_lock); - - scan_add_host(ici); - - return 0; - -edevreg: - mutex_unlock(&list_lock); - return ret; -} -EXPORT_SYMBOL(soc_camera_host_register); - -/* Unregister all clients! */ -void soc_camera_host_unregister(struct soc_camera_host *ici) -{ - struct soc_camera_device *icd; - - mutex_lock(&list_lock); - - list_del(&ici->list); - - list_for_each_entry(icd, &devices, list) { - if (icd->iface == ici->nr) { - void *pdata = icd->dev.platform_data; - /* The bus->remove will be called */ - device_unregister(&icd->dev); - /* - * Not before device_unregister(), .remove - * needs parent to call ici->ops->remove(). - * If the host module is loaded again, device_register() - * would complain "already initialised," since 2.6.32 - * this is also needed to prevent use-after-free of the - * device private data. - */ - memset(&icd->dev, 0, sizeof(icd->dev)); - soc_camera_device_init(&icd->dev, pdata); - } - } - - mutex_unlock(&list_lock); - - v4l2_device_unregister(&ici->v4l2_dev); -} -EXPORT_SYMBOL(soc_camera_host_unregister); - -/* Image capture device */ -static int soc_camera_device_register(struct soc_camera_device *icd) -{ - struct soc_camera_device *ix; - int num = -1, i; - - for (i = 0; i < 256 && num < 0; i++) { - num = i; - /* Check if this index is available on this interface */ - list_for_each_entry(ix, &devices, list) { - if (ix->iface == icd->iface && ix->devnum == i) { - num = -1; - break; - } - } - } - - if (num < 0) - /* - * ok, we have 256 cameras on this host... - * man, stay reasonable... - */ - return -ENOMEM; - - icd->devnum = num; - icd->use_count = 0; - icd->host_priv = NULL; - mutex_init(&icd->video_lock); - - list_add_tail(&icd->list, &devices); - - return 0; -} - -static void soc_camera_device_unregister(struct soc_camera_device *icd) -{ - list_del(&icd->list); -} - -static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { - .vidioc_querycap = soc_camera_querycap, - .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, - .vidioc_enum_input = soc_camera_enum_input, - .vidioc_g_input = soc_camera_g_input, - .vidioc_s_input = soc_camera_s_input, - .vidioc_s_std = soc_camera_s_std, - .vidioc_enum_framesizes = soc_camera_enum_fsizes, - .vidioc_reqbufs = soc_camera_reqbufs, - .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, - .vidioc_querybuf = soc_camera_querybuf, - .vidioc_qbuf = soc_camera_qbuf, - .vidioc_dqbuf = soc_camera_dqbuf, - .vidioc_streamon = soc_camera_streamon, - .vidioc_streamoff = soc_camera_streamoff, - .vidioc_queryctrl = soc_camera_queryctrl, - .vidioc_g_ctrl = soc_camera_g_ctrl, - .vidioc_s_ctrl = soc_camera_s_ctrl, - .vidioc_cropcap = soc_camera_cropcap, - .vidioc_g_crop = soc_camera_g_crop, - .vidioc_s_crop = soc_camera_s_crop, - .vidioc_g_parm = soc_camera_g_parm, - .vidioc_s_parm = soc_camera_s_parm, - .vidioc_g_chip_ident = soc_camera_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = soc_camera_g_register, - .vidioc_s_register = soc_camera_s_register, -#endif -}; - -static int video_dev_create(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct video_device *vdev = video_device_alloc(); - - if (!vdev) - return -ENOMEM; - - strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); - - vdev->parent = &icd->dev; - vdev->current_norm = V4L2_STD_UNKNOWN; - vdev->fops = &soc_camera_fops; - vdev->ioctl_ops = &soc_camera_ioctl_ops; - vdev->release = video_device_release; - vdev->tvnorms = V4L2_STD_UNKNOWN; - - icd->vdev = vdev; - - return 0; -} - -/* - * Called from soc_camera_probe() above (with .video_lock held???) - */ -static int soc_camera_video_start(struct soc_camera_device *icd) -{ - struct device_type *type = icd->vdev->dev.type; - int ret; - - if (!icd->dev.parent) - return -ENODEV; - - if (!icd->ops || - !icd->ops->query_bus_param || - !icd->ops->set_bus_param) - return -EINVAL; - - ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); - if (ret < 0) { - dev_err(&icd->dev, "video_register_device failed: %d\n", ret); - return ret; - } - - /* Restore device type, possibly set by the subdevice driver */ - icd->vdev->dev.type = type; - - return 0; -} - -static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) -{ - struct soc_camera_link *icl = pdev->dev.platform_data; - struct soc_camera_device *icd; - int ret; - - if (!icl) - return -EINVAL; - - icd = kzalloc(sizeof(*icd), GFP_KERNEL); - if (!icd) - return -ENOMEM; - - icd->iface = icl->bus_id; - icd->pdev = &pdev->dev; - platform_set_drvdata(pdev, icd); - - ret = soc_camera_device_register(icd); - if (ret < 0) - goto escdevreg; - - soc_camera_device_init(&icd->dev, icl); - - icd->user_width = DEFAULT_WIDTH; - icd->user_height = DEFAULT_HEIGHT; - - return 0; - -escdevreg: - kfree(icd); - - return ret; -} - -/* - * Only called on rmmod for each platform device, since they are not - * hot-pluggable. Now we know, that all our users - hosts and devices have - * been unloaded already - */ -static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) -{ - struct soc_camera_device *icd = platform_get_drvdata(pdev); - - if (!icd) - return -EINVAL; - - soc_camera_device_unregister(icd); - - kfree(icd); - - return 0; -} - -static struct platform_driver __refdata soc_camera_pdrv = { - .remove = __devexit_p(soc_camera_pdrv_remove), - .driver = { - .name = "soc-camera-pdrv", - .owner = THIS_MODULE, - }, -}; - -static int __init soc_camera_init(void) -{ - int ret = bus_register(&soc_camera_bus_type); - if (ret) - return ret; - ret = driver_register(&ic_drv); - if (ret) - goto edrvr; - - ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe); - if (ret) - goto epdr; - - return 0; - -epdr: - driver_unregister(&ic_drv); -edrvr: - bus_unregister(&soc_camera_bus_type); - return ret; -} - -static void __exit soc_camera_exit(void) -{ - platform_driver_unregister(&soc_camera_pdrv); - driver_unregister(&ic_drv); - bus_unregister(&soc_camera_bus_type); -} - -module_init(soc_camera_init); -module_exit(soc_camera_exit); - -MODULE_DESCRIPTION("Image capture bus driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:soc-camera-pdrv"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_camera_platform.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_camera_platform.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_camera_platform.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_camera_platform.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ -/* - * Generic Platform Camera Driver - * - * Copyright (C) 2008 Magnus Damm - * Based on mt9m001 driver, - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct soc_camera_platform_priv { - struct v4l2_subdev subdev; -}; - -static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) -{ - struct v4l2_subdev *subdev = platform_get_drvdata(pdev); - return container_of(subdev, struct soc_camera_platform_priv, subdev); -} - -static struct soc_camera_platform_info *get_info(struct soc_camera_device *icd) -{ - struct platform_device *pdev = - to_platform_device(to_soc_camera_control(icd)); - return pdev->dev.platform_data; -} - -static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - return p->set_capture(p, enable); -} - -static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - return 0; -} - -static unsigned long -soc_camera_platform_query_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_platform_info *p = get_info(icd); - return p->bus_param; -} - -static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - - mf->width = p->format.width; - mf->height = p->format.height; - mf->code = p->format.code; - mf->colorspace = p->format.colorspace; - mf->field = p->format.field; - - return 0; -} - -static struct v4l2_subdev_core_ops platform_subdev_core_ops; - -static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - - if (index) - return -EINVAL; - - *code = p->format.code; - return 0; -} - -static int soc_camera_platform_g_crop(struct v4l2_subdev *sd, - struct v4l2_crop *a) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - - a->c.left = 0; - a->c.top = 0; - a->c.width = p->format.width; - a->c.height = p->format.height; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int soc_camera_platform_cropcap(struct v4l2_subdev *sd, - struct v4l2_cropcap *a) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = p->format.width; - a->bounds.height = p->format.height; - a->defrect = a->bounds; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static struct v4l2_subdev_video_ops platform_subdev_video_ops = { - .s_stream = soc_camera_platform_s_stream, - .enum_mbus_fmt = soc_camera_platform_enum_fmt, - .cropcap = soc_camera_platform_cropcap, - .g_crop = soc_camera_platform_g_crop, - .try_mbus_fmt = soc_camera_platform_fill_fmt, - .g_mbus_fmt = soc_camera_platform_fill_fmt, - .s_mbus_fmt = soc_camera_platform_fill_fmt, -}; - -static struct v4l2_subdev_ops platform_subdev_ops = { - .core = &platform_subdev_core_ops, - .video = &platform_subdev_video_ops, -}; - -static struct soc_camera_ops soc_camera_platform_ops = { - .set_bus_param = soc_camera_platform_set_bus_param, - .query_bus_param = soc_camera_platform_query_bus_param, -}; - -static int soc_camera_platform_probe(struct platform_device *pdev) -{ - struct soc_camera_host *ici; - struct soc_camera_platform_priv *priv; - struct soc_camera_platform_info *p = pdev->dev.platform_data; - struct soc_camera_device *icd; - int ret; - - if (!p) - return -EINVAL; - - if (!p->dev) { - dev_err(&pdev->dev, - "Platform has not set soc_camera_device pointer!\n"); - return -EINVAL; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - icd = to_soc_camera_dev(p->dev); - - /* soc-camera convention: control's drvdata points to the subdev */ - platform_set_drvdata(pdev, &priv->subdev); - /* Set the control device reference */ - dev_set_drvdata(&icd->dev, &pdev->dev); - - icd->ops = &soc_camera_platform_ops; - - ici = to_soc_camera_host(icd->dev.parent); - - v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); - v4l2_set_subdevdata(&priv->subdev, p); - strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE); - - ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev); - if (ret) - goto evdrs; - - return ret; - -evdrs: - icd->ops = NULL; - platform_set_drvdata(pdev, NULL); - kfree(priv); - return ret; -} - -static int soc_camera_platform_remove(struct platform_device *pdev) -{ - struct soc_camera_platform_priv *priv = get_priv(pdev); - struct soc_camera_platform_info *p = pdev->dev.platform_data; - struct soc_camera_device *icd = to_soc_camera_dev(p->dev); - - v4l2_device_unregister_subdev(&priv->subdev); - icd->ops = NULL; - platform_set_drvdata(pdev, NULL); - kfree(priv); - return 0; -} - -static struct platform_driver soc_camera_platform_driver = { - .driver = { - .name = "soc_camera_platform", - .owner = THIS_MODULE, - }, - .probe = soc_camera_platform_probe, - .remove = soc_camera_platform_remove, -}; - -static int __init soc_camera_platform_module_init(void) -{ - return platform_driver_register(&soc_camera_platform_driver); -} - -static void __exit soc_camera_platform_module_exit(void) -{ - platform_driver_unregister(&soc_camera_platform_driver); -} - -module_init(soc_camera_platform_module_init); -module_exit(soc_camera_platform_module_exit); - -MODULE_DESCRIPTION("SoC Camera Platform driver"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:soc_camera_platform"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_mediabus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_mediabus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_mediabus.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/soc_mediabus.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -/* - * soc-camera media bus helper routines - * - * Copyright (C) 2009, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include - -#include -#include -#include - -#define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1) - -static const struct soc_mbus_pixelfmt mbus_fmt[] = { - [MBUS_IDX(YUYV8_2X8)] = { - .fourcc = V4L2_PIX_FMT_YUYV, - .name = "YUYV", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(YVYU8_2X8)] = { - .fourcc = V4L2_PIX_FMT_YVYU, - .name = "YVYU", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(UYVY8_2X8)] = { - .fourcc = V4L2_PIX_FMT_UYVY, - .name = "UYVY", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(VYUY8_2X8)] = { - .fourcc = V4L2_PIX_FMT_VYUY, - .name = "VYUY", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(RGB555_2X8_PADHI_LE)] = { - .fourcc = V4L2_PIX_FMT_RGB555, - .name = "RGB555", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(RGB555_2X8_PADHI_BE)] = { - .fourcc = V4L2_PIX_FMT_RGB555X, - .name = "RGB555X", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(RGB565_2X8_LE)] = { - .fourcc = V4L2_PIX_FMT_RGB565, - .name = "RGB565", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(RGB565_2X8_BE)] = { - .fourcc = V4L2_PIX_FMT_RGB565X, - .name = "RGB565X", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(SBGGR8_1X8)] = { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .name = "Bayer 8 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(SBGGR10_1X10)] = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 10, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(Y8_1X8)] = { - .fourcc = V4L2_PIX_FMT_GREY, - .name = "Grey", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(Y10_1X10)] = { - .fourcc = V4L2_PIX_FMT_Y10, - .name = "Grey 10bit", - .bits_per_sample = 10, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(SBGGR10_2X8_PADHI_LE)] = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(SBGGR10_2X8_PADLO_LE)] = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADLO, - .order = SOC_MBUS_ORDER_LE, - }, - [MBUS_IDX(SBGGR10_2X8_PADHI_BE)] = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - }, - [MBUS_IDX(SBGGR10_2X8_PADLO_BE)] = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADLO, - .order = SOC_MBUS_ORDER_BE, - }, -}; - -int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf) -{ - switch (mf->packing) { - case SOC_MBUS_PACKING_NONE: - case SOC_MBUS_PACKING_EXTEND16: - return 1; - case SOC_MBUS_PACKING_2X8_PADHI: - case SOC_MBUS_PACKING_2X8_PADLO: - return 2; - } - return -EINVAL; -} -EXPORT_SYMBOL(soc_mbus_samples_per_pixel); - -s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) -{ - switch (mf->packing) { - case SOC_MBUS_PACKING_NONE: - return width * mf->bits_per_sample / 8; - case SOC_MBUS_PACKING_2X8_PADHI: - case SOC_MBUS_PACKING_2X8_PADLO: - case SOC_MBUS_PACKING_EXTEND16: - return width * 2; - } - return -EINVAL; -} -EXPORT_SYMBOL(soc_mbus_bytes_per_line); - -const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( - enum v4l2_mbus_pixelcode code) -{ - if (code - V4L2_MBUS_FMT_FIXED > ARRAY_SIZE(mbus_fmt) || - code <= V4L2_MBUS_FMT_FIXED) - return NULL; - return mbus_fmt + code - V4L2_MBUS_FMT_FIXED - 1; -} -EXPORT_SYMBOL(soc_mbus_get_fmtdesc); - -static int __init soc_mbus_init(void) -{ - return 0; -} - -static void __exit soc_mbus_exit(void) -{ -} - -module_init(soc_mbus_init); -module_exit(soc_mbus_exit); - -MODULE_DESCRIPTION("soc-camera media bus interface"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sr030pc30.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sr030pc30.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sr030pc30.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/sr030pc30.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,884 +0,0 @@ -/* - * Driver for SiliconFile SR030PC30 VGA (1/10-Inch) Image Sensor with ISP - * - * Copyright (C) 2010 Samsung Electronics Co., Ltd - * Author: Sylwester Nawrocki, s.nawrocki@samsung.com - * - * Based on original driver authored by Dongsoo Nathaniel Kim - * and HeungJun Kim . - * - * Based on mt9v011 Micron Digital Image Sensor driver - * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.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, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -static int debug; -module_param(debug, int, 0644); - -#define MODULE_NAME "SR030PC30" - -/* - * Register offsets within a page - * b15..b8 - page id, b7..b0 - register address - */ -#define POWER_CTRL_REG 0x0001 -#define PAGEMODE_REG 0x03 -#define DEVICE_ID_REG 0x0004 -#define NOON010PC30_ID 0x86 -#define SR030PC30_ID 0x8C -#define VDO_CTL1_REG 0x0010 -#define SUBSAMPL_NONE_VGA 0 -#define SUBSAMPL_QVGA 0x10 -#define SUBSAMPL_QQVGA 0x20 -#define VDO_CTL2_REG 0x0011 -#define SYNC_CTL_REG 0x0012 -#define WIN_ROWH_REG 0x0020 -#define WIN_ROWL_REG 0x0021 -#define WIN_COLH_REG 0x0022 -#define WIN_COLL_REG 0x0023 -#define WIN_HEIGHTH_REG 0x0024 -#define WIN_HEIGHTL_REG 0x0025 -#define WIN_WIDTHH_REG 0x0026 -#define WIN_WIDTHL_REG 0x0027 -#define HBLANKH_REG 0x0040 -#define HBLANKL_REG 0x0041 -#define VSYNCH_REG 0x0042 -#define VSYNCL_REG 0x0043 -/* page 10 */ -#define ISP_CTL_REG(n) (0x1010 + (n)) -#define YOFS_REG 0x1040 -#define DARK_YOFS_REG 0x1041 -#define AG_ABRTH_REG 0x1050 -#define SAT_CTL_REG 0x1060 -#define BSAT_REG 0x1061 -#define RSAT_REG 0x1062 -#define AG_SAT_TH_REG 0x1063 -/* page 11 */ -#define ZLPF_CTRL_REG 0x1110 -#define ZLPF_CTRL2_REG 0x1112 -#define ZLPF_AGH_THR_REG 0x1121 -#define ZLPF_THR_REG 0x1160 -#define ZLPF_DYN_THR_REG 0x1160 -/* page 12 */ -#define YCLPF_CTL1_REG 0x1240 -#define YCLPF_CTL2_REG 0x1241 -#define YCLPF_THR_REG 0x1250 -#define BLPF_CTL_REG 0x1270 -#define BLPF_THR1_REG 0x1274 -#define BLPF_THR2_REG 0x1275 -/* page 14 - Lens Shading Compensation */ -#define LENS_CTRL_REG 0x1410 -#define LENS_XCEN_REG 0x1420 -#define LENS_YCEN_REG 0x1421 -#define LENS_R_COMP_REG 0x1422 -#define LENS_G_COMP_REG 0x1423 -#define LENS_B_COMP_REG 0x1424 -/* page 15 - Color correction */ -#define CMC_CTL_REG 0x1510 -#define CMC_OFSGH_REG 0x1514 -#define CMC_OFSGL_REG 0x1516 -#define CMC_SIGN_REG 0x1517 -/* Color correction coefficients */ -#define CMC_COEF_REG(n) (0x1530 + (n)) -/* Color correction offset coefficients */ -#define CMC_OFS_REG(n) (0x1540 + (n)) -/* page 16 - Gamma correction */ -#define GMA_CTL_REG 0x1610 -/* Gamma correction coefficients 0.14 */ -#define GMA_COEF_REG(n) (0x1630 + (n)) -/* page 20 - Auto Exposure */ -#define AE_CTL1_REG 0x2010 -#define AE_CTL2_REG 0x2011 -#define AE_FRM_CTL_REG 0x2020 -#define AE_FINE_CTL_REG(n) (0x2028 + (n)) -#define EXP_TIMEH_REG 0x2083 -#define EXP_TIMEM_REG 0x2084 -#define EXP_TIMEL_REG 0x2085 -#define EXP_MMINH_REG 0x2086 -#define EXP_MMINL_REG 0x2087 -#define EXP_MMAXH_REG 0x2088 -#define EXP_MMAXM_REG 0x2089 -#define EXP_MMAXL_REG 0x208A -/* page 22 - Auto White Balance */ -#define AWB_CTL1_REG 0x2210 -#define AWB_ENABLE 0x80 -#define AWB_CTL2_REG 0x2211 -#define MWB_ENABLE 0x01 -/* RGB gain control (manual WB) when AWB_CTL1[7]=0 */ -#define AWB_RGAIN_REG 0x2280 -#define AWB_GGAIN_REG 0x2281 -#define AWB_BGAIN_REG 0x2282 -#define AWB_RMAX_REG 0x2283 -#define AWB_RMIN_REG 0x2284 -#define AWB_BMAX_REG 0x2285 -#define AWB_BMIN_REG 0x2286 -/* R, B gain range in bright light conditions */ -#define AWB_RMAXB_REG 0x2287 -#define AWB_RMINB_REG 0x2288 -#define AWB_BMAXB_REG 0x2289 -#define AWB_BMINB_REG 0x228A -/* manual white balance, when AWB_CTL2[0]=1 */ -#define MWB_RGAIN_REG 0x22B2 -#define MWB_BGAIN_REG 0x22B3 -/* the token to mark an array end */ -#define REG_TERM 0xFFFF - -/* Minimum and maximum exposure time in ms */ -#define EXPOS_MIN_MS 1 -#define EXPOS_MAX_MS 125 - -struct sr030pc30_info { - struct v4l2_subdev sd; - const struct sr030pc30_platform_data *pdata; - const struct sr030pc30_format *curr_fmt; - const struct sr030pc30_frmsize *curr_win; - unsigned int auto_wb:1; - unsigned int auto_exp:1; - unsigned int hflip:1; - unsigned int vflip:1; - unsigned int sleep:1; - unsigned int exposure; - u8 blue_balance; - u8 red_balance; - u8 i2c_reg_page; -}; - -struct sr030pc30_format { - enum v4l2_mbus_pixelcode code; - enum v4l2_colorspace colorspace; - u16 ispctl1_reg; -}; - -struct sr030pc30_frmsize { - u16 width; - u16 height; - int vid_ctl1; -}; - -struct i2c_regval { - u16 addr; - u16 val; -}; - -static const struct v4l2_queryctrl sr030pc30_ctrl[] = { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto White Balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = 0, - }, { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Auto Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = EXPOS_MIN_MS, - .maximum = EXPOS_MAX_MS, - .step = 1, - .default_value = 1, - }, { - } -}; - -/* supported resolutions */ -static const struct sr030pc30_frmsize sr030pc30_sizes[] = { - { - .width = 640, - .height = 480, - .vid_ctl1 = SUBSAMPL_NONE_VGA, - }, { - .width = 320, - .height = 240, - .vid_ctl1 = SUBSAMPL_QVGA, - }, { - .width = 160, - .height = 120, - .vid_ctl1 = SUBSAMPL_QQVGA, - }, -}; - -/* supported pixel formats */ -static const struct sr030pc30_format sr030pc30_formats[] = { - { - .code = V4L2_MBUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0x03, - }, { - .code = V4L2_MBUS_FMT_YVYU8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0x02, - }, { - .code = V4L2_MBUS_FMT_VYUY8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0, - }, { - .code = V4L2_MBUS_FMT_UYVY8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0x01, - }, { - .code = V4L2_MBUS_FMT_RGB565_2X8_BE, - .colorspace = V4L2_COLORSPACE_JPEG, - .ispctl1_reg = 0x40, - }, -}; - -static const struct i2c_regval sr030pc30_base_regs[] = { - /* Window size and position within pixel matrix */ - { WIN_ROWH_REG, 0x00 }, { WIN_ROWL_REG, 0x06 }, - { WIN_COLH_REG, 0x00 }, { WIN_COLL_REG, 0x06 }, - { WIN_HEIGHTH_REG, 0x01 }, { WIN_HEIGHTL_REG, 0xE0 }, - { WIN_WIDTHH_REG, 0x02 }, { WIN_WIDTHL_REG, 0x80 }, - { HBLANKH_REG, 0x01 }, { HBLANKL_REG, 0x50 }, - { VSYNCH_REG, 0x00 }, { VSYNCL_REG, 0x14 }, - { SYNC_CTL_REG, 0 }, - /* Color corection and saturation */ - { ISP_CTL_REG(0), 0x30 }, { YOFS_REG, 0x80 }, - { DARK_YOFS_REG, 0x04 }, { AG_ABRTH_REG, 0x78 }, - { SAT_CTL_REG, 0x1F }, { BSAT_REG, 0x90 }, - { AG_SAT_TH_REG, 0xF0 }, { 0x1064, 0x80 }, - { CMC_CTL_REG, 0x03 }, { CMC_OFSGH_REG, 0x3C }, - { CMC_OFSGL_REG, 0x2C }, { CMC_SIGN_REG, 0x2F }, - { CMC_COEF_REG(0), 0xCB }, { CMC_OFS_REG(0), 0x87 }, - { CMC_COEF_REG(1), 0x61 }, { CMC_OFS_REG(1), 0x18 }, - { CMC_COEF_REG(2), 0x16 }, { CMC_OFS_REG(2), 0x91 }, - { CMC_COEF_REG(3), 0x23 }, { CMC_OFS_REG(3), 0x94 }, - { CMC_COEF_REG(4), 0xCE }, { CMC_OFS_REG(4), 0x9f }, - { CMC_COEF_REG(5), 0x2B }, { CMC_OFS_REG(5), 0x33 }, - { CMC_COEF_REG(6), 0x01 }, { CMC_OFS_REG(6), 0x00 }, - { CMC_COEF_REG(7), 0x34 }, { CMC_OFS_REG(7), 0x94 }, - { CMC_COEF_REG(8), 0x75 }, { CMC_OFS_REG(8), 0x14 }, - /* Color corection coefficients */ - { GMA_CTL_REG, 0x03 }, { GMA_COEF_REG(0), 0x00 }, - { GMA_COEF_REG(1), 0x19 }, { GMA_COEF_REG(2), 0x26 }, - { GMA_COEF_REG(3), 0x3B }, { GMA_COEF_REG(4), 0x5D }, - { GMA_COEF_REG(5), 0x79 }, { GMA_COEF_REG(6), 0x8E }, - { GMA_COEF_REG(7), 0x9F }, { GMA_COEF_REG(8), 0xAF }, - { GMA_COEF_REG(9), 0xBD }, { GMA_COEF_REG(10), 0xCA }, - { GMA_COEF_REG(11), 0xDD }, { GMA_COEF_REG(12), 0xEC }, - { GMA_COEF_REG(13), 0xF7 }, { GMA_COEF_REG(14), 0xFF }, - /* Noise reduction, Z-LPF, YC-LPF and BLPF filters setup */ - { ZLPF_CTRL_REG, 0x99 }, { ZLPF_CTRL2_REG, 0x0E }, - { ZLPF_AGH_THR_REG, 0x29 }, { ZLPF_THR_REG, 0x0F }, - { ZLPF_DYN_THR_REG, 0x63 }, { YCLPF_CTL1_REG, 0x23 }, - { YCLPF_CTL2_REG, 0x3B }, { YCLPF_THR_REG, 0x05 }, - { BLPF_CTL_REG, 0x1D }, { BLPF_THR1_REG, 0x05 }, - { BLPF_THR2_REG, 0x04 }, - /* Automatic white balance */ - { AWB_CTL1_REG, 0xFB }, { AWB_CTL2_REG, 0x26 }, - { AWB_RMAX_REG, 0x54 }, { AWB_RMIN_REG, 0x2B }, - { AWB_BMAX_REG, 0x57 }, { AWB_BMIN_REG, 0x29 }, - { AWB_RMAXB_REG, 0x50 }, { AWB_RMINB_REG, 0x43 }, - { AWB_BMAXB_REG, 0x30 }, { AWB_BMINB_REG, 0x22 }, - /* Auto exposure */ - { AE_CTL1_REG, 0x8C }, { AE_CTL2_REG, 0x04 }, - { AE_FRM_CTL_REG, 0x01 }, { AE_FINE_CTL_REG(0), 0x3F }, - { AE_FINE_CTL_REG(1), 0xA3 }, { AE_FINE_CTL_REG(3), 0x34 }, - /* Lens shading compensation */ - { LENS_CTRL_REG, 0x01 }, { LENS_XCEN_REG, 0x80 }, - { LENS_YCEN_REG, 0x70 }, { LENS_R_COMP_REG, 0x53 }, - { LENS_G_COMP_REG, 0x40 }, { LENS_B_COMP_REG, 0x3e }, - { REG_TERM, 0 }, -}; - -static inline struct sr030pc30_info *to_sr030pc30(struct v4l2_subdev *sd) -{ - return container_of(sd, struct sr030pc30_info, sd); -} - -static inline int set_i2c_page(struct sr030pc30_info *info, - struct i2c_client *client, unsigned int reg) -{ - int ret = 0; - u32 page = reg >> 8 & 0xFF; - - if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) { - ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page); - if (!ret) - info->i2c_reg_page = page; - } - return ret; -} - -static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct sr030pc30_info *info = to_sr030pc30(sd); - - int ret = set_i2c_page(info, client, reg_addr); - if (!ret) - ret = i2c_smbus_read_byte_data(client, reg_addr & 0xFF); - return ret; -} - -static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct sr030pc30_info *info = to_sr030pc30(sd); - - int ret = set_i2c_page(info, client, reg_addr); - if (!ret) - ret = i2c_smbus_write_byte_data( - client, reg_addr & 0xFF, val); - return ret; -} - -static inline int sr030pc30_bulk_write_reg(struct v4l2_subdev *sd, - const struct i2c_regval *msg) -{ - while (msg->addr != REG_TERM) { - int ret = cam_i2c_write(sd, msg->addr, msg->val); - if (ret) - return ret; - msg++; - } - return 0; -} - -/* Device reset and sleep mode control */ -static int sr030pc30_pwr_ctrl(struct v4l2_subdev *sd, - bool reset, bool sleep) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - u8 reg = sleep ? 0xF1 : 0xF0; - int ret = 0; - - if (reset) - ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02); - if (!ret) { - ret = cam_i2c_write(sd, POWER_CTRL_REG, reg); - if (!ret) { - info->sleep = sleep; - if (reset) - info->i2c_reg_page = -1; - } - } - return ret; -} - -static inline int sr030pc30_enable_autoexposure(struct v4l2_subdev *sd, int on) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - /* auto anti-flicker is also enabled here */ - int ret = cam_i2c_write(sd, AE_CTL1_REG, on ? 0xDC : 0x0C); - if (!ret) - info->auto_exp = on; - return ret; -} - -static int sr030pc30_set_exposure(struct v4l2_subdev *sd, int value) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - - unsigned long expos = value * info->pdata->clk_rate / (8 * 1000); - - int ret = cam_i2c_write(sd, EXP_TIMEH_REG, expos >> 16 & 0xFF); - if (!ret) - ret = cam_i2c_write(sd, EXP_TIMEM_REG, expos >> 8 & 0xFF); - if (!ret) - ret = cam_i2c_write(sd, EXP_TIMEL_REG, expos & 0xFF); - if (!ret) { /* Turn off AE */ - info->exposure = value; - ret = sr030pc30_enable_autoexposure(sd, 0); - } - return ret; -} - -/* Automatic white balance control */ -static int sr030pc30_enable_autowhitebalance(struct v4l2_subdev *sd, int on) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - - int ret = cam_i2c_write(sd, AWB_CTL2_REG, on ? 0x2E : 0x2F); - if (!ret) - ret = cam_i2c_write(sd, AWB_CTL1_REG, on ? 0xFB : 0x7B); - if (!ret) - info->auto_wb = on; - - return ret; -} - -static int sr030pc30_set_flip(struct v4l2_subdev *sd) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - - s32 reg = cam_i2c_read(sd, VDO_CTL2_REG); - if (reg < 0) - return reg; - - reg &= 0x7C; - if (info->hflip) - reg |= 0x01; - if (info->vflip) - reg |= 0x02; - return cam_i2c_write(sd, VDO_CTL2_REG, reg | 0x80); -} - -/* Configure resolution, color format and image flip */ -static int sr030pc30_set_params(struct v4l2_subdev *sd) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - int ret; - - if (!info->curr_win) - return -EINVAL; - - /* Configure the resolution through subsampling */ - ret = cam_i2c_write(sd, VDO_CTL1_REG, - info->curr_win->vid_ctl1); - - if (!ret && info->curr_fmt) - ret = cam_i2c_write(sd, ISP_CTL_REG(0), - info->curr_fmt->ispctl1_reg); - if (!ret) - ret = sr030pc30_set_flip(sd); - - return ret; -} - -/* Find nearest matching image pixel size. */ -static int sr030pc30_try_frame_size(struct v4l2_mbus_framefmt *mf) -{ - unsigned int min_err = ~0; - int i = ARRAY_SIZE(sr030pc30_sizes); - const struct sr030pc30_frmsize *fsize = &sr030pc30_sizes[0], - *match = NULL; - while (i--) { - int err = abs(fsize->width - mf->width) - + abs(fsize->height - mf->height); - if (err < min_err) { - min_err = err; - match = fsize; - } - fsize++; - } - if (match) { - mf->width = match->width; - mf->height = match->height; - return 0; - } - return -EINVAL; -} - -static int sr030pc30_queryctrl(struct v4l2_subdev *sd, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++) - if (qc->id == sr030pc30_ctrl[i].id) { - *qc = sr030pc30_ctrl[i]; - v4l2_dbg(1, debug, sd, "%s id: %d\n", - __func__, qc->id); - return 0; - } - - return -EINVAL; -} - -static inline int sr030pc30_set_bluebalance(struct v4l2_subdev *sd, int value) -{ - int ret = cam_i2c_write(sd, MWB_BGAIN_REG, value); - if (!ret) - to_sr030pc30(sd)->blue_balance = value; - return ret; -} - -static inline int sr030pc30_set_redbalance(struct v4l2_subdev *sd, int value) -{ - int ret = cam_i2c_write(sd, MWB_RGAIN_REG, value); - if (!ret) - to_sr030pc30(sd)->red_balance = value; - return ret; -} - -static int sr030pc30_s_ctrl(struct v4l2_subdev *sd, - struct v4l2_control *ctrl) -{ - int i, ret = 0; - - for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++) - if (ctrl->id == sr030pc30_ctrl[i].id) - break; - - if (i == ARRAY_SIZE(sr030pc30_ctrl)) - return -EINVAL; - - if (ctrl->value < sr030pc30_ctrl[i].minimum || - ctrl->value > sr030pc30_ctrl[i].maximum) - return -ERANGE; - - v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n", - __func__, ctrl->id, ctrl->value); - - switch (ctrl->id) { - case V4L2_CID_AUTO_WHITE_BALANCE: - sr030pc30_enable_autowhitebalance(sd, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - ret = sr030pc30_set_bluebalance(sd, ctrl->value); - break; - case V4L2_CID_RED_BALANCE: - ret = sr030pc30_set_redbalance(sd, ctrl->value); - break; - case V4L2_CID_EXPOSURE_AUTO: - sr030pc30_enable_autoexposure(sd, - ctrl->value == V4L2_EXPOSURE_AUTO); - break; - case V4L2_CID_EXPOSURE: - ret = sr030pc30_set_exposure(sd, ctrl->value); - break; - default: - return -EINVAL; - } - - return ret; -} - -static int sr030pc30_g_ctrl(struct v4l2_subdev *sd, - struct v4l2_control *ctrl) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - - v4l2_dbg(1, debug, sd, "%s: id: %d\n", __func__, ctrl->id); - - switch (ctrl->id) { - case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = info->auto_wb; - break; - case V4L2_CID_BLUE_BALANCE: - ctrl->value = info->blue_balance; - break; - case V4L2_CID_RED_BALANCE: - ctrl->value = info->red_balance; - break; - case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = info->auto_exp; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = info->exposure; - break; - default: - return -EINVAL; - } - return 0; -} - -static int sr030pc30_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (!code || index >= ARRAY_SIZE(sr030pc30_formats)) - return -EINVAL; - - *code = sr030pc30_formats[index].code; - return 0; -} - -static int sr030pc30_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - int ret; - - if (!mf) - return -EINVAL; - - if (!info->curr_win || !info->curr_fmt) { - ret = sr030pc30_set_params(sd); - if (ret) - return ret; - } - - mf->width = info->curr_win->width; - mf->height = info->curr_win->height; - mf->code = info->curr_fmt->code; - mf->colorspace = info->curr_fmt->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -/* Return nearest media bus frame format. */ -static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - int i = ARRAY_SIZE(sr030pc30_formats); - - sr030pc30_try_frame_size(mf); - - while (i--) - if (mf->code == sr030pc30_formats[i].code) - break; - - mf->code = sr030pc30_formats[i].code; - - return &sr030pc30_formats[i]; -} - -/* Return nearest media bus frame format. */ -static int sr030pc30_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - if (!sd || !mf) - return -EINVAL; - - try_fmt(sd, mf); - return 0; -} - -static int sr030pc30_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - - if (!sd || !mf) - return -EINVAL; - - info->curr_fmt = try_fmt(sd, mf); - - return sr030pc30_set_params(sd); -} - -static int sr030pc30_base_config(struct v4l2_subdev *sd) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - int ret; - unsigned long expmin, expmax; - - ret = sr030pc30_bulk_write_reg(sd, sr030pc30_base_regs); - if (!ret) { - info->curr_fmt = &sr030pc30_formats[0]; - info->curr_win = &sr030pc30_sizes[0]; - ret = sr030pc30_set_params(sd); - } - if (!ret) - ret = sr030pc30_pwr_ctrl(sd, false, false); - - if (!ret && !info->pdata) - return ret; - - expmin = EXPOS_MIN_MS * info->pdata->clk_rate / (8 * 1000); - expmax = EXPOS_MAX_MS * info->pdata->clk_rate / (8 * 1000); - - v4l2_dbg(1, debug, sd, "%s: expmin= %lx, expmax= %lx", __func__, - expmin, expmax); - - /* Setting up manual exposure time range */ - ret = cam_i2c_write(sd, EXP_MMINH_REG, expmin >> 8 & 0xFF); - if (!ret) - ret = cam_i2c_write(sd, EXP_MMINL_REG, expmin & 0xFF); - if (!ret) - ret = cam_i2c_write(sd, EXP_MMAXH_REG, expmax >> 16 & 0xFF); - if (!ret) - ret = cam_i2c_write(sd, EXP_MMAXM_REG, expmax >> 8 & 0xFF); - if (!ret) - ret = cam_i2c_write(sd, EXP_MMAXL_REG, expmax & 0xFF); - - return ret; -} - -static int sr030pc30_s_stream(struct v4l2_subdev *sd, int enable) -{ - return 0; -} - -static int sr030pc30_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct sr030pc30_info *info = to_sr030pc30(sd); - const struct sr030pc30_platform_data *pdata = info->pdata; - int ret; - - if (WARN(pdata == NULL, "No platform data!\n")) - return -ENOMEM; - - /* - * Put sensor into power sleep mode before switching off - * power and disabling MCLK. - */ - if (!on) - sr030pc30_pwr_ctrl(sd, false, true); - - /* set_power controls sensor's power and clock */ - if (pdata->set_power) { - ret = pdata->set_power(&client->dev, on); - if (ret) - return ret; - } - - if (on) { - ret = sr030pc30_base_config(sd); - } else { - info->curr_win = NULL; - info->curr_fmt = NULL; - } - - return ret; -} - -static const struct v4l2_subdev_core_ops sr030pc30_core_ops = { - .s_power = sr030pc30_s_power, - .queryctrl = sr030pc30_queryctrl, - .s_ctrl = sr030pc30_s_ctrl, - .g_ctrl = sr030pc30_g_ctrl, -}; - -static const struct v4l2_subdev_video_ops sr030pc30_video_ops = { - .s_stream = sr030pc30_s_stream, - .g_mbus_fmt = sr030pc30_g_fmt, - .s_mbus_fmt = sr030pc30_s_fmt, - .try_mbus_fmt = sr030pc30_try_fmt, - .enum_mbus_fmt = sr030pc30_enum_fmt, -}; - -static const struct v4l2_subdev_ops sr030pc30_ops = { - .core = &sr030pc30_core_ops, - .video = &sr030pc30_video_ops, -}; - -/* - * Detect sensor type. Return 0 if SR030PC30 was detected - * or -ENODEV otherwise. - */ -static int sr030pc30_detect(struct i2c_client *client) -{ - const struct sr030pc30_platform_data *pdata - = client->dev.platform_data; - int ret; - - /* Enable sensor's power and clock */ - if (pdata->set_power) { - ret = pdata->set_power(&client->dev, 1); - if (ret) - return ret; - } - - ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG); - - if (pdata->set_power) - pdata->set_power(&client->dev, 0); - - if (ret < 0) { - dev_err(&client->dev, "%s: I2C read failed\n", __func__); - return ret; - } - - return ret == SR030PC30_ID ? 0 : -ENODEV; -} - - -static int sr030pc30_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct sr030pc30_info *info; - struct v4l2_subdev *sd; - const struct sr030pc30_platform_data *pdata - = client->dev.platform_data; - int ret; - - if (!pdata) { - dev_err(&client->dev, "No platform data!"); - return -EIO; - } - - ret = sr030pc30_detect(client); - if (ret) - return ret; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - sd = &info->sd; - strcpy(sd->name, MODULE_NAME); - info->pdata = client->dev.platform_data; - - v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops); - - info->i2c_reg_page = -1; - info->hflip = 1; - info->auto_exp = 1; - info->exposure = 30; - - return 0; -} - -static int sr030pc30_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct sr030pc30_info *info = to_sr030pc30(sd); - - v4l2_device_unregister_subdev(sd); - kfree(info); - return 0; -} - -static const struct i2c_device_id sr030pc30_id[] = { - { MODULE_NAME, 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, sr030pc30_id); - - -static struct i2c_driver sr030pc30_i2c_driver = { - .driver = { - .name = MODULE_NAME - }, - .probe = sr030pc30_probe, - .remove = sr030pc30_remove, - .id_table = sr030pc30_id, -}; - -static int __init sr030pc30_init(void) -{ - return i2c_add_driver(&sr030pc30_i2c_driver); -} - -static void __exit sr030pc30_exit(void) -{ - i2c_del_driver(&sr030pc30_i2c_driver); -} - -module_init(sr030pc30_init); -module_exit(sr030pc30_exit); - -MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver"); -MODULE_AUTHOR("Sylwester Nawrocki "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-sensor.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-sensor.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-sensor.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-sensor.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,595 +0,0 @@ -/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams) - * - * Copyright 2007-2008 Jaime Velasco Juan - * - * Some parts derived from ov7670.c: - * Copyright 2006 One Laptop Per Child Association, Inc. Written - * by Jonathan Corbet with substantial inspiration from Mark - * McClelland's ovcamchip code. - * - * Copyright 2006-7 Jonathan Corbet - * - * This file may be distributed under the terms of the GNU General - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Controlling the sensor via the STK1125 vendor specific control interface: - * The camera uses an OmniVision sensor and the stk1125 provides an - * SCCB(i2c)-USB bridge which let us program the sensor. - * In my case the sensor id is 0x9652, it can be read from sensor's register - * 0x0A and 0x0B as follows: - * - read register #R: - * output #R to index 0x0208 - * output 0x0070 to index 0x0200 - * input 1 byte from index 0x0201 (some kind of status register) - * until its value is 0x01 - * input 1 byte from index 0x0209. This is the value of #R - * - write value V to register #R - * output #R to index 0x0204 - * output V to index 0x0205 - * output 0x0005 to index 0x0200 - * input 1 byte from index 0x0201 until its value becomes 0x04 - */ - -/* It seems the i2c bus is controlled with these registers */ - -#include "stk-webcam.h" - -#define STK_IIC_BASE (0x0200) -# define STK_IIC_OP (STK_IIC_BASE) -# define STK_IIC_OP_TX (0x05) -# define STK_IIC_OP_RX (0x70) -# define STK_IIC_STAT (STK_IIC_BASE+1) -# define STK_IIC_STAT_TX_OK (0x04) -# define STK_IIC_STAT_RX_OK (0x01) -/* I don't know what does this register. - * when it is 0x00 or 0x01, we cannot talk to the sensor, - * other values work */ -# define STK_IIC_ENABLE (STK_IIC_BASE+2) -# define STK_IIC_ENABLE_NO (0x00) -/* This is what the driver writes in windows */ -# define STK_IIC_ENABLE_YES (0x1e) -/* - * Address of the slave. Seems like the binary driver look for the - * sensor in multiple places, attempting a reset sequence. - * We only know about the ov9650 - */ -# define STK_IIC_ADDR (STK_IIC_BASE+3) -# define STK_IIC_TX_INDEX (STK_IIC_BASE+4) -# define STK_IIC_TX_VALUE (STK_IIC_BASE+5) -# define STK_IIC_RX_INDEX (STK_IIC_BASE+8) -# define STK_IIC_RX_VALUE (STK_IIC_BASE+9) - -#define MAX_RETRIES (50) - -#define SENSOR_ADDRESS (0x60) - -/* From ov7670.c (These registers aren't fully accurate) */ - -/* Registers */ -#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ -#define REG_BLUE 0x01 /* blue gain */ -#define REG_RED 0x02 /* red gain */ -#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ -#define REG_COM1 0x04 /* Control 1 */ -#define COM1_CCIR656 0x40 /* CCIR656 enable */ -#define COM1_QFMT 0x20 /* QVGA/QCIF format */ -#define COM1_SKIP_0 0x00 /* Do not skip any row */ -#define COM1_SKIP_2 0x04 /* Skip 2 rows of 4 */ -#define COM1_SKIP_3 0x08 /* Skip 3 rows of 4 */ -#define REG_BAVE 0x05 /* U/B Average level */ -#define REG_GbAVE 0x06 /* Y/Gb Average level */ -#define REG_AECHH 0x07 /* AEC MS 5 bits */ -#define REG_RAVE 0x08 /* V/R Average level */ -#define REG_COM2 0x09 /* Control 2 */ -#define COM2_SSLEEP 0x10 /* Soft sleep mode */ -#define REG_PID 0x0a /* Product ID MSB */ -#define REG_VER 0x0b /* Product ID LSB */ -#define REG_COM3 0x0c /* Control 3 */ -#define COM3_SWAP 0x40 /* Byte swap */ -#define COM3_SCALEEN 0x08 /* Enable scaling */ -#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */ -#define REG_COM4 0x0d /* Control 4 */ -#define REG_COM5 0x0e /* All "reserved" */ -#define REG_COM6 0x0f /* Control 6 */ -#define REG_AECH 0x10 /* More bits of AEC value */ -#define REG_CLKRC 0x11 /* Clock control */ -#define CLK_PLL 0x80 /* Enable internal PLL */ -#define CLK_EXT 0x40 /* Use external clock directly */ -#define CLK_SCALE 0x3f /* Mask for internal clock scale */ -#define REG_COM7 0x12 /* Control 7 */ -#define COM7_RESET 0x80 /* Register reset */ -#define COM7_FMT_MASK 0x38 -#define COM7_FMT_SXGA 0x00 -#define COM7_FMT_VGA 0x40 -#define COM7_FMT_CIF 0x20 /* CIF format */ -#define COM7_FMT_QVGA 0x10 /* QVGA format */ -#define COM7_FMT_QCIF 0x08 /* QCIF format */ -#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */ -#define COM7_YUV 0x00 /* YUV */ -#define COM7_BAYER 0x01 /* Bayer format */ -#define COM7_PBAYER 0x05 /* "Processed bayer" */ -#define REG_COM8 0x13 /* Control 8 */ -#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ -#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ -#define COM8_BFILT 0x20 /* Band filter enable */ -#define COM8_AGC 0x04 /* Auto gain enable */ -#define COM8_AWB 0x02 /* White balance enable */ -#define COM8_AEC 0x01 /* Auto exposure enable */ -#define REG_COM9 0x14 /* Control 9 - gain ceiling */ -#define REG_COM10 0x15 /* Control 10 */ -#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ -#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ -#define COM10_HREF_REV 0x08 /* Reverse HREF */ -#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ -#define COM10_VS_NEG 0x02 /* VSYNC negative */ -#define COM10_HS_NEG 0x01 /* HSYNC negative */ -#define REG_HSTART 0x17 /* Horiz start high bits */ -#define REG_HSTOP 0x18 /* Horiz stop high bits */ -#define REG_VSTART 0x19 /* Vert start high bits */ -#define REG_VSTOP 0x1a /* Vert stop high bits */ -#define REG_PSHFT 0x1b /* Pixel delay after HREF */ -#define REG_MIDH 0x1c /* Manuf. ID high */ -#define REG_MIDL 0x1d /* Manuf. ID low */ -#define REG_MVFP 0x1e /* Mirror / vflip */ -#define MVFP_MIRROR 0x20 /* Mirror image */ -#define MVFP_FLIP 0x10 /* Vertical flip */ - -#define REG_AEW 0x24 /* AGC upper limit */ -#define REG_AEB 0x25 /* AGC lower limit */ -#define REG_VPT 0x26 /* AGC/AEC fast mode op region */ -#define REG_ADVFL 0x2d /* Insert dummy lines (LSB) */ -#define REG_ADVFH 0x2e /* Insert dummy lines (MSB) */ -#define REG_HSYST 0x30 /* HSYNC rising edge delay */ -#define REG_HSYEN 0x31 /* HSYNC falling edge delay */ -#define REG_HREF 0x32 /* HREF pieces */ -#define REG_TSLB 0x3a /* lots of stuff */ -#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */ -#define TSLB_BYTEORD 0x08 /* swap bytes in 16bit mode? */ -#define REG_COM11 0x3b /* Control 11 */ -#define COM11_NIGHT 0x80 /* NIght mode enable */ -#define COM11_NMFR 0x60 /* Two bit NM frame rate */ -#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ -#define COM11_50HZ 0x08 /* Manual 50Hz select */ -#define COM11_EXP 0x02 -#define REG_COM12 0x3c /* Control 12 */ -#define COM12_HREF 0x80 /* HREF always */ -#define REG_COM13 0x3d /* Control 13 */ -#define COM13_GAMMA 0x80 /* Gamma enable */ -#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ -#define COM13_CMATRIX 0x10 /* Enable color matrix for RGB or YUV */ -#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ -#define REG_COM14 0x3e /* Control 14 */ -#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */ -#define REG_EDGE 0x3f /* Edge enhancement factor */ -#define REG_COM15 0x40 /* Control 15 */ -#define COM15_R10F0 0x00 /* Data range 10 to F0 */ -#define COM15_R01FE 0x80 /* 01 to FE */ -#define COM15_R00FF 0xc0 /* 00 to FF */ -#define COM15_RGB565 0x10 /* RGB565 output */ -#define COM15_RGBFIXME 0x20 /* FIXME */ -#define COM15_RGB555 0x30 /* RGB555 output */ -#define REG_COM16 0x41 /* Control 16 */ -#define COM16_AWBGAIN 0x08 /* AWB gain enable */ -#define REG_COM17 0x42 /* Control 17 */ -#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ -#define COM17_CBAR 0x08 /* DSP Color bar */ - -/* - * This matrix defines how the colors are generated, must be - * tweaked to adjust hue and saturation. - * - * Order: v-red, v-green, v-blue, u-red, u-green, u-blue - * - * They are nine-bit signed quantities, with the sign bit - * stored in 0x58. Sign for v-red is bit 0, and up from there. - */ -#define REG_CMATRIX_BASE 0x4f -#define CMATRIX_LEN 6 -#define REG_CMATRIX_SIGN 0x58 - - -#define REG_BRIGHT 0x55 /* Brightness */ -#define REG_CONTRAS 0x56 /* Contrast control */ - -#define REG_GFIX 0x69 /* Fix gain control */ - -#define REG_RGB444 0x8c /* RGB 444 control */ -#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ -#define R444_RGBX 0x01 /* Empty nibble at end */ - -#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ -#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ - -#define REG_BD50MAX 0xa5 /* 50hz banding step limit */ -#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ -#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ -#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ -#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ -#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ -#define REG_BD60MAX 0xab /* 60hz banding step limit */ - - - - -/* Returns 0 if OK */ -static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) -{ - int i = 0; - int tmpval = 0; - - if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg)) - return 1; - if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val)) - return 1; - if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX)) - return 1; - do { - if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) - return 1; - i++; - } while (tmpval == 0 && i < MAX_RETRIES); - if (tmpval != STK_IIC_STAT_TX_OK) { - if (tmpval) - STK_ERROR("stk_sensor_outb failed, status=0x%02x\n", - tmpval); - return 1; - } else - return 0; -} - -static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) -{ - int i = 0; - int tmpval = 0; - - if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg)) - return 1; - if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX)) - return 1; - do { - if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) - return 1; - i++; - } while (tmpval == 0 && i < MAX_RETRIES); - if (tmpval != STK_IIC_STAT_RX_OK) { - if (tmpval) - STK_ERROR("stk_sensor_inb failed, status=0x%02x\n", - tmpval); - return 1; - } - - if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval)) - return 1; - - *val = (u8) tmpval; - return 0; -} - -static int stk_sensor_write_regvals(struct stk_camera *dev, - struct regval *rv) -{ - int ret; - if (rv == NULL) - return 0; - while (rv->reg != 0xff || rv->val != 0xff) { - ret = stk_sensor_outb(dev, rv->reg, rv->val); - if (ret != 0) - return ret; - rv++; - } - return 0; -} - -int stk_sensor_sleep(struct stk_camera *dev) -{ - u8 tmp; - return stk_sensor_inb(dev, REG_COM2, &tmp) - || stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP); -} - -int stk_sensor_wakeup(struct stk_camera *dev) -{ - u8 tmp; - return stk_sensor_inb(dev, REG_COM2, &tmp) - || stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP); -} - -static struct regval ov_initvals[] = { - {REG_CLKRC, CLK_PLL}, - {REG_COM11, 0x01}, - {0x6a, 0x7d}, - {REG_AECH, 0x40}, - {REG_GAIN, 0x00}, - {REG_BLUE, 0x80}, - {REG_RED, 0x80}, - /* Do not enable fast AEC for now */ - /*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/ - {REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC}, - {0x39, 0x50}, {0x38, 0x93}, - {0x37, 0x00}, {0x35, 0x81}, - {REG_COM5, 0x20}, - {REG_COM1, 0x00}, - {REG_COM3, 0x00}, - {REG_COM4, 0x00}, - {REG_PSHFT, 0x00}, - {0x16, 0x07}, - {0x33, 0xe2}, {0x34, 0xbf}, - {REG_COM16, 0x00}, - {0x96, 0x04}, - /* Gamma curve values */ -/* { 0x7a, 0x20 }, { 0x7b, 0x10 }, - { 0x7c, 0x1e }, { 0x7d, 0x35 }, - { 0x7e, 0x5a }, { 0x7f, 0x69 }, - { 0x80, 0x76 }, { 0x81, 0x80 }, - { 0x82, 0x88 }, { 0x83, 0x8f }, - { 0x84, 0x96 }, { 0x85, 0xa3 }, - { 0x86, 0xaf }, { 0x87, 0xc4 }, - { 0x88, 0xd7 }, { 0x89, 0xe8 }, -*/ - {REG_GFIX, 0x40}, - {0x8e, 0x00}, - {REG_COM12, 0x73}, - {0x8f, 0xdf}, {0x8b, 0x06}, - {0x8c, 0x20}, - {0x94, 0x88}, {0x95, 0x88}, -/* {REG_COM15, 0xc1}, TODO */ - {0x29, 0x3f}, - {REG_COM6, 0x42}, - {REG_BD50MAX, 0x80}, - {REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92}, - {REG_BD60MAX, 0x0a}, - {0x90, 0x00}, {0x91, 0x00}, - {REG_HAECC1, 0x00}, {REG_HAECC2, 0x00}, - {REG_AEW, 0x68}, {REG_AEB, 0x5c}, - {REG_VPT, 0xc3}, - {REG_COM9, 0x2e}, - {0x2a, 0x00}, {0x2b, 0x00}, - - {0xff, 0xff}, /* END MARKER */ -}; - -/* Probe the I2C bus and initialise the sensor chip */ -int stk_sensor_init(struct stk_camera *dev) -{ - u8 idl = 0; - u8 idh = 0; - - if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES) - || stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS) - || stk_sensor_outb(dev, REG_COM7, COM7_RESET)) { - STK_ERROR("Sensor resetting failed\n"); - return -ENODEV; - } - msleep(10); - /* Read the manufacturer ID: ov = 0x7FA2 */ - if (stk_sensor_inb(dev, REG_MIDH, &idh) - || stk_sensor_inb(dev, REG_MIDL, &idl)) { - STK_ERROR("Strange error reading sensor ID\n"); - return -ENODEV; - } - if (idh != 0x7f || idl != 0xa2) { - STK_ERROR("Huh? you don't have a sensor from ovt\n"); - return -ENODEV; - } - if (stk_sensor_inb(dev, REG_PID, &idh) - || stk_sensor_inb(dev, REG_VER, &idl)) { - STK_ERROR("Could not read sensor model\n"); - return -ENODEV; - } - stk_sensor_write_regvals(dev, ov_initvals); - msleep(10); - STK_INFO("OmniVision sensor detected, id %02X%02X" - " at address %x\n", idh, idl, SENSOR_ADDRESS); - return 0; -} - -/* V4L2_PIX_FMT_UYVY */ -static struct regval ov_fmt_uyvy[] = { - {REG_TSLB, TSLB_YLAST|0x08 }, - { 0x4f, 0x80 }, /* "matrix coefficient 1" */ - { 0x50, 0x80 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x22 }, /* "matrix coefficient 4" */ - { 0x53, 0x5e }, /* "matrix coefficient 5" */ - { 0x54, 0x80 }, /* "matrix coefficient 6" */ - {REG_COM13, COM13_UVSAT|COM13_CMATRIX}, - {REG_COM15, COM15_R00FF }, - {0xff, 0xff}, /* END MARKER */ -}; -/* V4L2_PIX_FMT_YUYV */ -static struct regval ov_fmt_yuyv[] = { - {REG_TSLB, 0 }, - { 0x4f, 0x80 }, /* "matrix coefficient 1" */ - { 0x50, 0x80 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x22 }, /* "matrix coefficient 4" */ - { 0x53, 0x5e }, /* "matrix coefficient 5" */ - { 0x54, 0x80 }, /* "matrix coefficient 6" */ - {REG_COM13, COM13_UVSAT|COM13_CMATRIX}, - {REG_COM15, COM15_R00FF }, - {0xff, 0xff}, /* END MARKER */ -}; - -/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */ -static struct regval ov_fmt_rgbr[] = { - { REG_RGB444, 0 }, /* No RGB444 please */ - {REG_TSLB, 0x00}, - { REG_COM1, 0x0 }, - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ - { REG_COM13, COM13_GAMMA }, - { REG_COM15, COM15_RGB565|COM15_R00FF }, - { 0xff, 0xff }, -}; - -/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */ -static struct regval ov_fmt_rgbp[] = { - { REG_RGB444, 0 }, /* No RGB444 please */ - {REG_TSLB, TSLB_BYTEORD }, - { REG_COM1, 0x0 }, - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ - { REG_COM13, COM13_GAMMA }, - { REG_COM15, COM15_RGB565|COM15_R00FF }, - { 0xff, 0xff }, -}; - -/* V4L2_PIX_FMT_SRGGB8 */ -static struct regval ov_fmt_bayer[] = { - /* This changes color order */ - {REG_TSLB, 0x40}, /* BGGR */ - /* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */ - {REG_COM15, COM15_R00FF }, - {0xff, 0xff}, /* END MARKER */ -}; -/* - * Store a set of start/stop values into the camera. - */ -static int stk_sensor_set_hw(struct stk_camera *dev, - int hstart, int hstop, int vstart, int vstop) -{ - int ret; - unsigned char v; -/* - * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of - * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is - * a mystery "edge offset" value in the top two bits of href. - */ - ret = stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff); - ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff); - ret += stk_sensor_inb(dev, REG_HREF, &v); - v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); - msleep(10); - ret += stk_sensor_outb(dev, REG_HREF, v); -/* - * Vertical: similar arrangement (note: this is different from ov7670.c) - */ - ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff); - ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff); - ret += stk_sensor_inb(dev, REG_VREF, &v); - v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7); - msleep(10); - ret += stk_sensor_outb(dev, REG_VREF, v); - return ret; -} - - -int stk_sensor_configure(struct stk_camera *dev) -{ - int com7; - /* - * We setup the sensor to output dummy lines in low-res modes, - * so we don't get absurdly hight framerates. - */ - unsigned dummylines; - int flip; - struct regval *rv; - - switch (dev->vsettings.mode) { - case MODE_QCIF: com7 = COM7_FMT_QCIF; - dummylines = 604; - break; - case MODE_QVGA: com7 = COM7_FMT_QVGA; - dummylines = 267; - break; - case MODE_CIF: com7 = COM7_FMT_CIF; - dummylines = 412; - break; - case MODE_VGA: com7 = COM7_FMT_VGA; - dummylines = 11; - break; - case MODE_SXGA: com7 = COM7_FMT_SXGA; - dummylines = 0; - break; - default: STK_ERROR("Unsupported mode %d\n", dev->vsettings.mode); - return -EFAULT; - } - switch (dev->vsettings.palette) { - case V4L2_PIX_FMT_UYVY: - com7 |= COM7_YUV; - rv = ov_fmt_uyvy; - break; - case V4L2_PIX_FMT_YUYV: - com7 |= COM7_YUV; - rv = ov_fmt_yuyv; - break; - case V4L2_PIX_FMT_RGB565: - com7 |= COM7_RGB; - rv = ov_fmt_rgbp; - break; - case V4L2_PIX_FMT_RGB565X: - com7 |= COM7_RGB; - rv = ov_fmt_rgbr; - break; - case V4L2_PIX_FMT_SBGGR8: - com7 |= COM7_PBAYER; - rv = ov_fmt_bayer; - break; - default: STK_ERROR("Unsupported colorspace\n"); - return -EFAULT; - } - /*FIXME sometimes the sensor go to a bad state - stk_sensor_write_regvals(dev, ov_initvals); */ - stk_sensor_outb(dev, REG_COM7, com7); - msleep(50); - stk_sensor_write_regvals(dev, rv); - flip = (dev->vsettings.vflip?MVFP_FLIP:0) - | (dev->vsettings.hflip?MVFP_MIRROR:0); - stk_sensor_outb(dev, REG_MVFP, flip); - if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8 - && !dev->vsettings.vflip) - stk_sensor_outb(dev, REG_TSLB, 0x08); - stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8); - stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff); - msleep(50); - switch (dev->vsettings.mode) { - case MODE_VGA: - if (stk_sensor_set_hw(dev, 302, 1582, 6, 486)) - STK_ERROR("stk_sensor_set_hw failed (VGA)\n"); - break; - case MODE_SXGA: - case MODE_CIF: - case MODE_QVGA: - case MODE_QCIF: - /*FIXME These settings seem ignored by the sensor - if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034)) - STK_ERROR("stk_sensor_set_hw failed (SXGA)\n"); - */ - break; - } - msleep(10); - return 0; -} - -int stk_sensor_set_brightness(struct stk_camera *dev, int br) -{ - if (br < 0 || br > 0xff) - return -EINVAL; - stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6)); - stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6)); - return 0; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-webcam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-webcam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-webcam.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-webcam.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1392 +0,0 @@ -/* - * stk-webcam.c : Driver for Syntek 1125 USB webcam controller - * - * Copyright (C) 2006 Nicolas VIVIEN - * Copyright 2007-2008 Jaime Velasco Juan - * - * Some parts are inspired from cafe_ccic.c - * Copyright 2006-2007 Jonathan Corbet - * - * 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, or - * any later version. - * - * 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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "stk-webcam.h" - - -static int hflip = 1; -module_param(hflip, bool, 0444); -MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1"); - -static int vflip = 1; -module_param(vflip, bool, 0444); -MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1"); - -static int debug; -module_param(debug, int, 0444); -MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0"); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jaime Velasco Juan and Nicolas VIVIEN"); -MODULE_DESCRIPTION("Syntek DC1125 webcam driver"); - - - -/* Some cameras have audio interfaces, we aren't interested in those */ -static struct usb_device_id stkwebcam_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) }, - { } -}; -MODULE_DEVICE_TABLE(usb, stkwebcam_table); - -/* - * Basic stuff - */ -int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value) -{ - struct usb_device *udev = dev->udev; - int ret; - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x01, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - NULL, - 0, - 500); - if (ret < 0) - return ret; - else - return 0; -} - -int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) -{ - struct usb_device *udev = dev->udev; - int ret; - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x00, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, - index, - (u8 *) value, - sizeof(u8), - 500); - if (ret < 0) - return ret; - else - return 0; -} - -static int stk_start_stream(struct stk_camera *dev) -{ - int value; - int i, ret; - int value_116, value_117; - - if (!is_present(dev)) - return -ENODEV; - if (!is_memallocd(dev) || !is_initialised(dev)) { - STK_ERROR("FIXME: Buffers are not allocated\n"); - return -EFAULT; - } - ret = usb_set_interface(dev->udev, 0, 5); - - if (ret < 0) - STK_ERROR("usb_set_interface failed !\n"); - if (stk_sensor_wakeup(dev)) - STK_ERROR("error awaking the sensor\n"); - - stk_camera_read_reg(dev, 0x0116, &value_116); - stk_camera_read_reg(dev, 0x0117, &value_117); - - stk_camera_write_reg(dev, 0x0116, 0x0000); - stk_camera_write_reg(dev, 0x0117, 0x0000); - - stk_camera_read_reg(dev, 0x0100, &value); - stk_camera_write_reg(dev, 0x0100, value | 0x80); - - stk_camera_write_reg(dev, 0x0116, value_116); - stk_camera_write_reg(dev, 0x0117, value_117); - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (dev->isobufs[i].urb) { - ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL); - atomic_inc(&dev->urbs_used); - if (ret) - return ret; - } - } - set_streaming(dev); - return 0; -} - -static int stk_stop_stream(struct stk_camera *dev) -{ - int value; - int i; - if (is_present(dev)) { - stk_camera_read_reg(dev, 0x0100, &value); - stk_camera_write_reg(dev, 0x0100, value & ~0x80); - if (dev->isobufs != NULL) { - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (dev->isobufs[i].urb) - usb_kill_urb(dev->isobufs[i].urb); - } - } - unset_streaming(dev); - - if (usb_set_interface(dev->udev, 0, 0)) - STK_ERROR("usb_set_interface failed !\n"); - if (stk_sensor_sleep(dev)) - STK_ERROR("error suspending the sensor\n"); - } - return 0; -} - -/* - * This seems to be the shortest init sequence we - * must do in order to find the sensor - * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor - * is also reset. Maybe powers down it? - * Rest of values don't make a difference - */ - -static struct regval stk1125_initvals[] = { - /*TODO: What means this sequence? */ - {0x0000, 0x24}, - {0x0100, 0x21}, - {0x0002, 0x68}, - {0x0003, 0x80}, - {0x0005, 0x00}, - {0x0007, 0x03}, - {0x000d, 0x00}, - {0x000f, 0x02}, - {0x0300, 0x12}, - {0x0350, 0x41}, - {0x0351, 0x00}, - {0x0352, 0x00}, - {0x0353, 0x00}, - {0x0018, 0x10}, - {0x0019, 0x00}, - {0x001b, 0x0e}, - {0x001c, 0x46}, - {0x0300, 0x80}, - {0x001a, 0x04}, - {0x0110, 0x00}, - {0x0111, 0x00}, - {0x0112, 0x00}, - {0x0113, 0x00}, - - {0xffff, 0xff}, -}; - - -static int stk_initialise(struct stk_camera *dev) -{ - struct regval *rv; - int ret; - if (!is_present(dev)) - return -ENODEV; - if (is_initialised(dev)) - return 0; - rv = stk1125_initvals; - while (rv->reg != 0xffff) { - ret = stk_camera_write_reg(dev, rv->reg, rv->val); - if (ret) - return ret; - rv++; - } - if (stk_sensor_init(dev) == 0) { - set_initialised(dev); - return 0; - } else - return -1; -} - -/* *********************************************** */ -/* - * This function is called as an URB transfert is complete (Isochronous pipe). - * So, the traitement is done in interrupt time, so it has be fast, not crash, - * and not stall. Neat. - */ -static void stk_isoc_handler(struct urb *urb) -{ - int i; - int ret; - int framelen; - unsigned long flags; - - unsigned char *fill = NULL; - unsigned char *iso_buf = NULL; - - struct stk_camera *dev; - struct stk_sio_buffer *fb; - - dev = (struct stk_camera *) urb->context; - - if (dev == NULL) { - STK_ERROR("isoc_handler called with NULL device !\n"); - return; - } - - if (urb->status == -ENOENT || urb->status == -ECONNRESET - || urb->status == -ESHUTDOWN) { - atomic_dec(&dev->urbs_used); - return; - } - - spin_lock_irqsave(&dev->spinlock, flags); - - if (urb->status != -EINPROGRESS && urb->status != 0) { - STK_ERROR("isoc_handler: urb->status == %d\n", urb->status); - goto resubmit; - } - - if (list_empty(&dev->sio_avail)) { - /*FIXME Stop streaming after a while */ - (void) (printk_ratelimit() && - STK_ERROR("isoc_handler without available buffer!\n")); - goto resubmit; - } - fb = list_first_entry(&dev->sio_avail, - struct stk_sio_buffer, list); - fill = fb->buffer + fb->v4lbuf.bytesused; - - for (i = 0; i < urb->number_of_packets; i++) { - if (urb->iso_frame_desc[i].status != 0) { - if (urb->iso_frame_desc[i].status != -EXDEV) - STK_ERROR("Frame %d has error %d\n", i, - urb->iso_frame_desc[i].status); - continue; - } - framelen = urb->iso_frame_desc[i].actual_length; - iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - if (framelen <= 4) - continue; /* no data */ - - /* - * we found something informational from there - * the isoc frames have to type of headers - * type1: 00 xx 00 00 or 20 xx 00 00 - * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00 - * xx is a sequencer which has never been seen over 0x3f - * imho data written down looks like bayer, i see similarities - * after every 640 bytes - */ - if (*iso_buf & 0x80) { - framelen -= 8; - iso_buf += 8; - /* This marks a new frame */ - if (fb->v4lbuf.bytesused != 0 - && fb->v4lbuf.bytesused != dev->frame_size) { - (void) (printk_ratelimit() && - STK_ERROR("frame %d, " - "bytesused=%d, skipping\n", - i, fb->v4lbuf.bytesused)); - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; - } else if (fb->v4lbuf.bytesused == dev->frame_size) { - if (list_is_singular(&dev->sio_avail)) { - /* Always reuse the last buffer */ - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; - } else { - list_move_tail(dev->sio_avail.next, - &dev->sio_full); - wake_up(&dev->wait_frame); - fb = list_first_entry(&dev->sio_avail, - struct stk_sio_buffer, list); - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; - } - } - } else { - framelen -= 4; - iso_buf += 4; - } - - /* Our buffer is full !!! */ - if (framelen + fb->v4lbuf.bytesused > dev->frame_size) { - (void) (printk_ratelimit() && - STK_ERROR("Frame buffer overflow, lost sync\n")); - /*FIXME Do something here? */ - continue; - } - spin_unlock_irqrestore(&dev->spinlock, flags); - memcpy(fill, iso_buf, framelen); - spin_lock_irqsave(&dev->spinlock, flags); - fill += framelen; - - /* New size of our buffer */ - fb->v4lbuf.bytesused += framelen; - } - -resubmit: - spin_unlock_irqrestore(&dev->spinlock, flags); - urb->dev = dev->udev; - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret != 0) { - STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n", - ret); - } -} - -/* -------------------------------------------- */ - -static int stk_prepare_iso(struct stk_camera *dev) -{ - void *kbuf; - int i, j; - struct urb *urb; - struct usb_device *udev; - - if (dev == NULL) - return -ENXIO; - udev = dev->udev; - - if (dev->isobufs) - STK_ERROR("isobufs already allocated. Bad\n"); - else - dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs), - GFP_KERNEL); - if (dev->isobufs == NULL) { - STK_ERROR("Unable to allocate iso buffers\n"); - return -ENOMEM; - } - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (dev->isobufs[i].data == NULL) { - kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL); - if (kbuf == NULL) { - STK_ERROR("Failed to allocate iso buffer %d\n", - i); - goto isobufs_out; - } - dev->isobufs[i].data = kbuf; - } else - STK_ERROR("isobuf data already allocated\n"); - if (dev->isobufs[i].urb == NULL) { - urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); - if (urb == NULL) { - STK_ERROR("Failed to allocate URB %d\n", i); - goto isobufs_out; - } - dev->isobufs[i].urb = urb; - } else { - STK_ERROR("Killing URB\n"); - usb_kill_urb(dev->isobufs[i].urb); - urb = dev->isobufs[i].urb; - } - urb->interval = 1; - urb->dev = udev; - urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->isobufs[i].data; - urb->transfer_buffer_length = ISO_BUFFER_SIZE; - urb->complete = stk_isoc_handler; - urb->context = dev; - urb->start_frame = 0; - urb->number_of_packets = ISO_FRAMES_PER_DESC; - - for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { - urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; - urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; - } - } - set_memallocd(dev); - return 0; - -isobufs_out: - for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++) - kfree(dev->isobufs[i].data); - for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++) - usb_free_urb(dev->isobufs[i].urb); - kfree(dev->isobufs); - dev->isobufs = NULL; - return -ENOMEM; -} - -static void stk_clean_iso(struct stk_camera *dev) -{ - int i; - - if (dev == NULL || dev->isobufs == NULL) - return; - - for (i = 0; i < MAX_ISO_BUFS; i++) { - struct urb *urb; - - urb = dev->isobufs[i].urb; - if (urb) { - if (atomic_read(&dev->urbs_used) && is_present(dev)) - usb_kill_urb(urb); - usb_free_urb(urb); - } - kfree(dev->isobufs[i].data); - } - kfree(dev->isobufs); - dev->isobufs = NULL; - unset_memallocd(dev); -} - -static int stk_setup_siobuf(struct stk_camera *dev, int index) -{ - struct stk_sio_buffer *buf = dev->sio_bufs + index; - INIT_LIST_HEAD(&buf->list); - buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size); - buf->buffer = vmalloc_user(buf->v4lbuf.length); - if (buf->buffer == NULL) - return -ENOMEM; - buf->mapcount = 0; - buf->dev = dev; - buf->v4lbuf.index = index; - buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->v4lbuf.field = V4L2_FIELD_NONE; - buf->v4lbuf.memory = V4L2_MEMORY_MMAP; - buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; - return 0; -} - -static int stk_free_sio_buffers(struct stk_camera *dev) -{ - int i; - int nbufs; - unsigned long flags; - if (dev->n_sbufs == 0 || dev->sio_bufs == NULL) - return 0; - /* - * If any buffers are mapped, we cannot free them at all. - */ - for (i = 0; i < dev->n_sbufs; i++) { - if (dev->sio_bufs[i].mapcount > 0) - return -EBUSY; - } - /* - * OK, let's do it. - */ - spin_lock_irqsave(&dev->spinlock, flags); - INIT_LIST_HEAD(&dev->sio_avail); - INIT_LIST_HEAD(&dev->sio_full); - nbufs = dev->n_sbufs; - dev->n_sbufs = 0; - spin_unlock_irqrestore(&dev->spinlock, flags); - for (i = 0; i < nbufs; i++) { - if (dev->sio_bufs[i].buffer != NULL) - vfree(dev->sio_bufs[i].buffer); - } - kfree(dev->sio_bufs); - dev->sio_bufs = NULL; - return 0; -} - -static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs) -{ - int i; - if (dev->sio_bufs != NULL) - STK_ERROR("sio_bufs already allocated\n"); - else { - dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer), - GFP_KERNEL); - if (dev->sio_bufs == NULL) - return -ENOMEM; - for (i = 0; i < n_sbufs; i++) { - if (stk_setup_siobuf(dev, i)) - return (dev->n_sbufs > 1)? 0 : -ENOMEM; - dev->n_sbufs = i+1; - } - } - return 0; -} - -static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs) -{ - int err; - err = stk_prepare_iso(dev); - if (err) { - stk_clean_iso(dev); - return err; - } - err = stk_prepare_sio_buffers(dev, n_sbufs); - if (err) { - stk_free_sio_buffers(dev); - return err; - } - return 0; -} - -static void stk_free_buffers(struct stk_camera *dev) -{ - stk_clean_iso(dev); - stk_free_sio_buffers(dev); -} -/* -------------------------------------------- */ - -/* v4l file operations */ - -static int v4l_stk_open(struct file *fp) -{ - struct stk_camera *dev; - struct video_device *vdev; - - vdev = video_devdata(fp); - dev = vdev_to_camera(vdev); - - if (dev == NULL || !is_present(dev)) { - return -ENXIO; - } - fp->private_data = dev; - usb_autopm_get_interface(dev->interface); - - return 0; -} - -static int v4l_stk_release(struct file *fp) -{ - struct stk_camera *dev = fp->private_data; - - if (dev->owner == fp) { - stk_stop_stream(dev); - stk_free_buffers(dev); - dev->owner = NULL; - } - - if(is_present(dev)) - usb_autopm_put_interface(dev->interface); - - return 0; -} - -static ssize_t v4l_stk_read(struct file *fp, char __user *buf, - size_t count, loff_t *f_pos) -{ - int i; - int ret; - unsigned long flags; - struct stk_sio_buffer *sbuf; - struct stk_camera *dev = fp->private_data; - - if (!is_present(dev)) - return -EIO; - if (dev->owner && dev->owner != fp) - return -EBUSY; - dev->owner = fp; - if (!is_streaming(dev)) { - if (stk_initialise(dev) - || stk_allocate_buffers(dev, 3) - || stk_start_stream(dev)) - return -ENOMEM; - spin_lock_irqsave(&dev->spinlock, flags); - for (i = 0; i < dev->n_sbufs; i++) { - list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail); - dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED; - } - spin_unlock_irqrestore(&dev->spinlock, flags); - } - if (*f_pos == 0) { - if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) - return -EWOULDBLOCK; - ret = wait_event_interruptible(dev->wait_frame, - !list_empty(&dev->sio_full) || !is_present(dev)); - if (ret) - return ret; - if (!is_present(dev)) - return -EIO; - } - if (count + *f_pos > dev->frame_size) - count = dev->frame_size - *f_pos; - spin_lock_irqsave(&dev->spinlock, flags); - if (list_empty(&dev->sio_full)) { - spin_unlock_irqrestore(&dev->spinlock, flags); - STK_ERROR("BUG: No siobufs ready\n"); - return 0; - } - sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); - spin_unlock_irqrestore(&dev->spinlock, flags); - - if (copy_to_user(buf, sbuf->buffer + *f_pos, count)) - return -EFAULT; - - *f_pos += count; - - if (*f_pos >= dev->frame_size) { - *f_pos = 0; - spin_lock_irqsave(&dev->spinlock, flags); - list_move_tail(&sbuf->list, &dev->sio_avail); - spin_unlock_irqrestore(&dev->spinlock, flags); - } - return count; -} - -static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) -{ - struct stk_camera *dev = fp->private_data; - - poll_wait(fp, &dev->wait_frame, wait); - - if (!is_present(dev)) - return POLLERR; - - if (!list_empty(&dev->sio_full)) - return (POLLIN | POLLRDNORM); - - return 0; -} - - -static void stk_v4l_vm_open(struct vm_area_struct *vma) -{ - struct stk_sio_buffer *sbuf = vma->vm_private_data; - sbuf->mapcount++; -} -static void stk_v4l_vm_close(struct vm_area_struct *vma) -{ - struct stk_sio_buffer *sbuf = vma->vm_private_data; - sbuf->mapcount--; - if (sbuf->mapcount == 0) - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; -} -static const struct vm_operations_struct stk_v4l_vm_ops = { - .open = stk_v4l_vm_open, - .close = stk_v4l_vm_close -}; - -static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma) -{ - unsigned int i; - int ret; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - struct stk_camera *dev = fp->private_data; - struct stk_sio_buffer *sbuf = NULL; - - if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) - return -EINVAL; - - for (i = 0; i < dev->n_sbufs; i++) { - if (dev->sio_bufs[i].v4lbuf.m.offset == offset) { - sbuf = dev->sio_bufs + i; - break; - } - } - if (sbuf == NULL) - return -EINVAL; - ret = remap_vmalloc_range(vma, sbuf->buffer, 0); - if (ret) - return ret; - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_private_data = sbuf; - vma->vm_ops = &stk_v4l_vm_ops; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; - stk_v4l_vm_open(vma); - return 0; -} - -/* v4l ioctl handlers */ - -static int stk_vidioc_querycap(struct file *filp, - void *priv, struct v4l2_capability *cap) -{ - strcpy(cap->driver, "stk"); - strcpy(cap->card, "stk"); - cap->version = DRIVER_VERSION_NUM; - - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - return 0; -} - -static int stk_vidioc_enum_input(struct file *filp, - void *priv, struct v4l2_input *input) -{ - if (input->index != 0) - return -EINVAL; - - strcpy(input->name, "Syntek USB Camera"); - input->type = V4L2_INPUT_TYPE_CAMERA; - return 0; -} - - -static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - else - return 0; -} - -/* from vivi.c */ -static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) -{ - return 0; -} - -/* List of all V4Lv2 controls supported by the driver */ -static struct v4l2_queryctrl stk_controls[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xffff, - .step = 0x0100, - .default_value = 0x6000, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Horizontal Flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vertical Flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, -}; - -static int stk_vidioc_queryctrl(struct file *filp, - void *priv, struct v4l2_queryctrl *c) -{ - int i; - int nbr; - nbr = ARRAY_SIZE(stk_controls); - - for (i = 0; i < nbr; i++) { - if (stk_controls[i].id == c->id) { - memcpy(c, &stk_controls[i], - sizeof(struct v4l2_queryctrl)); - return 0; - } - } - return -EINVAL; -} - -static int stk_vidioc_g_ctrl(struct file *filp, - void *priv, struct v4l2_control *c) -{ - struct stk_camera *dev = priv; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = dev->vsettings.brightness; - break; - case V4L2_CID_HFLIP: - c->value = dev->vsettings.hflip; - break; - case V4L2_CID_VFLIP: - c->value = dev->vsettings.vflip; - break; - default: - return -EINVAL; - } - return 0; -} - -static int stk_vidioc_s_ctrl(struct file *filp, - void *priv, struct v4l2_control *c) -{ - struct stk_camera *dev = priv; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - dev->vsettings.brightness = c->value; - return stk_sensor_set_brightness(dev, c->value >> 8); - case V4L2_CID_HFLIP: - dev->vsettings.hflip = c->value; - return 0; - case V4L2_CID_VFLIP: - dev->vsettings.vflip = c->value; - return 0; - default: - return -EINVAL; - } - return 0; -} - - -static int stk_vidioc_enum_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_fmtdesc *fmtd) -{ - switch (fmtd->index) { - case 0: - fmtd->pixelformat = V4L2_PIX_FMT_RGB565; - strcpy(fmtd->description, "r5g6b5"); - break; - case 1: - fmtd->pixelformat = V4L2_PIX_FMT_RGB565X; - strcpy(fmtd->description, "r5g6b5BE"); - break; - case 2: - fmtd->pixelformat = V4L2_PIX_FMT_UYVY; - strcpy(fmtd->description, "yuv4:2:2"); - break; - case 3: - fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8; - strcpy(fmtd->description, "Raw bayer"); - break; - case 4: - fmtd->pixelformat = V4L2_PIX_FMT_YUYV; - strcpy(fmtd->description, "yuv4:2:2"); - break; - default: - return -EINVAL; - } - return 0; -} - -static struct stk_size { - unsigned w; - unsigned h; - enum stk_mode m; -} stk_sizes[] = { - { .w = 1280, .h = 1024, .m = MODE_SXGA, }, - { .w = 640, .h = 480, .m = MODE_VGA, }, - { .w = 352, .h = 288, .m = MODE_CIF, }, - { .w = 320, .h = 240, .m = MODE_QVGA, }, - { .w = 176, .h = 144, .m = MODE_QCIF, }, -}; - -static int stk_vidioc_g_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_format *f) -{ - struct v4l2_pix_format *pix_format = &f->fmt.pix; - struct stk_camera *dev = priv; - int i; - - for (i = 0; i < ARRAY_SIZE(stk_sizes) - && stk_sizes[i].m != dev->vsettings.mode; - i++); - if (i == ARRAY_SIZE(stk_sizes)) { - STK_ERROR("ERROR: mode invalid\n"); - return -EINVAL; - } - pix_format->width = stk_sizes[i].w; - pix_format->height = stk_sizes[i].h; - pix_format->field = V4L2_FIELD_NONE; - pix_format->colorspace = V4L2_COLORSPACE_SRGB; - pix_format->pixelformat = dev->vsettings.palette; - if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) - pix_format->bytesperline = pix_format->width; - else - pix_format->bytesperline = 2 * pix_format->width; - pix_format->sizeimage = pix_format->bytesperline - * pix_format->height; - return 0; -} - -static int stk_vidioc_try_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_format *fmtd) -{ - int i; - switch (fmtd->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_SBGGR8: - break; - default: - return -EINVAL; - } - for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) { - if (fmtd->fmt.pix.width > stk_sizes[i].w) - break; - } - if (i == ARRAY_SIZE(stk_sizes) - || (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w) - < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) { - fmtd->fmt.pix.height = stk_sizes[i-1].h; - fmtd->fmt.pix.width = stk_sizes[i-1].w; - fmtd->fmt.pix.priv = i - 1; - } else { - fmtd->fmt.pix.height = stk_sizes[i].h; - fmtd->fmt.pix.width = stk_sizes[i].w; - fmtd->fmt.pix.priv = i; - } - - fmtd->fmt.pix.field = V4L2_FIELD_NONE; - fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; - if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8) - fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width; - else - fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width; - fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline - * fmtd->fmt.pix.height; - return 0; -} - -static int stk_setup_format(struct stk_camera *dev) -{ - int i = 0; - int depth; - if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) - depth = 1; - else - depth = 2; - while (i < ARRAY_SIZE(stk_sizes) && - stk_sizes[i].m != dev->vsettings.mode) - i++; - if (i == ARRAY_SIZE(stk_sizes)) { - STK_ERROR("Something is broken in %s\n", __func__); - return -EFAULT; - } - /* This registers controls some timings, not sure of what. */ - stk_camera_write_reg(dev, 0x001b, 0x0e); - if (dev->vsettings.mode == MODE_SXGA) - stk_camera_write_reg(dev, 0x001c, 0x0e); - else - stk_camera_write_reg(dev, 0x001c, 0x46); - /* - * Registers 0x0115 0x0114 are the size of each line (bytes), - * regs 0x0117 0x0116 are the heigth of the image. - */ - stk_camera_write_reg(dev, 0x0115, - ((stk_sizes[i].w * depth) >> 8) & 0xff); - stk_camera_write_reg(dev, 0x0114, - (stk_sizes[i].w * depth) & 0xff); - stk_camera_write_reg(dev, 0x0117, - (stk_sizes[i].h >> 8) & 0xff); - stk_camera_write_reg(dev, 0x0116, - stk_sizes[i].h & 0xff); - return stk_sensor_configure(dev); -} - -static int stk_vidioc_s_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_format *fmtd) -{ - int ret; - struct stk_camera *dev = priv; - - if (dev == NULL) - return -ENODEV; - if (!is_present(dev)) - return -ENODEV; - if (is_streaming(dev)) - return -EBUSY; - if (dev->owner && dev->owner != filp) - return -EBUSY; - ret = stk_vidioc_try_fmt_vid_cap(filp, priv, fmtd); - if (ret) - return ret; - dev->owner = filp; - - dev->vsettings.palette = fmtd->fmt.pix.pixelformat; - stk_free_buffers(dev); - dev->frame_size = fmtd->fmt.pix.sizeimage; - dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m; - - stk_initialise(dev); - return stk_setup_format(dev); -} - -static int stk_vidioc_reqbufs(struct file *filp, - void *priv, struct v4l2_requestbuffers *rb) -{ - struct stk_camera *dev = priv; - - if (dev == NULL) - return -ENODEV; - if (rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - if (is_streaming(dev) - || (dev->owner && dev->owner != filp)) - return -EBUSY; - dev->owner = filp; - - /*FIXME If they ask for zero, we must stop streaming and free */ - if (rb->count < 3) - rb->count = 3; - /* Arbitrary limit */ - else if (rb->count > 5) - rb->count = 5; - - stk_allocate_buffers(dev, rb->count); - rb->count = dev->n_sbufs; - return 0; -} - -static int stk_vidioc_querybuf(struct file *filp, - void *priv, struct v4l2_buffer *buf) -{ - struct stk_camera *dev = priv; - struct stk_sio_buffer *sbuf; - - if (buf->index >= dev->n_sbufs) - return -EINVAL; - sbuf = dev->sio_bufs + buf->index; - *buf = sbuf->v4lbuf; - return 0; -} - -static int stk_vidioc_qbuf(struct file *filp, - void *priv, struct v4l2_buffer *buf) -{ - struct stk_camera *dev = priv; - struct stk_sio_buffer *sbuf; - unsigned long flags; - - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (buf->index >= dev->n_sbufs) - return -EINVAL; - sbuf = dev->sio_bufs + buf->index; - if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) - return 0; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; - spin_lock_irqsave(&dev->spinlock, flags); - list_add_tail(&sbuf->list, &dev->sio_avail); - *buf = sbuf->v4lbuf; - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; -} - -static int stk_vidioc_dqbuf(struct file *filp, - void *priv, struct v4l2_buffer *buf) -{ - struct stk_camera *dev = priv; - struct stk_sio_buffer *sbuf; - unsigned long flags; - int ret; - - if (!is_streaming(dev)) - return -EINVAL; - - if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) - return -EWOULDBLOCK; - ret = wait_event_interruptible(dev->wait_frame, - !list_empty(&dev->sio_full) || !is_present(dev)); - if (ret) - return ret; - if (!is_present(dev)) - return -EIO; - - spin_lock_irqsave(&dev->spinlock, flags); - sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); - list_del_init(&sbuf->list); - spin_unlock_irqrestore(&dev->spinlock, flags); - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; - sbuf->v4lbuf.sequence = ++dev->sequence; - do_gettimeofday(&sbuf->v4lbuf.timestamp); - - *buf = sbuf->v4lbuf; - return 0; -} - -static int stk_vidioc_streamon(struct file *filp, - void *priv, enum v4l2_buf_type type) -{ - struct stk_camera *dev = priv; - if (is_streaming(dev)) - return 0; - if (dev->sio_bufs == NULL) - return -EINVAL; - dev->sequence = 0; - return stk_start_stream(dev); -} - -static int stk_vidioc_streamoff(struct file *filp, - void *priv, enum v4l2_buf_type type) -{ - struct stk_camera *dev = priv; - unsigned long flags; - int i; - stk_stop_stream(dev); - spin_lock_irqsave(&dev->spinlock, flags); - INIT_LIST_HEAD(&dev->sio_avail); - INIT_LIST_HEAD(&dev->sio_full); - for (i = 0; i < dev->n_sbufs; i++) { - INIT_LIST_HEAD(&dev->sio_bufs[i].list); - dev->sio_bufs[i].v4lbuf.flags = 0; - } - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; -} - - -static int stk_vidioc_g_parm(struct file *filp, - void *priv, struct v4l2_streamparm *sp) -{ - /*FIXME This is not correct */ - sp->parm.capture.timeperframe.numerator = 1; - sp->parm.capture.timeperframe.denominator = 30; - sp->parm.capture.readbuffers = 2; - return 0; -} - -static int stk_vidioc_enum_framesizes(struct file *filp, - void *priv, struct v4l2_frmsizeenum *frms) -{ - if (frms->index >= ARRAY_SIZE(stk_sizes)) - return -EINVAL; - switch (frms->pixel_format) { - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_SBGGR8: - frms->type = V4L2_FRMSIZE_TYPE_DISCRETE; - frms->discrete.width = stk_sizes[frms->index].w; - frms->discrete.height = stk_sizes[frms->index].h; - return 0; - default: return -EINVAL; - } -} - -static struct v4l2_file_operations v4l_stk_fops = { - .owner = THIS_MODULE, - .open = v4l_stk_open, - .release = v4l_stk_release, - .read = v4l_stk_read, - .poll = v4l_stk_poll, - .mmap = v4l_stk_mmap, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { - .vidioc_querycap = stk_vidioc_querycap, - .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = stk_vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = stk_vidioc_g_fmt_vid_cap, - .vidioc_enum_input = stk_vidioc_enum_input, - .vidioc_s_input = stk_vidioc_s_input, - .vidioc_g_input = stk_vidioc_g_input, - .vidioc_s_std = stk_vidioc_s_std, - .vidioc_reqbufs = stk_vidioc_reqbufs, - .vidioc_querybuf = stk_vidioc_querybuf, - .vidioc_qbuf = stk_vidioc_qbuf, - .vidioc_dqbuf = stk_vidioc_dqbuf, - .vidioc_streamon = stk_vidioc_streamon, - .vidioc_streamoff = stk_vidioc_streamoff, - .vidioc_queryctrl = stk_vidioc_queryctrl, - .vidioc_g_ctrl = stk_vidioc_g_ctrl, - .vidioc_s_ctrl = stk_vidioc_s_ctrl, - .vidioc_g_parm = stk_vidioc_g_parm, - .vidioc_enum_framesizes = stk_vidioc_enum_framesizes, -}; - -static void stk_v4l_dev_release(struct video_device *vd) -{ - struct stk_camera *dev = vdev_to_camera(vd); - - if (dev->sio_bufs != NULL || dev->isobufs != NULL) - STK_ERROR("We are leaking memory\n"); - usb_put_intf(dev->interface); - kfree(dev); -} - -static struct video_device stk_v4l_data = { - .name = "stkwebcam", - .tvnorms = V4L2_STD_UNKNOWN, - .current_norm = V4L2_STD_UNKNOWN, - .fops = &v4l_stk_fops, - .ioctl_ops = &v4l_stk_ioctl_ops, - .release = stk_v4l_dev_release, -}; - - -static int stk_register_video_device(struct stk_camera *dev) -{ - int err; - - dev->vdev = stk_v4l_data; - dev->vdev.debug = debug; - dev->vdev.parent = &dev->interface->dev; - err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); - if (err) - STK_ERROR("v4l registration failed\n"); - else - STK_INFO("Syntek USB2.0 Camera is now controlling device %s\n", - video_device_node_name(&dev->vdev)); - return err; -} - - -/* USB Stuff */ - -static int stk_camera_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - int i; - int err = 0; - - struct stk_camera *dev = NULL; - struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - - dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL); - if (dev == NULL) { - STK_ERROR("Out of memory !\n"); - return -ENOMEM; - } - - spin_lock_init(&dev->spinlock); - init_waitqueue_head(&dev->wait_frame); - - dev->udev = udev; - dev->interface = interface; - usb_get_intf(interface); - - dev->vsettings.vflip = vflip; - dev->vsettings.hflip = hflip; - dev->n_sbufs = 0; - set_present(dev); - - /* Set up the endpoint information - * use only the first isoc-in endpoint - * for the current alternate setting */ - iface_desc = interface->cur_altsetting; - - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (!dev->isoc_ep - && usb_endpoint_is_isoc_in(endpoint)) { - /* we found an isoc in endpoint */ - dev->isoc_ep = usb_endpoint_num(endpoint); - break; - } - } - if (!dev->isoc_ep) { - STK_ERROR("Could not find isoc-in endpoint"); - err = -ENODEV; - goto error; - } - dev->vsettings.brightness = 0x7fff; - dev->vsettings.palette = V4L2_PIX_FMT_RGB565; - dev->vsettings.mode = MODE_VGA; - dev->frame_size = 640 * 480 * 2; - - INIT_LIST_HEAD(&dev->sio_avail); - INIT_LIST_HEAD(&dev->sio_full); - - usb_set_intfdata(interface, dev); - - err = stk_register_video_device(dev); - if (err) { - goto error; - } - - return 0; - -error: - kfree(dev); - return err; -} - -static void stk_camera_disconnect(struct usb_interface *interface) -{ - struct stk_camera *dev = usb_get_intfdata(interface); - - usb_set_intfdata(interface, NULL); - unset_present(dev); - - wake_up_interruptible(&dev->wait_frame); - - STK_INFO("Syntek USB2.0 Camera release resources device %s\n", - video_device_node_name(&dev->vdev)); - - video_unregister_device(&dev->vdev); -} - -#ifdef CONFIG_PM -static int stk_camera_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct stk_camera *dev = usb_get_intfdata(intf); - if (is_streaming(dev)) { - stk_stop_stream(dev); - /* yes, this is ugly */ - set_streaming(dev); - } - return 0; -} - -static int stk_camera_resume(struct usb_interface *intf) -{ - struct stk_camera *dev = usb_get_intfdata(intf); - if (!is_initialised(dev)) - return 0; - unset_initialised(dev); - stk_initialise(dev); - stk_setup_format(dev); - if (is_streaming(dev)) - stk_start_stream(dev); - return 0; -} -#endif - -static struct usb_driver stk_camera_driver = { - .name = "stkwebcam", - .probe = stk_camera_probe, - .disconnect = stk_camera_disconnect, - .id_table = stkwebcam_table, -#ifdef CONFIG_PM - .suspend = stk_camera_suspend, - .resume = stk_camera_resume, -#endif -}; - - -static int __init stk_camera_init(void) -{ - int result; - - result = usb_register(&stk_camera_driver); - if (result) - STK_ERROR("usb_register failed ! Error number %d\n", result); - - - return result; -} - -static void __exit stk_camera_exit(void) -{ - usb_deregister(&stk_camera_driver); -} - -module_init(stk_camera_init); -module_exit(stk_camera_exit); - - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-webcam.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-webcam.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-webcam.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/stk-webcam.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -/* - * stk-webcam.h : Driver for Syntek 1125 USB webcam controller - * - * Copyright (C) 2006 Nicolas VIVIEN - * Copyright 2007-2008 Jaime Velasco Juan - * - * 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, or - * any later version. - * - * 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 - */ - -#ifndef STKWEBCAM_H -#define STKWEBCAM_H - -#include -#include - -#define DRIVER_VERSION "v0.0.1" -#define DRIVER_VERSION_NUM 0x000001 - -#define MAX_ISO_BUFS 3 -#define ISO_FRAMES_PER_DESC 16 -#define ISO_MAX_FRAME_SIZE 3 * 1024 -#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) - - -#define PREFIX "stkwebcam: " -#define STK_INFO(str, args...) printk(KERN_INFO PREFIX str, ##args) -#define STK_ERROR(str, args...) printk(KERN_ERR PREFIX str, ##args) -#define STK_WARNING(str, args...) printk(KERN_WARNING PREFIX str, ##args) - -struct stk_iso_buf { - void *data; - int length; - int read; - struct urb *urb; -}; - -/* Streaming IO buffers */ -struct stk_sio_buffer { - struct v4l2_buffer v4lbuf; - char *buffer; - int mapcount; - struct stk_camera *dev; - struct list_head list; -}; - -enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF}; - -struct stk_video { - enum stk_mode mode; - int brightness; - __u32 palette; - int hflip; - int vflip; -}; - -enum stk_status { - S_PRESENT = 1, - S_INITIALISED = 2, - S_MEMALLOCD = 4, - S_STREAMING = 8, -}; -#define is_present(dev) ((dev)->status & S_PRESENT) -#define is_initialised(dev) ((dev)->status & S_INITIALISED) -#define is_streaming(dev) ((dev)->status & S_STREAMING) -#define is_memallocd(dev) ((dev)->status & S_MEMALLOCD) -#define set_present(dev) ((dev)->status = S_PRESENT) -#define unset_present(dev) ((dev)->status &= \ - ~(S_PRESENT|S_INITIALISED|S_STREAMING)) -#define set_initialised(dev) ((dev)->status |= S_INITIALISED) -#define unset_initialised(dev) ((dev)->status &= ~S_INITIALISED) -#define set_memallocd(dev) ((dev)->status |= S_MEMALLOCD) -#define unset_memallocd(dev) ((dev)->status &= ~S_MEMALLOCD) -#define set_streaming(dev) ((dev)->status |= S_STREAMING) -#define unset_streaming(dev) ((dev)->status &= ~S_STREAMING) - -struct regval { - unsigned reg; - unsigned val; -}; - -struct stk_camera { - struct video_device vdev; - struct usb_device *udev; - struct usb_interface *interface; - int webcam_model; - struct file *owner; - - u8 isoc_ep; - - /* Not sure if this is right */ - atomic_t urbs_used; - - struct stk_video vsettings; - - enum stk_status status; - - spinlock_t spinlock; - wait_queue_head_t wait_frame; - - struct stk_iso_buf *isobufs; - - int frame_size; - /* Streaming buffers */ - unsigned int n_sbufs; - struct stk_sio_buffer *sio_bufs; - struct list_head sio_avail; - struct list_head sio_full; - unsigned sequence; -}; - -#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev) - -int stk_camera_write_reg(struct stk_camera *, u16, u8); -int stk_camera_read_reg(struct stk_camera *, u16, int *); - -int stk_sensor_init(struct stk_camera *); -int stk_sensor_configure(struct stk_camera *); -int stk_sensor_sleep(struct stk_camera *dev); -int stk_sensor_wakeup(struct stk_camera *dev); -int stk_sensor_set_brightness(struct stk_camera *dev, int br); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tcm825x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tcm825x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tcm825x.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tcm825x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,936 +0,0 @@ -/* - * drivers/media/video/tcm825x.c - * - * TCM825X camera sensor driver. - * - * Copyright (C) 2007 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * Based on code from David Cohen - * - * This driver was based on ov9640 sensor driver from MontaVista - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include - -#include "tcm825x.h" - -/* - * The sensor has two fps modes: the lower one just gives half the fps - * at the same xclk than the high one. - */ -#define MAX_FPS 30 -#define MIN_FPS 8 -#define MAX_HALF_FPS (MAX_FPS / 2) -#define HIGH_FPS_MODE_LOWER_LIMIT 14 -#define DEFAULT_FPS MAX_HALF_FPS - -struct tcm825x_sensor { - const struct tcm825x_platform_data *platform_data; - struct v4l2_int_device *v4l2_int_device; - struct i2c_client *i2c_client; - struct v4l2_pix_format pix; - struct v4l2_fract timeperframe; -}; - -/* list of image formats supported by TCM825X sensor */ -static const struct v4l2_fmtdesc tcm825x_formats[] = { - { - .description = "YUYV (YUV 4:2:2), packed", - .pixelformat = V4L2_PIX_FMT_UYVY, - }, { - /* Note: V4L2 defines RGB565 as: - * - * Byte 0 Byte 1 - * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 - * - * We interpret RGB565 as: - * - * Byte 0 Byte 1 - * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 - */ - .description = "RGB565, le", - .pixelformat = V4L2_PIX_FMT_RGB565, - }, -}; - -#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats) - -/* - * TCM825X register configuration for all combinations of pixel format and - * image size - */ -static const struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ }; -static const struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ }; -static const struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ }; -static const struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ }; -static const struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ }; -static const struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ }; - -static const struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT }; -static const struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT }; - -/* Our own specific controls */ -#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE -#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1 -#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2 -#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3 -#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4 -#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME - -/* Video controls */ -static struct vcontrol { - struct v4l2_queryctrl qc; - u16 reg; - u16 start_bit; -} video_control[] = { - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 63, - .step = 1, - }, - .reg = TCM825X_AG, - .start_bit = 0, - }, - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 0, - .maximum = 255, - .step = 1, - }, - .reg = TCM825X_MRG, - .start_bit = 0, - }, - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 0, - .maximum = 255, - .step = 1, - }, - .reg = TCM825X_MBG, - .start_bit = 0, - }, - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto White Balance", - .minimum = 0, - .maximum = 1, - .step = 0, - }, - .reg = TCM825X_AWBSW, - .start_bit = 7, - }, - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure Time", - .minimum = 0, - .maximum = 0x1fff, - .step = 1, - }, - .reg = TCM825X_ESRSPD_U, - .start_bit = 0, - }, - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror Image", - .minimum = 0, - .maximum = 1, - .step = 0, - }, - .reg = TCM825X_H_INV, - .start_bit = 6, - }, - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vertical Flip", - .minimum = 0, - .maximum = 1, - .step = 0, - }, - .reg = TCM825X_V_INV, - .start_bit = 7, - }, - /* Private controls */ - { - { - .id = V4L2_CID_ALC, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Luminance Control", - .minimum = 0, - .maximum = 1, - .step = 0, - }, - .reg = TCM825X_ALCSW, - .start_bit = 7, - }, - { - { - .id = V4L2_CID_H_EDGE_EN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Horizontal Edge Enhancement", - .minimum = 0, - .maximum = 0xff, - .step = 1, - }, - .reg = TCM825X_HDTG, - .start_bit = 0, - }, - { - { - .id = V4L2_CID_V_EDGE_EN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Vertical Edge Enhancement", - .minimum = 0, - .maximum = 0xff, - .step = 1, - }, - .reg = TCM825X_VDTG, - .start_bit = 0, - }, - { - { - .id = V4L2_CID_LENS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Lens Shading Compensation", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - }, - .reg = TCM825X_LENS, - .start_bit = 0, - }, - { - { - .id = V4L2_CID_MAX_EXPOSURE_TIME, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Maximum Exposure Time", - .minimum = 0, - .maximum = 0x3, - .step = 1, - }, - .reg = TCM825X_ESRLIM, - .start_bit = 5, - }, -}; - - -static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] = -{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga }; - -static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] = -{ &yuv422, &rgb565 }; - -/* - * Read a value from a register in an TCM825X sensor device. The value is - * returned in 'val'. - * Returns zero if successful, or non-zero otherwise. - */ -static int tcm825x_read_reg(struct i2c_client *client, int reg) -{ - int err; - struct i2c_msg msg[2]; - u8 reg_buf, data_buf = 0; - - if (!client->adapter) - return -ENODEV; - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = ®_buf; - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = 1; - msg[1].buf = &data_buf; - - reg_buf = reg; - - err = i2c_transfer(client->adapter, msg, 2); - if (err < 0) - return err; - return data_buf; -} - -/* - * Write a value to a register in an TCM825X sensor device. - * Returns zero if successful, or non-zero otherwise. - */ -static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val) -{ - int err; - struct i2c_msg msg[1]; - unsigned char data[2]; - - if (!client->adapter) - return -ENODEV; - - msg->addr = client->addr; - msg->flags = 0; - msg->len = 2; - msg->buf = data; - data[0] = reg; - data[1] = val; - err = i2c_transfer(client->adapter, msg, 1); - if (err >= 0) - return 0; - return err; -} - -static int __tcm825x_write_reg_mask(struct i2c_client *client, - u8 reg, u8 val, u8 mask) -{ - int rc; - - /* need to do read - modify - write */ - rc = tcm825x_read_reg(client, reg); - if (rc < 0) - return rc; - - rc &= (~mask); /* Clear the masked bits */ - val &= mask; /* Enforce mask on value */ - val |= rc; - - /* write the new value to the register */ - rc = tcm825x_write_reg(client, reg, val); - if (rc) - return rc; - - return 0; -} - -#define tcm825x_write_reg_mask(client, regmask, val) \ - __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \ - TCM825X_MASK((regmask))) - - -/* - * Initialize a list of TCM825X registers. - * The list of registers is terminated by the pair of values - * { TCM825X_REG_TERM, TCM825X_VAL_TERM }. - * Returns zero if successful, or non-zero otherwise. - */ -static int tcm825x_write_default_regs(struct i2c_client *client, - const struct tcm825x_reg *reglist) -{ - int err; - const struct tcm825x_reg *next = reglist; - - while (!((next->reg == TCM825X_REG_TERM) - && (next->val == TCM825X_VAL_TERM))) { - err = tcm825x_write_reg(client, next->reg, next->val); - if (err) { - dev_err(&client->dev, "register writing failed\n"); - return err; - } - next++; - } - - return 0; -} - -static struct vcontrol *find_vctrl(int id) -{ - int i; - - if (id < V4L2_CID_BASE) - return NULL; - - for (i = 0; i < ARRAY_SIZE(video_control); i++) - if (video_control[i].qc.id == id) - return &video_control[i]; - - return NULL; -} - -/* - * Find the best match for a requested image capture size. The best match - * is chosen as the nearest match that has the same number or fewer pixels - * as the requested size, or the smallest image size if the requested size - * has fewer pixels than the smallest image. - */ -static enum image_size tcm825x_find_size(struct v4l2_int_device *s, - unsigned int width, - unsigned int height) -{ - enum image_size isize; - unsigned long pixels = width * height; - struct tcm825x_sensor *sensor = s->priv; - - for (isize = subQCIF; isize < VGA; isize++) { - if (tcm825x_sizes[isize + 1].height - * tcm825x_sizes[isize + 1].width > pixels) { - dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize); - - return isize; - } - } - - dev_dbg(&sensor->i2c_client->dev, "format default VGA\n"); - - return VGA; -} - -/* - * Configure the TCM825X for current image size, pixel format, and - * frame period. fper is the frame period (in seconds) expressed as a - * fraction. Returns zero if successful, or non-zero otherwise. The - * actual frame period is returned in fper. - */ -static int tcm825x_configure(struct v4l2_int_device *s) -{ - struct tcm825x_sensor *sensor = s->priv; - struct v4l2_pix_format *pix = &sensor->pix; - enum image_size isize = tcm825x_find_size(s, pix->width, pix->height); - struct v4l2_fract *fper = &sensor->timeperframe; - enum pixel_format pfmt; - int err; - u32 tgt_fps; - u8 val; - - /* common register initialization */ - err = tcm825x_write_default_regs( - sensor->i2c_client, sensor->platform_data->default_regs()); - if (err) - return err; - - /* configure image size */ - val = tcm825x_siz_reg[isize]->val; - dev_dbg(&sensor->i2c_client->dev, - "configuring image size %d\n", isize); - err = tcm825x_write_reg_mask(sensor->i2c_client, - tcm825x_siz_reg[isize]->reg, val); - if (err) - return err; - - /* configure pixel format */ - switch (pix->pixelformat) { - default: - case V4L2_PIX_FMT_RGB565: - pfmt = RGB565; - break; - case V4L2_PIX_FMT_UYVY: - pfmt = YUV422; - break; - } - - dev_dbg(&sensor->i2c_client->dev, - "configuring pixel format %d\n", pfmt); - val = tcm825x_fmt_reg[pfmt]->val; - - err = tcm825x_write_reg_mask(sensor->i2c_client, - tcm825x_fmt_reg[pfmt]->reg, val); - if (err) - return err; - - /* - * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be - * set. Frame rate will be halved from the normal. - */ - tgt_fps = fper->denominator / fper->numerator; - if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) { - val = tcm825x_read_reg(sensor->i2c_client, 0x02); - val |= 0x80; - tcm825x_write_reg(sensor->i2c_client, 0x02, val); - } - - return 0; -} - -static int ioctl_queryctrl(struct v4l2_int_device *s, - struct v4l2_queryctrl *qc) -{ - struct vcontrol *control; - - control = find_vctrl(qc->id); - - if (control == NULL) - return -EINVAL; - - *qc = control->qc; - - return 0; -} - -static int ioctl_g_ctrl(struct v4l2_int_device *s, - struct v4l2_control *vc) -{ - struct tcm825x_sensor *sensor = s->priv; - struct i2c_client *client = sensor->i2c_client; - int val, r; - struct vcontrol *lvc; - - /* exposure time is special, spread accross 2 registers */ - if (vc->id == V4L2_CID_EXPOSURE) { - int val_lower, val_upper; - - val_upper = tcm825x_read_reg(client, - TCM825X_ADDR(TCM825X_ESRSPD_U)); - if (val_upper < 0) - return val_upper; - val_lower = tcm825x_read_reg(client, - TCM825X_ADDR(TCM825X_ESRSPD_L)); - if (val_lower < 0) - return val_lower; - - vc->value = ((val_upper & 0x1f) << 8) | (val_lower); - return 0; - } - - lvc = find_vctrl(vc->id); - if (lvc == NULL) - return -EINVAL; - - r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg)); - if (r < 0) - return r; - val = r & TCM825X_MASK(lvc->reg); - val >>= lvc->start_bit; - - if (val < 0) - return val; - - if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP) - val ^= sensor->platform_data->is_upside_down(); - - vc->value = val; - return 0; -} - -static int ioctl_s_ctrl(struct v4l2_int_device *s, - struct v4l2_control *vc) -{ - struct tcm825x_sensor *sensor = s->priv; - struct i2c_client *client = sensor->i2c_client; - struct vcontrol *lvc; - int val = vc->value; - - /* exposure time is special, spread accross 2 registers */ - if (vc->id == V4L2_CID_EXPOSURE) { - int val_lower, val_upper; - val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L); - val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U); - - if (tcm825x_write_reg_mask(client, - TCM825X_ESRSPD_U, val_upper)) - return -EIO; - - if (tcm825x_write_reg_mask(client, - TCM825X_ESRSPD_L, val_lower)) - return -EIO; - - return 0; - } - - lvc = find_vctrl(vc->id); - if (lvc == NULL) - return -EINVAL; - - if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP) - val ^= sensor->platform_data->is_upside_down(); - - val = val << lvc->start_bit; - if (tcm825x_write_reg_mask(client, lvc->reg, val)) - return -EIO; - - return 0; -} - -static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, - struct v4l2_fmtdesc *fmt) -{ - int index = fmt->index; - - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (index >= TCM825X_NUM_CAPTURE_FORMATS) - return -EINVAL; - break; - - default: - return -EINVAL; - } - - fmt->flags = tcm825x_formats[index].flags; - strlcpy(fmt->description, tcm825x_formats[index].description, - sizeof(fmt->description)); - fmt->pixelformat = tcm825x_formats[index].pixelformat; - - return 0; -} - -static int ioctl_try_fmt_cap(struct v4l2_int_device *s, - struct v4l2_format *f) -{ - struct tcm825x_sensor *sensor = s->priv; - enum image_size isize; - int ifmt; - struct v4l2_pix_format *pix = &f->fmt.pix; - - isize = tcm825x_find_size(s, pix->width, pix->height); - dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n", - isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS); - - pix->width = tcm825x_sizes[isize].width; - pix->height = tcm825x_sizes[isize].height; - - for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++) - if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat) - break; - - if (ifmt == TCM825X_NUM_CAPTURE_FORMATS) - ifmt = 0; /* Default = YUV 4:2:2 */ - - pix->pixelformat = tcm825x_formats[ifmt].pixelformat; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL; - pix->sizeimage = pix->bytesperline * pix->height; - pix->priv = 0; - dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n", - pix->pixelformat); - - switch (pix->pixelformat) { - case V4L2_PIX_FMT_UYVY: - default: - pix->colorspace = V4L2_COLORSPACE_JPEG; - break; - case V4L2_PIX_FMT_RGB565: - pix->colorspace = V4L2_COLORSPACE_SRGB; - break; - } - - return 0; -} - -static int ioctl_s_fmt_cap(struct v4l2_int_device *s, - struct v4l2_format *f) -{ - struct tcm825x_sensor *sensor = s->priv; - struct v4l2_pix_format *pix = &f->fmt.pix; - int rval; - - rval = ioctl_try_fmt_cap(s, f); - if (rval) - return rval; - - rval = tcm825x_configure(s); - - sensor->pix = *pix; - - return rval; -} - -static int ioctl_g_fmt_cap(struct v4l2_int_device *s, - struct v4l2_format *f) -{ - struct tcm825x_sensor *sensor = s->priv; - - f->fmt.pix = sensor->pix; - - return 0; -} - -static int ioctl_g_parm(struct v4l2_int_device *s, - struct v4l2_streamparm *a) -{ - struct tcm825x_sensor *sensor = s->priv; - struct v4l2_captureparm *cparm = &a->parm.capture; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(a, 0, sizeof(*a)); - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - cparm->capability = V4L2_CAP_TIMEPERFRAME; - cparm->timeperframe = sensor->timeperframe; - - return 0; -} - -static int ioctl_s_parm(struct v4l2_int_device *s, - struct v4l2_streamparm *a) -{ - struct tcm825x_sensor *sensor = s->priv; - struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; - u32 tgt_fps; /* target frames per secound */ - int rval; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if ((timeperframe->numerator == 0) - || (timeperframe->denominator == 0)) { - timeperframe->denominator = DEFAULT_FPS; - timeperframe->numerator = 1; - } - - tgt_fps = timeperframe->denominator / timeperframe->numerator; - - if (tgt_fps > MAX_FPS) { - timeperframe->denominator = MAX_FPS; - timeperframe->numerator = 1; - } else if (tgt_fps < MIN_FPS) { - timeperframe->denominator = MIN_FPS; - timeperframe->numerator = 1; - } - - sensor->timeperframe = *timeperframe; - - rval = tcm825x_configure(s); - - return rval; -} - -static int ioctl_s_power(struct v4l2_int_device *s, int on) -{ - struct tcm825x_sensor *sensor = s->priv; - - return sensor->platform_data->power_set(on); -} - -/* - * Given the image capture format in pix, the nominal frame period in - * timeperframe, calculate the required xclk frequency. - * - * TCM825X input frequency characteristics are: - * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz - */ - -static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) -{ - struct tcm825x_sensor *sensor = s->priv; - struct v4l2_fract *timeperframe = &sensor->timeperframe; - u32 tgt_xclk; /* target xclk */ - u32 tgt_fps; /* target frames per secound */ - int rval; - - rval = sensor->platform_data->ifparm(p); - if (rval) - return rval; - - tgt_fps = timeperframe->denominator / timeperframe->numerator; - - tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? - (2457 * tgt_fps) / MAX_HALF_FPS : - (2457 * tgt_fps) / MAX_FPS; - tgt_xclk *= 10000; - - tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX); - tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN); - - p->u.bt656.clock_curr = tgt_xclk; - - return 0; -} - -static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf) -{ - struct tcm825x_sensor *sensor = s->priv; - - return sensor->platform_data->needs_reset(s, buf, &sensor->pix); -} - -static int ioctl_reset(struct v4l2_int_device *s) -{ - return -EBUSY; -} - -static int ioctl_init(struct v4l2_int_device *s) -{ - return tcm825x_configure(s); -} - -static int ioctl_dev_exit(struct v4l2_int_device *s) -{ - return 0; -} - -static int ioctl_dev_init(struct v4l2_int_device *s) -{ - struct tcm825x_sensor *sensor = s->priv; - int r; - - r = tcm825x_read_reg(sensor->i2c_client, 0x01); - if (r < 0) - return r; - if (r == 0) { - dev_err(&sensor->i2c_client->dev, "device not detected\n"); - return -EIO; - } - return 0; -} - -static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = { - { vidioc_int_dev_init_num, - (v4l2_int_ioctl_func *)ioctl_dev_init }, - { vidioc_int_dev_exit_num, - (v4l2_int_ioctl_func *)ioctl_dev_exit }, - { vidioc_int_s_power_num, - (v4l2_int_ioctl_func *)ioctl_s_power }, - { vidioc_int_g_ifparm_num, - (v4l2_int_ioctl_func *)ioctl_g_ifparm }, - { vidioc_int_g_needs_reset_num, - (v4l2_int_ioctl_func *)ioctl_g_needs_reset }, - { vidioc_int_reset_num, - (v4l2_int_ioctl_func *)ioctl_reset }, - { vidioc_int_init_num, - (v4l2_int_ioctl_func *)ioctl_init }, - { vidioc_int_enum_fmt_cap_num, - (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, - { vidioc_int_try_fmt_cap_num, - (v4l2_int_ioctl_func *)ioctl_try_fmt_cap }, - { vidioc_int_g_fmt_cap_num, - (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, - { vidioc_int_s_fmt_cap_num, - (v4l2_int_ioctl_func *)ioctl_s_fmt_cap }, - { vidioc_int_g_parm_num, - (v4l2_int_ioctl_func *)ioctl_g_parm }, - { vidioc_int_s_parm_num, - (v4l2_int_ioctl_func *)ioctl_s_parm }, - { vidioc_int_queryctrl_num, - (v4l2_int_ioctl_func *)ioctl_queryctrl }, - { vidioc_int_g_ctrl_num, - (v4l2_int_ioctl_func *)ioctl_g_ctrl }, - { vidioc_int_s_ctrl_num, - (v4l2_int_ioctl_func *)ioctl_s_ctrl }, -}; - -static struct v4l2_int_slave tcm825x_slave = { - .ioctls = tcm825x_ioctl_desc, - .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc), -}; - -static struct tcm825x_sensor tcm825x; - -static struct v4l2_int_device tcm825x_int_device = { - .module = THIS_MODULE, - .name = TCM825X_NAME, - .priv = &tcm825x, - .type = v4l2_int_type_slave, - .u = { - .slave = &tcm825x_slave, - }, -}; - -static int tcm825x_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct tcm825x_sensor *sensor = &tcm825x; - - if (i2c_get_clientdata(client)) - return -EBUSY; - - sensor->platform_data = client->dev.platform_data; - - if (sensor->platform_data == NULL - || !sensor->platform_data->is_okay()) - return -ENODEV; - - sensor->v4l2_int_device = &tcm825x_int_device; - - sensor->i2c_client = client; - i2c_set_clientdata(client, sensor); - - /* Make the default capture format QVGA RGB565 */ - sensor->pix.width = tcm825x_sizes[QVGA].width; - sensor->pix.height = tcm825x_sizes[QVGA].height; - sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565; - - return v4l2_int_device_register(sensor->v4l2_int_device); -} - -static int tcm825x_remove(struct i2c_client *client) -{ - struct tcm825x_sensor *sensor = i2c_get_clientdata(client); - - if (!client->adapter) - return -ENODEV; /* our client isn't attached */ - - v4l2_int_device_unregister(sensor->v4l2_int_device); - - return 0; -} - -static const struct i2c_device_id tcm825x_id[] = { - { "tcm825x", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tcm825x_id); - -static struct i2c_driver tcm825x_i2c_driver = { - .driver = { - .name = TCM825X_NAME, - }, - .probe = tcm825x_probe, - .remove = tcm825x_remove, - .id_table = tcm825x_id, -}; - -static struct tcm825x_sensor tcm825x = { - .timeperframe = { - .numerator = 1, - .denominator = DEFAULT_FPS, - }, -}; - -static int __init tcm825x_init(void) -{ - int rval; - - rval = i2c_add_driver(&tcm825x_i2c_driver); - if (rval) - printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n", - __func__); - - return rval; -} - -static void __exit tcm825x_exit(void) -{ - i2c_del_driver(&tcm825x_i2c_driver); -} - -/* - * FIXME: Menelaus isn't ready (?) at module_init stage, so use - * late_initcall for now. - */ -late_initcall(tcm825x_init); -module_exit(tcm825x_exit); - -MODULE_AUTHOR("Sakari Ailus "); -MODULE_DESCRIPTION("TCM825x camera sensor driver"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tcm825x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tcm825x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tcm825x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tcm825x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,200 +0,0 @@ -/* - * drivers/media/video/tcm825x.h - * - * Register definitions for the TCM825X CameraChip. - * - * Author: David Cohen (david.cohen@indt.org.br) - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - * This file was based on ov9640.h from MontaVista - */ - -#ifndef TCM825X_H -#define TCM825X_H - -#include - -#include - -#define TCM825X_NAME "tcm825x" - -#define TCM825X_MASK(x) x & 0x00ff -#define TCM825X_ADDR(x) (x & 0xff00) >> 8 - -/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */ -#define TCM825X_I2C_ADDR 0x3d - -/* - * define register offsets for the TCM825X sensor chip - * OFFSET(8 bits) + MASK(8 bits) - * MASK bit 4 and 3 are used when the register uses more than one address - */ -#define TCM825X_FPS 0x0280 -#define TCM825X_ACF 0x0240 -#define TCM825X_DOUTBUF 0x020C -#define TCM825X_DCLKP 0x0202 -#define TCM825X_ACFDET 0x0201 -#define TCM825X_DOUTSW 0x0380 -#define TCM825X_DATAHZ 0x0340 -#define TCM825X_PICSIZ 0x033c -#define TCM825X_PICFMT 0x0302 -#define TCM825X_V_INV 0x0480 -#define TCM825X_H_INV 0x0440 -#define TCM825X_ESRLSW 0x0430 -#define TCM825X_V_LENGTH 0x040F -#define TCM825X_ALCSW 0x0580 -#define TCM825X_ESRLIM 0x0560 -#define TCM825X_ESRSPD_U 0x051F -#define TCM825X_ESRSPD_L 0x06FF -#define TCM825X_AG 0x07FF -#define TCM825X_ESRSPD2 0x06FF -#define TCM825X_ALCMODE 0x0830 -#define TCM825X_ALCH 0x080F -#define TCM825X_ALCL 0x09FF -#define TCM825X_AWBSW 0x0A80 -#define TCM825X_MRG 0x0BFF -#define TCM825X_MBG 0x0CFF -#define TCM825X_GAMSW 0x0D80 -#define TCM825X_HDTG 0x0EFF -#define TCM825X_VDTG 0x0FFF -#define TCM825X_HDTCORE 0x10F0 -#define TCM825X_VDTCORE 0x100F -#define TCM825X_CONT 0x11FF -#define TCM825X_BRIGHT 0x12FF -#define TCM825X_VHUE 0x137F -#define TCM825X_UHUE 0x147F -#define TCM825X_VGAIN 0x153F -#define TCM825X_UGAIN 0x163F -#define TCM825X_UVCORE 0x170F -#define TCM825X_SATU 0x187F -#define TCM825X_MHMODE 0x1980 -#define TCM825X_MHLPFSEL 0x1940 -#define TCM825X_YMODE 0x1930 -#define TCM825X_MIXHG 0x1907 -#define TCM825X_LENS 0x1A3F -#define TCM825X_AGLIM 0x1BE0 -#define TCM825X_LENSRPOL 0x1B10 -#define TCM825X_LENSRGAIN 0x1B0F -#define TCM825X_ES100S 0x1CFF -#define TCM825X_ES120S 0x1DFF -#define TCM825X_DMASK 0x1EC0 -#define TCM825X_CODESW 0x1E20 -#define TCM825X_CODESEL 0x1E10 -#define TCM825X_TESPIC 0x1E04 -#define TCM825X_PICSEL 0x1E03 -#define TCM825X_HNUM 0x20FF -#define TCM825X_VOUTPH 0x287F -#define TCM825X_ESROUT 0x327F -#define TCM825X_ESROUT2 0x33FF -#define TCM825X_AGOUT 0x34FF -#define TCM825X_DGOUT 0x353F -#define TCM825X_AGSLOW1 0x39C0 -#define TCM825X_FLLSMODE 0x3930 -#define TCM825X_FLLSLIM 0x390F -#define TCM825X_DETSEL 0x3AF0 -#define TCM825X_ACDETNC 0x3A0F -#define TCM825X_AGSLOW2 0x3BC0 -#define TCM825X_DG 0x3B3F -#define TCM825X_REJHLEV 0x3CFF -#define TCM825X_ALCLOCK 0x3D80 -#define TCM825X_FPSLNKSW 0x3D40 -#define TCM825X_ALCSPD 0x3D30 -#define TCM825X_REJH 0x3D03 -#define TCM825X_SHESRSW 0x3E80 -#define TCM825X_ESLIMSEL 0x3E40 -#define TCM825X_SHESRSPD 0x3E30 -#define TCM825X_ELSTEP 0x3E0C -#define TCM825X_ELSTART 0x3E03 -#define TCM825X_AGMIN 0x3FFF -#define TCM825X_PREGRG 0x423F -#define TCM825X_PREGBG 0x433F -#define TCM825X_PRERG 0x443F -#define TCM825X_PREBG 0x453F -#define TCM825X_MSKBR 0x477F -#define TCM825X_MSKGR 0x487F -#define TCM825X_MSKRB 0x497F -#define TCM825X_MSKGB 0x4A7F -#define TCM825X_MSKRG 0x4B7F -#define TCM825X_MSKBG 0x4C7F -#define TCM825X_HDTCSW 0x4D80 -#define TCM825X_VDTCSW 0x4D40 -#define TCM825X_DTCYL 0x4D3F -#define TCM825X_HDTPSW 0x4E80 -#define TCM825X_VDTPSW 0x4E40 -#define TCM825X_DTCGAIN 0x4E3F -#define TCM825X_DTLLIMSW 0x4F10 -#define TCM825X_DTLYLIM 0x4F0F -#define TCM825X_YLCUTLMSK 0x5080 -#define TCM825X_YLCUTL 0x503F -#define TCM825X_YLCUTHMSK 0x5180 -#define TCM825X_YLCUTH 0x513F -#define TCM825X_UVSKNC 0x527F -#define TCM825X_UVLJ 0x537F -#define TCM825X_WBGMIN 0x54FF -#define TCM825X_WBGMAX 0x55FF -#define TCM825X_WBSPDUP 0x5603 -#define TCM825X_ALLAREA 0x5820 -#define TCM825X_WBLOCK 0x5810 -#define TCM825X_WB2SP 0x580F -#define TCM825X_KIZUSW 0x5920 -#define TCM825X_PBRSW 0x5910 -#define TCM825X_ABCSW 0x5903 -#define TCM825X_PBDLV 0x5AFF -#define TCM825X_PBC1LV 0x5BFF - -#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1) - -#define TCM825X_BYTES_PER_PIXEL 2 - -#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */ -#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */ - -/* define a structure for tcm825x register initialization values */ -struct tcm825x_reg { - u8 val; - u16 reg; -}; - -enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA }; -enum pixel_format { YUV422 = 0, RGB565 }; -#define NUM_IMAGE_SIZES 6 -#define NUM_PIXEL_FORMATS 2 - -#define TCM825X_XCLK_MIN 11900000 -#define TCM825X_XCLK_MAX 25000000 - -struct capture_size { - unsigned long width; - unsigned long height; -}; - -struct tcm825x_platform_data { - /* Is the sensor usable? Doesn't yet mean it's there, but you - * can try! */ - int (*is_okay)(void); - /* Set power state, zero is off, non-zero is on. */ - int (*power_set)(int power); - /* Default registers written after power-on or reset. */ - const struct tcm825x_reg *(*default_regs)(void); - int (*needs_reset)(struct v4l2_int_device *s, void *buf, - struct v4l2_pix_format *fmt); - int (*ifparm)(struct v4l2_ifparm *p); - int (*is_upside_down)(void); -}; - -/* Array of image sizes supported by TCM825X. These must be ordered from - * smallest image size to largest. - */ -static const struct capture_size tcm825x_sizes[] = { - { 128, 96 }, /* subQCIF */ - { 160, 120 }, /* QQVGA */ - { 176, 144 }, /* QCIF */ - { 320, 240 }, /* QVGA */ - { 352, 288 }, /* CIF */ - { 640, 480 }, /* VGA */ -}; - -#endif /* ifndef TCM825X_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tda7432.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tda7432.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tda7432.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tda7432.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,495 +0,0 @@ -/* - * For the STS-Thompson TDA7432 audio processor chip - * - * Handles audio functions: volume, balance, tone, loudness - * This driver will not complain if used with any - * other i2c device with the same address. - * - * Muting and tone control by Jonathan Isom - * - * Copyright (c) 2000 Eric Sandeen - * Copyright (c) 2006 Mauro Carvalho Chehab - * This code is placed under the terms of the GNU General Public License - * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) - * Which was based on tda8425.c by Greg Alexander (c) 1998 - * - * OPTIONS: - * debug - set to 1 if you'd like to see debug messages - * set to 2 if you'd like to be inundated with debug messages - * - * loudness - set between 0 and 15 for varying degrees of loudness effect - * - * maxvol - set maximium volume to +20db (1), default is 0db(0) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifndef VIDEO_AUDIO_BALANCE -# define VIDEO_AUDIO_BALANCE 32 -#endif - -MODULE_AUTHOR("Eric Sandeen "); -MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip"); -MODULE_LICENSE("GPL"); - -static int maxvol; -static int loudness; /* disable loudness by default */ -static int debug; /* insmod parameter */ -module_param(debug, int, S_IRUGO | S_IWUSR); -module_param(loudness, int, S_IRUGO); -MODULE_PARM_DESC(maxvol,"Set maximium volume to +20db (0), default is 0db(1)"); -module_param(maxvol, int, S_IRUGO | S_IWUSR); - - - -/* Structure of address and subaddresses for the tda7432 */ - -struct tda7432 { - struct v4l2_subdev sd; - int addr; - int input; - int volume; - int muted; - int bass, treble; - int lf, lr, rf, rr; - int loud; -}; - -static inline struct tda7432 *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct tda7432, sd); -} - -/* The TDA7432 is made by STS-Thompson - * http://www.st.com - * http://us.st.com/stonline/books/pdf/docs/4056.pdf - * - * TDA7432: I2C-bus controlled basic audio processor - * - * The TDA7432 controls basic audio functions like volume, balance, - * and tone control (including loudness). It also has four channel - * output (for front and rear). Since most vidcap cards probably - * don't have 4 channel output, this driver will set front & rear - * together (no independent control). - */ - - /* Subaddresses for TDA7432 */ - -#define TDA7432_IN 0x00 /* Input select */ -#define TDA7432_VL 0x01 /* Volume */ -#define TDA7432_TN 0x02 /* Bass, Treble (Tone) */ -#define TDA7432_LF 0x03 /* Attenuation LF (Left Front) */ -#define TDA7432_LR 0x04 /* Attenuation LR (Left Rear) */ -#define TDA7432_RF 0x05 /* Attenuation RF (Right Front) */ -#define TDA7432_RR 0x06 /* Attenuation RR (Right Rear) */ -#define TDA7432_LD 0x07 /* Loudness */ - - - /* Masks for bits in TDA7432 subaddresses */ - -/* Many of these not used - just for documentation */ - -/* Subaddress 0x00 - Input selection and bass control */ - -/* Bits 0,1,2 control input: - * 0x00 - Stereo input - * 0x02 - Mono input - * 0x03 - Mute (Using Attenuators Plays better with modules) - * Mono probably isn't used - I'm guessing only the stereo - * input is connected on most cards, so we'll set it to stereo. - * - * Bit 3 controls bass cut: 0/1 is non-symmetric/symmetric bass cut - * Bit 4 controls bass range: 0/1 is extended/standard bass range - * - * Highest 3 bits not used - */ - -#define TDA7432_STEREO_IN 0 -#define TDA7432_MONO_IN 2 /* Probably won't be used */ -#define TDA7432_BASS_SYM 1 << 3 -#define TDA7432_BASS_NORM 1 << 4 - -/* Subaddress 0x01 - Volume */ - -/* Lower 7 bits control volume from -79dB to +32dB in 1dB steps - * Recommended maximum is +20 dB - * - * +32dB: 0x00 - * +20dB: 0x0c - * 0dB: 0x20 - * -79dB: 0x6f - * - * MSB (bit 7) controls loudness: 1/0 is loudness on/off - */ - -#define TDA7432_VOL_0DB 0x20 -#define TDA7432_LD_ON 1 << 7 - - -/* Subaddress 0x02 - Tone control */ - -/* Bits 0,1,2 control absolute treble gain from 0dB to 14dB - * 0x0 is 14dB, 0x7 is 0dB - * - * Bit 3 controls treble attenuation/gain (sign) - * 1 = gain (+) - * 0 = attenuation (-) - * - * Bits 4,5,6 control absolute bass gain from 0dB to 14dB - * (This is only true for normal base range, set in 0x00) - * 0x0 << 4 is 14dB, 0x7 is 0dB - * - * Bit 7 controls bass attenuation/gain (sign) - * 1 << 7 = gain (+) - * 0 << 7 = attenuation (-) - * - * Example: - * 1 1 0 1 0 1 0 1 is +4dB bass, -4dB treble - */ - -#define TDA7432_TREBLE_0DB 0xf -#define TDA7432_TREBLE 7 -#define TDA7432_TREBLE_GAIN 1 << 3 -#define TDA7432_BASS_0DB 0xf -#define TDA7432_BASS 7 << 4 -#define TDA7432_BASS_GAIN 1 << 7 - - -/* Subaddress 0x03 - Left Front attenuation */ -/* Subaddress 0x04 - Left Rear attenuation */ -/* Subaddress 0x05 - Right Front attenuation */ -/* Subaddress 0x06 - Right Rear attenuation */ - -/* Bits 0,1,2,3,4 control attenuation from 0dB to -37.5dB - * in 1.5dB steps. - * - * 0x00 is 0dB - * 0x1f is -37.5dB - * - * Bit 5 mutes that channel when set (1 = mute, 0 = unmute) - * We'll use the mute on the input, though (above) - * Bits 6,7 unused - */ - -#define TDA7432_ATTEN_0DB 0x00 -#define TDA7432_MUTE 0x1 << 5 - - -/* Subaddress 0x07 - Loudness Control */ - -/* Bits 0,1,2,3 control loudness from 0dB to -15dB in 1dB steps - * when bit 4 is NOT set - * - * 0x0 is 0dB - * 0xf is -15dB - * - * If bit 4 is set, then there is a flat attenuation according to - * the lower 4 bits, as above. - * - * Bits 5,6,7 unused - */ - - - -/* Begin code */ - -static int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned char buffer[2]; - - v4l2_dbg(2, debug, sd, "In tda7432_write\n"); - v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val); - buffer[0] = subaddr; - buffer[1] = val; - if (2 != i2c_master_send(client, buffer, 2)) { - v4l2_err(sd, "I/O error, trying (write %d 0x%x)\n", - subaddr, val); - return -1; - } - return 0; -} - -static int tda7432_set(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tda7432 *t = to_state(sd); - unsigned char buf[16]; - - v4l2_dbg(1, debug, sd, - "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", - t->input, t->volume, t->bass, t->treble, t->lf, t->lr, - t->rf, t->rr, t->loud); - buf[0] = TDA7432_IN; - buf[1] = t->input; - buf[2] = t->volume; - buf[3] = t->bass; - buf[4] = t->treble; - buf[5] = t->lf; - buf[6] = t->lr; - buf[7] = t->rf; - buf[8] = t->rr; - buf[9] = t->loud; - if (10 != i2c_master_send(client, buf, 10)) { - v4l2_err(sd, "I/O error, trying tda7432_set\n"); - return -1; - } - - return 0; -} - -static void do_tda7432_init(struct v4l2_subdev *sd) -{ - struct tda7432 *t = to_state(sd); - - v4l2_dbg(2, debug, sd, "In tda7432_init\n"); - - t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ - TDA7432_BASS_SYM | /* Symmetric bass cut */ - TDA7432_BASS_NORM; /* Normal bass range */ - t->volume = 0x3b ; /* -27dB Volume */ - if (loudness) /* Turn loudness on? */ - t->volume |= TDA7432_LD_ON; - t->muted = 1; - t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ - t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ - t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->loud = loudness; /* insmod parameter */ - - tda7432_set(sd); -} - -static int tda7432_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct tda7432 *t = to_state(sd); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value=t->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (!maxvol){ /* max +20db */ - ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630; - } else { /* max 0db */ - ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829; - } - return 0; - case V4L2_CID_AUDIO_BALANCE: - { - if ( (t->lf) < (t->rf) ) - /* right is attenuated, balance shifted left */ - ctrl->value = (32768 - 1057*(t->rf)); - else - /* left is attenuated, balance shifted right */ - ctrl->value = (32768 + 1057*(t->lf)); - return 0; - } - case V4L2_CID_AUDIO_BASS: - { - /* Bass/treble 4 bits each */ - int bass=t->bass; - if(bass >= 0x8) - bass = ~(bass - 0x8) & 0xf; - ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass); - return 0; - } - case V4L2_CID_AUDIO_TREBLE: - { - int treble=t->treble; - if(treble >= 0x8) - treble = ~(treble - 0x8) & 0xf; - ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble); - return 0; - } - } - return -EINVAL; -} - -static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct tda7432 *t = to_state(sd); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - t->muted=ctrl->value; - break; - case V4L2_CID_AUDIO_VOLUME: - if(!maxvol){ /* max +20db */ - t->volume = 0x6f - ((ctrl->value)/630); - } else { /* max 0db */ - t->volume = 0x6f - ((ctrl->value)/829); - } - if (loudness) /* Turn on the loudness bit */ - t->volume |= TDA7432_LD_ON; - - tda7432_write(sd, TDA7432_VL, t->volume); - return 0; - case V4L2_CID_AUDIO_BALANCE: - if (ctrl->value < 32768) { - /* shifted to left, attenuate right */ - t->rr = (32768 - ctrl->value)/1057; - t->rf = t->rr; - t->lr = TDA7432_ATTEN_0DB; - t->lf = TDA7432_ATTEN_0DB; - } else if(ctrl->value > 32769) { - /* shifted to right, attenuate left */ - t->lf = (ctrl->value - 32768)/1057; - t->lr = t->lf; - t->rr = TDA7432_ATTEN_0DB; - t->rf = TDA7432_ATTEN_0DB; - } else { - /* centered */ - t->rr = TDA7432_ATTEN_0DB; - t->rf = TDA7432_ATTEN_0DB; - t->lf = TDA7432_ATTEN_0DB; - t->lr = TDA7432_ATTEN_0DB; - } - break; - case V4L2_CID_AUDIO_BASS: - t->bass = ctrl->value >> 12; - if(t->bass>= 0x8) - t->bass = (~t->bass & 0xf) + 0x8 ; - - tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble); - return 0; - case V4L2_CID_AUDIO_TREBLE: - t->treble= ctrl->value >> 12; - if(t->treble>= 0x8) - t->treble = (~t->treble & 0xf) + 0x8 ; - - tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble); - return 0; - default: - return -EINVAL; - } - - /* Used for both mute and balance changes */ - if (t->muted) - { - /* Mute & update balance*/ - tda7432_write(sd, TDA7432_LF, t->lf | TDA7432_MUTE); - tda7432_write(sd, TDA7432_LR, t->lr | TDA7432_MUTE); - tda7432_write(sd, TDA7432_RF, t->rf | TDA7432_MUTE); - tda7432_write(sd, TDA7432_RR, t->rr | TDA7432_MUTE); - } else { - tda7432_write(sd, TDA7432_LF, t->lf); - tda7432_write(sd, TDA7432_LR, t->lr); - tda7432_write(sd, TDA7432_RF, t->rf); - tda7432_write(sd, TDA7432_RR, t->rr); - } - return 0; -} - -static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); - } - return -EINVAL; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops tda7432_core_ops = { - .queryctrl = tda7432_queryctrl, - .g_ctrl = tda7432_g_ctrl, - .s_ctrl = tda7432_s_ctrl, -}; - -static const struct v4l2_subdev_ops tda7432_ops = { - .core = &tda7432_core_ops, -}; - -/* ----------------------------------------------------------------------- */ - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda7432_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tda7432 *t; - struct v4l2_subdev *sd; - - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr << 1, client->adapter->name); - - t = kzalloc(sizeof(*t), GFP_KERNEL); - if (!t) - return -ENOMEM; - sd = &t->sd; - v4l2_i2c_subdev_init(sd, client, &tda7432_ops); - if (loudness < 0 || loudness > 15) { - v4l2_warn(sd, "loudness parameter must be between 0 and 15\n"); - if (loudness < 0) - loudness = 0; - if (loudness > 15) - loudness = 15; - } - - do_tda7432_init(sd); - return 0; -} - -static int tda7432_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - do_tda7432_init(sd); - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id tda7432_id[] = { - { "tda7432", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tda7432_id); - -static struct i2c_driver tda7432_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tda7432", - }, - .probe = tda7432_probe, - .remove = tda7432_remove, - .id_table = tda7432_id, -}; - -static __init int init_tda7432(void) -{ - return i2c_add_driver(&tda7432_driver); -} - -static __exit void exit_tda7432(void) -{ - i2c_del_driver(&tda7432_driver); -} - -module_init(init_tda7432); -module_exit(exit_tda7432); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tda9840.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tda9840.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tda9840.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tda9840.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,222 +0,0 @@ - /* - tda9840 - i2c-driver for the tda9840 by SGS Thomson - - Copyright (C) 1998-2003 Michael Hunold - Copyright (C) 2008 Hans Verkuil - - The tda9840 is a stereo/dual sound processor with digital - identification. It can be found at address 0x84 on the i2c-bus. - - For detailed informations download the specifications directly - from SGS Thomson at http://www.st.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Michael Hunold "); -MODULE_DESCRIPTION("tda9840 driver"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0644); - -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -#define SWITCH 0x00 -#define LEVEL_ADJUST 0x02 -#define STEREO_ADJUST 0x03 -#define TEST 0x04 - -#define TDA9840_SET_MUTE 0x00 -#define TDA9840_SET_MONO 0x10 -#define TDA9840_SET_STEREO 0x2a -#define TDA9840_SET_LANG1 0x12 -#define TDA9840_SET_LANG2 0x1e -#define TDA9840_SET_BOTH 0x1a -#define TDA9840_SET_BOTH_R 0x16 -#define TDA9840_SET_EXTERNAL 0x7a - - -static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (i2c_smbus_write_byte_data(client, reg, val)) - v4l2_dbg(1, debug, sd, "error writing %02x to %02x\n", - val, reg); -} - -static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t) -{ - int byte; - - if (t->index) - return -EINVAL; - - switch (t->audmode) { - case V4L2_TUNER_MODE_STEREO: - byte = TDA9840_SET_STEREO; - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - byte = TDA9840_SET_BOTH; - break; - case V4L2_TUNER_MODE_LANG1: - byte = TDA9840_SET_LANG1; - break; - case V4L2_TUNER_MODE_LANG2: - byte = TDA9840_SET_LANG2; - break; - default: - byte = TDA9840_SET_MONO; - break; - } - v4l2_dbg(1, debug, sd, "TDA9840_SWITCH: 0x%02x\n", byte); - tda9840_write(sd, SWITCH, byte); - return 0; -} - -static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 byte; - - t->rxsubchans = V4L2_TUNER_SUB_MONO; - if (1 != i2c_master_recv(client, &byte, 1)) { - v4l2_dbg(1, debug, sd, - "i2c_master_recv() failed\n"); - return -EIO; - } - - if (byte & 0x80) { - v4l2_dbg(1, debug, sd, - "TDA9840_DETECT: register contents invalid\n"); - return -EINVAL; - } - - v4l2_dbg(1, debug, sd, "TDA9840_DETECT: byte: 0x%02x\n", byte); - - switch (byte & 0x60) { - case 0x00: - t->rxsubchans = V4L2_TUNER_SUB_MONO; - break; - case 0x20: - t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - break; - case 0x40: - t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; - break; - default: /* Incorrect detect */ - t->rxsubchans = V4L2_TUNER_MODE_MONO; - break; - } - return 0; -} - -static int tda9840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TDA9840, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops tda9840_core_ops = { - .g_chip_ident = tda9840_g_chip_ident, -}; - -static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = { - .s_tuner = tda9840_s_tuner, - .g_tuner = tda9840_g_tuner, -}; - -static const struct v4l2_subdev_ops tda9840_ops = { - .core = &tda9840_core_ops, - .tuner = &tda9840_tuner_ops, -}; - -/* ----------------------------------------------------------------------- */ - -static int tda9840_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct v4l2_subdev *sd; - - /* let's see whether this adapter can support what we need */ - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE_DATA | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); - if (sd == NULL) - return -ENOMEM; - v4l2_i2c_subdev_init(sd, client, &tda9840_ops); - - /* set initial values for level & stereo - adjustment, mode */ - tda9840_write(sd, LEVEL_ADJUST, 0); - tda9840_write(sd, STEREO_ADJUST, 0); - tda9840_write(sd, SWITCH, TDA9840_SET_STEREO); - return 0; -} - -static int tda9840_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(sd); - return 0; -} - -static const struct i2c_device_id tda9840_id[] = { - { "tda9840", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tda9840_id); - -static struct i2c_driver tda9840_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tda9840", - }, - .probe = tda9840_probe, - .remove = tda9840_remove, - .id_table = tda9840_id, -}; - -static __init int init_tda9840(void) -{ - return i2c_add_driver(&tda9840_driver); -} - -static __exit void exit_tda9840(void) -{ - i2c_del_driver(&tda9840_driver); -} - -module_init(init_tda9840); -module_exit(exit_tda9840); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6415c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6415c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6415c.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6415c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,198 +0,0 @@ - /* - tea6415c - i2c-driver for the tea6415c by SGS Thomson - - Copyright (C) 1998-2003 Michael Hunold - Copyright (C) 2008 Hans Verkuil - - The tea6415c is a bus controlled video-matrix-switch - with 8 inputs and 6 outputs. - It is cascadable, i.e. it can be found at the addresses - 0x86 and 0x06 on the i2c-bus. - - For detailed informations download the specifications directly - from SGS Thomson at http://www.st.com - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License vs published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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., 675 Mvss Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include "tea6415c.h" - -MODULE_AUTHOR("Michael Hunold "); -MODULE_DESCRIPTION("tea6415c driver"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0644); - -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -/* makes a connection between the input-pin 'i' and the output-pin 'o' */ -static int tea6415c_s_routing(struct v4l2_subdev *sd, - u32 i, u32 o, u32 config) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 byte = 0; - int ret; - - v4l2_dbg(1, debug, sd, "i=%d, o=%d\n", i, o); - - /* check if the pins are valid */ - if (0 == ((1 == i || 3 == i || 5 == i || 6 == i || 8 == i || 10 == i || 20 == i || 11 == i) - && (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o))) - return -EINVAL; - - /* to understand this, have a look at the tea6415c-specs (p.5) */ - switch (o) { - case 18: - byte = 0x00; - break; - case 14: - byte = 0x20; - break; - case 16: - byte = 0x10; - break; - case 17: - byte = 0x08; - break; - case 15: - byte = 0x18; - break; - case 13: - byte = 0x28; - break; - }; - - switch (i) { - case 5: - byte |= 0x00; - break; - case 8: - byte |= 0x04; - break; - case 3: - byte |= 0x02; - break; - case 20: - byte |= 0x06; - break; - case 6: - byte |= 0x01; - break; - case 10: - byte |= 0x05; - break; - case 1: - byte |= 0x03; - break; - case 11: - byte |= 0x07; - break; - }; - - ret = i2c_smbus_write_byte(client, byte); - if (ret) { - v4l2_dbg(1, debug, sd, - "i2c_smbus_write_byte() failed, ret:%d\n", ret); - return -EIO; - } - return ret; -} - -static int tea6415c_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6415C, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops tea6415c_core_ops = { - .g_chip_ident = tea6415c_g_chip_ident, -}; - -static const struct v4l2_subdev_video_ops tea6415c_video_ops = { - .s_routing = tea6415c_s_routing, -}; - -static const struct v4l2_subdev_ops tea6415c_ops = { - .core = &tea6415c_core_ops, - .video = &tea6415c_video_ops, -}; - -static int tea6415c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct v4l2_subdev *sd; - - /* let's see whether this adapter can support what we need */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); - if (sd == NULL) - return -ENOMEM; - v4l2_i2c_subdev_init(sd, client, &tea6415c_ops); - return 0; -} - -static int tea6415c_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(sd); - return 0; -} - -static const struct i2c_device_id tea6415c_id[] = { - { "tea6415c", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tea6415c_id); - -static struct i2c_driver tea6415c_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tea6415c", - }, - .probe = tea6415c_probe, - .remove = tea6415c_remove, - .id_table = tea6415c_id, -}; - -static __init int init_tea6415c(void) -{ - return i2c_add_driver(&tea6415c_driver); -} - -static __exit void exit_tea6415c(void) -{ - i2c_del_driver(&tea6415c_driver); -} - -module_init(init_tea6415c); -module_exit(exit_tea6415c); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6415c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6415c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6415c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6415c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#ifndef __INCLUDED_TEA6415C__ -#define __INCLUDED_TEA6415C__ - -/* the tea6415c's design is quite brain-dead. although there are - 8 inputs and 6 outputs, these aren't enumerated in any way. because - I don't want to say "connect input pin 20 to output pin 17", I define - a "virtual" pin-order. */ - -/* input pins */ -#define TEA6415C_OUTPUT1 18 -#define TEA6415C_OUTPUT2 14 -#define TEA6415C_OUTPUT3 16 -#define TEA6415C_OUTPUT4 17 -#define TEA6415C_OUTPUT5 13 -#define TEA6415C_OUTPUT6 15 - -/* output pins */ -#define TEA6415C_INPUT1 5 -#define TEA6415C_INPUT2 8 -#define TEA6415C_INPUT3 3 -#define TEA6415C_INPUT4 20 -#define TEA6415C_INPUT5 6 -#define TEA6415C_INPUT6 10 -#define TEA6415C_INPUT7 1 -#define TEA6415C_INPUT8 11 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6420.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6420.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6420.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6420.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,180 +0,0 @@ - /* - tea6420 - i2c-driver for the tea6420 by SGS Thomson - - Copyright (C) 1998-2003 Michael Hunold - Copyright (C) 2008 Hans Verkuil - - The tea6420 is a bus controlled audio-matrix with 5 stereo inputs, - 4 stereo outputs and gain control for each output. - It is cascadable, i.e. it can be found at the addresses 0x98 - and 0x9a on the i2c-bus. - - For detailed informations download the specifications directly - from SGS Thomson at http://www.st.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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include "tea6420.h" - -MODULE_AUTHOR("Michael Hunold "); -MODULE_DESCRIPTION("tea6420 driver"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0644); - -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -/* make a connection between the input 'i' and the output 'o' - with gain 'g' (note: i = 6 means 'mute') */ -static int tea6420_s_routing(struct v4l2_subdev *sd, - u32 i, u32 o, u32 config) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int g = (o >> 4) & 0xf; - u8 byte; - int ret; - - o &= 0xf; - v4l2_dbg(1, debug, sd, "i=%d, o=%d, g=%d\n", i, o, g); - - /* check if the parameters are valid */ - if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0) - return -EINVAL; - - byte = ((o - 1) << 5); - byte |= (i - 1); - - /* to understand this, have a look at the tea6420-specs (p.5) */ - switch (g) { - case 0: - byte |= (3 << 3); - break; - case 2: - byte |= (2 << 3); - break; - case 4: - byte |= (1 << 3); - break; - case 6: - break; - } - - ret = i2c_smbus_write_byte(client, byte); - if (ret) { - v4l2_dbg(1, debug, sd, - "i2c_smbus_write_byte() failed, ret:%d\n", ret); - return -EIO; - } - return 0; -} - -static int tea6420_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6420, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops tea6420_core_ops = { - .g_chip_ident = tea6420_g_chip_ident, -}; - -static const struct v4l2_subdev_audio_ops tea6420_audio_ops = { - .s_routing = tea6420_s_routing, -}; - -static const struct v4l2_subdev_ops tea6420_ops = { - .core = &tea6420_core_ops, - .audio = &tea6420_audio_ops, -}; - -static int tea6420_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct v4l2_subdev *sd; - int err, i; - - /* let's see whether this adapter can support what we need */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); - if (sd == NULL) - return -ENOMEM; - v4l2_i2c_subdev_init(sd, client, &tea6420_ops); - - /* set initial values: set "mute"-input to all outputs at gain 0 */ - err = 0; - for (i = 1; i < 5; i++) - err += tea6420_s_routing(sd, 6, i, 0); - if (err) { - v4l_dbg(1, debug, client, "could not initialize tea6420\n"); - return -ENODEV; - } - return 0; -} - -static int tea6420_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(sd); - return 0; -} - -static const struct i2c_device_id tea6420_id[] = { - { "tea6420", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tea6420_id); - -static struct i2c_driver tea6420_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tea6420", - }, - .probe = tea6420_probe, - .remove = tea6420_remove, - .id_table = tea6420_id, -}; - -static __init int init_tea6420(void) -{ - return i2c_add_driver(&tea6420_driver); -} - -static __exit void exit_tea6420(void) -{ - i2c_del_driver(&tea6420_driver); -} - -module_init(init_tea6420); -module_exit(exit_tea6420); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6420.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6420.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6420.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tea6420.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -#ifndef __INCLUDED_TEA6420__ -#define __INCLUDED_TEA6420__ - -/* input pins */ -#define TEA6420_OUTPUT1 1 -#define TEA6420_OUTPUT2 2 -#define TEA6420_OUTPUT3 3 -#define TEA6420_OUTPUT4 4 - -/* output pins */ -#define TEA6420_INPUT1 1 -#define TEA6420_INPUT2 2 -#define TEA6420_INPUT3 3 -#define TEA6420_INPUT4 4 -#define TEA6420_INPUT5 5 -#define TEA6420_INPUT6 6 - -/* gain on the output pins, ORed with the output pin */ -#define TEA6420_GAIN0 0x00 -#define TEA6420_GAIN2 0x20 -#define TEA6420_GAIN4 0x40 -#define TEA6420_GAIN6 0x60 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ths7303.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ths7303.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ths7303.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/ths7303.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,152 +0,0 @@ -/* - * ths7303- THS7303 Video Amplifier driver - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -MODULE_DESCRIPTION("TI THS7303 video amplifier driver"); -MODULE_AUTHOR("Chaithrika U S"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -/* following function is used to set ths7303 */ -static int ths7303_setvalue(struct v4l2_subdev *sd, v4l2_std_id std) -{ - int err = 0; - u8 val; - struct i2c_client *client; - - client = v4l2_get_subdevdata(sd); - - if (std & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) { - val = 0x02; - v4l2_dbg(1, debug, sd, "setting value for SDTV format\n"); - } else { - val = 0x00; - v4l2_dbg(1, debug, sd, "disabling all channels\n"); - } - - err |= i2c_smbus_write_byte_data(client, 0x01, val); - err |= i2c_smbus_write_byte_data(client, 0x02, val); - err |= i2c_smbus_write_byte_data(client, 0x03, val); - - if (err) - v4l2_err(sd, "write failed\n"); - - return err; -} - -static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - return ths7303_setvalue(sd, norm); -} - -static int ths7303_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_THS7303, 0); -} - -static const struct v4l2_subdev_video_ops ths7303_video_ops = { - .s_std_output = ths7303_s_std_output, -}; - -static const struct v4l2_subdev_core_ops ths7303_core_ops = { - .g_chip_ident = ths7303_g_chip_ident, -}; - -static const struct v4l2_subdev_ops ths7303_ops = { - .core = &ths7303_core_ops, - .video = &ths7303_video_ops, -}; - -static int ths7303_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct v4l2_subdev *sd; - v4l2_std_id std_id = V4L2_STD_NTSC; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); - if (sd == NULL) - return -ENOMEM; - - v4l2_i2c_subdev_init(sd, client, &ths7303_ops); - - return ths7303_setvalue(sd, std_id); -} - -static int ths7303_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(sd); - - return 0; -} - -static const struct i2c_device_id ths7303_id[] = { - {"ths7303", 0}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, ths7303_id); - -static struct i2c_driver ths7303_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "ths7303", - }, - .probe = ths7303_probe, - .remove = ths7303_remove, - .id_table = ths7303_id, -}; - -static int __init ths7303_init(void) -{ - return i2c_add_driver(&ths7303_driver); -} - -static void __exit ths7303_exit(void) -{ - i2c_del_driver(&ths7303_driver); -} - -module_init(ths7303_init); -module_exit(ths7303_exit); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/timblogiw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/timblogiw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/timblogiw.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/timblogiw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,893 +0,0 @@ -/* - * timblogiw.c timberdale FPGA LogiWin Video In driver - * Copyright (c) 2009-2010 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Supports: - * Timberdale FPGA LogiWin Video In - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "timb-video" - -#define TIMBLOGIWIN_NAME "Timberdale Video-In" -#define TIMBLOGIW_VERSION_CODE 0x04 - -#define TIMBLOGIW_LINES_PER_DESC 44 -#define TIMBLOGIW_MAX_VIDEO_MEM 16 - -#define TIMBLOGIW_HAS_DECODER(lw) (lw->pdata.encoder.module_name) - - -struct timblogiw { - struct video_device video_dev; - struct v4l2_device v4l2_dev; /* mutual exclusion */ - struct mutex lock; - struct device *dev; - struct timb_video_platform_data pdata; - struct v4l2_subdev *sd_enc; /* encoder */ - bool opened; -}; - -struct timblogiw_tvnorm { - v4l2_std_id std; - u16 width; - u16 height; - u8 fps; -}; - -struct timblogiw_fh { - struct videobuf_queue vb_vidq; - struct timblogiw_tvnorm const *cur_norm; - struct list_head capture; - struct dma_chan *chan; - spinlock_t queue_lock; /* mutual exclusion */ - unsigned int frame_count; -}; - -struct timblogiw_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - struct scatterlist sg[16]; - dma_cookie_t cookie; - struct timblogiw_fh *fh; -}; - -const struct timblogiw_tvnorm timblogiw_tvnorms[] = { - { - .std = V4L2_STD_PAL, - .width = 720, - .height = 576, - .fps = 25 - }, - { - .std = V4L2_STD_NTSC, - .width = 720, - .height = 480, - .fps = 30 - } -}; - -static int timblogiw_bytes_per_line(const struct timblogiw_tvnorm *norm) -{ - return norm->width * 2; -} - - -static int timblogiw_frame_size(const struct timblogiw_tvnorm *norm) -{ - return norm->height * timblogiw_bytes_per_line(norm); -} - -static const struct timblogiw_tvnorm *timblogiw_get_norm(const v4l2_std_id std) -{ - int i; - for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++) - if (timblogiw_tvnorms[i].std & std) - return timblogiw_tvnorms + i; - - /* default to first element */ - return timblogiw_tvnorms; -} - -static void timblogiw_dma_cb(void *data) -{ - struct timblogiw_buffer *buf = data; - struct timblogiw_fh *fh = buf->fh; - struct videobuf_buffer *vb = &buf->vb; - - spin_lock(&fh->queue_lock); - - /* mark the transfer done */ - buf->cookie = -1; - - fh->frame_count++; - - if (vb->state != VIDEOBUF_ERROR) { - list_del(&vb->queue); - do_gettimeofday(&vb->ts); - vb->field_count = fh->frame_count * 2; - vb->state = VIDEOBUF_DONE; - - wake_up(&vb->done); - } - - if (!list_empty(&fh->capture)) { - vb = list_entry(fh->capture.next, struct videobuf_buffer, - queue); - vb->state = VIDEOBUF_ACTIVE; - } - - spin_unlock(&fh->queue_lock); -} - -static bool timblogiw_dma_filter_fn(struct dma_chan *chan, void *filter_param) -{ - return chan->chan_id == (uintptr_t)filter_param; -} - -/* IOCTL functions */ - -static int timblogiw_g_fmt(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s entry\n", __func__); - - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - mutex_lock(&lw->lock); - - format->fmt.pix.width = fh->cur_norm->width; - format->fmt.pix.height = fh->cur_norm->height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; - format->fmt.pix.bytesperline = timblogiw_bytes_per_line(fh->cur_norm); - format->fmt.pix.sizeimage = timblogiw_frame_size(fh->cur_norm); - format->fmt.pix.field = V4L2_FIELD_NONE; - - mutex_unlock(&lw->lock); - - return 0; -} - -static int timblogiw_try_fmt(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_pix_format *pix = &format->fmt.pix; - - dev_dbg(&vdev->dev, - "%s - width=%d, height=%d, pixelformat=%d, field=%d\n" - "bytes per line %d, size image: %d, colorspace: %d\n", - __func__, - pix->width, pix->height, pix->pixelformat, pix->field, - pix->bytesperline, pix->sizeimage, pix->colorspace); - - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (pix->field != V4L2_FIELD_NONE) - return -EINVAL; - - if (pix->pixelformat != V4L2_PIX_FMT_UYVY) - return -EINVAL; - - return 0; -} - -static int timblogiw_s_fmt(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = priv; - struct v4l2_pix_format *pix = &format->fmt.pix; - int err; - - mutex_lock(&lw->lock); - - err = timblogiw_try_fmt(file, priv, format); - if (err) - goto out; - - if (videobuf_queue_is_busy(&fh->vb_vidq)) { - dev_err(&vdev->dev, "%s queue busy\n", __func__); - err = -EBUSY; - goto out; - } - - pix->width = fh->cur_norm->width; - pix->height = fh->cur_norm->height; - -out: - mutex_unlock(&lw->lock); - return err; -} - -static int timblogiw_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct video_device *vdev = video_devdata(file); - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - memset(cap, 0, sizeof(*cap)); - strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1); - strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1); - strlcpy(cap->bus_info, vdev->name, sizeof(cap->bus_info)); - cap->version = TIMBLOGIW_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - - return 0; -} - -static int timblogiw_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct video_device *vdev = video_devdata(file); - - dev_dbg(&vdev->dev, "%s, index: %d\n", __func__, fmt->index); - - if (fmt->index != 0) - return -EINVAL; - memset(fmt, 0, sizeof(*fmt)); - fmt->index = 0; - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strncpy(fmt->description, "4:2:2, packed, YUYV", - sizeof(fmt->description)-1); - fmt->pixelformat = V4L2_PIX_FMT_UYVY; - - return 0; -} - -static int timblogiw_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *sp) -{ - struct timblogiw_fh *fh = priv; - struct v4l2_captureparm *cp = &sp->parm.capture; - - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = 1; - cp->timeperframe.denominator = fh->cur_norm->fps; - - return 0; -} - -static int timblogiw_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_reqbufs(&fh->vb_vidq, rb); -} - -static int timblogiw_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_querybuf(&fh->vb_vidq, b); -} - -static int timblogiw_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_qbuf(&fh->vb_vidq, b); -} - -static int timblogiw_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); -} - -static int timblogiw_g_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - *std = fh->cur_norm->std; - return 0; -} - -static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = priv; - int err = 0; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - mutex_lock(&lw->lock); - - if (TIMBLOGIW_HAS_DECODER(lw)) - err = v4l2_subdev_call(lw->sd_enc, core, s_std, *std); - - if (!err) - fh->cur_norm = timblogiw_get_norm(*std); - - mutex_unlock(&lw->lock); - - return err; -} - -static int timblogiw_enuminput(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct video_device *vdev = video_devdata(file); - int i; - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - - if (inp->index != 0) - return -EINVAL; - - inp->index = 0; - - strncpy(inp->name, "Timb input 1", sizeof(inp->name) - 1); - inp->type = V4L2_INPUT_TYPE_CAMERA; - - inp->std = 0; - for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++) - inp->std |= timblogiw_tvnorms[i].std; - - return 0; -} - -static int timblogiw_g_input(struct file *file, void *priv, - unsigned int *input) -{ - struct video_device *vdev = video_devdata(file); - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - - *input = 0; - - return 0; -} - -static int timblogiw_s_input(struct file *file, void *priv, unsigned int input) -{ - struct video_device *vdev = video_devdata(file); - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - - if (input != 0) - return -EINVAL; - return 0; -} - -static int timblogiw_streamon(struct file *file, void *priv, unsigned int type) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_dbg(&vdev->dev, "%s - No capture device\n", __func__); - return -EINVAL; - } - - fh->frame_count = 0; - return videobuf_streamon(&fh->vb_vidq); -} - -static int timblogiw_streamoff(struct file *file, void *priv, - unsigned int type) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s entry\n", __func__); - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return videobuf_streamoff(&fh->vb_vidq); -} - -static int timblogiw_querystd(struct file *file, void *priv, v4l2_std_id *std) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s entry\n", __func__); - - if (TIMBLOGIW_HAS_DECODER(lw)) - return v4l2_subdev_call(lw->sd_enc, video, querystd, std); - else { - *std = fh->cur_norm->std; - return 0; - } -} - -static int timblogiw_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = priv; - - dev_dbg(&vdev->dev, "%s - index: %d, format: %d\n", __func__, - fsize->index, fsize->pixel_format); - - if ((fsize->index != 0) || - (fsize->pixel_format != V4L2_PIX_FMT_UYVY)) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = fh->cur_norm->width; - fsize->discrete.height = fh->cur_norm->height; - - return 0; -} - -/* Video buffer functions */ - -static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct timblogiw_fh *fh = vq->priv_data; - - *size = timblogiw_frame_size(fh->cur_norm); - - if (!*count) - *count = 32; - - while (*size * *count > TIMBLOGIW_MAX_VIDEO_MEM * 1024 * 1024) - (*count)--; - - return 0; -} - -static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct timblogiw_fh *fh = vq->priv_data; - struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, - vb); - unsigned int data_size = timblogiw_frame_size(fh->cur_norm); - int err = 0; - - if (vb->baddr && vb->bsize < data_size) - /* User provided buffer, but it is too small */ - return -ENOMEM; - - vb->size = data_size; - vb->width = fh->cur_norm->width; - vb->height = fh->cur_norm->height; - vb->field = field; - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - int i; - unsigned int size; - unsigned int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC * - timblogiw_bytes_per_line(fh->cur_norm); - dma_addr_t addr; - - sg_init_table(buf->sg, ARRAY_SIZE(buf->sg)); - - err = videobuf_iolock(vq, vb, NULL); - if (err) - goto err; - - addr = videobuf_to_dma_contig(vb); - for (i = 0, size = 0; size < data_size; i++) { - sg_dma_address(buf->sg + i) = addr + size; - size += bytes_per_desc; - sg_dma_len(buf->sg + i) = (size > data_size) ? - (bytes_per_desc - (size - data_size)) : - bytes_per_desc; - } - - vb->state = VIDEOBUF_PREPARED; - buf->cookie = -1; - buf->fh = fh; - } - - return 0; - -err: - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; - return err; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct timblogiw_fh *fh = vq->priv_data; - struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, - vb); - struct dma_async_tx_descriptor *desc; - int sg_elems; - int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC * - timblogiw_bytes_per_line(fh->cur_norm); - - sg_elems = timblogiw_frame_size(fh->cur_norm) / bytes_per_desc; - sg_elems += - (timblogiw_frame_size(fh->cur_norm) % bytes_per_desc) ? 1 : 0; - - if (list_empty(&fh->capture)) - vb->state = VIDEOBUF_ACTIVE; - else - vb->state = VIDEOBUF_QUEUED; - - list_add_tail(&vb->queue, &fh->capture); - - spin_unlock_irq(&fh->queue_lock); - - desc = fh->chan->device->device_prep_slave_sg(fh->chan, - buf->sg, sg_elems, DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP); - if (!desc) { - spin_lock_irq(&fh->queue_lock); - list_del_init(&vb->queue); - vb->state = VIDEOBUF_PREPARED; - return; - } - - desc->callback_param = buf; - desc->callback = timblogiw_dma_cb; - - buf->cookie = desc->tx_submit(desc); - - spin_lock_irq(&fh->queue_lock); -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct timblogiw_fh *fh = vq->priv_data; - struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, - vb); - - videobuf_waiton(vq, vb, 0, 0); - if (buf->cookie >= 0) - dma_sync_wait(fh->chan, buf->cookie); - - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static struct videobuf_queue_ops timblogiw_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* Device Operations functions */ - -static int timblogiw_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh; - v4l2_std_id std; - dma_cap_mask_t mask; - int err = 0; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - mutex_lock(&lw->lock); - if (lw->opened) { - err = -EBUSY; - goto out; - } - - if (TIMBLOGIW_HAS_DECODER(lw) && !lw->sd_enc) { - struct i2c_adapter *adapt; - - /* find the video decoder */ - adapt = i2c_get_adapter(lw->pdata.i2c_adapter); - if (!adapt) { - dev_err(&vdev->dev, "No I2C bus #%d\n", - lw->pdata.i2c_adapter); - err = -ENODEV; - goto out; - } - - /* now find the encoder */ - lw->sd_enc = v4l2_i2c_new_subdev_board(&lw->v4l2_dev, adapt, - lw->pdata.encoder.info, NULL); - - i2c_put_adapter(adapt); - - if (!lw->sd_enc) { - dev_err(&vdev->dev, "Failed to get encoder: %s\n", - lw->pdata.encoder.module_name); - err = -ENODEV; - goto out; - } - } - - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) { - err = -ENOMEM; - goto out; - } - - fh->cur_norm = timblogiw_tvnorms; - timblogiw_querystd(file, fh, &std); - fh->cur_norm = timblogiw_get_norm(std); - - INIT_LIST_HEAD(&fh->capture); - spin_lock_init(&fh->queue_lock); - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_cap_set(DMA_PRIVATE, mask); - - /* find the DMA channel */ - fh->chan = dma_request_channel(mask, timblogiw_dma_filter_fn, - (void *)(uintptr_t)lw->pdata.dma_channel); - if (!fh->chan) { - dev_err(&vdev->dev, "Failed to get DMA channel\n"); - kfree(fh); - err = -ENODEV; - goto out; - } - - file->private_data = fh; - videobuf_queue_dma_contig_init(&fh->vb_vidq, - &timblogiw_video_qops, lw->dev, &fh->queue_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct timblogiw_buffer), fh, NULL); - - lw->opened = true; -out: - mutex_unlock(&lw->lock); - - return err; -} - -static int timblogiw_close(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw *lw = video_get_drvdata(vdev); - struct timblogiw_fh *fh = file->private_data; - - dev_dbg(&vdev->dev, "%s: Entry\n", __func__); - - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - - dma_release_channel(fh->chan); - - kfree(fh); - - mutex_lock(&lw->lock); - lw->opened = false; - mutex_unlock(&lw->lock); - return 0; -} - -static ssize_t timblogiw_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = file->private_data; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static unsigned int timblogiw_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = file->private_data; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_poll_stream(file, &fh->vb_vidq, wait); -} - -static int timblogiw_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = video_devdata(file); - struct timblogiw_fh *fh = file->private_data; - - dev_dbg(&vdev->dev, "%s: entry\n", __func__); - - return videobuf_mmap_mapper(&fh->vb_vidq, vma); -} - -/* Platform device functions */ - -static __devinitconst struct v4l2_ioctl_ops timblogiw_ioctl_ops = { - .vidioc_querycap = timblogiw_querycap, - .vidioc_enum_fmt_vid_cap = timblogiw_enum_fmt, - .vidioc_g_fmt_vid_cap = timblogiw_g_fmt, - .vidioc_try_fmt_vid_cap = timblogiw_try_fmt, - .vidioc_s_fmt_vid_cap = timblogiw_s_fmt, - .vidioc_g_parm = timblogiw_g_parm, - .vidioc_reqbufs = timblogiw_reqbufs, - .vidioc_querybuf = timblogiw_querybuf, - .vidioc_qbuf = timblogiw_qbuf, - .vidioc_dqbuf = timblogiw_dqbuf, - .vidioc_g_std = timblogiw_g_std, - .vidioc_s_std = timblogiw_s_std, - .vidioc_enum_input = timblogiw_enuminput, - .vidioc_g_input = timblogiw_g_input, - .vidioc_s_input = timblogiw_s_input, - .vidioc_streamon = timblogiw_streamon, - .vidioc_streamoff = timblogiw_streamoff, - .vidioc_querystd = timblogiw_querystd, - .vidioc_enum_framesizes = timblogiw_enum_framesizes, -}; - -static __devinitconst struct v4l2_file_operations timblogiw_fops = { - .owner = THIS_MODULE, - .open = timblogiw_open, - .release = timblogiw_close, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = timblogiw_mmap, - .read = timblogiw_read, - .poll = timblogiw_poll, -}; - -static __devinitconst struct video_device timblogiw_template = { - .name = TIMBLOGIWIN_NAME, - .fops = &timblogiw_fops, - .ioctl_ops = &timblogiw_ioctl_ops, - .release = video_device_release_empty, - .minor = -1, - .tvnorms = V4L2_STD_PAL | V4L2_STD_NTSC -}; - -static int __devinit timblogiw_probe(struct platform_device *pdev) -{ - int err; - struct timblogiw *lw = NULL; - struct timb_video_platform_data *pdata = pdev->dev.platform_data; - - if (!pdata) { - dev_err(&pdev->dev, "No platform data\n"); - err = -EINVAL; - goto err; - } - - if (!pdata->encoder.module_name) - dev_info(&pdev->dev, "Running without decoder\n"); - - lw = kzalloc(sizeof(*lw), GFP_KERNEL); - if (!lw) { - err = -ENOMEM; - goto err; - } - - if (pdev->dev.parent) - lw->dev = pdev->dev.parent; - else - lw->dev = &pdev->dev; - - memcpy(&lw->pdata, pdata, sizeof(lw->pdata)); - - mutex_init(&lw->lock); - - lw->video_dev = timblogiw_template; - - strlcpy(lw->v4l2_dev.name, DRIVER_NAME, sizeof(lw->v4l2_dev.name)); - err = v4l2_device_register(NULL, &lw->v4l2_dev); - if (err) - goto err_register; - - lw->video_dev.v4l2_dev = &lw->v4l2_dev; - - platform_set_drvdata(pdev, lw); - video_set_drvdata(&lw->video_dev, lw); - - err = video_register_device(&lw->video_dev, VFL_TYPE_GRABBER, 0); - if (err) { - dev_err(&pdev->dev, "Error reg video: %d\n", err); - goto err_request; - } - - - return 0; - -err_request: - platform_set_drvdata(pdev, NULL); - v4l2_device_unregister(&lw->v4l2_dev); -err_register: - kfree(lw); -err: - dev_err(&pdev->dev, "Failed to register: %d\n", err); - - return err; -} - -static int __devexit timblogiw_remove(struct platform_device *pdev) -{ - struct timblogiw *lw = platform_get_drvdata(pdev); - - video_unregister_device(&lw->video_dev); - - v4l2_device_unregister(&lw->v4l2_dev); - - kfree(lw); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver timblogiw_platform_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, - .probe = timblogiw_probe, - .remove = __devexit_p(timblogiw_remove), -}; - -/* Module functions */ - -static int __init timblogiw_init(void) -{ - return platform_driver_register(&timblogiw_platform_driver); -} - -static void __exit timblogiw_exit(void) -{ - platform_driver_unregister(&timblogiw_platform_driver); -} - -module_init(timblogiw_init); -module_exit(timblogiw_exit); - -MODULE_DESCRIPTION(TIMBLOGIWIN_NAME); -MODULE_AUTHOR("Pelagicore AB "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:"DRIVER_NAME); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -config VIDEO_TLG2300 - tristate "Telegent TLG2300 USB video capture support" - depends on VIDEO_DEV && I2C && SND && DVB_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - depends on RC_CORE - select VIDEOBUF_VMALLOC - select SND_PCM - select VIDEOBUF_DVB - - ---help--- - This is a video4linux driver for Telegent tlg2300 based TV cards. - The driver supports V4L2, DVB-T and radio. - - To compile this driver as a module, choose M here: the - module will be called poseidon diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o - -obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-alsa.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-alsa.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-alsa.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-alsa.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,332 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pd-common.h" -#include "vendorcmds.h" - -static void complete_handler_audio(struct urb *urb); -#define AUDIO_EP (0x83) -#define AUDIO_BUF_SIZE (512) -#define PERIOD_SIZE (1024 * 8) -#define PERIOD_MIN (4) -#define PERIOD_MAX PERIOD_MIN - -static struct snd_pcm_hardware snd_pd_hw_capture = { - .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID, - - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = PERIOD_SIZE * PERIOD_MIN, - .period_bytes_min = PERIOD_SIZE, - .period_bytes_max = PERIOD_SIZE, - .periods_min = PERIOD_MIN, - .periods_max = PERIOD_MAX, - /* - .buffer_bytes_max = 62720 * 8, - .period_bytes_min = 64, - .period_bytes_max = 12544, - .periods_min = 2, - .periods_max = 98 - */ -}; - -static int snd_pd_capture_open(struct snd_pcm_substream *substream) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - struct poseidon_audio *pa = &p->audio; - struct snd_pcm_runtime *runtime = substream->runtime; - - if (!p) - return -ENODEV; - pa->users++; - pa->card_close = 0; - pa->capture_pcm_substream = substream; - runtime->private_data = p; - - runtime->hw = snd_pd_hw_capture; - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - usb_autopm_get_interface(p->interface); - kref_get(&p->kref); - return 0; -} - -static int snd_pd_pcm_close(struct snd_pcm_substream *substream) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - struct poseidon_audio *pa = &p->audio; - - pa->users--; - pa->card_close = 1; - usb_autopm_put_interface(p->interface); - kref_put(&p->kref, poseidon_delete); - return 0; -} - -static int snd_pd_hw_capture_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int size; - - size = params_buffer_bytes(hw_params); - if (runtime->dma_area) { - if (runtime->dma_bytes > size) - return 0; - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc(size); - if (!runtime->dma_area) - return -ENOMEM; - else - runtime->dma_bytes = size; - return 0; -} - -static int audio_buf_free(struct poseidon *p) -{ - struct poseidon_audio *pa = &p->audio; - int i; - - for (i = 0; i < AUDIO_BUFS; i++) - if (pa->urb_array[i]) - usb_kill_urb(pa->urb_array[i]); - free_all_urb_generic(pa->urb_array, AUDIO_BUFS); - logpm(); - return 0; -} - -static int snd_pd_hw_capture_free(struct snd_pcm_substream *substream) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - - logpm(); - audio_buf_free(p); - return 0; -} - -static int snd_pd_prepare(struct snd_pcm_substream *substream) -{ - return 0; -} - -#define AUDIO_TRAILER_SIZE (16) -static inline void handle_audio_data(struct urb *urb, int *period_elapsed) -{ - struct poseidon_audio *pa = urb->context; - struct snd_pcm_runtime *runtime = pa->capture_pcm_substream->runtime; - - int stride = runtime->frame_bits >> 3; - int len = urb->actual_length / stride; - unsigned char *cp = urb->transfer_buffer; - unsigned int oldptr = pa->rcv_position; - - if (urb->actual_length == AUDIO_BUF_SIZE - 4) - len -= (AUDIO_TRAILER_SIZE / stride); - - /* do the copy */ - if (oldptr + len >= runtime->buffer_size) { - unsigned int cnt = runtime->buffer_size - oldptr; - - memcpy(runtime->dma_area + oldptr * stride, cp, cnt * stride); - memcpy(runtime->dma_area, (cp + cnt * stride), - (len * stride - cnt * stride)); - } else - memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); - - /* update the statas */ - snd_pcm_stream_lock(pa->capture_pcm_substream); - pa->rcv_position += len; - if (pa->rcv_position >= runtime->buffer_size) - pa->rcv_position -= runtime->buffer_size; - - pa->copied_position += (len); - if (pa->copied_position >= runtime->period_size) { - pa->copied_position -= runtime->period_size; - *period_elapsed = 1; - } - snd_pcm_stream_unlock(pa->capture_pcm_substream); -} - -static void complete_handler_audio(struct urb *urb) -{ - struct poseidon_audio *pa = urb->context; - struct snd_pcm_substream *substream = pa->capture_pcm_substream; - int period_elapsed = 0; - int ret; - - if (1 == pa->card_close || pa->capture_stream != STREAM_ON) - return; - - if (urb->status != 0) { - /*if (urb->status == -ESHUTDOWN)*/ - return; - } - - if (substream) { - if (urb->actual_length) { - handle_audio_data(urb, &period_elapsed); - if (period_elapsed) - snd_pcm_period_elapsed(substream); - } - } - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) - log("audio urb failed (errcod = %i)", ret); - return; -} - -static int fire_audio_urb(struct poseidon *p) -{ - int i, ret = 0; - struct poseidon_audio *pa = &p->audio; - - alloc_bulk_urbs_generic(pa->urb_array, AUDIO_BUFS, - p->udev, AUDIO_EP, - AUDIO_BUF_SIZE, GFP_ATOMIC, - complete_handler_audio, pa); - - for (i = 0; i < AUDIO_BUFS; i++) { - ret = usb_submit_urb(pa->urb_array[i], GFP_KERNEL); - if (ret) - log("urb err : %d", ret); - } - log(); - return ret; -} - -static int snd_pd_capture_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - struct poseidon_audio *pa = &p->audio; - - if (debug_mode) - log("cmd %d, audio stat : %d\n", cmd, pa->capture_stream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_START: - if (pa->capture_stream == STREAM_ON) - return 0; - - pa->rcv_position = pa->copied_position = 0; - pa->capture_stream = STREAM_ON; - - if (in_hibernation(p)) - return 0; - fire_audio_urb(p); - return 0; - - case SNDRV_PCM_TRIGGER_SUSPEND: - pa->capture_stream = STREAM_SUSPEND; - return 0; - case SNDRV_PCM_TRIGGER_STOP: - pa->capture_stream = STREAM_OFF; - return 0; - default: - return -EINVAL; - } -} - -static snd_pcm_uframes_t -snd_pd_capture_pointer(struct snd_pcm_substream *substream) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - struct poseidon_audio *pa = &p->audio; - return pa->rcv_position; -} - -static struct page *snd_pcm_pd_get_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -static struct snd_pcm_ops pcm_capture_ops = { - .open = snd_pd_capture_open, - .close = snd_pd_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_pd_hw_capture_params, - .hw_free = snd_pd_hw_capture_free, - .prepare = snd_pd_prepare, - .trigger = snd_pd_capture_trigger, - .pointer = snd_pd_capture_pointer, - .page = snd_pcm_pd_get_page, -}; - -#ifdef CONFIG_PM -int pm_alsa_suspend(struct poseidon *p) -{ - logpm(p); - audio_buf_free(p); - return 0; -} - -int pm_alsa_resume(struct poseidon *p) -{ - logpm(p); - fire_audio_urb(p); - return 0; -} -#endif - -int poseidon_audio_init(struct poseidon *p) -{ - struct poseidon_audio *pa = &p->audio; - struct snd_card *card; - struct snd_pcm *pcm; - int ret; - - ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card); - if (ret != 0) - return ret; - - ret = snd_pcm_new(card, "poseidon audio", 0, 0, 1, &pcm); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); - pcm->info_flags = 0; - pcm->private_data = p; - strcpy(pcm->name, "poseidon audio capture"); - - strcpy(card->driver, "ALSA driver"); - strcpy(card->shortname, "poseidon Audio"); - strcpy(card->longname, "poseidon ALSA Audio"); - - if (snd_card_register(card)) { - snd_card_free(card); - return -ENOMEM; - } - pa->card = card; - return 0; -} - -int poseidon_audio_free(struct poseidon *p) -{ - struct poseidon_audio *pa = &p->audio; - - if (pa->card) - snd_card_free(pa->card); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-common.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,282 +0,0 @@ -#ifndef PD_COMMON_H -#define PD_COMMON_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dmxdev.h" - -#define SBUF_NUM 8 -#define MAX_BUFFER_NUM 6 -#define PK_PER_URB 32 -#define ISO_PKT_SIZE 3072 - -#define POSEIDON_STATE_NONE (0x0000) -#define POSEIDON_STATE_ANALOG (0x0001) -#define POSEIDON_STATE_FM (0x0002) -#define POSEIDON_STATE_DVBT (0x0004) -#define POSEIDON_STATE_VBI (0x0008) -#define POSEIDON_STATE_DISCONNECT (0x0080) - -#define PM_SUSPEND_DELAY 3 - -#define V4L_PAL_VBI_LINES 18 -#define V4L_NTSC_VBI_LINES 12 -#define V4L_PAL_VBI_FRAMESIZE (V4L_PAL_VBI_LINES * 1440 * 2) -#define V4L_NTSC_VBI_FRAMESIZE (V4L_NTSC_VBI_LINES * 1440 * 2) - -#define TUNER_FREQ_MIN (45000000) -#define TUNER_FREQ_MAX (862000000) - -struct vbi_data { - struct video_device *v_dev; - struct video_data *video; - struct front_face *front; - - unsigned int copied; - unsigned int vbi_size; /* the whole size of two fields */ - int users; -}; - -/* - * This is the running context of the video, it is useful for - * resume() - */ -struct running_context { - u32 freq; /* VIDIOC_S_FREQUENCY */ - int audio_idx; /* VIDIOC_S_TUNER */ - v4l2_std_id tvnormid; /* VIDIOC_S_STD */ - int sig_index; /* VIDIOC_S_INPUT */ - struct v4l2_pix_format pix; /* VIDIOC_S_FMT */ -}; - -struct video_data { - /* v4l2 video device */ - struct video_device *v_dev; - - /* the working context */ - struct running_context context; - - /* for data copy */ - int field_count; - - char *dst; - int lines_copied; - int prev_left; - - int lines_per_field; - int lines_size; - - /* for communication */ - u8 endpoint_addr; - struct urb *urb_array[SBUF_NUM]; - struct vbi_data *vbi; - struct poseidon *pd; - struct front_face *front; - - int is_streaming; - int users; - - /* for bubble handler */ - struct work_struct bubble_work; -}; - -enum pcm_stream_state { - STREAM_OFF, - STREAM_ON, - STREAM_SUSPEND, -}; - -#define AUDIO_BUFS (3) -#define CAPTURE_STREAM_EN 1 -struct poseidon_audio { - struct urb *urb_array[AUDIO_BUFS]; - unsigned int copied_position; - struct snd_pcm_substream *capture_pcm_substream; - - unsigned int rcv_position; - struct snd_card *card; - int card_close; - - int users; - int pm_state; - enum pcm_stream_state capture_stream; -}; - -struct radio_data { - __u32 fm_freq; - int users; - unsigned int is_radio_streaming; - int pre_emphasis; - struct video_device *fm_dev; -}; - -#define DVB_SBUF_NUM 4 -#define DVB_URB_BUF_SIZE 0x2000 -struct pd_dvb_adapter { - struct dvb_adapter dvb_adap; - struct dvb_frontend dvb_fe; - struct dmxdev dmxdev; - struct dvb_demux demux; - - atomic_t users; - atomic_t active_feed; - - /* data transfer */ - s32 is_streaming; - struct urb *urb_array[DVB_SBUF_NUM]; - struct poseidon *pd_device; - u8 ep_addr; - u8 reserved[3]; - - /* data for power resume*/ - struct dvb_frontend_parameters fe_param; - - /* for channel scanning */ - int prev_freq; - int bandwidth; - unsigned long last_jiffies; -}; - -struct front_face { - /* use this field to distinguish VIDEO and VBI */ - enum v4l2_buf_type type; - - /* for host */ - struct videobuf_queue q; - - /* the bridge for host and device */ - struct videobuf_buffer *curr_frame; - - /* for device */ - spinlock_t queue_lock; - struct list_head active; - struct poseidon *pd; -}; - -struct poseidon { - struct list_head device_list; - - struct mutex lock; - struct kref kref; - - /* for V4L2 */ - struct v4l2_device v4l2_dev; - - /* hardware info */ - struct usb_device *udev; - struct usb_interface *interface; - int cur_transfer_mode; - - struct video_data video_data; /* video */ - struct vbi_data vbi_data; /* vbi */ - struct poseidon_audio audio; /* audio (alsa) */ - struct radio_data radio_data; /* FM */ - struct pd_dvb_adapter dvb_data; /* DVB */ - - u32 state; - struct file *file_for_stream; /* the active stream*/ - -#ifdef CONFIG_PM - int (*pm_suspend)(struct poseidon *); - int (*pm_resume)(struct poseidon *); - pm_message_t msg; - - struct work_struct pm_work; - u8 portnum; -#endif -}; - -struct poseidon_format { - char *name; - int fourcc; /* video4linux 2 */ - int depth; /* bit/pixel */ - int flags; -}; - -struct poseidon_tvnorm { - v4l2_std_id v4l2_id; - char name[12]; - u32 tlg_tvnorm; -}; - -/* video */ -int pd_video_init(struct poseidon *); -void pd_video_exit(struct poseidon *); -int stop_all_video_stream(struct poseidon *); - -/* alsa audio */ -int poseidon_audio_init(struct poseidon *); -int poseidon_audio_free(struct poseidon *); -#ifdef CONFIG_PM -int pm_alsa_suspend(struct poseidon *); -int pm_alsa_resume(struct poseidon *); -#endif - -/* dvb */ -int pd_dvb_usb_device_init(struct poseidon *); -void pd_dvb_usb_device_exit(struct poseidon *); -void pd_dvb_usb_device_cleanup(struct poseidon *); -int pd_dvb_get_adapter_num(struct pd_dvb_adapter *); -void dvb_stop_streaming(struct pd_dvb_adapter *); - -/* FM */ -int poseidon_fm_init(struct poseidon *); -int poseidon_fm_exit(struct poseidon *); -struct video_device *vdev_init(struct poseidon *, struct video_device *); - -/* vendor command ops */ -int send_set_req(struct poseidon*, u8, s32, s32*); -int send_get_req(struct poseidon*, u8, s32, void*, s32*, s32); -s32 set_tuner_mode(struct poseidon*, unsigned char); - -/* bulk urb alloc/free */ -int alloc_bulk_urbs_generic(struct urb **urb_array, int num, - struct usb_device *udev, u8 ep_addr, - int buf_size, gfp_t gfp_flags, - usb_complete_t complete_fn, void *context); -void free_all_urb_generic(struct urb **urb_array, int num); - -/* misc */ -void poseidon_delete(struct kref *kref); -void destroy_video_device(struct video_device **v_dev); -extern int debug_mode; -void set_debug_mode(struct video_device *vfd, int debug_mode); - -#ifdef CONFIG_PM -#define in_hibernation(pd) (pd->msg.event == PM_EVENT_FREEZE) -#else -#define in_hibernation(pd) (0) -#endif -#define get_pm_count(p) (atomic_read(&(p)->interface->pm_usage_cnt)) - -#define log(a, ...) printk(KERN_DEBUG "\t[ %s : %.3d ] "a"\n", \ - __func__, __LINE__, ## __VA_ARGS__) - -/* for power management */ -#define logpm(pd) do {\ - if (debug_mode & 0x10)\ - log();\ - } while (0) - -#define logs(f) do { \ - if ((debug_mode & 0x4) && \ - (f)->type == V4L2_BUF_TYPE_VBI_CAPTURE) \ - log("type : VBI");\ - \ - if ((debug_mode & 0x8) && \ - (f)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) \ - log("type : VIDEO");\ - } while (0) -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-dvb.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,596 +0,0 @@ -#include "pd-common.h" -#include -#include -#include -#include -#include - -#include "vendorcmds.h" -#include -#include - -static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb); - -static int dvb_bandwidth[][2] = { - { TLG_BW_8, BANDWIDTH_8_MHZ }, - { TLG_BW_7, BANDWIDTH_7_MHZ }, - { TLG_BW_6, BANDWIDTH_6_MHZ } -}; -static int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth); - -static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb); -static int poseidon_check_mode_dvbt(struct poseidon *pd) -{ - s32 ret = 0, cmd_status = 0; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - - ret = usb_set_interface(pd->udev, 0, BULK_ALTERNATE_IFACE); - if (ret != 0) - return ret; - - ret = set_tuner_mode(pd, TLG_MODE_CAPS_DVB_T); - if (ret) - return ret; - - /* signal source */ - ret = send_set_req(pd, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &cmd_status); - if (ret|cmd_status) - return ret; - - return 0; -} - -/* acquire : - * 1 == open - * 0 == release - */ -static int poseidon_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct poseidon *pd = fe->demodulator_priv; - struct pd_dvb_adapter *pd_dvb; - int ret = 0; - - if (!pd) - return -ENODEV; - - pd_dvb = container_of(fe, struct pd_dvb_adapter, dvb_fe); - if (acquire) { - mutex_lock(&pd->lock); - if (pd->state & POSEIDON_STATE_DISCONNECT) { - ret = -ENODEV; - goto open_out; - } - - if (pd->state && !(pd->state & POSEIDON_STATE_DVBT)) { - ret = -EBUSY; - goto open_out; - } - - usb_autopm_get_interface(pd->interface); - if (0 == pd->state) { - ret = poseidon_check_mode_dvbt(pd); - if (ret < 0) { - usb_autopm_put_interface(pd->interface); - goto open_out; - } - pd->state |= POSEIDON_STATE_DVBT; - pd_dvb->bandwidth = 0; - pd_dvb->prev_freq = 0; - } - atomic_inc(&pd_dvb->users); - kref_get(&pd->kref); -open_out: - mutex_unlock(&pd->lock); - } else { - dvb_stop_streaming(pd_dvb); - - if (atomic_dec_and_test(&pd_dvb->users)) { - mutex_lock(&pd->lock); - pd->state &= ~POSEIDON_STATE_DVBT; - mutex_unlock(&pd->lock); - } - kref_put(&pd->kref, poseidon_delete); - usb_autopm_put_interface(pd->interface); - } - return ret; -} - -#ifdef CONFIG_PM -static void poseidon_fe_release(struct dvb_frontend *fe) -{ - struct poseidon *pd = fe->demodulator_priv; - - pd->pm_suspend = NULL; - pd->pm_resume = NULL; -} -#else -#define poseidon_fe_release NULL -#endif - -static s32 poseidon_fe_sleep(struct dvb_frontend *fe) -{ - return 0; -} - -/* - * return true if we can satisfy the conditions, else return false. - */ -static bool check_scan_ok(__u32 freq, int bandwidth, - struct pd_dvb_adapter *adapter) -{ - if (bandwidth < 0) - return false; - - if (adapter->prev_freq == freq - && adapter->bandwidth == bandwidth) { - long nl = jiffies - adapter->last_jiffies; - unsigned int msec ; - - msec = jiffies_to_msecs(abs(nl)); - return msec > 15000 ? true : false; - } - return true; -} - -/* - * Check if the firmware delays too long for an invalid frequency. - */ -static int fw_delay_overflow(struct pd_dvb_adapter *adapter) -{ - long nl = jiffies - adapter->last_jiffies; - unsigned int msec ; - - msec = jiffies_to_msecs(abs(nl)); - return msec > 800 ? true : false; -} - -static int poseidon_set_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - s32 ret = 0, cmd_status = 0; - s32 i, bandwidth = -1; - struct poseidon *pd = fe->demodulator_priv; - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - if (in_hibernation(pd)) - return -EBUSY; - - mutex_lock(&pd->lock); - for (i = 0; i < dvb_bandwidth_length; i++) - if (fep->u.ofdm.bandwidth == dvb_bandwidth[i][1]) - bandwidth = dvb_bandwidth[i][0]; - - if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) { - ret = send_set_req(pd, TUNE_FREQ_SELECT, - fep->frequency / 1000, &cmd_status); - if (ret | cmd_status) { - log("error line"); - goto front_out; - } - - ret = send_set_req(pd, DVBT_BANDW_SEL, - bandwidth, &cmd_status); - if (ret | cmd_status) { - log("error line"); - goto front_out; - } - - ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - if (ret | cmd_status) { - log("error line"); - goto front_out; - } - - /* save the context for future */ - memcpy(&pd_dvb->fe_param, fep, sizeof(*fep)); - pd_dvb->bandwidth = bandwidth; - pd_dvb->prev_freq = fep->frequency; - pd_dvb->last_jiffies = jiffies; - } -front_out: - mutex_unlock(&pd->lock); - return ret; -} - -#ifdef CONFIG_PM -static int pm_dvb_suspend(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - dvb_stop_streaming(pd_dvb); - dvb_urb_cleanup(pd_dvb); - msleep(500); - return 0; -} - -static int pm_dvb_resume(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - poseidon_check_mode_dvbt(pd); - msleep(300); - poseidon_set_fe(&pd_dvb->dvb_fe, &pd_dvb->fe_param); - - dvb_start_streaming(pd_dvb); - return 0; -} -#endif - -static s32 poseidon_fe_init(struct dvb_frontend *fe) -{ - struct poseidon *pd = fe->demodulator_priv; - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - -#ifdef CONFIG_PM - pd->pm_suspend = pm_dvb_suspend; - pd->pm_resume = pm_dvb_resume; -#endif - memset(&pd_dvb->fe_param, 0, - sizeof(struct dvb_frontend_parameters)); - return 0; -} - -static int poseidon_get_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct poseidon *pd = fe->demodulator_priv; - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - memcpy(fep, &pd_dvb->fe_param, sizeof(*fep)); - return 0; -} - -static int poseidon_fe_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static int poseidon_read_status(struct dvb_frontend *fe, fe_status_t *stat) -{ - struct poseidon *pd = fe->demodulator_priv; - s32 ret = -1, cmd_status; - struct tuner_dtv_sig_stat_s status = {}; - - if (in_hibernation(pd)) - return -EBUSY; - mutex_lock(&pd->lock); - - ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T, - &status, &cmd_status, sizeof(status)); - if (ret | cmd_status) { - log("get tuner status error"); - goto out; - } - - if (debug_mode) - log("P : %d, L %d, LB :%d", status.sig_present, - status.sig_locked, status.sig_lock_busy); - - if (status.sig_lock_busy) { - goto out; - } else if (status.sig_present || status.sig_locked) { - *stat |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER - | FE_HAS_SYNC | FE_HAS_VITERBI; - } else { - if (fw_delay_overflow(&pd->dvb_data)) - *stat |= FE_TIMEDOUT; - } -out: - mutex_unlock(&pd->lock); - return ret; -} - -static int poseidon_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct poseidon *pd = fe->demodulator_priv; - struct tuner_ber_rate_s tlg_ber = {}; - s32 ret = -1, cmd_status; - - mutex_lock(&pd->lock); - ret = send_get_req(pd, TUNER_BER_RATE, 0, - &tlg_ber, &cmd_status, sizeof(tlg_ber)); - if (ret | cmd_status) - goto out; - *ber = tlg_ber.ber_rate; -out: - mutex_unlock(&pd->lock); - return ret; -} - -static s32 poseidon_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct poseidon *pd = fe->demodulator_priv; - struct tuner_dtv_sig_stat_s status = {}; - s32 ret = 0, cmd_status; - - mutex_lock(&pd->lock); - ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T, - &status, &cmd_status, sizeof(status)); - if (ret | cmd_status) - goto out; - if ((status.sig_present || status.sig_locked) && !status.sig_strength) - *strength = 0xFFFF; - else - *strength = status.sig_strength; -out: - mutex_unlock(&pd->lock); - return ret; -} - -static int poseidon_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - return 0; -} - -static int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) -{ - *unc = 0; - return 0; -} - -static struct dvb_frontend_ops poseidon_frontend_ops = { - .info = { - .name = "Poseidon DVB-T", - .type = FE_OFDM, - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 62500,/* FIXME */ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = poseidon_fe_release, - - .init = poseidon_fe_init, - .sleep = poseidon_fe_sleep, - - .set_frontend = poseidon_set_fe, - .get_frontend = poseidon_get_fe, - .get_tune_settings = poseidon_fe_get_tune_settings, - - .read_status = poseidon_read_status, - .read_ber = poseidon_read_ber, - .read_signal_strength = poseidon_read_signal_strength, - .read_snr = poseidon_read_snr, - .read_ucblocks = poseidon_read_unc_blocks, - - .ts_bus_ctrl = poseidon_ts_bus_ctrl, -}; - -static void dvb_urb_irq(struct urb *urb) -{ - struct pd_dvb_adapter *pd_dvb = urb->context; - int len = urb->transfer_buffer_length; - struct dvb_demux *demux = &pd_dvb->demux; - s32 ret; - - if (!pd_dvb->is_streaming || urb->status) { - if (urb->status == -EPROTO) - goto resend; - return; - } - - if (urb->actual_length == len) - dvb_dmx_swfilter(demux, urb->transfer_buffer, len); - else if (urb->actual_length == len - 4) { - int offset; - u8 *buf = urb->transfer_buffer; - - /* - * The packet size is 512, - * last packet contains 456 bytes tsp data - */ - for (offset = 456; offset < len; offset += 512) { - if (!strncmp(buf + offset, "DVHS", 4)) { - dvb_dmx_swfilter(demux, buf, offset); - if (len > offset + 52 + 4) { - /*16 bytes trailer + 36 bytes padding */ - buf += offset + 52; - len -= offset + 52 + 4; - dvb_dmx_swfilter(demux, buf, len); - } - break; - } - } - } - -resend: - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - log(" usb_submit_urb failed: error %d", ret); -} - -static int dvb_urb_init(struct pd_dvb_adapter *pd_dvb) -{ - if (pd_dvb->urb_array[0]) - return 0; - - alloc_bulk_urbs_generic(pd_dvb->urb_array, DVB_SBUF_NUM, - pd_dvb->pd_device->udev, pd_dvb->ep_addr, - DVB_URB_BUF_SIZE, GFP_KERNEL, - dvb_urb_irq, pd_dvb); - return 0; -} - -static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb) -{ - free_all_urb_generic(pd_dvb->urb_array, DVB_SBUF_NUM); -} - -static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb) -{ - struct poseidon *pd = pd_dvb->pd_device; - int ret = 0; - - if (pd->state & POSEIDON_STATE_DISCONNECT) - return -ENODEV; - - mutex_lock(&pd->lock); - if (!pd_dvb->is_streaming) { - s32 i, cmd_status = 0; - /* - * Once upon a time, there was a difficult bug lying here. - * ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - */ - - ret = send_set_req(pd, PLAY_SERVICE, 1, &cmd_status); - if (ret | cmd_status) - goto out; - - ret = dvb_urb_init(pd_dvb); - if (ret < 0) - goto out; - - pd_dvb->is_streaming = 1; - for (i = 0; i < DVB_SBUF_NUM; i++) { - ret = usb_submit_urb(pd_dvb->urb_array[i], - GFP_KERNEL); - if (ret) { - log(" submit urb error %d", ret); - goto out; - } - } - } -out: - mutex_unlock(&pd->lock); - return ret; -} - -void dvb_stop_streaming(struct pd_dvb_adapter *pd_dvb) -{ - struct poseidon *pd = pd_dvb->pd_device; - - mutex_lock(&pd->lock); - if (pd_dvb->is_streaming) { - s32 i, ret, cmd_status = 0; - - pd_dvb->is_streaming = 0; - - for (i = 0; i < DVB_SBUF_NUM; i++) - if (pd_dvb->urb_array[i]) - usb_kill_urb(pd_dvb->urb_array[i]); - - ret = send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, - &cmd_status); - if (ret | cmd_status) - log("error"); - } - mutex_unlock(&pd->lock); -} - -static int pd_start_feed(struct dvb_demux_feed *feed) -{ - struct pd_dvb_adapter *pd_dvb = feed->demux->priv; - int ret = 0; - - if (!pd_dvb) - return -1; - if (atomic_inc_return(&pd_dvb->active_feed) == 1) - ret = dvb_start_streaming(pd_dvb); - return ret; -} - -static int pd_stop_feed(struct dvb_demux_feed *feed) -{ - struct pd_dvb_adapter *pd_dvb = feed->demux->priv; - - if (!pd_dvb) - return -1; - if (atomic_dec_and_test(&pd_dvb->active_feed)) - dvb_stop_streaming(pd_dvb); - return 0; -} - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -int pd_dvb_usb_device_init(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - struct dvb_demux *dvbdemux; - int ret = 0; - - pd_dvb->ep_addr = 0x82; - atomic_set(&pd_dvb->users, 0); - atomic_set(&pd_dvb->active_feed, 0); - pd_dvb->pd_device = pd; - - ret = dvb_register_adapter(&pd_dvb->dvb_adap, - "Poseidon dvbt adapter", - THIS_MODULE, - NULL /* for hibernation correctly*/, - adapter_nr); - if (ret < 0) - goto error1; - - /* register frontend */ - pd_dvb->dvb_fe.demodulator_priv = pd; - memcpy(&pd_dvb->dvb_fe.ops, &poseidon_frontend_ops, - sizeof(struct dvb_frontend_ops)); - ret = dvb_register_frontend(&pd_dvb->dvb_adap, &pd_dvb->dvb_fe); - if (ret < 0) - goto error2; - - /* register demux device */ - dvbdemux = &pd_dvb->demux; - dvbdemux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - dvbdemux->priv = pd_dvb; - dvbdemux->feednum = dvbdemux->filternum = 64; - dvbdemux->start_feed = pd_start_feed; - dvbdemux->stop_feed = pd_stop_feed; - dvbdemux->write_to_decoder = NULL; - - ret = dvb_dmx_init(dvbdemux); - if (ret < 0) - goto error3; - - pd_dvb->dmxdev.filternum = pd_dvb->demux.filternum; - pd_dvb->dmxdev.demux = &pd_dvb->demux.dmx; - pd_dvb->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&pd_dvb->dmxdev, &pd_dvb->dvb_adap); - if (ret < 0) - goto error3; - return 0; - -error3: - dvb_unregister_frontend(&pd_dvb->dvb_fe); -error2: - dvb_unregister_adapter(&pd_dvb->dvb_adap); -error1: - return ret; -} - -void pd_dvb_usb_device_exit(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - while (atomic_read(&pd_dvb->users) != 0 - || atomic_read(&pd_dvb->active_feed) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - } - dvb_dmxdev_release(&pd_dvb->dmxdev); - dvb_unregister_frontend(&pd_dvb->dvb_fe); - dvb_unregister_adapter(&pd_dvb->dvb_adap); - pd_dvb_usb_device_cleanup(pd); -} - -void pd_dvb_usb_device_cleanup(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - dvb_urb_cleanup(pd_dvb); -} - -int pd_dvb_get_adapter_num(struct pd_dvb_adapter *pd_dvb) -{ - return pd_dvb->dvb_adap.num; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-main.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-main.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-main.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-main.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,533 +0,0 @@ -/* - * device driver for Telegent tlg2300 based TV cards - * - * Author : - * Kang Yong - * Zhang Xiaobing - * Huang Shijie or - * - * (c) 2009 Telegent Systems - * (c) 2010 Telegent Systems - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vendorcmds.h" -#include "pd-common.h" - -#define VENDOR_ID 0x1B24 -#define PRODUCT_ID 0x4001 -static struct usb_device_id id_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 1) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -int debug_mode; -module_param(debug_mode, int, 0644); -MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose"); - -static const char *firmware_name = "tlg2300_firmware.bin"; -static struct usb_driver poseidon_driver; -static LIST_HEAD(pd_device_list); - -/* - * send set request to USB firmware. - */ -s32 send_set_req(struct poseidon *pd, u8 cmdid, s32 param, s32 *cmd_status) -{ - s32 ret; - s8 data[32] = {}; - u16 lower_16, upper_16; - - if (pd->state & POSEIDON_STATE_DISCONNECT) - return -ENODEV; - - mdelay(30); - - if (param == 0) { - upper_16 = lower_16 = 0; - } else { - /* send 32 bit param as two 16 bit param,little endian */ - lower_16 = (unsigned short)(param & 0xffff); - upper_16 = (unsigned short)((param >> 16) & 0xffff); - } - ret = usb_control_msg(pd->udev, - usb_rcvctrlpipe(pd->udev, 0), - REQ_SET_CMD | cmdid, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - lower_16, - upper_16, - &data, - sizeof(*cmd_status), - USB_CTRL_GET_TIMEOUT); - - if (!ret) { - return -ENXIO; - } else { - /* 1st 4 bytes into cmd_status */ - memcpy((char *)cmd_status, &(data[0]), sizeof(*cmd_status)); - } - return 0; -} - -/* - * send get request to Poseidon firmware. - */ -s32 send_get_req(struct poseidon *pd, u8 cmdid, s32 param, - void *buf, s32 *cmd_status, s32 datalen) -{ - s32 ret; - s8 data[128] = {}; - u16 lower_16, upper_16; - - if (pd->state & POSEIDON_STATE_DISCONNECT) - return -ENODEV; - - mdelay(30); - if (param == 0) { - upper_16 = lower_16 = 0; - } else { - /*send 32 bit param as two 16 bit param, little endian */ - lower_16 = (unsigned short)(param & 0xffff); - upper_16 = (unsigned short)((param >> 16) & 0xffff); - } - ret = usb_control_msg(pd->udev, - usb_rcvctrlpipe(pd->udev, 0), - REQ_GET_CMD | cmdid, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - lower_16, - upper_16, - &data, - (datalen + sizeof(*cmd_status)), - USB_CTRL_GET_TIMEOUT); - - if (ret < 0) { - return -ENXIO; - } else { - /* 1st 4 bytes into cmd_status, remaining data into cmd_data */ - memcpy((char *)cmd_status, &data[0], sizeof(*cmd_status)); - memcpy((char *)buf, &data[sizeof(*cmd_status)], datalen); - } - return 0; -} - -static int pm_notifier_block(struct notifier_block *nb, - unsigned long event, void *dummy) -{ - struct poseidon *pd = NULL; - struct list_head *node, *next; - - switch (event) { - case PM_POST_HIBERNATION: - list_for_each_safe(node, next, &pd_device_list) { - struct usb_device *udev; - struct usb_interface *iface; - int rc = 0; - - pd = container_of(node, struct poseidon, device_list); - udev = pd->udev; - iface = pd->interface; - - /* It will cause the system to reload the firmware */ - rc = usb_lock_device_for_reset(udev, iface); - if (rc >= 0) { - usb_reset_device(udev); - usb_unlock_device(udev); - } - } - break; - default: - break; - } - log("event :%ld\n", event); - return 0; -} - -static struct notifier_block pm_notifer = { - .notifier_call = pm_notifier_block, -}; - -int set_tuner_mode(struct poseidon *pd, unsigned char mode) -{ - s32 ret, cmd_status; - - if (pd->state & POSEIDON_STATE_DISCONNECT) - return -ENODEV; - - ret = send_set_req(pd, TUNE_MODE_SELECT, mode, &cmd_status); - if (ret || cmd_status) - return -ENXIO; - return 0; -} - -void poseidon_delete(struct kref *kref) -{ - struct poseidon *pd = container_of(kref, struct poseidon, kref); - - if (!pd) - return; - list_del_init(&pd->device_list); - - pd_dvb_usb_device_cleanup(pd); - /* clean_audio_data(&pd->audio_data);*/ - - if (pd->udev) { - usb_put_dev(pd->udev); - pd->udev = NULL; - } - if (pd->interface) { - usb_put_intf(pd->interface); - pd->interface = NULL; - } - kfree(pd); - log(); -} - -static int firmware_download(struct usb_device *udev) -{ - int ret = 0, actual_length; - const struct firmware *fw = NULL; - void *fwbuf = NULL; - size_t fwlength = 0, offset; - size_t max_packet_size; - - ret = request_firmware(&fw, firmware_name, &udev->dev); - if (ret) { - log("download err : %d", ret); - return ret; - } - - fwlength = fw->size; - - fwbuf = kmemdup(fw->data, fwlength, GFP_KERNEL); - if (!fwbuf) { - ret = -ENOMEM; - goto out; - } - - max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize; - log("\t\t download size : %d", (int)max_packet_size); - - for (offset = 0; offset < fwlength; offset += max_packet_size) { - actual_length = 0; - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x01), /* ep 1 */ - fwbuf + offset, - min(max_packet_size, fwlength - offset), - &actual_length, - HZ * 10); - if (ret) - break; - } - kfree(fwbuf); -out: - release_firmware(fw); - return ret; -} - -static inline struct poseidon *get_pd(struct usb_interface *intf) -{ - return usb_get_intfdata(intf); -} - -#ifdef CONFIG_PM -/* one-to-one map : poseidon{} <----> usb_device{}'s port */ -static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev) -{ - pd->portnum = udev->portnum; -} - -static inline int get_autopm_ref(struct poseidon *pd) -{ - return pd->video_data.users + pd->vbi_data.users + pd->audio.users - + atomic_read(&pd->dvb_data.users) + pd->radio_data.users; -} - -/* fixup something for poseidon */ -static inline struct poseidon *fixup(struct poseidon *pd) -{ - int count; - - /* old udev and interface have gone, so put back reference . */ - count = get_autopm_ref(pd); - log("count : %d, ref count : %d", count, get_pm_count(pd)); - while (count--) - usb_autopm_put_interface(pd->interface); - /*usb_autopm_set_interface(pd->interface); */ - - usb_put_dev(pd->udev); - usb_put_intf(pd->interface); - log("event : %d\n", pd->msg.event); - return pd; -} - -static struct poseidon *find_old_poseidon(struct usb_device *udev) -{ - struct poseidon *pd; - - list_for_each_entry(pd, &pd_device_list, device_list) { - if (pd->portnum == udev->portnum && in_hibernation(pd)) - return fixup(pd); - } - return NULL; -} - -/* Is the card working now ? */ -static inline int is_working(struct poseidon *pd) -{ - return get_pm_count(pd) > 0; -} - -static int poseidon_suspend(struct usb_interface *intf, pm_message_t msg) -{ - struct poseidon *pd = get_pd(intf); - - if (!pd) - return 0; - if (!is_working(pd)) { - if (get_pm_count(pd) <= 0 && !in_hibernation(pd)) { - pd->msg.event = PM_EVENT_AUTO_SUSPEND; - pd->pm_resume = NULL; /* a good guard */ - printk(KERN_DEBUG "\n\t+ TLG2300 auto suspend +\n\n"); - } - return 0; - } - pd->msg = msg; /* save it here */ - logpm(pd); - return pd->pm_suspend ? pd->pm_suspend(pd) : 0; -} - -static int poseidon_resume(struct usb_interface *intf) -{ - struct poseidon *pd = get_pd(intf); - - if (!pd) - return 0; - printk(KERN_DEBUG "\n\t ++ TLG2300 resume ++\n\n"); - - if (!is_working(pd)) { - if (PM_EVENT_AUTO_SUSPEND == pd->msg.event) - pd->msg = PMSG_ON; - return 0; - } - if (in_hibernation(pd)) { - logpm(pd); - return 0; - } - logpm(pd); - return pd->pm_resume ? pd->pm_resume(pd) : 0; -} - -static void hibernation_resume(struct work_struct *w) -{ - struct poseidon *pd = container_of(w, struct poseidon, pm_work); - int count; - - pd->msg.event = 0; /* clear it here */ - pd->state &= ~POSEIDON_STATE_DISCONNECT; - - /* set the new interface's reference */ - count = get_autopm_ref(pd); - while (count--) - usb_autopm_get_interface(pd->interface); - - /* resume the context */ - logpm(pd); - if (pd->pm_resume) - pd->pm_resume(pd); -} -#else /* CONFIG_PM is not enabled: */ -static inline struct poseidon *find_old_poseidon(struct usb_device *udev) -{ - return NULL; -} - -static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev) -{ -} -#endif - -static bool check_firmware(struct usb_device *udev, int *down_firmware) -{ - void *buf; - int ret; - struct cmd_firmware_vers_s *cmd_firm; - - buf = kzalloc(sizeof(*cmd_firm) + sizeof(u32), GFP_KERNEL); - if (!buf) - return -ENOMEM; - ret = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - REQ_GET_CMD | GET_FW_ID, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, - 0, - buf, - sizeof(*cmd_firm) + sizeof(u32), - USB_CTRL_GET_TIMEOUT); - kfree(buf); - - if (ret < 0) { - *down_firmware = 1; - return firmware_download(udev); - } - return ret; -} - -static int poseidon_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct poseidon *pd = NULL; - int ret = 0; - int new_one = 0; - - /* download firmware */ - check_firmware(udev, &ret); - if (ret) - return 0; - - /* Do I recovery from the hibernate ? */ - pd = find_old_poseidon(udev); - if (!pd) { - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) - return -ENOMEM; - kref_init(&pd->kref); - set_map_flags(pd, udev); - new_one = 1; - } - - pd->udev = usb_get_dev(udev); - pd->interface = usb_get_intf(interface); - usb_set_intfdata(interface, pd); - - if (new_one) { - struct device *dev = &interface->dev; - - logpm(pd); - mutex_init(&pd->lock); - - /* register v4l2 device */ - snprintf(pd->v4l2_dev.name, sizeof(pd->v4l2_dev.name), "%s %s", - dev->driver->name, dev_name(dev)); - ret = v4l2_device_register(NULL, &pd->v4l2_dev); - - /* register devices in directory /dev */ - ret = pd_video_init(pd); - poseidon_audio_init(pd); - poseidon_fm_init(pd); - pd_dvb_usb_device_init(pd); - - INIT_LIST_HEAD(&pd->device_list); - list_add_tail(&pd->device_list, &pd_device_list); - } - - device_init_wakeup(&udev->dev, 1); -#ifdef CONFIG_PM - pm_runtime_set_autosuspend_delay(&pd->udev->dev, - 1000 * PM_SUSPEND_DELAY); - usb_enable_autosuspend(pd->udev); - - if (in_hibernation(pd)) { - INIT_WORK(&pd->pm_work, hibernation_resume); - schedule_work(&pd->pm_work); - } -#endif - return 0; -} - -static void poseidon_disconnect(struct usb_interface *interface) -{ - struct poseidon *pd = get_pd(interface); - - if (!pd) - return; - logpm(pd); - if (in_hibernation(pd)) - return; - - mutex_lock(&pd->lock); - pd->state |= POSEIDON_STATE_DISCONNECT; - mutex_unlock(&pd->lock); - - /* stop urb transferring */ - stop_all_video_stream(pd); - dvb_stop_streaming(&pd->dvb_data); - - /*unregister v4l2 device */ - v4l2_device_unregister(&pd->v4l2_dev); - - pd_dvb_usb_device_exit(pd); - poseidon_fm_exit(pd); - - poseidon_audio_free(pd); - pd_video_exit(pd); - - usb_set_intfdata(interface, NULL); - kref_put(&pd->kref, poseidon_delete); -} - -static struct usb_driver poseidon_driver = { - .name = "poseidon", - .probe = poseidon_probe, - .disconnect = poseidon_disconnect, - .id_table = id_table, -#ifdef CONFIG_PM - .suspend = poseidon_suspend, - .resume = poseidon_resume, -#endif - .supports_autosuspend = 1, -}; - -static int __init poseidon_init(void) -{ - int ret; - - ret = usb_register(&poseidon_driver); - if (ret) - return ret; - register_pm_notifier(&pm_notifer); - return ret; -} - -static void __exit poseidon_exit(void) -{ - log(); - unregister_pm_notifier(&pm_notifer); - usb_deregister(&poseidon_driver); -} - -module_init(poseidon_init); -module_exit(poseidon_exit); - -MODULE_AUTHOR("Telegent Systems"); -MODULE_DESCRIPTION("For tlg2300-based USB device "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-radio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-radio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-radio.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-radio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,423 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pd-common.h" -#include "vendorcmds.h" - -static int set_frequency(struct poseidon *p, __u32 frequency); -static int poseidon_fm_close(struct file *filp); -static int poseidon_fm_open(struct file *filp); - -#define TUNER_FREQ_MIN_FM 76000000 -#define TUNER_FREQ_MAX_FM 108000000 - -#define MAX_PREEMPHASIS (V4L2_PREEMPHASIS_75_uS + 1) -static int preemphasis[MAX_PREEMPHASIS] = { - TLG_TUNE_ASTD_NONE, /* V4L2_PREEMPHASIS_DISABLED */ - TLG_TUNE_ASTD_FM_EUR, /* V4L2_PREEMPHASIS_50_uS */ - TLG_TUNE_ASTD_FM_US, /* V4L2_PREEMPHASIS_75_uS */ -}; - -static int poseidon_check_mode_radio(struct poseidon *p) -{ - int ret; - u32 status; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/2); - ret = usb_set_interface(p->udev, 0, BULK_ALTERNATE_IFACE); - if (ret < 0) - goto out; - - ret = set_tuner_mode(p, TLG_MODE_FM_RADIO); - if (ret != 0) - goto out; - - ret = send_set_req(p, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &status); - ret = send_set_req(p, TUNER_AUD_ANA_STD, - p->radio_data.pre_emphasis, &status); - ret |= send_set_req(p, TUNER_AUD_MODE, - TLG_TUNE_TVAUDIO_MODE_STEREO, &status); - ret |= send_set_req(p, AUDIO_SAMPLE_RATE_SEL, - ATV_AUDIO_RATE_48K, &status); - ret |= send_set_req(p, TUNE_FREQ_SELECT, TUNER_FREQ_MIN_FM, &status); -out: - return ret; -} - -#ifdef CONFIG_PM -static int pm_fm_suspend(struct poseidon *p) -{ - logpm(p); - pm_alsa_suspend(p); - usb_set_interface(p->udev, 0, 0); - msleep(300); - return 0; -} - -static int pm_fm_resume(struct poseidon *p) -{ - logpm(p); - poseidon_check_mode_radio(p); - set_frequency(p, p->radio_data.fm_freq); - pm_alsa_resume(p); - return 0; -} -#endif - -static int poseidon_fm_open(struct file *filp) -{ - struct video_device *vfd = video_devdata(filp); - struct poseidon *p = video_get_drvdata(vfd); - int ret = 0; - - if (!p) - return -1; - - mutex_lock(&p->lock); - if (p->state & POSEIDON_STATE_DISCONNECT) { - ret = -ENODEV; - goto out; - } - - if (p->state && !(p->state & POSEIDON_STATE_FM)) { - ret = -EBUSY; - goto out; - } - - usb_autopm_get_interface(p->interface); - if (0 == p->state) { - /* default pre-emphasis */ - if (p->radio_data.pre_emphasis == 0) - p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR; - set_debug_mode(vfd, debug_mode); - - ret = poseidon_check_mode_radio(p); - if (ret < 0) { - usb_autopm_put_interface(p->interface); - goto out; - } - p->state |= POSEIDON_STATE_FM; - } - p->radio_data.users++; - kref_get(&p->kref); - filp->private_data = p; -out: - mutex_unlock(&p->lock); - return ret; -} - -static int poseidon_fm_close(struct file *filp) -{ - struct poseidon *p = filp->private_data; - struct radio_data *fm = &p->radio_data; - uint32_t status; - - mutex_lock(&p->lock); - fm->users--; - if (0 == fm->users) - p->state &= ~POSEIDON_STATE_FM; - - if (fm->is_radio_streaming && filp == p->file_for_stream) { - fm->is_radio_streaming = 0; - send_set_req(p, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, &status); - } - usb_autopm_put_interface(p->interface); - mutex_unlock(&p->lock); - - kref_put(&p->kref, poseidon_delete); - filp->private_data = NULL; - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - struct poseidon *p = file->private_data; - - strlcpy(v->driver, "tele-radio", sizeof(v->driver)); - strlcpy(v->card, "Telegent Poseidon", sizeof(v->card)); - usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info)); - v->version = KERNEL_VERSION(0, 0, 1); - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static const struct v4l2_file_operations poseidon_fm_fops = { - .owner = THIS_MODULE, - .open = poseidon_fm_open, - .release = poseidon_fm_close, - .ioctl = video_ioctl2, -}; - -static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *vt) -{ - struct tuner_fm_sig_stat_s fm_stat = {}; - int ret, status, count = 5; - struct poseidon *p = file->private_data; - - if (vt->index != 0) - return -EINVAL; - - vt->type = V4L2_TUNER_RADIO; - vt->capability = V4L2_TUNER_CAP_STEREO; - vt->rangelow = TUNER_FREQ_MIN_FM / 62500; - vt->rangehigh = TUNER_FREQ_MAX_FM / 62500; - vt->rxsubchans = V4L2_TUNER_SUB_STEREO; - vt->audmode = V4L2_TUNER_MODE_STEREO; - vt->signal = 0; - vt->afc = 0; - - mutex_lock(&p->lock); - ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO, - &fm_stat, &status, sizeof(fm_stat)); - - while (fm_stat.sig_lock_busy && count-- && !ret) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - - ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO, - &fm_stat, &status, sizeof(fm_stat)); - } - mutex_unlock(&p->lock); - - if (ret || status) { - vt->signal = 0; - } else if ((fm_stat.sig_present || fm_stat.sig_locked) - && fm_stat.sig_strength == 0) { - vt->signal = 0xffff; - } else - vt->signal = (fm_stat.sig_strength * 255 / 10) << 8; - - return 0; -} - -static int fm_get_freq(struct file *file, void *priv, - struct v4l2_frequency *argp) -{ - struct poseidon *p = file->private_data; - - argp->frequency = p->radio_data.fm_freq; - return 0; -} - -static int set_frequency(struct poseidon *p, __u32 frequency) -{ - __u32 freq ; - int ret, status; - - mutex_lock(&p->lock); - - ret = send_set_req(p, TUNER_AUD_ANA_STD, - p->radio_data.pre_emphasis, &status); - - freq = (frequency * 125) * 500 / 1000;/* kHZ */ - if (freq < TUNER_FREQ_MIN_FM/1000 || freq > TUNER_FREQ_MAX_FM/1000) { - ret = -EINVAL; - goto error; - } - - ret = send_set_req(p, TUNE_FREQ_SELECT, freq, &status); - if (ret < 0) - goto error ; - ret = send_set_req(p, TAKE_REQUEST, 0, &status); - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - if (!p->radio_data.is_radio_streaming) { - ret = send_set_req(p, TAKE_REQUEST, 0, &status); - ret = send_set_req(p, PLAY_SERVICE, - TLG_TUNE_PLAY_SVC_START, &status); - p->radio_data.is_radio_streaming = 1; - } - p->radio_data.fm_freq = frequency; -error: - mutex_unlock(&p->lock); - return ret; -} - -static int fm_set_freq(struct file *file, void *priv, - struct v4l2_frequency *argp) -{ - struct poseidon *p = file->private_data; - - p->file_for_stream = file; -#ifdef CONFIG_PM - p->pm_suspend = pm_fm_suspend; - p->pm_resume = pm_fm_resume; -#endif - return set_frequency(p, argp->frequency); -} - -static int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *arg) -{ - return 0; -} - -static int tlg_fm_vidioc_g_exts_ctrl(struct file *file, void *fh, - struct v4l2_ext_controls *ctrls) -{ - struct poseidon *p = file->private_data; - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) - return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) - continue; - - if (i < MAX_PREEMPHASIS) - ctrl->value = p->radio_data.pre_emphasis; - } - return 0; -} - -static int tlg_fm_vidioc_s_exts_ctrl(struct file *file, void *fh, - struct v4l2_ext_controls *ctrls) -{ - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) - return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) - continue; - - if (ctrl->value >= 0 && ctrl->value < MAX_PREEMPHASIS) { - struct poseidon *p = file->private_data; - int pre_emphasis = preemphasis[ctrl->value]; - u32 status; - - send_set_req(p, TUNER_AUD_ANA_STD, - pre_emphasis, &status); - p->radio_data.pre_emphasis = pre_emphasis; - } - } - return 0; -} - -static int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - return 0; -} - -static int tlg_fm_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *ctrl) -{ - if (!(ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) - return -EINVAL; - - ctrl->id &= ~V4L2_CTRL_FLAG_NEXT_CTRL; - if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) { - /* return the next supported control */ - ctrl->id = V4L2_CID_TUNE_PREEMPHASIS; - v4l2_ctrl_query_fill(ctrl, V4L2_PREEMPHASIS_DISABLED, - V4L2_PREEMPHASIS_75_uS, 1, - V4L2_PREEMPHASIS_50_uS); - ctrl->flags = V4L2_CTRL_FLAG_UPDATE; - return 0; - } - return -EINVAL; -} - -static int tlg_fm_vidioc_querymenu(struct file *file, void *fh, - struct v4l2_querymenu *qmenu) -{ - return v4l2_ctrl_query_menu(qmenu, NULL, NULL); -} - -static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) -{ - return vt->index > 0 ? -EINVAL : 0; -} -static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *va) -{ - return (va->index != 0) ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - a->index = 0; - a->mode = 0; - a->capability = V4L2_AUDCAP_STEREO; - strcpy(a->name, "Radio"); - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, u32 i) -{ - return (i != 0) ? -EINVAL : 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, u32 *i) -{ - return (*i != 0) ? -EINVAL : 0; -} - -static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = tlg_fm_vidioc_queryctrl, - .vidioc_querymenu = tlg_fm_vidioc_querymenu, - .vidioc_g_ctrl = tlg_fm_vidioc_g_ctrl, - .vidioc_s_ctrl = tlg_fm_vidioc_s_ctrl, - .vidioc_s_ext_ctrls = tlg_fm_vidioc_s_exts_ctrl, - .vidioc_g_ext_ctrls = tlg_fm_vidioc_g_exts_ctrl, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_tuner = tlg_fm_vidioc_g_tuner, - .vidioc_g_frequency = fm_get_freq, - .vidioc_s_frequency = fm_set_freq, -}; - -static struct video_device poseidon_fm_template = { - .name = "Telegent-Radio", - .fops = &poseidon_fm_fops, - .minor = -1, - .release = video_device_release, - .ioctl_ops = &poseidon_fm_ioctl_ops, -}; - -int poseidon_fm_init(struct poseidon *p) -{ - struct video_device *fm_dev; - - fm_dev = vdev_init(p, &poseidon_fm_template); - if (fm_dev == NULL) - return -1; - - if (video_register_device(fm_dev, VFL_TYPE_RADIO, -1) < 0) { - video_device_release(fm_dev); - return -1; - } - p->radio_data.fm_dev = fm_dev; - return 0; -} - -int poseidon_fm_exit(struct poseidon *p) -{ - destroy_video_device(&p->radio_data.fm_dev); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-video.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/pd-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1669 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "pd-common.h" -#include "vendorcmds.h" - -#ifdef CONFIG_PM -static int pm_video_suspend(struct poseidon *pd); -static int pm_video_resume(struct poseidon *pd); -#endif -static void iso_bubble_handler(struct work_struct *w); - -static int usb_transfer_mode; -module_param(usb_transfer_mode, int, 0644); -MODULE_PARM_DESC(usb_transfer_mode, "0 = Bulk, 1 = Isochronous"); - -static const struct poseidon_format poseidon_formats[] = { - { "YUV 422", V4L2_PIX_FMT_YUYV, 16, 0}, - { "RGB565", V4L2_PIX_FMT_RGB565, 16, 0}, -}; - -static const struct poseidon_tvnorm poseidon_tvnorms[] = { - { V4L2_STD_PAL_D, "PAL-D", TLG_TUNE_VSTD_PAL_D }, - { V4L2_STD_PAL_B, "PAL-B", TLG_TUNE_VSTD_PAL_B }, - { V4L2_STD_PAL_G, "PAL-G", TLG_TUNE_VSTD_PAL_G }, - { V4L2_STD_PAL_H, "PAL-H", TLG_TUNE_VSTD_PAL_H }, - { V4L2_STD_PAL_I, "PAL-I", TLG_TUNE_VSTD_PAL_I }, - { V4L2_STD_PAL_M, "PAL-M", TLG_TUNE_VSTD_PAL_M }, - { V4L2_STD_PAL_N, "PAL-N", TLG_TUNE_VSTD_PAL_N_COMBO }, - { V4L2_STD_PAL_Nc, "PAL-Nc", TLG_TUNE_VSTD_PAL_N_COMBO }, - { V4L2_STD_NTSC_M, "NTSC-M", TLG_TUNE_VSTD_NTSC_M }, - { V4L2_STD_NTSC_M_JP, "NTSC-JP", TLG_TUNE_VSTD_NTSC_M_J }, - { V4L2_STD_SECAM_B, "SECAM-B", TLG_TUNE_VSTD_SECAM_B }, - { V4L2_STD_SECAM_D, "SECAM-D", TLG_TUNE_VSTD_SECAM_D }, - { V4L2_STD_SECAM_G, "SECAM-G", TLG_TUNE_VSTD_SECAM_G }, - { V4L2_STD_SECAM_H, "SECAM-H", TLG_TUNE_VSTD_SECAM_H }, - { V4L2_STD_SECAM_K, "SECAM-K", TLG_TUNE_VSTD_SECAM_K }, - { V4L2_STD_SECAM_K1, "SECAM-K1", TLG_TUNE_VSTD_SECAM_K1 }, - { V4L2_STD_SECAM_L, "SECAM-L", TLG_TUNE_VSTD_SECAM_L }, - { V4L2_STD_SECAM_LC, "SECAM-LC", TLG_TUNE_VSTD_SECAM_L1 }, -}; -static const unsigned int POSEIDON_TVNORMS = ARRAY_SIZE(poseidon_tvnorms); - -struct pd_audio_mode { - u32 tlg_audio_mode; - u32 v4l2_audio_sub; - u32 v4l2_audio_mode; -}; - -static const struct pd_audio_mode pd_audio_modes[] = { - { TLG_TUNE_TVAUDIO_MODE_MONO, V4L2_TUNER_SUB_MONO, - V4L2_TUNER_MODE_MONO }, - { TLG_TUNE_TVAUDIO_MODE_STEREO, V4L2_TUNER_SUB_STEREO, - V4L2_TUNER_MODE_STEREO }, - { TLG_TUNE_TVAUDIO_MODE_LANG_A, V4L2_TUNER_SUB_LANG1, - V4L2_TUNER_MODE_LANG1 }, - { TLG_TUNE_TVAUDIO_MODE_LANG_B, V4L2_TUNER_SUB_LANG2, - V4L2_TUNER_MODE_LANG2 }, - { TLG_TUNE_TVAUDIO_MODE_LANG_C, V4L2_TUNER_SUB_LANG1, - V4L2_TUNER_MODE_LANG1_LANG2 } -}; -static const unsigned int POSEIDON_AUDIOMODS = ARRAY_SIZE(pd_audio_modes); - -struct pd_input { - char *name; - uint32_t tlg_src; -}; - -static const struct pd_input pd_inputs[] = { - { "TV Antenna", TLG_SIG_SRC_ANTENNA }, - { "TV Cable", TLG_SIG_SRC_CABLE }, - { "TV SVideo", TLG_SIG_SRC_SVIDEO }, - { "TV Composite", TLG_SIG_SRC_COMPOSITE } -}; -static const unsigned int POSEIDON_INPUTS = ARRAY_SIZE(pd_inputs); - -struct poseidon_control { - struct v4l2_queryctrl v4l2_ctrl; - enum cmd_custom_param_id vc_id; -}; - -static struct poseidon_control controls[] = { - { - { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, - "brightness", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_BRIGHTNESS_CTRL - }, { - { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, - "contrast", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_CONTRAST_CTRL, - }, { - { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, - "hue", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_HUE_CTRL, - }, { - { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, - "saturation", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_SATURATION_CTRL, - }, -}; - -struct video_std_to_audio_std { - v4l2_std_id video_std; - int audio_std; -}; - -static const struct video_std_to_audio_std video_to_audio_map[] = { - /* country : { 27, 32, 33, 34, 36, 44, 45, 46, 47, 48, 64, - 65, 86, 351, 352, 353, 354, 358, 372, 852, 972 } */ - { (V4L2_STD_PAL_I | V4L2_STD_PAL_B | V4L2_STD_PAL_D | - V4L2_STD_SECAM_L | V4L2_STD_SECAM_D), TLG_TUNE_ASTD_NICAM }, - - /* country : { 1, 52, 54, 55, 886 } */ - {V4L2_STD_NTSC_M | V4L2_STD_PAL_N | V4L2_STD_PAL_M, TLG_TUNE_ASTD_BTSC}, - - /* country : { 81 } */ - { V4L2_STD_NTSC_M_JP, TLG_TUNE_ASTD_EIAJ }, - - /* other country : TLG_TUNE_ASTD_A2 */ -}; -static const unsigned int map_size = ARRAY_SIZE(video_to_audio_map); - -static int get_audio_std(v4l2_std_id v4l2_std) -{ - int i = 0; - - for (; i < map_size; i++) { - if (v4l2_std & video_to_audio_map[i].video_std) - return video_to_audio_map[i].audio_std; - } - return TLG_TUNE_ASTD_A2; -} - -static int vidioc_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) -{ - struct front_face *front = fh; - struct poseidon *p = front->pd; - - logs(front); - - strcpy(cap->driver, "tele-video"); - strcpy(cap->card, "Telegent Poseidon"); - usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->version = KERNEL_VERSION(0, 0, 1); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | - V4L2_CAP_AUDIO | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE; - return 0; -} - -/*====================================================================*/ -static void init_copy(struct video_data *video, bool index) -{ - struct front_face *front = video->front; - - video->field_count = index; - video->lines_copied = 0; - video->prev_left = 0 ; - video->dst = (char *)videobuf_to_vmalloc(front->curr_frame) - + index * video->lines_size; - video->vbi->copied = 0; /* set it here */ -} - -static bool get_frame(struct front_face *front, int *need_init) -{ - struct videobuf_buffer *vb = front->curr_frame; - - if (vb) - return true; - - spin_lock(&front->queue_lock); - if (!list_empty(&front->active)) { - vb = list_entry(front->active.next, - struct videobuf_buffer, queue); - if (need_init) - *need_init = 1; - front->curr_frame = vb; - list_del_init(&vb->queue); - } - spin_unlock(&front->queue_lock); - - return !!vb; -} - -/* check if the video's buffer is ready */ -static bool get_video_frame(struct front_face *front, struct video_data *video) -{ - int need_init = 0; - bool ret = true; - - ret = get_frame(front, &need_init); - if (ret && need_init) - init_copy(video, 0); - return ret; -} - -static void submit_frame(struct front_face *front) -{ - struct videobuf_buffer *vb = front->curr_frame; - - if (vb == NULL) - return; - - front->curr_frame = NULL; - vb->state = VIDEOBUF_DONE; - vb->field_count++; - do_gettimeofday(&vb->ts); - - wake_up(&vb->done); -} - -/* - * A frame is composed of two fields. If we receive all the two fields, - * call the submit_frame() to submit the whole frame to applications. - */ -static void end_field(struct video_data *video) -{ - /* logs(video->front); */ - if (1 == video->field_count) - submit_frame(video->front); - else - init_copy(video, 1); -} - -static void copy_video_data(struct video_data *video, char *src, - unsigned int count) -{ -#define copy_data(len) \ - do { \ - if (++video->lines_copied > video->lines_per_field) \ - goto overflow; \ - memcpy(video->dst, src, len);\ - video->dst += len + video->lines_size; \ - src += len; \ - count -= len; \ - } while (0) - - while (count && count >= video->lines_size) { - if (video->prev_left) { - copy_data(video->prev_left); - video->prev_left = 0; - continue; - } - copy_data(video->lines_size); - } - if (count && count < video->lines_size) { - memcpy(video->dst, src, count); - - video->prev_left = video->lines_size - count; - video->dst += count; - } - return; - -overflow: - end_field(video); -} - -static void check_trailer(struct video_data *video, char *src, int count) -{ - struct vbi_data *vbi = video->vbi; - int offset; /* trailer's offset */ - char *buf; - - offset = (video->context.pix.sizeimage / 2 + vbi->vbi_size / 2) - - (vbi->copied + video->lines_size * video->lines_copied); - if (video->prev_left) - offset -= (video->lines_size - video->prev_left); - - if (offset > count || offset <= 0) - goto short_package; - - buf = src + offset; - - /* trailer : (VFHS) + U32 + U32 + field_num */ - if (!strncmp(buf, "VFHS", 4)) { - int field_num = *((u32 *)(buf + 12)); - - if ((field_num & 1) ^ video->field_count) { - init_copy(video, video->field_count); - return; - } - copy_video_data(video, src, offset); - } -short_package: - end_field(video); -} - -/* ========== Check this more carefully! =========== */ -static inline void copy_vbi_data(struct vbi_data *vbi, - char *src, unsigned int count) -{ - struct front_face *front = vbi->front; - - if (front && get_frame(front, NULL)) { - char *buf = videobuf_to_vmalloc(front->curr_frame); - - if (vbi->video->field_count) - buf += (vbi->vbi_size / 2); - memcpy(buf + vbi->copied, src, count); - } - vbi->copied += count; -} - -/* - * Copy the normal data (VBI or VIDEO) without the trailer. - * VBI is not interlaced, while VIDEO is interlaced. - */ -static inline void copy_vbi_video_data(struct video_data *video, - char *src, unsigned int count) -{ - struct vbi_data *vbi = video->vbi; - unsigned int vbi_delta = (vbi->vbi_size / 2) - vbi->copied; - - if (vbi_delta >= count) { - copy_vbi_data(vbi, src, count); - } else { - if (vbi_delta) { - copy_vbi_data(vbi, src, vbi_delta); - - /* we receive the two fields of the VBI*/ - if (vbi->front && video->field_count) - submit_frame(vbi->front); - } - copy_video_data(video, src + vbi_delta, count - vbi_delta); - } -} - -static void urb_complete_bulk(struct urb *urb) -{ - struct front_face *front = urb->context; - struct video_data *video = &front->pd->video_data; - char *src = (char *)urb->transfer_buffer; - int count = urb->actual_length; - int ret = 0; - - if (!video->is_streaming || urb->status) { - if (urb->status == -EPROTO) - goto resend_it; - return; - } - if (!get_video_frame(front, video)) - goto resend_it; - - if (count == urb->transfer_buffer_length) - copy_vbi_video_data(video, src, count); - else - check_trailer(video, src, count); - -resend_it: - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - log(" submit failed: error %d", ret); -} - -/************************* for ISO *********************/ -#define GET_SUCCESS (0) -#define GET_TRAILER (1) -#define GET_TOO_MUCH_BUBBLE (2) -#define GET_NONE (3) -static int get_chunk(int start, struct urb *urb, - int *head, int *tail, int *bubble_err) -{ - struct usb_iso_packet_descriptor *pkt = NULL; - int ret = GET_SUCCESS; - - for (*head = *tail = -1; start < urb->number_of_packets; start++) { - pkt = &urb->iso_frame_desc[start]; - - /* handle the bubble of the Hub */ - if (-EOVERFLOW == pkt->status) { - if (++*bubble_err > urb->number_of_packets / 3) - return GET_TOO_MUCH_BUBBLE; - continue; - } - - /* This is the gap */ - if (pkt->status || pkt->actual_length <= 0 - || pkt->actual_length > ISO_PKT_SIZE) { - if (*head != -1) - break; - continue; - } - - /* a good isochronous packet */ - if (pkt->actual_length == ISO_PKT_SIZE) { - if (*head == -1) - *head = start; - *tail = start; - continue; - } - - /* trailer is here */ - if (pkt->actual_length < ISO_PKT_SIZE) { - if (*head == -1) { - *head = start; - *tail = start; - return GET_TRAILER; - } - break; - } - } - - if (*head == -1 && *tail == -1) - ret = GET_NONE; - return ret; -} - -/* - * |__|------|___|-----|_______| - * ^ ^ - * | | - * gap gap - */ -static void urb_complete_iso(struct urb *urb) -{ - struct front_face *front = urb->context; - struct video_data *video = &front->pd->video_data; - int bubble_err = 0, head = 0, tail = 0; - char *src = (char *)urb->transfer_buffer; - int ret = 0; - - if (!video->is_streaming) - return; - - do { - if (!get_video_frame(front, video)) - goto out; - - switch (get_chunk(head, urb, &head, &tail, &bubble_err)) { - case GET_SUCCESS: - copy_vbi_video_data(video, src + (head * ISO_PKT_SIZE), - (tail - head + 1) * ISO_PKT_SIZE); - break; - case GET_TRAILER: - check_trailer(video, src + (head * ISO_PKT_SIZE), - ISO_PKT_SIZE); - break; - case GET_NONE: - goto out; - case GET_TOO_MUCH_BUBBLE: - log("\t We got too much bubble"); - schedule_work(&video->bubble_work); - return; - } - } while (head = tail + 1, head < urb->number_of_packets); - -out: - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - log("usb_submit_urb err : %d", ret); -} -/*============================= [ end ] =====================*/ - -static int prepare_iso_urb(struct video_data *video) -{ - struct usb_device *udev = video->pd->udev; - int i; - - if (video->urb_array[0]) - return 0; - - for (i = 0; i < SBUF_NUM; i++) { - struct urb *urb; - void *mem; - int j; - - urb = usb_alloc_urb(PK_PER_URB, GFP_KERNEL); - if (urb == NULL) - goto out; - - video->urb_array[i] = urb; - mem = usb_alloc_coherent(udev, - ISO_PKT_SIZE * PK_PER_URB, - GFP_KERNEL, - &urb->transfer_dma); - - urb->complete = urb_complete_iso; /* handler */ - urb->dev = udev; - urb->context = video->front; - urb->pipe = usb_rcvisocpipe(udev, - video->endpoint_addr); - urb->interval = 1; - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->number_of_packets = PK_PER_URB; - urb->transfer_buffer = mem; - urb->transfer_buffer_length = PK_PER_URB * ISO_PKT_SIZE; - - for (j = 0; j < PK_PER_URB; j++) { - urb->iso_frame_desc[j].offset = ISO_PKT_SIZE * j; - urb->iso_frame_desc[j].length = ISO_PKT_SIZE; - } - } - return 0; -out: - for (; i > 0; i--) - ; - return -ENOMEM; -} - -/* return the succeeded number of the allocation */ -int alloc_bulk_urbs_generic(struct urb **urb_array, int num, - struct usb_device *udev, u8 ep_addr, - int buf_size, gfp_t gfp_flags, - usb_complete_t complete_fn, void *context) -{ - int i = 0; - - for (; i < num; i++) { - void *mem; - struct urb *urb = usb_alloc_urb(0, gfp_flags); - if (urb == NULL) - return i; - - mem = usb_alloc_coherent(udev, buf_size, gfp_flags, - &urb->transfer_dma); - if (mem == NULL) { - usb_free_urb(urb); - return i; - } - - usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, ep_addr), - mem, buf_size, complete_fn, context); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - urb_array[i] = urb; - } - return i; -} - -void free_all_urb_generic(struct urb **urb_array, int num) -{ - int i; - struct urb *urb; - - for (i = 0; i < num; i++) { - urb = urb_array[i]; - if (urb) { - usb_free_coherent(urb->dev, - urb->transfer_buffer_length, - urb->transfer_buffer, - urb->transfer_dma); - usb_free_urb(urb); - urb_array[i] = NULL; - } - } -} - -static int prepare_bulk_urb(struct video_data *video) -{ - if (video->urb_array[0]) - return 0; - - alloc_bulk_urbs_generic(video->urb_array, SBUF_NUM, - video->pd->udev, video->endpoint_addr, - 0x2000, GFP_KERNEL, - urb_complete_bulk, video->front); - return 0; -} - -/* free the URBs */ -static void free_all_urb(struct video_data *video) -{ - free_all_urb_generic(video->urb_array, SBUF_NUM); -} - -static void pd_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - videobuf_vmalloc_free(vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static void pd_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct front_face *front = q->priv_data; - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &front->active); -} - -static int pd_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct front_face *front = q->priv_data; - int rc; - - switch (front->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (VIDEOBUF_NEEDS_INIT == vb->state) { - struct v4l2_pix_format *pix; - - pix = &front->pd->video_data.context.pix; - vb->size = pix->sizeimage; /* real frame size */ - vb->width = pix->width; - vb->height = pix->height; - rc = videobuf_iolock(q, vb, NULL); - if (rc < 0) - return rc; - } - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->size = front->pd->vbi_data.vbi_size; - rc = videobuf_iolock(q, vb, NULL); - if (rc < 0) - return rc; - } - break; - default: - return -EINVAL; - } - vb->field = field; - vb->state = VIDEOBUF_PREPARED; - return 0; -} - -static int fire_all_urb(struct video_data *video) -{ - int i, ret; - - video->is_streaming = 1; - - for (i = 0; i < SBUF_NUM; i++) { - ret = usb_submit_urb(video->urb_array[i], GFP_KERNEL); - if (ret) - log("(%d) failed: error %d", i, ret); - } - return ret; -} - -static int start_video_stream(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - s32 cmd_status; - - send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_START, &cmd_status); - - if (pd->cur_transfer_mode) { - prepare_iso_urb(video); - INIT_WORK(&video->bubble_work, iso_bubble_handler); - } else { - /* The bulk mode does not need a bubble handler */ - prepare_bulk_urb(video); - } - fire_all_urb(video); - return 0; -} - -static int pd_buf_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct front_face *front = q->priv_data; - struct poseidon *pd = front->pd; - - switch (front->type) { - default: - return -EINVAL; - case V4L2_BUF_TYPE_VIDEO_CAPTURE: { - struct video_data *video = &pd->video_data; - struct v4l2_pix_format *pix = &video->context.pix; - - *size = PAGE_ALIGN(pix->sizeimage);/* page aligned frame size */ - if (*count < 4) - *count = 4; - if (1) { - /* same in different altersetting */ - video->endpoint_addr = 0x82; - video->vbi = &pd->vbi_data; - video->vbi->video = video; - video->pd = pd; - video->lines_per_field = pix->height / 2; - video->lines_size = pix->width * 2; - video->front = front; - } - return start_video_stream(pd); - } - - case V4L2_BUF_TYPE_VBI_CAPTURE: { - struct vbi_data *vbi = &pd->vbi_data; - - *size = PAGE_ALIGN(vbi->vbi_size); - log("size : %d", *size); - if (*count == 0) - *count = 4; - } - break; - } - return 0; -} - -static struct videobuf_queue_ops pd_video_qops = { - .buf_setup = pd_buf_setup, - .buf_prepare = pd_buf_prepare, - .buf_queue = pd_buf_queue, - .buf_release = pd_buf_release, -}; - -static int vidioc_enum_fmt(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - if (ARRAY_SIZE(poseidon_formats) <= f->index) - return -EINVAL; - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->flags = 0; - f->pixelformat = poseidon_formats[f->index].fourcc; - strcpy(f->description, poseidon_formats[f->index].name); - return 0; -} - -static int vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - - logs(front); - f->fmt.pix = pd->video_data.context.pix; - return 0; -} - -static int vidioc_try_fmt(struct file *file, void *fh, - struct v4l2_format *f) -{ - return 0; -} - -/* - * VLC calls VIDIOC_S_STD before VIDIOC_S_FMT, while - * Mplayer calls them in the reverse order. - */ -static int pd_vidioc_s_fmt(struct poseidon *pd, struct v4l2_pix_format *pix) -{ - struct video_data *video = &pd->video_data; - struct running_context *context = &video->context; - struct v4l2_pix_format *pix_def = &context->pix; - s32 ret = 0, cmd_status = 0, vid_resol; - - /* set the pixel format to firmware */ - if (pix->pixelformat == V4L2_PIX_FMT_RGB565) { - vid_resol = TLG_TUNER_VID_FORMAT_RGB_565; - } else { - pix->pixelformat = V4L2_PIX_FMT_YUYV; - vid_resol = TLG_TUNER_VID_FORMAT_YUV; - } - ret = send_set_req(pd, VIDEO_STREAM_FMT_SEL, - vid_resol, &cmd_status); - - /* set the resolution to firmware */ - vid_resol = TLG_TUNE_VID_RES_720; - switch (pix->width) { - case 704: - vid_resol = TLG_TUNE_VID_RES_704; - break; - default: - pix->width = 720; - case 720: - break; - } - ret |= send_set_req(pd, VIDEO_ROSOLU_SEL, - vid_resol, &cmd_status); - if (ret || cmd_status) - return -EBUSY; - - pix_def->pixelformat = pix->pixelformat; /* save it */ - pix->height = (context->tvnormid & V4L2_STD_525_60) ? 480 : 576; - - /* Compare with the default setting */ - if ((pix_def->width != pix->width) - || (pix_def->height != pix->height)) { - pix_def->width = pix->width; - pix_def->height = pix->height; - pix_def->bytesperline = pix->width * 2; - pix_def->sizeimage = pix->width * pix->height * 2; - } - *pix = *pix_def; - - return 0; -} - -static int vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - - logs(front); - /* stop VBI here */ - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) - return -EINVAL; - - mutex_lock(&pd->lock); - if (pd->file_for_stream == NULL) - pd->file_for_stream = file; - else if (file != pd->file_for_stream) { - mutex_unlock(&pd->lock); - return -EINVAL; - } - - pd_vidioc_s_fmt(pd, &f->fmt.pix); - mutex_unlock(&pd->lock); - return 0; -} - -static int vidioc_g_fmt_vbi(struct file *file, void *fh, - struct v4l2_format *v4l2_f) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct v4l2_vbi_format *vbi_fmt = &v4l2_f->fmt.vbi; - - vbi_fmt->samples_per_line = 720 * 2; - vbi_fmt->sampling_rate = 6750000 * 4; - vbi_fmt->sample_format = V4L2_PIX_FMT_GREY; - vbi_fmt->offset = 64 * 4; /*FIXME: why offset */ - if (pd->video_data.context.tvnormid & V4L2_STD_525_60) { - vbi_fmt->start[0] = 10; - vbi_fmt->start[1] = 264; - vbi_fmt->count[0] = V4L_NTSC_VBI_LINES; - vbi_fmt->count[1] = V4L_NTSC_VBI_LINES; - } else { - vbi_fmt->start[0] = 6; - vbi_fmt->start[1] = 314; - vbi_fmt->count[0] = V4L_PAL_VBI_LINES; - vbi_fmt->count[1] = V4L_PAL_VBI_LINES; - } - vbi_fmt->flags = V4L2_VBI_UNSYNC; - logs(front); - return 0; -} - -static int set_std(struct poseidon *pd, v4l2_std_id *norm) -{ - struct video_data *video = &pd->video_data; - struct vbi_data *vbi = &pd->vbi_data; - struct running_context *context; - struct v4l2_pix_format *pix; - s32 i, ret = 0, cmd_status, param; - int height; - - for (i = 0; i < POSEIDON_TVNORMS; i++) { - if (*norm & poseidon_tvnorms[i].v4l2_id) { - param = poseidon_tvnorms[i].tlg_tvnorm; - log("name : %s", poseidon_tvnorms[i].name); - goto found; - } - } - return -EINVAL; -found: - mutex_lock(&pd->lock); - ret = send_set_req(pd, VIDEO_STD_SEL, param, &cmd_status); - if (ret || cmd_status) - goto out; - - /* Set vbi size and check the height of the frame */ - context = &video->context; - context->tvnormid = poseidon_tvnorms[i].v4l2_id; - if (context->tvnormid & V4L2_STD_525_60) { - vbi->vbi_size = V4L_NTSC_VBI_FRAMESIZE; - height = 480; - } else { - vbi->vbi_size = V4L_PAL_VBI_FRAMESIZE; - height = 576; - } - - pix = &context->pix; - if (pix->height != height) { - pix->height = height; - pix->sizeimage = pix->width * pix->height * 2; - } - -out: - mutex_unlock(&pd->lock); - return ret; -} - -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - struct front_face *front = fh; - logs(front); - return set_std(front->pd, norm); -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) -{ - struct front_face *front = fh; - - if (in->index < 0 || in->index >= POSEIDON_INPUTS) - return -EINVAL; - strcpy(in->name, pd_inputs[in->index].name); - in->type = V4L2_INPUT_TYPE_TUNER; - - /* - * the audio input index mixed with this video input, - * Poseidon only have one audio/video, set to "0" - */ - in->audioset = 0; - in->tuner = 0; - in->std = V4L2_STD_ALL; - in->status = 0; - logs(front); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct running_context *context = &pd->video_data.context; - - logs(front); - *i = context->sig_index; - return 0; -} - -/* We can support several inputs */ -static int vidioc_s_input(struct file *file, void *fh, unsigned int i) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - s32 ret, cmd_status; - - if (i < 0 || i >= POSEIDON_INPUTS) - return -EINVAL; - ret = send_set_req(pd, SGNL_SRC_SEL, - pd_inputs[i].tlg_src, &cmd_status); - if (ret) - return ret; - - pd->video_data.context.sig_index = i; - return 0; -} - -static struct poseidon_control *check_control_id(__u32 id) -{ - struct poseidon_control *control = &controls[0]; - int array_size = ARRAY_SIZE(controls); - - for (; control < &controls[array_size]; control++) - if (control->v4l2_ctrl.id == id) - return control; - return NULL; -} - -static int vidioc_queryctrl(struct file *file, void *fh, - struct v4l2_queryctrl *a) -{ - struct poseidon_control *control = NULL; - - control = check_control_id(a->id); - if (!control) - return -EINVAL; - - *a = control->v4l2_ctrl; - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct poseidon_control *control = NULL; - struct tuner_custom_parameter_s tuner_param; - s32 ret = 0, cmd_status; - - control = check_control_id(ctrl->id); - if (!control) - return -EINVAL; - - mutex_lock(&pd->lock); - ret = send_get_req(pd, TUNER_CUSTOM_PARAMETER, control->vc_id, - &tuner_param, &cmd_status, sizeof(tuner_param)); - mutex_unlock(&pd->lock); - - if (ret || cmd_status) - return -1; - - ctrl->value = tuner_param.param_value; - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) -{ - struct tuner_custom_parameter_s param = {0}; - struct poseidon_control *control = NULL; - struct front_face *front = fh; - struct poseidon *pd = front->pd; - s32 ret = 0, cmd_status, params; - - control = check_control_id(a->id); - if (!control) - return -EINVAL; - - param.param_value = a->value; - param.param_id = control->vc_id; - params = *(s32 *)¶m; /* temp code */ - - mutex_lock(&pd->lock); - ret = send_set_req(pd, TUNER_CUSTOM_PARAMETER, params, &cmd_status); - ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - mutex_unlock(&pd->lock); - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - return ret; -} - -/* Audio ioctls */ -static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) -{ - if (0 != a->index) - return -EINVAL; - a->capability = V4L2_AUDCAP_STEREO; - strcpy(a->name, "USB audio in"); - /*Poseidon have no AVL function.*/ - a->mode = 0; - return 0; -} - -static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - a->index = 0; - a->capability = V4L2_AUDCAP_STEREO; - strcpy(a->name, "USB audio in"); - a->mode = 0; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - return (0 == a->index) ? 0 : -EINVAL; -} - -/* Tuner ioctls */ -static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *tuner) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct tuner_atv_sig_stat_s atv_stat; - s32 count = 5, ret, cmd_status; - int index; - - if (0 != tuner->index) - return -EINVAL; - - mutex_lock(&pd->lock); - ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV, - &atv_stat, &cmd_status, sizeof(atv_stat)); - - while (atv_stat.sig_lock_busy && count-- && !ret) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - - ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV, - &atv_stat, &cmd_status, sizeof(atv_stat)); - } - mutex_unlock(&pd->lock); - - if (debug_mode) - log("P:%d,S:%d", atv_stat.sig_present, atv_stat.sig_strength); - - if (ret || cmd_status) - tuner->signal = 0; - else if (atv_stat.sig_present && !atv_stat.sig_strength) - tuner->signal = 0xFFFF; - else - tuner->signal = (atv_stat.sig_strength * 255 / 10) << 8; - - strcpy(tuner->name, "Telegent Systems"); - tuner->type = V4L2_TUNER_ANALOG_TV; - tuner->rangelow = TUNER_FREQ_MIN / 62500; - tuner->rangehigh = TUNER_FREQ_MAX / 62500; - tuner->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - index = pd->video_data.context.audio_idx; - tuner->rxsubchans = pd_audio_modes[index].v4l2_audio_sub; - tuner->audmode = pd_audio_modes[index].v4l2_audio_mode; - tuner->afc = 0; - logs(front); - return 0; -} - -static int pd_vidioc_s_tuner(struct poseidon *pd, int index) -{ - s32 ret = 0, cmd_status, param, audiomode; - - mutex_lock(&pd->lock); - param = pd_audio_modes[index].tlg_audio_mode; - ret = send_set_req(pd, TUNER_AUD_MODE, param, &cmd_status); - audiomode = get_audio_std(pd->video_data.context.tvnormid); - ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, - &cmd_status); - if (!ret) - pd->video_data.context.audio_idx = index; - mutex_unlock(&pd->lock); - return ret; -} - -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - int index; - - if (0 != a->index) - return -EINVAL; - logs(front); - for (index = 0; index < POSEIDON_AUDIOMODS; index++) - if (a->audmode == pd_audio_modes[index].v4l2_audio_mode) - return pd_vidioc_s_tuner(pd, index); - return -EINVAL; -} - -static int vidioc_g_frequency(struct file *file, void *fh, - struct v4l2_frequency *freq) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct running_context *context = &pd->video_data.context; - - if (0 != freq->tuner) - return -EINVAL; - freq->frequency = context->freq; - freq->type = V4L2_TUNER_ANALOG_TV; - return 0; -} - -static int set_frequency(struct poseidon *pd, __u32 frequency) -{ - s32 ret = 0, param, cmd_status; - struct running_context *context = &pd->video_data.context; - - param = frequency * 62500 / 1000; - if (param < TUNER_FREQ_MIN/1000 || param > TUNER_FREQ_MAX / 1000) - return -EINVAL; - - mutex_lock(&pd->lock); - ret = send_set_req(pd, TUNE_FREQ_SELECT, param, &cmd_status); - ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - - msleep(250); /* wait for a while until the hardware is ready. */ - context->freq = frequency; - mutex_unlock(&pd->lock); - return ret; -} - -static int vidioc_s_frequency(struct file *file, void *fh, - struct v4l2_frequency *freq) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - - logs(front); -#ifdef CONFIG_PM - pd->pm_suspend = pm_video_suspend; - pd->pm_resume = pm_video_resume; -#endif - return set_frequency(pd, freq->frequency); -} - -static int vidioc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *b) -{ - struct front_face *front = file->private_data; - logs(front); - return videobuf_reqbufs(&front->q, b); -} - -static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct front_face *front = file->private_data; - logs(front); - return videobuf_querybuf(&front->q, b); -} - -static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct front_face *front = file->private_data; - return videobuf_qbuf(&front->q, b); -} - -static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct front_face *front = file->private_data; - return videobuf_dqbuf(&front->q, b, file->f_flags & O_NONBLOCK); -} - -/* Just stop the URBs, do not free the URBs */ -static int usb_transfer_stop(struct video_data *video) -{ - if (video->is_streaming) { - int i; - s32 cmd_status; - struct poseidon *pd = video->pd; - - video->is_streaming = 0; - for (i = 0; i < SBUF_NUM; ++i) { - if (video->urb_array[i]) - usb_kill_urb(video->urb_array[i]); - } - - send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, - &cmd_status); - } - return 0; -} - -int stop_all_video_stream(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - struct vbi_data *vbi = &pd->vbi_data; - - mutex_lock(&pd->lock); - if (video->is_streaming) { - struct front_face *front = video->front; - - /* stop the URBs */ - usb_transfer_stop(video); - free_all_urb(video); - - /* stop the host side of VIDEO */ - videobuf_stop(&front->q); - videobuf_mmap_free(&front->q); - - /* stop the host side of VBI */ - front = vbi->front; - if (front) { - videobuf_stop(&front->q); - videobuf_mmap_free(&front->q); - } - } - mutex_unlock(&pd->lock); - return 0; -} - -/* - * The bubbles can seriously damage the video's quality, - * though it occurs in very rare situation. - */ -static void iso_bubble_handler(struct work_struct *w) -{ - struct video_data *video; - struct poseidon *pd; - - video = container_of(w, struct video_data, bubble_work); - pd = video->pd; - - mutex_lock(&pd->lock); - usb_transfer_stop(video); - msleep(500); - start_video_stream(pd); - mutex_unlock(&pd->lock); -} - - -static int vidioc_streamon(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct front_face *front = fh; - - logs(front); - if (unlikely(type != front->type)) - return -EINVAL; - return videobuf_streamon(&front->q); -} - -static int vidioc_streamoff(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct front_face *front = file->private_data; - - logs(front); - if (unlikely(type != front->type)) - return -EINVAL; - return videobuf_streamoff(&front->q); -} - -/* Set the firmware's default values : need altersetting */ -static int pd_video_checkmode(struct poseidon *pd) -{ - s32 ret = 0, cmd_status, audiomode; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/2); - - /* choose the altersetting */ - ret = usb_set_interface(pd->udev, 0, - (pd->cur_transfer_mode ? - ISO_3K_BULK_ALTERNATE_IFACE : - BULK_ALTERNATE_IFACE)); - if (ret < 0) - goto error; - - /* set default parameters for PAL-D , with the VBI enabled*/ - ret = set_tuner_mode(pd, TLG_MODE_ANALOG_TV); - ret |= send_set_req(pd, SGNL_SRC_SEL, - TLG_SIG_SRC_ANTENNA, &cmd_status); - ret |= send_set_req(pd, VIDEO_STD_SEL, - TLG_TUNE_VSTD_PAL_D, &cmd_status); - ret |= send_set_req(pd, VIDEO_STREAM_FMT_SEL, - TLG_TUNER_VID_FORMAT_YUV, &cmd_status); - ret |= send_set_req(pd, VIDEO_ROSOLU_SEL, - TLG_TUNE_VID_RES_720, &cmd_status); - ret |= send_set_req(pd, TUNE_FREQ_SELECT, TUNER_FREQ_MIN, &cmd_status); - ret |= send_set_req(pd, VBI_DATA_SEL, 1, &cmd_status);/* enable vbi */ - - /* set the audio */ - audiomode = get_audio_std(pd->video_data.context.tvnormid); - ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, &cmd_status); - ret |= send_set_req(pd, TUNER_AUD_MODE, - TLG_TUNE_TVAUDIO_MODE_STEREO, &cmd_status); - ret |= send_set_req(pd, AUDIO_SAMPLE_RATE_SEL, - ATV_AUDIO_RATE_48K, &cmd_status); -error: - return ret; -} - -#ifdef CONFIG_PM -static int pm_video_suspend(struct poseidon *pd) -{ - /* stop audio */ - pm_alsa_suspend(pd); - - /* stop and free all the URBs */ - usb_transfer_stop(&pd->video_data); - free_all_urb(&pd->video_data); - - /* reset the interface */ - usb_set_interface(pd->udev, 0, 0); - msleep(300); - return 0; -} - -static int restore_v4l2_context(struct poseidon *pd, - struct running_context *context) -{ - struct front_face *front = pd->video_data.front; - - pd_video_checkmode(pd); - - set_std(pd, &context->tvnormid); - vidioc_s_input(NULL, front, context->sig_index); - pd_vidioc_s_tuner(pd, context->audio_idx); - pd_vidioc_s_fmt(pd, &context->pix); - set_frequency(pd, context->freq); - return 0; -} - -static int pm_video_resume(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - - /* resume the video */ - /* [1] restore the origin V4L2 parameters */ - restore_v4l2_context(pd, &video->context); - - /* [2] initiate video copy variables */ - if (video->front->curr_frame) - init_copy(video, 0); - - /* [3] fire urbs */ - start_video_stream(pd); - - /* resume the audio */ - pm_alsa_resume(pd); - return 0; -} -#endif - -void set_debug_mode(struct video_device *vfd, int debug_mode) -{ - vfd->debug = 0; - if (debug_mode & 0x1) - vfd->debug = V4L2_DEBUG_IOCTL; - if (debug_mode & 0x2) - vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; -} - -static void init_video_context(struct running_context *context) -{ - context->sig_index = 0; - context->audio_idx = 1; /* stereo */ - context->tvnormid = V4L2_STD_PAL_D; - context->pix = (struct v4l2_pix_format) { - .width = 720, - .height = 576, - .pixelformat = V4L2_PIX_FMT_YUYV, - .field = V4L2_FIELD_INTERLACED, - .bytesperline = 720 * 2, - .sizeimage = 720 * 576 * 2, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - .priv = 0 - }; -} - -static int pd_video_open(struct file *file) -{ - struct video_device *vfd = video_devdata(file); - struct poseidon *pd = video_get_drvdata(vfd); - struct front_face *front = NULL; - int ret = -ENOMEM; - - mutex_lock(&pd->lock); - usb_autopm_get_interface(pd->interface); - - if (vfd->vfl_type == VFL_TYPE_GRABBER - && !(pd->state & POSEIDON_STATE_ANALOG)) { - front = kzalloc(sizeof(struct front_face), GFP_KERNEL); - if (!front) - goto out; - - pd->cur_transfer_mode = usb_transfer_mode;/* bulk or iso */ - init_video_context(&pd->video_data.context); - - ret = pd_video_checkmode(pd); - if (ret < 0) { - kfree(front); - ret = -1; - goto out; - } - - pd->state |= POSEIDON_STATE_ANALOG; - front->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pd->video_data.users++; - set_debug_mode(vfd, debug_mode); - - videobuf_queue_vmalloc_init(&front->q, &pd_video_qops, - NULL, &front->queue_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED,/* video is interlacd */ - sizeof(struct videobuf_buffer),/*it's enough*/ - front, NULL); - } else if (vfd->vfl_type == VFL_TYPE_VBI - && !(pd->state & POSEIDON_STATE_VBI)) { - front = kzalloc(sizeof(struct front_face), GFP_KERNEL); - if (!front) - goto out; - - pd->state |= POSEIDON_STATE_VBI; - front->type = V4L2_BUF_TYPE_VBI_CAPTURE; - pd->vbi_data.front = front; - pd->vbi_data.users++; - - videobuf_queue_vmalloc_init(&front->q, &pd_video_qops, - NULL, &front->queue_lock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_NONE, /* vbi is NONE mode */ - sizeof(struct videobuf_buffer), - front, NULL); - } else { - /* maybe add FM support here */ - log("other "); - ret = -EINVAL; - goto out; - } - - front->pd = pd; - front->curr_frame = NULL; - INIT_LIST_HEAD(&front->active); - spin_lock_init(&front->queue_lock); - - file->private_data = front; - kref_get(&pd->kref); - - mutex_unlock(&pd->lock); - return 0; -out: - usb_autopm_put_interface(pd->interface); - mutex_unlock(&pd->lock); - return ret; -} - -static int pd_video_release(struct file *file) -{ - struct front_face *front = file->private_data; - struct poseidon *pd = front->pd; - s32 cmd_status = 0; - - logs(front); - mutex_lock(&pd->lock); - - if (front->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - pd->state &= ~POSEIDON_STATE_ANALOG; - - /* stop the device, and free the URBs */ - usb_transfer_stop(&pd->video_data); - free_all_urb(&pd->video_data); - - /* stop the firmware */ - send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, - &cmd_status); - - pd->file_for_stream = NULL; - pd->video_data.users--; - } else if (front->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - pd->state &= ~POSEIDON_STATE_VBI; - pd->vbi_data.front = NULL; - pd->vbi_data.users--; - } - videobuf_stop(&front->q); - videobuf_mmap_free(&front->q); - - usb_autopm_put_interface(pd->interface); - mutex_unlock(&pd->lock); - - kfree(front); - file->private_data = NULL; - kref_put(&pd->kref, poseidon_delete); - return 0; -} - -static int pd_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct front_face *front = file->private_data; - return videobuf_mmap_mapper(&front->q, vma); -} - -static unsigned int pd_video_poll(struct file *file, poll_table *table) -{ - struct front_face *front = file->private_data; - return videobuf_poll_stream(file, &front->q, table); -} - -static ssize_t pd_video_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct front_face *front = file->private_data; - return videobuf_read_stream(&front->q, buffer, count, ppos, - 0, file->f_flags & O_NONBLOCK); -} - -/* This struct works for both VIDEO and VBI */ -static const struct v4l2_file_operations pd_video_fops = { - .owner = THIS_MODULE, - .open = pd_video_open, - .release = pd_video_release, - .read = pd_video_read, - .poll = pd_video_poll, - .mmap = pd_video_mmap, - .ioctl = video_ioctl2, /* maybe changed in future */ -}; - -static const struct v4l2_ioctl_ops pd_video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - - /* Video format */ - .vidioc_g_fmt_vid_cap = vidioc_g_fmt, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt, - .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi, /* VBI */ - .vidioc_try_fmt_vid_cap = vidioc_try_fmt, - - /* Input */ - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_enum_input = vidioc_enum_input, - - /* Audio ioctls */ - .vidioc_enumaudio = vidioc_enumaudio, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - - /* Tuner ioctls */ - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_s_std = vidioc_s_std, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - - /* Buffer handlers */ - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - - /* Stream on/off */ - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - - /* Control handling */ - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static struct video_device pd_video_template = { - .name = "Telegent-Video", - .fops = &pd_video_fops, - .minor = -1, - .release = video_device_release, - .tvnorms = V4L2_STD_ALL, - .ioctl_ops = &pd_video_ioctl_ops, -}; - -struct video_device *vdev_init(struct poseidon *pd, struct video_device *tmp) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (vfd == NULL) - return NULL; - *vfd = *tmp; - vfd->minor = -1; - vfd->v4l2_dev = &pd->v4l2_dev; - /*vfd->parent = &(pd->udev->dev); */ - vfd->release = video_device_release; - video_set_drvdata(vfd, pd); - return vfd; -} - -void destroy_video_device(struct video_device **v_dev) -{ - struct video_device *dev = *v_dev; - - if (dev == NULL) - return; - - if (video_is_registered(dev)) - video_unregister_device(dev); - else - video_device_release(dev); - *v_dev = NULL; -} - -void pd_video_exit(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - struct vbi_data *vbi = &pd->vbi_data; - - destroy_video_device(&video->v_dev); - destroy_video_device(&vbi->v_dev); - log(); -} - -int pd_video_init(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - struct vbi_data *vbi = &pd->vbi_data; - int ret = -ENOMEM; - - video->v_dev = vdev_init(pd, &pd_video_template); - if (video->v_dev == NULL) - goto out; - - ret = video_register_device(video->v_dev, VFL_TYPE_GRABBER, -1); - if (ret != 0) - goto out; - - /* VBI uses the same template as video */ - vbi->v_dev = vdev_init(pd, &pd_video_template); - if (vbi->v_dev == NULL) { - ret = -ENOMEM; - goto out; - } - ret = video_register_device(vbi->v_dev, VFL_TYPE_VBI, -1); - if (ret != 0) - goto out; - log("register VIDEO/VBI devices"); - return 0; -out: - log("VIDEO/VBI devices register failed, : %d", ret); - pd_video_exit(pd); - return ret; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/vendorcmds.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/vendorcmds.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/vendorcmds.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlg2300/vendorcmds.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,243 +0,0 @@ -#ifndef VENDOR_CMD_H_ -#define VENDOR_CMD_H_ - -#define BULK_ALTERNATE_IFACE (2) -#define ISO_3K_BULK_ALTERNATE_IFACE (1) -#define REQ_SET_CMD (0X00) -#define REQ_GET_CMD (0X80) - -enum tlg__analog_audio_standard { - TLG_TUNE_ASTD_NONE = 0x00000000, - TLG_TUNE_ASTD_A2 = 0x00000001, - TLG_TUNE_ASTD_NICAM = 0x00000002, - TLG_TUNE_ASTD_EIAJ = 0x00000004, - TLG_TUNE_ASTD_BTSC = 0x00000008, - TLG_TUNE_ASTD_FM_US = 0x00000010, - TLG_TUNE_ASTD_FM_EUR = 0x00000020, - TLG_TUNE_ASTD_ALL = 0x0000003f -}; - -/* - * identifiers for Custom Parameter messages. - * @typedef cmd_custom_param_id_t - */ -enum cmd_custom_param_id { - CUST_PARM_ID_NONE = 0x00, - CUST_PARM_ID_BRIGHTNESS_CTRL = 0x01, - CUST_PARM_ID_CONTRAST_CTRL = 0x02, - CUST_PARM_ID_HUE_CTRL = 0x03, - CUST_PARM_ID_SATURATION_CTRL = 0x04, - CUST_PARM_ID_AUDIO_SNR_THRESHOLD = 0x10, - CUST_PARM_ID_AUDIO_AGC_THRESHOLD = 0x11, - CUST_PARM_ID_MAX -}; - -struct tuner_custom_parameter_s { - uint16_t param_id; /* Parameter identifier */ - uint16_t param_value; /* Parameter value */ -}; - -struct tuner_ber_rate_s { - uint32_t ber_rate; /* BER sample rate in seconds */ -}; - -struct tuner_atv_sig_stat_s { - uint32_t sig_present; - uint32_t sig_locked; - uint32_t sig_lock_busy; - uint32_t sig_strength; /* milliDb */ - uint32_t tv_audio_chan; /* mono/stereo/sap*/ - uint32_t mvision_stat; /* macrovision status */ -}; - -struct tuner_dtv_sig_stat_s { - uint32_t sig_present; /* Boolean*/ - uint32_t sig_locked; /* Boolean */ - uint32_t sig_lock_busy; /* Boolean (Can this time-out?) */ - uint32_t sig_strength; /* milliDb*/ -}; - -struct tuner_fm_sig_stat_s { - uint32_t sig_present; /* Boolean*/ - uint32_t sig_locked; /* Boolean */ - uint32_t sig_lock_busy; /* Boolean */ - uint32_t sig_stereo_mono;/* TBD*/ - uint32_t sig_strength; /* milliDb*/ -}; - -enum _tag_tlg_tune_srv_cmd { - TLG_TUNE_PLAY_SVC_START = 1, - TLG_TUNE_PLAY_SVC_STOP -}; - -enum _tag_tune_atv_audio_mode_caps { - TLG_TUNE_TVAUDIO_MODE_MONO = 0x00000001, - TLG_TUNE_TVAUDIO_MODE_STEREO = 0x00000002, - TLG_TUNE_TVAUDIO_MODE_LANG_A = 0x00000010,/* Primary language*/ - TLG_TUNE_TVAUDIO_MODE_LANG_B = 0x00000020,/* 2nd avail language*/ - TLG_TUNE_TVAUDIO_MODE_LANG_C = 0x00000040 -}; - - -enum _tag_tuner_atv_audio_rates { - ATV_AUDIO_RATE_NONE = 0x00,/* Audio not supported*/ - ATV_AUDIO_RATE_32K = 0x01,/* Audio rate = 32 KHz*/ - ATV_AUDIO_RATE_48K = 0x02, /* Audio rate = 48 KHz*/ - ATV_AUDIO_RATE_31_25K = 0x04 /* Audio rate = 31.25KHz */ -}; - -enum _tag_tune_atv_vid_res_caps { - TLG_TUNE_VID_RES_NONE = 0x00000000, - TLG_TUNE_VID_RES_720 = 0x00000001, - TLG_TUNE_VID_RES_704 = 0x00000002, - TLG_TUNE_VID_RES_360 = 0x00000004 -}; - -enum _tag_tuner_analog_video_format { - TLG_TUNER_VID_FORMAT_YUV = 0x00000001, - TLG_TUNER_VID_FORMAT_YCRCB = 0x00000002, - TLG_TUNER_VID_FORMAT_RGB_565 = 0x00000004, -}; - -enum tlg_ext_audio_support { - TLG_EXT_AUDIO_NONE = 0x00,/* No external audio input supported */ - TLG_EXT_AUDIO_LR = 0x01/* LR external audio inputs supported*/ -}; - -enum { - TLG_MODE_NONE = 0x00, /* No Mode specified*/ - TLG_MODE_ANALOG_TV = 0x01, /* Analog Television mode*/ - TLG_MODE_ANALOG_TV_UNCOMP = 0x01, /* Analog Television mode*/ - TLG_MODE_ANALOG_TV_COMP = 0x02, /* Analog TV mode (compressed)*/ - TLG_MODE_FM_RADIO = 0x04, /* FM Radio mode*/ - TLG_MODE_DVB_T = 0x08, /* Digital TV (DVB-T)*/ -}; - -enum tlg_signal_sources_t { - TLG_SIG_SRC_NONE = 0x00,/* Signal source not specified */ - TLG_SIG_SRC_ANTENNA = 0x01,/* Signal src is: Antenna */ - TLG_SIG_SRC_CABLE = 0x02,/* Signal src is: Coax Cable*/ - TLG_SIG_SRC_SVIDEO = 0x04,/* Signal src is: S_VIDEO */ - TLG_SIG_SRC_COMPOSITE = 0x08 /* Signal src is: Composite Video */ -}; - -enum tuner_analog_video_standard { - TLG_TUNE_VSTD_NONE = 0x00000000, - TLG_TUNE_VSTD_NTSC_M = 0x00000001, - TLG_TUNE_VSTD_NTSC_M_J = 0x00000002,/* Japan */ - TLG_TUNE_VSTD_PAL_B = 0x00000010, - TLG_TUNE_VSTD_PAL_D = 0x00000020, - TLG_TUNE_VSTD_PAL_G = 0x00000040, - TLG_TUNE_VSTD_PAL_H = 0x00000080, - TLG_TUNE_VSTD_PAL_I = 0x00000100, - TLG_TUNE_VSTD_PAL_M = 0x00000200, - TLG_TUNE_VSTD_PAL_N = 0x00000400, - TLG_TUNE_VSTD_SECAM_B = 0x00001000, - TLG_TUNE_VSTD_SECAM_D = 0x00002000, - TLG_TUNE_VSTD_SECAM_G = 0x00004000, - TLG_TUNE_VSTD_SECAM_H = 0x00008000, - TLG_TUNE_VSTD_SECAM_K = 0x00010000, - TLG_TUNE_VSTD_SECAM_K1 = 0x00020000, - TLG_TUNE_VSTD_SECAM_L = 0x00040000, - TLG_TUNE_VSTD_SECAM_L1 = 0x00080000, - TLG_TUNE_VSTD_PAL_N_COMBO = 0x00100000 -}; - -enum tlg_mode_caps { - TLG_MODE_CAPS_NONE = 0x00, /* No Mode specified */ - TLG_MODE_CAPS_ANALOG_TV_UNCOMP = 0x01, /* Analog TV mode */ - TLG_MODE_CAPS_ANALOG_TV_COMP = 0x02, /* Analog TV (compressed)*/ - TLG_MODE_CAPS_FM_RADIO = 0x04, /* FM Radio mode */ - TLG_MODE_CAPS_DVB_T = 0x08, /* Digital TV (DVB-T) */ -}; - -enum poseidon_vendor_cmds { - LAST_CMD_STAT = 0x00, - GET_CHIP_ID = 0x01, - GET_FW_ID = 0x02, - PRODUCT_CAPS = 0x03, - - TUNE_MODE_CAP_ATV = 0x10, - TUNE_MODE_CAP_ATVCOMP = 0X10, - TUNE_MODE_CAP_DVBT = 0x10, - TUNE_MODE_CAP_FM = 0x10, - TUNE_MODE_SELECT = 0x11, - TUNE_FREQ_SELECT = 0x12, - SGNL_SRC_SEL = 0x13, - - VIDEO_STD_SEL = 0x14, - VIDEO_STREAM_FMT_SEL = 0x15, - VIDEO_ROSOLU_AVAIL = 0x16, - VIDEO_ROSOLU_SEL = 0x17, - VIDEO_CONT_PROTECT = 0x20, - - VCR_TIMING_MODSEL = 0x21, - EXT_AUDIO_CAP = 0x22, - EXT_AUDIO_SEL = 0x23, - TEST_PATTERN_SEL = 0x24, - VBI_DATA_SEL = 0x25, - AUDIO_SAMPLE_RATE_CAP = 0x28, - AUDIO_SAMPLE_RATE_SEL = 0x29, - TUNER_AUD_MODE = 0x2a, - TUNER_AUD_MODE_AVAIL = 0x2b, - TUNER_AUD_ANA_STD = 0x2c, - TUNER_CUSTOM_PARAMETER = 0x2f, - - DVBT_TUNE_MODE_SEL = 0x30, - DVBT_BANDW_CAP = 0x31, - DVBT_BANDW_SEL = 0x32, - DVBT_GUARD_INTERV_CAP = 0x33, - DVBT_GUARD_INTERV_SEL = 0x34, - DVBT_MODULATION_CAP = 0x35, - DVBT_MODULATION_SEL = 0x36, - DVBT_INNER_FEC_RATE_CAP = 0x37, - DVBT_INNER_FEC_RATE_SEL = 0x38, - DVBT_TRANS_MODE_CAP = 0x39, - DVBT_TRANS_MODE_SEL = 0x3a, - DVBT_SEARCH_RANG = 0x3c, - - TUNER_SETUP_ANALOG = 0x40, - TUNER_SETUP_DIGITAL = 0x41, - TUNER_SETUP_FM_RADIO = 0x42, - TAKE_REQUEST = 0x43, /* Take effect of the command */ - PLAY_SERVICE = 0x44, /* Play start or Play stop */ - TUNER_STATUS = 0x45, - TUNE_PROP_DVBT = 0x46, - ERR_RATE_STATS = 0x47, - TUNER_BER_RATE = 0x48, - - SCAN_CAPS = 0x50, - SCAN_SETUP = 0x51, - SCAN_SERVICE = 0x52, - SCAN_STATS = 0x53, - - PID_SET = 0x58, - PID_UNSET = 0x59, - PID_LIST = 0x5a, - - IRD_CAP = 0x60, - IRD_MODE_SEL = 0x61, - IRD_SETUP = 0x62, - - PTM_MODE_CAP = 0x70, - PTM_MODE_SEL = 0x71, - PTM_SERVICE = 0x72, - TUNER_REG_SCRIPT = 0x73, - CMD_CHIP_RST = 0x74, -}; - -enum tlg_bw { - TLG_BW_5 = 5, - TLG_BW_6 = 6, - TLG_BW_7 = 7, - TLG_BW_8 = 8, - TLG_BW_12 = 12, - TLG_BW_15 = 15 -}; - -struct cmd_firmware_vers_s { - uint8_t fw_rev_major; - uint8_t fw_rev_minor; - uint16_t fw_patch; -}; -#endif /* VENDOR_CMD_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlv320aic23b.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlv320aic23b.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlv320aic23b.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tlv320aic23b.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,241 +0,0 @@ -/* - * tlv320aic23b - driver version 0.0.1 - * - * Copyright (C) 2006 Scott Alfter - * - * Based on wm8775 driver - * - * Copyright (C) 2004 Ulf Eklund - * Copyright (C) 2005 Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("tlv320aic23b driver"); -MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil"); -MODULE_LICENSE("GPL"); - - -/* ----------------------------------------------------------------------- */ - -struct tlv320aic23b_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; -}; - -static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct tlv320aic23b_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct tlv320aic23b_state, hdl)->sd; -} - -static int tlv320aic23b_write(struct v4l2_subdev *sd, int reg, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int i; - - if ((reg < 0 || reg > 9) && (reg != 15)) { - v4l2_err(sd, "Invalid register R%d\n", reg); - return -1; - } - - for (i = 0; i < 3; i++) - if (i2c_smbus_write_byte_data(client, - (reg << 1) | (val >> 8), val & 0xff) == 0) - return 0; - v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg); - return -1; -} - -static int tlv320aic23b_s_clock_freq(struct v4l2_subdev *sd, u32 freq) -{ - switch (freq) { - case 32000: /* set sample rate to 32 kHz */ - tlv320aic23b_write(sd, 8, 0x018); - break; - case 44100: /* set sample rate to 44.1 kHz */ - tlv320aic23b_write(sd, 8, 0x022); - break; - case 48000: /* set sample rate to 48 kHz */ - tlv320aic23b_write(sd, 8, 0x000); - break; - default: - return -EINVAL; - } - return 0; -} - -static int tlv320aic23b_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */ - /* set gain on both channels to +3.0 dB */ - if (!ctrl->val) - tlv320aic23b_write(sd, 0, 0x119); - return 0; - } - return -EINVAL; -} - -static int tlv320aic23b_log_status(struct v4l2_subdev *sd) -{ - struct tlv320aic23b_state *state = to_state(sd); - - v4l2_ctrl_handler_log_status(&state->hdl, sd->name); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops tlv320aic23b_ctrl_ops = { - .s_ctrl = tlv320aic23b_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = { - .log_status = tlv320aic23b_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - -static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = { - .s_clock_freq = tlv320aic23b_s_clock_freq, -}; - -static const struct v4l2_subdev_ops tlv320aic23b_ops = { - .core = &tlv320aic23b_core_ops, - .audio = &tlv320aic23b_audio_ops, -}; - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ - -/* - * Generic i2c probe - * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' - */ - -static int tlv320aic23b_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tlv320aic23b_state *state; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kzalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &tlv320aic23b_ops); - - /* Initialize tlv320aic23b */ - - /* RESET */ - tlv320aic23b_write(sd, 15, 0x000); - /* turn off DAC & mic input */ - tlv320aic23b_write(sd, 6, 0x00A); - /* left-justified, 24-bit, master mode */ - tlv320aic23b_write(sd, 7, 0x049); - /* set gain on both channels to +3.0 dB */ - tlv320aic23b_write(sd, 0, 0x119); - /* set sample rate to 48 kHz */ - tlv320aic23b_write(sd, 8, 0x000); - /* activate digital interface */ - tlv320aic23b_write(sd, 9, 0x001); - - v4l2_ctrl_handler_init(&state->hdl, 1); - v4l2_ctrl_new_std(&state->hdl, &tlv320aic23b_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - sd->ctrl_handler = &state->hdl; - if (state->hdl.error) { - int err = state->hdl.error; - - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return err; - } - v4l2_ctrl_handler_setup(&state->hdl); - return 0; -} - -static int tlv320aic23b_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct tlv320aic23b_state *state = to_state(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id tlv320aic23b_id[] = { - { "tlv320aic23b", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id); - -static struct i2c_driver tlv320aic23b_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tlv320aic23b", - }, - .probe = tlv320aic23b_probe, - .remove = tlv320aic23b_remove, - .id_table = tlv320aic23b_id, -}; - -static __init int init_tlv320aic23b(void) -{ - return i2c_add_driver(&tlv320aic23b_driver); -} - -static __exit void exit_tlv320aic23b(void) -{ - i2c_del_driver(&tlv320aic23b_driver); -} - -module_init(init_tlv320aic23b); -module_exit(exit_tlv320aic23b); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tuner-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tuner-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tuner-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tuner-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1306 +0,0 @@ -/* - * i2c tv tuner chip device driver - * core core, i.e. kernel interfaces, registering and so on - * - * Copyright(c) by Ralph Metzler, Gerd Knorr, Gunther Mayer - * - * Copyright(c) 2005-2011 by Mauro Carvalho Chehab - * - Added support for a separate Radio tuner - * - Major rework and cleanups at the code - * - * This driver supports many devices and the idea is to let the driver - * detect which device is present. So rather than listing all supported - * devices here, we pretend to support a single, fake device type that will - * handle both radio and analog TV tuning. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mt20xx.h" -#include "tda8290.h" -#include "tea5761.h" -#include "tea5767.h" -#include "tuner-xc2028.h" -#include "tuner-simple.h" -#include "tda9887.h" -#include "xc5000.h" -#include "tda18271.h" - -#define UNSET (-1U) - -#define PREFIX (t->i2c->driver->driver.name) - -/* - * Driver modprobe parameters - */ - -/* insmod options used at init time => read/only */ -static unsigned int addr; -static unsigned int no_autodetect; -static unsigned int show_i2c; - -module_param(addr, int, 0444); -module_param(no_autodetect, int, 0444); -module_param(show_i2c, int, 0444); - -/* insmod options used at runtime => read/write */ -static int tuner_debug; -static unsigned int tv_range[2] = { 44, 958 }; -static unsigned int radio_range[2] = { 65, 108 }; -static char pal[] = "--"; -static char secam[] = "--"; -static char ntsc[] = "-"; - -module_param_named(debug, tuner_debug, int, 0644); -module_param_array(tv_range, int, NULL, 0644); -module_param_array(radio_range, int, NULL, 0644); -module_param_string(pal, pal, sizeof(pal), 0644); -module_param_string(secam, secam, sizeof(secam), 0644); -module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); - -/* - * Static vars - */ - -static LIST_HEAD(tuner_list); -static const struct v4l2_subdev_ops tuner_ops; - -/* - * Debug macros - */ - -#define tuner_warn(fmt, arg...) do { \ - printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_dbg(fmt, arg...) do { \ - if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -/* - * Internal struct used inside the driver - */ - -struct tuner { - /* device */ - struct dvb_frontend fe; - struct i2c_client *i2c; - struct v4l2_subdev sd; - struct list_head list; - - /* keep track of the current settings */ - v4l2_std_id std; - unsigned int tv_freq; - unsigned int radio_freq; - unsigned int audmode; - - enum v4l2_tuner_type mode; - unsigned int mode_mask; /* Combination of allowable modes */ - - bool standby; /* Standby mode */ - - unsigned int type; /* chip type id */ - unsigned int config; - const char *name; -}; - -/* - * Function prototypes - */ - -static void set_tv_freq(struct i2c_client *c, unsigned int freq); -static void set_radio_freq(struct i2c_client *c, unsigned int freq); - -/* - * tuner attach/detach logic - */ - -/* This macro allows us to probe dynamically, avoiding static links */ -#ifdef CONFIG_MEDIA_ATTACH -#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ - int __r = -EINVAL; \ - typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ - if (__a) { \ - __r = (int) __a(ARGS); \ - symbol_put(FUNCTION); \ - } else { \ - printk(KERN_ERR "TUNER: Unable to find " \ - "symbol "#FUNCTION"()\n"); \ - } \ - __r; \ -}) - -static void tuner_detach(struct dvb_frontend *fe) -{ - if (fe->ops.tuner_ops.release) { - fe->ops.tuner_ops.release(fe); - symbol_put_addr(fe->ops.tuner_ops.release); - } - if (fe->ops.analog_ops.release) { - fe->ops.analog_ops.release(fe); - symbol_put_addr(fe->ops.analog_ops.release); - } -} -#else -#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ - FUNCTION(ARGS); \ -}) - -static void tuner_detach(struct dvb_frontend *fe) -{ - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); - if (fe->ops.analog_ops.release) - fe->ops.analog_ops.release(fe); -} -#endif - - -static inline struct tuner *to_tuner(struct v4l2_subdev *sd) -{ - return container_of(sd, struct tuner, sd); -} - -/* - * struct analog_demod_ops callbacks - */ - -static void fe_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; - struct tuner *t = fe->analog_demod_priv; - - if (NULL == fe_tuner_ops->set_analog_params) { - tuner_warn("Tuner frontend module has no way to set freq\n"); - return; - } - fe_tuner_ops->set_analog_params(fe, params); -} - -static void fe_standby(struct dvb_frontend *fe) -{ - struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; - - if (fe_tuner_ops->sleep) - fe_tuner_ops->sleep(fe); -} - -static int fe_has_signal(struct dvb_frontend *fe) -{ - u16 strength = 0; - - if (fe->ops.tuner_ops.get_rf_strength) - fe->ops.tuner_ops.get_rf_strength(fe, &strength); - - return strength; -} - -static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; - struct tuner *t = fe->analog_demod_priv; - - if (fe_tuner_ops->set_config) - return fe_tuner_ops->set_config(fe, priv_cfg); - - tuner_warn("Tuner frontend module has no way to set config\n"); - - return 0; -} - -static void tuner_status(struct dvb_frontend *fe); - -static struct analog_demod_ops tuner_analog_ops = { - .set_params = fe_set_params, - .standby = fe_standby, - .has_signal = fe_has_signal, - .set_config = fe_set_config, - .tuner_status = tuner_status -}; - -/* - * Functions to select between radio and TV and tuner probe/remove functions - */ - -/** - * set_type - Sets the tuner type for a given device - * - * @c: i2c_client descriptoy - * @type: type of the tuner (e. g. tuner number) - * @new_mode_mask: Indicates if tuner supports TV and/or Radio - * @new_config: an optional parameter ranging from 0-255 used by - a few tuners to adjust an internal parameter, - like LNA mode - * @tuner_callback: an optional function to be called when switching - * to analog mode - * - * This function applys the tuner config to tuner specified - * by tun_setup structure. It contains several per-tuner initialization "magic" - */ -static void set_type(struct i2c_client *c, unsigned int type, - unsigned int new_mode_mask, unsigned int new_config, - int (*tuner_callback) (void *dev, int component, int cmd, int arg)) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(c)); - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - unsigned char buffer[4]; - int tune_now = 1; - - if (type == UNSET || type == TUNER_ABSENT) { - tuner_dbg("tuner 0x%02x: Tuner type absent\n", c->addr); - return; - } - - t->type = type; - /* prevent invalid config values */ - t->config = new_config < 256 ? new_config : 0; - if (tuner_callback != NULL) { - tuner_dbg("defining GPIO callback\n"); - t->fe.callback = tuner_callback; - } - - /* discard private data, in case set_type() was previously called */ - tuner_detach(&t->fe); - t->fe.analog_demod_priv = NULL; - - switch (t->type) { - case TUNER_MT2032: - if (!dvb_attach(microtune_attach, - &t->fe, t->i2c->adapter, t->i2c->addr)) - goto attach_failed; - break; - case TUNER_PHILIPS_TDA8290: - { - struct tda829x_config cfg = { - .lna_cfg = t->config, - }; - if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter, - t->i2c->addr, &cfg)) - goto attach_failed; - break; - } - case TUNER_TEA5767: - if (!dvb_attach(tea5767_attach, &t->fe, - t->i2c->adapter, t->i2c->addr)) - goto attach_failed; - t->mode_mask = T_RADIO; - break; - case TUNER_TEA5761: - if (!dvb_attach(tea5761_attach, &t->fe, - t->i2c->adapter, t->i2c->addr)) - goto attach_failed; - t->mode_mask = T_RADIO; - break; - case TUNER_PHILIPS_FMD1216ME_MK3: - buffer[0] = 0x0b; - buffer[1] = 0xdc; - buffer[2] = 0x9c; - buffer[3] = 0x60; - i2c_master_send(c, buffer, 4); - mdelay(1); - buffer[2] = 0x86; - buffer[3] = 0x54; - i2c_master_send(c, buffer, 4); - if (!dvb_attach(simple_tuner_attach, &t->fe, - t->i2c->adapter, t->i2c->addr, t->type)) - goto attach_failed; - break; - case TUNER_PHILIPS_TD1316: - buffer[0] = 0x0b; - buffer[1] = 0xdc; - buffer[2] = 0x86; - buffer[3] = 0xa4; - i2c_master_send(c, buffer, 4); - if (!dvb_attach(simple_tuner_attach, &t->fe, - t->i2c->adapter, t->i2c->addr, t->type)) - goto attach_failed; - break; - case TUNER_XC2028: - { - struct xc2028_config cfg = { - .i2c_adap = t->i2c->adapter, - .i2c_addr = t->i2c->addr, - }; - if (!dvb_attach(xc2028_attach, &t->fe, &cfg)) - goto attach_failed; - tune_now = 0; - break; - } - case TUNER_TDA9887: - if (!dvb_attach(tda9887_attach, - &t->fe, t->i2c->adapter, t->i2c->addr)) - goto attach_failed; - break; - case TUNER_XC5000: - { - struct xc5000_config xc5000_cfg = { - .i2c_address = t->i2c->addr, - /* if_khz will be set at dvb_attach() */ - .if_khz = 0, - }; - - if (!dvb_attach(xc5000_attach, - &t->fe, t->i2c->adapter, &xc5000_cfg)) - goto attach_failed; - tune_now = 0; - break; - } - case TUNER_NXP_TDA18271: - { - struct tda18271_config cfg = { - .config = t->config, - .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, - }; - - if (!dvb_attach(tda18271_attach, &t->fe, t->i2c->addr, - t->i2c->adapter, &cfg)) - goto attach_failed; - tune_now = 0; - break; - } - default: - if (!dvb_attach(simple_tuner_attach, &t->fe, - t->i2c->adapter, t->i2c->addr, t->type)) - goto attach_failed; - - break; - } - - if ((NULL == analog_ops->set_params) && - (fe_tuner_ops->set_analog_params)) { - - t->name = fe_tuner_ops->info.name; - - t->fe.analog_demod_priv = t; - memcpy(analog_ops, &tuner_analog_ops, - sizeof(struct analog_demod_ops)); - - } else { - t->name = analog_ops->info.name; - } - - tuner_dbg("type set to %s\n", t->name); - - t->mode_mask = new_mode_mask; - - /* Some tuners require more initialization setup before use, - such as firmware download or device calibration. - trying to set a frequency here will just fail - FIXME: better to move set_freq to the tuner code. This is needed - on analog tuners for PLL to properly work - */ - if (tune_now) { - if (V4L2_TUNER_RADIO == t->mode) - set_radio_freq(c, t->radio_freq); - else - set_tv_freq(c, t->tv_freq); - } - - tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", - c->adapter->name, c->driver->driver.name, c->addr << 1, type, - t->mode_mask); - return; - -attach_failed: - tuner_dbg("Tuner attach for type = %d failed.\n", t->type); - t->type = TUNER_ABSENT; - - return; -} - -/** - * tuner_s_type_addr - Sets the tuner type for a device - * - * @sd: subdev descriptor - * @tun_setup: type to be associated to a given tuner i2c address - * - * This function applys the tuner config to tuner specified - * by tun_setup structure. - * If tuner I2C address is UNSET, then it will only set the device - * if the tuner supports the mode specified in the call. - * If the address is specified, the change will be applied only if - * tuner I2C address matches. - * The call can change the tuner number and the tuner mode. - */ -static int tuner_s_type_addr(struct v4l2_subdev *sd, - struct tuner_setup *tun_setup) -{ - struct tuner *t = to_tuner(sd); - struct i2c_client *c = v4l2_get_subdevdata(sd); - - tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", - tun_setup->type, - tun_setup->addr, - tun_setup->mode_mask, - tun_setup->config); - - if ((t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && - (t->mode_mask & tun_setup->mode_mask))) || - (tun_setup->addr == c->addr)) { - set_type(c, tun_setup->type, tun_setup->mode_mask, - tun_setup->config, tun_setup->tuner_callback); - } else - tuner_dbg("set addr discarded for type %i, mask %x. " - "Asked to change tuner at addr 0x%02x, with mask %x\n", - t->type, t->mode_mask, - tun_setup->addr, tun_setup->mode_mask); - - return 0; -} - -/** - * tuner_s_config - Sets tuner configuration - * - * @sd: subdev descriptor - * @cfg: tuner configuration - * - * Calls tuner set_config() private function to set some tuner-internal - * parameters - */ -static int tuner_s_config(struct v4l2_subdev *sd, - const struct v4l2_priv_tun_config *cfg) -{ - struct tuner *t = to_tuner(sd); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - if (t->type != cfg->tuner) - return 0; - - if (analog_ops->set_config) { - analog_ops->set_config(&t->fe, cfg->priv); - return 0; - } - - tuner_dbg("Tuner frontend module has no way to set config\n"); - return 0; -} - -/** - * tuner_lookup - Seek for tuner adapters - * - * @adap: i2c_adapter struct - * @radio: pointer to be filled if the adapter is radio - * @tv: pointer to be filled if the adapter is TV - * - * Search for existing radio and/or TV tuners on the given I2C adapter, - * discarding demod-only adapters (tda9887). - * - * Note that when this function is called from tuner_probe you can be - * certain no other devices will be added/deleted at the same time, I2C - * core protects against that. - */ -static void tuner_lookup(struct i2c_adapter *adap, - struct tuner **radio, struct tuner **tv) -{ - struct tuner *pos; - - *radio = NULL; - *tv = NULL; - - list_for_each_entry(pos, &tuner_list, list) { - int mode_mask; - - if (pos->i2c->adapter != adap || - strcmp(pos->i2c->driver->driver.name, "tuner")) - continue; - - mode_mask = pos->mode_mask; - if (*radio == NULL && mode_mask == T_RADIO) - *radio = pos; - /* Note: currently TDA9887 is the only demod-only - device. If other devices appear then we need to - make this test more general. */ - else if (*tv == NULL && pos->type != TUNER_TDA9887 && - (pos->mode_mask & T_ANALOG_TV)) - *tv = pos; - } -} - -/** - *tuner_probe - Probes the existing tuners on an I2C bus - * - * @client: i2c_client descriptor - * @id: not used - * - * This routine probes for tuners at the expected I2C addresses. On most - * cases, if a device answers to a given I2C address, it assumes that the - * device is a tuner. On a few cases, however, an additional logic is needed - * to double check if the device is really a tuner, or to identify the tuner - * type, like on tea5767/5761 devices. - * - * During client attach, set_type is called by adapter's attach_inform callback. - * set_type must then be completed by tuner_probe. - */ -static int tuner_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tuner *t; - struct tuner *radio; - struct tuner *tv; - - t = kzalloc(sizeof(struct tuner), GFP_KERNEL); - if (NULL == t) - return -ENOMEM; - v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops); - t->i2c = client; - t->name = "(tuner unset)"; - t->type = UNSET; - t->audmode = V4L2_TUNER_MODE_STEREO; - t->standby = 1; - t->radio_freq = 87.5 * 16000; /* Initial freq range */ - t->tv_freq = 400 * 16; /* Sets freq to VHF High - needed for some PLL's to properly start */ - - if (show_i2c) { - unsigned char buffer[16]; - int i, rc; - - memset(buffer, 0, sizeof(buffer)); - rc = i2c_master_recv(client, buffer, sizeof(buffer)); - tuner_info("I2C RECV = "); - for (i = 0; i < rc; i++) - printk(KERN_CONT "%02x ", buffer[i]); - printk("\n"); - } - - /* autodetection code based on the i2c addr */ - if (!no_autodetect) { - switch (client->addr) { - case 0x10: - if (tuner_symbol_probe(tea5761_autodetection, - t->i2c->adapter, - t->i2c->addr) >= 0) { - t->type = TUNER_TEA5761; - t->mode_mask = T_RADIO; - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv) - tv->mode_mask &= ~T_RADIO; - - goto register_client; - } - kfree(t); - return -ENODEV; - case 0x42: - case 0x43: - case 0x4a: - case 0x4b: - /* If chip is not tda8290, don't register. - since it can be tda9887*/ - if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter, - t->i2c->addr) >= 0) { - tuner_dbg("tda829x detected\n"); - } else { - /* Default is being tda9887 */ - t->type = TUNER_TDA9887; - t->mode_mask = T_RADIO | T_ANALOG_TV; - goto register_client; - } - break; - case 0x60: - if (tuner_symbol_probe(tea5767_autodetection, - t->i2c->adapter, t->i2c->addr) - >= 0) { - t->type = TUNER_TEA5767; - t->mode_mask = T_RADIO; - /* Sets freq to FM range */ - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv) - tv->mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - } - } - - /* Initializes only the first TV tuner on this adapter. Why only the - first? Because there are some devices (notably the ones with TI - tuners) that have more than one i2c address for the *same* device. - Experience shows that, except for just one case, the first - address is the right one. The exception is a Russian tuner - (ACORP_Y878F). So, the desired behavior is just to enable the - first found TV tuner. */ - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv == NULL) { - t->mode_mask = T_ANALOG_TV; - if (radio == NULL) - t->mode_mask |= T_RADIO; - tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); - } - - /* Should be just before return */ -register_client: - /* Sets a default mode */ - if (t->mode_mask & T_ANALOG_TV) - t->mode = V4L2_TUNER_ANALOG_TV; - else - t->mode = V4L2_TUNER_RADIO; - set_type(client, t->type, t->mode_mask, t->config, t->fe.callback); - list_add_tail(&t->list, &tuner_list); - - tuner_info("Tuner %d found with type(s)%s%s.\n", - t->type, - t->mode_mask & T_RADIO ? " Radio" : "", - t->mode_mask & T_ANALOG_TV ? " TV" : ""); - return 0; -} - -/** - * tuner_remove - detaches a tuner - * - * @client: i2c_client descriptor - */ - -static int tuner_remove(struct i2c_client *client) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(client)); - - v4l2_device_unregister_subdev(&t->sd); - tuner_detach(&t->fe); - t->fe.analog_demod_priv = NULL; - - list_del(&t->list); - kfree(t); - return 0; -} - -/* - * Functions to switch between Radio and TV - * - * A few cards have a separate I2C tuner for radio. Those routines - * take care of switching between TV/Radio mode, filtering only the - * commands that apply to the Radio or TV tuner. - */ - -/** - * check_mode - Verify if tuner supports the requested mode - * @t: a pointer to the module's internal struct_tuner - * - * This function checks if the tuner is capable of tuning analog TV, - * digital TV or radio, depending on what the caller wants. If the - * tuner can't support that mode, it returns -EINVAL. Otherwise, it - * returns 0. - * This function is needed for boards that have a separate tuner for - * radio (like devices with tea5767). - */ -static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode) -{ - if ((1 << mode & t->mode_mask) == 0) - return -EINVAL; - - return 0; -} - -/** - * set_mode_freq - Switch tuner to other mode. - * @client: struct i2c_client pointer - * @t: a pointer to the module's internal struct_tuner - * @mode: enum v4l2_type (radio or TV) - * @freq: frequency to set (0 means to use the previous one) - * - * If tuner doesn't support the needed mode (radio or TV), prints a - * debug message and returns -EINVAL, changing its state to standby. - * Otherwise, changes the state and sets frequency to the last value, if - * the tuner can sleep or if it supports both Radio and TV. - */ -static int set_mode_freq(struct i2c_client *client, struct tuner *t, - enum v4l2_tuner_type mode, unsigned int freq) -{ - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - if (mode != t->mode) { - if (check_mode(t, mode) == -EINVAL) { - tuner_dbg("Tuner doesn't support mode %d. " - "Putting tuner to sleep\n", mode); - t->standby = true; - if (analog_ops->standby) - analog_ops->standby(&t->fe); - return -EINVAL; - } - t->mode = mode; - tuner_dbg("Changing to mode %d\n", mode); - } - if (t->mode == V4L2_TUNER_RADIO) { - if (freq) - t->radio_freq = freq; - set_radio_freq(client, t->radio_freq); - } else { - if (freq) - t->tv_freq = freq; - set_tv_freq(client, t->tv_freq); - } - - return 0; -} - -/* - * Functions that are specific for TV mode - */ - -/** - * set_tv_freq - Set tuner frequency, freq in Units of 62.5 kHz = 1/16MHz - * - * @c: i2c_client descriptor - * @freq: frequency - */ -static void set_tv_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(c)); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - struct analog_parameters params = { - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; - - if (t->type == UNSET) { - tuner_warn("tuner type not set\n"); - return; - } - if (NULL == analog_ops->set_params) { - tuner_warn("Tuner has no way to set tv freq\n"); - return; - } - if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) { - tuner_dbg("TV freq (%d.%02d) out of range (%d-%d)\n", - freq / 16, freq % 16 * 100 / 16, tv_range[0], - tv_range[1]); - /* V4L2 spec: if the freq is not possible then the closest - possible value should be selected */ - if (freq < tv_range[0] * 16) - freq = tv_range[0] * 16; - else - freq = tv_range[1] * 16; - } - params.frequency = freq; - tuner_dbg("tv freq set to %d.%02d\n", - freq / 16, freq % 16 * 100 / 16); - t->tv_freq = freq; - t->standby = false; - - analog_ops->set_params(&t->fe, ¶ms); -} - -/** - * tuner_fixup_std - force a given video standard variant - * - * @t: tuner internal struct - * - * A few devices or drivers have problem to detect some standard variations. - * On other operational systems, the drivers generally have a per-country - * code, and some logic to apply per-country hacks. V4L2 API doesn't provide - * such hacks. Instead, it relies on a proper video standard selection from - * the userspace application. However, as some apps are buggy, not allowing - * to distinguish all video standard variations, a modprobe parameter can - * be used to force a video standard match. - */ -static int tuner_fixup_std(struct tuner *t) -{ - if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { - switch (pal[0]) { - case '6': - tuner_dbg("insmod fixup: PAL => PAL-60\n"); - t->std = V4L2_STD_PAL_60; - break; - case 'b': - case 'B': - case 'g': - case 'G': - tuner_dbg("insmod fixup: PAL => PAL-BG\n"); - t->std = V4L2_STD_PAL_BG; - break; - case 'i': - case 'I': - tuner_dbg("insmod fixup: PAL => PAL-I\n"); - t->std = V4L2_STD_PAL_I; - break; - case 'd': - case 'D': - case 'k': - case 'K': - tuner_dbg("insmod fixup: PAL => PAL-DK\n"); - t->std = V4L2_STD_PAL_DK; - break; - case 'M': - case 'm': - tuner_dbg("insmod fixup: PAL => PAL-M\n"); - t->std = V4L2_STD_PAL_M; - break; - case 'N': - case 'n': - if (pal[1] == 'c' || pal[1] == 'C') { - tuner_dbg("insmod fixup: PAL => PAL-Nc\n"); - t->std = V4L2_STD_PAL_Nc; - } else { - tuner_dbg("insmod fixup: PAL => PAL-N\n"); - t->std = V4L2_STD_PAL_N; - } - break; - case '-': - /* default parameter, do nothing */ - break; - default: - tuner_warn("pal= argument not recognised\n"); - break; - } - } - if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { - switch (secam[0]) { - case 'b': - case 'B': - case 'g': - case 'G': - case 'h': - case 'H': - tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n"); - t->std = V4L2_STD_SECAM_B | - V4L2_STD_SECAM_G | - V4L2_STD_SECAM_H; - break; - case 'd': - case 'D': - case 'k': - case 'K': - tuner_dbg("insmod fixup: SECAM => SECAM-DK\n"); - t->std = V4L2_STD_SECAM_DK; - break; - case 'l': - case 'L': - if ((secam[1] == 'C') || (secam[1] == 'c')) { - tuner_dbg("insmod fixup: SECAM => SECAM-L'\n"); - t->std = V4L2_STD_SECAM_LC; - } else { - tuner_dbg("insmod fixup: SECAM => SECAM-L\n"); - t->std = V4L2_STD_SECAM_L; - } - break; - case '-': - /* default parameter, do nothing */ - break; - default: - tuner_warn("secam= argument not recognised\n"); - break; - } - } - - if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) { - switch (ntsc[0]) { - case 'm': - case 'M': - tuner_dbg("insmod fixup: NTSC => NTSC-M\n"); - t->std = V4L2_STD_NTSC_M; - break; - case 'j': - case 'J': - tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n"); - t->std = V4L2_STD_NTSC_M_JP; - break; - case 'k': - case 'K': - tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n"); - t->std = V4L2_STD_NTSC_M_KR; - break; - case '-': - /* default parameter, do nothing */ - break; - default: - tuner_info("ntsc= argument not recognised\n"); - break; - } - } - return 0; -} - -/* - * Functions that are specific for Radio mode - */ - -/** - * set_radio_freq - Set tuner frequency, freq in Units of 62.5 Hz = 1/16kHz - * - * @c: i2c_client descriptor - * @freq: frequency - */ -static void set_radio_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(c)); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - struct analog_parameters params = { - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; - - if (t->type == UNSET) { - tuner_warn("tuner type not set\n"); - return; - } - if (NULL == analog_ops->set_params) { - tuner_warn("tuner has no way to set radio frequency\n"); - return; - } - if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) { - tuner_dbg("radio freq (%d.%02d) out of range (%d-%d)\n", - freq / 16000, freq % 16000 * 100 / 16000, - radio_range[0], radio_range[1]); - /* V4L2 spec: if the freq is not possible then the closest - possible value should be selected */ - if (freq < radio_range[0] * 16000) - freq = radio_range[0] * 16000; - else - freq = radio_range[1] * 16000; - } - params.frequency = freq; - tuner_dbg("radio freq set to %d.%02d\n", - freq / 16000, freq % 16000 * 100 / 16000); - t->radio_freq = freq; - t->standby = false; - - analog_ops->set_params(&t->fe, ¶ms); -} - -/* - * Debug function for reporting tuner status to userspace - */ - -/** - * tuner_status - Dumps the current tuner status at dmesg - * @fe: pointer to struct dvb_frontend - * - * This callback is used only for driver debug purposes, answering to - * VIDIOC_LOG_STATUS. No changes should happen on this call. - */ -static void tuner_status(struct dvb_frontend *fe) -{ - struct tuner *t = fe->analog_demod_priv; - unsigned long freq, freq_fraction; - struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; - struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; - const char *p; - - switch (t->mode) { - case V4L2_TUNER_RADIO: - p = "radio"; - break; - case V4L2_TUNER_DIGITAL_TV: - p = "digital TV"; - break; - case V4L2_TUNER_ANALOG_TV: - default: - p = "analog TV"; - break; - } - if (t->mode == V4L2_TUNER_RADIO) { - freq = t->radio_freq / 16000; - freq_fraction = (t->radio_freq % 16000) * 100 / 16000; - } else { - freq = t->tv_freq / 16; - freq_fraction = (t->tv_freq % 16) * 100 / 16; - } - tuner_info("Tuner mode: %s%s\n", p, - t->standby ? " on standby mode" : ""); - tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); - tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); - if (t->mode != V4L2_TUNER_RADIO) - return; - if (fe_tuner_ops->get_status) { - u32 tuner_status; - - fe_tuner_ops->get_status(&t->fe, &tuner_status); - if (tuner_status & TUNER_STATUS_LOCKED) - tuner_info("Tuner is locked.\n"); - if (tuner_status & TUNER_STATUS_STEREO) - tuner_info("Stereo: yes\n"); - } - if (analog_ops->has_signal) - tuner_info("Signal strength: %d\n", - analog_ops->has_signal(fe)); -} - -/* - * Function to splicitly change mode to radio. Probably not needed anymore - */ - -static int tuner_s_radio(struct v4l2_subdev *sd) -{ - struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (set_mode_freq(client, t, V4L2_TUNER_RADIO, 0) == -EINVAL) - return 0; - return 0; -} - -/* - * Tuner callbacks to handle userspace ioctl's - */ - -/** - * tuner_s_power - controls the power state of the tuner - * @sd: pointer to struct v4l2_subdev - * @on: a zero value puts the tuner to sleep - */ -static int tuner_s_power(struct v4l2_subdev *sd, int on) -{ - struct tuner *t = to_tuner(sd); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - /* FIXME: Why this function don't wake the tuner if on != 0 ? */ - if (on) - return 0; - - tuner_dbg("Putting tuner to sleep\n"); - t->standby = true; - if (analog_ops->standby) - analog_ops->standby(&t->fe); - return 0; -} - -static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (set_mode_freq(client, t, V4L2_TUNER_ANALOG_TV, 0) == -EINVAL) - return 0; - - t->std = std; - tuner_fixup_std(t); - - return 0; -} - -static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) -{ - struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (set_mode_freq(client, t, f->type, f->frequency) == -EINVAL) - return 0; - - return 0; -} - -static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) -{ - struct tuner *t = to_tuner(sd); - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - - if (check_mode(t, f->type) == -EINVAL) - return 0; - f->type = t->mode; - if (fe_tuner_ops->get_frequency && !t->standby) { - u32 abs_freq; - - fe_tuner_ops->get_frequency(&t->fe, &abs_freq); - f->frequency = (V4L2_TUNER_RADIO == t->mode) ? - DIV_ROUND_CLOSEST(abs_freq * 2, 125) : - DIV_ROUND_CLOSEST(abs_freq, 62500); - } else { - f->frequency = (V4L2_TUNER_RADIO == t->mode) ? - t->radio_freq : t->tv_freq; - } - return 0; -} - -static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct tuner *t = to_tuner(sd); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - - if (check_mode(t, vt->type) == -EINVAL) - return 0; - vt->type = t->mode; - if (analog_ops->get_afc) - vt->afc = analog_ops->get_afc(&t->fe); - if (t->mode == V4L2_TUNER_ANALOG_TV) - vt->capability |= V4L2_TUNER_CAP_NORM; - if (t->mode != V4L2_TUNER_RADIO) { - vt->rangelow = tv_range[0] * 16; - vt->rangehigh = tv_range[1] * 16; - return 0; - } - - /* radio mode */ - vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - if (fe_tuner_ops->get_status) { - u32 tuner_status; - - fe_tuner_ops->get_status(&t->fe, &tuner_status); - vt->rxsubchans = - (tuner_status & TUNER_STATUS_STEREO) ? - V4L2_TUNER_SUB_STEREO : - V4L2_TUNER_SUB_MONO; - } - if (analog_ops->has_signal) - vt->signal = analog_ops->has_signal(&t->fe); - vt->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - vt->audmode = t->audmode; - vt->rangelow = radio_range[0] * 16000; - vt->rangehigh = radio_range[1] * 16000; - - return 0; -} - -static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (set_mode_freq(client, t, vt->type, 0) == -EINVAL) - return 0; - - if (t->mode == V4L2_TUNER_RADIO) - t->audmode = vt->audmode; - - return 0; -} - -static int tuner_log_status(struct v4l2_subdev *sd) -{ - struct tuner *t = to_tuner(sd); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - if (analog_ops->tuner_status) - analog_ops->tuner_status(&t->fe); - return 0; -} - -static int tuner_suspend(struct i2c_client *c, pm_message_t state) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(c)); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - tuner_dbg("suspend\n"); - - if (!t->standby && analog_ops->standby) - analog_ops->standby(&t->fe); - - return 0; -} - -static int tuner_resume(struct i2c_client *c) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(c)); - - tuner_dbg("resume\n"); - - if (!t->standby) - set_mode_freq(c, t, t->type, 0); - - return 0; -} - -static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - /* TUNER_SET_CONFIG is still called by tuner-simple.c, so we have - to handle it here. - There must be a better way of doing this... */ - switch (cmd) { - case TUNER_SET_CONFIG: - return tuner_s_config(sd, arg); - } - return -ENOIOCTLCMD; -} - -/* - * Callback structs - */ - -static const struct v4l2_subdev_core_ops tuner_core_ops = { - .log_status = tuner_log_status, - .s_std = tuner_s_std, - .s_power = tuner_s_power, -}; - -static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = { - .s_radio = tuner_s_radio, - .g_tuner = tuner_g_tuner, - .s_tuner = tuner_s_tuner, - .s_frequency = tuner_s_frequency, - .g_frequency = tuner_g_frequency, - .s_type_addr = tuner_s_type_addr, - .s_config = tuner_s_config, -}; - -static const struct v4l2_subdev_ops tuner_ops = { - .core = &tuner_core_ops, - .tuner = &tuner_tuner_ops, -}; - -/* - * I2C structs and module init functions - */ - -static const struct i2c_device_id tuner_id[] = { - { "tuner", }, /* autodetect */ - { } -}; -MODULE_DEVICE_TABLE(i2c, tuner_id); - -static struct i2c_driver tuner_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tuner", - }, - .probe = tuner_probe, - .remove = tuner_remove, - .command = tuner_command, - .suspend = tuner_suspend, - .resume = tuner_resume, - .id_table = tuner_id, -}; - -static __init int init_tuner(void) -{ - return i2c_add_driver(&tuner_driver); -} - -static __exit void exit_tuner(void) -{ - i2c_del_driver(&tuner_driver); -} - -module_init(init_tuner); -module_exit(exit_tuner); - -MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); -MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvaudio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvaudio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvaudio.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvaudio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2089 +0,0 @@ -/* - * Driver for simple i2c audio chips. - * - * Copyright (c) 2000 Gerd Knorr - * based on code by: - * Eric Sandeen (eric_sandeen@bigfoot.com) - * Steve VanDeBogart (vandebo@uclink.berkeley.edu) - * Greg Alexander (galexand@acm.org) - * - * Copyright(c) 2005-2008 Mauro Carvalho Chehab - * - Some cleanups, code fixes, etc - * - Convert it to V4L2 API - * - * This code is placed under the terms of the GNU General Public License - * - * OPTIONS: - * debug - set to 1 if you'd like to see debug messages - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -/* ---------------------------------------------------------------------- */ -/* insmod args */ - -static int debug; /* insmod parameter */ -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("device driver for various i2c TV sound decoder / audiomux chips"); -MODULE_AUTHOR("Eric Sandeen, Steve VanDeBogart, Greg Alexander, Gerd Knorr"); -MODULE_LICENSE("GPL"); - -#define UNSET (-1U) - -/* ---------------------------------------------------------------------- */ -/* our structs */ - -#define MAXREGS 256 - -struct CHIPSTATE; -typedef int (*getvalue)(int); -typedef int (*checkit)(struct CHIPSTATE*); -typedef int (*initialize)(struct CHIPSTATE*); -typedef int (*getmode)(struct CHIPSTATE*); -typedef void (*setmode)(struct CHIPSTATE*, int mode); - -/* i2c command */ -typedef struct AUDIOCMD { - int count; /* # of bytes to send */ - unsigned char bytes[MAXREGS+1]; /* addr, data, data, ... */ -} audiocmd; - -/* chip description */ -struct CHIPDESC { - char *name; /* chip name */ - int addr_lo, addr_hi; /* i2c address range */ - int registers; /* # of registers */ - - int *insmodopt; - checkit checkit; - initialize initialize; - int flags; -#define CHIP_HAS_VOLUME 1 -#define CHIP_HAS_BASSTREBLE 2 -#define CHIP_HAS_INPUTSEL 4 -#define CHIP_NEED_CHECKMODE 8 - - /* various i2c command sequences */ - audiocmd init; - - /* which register has which value */ - int leftreg,rightreg,treblereg,bassreg; - - /* initialize with (defaults to 65535/65535/32768/32768 */ - int leftinit,rightinit,trebleinit,bassinit; - - /* functions to convert the values (v4l -> chip) */ - getvalue volfunc,treblefunc,bassfunc; - - /* get/set mode */ - getmode getmode; - setmode setmode; - - /* input switch register + values for v4l inputs */ - int inputreg; - int inputmap[4]; - int inputmute; - int inputmask; -}; - -/* current state of the chip */ -struct CHIPSTATE { - struct v4l2_subdev sd; - - /* chip-specific description - should point to - an entry at CHIPDESC table */ - struct CHIPDESC *desc; - - /* shadow register set */ - audiocmd shadow; - - /* current settings */ - __u16 left,right,treble,bass,muted,mode; - int prevmode; - int radio; - int input; - - /* thread */ - struct task_struct *thread; - struct timer_list wt; - int watch_stereo; - int audmode; -}; - -static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct CHIPSTATE, sd); -} - - -/* ---------------------------------------------------------------------- */ -/* i2c I/O functions */ - -static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) -{ - struct v4l2_subdev *sd = &chip->sd; - struct i2c_client *c = v4l2_get_subdevdata(sd); - unsigned char buffer[2]; - - if (subaddr < 0) { - v4l2_dbg(1, debug, sd, "chip_write: 0x%x\n", val); - chip->shadow.bytes[1] = val; - buffer[0] = val; - if (1 != i2c_master_send(c, buffer, 1)) { - v4l2_warn(sd, "I/O error (write 0x%x)\n", val); - return -1; - } - } else { - if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { - v4l2_info(sd, - "Tried to access a non-existent register: %d\n", - subaddr); - return -EINVAL; - } - - v4l2_dbg(1, debug, sd, "chip_write: reg%d=0x%x\n", - subaddr, val); - chip->shadow.bytes[subaddr+1] = val; - buffer[0] = subaddr; - buffer[1] = val; - if (2 != i2c_master_send(c, buffer, 2)) { - v4l2_warn(sd, "I/O error (write reg%d=0x%x)\n", - subaddr, val); - return -1; - } - } - return 0; -} - -static int chip_write_masked(struct CHIPSTATE *chip, - int subaddr, int val, int mask) -{ - struct v4l2_subdev *sd = &chip->sd; - - if (mask != 0) { - if (subaddr < 0) { - val = (chip->shadow.bytes[1] & ~mask) | (val & mask); - } else { - if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { - v4l2_info(sd, - "Tried to access a non-existent register: %d\n", - subaddr); - return -EINVAL; - } - - val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask); - } - } - return chip_write(chip, subaddr, val); -} - -static int chip_read(struct CHIPSTATE *chip) -{ - struct v4l2_subdev *sd = &chip->sd; - struct i2c_client *c = v4l2_get_subdevdata(sd); - unsigned char buffer; - - if (1 != i2c_master_recv(c, &buffer, 1)) { - v4l2_warn(sd, "I/O error (read)\n"); - return -1; - } - v4l2_dbg(1, debug, sd, "chip_read: 0x%x\n", buffer); - return buffer; -} - -static int chip_read2(struct CHIPSTATE *chip, int subaddr) -{ - struct v4l2_subdev *sd = &chip->sd; - struct i2c_client *c = v4l2_get_subdevdata(sd); - unsigned char write[1]; - unsigned char read[1]; - struct i2c_msg msgs[2] = { - { c->addr, 0, 1, write }, - { c->addr, I2C_M_RD, 1, read } - }; - - write[0] = subaddr; - - if (2 != i2c_transfer(c->adapter, msgs, 2)) { - v4l2_warn(sd, "I/O error (read2)\n"); - return -1; - } - v4l2_dbg(1, debug, sd, "chip_read2: reg%d=0x%x\n", - subaddr, read[0]); - return read[0]; -} - -static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) -{ - struct v4l2_subdev *sd = &chip->sd; - struct i2c_client *c = v4l2_get_subdevdata(sd); - int i; - - if (0 == cmd->count) - return 0; - - if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) { - v4l2_info(sd, - "Tried to access a non-existent register range: %d to %d\n", - cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1); - return -EINVAL; - } - - /* FIXME: it seems that the shadow bytes are wrong bellow !*/ - - /* update our shadow register set; print bytes if (debug > 0) */ - v4l2_dbg(1, debug, sd, "chip_cmd(%s): reg=%d, data:", - name, cmd->bytes[0]); - for (i = 1; i < cmd->count; i++) { - if (debug) - printk(KERN_CONT " 0x%x", cmd->bytes[i]); - chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i]; - } - if (debug) - printk(KERN_CONT "\n"); - - /* send data to the chip */ - if (cmd->count != i2c_master_send(c, cmd->bytes, cmd->count)) { - v4l2_warn(sd, "I/O error (%s)\n", name); - return -1; - } - return 0; -} - -/* ---------------------------------------------------------------------- */ -/* kernel thread for doing i2c stuff asyncronly - * right now it is used only to check the audio mode (mono/stereo/whatever) - * some time after switching to another TV channel, then turn on stereo - * if available, ... - */ - -static void chip_thread_wake(unsigned long data) -{ - struct CHIPSTATE *chip = (struct CHIPSTATE*)data; - wake_up_process(chip->thread); -} - -static int chip_thread(void *data) -{ - struct CHIPSTATE *chip = data; - struct CHIPDESC *desc = chip->desc; - struct v4l2_subdev *sd = &chip->sd; - int mode; - - v4l2_dbg(1, debug, sd, "thread started\n"); - set_freezable(); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (!kthread_should_stop()) - schedule(); - set_current_state(TASK_RUNNING); - try_to_freeze(); - if (kthread_should_stop()) - break; - v4l2_dbg(1, debug, sd, "thread wakeup\n"); - - /* don't do anything for radio or if mode != auto */ - if (chip->radio || chip->mode != 0) - continue; - - /* have a look what's going on */ - mode = desc->getmode(chip); - if (mode == chip->prevmode) - continue; - - /* chip detected a new audio mode - set it */ - v4l2_dbg(1, debug, sd, "thread checkmode\n"); - - chip->prevmode = mode; - - if (mode & V4L2_TUNER_MODE_STEREO) - desc->setmode(chip, V4L2_TUNER_MODE_STEREO); - if (mode & V4L2_TUNER_MODE_LANG1_LANG2) - desc->setmode(chip, V4L2_TUNER_MODE_STEREO); - else if (mode & V4L2_TUNER_MODE_LANG1) - desc->setmode(chip, V4L2_TUNER_MODE_LANG1); - else if (mode & V4L2_TUNER_MODE_LANG2) - desc->setmode(chip, V4L2_TUNER_MODE_LANG2); - else - desc->setmode(chip, V4L2_TUNER_MODE_MONO); - - /* schedule next check */ - mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); - } - - v4l2_dbg(1, debug, sd, "thread exiting\n"); - return 0; -} - -/* ---------------------------------------------------------------------- */ -/* audio chip descriptions - defines+functions for tda9840 */ - -#define TDA9840_SW 0x00 -#define TDA9840_LVADJ 0x02 -#define TDA9840_STADJ 0x03 -#define TDA9840_TEST 0x04 - -#define TDA9840_MONO 0x10 -#define TDA9840_STEREO 0x2a -#define TDA9840_DUALA 0x12 -#define TDA9840_DUALB 0x1e -#define TDA9840_DUALAB 0x1a -#define TDA9840_DUALBA 0x16 -#define TDA9840_EXTERNAL 0x7a - -#define TDA9840_DS_DUAL 0x20 /* Dual sound identified */ -#define TDA9840_ST_STEREO 0x40 /* Stereo sound identified */ -#define TDA9840_PONRES 0x80 /* Power-on reset detected if = 1 */ - -#define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */ -#define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */ - -static int tda9840_getmode(struct CHIPSTATE *chip) -{ - struct v4l2_subdev *sd = &chip->sd; - int val, mode; - - val = chip_read(chip); - mode = V4L2_TUNER_MODE_MONO; - if (val & TDA9840_DS_DUAL) - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - if (val & TDA9840_ST_STEREO) - mode |= V4L2_TUNER_MODE_STEREO; - - v4l2_dbg(1, debug, sd, "tda9840_getmode(): raw chip read: %d, return: %d\n", - val, mode); - return mode; -} - -static void tda9840_setmode(struct CHIPSTATE *chip, int mode) -{ - int update = 1; - int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e; - - switch (mode) { - case V4L2_TUNER_MODE_MONO: - t |= TDA9840_MONO; - break; - case V4L2_TUNER_MODE_STEREO: - t |= TDA9840_STEREO; - break; - case V4L2_TUNER_MODE_LANG1: - t |= TDA9840_DUALA; - break; - case V4L2_TUNER_MODE_LANG2: - t |= TDA9840_DUALB; - break; - default: - update = 0; - } - - if (update) - chip_write(chip, TDA9840_SW, t); -} - -static int tda9840_checkit(struct CHIPSTATE *chip) -{ - int rc; - rc = chip_read(chip); - /* lower 5 bits should be 0 */ - return ((rc & 0x1f) == 0) ? 1 : 0; -} - -/* ---------------------------------------------------------------------- */ -/* audio chip descriptions - defines+functions for tda985x */ - -/* subaddresses for TDA9855 */ -#define TDA9855_VR 0x00 /* Volume, right */ -#define TDA9855_VL 0x01 /* Volume, left */ -#define TDA9855_BA 0x02 /* Bass */ -#define TDA9855_TR 0x03 /* Treble */ -#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ - -/* subaddresses for TDA9850 */ -#define TDA9850_C4 0x04 /* Control 1 for TDA9850 */ - -/* subaddesses for both chips */ -#define TDA985x_C5 0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */ -#define TDA985x_C6 0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */ -#define TDA985x_C7 0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */ -#define TDA985x_A1 0x08 /* Alignment 1 for both chips */ -#define TDA985x_A2 0x09 /* Alignment 2 for both chips */ -#define TDA985x_A3 0x0a /* Alignment 3 for both chips */ - -/* Masks for bits in TDA9855 subaddresses */ -/* 0x00 - VR in TDA9855 */ -/* 0x01 - VL in TDA9855 */ -/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) - * in 1dB steps - mute is 0x27 */ - - -/* 0x02 - BA in TDA9855 */ -/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) - * in .5dB steps - 0 is 0x0E */ - - -/* 0x03 - TR in TDA9855 */ -/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) - * in 3dB steps - 0 is 0x7 */ - -/* Masks for bits in both chips' subaddresses */ -/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */ -/* Unique to TDA9855: */ -/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf) - * in 3dB steps - mute is 0x0 */ - -/* Unique to TDA9850: */ -/* lower 4 bits control stereo noise threshold, over which stereo turns off - * set to values of 0x00 through 0x0f for Ster1 through Ster16 */ - - -/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/ -/* Unique to TDA9855: */ -#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ -#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ -#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ -#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ - /* Bits 0 to 3 select various combinations - * of line in and line out, only the - * interesting ones are defined */ -#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ -#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ - -/* Unique to TDA9850: */ -/* lower 4 bits contol SAP noise threshold, over which SAP turns off - * set to values of 0x00 through 0x0f for SAP1 through SAP16 */ - - -/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */ -/* Common to TDA9855 and TDA9850: */ -#define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */ -#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ -#define TDA985x_MONO 0 /* Forces Mono output */ -#define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */ - -/* Unique to TDA9855: */ -#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ -#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ -#define TDA9855_LINEAR 0 /* Linear Stereo */ -#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ -#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ -#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ -#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ - -/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */ -/* Common to both TDA9855 and TDA9850: */ -/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) - * in .5dB steps - 0dB is 0x7 */ - -/* 0x08, 0x09 - A1 and A2 (read/write) */ -/* Common to both TDA9855 and TDA9850: */ -/* lower 5 bites are wideband and spectral expander alignment - * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ -#define TDA985x_STP 1<<5 /* Stereo Pilot/detect (read-only) */ -#define TDA985x_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ -#define TDA985x_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ - -/* 0x0a - A3 */ -/* Common to both TDA9855 and TDA9850: */ -/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), - * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ -#define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */ - -static int tda9855_volume(int val) { return val/0x2e8+0x27; } -static int tda9855_bass(int val) { return val/0xccc+0x06; } -static int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; } - -static int tda985x_getmode(struct CHIPSTATE *chip) -{ - int mode; - - mode = ((TDA985x_STP | TDA985x_SAPP) & - chip_read(chip)) >> 4; - /* Add mono mode regardless of SAP and stereo */ - /* Allows forced mono */ - return mode | V4L2_TUNER_MODE_MONO; -} - -static void tda985x_setmode(struct CHIPSTATE *chip, int mode) -{ - int update = 1; - int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f; - - switch (mode) { - case V4L2_TUNER_MODE_MONO: - c6 |= TDA985x_MONO; - break; - case V4L2_TUNER_MODE_STEREO: - c6 |= TDA985x_STEREO; - break; - case V4L2_TUNER_MODE_LANG1: - c6 |= TDA985x_SAP; - break; - default: - update = 0; - } - if (update) - chip_write(chip,TDA985x_C6,c6); -} - - -/* ---------------------------------------------------------------------- */ -/* audio chip descriptions - defines+functions for tda9873h */ - -/* Subaddresses for TDA9873H */ - -#define TDA9873_SW 0x00 /* Switching */ -#define TDA9873_AD 0x01 /* Adjust */ -#define TDA9873_PT 0x02 /* Port */ - -/* Subaddress 0x00: Switching Data - * B7..B0: - * - * B1, B0: Input source selection - * 0, 0 internal - * 1, 0 external stereo - * 0, 1 external mono - */ -#define TDA9873_INP_MASK 3 -#define TDA9873_INTERNAL 0 -#define TDA9873_EXT_STEREO 2 -#define TDA9873_EXT_MONO 1 - -/* B3, B2: output signal select - * B4 : transmission mode - * 0, 0, 1 Mono - * 1, 0, 0 Stereo - * 1, 1, 1 Stereo (reversed channel) - * 0, 0, 0 Dual AB - * 0, 0, 1 Dual AA - * 0, 1, 0 Dual BB - * 0, 1, 1 Dual BA - */ - -#define TDA9873_TR_MASK (7 << 2) -#define TDA9873_TR_MONO 4 -#define TDA9873_TR_STEREO 1 << 4 -#define TDA9873_TR_REVERSE (1 << 3) & (1 << 2) -#define TDA9873_TR_DUALA 1 << 2 -#define TDA9873_TR_DUALB 1 << 3 - -/* output level controls - * B5: output level switch (0 = reduced gain, 1 = normal gain) - * B6: mute (1 = muted) - * B7: auto-mute (1 = auto-mute enabled) - */ - -#define TDA9873_GAIN_NORMAL 1 << 5 -#define TDA9873_MUTE 1 << 6 -#define TDA9873_AUTOMUTE 1 << 7 - -/* Subaddress 0x01: Adjust/standard */ - -/* Lower 4 bits (C3..C0) control stereo adjustment on R channel (-0.6 - +0.7 dB) - * Recommended value is +0 dB - */ - -#define TDA9873_STEREO_ADJ 0x06 /* 0dB gain */ - -/* Bits C6..C4 control FM stantard - * C6, C5, C4 - * 0, 0, 0 B/G (PAL FM) - * 0, 0, 1 M - * 0, 1, 0 D/K(1) - * 0, 1, 1 D/K(2) - * 1, 0, 0 D/K(3) - * 1, 0, 1 I - */ -#define TDA9873_BG 0 -#define TDA9873_M 1 -#define TDA9873_DK1 2 -#define TDA9873_DK2 3 -#define TDA9873_DK3 4 -#define TDA9873_I 5 - -/* C7 controls identification response time (1=fast/0=normal) - */ -#define TDA9873_IDR_NORM 0 -#define TDA9873_IDR_FAST 1 << 7 - - -/* Subaddress 0x02: Port data */ - -/* E1, E0 free programmable ports P1/P2 - 0, 0 both ports low - 0, 1 P1 high - 1, 0 P2 high - 1, 1 both ports high -*/ - -#define TDA9873_PORTS 3 - -/* E2: test port */ -#define TDA9873_TST_PORT 1 << 2 - -/* E5..E3 control mono output channel (together with transmission mode bit B4) - * - * E5 E4 E3 B4 OUTM - * 0 0 0 0 mono - * 0 0 1 0 DUAL B - * 0 1 0 1 mono (from stereo decoder) - */ -#define TDA9873_MOUT_MONO 0 -#define TDA9873_MOUT_FMONO 0 -#define TDA9873_MOUT_DUALA 0 -#define TDA9873_MOUT_DUALB 1 << 3 -#define TDA9873_MOUT_ST 1 << 4 -#define TDA9873_MOUT_EXTM (1 << 4 ) & (1 << 3) -#define TDA9873_MOUT_EXTL 1 << 5 -#define TDA9873_MOUT_EXTR (1 << 5 ) & (1 << 3) -#define TDA9873_MOUT_EXTLR (1 << 5 ) & (1 << 4) -#define TDA9873_MOUT_MUTE (1 << 5 ) & (1 << 4) & (1 << 3) - -/* Status bits: (chip read) */ -#define TDA9873_PONR 0 /* Power-on reset detected if = 1 */ -#define TDA9873_STEREO 2 /* Stereo sound is identified */ -#define TDA9873_DUAL 4 /* Dual sound is identified */ - -static int tda9873_getmode(struct CHIPSTATE *chip) -{ - struct v4l2_subdev *sd = &chip->sd; - int val,mode; - - val = chip_read(chip); - mode = V4L2_TUNER_MODE_MONO; - if (val & TDA9873_STEREO) - mode |= V4L2_TUNER_MODE_STEREO; - if (val & TDA9873_DUAL) - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - v4l2_dbg(1, debug, sd, "tda9873_getmode(): raw chip read: %d, return: %d\n", - val, mode); - return mode; -} - -static void tda9873_setmode(struct CHIPSTATE *chip, int mode) -{ - struct v4l2_subdev *sd = &chip->sd; - int sw_data = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK; - /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ - - if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { - v4l2_dbg(1, debug, sd, "tda9873_setmode(): external input\n"); - return; - } - - v4l2_dbg(1, debug, sd, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); - v4l2_dbg(1, debug, sd, "tda9873_setmode(): sw_data = %d\n", sw_data); - - switch (mode) { - case V4L2_TUNER_MODE_MONO: - sw_data |= TDA9873_TR_MONO; - break; - case V4L2_TUNER_MODE_STEREO: - sw_data |= TDA9873_TR_STEREO; - break; - case V4L2_TUNER_MODE_LANG1: - sw_data |= TDA9873_TR_DUALA; - break; - case V4L2_TUNER_MODE_LANG2: - sw_data |= TDA9873_TR_DUALB; - break; - default: - chip->mode = 0; - return; - } - - chip_write(chip, TDA9873_SW, sw_data); - v4l2_dbg(1, debug, sd, "tda9873_setmode(): req. mode %d; chip_write: %d\n", - mode, sw_data); -} - -static int tda9873_checkit(struct CHIPSTATE *chip) -{ - int rc; - - if (-1 == (rc = chip_read2(chip,254))) - return 0; - return (rc & ~0x1f) == 0x80; -} - - -/* ---------------------------------------------------------------------- */ -/* audio chip description - defines+functions for tda9874h and tda9874a */ -/* Dariusz Kowalewski */ - -/* Subaddresses for TDA9874H and TDA9874A (slave rx) */ -#define TDA9874A_AGCGR 0x00 /* AGC gain */ -#define TDA9874A_GCONR 0x01 /* general config */ -#define TDA9874A_MSR 0x02 /* monitor select */ -#define TDA9874A_C1FRA 0x03 /* carrier 1 freq. */ -#define TDA9874A_C1FRB 0x04 /* carrier 1 freq. */ -#define TDA9874A_C1FRC 0x05 /* carrier 1 freq. */ -#define TDA9874A_C2FRA 0x06 /* carrier 2 freq. */ -#define TDA9874A_C2FRB 0x07 /* carrier 2 freq. */ -#define TDA9874A_C2FRC 0x08 /* carrier 2 freq. */ -#define TDA9874A_DCR 0x09 /* demodulator config */ -#define TDA9874A_FMER 0x0a /* FM de-emphasis */ -#define TDA9874A_FMMR 0x0b /* FM dematrix */ -#define TDA9874A_C1OLAR 0x0c /* ch.1 output level adj. */ -#define TDA9874A_C2OLAR 0x0d /* ch.2 output level adj. */ -#define TDA9874A_NCONR 0x0e /* NICAM config */ -#define TDA9874A_NOLAR 0x0f /* NICAM output level adj. */ -#define TDA9874A_NLELR 0x10 /* NICAM lower error limit */ -#define TDA9874A_NUELR 0x11 /* NICAM upper error limit */ -#define TDA9874A_AMCONR 0x12 /* audio mute control */ -#define TDA9874A_SDACOSR 0x13 /* stereo DAC output select */ -#define TDA9874A_AOSR 0x14 /* analog output select */ -#define TDA9874A_DAICONR 0x15 /* digital audio interface config */ -#define TDA9874A_I2SOSR 0x16 /* I2S-bus output select */ -#define TDA9874A_I2SOLAR 0x17 /* I2S-bus output level adj. */ -#define TDA9874A_MDACOSR 0x18 /* mono DAC output select (tda9874a) */ -#define TDA9874A_ESP 0xFF /* easy standard progr. (tda9874a) */ - -/* Subaddresses for TDA9874H and TDA9874A (slave tx) */ -#define TDA9874A_DSR 0x00 /* device status */ -#define TDA9874A_NSR 0x01 /* NICAM status */ -#define TDA9874A_NECR 0x02 /* NICAM error count */ -#define TDA9874A_DR1 0x03 /* add. data LSB */ -#define TDA9874A_DR2 0x04 /* add. data MSB */ -#define TDA9874A_LLRA 0x05 /* monitor level read-out LSB */ -#define TDA9874A_LLRB 0x06 /* monitor level read-out MSB */ -#define TDA9874A_SIFLR 0x07 /* SIF level */ -#define TDA9874A_TR2 252 /* test reg. 2 */ -#define TDA9874A_TR1 253 /* test reg. 1 */ -#define TDA9874A_DIC 254 /* device id. code */ -#define TDA9874A_SIC 255 /* software id. code */ - - -static int tda9874a_mode = 1; /* 0: A2, 1: NICAM */ -static int tda9874a_GCONR = 0xc0; /* default config. input pin: SIFSEL=0 */ -static int tda9874a_NCONR = 0x01; /* default NICAM config.: AMSEL=0,AMUTE=1 */ -static int tda9874a_ESP = 0x07; /* default standard: NICAM D/K */ -static int tda9874a_dic = -1; /* device id. code */ - -/* insmod options for tda9874a */ -static unsigned int tda9874a_SIF = UNSET; -static unsigned int tda9874a_AMSEL = UNSET; -static unsigned int tda9874a_STD = UNSET; -module_param(tda9874a_SIF, int, 0444); -module_param(tda9874a_AMSEL, int, 0444); -module_param(tda9874a_STD, int, 0444); - -/* - * initialization table for tda9874 decoder: - * - carrier 1 freq. registers (3 bytes) - * - carrier 2 freq. registers (3 bytes) - * - demudulator config register - * - FM de-emphasis register (slow identification mode) - * Note: frequency registers must be written in single i2c transfer. - */ -static struct tda9874a_MODES { - char *name; - audiocmd cmd; -} tda9874a_modelist[9] = { - { "A2, B/G", /* default */ - { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x77,0xA0,0x00, 0x00,0x00 }} }, - { "A2, M (Korea)", - { 9, { TDA9874A_C1FRA, 0x5D,0xC0,0x00, 0x62,0x6A,0xAA, 0x20,0x22 }} }, - { "A2, D/K (1)", - { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x82,0x60,0x00, 0x00,0x00 }} }, - { "A2, D/K (2)", - { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x8C,0x75,0x55, 0x00,0x00 }} }, - { "A2, D/K (3)", - { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x77,0xA0,0x00, 0x00,0x00 }} }, - { "NICAM, I", - { 9, { TDA9874A_C1FRA, 0x7D,0x00,0x00, 0x88,0x8A,0xAA, 0x08,0x33 }} }, - { "NICAM, B/G", - { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x79,0xEA,0xAA, 0x08,0x33 }} }, - { "NICAM, D/K", - { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x08,0x33 }} }, - { "NICAM, L", - { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x09,0x33 }} } -}; - -static int tda9874a_setup(struct CHIPSTATE *chip) -{ - struct v4l2_subdev *sd = &chip->sd; - - chip_write(chip, TDA9874A_AGCGR, 0x00); /* 0 dB */ - chip_write(chip, TDA9874A_GCONR, tda9874a_GCONR); - chip_write(chip, TDA9874A_MSR, (tda9874a_mode) ? 0x03:0x02); - if(tda9874a_dic == 0x11) { - chip_write(chip, TDA9874A_FMMR, 0x80); - } else { /* dic == 0x07 */ - chip_cmd(chip,"tda9874_modelist",&tda9874a_modelist[tda9874a_STD].cmd); - chip_write(chip, TDA9874A_FMMR, 0x00); - } - chip_write(chip, TDA9874A_C1OLAR, 0x00); /* 0 dB */ - chip_write(chip, TDA9874A_C2OLAR, 0x00); /* 0 dB */ - chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR); - chip_write(chip, TDA9874A_NOLAR, 0x00); /* 0 dB */ - /* Note: If signal quality is poor you may want to change NICAM */ - /* error limit registers (NLELR and NUELR) to some greater values. */ - /* Then the sound would remain stereo, but won't be so clear. */ - chip_write(chip, TDA9874A_NLELR, 0x14); /* default */ - chip_write(chip, TDA9874A_NUELR, 0x50); /* default */ - - if(tda9874a_dic == 0x11) { - chip_write(chip, TDA9874A_AMCONR, 0xf9); - chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); - chip_write(chip, TDA9874A_AOSR, 0x80); - chip_write(chip, TDA9874A_MDACOSR, (tda9874a_mode) ? 0x82:0x80); - chip_write(chip, TDA9874A_ESP, tda9874a_ESP); - } else { /* dic == 0x07 */ - chip_write(chip, TDA9874A_AMCONR, 0xfb); - chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); - chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */ - } - v4l2_dbg(1, debug, sd, "tda9874a_setup(): %s [0x%02X].\n", - tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); - return 1; -} - -static int tda9874a_getmode(struct CHIPSTATE *chip) -{ - struct v4l2_subdev *sd = &chip->sd; - int dsr,nsr,mode; - int necr; /* just for debugging */ - - mode = V4L2_TUNER_MODE_MONO; - - if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR))) - return mode; - if(-1 == (nsr = chip_read2(chip,TDA9874A_NSR))) - return mode; - if(-1 == (necr = chip_read2(chip,TDA9874A_NECR))) - return mode; - - /* need to store dsr/nsr somewhere */ - chip->shadow.bytes[MAXREGS-2] = dsr; - chip->shadow.bytes[MAXREGS-1] = nsr; - - if(tda9874a_mode) { - /* Note: DSR.RSSF and DSR.AMSTAT bits are also checked. - * If NICAM auto-muting is enabled, DSR.AMSTAT=1 indicates - * that sound has (temporarily) switched from NICAM to - * mono FM (or AM) on 1st sound carrier due to high NICAM bit - * error count. So in fact there is no stereo in this case :-( - * But changing the mode to V4L2_TUNER_MODE_MONO would switch - * external 4052 multiplexer in audio_hook(). - */ - if(nsr & 0x02) /* NSR.S/MB=1 */ - mode |= V4L2_TUNER_MODE_STEREO; - if(nsr & 0x01) /* NSR.D/SB=1 */ - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } else { - if(dsr & 0x02) /* DSR.IDSTE=1 */ - mode |= V4L2_TUNER_MODE_STEREO; - if(dsr & 0x04) /* DSR.IDDUA=1 */ - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } - - v4l2_dbg(1, debug, sd, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", - dsr, nsr, necr, mode); - return mode; -} - -static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) -{ - struct v4l2_subdev *sd = &chip->sd; - - /* Disable/enable NICAM auto-muting (based on DSR.RSSF status bit). */ - /* If auto-muting is disabled, we can hear a signal of degrading quality. */ - if (tda9874a_mode) { - if(chip->shadow.bytes[MAXREGS-2] & 0x20) /* DSR.RSSF=1 */ - tda9874a_NCONR &= 0xfe; /* enable */ - else - tda9874a_NCONR |= 0x01; /* disable */ - chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR); - } - - /* Note: TDA9874A supports automatic FM dematrixing (FMMR register) - * and has auto-select function for audio output (AOSR register). - * Old TDA9874H doesn't support these features. - * TDA9874A also has additional mono output pin (OUTM), which - * on same (all?) tv-cards is not used, anyway (as well as MONOIN). - */ - if(tda9874a_dic == 0x11) { - int aosr = 0x80; - int mdacosr = (tda9874a_mode) ? 0x82:0x80; - - switch(mode) { - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_STEREO: - break; - case V4L2_TUNER_MODE_LANG1: - aosr = 0x80; /* auto-select, dual A/A */ - mdacosr = (tda9874a_mode) ? 0x82:0x80; - break; - case V4L2_TUNER_MODE_LANG2: - aosr = 0xa0; /* auto-select, dual B/B */ - mdacosr = (tda9874a_mode) ? 0x83:0x81; - break; - default: - chip->mode = 0; - return; - } - chip_write(chip, TDA9874A_AOSR, aosr); - chip_write(chip, TDA9874A_MDACOSR, mdacosr); - - v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", - mode, aosr, mdacosr); - - } else { /* dic == 0x07 */ - int fmmr,aosr; - - switch(mode) { - case V4L2_TUNER_MODE_MONO: - fmmr = 0x00; /* mono */ - aosr = 0x10; /* A/A */ - break; - case V4L2_TUNER_MODE_STEREO: - if(tda9874a_mode) { - fmmr = 0x00; - aosr = 0x00; /* handled by NICAM auto-mute */ - } else { - fmmr = (tda9874a_ESP == 1) ? 0x05 : 0x04; /* stereo */ - aosr = 0x00; - } - break; - case V4L2_TUNER_MODE_LANG1: - fmmr = 0x02; /* dual */ - aosr = 0x10; /* dual A/A */ - break; - case V4L2_TUNER_MODE_LANG2: - fmmr = 0x02; /* dual */ - aosr = 0x20; /* dual B/B */ - break; - default: - chip->mode = 0; - return; - } - chip_write(chip, TDA9874A_FMMR, fmmr); - chip_write(chip, TDA9874A_AOSR, aosr); - - v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", - mode, fmmr, aosr); - } -} - -static int tda9874a_checkit(struct CHIPSTATE *chip) -{ - struct v4l2_subdev *sd = &chip->sd; - int dic,sic; /* device id. and software id. codes */ - - if(-1 == (dic = chip_read2(chip,TDA9874A_DIC))) - return 0; - if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) - return 0; - - v4l2_dbg(1, debug, sd, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); - - if((dic == 0x11)||(dic == 0x07)) { - v4l2_info(sd, "found tda9874%s.\n", (dic == 0x11) ? "a" : "h"); - tda9874a_dic = dic; /* remember device id. */ - return 1; - } - return 0; /* not found */ -} - -static int tda9874a_initialize(struct CHIPSTATE *chip) -{ - if (tda9874a_SIF > 2) - tda9874a_SIF = 1; - if (tda9874a_STD >= ARRAY_SIZE(tda9874a_modelist)) - tda9874a_STD = 0; - if(tda9874a_AMSEL > 1) - tda9874a_AMSEL = 0; - - if(tda9874a_SIF == 1) - tda9874a_GCONR = 0xc0; /* sound IF input 1 */ - else - tda9874a_GCONR = 0xc1; /* sound IF input 2 */ - - tda9874a_ESP = tda9874a_STD; - tda9874a_mode = (tda9874a_STD < 5) ? 0 : 1; - - if(tda9874a_AMSEL == 0) - tda9874a_NCONR = 0x01; /* auto-mute: analog mono input */ - else - tda9874a_NCONR = 0x05; /* auto-mute: 1st carrier FM or AM */ - - tda9874a_setup(chip); - return 0; -} - -/* ---------------------------------------------------------------------- */ -/* audio chip description - defines+functions for tda9875 */ -/* The TDA9875 is made by Philips Semiconductor - * http://www.semiconductors.philips.com - * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator - * - */ - -/* subaddresses for TDA9875 */ -#define TDA9875_MUT 0x12 /*General mute (value --> 0b11001100*/ -#define TDA9875_CFG 0x01 /* Config register (value --> 0b00000000 */ -#define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/ -#define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/ - -#define TDA9875_CH1V 0x0c /*Channel 1 volume (mute)*/ -#define TDA9875_CH2V 0x0d /*Channel 2 volume (mute)*/ -#define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/ -#define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/ - -#define TDA9875_ADCIS 0x17 /*ADC input select (mono) 0b0110 000*/ -#define TDA9875_AER 0x19 /*Audio effect (AVL+Pseudo) 0b0000 0110*/ -#define TDA9875_MCS 0x18 /*Main channel select (DAC) 0b0000100*/ -#define TDA9875_MVL 0x1a /* Main volume gauche */ -#define TDA9875_MVR 0x1b /* Main volume droite */ -#define TDA9875_MBA 0x1d /* Main Basse */ -#define TDA9875_MTR 0x1e /* Main treble */ -#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/ -#define TDA9875_AVL 0x20 /* Auxilary volume gauche */ -#define TDA9875_AVR 0x21 /* Auxilary volume droite */ -#define TDA9875_ABA 0x22 /* Auxilary Basse */ -#define TDA9875_ATR 0x23 /* Auxilary treble */ - -#define TDA9875_MSR 0x02 /* Monitor select register */ -#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */ -#define TDA9875_C1MIB 0x04 /* Carrier 1 (FM) frequency register (16-8]b */ -#define TDA9875_C1LSB 0x05 /* Carrier 1 (FM) frequency register LSB */ -#define TDA9875_C2MSB 0x06 /* Carrier 2 (nicam) frequency register MSB */ -#define TDA9875_C2MIB 0x07 /* Carrier 2 (nicam) frequency register (16-8]b */ -#define TDA9875_C2LSB 0x08 /* Carrier 2 (nicam) frequency register LSB */ -#define TDA9875_DCR 0x09 /* Demodulateur configuration regirter*/ -#define TDA9875_DEEM 0x0a /* FM de-emphasis regirter*/ -#define TDA9875_FMAT 0x0b /* FM Matrix regirter*/ - -/* values */ -#define TDA9875_MUTE_ON 0xff /* general mute */ -#define TDA9875_MUTE_OFF 0xcc /* general no mute */ - -static int tda9875_initialize(struct CHIPSTATE *chip) -{ - chip_write(chip, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/ - chip_write(chip, TDA9875_MSR, 0x03); /* Monitor 0b00000XXX*/ - chip_write(chip, TDA9875_C1MSB, 0x00); /*Car1(FM) MSB XMHz*/ - chip_write(chip, TDA9875_C1MIB, 0x00); /*Car1(FM) MIB XMHz*/ - chip_write(chip, TDA9875_C1LSB, 0x00); /*Car1(FM) LSB XMHz*/ - chip_write(chip, TDA9875_C2MSB, 0x00); /*Car2(NICAM) MSB XMHz*/ - chip_write(chip, TDA9875_C2MIB, 0x00); /*Car2(NICAM) MIB XMHz*/ - chip_write(chip, TDA9875_C2LSB, 0x00); /*Car2(NICAM) LSB XMHz*/ - chip_write(chip, TDA9875_DCR, 0x00); /*Demod config 0x00*/ - chip_write(chip, TDA9875_DEEM, 0x44); /*DE-Emph 0b0100 0100*/ - chip_write(chip, TDA9875_FMAT, 0x00); /*FM Matrix reg 0x00*/ - chip_write(chip, TDA9875_SC1, 0x00); /* SCART 1 (SC1)*/ - chip_write(chip, TDA9875_SC2, 0x01); /* SCART 2 (sc2)*/ - - chip_write(chip, TDA9875_CH1V, 0x10); /* Channel volume 1 mute*/ - chip_write(chip, TDA9875_CH2V, 0x10); /* Channel volume 2 mute */ - chip_write(chip, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/ - chip_write(chip, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/ - chip_write(chip, TDA9875_LOSR, 0x00); /* line out (in:mono)*/ - chip_write(chip, TDA9875_AER, 0x00); /*06 Effect (AVL+PSEUDO) */ - chip_write(chip, TDA9875_MCS, 0x44); /* Main ch select (DAC) */ - chip_write(chip, TDA9875_MVL, 0x03); /* Vol Main left 10dB */ - chip_write(chip, TDA9875_MVR, 0x03); /* Vol Main right 10dB*/ - chip_write(chip, TDA9875_MBA, 0x00); /* Main Bass Main 0dB*/ - chip_write(chip, TDA9875_MTR, 0x00); /* Main Treble Main 0dB*/ - chip_write(chip, TDA9875_ACS, 0x44); /* Aux chan select (dac)*/ - chip_write(chip, TDA9875_AVL, 0x00); /* Vol Aux left 0dB*/ - chip_write(chip, TDA9875_AVR, 0x00); /* Vol Aux right 0dB*/ - chip_write(chip, TDA9875_ABA, 0x00); /* Aux Bass Main 0dB*/ - chip_write(chip, TDA9875_ATR, 0x00); /* Aux Aigus Main 0dB*/ - - chip_write(chip, TDA9875_MUT, 0xcc); /* General mute */ - return 0; -} - -static int tda9875_volume(int val) { return (unsigned char)(val / 602 - 84); } -static int tda9875_bass(int val) { return (unsigned char)(max(-12, val / 2115 - 15)); } -static int tda9875_treble(int val) { return (unsigned char)(val / 2622 - 12); } - -/* ----------------------------------------------------------------------- */ - - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda9875_checkit(struct CHIPSTATE *chip) -{ - struct v4l2_subdev *sd = &chip->sd; - int dic, rev; - - dic = chip_read2(chip, 254); - rev = chip_read2(chip, 255); - - if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */ - v4l2_info(sd, "found tda9875%s rev. %d.\n", - dic == 0 ? "" : "A", rev); - return 1; - } - return 0; -} - -/* ---------------------------------------------------------------------- */ -/* audio chip descriptions - defines+functions for tea6420 */ - -#define TEA6300_VL 0x00 /* volume left */ -#define TEA6300_VR 0x01 /* volume right */ -#define TEA6300_BA 0x02 /* bass */ -#define TEA6300_TR 0x03 /* treble */ -#define TEA6300_FA 0x04 /* fader control */ -#define TEA6300_S 0x05 /* switch register */ - /* values for those registers: */ -#define TEA6300_S_SA 0x01 /* stereo A input */ -#define TEA6300_S_SB 0x02 /* stereo B */ -#define TEA6300_S_SC 0x04 /* stereo C */ -#define TEA6300_S_GMU 0x80 /* general mute */ - -#define TEA6320_V 0x00 /* volume (0-5)/loudness off (6)/zero crossing mute(7) */ -#define TEA6320_FFR 0x01 /* fader front right (0-5) */ -#define TEA6320_FFL 0x02 /* fader front left (0-5) */ -#define TEA6320_FRR 0x03 /* fader rear right (0-5) */ -#define TEA6320_FRL 0x04 /* fader rear left (0-5) */ -#define TEA6320_BA 0x05 /* bass (0-4) */ -#define TEA6320_TR 0x06 /* treble (0-4) */ -#define TEA6320_S 0x07 /* switch register */ - /* values for those registers: */ -#define TEA6320_S_SA 0x07 /* stereo A input */ -#define TEA6320_S_SB 0x06 /* stereo B */ -#define TEA6320_S_SC 0x05 /* stereo C */ -#define TEA6320_S_SD 0x04 /* stereo D */ -#define TEA6320_S_GMU 0x80 /* general mute */ - -#define TEA6420_S_SA 0x00 /* stereo A input */ -#define TEA6420_S_SB 0x01 /* stereo B */ -#define TEA6420_S_SC 0x02 /* stereo C */ -#define TEA6420_S_SD 0x03 /* stereo D */ -#define TEA6420_S_SE 0x04 /* stereo E */ -#define TEA6420_S_GMU 0x05 /* general mute */ - -static int tea6300_shift10(int val) { return val >> 10; } -static int tea6300_shift12(int val) { return val >> 12; } - -/* Assumes 16bit input (values 0x3f to 0x0c are unique, values less than */ -/* 0x0c mirror those immediately higher) */ -static int tea6320_volume(int val) { return (val / (65535/(63-12)) + 12) & 0x3f; } -static int tea6320_shift11(int val) { return val >> 11; } -static int tea6320_initialize(struct CHIPSTATE * chip) -{ - chip_write(chip, TEA6320_FFR, 0x3f); - chip_write(chip, TEA6320_FFL, 0x3f); - chip_write(chip, TEA6320_FRR, 0x3f); - chip_write(chip, TEA6320_FRL, 0x3f); - - return 0; -} - - -/* ---------------------------------------------------------------------- */ -/* audio chip descriptions - defines+functions for tda8425 */ - -#define TDA8425_VL 0x00 /* volume left */ -#define TDA8425_VR 0x01 /* volume right */ -#define TDA8425_BA 0x02 /* bass */ -#define TDA8425_TR 0x03 /* treble */ -#define TDA8425_S1 0x08 /* switch functions */ - /* values for those registers: */ -#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */ -#define TDA8425_S1_CH1 0xCE /* audio channel 1 (mute off) - "linear stereo" mode */ -#define TDA8425_S1_CH2 0xCF /* audio channel 2 (mute off) - "linear stereo" mode */ -#define TDA8425_S1_MU 0x20 /* mute bit */ -#define TDA8425_S1_STEREO 0x18 /* stereo bits */ -#define TDA8425_S1_STEREO_SPATIAL 0x18 /* spatial stereo */ -#define TDA8425_S1_STEREO_LINEAR 0x08 /* linear stereo */ -#define TDA8425_S1_STEREO_PSEUDO 0x10 /* pseudo stereo */ -#define TDA8425_S1_STEREO_MONO 0x00 /* forced mono */ -#define TDA8425_S1_ML 0x06 /* language selector */ -#define TDA8425_S1_ML_SOUND_A 0x02 /* sound a */ -#define TDA8425_S1_ML_SOUND_B 0x04 /* sound b */ -#define TDA8425_S1_ML_STEREO 0x06 /* stereo */ -#define TDA8425_S1_IS 0x01 /* channel selector */ - - -static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; } -static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; } - -static void tda8425_setmode(struct CHIPSTATE *chip, int mode) -{ - int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1; - - if (mode & V4L2_TUNER_MODE_LANG1) { - s1 |= TDA8425_S1_ML_SOUND_A; - s1 |= TDA8425_S1_STEREO_PSEUDO; - - } else if (mode & V4L2_TUNER_MODE_LANG2) { - s1 |= TDA8425_S1_ML_SOUND_B; - s1 |= TDA8425_S1_STEREO_PSEUDO; - - } else { - s1 |= TDA8425_S1_ML_STEREO; - - if (mode & V4L2_TUNER_MODE_MONO) - s1 |= TDA8425_S1_STEREO_MONO; - if (mode & V4L2_TUNER_MODE_STEREO) - s1 |= TDA8425_S1_STEREO_SPATIAL; - } - chip_write(chip,TDA8425_S1,s1); -} - - -/* ---------------------------------------------------------------------- */ -/* audio chip descriptions - defines+functions for pic16c54 (PV951) */ - -/* the registers of 16C54, I2C sub address. */ -#define PIC16C54_REG_KEY_CODE 0x01 /* Not use. */ -#define PIC16C54_REG_MISC 0x02 - -/* bit definition of the RESET register, I2C data. */ -#define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */ - /* code of remote controller */ -#define PIC16C54_MISC_MTS_MAIN 0x02 /* bit 1 */ -#define PIC16C54_MISC_MTS_SAP 0x04 /* bit 2 */ -#define PIC16C54_MISC_MTS_BOTH 0x08 /* bit 3 */ -#define PIC16C54_MISC_SND_MUTE 0x10 /* bit 4, Mute Audio(Line-in and Tuner) */ -#define PIC16C54_MISC_SND_NOTMUTE 0x20 /* bit 5 */ -#define PIC16C54_MISC_SWITCH_TUNER 0x40 /* bit 6 , Switch to Line-in */ -#define PIC16C54_MISC_SWITCH_LINE 0x80 /* bit 7 , Switch to Tuner */ - -/* ---------------------------------------------------------------------- */ -/* audio chip descriptions - defines+functions for TA8874Z */ - -/* write 1st byte */ -#define TA8874Z_LED_STE 0x80 -#define TA8874Z_LED_BIL 0x40 -#define TA8874Z_LED_EXT 0x20 -#define TA8874Z_MONO_SET 0x10 -#define TA8874Z_MUTE 0x08 -#define TA8874Z_F_MONO 0x04 -#define TA8874Z_MODE_SUB 0x02 -#define TA8874Z_MODE_MAIN 0x01 - -/* write 2nd byte */ -/*#define TA8874Z_TI 0x80 */ /* test mode */ -#define TA8874Z_SEPARATION 0x3f -#define TA8874Z_SEPARATION_DEFAULT 0x10 - -/* read */ -#define TA8874Z_B1 0x80 -#define TA8874Z_B0 0x40 -#define TA8874Z_CHAG_FLAG 0x20 - -/* - * B1 B0 - * mono L H - * stereo L L - * BIL H L - */ -static int ta8874z_getmode(struct CHIPSTATE *chip) -{ - int val, mode; - - val = chip_read(chip); - mode = V4L2_TUNER_MODE_MONO; - if (val & TA8874Z_B1){ - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - }else if (!(val & TA8874Z_B0)){ - mode |= V4L2_TUNER_MODE_STEREO; - } - /* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ - return mode; -} - -static audiocmd ta8874z_stereo = { 2, {0, TA8874Z_SEPARATION_DEFAULT}}; -static audiocmd ta8874z_mono = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}}; -static audiocmd ta8874z_main = {2, { 0, TA8874Z_SEPARATION_DEFAULT}}; -static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}}; - -static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) -{ - struct v4l2_subdev *sd = &chip->sd; - int update = 1; - audiocmd *t = NULL; - - v4l2_dbg(1, debug, sd, "ta8874z_setmode(): mode: 0x%02x\n", mode); - - switch(mode){ - case V4L2_TUNER_MODE_MONO: - t = &ta8874z_mono; - break; - case V4L2_TUNER_MODE_STEREO: - t = &ta8874z_stereo; - break; - case V4L2_TUNER_MODE_LANG1: - t = &ta8874z_main; - break; - case V4L2_TUNER_MODE_LANG2: - t = &ta8874z_sub; - break; - default: - update = 0; - } - - if(update) - chip_cmd(chip, "TA8874Z", t); -} - -static int ta8874z_checkit(struct CHIPSTATE *chip) -{ - int rc; - rc = chip_read(chip); - return ((rc & 0x1f) == 0x1f) ? 1 : 0; -} - -/* ---------------------------------------------------------------------- */ -/* audio chip descriptions - struct CHIPDESC */ - -/* insmod options to enable/disable individual audio chips */ -static int tda8425 = 1; -static int tda9840 = 1; -static int tda9850 = 1; -static int tda9855 = 1; -static int tda9873 = 1; -static int tda9874a = 1; -static int tda9875 = 1; -static int tea6300; /* default 0 - address clash with msp34xx */ -static int tea6320; /* default 0 - address clash with msp34xx */ -static int tea6420 = 1; -static int pic16c54 = 1; -static int ta8874z; /* default 0 - address clash with tda9840 */ - -module_param(tda8425, int, 0444); -module_param(tda9840, int, 0444); -module_param(tda9850, int, 0444); -module_param(tda9855, int, 0444); -module_param(tda9873, int, 0444); -module_param(tda9874a, int, 0444); -module_param(tda9875, int, 0444); -module_param(tea6300, int, 0444); -module_param(tea6320, int, 0444); -module_param(tea6420, int, 0444); -module_param(pic16c54, int, 0444); -module_param(ta8874z, int, 0444); - -static struct CHIPDESC chiplist[] = { - { - .name = "tda9840", - .insmodopt = &tda9840, - .addr_lo = I2C_ADDR_TDA9840 >> 1, - .addr_hi = I2C_ADDR_TDA9840 >> 1, - .registers = 5, - .flags = CHIP_NEED_CHECKMODE, - - /* callbacks */ - .checkit = tda9840_checkit, - .getmode = tda9840_getmode, - .setmode = tda9840_setmode, - - .init = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN - /* ,TDA9840_SW, TDA9840_MONO */} } - }, - { - .name = "tda9873h", - .insmodopt = &tda9873, - .addr_lo = I2C_ADDR_TDA985x_L >> 1, - .addr_hi = I2C_ADDR_TDA985x_H >> 1, - .registers = 3, - .flags = CHIP_HAS_INPUTSEL | CHIP_NEED_CHECKMODE, - - /* callbacks */ - .checkit = tda9873_checkit, - .getmode = tda9873_getmode, - .setmode = tda9873_setmode, - - .init = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } }, - .inputreg = TDA9873_SW, - .inputmute = TDA9873_MUTE | TDA9873_AUTOMUTE, - .inputmap = {0xa0, 0xa2, 0xa0, 0xa0}, - .inputmask = TDA9873_INP_MASK|TDA9873_MUTE|TDA9873_AUTOMUTE, - - }, - { - .name = "tda9874h/a", - .insmodopt = &tda9874a, - .addr_lo = I2C_ADDR_TDA9874 >> 1, - .addr_hi = I2C_ADDR_TDA9874 >> 1, - .flags = CHIP_NEED_CHECKMODE, - - /* callbacks */ - .initialize = tda9874a_initialize, - .checkit = tda9874a_checkit, - .getmode = tda9874a_getmode, - .setmode = tda9874a_setmode, - }, - { - .name = "tda9875", - .insmodopt = &tda9875, - .addr_lo = I2C_ADDR_TDA9875 >> 1, - .addr_hi = I2C_ADDR_TDA9875 >> 1, - .flags = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE, - - /* callbacks */ - .initialize = tda9875_initialize, - .checkit = tda9875_checkit, - .volfunc = tda9875_volume, - .bassfunc = tda9875_bass, - .treblefunc = tda9875_treble, - .leftreg = TDA9875_MVL, - .rightreg = TDA9875_MVR, - .bassreg = TDA9875_MBA, - .treblereg = TDA9875_MTR, - .leftinit = 58880, - .rightinit = 58880, - }, - { - .name = "tda9850", - .insmodopt = &tda9850, - .addr_lo = I2C_ADDR_TDA985x_L >> 1, - .addr_hi = I2C_ADDR_TDA985x_H >> 1, - .registers = 11, - - .getmode = tda985x_getmode, - .setmode = tda985x_setmode, - - .init = { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } } - }, - { - .name = "tda9855", - .insmodopt = &tda9855, - .addr_lo = I2C_ADDR_TDA985x_L >> 1, - .addr_hi = I2C_ADDR_TDA985x_H >> 1, - .registers = 11, - .flags = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE, - - .leftreg = TDA9855_VL, - .rightreg = TDA9855_VR, - .bassreg = TDA9855_BA, - .treblereg = TDA9855_TR, - - /* callbacks */ - .volfunc = tda9855_volume, - .bassfunc = tda9855_bass, - .treblefunc = tda9855_treble, - .getmode = tda985x_getmode, - .setmode = tda985x_setmode, - - .init = { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2, - TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT, - TDA985x_STEREO | TDA9855_LINEAR | TDA9855_TZCM | TDA9855_VZCM, - 0x07, 0x10, 0x10, 0x03 }} - }, - { - .name = "tea6300", - .insmodopt = &tea6300, - .addr_lo = I2C_ADDR_TEA6300 >> 1, - .addr_hi = I2C_ADDR_TEA6300 >> 1, - .registers = 6, - .flags = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL, - - .leftreg = TEA6300_VR, - .rightreg = TEA6300_VL, - .bassreg = TEA6300_BA, - .treblereg = TEA6300_TR, - - /* callbacks */ - .volfunc = tea6300_shift10, - .bassfunc = tea6300_shift12, - .treblefunc = tea6300_shift12, - - .inputreg = TEA6300_S, - .inputmap = { TEA6300_S_SA, TEA6300_S_SB, TEA6300_S_SC }, - .inputmute = TEA6300_S_GMU, - }, - { - .name = "tea6320", - .insmodopt = &tea6320, - .addr_lo = I2C_ADDR_TEA6300 >> 1, - .addr_hi = I2C_ADDR_TEA6300 >> 1, - .registers = 8, - .flags = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL, - - .leftreg = TEA6320_V, - .rightreg = TEA6320_V, - .bassreg = TEA6320_BA, - .treblereg = TEA6320_TR, - - /* callbacks */ - .initialize = tea6320_initialize, - .volfunc = tea6320_volume, - .bassfunc = tea6320_shift11, - .treblefunc = tea6320_shift11, - - .inputreg = TEA6320_S, - .inputmap = { TEA6320_S_SA, TEA6420_S_SB, TEA6300_S_SC, TEA6320_S_SD }, - .inputmute = TEA6300_S_GMU, - }, - { - .name = "tea6420", - .insmodopt = &tea6420, - .addr_lo = I2C_ADDR_TEA6420 >> 1, - .addr_hi = I2C_ADDR_TEA6420 >> 1, - .registers = 1, - .flags = CHIP_HAS_INPUTSEL, - - .inputreg = -1, - .inputmap = { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC }, - .inputmute = TEA6300_S_GMU, - }, - { - .name = "tda8425", - .insmodopt = &tda8425, - .addr_lo = I2C_ADDR_TDA8425 >> 1, - .addr_hi = I2C_ADDR_TDA8425 >> 1, - .registers = 9, - .flags = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL, - - .leftreg = TDA8425_VL, - .rightreg = TDA8425_VR, - .bassreg = TDA8425_BA, - .treblereg = TDA8425_TR, - - /* callbacks */ - .volfunc = tda8425_shift10, - .bassfunc = tda8425_shift12, - .treblefunc = tda8425_shift12, - .setmode = tda8425_setmode, - - .inputreg = TDA8425_S1, - .inputmap = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 }, - .inputmute = TDA8425_S1_OFF, - - }, - { - .name = "pic16c54 (PV951)", - .insmodopt = &pic16c54, - .addr_lo = I2C_ADDR_PIC16C54 >> 1, - .addr_hi = I2C_ADDR_PIC16C54>> 1, - .registers = 2, - .flags = CHIP_HAS_INPUTSEL, - - .inputreg = PIC16C54_REG_MISC, - .inputmap = {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER, - PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE, - PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE, - PIC16C54_MISC_SND_MUTE}, - .inputmute = PIC16C54_MISC_SND_MUTE, - }, - { - .name = "ta8874z", - .checkit = ta8874z_checkit, - .insmodopt = &ta8874z, - .addr_lo = I2C_ADDR_TDA9840 >> 1, - .addr_hi = I2C_ADDR_TDA9840 >> 1, - .registers = 2, - .flags = CHIP_NEED_CHECKMODE, - - /* callbacks */ - .getmode = ta8874z_getmode, - .setmode = ta8874z_setmode, - - .init = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}}, - }, - { .name = NULL } /* EOF */ -}; - - -/* ---------------------------------------------------------------------- */ - -static int tvaudio_g_ctrl(struct v4l2_subdev *sd, - struct v4l2_control *ctrl) -{ - struct CHIPSTATE *chip = to_state(sd); - struct CHIPDESC *desc = chip->desc; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (!(desc->flags & CHIP_HAS_INPUTSEL)) - break; - ctrl->value=chip->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (!(desc->flags & CHIP_HAS_VOLUME)) - break; - ctrl->value = max(chip->left,chip->right); - return 0; - case V4L2_CID_AUDIO_BALANCE: - { - int volume; - if (!(desc->flags & CHIP_HAS_VOLUME)) - break; - volume = max(chip->left,chip->right); - if (volume) - ctrl->value=(32768*min(chip->left,chip->right))/volume; - else - ctrl->value=32768; - return 0; - } - case V4L2_CID_AUDIO_BASS: - if (!(desc->flags & CHIP_HAS_BASSTREBLE)) - break; - ctrl->value = chip->bass; - return 0; - case V4L2_CID_AUDIO_TREBLE: - if (!(desc->flags & CHIP_HAS_BASSTREBLE)) - break; - ctrl->value = chip->treble; - return 0; - } - return -EINVAL; -} - -static int tvaudio_s_ctrl(struct v4l2_subdev *sd, - struct v4l2_control *ctrl) -{ - struct CHIPSTATE *chip = to_state(sd); - struct CHIPDESC *desc = chip->desc; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (!(desc->flags & CHIP_HAS_INPUTSEL)) - break; - - if (ctrl->value < 0 || ctrl->value >= 2) - return -ERANGE; - chip->muted = ctrl->value; - if (chip->muted) - chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask); - else - chip_write_masked(chip,desc->inputreg, - desc->inputmap[chip->input],desc->inputmask); - return 0; - case V4L2_CID_AUDIO_VOLUME: - { - int volume,balance; - - if (!(desc->flags & CHIP_HAS_VOLUME)) - break; - - volume = max(chip->left,chip->right); - if (volume) - balance=(32768*min(chip->left,chip->right))/volume; - else - balance=32768; - - volume=ctrl->value; - chip->left = (min(65536 - balance,32768) * volume) / 32768; - chip->right = (min(balance,volume *(__u16)32768)) / 32768; - - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); - - return 0; - } - case V4L2_CID_AUDIO_BALANCE: - { - int volume, balance; - if (!(desc->flags & CHIP_HAS_VOLUME)) - break; - - volume = max(chip->left,chip->right); - balance = ctrl->value; - - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); - - return 0; - } - case V4L2_CID_AUDIO_BASS: - if (!(desc->flags & CHIP_HAS_BASSTREBLE)) - break; - chip->bass = ctrl->value; - chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); - - return 0; - case V4L2_CID_AUDIO_TREBLE: - if (!(desc->flags & CHIP_HAS_BASSTREBLE)) - break; - chip->treble = ctrl->value; - chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); - - return 0; - } - return -EINVAL; -} - - -/* ---------------------------------------------------------------------- */ -/* video4linux interface */ - -static int tvaudio_s_radio(struct v4l2_subdev *sd) -{ - struct CHIPSTATE *chip = to_state(sd); - - chip->radio = 1; - chip->watch_stereo = 0; - /* del_timer(&chip->wt); */ - return 0; -} - -static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - struct CHIPSTATE *chip = to_state(sd); - struct CHIPDESC *desc = chip->desc; - - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - if (desc->flags & CHIP_HAS_INPUTSEL) - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - break; - case V4L2_CID_AUDIO_VOLUME: - if (desc->flags & CHIP_HAS_VOLUME) - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); - break; - case V4L2_CID_AUDIO_BALANCE: - if (desc->flags & CHIP_HAS_VOLUME) - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); - break; - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - if (desc->flags & CHIP_HAS_BASSTREBLE) - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); - break; - default: - break; - } - return -EINVAL; -} - -static int tvaudio_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct CHIPSTATE *chip = to_state(sd); - struct CHIPDESC *desc = chip->desc; - - if (!(desc->flags & CHIP_HAS_INPUTSEL)) - return 0; - if (input >= 4) - return -EINVAL; - /* There are four inputs: tuner, radio, extern and intern. */ - chip->input = input; - if (chip->muted) - return 0; - chip_write_masked(chip, desc->inputreg, - desc->inputmap[chip->input], desc->inputmask); - return 0; -} - -static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct CHIPSTATE *chip = to_state(sd); - struct CHIPDESC *desc = chip->desc; - int mode = 0; - - if (!desc->setmode) - return 0; - if (chip->radio) - return 0; - - switch (vt->audmode) { - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1: - case V4L2_TUNER_MODE_LANG2: - mode = vt->audmode; - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - mode = V4L2_TUNER_MODE_STEREO; - break; - default: - return -EINVAL; - } - chip->audmode = vt->audmode; - - if (mode) { - chip->watch_stereo = 0; - /* del_timer(&chip->wt); */ - chip->mode = mode; - desc->setmode(chip, mode); - } - return 0; -} - -static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct CHIPSTATE *chip = to_state(sd); - struct CHIPDESC *desc = chip->desc; - int mode = V4L2_TUNER_MODE_MONO; - - if (!desc->getmode) - return 0; - if (chip->radio) - return 0; - - vt->audmode = chip->audmode; - vt->rxsubchans = 0; - vt->capability = V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - - mode = desc->getmode(chip); - - if (mode & V4L2_TUNER_MODE_MONO) - vt->rxsubchans |= V4L2_TUNER_SUB_MONO; - if (mode & V4L2_TUNER_MODE_STEREO) - vt->rxsubchans |= V4L2_TUNER_SUB_STEREO; - /* Note: for SAP it should be mono/lang2 or stereo/lang2. - When this module is converted fully to v4l2, then this - should change for those chips that can detect SAP. */ - if (mode & V4L2_TUNER_MODE_LANG1) - vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | - V4L2_TUNER_SUB_LANG2; - return 0; -} - -static int tvaudio_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct CHIPSTATE *chip = to_state(sd); - - chip->radio = 0; - return 0; -} - -static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) -{ - struct CHIPSTATE *chip = to_state(sd); - struct CHIPDESC *desc = chip->desc; - - chip->mode = 0; /* automatic */ - - /* For chips that provide getmode and setmode, and doesn't - automatically follows the stereo carrier, a kthread is - created to set the audio standard. In this case, when then - the video channel is changed, tvaudio starts on MONO mode. - After waiting for 2 seconds, the kernel thread is called, - to follow whatever audio standard is pointed by the - audio carrier. - */ - if (chip->thread) { - desc->setmode(chip, V4L2_TUNER_MODE_MONO); - if (chip->prevmode != V4L2_TUNER_MODE_MONO) - chip->prevmode = -1; /* reset previous mode */ - mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); - } - return 0; -} - -static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops tvaudio_core_ops = { - .g_chip_ident = tvaudio_g_chip_ident, - .queryctrl = tvaudio_queryctrl, - .g_ctrl = tvaudio_g_ctrl, - .s_ctrl = tvaudio_s_ctrl, - .s_std = tvaudio_s_std, -}; - -static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = { - .s_radio = tvaudio_s_radio, - .s_frequency = tvaudio_s_frequency, - .s_tuner = tvaudio_s_tuner, - .g_tuner = tvaudio_g_tuner, -}; - -static const struct v4l2_subdev_audio_ops tvaudio_audio_ops = { - .s_routing = tvaudio_s_routing, -}; - -static const struct v4l2_subdev_ops tvaudio_ops = { - .core = &tvaudio_core_ops, - .tuner = &tvaudio_tuner_ops, - .audio = &tvaudio_audio_ops, -}; - -/* ----------------------------------------------------------------------- */ - - -/* i2c registration */ - -static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct CHIPSTATE *chip; - struct CHIPDESC *desc; - struct v4l2_subdev *sd; - - if (debug) { - printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); - printk(KERN_INFO "tvaudio: known chips: "); - for (desc = chiplist; desc->name != NULL; desc++) - printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); - printk("\n"); - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - sd = &chip->sd; - v4l2_i2c_subdev_init(sd, client, &tvaudio_ops); - - /* find description for the chip */ - v4l2_dbg(1, debug, sd, "chip found @ 0x%x\n", client->addr<<1); - for (desc = chiplist; desc->name != NULL; desc++) { - if (0 == *(desc->insmodopt)) - continue; - if (client->addr < desc->addr_lo || - client->addr > desc->addr_hi) - continue; - if (desc->checkit && !desc->checkit(chip)) - continue; - break; - } - if (desc->name == NULL) { - v4l2_dbg(1, debug, sd, "no matching chip description found\n"); - kfree(chip); - return -EIO; - } - v4l2_info(sd, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name); - if (desc->flags) { - v4l2_dbg(1, debug, sd, "matches:%s%s%s.\n", - (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", - (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", - (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); - } - - /* fill required data structures */ - if (!id) - strlcpy(client->name, desc->name, I2C_NAME_SIZE); - chip->desc = desc; - chip->shadow.count = desc->registers+1; - chip->prevmode = -1; - chip->audmode = V4L2_TUNER_MODE_LANG1; - - /* initialization */ - if (desc->initialize != NULL) - desc->initialize(chip); - else - chip_cmd(chip, "init", &desc->init); - - if (desc->flags & CHIP_HAS_VOLUME) { - if (!desc->volfunc) { - /* This shouldn't be happen. Warn user, but keep working - without volume controls - */ - v4l2_info(sd, "volume callback undefined!\n"); - desc->flags &= ~CHIP_HAS_VOLUME; - } else { - chip->left = desc->leftinit ? desc->leftinit : 65535; - chip->right = desc->rightinit ? desc->rightinit : 65535; - chip_write(chip, desc->leftreg, - desc->volfunc(chip->left)); - chip_write(chip, desc->rightreg, - desc->volfunc(chip->right)); - } - } - if (desc->flags & CHIP_HAS_BASSTREBLE) { - if (!desc->bassfunc || !desc->treblefunc) { - /* This shouldn't be happen. Warn user, but keep working - without bass/treble controls - */ - v4l2_info(sd, "bass/treble callbacks undefined!\n"); - desc->flags &= ~CHIP_HAS_BASSTREBLE; - } else { - chip->treble = desc->trebleinit ? - desc->trebleinit : 32768; - chip->bass = desc->bassinit ? - desc->bassinit : 32768; - chip_write(chip, desc->bassreg, - desc->bassfunc(chip->bass)); - chip_write(chip, desc->treblereg, - desc->treblefunc(chip->treble)); - } - } - - chip->thread = NULL; - init_timer(&chip->wt); - if (desc->flags & CHIP_NEED_CHECKMODE) { - if (!desc->getmode || !desc->setmode) { - /* This shouldn't be happen. Warn user, but keep working - without kthread - */ - v4l2_info(sd, "set/get mode callbacks undefined!\n"); - return 0; - } - /* start async thread */ - chip->wt.function = chip_thread_wake; - chip->wt.data = (unsigned long)chip; - chip->thread = kthread_run(chip_thread, chip, client->name); - if (IS_ERR(chip->thread)) { - v4l2_warn(sd, "failed to create kthread\n"); - chip->thread = NULL; - } - } - return 0; -} - -static int tvaudio_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct CHIPSTATE *chip = to_state(sd); - - del_timer_sync(&chip->wt); - if (chip->thread) { - /* shutdown async thread */ - kthread_stop(chip->thread); - chip->thread = NULL; - } - - v4l2_device_unregister_subdev(sd); - kfree(chip); - return 0; -} - -/* This driver supports many devices and the idea is to let the driver - detect which device is present. So rather than listing all supported - devices here, we pretend to support a single, fake device type. */ -static const struct i2c_device_id tvaudio_id[] = { - { "tvaudio", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tvaudio_id); - -static struct i2c_driver tvaudio_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tvaudio", - }, - .probe = tvaudio_probe, - .remove = tvaudio_remove, - .id_table = tvaudio_id, -}; - -static __init int init_tvaudio(void) -{ - return i2c_add_driver(&tvaudio_driver); -} - -static __exit void exit_tvaudio(void) -{ - i2c_del_driver(&tvaudio_driver); -} - -module_init(init_tvaudio); -module_exit(exit_tvaudio); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tveeprom.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tveeprom.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tveeprom.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tveeprom.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,778 +0,0 @@ -/* - * tveeprom - eeprom decoder for tvcard configuration eeproms - * - * Data and decoding routines shamelessly borrowed from bttv-cards.c - * eeprom access routine shamelessly borrowed from bttv-if.c - * which are: - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999-2001 Gerd Knorr - - * Adjustments to fit a more general model and all bugs: - - Copyright (C) 2003 John Klar - - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); -MODULE_AUTHOR("John Klar"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -#define STRM(array, i) \ - (i < sizeof(array) / sizeof(char *) ? array[i] : "unknown") - -#define tveeprom_info(fmt, arg...) \ - v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg) -#define tveeprom_warn(fmt, arg...) \ - v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg) -#define tveeprom_dbg(fmt, arg...) do { \ - if (debug) \ - v4l_printk(KERN_DEBUG, "tveeprom", \ - c->adapter, c->addr, fmt , ## arg); \ - } while (0) - -/* - * The Hauppauge eeprom uses an 8bit field to determine which - * tuner formats the tuner supports. - */ -static struct HAUPPAUGE_TUNER_FMT -{ - int id; - char *name; -} -hauppauge_tuner_fmt[] = -{ - { V4L2_STD_UNKNOWN, " UNKNOWN" }, - { V4L2_STD_UNKNOWN, " FM" }, - { V4L2_STD_B|V4L2_STD_GH, " PAL(B/G)" }, - { V4L2_STD_MN, " NTSC(M)" }, - { V4L2_STD_PAL_I, " PAL(I)" }, - { V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, " SECAM(L/L')" }, - { V4L2_STD_DK, " PAL(D/D1/K)" }, - { V4L2_STD_ATSC, " ATSC/DVB Digital" }, -}; - -/* This is the full list of possible tuners. Many thanks to Hauppauge for - supplying this information. Note that many tuners where only used for - testing and never made it to the outside world. So you will only see - a subset in actual produced cards. */ -static struct HAUPPAUGE_TUNER -{ - int id; - char *name; -} -hauppauge_tuner[] = -{ - /* 0-9 */ - { TUNER_ABSENT, "None" }, - { TUNER_ABSENT, "External" }, - { TUNER_ABSENT, "Unspecified" }, - { TUNER_PHILIPS_PAL, "Philips FI1216" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, - { TUNER_PHILIPS_PAL_DK, "Philips FI1256" }, - { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, - /* 10-19 */ - { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, - { TUNER_PHILIPS_PAL_DK, "Philips FI1256 MK2" }, - { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, - { TUNER_TEMIC_PAL, "Temic 4002FH5" }, - { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, - { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, - /* 20-29 */ - { TUNER_PHILIPS_PAL_DK, "Philips FR1256 MK2" }, - { TUNER_PHILIPS_PAL, "Philips FM1216" }, - { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FM1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, - { TUNER_PHILIPS_PAL_DK, "Philips FM1256" }, - { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, - { TUNER_ABSENT, "Samsung TCPN9082D" }, - { TUNER_ABSENT, "Samsung TCPM9092P" }, - { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, - /* 30-39 */ - { TUNER_ABSENT, "Samsung TCPN9085D" }, - { TUNER_ABSENT, "Samsung TCPB9085P" }, - { TUNER_ABSENT, "Samsung TCPL9091P" }, - { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, - { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, - { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, - { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ - { TUNER_ABSENT, "Philips FI1256MP" }, - /* 40-49 */ - { TUNER_ABSENT, "Samsung TCPQ9091P" }, - { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" }, - { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, - { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, - { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, - { TUNER_ABSENT, "Philips TD1536D FH 44"}, - { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, - { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, - { TUNER_LG_PAL, "LG TP18PSB11D"}, - { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, - /* 50-59 */ - { TUNER_LG_PAL_I, "LG TAPC-I701D"}, - { TUNER_ABSENT, "Temic 4042FI5"}, - { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, - { TUNER_ABSENT, "LG TPI8NSR11F"}, - { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, - { TUNER_ABSENT, "Philips FI1236 MK3"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, - { TUNER_ABSENT, "Philips FM1216MP MK3"}, - /* 60-69 */ - { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, - { TUNER_ABSENT, "LG M001D MK3"}, - { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, - { TUNER_ABSENT, "LG M701D MK3"}, - { TUNER_ABSENT, "Temic 4146FM5"}, - { TUNER_ABSENT, "Temic 4136FY5"}, - { TUNER_ABSENT, "Temic 4106FH5"}, - { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, - { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, - { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, - /* 70-79 */ - { TUNER_ABSENT, "LG TALN H200T"}, - { TUNER_ABSENT, "LG TALN H250T"}, - { TUNER_ABSENT, "LG TALN M200T"}, - { TUNER_ABSENT, "LG TALN Z200T"}, - { TUNER_ABSENT, "LG TALN S200T"}, - { TUNER_ABSENT, "Thompson DTT7595"}, - { TUNER_ABSENT, "Thompson DTT7592"}, - { TUNER_ABSENT, "Silicon TDA8275C1 8290"}, - { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, - { TUNER_ABSENT, "Thompson DTT757"}, - /* 80-89 */ - { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK3"}, - { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, - { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, - { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, - { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, - { TUNER_TCL_2002N, "TCL 2002N 6A"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"}, - { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"}, - { TUNER_ABSENT, "Samsung TCPE 4121P30A"}, - { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"}, - /* 90-99 */ - { TUNER_ABSENT, "LG TALN H202T"}, - { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, - { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, - { TUNER_ABSENT, "Philips FQ1286A MK4"}, - { TUNER_ABSENT, "Philips FQ1216ME MK5"}, - { TUNER_ABSENT, "Philips FQ1236 MK5"}, - { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"}, - { TUNER_TCL_2002MB, "TCL 2002MB_3H"}, - { TUNER_ABSENT, "TCL 2002MI_3H"}, - { TUNER_TCL_2002N, "TCL 2002N 5H"}, - /* 100-109 */ - { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"}, - { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, - { TUNER_ABSENT, "Panasonic ENV57H12D5"}, - { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, - { TUNER_PHILIPS_FM1236_MK3, "TCL MNM05-4"}, - { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, - { TUNER_ABSENT, "TCL MQNM05-4"}, - { TUNER_ABSENT, "LG TAPC-W701D"}, - { TUNER_ABSENT, "TCL 9886P-WM"}, - { TUNER_ABSENT, "TCL 1676NM-WM"}, - /* 110-119 */ - { TUNER_ABSENT, "Thompson DTT75105"}, - { TUNER_ABSENT, "Conexant_CX24109"}, - { TUNER_TCL_2002N, "TCL M2523_5N_E"}, - { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, - { TUNER_ABSENT, "Philips 8275A"}, - { TUNER_ABSENT, "Microtune MT2060"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, - { TUNER_ABSENT, "TCL M2523_3DI_E"}, - { TUNER_ABSENT, "Samsung THPD5222FG30A"}, - /* 120-129 */ - { TUNER_XC2028, "Xceive XC3028"}, - { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK5"}, - { TUNER_ABSENT, "Philips FQD1216LME"}, - { TUNER_ABSENT, "Conexant CX24118A"}, - { TUNER_ABSENT, "TCL DMF11WIP"}, - { TUNER_ABSENT, "TCL MFNM05_4H_E"}, - { TUNER_ABSENT, "TCL MNM05_4H_E"}, - { TUNER_ABSENT, "TCL MPE05_2H_E"}, - { TUNER_ABSENT, "TCL MQNM05_4_U"}, - { TUNER_ABSENT, "TCL M2523_5NH_E"}, - /* 130-139 */ - { TUNER_ABSENT, "TCL M2523_3DBH_E"}, - { TUNER_ABSENT, "TCL M2523_3DIH_E"}, - { TUNER_ABSENT, "TCL MFPE05_2_U"}, - { TUNER_PHILIPS_FMD1216MEX_MK3, "Philips FMD1216MEX"}, - { TUNER_ABSENT, "Philips FRH2036B"}, - { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, - { TUNER_ABSENT, "MaxLinear MXL5005"}, - { TUNER_ABSENT, "MaxLinear MXL5003"}, - { TUNER_ABSENT, "Xceive XC2028"}, - { TUNER_ABSENT, "Microtune MT2131"}, - /* 140-149 */ - { TUNER_ABSENT, "Philips 8275A_8295"}, - { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, - { TUNER_ABSENT, "Microtune MT2266"}, - { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, - { TUNER_ABSENT, "LG TAPQ_H702F"}, - { TUNER_ABSENT, "TCL M09WPP_4N_E"}, - { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, - { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, - /* 150-159 */ - { TUNER_XC5000, "Xceive XC5000"}, - { TUNER_ABSENT, "Xceive XC3028L"}, - { TUNER_ABSENT, "NXP 18271C2_716x"}, - { TUNER_ABSENT, "Xceive XC4000"}, - { TUNER_ABSENT, "Dibcom 7070"}, - { TUNER_PHILIPS_TDA8290, "NXP 18271C2"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - /* 160-169 */ - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_ABSENT, "unknown"}, - { TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"}, - { TUNER_ABSENT, "unknown"}, -}; - -/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are - * internal to a video chip, i.e. not a separate audio chip. */ -static struct HAUPPAUGE_AUDIOIC -{ - u32 id; - char *name; -} -audioIC[] = -{ - /* 0-4 */ - { V4L2_IDENT_NONE, "None" }, - { V4L2_IDENT_UNKNOWN, "TEA6300" }, - { V4L2_IDENT_UNKNOWN, "TEA6320" }, - { V4L2_IDENT_UNKNOWN, "TDA9850" }, - { V4L2_IDENT_MSPX4XX, "MSP3400C" }, - /* 5-9 */ - { V4L2_IDENT_MSPX4XX, "MSP3410D" }, - { V4L2_IDENT_MSPX4XX, "MSP3415" }, - { V4L2_IDENT_MSPX4XX, "MSP3430" }, - { V4L2_IDENT_MSPX4XX, "MSP3438" }, - { V4L2_IDENT_UNKNOWN, "CS5331" }, - /* 10-14 */ - { V4L2_IDENT_MSPX4XX, "MSP3435" }, - { V4L2_IDENT_MSPX4XX, "MSP3440" }, - { V4L2_IDENT_MSPX4XX, "MSP3445" }, - { V4L2_IDENT_MSPX4XX, "MSP3411" }, - { V4L2_IDENT_MSPX4XX, "MSP3416" }, - /* 15-19 */ - { V4L2_IDENT_MSPX4XX, "MSP3425" }, - { V4L2_IDENT_MSPX4XX, "MSP3451" }, - { V4L2_IDENT_MSPX4XX, "MSP3418" }, - { V4L2_IDENT_UNKNOWN, "Type 0x12" }, - { V4L2_IDENT_UNKNOWN, "OKI7716" }, - /* 20-24 */ - { V4L2_IDENT_MSPX4XX, "MSP4410" }, - { V4L2_IDENT_MSPX4XX, "MSP4420" }, - { V4L2_IDENT_MSPX4XX, "MSP4440" }, - { V4L2_IDENT_MSPX4XX, "MSP4450" }, - { V4L2_IDENT_MSPX4XX, "MSP4408" }, - /* 25-29 */ - { V4L2_IDENT_MSPX4XX, "MSP4418" }, - { V4L2_IDENT_MSPX4XX, "MSP4428" }, - { V4L2_IDENT_MSPX4XX, "MSP4448" }, - { V4L2_IDENT_MSPX4XX, "MSP4458" }, - { V4L2_IDENT_MSPX4XX, "Type 0x1d" }, - /* 30-34 */ - { V4L2_IDENT_AMBIGUOUS, "CX880" }, - { V4L2_IDENT_AMBIGUOUS, "CX881" }, - { V4L2_IDENT_AMBIGUOUS, "CX883" }, - { V4L2_IDENT_AMBIGUOUS, "CX882" }, - { V4L2_IDENT_AMBIGUOUS, "CX25840" }, - /* 35-39 */ - { V4L2_IDENT_AMBIGUOUS, "CX25841" }, - { V4L2_IDENT_AMBIGUOUS, "CX25842" }, - { V4L2_IDENT_AMBIGUOUS, "CX25843" }, - { V4L2_IDENT_AMBIGUOUS, "CX23418" }, - { V4L2_IDENT_AMBIGUOUS, "CX23885" }, - /* 40-44 */ - { V4L2_IDENT_AMBIGUOUS, "CX23888" }, - { V4L2_IDENT_AMBIGUOUS, "SAA7131" }, - { V4L2_IDENT_AMBIGUOUS, "CX23887" }, - { V4L2_IDENT_AMBIGUOUS, "SAA7164" }, - { V4L2_IDENT_AMBIGUOUS, "AU8522" }, -}; - -/* This list is supplied by Hauppauge. Thanks! */ -static const char *decoderIC[] = { - /* 0-4 */ - "None", "BT815", "BT817", "BT819", "BT815A", - /* 5-9 */ - "BT817A", "BT819A", "BT827", "BT829", "BT848", - /* 10-14 */ - "BT848A", "BT849A", "BT829A", "BT827A", "BT878", - /* 15-19 */ - "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115", - /* 20-24 */ - "CX880", "CX881", "CX883", "SAA7111", "SAA7113", - /* 25-29 */ - "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", - /* 30-34 */ - "CX25843", "CX23418", "NEC61153", "CX23885", "CX23888", - /* 35-39 */ - "SAA7131", "CX25837", "CX23887", "CX23885A", "CX23887A", - /* 40-42 */ - "SAA7164", "CX23885B", "AU8522" -}; - -static int hasRadioTuner(int tunerType) -{ - switch (tunerType) { - case 18: /* PNPEnv_TUNER_FR1236_MK2 */ - case 23: /* PNPEnv_TUNER_FM1236 */ - case 38: /* PNPEnv_TUNER_FMR1236 */ - case 16: /* PNPEnv_TUNER_FR1216_MK2 */ - case 19: /* PNPEnv_TUNER_FR1246_MK2 */ - case 21: /* PNPEnv_TUNER_FM1216 */ - case 24: /* PNPEnv_TUNER_FM1246 */ - case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */ - case 22: /* PNPEnv_TUNER_FM1216MF */ - case 20: /* PNPEnv_TUNER_FR1256_MK2 */ - case 25: /* PNPEnv_TUNER_FM1256 */ - case 33: /* PNPEnv_TUNER_4039FR5 */ - case 42: /* PNPEnv_TUNER_4009FR5 */ - case 52: /* PNPEnv_TUNER_4049FM5 */ - case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */ - case 44: /* PNPEnv_TUNER_4009FN5 */ - case 31: /* PNPEnv_TUNER_TCPB9085P */ - case 30: /* PNPEnv_TUNER_TCPN9085D */ - case 46: /* PNPEnv_TUNER_TP18NSR01F */ - case 47: /* PNPEnv_TUNER_TP18PSB01D */ - case 49: /* PNPEnv_TUNER_TAPC_I001D */ - case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */ - case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */ - case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */ - case 58: /* PNPEnv_TUNER_FM1236_MK3 */ - case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */ - case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */ - case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */ - case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */ - case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */ - case 105: - return 1; - } - return 0; -} - -void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, - unsigned char *eeprom_data) -{ - /* ---------------------------------------------- - ** The hauppauge eeprom format is tagged - ** - ** if packet[0] == 0x84, then packet[0..1] == length - ** else length = packet[0] & 3f; - ** if packet[0] & f8 == f8, then EOD and packet[1] == checksum - ** - ** In our (ivtv) case we're interested in the following: - ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) - ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into - ** hauppauge_tuner_fmt) - ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) - ** audio proc: tag [02].01 or [05].00 (mask with 0x7f) - ** decoder proc: tag [09].01) - - ** Fun info: - ** model: tag [00].07-08 or [06].00-01 - ** revision: tag [00].09-0b or [06].04-06 - ** serial#: tag [01].05-07 or [04].04-06 - - ** # of inputs/outputs ??? - */ - - int i, j, len, done, beenhere, tag, start; - - int tuner1 = 0, t_format1 = 0, audioic = -1; - char *t_name1 = NULL; - const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" }; - - int tuner2 = 0, t_format2 = 0; - char *t_name2 = NULL; - const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" }; - - memset(tvee, 0, sizeof(*tvee)); - tvee->tuner_type = TUNER_ABSENT; - tvee->tuner2_type = TUNER_ABSENT; - - done = len = beenhere = 0; - - /* Different eeprom start offsets for em28xx, cx2388x and cx23418 */ - if (eeprom_data[0] == 0x1a && - eeprom_data[1] == 0xeb && - eeprom_data[2] == 0x67 && - eeprom_data[3] == 0x95) - start = 0xa0; /* Generic em28xx offset */ - else if ((eeprom_data[0] & 0xe1) == 0x01 && - eeprom_data[1] == 0x00 && - eeprom_data[2] == 0x00 && - eeprom_data[8] == 0x84) - start = 8; /* Generic cx2388x offset */ - else if (eeprom_data[1] == 0x70 && - eeprom_data[2] == 0x00 && - eeprom_data[4] == 0x74 && - eeprom_data[8] == 0x84) - start = 8; /* Generic cx23418 offset (models 74xxx) */ - else - start = 0; - - for (i = start; !done && i < 256; i += len) { - if (eeprom_data[i] == 0x84) { - len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8); - i += 3; - } else if ((eeprom_data[i] & 0xf0) == 0x70) { - if (eeprom_data[i] & 0x08) { - /* verify checksum! */ - done = 1; - break; - } - len = eeprom_data[i] & 0x07; - ++i; - } else { - tveeprom_warn("Encountered bad packet header [%02x]. " - "Corrupt or not a Hauppauge eeprom.\n", - eeprom_data[i]); - return; - } - - if (debug) { - tveeprom_info("Tag [%02x] + %d bytes:", - eeprom_data[i], len - 1); - for (j = 1; j < len; j++) - printk(KERN_CONT " %02x", eeprom_data[i + j]); - printk(KERN_CONT "\n"); - } - - /* process by tag */ - tag = eeprom_data[i]; - switch (tag) { - case 0x00: - /* tag: 'Comprehensive' */ - tuner1 = eeprom_data[i+6]; - t_format1 = eeprom_data[i+5]; - tvee->has_radio = eeprom_data[i+len-1]; - /* old style tag, don't know how to detect - IR presence, mark as unknown. */ - tvee->has_ir = 0; - tvee->model = - eeprom_data[i+8] + - (eeprom_data[i+9] << 8); - tvee->revision = eeprom_data[i+10] + - (eeprom_data[i+11] << 8) + - (eeprom_data[i+12] << 16); - break; - - case 0x01: - /* tag: 'SerialID' */ - tvee->serial_number = - eeprom_data[i+6] + - (eeprom_data[i+7] << 8) + - (eeprom_data[i+8] << 16); - break; - - case 0x02: - /* tag 'AudioInfo' - Note mask with 0x7F, high bit used on some older models - to indicate 4052 mux was removed in favor of using MSP - inputs directly. */ - audioic = eeprom_data[i+2] & 0x7f; - if (audioic < ARRAY_SIZE(audioIC)) - tvee->audio_processor = audioIC[audioic].id; - else - tvee->audio_processor = V4L2_IDENT_UNKNOWN; - break; - - /* case 0x03: tag 'EEInfo' */ - - case 0x04: - /* tag 'SerialID2' */ - tvee->serial_number = - eeprom_data[i+5] + - (eeprom_data[i+6] << 8) + - (eeprom_data[i+7] << 16); - - if ((eeprom_data[i + 8] & 0xf0) && - (tvee->serial_number < 0xffffff)) { - tvee->MAC_address[0] = 0x00; - tvee->MAC_address[1] = 0x0D; - tvee->MAC_address[2] = 0xFE; - tvee->MAC_address[3] = eeprom_data[i + 7]; - tvee->MAC_address[4] = eeprom_data[i + 6]; - tvee->MAC_address[5] = eeprom_data[i + 5]; - tvee->has_MAC_address = 1; - } - break; - - case 0x05: - /* tag 'Audio2' - Note mask with 0x7F, high bit used on some older models - to indicate 4052 mux was removed in favor of using MSP - inputs directly. */ - audioic = eeprom_data[i+1] & 0x7f; - if (audioic < ARRAY_SIZE(audioIC)) - tvee->audio_processor = audioIC[audioic].id; - else - tvee->audio_processor = V4L2_IDENT_UNKNOWN; - - break; - - case 0x06: - /* tag 'ModelRev' */ - tvee->model = - eeprom_data[i + 1] + - (eeprom_data[i + 2] << 8) + - (eeprom_data[i + 3] << 16) + - (eeprom_data[i + 4] << 24); - tvee->revision = - eeprom_data[i + 5] + - (eeprom_data[i + 6] << 8) + - (eeprom_data[i + 7] << 16); - break; - - case 0x07: - /* tag 'Details': according to Hauppauge not interesting - on any PCI-era or later boards. */ - break; - - /* there is no tag 0x08 defined */ - - case 0x09: - /* tag 'Video' */ - tvee->decoder_processor = eeprom_data[i + 1]; - break; - - case 0x0a: - /* tag 'Tuner' */ - if (beenhere == 0) { - tuner1 = eeprom_data[i + 2]; - t_format1 = eeprom_data[i + 1]; - beenhere = 1; - } else { - /* a second (radio) tuner may be present */ - tuner2 = eeprom_data[i + 2]; - t_format2 = eeprom_data[i + 1]; - /* not a TV tuner? */ - if (t_format2 == 0) - tvee->has_radio = 1; /* must be radio */ - } - break; - - case 0x0b: - /* tag 'Inputs': according to Hauppauge this is specific - to each driver family, so no good assumptions can be - made. */ - break; - - /* case 0x0c: tag 'Balun' */ - /* case 0x0d: tag 'Teletext' */ - - case 0x0e: - /* tag: 'Radio' */ - tvee->has_radio = eeprom_data[i+1]; - break; - - case 0x0f: - /* tag 'IRInfo' */ - tvee->has_ir = 1 | (eeprom_data[i+1] << 1); - break; - - /* case 0x10: tag 'VBIInfo' */ - /* case 0x11: tag 'QCInfo' */ - /* case 0x12: tag 'InfoBits' */ - - default: - tveeprom_dbg("Not sure what to do with tag [%02x]\n", - tag); - /* dump the rest of the packet? */ - } - } - - if (!done) { - tveeprom_warn("Ran out of data!\n"); - return; - } - - if (tvee->revision != 0) { - tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f); - tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f); - tvee->rev_str[2] = 32 + ((tvee->revision >> 6) & 0x3f); - tvee->rev_str[3] = 32 + (tvee->revision & 0x3f); - tvee->rev_str[4] = 0; - } - - if (hasRadioTuner(tuner1) && !tvee->has_radio) { - tveeprom_info("The eeprom says no radio is present, but the tuner type\n"); - tveeprom_info("indicates otherwise. I will assume that radio is present.\n"); - tvee->has_radio = 1; - } - - if (tuner1 < ARRAY_SIZE(hauppauge_tuner)) { - tvee->tuner_type = hauppauge_tuner[tuner1].id; - t_name1 = hauppauge_tuner[tuner1].name; - } else { - t_name1 = "unknown"; - } - - if (tuner2 < ARRAY_SIZE(hauppauge_tuner)) { - tvee->tuner2_type = hauppauge_tuner[tuner2].id; - t_name2 = hauppauge_tuner[tuner2].name; - } else { - t_name2 = "unknown"; - } - - tvee->tuner_hauppauge_model = tuner1; - tvee->tuner2_hauppauge_model = tuner2; - tvee->tuner_formats = 0; - tvee->tuner2_formats = 0; - for (i = j = 0; i < 8; i++) { - if (t_format1 & (1 << i)) { - tvee->tuner_formats |= hauppauge_tuner_fmt[i].id; - t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name; - } - } - for (i = j = 0; i < 8; i++) { - if (t_format2 & (1 << i)) { - tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id; - t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name; - } - } - - tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", - tvee->model, tvee->rev_str, tvee->serial_number); - if (tvee->has_MAC_address == 1) - tveeprom_info("MAC address is %pM\n", tvee->MAC_address); - tveeprom_info("tuner model is %s (idx %d, type %d)\n", - t_name1, tuner1, tvee->tuner_type); - tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", - t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], - t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5], - t_fmt_name1[6], t_fmt_name1[7], t_format1); - if (tuner2) - tveeprom_info("second tuner model is %s (idx %d, type %d)\n", - t_name2, tuner2, tvee->tuner2_type); - if (t_format2) - tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", - t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], - t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5], - t_fmt_name2[6], t_fmt_name2[7], t_format2); - if (audioic < 0) { - tveeprom_info("audio processor is unknown (no idx)\n"); - tvee->audio_processor = V4L2_IDENT_UNKNOWN; - } else { - if (audioic < ARRAY_SIZE(audioIC)) - tveeprom_info("audio processor is %s (idx %d)\n", - audioIC[audioic].name, audioic); - else - tveeprom_info("audio processor is unknown (idx %d)\n", - audioic); - } - if (tvee->decoder_processor) - tveeprom_info("decoder processor is %s (idx %d)\n", - STRM(decoderIC, tvee->decoder_processor), - tvee->decoder_processor); - if (tvee->has_ir) - tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n", - tvee->has_radio ? "" : "no ", - (tvee->has_ir & 2) ? "" : "no ", - (tvee->has_ir & 4) ? "" : "no "); - else - tveeprom_info("has %sradio\n", - tvee->has_radio ? "" : "no "); -} -EXPORT_SYMBOL(tveeprom_hauppauge_analog); - -/* ----------------------------------------------------------------------- */ -/* generic helper functions */ - -int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) -{ - unsigned char buf; - int err; - - buf = 0; - err = i2c_master_send(c, &buf, 1); - if (err != 1) { - tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); - return -1; - } - err = i2c_master_recv(c, eedata, len); - if (err != len) { - tveeprom_warn("i2c eeprom read error (err=%d)\n", err); - return -1; - } - if (debug) { - int i; - - tveeprom_info("full 256-byte eeprom dump:\n"); - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - tveeprom_info("%02x:", i); - printk(KERN_CONT " %02x", eedata[i]); - if (15 == (i % 16)) - printk(KERN_CONT "\n"); - } - } - return 0; -} -EXPORT_SYMBOL(tveeprom_read); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp514x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp514x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp514x.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp514x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1176 +0,0 @@ -/* - * drivers/media/video/tvp514x.c - * - * TI TVP5146/47 decoder driver - * - * Copyright (C) 2008 Texas Instruments Inc - * Author: Vaibhav Hiremath - * - * Contributors: - * Sivaraj R - * Brijesh R Jadav - * Hardik Shah - * Manjunath Hadli - * Karicheri Muralidharan - * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "tvp514x_regs.h" - -/* Module Name */ -#define TVP514X_MODULE_NAME "tvp514x" - -/* Private macros for TVP */ -#define I2C_RETRY_COUNT (5) -#define LOCK_RETRY_COUNT (5) -#define LOCK_RETRY_DELAY (200) - -/* Debug functions */ -static int debug; -module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -MODULE_AUTHOR("Texas Instruments"); -MODULE_DESCRIPTION("TVP514X linux decoder driver"); -MODULE_LICENSE("GPL"); - -/* enum tvp514x_std - enum for supported standards */ -enum tvp514x_std { - STD_NTSC_MJ = 0, - STD_PAL_BDGHIN, - STD_INVALID -}; - -/** - * struct tvp514x_std_info - Structure to store standard informations - * @width: Line width in pixels - * @height:Number of active lines - * @video_std: Value to write in REG_VIDEO_STD register - * @standard: v4l2 standard structure information - */ -struct tvp514x_std_info { - unsigned long width; - unsigned long height; - u8 video_std; - struct v4l2_standard standard; -}; - -static struct tvp514x_reg tvp514x_reg_list_default[0x40]; - -static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable); -/** - * struct tvp514x_decoder - TVP5146/47 decoder object - * @sd: Subdevice Slave handle - * @tvp514x_regs: copy of hw's regs with preset values. - * @pdata: Board specific - * @ver: Chip version - * @streaming: TVP5146/47 decoder streaming - enabled or disabled. - * @current_std: Current standard - * @num_stds: Number of standards - * @std_list: Standards list - * @input: Input routing at chip level - * @output: Output routing at chip level - */ -struct tvp514x_decoder { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)]; - const struct tvp514x_platform_data *pdata; - - int ver; - int streaming; - - enum tvp514x_std current_std; - int num_stds; - const struct tvp514x_std_info *std_list; - /* Input and Output Routing parameters */ - u32 input; - u32 output; -}; - -/* TVP514x default register values */ -static struct tvp514x_reg tvp514x_reg_list_default[] = { - /* Composite selected */ - {TOK_WRITE, REG_INPUT_SEL, 0x05}, - {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F}, - /* Auto mode */ - {TOK_WRITE, REG_VIDEO_STD, 0x00}, - {TOK_WRITE, REG_OPERATION_MODE, 0x00}, - {TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F}, - {TOK_WRITE, REG_COLOR_KILLER, 0x10}, - {TOK_WRITE, REG_LUMA_CONTROL1, 0x00}, - {TOK_WRITE, REG_LUMA_CONTROL2, 0x00}, - {TOK_WRITE, REG_LUMA_CONTROL3, 0x02}, - {TOK_WRITE, REG_BRIGHTNESS, 0x80}, - {TOK_WRITE, REG_CONTRAST, 0x80}, - {TOK_WRITE, REG_SATURATION, 0x80}, - {TOK_WRITE, REG_HUE, 0x00}, - {TOK_WRITE, REG_CHROMA_CONTROL1, 0x00}, - {TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E}, - /* Reserved */ - {TOK_SKIP, 0x0F, 0x00}, - {TOK_WRITE, REG_COMP_PR_SATURATION, 0x80}, - {TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80}, - {TOK_WRITE, REG_COMP_PB_SATURATION, 0x80}, - /* Reserved */ - {TOK_SKIP, 0x13, 0x00}, - {TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80}, - /* Reserved */ - {TOK_SKIP, 0x15, 0x00}, - /* NTSC timing */ - {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55}, - {TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00}, - {TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25}, - {TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03}, - /* NTSC timing */ - {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00}, - {TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00}, - {TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40}, - {TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00}, - /* NTSC timing */ - {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04}, - {TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00}, - {TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07}, - {TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00}, - /* NTSC timing */ - {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01}, - {TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00}, - {TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15}, - {TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00}, - /* Reserved */ - {TOK_SKIP, 0x26, 0x00}, - /* Reserved */ - {TOK_SKIP, 0x27, 0x00}, - {TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC}, - /* Reserved */ - {TOK_SKIP, 0x29, 0x00}, - {TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00}, - /* Reserved */ - {TOK_SKIP, 0x2B, 0x00}, - {TOK_SKIP, REG_SCART_DELAY, 0x00}, - {TOK_SKIP, REG_CTI_DELAY, 0x00}, - {TOK_SKIP, REG_CTI_CONTROL, 0x00}, - /* Reserved */ - {TOK_SKIP, 0x2F, 0x00}, - /* Reserved */ - {TOK_SKIP, 0x30, 0x00}, - /* Reserved */ - {TOK_SKIP, 0x31, 0x00}, - /* HS, VS active high */ - {TOK_WRITE, REG_SYNC_CONTROL, 0x00}, - /* 10-bit BT.656 */ - {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00}, - /* Enable clk & data */ - {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11}, - /* Enable AVID & FLD */ - {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE}, - /* Enable VS & HS */ - {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF}, - {TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF}, - {TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF}, - /* Clear status */ - {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01}, - {TOK_TERM, 0, 0}, -}; - -/** - * Supported standards - - * - * Currently supports two standards only, need to add support for rest of the - * modes, like SECAM, etc... - */ -static const struct tvp514x_std_info tvp514x_std_list[] = { - /* Standard: STD_NTSC_MJ */ - [STD_NTSC_MJ] = { - .width = NTSC_NUM_ACTIVE_PIXELS, - .height = NTSC_NUM_ACTIVE_LINES, - .video_std = VIDEO_STD_NTSC_MJ_BIT, - .standard = { - .index = 0, - .id = V4L2_STD_NTSC, - .name = "NTSC", - .frameperiod = {1001, 30000}, - .framelines = 525 - }, - /* Standard: STD_PAL_BDGHIN */ - }, - [STD_PAL_BDGHIN] = { - .width = PAL_NUM_ACTIVE_PIXELS, - .height = PAL_NUM_ACTIVE_LINES, - .video_std = VIDEO_STD_PAL_BDGHIN_BIT, - .standard = { - .index = 1, - .id = V4L2_STD_PAL, - .name = "PAL", - .frameperiod = {1, 25}, - .framelines = 625 - }, - }, - /* Standard: need to add for additional standard */ -}; - - -static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd) -{ - return container_of(sd, struct tvp514x_decoder, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct tvp514x_decoder, hdl)->sd; -} - - -/** - * tvp514x_read_reg() - Read a value from a register in an TVP5146/47. - * @sd: ptr to v4l2_subdev struct - * @reg: TVP5146/47 register address - * - * Returns value read if successful, or non-zero (-1) otherwise. - */ -static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg) -{ - int err, retry = 0; - struct i2c_client *client = v4l2_get_subdevdata(sd); - -read_again: - - err = i2c_smbus_read_byte_data(client, reg); - if (err < 0) { - if (retry <= I2C_RETRY_COUNT) { - v4l2_warn(sd, "Read: retry ... %d\n", retry); - retry++; - msleep_interruptible(10); - goto read_again; - } - } - - return err; -} - -/** - * dump_reg() - dump the register content of TVP5146/47. - * @sd: ptr to v4l2_subdev struct - * @reg: TVP5146/47 register address - */ -static void dump_reg(struct v4l2_subdev *sd, u8 reg) -{ - u32 val; - - val = tvp514x_read_reg(sd, reg); - v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val); -} - -/** - * tvp514x_write_reg() - Write a value to a register in TVP5146/47 - * @sd: ptr to v4l2_subdev struct - * @reg: TVP5146/47 register address - * @val: value to be written to the register - * - * Write a value to a register in an TVP5146/47 decoder device. - * Returns zero if successful, or non-zero otherwise. - */ -static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - int err, retry = 0; - struct i2c_client *client = v4l2_get_subdevdata(sd); - -write_again: - - err = i2c_smbus_write_byte_data(client, reg, val); - if (err) { - if (retry <= I2C_RETRY_COUNT) { - v4l2_warn(sd, "Write: retry ... %d\n", retry); - retry++; - msleep_interruptible(10); - goto write_again; - } - } - - return err; -} - -/** - * tvp514x_write_regs() : Initializes a list of TVP5146/47 registers - * @sd: ptr to v4l2_subdev struct - * @reglist: list of TVP5146/47 registers and values - * - * Initializes a list of TVP5146/47 registers:- - * if token is TOK_TERM, then entire write operation terminates - * if token is TOK_DELAY, then a delay of 'val' msec is introduced - * if token is TOK_SKIP, then the register write is skipped - * if token is TOK_WRITE, then the register write is performed - * Returns zero if successful, or non-zero otherwise. - */ -static int tvp514x_write_regs(struct v4l2_subdev *sd, - const struct tvp514x_reg reglist[]) -{ - int err; - const struct tvp514x_reg *next = reglist; - - for (; next->token != TOK_TERM; next++) { - if (next->token == TOK_DELAY) { - msleep(next->val); - continue; - } - - if (next->token == TOK_SKIP) - continue; - - err = tvp514x_write_reg(sd, next->reg, (u8) next->val); - if (err) { - v4l2_err(sd, "Write failed. Err[%d]\n", err); - return err; - } - } - return 0; -} - -/** - * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47 - * @sd: ptr to v4l2_subdev struct - * - * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no - * standard detected. - */ -static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd) -{ - u8 std, std_status; - - std = tvp514x_read_reg(sd, REG_VIDEO_STD); - if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) - /* use the standard status register */ - std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS); - else - /* use the standard register itself */ - std_status = std; - - switch (std_status & VIDEO_STD_MASK) { - case VIDEO_STD_NTSC_MJ_BIT: - return STD_NTSC_MJ; - - case VIDEO_STD_PAL_BDGHIN_BIT: - return STD_PAL_BDGHIN; - - default: - return STD_INVALID; - } - - return STD_INVALID; -} - -/* TVP5146/47 register dump function */ -static void tvp514x_reg_dump(struct v4l2_subdev *sd) -{ - dump_reg(sd, REG_INPUT_SEL); - dump_reg(sd, REG_AFE_GAIN_CTRL); - dump_reg(sd, REG_VIDEO_STD); - dump_reg(sd, REG_OPERATION_MODE); - dump_reg(sd, REG_COLOR_KILLER); - dump_reg(sd, REG_LUMA_CONTROL1); - dump_reg(sd, REG_LUMA_CONTROL2); - dump_reg(sd, REG_LUMA_CONTROL3); - dump_reg(sd, REG_BRIGHTNESS); - dump_reg(sd, REG_CONTRAST); - dump_reg(sd, REG_SATURATION); - dump_reg(sd, REG_HUE); - dump_reg(sd, REG_CHROMA_CONTROL1); - dump_reg(sd, REG_CHROMA_CONTROL2); - dump_reg(sd, REG_COMP_PR_SATURATION); - dump_reg(sd, REG_COMP_Y_CONTRAST); - dump_reg(sd, REG_COMP_PB_SATURATION); - dump_reg(sd, REG_COMP_Y_BRIGHTNESS); - dump_reg(sd, REG_AVID_START_PIXEL_LSB); - dump_reg(sd, REG_AVID_START_PIXEL_MSB); - dump_reg(sd, REG_AVID_STOP_PIXEL_LSB); - dump_reg(sd, REG_AVID_STOP_PIXEL_MSB); - dump_reg(sd, REG_HSYNC_START_PIXEL_LSB); - dump_reg(sd, REG_HSYNC_START_PIXEL_MSB); - dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB); - dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB); - dump_reg(sd, REG_VSYNC_START_LINE_LSB); - dump_reg(sd, REG_VSYNC_START_LINE_MSB); - dump_reg(sd, REG_VSYNC_STOP_LINE_LSB); - dump_reg(sd, REG_VSYNC_STOP_LINE_MSB); - dump_reg(sd, REG_VBLK_START_LINE_LSB); - dump_reg(sd, REG_VBLK_START_LINE_MSB); - dump_reg(sd, REG_VBLK_STOP_LINE_LSB); - dump_reg(sd, REG_VBLK_STOP_LINE_MSB); - dump_reg(sd, REG_SYNC_CONTROL); - dump_reg(sd, REG_OUTPUT_FORMATTER1); - dump_reg(sd, REG_OUTPUT_FORMATTER2); - dump_reg(sd, REG_OUTPUT_FORMATTER3); - dump_reg(sd, REG_OUTPUT_FORMATTER4); - dump_reg(sd, REG_OUTPUT_FORMATTER5); - dump_reg(sd, REG_OUTPUT_FORMATTER6); - dump_reg(sd, REG_CLEAR_LOST_LOCK); -} - -/** - * tvp514x_configure() - Configure the TVP5146/47 registers - * @sd: ptr to v4l2_subdev struct - * @decoder: ptr to tvp514x_decoder structure - * - * Returns zero if successful, or non-zero otherwise. - */ -static int tvp514x_configure(struct v4l2_subdev *sd, - struct tvp514x_decoder *decoder) -{ - int err; - - /* common register initialization */ - err = - tvp514x_write_regs(sd, decoder->tvp514x_regs); - if (err) - return err; - - if (debug) - tvp514x_reg_dump(sd); - - return 0; -} - -/** - * tvp514x_detect() - Detect if an tvp514x is present, and if so which revision. - * @sd: pointer to standard V4L2 sub-device structure - * @decoder: pointer to tvp514x_decoder structure - * - * A device is considered to be detected if the chip ID (LSB and MSB) - * registers match the expected values. - * Any value of the rom version register is accepted. - * Returns ENODEV error number if no device is detected, or zero - * if a device is detected. - */ -static int tvp514x_detect(struct v4l2_subdev *sd, - struct tvp514x_decoder *decoder) -{ - u8 chip_id_msb, chip_id_lsb, rom_ver; - struct i2c_client *client = v4l2_get_subdevdata(sd); - - chip_id_msb = tvp514x_read_reg(sd, REG_CHIP_ID_MSB); - chip_id_lsb = tvp514x_read_reg(sd, REG_CHIP_ID_LSB); - rom_ver = tvp514x_read_reg(sd, REG_ROM_VERSION); - - v4l2_dbg(1, debug, sd, - "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n", - chip_id_msb, chip_id_lsb, rom_ver); - if ((chip_id_msb != TVP514X_CHIP_ID_MSB) - || ((chip_id_lsb != TVP5146_CHIP_ID_LSB) - && (chip_id_lsb != TVP5147_CHIP_ID_LSB))) { - /* We didn't read the values we expected, so this must not be - * an TVP5146/47. - */ - v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n", - chip_id_msb, chip_id_lsb); - return -ENODEV; - } - - decoder->ver = rom_ver; - - v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n", - client->name, decoder->ver, - client->addr << 1, client->adapter->name); - return 0; -} - -/** - * tvp514x_querystd() - V4L2 decoder interface handler for querystd - * @sd: pointer to standard V4L2 sub-device structure - * @std_id: standard V4L2 std_id ioctl enum - * - * Returns the current standard detected by TVP5146/47. If no active input is - * detected then *std_id is set to 0 and the function returns 0. - */ -static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - enum tvp514x_std current_std; - enum tvp514x_input input_sel; - u8 sync_lock_status, lock_mask; - - if (std_id == NULL) - return -EINVAL; - - *std_id = V4L2_STD_UNKNOWN; - - /* query the current standard */ - current_std = tvp514x_query_current_std(sd); - if (current_std == STD_INVALID) - return 0; - - input_sel = decoder->input; - - switch (input_sel) { - case INPUT_CVBS_VI1A: - case INPUT_CVBS_VI1B: - case INPUT_CVBS_VI1C: - case INPUT_CVBS_VI2A: - case INPUT_CVBS_VI2B: - case INPUT_CVBS_VI2C: - case INPUT_CVBS_VI3A: - case INPUT_CVBS_VI3B: - case INPUT_CVBS_VI3C: - case INPUT_CVBS_VI4A: - lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT | - STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - - case INPUT_SVIDEO_VI2A_VI1A: - case INPUT_SVIDEO_VI2B_VI1B: - case INPUT_SVIDEO_VI2C_VI1C: - case INPUT_SVIDEO_VI2A_VI3A: - case INPUT_SVIDEO_VI2B_VI3B: - case INPUT_SVIDEO_VI2C_VI3C: - case INPUT_SVIDEO_VI4A_VI1A: - case INPUT_SVIDEO_VI4A_VI1B: - case INPUT_SVIDEO_VI4A_VI1C: - case INPUT_SVIDEO_VI4A_VI3A: - case INPUT_SVIDEO_VI4A_VI3B: - case INPUT_SVIDEO_VI4A_VI3C: - lock_mask = STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - /*Need to add other interfaces*/ - default: - return -EINVAL; - } - /* check whether signal is locked */ - sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1); - if (lock_mask != (sync_lock_status & lock_mask)) - return 0; /* No input detected */ - - *std_id = decoder->std_list[current_std].standard.id; - - v4l2_dbg(1, debug, sd, "Current STD: %s\n", - decoder->std_list[current_std].standard.name); - return 0; -} - -/** - * tvp514x_s_std() - V4L2 decoder interface handler for s_std - * @sd: pointer to standard V4L2 sub-device structure - * @std_id: standard V4L2 v4l2_std_id ioctl enum - * - * If std_id is supported, sets the requested standard. Otherwise, returns - * -EINVAL - */ -static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - int err, i; - - for (i = 0; i < decoder->num_stds; i++) - if (std_id & decoder->std_list[i].standard.id) - break; - - if ((i == decoder->num_stds) || (i == STD_INVALID)) - return -EINVAL; - - err = tvp514x_write_reg(sd, REG_VIDEO_STD, - decoder->std_list[i].video_std); - if (err) - return err; - - decoder->current_std = i; - decoder->tvp514x_regs[REG_VIDEO_STD].val = - decoder->std_list[i].video_std; - - v4l2_dbg(1, debug, sd, "Standard set to: %s\n", - decoder->std_list[i].standard.name); - return 0; -} - -/** - * tvp514x_s_routing() - V4L2 decoder interface handler for s_routing - * @sd: pointer to standard V4L2 sub-device structure - * @input: input selector for routing the signal - * @output: output selector for routing the signal - * @config: config value. Not used - * - * If index is valid, selects the requested input. Otherwise, returns -EINVAL if - * the input is not supported or there is no active signal present in the - * selected input. - */ -static int tvp514x_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - int err; - enum tvp514x_input input_sel; - enum tvp514x_output output_sel; - u8 sync_lock_status, lock_mask; - int try_count = LOCK_RETRY_COUNT; - - if ((input >= INPUT_INVALID) || - (output >= OUTPUT_INVALID)) - /* Index out of bound */ - return -EINVAL; - - /* - * For the sequence streamon -> streamoff and again s_input - * it fails to lock the signal, since streamoff puts TVP514x - * into power off state which leads to failure in sub-sequent s_input. - * - * So power up the TVP514x device here, since it is important to lock - * the signal at this stage. - */ - if (!decoder->streaming) - tvp514x_s_stream(sd, 1); - - input_sel = input; - output_sel = output; - - err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel); - if (err) - return err; - - output_sel |= tvp514x_read_reg(sd, - REG_OUTPUT_FORMATTER1) & 0x7; - err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1, - output_sel); - if (err) - return err; - - decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel; - decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel; - - /* Clear status */ - msleep(LOCK_RETRY_DELAY); - err = - tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01); - if (err) - return err; - - switch (input_sel) { - case INPUT_CVBS_VI1A: - case INPUT_CVBS_VI1B: - case INPUT_CVBS_VI1C: - case INPUT_CVBS_VI2A: - case INPUT_CVBS_VI2B: - case INPUT_CVBS_VI2C: - case INPUT_CVBS_VI3A: - case INPUT_CVBS_VI3B: - case INPUT_CVBS_VI3C: - case INPUT_CVBS_VI4A: - lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT | - STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - - case INPUT_SVIDEO_VI2A_VI1A: - case INPUT_SVIDEO_VI2B_VI1B: - case INPUT_SVIDEO_VI2C_VI1C: - case INPUT_SVIDEO_VI2A_VI3A: - case INPUT_SVIDEO_VI2B_VI3B: - case INPUT_SVIDEO_VI2C_VI3C: - case INPUT_SVIDEO_VI4A_VI1A: - case INPUT_SVIDEO_VI4A_VI1B: - case INPUT_SVIDEO_VI4A_VI1C: - case INPUT_SVIDEO_VI4A_VI3A: - case INPUT_SVIDEO_VI4A_VI3B: - case INPUT_SVIDEO_VI4A_VI3C: - lock_mask = STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - /* Need to add other interfaces*/ - default: - return -EINVAL; - } - - while (try_count-- > 0) { - /* Allow decoder to sync up with new input */ - msleep(LOCK_RETRY_DELAY); - - sync_lock_status = tvp514x_read_reg(sd, - REG_STATUS1); - if (lock_mask == (sync_lock_status & lock_mask)) - /* Input detected */ - break; - } - - if (try_count < 0) - return -EINVAL; - - decoder->input = input; - decoder->output = output; - - v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel); - - return 0; -} - -/** - * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl - * @ctrl: pointer to v4l2_ctrl structure - * - * If the requested control is supported, sets the control's current - * value in HW. Otherwise, returns -EINVAL if the control is not supported. - */ -static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct tvp514x_decoder *decoder = to_decoder(sd); - int err = -EINVAL, value; - - value = ctrl->val; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - err = tvp514x_write_reg(sd, REG_BRIGHTNESS, value); - if (!err) - decoder->tvp514x_regs[REG_BRIGHTNESS].val = value; - break; - case V4L2_CID_CONTRAST: - err = tvp514x_write_reg(sd, REG_CONTRAST, value); - if (!err) - decoder->tvp514x_regs[REG_CONTRAST].val = value; - break; - case V4L2_CID_SATURATION: - err = tvp514x_write_reg(sd, REG_SATURATION, value); - if (!err) - decoder->tvp514x_regs[REG_SATURATION].val = value; - break; - case V4L2_CID_HUE: - if (value == 180) - value = 0x7F; - else if (value == -180) - value = 0x80; - err = tvp514x_write_reg(sd, REG_HUE, value); - if (!err) - decoder->tvp514x_regs[REG_HUE].val = value; - break; - case V4L2_CID_AUTOGAIN: - err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value ? 0x0f : 0x0c); - if (!err) - decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value; - break; - } - - v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n", - ctrl->id, ctrl->val); - return err; -} - -/** - * tvp514x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @index: index of pixelcode to retrieve - * @code: receives the pixelcode - * - * Enumerates supported mediabus formats - */ -static int -tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - enum v4l2_mbus_pixelcode *code) -{ - if (index) - return -EINVAL; - - *code = V4L2_MBUS_FMT_YUYV10_2X10; - return 0; -} - -/** - * tvp514x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to the mediabus format structure - * - * Negotiates the image capture size and mediabus format. - */ -static int -tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - enum tvp514x_std current_std; - - if (f == NULL) - return -EINVAL; - - /* Calculate height and width based on current standard */ - current_std = decoder->current_std; - - f->code = V4L2_MBUS_FMT_YUYV10_2X10; - f->width = decoder->std_list[current_std].width; - f->height = decoder->std_list[current_std].height; - f->field = V4L2_FIELD_INTERLACED; - f->colorspace = V4L2_COLORSPACE_SMPTE170M; - - v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n", - f->width, f->height); - return 0; -} - -/** - * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm - * @sd: pointer to standard V4L2 sub-device structure - * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure - * - * Returns the decoder's video CAPTURE parameters. - */ -static int -tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - struct v4l2_captureparm *cparm; - enum tvp514x_std current_std; - - if (a == NULL) - return -EINVAL; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; - - /* get the current standard */ - current_std = decoder->current_std; - - cparm = &a->parm.capture; - cparm->capability = V4L2_CAP_TIMEPERFRAME; - cparm->timeperframe = - decoder->std_list[current_std].standard.frameperiod; - - return 0; -} - -/** - * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm - * @sd: pointer to standard V4L2 sub-device structure - * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure - * - * Configures the decoder to use the input parameters, if possible. If - * not possible, returns the appropriate error code. - */ -static int -tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - struct v4l2_fract *timeperframe; - enum tvp514x_std current_std; - - if (a == NULL) - return -EINVAL; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; - - timeperframe = &a->parm.capture.timeperframe; - - /* get the current standard */ - current_std = decoder->current_std; - - *timeperframe = - decoder->std_list[current_std].standard.frameperiod; - - return 0; -} - -/** - * tvp514x_s_stream() - V4L2 decoder i/f handler for s_stream - * @sd: pointer to standard V4L2 sub-device structure - * @enable: streaming enable or disable - * - * Sets streaming to enable or disable, if possible. - */ -static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable) -{ - int err = 0; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tvp514x_decoder *decoder = to_decoder(sd); - - if (decoder->streaming == enable) - return 0; - - switch (enable) { - case 0: - { - /* Power Down Sequence */ - err = tvp514x_write_reg(sd, REG_OPERATION_MODE, 0x01); - if (err) { - v4l2_err(sd, "Unable to turn off decoder\n"); - return err; - } - decoder->streaming = enable; - break; - } - case 1: - { - struct tvp514x_reg *int_seq = (struct tvp514x_reg *) - client->driver->id_table->driver_data; - - /* Power Up Sequence */ - err = tvp514x_write_regs(sd, int_seq); - if (err) { - v4l2_err(sd, "Unable to turn on decoder\n"); - return err; - } - /* Detect if not already detected */ - err = tvp514x_detect(sd, decoder); - if (err) { - v4l2_err(sd, "Unable to detect decoder\n"); - return err; - } - err = tvp514x_configure(sd, decoder); - if (err) { - v4l2_err(sd, "Unable to configure decoder\n"); - return err; - } - decoder->streaming = enable; - break; - } - default: - err = -ENODEV; - break; - } - - return err; -} - -static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = { - .s_ctrl = tvp514x_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops tvp514x_core_ops = { - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = tvp514x_s_std, -}; - -static const struct v4l2_subdev_video_ops tvp514x_video_ops = { - .s_routing = tvp514x_s_routing, - .querystd = tvp514x_querystd, - .enum_mbus_fmt = tvp514x_enum_mbus_fmt, - .g_mbus_fmt = tvp514x_mbus_fmt, - .try_mbus_fmt = tvp514x_mbus_fmt, - .s_mbus_fmt = tvp514x_mbus_fmt, - .g_parm = tvp514x_g_parm, - .s_parm = tvp514x_s_parm, - .s_stream = tvp514x_s_stream, -}; - -static const struct v4l2_subdev_ops tvp514x_ops = { - .core = &tvp514x_core_ops, - .video = &tvp514x_video_ops, -}; - -static struct tvp514x_decoder tvp514x_dev = { - .streaming = 0, - .current_std = STD_NTSC_MJ, - .std_list = tvp514x_std_list, - .num_stds = ARRAY_SIZE(tvp514x_std_list), - -}; - -/** - * tvp514x_probe() - decoder driver i2c probe handler - * @client: i2c driver client device structure - * @id: i2c driver id table - * - * Register decoder as an i2c client device and V4L2 - * device. - */ -static int -tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct tvp514x_decoder *decoder; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - if (!client->dev.platform_data) { - v4l2_err(client, "No platform data!!\n"); - return -ENODEV; - } - - decoder = kzalloc(sizeof(*decoder), GFP_KERNEL); - if (!decoder) - return -ENOMEM; - - /* Initialize the tvp514x_decoder with default configuration */ - *decoder = tvp514x_dev; - /* Copy default register configuration */ - memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default, - sizeof(tvp514x_reg_list_default)); - - /* Copy board specific information here */ - decoder->pdata = client->dev.platform_data; - - /** - * Fetch platform specific data, and configure the - * tvp514x_reg_list[] accordingly. Since this is one - * time configuration, no need to preserve. - */ - decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |= - (decoder->pdata->clk_polarity << 1); - decoder->tvp514x_regs[REG_SYNC_CONTROL].val |= - ((decoder->pdata->hs_polarity << 2) | - (decoder->pdata->vs_polarity << 3)); - /* Set default standard to auto */ - decoder->tvp514x_regs[REG_VIDEO_STD].val = - VIDEO_STD_AUTO_SWITCH_BIT; - - /* Register with V4L2 layer as slave device */ - sd = &decoder->sd; - v4l2_i2c_subdev_init(sd, client, &tvp514x_ops); - - v4l2_ctrl_handler_init(&decoder->hdl, 5); - v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 128); - v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 128); - v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, - V4L2_CID_HUE, -180, 180, 180, 0); - v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, - V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - sd->ctrl_handler = &decoder->hdl; - if (decoder->hdl.error) { - int err = decoder->hdl.error; - - v4l2_ctrl_handler_free(&decoder->hdl); - kfree(decoder); - return err; - } - v4l2_ctrl_handler_setup(&decoder->hdl); - - v4l2_info(sd, "%s decoder driver registered !!\n", sd->name); - - return 0; - -} - -/** - * tvp514x_remove() - decoder driver i2c remove handler - * @client: i2c driver client device structure - * - * Unregister decoder as an i2c client device and V4L2 - * device. Complement of tvp514x_probe(). - */ -static int tvp514x_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct tvp514x_decoder *decoder = to_decoder(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&decoder->hdl); - kfree(decoder); - return 0; -} -/* TVP5146 Init/Power on Sequence */ -static const struct tvp514x_reg tvp5146_init_reg_seq[] = { - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80}, - {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0}, - {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01}, - {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00}, - {TOK_WRITE, REG_OPERATION_MODE, 0x01}, - {TOK_WRITE, REG_OPERATION_MODE, 0x00}, - {TOK_TERM, 0, 0}, -}; - -/* TVP5147 Init/Power on Sequence */ -static const struct tvp514x_reg tvp5147_init_reg_seq[] = { - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80}, - {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0}, - {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x16}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xA0}, - {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x16}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, - {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0}, - {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00}, - {TOK_WRITE, REG_OPERATION_MODE, 0x01}, - {TOK_WRITE, REG_OPERATION_MODE, 0x00}, - {TOK_TERM, 0, 0}, -}; - -/* TVP5146M2/TVP5147M1 Init/Power on Sequence */ -static const struct tvp514x_reg tvp514xm_init_reg_seq[] = { - {TOK_WRITE, REG_OPERATION_MODE, 0x01}, - {TOK_WRITE, REG_OPERATION_MODE, 0x00}, - {TOK_TERM, 0, 0}, -}; - -/** - * I2C Device Table - - * - * name - Name of the actual device/chip. - * driver_data - Driver data - */ -static const struct i2c_device_id tvp514x_id[] = { - {"tvp5146", (unsigned long)tvp5146_init_reg_seq}, - {"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq}, - {"tvp5147", (unsigned long)tvp5147_init_reg_seq}, - {"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, tvp514x_id); - -static struct i2c_driver tvp514x_driver = { - .driver = { - .owner = THIS_MODULE, - .name = TVP514X_MODULE_NAME, - }, - .probe = tvp514x_probe, - .remove = tvp514x_remove, - .id_table = tvp514x_id, -}; - -static int __init tvp514x_init(void) -{ - return i2c_add_driver(&tvp514x_driver); -} - -static void __exit tvp514x_exit(void) -{ - i2c_del_driver(&tvp514x_driver); -} - -module_init(tvp514x_init); -module_exit(tvp514x_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp514x_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp514x_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp514x_regs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp514x_regs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,287 +0,0 @@ -/* - * drivers/media/video/tvp514x_regs.h - * - * Copyright (C) 2008 Texas Instruments Inc - * Author: Vaibhav Hiremath - * - * Contributors: - * Sivaraj R - * Brijesh R Jadav - * Hardik Shah - * Manjunath Hadli - * Karicheri Muralidharan - * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _TVP514X_REGS_H -#define _TVP514X_REGS_H - -/* - * TVP5146/47 registers - */ -#define REG_INPUT_SEL (0x00) -#define REG_AFE_GAIN_CTRL (0x01) -#define REG_VIDEO_STD (0x02) -#define REG_OPERATION_MODE (0x03) -#define REG_AUTOSWITCH_MASK (0x04) - -#define REG_COLOR_KILLER (0x05) -#define REG_LUMA_CONTROL1 (0x06) -#define REG_LUMA_CONTROL2 (0x07) -#define REG_LUMA_CONTROL3 (0x08) - -#define REG_BRIGHTNESS (0x09) -#define REG_CONTRAST (0x0A) -#define REG_SATURATION (0x0B) -#define REG_HUE (0x0C) - -#define REG_CHROMA_CONTROL1 (0x0D) -#define REG_CHROMA_CONTROL2 (0x0E) - -/* 0x0F Reserved */ - -#define REG_COMP_PR_SATURATION (0x10) -#define REG_COMP_Y_CONTRAST (0x11) -#define REG_COMP_PB_SATURATION (0x12) - -/* 0x13 Reserved */ - -#define REG_COMP_Y_BRIGHTNESS (0x14) - -/* 0x15 Reserved */ - -#define REG_AVID_START_PIXEL_LSB (0x16) -#define REG_AVID_START_PIXEL_MSB (0x17) -#define REG_AVID_STOP_PIXEL_LSB (0x18) -#define REG_AVID_STOP_PIXEL_MSB (0x19) - -#define REG_HSYNC_START_PIXEL_LSB (0x1A) -#define REG_HSYNC_START_PIXEL_MSB (0x1B) -#define REG_HSYNC_STOP_PIXEL_LSB (0x1C) -#define REG_HSYNC_STOP_PIXEL_MSB (0x1D) - -#define REG_VSYNC_START_LINE_LSB (0x1E) -#define REG_VSYNC_START_LINE_MSB (0x1F) -#define REG_VSYNC_STOP_LINE_LSB (0x20) -#define REG_VSYNC_STOP_LINE_MSB (0x21) - -#define REG_VBLK_START_LINE_LSB (0x22) -#define REG_VBLK_START_LINE_MSB (0x23) -#define REG_VBLK_STOP_LINE_LSB (0x24) -#define REG_VBLK_STOP_LINE_MSB (0x25) - -/* 0x26 - 0x27 Reserved */ - -#define REG_FAST_SWTICH_CONTROL (0x28) - -/* 0x29 Reserved */ - -#define REG_FAST_SWTICH_SCART_DELAY (0x2A) - -/* 0x2B Reserved */ - -#define REG_SCART_DELAY (0x2C) -#define REG_CTI_DELAY (0x2D) -#define REG_CTI_CONTROL (0x2E) - -/* 0x2F - 0x31 Reserved */ - -#define REG_SYNC_CONTROL (0x32) -#define REG_OUTPUT_FORMATTER1 (0x33) -#define REG_OUTPUT_FORMATTER2 (0x34) -#define REG_OUTPUT_FORMATTER3 (0x35) -#define REG_OUTPUT_FORMATTER4 (0x36) -#define REG_OUTPUT_FORMATTER5 (0x37) -#define REG_OUTPUT_FORMATTER6 (0x38) -#define REG_CLEAR_LOST_LOCK (0x39) - -#define REG_STATUS1 (0x3A) -#define REG_STATUS2 (0x3B) - -#define REG_AGC_GAIN_STATUS_LSB (0x3C) -#define REG_AGC_GAIN_STATUS_MSB (0x3D) - -/* 0x3E Reserved */ - -#define REG_VIDEO_STD_STATUS (0x3F) -#define REG_GPIO_INPUT1 (0x40) -#define REG_GPIO_INPUT2 (0x41) - -/* 0x42 - 0x45 Reserved */ - -#define REG_AFE_COARSE_GAIN_CH1 (0x46) -#define REG_AFE_COARSE_GAIN_CH2 (0x47) -#define REG_AFE_COARSE_GAIN_CH3 (0x48) -#define REG_AFE_COARSE_GAIN_CH4 (0x49) - -#define REG_AFE_FINE_GAIN_PB_B_LSB (0x4A) -#define REG_AFE_FINE_GAIN_PB_B_MSB (0x4B) -#define REG_AFE_FINE_GAIN_Y_G_CHROMA_LSB (0x4C) -#define REG_AFE_FINE_GAIN_Y_G_CHROMA_MSB (0x4D) -#define REG_AFE_FINE_GAIN_PR_R_LSB (0x4E) -#define REG_AFE_FINE_GAIN_PR_R_MSB (0x4F) -#define REG_AFE_FINE_GAIN_CVBS_LUMA_LSB (0x50) -#define REG_AFE_FINE_GAIN_CVBS_LUMA_MSB (0x51) - -/* 0x52 - 0x68 Reserved */ - -#define REG_FBIT_VBIT_CONTROL1 (0x69) - -/* 0x6A - 0x6B Reserved */ - -#define REG_BACKEND_AGC_CONTROL (0x6C) - -/* 0x6D - 0x6E Reserved */ - -#define REG_AGC_DECREMENT_SPEED_CONTROL (0x6F) -#define REG_ROM_VERSION (0x70) - -/* 0x71 - 0x73 Reserved */ - -#define REG_AGC_WHITE_PEAK_PROCESSING (0x74) -#define REG_FBIT_VBIT_CONTROL2 (0x75) -#define REG_VCR_TRICK_MODE_CONTROL (0x76) -#define REG_HORIZONTAL_SHAKE_INCREMENT (0x77) -#define REG_AGC_INCREMENT_SPEED (0x78) -#define REG_AGC_INCREMENT_DELAY (0x79) - -/* 0x7A - 0x7F Reserved */ - -#define REG_CHIP_ID_MSB (0x80) -#define REG_CHIP_ID_LSB (0x81) - -/* 0x82 Reserved */ - -#define REG_CPLL_SPEED_CONTROL (0x83) - -/* 0x84 - 0x96 Reserved */ - -#define REG_STATUS_REQUEST (0x97) - -/* 0x98 - 0x99 Reserved */ - -#define REG_VERTICAL_LINE_COUNT_LSB (0x9A) -#define REG_VERTICAL_LINE_COUNT_MSB (0x9B) - -/* 0x9C - 0x9D Reserved */ - -#define REG_AGC_DECREMENT_DELAY (0x9E) - -/* 0x9F - 0xB0 Reserved */ - -#define REG_VDP_TTX_FILTER_1_MASK1 (0xB1) -#define REG_VDP_TTX_FILTER_1_MASK2 (0xB2) -#define REG_VDP_TTX_FILTER_1_MASK3 (0xB3) -#define REG_VDP_TTX_FILTER_1_MASK4 (0xB4) -#define REG_VDP_TTX_FILTER_1_MASK5 (0xB5) -#define REG_VDP_TTX_FILTER_2_MASK1 (0xB6) -#define REG_VDP_TTX_FILTER_2_MASK2 (0xB7) -#define REG_VDP_TTX_FILTER_2_MASK3 (0xB8) -#define REG_VDP_TTX_FILTER_2_MASK4 (0xB9) -#define REG_VDP_TTX_FILTER_2_MASK5 (0xBA) -#define REG_VDP_TTX_FILTER_CONTROL (0xBB) -#define REG_VDP_FIFO_WORD_COUNT (0xBC) -#define REG_VDP_FIFO_INTERRUPT_THRLD (0xBD) - -/* 0xBE Reserved */ - -#define REG_VDP_FIFO_RESET (0xBF) -#define REG_VDP_FIFO_OUTPUT_CONTROL (0xC0) -#define REG_VDP_LINE_NUMBER_INTERRUPT (0xC1) -#define REG_VDP_PIXEL_ALIGNMENT_LSB (0xC2) -#define REG_VDP_PIXEL_ALIGNMENT_MSB (0xC3) - -/* 0xC4 - 0xD5 Reserved */ - -#define REG_VDP_LINE_START (0xD6) -#define REG_VDP_LINE_STOP (0xD7) -#define REG_VDP_GLOBAL_LINE_MODE (0xD8) -#define REG_VDP_FULL_FIELD_ENABLE (0xD9) -#define REG_VDP_FULL_FIELD_MODE (0xDA) - -/* 0xDB - 0xDF Reserved */ - -#define REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR (0xE0) -#define REG_VBUS_DATA_ACCESS_VBUS_ADDR_INCR (0xE1) -#define REG_FIFO_READ_DATA (0xE2) - -/* 0xE3 - 0xE7 Reserved */ - -#define REG_VBUS_ADDRESS_ACCESS1 (0xE8) -#define REG_VBUS_ADDRESS_ACCESS2 (0xE9) -#define REG_VBUS_ADDRESS_ACCESS3 (0xEA) - -/* 0xEB - 0xEF Reserved */ - -#define REG_INTERRUPT_RAW_STATUS0 (0xF0) -#define REG_INTERRUPT_RAW_STATUS1 (0xF1) -#define REG_INTERRUPT_STATUS0 (0xF2) -#define REG_INTERRUPT_STATUS1 (0xF3) -#define REG_INTERRUPT_MASK0 (0xF4) -#define REG_INTERRUPT_MASK1 (0xF5) -#define REG_INTERRUPT_CLEAR0 (0xF6) -#define REG_INTERRUPT_CLEAR1 (0xF7) - -/* 0xF8 - 0xFF Reserved */ - -/* - * Mask and bit definitions of TVP5146/47 registers - */ -/* The ID values we are looking for */ -#define TVP514X_CHIP_ID_MSB (0x51) -#define TVP5146_CHIP_ID_LSB (0x46) -#define TVP5147_CHIP_ID_LSB (0x47) - -#define VIDEO_STD_MASK (0x07) -#define VIDEO_STD_AUTO_SWITCH_BIT (0x00) -#define VIDEO_STD_NTSC_MJ_BIT (0x01) -#define VIDEO_STD_PAL_BDGHIN_BIT (0x02) -#define VIDEO_STD_PAL_M_BIT (0x03) -#define VIDEO_STD_PAL_COMBINATION_N_BIT (0x04) -#define VIDEO_STD_NTSC_4_43_BIT (0x05) -#define VIDEO_STD_SECAM_BIT (0x06) -#define VIDEO_STD_PAL_60_BIT (0x07) - -/* - * Status bit - */ -#define STATUS_TV_VCR_BIT (1<<0) -#define STATUS_HORZ_SYNC_LOCK_BIT (1<<1) -#define STATUS_VIRT_SYNC_LOCK_BIT (1<<2) -#define STATUS_CLR_SUBCAR_LOCK_BIT (1<<3) -#define STATUS_LOST_LOCK_DETECT_BIT (1<<4) -#define STATUS_FEILD_RATE_BIT (1<<5) -#define STATUS_LINE_ALTERNATING_BIT (1<<6) -#define STATUS_PEAK_WHITE_DETECT_BIT (1<<7) - -/* Tokens for register write */ -#define TOK_WRITE (0) /* token for write operation */ -#define TOK_TERM (1) /* terminating token */ -#define TOK_DELAY (2) /* delay token for reg list */ -#define TOK_SKIP (3) /* token to skip a register */ -/** - * struct tvp514x_reg - Structure for TVP5146/47 register initialization values - * @token - Token: TOK_WRITE, TOK_TERM etc.. - * @reg - Register offset - * @val - Register Value for TOK_WRITE or delay in ms for TOK_DELAY - */ -struct tvp514x_reg { - u8 token; - u8 reg; - u32 val; -}; - -#endif /* ifndef _TVP514X_REGS_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp5150.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp5150.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp5150.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp5150.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1067 +0,0 @@ -/* - * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver - * - * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tvp5150_reg.h" - -MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); -MODULE_AUTHOR("Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL"); - - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-2)"); - -struct tvp5150 { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - - v4l2_std_id norm; /* Current set standard */ - u32 input; - u32 output; - int enable; -}; - -static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd) -{ - return container_of(sd, struct tvp5150, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct tvp5150, hdl)->sd; -} - -static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - unsigned char buffer[1]; - int rc; - - buffer[0] = addr; - if (1 != (rc = i2c_master_send(c, buffer, 1))) - v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc); - - msleep(10); - - if (1 != (rc = i2c_master_recv(c, buffer, 1))) - v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc); - - v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]); - - return (buffer[0]); -} - -static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, - unsigned char value) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - unsigned char buffer[2]; - int rc; - - buffer[0] = addr; - buffer[1] = value; - v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]); - if (2 != (rc = i2c_master_send(c, buffer, 2))) - v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 2)\n", rc); -} - -static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, - const u8 end, int max_line) -{ - int i = 0; - - while (init != (u8)(end + 1)) { - if ((i % max_line) == 0) { - if (i > 0) - printk("\n"); - printk("tvp5150: %s reg 0x%02x = ", s, init); - } - printk("%02x ", tvp5150_read(sd, init)); - - init++; - i++; - } - printk("\n"); -} - -static int tvp5150_log_status(struct v4l2_subdev *sd) -{ - printk("tvp5150: Video input source selection #1 = 0x%02x\n", - tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1)); - printk("tvp5150: Analog channel controls = 0x%02x\n", - tvp5150_read(sd, TVP5150_ANAL_CHL_CTL)); - printk("tvp5150: Operation mode controls = 0x%02x\n", - tvp5150_read(sd, TVP5150_OP_MODE_CTL)); - printk("tvp5150: Miscellaneous controls = 0x%02x\n", - tvp5150_read(sd, TVP5150_MISC_CTL)); - printk("tvp5150: Autoswitch mask= 0x%02x\n", - tvp5150_read(sd, TVP5150_AUTOSW_MSK)); - printk("tvp5150: Color killer threshold control = 0x%02x\n", - tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL)); - printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", - tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1), - tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2), - tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3)); - printk("tvp5150: Brightness control = 0x%02x\n", - tvp5150_read(sd, TVP5150_BRIGHT_CTL)); - printk("tvp5150: Color saturation control = 0x%02x\n", - tvp5150_read(sd, TVP5150_SATURATION_CTL)); - printk("tvp5150: Hue control = 0x%02x\n", - tvp5150_read(sd, TVP5150_HUE_CTL)); - printk("tvp5150: Contrast control = 0x%02x\n", - tvp5150_read(sd, TVP5150_CONTRAST_CTL)); - printk("tvp5150: Outputs and data rates select = 0x%02x\n", - tvp5150_read(sd, TVP5150_DATA_RATE_SEL)); - printk("tvp5150: Configuration shared pins = 0x%02x\n", - tvp5150_read(sd, TVP5150_CONF_SHARED_PIN)); - printk("tvp5150: Active video cropping start = 0x%02x%02x\n", - tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB), - tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB)); - printk("tvp5150: Active video cropping stop = 0x%02x%02x\n", - tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB), - tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB)); - printk("tvp5150: Genlock/RTC = 0x%02x\n", - tvp5150_read(sd, TVP5150_GENLOCK)); - printk("tvp5150: Horizontal sync start = 0x%02x\n", - tvp5150_read(sd, TVP5150_HORIZ_SYNC_START)); - printk("tvp5150: Vertical blanking start = 0x%02x\n", - tvp5150_read(sd, TVP5150_VERT_BLANKING_START)); - printk("tvp5150: Vertical blanking stop = 0x%02x\n", - tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP)); - printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", - tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1), - tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2)); - printk("tvp5150: Interrupt reset register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_RESET_REG_B)); - printk("tvp5150: Interrupt enable register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B)); - printk("tvp5150: Interrupt configuration register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B)); - printk("tvp5150: Video standard = 0x%02x\n", - tvp5150_read(sd, TVP5150_VIDEO_STD)); - printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", - tvp5150_read(sd, TVP5150_CB_GAIN_FACT), - tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR)); - printk("tvp5150: Macrovision on counter = 0x%02x\n", - tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR)); - printk("tvp5150: Macrovision off counter = 0x%02x\n", - tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR)); - printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", - (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4); - printk("tvp5150: Device ID = %02x%02x\n", - tvp5150_read(sd, TVP5150_MSB_DEV_ID), - tvp5150_read(sd, TVP5150_LSB_DEV_ID)); - printk("tvp5150: ROM version = (hex) %02x.%02x\n", - tvp5150_read(sd, TVP5150_ROM_MAJOR_VER), - tvp5150_read(sd, TVP5150_ROM_MINOR_VER)); - printk("tvp5150: Vertical line count = 0x%02x%02x\n", - tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB), - tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB)); - printk("tvp5150: Interrupt status register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_STATUS_REG_B)); - printk("tvp5150: Interrupt active register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B)); - printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", - tvp5150_read(sd, TVP5150_STATUS_REG_1), - tvp5150_read(sd, TVP5150_STATUS_REG_2), - tvp5150_read(sd, TVP5150_STATUS_REG_3), - tvp5150_read(sd, TVP5150_STATUS_REG_4), - tvp5150_read(sd, TVP5150_STATUS_REG_5)); - - dump_reg_range(sd, "Teletext filter 1", TVP5150_TELETEXT_FIL1_INI, - TVP5150_TELETEXT_FIL1_END, 8); - dump_reg_range(sd, "Teletext filter 2", TVP5150_TELETEXT_FIL2_INI, - TVP5150_TELETEXT_FIL2_END, 8); - - printk("tvp5150: Teletext filter enable = 0x%02x\n", - tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA)); - printk("tvp5150: Interrupt status register A = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_STATUS_REG_A)); - printk("tvp5150: Interrupt enable register A = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A)); - printk("tvp5150: Interrupt configuration = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_CONF)); - printk("tvp5150: VDP status register = 0x%02x\n", - tvp5150_read(sd, TVP5150_VDP_STATUS_REG)); - printk("tvp5150: FIFO word count = 0x%02x\n", - tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT)); - printk("tvp5150: FIFO interrupt threshold = 0x%02x\n", - tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD)); - printk("tvp5150: FIFO reset = 0x%02x\n", - tvp5150_read(sd, TVP5150_FIFO_RESET)); - printk("tvp5150: Line number interrupt = 0x%02x\n", - tvp5150_read(sd, TVP5150_LINE_NUMBER_INT)); - printk("tvp5150: Pixel alignment register = 0x%02x%02x\n", - tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH), - tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW)); - printk("tvp5150: FIFO output control = 0x%02x\n", - tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL)); - printk("tvp5150: Full field enable = 0x%02x\n", - tvp5150_read(sd, TVP5150_FULL_FIELD_ENA)); - printk("tvp5150: Full field mode register = 0x%02x\n", - tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG)); - - dump_reg_range(sd, "CC data", TVP5150_CC_DATA_INI, - TVP5150_CC_DATA_END, 8); - - dump_reg_range(sd, "WSS data", TVP5150_WSS_DATA_INI, - TVP5150_WSS_DATA_END, 8); - - dump_reg_range(sd, "VPS data", TVP5150_VPS_DATA_INI, - TVP5150_VPS_DATA_END, 8); - - dump_reg_range(sd, "VITC data", TVP5150_VITC_DATA_INI, - TVP5150_VITC_DATA_END, 10); - - dump_reg_range(sd, "Line mode", TVP5150_LINE_MODE_INI, - TVP5150_LINE_MODE_END, 8); - return 0; -} - -/**************************************************************************** - Basic functions - ****************************************************************************/ - -static inline void tvp5150_selmux(struct v4l2_subdev *sd) -{ - int opmode = 0; - struct tvp5150 *decoder = to_tvp5150(sd); - int input = 0; - unsigned char val; - - if ((decoder->output & TVP5150_BLACK_SCREEN) || !decoder->enable) - input = 8; - - switch (decoder->input) { - case TVP5150_COMPOSITE1: - input |= 2; - /* fall through */ - case TVP5150_COMPOSITE0: - break; - case TVP5150_SVIDEO: - default: - input |= 1; - break; - } - - v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i " - "=> tvp5150 input=%i, opmode=%i\n", - decoder->input, decoder->output, - input, opmode); - - tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode); - tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input); - - /* Svideo should enable YCrCb output and disable GPCL output - * For Composite and TV, it should be the reverse - */ - val = tvp5150_read(sd, TVP5150_MISC_CTL); - if (decoder->input == TVP5150_SVIDEO) - val = (val & ~0x40) | 0x10; - else - val = (val & ~0x10) | 0x40; - tvp5150_write(sd, TVP5150_MISC_CTL, val); -}; - -struct i2c_reg_value { - unsigned char reg; - unsigned char value; -}; - -/* Default values as sugested at TVP5150AM1 datasheet */ -static const struct i2c_reg_value tvp5150_init_default[] = { - { /* 0x00 */ - TVP5150_VD_IN_SRC_SEL_1,0x00 - }, - { /* 0x01 */ - TVP5150_ANAL_CHL_CTL,0x15 - }, - { /* 0x02 */ - TVP5150_OP_MODE_CTL,0x00 - }, - { /* 0x03 */ - TVP5150_MISC_CTL,0x01 - }, - { /* 0x06 */ - TVP5150_COLOR_KIL_THSH_CTL,0x10 - }, - { /* 0x07 */ - TVP5150_LUMA_PROC_CTL_1,0x60 - }, - { /* 0x08 */ - TVP5150_LUMA_PROC_CTL_2,0x00 - }, - { /* 0x09 */ - TVP5150_BRIGHT_CTL,0x80 - }, - { /* 0x0a */ - TVP5150_SATURATION_CTL,0x80 - }, - { /* 0x0b */ - TVP5150_HUE_CTL,0x00 - }, - { /* 0x0c */ - TVP5150_CONTRAST_CTL,0x80 - }, - { /* 0x0d */ - TVP5150_DATA_RATE_SEL,0x47 - }, - { /* 0x0e */ - TVP5150_LUMA_PROC_CTL_3,0x00 - }, - { /* 0x0f */ - TVP5150_CONF_SHARED_PIN,0x08 - }, - { /* 0x11 */ - TVP5150_ACT_VD_CROP_ST_MSB,0x00 - }, - { /* 0x12 */ - TVP5150_ACT_VD_CROP_ST_LSB,0x00 - }, - { /* 0x13 */ - TVP5150_ACT_VD_CROP_STP_MSB,0x00 - }, - { /* 0x14 */ - TVP5150_ACT_VD_CROP_STP_LSB,0x00 - }, - { /* 0x15 */ - TVP5150_GENLOCK,0x01 - }, - { /* 0x16 */ - TVP5150_HORIZ_SYNC_START,0x80 - }, - { /* 0x18 */ - TVP5150_VERT_BLANKING_START,0x00 - }, - { /* 0x19 */ - TVP5150_VERT_BLANKING_STOP,0x00 - }, - { /* 0x1a */ - TVP5150_CHROMA_PROC_CTL_1,0x0c - }, - { /* 0x1b */ - TVP5150_CHROMA_PROC_CTL_2,0x14 - }, - { /* 0x1c */ - TVP5150_INT_RESET_REG_B,0x00 - }, - { /* 0x1d */ - TVP5150_INT_ENABLE_REG_B,0x00 - }, - { /* 0x1e */ - TVP5150_INTT_CONFIG_REG_B,0x00 - }, - { /* 0x28 */ - TVP5150_VIDEO_STD,0x00 - }, - { /* 0x2e */ - TVP5150_MACROVISION_ON_CTR,0x0f - }, - { /* 0x2f */ - TVP5150_MACROVISION_OFF_CTR,0x01 - }, - { /* 0xbb */ - TVP5150_TELETEXT_FIL_ENA,0x00 - }, - { /* 0xc0 */ - TVP5150_INT_STATUS_REG_A,0x00 - }, - { /* 0xc1 */ - TVP5150_INT_ENABLE_REG_A,0x00 - }, - { /* 0xc2 */ - TVP5150_INT_CONF,0x04 - }, - { /* 0xc8 */ - TVP5150_FIFO_INT_THRESHOLD,0x80 - }, - { /* 0xc9 */ - TVP5150_FIFO_RESET,0x00 - }, - { /* 0xca */ - TVP5150_LINE_NUMBER_INT,0x00 - }, - { /* 0xcb */ - TVP5150_PIX_ALIGN_REG_LOW,0x4e - }, - { /* 0xcc */ - TVP5150_PIX_ALIGN_REG_HIGH,0x00 - }, - { /* 0xcd */ - TVP5150_FIFO_OUT_CTRL,0x01 - }, - { /* 0xcf */ - TVP5150_FULL_FIELD_ENA,0x00 - }, - { /* 0xd0 */ - TVP5150_LINE_MODE_INI,0x00 - }, - { /* 0xfc */ - TVP5150_FULL_FIELD_MODE_REG,0x7f - }, - { /* end of data */ - 0xff,0xff - } -}; - -/* Default values as sugested at TVP5150AM1 datasheet */ -static const struct i2c_reg_value tvp5150_init_enable[] = { - { - TVP5150_CONF_SHARED_PIN, 2 - },{ /* Automatic offset and AGC enabled */ - TVP5150_ANAL_CHL_CTL, 0x15 - },{ /* Activate YCrCb output 0x9 or 0xd ? */ - TVP5150_MISC_CTL, 0x6f - },{ /* Activates video std autodetection for all standards */ - TVP5150_AUTOSW_MSK, 0x0 - },{ /* Default format: 0x47. For 4:2:2: 0x40 */ - TVP5150_DATA_RATE_SEL, 0x47 - },{ - TVP5150_CHROMA_PROC_CTL_1, 0x0c - },{ - TVP5150_CHROMA_PROC_CTL_2, 0x54 - },{ /* Non documented, but initialized on WinTV USB2 */ - 0x27, 0x20 - },{ - 0xff,0xff - } -}; - -struct tvp5150_vbi_type { - unsigned int vbi_type; - unsigned int ini_line; - unsigned int end_line; - unsigned int by_field :1; -}; - -struct i2c_vbi_ram_value { - u16 reg; - struct tvp5150_vbi_type type; - unsigned char values[16]; -}; - -/* This struct have the values for each supported VBI Standard - * by - tvp5150_vbi_types should follow the same order as vbi_ram_default - * value 0 means rom position 0x10, value 1 means rom position 0x30 - * and so on. There are 16 possible locations from 0 to 15. - */ - -static struct i2c_vbi_ram_value vbi_ram_default[] = -{ - /* FIXME: Current api doesn't handle all VBI types, those not - yet supported are placed under #if 0 */ -#if 0 - {0x010, /* Teletext, SECAM, WST System A */ - {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, - { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, - 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } - }, -#endif - {0x030, /* Teletext, PAL, WST System B */ - {V4L2_SLICED_TELETEXT_B,6,22,1}, - { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, - 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } - }, -#if 0 - {0x050, /* Teletext, PAL, WST System C */ - {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, - { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, - 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } - }, - {0x070, /* Teletext, NTSC, WST System B */ - {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1}, - { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, - 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } - }, - {0x090, /* Tetetext, NTSC NABTS System C */ - {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1}, - { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, - 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } - }, - {0x0b0, /* Teletext, NTSC-J, NABTS System D */ - {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1}, - { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, - 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } - }, - {0x0d0, /* Closed Caption, PAL/SECAM */ - {V4L2_SLICED_CAPTION_625,22,22,1}, - { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, - 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } - }, -#endif - {0x0f0, /* Closed Caption, NTSC */ - {V4L2_SLICED_CAPTION_525,21,21,1}, - { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, - 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } - }, - {0x110, /* Wide Screen Signal, PAL/SECAM */ - {V4L2_SLICED_WSS_625,23,23,1}, - { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, - 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } - }, -#if 0 - {0x130, /* Wide Screen Signal, NTSC C */ - {V4L2_SLICED_WSS_525,20,20,1}, - { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, - 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } - }, - {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ - {V4l2_SLICED_VITC_625,6,22,0}, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, - 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } - }, - {0x170, /* Vertical Interval Timecode (VITC), NTSC */ - {V4l2_SLICED_VITC_525,10,20,0}, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, - 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } - }, -#endif - {0x190, /* Video Program System (VPS), PAL */ - {V4L2_SLICED_VPS,16,16,0}, - { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, - 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } - }, - /* 0x1d0 User programmable */ - - /* End of struct */ - { (u16)-1 } -}; - -static int tvp5150_write_inittab(struct v4l2_subdev *sd, - const struct i2c_reg_value *regs) -{ - while (regs->reg != 0xff) { - tvp5150_write(sd, regs->reg, regs->value); - regs++; - } - return 0; -} - -static int tvp5150_vdp_init(struct v4l2_subdev *sd, - const struct i2c_vbi_ram_value *regs) -{ - unsigned int i; - - /* Disable Full Field */ - tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); - - /* Before programming, Line mode should be at 0xff */ - for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) - tvp5150_write(sd, i, 0xff); - - /* Load Ram Table */ - while (regs->reg != (u16)-1) { - tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); - tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); - - for (i = 0; i < 16; i++) - tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]); - - regs++; - } - return 0; -} - -/* Fills VBI capabilities based on i2c_vbi_ram_value struct */ -static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, - struct v4l2_sliced_vbi_cap *cap) -{ - const struct i2c_vbi_ram_value *regs = vbi_ram_default; - int line; - - v4l2_dbg(1, debug, sd, "g_sliced_vbi_cap\n"); - memset(cap, 0, sizeof *cap); - - while (regs->reg != (u16)-1 ) { - for (line=regs->type.ini_line;line<=regs->type.end_line;line++) { - cap->service_lines[0][line] |= regs->type.vbi_type; - } - cap->service_set |= regs->type.vbi_type; - - regs++; - } - return 0; -} - -/* Set vbi processing - * type - one of tvp5150_vbi_types - * line - line to gather data - * fields: bit 0 field1, bit 1, field2 - * flags (default=0xf0) is a bitmask, were set means: - * bit 7: enable filtering null bytes on CC - * bit 6: send data also to FIFO - * bit 5: don't allow data with errors on FIFO - * bit 4: enable ECC when possible - * pix_align = pix alignment: - * LSB = field1 - * MSB = field2 - */ -static int tvp5150_set_vbi(struct v4l2_subdev *sd, - const struct i2c_vbi_ram_value *regs, - unsigned int type,u8 flags, int line, - const int fields) -{ - struct tvp5150 *decoder = to_tvp5150(sd); - v4l2_std_id std = decoder->norm; - u8 reg; - int pos=0; - - if (std == V4L2_STD_ALL) { - v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); - return 0; - } else if (std & V4L2_STD_625_50) { - /* Don't follow NTSC Line number convension */ - line += 3; - } - - if (line<6||line>27) - return 0; - - while (regs->reg != (u16)-1 ) { - if ((type & regs->type.vbi_type) && - (line>=regs->type.ini_line) && - (line<=regs->type.end_line)) { - type=regs->type.vbi_type; - break; - } - - regs++; - pos++; - } - if (regs->reg == (u16)-1) - return 0; - - type=pos | (flags & 0xf0); - reg=((line-6)<<1)+TVP5150_LINE_MODE_INI; - - if (fields&1) { - tvp5150_write(sd, reg, type); - } - - if (fields&2) { - tvp5150_write(sd, reg+1, type); - } - - return type; -} - -static int tvp5150_get_vbi(struct v4l2_subdev *sd, - const struct i2c_vbi_ram_value *regs, int line) -{ - struct tvp5150 *decoder = to_tvp5150(sd); - v4l2_std_id std = decoder->norm; - u8 reg; - int pos, type = 0; - - if (std == V4L2_STD_ALL) { - v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); - return 0; - } else if (std & V4L2_STD_625_50) { - /* Don't follow NTSC Line number convension */ - line += 3; - } - - if (line < 6 || line > 27) - return 0; - - reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; - - pos = tvp5150_read(sd, reg) & 0x0f; - if (pos < 0x0f) - type = regs[pos].type.vbi_type; - - pos = tvp5150_read(sd, reg + 1) & 0x0f; - if (pos < 0x0f) - type |= regs[pos].type.vbi_type; - - return type; -} - -static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct tvp5150 *decoder = to_tvp5150(sd); - int fmt = 0; - - decoder->norm = std; - - /* First tests should be against specific std */ - - if (std == V4L2_STD_ALL) { - fmt = 0; /* Autodetect mode */ - } else if (std & V4L2_STD_NTSC_443) { - fmt = 0xa; - } else if (std & V4L2_STD_PAL_M) { - fmt = 0x6; - } else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) { - fmt = 0x8; - } else { - /* Then, test against generic ones */ - if (std & V4L2_STD_NTSC) - fmt = 0x2; - else if (std & V4L2_STD_PAL) - fmt = 0x4; - else if (std & V4L2_STD_SECAM) - fmt = 0xc; - } - - v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt); - tvp5150_write(sd, TVP5150_VIDEO_STD, fmt); - return 0; -} - -static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct tvp5150 *decoder = to_tvp5150(sd); - - if (decoder->norm == std) - return 0; - - return tvp5150_set_std(sd, std); -} - -static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) -{ - struct tvp5150 *decoder = to_tvp5150(sd); - - /* Initializes TVP5150 to its default values */ - tvp5150_write_inittab(sd, tvp5150_init_default); - - /* Initializes VDP registers */ - tvp5150_vdp_init(sd, vbi_ram_default); - - /* Selects decoder input */ - tvp5150_selmux(sd); - - /* Initializes TVP5150 to stream enabled values */ - tvp5150_write_inittab(sd, tvp5150_init_enable); - - /* Initialize image preferences */ - v4l2_ctrl_handler_setup(&decoder->hdl); - - tvp5150_set_std(sd, decoder->norm); - return 0; -}; - -static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val); - return 0; - case V4L2_CID_CONTRAST: - tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val); - return 0; - case V4L2_CID_SATURATION: - tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val); - return 0; - case V4L2_CID_HUE: - tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val); - return 0; - } - return -EINVAL; -} - -/**************************************************************************** - I2C Command - ****************************************************************************/ - -static int tvp5150_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct tvp5150 *decoder = to_tvp5150(sd); - - decoder->input = input; - decoder->output = output; - tvp5150_selmux(sd); - return 0; -} - -static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) -{ - /* this is for capturing 36 raw vbi lines - if there's a way to cut off the beginning 2 vbi lines - with the tvp5150 then the vbi line count could be lowered - to 17 lines/field again, although I couldn't find a register - which could do that cropping */ - if (fmt->sample_format == V4L2_PIX_FMT_GREY) - tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70); - if (fmt->count[0] == 18 && fmt->count[1] == 18) { - tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00); - tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01); - } - return 0; -} - -static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) -{ - int i; - - if (svbi->service_set != 0) { - for (i = 0; i <= 23; i++) { - svbi->service_lines[1][i] = 0; - svbi->service_lines[0][i] = - tvp5150_set_vbi(sd, vbi_ram_default, - svbi->service_lines[0][i], 0xf0, i, 3); - } - /* Enables FIFO */ - tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1); - } else { - /* Disables FIFO*/ - tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0); - - /* Disable Full Field */ - tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); - - /* Disable Line modes */ - for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) - tvp5150_write(sd, i, 0xff); - } - return 0; -} - -static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) -{ - int i, mask = 0; - - memset(svbi, 0, sizeof(*svbi)); - - for (i = 0; i <= 23; i++) { - svbi->service_lines[0][i] = - tvp5150_get_vbi(sd, vbi_ram_default, i); - mask |= svbi->service_lines[0][i]; - } - svbi->service_set = mask; - return 0; -} - -static int tvp5150_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - int rev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - - rev = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER) << 8 | - tvp5150_read(sd, TVP5150_ROM_MINOR_VER); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP5150, - rev); -} - - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->val = tvp5150_read(sd, reg->reg & 0xff); - reg->size = 1; - return 0; -} - -static int tvp5150_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff); - return 0; -} -#endif - -static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - int status = tvp5150_read(sd, 0x88); - - vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0; - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { - .s_ctrl = tvp5150_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops tvp5150_core_ops = { - .log_status = tvp5150_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = tvp5150_s_std, - .reset = tvp5150_reset, - .g_chip_ident = tvp5150_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = tvp5150_g_register, - .s_register = tvp5150_s_register, -#endif -}; - -static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { - .g_tuner = tvp5150_g_tuner, -}; - -static const struct v4l2_subdev_video_ops tvp5150_video_ops = { - .s_routing = tvp5150_s_routing, -}; - -static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { - .g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap, - .g_sliced_fmt = tvp5150_g_sliced_fmt, - .s_sliced_fmt = tvp5150_s_sliced_fmt, - .s_raw_fmt = tvp5150_s_raw_fmt, -}; - -static const struct v4l2_subdev_ops tvp5150_ops = { - .core = &tvp5150_core_ops, - .tuner = &tvp5150_tuner_ops, - .video = &tvp5150_video_ops, - .vbi = &tvp5150_vbi_ops, -}; - - -/**************************************************************************** - I2C Client & Driver - ****************************************************************************/ - -static int tvp5150_probe(struct i2c_client *c, - const struct i2c_device_id *id) -{ - struct tvp5150 *core; - struct v4l2_subdev *sd; - u8 msb_id, lsb_id, msb_rom, lsb_rom; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(c->adapter, - I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - return -EIO; - - core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL); - if (!core) { - return -ENOMEM; - } - sd = &core->sd; - v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); - v4l_info(c, "chip found @ 0x%02x (%s)\n", - c->addr << 1, c->adapter->name); - - msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID); - lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID); - msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER); - lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER); - - if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */ - v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id); - - /* ITU-T BT.656.4 timing */ - tvp5150_write(sd, TVP5150_REV_SELECT, 0); - } else { - if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */ - v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id); - } else { - v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n", - msb_id, lsb_id); - v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom); - } - } - - core->norm = V4L2_STD_ALL; /* Default is autodetect */ - core->input = TVP5150_COMPOSITE1; - core->enable = 1; - - v4l2_ctrl_handler_init(&core->hdl, 4); - v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 128); - v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 128); - v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - sd->ctrl_handler = &core->hdl; - if (core->hdl.error) { - int err = core->hdl.error; - - v4l2_ctrl_handler_free(&core->hdl); - kfree(core); - return err; - } - v4l2_ctrl_handler_setup(&core->hdl); - - if (debug > 1) - tvp5150_log_status(sd); - return 0; -} - -static int tvp5150_remove(struct i2c_client *c) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(c); - struct tvp5150 *decoder = to_tvp5150(sd); - - v4l2_dbg(1, debug, sd, - "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", - c->addr << 1); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&decoder->hdl); - kfree(to_tvp5150(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id tvp5150_id[] = { - { "tvp5150", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tvp5150_id); - -static struct i2c_driver tvp5150_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tvp5150", - }, - .probe = tvp5150_probe, - .remove = tvp5150_remove, - .id_table = tvp5150_id, -}; - -static __init int init_tvp5150(void) -{ - return i2c_add_driver(&tvp5150_driver); -} - -static __exit void exit_tvp5150(void) -{ - i2c_del_driver(&tvp5150_driver); -} - -module_init(init_tvp5150); -module_exit(exit_tvp5150); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp5150_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp5150_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp5150_reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp5150_reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -/* - * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder registers - * - * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 - */ - -#define TVP5150_VD_IN_SRC_SEL_1 0x00 /* Video input source selection #1 */ -#define TVP5150_ANAL_CHL_CTL 0x01 /* Analog channel controls */ -#define TVP5150_OP_MODE_CTL 0x02 /* Operation mode controls */ -#define TVP5150_MISC_CTL 0x03 /* Miscellaneous controls */ -#define TVP5150_AUTOSW_MSK 0x04 /* Autoswitch mask: TVP5150A / TVP5150AM */ - -/* Reserved 05h */ - -#define TVP5150_COLOR_KIL_THSH_CTL 0x06 /* Color killer threshold control */ -#define TVP5150_LUMA_PROC_CTL_1 0x07 /* Luminance processing control #1 */ -#define TVP5150_LUMA_PROC_CTL_2 0x08 /* Luminance processing control #2 */ -#define TVP5150_BRIGHT_CTL 0x09 /* Brightness control */ -#define TVP5150_SATURATION_CTL 0x0a /* Color saturation control */ -#define TVP5150_HUE_CTL 0x0b /* Hue control */ -#define TVP5150_CONTRAST_CTL 0x0c /* Contrast control */ -#define TVP5150_DATA_RATE_SEL 0x0d /* Outputs and data rates select */ -#define TVP5150_LUMA_PROC_CTL_3 0x0e /* Luminance processing control #3 */ -#define TVP5150_CONF_SHARED_PIN 0x0f /* Configuration shared pins */ - -/* Reserved 10h */ - -#define TVP5150_ACT_VD_CROP_ST_MSB 0x11 /* Active video cropping start MSB */ -#define TVP5150_ACT_VD_CROP_ST_LSB 0x12 /* Active video cropping start LSB */ -#define TVP5150_ACT_VD_CROP_STP_MSB 0x13 /* Active video cropping stop MSB */ -#define TVP5150_ACT_VD_CROP_STP_LSB 0x14 /* Active video cropping stop LSB */ -#define TVP5150_GENLOCK 0x15 /* Genlock/RTC */ -#define TVP5150_HORIZ_SYNC_START 0x16 /* Horizontal sync start */ - -/* Reserved 17h */ - -#define TVP5150_VERT_BLANKING_START 0x18 /* Vertical blanking start */ -#define TVP5150_VERT_BLANKING_STOP 0x19 /* Vertical blanking stop */ -#define TVP5150_CHROMA_PROC_CTL_1 0x1a /* Chrominance processing control #1 */ -#define TVP5150_CHROMA_PROC_CTL_2 0x1b /* Chrominance processing control #2 */ -#define TVP5150_INT_RESET_REG_B 0x1c /* Interrupt reset register B */ -#define TVP5150_INT_ENABLE_REG_B 0x1d /* Interrupt enable register B */ -#define TVP5150_INTT_CONFIG_REG_B 0x1e /* Interrupt configuration register B */ - -/* Reserved 1Fh-27h */ - -#define TVP5150_VIDEO_STD 0x28 /* Video standard */ - -/* Reserved 29h-2bh */ - -#define TVP5150_CB_GAIN_FACT 0x2c /* Cb gain factor */ -#define TVP5150_CR_GAIN_FACTOR 0x2d /* Cr gain factor */ -#define TVP5150_MACROVISION_ON_CTR 0x2e /* Macrovision on counter */ -#define TVP5150_MACROVISION_OFF_CTR 0x2f /* Macrovision off counter */ -#define TVP5150_REV_SELECT 0x30 /* revision select (TVP5150AM1 only) */ - -/* Reserved 31h-7Fh */ - -#define TVP5150_MSB_DEV_ID 0x80 /* MSB of device ID */ -#define TVP5150_LSB_DEV_ID 0x81 /* LSB of device ID */ -#define TVP5150_ROM_MAJOR_VER 0x82 /* ROM major version */ -#define TVP5150_ROM_MINOR_VER 0x83 /* ROM minor version */ -#define TVP5150_VERT_LN_COUNT_MSB 0x84 /* Vertical line count MSB */ -#define TVP5150_VERT_LN_COUNT_LSB 0x85 /* Vertical line count LSB */ -#define TVP5150_INT_STATUS_REG_B 0x86 /* Interrupt status register B */ -#define TVP5150_INT_ACTIVE_REG_B 0x87 /* Interrupt active register B */ -#define TVP5150_STATUS_REG_1 0x88 /* Status register #1 */ -#define TVP5150_STATUS_REG_2 0x89 /* Status register #2 */ -#define TVP5150_STATUS_REG_3 0x8a /* Status register #3 */ -#define TVP5150_STATUS_REG_4 0x8b /* Status register #4 */ -#define TVP5150_STATUS_REG_5 0x8c /* Status register #5 */ -/* Reserved 8Dh-8Fh */ - /* Closed caption data registers */ -#define TVP5150_CC_DATA_INI 0x90 -#define TVP5150_CC_DATA_END 0x93 - - /* WSS data registers */ -#define TVP5150_WSS_DATA_INI 0x94 -#define TVP5150_WSS_DATA_END 0x99 - -/* VPS data registers */ -#define TVP5150_VPS_DATA_INI 0x9a -#define TVP5150_VPS_DATA_END 0xa6 - -/* VITC data registers */ -#define TVP5150_VITC_DATA_INI 0xa7 -#define TVP5150_VITC_DATA_END 0xaf - -#define TVP5150_VBI_FIFO_READ_DATA 0xb0 /* VBI FIFO read data */ - -/* Teletext filter 1 */ -#define TVP5150_TELETEXT_FIL1_INI 0xb1 -#define TVP5150_TELETEXT_FIL1_END 0xb5 - -/* Teletext filter 2 */ -#define TVP5150_TELETEXT_FIL2_INI 0xb6 -#define TVP5150_TELETEXT_FIL2_END 0xba - -#define TVP5150_TELETEXT_FIL_ENA 0xbb /* Teletext filter enable */ -/* Reserved BCh-BFh */ -#define TVP5150_INT_STATUS_REG_A 0xc0 /* Interrupt status register A */ -#define TVP5150_INT_ENABLE_REG_A 0xc1 /* Interrupt enable register A */ -#define TVP5150_INT_CONF 0xc2 /* Interrupt configuration */ -#define TVP5150_VDP_CONF_RAM_DATA 0xc3 /* VDP configuration RAM data */ -#define TVP5150_CONF_RAM_ADDR_LOW 0xc4 /* Configuration RAM address low byte */ -#define TVP5150_CONF_RAM_ADDR_HIGH 0xc5 /* Configuration RAM address high byte */ -#define TVP5150_VDP_STATUS_REG 0xc6 /* VDP status register */ -#define TVP5150_FIFO_WORD_COUNT 0xc7 /* FIFO word count */ -#define TVP5150_FIFO_INT_THRESHOLD 0xc8 /* FIFO interrupt threshold */ -#define TVP5150_FIFO_RESET 0xc9 /* FIFO reset */ -#define TVP5150_LINE_NUMBER_INT 0xca /* Line number interrupt */ -#define TVP5150_PIX_ALIGN_REG_LOW 0xcb /* Pixel alignment register low byte */ -#define TVP5150_PIX_ALIGN_REG_HIGH 0xcc /* Pixel alignment register high byte */ -#define TVP5150_FIFO_OUT_CTRL 0xcd /* FIFO output control */ -/* Reserved CEh */ -#define TVP5150_FULL_FIELD_ENA 0xcf /* Full field enable 1 */ - -/* Line mode registers */ -#define TVP5150_LINE_MODE_INI 0xd0 -#define TVP5150_LINE_MODE_END 0xfb - -#define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */ -/* Reserved FDh-FFh */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp7002.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp7002.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp7002.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp7002.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1100 +0,0 @@ -/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics - * Digitizer with Horizontal PLL registers - * - * Copyright (C) 2009 Texas Instruments Inc - * Author: Santiago Nunez-Corrales - * - * This code is partially based upon the TVP5150 driver - * written by Mauro Carvalho Chehab (mchehab@infradead.org), - * the TVP514x driver written by Vaibhav Hiremath - * and the TVP7002 driver in the TI LSP 2.10.00.14. Revisions by - * Muralidharan Karicheri and Snehaprabha Narnakaje (TI). - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tvp7002_reg.h" - -MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver"); -MODULE_AUTHOR("Santiago Nunez-Corrales "); -MODULE_LICENSE("GPL"); - -/* Module Name */ -#define TVP7002_MODULE_NAME "tvp7002" - -/* I2C retry attempts */ -#define I2C_RETRY_COUNT (5) - -/* End of registers */ -#define TVP7002_EOR 0x5c - -/* Read write definition for registers */ -#define TVP7002_READ 0 -#define TVP7002_WRITE 1 -#define TVP7002_RESERVED 2 - -/* Interlaced vs progressive mask and shift */ -#define TVP7002_IP_SHIFT 5 -#define TVP7002_INPR_MASK (0x01 << TVP7002_IP_SHIFT) - -/* Shift for CPL and LPF registers */ -#define TVP7002_CL_SHIFT 8 -#define TVP7002_CL_MASK 0x0f - -/* Debug functions */ -static int debug; -module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-2)"); - -/* Structure for register values */ -struct i2c_reg_value { - u8 reg; - u8 value; - u8 type; -}; - -/* - * Register default values (according to tvp7002 datasheet) - * In the case of read-only registers, the value (0xff) is - * never written. R/W functionality is controlled by the - * writable bit in the register struct definition. - */ -static const struct i2c_reg_value tvp7002_init_default[] = { - { TVP7002_CHIP_REV, 0xff, TVP7002_READ }, - { TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE }, - { TVP7002_HPLL_FDBK_DIV_LSBS, 0x20, TVP7002_WRITE }, - { TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x80, TVP7002_WRITE }, - { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE }, - { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE }, - { TVP7002_HSYNC_OUT_W, 0x60, TVP7002_WRITE }, - { TVP7002_B_FINE_GAIN, 0x00, TVP7002_WRITE }, - { TVP7002_G_FINE_GAIN, 0x00, TVP7002_WRITE }, - { TVP7002_R_FINE_GAIN, 0x00, TVP7002_WRITE }, - { TVP7002_B_FINE_OFF_MSBS, 0x80, TVP7002_WRITE }, - { TVP7002_G_FINE_OFF_MSBS, 0x80, TVP7002_WRITE }, - { TVP7002_R_FINE_OFF_MSBS, 0x80, TVP7002_WRITE }, - { TVP7002_SYNC_CTL_1, 0x20, TVP7002_WRITE }, - { TVP7002_HPLL_AND_CLAMP_CTL, 0x2e, TVP7002_WRITE }, - { TVP7002_SYNC_ON_G_THRS, 0x5d, TVP7002_WRITE }, - { TVP7002_SYNC_SEPARATOR_THRS, 0x47, TVP7002_WRITE }, - { TVP7002_HPLL_PRE_COAST, 0x00, TVP7002_WRITE }, - { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE }, - { TVP7002_SYNC_DETECT_STAT, 0xff, TVP7002_READ }, - { TVP7002_OUT_FORMATTER, 0x47, TVP7002_WRITE }, - { TVP7002_MISC_CTL_1, 0x01, TVP7002_WRITE }, - { TVP7002_MISC_CTL_2, 0x00, TVP7002_WRITE }, - { TVP7002_MISC_CTL_3, 0x01, TVP7002_WRITE }, - { TVP7002_IN_MUX_SEL_1, 0x00, TVP7002_WRITE }, - { TVP7002_IN_MUX_SEL_2, 0x67, TVP7002_WRITE }, - { TVP7002_B_AND_G_COARSE_GAIN, 0x77, TVP7002_WRITE }, - { TVP7002_R_COARSE_GAIN, 0x07, TVP7002_WRITE }, - { TVP7002_FINE_OFF_LSBS, 0x00, TVP7002_WRITE }, - { TVP7002_B_COARSE_OFF, 0x10, TVP7002_WRITE }, - { TVP7002_G_COARSE_OFF, 0x10, TVP7002_WRITE }, - { TVP7002_R_COARSE_OFF, 0x10, TVP7002_WRITE }, - { TVP7002_HSOUT_OUT_START, 0x08, TVP7002_WRITE }, - { TVP7002_MISC_CTL_4, 0x00, TVP7002_WRITE }, - { TVP7002_B_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ }, - { TVP7002_G_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ }, - { TVP7002_R_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ }, - { TVP7002_AUTO_LVL_CTL_ENABLE, 0x80, TVP7002_WRITE }, - { TVP7002_DGTL_ALC_OUT_MSBS, 0xff, TVP7002_READ }, - { TVP7002_AUTO_LVL_CTL_FILTER, 0x53, TVP7002_WRITE }, - { 0x29, 0x08, TVP7002_RESERVED }, - { TVP7002_FINE_CLAMP_CTL, 0x07, TVP7002_WRITE }, - /* PWR_CTL is controlled only by the probe and reset functions */ - { TVP7002_PWR_CTL, 0x00, TVP7002_RESERVED }, - { TVP7002_ADC_SETUP, 0x50, TVP7002_WRITE }, - { TVP7002_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE }, - { TVP7002_SOG_CLAMP, 0x80, TVP7002_WRITE }, - { TVP7002_RGB_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE }, - { TVP7002_SOG_COARSE_CLAMP_CTL, 0x04, TVP7002_WRITE }, - { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE }, - { 0x32, 0x18, TVP7002_RESERVED }, - { 0x33, 0x60, TVP7002_RESERVED }, - { TVP7002_MVIS_STRIPPER_W, 0xff, TVP7002_RESERVED }, - { TVP7002_VSYNC_ALGN, 0x10, TVP7002_WRITE }, - { TVP7002_SYNC_BYPASS, 0x00, TVP7002_WRITE }, - { TVP7002_L_FRAME_STAT_LSBS, 0xff, TVP7002_READ }, - { TVP7002_L_FRAME_STAT_MSBS, 0xff, TVP7002_READ }, - { TVP7002_CLK_L_STAT_LSBS, 0xff, TVP7002_READ }, - { TVP7002_CLK_L_STAT_MSBS, 0xff, TVP7002_READ }, - { TVP7002_HSYNC_W, 0xff, TVP7002_READ }, - { TVP7002_VSYNC_W, 0xff, TVP7002_READ }, - { TVP7002_L_LENGTH_TOL, 0x03, TVP7002_WRITE }, - { 0x3e, 0x60, TVP7002_RESERVED }, - { TVP7002_VIDEO_BWTH_CTL, 0x01, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_LSBS, 0x01, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_MSBS, 0x2c, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_LSBS, 0x06, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_MSBS, 0x2c, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_START_L_OFF, 0x05, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_DURATION, 0x1e, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE }, - { TVP7002_FBIT_F_0_START_L_OFF, 0x00, TVP7002_WRITE }, - { TVP7002_FBIT_F_1_START_L_OFF, 0x00, TVP7002_WRITE }, - { TVP7002_YUV_Y_G_COEF_LSBS, 0xe3, TVP7002_WRITE }, - { TVP7002_YUV_Y_G_COEF_MSBS, 0x16, TVP7002_WRITE }, - { TVP7002_YUV_Y_B_COEF_LSBS, 0x4f, TVP7002_WRITE }, - { TVP7002_YUV_Y_B_COEF_MSBS, 0x02, TVP7002_WRITE }, - { TVP7002_YUV_Y_R_COEF_LSBS, 0xce, TVP7002_WRITE }, - { TVP7002_YUV_Y_R_COEF_MSBS, 0x06, TVP7002_WRITE }, - { TVP7002_YUV_U_G_COEF_LSBS, 0xab, TVP7002_WRITE }, - { TVP7002_YUV_U_G_COEF_MSBS, 0xf3, TVP7002_WRITE }, - { TVP7002_YUV_U_B_COEF_LSBS, 0x00, TVP7002_WRITE }, - { TVP7002_YUV_U_B_COEF_MSBS, 0x10, TVP7002_WRITE }, - { TVP7002_YUV_U_R_COEF_LSBS, 0x55, TVP7002_WRITE }, - { TVP7002_YUV_U_R_COEF_MSBS, 0xfc, TVP7002_WRITE }, - { TVP7002_YUV_V_G_COEF_LSBS, 0x78, TVP7002_WRITE }, - { TVP7002_YUV_V_G_COEF_MSBS, 0xf1, TVP7002_WRITE }, - { TVP7002_YUV_V_B_COEF_LSBS, 0x88, TVP7002_WRITE }, - { TVP7002_YUV_V_B_COEF_MSBS, 0xfe, TVP7002_WRITE }, - { TVP7002_YUV_V_R_COEF_LSBS, 0x00, TVP7002_WRITE }, - { TVP7002_YUV_V_R_COEF_MSBS, 0x10, TVP7002_WRITE }, - /* This signals end of register values */ - { TVP7002_EOR, 0xff, TVP7002_RESERVED } -}; - -/* Register parameters for 480P */ -static const struct i2c_reg_value tvp7002_parms_480P[] = { - { TVP7002_HPLL_FDBK_DIV_MSBS, 0x35, TVP7002_WRITE }, - { TVP7002_HPLL_FDBK_DIV_LSBS, 0xa0, TVP7002_WRITE }, - { TVP7002_HPLL_CRTL, 0x02, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_LSBS, 0x91, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_LSBS, 0x0B, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_MSBS, 0x00, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_START_L_OFF, 0x03, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_START_L_OFF, 0x01, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_DURATION, 0x13, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_DURATION, 0x13, TVP7002_WRITE }, - { TVP7002_ALC_PLACEMENT, 0x18, TVP7002_WRITE }, - { TVP7002_CLAMP_START, 0x06, TVP7002_WRITE }, - { TVP7002_CLAMP_W, 0x10, TVP7002_WRITE }, - { TVP7002_HPLL_PRE_COAST, 0x03, TVP7002_WRITE }, - { TVP7002_HPLL_POST_COAST, 0x03, TVP7002_WRITE }, - { TVP7002_EOR, 0xff, TVP7002_RESERVED } -}; - -/* Register parameters for 576P */ -static const struct i2c_reg_value tvp7002_parms_576P[] = { - { TVP7002_HPLL_FDBK_DIV_MSBS, 0x36, TVP7002_WRITE }, - { TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE }, - { TVP7002_HPLL_CRTL, 0x18, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_LSBS, 0x9B, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_LSBS, 0x0F, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_MSBS, 0x00, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_START_L_OFF, 0x00, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_DURATION, 0x2D, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE }, - { TVP7002_ALC_PLACEMENT, 0x18, TVP7002_WRITE }, - { TVP7002_CLAMP_START, 0x06, TVP7002_WRITE }, - { TVP7002_CLAMP_W, 0x10, TVP7002_WRITE }, - { TVP7002_HPLL_PRE_COAST, 0x03, TVP7002_WRITE }, - { TVP7002_HPLL_POST_COAST, 0x03, TVP7002_WRITE }, - { TVP7002_EOR, 0xff, TVP7002_RESERVED } -}; - -/* Register parameters for 1080I60 */ -static const struct i2c_reg_value tvp7002_parms_1080I60[] = { - { TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE }, - { TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE }, - { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_MSBS, 0x08, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_START_L_OFF, 0x02, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_START_L_OFF, 0x02, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_DURATION, 0x16, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_DURATION, 0x17, TVP7002_WRITE }, - { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE }, - { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE }, - { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE }, - { TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE }, - { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE }, - { TVP7002_EOR, 0xff, TVP7002_RESERVED } -}; - -/* Register parameters for 1080P60 */ -static const struct i2c_reg_value tvp7002_parms_1080P60[] = { - { TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE }, - { TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE }, - { TVP7002_HPLL_CRTL, 0xE0, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_MSBS, 0x08, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_START_L_OFF, 0x02, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_START_L_OFF, 0x02, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_DURATION, 0x16, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_DURATION, 0x17, TVP7002_WRITE }, - { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE }, - { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE }, - { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE }, - { TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE }, - { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE }, - { TVP7002_EOR, 0xff, TVP7002_RESERVED } -}; - -/* Register parameters for 1080I50 */ -static const struct i2c_reg_value tvp7002_parms_1080I50[] = { - { TVP7002_HPLL_FDBK_DIV_MSBS, 0xa5, TVP7002_WRITE }, - { TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE }, - { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_MSBS, 0x08, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_START_L_OFF, 0x02, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_START_L_OFF, 0x02, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_DURATION, 0x16, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_DURATION, 0x17, TVP7002_WRITE }, - { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE }, - { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE }, - { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE }, - { TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE }, - { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE }, - { TVP7002_EOR, 0xff, TVP7002_RESERVED } -}; - -/* Register parameters for 720P60 */ -static const struct i2c_reg_value tvp7002_parms_720P60[] = { - { TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE }, - { TVP7002_HPLL_FDBK_DIV_LSBS, 0x20, TVP7002_WRITE }, - { TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_MSBS, 0x06, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_START_L_OFF, 0x05, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_DURATION, 0x2D, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE }, - { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE }, - { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE }, - { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE }, - { TVP7002_HPLL_PRE_COAST, 0x00, TVP7002_WRITE }, - { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE }, - { TVP7002_EOR, 0xff, TVP7002_RESERVED } -}; - -/* Register parameters for 720P50 */ -static const struct i2c_reg_value tvp7002_parms_720P50[] = { - { TVP7002_HPLL_FDBK_DIV_MSBS, 0x7b, TVP7002_WRITE }, - { TVP7002_HPLL_FDBK_DIV_LSBS, 0xc0, TVP7002_WRITE }, - { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE }, - { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE }, - { TVP7002_AVID_STOP_PIXEL_MSBS, 0x06, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_START_L_OFF, 0x05, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_START_L_OFF, 0x00, TVP7002_WRITE }, - { TVP7002_VBLK_F_0_DURATION, 0x2D, TVP7002_WRITE }, - { TVP7002_VBLK_F_1_DURATION, 0x00, TVP7002_WRITE }, - { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE }, - { TVP7002_CLAMP_START, 0x32, TVP7002_WRITE }, - { TVP7002_CLAMP_W, 0x20, TVP7002_WRITE }, - { TVP7002_HPLL_PRE_COAST, 0x01, TVP7002_WRITE }, - { TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE }, - { TVP7002_EOR, 0xff, TVP7002_RESERVED } -}; - -/* Preset definition for handling device operation */ -struct tvp7002_preset_definition { - u32 preset; - const struct i2c_reg_value *p_settings; - enum v4l2_colorspace color_space; - enum v4l2_field scanmode; - u16 progressive; - u16 lines_per_frame; - u16 cpl_min; - u16 cpl_max; -}; - -/* Struct list for digital video presets */ -static const struct tvp7002_preset_definition tvp7002_presets[] = { - { - V4L2_DV_720P60, - tvp7002_parms_720P60, - V4L2_COLORSPACE_REC709, - V4L2_FIELD_NONE, - 1, - 0x2EE, - 135, - 153 - }, - { - V4L2_DV_1080I60, - tvp7002_parms_1080I60, - V4L2_COLORSPACE_REC709, - V4L2_FIELD_INTERLACED, - 0, - 0x465, - 181, - 205 - }, - { - V4L2_DV_1080I50, - tvp7002_parms_1080I50, - V4L2_COLORSPACE_REC709, - V4L2_FIELD_INTERLACED, - 0, - 0x465, - 217, - 245 - }, - { - V4L2_DV_720P50, - tvp7002_parms_720P50, - V4L2_COLORSPACE_REC709, - V4L2_FIELD_NONE, - 1, - 0x2EE, - 163, - 183 - }, - { - V4L2_DV_1080P60, - tvp7002_parms_1080P60, - V4L2_COLORSPACE_REC709, - V4L2_FIELD_NONE, - 1, - 0x465, - 90, - 102 - }, - { - V4L2_DV_480P59_94, - tvp7002_parms_480P, - V4L2_COLORSPACE_SMPTE170M, - V4L2_FIELD_NONE, - 1, - 0x20D, - 0xffff, - 0xffff - }, - { - V4L2_DV_576P50, - tvp7002_parms_576P, - V4L2_COLORSPACE_SMPTE170M, - V4L2_FIELD_NONE, - 1, - 0x271, - 0xffff, - 0xffff - } -}; - -#define NUM_PRESETS ARRAY_SIZE(tvp7002_presets) - -/* Device definition */ -struct tvp7002 { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - const struct tvp7002_config *pdata; - - int ver; - int streaming; - - const struct tvp7002_preset_definition *current_preset; -}; - -/* - * to_tvp7002 - Obtain device handler TVP7002 - * @sd: ptr to v4l2_subdev struct - * - * Returns device handler tvp7002. - */ -static inline struct tvp7002 *to_tvp7002(struct v4l2_subdev *sd) -{ - return container_of(sd, struct tvp7002, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct tvp7002, hdl)->sd; -} - -/* - * tvp7002_read - Read a value from a register in an TVP7002 - * @sd: ptr to v4l2_subdev struct - * @addr: TVP7002 register address - * @dst: pointer to 8-bit destination - * - * Returns value read if successful, or non-zero (-1) otherwise. - */ -static int tvp7002_read(struct v4l2_subdev *sd, u8 addr, u8 *dst) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - int retry; - int error; - - for (retry = 0; retry < I2C_RETRY_COUNT; retry++) { - error = i2c_smbus_read_byte_data(c, addr); - - if (error >= 0) { - *dst = (u8)error; - return 0; - } - - msleep_interruptible(10); - } - v4l2_err(sd, "TVP7002 read error %d\n", error); - return error; -} - -/* - * tvp7002_read_err() - Read a register value with error code - * @sd: pointer to standard V4L2 sub-device structure - * @reg: destination register - * @val: value to be read - * @err: pointer to error value - * - * Read a value in a register and save error value in pointer. - * Also update the register table if successful - */ -static inline void tvp7002_read_err(struct v4l2_subdev *sd, u8 reg, - u8 *dst, int *err) -{ - if (!*err) - *err = tvp7002_read(sd, reg, dst); -} - -/* - * tvp7002_write() - Write a value to a register in TVP7002 - * @sd: ptr to v4l2_subdev struct - * @addr: TVP7002 register address - * @value: value to be written to the register - * - * Write a value to a register in an TVP7002 decoder device. - * Returns zero if successful, or non-zero otherwise. - */ -static int tvp7002_write(struct v4l2_subdev *sd, u8 addr, u8 value) -{ - struct i2c_client *c; - int retry; - int error; - - c = v4l2_get_subdevdata(sd); - - for (retry = 0; retry < I2C_RETRY_COUNT; retry++) { - error = i2c_smbus_write_byte_data(c, addr, value); - - if (error >= 0) - return 0; - - v4l2_warn(sd, "Write: retry ... %d\n", retry); - msleep_interruptible(10); - } - v4l2_err(sd, "TVP7002 write error %d\n", error); - return error; -} - -/* - * tvp7002_write_err() - Write a register value with error code - * @sd: pointer to standard V4L2 sub-device structure - * @reg: destination register - * @val: value to be written - * @err: pointer to error value - * - * Write a value in a register and save error value in pointer. - * Also update the register table if successful - */ -static inline void tvp7002_write_err(struct v4l2_subdev *sd, u8 reg, - u8 val, int *err) -{ - if (!*err) - *err = tvp7002_write(sd, reg, val); -} - -/* - * tvp7002_g_chip_ident() - Get chip identification number - * @sd: ptr to v4l2_subdev struct - * @chip: ptr to v4l2_dbg_chip_ident struct - * - * Obtains the chip's identification number. - * Returns zero or -EINVAL if read operation fails. - */ -static int tvp7002_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - u8 rev; - int error; - struct i2c_client *client = v4l2_get_subdevdata(sd); - - error = tvp7002_read(sd, TVP7002_CHIP_REV, &rev); - - if (error < 0) - return error; - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP7002, rev); -} - -/* - * tvp7002_write_inittab() - Write initialization values - * @sd: ptr to v4l2_subdev struct - * @regs: ptr to i2c_reg_value struct - * - * Write initialization values. - * Returns zero or -EINVAL if read operation fails. - */ -static int tvp7002_write_inittab(struct v4l2_subdev *sd, - const struct i2c_reg_value *regs) -{ - int error = 0; - - /* Initialize the first (defined) registers */ - while (TVP7002_EOR != regs->reg) { - if (TVP7002_WRITE == regs->type) - tvp7002_write_err(sd, regs->reg, regs->value, &error); - regs++; - } - - return error; -} - -/* - * tvp7002_s_dv_preset() - Set digital video preset - * @sd: ptr to v4l2_subdev struct - * @dv_preset: ptr to v4l2_dv_preset struct - * - * Set the digital video preset for a TVP7002 decoder device. - * Returns zero when successful or -EINVAL if register access fails. - */ -static int tvp7002_s_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *dv_preset) -{ - struct tvp7002 *device = to_tvp7002(sd); - u32 preset; - int i; - - for (i = 0; i < NUM_PRESETS; i++) { - preset = tvp7002_presets[i].preset; - if (preset == dv_preset->preset) { - device->current_preset = &tvp7002_presets[i]; - return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings); - } - } - - return -EINVAL; -} - -/* - * tvp7002_s_ctrl() - Set a control - * @ctrl: ptr to v4l2_ctrl struct - * - * Set a control in TVP7002 decoder device. - * Returns zero when successful or -EINVAL if register access fails. - */ -static int tvp7002_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - int error = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - tvp7002_write_err(sd, TVP7002_R_FINE_GAIN, ctrl->val, &error); - tvp7002_write_err(sd, TVP7002_G_FINE_GAIN, ctrl->val, &error); - tvp7002_write_err(sd, TVP7002_B_FINE_GAIN, ctrl->val, &error); - return error; - } - return -EINVAL; -} - -/* - * tvp7002_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to mediabus format structure - * - * Negotiate the image capture size and mediabus format. - * There is only one possible format, so this single function works for - * get, set and try. - */ -static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct tvp7002 *device = to_tvp7002(sd); - struct v4l2_dv_enum_preset e_preset; - int error; - - /* Calculate height and width based on current standard */ - error = v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset); - if (error) - return error; - - f->width = e_preset.width; - f->height = e_preset.height; - f->code = V4L2_MBUS_FMT_YUYV10_1X20; - f->field = device->current_preset->scanmode; - f->colorspace = device->current_preset->color_space; - - v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d", - f->width, f->height); - return 0; -} - -/* - * tvp7002_query_dv_preset() - query DV preset - * @sd: pointer to standard V4L2 sub-device structure - * @qpreset: standard V4L2 v4l2_dv_preset structure - * - * Returns the current DV preset by TVP7002. If no active input is - * detected, returns -EINVAL - */ -static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *qpreset) -{ - const struct tvp7002_preset_definition *presets = tvp7002_presets; - struct tvp7002 *device; - u8 progressive; - u32 lpfr; - u32 cpln; - int error = 0; - u8 lpf_lsb; - u8 lpf_msb; - u8 cpl_lsb; - u8 cpl_msb; - int index; - - device = to_tvp7002(sd); - - /* Read standards from device registers */ - tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_LSBS, &lpf_lsb, &error); - tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_MSBS, &lpf_msb, &error); - - if (error < 0) - return error; - - tvp7002_read_err(sd, TVP7002_CLK_L_STAT_LSBS, &cpl_lsb, &error); - tvp7002_read_err(sd, TVP7002_CLK_L_STAT_MSBS, &cpl_msb, &error); - - if (error < 0) - return error; - - /* Get lines per frame, clocks per line and interlaced/progresive */ - lpfr = lpf_lsb | ((TVP7002_CL_MASK & lpf_msb) << TVP7002_CL_SHIFT); - cpln = cpl_lsb | ((TVP7002_CL_MASK & cpl_msb) << TVP7002_CL_SHIFT); - progressive = (lpf_msb & TVP7002_INPR_MASK) >> TVP7002_IP_SHIFT; - - /* Do checking of video modes */ - for (index = 0; index < NUM_PRESETS; index++, presets++) - if (lpfr == presets->lines_per_frame && - progressive == presets->progressive) { - if (presets->cpl_min == 0xffff) - break; - if (cpln >= presets->cpl_min && cpln <= presets->cpl_max) - break; - } - - if (index == NUM_PRESETS) { - v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n", - lpfr, cpln); - /* Could not detect a signal, so return the 'invalid' preset */ - qpreset->preset = V4L2_DV_INVALID; - return 0; - } - - /* Set values in found preset */ - qpreset->preset = presets->preset; - - /* Update lines per frame and clocks per line info */ - v4l2_dbg(1, debug, sd, "detected preset: %d\n", presets->preset); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -/* - * tvp7002_g_register() - Get the value of a register - * @sd: ptr to v4l2_subdev struct - * @reg: ptr to v4l2_dbg_register struct - * - * Get the value of a TVP7002 decoder device register. - * Returns zero when successful, -EINVAL if register read fails or - * access to I2C client fails, -EPERM if the call is not allowed - * by disabled CAP_SYS_ADMIN. - */ -static int tvp7002_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 val; - int ret; - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = tvp7002_read(sd, reg->reg & 0xff, &val); - reg->val = val; - return ret; -} - -/* - * tvp7002_s_register() - set a control - * @sd: ptr to v4l2_subdev struct - * @reg: ptr to v4l2_dbg_register struct - * - * Get the value of a TVP7002 decoder device register. - * Returns zero when successful, -EINVAL if register read fails or - * -EPERM if call not allowed. - */ -static int tvp7002_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - return tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff); -} -#endif - -/* - * tvp7002_enum_mbus_fmt() - Enum supported mediabus formats - * @sd: pointer to standard V4L2 sub-device structure - * @index: format index - * @code: pointer to mediabus format - * - * Enumerate supported mediabus formats. - */ - -static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - enum v4l2_mbus_pixelcode *code) -{ - /* Check requested format index is within range */ - if (index) - return -EINVAL; - *code = V4L2_MBUS_FMT_YUYV10_1X20; - return 0; -} - -/* - * tvp7002_s_stream() - V4L2 decoder i/f handler for s_stream - * @sd: pointer to standard V4L2 sub-device structure - * @enable: streaming enable or disable - * - * Sets streaming to enable or disable, if possible. - */ -static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct tvp7002 *device = to_tvp7002(sd); - int error = 0; - - if (device->streaming == enable) - return 0; - - if (enable) { - /* Set output state on (low impedance means stream on) */ - error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); - device->streaming = enable; - } else { - /* Set output state off (high impedance means stream off) */ - error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x03); - if (error) - v4l2_dbg(1, debug, sd, "Unable to stop streaming\n"); - - device->streaming = enable; - } - - return error; -} - -/* - * tvp7002_log_status() - Print information about register settings - * @sd: ptr to v4l2_subdev struct - * - * Log register values of a TVP7002 decoder device. - * Returns zero or -EINVAL if read operation fails. - */ -static int tvp7002_log_status(struct v4l2_subdev *sd) -{ - const struct tvp7002_preset_definition *presets = tvp7002_presets; - struct tvp7002 *device = to_tvp7002(sd); - struct v4l2_dv_enum_preset e_preset; - struct v4l2_dv_preset detected; - int i; - - detected.preset = V4L2_DV_INVALID; - /* Find my current standard*/ - tvp7002_query_dv_preset(sd, &detected); - - /* Print standard related code values */ - for (i = 0; i < NUM_PRESETS; i++, presets++) - if (presets->preset == detected.preset) - break; - - if (v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset)) - return -EINVAL; - - v4l2_info(sd, "Selected DV Preset: %s\n", e_preset.name); - v4l2_info(sd, " Pixels per line: %u\n", e_preset.width); - v4l2_info(sd, " Lines per frame: %u\n\n", e_preset.height); - if (i == NUM_PRESETS) { - v4l2_info(sd, "Detected DV Preset: None\n"); - } else { - if (v4l_fill_dv_preset_info(presets->preset, &e_preset)) - return -EINVAL; - v4l2_info(sd, "Detected DV Preset: %s\n", e_preset.name); - v4l2_info(sd, " Pixels per line: %u\n", e_preset.width); - v4l2_info(sd, " Lines per frame: %u\n\n", e_preset.height); - } - v4l2_info(sd, "Streaming enabled: %s\n", - device->streaming ? "yes" : "no"); - - /* Print the current value of the gain control */ - v4l2_ctrl_handler_log_status(&device->hdl, sd->name); - - return 0; -} - -/* - * tvp7002_enum_dv_presets() - Enum supported digital video formats - * @sd: pointer to standard V4L2 sub-device structure - * @preset: pointer to format struct - * - * Enumerate supported digital video formats. - */ -static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd, - struct v4l2_dv_enum_preset *preset) -{ - /* Check requested format index is within range */ - if (preset->index >= NUM_PRESETS) - return -EINVAL; - - return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset); -} - -static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = { - .s_ctrl = tvp7002_s_ctrl, -}; - -/* V4L2 core operation handlers */ -static const struct v4l2_subdev_core_ops tvp7002_core_ops = { - .g_chip_ident = tvp7002_g_chip_ident, - .log_status = tvp7002_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = tvp7002_g_register, - .s_register = tvp7002_s_register, -#endif -}; - -/* Specific video subsystem operation handlers */ -static const struct v4l2_subdev_video_ops tvp7002_video_ops = { - .enum_dv_presets = tvp7002_enum_dv_presets, - .s_dv_preset = tvp7002_s_dv_preset, - .query_dv_preset = tvp7002_query_dv_preset, - .s_stream = tvp7002_s_stream, - .g_mbus_fmt = tvp7002_mbus_fmt, - .try_mbus_fmt = tvp7002_mbus_fmt, - .s_mbus_fmt = tvp7002_mbus_fmt, - .enum_mbus_fmt = tvp7002_enum_mbus_fmt, -}; - -/* V4L2 top level operation handlers */ -static const struct v4l2_subdev_ops tvp7002_ops = { - .core = &tvp7002_core_ops, - .video = &tvp7002_video_ops, -}; - -/* - * tvp7002_probe - Probe a TVP7002 device - * @c: ptr to i2c_client struct - * @id: ptr to i2c_device_id struct - * - * Initialize the TVP7002 device - * Returns zero when successful, -EINVAL if register read fails or - * -EIO if i2c access is not available. - */ -static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) -{ - struct v4l2_subdev *sd; - struct tvp7002 *device; - struct v4l2_dv_preset preset; - int polarity_a; - int polarity_b; - u8 revision; - - int error; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(c->adapter, - I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - return -EIO; - - if (!c->dev.platform_data) { - v4l_err(c, "No platform data!!\n"); - return -ENODEV; - } - - device = kzalloc(sizeof(struct tvp7002), GFP_KERNEL); - - if (!device) - return -ENOMEM; - - sd = &device->sd; - device->pdata = c->dev.platform_data; - device->current_preset = tvp7002_presets; - - /* Tell v4l2 the device is ready */ - v4l2_i2c_subdev_init(sd, c, &tvp7002_ops); - v4l_info(c, "tvp7002 found @ 0x%02x (%s)\n", - c->addr, c->adapter->name); - - error = tvp7002_read(sd, TVP7002_CHIP_REV, &revision); - if (error < 0) - goto found_error; - - /* Get revision number */ - v4l2_info(sd, "Rev. %02x detected.\n", revision); - if (revision != 0x02) - v4l2_info(sd, "Unknown revision detected.\n"); - - /* Initializes TVP7002 to its default values */ - error = tvp7002_write_inittab(sd, tvp7002_init_default); - - if (error < 0) - goto found_error; - - /* Set polarity information after registers have been set */ - polarity_a = 0x20 | device->pdata->hs_polarity << 5 - | device->pdata->vs_polarity << 2; - error = tvp7002_write(sd, TVP7002_SYNC_CTL_1, polarity_a); - if (error < 0) - goto found_error; - - polarity_b = 0x01 | device->pdata->fid_polarity << 2 - | device->pdata->sog_polarity << 1 - | device->pdata->clk_polarity; - error = tvp7002_write(sd, TVP7002_MISC_CTL_3, polarity_b); - if (error < 0) - goto found_error; - - /* Set registers according to default video mode */ - preset.preset = device->current_preset->preset; - error = tvp7002_s_dv_preset(sd, &preset); - - v4l2_ctrl_handler_init(&device->hdl, 1); - v4l2_ctrl_new_std(&device->hdl, &tvp7002_ctrl_ops, - V4L2_CID_GAIN, 0, 255, 1, 0); - sd->ctrl_handler = &device->hdl; - if (device->hdl.error) { - int err = device->hdl.error; - - v4l2_ctrl_handler_free(&device->hdl); - kfree(device); - return err; - } - v4l2_ctrl_handler_setup(&device->hdl); - -found_error: - if (error < 0) - kfree(device); - - return error; -} - -/* - * tvp7002_remove - Remove TVP7002 device support - * @c: ptr to i2c_client struct - * - * Reset the TVP7002 device - * Returns zero. - */ -static int tvp7002_remove(struct i2c_client *c) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(c); - struct tvp7002 *device = to_tvp7002(sd); - - v4l2_dbg(1, debug, sd, "Removing tvp7002 adapter" - "on address 0x%x\n", c->addr); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&device->hdl); - kfree(device); - return 0; -} - -/* I2C Device ID table */ -static const struct i2c_device_id tvp7002_id[] = { - { "tvp7002", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tvp7002_id); - -/* I2C driver data */ -static struct i2c_driver tvp7002_driver = { - .driver = { - .owner = THIS_MODULE, - .name = TVP7002_MODULE_NAME, - }, - .probe = tvp7002_probe, - .remove = tvp7002_remove, - .id_table = tvp7002_id, -}; - -/* - * tvp7002_init - Initialize driver via I2C interface - * - * Register the TVP7002 driver. - * Return 0 on success or error code on failure. - */ -static int __init tvp7002_init(void) -{ - return i2c_add_driver(&tvp7002_driver); -} - -/* - * tvp7002_exit - Remove driver via I2C interface - * - * Unregister the TVP7002 driver. - * Returns nothing. - */ -static void __exit tvp7002_exit(void) -{ - i2c_del_driver(&tvp7002_driver); -} - -module_init(tvp7002_init); -module_exit(tvp7002_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp7002_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp7002_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp7002_reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tvp7002_reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics - * Digitizer with Horizontal PLL registers - * - * Copyright (C) 2009 Texas Instruments Inc - * Author: Santiago Nunez-Corrales - * - * This code is partially based upon the TVP5150 driver - * written by Mauro Carvalho Chehab (mchehab@infradead.org), - * the TVP514x driver written by Vaibhav Hiremath - * and the TVP7002 driver in the TI LSP 2.10.00.14 - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Naming conventions - * ------------------ - * - * FDBK: Feedback - * DIV: Divider - * CTL: Control - * SEL: Select - * IN: Input - * OUT: Output - * R: Red - * G: Green - * B: Blue - * OFF: Offset - * THRS: Threshold - * DGTL: Digital - * LVL: Level - * PWR: Power - * MVIS: Macrovision - * W: Width - * H: Height - * ALGN: Alignment - * CLK: Clocks - * TOL: Tolerance - * BWTH: Bandwidth - * COEF: Coefficient - * STAT: Status - * AUTO: Automatic - * FLD: Field - * L: Line - */ - -#define TVP7002_CHIP_REV 0x00 -#define TVP7002_HPLL_FDBK_DIV_MSBS 0x01 -#define TVP7002_HPLL_FDBK_DIV_LSBS 0x02 -#define TVP7002_HPLL_CRTL 0x03 -#define TVP7002_HPLL_PHASE_SEL 0x04 -#define TVP7002_CLAMP_START 0x05 -#define TVP7002_CLAMP_W 0x06 -#define TVP7002_HSYNC_OUT_W 0x07 -#define TVP7002_B_FINE_GAIN 0x08 -#define TVP7002_G_FINE_GAIN 0x09 -#define TVP7002_R_FINE_GAIN 0x0a -#define TVP7002_B_FINE_OFF_MSBS 0x0b -#define TVP7002_G_FINE_OFF_MSBS 0x0c -#define TVP7002_R_FINE_OFF_MSBS 0x0d -#define TVP7002_SYNC_CTL_1 0x0e -#define TVP7002_HPLL_AND_CLAMP_CTL 0x0f -#define TVP7002_SYNC_ON_G_THRS 0x10 -#define TVP7002_SYNC_SEPARATOR_THRS 0x11 -#define TVP7002_HPLL_PRE_COAST 0x12 -#define TVP7002_HPLL_POST_COAST 0x13 -#define TVP7002_SYNC_DETECT_STAT 0x14 -#define TVP7002_OUT_FORMATTER 0x15 -#define TVP7002_MISC_CTL_1 0x16 -#define TVP7002_MISC_CTL_2 0x17 -#define TVP7002_MISC_CTL_3 0x18 -#define TVP7002_IN_MUX_SEL_1 0x19 -#define TVP7002_IN_MUX_SEL_2 0x1a -#define TVP7002_B_AND_G_COARSE_GAIN 0x1b -#define TVP7002_R_COARSE_GAIN 0x1c -#define TVP7002_FINE_OFF_LSBS 0x1d -#define TVP7002_B_COARSE_OFF 0x1e -#define TVP7002_G_COARSE_OFF 0x1f -#define TVP7002_R_COARSE_OFF 0x20 -#define TVP7002_HSOUT_OUT_START 0x21 -#define TVP7002_MISC_CTL_4 0x22 -#define TVP7002_B_DGTL_ALC_OUT_LSBS 0x23 -#define TVP7002_G_DGTL_ALC_OUT_LSBS 0x24 -#define TVP7002_R_DGTL_ALC_OUT_LSBS 0x25 -#define TVP7002_AUTO_LVL_CTL_ENABLE 0x26 -#define TVP7002_DGTL_ALC_OUT_MSBS 0x27 -#define TVP7002_AUTO_LVL_CTL_FILTER 0x28 -/* Reserved 0x29*/ -#define TVP7002_FINE_CLAMP_CTL 0x2a -#define TVP7002_PWR_CTL 0x2b -#define TVP7002_ADC_SETUP 0x2c -#define TVP7002_COARSE_CLAMP_CTL 0x2d -#define TVP7002_SOG_CLAMP 0x2e -#define TVP7002_RGB_COARSE_CLAMP_CTL 0x2f -#define TVP7002_SOG_COARSE_CLAMP_CTL 0x30 -#define TVP7002_ALC_PLACEMENT 0x31 -/* Reserved 0x32 */ -/* Reserved 0x33 */ -#define TVP7002_MVIS_STRIPPER_W 0x34 -#define TVP7002_VSYNC_ALGN 0x35 -#define TVP7002_SYNC_BYPASS 0x36 -#define TVP7002_L_FRAME_STAT_LSBS 0x37 -#define TVP7002_L_FRAME_STAT_MSBS 0x38 -#define TVP7002_CLK_L_STAT_LSBS 0x39 -#define TVP7002_CLK_L_STAT_MSBS 0x3a -#define TVP7002_HSYNC_W 0x3b -#define TVP7002_VSYNC_W 0x3c -#define TVP7002_L_LENGTH_TOL 0x3d -/* Reserved 0x3e */ -#define TVP7002_VIDEO_BWTH_CTL 0x3f -#define TVP7002_AVID_START_PIXEL_LSBS 0x40 -#define TVP7002_AVID_START_PIXEL_MSBS 0x41 -#define TVP7002_AVID_STOP_PIXEL_LSBS 0x42 -#define TVP7002_AVID_STOP_PIXEL_MSBS 0x43 -#define TVP7002_VBLK_F_0_START_L_OFF 0x44 -#define TVP7002_VBLK_F_1_START_L_OFF 0x45 -#define TVP7002_VBLK_F_0_DURATION 0x46 -#define TVP7002_VBLK_F_1_DURATION 0x47 -#define TVP7002_FBIT_F_0_START_L_OFF 0x48 -#define TVP7002_FBIT_F_1_START_L_OFF 0x49 -#define TVP7002_YUV_Y_G_COEF_LSBS 0x4a -#define TVP7002_YUV_Y_G_COEF_MSBS 0x4b -#define TVP7002_YUV_Y_B_COEF_LSBS 0x4c -#define TVP7002_YUV_Y_B_COEF_MSBS 0x4d -#define TVP7002_YUV_Y_R_COEF_LSBS 0x4e -#define TVP7002_YUV_Y_R_COEF_MSBS 0x4f -#define TVP7002_YUV_U_G_COEF_LSBS 0x50 -#define TVP7002_YUV_U_G_COEF_MSBS 0x51 -#define TVP7002_YUV_U_B_COEF_LSBS 0x52 -#define TVP7002_YUV_U_B_COEF_MSBS 0x53 -#define TVP7002_YUV_U_R_COEF_LSBS 0x54 -#define TVP7002_YUV_U_R_COEF_MSBS 0x55 -#define TVP7002_YUV_V_G_COEF_LSBS 0x56 -#define TVP7002_YUV_V_G_COEF_MSBS 0x57 -#define TVP7002_YUV_V_B_COEF_LSBS 0x58 -#define TVP7002_YUV_V_B_COEF_MSBS 0x59 -#define TVP7002_YUV_V_R_COEF_LSBS 0x5a -#define TVP7002_YUV_V_R_COEF_MSBS 0x5b - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tw9910.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tw9910.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tw9910.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/tw9910.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1029 +0,0 @@ -/* - * tw9910 Video Driver - * - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto - * - * Based on ov772x driver, - * - * Copyright (C) 2008 Kuninori Morimoto - * Copyright 2006-7 Jonathan Corbet - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define GET_ID(val) ((val & 0xF8) >> 3) -#define GET_REV(val) (val & 0x07) - -/* - * register offset - */ -#define ID 0x00 /* Product ID Code Register */ -#define STATUS1 0x01 /* Chip Status Register I */ -#define INFORM 0x02 /* Input Format */ -#define OPFORM 0x03 /* Output Format Control Register */ -#define DLYCTR 0x04 /* Hysteresis and HSYNC Delay Control */ -#define OUTCTR1 0x05 /* Output Control I */ -#define ACNTL1 0x06 /* Analog Control Register 1 */ -#define CROP_HI 0x07 /* Cropping Register, High */ -#define VDELAY_LO 0x08 /* Vertical Delay Register, Low */ -#define VACTIVE_LO 0x09 /* Vertical Active Register, Low */ -#define HDELAY_LO 0x0A /* Horizontal Delay Register, Low */ -#define HACTIVE_LO 0x0B /* Horizontal Active Register, Low */ -#define CNTRL1 0x0C /* Control Register I */ -#define VSCALE_LO 0x0D /* Vertical Scaling Register, Low */ -#define SCALE_HI 0x0E /* Scaling Register, High */ -#define HSCALE_LO 0x0F /* Horizontal Scaling Register, Low */ -#define BRIGHT 0x10 /* BRIGHTNESS Control Register */ -#define CONTRAST 0x11 /* CONTRAST Control Register */ -#define SHARPNESS 0x12 /* SHARPNESS Control Register I */ -#define SAT_U 0x13 /* Chroma (U) Gain Register */ -#define SAT_V 0x14 /* Chroma (V) Gain Register */ -#define HUE 0x15 /* Hue Control Register */ -#define CORING1 0x17 -#define CORING2 0x18 /* Coring and IF compensation */ -#define VBICNTL 0x19 /* VBI Control Register */ -#define ACNTL2 0x1A /* Analog Control 2 */ -#define OUTCTR2 0x1B /* Output Control 2 */ -#define SDT 0x1C /* Standard Selection */ -#define SDTR 0x1D /* Standard Recognition */ -#define TEST 0x1F /* Test Control Register */ -#define CLMPG 0x20 /* Clamping Gain */ -#define IAGC 0x21 /* Individual AGC Gain */ -#define AGCGAIN 0x22 /* AGC Gain */ -#define PEAKWT 0x23 /* White Peak Threshold */ -#define CLMPL 0x24 /* Clamp level */ -#define SYNCT 0x25 /* Sync Amplitude */ -#define MISSCNT 0x26 /* Sync Miss Count Register */ -#define PCLAMP 0x27 /* Clamp Position Register */ -#define VCNTL1 0x28 /* Vertical Control I */ -#define VCNTL2 0x29 /* Vertical Control II */ -#define CKILL 0x2A /* Color Killer Level Control */ -#define COMB 0x2B /* Comb Filter Control */ -#define LDLY 0x2C /* Luma Delay and H Filter Control */ -#define MISC1 0x2D /* Miscellaneous Control I */ -#define LOOP 0x2E /* LOOP Control Register */ -#define MISC2 0x2F /* Miscellaneous Control II */ -#define MVSN 0x30 /* Macrovision Detection */ -#define STATUS2 0x31 /* Chip STATUS II */ -#define HFREF 0x32 /* H monitor */ -#define CLMD 0x33 /* CLAMP MODE */ -#define IDCNTL 0x34 /* ID Detection Control */ -#define CLCNTL1 0x35 /* Clamp Control I */ -#define ANAPLLCTL 0x4C -#define VBIMIN 0x4D -#define HSLOWCTL 0x4E -#define WSS3 0x4F -#define FILLDATA 0x50 -#define SDID 0x51 -#define DID 0x52 -#define WSS1 0x53 -#define WSS2 0x54 -#define VVBI 0x55 -#define LCTL6 0x56 -#define LCTL7 0x57 -#define LCTL8 0x58 -#define LCTL9 0x59 -#define LCTL10 0x5A -#define LCTL11 0x5B -#define LCTL12 0x5C -#define LCTL13 0x5D -#define LCTL14 0x5E -#define LCTL15 0x5F -#define LCTL16 0x60 -#define LCTL17 0x61 -#define LCTL18 0x62 -#define LCTL19 0x63 -#define LCTL20 0x64 -#define LCTL21 0x65 -#define LCTL22 0x66 -#define LCTL23 0x67 -#define LCTL24 0x68 -#define LCTL25 0x69 -#define LCTL26 0x6A -#define HSBEGIN 0x6B -#define HSEND 0x6C -#define OVSDLY 0x6D -#define OVSEND 0x6E -#define VBIDELAY 0x6F - -/* - * register detail - */ - -/* INFORM */ -#define FC27_ON 0x40 /* 1 : Input crystal clock frequency is 27MHz */ -#define FC27_FF 0x00 /* 0 : Square pixel mode. */ - /* Must use 24.54MHz for 60Hz field rate */ - /* source or 29.5MHz for 50Hz field rate */ -#define IFSEL_S 0x10 /* 01 : S-video decoding */ -#define IFSEL_C 0x00 /* 00 : Composite video decoding */ - /* Y input video selection */ -#define YSEL_M0 0x00 /* 00 : Mux0 selected */ -#define YSEL_M1 0x04 /* 01 : Mux1 selected */ -#define YSEL_M2 0x08 /* 10 : Mux2 selected */ -#define YSEL_M3 0x10 /* 11 : Mux3 selected */ - -/* OPFORM */ -#define MODE 0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */ - /* 1 : ITU-R-656 compatible data sequence format */ -#define LEN 0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */ - /* 1 : 16-bit YCrCb 4:2:2 output format.*/ -#define LLCMODE 0x20 /* 1 : LLC output mode. */ - /* 0 : free-run output mode */ -#define AINC 0x10 /* Serial interface auto-indexing control */ - /* 0 : auto-increment */ - /* 1 : non-auto */ -#define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */ - /* 0 : Vertical out ctrl by HACTIVE and DVALID */ -#define OEN_TRI_SEL_MASK 0x07 -#define OEN_TRI_SEL_ALL_ON 0x00 /* Enable output for Rev0/Rev1 */ -#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */ -#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */ - -/* OUTCTR1 */ -#define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */ -#define VSP_HI 0x80 /* 1 : VS pin output polarity is active high. */ - /* VS pin output control */ -#define VSSL_VSYNC 0x00 /* 0 : VSYNC */ -#define VSSL_VACT 0x10 /* 1 : VACT */ -#define VSSL_FIELD 0x20 /* 2 : FIELD */ -#define VSSL_VVALID 0x30 /* 3 : VVALID */ -#define VSSL_ZERO 0x70 /* 7 : 0 */ -#define HSP_LOW 0x00 /* 0 : HS pin output polarity is active low */ -#define HSP_HI 0x08 /* 1 : HS pin output polarity is active high.*/ - /* HS pin output control */ -#define HSSL_HACT 0x00 /* 0 : HACT */ -#define HSSL_HSYNC 0x01 /* 1 : HSYNC */ -#define HSSL_DVALID 0x02 /* 2 : DVALID */ -#define HSSL_HLOCK 0x03 /* 3 : HLOCK */ -#define HSSL_ASYNCW 0x04 /* 4 : ASYNCW */ -#define HSSL_ZERO 0x07 /* 7 : 0 */ - -/* ACNTL1 */ -#define SRESET 0x80 /* resets the device to its default state - * but all register content remain unchanged. - * This bit is self-resetting. - */ -#define ACNTL1_PDN_MASK 0x0e -#define CLK_PDN 0x08 /* system clock power down */ -#define Y_PDN 0x04 /* Luma ADC power down */ -#define C_PDN 0x02 /* Chroma ADC power down */ - -/* ACNTL2 */ -#define ACNTL2_PDN_MASK 0x40 -#define PLL_PDN 0x40 /* PLL power down */ - -/* VBICNTL */ - -/* RTSEL : control the real time signal output from the MPOUT pin */ -#define RTSEL_MASK 0x07 -#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */ -#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */ -#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */ -#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */ -#define RTSEL_MONO 0x04 /* 0100 = MONO */ -#define RTSEL_DET50 0x05 /* 0101 = DET50 */ -#define RTSEL_FIELD 0x06 /* 0110 = FIELD */ -#define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */ - -/* - * structure - */ - -struct regval_list { - unsigned char reg_num; - unsigned char value; -}; - -struct tw9910_scale_ctrl { - char *name; - unsigned short width; - unsigned short height; - u16 hscale; - u16 vscale; -}; - -struct tw9910_cropping_ctrl { - u16 vdelay; - u16 vactive; - u16 hdelay; - u16 hactive; -}; - -struct tw9910_hsync_ctrl { - u16 start; - u16 end; -}; - -struct tw9910_priv { - struct v4l2_subdev subdev; - struct tw9910_video_info *info; - const struct tw9910_scale_ctrl *scale; - u32 revision; -}; - -static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = { - { - .name = "NTSC SQ", - .width = 640, - .height = 480, - .hscale = 0x0100, - .vscale = 0x0100, - }, - { - .name = "NTSC CCIR601", - .width = 720, - .height = 480, - .hscale = 0x0100, - .vscale = 0x0100, - }, - { - .name = "NTSC SQ (CIF)", - .width = 320, - .height = 240, - .hscale = 0x0200, - .vscale = 0x0200, - }, - { - .name = "NTSC CCIR601 (CIF)", - .width = 360, - .height = 240, - .hscale = 0x0200, - .vscale = 0x0200, - }, - { - .name = "NTSC SQ (QCIF)", - .width = 160, - .height = 120, - .hscale = 0x0400, - .vscale = 0x0400, - }, - { - .name = "NTSC CCIR601 (QCIF)", - .width = 180, - .height = 120, - .hscale = 0x0400, - .vscale = 0x0400, - }, -}; - -static const struct tw9910_scale_ctrl tw9910_pal_scales[] = { - { - .name = "PAL SQ", - .width = 768, - .height = 576, - .hscale = 0x0100, - .vscale = 0x0100, - }, - { - .name = "PAL CCIR601", - .width = 720, - .height = 576, - .hscale = 0x0100, - .vscale = 0x0100, - }, - { - .name = "PAL SQ (CIF)", - .width = 384, - .height = 288, - .hscale = 0x0200, - .vscale = 0x0200, - }, - { - .name = "PAL CCIR601 (CIF)", - .width = 360, - .height = 288, - .hscale = 0x0200, - .vscale = 0x0200, - }, - { - .name = "PAL SQ (QCIF)", - .width = 192, - .height = 144, - .hscale = 0x0400, - .vscale = 0x0400, - }, - { - .name = "PAL CCIR601 (QCIF)", - .width = 180, - .height = 144, - .hscale = 0x0400, - .vscale = 0x0400, - }, -}; - -static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = { - .start = 0x0260, - .end = 0x0300, -}; - -/* - * general function - */ -static struct tw9910_priv *to_tw9910(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct tw9910_priv, - subdev); -} - -static int tw9910_mask_set(struct i2c_client *client, u8 command, - u8 mask, u8 set) -{ - s32 val = i2c_smbus_read_byte_data(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return i2c_smbus_write_byte_data(client, command, val); -} - -static int tw9910_set_scale(struct i2c_client *client, - const struct tw9910_scale_ctrl *scale) -{ - int ret; - - ret = i2c_smbus_write_byte_data(client, SCALE_HI, - (scale->vscale & 0x0F00) >> 4 | - (scale->hscale & 0x0F00) >> 8); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, HSCALE_LO, - scale->hscale & 0x00FF); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, VSCALE_LO, - scale->vscale & 0x00FF); - - return ret; -} - -static int tw9910_set_hsync(struct i2c_client *client, - const struct tw9910_hsync_ctrl *hsync) -{ - struct tw9910_priv *priv = to_tw9910(client); - int ret; - - /* bit 10 - 3 */ - ret = i2c_smbus_write_byte_data(client, HSBEGIN, - (hsync->start & 0x07F8) >> 3); - if (ret < 0) - return ret; - - /* bit 10 - 3 */ - ret = i2c_smbus_write_byte_data(client, HSEND, - (hsync->end & 0x07F8) >> 3); - if (ret < 0) - return ret; - - /* So far only revisions 0 and 1 have been seen */ - /* bit 2 - 0 */ - if (1 == priv->revision) - ret = tw9910_mask_set(client, HSLOWCTL, 0x77, - (hsync->start & 0x0007) << 4 | - (hsync->end & 0x0007)); - - return ret; -} - -static void tw9910_reset(struct i2c_client *client) -{ - tw9910_mask_set(client, ACNTL1, SRESET, SRESET); - msleep(1); -} - -static int tw9910_power(struct i2c_client *client, int enable) -{ - int ret; - u8 acntl1; - u8 acntl2; - - if (enable) { - acntl1 = 0; - acntl2 = 0; - } else { - acntl1 = CLK_PDN | Y_PDN | C_PDN; - acntl2 = PLL_PDN; - } - - ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1); - if (ret < 0) - return ret; - - return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); -} - -static const struct tw9910_scale_ctrl* -tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height) -{ - const struct tw9910_scale_ctrl *scale; - const struct tw9910_scale_ctrl *ret = NULL; - v4l2_std_id norm = icd->vdev->current_norm; - __u32 diff = 0xffffffff, tmp; - int size, i; - - if (norm & V4L2_STD_NTSC) { - scale = tw9910_ntsc_scales; - size = ARRAY_SIZE(tw9910_ntsc_scales); - } else if (norm & V4L2_STD_PAL) { - scale = tw9910_pal_scales; - size = ARRAY_SIZE(tw9910_pal_scales); - } else { - return NULL; - } - - for (i = 0; i < size; i++) { - tmp = abs(width - scale[i].width) + - abs(height - scale[i].height); - if (tmp < diff) { - diff = tmp; - ret = scale + i; - } - } - - return ret; -} - -/* - * soc_camera_ops function - */ -static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - u8 val; - int ret; - - if (!enable) { - switch (priv->revision) { - case 0: - val = OEN_TRI_SEL_ALL_OFF_r0; - break; - case 1: - val = OEN_TRI_SEL_ALL_OFF_r1; - break; - default: - dev_err(&client->dev, "un-supported revision\n"); - return -EINVAL; - } - } else { - val = OEN_TRI_SEL_ALL_ON; - - if (!priv->scale) { - dev_err(&client->dev, "norm select error\n"); - return -EPERM; - } - - dev_dbg(&client->dev, "%s %dx%d\n", - priv->scale->name, - priv->scale->width, - priv->scale->height); - } - - ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val); - if (ret < 0) - return ret; - - return tw9910_power(client, enable); -} - -static int tw9910_set_bus_param(struct soc_camera_device *icd, - unsigned long flags) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 val = VSSL_VVALID | HSSL_DVALID; - - /* - * set OUTCTR1 - * - * We use VVALID and DVALID signals to control VSYNC and HSYNC - * outputs, in this mode their polarity is inverted. - */ - if (flags & SOCAM_HSYNC_ACTIVE_LOW) - val |= HSP_HI; - - if (flags & SOCAM_VSYNC_ACTIVE_LOW) - val |= VSP_HI; - - return i2c_smbus_write_byte_data(client, OUTCTR1, val); -} - -static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) -{ - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); - struct tw9910_priv *priv = to_tw9910(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); - unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | - SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - SOCAM_VSYNC_ACTIVE_LOW | SOCAM_HSYNC_ACTIVE_LOW | - SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; - - return soc_camera_apply_sensor_flags(icl, flags); -} - -static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - int ret = -EINVAL; - - if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL)) - ret = 0; - - return ret; -} - -static int tw9910_enum_input(struct soc_camera_device *icd, - struct v4l2_input *inp) -{ - inp->type = V4L2_INPUT_TYPE_TUNER; - inp->std = V4L2_STD_UNKNOWN; - strcpy(inp->name, "Video"); - - return 0; -} - -static int tw9910_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *id) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - - id->ident = V4L2_IDENT_TW9910; - id->revision = priv->revision; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int tw9910_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (reg->reg > 0xff) - return -EINVAL; - - ret = i2c_smbus_read_byte_data(client, reg->reg); - if (ret < 0) - return ret; - - /* - * ret = int - * reg->val = __u64 - */ - reg->val = (__u64)ret; - - return 0; -} - -static int tw9910_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff || - reg->val > 0xff) - return -EINVAL; - - return i2c_smbus_write_byte_data(client, reg->reg, reg->val); -} -#endif - -static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct v4l2_rect *rect = &a->c; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - struct soc_camera_device *icd = client->dev.platform_data; - int ret = -EINVAL; - u8 val; - - /* - * select suitable norm - */ - priv->scale = tw9910_select_norm(icd, rect->width, rect->height); - if (!priv->scale) - goto tw9910_set_fmt_error; - - /* - * reset hardware - */ - tw9910_reset(client); - - /* - * set bus width - */ - val = 0x00; - if (SOCAM_DATAWIDTH_16 == priv->info->buswidth) - val = LEN; - - ret = tw9910_mask_set(client, OPFORM, LEN, val); - if (ret < 0) - goto tw9910_set_fmt_error; - - /* - * select MPOUT behavior - */ - switch (priv->info->mpout) { - case TW9910_MPO_VLOSS: - val = RTSEL_VLOSS; break; - case TW9910_MPO_HLOCK: - val = RTSEL_HLOCK; break; - case TW9910_MPO_SLOCK: - val = RTSEL_SLOCK; break; - case TW9910_MPO_VLOCK: - val = RTSEL_VLOCK; break; - case TW9910_MPO_MONO: - val = RTSEL_MONO; break; - case TW9910_MPO_DET50: - val = RTSEL_DET50; break; - case TW9910_MPO_FIELD: - val = RTSEL_FIELD; break; - case TW9910_MPO_RTCO: - val = RTSEL_RTCO; break; - default: - val = 0; - } - - ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val); - if (ret < 0) - goto tw9910_set_fmt_error; - - /* - * set scale - */ - ret = tw9910_set_scale(client, priv->scale); - if (ret < 0) - goto tw9910_set_fmt_error; - - /* - * set hsync - */ - ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl); - if (ret < 0) - goto tw9910_set_fmt_error; - - rect->width = priv->scale->width; - rect->height = priv->scale->height; - rect->left = 0; - rect->top = 0; - - return ret; - -tw9910_set_fmt_error: - - tw9910_reset(client); - priv->scale = NULL; - - return ret; -} - -static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - - if (!priv->scale) { - int ret; - struct v4l2_crop crop = { - .c = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }; - ret = tw9910_s_crop(sd, &crop); - if (ret < 0) - return ret; - } - - a->c.left = 0; - a->c.top = 0; - a->c.width = priv->scale->width; - a->c.height = priv->scale->height; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - return 0; -} - -static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -{ - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = 768; - a->bounds.height = 576; - a->defrect.left = 0; - a->defrect.top = 0; - a->defrect.width = 640; - a->defrect.height = 480; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - -static int tw9910_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - - if (!priv->scale) { - int ret; - struct v4l2_crop crop = { - .c = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }; - ret = tw9910_s_crop(sd, &crop); - if (ret < 0) - return ret; - } - - mf->width = priv->scale->width; - mf->height = priv->scale->height; - mf->code = V4L2_MBUS_FMT_UYVY8_2X8; - mf->colorspace = V4L2_COLORSPACE_JPEG; - mf->field = V4L2_FIELD_INTERLACED_BT; - - return 0; -} - -static int tw9910_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - /* See tw9910_s_crop() - no proper cropping support */ - struct v4l2_crop a = { - .c = { - .left = 0, - .top = 0, - .width = mf->width, - .height = mf->height, - }, - }; - int ret; - - WARN_ON(mf->field != V4L2_FIELD_ANY && - mf->field != V4L2_FIELD_INTERLACED_BT); - - /* - * check color format - */ - if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8) - return -EINVAL; - - mf->colorspace = V4L2_COLORSPACE_JPEG; - - ret = tw9910_s_crop(sd, &a); - if (!ret) { - mf->width = priv->scale->width; - mf->height = priv->scale->height; - } - return ret; -} - -static int tw9910_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - const struct tw9910_scale_ctrl *scale; - - if (V4L2_FIELD_ANY == mf->field) { - mf->field = V4L2_FIELD_INTERLACED_BT; - } else if (V4L2_FIELD_INTERLACED_BT != mf->field) { - dev_err(&client->dev, "Field type %d invalid.\n", mf->field); - return -EINVAL; - } - - mf->code = V4L2_MBUS_FMT_UYVY8_2X8; - mf->colorspace = V4L2_COLORSPACE_JPEG; - - /* - * select suitable norm - */ - scale = tw9910_select_norm(icd, mf->width, mf->height); - if (!scale) - return -EINVAL; - - mf->width = scale->width; - mf->height = scale->height; - - return 0; -} - -static int tw9910_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) -{ - struct tw9910_priv *priv = to_tw9910(client); - s32 id; - - /* - * We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. - */ - if (!icd->dev.parent || - to_soc_camera_host(icd->dev.parent)->nr != icd->iface) - return -ENODEV; - - /* - * tw9910 only use 8 or 16 bit bus width - */ - if (SOCAM_DATAWIDTH_16 != priv->info->buswidth && - SOCAM_DATAWIDTH_8 != priv->info->buswidth) { - dev_err(&client->dev, "bus width error\n"); - return -ENODEV; - } - - /* - * check and show Product ID - * So far only revisions 0 and 1 have been seen - */ - id = i2c_smbus_read_byte_data(client, ID); - priv->revision = GET_REV(id); - id = GET_ID(id); - - if (0x0B != id || - 0x01 < priv->revision) { - dev_err(&client->dev, - "Product ID error %x:%x\n", - id, priv->revision); - return -ENODEV; - } - - dev_info(&client->dev, - "tw9910 Product ID %0x:%0x\n", id, priv->revision); - - icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; - icd->vdev->current_norm = V4L2_STD_NTSC; - - return 0; -} - -static struct soc_camera_ops tw9910_ops = { - .set_bus_param = tw9910_set_bus_param, - .query_bus_param = tw9910_query_bus_param, - .enum_input = tw9910_enum_input, -}; - -static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { - .g_chip_ident = tw9910_g_chip_ident, - .s_std = tw9910_s_std, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = tw9910_g_register, - .s_register = tw9910_s_register, -#endif -}; - -static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) -{ - if (index) - return -EINVAL; - - *code = V4L2_MBUS_FMT_UYVY8_2X8; - return 0; -} - -static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { - .s_stream = tw9910_s_stream, - .g_mbus_fmt = tw9910_g_fmt, - .s_mbus_fmt = tw9910_s_fmt, - .try_mbus_fmt = tw9910_try_fmt, - .cropcap = tw9910_cropcap, - .g_crop = tw9910_g_crop, - .s_crop = tw9910_s_crop, - .enum_mbus_fmt = tw9910_enum_fmt, -}; - -static struct v4l2_subdev_ops tw9910_subdev_ops = { - .core = &tw9910_subdev_core_ops, - .video = &tw9910_subdev_video_ops, -}; - -/* - * i2c_driver function - */ - -static int tw9910_probe(struct i2c_client *client, - const struct i2c_device_id *did) - -{ - struct tw9910_priv *priv; - struct tw9910_video_info *info; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = - to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "TW9910: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) - return -EINVAL; - - info = icl->priv; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, - "I2C-Adapter doesn't support " - "I2C_FUNC_SMBUS_BYTE_DATA\n"); - return -EIO; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->info = info; - - v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - - icd->ops = &tw9910_ops; - icd->iface = icl->bus_id; - - ret = tw9910_video_probe(icd, client); - if (ret) { - icd->ops = NULL; - kfree(priv); - } - - return ret; -} - -static int tw9910_remove(struct i2c_client *client) -{ - struct tw9910_priv *priv = to_tw9910(client); - struct soc_camera_device *icd = client->dev.platform_data; - - icd->ops = NULL; - kfree(priv); - return 0; -} - -static const struct i2c_device_id tw9910_id[] = { - { "tw9910", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tw9910_id); - -static struct i2c_driver tw9910_i2c_driver = { - .driver = { - .name = "tw9910", - }, - .probe = tw9910_probe, - .remove = tw9910_remove, - .id_table = tw9910_id, -}; - -/* - * module function - */ -static int __init tw9910_module_init(void) -{ - return i2c_add_driver(&tw9910_i2c_driver); -} - -static void __exit tw9910_module_exit(void) -{ - i2c_del_driver(&tw9910_i2c_driver); -} - -module_init(tw9910_module_init); -module_exit(tw9910_module_exit); - -MODULE_DESCRIPTION("SoC Camera driver for tw9910"); -MODULE_AUTHOR("Kuninori Morimoto"); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/upd64031a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/upd64031a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/upd64031a.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/upd64031a.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,285 +0,0 @@ -/* - * upd64031A - NEC Electronics Ghost Reduction for NTSC in Japan - * - * 2003 by T.Adachi - * 2003 by Takeru KOMORIYA - * 2006 by Hans Verkuil - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -/* --------------------- read registers functions define -------------------- */ - -/* bit masks */ -#define GR_MODE_MASK 0xc0 -#define DIRECT_3DYCS_CONNECT_MASK 0xc0 -#define SYNC_CIRCUIT_MASK 0xa0 - -/* -------------------------------------------------------------------------- */ - -MODULE_DESCRIPTION("uPD64031A driver"); -MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0644); - -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -enum { - R00 = 0, R01, R02, R03, R04, - R05, R06, R07, R08, R09, - R0A, R0B, R0C, R0D, R0E, R0F, - /* unused registers - R10, R11, R12, R13, R14, - R15, R16, R17, - */ - TOT_REGS -}; - -struct upd64031a_state { - struct v4l2_subdev sd; - u8 regs[TOT_REGS]; - u8 gr_mode; - u8 direct_3dycs_connect; - u8 ext_comp_sync; - u8 ext_vert_sync; -}; - -static inline struct upd64031a_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct upd64031a_state, sd); -} - -static u8 upd64031a_init[] = { - 0x00, 0xb8, 0x48, 0xd2, 0xe6, - 0x03, 0x10, 0x0b, 0xaf, 0x7f, - 0x00, 0x00, 0x1d, 0x5e, 0x00, - 0xd0 -}; - -/* ------------------------------------------------------------------------ */ - -static u8 upd64031a_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 buf[2]; - - if (reg >= sizeof(buf)) - return 0xff; - i2c_master_recv(client, buf, 2); - return buf[reg]; -} - -/* ------------------------------------------------------------------------ */ - -static void upd64031a_write(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 buf[2]; - - buf[0] = reg; - buf[1] = val; - v4l2_dbg(1, debug, sd, "write reg: %02X val: %02X\n", reg, val); - if (i2c_master_send(client, buf, 2) != 2) - v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val); -} - -/* ------------------------------------------------------------------------ */ - -/* The input changed due to new input or channel changed */ -static int upd64031a_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) -{ - struct upd64031a_state *state = to_state(sd); - u8 reg = state->regs[R00]; - - v4l2_dbg(1, debug, sd, "changed input or channel\n"); - upd64031a_write(sd, R00, reg | 0x10); - upd64031a_write(sd, R00, reg & ~0x10); - return 0; -} - -/* ------------------------------------------------------------------------ */ - -static int upd64031a_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct upd64031a_state *state = to_state(sd); - u8 r00, r05, r08; - - state->gr_mode = (input & 3) << 6; - state->direct_3dycs_connect = (input & 0xc) << 4; - state->ext_comp_sync = - (input & UPD64031A_COMPOSITE_EXTERNAL) << 1; - state->ext_vert_sync = - (input & UPD64031A_VERTICAL_EXTERNAL) << 2; - r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode; - r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) | - state->ext_comp_sync | state->ext_vert_sync; - r08 = (state->regs[R08] & ~DIRECT_3DYCS_CONNECT_MASK) | - state->direct_3dycs_connect; - upd64031a_write(sd, R00, r00); - upd64031a_write(sd, R05, r05); - upd64031a_write(sd, R08, r08); - return upd64031a_s_frequency(sd, NULL); -} - -static int upd64031a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64031A, 0); -} - -static int upd64031a_log_status(struct v4l2_subdev *sd) -{ - v4l2_info(sd, "Status: SA00=0x%02x SA01=0x%02x\n", - upd64031a_read(sd, 0), upd64031a_read(sd, 1)); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->val = upd64031a_read(sd, reg->reg & 0xff); - reg->size = 1; - return 0; -} - -static int upd64031a_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - upd64031a_write(sd, reg->reg & 0xff, reg->val & 0xff); - return 0; -} -#endif - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops upd64031a_core_ops = { - .log_status = upd64031a_log_status, - .g_chip_ident = upd64031a_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = upd64031a_g_register, - .s_register = upd64031a_s_register, -#endif -}; - -static const struct v4l2_subdev_tuner_ops upd64031a_tuner_ops = { - .s_frequency = upd64031a_s_frequency, -}; - -static const struct v4l2_subdev_video_ops upd64031a_video_ops = { - .s_routing = upd64031a_s_routing, -}; - -static const struct v4l2_subdev_ops upd64031a_ops = { - .core = &upd64031a_core_ops, - .tuner = &upd64031a_tuner_ops, - .video = &upd64031a_video_ops, -}; - -/* ------------------------------------------------------------------------ */ - -/* i2c implementation */ - -static int upd64031a_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct upd64031a_state *state; - struct v4l2_subdev *sd; - int i; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &upd64031a_ops); - memcpy(state->regs, upd64031a_init, sizeof(state->regs)); - state->gr_mode = UPD64031A_GR_ON << 6; - state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4; - state->ext_comp_sync = state->ext_vert_sync = 0; - for (i = 0; i < TOT_REGS; i++) - upd64031a_write(sd, i, state->regs[i]); - return 0; -} - -static int upd64031a_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id upd64031a_id[] = { - { "upd64031a", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, upd64031a_id); - -static struct i2c_driver upd64031a_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "upd64031a", - }, - .probe = upd64031a_probe, - .remove = upd64031a_remove, - .id_table = upd64031a_id, -}; - -static __init int init_upd64031a(void) -{ - return i2c_add_driver(&upd64031a_driver); -} - -static __exit void exit_upd64031a(void) -{ - i2c_del_driver(&upd64031a_driver); -} - -module_init(init_upd64031a); -module_exit(exit_upd64031a); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/upd64083.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/upd64083.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/upd64083.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/upd64083.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,257 +0,0 @@ -/* - * upd6408x - NEC Electronics 3-Dimensional Y/C separation driver - * - * 2003 by T.Adachi (tadachi@tadachi-net.com) - * 2003 by Takeru KOMORIYA - * 2006 by Hans Verkuil - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("uPD64083 driver"); -MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, bool, 0644); - -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -enum { - R00 = 0, R01, R02, R03, R04, - R05, R06, R07, R08, R09, - R0A, R0B, R0C, R0D, R0E, R0F, - R10, R11, R12, R13, R14, - R15, R16, - TOT_REGS -}; - -struct upd64083_state { - struct v4l2_subdev sd; - u8 mode; - u8 ext_y_adc; - u8 regs[TOT_REGS]; -}; - -static inline struct upd64083_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct upd64083_state, sd); -} - -/* Initial values when used in combination with the - NEC upd64031a ghost reduction chip. */ -static u8 upd64083_init[] = { - 0x1f, 0x01, 0xa0, 0x2d, 0x29, /* we use EXCSS=0 */ - 0x36, 0xdd, 0x05, 0x56, 0x48, - 0x00, 0x3a, 0xa0, 0x05, 0x08, - 0x44, 0x60, 0x08, 0x52, 0xf8, - 0x53, 0x60, 0x10 -}; - -/* ------------------------------------------------------------------------ */ - -static void upd64083_write(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 buf[2]; - - buf[0] = reg; - buf[1] = val; - v4l2_dbg(1, debug, sd, "write reg: %02x val: %02x\n", reg, val); - if (i2c_master_send(client, buf, 2) != 2) - v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val); -} - -/* ------------------------------------------------------------------------ */ - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static u8 upd64083_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 buf[7]; - - if (reg >= sizeof(buf)) - return 0xff; - i2c_master_recv(client, buf, sizeof(buf)); - return buf[reg]; -} -#endif - -/* ------------------------------------------------------------------------ */ - -static int upd64083_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct upd64083_state *state = to_state(sd); - u8 r00, r02; - - if (input > 7 || (input & 6) == 6) - return -EINVAL; - state->mode = (input & 3) << 6; - state->ext_y_adc = (input & UPD64083_EXT_Y_ADC) << 3; - r00 = (state->regs[R00] & ~(3 << 6)) | state->mode; - r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc; - upd64083_write(sd, R00, r00); - upd64083_write(sd, R02, r02); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->val = upd64083_read(sd, reg->reg & 0xff); - reg->size = 1; - return 0; -} - -static int upd64083_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!v4l2_chip_match_i2c_client(client, ®->match)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - upd64083_write(sd, reg->reg & 0xff, reg->val & 0xff); - return 0; -} -#endif - -static int upd64083_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64083, 0); -} - -static int upd64083_log_status(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 buf[7]; - - i2c_master_recv(client, buf, 7); - v4l2_info(sd, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x " - "SA04=%02x SA05=%02x SA06=%02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops upd64083_core_ops = { - .log_status = upd64083_log_status, - .g_chip_ident = upd64083_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = upd64083_g_register, - .s_register = upd64083_s_register, -#endif -}; - -static const struct v4l2_subdev_video_ops upd64083_video_ops = { - .s_routing = upd64083_s_routing, -}; - -static const struct v4l2_subdev_ops upd64083_ops = { - .core = &upd64083_core_ops, - .video = &upd64083_video_ops, -}; - -/* ------------------------------------------------------------------------ */ - -/* i2c implementation */ - -static int upd64083_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct upd64083_state *state; - struct v4l2_subdev *sd; - int i; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &upd64083_ops); - /* Initially assume that a ghost reduction chip is present */ - state->mode = 0; /* YCS mode */ - state->ext_y_adc = (1 << 5); - memcpy(state->regs, upd64083_init, TOT_REGS); - for (i = 0; i < TOT_REGS; i++) - upd64083_write(sd, i, state->regs[i]); - return 0; -} - -static int upd64083_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id upd64083_id[] = { - { "upd64083", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, upd64083_id); - -static struct i2c_driver upd64083_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "upd64083", - }, - .probe = upd64083_probe, - .remove = upd64083_remove, - .id_table = upd64083_id, -}; - -static __init int init_upd64083(void) -{ - return i2c_add_driver(&upd64083_driver); -} - -static __exit void exit_upd64083(void) -{ - i2c_del_driver(&upd64083_driver); -} - -module_init(init_upd64083); -module_exit(exit_upd64083); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -config VIDEO_USBVISION - tristate "USB video devices based on Nogatech NT1003/1004/1005" - depends on I2C && VIDEO_V4L2 - select VIDEO_TUNER - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - ---help--- - There are more than 50 different USB video devices based on - NT1003/1004/1005 USB Bridges. This driver enables using those - devices. - - To compile this driver as a module, choose M here: the - module will be called usbvision. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-cards.o - -obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-cards.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1103 +0,0 @@ -/* - * usbvision-cards.c - * usbvision cards definition file - * - * Copyright (c) 1999-2005 Joerg Heckenbach - * - * This module is part of usbvision driver project. - * Updates to driver completed by Dwaine P. Garden - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include "usbvision.h" -#include "usbvision-cards.h" - -/* Supported Devices: A table for usbvision.c*/ -struct usbvision_device_data_st usbvision_device_data[] = { - [XANBOO] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 4, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = -1, - .y_offset = -1, - .model_string = "Xanboo", - }, - [BELKIN_VIDEOBUS_II] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Belkin USB VideoBus II Adapter", - }, - [BELKIN_VIDEOBUS] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 2, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = -1, - .y_offset = -1, - .model_string = "Belkin Components USB VideoBus", - }, - [BELKIN_USB_VIDEOBUS_II] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Belkin USB VideoBus II", - }, - [ECHOFX_INTERVIEW_LITE] = { - .interface = 0, - .codec = CODEC_SAA7111, - .video_channels = 2, - .video_norm = V4L2_STD_PAL, - .audio_channels = 0, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = -1, - .y_offset = -1, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "echoFX InterView Lite", - }, - [USBGEAR_USBG_V1] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 2, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = -1, - .y_offset = -1, - .model_string = "USBGear USBG-V1 resp. HAMA USB", - }, - [D_LINK_V100] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 4, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 0, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "D-Link V100", - }, - [X10_USB_CAMERA] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 2, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = -1, - .y_offset = -1, - .model_string = "X10 USB Camera", - }, - [HPG_WINTV_LIVE_PAL_BG] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 2, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = -1, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Live (PAL B/G)", - }, - [HPG_WINTV_LIVE_PRO_NTSC_MN] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 0, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Live Pro (NTSC M/N)", - }, - [ZORAN_PMD_NOGATECH] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_PAL, - .audio_channels = 2, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Zoran Co. PMD (Nogatech) AV-grabber Manhattan", - }, - [NOGATECH_USB_TV_NTSC_FM] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = -1, - .y_offset = 20, - .model_string = "Nogatech USB-TV (NTSC) FM", - }, - [PNY_USB_TV_NTSC_FM] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = -1, - .y_offset = 20, - .model_string = "PNY USB-TV (NTSC) FM", - }, - [PV_PLAYTV_USB_PRO_PAL_FM] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "PixelView PlayTv-USB PRO (PAL) FM", - }, - [ZT_721] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "ZTV ZT-721 2.4GHz USB A/V Receiver", - }, - [HPG_WINTV_NTSC_MN] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = -1, - .y_offset = 20, - .model_string = "Hauppauge WinTV USB (NTSC M/N)", - }, - [HPG_WINTV_PAL_BG] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = -1, - .y_offset = -1, - .model_string = "Hauppauge WinTV USB (PAL B/G)", - }, - [HPG_WINTV_PAL_I] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = -1, - .y_offset = -1, - .model_string = "Hauppauge WinTV USB (PAL I)", - }, - [HPG_WINTV_PAL_SECAM_L] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_SECAM, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_SECAM, - .x_offset = 0x80, - .y_offset = 0x16, - .model_string = "Hauppauge WinTV USB (PAL/SECAM L)", - }, - [HPG_WINTV_PAL_D_K] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = -1, - .y_offset = -1, - .model_string = "Hauppauge WinTV USB (PAL D/K)", - }, - [HPG_WINTV_NTSC_FM] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = -1, - .y_offset = -1, - .model_string = "Hauppauge WinTV USB (NTSC FM)", - }, - [HPG_WINTV_PAL_BG_FM] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = -1, - .y_offset = -1, - .model_string = "Hauppauge WinTV USB (PAL B/G FM)", - }, - [HPG_WINTV_PAL_I_FM] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = -1, - .y_offset = -1, - .model_string = "Hauppauge WinTV USB (PAL I FM)", - }, - [HPG_WINTV_PAL_D_K_FM] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = -1, - .y_offset = -1, - .model_string = "Hauppauge WinTV USB (PAL D/K FM)", - }, - [HPG_WINTV_PRO_NTSC_MN] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_MICROTUNE_4049FM5, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (NTSC M/N)", - }, - [HPG_WINTV_PRO_NTSC_MN_V2] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_MICROTUNE_4049FM5, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (NTSC M/N) V2", - }, - [HPG_WINTV_PRO_PAL] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)", - }, - [HPG_WINTV_PRO_NTSC_MN_V3] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (NTSC M/N) V3", - }, - [HPG_WINTV_PRO_PAL_BG] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL B/G)", - }, - [HPG_WINTV_PRO_PAL_I] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL I)", - }, - [HPG_WINTV_PRO_PAL_SECAM_L] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_SECAM, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_SECAM, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM L)", - }, - [HPG_WINTV_PRO_PAL_D_K] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL D/K)", - }, - [HPG_WINTV_PRO_PAL_SECAM] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_SECAM, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_SECAM, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)", - }, - [HPG_WINTV_PRO_PAL_SECAM_V2] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_SECAM, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_SECAM, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2", - }, - [HPG_WINTV_PRO_PAL_BG_V2] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_ALPS_TSBE1_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL B/G) V2", - }, - [HPG_WINTV_PRO_PAL_BG_D_K] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_ALPS_TSBE1_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL B/G,D/K)", - }, - [HPG_WINTV_PRO_PAL_I_D_K] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL I,D/K)", - }, - [HPG_WINTV_PRO_NTSC_MN_FM] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (NTSC M/N FM)", - }, - [HPG_WINTV_PRO_PAL_BG_FM] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL B/G FM)", - }, - [HPG_WINTV_PRO_PAL_I_FM] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL I FM)", - }, - [HPG_WINTV_PRO_PAL_D_K_FM] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL D/K FM)", - }, - [HPG_WINTV_PRO_TEMIC_PAL_FM] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_MICROTUNE_4049FM5, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM)", - }, - [HPG_WINTV_PRO_TEMIC_PAL_BG_FM] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_MICROTUNE_4049FM5, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (Temic PAL B/G FM)", - }, - [HPG_WINTV_PRO_PAL_FM] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)", - }, - [HPG_WINTV_PRO_NTSC_MN_FM_V2] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Hauppauge WinTV USB Pro (NTSC M/N FM) V2", - }, - [CAMTEL_TVB330] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = 5, - .y_offset = 5, - .model_string = "Camtel Technology USB TV Genie Pro FM Model TVB330", - }, - [DIGITAL_VIDEO_CREATOR_I] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_PAL, - .audio_channels = 0, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Digital Video Creator I", - }, - [GLOBAL_VILLAGE_GV_007_NTSC] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 2, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 0, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 82, - .y_offset = 20, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Global Village GV-007 (NTSC)", - }, - [DAZZLE_DVC_50_REV_1_NTSC] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 0, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)", - }, - [DAZZLE_DVC_80_REV_1_PAL] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_PAL, - .audio_channels = 0, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Dazzle Fusion Model DVC-80 Rev 1 (PAL)", - }, - [DAZZLE_DVC_90_REV_1_SECAM] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_SECAM, - .audio_channels = 0, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)", - }, - [ESKAPE_LABS_MYTV2GO] = { - .interface = 0, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Eskape Labs MyTV2Go", - }, - [PINNA_PCTV_USB_PAL] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 0, - .tuner = 1, - .tuner_type = TUNER_TEMIC_4066FY5_PAL_I, - .x_offset = -1, - .y_offset = -1, - .model_string = "Pinnacle Studio PCTV USB (PAL)", - }, - [PINNA_PCTV_USB_SECAM] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_SECAM, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_SECAM, - .x_offset = -1, - .y_offset = -1, - .model_string = "Pinnacle Studio PCTV USB (SECAM)", - }, - [PINNA_PCTV_USB_PAL_FM] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = 128, - .y_offset = 23, - .model_string = "Pinnacle Studio PCTV USB (PAL) FM", - }, - [MIRO_PCTV_USB] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .x_offset = -1, - .y_offset = -1, - .model_string = "Miro PCTV USB", - }, - [PINNA_PCTV_USB_NTSC_FM] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = -1, - .y_offset = -1, - .model_string = "Pinnacle Studio PCTV USB (NTSC) FM", - }, - [PINNA_PCTV_USB_NTSC_FM_V3] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = -1, - .y_offset = -1, - .model_string = "Pinnacle Studio PCTV USB (NTSC) FM V3", - }, - [PINNA_PCTV_USB_PAL_FM_V2] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_TEMIC_4009FR5_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Pinnacle Studio PCTV USB (PAL) FM V2", - }, - [PINNA_PCTV_USB_NTSC_FM_V2] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_TEMIC_4039FR5_NTSC, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Pinnacle Studio PCTV USB (NTSC) FM V2", - }, - [PINNA_PCTV_USB_PAL_FM_V3] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_TEMIC_4009FR5_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Pinnacle Studio PCTV USB (PAL) FM V3", - }, - [PINNA_LINX_VD_IN_CAB_NTSC] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Pinnacle Studio Linx Video input cable (NTSC)", - }, - [PINNA_LINX_VD_IN_CAB_PAL] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 2, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 0, - .tuner_type = 0, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Pinnacle Studio Linx Video input cable (PAL)", - }, - [PINNA_PCTV_BUNGEE_PAL_FM] = { - .interface = -1, - .codec = CODEC_SAA7113, - .video_channels = 3, - .video_norm = V4L2_STD_PAL, - .audio_channels = 1, - .radio = 1, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_TEMIC_4009FR5_PAL, - .x_offset = 0, - .y_offset = 3, - .dvi_yuv_override = 1, - .dvi_yuv = 7, - .model_string = "Pinnacle PCTV Bungee USB (PAL) FM", - }, - [HPG_WINTV] = { - .interface = -1, - .codec = CODEC_SAA7111, - .video_channels = 3, - .video_norm = V4L2_STD_NTSC, - .audio_channels = 1, - .radio = 0, - .vbi = 1, - .tuner = 1, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .x_offset = -1, - .y_offset = -1, - .model_string = "Hauppauge WinTv-USB", - }, -}; -const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data); - -/* Supported Devices */ - -struct usb_device_id usbvision_table[] = { - { USB_DEVICE(0x0a6f, 0x0400), .driver_info = XANBOO }, - { USB_DEVICE(0x050d, 0x0106), .driver_info = BELKIN_VIDEOBUS_II }, - { USB_DEVICE(0x050d, 0x0207), .driver_info = BELKIN_VIDEOBUS }, - { USB_DEVICE(0x050d, 0x0208), .driver_info = BELKIN_USB_VIDEOBUS_II }, - { USB_DEVICE(0x0571, 0x0002), .driver_info = ECHOFX_INTERVIEW_LITE }, - { USB_DEVICE(0x0573, 0x0003), .driver_info = USBGEAR_USBG_V1 }, - { USB_DEVICE(0x0573, 0x0400), .driver_info = D_LINK_V100 }, - { USB_DEVICE(0x0573, 0x2000), .driver_info = X10_USB_CAMERA }, - { USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG }, - { USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN }, - { USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH }, - { USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM }, - { USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM }, - { USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM }, - { USB_DEVICE(0x0573, 0x4550), .driver_info = ZT_721 }, - { USB_DEVICE(0x0573, 0x4d00), .driver_info = HPG_WINTV_NTSC_MN }, - { USB_DEVICE(0x0573, 0x4d01), .driver_info = HPG_WINTV_PAL_BG }, - { USB_DEVICE(0x0573, 0x4d02), .driver_info = HPG_WINTV_PAL_I }, - { USB_DEVICE(0x0573, 0x4d03), .driver_info = HPG_WINTV_PAL_SECAM_L }, - { USB_DEVICE(0x0573, 0x4d04), .driver_info = HPG_WINTV_PAL_D_K }, - { USB_DEVICE(0x0573, 0x4d10), .driver_info = HPG_WINTV_NTSC_FM }, - { USB_DEVICE(0x0573, 0x4d11), .driver_info = HPG_WINTV_PAL_BG_FM }, - { USB_DEVICE(0x0573, 0x4d12), .driver_info = HPG_WINTV_PAL_I_FM }, - { USB_DEVICE(0x0573, 0x4d14), .driver_info = HPG_WINTV_PAL_D_K_FM }, - { USB_DEVICE(0x0573, 0x4d2a), .driver_info = HPG_WINTV_PRO_NTSC_MN }, - { USB_DEVICE(0x0573, 0x4d2b), .driver_info = HPG_WINTV_PRO_NTSC_MN_V2 }, - { USB_DEVICE(0x0573, 0x4d2c), .driver_info = HPG_WINTV_PRO_PAL }, - { USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 }, - { USB_DEVICE(0x0573, 0x4d21), .driver_info = HPG_WINTV_PRO_PAL_BG }, - { USB_DEVICE(0x0573, 0x4d22), .driver_info = HPG_WINTV_PRO_PAL_I }, - { USB_DEVICE(0x0573, 0x4d23), .driver_info = HPG_WINTV_PRO_PAL_SECAM_L }, - { USB_DEVICE(0x0573, 0x4d24), .driver_info = HPG_WINTV_PRO_PAL_D_K }, - { USB_DEVICE(0x0573, 0x4d25), .driver_info = HPG_WINTV_PRO_PAL_SECAM }, - { USB_DEVICE(0x0573, 0x4d26), .driver_info = HPG_WINTV_PRO_PAL_SECAM_V2 }, - { USB_DEVICE(0x0573, 0x4d27), .driver_info = HPG_WINTV_PRO_PAL_BG_V2 }, - { USB_DEVICE(0x0573, 0x4d28), .driver_info = HPG_WINTV_PRO_PAL_BG_D_K }, - { USB_DEVICE(0x0573, 0x4d29), .driver_info = HPG_WINTV_PRO_PAL_I_D_K }, - { USB_DEVICE(0x0573, 0x4d30), .driver_info = HPG_WINTV_PRO_NTSC_MN_FM }, - { USB_DEVICE(0x0573, 0x4d31), .driver_info = HPG_WINTV_PRO_PAL_BG_FM }, - { USB_DEVICE(0x0573, 0x4d32), .driver_info = HPG_WINTV_PRO_PAL_I_FM }, - { USB_DEVICE(0x0573, 0x4d34), .driver_info = HPG_WINTV_PRO_PAL_D_K_FM }, - { USB_DEVICE(0x0573, 0x4d35), .driver_info = HPG_WINTV_PRO_TEMIC_PAL_FM }, - { USB_DEVICE(0x0573, 0x4d36), .driver_info = HPG_WINTV_PRO_TEMIC_PAL_BG_FM }, - { USB_DEVICE(0x0573, 0x4d37), .driver_info = HPG_WINTV_PRO_PAL_FM }, - { USB_DEVICE(0x0573, 0x4d38), .driver_info = HPG_WINTV_PRO_NTSC_MN_FM_V2 }, - { USB_DEVICE(0x0768, 0x0006), .driver_info = CAMTEL_TVB330 }, - { USB_DEVICE(0x07d0, 0x0001), .driver_info = DIGITAL_VIDEO_CREATOR_I }, - { USB_DEVICE(0x07d0, 0x0002), .driver_info = GLOBAL_VILLAGE_GV_007_NTSC }, - { USB_DEVICE(0x07d0, 0x0003), .driver_info = DAZZLE_DVC_50_REV_1_NTSC }, - { USB_DEVICE(0x07d0, 0x0004), .driver_info = DAZZLE_DVC_80_REV_1_PAL }, - { USB_DEVICE(0x07d0, 0x0005), .driver_info = DAZZLE_DVC_90_REV_1_SECAM }, - { USB_DEVICE(0x07f8, 0x9104), .driver_info = ESKAPE_LABS_MYTV2GO }, - { USB_DEVICE(0x2304, 0x010d), .driver_info = PINNA_PCTV_USB_PAL }, - { USB_DEVICE(0x2304, 0x0109), .driver_info = PINNA_PCTV_USB_SECAM }, - { USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM }, - { USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB }, - { USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM }, - { USB_DEVICE(0x2304, 0x0113), - .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 }, - { USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 }, - { USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 }, - { USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 }, - { USB_DEVICE(0x2304, 0x0300), .driver_info = PINNA_LINX_VD_IN_CAB_NTSC }, - { USB_DEVICE(0x2304, 0x0301), .driver_info = PINNA_LINX_VD_IN_CAB_PAL }, - { USB_DEVICE(0x2304, 0x0419), .driver_info = PINNA_PCTV_BUNGEE_PAL_FM }, - { USB_DEVICE(0x2400, 0x4200), .driver_info = HPG_WINTV }, - { }, /* terminate list */ -}; - -MODULE_DEVICE_TABLE(usb, usbvision_table); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-cards.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-cards.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-cards.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-cards.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -#define XANBOO 0 -#define BELKIN_VIDEOBUS_II 1 -#define BELKIN_VIDEOBUS 2 -#define BELKIN_USB_VIDEOBUS_II 3 -#define ECHOFX_INTERVIEW_LITE 4 -#define USBGEAR_USBG_V1 5 -#define D_LINK_V100 6 -#define X10_USB_CAMERA 7 -#define HPG_WINTV_LIVE_PAL_BG 8 -#define HPG_WINTV_LIVE_PRO_NTSC_MN 9 -#define ZORAN_PMD_NOGATECH 10 -#define NOGATECH_USB_TV_NTSC_FM 11 -#define PNY_USB_TV_NTSC_FM 12 -#define PV_PLAYTV_USB_PRO_PAL_FM 13 -#define ZT_721 14 -#define HPG_WINTV_NTSC_MN 15 -#define HPG_WINTV_PAL_BG 16 -#define HPG_WINTV_PAL_I 17 -#define HPG_WINTV_PAL_SECAM_L 18 -#define HPG_WINTV_PAL_D_K 19 -#define HPG_WINTV_NTSC_FM 20 -#define HPG_WINTV_PAL_BG_FM 21 -#define HPG_WINTV_PAL_I_FM 22 -#define HPG_WINTV_PAL_D_K_FM 23 -#define HPG_WINTV_PRO_NTSC_MN 24 -#define HPG_WINTV_PRO_NTSC_MN_V2 25 -#define HPG_WINTV_PRO_PAL 26 -#define HPG_WINTV_PRO_NTSC_MN_V3 27 -#define HPG_WINTV_PRO_PAL_BG 28 -#define HPG_WINTV_PRO_PAL_I 29 -#define HPG_WINTV_PRO_PAL_SECAM_L 30 -#define HPG_WINTV_PRO_PAL_D_K 31 -#define HPG_WINTV_PRO_PAL_SECAM 32 -#define HPG_WINTV_PRO_PAL_SECAM_V2 33 -#define HPG_WINTV_PRO_PAL_BG_V2 34 -#define HPG_WINTV_PRO_PAL_BG_D_K 35 -#define HPG_WINTV_PRO_PAL_I_D_K 36 -#define HPG_WINTV_PRO_NTSC_MN_FM 37 -#define HPG_WINTV_PRO_PAL_BG_FM 38 -#define HPG_WINTV_PRO_PAL_I_FM 39 -#define HPG_WINTV_PRO_PAL_D_K_FM 40 -#define HPG_WINTV_PRO_TEMIC_PAL_FM 41 -#define HPG_WINTV_PRO_TEMIC_PAL_BG_FM 42 -#define HPG_WINTV_PRO_PAL_FM 43 -#define HPG_WINTV_PRO_NTSC_MN_FM_V2 44 -#define CAMTEL_TVB330 45 -#define DIGITAL_VIDEO_CREATOR_I 46 -#define GLOBAL_VILLAGE_GV_007_NTSC 47 -#define DAZZLE_DVC_50_REV_1_NTSC 48 -#define DAZZLE_DVC_80_REV_1_PAL 49 -#define DAZZLE_DVC_90_REV_1_SECAM 50 -#define ESKAPE_LABS_MYTV2GO 51 -#define PINNA_PCTV_USB_PAL 52 -#define PINNA_PCTV_USB_SECAM 53 -#define PINNA_PCTV_USB_PAL_FM 54 -#define MIRO_PCTV_USB 55 -#define PINNA_PCTV_USB_NTSC_FM 56 -#define PINNA_PCTV_USB_PAL_FM_V2 57 -#define PINNA_PCTV_USB_NTSC_FM_V2 58 -#define PINNA_PCTV_USB_PAL_FM_V3 59 -#define PINNA_LINX_VD_IN_CAB_NTSC 60 -#define PINNA_LINX_VD_IN_CAB_PAL 61 -#define PINNA_PCTV_BUNGEE_PAL_FM 62 -#define HPG_WINTV 63 -#define PINNA_PCTV_USB_NTSC_FM_V3 64 - -extern const int usbvision_device_data_size; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2541 +0,0 @@ -/* - * usbvision-core.c - driver for NT100x USB video capture devices - * - * - * Copyright (c) 1999-2005 Joerg Heckenbach - * Dwaine Garden - * - * This module is part of usbvision driver project. - * Updates to driver completed by Dwaine P. Garden - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "usbvision.h" - -static unsigned int core_debug; -module_param(core_debug, int, 0644); -MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); - -static unsigned int force_testpattern; -module_param(force_testpattern, int, 0644); -MODULE_PARM_DESC(force_testpattern, "enable test pattern display [core]"); - -static int adjust_compression = 1; /* Set the compression to be adaptive */ -module_param(adjust_compression, int, 0444); -MODULE_PARM_DESC(adjust_compression, " Set the ADPCM compression for the device. Default: 1 (On)"); - -/* To help people with Black and White output with using s-video input. - * Some cables and input device are wired differently. */ -static int switch_svideo_input; -module_param(switch_svideo_input, int, 0444); -MODULE_PARM_DESC(switch_svideo_input, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)"); - -static unsigned int adjust_x_offset = -1; -module_param(adjust_x_offset, int, 0644); -MODULE_PARM_DESC(adjust_x_offset, "adjust X offset display [core]"); - -static unsigned int adjust_y_offset = -1; -module_param(adjust_y_offset, int, 0644); -MODULE_PARM_DESC(adjust_y_offset, "adjust Y offset display [core]"); - - -#define ENABLE_HEXDUMP 0 /* Enable if you need it */ - - -#ifdef USBVISION_DEBUG - #define PDEBUG(level, fmt, args...) { \ - if (core_debug & (level)) \ - printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \ - __func__, __LINE__ , ## args); \ - } -#else - #define PDEBUG(level, fmt, args...) do {} while (0) -#endif - -#define DBG_HEADER (1 << 0) -#define DBG_IRQ (1 << 1) -#define DBG_ISOC (1 << 2) -#define DBG_PARSE (1 << 3) -#define DBG_SCRATCH (1 << 4) -#define DBG_FUNC (1 << 5) - -static const int max_imgwidth = MAX_FRAME_WIDTH; -static const int max_imgheight = MAX_FRAME_HEIGHT; -static const int min_imgwidth = MIN_FRAME_WIDTH; -static const int min_imgheight = MIN_FRAME_HEIGHT; - -/* The value of 'scratch_buf_size' affects quality of the picture - * in many ways. Shorter buffers may cause loss of data when client - * is too slow. Larger buffers are memory-consuming and take longer - * to work with. This setting can be adjusted, but the default value - * should be OK for most desktop users. - */ -#define DEFAULT_SCRATCH_BUF_SIZE (0x20000) /* 128kB memory scratch buffer */ -static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE; - -/* Function prototypes */ -static int usbvision_request_intra(struct usb_usbvision *usbvision); -static int usbvision_unrequest_intra(struct usb_usbvision *usbvision); -static int usbvision_adjust_compression(struct usb_usbvision *usbvision); -static int usbvision_measure_bandwidth(struct usb_usbvision *usbvision); - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -/* - * Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ - -static void *usbvision_rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - -static void usbvision_rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - size = PAGE_ALIGN(size); - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vfree(mem); -} - - -#if ENABLE_HEXDUMP -static void usbvision_hexdump(const unsigned char *data, int len) -{ - char tmp[80]; - int i, k; - - for (i = k = 0; len > 0; i++, len--) { - if (i > 0 && (i % 16 == 0)) { - printk("%s\n", tmp); - k = 0; - } - k += sprintf(&tmp[k], "%02x ", data[i]); - } - if (k > 0) - printk(KERN_CONT "%s\n", tmp); -} -#endif - -/******************************** - * scratch ring buffer handling - ********************************/ -static int scratch_len(struct usb_usbvision *usbvision) /* This returns the amount of data actually in the buffer */ -{ - int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr; - - if (len < 0) - len += scratch_buf_size; - PDEBUG(DBG_SCRATCH, "scratch_len() = %d\n", len); - - return len; -} - - -/* This returns the free space left in the buffer */ -static int scratch_free(struct usb_usbvision *usbvision) -{ - int free = usbvision->scratch_read_ptr - usbvision->scratch_write_ptr; - if (free <= 0) - free += scratch_buf_size; - if (free) { - free -= 1; /* at least one byte in the buffer must */ - /* left blank, otherwise there is no chance to differ between full and empty */ - } - PDEBUG(DBG_SCRATCH, "return %d\n", free); - - return free; -} - - -/* This puts data into the buffer */ -static int scratch_put(struct usb_usbvision *usbvision, unsigned char *data, - int len) -{ - int len_part; - - if (usbvision->scratch_write_ptr + len < scratch_buf_size) { - memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len); - usbvision->scratch_write_ptr += len; - } else { - len_part = scratch_buf_size - usbvision->scratch_write_ptr; - memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len_part); - if (len == len_part) { - usbvision->scratch_write_ptr = 0; /* just set write_ptr to zero */ - } else { - memcpy(usbvision->scratch, data + len_part, len - len_part); - usbvision->scratch_write_ptr = len - len_part; - } - } - - PDEBUG(DBG_SCRATCH, "len=%d, new write_ptr=%d\n", len, usbvision->scratch_write_ptr); - - return len; -} - -/* This marks the write_ptr as position of new frame header */ -static void scratch_mark_header(struct usb_usbvision *usbvision) -{ - PDEBUG(DBG_SCRATCH, "header at write_ptr=%d\n", usbvision->scratch_headermarker_write_ptr); - - usbvision->scratch_headermarker[usbvision->scratch_headermarker_write_ptr] = - usbvision->scratch_write_ptr; - usbvision->scratch_headermarker_write_ptr += 1; - usbvision->scratch_headermarker_write_ptr %= USBVISION_NUM_HEADERMARKER; -} - -/* This gets data from the buffer at the given "ptr" position */ -static int scratch_get_extra(struct usb_usbvision *usbvision, - unsigned char *data, int *ptr, int len) -{ - int len_part; - - if (*ptr + len < scratch_buf_size) { - memcpy(data, usbvision->scratch + *ptr, len); - *ptr += len; - } else { - len_part = scratch_buf_size - *ptr; - memcpy(data, usbvision->scratch + *ptr, len_part); - if (len == len_part) { - *ptr = 0; /* just set the y_ptr to zero */ - } else { - memcpy(data + len_part, usbvision->scratch, len - len_part); - *ptr = len - len_part; - } - } - - PDEBUG(DBG_SCRATCH, "len=%d, new ptr=%d\n", len, *ptr); - - return len; -} - - -/* This sets the scratch extra read pointer */ -static void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr, - int len) -{ - *ptr = (usbvision->scratch_read_ptr + len) % scratch_buf_size; - - PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr); -} - - -/* This increments the scratch extra read pointer */ -static void scratch_inc_extra_ptr(int *ptr, int len) -{ - *ptr = (*ptr + len) % scratch_buf_size; - - PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr); -} - - -/* This gets data from the buffer */ -static int scratch_get(struct usb_usbvision *usbvision, unsigned char *data, - int len) -{ - int len_part; - - if (usbvision->scratch_read_ptr + len < scratch_buf_size) { - memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len); - usbvision->scratch_read_ptr += len; - } else { - len_part = scratch_buf_size - usbvision->scratch_read_ptr; - memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len_part); - if (len == len_part) { - usbvision->scratch_read_ptr = 0; /* just set the read_ptr to zero */ - } else { - memcpy(data + len_part, usbvision->scratch, len - len_part); - usbvision->scratch_read_ptr = len - len_part; - } - } - - PDEBUG(DBG_SCRATCH, "len=%d, new read_ptr=%d\n", len, usbvision->scratch_read_ptr); - - return len; -} - - -/* This sets read pointer to next header and returns it */ -static int scratch_get_header(struct usb_usbvision *usbvision, - struct usbvision_frame_header *header) -{ - int err_code = 0; - - PDEBUG(DBG_SCRATCH, "from read_ptr=%d", usbvision->scratch_headermarker_read_ptr); - - while (usbvision->scratch_headermarker_write_ptr - - usbvision->scratch_headermarker_read_ptr != 0) { - usbvision->scratch_read_ptr = - usbvision->scratch_headermarker[usbvision->scratch_headermarker_read_ptr]; - usbvision->scratch_headermarker_read_ptr += 1; - usbvision->scratch_headermarker_read_ptr %= USBVISION_NUM_HEADERMARKER; - scratch_get(usbvision, (unsigned char *)header, USBVISION_HEADER_LENGTH); - if ((header->magic_1 == USBVISION_MAGIC_1) - && (header->magic_2 == USBVISION_MAGIC_2) - && (header->header_length == USBVISION_HEADER_LENGTH)) { - err_code = USBVISION_HEADER_LENGTH; - header->frame_width = header->frame_width_lo + (header->frame_width_hi << 8); - header->frame_height = header->frame_height_lo + (header->frame_height_hi << 8); - break; - } - } - - return err_code; -} - - -/* This removes len bytes of old data from the buffer */ -static void scratch_rm_old(struct usb_usbvision *usbvision, int len) -{ - usbvision->scratch_read_ptr += len; - usbvision->scratch_read_ptr %= scratch_buf_size; - PDEBUG(DBG_SCRATCH, "read_ptr is now %d\n", usbvision->scratch_read_ptr); -} - - -/* This resets the buffer - kills all data in it too */ -static void scratch_reset(struct usb_usbvision *usbvision) -{ - PDEBUG(DBG_SCRATCH, "\n"); - - usbvision->scratch_read_ptr = 0; - usbvision->scratch_write_ptr = 0; - usbvision->scratch_headermarker_read_ptr = 0; - usbvision->scratch_headermarker_write_ptr = 0; - usbvision->isocstate = isoc_state_no_frame; -} - -int usbvision_scratch_alloc(struct usb_usbvision *usbvision) -{ - usbvision->scratch = vmalloc_32(scratch_buf_size); - scratch_reset(usbvision); - if (usbvision->scratch == NULL) { - dev_err(&usbvision->dev->dev, - "%s: unable to allocate %d bytes for scratch\n", - __func__, scratch_buf_size); - return -ENOMEM; - } - return 0; -} - -void usbvision_scratch_free(struct usb_usbvision *usbvision) -{ - vfree(usbvision->scratch); - usbvision->scratch = NULL; -} - -/* - * usbvision_testpattern() - * - * Procedure forms a test pattern (yellow grid on blue background). - * - * Parameters: - * fullframe: if TRUE then entire frame is filled, otherwise the procedure - * continues from the current scanline. - * pmode 0: fill the frame with solid blue color (like on VCR or TV) - * 1: Draw a colored grid - * - */ -static void usbvision_testpattern(struct usb_usbvision *usbvision, - int fullframe, int pmode) -{ - static const char proc[] = "usbvision_testpattern"; - struct usbvision_frame *frame; - unsigned char *f; - int num_cell = 0; - int scan_length = 0; - static int num_pass; - - if (usbvision == NULL) { - printk(KERN_ERR "%s: usbvision == NULL\n", proc); - return; - } - if (usbvision->cur_frame == NULL) { - printk(KERN_ERR "%s: usbvision->cur_frame is NULL.\n", proc); - return; - } - - /* Grab the current frame */ - frame = usbvision->cur_frame; - - /* Optionally start at the beginning */ - if (fullframe) { - frame->curline = 0; - frame->scanlength = 0; - } - - /* Form every scan line */ - for (; frame->curline < frame->frmheight; frame->curline++) { - int i; - - f = frame->data + (usbvision->curwidth * 3 * frame->curline); - for (i = 0; i < usbvision->curwidth; i++) { - unsigned char cb = 0x80; - unsigned char cg = 0; - unsigned char cr = 0; - - if (pmode == 1) { - if (frame->curline % 32 == 0) - cb = 0, cg = cr = 0xFF; - else if (i % 32 == 0) { - if (frame->curline % 32 == 1) - num_cell++; - cb = 0, cg = cr = 0xFF; - } else { - cb = - ((num_cell * 7) + - num_pass) & 0xFF; - cg = - ((num_cell * 5) + - num_pass * 2) & 0xFF; - cr = - ((num_cell * 3) + - num_pass * 3) & 0xFF; - } - } else { - /* Just the blue screen */ - } - - *f++ = cb; - *f++ = cg; - *f++ = cr; - scan_length += 3; - } - } - - frame->grabstate = frame_state_done; - frame->scanlength += scan_length; - ++num_pass; -} - -/* - * usbvision_decompress_alloc() - * - * allocates intermediate buffer for decompression - */ -int usbvision_decompress_alloc(struct usb_usbvision *usbvision) -{ - int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2; - - usbvision->intra_frame_buffer = vmalloc_32(IFB_size); - if (usbvision->intra_frame_buffer == NULL) { - dev_err(&usbvision->dev->dev, - "%s: unable to allocate %d for compr. frame buffer\n", - __func__, IFB_size); - return -ENOMEM; - } - return 0; -} - -/* - * usbvision_decompress_free() - * - * frees intermediate buffer for decompression - */ -void usbvision_decompress_free(struct usb_usbvision *usbvision) -{ - vfree(usbvision->intra_frame_buffer); - usbvision->intra_frame_buffer = NULL; - -} - -/************************************************************ - * Here comes the data parsing stuff that is run as interrupt - ************************************************************/ -/* - * usbvision_find_header() - * - * Locate one of supported header markers in the scratch buffer. - */ -static enum parse_state usbvision_find_header(struct usb_usbvision *usbvision) -{ - struct usbvision_frame *frame; - int found_header = 0; - - frame = usbvision->cur_frame; - - while (scratch_get_header(usbvision, &frame->isoc_header) == USBVISION_HEADER_LENGTH) { - /* found header in scratch */ - PDEBUG(DBG_HEADER, "found header: 0x%02x%02x %d %d %d %d %#x 0x%02x %u %u", - frame->isoc_header.magic_2, - frame->isoc_header.magic_1, - frame->isoc_header.header_length, - frame->isoc_header.frame_num, - frame->isoc_header.frame_phase, - frame->isoc_header.frame_latency, - frame->isoc_header.data_format, - frame->isoc_header.format_param, - frame->isoc_header.frame_width, - frame->isoc_header.frame_height); - - if (usbvision->request_intra) { - if (frame->isoc_header.format_param & 0x80) { - found_header = 1; - usbvision->last_isoc_frame_num = -1; /* do not check for lost frames this time */ - usbvision_unrequest_intra(usbvision); - break; - } - } else { - found_header = 1; - break; - } - } - - if (found_header) { - frame->frmwidth = frame->isoc_header.frame_width * usbvision->stretch_width; - frame->frmheight = frame->isoc_header.frame_height * usbvision->stretch_height; - frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth) >> 3; - } else { /* no header found */ - PDEBUG(DBG_HEADER, "skipping scratch data, no header"); - scratch_reset(usbvision); - return parse_state_end_parse; - } - - /* found header */ - if (frame->isoc_header.data_format == ISOC_MODE_COMPRESS) { - /* check isoc_header.frame_num for lost frames */ - if (usbvision->last_isoc_frame_num >= 0) { - if (((usbvision->last_isoc_frame_num + 1) % 32) != frame->isoc_header.frame_num) { - /* unexpected frame drop: need to request new intra frame */ - PDEBUG(DBG_HEADER, "Lost frame before %d on USB", frame->isoc_header.frame_num); - usbvision_request_intra(usbvision); - return parse_state_next_frame; - } - } - usbvision->last_isoc_frame_num = frame->isoc_header.frame_num; - } - usbvision->header_count++; - frame->scanstate = scan_state_lines; - frame->curline = 0; - - if (force_testpattern) { - usbvision_testpattern(usbvision, 1, 1); - return parse_state_next_frame; - } - return parse_state_continue; -} - -static enum parse_state usbvision_parse_lines_422(struct usb_usbvision *usbvision, - long *pcopylen) -{ - volatile struct usbvision_frame *frame; - unsigned char *f; - int len; - int i; - unsigned char yuyv[4] = { 180, 128, 10, 128 }; /* YUV components */ - unsigned char rv, gv, bv; /* RGB components */ - int clipmask_index, bytes_per_pixel; - int stretch_bytes, clipmask_add; - - frame = usbvision->cur_frame; - f = frame->data + (frame->v4l2_linesize * frame->curline); - - /* Make sure there's enough data for the entire line */ - len = (frame->isoc_header.frame_width * 2) + 5; - if (scratch_len(usbvision) < len) { - PDEBUG(DBG_PARSE, "out of data in line %d, need %u.\n", frame->curline, len); - return parse_state_out; - } - - if ((frame->curline + 1) >= frame->frmheight) - return parse_state_next_frame; - - bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; - stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel; - clipmask_index = frame->curline * MAX_FRAME_WIDTH; - clipmask_add = usbvision->stretch_width; - - for (i = 0; i < frame->frmwidth; i += (2 * usbvision->stretch_width)) { - scratch_get(usbvision, &yuyv[0], 4); - - if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { - *f++ = yuyv[0]; /* Y */ - *f++ = yuyv[3]; /* U */ - } else { - YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv); - switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x07 & (gv >> 3)) | - (0xF8 & bv); - break; - case V4L2_PIX_FMT_RGB24: - *f++ = rv; - *f++ = gv; - *f++ = bv; - break; - case V4L2_PIX_FMT_RGB32: - *f++ = rv; - *f++ = gv; - *f++ = bv; - f++; - break; - case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x03 & (gv >> 3)) | - (0x7C & (bv << 2)); - break; - } - } - clipmask_index += clipmask_add; - f += stretch_bytes; - - if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { - *f++ = yuyv[2]; /* Y */ - *f++ = yuyv[1]; /* V */ - } else { - YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv); - switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x07 & (gv >> 3)) | - (0xF8 & bv); - break; - case V4L2_PIX_FMT_RGB24: - *f++ = rv; - *f++ = gv; - *f++ = bv; - break; - case V4L2_PIX_FMT_RGB32: - *f++ = rv; - *f++ = gv; - *f++ = bv; - f++; - break; - case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x03 & (gv >> 3)) | - (0x7C & (bv << 2)); - break; - } - } - clipmask_index += clipmask_add; - f += stretch_bytes; - } - - frame->curline += usbvision->stretch_height; - *pcopylen += frame->v4l2_linesize * usbvision->stretch_height; - - if (frame->curline >= frame->frmheight) - return parse_state_next_frame; - return parse_state_continue; -} - -/* The decompression routine */ -static int usbvision_decompress(struct usb_usbvision *usbvision, unsigned char *compressed, - unsigned char *decompressed, int *start_pos, - int *block_typestart_pos, int len) -{ - int rest_pixel, idx, max_pos, pos, extra_pos, block_len, block_type_pos, block_type_len; - unsigned char block_byte, block_code, block_type, block_type_byte, integrator; - - integrator = 0; - pos = *start_pos; - block_type_pos = *block_typestart_pos; - max_pos = 396; /* pos + len; */ - extra_pos = pos; - block_len = 0; - block_byte = 0; - block_code = 0; - block_type = 0; - block_type_byte = 0; - block_type_len = 0; - rest_pixel = len; - - for (idx = 0; idx < len; idx++) { - if (block_len == 0) { - if (block_type_len == 0) { - block_type_byte = compressed[block_type_pos]; - block_type_pos++; - block_type_len = 4; - } - block_type = (block_type_byte & 0xC0) >> 6; - - /* statistic: */ - usbvision->compr_block_types[block_type]++; - - pos = extra_pos; - if (block_type == 0) { - if (rest_pixel >= 24) { - idx += 23; - rest_pixel -= 24; - integrator = decompressed[idx]; - } else { - idx += rest_pixel - 1; - rest_pixel = 0; - } - } else { - block_code = compressed[pos]; - pos++; - if (rest_pixel >= 24) - block_len = 24; - else - block_len = rest_pixel; - rest_pixel -= block_len; - extra_pos = pos + (block_len / 4); - } - block_type_byte <<= 2; - block_type_len -= 1; - } - if (block_len > 0) { - if ((block_len % 4) == 0) { - block_byte = compressed[pos]; - pos++; - } - if (block_type == 1) /* inter Block */ - integrator = decompressed[idx]; - switch (block_byte & 0xC0) { - case 0x03 << 6: - integrator += compressed[extra_pos]; - extra_pos++; - break; - case 0x02 << 6: - integrator += block_code; - break; - case 0x00: - integrator -= block_code; - break; - } - decompressed[idx] = integrator; - block_byte <<= 2; - block_len -= 1; - } - } - *start_pos = extra_pos; - *block_typestart_pos = block_type_pos; - return idx; -} - - -/* - * usbvision_parse_compress() - * - * Parse compressed frame from the scratch buffer, put - * decoded RGB value into the current frame buffer and add the written - * number of bytes (RGB) to the *pcopylen. - * - */ -static enum parse_state usbvision_parse_compress(struct usb_usbvision *usbvision, - long *pcopylen) -{ -#define USBVISION_STRIP_MAGIC 0x5A -#define USBVISION_STRIP_LEN_MAX 400 -#define USBVISION_STRIP_HEADER_LEN 3 - - struct usbvision_frame *frame; - unsigned char *f, *u = NULL, *v = NULL; - unsigned char strip_data[USBVISION_STRIP_LEN_MAX]; - unsigned char strip_header[USBVISION_STRIP_HEADER_LEN]; - int idx, idx_end, strip_len, strip_ptr, startblock_pos, block_pos, block_type_pos; - int clipmask_index, bytes_per_pixel, rc; - int image_size; - unsigned char rv, gv, bv; - static unsigned char *Y, *U, *V; - - frame = usbvision->cur_frame; - image_size = frame->frmwidth * frame->frmheight; - if ((frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) || - (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420)) { /* this is a planar format */ - /* ... v4l2_linesize not used here. */ - f = frame->data + (frame->width * frame->curline); - } else - f = frame->data + (frame->v4l2_linesize * frame->curline); - - if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { /* initialise u and v pointers */ - /* get base of u and b planes add halfoffset */ - u = frame->data - + image_size - + (frame->frmwidth >> 1) * frame->curline; - v = u + (image_size >> 1); - } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) { - v = frame->data + image_size + ((frame->curline * (frame->width)) >> 2); - u = v + (image_size >> 2); - } - - if (frame->curline == 0) - usbvision_adjust_compression(usbvision); - - if (scratch_len(usbvision) < USBVISION_STRIP_HEADER_LEN) - return parse_state_out; - - /* get strip header without changing the scratch_read_ptr */ - scratch_set_extra_ptr(usbvision, &strip_ptr, 0); - scratch_get_extra(usbvision, &strip_header[0], &strip_ptr, - USBVISION_STRIP_HEADER_LEN); - - if (strip_header[0] != USBVISION_STRIP_MAGIC) { - /* wrong strip magic */ - usbvision->strip_magic_errors++; - return parse_state_next_frame; - } - - if (frame->curline != (int)strip_header[2]) { - /* line number mismatch error */ - usbvision->strip_line_number_errors++; - } - - strip_len = 2 * (unsigned int)strip_header[1]; - if (strip_len > USBVISION_STRIP_LEN_MAX) { - /* strip overrun */ - /* I think this never happens */ - usbvision_request_intra(usbvision); - } - - if (scratch_len(usbvision) < strip_len) { - /* there is not enough data for the strip */ - return parse_state_out; - } - - if (usbvision->intra_frame_buffer) { - Y = usbvision->intra_frame_buffer + frame->frmwidth * frame->curline; - U = usbvision->intra_frame_buffer + image_size + (frame->frmwidth / 2) * (frame->curline / 2); - V = usbvision->intra_frame_buffer + image_size / 4 * 5 + (frame->frmwidth / 2) * (frame->curline / 2); - } else { - return parse_state_next_frame; - } - - bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; - clipmask_index = frame->curline * MAX_FRAME_WIDTH; - - scratch_get(usbvision, strip_data, strip_len); - - idx_end = frame->frmwidth; - block_type_pos = USBVISION_STRIP_HEADER_LEN; - startblock_pos = block_type_pos + (idx_end - 1) / 96 + (idx_end / 2 - 1) / 96 + 2; - block_pos = startblock_pos; - - usbvision->block_pos = block_pos; - - rc = usbvision_decompress(usbvision, strip_data, Y, &block_pos, &block_type_pos, idx_end); - if (strip_len > usbvision->max_strip_len) - usbvision->max_strip_len = strip_len; - - if (frame->curline % 2) - rc = usbvision_decompress(usbvision, strip_data, V, &block_pos, &block_type_pos, idx_end / 2); - else - rc = usbvision_decompress(usbvision, strip_data, U, &block_pos, &block_type_pos, idx_end / 2); - - if (block_pos > usbvision->comprblock_pos) - usbvision->comprblock_pos = block_pos; - if (block_pos > strip_len) - usbvision->strip_len_errors++; - - for (idx = 0; idx < idx_end; idx++) { - if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { - *f++ = Y[idx]; - *f++ = idx & 0x01 ? U[idx / 2] : V[idx / 2]; - } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) { - *f++ = Y[idx]; - if (idx & 0x01) - *u++ = U[idx >> 1]; - else - *v++ = V[idx >> 1]; - } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) { - *f++ = Y[idx]; - if (!((idx & 0x01) | (frame->curline & 0x01))) { - /* only need do this for 1 in 4 pixels */ - /* intraframe buffer is YUV420 format */ - *u++ = U[idx >> 1]; - *v++ = V[idx >> 1]; - } - } else { - YUV_TO_RGB_BY_THE_BOOK(Y[idx], U[idx / 2], V[idx / 2], rv, gv, bv); - switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_GREY: - *f++ = Y[idx]; - break; - case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x03 & (gv >> 3)) | - (0x7C & (bv << 2)); - break; - case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x07 & (gv >> 3)) | - (0xF8 & bv); - break; - case V4L2_PIX_FMT_RGB24: - *f++ = rv; - *f++ = gv; - *f++ = bv; - break; - case V4L2_PIX_FMT_RGB32: - *f++ = rv; - *f++ = gv; - *f++ = bv; - f++; - break; - } - } - clipmask_index++; - } - /* Deal with non-integer no. of bytes for YUV420P */ - if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420) - *pcopylen += frame->v4l2_linesize; - else - *pcopylen += frame->curline & 0x01 ? frame->v4l2_linesize : frame->v4l2_linesize << 1; - - frame->curline += 1; - - if (frame->curline >= frame->frmheight) - return parse_state_next_frame; - return parse_state_continue; - -} - - -/* - * usbvision_parse_lines_420() - * - * Parse two lines from the scratch buffer, put - * decoded RGB value into the current frame buffer and add the written - * number of bytes (RGB) to the *pcopylen. - * - */ -static enum parse_state usbvision_parse_lines_420(struct usb_usbvision *usbvision, - long *pcopylen) -{ - struct usbvision_frame *frame; - unsigned char *f_even = NULL, *f_odd = NULL; - unsigned int pixel_per_line, block; - int pixel, block_split; - int y_ptr, u_ptr, v_ptr, y_odd_offset; - const int y_block_size = 128; - const int uv_block_size = 64; - const int sub_block_size = 32; - const int y_step[] = { 0, 0, 0, 2 }, y_step_size = 4; - const int uv_step[] = { 0, 0, 0, 4 }, uv_step_size = 4; - unsigned char y[2], u, v; /* YUV components */ - int y_, u_, v_, vb, uvg, ur; - int r_, g_, b_; /* RGB components */ - unsigned char g; - int clipmask_even_index, clipmask_odd_index, bytes_per_pixel; - int clipmask_add, stretch_bytes; - - frame = usbvision->cur_frame; - f_even = frame->data + (frame->v4l2_linesize * frame->curline); - f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height; - - /* Make sure there's enough data for the entire line */ - /* In this mode usbvision transfer 3 bytes for every 2 pixels */ - /* I need two lines to decode the color */ - bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; - stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel; - clipmask_even_index = frame->curline * MAX_FRAME_WIDTH; - clipmask_odd_index = clipmask_even_index + MAX_FRAME_WIDTH; - clipmask_add = usbvision->stretch_width; - pixel_per_line = frame->isoc_header.frame_width; - - if (scratch_len(usbvision) < (int)pixel_per_line * 3) { - /* printk(KERN_DEBUG "out of data, need %d\n", len); */ - return parse_state_out; - } - - if ((frame->curline + 1) >= frame->frmheight) - return parse_state_next_frame; - - block_split = (pixel_per_line%y_block_size) ? 1 : 0; /* are some blocks splitted into different lines? */ - - y_odd_offset = (pixel_per_line / y_block_size) * (y_block_size + uv_block_size) - + block_split * uv_block_size; - - scratch_set_extra_ptr(usbvision, &y_ptr, y_odd_offset); - scratch_set_extra_ptr(usbvision, &u_ptr, y_block_size); - scratch_set_extra_ptr(usbvision, &v_ptr, y_odd_offset - + (4 - block_split) * sub_block_size); - - for (block = 0; block < (pixel_per_line / sub_block_size); block++) { - for (pixel = 0; pixel < sub_block_size; pixel += 2) { - scratch_get(usbvision, &y[0], 2); - scratch_get_extra(usbvision, &u, &u_ptr, 1); - scratch_get_extra(usbvision, &v, &v_ptr, 1); - - /* I don't use the YUV_TO_RGB macro for better performance */ - v_ = v - 128; - u_ = u - 128; - vb = 132252 * v_; - uvg = -53281 * u_ - 25625 * v_; - ur = 104595 * u_; - - if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { - *f_even++ = y[0]; - *f_even++ = v; - } else { - y_ = 76284 * (y[0] - 16); - - b_ = (y_ + vb) >> 16; - g_ = (y_ + uvg) >> 16; - r_ = (y_ + ur) >> 16; - - switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_even++ = - (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_even++ = - (0x07 & (g >> 3)) | - (0xF8 & LIMIT_RGB(b_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_even++ = LIMIT_RGB(r_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(b_); - break; - case V4L2_PIX_FMT_RGB32: - *f_even++ = LIMIT_RGB(r_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(b_); - f_even++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_even++ = (0x03 & (g >> 3)) | - (0x7C & (LIMIT_RGB(b_) << 2)); - break; - } - } - clipmask_even_index += clipmask_add; - f_even += stretch_bytes; - - if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { - *f_even++ = y[1]; - *f_even++ = u; - } else { - y_ = 76284 * (y[1] - 16); - - b_ = (y_ + vb) >> 16; - g_ = (y_ + uvg) >> 16; - r_ = (y_ + ur) >> 16; - - switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_even++ = - (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_even++ = - (0x07 & (g >> 3)) | - (0xF8 & LIMIT_RGB(b_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_even++ = LIMIT_RGB(r_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(b_); - break; - case V4L2_PIX_FMT_RGB32: - *f_even++ = LIMIT_RGB(r_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(b_); - f_even++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_even++ = (0x03 & (g >> 3)) | - (0x7C & (LIMIT_RGB(b_) << 2)); - break; - } - } - clipmask_even_index += clipmask_add; - f_even += stretch_bytes; - - scratch_get_extra(usbvision, &y[0], &y_ptr, 2); - - if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { - *f_odd++ = y[0]; - *f_odd++ = v; - } else { - y_ = 76284 * (y[0] - 16); - - b_ = (y_ + vb) >> 16; - g_ = (y_ + uvg) >> 16; - r_ = (y_ + ur) >> 16; - - switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_odd++ = - (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_odd++ = - (0x07 & (g >> 3)) | - (0xF8 & LIMIT_RGB(b_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_odd++ = LIMIT_RGB(r_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(b_); - break; - case V4L2_PIX_FMT_RGB32: - *f_odd++ = LIMIT_RGB(r_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(b_); - f_odd++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_odd++ = (0x03 & (g >> 3)) | - (0x7C & (LIMIT_RGB(b_) << 2)); - break; - } - } - clipmask_odd_index += clipmask_add; - f_odd += stretch_bytes; - - if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { - *f_odd++ = y[1]; - *f_odd++ = u; - } else { - y_ = 76284 * (y[1] - 16); - - b_ = (y_ + vb) >> 16; - g_ = (y_ + uvg) >> 16; - r_ = (y_ + ur) >> 16; - - switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_odd++ = - (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_odd++ = - (0x07 & (g >> 3)) | - (0xF8 & LIMIT_RGB(b_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_odd++ = LIMIT_RGB(r_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(b_); - break; - case V4L2_PIX_FMT_RGB32: - *f_odd++ = LIMIT_RGB(r_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(b_); - f_odd++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_odd++ = (0x03 & (g >> 3)) | - (0x7C & (LIMIT_RGB(b_) << 2)); - break; - } - } - clipmask_odd_index += clipmask_add; - f_odd += stretch_bytes; - } - - scratch_rm_old(usbvision, y_step[block % y_step_size] * sub_block_size); - scratch_inc_extra_ptr(&y_ptr, y_step[(block + 2 * block_split) % y_step_size] - * sub_block_size); - scratch_inc_extra_ptr(&u_ptr, uv_step[block % uv_step_size] - * sub_block_size); - scratch_inc_extra_ptr(&v_ptr, uv_step[(block + 2 * block_split) % uv_step_size] - * sub_block_size); - } - - scratch_rm_old(usbvision, pixel_per_line * 3 / 2 - + block_split * sub_block_size); - - frame->curline += 2 * usbvision->stretch_height; - *pcopylen += frame->v4l2_linesize * 2 * usbvision->stretch_height; - - if (frame->curline >= frame->frmheight) - return parse_state_next_frame; - return parse_state_continue; -} - -/* - * usbvision_parse_data() - * - * Generic routine to parse the scratch buffer. It employs either - * usbvision_find_header() or usbvision_parse_lines() to do most - * of work. - * - */ -static void usbvision_parse_data(struct usb_usbvision *usbvision) -{ - struct usbvision_frame *frame; - enum parse_state newstate; - long copylen = 0; - unsigned long lock_flags; - - frame = usbvision->cur_frame; - - PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision)); - - while (1) { - newstate = parse_state_out; - if (scratch_len(usbvision)) { - if (frame->scanstate == scan_state_scanning) { - newstate = usbvision_find_header(usbvision); - } else if (frame->scanstate == scan_state_lines) { - if (usbvision->isoc_mode == ISOC_MODE_YUV420) - newstate = usbvision_parse_lines_420(usbvision, ©len); - else if (usbvision->isoc_mode == ISOC_MODE_YUV422) - newstate = usbvision_parse_lines_422(usbvision, ©len); - else if (usbvision->isoc_mode == ISOC_MODE_COMPRESS) - newstate = usbvision_parse_compress(usbvision, ©len); - } - } - if (newstate == parse_state_continue) - continue; - if ((newstate == parse_state_next_frame) || (newstate == parse_state_out)) - break; - return; /* parse_state_end_parse */ - } - - if (newstate == parse_state_next_frame) { - frame->grabstate = frame_state_done; - do_gettimeofday(&(frame->timestamp)); - frame->sequence = usbvision->frame_num; - - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - list_move_tail(&(frame->frame), &usbvision->outqueue); - usbvision->cur_frame = NULL; - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - - usbvision->frame_num++; - - /* This will cause the process to request another frame. */ - if (waitqueue_active(&usbvision->wait_frame)) { - PDEBUG(DBG_PARSE, "Wake up !"); - wake_up_interruptible(&usbvision->wait_frame); - } - } else { - frame->grabstate = frame_state_grabbing; - } - - /* Update the frame's uncompressed length. */ - frame->scanlength += copylen; -} - - -/* - * Make all of the blocks of data contiguous - */ -static int usbvision_compress_isochronous(struct usb_usbvision *usbvision, - struct urb *urb) -{ - unsigned char *packet_data; - int i, totlen = 0; - - for (i = 0; i < urb->number_of_packets; i++) { - int packet_len = urb->iso_frame_desc[i].actual_length; - int packet_stat = urb->iso_frame_desc[i].status; - - packet_data = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - /* Detect and ignore errored packets */ - if (packet_stat) { /* packet_stat != 0 ????????????? */ - PDEBUG(DBG_ISOC, "data error: [%d] len=%d, status=%X", i, packet_len, packet_stat); - usbvision->isoc_err_count++; - continue; - } - - /* Detect and ignore empty packets */ - if (packet_len < 0) { - PDEBUG(DBG_ISOC, "error packet [%d]", i); - usbvision->isoc_skip_count++; - continue; - } else if (packet_len == 0) { /* Frame end ????? */ - PDEBUG(DBG_ISOC, "null packet [%d]", i); - usbvision->isocstate = isoc_state_no_frame; - usbvision->isoc_skip_count++; - continue; - } else if (packet_len > usbvision->isoc_packet_size) { - PDEBUG(DBG_ISOC, "packet[%d] > isoc_packet_size", i); - usbvision->isoc_skip_count++; - continue; - } - - PDEBUG(DBG_ISOC, "packet ok [%d] len=%d", i, packet_len); - - if (usbvision->isocstate == isoc_state_no_frame) { /* new frame begins */ - usbvision->isocstate = isoc_state_in_frame; - scratch_mark_header(usbvision); - usbvision_measure_bandwidth(usbvision); - PDEBUG(DBG_ISOC, "packet with header"); - } - - /* - * If usbvision continues to feed us with data but there is no - * consumption (if, for example, V4L client fell asleep) we - * may overflow the buffer. We have to move old data over to - * free room for new data. This is bad for old data. If we - * just drop new data then it's bad for new data... choose - * your favorite evil here. - */ - if (scratch_free(usbvision) < packet_len) { - usbvision->scratch_ovf_count++; - PDEBUG(DBG_ISOC, "scratch buf overflow! scr_len: %d, n: %d", - scratch_len(usbvision), packet_len); - scratch_rm_old(usbvision, packet_len - scratch_free(usbvision)); - } - - /* Now we know that there is enough room in scratch buffer */ - scratch_put(usbvision, packet_data, packet_len); - totlen += packet_len; - usbvision->isoc_data_count += packet_len; - usbvision->isoc_packet_count++; - } -#if ENABLE_HEXDUMP - if (totlen > 0) { - static int foo; - - if (foo < 1) { - printk(KERN_DEBUG "+%d.\n", usbvision->scratchlen); - usbvision_hexdump(data0, (totlen > 64) ? 64 : totlen); - ++foo; - } - } -#endif - return totlen; -} - -static void usbvision_isoc_irq(struct urb *urb) -{ - int err_code = 0; - int len; - struct usb_usbvision *usbvision = urb->context; - int i; - unsigned long start_time = jiffies; - struct usbvision_frame **f; - - /* We don't want to do anything if we are about to be removed! */ - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return; - - /* any urb with wrong status is ignored without acknowledgement */ - if (urb->status == -ENOENT) - return; - - f = &usbvision->cur_frame; - - /* Manage streaming interruption */ - if (usbvision->streaming == stream_interrupt) { - usbvision->streaming = stream_idle; - if ((*f)) { - (*f)->grabstate = frame_state_ready; - (*f)->scanstate = scan_state_scanning; - } - PDEBUG(DBG_IRQ, "stream interrupted"); - wake_up_interruptible(&usbvision->wait_stream); - } - - /* Copy the data received into our scratch buffer */ - len = usbvision_compress_isochronous(usbvision, urb); - - usbvision->isoc_urb_count++; - usbvision->urb_length = len; - - if (usbvision->streaming == stream_on) { - /* If we collected enough data let's parse! */ - if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH && - !list_empty(&(usbvision->inqueue))) { - if (!(*f)) { - (*f) = list_entry(usbvision->inqueue.next, - struct usbvision_frame, - frame); - } - usbvision_parse_data(usbvision); - } else { - /* If we don't have a frame - we're current working on, complain */ - PDEBUG(DBG_IRQ, - "received data, but no one needs it"); - scratch_reset(usbvision); - } - } else { - PDEBUG(DBG_IRQ, "received data, but no one needs it"); - scratch_reset(usbvision); - } - - usbvision->time_in_irq += jiffies - start_time; - - for (i = 0; i < USBVISION_URB_FRAMES; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - - urb->status = 0; - urb->dev = usbvision->dev; - err_code = usb_submit_urb(urb, GFP_ATOMIC); - - if (err_code) { - dev_err(&usbvision->dev->dev, - "%s: usb_submit_urb failed: error %d\n", - __func__, err_code); - } - - return; -} - -/*************************************/ -/* Low level usbvision access functions */ -/*************************************/ - -/* - * usbvision_read_reg() - * - * return < 0 -> Error - * >= 0 -> Data - */ - -int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg) -{ - int err_code = 0; - unsigned char buffer[1]; - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -1; - - err_code = usb_control_msg(usbvision->dev, usb_rcvctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, - 0, (__u16) reg, buffer, 1, HZ); - - if (err_code < 0) { - dev_err(&usbvision->dev->dev, - "%s: failed: error %d\n", __func__, err_code); - return err_code; - } - return buffer[0]; -} - -/* - * usbvision_write_reg() - * - * return 1 -> Reg written - * 0 -> usbvision is not yet ready - * -1 -> Something went wrong - */ - -int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, - unsigned char value) -{ - int err_code = 0; - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return 0; - - err_code = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ); - - if (err_code < 0) { - dev_err(&usbvision->dev->dev, - "%s: failed: error %d\n", __func__, err_code); - } - return err_code; -} - - -static void usbvision_ctrl_urb_complete(struct urb *urb) -{ - struct usb_usbvision *usbvision = (struct usb_usbvision *)urb->context; - - PDEBUG(DBG_IRQ, ""); - usbvision->ctrl_urb_busy = 0; - if (waitqueue_active(&usbvision->ctrl_urb_wq)) - wake_up_interruptible(&usbvision->ctrl_urb_wq); -} - - -static int usbvision_write_reg_irq(struct usb_usbvision *usbvision, int address, - unsigned char *data, int len) -{ - int err_code = 0; - - PDEBUG(DBG_IRQ, ""); - if (len > 8) - return -EFAULT; - if (usbvision->ctrl_urb_busy) - return -EBUSY; - usbvision->ctrl_urb_busy = 1; - - usbvision->ctrl_urb_setup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; - usbvision->ctrl_urb_setup.bRequest = USBVISION_OP_CODE; - usbvision->ctrl_urb_setup.wValue = 0; - usbvision->ctrl_urb_setup.wIndex = cpu_to_le16(address); - usbvision->ctrl_urb_setup.wLength = cpu_to_le16(len); - usb_fill_control_urb(usbvision->ctrl_urb, usbvision->dev, - usb_sndctrlpipe(usbvision->dev, 1), - (unsigned char *)&usbvision->ctrl_urb_setup, - (void *)usbvision->ctrl_urb_buffer, len, - usbvision_ctrl_urb_complete, - (void *)usbvision); - - memcpy(usbvision->ctrl_urb_buffer, data, len); - - err_code = usb_submit_urb(usbvision->ctrl_urb, GFP_ATOMIC); - if (err_code < 0) { - /* error in usb_submit_urb() */ - usbvision->ctrl_urb_busy = 0; - } - PDEBUG(DBG_IRQ, "submit %d byte: error %d", len, err_code); - return err_code; -} - - -static int usbvision_init_compression(struct usb_usbvision *usbvision) -{ - int err_code = 0; - - usbvision->last_isoc_frame_num = -1; - usbvision->isoc_data_count = 0; - usbvision->isoc_packet_count = 0; - usbvision->isoc_skip_count = 0; - usbvision->compr_level = 50; - usbvision->last_compr_level = -1; - usbvision->isoc_urb_count = 0; - usbvision->request_intra = 1; - usbvision->isoc_measure_bandwidth_count = 0; - - return err_code; -} - -/* this function measures the used bandwidth since last call - * return: 0 : no error - * sets used_bandwidth to 1-100 : 1-100% of full bandwidth resp. to isoc_packet_size - */ -static int usbvision_measure_bandwidth(struct usb_usbvision *usbvision) -{ - int err_code = 0; - - if (usbvision->isoc_measure_bandwidth_count < 2) { /* this gives an average bandwidth of 3 frames */ - usbvision->isoc_measure_bandwidth_count++; - return err_code; - } - if ((usbvision->isoc_packet_size > 0) && (usbvision->isoc_packet_count > 0)) { - usbvision->used_bandwidth = usbvision->isoc_data_count / - (usbvision->isoc_packet_count + usbvision->isoc_skip_count) * - 100 / usbvision->isoc_packet_size; - } - usbvision->isoc_measure_bandwidth_count = 0; - usbvision->isoc_data_count = 0; - usbvision->isoc_packet_count = 0; - usbvision->isoc_skip_count = 0; - return err_code; -} - -static int usbvision_adjust_compression(struct usb_usbvision *usbvision) -{ - int err_code = 0; - unsigned char buffer[6]; - - PDEBUG(DBG_IRQ, ""); - if ((adjust_compression) && (usbvision->used_bandwidth > 0)) { - usbvision->compr_level += (usbvision->used_bandwidth - 90) / 2; - RESTRICT_TO_RANGE(usbvision->compr_level, 0, 100); - if (usbvision->compr_level != usbvision->last_compr_level) { - int distortion; - - if (usbvision->bridge_type == BRIDGE_NT1004 || usbvision->bridge_type == BRIDGE_NT1005) { - buffer[0] = (unsigned char)(4 + 16 * usbvision->compr_level / 100); /* PCM Threshold 1 */ - buffer[1] = (unsigned char)(4 + 8 * usbvision->compr_level / 100); /* PCM Threshold 2 */ - distortion = 7 + 248 * usbvision->compr_level / 100; - buffer[2] = (unsigned char)(distortion & 0xFF); /* Average distortion Threshold (inter) */ - buffer[3] = (unsigned char)(distortion & 0xFF); /* Average distortion Threshold (intra) */ - distortion = 1 + 42 * usbvision->compr_level / 100; - buffer[4] = (unsigned char)(distortion & 0xFF); /* Maximum distortion Threshold (inter) */ - buffer[5] = (unsigned char)(distortion & 0xFF); /* Maximum distortion Threshold (intra) */ - } else { /* BRIDGE_NT1003 */ - buffer[0] = (unsigned char)(4 + 16 * usbvision->compr_level / 100); /* PCM threshold 1 */ - buffer[1] = (unsigned char)(4 + 8 * usbvision->compr_level / 100); /* PCM threshold 2 */ - distortion = 2 + 253 * usbvision->compr_level / 100; - buffer[2] = (unsigned char)(distortion & 0xFF); /* distortion threshold bit0-7 */ - buffer[3] = 0; /* (unsigned char)((distortion >> 8) & 0x0F); distortion threshold bit 8-11 */ - distortion = 0 + 43 * usbvision->compr_level / 100; - buffer[4] = (unsigned char)(distortion & 0xFF); /* maximum distortion bit0-7 */ - buffer[5] = 0; /* (unsigned char)((distortion >> 8) & 0x01); maximum distortion bit 8 */ - } - err_code = usbvision_write_reg_irq(usbvision, USBVISION_PCM_THR1, buffer, 6); - if (err_code == 0) { - PDEBUG(DBG_IRQ, "new compr params %#02x %#02x %#02x %#02x %#02x %#02x", buffer[0], - buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); - usbvision->last_compr_level = usbvision->compr_level; - } - } - } - return err_code; -} - -static int usbvision_request_intra(struct usb_usbvision *usbvision) -{ - int err_code = 0; - unsigned char buffer[1]; - - PDEBUG(DBG_IRQ, ""); - usbvision->request_intra = 1; - buffer[0] = 1; - usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1); - return err_code; -} - -static int usbvision_unrequest_intra(struct usb_usbvision *usbvision) -{ - int err_code = 0; - unsigned char buffer[1]; - - PDEBUG(DBG_IRQ, ""); - usbvision->request_intra = 0; - buffer[0] = 0; - usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1); - return err_code; -} - -/******************************* - * usbvision utility functions - *******************************/ - -int usbvision_power_off(struct usb_usbvision *usbvision) -{ - int err_code = 0; - - PDEBUG(DBG_FUNC, ""); - - err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN); - if (err_code == 1) - usbvision->power = 0; - PDEBUG(DBG_FUNC, "%s: err_code %d", (err_code != 1) ? "ERROR" : "power is off", err_code); - return err_code; -} - -/* - * usbvision_set_video_format() - * - */ -static int usbvision_set_video_format(struct usb_usbvision *usbvision, int format) -{ - static const char proc[] = "usbvision_set_video_format"; - int rc; - unsigned char value[2]; - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return 0; - - PDEBUG(DBG_FUNC, "isoc_mode %#02x", format); - - if ((format != ISOC_MODE_YUV422) - && (format != ISOC_MODE_YUV420) - && (format != ISOC_MODE_COMPRESS)) { - printk(KERN_ERR "usbvision: unknown video format %02x, using default YUV420", - format); - format = ISOC_MODE_YUV420; - } - value[0] = 0x0A; /* TODO: See the effect of the filter */ - value[1] = format; /* Sets the VO_MODE register which follows FILT_CONT */ - rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_ENDPOINT, 0, - (__u16) USBVISION_FILT_CONT, value, 2, HZ); - - if (rc < 0) { - printk(KERN_ERR "%s: ERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); - } - usbvision->isoc_mode = format; - return rc; -} - -/* - * usbvision_set_output() - * - */ - -int usbvision_set_output(struct usb_usbvision *usbvision, int width, - int height) -{ - int err_code = 0; - int usb_width, usb_height; - unsigned int frame_rate = 0, frame_drop = 0; - unsigned char value[4]; - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return 0; - - if (width > MAX_USB_WIDTH) { - usb_width = width / 2; - usbvision->stretch_width = 2; - } else { - usb_width = width; - usbvision->stretch_width = 1; - } - - if (height > MAX_USB_HEIGHT) { - usb_height = height / 2; - usbvision->stretch_height = 2; - } else { - usb_height = height; - usbvision->stretch_height = 1; - } - - RESTRICT_TO_RANGE(usb_width, MIN_FRAME_WIDTH, MAX_USB_WIDTH); - usb_width &= ~(MIN_FRAME_WIDTH-1); - RESTRICT_TO_RANGE(usb_height, MIN_FRAME_HEIGHT, MAX_USB_HEIGHT); - usb_height &= ~(1); - - PDEBUG(DBG_FUNC, "usb %dx%d; screen %dx%d; stretch %dx%d", - usb_width, usb_height, width, height, - usbvision->stretch_width, usbvision->stretch_height); - - /* I'll not rewrite the same values */ - if ((usb_width != usbvision->curwidth) || (usb_height != usbvision->curheight)) { - value[0] = usb_width & 0xff; /* LSB */ - value[1] = (usb_width >> 8) & 0x03; /* MSB */ - value[2] = usb_height & 0xff; /* LSB */ - value[3] = (usb_height >> 8) & 0x03; /* MSB */ - - err_code = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, - 0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ); - - if (err_code < 0) { - dev_err(&usbvision->dev->dev, - "%s failed: error %d\n", __func__, err_code); - return err_code; - } - usbvision->curwidth = usbvision->stretch_width * usb_width; - usbvision->curheight = usbvision->stretch_height * usb_height; - } - - if (usbvision->isoc_mode == ISOC_MODE_YUV422) - frame_rate = (usbvision->isoc_packet_size * 1000) / (usb_width * usb_height * 2); - else if (usbvision->isoc_mode == ISOC_MODE_YUV420) - frame_rate = (usbvision->isoc_packet_size * 1000) / ((usb_width * usb_height * 12) / 8); - else - frame_rate = FRAMERATE_MAX; - - if (usbvision->tvnorm_id & V4L2_STD_625_50) - frame_drop = frame_rate * 32 / 25 - 1; - else if (usbvision->tvnorm_id & V4L2_STD_525_60) - frame_drop = frame_rate * 32 / 30 - 1; - - RESTRICT_TO_RANGE(frame_drop, FRAMERATE_MIN, FRAMERATE_MAX); - - PDEBUG(DBG_FUNC, "frame_rate %d fps, frame_drop %d", frame_rate, frame_drop); - - frame_drop = FRAMERATE_MAX; /* We can allow the maximum here, because dropping is controlled */ - - /* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ... - => frame_skip = 4; - => frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25; - - frame_drop = 9; => frame_phase = 1, 5, 8, 11, 14, 17, 21, 24, 27, 1, 4, 8, ... - => frame_skip = 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, ... - => frame_rate = (9 + 1) * 25 / 32 = 250 / 32 = 7.8125; - */ - err_code = usbvision_write_reg(usbvision, USBVISION_FRM_RATE, frame_drop); - return err_code; -} - - -/* - * usbvision_frames_alloc - * allocate the required frames - */ -int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames) -{ - int i; - - /* needs to be page aligned cause the buffers can be mapped individually! */ - usbvision->max_frame_size = PAGE_ALIGN(usbvision->curwidth * - usbvision->curheight * - usbvision->palette.bytes_per_pixel); - - /* Try to do my best to allocate the frames the user want in the remaining memory */ - usbvision->num_frames = number_of_frames; - while (usbvision->num_frames > 0) { - usbvision->fbuf_size = usbvision->num_frames * usbvision->max_frame_size; - usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size); - if (usbvision->fbuf) - break; - usbvision->num_frames--; - } - - spin_lock_init(&usbvision->queue_lock); - init_waitqueue_head(&usbvision->wait_frame); - init_waitqueue_head(&usbvision->wait_stream); - - /* Allocate all buffers */ - for (i = 0; i < usbvision->num_frames; i++) { - usbvision->frame[i].index = i; - usbvision->frame[i].grabstate = frame_state_unused; - usbvision->frame[i].data = usbvision->fbuf + - i * usbvision->max_frame_size; - /* - * Set default sizes for read operation. - */ - usbvision->stretch_width = 1; - usbvision->stretch_height = 1; - usbvision->frame[i].width = usbvision->curwidth; - usbvision->frame[i].height = usbvision->curheight; - usbvision->frame[i].bytes_read = 0; - } - PDEBUG(DBG_FUNC, "allocated %d frames (%d bytes per frame)", - usbvision->num_frames, usbvision->max_frame_size); - return usbvision->num_frames; -} - -/* - * usbvision_frames_free - * frees memory allocated for the frames - */ -void usbvision_frames_free(struct usb_usbvision *usbvision) -{ - /* Have to free all that memory */ - PDEBUG(DBG_FUNC, "free %d frames", usbvision->num_frames); - - if (usbvision->fbuf != NULL) { - usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size); - usbvision->fbuf = NULL; - - usbvision->num_frames = 0; - } -} -/* - * usbvision_empty_framequeues() - * prepare queues for incoming and outgoing frames - */ -void usbvision_empty_framequeues(struct usb_usbvision *usbvision) -{ - u32 i; - - INIT_LIST_HEAD(&(usbvision->inqueue)); - INIT_LIST_HEAD(&(usbvision->outqueue)); - - for (i = 0; i < USBVISION_NUMFRAMES; i++) { - usbvision->frame[i].grabstate = frame_state_unused; - usbvision->frame[i].bytes_read = 0; - } -} - -/* - * usbvision_stream_interrupt() - * stops streaming - */ -int usbvision_stream_interrupt(struct usb_usbvision *usbvision) -{ - int ret = 0; - - /* stop reading from the device */ - - usbvision->streaming = stream_interrupt; - ret = wait_event_timeout(usbvision->wait_stream, - (usbvision->streaming == stream_idle), - msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES)); - return ret; -} - -/* - * usbvision_set_compress_params() - * - */ - -static int usbvision_set_compress_params(struct usb_usbvision *usbvision) -{ - static const char proc[] = "usbvision_set_compresion_params: "; - int rc; - unsigned char value[6]; - - value[0] = 0x0F; /* Intra-Compression cycle */ - value[1] = 0x01; /* Reg.45 one line per strip */ - value[2] = 0x00; /* Reg.46 Force intra mode on all new frames */ - value[3] = 0x00; /* Reg.47 FORCE_UP <- 0 normal operation (not force) */ - value[4] = 0xA2; /* Reg.48 BUF_THR I'm not sure if this does something in not compressed mode. */ - value[5] = 0x00; /* Reg.49 DVI_YUV This has nothing to do with compression */ - - /* catched values for NT1004 */ - /* value[0] = 0xFF; Never apply intra mode automatically */ - /* value[1] = 0xF1; Use full frame height for virtual strip width; One line per strip */ - /* value[2] = 0x01; Force intra mode on all new frames */ - /* value[3] = 0x00; Strip size 400 Bytes; do not force up */ - /* value[4] = 0xA2; */ - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return 0; - - rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_ENDPOINT, 0, - (__u16) USBVISION_INTRA_CYC, value, 5, HZ); - - if (rc < 0) { - printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); - return rc; - } - - if (usbvision->bridge_type == BRIDGE_NT1004) { - value[0] = 20; /* PCM Threshold 1 */ - value[1] = 12; /* PCM Threshold 2 */ - value[2] = 255; /* Distortion Threshold inter */ - value[3] = 255; /* Distortion Threshold intra */ - value[4] = 43; /* Max Distortion inter */ - value[5] = 43; /* Max Distortion intra */ - } else { - value[0] = 20; /* PCM Threshold 1 */ - value[1] = 12; /* PCM Threshold 2 */ - value[2] = 255; /* Distortion Threshold d7-d0 */ - value[3] = 0; /* Distortion Threshold d11-d8 */ - value[4] = 43; /* Max Distortion d7-d0 */ - value[5] = 0; /* Max Distortion d8 */ - } - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return 0; - - rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_ENDPOINT, 0, - (__u16) USBVISION_PCM_THR1, value, 6, HZ); - - if (rc < 0) { - printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); - } - return rc; -} - - -/* - * usbvision_set_input() - * - * Set the input (saa711x, ...) size x y and other misc input params - * I've no idea if this parameters are right - * - */ -int usbvision_set_input(struct usb_usbvision *usbvision) -{ - static const char proc[] = "usbvision_set_input: "; - int rc; - unsigned char value[8]; - unsigned char dvi_yuv_value; - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return 0; - - /* Set input format expected from decoder*/ - if (usbvision_device_data[usbvision->dev_model].vin_reg1_override) { - value[0] = usbvision_device_data[usbvision->dev_model].vin_reg1; - } else if (usbvision_device_data[usbvision->dev_model].codec == CODEC_SAA7113) { - /* SAA7113 uses 8 bit output */ - value[0] = USBVISION_8_422_SYNC; - } else { - /* I'm sure only about d2-d0 [010] 16 bit 4:2:2 usin sync pulses - * as that is how saa7111 is configured */ - value[0] = USBVISION_16_422_SYNC; - /* | USBVISION_VSNC_POL | USBVISION_VCLK_POL);*/ - } - - rc = usbvision_write_reg(usbvision, USBVISION_VIN_REG1, value[0]); - if (rc < 0) { - printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); - return rc; - } - - - if (usbvision->tvnorm_id & V4L2_STD_PAL) { - value[0] = 0xC0; - value[1] = 0x02; /* 0x02C0 -> 704 Input video line length */ - value[2] = 0x20; - value[3] = 0x01; /* 0x0120 -> 288 Input video n. of lines */ - value[4] = 0x60; - value[5] = 0x00; /* 0x0060 -> 96 Input video h offset */ - value[6] = 0x16; - value[7] = 0x00; /* 0x0016 -> 22 Input video v offset */ - } else if (usbvision->tvnorm_id & V4L2_STD_SECAM) { - value[0] = 0xC0; - value[1] = 0x02; /* 0x02C0 -> 704 Input video line length */ - value[2] = 0x20; - value[3] = 0x01; /* 0x0120 -> 288 Input video n. of lines */ - value[4] = 0x01; - value[5] = 0x00; /* 0x0001 -> 01 Input video h offset */ - value[6] = 0x01; - value[7] = 0x00; /* 0x0001 -> 01 Input video v offset */ - } else { /* V4L2_STD_NTSC */ - value[0] = 0xD0; - value[1] = 0x02; /* 0x02D0 -> 720 Input video line length */ - value[2] = 0xF0; - value[3] = 0x00; /* 0x00F0 -> 240 Input video number of lines */ - value[4] = 0x50; - value[5] = 0x00; /* 0x0050 -> 80 Input video h offset */ - value[6] = 0x10; - value[7] = 0x00; /* 0x0010 -> 16 Input video v offset */ - } - - if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) { - value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff; - value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8; - } - - if (adjust_x_offset != -1) { - value[4] = adjust_x_offset & 0xff; - value[5] = (adjust_x_offset & 0x0300) >> 8; - } - - if (usbvision_device_data[usbvision->dev_model].y_offset >= 0) { - value[6] = usbvision_device_data[usbvision->dev_model].y_offset & 0xff; - value[7] = (usbvision_device_data[usbvision->dev_model].y_offset & 0x0300) >> 8; - } - - if (adjust_y_offset != -1) { - value[6] = adjust_y_offset & 0xff; - value[7] = (adjust_y_offset & 0x0300) >> 8; - } - - rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, /* USBVISION specific code */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0, - (__u16) USBVISION_LXSIZE_I, value, 8, HZ); - if (rc < 0) { - printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); - return rc; - } - - - dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */ - - if (usbvision_device_data[usbvision->dev_model].dvi_yuv_override) { - dvi_yuv_value = usbvision_device_data[usbvision->dev_model].dvi_yuv; - } else if (usbvision_device_data[usbvision->dev_model].codec == CODEC_SAA7113) { - /* This changes as the fine sync control changes. Further investigation necessary */ - dvi_yuv_value = 0x06; - } - - return usbvision_write_reg(usbvision, USBVISION_DVI_YUV, dvi_yuv_value); -} - - -/* - * usbvision_set_dram_settings() - * - * Set the buffer address needed by the usbvision dram to operate - * This values has been taken with usbsnoop. - * - */ - -static int usbvision_set_dram_settings(struct usb_usbvision *usbvision) -{ - int rc; - unsigned char value[8]; - - if (usbvision->isoc_mode == ISOC_MODE_COMPRESS) { - value[0] = 0x42; - value[1] = 0x71; - value[2] = 0xff; - value[3] = 0x00; - value[4] = 0x98; - value[5] = 0xe0; - value[6] = 0x71; - value[7] = 0xff; - /* UR: 0x0E200-0x3FFFF = 204288 Words (1 Word = 2 Byte) */ - /* FDL: 0x00000-0x0E099 = 57498 Words */ - /* VDW: 0x0E3FF-0x3FFFF */ - } else { - value[0] = 0x42; - value[1] = 0x00; - value[2] = 0xff; - value[3] = 0x00; - value[4] = 0x00; - value[5] = 0x00; - value[6] = 0x00; - value[7] = 0xff; - } - /* These are the values of the address of the video buffer, - * they have to be loaded into the USBVISION_DRM_PRM1-8 - * - * Start address of video output buffer for read: drm_prm1-2 -> 0x00000 - * End address of video output buffer for read: drm_prm1-3 -> 0x1ffff - * Start address of video frame delay buffer: drm_prm1-4 -> 0x20000 - * Only used in compressed mode - * End address of video frame delay buffer: drm_prm1-5-6 -> 0x3ffff - * Only used in compressed mode - * Start address of video output buffer for write: drm_prm1-7 -> 0x00000 - * End address of video output buffer for write: drm_prm1-8 -> 0x1ffff - */ - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return 0; - - rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, /* USBVISION specific code */ - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_ENDPOINT, 0, - (__u16) USBVISION_DRM_PRM1, value, 8, HZ); - - if (rc < 0) { - dev_err(&usbvision->dev->dev, "%sERROR=%d\n", __func__, rc); - return rc; - } - - /* Restart the video buffer logic */ - rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, USBVISION_RES_UR | - USBVISION_RES_FDL | USBVISION_RES_VDW); - if (rc < 0) - return rc; - rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, 0x00); - - return rc; -} - -/* - * () - * - * Power on the device, enables suspend-resume logic - * & reset the isoc End-Point - * - */ - -int usbvision_power_on(struct usb_usbvision *usbvision) -{ - int err_code = 0; - - PDEBUG(DBG_FUNC, ""); - - usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN); - usbvision_write_reg(usbvision, USBVISION_PWR_REG, - USBVISION_SSPND_EN | USBVISION_RES2); - - usbvision_write_reg(usbvision, USBVISION_PWR_REG, - USBVISION_SSPND_EN | USBVISION_PWR_VID); - err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG, - USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2); - if (err_code == 1) - usbvision->power = 1; - PDEBUG(DBG_FUNC, "%s: err_code %d", (err_code < 0) ? "ERROR" : "power is on", err_code); - return err_code; -} - - -/* - * usbvision timer stuff - */ - -/* to call usbvision_power_off from task queue */ -static void call_usbvision_power_off(struct work_struct *work) -{ - struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, power_off_work); - - PDEBUG(DBG_FUNC, ""); - if (mutex_lock_interruptible(&usbvision->v4l2_lock)) - return; - - if (usbvision->user == 0) { - usbvision_i2c_unregister(usbvision); - - usbvision_power_off(usbvision); - usbvision->initialized = 0; - } - mutex_unlock(&usbvision->v4l2_lock); -} - -static void usbvision_power_off_timer(unsigned long data) -{ - struct usb_usbvision *usbvision = (void *)data; - - PDEBUG(DBG_FUNC, ""); - del_timer(&usbvision->power_off_timer); - INIT_WORK(&usbvision->power_off_work, call_usbvision_power_off); - (void) schedule_work(&usbvision->power_off_work); -} - -void usbvision_init_power_off_timer(struct usb_usbvision *usbvision) -{ - init_timer(&usbvision->power_off_timer); - usbvision->power_off_timer.data = (long)usbvision; - usbvision->power_off_timer.function = usbvision_power_off_timer; -} - -void usbvision_set_power_off_timer(struct usb_usbvision *usbvision) -{ - mod_timer(&usbvision->power_off_timer, jiffies + USBVISION_POWEROFF_TIME); -} - -void usbvision_reset_power_off_timer(struct usb_usbvision *usbvision) -{ - if (timer_pending(&usbvision->power_off_timer)) - del_timer(&usbvision->power_off_timer); -} - -/* - * usbvision_begin_streaming() - * Sure you have to put bit 7 to 0, if not incoming frames are droped, but no - * idea about the rest - */ -int usbvision_begin_streaming(struct usb_usbvision *usbvision) -{ - if (usbvision->isoc_mode == ISOC_MODE_COMPRESS) - usbvision_init_compression(usbvision); - return usbvision_write_reg(usbvision, USBVISION_VIN_REG2, - USBVISION_NOHVALID | usbvision->vin_reg2_preset); -} - -/* - * usbvision_restart_isoc() - * Not sure yet if touching here PWR_REG make loose the config - */ - -int usbvision_restart_isoc(struct usb_usbvision *usbvision) -{ - int ret; - - ret = usbvision_write_reg(usbvision, USBVISION_PWR_REG, - USBVISION_SSPND_EN | USBVISION_PWR_VID); - if (ret < 0) - return ret; - ret = usbvision_write_reg(usbvision, USBVISION_PWR_REG, - USBVISION_SSPND_EN | USBVISION_PWR_VID | - USBVISION_RES2); - if (ret < 0) - return ret; - ret = usbvision_write_reg(usbvision, USBVISION_VIN_REG2, - USBVISION_KEEP_BLANK | USBVISION_NOHVALID | - usbvision->vin_reg2_preset); - if (ret < 0) - return ret; - - /* TODO: schedule timeout */ - while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) & 0x01) != 1) - ; - - return 0; -} - -int usbvision_audio_off(struct usb_usbvision *usbvision) -{ - if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_AUDIO_MUTE) < 0) { - printk(KERN_ERR "usbvision_audio_off: can't write reg\n"); - return -1; - } - usbvision->audio_mute = 0; - usbvision->audio_channel = USBVISION_AUDIO_MUTE; - return 0; -} - -int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel) -{ - if (!usbvision->audio_mute) { - if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, audio_channel) < 0) { - printk(KERN_ERR "usbvision_set_audio: can't write iopin register for audio switching\n"); - return -1; - } - } - usbvision->audio_channel = audio_channel; - return 0; -} - -int usbvision_setup(struct usb_usbvision *usbvision, int format) -{ - usbvision_set_video_format(usbvision, format); - usbvision_set_dram_settings(usbvision); - usbvision_set_compress_params(usbvision); - usbvision_set_input(usbvision); - usbvision_set_output(usbvision, MAX_USB_WIDTH, MAX_USB_HEIGHT); - usbvision_restart_isoc(usbvision); - - /* cosas del PCM */ - return USBVISION_IS_OPERATIONAL(usbvision); -} - -int usbvision_set_alternate(struct usb_usbvision *dev) -{ - int err_code, prev_alt = dev->iface_alt; - int i; - - dev->iface_alt = 0; - for (i = 0; i < dev->num_alt; i++) - if (dev->alt_max_pkt_size[i] > dev->alt_max_pkt_size[dev->iface_alt]) - dev->iface_alt = i; - - if (dev->iface_alt != prev_alt) { - dev->isoc_packet_size = dev->alt_max_pkt_size[dev->iface_alt]; - PDEBUG(DBG_FUNC, "setting alternate %d with max_packet_size=%u", - dev->iface_alt, dev->isoc_packet_size); - err_code = usb_set_interface(dev->dev, dev->iface, dev->iface_alt); - if (err_code < 0) { - dev_err(&dev->dev->dev, - "cannot change alternate number to %d (error=%i)\n", - dev->iface_alt, err_code); - return err_code; - } - } - - PDEBUG(DBG_ISOC, "ISO Packet Length:%d", dev->isoc_packet_size); - - return 0; -} - -/* - * usbvision_init_isoc() - * - */ -int usbvision_init_isoc(struct usb_usbvision *usbvision) -{ - struct usb_device *dev = usbvision->dev; - int buf_idx, err_code, reg_value; - int sb_size; - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -EFAULT; - - usbvision->cur_frame = NULL; - scratch_reset(usbvision); - - /* Alternate interface 1 is is the biggest frame size */ - err_code = usbvision_set_alternate(usbvision); - if (err_code < 0) { - usbvision->last_error = err_code; - return -EBUSY; - } - sb_size = USBVISION_URB_FRAMES * usbvision->isoc_packet_size; - - reg_value = (16 - usbvision_read_reg(usbvision, - USBVISION_ALTER_REG)) & 0x0F; - - usbvision->usb_bandwidth = reg_value >> 1; - PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", - usbvision->usb_bandwidth); - - - - /* We double buffer the Iso lists */ - - for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) { - int j, k; - struct urb *urb; - - urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); - if (urb == NULL) { - dev_err(&usbvision->dev->dev, - "%s: usb_alloc_urb() failed\n", __func__); - return -ENOMEM; - } - usbvision->sbuf[buf_idx].urb = urb; - usbvision->sbuf[buf_idx].data = - usb_alloc_coherent(usbvision->dev, - sb_size, - GFP_KERNEL, - &urb->transfer_dma); - urb->dev = dev; - urb->context = usbvision; - urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = 1; - urb->transfer_buffer = usbvision->sbuf[buf_idx].data; - urb->complete = usbvision_isoc_irq; - urb->number_of_packets = USBVISION_URB_FRAMES; - urb->transfer_buffer_length = - usbvision->isoc_packet_size * USBVISION_URB_FRAMES; - for (j = k = 0; j < USBVISION_URB_FRAMES; j++, - k += usbvision->isoc_packet_size) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - usbvision->isoc_packet_size; - } - } - - /* Submit all URBs */ - for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) { - err_code = usb_submit_urb(usbvision->sbuf[buf_idx].urb, - GFP_KERNEL); - if (err_code) { - dev_err(&usbvision->dev->dev, - "%s: usb_submit_urb(%d) failed: error %d\n", - __func__, buf_idx, err_code); - } - } - - usbvision->streaming = stream_idle; - PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", - __func__, - usbvision->video_endp); - return 0; -} - -/* - * usbvision_stop_isoc() - * - * This procedure stops streaming and deallocates URBs. Then it - * activates zero-bandwidth alt. setting of the video interface. - * - */ -void usbvision_stop_isoc(struct usb_usbvision *usbvision) -{ - int buf_idx, err_code, reg_value; - int sb_size = USBVISION_URB_FRAMES * usbvision->isoc_packet_size; - - if ((usbvision->streaming == stream_off) || (usbvision->dev == NULL)) - return; - - /* Unschedule all of the iso td's */ - for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) { - usb_kill_urb(usbvision->sbuf[buf_idx].urb); - if (usbvision->sbuf[buf_idx].data) { - usb_free_coherent(usbvision->dev, - sb_size, - usbvision->sbuf[buf_idx].data, - usbvision->sbuf[buf_idx].urb->transfer_dma); - } - usb_free_urb(usbvision->sbuf[buf_idx].urb); - usbvision->sbuf[buf_idx].urb = NULL; - } - - PDEBUG(DBG_ISOC, "%s: streaming=stream_off\n", __func__); - usbvision->streaming = stream_off; - - if (!usbvision->remove_pending) { - /* Set packet size to 0 */ - usbvision->iface_alt = 0; - err_code = usb_set_interface(usbvision->dev, usbvision->iface, - usbvision->iface_alt); - if (err_code < 0) { - dev_err(&usbvision->dev->dev, - "%s: usb_set_interface() failed: error %d\n", - __func__, err_code); - usbvision->last_error = err_code; - } - reg_value = (16-usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F; - usbvision->isoc_packet_size = - (reg_value == 0) ? 0 : (reg_value * 64) - 1; - PDEBUG(DBG_ISOC, "ISO Packet Length:%d", - usbvision->isoc_packet_size); - - usbvision->usb_bandwidth = reg_value >> 1; - PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", - usbvision->usb_bandwidth); - } -} - -int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) -{ - /* inputs #0 and #3 are constant for every SAA711x. */ - /* inputs #1 and #2 are variable for SAA7111 and SAA7113 */ - int mode[4] = { SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3 }; - int audio[] = { 1, 0, 0, 0 }; - /* channel 0 is TV with audiochannel 1 (tuner mono) */ - /* channel 1 is Composite with audio channel 0 (line in) */ - /* channel 2 is S-Video with audio channel 0 (line in) */ - /* channel 3 is additional video inputs to the device with audio channel 0 (line in) */ - - RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs); - usbvision->ctl_input = channel; - - /* set the new channel */ - /* Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video */ - /* Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red */ - - switch (usbvision_device_data[usbvision->dev_model].codec) { - case CODEC_SAA7113: - mode[1] = SAA7115_COMPOSITE2; - if (switch_svideo_input) { - /* To handle problems with S-Video Input for - * some devices. Use switch_svideo_input - * parameter when loading the module.*/ - mode[2] = SAA7115_COMPOSITE1; - } else { - mode[2] = SAA7115_SVIDEO1; - } - break; - case CODEC_SAA7111: - default: - /* modes for saa7111 */ - mode[1] = SAA7115_COMPOSITE1; - mode[2] = SAA7115_SVIDEO1; - break; - } - call_all(usbvision, video, s_routing, mode[channel], 0, 0); - usbvision_set_audio(usbvision, audio[channel]); - return 0; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,529 +0,0 @@ -/* - * USBVISION.H - * usbvision header file - * - * Copyright (c) 1999-2005 Joerg Heckenbach - * Dwaine Garden - * - * - * Report problems to v4l MailingList: linux-media@vger.kernel.org - * - * This module is part of usbvision driver project. - * Updates to driver completed by Dwaine P. Garden - * v4l2 conversion by Thierry Merle - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#ifndef __LINUX_USBVISION_H -#define __LINUX_USBVISION_H - -#include -#include -#include -#include -#include -#include -#include - -#define USBVISION_DEBUG /* Turn on debug messages */ - -#define USBVISION_PWR_REG 0x00 - #define USBVISION_SSPND_EN (1 << 1) - #define USBVISION_RES2 (1 << 2) - #define USBVISION_PWR_VID (1 << 5) - #define USBVISION_E2_EN (1 << 7) -#define USBVISION_CONFIG_REG 0x01 -#define USBVISION_ADRS_REG 0x02 -#define USBVISION_ALTER_REG 0x03 -#define USBVISION_FORCE_ALTER_REG 0x04 -#define USBVISION_STATUS_REG 0x05 -#define USBVISION_IOPIN_REG 0x06 - #define USBVISION_IO_1 (1 << 0) - #define USBVISION_IO_2 (1 << 1) - #define USBVISION_AUDIO_IN 0 - #define USBVISION_AUDIO_TV 1 - #define USBVISION_AUDIO_RADIO 2 - #define USBVISION_AUDIO_MUTE 3 -#define USBVISION_SER_MODE 0x07 -#define USBVISION_SER_ADRS 0x08 -#define USBVISION_SER_CONT 0x09 -#define USBVISION_SER_DAT1 0x0A -#define USBVISION_SER_DAT2 0x0B -#define USBVISION_SER_DAT3 0x0C -#define USBVISION_SER_DAT4 0x0D -#define USBVISION_EE_DATA 0x0E -#define USBVISION_EE_LSBAD 0x0F -#define USBVISION_EE_CONT 0x10 -#define USBVISION_DRM_CONT 0x12 - #define USBVISION_REF (1 << 0) - #define USBVISION_RES_UR (1 << 2) - #define USBVISION_RES_FDL (1 << 3) - #define USBVISION_RES_VDW (1 << 4) -#define USBVISION_DRM_PRM1 0x13 -#define USBVISION_DRM_PRM2 0x14 -#define USBVISION_DRM_PRM3 0x15 -#define USBVISION_DRM_PRM4 0x16 -#define USBVISION_DRM_PRM5 0x17 -#define USBVISION_DRM_PRM6 0x18 -#define USBVISION_DRM_PRM7 0x19 -#define USBVISION_DRM_PRM8 0x1A -#define USBVISION_VIN_REG1 0x1B - #define USBVISION_8_422_SYNC 0x01 - #define USBVISION_16_422_SYNC 0x02 - #define USBVISION_VSNC_POL (1 << 3) - #define USBVISION_HSNC_POL (1 << 4) - #define USBVISION_FID_POL (1 << 5) - #define USBVISION_HVALID_PO (1 << 6) - #define USBVISION_VCLK_POL (1 << 7) -#define USBVISION_VIN_REG2 0x1C - #define USBVISION_AUTO_FID (1 << 0) - #define USBVISION_NONE_INTER (1 << 1) - #define USBVISION_NOHVALID (1 << 2) - #define USBVISION_UV_ID (1 << 3) - #define USBVISION_FIX_2C (1 << 4) - #define USBVISION_SEND_FID (1 << 5) - #define USBVISION_KEEP_BLANK (1 << 7) -#define USBVISION_LXSIZE_I 0x1D -#define USBVISION_MXSIZE_I 0x1E -#define USBVISION_LYSIZE_I 0x1F -#define USBVISION_MYSIZE_I 0x20 -#define USBVISION_LX_OFFST 0x21 -#define USBVISION_MX_OFFST 0x22 -#define USBVISION_LY_OFFST 0x23 -#define USBVISION_MY_OFFST 0x24 -#define USBVISION_FRM_RATE 0x25 -#define USBVISION_LXSIZE_O 0x26 -#define USBVISION_MXSIZE_O 0x27 -#define USBVISION_LYSIZE_O 0x28 -#define USBVISION_MYSIZE_O 0x29 -#define USBVISION_FILT_CONT 0x2A -#define USBVISION_VO_MODE 0x2B -#define USBVISION_INTRA_CYC 0x2C -#define USBVISION_STRIP_SZ 0x2D -#define USBVISION_FORCE_INTRA 0x2E -#define USBVISION_FORCE_UP 0x2F -#define USBVISION_BUF_THR 0x30 -#define USBVISION_DVI_YUV 0x31 -#define USBVISION_AUDIO_CONT 0x32 -#define USBVISION_AUD_PK_LEN 0x33 -#define USBVISION_BLK_PK_LEN 0x34 -#define USBVISION_PCM_THR1 0x38 -#define USBVISION_PCM_THR2 0x39 -#define USBVISION_DIST_THR_L 0x3A -#define USBVISION_DIST_THR_H 0x3B -#define USBVISION_MAX_DIST_L 0x3C -#define USBVISION_MAX_DIST_H 0x3D -#define USBVISION_OP_CODE 0x33 - -#define MAX_BYTES_PER_PIXEL 4 - -#define MIN_FRAME_WIDTH 64 -#define MAX_USB_WIDTH 320 /* 384 */ -#define MAX_FRAME_WIDTH 320 /* 384 */ /* streching sometimes causes crashes*/ - -#define MIN_FRAME_HEIGHT 48 -#define MAX_USB_HEIGHT 240 /* 288 */ -#define MAX_FRAME_HEIGHT 240 /* 288 */ /* Streching sometimes causes crashes*/ - -#define MAX_FRAME_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * MAX_BYTES_PER_PIXEL) -#define USBVISION_CLIPMASK_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT / 8) /* bytesize of clipmask */ - -#define USBVISION_URB_FRAMES 32 - -#define USBVISION_NUM_HEADERMARKER 20 -#define USBVISION_NUMFRAMES 3 /* Maximum number of frames an application can get */ -#define USBVISION_NUMSBUF 2 /* Dimensioning the USB S buffering */ - -#define USBVISION_POWEROFF_TIME (3 * HZ) /* 3 seconds */ - - -#define FRAMERATE_MIN 0 -#define FRAMERATE_MAX 31 - -enum { - ISOC_MODE_YUV422 = 0x03, - ISOC_MODE_YUV420 = 0x14, - ISOC_MODE_COMPRESS = 0x60, -}; - -/* This macro restricts an int variable to an inclusive range */ -#define RESTRICT_TO_RANGE(v, mi, ma) \ - { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } - -/* - * We use macros to do YUV -> RGB conversion because this is - * very important for speed and totally unimportant for size. - * - * YUV -> RGB Conversion - * --------------------- - * - * B = 1.164*(Y-16) + 2.018*(V-128) - * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) - * R = 1.164*(Y-16) + 1.596*(U-128) - * - * If you fancy integer arithmetics (as you should), hear this: - * - * 65536*B = 76284*(Y-16) + 132252*(V-128) - * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) - * 65536*R = 76284*(Y-16) + 104595*(U-128) - * - * Make sure the output values are within [0..255] range. - */ -#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x))) -#define YUV_TO_RGB_BY_THE_BOOK(my, mu, mv, mr, mg, mb) { \ - int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \ - mm_y = (my) - 16; \ - mm_u = (mu) - 128; \ - mm_v = (mv) - 128; \ - mm_yc = mm_y * 76284; \ - mm_b = (mm_yc + 132252 * mm_v) >> 16; \ - mm_g = (mm_yc - 53281 * mm_u - 25625 * mm_v) >> 16; \ - mm_r = (mm_yc + 104595 * mm_u) >> 16; \ - mb = LIMIT_RGB(mm_b); \ - mg = LIMIT_RGB(mm_g); \ - mr = LIMIT_RGB(mm_r); \ -} - -/* Debugging aid */ -#define USBVISION_SAY_AND_WAIT(what) { \ - wait_queue_head_t wq; \ - init_waitqueue_head(&wq); \ - printk(KERN_INFO "Say: %s\n", what); \ - interruptible_sleep_on_timeout(&wq, HZ * 3); \ -} - -/* - * This macro checks if usbvision is still operational. The 'usbvision' - * pointer must be valid, usbvision->dev must be valid, we are not - * removing the device and the device has not erred on us. - */ -#define USBVISION_IS_OPERATIONAL(udevice) (\ - (udevice != NULL) && \ - ((udevice)->dev != NULL) && \ - ((udevice)->last_error == 0) && \ - (!(udevice)->remove_pending)) - -#define I2C_USB_ADAP_MAX 16 - -#define USBVISION_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_M) - -/* ----------------------------------------------------------------- */ -/* usbvision video structures */ -/* ----------------------------------------------------------------- */ -enum scan_state { - scan_state_scanning, /* Scanning for header */ - scan_state_lines /* Parsing lines */ -}; - -/* Completion states of the data parser */ -enum parse_state { - parse_state_continue, /* Just parse next item */ - parse_state_next_frame, /* Frame done, send it to V4L */ - parse_state_out, /* Not enough data for frame */ - parse_state_end_parse /* End parsing */ -}; - -enum frame_state { - frame_state_unused, /* Unused (no MCAPTURE) */ - frame_state_ready, /* Ready to start grabbing */ - frame_state_grabbing, /* In the process of being grabbed into */ - frame_state_done, /* Finished grabbing, but not been synced yet */ - frame_state_done_hold, /* Are syncing or reading */ - frame_state_error, /* Something bad happened while processing */ -}; - -/* stream states */ -enum stream_state { - stream_off, /* Driver streaming is completely OFF */ - stream_idle, /* Driver streaming is ready to be put ON by the application */ - stream_interrupt, /* Driver streaming must be interrupted */ - stream_on, /* Driver streaming is put ON by the application */ -}; - -enum isoc_state { - isoc_state_in_frame, /* Isoc packet is member of frame */ - isoc_state_no_frame, /* Isoc packet is not member of any frame */ -}; - -struct usb_device; - -struct usbvision_sbuf { - char *data; - struct urb *urb; -}; - -#define USBVISION_MAGIC_1 0x55 -#define USBVISION_MAGIC_2 0xAA -#define USBVISION_HEADER_LENGTH 0x0c -#define USBVISION_SAA7111_ADDR 0x48 -#define USBVISION_SAA7113_ADDR 0x4a -#define USBVISION_IIC_LRACK 0x20 -#define USBVISION_IIC_LRNACK 0x30 -#define USBVISION_FRAME_FORMAT_PARAM_INTRA (1<<7) - -struct usbvision_v4l2_format_st { - int supported; - int bytes_per_pixel; - int depth; - int format; - char *desc; -}; -#define USBVISION_SUPPORTED_PALETTES ARRAY_SIZE(usbvision_v4l2_format) - -struct usbvision_frame_header { - unsigned char magic_1; /* 0 magic */ - unsigned char magic_2; /* 1 magic */ - unsigned char header_length; /* 2 */ - unsigned char frame_num; /* 3 */ - unsigned char frame_phase; /* 4 */ - unsigned char frame_latency; /* 5 */ - unsigned char data_format; /* 6 */ - unsigned char format_param; /* 7 */ - unsigned char frame_width_lo; /* 8 */ - unsigned char frame_width_hi; /* 9 */ - unsigned char frame_height_lo; /* 10 */ - unsigned char frame_height_hi; /* 11 */ - __u16 frame_width; /* 8 - 9 after endian correction*/ - __u16 frame_height; /* 10 - 11 after endian correction*/ -}; - -struct usbvision_frame { - char *data; /* Frame buffer */ - struct usbvision_frame_header isoc_header; /* Header from stream */ - - int width; /* Width application is expecting */ - int height; /* Height */ - int index; /* Frame index */ - int frmwidth; /* Width the frame actually is */ - int frmheight; /* Height */ - - volatile int grabstate; /* State of grabbing */ - int scanstate; /* State of scanning */ - - struct list_head frame; - - int curline; /* Line of frame we're working on */ - - long scanlength; /* uncompressed, raw data length of frame */ - long bytes_read; /* amount of scanlength that has been read from data */ - struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/ - int v4l2_linesize; /* bytes for one videoline*/ - struct timeval timestamp; - int sequence; /* How many video frames we send to user */ -}; - -#define CODEC_SAA7113 7113 -#define CODEC_SAA7111 7111 -#define BRIDGE_NT1003 1003 -#define BRIDGE_NT1004 1004 -#define BRIDGE_NT1005 1005 - -struct usbvision_device_data_st { - __u64 video_norm; - const char *model_string; - int interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ - __u16 codec; - unsigned video_channels:3; - unsigned audio_channels:2; - unsigned radio:1; - unsigned vbi:1; - unsigned tuner:1; - unsigned vin_reg1_override:1; /* Override default value with */ - unsigned vin_reg2_override:1; /* vin_reg1, vin_reg2, etc. */ - unsigned dvi_yuv_override:1; - __u8 vin_reg1; - __u8 vin_reg2; - __u8 dvi_yuv; - __u8 tuner_type; - __s16 x_offset; - __s16 y_offset; -}; - -/* Declared on usbvision-cards.c */ -extern struct usbvision_device_data_st usbvision_device_data[]; -extern struct usb_device_id usbvision_table[]; - -struct usb_usbvision { - struct v4l2_device v4l2_dev; - struct video_device *vdev; /* Video Device */ - struct video_device *rdev; /* Radio Device */ - - /* i2c Declaration Section*/ - struct i2c_adapter i2c_adap; - int registered_i2c; - - struct urb *ctrl_urb; - unsigned char ctrl_urb_buffer[8]; - int ctrl_urb_busy; - struct usb_ctrlrequest ctrl_urb_setup; - wait_queue_head_t ctrl_urb_wq; /* Processes waiting */ - - /* configuration part */ - int have_tuner; - int tuner_type; - int bridge_type; /* NT1003, NT1004, NT1005 */ - int radio; - int video_inputs; /* # of inputs */ - unsigned long freq; - int audio_mute; - int audio_channel; - int isoc_mode; /* format of video data for the usb isoc-transfer */ - unsigned int nr; /* Number of the device */ - - /* Device structure */ - struct usb_device *dev; - /* usb transfer */ - int num_alt; /* Number of alternative settings */ - unsigned int *alt_max_pkt_size; /* array of max_packet_size */ - unsigned char iface; /* Video interface number */ - unsigned char iface_alt; /* Alt settings */ - unsigned char vin_reg2_preset; - struct mutex v4l2_lock; - struct timer_list power_off_timer; - struct work_struct power_off_work; - int power; /* is the device powered on? */ - int user; /* user count for exclusive use */ - int initialized; /* Had we already sent init sequence? */ - int dev_model; /* What type of USBVISION device we got? */ - enum stream_state streaming; /* Are we streaming Isochronous? */ - int last_error; /* What calamity struck us? */ - int curwidth; /* width of the frame the device is currently set to*/ - int curheight; /* height of the frame the device is currently set to*/ - int stretch_width; /* stretch-factor for frame width (from usb to screen)*/ - int stretch_height; /* stretch-factor for frame height (from usb to screen)*/ - char *fbuf; /* Videodev buffer area for mmap*/ - int max_frame_size; /* Bytes in one video frame */ - int fbuf_size; /* Videodev buffer size */ - spinlock_t queue_lock; /* spinlock for protecting mods on inqueue and outqueue */ - struct list_head inqueue, outqueue; /* queued frame list and ready to dequeue frame list */ - wait_queue_head_t wait_frame; /* Processes waiting */ - wait_queue_head_t wait_stream; /* Processes waiting */ - struct usbvision_frame *cur_frame; /* pointer to current frame, set by usbvision_find_header */ - struct usbvision_frame frame[USBVISION_NUMFRAMES]; /* frame buffer */ - int num_frames; /* number of frames allocated */ - struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; /* S buffering */ - volatile int remove_pending; /* If set then about to exit */ - - /* Scratch space from the Isochronous Pipe.*/ - unsigned char *scratch; - int scratch_read_ptr; - int scratch_write_ptr; - int scratch_headermarker[USBVISION_NUM_HEADERMARKER]; - int scratch_headermarker_read_ptr; - int scratch_headermarker_write_ptr; - enum isoc_state isocstate; - struct usbvision_v4l2_format_st palette; - - struct v4l2_capability vcap; /* Video capabilities */ - unsigned int ctl_input; /* selected input */ - v4l2_std_id tvnorm_id; /* selected tv norm */ - unsigned char video_endp; /* 0x82 for USBVISION devices based */ - - /* Decompression stuff: */ - unsigned char *intra_frame_buffer; /* Buffer for reference frame */ - int block_pos; /* for test only */ - int request_intra; /* 0 = normal; 1 = intra frame is requested; */ - int last_isoc_frame_num; /* check for lost isoc frames */ - int isoc_packet_size; /* need to calculate used_bandwidth */ - int used_bandwidth; /* used bandwidth 0-100%, need to set compr_level */ - int compr_level; /* How strong (100) or weak (0) is compression */ - int last_compr_level; /* How strong (100) or weak (0) was compression */ - int usb_bandwidth; /* Mbit/s */ - - /* Statistics that can be overlayed on the screen */ - unsigned long isoc_urb_count; /* How many URBs we received so far */ - unsigned long urb_length; /* Length of last URB */ - unsigned long isoc_data_count; /* How many bytes we received */ - unsigned long header_count; /* How many frame headers we found */ - unsigned long scratch_ovf_count; /* How many times we overflowed scratch */ - unsigned long isoc_skip_count; /* How many empty ISO packets received */ - unsigned long isoc_err_count; /* How many bad ISO packets received */ - unsigned long isoc_packet_count; /* How many packets we totally got */ - unsigned long time_in_irq; /* How long do we need for interrupt */ - int isoc_measure_bandwidth_count; - int frame_num; /* How many video frames we send to user */ - int max_strip_len; /* How big is the biggest strip */ - int comprblock_pos; - int strip_len_errors; /* How many times was block_pos greater than strip_len */ - int strip_magic_errors; - int strip_line_number_errors; - int compr_block_types[4]; -}; - -static inline struct usb_usbvision *to_usbvision(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct usb_usbvision, v4l2_dev); -} - -#define call_all(usbvision, o, f, args...) \ - v4l2_device_call_all(&usbvision->v4l2_dev, 0, o, f, ##args) - -/* --------------------------------------------------------------- */ -/* defined in usbvision-i2c.c */ -/* i2c-algo-usb declaration */ -/* --------------------------------------------------------------- */ - -/* ----------------------------------------------------------------------- */ -/* usbvision specific I2C functions */ -/* ----------------------------------------------------------------------- */ -int usbvision_i2c_register(struct usb_usbvision *usbvision); -int usbvision_i2c_unregister(struct usb_usbvision *usbvision); - -/* defined in usbvision-core.c */ -int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg); -int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, - unsigned char value); - -int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames); -void usbvision_frames_free(struct usb_usbvision *usbvision); -int usbvision_scratch_alloc(struct usb_usbvision *usbvision); -void usbvision_scratch_free(struct usb_usbvision *usbvision); -int usbvision_decompress_alloc(struct usb_usbvision *usbvision); -void usbvision_decompress_free(struct usb_usbvision *usbvision); - -int usbvision_setup(struct usb_usbvision *usbvision, int format); -int usbvision_init_isoc(struct usb_usbvision *usbvision); -int usbvision_restart_isoc(struct usb_usbvision *usbvision); -void usbvision_stop_isoc(struct usb_usbvision *usbvision); -int usbvision_set_alternate(struct usb_usbvision *dev); - -int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel); -int usbvision_audio_off(struct usb_usbvision *usbvision); - -int usbvision_begin_streaming(struct usb_usbvision *usbvision); -void usbvision_empty_framequeues(struct usb_usbvision *dev); -int usbvision_stream_interrupt(struct usb_usbvision *dev); - -int usbvision_muxsel(struct usb_usbvision *usbvision, int channel); -int usbvision_set_input(struct usb_usbvision *usbvision); -int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height); - -void usbvision_init_power_off_timer(struct usb_usbvision *usbvision); -void usbvision_set_power_off_timer(struct usb_usbvision *usbvision); -void usbvision_reset_power_off_timer(struct usb_usbvision *usbvision); -int usbvision_power_off(struct usb_usbvision *usbvision); -int usbvision_power_on(struct usb_usbvision *usbvision); - -#endif /* __LINUX_USBVISION_H */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,478 +0,0 @@ -/* - * usbvision_i2c.c - * i2c algorithm for USB-I2C Bridges - * - * Copyright (c) 1999-2007 Joerg Heckenbach - * Dwaine Garden - * - * This module is part of usbvision driver project. - * Updates to driver completed by Dwaine P. Garden - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "usbvision.h" - -#define DBG_I2C (1 << 0) - -static int i2c_debug; - -module_param(i2c_debug, int, 0644); /* debug_i2c_usb mode of the device driver */ -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -#define PDEBUG(level, fmt, args...) { \ - if (i2c_debug & (level)) \ - printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \ - __func__, __LINE__ , ## args); \ - } - -static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf, - short len); -static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf, - short len); - -static inline int try_write_address(struct i2c_adapter *i2c_adap, - unsigned char addr, int retries) -{ - struct usb_usbvision *usbvision; - int i, ret = -1; - char buf[4]; - - usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); - buf[0] = 0x00; - for (i = 0; i <= retries; i++) { - ret = (usbvision_i2c_write(usbvision, addr, buf, 1)); - if (ret == 1) - break; /* success! */ - udelay(5); - if (i == retries) /* no success */ - break; - udelay(10); - } - if (i) { - PDEBUG(DBG_I2C, "Needed %d retries for address %#2x", i, addr); - PDEBUG(DBG_I2C, "Maybe there's no device at this address"); - } - return ret; -} - -static inline int try_read_address(struct i2c_adapter *i2c_adap, - unsigned char addr, int retries) -{ - struct usb_usbvision *usbvision; - int i, ret = -1; - char buf[4]; - - usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); - for (i = 0; i <= retries; i++) { - ret = (usbvision_i2c_read(usbvision, addr, buf, 1)); - if (ret == 1) - break; /* success! */ - udelay(5); - if (i == retries) /* no success */ - break; - udelay(10); - } - if (i) { - PDEBUG(DBG_I2C, "Needed %d retries for address %#2x", i, addr); - PDEBUG(DBG_I2C, "Maybe there's no device at this address"); - } - return ret; -} - -static inline int usb_find_address(struct i2c_adapter *i2c_adap, - struct i2c_msg *msg, int retries, - unsigned char *add) -{ - unsigned short flags = msg->flags; - - unsigned char addr; - int ret; - if ((flags & I2C_M_TEN)) { - /* a ten bit address */ - addr = 0xf0 | ((msg->addr >> 7) & 0x03); - /* try extended address code... */ - ret = try_write_address(i2c_adap, addr, retries); - if (ret != 1) { - dev_err(&i2c_adap->dev, - "died at extended address code, while writing\n"); - return -EREMOTEIO; - } - add[0] = addr; - if (flags & I2C_M_RD) { - /* okay, now switch into reading mode */ - addr |= 0x01; - ret = try_read_address(i2c_adap, addr, retries); - if (ret != 1) { - dev_err(&i2c_adap->dev, - "died at extended address code, while reading\n"); - return -EREMOTEIO; - } - } - - } else { /* normal 7bit address */ - addr = (msg->addr << 1); - if (flags & I2C_M_RD) - addr |= 1; - - add[0] = addr; - if (flags & I2C_M_RD) - ret = try_read_address(i2c_adap, addr, retries); - else - ret = try_write_address(i2c_adap, addr, retries); - - if (ret != 1) - return -EREMOTEIO; - } - return 0; -} - -static int -usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) -{ - struct i2c_msg *pmsg; - struct usb_usbvision *usbvision; - int i, ret; - unsigned char addr = 0; - - usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); - - for (i = 0; i < num; i++) { - pmsg = &msgs[i]; - ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); - if (ret != 0) { - PDEBUG(DBG_I2C, "got NAK from device, message #%d", i); - return (ret < 0) ? ret : -EREMOTEIO; - } - - if (pmsg->flags & I2C_M_RD) { - /* read bytes into buffer */ - ret = (usbvision_i2c_read(usbvision, addr, pmsg->buf, pmsg->len)); - if (ret < pmsg->len) - return (ret < 0) ? ret : -EREMOTEIO; - } else { - /* write bytes from buffer */ - ret = (usbvision_i2c_write(usbvision, addr, pmsg->buf, pmsg->len)); - if (ret < pmsg->len) - return (ret < 0) ? ret : -EREMOTEIO; - } - } - return num; -} - -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; -} - -/* -----exported algorithm data: ------------------------------------- */ - -static struct i2c_algorithm usbvision_algo = { - .master_xfer = usbvision_i2c_xfer, - .smbus_xfer = NULL, - .functionality = functionality, -}; - - -/* ----------------------------------------------------------------------- */ -/* usbvision specific I2C functions */ -/* ----------------------------------------------------------------------- */ -static struct i2c_adapter i2c_adap_template; - -int usbvision_i2c_register(struct usb_usbvision *usbvision) -{ - static unsigned short saa711x_addrs[] = { - 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ - 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ - I2C_CLIENT_END }; - - if (usbvision->registered_i2c) - return 0; - - memcpy(&usbvision->i2c_adap, &i2c_adap_template, - sizeof(struct i2c_adapter)); - - sprintf(usbvision->i2c_adap.name, "%s-%d-%s", i2c_adap_template.name, - usbvision->dev->bus->busnum, usbvision->dev->devpath); - PDEBUG(DBG_I2C, "Adaptername: %s", usbvision->i2c_adap.name); - usbvision->i2c_adap.dev.parent = &usbvision->dev->dev; - - i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev); - - if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { - printk(KERN_ERR "usbvision_register: can't write reg\n"); - return -EBUSY; - } - - PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); - PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]"); - - /* register new adapter to i2c module... */ - - usbvision->i2c_adap.algo = &usbvision_algo; - - usbvision->i2c_adap.timeout = 100; /* default values, should */ - usbvision->i2c_adap.retries = 3; /* be replaced by defines */ - - i2c_add_adapter(&usbvision->i2c_adap); - - PDEBUG(DBG_I2C, "i2c bus for %s registered", usbvision->i2c_adap.name); - - /* Request the load of the i2c modules we need */ - switch (usbvision_device_data[usbvision->dev_model].codec) { - case CODEC_SAA7113: - case CODEC_SAA7111: - /* Without this delay the detection of the saa711x is - hit-and-miss. */ - mdelay(10); - v4l2_i2c_new_subdev(&usbvision->v4l2_dev, - &usbvision->i2c_adap, - "saa7115_auto", 0, saa711x_addrs); - break; - } - if (usbvision_device_data[usbvision->dev_model].tuner == 1) { - struct v4l2_subdev *sd; - enum v4l2_i2c_tuner_type type; - struct tuner_setup tun_setup; - - sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev, - &usbvision->i2c_adap, - "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); - /* depending on whether we found a demod or not, select - the tuner type. */ - type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; - - sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev, - &usbvision->i2c_adap, - "tuner", 0, v4l2_i2c_tuner_addrs(type)); - - if (sd == NULL) - return -ENODEV; - if (usbvision->tuner_type != -1) { - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = usbvision->tuner_type; - tun_setup.addr = v4l2_i2c_subdev_addr(sd); - call_all(usbvision, tuner, s_type_addr, &tun_setup); - } - } - usbvision->registered_i2c = 1; - - return 0; -} - -int usbvision_i2c_unregister(struct usb_usbvision *usbvision) -{ - if (!usbvision->registered_i2c) - return 0; - - i2c_del_adapter(&(usbvision->i2c_adap)); - usbvision->registered_i2c = 0; - - PDEBUG(DBG_I2C, "i2c bus for %s unregistered", usbvision->i2c_adap.name); - - return 0; -} - -static int -usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr, - char *buf, short len) -{ - int rc, retries; - - for (retries = 5;;) { - rc = usbvision_write_reg(usbvision, USBVISION_SER_ADRS, addr); - if (rc < 0) - return rc; - - /* Initiate byte read cycle */ - /* USBVISION_SER_CONT <- d0-d2 n. of bytes to r/w */ - /* d3 0=Wr 1=Rd */ - rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, - (len & 0x07) | 0x18); - if (rc < 0) - return rc; - - /* Test for Busy and ACK */ - do { - /* USBVISION_SER_CONT -> d4 == 0 busy */ - rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT); - } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */ - if (rc < 0) - return rc; - - /* USBVISION_SER_CONT -> d5 == 1 Not ack */ - if ((rc & 0x20) == 0) /* Ack? */ - break; - - /* I2C abort */ - rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00); - if (rc < 0) - return rc; - - if (--retries < 0) - return -1; - } - - switch (len) { - case 4: - buf[3] = usbvision_read_reg(usbvision, USBVISION_SER_DAT4); - case 3: - buf[2] = usbvision_read_reg(usbvision, USBVISION_SER_DAT3); - case 2: - buf[1] = usbvision_read_reg(usbvision, USBVISION_SER_DAT2); - case 1: - buf[0] = usbvision_read_reg(usbvision, USBVISION_SER_DAT1); - break; - default: - printk(KERN_ERR - "usbvision_i2c_read_max4: buffer length > 4\n"); - } - - if (i2c_debug & DBG_I2C) { - int idx; - - for (idx = 0; idx < len; idx++) - PDEBUG(DBG_I2C, "read %x from address %x", (unsigned char)buf[idx], addr); - } - return len; -} - - -static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision, - unsigned char addr, const char *buf, - short len) -{ - int rc, retries; - int i; - unsigned char value[6]; - unsigned char ser_cont; - - ser_cont = (len & 0x07) | 0x10; - - value[0] = addr; - value[1] = ser_cont; - for (i = 0; i < len; i++) - value[i + 2] = buf[i]; - - for (retries = 5;;) { - rc = usb_control_msg(usbvision->dev, - usb_sndctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_ENDPOINT, 0, - (__u16) USBVISION_SER_ADRS, value, - len + 2, HZ); - - if (rc < 0) - return rc; - - rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, - (len & 0x07) | 0x10); - if (rc < 0) - return rc; - - /* Test for Busy and ACK */ - do { - rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT); - } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */ - if (rc < 0) - return rc; - - if ((rc & 0x20) == 0) /* Ack? */ - break; - - /* I2C abort */ - usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00); - - if (--retries < 0) - return -1; - - } - - if (i2c_debug & DBG_I2C) { - int idx; - - for (idx = 0; idx < len; idx++) - PDEBUG(DBG_I2C, "wrote %x at address %x", (unsigned char)buf[idx], addr); - } - return len; -} - -static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf, - short len) -{ - char *buf_ptr = buf; - int retval; - int wrcount = 0; - int count; - int max_len = 4; - - while (len > 0) { - count = (len > max_len) ? max_len : len; - retval = usbvision_i2c_write_max4(usbvision, addr, buf_ptr, count); - if (retval > 0) { - len -= count; - buf_ptr += count; - wrcount += count; - } else - return (retval < 0) ? retval : -EFAULT; - } - return wrcount; -} - -static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf, - short len) -{ - char temp[4]; - int retval, i; - int rdcount = 0; - int count; - - while (len > 0) { - count = (len > 3) ? 4 : len; - retval = usbvision_i2c_read_max4(usbvision, addr, temp, count); - if (retval > 0) { - for (i = 0; i < len; i++) - buf[rdcount + i] = temp[i]; - len -= count; - rdcount += count; - } else - return (retval < 0) ? retval : -EFAULT; - } - return rdcount; -} - -static struct i2c_adapter i2c_adap_template = { - .owner = THIS_MODULE, - .name = "usbvision", -}; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/usbvision/usbvision-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1693 +0,0 @@ -/* - * USB USBVISION Video device driver 0.9.10 - * - * - * - * Copyright (c) 1999-2005 Joerg Heckenbach - * - * This module is part of usbvision driver project. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Let's call the version 0.... until compression decoding is completely - * implemented. - * - * This driver is written by Jose Ignacio Gijon and Joerg Heckenbach. - * It was based on USB CPiA driver written by Peter Pregler, - * Scott J. Bertin and Johannes Erdfelt - * Ideas are taken from bttv driver by Ralph Metzler, Marcus Metzler & - * Gerd Knorr and zoran 36120/36125 driver by Pauline Middelink - * Updates to driver completed by Dwaine P. Garden - * - * - * TODO: - * - use submit_urb for all setup packets - * - Fix memory settings for nt1004. It is 4 times as big as the - * nt1003 memory. - * - Add audio on endpoint 3 for nt1004 chip. - * Seems impossible, needs a codec interface. Which one? - * - Clean up the driver. - * - optimization for performance. - * - Add Videotext capability (VBI). Working on it..... - * - Check audio for other devices - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "usbvision.h" -#include "usbvision-cards.h" - -#define DRIVER_AUTHOR "Joerg Heckenbach , \ -Dwaine Garden " -#define DRIVER_NAME "usbvision" -#define DRIVER_ALIAS "USBVision" -#define DRIVER_DESC "USBVision USB Video Device Driver for Linux" -#define DRIVER_LICENSE "GPL" -#define USBVISION_DRIVER_VERSION_MAJOR 0 -#define USBVISION_DRIVER_VERSION_MINOR 9 -#define USBVISION_DRIVER_VERSION_PATCHLEVEL 10 -#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\ -USBVISION_DRIVER_VERSION_MINOR,\ -USBVISION_DRIVER_VERSION_PATCHLEVEL) -#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) \ -"." __stringify(USBVISION_DRIVER_VERSION_MINOR) \ -"." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL) - -#define ENABLE_HEXDUMP 0 /* Enable if you need it */ - - -#ifdef USBVISION_DEBUG - #define PDEBUG(level, fmt, args...) { \ - if (video_debug & (level)) \ - printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \ - __func__, __LINE__ , ## args); \ - } -#else - #define PDEBUG(level, fmt, args...) do {} while (0) -#endif - -#define DBG_IO (1 << 1) -#define DBG_PROBE (1 << 2) -#define DBG_MMAP (1 << 3) - -/* String operations */ -#define rmspace(str) while (*str == ' ') str++; -#define goto2next(str) while (*str != ' ') str++; while (*str == ' ') str++; - - -/* sequential number of usbvision device */ -static int usbvision_nr; - -static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { - { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, - { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, - { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, - { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, - { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, /* 1.5 ! */ - { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } -}; - -/* Function prototypes */ -static void usbvision_release(struct usb_usbvision *usbvision); - -/* Default initialization of device driver parameters */ -/* Set the default format for ISOC endpoint */ -static int isoc_mode = ISOC_MODE_COMPRESS; -/* Set the default Debug Mode of the device driver */ -static int video_debug; -/* Set the default device to power on at startup */ -static int power_on_at_open = 1; -/* Sequential Number of Video Device */ -static int video_nr = -1; -/* Sequential Number of Radio Device */ -static int radio_nr = -1; - -/* Grab parameters for the device driver */ - -/* Showing parameters under SYSFS */ -module_param(isoc_mode, int, 0444); -module_param(video_debug, int, 0444); -module_param(power_on_at_open, int, 0444); -module_param(video_nr, int, 0444); -module_param(radio_nr, int, 0444); - -MODULE_PARM_DESC(isoc_mode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); -MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)"); -MODULE_PARM_DESC(power_on_at_open, " Set the default device to power on when device is opened. Default: 1 (On)"); -MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); -MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); - - -/* Misc stuff */ -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); -MODULE_ALIAS(DRIVER_ALIAS); - - -/*****************************************************************************/ -/* SYSFS Code - Copied from the stv680.c usb module. */ -/* Device information is located at /sys/class/video4linux/video0 */ -/* Device parameters information is located at /sys/module/usbvision */ -/* Device USB Information is located at */ -/* /sys/bus/usb/drivers/USBVision Video Grabber */ -/*****************************************************************************/ - -#define YES_NO(x) ((x) ? "Yes" : "No") - -static inline struct usb_usbvision *cd_to_usbvision(struct device *cd) -{ - struct video_device *vdev = - container_of(cd, struct video_device, dev); - return video_get_drvdata(vdev); -} - -static ssize_t show_version(struct device *cd, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", USBVISION_VERSION_STRING); -} -static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); - -static ssize_t show_model(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = - container_of(cd, struct video_device, dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", - usbvision_device_data[usbvision->dev_model].model_string); -} -static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); - -static ssize_t show_hue(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = - container_of(cd, struct video_device, dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - struct v4l2_control ctrl; - ctrl.id = V4L2_CID_HUE; - ctrl.value = 0; - if (usbvision->user) - call_all(usbvision, core, g_ctrl, &ctrl); - return sprintf(buf, "%d\n", ctrl.value); -} -static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); - -static ssize_t show_contrast(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = - container_of(cd, struct video_device, dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - struct v4l2_control ctrl; - ctrl.id = V4L2_CID_CONTRAST; - ctrl.value = 0; - if (usbvision->user) - call_all(usbvision, core, g_ctrl, &ctrl); - return sprintf(buf, "%d\n", ctrl.value); -} -static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); - -static ssize_t show_brightness(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = - container_of(cd, struct video_device, dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - struct v4l2_control ctrl; - ctrl.id = V4L2_CID_BRIGHTNESS; - ctrl.value = 0; - if (usbvision->user) - call_all(usbvision, core, g_ctrl, &ctrl); - return sprintf(buf, "%d\n", ctrl.value); -} -static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); - -static ssize_t show_saturation(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = - container_of(cd, struct video_device, dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - struct v4l2_control ctrl; - ctrl.id = V4L2_CID_SATURATION; - ctrl.value = 0; - if (usbvision->user) - call_all(usbvision, core, g_ctrl, &ctrl); - return sprintf(buf, "%d\n", ctrl.value); -} -static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); - -static ssize_t show_streaming(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = - container_of(cd, struct video_device, dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", - YES_NO(usbvision->streaming == stream_on ? 1 : 0)); -} -static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); - -static ssize_t show_compression(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = - container_of(cd, struct video_device, dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", - YES_NO(usbvision->isoc_mode == ISOC_MODE_COMPRESS)); -} -static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); - -static ssize_t show_device_bridge(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = - container_of(cd, struct video_device, dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%d\n", usbvision->bridge_type); -} -static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); - -static void usbvision_create_sysfs(struct video_device *vdev) -{ - int res; - - if (!vdev) - return; - do { - res = device_create_file(&vdev->dev, &dev_attr_version); - if (res < 0) - break; - res = device_create_file(&vdev->dev, &dev_attr_model); - if (res < 0) - break; - res = device_create_file(&vdev->dev, &dev_attr_hue); - if (res < 0) - break; - res = device_create_file(&vdev->dev, &dev_attr_contrast); - if (res < 0) - break; - res = device_create_file(&vdev->dev, &dev_attr_brightness); - if (res < 0) - break; - res = device_create_file(&vdev->dev, &dev_attr_saturation); - if (res < 0) - break; - res = device_create_file(&vdev->dev, &dev_attr_streaming); - if (res < 0) - break; - res = device_create_file(&vdev->dev, &dev_attr_compression); - if (res < 0) - break; - res = device_create_file(&vdev->dev, &dev_attr_bridge); - if (res >= 0) - return; - } while (0); - - dev_err(&vdev->dev, "%s error: %d\n", __func__, res); -} - -static void usbvision_remove_sysfs(struct video_device *vdev) -{ - if (vdev) { - device_remove_file(&vdev->dev, &dev_attr_version); - device_remove_file(&vdev->dev, &dev_attr_model); - device_remove_file(&vdev->dev, &dev_attr_hue); - device_remove_file(&vdev->dev, &dev_attr_contrast); - device_remove_file(&vdev->dev, &dev_attr_brightness); - device_remove_file(&vdev->dev, &dev_attr_saturation); - device_remove_file(&vdev->dev, &dev_attr_streaming); - device_remove_file(&vdev->dev, &dev_attr_compression); - device_remove_file(&vdev->dev, &dev_attr_bridge); - } -} - -/* - * usbvision_open() - * - * This is part of Video 4 Linux API. The driver can be opened by one - * client only (checks internal counter 'usbvision->user'). The procedure - * then allocates buffers needed for video processing. - * - */ -static int usbvision_v4l2_open(struct file *file) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int err_code = 0; - - PDEBUG(DBG_IO, "open"); - - usbvision_reset_power_off_timer(usbvision); - - if (usbvision->user) - err_code = -EBUSY; - else { - /* Allocate memory for the scratch ring buffer */ - err_code = usbvision_scratch_alloc(usbvision); - if (isoc_mode == ISOC_MODE_COMPRESS) { - /* Allocate intermediate decompression buffers - only if needed */ - err_code = usbvision_decompress_alloc(usbvision); - } - if (err_code) { - /* Deallocate all buffers if trouble */ - usbvision_scratch_free(usbvision); - usbvision_decompress_free(usbvision); - } - } - - /* If so far no errors then we shall start the camera */ - if (!err_code) { - if (usbvision->power == 0) { - usbvision_power_on(usbvision); - usbvision_i2c_register(usbvision); - } - - /* Send init sequence only once, it's large! */ - if (!usbvision->initialized) { - int setup_ok = 0; - setup_ok = usbvision_setup(usbvision, isoc_mode); - if (setup_ok) - usbvision->initialized = 1; - else - err_code = -EBUSY; - } - - if (!err_code) { - usbvision_begin_streaming(usbvision); - err_code = usbvision_init_isoc(usbvision); - /* device must be initialized before isoc transfer */ - usbvision_muxsel(usbvision, 0); - usbvision->user++; - } else { - if (power_on_at_open) { - usbvision_i2c_unregister(usbvision); - usbvision_power_off(usbvision); - usbvision->initialized = 0; - } - } - } - - /* prepare queues */ - usbvision_empty_framequeues(usbvision); - - PDEBUG(DBG_IO, "success"); - return err_code; -} - -/* - * usbvision_v4l2_close() - * - * This is part of Video 4 Linux API. The procedure - * stops streaming and deallocates all buffers that were earlier - * allocated in usbvision_v4l2_open(). - * - */ -static int usbvision_v4l2_close(struct file *file) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - PDEBUG(DBG_IO, "close"); - - usbvision_audio_off(usbvision); - usbvision_restart_isoc(usbvision); - usbvision_stop_isoc(usbvision); - - usbvision_decompress_free(usbvision); - usbvision_frames_free(usbvision); - usbvision_empty_framequeues(usbvision); - usbvision_scratch_free(usbvision); - - usbvision->user--; - - if (power_on_at_open) { - /* power off in a little while - to avoid off/on every close/open short sequences */ - usbvision_set_power_off_timer(usbvision); - usbvision->initialized = 0; - } - - if (usbvision->remove_pending) { - printk(KERN_INFO "%s: Final disconnect\n", __func__); - usbvision_release(usbvision); - } - - PDEBUG(DBG_IO, "success"); - return 0; -} - - -/* - * usbvision_ioctl() - * - * This is part of Video 4 Linux API. The procedure handles ioctl() calls. - * - */ -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int err_code; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - /* NT100x has a 8-bit register space */ - err_code = usbvision_read_reg(usbvision, reg->reg&0xff); - if (err_code < 0) { - dev_err(&usbvision->vdev->dev, - "%s: VIDIOC_DBG_G_REGISTER failed: error %d\n", - __func__, err_code); - return err_code; - } - reg->val = err_code; - reg->size = 1; - return 0; -} - -static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int err_code; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - /* NT100x has a 8-bit register space */ - err_code = usbvision_write_reg(usbvision, reg->reg & 0xff, reg->val); - if (err_code < 0) { - dev_err(&usbvision->vdev->dev, - "%s: VIDIOC_DBG_S_REGISTER failed: error %d\n", - __func__, err_code); - return err_code; - } - return 0; -} -#endif - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *vc) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); - strlcpy(vc->card, - usbvision_device_data[usbvision->dev_model].model_string, - sizeof(vc->card)); - usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info)); - vc->version = USBVISION_DRIVER_VERSION; - vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); - return 0; -} - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *vi) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int chan; - - if (vi->index >= usbvision->video_inputs) - return -EINVAL; - if (usbvision->have_tuner) - chan = vi->index; - else - chan = vi->index + 1; /* skip Television string*/ - - /* Determine the requested input characteristics - specific for each usbvision card model */ - switch (chan) { - case 0: - if (usbvision_device_data[usbvision->dev_model].video_channels == 4) { - strcpy(vi->name, "White Video Input"); - } else { - strcpy(vi->name, "Television"); - vi->type = V4L2_INPUT_TYPE_TUNER; - vi->audioset = 1; - vi->tuner = chan; - vi->std = USBVISION_NORMS; - } - break; - case 1: - vi->type = V4L2_INPUT_TYPE_CAMERA; - if (usbvision_device_data[usbvision->dev_model].video_channels == 4) - strcpy(vi->name, "Green Video Input"); - else - strcpy(vi->name, "Composite Video Input"); - vi->std = V4L2_STD_PAL; - break; - case 2: - vi->type = V4L2_INPUT_TYPE_CAMERA; - if (usbvision_device_data[usbvision->dev_model].video_channels == 4) - strcpy(vi->name, "Yellow Video Input"); - else - strcpy(vi->name, "S-Video Input"); - vi->std = V4L2_STD_PAL; - break; - case 3: - vi->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(vi->name, "Red Video Input"); - vi->std = V4L2_STD_PAL; - break; - } - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *input) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - *input = usbvision->ctl_input; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int input) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - if (input >= usbvision->video_inputs) - return -EINVAL; - - usbvision_muxsel(usbvision, input); - usbvision_set_input(usbvision); - usbvision_set_output(usbvision, - usbvision->curwidth, - usbvision->curheight); - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - usbvision->tvnorm_id = *id; - - call_all(usbvision, core, s_std, usbvision->tvnorm_id); - /* propagate the change to the decoder */ - usbvision_muxsel(usbvision, usbvision->ctl_input); - - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *vt) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - if (!usbvision->have_tuner || vt->index) /* Only tuner 0 */ - return -EINVAL; - if (usbvision->radio) { - strcpy(vt->name, "Radio"); - vt->type = V4L2_TUNER_RADIO; - } else { - strcpy(vt->name, "Television"); - } - /* Let clients fill in the remainder of this struct */ - call_all(usbvision, tuner, g_tuner, vt); - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *vt) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - /* Only no or one tuner for now */ - if (!usbvision->have_tuner || vt->index) - return -EINVAL; - /* let clients handle this */ - call_all(usbvision, tuner, s_tuner, vt); - - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - freq->tuner = 0; /* Only one tuner */ - if (usbvision->radio) - freq->type = V4L2_TUNER_RADIO; - else - freq->type = V4L2_TUNER_ANALOG_TV; - freq->frequency = usbvision->freq; - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - /* Only no or one tuner for now */ - if (!usbvision->have_tuner || freq->tuner) - return -EINVAL; - - usbvision->freq = freq->frequency; - call_all(usbvision, tuner, s_frequency, freq); - - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - if (usbvision->radio) - strcpy(a->name, "Radio"); - else - strcpy(a->name, "TV"); - - return 0; -} - -static int vidioc_s_audio(struct file *file, void *fh, - struct v4l2_audio *a) -{ - if (a->index) - return -EINVAL; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *ctrl) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - call_all(usbvision, core, queryctrl, ctrl); - - if (!ctrl->type) - return -EINVAL; - - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - call_all(usbvision, core, g_ctrl, ctrl); - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - call_all(usbvision, core, s_ctrl, ctrl); - return 0; -} - -static int vidioc_reqbufs(struct file *file, - void *priv, struct v4l2_requestbuffers *vr) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int ret; - - RESTRICT_TO_RANGE(vr->count, 1, USBVISION_NUMFRAMES); - - /* Check input validity: - the user must do a VIDEO CAPTURE and MMAP method. */ - if (vr->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (usbvision->streaming == stream_on) { - ret = usbvision_stream_interrupt(usbvision); - if (ret) - return ret; - } - - usbvision_frames_free(usbvision); - usbvision_empty_framequeues(usbvision); - vr->count = usbvision_frames_alloc(usbvision, vr->count); - - usbvision->cur_frame = NULL; - - return 0; -} - -static int vidioc_querybuf(struct file *file, - void *priv, struct v4l2_buffer *vb) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - struct usbvision_frame *frame; - - /* FIXME : must control - that buffers are mapped (VIDIOC_REQBUFS has been called) */ - if (vb->index >= usbvision->num_frames) - return -EINVAL; - /* Updating the corresponding frame state */ - vb->flags = 0; - frame = &usbvision->frame[vb->index]; - if (frame->grabstate >= frame_state_ready) - vb->flags |= V4L2_BUF_FLAG_QUEUED; - if (frame->grabstate >= frame_state_done) - vb->flags |= V4L2_BUF_FLAG_DONE; - if (frame->grabstate == frame_state_unused) - vb->flags |= V4L2_BUF_FLAG_MAPPED; - vb->memory = V4L2_MEMORY_MMAP; - - vb->m.offset = vb->index * PAGE_ALIGN(usbvision->max_frame_size); - - vb->memory = V4L2_MEMORY_MMAP; - vb->field = V4L2_FIELD_NONE; - vb->length = usbvision->curwidth * - usbvision->curheight * - usbvision->palette.bytes_per_pixel; - vb->timestamp = usbvision->frame[vb->index].timestamp; - vb->sequence = usbvision->frame[vb->index].sequence; - return 0; -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *vb) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - struct usbvision_frame *frame; - unsigned long lock_flags; - - /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */ - if (vb->index >= usbvision->num_frames) - return -EINVAL; - - frame = &usbvision->frame[vb->index]; - - if (frame->grabstate != frame_state_unused) - return -EAGAIN; - - /* Mark it as ready and enqueue frame */ - frame->grabstate = frame_state_ready; - frame->scanstate = scan_state_scanning; - frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ - - vb->flags &= ~V4L2_BUF_FLAG_DONE; - - /* set v4l2_format index */ - frame->v4l2_format = usbvision->palette; - - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - - return 0; -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *vb) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int ret; - struct usbvision_frame *f; - unsigned long lock_flags; - - if (list_empty(&(usbvision->outqueue))) { - if (usbvision->streaming == stream_idle) - return -EINVAL; - ret = wait_event_interruptible - (usbvision->wait_frame, - !list_empty(&(usbvision->outqueue))); - if (ret) - return ret; - } - - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - f = list_entry(usbvision->outqueue.next, - struct usbvision_frame, frame); - list_del(usbvision->outqueue.next); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - - f->grabstate = frame_state_unused; - - vb->memory = V4L2_MEMORY_MMAP; - vb->flags = V4L2_BUF_FLAG_MAPPED | - V4L2_BUF_FLAG_QUEUED | - V4L2_BUF_FLAG_DONE; - vb->index = f->index; - vb->sequence = f->sequence; - vb->timestamp = f->timestamp; - vb->field = V4L2_FIELD_NONE; - vb->bytesused = f->scanlength; - - return 0; -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - usbvision->streaming = stream_on; - call_all(usbvision, video, s_stream, 1); - - return 0; -} - -static int vidioc_streamoff(struct file *file, - void *priv, enum v4l2_buf_type type) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (usbvision->streaming == stream_on) { - usbvision_stream_interrupt(usbvision); - /* Stop all video streamings */ - call_all(usbvision, video, s_stream, 0); - } - usbvision_empty_framequeues(usbvision); - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *vfd) -{ - if (vfd->index >= USBVISION_SUPPORTED_PALETTES - 1) - return -EINVAL; - strcpy(vfd->description, usbvision_v4l2_format[vfd->index].desc); - vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *vf) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - vf->fmt.pix.width = usbvision->curwidth; - vf->fmt.pix.height = usbvision->curheight; - vf->fmt.pix.pixelformat = usbvision->palette.format; - vf->fmt.pix.bytesperline = - usbvision->curwidth * usbvision->palette.bytes_per_pixel; - vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline * usbvision->curheight; - vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *vf) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int format_idx; - - /* Find requested format in available ones */ - for (format_idx = 0; format_idx < USBVISION_SUPPORTED_PALETTES; format_idx++) { - if (vf->fmt.pix.pixelformat == - usbvision_v4l2_format[format_idx].format) { - usbvision->palette = usbvision_v4l2_format[format_idx]; - break; - } - } - /* robustness */ - if (format_idx == USBVISION_SUPPORTED_PALETTES) - return -EINVAL; - RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); - RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); - - vf->fmt.pix.bytesperline = vf->fmt.pix.width* - usbvision->palette.bytes_per_pixel; - vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height; - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *vf) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int ret; - - ret = vidioc_try_fmt_vid_cap(file, priv, vf); - if (ret) - return ret; - - /* stop io in case it is already in progress */ - if (usbvision->streaming == stream_on) { - ret = usbvision_stream_interrupt(usbvision); - if (ret) - return ret; - } - usbvision_frames_free(usbvision); - usbvision_empty_framequeues(usbvision); - - usbvision->cur_frame = NULL; - - /* by now we are committed to the new data... */ - usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); - - return 0; -} - -static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int noblock = file->f_flags & O_NONBLOCK; - unsigned long lock_flags; - int ret, i; - struct usbvision_frame *frame; - - PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __func__, - (unsigned long)count, noblock); - - if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) - return -EFAULT; - - /* This entry point is compatible with the mmap routines - so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF - to get frames or call read on the device. */ - if (!usbvision->num_frames) { - /* First, allocate some frames to work with - if this has not been done with VIDIOC_REQBUF */ - usbvision_frames_free(usbvision); - usbvision_empty_framequeues(usbvision); - usbvision_frames_alloc(usbvision, USBVISION_NUMFRAMES); - } - - if (usbvision->streaming != stream_on) { - /* no stream is running, make it running ! */ - usbvision->streaming = stream_on; - call_all(usbvision, video, s_stream, 1); - } - - /* Then, enqueue as many frames as possible - (like a user of VIDIOC_QBUF would do) */ - for (i = 0; i < usbvision->num_frames; i++) { - frame = &usbvision->frame[i]; - if (frame->grabstate == frame_state_unused) { - /* Mark it as ready and enqueue frame */ - frame->grabstate = frame_state_ready; - frame->scanstate = scan_state_scanning; - /* Accumulated in usbvision_parse_data() */ - frame->scanlength = 0; - - /* set v4l2_format index */ - frame->v4l2_format = usbvision->palette; - - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - list_add_tail(&frame->frame, &usbvision->inqueue); - spin_unlock_irqrestore(&usbvision->queue_lock, - lock_flags); - } - } - - /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */ - if (list_empty(&(usbvision->outqueue))) { - if (noblock) - return -EAGAIN; - - ret = wait_event_interruptible - (usbvision->wait_frame, - !list_empty(&(usbvision->outqueue))); - if (ret) - return ret; - } - - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - frame = list_entry(usbvision->outqueue.next, - struct usbvision_frame, frame); - list_del(usbvision->outqueue.next); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - - /* An error returns an empty frame */ - if (frame->grabstate == frame_state_error) { - frame->bytes_read = 0; - return 0; - } - - PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", - __func__, - frame->index, frame->bytes_read, frame->scanlength); - - /* copy bytes to user space; we allow for partials reads */ - if ((count + frame->bytes_read) > (unsigned long)frame->scanlength) - count = frame->scanlength - frame->bytes_read; - - if (copy_to_user(buf, frame->data + frame->bytes_read, count)) - return -EFAULT; - - frame->bytes_read += count; - PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", - __func__, - (unsigned long)count, frame->bytes_read); - - /* For now, forget the frame if it has not been read in one shot. */ -/* if (frame->bytes_read >= frame->scanlength) {*/ /* All data has been read */ - frame->bytes_read = 0; - - /* Mark it as available to be used again. */ - frame->grabstate = frame_state_unused; -/* } */ - - return count; -} - -static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - struct usb_usbvision *usbvision = video_drvdata(file); - - PDEBUG(DBG_MMAP, "mmap"); - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -EFAULT; - - if (!(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(usbvision->max_frame_size)) { - return -EINVAL; - } - - for (i = 0; i < usbvision->num_frames; i++) { - if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == - vma->vm_pgoff) - break; - } - if (i == usbvision->num_frames) { - PDEBUG(DBG_MMAP, - "mmap: user supplied mapping address is out of range"); - return -EINVAL; - } - - /* VM_IO is eventually going to replace PageReserved altogether */ - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ - - pos = usbvision->frame[i].data; - while (size > 0) { - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed"); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return 0; -} - - -/* - * Here comes the stuff for radio on usbvision based devices - * - */ -static int usbvision_radio_open(struct file *file) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int err_code = 0; - - PDEBUG(DBG_IO, "%s:", __func__); - - if (usbvision->user) { - dev_err(&usbvision->rdev->dev, - "%s: Someone tried to open an already opened USBVision Radio!\n", - __func__); - err_code = -EBUSY; - } else { - if (power_on_at_open) { - usbvision_reset_power_off_timer(usbvision); - if (usbvision->power == 0) { - usbvision_power_on(usbvision); - usbvision_i2c_register(usbvision); - } - } - - /* Alternate interface 1 is is the biggest frame size */ - err_code = usbvision_set_alternate(usbvision); - if (err_code < 0) { - usbvision->last_error = err_code; - err_code = -EBUSY; - goto out; - } - - /* If so far no errors then we shall start the radio */ - usbvision->radio = 1; - call_all(usbvision, tuner, s_radio); - usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); - usbvision->user++; - } - - if (err_code) { - if (power_on_at_open) { - usbvision_i2c_unregister(usbvision); - usbvision_power_off(usbvision); - usbvision->initialized = 0; - } - } -out: - return err_code; -} - - -static int usbvision_radio_close(struct file *file) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - int err_code = 0; - - PDEBUG(DBG_IO, ""); - - /* Set packet size to 0 */ - usbvision->iface_alt = 0; - err_code = usb_set_interface(usbvision->dev, usbvision->iface, - usbvision->iface_alt); - - usbvision_audio_off(usbvision); - usbvision->radio = 0; - usbvision->user--; - - if (power_on_at_open) { - usbvision_set_power_off_timer(usbvision); - usbvision->initialized = 0; - } - - if (usbvision->remove_pending) { - printk(KERN_INFO "%s: Final disconnect\n", __func__); - usbvision_release(usbvision); - } - - PDEBUG(DBG_IO, "success"); - return err_code; -} - -/* Video registration stuff */ - -/* Video template */ -static const struct v4l2_file_operations usbvision_fops = { - .owner = THIS_MODULE, - .open = usbvision_v4l2_open, - .release = usbvision_v4l2_close, - .read = usbvision_v4l2_read, - .mmap = usbvision_v4l2_mmap, - .unlocked_ioctl = video_ioctl2, -/* .poll = video_poll, */ -}; - -static const struct v4l2_ioctl_ops usbvision_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif -}; - -static struct video_device usbvision_video_template = { - .fops = &usbvision_fops, - .ioctl_ops = &usbvision_ioctl_ops, - .name = "usbvision-video", - .release = video_device_release, - .tvnorms = USBVISION_NORMS, - .current_norm = V4L2_STD_PAL -}; - - -/* Radio template */ -static const struct v4l2_file_operations usbvision_radio_fops = { - .owner = THIS_MODULE, - .open = usbvision_radio_open, - .release = usbvision_radio_close, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -}; - -static struct video_device usbvision_radio_template = { - .fops = &usbvision_radio_fops, - .name = "usbvision-radio", - .release = video_device_release, - .ioctl_ops = &usbvision_radio_ioctl_ops, - - .tvnorms = USBVISION_NORMS, - .current_norm = V4L2_STD_PAL -}; - - -static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision, - struct video_device *vdev_template, - char *name) -{ - struct usb_device *usb_dev = usbvision->dev; - struct video_device *vdev; - - if (usb_dev == NULL) { - dev_err(&usbvision->dev->dev, - "%s: usbvision->dev is not set\n", __func__); - return NULL; - } - - vdev = video_device_alloc(); - if (NULL == vdev) - return NULL; - *vdev = *vdev_template; - vdev->lock = &usbvision->v4l2_lock; - vdev->v4l2_dev = &usbvision->v4l2_dev; - snprintf(vdev->name, sizeof(vdev->name), "%s", name); - video_set_drvdata(vdev, usbvision); - return vdev; -} - -/* unregister video4linux devices */ -static void usbvision_unregister_video(struct usb_usbvision *usbvision) -{ - /* Radio Device: */ - if (usbvision->rdev) { - PDEBUG(DBG_PROBE, "unregister %s [v4l2]", - video_device_node_name(usbvision->rdev)); - if (video_is_registered(usbvision->rdev)) - video_unregister_device(usbvision->rdev); - else - video_device_release(usbvision->rdev); - usbvision->rdev = NULL; - } - - /* Video Device: */ - if (usbvision->vdev) { - PDEBUG(DBG_PROBE, "unregister %s [v4l2]", - video_device_node_name(usbvision->vdev)); - if (video_is_registered(usbvision->vdev)) - video_unregister_device(usbvision->vdev); - else - video_device_release(usbvision->vdev); - usbvision->vdev = NULL; - } -} - -/* register video4linux devices */ -static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) -{ - /* Video Device: */ - usbvision->vdev = usbvision_vdev_init(usbvision, - &usbvision_video_template, - "USBVision Video"); - if (usbvision->vdev == NULL) - goto err_exit; - if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0) - goto err_exit; - printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n", - usbvision->nr, video_device_node_name(usbvision->vdev)); - - /* Radio Device: */ - if (usbvision_device_data[usbvision->dev_model].radio) { - /* usbvision has radio */ - usbvision->rdev = usbvision_vdev_init(usbvision, - &usbvision_radio_template, - "USBVision Radio"); - if (usbvision->rdev == NULL) - goto err_exit; - if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0) - goto err_exit; - printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n", - usbvision->nr, video_device_node_name(usbvision->rdev)); - } - /* all done */ - return 0; - - err_exit: - dev_err(&usbvision->dev->dev, - "USBVision[%d]: video_register_device() failed\n", - usbvision->nr); - usbvision_unregister_video(usbvision); - return -1; -} - -/* - * usbvision_alloc() - * - * This code allocates the struct usb_usbvision. - * It is filled with default values. - * - * Returns NULL on error, a pointer to usb_usbvision else. - * - */ -static struct usb_usbvision *usbvision_alloc(struct usb_device *dev, - struct usb_interface *intf) -{ - struct usb_usbvision *usbvision; - - usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL); - if (usbvision == NULL) - return NULL; - - usbvision->dev = dev; - if (v4l2_device_register(&intf->dev, &usbvision->v4l2_dev)) - goto err_free; - - mutex_init(&usbvision->v4l2_lock); - - /* prepare control urb for control messages during interrupts */ - usbvision->ctrl_urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); - if (usbvision->ctrl_urb == NULL) - goto err_unreg; - init_waitqueue_head(&usbvision->ctrl_urb_wq); - - usbvision_init_power_off_timer(usbvision); - - return usbvision; - -err_unreg: - v4l2_device_unregister(&usbvision->v4l2_dev); -err_free: - kfree(usbvision); - return NULL; -} - -/* - * usbvision_release() - * - * This code does final release of struct usb_usbvision. This happens - * after the device is disconnected -and- all clients closed their files. - * - */ -static void usbvision_release(struct usb_usbvision *usbvision) -{ - PDEBUG(DBG_PROBE, ""); - - usbvision_reset_power_off_timer(usbvision); - - usbvision->initialized = 0; - - usbvision_remove_sysfs(usbvision->vdev); - usbvision_unregister_video(usbvision); - - usb_free_urb(usbvision->ctrl_urb); - - v4l2_device_unregister(&usbvision->v4l2_dev); - kfree(usbvision); - - PDEBUG(DBG_PROBE, "success"); -} - - -/*********************** usb interface **********************************/ - -static void usbvision_configure_video(struct usb_usbvision *usbvision) -{ - int model; - - if (usbvision == NULL) - return; - - model = usbvision->dev_model; - usbvision->palette = usbvision_v4l2_format[2]; /* V4L2_PIX_FMT_RGB24; */ - - if (usbvision_device_data[usbvision->dev_model].vin_reg2_override) { - usbvision->vin_reg2_preset = - usbvision_device_data[usbvision->dev_model].vin_reg2; - } else { - usbvision->vin_reg2_preset = 0; - } - - usbvision->tvnorm_id = usbvision_device_data[model].video_norm; - - usbvision->video_inputs = usbvision_device_data[model].video_channels; - usbvision->ctl_input = 0; - - /* This should be here to make i2c clients to be able to register */ - /* first switch off audio */ - usbvision_audio_off(usbvision); - if (!power_on_at_open) { - /* and then power up the noisy tuner */ - usbvision_power_on(usbvision); - usbvision_i2c_register(usbvision); - } -} - -/* - * usbvision_probe() - * - * This procedure queries device descriptor and accepts the interface - * if it looks like USBVISION video device - * - */ -static int __devinit usbvision_probe(struct usb_interface *intf, - const struct usb_device_id *devid) -{ - struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf)); - struct usb_interface *uif; - __u8 ifnum = intf->altsetting->desc.bInterfaceNumber; - const struct usb_host_interface *interface; - struct usb_usbvision *usbvision = NULL; - const struct usb_endpoint_descriptor *endpoint; - int model, i; - - PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", - dev->descriptor.idVendor, - dev->descriptor.idProduct, ifnum); - - model = devid->driver_info; - if (model < 0 || model >= usbvision_device_data_size) { - PDEBUG(DBG_PROBE, "model out of bounds %d", model); - return -ENODEV; - } - printk(KERN_INFO "%s: %s found\n", __func__, - usbvision_device_data[model].model_string); - - if (usbvision_device_data[model].interface >= 0) - interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0]; - else - interface = &dev->actconfig->interface[ifnum]->altsetting[0]; - endpoint = &interface->endpoint[1].desc; - if (!usb_endpoint_xfer_isoc(endpoint)) { - dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n", - __func__, ifnum); - dev_err(&intf->dev, "%s: Endpoint attributes %d", - __func__, endpoint->bmAttributes); - return -ENODEV; - } - if (usb_endpoint_dir_out(endpoint)) { - dev_err(&intf->dev, "%s: interface %d. has ISO OUT endpoint!\n", - __func__, ifnum); - return -ENODEV; - } - - usbvision = usbvision_alloc(dev, intf); - if (usbvision == NULL) { - dev_err(&intf->dev, "%s: couldn't allocate USBVision struct\n", __func__); - return -ENOMEM; - } - - if (dev->descriptor.bNumConfigurations > 1) - usbvision->bridge_type = BRIDGE_NT1004; - else if (model == DAZZLE_DVC_90_REV_1_SECAM) - usbvision->bridge_type = BRIDGE_NT1005; - else - usbvision->bridge_type = BRIDGE_NT1003; - PDEBUG(DBG_PROBE, "bridge_type %d", usbvision->bridge_type); - - /* compute alternate max packet sizes */ - uif = dev->actconfig->interface[0]; - - usbvision->num_alt = uif->num_altsetting; - PDEBUG(DBG_PROBE, "Alternate settings: %i", usbvision->num_alt); - usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL); - if (usbvision->alt_max_pkt_size == NULL) { - dev_err(&intf->dev, "usbvision: out of memory!\n"); - return -ENOMEM; - } - - for (i = 0; i < usbvision->num_alt; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc. - wMaxPacketSize); - usbvision->alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i", i, - usbvision->alt_max_pkt_size[i]); - } - - - usbvision->nr = usbvision_nr++; - - usbvision->have_tuner = usbvision_device_data[model].tuner; - if (usbvision->have_tuner) - usbvision->tuner_type = usbvision_device_data[model].tuner_type; - - usbvision->dev_model = model; - usbvision->remove_pending = 0; - usbvision->iface = ifnum; - usbvision->iface_alt = 0; - usbvision->video_endp = endpoint->bEndpointAddress; - usbvision->isoc_packet_size = 0; - usbvision->usb_bandwidth = 0; - usbvision->user = 0; - usbvision->streaming = stream_off; - usbvision_configure_video(usbvision); - usbvision_register_video(usbvision); - - usbvision_create_sysfs(usbvision->vdev); - - PDEBUG(DBG_PROBE, "success"); - return 0; -} - - -/* - * usbvision_disconnect() - * - * This procedure stops all driver activity, deallocates interface-private - * structure (pointed by 'ptr') and after that driver should be removable - * with no ill consequences. - * - */ -static void __devexit usbvision_disconnect(struct usb_interface *intf) -{ - struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf)); - - PDEBUG(DBG_PROBE, ""); - - if (usbvision == NULL) { - pr_err("%s: usb_get_intfdata() failed\n", __func__); - return; - } - - mutex_lock(&usbvision->v4l2_lock); - - /* At this time we ask to cancel outstanding URBs */ - usbvision_stop_isoc(usbvision); - - v4l2_device_disconnect(&usbvision->v4l2_dev); - - if (usbvision->power) { - usbvision_i2c_unregister(usbvision); - usbvision_power_off(usbvision); - } - usbvision->remove_pending = 1; /* Now all ISO data will be ignored */ - - usb_put_dev(usbvision->dev); - usbvision->dev = NULL; /* USB device is no more */ - - mutex_unlock(&usbvision->v4l2_lock); - - if (usbvision->user) { - printk(KERN_INFO "%s: In use, disconnect pending\n", - __func__); - wake_up_interruptible(&usbvision->wait_frame); - wake_up_interruptible(&usbvision->wait_stream); - } else { - usbvision_release(usbvision); - } - - PDEBUG(DBG_PROBE, "success"); -} - -static struct usb_driver usbvision_driver = { - .name = "usbvision", - .id_table = usbvision_table, - .probe = usbvision_probe, - .disconnect = __devexit_p(usbvision_disconnect), -}; - -/* - * usbvision_init() - * - * This code is run to initialize the driver. - * - */ -static int __init usbvision_init(void) -{ - int err_code; - - PDEBUG(DBG_PROBE, ""); - - PDEBUG(DBG_IO, "IO debugging is enabled [video]"); - PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]"); - PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]"); - - /* disable planar mode support unless compression enabled */ - if (isoc_mode != ISOC_MODE_COMPRESS) { - /* FIXME : not the right way to set supported flag */ - usbvision_v4l2_format[6].supported = 0; /* V4L2_PIX_FMT_YVU420 */ - usbvision_v4l2_format[7].supported = 0; /* V4L2_PIX_FMT_YUV422P */ - } - - err_code = usb_register(&usbvision_driver); - - if (err_code == 0) { - printk(KERN_INFO DRIVER_DESC " : " USBVISION_VERSION_STRING "\n"); - PDEBUG(DBG_PROBE, "success"); - } - return err_code; -} - -static void __exit usbvision_exit(void) -{ - PDEBUG(DBG_PROBE, ""); - - usb_deregister(&usbvision_driver); - PDEBUG(DBG_PROBE, "success"); -} - -module_init(usbvision_init); -module_exit(usbvision_exit); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -config USB_VIDEO_CLASS - tristate "USB Video Class (UVC)" - ---help--- - Support for the USB Video Class (UVC). Currently only video - input devices, such as webcams, are supported. - - For more information see: - -config USB_VIDEO_CLASS_INPUT_EVDEV - bool "UVC input events device support" - default y - depends on USB_VIDEO_CLASS=INPUT || INPUT=y - ---help--- - This option makes USB Video Class devices register an input device - to report button events. - - If you are in doubt, say Y. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \ - uvc_status.o uvc_isight.o -obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_ctrl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_ctrl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_ctrl.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_ctrl.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1820 +0,0 @@ -/* - * uvc_ctrl.c -- USB Video Class driver - Controls - * - * Copyright (C) 2005-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.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, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "uvcvideo.h" - -#define UVC_CTRL_DATA_CURRENT 0 -#define UVC_CTRL_DATA_BACKUP 1 -#define UVC_CTRL_DATA_MIN 2 -#define UVC_CTRL_DATA_MAX 3 -#define UVC_CTRL_DATA_RES 4 -#define UVC_CTRL_DATA_DEF 5 -#define UVC_CTRL_DATA_LAST 6 - -/* ------------------------------------------------------------------------ - * Controls - */ - -static struct uvc_control_info uvc_ctrls[] = { - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_BRIGHTNESS_CONTROL, - .index = 0, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_CONTRAST_CONTROL, - .index = 1, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_HUE_CONTROL, - .index = 2, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_SATURATION_CONTROL, - .index = 3, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_SHARPNESS_CONTROL, - .index = 4, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_GAMMA_CONTROL, - .index = 5, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL, - .index = 6, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, - .index = 7, - .size = 4, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL, - .index = 8, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_GAIN_CONTROL, - .index = 9, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, - .index = 10, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_HUE_AUTO_CONTROL, - .index = 11, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, - .index = 12, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, - .index = 13, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_DIGITAL_MULTIPLIER_CONTROL, - .index = 14, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL, - .index = 15, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL, - .index = 16, - .size = 1, - .flags = UVC_CONTROL_GET_CUR, - }, - { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL, - .index = 17, - .size = 1, - .flags = UVC_CONTROL_GET_CUR, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_SCANNING_MODE_CONTROL, - .index = 0, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_AE_MODE_CONTROL, - .index = 1, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_AE_PRIORITY_CONTROL, - .index = 2, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, - .index = 3, - .size = 4, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL, - .index = 4, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL, - .index = 5, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_FOCUS_RELATIVE_CONTROL, - .index = 6, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN - | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES - | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL, - .index = 7, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_IRIS_RELATIVE_CONTROL, - .index = 8, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL, - .index = 9, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_ZOOM_RELATIVE_CONTROL, - .index = 10, - .size = 3, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN - | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES - | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, - .index = 11, - .size = 8, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, - .index = 12, - .size = 4, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN - | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES - | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_ROLL_ABSOLUTE_CONTROL, - .index = 13, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE - | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_ROLL_RELATIVE_CONTROL, - .index = 14, - .size = 2, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN - | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES - | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_FOCUS_AUTO_CONTROL, - .index = 17, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, - }, - { - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_PRIVACY_CONTROL, - .index = 18, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, - }, -}; - -static struct uvc_menu_info power_line_frequency_controls[] = { - { 0, "Disabled" }, - { 1, "50 Hz" }, - { 2, "60 Hz" }, -}; - -static struct uvc_menu_info exposure_auto_controls[] = { - { 2, "Auto Mode" }, - { 1, "Manual Mode" }, - { 4, "Shutter Priority Mode" }, - { 8, "Aperture Priority Mode" }, -}; - -static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, - __u8 query, const __u8 *data) -{ - __s8 zoom = (__s8)data[0]; - - switch (query) { - case UVC_GET_CUR: - return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]); - - case UVC_GET_MIN: - case UVC_GET_MAX: - case UVC_GET_RES: - case UVC_GET_DEF: - default: - return data[2]; - } -} - -static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, - __s32 value, __u8 *data) -{ - data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; - data[2] = min((int)abs(value), 0xff); -} - -static struct uvc_control_mapping uvc_ctrl_mappings[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_BRIGHTNESS_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_SIGNED, - }, - { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_CONTRAST_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_HUE, - .name = "Hue", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_HUE_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_SIGNED, - }, - { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_SATURATION_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_SHARPNESS, - .name = "Sharpness", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_SHARPNESS_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_GAMMA, - .name = "Gamma", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_GAMMA_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_BACKLIGHT_COMPENSATION, - .name = "Backlight Compensation", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_GAIN, - .name = "Gain", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_GAIN_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .name = "Power Line Frequency", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, - .size = 2, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_MENU, - .data_type = UVC_CTRL_DATA_TYPE_ENUM, - .menu_info = power_line_frequency_controls, - .menu_count = ARRAY_SIZE(power_line_frequency_controls), - }, - { - .id = V4L2_CID_HUE_AUTO, - .name = "Hue, Auto", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_HUE_AUTO_CONTROL, - .size = 1, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, - .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, - }, - { - .id = V4L2_CID_EXPOSURE_AUTO, - .name = "Exposure, Auto", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_AE_MODE_CONTROL, - .size = 4, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_MENU, - .data_type = UVC_CTRL_DATA_TYPE_BITMASK, - .menu_info = exposure_auto_controls, - .menu_count = ARRAY_SIZE(exposure_auto_controls), - }, - { - .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY, - .name = "Exposure, Auto Priority", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_AE_PRIORITY_CONTROL, - .size = 1, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, - .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, - }, - { - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .name = "Exposure (Absolute)", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, - .size = 32, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .name = "White Balance Temperature, Auto", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, - .size = 1, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, - .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, - }, - { - .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, - .name = "White Balance Temperature", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .name = "White Balance Component, Auto", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, - .size = 1, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, - .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .name = "White Balance Blue Component", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_SIGNED, - }, - { - .id = V4L2_CID_RED_BALANCE, - .name = "White Balance Red Component", - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, - .size = 16, - .offset = 16, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_SIGNED, - }, - { - .id = V4L2_CID_FOCUS_ABSOLUTE, - .name = "Focus (absolute)", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_FOCUS_AUTO, - .name = "Focus, Auto", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_FOCUS_AUTO_CONTROL, - .size = 1, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, - .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, - }, - { - .id = V4L2_CID_IRIS_ABSOLUTE, - .name = "Iris, Absolute", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_IRIS_RELATIVE, - .name = "Iris, Relative", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_IRIS_RELATIVE_CONTROL, - .size = 8, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_SIGNED, - }, - { - .id = V4L2_CID_ZOOM_ABSOLUTE, - .name = "Zoom, Absolute", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL, - .size = 16, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_ZOOM_CONTINUOUS, - .name = "Zoom, Continuous", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_ZOOM_RELATIVE_CONTROL, - .size = 0, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_SIGNED, - .get = uvc_ctrl_get_zoom, - .set = uvc_ctrl_set_zoom, - }, - { - .id = V4L2_CID_PAN_ABSOLUTE, - .name = "Pan (Absolute)", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, - .size = 32, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_TILT_ABSOLUTE, - .name = "Tilt (Absolute)", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, - .size = 32, - .offset = 32, - .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, - }, - { - .id = V4L2_CID_PRIVACY, - .name = "Privacy", - .entity = UVC_GUID_UVC_CAMERA, - .selector = UVC_CT_PRIVACY_CONTROL, - .size = 1, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, - .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, - }, -}; - -/* ------------------------------------------------------------------------ - * Utility functions - */ - -static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id) -{ - return ctrl->uvc_data + id * ctrl->info.size; -} - -static inline int uvc_test_bit(const __u8 *data, int bit) -{ - return (data[bit >> 3] >> (bit & 7)) & 1; -} - -static inline void uvc_clear_bit(__u8 *data, int bit) -{ - data[bit >> 3] &= ~(1 << (bit & 7)); -} - -/* Extract the bit string specified by mapping->offset and mapping->size - * from the little-endian data stored at 'data' and return the result as - * a signed 32bit integer. Sign extension will be performed if the mapping - * references a signed data type. - */ -static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping, - __u8 query, const __u8 *data) -{ - int bits = mapping->size; - int offset = mapping->offset; - __s32 value = 0; - __u8 mask; - - data += offset / 8; - offset &= 7; - mask = ((1LL << bits) - 1) << offset; - - for (; bits > 0; data++) { - __u8 byte = *data & mask; - value |= offset > 0 ? (byte >> offset) : (byte << (-offset)); - bits -= 8 - (offset > 0 ? offset : 0); - offset -= 8; - mask = (1 << bits) - 1; - } - - /* Sign-extend the value if needed. */ - if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) - value |= -(value & (1 << (mapping->size - 1))); - - return value; -} - -/* Set the bit string specified by mapping->offset and mapping->size - * in the little-endian data stored at 'data' to the value 'value'. - */ -static void uvc_set_le_value(struct uvc_control_mapping *mapping, - __s32 value, __u8 *data) -{ - int bits = mapping->size; - int offset = mapping->offset; - __u8 mask; - - /* According to the v4l2 spec, writing any value to a button control - * should result in the action belonging to the button control being - * triggered. UVC devices however want to see a 1 written -> override - * value. - */ - if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON) - value = -1; - - data += offset / 8; - offset &= 7; - - for (; bits > 0; data++) { - mask = ((1LL << bits) - 1) << offset; - *data = (*data & ~mask) | ((value << offset) & mask); - value >>= offset ? offset : 8; - bits -= 8 - offset; - offset = 0; - } -} - -/* ------------------------------------------------------------------------ - * Terminal and unit management - */ - -static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; -static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA; -static const __u8 uvc_media_transport_input_guid[16] = - UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT; - -static int uvc_entity_match_guid(const struct uvc_entity *entity, - const __u8 guid[16]) -{ - switch (UVC_ENTITY_TYPE(entity)) { - case UVC_ITT_CAMERA: - return memcmp(uvc_camera_guid, guid, 16) == 0; - - case UVC_ITT_MEDIA_TRANSPORT_INPUT: - return memcmp(uvc_media_transport_input_guid, guid, 16) == 0; - - case UVC_VC_PROCESSING_UNIT: - return memcmp(uvc_processing_guid, guid, 16) == 0; - - case UVC_VC_EXTENSION_UNIT: - return memcmp(entity->extension.guidExtensionCode, - guid, 16) == 0; - - default: - return 0; - } -} - -/* ------------------------------------------------------------------------ - * UVC Controls - */ - -static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, - struct uvc_control_mapping **mapping, struct uvc_control **control, - int next) -{ - struct uvc_control *ctrl; - struct uvc_control_mapping *map; - unsigned int i; - - if (entity == NULL) - return; - - for (i = 0; i < entity->ncontrols; ++i) { - ctrl = &entity->controls[i]; - if (!ctrl->initialized) - continue; - - list_for_each_entry(map, &ctrl->info.mappings, list) { - if ((map->id == v4l2_id) && !next) { - *control = ctrl; - *mapping = map; - return; - } - - if ((*mapping == NULL || (*mapping)->id > map->id) && - (map->id > v4l2_id) && next) { - *control = ctrl; - *mapping = map; - } - } - } -} - -static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, - __u32 v4l2_id, struct uvc_control_mapping **mapping) -{ - struct uvc_control *ctrl = NULL; - struct uvc_entity *entity; - int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL; - - *mapping = NULL; - - /* Mask the query flags. */ - v4l2_id &= V4L2_CTRL_ID_MASK; - - /* Find the control. */ - list_for_each_entry(entity, &chain->entities, chain) { - __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); - if (ctrl && !next) - return ctrl; - } - - if (ctrl == NULL && !next) - uvc_trace(UVC_TRACE_CONTROL, "Control 0x%08x not found.\n", - v4l2_id); - - return ctrl; -} - -static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, - struct uvc_control *ctrl) -{ - int ret; - - if (ctrl->info.flags & UVC_CONTROL_GET_DEF) { - ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, - chain->dev->intfnum, ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF), - ctrl->info.size); - if (ret < 0) - return ret; - } - - if (ctrl->info.flags & UVC_CONTROL_GET_MIN) { - ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, - chain->dev->intfnum, ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN), - ctrl->info.size); - if (ret < 0) - return ret; - } - if (ctrl->info.flags & UVC_CONTROL_GET_MAX) { - ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id, - chain->dev->intfnum, ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX), - ctrl->info.size); - if (ret < 0) - return ret; - } - if (ctrl->info.flags & UVC_CONTROL_GET_RES) { - ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id, - chain->dev->intfnum, ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), - ctrl->info.size); - if (ret < 0) - return ret; - } - - ctrl->cached = 1; - return 0; -} - -int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, - struct v4l2_queryctrl *v4l2_ctrl) -{ - struct uvc_control *ctrl; - struct uvc_control_mapping *mapping; - struct uvc_menu_info *menu; - unsigned int i; - int ret; - - ret = mutex_lock_interruptible(&chain->ctrl_mutex); - if (ret < 0) - return -ERESTARTSYS; - - ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); - if (ctrl == NULL) { - ret = -EINVAL; - goto done; - } - - memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); - v4l2_ctrl->id = mapping->id; - v4l2_ctrl->type = mapping->v4l2_type; - strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); - v4l2_ctrl->flags = 0; - - if (!(ctrl->info.flags & UVC_CONTROL_GET_CUR)) - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; - if (!(ctrl->info.flags & UVC_CONTROL_SET_CUR)) - v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - if (!ctrl->cached) { - ret = uvc_ctrl_populate_cache(chain, ctrl); - if (ret < 0) - goto done; - } - - if (ctrl->info.flags & UVC_CONTROL_GET_DEF) { - v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); - } - - switch (mapping->v4l2_type) { - case V4L2_CTRL_TYPE_MENU: - v4l2_ctrl->minimum = 0; - v4l2_ctrl->maximum = mapping->menu_count - 1; - v4l2_ctrl->step = 1; - - menu = mapping->menu_info; - for (i = 0; i < mapping->menu_count; ++i, ++menu) { - if (menu->value == v4l2_ctrl->default_value) { - v4l2_ctrl->default_value = i; - break; - } - } - - goto done; - - case V4L2_CTRL_TYPE_BOOLEAN: - v4l2_ctrl->minimum = 0; - v4l2_ctrl->maximum = 1; - v4l2_ctrl->step = 1; - goto done; - - case V4L2_CTRL_TYPE_BUTTON: - v4l2_ctrl->minimum = 0; - v4l2_ctrl->maximum = 0; - v4l2_ctrl->step = 0; - goto done; - - default: - break; - } - - if (ctrl->info.flags & UVC_CONTROL_GET_MIN) - v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); - - if (ctrl->info.flags & UVC_CONTROL_GET_MAX) - v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); - - if (ctrl->info.flags & UVC_CONTROL_GET_RES) - v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); - -done: - mutex_unlock(&chain->ctrl_mutex); - return ret; -} - -/* - * Mapping V4L2 controls to UVC controls can be straighforward if done well. - * Most of the UVC controls exist in V4L2, and can be mapped directly. Some - * must be grouped (for instance the Red Balance, Blue Balance and Do White - * Balance V4L2 controls use the White Balance Component UVC control) or - * otherwise translated. The approach we take here is to use a translation - * table for the controls that can be mapped directly, and handle the others - * manually. - */ -int uvc_query_v4l2_menu(struct uvc_video_chain *chain, - struct v4l2_querymenu *query_menu) -{ - struct uvc_menu_info *menu_info; - struct uvc_control_mapping *mapping; - struct uvc_control *ctrl; - u32 index = query_menu->index; - u32 id = query_menu->id; - int ret; - - memset(query_menu, 0, sizeof(*query_menu)); - query_menu->id = id; - query_menu->index = index; - - ret = mutex_lock_interruptible(&chain->ctrl_mutex); - if (ret < 0) - return -ERESTARTSYS; - - ctrl = uvc_find_control(chain, query_menu->id, &mapping); - if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) { - ret = -EINVAL; - goto done; - } - - if (query_menu->index >= mapping->menu_count) { - ret = -EINVAL; - goto done; - } - - menu_info = &mapping->menu_info[query_menu->index]; - strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); - -done: - mutex_unlock(&chain->ctrl_mutex); - return ret; -} - - -/* -------------------------------------------------------------------------- - * Control transactions - * - * To make extended set operations as atomic as the hardware allows, controls - * are handled using begin/commit/rollback operations. - * - * At the beginning of a set request, uvc_ctrl_begin should be called to - * initialize the request. This function acquires the control lock. - * - * When setting a control, the new value is stored in the control data field - * at position UVC_CTRL_DATA_CURRENT. The control is then marked as dirty for - * later processing. If the UVC and V4L2 control sizes differ, the current - * value is loaded from the hardware before storing the new value in the data - * field. - * - * After processing all controls in the transaction, uvc_ctrl_commit or - * uvc_ctrl_rollback must be called to apply the pending changes to the - * hardware or revert them. When applying changes, all controls marked as - * dirty will be modified in the UVC device, and the dirty flag will be - * cleared. When reverting controls, the control data field - * UVC_CTRL_DATA_CURRENT is reverted to its previous value - * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the - * control lock. - */ -int uvc_ctrl_begin(struct uvc_video_chain *chain) -{ - return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0; -} - -static int uvc_ctrl_commit_entity(struct uvc_device *dev, - struct uvc_entity *entity, int rollback) -{ - struct uvc_control *ctrl; - unsigned int i; - int ret; - - if (entity == NULL) - return 0; - - for (i = 0; i < entity->ncontrols; ++i) { - ctrl = &entity->controls[i]; - if (!ctrl->initialized) - continue; - - /* Reset the loaded flag for auto-update controls that were - * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent - * uvc_ctrl_get from using the cached value. - */ - if (ctrl->info.flags & UVC_CONTROL_AUTO_UPDATE) - ctrl->loaded = 0; - - if (!ctrl->dirty) - continue; - - if (!rollback) - ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id, - dev->intfnum, ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - else - ret = 0; - - if (rollback || ret < 0) - memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), - ctrl->info.size); - - ctrl->dirty = 0; - - if (ret < 0) - return ret; - } - - return 0; -} - -int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback) -{ - struct uvc_entity *entity; - int ret = 0; - - /* Find the control. */ - list_for_each_entry(entity, &chain->entities, chain) { - ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback); - if (ret < 0) - goto done; - } - -done: - mutex_unlock(&chain->ctrl_mutex); - return ret; -} - -int uvc_ctrl_get(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl) -{ - struct uvc_control *ctrl; - struct uvc_control_mapping *mapping; - struct uvc_menu_info *menu; - unsigned int i; - int ret; - - ctrl = uvc_find_control(chain, xctrl->id, &mapping); - if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) - return -EINVAL; - - if (!ctrl->loaded) { - ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id, - chain->dev->intfnum, ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - if (ret < 0) - return ret; - - ctrl->loaded = 1; - } - - xctrl->value = mapping->get(mapping, UVC_GET_CUR, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); - - if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { - menu = mapping->menu_info; - for (i = 0; i < mapping->menu_count; ++i, ++menu) { - if (menu->value == xctrl->value) { - xctrl->value = i; - break; - } - } - } - - return 0; -} - -int uvc_ctrl_set(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl) -{ - struct uvc_control *ctrl; - struct uvc_control_mapping *mapping; - s32 value; - u32 step; - s32 min; - s32 max; - int ret; - - ctrl = uvc_find_control(chain, xctrl->id, &mapping); - if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_SET_CUR) == 0) - return -EINVAL; - - /* Clamp out of range values. */ - switch (mapping->v4l2_type) { - case V4L2_CTRL_TYPE_INTEGER: - if (!ctrl->cached) { - ret = uvc_ctrl_populate_cache(chain, ctrl); - if (ret < 0) - return ret; - } - - min = mapping->get(mapping, UVC_GET_MIN, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); - max = mapping->get(mapping, UVC_GET_MAX, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); - step = mapping->get(mapping, UVC_GET_RES, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); - if (step == 0) - step = 1; - - xctrl->value = min + (xctrl->value - min + step/2) / step * step; - xctrl->value = clamp(xctrl->value, min, max); - value = xctrl->value; - break; - - case V4L2_CTRL_TYPE_BOOLEAN: - xctrl->value = clamp(xctrl->value, 0, 1); - value = xctrl->value; - break; - - case V4L2_CTRL_TYPE_MENU: - if (xctrl->value < 0 || xctrl->value >= mapping->menu_count) - return -ERANGE; - value = mapping->menu_info[xctrl->value].value; - break; - - default: - value = xctrl->value; - break; - } - - /* If the mapping doesn't span the whole UVC control, the current value - * needs to be loaded from the device to perform the read-modify-write - * operation. - */ - if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) { - if ((ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) { - memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - 0, ctrl->info.size); - } else { - ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, - ctrl->entity->id, chain->dev->intfnum, - ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - if (ret < 0) - return ret; - } - - ctrl->loaded = 1; - } - - /* Backup the current value in case we need to rollback later. */ - if (!ctrl->dirty) { - memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - } - - mapping->set(mapping, value, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); - - ctrl->dirty = 1; - ctrl->modified = 1; - return 0; -} - -/* -------------------------------------------------------------------------- - * Dynamic controls - */ - -static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev, - const struct uvc_control *ctrl, struct uvc_control_info *info) -{ - struct uvc_ctrl_fixup { - struct usb_device_id id; - u8 entity; - u8 selector; - u8 flags; - }; - - static const struct uvc_ctrl_fixup fixups[] = { - { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1, - UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | - UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR | - UVC_CONTROL_AUTO_UPDATE }, - { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1, - UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | - UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR | - UVC_CONTROL_AUTO_UPDATE }, - { { USB_DEVICE(0x046d, 0x0994) }, 9, 1, - UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | - UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR | - UVC_CONTROL_AUTO_UPDATE }, - }; - - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(fixups); ++i) { - if (!usb_match_one_id(dev->intf, &fixups[i].id)) - continue; - - if (fixups[i].entity == ctrl->entity->id && - fixups[i].selector == info->selector) { - info->flags = fixups[i].flags; - return; - } - } -} - -/* - * Query control information (size and flags) for XU controls. - */ -static int uvc_ctrl_fill_xu_info(struct uvc_device *dev, - const struct uvc_control *ctrl, struct uvc_control_info *info) -{ - u8 *data; - int ret; - - data = kmalloc(2, GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - memcpy(info->entity, ctrl->entity->extension.guidExtensionCode, - sizeof(info->entity)); - info->index = ctrl->index; - info->selector = ctrl->index + 1; - - /* Query and verify the control length (GET_LEN) */ - ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum, - info->selector, data, 2); - if (ret < 0) { - uvc_trace(UVC_TRACE_CONTROL, - "GET_LEN failed on control %pUl/%u (%d).\n", - info->entity, info->selector, ret); - goto done; - } - - info->size = le16_to_cpup((__le16 *)data); - - /* Query the control information (GET_INFO) */ - ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum, - info->selector, data, 1); - if (ret < 0) { - uvc_trace(UVC_TRACE_CONTROL, - "GET_INFO failed on control %pUl/%u (%d).\n", - info->entity, info->selector, ret); - goto done; - } - - info->flags = UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX - | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF - | (data[0] & UVC_CONTROL_CAP_GET ? UVC_CONTROL_GET_CUR : 0) - | (data[0] & UVC_CONTROL_CAP_SET ? UVC_CONTROL_SET_CUR : 0) - | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ? - UVC_CONTROL_AUTO_UPDATE : 0); - - uvc_ctrl_fixup_xu_info(dev, ctrl, info); - - uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, " - "flags { get %u set %u auto %u }.\n", - info->entity, info->selector, info->size, - (info->flags & UVC_CONTROL_GET_CUR) ? 1 : 0, - (info->flags & UVC_CONTROL_SET_CUR) ? 1 : 0, - (info->flags & UVC_CONTROL_AUTO_UPDATE) ? 1 : 0); - -done: - kfree(data); - return ret; -} - -static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl, - const struct uvc_control_info *info); - -static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev, - struct uvc_control *ctrl) -{ - struct uvc_control_info info; - int ret; - - if (ctrl->initialized) - return 0; - - ret = uvc_ctrl_fill_xu_info(dev, ctrl, &info); - if (ret < 0) - return ret; - - ret = uvc_ctrl_add_info(dev, ctrl, &info); - if (ret < 0) - uvc_trace(UVC_TRACE_CONTROL, "Failed to initialize control " - "%pUl/%u on device %s entity %u\n", info.entity, - info.selector, dev->udev->devpath, ctrl->entity->id); - - return ret; -} - -int uvc_xu_ctrl_query(struct uvc_video_chain *chain, - struct uvc_xu_control *xctrl, int set) -{ - struct uvc_entity *entity; - struct uvc_control *ctrl = NULL; - unsigned int i, found = 0; - int restore = 0; - __u8 *data; - int ret; - - /* Find the extension unit. */ - list_for_each_entry(entity, &chain->entities, chain) { - if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT && - entity->id == xctrl->unit) - break; - } - - if (entity->id != xctrl->unit) { - uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n", - xctrl->unit); - return -EINVAL; - } - - /* Find the control and perform delayed initialization if needed. */ - for (i = 0; i < entity->ncontrols; ++i) { - ctrl = &entity->controls[i]; - if (ctrl->index == xctrl->selector - 1) { - found = 1; - break; - } - } - - if (!found) { - uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n", - entity->extension.guidExtensionCode, xctrl->selector); - return -EINVAL; - } - - if (mutex_lock_interruptible(&chain->ctrl_mutex)) - return -ERESTARTSYS; - - ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl); - if (ret < 0) { - ret = -ENOENT; - goto done; - } - - /* Validate control data size. */ - if (ctrl->info.size != xctrl->size) { - ret = -EINVAL; - goto done; - } - - if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) || - (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR))) { - ret = -EINVAL; - goto done; - } - - memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT); - restore = set; - - if (set && copy_from_user(data, xctrl->data, xctrl->size)) { - ret = -EFAULT; - goto done; - } - - ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR, - xctrl->unit, chain->dev->intfnum, xctrl->selector, - data, xctrl->size); - if (ret < 0) - goto done; - - if (!set && copy_to_user(xctrl->data, data, xctrl->size)) - ret = -EFAULT; -done: - if (ret && restore) - memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), - xctrl->size); - - mutex_unlock(&chain->ctrl_mutex); - return ret; -} - -/* -------------------------------------------------------------------------- - * Suspend/resume - */ - -/* - * Restore control values after resume, skipping controls that haven't been - * changed. - * - * TODO - * - Don't restore modified controls that are back to their default value. - * - Handle restore order (Auto-Exposure Mode should be restored before - * Exposure Time). - */ -int uvc_ctrl_resume_device(struct uvc_device *dev) -{ - struct uvc_control *ctrl; - struct uvc_entity *entity; - unsigned int i; - int ret; - - /* Walk the entities list and restore controls when possible. */ - list_for_each_entry(entity, &dev->entities, list) { - - for (i = 0; i < entity->ncontrols; ++i) { - ctrl = &entity->controls[i]; - - if (!ctrl->initialized || !ctrl->modified || - (ctrl->info.flags & UVC_CONTROL_RESTORE) == 0) - continue; - - printk(KERN_INFO "restoring control %pUl/%u/%u\n", - ctrl->info.entity, ctrl->info.index, - ctrl->info.selector); - ctrl->dirty = 1; - } - - ret = uvc_ctrl_commit_entity(dev, entity, 0); - if (ret < 0) - return ret; - } - - return 0; -} - -/* -------------------------------------------------------------------------- - * Control and mapping handling - */ - -/* - * Add control information to a given control. - */ -static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl, - const struct uvc_control_info *info) -{ - int ret = 0; - - memcpy(&ctrl->info, info, sizeof(*info)); - INIT_LIST_HEAD(&ctrl->info.mappings); - - /* Allocate an array to save control values (cur, def, max, etc.) */ - ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST + 1, - GFP_KERNEL); - if (ctrl->uvc_data == NULL) { - ret = -ENOMEM; - goto done; - } - - ctrl->initialized = 1; - - uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s " - "entity %u\n", ctrl->info.entity, ctrl->info.selector, - dev->udev->devpath, ctrl->entity->id); - -done: - if (ret < 0) - kfree(ctrl->uvc_data); - return ret; -} - -/* - * Add a control mapping to a given control. - */ -static int __uvc_ctrl_add_mapping(struct uvc_device *dev, - struct uvc_control *ctrl, const struct uvc_control_mapping *mapping) -{ - struct uvc_control_mapping *map; - unsigned int size; - - /* Most mappings come from static kernel data and need to be duplicated. - * Mappings that come from userspace will be unnecessarily duplicated, - * this could be optimized. - */ - map = kmemdup(mapping, sizeof(*mapping), GFP_KERNEL); - if (map == NULL) - return -ENOMEM; - - size = sizeof(*mapping->menu_info) * mapping->menu_count; - map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL); - if (map->menu_info == NULL) { - kfree(map); - return -ENOMEM; - } - - if (map->get == NULL) - map->get = uvc_get_le_value; - if (map->set == NULL) - map->set = uvc_set_le_value; - - map->ctrl = &ctrl->info; - list_add_tail(&map->list, &ctrl->info.mappings); - uvc_trace(UVC_TRACE_CONTROL, - "Adding mapping '%s' to control %pUl/%u.\n", - map->name, ctrl->info.entity, ctrl->info.selector); - - return 0; -} - -int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, - const struct uvc_control_mapping *mapping) -{ - struct uvc_device *dev = chain->dev; - struct uvc_control_mapping *map; - struct uvc_entity *entity; - struct uvc_control *ctrl; - int found = 0; - int ret; - - if (mapping->id & ~V4L2_CTRL_ID_MASK) { - uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', control " - "id 0x%08x is invalid.\n", mapping->name, - mapping->id); - return -EINVAL; - } - - /* Search for the matching (GUID/CS) control in the given device */ - list_for_each_entry(entity, &dev->entities, list) { - unsigned int i; - - if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT || - !uvc_entity_match_guid(entity, mapping->entity)) - continue; - - for (i = 0; i < entity->ncontrols; ++i) { - ctrl = &entity->controls[i]; - if (ctrl->index == mapping->selector - 1) { - found = 1; - break; - } - } - - if (found) - break; - } - if (!found) - return -ENOENT; - - if (mutex_lock_interruptible(&chain->ctrl_mutex)) - return -ERESTARTSYS; - - /* Perform delayed initialization of XU controls */ - ret = uvc_ctrl_init_xu_ctrl(dev, ctrl); - if (ret < 0) { - ret = -ENOENT; - goto done; - } - - list_for_each_entry(map, &ctrl->info.mappings, list) { - if (mapping->id == map->id) { - uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', " - "control id 0x%08x already exists.\n", - mapping->name, mapping->id); - ret = -EEXIST; - goto done; - } - } - - /* Prevent excess memory consumption */ - if (atomic_inc_return(&dev->nmappings) > UVC_MAX_CONTROL_MAPPINGS) { - atomic_dec(&dev->nmappings); - uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', maximum " - "mappings count (%u) exceeded.\n", mapping->name, - UVC_MAX_CONTROL_MAPPINGS); - ret = -ENOMEM; - goto done; - } - - ret = __uvc_ctrl_add_mapping(dev, ctrl, mapping); - if (ret < 0) - atomic_dec(&dev->nmappings); - -done: - mutex_unlock(&chain->ctrl_mutex); - return ret; -} - -/* - * Prune an entity of its bogus controls using a blacklist. Bogus controls - * are currently the ones that crash the camera or unconditionally return an - * error when queried. - */ -static void uvc_ctrl_prune_entity(struct uvc_device *dev, - struct uvc_entity *entity) -{ - struct uvc_ctrl_blacklist { - struct usb_device_id id; - u8 index; - }; - - static const struct uvc_ctrl_blacklist processing_blacklist[] = { - { { USB_DEVICE(0x13d3, 0x509b) }, 9 }, /* Gain */ - { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */ - { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */ - }; - static const struct uvc_ctrl_blacklist camera_blacklist[] = { - { { USB_DEVICE(0x06f8, 0x3005) }, 9 }, /* Zoom, Absolute */ - }; - - const struct uvc_ctrl_blacklist *blacklist; - unsigned int size; - unsigned int count; - unsigned int i; - u8 *controls; - - switch (UVC_ENTITY_TYPE(entity)) { - case UVC_VC_PROCESSING_UNIT: - blacklist = processing_blacklist; - count = ARRAY_SIZE(processing_blacklist); - controls = entity->processing.bmControls; - size = entity->processing.bControlSize; - break; - - case UVC_ITT_CAMERA: - blacklist = camera_blacklist; - count = ARRAY_SIZE(camera_blacklist); - controls = entity->camera.bmControls; - size = entity->camera.bControlSize; - break; - - default: - return; - } - - for (i = 0; i < count; ++i) { - if (!usb_match_one_id(dev->intf, &blacklist[i].id)) - continue; - - if (blacklist[i].index >= 8 * size || - !uvc_test_bit(controls, blacklist[i].index)) - continue; - - uvc_trace(UVC_TRACE_CONTROL, "%u/%u control is black listed, " - "removing it.\n", entity->id, blacklist[i].index); - - uvc_clear_bit(controls, blacklist[i].index); - } -} - -/* - * Add control information and hardcoded stock control mappings to the given - * device. - */ -static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl) -{ - const struct uvc_control_info *info = uvc_ctrls; - const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls); - const struct uvc_control_mapping *mapping = uvc_ctrl_mappings; - const struct uvc_control_mapping *mend = - mapping + ARRAY_SIZE(uvc_ctrl_mappings); - - /* XU controls initialization requires querying the device for control - * information. As some buggy UVC devices will crash when queried - * repeatedly in a tight loop, delay XU controls initialization until - * first use. - */ - if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT) - return; - - for (; info < iend; ++info) { - if (uvc_entity_match_guid(ctrl->entity, info->entity) && - ctrl->index == info->index) { - uvc_ctrl_add_info(dev, ctrl, info); - break; - } - } - - if (!ctrl->initialized) - return; - - for (; mapping < mend; ++mapping) { - if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && - ctrl->info.selector == mapping->selector) - __uvc_ctrl_add_mapping(dev, ctrl, mapping); - } -} - -/* - * Initialize device controls. - */ -int uvc_ctrl_init_device(struct uvc_device *dev) -{ - struct uvc_entity *entity; - unsigned int i; - - /* Walk the entities list and instantiate controls */ - list_for_each_entry(entity, &dev->entities, list) { - struct uvc_control *ctrl; - unsigned int bControlSize = 0, ncontrols = 0; - __u8 *bmControls = NULL; - - if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) { - bmControls = entity->extension.bmControls; - bControlSize = entity->extension.bControlSize; - } else if (UVC_ENTITY_TYPE(entity) == UVC_VC_PROCESSING_UNIT) { - bmControls = entity->processing.bmControls; - bControlSize = entity->processing.bControlSize; - } else if (UVC_ENTITY_TYPE(entity) == UVC_ITT_CAMERA) { - bmControls = entity->camera.bmControls; - bControlSize = entity->camera.bControlSize; - } - - /* Remove bogus/blacklisted controls */ - uvc_ctrl_prune_entity(dev, entity); - - /* Count supported controls and allocate the controls array */ - for (i = 0; i < bControlSize; ++i) - ncontrols += hweight8(bmControls[i]); - if (ncontrols == 0) - continue; - - entity->controls = kzalloc(ncontrols * sizeof(*ctrl), - GFP_KERNEL); - if (entity->controls == NULL) - return -ENOMEM; - entity->ncontrols = ncontrols; - - /* Initialize all supported controls */ - ctrl = entity->controls; - for (i = 0; i < bControlSize * 8; ++i) { - if (uvc_test_bit(bmControls, i) == 0) - continue; - - ctrl->entity = entity; - ctrl->index = i; - - uvc_ctrl_init_ctrl(dev, ctrl); - ctrl++; - } - } - - return 0; -} - -/* - * Cleanup device controls. - */ -static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev, - struct uvc_control *ctrl) -{ - struct uvc_control_mapping *mapping, *nm; - - list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) { - list_del(&mapping->list); - kfree(mapping->menu_info); - kfree(mapping); - } -} - -void uvc_ctrl_cleanup_device(struct uvc_device *dev) -{ - struct uvc_entity *entity; - unsigned int i; - - /* Free controls and control mappings for all entities. */ - list_for_each_entry(entity, &dev->entities, list) { - for (i = 0; i < entity->ncontrols; ++i) { - struct uvc_control *ctrl = &entity->controls[i]; - - if (!ctrl->initialized) - continue; - - uvc_ctrl_cleanup_mappings(dev, ctrl); - kfree(ctrl->uvc_data); - } - - kfree(entity->controls); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_driver.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_driver.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2315 +0,0 @@ -/* - * uvc_driver.c -- USB Video Class driver - * - * Copyright (C) 2005-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.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, or - * (at your option) any later version. - * - */ - -/* - * This driver aims to support video input and ouput devices compliant with the - * 'USB Video Class' specification. - * - * The driver doesn't support the deprecated v4l1 interface. It implements the - * mmap capture method only, and doesn't do any image format conversion in - * software. If your user-space application doesn't support YUYV or MJPEG, fix - * it :-). Please note that the MJPEG data have been stripped from their - * Huffman tables (DHT marker), you will need to add it back if your JPEG - * codec can't handle MJPEG data. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "uvcvideo.h" - -#define DRIVER_AUTHOR "Laurent Pinchart " \ - "" -#define DRIVER_DESC "USB Video Class driver" - -unsigned int uvc_clock_param = CLOCK_MONOTONIC; -unsigned int uvc_no_drop_param; -static unsigned int uvc_quirks_param = -1; -unsigned int uvc_trace_param; -unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT; - -/* ------------------------------------------------------------------------ - * Video formats - */ - -static struct uvc_format_desc uvc_fmts[] = { - { - .name = "YUV 4:2:2 (YUYV)", - .guid = UVC_GUID_FORMAT_YUY2, - .fcc = V4L2_PIX_FMT_YUYV, - }, - { - .name = "YUV 4:2:2 (YUYV)", - .guid = UVC_GUID_FORMAT_YUY2_ISIGHT, - .fcc = V4L2_PIX_FMT_YUYV, - }, - { - .name = "YUV 4:2:0 (NV12)", - .guid = UVC_GUID_FORMAT_NV12, - .fcc = V4L2_PIX_FMT_NV12, - }, - { - .name = "MJPEG", - .guid = UVC_GUID_FORMAT_MJPEG, - .fcc = V4L2_PIX_FMT_MJPEG, - }, - { - .name = "YVU 4:2:0 (YV12)", - .guid = UVC_GUID_FORMAT_YV12, - .fcc = V4L2_PIX_FMT_YVU420, - }, - { - .name = "YUV 4:2:0 (I420)", - .guid = UVC_GUID_FORMAT_I420, - .fcc = V4L2_PIX_FMT_YUV420, - }, - { - .name = "YUV 4:2:2 (UYVY)", - .guid = UVC_GUID_FORMAT_UYVY, - .fcc = V4L2_PIX_FMT_UYVY, - }, - { - .name = "Greyscale (8-bit)", - .guid = UVC_GUID_FORMAT_Y800, - .fcc = V4L2_PIX_FMT_GREY, - }, - { - .name = "Greyscale (16-bit)", - .guid = UVC_GUID_FORMAT_Y16, - .fcc = V4L2_PIX_FMT_Y16, - }, - { - .name = "RGB Bayer", - .guid = UVC_GUID_FORMAT_BY8, - .fcc = V4L2_PIX_FMT_SBGGR8, - }, -}; - -/* ------------------------------------------------------------------------ - * Utility functions - */ - -struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, - __u8 epaddr) -{ - struct usb_host_endpoint *ep; - unsigned int i; - - for (i = 0; i < alts->desc.bNumEndpoints; ++i) { - ep = &alts->endpoint[i]; - if (ep->desc.bEndpointAddress == epaddr) - return ep; - } - - return NULL; -} - -static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16]) -{ - unsigned int len = ARRAY_SIZE(uvc_fmts); - unsigned int i; - - for (i = 0; i < len; ++i) { - if (memcmp(guid, uvc_fmts[i].guid, 16) == 0) - return &uvc_fmts[i]; - } - - return NULL; -} - -static __u32 uvc_colorspace(const __u8 primaries) -{ - static const __u8 colorprimaries[] = { - 0, - V4L2_COLORSPACE_SRGB, - V4L2_COLORSPACE_470_SYSTEM_M, - V4L2_COLORSPACE_470_SYSTEM_BG, - V4L2_COLORSPACE_SMPTE170M, - V4L2_COLORSPACE_SMPTE240M, - }; - - if (primaries < ARRAY_SIZE(colorprimaries)) - return colorprimaries[primaries]; - - return 0; -} - -/* Simplify a fraction using a simple continued fraction decomposition. The - * idea here is to convert fractions such as 333333/10000000 to 1/30 using - * 32 bit arithmetic only. The algorithm is not perfect and relies upon two - * arbitrary parameters to remove non-significative terms from the simple - * continued fraction decomposition. Using 8 and 333 for n_terms and threshold - * respectively seems to give nice results. - */ -void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, - unsigned int n_terms, unsigned int threshold) -{ - uint32_t *an; - uint32_t x, y, r; - unsigned int i, n; - - an = kmalloc(n_terms * sizeof *an, GFP_KERNEL); - if (an == NULL) - return; - - /* Convert the fraction to a simple continued fraction. See - * http://mathforum.org/dr.math/faq/faq.fractions.html - * Stop if the current term is bigger than or equal to the given - * threshold. - */ - x = *numerator; - y = *denominator; - - for (n = 0; n < n_terms && y != 0; ++n) { - an[n] = x / y; - if (an[n] >= threshold) { - if (n < 2) - n++; - break; - } - - r = x - an[n] * y; - x = y; - y = r; - } - - /* Expand the simple continued fraction back to an integer fraction. */ - x = 0; - y = 1; - - for (i = n; i > 0; --i) { - r = y; - y = an[i-1] * y + x; - x = r; - } - - *numerator = y; - *denominator = x; - kfree(an); -} - -/* Convert a fraction to a frame interval in 100ns multiples. The idea here is - * to compute numerator / denominator * 10000000 using 32 bit fixed point - * arithmetic only. - */ -uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator) -{ - uint32_t multiplier; - - /* Saturate the result if the operation would overflow. */ - if (denominator == 0 || - numerator/denominator >= ((uint32_t)-1)/10000000) - return (uint32_t)-1; - - /* Divide both the denominator and the multiplier by two until - * numerator * multiplier doesn't overflow. If anyone knows a better - * algorithm please let me know. - */ - multiplier = 10000000; - while (numerator > ((uint32_t)-1)/multiplier) { - multiplier /= 2; - denominator /= 2; - } - - return denominator ? numerator * multiplier / denominator : 0; -} - -/* ------------------------------------------------------------------------ - * Terminal and unit management - */ - -static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) -{ - struct uvc_entity *entity; - - list_for_each_entry(entity, &dev->entities, list) { - if (entity->id == id) - return entity; - } - - return NULL; -} - -static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev, - int id, struct uvc_entity *entity) -{ - unsigned int i; - - if (entity == NULL) - entity = list_entry(&dev->entities, struct uvc_entity, list); - - list_for_each_entry_continue(entity, &dev->entities, list) { - for (i = 0; i < entity->bNrInPins; ++i) - if (entity->baSourceID[i] == id) - return entity; - } - - return NULL; -} - -static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id) -{ - struct uvc_streaming *stream; - - list_for_each_entry(stream, &dev->streams, list) { - if (stream->header.bTerminalLink == id) - return stream; - } - - return NULL; -} - -/* ------------------------------------------------------------------------ - * Descriptors parsing - */ - -static int uvc_parse_format(struct uvc_device *dev, - struct uvc_streaming *streaming, struct uvc_format *format, - __u32 **intervals, unsigned char *buffer, int buflen) -{ - struct usb_interface *intf = streaming->intf; - struct usb_host_interface *alts = intf->cur_altsetting; - struct uvc_format_desc *fmtdesc; - struct uvc_frame *frame; - const unsigned char *start = buffer; - unsigned int interval; - unsigned int i, n; - __u8 ftype; - - format->type = buffer[2]; - format->index = buffer[3]; - - switch (buffer[2]) { - case UVC_VS_FORMAT_UNCOMPRESSED: - case UVC_VS_FORMAT_FRAME_BASED: - n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28; - if (buflen < n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FORMAT error\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber); - return -EINVAL; - } - - /* Find the format descriptor from its GUID. */ - fmtdesc = uvc_format_by_guid(&buffer[5]); - - if (fmtdesc != NULL) { - strlcpy(format->name, fmtdesc->name, - sizeof format->name); - format->fcc = fmtdesc->fcc; - } else { - uvc_printk(KERN_INFO, "Unknown video format %pUl\n", - &buffer[5]); - snprintf(format->name, sizeof(format->name), "%pUl\n", - &buffer[5]); - format->fcc = 0; - } - - format->bpp = buffer[21]; - if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) { - ftype = UVC_VS_FRAME_UNCOMPRESSED; - } else { - ftype = UVC_VS_FRAME_FRAME_BASED; - if (buffer[27]) - format->flags = UVC_FMT_FLAG_COMPRESSED; - } - break; - - case UVC_VS_FORMAT_MJPEG: - if (buflen < 11) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FORMAT error\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber); - return -EINVAL; - } - - strlcpy(format->name, "MJPEG", sizeof format->name); - format->fcc = V4L2_PIX_FMT_MJPEG; - format->flags = UVC_FMT_FLAG_COMPRESSED; - format->bpp = 0; - ftype = UVC_VS_FRAME_MJPEG; - break; - - case UVC_VS_FORMAT_DV: - if (buflen < 9) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FORMAT error\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber); - return -EINVAL; - } - - switch (buffer[8] & 0x7f) { - case 0: - strlcpy(format->name, "SD-DV", sizeof format->name); - break; - case 1: - strlcpy(format->name, "SDL-DV", sizeof format->name); - break; - case 2: - strlcpy(format->name, "HD-DV", sizeof format->name); - break; - default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d: unknown DV format %u\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber, buffer[8]); - return -EINVAL; - } - - strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz", - sizeof format->name); - - format->fcc = V4L2_PIX_FMT_DV; - format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM; - format->bpp = 0; - ftype = 0; - - /* Create a dummy frame descriptor. */ - frame = &format->frame[0]; - memset(&format->frame[0], 0, sizeof format->frame[0]); - frame->bFrameIntervalType = 1; - frame->dwDefaultFrameInterval = 1; - frame->dwFrameInterval = *intervals; - *(*intervals)++ = 1; - format->nframes = 1; - break; - - case UVC_VS_FORMAT_MPEG2TS: - case UVC_VS_FORMAT_STREAM_BASED: - /* Not supported yet. */ - default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d unsupported format %u\n", - dev->udev->devnum, alts->desc.bInterfaceNumber, - buffer[2]); - return -EINVAL; - } - - uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name); - - buflen -= buffer[0]; - buffer += buffer[0]; - - /* Parse the frame descriptors. Only uncompressed, MJPEG and frame - * based formats have frame descriptors. - */ - while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && - buffer[2] == ftype) { - frame = &format->frame[format->nframes]; - if (ftype != UVC_VS_FRAME_FRAME_BASED) - n = buflen > 25 ? buffer[25] : 0; - else - n = buflen > 21 ? buffer[21] : 0; - - n = n ? n : 3; - - if (buflen < 26 + 4*n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FRAME error\n", dev->udev->devnum, - alts->desc.bInterfaceNumber); - return -EINVAL; - } - - frame->bFrameIndex = buffer[3]; - frame->bmCapabilities = buffer[4]; - frame->wWidth = get_unaligned_le16(&buffer[5]); - frame->wHeight = get_unaligned_le16(&buffer[7]); - frame->dwMinBitRate = get_unaligned_le32(&buffer[9]); - frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]); - if (ftype != UVC_VS_FRAME_FRAME_BASED) { - frame->dwMaxVideoFrameBufferSize = - get_unaligned_le32(&buffer[17]); - frame->dwDefaultFrameInterval = - get_unaligned_le32(&buffer[21]); - frame->bFrameIntervalType = buffer[25]; - } else { - frame->dwMaxVideoFrameBufferSize = 0; - frame->dwDefaultFrameInterval = - get_unaligned_le32(&buffer[17]); - frame->bFrameIntervalType = buffer[21]; - } - frame->dwFrameInterval = *intervals; - - /* Several UVC chipsets screw up dwMaxVideoFrameBufferSize - * completely. Observed behaviours range from setting the - * value to 1.1x the actual frame size to hardwiring the - * 16 low bits to 0. This results in a higher than necessary - * memory usage as well as a wrong image size information. For - * uncompressed formats this can be fixed by computing the - * value from the frame size. - */ - if (!(format->flags & UVC_FMT_FLAG_COMPRESSED)) - frame->dwMaxVideoFrameBufferSize = format->bpp - * frame->wWidth * frame->wHeight / 8; - - /* Some bogus devices report dwMinFrameInterval equal to - * dwMaxFrameInterval and have dwFrameIntervalStep set to - * zero. Setting all null intervals to 1 fixes the problem and - * some other divisions by zero that could happen. - */ - for (i = 0; i < n; ++i) { - interval = get_unaligned_le32(&buffer[26+4*i]); - *(*intervals)++ = interval ? interval : 1; - } - - /* Make sure that the default frame interval stays between - * the boundaries. - */ - n -= frame->bFrameIntervalType ? 1 : 2; - frame->dwDefaultFrameInterval = - min(frame->dwFrameInterval[n], - max(frame->dwFrameInterval[0], - frame->dwDefaultFrameInterval)); - - if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) { - frame->bFrameIntervalType = 1; - frame->dwFrameInterval[0] = - frame->dwDefaultFrameInterval; - } - - uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n", - frame->wWidth, frame->wHeight, - 10000000/frame->dwDefaultFrameInterval, - (100000000/frame->dwDefaultFrameInterval)%10); - - format->nframes++; - buflen -= buffer[0]; - buffer += buffer[0]; - } - - if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && - buffer[2] == UVC_VS_STILL_IMAGE_FRAME) { - buflen -= buffer[0]; - buffer += buffer[0]; - } - - if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && - buffer[2] == UVC_VS_COLORFORMAT) { - if (buflen < 6) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d COLORFORMAT error\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber); - return -EINVAL; - } - - format->colorspace = uvc_colorspace(buffer[3]); - - buflen -= buffer[0]; - buffer += buffer[0]; - } - - return buffer - start; -} - -static int uvc_parse_streaming(struct uvc_device *dev, - struct usb_interface *intf) -{ - struct uvc_streaming *streaming = NULL; - struct uvc_format *format; - struct uvc_frame *frame; - struct usb_host_interface *alts = &intf->altsetting[0]; - unsigned char *_buffer, *buffer = alts->extra; - int _buflen, buflen = alts->extralen; - unsigned int nformats = 0, nframes = 0, nintervals = 0; - unsigned int size, i, n, p; - __u32 *interval; - __u16 psize; - int ret = -EINVAL; - - if (intf->cur_altsetting->desc.bInterfaceSubClass - != UVC_SC_VIDEOSTREAMING) { - uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a " - "video streaming interface\n", dev->udev->devnum, - intf->altsetting[0].desc.bInterfaceNumber); - return -EINVAL; - } - - if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) { - uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already " - "claimed\n", dev->udev->devnum, - intf->altsetting[0].desc.bInterfaceNumber); - return -EINVAL; - } - - streaming = kzalloc(sizeof *streaming, GFP_KERNEL); - if (streaming == NULL) { - usb_driver_release_interface(&uvc_driver.driver, intf); - return -EINVAL; - } - - mutex_init(&streaming->mutex); - streaming->dev = dev; - streaming->intf = usb_get_intf(intf); - streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; - - /* The Pico iMage webcam has its class-specific interface descriptors - * after the endpoint descriptors. - */ - if (buflen == 0) { - for (i = 0; i < alts->desc.bNumEndpoints; ++i) { - struct usb_host_endpoint *ep = &alts->endpoint[i]; - - if (ep->extralen == 0) - continue; - - if (ep->extralen > 2 && - ep->extra[1] == USB_DT_CS_INTERFACE) { - uvc_trace(UVC_TRACE_DESCR, "trying extra data " - "from endpoint %u.\n", i); - buffer = alts->endpoint[i].extra; - buflen = alts->endpoint[i].extralen; - break; - } - } - } - - /* Skip the standard interface descriptors. */ - while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) { - buflen -= buffer[0]; - buffer += buffer[0]; - } - - if (buflen <= 2) { - uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming " - "interface descriptors found.\n"); - goto error; - } - - /* Parse the header descriptor. */ - switch (buffer[2]) { - case UVC_VS_OUTPUT_HEADER: - streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - size = 9; - break; - - case UVC_VS_INPUT_HEADER: - streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - size = 13; - break; - - default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " - "%d HEADER descriptor not found.\n", dev->udev->devnum, - alts->desc.bInterfaceNumber); - goto error; - } - - p = buflen >= 4 ? buffer[3] : 0; - n = buflen >= size ? buffer[size-1] : 0; - - if (buflen < size + p*n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d HEADER descriptor is invalid.\n", - dev->udev->devnum, alts->desc.bInterfaceNumber); - goto error; - } - - streaming->header.bNumFormats = p; - streaming->header.bEndpointAddress = buffer[6]; - if (buffer[2] == UVC_VS_INPUT_HEADER) { - streaming->header.bmInfo = buffer[7]; - streaming->header.bTerminalLink = buffer[8]; - streaming->header.bStillCaptureMethod = buffer[9]; - streaming->header.bTriggerSupport = buffer[10]; - streaming->header.bTriggerUsage = buffer[11]; - } else { - streaming->header.bTerminalLink = buffer[7]; - } - streaming->header.bControlSize = n; - - streaming->header.bmaControls = kmemdup(&buffer[size], p * n, - GFP_KERNEL); - if (streaming->header.bmaControls == NULL) { - ret = -ENOMEM; - goto error; - } - - buflen -= buffer[0]; - buffer += buffer[0]; - - _buffer = buffer; - _buflen = buflen; - - /* Count the format and frame descriptors. */ - while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) { - switch (_buffer[2]) { - case UVC_VS_FORMAT_UNCOMPRESSED: - case UVC_VS_FORMAT_MJPEG: - case UVC_VS_FORMAT_FRAME_BASED: - nformats++; - break; - - case UVC_VS_FORMAT_DV: - /* DV format has no frame descriptor. We will create a - * dummy frame descriptor with a dummy frame interval. - */ - nformats++; - nframes++; - nintervals++; - break; - - case UVC_VS_FORMAT_MPEG2TS: - case UVC_VS_FORMAT_STREAM_BASED: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FORMAT %u is not supported.\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber, _buffer[2]); - break; - - case UVC_VS_FRAME_UNCOMPRESSED: - case UVC_VS_FRAME_MJPEG: - nframes++; - if (_buflen > 25) - nintervals += _buffer[25] ? _buffer[25] : 3; - break; - - case UVC_VS_FRAME_FRAME_BASED: - nframes++; - if (_buflen > 21) - nintervals += _buffer[21] ? _buffer[21] : 3; - break; - } - - _buflen -= _buffer[0]; - _buffer += _buffer[0]; - } - - if (nformats == 0) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " - "%d has no supported formats defined.\n", - dev->udev->devnum, alts->desc.bInterfaceNumber); - goto error; - } - - size = nformats * sizeof *format + nframes * sizeof *frame - + nintervals * sizeof *interval; - format = kzalloc(size, GFP_KERNEL); - if (format == NULL) { - ret = -ENOMEM; - goto error; - } - - frame = (struct uvc_frame *)&format[nformats]; - interval = (__u32 *)&frame[nframes]; - - streaming->format = format; - streaming->nformats = nformats; - - /* Parse the format descriptors. */ - while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) { - switch (buffer[2]) { - case UVC_VS_FORMAT_UNCOMPRESSED: - case UVC_VS_FORMAT_MJPEG: - case UVC_VS_FORMAT_DV: - case UVC_VS_FORMAT_FRAME_BASED: - format->frame = frame; - ret = uvc_parse_format(dev, streaming, format, - &interval, buffer, buflen); - if (ret < 0) - goto error; - - frame += format->nframes; - format++; - - buflen -= ret; - buffer += ret; - continue; - - default: - break; - } - - buflen -= buffer[0]; - buffer += buffer[0]; - } - - if (buflen) - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " - "%d has %u bytes of trailing descriptor garbage.\n", - dev->udev->devnum, alts->desc.bInterfaceNumber, buflen); - - /* Parse the alternate settings to find the maximum bandwidth. */ - for (i = 0; i < intf->num_altsetting; ++i) { - struct usb_host_endpoint *ep; - alts = &intf->altsetting[i]; - ep = uvc_find_endpoint(alts, - streaming->header.bEndpointAddress); - if (ep == NULL) - continue; - - psize = le16_to_cpu(ep->desc.wMaxPacketSize); - psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - if (psize > streaming->maxpsize) - streaming->maxpsize = psize; - } - - list_add_tail(&streaming->list, &dev->streams); - return 0; - -error: - usb_driver_release_interface(&uvc_driver.driver, intf); - usb_put_intf(intf); - kfree(streaming->format); - kfree(streaming->header.bmaControls); - kfree(streaming); - return ret; -} - -static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, - unsigned int num_pads, unsigned int extra_size) -{ - struct uvc_entity *entity; - unsigned int num_inputs; - unsigned int size; - - num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; - size = sizeof(*entity) + extra_size + num_inputs; - entity = kzalloc(size, GFP_KERNEL); - if (entity == NULL) - return NULL; - - entity->id = id; - entity->type = type; - - entity->bNrInPins = num_inputs; - entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size; - - return entity; -} - -/* Parse vendor-specific extensions. */ -static int uvc_parse_vendor_control(struct uvc_device *dev, - const unsigned char *buffer, int buflen) -{ - struct usb_device *udev = dev->udev; - struct usb_host_interface *alts = dev->intf->cur_altsetting; - struct uvc_entity *unit; - unsigned int n, p; - int handled = 0; - - switch (le16_to_cpu(dev->udev->descriptor.idVendor)) { - case 0x046d: /* Logitech */ - if (buffer[1] != 0x41 || buffer[2] != 0x01) - break; - - /* Logitech implements several vendor specific functions - * through vendor specific extension units (LXU). - * - * The LXU descriptors are similar to XU descriptors - * (see "USB Device Video Class for Video Devices", section - * 3.7.2.6 "Extension Unit Descriptor") with the following - * differences: - * - * ---------------------------------------------------------- - * 0 bLength 1 Number - * Size of this descriptor, in bytes: 24+p+n*2 - * ---------------------------------------------------------- - * 23+p+n bmControlsType N Bitmap - * Individual bits in the set are defined: - * 0: Absolute - * 1: Relative - * - * This bitset is mapped exactly the same as bmControls. - * ---------------------------------------------------------- - * 23+p+n*2 bReserved 1 Boolean - * ---------------------------------------------------------- - * 24+p+n*2 iExtension 1 Index - * Index of a string descriptor that describes this - * extension unit. - * ---------------------------------------------------------- - */ - p = buflen >= 22 ? buffer[21] : 0; - n = buflen >= 25 + p ? buffer[22+p] : 0; - - if (buflen < 25 + p + 2*n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d EXTENSION_UNIT error\n", - udev->devnum, alts->desc.bInterfaceNumber); - break; - } - - unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3], - p + 1, 2*n); - if (unit == NULL) - return -ENOMEM; - - memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); - unit->extension.bNumControls = buffer[20]; - memcpy(unit->baSourceID, &buffer[22], p); - unit->extension.bControlSize = buffer[22+p]; - unit->extension.bmControls = (__u8 *)unit + sizeof(*unit); - unit->extension.bmControlsType = (__u8 *)unit + sizeof(*unit) - + n; - memcpy(unit->extension.bmControls, &buffer[23+p], 2*n); - - if (buffer[24+p+2*n] != 0) - usb_string(udev, buffer[24+p+2*n], unit->name, - sizeof unit->name); - else - sprintf(unit->name, "Extension %u", buffer[3]); - - list_add_tail(&unit->list, &dev->entities); - handled = 1; - break; - } - - return handled; -} - -static int uvc_parse_standard_control(struct uvc_device *dev, - const unsigned char *buffer, int buflen) -{ - struct usb_device *udev = dev->udev; - struct uvc_entity *unit, *term; - struct usb_interface *intf; - struct usb_host_interface *alts = dev->intf->cur_altsetting; - unsigned int i, n, p, len; - __u16 type; - - switch (buffer[2]) { - case UVC_VC_HEADER: - n = buflen >= 12 ? buffer[11] : 0; - - if (buflen < 12 || buflen < 12 + n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d HEADER error\n", udev->devnum, - alts->desc.bInterfaceNumber); - return -EINVAL; - } - - dev->uvc_version = get_unaligned_le16(&buffer[3]); - dev->clock_frequency = get_unaligned_le32(&buffer[7]); - - /* Parse all USB Video Streaming interfaces. */ - for (i = 0; i < n; ++i) { - intf = usb_ifnum_to_if(udev, buffer[12+i]); - if (intf == NULL) { - uvc_trace(UVC_TRACE_DESCR, "device %d " - "interface %d doesn't exists\n", - udev->devnum, i); - continue; - } - - uvc_parse_streaming(dev, intf); - } - break; - - case UVC_VC_INPUT_TERMINAL: - if (buflen < 8) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d INPUT_TERMINAL error\n", - udev->devnum, alts->desc.bInterfaceNumber); - return -EINVAL; - } - - /* Make sure the terminal type MSB is not null, otherwise it - * could be confused with a unit. - */ - type = get_unaligned_le16(&buffer[4]); - if ((type & 0xff00) == 0) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d INPUT_TERMINAL %d has invalid " - "type 0x%04x, skipping\n", udev->devnum, - alts->desc.bInterfaceNumber, - buffer[3], type); - return 0; - } - - n = 0; - p = 0; - len = 8; - - if (type == UVC_ITT_CAMERA) { - n = buflen >= 15 ? buffer[14] : 0; - len = 15; - - } else if (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) { - n = buflen >= 9 ? buffer[8] : 0; - p = buflen >= 10 + n ? buffer[9+n] : 0; - len = 10; - } - - if (buflen < len + n + p) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d INPUT_TERMINAL error\n", - udev->devnum, alts->desc.bInterfaceNumber); - return -EINVAL; - } - - term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3], - 1, n + p); - if (term == NULL) - return -ENOMEM; - - if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { - term->camera.bControlSize = n; - term->camera.bmControls = (__u8 *)term + sizeof *term; - term->camera.wObjectiveFocalLengthMin = - get_unaligned_le16(&buffer[8]); - term->camera.wObjectiveFocalLengthMax = - get_unaligned_le16(&buffer[10]); - term->camera.wOcularFocalLength = - get_unaligned_le16(&buffer[12]); - memcpy(term->camera.bmControls, &buffer[15], n); - } else if (UVC_ENTITY_TYPE(term) == - UVC_ITT_MEDIA_TRANSPORT_INPUT) { - term->media.bControlSize = n; - term->media.bmControls = (__u8 *)term + sizeof *term; - term->media.bTransportModeSize = p; - term->media.bmTransportModes = (__u8 *)term - + sizeof *term + n; - memcpy(term->media.bmControls, &buffer[9], n); - memcpy(term->media.bmTransportModes, &buffer[10+n], p); - } - - if (buffer[7] != 0) - usb_string(udev, buffer[7], term->name, - sizeof term->name); - else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) - sprintf(term->name, "Camera %u", buffer[3]); - else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) - sprintf(term->name, "Media %u", buffer[3]); - else - sprintf(term->name, "Input %u", buffer[3]); - - list_add_tail(&term->list, &dev->entities); - break; - - case UVC_VC_OUTPUT_TERMINAL: - if (buflen < 9) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d OUTPUT_TERMINAL error\n", - udev->devnum, alts->desc.bInterfaceNumber); - return -EINVAL; - } - - /* Make sure the terminal type MSB is not null, otherwise it - * could be confused with a unit. - */ - type = get_unaligned_le16(&buffer[4]); - if ((type & 0xff00) == 0) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d OUTPUT_TERMINAL %d has invalid " - "type 0x%04x, skipping\n", udev->devnum, - alts->desc.bInterfaceNumber, buffer[3], type); - return 0; - } - - term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3], - 1, 0); - if (term == NULL) - return -ENOMEM; - - memcpy(term->baSourceID, &buffer[7], 1); - - if (buffer[8] != 0) - usb_string(udev, buffer[8], term->name, - sizeof term->name); - else - sprintf(term->name, "Output %u", buffer[3]); - - list_add_tail(&term->list, &dev->entities); - break; - - case UVC_VC_SELECTOR_UNIT: - p = buflen >= 5 ? buffer[4] : 0; - - if (buflen < 5 || buflen < 6 + p) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d SELECTOR_UNIT error\n", - udev->devnum, alts->desc.bInterfaceNumber); - return -EINVAL; - } - - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0); - if (unit == NULL) - return -ENOMEM; - - memcpy(unit->baSourceID, &buffer[5], p); - - if (buffer[5+p] != 0) - usb_string(udev, buffer[5+p], unit->name, - sizeof unit->name); - else - sprintf(unit->name, "Selector %u", buffer[3]); - - list_add_tail(&unit->list, &dev->entities); - break; - - case UVC_VC_PROCESSING_UNIT: - n = buflen >= 8 ? buffer[7] : 0; - p = dev->uvc_version >= 0x0110 ? 10 : 9; - - if (buflen < p + n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d PROCESSING_UNIT error\n", - udev->devnum, alts->desc.bInterfaceNumber); - return -EINVAL; - } - - unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n); - if (unit == NULL) - return -ENOMEM; - - memcpy(unit->baSourceID, &buffer[4], 1); - unit->processing.wMaxMultiplier = - get_unaligned_le16(&buffer[5]); - unit->processing.bControlSize = buffer[7]; - unit->processing.bmControls = (__u8 *)unit + sizeof *unit; - memcpy(unit->processing.bmControls, &buffer[8], n); - if (dev->uvc_version >= 0x0110) - unit->processing.bmVideoStandards = buffer[9+n]; - - if (buffer[8+n] != 0) - usb_string(udev, buffer[8+n], unit->name, - sizeof unit->name); - else - sprintf(unit->name, "Processing %u", buffer[3]); - - list_add_tail(&unit->list, &dev->entities); - break; - - case UVC_VC_EXTENSION_UNIT: - p = buflen >= 22 ? buffer[21] : 0; - n = buflen >= 24 + p ? buffer[22+p] : 0; - - if (buflen < 24 + p + n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d EXTENSION_UNIT error\n", - udev->devnum, alts->desc.bInterfaceNumber); - return -EINVAL; - } - - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n); - if (unit == NULL) - return -ENOMEM; - - memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); - unit->extension.bNumControls = buffer[20]; - memcpy(unit->baSourceID, &buffer[22], p); - unit->extension.bControlSize = buffer[22+p]; - unit->extension.bmControls = (__u8 *)unit + sizeof *unit; - memcpy(unit->extension.bmControls, &buffer[23+p], n); - - if (buffer[23+p+n] != 0) - usb_string(udev, buffer[23+p+n], unit->name, - sizeof unit->name); - else - sprintf(unit->name, "Extension %u", buffer[3]); - - list_add_tail(&unit->list, &dev->entities); - break; - - default: - uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE " - "descriptor (%u)\n", buffer[2]); - break; - } - - return 0; -} - -static int uvc_parse_control(struct uvc_device *dev) -{ - struct usb_host_interface *alts = dev->intf->cur_altsetting; - unsigned char *buffer = alts->extra; - int buflen = alts->extralen; - int ret; - - /* Parse the default alternate setting only, as the UVC specification - * defines a single alternate setting, the default alternate setting - * zero. - */ - - while (buflen > 2) { - if (uvc_parse_vendor_control(dev, buffer, buflen) || - buffer[1] != USB_DT_CS_INTERFACE) - goto next_descriptor; - - if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0) - return ret; - -next_descriptor: - buflen -= buffer[0]; - buffer += buffer[0]; - } - - /* Check if the optional status endpoint is present. Built-in iSight - * webcams have an interrupt endpoint but spit proprietary data that - * don't conform to the UVC status endpoint messages. Don't try to - * handle the interrupt endpoint for those cameras. - */ - if (alts->desc.bNumEndpoints == 1 && - !(dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)) { - struct usb_host_endpoint *ep = &alts->endpoint[0]; - struct usb_endpoint_descriptor *desc = &ep->desc; - - if (usb_endpoint_is_int_in(desc) && - le16_to_cpu(desc->wMaxPacketSize) >= 8 && - desc->bInterval != 0) { - uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint " - "(addr %02x).\n", desc->bEndpointAddress); - dev->int_ep = ep; - } - } - - return 0; -} - -/* ------------------------------------------------------------------------ - * UVC device scan - */ - -/* - * Scan the UVC descriptors to locate a chain starting at an Output Terminal - * and containing the following units: - * - * - one or more Output Terminals (USB Streaming or Display) - * - zero or one Processing Unit - * - zero, one or more single-input Selector Units - * - zero or one multiple-input Selector Units, provided all inputs are - * connected to input terminals - * - zero, one or mode single-input Extension Units - * - one or more Input Terminals (Camera, External or USB Streaming) - * - * The terminal and units must match on of the following structures: - * - * ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0) - * ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ... - * ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n) - * - * +---------+ +---------+ -> OTT_*(0) - * TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ... - * +---------+ +---------+ -> OTT_*(n) - * - * The Processing Unit and Extension Units can be in any order. Additional - * Extension Units connected to the main chain as single-unit branches are - * also supported. Single-input Selector Units are ignored. - */ -static int uvc_scan_chain_entity(struct uvc_video_chain *chain, - struct uvc_entity *entity) -{ - switch (UVC_ENTITY_TYPE(entity)) { - case UVC_VC_EXTENSION_UNIT: - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- XU %d", entity->id); - - if (entity->bNrInPins != 1) { - uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more " - "than 1 input pin.\n", entity->id); - return -1; - } - - break; - - case UVC_VC_PROCESSING_UNIT: - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- PU %d", entity->id); - - if (chain->processing != NULL) { - uvc_trace(UVC_TRACE_DESCR, "Found multiple " - "Processing Units in chain.\n"); - return -1; - } - - chain->processing = entity; - break; - - case UVC_VC_SELECTOR_UNIT: - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- SU %d", entity->id); - - /* Single-input selector units are ignored. */ - if (entity->bNrInPins == 1) - break; - - if (chain->selector != NULL) { - uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector " - "Units in chain.\n"); - return -1; - } - - chain->selector = entity; - break; - - case UVC_ITT_VENDOR_SPECIFIC: - case UVC_ITT_CAMERA: - case UVC_ITT_MEDIA_TRANSPORT_INPUT: - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- IT %d\n", entity->id); - - break; - - case UVC_OTT_VENDOR_SPECIFIC: - case UVC_OTT_DISPLAY: - case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" OT %d", entity->id); - - break; - - case UVC_TT_STREAMING: - if (UVC_ENTITY_IS_ITERM(entity)) { - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- IT %d\n", entity->id); - } else { - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" OT %d", entity->id); - } - - break; - - default: - uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type " - "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity)); - return -1; - } - - list_add_tail(&entity->chain, &chain->entities); - return 0; -} - -static int uvc_scan_chain_forward(struct uvc_video_chain *chain, - struct uvc_entity *entity, struct uvc_entity *prev) -{ - struct uvc_entity *forward; - int found; - - /* Forward scan */ - forward = NULL; - found = 0; - - while (1) { - forward = uvc_entity_by_reference(chain->dev, entity->id, - forward); - if (forward == NULL) - break; - if (forward == prev) - continue; - - switch (UVC_ENTITY_TYPE(forward)) { - case UVC_VC_EXTENSION_UNIT: - if (forward->bNrInPins != 1) { - uvc_trace(UVC_TRACE_DESCR, "Extension unit %d " - "has more than 1 input pin.\n", - entity->id); - return -EINVAL; - } - - list_add_tail(&forward->chain, &chain->entities); - if (uvc_trace_param & UVC_TRACE_PROBE) { - if (!found) - printk(" (->"); - - printk(" XU %d", forward->id); - found = 1; - } - break; - - case UVC_OTT_VENDOR_SPECIFIC: - case UVC_OTT_DISPLAY: - case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: - case UVC_TT_STREAMING: - if (UVC_ENTITY_IS_ITERM(forward)) { - uvc_trace(UVC_TRACE_DESCR, "Unsupported input " - "terminal %u.\n", forward->id); - return -EINVAL; - } - - list_add_tail(&forward->chain, &chain->entities); - if (uvc_trace_param & UVC_TRACE_PROBE) { - if (!found) - printk(" (->"); - - printk(" OT %d", forward->id); - found = 1; - } - break; - } - } - if (found) - printk(")"); - - return 0; -} - -static int uvc_scan_chain_backward(struct uvc_video_chain *chain, - struct uvc_entity **_entity) -{ - struct uvc_entity *entity = *_entity; - struct uvc_entity *term; - int id = -EINVAL, i; - - switch (UVC_ENTITY_TYPE(entity)) { - case UVC_VC_EXTENSION_UNIT: - case UVC_VC_PROCESSING_UNIT: - id = entity->baSourceID[0]; - break; - - case UVC_VC_SELECTOR_UNIT: - /* Single-input selector units are ignored. */ - if (entity->bNrInPins == 1) { - id = entity->baSourceID[0]; - break; - } - - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- IT"); - - chain->selector = entity; - for (i = 0; i < entity->bNrInPins; ++i) { - id = entity->baSourceID[i]; - term = uvc_entity_by_id(chain->dev, id); - if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) { - uvc_trace(UVC_TRACE_DESCR, "Selector unit %d " - "input %d isn't connected to an " - "input terminal\n", entity->id, i); - return -1; - } - - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" %d", term->id); - - list_add_tail(&term->chain, &chain->entities); - uvc_scan_chain_forward(chain, term, entity); - } - - if (uvc_trace_param & UVC_TRACE_PROBE) - printk("\n"); - - id = 0; - break; - - case UVC_ITT_VENDOR_SPECIFIC: - case UVC_ITT_CAMERA: - case UVC_ITT_MEDIA_TRANSPORT_INPUT: - case UVC_OTT_VENDOR_SPECIFIC: - case UVC_OTT_DISPLAY: - case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: - case UVC_TT_STREAMING: - id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0; - break; - } - - if (id <= 0) { - *_entity = NULL; - return id; - } - - entity = uvc_entity_by_id(chain->dev, id); - if (entity == NULL) { - uvc_trace(UVC_TRACE_DESCR, "Found reference to " - "unknown entity %d.\n", id); - return -EINVAL; - } - - *_entity = entity; - return 0; -} - -static int uvc_scan_chain(struct uvc_video_chain *chain, - struct uvc_entity *term) -{ - struct uvc_entity *entity, *prev; - - uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:"); - - entity = term; - prev = NULL; - - while (entity != NULL) { - /* Entity must not be part of an existing chain */ - if (entity->chain.next || entity->chain.prev) { - uvc_trace(UVC_TRACE_DESCR, "Found reference to " - "entity %d already in chain.\n", entity->id); - return -EINVAL; - } - - /* Process entity */ - if (uvc_scan_chain_entity(chain, entity) < 0) - return -EINVAL; - - /* Forward scan */ - if (uvc_scan_chain_forward(chain, entity, prev) < 0) - return -EINVAL; - - /* Backward scan */ - prev = entity; - if (uvc_scan_chain_backward(chain, &entity) < 0) - return -EINVAL; - } - - return 0; -} - -static unsigned int uvc_print_terms(struct list_head *terms, u16 dir, - char *buffer) -{ - struct uvc_entity *term; - unsigned int nterms = 0; - char *p = buffer; - - list_for_each_entry(term, terms, chain) { - if (!UVC_ENTITY_IS_TERM(term) || - UVC_TERM_DIRECTION(term) != dir) - continue; - - if (nterms) - p += sprintf(p, ","); - if (++nterms >= 4) { - p += sprintf(p, "..."); - break; - } - p += sprintf(p, "%u", term->id); - } - - return p - buffer; -} - -static const char *uvc_print_chain(struct uvc_video_chain *chain) -{ - static char buffer[43]; - char *p = buffer; - - p += uvc_print_terms(&chain->entities, UVC_TERM_INPUT, p); - p += sprintf(p, " -> "); - uvc_print_terms(&chain->entities, UVC_TERM_OUTPUT, p); - - return buffer; -} - -/* - * Scan the device for video chains and register video devices. - * - * Chains are scanned starting at their output terminals and walked backwards. - */ -static int uvc_scan_device(struct uvc_device *dev) -{ - struct uvc_video_chain *chain; - struct uvc_entity *term; - - list_for_each_entry(term, &dev->entities, list) { - if (!UVC_ENTITY_IS_OTERM(term)) - continue; - - /* If the terminal is already included in a chain, skip it. - * This can happen for chains that have multiple output - * terminals, where all output terminals beside the first one - * will be inserted in the chain in forward scans. - */ - if (term->chain.next || term->chain.prev) - continue; - - chain = kzalloc(sizeof(*chain), GFP_KERNEL); - if (chain == NULL) - return -ENOMEM; - - INIT_LIST_HEAD(&chain->entities); - mutex_init(&chain->ctrl_mutex); - chain->dev = dev; - - if (uvc_scan_chain(chain, term) < 0) { - kfree(chain); - continue; - } - - uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n", - uvc_print_chain(chain)); - - list_add_tail(&chain->list, &dev->chains); - } - - if (list_empty(&dev->chains)) { - uvc_printk(KERN_INFO, "No valid video chain found.\n"); - return -1; - } - - return 0; -} - -/* ------------------------------------------------------------------------ - * Video device registration and unregistration - */ - -/* - * Delete the UVC device. - * - * Called by the kernel when the last reference to the uvc_device structure - * is released. - * - * As this function is called after or during disconnect(), all URBs have - * already been canceled by the USB core. There is no need to kill the - * interrupt URB manually. - */ -static void uvc_delete(struct uvc_device *dev) -{ - struct list_head *p, *n; - - usb_put_intf(dev->intf); - usb_put_dev(dev->udev); - - uvc_status_cleanup(dev); - uvc_ctrl_cleanup_device(dev); - - list_for_each_safe(p, n, &dev->chains) { - struct uvc_video_chain *chain; - chain = list_entry(p, struct uvc_video_chain, list); - kfree(chain); - } - - list_for_each_safe(p, n, &dev->entities) { - struct uvc_entity *entity; - entity = list_entry(p, struct uvc_entity, list); - kfree(entity); - } - - list_for_each_safe(p, n, &dev->streams) { - struct uvc_streaming *streaming; - streaming = list_entry(p, struct uvc_streaming, list); - usb_driver_release_interface(&uvc_driver.driver, - streaming->intf); - usb_put_intf(streaming->intf); - kfree(streaming->format); - kfree(streaming->header.bmaControls); - kfree(streaming); - } - - kfree(dev); -} - -static void uvc_release(struct video_device *vdev) -{ - struct uvc_streaming *stream = video_get_drvdata(vdev); - struct uvc_device *dev = stream->dev; - - video_device_release(vdev); - - /* Decrement the registered streams count and delete the device when it - * reaches zero. - */ - if (atomic_dec_and_test(&dev->nstreams)) - uvc_delete(dev); -} - -/* - * Unregister the video devices. - */ -static void uvc_unregister_video(struct uvc_device *dev) -{ - struct uvc_streaming *stream; - - /* Unregistering all video devices might result in uvc_delete() being - * called from inside the loop if there's no open file handle. To avoid - * that, increment the stream count before iterating over the streams - * and decrement it when done. - */ - atomic_inc(&dev->nstreams); - - list_for_each_entry(stream, &dev->streams, list) { - if (stream->vdev == NULL) - continue; - - video_unregister_device(stream->vdev); - stream->vdev = NULL; - } - - /* Decrement the stream count and call uvc_delete explicitly if there - * are no stream left. - */ - if (atomic_dec_and_test(&dev->nstreams)) - uvc_delete(dev); -} - -static int uvc_register_video(struct uvc_device *dev, - struct uvc_streaming *stream) -{ - struct video_device *vdev; - int ret; - - /* Initialize the streaming interface with default streaming - * parameters. - */ - ret = uvc_video_init(stream); - if (ret < 0) { - uvc_printk(KERN_ERR, "Failed to initialize the device " - "(%d).\n", ret); - return ret; - } - - /* Register the device with V4L. */ - vdev = video_device_alloc(); - if (vdev == NULL) { - uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n", - ret); - return -ENOMEM; - } - - /* We already hold a reference to dev->udev. The video device will be - * unregistered before the reference is released, so we don't need to - * get another one. - */ - vdev->parent = &dev->intf->dev; - vdev->fops = &uvc_fops; - vdev->release = uvc_release; - strlcpy(vdev->name, dev->name, sizeof vdev->name); - - /* Set the driver data before calling video_register_device, otherwise - * uvc_v4l2_open might race us. - */ - stream->vdev = vdev; - video_set_drvdata(vdev, stream); - - ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); - if (ret < 0) { - uvc_printk(KERN_ERR, "Failed to register video device (%d).\n", - ret); - stream->vdev = NULL; - video_device_release(vdev); - return ret; - } - - atomic_inc(&dev->nstreams); - return 0; -} - -/* - * Register all video devices in all chains. - */ -static int uvc_register_terms(struct uvc_device *dev, - struct uvc_video_chain *chain) -{ - struct uvc_streaming *stream; - struct uvc_entity *term; - int ret; - - list_for_each_entry(term, &chain->entities, chain) { - if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING) - continue; - - stream = uvc_stream_by_id(dev, term->id); - if (stream == NULL) { - uvc_printk(KERN_INFO, "No streaming interface found " - "for terminal %u.", term->id); - continue; - } - - stream->chain = chain; - ret = uvc_register_video(dev, stream); - if (ret < 0) - return ret; - } - - return 0; -} - -static int uvc_register_chains(struct uvc_device *dev) -{ - struct uvc_video_chain *chain; - int ret; - - list_for_each_entry(chain, &dev->chains, list) { - ret = uvc_register_terms(dev, chain); - if (ret < 0) - return ret; - } - - return 0; -} - -/* ------------------------------------------------------------------------ - * USB probe, disconnect, suspend and resume - */ - -static int uvc_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct uvc_device *dev; - int ret; - - if (id->idVendor && id->idProduct) - uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s " - "(%04x:%04x)\n", udev->devpath, id->idVendor, - id->idProduct); - else - uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n", - udev->devpath); - - /* Allocate memory for the device and initialize it. */ - if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL) - return -ENOMEM; - - INIT_LIST_HEAD(&dev->entities); - INIT_LIST_HEAD(&dev->chains); - INIT_LIST_HEAD(&dev->streams); - atomic_set(&dev->nstreams, 0); - atomic_set(&dev->users, 0); - atomic_set(&dev->nmappings, 0); - - dev->udev = usb_get_dev(udev); - dev->intf = usb_get_intf(intf); - dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; - dev->quirks = (uvc_quirks_param == -1) - ? id->driver_info : uvc_quirks_param; - - if (udev->product != NULL) - strlcpy(dev->name, udev->product, sizeof dev->name); - else - snprintf(dev->name, sizeof dev->name, - "UVC Camera (%04x:%04x)", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - - /* Parse the Video Class control descriptor. */ - if (uvc_parse_control(dev) < 0) { - uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC " - "descriptors.\n"); - goto error; - } - - uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n", - dev->uvc_version >> 8, dev->uvc_version & 0xff, - udev->product ? udev->product : "", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - - if (dev->quirks != id->driver_info) { - uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module " - "parameter for testing purpose.\n", dev->quirks); - uvc_printk(KERN_INFO, "Please report required quirks to the " - "linux-uvc-devel mailing list.\n"); - } - - /* Initialize controls. */ - if (uvc_ctrl_init_device(dev) < 0) - goto error; - - /* Scan the device for video chains. */ - if (uvc_scan_device(dev) < 0) - goto error; - - /* Register video devices. */ - if (uvc_register_chains(dev) < 0) - goto error; - - /* Save our data pointer in the interface data. */ - usb_set_intfdata(intf, dev); - - /* Initialize the interrupt URB. */ - if ((ret = uvc_status_init(dev)) < 0) { - uvc_printk(KERN_INFO, "Unable to initialize the status " - "endpoint (%d), status interrupt will not be " - "supported.\n", ret); - } - - uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n"); - usb_enable_autosuspend(udev); - return 0; - -error: - uvc_unregister_video(dev); - return -ENODEV; -} - -static void uvc_disconnect(struct usb_interface *intf) -{ - struct uvc_device *dev = usb_get_intfdata(intf); - - /* Set the USB interface data to NULL. This can be done outside the - * lock, as there's no other reader. - */ - usb_set_intfdata(intf, NULL); - - if (intf->cur_altsetting->desc.bInterfaceSubClass == - UVC_SC_VIDEOSTREAMING) - return; - - dev->state |= UVC_DEV_DISCONNECTED; - - uvc_unregister_video(dev); -} - -static int uvc_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct uvc_device *dev = usb_get_intfdata(intf); - struct uvc_streaming *stream; - - uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n", - intf->cur_altsetting->desc.bInterfaceNumber); - - /* Controls are cached on the fly so they don't need to be saved. */ - if (intf->cur_altsetting->desc.bInterfaceSubClass == - UVC_SC_VIDEOCONTROL) - return uvc_status_suspend(dev); - - list_for_each_entry(stream, &dev->streams, list) { - if (stream->intf == intf) - return uvc_video_suspend(stream); - } - - uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface " - "mismatch.\n"); - return -EINVAL; -} - -static int __uvc_resume(struct usb_interface *intf, int reset) -{ - struct uvc_device *dev = usb_get_intfdata(intf); - struct uvc_streaming *stream; - - uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n", - intf->cur_altsetting->desc.bInterfaceNumber); - - if (intf->cur_altsetting->desc.bInterfaceSubClass == - UVC_SC_VIDEOCONTROL) { - if (reset) { - int ret = uvc_ctrl_resume_device(dev); - - if (ret < 0) - return ret; - } - - return uvc_status_resume(dev); - } - - list_for_each_entry(stream, &dev->streams, list) { - if (stream->intf == intf) - return uvc_video_resume(stream); - } - - uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface " - "mismatch.\n"); - return -EINVAL; -} - -static int uvc_resume(struct usb_interface *intf) -{ - return __uvc_resume(intf, 0); -} - -static int uvc_reset_resume(struct usb_interface *intf) -{ - return __uvc_resume(intf, 1); -} - -/* ------------------------------------------------------------------------ - * Module parameters - */ - -static int uvc_clock_param_get(char *buffer, struct kernel_param *kp) -{ - if (uvc_clock_param == CLOCK_MONOTONIC) - return sprintf(buffer, "CLOCK_MONOTONIC"); - else - return sprintf(buffer, "CLOCK_REALTIME"); -} - -static int uvc_clock_param_set(const char *val, struct kernel_param *kp) -{ - if (strncasecmp(val, "clock_", strlen("clock_")) == 0) - val += strlen("clock_"); - - if (strcasecmp(val, "monotonic") == 0) - uvc_clock_param = CLOCK_MONOTONIC; - else if (strcasecmp(val, "realtime") == 0) - uvc_clock_param = CLOCK_REALTIME; - else - return -EINVAL; - - return 0; -} - -module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get, - &uvc_clock_param, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(clock, "Video buffers timestamp clock"); -module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames"); -module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(quirks, "Forced device quirks"); -module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(trace, "Trace level bitmask"); -module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); - -/* ------------------------------------------------------------------------ - * Driver initialization and cleanup - */ - -/* - * The Logitech cameras listed below have their interface class set to - * VENDOR_SPEC because they don't announce themselves as UVC devices, even - * though they are compliant. - */ -static struct usb_device_id uvc_ids[] = { - /* Genius eFace 2025 */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0458, - .idProduct = 0x706e, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Microsoft Lifecam NX-6000 */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x045e, - .idProduct = 0x00f8, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Microsoft Lifecam VX-7000 */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x045e, - .idProduct = 0x0723, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Logitech Quickcam Fusion */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x046d, - .idProduct = 0x08c1, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0 }, - /* Logitech Quickcam Orbit MP */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x046d, - .idProduct = 0x08c2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0 }, - /* Logitech Quickcam Pro for Notebook */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x046d, - .idProduct = 0x08c3, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0 }, - /* Logitech Quickcam Pro 5000 */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x046d, - .idProduct = 0x08c5, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0 }, - /* Logitech Quickcam OEM Dell Notebook */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x046d, - .idProduct = 0x08c6, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0 }, - /* Logitech Quickcam OEM Cisco VT Camera II */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x046d, - .idProduct = 0x08c7, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0 }, - /* Chicony CNF7129 (Asus EEE 100HE) */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x04f2, - .idProduct = 0xb071, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_RESTRICT_FRAME_RATE }, - /* Alcor Micro AU3820 (Future Boy PC USB Webcam) */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x058f, - .idProduct = 0x3820, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Apple Built-In iSight */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x05ac, - .idProduct = 0x8501, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX - | UVC_QUIRK_BUILTIN_ISIGHT }, - /* Genesys Logic USB 2.0 PC Camera */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x05e3, - .idProduct = 0x0505, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* ViMicro Vega */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0ac8, - .idProduct = 0x332d, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, - /* ViMicro - Minoru3D */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0ac8, - .idProduct = 0x3410, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, - /* ViMicro Venus - Minoru3D */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0ac8, - .idProduct = 0x3420, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, - /* MT6227 */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0e8d, - .idProduct = 0x0004, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX - | UVC_QUIRK_PROBE_DEF }, - /* IMC Networks (Medion Akoya) */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x13d3, - .idProduct = 0x5103, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Syntek (HP Spartan) */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x174f, - .idProduct = 0x5212, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Syntek (Samsung Q310) */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x174f, - .idProduct = 0x5931, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Syntek (Packard Bell EasyNote MX52 */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x174f, - .idProduct = 0x8a12, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Syntek (Asus F9SG) */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x174f, - .idProduct = 0x8a31, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Syntek (Asus U3S) */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x174f, - .idProduct = 0x8a33, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Syntek (JAOtech Smart Terminal) */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x174f, - .idProduct = 0x8a34, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Miricle 307K */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x17dc, - .idProduct = 0x0202, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Lenovo Thinkpad SL400/SL500 */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x17ef, - .idProduct = 0x480b, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Aveo Technology USB 2.0 Camera */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x1871, - .idProduct = 0x0306, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX - | UVC_QUIRK_PROBE_EXTRAFIELDS }, - /* Ecamm Pico iMage */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x18cd, - .idProduct = 0xcafe, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS }, - /* Manta MM-353 Plako */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x18ec, - .idProduct = 0x3188, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* FSC WebCam V30S */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x18ec, - .idProduct = 0x3288, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Arkmicro unbranded */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x18ec, - .idProduct = 0x3290, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_DEF }, - /* Bodelin ProScopeHR */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_DEV_HI - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x19ab, - .idProduct = 0x1000, - .bcdDevice_hi = 0x0126, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STATUS_INTERVAL }, - /* MSI StarCam 370i */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x1b3b, - .idProduct = 0x2951, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* SiGma Micro USB Web Camera */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x1c4f, - .idProduct = 0x3000, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX - | UVC_QUIRK_IGNORE_SELECTOR_UNIT }, - /* Generic USB Video Class */ - { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, - {} -}; - -MODULE_DEVICE_TABLE(usb, uvc_ids); - -struct uvc_driver uvc_driver = { - .driver = { - .name = "uvcvideo", - .probe = uvc_probe, - .disconnect = uvc_disconnect, - .suspend = uvc_suspend, - .resume = uvc_resume, - .reset_resume = uvc_reset_resume, - .id_table = uvc_ids, - .supports_autosuspend = 1, - }, -}; - -static int __init uvc_init(void) -{ - int result; - - result = usb_register(&uvc_driver.driver); - if (result == 0) - printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n"); - return result; -} - -static void __exit uvc_cleanup(void) -{ - usb_deregister(&uvc_driver.driver); -} - -module_init(uvc_init); -module_exit(uvc_cleanup); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_isight.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_isight.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_isight.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_isight.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,137 +0,0 @@ -/* - * uvc_isight.c -- USB Video Class driver - iSight support - * - * Copyright (C) 2006-2007 - * Ivan N. Zlatev - * Copyright (C) 2008-2009 - * Laurent Pinchart - * - * 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, or - * (at your option) any later version. - * - */ - -#include -#include -#include - -#include "uvcvideo.h" - -/* Built-in iSight webcams implements most of UVC 1.0 except a - * different packet format. Instead of sending a header at the - * beginning of each isochronous transfer payload, the webcam sends a - * single header per image (on its own in a packet), followed by - * packets containing data only. - * - * Offset Size (bytes) Description - * ------------------------------------------------------------------ - * 0x00 1 Header length - * 0x01 1 Flags (UVC-compliant) - * 0x02 4 Always equal to '11223344' - * 0x06 8 Always equal to 'deadbeefdeadface' - * 0x0e 16 Unknown - * - * The header can be prefixed by an optional, unknown-purpose byte. - */ - -static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, - const __u8 *data, unsigned int len) -{ - static const __u8 hdr[] = { - 0x11, 0x22, 0x33, 0x44, - 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xfa, 0xce - }; - - unsigned int maxlen, nbytes; - __u8 *mem; - int is_header = 0; - - if (buf == NULL) - return 0; - - if ((len >= 14 && memcmp(&data[2], hdr, 12) == 0) || - (len >= 15 && memcmp(&data[3], hdr, 12) == 0)) { - uvc_trace(UVC_TRACE_FRAME, "iSight header found\n"); - is_header = 1; - } - - /* Synchronize to the input stream by waiting for a header packet. */ - if (buf->state != UVC_BUF_STATE_ACTIVE) { - if (!is_header) { - uvc_trace(UVC_TRACE_FRAME, "Dropping packet (out of " - "sync).\n"); - return 0; - } - - buf->state = UVC_BUF_STATE_ACTIVE; - } - - /* Mark the buffer as done if we're at the beginning of a new frame. - * - * Empty buffers (bytesused == 0) don't trigger end of frame detection - * as it doesn't make sense to return an empty buffer. - */ - if (is_header && buf->buf.bytesused != 0) { - buf->state = UVC_BUF_STATE_DONE; - return -EAGAIN; - } - - /* Copy the video data to the buffer. Skip header packets, as they - * contain no data. - */ - if (!is_header) { - maxlen = buf->buf.length - buf->buf.bytesused; - mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused; - nbytes = min(len, maxlen); - memcpy(mem, data, nbytes); - buf->buf.bytesused += nbytes; - - if (len > maxlen || buf->buf.bytesused == buf->buf.length) { - uvc_trace(UVC_TRACE_FRAME, "Frame complete " - "(overflow).\n"); - buf->state = UVC_BUF_STATE_DONE; - } - } - - return 0; -} - -void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, - struct uvc_buffer *buf) -{ - int ret, i; - - for (i = 0; i < urb->number_of_packets; ++i) { - if (urb->iso_frame_desc[i].status < 0) { - uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame " - "lost (%d).\n", - urb->iso_frame_desc[i].status); - } - - /* Decode the payload packet. - * uvc_video_decode is entered twice when a frame transition - * has been detected because the end of frame can only be - * reliably detected when the first packet of the new frame - * is processed. The first pass detects the transition and - * closes the previous frame's buffer, the second pass - * processes the data of the first payload of the new frame. - */ - do { - ret = isight_decode(&stream->queue, buf, - urb->transfer_buffer + - urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - - if (buf == NULL) - break; - - if (buf->state == UVC_BUF_STATE_DONE || - buf->state == UVC_BUF_STATE_ERROR) - buf = uvc_queue_next_buffer(&stream->queue, - buf); - } while (ret == -EAGAIN); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_queue.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_queue.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_queue.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_queue.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,600 +0,0 @@ -/* - * uvc_queue.c -- USB Video Class driver - Buffers management - * - * Copyright (C) 2005-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.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, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "uvcvideo.h" - -/* ------------------------------------------------------------------------ - * Video buffers queue management. - * - * Video queues is initialized by uvc_queue_init(). The function performs - * basic initialization of the uvc_video_queue struct and never fails. - * - * Video buffer allocation and freeing are performed by uvc_alloc_buffers and - * uvc_free_buffers respectively. The former acquires the video queue lock, - * while the later must be called with the lock held (so that allocation can - * free previously allocated buffers). Trying to free buffers that are mapped - * to user space will return -EBUSY. - * - * Video buffers are managed using two queues. However, unlike most USB video - * drivers that use an in queue and an out queue, we use a main queue to hold - * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to - * hold empty buffers. This design (copied from video-buf) minimizes locking - * in interrupt, as only one queue is shared between interrupt and user - * contexts. - * - * Use cases - * --------- - * - * Unless stated otherwise, all operations that modify the irq buffers queue - * are protected by the irq spinlock. - * - * 1. The user queues the buffers, starts streaming and dequeues a buffer. - * - * The buffers are added to the main and irq queues. Both operations are - * protected by the queue lock, and the later is protected by the irq - * spinlock as well. - * - * The completion handler fetches a buffer from the irq queue and fills it - * with video data. If no buffer is available (irq queue empty), the handler - * returns immediately. - * - * When the buffer is full, the completion handler removes it from the irq - * queue, marks it as done (UVC_BUF_STATE_DONE) and wakes its wait queue. - * At that point, any process waiting on the buffer will be woken up. If a - * process tries to dequeue a buffer after it has been marked done, the - * dequeing will succeed immediately. - * - * 2. Buffers are queued, user is waiting on a buffer and the device gets - * disconnected. - * - * When the device is disconnected, the kernel calls the completion handler - * with an appropriate status code. The handler marks all buffers in the - * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so - * that any process waiting on a buffer gets woken up. - * - * Waking up up the first buffer on the irq list is not enough, as the - * process waiting on the buffer might restart the dequeue operation - * immediately. - * - */ - -void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, - int drop_corrupted) -{ - mutex_init(&queue->mutex); - spin_lock_init(&queue->irqlock); - INIT_LIST_HEAD(&queue->mainqueue); - INIT_LIST_HEAD(&queue->irqqueue); - queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; - queue->type = type; -} - -/* - * Free the video buffers. - * - * This function must be called with the queue lock held. - */ -static int __uvc_free_buffers(struct uvc_video_queue *queue) -{ - unsigned int i; - - for (i = 0; i < queue->count; ++i) { - if (queue->buffer[i].vma_use_count != 0) - return -EBUSY; - } - - if (queue->count) { - vfree(queue->mem); - queue->count = 0; - } - - return 0; -} - -int uvc_free_buffers(struct uvc_video_queue *queue) -{ - int ret; - - mutex_lock(&queue->mutex); - ret = __uvc_free_buffers(queue); - mutex_unlock(&queue->mutex); - - return ret; -} - -/* - * Allocate the video buffers. - * - * Pages are reserved to make sure they will not be swapped, as they will be - * filled in the URB completion handler. - * - * Buffers will be individually mapped, so they must all be page aligned. - */ -int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, - unsigned int buflength) -{ - unsigned int bufsize = PAGE_ALIGN(buflength); - unsigned int i; - void *mem = NULL; - int ret; - - if (nbuffers > UVC_MAX_VIDEO_BUFFERS) - nbuffers = UVC_MAX_VIDEO_BUFFERS; - - mutex_lock(&queue->mutex); - - if ((ret = __uvc_free_buffers(queue)) < 0) - goto done; - - /* Bail out if no buffers should be allocated. */ - if (nbuffers == 0) - goto done; - - /* Decrement the number of buffers until allocation succeeds. */ - for (; nbuffers > 0; --nbuffers) { - mem = vmalloc_32(nbuffers * bufsize); - if (mem != NULL) - break; - } - - if (mem == NULL) { - ret = -ENOMEM; - goto done; - } - - for (i = 0; i < nbuffers; ++i) { - memset(&queue->buffer[i], 0, sizeof queue->buffer[i]); - queue->buffer[i].buf.index = i; - queue->buffer[i].buf.m.offset = i * bufsize; - queue->buffer[i].buf.length = buflength; - queue->buffer[i].buf.type = queue->type; - queue->buffer[i].buf.field = V4L2_FIELD_NONE; - queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP; - queue->buffer[i].buf.flags = 0; - init_waitqueue_head(&queue->buffer[i].wait); - } - - queue->mem = mem; - queue->count = nbuffers; - queue->buf_size = bufsize; - ret = nbuffers; - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -/* - * Check if buffers have been allocated. - */ -int uvc_queue_allocated(struct uvc_video_queue *queue) -{ - int allocated; - - mutex_lock(&queue->mutex); - allocated = queue->count != 0; - mutex_unlock(&queue->mutex); - - return allocated; -} - -static void __uvc_query_buffer(struct uvc_buffer *buf, - struct v4l2_buffer *v4l2_buf) -{ - memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf); - - if (buf->vma_use_count) - v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - case UVC_BUF_STATE_DONE: - v4l2_buf->flags |= V4L2_BUF_FLAG_DONE; - break; - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - case UVC_BUF_STATE_READY: - v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case UVC_BUF_STATE_IDLE: - default: - break; - } -} - -int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf) -{ - int ret = 0; - - mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - ret = -EINVAL; - goto done; - } - - __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf); - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -/* - * Queue a video buffer. Attempting to queue a buffer that has already been - * queued will return -EINVAL. - */ -int uvc_queue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf) -{ - struct uvc_buffer *buf; - unsigned long flags; - int ret = 0; - - uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index); - - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } - - mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n"); - ret = -EINVAL; - goto done; - } - - buf = &queue->buffer[v4l2_buf->index]; - if (buf->state != UVC_BUF_STATE_IDLE) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state " - "(%u).\n", buf->state); - ret = -EINVAL; - goto done; - } - - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - v4l2_buf->bytesused > buf->buf.length) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); - ret = -EINVAL; - goto done; - } - - spin_lock_irqsave(&queue->irqlock, flags); - if (queue->flags & UVC_QUEUE_DISCONNECTED) { - spin_unlock_irqrestore(&queue->irqlock, flags); - ret = -ENODEV; - goto done; - } - buf->state = UVC_BUF_STATE_QUEUED; - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - buf->buf.bytesused = 0; - else - buf->buf.bytesused = v4l2_buf->bytesused; - - list_add_tail(&buf->stream, &queue->mainqueue); - list_add_tail(&buf->queue, &queue->irqqueue); - spin_unlock_irqrestore(&queue->irqlock, flags); - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking) -{ - if (nonblocking) { - return (buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE && - buf->state != UVC_BUF_STATE_READY) - ? 0 : -EAGAIN; - } - - return wait_event_interruptible(buf->wait, - buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE && - buf->state != UVC_BUF_STATE_READY); -} - -/* - * Dequeue a video buffer. If nonblocking is false, block until a buffer is - * available. - */ -int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking) -{ - struct uvc_buffer *buf; - int ret = 0; - - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } - - mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n"); - ret = -EINVAL; - goto done; - } - - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0) - goto done; - - uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n", - buf->buf.index, buf->state, buf->buf.bytesused); - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data " - "(transmission error).\n"); - ret = -EIO; - case UVC_BUF_STATE_DONE: - buf->state = UVC_BUF_STATE_IDLE; - break; - - case UVC_BUF_STATE_IDLE: - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - case UVC_BUF_STATE_READY: - default: - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u " - "(driver bug?).\n", buf->state); - ret = -EINVAL; - goto done; - } - - list_del(&buf->stream); - __uvc_query_buffer(buf, v4l2_buf); - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -/* - * VMA operations. - */ -static void uvc_vm_open(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count++; -} - -static void uvc_vm_close(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count--; -} - -static const struct vm_operations_struct uvc_vm_ops = { - .open = uvc_vm_open, - .close = uvc_vm_close, -}; - -/* - * Memory-map a video buffer. - * - * This function implements video buffers memory mapping and is intended to be - * used by the device mmap handler. - */ -int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) -{ - struct uvc_buffer *uninitialized_var(buffer); - struct page *page; - unsigned long addr, start, size; - unsigned int i; - int ret = 0; - - start = vma->vm_start; - size = vma->vm_end - vma->vm_start; - - mutex_lock(&queue->mutex); - - for (i = 0; i < queue->count; ++i) { - buffer = &queue->buffer[i]; - if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - - if (i == queue->count || size != queue->buf_size) { - ret = -EINVAL; - goto done; - } - - /* - * VM_IO marks the area as being an mmaped region for I/O to a - * device. It also prevents the region from being core dumped. - */ - vma->vm_flags |= VM_IO; - - addr = (unsigned long)queue->mem + buffer->buf.m.offset; - while (size > 0) { - page = vmalloc_to_page((void *)addr); - if ((ret = vm_insert_page(vma, start, page)) < 0) - goto done; - - start += PAGE_SIZE; - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &uvc_vm_ops; - vma->vm_private_data = buffer; - uvc_vm_open(vma); - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -/* - * Poll the video queue. - * - * This function implements video queue polling and is intended to be used by - * the device poll handler. - */ -unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait) -{ - struct uvc_buffer *buf; - unsigned int mask = 0; - - mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) { - mask |= POLLERR; - goto done; - } - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - - poll_wait(file, &buf->wait, wait); - if (buf->state == UVC_BUF_STATE_DONE || - buf->state == UVC_BUF_STATE_ERROR) { - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - mask |= POLLIN | POLLRDNORM; - else - mask |= POLLOUT | POLLWRNORM; - } - -done: - mutex_unlock(&queue->mutex); - return mask; -} - -/* - * Enable or disable the video buffers queue. - * - * The queue must be enabled before starting video acquisition and must be - * disabled after stopping it. This ensures that the video buffers queue - * state can be properly initialized before buffers are accessed from the - * interrupt handler. - * - * Enabling the video queue returns -EBUSY if the queue is already enabled. - * - * Disabling the video queue cancels the queue and removes all buffers from - * the main queue. - * - * This function can't be called from interrupt context. Use - * uvc_queue_cancel() instead. - */ -int uvc_queue_enable(struct uvc_video_queue *queue, int enable) -{ - unsigned int i; - int ret = 0; - - mutex_lock(&queue->mutex); - if (enable) { - if (uvc_queue_streaming(queue)) { - ret = -EBUSY; - goto done; - } - queue->flags |= UVC_QUEUE_STREAMING; - queue->buf_used = 0; - } else { - uvc_queue_cancel(queue, 0); - INIT_LIST_HEAD(&queue->mainqueue); - - for (i = 0; i < queue->count; ++i) { - queue->buffer[i].error = 0; - queue->buffer[i].state = UVC_BUF_STATE_IDLE; - } - - queue->flags &= ~UVC_QUEUE_STREAMING; - } - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -/* - * Cancel the video buffers queue. - * - * Cancelling the queue marks all buffers on the irq queue as erroneous, - * wakes them up and removes them from the queue. - * - * If the disconnect parameter is set, further calls to uvc_queue_buffer will - * fail with -ENODEV. - * - * This function acquires the irq spinlock and can be called from interrupt - * context. - */ -void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) -{ - struct uvc_buffer *buf; - unsigned long flags; - - spin_lock_irqsave(&queue->irqlock, flags); - while (!list_empty(&queue->irqqueue)) { - buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - list_del(&buf->queue); - buf->state = UVC_BUF_STATE_ERROR; - wake_up(&buf->wait); - } - /* This must be protected by the irqlock spinlock to avoid race - * conditions between uvc_queue_buffer and the disconnection event that - * could result in an interruptible wait in uvc_dequeue_buffer. Do not - * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED - * state outside the queue code. - */ - if (disconnect) - queue->flags |= UVC_QUEUE_DISCONNECTED; - spin_unlock_irqrestore(&queue->irqlock, flags); -} - -struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, - struct uvc_buffer *buf) -{ - struct uvc_buffer *nextbuf; - unsigned long flags; - - if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) { - buf->error = 0; - buf->state = UVC_BUF_STATE_QUEUED; - buf->buf.bytesused = 0; - return buf; - } - - spin_lock_irqsave(&queue->irqlock, flags); - list_del(&buf->queue); - buf->error = 0; - buf->state = UVC_BUF_STATE_DONE; - if (!list_empty(&queue->irqqueue)) - nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - else - nextbuf = NULL; - spin_unlock_irqrestore(&queue->irqlock, flags); - - wake_up(&buf->wait); - return nextbuf; -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_status.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_status.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_status.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_status.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,237 +0,0 @@ -/* - * uvc_status.c -- USB Video Class driver - Status endpoint - * - * Copyright (C) 2005-2009 - * Laurent Pinchart (laurent.pinchart@ideasonboard.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, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include - -#include "uvcvideo.h" - -/* -------------------------------------------------------------------------- - * Input device - */ -#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV -static int uvc_input_init(struct uvc_device *dev) -{ - struct input_dev *input; - int ret; - - input = input_allocate_device(); - if (input == NULL) - return -ENOMEM; - - usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys)); - strlcat(dev->input_phys, "/button", sizeof(dev->input_phys)); - - input->name = dev->name; - input->phys = dev->input_phys; - usb_to_input_id(dev->udev, &input->id); - input->dev.parent = &dev->intf->dev; - - __set_bit(EV_KEY, input->evbit); - __set_bit(KEY_CAMERA, input->keybit); - - if ((ret = input_register_device(input)) < 0) - goto error; - - dev->input = input; - return 0; - -error: - input_free_device(input); - return ret; -} - -static void uvc_input_cleanup(struct uvc_device *dev) -{ - if (dev->input) - input_unregister_device(dev->input); -} - -static void uvc_input_report_key(struct uvc_device *dev, unsigned int code, - int value) -{ - if (dev->input) { - input_report_key(dev->input, code, value); - input_sync(dev->input); - } -} - -#else -#define uvc_input_init(dev) -#define uvc_input_cleanup(dev) -#define uvc_input_report_key(dev, code, value) -#endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */ - -/* -------------------------------------------------------------------------- - * Status interrupt endpoint - */ -static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len) -{ - if (len < 3) { - uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event " - "received.\n"); - return; - } - - if (data[2] == 0) { - if (len < 4) - return; - uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n", - data[1], data[3] ? "pressed" : "released", len); - uvc_input_report_key(dev, KEY_CAMERA, data[3]); - } else { - uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x " - "len %d.\n", data[1], data[2], data[3], len); - } -} - -static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len) -{ - char *attrs[3] = { "value", "info", "failure" }; - - if (len < 6 || data[2] != 0 || data[4] > 2) { - uvc_trace(UVC_TRACE_STATUS, "Invalid control status event " - "received.\n"); - return; - } - - uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n", - data[1], data[3], attrs[data[4]], len); -} - -static void uvc_status_complete(struct urb *urb) -{ - struct uvc_device *dev = urb->context; - int len, ret; - - switch (urb->status) { - case 0: - break; - - case -ENOENT: /* usb_kill_urb() called. */ - case -ECONNRESET: /* usb_unlink_urb() called. */ - case -ESHUTDOWN: /* The endpoint is being disabled. */ - case -EPROTO: /* Device is disconnected (reported by some - * host controller). */ - return; - - default: - uvc_printk(KERN_WARNING, "Non-zero status (%d) in status " - "completion handler.\n", urb->status); - return; - } - - len = urb->actual_length; - if (len > 0) { - switch (dev->status[0] & 0x0f) { - case UVC_STATUS_TYPE_CONTROL: - uvc_event_control(dev, dev->status, len); - break; - - case UVC_STATUS_TYPE_STREAMING: - uvc_event_streaming(dev, dev->status, len); - break; - - default: - uvc_trace(UVC_TRACE_STATUS, "Unknown status event " - "type %u.\n", dev->status[0]); - break; - } - } - - /* Resubmit the URB. */ - urb->interval = dev->int_ep->desc.bInterval; - if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n", - ret); - } -} - -int uvc_status_init(struct uvc_device *dev) -{ - struct usb_host_endpoint *ep = dev->int_ep; - unsigned int pipe; - int interval; - - if (ep == NULL) - return 0; - - uvc_input_init(dev); - - dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL); - if (dev->status == NULL) - return -ENOMEM; - - dev->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (dev->int_urb == NULL) { - kfree(dev->status); - return -ENOMEM; - } - - pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress); - - /* For high-speed interrupt endpoints, the bInterval value is used as - * an exponent of two. Some developers forgot about it. - */ - interval = ep->desc.bInterval; - if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH && - (dev->quirks & UVC_QUIRK_STATUS_INTERVAL)) - interval = fls(interval) - 1; - - usb_fill_int_urb(dev->int_urb, dev->udev, pipe, - dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, - dev, interval); - - return 0; -} - -void uvc_status_cleanup(struct uvc_device *dev) -{ - usb_kill_urb(dev->int_urb); - usb_free_urb(dev->int_urb); - kfree(dev->status); - uvc_input_cleanup(dev); -} - -int uvc_status_start(struct uvc_device *dev) -{ - if (dev->int_urb == NULL) - return 0; - - return usb_submit_urb(dev->int_urb, GFP_KERNEL); -} - -void uvc_status_stop(struct uvc_device *dev) -{ - usb_kill_urb(dev->int_urb); -} - -int uvc_status_suspend(struct uvc_device *dev) -{ - if (atomic_read(&dev->users)) - usb_kill_urb(dev->int_urb); - - return 0; -} - -int uvc_status_resume(struct uvc_device *dev) -{ - if (dev->int_urb == NULL || atomic_read(&dev->users) == 0) - return 0; - - return usb_submit_urb(dev->int_urb, GFP_NOIO); -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_v4l2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_v4l2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_v4l2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_v4l2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1093 +0,0 @@ -/* - * uvc_v4l2.c -- USB Video Class driver - V4L2 API - * - * Copyright (C) 2005-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.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, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "uvcvideo.h" - -/* ------------------------------------------------------------------------ - * UVC ioctls - */ -static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, - struct uvc_xu_control_mapping *xmap, int old) -{ - struct uvc_control_mapping *map; - unsigned int size; - int ret; - - map = kzalloc(sizeof *map, GFP_KERNEL); - if (map == NULL) - return -ENOMEM; - - map->id = xmap->id; - memcpy(map->name, xmap->name, sizeof map->name); - memcpy(map->entity, xmap->entity, sizeof map->entity); - map->selector = xmap->selector; - map->size = xmap->size; - map->offset = xmap->offset; - map->v4l2_type = xmap->v4l2_type; - map->data_type = xmap->data_type; - - switch (xmap->v4l2_type) { - case V4L2_CTRL_TYPE_INTEGER: - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_BUTTON: - break; - - case V4L2_CTRL_TYPE_MENU: - if (old) { - uvc_trace(UVC_TRACE_CONTROL, "V4L2_CTRL_TYPE_MENU not " - "supported for UVCIOC_CTRL_MAP_OLD.\n"); - ret = -EINVAL; - goto done; - } - - size = xmap->menu_count * sizeof(*map->menu_info); - map->menu_info = kmalloc(size, GFP_KERNEL); - if (map->menu_info == NULL) { - ret = -ENOMEM; - goto done; - } - - if (copy_from_user(map->menu_info, xmap->menu_info, size)) { - ret = -EFAULT; - goto done; - } - - map->menu_count = xmap->menu_count; - break; - - default: - uvc_trace(UVC_TRACE_CONTROL, "Unsupported V4L2 control type " - "%u.\n", xmap->v4l2_type); - ret = -EINVAL; - goto done; - } - - ret = uvc_ctrl_add_mapping(chain, map); - -done: - kfree(map->menu_info); - kfree(map); - - return ret; -} - -/* ------------------------------------------------------------------------ - * V4L2 interface - */ - -/* - * Find the frame interval closest to the requested frame interval for the - * given frame format and size. This should be done by the device as part of - * the Video Probe and Commit negotiation, but some hardware don't implement - * that feature. - */ -static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval) -{ - unsigned int i; - - if (frame->bFrameIntervalType) { - __u32 best = -1, dist; - - for (i = 0; i < frame->bFrameIntervalType; ++i) { - dist = interval > frame->dwFrameInterval[i] - ? interval - frame->dwFrameInterval[i] - : frame->dwFrameInterval[i] - interval; - - if (dist > best) - break; - - best = dist; - } - - interval = frame->dwFrameInterval[i-1]; - } else { - const __u32 min = frame->dwFrameInterval[0]; - const __u32 max = frame->dwFrameInterval[1]; - const __u32 step = frame->dwFrameInterval[2]; - - interval = min + (interval - min + step/2) / step * step; - if (interval > max) - interval = max; - } - - return interval; -} - -static int uvc_v4l2_try_format(struct uvc_streaming *stream, - struct v4l2_format *fmt, struct uvc_streaming_control *probe, - struct uvc_format **uvc_format, struct uvc_frame **uvc_frame) -{ - struct uvc_format *format = NULL; - struct uvc_frame *frame = NULL; - __u16 rw, rh; - unsigned int d, maxd; - unsigned int i; - __u32 interval; - int ret = 0; - __u8 *fcc; - - if (fmt->type != stream->type) - return -EINVAL; - - fcc = (__u8 *)&fmt->fmt.pix.pixelformat; - uvc_trace(UVC_TRACE_FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u.\n", - fmt->fmt.pix.pixelformat, - fcc[0], fcc[1], fcc[2], fcc[3], - fmt->fmt.pix.width, fmt->fmt.pix.height); - - /* Check if the hardware supports the requested format. */ - for (i = 0; i < stream->nformats; ++i) { - format = &stream->format[i]; - if (format->fcc == fmt->fmt.pix.pixelformat) - break; - } - - if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) { - uvc_trace(UVC_TRACE_FORMAT, "Unsupported format 0x%08x.\n", - fmt->fmt.pix.pixelformat); - return -EINVAL; - } - - /* Find the closest image size. The distance between image sizes is - * the size in pixels of the non-overlapping regions between the - * requested size and the frame-specified size. - */ - rw = fmt->fmt.pix.width; - rh = fmt->fmt.pix.height; - maxd = (unsigned int)-1; - - for (i = 0; i < format->nframes; ++i) { - __u16 w = format->frame[i].wWidth; - __u16 h = format->frame[i].wHeight; - - d = min(w, rw) * min(h, rh); - d = w*h + rw*rh - 2*d; - if (d < maxd) { - maxd = d; - frame = &format->frame[i]; - } - - if (maxd == 0) - break; - } - - if (frame == NULL) { - uvc_trace(UVC_TRACE_FORMAT, "Unsupported size %ux%u.\n", - fmt->fmt.pix.width, fmt->fmt.pix.height); - return -EINVAL; - } - - /* Use the default frame interval. */ - interval = frame->dwDefaultFrameInterval; - uvc_trace(UVC_TRACE_FORMAT, "Using default frame interval %u.%u us " - "(%u.%u fps).\n", interval/10, interval%10, 10000000/interval, - (100000000/interval)%10); - - /* Set the format index, frame index and frame interval. */ - memset(probe, 0, sizeof *probe); - probe->bmHint = 1; /* dwFrameInterval */ - probe->bFormatIndex = format->index; - probe->bFrameIndex = frame->bFrameIndex; - probe->dwFrameInterval = uvc_try_frame_interval(frame, interval); - /* Some webcams stall the probe control set request when the - * dwMaxVideoFrameSize field is set to zero. The UVC specification - * clearly states that the field is read-only from the host, so this - * is a webcam bug. Set dwMaxVideoFrameSize to the value reported by - * the webcam to work around the problem. - * - * The workaround could probably be enabled for all webcams, so the - * quirk can be removed if needed. It's currently useful to detect - * webcam bugs and fix them before they hit the market (providing - * developers test their webcams with the Linux driver as well as with - * the Windows driver). - */ - mutex_lock(&stream->mutex); - if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) - probe->dwMaxVideoFrameSize = - stream->ctrl.dwMaxVideoFrameSize; - - /* Probe the device. */ - ret = uvc_probe_video(stream, probe); - mutex_unlock(&stream->mutex); - if (ret < 0) - goto done; - - fmt->fmt.pix.width = frame->wWidth; - fmt->fmt.pix.height = frame->wHeight; - fmt->fmt.pix.field = V4L2_FIELD_NONE; - fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8; - fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize; - fmt->fmt.pix.colorspace = format->colorspace; - fmt->fmt.pix.priv = 0; - - if (uvc_format != NULL) - *uvc_format = format; - if (uvc_frame != NULL) - *uvc_frame = frame; - -done: - return ret; -} - -static int uvc_v4l2_get_format(struct uvc_streaming *stream, - struct v4l2_format *fmt) -{ - struct uvc_format *format; - struct uvc_frame *frame; - int ret = 0; - - if (fmt->type != stream->type) - return -EINVAL; - - mutex_lock(&stream->mutex); - format = stream->cur_format; - frame = stream->cur_frame; - - if (format == NULL || frame == NULL) { - ret = -EINVAL; - goto done; - } - - fmt->fmt.pix.pixelformat = format->fcc; - fmt->fmt.pix.width = frame->wWidth; - fmt->fmt.pix.height = frame->wHeight; - fmt->fmt.pix.field = V4L2_FIELD_NONE; - fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8; - fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize; - fmt->fmt.pix.colorspace = format->colorspace; - fmt->fmt.pix.priv = 0; - -done: - mutex_unlock(&stream->mutex); - return ret; -} - -static int uvc_v4l2_set_format(struct uvc_streaming *stream, - struct v4l2_format *fmt) -{ - struct uvc_streaming_control probe; - struct uvc_format *format; - struct uvc_frame *frame; - int ret; - - if (fmt->type != stream->type) - return -EINVAL; - - ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); - if (ret < 0) - return ret; - - mutex_lock(&stream->mutex); - - if (uvc_queue_allocated(&stream->queue)) { - ret = -EBUSY; - goto done; - } - - memcpy(&stream->ctrl, &probe, sizeof probe); - stream->cur_format = format; - stream->cur_frame = frame; - -done: - mutex_unlock(&stream->mutex); - return ret; -} - -static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, - struct v4l2_streamparm *parm) -{ - uint32_t numerator, denominator; - - if (parm->type != stream->type) - return -EINVAL; - - mutex_lock(&stream->mutex); - numerator = stream->ctrl.dwFrameInterval; - mutex_unlock(&stream->mutex); - - denominator = 10000000; - uvc_simplify_fraction(&numerator, &denominator, 8, 333); - - memset(parm, 0, sizeof *parm); - parm->type = stream->type; - - if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - parm->parm.capture.capturemode = 0; - parm->parm.capture.timeperframe.numerator = numerator; - parm->parm.capture.timeperframe.denominator = denominator; - parm->parm.capture.extendedmode = 0; - parm->parm.capture.readbuffers = 0; - } else { - parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; - parm->parm.output.outputmode = 0; - parm->parm.output.timeperframe.numerator = numerator; - parm->parm.output.timeperframe.denominator = denominator; - } - - return 0; -} - -static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, - struct v4l2_streamparm *parm) -{ - struct uvc_streaming_control probe; - struct v4l2_fract timeperframe; - uint32_t interval; - int ret; - - if (parm->type != stream->type) - return -EINVAL; - - if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - timeperframe = parm->parm.capture.timeperframe; - else - timeperframe = parm->parm.output.timeperframe; - - interval = uvc_fraction_to_interval(timeperframe.numerator, - timeperframe.denominator); - uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n", - timeperframe.numerator, timeperframe.denominator, interval); - - mutex_lock(&stream->mutex); - - if (uvc_queue_streaming(&stream->queue)) { - mutex_unlock(&stream->mutex); - return -EBUSY; - } - - memcpy(&probe, &stream->ctrl, sizeof probe); - probe.dwFrameInterval = - uvc_try_frame_interval(stream->cur_frame, interval); - - /* Probe the device with the new settings. */ - ret = uvc_probe_video(stream, &probe); - if (ret < 0) { - mutex_unlock(&stream->mutex); - return ret; - } - - memcpy(&stream->ctrl, &probe, sizeof probe); - mutex_unlock(&stream->mutex); - - /* Return the actual frame period. */ - timeperframe.numerator = probe.dwFrameInterval; - timeperframe.denominator = 10000000; - uvc_simplify_fraction(&timeperframe.numerator, - &timeperframe.denominator, 8, 333); - - if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - parm->parm.capture.timeperframe = timeperframe; - else - parm->parm.output.timeperframe = timeperframe; - - return 0; -} - -/* ------------------------------------------------------------------------ - * Privilege management - */ - -/* - * Privilege management is the multiple-open implementation basis. The current - * implementation is completely transparent for the end-user and doesn't - * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls. - * Those ioctls enable finer control on the device (by making possible for a - * user to request exclusive access to a device), but are not mature yet. - * Switching to the V4L2 priority mechanism might be considered in the future - * if this situation changes. - * - * Each open instance of a UVC device can either be in a privileged or - * unprivileged state. Only a single instance can be in a privileged state at - * a given time. Trying to perform an operation that requires privileges will - * automatically acquire the required privileges if possible, or return -EBUSY - * otherwise. Privileges are dismissed when closing the instance or when - * freeing the video buffers using VIDIOC_REQBUFS. - * - * Operations that require privileges are: - * - * - VIDIOC_S_INPUT - * - VIDIOC_S_PARM - * - VIDIOC_S_FMT - * - VIDIOC_REQBUFS - */ -static int uvc_acquire_privileges(struct uvc_fh *handle) -{ - /* Always succeed if the handle is already privileged. */ - if (handle->state == UVC_HANDLE_ACTIVE) - return 0; - - /* Check if the device already has a privileged handle. */ - if (atomic_inc_return(&handle->stream->active) != 1) { - atomic_dec(&handle->stream->active); - return -EBUSY; - } - - handle->state = UVC_HANDLE_ACTIVE; - return 0; -} - -static void uvc_dismiss_privileges(struct uvc_fh *handle) -{ - if (handle->state == UVC_HANDLE_ACTIVE) - atomic_dec(&handle->stream->active); - - handle->state = UVC_HANDLE_PASSIVE; -} - -static int uvc_has_privileges(struct uvc_fh *handle) -{ - return handle->state == UVC_HANDLE_ACTIVE; -} - -/* ------------------------------------------------------------------------ - * V4L2 file operations - */ - -static int uvc_v4l2_open(struct file *file) -{ - struct uvc_streaming *stream; - struct uvc_fh *handle; - int ret = 0; - - uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n"); - stream = video_drvdata(file); - - if (stream->dev->state & UVC_DEV_DISCONNECTED) - return -ENODEV; - - ret = usb_autopm_get_interface(stream->dev->intf); - if (ret < 0) - return ret; - - /* Create the device handle. */ - handle = kzalloc(sizeof *handle, GFP_KERNEL); - if (handle == NULL) { - usb_autopm_put_interface(stream->dev->intf); - return -ENOMEM; - } - - if (atomic_inc_return(&stream->dev->users) == 1) { - ret = uvc_status_start(stream->dev); - if (ret < 0) { - usb_autopm_put_interface(stream->dev->intf); - atomic_dec(&stream->dev->users); - kfree(handle); - return ret; - } - } - - handle->chain = stream->chain; - handle->stream = stream; - handle->state = UVC_HANDLE_PASSIVE; - file->private_data = handle; - - return 0; -} - -static int uvc_v4l2_release(struct file *file) -{ - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; - - uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n"); - - /* Only free resources if this is a privileged handle. */ - if (uvc_has_privileges(handle)) { - uvc_video_enable(stream, 0); - - if (uvc_free_buffers(&stream->queue) < 0) - uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " - "free buffers.\n"); - } - - /* Release the file handle. */ - uvc_dismiss_privileges(handle); - kfree(handle); - file->private_data = NULL; - - if (atomic_dec_return(&stream->dev->users) == 0) - uvc_status_stop(stream->dev); - - usb_autopm_put_interface(stream->dev->intf); - return 0; -} - -static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct uvc_fh *handle = file->private_data; - struct uvc_video_chain *chain = handle->chain; - struct uvc_streaming *stream = handle->stream; - long ret = 0; - - switch (cmd) { - /* Query capabilities */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap, 0, sizeof *cap); - strlcpy(cap->driver, "uvcvideo", sizeof cap->driver); - strlcpy(cap->card, vdev->name, sizeof cap->card); - usb_make_path(stream->dev->udev, - cap->bus_info, sizeof(cap->bus_info)); - cap->version = DRIVER_VERSION_NUMBER; - if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_STREAMING; - else - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT - | V4L2_CAP_STREAMING; - break; - } - - /* Get, Set & Query control */ - case VIDIOC_QUERYCTRL: - return uvc_query_v4l2_ctrl(chain, arg); - - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - struct v4l2_ext_control xctrl; - - memset(&xctrl, 0, sizeof xctrl); - xctrl.id = ctrl->id; - - ret = uvc_ctrl_begin(chain); - if (ret < 0) - return ret; - - ret = uvc_ctrl_get(chain, &xctrl); - uvc_ctrl_rollback(chain); - if (ret >= 0) - ctrl->value = xctrl.value; - break; - } - - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - struct v4l2_ext_control xctrl; - - memset(&xctrl, 0, sizeof xctrl); - xctrl.id = ctrl->id; - xctrl.value = ctrl->value; - - ret = uvc_ctrl_begin(chain); - if (ret < 0) - return ret; - - ret = uvc_ctrl_set(chain, &xctrl); - if (ret < 0) { - uvc_ctrl_rollback(chain); - return ret; - } - ret = uvc_ctrl_commit(chain); - if (ret == 0) - ctrl->value = xctrl.value; - break; - } - - case VIDIOC_QUERYMENU: - return uvc_query_v4l2_menu(chain, arg); - - case VIDIOC_G_EXT_CTRLS: - { - struct v4l2_ext_controls *ctrls = arg; - struct v4l2_ext_control *ctrl = ctrls->controls; - unsigned int i; - - ret = uvc_ctrl_begin(chain); - if (ret < 0) - return ret; - - for (i = 0; i < ctrls->count; ++ctrl, ++i) { - ret = uvc_ctrl_get(chain, ctrl); - if (ret < 0) { - uvc_ctrl_rollback(chain); - ctrls->error_idx = i; - return ret; - } - } - ctrls->error_idx = 0; - ret = uvc_ctrl_rollback(chain); - break; - } - - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *ctrls = arg; - struct v4l2_ext_control *ctrl = ctrls->controls; - unsigned int i; - - ret = uvc_ctrl_begin(chain); - if (ret < 0) - return ret; - - for (i = 0; i < ctrls->count; ++ctrl, ++i) { - ret = uvc_ctrl_set(chain, ctrl); - if (ret < 0) { - uvc_ctrl_rollback(chain); - ctrls->error_idx = i; - return ret; - } - } - - ctrls->error_idx = 0; - - if (cmd == VIDIOC_S_EXT_CTRLS) - ret = uvc_ctrl_commit(chain); - else - ret = uvc_ctrl_rollback(chain); - break; - } - - /* Get, Set & Enum input */ - case VIDIOC_ENUMINPUT: - { - const struct uvc_entity *selector = chain->selector; - struct v4l2_input *input = arg; - struct uvc_entity *iterm = NULL; - u32 index = input->index; - int pin = 0; - - if (selector == NULL || - (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { - if (index != 0) - return -EINVAL; - list_for_each_entry(iterm, &chain->entities, chain) { - if (UVC_ENTITY_IS_ITERM(iterm)) - break; - } - pin = iterm->id; - } else if (pin < selector->bNrInPins) { - pin = selector->baSourceID[index]; - list_for_each_entry(iterm, &chain->entities, chain) { - if (!UVC_ENTITY_IS_ITERM(iterm)) - continue; - if (iterm->id == pin) - break; - } - } - - if (iterm == NULL || iterm->id != pin) - return -EINVAL; - - memset(input, 0, sizeof *input); - input->index = index; - strlcpy(input->name, iterm->name, sizeof input->name); - if (UVC_ENTITY_TYPE(iterm) == UVC_ITT_CAMERA) - input->type = V4L2_INPUT_TYPE_CAMERA; - break; - } - - case VIDIOC_G_INPUT: - { - u8 input; - - if (chain->selector == NULL || - (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { - *(int *)arg = 0; - break; - } - - ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, - chain->selector->id, chain->dev->intfnum, - UVC_SU_INPUT_SELECT_CONTROL, &input, 1); - if (ret < 0) - return ret; - - *(int *)arg = input - 1; - break; - } - - case VIDIOC_S_INPUT: - { - u32 input = *(u32 *)arg + 1; - - if ((ret = uvc_acquire_privileges(handle)) < 0) - return ret; - - if (chain->selector == NULL || - (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { - if (input != 1) - return -EINVAL; - break; - } - - if (input == 0 || input > chain->selector->bNrInPins) - return -EINVAL; - - return uvc_query_ctrl(chain->dev, UVC_SET_CUR, - chain->selector->id, chain->dev->intfnum, - UVC_SU_INPUT_SELECT_CONTROL, &input, 1); - } - - /* Try, Get, Set & Enum format */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *fmt = arg; - struct uvc_format *format; - enum v4l2_buf_type type = fmt->type; - __u32 index = fmt->index; - - if (fmt->type != stream->type || - fmt->index >= stream->nformats) - return -EINVAL; - - memset(fmt, 0, sizeof(*fmt)); - fmt->index = index; - fmt->type = type; - - format = &stream->format[fmt->index]; - fmt->flags = 0; - if (format->flags & UVC_FMT_FLAG_COMPRESSED) - fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; - strlcpy(fmt->description, format->name, - sizeof fmt->description); - fmt->description[sizeof fmt->description - 1] = 0; - fmt->pixelformat = format->fcc; - break; - } - - case VIDIOC_TRY_FMT: - { - struct uvc_streaming_control probe; - - return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL); - } - - case VIDIOC_S_FMT: - if ((ret = uvc_acquire_privileges(handle)) < 0) - return ret; - - return uvc_v4l2_set_format(stream, arg); - - case VIDIOC_G_FMT: - return uvc_v4l2_get_format(stream, arg); - - /* Frame size enumeration */ - case VIDIOC_ENUM_FRAMESIZES: - { - struct v4l2_frmsizeenum *fsize = arg; - struct uvc_format *format = NULL; - struct uvc_frame *frame; - int i; - - /* Look for the given pixel format */ - for (i = 0; i < stream->nformats; i++) { - if (stream->format[i].fcc == - fsize->pixel_format) { - format = &stream->format[i]; - break; - } - } - if (format == NULL) - return -EINVAL; - - if (fsize->index >= format->nframes) - return -EINVAL; - - frame = &format->frame[fsize->index]; - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = frame->wWidth; - fsize->discrete.height = frame->wHeight; - break; - } - - /* Frame interval enumeration */ - case VIDIOC_ENUM_FRAMEINTERVALS: - { - struct v4l2_frmivalenum *fival = arg; - struct uvc_format *format = NULL; - struct uvc_frame *frame = NULL; - int i; - - /* Look for the given pixel format and frame size */ - for (i = 0; i < stream->nformats; i++) { - if (stream->format[i].fcc == - fival->pixel_format) { - format = &stream->format[i]; - break; - } - } - if (format == NULL) - return -EINVAL; - - for (i = 0; i < format->nframes; i++) { - if (format->frame[i].wWidth == fival->width && - format->frame[i].wHeight == fival->height) { - frame = &format->frame[i]; - break; - } - } - if (frame == NULL) - return -EINVAL; - - if (frame->bFrameIntervalType) { - if (fival->index >= frame->bFrameIntervalType) - return -EINVAL; - - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete.numerator = - frame->dwFrameInterval[fival->index]; - fival->discrete.denominator = 10000000; - uvc_simplify_fraction(&fival->discrete.numerator, - &fival->discrete.denominator, 8, 333); - } else { - fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; - fival->stepwise.min.numerator = - frame->dwFrameInterval[0]; - fival->stepwise.min.denominator = 10000000; - fival->stepwise.max.numerator = - frame->dwFrameInterval[1]; - fival->stepwise.max.denominator = 10000000; - fival->stepwise.step.numerator = - frame->dwFrameInterval[2]; - fival->stepwise.step.denominator = 10000000; - uvc_simplify_fraction(&fival->stepwise.min.numerator, - &fival->stepwise.min.denominator, 8, 333); - uvc_simplify_fraction(&fival->stepwise.max.numerator, - &fival->stepwise.max.denominator, 8, 333); - uvc_simplify_fraction(&fival->stepwise.step.numerator, - &fival->stepwise.step.denominator, 8, 333); - } - break; - } - - /* Get & Set streaming parameters */ - case VIDIOC_G_PARM: - return uvc_v4l2_get_streamparm(stream, arg); - - case VIDIOC_S_PARM: - if ((ret = uvc_acquire_privileges(handle)) < 0) - return ret; - - return uvc_v4l2_set_streamparm(stream, arg); - - /* Cropping and scaling */ - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *ccap = arg; - - if (ccap->type != stream->type) - return -EINVAL; - - ccap->bounds.left = 0; - ccap->bounds.top = 0; - - mutex_lock(&stream->mutex); - ccap->bounds.width = stream->cur_frame->wWidth; - ccap->bounds.height = stream->cur_frame->wHeight; - mutex_unlock(&stream->mutex); - - ccap->defrect = ccap->bounds; - - ccap->pixelaspect.numerator = 1; - ccap->pixelaspect.denominator = 1; - break; - } - - case VIDIOC_G_CROP: - case VIDIOC_S_CROP: - return -EINVAL; - - /* Buffers & streaming */ - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *rb = arg; - - if (rb->type != stream->type || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if ((ret = uvc_acquire_privileges(handle)) < 0) - return ret; - - mutex_lock(&stream->mutex); - ret = uvc_alloc_buffers(&stream->queue, rb->count, - stream->ctrl.dwMaxVideoFrameSize); - mutex_unlock(&stream->mutex); - if (ret < 0) - return ret; - - if (ret == 0) - uvc_dismiss_privileges(handle); - - rb->count = ret; - ret = 0; - break; - } - - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *buf = arg; - - if (buf->type != stream->type) - return -EINVAL; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_query_buffer(&stream->queue, buf); - } - - case VIDIOC_QBUF: - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_queue_buffer(&stream->queue, arg); - - case VIDIOC_DQBUF: - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_dequeue_buffer(&stream->queue, arg, - file->f_flags & O_NONBLOCK); - - case VIDIOC_STREAMON: - { - int *type = arg; - - if (*type != stream->type) - return -EINVAL; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - mutex_lock(&stream->mutex); - ret = uvc_video_enable(stream, 1); - mutex_unlock(&stream->mutex); - if (ret < 0) - return ret; - break; - } - - case VIDIOC_STREAMOFF: - { - int *type = arg; - - if (*type != stream->type) - return -EINVAL; - - if (!uvc_has_privileges(handle)) - return -EBUSY; - - return uvc_video_enable(stream, 0); - } - - /* Analog video standards make no sense for digital cameras. */ - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYSTD: - case VIDIOC_G_STD: - case VIDIOC_S_STD: - - case VIDIOC_OVERLAY: - - case VIDIOC_ENUMAUDIO: - case VIDIOC_ENUMAUDOUT: - - case VIDIOC_ENUMOUTPUT: - uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd); - return -EINVAL; - - /* Dynamic controls. */ - case UVCIOC_CTRL_ADD: - /* Legacy ioctl, kept for API compatibility reasons */ - return -EEXIST; - - case UVCIOC_CTRL_MAP_OLD: - case UVCIOC_CTRL_MAP: - return uvc_ioctl_ctrl_map(chain, arg, - cmd == UVCIOC_CTRL_MAP_OLD); - - case UVCIOC_CTRL_GET: - return uvc_xu_ctrl_query(chain, arg, 0); - - case UVCIOC_CTRL_SET: - return uvc_xu_ctrl_query(chain, arg, 1); - - default: - uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd); - return -EINVAL; - } - - return ret; -} - -static long uvc_v4l2_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - if (uvc_trace_param & UVC_TRACE_IOCTL) { - uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl("); - v4l_printk_ioctl(cmd); - printk(")\n"); - } - - return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); -} - -static ssize_t uvc_v4l2_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n"); - return -EINVAL; -} - -static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; - - uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n"); - - return uvc_queue_mmap(&stream->queue, vma); -} - -static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) -{ - struct uvc_fh *handle = file->private_data; - struct uvc_streaming *stream = handle->stream; - - uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n"); - - return uvc_queue_poll(&stream->queue, file, wait); -} - -const struct v4l2_file_operations uvc_fops = { - .owner = THIS_MODULE, - .open = uvc_v4l2_open, - .release = uvc_v4l2_release, - .unlocked_ioctl = uvc_v4l2_ioctl, - .read = uvc_v4l2_read, - .mmap = uvc_v4l2_mmap, - .poll = uvc_v4l2_poll, -}; - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvc_video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1263 +0,0 @@ -/* - * uvc_video.c -- USB Video Class driver - Video handling - * - * Copyright (C) 2005-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.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, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "uvcvideo.h" - -/* ------------------------------------------------------------------------ - * UVC Controls - */ - -static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size, - int timeout) -{ - __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - unsigned int pipe; - - pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0) - : usb_sndctrlpipe(dev->udev, 0); - type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT; - - return usb_control_msg(dev->udev, pipe, query, type, cs << 8, - unit << 8 | intfnum, data, size, timeout); -} - -static const char *uvc_query_name(__u8 query) -{ - switch (query) { - case UVC_SET_CUR: - return "SET_CUR"; - case UVC_GET_CUR: - return "GET_CUR"; - case UVC_GET_MIN: - return "GET_MIN"; - case UVC_GET_MAX: - return "GET_MAX"; - case UVC_GET_RES: - return "GET_RES"; - case UVC_GET_LEN: - return "GET_LEN"; - case UVC_GET_INFO: - return "GET_INFO"; - case UVC_GET_DEF: - return "GET_DEF"; - default: - return ""; - } -} - -int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size) -{ - int ret; - - ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size, - UVC_CTRL_CONTROL_TIMEOUT); - if (ret != size) { - uvc_printk(KERN_ERR, "Failed to query (%s) UVC control %u on " - "unit %u: %d (exp. %u).\n", uvc_query_name(query), cs, - unit, ret, size); - return -EIO; - } - - return 0; -} - -static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, - struct uvc_streaming_control *ctrl) -{ - struct uvc_format *format = NULL; - struct uvc_frame *frame = NULL; - unsigned int i; - - for (i = 0; i < stream->nformats; ++i) { - if (stream->format[i].index == ctrl->bFormatIndex) { - format = &stream->format[i]; - break; - } - } - - if (format == NULL) - return; - - for (i = 0; i < format->nframes; ++i) { - if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) { - frame = &format->frame[i]; - break; - } - } - - if (frame == NULL) - return; - - if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) || - (ctrl->dwMaxVideoFrameSize == 0 && - stream->dev->uvc_version < 0x0110)) - ctrl->dwMaxVideoFrameSize = - frame->dwMaxVideoFrameBufferSize; - - if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) && - stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH && - stream->intf->num_altsetting > 1) { - u32 interval; - u32 bandwidth; - - interval = (ctrl->dwFrameInterval > 100000) - ? ctrl->dwFrameInterval - : frame->dwFrameInterval[0]; - - /* Compute a bandwidth estimation by multiplying the frame - * size by the number of video frames per second, divide the - * result by the number of USB frames (or micro-frames for - * high-speed devices) per second and add the UVC header size - * (assumed to be 12 bytes long). - */ - bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp; - bandwidth *= 10000000 / interval + 1; - bandwidth /= 1000; - if (stream->dev->udev->speed == USB_SPEED_HIGH) - bandwidth /= 8; - bandwidth += 12; - - /* The bandwidth estimate is too low for many cameras. Don't use - * maximum packet sizes lower than 1024 bytes to try and work - * around the problem. According to measurements done on two - * different camera models, the value is high enough to get most - * resolutions working while not preventing two simultaneous - * VGA streams at 15 fps. - */ - bandwidth = max_t(u32, bandwidth, 1024); - - ctrl->dwMaxPayloadTransferSize = bandwidth; - } -} - -static int uvc_get_video_ctrl(struct uvc_streaming *stream, - struct uvc_streaming_control *ctrl, int probe, __u8 query) -{ - __u8 *data; - __u16 size; - int ret; - - size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; - if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && - query == UVC_GET_DEF) - return -EIO; - - data = kmalloc(size, GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum, - probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data, - size, uvc_timeout_param); - - if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) { - /* Some cameras, mostly based on Bison Electronics chipsets, - * answer a GET_MIN or GET_MAX request with the wCompQuality - * field only. - */ - uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non " - "compliance - GET_MIN/MAX(PROBE) incorrectly " - "supported. Enabling workaround.\n"); - memset(ctrl, 0, sizeof *ctrl); - ctrl->wCompQuality = le16_to_cpup((__le16 *)data); - ret = 0; - goto out; - } else if (query == UVC_GET_DEF && probe == 1 && ret != size) { - /* Many cameras don't support the GET_DEF request on their - * video probe control. Warn once and return, the caller will - * fall back to GET_CUR. - */ - uvc_warn_once(stream->dev, UVC_WARN_PROBE_DEF, "UVC non " - "compliance - GET_DEF(PROBE) not supported. " - "Enabling workaround.\n"); - ret = -EIO; - goto out; - } else if (ret != size) { - uvc_printk(KERN_ERR, "Failed to query (%u) UVC %s control : " - "%d (exp. %u).\n", query, probe ? "probe" : "commit", - ret, size); - ret = -EIO; - goto out; - } - - ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]); - ctrl->bFormatIndex = data[2]; - ctrl->bFrameIndex = data[3]; - ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]); - ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]); - ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]); - ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]); - ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]); - ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]); - ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]); - ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]); - - if (size == 34) { - ctrl->dwClockFrequency = get_unaligned_le32(&data[26]); - ctrl->bmFramingInfo = data[30]; - ctrl->bPreferedVersion = data[31]; - ctrl->bMinVersion = data[32]; - ctrl->bMaxVersion = data[33]; - } else { - ctrl->dwClockFrequency = stream->dev->clock_frequency; - ctrl->bmFramingInfo = 0; - ctrl->bPreferedVersion = 0; - ctrl->bMinVersion = 0; - ctrl->bMaxVersion = 0; - } - - /* Some broken devices return null or wrong dwMaxVideoFrameSize and - * dwMaxPayloadTransferSize fields. Try to get the value from the - * format and frame descriptors. - */ - uvc_fixup_video_ctrl(stream, ctrl); - ret = 0; - -out: - kfree(data); - return ret; -} - -static int uvc_set_video_ctrl(struct uvc_streaming *stream, - struct uvc_streaming_control *ctrl, int probe) -{ - __u8 *data; - __u16 size; - int ret; - - size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; - data = kzalloc(size, GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint); - data[2] = ctrl->bFormatIndex; - data[3] = ctrl->bFrameIndex; - *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval); - *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate); - *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate); - *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality); - *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize); - *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay); - put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]); - put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]); - - if (size == 34) { - put_unaligned_le32(ctrl->dwClockFrequency, &data[26]); - data[30] = ctrl->bmFramingInfo; - data[31] = ctrl->bPreferedVersion; - data[32] = ctrl->bMinVersion; - data[33] = ctrl->bMaxVersion; - } - - ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum, - probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data, - size, uvc_timeout_param); - if (ret != size) { - uvc_printk(KERN_ERR, "Failed to set UVC %s control : " - "%d (exp. %u).\n", probe ? "probe" : "commit", - ret, size); - ret = -EIO; - } - - kfree(data); - return ret; -} - -int uvc_probe_video(struct uvc_streaming *stream, - struct uvc_streaming_control *probe) -{ - struct uvc_streaming_control probe_min, probe_max; - __u16 bandwidth; - unsigned int i; - int ret; - - /* Perform probing. The device should adjust the requested values - * according to its capabilities. However, some devices, namely the - * first generation UVC Logitech webcams, don't implement the Video - * Probe control properly, and just return the needed bandwidth. For - * that reason, if the needed bandwidth exceeds the maximum available - * bandwidth, try to lower the quality. - */ - ret = uvc_set_video_ctrl(stream, probe, 1); - if (ret < 0) - goto done; - - /* Get the minimum and maximum values for compression settings. */ - if (!(stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) { - ret = uvc_get_video_ctrl(stream, &probe_min, 1, UVC_GET_MIN); - if (ret < 0) - goto done; - ret = uvc_get_video_ctrl(stream, &probe_max, 1, UVC_GET_MAX); - if (ret < 0) - goto done; - - probe->wCompQuality = probe_max.wCompQuality; - } - - for (i = 0; i < 2; ++i) { - ret = uvc_set_video_ctrl(stream, probe, 1); - if (ret < 0) - goto done; - ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR); - if (ret < 0) - goto done; - - if (stream->intf->num_altsetting == 1) - break; - - bandwidth = probe->dwMaxPayloadTransferSize; - if (bandwidth <= stream->maxpsize) - break; - - if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) { - ret = -ENOSPC; - goto done; - } - - /* TODO: negotiate compression parameters */ - probe->wKeyFrameRate = probe_min.wKeyFrameRate; - probe->wPFrameRate = probe_min.wPFrameRate; - probe->wCompQuality = probe_max.wCompQuality; - probe->wCompWindowSize = probe_min.wCompWindowSize; - } - -done: - return ret; -} - -int uvc_commit_video(struct uvc_streaming *stream, - struct uvc_streaming_control *probe) -{ - return uvc_set_video_ctrl(stream, probe, 0); -} - -/* ------------------------------------------------------------------------ - * Video codecs - */ - -/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ -#define UVC_STREAM_EOH (1 << 7) -#define UVC_STREAM_ERR (1 << 6) -#define UVC_STREAM_STI (1 << 5) -#define UVC_STREAM_RES (1 << 4) -#define UVC_STREAM_SCR (1 << 3) -#define UVC_STREAM_PTS (1 << 2) -#define UVC_STREAM_EOF (1 << 1) -#define UVC_STREAM_FID (1 << 0) - -/* Video payload decoding is handled by uvc_video_decode_start(), - * uvc_video_decode_data() and uvc_video_decode_end(). - * - * uvc_video_decode_start is called with URB data at the start of a bulk or - * isochronous payload. It processes header data and returns the header size - * in bytes if successful. If an error occurs, it returns a negative error - * code. The following error codes have special meanings. - * - * - EAGAIN informs the caller that the current video buffer should be marked - * as done, and that the function should be called again with the same data - * and a new video buffer. This is used when end of frame conditions can be - * reliably detected at the beginning of the next frame only. - * - * If an error other than -EAGAIN is returned, the caller will drop the current - * payload. No call to uvc_video_decode_data and uvc_video_decode_end will be - * made until the next payload. -ENODATA can be used to drop the current - * payload if no other error code is appropriate. - * - * uvc_video_decode_data is called for every URB with URB data. It copies the - * data to the video buffer. - * - * uvc_video_decode_end is called with header data at the end of a bulk or - * isochronous payload. It performs any additional header data processing and - * returns 0 or a negative error code if an error occured. As header data have - * already been processed by uvc_video_decode_start, this functions isn't - * required to perform sanity checks a second time. - * - * For isochronous transfers where a payload is always transfered in a single - * URB, the three functions will be called in a row. - * - * To let the decoder process header data and update its internal state even - * when no video buffer is available, uvc_video_decode_start must be prepared - * to be called with a NULL buf parameter. uvc_video_decode_data and - * uvc_video_decode_end will never be called with a NULL buffer. - */ -static int uvc_video_decode_start(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) -{ - __u8 fid; - - /* Sanity checks: - * - packet must be at least 2 bytes long - * - bHeaderLength value must be at least 2 bytes (see above) - * - bHeaderLength value can't be larger than the packet size. - */ - if (len < 2 || data[0] < 2 || data[0] > len) - return -EINVAL; - - /* Skip payloads marked with the error bit ("error frames"). */ - if (data[1] & UVC_STREAM_ERR) { - uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit " - "set).\n"); - return -ENODATA; - } - - fid = data[1] & UVC_STREAM_FID; - - /* Increase the sequence number regardless of any buffer states, so - * that discontinuous sequence numbers always indicate lost frames. - */ - if (stream->last_fid != fid) - stream->sequence++; - - /* Store the payload FID bit and return immediately when the buffer is - * NULL. - */ - if (buf == NULL) { - stream->last_fid = fid; - return -ENODATA; - } - - /* Synchronize to the input stream by waiting for the FID bit to be - * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE. - * stream->last_fid is initialized to -1, so the first isochronous - * frame will always be in sync. - * - * If the device doesn't toggle the FID bit, invert stream->last_fid - * when the EOF bit is set to force synchronisation on the next packet. - */ - if (buf->state != UVC_BUF_STATE_ACTIVE) { - struct timespec ts; - - if (fid == stream->last_fid) { - uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of " - "sync).\n"); - if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) && - (data[1] & UVC_STREAM_EOF)) - stream->last_fid ^= UVC_STREAM_FID; - return -ENODATA; - } - - if (uvc_clock_param == CLOCK_MONOTONIC) - ktime_get_ts(&ts); - else - ktime_get_real_ts(&ts); - - buf->buf.sequence = stream->sequence; - buf->buf.timestamp.tv_sec = ts.tv_sec; - buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; - - /* TODO: Handle PTS and SCR. */ - buf->state = UVC_BUF_STATE_ACTIVE; - } - - /* Mark the buffer as done if we're at the beginning of a new frame. - * End of frame detection is better implemented by checking the EOF - * bit (FID bit toggling is delayed by one frame compared to the EOF - * bit), but some devices don't set the bit at end of frame (and the - * last payload can be lost anyway). We thus must check if the FID has - * been toggled. - * - * stream->last_fid is initialized to -1, so the first isochronous - * frame will never trigger an end of frame detection. - * - * Empty buffers (bytesused == 0) don't trigger end of frame detection - * as it doesn't make sense to return an empty buffer. This also - * avoids detecting end of frame conditions at FID toggling if the - * previous payload had the EOF bit set. - */ - if (fid != stream->last_fid && buf->buf.bytesused != 0) { - uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit " - "toggled).\n"); - buf->state = UVC_BUF_STATE_READY; - return -EAGAIN; - } - - stream->last_fid = fid; - - return data[0]; -} - -static void uvc_video_decode_data(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) -{ - struct uvc_video_queue *queue = &stream->queue; - unsigned int maxlen, nbytes; - void *mem; - - if (len <= 0) - return; - - /* Copy the video data to the buffer. */ - maxlen = buf->buf.length - buf->buf.bytesused; - mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused; - nbytes = min((unsigned int)len, maxlen); - memcpy(mem, data, nbytes); - buf->buf.bytesused += nbytes; - - /* Complete the current frame if the buffer size was exceeded. */ - if (len > maxlen) { - uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n"); - buf->state = UVC_BUF_STATE_READY; - } -} - -static void uvc_video_decode_end(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) -{ - /* Mark the buffer as done if the EOF marker is set. */ - if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) { - uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n"); - if (data[0] == len) - uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n"); - buf->state = UVC_BUF_STATE_READY; - if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) - stream->last_fid ^= UVC_STREAM_FID; - } -} - -/* Video payload encoding is handled by uvc_video_encode_header() and - * uvc_video_encode_data(). Only bulk transfers are currently supported. - * - * uvc_video_encode_header is called at the start of a payload. It adds header - * data to the transfer buffer and returns the header size. As the only known - * UVC output device transfers a whole frame in a single payload, the EOF bit - * is always set in the header. - * - * uvc_video_encode_data is called for every URB and copies the data from the - * video buffer to the transfer buffer. - */ -static int uvc_video_encode_header(struct uvc_streaming *stream, - struct uvc_buffer *buf, __u8 *data, int len) -{ - data[0] = 2; /* Header length */ - data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF - | (stream->last_fid & UVC_STREAM_FID); - return 2; -} - -static int uvc_video_encode_data(struct uvc_streaming *stream, - struct uvc_buffer *buf, __u8 *data, int len) -{ - struct uvc_video_queue *queue = &stream->queue; - unsigned int nbytes; - void *mem; - - /* Copy video data to the URB buffer. */ - mem = queue->mem + buf->buf.m.offset + queue->buf_used; - nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); - nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size, - nbytes); - memcpy(data, mem, nbytes); - - queue->buf_used += nbytes; - - return nbytes; -} - -/* ------------------------------------------------------------------------ - * URB handling - */ - -/* - * Completion handler for video URBs. - */ -static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, - struct uvc_buffer *buf) -{ - u8 *mem; - int ret, i; - - for (i = 0; i < urb->number_of_packets; ++i) { - if (urb->iso_frame_desc[i].status < 0) { - uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame " - "lost (%d).\n", urb->iso_frame_desc[i].status); - /* Mark the buffer as faulty. */ - if (buf != NULL) - buf->error = 1; - continue; - } - - /* Decode the payload header. */ - mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - do { - ret = uvc_video_decode_start(stream, buf, mem, - urb->iso_frame_desc[i].actual_length); - if (ret == -EAGAIN) - buf = uvc_queue_next_buffer(&stream->queue, - buf); - } while (ret == -EAGAIN); - - if (ret < 0) - continue; - - /* Decode the payload data. */ - uvc_video_decode_data(stream, buf, mem + ret, - urb->iso_frame_desc[i].actual_length - ret); - - /* Process the header again. */ - uvc_video_decode_end(stream, buf, mem, - urb->iso_frame_desc[i].actual_length); - - if (buf->state == UVC_BUF_STATE_READY) { - if (buf->buf.length != buf->buf.bytesused && - !(stream->cur_format->flags & - UVC_FMT_FLAG_COMPRESSED)) - buf->error = 1; - - buf = uvc_queue_next_buffer(&stream->queue, buf); - } - } -} - -static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream, - struct uvc_buffer *buf) -{ - u8 *mem; - int len, ret; - - if (urb->actual_length == 0) - return; - - mem = urb->transfer_buffer; - len = urb->actual_length; - stream->bulk.payload_size += len; - - /* If the URB is the first of its payload, decode and save the - * header. - */ - if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) { - do { - ret = uvc_video_decode_start(stream, buf, mem, len); - if (ret == -EAGAIN) - buf = uvc_queue_next_buffer(&stream->queue, - buf); - } while (ret == -EAGAIN); - - /* If an error occured skip the rest of the payload. */ - if (ret < 0 || buf == NULL) { - stream->bulk.skip_payload = 1; - } else { - memcpy(stream->bulk.header, mem, ret); - stream->bulk.header_size = ret; - - mem += ret; - len -= ret; - } - } - - /* The buffer queue might have been cancelled while a bulk transfer - * was in progress, so we can reach here with buf equal to NULL. Make - * sure buf is never dereferenced if NULL. - */ - - /* Process video data. */ - if (!stream->bulk.skip_payload && buf != NULL) - uvc_video_decode_data(stream, buf, mem, len); - - /* Detect the payload end by a URB smaller than the maximum size (or - * a payload size equal to the maximum) and process the header again. - */ - if (urb->actual_length < urb->transfer_buffer_length || - stream->bulk.payload_size >= stream->bulk.max_payload_size) { - if (!stream->bulk.skip_payload && buf != NULL) { - uvc_video_decode_end(stream, buf, stream->bulk.header, - stream->bulk.payload_size); - if (buf->state == UVC_BUF_STATE_READY) - buf = uvc_queue_next_buffer(&stream->queue, - buf); - } - - stream->bulk.header_size = 0; - stream->bulk.skip_payload = 0; - stream->bulk.payload_size = 0; - } -} - -static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream, - struct uvc_buffer *buf) -{ - u8 *mem = urb->transfer_buffer; - int len = stream->urb_size, ret; - - if (buf == NULL) { - urb->transfer_buffer_length = 0; - return; - } - - /* If the URB is the first of its payload, add the header. */ - if (stream->bulk.header_size == 0) { - ret = uvc_video_encode_header(stream, buf, mem, len); - stream->bulk.header_size = ret; - stream->bulk.payload_size += ret; - mem += ret; - len -= ret; - } - - /* Process video data. */ - ret = uvc_video_encode_data(stream, buf, mem, len); - - stream->bulk.payload_size += ret; - len -= ret; - - if (buf->buf.bytesused == stream->queue.buf_used || - stream->bulk.payload_size == stream->bulk.max_payload_size) { - if (buf->buf.bytesused == stream->queue.buf_used) { - stream->queue.buf_used = 0; - buf->state = UVC_BUF_STATE_READY; - buf->buf.sequence = ++stream->sequence; - uvc_queue_next_buffer(&stream->queue, buf); - stream->last_fid ^= UVC_STREAM_FID; - } - - stream->bulk.header_size = 0; - stream->bulk.payload_size = 0; - } - - urb->transfer_buffer_length = stream->urb_size - len; -} - -static void uvc_video_complete(struct urb *urb) -{ - struct uvc_streaming *stream = urb->context; - struct uvc_video_queue *queue = &stream->queue; - struct uvc_buffer *buf = NULL; - unsigned long flags; - int ret; - - switch (urb->status) { - case 0: - break; - - default: - uvc_printk(KERN_WARNING, "Non-zero status (%d) in video " - "completion handler.\n", urb->status); - - case -ENOENT: /* usb_kill_urb() called. */ - if (stream->frozen) - return; - - case -ECONNRESET: /* usb_unlink_urb() called. */ - case -ESHUTDOWN: /* The endpoint is being disabled. */ - uvc_queue_cancel(queue, urb->status == -ESHUTDOWN); - return; - } - - spin_lock_irqsave(&queue->irqlock, flags); - if (!list_empty(&queue->irqqueue)) - buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - spin_unlock_irqrestore(&queue->irqlock, flags); - - stream->decode(urb, stream, buf); - - if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n", - ret); - } -} - -/* - * Free transfer buffers. - */ -static void uvc_free_urb_buffers(struct uvc_streaming *stream) -{ - unsigned int i; - - for (i = 0; i < UVC_URBS; ++i) { - if (stream->urb_buffer[i]) { - usb_free_coherent(stream->dev->udev, stream->urb_size, - stream->urb_buffer[i], stream->urb_dma[i]); - stream->urb_buffer[i] = NULL; - } - } - - stream->urb_size = 0; -} - -/* - * Allocate transfer buffers. This function can be called with buffers - * already allocated when resuming from suspend, in which case it will - * return without touching the buffers. - * - * Limit the buffer size to UVC_MAX_PACKETS bulk/isochronous packets. If the - * system is too low on memory try successively smaller numbers of packets - * until allocation succeeds. - * - * Return the number of allocated packets on success or 0 when out of memory. - */ -static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, - unsigned int size, unsigned int psize, gfp_t gfp_flags) -{ - unsigned int npackets; - unsigned int i; - - /* Buffers are already allocated, bail out. */ - if (stream->urb_size) - return stream->urb_size / psize; - - /* Compute the number of packets. Bulk endpoints might transfer UVC - * payloads accross multiple URBs. - */ - npackets = DIV_ROUND_UP(size, psize); - if (npackets > UVC_MAX_PACKETS) - npackets = UVC_MAX_PACKETS; - - /* Retry allocations until one succeed. */ - for (; npackets > 1; npackets /= 2) { - for (i = 0; i < UVC_URBS; ++i) { - stream->urb_size = psize * npackets; - stream->urb_buffer[i] = usb_alloc_coherent( - stream->dev->udev, stream->urb_size, - gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]); - if (!stream->urb_buffer[i]) { - uvc_free_urb_buffers(stream); - break; - } - } - - if (i == UVC_URBS) { - uvc_trace(UVC_TRACE_VIDEO, "Allocated %u URB buffers " - "of %ux%u bytes each.\n", UVC_URBS, npackets, - psize); - return npackets; - } - } - - uvc_trace(UVC_TRACE_VIDEO, "Failed to allocate URB buffers (%u bytes " - "per packet).\n", psize); - return 0; -} - -/* - * Uninitialize isochronous/bulk URBs and free transfer buffers. - */ -static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) -{ - struct urb *urb; - unsigned int i; - - for (i = 0; i < UVC_URBS; ++i) { - urb = stream->urb[i]; - if (urb == NULL) - continue; - - usb_kill_urb(urb); - usb_free_urb(urb); - stream->urb[i] = NULL; - } - - if (free_buffers) - uvc_free_urb_buffers(stream); -} - -/* - * Initialize isochronous URBs and allocate transfer buffers. The packet size - * is given by the endpoint. - */ -static int uvc_init_video_isoc(struct uvc_streaming *stream, - struct usb_host_endpoint *ep, gfp_t gfp_flags) -{ - struct urb *urb; - unsigned int npackets, i, j; - u16 psize; - u32 size; - - psize = le16_to_cpu(ep->desc.wMaxPacketSize); - psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - size = stream->ctrl.dwMaxVideoFrameSize; - - npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags); - if (npackets == 0) - return -ENOMEM; - - size = npackets * psize; - - for (i = 0; i < UVC_URBS; ++i) { - urb = usb_alloc_urb(npackets, gfp_flags); - if (urb == NULL) { - uvc_uninit_video(stream, 1); - return -ENOMEM; - } - - urb->dev = stream->dev->udev; - urb->context = stream; - urb->pipe = usb_rcvisocpipe(stream->dev->udev, - ep->desc.bEndpointAddress); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = ep->desc.bInterval; - urb->transfer_buffer = stream->urb_buffer[i]; - urb->transfer_dma = stream->urb_dma[i]; - urb->complete = uvc_video_complete; - urb->number_of_packets = npackets; - urb->transfer_buffer_length = size; - - for (j = 0; j < npackets; ++j) { - urb->iso_frame_desc[j].offset = j * psize; - urb->iso_frame_desc[j].length = psize; - } - - stream->urb[i] = urb; - } - - return 0; -} - -/* - * Initialize bulk URBs and allocate transfer buffers. The packet size is - * given by the endpoint. - */ -static int uvc_init_video_bulk(struct uvc_streaming *stream, - struct usb_host_endpoint *ep, gfp_t gfp_flags) -{ - struct urb *urb; - unsigned int npackets, pipe, i; - u16 psize; - u32 size; - - psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff; - size = stream->ctrl.dwMaxPayloadTransferSize; - stream->bulk.max_payload_size = size; - - npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags); - if (npackets == 0) - return -ENOMEM; - - size = npackets * psize; - - if (usb_endpoint_dir_in(&ep->desc)) - pipe = usb_rcvbulkpipe(stream->dev->udev, - ep->desc.bEndpointAddress); - else - pipe = usb_sndbulkpipe(stream->dev->udev, - ep->desc.bEndpointAddress); - - if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - size = 0; - - for (i = 0; i < UVC_URBS; ++i) { - urb = usb_alloc_urb(0, gfp_flags); - if (urb == NULL) { - uvc_uninit_video(stream, 1); - return -ENOMEM; - } - - usb_fill_bulk_urb(urb, stream->dev->udev, pipe, - stream->urb_buffer[i], size, uvc_video_complete, - stream); - urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - urb->transfer_dma = stream->urb_dma[i]; - - stream->urb[i] = urb; - } - - return 0; -} - -/* - * Initialize isochronous/bulk URBs and allocate transfer buffers. - */ -static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) -{ - struct usb_interface *intf = stream->intf; - struct usb_host_endpoint *ep; - unsigned int i; - int ret; - - stream->sequence = -1; - stream->last_fid = -1; - stream->bulk.header_size = 0; - stream->bulk.skip_payload = 0; - stream->bulk.payload_size = 0; - - if (intf->num_altsetting > 1) { - struct usb_host_endpoint *best_ep = NULL; - unsigned int best_psize = 3 * 1024; - unsigned int bandwidth; - unsigned int uninitialized_var(altsetting); - int intfnum = stream->intfnum; - - /* Isochronous endpoint, select the alternate setting. */ - bandwidth = stream->ctrl.dwMaxPayloadTransferSize; - - if (bandwidth == 0) { - uvc_trace(UVC_TRACE_VIDEO, "Device requested null " - "bandwidth, defaulting to lowest.\n"); - bandwidth = 1; - } else { - uvc_trace(UVC_TRACE_VIDEO, "Device requested %u " - "B/frame bandwidth.\n", bandwidth); - } - - for (i = 0; i < intf->num_altsetting; ++i) { - struct usb_host_interface *alts; - unsigned int psize; - - alts = &intf->altsetting[i]; - ep = uvc_find_endpoint(alts, - stream->header.bEndpointAddress); - if (ep == NULL) - continue; - - /* Check if the bandwidth is high enough. */ - psize = le16_to_cpu(ep->desc.wMaxPacketSize); - psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - if (psize >= bandwidth && psize <= best_psize) { - altsetting = i; - best_psize = psize; - best_ep = ep; - } - } - - if (best_ep == NULL) { - uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting " - "for requested bandwidth.\n"); - return -EIO; - } - - uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u " - "(%u B/frame bandwidth).\n", altsetting, best_psize); - - ret = usb_set_interface(stream->dev->udev, intfnum, altsetting); - if (ret < 0) - return ret; - - ret = uvc_init_video_isoc(stream, best_ep, gfp_flags); - } else { - /* Bulk endpoint, proceed to URB initialization. */ - ep = uvc_find_endpoint(&intf->altsetting[0], - stream->header.bEndpointAddress); - if (ep == NULL) - return -EIO; - - ret = uvc_init_video_bulk(stream, ep, gfp_flags); - } - - if (ret < 0) - return ret; - - /* Submit the URBs. */ - for (i = 0; i < UVC_URBS; ++i) { - ret = usb_submit_urb(stream->urb[i], gfp_flags); - if (ret < 0) { - uvc_printk(KERN_ERR, "Failed to submit URB %u " - "(%d).\n", i, ret); - uvc_uninit_video(stream, 1); - return ret; - } - } - - return 0; -} - -/* -------------------------------------------------------------------------- - * Suspend/resume - */ - -/* - * Stop streaming without disabling the video queue. - * - * To let userspace applications resume without trouble, we must not touch the - * video buffers in any way. We mark the device as frozen to make sure the URB - * completion handler won't try to cancel the queue when we kill the URBs. - */ -int uvc_video_suspend(struct uvc_streaming *stream) -{ - if (!uvc_queue_streaming(&stream->queue)) - return 0; - - stream->frozen = 1; - uvc_uninit_video(stream, 0); - usb_set_interface(stream->dev->udev, stream->intfnum, 0); - return 0; -} - -/* - * Reconfigure the video interface and restart streaming if it was enabled - * before suspend. - * - * If an error occurs, disable the video queue. This will wake all pending - * buffers, making sure userspace applications are notified of the problem - * instead of waiting forever. - */ -int uvc_video_resume(struct uvc_streaming *stream) -{ - int ret; - - stream->frozen = 0; - - ret = uvc_commit_video(stream, &stream->ctrl); - if (ret < 0) { - uvc_queue_enable(&stream->queue, 0); - return ret; - } - - if (!uvc_queue_streaming(&stream->queue)) - return 0; - - ret = uvc_init_video(stream, GFP_NOIO); - if (ret < 0) - uvc_queue_enable(&stream->queue, 0); - - return ret; -} - -/* ------------------------------------------------------------------------ - * Video device - */ - -/* - * Initialize the UVC video device by switching to alternate setting 0 and - * retrieve the default format. - * - * Some cameras (namely the Fuji Finepix) set the format and frame - * indexes to zero. The UVC standard doesn't clearly make this a spec - * violation, so try to silently fix the values if possible. - * - * This function is called before registering the device with V4L. - */ -int uvc_video_init(struct uvc_streaming *stream) -{ - struct uvc_streaming_control *probe = &stream->ctrl; - struct uvc_format *format = NULL; - struct uvc_frame *frame = NULL; - unsigned int i; - int ret; - - if (stream->nformats == 0) { - uvc_printk(KERN_INFO, "No supported video formats found.\n"); - return -EINVAL; - } - - atomic_set(&stream->active, 0); - - /* Initialize the video buffers queue. */ - uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); - - /* Alternate setting 0 should be the default, yet the XBox Live Vision - * Cam (and possibly other devices) crash or otherwise misbehave if - * they don't receive a SET_INTERFACE request before any other video - * control request. - */ - usb_set_interface(stream->dev->udev, stream->intfnum, 0); - - /* Set the streaming probe control with default streaming parameters - * retrieved from the device. Webcams that don't suport GET_DEF - * requests on the probe control will just keep their current streaming - * parameters. - */ - if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0) - uvc_set_video_ctrl(stream, probe, 1); - - /* Initialize the streaming parameters with the probe control current - * value. This makes sure SET_CUR requests on the streaming commit - * control will always use values retrieved from a successful GET_CUR - * request on the probe control, as required by the UVC specification. - */ - ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR); - if (ret < 0) - return ret; - - /* Check if the default format descriptor exists. Use the first - * available format otherwise. - */ - for (i = stream->nformats; i > 0; --i) { - format = &stream->format[i-1]; - if (format->index == probe->bFormatIndex) - break; - } - - if (format->nframes == 0) { - uvc_printk(KERN_INFO, "No frame descriptor found for the " - "default format.\n"); - return -EINVAL; - } - - /* Zero bFrameIndex might be correct. Stream-based formats (including - * MPEG-2 TS and DV) do not support frames but have a dummy frame - * descriptor with bFrameIndex set to zero. If the default frame - * descriptor is not found, use the first available frame. - */ - for (i = format->nframes; i > 0; --i) { - frame = &format->frame[i-1]; - if (frame->bFrameIndex == probe->bFrameIndex) - break; - } - - probe->bFormatIndex = format->index; - probe->bFrameIndex = frame->bFrameIndex; - - stream->cur_format = format; - stream->cur_frame = frame; - - /* Select the video decoding function */ - if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) - stream->decode = uvc_video_decode_isight; - else if (stream->intf->num_altsetting > 1) - stream->decode = uvc_video_decode_isoc; - else - stream->decode = uvc_video_decode_bulk; - } else { - if (stream->intf->num_altsetting == 1) - stream->decode = uvc_video_encode_bulk; - else { - uvc_printk(KERN_INFO, "Isochronous endpoints are not " - "supported for video output devices.\n"); - return -EINVAL; - } - } - - return 0; -} - -/* - * Enable or disable the video stream. - */ -int uvc_video_enable(struct uvc_streaming *stream, int enable) -{ - int ret; - - if (!enable) { - uvc_uninit_video(stream, 1); - usb_set_interface(stream->dev->udev, stream->intfnum, 0); - uvc_queue_enable(&stream->queue, 0); - return 0; - } - - ret = uvc_queue_enable(&stream->queue, 1); - if (ret < 0) - return ret; - - /* Commit the streaming parameters. */ - ret = uvc_commit_video(stream, &stream->ctrl); - if (ret < 0) - return ret; - - return uvc_init_video(stream, GFP_KERNEL); -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvcvideo.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvcvideo.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvcvideo.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/uvc/uvcvideo.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,658 +0,0 @@ -#ifndef _USB_VIDEO_H_ -#define _USB_VIDEO_H_ - -#include -#include - -/* - * Dynamic controls - */ - -/* Data types for UVC control data */ -#define UVC_CTRL_DATA_TYPE_RAW 0 -#define UVC_CTRL_DATA_TYPE_SIGNED 1 -#define UVC_CTRL_DATA_TYPE_UNSIGNED 2 -#define UVC_CTRL_DATA_TYPE_BOOLEAN 3 -#define UVC_CTRL_DATA_TYPE_ENUM 4 -#define UVC_CTRL_DATA_TYPE_BITMASK 5 - -/* Control flags */ -#define UVC_CONTROL_SET_CUR (1 << 0) -#define UVC_CONTROL_GET_CUR (1 << 1) -#define UVC_CONTROL_GET_MIN (1 << 2) -#define UVC_CONTROL_GET_MAX (1 << 3) -#define UVC_CONTROL_GET_RES (1 << 4) -#define UVC_CONTROL_GET_DEF (1 << 5) -/* Control should be saved at suspend and restored at resume. */ -#define UVC_CONTROL_RESTORE (1 << 6) -/* Control can be updated by the camera. */ -#define UVC_CONTROL_AUTO_UPDATE (1 << 7) - -#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \ - UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ - UVC_CONTROL_GET_DEF) - -struct uvc_xu_control_info { - __u8 entity[16]; - __u8 index; - __u8 selector; - __u16 size; - __u32 flags; -}; - -struct uvc_menu_info { - __u32 value; - __u8 name[32]; -}; - -struct uvc_xu_control_mapping_old { - __u8 reserved[64]; -}; - -struct uvc_xu_control_mapping { - __u32 id; - __u8 name[32]; - __u8 entity[16]; - __u8 selector; - - __u8 size; - __u8 offset; - enum v4l2_ctrl_type v4l2_type; - __u32 data_type; - - struct uvc_menu_info __user *menu_info; - __u32 menu_count; - - __u32 reserved[4]; -}; - -struct uvc_xu_control { - __u8 unit; - __u8 selector; - __u16 size; - __u8 __user *data; -}; - -#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) -#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old) -#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) -#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) -#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) - -#ifdef __KERNEL__ - -#include -#include - -/* -------------------------------------------------------------------------- - * UVC constants - */ - -#define UVC_TERM_INPUT 0x0000 -#define UVC_TERM_OUTPUT 0x8000 -#define UVC_TERM_DIRECTION(term) ((term)->type & 0x8000) - -#define UVC_ENTITY_TYPE(entity) ((entity)->type & 0x7fff) -#define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0) -#define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0) -#define UVC_ENTITY_IS_ITERM(entity) \ - (UVC_ENTITY_IS_TERM(entity) && \ - ((entity)->type & 0x8000) == UVC_TERM_INPUT) -#define UVC_ENTITY_IS_OTERM(entity) \ - (UVC_ENTITY_IS_TERM(entity) && \ - ((entity)->type & 0x8000) == UVC_TERM_OUTPUT) - - -/* ------------------------------------------------------------------------ - * GUIDs - */ -#define UVC_GUID_UVC_CAMERA \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} -#define UVC_GUID_UVC_OUTPUT \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02} -#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03} -#define UVC_GUID_UVC_PROCESSING \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01} -#define UVC_GUID_UVC_SELECTOR \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02} - -#define UVC_GUID_FORMAT_MJPEG \ - { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_YUY2 \ - { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_YUY2_ISIGHT \ - { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_NV12 \ - { 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_YV12 \ - { 'Y', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_I420 \ - { 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_UYVY \ - { 'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Y800 \ - { 'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Y16 \ - { 'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_BY8 \ - { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} - -/* ------------------------------------------------------------------------ - * Driver specific constants. - */ - -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(1, 0, 0) -#define DRIVER_VERSION "v1.0.0" - -/* Number of isochronous URBs. */ -#define UVC_URBS 5 -/* Maximum number of packets per URB. */ -#define UVC_MAX_PACKETS 32 -/* Maximum number of video buffers. */ -#define UVC_MAX_VIDEO_BUFFERS 32 -/* Maximum status buffer size in bytes of interrupt URB. */ -#define UVC_MAX_STATUS_SIZE 16 - -#define UVC_CTRL_CONTROL_TIMEOUT 300 -#define UVC_CTRL_STREAMING_TIMEOUT 5000 - -/* Maximum allowed number of control mappings per device */ -#define UVC_MAX_CONTROL_MAPPINGS 1024 - -/* Devices quirks */ -#define UVC_QUIRK_STATUS_INTERVAL 0x00000001 -#define UVC_QUIRK_PROBE_MINMAX 0x00000002 -#define UVC_QUIRK_PROBE_EXTRAFIELDS 0x00000004 -#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008 -#define UVC_QUIRK_STREAM_NO_FID 0x00000010 -#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020 -#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080 -#define UVC_QUIRK_PROBE_DEF 0x00000100 -#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200 - -/* Format flags */ -#define UVC_FMT_FLAG_COMPRESSED 0x00000001 -#define UVC_FMT_FLAG_STREAM 0x00000002 - -/* ------------------------------------------------------------------------ - * Structures. - */ - -struct uvc_device; - -/* TODO: Put the most frequently accessed fields at the beginning of - * structures to maximize cache efficiency. - */ -struct uvc_control_info { - struct list_head mappings; - - __u8 entity[16]; - __u8 index; /* Bit index in bmControls */ - __u8 selector; - - __u16 size; - __u32 flags; -}; - -struct uvc_control_mapping { - struct list_head list; - - struct uvc_control_info *ctrl; - - __u32 id; - __u8 name[32]; - __u8 entity[16]; - __u8 selector; - - __u8 size; - __u8 offset; - enum v4l2_ctrl_type v4l2_type; - __u32 data_type; - - struct uvc_menu_info *menu_info; - __u32 menu_count; - - __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query, - const __u8 *data); - void (*set) (struct uvc_control_mapping *mapping, __s32 value, - __u8 *data); -}; - -struct uvc_control { - struct uvc_entity *entity; - struct uvc_control_info info; - - __u8 index; /* Used to match the uvc_control entry with a - uvc_control_info. */ - __u8 dirty:1, - loaded:1, - modified:1, - cached:1, - initialized:1; - - __u8 *uvc_data; -}; - -struct uvc_format_desc { - char *name; - __u8 guid[16]; - __u32 fcc; -}; - -/* The term 'entity' refers to both UVC units and UVC terminals. - * - * The type field is either the terminal type (wTerminalType in the terminal - * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor). - * As the bDescriptorSubtype field is one byte long, the type value will - * always have a null MSB for units. All terminal types defined by the UVC - * specification have a non-null MSB, so it is safe to use the MSB to - * differentiate between units and terminals as long as the descriptor parsing - * code makes sure terminal types have a non-null MSB. - * - * For terminals, the type's most significant bit stores the terminal - * direction (either UVC_TERM_INPUT or UVC_TERM_OUTPUT). The type field should - * always be accessed with the UVC_ENTITY_* macros and never directly. - */ - -struct uvc_entity { - struct list_head list; /* Entity as part of a UVC device. */ - struct list_head chain; /* Entity as part of a video device - * chain. */ - __u8 id; - __u16 type; - char name[64]; - - union { - struct { - __u16 wObjectiveFocalLengthMin; - __u16 wObjectiveFocalLengthMax; - __u16 wOcularFocalLength; - __u8 bControlSize; - __u8 *bmControls; - } camera; - - struct { - __u8 bControlSize; - __u8 *bmControls; - __u8 bTransportModeSize; - __u8 *bmTransportModes; - } media; - - struct { - } output; - - struct { - __u16 wMaxMultiplier; - __u8 bControlSize; - __u8 *bmControls; - __u8 bmVideoStandards; - } processing; - - struct { - } selector; - - struct { - __u8 guidExtensionCode[16]; - __u8 bNumControls; - __u8 bControlSize; - __u8 *bmControls; - __u8 *bmControlsType; - } extension; - }; - - __u8 bNrInPins; - __u8 *baSourceID; - - unsigned int ncontrols; - struct uvc_control *controls; -}; - -struct uvc_frame { - __u8 bFrameIndex; - __u8 bmCapabilities; - __u16 wWidth; - __u16 wHeight; - __u32 dwMinBitRate; - __u32 dwMaxBitRate; - __u32 dwMaxVideoFrameBufferSize; - __u8 bFrameIntervalType; - __u32 dwDefaultFrameInterval; - __u32 *dwFrameInterval; -}; - -struct uvc_format { - __u8 type; - __u8 index; - __u8 bpp; - __u8 colorspace; - __u32 fcc; - __u32 flags; - - char name[32]; - - unsigned int nframes; - struct uvc_frame *frame; -}; - -struct uvc_streaming_header { - __u8 bNumFormats; - __u8 bEndpointAddress; - __u8 bTerminalLink; - __u8 bControlSize; - __u8 *bmaControls; - /* The following fields are used by input headers only. */ - __u8 bmInfo; - __u8 bStillCaptureMethod; - __u8 bTriggerSupport; - __u8 bTriggerUsage; -}; - -enum uvc_buffer_state { - UVC_BUF_STATE_IDLE = 0, - UVC_BUF_STATE_QUEUED = 1, - UVC_BUF_STATE_ACTIVE = 2, - UVC_BUF_STATE_READY = 3, - UVC_BUF_STATE_DONE = 4, - UVC_BUF_STATE_ERROR = 5, -}; - -struct uvc_buffer { - unsigned long vma_use_count; - struct list_head stream; - - /* Touched by interrupt handler. */ - struct v4l2_buffer buf; - struct list_head queue; - wait_queue_head_t wait; - enum uvc_buffer_state state; - unsigned int error; -}; - -#define UVC_QUEUE_STREAMING (1 << 0) -#define UVC_QUEUE_DISCONNECTED (1 << 1) -#define UVC_QUEUE_DROP_CORRUPTED (1 << 2) - -struct uvc_video_queue { - enum v4l2_buf_type type; - - void *mem; - unsigned int flags; - - unsigned int count; - unsigned int buf_size; - unsigned int buf_used; - struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; - struct mutex mutex; /* protects buffers and mainqueue */ - spinlock_t irqlock; /* protects irqqueue */ - - struct list_head mainqueue; - struct list_head irqqueue; -}; - -struct uvc_video_chain { - struct uvc_device *dev; - struct list_head list; - - struct list_head entities; /* All entities */ - struct uvc_entity *processing; /* Processing unit */ - struct uvc_entity *selector; /* Selector unit */ - - struct mutex ctrl_mutex; /* Protects ctrl.info */ -}; - -struct uvc_streaming { - struct list_head list; - struct uvc_device *dev; - struct video_device *vdev; - struct uvc_video_chain *chain; - atomic_t active; - - struct usb_interface *intf; - int intfnum; - __u16 maxpsize; - - struct uvc_streaming_header header; - enum v4l2_buf_type type; - - unsigned int nformats; - struct uvc_format *format; - - struct uvc_streaming_control ctrl; - struct uvc_format *cur_format; - struct uvc_frame *cur_frame; - /* Protect access to ctrl, cur_format, cur_frame and hardware video - * probe control. - */ - struct mutex mutex; - - unsigned int frozen : 1; - struct uvc_video_queue queue; - void (*decode) (struct urb *urb, struct uvc_streaming *video, - struct uvc_buffer *buf); - - /* Context data used by the bulk completion handler. */ - struct { - __u8 header[256]; - unsigned int header_size; - int skip_payload; - __u32 payload_size; - __u32 max_payload_size; - } bulk; - - struct urb *urb[UVC_URBS]; - char *urb_buffer[UVC_URBS]; - dma_addr_t urb_dma[UVC_URBS]; - unsigned int urb_size; - - __u32 sequence; - __u8 last_fid; -}; - -enum uvc_device_state { - UVC_DEV_DISCONNECTED = 1, -}; - -struct uvc_device { - struct usb_device *udev; - struct usb_interface *intf; - unsigned long warnings; - __u32 quirks; - int intfnum; - char name[32]; - - enum uvc_device_state state; - atomic_t users; - atomic_t nmappings; - - /* Video control interface */ - __u16 uvc_version; - __u32 clock_frequency; - - struct list_head entities; - struct list_head chains; - - /* Video Streaming interfaces */ - struct list_head streams; - atomic_t nstreams; - - /* Status Interrupt Endpoint */ - struct usb_host_endpoint *int_ep; - struct urb *int_urb; - __u8 *status; - struct input_dev *input; - char input_phys[64]; -}; - -enum uvc_handle_state { - UVC_HANDLE_PASSIVE = 0, - UVC_HANDLE_ACTIVE = 1, -}; - -struct uvc_fh { - struct uvc_video_chain *chain; - struct uvc_streaming *stream; - enum uvc_handle_state state; -}; - -struct uvc_driver { - struct usb_driver driver; -}; - -/* ------------------------------------------------------------------------ - * Debugging, printing and logging - */ - -#define UVC_TRACE_PROBE (1 << 0) -#define UVC_TRACE_DESCR (1 << 1) -#define UVC_TRACE_CONTROL (1 << 2) -#define UVC_TRACE_FORMAT (1 << 3) -#define UVC_TRACE_CAPTURE (1 << 4) -#define UVC_TRACE_CALLS (1 << 5) -#define UVC_TRACE_IOCTL (1 << 6) -#define UVC_TRACE_FRAME (1 << 7) -#define UVC_TRACE_SUSPEND (1 << 8) -#define UVC_TRACE_STATUS (1 << 9) -#define UVC_TRACE_VIDEO (1 << 10) - -#define UVC_WARN_MINMAX 0 -#define UVC_WARN_PROBE_DEF 1 - -extern unsigned int uvc_clock_param; -extern unsigned int uvc_no_drop_param; -extern unsigned int uvc_trace_param; -extern unsigned int uvc_timeout_param; - -#define uvc_trace(flag, msg...) \ - do { \ - if (uvc_trace_param & flag) \ - printk(KERN_DEBUG "uvcvideo: " msg); \ - } while (0) - -#define uvc_warn_once(dev, warn, msg...) \ - do { \ - if (!test_and_set_bit(warn, &dev->warnings)) \ - printk(KERN_INFO "uvcvideo: " msg); \ - } while (0) - -#define uvc_printk(level, msg...) \ - printk(level "uvcvideo: " msg) - -/* -------------------------------------------------------------------------- - * Internal functions. - */ - -/* Core driver */ -extern struct uvc_driver uvc_driver; - -/* Video buffers queue management. */ -extern void uvc_queue_init(struct uvc_video_queue *queue, - enum v4l2_buf_type type, int drop_corrupted); -extern int uvc_alloc_buffers(struct uvc_video_queue *queue, - unsigned int nbuffers, unsigned int buflength); -extern int uvc_free_buffers(struct uvc_video_queue *queue); -extern int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -extern int uvc_queue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -extern int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking); -extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable); -extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); -extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, - struct uvc_buffer *buf); -extern int uvc_queue_mmap(struct uvc_video_queue *queue, - struct vm_area_struct *vma); -extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, - struct file *file, poll_table *wait); -extern int uvc_queue_allocated(struct uvc_video_queue *queue); -static inline int uvc_queue_streaming(struct uvc_video_queue *queue) -{ - return queue->flags & UVC_QUEUE_STREAMING; -} - -/* V4L2 interface */ -extern const struct v4l2_file_operations uvc_fops; - -/* Video */ -extern int uvc_video_init(struct uvc_streaming *stream); -extern int uvc_video_suspend(struct uvc_streaming *stream); -extern int uvc_video_resume(struct uvc_streaming *stream); -extern int uvc_video_enable(struct uvc_streaming *stream, int enable); -extern int uvc_probe_video(struct uvc_streaming *stream, - struct uvc_streaming_control *probe); -extern int uvc_commit_video(struct uvc_streaming *stream, - struct uvc_streaming_control *ctrl); -extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size); - -/* Status */ -extern int uvc_status_init(struct uvc_device *dev); -extern void uvc_status_cleanup(struct uvc_device *dev); -extern int uvc_status_start(struct uvc_device *dev); -extern void uvc_status_stop(struct uvc_device *dev); -extern int uvc_status_suspend(struct uvc_device *dev); -extern int uvc_status_resume(struct uvc_device *dev); - -/* Controls */ -extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, - struct v4l2_queryctrl *v4l2_ctrl); -extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain, - struct v4l2_querymenu *query_menu); - -extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, - const struct uvc_control_mapping *mapping); -extern int uvc_ctrl_init_device(struct uvc_device *dev); -extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); -extern int uvc_ctrl_resume_device(struct uvc_device *dev); - -extern int uvc_ctrl_begin(struct uvc_video_chain *chain); -extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback); -static inline int uvc_ctrl_commit(struct uvc_video_chain *chain) -{ - return __uvc_ctrl_commit(chain, 0); -} -static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain) -{ - return __uvc_ctrl_commit(chain, 1); -} - -extern int uvc_ctrl_get(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl); -extern int uvc_ctrl_set(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl); - -extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain, - struct uvc_xu_control *ctrl, int set); - -/* Utility functions */ -extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, - unsigned int n_terms, unsigned int threshold); -extern uint32_t uvc_fraction_to_interval(uint32_t numerator, - uint32_t denominator); -extern struct usb_host_endpoint *uvc_find_endpoint( - struct usb_host_interface *alts, __u8 epaddr); - -/* Quirks support */ -void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, - struct uvc_buffer *buf); - -#endif /* __KERNEL__ */ - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-common.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,621 +0,0 @@ -/* - * Video for Linux Two - * - * A generic video device interface for the LINUX operating system - * using a set of device structures/vectors for low level operations. - * - * This file replaces the videodev.c file that comes with the - * regular kernel distribution. - * - * 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, or (at your option) any later version. - * - * Author: Bill Dirks - * based on code by Alan Cox, - * - */ - -/* - * Video capture interface for Linux - * - * A generic video device interface for the LINUX operating system - * using a set of device structures/vectors for low level operations. - * - * 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, or (at your option) any later version. - * - * Author: Alan Cox, - * - * Fixes: - */ - -/* - * Video4linux 1/2 integration by Justin Schoeman - * - * 2.4 PROCFS support ported from 2.4 kernels by - * Iñaki García Etxebarria - * Makefile fix by "W. Michael Petullo" - * 2.4 devfs support ported from 2.4 kernels by - * Dan Merillat - * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman) - */ - -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_SPI) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr"); -MODULE_DESCRIPTION("misc helper functions for v4l2 device drivers"); -MODULE_LICENSE("GPL"); - -/* - * - * V 4 L 2 D R I V E R H E L P E R A P I - * - */ - -/* - * Video Standard Operations (contributed by Michael Schimek) - */ - -/* Helper functions for control handling */ - -/* Check for correctness of the ctrl's value based on the data from - struct v4l2_queryctrl and the available menu items. Note that - menu_items may be NULL, in that case it is ignored. */ -int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl, - const char * const *menu_items) -{ - if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED) - return -EINVAL; - if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED) - return -EBUSY; - if (qctrl->type == V4L2_CTRL_TYPE_STRING) - return 0; - if (qctrl->type == V4L2_CTRL_TYPE_BUTTON || - qctrl->type == V4L2_CTRL_TYPE_INTEGER64 || - qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) - return 0; - if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum) - return -ERANGE; - if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) { - if (menu_items[ctrl->value] == NULL || - menu_items[ctrl->value][0] == '\0') - return -EINVAL; - } - return 0; -} -EXPORT_SYMBOL(v4l2_ctrl_check); - -/* Fill in a struct v4l2_queryctrl */ -int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def) -{ - const char *name; - - v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type, - &min, &max, &step, &def, &qctrl->flags); - - if (name == NULL) - return -EINVAL; - - qctrl->minimum = min; - qctrl->maximum = max; - qctrl->step = step; - qctrl->default_value = def; - qctrl->reserved[0] = qctrl->reserved[1] = 0; - strlcpy(qctrl->name, name, sizeof(qctrl->name)); - return 0; -} -EXPORT_SYMBOL(v4l2_ctrl_query_fill); - -/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and - the menu. The qctrl pointer may be NULL, in which case it is ignored. - If menu_items is NULL, then the menu items are retrieved using - v4l2_ctrl_get_menu. */ -int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl, - const char * const *menu_items) -{ - int i; - - qmenu->reserved = 0; - if (menu_items == NULL) - menu_items = v4l2_ctrl_get_menu(qmenu->id); - if (menu_items == NULL || - (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum))) - return -EINVAL; - for (i = 0; i < qmenu->index && menu_items[i]; i++) ; - if (menu_items[i] == NULL || menu_items[i][0] == '\0') - return -EINVAL; - strlcpy(qmenu->name, menu_items[qmenu->index], sizeof(qmenu->name)); - return 0; -} -EXPORT_SYMBOL(v4l2_ctrl_query_menu); - -/* Fill in a struct v4l2_querymenu based on the specified array of valid - menu items (terminated by V4L2_CTRL_MENU_IDS_END). - Use this if there are 'holes' in the list of valid menu items. */ -int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids) -{ - const char * const *menu_items = v4l2_ctrl_get_menu(qmenu->id); - - qmenu->reserved = 0; - if (menu_items == NULL || ids == NULL) - return -EINVAL; - while (*ids != V4L2_CTRL_MENU_IDS_END) { - if (*ids++ == qmenu->index) { - strlcpy(qmenu->name, menu_items[qmenu->index], - sizeof(qmenu->name)); - return 0; - } - } - return -EINVAL; -} -EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items); - -/* ctrl_classes points to an array of u32 pointers, the last element is - a NULL pointer. Each u32 array is a 0-terminated array of control IDs. - Each array must be sorted low to high and belong to the same control - class. The array of u32 pointers must also be sorted, from low class IDs - to high class IDs. - - This function returns the first ID that follows after the given ID. - When no more controls are available 0 is returned. */ -u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id) -{ - u32 ctrl_class = V4L2_CTRL_ID2CLASS(id); - const u32 *pctrl; - - if (ctrl_classes == NULL) - return 0; - - /* if no query is desired, then check if the ID is part of ctrl_classes */ - if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) { - /* find class */ - while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class) - ctrl_classes++; - if (*ctrl_classes == NULL) - return 0; - pctrl = *ctrl_classes; - /* find control ID */ - while (*pctrl && *pctrl != id) pctrl++; - return *pctrl ? id : 0; - } - id &= V4L2_CTRL_ID_MASK; - id++; /* select next control */ - /* find first class that matches (or is greater than) the class of - the ID */ - while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) < ctrl_class) - ctrl_classes++; - /* no more classes */ - if (*ctrl_classes == NULL) - return 0; - pctrl = *ctrl_classes; - /* find first ctrl within the class that is >= ID */ - while (*pctrl && *pctrl < id) pctrl++; - if (*pctrl) - return *pctrl; - /* we are at the end of the controls of the current class. */ - /* continue with next class if available */ - ctrl_classes++; - if (*ctrl_classes == NULL) - return 0; - return **ctrl_classes; -} -EXPORT_SYMBOL(v4l2_ctrl_next); - -int v4l2_chip_match_host(const struct v4l2_dbg_match *match) -{ - switch (match->type) { - case V4L2_CHIP_MATCH_HOST: - return match->addr == 0; - default: - return 0; - } -} -EXPORT_SYMBOL(v4l2_chip_match_host); - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match) -{ - int len; - - if (c == NULL || match == NULL) - return 0; - - switch (match->type) { - case V4L2_CHIP_MATCH_I2C_DRIVER: - if (c->driver == NULL || c->driver->driver.name == NULL) - return 0; - len = strlen(c->driver->driver.name); - /* legacy drivers have a ' suffix, don't try to match that */ - if (len && c->driver->driver.name[len - 1] == '\'') - len--; - return len && !strncmp(c->driver->driver.name, match->name, len); - case V4L2_CHIP_MATCH_I2C_ADDR: - return c->addr == match->addr; - default: - return 0; - } -} -EXPORT_SYMBOL(v4l2_chip_match_i2c_client); - -int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_dbg_chip_ident *chip, - u32 ident, u32 revision) -{ - if (!v4l2_chip_match_i2c_client(c, &chip->match)) - return 0; - if (chip->ident == V4L2_IDENT_NONE) { - chip->ident = ident; - chip->revision = revision; - } - else { - chip->ident = V4L2_IDENT_AMBIGUOUS; - chip->revision = 0; - } - return 0; -} -EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); - -/* ----------------------------------------------------------------- */ - -/* I2C Helper functions */ - - -void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, - const struct v4l2_subdev_ops *ops) -{ - v4l2_subdev_init(sd, ops); - sd->flags |= V4L2_SUBDEV_FL_IS_I2C; - /* the owner is the same as the i2c_client's driver owner */ - sd->owner = client->driver->driver.owner; - /* i2c_client and v4l2_subdev point to one another */ - v4l2_set_subdevdata(sd, client); - i2c_set_clientdata(client, sd); - /* initialize name */ - snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", - client->driver->driver.name, i2c_adapter_id(client->adapter), - client->addr); -} -EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); - - - -/* Load an i2c sub-device. */ -struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, struct i2c_board_info *info, - const unsigned short *probe_addrs) -{ - struct v4l2_subdev *sd = NULL; - struct i2c_client *client; - - BUG_ON(!v4l2_dev); - - request_module(I2C_MODULE_PREFIX "%s", info->type); - - /* Create the i2c client */ - if (info->addr == 0 && probe_addrs) - client = i2c_new_probed_device(adapter, info, probe_addrs, - NULL); - else - client = i2c_new_device(adapter, info); - - /* Note: by loading the module first we are certain that c->driver - will be set if the driver was found. If the module was not loaded - first, then the i2c core tries to delay-load the module for us, - and then c->driver is still NULL until the module is finally - loaded. This delay-load mechanism doesn't work if other drivers - want to use the i2c device, so explicitly loading the module - is the best alternative. */ - if (client == NULL || client->driver == NULL) - goto error; - - /* Lock the module so we can safely get the v4l2_subdev pointer */ - if (!try_module_get(client->driver->driver.owner)) - goto error; - sd = i2c_get_clientdata(client); - - /* Register with the v4l2_device which increases the module's - use count as well. */ - if (v4l2_device_register_subdev(v4l2_dev, sd)) - sd = NULL; - /* Decrease the module use count to match the first try_module_get. */ - module_put(client->driver->driver.owner); - -error: - /* If we have a client but no subdev, then something went wrong and - we must unregister the client. */ - if (client && sd == NULL) - i2c_unregister_device(client); - return sd; -} -EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board); - -struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, const char *client_type, - u8 addr, const unsigned short *probe_addrs) -{ - struct i2c_board_info info; - - /* Setup the i2c board info with the device type and - the device address. */ - memset(&info, 0, sizeof(info)); - strlcpy(info.type, client_type, sizeof(info.type)); - info.addr = addr; - - return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs); -} -EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); - -/* Return i2c client address of v4l2_subdev. */ -unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return client ? client->addr : I2C_CLIENT_END; -} -EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr); - -/* Return a list of I2C tuner addresses to probe. Use only if the tuner - addresses are unknown. */ -const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) -{ - static const unsigned short radio_addrs[] = { -#if defined(CONFIG_MEDIA_TUNER_TEA5761) || defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) - 0x10, -#endif - 0x60, - I2C_CLIENT_END - }; - static const unsigned short demod_addrs[] = { - 0x42, 0x43, 0x4a, 0x4b, - I2C_CLIENT_END - }; - static const unsigned short tv_addrs[] = { - 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ - 0x60, 0x61, 0x62, 0x63, 0x64, - I2C_CLIENT_END - }; - - switch (type) { - case ADDRS_RADIO: - return radio_addrs; - case ADDRS_DEMOD: - return demod_addrs; - case ADDRS_TV: - return tv_addrs; - case ADDRS_TV_WITH_DEMOD: - return tv_addrs + 4; - } - return NULL; -} -EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); - -#endif /* defined(CONFIG_I2C) */ - -#if defined(CONFIG_SPI) - -/* Load a spi sub-device. */ - -void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, - const struct v4l2_subdev_ops *ops) -{ - v4l2_subdev_init(sd, ops); - sd->flags |= V4L2_SUBDEV_FL_IS_SPI; - /* the owner is the same as the spi_device's driver owner */ - sd->owner = spi->dev.driver->owner; - /* spi_device and v4l2_subdev point to one another */ - v4l2_set_subdevdata(sd, spi); - spi_set_drvdata(spi, sd); - /* initialize name */ - strlcpy(sd->name, spi->dev.driver->name, sizeof(sd->name)); -} -EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init); - -struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, - struct spi_master *master, struct spi_board_info *info) -{ - struct v4l2_subdev *sd = NULL; - struct spi_device *spi = NULL; - - BUG_ON(!v4l2_dev); - - if (info->modalias) - request_module(info->modalias); - - spi = spi_new_device(master, info); - - if (spi == NULL || spi->dev.driver == NULL) - goto error; - - if (!try_module_get(spi->dev.driver->owner)) - goto error; - - sd = spi_get_drvdata(spi); - - /* Register with the v4l2_device which increases the module's - use count as well. */ - if (v4l2_device_register_subdev(v4l2_dev, sd)) - sd = NULL; - - /* Decrease the module use count to match the first try_module_get. */ - module_put(spi->dev.driver->owner); - -error: - /* If we have a client but no subdev, then something went wrong and - we must unregister the client. */ - if (spi && sd == NULL) - spi_unregister_device(spi); - - return sd; -} -EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev); - -#endif /* defined(CONFIG_SPI) */ - -/* Clamp x to be between min and max, aligned to a multiple of 2^align. min - * and max don't have to be aligned, but there must be at least one valid - * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples - * of 16 between 17 and 31. */ -static unsigned int clamp_align(unsigned int x, unsigned int min, - unsigned int max, unsigned int align) -{ - /* Bits that must be zero to be aligned */ - unsigned int mask = ~((1 << align) - 1); - - /* Round to nearest aligned value */ - if (align) - x = (x + (1 << (align - 1))) & mask; - - /* Clamp to aligned value of min and max */ - if (x < min) - x = (min + ~mask) & mask; - else if (x > max) - x = max & mask; - - return x; -} - -/* Bound an image to have a width between wmin and wmax, and height between - * hmin and hmax, inclusive. Additionally, the width will be a multiple of - * 2^walign, the height will be a multiple of 2^halign, and the overall size - * (width*height) will be a multiple of 2^salign. The image may be shrunk - * or enlarged to fit the alignment constraints. - * - * The width or height maximum must not be smaller than the corresponding - * minimum. The alignments must not be so high there are no possible image - * sizes within the allowed bounds. wmin and hmin must be at least 1 - * (don't use 0). If you don't care about a certain alignment, specify 0, - * as 2^0 is 1 and one byte alignment is equivalent to no alignment. If - * you only want to adjust downward, specify a maximum that's the same as - * the initial value. - */ -void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, - unsigned int walign, - u32 *h, unsigned int hmin, unsigned int hmax, - unsigned int halign, unsigned int salign) -{ - *w = clamp_align(*w, wmin, wmax, walign); - *h = clamp_align(*h, hmin, hmax, halign); - - /* Usually we don't need to align the size and are done now. */ - if (!salign) - return; - - /* How much alignment do we have? */ - walign = __ffs(*w); - halign = __ffs(*h); - /* Enough to satisfy the image alignment? */ - if (walign + halign < salign) { - /* Max walign where there is still a valid width */ - unsigned int wmaxa = __fls(wmax ^ (wmin - 1)); - /* Max halign where there is still a valid height */ - unsigned int hmaxa = __fls(hmax ^ (hmin - 1)); - - /* up the smaller alignment until we have enough */ - do { - if (halign >= hmaxa || - (walign <= halign && walign < wmaxa)) { - *w = clamp_align(*w, wmin, wmax, walign + 1); - walign = __ffs(*w); - } else { - *h = clamp_align(*h, hmin, hmax, halign + 1); - halign = __ffs(*h); - } - } while (halign + walign < salign); - } -} -EXPORT_SYMBOL_GPL(v4l_bound_align_image); - -/** - * v4l_fill_dv_preset_info - fill description of a digital video preset - * @preset - preset value - * @info - pointer to struct v4l2_dv_enum_preset - * - * drivers can use this helper function to fill description of dv preset - * in info. - */ -int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info) -{ - static const struct v4l2_dv_preset_info { - u16 width; - u16 height; - const char *name; - } dv_presets[] = { - { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */ - { 720, 480, "480p@59.94" }, /* V4L2_DV_480P59_94 */ - { 720, 576, "576p@50" }, /* V4L2_DV_576P50 */ - { 1280, 720, "720p@24" }, /* V4L2_DV_720P24 */ - { 1280, 720, "720p@25" }, /* V4L2_DV_720P25 */ - { 1280, 720, "720p@30" }, /* V4L2_DV_720P30 */ - { 1280, 720, "720p@50" }, /* V4L2_DV_720P50 */ - { 1280, 720, "720p@59.94" }, /* V4L2_DV_720P59_94 */ - { 1280, 720, "720p@60" }, /* V4L2_DV_720P60 */ - { 1920, 1080, "1080i@29.97" }, /* V4L2_DV_1080I29_97 */ - { 1920, 1080, "1080i@30" }, /* V4L2_DV_1080I30 */ - { 1920, 1080, "1080i@25" }, /* V4L2_DV_1080I25 */ - { 1920, 1080, "1080i@50" }, /* V4L2_DV_1080I50 */ - { 1920, 1080, "1080i@60" }, /* V4L2_DV_1080I60 */ - { 1920, 1080, "1080p@24" }, /* V4L2_DV_1080P24 */ - { 1920, 1080, "1080p@25" }, /* V4L2_DV_1080P25 */ - { 1920, 1080, "1080p@30" }, /* V4L2_DV_1080P30 */ - { 1920, 1080, "1080p@50" }, /* V4L2_DV_1080P50 */ - { 1920, 1080, "1080p@60" }, /* V4L2_DV_1080P60 */ - }; - - if (info == NULL || preset >= ARRAY_SIZE(dv_presets)) - return -EINVAL; - - info->preset = preset; - info->width = dv_presets[preset].width; - info->height = dv_presets[preset].height; - strlcpy(info->name, dv_presets[preset].name, sizeof(info->name)); - return 0; -} -EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info); - -const struct v4l2_frmsize_discrete *v4l2_find_nearest_format( - const struct v4l2_discrete_probe *probe, - s32 width, s32 height) -{ - int i; - u32 error, min_error = UINT_MAX; - const struct v4l2_frmsize_discrete *size, *best = NULL; - - if (!probe) - return best; - - for (i = 0, size = probe->sizes; i < probe->num_sizes; i++, size++) { - error = abs(size->width - width) + abs(size->height - height); - if (error < min_error) { - min_error = error; - best = size; - } - if (!error) - break; - } - - return best; -} -EXPORT_SYMBOL_GPL(v4l2_find_nearest_format); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-compat-ioctl32.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-compat-ioctl32.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-compat-ioctl32.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-compat-ioctl32.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,939 +0,0 @@ -/* - * ioctl32.c: Conversion between 32bit and 64bit native ioctls. - * Separated from fs stuff by Arnd Bergmann - * - * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs - * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz) - * Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be) - * Copyright (C) 2008 Hans Verkuil - * - * These routines maintain argument size conversion between 32bit and 64bit - * ioctls. - */ - -#include -#include -#include -#include - -#ifdef CONFIG_COMPAT - -static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret = -ENOIOCTLCMD; - - if (file->f_op->unlocked_ioctl) - ret = file->f_op->unlocked_ioctl(file, cmd, arg); - - return ret; -} - - -struct v4l2_clip32 { - struct v4l2_rect c; - compat_caddr_t next; -}; - -struct v4l2_window32 { - struct v4l2_rect w; - enum v4l2_field field; - __u32 chromakey; - compat_caddr_t clips; /* actually struct v4l2_clip32 * */ - __u32 clipcount; - compat_caddr_t bitmap; -}; - -static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) -{ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || - copy_from_user(&kp->w, &up->w, sizeof(up->w)) || - get_user(kp->field, &up->field) || - get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount)) - return -EFAULT; - if (kp->clipcount > 2048) - return -EINVAL; - if (kp->clipcount) { - struct v4l2_clip32 __user *uclips; - struct v4l2_clip __user *kclips; - int n = kp->clipcount; - compat_caddr_t p; - - if (get_user(p, &up->clips)) - return -EFAULT; - uclips = compat_ptr(p); - kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); - kp->clips = kclips; - while (--n >= 0) { - if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(n ? kclips + 1 : NULL, &kclips->next)) - return -EFAULT; - uclips += 1; - kclips += 1; - } - } else - kp->clips = NULL; - return 0; -} - -static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) -{ - if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || - put_user(kp->field, &up->field) || - put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount)) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, - struct v4l2_pix_format_mplane __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) - return -EFAULT; - return 0; -} - -struct v4l2_format32 { - enum v4l2_buf_type type; - union { - struct v4l2_pix_format pix; - struct v4l2_pix_format_mplane pix_mp; - struct v4l2_window32 win; - struct v4l2_vbi_format vbi; - struct v4l2_sliced_vbi_format sliced; - __u8 raw_data[200]; /* user-defined */ - } fmt; -}; - -static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) -{ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) || - get_user(kp->type, &up->type)) - return -EFAULT; - switch (kp->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); - case V4L2_BUF_TYPE_VBI_CAPTURE: - case V4L2_BUF_TYPE_VBI_OUTPUT: - return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); - case V4L2_BUF_TYPE_PRIVATE: - if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data))) - return -EFAULT; - return 0; - default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); - return -EINVAL; - } -} - -static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) -{ - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || - put_user(kp->type, &up->type)) - return -EFAULT; - switch (kp->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp, - &up->fmt.pix_mp); - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); - case V4L2_BUF_TYPE_VBI_CAPTURE: - case V4L2_BUF_TYPE_VBI_OUTPUT: - return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); - case V4L2_BUF_TYPE_PRIVATE: - if (copy_to_user(up, kp, sizeof(up->fmt.raw_data))) - return -EFAULT; - return 0; - default: - printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n", - kp->type); - return -EINVAL; - } -} - -struct v4l2_standard32 { - __u32 index; - __u32 id[2]; /* __u64 would get the alignment wrong */ - __u8 name[24]; - struct v4l2_fract frameperiod; /* Frames, not fields */ - __u32 framelines; - __u32 reserved[4]; -}; - -static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) -{ - /* other fields are not set by the user, nor used by the driver */ - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || - get_user(kp->index, &up->index)) - return -EFAULT; - return 0; -} - -static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) -{ - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || - put_user(kp->index, &up->index) || - copy_to_user(up->id, &kp->id, sizeof(__u64)) || - copy_to_user(up->name, kp->name, 24) || - copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || - put_user(kp->framelines, &up->framelines) || - copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) - return -EFAULT; - return 0; -} - -struct v4l2_plane32 { - __u32 bytesused; - __u32 length; - union { - __u32 mem_offset; - compat_long_t userptr; - } m; - __u32 data_offset; - __u32 reserved[11]; -}; - -struct v4l2_buffer32 { - __u32 index; - enum v4l2_buf_type type; - __u32 bytesused; - __u32 flags; - enum v4l2_field field; - struct compat_timeval timestamp; - struct v4l2_timecode timecode; - __u32 sequence; - - /* memory location */ - enum v4l2_memory memory; - union { - __u32 offset; - compat_long_t userptr; - compat_caddr_t planes; - } m; - __u32 length; - __u32 input; - __u32 reserved; -}; - -static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, - enum v4l2_memory memory) -{ - void __user *up_pln; - compat_long_t p; - - if (copy_in_user(up, up32, 2 * sizeof(__u32)) || - copy_in_user(&up->data_offset, &up32->data_offset, - sizeof(__u32))) - return -EFAULT; - - if (memory == V4L2_MEMORY_USERPTR) { - if (get_user(p, &up32->m.userptr)) - return -EFAULT; - up_pln = compat_ptr(p); - if (put_user((unsigned long)up_pln, &up->m.userptr)) - return -EFAULT; - } else { - if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, - sizeof(__u32))) - return -EFAULT; - } - - return 0; -} - -static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, - enum v4l2_memory memory) -{ - if (copy_in_user(up32, up, 2 * sizeof(__u32)) || - copy_in_user(&up32->data_offset, &up->data_offset, - sizeof(__u32))) - return -EFAULT; - - /* For MMAP, driver might've set up the offset, so copy it back. - * USERPTR stays the same (was userspace-provided), so no copying. */ - if (memory == V4L2_MEMORY_MMAP) - if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, - sizeof(__u32))) - return -EFAULT; - - return 0; -} - -static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) -{ - struct v4l2_plane32 __user *uplane32; - struct v4l2_plane __user *uplane; - compat_caddr_t p; - int num_planes; - int ret; - - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || - get_user(kp->index, &up->index) || - get_user(kp->type, &up->type) || - get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory) || - get_user(kp->input, &up->input)) - return -EFAULT; - - if (V4L2_TYPE_IS_OUTPUT(kp->type)) - if (get_user(kp->bytesused, &up->bytesused) || - get_user(kp->field, &up->field) || - get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - get_user(kp->timestamp.tv_usec, - &up->timestamp.tv_usec)) - return -EFAULT; - - if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - if (get_user(kp->length, &up->length)) - return -EFAULT; - - num_planes = kp->length; - if (num_planes == 0) { - kp->m.planes = NULL; - /* num_planes == 0 is legal, e.g. when userspace doesn't - * need planes array on DQBUF*/ - return 0; - } - - if (get_user(p, &up->m.planes)) - return -EFAULT; - - uplane32 = compat_ptr(p); - if (!access_ok(VERIFY_READ, uplane32, - num_planes * sizeof(struct v4l2_plane32))) - return -EFAULT; - - /* We don't really care if userspace decides to kill itself - * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * - sizeof(struct v4l2_plane)); - kp->m.planes = uplane; - - while (--num_planes >= 0) { - ret = get_v4l2_plane32(uplane, uplane32, kp->memory); - if (ret) - return ret; - ++uplane; - ++uplane32; - } - } else { - switch (kp->memory) { - case V4L2_MEMORY_MMAP: - if (get_user(kp->length, &up->length) || - get_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; - case V4L2_MEMORY_USERPTR: - { - compat_long_t tmp; - - if (get_user(kp->length, &up->length) || - get_user(tmp, &up->m.userptr)) - return -EFAULT; - - kp->m.userptr = (unsigned long)compat_ptr(tmp); - } - break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; - } - } - - return 0; -} - -static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) -{ - struct v4l2_plane32 __user *uplane32; - struct v4l2_plane __user *uplane; - compat_caddr_t p; - int num_planes; - int ret; - - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || - put_user(kp->index, &up->index) || - put_user(kp->type, &up->type) || - put_user(kp->flags, &up->flags) || - put_user(kp->memory, &up->memory) || - put_user(kp->input, &up->input)) - return -EFAULT; - - if (put_user(kp->bytesused, &up->bytesused) || - put_user(kp->field, &up->field) || - put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || - put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || - copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || - put_user(kp->sequence, &up->sequence) || - put_user(kp->reserved, &up->reserved)) - return -EFAULT; - - if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; - if (num_planes == 0) - return 0; - - uplane = kp->m.planes; - if (get_user(p, &up->m.planes)) - return -EFAULT; - uplane32 = compat_ptr(p); - - while (--num_planes >= 0) { - ret = put_v4l2_plane32(uplane, uplane32, kp->memory); - if (ret) - return ret; - ++uplane; - ++uplane32; - } - } else { - switch (kp->memory) { - case V4L2_MEMORY_MMAP: - if (put_user(kp->length, &up->length) || - put_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; - case V4L2_MEMORY_USERPTR: - if (put_user(kp->length, &up->length) || - put_user(kp->m.userptr, &up->m.userptr)) - return -EFAULT; - break; - case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; - } - } - - return 0; -} - -struct v4l2_framebuffer32 { - __u32 capability; - __u32 flags; - compat_caddr_t base; - struct v4l2_pix_format fmt; -}; - -static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) -{ - u32 tmp; - - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || - get_user(tmp, &up->base) || - get_user(kp->capability, &up->capability) || - get_user(kp->flags, &up->flags)) - return -EFAULT; - kp->base = compat_ptr(tmp); - get_v4l2_pix_format(&kp->fmt, &up->fmt); - return 0; -} - -static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) -{ - u32 tmp = (u32)((unsigned long)kp->base); - - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || - put_user(tmp, &up->base) || - put_user(kp->capability, &up->capability) || - put_user(kp->flags, &up->flags)) - return -EFAULT; - put_v4l2_pix_format(&kp->fmt, &up->fmt); - return 0; -} - -struct v4l2_input32 { - __u32 index; /* Which input */ - __u8 name[32]; /* Label */ - __u32 type; /* Type of input */ - __u32 audioset; /* Associated audios (bitfield) */ - __u32 tuner; /* Associated tuner */ - v4l2_std_id std; - __u32 status; - __u32 reserved[4]; -} __attribute__ ((packed)); - -/* The 64-bit v4l2_input struct has extra padding at the end of the struct. - Otherwise it is identical to the 32-bit version. */ -static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) -{ - if (copy_from_user(kp, up, sizeof(struct v4l2_input32))) - return -EFAULT; - return 0; -} - -static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) -{ - if (copy_to_user(up, kp, sizeof(struct v4l2_input32))) - return -EFAULT; - return 0; -} - -struct v4l2_ext_controls32 { - __u32 ctrl_class; - __u32 count; - __u32 error_idx; - __u32 reserved[2]; - compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ -}; - -struct v4l2_ext_control32 { - __u32 id; - __u32 size; - __u32 reserved2[1]; - union { - __s32 value; - __s64 value64; - compat_caddr_t string; /* actually char * */ - }; -} __attribute__ ((packed)); - -/* The following function really belong in v4l2-common, but that causes - a circular dependency between modules. We need to think about this, but - for now this will do. */ - -/* Return non-zero if this control is a pointer type. Currently only - type STRING is a pointer type. */ -static inline int ctrl_is_pointer(u32 id) -{ - switch (id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - return 1; - default: - return 0; - } -} - -static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) -{ - struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols; - int n; - compat_caddr_t p; - - if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || - get_user(kp->ctrl_class, &up->ctrl_class) || - get_user(kp->count, &up->count) || - get_user(kp->error_idx, &up->error_idx) || - copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) - return -EFAULT; - n = kp->count; - if (n == 0) { - kp->controls = NULL; - return 0; - } - if (get_user(p, &up->controls)) - return -EFAULT; - ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_READ, ucontrols, - n * sizeof(struct v4l2_ext_control32))) - return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); - kp->controls = kcontrols; - while (--n >= 0) { - if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) - return -EFAULT; - if (ctrl_is_pointer(kcontrols->id)) { - void __user *s; - - if (get_user(p, &ucontrols->string)) - return -EFAULT; - s = compat_ptr(p); - if (put_user(s, &kcontrols->string)) - return -EFAULT; - } - ucontrols++; - kcontrols++; - } - return 0; -} - -static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) -{ - struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols = kp->controls; - int n = kp->count; - compat_caddr_t p; - - if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || - put_user(kp->ctrl_class, &up->ctrl_class) || - put_user(kp->count, &up->count) || - put_user(kp->error_idx, &up->error_idx) || - copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) - return -EFAULT; - if (!kp->count) - return 0; - - if (get_user(p, &up->controls)) - return -EFAULT; - ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_WRITE, ucontrols, - n * sizeof(struct v4l2_ext_control32))) - return -EFAULT; - - while (--n >= 0) { - unsigned size = sizeof(*ucontrols); - - /* Do not modify the pointer when copying a pointer control. - The contents of the pointer was changed, not the pointer - itself. */ - if (ctrl_is_pointer(kcontrols->id)) - size -= sizeof(ucontrols->value64); - if (copy_in_user(ucontrols, kcontrols, size)) - return -EFAULT; - ucontrols++; - kcontrols++; - } - return 0; -} - -#define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32) -#define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32) -#define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32) -#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32) -#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32) -#define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32) -#define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32) -#define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32) -#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) -#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) -#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) -#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) -#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) - -#define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) -#define VIDIOC_STREAMON32 _IOW ('V', 18, s32) -#define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32) -#define VIDIOC_G_INPUT32 _IOR ('V', 38, s32) -#define VIDIOC_S_INPUT32 _IOWR('V', 39, s32) -#define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) -#define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32) - -static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - union { - struct v4l2_format v2f; - struct v4l2_buffer v2b; - struct v4l2_framebuffer v2fb; - struct v4l2_input v2i; - struct v4l2_standard v2s; - struct v4l2_ext_controls v2ecs; - unsigned long vx; - int vi; - } karg; - void __user *up = compat_ptr(arg); - int compatible_arg = 1; - long err = 0; - - /* First, convert the command. */ - switch (cmd) { - case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break; - case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break; - case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break; - case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break; - case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break; - case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break; - case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break; - case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break; - case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break; - case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break; - case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break; - case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break; - case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break; - case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break; - case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break; - case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break; - case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break; - case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; - case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break; - case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break; - } - - switch (cmd) { - case VIDIOC_OVERLAY: - case VIDIOC_STREAMON: - case VIDIOC_STREAMOFF: - case VIDIOC_S_INPUT: - case VIDIOC_S_OUTPUT: - err = get_user(karg.vi, (s32 __user *)up); - compatible_arg = 0; - break; - - case VIDIOC_G_INPUT: - case VIDIOC_G_OUTPUT: - compatible_arg = 0; - break; - - case VIDIOC_G_FMT: - case VIDIOC_S_FMT: - case VIDIOC_TRY_FMT: - err = get_v4l2_format32(&karg.v2f, up); - compatible_arg = 0; - break; - - case VIDIOC_QUERYBUF: - case VIDIOC_QBUF: - case VIDIOC_DQBUF: - err = get_v4l2_buffer32(&karg.v2b, up); - compatible_arg = 0; - break; - - case VIDIOC_S_FBUF: - err = get_v4l2_framebuffer32(&karg.v2fb, up); - compatible_arg = 0; - break; - - case VIDIOC_G_FBUF: - compatible_arg = 0; - break; - - case VIDIOC_ENUMSTD: - err = get_v4l2_standard32(&karg.v2s, up); - compatible_arg = 0; - break; - - case VIDIOC_ENUMINPUT: - err = get_v4l2_input32(&karg.v2i, up); - compatible_arg = 0; - break; - - case VIDIOC_G_EXT_CTRLS: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_TRY_EXT_CTRLS: - err = get_v4l2_ext_controls32(&karg.v2ecs, up); - compatible_arg = 0; - break; - } - if (err) - return err; - - if (compatible_arg) - err = native_ioctl(file, cmd, (unsigned long)up); - else { - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - err = native_ioctl(file, cmd, (unsigned long)&karg); - set_fs(old_fs); - } - - /* Special case: even after an error we need to put the - results back for these ioctls since the error_idx will - contain information on which control failed. */ - switch (cmd) { - case VIDIOC_G_EXT_CTRLS: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_TRY_EXT_CTRLS: - if (put_v4l2_ext_controls32(&karg.v2ecs, up)) - err = -EFAULT; - break; - } - if (err) - return err; - - switch (cmd) { - case VIDIOC_S_INPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_G_INPUT: - case VIDIOC_G_OUTPUT: - err = put_user(((s32)karg.vi), (s32 __user *)up); - break; - - case VIDIOC_G_FBUF: - err = put_v4l2_framebuffer32(&karg.v2fb, up); - break; - - case VIDIOC_G_FMT: - case VIDIOC_S_FMT: - case VIDIOC_TRY_FMT: - err = put_v4l2_format32(&karg.v2f, up); - break; - - case VIDIOC_QUERYBUF: - case VIDIOC_QBUF: - case VIDIOC_DQBUF: - err = put_v4l2_buffer32(&karg.v2b, up); - break; - - case VIDIOC_ENUMSTD: - err = put_v4l2_standard32(&karg.v2s, up); - break; - - case VIDIOC_ENUMINPUT: - err = put_v4l2_input32(&karg.v2i, up); - break; - } - return err; -} - -long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret = -ENOIOCTLCMD; - - if (!file->f_op->unlocked_ioctl) - return ret; - - switch (cmd) { - case VIDIOC_QUERYCAP: - case VIDIOC_RESERVED: - case VIDIOC_ENUM_FMT: - case VIDIOC_G_FMT32: - case VIDIOC_S_FMT32: - case VIDIOC_REQBUFS: - case VIDIOC_QUERYBUF32: - case VIDIOC_G_FBUF32: - case VIDIOC_S_FBUF32: - case VIDIOC_OVERLAY32: - case VIDIOC_QBUF32: - case VIDIOC_DQBUF32: - case VIDIOC_STREAMON32: - case VIDIOC_STREAMOFF32: - case VIDIOC_G_PARM: - case VIDIOC_S_PARM: - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_ENUMSTD32: - case VIDIOC_ENUMINPUT32: - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - case VIDIOC_G_TUNER: - case VIDIOC_S_TUNER: - case VIDIOC_G_AUDIO: - case VIDIOC_S_AUDIO: - case VIDIOC_QUERYCTRL: - case VIDIOC_QUERYMENU: - case VIDIOC_G_INPUT32: - case VIDIOC_S_INPUT32: - case VIDIOC_G_OUTPUT32: - case VIDIOC_S_OUTPUT32: - case VIDIOC_ENUMOUTPUT: - case VIDIOC_G_AUDOUT: - case VIDIOC_S_AUDOUT: - case VIDIOC_G_MODULATOR: - case VIDIOC_S_MODULATOR: - case VIDIOC_S_FREQUENCY: - case VIDIOC_G_FREQUENCY: - case VIDIOC_CROPCAP: - case VIDIOC_G_CROP: - case VIDIOC_S_CROP: - case VIDIOC_G_JPEGCOMP: - case VIDIOC_S_JPEGCOMP: - case VIDIOC_QUERYSTD: - case VIDIOC_TRY_FMT32: - case VIDIOC_ENUMAUDIO: - case VIDIOC_ENUMAUDOUT: - case VIDIOC_G_PRIORITY: - case VIDIOC_S_PRIORITY: - case VIDIOC_G_SLICED_VBI_CAP: - case VIDIOC_LOG_STATUS: - case VIDIOC_G_EXT_CTRLS32: - case VIDIOC_S_EXT_CTRLS32: - case VIDIOC_TRY_EXT_CTRLS32: - case VIDIOC_ENUM_FRAMESIZES: - case VIDIOC_ENUM_FRAMEINTERVALS: - case VIDIOC_G_ENC_INDEX: - case VIDIOC_ENCODER_CMD: - case VIDIOC_TRY_ENCODER_CMD: - case VIDIOC_DBG_S_REGISTER: - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_G_CHIP_IDENT: - case VIDIOC_S_HW_FREQ_SEEK: - case VIDIOC_ENUM_DV_PRESETS: - case VIDIOC_S_DV_PRESET: - case VIDIOC_G_DV_PRESET: - case VIDIOC_QUERY_DV_PRESET: - case VIDIOC_S_DV_TIMINGS: - case VIDIOC_G_DV_TIMINGS: - case VIDIOC_DQEVENT: - case VIDIOC_SUBSCRIBE_EVENT: - case VIDIOC_UNSUBSCRIBE_EVENT: - ret = do_video_ioctl(file, cmd, arg); - break; - - default: - printk(KERN_WARNING "compat_ioctl32: " - "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", - _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd); - break; - } - return ret; -} -EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32); -#endif - -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-ctrls.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-ctrls.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-ctrls.c 2011-03-24 07:51:37.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-ctrls.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1875 +0,0 @@ -/* - V4L2 controls framework implementation. - - Copyright (C) 2010 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 -#include -#include -#include -#include -#include - -/* Internal temporary helper struct, one for each v4l2_ext_control */ -struct ctrl_helper { - /* The control corresponding to the v4l2_ext_control ID field. */ - struct v4l2_ctrl *ctrl; - /* Used internally to mark whether this control was already - processed. */ - bool handled; -}; - -/* Returns NULL or a character pointer array containing the menu for - the given control ID. The pointer array ends with a NULL pointer. - An empty string signifies a menu entry that is invalid. This allows - drivers to disable certain options if it is not supported. */ -const char * const *v4l2_ctrl_get_menu(u32 id) -{ - static const char * const mpeg_audio_sampling_freq[] = { - "44.1 kHz", - "48 kHz", - "32 kHz", - NULL - }; - static const char * const mpeg_audio_encoding[] = { - "MPEG-1/2 Layer I", - "MPEG-1/2 Layer II", - "MPEG-1/2 Layer III", - "MPEG-2/4 AAC", - "AC-3", - NULL - }; - static const char * const mpeg_audio_l1_bitrate[] = { - "32 kbps", - "64 kbps", - "96 kbps", - "128 kbps", - "160 kbps", - "192 kbps", - "224 kbps", - "256 kbps", - "288 kbps", - "320 kbps", - "352 kbps", - "384 kbps", - "416 kbps", - "448 kbps", - NULL - }; - static const char * const mpeg_audio_l2_bitrate[] = { - "32 kbps", - "48 kbps", - "56 kbps", - "64 kbps", - "80 kbps", - "96 kbps", - "112 kbps", - "128 kbps", - "160 kbps", - "192 kbps", - "224 kbps", - "256 kbps", - "320 kbps", - "384 kbps", - NULL - }; - static const char * const mpeg_audio_l3_bitrate[] = { - "32 kbps", - "40 kbps", - "48 kbps", - "56 kbps", - "64 kbps", - "80 kbps", - "96 kbps", - "112 kbps", - "128 kbps", - "160 kbps", - "192 kbps", - "224 kbps", - "256 kbps", - "320 kbps", - NULL - }; - static const char * const mpeg_audio_ac3_bitrate[] = { - "32 kbps", - "40 kbps", - "48 kbps", - "56 kbps", - "64 kbps", - "80 kbps", - "96 kbps", - "112 kbps", - "128 kbps", - "160 kbps", - "192 kbps", - "224 kbps", - "256 kbps", - "320 kbps", - "384 kbps", - "448 kbps", - "512 kbps", - "576 kbps", - "640 kbps", - NULL - }; - static const char * const mpeg_audio_mode[] = { - "Stereo", - "Joint Stereo", - "Dual", - "Mono", - NULL - }; - static const char * const mpeg_audio_mode_extension[] = { - "Bound 4", - "Bound 8", - "Bound 12", - "Bound 16", - NULL - }; - static const char * const mpeg_audio_emphasis[] = { - "No Emphasis", - "50/15 us", - "CCITT J17", - NULL - }; - static const char * const mpeg_audio_crc[] = { - "No CRC", - "16-bit CRC", - NULL - }; - static const char * const mpeg_video_encoding[] = { - "MPEG-1", - "MPEG-2", - "MPEG-4 AVC", - NULL - }; - static const char * const mpeg_video_aspect[] = { - "1x1", - "4x3", - "16x9", - "2.21x1", - NULL - }; - static const char * const mpeg_video_bitrate_mode[] = { - "Variable Bitrate", - "Constant Bitrate", - NULL - }; - static const char * const mpeg_stream_type[] = { - "MPEG-2 Program Stream", - "MPEG-2 Transport Stream", - "MPEG-1 System Stream", - "MPEG-2 DVD-compatible Stream", - "MPEG-1 VCD-compatible Stream", - "MPEG-2 SVCD-compatible Stream", - NULL - }; - static const char * const mpeg_stream_vbi_fmt[] = { - "No VBI", - "Private packet, IVTV format", - NULL - }; - static const char * const camera_power_line_frequency[] = { - "Disabled", - "50 Hz", - "60 Hz", - NULL - }; - static const char * const camera_exposure_auto[] = { - "Auto Mode", - "Manual Mode", - "Shutter Priority Mode", - "Aperture Priority Mode", - NULL - }; - static const char * const colorfx[] = { - "None", - "Black & White", - "Sepia", - "Negative", - "Emboss", - "Sketch", - "Sky blue", - "Grass green", - "Skin whiten", - "Vivid", - NULL - }; - static const char * const tune_preemphasis[] = { - "No preemphasis", - "50 useconds", - "75 useconds", - NULL, - }; - - switch (id) { - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - return mpeg_audio_sampling_freq; - case V4L2_CID_MPEG_AUDIO_ENCODING: - return mpeg_audio_encoding; - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: - return mpeg_audio_l1_bitrate; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - return mpeg_audio_l2_bitrate; - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: - return mpeg_audio_l3_bitrate; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - return mpeg_audio_ac3_bitrate; - case V4L2_CID_MPEG_AUDIO_MODE: - return mpeg_audio_mode; - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - return mpeg_audio_mode_extension; - case V4L2_CID_MPEG_AUDIO_EMPHASIS: - return mpeg_audio_emphasis; - case V4L2_CID_MPEG_AUDIO_CRC: - return mpeg_audio_crc; - case V4L2_CID_MPEG_VIDEO_ENCODING: - return mpeg_video_encoding; - case V4L2_CID_MPEG_VIDEO_ASPECT: - return mpeg_video_aspect; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - return mpeg_video_bitrate_mode; - case V4L2_CID_MPEG_STREAM_TYPE: - return mpeg_stream_type; - case V4L2_CID_MPEG_STREAM_VBI_FMT: - return mpeg_stream_vbi_fmt; - case V4L2_CID_POWER_LINE_FREQUENCY: - return camera_power_line_frequency; - case V4L2_CID_EXPOSURE_AUTO: - return camera_exposure_auto; - case V4L2_CID_COLORFX: - return colorfx; - case V4L2_CID_TUNE_PREEMPHASIS: - return tune_preemphasis; - default: - return NULL; - } -} -EXPORT_SYMBOL(v4l2_ctrl_get_menu); - -/* Return the control name. */ -const char *v4l2_ctrl_get_name(u32 id) -{ - switch (id) { - /* USER controls */ - /* Keep the order of the 'case's the same as in videodev2.h! */ - case V4L2_CID_USER_CLASS: return "User Controls"; - case V4L2_CID_BRIGHTNESS: return "Brightness"; - case V4L2_CID_CONTRAST: return "Contrast"; - case V4L2_CID_SATURATION: return "Saturation"; - case V4L2_CID_HUE: return "Hue"; - case V4L2_CID_AUDIO_VOLUME: return "Volume"; - case V4L2_CID_AUDIO_BALANCE: return "Balance"; - case V4L2_CID_AUDIO_BASS: return "Bass"; - case V4L2_CID_AUDIO_TREBLE: return "Treble"; - case V4L2_CID_AUDIO_MUTE: return "Mute"; - case V4L2_CID_AUDIO_LOUDNESS: return "Loudness"; - case V4L2_CID_BLACK_LEVEL: return "Black Level"; - case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic"; - case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance"; - case V4L2_CID_RED_BALANCE: return "Red Balance"; - case V4L2_CID_BLUE_BALANCE: return "Blue Balance"; - case V4L2_CID_GAMMA: return "Gamma"; - case V4L2_CID_EXPOSURE: return "Exposure"; - case V4L2_CID_AUTOGAIN: return "Gain, Automatic"; - case V4L2_CID_GAIN: return "Gain"; - case V4L2_CID_HFLIP: return "Horizontal Flip"; - case V4L2_CID_VFLIP: return "Vertical Flip"; - case V4L2_CID_HCENTER: return "Horizontal Center"; - case V4L2_CID_VCENTER: return "Vertical Center"; - case V4L2_CID_POWER_LINE_FREQUENCY: return "Power Line Frequency"; - case V4L2_CID_HUE_AUTO: return "Hue, Automatic"; - case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature"; - case V4L2_CID_SHARPNESS: return "Sharpness"; - case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation"; - case V4L2_CID_CHROMA_AGC: return "Chroma AGC"; - case V4L2_CID_COLOR_KILLER: return "Color Killer"; - case V4L2_CID_COLORFX: return "Color Effects"; - case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic"; - case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter"; - case V4L2_CID_ROTATE: return "Rotate"; - case V4L2_CID_BG_COLOR: return "Background Color"; - case V4L2_CID_CHROMA_GAIN: return "Chroma Gain"; - case V4L2_CID_ILLUMINATORS_1: return "Illuminator 1"; - case V4L2_CID_ILLUMINATORS_2: return "Illuminator 2"; - - /* MPEG controls */ - /* Keep the order of the 'case's the same as in videodev2.h! */ - case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls"; - case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type"; - case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID"; - case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID"; - case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID"; - case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID"; - case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID"; - case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID"; - case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format"; - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency"; - case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding"; - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate"; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate"; - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate"; - case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode"; - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension"; - case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis"; - case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC"; - case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute"; - case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate"; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate"; - case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding"; - case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect"; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames"; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size"; - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure"; - case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown"; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode"; - case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate"; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate"; - case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation"; - case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute"; - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV"; - - /* CAMERA controls */ - /* Keep the order of the 'case's the same as in videodev2.h! */ - case V4L2_CID_CAMERA_CLASS: return "Camera Controls"; - case V4L2_CID_EXPOSURE_AUTO: return "Auto Exposure"; - case V4L2_CID_EXPOSURE_ABSOLUTE: return "Exposure Time, Absolute"; - case V4L2_CID_EXPOSURE_AUTO_PRIORITY: return "Exposure, Dynamic Framerate"; - case V4L2_CID_PAN_RELATIVE: return "Pan, Relative"; - case V4L2_CID_TILT_RELATIVE: return "Tilt, Relative"; - case V4L2_CID_PAN_RESET: return "Pan, Reset"; - case V4L2_CID_TILT_RESET: return "Tilt, Reset"; - case V4L2_CID_PAN_ABSOLUTE: return "Pan, Absolute"; - case V4L2_CID_TILT_ABSOLUTE: return "Tilt, Absolute"; - case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute"; - case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative"; - case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic"; - case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute"; - case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative"; - case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous"; - case V4L2_CID_PRIVACY: return "Privacy"; - case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute"; - case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative"; - - /* FM Radio Modulator control */ - /* Keep the order of the 'case's the same as in videodev2.h! */ - case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls"; - case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation"; - case V4L2_CID_RDS_TX_PI: return "RDS Program ID"; - case V4L2_CID_RDS_TX_PTY: return "RDS Program Type"; - case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name"; - case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text"; - case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled"; - case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time"; - case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation"; - case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled"; - case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain"; - case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold"; - case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time"; - case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time"; - case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled"; - case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation"; - case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency"; - case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings"; - case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level"; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor"; - - default: - return NULL; - } -} -EXPORT_SYMBOL(v4l2_ctrl_get_name); - -void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, - s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags) -{ - *name = v4l2_ctrl_get_name(id); - *flags = 0; - - switch (id) { - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_LOUDNESS: - case V4L2_CID_AUTO_WHITE_BALANCE: - case V4L2_CID_AUTOGAIN: - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - case V4L2_CID_HUE_AUTO: - case V4L2_CID_CHROMA_AGC: - case V4L2_CID_COLOR_KILLER: - case V4L2_CID_MPEG_AUDIO_MUTE: - case V4L2_CID_MPEG_VIDEO_MUTE: - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - case V4L2_CID_MPEG_VIDEO_PULLDOWN: - case V4L2_CID_EXPOSURE_AUTO_PRIORITY: - case V4L2_CID_FOCUS_AUTO: - case V4L2_CID_PRIVACY: - case V4L2_CID_AUDIO_LIMITER_ENABLED: - case V4L2_CID_AUDIO_COMPRESSION_ENABLED: - case V4L2_CID_PILOT_TONE_ENABLED: - case V4L2_CID_ILLUMINATORS_1: - case V4L2_CID_ILLUMINATORS_2: - *type = V4L2_CTRL_TYPE_BOOLEAN; - *min = 0; - *max = *step = 1; - break; - case V4L2_CID_PAN_RESET: - case V4L2_CID_TILT_RESET: - *type = V4L2_CTRL_TYPE_BUTTON; - *flags |= V4L2_CTRL_FLAG_WRITE_ONLY; - *min = *max = *step = *def = 0; - break; - case V4L2_CID_POWER_LINE_FREQUENCY: - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - case V4L2_CID_MPEG_AUDIO_ENCODING: - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - case V4L2_CID_MPEG_AUDIO_MODE: - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - case V4L2_CID_MPEG_AUDIO_EMPHASIS: - case V4L2_CID_MPEG_AUDIO_CRC: - case V4L2_CID_MPEG_VIDEO_ENCODING: - case V4L2_CID_MPEG_VIDEO_ASPECT: - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - case V4L2_CID_MPEG_STREAM_TYPE: - case V4L2_CID_MPEG_STREAM_VBI_FMT: - case V4L2_CID_EXPOSURE_AUTO: - case V4L2_CID_COLORFX: - case V4L2_CID_TUNE_PREEMPHASIS: - *type = V4L2_CTRL_TYPE_MENU; - break; - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - *type = V4L2_CTRL_TYPE_STRING; - break; - case V4L2_CID_USER_CLASS: - case V4L2_CID_CAMERA_CLASS: - case V4L2_CID_MPEG_CLASS: - case V4L2_CID_FM_TX_CLASS: - *type = V4L2_CTRL_TYPE_CTRL_CLASS; - /* You can neither read not write these */ - *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; - *min = *max = *step = *def = 0; - break; - case V4L2_CID_BG_COLOR: - *type = V4L2_CTRL_TYPE_INTEGER; - *step = 1; - *min = 0; - /* Max is calculated as RGB888 that is 2^24 */ - *max = 0xFFFFFF; - break; - default: - *type = V4L2_CTRL_TYPE_INTEGER; - break; - } - switch (id) { - case V4L2_CID_MPEG_AUDIO_ENCODING: - case V4L2_CID_MPEG_AUDIO_MODE: - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - case V4L2_CID_MPEG_STREAM_TYPE: - *flags |= V4L2_CTRL_FLAG_UPDATE; - break; - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_CONTRAST: - case V4L2_CID_SATURATION: - case V4L2_CID_HUE: - case V4L2_CID_RED_BALANCE: - case V4L2_CID_BLUE_BALANCE: - case V4L2_CID_GAMMA: - case V4L2_CID_SHARPNESS: - case V4L2_CID_CHROMA_GAIN: - case V4L2_CID_RDS_TX_DEVIATION: - case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: - case V4L2_CID_AUDIO_LIMITER_DEVIATION: - case V4L2_CID_AUDIO_COMPRESSION_GAIN: - case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: - case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: - case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: - case V4L2_CID_PILOT_TONE_DEVIATION: - case V4L2_CID_PILOT_TONE_FREQUENCY: - case V4L2_CID_TUNE_POWER_LEVEL: - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - *flags |= V4L2_CTRL_FLAG_SLIDER; - break; - case V4L2_CID_PAN_RELATIVE: - case V4L2_CID_TILT_RELATIVE: - case V4L2_CID_FOCUS_RELATIVE: - case V4L2_CID_IRIS_RELATIVE: - case V4L2_CID_ZOOM_RELATIVE: - *flags |= V4L2_CTRL_FLAG_WRITE_ONLY; - break; - } -} -EXPORT_SYMBOL(v4l2_ctrl_fill); - -/* Helper function to determine whether the control type is compatible with - VIDIOC_G/S_CTRL. */ -static bool type_is_int(const struct v4l2_ctrl *ctrl) -{ - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER64: - case V4L2_CTRL_TYPE_STRING: - /* Nope, these need v4l2_ext_control */ - return false; - default: - return true; - } -} - -/* Helper function: copy the current control value back to the caller */ -static int cur_to_user(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl) -{ - u32 len; - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_STRING: - len = strlen(ctrl->cur.string); - if (c->size < len + 1) { - c->size = len + 1; - return -ENOSPC; - } - return copy_to_user(c->string, ctrl->cur.string, - len + 1) ? -EFAULT : 0; - case V4L2_CTRL_TYPE_INTEGER64: - c->value64 = ctrl->cur.val64; - break; - default: - c->value = ctrl->cur.val; - break; - } - return 0; -} - -/* Helper function: copy the caller-provider value as the new control value */ -static int user_to_new(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl) -{ - int ret; - u32 size; - - ctrl->is_new = 1; - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER64: - ctrl->val64 = c->value64; - break; - case V4L2_CTRL_TYPE_STRING: - size = c->size; - if (size == 0) - return -ERANGE; - if (size > ctrl->maximum + 1) - size = ctrl->maximum + 1; - ret = copy_from_user(ctrl->string, c->string, size); - if (!ret) { - char last = ctrl->string[size - 1]; - - ctrl->string[size - 1] = 0; - /* If the string was longer than ctrl->maximum, - then return an error. */ - if (strlen(ctrl->string) == ctrl->maximum && last) - return -ERANGE; - } - return ret ? -EFAULT : 0; - default: - ctrl->val = c->value; - break; - } - return 0; -} - -/* Helper function: copy the new control value back to the caller */ -static int new_to_user(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl) -{ - u32 len; - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_STRING: - len = strlen(ctrl->string); - if (c->size < len + 1) { - c->size = ctrl->maximum + 1; - return -ENOSPC; - } - return copy_to_user(c->string, ctrl->string, - len + 1) ? -EFAULT : 0; - case V4L2_CTRL_TYPE_INTEGER64: - c->value64 = ctrl->val64; - break; - default: - c->value = ctrl->val; - break; - } - return 0; -} - -/* Copy the new value to the current value. */ -static void new_to_cur(struct v4l2_ctrl *ctrl) -{ - if (ctrl == NULL) - return; - switch (ctrl->type) { - case V4L2_CTRL_TYPE_STRING: - /* strings are always 0-terminated */ - strcpy(ctrl->cur.string, ctrl->string); - break; - case V4L2_CTRL_TYPE_INTEGER64: - ctrl->cur.val64 = ctrl->val64; - break; - default: - ctrl->cur.val = ctrl->val; - break; - } -} - -/* Copy the current value to the new value */ -static void cur_to_new(struct v4l2_ctrl *ctrl) -{ - if (ctrl == NULL) - return; - switch (ctrl->type) { - case V4L2_CTRL_TYPE_STRING: - /* strings are always 0-terminated */ - strcpy(ctrl->string, ctrl->cur.string); - break; - case V4L2_CTRL_TYPE_INTEGER64: - ctrl->val64 = ctrl->cur.val64; - break; - default: - ctrl->val = ctrl->cur.val; - break; - } -} - -/* Return non-zero if one or more of the controls in the cluster has a new - value that differs from the current value. */ -static int cluster_changed(struct v4l2_ctrl *master) -{ - int diff = 0; - int i; - - for (i = 0; !diff && i < master->ncontrols; i++) { - struct v4l2_ctrl *ctrl = master->cluster[i]; - - if (ctrl == NULL) - continue; - switch (ctrl->type) { - case V4L2_CTRL_TYPE_BUTTON: - /* Button controls are always 'different' */ - return 1; - case V4L2_CTRL_TYPE_STRING: - /* strings are always 0-terminated */ - diff = strcmp(ctrl->string, ctrl->cur.string); - break; - case V4L2_CTRL_TYPE_INTEGER64: - diff = ctrl->val64 != ctrl->cur.val64; - break; - default: - diff = ctrl->val != ctrl->cur.val; - break; - } - } - return diff; -} - -/* Validate a new control */ -static int validate_new(struct v4l2_ctrl *ctrl) -{ - s32 val = ctrl->val; - char *s = ctrl->string; - u32 offset; - size_t len; - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - /* Round towards the closest legal value */ - val += ctrl->step / 2; - if (val < ctrl->minimum) - val = ctrl->minimum; - if (val > ctrl->maximum) - val = ctrl->maximum; - offset = val - ctrl->minimum; - offset = ctrl->step * (offset / ctrl->step); - val = ctrl->minimum + offset; - ctrl->val = val; - return 0; - - case V4L2_CTRL_TYPE_BOOLEAN: - ctrl->val = !!ctrl->val; - return 0; - - case V4L2_CTRL_TYPE_MENU: - if (val < ctrl->minimum || val > ctrl->maximum) - return -ERANGE; - if (ctrl->qmenu[val][0] == '\0' || - (ctrl->menu_skip_mask & (1 << val))) - return -EINVAL; - return 0; - - case V4L2_CTRL_TYPE_BUTTON: - case V4L2_CTRL_TYPE_CTRL_CLASS: - ctrl->val64 = 0; - return 0; - - case V4L2_CTRL_TYPE_INTEGER64: - return 0; - - case V4L2_CTRL_TYPE_STRING: - len = strlen(s); - if (len < ctrl->minimum) - return -ERANGE; - if ((len - ctrl->minimum) % ctrl->step) - return -ERANGE; - return 0; - - default: - return -EINVAL; - } -} - -static inline u32 node2id(struct list_head *node) -{ - return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id; -} - -/* Set the handler's error code if it wasn't set earlier already */ -static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err) -{ - if (hdl->error == 0) - hdl->error = err; - return err; -} - -/* Initialize the handler */ -int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, - unsigned nr_of_controls_hint) -{ - mutex_init(&hdl->lock); - INIT_LIST_HEAD(&hdl->ctrls); - INIT_LIST_HEAD(&hdl->ctrl_refs); - hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; - hdl->buckets = kzalloc(sizeof(hdl->buckets[0]) * hdl->nr_of_buckets, - GFP_KERNEL); - hdl->error = hdl->buckets ? 0 : -ENOMEM; - return hdl->error; -} -EXPORT_SYMBOL(v4l2_ctrl_handler_init); - -/* Free all controls and control refs */ -void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) -{ - struct v4l2_ctrl_ref *ref, *next_ref; - struct v4l2_ctrl *ctrl, *next_ctrl; - - if (hdl == NULL || hdl->buckets == NULL) - return; - - mutex_lock(&hdl->lock); - /* Free all nodes */ - list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) { - list_del(&ref->node); - kfree(ref); - } - /* Free all controls owned by the handler */ - list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) { - list_del(&ctrl->node); - kfree(ctrl); - } - kfree(hdl->buckets); - hdl->buckets = NULL; - hdl->cached = NULL; - hdl->error = 0; - mutex_unlock(&hdl->lock); -} -EXPORT_SYMBOL(v4l2_ctrl_handler_free); - -/* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer - be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing - with applications that do not use the NEXT_CTRL flag. - - We just find the n-th private user control. It's O(N), but that should not - be an issue in this particular case. */ -static struct v4l2_ctrl_ref *find_private_ref( - struct v4l2_ctrl_handler *hdl, u32 id) -{ - struct v4l2_ctrl_ref *ref; - - id -= V4L2_CID_PRIVATE_BASE; - list_for_each_entry(ref, &hdl->ctrl_refs, node) { - /* Search for private user controls that are compatible with - VIDIOC_G/S_CTRL. */ - if (V4L2_CTRL_ID2CLASS(ref->ctrl->id) == V4L2_CTRL_CLASS_USER && - V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) { - if (!type_is_int(ref->ctrl)) - continue; - if (id == 0) - return ref; - id--; - } - } - return NULL; -} - -/* Find a control with the given ID. */ -static struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id) -{ - struct v4l2_ctrl_ref *ref; - int bucket; - - id &= V4L2_CTRL_ID_MASK; - - /* Old-style private controls need special handling */ - if (id >= V4L2_CID_PRIVATE_BASE) - return find_private_ref(hdl, id); - bucket = id % hdl->nr_of_buckets; - - /* Simple optimization: cache the last control found */ - if (hdl->cached && hdl->cached->ctrl->id == id) - return hdl->cached; - - /* Not in cache, search the hash */ - ref = hdl->buckets ? hdl->buckets[bucket] : NULL; - while (ref && ref->ctrl->id != id) - ref = ref->next; - - if (ref) - hdl->cached = ref; /* cache it! */ - return ref; -} - -/* Find a control with the given ID. Take the handler's lock first. */ -static struct v4l2_ctrl_ref *find_ref_lock( - struct v4l2_ctrl_handler *hdl, u32 id) -{ - struct v4l2_ctrl_ref *ref = NULL; - - if (hdl) { - mutex_lock(&hdl->lock); - ref = find_ref(hdl, id); - mutex_unlock(&hdl->lock); - } - return ref; -} - -/* Find a control with the given ID. */ -struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id) -{ - struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id); - - return ref ? ref->ctrl : NULL; -} -EXPORT_SYMBOL(v4l2_ctrl_find); - -/* Allocate a new v4l2_ctrl_ref and hook it into the handler. */ -static int handler_new_ref(struct v4l2_ctrl_handler *hdl, - struct v4l2_ctrl *ctrl) -{ - struct v4l2_ctrl_ref *ref; - struct v4l2_ctrl_ref *new_ref; - u32 id = ctrl->id; - u32 class_ctrl = V4L2_CTRL_ID2CLASS(id) | 1; - int bucket = id % hdl->nr_of_buckets; /* which bucket to use */ - - /* Automatically add the control class if it is not yet present. */ - if (id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL) - if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0)) - return hdl->error; - - if (hdl->error) - return hdl->error; - - new_ref = kzalloc(sizeof(*new_ref), GFP_KERNEL); - if (!new_ref) - return handler_set_err(hdl, -ENOMEM); - new_ref->ctrl = ctrl; - if (ctrl->handler == hdl) { - /* By default each control starts in a cluster of its own. - new_ref->ctrl is basically a cluster array with one - element, so that's perfect to use as the cluster pointer. - But only do this for the handler that owns the control. */ - ctrl->cluster = &new_ref->ctrl; - ctrl->ncontrols = 1; - } - - INIT_LIST_HEAD(&new_ref->node); - - mutex_lock(&hdl->lock); - - /* Add immediately at the end of the list if the list is empty, or if - the last element in the list has a lower ID. - This ensures that when elements are added in ascending order the - insertion is an O(1) operation. */ - if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) { - list_add_tail(&new_ref->node, &hdl->ctrl_refs); - goto insert_in_hash; - } - - /* Find insert position in sorted list */ - list_for_each_entry(ref, &hdl->ctrl_refs, node) { - if (ref->ctrl->id < id) - continue; - /* Don't add duplicates */ - if (ref->ctrl->id == id) { - kfree(new_ref); - goto unlock; - } - list_add(&new_ref->node, ref->node.prev); - break; - } - -insert_in_hash: - /* Insert the control node in the hash */ - new_ref->next = hdl->buckets[bucket]; - hdl->buckets[bucket] = new_ref; - -unlock: - mutex_unlock(&hdl->lock); - return 0; -} - -/* Add a new control */ -static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, - u32 id, const char *name, enum v4l2_ctrl_type type, - s32 min, s32 max, u32 step, s32 def, - u32 flags, const char * const *qmenu, void *priv) -{ - struct v4l2_ctrl *ctrl; - unsigned sz_extra = 0; - - if (hdl->error) - return NULL; - - /* Sanity checks */ - if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE || - max < min || - (type == V4L2_CTRL_TYPE_INTEGER && step == 0) || - (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) || - (type == V4L2_CTRL_TYPE_STRING && max == 0)) { - handler_set_err(hdl, -ERANGE); - return NULL; - } - if ((type == V4L2_CTRL_TYPE_INTEGER || - type == V4L2_CTRL_TYPE_MENU || - type == V4L2_CTRL_TYPE_BOOLEAN) && - (def < min || def > max)) { - handler_set_err(hdl, -ERANGE); - return NULL; - } - - if (type == V4L2_CTRL_TYPE_BUTTON) - flags |= V4L2_CTRL_FLAG_WRITE_ONLY; - else if (type == V4L2_CTRL_TYPE_CTRL_CLASS) - flags |= V4L2_CTRL_FLAG_READ_ONLY; - else if (type == V4L2_CTRL_TYPE_STRING) - sz_extra += 2 * (max + 1); - - ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL); - if (ctrl == NULL) { - handler_set_err(hdl, -ENOMEM); - return NULL; - } - - INIT_LIST_HEAD(&ctrl->node); - ctrl->handler = hdl; - ctrl->ops = ops; - ctrl->id = id; - ctrl->name = name; - ctrl->type = type; - ctrl->flags = flags; - ctrl->minimum = min; - ctrl->maximum = max; - ctrl->step = step; - ctrl->qmenu = qmenu; - ctrl->priv = priv; - ctrl->cur.val = ctrl->val = ctrl->default_value = def; - - if (ctrl->type == V4L2_CTRL_TYPE_STRING) { - ctrl->cur.string = (char *)&ctrl[1] + sz_extra - (max + 1); - ctrl->string = (char *)&ctrl[1] + sz_extra - 2 * (max + 1); - if (ctrl->minimum) - memset(ctrl->cur.string, ' ', ctrl->minimum); - } - if (handler_new_ref(hdl, ctrl)) { - kfree(ctrl); - return NULL; - } - mutex_lock(&hdl->lock); - list_add_tail(&ctrl->node, &hdl->ctrls); - mutex_unlock(&hdl->lock); - return ctrl; -} - -struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_config *cfg, void *priv) -{ - bool is_menu; - struct v4l2_ctrl *ctrl; - const char *name = cfg->name; - const char * const *qmenu = cfg->qmenu; - enum v4l2_ctrl_type type = cfg->type; - u32 flags = cfg->flags; - s32 min = cfg->min; - s32 max = cfg->max; - u32 step = cfg->step; - s32 def = cfg->def; - - if (name == NULL) - v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step, - &def, &flags); - - is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU); - if (is_menu) - WARN_ON(step); - else - WARN_ON(cfg->menu_skip_mask); - if (is_menu && qmenu == NULL) - qmenu = v4l2_ctrl_get_menu(cfg->id); - - ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name, - type, min, max, - is_menu ? cfg->menu_skip_mask : step, - def, flags, qmenu, priv); - if (ctrl) { - ctrl->is_private = cfg->is_private; - ctrl->is_volatile = cfg->is_volatile; - } - return ctrl; -} -EXPORT_SYMBOL(v4l2_ctrl_new_custom); - -/* Helper function for standard non-menu controls */ -struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, - u32 id, s32 min, s32 max, u32 step, s32 def) -{ - const char *name; - enum v4l2_ctrl_type type; - u32 flags; - - v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); - if (type == V4L2_CTRL_TYPE_MENU) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - return v4l2_ctrl_new(hdl, ops, id, name, type, - min, max, step, def, flags, NULL, NULL); -} -EXPORT_SYMBOL(v4l2_ctrl_new_std); - -/* Helper function for standard menu controls */ -struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, - u32 id, s32 max, s32 mask, s32 def) -{ - const char * const *qmenu = v4l2_ctrl_get_menu(id); - const char *name; - enum v4l2_ctrl_type type; - s32 min; - s32 step; - u32 flags; - - v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); - if (type != V4L2_CTRL_TYPE_MENU) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - return v4l2_ctrl_new(hdl, ops, id, name, type, - 0, max, mask, def, flags, qmenu, NULL); -} -EXPORT_SYMBOL(v4l2_ctrl_new_std_menu); - -/* Add a control from another handler to this handler */ -struct v4l2_ctrl *v4l2_ctrl_add_ctrl(struct v4l2_ctrl_handler *hdl, - struct v4l2_ctrl *ctrl) -{ - if (hdl == NULL || hdl->error) - return NULL; - if (ctrl == NULL) { - handler_set_err(hdl, -EINVAL); - return NULL; - } - if (ctrl->handler == hdl) - return ctrl; - return handler_new_ref(hdl, ctrl) ? NULL : ctrl; -} -EXPORT_SYMBOL(v4l2_ctrl_add_ctrl); - -/* Add the controls from another handler to our own. */ -int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, - struct v4l2_ctrl_handler *add) -{ - struct v4l2_ctrl *ctrl; - int ret = 0; - - /* Do nothing if either handler is NULL or if they are the same */ - if (!hdl || !add || hdl == add) - return 0; - if (hdl->error) - return hdl->error; - mutex_lock(&add->lock); - list_for_each_entry(ctrl, &add->ctrls, node) { - /* Skip handler-private controls. */ - if (ctrl->is_private) - continue; - ret = handler_new_ref(hdl, ctrl); - if (ret) - break; - } - mutex_unlock(&add->lock); - return ret; -} -EXPORT_SYMBOL(v4l2_ctrl_add_handler); - -/* Cluster controls */ -void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls) -{ - int i; - - /* The first control is the master control and it must not be NULL */ - BUG_ON(controls[0] == NULL); - - for (i = 0; i < ncontrols; i++) { - if (controls[i]) { - controls[i]->cluster = controls; - controls[i]->ncontrols = ncontrols; - } - } -} -EXPORT_SYMBOL(v4l2_ctrl_cluster); - -/* Activate/deactivate a control. */ -void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active) -{ - if (ctrl == NULL) - return; - - if (!active) - /* set V4L2_CTRL_FLAG_INACTIVE */ - set_bit(4, &ctrl->flags); - else - /* clear V4L2_CTRL_FLAG_INACTIVE */ - clear_bit(4, &ctrl->flags); -} -EXPORT_SYMBOL(v4l2_ctrl_activate); - -/* Grab/ungrab a control. - Typically used when streaming starts and you want to grab controls, - preventing the user from changing them. - - Just call this and the framework will block any attempts to change - these controls. */ -void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed) -{ - if (ctrl == NULL) - return; - - if (grabbed) - /* set V4L2_CTRL_FLAG_GRABBED */ - set_bit(1, &ctrl->flags); - else - /* clear V4L2_CTRL_FLAG_GRABBED */ - clear_bit(1, &ctrl->flags); -} -EXPORT_SYMBOL(v4l2_ctrl_grab); - -/* Log the control name and value */ -static void log_ctrl(const struct v4l2_ctrl *ctrl, - const char *prefix, const char *colon) -{ - int fl_inact = ctrl->flags & V4L2_CTRL_FLAG_INACTIVE; - int fl_grabbed = ctrl->flags & V4L2_CTRL_FLAG_GRABBED; - - if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY)) - return; - if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) - return; - - printk(KERN_INFO "%s%s%s: ", prefix, colon, ctrl->name); - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - printk(KERN_CONT "%d", ctrl->cur.val); - break; - case V4L2_CTRL_TYPE_BOOLEAN: - printk(KERN_CONT "%s", ctrl->cur.val ? "true" : "false"); - break; - case V4L2_CTRL_TYPE_MENU: - printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]); - break; - case V4L2_CTRL_TYPE_INTEGER64: - printk(KERN_CONT "%lld", ctrl->cur.val64); - break; - case V4L2_CTRL_TYPE_STRING: - printk(KERN_CONT "%s", ctrl->cur.string); - break; - default: - printk(KERN_CONT "unknown type %d", ctrl->type); - break; - } - if (fl_inact && fl_grabbed) - printk(KERN_CONT " (inactive, grabbed)\n"); - else if (fl_inact) - printk(KERN_CONT " (inactive)\n"); - else if (fl_grabbed) - printk(KERN_CONT " (grabbed)\n"); - else - printk(KERN_CONT "\n"); -} - -/* Log all controls owned by the handler */ -void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl, - const char *prefix) -{ - struct v4l2_ctrl *ctrl; - const char *colon = ""; - int len; - - if (hdl == NULL) - return; - if (prefix == NULL) - prefix = ""; - len = strlen(prefix); - if (len && prefix[len - 1] != ' ') - colon = ": "; - mutex_lock(&hdl->lock); - list_for_each_entry(ctrl, &hdl->ctrls, node) - if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED)) - log_ctrl(ctrl, prefix, colon); - mutex_unlock(&hdl->lock); -} -EXPORT_SYMBOL(v4l2_ctrl_handler_log_status); - -/* Call s_ctrl for all controls owned by the handler */ -int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl) -{ - struct v4l2_ctrl *ctrl; - int ret = 0; - - if (hdl == NULL) - return 0; - mutex_lock(&hdl->lock); - list_for_each_entry(ctrl, &hdl->ctrls, node) - ctrl->done = false; - - list_for_each_entry(ctrl, &hdl->ctrls, node) { - struct v4l2_ctrl *master = ctrl->cluster[0]; - int i; - - /* Skip if this control was already handled by a cluster. */ - if (ctrl->done) - continue; - - for (i = 0; i < master->ncontrols; i++) { - if (master->cluster[i]) { - cur_to_new(master->cluster[i]); - master->cluster[i]->is_new = 1; - } - } - - /* Skip button controls and read-only controls. */ - if (ctrl->type == V4L2_CTRL_TYPE_BUTTON || - (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)) - continue; - ret = master->ops->s_ctrl(master); - if (ret) - break; - for (i = 0; i < master->ncontrols; i++) - if (master->cluster[i]) - master->cluster[i]->done = true; - } - mutex_unlock(&hdl->lock); - return ret; -} -EXPORT_SYMBOL(v4l2_ctrl_handler_setup); - -/* Implement VIDIOC_QUERYCTRL */ -int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc) -{ - u32 id = qc->id & V4L2_CTRL_ID_MASK; - struct v4l2_ctrl_ref *ref; - struct v4l2_ctrl *ctrl; - - if (hdl == NULL) - return -EINVAL; - - mutex_lock(&hdl->lock); - - /* Try to find it */ - ref = find_ref(hdl, id); - - if ((qc->id & V4L2_CTRL_FLAG_NEXT_CTRL) && !list_empty(&hdl->ctrl_refs)) { - /* Find the next control with ID > qc->id */ - - /* Did we reach the end of the control list? */ - if (id >= node2id(hdl->ctrl_refs.prev)) { - ref = NULL; /* Yes, so there is no next control */ - } else if (ref) { - /* We found a control with the given ID, so just get - the next one in the list. */ - ref = list_entry(ref->node.next, typeof(*ref), node); - } else { - /* No control with the given ID exists, so start - searching for the next largest ID. We know there - is one, otherwise the first 'if' above would have - been true. */ - list_for_each_entry(ref, &hdl->ctrl_refs, node) - if (id < ref->ctrl->id) - break; - } - } - mutex_unlock(&hdl->lock); - if (!ref) - return -EINVAL; - - ctrl = ref->ctrl; - memset(qc, 0, sizeof(*qc)); - if (id >= V4L2_CID_PRIVATE_BASE) - qc->id = id; - else - qc->id = ctrl->id; - strlcpy(qc->name, ctrl->name, sizeof(qc->name)); - qc->minimum = ctrl->minimum; - qc->maximum = ctrl->maximum; - qc->default_value = ctrl->default_value; - if (ctrl->type == V4L2_CTRL_TYPE_MENU) - qc->step = 1; - else - qc->step = ctrl->step; - qc->flags = ctrl->flags; - qc->type = ctrl->type; - return 0; -} -EXPORT_SYMBOL(v4l2_queryctrl); - -int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - if (qc->id & V4L2_CTRL_FLAG_NEXT_CTRL) - return -EINVAL; - return v4l2_queryctrl(sd->ctrl_handler, qc); -} -EXPORT_SYMBOL(v4l2_subdev_queryctrl); - -/* Implement VIDIOC_QUERYMENU */ -int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm) -{ - struct v4l2_ctrl *ctrl; - u32 i = qm->index; - - ctrl = v4l2_ctrl_find(hdl, qm->id); - if (!ctrl) - return -EINVAL; - - qm->reserved = 0; - /* Sanity checks */ - if (ctrl->qmenu == NULL || - i < ctrl->minimum || i > ctrl->maximum) - return -EINVAL; - /* Use mask to see if this menu item should be skipped */ - if (ctrl->menu_skip_mask & (1 << i)) - return -EINVAL; - /* Empty menu items should also be skipped */ - if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0') - return -EINVAL; - strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name)); - return 0; -} -EXPORT_SYMBOL(v4l2_querymenu); - -int v4l2_subdev_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm) -{ - return v4l2_querymenu(sd->ctrl_handler, qm); -} -EXPORT_SYMBOL(v4l2_subdev_querymenu); - - - -/* Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS: - - It is not a fully atomic operation, just best-effort only. After all, if - multiple controls have to be set through multiple i2c writes (for example) - then some initial writes may succeed while others fail. Thus leaving the - system in an inconsistent state. The question is how much effort you are - willing to spend on trying to make something atomic that really isn't. - - From the point of view of an application the main requirement is that - when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an - error should be returned without actually affecting any controls. - - If all the values are correct, then it is acceptable to just give up - in case of low-level errors. - - It is important though that the application can tell when only a partial - configuration was done. The way we do that is through the error_idx field - of struct v4l2_ext_controls: if that is equal to the count field then no - controls were affected. Otherwise all controls before that index were - successful in performing their 'get' or 'set' operation, the control at - the given index failed, and you don't know what happened with the controls - after the failed one. Since if they were part of a control cluster they - could have been successfully processed (if a cluster member was encountered - at index < error_idx), they could have failed (if a cluster member was at - error_idx), or they may not have been processed yet (if the first cluster - member appeared after error_idx). - - It is all fairly theoretical, though. In practice all you can do is to - bail out. If error_idx == count, then it is an application bug. If - error_idx < count then it is only an application bug if the error code was - EBUSY. That usually means that something started streaming just when you - tried to set the controls. In all other cases it is a driver/hardware - problem and all you can do is to retry or bail out. - - Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that - never modifies controls the error_idx is just set to whatever control - has an invalid value. - */ - -/* Prepare for the extended g/s/try functions. - Find the controls in the control array and do some basic checks. */ -static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, - struct v4l2_ext_controls *cs, - struct ctrl_helper *helpers, - bool try) -{ - u32 i; - - for (i = 0; i < cs->count; i++) { - struct v4l2_ext_control *c = &cs->controls[i]; - struct v4l2_ctrl *ctrl; - u32 id = c->id & V4L2_CTRL_ID_MASK; - - if (try) - cs->error_idx = i; - - if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class) - return -EINVAL; - - /* Old-style private controls are not allowed for - extended controls */ - if (id >= V4L2_CID_PRIVATE_BASE) - return -EINVAL; - ctrl = v4l2_ctrl_find(hdl, id); - if (ctrl == NULL) - return -EINVAL; - if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) - return -EINVAL; - - helpers[i].ctrl = ctrl; - helpers[i].handled = false; - } - return 0; -} - -typedef int (*cluster_func)(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl); - -/* Walk over all controls in v4l2_ext_controls belonging to the same cluster - and call the provided function. */ -static int cluster_walk(unsigned from, - struct v4l2_ext_controls *cs, - struct ctrl_helper *helpers, - cluster_func f) -{ - struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster; - int ret = 0; - int i; - - /* Find any controls from the same cluster and call the function */ - for (i = from; !ret && i < cs->count; i++) { - struct v4l2_ctrl *ctrl = helpers[i].ctrl; - - if (!helpers[i].handled && ctrl->cluster == cluster) - ret = f(&cs->controls[i], ctrl); - } - return ret; -} - -static void cluster_done(unsigned from, - struct v4l2_ext_controls *cs, - struct ctrl_helper *helpers) -{ - struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster; - int i; - - /* Find any controls from the same cluster and mark them as handled */ - for (i = from; i < cs->count; i++) - if (helpers[i].ctrl->cluster == cluster) - helpers[i].handled = true; -} - -/* Handles the corner case where cs->count == 0. It checks whether the - specified control class exists. If that class ID is 0, then it checks - whether there are any controls at all. */ -static int class_check(struct v4l2_ctrl_handler *hdl, u32 ctrl_class) -{ - if (ctrl_class == 0) - return list_empty(&hdl->ctrl_refs) ? -EINVAL : 0; - return find_ref_lock(hdl, ctrl_class | 1) ? 0 : -EINVAL; -} - - - -/* Get extended controls. Allocates the helpers array if needed. */ -int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs) -{ - struct ctrl_helper helper[4]; - struct ctrl_helper *helpers = helper; - int ret; - int i; - - cs->error_idx = cs->count; - cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class); - - if (hdl == NULL) - return -EINVAL; - - if (cs->count == 0) - return class_check(hdl, cs->ctrl_class); - - if (cs->count > ARRAY_SIZE(helper)) { - helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL); - if (helpers == NULL) - return -ENOMEM; - } - - ret = prepare_ext_ctrls(hdl, cs, helpers, false); - - for (i = 0; !ret && i < cs->count; i++) - if (helpers[i].ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) - ret = -EACCES; - - for (i = 0; !ret && i < cs->count; i++) { - struct v4l2_ctrl *ctrl = helpers[i].ctrl; - struct v4l2_ctrl *master = ctrl->cluster[0]; - - if (helpers[i].handled) - continue; - - cs->error_idx = i; - - v4l2_ctrl_lock(master); - /* g_volatile_ctrl will update the current control values */ - if (ctrl->is_volatile && master->ops->g_volatile_ctrl) - ret = master->ops->g_volatile_ctrl(master); - /* If OK, then copy the current control values to the caller */ - if (!ret) - ret = cluster_walk(i, cs, helpers, cur_to_user); - v4l2_ctrl_unlock(master); - cluster_done(i, cs, helpers); - } - - if (cs->count > ARRAY_SIZE(helper)) - kfree(helpers); - return ret; -} -EXPORT_SYMBOL(v4l2_g_ext_ctrls); - -int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs) -{ - return v4l2_g_ext_ctrls(sd->ctrl_handler, cs); -} -EXPORT_SYMBOL(v4l2_subdev_g_ext_ctrls); - -/* Helper function to get a single control */ -static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val) -{ - struct v4l2_ctrl *master = ctrl->cluster[0]; - int ret = 0; - - if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) - return -EACCES; - - v4l2_ctrl_lock(master); - /* g_volatile_ctrl will update the current control values */ - if (ctrl->is_volatile && master->ops->g_volatile_ctrl) - ret = master->ops->g_volatile_ctrl(master); - *val = ctrl->cur.val; - v4l2_ctrl_unlock(master); - return ret; -} - -int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control) -{ - struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); - - if (ctrl == NULL || !type_is_int(ctrl)) - return -EINVAL; - return get_ctrl(ctrl, &control->value); -} -EXPORT_SYMBOL(v4l2_g_ctrl); - -int v4l2_subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control) -{ - return v4l2_g_ctrl(sd->ctrl_handler, control); -} -EXPORT_SYMBOL(v4l2_subdev_g_ctrl); - -s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl) -{ - s32 val = 0; - - /* It's a driver bug if this happens. */ - WARN_ON(!type_is_int(ctrl)); - get_ctrl(ctrl, &val); - return val; -} -EXPORT_SYMBOL(v4l2_ctrl_g_ctrl); - - -/* Core function that calls try/s_ctrl and ensures that the new value is - copied to the current value on a set. - Must be called with ctrl->handler->lock held. */ -static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set) -{ - bool try = !set; - int ret = 0; - int i; - - /* Go through the cluster and either validate the new value or - (if no new value was set), copy the current value to the new - value, ensuring a consistent view for the control ops when - called. */ - for (i = 0; !ret && i < master->ncontrols; i++) { - struct v4l2_ctrl *ctrl = master->cluster[i]; - - if (ctrl == NULL) - continue; - - if (ctrl->is_new) { - /* Double check this: it may have changed since the - last check in try_or_set_ext_ctrls(). */ - if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) - return -EBUSY; - - /* Validate if required */ - if (!set) - ret = validate_new(ctrl); - continue; - } - /* No new value was set, so copy the current and force - a call to try_ctrl later, since the values for the cluster - may now have changed and the end result might be invalid. */ - try = true; - cur_to_new(ctrl); - } - - /* For larger clusters you have to call try_ctrl again to - verify that the controls are still valid after the - 'cur_to_new' above. */ - if (!ret && master->ops->try_ctrl && try) - ret = master->ops->try_ctrl(master); - - /* Don't set if there is no change */ - if (!ret && set && cluster_changed(master)) { - ret = master->ops->s_ctrl(master); - /* If OK, then make the new values permanent. */ - if (!ret) - for (i = 0; i < master->ncontrols; i++) - new_to_cur(master->cluster[i]); - } - return ret; -} - -/* Try or set controls. */ -static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl, - struct v4l2_ext_controls *cs, - struct ctrl_helper *helpers, - bool set) -{ - unsigned i, j; - int ret = 0; - - cs->error_idx = cs->count; - for (i = 0; i < cs->count; i++) { - struct v4l2_ctrl *ctrl = helpers[i].ctrl; - - if (!set) - cs->error_idx = i; - - if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) - return -EACCES; - /* This test is also done in try_set_control_cluster() which - is called in atomic context, so that has the final say, - but it makes sense to do an up-front check as well. Once - an error occurs in try_set_control_cluster() some other - controls may have been set already and we want to do a - best-effort to avoid that. */ - if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) - return -EBUSY; - } - - for (i = 0; !ret && i < cs->count; i++) { - struct v4l2_ctrl *ctrl = helpers[i].ctrl; - struct v4l2_ctrl *master = ctrl->cluster[0]; - - cs->error_idx = i; - - if (helpers[i].handled) - continue; - - v4l2_ctrl_lock(ctrl); - - /* Reset the 'is_new' flags of the cluster */ - for (j = 0; j < master->ncontrols; j++) - if (master->cluster[j]) - master->cluster[j]->is_new = 0; - - /* Copy the new caller-supplied control values. - user_to_new() sets 'is_new' to 1. */ - ret = cluster_walk(i, cs, helpers, user_to_new); - - if (!ret) - ret = try_or_set_control_cluster(master, set); - - /* Copy the new values back to userspace. */ - if (!ret) - ret = cluster_walk(i, cs, helpers, new_to_user); - - v4l2_ctrl_unlock(ctrl); - cluster_done(i, cs, helpers); - } - return ret; -} - -/* Try or try-and-set controls */ -static int try_set_ext_ctrls(struct v4l2_ctrl_handler *hdl, - struct v4l2_ext_controls *cs, - bool set) -{ - struct ctrl_helper helper[4]; - struct ctrl_helper *helpers = helper; - int ret; - int i; - - cs->error_idx = cs->count; - cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class); - - if (hdl == NULL) - return -EINVAL; - - if (cs->count == 0) - return class_check(hdl, cs->ctrl_class); - - if (cs->count > ARRAY_SIZE(helper)) { - helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL); - if (!helpers) - return -ENOMEM; - } - ret = prepare_ext_ctrls(hdl, cs, helpers, !set); - if (ret) - goto free; - - /* First 'try' all controls and abort on error */ - ret = try_or_set_ext_ctrls(hdl, cs, helpers, false); - /* If this is a 'set' operation and the initial 'try' failed, - then set error_idx to count to tell the application that no - controls changed value yet. */ - if (set) - cs->error_idx = cs->count; - if (!ret && set) { - /* Reset 'handled' state */ - for (i = 0; i < cs->count; i++) - helpers[i].handled = false; - ret = try_or_set_ext_ctrls(hdl, cs, helpers, true); - } - -free: - if (cs->count > ARRAY_SIZE(helper)) - kfree(helpers); - return ret; -} - -int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs) -{ - return try_set_ext_ctrls(hdl, cs, false); -} -EXPORT_SYMBOL(v4l2_try_ext_ctrls); - -int v4l2_s_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs) -{ - return try_set_ext_ctrls(hdl, cs, true); -} -EXPORT_SYMBOL(v4l2_s_ext_ctrls); - -int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs) -{ - return try_set_ext_ctrls(sd->ctrl_handler, cs, false); -} -EXPORT_SYMBOL(v4l2_subdev_try_ext_ctrls); - -int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs) -{ - return try_set_ext_ctrls(sd->ctrl_handler, cs, true); -} -EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls); - -/* Helper function for VIDIOC_S_CTRL compatibility */ -static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val) -{ - struct v4l2_ctrl *master = ctrl->cluster[0]; - int ret; - int i; - - if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) - return -EACCES; - - v4l2_ctrl_lock(ctrl); - - /* Reset the 'is_new' flags of the cluster */ - for (i = 0; i < master->ncontrols; i++) - if (master->cluster[i]) - master->cluster[i]->is_new = 0; - - ctrl->val = *val; - ctrl->is_new = 1; - ret = try_or_set_control_cluster(master, false); - if (!ret) - ret = try_or_set_control_cluster(master, true); - *val = ctrl->cur.val; - v4l2_ctrl_unlock(ctrl); - return ret; -} - -int v4l2_s_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control) -{ - struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id); - - if (ctrl == NULL || !type_is_int(ctrl)) - return -EINVAL; - - return set_ctrl(ctrl, &control->value); -} -EXPORT_SYMBOL(v4l2_s_ctrl); - -int v4l2_subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control) -{ - return v4l2_s_ctrl(sd->ctrl_handler, control); -} -EXPORT_SYMBOL(v4l2_subdev_s_ctrl); - -int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val) -{ - /* It's a driver bug if this happens. */ - WARN_ON(!type_is_int(ctrl)); - return set_ctrl(ctrl, &val); -} -EXPORT_SYMBOL(v4l2_ctrl_s_ctrl); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-dev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-dev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-dev.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-dev.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,797 +0,0 @@ -/* - * Video capture interface for Linux version 2 - * - * A generic video device interface for the LINUX operating system - * using a set of device structures/vectors for low level operations. - * - * 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, or (at your option) any later version. - * - * Authors: Alan Cox, (version 1) - * Mauro Carvalho Chehab (version 2) - * - * Fixes: 20000516 Claudio Matsuoka - * - Added procfs support - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define VIDEO_NUM_DEVICES 256 -#define VIDEO_NAME "video4linux" - -/* - * sysfs stuff - */ - -static ssize_t show_index(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = to_video_device(cd); - - return sprintf(buf, "%i\n", vdev->index); -} - -static ssize_t show_name(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = to_video_device(cd); - - return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name); -} - -static struct device_attribute video_device_attrs[] = { - __ATTR(name, S_IRUGO, show_name, NULL), - __ATTR(index, S_IRUGO, show_index, NULL), - __ATTR_NULL -}; - -/* - * Active devices - */ -static struct video_device *video_device[VIDEO_NUM_DEVICES]; -static DEFINE_MUTEX(videodev_lock); -static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES); - -/* Device node utility functions */ - -/* Note: these utility functions all assume that vfl_type is in the range - [0, VFL_TYPE_MAX-1]. */ - -#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES -/* Return the bitmap corresponding to vfl_type. */ -static inline unsigned long *devnode_bits(int vfl_type) -{ - /* Any types not assigned to fixed minor ranges must be mapped to - one single bitmap for the purposes of finding a free node number - since all those unassigned types use the same minor range. */ - int idx = (vfl_type > VFL_TYPE_RADIO) ? VFL_TYPE_MAX - 1 : vfl_type; - - return devnode_nums[idx]; -} -#else -/* Return the bitmap corresponding to vfl_type. */ -static inline unsigned long *devnode_bits(int vfl_type) -{ - return devnode_nums[vfl_type]; -} -#endif - -/* Mark device node number vdev->num as used */ -static inline void devnode_set(struct video_device *vdev) -{ - set_bit(vdev->num, devnode_bits(vdev->vfl_type)); -} - -/* Mark device node number vdev->num as unused */ -static inline void devnode_clear(struct video_device *vdev) -{ - clear_bit(vdev->num, devnode_bits(vdev->vfl_type)); -} - -/* Try to find a free device node number in the range [from, to> */ -static inline int devnode_find(struct video_device *vdev, int from, int to) -{ - return find_next_zero_bit(devnode_bits(vdev->vfl_type), to, from); -} - -struct video_device *video_device_alloc(void) -{ - return kzalloc(sizeof(struct video_device), GFP_KERNEL); -} -EXPORT_SYMBOL(video_device_alloc); - -void video_device_release(struct video_device *vdev) -{ - kfree(vdev); -} -EXPORT_SYMBOL(video_device_release); - -void video_device_release_empty(struct video_device *vdev) -{ - /* Do nothing */ - /* Only valid when the video_device struct is a static. */ -} -EXPORT_SYMBOL(video_device_release_empty); - -static inline void video_get(struct video_device *vdev) -{ - get_device(&vdev->dev); -} - -static inline void video_put(struct video_device *vdev) -{ - put_device(&vdev->dev); -} - -/* Called when the last user of the video device exits. */ -static void v4l2_device_release(struct device *cd) -{ - struct video_device *vdev = to_video_device(cd); - struct v4l2_device *v4l2_dev = vdev->v4l2_dev; - - mutex_lock(&videodev_lock); - if (video_device[vdev->minor] != vdev) { - mutex_unlock(&videodev_lock); - /* should not happen */ - WARN_ON(1); - return; - } - - /* Free up this device for reuse */ - video_device[vdev->minor] = NULL; - - /* Delete the cdev on this minor as well */ - cdev_del(vdev->cdev); - /* Just in case some driver tries to access this from - the release() callback. */ - vdev->cdev = NULL; - - /* Mark device node number as free */ - devnode_clear(vdev); - - mutex_unlock(&videodev_lock); - - /* Release video_device and perform other - cleanups as needed. */ - vdev->release(vdev); - - /* Decrease v4l2_device refcount */ - if (v4l2_dev) - v4l2_device_put(v4l2_dev); -} - -static struct class video_class = { - .name = VIDEO_NAME, - .dev_attrs = video_device_attrs, -}; - -struct video_device *video_devdata(struct file *file) -{ - return video_device[iminor(file->f_path.dentry->d_inode)]; -} -EXPORT_SYMBOL(video_devdata); - - -/* Priority handling */ - -static inline bool prio_is_valid(enum v4l2_priority prio) -{ - return prio == V4L2_PRIORITY_BACKGROUND || - prio == V4L2_PRIORITY_INTERACTIVE || - prio == V4L2_PRIORITY_RECORD; -} - -void v4l2_prio_init(struct v4l2_prio_state *global) -{ - memset(global, 0, sizeof(*global)); -} -EXPORT_SYMBOL(v4l2_prio_init); - -int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, - enum v4l2_priority new) -{ - if (!prio_is_valid(new)) - return -EINVAL; - if (*local == new) - return 0; - - atomic_inc(&global->prios[new]); - if (prio_is_valid(*local)) - atomic_dec(&global->prios[*local]); - *local = new; - return 0; -} -EXPORT_SYMBOL(v4l2_prio_change); - -void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local) -{ - v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT); -} -EXPORT_SYMBOL(v4l2_prio_open); - -void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local) -{ - if (prio_is_valid(local)) - atomic_dec(&global->prios[local]); -} -EXPORT_SYMBOL(v4l2_prio_close); - -enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global) -{ - if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0) - return V4L2_PRIORITY_RECORD; - if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0) - return V4L2_PRIORITY_INTERACTIVE; - if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0) - return V4L2_PRIORITY_BACKGROUND; - return V4L2_PRIORITY_UNSET; -} -EXPORT_SYMBOL(v4l2_prio_max); - -int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local) -{ - return (local < v4l2_prio_max(global)) ? -EBUSY : 0; -} -EXPORT_SYMBOL(v4l2_prio_check); - - -static ssize_t v4l2_read(struct file *filp, char __user *buf, - size_t sz, loff_t *off) -{ - struct video_device *vdev = video_devdata(filp); - int ret = -ENODEV; - - if (!vdev->fops->read) - return -EINVAL; - if (vdev->lock && mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; - if (video_is_registered(vdev)) - ret = vdev->fops->read(filp, buf, sz, off); - if (vdev->lock) - mutex_unlock(vdev->lock); - return ret; -} - -static ssize_t v4l2_write(struct file *filp, const char __user *buf, - size_t sz, loff_t *off) -{ - struct video_device *vdev = video_devdata(filp); - int ret = -ENODEV; - - if (!vdev->fops->write) - return -EINVAL; - if (vdev->lock && mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; - if (video_is_registered(vdev)) - ret = vdev->fops->write(filp, buf, sz, off); - if (vdev->lock) - mutex_unlock(vdev->lock); - return ret; -} - -static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) -{ - struct video_device *vdev = video_devdata(filp); - int ret = POLLERR | POLLHUP; - - if (!vdev->fops->poll) - return DEFAULT_POLLMASK; - if (vdev->lock) - mutex_lock(vdev->lock); - if (video_is_registered(vdev)) - ret = vdev->fops->poll(filp, poll); - if (vdev->lock) - mutex_unlock(vdev->lock); - return ret; -} - -static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct video_device *vdev = video_devdata(filp); - int ret = -ENODEV; - - if (vdev->fops->unlocked_ioctl) { - if (vdev->lock && mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; - if (video_is_registered(vdev)) - ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); - if (vdev->lock) - mutex_unlock(vdev->lock); - } else if (vdev->fops->ioctl) { - /* This code path is a replacement for the BKL. It is a major - * hack but it will have to do for those drivers that are not - * yet converted to use unlocked_ioctl. - * - * There are two options: if the driver implements struct - * v4l2_device, then the lock defined there is used to - * serialize the ioctls. Otherwise the v4l2 core lock defined - * below is used. This lock is really bad since it serializes - * completely independent devices. - * - * Both variants suffer from the same problem: if the driver - * sleeps, then it blocks all ioctls since the lock is still - * held. This is very common for VIDIOC_DQBUF since that - * normally waits for a frame to arrive. As a result any other - * ioctl calls will proceed very, very slowly since each call - * will have to wait for the VIDIOC_QBUF to finish. Things that - * should take 0.01s may now take 10-20 seconds. - * - * The workaround is to *not* take the lock for VIDIOC_DQBUF. - * This actually works OK for videobuf-based drivers, since - * videobuf will take its own internal lock. - */ - static DEFINE_MUTEX(v4l2_ioctl_mutex); - struct mutex *m = vdev->v4l2_dev ? - &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex; - - if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m)) - return -ERESTARTSYS; - if (video_is_registered(vdev)) - ret = vdev->fops->ioctl(filp, cmd, arg); - if (cmd != VIDIOC_DQBUF) - mutex_unlock(m); - } else - ret = -ENOTTY; - - return ret; -} - -static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) -{ - struct video_device *vdev = video_devdata(filp); - int ret = -ENODEV; - - if (!vdev->fops->mmap) - return ret; - if (vdev->lock && mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; - if (video_is_registered(vdev)) - ret = vdev->fops->mmap(filp, vm); - if (vdev->lock) - mutex_unlock(vdev->lock); - return ret; -} - -/* Override for the open function */ -static int v4l2_open(struct inode *inode, struct file *filp) -{ - struct video_device *vdev; -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity *entity = NULL; -#endif - int ret = 0; - - /* Check if the video device is available */ - mutex_lock(&videodev_lock); - vdev = video_devdata(filp); - /* return ENODEV if the video device has already been removed. */ - if (vdev == NULL || !video_is_registered(vdev)) { - mutex_unlock(&videodev_lock); - return -ENODEV; - } - /* and increase the device refcount */ - video_get(vdev); - mutex_unlock(&videodev_lock); -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { - entity = media_entity_get(&vdev->entity); - if (!entity) { - ret = -EBUSY; - video_put(vdev); - return ret; - } - } -#endif - if (vdev->fops->open) { - if (vdev->lock && mutex_lock_interruptible(vdev->lock)) { - ret = -ERESTARTSYS; - goto err; - } - if (video_is_registered(vdev)) - ret = vdev->fops->open(filp); - else - ret = -ENODEV; - if (vdev->lock) - mutex_unlock(vdev->lock); - } - -err: - /* decrease the refcount in case of an error */ - if (ret) { -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) - media_entity_put(entity); -#endif - video_put(vdev); - } - return ret; -} - -/* Override for the release function */ -static int v4l2_release(struct inode *inode, struct file *filp) -{ - struct video_device *vdev = video_devdata(filp); - int ret = 0; - - if (vdev->fops->release) { - if (vdev->lock) - mutex_lock(vdev->lock); - vdev->fops->release(filp); - if (vdev->lock) - mutex_unlock(vdev->lock); - } -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) - media_entity_put(&vdev->entity); -#endif - /* decrease the refcount unconditionally since the release() - return value is ignored. */ - video_put(vdev); - return ret; -} - -static const struct file_operations v4l2_fops = { - .owner = THIS_MODULE, - .read = v4l2_read, - .write = v4l2_write, - .open = v4l2_open, - .mmap = v4l2_mmap, - .unlocked_ioctl = v4l2_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = v4l2_compat_ioctl32, -#endif - .release = v4l2_release, - .poll = v4l2_poll, - .llseek = no_llseek, -}; - -/** - * get_index - assign stream index number based on parent device - * @vdev: video_device to assign index number to, vdev->parent should be assigned - * - * Note that when this is called the new device has not yet been registered - * in the video_device array, but it was able to obtain a minor number. - * - * This means that we can always obtain a free stream index number since - * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in - * use of the video_device array. - * - * Returns a free index number. - */ -static int get_index(struct video_device *vdev) -{ - /* This can be static since this function is called with the global - videodev_lock held. */ - static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES); - int i; - - /* Some drivers do not set the parent. In that case always return 0. */ - if (vdev->parent == NULL) - return 0; - - bitmap_zero(used, VIDEO_NUM_DEVICES); - - for (i = 0; i < VIDEO_NUM_DEVICES; i++) { - if (video_device[i] != NULL && - video_device[i]->parent == vdev->parent) { - set_bit(video_device[i]->index, used); - } - } - - return find_first_zero_bit(used, VIDEO_NUM_DEVICES); -} - -/** - * __video_register_device - register video4linux devices - * @vdev: video device structure we want to register - * @type: type of device to register - * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... - * -1 == first free) - * @warn_if_nr_in_use: warn if the desired device node number - * was already in use and another number was chosen instead. - * @owner: module that owns the video device node - * - * The registration code assigns minor numbers and device node numbers - * based on the requested type and registers the new device node with - * the kernel. - * - * This function assumes that struct video_device was zeroed when it - * was allocated and does not contain any stale date. - * - * An error is returned if no free minor or device node number could be - * found, or if the registration of the device node failed. - * - * Zero is returned on success. - * - * Valid types are - * - * %VFL_TYPE_GRABBER - A frame grabber - * - * %VFL_TYPE_VBI - Vertical blank data (undecoded) - * - * %VFL_TYPE_RADIO - A radio card - * - * %VFL_TYPE_SUBDEV - A subdevice - */ -int __video_register_device(struct video_device *vdev, int type, int nr, - int warn_if_nr_in_use, struct module *owner) -{ - int i = 0; - int ret; - int minor_offset = 0; - int minor_cnt = VIDEO_NUM_DEVICES; - const char *name_base; - - /* A minor value of -1 marks this video device as never - having been registered */ - vdev->minor = -1; - - /* the release callback MUST be present */ - WARN_ON(!vdev->release); - if (!vdev->release) - return -EINVAL; - - /* v4l2_fh support */ - spin_lock_init(&vdev->fh_lock); - INIT_LIST_HEAD(&vdev->fh_list); - - /* Part 1: check device type */ - switch (type) { - case VFL_TYPE_GRABBER: - name_base = "video"; - break; - case VFL_TYPE_VBI: - name_base = "vbi"; - break; - case VFL_TYPE_RADIO: - name_base = "radio"; - break; - case VFL_TYPE_SUBDEV: - name_base = "v4l-subdev"; - break; - default: - printk(KERN_ERR "%s called with unknown type: %d\n", - __func__, type); - return -EINVAL; - } - - vdev->vfl_type = type; - vdev->cdev = NULL; - if (vdev->v4l2_dev) { - if (vdev->v4l2_dev->dev) - vdev->parent = vdev->v4l2_dev->dev; - if (vdev->ctrl_handler == NULL) - vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; - /* If the prio state pointer is NULL, then use the v4l2_device - prio state. */ - if (vdev->prio == NULL) - vdev->prio = &vdev->v4l2_dev->prio; - } - - /* Part 2: find a free minor, device node number and device index. */ -#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES - /* Keep the ranges for the first four types for historical - * reasons. - * Newer devices (not yet in place) should use the range - * of 128-191 and just pick the first free minor there - * (new style). */ - switch (type) { - case VFL_TYPE_GRABBER: - minor_offset = 0; - minor_cnt = 64; - break; - case VFL_TYPE_RADIO: - minor_offset = 64; - minor_cnt = 64; - break; - case VFL_TYPE_VBI: - minor_offset = 224; - minor_cnt = 32; - break; - default: - minor_offset = 128; - minor_cnt = 64; - break; - } -#endif - - /* Pick a device node number */ - mutex_lock(&videodev_lock); - nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt); - if (nr == minor_cnt) - nr = devnode_find(vdev, 0, minor_cnt); - if (nr == minor_cnt) { - printk(KERN_ERR "could not get a free device node number\n"); - mutex_unlock(&videodev_lock); - return -ENFILE; - } -#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES - /* 1-on-1 mapping of device node number to minor number */ - i = nr; -#else - /* The device node number and minor numbers are independent, so - we just find the first free minor number. */ - for (i = 0; i < VIDEO_NUM_DEVICES; i++) - if (video_device[i] == NULL) - break; - if (i == VIDEO_NUM_DEVICES) { - mutex_unlock(&videodev_lock); - printk(KERN_ERR "could not get a free minor\n"); - return -ENFILE; - } -#endif - vdev->minor = i + minor_offset; - vdev->num = nr; - devnode_set(vdev); - - /* Should not happen since we thought this minor was free */ - WARN_ON(video_device[vdev->minor] != NULL); - vdev->index = get_index(vdev); - mutex_unlock(&videodev_lock); - - /* Part 3: Initialize the character device */ - vdev->cdev = cdev_alloc(); - if (vdev->cdev == NULL) { - ret = -ENOMEM; - goto cleanup; - } - vdev->cdev->ops = &v4l2_fops; - vdev->cdev->owner = owner; - ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); - if (ret < 0) { - printk(KERN_ERR "%s: cdev_add failed\n", __func__); - kfree(vdev->cdev); - vdev->cdev = NULL; - goto cleanup; - } - - /* Part 4: register the device with sysfs */ - vdev->dev.class = &video_class; - vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); - if (vdev->parent) - vdev->dev.parent = vdev->parent; - dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); - ret = device_register(&vdev->dev); - if (ret < 0) { - printk(KERN_ERR "%s: device_register failed\n", __func__); - goto cleanup; - } - /* Register the release callback that will be called when the last - reference to the device goes away. */ - vdev->dev.release = v4l2_device_release; - - if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) - printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__, - name_base, nr, video_device_node_name(vdev)); - - /* Increase v4l2_device refcount */ - if (vdev->v4l2_dev) - v4l2_device_get(vdev->v4l2_dev); - -#if defined(CONFIG_MEDIA_CONTROLLER) - /* Part 5: Register the entity. */ - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { - vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; - vdev->entity.name = vdev->name; - vdev->entity.v4l.major = VIDEO_MAJOR; - vdev->entity.v4l.minor = vdev->minor; - ret = media_device_register_entity(vdev->v4l2_dev->mdev, - &vdev->entity); - if (ret < 0) - printk(KERN_WARNING - "%s: media_device_register_entity failed\n", - __func__); - } -#endif - /* Part 6: Activate this minor. The char device can now be used. */ - set_bit(V4L2_FL_REGISTERED, &vdev->flags); - mutex_lock(&videodev_lock); - video_device[vdev->minor] = vdev; - mutex_unlock(&videodev_lock); - - return 0; - -cleanup: - mutex_lock(&videodev_lock); - if (vdev->cdev) - cdev_del(vdev->cdev); - devnode_clear(vdev); - mutex_unlock(&videodev_lock); - /* Mark this video device as never having been registered. */ - vdev->minor = -1; - return ret; -} -EXPORT_SYMBOL(__video_register_device); - -/** - * video_unregister_device - unregister a video4linux device - * @vdev: the device to unregister - * - * This unregisters the passed device. Future open calls will - * be met with errors. - */ -void video_unregister_device(struct video_device *vdev) -{ - /* Check if vdev was ever registered at all */ - if (!vdev || !video_is_registered(vdev)) - return; - -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) - media_device_unregister_entity(&vdev->entity); -#endif - - mutex_lock(&videodev_lock); - /* This must be in a critical section to prevent a race with v4l2_open. - * Once this bit has been cleared video_get may never be called again. - */ - clear_bit(V4L2_FL_REGISTERED, &vdev->flags); - mutex_unlock(&videodev_lock); - device_unregister(&vdev->dev); -} -EXPORT_SYMBOL(video_unregister_device); - -/* - * Initialise video for linux - */ -static int __init videodev_init(void) -{ - dev_t dev = MKDEV(VIDEO_MAJOR, 0); - int ret; - - printk(KERN_INFO "Linux video capture interface: v2.00\n"); - ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME); - if (ret < 0) { - printk(KERN_WARNING "videodev: unable to get major %d\n", - VIDEO_MAJOR); - return ret; - } - - ret = class_register(&video_class); - if (ret < 0) { - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); - printk(KERN_WARNING "video_dev: class_register failed\n"); - return -EIO; - } - - return 0; -} - -static void __exit videodev_exit(void) -{ - dev_t dev = MKDEV(VIDEO_MAJOR, 0); - - class_unregister(&video_class); - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); -} - -module_init(videodev_init) -module_exit(videodev_exit) - -MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab "); -MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR); - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-device.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-device.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-device.c 2011-03-24 07:51:41.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-device.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,247 +0,0 @@ -/* - V4L2 device support. - - Copyright (C) 2008 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 -#include -#include -#if defined(CONFIG_SPI) -#include -#endif -#include -#include -#include - -int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) -{ - if (v4l2_dev == NULL) - return -EINVAL; - - INIT_LIST_HEAD(&v4l2_dev->subdevs); - spin_lock_init(&v4l2_dev->lock); - mutex_init(&v4l2_dev->ioctl_lock); - v4l2_prio_init(&v4l2_dev->prio); - kref_init(&v4l2_dev->ref); - v4l2_dev->dev = dev; - if (dev == NULL) { - /* If dev == NULL, then name must be filled in by the caller */ - WARN_ON(!v4l2_dev->name[0]); - return 0; - } - - /* Set name to driver name + device name if it is empty. */ - if (!v4l2_dev->name[0]) - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s", - dev->driver->name, dev_name(dev)); - if (!dev_get_drvdata(dev)) - dev_set_drvdata(dev, v4l2_dev); - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_device_register); - -static void v4l2_device_release(struct kref *ref) -{ - struct v4l2_device *v4l2_dev = - container_of(ref, struct v4l2_device, ref); - - if (v4l2_dev->release) - v4l2_dev->release(v4l2_dev); -} - -int v4l2_device_put(struct v4l2_device *v4l2_dev) -{ - return kref_put(&v4l2_dev->ref, v4l2_device_release); -} -EXPORT_SYMBOL_GPL(v4l2_device_put); - -int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename, - atomic_t *instance) -{ - int num = atomic_inc_return(instance) - 1; - int len = strlen(basename); - - if (basename[len - 1] >= '0' && basename[len - 1] <= '9') - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), - "%s-%d", basename, num); - else - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), - "%s%d", basename, num); - return num; -} -EXPORT_SYMBOL_GPL(v4l2_device_set_name); - -void v4l2_device_disconnect(struct v4l2_device *v4l2_dev) -{ - if (v4l2_dev->dev == NULL) - return; - - if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev) - dev_set_drvdata(v4l2_dev->dev, NULL); - v4l2_dev->dev = NULL; -} -EXPORT_SYMBOL_GPL(v4l2_device_disconnect); - -void v4l2_device_unregister(struct v4l2_device *v4l2_dev) -{ - struct v4l2_subdev *sd, *next; - - if (v4l2_dev == NULL) - return; - v4l2_device_disconnect(v4l2_dev); - - /* Unregister subdevs */ - list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) { - v4l2_device_unregister_subdev(sd); -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) - if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* We need to unregister the i2c client explicitly. - We cannot rely on i2c_del_adapter to always - unregister clients for us, since if the i2c bus - is a platform bus, then it is never deleted. */ - if (client) - i2c_unregister_device(client); - continue; - } -#endif -#if defined(CONFIG_SPI) - if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) { - struct spi_device *spi = v4l2_get_subdevdata(sd); - - if (spi) - spi_unregister_device(spi); - continue; - } -#endif - } -} -EXPORT_SYMBOL_GPL(v4l2_device_unregister); - -int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, - struct v4l2_subdev *sd) -{ -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity *entity = &sd->entity; -#endif - int err; - - /* Check for valid input */ - if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) - return -EINVAL; - - /* Warn if we apparently re-register a subdev */ - WARN_ON(sd->v4l2_dev != NULL); - - if (!try_module_get(sd->owner)) - return -ENODEV; - - sd->v4l2_dev = v4l2_dev; - if (sd->internal_ops && sd->internal_ops->registered) { - err = sd->internal_ops->registered(sd); - if (err) - return err; - } - - /* This just returns 0 if either of the two args is NULL */ - err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); - if (err) { - if (sd->internal_ops && sd->internal_ops->unregistered) - sd->internal_ops->unregistered(sd); - return err; - } - -#if defined(CONFIG_MEDIA_CONTROLLER) - /* Register the entity. */ - if (v4l2_dev->mdev) { - err = media_device_register_entity(v4l2_dev->mdev, entity); - if (err < 0) { - if (sd->internal_ops && sd->internal_ops->unregistered) - sd->internal_ops->unregistered(sd); - module_put(sd->owner); - return err; - } - } -#endif - - spin_lock(&v4l2_dev->lock); - list_add_tail(&sd->list, &v4l2_dev->subdevs); - spin_unlock(&v4l2_dev->lock); - - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); - -int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) -{ - struct video_device *vdev; - struct v4l2_subdev *sd; - int err; - - /* Register a device node for every subdev marked with the - * V4L2_SUBDEV_FL_HAS_DEVNODE flag. - */ - list_for_each_entry(sd, &v4l2_dev->subdevs, list) { - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) - continue; - - vdev = &sd->devnode; - strlcpy(vdev->name, sd->name, sizeof(vdev->name)); - vdev->v4l2_dev = v4l2_dev; - vdev->fops = &v4l2_subdev_fops; - vdev->release = video_device_release_empty; - err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, - sd->owner); - if (err < 0) - return err; -#if defined(CONFIG_MEDIA_CONTROLLER) - sd->entity.v4l.major = VIDEO_MAJOR; - sd->entity.v4l.minor = vdev->minor; -#endif - } - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); - -void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) -{ - struct v4l2_device *v4l2_dev; - - /* return if it isn't registered */ - if (sd == NULL || sd->v4l2_dev == NULL) - return; - - v4l2_dev = sd->v4l2_dev; - - spin_lock(&v4l2_dev->lock); - list_del(&sd->list); - spin_unlock(&v4l2_dev->lock); - - if (sd->internal_ops && sd->internal_ops->unregistered) - sd->internal_ops->unregistered(sd); - sd->v4l2_dev = NULL; - -#if defined(CONFIG_MEDIA_CONTROLLER) - if (v4l2_dev->mdev) - media_device_unregister_entity(&sd->entity); -#endif - video_unregister_device(&sd->devnode); - module_put(sd->owner); -} -EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-event.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-event.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-event.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-event.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,299 +0,0 @@ -/* - * v4l2-event.c - * - * V4L2 events. - * - * Copyright (C) 2009--2010 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include - -#include -#include - -int v4l2_event_init(struct v4l2_fh *fh) -{ - fh->events = kzalloc(sizeof(*fh->events), GFP_KERNEL); - if (fh->events == NULL) - return -ENOMEM; - - init_waitqueue_head(&fh->events->wait); - - INIT_LIST_HEAD(&fh->events->free); - INIT_LIST_HEAD(&fh->events->available); - INIT_LIST_HEAD(&fh->events->subscribed); - - fh->events->sequence = -1; - - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_event_init); - -int v4l2_event_alloc(struct v4l2_fh *fh, unsigned int n) -{ - struct v4l2_events *events = fh->events; - unsigned long flags; - - if (!events) { - WARN_ON(1); - return -ENOMEM; - } - - while (events->nallocated < n) { - struct v4l2_kevent *kev; - - kev = kzalloc(sizeof(*kev), GFP_KERNEL); - if (kev == NULL) - return -ENOMEM; - - spin_lock_irqsave(&fh->vdev->fh_lock, flags); - list_add_tail(&kev->list, &events->free); - events->nallocated++; - spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - } - - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_event_alloc); - -#define list_kfree(list, type, member) \ - while (!list_empty(list)) { \ - type *hi; \ - hi = list_first_entry(list, type, member); \ - list_del(&hi->member); \ - kfree(hi); \ - } - -void v4l2_event_free(struct v4l2_fh *fh) -{ - struct v4l2_events *events = fh->events; - - if (!events) - return; - - list_kfree(&events->free, struct v4l2_kevent, list); - list_kfree(&events->available, struct v4l2_kevent, list); - list_kfree(&events->subscribed, struct v4l2_subscribed_event, list); - - kfree(events); - fh->events = NULL; -} -EXPORT_SYMBOL_GPL(v4l2_event_free); - -static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event) -{ - struct v4l2_events *events = fh->events; - struct v4l2_kevent *kev; - unsigned long flags; - - spin_lock_irqsave(&fh->vdev->fh_lock, flags); - - if (list_empty(&events->available)) { - spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - return -ENOENT; - } - - WARN_ON(events->navailable == 0); - - kev = list_first_entry(&events->available, struct v4l2_kevent, list); - list_move(&kev->list, &events->free); - events->navailable--; - - kev->event.pending = events->navailable; - *event = kev->event; - - spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - - return 0; -} - -int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event, - int nonblocking) -{ - struct v4l2_events *events = fh->events; - int ret; - - if (nonblocking) - return __v4l2_event_dequeue(fh, event); - - /* Release the vdev lock while waiting */ - if (fh->vdev->lock) - mutex_unlock(fh->vdev->lock); - - do { - ret = wait_event_interruptible(events->wait, - events->navailable != 0); - if (ret < 0) - break; - - ret = __v4l2_event_dequeue(fh, event); - } while (ret == -ENOENT); - - if (fh->vdev->lock) - mutex_lock(fh->vdev->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(v4l2_event_dequeue); - -/* Caller must hold fh->event->lock! */ -static struct v4l2_subscribed_event *v4l2_event_subscribed( - struct v4l2_fh *fh, u32 type) -{ - struct v4l2_events *events = fh->events; - struct v4l2_subscribed_event *sev; - - assert_spin_locked(&fh->vdev->fh_lock); - - list_for_each_entry(sev, &events->subscribed, list) { - if (sev->type == type) - return sev; - } - - return NULL; -} - -void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev) -{ - struct v4l2_fh *fh; - unsigned long flags; - struct timespec timestamp; - - ktime_get_ts(×tamp); - - spin_lock_irqsave(&vdev->fh_lock, flags); - - list_for_each_entry(fh, &vdev->fh_list, list) { - struct v4l2_events *events = fh->events; - struct v4l2_kevent *kev; - - /* Are we subscribed? */ - if (!v4l2_event_subscribed(fh, ev->type)) - continue; - - /* Increase event sequence number on fh. */ - events->sequence++; - - /* Do we have any free events? */ - if (list_empty(&events->free)) - continue; - - /* Take one and fill it. */ - kev = list_first_entry(&events->free, struct v4l2_kevent, list); - kev->event.type = ev->type; - kev->event.u = ev->u; - kev->event.timestamp = timestamp; - kev->event.sequence = events->sequence; - list_move_tail(&kev->list, &events->available); - - events->navailable++; - - wake_up_all(&events->wait); - } - - spin_unlock_irqrestore(&vdev->fh_lock, flags); -} -EXPORT_SYMBOL_GPL(v4l2_event_queue); - -int v4l2_event_pending(struct v4l2_fh *fh) -{ - return fh->events->navailable; -} -EXPORT_SYMBOL_GPL(v4l2_event_pending); - -int v4l2_event_subscribe(struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - struct v4l2_events *events = fh->events; - struct v4l2_subscribed_event *sev; - unsigned long flags; - - if (fh->events == NULL) { - WARN_ON(1); - return -ENOMEM; - } - - sev = kmalloc(sizeof(*sev), GFP_KERNEL); - if (!sev) - return -ENOMEM; - - spin_lock_irqsave(&fh->vdev->fh_lock, flags); - - if (v4l2_event_subscribed(fh, sub->type) == NULL) { - INIT_LIST_HEAD(&sev->list); - sev->type = sub->type; - - list_add(&sev->list, &events->subscribed); - sev = NULL; - } - - spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - - kfree(sev); - - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_event_subscribe); - -static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh) -{ - struct v4l2_events *events = fh->events; - struct v4l2_subscribed_event *sev; - unsigned long flags; - - do { - sev = NULL; - - spin_lock_irqsave(&fh->vdev->fh_lock, flags); - if (!list_empty(&events->subscribed)) { - sev = list_first_entry(&events->subscribed, - struct v4l2_subscribed_event, list); - list_del(&sev->list); - } - spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - kfree(sev); - } while (sev); -} - -int v4l2_event_unsubscribe(struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - struct v4l2_subscribed_event *sev; - unsigned long flags; - - if (sub->type == V4L2_EVENT_ALL) { - v4l2_event_unsubscribe_all(fh); - return 0; - } - - spin_lock_irqsave(&fh->vdev->fh_lock, flags); - - sev = v4l2_event_subscribed(fh, sub->type); - if (sev != NULL) - list_del(&sev->list); - - spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - - kfree(sev); - - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_event_unsubscribe); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-fh.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-fh.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-fh.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-fh.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -/* - * v4l2-fh.c - * - * V4L2 file handles. - * - * Copyright (C) 2009--2010 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include - -int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) -{ - fh->vdev = vdev; - INIT_LIST_HEAD(&fh->list); - set_bit(V4L2_FL_USES_V4L2_FH, &fh->vdev->flags); - fh->prio = V4L2_PRIORITY_UNSET; - - /* - * fh->events only needs to be initialized if the driver - * supports the VIDIOC_SUBSCRIBE_EVENT ioctl. - */ - if (vdev->ioctl_ops && vdev->ioctl_ops->vidioc_subscribe_event) - return v4l2_event_init(fh); - - fh->events = NULL; - - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_fh_init); - -void v4l2_fh_add(struct v4l2_fh *fh) -{ - unsigned long flags; - - if (test_bit(V4L2_FL_USE_FH_PRIO, &fh->vdev->flags)) - v4l2_prio_open(fh->vdev->prio, &fh->prio); - spin_lock_irqsave(&fh->vdev->fh_lock, flags); - list_add(&fh->list, &fh->vdev->fh_list); - spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); -} -EXPORT_SYMBOL_GPL(v4l2_fh_add); - -int v4l2_fh_open(struct file *filp) -{ - struct video_device *vdev = video_devdata(filp); - struct v4l2_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); - - filp->private_data = fh; - if (fh == NULL) - return -ENOMEM; - v4l2_fh_init(fh, vdev); - v4l2_fh_add(fh); - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_fh_open); - -void v4l2_fh_del(struct v4l2_fh *fh) -{ - unsigned long flags; - - spin_lock_irqsave(&fh->vdev->fh_lock, flags); - list_del_init(&fh->list); - spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - if (test_bit(V4L2_FL_USE_FH_PRIO, &fh->vdev->flags)) - v4l2_prio_close(fh->vdev->prio, fh->prio); -} -EXPORT_SYMBOL_GPL(v4l2_fh_del); - -void v4l2_fh_exit(struct v4l2_fh *fh) -{ - if (fh->vdev == NULL) - return; - - fh->vdev = NULL; - - v4l2_event_free(fh); -} -EXPORT_SYMBOL_GPL(v4l2_fh_exit); - -int v4l2_fh_release(struct file *filp) -{ - struct v4l2_fh *fh = filp->private_data; - - if (fh) { - v4l2_fh_del(fh); - v4l2_fh_exit(fh); - kfree(fh); - } - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_fh_release); - -int v4l2_fh_is_singular(struct v4l2_fh *fh) -{ - unsigned long flags; - int is_singular; - - if (fh == NULL || fh->vdev == NULL) - return 0; - spin_lock_irqsave(&fh->vdev->fh_lock, flags); - is_singular = list_is_singular(&fh->list); - spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - return is_singular; -} -EXPORT_SYMBOL_GPL(v4l2_fh_is_singular); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-int-device.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-int-device.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-int-device.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-int-device.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,163 +0,0 @@ -/* - * drivers/media/video/v4l2-int-device.c - * - * V4L2 internal ioctl interface. - * - * Copyright (C) 2007 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include - -#include - -static DEFINE_MUTEX(mutex); -static LIST_HEAD(int_list); - -void v4l2_int_device_try_attach_all(void) -{ - struct v4l2_int_device *m, *s; - - list_for_each_entry(m, &int_list, head) { - if (m->type != v4l2_int_type_master) - continue; - - list_for_each_entry(s, &int_list, head) { - if (s->type != v4l2_int_type_slave) - continue; - - /* Slave is connected? */ - if (s->u.slave->master) - continue; - - /* Slave wants to attach to master? */ - if (s->u.slave->attach_to[0] != 0 - && strncmp(m->name, s->u.slave->attach_to, - V4L2NAMESIZE)) - continue; - - if (!try_module_get(m->module)) - continue; - - s->u.slave->master = m; - if (m->u.master->attach(s)) { - s->u.slave->master = NULL; - module_put(m->module); - continue; - } - } - } -} -EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all); - -static int ioctl_sort_cmp(const void *a, const void *b) -{ - const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b; - - if (d1->num > d2->num) - return 1; - - if (d1->num < d2->num) - return -1; - - return 0; -} - -int v4l2_int_device_register(struct v4l2_int_device *d) -{ - if (d->type == v4l2_int_type_slave) - sort(d->u.slave->ioctls, d->u.slave->num_ioctls, - sizeof(struct v4l2_int_ioctl_desc), - &ioctl_sort_cmp, NULL); - mutex_lock(&mutex); - list_add(&d->head, &int_list); - v4l2_int_device_try_attach_all(); - mutex_unlock(&mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(v4l2_int_device_register); - -void v4l2_int_device_unregister(struct v4l2_int_device *d) -{ - mutex_lock(&mutex); - list_del(&d->head); - if (d->type == v4l2_int_type_slave - && d->u.slave->master != NULL) { - d->u.slave->master->u.master->detach(d); - module_put(d->u.slave->master->module); - d->u.slave->master = NULL; - } - mutex_unlock(&mutex); -} -EXPORT_SYMBOL_GPL(v4l2_int_device_unregister); - -/* Adapted from search_extable in extable.c. */ -static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, - v4l2_int_ioctl_func *no_such_ioctl) -{ - const struct v4l2_int_ioctl_desc *first = slave->ioctls; - const struct v4l2_int_ioctl_desc *last = - first + slave->num_ioctls - 1; - - while (first <= last) { - const struct v4l2_int_ioctl_desc *mid; - - mid = (last - first) / 2 + first; - - if (mid->num < cmd) - first = mid + 1; - else if (mid->num > cmd) - last = mid - 1; - else - return mid->func; - } - - return no_such_ioctl; -} - -static int no_such_ioctl_0(struct v4l2_int_device *d) -{ - return -ENOIOCTLCMD; -} - -int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) -{ - return ((v4l2_int_ioctl_func_0 *) - find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); -} -EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0); - -static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) -{ - return -ENOIOCTLCMD; -} - -int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) -{ - return ((v4l2_int_ioctl_func_1 *) - find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); -} -EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1); - -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-ioctl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-ioctl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-ioctl.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-ioctl.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2391 +0,0 @@ -/* - * Video capture interface for Linux version 2 - * - * A generic framework to process V4L2 ioctl commands. - * - * 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, or (at your option) any later version. - * - * Authors: Alan Cox, (version 1) - * Mauro Carvalho Chehab (version 2) - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define dbgarg(cmd, fmt, arg...) \ - do { \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ - printk(KERN_DEBUG "%s: ", vfd->name); \ - v4l_printk_ioctl(cmd); \ - printk(" " fmt, ## arg); \ - } \ - } while (0) - -#define dbgarg2(fmt, arg...) \ - do { \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ - printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\ - } while (0) - -#define dbgarg3(fmt, arg...) \ - do { \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ - printk(KERN_CONT "%s: " fmt, vfd->name, ## arg);\ - } while (0) - -/* Zero out the end of the struct pointed to by p. Everthing after, but - * not including, the specified field is cleared. */ -#define CLEAR_AFTER_FIELD(p, field) \ - memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \ - 0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field)) - -struct std_descr { - v4l2_std_id std; - const char *descr; -}; - -static const struct std_descr standards[] = { - { V4L2_STD_NTSC, "NTSC" }, - { V4L2_STD_NTSC_M, "NTSC-M" }, - { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" }, - { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" }, - { V4L2_STD_NTSC_443, "NTSC-443" }, - { V4L2_STD_PAL, "PAL" }, - { V4L2_STD_PAL_BG, "PAL-BG" }, - { V4L2_STD_PAL_B, "PAL-B" }, - { V4L2_STD_PAL_B1, "PAL-B1" }, - { V4L2_STD_PAL_G, "PAL-G" }, - { V4L2_STD_PAL_H, "PAL-H" }, - { V4L2_STD_PAL_I, "PAL-I" }, - { V4L2_STD_PAL_DK, "PAL-DK" }, - { V4L2_STD_PAL_D, "PAL-D" }, - { V4L2_STD_PAL_D1, "PAL-D1" }, - { V4L2_STD_PAL_K, "PAL-K" }, - { V4L2_STD_PAL_M, "PAL-M" }, - { V4L2_STD_PAL_N, "PAL-N" }, - { V4L2_STD_PAL_Nc, "PAL-Nc" }, - { V4L2_STD_PAL_60, "PAL-60" }, - { V4L2_STD_SECAM, "SECAM" }, - { V4L2_STD_SECAM_B, "SECAM-B" }, - { V4L2_STD_SECAM_G, "SECAM-G" }, - { V4L2_STD_SECAM_H, "SECAM-H" }, - { V4L2_STD_SECAM_DK, "SECAM-DK" }, - { V4L2_STD_SECAM_D, "SECAM-D" }, - { V4L2_STD_SECAM_K, "SECAM-K" }, - { V4L2_STD_SECAM_K1, "SECAM-K1" }, - { V4L2_STD_SECAM_L, "SECAM-L" }, - { V4L2_STD_SECAM_LC, "SECAM-Lc" }, - { 0, "Unknown" } -}; - -/* video4linux standard ID conversion to standard name - */ -const char *v4l2_norm_to_name(v4l2_std_id id) -{ - u32 myid = id; - int i; - - /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle - 64 bit comparations. So, on that architecture, with some gcc - variants, compilation fails. Currently, the max value is 30bit wide. - */ - BUG_ON(myid != id); - - for (i = 0; standards[i].std; i++) - if (myid == standards[i].std) - break; - return standards[i].descr; -} -EXPORT_SYMBOL(v4l2_norm_to_name); - -/* Returns frame period for the given standard */ -void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod) -{ - if (id & V4L2_STD_525_60) { - frameperiod->numerator = 1001; - frameperiod->denominator = 30000; - } else { - frameperiod->numerator = 1; - frameperiod->denominator = 25; - } -} -EXPORT_SYMBOL(v4l2_video_std_frame_period); - -/* Fill in the fields of a v4l2_standard structure according to the - 'id' and 'transmission' parameters. Returns negative on error. */ -int v4l2_video_std_construct(struct v4l2_standard *vs, - int id, const char *name) -{ - vs->id = id; - v4l2_video_std_frame_period(id, &vs->frameperiod); - vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625; - strlcpy(vs->name, name, sizeof(vs->name)); - return 0; -} -EXPORT_SYMBOL(v4l2_video_std_construct); - -/* ----------------------------------------------------------------- */ -/* some arrays for pretty-printing debug messages of enum types */ - -const char *v4l2_field_names[] = { - [V4L2_FIELD_ANY] = "any", - [V4L2_FIELD_NONE] = "none", - [V4L2_FIELD_TOP] = "top", - [V4L2_FIELD_BOTTOM] = "bottom", - [V4L2_FIELD_INTERLACED] = "interlaced", - [V4L2_FIELD_SEQ_TB] = "seq-tb", - [V4L2_FIELD_SEQ_BT] = "seq-bt", - [V4L2_FIELD_ALTERNATE] = "alternate", - [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", - [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", -}; -EXPORT_SYMBOL(v4l2_field_names); - -const char *v4l2_type_names[] = { - [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "vid-cap", - [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "vid-overlay", - [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "vid-out", - [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", - [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", - [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", - [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", - [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", - [V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane", - [V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane", -}; -EXPORT_SYMBOL(v4l2_type_names); - -static const char *v4l2_memory_names[] = { - [V4L2_MEMORY_MMAP] = "mmap", - [V4L2_MEMORY_USERPTR] = "userptr", - [V4L2_MEMORY_OVERLAY] = "overlay", -}; - -#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ - arr[a] : "unknown") - -/* ------------------------------------------------------------------ */ -/* debug help functions */ -static const char *v4l2_ioctls[] = { - [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", - [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", - [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", - [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", - [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", - [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", - [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", - [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", - [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", - [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", - [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", - [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", - [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", - [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", - [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", - [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", - [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", - [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", - [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", - [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", - [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", - [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", - [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", - [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", - [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", - [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", - [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", - [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", - [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", - [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", - [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", - [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", - [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", - [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", - [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", - [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", - [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", - [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", - [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", - [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", - [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", - [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", - [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", - [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", - [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", - [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", - [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO", - [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", - [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", - [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", - [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", - [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS", - [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", - [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", - [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", -#if 1 - [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", - [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", - [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX", - [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", - [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", - - [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", - [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", - - [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT", - [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", -#endif - [_IOC_NR(VIDIOC_ENUM_DV_PRESETS)] = "VIDIOC_ENUM_DV_PRESETS", - [_IOC_NR(VIDIOC_S_DV_PRESET)] = "VIDIOC_S_DV_PRESET", - [_IOC_NR(VIDIOC_G_DV_PRESET)] = "VIDIOC_G_DV_PRESET", - [_IOC_NR(VIDIOC_QUERY_DV_PRESET)] = "VIDIOC_QUERY_DV_PRESET", - [_IOC_NR(VIDIOC_S_DV_TIMINGS)] = "VIDIOC_S_DV_TIMINGS", - [_IOC_NR(VIDIOC_G_DV_TIMINGS)] = "VIDIOC_G_DV_TIMINGS", - [_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT", - [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT", - [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT", -}; -#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) - -/* Common ioctl debug function. This function can be used by - external ioctl messages as well as internal V4L ioctl */ -void v4l_printk_ioctl(unsigned int cmd) -{ - char *dir, *type; - - switch (_IOC_TYPE(cmd)) { - case 'd': - type = "v4l2_int"; - break; - case 'V': - if (_IOC_NR(cmd) >= V4L2_IOCTLS) { - type = "v4l2"; - break; - } - printk("%s", v4l2_ioctls[_IOC_NR(cmd)]); - return; - default: - type = "unknown"; - } - - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "*ERR*"; break; - } - printk("%s ioctl '%c', dir=%s, #%d (0x%08x)", - type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); -} -EXPORT_SYMBOL(v4l_printk_ioctl); - -static void dbgbuf(unsigned int cmd, struct video_device *vfd, - struct v4l2_buffer *p) -{ - struct v4l2_timecode *tc = &p->timecode; - struct v4l2_plane *plane; - int i; - - dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " - "flags=0x%08d, field=%0d, sequence=%d, memory=%s\n", - p->timestamp.tv_sec / 3600, - (int)(p->timestamp.tv_sec / 60) % 60, - (int)(p->timestamp.tv_sec % 60), - (long)p->timestamp.tv_usec, - p->index, - prt_names(p->type, v4l2_type_names), - p->flags, p->field, p->sequence, - prt_names(p->memory, v4l2_memory_names)); - - if (V4L2_TYPE_IS_MULTIPLANAR(p->type) && p->m.planes) { - for (i = 0; i < p->length; ++i) { - plane = &p->m.planes[i]; - dbgarg2("plane %d: bytesused=%d, data_offset=0x%08x " - "offset/userptr=0x%08lx, length=%d\n", - i, plane->bytesused, plane->data_offset, - plane->m.userptr, plane->length); - } - } else { - dbgarg2("bytesused=%d, offset/userptr=0x%08lx, length=%d\n", - p->bytesused, p->m.userptr, p->length); - } - - dbgarg2("timecode=%02d:%02d:%02d type=%d, " - "flags=0x%08d, frames=%d, userbits=0x%08x\n", - tc->hours, tc->minutes, tc->seconds, - tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits); -} - -static inline void dbgrect(struct video_device *vfd, char *s, - struct v4l2_rect *r) -{ - dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top, - r->width, r->height); -}; - -static inline void v4l_print_pix_fmt(struct video_device *vfd, - struct v4l2_pix_format *fmt) -{ - dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " - "bytesperline=%d sizeimage=%d, colorspace=%d\n", - fmt->width, fmt->height, - (fmt->pixelformat & 0xff), - (fmt->pixelformat >> 8) & 0xff, - (fmt->pixelformat >> 16) & 0xff, - (fmt->pixelformat >> 24) & 0xff, - prt_names(fmt->field, v4l2_field_names), - fmt->bytesperline, fmt->sizeimage, fmt->colorspace); -}; - -static inline void v4l_print_pix_fmt_mplane(struct video_device *vfd, - struct v4l2_pix_format_mplane *fmt) -{ - int i; - - dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " - "colorspace=%d, num_planes=%d\n", - fmt->width, fmt->height, - (fmt->pixelformat & 0xff), - (fmt->pixelformat >> 8) & 0xff, - (fmt->pixelformat >> 16) & 0xff, - (fmt->pixelformat >> 24) & 0xff, - prt_names(fmt->field, v4l2_field_names), - fmt->colorspace, fmt->num_planes); - - for (i = 0; i < fmt->num_planes; ++i) - dbgarg2("plane %d: bytesperline=%d sizeimage=%d\n", i, - fmt->plane_fmt[i].bytesperline, - fmt->plane_fmt[i].sizeimage); -} - -static inline void v4l_print_ext_ctrls(unsigned int cmd, - struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) -{ - __u32 i; - - if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) - return; - dbgarg(cmd, ""); - printk(KERN_CONT "class=0x%x", c->ctrl_class); - for (i = 0; i < c->count; i++) { - if (show_vals && !c->controls[i].size) - printk(KERN_CONT " id/val=0x%x/0x%x", - c->controls[i].id, c->controls[i].value); - else - printk(KERN_CONT " id=0x%x,size=%u", - c->controls[i].id, c->controls[i].size); - } - printk(KERN_CONT "\n"); -}; - -static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) -{ - __u32 i; - - /* zero the reserved fields */ - c->reserved[0] = c->reserved[1] = 0; - for (i = 0; i < c->count; i++) - c->controls[i].reserved2[0] = 0; - - /* V4L2_CID_PRIVATE_BASE cannot be used as control class - when using extended controls. - Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL - is it allowed for backwards compatibility. - */ - if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) - return 0; - /* Check that all controls are from the same control class. */ - for (i = 0; i < c->count; i++) { - if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { - c->error_idx = i; - return 0; - } - } - return 1; -} - -static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) -{ - if (ops == NULL) - return -EINVAL; - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (ops->vidioc_g_fmt_vid_cap || - ops->vidioc_g_fmt_vid_cap_mplane) - return 0; - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (ops->vidioc_g_fmt_vid_cap_mplane) - return 0; - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (ops->vidioc_g_fmt_vid_overlay) - return 0; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (ops->vidioc_g_fmt_vid_out || - ops->vidioc_g_fmt_vid_out_mplane) - return 0; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (ops->vidioc_g_fmt_vid_out_mplane) - return 0; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (ops->vidioc_g_fmt_vid_out_overlay) - return 0; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (ops->vidioc_g_fmt_vbi_cap) - return 0; - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (ops->vidioc_g_fmt_vbi_out) - return 0; - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (ops->vidioc_g_fmt_sliced_vbi_cap) - return 0; - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (ops->vidioc_g_fmt_sliced_vbi_out) - return 0; - break; - case V4L2_BUF_TYPE_PRIVATE: - if (ops->vidioc_g_fmt_type_private) - return 0; - break; - } - return -EINVAL; -} - -/** - * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane - * equivalent - */ -static int fmt_sp_to_mp(const struct v4l2_format *f_sp, - struct v4l2_format *f_mp) -{ - struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; - const struct v4l2_pix_format *pix = &f_sp->fmt.pix; - - if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - else - return -EINVAL; - - pix_mp->width = pix->width; - pix_mp->height = pix->height; - pix_mp->pixelformat = pix->pixelformat; - pix_mp->field = pix->field; - pix_mp->colorspace = pix->colorspace; - pix_mp->num_planes = 1; - pix_mp->plane_fmt[0].sizeimage = pix->sizeimage; - pix_mp->plane_fmt[0].bytesperline = pix->bytesperline; - - return 0; -} - -/** - * fmt_mp_to_sp() - Convert a multi-planar 1-plane format to its single-planar - * equivalent - */ -static int fmt_mp_to_sp(const struct v4l2_format *f_mp, - struct v4l2_format *f_sp) -{ - const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; - struct v4l2_pix_format *pix = &f_sp->fmt.pix; - - if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - else - return -EINVAL; - - pix->width = pix_mp->width; - pix->height = pix_mp->height; - pix->pixelformat = pix_mp->pixelformat; - pix->field = pix_mp->field; - pix->colorspace = pix_mp->colorspace; - pix->sizeimage = pix_mp->plane_fmt[0].sizeimage; - pix->bytesperline = pix_mp->plane_fmt[0].bytesperline; - - return 0; -} - -static long __video_do_ioctl(struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *vfd = video_devdata(file); - const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; - void *fh = file->private_data; - struct v4l2_fh *vfh = NULL; - struct v4l2_format f_copy; - int use_fh_prio = 0; - long ret = -EINVAL; - - if (ops == NULL) { - printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n", - vfd->name); - return -EINVAL; - } - - if ((vfd->debug & V4L2_DEBUG_IOCTL) && - !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) { - v4l_print_ioctl(vfd->name, cmd); - printk(KERN_CONT "\n"); - } - - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { - vfh = file->private_data; - use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); - } - - if (use_fh_prio) { - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - case VIDIOC_S_FMT: - case VIDIOC_S_CROP: - case VIDIOC_S_AUDIO: - case VIDIOC_S_AUDOUT: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_S_FBUF: - case VIDIOC_S_PRIORITY: - case VIDIOC_S_DV_PRESET: - case VIDIOC_S_DV_TIMINGS: - case VIDIOC_S_JPEGCOMP: - case VIDIOC_S_MODULATOR: - case VIDIOC_S_PARM: - case VIDIOC_S_HW_FREQ_SEEK: - case VIDIOC_ENCODER_CMD: - case VIDIOC_OVERLAY: - case VIDIOC_REQBUFS: - case VIDIOC_STREAMON: - case VIDIOC_STREAMOFF: - ret = v4l2_prio_check(vfd->prio, vfh->prio); - if (ret) - goto exit_prio; - ret = -EINVAL; - break; - } - } - - switch (cmd) { - - /* --- capabilities ------------------------------------------ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = (struct v4l2_capability *)arg; - - if (!ops->vidioc_querycap) - break; - - ret = ops->vidioc_querycap(file, fh, cap); - if (!ret) - dbgarg(cmd, "driver=%s, card=%s, bus=%s, " - "version=0x%08x, " - "capabilities=0x%08x\n", - cap->driver, cap->card, cap->bus_info, - cap->version, - cap->capabilities); - break; - } - - /* --- priority ------------------------------------------ */ - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; - - if (ops->vidioc_g_priority) { - ret = ops->vidioc_g_priority(file, fh, p); - } else if (use_fh_prio) { - *p = v4l2_prio_max(&vfd->v4l2_dev->prio); - ret = 0; - } - if (!ret) - dbgarg(cmd, "priority is %d\n", *p); - break; - } - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *p = arg; - - if (!ops->vidioc_s_priority && !use_fh_prio) - break; - dbgarg(cmd, "setting priority to %d\n", *p); - if (ops->vidioc_s_priority) - ret = ops->vidioc_s_priority(file, fh, *p); - else - ret = v4l2_prio_change(&vfd->v4l2_dev->prio, &vfh->prio, *p); - break; - } - - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (ops->vidioc_enum_fmt_vid_cap) - ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (ops->vidioc_enum_fmt_vid_cap_mplane) - ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (ops->vidioc_enum_fmt_vid_overlay) - ret = ops->vidioc_enum_fmt_vid_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (ops->vidioc_enum_fmt_vid_out) - ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (ops->vidioc_enum_fmt_vid_out_mplane) - ret = ops->vidioc_enum_fmt_vid_out_mplane(file, - fh, f); - break; - case V4L2_BUF_TYPE_PRIVATE: - if (ops->vidioc_enum_fmt_type_private) - ret = ops->vidioc_enum_fmt_type_private(file, - fh, f); - break; - default: - break; - } - if (!ret) - dbgarg(cmd, "index=%d, type=%d, flags=%d, " - "pixelformat=%c%c%c%c, description='%s'\n", - f->index, f->type, f->flags, - (f->pixelformat & 0xff), - (f->pixelformat >> 8) & 0xff, - (f->pixelformat >> 16) & 0xff, - (f->pixelformat >> 24) & 0xff, - f->description); - break; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = (struct v4l2_format *)arg; - - /* FIXME: Should be one dump per type */ - dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (ops->vidioc_g_fmt_vid_cap) { - ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); - } else if (ops->vidioc_g_fmt_vid_cap_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh, - &f_copy); - if (ret) - break; - - /* Driver is currently in multi-planar format, - * we can't return it in single-planar API*/ - if (f_copy.fmt.pix_mp.num_planes > 1) { - ret = -EBUSY; - break; - } - - ret = fmt_mp_to_sp(&f_copy, f); - } - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (ops->vidioc_g_fmt_vid_cap_mplane) { - ret = ops->vidioc_g_fmt_vid_cap_mplane(file, - fh, f); - } else if (ops->vidioc_g_fmt_vid_cap) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_g_fmt_vid_cap(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } - if (!ret) - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (ops->vidioc_g_fmt_vid_overlay) - ret = ops->vidioc_g_fmt_vid_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (ops->vidioc_g_fmt_vid_out) { - ret = ops->vidioc_g_fmt_vid_out(file, fh, f); - } else if (ops->vidioc_g_fmt_vid_out_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_g_fmt_vid_out_mplane(file, fh, - &f_copy); - if (ret) - break; - - /* Driver is currently in multi-planar format, - * we can't return it in single-planar API*/ - if (f_copy.fmt.pix_mp.num_planes > 1) { - ret = -EBUSY; - break; - } - - ret = fmt_mp_to_sp(&f_copy, f); - } - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (ops->vidioc_g_fmt_vid_out_mplane) { - ret = ops->vidioc_g_fmt_vid_out_mplane(file, - fh, f); - } else if (ops->vidioc_g_fmt_vid_out) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_g_fmt_vid_out(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } - if (!ret) - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (ops->vidioc_g_fmt_vid_out_overlay) - ret = ops->vidioc_g_fmt_vid_out_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (ops->vidioc_g_fmt_vbi_cap) - ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (ops->vidioc_g_fmt_vbi_out) - ret = ops->vidioc_g_fmt_vbi_out(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (ops->vidioc_g_fmt_sliced_vbi_cap) - ret = ops->vidioc_g_fmt_sliced_vbi_cap(file, - fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (ops->vidioc_g_fmt_sliced_vbi_out) - ret = ops->vidioc_g_fmt_sliced_vbi_out(file, - fh, f); - break; - case V4L2_BUF_TYPE_PRIVATE: - if (ops->vidioc_g_fmt_type_private) - ret = ops->vidioc_g_fmt_type_private(file, - fh, f); - break; - } - - break; - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = (struct v4l2_format *)arg; - - /* FIXME: Should be one dump per type */ - dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.pix); - v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (ops->vidioc_s_fmt_vid_cap) { - ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); - } else if (ops->vidioc_s_fmt_vid_cap_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh, - &f_copy); - if (ret) - break; - - if (f_copy.fmt.pix_mp.num_planes > 1) { - /* Drivers shouldn't adjust from 1-plane - * to more than 1-plane formats */ - ret = -EBUSY; - WARN_ON(1); - break; - } - - ret = fmt_mp_to_sp(&f_copy, f); - } - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - CLEAR_AFTER_FIELD(f, fmt.pix_mp); - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - if (ops->vidioc_s_fmt_vid_cap_mplane) { - ret = ops->vidioc_s_fmt_vid_cap_mplane(file, - fh, f); - } else if (ops->vidioc_s_fmt_vid_cap && - f->fmt.pix_mp.num_planes == 1) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_s_fmt_vid_cap(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_s_fmt_vid_overlay) - ret = ops->vidioc_s_fmt_vid_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.pix); - v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (ops->vidioc_s_fmt_vid_out) { - ret = ops->vidioc_s_fmt_vid_out(file, fh, f); - } else if (ops->vidioc_s_fmt_vid_out_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_s_fmt_vid_out_mplane(file, fh, - &f_copy); - if (ret) - break; - - if (f_copy.fmt.pix_mp.num_planes > 1) { - /* Drivers shouldn't adjust from 1-plane - * to more than 1-plane formats */ - ret = -EBUSY; - WARN_ON(1); - break; - } - - ret = fmt_mp_to_sp(&f_copy, f); - } - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - CLEAR_AFTER_FIELD(f, fmt.pix_mp); - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - if (ops->vidioc_s_fmt_vid_out_mplane) { - ret = ops->vidioc_s_fmt_vid_out_mplane(file, - fh, f); - } else if (ops->vidioc_s_fmt_vid_out && - f->fmt.pix_mp.num_planes == 1) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_s_fmt_vid_out(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_mp_to_sp(&f_copy, f); - } - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_s_fmt_vid_out_overlay) - ret = ops->vidioc_s_fmt_vid_out_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_s_fmt_vbi_cap) - ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_s_fmt_vbi_out) - ret = ops->vidioc_s_fmt_vbi_out(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_s_fmt_sliced_vbi_cap) - ret = ops->vidioc_s_fmt_sliced_vbi_cap(file, - fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_s_fmt_sliced_vbi_out) - ret = ops->vidioc_s_fmt_sliced_vbi_out(file, - fh, f); - break; - case V4L2_BUF_TYPE_PRIVATE: - /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */ - if (ops->vidioc_s_fmt_type_private) - ret = ops->vidioc_s_fmt_type_private(file, - fh, f); - break; - } - break; - } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = (struct v4l2_format *)arg; - - /* FIXME: Should be one dump per type */ - dbgarg(cmd, "type=%s\n", prt_names(f->type, - v4l2_type_names)); - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.pix); - if (ops->vidioc_try_fmt_vid_cap) { - ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); - } else if (ops->vidioc_try_fmt_vid_cap_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_try_fmt_vid_cap_mplane(file, - fh, &f_copy); - if (ret) - break; - - if (f_copy.fmt.pix_mp.num_planes > 1) { - /* Drivers shouldn't adjust from 1-plane - * to more than 1-plane formats */ - ret = -EBUSY; - WARN_ON(1); - break; - } - ret = fmt_mp_to_sp(&f_copy, f); - } - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - CLEAR_AFTER_FIELD(f, fmt.pix_mp); - if (ops->vidioc_try_fmt_vid_cap_mplane) { - ret = ops->vidioc_try_fmt_vid_cap_mplane(file, - fh, f); - } else if (ops->vidioc_try_fmt_vid_cap && - f->fmt.pix_mp.num_planes == 1) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_try_fmt_vid_cap(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } - if (!ret) - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_try_fmt_vid_overlay) - ret = ops->vidioc_try_fmt_vid_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.pix); - if (ops->vidioc_try_fmt_vid_out) { - ret = ops->vidioc_try_fmt_vid_out(file, fh, f); - } else if (ops->vidioc_try_fmt_vid_out_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_try_fmt_vid_out_mplane(file, - fh, &f_copy); - if (ret) - break; - - if (f_copy.fmt.pix_mp.num_planes > 1) { - /* Drivers shouldn't adjust from 1-plane - * to more than 1-plane formats */ - ret = -EBUSY; - WARN_ON(1); - break; - } - ret = fmt_mp_to_sp(&f_copy, f); - } - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - CLEAR_AFTER_FIELD(f, fmt.pix_mp); - if (ops->vidioc_try_fmt_vid_out_mplane) { - ret = ops->vidioc_try_fmt_vid_out_mplane(file, - fh, f); - } else if (ops->vidioc_try_fmt_vid_out && - f->fmt.pix_mp.num_planes == 1) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_try_fmt_vid_out(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } - if (!ret) - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_try_fmt_vid_out_overlay) - ret = ops->vidioc_try_fmt_vid_out_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_try_fmt_vbi_cap) - ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_try_fmt_vbi_out) - ret = ops->vidioc_try_fmt_vbi_out(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_try_fmt_sliced_vbi_cap) - ret = ops->vidioc_try_fmt_sliced_vbi_cap(file, - fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_try_fmt_sliced_vbi_out) - ret = ops->vidioc_try_fmt_sliced_vbi_out(file, - fh, f); - break; - case V4L2_BUF_TYPE_PRIVATE: - /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */ - if (ops->vidioc_try_fmt_type_private) - ret = ops->vidioc_try_fmt_type_private(file, - fh, f); - break; - } - - break; - } - /* FIXME: Those buf reqs could be handled here, - with some changes on videobuf to allow its header to be included at - videodev2.h or being merged at videodev2. - */ - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *p = arg; - - if (!ops->vidioc_reqbufs) - break; - ret = check_fmt(ops, p->type); - if (ret) - break; - - if (p->type < V4L2_BUF_TYPE_PRIVATE) - CLEAR_AFTER_FIELD(p, memory); - - ret = ops->vidioc_reqbufs(file, fh, p); - dbgarg(cmd, "count=%d, type=%s, memory=%s\n", - p->count, - prt_names(p->type, v4l2_type_names), - prt_names(p->memory, v4l2_memory_names)); - break; - } - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *p = arg; - - if (!ops->vidioc_querybuf) - break; - ret = check_fmt(ops, p->type); - if (ret) - break; - - ret = ops->vidioc_querybuf(file, fh, p); - if (!ret) - dbgbuf(cmd, vfd, p); - break; - } - case VIDIOC_QBUF: - { - struct v4l2_buffer *p = arg; - - if (!ops->vidioc_qbuf) - break; - ret = check_fmt(ops, p->type); - if (ret) - break; - - ret = ops->vidioc_qbuf(file, fh, p); - if (!ret) - dbgbuf(cmd, vfd, p); - break; - } - case VIDIOC_DQBUF: - { - struct v4l2_buffer *p = arg; - - if (!ops->vidioc_dqbuf) - break; - ret = check_fmt(ops, p->type); - if (ret) - break; - - ret = ops->vidioc_dqbuf(file, fh, p); - if (!ret) - dbgbuf(cmd, vfd, p); - break; - } - case VIDIOC_OVERLAY: - { - int *i = arg; - - if (!ops->vidioc_overlay) - break; - dbgarg(cmd, "value=%d\n", *i); - ret = ops->vidioc_overlay(file, fh, *i); - break; - } - case VIDIOC_G_FBUF: - { - struct v4l2_framebuffer *p = arg; - - if (!ops->vidioc_g_fbuf) - break; - ret = ops->vidioc_g_fbuf(file, fh, arg); - if (!ret) { - dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", - p->capability, p->flags, - (unsigned long)p->base); - v4l_print_pix_fmt(vfd, &p->fmt); - } - break; - } - case VIDIOC_S_FBUF: - { - struct v4l2_framebuffer *p = arg; - - if (!ops->vidioc_s_fbuf) - break; - dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", - p->capability, p->flags, (unsigned long)p->base); - v4l_print_pix_fmt(vfd, &p->fmt); - ret = ops->vidioc_s_fbuf(file, fh, arg); - break; - } - case VIDIOC_STREAMON: - { - enum v4l2_buf_type i = *(int *)arg; - - if (!ops->vidioc_streamon) - break; - dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret = ops->vidioc_streamon(file, fh, i); - break; - } - case VIDIOC_STREAMOFF: - { - enum v4l2_buf_type i = *(int *)arg; - - if (!ops->vidioc_streamoff) - break; - dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret = ops->vidioc_streamoff(file, fh, i); - break; - } - /* ---------- tv norms ---------- */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *p = arg; - v4l2_std_id id = vfd->tvnorms, curr_id = 0; - unsigned int index = p->index, i, j = 0; - const char *descr = ""; - - /* Return norm array in a canonical way */ - for (i = 0; i <= index && id; i++) { - /* last std value in the standards array is 0, so this - while always ends there since (id & 0) == 0. */ - while ((id & standards[j].std) != standards[j].std) - j++; - curr_id = standards[j].std; - descr = standards[j].descr; - j++; - if (curr_id == 0) - break; - if (curr_id != V4L2_STD_PAL && - curr_id != V4L2_STD_SECAM && - curr_id != V4L2_STD_NTSC) - id &= ~curr_id; - } - if (i <= index) - break; - - v4l2_video_std_construct(p, curr_id, descr); - - dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, " - "framelines=%d\n", p->index, - (unsigned long long)p->id, p->name, - p->frameperiod.numerator, - p->frameperiod.denominator, - p->framelines); - - ret = 0; - break; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - - ret = 0; - /* Calls the specific handler */ - if (ops->vidioc_g_std) - ret = ops->vidioc_g_std(file, fh, id); - else if (vfd->current_norm) - *id = vfd->current_norm; - else - ret = -EINVAL; - - if (!ret) - dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); - break; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg, norm; - - dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id); - - norm = (*id) & vfd->tvnorms; - if (vfd->tvnorms && !norm) /* Check if std is supported */ - break; - - /* Calls the specific handler */ - if (ops->vidioc_s_std) - ret = ops->vidioc_s_std(file, fh, &norm); - else - ret = -EINVAL; - - /* Updates standard information */ - if (ret >= 0) - vfd->current_norm = norm; - break; - } - case VIDIOC_QUERYSTD: - { - v4l2_std_id *p = arg; - - if (!ops->vidioc_querystd) - break; - ret = ops->vidioc_querystd(file, fh, arg); - if (!ret) - dbgarg(cmd, "detected std=%08Lx\n", - (unsigned long long)*p); - break; - } - /* ------ input switching ---------- */ - /* FIXME: Inputs can be handled inside videodev2 */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *p = arg; - - /* - * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & - * CAP_STD here based on ioctl handler provided by the - * driver. If the driver doesn't support these - * for a specific input, it must override these flags. - */ - if (ops->vidioc_s_std) - p->capabilities |= V4L2_IN_CAP_STD; - if (ops->vidioc_s_dv_preset) - p->capabilities |= V4L2_IN_CAP_PRESETS; - if (ops->vidioc_s_dv_timings) - p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS; - - if (!ops->vidioc_enum_input) - break; - - ret = ops->vidioc_enum_input(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "audioset=%d, " - "tuner=%d, std=%08Lx, status=%d\n", - p->index, p->name, p->type, p->audioset, - p->tuner, - (unsigned long long)p->std, - p->status); - break; - } - case VIDIOC_G_INPUT: - { - unsigned int *i = arg; - - if (!ops->vidioc_g_input) - break; - ret = ops->vidioc_g_input(file, fh, i); - if (!ret) - dbgarg(cmd, "value=%d\n", *i); - break; - } - case VIDIOC_S_INPUT: - { - unsigned int *i = arg; - - if (!ops->vidioc_s_input) - break; - dbgarg(cmd, "value=%d\n", *i); - ret = ops->vidioc_s_input(file, fh, *i); - break; - } - - /* ------ output switching ---------- */ - case VIDIOC_ENUMOUTPUT: - { - struct v4l2_output *p = arg; - - if (!ops->vidioc_enum_output) - break; - - /* - * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & - * CAP_STD here based on ioctl handler provided by the - * driver. If the driver doesn't support these - * for a specific output, it must override these flags. - */ - if (ops->vidioc_s_std) - p->capabilities |= V4L2_OUT_CAP_STD; - if (ops->vidioc_s_dv_preset) - p->capabilities |= V4L2_OUT_CAP_PRESETS; - if (ops->vidioc_s_dv_timings) - p->capabilities |= V4L2_OUT_CAP_CUSTOM_TIMINGS; - - ret = ops->vidioc_enum_output(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "audioset=0x%x, " - "modulator=%d, std=0x%08Lx\n", - p->index, p->name, p->type, p->audioset, - p->modulator, (unsigned long long)p->std); - break; - } - case VIDIOC_G_OUTPUT: - { - unsigned int *i = arg; - - if (!ops->vidioc_g_output) - break; - ret = ops->vidioc_g_output(file, fh, i); - if (!ret) - dbgarg(cmd, "value=%d\n", *i); - break; - } - case VIDIOC_S_OUTPUT: - { - unsigned int *i = arg; - - if (!ops->vidioc_s_output) - break; - dbgarg(cmd, "value=%d\n", *i); - ret = ops->vidioc_s_output(file, fh, *i); - break; - } - - /* --- controls ---------------------------------------------- */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *p = arg; - - if (vfd->ctrl_handler) - ret = v4l2_queryctrl(vfd->ctrl_handler, p); - else if (ops->vidioc_queryctrl) - ret = ops->vidioc_queryctrl(file, fh, p); - else - break; - if (!ret) - dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " - "step=%d, default=%d, flags=0x%08x\n", - p->id, p->type, p->name, - p->minimum, p->maximum, - p->step, p->default_value, p->flags); - else - dbgarg(cmd, "id=0x%x\n", p->id); - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *p = arg; - - if (vfd->ctrl_handler) - ret = v4l2_g_ctrl(vfd->ctrl_handler, p); - else if (ops->vidioc_g_ctrl) - ret = ops->vidioc_g_ctrl(file, fh, p); - else if (ops->vidioc_g_ext_ctrls) { - struct v4l2_ext_controls ctrls; - struct v4l2_ext_control ctrl; - - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); - ctrls.count = 1; - ctrls.controls = &ctrl; - ctrl.id = p->id; - ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) { - ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); - if (ret == 0) - p->value = ctrl.value; - } - } else - break; - if (!ret) - dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); - else - dbgarg(cmd, "id=0x%x\n", p->id); - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *p = arg; - struct v4l2_ext_controls ctrls; - struct v4l2_ext_control ctrl; - - if (!vfd->ctrl_handler && - !ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls) - break; - - dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); - - if (vfd->ctrl_handler) { - ret = v4l2_s_ctrl(vfd->ctrl_handler, p); - break; - } - if (ops->vidioc_s_ctrl) { - ret = ops->vidioc_s_ctrl(file, fh, p); - break; - } - if (!ops->vidioc_s_ext_ctrls) - break; - - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); - ctrls.count = 1; - ctrls.controls = &ctrl; - ctrl.id = p->id; - ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) - ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); - break; - } - case VIDIOC_G_EXT_CTRLS: - { - struct v4l2_ext_controls *p = arg; - - p->error_idx = p->count; - if (vfd->ctrl_handler) - ret = v4l2_g_ext_ctrls(vfd->ctrl_handler, p); - else if (ops->vidioc_g_ext_ctrls && check_ext_ctrls(p, 0)) - ret = ops->vidioc_g_ext_ctrls(file, fh, p); - else - break; - v4l_print_ext_ctrls(cmd, vfd, p, !ret); - break; - } - case VIDIOC_S_EXT_CTRLS: - { - struct v4l2_ext_controls *p = arg; - - p->error_idx = p->count; - if (!vfd->ctrl_handler && !ops->vidioc_s_ext_ctrls) - break; - v4l_print_ext_ctrls(cmd, vfd, p, 1); - if (vfd->ctrl_handler) - ret = v4l2_s_ext_ctrls(vfd->ctrl_handler, p); - else if (check_ext_ctrls(p, 0)) - ret = ops->vidioc_s_ext_ctrls(file, fh, p); - break; - } - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *p = arg; - - p->error_idx = p->count; - if (!vfd->ctrl_handler && !ops->vidioc_try_ext_ctrls) - break; - v4l_print_ext_ctrls(cmd, vfd, p, 1); - if (vfd->ctrl_handler) - ret = v4l2_try_ext_ctrls(vfd->ctrl_handler, p); - else if (check_ext_ctrls(p, 0)) - ret = ops->vidioc_try_ext_ctrls(file, fh, p); - break; - } - case VIDIOC_QUERYMENU: - { - struct v4l2_querymenu *p = arg; - - if (vfd->ctrl_handler) - ret = v4l2_querymenu(vfd->ctrl_handler, p); - else if (ops->vidioc_querymenu) - ret = ops->vidioc_querymenu(file, fh, p); - else - break; - if (!ret) - dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", - p->id, p->index, p->name); - else - dbgarg(cmd, "id=0x%x, index=%d\n", - p->id, p->index); - break; - } - /* --- audio ---------------------------------------------- */ - case VIDIOC_ENUMAUDIO: - { - struct v4l2_audio *p = arg; - - if (!ops->vidioc_enumaudio) - break; - ret = ops->vidioc_enumaudio(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " - "mode=0x%x\n", p->index, p->name, - p->capability, p->mode); - else - dbgarg(cmd, "index=%d\n", p->index); - break; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *p = arg; - - if (!ops->vidioc_g_audio) - break; - - ret = ops->vidioc_g_audio(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " - "mode=0x%x\n", p->index, - p->name, p->capability, p->mode); - else - dbgarg(cmd, "index=%d\n", p->index); - break; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *p = arg; - - if (!ops->vidioc_s_audio) - break; - dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " - "mode=0x%x\n", p->index, p->name, - p->capability, p->mode); - ret = ops->vidioc_s_audio(file, fh, p); - break; - } - case VIDIOC_ENUMAUDOUT: - { - struct v4l2_audioout *p = arg; - - if (!ops->vidioc_enumaudout) - break; - dbgarg(cmd, "Enum for index=%d\n", p->index); - ret = ops->vidioc_enumaudout(file, fh, p); - if (!ret) - dbgarg2("index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, - p->capability, p->mode); - break; - } - case VIDIOC_G_AUDOUT: - { - struct v4l2_audioout *p = arg; - - if (!ops->vidioc_g_audout) - break; - - ret = ops->vidioc_g_audout(file, fh, p); - if (!ret) - dbgarg2("index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, - p->capability, p->mode); - break; - } - case VIDIOC_S_AUDOUT: - { - struct v4l2_audioout *p = arg; - - if (!ops->vidioc_s_audout) - break; - dbgarg(cmd, "index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, - p->capability, p->mode); - - ret = ops->vidioc_s_audout(file, fh, p); - break; - } - case VIDIOC_G_MODULATOR: - { - struct v4l2_modulator *p = arg; - - if (!ops->vidioc_g_modulator) - break; - ret = ops->vidioc_g_modulator(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, " - "capability=%d, rangelow=%d," - " rangehigh=%d, txsubchans=%d\n", - p->index, p->name, p->capability, - p->rangelow, p->rangehigh, - p->txsubchans); - break; - } - case VIDIOC_S_MODULATOR: - { - struct v4l2_modulator *p = arg; - - if (!ops->vidioc_s_modulator) - break; - dbgarg(cmd, "index=%d, name=%s, capability=%d, " - "rangelow=%d, rangehigh=%d, txsubchans=%d\n", - p->index, p->name, p->capability, p->rangelow, - p->rangehigh, p->txsubchans); - ret = ops->vidioc_s_modulator(file, fh, p); - break; - } - case VIDIOC_G_CROP: - { - struct v4l2_crop *p = arg; - - if (!ops->vidioc_g_crop) - break; - - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = ops->vidioc_g_crop(file, fh, p); - if (!ret) - dbgrect(vfd, "", &p->c); - break; - } - case VIDIOC_S_CROP: - { - struct v4l2_crop *p = arg; - - if (!ops->vidioc_s_crop) - break; - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - dbgrect(vfd, "", &p->c); - ret = ops->vidioc_s_crop(file, fh, p); - break; - } - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *p = arg; - - /*FIXME: Should also show v4l2_fract pixelaspect */ - if (!ops->vidioc_cropcap) - break; - - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = ops->vidioc_cropcap(file, fh, p); - if (!ret) { - dbgrect(vfd, "bounds ", &p->bounds); - dbgrect(vfd, "defrect ", &p->defrect); - } - break; - } - case VIDIOC_G_JPEGCOMP: - { - struct v4l2_jpegcompression *p = arg; - - if (!ops->vidioc_g_jpegcomp) - break; - - ret = ops->vidioc_g_jpegcomp(file, fh, p); - if (!ret) - dbgarg(cmd, "quality=%d, APPn=%d, " - "APP_len=%d, COM_len=%d, " - "jpeg_markers=%d\n", - p->quality, p->APPn, p->APP_len, - p->COM_len, p->jpeg_markers); - break; - } - case VIDIOC_S_JPEGCOMP: - { - struct v4l2_jpegcompression *p = arg; - - if (!ops->vidioc_g_jpegcomp) - break; - dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, " - "COM_len=%d, jpeg_markers=%d\n", - p->quality, p->APPn, p->APP_len, - p->COM_len, p->jpeg_markers); - ret = ops->vidioc_s_jpegcomp(file, fh, p); - break; - } - case VIDIOC_G_ENC_INDEX: - { - struct v4l2_enc_idx *p = arg; - - if (!ops->vidioc_g_enc_index) - break; - ret = ops->vidioc_g_enc_index(file, fh, p); - if (!ret) - dbgarg(cmd, "entries=%d, entries_cap=%d\n", - p->entries, p->entries_cap); - break; - } - case VIDIOC_ENCODER_CMD: - { - struct v4l2_encoder_cmd *p = arg; - - if (!ops->vidioc_encoder_cmd) - break; - ret = ops->vidioc_encoder_cmd(file, fh, p); - if (!ret) - dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); - break; - } - case VIDIOC_TRY_ENCODER_CMD: - { - struct v4l2_encoder_cmd *p = arg; - - if (!ops->vidioc_try_encoder_cmd) - break; - ret = ops->vidioc_try_encoder_cmd(file, fh, p); - if (!ret) - dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); - break; - } - case VIDIOC_G_PARM: - { - struct v4l2_streamparm *p = arg; - - if (ops->vidioc_g_parm) { - ret = check_fmt(ops, p->type); - if (ret) - break; - ret = ops->vidioc_g_parm(file, fh, p); - } else { - v4l2_std_id std = vfd->current_norm; - - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - break; - - ret = 0; - if (ops->vidioc_g_std) - ret = ops->vidioc_g_std(file, fh, &std); - else if (std == 0) - ret = -EINVAL; - if (ret == 0) - v4l2_video_std_frame_period(std, - &p->parm.capture.timeperframe); - } - - dbgarg(cmd, "type=%d\n", p->type); - break; - } - case VIDIOC_S_PARM: - { - struct v4l2_streamparm *p = arg; - - if (!ops->vidioc_s_parm) - break; - ret = check_fmt(ops, p->type); - if (ret) - break; - - dbgarg(cmd, "type=%d\n", p->type); - ret = ops->vidioc_s_parm(file, fh, p); - break; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *p = arg; - - if (!ops->vidioc_g_tuner) - break; - - ret = ops->vidioc_g_tuner(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "capability=0x%x, rangelow=%d, " - "rangehigh=%d, signal=%d, afc=%d, " - "rxsubchans=0x%x, audmode=%d\n", - p->index, p->name, p->type, - p->capability, p->rangelow, - p->rangehigh, p->signal, p->afc, - p->rxsubchans, p->audmode); - break; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *p = arg; - - if (!ops->vidioc_s_tuner) - break; - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "capability=0x%x, rangelow=%d, " - "rangehigh=%d, signal=%d, afc=%d, " - "rxsubchans=0x%x, audmode=%d\n", - p->index, p->name, p->type, - p->capability, p->rangelow, - p->rangehigh, p->signal, p->afc, - p->rxsubchans, p->audmode); - ret = ops->vidioc_s_tuner(file, fh, p); - break; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *p = arg; - - if (!ops->vidioc_g_frequency) - break; - - ret = ops->vidioc_g_frequency(file, fh, p); - if (!ret) - dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", - p->tuner, p->type, p->frequency); - break; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *p = arg; - - if (!ops->vidioc_s_frequency) - break; - dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", - p->tuner, p->type, p->frequency); - ret = ops->vidioc_s_frequency(file, fh, p); - break; - } - case VIDIOC_G_SLICED_VBI_CAP: - { - struct v4l2_sliced_vbi_cap *p = arg; - - if (!ops->vidioc_g_sliced_vbi_cap) - break; - - /* Clear up to type, everything after type is zerod already */ - memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type)); - - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p); - if (!ret) - dbgarg2("service_set=%d\n", p->service_set); - break; - } - case VIDIOC_LOG_STATUS: - { - if (!ops->vidioc_log_status) - break; - ret = ops->vidioc_log_status(file, fh); - break; - } -#ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_G_REGISTER: - { - struct v4l2_dbg_register *p = arg; - - if (ops->vidioc_g_register) { - if (!capable(CAP_SYS_ADMIN)) - ret = -EPERM; - else - ret = ops->vidioc_g_register(file, fh, p); - } - break; - } - case VIDIOC_DBG_S_REGISTER: - { - struct v4l2_dbg_register *p = arg; - - if (ops->vidioc_s_register) { - if (!capable(CAP_SYS_ADMIN)) - ret = -EPERM; - else - ret = ops->vidioc_s_register(file, fh, p); - } - break; - } -#endif - case VIDIOC_DBG_G_CHIP_IDENT: - { - struct v4l2_dbg_chip_ident *p = arg; - - if (!ops->vidioc_g_chip_ident) - break; - p->ident = V4L2_IDENT_NONE; - p->revision = 0; - ret = ops->vidioc_g_chip_ident(file, fh, p); - if (!ret) - dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); - break; - } - case VIDIOC_S_HW_FREQ_SEEK: - { - struct v4l2_hw_freq_seek *p = arg; - - if (!ops->vidioc_s_hw_freq_seek) - break; - dbgarg(cmd, - "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", - p->tuner, p->type, p->seek_upward, p->wrap_around); - ret = ops->vidioc_s_hw_freq_seek(file, fh, p); - break; - } - case VIDIOC_ENUM_FRAMESIZES: - { - struct v4l2_frmsizeenum *p = arg; - - if (!ops->vidioc_enum_framesizes) - break; - - ret = ops->vidioc_enum_framesizes(file, fh, p); - dbgarg(cmd, - "index=%d, pixelformat=%c%c%c%c, type=%d ", - p->index, - (p->pixel_format & 0xff), - (p->pixel_format >> 8) & 0xff, - (p->pixel_format >> 16) & 0xff, - (p->pixel_format >> 24) & 0xff, - p->type); - switch (p->type) { - case V4L2_FRMSIZE_TYPE_DISCRETE: - dbgarg3("width = %d, height=%d\n", - p->discrete.width, p->discrete.height); - break; - case V4L2_FRMSIZE_TYPE_STEPWISE: - dbgarg3("min %dx%d, max %dx%d, step %dx%d\n", - p->stepwise.min_width, p->stepwise.min_height, - p->stepwise.step_width, p->stepwise.step_height, - p->stepwise.max_width, p->stepwise.max_height); - break; - case V4L2_FRMSIZE_TYPE_CONTINUOUS: - dbgarg3("continuous\n"); - break; - default: - dbgarg3("- Unknown type!\n"); - } - - break; - } - case VIDIOC_ENUM_FRAMEINTERVALS: - { - struct v4l2_frmivalenum *p = arg; - - if (!ops->vidioc_enum_frameintervals) - break; - - ret = ops->vidioc_enum_frameintervals(file, fh, p); - dbgarg(cmd, - "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ", - p->index, p->pixel_format, - p->width, p->height, p->type); - switch (p->type) { - case V4L2_FRMIVAL_TYPE_DISCRETE: - dbgarg2("fps=%d/%d\n", - p->discrete.numerator, - p->discrete.denominator); - break; - case V4L2_FRMIVAL_TYPE_STEPWISE: - dbgarg2("min=%d/%d, max=%d/%d, step=%d/%d\n", - p->stepwise.min.numerator, - p->stepwise.min.denominator, - p->stepwise.max.numerator, - p->stepwise.max.denominator, - p->stepwise.step.numerator, - p->stepwise.step.denominator); - break; - case V4L2_FRMIVAL_TYPE_CONTINUOUS: - dbgarg2("continuous\n"); - break; - default: - dbgarg2("- Unknown type!\n"); - } - break; - } - case VIDIOC_ENUM_DV_PRESETS: - { - struct v4l2_dv_enum_preset *p = arg; - - if (!ops->vidioc_enum_dv_presets) - break; - - ret = ops->vidioc_enum_dv_presets(file, fh, p); - if (!ret) - dbgarg(cmd, - "index=%d, preset=%d, name=%s, width=%d," - " height=%d ", - p->index, p->preset, p->name, p->width, - p->height); - break; - } - case VIDIOC_S_DV_PRESET: - { - struct v4l2_dv_preset *p = arg; - - if (!ops->vidioc_s_dv_preset) - break; - - dbgarg(cmd, "preset=%d\n", p->preset); - ret = ops->vidioc_s_dv_preset(file, fh, p); - break; - } - case VIDIOC_G_DV_PRESET: - { - struct v4l2_dv_preset *p = arg; - - if (!ops->vidioc_g_dv_preset) - break; - - ret = ops->vidioc_g_dv_preset(file, fh, p); - if (!ret) - dbgarg(cmd, "preset=%d\n", p->preset); - break; - } - case VIDIOC_QUERY_DV_PRESET: - { - struct v4l2_dv_preset *p = arg; - - if (!ops->vidioc_query_dv_preset) - break; - - ret = ops->vidioc_query_dv_preset(file, fh, p); - if (!ret) - dbgarg(cmd, "preset=%d\n", p->preset); - break; - } - case VIDIOC_S_DV_TIMINGS: - { - struct v4l2_dv_timings *p = arg; - - if (!ops->vidioc_s_dv_timings) - break; - - switch (p->type) { - case V4L2_DV_BT_656_1120: - dbgarg2("bt-656/1120:interlaced=%d, pixelclock=%lld," - " width=%d, height=%d, polarities=%x," - " hfrontporch=%d, hsync=%d, hbackporch=%d," - " vfrontporch=%d, vsync=%d, vbackporch=%d," - " il_vfrontporch=%d, il_vsync=%d," - " il_vbackporch=%d\n", - p->bt.interlaced, p->bt.pixelclock, - p->bt.width, p->bt.height, p->bt.polarities, - p->bt.hfrontporch, p->bt.hsync, - p->bt.hbackporch, p->bt.vfrontporch, - p->bt.vsync, p->bt.vbackporch, - p->bt.il_vfrontporch, p->bt.il_vsync, - p->bt.il_vbackporch); - ret = ops->vidioc_s_dv_timings(file, fh, p); - break; - default: - dbgarg2("Unknown type %d!\n", p->type); - break; - } - break; - } - case VIDIOC_G_DV_TIMINGS: - { - struct v4l2_dv_timings *p = arg; - - if (!ops->vidioc_g_dv_timings) - break; - - ret = ops->vidioc_g_dv_timings(file, fh, p); - if (!ret) { - switch (p->type) { - case V4L2_DV_BT_656_1120: - dbgarg2("bt-656/1120:interlaced=%d," - " pixelclock=%lld," - " width=%d, height=%d, polarities=%x," - " hfrontporch=%d, hsync=%d," - " hbackporch=%d, vfrontporch=%d," - " vsync=%d, vbackporch=%d," - " il_vfrontporch=%d, il_vsync=%d," - " il_vbackporch=%d\n", - p->bt.interlaced, p->bt.pixelclock, - p->bt.width, p->bt.height, - p->bt.polarities, p->bt.hfrontporch, - p->bt.hsync, p->bt.hbackporch, - p->bt.vfrontporch, p->bt.vsync, - p->bt.vbackporch, p->bt.il_vfrontporch, - p->bt.il_vsync, p->bt.il_vbackporch); - break; - default: - dbgarg2("Unknown type %d!\n", p->type); - break; - } - } - break; - } - case VIDIOC_DQEVENT: - { - struct v4l2_event *ev = arg; - - if (!ops->vidioc_subscribe_event) - break; - - ret = v4l2_event_dequeue(fh, ev, file->f_flags & O_NONBLOCK); - if (ret < 0) { - dbgarg(cmd, "no pending events?"); - break; - } - dbgarg(cmd, - "pending=%d, type=0x%8.8x, sequence=%d, " - "timestamp=%lu.%9.9lu ", - ev->pending, ev->type, ev->sequence, - ev->timestamp.tv_sec, ev->timestamp.tv_nsec); - break; - } - case VIDIOC_SUBSCRIBE_EVENT: - { - struct v4l2_event_subscription *sub = arg; - - if (!ops->vidioc_subscribe_event) - break; - - ret = ops->vidioc_subscribe_event(fh, sub); - if (ret < 0) { - dbgarg(cmd, "failed, ret=%ld", ret); - break; - } - dbgarg(cmd, "type=0x%8.8x", sub->type); - break; - } - case VIDIOC_UNSUBSCRIBE_EVENT: - { - struct v4l2_event_subscription *sub = arg; - - if (!ops->vidioc_unsubscribe_event) - break; - - ret = ops->vidioc_unsubscribe_event(fh, sub); - if (ret < 0) { - dbgarg(cmd, "failed, ret=%ld", ret); - break; - } - dbgarg(cmd, "type=0x%8.8x", sub->type); - break; - } - default: - { - bool valid_prio = true; - - if (!ops->vidioc_default) - break; - if (use_fh_prio) - valid_prio = v4l2_prio_check(vfd->prio, vfh->prio) >= 0; - ret = ops->vidioc_default(file, fh, valid_prio, cmd, arg); - break; - } - } /* switch */ - -exit_prio: - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { - if (ret < 0) { - v4l_print_ioctl(vfd->name, cmd); - printk(KERN_CONT " error %ld\n", ret); - } - } - - return ret; -} - -/* In some cases, only a few fields are used as input, i.e. when the app sets - * "index" and then the driver fills in the rest of the structure for the thing - * with that index. We only need to copy up the first non-input field. */ -static unsigned long cmd_input_size(unsigned int cmd) -{ - /* Size of structure up to and including 'field' */ -#define CMDINSIZE(cmd, type, field) \ - case VIDIOC_##cmd: \ - return offsetof(struct v4l2_##type, field) + \ - sizeof(((struct v4l2_##type *)0)->field); - - switch (cmd) { - CMDINSIZE(ENUM_FMT, fmtdesc, type); - CMDINSIZE(G_FMT, format, type); - CMDINSIZE(QUERYBUF, buffer, length); - CMDINSIZE(G_PARM, streamparm, type); - CMDINSIZE(ENUMSTD, standard, index); - CMDINSIZE(ENUMINPUT, input, index); - CMDINSIZE(G_CTRL, control, id); - CMDINSIZE(G_TUNER, tuner, index); - CMDINSIZE(QUERYCTRL, queryctrl, id); - CMDINSIZE(QUERYMENU, querymenu, index); - CMDINSIZE(ENUMOUTPUT, output, index); - CMDINSIZE(G_MODULATOR, modulator, index); - CMDINSIZE(G_FREQUENCY, frequency, tuner); - CMDINSIZE(CROPCAP, cropcap, type); - CMDINSIZE(G_CROP, crop, type); - CMDINSIZE(ENUMAUDIO, audio, index); - CMDINSIZE(ENUMAUDOUT, audioout, index); - CMDINSIZE(ENCODER_CMD, encoder_cmd, flags); - CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags); - CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type); - CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); - CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); - default: - return _IOC_SIZE(cmd); - } -} - -static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, - void * __user *user_ptr, void ***kernel_ptr) -{ - int ret = 0; - - switch (cmd) { - case VIDIOC_QUERYBUF: - case VIDIOC_QBUF: - case VIDIOC_DQBUF: { - struct v4l2_buffer *buf = parg; - - if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) { - if (buf->length > VIDEO_MAX_PLANES) { - ret = -EINVAL; - break; - } - *user_ptr = (void __user *)buf->m.planes; - *kernel_ptr = (void **)&buf->m.planes; - *array_size = sizeof(struct v4l2_plane) * buf->length; - ret = 1; - } - break; - } - - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_G_EXT_CTRLS: - case VIDIOC_TRY_EXT_CTRLS: { - struct v4l2_ext_controls *ctrls = parg; - - if (ctrls->count != 0) { - *user_ptr = (void __user *)ctrls->controls; - *kernel_ptr = (void **)&ctrls->controls; - *array_size = sizeof(struct v4l2_ext_control) - * ctrls->count; - ret = 1; - } - break; - } - } - - return ret; -} - -long -video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, - v4l2_kioctl func) -{ - char sbuf[128]; - void *mbuf = NULL; - void *parg = (void *)arg; - long err = -EINVAL; - bool has_array_args; - size_t array_size = 0; - void __user *user_ptr = NULL; - void **kernel_ptr = NULL; - - /* Copy arguments into temp kernel buffer */ - if (_IOC_DIR(cmd) != _IOC_NONE) { - if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { - parg = sbuf; - } else { - /* too big to allocate from stack */ - mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); - if (NULL == mbuf) - return -ENOMEM; - parg = mbuf; - } - - err = -EFAULT; - if (_IOC_DIR(cmd) & _IOC_WRITE) { - unsigned long n = cmd_input_size(cmd); - - if (copy_from_user(parg, (void __user *)arg, n)) - goto out; - - /* zero out anything we don't copy from userspace */ - if (n < _IOC_SIZE(cmd)) - memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); - } else { - /* read-only ioctl */ - memset(parg, 0, _IOC_SIZE(cmd)); - } - } - - err = check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr); - if (err < 0) - goto out; - has_array_args = err; - - if (has_array_args) { - /* - * When adding new types of array args, make sure that the - * parent argument to ioctl (which contains the pointer to the - * array) fits into sbuf (so that mbuf will still remain - * unused up to here). - */ - mbuf = kmalloc(array_size, GFP_KERNEL); - err = -ENOMEM; - if (NULL == mbuf) - goto out_array_args; - err = -EFAULT; - if (copy_from_user(mbuf, user_ptr, array_size)) - goto out_array_args; - *kernel_ptr = mbuf; - } - - /* Handles IOCTL */ - err = func(file, cmd, parg); - if (err == -ENOIOCTLCMD) - err = -EINVAL; - - if (has_array_args) { - *kernel_ptr = user_ptr; - if (copy_to_user(user_ptr, mbuf, array_size)) - err = -EFAULT; - goto out_array_args; - } - if (err < 0) - goto out; - -out_array_args: - /* Copy results into user buffer */ - switch (_IOC_DIR(cmd)) { - case _IOC_READ: - case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) - err = -EFAULT; - break; - } - -out: - kfree(mbuf); - return err; -} -EXPORT_SYMBOL(video_usercopy); - -long video_ioctl2(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(file, cmd, arg, __video_do_ioctl); -} -EXPORT_SYMBOL(video_ioctl2); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-mem2mem.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-mem2mem.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-mem2mem.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-mem2mem.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,629 +0,0 @@ -/* - * Memory-to-memory device framework for Video for Linux 2 and videobuf. - * - * Helper functions for devices that use videobuf buffers for both their - * source and destination. - * - * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. - * Pawel Osciak, - * Marek Szyprowski, - * - * 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, or (at your - * option) any later version. - */ -#include -#include -#include - -#include -#include - -MODULE_DESCRIPTION("Mem to mem device framework for videobuf"); -MODULE_AUTHOR("Pawel Osciak, "); -MODULE_LICENSE("GPL"); - -static bool debug; -module_param(debug, bool, 0644); - -#define dprintk(fmt, arg...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "%s: " fmt, __func__, ## arg);\ - } while (0) - - -/* Instance is already queued on the job_queue */ -#define TRANS_QUEUED (1 << 0) -/* Instance is currently running in hardware */ -#define TRANS_RUNNING (1 << 1) - - -/* Offset base for buffers on the destination queue - used to distinguish - * between source and destination buffers when mmapping - they receive the same - * offsets but for different queues */ -#define DST_QUEUE_OFF_BASE (1 << 30) - - -/** - * struct v4l2_m2m_dev - per-device context - * @curr_ctx: currently running instance - * @job_queue: instances queued to run - * @job_spinlock: protects job_queue - * @m2m_ops: driver callbacks - */ -struct v4l2_m2m_dev { - struct v4l2_m2m_ctx *curr_ctx; - - struct list_head job_queue; - spinlock_t job_spinlock; - - struct v4l2_m2m_ops *m2m_ops; -}; - -static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx, - enum v4l2_buf_type type) -{ - if (V4L2_TYPE_IS_OUTPUT(type)) - return &m2m_ctx->out_q_ctx; - else - return &m2m_ctx->cap_q_ctx; -} - -/** - * v4l2_m2m_get_vq() - return vb2_queue for the given type - */ -struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, - enum v4l2_buf_type type) -{ - struct v4l2_m2m_queue_ctx *q_ctx; - - q_ctx = get_queue_ctx(m2m_ctx, type); - if (!q_ctx) - return NULL; - - return &q_ctx->q; -} -EXPORT_SYMBOL(v4l2_m2m_get_vq); - -/** - * v4l2_m2m_next_buf() - return next buffer from the list of ready buffers - */ -void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) -{ - struct v4l2_m2m_buffer *b = NULL; - unsigned long flags; - - spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); - - if (list_empty(&q_ctx->rdy_queue)) - goto end; - - b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, list); -end: - spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); - return &b->vb; -} -EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf); - -/** - * v4l2_m2m_buf_remove() - take off a buffer from the list of ready buffers and - * return it - */ -void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx) -{ - struct v4l2_m2m_buffer *b = NULL; - unsigned long flags; - - spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); - if (!list_empty(&q_ctx->rdy_queue)) { - b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, - list); - list_del(&b->list); - q_ctx->num_rdy--; - } - spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); - - return &b->vb; -} -EXPORT_SYMBOL_GPL(v4l2_m2m_buf_remove); - -/* - * Scheduling handlers - */ - -/** - * v4l2_m2m_get_curr_priv() - return driver private data for the currently - * running instance or NULL if no instance is running - */ -void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev) -{ - unsigned long flags; - void *ret = NULL; - - spin_lock_irqsave(&m2m_dev->job_spinlock, flags); - if (m2m_dev->curr_ctx) - ret = m2m_dev->curr_ctx->priv; - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - - return ret; -} -EXPORT_SYMBOL(v4l2_m2m_get_curr_priv); - -/** - * v4l2_m2m_try_run() - select next job to perform and run it if possible - * - * Get next transaction (if present) from the waiting jobs list and run it. - */ -static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&m2m_dev->job_spinlock, flags); - if (NULL != m2m_dev->curr_ctx) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - dprintk("Another instance is running, won't run now\n"); - return; - } - - if (list_empty(&m2m_dev->job_queue)) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - dprintk("No job pending\n"); - return; - } - - m2m_dev->curr_ctx = list_entry(m2m_dev->job_queue.next, - struct v4l2_m2m_ctx, queue); - m2m_dev->curr_ctx->job_flags |= TRANS_RUNNING; - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - - m2m_dev->m2m_ops->device_run(m2m_dev->curr_ctx->priv); -} - -/** - * v4l2_m2m_try_schedule() - check whether an instance is ready to be added to - * the pending job queue and add it if so. - * @m2m_ctx: m2m context assigned to the instance to be checked - * - * There are three basic requirements an instance has to meet to be able to run: - * 1) at least one source buffer has to be queued, - * 2) at least one destination buffer has to be queued, - * 3) streaming has to be on. - * - * There may also be additional, custom requirements. In such case the driver - * should supply a custom callback (job_ready in v4l2_m2m_ops) that should - * return 1 if the instance is ready. - * An example of the above could be an instance that requires more than one - * src/dst buffer per transaction. - */ -static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx) -{ - struct v4l2_m2m_dev *m2m_dev; - unsigned long flags_job, flags; - - m2m_dev = m2m_ctx->m2m_dev; - dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx); - - if (!m2m_ctx->out_q_ctx.q.streaming - || !m2m_ctx->cap_q_ctx.q.streaming) { - dprintk("Streaming needs to be on for both queues\n"); - return; - } - - spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job); - if (m2m_ctx->job_flags & TRANS_QUEUED) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); - dprintk("On job queue already\n"); - return; - } - - spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); - if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)) { - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); - dprintk("No input buffers available\n"); - return; - } - if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)) { - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); - dprintk("No output buffers available\n"); - return; - } - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); - - if (m2m_dev->m2m_ops->job_ready - && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); - dprintk("Driver not ready\n"); - return; - } - - list_add_tail(&m2m_ctx->queue, &m2m_dev->job_queue); - m2m_ctx->job_flags |= TRANS_QUEUED; - - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); - - v4l2_m2m_try_run(m2m_dev); -} - -/** - * v4l2_m2m_job_finish() - inform the framework that a job has been finished - * and have it clean up - * - * Called by a driver to yield back the device after it has finished with it. - * Should be called as soon as possible after reaching a state which allows - * other instances to take control of the device. - * - * This function has to be called only after device_run() callback has been - * called on the driver. To prevent recursion, it should not be called directly - * from the device_run() callback though. - */ -void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, - struct v4l2_m2m_ctx *m2m_ctx) -{ - unsigned long flags; - - spin_lock_irqsave(&m2m_dev->job_spinlock, flags); - if (!m2m_dev->curr_ctx || m2m_dev->curr_ctx != m2m_ctx) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - dprintk("Called by an instance not currently running\n"); - return; - } - - list_del(&m2m_dev->curr_ctx->queue); - m2m_dev->curr_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING); - wake_up(&m2m_dev->curr_ctx->finished); - m2m_dev->curr_ctx = NULL; - - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - - /* This instance might have more buffers ready, but since we do not - * allow more than one job on the job_queue per instance, each has - * to be scheduled separately after the previous one finishes. */ - v4l2_m2m_try_schedule(m2m_ctx); - v4l2_m2m_try_run(m2m_dev); -} -EXPORT_SYMBOL(v4l2_m2m_job_finish); - -/** - * v4l2_m2m_reqbufs() - multi-queue-aware REQBUFS multiplexer - */ -int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct v4l2_requestbuffers *reqbufs) -{ - struct vb2_queue *vq; - - vq = v4l2_m2m_get_vq(m2m_ctx, reqbufs->type); - return vb2_reqbufs(vq, reqbufs); -} -EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs); - -/** - * v4l2_m2m_querybuf() - multi-queue-aware QUERYBUF multiplexer - * - * See v4l2_m2m_mmap() documentation for details. - */ -int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct v4l2_buffer *buf) -{ - struct vb2_queue *vq; - int ret = 0; - unsigned int i; - - vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); - ret = vb2_querybuf(vq, buf); - - /* Adjust MMAP memory offsets for the CAPTURE queue */ - if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) { - if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { - for (i = 0; i < buf->length; ++i) - buf->m.planes[i].m.mem_offset - += DST_QUEUE_OFF_BASE; - } else { - buf->m.offset += DST_QUEUE_OFF_BASE; - } - } - - return ret; -} -EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf); - -/** - * v4l2_m2m_qbuf() - enqueue a source or destination buffer, depending on - * the type - */ -int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct v4l2_buffer *buf) -{ - struct vb2_queue *vq; - int ret; - - vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); - ret = vb2_qbuf(vq, buf); - if (!ret) - v4l2_m2m_try_schedule(m2m_ctx); - - return ret; -} -EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf); - -/** - * v4l2_m2m_dqbuf() - dequeue a source or destination buffer, depending on - * the type - */ -int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct v4l2_buffer *buf) -{ - struct vb2_queue *vq; - - vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); - return vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK); -} -EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf); - -/** - * v4l2_m2m_streamon() - turn on streaming for a video queue - */ -int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - enum v4l2_buf_type type) -{ - struct vb2_queue *vq; - int ret; - - vq = v4l2_m2m_get_vq(m2m_ctx, type); - ret = vb2_streamon(vq, type); - if (!ret) - v4l2_m2m_try_schedule(m2m_ctx); - - return ret; -} -EXPORT_SYMBOL_GPL(v4l2_m2m_streamon); - -/** - * v4l2_m2m_streamoff() - turn off streaming for a video queue - */ -int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - enum v4l2_buf_type type) -{ - struct vb2_queue *vq; - - vq = v4l2_m2m_get_vq(m2m_ctx, type); - return vb2_streamoff(vq, type); -} -EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff); - -/** - * v4l2_m2m_poll() - poll replacement, for destination buffers only - * - * Call from the driver's poll() function. Will poll both queues. If a buffer - * is available to dequeue (with dqbuf) from the source queue, this will - * indicate that a non-blocking write can be performed, while read will be - * returned in case of the destination queue. - */ -unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct poll_table_struct *wait) -{ - struct vb2_queue *src_q, *dst_q; - struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; - unsigned int rc = 0; - unsigned long flags; - - src_q = v4l2_m2m_get_src_vq(m2m_ctx); - dst_q = v4l2_m2m_get_dst_vq(m2m_ctx); - - /* - * There has to be at least one buffer queued on each queued_list, which - * means either in driver already or waiting for driver to claim it - * and start processing. - */ - if ((!src_q->streaming || list_empty(&src_q->queued_list)) - && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { - rc = POLLERR; - goto end; - } - - if (m2m_ctx->m2m_dev->m2m_ops->unlock) - m2m_ctx->m2m_dev->m2m_ops->unlock(m2m_ctx->priv); - - poll_wait(file, &src_q->done_wq, wait); - poll_wait(file, &dst_q->done_wq, wait); - - if (m2m_ctx->m2m_dev->m2m_ops->lock) - m2m_ctx->m2m_dev->m2m_ops->lock(m2m_ctx->priv); - - spin_lock_irqsave(&src_q->done_lock, flags); - if (!list_empty(&src_q->done_list)) - src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, - done_entry); - if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE - || src_vb->state == VB2_BUF_STATE_ERROR)) - rc |= POLLOUT | POLLWRNORM; - spin_unlock_irqrestore(&src_q->done_lock, flags); - - spin_lock_irqsave(&dst_q->done_lock, flags); - if (!list_empty(&dst_q->done_list)) - dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer, - done_entry); - if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE - || dst_vb->state == VB2_BUF_STATE_ERROR)) - rc |= POLLIN | POLLRDNORM; - spin_unlock_irqrestore(&dst_q->done_lock, flags); - -end: - return rc; -} -EXPORT_SYMBOL_GPL(v4l2_m2m_poll); - -/** - * v4l2_m2m_mmap() - source and destination queues-aware mmap multiplexer - * - * Call from driver's mmap() function. Will handle mmap() for both queues - * seamlessly for videobuffer, which will receive normal per-queue offsets and - * proper videobuf queue pointers. The differentiation is made outside videobuf - * by adding a predefined offset to buffers from one of the queues and - * subtracting it before passing it back to videobuf. Only drivers (and - * thus applications) receive modified offsets. - */ -int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct vm_area_struct *vma) -{ - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - struct vb2_queue *vq; - - if (offset < DST_QUEUE_OFF_BASE) { - vq = v4l2_m2m_get_src_vq(m2m_ctx); - } else { - vq = v4l2_m2m_get_dst_vq(m2m_ctx); - vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); - } - - return vb2_mmap(vq, vma); -} -EXPORT_SYMBOL(v4l2_m2m_mmap); - -/** - * v4l2_m2m_init() - initialize per-driver m2m data - * - * Usually called from driver's probe() function. - */ -struct v4l2_m2m_dev *v4l2_m2m_init(struct v4l2_m2m_ops *m2m_ops) -{ - struct v4l2_m2m_dev *m2m_dev; - - if (!m2m_ops) - return ERR_PTR(-EINVAL); - - BUG_ON(!m2m_ops->device_run); - BUG_ON(!m2m_ops->job_abort); - - m2m_dev = kzalloc(sizeof *m2m_dev, GFP_KERNEL); - if (!m2m_dev) - return ERR_PTR(-ENOMEM); - - m2m_dev->curr_ctx = NULL; - m2m_dev->m2m_ops = m2m_ops; - INIT_LIST_HEAD(&m2m_dev->job_queue); - spin_lock_init(&m2m_dev->job_spinlock); - - return m2m_dev; -} -EXPORT_SYMBOL_GPL(v4l2_m2m_init); - -/** - * v4l2_m2m_release() - cleans up and frees a m2m_dev structure - * - * Usually called from driver's remove() function. - */ -void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev) -{ - kfree(m2m_dev); -} -EXPORT_SYMBOL_GPL(v4l2_m2m_release); - -/** - * v4l2_m2m_ctx_init() - allocate and initialize a m2m context - * @priv - driver's instance private data - * @m2m_dev - a previously initialized m2m_dev struct - * @vq_init - a callback for queue type-specific initialization function to be - * used for initializing videobuf_queues - * - * Usually called from driver's open() function. - */ -struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev, - void *drv_priv, - int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)) -{ - struct v4l2_m2m_ctx *m2m_ctx; - struct v4l2_m2m_queue_ctx *out_q_ctx, *cap_q_ctx; - int ret; - - m2m_ctx = kzalloc(sizeof *m2m_ctx, GFP_KERNEL); - if (!m2m_ctx) - return ERR_PTR(-ENOMEM); - - m2m_ctx->priv = drv_priv; - m2m_ctx->m2m_dev = m2m_dev; - init_waitqueue_head(&m2m_ctx->finished); - - out_q_ctx = &m2m_ctx->out_q_ctx; - cap_q_ctx = &m2m_ctx->cap_q_ctx; - - INIT_LIST_HEAD(&out_q_ctx->rdy_queue); - INIT_LIST_HEAD(&cap_q_ctx->rdy_queue); - spin_lock_init(&out_q_ctx->rdy_spinlock); - spin_lock_init(&cap_q_ctx->rdy_spinlock); - - INIT_LIST_HEAD(&m2m_ctx->queue); - - ret = queue_init(drv_priv, &out_q_ctx->q, &cap_q_ctx->q); - - if (ret) - goto err; - - return m2m_ctx; -err: - kfree(m2m_ctx); - return ERR_PTR(ret); -} -EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init); - -/** - * v4l2_m2m_ctx_release() - release m2m context - * - * Usually called from driver's release() function. - */ -void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx) -{ - struct v4l2_m2m_dev *m2m_dev; - unsigned long flags; - - m2m_dev = m2m_ctx->m2m_dev; - - spin_lock_irqsave(&m2m_dev->job_spinlock, flags); - if (m2m_ctx->job_flags & TRANS_RUNNING) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - m2m_dev->m2m_ops->job_abort(m2m_ctx->priv); - dprintk("m2m_ctx %p running, will wait to complete", m2m_ctx); - wait_event(m2m_ctx->finished, !(m2m_ctx->job_flags & TRANS_RUNNING)); - } else if (m2m_ctx->job_flags & TRANS_QUEUED) { - list_del(&m2m_ctx->queue); - m2m_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING); - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - dprintk("m2m_ctx: %p had been on queue and was removed\n", - m2m_ctx); - } else { - /* Do nothing, was not on queue/running */ - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - } - - vb2_queue_release(&m2m_ctx->cap_q_ctx.q); - vb2_queue_release(&m2m_ctx->out_q_ctx.q); - - kfree(m2m_ctx); -} -EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_release); - -/** - * v4l2_m2m_buf_queue() - add a buffer to the proper ready buffers list. - * - * Call from buf_queue(), videobuf_queue_ops callback. - */ -void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb) -{ - struct v4l2_m2m_buffer *b = container_of(vb, struct v4l2_m2m_buffer, vb); - struct v4l2_m2m_queue_ctx *q_ctx; - unsigned long flags; - - q_ctx = get_queue_ctx(m2m_ctx, vb->vb2_queue->type); - if (!q_ctx) - return; - - spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); - list_add_tail(&b->list, &q_ctx->rdy_queue); - q_ctx->num_rdy++; - spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); -} -EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-subdev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-subdev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-subdev.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/v4l2-subdev.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,332 +0,0 @@ -/* - * V4L2 sub-device - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include - -#include -#include -#include -#include -#include - -static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) -{ -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - /* Allocate try format and crop in the same memory block */ - fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop)) - * sd->entity.num_pads, GFP_KERNEL); - if (fh->try_fmt == NULL) - return -ENOMEM; - - fh->try_crop = (struct v4l2_rect *) - (fh->try_fmt + sd->entity.num_pads); -#endif - return 0; -} - -static void subdev_fh_free(struct v4l2_subdev_fh *fh) -{ -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - kfree(fh->try_fmt); - fh->try_fmt = NULL; - fh->try_crop = NULL; -#endif -} - -static int subdev_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_subdev_fh *subdev_fh; -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity *entity = NULL; -#endif - int ret; - - subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL); - if (subdev_fh == NULL) - return -ENOMEM; - - ret = subdev_fh_init(subdev_fh, sd); - if (ret) { - kfree(subdev_fh); - return ret; - } - - ret = v4l2_fh_init(&subdev_fh->vfh, vdev); - if (ret) - goto err; - - if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) { - ret = v4l2_event_init(&subdev_fh->vfh); - if (ret) - goto err; - - ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents); - if (ret) - goto err; - } - - v4l2_fh_add(&subdev_fh->vfh); - file->private_data = &subdev_fh->vfh; -#if defined(CONFIG_MEDIA_CONTROLLER) - if (sd->v4l2_dev->mdev) { - entity = media_entity_get(&sd->entity); - if (!entity) { - ret = -EBUSY; - goto err; - } - } -#endif - - if (sd->internal_ops && sd->internal_ops->open) { - ret = sd->internal_ops->open(sd, subdev_fh); - if (ret < 0) - goto err; - } - - return 0; - -err: -#if defined(CONFIG_MEDIA_CONTROLLER) - if (entity) - media_entity_put(entity); -#endif - v4l2_fh_del(&subdev_fh->vfh); - v4l2_fh_exit(&subdev_fh->vfh); - subdev_fh_free(subdev_fh); - kfree(subdev_fh); - - return ret; -} - -static int subdev_close(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; - struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); - - if (sd->internal_ops && sd->internal_ops->close) - sd->internal_ops->close(sd, subdev_fh); -#if defined(CONFIG_MEDIA_CONTROLLER) - if (sd->v4l2_dev->mdev) - media_entity_put(&sd->entity); -#endif - v4l2_fh_del(vfh); - v4l2_fh_exit(vfh); - subdev_fh_free(subdev_fh); - kfree(subdev_fh); - file->private_data = NULL; - - return 0; -} - -static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); -#endif - - switch (cmd) { - case VIDIOC_QUERYCTRL: - return v4l2_subdev_queryctrl(sd, arg); - - case VIDIOC_QUERYMENU: - return v4l2_subdev_querymenu(sd, arg); - - case VIDIOC_G_CTRL: - return v4l2_subdev_g_ctrl(sd, arg); - - case VIDIOC_S_CTRL: - return v4l2_subdev_s_ctrl(sd, arg); - - case VIDIOC_G_EXT_CTRLS: - return v4l2_subdev_g_ext_ctrls(sd, arg); - - case VIDIOC_S_EXT_CTRLS: - return v4l2_subdev_s_ext_ctrls(sd, arg); - - case VIDIOC_TRY_EXT_CTRLS: - return v4l2_subdev_try_ext_ctrls(sd, arg); - - case VIDIOC_DQEVENT: - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) - return -ENOIOCTLCMD; - - return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); - - case VIDIOC_SUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); - - case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - case VIDIOC_SUBDEV_G_FMT: { - struct v4l2_subdev_format *format = arg; - - if (format->which != V4L2_SUBDEV_FORMAT_TRY && - format->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (format->pad >= sd->entity.num_pads) - return -EINVAL; - - return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format); - } - - case VIDIOC_SUBDEV_S_FMT: { - struct v4l2_subdev_format *format = arg; - - if (format->which != V4L2_SUBDEV_FORMAT_TRY && - format->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (format->pad >= sd->entity.num_pads) - return -EINVAL; - - return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format); - } - - case VIDIOC_SUBDEV_G_CROP: { - struct v4l2_subdev_crop *crop = arg; - - if (crop->which != V4L2_SUBDEV_FORMAT_TRY && - crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (crop->pad >= sd->entity.num_pads) - return -EINVAL; - - return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop); - } - - case VIDIOC_SUBDEV_S_CROP: { - struct v4l2_subdev_crop *crop = arg; - - if (crop->which != V4L2_SUBDEV_FORMAT_TRY && - crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (crop->pad >= sd->entity.num_pads) - return -EINVAL; - - return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop); - } - - case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { - struct v4l2_subdev_mbus_code_enum *code = arg; - - if (code->pad >= sd->entity.num_pads) - return -EINVAL; - - return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh, - code); - } - - case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { - struct v4l2_subdev_frame_size_enum *fse = arg; - - if (fse->pad >= sd->entity.num_pads) - return -EINVAL; - - return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh, - fse); - } - - case VIDIOC_SUBDEV_G_FRAME_INTERVAL: - return v4l2_subdev_call(sd, video, g_frame_interval, arg); - - case VIDIOC_SUBDEV_S_FRAME_INTERVAL: - return v4l2_subdev_call(sd, video, s_frame_interval, arg); - - case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { - struct v4l2_subdev_frame_interval_enum *fie = arg; - - if (fie->pad >= sd->entity.num_pads) - return -EINVAL; - - return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh, - fie); - } -#endif - default: - return v4l2_subdev_call(sd, core, ioctl, cmd, arg); - } - - return 0; -} - -static long subdev_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return video_usercopy(file, cmd, arg, subdev_do_ioctl); -} - -static unsigned int subdev_poll(struct file *file, poll_table *wait) -{ - struct video_device *vdev = video_devdata(file); - struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *fh = file->private_data; - - if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) - return POLLERR; - - poll_wait(file, &fh->events->wait, wait); - - if (v4l2_event_pending(fh)) - return POLLPRI; - - return 0; -} - -const struct v4l2_file_operations v4l2_subdev_fops = { - .owner = THIS_MODULE, - .open = subdev_open, - .unlocked_ioctl = subdev_ioctl, - .release = subdev_close, - .poll = subdev_poll, -}; - -void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) -{ - INIT_LIST_HEAD(&sd->list); - BUG_ON(!ops); - sd->ops = ops; - sd->v4l2_dev = NULL; - sd->flags = 0; - sd->name[0] = '\0'; - sd->grp_id = 0; - sd->dev_priv = NULL; - sd->host_priv = NULL; -#if defined(CONFIG_MEDIA_CONTROLLER) - sd->entity.name = sd->name; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; -#endif -} -EXPORT_SYMBOL(v4l2_subdev_init); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/via-camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/via-camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/via-camera.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/via-camera.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1514 +0,0 @@ -/* - * Driver for the VIA Chrome integrated camera controller. - * - * Copyright 2009,2010 Jonathan Corbet - * Distributable under the terms of the GNU General Public License, version 2 - * - * This work was supported by the One Laptop Per Child project - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "via-camera.h" - -MODULE_AUTHOR("Jonathan Corbet "); -MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver"); -MODULE_LICENSE("GPL"); - -static int flip_image; -module_param(flip_image, bool, 0444); -MODULE_PARM_DESC(flip_image, - "If set, the sensor will be instructed to flip the image " - "vertically."); - -static int override_serial; -module_param(override_serial, bool, 0444); -MODULE_PARM_DESC(override_serial, - "The camera driver will normally refuse to load if " - "the XO 1.5 serial port is enabled. Set this option " - "to force-enable the camera."); - -/* - * Basic window sizes. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 - -/* - * The structure describing our camera. - */ -enum viacam_opstate { S_IDLE = 0, S_RUNNING = 1 }; - -struct via_camera { - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct v4l2_subdev *sensor; - struct platform_device *platdev; - struct viafb_dev *viadev; - struct mutex lock; - enum viacam_opstate opstate; - unsigned long flags; - struct pm_qos_request_list qos_request; - /* - * GPIO info for power/reset management - */ - int power_gpio; - int reset_gpio; - /* - * I/O memory stuff. - */ - void __iomem *mmio; /* Where the registers live */ - void __iomem *fbmem; /* Frame buffer memory */ - u32 fb_offset; /* Reserved memory offset (FB) */ - /* - * Capture buffers and related. The controller supports - * up to three, so that's what we have here. These buffers - * live in frame buffer memory, so we don't call them "DMA". - */ - unsigned int cb_offsets[3]; /* offsets into fb mem */ - u8 *cb_addrs[3]; /* Kernel-space addresses */ - int n_cap_bufs; /* How many are we using? */ - int next_buf; - struct videobuf_queue vb_queue; - struct list_head buffer_queue; /* prot. by reg_lock */ - /* - * User tracking. - */ - int users; - struct file *owner; - /* - * Video format information. sensor_format is kept in a form - * that we can use to pass to the sensor. We always run the - * sensor in VGA resolution, though, and let the controller - * downscale things if need be. So we keep the "real* - * dimensions separately. - */ - struct v4l2_pix_format sensor_format; - struct v4l2_pix_format user_format; - enum v4l2_mbus_pixelcode mbus_code; -}; - -/* - * Yes, this is a hack, but there's only going to be one of these - * on any system we know of. - */ -static struct via_camera *via_cam_info; - -/* - * Flag values, manipulated with bitops - */ -#define CF_DMA_ACTIVE 0 /* A frame is incoming */ -#define CF_CONFIG_NEEDED 1 /* Must configure hardware */ - - -/* - * Nasty ugly v4l2 boilerplate. - */ -#define sensor_call(cam, optype, func, args...) \ - v4l2_subdev_call(cam->sensor, optype, func, ##args) - -/* - * Debugging and related. - */ -#define cam_err(cam, fmt, arg...) \ - dev_err(&(cam)->platdev->dev, fmt, ##arg); -#define cam_warn(cam, fmt, arg...) \ - dev_warn(&(cam)->platdev->dev, fmt, ##arg); -#define cam_dbg(cam, fmt, arg...) \ - dev_dbg(&(cam)->platdev->dev, fmt, ##arg); - -/* - * Format handling. This is ripped almost directly from Hans's changes - * to cafe_ccic.c. It's a little unfortunate; until this change, we - * didn't need to know anything about the format except its byte depth; - * now this information must be managed at this level too. - */ -static struct via_format { - __u8 *desc; - __u32 pixelformat; - int bpp; /* Bytes per pixel */ - enum v4l2_mbus_pixelcode mbus_code; -} via_formats[] = { - { - .desc = "YUYV 4:2:2", - .pixelformat = V4L2_PIX_FMT_YUYV, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, - .bpp = 2, - }, - { - .desc = "RGB 565", - .pixelformat = V4L2_PIX_FMT_RGB565, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, - .bpp = 2, - }, - /* RGB444 and Bayer should be doable, but have never been - tested with this driver. */ -}; -#define N_VIA_FMTS ARRAY_SIZE(via_formats) - -static struct via_format *via_find_format(u32 pixelformat) -{ - unsigned i; - - for (i = 0; i < N_VIA_FMTS; i++) - if (via_formats[i].pixelformat == pixelformat) - return via_formats + i; - /* Not found? Then return the first format. */ - return via_formats; -} - - -/*--------------------------------------------------------------------------*/ -/* - * Sensor power/reset management. This piece is OLPC-specific for - * sure; other configurations will have things connected differently. - */ -static int via_sensor_power_setup(struct via_camera *cam) -{ - int ret; - - cam->power_gpio = viafb_gpio_lookup("VGPIO3"); - cam->reset_gpio = viafb_gpio_lookup("VGPIO2"); - if (cam->power_gpio < 0 || cam->reset_gpio < 0) { - dev_err(&cam->platdev->dev, "Unable to find GPIO lines\n"); - return -EINVAL; - } - ret = gpio_request(cam->power_gpio, "viafb-camera"); - if (ret) { - dev_err(&cam->platdev->dev, "Unable to request power GPIO\n"); - return ret; - } - ret = gpio_request(cam->reset_gpio, "viafb-camera"); - if (ret) { - dev_err(&cam->platdev->dev, "Unable to request reset GPIO\n"); - gpio_free(cam->power_gpio); - return ret; - } - gpio_direction_output(cam->power_gpio, 0); - gpio_direction_output(cam->reset_gpio, 0); - return 0; -} - -/* - * Power up the sensor and perform the reset dance. - */ -static void via_sensor_power_up(struct via_camera *cam) -{ - gpio_set_value(cam->power_gpio, 1); - gpio_set_value(cam->reset_gpio, 0); - msleep(20); /* Probably excessive */ - gpio_set_value(cam->reset_gpio, 1); - msleep(20); -} - -static void via_sensor_power_down(struct via_camera *cam) -{ - gpio_set_value(cam->power_gpio, 0); - gpio_set_value(cam->reset_gpio, 0); -} - - -static void via_sensor_power_release(struct via_camera *cam) -{ - via_sensor_power_down(cam); - gpio_free(cam->power_gpio); - gpio_free(cam->reset_gpio); -} - -/* --------------------------------------------------------------------------*/ -/* Sensor ops */ - -/* - * Manage the ov7670 "flip" bit, which needs special help. - */ -static int viacam_set_flip(struct via_camera *cam) -{ - struct v4l2_control ctrl; - - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_VFLIP; - ctrl.value = flip_image; - return sensor_call(cam, core, s_ctrl, &ctrl); -} - -/* - * Configure the sensor. It's up to the caller to ensure - * that the camera is in the correct operating state. - */ -static int viacam_configure_sensor(struct via_camera *cam) -{ - struct v4l2_mbus_framefmt mbus_fmt; - int ret; - - v4l2_fill_mbus_format(&mbus_fmt, &cam->sensor_format, cam->mbus_code); - ret = sensor_call(cam, core, init, 0); - if (ret == 0) - ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); - /* - * OV7670 does weird things if flip is set *before* format... - */ - if (ret == 0) - ret = viacam_set_flip(cam); - return ret; -} - - - -/* --------------------------------------------------------------------------*/ -/* - * Some simple register accessors; they assume that the lock is held. - * - * Should we want to support the second capture engine, we could - * hide the register difference by adding 0x1000 to registers in the - * 0x300-350 range. - */ -static inline void viacam_write_reg(struct via_camera *cam, - int reg, int value) -{ - iowrite32(value, cam->mmio + reg); -} - -static inline int viacam_read_reg(struct via_camera *cam, int reg) -{ - return ioread32(cam->mmio + reg); -} - -static inline void viacam_write_reg_mask(struct via_camera *cam, - int reg, int value, int mask) -{ - int tmp = viacam_read_reg(cam, reg); - - tmp = (tmp & ~mask) | (value & mask); - viacam_write_reg(cam, reg, tmp); -} - - -/* --------------------------------------------------------------------------*/ -/* Interrupt management and handling */ - -static irqreturn_t viacam_quick_irq(int irq, void *data) -{ - struct via_camera *cam = data; - irqreturn_t ret = IRQ_NONE; - int icv; - - /* - * All we do here is to clear the interrupts and tell - * the handler thread to wake up. - */ - spin_lock(&cam->viadev->reg_lock); - icv = viacam_read_reg(cam, VCR_INTCTRL); - if (icv & VCR_IC_EAV) { - icv |= VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL; - viacam_write_reg(cam, VCR_INTCTRL, icv); - ret = IRQ_WAKE_THREAD; - } - spin_unlock(&cam->viadev->reg_lock); - return ret; -} - -/* - * Find the next videobuf buffer which has somebody waiting on it. - */ -static struct videobuf_buffer *viacam_next_buffer(struct via_camera *cam) -{ - unsigned long flags; - struct videobuf_buffer *buf = NULL; - - spin_lock_irqsave(&cam->viadev->reg_lock, flags); - if (cam->opstate != S_RUNNING) - goto out; - if (list_empty(&cam->buffer_queue)) - goto out; - buf = list_entry(cam->buffer_queue.next, struct videobuf_buffer, queue); - if (!waitqueue_active(&buf->done)) {/* Nobody waiting */ - buf = NULL; - goto out; - } - list_del(&buf->queue); - buf->state = VIDEOBUF_ACTIVE; -out: - spin_unlock_irqrestore(&cam->viadev->reg_lock, flags); - return buf; -} - -/* - * The threaded IRQ handler. - */ -static irqreturn_t viacam_irq(int irq, void *data) -{ - int bufn; - struct videobuf_buffer *vb; - struct via_camera *cam = data; - struct videobuf_dmabuf *vdma; - - /* - * If there is no place to put the data frame, don't bother - * with anything else. - */ - vb = viacam_next_buffer(cam); - if (vb == NULL) - goto done; - /* - * Figure out which buffer we just completed. - */ - bufn = (viacam_read_reg(cam, VCR_INTCTRL) & VCR_IC_ACTBUF) >> 3; - bufn -= 1; - if (bufn < 0) - bufn = cam->n_cap_bufs - 1; - /* - * Copy over the data and let any waiters know. - */ - vdma = videobuf_to_dma(vb); - viafb_dma_copy_out_sg(cam->cb_offsets[bufn], vdma->sglist, vdma->sglen); - vb->state = VIDEOBUF_DONE; - vb->size = cam->user_format.sizeimage; - wake_up(&vb->done); -done: - return IRQ_HANDLED; -} - - -/* - * These functions must mess around with the general interrupt - * control register, which is relevant to much more than just the - * camera. Nothing else uses interrupts, though, as of this writing. - * Should that situation change, we'll have to improve support at - * the via-core level. - */ -static void viacam_int_enable(struct via_camera *cam) -{ - viacam_write_reg(cam, VCR_INTCTRL, - VCR_IC_INTEN|VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL); - viafb_irq_enable(VDE_I_C0AVEN); -} - -static void viacam_int_disable(struct via_camera *cam) -{ - viafb_irq_disable(VDE_I_C0AVEN); - viacam_write_reg(cam, VCR_INTCTRL, 0); -} - - - -/* --------------------------------------------------------------------------*/ -/* Controller operations */ - -/* - * Set up our capture buffers in framebuffer memory. - */ -static int viacam_ctlr_cbufs(struct via_camera *cam) -{ - int nbuf = cam->viadev->camera_fbmem_size/cam->sensor_format.sizeimage; - int i; - unsigned int offset; - - /* - * See how many buffers we can work with. - */ - if (nbuf >= 3) { - cam->n_cap_bufs = 3; - viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_3BUFS, - VCR_CI_3BUFS); - } else if (nbuf == 2) { - cam->n_cap_bufs = 2; - viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_3BUFS); - } else { - cam_warn(cam, "Insufficient frame buffer memory\n"); - return -ENOMEM; - } - /* - * Set them up. - */ - offset = cam->fb_offset; - for (i = 0; i < cam->n_cap_bufs; i++) { - cam->cb_offsets[i] = offset; - cam->cb_addrs[i] = cam->fbmem + offset; - viacam_write_reg(cam, VCR_VBUF1 + i*4, offset & VCR_VBUF_MASK); - offset += cam->sensor_format.sizeimage; - } - return 0; -} - -/* - * Set the scaling register for downscaling the image. - * - * This register works like this... Vertical scaling is enabled - * by bit 26; if that bit is set, downscaling is controlled by the - * value in bits 16:25. Those bits are divided by 1024 to get - * the scaling factor; setting just bit 25 thus cuts the height - * in half. - * - * Horizontal scaling works about the same, but it's enabled by - * bit 11, with bits 0:10 giving the numerator of a fraction - * (over 2048) for the scaling value. - * - * This function is naive in that, if the user departs from - * the 3x4 VGA scaling factor, the image will distort. We - * could work around that if it really seemed important. - */ -static void viacam_set_scale(struct via_camera *cam) -{ - unsigned int avscale; - int sf; - - if (cam->user_format.width == VGA_WIDTH) - avscale = 0; - else { - sf = (cam->user_format.width*2048)/VGA_WIDTH; - avscale = VCR_AVS_HEN | sf; - } - if (cam->user_format.height < VGA_HEIGHT) { - sf = (1024*cam->user_format.height)/VGA_HEIGHT; - avscale |= VCR_AVS_VEN | (sf << 16); - } - viacam_write_reg(cam, VCR_AVSCALE, avscale); -} - - -/* - * Configure image-related information into the capture engine. - */ -static void viacam_ctlr_image(struct via_camera *cam) -{ - int cicreg; - - /* - * Disable clock before messing with stuff - from the via - * sample driver. - */ - viacam_write_reg(cam, VCR_CAPINTC, ~(VCR_CI_ENABLE|VCR_CI_CLKEN)); - /* - * Set up the controller for VGA resolution, modulo magic - * offsets from the via sample driver. - */ - viacam_write_reg(cam, VCR_HORRANGE, 0x06200120); - viacam_write_reg(cam, VCR_VERTRANGE, 0x01de0000); - viacam_set_scale(cam); - /* - * Image size info. - */ - viacam_write_reg(cam, VCR_MAXDATA, - (cam->sensor_format.height << 16) | - (cam->sensor_format.bytesperline >> 3)); - viacam_write_reg(cam, VCR_MAXVBI, 0); - viacam_write_reg(cam, VCR_VSTRIDE, - cam->user_format.bytesperline & VCR_VS_STRIDE); - /* - * Set up the capture interface control register, - * everything but the "go" bit. - * - * The FIFO threshold is a bit of a magic number; 8 is what - * VIA's sample code uses. - */ - cicreg = VCR_CI_CLKEN | - 0x08000000 | /* FIFO threshold */ - VCR_CI_FLDINV | /* OLPC-specific? */ - VCR_CI_VREFINV | /* OLPC-specific? */ - VCR_CI_DIBOTH | /* Capture both fields */ - VCR_CI_CCIR601_8; - if (cam->n_cap_bufs == 3) - cicreg |= VCR_CI_3BUFS; - /* - * YUV formats need different byte swapping than RGB. - */ - if (cam->user_format.pixelformat == V4L2_PIX_FMT_YUYV) - cicreg |= VCR_CI_YUYV; - else - cicreg |= VCR_CI_UYVY; - viacam_write_reg(cam, VCR_CAPINTC, cicreg); -} - - -static int viacam_config_controller(struct via_camera *cam) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&cam->viadev->reg_lock, flags); - ret = viacam_ctlr_cbufs(cam); - if (!ret) - viacam_ctlr_image(cam); - spin_unlock_irqrestore(&cam->viadev->reg_lock, flags); - clear_bit(CF_CONFIG_NEEDED, &cam->flags); - return ret; -} - -/* - * Make it start grabbing data. - */ -static void viacam_start_engine(struct via_camera *cam) -{ - spin_lock_irq(&cam->viadev->reg_lock); - cam->next_buf = 0; - viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_ENABLE, VCR_CI_ENABLE); - viacam_int_enable(cam); - (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */ - cam->opstate = S_RUNNING; - spin_unlock_irq(&cam->viadev->reg_lock); -} - - -static void viacam_stop_engine(struct via_camera *cam) -{ - spin_lock_irq(&cam->viadev->reg_lock); - viacam_int_disable(cam); - viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_ENABLE); - (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */ - cam->opstate = S_IDLE; - spin_unlock_irq(&cam->viadev->reg_lock); -} - - -/* --------------------------------------------------------------------------*/ -/* Videobuf callback ops */ - -/* - * buffer_setup. The purpose of this one would appear to be to tell - * videobuf how big a single image is. It's also evidently up to us - * to put some sort of limit on the maximum number of buffers allowed. - */ -static int viacam_vb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) -{ - struct via_camera *cam = q->priv_data; - - *size = cam->user_format.sizeimage; - if (*count == 0 || *count > 6) /* Arbitrary number */ - *count = 6; - return 0; -} - -/* - * Prepare a buffer. - */ -static int viacam_vb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) -{ - struct via_camera *cam = q->priv_data; - - vb->size = cam->user_format.sizeimage; - vb->width = cam->user_format.width; /* bytesperline???? */ - vb->height = cam->user_format.height; - vb->field = field; - if (vb->state == VIDEOBUF_NEEDS_INIT) { - int ret = videobuf_iolock(q, vb, NULL); - if (ret) - return ret; - } - vb->state = VIDEOBUF_PREPARED; - return 0; -} - -/* - * We've got a buffer to put data into. - * - * FIXME: check for a running engine and valid buffers? - */ -static void viacam_vb_buf_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct via_camera *cam = q->priv_data; - - /* - * Note that videobuf holds the lock when it calls - * us, so we need not (indeed, cannot) take it here. - */ - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &cam->buffer_queue); -} - -/* - * Free a buffer. - */ -static void viacam_vb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct via_camera *cam = q->priv_data; - - videobuf_dma_unmap(&cam->platdev->dev, videobuf_to_dma(vb)); - videobuf_dma_free(videobuf_to_dma(vb)); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static const struct videobuf_queue_ops viacam_vb_ops = { - .buf_setup = viacam_vb_buf_setup, - .buf_prepare = viacam_vb_buf_prepare, - .buf_queue = viacam_vb_buf_queue, - .buf_release = viacam_vb_buf_release, -}; - -/* --------------------------------------------------------------------------*/ -/* File operations */ - -static int viacam_open(struct file *filp) -{ - struct via_camera *cam = video_drvdata(filp); - - filp->private_data = cam; - /* - * Note the new user. If this is the first one, we'll also - * need to power up the sensor. - */ - mutex_lock(&cam->lock); - if (cam->users == 0) { - int ret = viafb_request_dma(); - - if (ret) { - mutex_unlock(&cam->lock); - return ret; - } - via_sensor_power_up(cam); - set_bit(CF_CONFIG_NEEDED, &cam->flags); - /* - * Hook into videobuf. Evidently this cannot fail. - */ - videobuf_queue_sg_init(&cam->vb_queue, &viacam_vb_ops, - &cam->platdev->dev, &cam->viadev->reg_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), cam, NULL); - } - (cam->users)++; - mutex_unlock(&cam->lock); - return 0; -} - -static int viacam_release(struct file *filp) -{ - struct via_camera *cam = video_drvdata(filp); - - mutex_lock(&cam->lock); - (cam->users)--; - /* - * If the "owner" is closing, shut down any ongoing - * operations. - */ - if (filp == cam->owner) { - videobuf_stop(&cam->vb_queue); - /* - * We don't hold the spinlock here, but, if release() - * is being called by the owner, nobody else will - * be changing the state. And an extra stop would - * not hurt anyway. - */ - if (cam->opstate != S_IDLE) - viacam_stop_engine(cam); - cam->owner = NULL; - } - /* - * Last one out needs to turn out the lights. - */ - if (cam->users == 0) { - videobuf_mmap_free(&cam->vb_queue); - via_sensor_power_down(cam); - viafb_release_dma(); - } - mutex_unlock(&cam->lock); - return 0; -} - -/* - * Read a frame from the device. - */ -static ssize_t viacam_read(struct file *filp, char __user *buffer, - size_t len, loff_t *pos) -{ - struct via_camera *cam = video_drvdata(filp); - int ret; - - mutex_lock(&cam->lock); - /* - * Enforce the V4l2 "only one owner gets to read data" rule. - */ - if (cam->owner && cam->owner != filp) { - ret = -EBUSY; - goto out_unlock; - } - cam->owner = filp; - /* - * Do we need to configure the hardware? - */ - if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) { - ret = viacam_configure_sensor(cam); - if (!ret) - ret = viacam_config_controller(cam); - if (ret) - goto out_unlock; - } - /* - * Fire up the capture engine, then have videobuf do - * the heavy lifting. Someday it would be good to avoid - * stopping and restarting the engine each time. - */ - INIT_LIST_HEAD(&cam->buffer_queue); - viacam_start_engine(cam); - ret = videobuf_read_stream(&cam->vb_queue, buffer, len, pos, 0, - filp->f_flags & O_NONBLOCK); - viacam_stop_engine(cam); - /* videobuf_stop() ?? */ - -out_unlock: - mutex_unlock(&cam->lock); - return ret; -} - - -static unsigned int viacam_poll(struct file *filp, struct poll_table_struct *pt) -{ - struct via_camera *cam = video_drvdata(filp); - - return videobuf_poll_stream(filp, &cam->vb_queue, pt); -} - - -static int viacam_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct via_camera *cam = video_drvdata(filp); - - return videobuf_mmap_mapper(&cam->vb_queue, vma); -} - - - -static const struct v4l2_file_operations viacam_fops = { - .owner = THIS_MODULE, - .open = viacam_open, - .release = viacam_release, - .read = viacam_read, - .poll = viacam_poll, - .mmap = viacam_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -/*----------------------------------------------------------------------------*/ -/* - * The long list of v4l2 ioctl ops - */ - -static int viacam_g_chip_ident(struct file *file, void *priv, - struct v4l2_dbg_chip_ident *ident) -{ - struct via_camera *cam = priv; - - ident->ident = V4L2_IDENT_NONE; - ident->revision = 0; - if (v4l2_chip_match_host(&ident->match)) { - ident->ident = V4L2_IDENT_VIA_VX855; - return 0; - } - return sensor_call(cam, core, g_chip_ident, ident); -} - -/* - * Control ops are passed through to the sensor. - */ -static int viacam_queryctrl(struct file *filp, void *priv, - struct v4l2_queryctrl *qc) -{ - struct via_camera *cam = priv; - int ret; - - mutex_lock(&cam->lock); - ret = sensor_call(cam, core, queryctrl, qc); - mutex_unlock(&cam->lock); - return ret; -} - - -static int viacam_g_ctrl(struct file *filp, void *priv, - struct v4l2_control *ctrl) -{ - struct via_camera *cam = priv; - int ret; - - mutex_lock(&cam->lock); - ret = sensor_call(cam, core, g_ctrl, ctrl); - mutex_unlock(&cam->lock); - return ret; -} - - -static int viacam_s_ctrl(struct file *filp, void *priv, - struct v4l2_control *ctrl) -{ - struct via_camera *cam = priv; - int ret; - - mutex_lock(&cam->lock); - ret = sensor_call(cam, core, s_ctrl, ctrl); - mutex_unlock(&cam->lock); - return ret; -} - -/* - * Only one input. - */ -static int viacam_enum_input(struct file *filp, void *priv, - struct v4l2_input *input) -{ - if (input->index != 0) - return -EINVAL; - - input->type = V4L2_INPUT_TYPE_CAMERA; - input->std = V4L2_STD_ALL; /* Not sure what should go here */ - strcpy(input->name, "Camera"); - return 0; -} - -static int viacam_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int viacam_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id *std) -{ - return 0; -} - -/* - * Video format stuff. Here is our default format until - * user space messes with things. - */ -static const struct v4l2_pix_format viacam_def_pix_format = { - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .pixelformat = V4L2_PIX_FMT_YUYV, - .field = V4L2_FIELD_NONE, - .bytesperline = VGA_WIDTH * 2, - .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, -}; - -static const enum v4l2_mbus_pixelcode via_def_mbus_code = V4L2_MBUS_FMT_YUYV8_2X8; - -static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_fmtdesc *fmt) -{ - if (fmt->index >= N_VIA_FMTS) - return -EINVAL; - strlcpy(fmt->description, via_formats[fmt->index].desc, - sizeof(fmt->description)); - fmt->pixelformat = via_formats[fmt->index].pixelformat; - return 0; -} - -/* - * Figure out proper image dimensions, but always force the - * sensor to VGA. - */ -static void viacam_fmt_pre(struct v4l2_pix_format *userfmt, - struct v4l2_pix_format *sensorfmt) -{ - *sensorfmt = *userfmt; - if (userfmt->width < QCIF_WIDTH || userfmt->height < QCIF_HEIGHT) { - userfmt->width = QCIF_WIDTH; - userfmt->height = QCIF_HEIGHT; - } - if (userfmt->width > VGA_WIDTH || userfmt->height > VGA_HEIGHT) { - userfmt->width = VGA_WIDTH; - userfmt->height = VGA_HEIGHT; - } - sensorfmt->width = VGA_WIDTH; - sensorfmt->height = VGA_HEIGHT; -} - -static void viacam_fmt_post(struct v4l2_pix_format *userfmt, - struct v4l2_pix_format *sensorfmt) -{ - struct via_format *f = via_find_format(userfmt->pixelformat); - - sensorfmt->bytesperline = sensorfmt->width * f->bpp; - sensorfmt->sizeimage = sensorfmt->height * sensorfmt->bytesperline; - userfmt->pixelformat = sensorfmt->pixelformat; - userfmt->field = sensorfmt->field; - userfmt->bytesperline = 2 * userfmt->width; - userfmt->sizeimage = userfmt->bytesperline * userfmt->height; -} - - -/* - * The real work of figuring out a workable format. - */ -static int viacam_do_try_fmt(struct via_camera *cam, - struct v4l2_pix_format *upix, struct v4l2_pix_format *spix) -{ - int ret; - struct v4l2_mbus_framefmt mbus_fmt; - struct via_format *f = via_find_format(upix->pixelformat); - - upix->pixelformat = f->pixelformat; - viacam_fmt_pre(upix, spix); - v4l2_fill_mbus_format(&mbus_fmt, upix, f->mbus_code); - ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(spix, &mbus_fmt); - viacam_fmt_post(upix, spix); - return ret; -} - - - -static int viacam_try_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_format *fmt) -{ - struct via_camera *cam = priv; - struct v4l2_format sfmt; - int ret; - - mutex_lock(&cam->lock); - ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix); - mutex_unlock(&cam->lock); - return ret; -} - - -static int viacam_g_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_format *fmt) -{ - struct via_camera *cam = priv; - - mutex_lock(&cam->lock); - fmt->fmt.pix = cam->user_format; - mutex_unlock(&cam->lock); - return 0; -} - -static int viacam_s_fmt_vid_cap(struct file *filp, void *priv, - struct v4l2_format *fmt) -{ - struct via_camera *cam = priv; - int ret; - struct v4l2_format sfmt; - struct via_format *f = via_find_format(fmt->fmt.pix.pixelformat); - - /* - * Camera must be idle or we can't mess with the - * video setup. - */ - mutex_lock(&cam->lock); - if (cam->opstate != S_IDLE) { - ret = -EBUSY; - goto out; - } - /* - * Let the sensor code look over and tweak the - * requested formatting. - */ - ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix); - if (ret) - goto out; - /* - * OK, let's commit to the new format. - */ - cam->user_format = fmt->fmt.pix; - cam->sensor_format = sfmt.fmt.pix; - cam->mbus_code = f->mbus_code; - ret = viacam_configure_sensor(cam); - if (!ret) - ret = viacam_config_controller(cam); -out: - mutex_unlock(&cam->lock); - return ret; -} - -static int viacam_querycap(struct file *filp, void *priv, - struct v4l2_capability *cap) -{ - strcpy(cap->driver, "via-camera"); - strcpy(cap->card, "via-camera"); - cap->version = 1; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - return 0; -} - -/* - * Streaming operations - pure videobuf stuff. - */ -static int viacam_reqbufs(struct file *filp, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct via_camera *cam = priv; - - return videobuf_reqbufs(&cam->vb_queue, rb); -} - -static int viacam_querybuf(struct file *filp, void *priv, - struct v4l2_buffer *buf) -{ - struct via_camera *cam = priv; - - return videobuf_querybuf(&cam->vb_queue, buf); -} - -static int viacam_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) -{ - struct via_camera *cam = priv; - - return videobuf_qbuf(&cam->vb_queue, buf); -} - -static int viacam_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) -{ - struct via_camera *cam = priv; - - return videobuf_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK); -} - -static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t) -{ - struct via_camera *cam = priv; - int ret = 0; - - if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - mutex_lock(&cam->lock); - if (cam->opstate != S_IDLE) { - ret = -EBUSY; - goto out; - } - /* - * Enforce the V4l2 "only one owner gets to read data" rule. - */ - if (cam->owner && cam->owner != filp) { - ret = -EBUSY; - goto out; - } - cam->owner = filp; - /* - * Configure things if need be. - */ - if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) { - ret = viacam_configure_sensor(cam); - if (ret) - goto out; - ret = viacam_config_controller(cam); - if (ret) - goto out; - } - /* - * If the CPU goes into C3, the DMA transfer gets corrupted and - * users start filing unsightly bug reports. Put in a "latency" - * requirement which will keep the CPU out of the deeper sleep - * states. - */ - pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50); - /* - * Fire things up. - */ - INIT_LIST_HEAD(&cam->buffer_queue); - ret = videobuf_streamon(&cam->vb_queue); - if (!ret) - viacam_start_engine(cam); -out: - mutex_unlock(&cam->lock); - return ret; -} - -static int viacam_streamoff(struct file *filp, void *priv, enum v4l2_buf_type t) -{ - struct via_camera *cam = priv; - int ret; - - if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - mutex_lock(&cam->lock); - if (cam->opstate != S_RUNNING) { - ret = -EINVAL; - goto out; - } - pm_qos_remove_request(&cam->qos_request); - viacam_stop_engine(cam); - /* - * Videobuf will recycle all of the outstanding buffers, but - * we should be sure we don't retain any references to - * any of them. - */ - ret = videobuf_streamoff(&cam->vb_queue); - INIT_LIST_HEAD(&cam->buffer_queue); -out: - mutex_unlock(&cam->lock); - return ret; -} - -/* G/S_PARM */ - -static int viacam_g_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parm) -{ - struct via_camera *cam = priv; - int ret; - - mutex_lock(&cam->lock); - ret = sensor_call(cam, video, g_parm, parm); - mutex_unlock(&cam->lock); - parm->parm.capture.readbuffers = cam->n_cap_bufs; - return ret; -} - -static int viacam_s_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parm) -{ - struct via_camera *cam = priv; - int ret; - - mutex_lock(&cam->lock); - ret = sensor_call(cam, video, s_parm, parm); - mutex_unlock(&cam->lock); - parm->parm.capture.readbuffers = cam->n_cap_bufs; - return ret; -} - -static int viacam_enum_framesizes(struct file *filp, void *priv, - struct v4l2_frmsizeenum *sizes) -{ - if (sizes->index != 0) - return -EINVAL; - sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; - sizes->stepwise.min_width = QCIF_WIDTH; - sizes->stepwise.min_height = QCIF_HEIGHT; - sizes->stepwise.max_width = VGA_WIDTH; - sizes->stepwise.max_height = VGA_HEIGHT; - sizes->stepwise.step_width = sizes->stepwise.step_height = 1; - return 0; -} - -static int viacam_enum_frameintervals(struct file *filp, void *priv, - struct v4l2_frmivalenum *interval) -{ - struct via_camera *cam = priv; - int ret; - - mutex_lock(&cam->lock); - ret = sensor_call(cam, video, enum_frameintervals, interval); - mutex_unlock(&cam->lock); - return ret; -} - - - -static const struct v4l2_ioctl_ops viacam_ioctl_ops = { - .vidioc_g_chip_ident = viacam_g_chip_ident, - .vidioc_queryctrl = viacam_queryctrl, - .vidioc_g_ctrl = viacam_g_ctrl, - .vidioc_s_ctrl = viacam_s_ctrl, - .vidioc_enum_input = viacam_enum_input, - .vidioc_g_input = viacam_g_input, - .vidioc_s_input = viacam_s_input, - .vidioc_s_std = viacam_s_std, - .vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = viacam_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = viacam_s_fmt_vid_cap, - .vidioc_querycap = viacam_querycap, - .vidioc_reqbufs = viacam_reqbufs, - .vidioc_querybuf = viacam_querybuf, - .vidioc_qbuf = viacam_qbuf, - .vidioc_dqbuf = viacam_dqbuf, - .vidioc_streamon = viacam_streamon, - .vidioc_streamoff = viacam_streamoff, - .vidioc_g_parm = viacam_g_parm, - .vidioc_s_parm = viacam_s_parm, - .vidioc_enum_framesizes = viacam_enum_framesizes, - .vidioc_enum_frameintervals = viacam_enum_frameintervals, -}; - -/*----------------------------------------------------------------------------*/ - -/* - * Power management. - */ -#ifdef CONFIG_PM - -static int viacam_suspend(void *priv) -{ - struct via_camera *cam = priv; - enum viacam_opstate state = cam->opstate; - - if (cam->opstate != S_IDLE) { - viacam_stop_engine(cam); - cam->opstate = state; /* So resume restarts */ - } - - return 0; -} - -static int viacam_resume(void *priv) -{ - struct via_camera *cam = priv; - int ret = 0; - - /* - * Get back to a reasonable operating state. - */ - via_write_reg_mask(VIASR, 0x78, 0, 0x80); - via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0); - viacam_int_disable(cam); - set_bit(CF_CONFIG_NEEDED, &cam->flags); - /* - * Make sure the sensor's power state is correct - */ - if (cam->users > 0) - via_sensor_power_up(cam); - else - via_sensor_power_down(cam); - /* - * If it was operating, try to restart it. - */ - if (cam->opstate != S_IDLE) { - mutex_lock(&cam->lock); - ret = viacam_configure_sensor(cam); - if (!ret) - ret = viacam_config_controller(cam); - mutex_unlock(&cam->lock); - if (!ret) - viacam_start_engine(cam); - } - - return ret; -} - -static struct viafb_pm_hooks viacam_pm_hooks = { - .suspend = viacam_suspend, - .resume = viacam_resume -}; - -#endif /* CONFIG_PM */ - -/* - * Setup stuff. - */ - -static struct video_device viacam_v4l_template = { - .name = "via-camera", - .minor = -1, - .tvnorms = V4L2_STD_NTSC_M, - .current_norm = V4L2_STD_NTSC_M, - .fops = &viacam_fops, - .ioctl_ops = &viacam_ioctl_ops, - .release = video_device_release_empty, /* Check this */ -}; - -/* - * The OLPC folks put the serial port on the same pin as - * the camera. They also get grumpy if we break the - * serial port and keep them from using it. So we have - * to check the serial enable bit and not step on it. - */ -#define VIACAM_SERIAL_DEVFN 0x88 -#define VIACAM_SERIAL_CREG 0x46 -#define VIACAM_SERIAL_BIT 0x40 - -static __devinit bool viacam_serial_is_enabled(void) -{ - struct pci_bus *pbus = pci_find_bus(0, 0); - u8 cbyte; - - pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN, - VIACAM_SERIAL_CREG, &cbyte); - if ((cbyte & VIACAM_SERIAL_BIT) == 0) - return false; /* Not enabled */ - if (override_serial == 0) { - printk(KERN_NOTICE "Via camera: serial port is enabled, " \ - "refusing to load.\n"); - printk(KERN_NOTICE "Specify override_serial=1 to force " \ - "module loading.\n"); - return true; - } - printk(KERN_NOTICE "Via camera: overriding serial port\n"); - pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN, - VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT); - return false; -} - -static __devinit int viacam_probe(struct platform_device *pdev) -{ - int ret; - struct i2c_adapter *sensor_adapter; - struct viafb_dev *viadev = pdev->dev.platform_data; - - /* - * Note that there are actually two capture channels on - * the device. We only deal with one for now. That - * is encoded here; nothing else assumes it's dealing with - * a unique capture device. - */ - struct via_camera *cam; - - /* - * Ensure that frame buffer memory has been set aside for - * this purpose. As an arbitrary limit, refuse to work - * with less than two frames of VGA 16-bit data. - * - * If we ever support the second port, we'll need to set - * aside more memory. - */ - if (viadev->camera_fbmem_size < (VGA_HEIGHT*VGA_WIDTH*4)) { - printk(KERN_ERR "viacam: insufficient FB memory reserved\n"); - return -ENOMEM; - } - if (viadev->engine_mmio == NULL) { - printk(KERN_ERR "viacam: No I/O memory, so no pictures\n"); - return -ENOMEM; - } - - if (machine_is_olpc() && viacam_serial_is_enabled()) - return -EBUSY; - - /* - * Basic structure initialization. - */ - cam = kzalloc (sizeof(struct via_camera), GFP_KERNEL); - if (cam == NULL) - return -ENOMEM; - via_cam_info = cam; - cam->platdev = pdev; - cam->viadev = viadev; - cam->users = 0; - cam->owner = NULL; - cam->opstate = S_IDLE; - cam->user_format = cam->sensor_format = viacam_def_pix_format; - mutex_init(&cam->lock); - INIT_LIST_HEAD(&cam->buffer_queue); - cam->mmio = viadev->engine_mmio; - cam->fbmem = viadev->fbmem; - cam->fb_offset = viadev->camera_fbmem_offset; - cam->flags = 1 << CF_CONFIG_NEEDED; - cam->mbus_code = via_def_mbus_code; - /* - * Tell V4L that we exist. - */ - ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev); - if (ret) { - dev_err(&pdev->dev, "Unable to register v4l2 device\n"); - return ret; - } - /* - * Convince the system that we can do DMA. - */ - pdev->dev.dma_mask = &viadev->pdev->dma_mask; - dma_set_mask(&pdev->dev, 0xffffffff); - /* - * Fire up the capture port. The write to 0x78 looks purely - * OLPCish; any system will need to tweak 0x1e. - */ - via_write_reg_mask(VIASR, 0x78, 0, 0x80); - via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0); - /* - * Get the sensor powered up. - */ - ret = via_sensor_power_setup(cam); - if (ret) - goto out_unregister; - via_sensor_power_up(cam); - - /* - * See if we can't find it on the bus. The VIA_PORT_31 assumption - * is OLPC-specific. 0x42 assumption is ov7670-specific. - */ - sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31); - cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter, - "ov7670", 0x42 >> 1, NULL); - if (cam->sensor == NULL) { - dev_err(&pdev->dev, "Unable to find the sensor!\n"); - ret = -ENODEV; - goto out_power_down; - } - /* - * Get the IRQ. - */ - viacam_int_disable(cam); - ret = request_threaded_irq(viadev->pdev->irq, viacam_quick_irq, - viacam_irq, IRQF_SHARED, "via-camera", cam); - if (ret) - goto out_power_down; - /* - * Tell V4l2 that we exist. - */ - cam->vdev = viacam_v4l_template; - cam->vdev.v4l2_dev = &cam->v4l2_dev; - ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); - if (ret) - goto out_irq; - video_set_drvdata(&cam->vdev, cam); - -#ifdef CONFIG_PM - /* - * Hook into PM events - */ - viacam_pm_hooks.private = cam; - viafb_pm_register(&viacam_pm_hooks); -#endif - - /* Power the sensor down until somebody opens the device */ - via_sensor_power_down(cam); - return 0; - -out_irq: - free_irq(viadev->pdev->irq, cam); -out_power_down: - via_sensor_power_release(cam); -out_unregister: - v4l2_device_unregister(&cam->v4l2_dev); - return ret; -} - -static __devexit int viacam_remove(struct platform_device *pdev) -{ - struct via_camera *cam = via_cam_info; - struct viafb_dev *viadev = pdev->dev.platform_data; - - video_unregister_device(&cam->vdev); - v4l2_device_unregister(&cam->v4l2_dev); - free_irq(viadev->pdev->irq, cam); - via_sensor_power_release(cam); - via_cam_info = NULL; - return 0; -} - -static struct platform_driver viacam_driver = { - .driver = { - .name = "viafb-camera", - }, - .probe = viacam_probe, - .remove = viacam_remove, -}; - -static int viacam_init(void) -{ - return platform_driver_register(&viacam_driver); -} -module_init(viacam_init); - -static void viacam_exit(void) -{ - platform_driver_unregister(&viacam_driver); -} -module_exit(viacam_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/via-camera.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/via-camera.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/via-camera.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/via-camera.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/* - * VIA Camera register definitions. - */ -#define VCR_INTCTRL 0x300 /* Capture interrupt control */ -#define VCR_IC_EAV 0x0001 /* End of active video status */ -#define VCR_IC_EVBI 0x0002 /* End of VBI status */ -#define VCR_IC_FBOTFLD 0x0004 /* "flipping" Bottom field is active */ -#define VCR_IC_ACTBUF 0x0018 /* Active video buffer */ -#define VCR_IC_VSYNC 0x0020 /* 0 = VB, 1 = active video */ -#define VCR_IC_BOTFLD 0x0040 /* Bottom field is active */ -#define VCR_IC_FFULL 0x0080 /* FIFO full */ -#define VCR_IC_INTEN 0x0100 /* End of active video int. enable */ -#define VCR_IC_VBIINT 0x0200 /* End of VBI int enable */ -#define VCR_IC_VBIBUF 0x0400 /* Current VBI buffer */ - -#define VCR_TSC 0x308 /* Transport stream control */ -#define VCR_TSC_ENABLE 0x000001 /* Transport stream input enable */ -#define VCR_TSC_DROPERR 0x000002 /* Drop error packets */ -#define VCR_TSC_METHOD 0x00000c /* DMA method (non-functional) */ -#define VCR_TSC_COUNT 0x07fff0 /* KByte or packet count */ -#define VCR_TSC_CBMODE 0x080000 /* Change buffer by byte count */ -#define VCR_TSC_PSSIG 0x100000 /* Packet starting signal disable */ -#define VCR_TSC_BE 0x200000 /* MSB first (serial mode) */ -#define VCR_TSC_SERIAL 0x400000 /* Serial input (0 = parallel) */ - -#define VCR_CAPINTC 0x310 /* Capture interface control */ -#define VCR_CI_ENABLE 0x00000001 /* Capture enable */ -#define VCR_CI_BSS 0x00000002 /* WTF "bit stream selection" */ -#define VCR_CI_3BUFS 0x00000004 /* 1 = 3 buffers, 0 = 2 buffers */ -#define VCR_CI_VIPEN 0x00000008 /* VIP enable */ -#define VCR_CI_CCIR601_8 0 /* CCIR601 input stream, 8 bit */ -#define VCR_CI_CCIR656_8 0x00000010 /* ... CCIR656, 8 bit */ -#define VCR_CI_CCIR601_16 0x00000020 /* ... CCIR601, 16 bit */ -#define VCR_CI_CCIR656_16 0x00000030 /* ... CCIR656, 16 bit */ -#define VCR_CI_HDMODE 0x00000040 /* CCIR656-16 hdr decode mode; 1=16b */ -#define VCR_CI_BSWAP 0x00000080 /* Swap bytes (16-bit) */ -#define VCR_CI_YUYV 0 /* Byte order 0123 */ -#define VCR_CI_UYVY 0x00000100 /* Byte order 1032 */ -#define VCR_CI_YVYU 0x00000200 /* Byte order 0321 */ -#define VCR_CI_VYUY 0x00000300 /* Byte order 3012 */ -#define VCR_CI_VIPTYPE 0x00000400 /* VIP type */ -#define VCR_CI_IFSEN 0x00000800 /* Input field signal enable */ -#define VCR_CI_DIODD 0 /* De-interlace odd, 30fps */ -#define VCR_CI_DIEVEN 0x00001000 /* ...even field, 30fps */ -#define VCR_CI_DIBOTH 0x00002000 /* ...both fields, 60fps */ -#define VCR_CI_DIBOTH30 0x00003000 /* ...both fields, 30fps interlace */ -#define VCR_CI_CONVTYPE 0x00004000 /* 4:2:2 to 4:4:4; 1 = interpolate */ -#define VCR_CI_CFC 0x00008000 /* Capture flipping control */ -#define VCR_CI_FILTER 0x00070000 /* Horiz filter mode select - 000 = none - 001 = 2 tap - 010 = 3 tap - 011 = 4 tap - 100 = 5 tap */ -#define VCR_CI_CLKINV 0x00080000 /* Input CLK inverted */ -#define VCR_CI_VREFINV 0x00100000 /* VREF inverted */ -#define VCR_CI_HREFINV 0x00200000 /* HREF inverted */ -#define VCR_CI_FLDINV 0x00400000 /* Field inverted */ -#define VCR_CI_CLKPIN 0x00800000 /* Capture clock pin */ -#define VCR_CI_THRESH 0x0f000000 /* Capture fifo threshold */ -#define VCR_CI_HRLE 0x10000000 /* Positive edge of HREF */ -#define VCR_CI_VRLE 0x20000000 /* Positive edge of VREF */ -#define VCR_CI_OFLDINV 0x40000000 /* Field output inverted */ -#define VCR_CI_CLKEN 0x80000000 /* Capture clock enable */ - -#define VCR_HORRANGE 0x314 /* Active video horizontal range */ -#define VCR_VERTRANGE 0x318 /* Active video vertical range */ -#define VCR_AVSCALE 0x31c /* Active video scaling control */ -#define VCR_AVS_HEN 0x00000800 /* Horizontal scale enable */ -#define VCR_AVS_VEN 0x04000000 /* Vertical enable */ -#define VCR_VBIHOR 0x320 /* VBI Data horizontal range */ -#define VCR_VBIVERT 0x324 /* VBI data vertical range */ -#define VCR_VBIBUF1 0x328 /* First VBI buffer */ -#define VCR_VBISTRIDE 0x32c /* VBI stride */ -#define VCR_ANCDATACNT 0x330 /* Ancillary data count setting */ -#define VCR_MAXDATA 0x334 /* Active data count of active video */ -#define VCR_MAXVBI 0x338 /* Maximum data count of VBI */ -#define VCR_CAPDATA 0x33c /* Capture data count */ -#define VCR_VBUF1 0x340 /* First video buffer */ -#define VCR_VBUF2 0x344 /* Second video buffer */ -#define VCR_VBUF3 0x348 /* Third video buffer */ -#define VCR_VBUF_MASK 0x1ffffff0 /* Bits 28:4 */ -#define VCR_VBIBUF2 0x34c /* Second VBI buffer */ -#define VCR_VSTRIDE 0x350 /* Stride of video + coring control */ -#define VCR_VS_STRIDE_SHIFT 4 -#define VCR_VS_STRIDE 0x00001ff0 /* Stride (8-byte units) */ -#define VCR_VS_CCD 0x007f0000 /* Coring compare data */ -#define VCR_VS_COREEN 0x00800000 /* Coring enable */ -#define VCR_TS0ERR 0x354 /* TS buffer 0 error indicator */ -#define VCR_TS1ERR 0x358 /* TS buffer 0 error indicator */ -#define VCR_TS2ERR 0x35c /* TS buffer 0 error indicator */ - -/* Add 0x1000 for the second capture engine registers */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1819 +0,0 @@ -/* - * videobuf2-core.c - V4L2 driver helper framework - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Pawel Osciak - * Marek Szyprowski - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -static int debug; -module_param(debug, int, 0644); - -#define dprintk(level, fmt, arg...) \ - do { \ - if (debug >= level) \ - printk(KERN_DEBUG "vb2: " fmt, ## arg); \ - } while (0) - -#define call_memop(q, plane, op, args...) \ - (((q)->mem_ops->op) ? \ - ((q)->mem_ops->op(args)) : 0) - -#define call_qop(q, op, args...) \ - (((q)->ops->op) ? ((q)->ops->op(args)) : 0) - -/** - * __vb2_buf_mem_alloc() - allocate video memory for the given buffer - */ -static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, - unsigned long *plane_sizes) -{ - struct vb2_queue *q = vb->vb2_queue; - void *mem_priv; - int plane; - - /* Allocate memory for all planes in this buffer */ - for (plane = 0; plane < vb->num_planes; ++plane) { - mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], - plane_sizes[plane]); - if (!mem_priv) - goto free; - - /* Associate allocator private data with this plane */ - vb->planes[plane].mem_priv = mem_priv; - vb->v4l2_planes[plane].length = plane_sizes[plane]; - } - - return 0; -free: - /* Free already allocated memory if one of the allocations failed */ - for (; plane > 0; --plane) - call_memop(q, plane, put, vb->planes[plane - 1].mem_priv); - - return -ENOMEM; -} - -/** - * __vb2_buf_mem_free() - free memory of the given buffer - */ -static void __vb2_buf_mem_free(struct vb2_buffer *vb) -{ - struct vb2_queue *q = vb->vb2_queue; - unsigned int plane; - - for (plane = 0; plane < vb->num_planes; ++plane) { - call_memop(q, plane, put, vb->planes[plane].mem_priv); - vb->planes[plane].mem_priv = NULL; - dprintk(3, "Freed plane %d of buffer %d\n", - plane, vb->v4l2_buf.index); - } -} - -/** - * __vb2_buf_userptr_put() - release userspace memory associated with - * a USERPTR buffer - */ -static void __vb2_buf_userptr_put(struct vb2_buffer *vb) -{ - struct vb2_queue *q = vb->vb2_queue; - unsigned int plane; - - for (plane = 0; plane < vb->num_planes; ++plane) { - void *mem_priv = vb->planes[plane].mem_priv; - - if (mem_priv) { - call_memop(q, plane, put_userptr, mem_priv); - vb->planes[plane].mem_priv = NULL; - } - } -} - -/** - * __setup_offsets() - setup unique offsets ("cookies") for every plane in - * every buffer on the queue - */ -static void __setup_offsets(struct vb2_queue *q) -{ - unsigned int buffer, plane; - struct vb2_buffer *vb; - unsigned long off = 0; - - for (buffer = 0; buffer < q->num_buffers; ++buffer) { - vb = q->bufs[buffer]; - if (!vb) - continue; - - for (plane = 0; plane < vb->num_planes; ++plane) { - vb->v4l2_planes[plane].m.mem_offset = off; - - dprintk(3, "Buffer %d, plane %d offset 0x%08lx\n", - buffer, plane, off); - - off += vb->v4l2_planes[plane].length; - off = PAGE_ALIGN(off); - } - } -} - -/** - * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type) - * video buffer memory for all buffers/planes on the queue and initializes the - * queue - * - * Returns the number of buffers successfully allocated. - */ -static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, - unsigned int num_buffers, unsigned int num_planes, - unsigned long plane_sizes[]) -{ - unsigned int buffer; - struct vb2_buffer *vb; - int ret; - - for (buffer = 0; buffer < num_buffers; ++buffer) { - /* Allocate videobuf buffer structures */ - vb = kzalloc(q->buf_struct_size, GFP_KERNEL); - if (!vb) { - dprintk(1, "Memory alloc for buffer struct failed\n"); - break; - } - - /* Length stores number of planes for multiplanar buffers */ - if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) - vb->v4l2_buf.length = num_planes; - - vb->state = VB2_BUF_STATE_DEQUEUED; - vb->vb2_queue = q; - vb->num_planes = num_planes; - vb->v4l2_buf.index = buffer; - vb->v4l2_buf.type = q->type; - vb->v4l2_buf.memory = memory; - - /* Allocate video buffer memory for the MMAP type */ - if (memory == V4L2_MEMORY_MMAP) { - ret = __vb2_buf_mem_alloc(vb, plane_sizes); - if (ret) { - dprintk(1, "Failed allocating memory for " - "buffer %d\n", buffer); - kfree(vb); - break; - } - /* - * Call the driver-provided buffer initialization - * callback, if given. An error in initialization - * results in queue setup failure. - */ - ret = call_qop(q, buf_init, vb); - if (ret) { - dprintk(1, "Buffer %d %p initialization" - " failed\n", buffer, vb); - __vb2_buf_mem_free(vb); - kfree(vb); - break; - } - } - - q->bufs[buffer] = vb; - } - - q->num_buffers = buffer; - - __setup_offsets(q); - - dprintk(1, "Allocated %d buffers, %d plane(s) each\n", - q->num_buffers, num_planes); - - return buffer; -} - -/** - * __vb2_free_mem() - release all video buffer memory for a given queue - */ -static void __vb2_free_mem(struct vb2_queue *q) -{ - unsigned int buffer; - struct vb2_buffer *vb; - - for (buffer = 0; buffer < q->num_buffers; ++buffer) { - vb = q->bufs[buffer]; - if (!vb) - continue; - - /* Free MMAP buffers or release USERPTR buffers */ - if (q->memory == V4L2_MEMORY_MMAP) - __vb2_buf_mem_free(vb); - else - __vb2_buf_userptr_put(vb); - } -} - -/** - * __vb2_queue_free() - free the queue - video memory and related information - * and return the queue to an uninitialized state. Might be called even if the - * queue has already been freed. - */ -static void __vb2_queue_free(struct vb2_queue *q) -{ - unsigned int buffer; - - /* Call driver-provided cleanup function for each buffer, if provided */ - if (q->ops->buf_cleanup) { - for (buffer = 0; buffer < q->num_buffers; ++buffer) { - if (NULL == q->bufs[buffer]) - continue; - q->ops->buf_cleanup(q->bufs[buffer]); - } - } - - /* Release video buffer memory */ - __vb2_free_mem(q); - - /* Free videobuf buffers */ - for (buffer = 0; buffer < q->num_buffers; ++buffer) { - kfree(q->bufs[buffer]); - q->bufs[buffer] = NULL; - } - - q->num_buffers = 0; - q->memory = 0; -} - -/** - * __verify_planes_array() - verify that the planes array passed in struct - * v4l2_buffer from userspace can be safely used - */ -static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b) -{ - /* Is memory for copying plane information present? */ - if (NULL == b->m.planes) { - dprintk(1, "Multi-planar buffer passed but " - "planes array not provided\n"); - return -EINVAL; - } - - if (b->length < vb->num_planes || b->length > VIDEO_MAX_PLANES) { - dprintk(1, "Incorrect planes array length, " - "expected %d, got %d\n", vb->num_planes, b->length); - return -EINVAL; - } - - return 0; -} - -/** - * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be - * returned to userspace - */ -static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) -{ - struct vb2_queue *q = vb->vb2_queue; - int ret = 0; - - /* Copy back data such as timestamp, input, etc. */ - memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); - b->input = vb->v4l2_buf.input; - b->reserved = vb->v4l2_buf.reserved; - - if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) { - ret = __verify_planes_array(vb, b); - if (ret) - return ret; - - /* - * Fill in plane-related data if userspace provided an array - * for it. The memory and size is verified above. - */ - memcpy(b->m.planes, vb->v4l2_planes, - b->length * sizeof(struct v4l2_plane)); - } else { - /* - * We use length and offset in v4l2_planes array even for - * single-planar buffers, but userspace does not. - */ - b->length = vb->v4l2_planes[0].length; - b->bytesused = vb->v4l2_planes[0].bytesused; - if (q->memory == V4L2_MEMORY_MMAP) - b->m.offset = vb->v4l2_planes[0].m.mem_offset; - else if (q->memory == V4L2_MEMORY_USERPTR) - b->m.userptr = vb->v4l2_planes[0].m.userptr; - } - - b->flags = 0; - - switch (vb->state) { - case VB2_BUF_STATE_QUEUED: - case VB2_BUF_STATE_ACTIVE: - b->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case VB2_BUF_STATE_ERROR: - b->flags |= V4L2_BUF_FLAG_ERROR; - /* fall through */ - case VB2_BUF_STATE_DONE: - b->flags |= V4L2_BUF_FLAG_DONE; - break; - case VB2_BUF_STATE_DEQUEUED: - /* nothing */ - break; - } - - if (vb->num_planes_mapped == vb->num_planes) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - return ret; -} - -/** - * vb2_querybuf() - query video buffer information - * @q: videobuf queue - * @b: buffer struct passed from userspace to vidioc_querybuf handler - * in driver - * - * Should be called from vidioc_querybuf ioctl handler in driver. - * This function will verify the passed v4l2_buffer structure and fill the - * relevant information for the userspace. - * - * The return values from this function are intended to be directly returned - * from vidioc_querybuf handler in driver. - */ -int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) -{ - struct vb2_buffer *vb; - - if (b->type != q->type) { - dprintk(1, "querybuf: wrong buffer type\n"); - return -EINVAL; - } - - if (b->index >= q->num_buffers) { - dprintk(1, "querybuf: buffer index out of range\n"); - return -EINVAL; - } - vb = q->bufs[b->index]; - - return __fill_v4l2_buffer(vb, b); -} -EXPORT_SYMBOL(vb2_querybuf); - -/** - * __verify_userptr_ops() - verify that all memory operations required for - * USERPTR queue type have been provided - */ -static int __verify_userptr_ops(struct vb2_queue *q) -{ - if (!(q->io_modes & VB2_USERPTR) || !q->mem_ops->get_userptr || - !q->mem_ops->put_userptr) - return -EINVAL; - - return 0; -} - -/** - * __verify_mmap_ops() - verify that all memory operations required for - * MMAP queue type have been provided - */ -static int __verify_mmap_ops(struct vb2_queue *q) -{ - if (!(q->io_modes & VB2_MMAP) || !q->mem_ops->alloc || - !q->mem_ops->put || !q->mem_ops->mmap) - return -EINVAL; - - return 0; -} - -/** - * __buffers_in_use() - return true if any buffers on the queue are in use and - * the queue cannot be freed (by the means of REQBUFS(0)) call - */ -static bool __buffers_in_use(struct vb2_queue *q) -{ - unsigned int buffer, plane; - struct vb2_buffer *vb; - - for (buffer = 0; buffer < q->num_buffers; ++buffer) { - vb = q->bufs[buffer]; - for (plane = 0; plane < vb->num_planes; ++plane) { - /* - * If num_users() has not been provided, call_memop - * will return 0, apparently nobody cares about this - * case anyway. If num_users() returns more than 1, - * we are not the only user of the plane's memory. - */ - if (call_memop(q, plane, num_users, - vb->planes[plane].mem_priv) > 1) - return true; - } - } - - return false; -} - -/** - * vb2_reqbufs() - Initiate streaming - * @q: videobuf2 queue - * @req: struct passed from userspace to vidioc_reqbufs handler in driver - * - * Should be called from vidioc_reqbufs ioctl handler of a driver. - * This function: - * 1) verifies streaming parameters passed from the userspace, - * 2) sets up the queue, - * 3) negotiates number of buffers and planes per buffer with the driver - * to be used during streaming, - * 4) allocates internal buffer structures (struct vb2_buffer), according to - * the agreed parameters, - * 5) for MMAP memory type, allocates actual video memory, using the - * memory handling/allocation routines provided during queue initialization - * - * If req->count is 0, all the memory will be freed instead. - * If the queue has been allocated previously (by a previous vb2_reqbufs) call - * and the queue is not busy, memory will be reallocated. - * - * The return values from this function are intended to be directly returned - * from vidioc_reqbufs handler in driver. - */ -int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) -{ - unsigned int num_buffers, num_planes; - unsigned long plane_sizes[VIDEO_MAX_PLANES]; - int ret = 0; - - if (q->fileio) { - dprintk(1, "reqbufs: file io in progress\n"); - return -EBUSY; - } - - if (req->memory != V4L2_MEMORY_MMAP - && req->memory != V4L2_MEMORY_USERPTR) { - dprintk(1, "reqbufs: unsupported memory type\n"); - return -EINVAL; - } - - if (req->type != q->type) { - dprintk(1, "reqbufs: requested type is incorrect\n"); - return -EINVAL; - } - - if (q->streaming) { - dprintk(1, "reqbufs: streaming active\n"); - return -EBUSY; - } - - /* - * Make sure all the required memory ops for given memory type - * are available. - */ - if (req->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { - dprintk(1, "reqbufs: MMAP for current setup unsupported\n"); - return -EINVAL; - } - - if (req->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { - dprintk(1, "reqbufs: USERPTR for current setup unsupported\n"); - return -EINVAL; - } - - /* - * If the same number of buffers and memory access method is requested - * then return immediately. - */ - if (q->memory == req->memory && req->count == q->num_buffers) - return 0; - - if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) { - /* - * We already have buffers allocated, so first check if they - * are not in use and can be freed. - */ - if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) { - dprintk(1, "reqbufs: memory in use, cannot free\n"); - return -EBUSY; - } - - __vb2_queue_free(q); - - /* - * In case of REQBUFS(0) return immediately without calling - * driver's queue_setup() callback and allocating resources. - */ - if (req->count == 0) - return 0; - } - - /* - * Make sure the requested values and current defaults are sane. - */ - num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); - memset(plane_sizes, 0, sizeof(plane_sizes)); - memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); - - /* - * Ask the driver how many buffers and planes per buffer it requires. - * Driver also sets the size and allocator context for each plane. - */ - ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, - plane_sizes, q->alloc_ctx); - if (ret) - return ret; - - /* Finally, allocate buffers and video memory */ - ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes, - plane_sizes); - if (ret < 0) { - dprintk(1, "Memory allocation failed with error: %d\n", ret); - return ret; - } - - /* - * Check if driver can handle the allocated number of buffers. - */ - if (ret < num_buffers) { - unsigned int orig_num_buffers; - - orig_num_buffers = num_buffers = ret; - ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, - plane_sizes, q->alloc_ctx); - if (ret) - goto free_mem; - - if (orig_num_buffers < num_buffers) { - ret = -ENOMEM; - goto free_mem; - } - - /* - * Ok, driver accepted smaller number of buffers. - */ - ret = num_buffers; - } - - q->memory = req->memory; - - /* - * Return the number of successfully allocated buffers - * to the userspace. - */ - req->count = ret; - - return 0; - -free_mem: - __vb2_queue_free(q); - return ret; -} -EXPORT_SYMBOL_GPL(vb2_reqbufs); - -/** - * vb2_plane_vaddr() - Return a kernel virtual address of a given plane - * @vb: vb2_buffer to which the plane in question belongs to - * @plane_no: plane number for which the address is to be returned - * - * This function returns a kernel virtual address of a given plane if - * such a mapping exist, NULL otherwise. - */ -void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) -{ - struct vb2_queue *q = vb->vb2_queue; - - if (plane_no > vb->num_planes) - return NULL; - - return call_memop(q, plane_no, vaddr, vb->planes[plane_no].mem_priv); - -} -EXPORT_SYMBOL_GPL(vb2_plane_vaddr); - -/** - * vb2_plane_cookie() - Return allocator specific cookie for the given plane - * @vb: vb2_buffer to which the plane in question belongs to - * @plane_no: plane number for which the cookie is to be returned - * - * This function returns an allocator specific cookie for a given plane if - * available, NULL otherwise. The allocator should provide some simple static - * inline function, which would convert this cookie to the allocator specific - * type that can be used directly by the driver to access the buffer. This can - * be for example physical address, pointer to scatter list or IOMMU mapping. - */ -void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) -{ - struct vb2_queue *q = vb->vb2_queue; - - if (plane_no > vb->num_planes) - return NULL; - - return call_memop(q, plane_no, cookie, vb->planes[plane_no].mem_priv); -} -EXPORT_SYMBOL_GPL(vb2_plane_cookie); - -/** - * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished - * @vb: vb2_buffer returned from the driver - * @state: either VB2_BUF_STATE_DONE if the operation finished successfully - * or VB2_BUF_STATE_ERROR if the operation finished with an error - * - * This function should be called by the driver after a hardware operation on - * a buffer is finished and the buffer may be returned to userspace. The driver - * cannot use this buffer anymore until it is queued back to it by videobuf - * by the means of buf_queue callback. Only buffers previously queued to the - * driver by buf_queue can be passed to this function. - */ -void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) -{ - struct vb2_queue *q = vb->vb2_queue; - unsigned long flags; - - if (vb->state != VB2_BUF_STATE_ACTIVE) - return; - - if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR) - return; - - dprintk(4, "Done processing on buffer %d, state: %d\n", - vb->v4l2_buf.index, vb->state); - - /* Add the buffer to the done buffers list */ - spin_lock_irqsave(&q->done_lock, flags); - vb->state = state; - list_add_tail(&vb->done_entry, &q->done_list); - atomic_dec(&q->queued_count); - spin_unlock_irqrestore(&q->done_lock, flags); - - /* Inform any processes that may be waiting for buffers */ - wake_up(&q->done_wq); -} -EXPORT_SYMBOL_GPL(vb2_buffer_done); - -/** - * __fill_vb2_buffer() - fill a vb2_buffer with information provided in - * a v4l2_buffer by the userspace - */ -static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, - struct v4l2_plane *v4l2_planes) -{ - unsigned int plane; - int ret; - - if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { - /* - * Verify that the userspace gave us a valid array for - * plane information. - */ - ret = __verify_planes_array(vb, b); - if (ret) - return ret; - - /* Fill in driver-provided information for OUTPUT types */ - if (V4L2_TYPE_IS_OUTPUT(b->type)) { - /* - * Will have to go up to b->length when API starts - * accepting variable number of planes. - */ - for (plane = 0; plane < vb->num_planes; ++plane) { - v4l2_planes[plane].bytesused = - b->m.planes[plane].bytesused; - v4l2_planes[plane].data_offset = - b->m.planes[plane].data_offset; - } - } - - if (b->memory == V4L2_MEMORY_USERPTR) { - for (plane = 0; plane < vb->num_planes; ++plane) { - v4l2_planes[plane].m.userptr = - b->m.planes[plane].m.userptr; - v4l2_planes[plane].length = - b->m.planes[plane].length; - } - } - } else { - /* - * Single-planar buffers do not use planes array, - * so fill in relevant v4l2_buffer struct fields instead. - * In videobuf we use our internal V4l2_planes struct for - * single-planar buffers as well, for simplicity. - */ - if (V4L2_TYPE_IS_OUTPUT(b->type)) - v4l2_planes[0].bytesused = b->bytesused; - - if (b->memory == V4L2_MEMORY_USERPTR) { - v4l2_planes[0].m.userptr = b->m.userptr; - v4l2_planes[0].length = b->length; - } - } - - vb->v4l2_buf.field = b->field; - vb->v4l2_buf.timestamp = b->timestamp; - - return 0; -} - -/** - * __qbuf_userptr() - handle qbuf of a USERPTR buffer - */ -static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) -{ - struct v4l2_plane planes[VIDEO_MAX_PLANES]; - struct vb2_queue *q = vb->vb2_queue; - void *mem_priv; - unsigned int plane; - int ret; - int write = !V4L2_TYPE_IS_OUTPUT(q->type); - - /* Verify and copy relevant information provided by the userspace */ - ret = __fill_vb2_buffer(vb, b, planes); - if (ret) - return ret; - - for (plane = 0; plane < vb->num_planes; ++plane) { - /* Skip the plane if already verified */ - if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr - && vb->v4l2_planes[plane].length == planes[plane].length) - continue; - - dprintk(3, "qbuf: userspace address for plane %d changed, " - "reacquiring memory\n", plane); - - /* Release previously acquired memory if present */ - if (vb->planes[plane].mem_priv) - call_memop(q, plane, put_userptr, - vb->planes[plane].mem_priv); - - vb->planes[plane].mem_priv = NULL; - - /* Acquire each plane's memory */ - if (q->mem_ops->get_userptr) { - mem_priv = q->mem_ops->get_userptr(q->alloc_ctx[plane], - planes[plane].m.userptr, - planes[plane].length, - write); - if (IS_ERR(mem_priv)) { - dprintk(1, "qbuf: failed acquiring userspace " - "memory for plane %d\n", plane); - ret = PTR_ERR(mem_priv); - goto err; - } - vb->planes[plane].mem_priv = mem_priv; - } - } - - /* - * Call driver-specific initialization on the newly acquired buffer, - * if provided. - */ - ret = call_qop(q, buf_init, vb); - if (ret) { - dprintk(1, "qbuf: buffer initialization failed\n"); - goto err; - } - - /* - * Now that everything is in order, copy relevant information - * provided by userspace. - */ - for (plane = 0; plane < vb->num_planes; ++plane) - vb->v4l2_planes[plane] = planes[plane]; - - return 0; -err: - /* In case of errors, release planes that were already acquired */ - for (; plane > 0; --plane) { - call_memop(q, plane, put_userptr, - vb->planes[plane - 1].mem_priv); - vb->planes[plane - 1].mem_priv = NULL; - } - - return ret; -} - -/** - * __qbuf_mmap() - handle qbuf of an MMAP buffer - */ -static int __qbuf_mmap(struct vb2_buffer *vb, struct v4l2_buffer *b) -{ - return __fill_vb2_buffer(vb, b, vb->v4l2_planes); -} - -/** - * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing - */ -static void __enqueue_in_driver(struct vb2_buffer *vb) -{ - struct vb2_queue *q = vb->vb2_queue; - - vb->state = VB2_BUF_STATE_ACTIVE; - atomic_inc(&q->queued_count); - q->ops->buf_queue(vb); -} - -/** - * vb2_qbuf() - Queue a buffer from userspace - * @q: videobuf2 queue - * @b: buffer structure passed from userspace to vidioc_qbuf handler - * in driver - * - * Should be called from vidioc_qbuf ioctl handler of a driver. - * This function: - * 1) verifies the passed buffer, - * 2) calls buf_prepare callback in the driver (if provided), in which - * driver-specific buffer initialization can be performed, - * 3) if streaming is on, queues the buffer in driver by the means of buf_queue - * callback for processing. - * - * The return values from this function are intended to be directly returned - * from vidioc_qbuf handler in driver. - */ -int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) -{ - struct vb2_buffer *vb; - int ret = 0; - - if (q->fileio) { - dprintk(1, "qbuf: file io in progress\n"); - return -EBUSY; - } - - if (b->type != q->type) { - dprintk(1, "qbuf: invalid buffer type\n"); - return -EINVAL; - } - - if (b->index >= q->num_buffers) { - dprintk(1, "qbuf: buffer index out of range\n"); - return -EINVAL; - } - - vb = q->bufs[b->index]; - if (NULL == vb) { - /* Should never happen */ - dprintk(1, "qbuf: buffer is NULL\n"); - return -EINVAL; - } - - if (b->memory != q->memory) { - dprintk(1, "qbuf: invalid memory type\n"); - return -EINVAL; - } - - if (vb->state != VB2_BUF_STATE_DEQUEUED) { - dprintk(1, "qbuf: buffer already in use\n"); - return -EINVAL; - } - - if (q->memory == V4L2_MEMORY_MMAP) - ret = __qbuf_mmap(vb, b); - else if (q->memory == V4L2_MEMORY_USERPTR) - ret = __qbuf_userptr(vb, b); - else { - WARN(1, "Invalid queue type\n"); - return -EINVAL; - } - - if (ret) - return ret; - - ret = call_qop(q, buf_prepare, vb); - if (ret) { - dprintk(1, "qbuf: buffer preparation failed\n"); - return ret; - } - - /* - * Add to the queued buffers list, a buffer will stay on it until - * dequeued in dqbuf. - */ - list_add_tail(&vb->queued_entry, &q->queued_list); - vb->state = VB2_BUF_STATE_QUEUED; - - /* - * If already streaming, give the buffer to driver for processing. - * If not, the buffer will be given to driver on next streamon. - */ - if (q->streaming) - __enqueue_in_driver(vb); - - dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); - return 0; -} -EXPORT_SYMBOL_GPL(vb2_qbuf); - -/** - * __vb2_wait_for_done_vb() - wait for a buffer to become available - * for dequeuing - * - * Will sleep if required for nonblocking == false. - */ -static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) -{ - /* - * All operations on vb_done_list are performed under done_lock - * spinlock protection. However, buffers may be removed from - * it and returned to userspace only while holding both driver's - * lock and the done_lock spinlock. Thus we can be sure that as - * long as we hold the driver's lock, the list will remain not - * empty if list_empty() check succeeds. - */ - - for (;;) { - int ret; - - if (!q->streaming) { - dprintk(1, "Streaming off, will not wait for buffers\n"); - return -EINVAL; - } - - if (!list_empty(&q->done_list)) { - /* - * Found a buffer that we were waiting for. - */ - break; - } - - if (nonblocking) { - dprintk(1, "Nonblocking and no buffers to dequeue, " - "will not wait\n"); - return -EAGAIN; - } - - /* - * We are streaming and blocking, wait for another buffer to - * become ready or for streamoff. Driver's lock is released to - * allow streamoff or qbuf to be called while waiting. - */ - call_qop(q, wait_prepare, q); - - /* - * All locks have been released, it is safe to sleep now. - */ - dprintk(3, "Will sleep waiting for buffers\n"); - ret = wait_event_interruptible(q->done_wq, - !list_empty(&q->done_list) || !q->streaming); - - /* - * We need to reevaluate both conditions again after reacquiring - * the locks or return an error if one occurred. - */ - call_qop(q, wait_finish, q); - if (ret) - return ret; - } - return 0; -} - -/** - * __vb2_get_done_vb() - get a buffer ready for dequeuing - * - * Will sleep if required for nonblocking == false. - */ -static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, - int nonblocking) -{ - unsigned long flags; - int ret; - - /* - * Wait for at least one buffer to become available on the done_list. - */ - ret = __vb2_wait_for_done_vb(q, nonblocking); - if (ret) - return ret; - - /* - * Driver's lock has been held since we last verified that done_list - * is not empty, so no need for another list_empty(done_list) check. - */ - spin_lock_irqsave(&q->done_lock, flags); - *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); - list_del(&(*vb)->done_entry); - spin_unlock_irqrestore(&q->done_lock, flags); - - return 0; -} - -/** - * vb2_wait_for_all_buffers() - wait until all buffers are given back to vb2 - * @q: videobuf2 queue - * - * This function will wait until all buffers that have been given to the driver - * by buf_queue() are given back to vb2 with vb2_buffer_done(). It doesn't call - * wait_prepare, wait_finish pair. It is intended to be called with all locks - * taken, for example from stop_streaming() callback. - */ -int vb2_wait_for_all_buffers(struct vb2_queue *q) -{ - if (!q->streaming) { - dprintk(1, "Streaming off, will not wait for buffers\n"); - return -EINVAL; - } - - wait_event(q->done_wq, !atomic_read(&q->queued_count)); - return 0; -} -EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); - -/** - * vb2_dqbuf() - Dequeue a buffer to the userspace - * @q: videobuf2 queue - * @b: buffer structure passed from userspace to vidioc_dqbuf handler - * in driver - * @nonblocking: if true, this call will not sleep waiting for a buffer if no - * buffers ready for dequeuing are present. Normally the driver - * would be passing (file->f_flags & O_NONBLOCK) here - * - * Should be called from vidioc_dqbuf ioctl handler of a driver. - * This function: - * 1) verifies the passed buffer, - * 2) calls buf_finish callback in the driver (if provided), in which - * driver can perform any additional operations that may be required before - * returning the buffer to userspace, such as cache sync, - * 3) the buffer struct members are filled with relevant information for - * the userspace. - * - * The return values from this function are intended to be directly returned - * from vidioc_dqbuf handler in driver. - */ -int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) -{ - struct vb2_buffer *vb = NULL; - int ret; - - if (q->fileio) { - dprintk(1, "dqbuf: file io in progress\n"); - return -EBUSY; - } - - if (b->type != q->type) { - dprintk(1, "dqbuf: invalid buffer type\n"); - return -EINVAL; - } - - ret = __vb2_get_done_vb(q, &vb, nonblocking); - if (ret < 0) { - dprintk(1, "dqbuf: error getting next done buffer\n"); - return ret; - } - - ret = call_qop(q, buf_finish, vb); - if (ret) { - dprintk(1, "dqbuf: buffer finish failed\n"); - return ret; - } - - switch (vb->state) { - case VB2_BUF_STATE_DONE: - dprintk(3, "dqbuf: Returning done buffer\n"); - break; - case VB2_BUF_STATE_ERROR: - dprintk(3, "dqbuf: Returning done buffer with errors\n"); - break; - default: - dprintk(1, "dqbuf: Invalid buffer state\n"); - return -EINVAL; - } - - /* Fill buffer information for the userspace */ - __fill_v4l2_buffer(vb, b); - /* Remove from videobuf queue */ - list_del(&vb->queued_entry); - - dprintk(1, "dqbuf of buffer %d, with state %d\n", - vb->v4l2_buf.index, vb->state); - - vb->state = VB2_BUF_STATE_DEQUEUED; - return 0; -} -EXPORT_SYMBOL_GPL(vb2_dqbuf); - -/** - * vb2_streamon - start streaming - * @q: videobuf2 queue - * @type: type argument passed from userspace to vidioc_streamon handler - * - * Should be called from vidioc_streamon handler of a driver. - * This function: - * 1) verifies current state - * 2) starts streaming and passes any previously queued buffers to the driver - * - * The return values from this function are intended to be directly returned - * from vidioc_streamon handler in the driver. - */ -int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) -{ - struct vb2_buffer *vb; - int ret; - - if (q->fileio) { - dprintk(1, "streamon: file io in progress\n"); - return -EBUSY; - } - - if (type != q->type) { - dprintk(1, "streamon: invalid stream type\n"); - return -EINVAL; - } - - if (q->streaming) { - dprintk(1, "streamon: already streaming\n"); - return -EBUSY; - } - - /* - * Cannot start streaming on an OUTPUT device if no buffers have - * been queued yet. - */ - if (V4L2_TYPE_IS_OUTPUT(q->type)) { - if (list_empty(&q->queued_list)) { - dprintk(1, "streamon: no output buffers queued\n"); - return -EINVAL; - } - } - - /* - * Let driver notice that streaming state has been enabled. - */ - ret = call_qop(q, start_streaming, q); - if (ret) { - dprintk(1, "streamon: driver refused to start streaming\n"); - return ret; - } - - q->streaming = 1; - - /* - * If any buffers were queued before streamon, - * we can now pass them to driver for processing. - */ - list_for_each_entry(vb, &q->queued_list, queued_entry) - __enqueue_in_driver(vb); - - dprintk(3, "Streamon successful\n"); - return 0; -} -EXPORT_SYMBOL_GPL(vb2_streamon); - -/** - * __vb2_queue_cancel() - cancel and stop (pause) streaming - * - * Removes all queued buffers from driver's queue and all buffers queued by - * userspace from videobuf's queue. Returns to state after reqbufs. - */ -static void __vb2_queue_cancel(struct vb2_queue *q) -{ - unsigned int i; - - /* - * Tell driver to stop all transactions and release all queued - * buffers. - */ - if (q->streaming) - call_qop(q, stop_streaming, q); - q->streaming = 0; - - /* - * Remove all buffers from videobuf's list... - */ - INIT_LIST_HEAD(&q->queued_list); - /* - * ...and done list; userspace will not receive any buffers it - * has not already dequeued before initiating cancel. - */ - INIT_LIST_HEAD(&q->done_list); - wake_up_all(&q->done_wq); - - /* - * Reinitialize all buffers for next use. - */ - for (i = 0; i < q->num_buffers; ++i) - q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED; -} - -/** - * vb2_streamoff - stop streaming - * @q: videobuf2 queue - * @type: type argument passed from userspace to vidioc_streamoff handler - * - * Should be called from vidioc_streamoff handler of a driver. - * This function: - * 1) verifies current state, - * 2) stop streaming and dequeues any queued buffers, including those previously - * passed to the driver (after waiting for the driver to finish). - * - * This call can be used for pausing playback. - * The return values from this function are intended to be directly returned - * from vidioc_streamoff handler in the driver - */ -int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) -{ - if (q->fileio) { - dprintk(1, "streamoff: file io in progress\n"); - return -EBUSY; - } - - if (type != q->type) { - dprintk(1, "streamoff: invalid stream type\n"); - return -EINVAL; - } - - if (!q->streaming) { - dprintk(1, "streamoff: not streaming\n"); - return -EINVAL; - } - - /* - * Cancel will pause streaming and remove all buffers from the driver - * and videobuf, effectively returning control over them to userspace. - */ - __vb2_queue_cancel(q); - - dprintk(3, "Streamoff successful\n"); - return 0; -} -EXPORT_SYMBOL_GPL(vb2_streamoff); - -/** - * __find_plane_by_offset() - find plane associated with the given offset off - */ -static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, - unsigned int *_buffer, unsigned int *_plane) -{ - struct vb2_buffer *vb; - unsigned int buffer, plane; - - /* - * Go over all buffers and their planes, comparing the given offset - * with an offset assigned to each plane. If a match is found, - * return its buffer and plane numbers. - */ - for (buffer = 0; buffer < q->num_buffers; ++buffer) { - vb = q->bufs[buffer]; - - for (plane = 0; plane < vb->num_planes; ++plane) { - if (vb->v4l2_planes[plane].m.mem_offset == off) { - *_buffer = buffer; - *_plane = plane; - return 0; - } - } - } - - return -EINVAL; -} - -/** - * vb2_mmap() - map video buffers into application address space - * @q: videobuf2 queue - * @vma: vma passed to the mmap file operation handler in the driver - * - * Should be called from mmap file operation handler of a driver. - * This function maps one plane of one of the available video buffers to - * userspace. To map whole video memory allocated on reqbufs, this function - * has to be called once per each plane per each buffer previously allocated. - * - * When the userspace application calls mmap, it passes to it an offset returned - * to it earlier by the means of vidioc_querybuf handler. That offset acts as - * a "cookie", which is then used to identify the plane to be mapped. - * This function finds a plane with a matching offset and a mapping is performed - * by the means of a provided memory operation. - * - * The return values from this function are intended to be directly returned - * from the mmap handler in driver. - */ -int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) -{ - unsigned long off = vma->vm_pgoff << PAGE_SHIFT; - struct vb2_plane *vb_plane; - struct vb2_buffer *vb; - unsigned int buffer, plane; - int ret; - - if (q->memory != V4L2_MEMORY_MMAP) { - dprintk(1, "Queue is not currently set up for mmap\n"); - return -EINVAL; - } - - /* - * Check memory area access mode. - */ - if (!(vma->vm_flags & VM_SHARED)) { - dprintk(1, "Invalid vma flags, VM_SHARED needed\n"); - return -EINVAL; - } - if (V4L2_TYPE_IS_OUTPUT(q->type)) { - if (!(vma->vm_flags & VM_WRITE)) { - dprintk(1, "Invalid vma flags, VM_WRITE needed\n"); - return -EINVAL; - } - } else { - if (!(vma->vm_flags & VM_READ)) { - dprintk(1, "Invalid vma flags, VM_READ needed\n"); - return -EINVAL; - } - } - - /* - * Find the plane corresponding to the offset passed by userspace. - */ - ret = __find_plane_by_offset(q, off, &buffer, &plane); - if (ret) - return ret; - - vb = q->bufs[buffer]; - vb_plane = &vb->planes[plane]; - - ret = q->mem_ops->mmap(vb_plane->mem_priv, vma); - if (ret) - return ret; - - vb_plane->mapped = 1; - vb->num_planes_mapped++; - - dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane); - return 0; -} -EXPORT_SYMBOL_GPL(vb2_mmap); - -static int __vb2_init_fileio(struct vb2_queue *q, int read); -static int __vb2_cleanup_fileio(struct vb2_queue *q); - -/** - * vb2_poll() - implements poll userspace operation - * @q: videobuf2 queue - * @file: file argument passed to the poll file operation handler - * @wait: wait argument passed to the poll file operation handler - * - * This function implements poll file operation handler for a driver. - * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will - * be informed that the file descriptor of a video device is available for - * reading. - * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor - * will be reported as available for writing. - * - * The return values from this function are intended to be directly returned - * from poll handler in driver. - */ -unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) -{ - unsigned long flags; - unsigned int ret; - struct vb2_buffer *vb = NULL; - - /* - * Start file I/O emulator only if streaming API has not been used yet. - */ - if (q->num_buffers == 0 && q->fileio == NULL) { - if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ)) { - ret = __vb2_init_fileio(q, 1); - if (ret) - return POLLERR; - } - if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE)) { - ret = __vb2_init_fileio(q, 0); - if (ret) - return POLLERR; - /* - * Write to OUTPUT queue can be done immediately. - */ - return POLLOUT | POLLWRNORM; - } - } - - /* - * There is nothing to wait for if no buffers have already been queued. - */ - if (list_empty(&q->queued_list)) - return POLLERR; - - poll_wait(file, &q->done_wq, wait); - - /* - * Take first buffer available for dequeuing. - */ - spin_lock_irqsave(&q->done_lock, flags); - if (!list_empty(&q->done_list)) - vb = list_first_entry(&q->done_list, struct vb2_buffer, - done_entry); - spin_unlock_irqrestore(&q->done_lock, flags); - - if (vb && (vb->state == VB2_BUF_STATE_DONE - || vb->state == VB2_BUF_STATE_ERROR)) { - return (V4L2_TYPE_IS_OUTPUT(q->type)) ? POLLOUT | POLLWRNORM : - POLLIN | POLLRDNORM; - } - return 0; -} -EXPORT_SYMBOL_GPL(vb2_poll); - -/** - * vb2_queue_init() - initialize a videobuf2 queue - * @q: videobuf2 queue; this structure should be allocated in driver - * - * The vb2_queue structure should be allocated by the driver. The driver is - * responsible of clearing it's content and setting initial values for some - * required entries before calling this function. - * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer - * to the struct vb2_queue description in include/media/videobuf2-core.h - * for more information. - */ -int vb2_queue_init(struct vb2_queue *q) -{ - BUG_ON(!q); - BUG_ON(!q->ops); - BUG_ON(!q->mem_ops); - BUG_ON(!q->type); - BUG_ON(!q->io_modes); - - BUG_ON(!q->ops->queue_setup); - BUG_ON(!q->ops->buf_queue); - - INIT_LIST_HEAD(&q->queued_list); - INIT_LIST_HEAD(&q->done_list); - spin_lock_init(&q->done_lock); - init_waitqueue_head(&q->done_wq); - - if (q->buf_struct_size == 0) - q->buf_struct_size = sizeof(struct vb2_buffer); - - return 0; -} -EXPORT_SYMBOL_GPL(vb2_queue_init); - -/** - * vb2_queue_release() - stop streaming, release the queue and free memory - * @q: videobuf2 queue - * - * This function stops streaming and performs necessary clean ups, including - * freeing video buffer memory. The driver is responsible for freeing - * the vb2_queue structure itself. - */ -void vb2_queue_release(struct vb2_queue *q) -{ - __vb2_cleanup_fileio(q); - __vb2_queue_cancel(q); - __vb2_queue_free(q); -} -EXPORT_SYMBOL_GPL(vb2_queue_release); - -/** - * struct vb2_fileio_buf - buffer context used by file io emulator - * - * vb2 provides a compatibility layer and emulator of file io (read and - * write) calls on top of streaming API. This structure is used for - * tracking context related to the buffers. - */ -struct vb2_fileio_buf { - void *vaddr; - unsigned int size; - unsigned int pos; - unsigned int queued:1; -}; - -/** - * struct vb2_fileio_data - queue context used by file io emulator - * - * vb2 provides a compatibility layer and emulator of file io (read and - * write) calls on top of streaming API. For proper operation it required - * this structure to save the driver state between each call of the read - * or write function. - */ -struct vb2_fileio_data { - struct v4l2_requestbuffers req; - struct v4l2_buffer b; - struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME]; - unsigned int index; - unsigned int q_count; - unsigned int dq_count; - unsigned int flags; -}; - -/** - * __vb2_init_fileio() - initialize file io emulator - * @q: videobuf2 queue - * @read: mode selector (1 means read, 0 means write) - */ -static int __vb2_init_fileio(struct vb2_queue *q, int read) -{ - struct vb2_fileio_data *fileio; - int i, ret; - unsigned int count = 0; - - /* - * Sanity check - */ - if ((read && !(q->io_modes & VB2_READ)) || - (!read && !(q->io_modes & VB2_WRITE))) - BUG(); - - /* - * Check if device supports mapping buffers to kernel virtual space. - */ - if (!q->mem_ops->vaddr) - return -EBUSY; - - /* - * Check if streaming api has not been already activated. - */ - if (q->streaming || q->num_buffers > 0) - return -EBUSY; - - /* - * Start with count 1, driver can increase it in queue_setup() - */ - count = 1; - - dprintk(3, "setting up file io: mode %s, count %d, flags %08x\n", - (read) ? "read" : "write", count, q->io_flags); - - fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL); - if (fileio == NULL) - return -ENOMEM; - - fileio->flags = q->io_flags; - - /* - * Request buffers and use MMAP type to force driver - * to allocate buffers by itself. - */ - fileio->req.count = count; - fileio->req.memory = V4L2_MEMORY_MMAP; - fileio->req.type = q->type; - ret = vb2_reqbufs(q, &fileio->req); - if (ret) - goto err_kfree; - - /* - * Check if plane_count is correct - * (multiplane buffers are not supported). - */ - if (q->bufs[0]->num_planes != 1) { - fileio->req.count = 0; - ret = -EBUSY; - goto err_reqbufs; - } - - /* - * Get kernel address of each buffer. - */ - for (i = 0; i < q->num_buffers; i++) { - fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0); - if (fileio->bufs[i].vaddr == NULL) - goto err_reqbufs; - fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0); - } - - /* - * Read mode requires pre queuing of all buffers. - */ - if (read) { - /* - * Queue all buffers. - */ - for (i = 0; i < q->num_buffers; i++) { - struct v4l2_buffer *b = &fileio->b; - memset(b, 0, sizeof(*b)); - b->type = q->type; - b->memory = q->memory; - b->index = i; - ret = vb2_qbuf(q, b); - if (ret) - goto err_reqbufs; - fileio->bufs[i].queued = 1; - } - - /* - * Start streaming. - */ - ret = vb2_streamon(q, q->type); - if (ret) - goto err_reqbufs; - } - - q->fileio = fileio; - - return ret; - -err_reqbufs: - vb2_reqbufs(q, &fileio->req); - -err_kfree: - kfree(fileio); - return ret; -} - -/** - * __vb2_cleanup_fileio() - free resourced used by file io emulator - * @q: videobuf2 queue - */ -static int __vb2_cleanup_fileio(struct vb2_queue *q) -{ - struct vb2_fileio_data *fileio = q->fileio; - - if (fileio) { - /* - * Hack fileio context to enable direct calls to vb2 ioctl - * interface. - */ - q->fileio = NULL; - - vb2_streamoff(q, q->type); - fileio->req.count = 0; - vb2_reqbufs(q, &fileio->req); - kfree(fileio); - dprintk(3, "file io emulator closed\n"); - } - return 0; -} - -/** - * __vb2_perform_fileio() - perform a single file io (read or write) operation - * @q: videobuf2 queue - * @data: pointed to target userspace buffer - * @count: number of bytes to read or write - * @ppos: file handle position tracking pointer - * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) - * @read: access mode selector (1 means read, 0 means write) - */ -static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, - loff_t *ppos, int nonblock, int read) -{ - struct vb2_fileio_data *fileio; - struct vb2_fileio_buf *buf; - int ret, index; - - dprintk(3, "file io: mode %s, offset %ld, count %zd, %sblocking\n", - read ? "read" : "write", (long)*ppos, count, - nonblock ? "non" : ""); - - if (!data) - return -EINVAL; - - /* - * Initialize emulator on first call. - */ - if (!q->fileio) { - ret = __vb2_init_fileio(q, read); - dprintk(3, "file io: vb2_init_fileio result: %d\n", ret); - if (ret) - return ret; - } - fileio = q->fileio; - - /* - * Hack fileio context to enable direct calls to vb2 ioctl interface. - * The pointer will be restored before returning from this function. - */ - q->fileio = NULL; - - index = fileio->index; - buf = &fileio->bufs[index]; - - /* - * Check if we need to dequeue the buffer. - */ - if (buf->queued) { - struct vb2_buffer *vb; - - /* - * Call vb2_dqbuf to get buffer back. - */ - memset(&fileio->b, 0, sizeof(fileio->b)); - fileio->b.type = q->type; - fileio->b.memory = q->memory; - fileio->b.index = index; - ret = vb2_dqbuf(q, &fileio->b, nonblock); - dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); - if (ret) - goto end; - fileio->dq_count += 1; - - /* - * Get number of bytes filled by the driver - */ - vb = q->bufs[index]; - buf->size = vb2_get_plane_payload(vb, 0); - buf->queued = 0; - } - - /* - * Limit count on last few bytes of the buffer. - */ - if (buf->pos + count > buf->size) { - count = buf->size - buf->pos; - dprintk(5, "reducing read count: %zd\n", count); - } - - /* - * Transfer data to userspace. - */ - dprintk(3, "file io: copying %zd bytes - buffer %d, offset %u\n", - count, index, buf->pos); - if (read) - ret = copy_to_user(data, buf->vaddr + buf->pos, count); - else - ret = copy_from_user(buf->vaddr + buf->pos, data, count); - if (ret) { - dprintk(3, "file io: error copying data\n"); - ret = -EFAULT; - goto end; - } - - /* - * Update counters. - */ - buf->pos += count; - *ppos += count; - - /* - * Queue next buffer if required. - */ - if (buf->pos == buf->size || - (!read && (fileio->flags & VB2_FILEIO_WRITE_IMMEDIATELY))) { - /* - * Check if this is the last buffer to read. - */ - if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) && - fileio->dq_count == 1) { - dprintk(3, "file io: read limit reached\n"); - /* - * Restore fileio pointer and release the context. - */ - q->fileio = fileio; - return __vb2_cleanup_fileio(q); - } - - /* - * Call vb2_qbuf and give buffer to the driver. - */ - memset(&fileio->b, 0, sizeof(fileio->b)); - fileio->b.type = q->type; - fileio->b.memory = q->memory; - fileio->b.index = index; - fileio->b.bytesused = buf->pos; - ret = vb2_qbuf(q, &fileio->b); - dprintk(5, "file io: vb2_dbuf result: %d\n", ret); - if (ret) - goto end; - - /* - * Buffer has been queued, update the status - */ - buf->pos = 0; - buf->queued = 1; - buf->size = q->bufs[0]->v4l2_planes[0].length; - fileio->q_count += 1; - - /* - * Switch to the next buffer - */ - fileio->index = (index + 1) % q->num_buffers; - - /* - * Start streaming if required. - */ - if (!read && !q->streaming) { - ret = vb2_streamon(q, q->type); - if (ret) - goto end; - } - } - - /* - * Return proper number of bytes processed. - */ - if (ret == 0) - ret = count; -end: - /* - * Restore the fileio context and block vb2 ioctl interface. - */ - q->fileio = fileio; - return ret; -} - -size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, - loff_t *ppos, int nonblocking) -{ - return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1); -} -EXPORT_SYMBOL_GPL(vb2_read); - -size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count, - loff_t *ppos, int nonblocking) -{ - return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 0); -} -EXPORT_SYMBOL_GPL(vb2_write); - -MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2"); -MODULE_AUTHOR("Pawel Osciak , Marek Szyprowski"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-dma-contig.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-dma-contig.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-dma-contig.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-dma-contig.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,185 +0,0 @@ -/* - * videobuf2-dma-contig.c - DMA contig memory allocator for videobuf2 - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Pawel Osciak - * - * 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. - */ - -#include -#include -#include - -#include -#include - -struct vb2_dc_conf { - struct device *dev; -}; - -struct vb2_dc_buf { - struct vb2_dc_conf *conf; - void *vaddr; - dma_addr_t paddr; - unsigned long size; - struct vm_area_struct *vma; - atomic_t refcount; - struct vb2_vmarea_handler handler; -}; - -static void vb2_dma_contig_put(void *buf_priv); - -static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) -{ - struct vb2_dc_conf *conf = alloc_ctx; - struct vb2_dc_buf *buf; - - buf = kzalloc(sizeof *buf, GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->paddr, - GFP_KERNEL); - if (!buf->vaddr) { - dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n", - buf->size); - kfree(buf); - return ERR_PTR(-ENOMEM); - } - - buf->conf = conf; - buf->size = size; - - buf->handler.refcount = &buf->refcount; - buf->handler.put = vb2_dma_contig_put; - buf->handler.arg = buf; - - atomic_inc(&buf->refcount); - - return buf; -} - -static void vb2_dma_contig_put(void *buf_priv) -{ - struct vb2_dc_buf *buf = buf_priv; - - if (atomic_dec_and_test(&buf->refcount)) { - dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr, - buf->paddr); - kfree(buf); - } -} - -static void *vb2_dma_contig_cookie(void *buf_priv) -{ - struct vb2_dc_buf *buf = buf_priv; - - return &buf->paddr; -} - -static void *vb2_dma_contig_vaddr(void *buf_priv) -{ - struct vb2_dc_buf *buf = buf_priv; - if (!buf) - return 0; - - return buf->vaddr; -} - -static unsigned int vb2_dma_contig_num_users(void *buf_priv) -{ - struct vb2_dc_buf *buf = buf_priv; - - return atomic_read(&buf->refcount); -} - -static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma) -{ - struct vb2_dc_buf *buf = buf_priv; - - if (!buf) { - printk(KERN_ERR "No buffer to map\n"); - return -EINVAL; - } - - return vb2_mmap_pfn_range(vma, buf->paddr, buf->size, - &vb2_common_vm_ops, &buf->handler); -} - -static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr, - unsigned long size, int write) -{ - struct vb2_dc_buf *buf; - struct vm_area_struct *vma; - dma_addr_t paddr = 0; - int ret; - - buf = kzalloc(sizeof *buf, GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr); - if (ret) { - printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n", - vaddr); - kfree(buf); - return ERR_PTR(ret); - } - - buf->size = size; - buf->paddr = paddr; - buf->vma = vma; - - return buf; -} - -static void vb2_dma_contig_put_userptr(void *mem_priv) -{ - struct vb2_dc_buf *buf = mem_priv; - - if (!buf) - return; - - vb2_put_vma(buf->vma); - kfree(buf); -} - -const struct vb2_mem_ops vb2_dma_contig_memops = { - .alloc = vb2_dma_contig_alloc, - .put = vb2_dma_contig_put, - .cookie = vb2_dma_contig_cookie, - .vaddr = vb2_dma_contig_vaddr, - .mmap = vb2_dma_contig_mmap, - .get_userptr = vb2_dma_contig_get_userptr, - .put_userptr = vb2_dma_contig_put_userptr, - .num_users = vb2_dma_contig_num_users, -}; -EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); - -void *vb2_dma_contig_init_ctx(struct device *dev) -{ - struct vb2_dc_conf *conf; - - conf = kzalloc(sizeof *conf, GFP_KERNEL); - if (!conf) - return ERR_PTR(-ENOMEM); - - conf->dev = dev; - - return conf; -} -EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx); - -void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) -{ - kfree(alloc_ctx); -} -EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); - -MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); -MODULE_AUTHOR("Pawel Osciak "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-dma-sg.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-dma-sg.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-dma-sg.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-dma-sg.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,294 +0,0 @@ -/* - * videobuf2-dma-sg.c - dma scatter/gather memory allocator for videobuf2 - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Andrzej Pietrasiewicz - * - * 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. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -struct vb2_dma_sg_buf { - void *vaddr; - struct page **pages; - int write; - int offset; - struct vb2_dma_sg_desc sg_desc; - atomic_t refcount; - struct vb2_vmarea_handler handler; -}; - -static void vb2_dma_sg_put(void *buf_priv); - -static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) -{ - struct vb2_dma_sg_buf *buf; - int i; - - buf = kzalloc(sizeof *buf, GFP_KERNEL); - if (!buf) - return NULL; - - buf->vaddr = NULL; - buf->write = 0; - buf->offset = 0; - buf->sg_desc.size = size; - buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - - buf->sg_desc.sglist = vmalloc(buf->sg_desc.num_pages * - sizeof(*buf->sg_desc.sglist)); - if (!buf->sg_desc.sglist) - goto fail_sglist_alloc; - memset(buf->sg_desc.sglist, 0, buf->sg_desc.num_pages * - sizeof(*buf->sg_desc.sglist)); - sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages); - - buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *), - GFP_KERNEL); - if (!buf->pages) - goto fail_pages_array_alloc; - - for (i = 0; i < buf->sg_desc.num_pages; ++i) { - buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (NULL == buf->pages[i]) - goto fail_pages_alloc; - sg_set_page(&buf->sg_desc.sglist[i], - buf->pages[i], PAGE_SIZE, 0); - } - - buf->handler.refcount = &buf->refcount; - buf->handler.put = vb2_dma_sg_put; - buf->handler.arg = buf; - - atomic_inc(&buf->refcount); - - printk(KERN_DEBUG "%s: Allocated buffer of %d pages\n", - __func__, buf->sg_desc.num_pages); - - if (!buf->vaddr) - buf->vaddr = vm_map_ram(buf->pages, - buf->sg_desc.num_pages, - -1, - PAGE_KERNEL); - return buf; - -fail_pages_alloc: - while (--i >= 0) - __free_page(buf->pages[i]); - kfree(buf->pages); - -fail_pages_array_alloc: - vfree(buf->sg_desc.sglist); - -fail_sglist_alloc: - kfree(buf); - return NULL; -} - -static void vb2_dma_sg_put(void *buf_priv) -{ - struct vb2_dma_sg_buf *buf = buf_priv; - int i = buf->sg_desc.num_pages; - - if (atomic_dec_and_test(&buf->refcount)) { - printk(KERN_DEBUG "%s: Freeing buffer of %d pages\n", __func__, - buf->sg_desc.num_pages); - if (buf->vaddr) - vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages); - vfree(buf->sg_desc.sglist); - while (--i >= 0) - __free_page(buf->pages[i]); - kfree(buf->pages); - kfree(buf); - } -} - -static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, - unsigned long size, int write) -{ - struct vb2_dma_sg_buf *buf; - unsigned long first, last; - int num_pages_from_user, i; - - buf = kzalloc(sizeof *buf, GFP_KERNEL); - if (!buf) - return NULL; - - buf->vaddr = NULL; - buf->write = write; - buf->offset = vaddr & ~PAGE_MASK; - buf->sg_desc.size = size; - - first = (vaddr & PAGE_MASK) >> PAGE_SHIFT; - last = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT; - buf->sg_desc.num_pages = last - first + 1; - - buf->sg_desc.sglist = vmalloc( - buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist)); - if (!buf->sg_desc.sglist) - goto userptr_fail_sglist_alloc; - - memset(buf->sg_desc.sglist, 0, - buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist)); - sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages); - - buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *), - GFP_KERNEL); - if (!buf->pages) - goto userptr_fail_pages_array_alloc; - - down_read(¤t->mm->mmap_sem); - num_pages_from_user = get_user_pages(current, current->mm, - vaddr & PAGE_MASK, - buf->sg_desc.num_pages, - write, - 1, /* force */ - buf->pages, - NULL); - up_read(¤t->mm->mmap_sem); - if (num_pages_from_user != buf->sg_desc.num_pages) - goto userptr_fail_get_user_pages; - - sg_set_page(&buf->sg_desc.sglist[0], buf->pages[0], - PAGE_SIZE - buf->offset, buf->offset); - size -= PAGE_SIZE - buf->offset; - for (i = 1; i < buf->sg_desc.num_pages; ++i) { - sg_set_page(&buf->sg_desc.sglist[i], buf->pages[i], - min_t(size_t, PAGE_SIZE, size), 0); - size -= min_t(size_t, PAGE_SIZE, size); - } - return buf; - -userptr_fail_get_user_pages: - printk(KERN_DEBUG "get_user_pages requested/got: %d/%d]\n", - num_pages_from_user, buf->sg_desc.num_pages); - while (--num_pages_from_user >= 0) - put_page(buf->pages[num_pages_from_user]); - kfree(buf->pages); - -userptr_fail_pages_array_alloc: - vfree(buf->sg_desc.sglist); - -userptr_fail_sglist_alloc: - kfree(buf); - return NULL; -} - -/* - * @put_userptr: inform the allocator that a USERPTR buffer will no longer - * be used - */ -static void vb2_dma_sg_put_userptr(void *buf_priv) -{ - struct vb2_dma_sg_buf *buf = buf_priv; - int i = buf->sg_desc.num_pages; - - printk(KERN_DEBUG "%s: Releasing userspace buffer of %d pages\n", - __func__, buf->sg_desc.num_pages); - if (buf->vaddr) - vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages); - while (--i >= 0) { - if (buf->write) - set_page_dirty_lock(buf->pages[i]); - put_page(buf->pages[i]); - } - vfree(buf->sg_desc.sglist); - kfree(buf->pages); - kfree(buf); -} - -static void *vb2_dma_sg_vaddr(void *buf_priv) -{ - struct vb2_dma_sg_buf *buf = buf_priv; - - BUG_ON(!buf); - - if (!buf->vaddr) - buf->vaddr = vm_map_ram(buf->pages, - buf->sg_desc.num_pages, - -1, - PAGE_KERNEL); - - /* add offset in case userptr is not page-aligned */ - return buf->vaddr + buf->offset; -} - -static unsigned int vb2_dma_sg_num_users(void *buf_priv) -{ - struct vb2_dma_sg_buf *buf = buf_priv; - - return atomic_read(&buf->refcount); -} - -static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma) -{ - struct vb2_dma_sg_buf *buf = buf_priv; - unsigned long uaddr = vma->vm_start; - unsigned long usize = vma->vm_end - vma->vm_start; - int i = 0; - - if (!buf) { - printk(KERN_ERR "No memory to map\n"); - return -EINVAL; - } - - do { - int ret; - - ret = vm_insert_page(vma, uaddr, buf->pages[i++]); - if (ret) { - printk(KERN_ERR "Remapping memory, error: %d\n", ret); - return ret; - } - - uaddr += PAGE_SIZE; - usize -= PAGE_SIZE; - } while (usize > 0); - - - /* - * Use common vm_area operations to track buffer refcount. - */ - vma->vm_private_data = &buf->handler; - vma->vm_ops = &vb2_common_vm_ops; - - vma->vm_ops->open(vma); - - return 0; -} - -static void *vb2_dma_sg_cookie(void *buf_priv) -{ - struct vb2_dma_sg_buf *buf = buf_priv; - - return &buf->sg_desc; -} - -const struct vb2_mem_ops vb2_dma_sg_memops = { - .alloc = vb2_dma_sg_alloc, - .put = vb2_dma_sg_put, - .get_userptr = vb2_dma_sg_get_userptr, - .put_userptr = vb2_dma_sg_put_userptr, - .vaddr = vb2_dma_sg_vaddr, - .mmap = vb2_dma_sg_mmap, - .num_users = vb2_dma_sg_num_users, - .cookie = vb2_dma_sg_cookie, -}; -EXPORT_SYMBOL_GPL(vb2_dma_sg_memops); - -MODULE_DESCRIPTION("dma scatter/gather memory handling routines for videobuf2"); -MODULE_AUTHOR("Andrzej Pietrasiewicz"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-memops.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-memops.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-memops.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-memops.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,235 +0,0 @@ -/* - * videobuf2-memops.c - generic memory handling routines for videobuf2 - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Pawel Osciak - * Marek Szyprowski - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/** - * vb2_get_vma() - acquire and lock the virtual memory area - * @vma: given virtual memory area - * - * This function attempts to acquire an area mapped in the userspace for - * the duration of a hardware operation. The area is "locked" by performing - * the same set of operation that are done when process calls fork() and - * memory areas are duplicated. - * - * Returns a copy of a virtual memory region on success or NULL. - */ -struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma) -{ - struct vm_area_struct *vma_copy; - - vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL); - if (vma_copy == NULL) - return NULL; - - if (vma->vm_ops && vma->vm_ops->open) - vma->vm_ops->open(vma); - - if (vma->vm_file) - get_file(vma->vm_file); - - memcpy(vma_copy, vma, sizeof(*vma)); - - vma_copy->vm_mm = NULL; - vma_copy->vm_next = NULL; - vma_copy->vm_prev = NULL; - - return vma_copy; -} - -/** - * vb2_put_userptr() - release a userspace virtual memory area - * @vma: virtual memory region associated with the area to be released - * - * This function releases the previously acquired memory area after a hardware - * operation. - */ -void vb2_put_vma(struct vm_area_struct *vma) -{ - if (!vma) - return; - - if (vma->vm_file) - fput(vma->vm_file); - - if (vma->vm_ops && vma->vm_ops->close) - vma->vm_ops->close(vma); - - kfree(vma); -} -EXPORT_SYMBOL_GPL(vb2_put_vma); - -/** - * vb2_get_contig_userptr() - lock physically contiguous userspace mapped memory - * @vaddr: starting virtual address of the area to be verified - * @size: size of the area - * @res_paddr: will return physical address for the given vaddr - * @res_vma: will return locked copy of struct vm_area for the given area - * - * This function will go through memory area of size @size mapped at @vaddr and - * verify that the underlying physical pages are contiguous. If they are - * contiguous the virtual memory area is locked and a @res_vma is filled with - * the copy and @res_pa set to the physical address of the buffer. - * - * Returns 0 on success. - */ -int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, - struct vm_area_struct **res_vma, dma_addr_t *res_pa) -{ - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long offset, start, end; - unsigned long this_pfn, prev_pfn; - dma_addr_t pa = 0; - int ret = -EFAULT; - - start = vaddr; - offset = start & ~PAGE_MASK; - end = start + size; - - down_read(&mm->mmap_sem); - vma = find_vma(mm, start); - - if (vma == NULL || vma->vm_end < end) - goto done; - - for (prev_pfn = 0; start < end; start += PAGE_SIZE) { - ret = follow_pfn(vma, start, &this_pfn); - if (ret) - goto done; - - if (prev_pfn == 0) - pa = this_pfn << PAGE_SHIFT; - else if (this_pfn != prev_pfn + 1) { - ret = -EFAULT; - goto done; - } - prev_pfn = this_pfn; - } - - /* - * Memory is contigous, lock vma and return to the caller - */ - *res_vma = vb2_get_vma(vma); - if (*res_vma == NULL) { - ret = -ENOMEM; - goto done; - } - *res_pa = pa + offset; - ret = 0; - -done: - up_read(&mm->mmap_sem); - return ret; -} -EXPORT_SYMBOL_GPL(vb2_get_contig_userptr); - -/** - * vb2_mmap_pfn_range() - map physical pages to userspace - * @vma: virtual memory region for the mapping - * @paddr: starting physical address of the memory to be mapped - * @size: size of the memory to be mapped - * @vm_ops: vm operations to be assigned to the created area - * @priv: private data to be associated with the area - * - * Returns 0 on success. - */ -int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, - unsigned long size, - const struct vm_operations_struct *vm_ops, - void *priv) -{ - int ret; - - size = min_t(unsigned long, vma->vm_end - vma->vm_start, size); - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - ret = remap_pfn_range(vma, vma->vm_start, paddr >> PAGE_SHIFT, - size, vma->vm_page_prot); - if (ret) { - printk(KERN_ERR "Remapping memory failed, error: %d\n", ret); - return ret; - } - - vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; - vma->vm_private_data = priv; - vma->vm_ops = vm_ops; - - vma->vm_ops->open(vma); - - printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n", - __func__, paddr, vma->vm_start, size); - - return 0; -} -EXPORT_SYMBOL_GPL(vb2_mmap_pfn_range); - -/** - * vb2_common_vm_open() - increase refcount of the vma - * @vma: virtual memory region for the mapping - * - * This function adds another user to the provided vma. It expects - * struct vb2_vmarea_handler pointer in vma->vm_private_data. - */ -static void vb2_common_vm_open(struct vm_area_struct *vma) -{ - struct vb2_vmarea_handler *h = vma->vm_private_data; - - printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n", - __func__, h, atomic_read(h->refcount), vma->vm_start, - vma->vm_end); - - atomic_inc(h->refcount); -} - -/** - * vb2_common_vm_close() - decrease refcount of the vma - * @vma: virtual memory region for the mapping - * - * This function releases the user from the provided vma. It expects - * struct vb2_vmarea_handler pointer in vma->vm_private_data. - */ -static void vb2_common_vm_close(struct vm_area_struct *vma) -{ - struct vb2_vmarea_handler *h = vma->vm_private_data; - - printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n", - __func__, h, atomic_read(h->refcount), vma->vm_start, - vma->vm_end); - - h->put(h->arg); -} - -/** - * vb2_common_vm_ops - common vm_ops used for tracking refcount of mmaped - * video buffers - */ -const struct vm_operations_struct vb2_common_vm_ops = { - .open = vb2_common_vm_open, - .close = vb2_common_vm_close, -}; -EXPORT_SYMBOL_GPL(vb2_common_vm_ops); - -MODULE_DESCRIPTION("common memory handling routines for videobuf2"); -MODULE_AUTHOR("Pawel Osciak "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-vmalloc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-vmalloc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-vmalloc.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf2-vmalloc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,132 +0,0 @@ -/* - * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2 - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Pawel Osciak - * - * 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. - */ - -#include -#include -#include -#include - -#include -#include - -struct vb2_vmalloc_buf { - void *vaddr; - unsigned long size; - atomic_t refcount; - struct vb2_vmarea_handler handler; -}; - -static void vb2_vmalloc_put(void *buf_priv); - -static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size) -{ - struct vb2_vmalloc_buf *buf; - - buf = kzalloc(sizeof *buf, GFP_KERNEL); - if (!buf) - return NULL; - - buf->size = size; - buf->vaddr = vmalloc_user(buf->size); - buf->handler.refcount = &buf->refcount; - buf->handler.put = vb2_vmalloc_put; - buf->handler.arg = buf; - - if (!buf->vaddr) { - printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size); - kfree(buf); - return NULL; - } - - atomic_inc(&buf->refcount); - printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n", - buf->size, buf->vaddr); - - return buf; -} - -static void vb2_vmalloc_put(void *buf_priv) -{ - struct vb2_vmalloc_buf *buf = buf_priv; - - if (atomic_dec_and_test(&buf->refcount)) { - printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n", - __func__, buf->vaddr); - vfree(buf->vaddr); - kfree(buf); - } -} - -static void *vb2_vmalloc_vaddr(void *buf_priv) -{ - struct vb2_vmalloc_buf *buf = buf_priv; - - BUG_ON(!buf); - - if (!buf->vaddr) { - printk(KERN_ERR "Address of an unallocated plane requested\n"); - return NULL; - } - - return buf->vaddr; -} - -static unsigned int vb2_vmalloc_num_users(void *buf_priv) -{ - struct vb2_vmalloc_buf *buf = buf_priv; - return atomic_read(&buf->refcount); -} - -static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) -{ - struct vb2_vmalloc_buf *buf = buf_priv; - int ret; - - if (!buf) { - printk(KERN_ERR "No memory to map\n"); - return -EINVAL; - } - - ret = remap_vmalloc_range(vma, buf->vaddr, 0); - if (ret) { - printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret); - return ret; - } - - /* - * Make sure that vm_areas for 2 buffers won't be merged together - */ - vma->vm_flags |= VM_DONTEXPAND; - - /* - * Use common vm_area operations to track buffer refcount. - */ - vma->vm_private_data = &buf->handler; - vma->vm_ops = &vb2_common_vm_ops; - - vma->vm_ops->open(vma); - - return 0; -} - -const struct vb2_mem_ops vb2_vmalloc_memops = { - .alloc = vb2_vmalloc_alloc, - .put = vb2_vmalloc_put, - .vaddr = vb2_vmalloc_vaddr, - .mmap = vb2_vmalloc_mmap, - .num_users = vb2_vmalloc_num_users, -}; -EXPORT_SYMBOL_GPL(vb2_vmalloc_memops); - -MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2"); -MODULE_AUTHOR("Pawel Osciak "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-core.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1204 +0,0 @@ -/* - * generic helper functions for handling video4linux capture buffers - * - * (c) 2007 Mauro Carvalho Chehab, - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - * - * 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 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MAGIC_BUFFER 0x20070728 -#define MAGIC_CHECK(is, should) \ - do { \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR \ - "magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } \ - } while (0) - -static int debug; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux buffers"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) \ - do { \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt, ## arg); \ - } while (0) - -/* --------------------------------------------------------------------- */ - -#define CALL(q, f, arg...) \ - ((q->int_ops->f) ? q->int_ops->f(arg) : 0) - -struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q) -{ - struct videobuf_buffer *vb; - - BUG_ON(q->msize < sizeof(*vb)); - - if (!q->int_ops || !q->int_ops->alloc_vb) { - printk(KERN_ERR "No specific ops defined!\n"); - BUG(); - } - - vb = q->int_ops->alloc_vb(q->msize); - if (NULL != vb) { - init_waitqueue_head(&vb->done); - vb->magic = MAGIC_BUFFER; - } - - return vb; -} -EXPORT_SYMBOL_GPL(videobuf_alloc_vb); - -static int is_state_active_or_queued(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - unsigned long flags; - bool rc; - - spin_lock_irqsave(q->irqlock, flags); - rc = vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED; - spin_unlock_irqrestore(q->irqlock, flags); - return rc; -}; - -int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb, - int non_blocking, int intr) -{ - bool is_ext_locked; - int ret = 0; - - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - - if (non_blocking) { - if (is_state_active_or_queued(q, vb)) - return 0; - return -EAGAIN; - } - - is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock); - - /* Release vdev lock to prevent this wait from blocking outside access to - the device. */ - if (is_ext_locked) - mutex_unlock(q->ext_lock); - if (intr) - ret = wait_event_interruptible(vb->done, is_state_active_or_queued(q, vb)); - else - wait_event(vb->done, is_state_active_or_queued(q, vb)); - /* Relock */ - if (is_ext_locked) - mutex_lock(q->ext_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_waiton); - -int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - return CALL(q, iolock, q, vb, fbuf); -} -EXPORT_SYMBOL_GPL(videobuf_iolock); - -void *videobuf_queue_to_vaddr(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - if (q->int_ops->vaddr) - return q->int_ops->vaddr(buf); - return NULL; -} -EXPORT_SYMBOL_GPL(videobuf_queue_to_vaddr); - -/* --------------------------------------------------------------------- */ - - -void videobuf_queue_core_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct videobuf_qtype_ops *int_ops, - struct mutex *ext_lock) -{ - BUG_ON(!q); - memset(q, 0, sizeof(*q)); - q->irqlock = irqlock; - q->ext_lock = ext_lock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; - q->priv_data = priv; - q->int_ops = int_ops; - - /* All buffer operations are mandatory */ - BUG_ON(!q->ops->buf_setup); - BUG_ON(!q->ops->buf_prepare); - BUG_ON(!q->ops->buf_queue); - BUG_ON(!q->ops->buf_release); - - /* Lock is mandatory for queue_cancel to work */ - BUG_ON(!irqlock); - - /* Having implementations for abstract methods are mandatory */ - BUG_ON(!q->int_ops); - - mutex_init(&q->vb_lock); - init_waitqueue_head(&q->wait); - INIT_LIST_HEAD(&q->stream); -} -EXPORT_SYMBOL_GPL(videobuf_queue_core_init); - -/* Locking: Only usage in bttv unsafe find way to remove */ -int videobuf_queue_is_busy(struct videobuf_queue *q) -{ - int i; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - if (q->streaming) { - dprintk(1, "busy: streaming active\n"); - return 1; - } - if (q->reading) { - dprintk(1, "busy: pending read #1\n"); - return 1; - } - if (q->read_buf) { - dprintk(1, "busy: pending read #2\n"); - return 1; - } - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->map) { - dprintk(1, "busy: buffer #%d mapped\n", i); - return 1; - } - if (q->bufs[i]->state == VIDEOBUF_QUEUED) { - dprintk(1, "busy: buffer #%d queued\n", i); - return 1; - } - if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { - dprintk(1, "busy: buffer #%d avtive\n", i); - return 1; - } - } - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); - -/** - * __videobuf_free() - free all the buffers and their control structures - * - * This function can only be called if streaming/reading is off, i.e. no buffers - * are under control of the driver. - */ -/* Locking: Caller holds q->vb_lock */ -static int __videobuf_free(struct videobuf_queue *q) -{ - int i; - - dprintk(1, "%s\n", __func__); - if (!q) - return 0; - - if (q->streaming || q->reading) { - dprintk(1, "Cannot free buffers when streaming or reading\n"); - return -EBUSY; - } - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) - if (q->bufs[i] && q->bufs[i]->map) { - dprintk(1, "Cannot free mmapped buffers\n"); - return -EBUSY; - } - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q, q->bufs[i]); - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - - return 0; -} - -/* Locking: Caller holds q->vb_lock */ -void videobuf_queue_cancel(struct videobuf_queue *q) -{ - unsigned long flags = 0; - int i; - - q->streaming = 0; - q->reading = 0; - wake_up_interruptible_sync(&q->wait); - - /* remove queued buffers from list */ - spin_lock_irqsave(q->irqlock, flags); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->state == VIDEOBUF_QUEUED) { - list_del(&q->bufs[i]->queue); - q->bufs[i]->state = VIDEOBUF_ERROR; - wake_up_all(&q->bufs[i]->done); - } - } - spin_unlock_irqrestore(q->irqlock, flags); - - /* free all buffers + clear queue */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q, q->bufs[i]); - } - INIT_LIST_HEAD(&q->stream); -} -EXPORT_SYMBOL_GPL(videobuf_queue_cancel); - -/* --------------------------------------------------------------------- */ - -/* Locking: Caller holds q->vb_lock */ -enum v4l2_field videobuf_next_field(struct videobuf_queue *q) -{ - enum v4l2_field field = q->field; - - BUG_ON(V4L2_FIELD_ANY == field); - - if (V4L2_FIELD_ALTERNATE == field) { - if (V4L2_FIELD_TOP == q->last) { - field = V4L2_FIELD_BOTTOM; - q->last = V4L2_FIELD_BOTTOM; - } else { - field = V4L2_FIELD_TOP; - q->last = V4L2_FIELD_TOP; - } - } - return field; -} -EXPORT_SYMBOL_GPL(videobuf_next_field); - -/* Locking: Caller holds q->vb_lock */ -static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, - struct videobuf_buffer *vb, enum v4l2_buf_type type) -{ - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - b->index = vb->i; - b->type = type; - - b->memory = vb->memory; - switch (b->memory) { - case V4L2_MEMORY_MMAP: - b->m.offset = vb->boff; - b->length = vb->bsize; - break; - case V4L2_MEMORY_USERPTR: - b->m.userptr = vb->baddr; - b->length = vb->bsize; - break; - case V4L2_MEMORY_OVERLAY: - b->m.offset = vb->boff; - break; - } - - b->flags = 0; - if (vb->map) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (vb->state) { - case VIDEOBUF_PREPARED: - case VIDEOBUF_QUEUED: - case VIDEOBUF_ACTIVE: - b->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case VIDEOBUF_ERROR: - b->flags |= V4L2_BUF_FLAG_ERROR; - /* fall through */ - case VIDEOBUF_DONE: - b->flags |= V4L2_BUF_FLAG_DONE; - break; - case VIDEOBUF_NEEDS_INIT: - case VIDEOBUF_IDLE: - /* nothing */ - break; - } - - if (vb->input != UNSET) { - b->flags |= V4L2_BUF_FLAG_INPUT; - b->input = vb->input; - } - - b->field = vb->field; - b->timestamp = vb->ts; - b->bytesused = vb->size; - b->sequence = vb->field_count >> 1; -} - -int videobuf_mmap_free(struct videobuf_queue *q) -{ - int ret; - videobuf_queue_lock(q); - ret = __videobuf_free(q); - videobuf_queue_unlock(q); - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_mmap_free); - -/* Locking: Caller holds q->vb_lock */ -int __videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - unsigned int i; - int err; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - err = __videobuf_free(q); - if (0 != err) - return err; - - /* Allocate and initialize buffers */ - for (i = 0; i < bcount; i++) { - q->bufs[i] = videobuf_alloc_vb(q); - - if (NULL == q->bufs[i]) - break; - - q->bufs[i]->i = i; - q->bufs[i]->input = UNSET; - q->bufs[i]->memory = memory; - q->bufs[i]->bsize = bsize; - switch (memory) { - case V4L2_MEMORY_MMAP: - q->bufs[i]->boff = PAGE_ALIGN(bsize) * i; - break; - case V4L2_MEMORY_USERPTR: - case V4L2_MEMORY_OVERLAY: - /* nothing */ - break; - } - } - - if (!i) - return -ENOMEM; - - dprintk(1, "mmap setup: %d buffers, %d bytes each\n", i, bsize); - - return i; -} -EXPORT_SYMBOL_GPL(__videobuf_mmap_setup); - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - int ret; - videobuf_queue_lock(q); - ret = __videobuf_mmap_setup(q, bcount, bsize, memory); - videobuf_queue_unlock(q); - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_mmap_setup); - -int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req) -{ - unsigned int size, count; - int retval; - - if (req->count < 1) { - dprintk(1, "reqbufs: count invalid (%d)\n", req->count); - return -EINVAL; - } - - if (req->memory != V4L2_MEMORY_MMAP && - req->memory != V4L2_MEMORY_USERPTR && - req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1, "reqbufs: memory type invalid\n"); - return -EINVAL; - } - - videobuf_queue_lock(q); - if (req->type != q->type) { - dprintk(1, "reqbufs: queue type invalid\n"); - retval = -EINVAL; - goto done; - } - - if (q->streaming) { - dprintk(1, "reqbufs: streaming already exists\n"); - retval = -EBUSY; - goto done; - } - if (!list_empty(&q->stream)) { - dprintk(1, "reqbufs: stream running\n"); - retval = -EBUSY; - goto done; - } - - count = req->count; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = 0; - q->ops->buf_setup(q, &count, &size); - dprintk(1, "reqbufs: bufs=%d, size=0x%x [%u pages total]\n", - count, size, - (unsigned int)((count * PAGE_ALIGN(size)) >> PAGE_SHIFT)); - - retval = __videobuf_mmap_setup(q, count, size, req->memory); - if (retval < 0) { - dprintk(1, "reqbufs: mmap setup returned %d\n", retval); - goto done; - } - - req->count = retval; - retval = 0; - - done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_reqbufs); - -int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - int ret = -EINVAL; - - videobuf_queue_lock(q); - if (unlikely(b->type != q->type)) { - dprintk(1, "querybuf: Wrong type.\n"); - goto done; - } - if (unlikely(b->index >= VIDEO_MAX_FRAME)) { - dprintk(1, "querybuf: index out of range.\n"); - goto done; - } - if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1, "querybuf: buffer is null.\n"); - goto done; - } - - videobuf_status(q, b, q->bufs[b->index], q->type); - - ret = 0; -done: - videobuf_queue_unlock(q); - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_querybuf); - -int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - struct videobuf_buffer *buf; - enum v4l2_field field; - unsigned long flags = 0; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - if (b->memory == V4L2_MEMORY_MMAP) - down_read(¤t->mm->mmap_sem); - - videobuf_queue_lock(q); - retval = -EBUSY; - if (q->reading) { - dprintk(1, "qbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1, "qbuf: Wrong type.\n"); - goto done; - } - if (b->index >= VIDEO_MAX_FRAME) { - dprintk(1, "qbuf: index out of range.\n"); - goto done; - } - buf = q->bufs[b->index]; - if (NULL == buf) { - dprintk(1, "qbuf: buffer is null.\n"); - goto done; - } - MAGIC_CHECK(buf->magic, MAGIC_BUFFER); - if (buf->memory != b->memory) { - dprintk(1, "qbuf: memory type is wrong.\n"); - goto done; - } - if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { - dprintk(1, "qbuf: buffer is already queued or active.\n"); - goto done; - } - - if (b->flags & V4L2_BUF_FLAG_INPUT) { - if (b->input >= q->inputs) { - dprintk(1, "qbuf: wrong input.\n"); - goto done; - } - buf->input = b->input; - } else { - buf->input = UNSET; - } - - switch (b->memory) { - case V4L2_MEMORY_MMAP: - if (0 == buf->baddr) { - dprintk(1, "qbuf: mmap requested " - "but buffer addr is zero!\n"); - goto done; - } - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT - || q->type == V4L2_BUF_TYPE_VBI_OUTPUT - || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { - buf->size = b->bytesused; - buf->field = b->field; - buf->ts = b->timestamp; - } - break; - case V4L2_MEMORY_USERPTR: - if (b->length < buf->bsize) { - dprintk(1, "qbuf: buffer length is not enough\n"); - goto done; - } - if (VIDEOBUF_NEEDS_INIT != buf->state && - buf->baddr != b->m.userptr) - q->ops->buf_release(q, buf); - buf->baddr = b->m.userptr; - break; - case V4L2_MEMORY_OVERLAY: - buf->boff = b->m.offset; - break; - default: - dprintk(1, "qbuf: wrong memory type\n"); - goto done; - } - - dprintk(1, "qbuf: requesting next field\n"); - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, buf, field); - if (0 != retval) { - dprintk(1, "qbuf: buffer_prepare returned %d\n", retval); - goto done; - } - - list_add_tail(&buf->stream, &q->stream); - if (q->streaming) { - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, buf); - spin_unlock_irqrestore(q->irqlock, flags); - } - dprintk(1, "qbuf: succeeded\n"); - retval = 0; - wake_up_interruptible_sync(&q->wait); - -done: - videobuf_queue_unlock(q); - - if (b->memory == V4L2_MEMORY_MMAP) - up_read(¤t->mm->mmap_sem); - - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_qbuf); - -/* Locking: Caller holds q->vb_lock */ -static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock) -{ - int retval; - -checks: - if (!q->streaming) { - dprintk(1, "next_buffer: Not streaming\n"); - retval = -EINVAL; - goto done; - } - - if (list_empty(&q->stream)) { - if (noblock) { - retval = -EAGAIN; - dprintk(2, "next_buffer: no buffers to dequeue\n"); - goto done; - } else { - dprintk(2, "next_buffer: waiting on buffer\n"); - - /* Drop lock to avoid deadlock with qbuf */ - videobuf_queue_unlock(q); - - /* Checking list_empty and streaming is safe without - * locks because we goto checks to validate while - * holding locks before proceeding */ - retval = wait_event_interruptible(q->wait, - !list_empty(&q->stream) || !q->streaming); - videobuf_queue_lock(q); - - if (retval) - goto done; - - goto checks; - } - } - - retval = 0; - -done: - return retval; -} - -/* Locking: Caller holds q->vb_lock */ -static int stream_next_buffer(struct videobuf_queue *q, - struct videobuf_buffer **vb, int nonblocking) -{ - int retval; - struct videobuf_buffer *buf = NULL; - - retval = stream_next_buffer_check_queue(q, nonblocking); - if (retval) - goto done; - - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - retval = videobuf_waiton(q, buf, nonblocking, 1); - if (retval < 0) - goto done; - - *vb = buf; -done: - return retval; -} - -int videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking) -{ - struct videobuf_buffer *buf = NULL; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - memset(b, 0, sizeof(*b)); - videobuf_queue_lock(q); - - retval = stream_next_buffer(q, &buf, nonblocking); - if (retval < 0) { - dprintk(1, "dqbuf: next_buffer error: %i\n", retval); - goto done; - } - - switch (buf->state) { - case VIDEOBUF_ERROR: - dprintk(1, "dqbuf: state is error\n"); - break; - case VIDEOBUF_DONE: - dprintk(1, "dqbuf: state is done\n"); - break; - default: - dprintk(1, "dqbuf: state invalid\n"); - retval = -EINVAL; - goto done; - } - CALL(q, sync, q, buf); - videobuf_status(q, b, buf, q->type); - list_del(&buf->stream); - buf->state = VIDEOBUF_IDLE; - b->flags &= ~V4L2_BUF_FLAG_DONE; -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_dqbuf); - -int videobuf_streamon(struct videobuf_queue *q) -{ - struct videobuf_buffer *buf; - unsigned long flags = 0; - int retval; - - videobuf_queue_lock(q); - retval = -EBUSY; - if (q->reading) - goto done; - retval = 0; - if (q->streaming) - goto done; - q->streaming = 1; - spin_lock_irqsave(q->irqlock, flags); - list_for_each_entry(buf, &q->stream, stream) - if (buf->state == VIDEOBUF_PREPARED) - q->ops->buf_queue(q, buf); - spin_unlock_irqrestore(q->irqlock, flags); - - wake_up_interruptible_sync(&q->wait); -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_streamon); - -/* Locking: Caller holds q->vb_lock */ -static int __videobuf_streamoff(struct videobuf_queue *q) -{ - if (!q->streaming) - return -EINVAL; - - videobuf_queue_cancel(q); - - return 0; -} - -int videobuf_streamoff(struct videobuf_queue *q) -{ - int retval; - - videobuf_queue_lock(q); - retval = __videobuf_streamoff(q); - videobuf_queue_unlock(q); - - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_streamoff); - -/* Locking: Caller holds q->vb_lock */ -static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, - char __user *data, - size_t count, loff_t *ppos) -{ - enum v4l2_field field; - unsigned long flags = 0; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - /* setup stuff */ - q->read_buf = videobuf_alloc_vb(q); - if (NULL == q->read_buf) - return -ENOMEM; - - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->baddr = (unsigned long)data; - q->read_buf->bsize = count; - - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, q->read_buf, field); - if (0 != retval) - goto done; - - /* start capture & wait */ - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); - spin_unlock_irqrestore(q->irqlock, flags); - retval = videobuf_waiton(q, q->read_buf, 0, 0); - if (0 == retval) { - CALL(q, sync, q, q->read_buf); - if (VIDEOBUF_ERROR == q->read_buf->state) - retval = -EIO; - else - retval = q->read_buf->size; - } - -done: - /* cleanup */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - return retval; -} - -static int __videobuf_copy_to_user(struct videobuf_queue *q, - struct videobuf_buffer *buf, - char __user *data, size_t count, - int nonblocking) -{ - void *vaddr = CALL(q, vaddr, buf); - - /* copy to userspace */ - if (count > buf->size - q->read_off) - count = buf->size - q->read_off; - - if (copy_to_user(data, vaddr + q->read_off, count)) - return -EFAULT; - - return count; -} - -static int __videobuf_copy_stream(struct videobuf_queue *q, - struct videobuf_buffer *buf, - char __user *data, size_t count, size_t pos, - int vbihack, int nonblocking) -{ - unsigned int *fc = CALL(q, vaddr, buf); - - if (vbihack) { - /* dirty, undocumented hack -- pass the frame counter - * within the last four bytes of each vbi data block. - * We need that one to maintain backward compatibility - * to all vbi decoding software out there ... */ - fc += (buf->size >> 2) - 1; - *fc = buf->field_count >> 1; - dprintk(1, "vbihack: %d\n", *fc); - } - - /* copy stuff using the common method */ - count = __videobuf_copy_to_user(q, buf, data, count, nonblocking); - - if ((count == -EFAULT) && (pos == 0)) - return -EFAULT; - - return count; -} - -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking) -{ - enum v4l2_field field; - unsigned long flags = 0; - unsigned size = 0, nbufs = 1; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - videobuf_queue_lock(q); - - q->ops->buf_setup(q, &nbufs, &size); - - if (NULL == q->read_buf && - count >= size && - !nonblocking) { - retval = videobuf_read_zerocopy(q, data, count, ppos); - if (retval >= 0 || retval == -EIO) - /* ok, all done */ - goto done; - /* fallback to kernel bounce buffer on failures */ - } - - if (NULL == q->read_buf) { - /* need to capture a new frame */ - retval = -ENOMEM; - q->read_buf = videobuf_alloc_vb(q); - - dprintk(1, "video alloc=0x%p\n", q->read_buf); - if (NULL == q->read_buf) - goto done; - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->bsize = count; /* preferred size */ - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, q->read_buf, field); - - if (0 != retval) { - kfree(q->read_buf); - q->read_buf = NULL; - goto done; - } - - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); - spin_unlock_irqrestore(q->irqlock, flags); - - q->read_off = 0; - } - - /* wait until capture is done */ - retval = videobuf_waiton(q, q->read_buf, nonblocking, 1); - if (0 != retval) - goto done; - - CALL(q, sync, q, q->read_buf); - - if (VIDEOBUF_ERROR == q->read_buf->state) { - /* catch I/O errors */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - retval = -EIO; - goto done; - } - - /* Copy to userspace */ - retval = __videobuf_copy_to_user(q, q->read_buf, data, count, nonblocking); - if (retval < 0) - goto done; - - q->read_off += retval; - if (q->read_off == q->read_buf->size) { - /* all data copied, cleanup */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - } - -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_read_one); - -/* Locking: Caller holds q->vb_lock */ -static int __videobuf_read_start(struct videobuf_queue *q) -{ - enum v4l2_field field; - unsigned long flags = 0; - unsigned int count = 0, size = 0; - int err, i; - - q->ops->buf_setup(q, &count, &size); - if (count < 2) - count = 2; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = PAGE_ALIGN(size); - - err = __videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err < 0) - return err; - - count = err; - - for (i = 0; i < count; i++) { - field = videobuf_next_field(q); - err = q->ops->buf_prepare(q, q->bufs[i], field); - if (err) - return err; - list_add_tail(&q->bufs[i]->stream, &q->stream); - } - spin_lock_irqsave(q->irqlock, flags); - for (i = 0; i < count; i++) - q->ops->buf_queue(q, q->bufs[i]); - spin_unlock_irqrestore(q->irqlock, flags); - q->reading = 1; - return 0; -} - -static void __videobuf_read_stop(struct videobuf_queue *q) -{ - int i; - - videobuf_queue_cancel(q); - __videobuf_free(q); - INIT_LIST_HEAD(&q->stream); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - q->read_buf = NULL; -} - -int videobuf_read_start(struct videobuf_queue *q) -{ - int rc; - - videobuf_queue_lock(q); - rc = __videobuf_read_start(q); - videobuf_queue_unlock(q); - - return rc; -} -EXPORT_SYMBOL_GPL(videobuf_read_start); - -void videobuf_read_stop(struct videobuf_queue *q) -{ - videobuf_queue_lock(q); - __videobuf_read_stop(q); - videobuf_queue_unlock(q); -} -EXPORT_SYMBOL_GPL(videobuf_read_stop); - -void videobuf_stop(struct videobuf_queue *q) -{ - videobuf_queue_lock(q); - - if (q->streaming) - __videobuf_streamoff(q); - - if (q->reading) - __videobuf_read_stop(q); - - videobuf_queue_unlock(q); -} -EXPORT_SYMBOL_GPL(videobuf_stop); - -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking) -{ - int rc, retval; - unsigned long flags = 0; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - dprintk(2, "%s\n", __func__); - videobuf_queue_lock(q); - retval = -EBUSY; - if (q->streaming) - goto done; - if (!q->reading) { - retval = __videobuf_read_start(q); - if (retval < 0) - goto done; - } - - retval = 0; - while (count > 0) { - /* get / wait for data */ - if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - rc = videobuf_waiton(q, q->read_buf, nonblocking, 1); - if (rc < 0) { - if (0 == retval) - retval = rc; - break; - } - - if (q->read_buf->state == VIDEOBUF_DONE) { - rc = __videobuf_copy_stream(q, q->read_buf, data + retval, count, - retval, vbihack, nonblocking); - if (rc < 0) { - retval = rc; - break; - } - retval += rc; - count -= rc; - q->read_off += rc; - } else { - /* some error */ - q->read_off = q->read_buf->size; - if (0 == retval) - retval = -EIO; - } - - /* requeue buffer when done with copying */ - if (q->read_off == q->read_buf->size) { - list_add_tail(&q->read_buf->stream, - &q->stream); - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); - spin_unlock_irqrestore(q->irqlock, flags); - q->read_buf = NULL; - } - if (retval < 0) - break; - } - -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_read_stream); - -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait) -{ - struct videobuf_buffer *buf = NULL; - unsigned int rc = 0; - - videobuf_queue_lock(q); - if (q->streaming) { - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, - struct videobuf_buffer, stream); - } else { - if (!q->reading) - __videobuf_read_start(q); - if (!q->reading) { - rc = POLLERR; - } else if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - buf = q->read_buf; - } - if (!buf) - rc = POLLERR; - - if (0 == rc) { - poll_wait(file, &buf->done, wait); - if (buf->state == VIDEOBUF_DONE || - buf->state == VIDEOBUF_ERROR) { - switch (q->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - case V4L2_BUF_TYPE_VBI_OUTPUT: - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - rc = POLLOUT | POLLWRNORM; - break; - default: - rc = POLLIN | POLLRDNORM; - break; - } - } - } - videobuf_queue_unlock(q); - return rc; -} -EXPORT_SYMBOL_GPL(videobuf_poll_stream); - -int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma) -{ - int rc = -EINVAL; - int i; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) { - dprintk(1, "mmap appl bug: PROT_WRITE and MAP_SHARED are required\n"); - return -EINVAL; - } - - videobuf_queue_lock(q); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - struct videobuf_buffer *buf = q->bufs[i]; - - if (buf && buf->memory == V4L2_MEMORY_MMAP && - buf->boff == (vma->vm_pgoff << PAGE_SHIFT)) { - rc = CALL(q, mmap_mapper, q, buf, vma); - break; - } - } - videobuf_queue_unlock(q); - - return rc; -} -EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dma-contig.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dma-contig.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dma-contig.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dma-contig.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,400 +0,0 @@ -/* - * helper functions for physically contiguous capture buffers - * - * The functions support hardware lacking scatter gather support - * (i.e. the buffers must be linear in physical memory) - * - * Copyright (c) 2008 Magnus Damm - * - * Based on videobuf-vmalloc.c, - * (c) 2007 Mauro Carvalho Chehab, - * - * 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 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct videobuf_dma_contig_memory { - u32 magic; - void *vaddr; - dma_addr_t dma_handle; - unsigned long size; -}; - -#define MAGIC_DC_MEM 0x0733ac61 -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - pr_err("magic mismatch: %x expected %x\n", (is), (should)); \ - BUG(); \ - } - -static void -videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", - map, map->count, vma->vm_start, vma->vm_end); - - map->count++; -} - -static void videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", - map, map->count, vma->vm_start, vma->vm_end); - - map->count--; - if (0 == map->count) { - struct videobuf_dma_contig_memory *mem; - - dev_dbg(q->dev, "munmap %p q=%p\n", map, q); - videobuf_queue_lock(q); - - /* We need first to cancel streams, before unmapping */ - if (q->streaming) - videobuf_queue_cancel(q); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - - if (q->bufs[i]->map != map) - continue; - - mem = q->bufs[i]->priv; - if (mem) { - /* This callback is called only if kernel has - allocated memory and this memory is mmapped. - In this case, memory should be freed, - in order to do memory unmap. - */ - - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - /* vfree is not atomic - can't be - called with IRQ's disabled - */ - dev_dbg(q->dev, "buf[%d] freeing %p\n", - i, mem->vaddr); - - dma_free_coherent(q->dev, mem->size, - mem->vaddr, mem->dma_handle); - mem->vaddr = NULL; - } - - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - } - - kfree(map); - - videobuf_queue_unlock(q); - } -} - -static const struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, -}; - -/** - * videobuf_dma_contig_user_put() - reset pointer to user space buffer - * @mem: per-buffer private videobuf-dma-contig data - * - * This function resets the user space pointer - */ -static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem) -{ - mem->dma_handle = 0; - mem->size = 0; -} - -/** - * videobuf_dma_contig_user_get() - setup user space memory pointer - * @mem: per-buffer private videobuf-dma-contig data - * @vb: video buffer to map - * - * This function validates and sets up a pointer to user space memory. - * Only physically contiguous pfn-mapped memory is accepted. - * - * Returns 0 if successful. - */ -static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, - struct videobuf_buffer *vb) -{ - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long prev_pfn, this_pfn; - unsigned long pages_done, user_address; - unsigned int offset; - int ret; - - offset = vb->baddr & ~PAGE_MASK; - mem->size = PAGE_ALIGN(vb->size + offset); - ret = -EINVAL; - - down_read(&mm->mmap_sem); - - vma = find_vma(mm, vb->baddr); - if (!vma) - goto out_up; - - if ((vb->baddr + mem->size) > vma->vm_end) - goto out_up; - - pages_done = 0; - prev_pfn = 0; /* kill warning */ - user_address = vb->baddr; - - while (pages_done < (mem->size >> PAGE_SHIFT)) { - ret = follow_pfn(vma, user_address, &this_pfn); - if (ret) - break; - - if (pages_done == 0) - mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset; - else if (this_pfn != (prev_pfn + 1)) - ret = -EFAULT; - - if (ret) - break; - - prev_pfn = this_pfn; - user_address += PAGE_SIZE; - pages_done++; - } - - out_up: - up_read(¤t->mm->mmap_sem); - - return ret; -} - -static struct videobuf_buffer *__videobuf_alloc_vb(size_t size) -{ - struct videobuf_dma_contig_memory *mem; - struct videobuf_buffer *vb; - - vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); - if (vb) { - mem = vb->priv = ((char *)vb) + size; - mem->magic = MAGIC_DC_MEM; - } - - return vb; -} - -static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - return mem->vaddr; -} - -static int __videobuf_iolock(struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - struct videobuf_dma_contig_memory *mem = vb->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - dev_dbg(q->dev, "%s memory method MMAP\n", __func__); - - /* All handling should be done by __videobuf_mmap_mapper() */ - if (!mem->vaddr) { - dev_err(q->dev, "memory is not alloced/mmapped.\n"); - return -EINVAL; - } - break; - case V4L2_MEMORY_USERPTR: - dev_dbg(q->dev, "%s memory method USERPTR\n", __func__); - - /* handle pointer from user space */ - if (vb->baddr) - return videobuf_dma_contig_user_get(mem, vb); - - /* allocate memory for the read() method */ - mem->size = PAGE_ALIGN(vb->size); - mem->vaddr = dma_alloc_coherent(q->dev, mem->size, - &mem->dma_handle, GFP_KERNEL); - if (!mem->vaddr) { - dev_err(q->dev, "dma_alloc_coherent %ld failed\n", - mem->size); - return -ENOMEM; - } - - dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n", - mem->vaddr, mem->size); - break; - case V4L2_MEMORY_OVERLAY: - default: - dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", - __func__); - return -EINVAL; - } - - return 0; -} - -static int __videobuf_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct videobuf_dma_contig_memory *mem; - struct videobuf_mapping *map; - int retval; - unsigned long size; - - dev_dbg(q->dev, "%s\n", __func__); - - /* create mapping + update buffer list */ - map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (!map) - return -ENOMEM; - - buf->map = map; - map->q = q; - - buf->baddr = vma->vm_start; - - mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - mem->size = PAGE_ALIGN(buf->bsize); - mem->vaddr = dma_alloc_coherent(q->dev, mem->size, - &mem->dma_handle, GFP_KERNEL); - if (!mem->vaddr) { - dev_err(q->dev, "dma_alloc_coherent size %ld failed\n", - mem->size); - goto error; - } - dev_dbg(q->dev, "dma_alloc_coherent data is at addr %p (size %ld)\n", - mem->vaddr, mem->size); - - /* Try to remap memory */ - - size = vma->vm_end - vma->vm_start; - size = (size < mem->size) ? size : mem->size; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - retval = remap_pfn_range(vma, vma->vm_start, - PFN_DOWN(virt_to_phys(mem->vaddr)), - size, vma->vm_page_prot); - if (retval) { - dev_err(q->dev, "mmap: remap failed with error %d. ", retval); - dma_free_coherent(q->dev, mem->size, - mem->vaddr, mem->dma_handle); - goto error; - } - - vma->vm_ops = &videobuf_vm_ops; - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_private_data = map; - - dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", - map, q, vma->vm_start, vma->vm_end, - (long int)buf->bsize, - vma->vm_pgoff, buf->i); - - videobuf_vm_open(vma); - - return 0; - -error: - kfree(map); - return -ENOMEM; -} - -static struct videobuf_qtype_ops qops = { - .magic = MAGIC_QTYPE_OPS, - - .alloc_vb = __videobuf_alloc_vb, - .iolock = __videobuf_iolock, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = __videobuf_to_vaddr, -}; - -void videobuf_queue_dma_contig_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &qops, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init); - -dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - return mem->dma_handle; -} -EXPORT_SYMBOL_GPL(videobuf_to_dma_contig); - -void videobuf_dma_contig_free(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - /* mmapped memory can't be freed here, otherwise mmapped region - would be released, while still needed. In this case, the memory - release should happen inside videobuf_vm_close(). - So, it should free memory only if the memory were allocated for - read() operation. - */ - if (buf->memory != V4L2_MEMORY_USERPTR) - return; - - if (!mem) - return; - - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - /* handle user space pointer case */ - if (buf->baddr) { - videobuf_dma_contig_user_put(mem); - return; - } - - /* read() method */ - if (mem->vaddr) { - dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle); - mem->vaddr = NULL; - } -} -EXPORT_SYMBOL_GPL(videobuf_dma_contig_free); - -MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dma-sg.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dma-sg.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dma-sg.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dma-sg.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,632 +0,0 @@ -/* - * helper functions for SG DMA video4linux capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab, - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - * - * 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 - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#define MAGIC_DMABUF 0x19721112 -#define MAGIC_SG_MEM 0x17890714 - -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } - -static int debug; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux dma sg buffers"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) - -/* --------------------------------------------------------------------- */ - -/* - * Return a scatterlist for some page-aligned vmalloc()'ed memory - * block (NULL on errors). Memory for the scatterlist is allocated - * using kmalloc. The caller must free the memory. - */ -static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, - int nr_pages) -{ - struct scatterlist *sglist; - struct page *pg; - int i; - - sglist = vzalloc(nr_pages * sizeof(*sglist)); - if (NULL == sglist) - return NULL; - sg_init_table(sglist, nr_pages); - for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { - pg = vmalloc_to_page(virt); - if (NULL == pg) - goto err; - BUG_ON(PageHighMem(pg)); - sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); - } - return sglist; - -err: - vfree(sglist); - return NULL; -} - -/* - * Return a scatterlist for a an array of userpages (NULL on errors). - * Memory for the scatterlist is allocated using kmalloc. The caller - * must free the memory. - */ -static struct scatterlist *videobuf_pages_to_sg(struct page **pages, - int nr_pages, int offset, size_t size) -{ - struct scatterlist *sglist; - int i; - - if (NULL == pages[0]) - return NULL; - sglist = vmalloc(nr_pages * sizeof(*sglist)); - if (NULL == sglist) - return NULL; - sg_init_table(sglist, nr_pages); - - if (PageHighMem(pages[0])) - /* DMA to highmem pages might not work */ - goto highmem; - sg_set_page(&sglist[0], pages[0], PAGE_SIZE - offset, offset); - size -= PAGE_SIZE - offset; - for (i = 1; i < nr_pages; i++) { - if (NULL == pages[i]) - goto nopage; - if (PageHighMem(pages[i])) - goto highmem; - sg_set_page(&sglist[i], pages[i], min_t(size_t, PAGE_SIZE, size), 0); - size -= min_t(size_t, PAGE_SIZE, size); - } - return sglist; - -nopage: - dprintk(2, "sgl: oops - no page\n"); - vfree(sglist); - return NULL; - -highmem: - dprintk(2, "sgl: oops - highmem page\n"); - vfree(sglist); - return NULL; -} - -/* --------------------------------------------------------------------- */ - -struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - return &mem->dma; -} -EXPORT_SYMBOL_GPL(videobuf_to_dma); - -void videobuf_dma_init(struct videobuf_dmabuf *dma) -{ - memset(dma, 0, sizeof(*dma)); - dma->magic = MAGIC_DMABUF; -} -EXPORT_SYMBOL_GPL(videobuf_dma_init); - -static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, - int direction, unsigned long data, unsigned long size) -{ - unsigned long first, last; - int err, rw = 0; - - dma->direction = direction; - switch (dma->direction) { - case DMA_FROM_DEVICE: - rw = READ; - break; - case DMA_TO_DEVICE: - rw = WRITE; - break; - default: - BUG(); - } - - first = (data & PAGE_MASK) >> PAGE_SHIFT; - last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; - dma->offset = data & ~PAGE_MASK; - dma->size = size; - dma->nr_pages = last-first+1; - dma->pages = kmalloc(dma->nr_pages * sizeof(struct page *), GFP_KERNEL); - if (NULL == dma->pages) - return -ENOMEM; - - dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n", - data, size, dma->nr_pages); - - err = get_user_pages(current, current->mm, - data & PAGE_MASK, dma->nr_pages, - rw == READ, 1, /* force */ - dma->pages, NULL); - - if (err != dma->nr_pages) { - dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1, "get_user_pages: err=%d [%d]\n", err, dma->nr_pages); - return err < 0 ? err : -EINVAL; - } - return 0; -} - -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) -{ - int ret; - - down_read(¤t->mm->mmap_sem); - ret = videobuf_dma_init_user_locked(dma, direction, data, size); - up_read(¤t->mm->mmap_sem); - - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_dma_init_user); - -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages) -{ - dprintk(1, "init kernel [%d pages]\n", nr_pages); - - dma->direction = direction; - dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); - if (NULL == dma->vaddr) { - dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); - return -ENOMEM; - } - - dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)dma->vaddr, - nr_pages << PAGE_SHIFT); - - memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); - dma->nr_pages = nr_pages; - - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); - -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages) -{ - dprintk(1, "init overlay [%d pages @ bus 0x%lx]\n", - nr_pages, (unsigned long)addr); - dma->direction = direction; - - if (0 == addr) - return -EINVAL; - - dma->bus_addr = addr; - dma->nr_pages = nr_pages; - - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); - -int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - BUG_ON(0 == dma->nr_pages); - - if (dma->pages) { - dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, - dma->offset, dma->size); - } - if (dma->vaddr) { - dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr, - dma->nr_pages); - } - if (dma->bus_addr) { - dma->sglist = vmalloc(sizeof(*dma->sglist)); - if (NULL != dma->sglist) { - dma->sglen = 1; - sg_dma_address(&dma->sglist[0]) = dma->bus_addr - & PAGE_MASK; - dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; - sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; - } - } - if (NULL == dma->sglist) { - dprintk(1, "scatterlist is NULL\n"); - return -ENOMEM; - } - if (!dma->bus_addr) { - dma->sglen = dma_map_sg(dev, dma->sglist, - dma->nr_pages, dma->direction); - if (0 == dma->sglen) { - printk(KERN_WARNING - "%s: videobuf_map_sg failed\n", __func__); - vfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return -ENOMEM; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_dma_map); - -int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - - if (!dma->sglen) - return 0; - - dma_unmap_sg(dev, dma->sglist, dma->sglen, dma->direction); - - vfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_dma_unmap); - -int videobuf_dma_free(struct videobuf_dmabuf *dma) -{ - int i; - MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - BUG_ON(dma->sglen); - - if (dma->pages) { - for (i = 0; i < dma->nr_pages; i++) - page_cache_release(dma->pages[i]); - kfree(dma->pages); - dma->pages = NULL; - } - - vfree(dma->vaddr); - dma->vaddr = NULL; - - if (dma->bus_addr) - dma->bus_addr = 0; - dma->direction = DMA_NONE; - - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_dma_free); - -/* --------------------------------------------------------------------- */ - -static void videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count++; -} - -static void videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - struct videobuf_dma_sg_memory *mem; - int i; - - dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count--; - if (0 == map->count) { - dprintk(1, "munmap %p q=%p\n", map, q); - videobuf_queue_lock(q); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - mem = q->bufs[i]->priv; - if (!mem) - continue; - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - if (q->bufs[i]->map != map) - continue; - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - q->ops->buf_release(q, q->bufs[i]); - } - videobuf_queue_unlock(q); - kfree(map); - } - return; -} - -/* - * Get a anonymous page for the mapping. Make sure we can DMA to that - * memory location with 32bit PCI devices (i.e. don't use highmem for - * now ...). Bounce buffers don't work very well for the data rates - * video capture has. - */ -static int videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct page *page; - - dprintk(3, "fault: fault @ %08lx [vma %08lx-%08lx]\n", - (unsigned long)vmf->virtual_address, - vma->vm_start, vma->vm_end); - - page = alloc_page(GFP_USER | __GFP_DMA32); - if (!page) - return VM_FAULT_OOM; - clear_user_highpage(page, (unsigned long)vmf->virtual_address); - vmf->page = page; - - return 0; -} - -static const struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, - .fault = videobuf_vm_fault, -}; - -/* --------------------------------------------------------------------- - * SG handlers for the generic methods - */ - -/* Allocated area consists on 3 parts: - struct video_buffer - struct _buffer (cx88_buffer, saa7134_buf, ...) - struct videobuf_dma_sg_memory - */ - -static struct videobuf_buffer *__videobuf_alloc_vb(size_t size) -{ - struct videobuf_dma_sg_memory *mem; - struct videobuf_buffer *vb; - - vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); - if (!vb) - return vb; - - mem = vb->priv = ((char *)vb) + size; - mem->magic = MAGIC_SG_MEM; - - videobuf_dma_init(&mem->dma); - - dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n", - __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb), - mem, (long)sizeof(*mem)); - - return vb; -} - -static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - return mem->dma.vaddr; -} - -static int __videobuf_iolock(struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - int err, pages; - dma_addr_t bus; - struct videobuf_dma_sg_memory *mem = vb->priv; - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_USERPTR: - if (0 == vb->baddr) { - /* no userspace addr -- kernel bounce buffer */ - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_kernel(&mem->dma, - DMA_FROM_DEVICE, - pages); - if (0 != err) - return err; - } else if (vb->memory == V4L2_MEMORY_USERPTR) { - /* dma directly to userspace */ - err = videobuf_dma_init_user(&mem->dma, - DMA_FROM_DEVICE, - vb->baddr, vb->bsize); - if (0 != err) - return err; - } else { - /* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP - buffers can only be called from videobuf_qbuf - we take current->mm->mmap_sem there, to prevent - locking inversion, so don't take it here */ - - err = videobuf_dma_init_user_locked(&mem->dma, - DMA_FROM_DEVICE, - vb->baddr, vb->bsize); - if (0 != err) - return err; - } - break; - case V4L2_MEMORY_OVERLAY: - if (NULL == fbuf) - return -EINVAL; - /* FIXME: need sanity checks for vb->boff */ - /* - * Using a double cast to avoid compiler warnings when - * building for PAE. Compiler doesn't like direct casting - * of a 32 bit ptr to 64 bit integer. - */ - bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_overlay(&mem->dma, DMA_FROM_DEVICE, - bus, pages); - if (0 != err) - return err; - break; - default: - BUG(); - } - err = videobuf_dma_map(q->dev, &mem->dma); - if (0 != err) - return err; - - return 0; -} - -static int __videobuf_sync(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - BUG_ON(!mem || !mem->dma.sglen); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - MAGIC_CHECK(mem->dma.magic, MAGIC_DMABUF); - - dma_sync_sg_for_cpu(q->dev, mem->dma.sglist, - mem->dma.sglen, mem->dma.direction); - - return 0; -} - -static int __videobuf_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - struct videobuf_mapping *map; - unsigned int first, last, size = 0, i; - int retval; - - retval = -EINVAL; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - /* look for first buffer to map */ - for (first = 0; first < VIDEO_MAX_FRAME; first++) { - if (buf == q->bufs[first]) { - size = PAGE_ALIGN(q->bufs[first]->bsize); - break; - } - } - - /* paranoia, should never happen since buf is always valid. */ - if (!size) { - dprintk(1, "mmap app bug: offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - goto done; - } - - last = first; - - /* create mapping + update buffer list */ - retval = -ENOMEM; - map = kmalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (NULL == map) - goto done; - - size = 0; - for (i = first; i <= last; i++) { - if (NULL == q->bufs[i]) - continue; - q->bufs[i]->map = map; - q->bufs[i]->baddr = vma->vm_start + size; - size += PAGE_ALIGN(q->bufs[i]->bsize); - } - - map->count = 1; - map->q = q; - vma->vm_ops = &videobuf_vm_ops; - vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; - vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ - vma->vm_private_data = map; - dprintk(1, "mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", - map, q, vma->vm_start, vma->vm_end, vma->vm_pgoff, first, last); - retval = 0; - -done: - return retval; -} - -static struct videobuf_qtype_ops sg_ops = { - .magic = MAGIC_QTYPE_OPS, - - .alloc_vb = __videobuf_alloc_vb, - .iolock = __videobuf_iolock, - .sync = __videobuf_sync, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = __videobuf_to_vaddr, -}; - -void *videobuf_sg_alloc(size_t size) -{ - struct videobuf_queue q; - - /* Required to make generic handler to call __videobuf_alloc */ - q.int_ops = &sg_ops; - - q.msize = size; - - return videobuf_alloc_vb(&q); -} -EXPORT_SYMBOL_GPL(videobuf_sg_alloc); - -void videobuf_queue_sg_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &sg_ops, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_sg_init); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dvb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,403 +0,0 @@ -/* - * - * some helper function for simple DVB cards which simply DMA the - * complete transport stream and let the computer sort everything else - * (i.e. we are using the software demux, ...). Also uses the - * video-buf to manage DMA buffers. - * - * (c) 2004 Gerd Knorr [SUSE Labs] - * - * 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, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -/* ------------------------------------------------------------------ */ - -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages"); - -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/dvb: " fmt, dvb->name , ## arg) - -/* ------------------------------------------------------------------ */ - -static int videobuf_dvb_thread(void *data) -{ - struct videobuf_dvb *dvb = data; - struct videobuf_buffer *buf; - unsigned long flags; - int err; - void *outp; - - dprintk("dvb thread started\n"); - set_freezable(); - videobuf_read_start(&dvb->dvbq); - - for (;;) { - /* fetch next buffer */ - buf = list_entry(dvb->dvbq.stream.next, - struct videobuf_buffer, stream); - list_del(&buf->stream); - err = videobuf_waiton(&dvb->dvbq, buf, 0, 1); - - /* no more feeds left or stop_feed() asked us to quit */ - if (0 == dvb->nfeeds) - break; - if (kthread_should_stop()) - break; - try_to_freeze(); - - /* feed buffer data to demux */ - outp = videobuf_queue_to_vaddr(&dvb->dvbq, buf); - - if (buf->state == VIDEOBUF_DONE) - dvb_dmx_swfilter(&dvb->demux, outp, - buf->size); - - /* requeue buffer */ - list_add_tail(&buf->stream,&dvb->dvbq.stream); - spin_lock_irqsave(dvb->dvbq.irqlock,flags); - dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf); - spin_unlock_irqrestore(dvb->dvbq.irqlock,flags); - } - - videobuf_read_stop(&dvb->dvbq); - dprintk("dvb thread stopped\n"); - - /* Hmm, linux becomes *very* unhappy without this ... */ - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - return 0; -} - -static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct videobuf_dvb *dvb = demux->priv; - int rc; - - if (!demux->dmx.frontend) - return -EINVAL; - - mutex_lock(&dvb->lock); - dvb->nfeeds++; - rc = dvb->nfeeds; - - if (NULL != dvb->thread) - goto out; - dvb->thread = kthread_run(videobuf_dvb_thread, - dvb, "%s dvb", dvb->name); - if (IS_ERR(dvb->thread)) { - rc = PTR_ERR(dvb->thread); - dvb->thread = NULL; - } - -out: - mutex_unlock(&dvb->lock); - return rc; -} - -static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct videobuf_dvb *dvb = demux->priv; - int err = 0; - - mutex_lock(&dvb->lock); - dvb->nfeeds--; - if (0 == dvb->nfeeds && NULL != dvb->thread) { - err = kthread_stop(dvb->thread); - dvb->thread = NULL; - } - mutex_unlock(&dvb->lock); - return err; -} - -static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, - struct module *module, - void *adapter_priv, - struct device *device, - char *adapter_name, - short *adapter_nr, - int mfe_shared, - int (*fe_ioctl_override)(struct dvb_frontend *, - unsigned int, void *, unsigned int)) -{ - int result; - - mutex_init(&fe->lock); - - /* register adapter */ - result = dvb_register_adapter(&fe->adapter, adapter_name, module, - device, adapter_nr); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", - adapter_name, result); - } - fe->adapter.priv = adapter_priv; - fe->adapter.mfe_shared = mfe_shared; - fe->adapter.fe_ioctl_override = fe_ioctl_override; - - return result; -} - -static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, - struct videobuf_dvb *dvb) -{ - int result; - - /* register frontend */ - result = dvb_register_frontend(adapter, dvb->frontend); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", - dvb->name, result); - goto fail_frontend; - } - - /* register demux stuff */ - dvb->demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dvb; - dvb->demux.filternum = 256; - dvb->demux.feednum = 256; - dvb->demux.start_feed = videobuf_dvb_start_feed; - dvb->demux.stop_feed = videobuf_dvb_stop_feed; - result = dvb_dmx_init(&dvb->demux); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", - dvb->name, result); - goto fail_dmx; - } - - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = &dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, adapter); - - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", - dvb->name, result); - goto fail_dmxdev; - } - - dvb->fe_hw.source = DMX_FRONTEND_0; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", - dvb->name, result); - goto fail_fe_hw; - } - - dvb->fe_mem.source = DMX_MEMORY_FE; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", - dvb->name, result); - goto fail_fe_mem; - } - - result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", - dvb->name, result); - goto fail_fe_conn; - } - - /* register network adapter */ - dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); - if (dvb->net.dvbdev == NULL) { - result = -ENOMEM; - goto fail_fe_conn; - } - return 0; - -fail_fe_conn: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); -fail_fe_mem: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); -fail_fe_hw: - dvb_dmxdev_release(&dvb->dmxdev); -fail_dmxdev: - dvb_dmx_release(&dvb->demux); -fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); - dvb->frontend = NULL; - - return result; -} - -/* ------------------------------------------------------------------ */ -/* Register a single adapter and one or more frontends */ -int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, - struct module *module, - void *adapter_priv, - struct device *device, - short *adapter_nr, - int mfe_shared, - int (*fe_ioctl_override)(struct dvb_frontend *, - unsigned int, void *, unsigned int)) -{ - struct list_head *list, *q; - struct videobuf_dvb_frontend *fe; - int res; - - fe = videobuf_dvb_get_frontend(f, 1); - if (!fe) { - printk(KERN_WARNING "Unable to register the adapter which has no frontends\n"); - return -EINVAL; - } - - /* Bring up the adapter */ - res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, - fe->dvb.name, adapter_nr, mfe_shared, fe_ioctl_override); - if (res < 0) { - printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); - return res; - } - - /* Attach all of the frontends to the adapter */ - mutex_lock(&f->lock); - list_for_each_safe(list, q, &f->felist) { - fe = list_entry(list, struct videobuf_dvb_frontend, felist); - res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb); - if (res < 0) { - printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n", - fe->dvb.name, res); - goto err; - } - } - mutex_unlock(&f->lock); - return 0; - -err: - mutex_unlock(&f->lock); - videobuf_dvb_unregister_bus(f); - return res; -} -EXPORT_SYMBOL(videobuf_dvb_register_bus); - -void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f) -{ - videobuf_dvb_dealloc_frontends(f); - - dvb_unregister_adapter(&f->adapter); -} -EXPORT_SYMBOL(videobuf_dvb_unregister_bus); - -struct videobuf_dvb_frontend *videobuf_dvb_get_frontend( - struct videobuf_dvb_frontends *f, int id) -{ - struct list_head *list, *q; - struct videobuf_dvb_frontend *fe, *ret = NULL; - - mutex_lock(&f->lock); - - list_for_each_safe(list, q, &f->felist) { - fe = list_entry(list, struct videobuf_dvb_frontend, felist); - if (fe->id == id) { - ret = fe; - break; - } - } - - mutex_unlock(&f->lock); - - return ret; -} -EXPORT_SYMBOL(videobuf_dvb_get_frontend); - -int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, - struct dvb_frontend *p) -{ - struct list_head *list, *q; - struct videobuf_dvb_frontend *fe = NULL; - int ret = 0; - - mutex_lock(&f->lock); - - list_for_each_safe(list, q, &f->felist) { - fe = list_entry(list, struct videobuf_dvb_frontend, felist); - if (fe->dvb.frontend == p) { - ret = fe->id; - break; - } - } - - mutex_unlock(&f->lock); - - return ret; -} -EXPORT_SYMBOL(videobuf_dvb_find_frontend); - -struct videobuf_dvb_frontend *videobuf_dvb_alloc_frontend( - struct videobuf_dvb_frontends *f, int id) -{ - struct videobuf_dvb_frontend *fe; - - fe = kzalloc(sizeof(struct videobuf_dvb_frontend), GFP_KERNEL); - if (fe == NULL) - goto fail_alloc; - - fe->id = id; - mutex_init(&fe->dvb.lock); - - mutex_lock(&f->lock); - list_add_tail(&fe->felist, &f->felist); - mutex_unlock(&f->lock); - -fail_alloc: - return fe; -} -EXPORT_SYMBOL(videobuf_dvb_alloc_frontend); - -void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f) -{ - struct list_head *list, *q; - struct videobuf_dvb_frontend *fe; - - mutex_lock(&f->lock); - list_for_each_safe(list, q, &f->felist) { - fe = list_entry(list, struct videobuf_dvb_frontend, felist); - if (fe->dvb.net.dvbdev) { - dvb_net_release(&fe->dvb.net); - fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, - &fe->dvb.fe_mem); - fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, - &fe->dvb.fe_hw); - dvb_dmxdev_release(&fe->dvb.dmxdev); - dvb_dmx_release(&fe->dvb.demux); - dvb_unregister_frontend(fe->dvb.frontend); - } - if (fe->dvb.frontend) - /* always allocated, may have been reset */ - dvb_frontend_detach(fe->dvb.frontend); - list_del(list); /* remove list entry */ - kfree(fe); /* free frontend allocation */ - } - mutex_unlock(&f->lock); -} -EXPORT_SYMBOL(videobuf_dvb_dealloc_frontends); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-vmalloc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-vmalloc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-vmalloc.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/videobuf-vmalloc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,349 +0,0 @@ -/* - * helper functions for vmalloc video4linux capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab, - * - * 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 - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#define MAGIC_DMABUF 0x17760309 -#define MAGIC_VMAL_MEM 0x18221223 - -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } - -static int debug; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg) - - -/***************************************************************************/ - -static void videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count++; -} - -static void videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count--; - if (0 == map->count) { - struct videobuf_vmalloc_memory *mem; - - dprintk(1, "munmap %p q=%p\n", map, q); - videobuf_queue_lock(q); - - /* We need first to cancel streams, before unmapping */ - if (q->streaming) - videobuf_queue_cancel(q); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - - if (q->bufs[i]->map != map) - continue; - - mem = q->bufs[i]->priv; - if (mem) { - /* This callback is called only if kernel has - allocated memory and this memory is mmapped. - In this case, memory should be freed, - in order to do memory unmap. - */ - - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - /* vfree is not atomic - can't be - called with IRQ's disabled - */ - dprintk(1, "%s: buf[%d] freeing (%p)\n", - __func__, i, mem->vaddr); - - vfree(mem->vaddr); - mem->vaddr = NULL; - } - - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - } - - kfree(map); - - videobuf_queue_unlock(q); - } - - return; -} - -static const struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, -}; - -/* --------------------------------------------------------------------- - * vmalloc handlers for the generic methods - */ - -/* Allocated area consists on 3 parts: - struct video_buffer - struct _buffer (cx88_buffer, saa7134_buf, ...) - struct videobuf_dma_sg_memory - */ - -static struct videobuf_buffer *__videobuf_alloc_vb(size_t size) -{ - struct videobuf_vmalloc_memory *mem; - struct videobuf_buffer *vb; - - vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); - if (!vb) - return vb; - - mem = vb->priv = ((char *)vb) + size; - mem->magic = MAGIC_VMAL_MEM; - - dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n", - __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb), - mem, (long)sizeof(*mem)); - - return vb; -} - -static int __videobuf_iolock(struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - struct videobuf_vmalloc_memory *mem = vb->priv; - int pages; - - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - dprintk(1, "%s memory method MMAP\n", __func__); - - /* All handling should be done by __videobuf_mmap_mapper() */ - if (!mem->vaddr) { - printk(KERN_ERR "memory is not alloced/mmapped.\n"); - return -EINVAL; - } - break; - case V4L2_MEMORY_USERPTR: - pages = PAGE_ALIGN(vb->size); - - dprintk(1, "%s memory method USERPTR\n", __func__); - - if (vb->baddr) { - printk(KERN_ERR "USERPTR is currently not supported\n"); - return -EINVAL; - } - - /* The only USERPTR currently supported is the one needed for - * read() method. - */ - - mem->vaddr = vmalloc_user(pages); - if (!mem->vaddr) { - printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); - return -ENOMEM; - } - dprintk(1, "vmalloc is at addr %p (%d pages)\n", - mem->vaddr, pages); - -#if 0 - int rc; - /* Kernel userptr is used also by read() method. In this case, - there's no need to remap, since data will be copied to user - */ - if (!vb->baddr) - return 0; - - /* FIXME: to properly support USERPTR, remap should occur. - The code below won't work, since mem->vma = NULL - */ - /* Try to remap memory */ - rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); - if (rc < 0) { - printk(KERN_ERR "mmap: remap failed with error %d", rc); - return -ENOMEM; - } -#endif - - break; - case V4L2_MEMORY_OVERLAY: - default: - dprintk(1, "%s memory method OVERLAY/unknown\n", __func__); - - /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ - printk(KERN_ERR "Memory method currently unsupported.\n"); - return -EINVAL; - } - - return 0; -} - -static int __videobuf_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct videobuf_vmalloc_memory *mem; - struct videobuf_mapping *map; - int retval, pages; - - dprintk(1, "%s\n", __func__); - - /* create mapping + update buffer list */ - map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (NULL == map) - return -ENOMEM; - - buf->map = map; - map->q = q; - - buf->baddr = vma->vm_start; - - mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - pages = PAGE_ALIGN(vma->vm_end - vma->vm_start); - mem->vaddr = vmalloc_user(pages); - if (!mem->vaddr) { - printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); - goto error; - } - dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages); - - /* Try to remap memory */ - retval = remap_vmalloc_range(vma, mem->vaddr, 0); - if (retval < 0) { - printk(KERN_ERR "mmap: remap failed with error %d. ", retval); - vfree(mem->vaddr); - goto error; - } - - vma->vm_ops = &videobuf_vm_ops; - vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; - vma->vm_private_data = map; - - dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", - map, q, vma->vm_start, vma->vm_end, - (long int)buf->bsize, - vma->vm_pgoff, buf->i); - - videobuf_vm_open(vma); - - return 0; - -error: - mem = NULL; - kfree(map); - return -ENOMEM; -} - -static struct videobuf_qtype_ops qops = { - .magic = MAGIC_QTYPE_OPS, - - .alloc_vb = __videobuf_alloc_vb, - .iolock = __videobuf_iolock, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = videobuf_to_vmalloc, -}; - -void videobuf_queue_vmalloc_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &qops, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); - -void *videobuf_to_vmalloc(struct videobuf_buffer *buf) -{ - struct videobuf_vmalloc_memory *mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - return mem->vaddr; -} -EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); - -void videobuf_vmalloc_free(struct videobuf_buffer *buf) -{ - struct videobuf_vmalloc_memory *mem = buf->priv; - - /* mmapped memory can't be freed here, otherwise mmapped region - would be released, while still needed. In this case, the memory - release should happen inside videobuf_vm_close(). - So, it should free memory only if the memory were allocated for - read() operation. - */ - if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr) - return; - - if (!mem) - return; - - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - vfree(mem->vaddr); - mem->vaddr = NULL; - - return; -} -EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vino.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vino.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vino.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vino.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,4351 +0,0 @@ -/* - * Driver for the VINO (Video In No Out) system found in SGI Indys. - * - * This file is subject to the terms and conditions of the GNU General Public - * License version 2 as published by the Free Software Foundation. - * - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * Based on the previous version of the driver for 2.4 kernels by: - * Copyright (C) 2003 Ladislav Michl - * - * v4l2_device/v4l2_subdev conversion by: - * Copyright (C) 2009 Hans Verkuil - * - * Note: this conversion is untested! Please contact the linux-media - * mailinglist if you can test this, together with the test results. - */ - -/* - * TODO: - * - remove "mark pages reserved-hacks" from memory allocation code - * and implement fault() - * - check decimation, calculating and reporting image size when - * using decimation - * - implement read(), user mode buffers and overlay (?) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "vino.h" -#include "saa7191.h" -#include "indycam.h" - -/* Uncomment the following line to get lots and lots of (mostly useless) - * debug info. - * Note that the debug output also slows down the driver significantly */ -// #define VINO_DEBUG -// #define VINO_DEBUG_INT - -#define VINO_MODULE_VERSION "0.0.6" -#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 6) - -MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver"); -MODULE_AUTHOR("Mikael Nousiainen "); -MODULE_LICENSE("GPL"); - -#ifdef VINO_DEBUG -#define dprintk(x...) printk("VINO: " x); -#else -#define dprintk(x...) -#endif - -#define VINO_NO_CHANNEL 0 -#define VINO_CHANNEL_A 1 -#define VINO_CHANNEL_B 2 - -#define VINO_PAL_WIDTH 768 -#define VINO_PAL_HEIGHT 576 -#define VINO_NTSC_WIDTH 640 -#define VINO_NTSC_HEIGHT 480 - -#define VINO_MIN_WIDTH 32 -#define VINO_MIN_HEIGHT 32 - -#define VINO_CLIPPING_START_ODD_D1 1 -#define VINO_CLIPPING_START_ODD_PAL 15 -#define VINO_CLIPPING_START_ODD_NTSC 12 - -#define VINO_CLIPPING_START_EVEN_D1 2 -#define VINO_CLIPPING_START_EVEN_PAL 15 -#define VINO_CLIPPING_START_EVEN_NTSC 12 - -#define VINO_INPUT_CHANNEL_COUNT 3 - -/* the number is the index for vino_inputs */ -#define VINO_INPUT_NONE -1 -#define VINO_INPUT_COMPOSITE 0 -#define VINO_INPUT_SVIDEO 1 -#define VINO_INPUT_D1 2 - -#define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE) - -#define VINO_FIFO_THRESHOLD_DEFAULT 16 - -#define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \ - * VINO_PAL_HEIGHT * 4 \ - + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1)) - -#define VINO_FRAMEBUFFER_COUNT_MAX 8 - -#define VINO_FRAMEBUFFER_UNUSED 0 -#define VINO_FRAMEBUFFER_IN_USE 1 -#define VINO_FRAMEBUFFER_READY 2 - -#define VINO_QUEUE_ERROR -1 -#define VINO_QUEUE_MAGIC 0x20050125 - -#define VINO_MEMORY_NONE 0 -#define VINO_MEMORY_MMAP 1 -#define VINO_MEMORY_USERPTR 2 - -#define VINO_DUMMY_DESC_COUNT 4 -#define VINO_DESC_FETCH_DELAY 5 /* microseconds */ - -#define VINO_MAX_FRAME_SKIP_COUNT 128 - -/* the number is the index for vino_data_formats */ -#define VINO_DATA_FMT_NONE -1 -#define VINO_DATA_FMT_GREY 0 -#define VINO_DATA_FMT_RGB332 1 -#define VINO_DATA_FMT_RGB32 2 -#define VINO_DATA_FMT_YUV 3 - -#define VINO_DATA_FMT_COUNT 4 - -/* the number is the index for vino_data_norms */ -#define VINO_DATA_NORM_NONE -1 -#define VINO_DATA_NORM_NTSC 0 -#define VINO_DATA_NORM_PAL 1 -#define VINO_DATA_NORM_SECAM 2 -#define VINO_DATA_NORM_D1 3 - -#define VINO_DATA_NORM_COUNT 4 - -/* I2C controller flags */ -#define SGI_I2C_FORCE_IDLE (0 << 0) -#define SGI_I2C_NOT_IDLE (1 << 0) -#define SGI_I2C_WRITE (0 << 1) -#define SGI_I2C_READ (1 << 1) -#define SGI_I2C_RELEASE_BUS (0 << 2) -#define SGI_I2C_HOLD_BUS (1 << 2) -#define SGI_I2C_XFER_DONE (0 << 4) -#define SGI_I2C_XFER_BUSY (1 << 4) -#define SGI_I2C_ACK (0 << 5) -#define SGI_I2C_NACK (1 << 5) -#define SGI_I2C_BUS_OK (0 << 7) -#define SGI_I2C_BUS_ERR (1 << 7) - -/* Internal data structure definitions */ - -struct vino_input { - char *name; - v4l2_std_id std; -}; - -struct vino_clipping { - unsigned int left, right, top, bottom; -}; - -struct vino_data_format { - /* the description */ - char *description; - /* bytes per pixel */ - unsigned int bpp; - /* V4L2 fourcc code */ - __u32 pixelformat; - /* V4L2 colorspace (duh!) */ - enum v4l2_colorspace colorspace; -}; - -struct vino_data_norm { - char *description; - unsigned int width, height; - struct vino_clipping odd; - struct vino_clipping even; - - v4l2_std_id std; - unsigned int fps_min, fps_max; - __u32 framelines; -}; - -struct vino_descriptor_table { - /* the number of PAGE_SIZE sized pages in the buffer */ - unsigned int page_count; - /* virtual (kmalloc'd) pointers to the actual data - * (in PAGE_SIZE chunks, used with mmap streaming) */ - unsigned long *virtual; - - /* cpu address for the VINO descriptor table - * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ - unsigned long *dma_cpu; - /* dma address for the VINO descriptor table - * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ - dma_addr_t dma; -}; - -struct vino_framebuffer { - /* identifier nubmer */ - unsigned int id; - /* the length of the whole buffer */ - unsigned int size; - /* the length of actual data in buffer */ - unsigned int data_size; - /* the data format */ - unsigned int data_format; - /* the state of buffer data */ - unsigned int state; - /* is the buffer mapped in user space? */ - unsigned int map_count; - /* memory offset for mmap() */ - unsigned int offset; - /* frame counter */ - unsigned int frame_counter; - /* timestamp (written when image capture finishes) */ - struct timeval timestamp; - - struct vino_descriptor_table desc_table; - - spinlock_t state_lock; -}; - -struct vino_framebuffer_fifo { - unsigned int length; - - unsigned int used; - unsigned int head; - unsigned int tail; - - unsigned int data[VINO_FRAMEBUFFER_COUNT_MAX]; -}; - -struct vino_framebuffer_queue { - unsigned int magic; - - /* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */ - unsigned int type; - unsigned int length; - - /* data field of in and out contain index numbers for buffer */ - struct vino_framebuffer_fifo in; - struct vino_framebuffer_fifo out; - - struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX]; - - spinlock_t queue_lock; - struct mutex queue_mutex; - wait_queue_head_t frame_wait_queue; -}; - -struct vino_interrupt_data { - struct timeval timestamp; - unsigned int frame_counter; - unsigned int skip_count; - unsigned int skip; -}; - -struct vino_channel_settings { - unsigned int channel; - - int input; - unsigned int data_format; - unsigned int data_norm; - struct vino_clipping clipping; - unsigned int decimation; - unsigned int line_size; - unsigned int alpha; - unsigned int fps; - unsigned int framert_reg; - - unsigned int fifo_threshold; - - struct vino_framebuffer_queue fb_queue; - - /* number of the current field */ - unsigned int field; - - /* read in progress */ - int reading; - /* streaming is active */ - int streaming; - /* the driver is currently processing the queue */ - int capturing; - - struct mutex mutex; - spinlock_t capture_lock; - - unsigned int users; - - struct vino_interrupt_data int_data; - - /* V4L support */ - struct video_device *vdev; -}; - -struct vino_settings { - struct v4l2_device v4l2_dev; - struct vino_channel_settings a; - struct vino_channel_settings b; - - /* the channel which owns this client: - * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */ - unsigned int decoder_owner; - struct v4l2_subdev *decoder; - unsigned int camera_owner; - struct v4l2_subdev *camera; - - /* a lock for vino register access */ - spinlock_t vino_lock; - /* a lock for channel input changes */ - spinlock_t input_lock; - - unsigned long dummy_page; - struct vino_descriptor_table dummy_desc_table; -}; - -/* Module parameters */ - -/* - * Using vino_pixel_conversion the ABGR32-format pixels supplied - * by the VINO chip can be converted to more common formats - * like RGBA32 (or probably RGB24 in the future). This way we - * can give out data that can be specified correctly with - * the V4L2-definitions. - * - * The pixel format is specified as RGBA32 when no conversion - * is used. - * - * Note that this only affects the 32-bit bit depth. - * - * Use non-zero value to enable conversion. - */ -static int vino_pixel_conversion; - -module_param_named(pixelconv, vino_pixel_conversion, int, 0); - -MODULE_PARM_DESC(pixelconv, - "enable pixel conversion (non-zero value enables)"); - -/* Internal data structures */ - -static struct sgi_vino *vino; - -static struct vino_settings *vino_drvdata; - -#define camera_call(o, f, args...) \ - v4l2_subdev_call(vino_drvdata->camera, o, f, ##args) -#define decoder_call(o, f, args...) \ - v4l2_subdev_call(vino_drvdata->decoder, o, f, ##args) - -static const char *vino_driver_name = "vino"; -static const char *vino_driver_description = "SGI VINO"; -static const char *vino_bus_name = "GIO64 bus"; -static const char *vino_vdev_name_a = "SGI VINO Channel A"; -static const char *vino_vdev_name_b = "SGI VINO Channel B"; - -static void vino_capture_tasklet(unsigned long channel); - -DECLARE_TASKLET(vino_tasklet_a, vino_capture_tasklet, VINO_CHANNEL_A); -DECLARE_TASKLET(vino_tasklet_b, vino_capture_tasklet, VINO_CHANNEL_B); - -static const struct vino_input vino_inputs[] = { - { - .name = "Composite", - .std = V4L2_STD_NTSC | V4L2_STD_PAL - | V4L2_STD_SECAM, - }, { - .name = "S-Video", - .std = V4L2_STD_NTSC | V4L2_STD_PAL - | V4L2_STD_SECAM, - }, { - .name = "D1/IndyCam", - .std = V4L2_STD_NTSC, - } -}; - -static const struct vino_data_format vino_data_formats[] = { - { - .description = "8-bit greyscale", - .bpp = 1, - .pixelformat = V4L2_PIX_FMT_GREY, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - }, { - .description = "8-bit dithered RGB 3-3-2", - .bpp = 1, - .pixelformat = V4L2_PIX_FMT_RGB332, - .colorspace = V4L2_COLORSPACE_SRGB, - }, { - .description = "32-bit RGB", - .bpp = 4, - .pixelformat = V4L2_PIX_FMT_RGB32, - .colorspace = V4L2_COLORSPACE_SRGB, - }, { - .description = "YUV 4:2:2", - .bpp = 2, - .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped? - .colorspace = V4L2_COLORSPACE_SMPTE170M, - } -}; - -static const struct vino_data_norm vino_data_norms[] = { - { - .description = "NTSC", - .std = V4L2_STD_NTSC, - .fps_min = 6, - .fps_max = 30, - .framelines = 525, - .width = VINO_NTSC_WIDTH, - .height = VINO_NTSC_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_NTSC, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_NTSC - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_NTSC, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_NTSC - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - }, { - .description = "PAL", - .std = V4L2_STD_PAL, - .fps_min = 5, - .fps_max = 25, - .framelines = 625, - .width = VINO_PAL_WIDTH, - .height = VINO_PAL_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - }, { - .description = "SECAM", - .std = V4L2_STD_SECAM, - .fps_min = 5, - .fps_max = 25, - .framelines = 625, - .width = VINO_PAL_WIDTH, - .height = VINO_PAL_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - }, { - .description = "NTSC/D1", - .std = V4L2_STD_NTSC, - .fps_min = 6, - .fps_max = 30, - .framelines = 525, - .width = VINO_NTSC_WIDTH, - .height = VINO_NTSC_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_D1, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_D1 - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_D1, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_D1 - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - } -}; - -#define VINO_INDYCAM_V4L2_CONTROL_COUNT 9 - -struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain Control", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = INDYCAM_AGC_DEFAULT, - }, { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic White Balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = INDYCAM_AWB_DEFAULT, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = INDYCAM_GAIN_MIN, - .maximum = INDYCAM_GAIN_MAX, - .step = 1, - .default_value = INDYCAM_GAIN_DEFAULT, - }, { - .id = INDYCAM_CONTROL_RED_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Saturation", - .minimum = INDYCAM_RED_SATURATION_MIN, - .maximum = INDYCAM_RED_SATURATION_MAX, - .step = 1, - .default_value = INDYCAM_RED_SATURATION_DEFAULT, - }, { - .id = INDYCAM_CONTROL_BLUE_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Saturation", - .minimum = INDYCAM_BLUE_SATURATION_MIN, - .maximum = INDYCAM_BLUE_SATURATION_MAX, - .step = 1, - .default_value = INDYCAM_BLUE_SATURATION_DEFAULT, - }, { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = INDYCAM_RED_BALANCE_MIN, - .maximum = INDYCAM_RED_BALANCE_MAX, - .step = 1, - .default_value = INDYCAM_RED_BALANCE_DEFAULT, - }, { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = INDYCAM_BLUE_BALANCE_MIN, - .maximum = INDYCAM_BLUE_BALANCE_MAX, - .step = 1, - .default_value = INDYCAM_BLUE_BALANCE_DEFAULT, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Shutter Control", - .minimum = INDYCAM_SHUTTER_MIN, - .maximum = INDYCAM_SHUTTER_MAX, - .step = 1, - .default_value = INDYCAM_SHUTTER_DEFAULT, - }, { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = INDYCAM_GAMMA_MIN, - .maximum = INDYCAM_GAMMA_MAX, - .step = 1, - .default_value = INDYCAM_GAMMA_DEFAULT, - } -}; - -#define VINO_SAA7191_V4L2_CONTROL_COUNT 9 - -struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = SAA7191_HUE_MIN, - .maximum = SAA7191_HUE_MAX, - .step = 1, - .default_value = SAA7191_HUE_DEFAULT, - }, { - .id = SAA7191_CONTROL_BANDPASS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Luminance Bandpass", - .minimum = SAA7191_BANDPASS_MIN, - .maximum = SAA7191_BANDPASS_MAX, - .step = 1, - .default_value = SAA7191_BANDPASS_DEFAULT, - }, { - .id = SAA7191_CONTROL_BANDPASS_WEIGHT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Luminance Bandpass Weight", - .minimum = SAA7191_BANDPASS_WEIGHT_MIN, - .maximum = SAA7191_BANDPASS_WEIGHT_MAX, - .step = 1, - .default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT, - }, { - .id = SAA7191_CONTROL_CORING, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "HF Luminance Coring", - .minimum = SAA7191_CORING_MIN, - .maximum = SAA7191_CORING_MAX, - .step = 1, - .default_value = SAA7191_CORING_DEFAULT, - }, { - .id = SAA7191_CONTROL_FORCE_COLOUR, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Force Colour", - .minimum = SAA7191_FORCE_COLOUR_MIN, - .maximum = SAA7191_FORCE_COLOUR_MAX, - .step = 1, - .default_value = SAA7191_FORCE_COLOUR_DEFAULT, - }, { - .id = SAA7191_CONTROL_CHROMA_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Chrominance Gain Control", - .minimum = SAA7191_CHROMA_GAIN_MIN, - .maximum = SAA7191_CHROMA_GAIN_MAX, - .step = 1, - .default_value = SAA7191_CHROMA_GAIN_DEFAULT, - }, { - .id = SAA7191_CONTROL_VTRC, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "VTR Time Constant", - .minimum = SAA7191_VTRC_MIN, - .maximum = SAA7191_VTRC_MAX, - .step = 1, - .default_value = SAA7191_VTRC_DEFAULT, - }, { - .id = SAA7191_CONTROL_LUMA_DELAY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Luminance Delay Compensation", - .minimum = SAA7191_LUMA_DELAY_MIN, - .maximum = SAA7191_LUMA_DELAY_MAX, - .step = 1, - .default_value = SAA7191_LUMA_DELAY_DEFAULT, - }, { - .id = SAA7191_CONTROL_VNR, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Vertical Noise Reduction", - .minimum = SAA7191_VNR_MIN, - .maximum = SAA7191_VNR_MAX, - .step = 1, - .default_value = SAA7191_VNR_DEFAULT, - } -}; - -/* VINO framebuffer/DMA descriptor management */ - -static void vino_free_buffer_with_count(struct vino_framebuffer *fb, - unsigned int count) -{ - unsigned int i; - - dprintk("vino_free_buffer_with_count(): count = %d\n", count); - - for (i = 0; i < count; i++) { - ClearPageReserved(virt_to_page((void *)fb->desc_table.virtual[i])); - dma_unmap_single(NULL, - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], - PAGE_SIZE, DMA_FROM_DEVICE); - free_page(fb->desc_table.virtual[i]); - } - - dma_free_coherent(NULL, - VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) * - sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu, - fb->desc_table.dma); - kfree(fb->desc_table.virtual); - - memset(fb, 0, sizeof(struct vino_framebuffer)); -} - -static void vino_free_buffer(struct vino_framebuffer *fb) -{ - vino_free_buffer_with_count(fb, fb->desc_table.page_count); -} - -static int vino_allocate_buffer(struct vino_framebuffer *fb, - unsigned int size) -{ - unsigned int count, i, j; - int ret = 0; - - dprintk("vino_allocate_buffer():\n"); - - if (size < 1) - return -EINVAL; - - memset(fb, 0, sizeof(struct vino_framebuffer)); - - count = ((size / PAGE_SIZE) + 4) & ~3; - - dprintk("vino_allocate_buffer(): size = %d, count = %d\n", - size, count); - - /* allocate memory for table with virtual (page) addresses */ - fb->desc_table.virtual = (unsigned long *) - kmalloc(count * sizeof(unsigned long), GFP_KERNEL); - if (!fb->desc_table.virtual) - return -ENOMEM; - - /* allocate memory for table with dma addresses - * (has space for four extra descriptors) */ - fb->desc_table.dma_cpu = - dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) * - sizeof(dma_addr_t), &fb->desc_table.dma, - GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.dma_cpu) { - ret = -ENOMEM; - goto out_free_virtual; - } - - /* allocate pages for the buffer and acquire the according - * dma addresses */ - for (i = 0; i < count; i++) { - dma_addr_t dma_data_addr; - - fb->desc_table.virtual[i] = - get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.virtual[i]) { - ret = -ENOBUFS; - break; - } - - dma_data_addr = - dma_map_single(NULL, - (void *)fb->desc_table.virtual[i], - PAGE_SIZE, DMA_FROM_DEVICE); - - for (j = 0; j < VINO_PAGE_RATIO; j++) { - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] = - dma_data_addr + VINO_PAGE_SIZE * j; - } - - SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i])); - } - - /* page_count needs to be set anyway, because the descriptor table has - * been allocated according to this number */ - fb->desc_table.page_count = count; - - if (ret) { - /* the descriptor with index i doesn't contain - * a valid address yet */ - vino_free_buffer_with_count(fb, i); - return ret; - } - - //fb->size = size; - fb->size = count * PAGE_SIZE; - fb->data_format = VINO_DATA_FMT_NONE; - - /* set the dma stop-bit for the last (count+1)th descriptor */ - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP; - return 0; - - out_free_virtual: - kfree(fb->desc_table.virtual); - return ret; -} - -#if 0 -/* user buffers not fully implemented yet */ -static int vino_prepare_user_buffer(struct vino_framebuffer *fb, - void *user, - unsigned int size) -{ - unsigned int count, i, j; - int ret = 0; - - dprintk("vino_prepare_user_buffer():\n"); - - if (size < 1) - return -EINVAL; - - memset(fb, 0, sizeof(struct vino_framebuffer)); - - count = ((size / PAGE_SIZE)) & ~3; - - dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n", - size, count); - - /* allocate memory for table with virtual (page) addresses */ - fb->desc_table.virtual = (unsigned long *) - kmalloc(count * sizeof(unsigned long), GFP_KERNEL); - if (!fb->desc_table.virtual) - return -ENOMEM; - - /* allocate memory for table with dma addresses - * (has space for four extra descriptors) */ - fb->desc_table.dma_cpu = - dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) * - sizeof(dma_addr_t), &fb->desc_table.dma, - GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.dma_cpu) { - ret = -ENOMEM; - goto out_free_virtual; - } - - /* allocate pages for the buffer and acquire the according - * dma addresses */ - for (i = 0; i < count; i++) { - dma_addr_t dma_data_addr; - - fb->desc_table.virtual[i] = - get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.virtual[i]) { - ret = -ENOBUFS; - break; - } - - dma_data_addr = - dma_map_single(NULL, - (void *)fb->desc_table.virtual[i], - PAGE_SIZE, DMA_FROM_DEVICE); - - for (j = 0; j < VINO_PAGE_RATIO; j++) { - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] = - dma_data_addr + VINO_PAGE_SIZE * j; - } - - SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i])); - } - - /* page_count needs to be set anyway, because the descriptor table has - * been allocated according to this number */ - fb->desc_table.page_count = count; - - if (ret) { - /* the descriptor with index i doesn't contain - * a valid address yet */ - vino_free_buffer_with_count(fb, i); - return ret; - } - - //fb->size = size; - fb->size = count * PAGE_SIZE; - - /* set the dma stop-bit for the last (count+1)th descriptor */ - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP; - return 0; - - out_free_virtual: - kfree(fb->desc_table.virtual); - return ret; -} -#endif - -static void vino_sync_buffer(struct vino_framebuffer *fb) -{ - int i; - - dprintk("vino_sync_buffer():\n"); - - for (i = 0; i < fb->desc_table.page_count; i++) - dma_sync_single_for_cpu(NULL, - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], - PAGE_SIZE, DMA_FROM_DEVICE); -} - -/* Framebuffer fifo functions (need to be locked externally) */ - -static inline void vino_fifo_init(struct vino_framebuffer_fifo *f, - unsigned int length) -{ - f->length = 0; - f->used = 0; - f->head = 0; - f->tail = 0; - - if (length > VINO_FRAMEBUFFER_COUNT_MAX) - length = VINO_FRAMEBUFFER_COUNT_MAX; - - f->length = length; -} - -/* returns true/false */ -static inline int vino_fifo_has_id(struct vino_framebuffer_fifo *f, - unsigned int id) -{ - unsigned int i; - - for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) { - if (f->data[i] == id) - return 1; - } - - return 0; -} - -#if 0 -/* returns true/false */ -static inline int vino_fifo_full(struct vino_framebuffer_fifo *f) -{ - return (f->used == f->length); -} -#endif - -static inline unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f) -{ - return f->used; -} - -static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id) -{ - if (id >= f->length) { - return VINO_QUEUE_ERROR; - } - - if (vino_fifo_has_id(f, id)) { - return VINO_QUEUE_ERROR; - } - - if (f->used < f->length) { - f->data[f->tail] = id; - f->tail = (f->tail + 1) % f->length; - f->used++; - } else { - return VINO_QUEUE_ERROR; - } - - return 0; -} - -static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id) -{ - if (f->used > 0) { - *id = f->data[f->head]; - } else { - return VINO_QUEUE_ERROR; - } - - return 0; -} - -static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id) -{ - if (f->used > 0) { - *id = f->data[f->head]; - f->head = (f->head + 1) % f->length; - f->used--; - } else { - return VINO_QUEUE_ERROR; - } - - return 0; -} - -/* Framebuffer queue functions */ - -/* execute with queue_lock locked */ -static void vino_queue_free_with_count(struct vino_framebuffer_queue *q, - unsigned int length) -{ - unsigned int i; - - q->length = 0; - memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo)); - memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo)); - for (i = 0; i < length; i++) { - dprintk("vino_queue_free_with_count(): freeing buffer %d\n", - i); - vino_free_buffer(q->buffer[i]); - kfree(q->buffer[i]); - } - - q->type = VINO_MEMORY_NONE; - q->magic = 0; -} - -static void vino_queue_free(struct vino_framebuffer_queue *q) -{ - dprintk("vino_queue_free():\n"); - - if (q->magic != VINO_QUEUE_MAGIC) - return; - if (q->type != VINO_MEMORY_MMAP) - return; - - mutex_lock(&q->queue_mutex); - - vino_queue_free_with_count(q, q->length); - - mutex_unlock(&q->queue_mutex); -} - -static int vino_queue_init(struct vino_framebuffer_queue *q, - unsigned int *length) -{ - unsigned int i; - int ret = 0; - - dprintk("vino_queue_init(): length = %d\n", *length); - - if (q->magic == VINO_QUEUE_MAGIC) { - dprintk("vino_queue_init(): queue already initialized!\n"); - return -EINVAL; - } - - if (q->type != VINO_MEMORY_NONE) { - dprintk("vino_queue_init(): queue already initialized!\n"); - return -EINVAL; - } - - if (*length < 1) - return -EINVAL; - - mutex_lock(&q->queue_mutex); - - if (*length > VINO_FRAMEBUFFER_COUNT_MAX) - *length = VINO_FRAMEBUFFER_COUNT_MAX; - - q->length = 0; - - for (i = 0; i < *length; i++) { - dprintk("vino_queue_init(): allocating buffer %d\n", i); - q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer), - GFP_KERNEL); - if (!q->buffer[i]) { - dprintk("vino_queue_init(): kmalloc() failed\n"); - ret = -ENOMEM; - break; - } - - ret = vino_allocate_buffer(q->buffer[i], - VINO_FRAMEBUFFER_SIZE); - if (ret) { - kfree(q->buffer[i]); - dprintk("vino_queue_init(): " - "vino_allocate_buffer() failed\n"); - break; - } - - q->buffer[i]->id = i; - if (i > 0) { - q->buffer[i]->offset = q->buffer[i - 1]->offset + - q->buffer[i - 1]->size; - } else { - q->buffer[i]->offset = 0; - } - - spin_lock_init(&q->buffer[i]->state_lock); - - dprintk("vino_queue_init(): buffer = %d, offset = %d, " - "size = %d\n", i, q->buffer[i]->offset, - q->buffer[i]->size); - } - - if (ret) { - vino_queue_free_with_count(q, i); - *length = 0; - } else { - q->length = *length; - vino_fifo_init(&q->in, q->length); - vino_fifo_init(&q->out, q->length); - q->type = VINO_MEMORY_MMAP; - q->magic = VINO_QUEUE_MAGIC; - } - - mutex_unlock(&q->queue_mutex); - - return ret; -} - -static struct vino_framebuffer *vino_queue_add(struct - vino_framebuffer_queue *q, - unsigned int id) -{ - struct vino_framebuffer *ret = NULL; - unsigned int total; - unsigned long flags; - - dprintk("vino_queue_add(): id = %d\n", id); - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - if (id >= q->length) - goto out; - - /* not needed?: if (vino_fifo_full(&q->out)) { - goto out; - }*/ - /* check that outgoing queue isn't already full - * (or that it won't become full) */ - total = vino_fifo_get_used(&q->in) + - vino_fifo_get_used(&q->out); - if (total >= q->length) - goto out; - - if (vino_fifo_enqueue(&q->in, id)) - goto out; - - ret = q->buffer[id]; - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static struct vino_framebuffer *vino_queue_transfer(struct - vino_framebuffer_queue *q) -{ - struct vino_framebuffer *ret = NULL; - struct vino_framebuffer *fb; - int id; - unsigned long flags; - - dprintk("vino_queue_transfer():\n"); - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - // now this actually removes an entry from the incoming queue - if (vino_fifo_dequeue(&q->in, &id)) { - goto out; - } - - dprintk("vino_queue_transfer(): id = %d\n", id); - fb = q->buffer[id]; - - // we have already checked that the outgoing queue is not full, but... - if (vino_fifo_enqueue(&q->out, id)) { - printk(KERN_ERR "vino_queue_transfer(): " - "outgoing queue is full, this shouldn't happen!\n"); - goto out; - } - - ret = fb; -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -/* returns true/false */ -static int vino_queue_incoming_contains(struct vino_framebuffer_queue *q, - unsigned int id) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - ret = vino_fifo_has_id(&q->in, id); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -/* returns true/false */ -static int vino_queue_outgoing_contains(struct vino_framebuffer_queue *q, - unsigned int id) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - ret = vino_fifo_has_id(&q->out, id); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static int vino_queue_get_incoming(struct vino_framebuffer_queue *q, - unsigned int *used) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return VINO_QUEUE_ERROR; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) { - ret = VINO_QUEUE_ERROR; - goto out; - } - - *used = vino_fifo_get_used(&q->in); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q, - unsigned int *used) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return VINO_QUEUE_ERROR; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) { - ret = VINO_QUEUE_ERROR; - goto out; - } - - *used = vino_fifo_get_used(&q->out); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -#if 0 -static int vino_queue_get_total(struct vino_framebuffer_queue *q, - unsigned int *total) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return VINO_QUEUE_ERROR; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) { - ret = VINO_QUEUE_ERROR; - goto out; - } - - *total = vino_fifo_get_used(&q->in) + - vino_fifo_get_used(&q->out); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} -#endif - -static struct vino_framebuffer *vino_queue_peek(struct - vino_framebuffer_queue *q, - unsigned int *id) -{ - struct vino_framebuffer *ret = NULL; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - if (vino_fifo_peek(&q->in, id)) { - goto out; - } - - ret = q->buffer[*id]; -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static struct vino_framebuffer *vino_queue_remove(struct - vino_framebuffer_queue *q, - unsigned int *id) -{ - struct vino_framebuffer *ret = NULL; - unsigned long flags; - dprintk("vino_queue_remove():\n"); - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - if (vino_fifo_dequeue(&q->out, id)) { - goto out; - } - - dprintk("vino_queue_remove(): id = %d\n", *id); - ret = q->buffer[*id]; -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static struct -vino_framebuffer *vino_queue_get_buffer(struct vino_framebuffer_queue *q, - unsigned int id) -{ - struct vino_framebuffer *ret = NULL; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - if (id >= q->length) - goto out; - - ret = q->buffer[id]; - out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static unsigned int vino_queue_get_length(struct vino_framebuffer_queue *q) -{ - unsigned int length = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return length; - } - - spin_lock_irqsave(&q->queue_lock, flags); - length = q->length; - spin_unlock_irqrestore(&q->queue_lock, flags); - - return length; -} - -static int vino_queue_has_mapped_buffers(struct vino_framebuffer_queue *q) -{ - unsigned int i; - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - for (i = 0; i < q->length; i++) { - if (q->buffer[i]->map_count > 0) { - ret = 1; - break; - } - } - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -/* VINO functions */ - -/* execute with input_lock locked */ -static void vino_update_line_size(struct vino_channel_settings *vcs) -{ - unsigned int w = vcs->clipping.right - vcs->clipping.left; - unsigned int d = vcs->decimation; - unsigned int bpp = vino_data_formats[vcs->data_format].bpp; - unsigned int lsize; - - dprintk("update_line_size(): before: w = %d, d = %d, " - "line_size = %d\n", w, d, vcs->line_size); - - /* line size must be multiple of 8 bytes */ - lsize = (bpp * (w / d)) & ~7; - w = (lsize / bpp) * d; - - vcs->clipping.right = vcs->clipping.left + w; - vcs->line_size = lsize; - - dprintk("update_line_size(): after: w = %d, d = %d, " - "line_size = %d\n", w, d, vcs->line_size); -} - -/* execute with input_lock locked */ -static void vino_set_clipping(struct vino_channel_settings *vcs, - unsigned int x, unsigned int y, - unsigned int w, unsigned int h) -{ - unsigned int maxwidth, maxheight; - unsigned int d; - - maxwidth = vino_data_norms[vcs->data_norm].width; - maxheight = vino_data_norms[vcs->data_norm].height; - d = vcs->decimation; - - y &= ~1; /* odd/even fields */ - - if (x > maxwidth) { - x = 0; - } - if (y > maxheight) { - y = 0; - } - - if (((w / d) < VINO_MIN_WIDTH) - || ((h / d) < VINO_MIN_HEIGHT)) { - w = VINO_MIN_WIDTH * d; - h = VINO_MIN_HEIGHT * d; - } - - if ((x + w) > maxwidth) { - w = maxwidth - x; - if ((w / d) < VINO_MIN_WIDTH) - x = maxwidth - VINO_MIN_WIDTH * d; - } - if ((y + h) > maxheight) { - h = maxheight - y; - if ((h / d) < VINO_MIN_HEIGHT) - y = maxheight - VINO_MIN_HEIGHT * d; - } - - vcs->clipping.left = x; - vcs->clipping.top = y; - vcs->clipping.right = x + w; - vcs->clipping.bottom = y + h; - - vino_update_line_size(vcs); - - dprintk("clipping %d, %d, %d, %d / %d - %d\n", - vcs->clipping.left, vcs->clipping.top, vcs->clipping.right, - vcs->clipping.bottom, vcs->decimation, vcs->line_size); -} - -/* execute with input_lock locked */ -static inline void vino_set_default_clipping(struct vino_channel_settings *vcs) -{ - vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width, - vino_data_norms[vcs->data_norm].height); -} - -/* execute with input_lock locked */ -static void vino_set_scaling(struct vino_channel_settings *vcs, - unsigned int w, unsigned int h) -{ - unsigned int x, y, curw, curh, d; - - x = vcs->clipping.left; - y = vcs->clipping.top; - curw = vcs->clipping.right - vcs->clipping.left; - curh = vcs->clipping.bottom - vcs->clipping.top; - - d = max(curw / w, curh / h); - - dprintk("scaling w: %d, h: %d, curw: %d, curh: %d, d: %d\n", - w, h, curw, curh, d); - - if (d < 1) { - d = 1; - } else if (d > 8) { - d = 8; - } - - vcs->decimation = d; - vino_set_clipping(vcs, x, y, w * d, h * d); - - dprintk("scaling %d, %d, %d, %d / %d - %d\n", vcs->clipping.left, - vcs->clipping.top, vcs->clipping.right, vcs->clipping.bottom, - vcs->decimation, vcs->line_size); -} - -/* execute with input_lock locked */ -static inline void vino_set_default_scaling(struct vino_channel_settings *vcs) -{ - vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left, - vcs->clipping.bottom - vcs->clipping.top); -} - -/* execute with input_lock locked */ -static void vino_set_framerate(struct vino_channel_settings *vcs, - unsigned int fps) -{ - unsigned int mask; - - switch (vcs->data_norm) { - case VINO_DATA_NORM_NTSC: - case VINO_DATA_NORM_D1: - fps = (unsigned int)(fps / 6) * 6; // FIXME: round! - - if (fps < vino_data_norms[vcs->data_norm].fps_min) - fps = vino_data_norms[vcs->data_norm].fps_min; - if (fps > vino_data_norms[vcs->data_norm].fps_max) - fps = vino_data_norms[vcs->data_norm].fps_max; - - switch (fps) { - case 6: - mask = 0x003; - break; - case 12: - mask = 0x0c3; - break; - case 18: - mask = 0x333; - break; - case 24: - mask = 0x3ff; - break; - case 30: - mask = 0xfff; - break; - default: - mask = VINO_FRAMERT_FULL; - } - vcs->framert_reg = VINO_FRAMERT_RT(mask); - break; - case VINO_DATA_NORM_PAL: - case VINO_DATA_NORM_SECAM: - fps = (unsigned int)(fps / 5) * 5; // FIXME: round! - - if (fps < vino_data_norms[vcs->data_norm].fps_min) - fps = vino_data_norms[vcs->data_norm].fps_min; - if (fps > vino_data_norms[vcs->data_norm].fps_max) - fps = vino_data_norms[vcs->data_norm].fps_max; - - switch (fps) { - case 5: - mask = 0x003; - break; - case 10: - mask = 0x0c3; - break; - case 15: - mask = 0x333; - break; - case 20: - mask = 0x0ff; - break; - case 25: - mask = 0x3ff; - break; - default: - mask = VINO_FRAMERT_FULL; - } - vcs->framert_reg = VINO_FRAMERT_RT(mask) | VINO_FRAMERT_PAL; - break; - } - - vcs->fps = fps; -} - -/* execute with input_lock locked */ -static inline void vino_set_default_framerate(struct - vino_channel_settings *vcs) -{ - vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max); -} - -/* VINO I2C bus functions */ - -struct i2c_algo_sgi_data { - void *data; /* private data for lowlevel routines */ - unsigned (*getctrl)(void *data); - void (*setctrl)(void *data, unsigned val); - unsigned (*rdata)(void *data); - void (*wdata)(void *data, unsigned val); - - int xfer_timeout; - int ack_timeout; -}; - -static int wait_xfer_done(struct i2c_algo_sgi_data *adap) -{ - int i; - - for (i = 0; i < adap->xfer_timeout; i++) { - if ((adap->getctrl(adap->data) & SGI_I2C_XFER_BUSY) == 0) - return 0; - udelay(1); - } - - return -ETIMEDOUT; -} - -static int wait_ack(struct i2c_algo_sgi_data *adap) -{ - int i; - - if (wait_xfer_done(adap)) - return -ETIMEDOUT; - for (i = 0; i < adap->ack_timeout; i++) { - if ((adap->getctrl(adap->data) & SGI_I2C_NACK) == 0) - return 0; - udelay(1); - } - - return -ETIMEDOUT; -} - -static int force_idle(struct i2c_algo_sgi_data *adap) -{ - int i; - - adap->setctrl(adap->data, SGI_I2C_FORCE_IDLE); - for (i = 0; i < adap->xfer_timeout; i++) { - if ((adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) == 0) - goto out; - udelay(1); - } - return -ETIMEDOUT; -out: - if (adap->getctrl(adap->data) & SGI_I2C_BUS_ERR) - return -EIO; - return 0; -} - -static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr, - int rd) -{ - if (rd) - adap->setctrl(adap->data, SGI_I2C_NOT_IDLE); - /* Check if bus is idle, eventually force it to do so */ - if (adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) - if (force_idle(adap)) - return -EIO; - /* Write out the i2c chip address and specify operation */ - adap->setctrl(adap->data, - SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE); - if (rd) - addr |= 1; - adap->wdata(adap->data, addr); - if (wait_ack(adap)) - return -EIO; - return 0; -} - -static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf, - unsigned int len) -{ - int i; - - adap->setctrl(adap->data, - SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE); - for (i = 0; i < len; i++) { - if (wait_xfer_done(adap)) - return -EIO; - buf[i] = adap->rdata(adap->data); - } - adap->setctrl(adap->data, SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE); - - return 0; - -} - -static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf, - unsigned int len) -{ - int i; - - /* We are already in write state */ - for (i = 0; i < len; i++) { - adap->wdata(adap->data, buf[i]); - if (wait_ack(adap)) - return -EIO; - } - return 0; -} - -static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, - int num) -{ - struct i2c_algo_sgi_data *adap = i2c_adap->algo_data; - struct i2c_msg *p; - int i, err = 0; - - for (i = 0; !err && i < num; i++) { - p = &msgs[i]; - err = do_address(adap, p->addr, p->flags & I2C_M_RD); - if (err || !p->len) - continue; - if (p->flags & I2C_M_RD) - err = i2c_read(adap, p->buf, p->len); - else - err = i2c_write(adap, p->buf, p->len); - } - - return (err < 0) ? err : i; -} - -static u32 sgi_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm sgi_algo = { - .master_xfer = sgi_xfer, - .functionality = sgi_func, -}; - -static unsigned i2c_vino_getctrl(void *data) -{ - return vino->i2c_control; -} - -static void i2c_vino_setctrl(void *data, unsigned val) -{ - vino->i2c_control = val; -} - -static unsigned i2c_vino_rdata(void *data) -{ - return vino->i2c_data; -} - -static void i2c_vino_wdata(void *data, unsigned val) -{ - vino->i2c_data = val; -} - -static struct i2c_algo_sgi_data i2c_sgi_vino_data = { - .getctrl = &i2c_vino_getctrl, - .setctrl = &i2c_vino_setctrl, - .rdata = &i2c_vino_rdata, - .wdata = &i2c_vino_wdata, - .xfer_timeout = 200, - .ack_timeout = 1000, -}; - -static struct i2c_adapter vino_i2c_adapter = { - .name = "VINO I2C bus", - .algo = &sgi_algo, - .algo_data = &i2c_sgi_vino_data, - .owner = THIS_MODULE, -}; - -/* - * Prepare VINO for DMA transfer... - * (execute only with vino_lock and input_lock locked) - */ -static int vino_dma_setup(struct vino_channel_settings *vcs, - struct vino_framebuffer *fb) -{ - u32 ctrl, intr; - struct sgi_vino_channel *ch; - const struct vino_data_norm *norm; - - dprintk("vino_dma_setup():\n"); - - vcs->field = 0; - fb->frame_counter = 0; - - ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b; - norm = &vino_data_norms[vcs->data_norm]; - - ch->page_index = 0; - ch->line_count = 0; - - /* VINO line size register is set 8 bytes less than actual */ - ch->line_size = vcs->line_size - 8; - - /* let VINO know where to transfer data */ - ch->start_desc_tbl = fb->desc_table.dma; - ch->next_4_desc = fb->desc_table.dma; - - /* give vino time to fetch the first four descriptors, 5 usec - * should be more than enough time */ - udelay(VINO_DESC_FETCH_DELAY); - - dprintk("vino_dma_setup(): start desc = %08x, next 4 desc = %08x\n", - ch->start_desc_tbl, ch->next_4_desc); - - /* set the alpha register */ - ch->alpha = vcs->alpha; - - /* set clipping registers */ - ch->clip_start = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.top / 2) | - VINO_CLIP_EVEN(norm->even.top + - vcs->clipping.top / 2) | - VINO_CLIP_X(vcs->clipping.left); - ch->clip_end = VINO_CLIP_ODD(norm->odd.top + - vcs->clipping.bottom / 2 - 1) | - VINO_CLIP_EVEN(norm->even.top + - vcs->clipping.bottom / 2 - 1) | - VINO_CLIP_X(vcs->clipping.right); - - /* set the size of actual content in the buffer (DECIMATION !) */ - fb->data_size = ((vcs->clipping.right - vcs->clipping.left) / - vcs->decimation) * - ((vcs->clipping.bottom - vcs->clipping.top) / - vcs->decimation) * - vino_data_formats[vcs->data_format].bpp; - - ch->frame_rate = vcs->framert_reg; - - ctrl = vino->control; - intr = vino->intr_status; - - if (vcs->channel == VINO_CHANNEL_A) { - /* All interrupt conditions for this channel was cleared - * so clear the interrupt status register and enable - * interrupts */ - intr &= ~VINO_INTSTAT_A; - ctrl |= VINO_CTRL_A_INT; - - /* enable synchronization */ - ctrl |= VINO_CTRL_A_SYNC_ENBL; - - /* enable frame assembly */ - ctrl |= VINO_CTRL_A_INTERLEAVE_ENBL; - - /* set decimation used */ - if (vcs->decimation < 2) - ctrl &= ~VINO_CTRL_A_DEC_ENBL; - else { - ctrl |= VINO_CTRL_A_DEC_ENBL; - ctrl &= ~VINO_CTRL_A_DEC_SCALE_MASK; - ctrl |= (vcs->decimation - 1) << - VINO_CTRL_A_DEC_SCALE_SHIFT; - } - - /* select input interface */ - if (vcs->input == VINO_INPUT_D1) - ctrl |= VINO_CTRL_A_SELECT; - else - ctrl &= ~VINO_CTRL_A_SELECT; - - /* palette */ - ctrl &= ~(VINO_CTRL_A_LUMA_ONLY | VINO_CTRL_A_RGB | - VINO_CTRL_A_DITHER); - } else { - intr &= ~VINO_INTSTAT_B; - ctrl |= VINO_CTRL_B_INT; - - ctrl |= VINO_CTRL_B_SYNC_ENBL; - ctrl |= VINO_CTRL_B_INTERLEAVE_ENBL; - - if (vcs->decimation < 2) - ctrl &= ~VINO_CTRL_B_DEC_ENBL; - else { - ctrl |= VINO_CTRL_B_DEC_ENBL; - ctrl &= ~VINO_CTRL_B_DEC_SCALE_MASK; - ctrl |= (vcs->decimation - 1) << - VINO_CTRL_B_DEC_SCALE_SHIFT; - - } - if (vcs->input == VINO_INPUT_D1) - ctrl |= VINO_CTRL_B_SELECT; - else - ctrl &= ~VINO_CTRL_B_SELECT; - - ctrl &= ~(VINO_CTRL_B_LUMA_ONLY | VINO_CTRL_B_RGB | - VINO_CTRL_B_DITHER); - } - - /* set palette */ - fb->data_format = vcs->data_format; - - switch (vcs->data_format) { - case VINO_DATA_FMT_GREY: - ctrl |= (vcs->channel == VINO_CHANNEL_A) ? - VINO_CTRL_A_LUMA_ONLY : VINO_CTRL_B_LUMA_ONLY; - break; - case VINO_DATA_FMT_RGB32: - ctrl |= (vcs->channel == VINO_CHANNEL_A) ? - VINO_CTRL_A_RGB : VINO_CTRL_B_RGB; - break; - case VINO_DATA_FMT_YUV: - /* nothing needs to be done */ - break; - case VINO_DATA_FMT_RGB332: - ctrl |= (vcs->channel == VINO_CHANNEL_A) ? - VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER : - VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER; - break; - } - - vino->intr_status = intr; - vino->control = ctrl; - - return 0; -} - -/* (execute only with vino_lock locked) */ -static inline void vino_dma_start(struct vino_channel_settings *vcs) -{ - u32 ctrl = vino->control; - - dprintk("vino_dma_start():\n"); - ctrl |= (vcs->channel == VINO_CHANNEL_A) ? - VINO_CTRL_A_DMA_ENBL : VINO_CTRL_B_DMA_ENBL; - vino->control = ctrl; -} - -/* (execute only with vino_lock locked) */ -static inline void vino_dma_stop(struct vino_channel_settings *vcs) -{ - u32 ctrl = vino->control; - - ctrl &= (vcs->channel == VINO_CHANNEL_A) ? - ~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL; - ctrl &= (vcs->channel == VINO_CHANNEL_A) ? - ~VINO_CTRL_A_INT : ~VINO_CTRL_B_INT; - vino->control = ctrl; - dprintk("vino_dma_stop():\n"); -} - -/* - * Load dummy page to descriptor registers. This prevents generating of - * spurious interrupts. (execute only with vino_lock locked) - */ -static void vino_clear_interrupt(struct vino_channel_settings *vcs) -{ - struct sgi_vino_channel *ch; - - ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b; - - ch->page_index = 0; - ch->line_count = 0; - - ch->start_desc_tbl = vino_drvdata->dummy_desc_table.dma; - ch->next_4_desc = vino_drvdata->dummy_desc_table.dma; - - udelay(VINO_DESC_FETCH_DELAY); - dprintk("channel %c clear interrupt condition\n", - (vcs->channel == VINO_CHANNEL_A) ? 'A':'B'); -} - -static int vino_capture(struct vino_channel_settings *vcs, - struct vino_framebuffer *fb) -{ - int err = 0; - unsigned long flags, flags2; - - spin_lock_irqsave(&fb->state_lock, flags); - - if (fb->state == VINO_FRAMEBUFFER_IN_USE) - err = -EBUSY; - fb->state = VINO_FRAMEBUFFER_IN_USE; - - spin_unlock_irqrestore(&fb->state_lock, flags); - - if (err) - return err; - - spin_lock_irqsave(&vino_drvdata->vino_lock, flags); - spin_lock_irqsave(&vino_drvdata->input_lock, flags2); - - vino_dma_setup(vcs, fb); - vino_dma_start(vcs); - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags2); - spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); - - return err; -} - -static -struct vino_framebuffer *vino_capture_enqueue(struct - vino_channel_settings *vcs, - unsigned int index) -{ - struct vino_framebuffer *fb; - unsigned long flags; - - dprintk("vino_capture_enqueue():\n"); - - spin_lock_irqsave(&vcs->capture_lock, flags); - - fb = vino_queue_add(&vcs->fb_queue, index); - if (fb == NULL) { - dprintk("vino_capture_enqueue(): vino_queue_add() failed, " - "queue full?\n"); - goto out; - } -out: - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - return fb; -} - -static int vino_capture_next(struct vino_channel_settings *vcs, int start) -{ - struct vino_framebuffer *fb; - unsigned int incoming, id; - int err = 0; - unsigned long flags; - - dprintk("vino_capture_next():\n"); - - spin_lock_irqsave(&vcs->capture_lock, flags); - - if (start) { - /* start capture only if capture isn't in progress already */ - if (vcs->capturing) { - spin_unlock_irqrestore(&vcs->capture_lock, flags); - return 0; - } - - } else { - /* capture next frame: - * stop capture if capturing is not set */ - if (!vcs->capturing) { - spin_unlock_irqrestore(&vcs->capture_lock, flags); - return 0; - } - } - - err = vino_queue_get_incoming(&vcs->fb_queue, &incoming); - if (err) { - dprintk("vino_capture_next(): vino_queue_get_incoming() " - "failed\n"); - err = -EINVAL; - goto out; - } - if (incoming == 0) { - dprintk("vino_capture_next(): no buffers available\n"); - goto out; - } - - fb = vino_queue_peek(&vcs->fb_queue, &id); - if (fb == NULL) { - dprintk("vino_capture_next(): vino_queue_peek() failed\n"); - err = -EINVAL; - goto out; - } - - if (start) { - vcs->capturing = 1; - } - - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - err = vino_capture(vcs, fb); - - return err; - -out: - vcs->capturing = 0; - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - return err; -} - -static inline int vino_is_capturing(struct vino_channel_settings *vcs) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&vcs->capture_lock, flags); - - ret = vcs->capturing; - - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - return ret; -} - -/* waits until a frame is captured */ -static int vino_wait_for_frame(struct vino_channel_settings *vcs) -{ - wait_queue_t wait; - int err = 0; - - dprintk("vino_wait_for_frame():\n"); - - init_waitqueue_entry(&wait, current); - /* add ourselves into wait queue */ - add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait); - - /* to ensure that schedule_timeout will return immediately - * if VINO interrupt was triggered meanwhile */ - schedule_timeout_interruptible(msecs_to_jiffies(100)); - - if (signal_pending(current)) - err = -EINTR; - - remove_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait); - - dprintk("vino_wait_for_frame(): waiting for frame %s\n", - err ? "failed" : "ok"); - - return err; -} - -/* the function assumes that PAGE_SIZE % 4 == 0 */ -static void vino_convert_to_rgba(struct vino_framebuffer *fb) { - unsigned char *pageptr; - unsigned int page, i; - unsigned char a; - - for (page = 0; page < fb->desc_table.page_count; page++) { - pageptr = (unsigned char *)fb->desc_table.virtual[page]; - - for (i = 0; i < PAGE_SIZE; i += 4) { - a = pageptr[0]; - pageptr[0] = pageptr[3]; - pageptr[1] = pageptr[2]; - pageptr[2] = pageptr[1]; - pageptr[3] = a; - pageptr += 4; - } - } -} - -/* checks if the buffer is in correct state and syncs data */ -static int vino_check_buffer(struct vino_channel_settings *vcs, - struct vino_framebuffer *fb) -{ - int err = 0; - unsigned long flags; - - dprintk("vino_check_buffer():\n"); - - spin_lock_irqsave(&fb->state_lock, flags); - switch (fb->state) { - case VINO_FRAMEBUFFER_IN_USE: - err = -EIO; - break; - case VINO_FRAMEBUFFER_READY: - vino_sync_buffer(fb); - fb->state = VINO_FRAMEBUFFER_UNUSED; - break; - default: - err = -EINVAL; - } - spin_unlock_irqrestore(&fb->state_lock, flags); - - if (!err) { - if (vino_pixel_conversion - && (fb->data_format == VINO_DATA_FMT_RGB32)) { - vino_convert_to_rgba(fb); - } - } else if (err && (err != -EINVAL)) { - dprintk("vino_check_buffer(): buffer not ready\n"); - - spin_lock_irqsave(&vino_drvdata->vino_lock, flags); - vino_dma_stop(vcs); - vino_clear_interrupt(vcs); - spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); - } - - return err; -} - -/* forcefully terminates capture */ -static void vino_capture_stop(struct vino_channel_settings *vcs) -{ - unsigned int incoming = 0, outgoing = 0, id; - unsigned long flags, flags2; - - dprintk("vino_capture_stop():\n"); - - spin_lock_irqsave(&vcs->capture_lock, flags); - - /* unset capturing to stop queue processing */ - vcs->capturing = 0; - - spin_lock_irqsave(&vino_drvdata->vino_lock, flags2); - - vino_dma_stop(vcs); - vino_clear_interrupt(vcs); - - spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags2); - - /* remove all items from the queue */ - if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) { - dprintk("vino_capture_stop(): " - "vino_queue_get_incoming() failed\n"); - goto out; - } - while (incoming > 0) { - vino_queue_transfer(&vcs->fb_queue); - - if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) { - dprintk("vino_capture_stop(): " - "vino_queue_get_incoming() failed\n"); - goto out; - } - } - - if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { - dprintk("vino_capture_stop(): " - "vino_queue_get_outgoing() failed\n"); - goto out; - } - while (outgoing > 0) { - vino_queue_remove(&vcs->fb_queue, &id); - - if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { - dprintk("vino_capture_stop(): " - "vino_queue_get_outgoing() failed\n"); - goto out; - } - } - -out: - spin_unlock_irqrestore(&vcs->capture_lock, flags); -} - -#if 0 -static int vino_capture_failed(struct vino_channel_settings *vcs) -{ - struct vino_framebuffer *fb; - unsigned long flags; - unsigned int i; - int ret; - - dprintk("vino_capture_failed():\n"); - - spin_lock_irqsave(&vino_drvdata->vino_lock, flags); - - vino_dma_stop(vcs); - vino_clear_interrupt(vcs); - - spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); - - ret = vino_queue_get_incoming(&vcs->fb_queue, &i); - if (ret == VINO_QUEUE_ERROR) { - dprintk("vino_queue_get_incoming() failed\n"); - return -EINVAL; - } - if (i == 0) { - /* no buffers to process */ - return 0; - } - - fb = vino_queue_peek(&vcs->fb_queue, &i); - if (fb == NULL) { - dprintk("vino_queue_peek() failed\n"); - return -EINVAL; - } - - spin_lock_irqsave(&fb->state_lock, flags); - if (fb->state == VINO_FRAMEBUFFER_IN_USE) { - fb->state = VINO_FRAMEBUFFER_UNUSED; - vino_queue_transfer(&vcs->fb_queue); - vino_queue_remove(&vcs->fb_queue, &i); - /* we should actually discard the newest frame, - * but who cares ... */ - } - spin_unlock_irqrestore(&fb->state_lock, flags); - - return 0; -} -#endif - -static void vino_skip_frame(struct vino_channel_settings *vcs) -{ - struct vino_framebuffer *fb; - unsigned long flags; - unsigned int id; - - spin_lock_irqsave(&vcs->capture_lock, flags); - fb = vino_queue_peek(&vcs->fb_queue, &id); - if (!fb) { - spin_unlock_irqrestore(&vcs->capture_lock, flags); - dprintk("vino_skip_frame(): vino_queue_peek() failed!\n"); - return; - } - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - spin_lock_irqsave(&fb->state_lock, flags); - fb->state = VINO_FRAMEBUFFER_UNUSED; - spin_unlock_irqrestore(&fb->state_lock, flags); - - vino_capture_next(vcs, 0); -} - -static void vino_frame_done(struct vino_channel_settings *vcs) -{ - struct vino_framebuffer *fb; - unsigned long flags; - - spin_lock_irqsave(&vcs->capture_lock, flags); - fb = vino_queue_transfer(&vcs->fb_queue); - if (!fb) { - spin_unlock_irqrestore(&vcs->capture_lock, flags); - dprintk("vino_frame_done(): vino_queue_transfer() failed!\n"); - return; - } - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - fb->frame_counter = vcs->int_data.frame_counter; - memcpy(&fb->timestamp, &vcs->int_data.timestamp, - sizeof(struct timeval)); - - spin_lock_irqsave(&fb->state_lock, flags); - if (fb->state == VINO_FRAMEBUFFER_IN_USE) - fb->state = VINO_FRAMEBUFFER_READY; - spin_unlock_irqrestore(&fb->state_lock, flags); - - wake_up(&vcs->fb_queue.frame_wait_queue); - - vino_capture_next(vcs, 0); -} - -static void vino_capture_tasklet(unsigned long channel) { - struct vino_channel_settings *vcs; - - vcs = (channel == VINO_CHANNEL_A) - ? &vino_drvdata->a : &vino_drvdata->b; - - if (vcs->int_data.skip) - vcs->int_data.skip_count++; - - if (vcs->int_data.skip && (vcs->int_data.skip_count - <= VINO_MAX_FRAME_SKIP_COUNT)) { - vino_skip_frame(vcs); - } else { - vcs->int_data.skip_count = 0; - vino_frame_done(vcs); - } -} - -static irqreturn_t vino_interrupt(int irq, void *dev_id) -{ - u32 ctrl, intr; - unsigned int fc_a, fc_b; - int handled_a = 0, skip_a = 0, done_a = 0; - int handled_b = 0, skip_b = 0, done_b = 0; - -#ifdef VINO_DEBUG_INT - int loop = 0; - unsigned int line_count = vino->a.line_count, - page_index = vino->a.page_index, - field_counter = vino->a.field_counter, - start_desc_tbl = vino->a.start_desc_tbl, - next_4_desc = vino->a.next_4_desc; - unsigned int line_count_2, - page_index_2, - field_counter_2, - start_desc_tbl_2, - next_4_desc_2; -#endif - - spin_lock(&vino_drvdata->vino_lock); - - while ((intr = vino->intr_status)) { - fc_a = vino->a.field_counter >> 1; - fc_b = vino->b.field_counter >> 1; - - /* handle error-interrupts in some special way ? - * --> skips frames */ - if (intr & VINO_INTSTAT_A) { - if (intr & VINO_INTSTAT_A_EOF) { - vino_drvdata->a.field++; - if (vino_drvdata->a.field > 1) { - vino_dma_stop(&vino_drvdata->a); - vino_clear_interrupt(&vino_drvdata->a); - vino_drvdata->a.field = 0; - done_a = 1; - } else { - if (vino->a.page_index - != vino_drvdata->a.line_size) { - vino->a.line_count = 0; - vino->a.page_index = - vino_drvdata-> - a.line_size; - vino->a.next_4_desc = - vino->a.start_desc_tbl; - } - } - dprintk("channel A end-of-field " - "interrupt: %04x\n", intr); - } else { - vino_dma_stop(&vino_drvdata->a); - vino_clear_interrupt(&vino_drvdata->a); - vino_drvdata->a.field = 0; - skip_a = 1; - dprintk("channel A error interrupt: %04x\n", - intr); - } - -#ifdef VINO_DEBUG_INT - line_count_2 = vino->a.line_count; - page_index_2 = vino->a.page_index; - field_counter_2 = vino->a.field_counter; - start_desc_tbl_2 = vino->a.start_desc_tbl; - next_4_desc_2 = vino->a.next_4_desc; - - printk("intr = %04x, loop = %d, field = %d\n", - intr, loop, vino_drvdata->a.field); - printk("1- line count = %04d, page index = %04d, " - "start = %08x, next = %08x\n" - " fieldc = %d, framec = %d\n", - line_count, page_index, start_desc_tbl, - next_4_desc, field_counter, fc_a); - printk("12-line count = %04d, page index = %04d, " - " start = %08x, next = %08x\n", - line_count_2, page_index_2, start_desc_tbl_2, - next_4_desc_2); - - if (done_a) - printk("\n"); -#endif - } - - if (intr & VINO_INTSTAT_B) { - if (intr & VINO_INTSTAT_B_EOF) { - vino_drvdata->b.field++; - if (vino_drvdata->b.field > 1) { - vino_dma_stop(&vino_drvdata->b); - vino_clear_interrupt(&vino_drvdata->b); - vino_drvdata->b.field = 0; - done_b = 1; - } - dprintk("channel B end-of-field " - "interrupt: %04x\n", intr); - } else { - vino_dma_stop(&vino_drvdata->b); - vino_clear_interrupt(&vino_drvdata->b); - vino_drvdata->b.field = 0; - skip_b = 1; - dprintk("channel B error interrupt: %04x\n", - intr); - } - } - - /* Always remember to clear interrupt status. - * Disable VINO interrupts while we do this. */ - ctrl = vino->control; - vino->control = ctrl & ~(VINO_CTRL_A_INT | VINO_CTRL_B_INT); - vino->intr_status = ~intr; - vino->control = ctrl; - - spin_unlock(&vino_drvdata->vino_lock); - - if ((!handled_a) && (done_a || skip_a)) { - if (!skip_a) { - do_gettimeofday(&vino_drvdata-> - a.int_data.timestamp); - vino_drvdata->a.int_data.frame_counter = fc_a; - } - vino_drvdata->a.int_data.skip = skip_a; - - dprintk("channel A %s, interrupt: %d\n", - skip_a ? "skipping frame" : "frame done", - intr); - tasklet_hi_schedule(&vino_tasklet_a); - handled_a = 1; - } - - if ((!handled_b) && (done_b || skip_b)) { - if (!skip_b) { - do_gettimeofday(&vino_drvdata-> - b.int_data.timestamp); - vino_drvdata->b.int_data.frame_counter = fc_b; - } - vino_drvdata->b.int_data.skip = skip_b; - - dprintk("channel B %s, interrupt: %d\n", - skip_b ? "skipping frame" : "frame done", - intr); - tasklet_hi_schedule(&vino_tasklet_b); - handled_b = 1; - } - -#ifdef VINO_DEBUG_INT - loop++; -#endif - spin_lock(&vino_drvdata->vino_lock); - } - - spin_unlock(&vino_drvdata->vino_lock); - - return IRQ_HANDLED; -} - -/* VINO video input management */ - -static int vino_get_saa7191_input(int input) -{ - switch (input) { - case VINO_INPUT_COMPOSITE: - return SAA7191_INPUT_COMPOSITE; - case VINO_INPUT_SVIDEO: - return SAA7191_INPUT_SVIDEO; - default: - printk(KERN_ERR "VINO: vino_get_saa7191_input(): " - "invalid input!\n"); - return -1; - } -} - -/* execute with input_lock locked */ -static int vino_is_input_owner(struct vino_channel_settings *vcs) -{ - switch(vcs->input) { - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: - return vino_drvdata->decoder_owner == vcs->channel; - case VINO_INPUT_D1: - return vino_drvdata->camera_owner == vcs->channel; - default: - return 0; - } -} - -static int vino_acquire_input(struct vino_channel_settings *vcs) -{ - unsigned long flags; - int ret = 0; - - dprintk("vino_acquire_input():\n"); - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - /* First try D1 and then SAA7191 */ - if (vino_drvdata->camera - && (vino_drvdata->camera_owner == VINO_NO_CHANNEL)) { - vino_drvdata->camera_owner = vcs->channel; - vcs->input = VINO_INPUT_D1; - vcs->data_norm = VINO_DATA_NORM_D1; - } else if (vino_drvdata->decoder - && (vino_drvdata->decoder_owner == VINO_NO_CHANNEL)) { - int input; - int data_norm; - v4l2_std_id norm; - - input = VINO_INPUT_COMPOSITE; - - ret = decoder_call(video, s_routing, - vino_get_saa7191_input(input), 0, 0); - if (ret) { - ret = -EINVAL; - goto out; - } - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - /* Don't hold spinlocks while auto-detecting norm - * as it may take a while... */ - - ret = decoder_call(video, querystd, &norm); - if (!ret) { - for (data_norm = 0; data_norm < 3; data_norm++) { - if (vino_data_norms[data_norm].std & norm) - break; - } - if (data_norm == 3) - data_norm = VINO_DATA_NORM_PAL; - ret = decoder_call(core, s_std, norm); - } - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (ret) { - ret = -EINVAL; - goto out; - } - - vino_drvdata->decoder_owner = vcs->channel; - - vcs->input = input; - vcs->data_norm = data_norm; - } else { - vcs->input = (vcs->channel == VINO_CHANNEL_A) ? - vino_drvdata->b.input : vino_drvdata->a.input; - vcs->data_norm = (vcs->channel == VINO_CHANNEL_A) ? - vino_drvdata->b.data_norm : vino_drvdata->a.data_norm; - } - - if (vcs->input == VINO_INPUT_NONE) { - ret = -ENODEV; - goto out; - } - - vino_set_default_clipping(vcs); - vino_set_default_scaling(vcs); - vino_set_default_framerate(vcs); - - dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name); - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return ret; -} - -static int vino_set_input(struct vino_channel_settings *vcs, int input) -{ - struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ? - &vino_drvdata->b : &vino_drvdata->a; - unsigned long flags; - int ret = 0; - - dprintk("vino_set_input():\n"); - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (vcs->input == input) - goto out; - - switch (input) { - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: - if (!vino_drvdata->decoder) { - ret = -EINVAL; - goto out; - } - - if (vino_drvdata->decoder_owner == VINO_NO_CHANNEL) { - vino_drvdata->decoder_owner = vcs->channel; - } - - if (vino_drvdata->decoder_owner == vcs->channel) { - int data_norm; - v4l2_std_id norm; - - ret = decoder_call(video, s_routing, - vino_get_saa7191_input(input), 0, 0); - if (ret) { - vino_drvdata->decoder_owner = VINO_NO_CHANNEL; - ret = -EINVAL; - goto out; - } - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - /* Don't hold spinlocks while auto-detecting norm - * as it may take a while... */ - - ret = decoder_call(video, querystd, &norm); - if (!ret) { - for (data_norm = 0; data_norm < 3; data_norm++) { - if (vino_data_norms[data_norm].std & norm) - break; - } - if (data_norm == 3) - data_norm = VINO_DATA_NORM_PAL; - ret = decoder_call(core, s_std, norm); - } - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (ret) { - vino_drvdata->decoder_owner = VINO_NO_CHANNEL; - ret = -EINVAL; - goto out; - } - - vcs->input = input; - vcs->data_norm = data_norm; - } else { - if (input != vcs2->input) { - ret = -EBUSY; - goto out; - } - - vcs->input = input; - vcs->data_norm = vcs2->data_norm; - } - - if (vino_drvdata->camera_owner == vcs->channel) { - /* Transfer the ownership or release the input */ - if (vcs2->input == VINO_INPUT_D1) { - vino_drvdata->camera_owner = vcs2->channel; - } else { - vino_drvdata->camera_owner = VINO_NO_CHANNEL; - } - } - break; - case VINO_INPUT_D1: - if (!vino_drvdata->camera) { - ret = -EINVAL; - goto out; - } - - if (vino_drvdata->camera_owner == VINO_NO_CHANNEL) - vino_drvdata->camera_owner = vcs->channel; - - if (vino_drvdata->decoder_owner == vcs->channel) { - /* Transfer the ownership or release the input */ - if ((vcs2->input == VINO_INPUT_COMPOSITE) || - (vcs2->input == VINO_INPUT_SVIDEO)) { - vino_drvdata->decoder_owner = vcs2->channel; - } else { - vino_drvdata->decoder_owner = VINO_NO_CHANNEL; - } - } - - vcs->input = input; - vcs->data_norm = VINO_DATA_NORM_D1; - break; - default: - ret = -EINVAL; - goto out; - } - - vino_set_default_clipping(vcs); - vino_set_default_scaling(vcs); - vino_set_default_framerate(vcs); - - dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name); - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return ret; -} - -static void vino_release_input(struct vino_channel_settings *vcs) -{ - struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ? - &vino_drvdata->b : &vino_drvdata->a; - unsigned long flags; - - dprintk("vino_release_input():\n"); - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - /* Release ownership of the channel - * and if the other channel takes input from - * the same source, transfer the ownership */ - if (vino_drvdata->camera_owner == vcs->channel) { - if (vcs2->input == VINO_INPUT_D1) { - vino_drvdata->camera_owner = vcs2->channel; - } else { - vino_drvdata->camera_owner = VINO_NO_CHANNEL; - } - } else if (vino_drvdata->decoder_owner == vcs->channel) { - if ((vcs2->input == VINO_INPUT_COMPOSITE) || - (vcs2->input == VINO_INPUT_SVIDEO)) { - vino_drvdata->decoder_owner = vcs2->channel; - } else { - vino_drvdata->decoder_owner = VINO_NO_CHANNEL; - } - } - vcs->input = VINO_INPUT_NONE; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); -} - -/* execute with input_lock locked */ -static int vino_set_data_norm(struct vino_channel_settings *vcs, - unsigned int data_norm, - unsigned long *flags) -{ - int err = 0; - - if (data_norm == vcs->data_norm) - return 0; - - switch (vcs->input) { - case VINO_INPUT_D1: - /* only one "norm" supported */ - if (data_norm != VINO_DATA_NORM_D1) - return -EINVAL; - break; - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: { - v4l2_std_id norm; - - if ((data_norm != VINO_DATA_NORM_PAL) - && (data_norm != VINO_DATA_NORM_NTSC) - && (data_norm != VINO_DATA_NORM_SECAM)) - return -EINVAL; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags); - - /* Don't hold spinlocks while setting norm - * as it may take a while... */ - - norm = vino_data_norms[data_norm].std; - err = decoder_call(core, s_std, norm); - - spin_lock_irqsave(&vino_drvdata->input_lock, *flags); - - if (err) - goto out; - - vcs->data_norm = data_norm; - - vino_set_default_clipping(vcs); - vino_set_default_scaling(vcs); - vino_set_default_framerate(vcs); - break; - } - default: - return -EINVAL; - } - -out: - return err; -} - -/* V4L2 helper functions */ - -static int vino_find_data_format(__u32 pixelformat) -{ - int i; - - for (i = 0; i < VINO_DATA_FMT_COUNT; i++) { - if (vino_data_formats[i].pixelformat == pixelformat) - return i; - } - - return VINO_DATA_FMT_NONE; -} - -static int vino_int_enum_input(struct vino_channel_settings *vcs, __u32 index) -{ - int input = VINO_INPUT_NONE; - unsigned long flags; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - if (vino_drvdata->decoder && vino_drvdata->camera) { - switch (index) { - case 0: - input = VINO_INPUT_COMPOSITE; - break; - case 1: - input = VINO_INPUT_SVIDEO; - break; - case 2: - input = VINO_INPUT_D1; - break; - } - } else if (vino_drvdata->decoder) { - switch (index) { - case 0: - input = VINO_INPUT_COMPOSITE; - break; - case 1: - input = VINO_INPUT_SVIDEO; - break; - } - } else if (vino_drvdata->camera) { - switch (index) { - case 0: - input = VINO_INPUT_D1; - break; - } - } - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return input; -} - -/* execute with input_lock locked */ -static __u32 vino_find_input_index(struct vino_channel_settings *vcs) -{ - __u32 index = 0; - // FIXME: detect when no inputs available - - if (vino_drvdata->decoder && vino_drvdata->camera) { - switch (vcs->input) { - case VINO_INPUT_COMPOSITE: - index = 0; - break; - case VINO_INPUT_SVIDEO: - index = 1; - break; - case VINO_INPUT_D1: - index = 2; - break; - } - } else if (vino_drvdata->decoder) { - switch (vcs->input) { - case VINO_INPUT_COMPOSITE: - index = 0; - break; - case VINO_INPUT_SVIDEO: - index = 1; - break; - } - } else if (vino_drvdata->camera) { - switch (vcs->input) { - case VINO_INPUT_D1: - index = 0; - break; - } - } - - return index; -} - -/* V4L2 ioctls */ - -static int vino_querycap(struct file *file, void *__fh, - struct v4l2_capability *cap) -{ - memset(cap, 0, sizeof(struct v4l2_capability)); - - strcpy(cap->driver, vino_driver_name); - strcpy(cap->card, vino_driver_description); - strcpy(cap->bus_info, vino_bus_name); - cap->version = VINO_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING; - // V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE - return 0; -} - -static int vino_enum_input(struct file *file, void *__fh, - struct v4l2_input *i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - __u32 index = i->index; - int input; - dprintk("requested index = %d\n", index); - - input = vino_int_enum_input(vcs, index); - if (input == VINO_INPUT_NONE) - return -EINVAL; - - i->type = V4L2_INPUT_TYPE_CAMERA; - i->std = vino_inputs[input].std; - strcpy(i->name, vino_inputs[input].name); - - if (input == VINO_INPUT_COMPOSITE || input == VINO_INPUT_SVIDEO) - decoder_call(video, g_input_status, &i->status); - return 0; -} - -static int vino_g_input(struct file *file, void *__fh, - unsigned int *i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - __u32 index; - int input; - unsigned long flags; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - input = vcs->input; - index = vino_find_input_index(vcs); - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - dprintk("input = %d\n", input); - - if (input == VINO_INPUT_NONE) { - return -EINVAL; - } - - *i = index; - - return 0; -} - -static int vino_s_input(struct file *file, void *__fh, - unsigned int i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - int input; - dprintk("requested input = %d\n", i); - - input = vino_int_enum_input(vcs, i); - if (input == VINO_INPUT_NONE) - return -EINVAL; - - return vino_set_input(vcs, input); -} - -static int vino_querystd(struct file *file, void *__fh, - v4l2_std_id *std) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int err = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - switch (vcs->input) { - case VINO_INPUT_D1: - *std = vino_inputs[vcs->input].std; - break; - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: { - decoder_call(video, querystd, std); - break; - } - default: - err = -EINVAL; - } - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return err; -} - -static int vino_g_std(struct file *file, void *__fh, - v4l2_std_id *std) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - *std = vino_data_norms[vcs->data_norm].std; - dprintk("current standard = %d\n", vcs->data_norm); - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return 0; -} - -static int vino_s_std(struct file *file, void *__fh, - v4l2_std_id *std) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (!vino_is_input_owner(vcs)) { - ret = -EBUSY; - goto out; - } - - /* check if the standard is valid for the current input */ - if ((*std) & vino_inputs[vcs->input].std) { - dprintk("standard accepted\n"); - - /* change the video norm for SAA7191 - * and accept NTSC for D1 (do nothing) */ - - if (vcs->input == VINO_INPUT_D1) - goto out; - - if ((*std) & V4L2_STD_PAL) { - ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL, - &flags); - } else if ((*std) & V4L2_STD_NTSC) { - ret = vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC, - &flags); - } else if ((*std) & V4L2_STD_SECAM) { - ret = vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM, - &flags); - } else { - ret = -EINVAL; - } - - if (ret) { - ret = -EINVAL; - } - } else { - ret = -EINVAL; - } - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return ret; -} - -static int vino_enum_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_fmtdesc *fd) -{ - dprintk("format index = %d\n", fd->index); - - if (fd->index >= VINO_DATA_FMT_COUNT) - return -EINVAL; - dprintk("format name = %s\n", vino_data_formats[fd->index].description); - - fd->pixelformat = vino_data_formats[fd->index].pixelformat; - strcpy(fd->description, vino_data_formats[fd->index].description); - return 0; -} - -static int vino_try_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *f) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - struct vino_channel_settings tempvcs; - unsigned long flags; - struct v4l2_pix_format *pf = &f->fmt.pix; - - dprintk("requested: w = %d, h = %d\n", - pf->width, pf->height); - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings)); - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - tempvcs.data_format = vino_find_data_format(pf->pixelformat); - if (tempvcs.data_format == VINO_DATA_FMT_NONE) { - tempvcs.data_format = VINO_DATA_FMT_GREY; - pf->pixelformat = - vino_data_formats[tempvcs.data_format]. - pixelformat; - } - - /* data format must be set before clipping/scaling */ - vino_set_scaling(&tempvcs, pf->width, pf->height); - - dprintk("data format = %s\n", - vino_data_formats[tempvcs.data_format].description); - - pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) / - tempvcs.decimation; - pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) / - tempvcs.decimation; - - pf->field = V4L2_FIELD_INTERLACED; - pf->bytesperline = tempvcs.line_size; - pf->sizeimage = tempvcs.line_size * - (tempvcs.clipping.bottom - tempvcs.clipping.top) / - tempvcs.decimation; - pf->colorspace = - vino_data_formats[tempvcs.data_format].colorspace; - - pf->priv = 0; - return 0; -} - -static int vino_g_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *f) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - struct v4l2_pix_format *pf = &f->fmt.pix; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - pf->width = (vcs->clipping.right - vcs->clipping.left) / - vcs->decimation; - pf->height = (vcs->clipping.bottom - vcs->clipping.top) / - vcs->decimation; - pf->pixelformat = - vino_data_formats[vcs->data_format].pixelformat; - - pf->field = V4L2_FIELD_INTERLACED; - pf->bytesperline = vcs->line_size; - pf->sizeimage = vcs->line_size * - (vcs->clipping.bottom - vcs->clipping.top) / - vcs->decimation; - pf->colorspace = - vino_data_formats[vcs->data_format].colorspace; - - pf->priv = 0; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - return 0; -} - -static int vino_s_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *f) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - int data_format; - unsigned long flags; - struct v4l2_pix_format *pf = &f->fmt.pix; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - data_format = vino_find_data_format(pf->pixelformat); - - if (data_format == VINO_DATA_FMT_NONE) { - vcs->data_format = VINO_DATA_FMT_GREY; - pf->pixelformat = - vino_data_formats[vcs->data_format]. - pixelformat; - } else { - vcs->data_format = data_format; - } - - /* data format must be set before clipping/scaling */ - vino_set_scaling(vcs, pf->width, pf->height); - - dprintk("data format = %s\n", - vino_data_formats[vcs->data_format].description); - - pf->width = vcs->clipping.right - vcs->clipping.left; - pf->height = vcs->clipping.bottom - vcs->clipping.top; - - pf->field = V4L2_FIELD_INTERLACED; - pf->bytesperline = vcs->line_size; - pf->sizeimage = vcs->line_size * - (vcs->clipping.bottom - vcs->clipping.top) / - vcs->decimation; - pf->colorspace = - vino_data_formats[vcs->data_format].colorspace; - - pf->priv = 0; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - return 0; -} - -static int vino_cropcap(struct file *file, void *__fh, - struct v4l2_cropcap *ccap) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - const struct vino_data_norm *norm; - unsigned long flags; - - switch (ccap->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - norm = &vino_data_norms[vcs->data_norm]; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - ccap->bounds.left = 0; - ccap->bounds.top = 0; - ccap->bounds.width = norm->width; - ccap->bounds.height = norm->height; - memcpy(&ccap->defrect, &ccap->bounds, - sizeof(struct v4l2_rect)); - - ccap->pixelaspect.numerator = 1; - ccap->pixelaspect.denominator = 1; - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - default: - return -EINVAL; - } - - return 0; -} - -static int vino_g_crop(struct file *file, void *__fh, - struct v4l2_crop *c) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - - switch (c->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - c->c.left = vcs->clipping.left; - c->c.top = vcs->clipping.top; - c->c.width = vcs->clipping.right - vcs->clipping.left; - c->c.height = vcs->clipping.bottom - vcs->clipping.top; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - default: - return -EINVAL; - } - - return 0; -} - -static int vino_s_crop(struct file *file, void *__fh, - struct v4l2_crop *c) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - - switch (c->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - vino_set_clipping(vcs, c->c.left, c->c.top, - c->c.width, c->c.height); - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - default: - return -EINVAL; - } - - return 0; -} - -static int vino_g_parm(struct file *file, void *__fh, - struct v4l2_streamparm *sp) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - struct v4l2_captureparm *cp = &sp->parm.capture; - - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = 1; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - cp->timeperframe.denominator = vcs->fps; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - /* TODO: cp->readbuffers = xxx; */ - - return 0; -} - -static int vino_s_parm(struct file *file, void *__fh, - struct v4l2_streamparm *sp) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - struct v4l2_captureparm *cp = &sp->parm.capture; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if ((cp->timeperframe.numerator == 0) || - (cp->timeperframe.denominator == 0)) { - /* reset framerate */ - vino_set_default_framerate(vcs); - } else { - vino_set_framerate(vcs, cp->timeperframe.denominator / - cp->timeperframe.numerator); - } - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return 0; -} - -static int vino_reqbufs(struct file *file, void *__fh, - struct v4l2_requestbuffers *rb) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - - if (vcs->reading) - return -EBUSY; - - /* TODO: check queue type */ - if (rb->memory != V4L2_MEMORY_MMAP) { - dprintk("type not mmap\n"); - return -EINVAL; - } - - dprintk("count = %d\n", rb->count); - if (rb->count > 0) { - if (vino_is_capturing(vcs)) { - dprintk("busy, capturing\n"); - return -EBUSY; - } - - if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) { - dprintk("busy, buffers still mapped\n"); - return -EBUSY; - } else { - vcs->streaming = 0; - vino_queue_free(&vcs->fb_queue); - vino_queue_init(&vcs->fb_queue, &rb->count); - } - } else { - vcs->streaming = 0; - vino_capture_stop(vcs); - vino_queue_free(&vcs->fb_queue); - } - - return 0; -} - -static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs, - struct vino_framebuffer *fb, - struct v4l2_buffer *b) -{ - if (vino_queue_outgoing_contains(&vcs->fb_queue, - fb->id)) { - b->flags &= ~V4L2_BUF_FLAG_QUEUED; - b->flags |= V4L2_BUF_FLAG_DONE; - } else if (vino_queue_incoming_contains(&vcs->fb_queue, - fb->id)) { - b->flags &= ~V4L2_BUF_FLAG_DONE; - b->flags |= V4L2_BUF_FLAG_QUEUED; - } else { - b->flags &= ~(V4L2_BUF_FLAG_DONE | - V4L2_BUF_FLAG_QUEUED); - } - - b->flags &= ~(V4L2_BUF_FLAG_TIMECODE); - - if (fb->map_count > 0) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - b->index = fb->id; - b->memory = (vcs->fb_queue.type == VINO_MEMORY_MMAP) ? - V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR; - b->m.offset = fb->offset; - b->bytesused = fb->data_size; - b->length = fb->size; - b->field = V4L2_FIELD_INTERLACED; - b->sequence = fb->frame_counter; - memcpy(&b->timestamp, &fb->timestamp, - sizeof(struct timeval)); - // b->input ? - - dprintk("buffer %d: length = %d, bytesused = %d, offset = %d\n", - fb->id, fb->size, fb->data_size, fb->offset); -} - -static int vino_querybuf(struct file *file, void *__fh, - struct v4l2_buffer *b) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - struct vino_framebuffer *fb; - - if (vcs->reading) - return -EBUSY; - - /* TODO: check queue type */ - if (b->index >= vino_queue_get_length(&vcs->fb_queue)) { - dprintk("invalid index = %d\n", - b->index); - return -EINVAL; - } - - fb = vino_queue_get_buffer(&vcs->fb_queue, - b->index); - if (fb == NULL) { - dprintk("vino_queue_get_buffer() failed"); - return -EINVAL; - } - - vino_v4l2_get_buffer_status(vcs, fb, b); - - return 0; -} - -static int vino_qbuf(struct file *file, void *__fh, - struct v4l2_buffer *b) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - struct vino_framebuffer *fb; - int ret; - - if (vcs->reading) - return -EBUSY; - - /* TODO: check queue type */ - if (b->memory != V4L2_MEMORY_MMAP) { - dprintk("type not mmap\n"); - return -EINVAL; - } - - fb = vino_capture_enqueue(vcs, b->index); - if (fb == NULL) - return -EINVAL; - - vino_v4l2_get_buffer_status(vcs, fb, b); - - if (vcs->streaming) { - ret = vino_capture_next(vcs, 1); - if (ret) - return ret; - } - - return 0; -} - -static int vino_dqbuf(struct file *file, void *__fh, - struct v4l2_buffer *b) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned int nonblocking = file->f_flags & O_NONBLOCK; - struct vino_framebuffer *fb; - unsigned int incoming, outgoing; - int err; - - if (vcs->reading) - return -EBUSY; - - /* TODO: check queue type */ - - err = vino_queue_get_incoming(&vcs->fb_queue, &incoming); - if (err) { - dprintk("vino_queue_get_incoming() failed\n"); - return -EINVAL; - } - err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing); - if (err) { - dprintk("vino_queue_get_outgoing() failed\n"); - return -EINVAL; - } - - dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing); - - if (outgoing == 0) { - if (incoming == 0) { - dprintk("no incoming or outgoing buffers\n"); - return -EINVAL; - } - if (nonblocking) { - dprintk("non-blocking I/O was selected and " - "there are no buffers to dequeue\n"); - return -EAGAIN; - } - - err = vino_wait_for_frame(vcs); - if (err) { - err = vino_wait_for_frame(vcs); - if (err) { - /* interrupted or no frames captured because of - * frame skipping */ - /* vino_capture_failed(vcs); */ - return -EIO; - } - } - } - - fb = vino_queue_remove(&vcs->fb_queue, &b->index); - if (fb == NULL) { - dprintk("vino_queue_remove() failed\n"); - return -EINVAL; - } - - err = vino_check_buffer(vcs, fb); - - vino_v4l2_get_buffer_status(vcs, fb, b); - - if (err) - return -EIO; - - return 0; -} - -static int vino_streamon(struct file *file, void *__fh, - enum v4l2_buf_type i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned int incoming; - int ret; - if (vcs->reading) - return -EBUSY; - - if (vcs->streaming) - return 0; - - // TODO: check queue type - - if (vino_queue_get_length(&vcs->fb_queue) < 1) { - dprintk("no buffers allocated\n"); - return -EINVAL; - } - - ret = vino_queue_get_incoming(&vcs->fb_queue, &incoming); - if (ret) { - dprintk("vino_queue_get_incoming() failed\n"); - return -EINVAL; - } - - vcs->streaming = 1; - - if (incoming > 0) { - ret = vino_capture_next(vcs, 1); - if (ret) { - vcs->streaming = 0; - - dprintk("couldn't start capture\n"); - return -EINVAL; - } - } - - return 0; -} - -static int vino_streamoff(struct file *file, void *__fh, - enum v4l2_buf_type i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - if (vcs->reading) - return -EBUSY; - - if (!vcs->streaming) - return 0; - - vcs->streaming = 0; - vino_capture_stop(vcs); - - return 0; -} - -static int vino_queryctrl(struct file *file, void *__fh, - struct v4l2_queryctrl *queryctrl) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int i; - int err = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - switch (vcs->input) { - case VINO_INPUT_D1: - for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { - if (vino_indycam_v4l2_controls[i].id == - queryctrl->id) { - memcpy(queryctrl, - &vino_indycam_v4l2_controls[i], - sizeof(struct v4l2_queryctrl)); - queryctrl->reserved[0] = 0; - goto found; - } - } - - err = -EINVAL; - break; - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: - for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { - if (vino_saa7191_v4l2_controls[i].id == - queryctrl->id) { - memcpy(queryctrl, - &vino_saa7191_v4l2_controls[i], - sizeof(struct v4l2_queryctrl)); - queryctrl->reserved[0] = 0; - goto found; - } - } - - err = -EINVAL; - break; - default: - err = -EINVAL; - } - - found: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return err; -} - -static int vino_g_ctrl(struct file *file, void *__fh, - struct v4l2_control *control) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int i; - int err = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - switch (vcs->input) { - case VINO_INPUT_D1: { - err = -EINVAL; - for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { - if (vino_indycam_v4l2_controls[i].id == control->id) { - err = 0; - break; - } - } - - if (err) - goto out; - - err = camera_call(core, g_ctrl, control); - if (err) - err = -EINVAL; - break; - } - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: { - err = -EINVAL; - for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { - if (vino_saa7191_v4l2_controls[i].id == control->id) { - err = 0; - break; - } - } - - if (err) - goto out; - - err = decoder_call(core, g_ctrl, control); - if (err) - err = -EINVAL; - break; - } - default: - err = -EINVAL; - } - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return err; -} - -static int vino_s_ctrl(struct file *file, void *__fh, - struct v4l2_control *control) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int i; - int err = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (!vino_is_input_owner(vcs)) { - err = -EBUSY; - goto out; - } - - switch (vcs->input) { - case VINO_INPUT_D1: { - err = -EINVAL; - for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { - if (vino_indycam_v4l2_controls[i].id == control->id) { - err = 0; - break; - } - } - if (err) - goto out; - if (control->value < vino_indycam_v4l2_controls[i].minimum || - control->value > vino_indycam_v4l2_controls[i].maximum) { - err = -ERANGE; - goto out; - } - err = camera_call(core, s_ctrl, control); - if (err) - err = -EINVAL; - break; - } - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: { - err = -EINVAL; - for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { - if (vino_saa7191_v4l2_controls[i].id == control->id) { - err = 0; - break; - } - } - if (err) - goto out; - if (control->value < vino_saa7191_v4l2_controls[i].minimum || - control->value > vino_saa7191_v4l2_controls[i].maximum) { - err = -ERANGE; - goto out; - } - - err = decoder_call(core, s_ctrl, control); - if (err) - err = -EINVAL; - break; - } - default: - err = -EINVAL; - } - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return err; -} - -/* File operations */ - -static int vino_open(struct file *file) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - int ret = 0; - dprintk("open(): channel = %c\n", - (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B'); - - mutex_lock(&vcs->mutex); - - if (vcs->users) { - dprintk("open(): driver busy\n"); - ret = -EBUSY; - goto out; - } - - ret = vino_acquire_input(vcs); - if (ret) { - dprintk("open(): vino_acquire_input() failed\n"); - goto out; - } - - vcs->users++; - - out: - mutex_unlock(&vcs->mutex); - - dprintk("open(): %s!\n", ret ? "failed" : "complete"); - - return ret; -} - -static int vino_close(struct file *file) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - dprintk("close():\n"); - - mutex_lock(&vcs->mutex); - - vcs->users--; - - if (!vcs->users) { - vino_release_input(vcs); - - /* stop DMA and free buffers */ - vino_capture_stop(vcs); - vino_queue_free(&vcs->fb_queue); - } - - mutex_unlock(&vcs->mutex); - - return 0; -} - -static void vino_vm_open(struct vm_area_struct *vma) -{ - struct vino_framebuffer *fb = vma->vm_private_data; - - fb->map_count++; - dprintk("vino_vm_open(): count = %d\n", fb->map_count); -} - -static void vino_vm_close(struct vm_area_struct *vma) -{ - struct vino_framebuffer *fb = vma->vm_private_data; - - fb->map_count--; - dprintk("vino_vm_close(): count = %d\n", fb->map_count); -} - -static const struct vm_operations_struct vino_vm_ops = { - .open = vino_vm_open, - .close = vino_vm_close, -}; - -static int vino_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - - struct vino_framebuffer *fb = NULL; - unsigned int i, length; - int ret = 0; - - dprintk("mmap():\n"); - - // TODO: reject mmap if already mapped - - if (mutex_lock_interruptible(&vcs->mutex)) - return -EINTR; - - if (vcs->reading) { - ret = -EBUSY; - goto out; - } - - // TODO: check queue type - - if (!(vma->vm_flags & VM_WRITE)) { - dprintk("mmap(): app bug: PROT_WRITE please\n"); - ret = -EINVAL; - goto out; - } - if (!(vma->vm_flags & VM_SHARED)) { - dprintk("mmap(): app bug: MAP_SHARED please\n"); - ret = -EINVAL; - goto out; - } - - /* find the correct buffer using offset */ - length = vino_queue_get_length(&vcs->fb_queue); - if (length == 0) { - dprintk("mmap(): queue not initialized\n"); - ret = -EINVAL; - goto out; - } - - for (i = 0; i < length; i++) { - fb = vino_queue_get_buffer(&vcs->fb_queue, i); - if (fb == NULL) { - dprintk("mmap(): vino_queue_get_buffer() failed\n"); - ret = -EINVAL; - goto out; - } - - if (fb->offset == offset) - goto found; - } - - dprintk("mmap(): invalid offset = %lu\n", offset); - ret = -EINVAL; - goto out; - -found: - dprintk("mmap(): buffer = %d\n", i); - - if (size > (fb->desc_table.page_count * PAGE_SIZE)) { - dprintk("mmap(): failed: size = %lu > %lu\n", - size, fb->desc_table.page_count * PAGE_SIZE); - ret = -EINVAL; - goto out; - } - - for (i = 0; i < fb->desc_table.page_count; i++) { - unsigned long pfn = - virt_to_phys((void *)fb->desc_table.virtual[i]) >> - PAGE_SHIFT; - - if (size < PAGE_SIZE) - break; - - // protection was: PAGE_READONLY - if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, - vma->vm_page_prot)) { - dprintk("mmap(): remap_pfn_range() failed\n"); - ret = -EAGAIN; - goto out; - } - - start += PAGE_SIZE; - size -= PAGE_SIZE; - } - - fb->map_count = 1; - - vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; - vma->vm_flags &= ~VM_IO; - vma->vm_private_data = fb; - vma->vm_file = file; - vma->vm_ops = &vino_vm_ops; - -out: - mutex_unlock(&vcs->mutex); - - return ret; -} - -static unsigned int vino_poll(struct file *file, poll_table *pt) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned int outgoing; - unsigned int ret = 0; - - // lock mutex (?) - // TODO: this has to be corrected for different read modes - - dprintk("poll():\n"); - - if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { - dprintk("poll(): vino_queue_get_outgoing() failed\n"); - ret = POLLERR; - goto error; - } - if (outgoing > 0) - goto over; - - poll_wait(file, &vcs->fb_queue.frame_wait_queue, pt); - - if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { - dprintk("poll(): vino_queue_get_outgoing() failed\n"); - ret = POLLERR; - goto error; - } - -over: - dprintk("poll(): data %savailable\n", - (outgoing > 0) ? "" : "not "); - - if (outgoing > 0) - ret = POLLIN | POLLRDNORM; - -error: - return ret; -} - -static long vino_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - long ret; - - if (mutex_lock_interruptible(&vcs->mutex)) - return -EINTR; - - ret = video_ioctl2(file, cmd, arg); - - mutex_unlock(&vcs->mutex); - - return ret; -} - -/* Initialization and cleanup */ - -/* __initdata */ -static int vino_init_stage; - -const struct v4l2_ioctl_ops vino_ioctl_ops = { - .vidioc_enum_fmt_vid_cap = vino_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vino_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vino_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vino_try_fmt_vid_cap, - .vidioc_querycap = vino_querycap, - .vidioc_enum_input = vino_enum_input, - .vidioc_g_input = vino_g_input, - .vidioc_s_input = vino_s_input, - .vidioc_g_std = vino_g_std, - .vidioc_s_std = vino_s_std, - .vidioc_querystd = vino_querystd, - .vidioc_cropcap = vino_cropcap, - .vidioc_s_crop = vino_s_crop, - .vidioc_g_crop = vino_g_crop, - .vidioc_s_parm = vino_s_parm, - .vidioc_g_parm = vino_g_parm, - .vidioc_reqbufs = vino_reqbufs, - .vidioc_querybuf = vino_querybuf, - .vidioc_qbuf = vino_qbuf, - .vidioc_dqbuf = vino_dqbuf, - .vidioc_streamon = vino_streamon, - .vidioc_streamoff = vino_streamoff, - .vidioc_queryctrl = vino_queryctrl, - .vidioc_g_ctrl = vino_g_ctrl, - .vidioc_s_ctrl = vino_s_ctrl, -}; - -static const struct v4l2_file_operations vino_fops = { - .owner = THIS_MODULE, - .open = vino_open, - .release = vino_close, - .unlocked_ioctl = vino_ioctl, - .mmap = vino_mmap, - .poll = vino_poll, -}; - -static struct video_device vdev_template = { - .name = "NOT SET", - .fops = &vino_fops, - .ioctl_ops = &vino_ioctl_ops, - .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, -}; - -static void vino_module_cleanup(int stage) -{ - switch(stage) { - case 11: - video_unregister_device(vino_drvdata->b.vdev); - vino_drvdata->b.vdev = NULL; - case 10: - video_unregister_device(vino_drvdata->a.vdev); - vino_drvdata->a.vdev = NULL; - case 9: - i2c_del_adapter(&vino_i2c_adapter); - case 8: - free_irq(SGI_VINO_IRQ, NULL); - case 7: - if (vino_drvdata->b.vdev) { - video_device_release(vino_drvdata->b.vdev); - vino_drvdata->b.vdev = NULL; - } - case 6: - if (vino_drvdata->a.vdev) { - video_device_release(vino_drvdata->a.vdev); - vino_drvdata->a.vdev = NULL; - } - case 5: - /* all entries in dma_cpu dummy table have the same address */ - dma_unmap_single(NULL, - vino_drvdata->dummy_desc_table.dma_cpu[0], - PAGE_SIZE, DMA_FROM_DEVICE); - dma_free_coherent(NULL, VINO_DUMMY_DESC_COUNT - * sizeof(dma_addr_t), - (void *)vino_drvdata-> - dummy_desc_table.dma_cpu, - vino_drvdata->dummy_desc_table.dma); - case 4: - free_page(vino_drvdata->dummy_page); - case 3: - v4l2_device_unregister(&vino_drvdata->v4l2_dev); - case 2: - kfree(vino_drvdata); - case 1: - iounmap(vino); - case 0: - break; - default: - dprintk("vino_module_cleanup(): invalid cleanup stage = %d\n", - stage); - } -} - -static int vino_probe(void) -{ - unsigned long rev_id; - - if (ip22_is_fullhouse()) { - printk(KERN_ERR "VINO doesn't exist in IP22 Fullhouse\n"); - return -ENODEV; - } - - if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) { - printk(KERN_ERR "VINO is not found (EISA BUS not present)\n"); - return -ENODEV; - } - - vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino)); - if (!vino) { - printk(KERN_ERR "VINO: ioremap() failed\n"); - return -EIO; - } - vino_init_stage++; - - if (get_dbe(rev_id, &(vino->rev_id))) { - printk(KERN_ERR "Failed to read VINO revision register\n"); - vino_module_cleanup(vino_init_stage); - return -ENODEV; - } - - if (VINO_ID_VALUE(rev_id) != VINO_CHIP_ID) { - printk(KERN_ERR "Unknown VINO chip ID (Rev/ID: 0x%02lx)\n", - rev_id); - vino_module_cleanup(vino_init_stage); - return -ENODEV; - } - - printk(KERN_INFO "VINO revision %ld found\n", VINO_REV_NUM(rev_id)); - - return 0; -} - -static int vino_init(void) -{ - dma_addr_t dma_dummy_address; - int err; - int i; - - vino_drvdata = kzalloc(sizeof(struct vino_settings), GFP_KERNEL); - if (!vino_drvdata) { - vino_module_cleanup(vino_init_stage); - return -ENOMEM; - } - vino_init_stage++; - strlcpy(vino_drvdata->v4l2_dev.name, "vino", - sizeof(vino_drvdata->v4l2_dev.name)); - err = v4l2_device_register(NULL, &vino_drvdata->v4l2_dev); - if (err) - return err; - vino_init_stage++; - - /* create a dummy dma descriptor */ - vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!vino_drvdata->dummy_page) { - vino_module_cleanup(vino_init_stage); - return -ENOMEM; - } - vino_init_stage++; - - // TODO: use page_count in dummy_desc_table - - vino_drvdata->dummy_desc_table.dma_cpu = - dma_alloc_coherent(NULL, - VINO_DUMMY_DESC_COUNT * sizeof(dma_addr_t), - &vino_drvdata->dummy_desc_table.dma, - GFP_KERNEL | GFP_DMA); - if (!vino_drvdata->dummy_desc_table.dma_cpu) { - vino_module_cleanup(vino_init_stage); - return -ENOMEM; - } - vino_init_stage++; - - dma_dummy_address = dma_map_single(NULL, - (void *)vino_drvdata->dummy_page, - PAGE_SIZE, DMA_FROM_DEVICE); - for (i = 0; i < VINO_DUMMY_DESC_COUNT; i++) { - vino_drvdata->dummy_desc_table.dma_cpu[i] = dma_dummy_address; - } - - /* initialize VINO */ - - vino->control = 0; - vino->a.next_4_desc = vino_drvdata->dummy_desc_table.dma; - vino->b.next_4_desc = vino_drvdata->dummy_desc_table.dma; - udelay(VINO_DESC_FETCH_DELAY); - - vino->intr_status = 0; - - vino->a.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT; - vino->b.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT; - - return 0; -} - -static int vino_init_channel_settings(struct vino_channel_settings *vcs, - unsigned int channel, const char *name) -{ - vcs->channel = channel; - vcs->input = VINO_INPUT_NONE; - vcs->alpha = 0; - vcs->users = 0; - vcs->data_format = VINO_DATA_FMT_GREY; - vcs->data_norm = VINO_DATA_NORM_NTSC; - vcs->decimation = 1; - vino_set_default_clipping(vcs); - vino_set_default_framerate(vcs); - - vcs->capturing = 0; - - mutex_init(&vcs->mutex); - spin_lock_init(&vcs->capture_lock); - - mutex_init(&vcs->fb_queue.queue_mutex); - spin_lock_init(&vcs->fb_queue.queue_lock); - init_waitqueue_head(&vcs->fb_queue.frame_wait_queue); - - vcs->vdev = video_device_alloc(); - if (!vcs->vdev) { - vino_module_cleanup(vino_init_stage); - return -ENOMEM; - } - vino_init_stage++; - - memcpy(vcs->vdev, &vdev_template, - sizeof(struct video_device)); - strcpy(vcs->vdev->name, name); - vcs->vdev->release = video_device_release; - vcs->vdev->v4l2_dev = &vino_drvdata->v4l2_dev; - - video_set_drvdata(vcs->vdev, vcs); - - return 0; -} - -static int __init vino_module_init(void) -{ - int ret; - - printk(KERN_INFO "SGI VINO driver version %s\n", - VINO_MODULE_VERSION); - - ret = vino_probe(); - if (ret) - return ret; - - ret = vino_init(); - if (ret) - return ret; - - /* initialize data structures */ - - spin_lock_init(&vino_drvdata->vino_lock); - spin_lock_init(&vino_drvdata->input_lock); - - ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A, - vino_vdev_name_a); - if (ret) - return ret; - - ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B, - vino_vdev_name_b); - if (ret) - return ret; - - /* initialize hardware and register V4L devices */ - - ret = request_irq(SGI_VINO_IRQ, vino_interrupt, 0, - vino_driver_description, NULL); - if (ret) { - printk(KERN_ERR "VINO: requesting IRQ %02d failed\n", - SGI_VINO_IRQ); - vino_module_cleanup(vino_init_stage); - return -EAGAIN; - } - vino_init_stage++; - - ret = i2c_add_adapter(&vino_i2c_adapter); - if (ret) { - printk(KERN_ERR "VINO I2C bus registration failed\n"); - vino_module_cleanup(vino_init_stage); - return ret; - } - i2c_set_adapdata(&vino_i2c_adapter, &vino_drvdata->v4l2_dev); - vino_init_stage++; - - ret = video_register_device(vino_drvdata->a.vdev, - VFL_TYPE_GRABBER, -1); - if (ret < 0) { - printk(KERN_ERR "VINO channel A Video4Linux-device " - "registration failed\n"); - vino_module_cleanup(vino_init_stage); - return -EINVAL; - } - vino_init_stage++; - - ret = video_register_device(vino_drvdata->b.vdev, - VFL_TYPE_GRABBER, -1); - if (ret < 0) { - printk(KERN_ERR "VINO channel B Video4Linux-device " - "registration failed\n"); - vino_module_cleanup(vino_init_stage); - return -EINVAL; - } - vino_init_stage++; - - vino_drvdata->decoder = - v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter, - "saa7191", 0, I2C_ADDRS(0x45)); - vino_drvdata->camera = - v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter, - "indycam", 0, I2C_ADDRS(0x2b)); - - dprintk("init complete!\n"); - - return 0; -} - -static void __exit vino_module_exit(void) -{ - dprintk("exiting, stage = %d ...\n", vino_init_stage); - vino_module_cleanup(vino_init_stage); - dprintk("cleanup complete, exit!\n"); -} - -module_init(vino_module_init); -module_exit(vino_module_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vino.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vino.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vino.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vino.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,138 +0,0 @@ -/* - * Driver for the VINO (Video In No Out) system found in SGI Indys. - * - * This file is subject to the terms and conditions of the GNU General Public - * License version 2 as published by the Free Software Foundation. - * - * Copyright (C) 1999 Ulf Karlsson - * Copyright (C) 2003 Ladislav Michl - */ - -#ifndef _VINO_H_ -#define _VINO_H_ - -#define VINO_BASE 0x00080000 /* Vino is in the EISA address space, - * but it is not an EISA bus card */ -#define VINO_PAGE_SIZE 4096 - -struct sgi_vino_channel { - u32 _pad_alpha; - volatile u32 alpha; - -#define VINO_CLIP_X(x) ((x) & 0x3ff) /* bits 0:9 */ -#define VINO_CLIP_ODD(x) (((x) & 0x1ff) << 10) /* bits 10:18 */ -#define VINO_CLIP_EVEN(x) (((x) & 0x1ff) << 19) /* bits 19:27 */ - u32 _pad_clip_start; - volatile u32 clip_start; - u32 _pad_clip_end; - volatile u32 clip_end; - -#define VINO_FRAMERT_FULL 0xfff -#define VINO_FRAMERT_PAL (1<<0) /* 0=NTSC 1=PAL */ -#define VINO_FRAMERT_RT(x) (((x) & 0xfff) << 1) /* bits 1:12 */ - u32 _pad_frame_rate; - volatile u32 frame_rate; - - u32 _pad_field_counter; - volatile u32 field_counter; - u32 _pad_line_size; - volatile u32 line_size; - u32 _pad_line_count; - volatile u32 line_count; - u32 _pad_page_index; - volatile u32 page_index; - u32 _pad_next_4_desc; - volatile u32 next_4_desc; - u32 _pad_start_desc_tbl; - volatile u32 start_desc_tbl; - -#define VINO_DESC_JUMP (1<<30) -#define VINO_DESC_STOP (1<<31) -#define VINO_DESC_VALID (1<<32) - u32 _pad_desc_0; - volatile u32 desc_0; - u32 _pad_desc_1; - volatile u32 desc_1; - u32 _pad_desc_2; - volatile u32 desc_2; - u32 _pad_Bdesc_3; - volatile u32 desc_3; - - u32 _pad_fifo_thres; - volatile u32 fifo_thres; - u32 _pad_fifo_read; - volatile u32 fifo_read; - u32 _pad_fifo_write; - volatile u32 fifo_write; -}; - -struct sgi_vino { -#define VINO_CHIP_ID 0xb -#define VINO_REV_NUM(x) ((x) & 0x0f) -#define VINO_ID_VALUE(x) (((x) & 0xf0) >> 4) - u32 _pad_rev_id; - volatile u32 rev_id; - -#define VINO_CTRL_LITTLE_ENDIAN (1<<0) -#define VINO_CTRL_A_EOF_INT (1<<1) /* Field transferred int */ -#define VINO_CTRL_A_FIFO_INT (1<<2) /* FIFO overflow int */ -#define VINO_CTRL_A_EOD_INT (1<<3) /* End of desc table int */ -#define VINO_CTRL_A_INT (VINO_CTRL_A_EOF_INT | \ - VINO_CTRL_A_FIFO_INT | \ - VINO_CTRL_A_EOD_INT) -#define VINO_CTRL_B_EOF_INT (1<<4) /* Field transferred int */ -#define VINO_CTRL_B_FIFO_INT (1<<5) /* FIFO overflow int */ -#define VINO_CTRL_B_EOD_INT (1<<6) /* End of desc table int */ -#define VINO_CTRL_B_INT (VINO_CTRL_B_EOF_INT | \ - VINO_CTRL_B_FIFO_INT | \ - VINO_CTRL_B_EOD_INT) -#define VINO_CTRL_A_DMA_ENBL (1<<7) -#define VINO_CTRL_A_INTERLEAVE_ENBL (1<<8) -#define VINO_CTRL_A_SYNC_ENBL (1<<9) -#define VINO_CTRL_A_SELECT (1<<10) /* 1=D1 0=Philips */ -#define VINO_CTRL_A_RGB (1<<11) /* 1=RGB 0=YUV */ -#define VINO_CTRL_A_LUMA_ONLY (1<<12) -#define VINO_CTRL_A_DEC_ENBL (1<<13) /* Decimation */ -#define VINO_CTRL_A_DEC_SCALE_MASK 0x1c000 /* bits 14:17 */ -#define VINO_CTRL_A_DEC_SCALE_SHIFT (14) -#define VINO_CTRL_A_DEC_HOR_ONLY (1<<17) /* Horizontal only */ -#define VINO_CTRL_A_DITHER (1<<18) /* 24 -> 8 bit dither */ -#define VINO_CTRL_B_DMA_ENBL (1<<19) -#define VINO_CTRL_B_INTERLEAVE_ENBL (1<<20) -#define VINO_CTRL_B_SYNC_ENBL (1<<21) -#define VINO_CTRL_B_SELECT (1<<22) /* 1=D1 0=Philips */ -#define VINO_CTRL_B_RGB (1<<23) /* 1=RGB 0=YUV */ -#define VINO_CTRL_B_LUMA_ONLY (1<<24) -#define VINO_CTRL_B_DEC_ENBL (1<<25) /* Decimation */ -#define VINO_CTRL_B_DEC_SCALE_MASK 0x1c000000 /* bits 26:28 */ -#define VINO_CTRL_B_DEC_SCALE_SHIFT (26) -#define VINO_CTRL_B_DEC_HOR_ONLY (1<<29) /* Decimation horizontal only */ -#define VINO_CTRL_B_DITHER (1<<30) /* ChanB 24 -> 8 bit dither */ - u32 _pad_control; - volatile u32 control; - -#define VINO_INTSTAT_A_EOF (1<<0) /* Field transferred int */ -#define VINO_INTSTAT_A_FIFO (1<<1) /* FIFO overflow int */ -#define VINO_INTSTAT_A_EOD (1<<2) /* End of desc table int */ -#define VINO_INTSTAT_A (VINO_INTSTAT_A_EOF | \ - VINO_INTSTAT_A_FIFO | \ - VINO_INTSTAT_A_EOD) -#define VINO_INTSTAT_B_EOF (1<<3) /* Field transferred int */ -#define VINO_INTSTAT_B_FIFO (1<<4) /* FIFO overflow int */ -#define VINO_INTSTAT_B_EOD (1<<5) /* End of desc table int */ -#define VINO_INTSTAT_B (VINO_INTSTAT_B_EOF | \ - VINO_INTSTAT_B_FIFO | \ - VINO_INTSTAT_B_EOD) - u32 _pad_intr_status; - volatile u32 intr_status; - - u32 _pad_i2c_control; - volatile u32 i2c_control; - u32 _pad_i2c_data; - volatile u32 i2c_data; - - struct sgi_vino_channel a; - struct sgi_vino_channel b; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vivi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vivi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vivi.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vivi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1344 +0,0 @@ -/* - * Virtual Video driver - This code emulates a real video device with v4l2 api - * - * Copyright (c) 2006 by: - * Mauro Carvalho Chehab - * Ted Walther - * John Sokol - * http://v4l.videotechnology.com/ - * - * Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski - * Copyright (c) 2010 Samsung Electronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the BSD Licence, GNU General Public License - * as published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VIVI_MODULE_NAME "vivi" - -/* Wake up at about 30 fps */ -#define WAKE_NUMERATOR 30 -#define WAKE_DENOMINATOR 1001 -#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ - -#define MAX_WIDTH 1920 -#define MAX_HEIGHT 1200 - -#define VIVI_MAJOR_VERSION 0 -#define VIVI_MINOR_VERSION 8 -#define VIVI_RELEASE 0 -#define VIVI_VERSION \ - KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) - -MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); -MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); -MODULE_LICENSE("Dual BSD/GPL"); - -static unsigned video_nr = -1; -module_param(video_nr, uint, 0644); -MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); - -static unsigned n_devs = 1; -module_param(n_devs, uint, 0644); -MODULE_PARM_DESC(n_devs, "number of video devices to create"); - -static unsigned debug; -module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); - -static unsigned int vid_limit = 16; -module_param(vid_limit, uint, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); - -/* Global font descriptor */ -static const u8 *font8x16; - -#define dprintk(dev, level, fmt, arg...) \ - v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) - -/* ------------------------------------------------------------------ - Basic structures - ------------------------------------------------------------------*/ - -struct vivi_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; -}; - -static struct vivi_fmt formats[] = { - { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - }, - { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - }, - { - .name = "RGB565 (LE)", - .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ - .depth = 16, - }, - { - .name = "RGB565 (BE)", - .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ - .depth = 16, - }, - { - .name = "RGB555 (LE)", - .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, - }, - { - .name = "RGB555 (BE)", - .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ - .depth = 16, - }, -}; - -static struct vivi_fmt *get_format(struct v4l2_format *f) -{ - struct vivi_fmt *fmt; - unsigned int k; - - for (k = 0; k < ARRAY_SIZE(formats); k++) { - fmt = &formats[k]; - if (fmt->fourcc == f->fmt.pix.pixelformat) - break; - } - - if (k == ARRAY_SIZE(formats)) - return NULL; - - return &formats[k]; -} - -/* buffer for one video frame */ -struct vivi_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_buffer vb; - struct list_head list; - struct vivi_fmt *fmt; -}; - -struct vivi_dmaqueue { - struct list_head active; - - /* thread for generating video stream*/ - struct task_struct *kthread; - wait_queue_head_t wq; - /* Counters to control fps rate */ - int frame; - int ini_jiffies; -}; - -static LIST_HEAD(vivi_devlist); - -struct vivi_dev { - struct list_head vivi_devlist; - struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler ctrl_handler; - - /* controls */ - struct v4l2_ctrl *brightness; - struct v4l2_ctrl *contrast; - struct v4l2_ctrl *saturation; - struct v4l2_ctrl *hue; - struct v4l2_ctrl *volume; - struct v4l2_ctrl *button; - struct v4l2_ctrl *boolean; - struct v4l2_ctrl *int32; - struct v4l2_ctrl *int64; - struct v4l2_ctrl *menu; - struct v4l2_ctrl *string; - - spinlock_t slock; - struct mutex mutex; - - /* various device info */ - struct video_device *vfd; - - struct vivi_dmaqueue vidq; - - /* Several counters */ - unsigned ms; - unsigned long jiffies; - unsigned button_pressed; - - int mv_count; /* Controls bars movement */ - - /* Input Number */ - int input; - - /* video capture */ - struct vivi_fmt *fmt; - unsigned int width, height; - struct vb2_queue vb_vidq; - enum v4l2_field field; - unsigned int field_count; - - u8 bars[9][3]; - u8 line[MAX_WIDTH * 4]; -}; - -/* ------------------------------------------------------------------ - DMA and thread functions - ------------------------------------------------------------------*/ - -/* Bars and Colors should match positions */ - -enum colors { - WHITE, - AMBER, - CYAN, - GREEN, - MAGENTA, - RED, - BLUE, - BLACK, - TEXT_BLACK, -}; - -/* R G B */ -#define COLOR_WHITE {204, 204, 204} -#define COLOR_AMBER {208, 208, 0} -#define COLOR_CYAN { 0, 206, 206} -#define COLOR_GREEN { 0, 239, 0} -#define COLOR_MAGENTA {239, 0, 239} -#define COLOR_RED {205, 0, 0} -#define COLOR_BLUE { 0, 0, 255} -#define COLOR_BLACK { 0, 0, 0} - -struct bar_std { - u8 bar[9][3]; -}; - -/* Maximum number of bars are 10 - otherwise, the input print code - should be modified */ -static struct bar_std bars[] = { - { /* Standard ITU-R color bar sequence */ - { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN, - COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK } - }, { - { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, - COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK } - }, { - { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, - COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK } - }, { - { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, - COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK } - }, -}; - -#define NUM_INPUTS ARRAY_SIZE(bars) - -#define TO_Y(r, g, b) \ - (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) -/* RGB to V(Cr) Color transform */ -#define TO_V(r, g, b) \ - (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) -/* RGB to U(Cb) Color transform */ -#define TO_U(r, g, b) \ - (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) - -/* precalculate color bar values to speed up rendering */ -static void precalculate_bars(struct vivi_dev *dev) -{ - u8 r, g, b; - int k, is_yuv; - - for (k = 0; k < 9; k++) { - r = bars[dev->input].bar[k][0]; - g = bars[dev->input].bar[k][1]; - b = bars[dev->input].bar[k][2]; - is_yuv = 0; - - switch (dev->fmt->fourcc) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - is_yuv = 1; - break; - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - r >>= 3; - g >>= 2; - b >>= 3; - break; - case V4L2_PIX_FMT_RGB555: - case V4L2_PIX_FMT_RGB555X: - r >>= 3; - g >>= 3; - b >>= 3; - break; - } - - if (is_yuv) { - dev->bars[k][0] = TO_Y(r, g, b); /* Luma */ - dev->bars[k][1] = TO_U(r, g, b); /* Cb */ - dev->bars[k][2] = TO_V(r, g, b); /* Cr */ - } else { - dev->bars[k][0] = r; - dev->bars[k][1] = g; - dev->bars[k][2] = b; - } - } -} - -#define TSTAMP_MIN_Y 24 -#define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15) -#define TSTAMP_INPUT_X 10 -#define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X) - -static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos) -{ - u8 r_y, g_u, b_v; - int color; - u8 *p; - - r_y = dev->bars[colorpos][0]; /* R or precalculated Y */ - g_u = dev->bars[colorpos][1]; /* G or precalculated U */ - b_v = dev->bars[colorpos][2]; /* B or precalculated V */ - - for (color = 0; color < 4; color++) { - p = buf + color; - - switch (dev->fmt->fourcc) { - case V4L2_PIX_FMT_YUYV: - switch (color) { - case 0: - case 2: - *p = r_y; - break; - case 1: - *p = g_u; - break; - case 3: - *p = b_v; - break; - } - break; - case V4L2_PIX_FMT_UYVY: - switch (color) { - case 1: - case 3: - *p = r_y; - break; - case 0: - *p = g_u; - break; - case 2: - *p = b_v; - break; - } - break; - case V4L2_PIX_FMT_RGB565: - switch (color) { - case 0: - case 2: - *p = (g_u << 5) | b_v; - break; - case 1: - case 3: - *p = (r_y << 3) | (g_u >> 3); - break; - } - break; - case V4L2_PIX_FMT_RGB565X: - switch (color) { - case 0: - case 2: - *p = (r_y << 3) | (g_u >> 3); - break; - case 1: - case 3: - *p = (g_u << 5) | b_v; - break; - } - break; - case V4L2_PIX_FMT_RGB555: - switch (color) { - case 0: - case 2: - *p = (g_u << 5) | b_v; - break; - case 1: - case 3: - *p = (r_y << 2) | (g_u >> 3); - break; - } - break; - case V4L2_PIX_FMT_RGB555X: - switch (color) { - case 0: - case 2: - *p = (r_y << 2) | (g_u >> 3); - break; - case 1: - case 3: - *p = (g_u << 5) | b_v; - break; - } - break; - } - } -} - -static void precalculate_line(struct vivi_dev *dev) -{ - int w; - - for (w = 0; w < dev->width * 2; w += 2) { - int colorpos = (w / (dev->width / 8) % 8); - - gen_twopix(dev, dev->line + w * 2, colorpos); - } -} - -static void gen_text(struct vivi_dev *dev, char *basep, - int y, int x, char *text) -{ - int line; - - /* Checks if it is possible to show string */ - if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width) - return; - - /* Print stream time */ - for (line = y; line < y + 16; line++) { - int j = 0; - char *pos = basep + line * dev->width * 2 + x * 2; - char *s; - - for (s = text; *s; s++) { - u8 chr = font8x16[*s * 16 + line - y]; - int i; - - for (i = 0; i < 7; i++, j++) { - /* Draw white font on black background */ - if (chr & (1 << (7 - i))) - gen_twopix(dev, pos + j * 2, WHITE); - else - gen_twopix(dev, pos + j * 2, TEXT_BLACK); - } - } - } -} - -static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) -{ - int wmax = dev->width; - int hmax = dev->height; - struct timeval ts; - void *vbuf = vb2_plane_vaddr(&buf->vb, 0); - unsigned ms; - char str[100]; - int h, line = 1; - - if (!vbuf) - return; - - for (h = 0; h < hmax; h++) - memcpy(vbuf + h * wmax * 2, dev->line + (dev->mv_count % wmax) * 2, wmax * 2); - - /* Updates stream time */ - - dev->ms += jiffies_to_msecs(jiffies - dev->jiffies); - dev->jiffies = jiffies; - ms = dev->ms; - snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ", - (ms / (60 * 60 * 1000)) % 24, - (ms / (60 * 1000)) % 60, - (ms / 1000) % 60, - ms % 1000); - gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " %dx%d, input %d ", - dev->width, dev->height, dev->input); - gen_text(dev, vbuf, line++ * 16, 16, str); - - mutex_lock(&dev->ctrl_handler.lock); - snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ", - dev->brightness->cur.val, - dev->contrast->cur.val, - dev->saturation->cur.val, - dev->hue->cur.val); - gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " volume %3d ", dev->volume->cur.val); - gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " int32 %d, int64 %lld ", - dev->int32->cur.val, - dev->int64->cur.val64); - gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", - dev->boolean->cur.val, - dev->menu->qmenu[dev->menu->cur.val], - dev->string->cur.string); - mutex_unlock(&dev->ctrl_handler.lock); - gen_text(dev, vbuf, line++ * 16, 16, str); - if (dev->button_pressed) { - dev->button_pressed--; - snprintf(str, sizeof(str), " button pressed!"); - gen_text(dev, vbuf, line++ * 16, 16, str); - } - - dev->mv_count += 2; - - buf->vb.v4l2_buf.field = dev->field; - dev->field_count++; - buf->vb.v4l2_buf.sequence = dev->field_count >> 1; - do_gettimeofday(&ts); - buf->vb.v4l2_buf.timestamp = ts; -} - -static void vivi_thread_tick(struct vivi_dev *dev) -{ - struct vivi_dmaqueue *dma_q = &dev->vidq; - struct vivi_buffer *buf; - unsigned long flags = 0; - - dprintk(dev, 1, "Thread tick\n"); - - spin_lock_irqsave(&dev->slock, flags); - if (list_empty(&dma_q->active)) { - dprintk(dev, 1, "No active queue to serve\n"); - goto unlock; - } - - buf = list_entry(dma_q->active.next, struct vivi_buffer, list); - list_del(&buf->list); - - do_gettimeofday(&buf->vb.v4l2_buf.timestamp); - - /* Fill buffer */ - vivi_fillbuff(dev, buf); - dprintk(dev, 1, "filled buffer %p\n", buf); - - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); - dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); -unlock: - spin_unlock_irqrestore(&dev->slock, flags); -} - -#define frames_to_ms(frames) \ - ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) - -static void vivi_sleep(struct vivi_dev *dev) -{ - struct vivi_dmaqueue *dma_q = &dev->vidq; - int timeout; - DECLARE_WAITQUEUE(wait, current); - - dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__, - (unsigned long)dma_q); - - add_wait_queue(&dma_q->wq, &wait); - if (kthread_should_stop()) - goto stop_task; - - /* Calculate time to wake up */ - timeout = msecs_to_jiffies(frames_to_ms(1)); - - vivi_thread_tick(dev); - - schedule_timeout_interruptible(timeout); - -stop_task: - remove_wait_queue(&dma_q->wq, &wait); - try_to_freeze(); -} - -static int vivi_thread(void *data) -{ - struct vivi_dev *dev = data; - - dprintk(dev, 1, "thread started\n"); - - set_freezable(); - - for (;;) { - vivi_sleep(dev); - - if (kthread_should_stop()) - break; - } - dprintk(dev, 1, "thread: exit\n"); - return 0; -} - -static int vivi_start_generating(struct vivi_dev *dev) -{ - struct vivi_dmaqueue *dma_q = &dev->vidq; - - dprintk(dev, 1, "%s\n", __func__); - - /* Resets frame counters */ - dev->ms = 0; - dev->mv_count = 0; - dev->jiffies = jiffies; - - dma_q->frame = 0; - dma_q->ini_jiffies = jiffies; - dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name); - - if (IS_ERR(dma_q->kthread)) { - v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); - return PTR_ERR(dma_q->kthread); - } - /* Wakes thread */ - wake_up_interruptible(&dma_q->wq); - - dprintk(dev, 1, "returning from %s\n", __func__); - return 0; -} - -static void vivi_stop_generating(struct vivi_dev *dev) -{ - struct vivi_dmaqueue *dma_q = &dev->vidq; - - dprintk(dev, 1, "%s\n", __func__); - - /* shutdown control thread */ - if (dma_q->kthread) { - kthread_stop(dma_q->kthread); - dma_q->kthread = NULL; - } - - /* - * Typical driver might need to wait here until dma engine stops. - * In this case we can abort imiedetly, so it's just a noop. - */ - - /* Release all active buffers */ - while (!list_empty(&dma_q->active)) { - struct vivi_buffer *buf; - buf = list_entry(dma_q->active.next, struct vivi_buffer, list); - list_del(&buf->list); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); - } -} -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned long sizes[], - void *alloc_ctxs[]) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - unsigned long size; - - size = dev->width * dev->height * 2; - - if (0 == *nbuffers) - *nbuffers = 32; - - while (size * *nbuffers > vid_limit * 1024 * 1024) - (*nbuffers)--; - - *nplanes = 1; - - sizes[0] = size; - - /* - * videobuf2-vmalloc allocator is context-less so no need to set - * alloc_ctxs array. - */ - - dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__, - *nbuffers, size); - - return 0; -} - -static int buffer_init(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - BUG_ON(NULL == dev->fmt); - - /* - * This callback is called once per buffer, after its allocation. - * - * Vivi does not allow changing format during streaming, but it is - * possible to do so when streaming is paused (i.e. in streamoff state). - * Buffers however are not freed when going into streamoff and so - * buffer size verification has to be done in buffer_prepare, on each - * qbuf. - * It would be best to move verification code here to buf_init and - * s_fmt though. - */ - - return 0; -} - -static int buffer_prepare(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); - unsigned long size; - - dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field); - - BUG_ON(NULL == dev->fmt); - - /* - * Theses properties only change when queue is idle, see s_fmt. - * The below checks should not be performed here, on each - * buffer_prepare (i.e. on each qbuf). Most of the code in this function - * should thus be moved to buffer_init and s_fmt. - */ - if (dev->width < 48 || dev->width > MAX_WIDTH || - dev->height < 32 || dev->height > MAX_HEIGHT) - return -EINVAL; - - size = dev->width * dev->height * 2; - if (vb2_plane_size(vb, 0) < size) { - dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - - vb2_set_plane_payload(&buf->vb, 0, size); - - buf->fmt = dev->fmt; - - precalculate_bars(dev); - precalculate_line(dev); - - return 0; -} - -static int buffer_finish(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - dprintk(dev, 1, "%s\n", __func__); - return 0; -} - -static void buffer_cleanup(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - dprintk(dev, 1, "%s\n", __func__); - -} - -static void buffer_queue(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); - struct vivi_dmaqueue *vidq = &dev->vidq; - unsigned long flags = 0; - - dprintk(dev, 1, "%s\n", __func__); - - spin_lock_irqsave(&dev->slock, flags); - list_add_tail(&buf->list, &vidq->active); - spin_unlock_irqrestore(&dev->slock, flags); -} - -static int start_streaming(struct vb2_queue *vq) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - dprintk(dev, 1, "%s\n", __func__); - return vivi_start_generating(dev); -} - -/* abort streaming and wait for last buffer */ -static int stop_streaming(struct vb2_queue *vq) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - dprintk(dev, 1, "%s\n", __func__); - vivi_stop_generating(dev); - return 0; -} - -static void vivi_lock(struct vb2_queue *vq) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - mutex_lock(&dev->mutex); -} - -static void vivi_unlock(struct vb2_queue *vq) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - mutex_unlock(&dev->mutex); -} - - -static struct vb2_ops vivi_video_qops = { - .queue_setup = queue_setup, - .buf_init = buffer_init, - .buf_prepare = buffer_prepare, - .buf_finish = buffer_finish, - .buf_cleanup = buffer_cleanup, - .buf_queue = buffer_queue, - .start_streaming = start_streaming, - .stop_streaming = stop_streaming, - .wait_prepare = vivi_unlock, - .wait_finish = vivi_lock, -}; - -/* ------------------------------------------------------------------ - IOCTL vidioc handling - ------------------------------------------------------------------*/ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vivi_dev *dev = video_drvdata(file); - - strcpy(cap->driver, "vivi"); - strcpy(cap->card, "vivi"); - strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); - cap->version = VIVI_VERSION; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \ - V4L2_CAP_READWRITE; - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vivi_fmt *fmt; - - if (f->index >= ARRAY_SIZE(formats)) - return -EINVAL; - - fmt = &formats[f->index]; - - strlcpy(f->description, fmt->name, sizeof(f->description)); - f->pixelformat = fmt->fourcc; - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivi_dev *dev = video_drvdata(file); - - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - f->fmt.pix.field = dev->field; - f->fmt.pix.pixelformat = dev->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * dev->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivi_dev *dev = video_drvdata(file); - struct vivi_fmt *fmt; - enum v4l2_field field; - - fmt = get_format(f); - if (!fmt) { - dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - field = f->fmt.pix.field; - - if (field == V4L2_FIELD_ANY) { - field = V4L2_FIELD_INTERLACED; - } else if (V4L2_FIELD_INTERLACED != field) { - dprintk(dev, 1, "Field type invalid.\n"); - return -EINVAL; - } - - f->fmt.pix.field = field; - v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2, - &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0); - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivi_dev *dev = video_drvdata(file); - struct vb2_queue *q = &dev->vb_vidq; - - int ret = vidioc_try_fmt_vid_cap(file, priv, f); - if (ret < 0) - return ret; - - if (vb2_is_streaming(q)) { - dprintk(dev, 1, "%s device busy\n", __func__); - return -EBUSY; - } - - dev->fmt = get_format(f); - dev->width = f->fmt.pix.width; - dev->height = f->fmt.pix.height; - dev->field = f->fmt.pix.field; - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_reqbufs(&dev->vb_vidq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_querybuf(&dev->vb_vidq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_qbuf(&dev->vb_vidq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_streamon(&dev->vb_vidq, i); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_streamoff(&dev->vb_vidq, i); -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) -{ - return 0; -} - -/* only one input in this sample driver */ -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - if (inp->index >= NUM_INPUTS) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = V4L2_STD_525_60; - sprintf(inp->name, "Camera %u", inp->index); - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct vivi_dev *dev = video_drvdata(file); - - *i = dev->input; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct vivi_dev *dev = video_drvdata(file); - - if (i >= NUM_INPUTS) - return -EINVAL; - - dev->input = i; - precalculate_bars(dev); - precalculate_line(dev); - return 0; -} - -/* --- controls ---------------------------------------------- */ - -static int vivi_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler); - - if (ctrl == dev->button) - dev->button_pressed = 30; - return 0; -} - -/* ------------------------------------------------------------------ - File operations for the device - ------------------------------------------------------------------*/ - -static ssize_t -vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct vivi_dev *dev = video_drvdata(file); - - dprintk(dev, 1, "read called\n"); - return vb2_read(&dev->vb_vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); -} - -static unsigned int -vivi_poll(struct file *file, struct poll_table_struct *wait) -{ - struct vivi_dev *dev = video_drvdata(file); - struct vb2_queue *q = &dev->vb_vidq; - - dprintk(dev, 1, "%s\n", __func__); - return vb2_poll(q, file, wait); -} - -static int vivi_close(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct vivi_dev *dev = video_drvdata(file); - - dprintk(dev, 1, "close called (dev=%s), file %p\n", - video_device_node_name(vdev), file); - - if (v4l2_fh_is_singular_file(file)) - vb2_queue_release(&dev->vb_vidq); - return v4l2_fh_release(file); -} - -static int vivi_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct vivi_dev *dev = video_drvdata(file); - int ret; - - dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); - - ret = vb2_mmap(&dev->vb_vidq, vma); - dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, - ret); - return ret; -} - -static const struct v4l2_ctrl_ops vivi_ctrl_ops = { - .s_ctrl = vivi_s_ctrl, -}; - -#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) - -static const struct v4l2_ctrl_config vivi_ctrl_button = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 0, - .name = "Button", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_boolean = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 1, - .name = "Boolean", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .min = 0, - .max = 1, - .step = 1, - .def = 1, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_int32 = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 2, - .name = "Integer 32 Bits", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0x80000000, - .max = 0x7fffffff, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_int64 = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 3, - .name = "Integer 64 Bits", - .type = V4L2_CTRL_TYPE_INTEGER64, -}; - -static const char * const vivi_ctrl_menu_strings[] = { - "Menu Item 0 (Skipped)", - "Menu Item 1", - "Menu Item 2 (Skipped)", - "Menu Item 3", - "Menu Item 4", - "Menu Item 5 (Skipped)", - NULL, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_menu = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 4, - .name = "Menu", - .type = V4L2_CTRL_TYPE_MENU, - .min = 1, - .max = 4, - .def = 3, - .menu_skip_mask = 0x04, - .qmenu = vivi_ctrl_menu_strings, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_string = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 5, - .name = "String", - .type = V4L2_CTRL_TYPE_STRING, - .min = 2, - .max = 4, - .step = 1, -}; - -static const struct v4l2_file_operations vivi_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vivi_close, - .read = vivi_read, - .poll = vivi_poll, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = vivi_mmap, -}; - -static const struct v4l2_ioctl_ops vivi_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, -}; - -static struct video_device vivi_template = { - .name = "vivi", - .fops = &vivi_fops, - .ioctl_ops = &vivi_ioctl_ops, - .release = video_device_release, - - .tvnorms = V4L2_STD_525_60, - .current_norm = V4L2_STD_NTSC_M, -}; - -/* ----------------------------------------------------------------- - Initialization and module stuff - ------------------------------------------------------------------*/ - -static int vivi_release(void) -{ - struct vivi_dev *dev; - struct list_head *list; - - while (!list_empty(&vivi_devlist)) { - list = vivi_devlist.next; - list_del(list); - dev = list_entry(list, struct vivi_dev, vivi_devlist); - - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(dev->vfd)); - video_unregister_device(dev->vfd); - v4l2_device_unregister(&dev->v4l2_dev); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - } - - return 0; -} - -static int __init vivi_create_instance(int inst) -{ - struct vivi_dev *dev; - struct video_device *vfd; - struct v4l2_ctrl_handler *hdl; - struct vb2_queue *q; - int ret; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), - "%s-%03d", VIVI_MODULE_NAME, inst); - ret = v4l2_device_register(NULL, &dev->v4l2_dev); - if (ret) - goto free_dev; - - dev->fmt = &formats[0]; - dev->width = 640; - dev->height = 480; - hdl = &dev->ctrl_handler; - v4l2_ctrl_handler_init(hdl, 11); - dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); - dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); - dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 16); - dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 127); - dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL); - dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL); - dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL); - dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL); - dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL); - dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL); - if (hdl->error) { - ret = hdl->error; - goto unreg_dev; - } - dev->v4l2_dev.ctrl_handler = hdl; - - /* initialize locks */ - spin_lock_init(&dev->slock); - - /* initialize queue */ - q = &dev->vb_vidq; - memset(q, 0, sizeof(dev->vb_vidq)); - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivi_buffer); - q->ops = &vivi_video_qops; - q->mem_ops = &vb2_vmalloc_memops; - - vb2_queue_init(q); - - mutex_init(&dev->mutex); - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - init_waitqueue_head(&dev->vidq.wq); - - ret = -ENOMEM; - vfd = video_device_alloc(); - if (!vfd) - goto unreg_dev; - - *vfd = vivi_template; - vfd->debug = debug; - vfd->v4l2_dev = &dev->v4l2_dev; - set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); - - /* - * Provide a mutex to v4l2 core. It will be used to protect - * all fops and v4l2 ioctls. - */ - vfd->lock = &dev->mutex; - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); - if (ret < 0) - goto rel_vdev; - - video_set_drvdata(vfd, dev); - - /* Now that everything is fine, let's add it to device list */ - list_add_tail(&dev->vivi_devlist, &vivi_devlist); - - if (video_nr != -1) - video_nr++; - - dev->vfd = vfd; - v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", - video_device_node_name(vfd)); - return 0; - -rel_vdev: - video_device_release(vfd); -unreg_dev: - v4l2_ctrl_handler_free(hdl); - v4l2_device_unregister(&dev->v4l2_dev); -free_dev: - kfree(dev); - return ret; -} - -/* This routine allocates from 1 to n_devs virtual drivers. - - The real maximum number of virtual drivers will depend on how many drivers - will succeed. This is limited to the maximum number of devices that - videodev supports, which is equal to VIDEO_NUM_DEVICES. - */ -static int __init vivi_init(void) -{ - const struct font_desc *font = find_font("VGA8x16"); - int ret = 0, i; - - if (font == NULL) { - printk(KERN_ERR "vivi: could not find font\n"); - return -ENODEV; - } - font8x16 = font->data; - - if (n_devs <= 0) - n_devs = 1; - - for (i = 0; i < n_devs; i++) { - ret = vivi_create_instance(i); - if (ret) { - /* If some instantiations succeeded, keep driver */ - if (i) - ret = 0; - break; - } - } - - if (ret < 0) { - printk(KERN_ERR "vivi: error %d while loading driver\n", ret); - return ret; - } - - printk(KERN_INFO "Video Technology Magazine Virtual Video " - "Capture Board ver %u.%u.%u successfully loaded.\n", - (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, - VIVI_VERSION & 0xFF); - - /* n_devs will reflect the actual number of allocated devices */ - n_devs = i; - - return ret; -} - -static void __exit vivi_exit(void) -{ - vivi_release(); -} - -module_init(vivi_init); -module_exit(vivi_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vp27smpx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vp27smpx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vp27smpx.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vp27smpx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,222 +0,0 @@ -/* - * vp27smpx - driver version 0.0.1 - * - * Copyright (C) 2007 Hans Verkuil - * - * Based on a tvaudio patch from Takahiro Adachi - * and Kazuhiko Kawakami - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("vp27smpx driver"); -MODULE_AUTHOR("Hans Verkuil"); -MODULE_LICENSE("GPL"); - - -/* ----------------------------------------------------------------------- */ - -struct vp27smpx_state { - struct v4l2_subdev sd; - int radio; - u32 audmode; -}; - -static inline struct vp27smpx_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct vp27smpx_state, sd); -} - -static void vp27smpx_set_audmode(struct v4l2_subdev *sd, u32 audmode) -{ - struct vp27smpx_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 data[3] = { 0x00, 0x00, 0x04 }; - - switch (audmode) { - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - data[1] = 0x01; - break; - case V4L2_TUNER_MODE_LANG2: - data[1] = 0x02; - break; - } - - if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) - v4l2_err(sd, "I/O error setting audmode\n"); - else - state->audmode = audmode; -} - -static int vp27smpx_s_radio(struct v4l2_subdev *sd) -{ - struct vp27smpx_state *state = to_state(sd); - - state->radio = 1; - return 0; -} - -static int vp27smpx_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - struct vp27smpx_state *state = to_state(sd); - - state->radio = 0; - return 0; -} - -static int vp27smpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct vp27smpx_state *state = to_state(sd); - - if (!state->radio) - vp27smpx_set_audmode(sd, vt->audmode); - return 0; -} - -static int vp27smpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct vp27smpx_state *state = to_state(sd); - - if (state->radio) - return 0; - vt->audmode = state->audmode; - vt->capability = V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - return 0; -} - -static int vp27smpx_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VP27SMPX, 0); -} - -static int vp27smpx_log_status(struct v4l2_subdev *sd) -{ - struct vp27smpx_state *state = to_state(sd); - - v4l2_info(sd, "Audio Mode: %u%s\n", state->audmode, - state->radio ? " (Radio)" : ""); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops vp27smpx_core_ops = { - .log_status = vp27smpx_log_status, - .g_chip_ident = vp27smpx_g_chip_ident, - .s_std = vp27smpx_s_std, -}; - -static const struct v4l2_subdev_tuner_ops vp27smpx_tuner_ops = { - .s_radio = vp27smpx_s_radio, - .s_tuner = vp27smpx_s_tuner, - .g_tuner = vp27smpx_g_tuner, -}; - -static const struct v4l2_subdev_ops vp27smpx_ops = { - .core = &vp27smpx_core_ops, - .tuner = &vp27smpx_tuner_ops, -}; - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ - -/* - * Generic i2c probe - * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' - */ - -static int vp27smpx_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct vp27smpx_state *state; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &vp27smpx_ops); - state->audmode = V4L2_TUNER_MODE_STEREO; - - /* initialize vp27smpx */ - vp27smpx_set_audmode(sd, state->audmode); - return 0; -} - -static int vp27smpx_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id vp27smpx_id[] = { - { "vp27smpx", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, vp27smpx_id); - -static struct i2c_driver vp27smpx_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "vp27smpx", - }, - .probe = vp27smpx_probe, - .remove = vp27smpx_remove, - .id_table = vp27smpx_id, -}; - -static __init int init_vp27smpx(void) -{ - return i2c_add_driver(&vp27smpx_driver); -} - -static __exit void exit_vp27smpx(void) -{ - i2c_del_driver(&vp27smpx_driver); -} - -module_init(init_vp27smpx); -module_exit(exit_vp27smpx); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vpx3220.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vpx3220.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vpx3220.c 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/vpx3220.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,602 +0,0 @@ -/* - * vpx3220a, vpx3216b & vpx3214c video decoder driver version 0.0.1 - * - * Copyright (C) 2001 Laurent Pinchart - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); -MODULE_AUTHOR("Laurent Pinchart"); -MODULE_LICENSE("GPL"); - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -#define VPX_TIMEOUT_COUNT 10 - -/* ----------------------------------------------------------------------- */ - -struct vpx3220 { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - unsigned char reg[255]; - - v4l2_std_id norm; - int ident; - int input; - int enable; -}; - -static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd) -{ - return container_of(sd, struct vpx3220, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct vpx3220, hdl)->sd; -} - -static char *inputs[] = { "internal", "composite", "svideo" }; - -/* ----------------------------------------------------------------------- */ - -static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct vpx3220 *decoder = i2c_get_clientdata(client); - - decoder->reg[reg] = value; - return i2c_smbus_write_byte_data(client, reg, value); -} - -static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return i2c_smbus_read_byte_data(client, reg); -} - -static int vpx3220_fp_status(struct v4l2_subdev *sd) -{ - unsigned char status; - unsigned int i; - - for (i = 0; i < VPX_TIMEOUT_COUNT; i++) { - status = vpx3220_read(sd, 0x29); - - if (!(status & 4)) - return 0; - - udelay(10); - - if (need_resched()) - cond_resched(); - } - - return -1; -} - -static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* Write the 16-bit address to the FPWR register */ - if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) { - v4l2_dbg(1, debug, sd, "%s: failed\n", __func__); - return -1; - } - - if (vpx3220_fp_status(sd) < 0) - return -1; - - /* Write the 16-bit data to the FPDAT register */ - if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) { - v4l2_dbg(1, debug, sd, "%s: failed\n", __func__); - return -1; - } - - return 0; -} - -static u16 vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - s16 data; - - /* Write the 16-bit address to the FPRD register */ - if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) { - v4l2_dbg(1, debug, sd, "%s: failed\n", __func__); - return -1; - } - - if (vpx3220_fp_status(sd) < 0) - return -1; - - /* Read the 16-bit data from the FPDAT register */ - data = i2c_smbus_read_word_data(client, 0x28); - if (data == -1) { - v4l2_dbg(1, debug, sd, "%s: failed\n", __func__); - return -1; - } - - return swab16(data); -} - -static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len) -{ - u8 reg; - int ret = -1; - - while (len >= 2) { - reg = *data++; - ret = vpx3220_write(sd, reg, *data++); - if (ret < 0) - break; - len -= 2; - } - - return ret; -} - -static int vpx3220_write_fp_block(struct v4l2_subdev *sd, - const u16 *data, unsigned int len) -{ - u8 reg; - int ret = 0; - - while (len > 1) { - reg = *data++; - ret |= vpx3220_fp_write(sd, reg, *data++); - len -= 2; - } - - return ret; -} - -/* ---------------------------------------------------------------------- */ - -static const unsigned short init_ntsc[] = { - 0x1c, 0x00, /* NTSC tint angle */ - 0x88, 17, /* Window 1 vertical */ - 0x89, 240, /* Vertical lines in */ - 0x8a, 240, /* Vertical lines out */ - 0x8b, 000, /* Horizontal begin */ - 0x8c, 640, /* Horizontal length */ - 0x8d, 640, /* Number of pixels */ - 0x8f, 0xc00, /* Disable window 2 */ - 0xf0, 0x73, /* 13.5 MHz transport, Forced - * mode, latch windows */ - 0xf2, 0x13, /* NTSC M, composite input */ - 0xe7, 0x1e1, /* Enable vertical standard - * locking @ 240 lines */ -}; - -static const unsigned short init_pal[] = { - 0x88, 23, /* Window 1 vertical begin */ - 0x89, 288, /* Vertical lines in (16 lines - * skipped by the VFE) */ - 0x8a, 288, /* Vertical lines out (16 lines - * skipped by the VFE) */ - 0x8b, 16, /* Horizontal begin */ - 0x8c, 768, /* Horizontal length */ - 0x8d, 784, /* Number of pixels - * Must be >= Horizontal begin + Horizontal length */ - 0x8f, 0xc00, /* Disable window 2 */ - 0xf0, 0x77, /* 13.5 MHz transport, Forced - * mode, latch windows */ - 0xf2, 0x3d1, /* PAL B,G,H,I, composite input */ - 0xe7, 0x241, /* PAL/SECAM set to 288 lines */ -}; - -static const unsigned short init_secam[] = { - 0x88, 23, /* Window 1 vertical begin */ - 0x89, 288, /* Vertical lines in (16 lines - * skipped by the VFE) */ - 0x8a, 288, /* Vertical lines out (16 lines - * skipped by the VFE) */ - 0x8b, 16, /* Horizontal begin */ - 0x8c, 768, /* Horizontal length */ - 0x8d, 784, /* Number of pixels - * Must be >= Horizontal begin + Horizontal length */ - 0x8f, 0xc00, /* Disable window 2 */ - 0xf0, 0x77, /* 13.5 MHz transport, Forced - * mode, latch windows */ - 0xf2, 0x3d5, /* SECAM, composite input */ - 0xe7, 0x241, /* PAL/SECAM set to 288 lines */ -}; - -static const unsigned char init_common[] = { - 0xf2, 0x00, /* Disable all outputs */ - 0x33, 0x0d, /* Luma : VIN2, Chroma : CIN - * (clamp off) */ - 0xd8, 0xa8, /* HREF/VREF active high, VREF - * pulse = 2, Odd/Even flag */ - 0x20, 0x03, /* IF compensation 0dB/oct */ - 0xe0, 0xff, /* Open up all comparators */ - 0xe1, 0x00, - 0xe2, 0x7f, - 0xe3, 0x80, - 0xe4, 0x7f, - 0xe5, 0x80, - 0xe6, 0x00, /* Brightness set to 0 */ - 0xe7, 0xe0, /* Contrast to 1.0, noise shaping - * 10 to 8 2-bit error diffusion */ - 0xe8, 0xf8, /* YUV422, CbCr binary offset, - * ... (p.32) */ - 0xea, 0x18, /* LLC2 connected, output FIFO - * reset with VACTintern */ - 0xf0, 0x8a, /* Half full level to 10, bus - * shuffler [7:0, 23:16, 15:8] */ - 0xf1, 0x18, /* Single clock, sync mode, no - * FE delay, no HLEN counter */ - 0xf8, 0x12, /* Port A, PIXCLK, HF# & FE# - * strength to 2 */ - 0xf9, 0x24, /* Port B, HREF, VREF, PREF & - * ALPHA strength to 4 */ -}; - -static const unsigned short init_fp[] = { - 0x59, 0, - 0xa0, 2070, /* ACC reference */ - 0xa3, 0, - 0xa4, 0, - 0xa8, 30, - 0xb2, 768, - 0xbe, 27, - 0x58, 0, - 0x26, 0, - 0x4b, 0x298, /* PLL gain */ -}; - - -static int vpx3220_init(struct v4l2_subdev *sd, u32 val) -{ - struct vpx3220 *decoder = to_vpx3220(sd); - - vpx3220_write_block(sd, init_common, sizeof(init_common)); - vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1); - if (decoder->norm & V4L2_STD_NTSC) - vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1); - else if (decoder->norm & V4L2_STD_PAL) - vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1); - else if (decoder->norm & V4L2_STD_SECAM) - vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1); - else - vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1); - return 0; -} - -static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) -{ - int res = V4L2_IN_ST_NO_SIGNAL, status; - v4l2_std_id std = 0; - - status = vpx3220_fp_read(sd, 0x0f3); - - v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status); - - if (status < 0) - return status; - - if ((status & 0x20) == 0) { - res = 0; - - switch (status & 0x18) { - case 0x00: - case 0x10: - case 0x14: - case 0x18: - std = V4L2_STD_PAL; - break; - - case 0x08: - std = V4L2_STD_SECAM; - break; - - case 0x04: - case 0x0c: - case 0x1c: - std = V4L2_STD_NTSC; - break; - } - } - if (pstd) - *pstd = std; - if (pstatus) - *pstatus = status; - return 0; -} - -static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) -{ - v4l2_dbg(1, debug, sd, "querystd\n"); - return vpx3220_status(sd, NULL, std); -} - -static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status) -{ - v4l2_dbg(1, debug, sd, "g_input_status\n"); - return vpx3220_status(sd, status, NULL); -} - -static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -{ - struct vpx3220 *decoder = to_vpx3220(sd); - int temp_input; - - /* Here we back up the input selection because it gets - overwritten when we fill the registers with the - choosen video norm */ - temp_input = vpx3220_fp_read(sd, 0xf2); - - v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std); - if (std & V4L2_STD_NTSC) { - vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1); - v4l2_dbg(1, debug, sd, "norm switched to NTSC\n"); - } else if (std & V4L2_STD_PAL) { - vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1); - v4l2_dbg(1, debug, sd, "norm switched to PAL\n"); - } else if (std & V4L2_STD_SECAM) { - vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1); - v4l2_dbg(1, debug, sd, "norm switched to SECAM\n"); - } else { - return -EINVAL; - } - - decoder->norm = std; - - /* And here we set the backed up video input again */ - vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010); - udelay(10); - return 0; -} - -static int vpx3220_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - int data; - - /* RJ: input = 0: ST8 (PCTV) input - input = 1: COMPOSITE input - input = 2: SVHS input */ - - const int input_vals[3][2] = { - {0x0c, 0}, - {0x0d, 0}, - {0x0e, 1} - }; - - if (input > 2) - return -EINVAL; - - v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[input]); - - vpx3220_write(sd, 0x33, input_vals[input][0]); - - data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020); - if (data < 0) - return data; - /* 0x0010 is required to latch the setting */ - vpx3220_fp_write(sd, 0xf2, - data | (input_vals[input][1] << 5) | 0x0010); - - udelay(10); - return 0; -} - -static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable) -{ - v4l2_dbg(1, debug, sd, "s_stream %s\n", enable ? "on" : "off"); - - vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00)); - return 0; -} - -static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - vpx3220_write(sd, 0xe6, ctrl->val); - return 0; - case V4L2_CID_CONTRAST: - /* Bit 7 and 8 is for noise shaping */ - vpx3220_write(sd, 0xe7, ctrl->val + 192); - return 0; - case V4L2_CID_SATURATION: - vpx3220_fp_write(sd, 0xa0, ctrl->val); - return 0; - case V4L2_CID_HUE: - vpx3220_fp_write(sd, 0x1c, ctrl->val); - return 0; - } - return -EINVAL; -} - -static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct vpx3220 *decoder = to_vpx3220(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0); -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = { - .s_ctrl = vpx3220_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops vpx3220_core_ops = { - .g_chip_ident = vpx3220_g_chip_ident, - .init = vpx3220_init, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = vpx3220_s_std, -}; - -static const struct v4l2_subdev_video_ops vpx3220_video_ops = { - .s_routing = vpx3220_s_routing, - .s_stream = vpx3220_s_stream, - .querystd = vpx3220_querystd, - .g_input_status = vpx3220_g_input_status, -}; - -static const struct v4l2_subdev_ops vpx3220_ops = { - .core = &vpx3220_core_ops, - .video = &vpx3220_video_ops, -}; - -/* ----------------------------------------------------------------------- - * Client management code - */ - -static int vpx3220_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct vpx3220 *decoder; - struct v4l2_subdev *sd; - const char *name = NULL; - u8 ver; - u16 pn; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) - return -ENODEV; - - decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL); - if (decoder == NULL) - return -ENOMEM; - sd = &decoder->sd; - v4l2_i2c_subdev_init(sd, client, &vpx3220_ops); - decoder->norm = V4L2_STD_PAL; - decoder->input = 0; - decoder->enable = 1; - v4l2_ctrl_handler_init(&decoder->hdl, 4); - v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, - V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); - v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, - V4L2_CID_CONTRAST, 0, 63, 1, 32); - v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, - V4L2_CID_SATURATION, 0, 4095, 1, 2048); - v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, - V4L2_CID_HUE, -512, 511, 1, 0); - sd->ctrl_handler = &decoder->hdl; - if (decoder->hdl.error) { - int err = decoder->hdl.error; - - v4l2_ctrl_handler_free(&decoder->hdl); - kfree(decoder); - return err; - } - v4l2_ctrl_handler_setup(&decoder->hdl); - - ver = i2c_smbus_read_byte_data(client, 0x00); - pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) + - i2c_smbus_read_byte_data(client, 0x01); - decoder->ident = V4L2_IDENT_VPX3220A; - if (ver == 0xec) { - switch (pn) { - case 0x4680: - name = "vpx3220a"; - break; - case 0x4260: - name = "vpx3216b"; - decoder->ident = V4L2_IDENT_VPX3216B; - break; - case 0x4280: - name = "vpx3214c"; - decoder->ident = V4L2_IDENT_VPX3214C; - break; - } - } - if (name) - v4l2_info(sd, "%s found @ 0x%x (%s)\n", name, - client->addr << 1, client->adapter->name); - else - v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n", - ver, pn, client->addr << 1, client->adapter->name); - - vpx3220_write_block(sd, init_common, sizeof(init_common)); - vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1); - /* Default to PAL */ - vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1); - return 0; -} - -static int vpx3220_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct vpx3220 *decoder = to_vpx3220(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&decoder->hdl); - kfree(decoder); - return 0; -} - -static const struct i2c_device_id vpx3220_id[] = { - { "vpx3220a", 0 }, - { "vpx3216b", 0 }, - { "vpx3214c", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, vpx3220_id); - -static struct i2c_driver vpx3220_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "vpx3220", - }, - .probe = vpx3220_probe, - .remove = vpx3220_remove, - .id_table = vpx3220_id, -}; - -static __init int init_vpx3220(void) -{ - return i2c_add_driver(&vpx3220_driver); -} - -static __exit void exit_vpx3220(void) -{ - i2c_del_driver(&vpx3220_driver); -} - -module_init(init_vpx3220); -module_exit(exit_vpx3220); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/w9966.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/w9966.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/w9966.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/w9966.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,995 +0,0 @@ -/* - Winbond w9966cf Webcam parport driver. - - Version 0.33 - - Copyright (C) 2001 Jakob Kemi - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - Supported devices: - *Lifeview FlyCam Supra (using the Philips saa7111a chip) - - Does any other model using the w9966 interface chip exist ? - - Todo: - - *Add a working EPP mode, since DMA ECP read isn't implemented - in the parport drivers. (That's why it's so sloow) - - *Add support for other ccd-control chips than the saa7111 - please send me feedback on what kind of chips you have. - - *Add proper probing. I don't know what's wrong with the IEEE1284 - parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID) - and nibble read seems to be broken for some peripherals. - - *Add probing for onboard SRAM, port directions etc. (if possible) - - *Add support for the hardware compressed modes (maybe using v4l2) - - *Fix better support for the capture window (no skewed images, v4l - interface to capt. window) - - *Probably some bugs that I don't know of - - Please support me by sending feedback! - - Changes: - - Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE - and owner support for newer module locks -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/*#define DEBUG*/ /* Undef me for production */ - -#ifdef DEBUG -#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a) -#else -#define DPRINTF(x...) -#endif - -/* - * Defines, simple typedefs etc. - */ - -#define W9966_DRIVERNAME "W9966CF Webcam" -#define W9966_MAXCAMS 4 /* Maximum number of cameras */ -#define W9966_RBUFFER 2048 /* Read buffer (must be an even number) */ -#define W9966_SRAMSIZE 131072 /* 128kb */ -#define W9966_SRAMID 0x02 /* check w9966cf.pdf */ - -/* Empirically determined window limits */ -#define W9966_WND_MIN_X 16 -#define W9966_WND_MIN_Y 14 -#define W9966_WND_MAX_X 705 -#define W9966_WND_MAX_Y 253 -#define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X) -#define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y) - -/* Keep track of our current state */ -#define W9966_STATE_PDEV 0x01 -#define W9966_STATE_CLAIMED 0x02 -#define W9966_STATE_VDEV 0x04 - -#define W9966_I2C_W_ID 0x48 -#define W9966_I2C_R_ID 0x49 -#define W9966_I2C_R_DATA 0x08 -#define W9966_I2C_R_CLOCK 0x04 -#define W9966_I2C_W_DATA 0x02 -#define W9966_I2C_W_CLOCK 0x01 - -struct w9966 { - struct v4l2_device v4l2_dev; - unsigned char dev_state; - unsigned char i2c_state; - unsigned short ppmode; - struct parport *pport; - struct pardevice *pdev; - struct video_device vdev; - unsigned short width; - unsigned short height; - unsigned char brightness; - signed char contrast; - signed char color; - signed char hue; - struct mutex lock; -}; - -/* - * Module specific properties - */ - -MODULE_AUTHOR("Jakob Kemi "); -MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); -MODULE_LICENSE("GPL"); - - -#ifdef MODULE -static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; -#else -static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; -#endif -module_param_array(pardev, charp, NULL, 0); -MODULE_PARM_DESC(pardev, "pardev: where to search for\n" - "\teach camera. 'aggressive' means brute-force search.\n" - "\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n" - "\tcam 1 to parport3 and search every parport for cam 2 etc..."); - -static int parmode; -module_param(parmode, int, 0); -MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); - -static int video_nr = -1; -module_param(video_nr, int, 0); - -static struct w9966 w9966_cams[W9966_MAXCAMS]; - -/* - * Private function defines - */ - - -/* Set camera phase flags, so we know what to uninit when terminating */ -static inline void w9966_set_state(struct w9966 *cam, int mask, int val) -{ - cam->dev_state = (cam->dev_state & ~mask) ^ val; -} - -/* Get camera phase flags */ -static inline int w9966_get_state(struct w9966 *cam, int mask, int val) -{ - return ((cam->dev_state & mask) == val); -} - -/* Claim parport for ourself */ -static void w9966_pdev_claim(struct w9966 *cam) -{ - if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) - return; - parport_claim_or_block(cam->pdev); - w9966_set_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED); -} - -/* Release parport for others to use */ -static void w9966_pdev_release(struct w9966 *cam) -{ - if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0)) - return; - parport_release(cam->pdev); - w9966_set_state(cam, W9966_STATE_CLAIMED, 0); -} - -/* Read register from W9966 interface-chip - Expects a claimed pdev - -1 on error, else register data (byte) */ -static int w9966_read_reg(struct w9966 *cam, int reg) -{ - /* ECP, read, regtransfer, REG, REG, REG, REG, REG */ - const unsigned char addr = 0x80 | (reg & 0x1f); - unsigned char val; - - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) - return -1; - if (parport_write(cam->pport, &addr, 1) != 1) - return -1; - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) - return -1; - if (parport_read(cam->pport, &val, 1) != 1) - return -1; - - return val; -} - -/* Write register to W9966 interface-chip - Expects a claimed pdev - -1 on error */ -static int w9966_write_reg(struct w9966 *cam, int reg, int data) -{ - /* ECP, write, regtransfer, REG, REG, REG, REG, REG */ - const unsigned char addr = 0xc0 | (reg & 0x1f); - const unsigned char val = data; - - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) - return -1; - if (parport_write(cam->pport, &addr, 1) != 1) - return -1; - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) - return -1; - if (parport_write(cam->pport, &val, 1) != 1) - return -1; - - return 0; -} - -/* - * Ugly and primitive i2c protocol functions - */ - -/* Sets the data line on the i2c bus. - Expects a claimed pdev. */ -static void w9966_i2c_setsda(struct w9966 *cam, int state) -{ - if (state) - cam->i2c_state |= W9966_I2C_W_DATA; - else - cam->i2c_state &= ~W9966_I2C_W_DATA; - - w9966_write_reg(cam, 0x18, cam->i2c_state); - udelay(5); -} - -/* Get peripheral clock line - Expects a claimed pdev. */ -static int w9966_i2c_getscl(struct w9966 *cam) -{ - const unsigned char state = w9966_read_reg(cam, 0x18); - return ((state & W9966_I2C_R_CLOCK) > 0); -} - -/* Sets the clock line on the i2c bus. - Expects a claimed pdev. -1 on error */ -static int w9966_i2c_setscl(struct w9966 *cam, int state) -{ - unsigned long timeout; - - if (state) - cam->i2c_state |= W9966_I2C_W_CLOCK; - else - cam->i2c_state &= ~W9966_I2C_W_CLOCK; - - w9966_write_reg(cam, 0x18, cam->i2c_state); - udelay(5); - - /* we go to high, we also expect the peripheral to ack. */ - if (state) { - timeout = jiffies + 100; - while (!w9966_i2c_getscl(cam)) { - if (time_after(jiffies, timeout)) - return -1; - } - } - return 0; -} - -#if 0 -/* Get peripheral data line - Expects a claimed pdev. */ -static int w9966_i2c_getsda(struct w9966 *cam) -{ - const unsigned char state = w9966_read_reg(cam, 0x18); - return ((state & W9966_I2C_R_DATA) > 0); -} -#endif - -/* Write a byte with ack to the i2c bus. - Expects a claimed pdev. -1 on error */ -static int w9966_i2c_wbyte(struct w9966 *cam, int data) -{ - int i; - - for (i = 7; i >= 0; i--) { - w9966_i2c_setsda(cam, (data >> i) & 0x01); - - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setscl(cam, 0); - } - - w9966_i2c_setsda(cam, 1); - - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setscl(cam, 0); - - return 0; -} - -/* Read a data byte with ack from the i2c-bus - Expects a claimed pdev. -1 on error */ -#if 0 -static int w9966_i2c_rbyte(struct w9966 *cam) -{ - unsigned char data = 0x00; - int i; - - w9966_i2c_setsda(cam, 1); - - for (i = 0; i < 8; i++) { - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - data = data << 1; - if (w9966_i2c_getsda(cam)) - data |= 0x01; - - w9966_i2c_setscl(cam, 0); - } - return data; -} -#endif - -/* Read a register from the i2c device. - Expects claimed pdev. -1 on error */ -#if 0 -static int w9966_read_reg_i2c(struct w9966 *cam, int reg) -{ - int data; - - w9966_i2c_setsda(cam, 0); - w9966_i2c_setscl(cam, 0); - - if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || - w9966_i2c_wbyte(cam, reg) == -1) - return -1; - - w9966_i2c_setsda(cam, 1); - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setsda(cam, 0); - w9966_i2c_setscl(cam, 0); - - if (w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1) - return -1; - data = w9966_i2c_rbyte(cam); - if (data == -1) - return -1; - - w9966_i2c_setsda(cam, 0); - - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setsda(cam, 1); - - return data; -} -#endif - -/* Write a register to the i2c device. - Expects claimed pdev. -1 on error */ -static int w9966_write_reg_i2c(struct w9966 *cam, int reg, int data) -{ - w9966_i2c_setsda(cam, 0); - w9966_i2c_setscl(cam, 0); - - if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || - w9966_i2c_wbyte(cam, reg) == -1 || - w9966_i2c_wbyte(cam, data) == -1) - return -1; - - w9966_i2c_setsda(cam, 0); - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - - w9966_i2c_setsda(cam, 1); - - return 0; -} - -/* Find a good length for capture window (used both for W and H) - A bit ugly but pretty functional. The capture length - have to match the downscale */ -static int w9966_findlen(int near, int size, int maxlen) -{ - int bestlen = size; - int besterr = abs(near - bestlen); - int len; - - for (len = size + 1; len < maxlen; len++) { - int err; - if (((64 * size) % len) != 0) - continue; - - err = abs(near - len); - - /* Only continue as long as we keep getting better values */ - if (err > besterr) - break; - - besterr = err; - bestlen = len; - } - - return bestlen; -} - -/* Modify capture window (if necessary) - and calculate downscaling - Return -1 on error */ -static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsigned char *factor) -{ - int maxlen = max - min; - int len = *end - *beg + 1; - int newlen = w9966_findlen(len, size, maxlen); - int err = newlen - len; - - /* Check for bad format */ - if (newlen > maxlen || newlen < size) - return -1; - - /* Set factor (6 bit fixed) */ - *factor = (64 * size) / newlen; - if (*factor == 64) - *factor = 0x00; /* downscale is disabled */ - else - *factor |= 0x80; /* set downscale-enable bit */ - - /* Modify old beginning and end */ - *beg -= err / 2; - *end += err - (err / 2); - - /* Move window if outside borders */ - if (*beg < min) { - *end += min - *beg; - *beg += min - *beg; - } - if (*end > max) { - *beg -= *end - max; - *end -= *end - max; - } - - return 0; -} - -/* Setup the cameras capture window etc. - Expects a claimed pdev - return -1 on error */ -static int w9966_setup(struct w9966 *cam, int x1, int y1, int x2, int y2, int w, int h) -{ - unsigned int i; - unsigned int enh_s, enh_e; - unsigned char scale_x, scale_y; - unsigned char regs[0x1c]; - unsigned char saa7111_regs[] = { - 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, - 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, - 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0 - }; - - - if (w * h * 2 > W9966_SRAMSIZE) { - DPRINTF("capture window exceeds SRAM size!.\n"); - w = 200; h = 160; /* Pick default values */ - } - - w &= ~0x1; - if (w < 2) - w = 2; - if (h < 1) - h = 1; - if (w > W9966_WND_MAX_W) - w = W9966_WND_MAX_W; - if (h > W9966_WND_MAX_H) - h = W9966_WND_MAX_H; - - cam->width = w; - cam->height = h; - - enh_s = 0; - enh_e = w * h * 2; - - /* Modify capture window if necessary and calculate downscaling */ - if (w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 || - w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0) - return -1; - - DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", - w, h, x1, x2, y1, y2, scale_x & ~0x80, scale_y & ~0x80); - - /* Setup registers */ - regs[0x00] = 0x00; /* Set normal operation */ - regs[0x01] = 0x18; /* Capture mode */ - regs[0x02] = scale_y; /* V-scaling */ - regs[0x03] = scale_x; /* H-scaling */ - - /* Capture window */ - regs[0x04] = (x1 & 0x0ff); /* X-start (8 low bits) */ - regs[0x05] = (x1 & 0x300)>>8; /* X-start (2 high bits) */ - regs[0x06] = (y1 & 0x0ff); /* Y-start (8 low bits) */ - regs[0x07] = (y1 & 0x300)>>8; /* Y-start (2 high bits) */ - regs[0x08] = (x2 & 0x0ff); /* X-end (8 low bits) */ - regs[0x09] = (x2 & 0x300)>>8; /* X-end (2 high bits) */ - regs[0x0a] = (y2 & 0x0ff); /* Y-end (8 low bits) */ - - regs[0x0c] = W9966_SRAMID; /* SRAM-banks (1x 128kb) */ - - /* Enhancement layer */ - regs[0x0d] = (enh_s & 0x000ff); /* Enh. start (0-7) */ - regs[0x0e] = (enh_s & 0x0ff00) >> 8; /* Enh. start (8-15) */ - regs[0x0f] = (enh_s & 0x70000) >> 16; /* Enh. start (16-17/18??) */ - regs[0x10] = (enh_e & 0x000ff); /* Enh. end (0-7) */ - regs[0x11] = (enh_e & 0x0ff00) >> 8; /* Enh. end (8-15) */ - regs[0x12] = (enh_e & 0x70000) >> 16; /* Enh. end (16-17/18??) */ - - /* Misc */ - regs[0x13] = 0x40; /* VEE control (raw 4:2:2) */ - regs[0x17] = 0x00; /* ??? */ - regs[0x18] = cam->i2c_state = 0x00; /* Serial bus */ - regs[0x19] = 0xff; /* I/O port direction control */ - regs[0x1a] = 0xff; /* I/O port data register */ - regs[0x1b] = 0x10; /* ??? */ - - /* SAA7111 chip settings */ - saa7111_regs[0x0a] = cam->brightness; - saa7111_regs[0x0b] = cam->contrast; - saa7111_regs[0x0c] = cam->color; - saa7111_regs[0x0d] = cam->hue; - - /* Reset (ECP-fifo & serial-bus) */ - if (w9966_write_reg(cam, 0x00, 0x03) == -1) - return -1; - - /* Write regs to w9966cf chip */ - for (i = 0; i < 0x1c; i++) - if (w9966_write_reg(cam, i, regs[i]) == -1) - return -1; - - /* Write regs to saa7111 chip */ - for (i = 0; i < 0x20; i++) - if (w9966_write_reg_i2c(cam, i, saa7111_regs[i]) == -1) - return -1; - - return 0; -} - -/* - * Video4linux interfacing - */ - -static int cam_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct w9966 *cam = video_drvdata(file); - - strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card)); - strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); - vcap->version = KERNEL_VERSION(0, 33, 0); - vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - return 0; -} - -static int cam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - if (vin->index > 0) - return -EINVAL; - strlcpy(vin->name, "Camera", sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = 0; - vin->status = 0; - return 0; -} - -static int cam_g_input(struct file *file, void *fh, unsigned int *inp) -{ - *inp = 0; - return 0; -} - -static int cam_s_input(struct file *file, void *fh, unsigned int inp) -{ - return (inp > 0) ? -EINVAL : 0; -} - -static int cam_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); - } - return -EINVAL; -} - -static int cam_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct w9966 *cam = video_drvdata(file); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = cam->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = cam->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = cam->color; - break; - case V4L2_CID_HUE: - ctrl->value = cam->hue; - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static int cam_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct w9966 *cam = video_drvdata(file); - int ret = 0; - - mutex_lock(&cam->lock); - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - cam->brightness = ctrl->value; - break; - case V4L2_CID_CONTRAST: - cam->contrast = ctrl->value; - break; - case V4L2_CID_SATURATION: - cam->color = ctrl->value; - break; - case V4L2_CID_HUE: - cam->hue = ctrl->value; - break; - default: - ret = -EINVAL; - break; - } - - if (ret == 0) { - w9966_pdev_claim(cam); - - if (w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 || - w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 || - w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 || - w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1) { - ret = -EIO; - } - - w9966_pdev_release(cam); - } - mutex_unlock(&cam->lock); - return ret; -} - -static int cam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct w9966 *cam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = cam->width; - pix->height = cam->height; - pix->pixelformat = V4L2_PIX_FMT_YUYV; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 2 * cam->width; - pix->sizeimage = 2 * cam->width * cam->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int cam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->width < 2) - pix->width = 2; - if (pix->height < 1) - pix->height = 1; - if (pix->width > W9966_WND_MAX_W) - pix->width = W9966_WND_MAX_W; - if (pix->height > W9966_WND_MAX_H) - pix->height = W9966_WND_MAX_H; - pix->pixelformat = V4L2_PIX_FMT_YUYV; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 2 * pix->width; - pix->sizeimage = 2 * pix->width * pix->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int cam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct w9966 *cam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = cam_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - - mutex_lock(&cam->lock); - /* Update camera regs */ - w9966_pdev_claim(cam); - ret = w9966_setup(cam, 0, 0, 1023, 1023, pix->width, pix->height); - w9966_pdev_release(cam); - mutex_unlock(&cam->lock); - return ret; -} - -static int cam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "YUV 4:2:2", V4L2_PIX_FMT_YUYV, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 0) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -/* Capture data */ -static ssize_t w9966_v4l_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct w9966 *cam = video_drvdata(file); - unsigned char addr = 0xa0; /* ECP, read, CCD-transfer, 00000 */ - unsigned char __user *dest = (unsigned char __user *)buf; - unsigned long dleft = count; - unsigned char *tbuf; - - /* Why would anyone want more than this?? */ - if (count > cam->width * cam->height * 2) - return -EINVAL; - - mutex_lock(&cam->lock); - w9966_pdev_claim(cam); - w9966_write_reg(cam, 0x00, 0x02); /* Reset ECP-FIFO buffer */ - w9966_write_reg(cam, 0x00, 0x00); /* Return to normal operation */ - w9966_write_reg(cam, 0x01, 0x98); /* Enable capture */ - - /* write special capture-addr and negotiate into data transfer */ - if ((parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0) || - (parport_write(cam->pport, &addr, 1) != 1) || - (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) { - w9966_pdev_release(cam); - mutex_unlock(&cam->lock); - return -EFAULT; - } - - tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL); - if (tbuf == NULL) { - count = -ENOMEM; - goto out; - } - - while (dleft > 0) { - unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; - - if (parport_read(cam->pport, tbuf, tsize) < tsize) { - count = -EFAULT; - goto out; - } - if (copy_to_user(dest, tbuf, tsize) != 0) { - count = -EFAULT; - goto out; - } - dest += tsize; - dleft -= tsize; - } - - w9966_write_reg(cam, 0x01, 0x18); /* Disable capture */ - -out: - kfree(tbuf); - w9966_pdev_release(cam); - mutex_unlock(&cam->lock); - - return count; -} - -static const struct v4l2_file_operations w9966_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - .read = w9966_v4l_read, -}; - -static const struct v4l2_ioctl_ops w9966_ioctl_ops = { - .vidioc_querycap = cam_querycap, - .vidioc_g_input = cam_g_input, - .vidioc_s_input = cam_s_input, - .vidioc_enum_input = cam_enum_input, - .vidioc_queryctrl = cam_queryctrl, - .vidioc_g_ctrl = cam_g_ctrl, - .vidioc_s_ctrl = cam_s_ctrl, - .vidioc_enum_fmt_vid_cap = cam_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = cam_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cam_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cam_try_fmt_vid_cap, -}; - - -/* Initialize camera device. Setup all internal flags, set a - default video mode, setup ccd-chip, register v4l device etc.. - Also used for 'probing' of hardware. - -1 on error */ -static int w9966_init(struct w9966 *cam, struct parport *port) -{ - struct v4l2_device *v4l2_dev = &cam->v4l2_dev; - - if (cam->dev_state != 0) - return -1; - - strlcpy(v4l2_dev->name, "w9966", sizeof(v4l2_dev->name)); - - if (v4l2_device_register(NULL, v4l2_dev) < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return -1; - } - cam->pport = port; - cam->brightness = 128; - cam->contrast = 64; - cam->color = 64; - cam->hue = 0; - - /* Select requested transfer mode */ - switch (parmode) { - default: /* Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) */ - case 0: - if (port->modes & PARPORT_MODE_ECP) - cam->ppmode = IEEE1284_MODE_ECP; - else if (port->modes & PARPORT_MODE_EPP) - cam->ppmode = IEEE1284_MODE_EPP; - else - cam->ppmode = IEEE1284_MODE_ECP; - break; - case 1: /* hw- or sw-ecp */ - cam->ppmode = IEEE1284_MODE_ECP; - break; - case 2: /* hw- or sw-epp */ - cam->ppmode = IEEE1284_MODE_EPP; - break; - } - - /* Tell the parport driver that we exists */ - cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL); - if (cam->pdev == NULL) { - DPRINTF("parport_register_device() failed\n"); - return -1; - } - w9966_set_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV); - - w9966_pdev_claim(cam); - - /* Setup a default capture mode */ - if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) { - DPRINTF("w9966_setup() failed.\n"); - return -1; - } - - w9966_pdev_release(cam); - - /* Fill in the video_device struct and register us to v4l */ - strlcpy(cam->vdev.name, W9966_DRIVERNAME, sizeof(cam->vdev.name)); - cam->vdev.v4l2_dev = v4l2_dev; - cam->vdev.fops = &w9966_fops; - cam->vdev.ioctl_ops = &w9966_ioctl_ops; - cam->vdev.release = video_device_release_empty; - video_set_drvdata(&cam->vdev, cam); - - mutex_init(&cam->lock); - - if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) - return -1; - - w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); - - /* All ok */ - v4l2_info(v4l2_dev, "Found and initialized a webcam on %s.\n", - cam->pport->name); - return 0; -} - - -/* Terminate everything gracefully */ -static void w9966_term(struct w9966 *cam) -{ - /* Unregister from v4l */ - if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { - video_unregister_device(&cam->vdev); - w9966_set_state(cam, W9966_STATE_VDEV, 0); - } - - /* Terminate from IEEE1284 mode and release pdev block */ - if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { - w9966_pdev_claim(cam); - parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); - w9966_pdev_release(cam); - } - - /* Unregister from parport */ - if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { - parport_unregister_device(cam->pdev); - w9966_set_state(cam, W9966_STATE_PDEV, 0); - } - memset(cam, 0, sizeof(*cam)); -} - - -/* Called once for every parport on init */ -static void w9966_attach(struct parport *port) -{ - int i; - - for (i = 0; i < W9966_MAXCAMS; i++) { - if (w9966_cams[i].dev_state != 0) /* Cam is already assigned */ - continue; - if (strcmp(pardev[i], "aggressive") == 0 || strcmp(pardev[i], port->name) == 0) { - if (w9966_init(&w9966_cams[i], port) != 0) - w9966_term(&w9966_cams[i]); - break; /* return */ - } - } -} - -/* Called once for every parport on termination */ -static void w9966_detach(struct parport *port) -{ - int i; - - for (i = 0; i < W9966_MAXCAMS; i++) - if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port) - w9966_term(&w9966_cams[i]); -} - - -static struct parport_driver w9966_ppd = { - .name = W9966_DRIVERNAME, - .attach = w9966_attach, - .detach = w9966_detach, -}; - -/* Module entry point */ -static int __init w9966_mod_init(void) -{ - int i; - - for (i = 0; i < W9966_MAXCAMS; i++) - w9966_cams[i].dev_state = 0; - - return parport_register_driver(&w9966_ppd); -} - -/* Module cleanup */ -static void __exit w9966_mod_term(void) -{ - parport_unregister_driver(&w9966_ppd); -} - -module_init(w9966_mod_init); -module_exit(w9966_mod_term); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/wm8739.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/wm8739.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/wm8739.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/wm8739.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,305 +0,0 @@ -/* - * wm8739 - * - * Copyright (C) 2005 T. Adachi - * - * Copyright (C) 2005 Hans Verkuil - * - Cleanup - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("wm8739 driver"); -MODULE_AUTHOR("T. Adachi, Hans Verkuil"); -MODULE_LICENSE("GPL"); - -static int debug; - -module_param(debug, int, 0644); - -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - - -/* ------------------------------------------------------------------------ */ - -enum { - R0 = 0, R1, - R5 = 5, R6, R7, R8, R9, R15 = 15, - TOT_REGS -}; - -struct wm8739_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - struct { - /* audio cluster */ - struct v4l2_ctrl *volume; - struct v4l2_ctrl *mute; - struct v4l2_ctrl *balance; - }; - u32 clock_freq; -}; - -static inline struct wm8739_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct wm8739_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct wm8739_state, hdl)->sd; -} - -/* ------------------------------------------------------------------------ */ - -static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int i; - - if (reg < 0 || reg >= TOT_REGS) { - v4l2_err(sd, "Invalid register R%d\n", reg); - return -1; - } - - v4l2_dbg(1, debug, sd, "write: %02x %02x\n", reg, val); - - for (i = 0; i < 3; i++) - if (i2c_smbus_write_byte_data(client, - (reg << 1) | (val >> 8), val & 0xff) == 0) - return 0; - v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg); - return -1; -} - -static int wm8739_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct wm8739_state *state = to_state(sd); - unsigned int work_l, work_r; - u8 vol_l; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */ - u8 vol_r; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */ - u16 mute; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - break; - - default: - return -EINVAL; - } - - /* normalize ( 65535 to 0 -> 31 to 0 (12dB to -34.5dB) ) */ - work_l = (min(65536 - state->balance->val, 32768) * state->volume->val) / 32768; - work_r = (min(state->balance->val, 32768) * state->volume->val) / 32768; - - vol_l = (long)work_l * 31 / 65535; - vol_r = (long)work_r * 31 / 65535; - - /* set audio volume etc. */ - mute = state->mute->val ? 0x80 : 0; - - /* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB - * Default setting: 0x17 = 0 dB - */ - wm8739_write(sd, R0, (vol_l & 0x1f) | mute); - wm8739_write(sd, R1, (vol_r & 0x1f) | mute); - return 0; -} - -/* ------------------------------------------------------------------------ */ - -static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq) -{ - struct wm8739_state *state = to_state(sd); - - state->clock_freq = audiofreq; - /* de-activate */ - wm8739_write(sd, R9, 0x000); - switch (audiofreq) { - case 44100: - /* 256fps, fs=44.1k */ - wm8739_write(sd, R8, 0x020); - break; - case 48000: - /* 256fps, fs=48k */ - wm8739_write(sd, R8, 0x000); - break; - case 32000: - /* 256fps, fs=32k */ - wm8739_write(sd, R8, 0x018); - break; - default: - break; - } - /* activate */ - wm8739_write(sd, R9, 0x001); - return 0; -} - -static int wm8739_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8739, 0); -} - -static int wm8739_log_status(struct v4l2_subdev *sd) -{ - struct wm8739_state *state = to_state(sd); - - v4l2_info(sd, "Frequency: %u Hz\n", state->clock_freq); - v4l2_ctrl_handler_log_status(&state->hdl, sd->name); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops wm8739_ctrl_ops = { - .s_ctrl = wm8739_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops wm8739_core_ops = { - .log_status = wm8739_log_status, - .g_chip_ident = wm8739_g_chip_ident, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - -static const struct v4l2_subdev_audio_ops wm8739_audio_ops = { - .s_clock_freq = wm8739_s_clock_freq, -}; - -static const struct v4l2_subdev_ops wm8739_ops = { - .core = &wm8739_core_ops, - .audio = &wm8739_audio_ops, -}; - -/* ------------------------------------------------------------------------ */ - -/* i2c implementation */ - -static int wm8739_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct wm8739_state *state; - struct v4l2_subdev *sd; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kzalloc(sizeof(struct wm8739_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &wm8739_ops); - v4l2_ctrl_handler_init(&state->hdl, 2); - state->volume = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 50736); - state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - state->balance = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768); - sd->ctrl_handler = &state->hdl; - if (state->hdl.error) { - int err = state->hdl.error; - - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return err; - } - v4l2_ctrl_cluster(3, &state->volume); - - state->clock_freq = 48000; - - /* Initialize wm8739 */ - - /* reset */ - wm8739_write(sd, R15, 0x00); - /* filter setting, high path, offet clear */ - wm8739_write(sd, R5, 0x000); - /* ADC, OSC, Power Off mode Disable */ - wm8739_write(sd, R6, 0x000); - /* Digital Audio interface format: - Enable Master mode, 24 bit, MSB first/left justified */ - wm8739_write(sd, R7, 0x049); - /* sampling control: normal, 256fs, 48KHz sampling rate */ - wm8739_write(sd, R8, 0x000); - /* activate */ - wm8739_write(sd, R9, 0x001); - /* set volume/mute */ - v4l2_ctrl_handler_setup(&state->hdl); - return 0; -} - -static int wm8739_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct wm8739_state *state = to_state(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&state->hdl); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id wm8739_id[] = { - { "wm8739", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8739_id); - -static struct i2c_driver wm8739_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "wm8739", - }, - .probe = wm8739_probe, - .remove = wm8739_remove, - .id_table = wm8739_id, -}; - -static __init int init_wm8739(void) -{ - return i2c_add_driver(&wm8739_driver); -} - -static __exit void exit_wm8739(void) -{ - i2c_del_driver(&wm8739_driver); -} - -module_init(init_wm8739); -module_exit(exit_wm8739); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/wm8775.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/wm8775.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/wm8775.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/wm8775.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,353 +0,0 @@ -/* - * wm8775 - driver version 0.0.1 - * - * Copyright (C) 2004 Ulf Eklund - * - * Based on saa7115 driver - * - * Copyright (C) 2005 Hans Verkuil - * - Cleanup - * - V4L2 API update - * - sound fixes - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("wm8775 driver"); -MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); -MODULE_LICENSE("GPL"); - - - -/* ----------------------------------------------------------------------- */ - -enum { - R7 = 7, R11 = 11, - R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23, - TOT_REGS -}; - -#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */ -#define ALC_EN 0x100 /* R17: ALC enable */ - -struct wm8775_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - struct v4l2_ctrl *mute; - struct v4l2_ctrl *vol; - struct v4l2_ctrl *bal; - struct v4l2_ctrl *loud; - u8 input; /* Last selected input (0-0xf) */ -}; - -static inline struct wm8775_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct wm8775_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct wm8775_state, hdl)->sd; -} - -static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int i; - - if (reg < 0 || reg >= TOT_REGS) { - v4l2_err(sd, "Invalid register R%d\n", reg); - return -1; - } - - for (i = 0; i < 3; i++) - if (i2c_smbus_write_byte_data(client, - (reg << 1) | (val >> 8), val & 0xff) == 0) - return 0; - v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg); - return -1; -} - -static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly) -{ - struct wm8775_state *state = to_state(sd); - u8 vol_l, vol_r; - int muted = 0 != state->mute->val; - u16 volume = (u16)state->vol->val; - u16 balance = (u16)state->bal->val; - - /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */ - vol_l = (min(65536 - balance, 32768) * volume) >> 23; - vol_r = (min(balance, (u16)32768) * volume) >> 23; - - /* Mute */ - if (muted || quietly) - wm8775_write(sd, R21, 0x0c0 | state->input); - - wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */ - wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */ - - /* Un-mute */ - if (!muted) - wm8775_write(sd, R21, state->input); -} - -static int wm8775_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct wm8775_state *state = to_state(sd); - - /* There are 4 inputs and one output. Zero or more inputs - are multiplexed together to the output. Hence there are - 16 combinations. - If only one input is active (the normal case) then the - input values 1, 2, 4 or 8 should be used. */ - if (input > 15) { - v4l2_err(sd, "Invalid input %d.\n", input); - return -EINVAL; - } - state->input = input; - if (!v4l2_ctrl_g_ctrl(state->mute)) - return 0; - if (!v4l2_ctrl_g_ctrl(state->vol)) - return 0; - if (!v4l2_ctrl_g_ctrl(state->bal)) - return 0; - wm8775_set_audio(sd, 1); - return 0; -} - -static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - wm8775_set_audio(sd, 0); - return 0; - case V4L2_CID_AUDIO_LOUDNESS: - wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD); - return 0; - } - return -EINVAL; -} - -static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8775, 0); -} - -static int wm8775_log_status(struct v4l2_subdev *sd) -{ - struct wm8775_state *state = to_state(sd); - - v4l2_info(sd, "Input: %d\n", state->input); - v4l2_ctrl_handler_log_status(&state->hdl, sd->name); - return 0; -} - -static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) -{ - wm8775_set_audio(sd, 0); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_ctrl_ops wm8775_ctrl_ops = { - .s_ctrl = wm8775_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops wm8775_core_ops = { - .log_status = wm8775_log_status, - .g_chip_ident = wm8775_g_chip_ident, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - -static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = { - .s_frequency = wm8775_s_frequency, -}; - -static const struct v4l2_subdev_audio_ops wm8775_audio_ops = { - .s_routing = wm8775_s_routing, -}; - -static const struct v4l2_subdev_ops wm8775_ops = { - .core = &wm8775_core_ops, - .tuner = &wm8775_tuner_ops, - .audio = &wm8775_audio_ops, -}; - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ - -/* - * Generic i2c probe - * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' - */ - -static int wm8775_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct wm8775_state *state; - struct v4l2_subdev *sd; - int err; - bool is_nova_s = false; - - if (client->dev.platform_data) { - struct wm8775_platform_data *data = client->dev.platform_data; - is_nova_s = data->is_nova_s; - } - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kzalloc(sizeof(struct wm8775_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &wm8775_ops); - state->input = 2; - - v4l2_ctrl_handler_init(&state->hdl, 4); - state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/ - state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768); - state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, - V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1); - sd->ctrl_handler = &state->hdl; - err = state->hdl.error; - if (err) { - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return err; - } - - /* Initialize wm8775 */ - - /* RESET */ - wm8775_write(sd, R23, 0x000); - /* Disable zero cross detect timeout */ - wm8775_write(sd, R7, 0x000); - /* HPF enable, left justified, 24-bit (Philips) mode */ - wm8775_write(sd, R11, 0x021); - /* Master mode, clock ratio 256fs */ - wm8775_write(sd, R12, 0x102); - /* Powered up */ - wm8775_write(sd, R13, 0x000); - - if (!is_nova_s) { - /* ADC gain +2.5dB, enable zero cross */ - wm8775_write(sd, R14, 0x1d4); - /* ADC gain +2.5dB, enable zero cross */ - wm8775_write(sd, R15, 0x1d4); - /* ALC Stereo, ALC target level -1dB FS max gain +8dB */ - wm8775_write(sd, R16, 0x1bf); - /* Enable gain control, use zero cross detection, - ALC hold time 42.6 ms */ - wm8775_write(sd, R17, 0x185); - } else { - /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */ - wm8775_write(sd, R16, 0x1bb); - /* Set ALC mode and hold time */ - wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD); - } - /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ - wm8775_write(sd, R18, 0x0a2); - /* Enable noise gate, threshold -72dBfs */ - wm8775_write(sd, R19, 0x005); - if (!is_nova_s) { - /* Transient window 4ms, lower PGA gain limit -1dB */ - wm8775_write(sd, R20, 0x07a); - /* LRBOTH = 1, use input 2. */ - wm8775_write(sd, R21, 0x102); - } else { - /* Transient window 4ms, ALC min gain -5dB */ - wm8775_write(sd, R20, 0x0fb); - - wm8775_set_audio(sd, 1); /* set volume/mute/mux */ - } - return 0; -} - -static int wm8775_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct wm8775_state *state = to_state(sd); - - v4l2_device_unregister_subdev(sd); - v4l2_ctrl_handler_free(&state->hdl); - kfree(state); - return 0; -} - -static const struct i2c_device_id wm8775_id[] = { - { "wm8775", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8775_id); - -static struct i2c_driver wm8775_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "wm8775", - }, - .probe = wm8775_probe, - .remove = wm8775_remove, - .id_table = wm8775_id, -}; - -static __init int init_wm8775(void) -{ - return i2c_add_driver(&wm8775_driver); -} - -static __exit void exit_wm8775(void) -{ - i2c_del_driver(&wm8775_driver); -} - -module_init(init_wm8775); -module_exit(exit_wm8775); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -config VIDEO_ZORAN - tristate "Zoran ZR36057/36067 Video For Linux" - depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 && VIRT_TO_BUS - help - Say Y for support for MJPEG capture cards based on the Zoran - 36057/36067 PCI controller chipset. This includes the Iomega - Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is - a driver homepage at . For - more information, check . - - To compile this driver as a module, choose M here: the - module will be called zr36067. - -config VIDEO_ZORAN_DC30 - tristate "Pinnacle/Miro DC30(+) support" - depends on VIDEO_ZORAN - select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback - card. This also supports really old DC10 cards based on the - zr36050 MJPEG codec and zr36016 VFE. - -config VIDEO_ZORAN_ZR36060 - tristate "Zoran ZR36060" - depends on VIDEO_ZORAN - help - Say Y to support Zoran boards based on 36060 chips. - This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33 - and 33 R10 and AverMedia 6 boards. - -config VIDEO_ZORAN_BUZ - tristate "Iomega Buz support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the Iomega Buz MJPEG capture/playback card. - -config VIDEO_ZORAN_DC10 - tristate "Pinnacle/Miro DC10(+) support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA7110 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback - card. - -config VIDEO_ZORAN_LML33 - tristate "Linux Media Labs LML33 support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the Linux Media Labs LML33 MJPEG capture/playback - card. - -config VIDEO_ZORAN_LML33R10 - tristate "Linux Media Labs LML33R10 support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO - help - support for the Linux Media Labs LML33R10 MJPEG capture/playback - card. - -config VIDEO_ZORAN_AVS6EYES - tristate "AverMedia 6 Eyes support (EXPERIMENTAL)" - depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL - select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_BT866 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO - help - Support for the AverMedia 6 Eyes video surveillance card. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -zr36067-objs := zoran_procfs.o zoran_device.o \ - zoran_driver.o zoran_card.o - -obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o -obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o -obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/videocodec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/videocodec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/videocodec.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/videocodec.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,407 +0,0 @@ -/* - * VIDEO MOTION CODECs internal API for video devices - * - * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's - * bound to a master device. - * - * (c) 2002 Wolfgang Scherr - * - * $Id: videocodec.c,v 1.1.2.8 2003/03/29 07:16:04 rbultje Exp $ - * - * ------------------------------------------------------------------------ - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ------------------------------------------------------------------------ - */ - -#define VIDEOCODEC_VERSION "v0.2" - -#include -#include -#include -#include -#include - -// kernel config is here (procfs flag) - -#ifdef CONFIG_PROC_FS -#include -#include -#include -#endif - -#include "videocodec.h" - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) - -struct attached_list { - struct videocodec *codec; - struct attached_list *next; -}; - -struct codec_list { - const struct videocodec *codec; - int attached; - struct attached_list *list; - struct codec_list *next; -}; - -static struct codec_list *codeclist_top = NULL; - -/* ================================================= */ -/* function prototypes of the master/slave interface */ -/* ================================================= */ - -struct videocodec * -videocodec_attach (struct videocodec_master *master) -{ - struct codec_list *h = codeclist_top; - struct attached_list *a, *ptr; - struct videocodec *codec; - int res; - - if (!master) { - dprintk(1, KERN_ERR "videocodec_attach: no data\n"); - return NULL; - } - - dprintk(2, - "videocodec_attach: '%s', flags %lx, magic %lx\n", - master->name, master->flags, master->magic); - - if (!h) { - dprintk(1, - KERN_ERR - "videocodec_attach: no device available\n"); - return NULL; - } - - while (h) { - // attach only if the slave has at least the flags - // expected by the master - if ((master->flags & h->codec->flags) == master->flags) { - dprintk(4, "videocodec_attach: try '%s'\n", - h->codec->name); - - if (!try_module_get(h->codec->owner)) - return NULL; - - codec = kmemdup(h->codec, sizeof(struct videocodec), - GFP_KERNEL); - if (!codec) { - dprintk(1, - KERN_ERR - "videocodec_attach: no mem\n"); - goto out_module_put; - } - - snprintf(codec->name, sizeof(codec->name), - "%s[%d]", codec->name, h->attached); - codec->master_data = master; - res = codec->setup(codec); - if (res == 0) { - dprintk(3, "videocodec_attach '%s'\n", - codec->name); - ptr = kzalloc(sizeof(struct attached_list), GFP_KERNEL); - if (!ptr) { - dprintk(1, - KERN_ERR - "videocodec_attach: no memory\n"); - goto out_kfree; - } - ptr->codec = codec; - - a = h->list; - if (!a) { - h->list = ptr; - dprintk(4, - "videocodec: first element\n"); - } else { - while (a->next) - a = a->next; // find end - a->next = ptr; - dprintk(4, - "videocodec: in after '%s'\n", - h->codec->name); - } - - h->attached += 1; - return codec; - } else { - kfree(codec); - } - } - h = h->next; - } - - dprintk(1, KERN_ERR "videocodec_attach: no codec found!\n"); - return NULL; - - out_module_put: - module_put(h->codec->owner); - out_kfree: - kfree(codec); - return NULL; -} - -int -videocodec_detach (struct videocodec *codec) -{ - struct codec_list *h = codeclist_top; - struct attached_list *a, *prev; - int res; - - if (!codec) { - dprintk(1, KERN_ERR "videocodec_detach: no data\n"); - return -EINVAL; - } - - dprintk(2, - "videocodec_detach: '%s', type: %x, flags %lx, magic %lx\n", - codec->name, codec->type, codec->flags, codec->magic); - - if (!h) { - dprintk(1, - KERN_ERR "videocodec_detach: no device left...\n"); - return -ENXIO; - } - - while (h) { - a = h->list; - prev = NULL; - while (a) { - if (codec == a->codec) { - res = a->codec->unset(a->codec); - if (res >= 0) { - dprintk(3, - "videocodec_detach: '%s'\n", - a->codec->name); - a->codec->master_data = NULL; - } else { - dprintk(1, - KERN_ERR - "videocodec_detach: '%s'\n", - a->codec->name); - a->codec->master_data = NULL; - } - if (prev == NULL) { - h->list = a->next; - dprintk(4, - "videocodec: delete first\n"); - } else { - prev->next = a->next; - dprintk(4, - "videocodec: delete middle\n"); - } - module_put(a->codec->owner); - kfree(a->codec); - kfree(a); - h->attached -= 1; - return 0; - } - prev = a; - a = a->next; - } - h = h->next; - } - - dprintk(1, KERN_ERR "videocodec_detach: given codec not found!\n"); - return -EINVAL; -} - -int -videocodec_register (const struct videocodec *codec) -{ - struct codec_list *ptr, *h = codeclist_top; - - if (!codec) { - dprintk(1, KERN_ERR "videocodec_register: no data!\n"); - return -EINVAL; - } - - dprintk(2, - "videocodec: register '%s', type: %x, flags %lx, magic %lx\n", - codec->name, codec->type, codec->flags, codec->magic); - - ptr = kzalloc(sizeof(struct codec_list), GFP_KERNEL); - if (!ptr) { - dprintk(1, KERN_ERR "videocodec_register: no memory\n"); - return -ENOMEM; - } - ptr->codec = codec; - - if (!h) { - codeclist_top = ptr; - dprintk(4, "videocodec: hooked in as first element\n"); - } else { - while (h->next) - h = h->next; // find the end - h->next = ptr; - dprintk(4, "videocodec: hooked in after '%s'\n", - h->codec->name); - } - - return 0; -} - -int -videocodec_unregister (const struct videocodec *codec) -{ - struct codec_list *prev = NULL, *h = codeclist_top; - - if (!codec) { - dprintk(1, KERN_ERR "videocodec_unregister: no data!\n"); - return -EINVAL; - } - - dprintk(2, - "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n", - codec->name, codec->type, codec->flags, codec->magic); - - if (!h) { - dprintk(1, - KERN_ERR - "videocodec_unregister: no device left...\n"); - return -ENXIO; - } - - while (h) { - if (codec == h->codec) { - if (h->attached) { - dprintk(1, - KERN_ERR - "videocodec: '%s' is used\n", - h->codec->name); - return -EBUSY; - } - dprintk(3, "videocodec: unregister '%s' is ok.\n", - h->codec->name); - if (prev == NULL) { - codeclist_top = h->next; - dprintk(4, - "videocodec: delete first element\n"); - } else { - prev->next = h->next; - dprintk(4, - "videocodec: delete middle element\n"); - } - kfree(h); - return 0; - } - prev = h; - h = h->next; - } - - dprintk(1, - KERN_ERR - "videocodec_unregister: given codec not found!\n"); - return -EINVAL; -} - -#ifdef CONFIG_PROC_FS -static int proc_videocodecs_show(struct seq_file *m, void *v) -{ - struct codec_list *h = codeclist_top; - struct attached_list *a; - - seq_printf(m, "lave or attached aster name type flags magic "); - seq_printf(m, "(connected as)\n"); - - h = codeclist_top; - while (h) { - seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n", - h->codec->name, h->codec->type, - h->codec->flags, h->codec->magic); - a = h->list; - while (a) { - seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n", - a->codec->master_data->name, - a->codec->master_data->type, - a->codec->master_data->flags, - a->codec->master_data->magic, - a->codec->name); - a = a->next; - } - h = h->next; - } - - return 0; -} - -static int proc_videocodecs_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_videocodecs_show, NULL); -} - -static const struct file_operations videocodecs_proc_fops = { - .owner = THIS_MODULE, - .open = proc_videocodecs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -/* ===================== */ -/* hook in driver module */ -/* ===================== */ -static int __init -videocodec_init (void) -{ -#ifdef CONFIG_PROC_FS - static struct proc_dir_entry *videocodec_proc_entry; -#endif - - printk(KERN_INFO "Linux video codec intermediate layer: %s\n", - VIDEOCODEC_VERSION); - -#ifdef CONFIG_PROC_FS - videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops); - if (!videocodec_proc_entry) { - dprintk(1, KERN_ERR "videocodec: can't init procfs.\n"); - } -#endif - return 0; -} - -static void __exit -videocodec_exit (void) -{ -#ifdef CONFIG_PROC_FS - remove_proc_entry("videocodecs", NULL); -#endif -} - -EXPORT_SYMBOL(videocodec_attach); -EXPORT_SYMBOL(videocodec_detach); -EXPORT_SYMBOL(videocodec_register); -EXPORT_SYMBOL(videocodec_unregister); - -module_init(videocodec_init); -module_exit(videocodec_exit); - -MODULE_AUTHOR("Wolfgang Scherr "); -MODULE_DESCRIPTION("Intermediate API module for video codecs " - VIDEOCODEC_VERSION); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/videocodec.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/videocodec.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/videocodec.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/videocodec.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,353 +0,0 @@ -/* - * VIDEO MOTION CODECs internal API for video devices - * - * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's - * bound to a master device. - * - * (c) 2002 Wolfgang Scherr - * - * $Id: videocodec.h,v 1.1.2.4 2003/01/14 21:15:03 rbultje Exp $ - * - * ------------------------------------------------------------------------ - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ------------------------------------------------------------------------ - */ - -/* =================== */ -/* general description */ -/* =================== */ - -/* Should ease the (re-)usage of drivers supporting cards with (different) - video codecs. The codecs register to this module their functionality, - and the processors (masters) can attach to them if they fit. - - The codecs are typically have a "strong" binding to their master - so I - don't think it makes sense to have a full blown interfacing as with e.g. - i2c. If you have an other opinion, let's discuss & implement it :-))) - - Usage: - - The slave has just to setup the videocodec structure and use two functions: - videocodec_register(codecdata); - videocodec_unregister(codecdata); - The best is just calling them at module (de-)initialisation. - - The master sets up the structure videocodec_master and calls: - codecdata=videocodec_attach(master_codecdata); - videocodec_detach(codecdata); - - The slave is called during attach/detach via functions setup previously - during register. At that time, the master_data pointer is set up - and the slave can access any io registers of the master device (in the case - the slave is bound to it). Otherwise it doesn't need this functions and - therfor they may not be initialized. - - The other functions are just for convenience, as they are for sure used by - most/all of the codecs. The last ones may be ommited, too. - - See the structure declaration below for more information and which data has - to be set up for the master and the slave. - - ---------------------------------------------------------------------------- - The master should have "knowledge" of the slave and vice versa. So the data - structures sent to/from slave via set_data/get_data set_image/get_image are - device dependent and vary between MJPEG/MPEG/WAVELET/... devices. (!!!!) - ---------------------------------------------------------------------------- -*/ - - -/* ========================================== */ -/* description of the videocodec_io structure */ -/* ========================================== */ - -/* - ==== master setup ==== - name -> name of the device structure for reference and debugging - master_data -> data ref. for the master (e.g. the zr36055,57,67) - readreg -> ref. to read-fn from register (setup by master, used by slave) - writereg -> ref. to write-fn to register (setup by master, used by slave) - this two functions do the lowlevel I/O job - - ==== slave functionality setup ==== - slave_data -> data ref. for the slave (e.g. the zr36050,60) - check -> fn-ref. checks availability of an device, returns -EIO on failure or - the type on success - this makes espcecially sense if a driver module supports more than - one codec which may be quite similar to access, nevertheless it - is good for a first functionality check - - -- main functions you always need for compression/decompression -- - - set_mode -> this fn-ref. resets the entire codec, and sets up the mode - with the last defined norm/size (or device default if not - available) - it returns 0 if the mode is possible - set_size -> this fn-ref. sets the norm and image size for - compression/decompression (returns 0 on success) - the norm param is defined in videodev2.h (V4L2_STD_*) - - additional setup may be available, too - but the codec should work with - some default values even without this - - set_data -> sets device-specific data (tables, quality etc.) - get_data -> query device-specific data (tables, quality etc.) - - if the device delivers interrupts, they may be setup/handled here - setup_interrupt -> codec irq setup (not needed for 36050/60) - handle_interrupt -> codec irq handling (not needed for 36050/60) - - if the device delivers pictures, they may be handled here - put_image -> puts image data to the codec (not needed for 36050/60) - get_image -> gets image data from the codec (not needed for 36050/60) - the calls include frame numbers and flags (even/odd/...) - if needed and a flag which allows blocking until its ready -*/ - -/* ============== */ -/* user interface */ -/* ============== */ - -/* - Currently there is only a information display planned, as the layer - is not visible for the user space at all. - - Information is available via procfs. The current entry is "/proc/videocodecs" - but it makes sense to "hide" it in the /proc/video tree of v4l(2) --TODO--. - -A example for such an output is: - -lave or attached aster name type flags magic (connected as) -S zr36050 0002 0000d001 00000000 (TEMPLATE) -M zr36055[0] 0001 0000c001 00000000 (zr36050[0]) -M zr36055[1] 0001 0000c001 00000000 (zr36050[1]) - -*/ - - -/* =============================================== */ -/* special defines for the videocodec_io structure */ -/* =============================================== */ - -#ifndef __LINUX_VIDEOCODEC_H -#define __LINUX_VIDEOCODEC_H - -#include - -#define CODEC_DO_COMPRESSION 0 -#define CODEC_DO_EXPANSION 1 - -/* this are the current codec flags I think they are needed */ -/* -> type value in structure */ -#define CODEC_FLAG_JPEG 0x00000001L // JPEG codec -#define CODEC_FLAG_MPEG 0x00000002L // MPEG1/2/4 codec -#define CODEC_FLAG_DIVX 0x00000004L // DIVX codec -#define CODEC_FLAG_WAVELET 0x00000008L // WAVELET codec - // room for other types - -#define CODEC_FLAG_MAGIC 0x00000800L // magic key must match -#define CODEC_FLAG_HARDWARE 0x00001000L // is a hardware codec -#define CODEC_FLAG_VFE 0x00002000L // has direct video frontend -#define CODEC_FLAG_ENCODER 0x00004000L // compression capability -#define CODEC_FLAG_DECODER 0x00008000L // decompression capability -#define CODEC_FLAG_NEEDIRQ 0x00010000L // needs irq handling -#define CODEC_FLAG_RDWRPIC 0x00020000L // handles picture I/O - -/* a list of modes, some are just examples (is there any HW?) */ -#define CODEC_MODE_BJPG 0x0001 // Baseline JPEG -#define CODEC_MODE_LJPG 0x0002 // Lossless JPEG -#define CODEC_MODE_MPEG1 0x0003 // MPEG 1 -#define CODEC_MODE_MPEG2 0x0004 // MPEG 2 -#define CODEC_MODE_MPEG4 0x0005 // MPEG 4 -#define CODEC_MODE_MSDIVX 0x0006 // MS DivX -#define CODEC_MODE_ODIVX 0x0007 // Open DivX -#define CODEC_MODE_WAVELET 0x0008 // Wavelet - -/* this are the current codec types I want to implement */ -/* -> type value in structure */ -#define CODEC_TYPE_NONE 0 -#define CODEC_TYPE_L64702 1 -#define CODEC_TYPE_ZR36050 2 -#define CODEC_TYPE_ZR36016 3 -#define CODEC_TYPE_ZR36060 4 - -/* the type of data may be enhanced by future implementations (data-fn.'s) */ -/* -> used in command */ -#define CODEC_G_STATUS 0x0000 /* codec status (query only) */ -#define CODEC_S_CODEC_MODE 0x0001 /* codec mode (baseline JPEG, MPEG1,... */ -#define CODEC_G_CODEC_MODE 0x8001 -#define CODEC_S_VFE 0x0002 /* additional video frontend setup */ -#define CODEC_G_VFE 0x8002 -#define CODEC_S_MMAP 0x0003 /* MMAP setup (if available) */ - -#define CODEC_S_JPEG_TDS_BYTE 0x0010 /* target data size in bytes */ -#define CODEC_G_JPEG_TDS_BYTE 0x8010 -#define CODEC_S_JPEG_SCALE 0x0011 /* scaling factor for quant. tables */ -#define CODEC_G_JPEG_SCALE 0x8011 -#define CODEC_S_JPEG_HDT_DATA 0x0018 /* huffman-tables */ -#define CODEC_G_JPEG_HDT_DATA 0x8018 -#define CODEC_S_JPEG_QDT_DATA 0x0019 /* quantizing-tables */ -#define CODEC_G_JPEG_QDT_DATA 0x8019 -#define CODEC_S_JPEG_APP_DATA 0x001A /* APP marker */ -#define CODEC_G_JPEG_APP_DATA 0x801A -#define CODEC_S_JPEG_COM_DATA 0x001B /* COM marker */ -#define CODEC_G_JPEG_COM_DATA 0x801B - -#define CODEC_S_PRIVATE 0x1000 /* "private" commands start here */ -#define CODEC_G_PRIVATE 0x9000 - -#define CODEC_G_FLAG 0x8000 /* this is how 'get' is detected */ - -/* types of transfer, directly user space or a kernel buffer (image-fn.'s) */ -/* -> used in get_image, put_image */ -#define CODEC_TRANSFER_KERNEL 0 /* use "memcopy" */ -#define CODEC_TRANSFER_USER 1 /* use "to/from_user" */ - - -/* ========================= */ -/* the structures itself ... */ -/* ========================= */ - -struct vfe_polarity { - unsigned int vsync_pol:1; - unsigned int hsync_pol:1; - unsigned int field_pol:1; - unsigned int blank_pol:1; - unsigned int subimg_pol:1; - unsigned int poe_pol:1; - unsigned int pvalid_pol:1; - unsigned int vclk_pol:1; -}; - -struct vfe_settings { - __u32 x, y; /* Offsets into image */ - __u32 width, height; /* Area to capture */ - __u16 decimation; /* Decimation divider */ - __u16 flags; /* Flags for capture */ - __u16 quality; /* quality of the video */ -}; - -struct tvnorm { - u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart; -}; - -struct jpeg_com_marker { - int len; /* number of usable bytes in data */ - char data[60]; -}; - -struct jpeg_app_marker { - int appn; /* number app segment */ - int len; /* number of usable bytes in data */ - char data[60]; -}; - -struct videocodec { - struct module *owner; - /* -- filled in by slave device during register -- */ - char name[32]; - unsigned long magic; /* may be used for client<->master attaching */ - unsigned long flags; /* functionality flags */ - unsigned int type; /* codec type */ - - /* -- these is filled in later during master device attach -- */ - - struct videocodec_master *master_data; - - /* -- these are filled in by the slave device during register -- */ - - void *data; /* private slave data */ - - /* attach/detach client functions (indirect call) */ - int (*setup) (struct videocodec * codec); - int (*unset) (struct videocodec * codec); - - /* main functions, every client needs them for sure! */ - // set compression or decompression (or freeze, stop, standby, etc) - int (*set_mode) (struct videocodec * codec, - int mode); - // setup picture size and norm (for the codec's video frontend) - int (*set_video) (struct videocodec * codec, - struct tvnorm * norm, - struct vfe_settings * cap, - struct vfe_polarity * pol); - // other control commands, also mmap setup etc. - int (*control) (struct videocodec * codec, - int type, - int size, - void *data); - - /* additional setup/query/processing (may be NULL pointer) */ - // interrupt setup / handling (for irq's delivered by master) - int (*setup_interrupt) (struct videocodec * codec, - long mode); - int (*handle_interrupt) (struct videocodec * codec, - int source, - long flag); - // picture interface (if any) - long (*put_image) (struct videocodec * codec, - int tr_type, - int block, - long *fr_num, - long *flag, - long size, - void *buf); - long (*get_image) (struct videocodec * codec, - int tr_type, - int block, - long *fr_num, - long *flag, - long size, - void *buf); -}; - -struct videocodec_master { - /* -- filled in by master device for registration -- */ - char name[32]; - unsigned long magic; /* may be used for client<->master attaching */ - unsigned long flags; /* functionality flags */ - unsigned int type; /* master type */ - - void *data; /* private master data */ - - __u32(*readreg) (struct videocodec * codec, - __u16 reg); - void (*writereg) (struct videocodec * codec, - __u16 reg, - __u32 value); -}; - - -/* ================================================= */ -/* function prototypes of the master/slave interface */ -/* ================================================= */ - -/* attach and detach commands for the master */ -// * master structure needs to be kmalloc'ed before calling attach -// and free'd after calling detach -// * returns pointer on success, NULL on failure -extern struct videocodec *videocodec_attach(struct videocodec_master *); -// * 0 on success, <0 (errno) on failure -extern int videocodec_detach(struct videocodec *); - -/* register and unregister commands for the slaves */ -// * 0 on success, <0 (errno) on failure -extern int videocodec_register(const struct videocodec *); -// * 0 on success, <0 (errno) on failure -extern int videocodec_unregister(const struct videocodec *); - -/* the other calls are directly done via the videocodec structure! */ - -#endif /*ifndef __LINUX_VIDEOCODEC_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_card.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_card.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_card.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_card.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1529 +0,0 @@ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles card-specific data and detection - * - * Copyright (C) 2000 Serguei Miridonov - * - * Currently maintained by: - * Ronald Bultje - * Laurent Pinchart - * Mailinglist - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "videocodec.h" -#include "zoran.h" -#include "zoran_card.h" -#include "zoran_device.h" -#include "zoran_procfs.h" - -extern const struct zoran_format zoran_formats[]; - -static int card[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; -module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card, "Card type"); - -static int encoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; -module_param_array(encoder, int, NULL, 0444); -MODULE_PARM_DESC(encoder, "Video encoder chip"); - -static int decoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; -module_param_array(decoder, int, NULL, 0444); -MODULE_PARM_DESC(decoder, "Video decoder chip"); - -/* - The video mem address of the video card. - The driver has a little database for some videocards - to determine it from there. If your video card is not in there - you have either to give it to the driver as a parameter - or set in in a VIDIOCSFBUF ioctl - */ - -static unsigned long vidmem; /* default = 0 - Video memory base address */ -module_param(vidmem, ulong, 0444); -MODULE_PARM_DESC(vidmem, "Default video memory base address"); - -/* - Default input and video norm at startup of the driver. -*/ - -static unsigned int default_input; /* default 0 = Composite, 1 = S-Video */ -module_param(default_input, uint, 0444); -MODULE_PARM_DESC(default_input, - "Default input (0=Composite, 1=S-Video, 2=Internal)"); - -static int default_mux = 1; /* 6 Eyes input selection */ -module_param(default_mux, int, 0644); -MODULE_PARM_DESC(default_mux, - "Default 6 Eyes mux setting (Input selection)"); - -static int default_norm; /* default 0 = PAL, 1 = NTSC 2 = SECAM */ -module_param(default_norm, int, 0444); -MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)"); - -/* /dev/videoN, -1 for autodetect */ -static int video_nr[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; -module_param_array(video_nr, int, NULL, 0444); -MODULE_PARM_DESC(video_nr, "Video device number (-1=Auto)"); - -int v4l_nbufs = 4; -int v4l_bufsize = 864; /* Everybody should be able to work with this setting */ -module_param(v4l_nbufs, int, 0644); -MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use"); -module_param(v4l_bufsize, int, 0644); -MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)"); - -int jpg_nbufs = 32; -int jpg_bufsize = 512; /* max size for 100% quality full-PAL frame */ -module_param(jpg_nbufs, int, 0644); -MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use"); -module_param(jpg_bufsize, int, 0644); -MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)"); - -int pass_through = 0; /* 1=Pass through TV signal when device is not used */ - /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */ -module_param(pass_through, int, 0644); -MODULE_PARM_DESC(pass_through, - "Pass TV signal through to TV-out when idling"); - -int zr36067_debug = 1; -module_param_named(debug, zr36067_debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-5)"); - -MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); -MODULE_AUTHOR("Serguei Miridonov"); -MODULE_LICENSE("GPL"); - -#define ZR_DEVICE(subven, subdev, data) { \ - .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \ - .subvendor = (subven), .subdevice = (subdev), .driver_data = (data) } - -static struct pci_device_id zr36067_pci_tbl[] = { - ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC10PLUS, DC10plus), - ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC30PLUS, DC30plus), - ZR_DEVICE(PCI_VENDOR_ID_ELECTRONICDESIGNGMBH, PCI_DEVICE_ID_LML_33R10, LML33R10), - ZR_DEVICE(PCI_VENDOR_ID_IOMEGA, PCI_DEVICE_ID_IOMEGA_BUZ, BUZ), - ZR_DEVICE(PCI_ANY_ID, PCI_ANY_ID, NUM_CARDS), - {0} -}; -MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); - -static unsigned int zoran_num; /* number of cards found */ - -/* videocodec bus functions ZR36060 */ -static u32 -zr36060_read (struct videocodec *codec, - u16 reg) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - __u32 data; - - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg & 0xff)) { - return -1; - } - - data = post_office_read(zr, 0, 3) & 0xff; - return data; -} - -static void -zr36060_write (struct videocodec *codec, - u16 reg, - u32 val) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg & 0xff)) { - return; - } - - post_office_write(zr, 0, 3, val & 0xff); -} - -/* videocodec bus functions ZR36050 */ -static u32 -zr36050_read (struct videocodec *codec, - u16 reg) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - __u32 data; - - if (post_office_wait(zr) - || post_office_write(zr, 1, 0, reg >> 2)) { // reg. HIGHBYTES - return -1; - } - - data = post_office_read(zr, 0, reg & 0x03) & 0xff; // reg. LOWBYTES + read - return data; -} - -static void -zr36050_write (struct videocodec *codec, - u16 reg, - u32 val) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - - if (post_office_wait(zr) - || post_office_write(zr, 1, 0, reg >> 2)) { // reg. HIGHBYTES - return; - } - - post_office_write(zr, 0, reg & 0x03, val & 0xff); // reg. LOWBYTES + wr. data -} - -/* videocodec bus functions ZR36016 */ -static u32 -zr36016_read (struct videocodec *codec, - u16 reg) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - __u32 data; - - if (post_office_wait(zr)) { - return -1; - } - - data = post_office_read(zr, 2, reg & 0x03) & 0xff; // read - return data; -} - -/* hack for in zoran_device.c */ -void -zr36016_write (struct videocodec *codec, - u16 reg, - u32 val) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - - if (post_office_wait(zr)) { - return; - } - - post_office_write(zr, 2, reg & 0x03, val & 0x0ff); // wr. data -} - -/* - * Board specific information - */ - -static void -dc10_init (struct zoran *zr) -{ - dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); - - /* Pixel clock selection */ - GPIO(zr, 4, 0); - GPIO(zr, 5, 1); - /* Enable the video bus sync signals */ - GPIO(zr, 7, 0); -} - -static void -dc10plus_init (struct zoran *zr) -{ - dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); -} - -static void -buz_init (struct zoran *zr) -{ - dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); - - /* some stuff from Iomega */ - pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15); - pci_write_config_dword(zr->pci_dev, 0x0c, 0x00012020); - pci_write_config_dword(zr->pci_dev, 0xe8, 0xc0200000); -} - -static void -lml33_init (struct zoran *zr) -{ - dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); - - GPIO(zr, 2, 1); // Set Composite input/output -} - -static void -avs6eyes_init (struct zoran *zr) -{ - // AverMedia 6-Eyes original driver by Christer Weinigel - - // Lifted straight from Christer's old driver and - // modified slightly by Martin Samuelsson. - - int mux = default_mux; /* 1 = BT866, 7 = VID1 */ - - GPIO(zr, 4, 1); /* Bt866 SLEEP on */ - udelay(2); - - GPIO(zr, 0, 1); /* ZR36060 /RESET on */ - GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */ - GPIO(zr, 2, mux & 1); /* MUX S0 */ - GPIO(zr, 3, 0); /* /FRAME on */ - GPIO(zr, 4, 0); /* Bt866 SLEEP off */ - GPIO(zr, 5, mux & 2); /* MUX S1 */ - GPIO(zr, 6, 0); /* ? */ - GPIO(zr, 7, mux & 4); /* MUX S2 */ - -} - -static char * -codecid_to_modulename (u16 codecid) -{ - char *name = NULL; - - switch (codecid) { - case CODEC_TYPE_ZR36060: - name = "zr36060"; - break; - case CODEC_TYPE_ZR36050: - name = "zr36050"; - break; - case CODEC_TYPE_ZR36016: - name = "zr36016"; - break; - } - - return name; -} - -// struct tvnorm { -// u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart; -// }; - -static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 }; -static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 }; -static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 }; -static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 }; - -static struct tvnorm f50ccir601_lml33 = { 864, 720, 75+34, 804, 625, 576, 18 }; -static struct tvnorm f60ccir601_lml33 = { 858, 720, 57+34, 788, 525, 480, 16 }; - -/* The DC10 (57/16/50) uses VActive as HSync, so HStart must be 0 */ -static struct tvnorm f50sqpixel_dc10 = { 944, 768, 0, 880, 625, 576, 0 }; -static struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 }; - -/* FIXME: I cannot swap U and V in saa7114, so i do one - * pixel left shift in zoran (75 -> 74) - * (Maxim Yevtyushkin ) */ -static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 }; -static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 }; - -/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I - * copy Maxim's left shift hack for the 6 Eyes. - * - * Christer's driver used the unshifted norms, though... - * /Sam */ -static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 }; -static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 }; - -static const unsigned short vpx3220_addrs[] = { 0x43, 0x47, I2C_CLIENT_END }; -static const unsigned short saa7110_addrs[] = { 0x4e, 0x4f, I2C_CLIENT_END }; -static const unsigned short saa7111_addrs[] = { 0x25, 0x24, I2C_CLIENT_END }; -static const unsigned short saa7114_addrs[] = { 0x21, 0x20, I2C_CLIENT_END }; -static const unsigned short adv717x_addrs[] = { 0x6a, 0x6b, 0x2a, 0x2b, I2C_CLIENT_END }; -static const unsigned short ks0127_addrs[] = { 0x6c, 0x6d, I2C_CLIENT_END }; -static const unsigned short saa7185_addrs[] = { 0x44, I2C_CLIENT_END }; -static const unsigned short bt819_addrs[] = { 0x45, I2C_CLIENT_END }; -static const unsigned short bt856_addrs[] = { 0x44, I2C_CLIENT_END }; -static const unsigned short bt866_addrs[] = { 0x44, I2C_CLIENT_END }; - -static struct card_info zoran_cards[NUM_CARDS] __devinitdata = { - { - .type = DC10_old, - .name = "DC10(old)", - .i2c_decoder = "vpx3220a", - .addrs_decoder = vpx3220_addrs, - .video_codec = CODEC_TYPE_ZR36050, - .video_vfe = CODEC_TYPE_ZR36016, - - .inputs = 3, - .input = { - { 1, "Composite" }, - { 2, "S-Video" }, - { 0, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel_dc10, - &f60sqpixel_dc10, - &f50sqpixel_dc10 - }, - .jpeg_int = 0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 }, - .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 }, - .gpcs = { -1, 0 }, - .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10_init, - }, { - .type = DC10_new, - .name = "DC10(new)", - .i2c_decoder = "saa7110", - .addrs_decoder = saa7110_addrs, - .i2c_encoder = "adv7175", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 3, - .input = { - { 0, "Composite" }, - { 7, "S-Video" }, - { 5, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel, - &f60sqpixel, - &f50sqpixel}, - .jpeg_int = ZR36057_ISR_GIRQ0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 3, 0, 6, 1, 2, -1, 4, 5 }, - .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gpcs = { -1, 1}, - .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10plus_init, - }, { - .type = DC10plus, - .name = "DC10plus", - .i2c_decoder = "saa7110", - .addrs_decoder = saa7110_addrs, - .i2c_encoder = "adv7175", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 3, - .input = { - { 0, "Composite" }, - { 7, "S-Video" }, - { 5, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel, - &f60sqpixel, - &f50sqpixel - }, - .jpeg_int = ZR36057_ISR_GIRQ0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 3, 0, 6, 1, 2, -1, 4, 5 }, - .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gpcs = { -1, 1 }, - .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10plus_init, - }, { - .type = DC30, - .name = "DC30", - .i2c_decoder = "vpx3220a", - .addrs_decoder = vpx3220_addrs, - .i2c_encoder = "adv7175", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36050, - .video_vfe = CODEC_TYPE_ZR36016, - - .inputs = 3, - .input = { - { 1, "Composite" }, - { 2, "S-Video" }, - { 0, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel_dc10, - &f60sqpixel_dc10, - &f50sqpixel_dc10 - }, - .jpeg_int = 0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 }, - .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 }, - .gpcs = { -1, 0 }, - .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10_init, - }, { - .type = DC30plus, - .name = "DC30plus", - .i2c_decoder = "vpx3220a", - .addrs_decoder = vpx3220_addrs, - .i2c_encoder = "adv7175", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36050, - .video_vfe = CODEC_TYPE_ZR36016, - - .inputs = 3, - .input = { - { 1, "Composite" }, - { 2, "S-Video" }, - { 0, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel_dc10, - &f60sqpixel_dc10, - &f50sqpixel_dc10 - }, - .jpeg_int = 0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 }, - .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 }, - .gpcs = { -1, 0 }, - .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10_init, - }, { - .type = LML33, - .name = "LML33", - .i2c_decoder = "bt819a", - .addrs_decoder = bt819_addrs, - .i2c_encoder = "bt856", - .addrs_encoder = bt856_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 2, - .input = { - { 0, "Composite" }, - { 7, "S-Video" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL, - .tvn = { - &f50ccir601_lml33, - &f60ccir601_lml33, - NULL - }, - .jpeg_int = ZR36057_ISR_GIRQ1, - .vsync_int = ZR36057_ISR_GIRQ0, - .gpio = { 1, -1, 3, 5, 7, -1, -1, -1 }, - .gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 }, - .gpcs = { 3, 1 }, - .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 }, - .gws_not_connected = 1, - .input_mux = 0, - .init = &lml33_init, - }, { - .type = LML33R10, - .name = "LML33R10", - .i2c_decoder = "saa7114", - .addrs_decoder = saa7114_addrs, - .i2c_encoder = "adv7170", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 2, - .input = { - { 0, "Composite" }, - { 7, "S-Video" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL, - .tvn = { - &f50ccir601_lm33r10, - &f60ccir601_lm33r10, - NULL - }, - .jpeg_int = ZR36057_ISR_GIRQ1, - .vsync_int = ZR36057_ISR_GIRQ0, - .gpio = { 1, -1, 3, 5, 7, -1, -1, -1 }, - .gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 }, - .gpcs = { 3, 1 }, - .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 }, - .gws_not_connected = 1, - .input_mux = 0, - .init = &lml33_init, - }, { - .type = BUZ, - .name = "Buz", - .i2c_decoder = "saa7111", - .addrs_decoder = saa7111_addrs, - .i2c_encoder = "saa7185", - .addrs_encoder = saa7185_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 2, - .input = { - { 3, "Composite" }, - { 7, "S-Video" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50ccir601, - &f60ccir601, - &f50ccir601 - }, - .jpeg_int = ZR36057_ISR_GIRQ1, - .vsync_int = ZR36057_ISR_GIRQ0, - .gpio = { 1, -1, 3, -1, -1, -1, -1, -1 }, - .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gpcs = { 3, 1 }, - .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 }, - .gws_not_connected = 1, - .input_mux = 0, - .init = &buz_init, - }, { - .type = AVS6EYES, - .name = "6-Eyes", - /* AverMedia chose not to brand the 6-Eyes. Thus it - can't be autodetected, and requires card=x. */ - .i2c_decoder = "ks0127", - .addrs_decoder = ks0127_addrs, - .i2c_encoder = "bt866", - .addrs_encoder = bt866_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 10, - .input = { - { 0, "Composite 1" }, - { 1, "Composite 2" }, - { 2, "Composite 3" }, - { 4, "Composite 4" }, - { 5, "Composite 5" }, - { 6, "Composite 6" }, - { 8, "S-Video 1" }, - { 9, "S-Video 2" }, - {10, "S-Video 3" }, - {15, "YCbCr" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL, - .tvn = { - &f50ccir601_avs6eyes, - &f60ccir601_avs6eyes, - NULL - }, - .jpeg_int = ZR36057_ISR_GIRQ1, - .vsync_int = ZR36057_ISR_GIRQ0, - .gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam - .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam - .gpcs = { 3, 1 }, // Validity unknown /Sam - .vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 }, // Validity unknown /Sam - .gws_not_connected = 1, - .input_mux = 1, - .init = &avs6eyes_init, - } - -}; - -/* - * I2C functions - */ -/* software I2C functions */ -static int -zoran_i2c_getsda (void *data) -{ - struct zoran *zr = (struct zoran *) data; - - return (btread(ZR36057_I2CBR) >> 1) & 1; -} - -static int -zoran_i2c_getscl (void *data) -{ - struct zoran *zr = (struct zoran *) data; - - return btread(ZR36057_I2CBR) & 1; -} - -static void -zoran_i2c_setsda (void *data, - int state) -{ - struct zoran *zr = (struct zoran *) data; - - if (state) - zr->i2cbr |= 2; - else - zr->i2cbr &= ~2; - btwrite(zr->i2cbr, ZR36057_I2CBR); -} - -static void -zoran_i2c_setscl (void *data, - int state) -{ - struct zoran *zr = (struct zoran *) data; - - if (state) - zr->i2cbr |= 1; - else - zr->i2cbr &= ~1; - btwrite(zr->i2cbr, ZR36057_I2CBR); -} - -static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = { - .setsda = zoran_i2c_setsda, - .setscl = zoran_i2c_setscl, - .getsda = zoran_i2c_getsda, - .getscl = zoran_i2c_getscl, - .udelay = 10, - .timeout = 100, -}; - -static int -zoran_register_i2c (struct zoran *zr) -{ - memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template, - sizeof(struct i2c_algo_bit_data)); - zr->i2c_algo.data = zr; - strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr), - sizeof(zr->i2c_adapter.name)); - i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev); - zr->i2c_adapter.algo_data = &zr->i2c_algo; - zr->i2c_adapter.dev.parent = &zr->pci_dev->dev; - return i2c_bit_add_bus(&zr->i2c_adapter); -} - -static void -zoran_unregister_i2c (struct zoran *zr) -{ - i2c_del_adapter(&zr->i2c_adapter); -} - -/* Check a zoran_params struct for correctness, insert default params */ - -int -zoran_check_jpg_settings (struct zoran *zr, - struct zoran_jpg_settings *settings, - int try) -{ - int err = 0, err0 = 0; - - dprintk(4, - KERN_DEBUG - "%s: %s - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n", - ZR_DEVNAME(zr), __func__, settings->decimation, settings->HorDcm, - settings->VerDcm, settings->TmpDcm); - dprintk(4, - KERN_DEBUG - "%s: %s - x: %d, y: %d, w: %d, y: %d\n", - ZR_DEVNAME(zr), __func__, settings->img_x, settings->img_y, - settings->img_width, settings->img_height); - /* Check decimation, set default values for decimation = 1, 2, 4 */ - switch (settings->decimation) { - case 1: - - settings->HorDcm = 1; - settings->VerDcm = 1; - settings->TmpDcm = 1; - settings->field_per_buff = 2; - settings->img_x = 0; - settings->img_y = 0; - settings->img_width = BUZ_MAX_WIDTH; - settings->img_height = BUZ_MAX_HEIGHT / 2; - break; - case 2: - - settings->HorDcm = 2; - settings->VerDcm = 1; - settings->TmpDcm = 2; - settings->field_per_buff = 1; - settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; - settings->img_y = 0; - settings->img_width = - (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; - settings->img_height = BUZ_MAX_HEIGHT / 2; - break; - case 4: - - if (zr->card.type == DC10_new) { - dprintk(1, - KERN_DEBUG - "%s: %s - HDec by 4 is not supported on the DC10\n", - ZR_DEVNAME(zr), __func__); - err0++; - break; - } - - settings->HorDcm = 4; - settings->VerDcm = 2; - settings->TmpDcm = 2; - settings->field_per_buff = 1; - settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; - settings->img_y = 0; - settings->img_width = - (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; - settings->img_height = BUZ_MAX_HEIGHT / 2; - break; - case 0: - - /* We have to check the data the user has set */ - - if (settings->HorDcm != 1 && settings->HorDcm != 2 && - (zr->card.type == DC10_new || settings->HorDcm != 4)) { - settings->HorDcm = clamp(settings->HorDcm, 1, 2); - err0++; - } - if (settings->VerDcm != 1 && settings->VerDcm != 2) { - settings->VerDcm = clamp(settings->VerDcm, 1, 2); - err0++; - } - if (settings->TmpDcm != 1 && settings->TmpDcm != 2) { - settings->TmpDcm = clamp(settings->TmpDcm, 1, 2); - err0++; - } - if (settings->field_per_buff != 1 && - settings->field_per_buff != 2) { - settings->field_per_buff = clamp(settings->field_per_buff, 1, 2); - err0++; - } - if (settings->img_x < 0) { - settings->img_x = 0; - err0++; - } - if (settings->img_y < 0) { - settings->img_y = 0; - err0++; - } - if (settings->img_width < 0 || settings->img_width > BUZ_MAX_WIDTH) { - settings->img_width = clamp(settings->img_width, 0, (int)BUZ_MAX_WIDTH); - err0++; - } - if (settings->img_height < 0 || settings->img_height > BUZ_MAX_HEIGHT / 2) { - settings->img_height = clamp(settings->img_height, 0, BUZ_MAX_HEIGHT / 2); - err0++; - } - if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH) { - settings->img_x = BUZ_MAX_WIDTH - settings->img_width; - err0++; - } - if (settings->img_y + settings->img_height > BUZ_MAX_HEIGHT / 2) { - settings->img_y = BUZ_MAX_HEIGHT / 2 - settings->img_height; - err0++; - } - if (settings->img_width % (16 * settings->HorDcm) != 0) { - settings->img_width -= settings->img_width % (16 * settings->HorDcm); - if (settings->img_width == 0) - settings->img_width = 16 * settings->HorDcm; - err0++; - } - if (settings->img_height % (8 * settings->VerDcm) != 0) { - settings->img_height -= settings->img_height % (8 * settings->VerDcm); - if (settings->img_height == 0) - settings->img_height = 8 * settings->VerDcm; - err0++; - } - - if (!try && err0) { - dprintk(1, - KERN_ERR - "%s: %s - error in params for decimation = 0\n", - ZR_DEVNAME(zr), __func__); - err++; - } - break; - default: - dprintk(1, - KERN_ERR - "%s: %s - decimation = %d, must be 0, 1, 2 or 4\n", - ZR_DEVNAME(zr), __func__, settings->decimation); - err++; - break; - } - - if (settings->jpg_comp.quality > 100) - settings->jpg_comp.quality = 100; - if (settings->jpg_comp.quality < 5) - settings->jpg_comp.quality = 5; - if (settings->jpg_comp.APPn < 0) - settings->jpg_comp.APPn = 0; - if (settings->jpg_comp.APPn > 15) - settings->jpg_comp.APPn = 15; - if (settings->jpg_comp.APP_len < 0) - settings->jpg_comp.APP_len = 0; - if (settings->jpg_comp.APP_len > 60) - settings->jpg_comp.APP_len = 60; - if (settings->jpg_comp.COM_len < 0) - settings->jpg_comp.COM_len = 0; - if (settings->jpg_comp.COM_len > 60) - settings->jpg_comp.COM_len = 60; - if (err) - return -EINVAL; - return 0; -} - -void -zoran_open_init_params (struct zoran *zr) -{ - int i; - - /* User must explicitly set a window */ - zr->overlay_settings.is_set = 0; - zr->overlay_mask = NULL; - zr->overlay_active = ZORAN_FREE; - - zr->v4l_memgrab_active = 0; - zr->v4l_overlay_active = 0; - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_grab_seq = 0; - zr->v4l_settings.width = 192; - zr->v4l_settings.height = 144; - zr->v4l_settings.format = &zoran_formats[7]; /* YUY2 - YUV-4:2:2 packed */ - zr->v4l_settings.bytesperline = - zr->v4l_settings.width * - ((zr->v4l_settings.format->depth + 7) / 8); - - /* DMA ring stuff for V4L */ - zr->v4l_pend_tail = 0; - zr->v4l_pend_head = 0; - zr->v4l_sync_tail = 0; - zr->v4l_buffers.active = ZORAN_FREE; - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ - } - zr->v4l_buffers.allocated = 0; - - for (i = 0; i < BUZ_MAX_FRAME; i++) { - zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ - } - zr->jpg_buffers.active = ZORAN_FREE; - zr->jpg_buffers.allocated = 0; - /* Set necessary params and call zoran_check_jpg_settings to set the defaults */ - zr->jpg_settings.decimation = 1; - zr->jpg_settings.jpg_comp.quality = 50; /* default compression factor 8 */ - if (zr->card.type != BUZ) - zr->jpg_settings.odd_even = 1; - else - zr->jpg_settings.odd_even = 0; - zr->jpg_settings.jpg_comp.APPn = 0; - zr->jpg_settings.jpg_comp.APP_len = 0; /* No APPn marker */ - memset(zr->jpg_settings.jpg_comp.APP_data, 0, - sizeof(zr->jpg_settings.jpg_comp.APP_data)); - zr->jpg_settings.jpg_comp.COM_len = 0; /* No COM marker */ - memset(zr->jpg_settings.jpg_comp.COM_data, 0, - sizeof(zr->jpg_settings.jpg_comp.COM_data)); - zr->jpg_settings.jpg_comp.jpeg_markers = - V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT; - i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0); - if (i) - dprintk(1, KERN_ERR "%s: %s internal error\n", - ZR_DEVNAME(zr), __func__); - - clear_interrupt_counters(zr); - zr->testing = 0; -} - -static void __devinit -test_interrupts (struct zoran *zr) -{ - DEFINE_WAIT(wait); - int timeout, icr; - - clear_interrupt_counters(zr); - - zr->testing = 1; - icr = btread(ZR36057_ICR); - btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR); - prepare_to_wait(&zr->test_q, &wait, TASK_INTERRUPTIBLE); - timeout = schedule_timeout(HZ); - finish_wait(&zr->test_q, &wait); - btwrite(0, ZR36057_ICR); - btwrite(0x78000000, ZR36057_ISR); - zr->testing = 0; - dprintk(5, KERN_INFO "%s: Testing interrupts...\n", ZR_DEVNAME(zr)); - if (timeout) { - dprintk(1, ": time spent: %d\n", 1 * HZ - timeout); - } - if (zr36067_debug > 1) - print_interrupts(zr); - btwrite(icr, ZR36057_ICR); -} - -static int __devinit -zr36057_init (struct zoran *zr) -{ - int j, err; - - dprintk(1, - KERN_INFO - "%s: %s - initializing card[%d], zr=%p\n", - ZR_DEVNAME(zr), __func__, zr->id, zr); - - /* default setup of all parameters which will persist between opens */ - zr->user = 0; - - init_waitqueue_head(&zr->v4l_capq); - init_waitqueue_head(&zr->jpg_capq); - init_waitqueue_head(&zr->test_q); - zr->jpg_buffers.allocated = 0; - zr->v4l_buffers.allocated = 0; - - zr->vbuf_base = (void *) vidmem; - zr->vbuf_width = 0; - zr->vbuf_height = 0; - zr->vbuf_depth = 0; - zr->vbuf_bytesperline = 0; - - /* Avoid nonsense settings from user for default input/norm */ - if (default_norm < 0 || default_norm > 2) - default_norm = 0; - if (default_norm == 0) { - zr->norm = V4L2_STD_PAL; - zr->timing = zr->card.tvn[0]; - } else if (default_norm == 1) { - zr->norm = V4L2_STD_NTSC; - zr->timing = zr->card.tvn[1]; - } else { - zr->norm = V4L2_STD_SECAM; - zr->timing = zr->card.tvn[2]; - } - if (zr->timing == NULL) { - dprintk(1, - KERN_WARNING - "%s: %s - default TV standard not supported by hardware. PAL will be used.\n", - ZR_DEVNAME(zr), __func__); - zr->norm = V4L2_STD_PAL; - zr->timing = zr->card.tvn[0]; - } - - if (default_input > zr->card.inputs-1) { - dprintk(1, - KERN_WARNING - "%s: default_input value %d out of range (0-%d)\n", - ZR_DEVNAME(zr), default_input, zr->card.inputs-1); - default_input = 0; - } - zr->input = default_input; - - /* default setup (will be repeated at every open) */ - zoran_open_init_params(zr); - - /* allocate memory *before* doing anything to the hardware - * in case allocation fails */ - zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL); - zr->video_dev = video_device_alloc(); - if (!zr->stat_com || !zr->video_dev) { - dprintk(1, - KERN_ERR - "%s: %s - kmalloc (STAT_COM) failed\n", - ZR_DEVNAME(zr), __func__); - err = -ENOMEM; - goto exit_free; - } - for (j = 0; j < BUZ_NUM_STAT_COM; j++) { - zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ - } - - /* - * Now add the template and register the device unit. - */ - memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template)); - zr->video_dev->parent = &zr->pci_dev->dev; - strcpy(zr->video_dev->name, ZR_DEVNAME(zr)); - err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]); - if (err < 0) - goto exit_free; - video_set_drvdata(zr->video_dev, zr); - - zoran_init_hardware(zr); - if (zr36067_debug > 2) - detect_guest_activity(zr); - test_interrupts(zr); - if (!pass_through) { - decoder_call(zr, video, s_stream, 0); - encoder_call(zr, video, s_routing, 2, 0, 0); - } - - zr->zoran_proc = NULL; - zr->initialized = 1; - return 0; - -exit_free: - kfree(zr->stat_com); - kfree(zr->video_dev); - return err; -} - -static void __devexit zoran_remove(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct zoran *zr = to_zoran(v4l2_dev); - - if (!zr->initialized) - goto exit_free; - - /* unregister videocodec bus */ - if (zr->codec) { - struct videocodec_master *master = zr->codec->master_data; - - videocodec_detach(zr->codec); - kfree(master); - } - if (zr->vfe) { - struct videocodec_master *master = zr->vfe->master_data; - - videocodec_detach(zr->vfe); - kfree(master); - } - - /* unregister i2c bus */ - zoran_unregister_i2c(zr); - /* disable PCI bus-mastering */ - zoran_set_pci_master(zr, 0); - /* put chip into reset */ - btwrite(0, ZR36057_SPGPPCR); - free_irq(zr->pci_dev->irq, zr); - /* unmap and free memory */ - kfree(zr->stat_com); - zoran_proc_cleanup(zr); - iounmap(zr->zr36057_mem); - pci_disable_device(zr->pci_dev); - video_unregister_device(zr->video_dev); -exit_free: - v4l2_device_unregister(&zr->v4l2_dev); - kfree(zr); -} - -void -zoran_vdev_release (struct video_device *vdev) -{ - kfree(vdev); -} - -static struct videocodec_master * __devinit -zoran_setup_videocodec (struct zoran *zr, - int type) -{ - struct videocodec_master *m = NULL; - - m = kmalloc(sizeof(struct videocodec_master), GFP_KERNEL); - if (!m) { - dprintk(1, KERN_ERR "%s: %s - no memory\n", - ZR_DEVNAME(zr), __func__); - return m; - } - - /* magic and type are unused for master struct. Makes sense only at - codec structs. - In the past, .type were initialized to the old V4L1 .hardware - value, as VID_HARDWARE_ZR36067 - */ - m->magic = 0L; - m->type = 0; - - m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER; - strlcpy(m->name, ZR_DEVNAME(zr), sizeof(m->name)); - m->data = zr; - - switch (type) - { - case CODEC_TYPE_ZR36060: - m->readreg = zr36060_read; - m->writereg = zr36060_write; - m->flags |= CODEC_FLAG_JPEG | CODEC_FLAG_VFE; - break; - case CODEC_TYPE_ZR36050: - m->readreg = zr36050_read; - m->writereg = zr36050_write; - m->flags |= CODEC_FLAG_JPEG; - break; - case CODEC_TYPE_ZR36016: - m->readreg = zr36016_read; - m->writereg = zr36016_write; - m->flags |= CODEC_FLAG_VFE; - break; - } - - return m; -} - -static void zoran_subdev_notify(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct zoran *zr = to_zoran(sd->v4l2_dev); - - /* Bt819 needs to reset its FIFO buffer using #FRST pin and - LML33 card uses GPIO(7) for that. */ - if (cmd == BT819_FIFO_RESET_LOW) - GPIO(zr, 7, 0); - else if (cmd == BT819_FIFO_RESET_HIGH) - GPIO(zr, 7, 1); -} - -/* - * Scan for a Buz card (actually for the PCI controller ZR36057), - * request the irq and map the io memory - */ -static int __devinit zoran_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - unsigned char latency, need_latency; - struct zoran *zr; - int result; - struct videocodec_master *master_vfe = NULL; - struct videocodec_master *master_codec = NULL; - int card_num; - char *codec_name, *vfe_name; - unsigned int nr; - - - nr = zoran_num++; - if (nr >= BUZ_MAX) { - dprintk(1, KERN_ERR "%s: driver limited to %d card(s) maximum\n", - ZORAN_NAME, BUZ_MAX); - return -ENOENT; - } - - zr = kzalloc(sizeof(struct zoran), GFP_KERNEL); - if (!zr) { - dprintk(1, KERN_ERR "%s: %s - kzalloc failed\n", - ZORAN_NAME, __func__); - return -ENOMEM; - } - zr->v4l2_dev.notify = zoran_subdev_notify; - if (v4l2_device_register(&pdev->dev, &zr->v4l2_dev)) - goto zr_free_mem; - zr->pci_dev = pdev; - zr->id = nr; - snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id); - spin_lock_init(&zr->spinlock); - mutex_init(&zr->resource_lock); - mutex_init(&zr->other_lock); - if (pci_enable_device(pdev)) - goto zr_unreg; - pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); - - dprintk(1, - KERN_INFO - "%s: Zoran ZR360%c7 (rev %d), irq: %d, memory: 0x%08llx\n", - ZR_DEVNAME(zr), zr->revision < 2 ? '5' : '6', zr->revision, - zr->pci_dev->irq, (uint64_t)pci_resource_start(zr->pci_dev, 0)); - if (zr->revision >= 2) { - dprintk(1, - KERN_INFO - "%s: Subsystem vendor=0x%04x id=0x%04x\n", - ZR_DEVNAME(zr), zr->pci_dev->subsystem_vendor, - zr->pci_dev->subsystem_device); - } - - /* Use auto-detected card type? */ - if (card[nr] == -1) { - if (zr->revision < 2) { - dprintk(1, - KERN_ERR - "%s: No card type specified, please use the card=X module parameter\n", - ZR_DEVNAME(zr)); - dprintk(1, - KERN_ERR - "%s: It is not possible to auto-detect ZR36057 based cards\n", - ZR_DEVNAME(zr)); - goto zr_unreg; - } - - card_num = ent->driver_data; - if (card_num >= NUM_CARDS) { - dprintk(1, - KERN_ERR - "%s: Unknown card, try specifying card=X module parameter\n", - ZR_DEVNAME(zr)); - goto zr_unreg; - } - dprintk(3, - KERN_DEBUG - "%s: %s() - card %s detected\n", - ZR_DEVNAME(zr), __func__, zoran_cards[card_num].name); - } else { - card_num = card[nr]; - if (card_num >= NUM_CARDS || card_num < 0) { - dprintk(1, - KERN_ERR - "%s: User specified card type %d out of range (0 .. %d)\n", - ZR_DEVNAME(zr), card_num, NUM_CARDS - 1); - goto zr_unreg; - } - } - - /* even though we make this a non pointer and thus - * theoretically allow for making changes to this struct - * on a per-individual card basis at runtime, this is - * strongly discouraged. This structure is intended to - * keep general card information, no settings or anything */ - zr->card = zoran_cards[card_num]; - snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), - "%s[%u]", zr->card.name, zr->id); - - zr->zr36057_mem = pci_ioremap_bar(zr->pci_dev, 0); - if (!zr->zr36057_mem) { - dprintk(1, KERN_ERR "%s: %s() - ioremap failed\n", - ZR_DEVNAME(zr), __func__); - goto zr_unreg; - } - - result = request_irq(zr->pci_dev->irq, zoran_irq, - IRQF_SHARED | IRQF_DISABLED, ZR_DEVNAME(zr), zr); - if (result < 0) { - if (result == -EINVAL) { - dprintk(1, - KERN_ERR - "%s: %s - bad irq number or handler\n", - ZR_DEVNAME(zr), __func__); - } else if (result == -EBUSY) { - dprintk(1, - KERN_ERR - "%s: %s - IRQ %d busy, change your PnP config in BIOS\n", - ZR_DEVNAME(zr), __func__, zr->pci_dev->irq); - } else { - dprintk(1, - KERN_ERR - "%s: %s - can't assign irq, error code %d\n", - ZR_DEVNAME(zr), __func__, result); - } - goto zr_unmap; - } - - /* set PCI latency timer */ - pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, - &latency); - need_latency = zr->revision > 1 ? 32 : 48; - if (latency != need_latency) { - dprintk(2, KERN_INFO "%s: Changing PCI latency from %d to %d\n", - ZR_DEVNAME(zr), latency, need_latency); - pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, - need_latency); - } - - zr36057_restart(zr); - /* i2c */ - dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n", - ZR_DEVNAME(zr)); - - if (zoran_register_i2c(zr) < 0) { - dprintk(1, KERN_ERR "%s: %s - can't initialize i2c bus\n", - ZR_DEVNAME(zr), __func__); - goto zr_free_irq; - } - - zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, - &zr->i2c_adapter, zr->card.i2c_decoder, - 0, zr->card.addrs_decoder); - - if (zr->card.i2c_encoder) - zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, - &zr->i2c_adapter, zr->card.i2c_encoder, - 0, zr->card.addrs_encoder); - - dprintk(2, - KERN_INFO "%s: Initializing videocodec bus...\n", - ZR_DEVNAME(zr)); - - if (zr->card.video_codec) { - codec_name = codecid_to_modulename(zr->card.video_codec); - if (codec_name) { - result = request_module(codec_name); - if (result) { - dprintk(1, - KERN_ERR - "%s: failed to load modules %s: %d\n", - ZR_DEVNAME(zr), codec_name, result); - } - } - } - if (zr->card.video_vfe) { - vfe_name = codecid_to_modulename(zr->card.video_vfe); - if (vfe_name) { - result = request_module(vfe_name); - if (result < 0) { - dprintk(1, - KERN_ERR - "%s: failed to load modules %s: %d\n", - ZR_DEVNAME(zr), vfe_name, result); - } - } - } - - /* reset JPEG codec */ - jpeg_codec_sleep(zr, 1); - jpeg_codec_reset(zr); - /* video bus enabled */ - /* display codec revision */ - if (zr->card.video_codec != 0) { - master_codec = zoran_setup_videocodec(zr, zr->card.video_codec); - if (!master_codec) - goto zr_unreg_i2c; - zr->codec = videocodec_attach(master_codec); - if (!zr->codec) { - dprintk(1, KERN_ERR "%s: %s - no codec found\n", - ZR_DEVNAME(zr), __func__); - goto zr_free_codec; - } - if (zr->codec->type != zr->card.video_codec) { - dprintk(1, KERN_ERR "%s: %s - wrong codec\n", - ZR_DEVNAME(zr), __func__); - goto zr_detach_codec; - } - } - if (zr->card.video_vfe != 0) { - master_vfe = zoran_setup_videocodec(zr, zr->card.video_vfe); - if (!master_vfe) - goto zr_detach_codec; - zr->vfe = videocodec_attach(master_vfe); - if (!zr->vfe) { - dprintk(1, KERN_ERR "%s: %s - no VFE found\n", - ZR_DEVNAME(zr), __func__); - goto zr_free_vfe; - } - if (zr->vfe->type != zr->card.video_vfe) { - dprintk(1, KERN_ERR "%s: %s = wrong VFE\n", - ZR_DEVNAME(zr), __func__); - goto zr_detach_vfe; - } - } - - /* take care of Natoma chipset and a revision 1 zr36057 */ - if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) { - zr->jpg_buffers.need_contiguous = 1; - dprintk(1, KERN_INFO - "%s: ZR36057/Natoma bug, max. buffer size is 128K\n", - ZR_DEVNAME(zr)); - } - - if (zr36057_init(zr) < 0) - goto zr_detach_vfe; - - zoran_proc_init(zr); - - return 0; - -zr_detach_vfe: - videocodec_detach(zr->vfe); -zr_free_vfe: - kfree(master_vfe); -zr_detach_codec: - videocodec_detach(zr->codec); -zr_free_codec: - kfree(master_codec); -zr_unreg_i2c: - zoran_unregister_i2c(zr); -zr_free_irq: - btwrite(0, ZR36057_SPGPPCR); - free_irq(zr->pci_dev->irq, zr); -zr_unmap: - iounmap(zr->zr36057_mem); -zr_unreg: - v4l2_device_unregister(&zr->v4l2_dev); -zr_free_mem: - kfree(zr); - - return -ENODEV; -} - -static struct pci_driver zoran_driver = { - .name = "zr36067", - .id_table = zr36067_pci_tbl, - .probe = zoran_probe, - .remove = __devexit_p(zoran_remove), -}; - -static int __init zoran_init(void) -{ - int res; - - printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n", - MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION); - - /* check the parameters we have been given, adjust if necessary */ - if (v4l_nbufs < 2) - v4l_nbufs = 2; - if (v4l_nbufs > VIDEO_MAX_FRAME) - v4l_nbufs = VIDEO_MAX_FRAME; - /* The user specfies the in KB, we want them in byte - * (and page aligned) */ - v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); - if (v4l_bufsize < 32768) - v4l_bufsize = 32768; - /* 2 MB is arbitrary but sufficient for the maximum possible images */ - if (v4l_bufsize > 2048 * 1024) - v4l_bufsize = 2048 * 1024; - if (jpg_nbufs < 4) - jpg_nbufs = 4; - if (jpg_nbufs > BUZ_MAX_FRAME) - jpg_nbufs = BUZ_MAX_FRAME; - jpg_bufsize = PAGE_ALIGN(jpg_bufsize * 1024); - if (jpg_bufsize < 8192) - jpg_bufsize = 8192; - if (jpg_bufsize > (512 * 1024)) - jpg_bufsize = 512 * 1024; - /* Use parameter for vidmem or try to find a video card */ - if (vidmem) { - dprintk(1, - KERN_INFO - "%s: Using supplied video memory base address @ 0x%lx\n", - ZORAN_NAME, vidmem); - } - - /* some mainboards might not do PCI-PCI data transfer well */ - if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) { - dprintk(1, - KERN_WARNING - "%s: chipset does not support reliable PCI-PCI DMA\n", - ZORAN_NAME); - } - - res = pci_register_driver(&zoran_driver); - if (res) { - dprintk(1, - KERN_ERR - "%s: Unable to register ZR36057 driver\n", - ZORAN_NAME); - return res; - } - - return 0; -} - -static void __exit zoran_exit(void) -{ - pci_unregister_driver(&zoran_driver); -} - -module_init(zoran_init); -module_exit(zoran_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_card.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_card.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_card.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_card.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles card-specific data and detection - * - * Copyright (C) 2000 Serguei Miridonov - * - * Currently maintained by: - * Ronald Bultje - * Laurent Pinchart - * Mailinglist - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ZORAN_CARD_H__ -#define __ZORAN_CARD_H__ - -extern int zr36067_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (zr36067_debug >= num) \ - printk(format, ##args); \ - } while (0) - -/* Anybody who uses more than four? */ -#define BUZ_MAX 4 - -extern struct video_device zoran_template; - -extern int zoran_check_jpg_settings(struct zoran *zr, - struct zoran_jpg_settings *settings, - int try); -extern void zoran_open_init_params(struct zoran *zr); -extern void zoran_vdev_release(struct video_device *vdev); - -void zr36016_write(struct videocodec *codec, u16 reg, u32 val); - -#endif /* __ZORAN_CARD_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_device.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_device.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_device.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_device.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1642 +0,0 @@ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles device access (PCI/I2C/codec/...) - * - * Copyright (C) 2000 Serguei Miridonov - * - * Currently maintained by: - * Ronald Bultje - * Laurent Pinchart - * Mailinglist - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "videocodec.h" -#include "zoran.h" -#include "zoran_device.h" -#include "zoran_card.h" - -#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \ - ZR36057_ISR_GIRQ1 | \ - ZR36057_ISR_JPEGRepIRQ ) - -static int lml33dpath; /* default = 0 - * 1 will use digital path in capture - * mode instead of analog. It can be - * used for picture adjustments using - * tool like xawtv while watching image - * on TV monitor connected to the output. - * However, due to absence of 75 Ohm - * load on Bt819 input, there will be - * some image imperfections */ - -module_param(lml33dpath, bool, 0644); -MODULE_PARM_DESC(lml33dpath, - "Use digital path capture mode (on LML33 cards)"); - -static void -zr36057_init_vfe (struct zoran *zr); - -/* - * General Purpose I/O and Guest bus access - */ - -/* - * This is a bit tricky. When a board lacks a GPIO function, the corresponding - * GPIO bit number in the card_info structure is set to 0. - */ - -void -GPIO (struct zoran *zr, - int bit, - unsigned int value) -{ - u32 reg; - u32 mask; - - /* Make sure the bit number is legal - * A bit number of -1 (lacking) gives a mask of 0, - * making it harmless */ - mask = (1 << (24 + bit)) & 0xff000000; - reg = btread(ZR36057_GPPGCR1) & ~mask; - if (value) { - reg |= mask; - } - btwrite(reg, ZR36057_GPPGCR1); - udelay(1); -} - -/* - * Wait til post office is no longer busy - */ - -int -post_office_wait (struct zoran *zr) -{ - u32 por; - -// while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { - while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) { - /* wait for something to happen */ - } - if ((por & ZR36057_POR_POTime) && !zr->card.gws_not_connected) { - /* In LML33/BUZ \GWS line is not connected, so it has always timeout set */ - dprintk(1, KERN_INFO "%s: pop timeout %08x\n", ZR_DEVNAME(zr), - por); - return -1; - } - - return 0; -} - -int -post_office_write (struct zoran *zr, - unsigned int guest, - unsigned int reg, - unsigned int value) -{ - u32 por; - - por = - ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | - ((reg & 7) << 16) | (value & 0xFF); - btwrite(por, ZR36057_POR); - - return post_office_wait(zr); -} - -int -post_office_read (struct zoran *zr, - unsigned int guest, - unsigned int reg) -{ - u32 por; - - por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); - btwrite(por, ZR36057_POR); - if (post_office_wait(zr) < 0) { - return -1; - } - - return btread(ZR36057_POR) & 0xFF; -} - -/* - * detect guests - */ - -static void -dump_guests (struct zoran *zr) -{ - if (zr36067_debug > 2) { - int i, guest[8]; - - for (i = 1; i < 8; i++) { // Don't read jpeg codec here - guest[i] = post_office_read(zr, i, 0); - } - - printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr)); - - for (i = 1; i < 8; i++) { - printk(" 0x%02x", guest[i]); - } - printk("\n"); - } -} - -static inline unsigned long -get_time (void) -{ - struct timeval tv; - - do_gettimeofday(&tv); - return (1000000 * tv.tv_sec + tv.tv_usec); -} - -void -detect_guest_activity (struct zoran *zr) -{ - int timeout, i, j, res, guest[8], guest0[8], change[8][3]; - unsigned long t0, t1; - - dump_guests(zr); - printk(KERN_INFO "%s: Detecting guests activity, please wait...\n", - ZR_DEVNAME(zr)); - for (i = 1; i < 8; i++) { // Don't read jpeg codec here - guest0[i] = guest[i] = post_office_read(zr, i, 0); - } - - timeout = 0; - j = 0; - t0 = get_time(); - while (timeout < 10000) { - udelay(10); - timeout++; - for (i = 1; (i < 8) && (j < 8); i++) { - res = post_office_read(zr, i, 0); - if (res != guest[i]) { - t1 = get_time(); - change[j][0] = (t1 - t0); - t0 = t1; - change[j][1] = i; - change[j][2] = res; - j++; - guest[i] = res; - } - } - if (j >= 8) - break; - } - printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr)); - - for (i = 1; i < 8; i++) { - printk(" 0x%02x", guest0[i]); - } - printk("\n"); - if (j == 0) { - printk(KERN_INFO "%s: No activity detected.\n", ZR_DEVNAME(zr)); - return; - } - for (i = 0; i < j; i++) { - printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", ZR_DEVNAME(zr), - change[i][0], change[i][1], change[i][2]); - } -} - -/* - * JPEG Codec access - */ - -void -jpeg_codec_sleep (struct zoran *zr, - int sleep) -{ - GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep); - if (!sleep) { - dprintk(3, - KERN_DEBUG - "%s: jpeg_codec_sleep() - wake GPIO=0x%08x\n", - ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1)); - udelay(500); - } else { - dprintk(3, - KERN_DEBUG - "%s: jpeg_codec_sleep() - sleep GPIO=0x%08x\n", - ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1)); - udelay(2); - } -} - -int -jpeg_codec_reset (struct zoran *zr) -{ - /* Take the codec out of sleep */ - jpeg_codec_sleep(zr, 0); - - if (zr->card.gpcs[GPCS_JPEG_RESET] != 0xff) { - post_office_write(zr, zr->card.gpcs[GPCS_JPEG_RESET], 0, - 0); - udelay(2); - } else { - GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 0); - udelay(2); - GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 1); - udelay(2); - } - - return 0; -} - -/* - * Set the registers for the size we have specified. Don't bother - * trying to understand this without the ZR36057 manual in front of - * you [AC]. - * - * PS: The manual is free for download in .pdf format from - * www.zoran.com - nicely done those folks. - */ - -static void -zr36057_adjust_vfe (struct zoran *zr, - enum zoran_codec_mode mode) -{ - u32 reg; - - switch (mode) { - case BUZ_MODE_MOTION_DECOMPRESS: - btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); - reg = btread(ZR36057_VFEHCR); - if ((reg & (1 << 10)) && zr->card.type != LML33R10) { - reg += ((1 << 10) | 1); - } - btwrite(reg, ZR36057_VFEHCR); - break; - case BUZ_MODE_MOTION_COMPRESS: - case BUZ_MODE_IDLE: - default: - if ((zr->norm & V4L2_STD_NTSC) || - (zr->card.type == LML33R10 && - (zr->norm & V4L2_STD_PAL))) - btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); - else - btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); - reg = btread(ZR36057_VFEHCR); - if (!(reg & (1 << 10)) && zr->card.type != LML33R10) { - reg -= ((1 << 10) | 1); - } - btwrite(reg, ZR36057_VFEHCR); - break; - } -} - -/* - * set geometry - */ - -static void -zr36057_set_vfe (struct zoran *zr, - int video_width, - int video_height, - const struct zoran_format *format) -{ - struct tvnorm *tvn; - unsigned HStart, HEnd, VStart, VEnd; - unsigned DispMode; - unsigned VidWinWid, VidWinHt; - unsigned hcrop1, hcrop2, vcrop1, vcrop2; - unsigned Wa, We, Ha, He; - unsigned X, Y, HorDcm, VerDcm; - u32 reg; - unsigned mask_line_size; - - tvn = zr->timing; - - Wa = tvn->Wa; - Ha = tvn->Ha; - - dprintk(2, KERN_INFO "%s: set_vfe() - width = %d, height = %d\n", - ZR_DEVNAME(zr), video_width, video_height); - - if (video_width < BUZ_MIN_WIDTH || - video_height < BUZ_MIN_HEIGHT || - video_width > Wa || video_height > Ha) { - dprintk(1, KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", - ZR_DEVNAME(zr), video_width, video_height); - return; - } - - /**** zr36057 ****/ - - /* horizontal */ - VidWinWid = video_width; - X = DIV_ROUND_UP(VidWinWid * 64, tvn->Wa); - We = (VidWinWid * 64) / X; - HorDcm = 64 - X; - hcrop1 = 2 * ((tvn->Wa - We) / 4); - hcrop2 = tvn->Wa - We - hcrop1; - HStart = tvn->HStart ? tvn->HStart : 1; - /* (Ronald) Original comment: - * "| 1 Doesn't have any effect, tested on both a DC10 and a DC10+" - * this is false. It inverses chroma values on the LML33R10 (so Cr - * suddenly is shown as Cb and reverse, really cool effect if you - * want to see blue faces, not useful otherwise). So don't use |1. - * However, the DC10 has '0' as HStart, but does need |1, so we - * use a dirty check... - */ - HEnd = HStart + tvn->Wa - 1; - HStart += hcrop1; - HEnd -= hcrop2; - reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) - | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); - if (zr->card.vfe_pol.hsync_pol) - reg |= ZR36057_VFEHCR_HSPol; - btwrite(reg, ZR36057_VFEHCR); - - /* Vertical */ - DispMode = !(video_height > BUZ_MAX_HEIGHT / 2); - VidWinHt = DispMode ? video_height : video_height / 2; - Y = DIV_ROUND_UP(VidWinHt * 64 * 2, tvn->Ha); - He = (VidWinHt * 64) / Y; - VerDcm = 64 - Y; - vcrop1 = (tvn->Ha / 2 - He) / 2; - vcrop2 = tvn->Ha / 2 - He - vcrop1; - VStart = tvn->VStart; - VEnd = VStart + tvn->Ha / 2; // - 1; FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP - VStart += vcrop1; - VEnd -= vcrop2; - reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) - | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); - if (zr->card.vfe_pol.vsync_pol) - reg |= ZR36057_VFEVCR_VSPol; - btwrite(reg, ZR36057_VFEVCR); - - /* scaler and pixel format */ - reg = 0; - reg |= (HorDcm << ZR36057_VFESPFR_HorDcm); - reg |= (VerDcm << ZR36057_VFESPFR_VerDcm); - reg |= (DispMode << ZR36057_VFESPFR_DispMode); - /* RJ: I don't know, why the following has to be the opposite - * of the corresponding ZR36060 setting, but only this way - * we get the correct colors when uncompressing to the screen */ - //reg |= ZR36057_VFESPFR_VCLKPol; /**/ - /* RJ: Don't know if that is needed for NTSC also */ - if (!(zr->norm & V4L2_STD_NTSC)) - reg |= ZR36057_VFESPFR_ExtFl; // NEEDED!!!!!!! Wolfgang - reg |= ZR36057_VFESPFR_TopField; - if (HorDcm >= 48) { - reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ - } else if (HorDcm >= 32) { - reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ - } else if (HorDcm >= 16) { - reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ - } - reg |= format->vfespfr; - btwrite(reg, ZR36057_VFESPFR); - - /* display configuration */ - reg = (16 << ZR36057_VDCR_MinPix) - | (VidWinHt << ZR36057_VDCR_VidWinHt) - | (VidWinWid << ZR36057_VDCR_VidWinWid); - if (pci_pci_problems & PCIPCI_TRITON) - // || zr->revision < 1) // Revision 1 has also Triton support - reg &= ~ZR36057_VDCR_Triton; - else - reg |= ZR36057_VDCR_Triton; - btwrite(reg, ZR36057_VDCR); - - /* (Ronald) don't write this if overlay_mask = NULL */ - if (zr->overlay_mask) { - /* Write overlay clipping mask data, but don't enable overlay clipping */ - /* RJ: since this makes only sense on the screen, we use - * zr->overlay_settings.width instead of video_width */ - - mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - reg = virt_to_bus(zr->overlay_mask); - btwrite(reg, ZR36057_MMTR); - reg = virt_to_bus(zr->overlay_mask + mask_line_size); - btwrite(reg, ZR36057_MMBR); - reg = - mask_line_size - (zr->overlay_settings.width + - 31) / 32; - if (DispMode == 0) - reg += mask_line_size; - reg <<= ZR36057_OCR_MaskStride; - btwrite(reg, ZR36057_OCR); - } - - zr36057_adjust_vfe(zr, zr->codec_mode); -} - -/* - * Switch overlay on or off - */ - -void -zr36057_overlay (struct zoran *zr, - int on) -{ - u32 reg; - - if (on) { - /* do the necessary settings ... */ - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ - - zr36057_set_vfe(zr, - zr->overlay_settings.width, - zr->overlay_settings.height, - zr->overlay_settings.format); - - /* Start and length of each line MUST be 4-byte aligned. - * This should be already checked before the call to this routine. - * All error messages are internal driver checking only! */ - - /* video display top and bottom registers */ - reg = (long) zr->vbuf_base + - zr->overlay_settings.x * - ((zr->overlay_settings.format->depth + 7) / 8) + - zr->overlay_settings.y * - zr->vbuf_bytesperline; - btwrite(reg, ZR36057_VDTR); - if (reg & 3) - dprintk(1, - KERN_ERR - "%s: zr36057_overlay() - video_address not aligned\n", - ZR_DEVNAME(zr)); - if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2) - reg += zr->vbuf_bytesperline; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - reg = zr->vbuf_bytesperline - - zr->overlay_settings.width * - ((zr->overlay_settings.format->depth + 7) / 8); - if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2) - reg += zr->vbuf_bytesperline; - if (reg & 3) - dprintk(1, - KERN_ERR - "%s: zr36057_overlay() - video_stride not aligned\n", - ZR_DEVNAME(zr)); - reg = (reg << ZR36057_VSSFGR_DispStride); - reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ - btwrite(reg, ZR36057_VSSFGR); - - /* Set overlay clipping */ - if (zr->overlay_settings.clipcount > 0) - btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); - - /* ... and switch it on */ - btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); - } else { - /* Switch it off */ - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - } -} - -/* - * The overlay mask has one bit for each pixel on a scan line, - * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. - */ - -void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count) -{ - struct zoran *zr = fh->zr; - unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - u32 *mask; - int x, y, width, height; - unsigned i, j, k; - u32 reg; - - /* fill mask with one bits */ - memset(fh->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); - reg = 0; - - for (i = 0; i < count; ++i) { - /* pick up local copy of clip */ - x = vp[i].c.left; - y = vp[i].c.top; - width = vp[i].c.width; - height = vp[i].c.height; - - /* trim clips that extend beyond the window */ - if (x < 0) { - width += x; - x = 0; - } - if (y < 0) { - height += y; - y = 0; - } - if (x + width > fh->overlay_settings.width) { - width = fh->overlay_settings.width - x; - } - if (y + height > fh->overlay_settings.height) { - height = fh->overlay_settings.height - y; - } - - /* ignore degenerate clips */ - if (height <= 0) { - continue; - } - if (width <= 0) { - continue; - } - - /* apply clip for each scan line */ - for (j = 0; j < height; ++j) { - /* reset bit for each pixel */ - /* this can be optimized later if need be */ - mask = fh->overlay_mask + (y + j) * mask_line_size; - for (k = 0; k < width; ++k) { - mask[(x + k) / 32] &= - ~((u32) 1 << (x + k) % 32); - } - } - } -} - -/* Enable/Disable uncompressed memory grabbing of the 36057 */ - -void -zr36057_set_memgrab (struct zoran *zr, - int mode) -{ - if (mode) { - /* We only check SnapShot and not FrameGrab here. SnapShot==1 - * means a capture is already in progress, but FrameGrab==1 - * doesn't necessary mean that. It's more correct to say a 1 - * to 0 transition indicates a capture completed. If a - * capture is pending when capturing is tuned off, FrameGrab - * will be stuck at 1 until capturing is turned back on. - */ - if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) - dprintk(1, - KERN_WARNING - "%s: zr36057_set_memgrab(1) with SnapShot on!?\n", - ZR_DEVNAME(zr)); - - /* switch on VSync interrupts */ - btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts - btor(zr->card.vsync_int, ZR36057_ICR); // SW - - /* enable SnapShot */ - btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - - /* Set zr36057 video front end and enable video */ - zr36057_set_vfe(zr, zr->v4l_settings.width, - zr->v4l_settings.height, - zr->v4l_settings.format); - - zr->v4l_memgrab_active = 1; - } else { - /* switch off VSync interrupts */ - btand(~zr->card.vsync_int, ZR36057_ICR); // SW - - zr->v4l_memgrab_active = 0; - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - - /* reenable grabbing to screen if it was running */ - if (zr->v4l_overlay_active) { - zr36057_overlay(zr, 1); - } else { - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - } - } -} - -int -wait_grab_pending (struct zoran *zr) -{ - unsigned long flags; - - /* wait until all pending grabs are finished */ - - if (!zr->v4l_memgrab_active) - return 0; - - wait_event_interruptible(zr->v4l_capq, - (zr->v4l_pend_tail == zr->v4l_pend_head)); - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&zr->spinlock, flags); - zr36057_set_memgrab(zr, 0); - spin_unlock_irqrestore(&zr->spinlock, flags); - - return 0; -} - -/***************************************************************************** - * * - * Set up the Buz-specific MJPEG part * - * * - *****************************************************************************/ - -static inline void -set_frame (struct zoran *zr, - int val) -{ - GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_FRAME], val); -} - -static void -set_videobus_dir (struct zoran *zr, - int val) -{ - switch (zr->card.type) { - case LML33: - case LML33R10: - if (lml33dpath == 0) - GPIO(zr, 5, val); - else - GPIO(zr, 5, 1); - break; - default: - GPIO(zr, zr->card.gpio[ZR_GPIO_VID_DIR], - zr->card.gpio_pol[ZR_GPIO_VID_DIR] ? !val : val); - break; - } -} - -static void -init_jpeg_queue (struct zoran *zr) -{ - int i; - - /* re-initialize DMA ring stuff */ - zr->jpg_que_head = 0; - zr->jpg_dma_head = 0; - zr->jpg_dma_tail = 0; - zr->jpg_que_tail = 0; - zr->jpg_seq_num = 0; - zr->JPEG_error = 0; - zr->num_errors = 0; - zr->jpg_err_seq = 0; - zr->jpg_err_shift = 0; - zr->jpg_queued_num = 0; - for (i = 0; i < zr->jpg_buffers.num_buffers; i++) { - zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ - } - for (i = 0; i < BUZ_NUM_STAT_COM; i++) { - zr->stat_com[i] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ - } -} - -static void -zr36057_set_jpg (struct zoran *zr, - enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - - tvn = zr->timing; - - /* assert P_Reset, disable code transfer, deassert Active */ - btwrite(0, ZR36057_JPC); - - /* MJPEG compression mode */ - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: - default: - reg = ZR36057_JMC_MJPGCmpMode; - break; - - case BUZ_MODE_MOTION_DECOMPRESS: - reg = ZR36057_JMC_MJPGExpMode; - reg |= ZR36057_JMC_SyncMstr; - /* RJ: The following is experimental - improves the output to screen */ - //if(zr->jpg_settings.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM - break; - - case BUZ_MODE_STILL_COMPRESS: - reg = ZR36057_JMC_JPGCmpMode; - break; - - case BUZ_MODE_STILL_DECOMPRESS: - reg = ZR36057_JMC_JPGExpMode; - break; - - } - reg |= ZR36057_JMC_JPG; - if (zr->jpg_settings.field_per_buff == 1) - reg |= ZR36057_JMC_Fld_per_buff; - btwrite(reg, ZR36057_JMC); - - /* vertical */ - btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); - reg = (6 << ZR36057_VSP_VsyncSize) | - (tvn->Ht << ZR36057_VSP_FrmTot); - btwrite(reg, ZR36057_VSP); - reg = ((zr->jpg_settings.img_y + tvn->VStart) << ZR36057_FVAP_NAY) | - (zr->jpg_settings.img_height << ZR36057_FVAP_PAY); - btwrite(reg, ZR36057_FVAP); - - /* horizontal */ - if (zr->card.vfe_pol.hsync_pol) - btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); - else - btand(~ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); - reg = ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) | - (tvn->Wt << ZR36057_HSP_LineTot); - btwrite(reg, ZR36057_HSP); - reg = ((zr->jpg_settings.img_x + - tvn->HStart + 4) << ZR36057_FHAP_NAX) | - (zr->jpg_settings.img_width << ZR36057_FHAP_PAX); - btwrite(reg, ZR36057_FHAP); - - /* field process parameters */ - if (zr->jpg_settings.odd_even) - reg = ZR36057_FPP_Odd_Even; - else - reg = 0; - - btwrite(reg, ZR36057_FPP); - - /* Set proper VCLK Polarity, else colors will be wrong during playback */ - //btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); - - /* code base address */ - reg = virt_to_bus(zr->stat_com); - btwrite(reg, ZR36057_JCBA); - - /* FIFO threshold (FIFO is 160. double words) */ - /* NOTE: decimal values here */ - switch (mode) { - - case BUZ_MODE_STILL_COMPRESS: - case BUZ_MODE_MOTION_COMPRESS: - if (zr->card.type != BUZ) - reg = 140; - else - reg = 60; - break; - - case BUZ_MODE_STILL_DECOMPRESS: - case BUZ_MODE_MOTION_DECOMPRESS: - reg = 20; - break; - - default: - reg = 80; - break; - - } - btwrite(reg, ZR36057_JCFT); - zr36057_adjust_vfe(zr, mode); - -} - -void -print_interrupts (struct zoran *zr) -{ - int res, noerr = 0; - - printk(KERN_INFO "%s: interrupts received:", ZR_DEVNAME(zr)); - if ((res = zr->field_counter) < -1 || res > 1) { - printk(" FD:%d", res); - } - if ((res = zr->intr_counter_GIRQ1) != 0) { - printk(" GIRQ1:%d", res); - noerr++; - } - if ((res = zr->intr_counter_GIRQ0) != 0) { - printk(" GIRQ0:%d", res); - noerr++; - } - if ((res = zr->intr_counter_CodRepIRQ) != 0) { - printk(" CodRepIRQ:%d", res); - noerr++; - } - if ((res = zr->intr_counter_JPEGRepIRQ) != 0) { - printk(" JPEGRepIRQ:%d", res); - noerr++; - } - if (zr->JPEG_max_missed) { - printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed, - zr->JPEG_min_missed); - } - if (zr->END_event_missed) { - printk(" ENDs missed: %d", zr->END_event_missed); - } - //if (zr->jpg_queued_num) { - printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail, - zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head); - //} - if (!noerr) { - printk(": no interrupts detected."); - } - printk("\n"); -} - -void -clear_interrupt_counters (struct zoran *zr) -{ - zr->intr_counter_GIRQ1 = 0; - zr->intr_counter_GIRQ0 = 0; - zr->intr_counter_CodRepIRQ = 0; - zr->intr_counter_JPEGRepIRQ = 0; - zr->field_counter = 0; - zr->IRQ1_in = 0; - zr->IRQ1_out = 0; - zr->JPEG_in = 0; - zr->JPEG_out = 0; - zr->JPEG_0 = 0; - zr->JPEG_1 = 0; - zr->END_event_missed = 0; - zr->JPEG_missed = 0; - zr->JPEG_max_missed = 0; - zr->JPEG_min_missed = 0x7fffffff; -} - -static u32 -count_reset_interrupt (struct zoran *zr) -{ - u32 isr; - - if ((isr = btread(ZR36057_ISR) & 0x78000000)) { - if (isr & ZR36057_ISR_GIRQ1) { - btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR); - zr->intr_counter_GIRQ1++; - } - if (isr & ZR36057_ISR_GIRQ0) { - btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR); - zr->intr_counter_GIRQ0++; - } - if (isr & ZR36057_ISR_CodRepIRQ) { - btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR); - zr->intr_counter_CodRepIRQ++; - } - if (isr & ZR36057_ISR_JPEGRepIRQ) { - btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR); - zr->intr_counter_JPEGRepIRQ++; - } - } - return isr; -} - -void -jpeg_start (struct zoran *zr) -{ - int reg; - - zr->frame_num = 0; - - /* deassert P_reset, disable code transfer, deassert Active */ - btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); - /* stop flushing the internal code buffer */ - btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - /* enable code transfer */ - btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC); - - /* clear IRQs */ - btwrite(IRQ_MASK, ZR36057_ISR); - /* enable the JPEG IRQs */ - btwrite(zr->card.jpeg_int | - ZR36057_ICR_JPEGRepIRQ | - ZR36057_ICR_IntPinEn, - ZR36057_ICR); - - set_frame(zr, 0); // \FRAME - - /* set the JPEG codec guest ID */ - reg = (zr->card.gpcs[1] << ZR36057_JCGI_JPEGuestID) | - (0 << ZR36057_JCGI_JPEGuestReg); - btwrite(reg, ZR36057_JCGI); - - if (zr->card.video_vfe == CODEC_TYPE_ZR36016 && - zr->card.video_codec == CODEC_TYPE_ZR36050) { - /* Enable processing on the ZR36016 */ - if (zr->vfe) - zr36016_write(zr->vfe, 0, 1); - - /* load the address of the GO register in the ZR36050 latch */ - post_office_write(zr, 0, 0, 0); - } - - /* assert Active */ - btor(ZR36057_JPC_Active, ZR36057_JPC); - - /* enable the Go generation */ - btor(ZR36057_JMC_Go_en, ZR36057_JMC); - udelay(30); - - set_frame(zr, 1); // /FRAME - - dprintk(3, KERN_DEBUG "%s: jpeg_start\n", ZR_DEVNAME(zr)); -} - -void -zr36057_enable_jpg (struct zoran *zr, - enum zoran_codec_mode mode) -{ - struct vfe_settings cap; - int field_size = - zr->jpg_buffers.buffer_size / zr->jpg_settings.field_per_buff; - - zr->codec_mode = mode; - - cap.x = zr->jpg_settings.img_x; - cap.y = zr->jpg_settings.img_y; - cap.width = zr->jpg_settings.img_width; - cap.height = zr->jpg_settings.img_height; - cap.decimation = - zr->jpg_settings.HorDcm | (zr->jpg_settings.VerDcm << 8); - cap.quality = zr->jpg_settings.jpg_comp.quality; - - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: { - struct jpeg_app_marker app; - struct jpeg_com_marker com; - - /* In motion compress mode, the decoder output must be enabled, and - * the video bus direction set to input. - */ - set_videobus_dir(zr, 0); - decoder_call(zr, video, s_stream, 1); - encoder_call(zr, video, s_routing, 0, 0, 0); - - /* Take the JPEG codec and the VFE out of sleep */ - jpeg_codec_sleep(zr, 0); - - /* set JPEG app/com marker */ - app.appn = zr->jpg_settings.jpg_comp.APPn; - app.len = zr->jpg_settings.jpg_comp.APP_len; - memcpy(app.data, zr->jpg_settings.jpg_comp.APP_data, 60); - zr->codec->control(zr->codec, CODEC_S_JPEG_APP_DATA, - sizeof(struct jpeg_app_marker), &app); - - com.len = zr->jpg_settings.jpg_comp.COM_len; - memcpy(com.data, zr->jpg_settings.jpg_comp.COM_data, 60); - zr->codec->control(zr->codec, CODEC_S_JPEG_COM_DATA, - sizeof(struct jpeg_com_marker), &com); - - /* Setup the JPEG codec */ - zr->codec->control(zr->codec, CODEC_S_JPEG_TDS_BYTE, - sizeof(int), &field_size); - zr->codec->set_video(zr->codec, zr->timing, &cap, - &zr->card.vfe_pol); - zr->codec->set_mode(zr->codec, CODEC_DO_COMPRESSION); - - /* Setup the VFE */ - if (zr->vfe) { - zr->vfe->control(zr->vfe, CODEC_S_JPEG_TDS_BYTE, - sizeof(int), &field_size); - zr->vfe->set_video(zr->vfe, zr->timing, &cap, - &zr->card.vfe_pol); - zr->vfe->set_mode(zr->vfe, CODEC_DO_COMPRESSION); - } - - init_jpeg_queue(zr); - zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO - - clear_interrupt_counters(zr); - dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_COMPRESS)\n", - ZR_DEVNAME(zr)); - break; - } - - case BUZ_MODE_MOTION_DECOMPRESS: - /* In motion decompression mode, the decoder output must be disabled, and - * the video bus direction set to output. - */ - decoder_call(zr, video, s_stream, 0); - set_videobus_dir(zr, 1); - encoder_call(zr, video, s_routing, 1, 0, 0); - - /* Take the JPEG codec and the VFE out of sleep */ - jpeg_codec_sleep(zr, 0); - /* Setup the VFE */ - if (zr->vfe) { - zr->vfe->set_video(zr->vfe, zr->timing, &cap, - &zr->card.vfe_pol); - zr->vfe->set_mode(zr->vfe, CODEC_DO_EXPANSION); - } - /* Setup the JPEG codec */ - zr->codec->set_video(zr->codec, zr->timing, &cap, - &zr->card.vfe_pol); - zr->codec->set_mode(zr->codec, CODEC_DO_EXPANSION); - - init_jpeg_queue(zr); - zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO - - clear_interrupt_counters(zr); - dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_DECOMPRESS)\n", - ZR_DEVNAME(zr)); - break; - - case BUZ_MODE_IDLE: - default: - /* shut down processing */ - btand(~(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ), - ZR36057_ICR); - btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ, - ZR36057_ISR); - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); // \Go_en - - msleep(50); - - set_videobus_dir(zr, 0); - set_frame(zr, 1); // /FRAME - btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); // /CFlush - btwrite(0, ZR36057_JPC); // \P_Reset,\CodTrnsEn,\Active - btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); - btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); - jpeg_codec_reset(zr); - jpeg_codec_sleep(zr, 1); - zr36057_adjust_vfe(zr, mode); - - decoder_call(zr, video, s_stream, 1); - encoder_call(zr, video, s_routing, 0, 0, 0); - - dprintk(2, KERN_INFO "%s: enable_jpg(IDLE)\n", ZR_DEVNAME(zr)); - break; - - } -} - -/* when this is called the spinlock must be held */ -void -zoran_feed_stat_com (struct zoran *zr) -{ - /* move frames from pending queue to DMA */ - - int frame, i, max_stat_com; - - max_stat_com = - (zr->jpg_settings.TmpDcm == - 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); - - while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com && - zr->jpg_dma_head < zr->jpg_que_head) { - - frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; - if (zr->jpg_settings.TmpDcm == 1) { - /* fill 1 stat_com entry */ - i = (zr->jpg_dma_head - - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; - if (!(zr->stat_com[i] & cpu_to_le32(1))) - break; - zr->stat_com[i] = - cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus); - } else { - /* fill 2 stat_com entries */ - i = ((zr->jpg_dma_head - - zr->jpg_err_shift) & 1) * 2; - if (!(zr->stat_com[i] & cpu_to_le32(1))) - break; - zr->stat_com[i] = - cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus); - zr->stat_com[i + 1] = - cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus); - } - zr->jpg_buffers.buffer[frame].state = BUZ_STATE_DMA; - zr->jpg_dma_head++; - - } - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) - zr->jpg_queued_num++; -} - -/* when this is called the spinlock must be held */ -static void -zoran_reap_stat_com (struct zoran *zr) -{ - /* move frames from DMA queue to done queue */ - - int i; - u32 stat_com; - unsigned int seq; - unsigned int dif; - struct zoran_buffer *buffer; - int frame; - - /* In motion decompress we don't have a hardware frame counter, - * we just count the interrupts here */ - - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) { - zr->jpg_seq_num++; - } - while (zr->jpg_dma_tail < zr->jpg_dma_head) { - if (zr->jpg_settings.TmpDcm == 1) - i = (zr->jpg_dma_tail - - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; - else - i = ((zr->jpg_dma_tail - - zr->jpg_err_shift) & 1) * 2 + 1; - - stat_com = le32_to_cpu(zr->stat_com[i]); - - if ((stat_com & 1) == 0) { - return; - } - frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; - buffer = &zr->jpg_buffers.buffer[frame]; - do_gettimeofday(&buffer->bs.timestamp); - - if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - buffer->bs.length = (stat_com & 0x7fffff) >> 1; - - /* update sequence number with the help of the counter in stat_com */ - - seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff; - dif = (seq - zr->jpg_seq_num) & 0xff; - zr->jpg_seq_num += dif; - } else { - buffer->bs.length = 0; - } - buffer->bs.seq = - zr->jpg_settings.TmpDcm == - 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; - buffer->state = BUZ_STATE_DONE; - - zr->jpg_dma_tail++; - } -} - -static void zoran_restart(struct zoran *zr) -{ - /* Now the stat_comm buffer is ready for restart */ - unsigned int status = 0; - int mode; - - if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - decoder_call(zr, video, g_input_status, &status); - mode = CODEC_DO_COMPRESSION; - } else { - status = V4L2_IN_ST_NO_SIGNAL; - mode = CODEC_DO_EXPANSION; - } - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || - !(status & V4L2_IN_ST_NO_SIGNAL)) { - /********** RESTART code *************/ - jpeg_codec_reset(zr); - zr->codec->set_mode(zr->codec, mode); - zr36057_set_jpg(zr, zr->codec_mode); - jpeg_start(zr); - - if (zr->num_errors <= 8) - dprintk(2, KERN_INFO "%s: Restart\n", - ZR_DEVNAME(zr)); - - zr->JPEG_missed = 0; - zr->JPEG_error = 2; - /********** End RESTART code ***********/ - } -} - -static void -error_handler (struct zoran *zr, - u32 astat, - u32 stat) -{ - int i; - - /* This is JPEG error handling part */ - if (zr->codec_mode != BUZ_MODE_MOTION_COMPRESS && - zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS) { - return; - } - - if ((stat & 1) == 0 && - zr->codec_mode == BUZ_MODE_MOTION_COMPRESS && - zr->jpg_dma_tail - zr->jpg_que_tail >= zr->jpg_buffers.num_buffers) { - /* No free buffers... */ - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - wake_up_interruptible(&zr->jpg_capq); - zr->JPEG_missed = 0; - return; - } - - if (zr->JPEG_error == 1) { - zoran_restart(zr); - return; - } - - /* - * First entry: error just happened during normal operation - * - * In BUZ_MODE_MOTION_COMPRESS: - * - * Possible glitch in TV signal. In this case we should - * stop the codec and wait for good quality signal before - * restarting it to avoid further problems - * - * In BUZ_MODE_MOTION_DECOMPRESS: - * - * Bad JPEG frame: we have to mark it as processed (codec crashed - * and was not able to do it itself), and to remove it from queue. - */ - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); - udelay(1); - stat = stat | (post_office_read(zr, 7, 0) & 3) << 8; - btwrite(0, ZR36057_JPC); - btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - jpeg_codec_reset(zr); - jpeg_codec_sleep(zr, 1); - zr->JPEG_error = 1; - zr->num_errors++; - - /* Report error */ - if (zr36067_debug > 1 && zr->num_errors <= 8) { - long frame; - int j; - - frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; - printk(KERN_ERR - "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ", - ZR_DEVNAME(zr), stat, zr->last_isr, - zr->jpg_que_tail, zr->jpg_dma_tail, - zr->jpg_dma_head, zr->jpg_que_head, - zr->jpg_seq_num, frame); - printk(KERN_INFO "stat_com frames:"); - for (j = 0; j < BUZ_NUM_STAT_COM; j++) { - for (i = 0; i < zr->jpg_buffers.num_buffers; i++) { - if (le32_to_cpu(zr->stat_com[j]) == zr->jpg_buffers.buffer[i].jpg.frag_tab_bus) - printk(KERN_CONT "% d->%d", j, i); - } - } - printk(KERN_CONT "\n"); - } - /* Find an entry in stat_com and rotate contents */ - if (zr->jpg_settings.TmpDcm == 1) - i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; - else - i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) { - /* Mimic zr36067 operation */ - zr->stat_com[i] |= cpu_to_le32(1); - if (zr->jpg_settings.TmpDcm != 1) - zr->stat_com[i + 1] |= cpu_to_le32(1); - /* Refill */ - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - wake_up_interruptible(&zr->jpg_capq); - /* Find an entry in stat_com again after refill */ - if (zr->jpg_settings.TmpDcm == 1) - i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; - else - i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; - } - if (i) { - /* Rotate stat_comm entries to make current entry first */ - int j; - __le32 bus_addr[BUZ_NUM_STAT_COM]; - - /* Here we are copying the stat_com array, which - * is already in little endian format, so - * no endian conversions here - */ - memcpy(bus_addr, zr->stat_com, sizeof(bus_addr)); - - for (j = 0; j < BUZ_NUM_STAT_COM; j++) - zr->stat_com[j] = bus_addr[(i + j) & BUZ_MASK_STAT_COM]; - - zr->jpg_err_shift += i; - zr->jpg_err_shift &= BUZ_MASK_STAT_COM; - } - if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) - zr->jpg_err_seq = zr->jpg_seq_num; /* + 1; */ - zoran_restart(zr); -} - -irqreturn_t -zoran_irq (int irq, - void *dev_id) -{ - u32 stat, astat; - int count; - struct zoran *zr; - unsigned long flags; - - zr = dev_id; - count = 0; - - if (zr->testing) { - /* Testing interrupts */ - spin_lock_irqsave(&zr->spinlock, flags); - while ((stat = count_reset_interrupt(zr))) { - if (count++ > 100) { - btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - dprintk(1, - KERN_ERR - "%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n", - ZR_DEVNAME(zr), stat); - wake_up_interruptible(&zr->test_q); - } - } - zr->last_isr = stat; - spin_unlock_irqrestore(&zr->spinlock, flags); - return IRQ_HANDLED; - } - - spin_lock_irqsave(&zr->spinlock, flags); - while (1) { - /* get/clear interrupt status bits */ - stat = count_reset_interrupt(zr); - astat = stat & IRQ_MASK; - if (!astat) { - break; - } - dprintk(4, - KERN_DEBUG - "zoran_irq: astat: 0x%08x, mask: 0x%08x\n", - astat, btread(ZR36057_ICR)); - if (astat & zr->card.vsync_int) { // SW - - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || - zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - /* count missed interrupts */ - zr->JPEG_missed++; - } - //post_office_read(zr,1,0); - /* Interrupts may still happen when - * zr->v4l_memgrab_active is switched off. - * We simply ignore them */ - - if (zr->v4l_memgrab_active) { - /* A lot more checks should be here ... */ - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0) - dprintk(1, - KERN_WARNING - "%s: BuzIRQ with SnapShot off ???\n", - ZR_DEVNAME(zr)); - - if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { - /* There is a grab on a frame going on, check if it has finished */ - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) { - /* it is finished, notify the user */ - - zr->v4l_buffers.buffer[zr->v4l_grab_frame].state = BUZ_STATE_DONE; - zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.seq = zr->v4l_grab_seq; - do_gettimeofday(&zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.timestamp); - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_pend_tail++; - } - } - - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) - wake_up_interruptible(&zr->v4l_capq); - - /* Check if there is another grab queued */ - - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE && - zr->v4l_pend_tail != zr->v4l_pend_head) { - int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME]; - u32 reg; - - zr->v4l_grab_frame = frame; - - /* Set zr36057 video front end and enable video */ - - /* Buffer address */ - - reg = zr->v4l_buffers.buffer[frame].v4l.fbuffer_bus; - btwrite(reg, ZR36057_VDTR); - if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2) - reg += zr->v4l_settings.bytesperline; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - reg = 0; - if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2) - reg += zr->v4l_settings.bytesperline; - reg = (reg << ZR36057_VSSFGR_DispStride); - reg |= ZR36057_VSSFGR_VidOvf; - reg |= ZR36057_VSSFGR_SnapShot; - reg |= ZR36057_VSSFGR_FrameGrab; - btwrite(reg, ZR36057_VSSFGR); - - btor(ZR36057_VDCR_VidEn, - ZR36057_VDCR); - } - } - - /* even if we don't grab, we do want to increment - * the sequence counter to see lost frames */ - zr->v4l_grab_seq++; - } -#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) - if (astat & ZR36057_ISR_CodRepIRQ) { - zr->intr_counter_CodRepIRQ++; - IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", - ZR_DEVNAME(zr))); - btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); - } -#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ - -#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) - if ((astat & ZR36057_ISR_JPEGRepIRQ) && - (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || - zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) { - if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) { - char sv[BUZ_NUM_STAT_COM + 1]; - int i; - - printk(KERN_INFO - "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n", - ZR_DEVNAME(zr), stat, - zr->jpg_settings.odd_even, - zr->jpg_settings.field_per_buff, - zr->JPEG_missed); - - for (i = 0; i < BUZ_NUM_STAT_COM; i++) - sv[i] = le32_to_cpu(zr->stat_com[i]) & 1 ? '1' : '0'; - sv[BUZ_NUM_STAT_COM] = 0; - printk(KERN_INFO - "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n", - ZR_DEVNAME(zr), sv, - zr->jpg_que_tail, - zr->jpg_dma_tail, - zr->jpg_dma_head, - zr->jpg_que_head); - } else { - /* Get statistics */ - if (zr->JPEG_missed > zr->JPEG_max_missed) - zr->JPEG_max_missed = zr->JPEG_missed; - if (zr->JPEG_missed < zr->JPEG_min_missed) - zr->JPEG_min_missed = zr->JPEG_missed; - } - - if (zr36067_debug > 2 && zr->frame_num < 6) { - int i; - - printk(KERN_INFO "%s: seq=%ld stat_com:", - ZR_DEVNAME(zr), zr->jpg_seq_num); - for (i = 0; i < 4; i++) { - printk(KERN_CONT " %08x", - le32_to_cpu(zr->stat_com[i])); - } - printk(KERN_CONT "\n"); - } - zr->frame_num++; - zr->JPEG_missed = 0; - zr->JPEG_error = 0; - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - wake_up_interruptible(&zr->jpg_capq); - } -#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ - - /* DATERR, too many fields missed, error processing */ - if ((astat & zr->card.jpeg_int) || - zr->JPEG_missed > 25 || - zr->JPEG_error == 1 || - ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) && - (zr->frame_num && (zr->JPEG_missed > zr->jpg_settings.field_per_buff)))) { - error_handler(zr, astat, stat); - } - - count++; - if (count > 10) { - dprintk(2, KERN_WARNING "%s: irq loop %d\n", - ZR_DEVNAME(zr), count); - if (count > 20) { - btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - dprintk(2, - KERN_ERR - "%s: IRQ lockup, cleared int mask\n", - ZR_DEVNAME(zr)); - break; - } - } - zr->last_isr = stat; - } - spin_unlock_irqrestore(&zr->spinlock, flags); - - return IRQ_HANDLED; -} - -void -zoran_set_pci_master (struct zoran *zr, - int set_master) -{ - if (set_master) { - pci_set_master(zr->pci_dev); - } else { - u16 command; - - pci_read_config_word(zr->pci_dev, PCI_COMMAND, &command); - command &= ~PCI_COMMAND_MASTER; - pci_write_config_word(zr->pci_dev, PCI_COMMAND, command); - } -} - -void -zoran_init_hardware (struct zoran *zr) -{ - /* Enable bus-mastering */ - zoran_set_pci_master(zr, 1); - - /* Initialize the board */ - if (zr->card.init) { - zr->card.init(zr); - } - - decoder_call(zr, core, init, 0); - decoder_call(zr, core, s_std, zr->norm); - decoder_call(zr, video, s_routing, - zr->card.input[zr->input].muxsel, 0, 0); - - encoder_call(zr, core, init, 0); - encoder_call(zr, video, s_std_output, zr->norm); - encoder_call(zr, video, s_routing, 0, 0, 0); - - /* toggle JPEG codec sleep to sync PLL */ - jpeg_codec_sleep(zr, 1); - jpeg_codec_sleep(zr, 0); - - /* set individual interrupt enables (without GIRQ1) - * but don't global enable until zoran_open() */ - - //btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR); // SW - // It looks like using only JPEGRepIRQEn is not always reliable, - // may be when JPEG codec crashes it won't generate IRQ? So, - /*CP*/ // btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM WHY ? LP - zr36057_init_vfe(zr); - - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - - btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts -} - -void -zr36057_restart (struct zoran *zr) -{ - btwrite(0, ZR36057_SPGPPCR); - mdelay(1); - btor(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); - mdelay(1); - - /* assert P_Reset */ - btwrite(0, ZR36057_JPC); - /* set up GPIO direction - all output */ - btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); - - /* set up GPIO pins and guest bus timing */ - btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1); -} - -/* - * initialize video front end - */ - -static void -zr36057_init_vfe (struct zoran *zr) -{ - u32 reg; - - reg = btread(ZR36057_VFESPFR); - reg |= ZR36057_VFESPFR_LittleEndian; - reg &= ~ZR36057_VFESPFR_VCLKPol; - reg |= ZR36057_VFESPFR_ExtFl; - reg |= ZR36057_VFESPFR_TopField; - btwrite(reg, ZR36057_VFESPFR); - reg = btread(ZR36057_VDCR); - if (pci_pci_problems & PCIPCI_TRITON) - // || zr->revision < 1) // Revision 1 has also Triton support - reg &= ~ZR36057_VDCR_Triton; - else - reg |= ZR36057_VDCR_Triton; - btwrite(reg, ZR36057_VDCR); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_device.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_device.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_device.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles card-specific data and detection - * - * Copyright (C) 2000 Serguei Miridonov - * - * Currently maintained by: - * Ronald Bultje - * Laurent Pinchart - * Mailinglist - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ZORAN_DEVICE_H__ -#define __ZORAN_DEVICE_H__ - -/* general purpose I/O */ -extern void GPIO(struct zoran *zr, - int bit, - unsigned int value); - -/* codec (or actually: guest bus) access */ -extern int post_office_wait(struct zoran *zr); -extern int post_office_write(struct zoran *zr, - unsigned guest, - unsigned reg, - unsigned value); -extern int post_office_read(struct zoran *zr, - unsigned guest, - unsigned reg); - -extern void detect_guest_activity(struct zoran *zr); - -extern void jpeg_codec_sleep(struct zoran *zr, - int sleep); -extern int jpeg_codec_reset(struct zoran *zr); - -/* zr360x7 access to raw capture */ -extern void zr36057_overlay(struct zoran *zr, - int on); -extern void write_overlay_mask(struct zoran_fh *fh, - struct v4l2_clip *vp, - int count); -extern void zr36057_set_memgrab(struct zoran *zr, - int mode); -extern int wait_grab_pending(struct zoran *zr); - -/* interrupts */ -extern void print_interrupts(struct zoran *zr); -extern void clear_interrupt_counters(struct zoran *zr); -extern irqreturn_t zoran_irq(int irq, void *dev_id); - -/* JPEG codec access */ -extern void jpeg_start(struct zoran *zr); -extern void zr36057_enable_jpg(struct zoran *zr, - enum zoran_codec_mode mode); -extern void zoran_feed_stat_com(struct zoran *zr); - -/* general */ -extern void zoran_set_pci_master(struct zoran *zr, - int set_master); -extern void zoran_init_hardware(struct zoran *zr); -extern void zr36057_restart(struct zoran *zr); - -extern const struct zoran_format zoran_formats[]; - -extern int v4l_nbufs; -extern int v4l_bufsize; -extern int jpg_nbufs; -extern int jpg_bufsize; -extern int pass_through; - -/* i2c */ -#define decoder_call(zr, o, f, args...) \ - v4l2_subdev_call(zr->decoder, o, f, ##args) -#define encoder_call(zr, o, f, args...) \ - v4l2_subdev_call(zr->encoder, o, f, ##args) - -#endif /* __ZORAN_DEVICE_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_driver.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_driver.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,3080 +0,0 @@ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * Copyright (C) 2000 Serguei Miridonov - * - * Changes for BUZ by Wolfgang Scherr - * - * Changes for DC10/DC30 by Laurent Pinchart - * - * Changes for LML33R10 by Maxim Yevtyushkin - * - * Changes for videodev2/v4l2 by Ronald Bultje - * - * Based on - * - * Miro DC10 driver - * Copyright (C) 1999 Wolfgang Scherr - * - * Iomega Buz driver version 1.0 - * Copyright (C) 1999 Rainer Johanni - * - * buz.0.0.3 - * Copyright (C) 1998 Dave Perks - * - * bttv - Bt848 frame grabber driver - * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - * & Marcus Metzler (mocm@thp.uni-koeln.de) - * - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include "videocodec.h" - -#include -#include -#include -#include - -#include -#include "zoran.h" -#include "zoran_device.h" -#include "zoran_card.h" - - -const struct zoran_format zoran_formats[] = { - { - .name = "15-bit RGB LE", - .fourcc = V4L2_PIX_FMT_RGB555, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 15, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif| - ZR36057_VFESPFR_LittleEndian, - }, { - .name = "15-bit RGB BE", - .fourcc = V4L2_PIX_FMT_RGB555X, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 15, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif, - }, { - .name = "16-bit RGB LE", - .fourcc = V4L2_PIX_FMT_RGB565, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 16, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif| - ZR36057_VFESPFR_LittleEndian, - }, { - .name = "16-bit RGB BE", - .fourcc = V4L2_PIX_FMT_RGB565X, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 16, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif, - }, { - .name = "24-bit RGB", - .fourcc = V4L2_PIX_FMT_BGR24, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 24, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24, - }, { - .name = "32-bit RGB LE", - .fourcc = V4L2_PIX_FMT_BGR32, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 32, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian, - }, { - .name = "32-bit RGB BE", - .fourcc = V4L2_PIX_FMT_RGB32, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 32, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB888, - }, { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - .depth = 16, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_YUV422, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - .depth = 16, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian, - }, { - .name = "Hardware-encoded Motion-JPEG", - .fourcc = V4L2_PIX_FMT_MJPEG, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - .depth = 0, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_PLAYBACK | - ZORAN_FORMAT_COMPRESSED, - } -}; -#define NUM_FORMATS ARRAY_SIZE(zoran_formats) - - /* small helper function for calculating buffersizes for v4l2 - * we calculate the nearest higher power-of-two, which - * will be the recommended buffersize */ -static __u32 -zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings) -{ - __u8 div = settings->VerDcm * settings->HorDcm * settings->TmpDcm; - __u32 num = (1024 * 512) / (div); - __u32 result = 2; - - num--; - while (num) { - num >>= 1; - result <<= 1; - } - - if (result > jpg_bufsize) - return jpg_bufsize; - if (result < 8192) - return 8192; - return result; -} - -/* forward references */ -static void v4l_fbuffer_free(struct zoran_fh *fh); -static void jpg_fbuffer_free(struct zoran_fh *fh); - -/* Set mapping mode */ -static void map_mode_raw(struct zoran_fh *fh) -{ - fh->map_mode = ZORAN_MAP_MODE_RAW; - fh->buffers.buffer_size = v4l_bufsize; - fh->buffers.num_buffers = v4l_nbufs; -} -static void map_mode_jpg(struct zoran_fh *fh, int play) -{ - fh->map_mode = play ? ZORAN_MAP_MODE_JPG_PLAY : ZORAN_MAP_MODE_JPG_REC; - fh->buffers.buffer_size = jpg_bufsize; - fh->buffers.num_buffers = jpg_nbufs; -} -static inline const char *mode_name(enum zoran_map_mode mode) -{ - return mode == ZORAN_MAP_MODE_RAW ? "V4L" : "JPG"; -} - -/* - * Allocate the V4L grab buffers - * - * These have to be pysically contiguous. - */ - -static int v4l_fbuffer_alloc(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - int i, off; - unsigned char *mem; - - for (i = 0; i < fh->buffers.num_buffers; i++) { - if (fh->buffers.buffer[i].v4l.fbuffer) - dprintk(2, - KERN_WARNING - "%s: %s - buffer %d already allocated!?\n", - ZR_DEVNAME(zr), __func__, i); - - //udelay(20); - mem = kmalloc(fh->buffers.buffer_size, - GFP_KERNEL | __GFP_NOWARN); - if (!mem) { - dprintk(1, - KERN_ERR - "%s: %s - kmalloc for V4L buf %d failed\n", - ZR_DEVNAME(zr), __func__, i); - v4l_fbuffer_free(fh); - return -ENOBUFS; - } - fh->buffers.buffer[i].v4l.fbuffer = mem; - fh->buffers.buffer[i].v4l.fbuffer_phys = virt_to_phys(mem); - fh->buffers.buffer[i].v4l.fbuffer_bus = virt_to_bus(mem); - for (off = 0; off < fh->buffers.buffer_size; - off += PAGE_SIZE) - SetPageReserved(virt_to_page(mem + off)); - dprintk(4, - KERN_INFO - "%s: %s - V4L frame %d mem 0x%lx (bus: 0x%llx)\n", - ZR_DEVNAME(zr), __func__, i, (unsigned long) mem, - (unsigned long long)virt_to_bus(mem)); - } - - fh->buffers.allocated = 1; - - return 0; -} - -/* free the V4L grab buffers */ -static void v4l_fbuffer_free(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - int i, off; - unsigned char *mem; - - dprintk(4, KERN_INFO "%s: %s\n", ZR_DEVNAME(zr), __func__); - - for (i = 0; i < fh->buffers.num_buffers; i++) { - if (!fh->buffers.buffer[i].v4l.fbuffer) - continue; - - mem = fh->buffers.buffer[i].v4l.fbuffer; - for (off = 0; off < fh->buffers.buffer_size; - off += PAGE_SIZE) - ClearPageReserved(virt_to_page(mem + off)); - kfree(fh->buffers.buffer[i].v4l.fbuffer); - fh->buffers.buffer[i].v4l.fbuffer = NULL; - } - - fh->buffers.allocated = 0; -} - -/* - * Allocate the MJPEG grab buffers. - * - * If a Natoma chipset is present and this is a revision 1 zr36057, - * each MJPEG buffer needs to be physically contiguous. - * (RJ: This statement is from Dave Perks' original driver, - * I could never check it because I have a zr36067) - * - * RJ: The contents grab buffers needs never be accessed in the driver. - * Therefore there is no need to allocate them with vmalloc in order - * to get a contiguous virtual memory space. - * I don't understand why many other drivers first allocate them with - * vmalloc (which uses internally also get_zeroed_page, but delivers you - * virtual addresses) and then again have to make a lot of efforts - * to get the physical address. - * - * Ben Capper: - * On big-endian architectures (such as ppc) some extra steps - * are needed. When reading and writing to the stat_com array - * and fragment buffers, the device expects to see little- - * endian values. The use of cpu_to_le32() and le32_to_cpu() - * in this function (and one or two others in zoran_device.c) - * ensure that these values are always stored in little-endian - * form, regardless of architecture. The zr36057 does Very Bad - * Things on big endian architectures if the stat_com array - * and fragment buffers are not little-endian. - */ - -static int jpg_fbuffer_alloc(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - int i, j, off; - u8 *mem; - - for (i = 0; i < fh->buffers.num_buffers; i++) { - if (fh->buffers.buffer[i].jpg.frag_tab) - dprintk(2, - KERN_WARNING - "%s: %s - buffer %d already allocated!?\n", - ZR_DEVNAME(zr), __func__, i); - - /* Allocate fragment table for this buffer */ - - mem = (void *)get_zeroed_page(GFP_KERNEL); - if (!mem) { - dprintk(1, - KERN_ERR - "%s: %s - get_zeroed_page (frag_tab) failed for buffer %d\n", - ZR_DEVNAME(zr), __func__, i); - jpg_fbuffer_free(fh); - return -ENOBUFS; - } - fh->buffers.buffer[i].jpg.frag_tab = (__le32 *)mem; - fh->buffers.buffer[i].jpg.frag_tab_bus = virt_to_bus(mem); - - if (fh->buffers.need_contiguous) { - mem = kmalloc(fh->buffers.buffer_size, GFP_KERNEL); - if (mem == NULL) { - dprintk(1, - KERN_ERR - "%s: %s - kmalloc failed for buffer %d\n", - ZR_DEVNAME(zr), __func__, i); - jpg_fbuffer_free(fh); - return -ENOBUFS; - } - fh->buffers.buffer[i].jpg.frag_tab[0] = - cpu_to_le32(virt_to_bus(mem)); - fh->buffers.buffer[i].jpg.frag_tab[1] = - cpu_to_le32((fh->buffers.buffer_size >> 1) | 1); - for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE) - SetPageReserved(virt_to_page(mem + off)); - } else { - /* jpg_bufsize is already page aligned */ - for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) { - mem = (void *)get_zeroed_page(GFP_KERNEL); - if (mem == NULL) { - dprintk(1, - KERN_ERR - "%s: %s - get_zeroed_page failed for buffer %d\n", - ZR_DEVNAME(zr), __func__, i); - jpg_fbuffer_free(fh); - return -ENOBUFS; - } - - fh->buffers.buffer[i].jpg.frag_tab[2 * j] = - cpu_to_le32(virt_to_bus(mem)); - fh->buffers.buffer[i].jpg.frag_tab[2 * j + 1] = - cpu_to_le32((PAGE_SIZE >> 2) << 1); - SetPageReserved(virt_to_page(mem)); - } - - fh->buffers.buffer[i].jpg.frag_tab[2 * j - 1] |= cpu_to_le32(1); - } - } - - dprintk(4, - KERN_DEBUG "%s: %s - %d KB allocated\n", - ZR_DEVNAME(zr), __func__, - (fh->buffers.num_buffers * fh->buffers.buffer_size) >> 10); - - fh->buffers.allocated = 1; - - return 0; -} - -/* free the MJPEG grab buffers */ -static void jpg_fbuffer_free(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - int i, j, off; - unsigned char *mem; - __le32 frag_tab; - struct zoran_buffer *buffer; - - dprintk(4, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); - - for (i = 0, buffer = &fh->buffers.buffer[0]; - i < fh->buffers.num_buffers; i++, buffer++) { - if (!buffer->jpg.frag_tab) - continue; - - if (fh->buffers.need_contiguous) { - frag_tab = buffer->jpg.frag_tab[0]; - - if (frag_tab) { - mem = bus_to_virt(le32_to_cpu(frag_tab)); - for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE) - ClearPageReserved(virt_to_page(mem + off)); - kfree(mem); - buffer->jpg.frag_tab[0] = 0; - buffer->jpg.frag_tab[1] = 0; - } - } else { - for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) { - frag_tab = buffer->jpg.frag_tab[2 * j]; - - if (!frag_tab) - break; - ClearPageReserved(virt_to_page(bus_to_virt(le32_to_cpu(frag_tab)))); - free_page((unsigned long)bus_to_virt(le32_to_cpu(frag_tab))); - buffer->jpg.frag_tab[2 * j] = 0; - buffer->jpg.frag_tab[2 * j + 1] = 0; - } - } - - free_page((unsigned long)buffer->jpg.frag_tab); - buffer->jpg.frag_tab = NULL; - } - - fh->buffers.allocated = 0; -} - -/* - * V4L Buffer grabbing - */ - -static int -zoran_v4l_set_format (struct zoran_fh *fh, - int width, - int height, - const struct zoran_format *format) -{ - struct zoran *zr = fh->zr; - int bpp; - - /* Check size and format of the grab wanted */ - - if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH || - height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) { - dprintk(1, - KERN_ERR - "%s: %s - wrong frame size (%dx%d)\n", - ZR_DEVNAME(zr), __func__, width, height); - return -EINVAL; - } - - bpp = (format->depth + 7) / 8; - - /* Check against available buffer size */ - if (height * width * bpp > fh->buffers.buffer_size) { - dprintk(1, - KERN_ERR - "%s: %s - video buffer size (%d kB) is too small\n", - ZR_DEVNAME(zr), __func__, fh->buffers.buffer_size >> 10); - return -EINVAL; - } - - /* The video front end needs 4-byte alinged line sizes */ - - if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) { - dprintk(1, - KERN_ERR - "%s: %s - wrong frame alignment\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - fh->v4l_settings.width = width; - fh->v4l_settings.height = height; - fh->v4l_settings.format = format; - fh->v4l_settings.bytesperline = bpp * fh->v4l_settings.width; - - return 0; -} - -static int zoran_v4l_queue_frame(struct zoran_fh *fh, int num) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - int res = 0; - - if (!fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s - buffers not yet allocated\n", - ZR_DEVNAME(zr), __func__); - res = -ENOMEM; - } - - /* No grabbing outside the buffer range! */ - if (num >= fh->buffers.num_buffers || num < 0) { - dprintk(1, - KERN_ERR - "%s: %s - buffer %d is out of range\n", - ZR_DEVNAME(zr), __func__, num); - res = -EINVAL; - } - - spin_lock_irqsave(&zr->spinlock, flags); - - if (fh->buffers.active == ZORAN_FREE) { - if (zr->v4l_buffers.active == ZORAN_FREE) { - zr->v4l_buffers = fh->buffers; - fh->buffers.active = ZORAN_ACTIVE; - } else { - dprintk(1, - KERN_ERR - "%s: %s - another session is already capturing\n", - ZR_DEVNAME(zr), __func__); - res = -EBUSY; - } - } - - /* make sure a grab isn't going on currently with this buffer */ - if (!res) { - switch (zr->v4l_buffers.buffer[num].state) { - default: - case BUZ_STATE_PEND: - if (zr->v4l_buffers.active == ZORAN_FREE) { - fh->buffers.active = ZORAN_FREE; - zr->v4l_buffers.allocated = 0; - } - res = -EBUSY; /* what are you doing? */ - break; - case BUZ_STATE_DONE: - dprintk(2, - KERN_WARNING - "%s: %s - queueing buffer %d in state DONE!?\n", - ZR_DEVNAME(zr), __func__, num); - case BUZ_STATE_USER: - /* since there is at least one unused buffer there's room for at least - * one more pend[] entry */ - zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = num; - zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND; - zr->v4l_buffers.buffer[num].bs.length = - fh->v4l_settings.bytesperline * - zr->v4l_settings.height; - fh->buffers.buffer[num] = zr->v4l_buffers.buffer[num]; - break; - } - } - - spin_unlock_irqrestore(&zr->spinlock, flags); - - if (!res && zr->v4l_buffers.active == ZORAN_FREE) - zr->v4l_buffers.active = fh->buffers.active; - - return res; -} - -/* - * Sync on a V4L buffer - */ - -static int v4l_sync(struct zoran_fh *fh, int frame) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - - if (fh->buffers.active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s - no grab active for this session\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - /* check passed-in frame number */ - if (frame >= fh->buffers.num_buffers || frame < 0) { - dprintk(1, - KERN_ERR "%s: %s - frame %d is invalid\n", - ZR_DEVNAME(zr), __func__, frame); - return -EINVAL; - } - - /* Check if is buffer was queued at all */ - if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) { - dprintk(1, - KERN_ERR - "%s: %s - attempt to sync on a buffer which was not queued?\n", - ZR_DEVNAME(zr), __func__); - return -EPROTO; - } - - /* wait on this buffer to get ready */ - if (!wait_event_interruptible_timeout(zr->v4l_capq, - (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), 10*HZ)) - return -ETIME; - if (signal_pending(current)) - return -ERESTARTSYS; - - /* buffer should now be in BUZ_STATE_DONE */ - if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE) - dprintk(2, - KERN_ERR "%s: %s - internal state error\n", - ZR_DEVNAME(zr), __func__); - - zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER; - fh->buffers.buffer[frame] = zr->v4l_buffers.buffer[frame]; - - spin_lock_irqsave(&zr->spinlock, flags); - - /* Check if streaming capture has finished */ - if (zr->v4l_pend_tail == zr->v4l_pend_head) { - zr36057_set_memgrab(zr, 0); - if (zr->v4l_buffers.active == ZORAN_ACTIVE) { - fh->buffers.active = zr->v4l_buffers.active = ZORAN_FREE; - zr->v4l_buffers.allocated = 0; - } - } - - spin_unlock_irqrestore(&zr->spinlock, flags); - - return 0; -} - -/* - * Queue a MJPEG buffer for capture/playback - */ - -static int zoran_jpg_queue_frame(struct zoran_fh *fh, int num, - enum zoran_codec_mode mode) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - int res = 0; - - /* Check if buffers are allocated */ - if (!fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s - buffers not yet allocated\n", - ZR_DEVNAME(zr), __func__); - return -ENOMEM; - } - - /* No grabbing outside the buffer range! */ - if (num >= fh->buffers.num_buffers || num < 0) { - dprintk(1, - KERN_ERR - "%s: %s - buffer %d out of range\n", - ZR_DEVNAME(zr), __func__, num); - return -EINVAL; - } - - /* what is the codec mode right now? */ - if (zr->codec_mode == BUZ_MODE_IDLE) { - zr->jpg_settings = fh->jpg_settings; - } else if (zr->codec_mode != mode) { - /* wrong codec mode active - invalid */ - dprintk(1, - KERN_ERR - "%s: %s - codec in wrong mode\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - if (fh->buffers.active == ZORAN_FREE) { - if (zr->jpg_buffers.active == ZORAN_FREE) { - zr->jpg_buffers = fh->buffers; - fh->buffers.active = ZORAN_ACTIVE; - } else { - dprintk(1, - KERN_ERR - "%s: %s - another session is already capturing\n", - ZR_DEVNAME(zr), __func__); - res = -EBUSY; - } - } - - if (!res && zr->codec_mode == BUZ_MODE_IDLE) { - /* Ok load up the jpeg codec */ - zr36057_enable_jpg(zr, mode); - } - - spin_lock_irqsave(&zr->spinlock, flags); - - if (!res) { - switch (zr->jpg_buffers.buffer[num].state) { - case BUZ_STATE_DONE: - dprintk(2, - KERN_WARNING - "%s: %s - queing frame in BUZ_STATE_DONE state!?\n", - ZR_DEVNAME(zr), __func__); - case BUZ_STATE_USER: - /* since there is at least one unused buffer there's room for at - *least one more pend[] entry */ - zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = num; - zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND; - fh->buffers.buffer[num] = zr->jpg_buffers.buffer[num]; - zoran_feed_stat_com(zr); - break; - default: - case BUZ_STATE_DMA: - case BUZ_STATE_PEND: - if (zr->jpg_buffers.active == ZORAN_FREE) { - fh->buffers.active = ZORAN_FREE; - zr->jpg_buffers.allocated = 0; - } - res = -EBUSY; /* what are you doing? */ - break; - } - } - - spin_unlock_irqrestore(&zr->spinlock, flags); - - if (!res && zr->jpg_buffers.active == ZORAN_FREE) - zr->jpg_buffers.active = fh->buffers.active; - - return res; -} - -static int jpg_qbuf(struct zoran_fh *fh, int frame, enum zoran_codec_mode mode) -{ - struct zoran *zr = fh->zr; - int res = 0; - - /* Does the user want to stop streaming? */ - if (frame < 0) { - if (zr->codec_mode == mode) { - if (fh->buffers.active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s(-1) - session not active\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - fh->buffers.active = zr->jpg_buffers.active = ZORAN_FREE; - zr->jpg_buffers.allocated = 0; - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - return 0; - } else { - dprintk(1, - KERN_ERR - "%s: %s - stop streaming but not in streaming mode\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - } - - if ((res = zoran_jpg_queue_frame(fh, frame, mode))) - return res; - - /* Start the jpeg codec when the first frame is queued */ - if (!res && zr->jpg_que_head == 1) - jpeg_start(zr); - - return res; -} - -/* - * Sync on a MJPEG buffer - */ - -static int jpg_sync(struct zoran_fh *fh, struct zoran_sync *bs) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - int frame; - - if (fh->buffers.active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s - capture is not currently active\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && - zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { - dprintk(1, - KERN_ERR - "%s: %s - codec not in streaming mode\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - if (!wait_event_interruptible_timeout(zr->jpg_capq, - (zr->jpg_que_tail != zr->jpg_dma_tail || - zr->jpg_dma_tail == zr->jpg_dma_head), - 10*HZ)) { - int isr; - - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); - udelay(1); - zr->codec->control(zr->codec, CODEC_G_STATUS, - sizeof(isr), &isr); - dprintk(1, - KERN_ERR - "%s: %s - timeout: codec isr=0x%02x\n", - ZR_DEVNAME(zr), __func__, isr); - - return -ETIME; - - } - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&zr->spinlock, flags); - - if (zr->jpg_dma_tail != zr->jpg_dma_head) - frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; - else - frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; - - /* buffer should now be in BUZ_STATE_DONE */ - if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) - dprintk(2, - KERN_ERR "%s: %s - internal state error\n", - ZR_DEVNAME(zr), __func__); - - *bs = zr->jpg_buffers.buffer[frame].bs; - bs->frame = frame; - zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER; - fh->buffers.buffer[frame] = zr->jpg_buffers.buffer[frame]; - - spin_unlock_irqrestore(&zr->spinlock, flags); - - return 0; -} - -static void zoran_open_init_session(struct zoran_fh *fh) -{ - int i; - struct zoran *zr = fh->zr; - - /* Per default, map the V4L Buffers */ - map_mode_raw(fh); - - /* take over the card's current settings */ - fh->overlay_settings = zr->overlay_settings; - fh->overlay_settings.is_set = 0; - fh->overlay_settings.format = zr->overlay_settings.format; - fh->overlay_active = ZORAN_FREE; - - /* v4l settings */ - fh->v4l_settings = zr->v4l_settings; - /* jpg settings */ - fh->jpg_settings = zr->jpg_settings; - - /* buffers */ - memset(&fh->buffers, 0, sizeof(fh->buffers)); - for (i = 0; i < MAX_FRAME; i++) { - fh->buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ - fh->buffers.buffer[i].bs.frame = i; - } - fh->buffers.allocated = 0; - fh->buffers.active = ZORAN_FREE; -} - -static void zoran_close_end_session(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - - /* overlay */ - if (fh->overlay_active != ZORAN_FREE) { - fh->overlay_active = zr->overlay_active = ZORAN_FREE; - zr->v4l_overlay_active = 0; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 0); - zr->overlay_mask = NULL; - } - - if (fh->map_mode == ZORAN_MAP_MODE_RAW) { - /* v4l capture */ - if (fh->buffers.active != ZORAN_FREE) { - unsigned long flags; - - spin_lock_irqsave(&zr->spinlock, flags); - zr36057_set_memgrab(zr, 0); - zr->v4l_buffers.allocated = 0; - zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE; - spin_unlock_irqrestore(&zr->spinlock, flags); - } - - /* v4l buffers */ - if (fh->buffers.allocated) - v4l_fbuffer_free(fh); - } else { - /* jpg capture */ - if (fh->buffers.active != ZORAN_FREE) { - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - zr->jpg_buffers.allocated = 0; - zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE; - } - - /* jpg buffers */ - if (fh->buffers.allocated) - jpg_fbuffer_free(fh); - } -} - -/* - * Open a zoran card. Right now the flags stuff is just playing - */ - -static int zoran_open(struct file *file) -{ - struct zoran *zr = video_drvdata(file); - struct zoran_fh *fh; - int res, first_open = 0; - - dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(-)=%d\n", - ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user + 1); - - mutex_lock(&zr->other_lock); - - if (zr->user >= 2048) { - dprintk(1, KERN_ERR "%s: too many users (%d) on device\n", - ZR_DEVNAME(zr), zr->user); - res = -EBUSY; - goto fail_unlock; - } - - /* now, create the open()-specific file_ops struct */ - fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL); - if (!fh) { - dprintk(1, - KERN_ERR - "%s: %s - allocation of zoran_fh failed\n", - ZR_DEVNAME(zr), __func__); - res = -ENOMEM; - goto fail_unlock; - } - /* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows - * on norm-change! */ - fh->overlay_mask = - kmalloc(((768 + 31) / 32) * 576 * 4, GFP_KERNEL); - if (!fh->overlay_mask) { - dprintk(1, - KERN_ERR - "%s: %s - allocation of overlay_mask failed\n", - ZR_DEVNAME(zr), __func__); - res = -ENOMEM; - goto fail_fh; - } - - if (zr->user++ == 0) - first_open = 1; - - /*mutex_unlock(&zr->resource_lock);*/ - - /* default setup - TODO: look at flags */ - if (first_open) { /* First device open */ - zr36057_restart(zr); - zoran_open_init_params(zr); - zoran_init_hardware(zr); - - btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); - } - - /* set file_ops stuff */ - file->private_data = fh; - fh->zr = zr; - zoran_open_init_session(fh); - mutex_unlock(&zr->other_lock); - - return 0; - -fail_fh: - kfree(fh); -fail_unlock: - mutex_unlock(&zr->other_lock); - - dprintk(2, KERN_INFO "%s: open failed (%d), users(-)=%d\n", - ZR_DEVNAME(zr), res, zr->user); - - return res; -} - -static int -zoran_close(struct file *file) -{ - struct zoran_fh *fh = file->private_data; - struct zoran *zr = fh->zr; - - dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(+)=%d\n", - ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user - 1); - - /* kernel locks (fs/device.c), so don't do that ourselves - * (prevents deadlocks) */ - mutex_lock(&zr->other_lock); - - zoran_close_end_session(fh); - - if (zr->user-- == 1) { /* Last process */ - /* Clean up JPEG process */ - wake_up_interruptible(&zr->jpg_capq); - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - zr->jpg_buffers.allocated = 0; - zr->jpg_buffers.active = ZORAN_FREE; - - /* disable interrupts */ - btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - - if (zr36067_debug > 1) - print_interrupts(zr); - - /* Overlay off */ - zr->v4l_overlay_active = 0; - zr36057_overlay(zr, 0); - zr->overlay_mask = NULL; - - /* capture off */ - wake_up_interruptible(&zr->v4l_capq); - zr36057_set_memgrab(zr, 0); - zr->v4l_buffers.allocated = 0; - zr->v4l_buffers.active = ZORAN_FREE; - zoran_set_pci_master(zr, 0); - - if (!pass_through) { /* Switch to color bar */ - decoder_call(zr, video, s_stream, 0); - encoder_call(zr, video, s_routing, 2, 0, 0); - } - } - mutex_unlock(&zr->other_lock); - - file->private_data = NULL; - kfree(fh->overlay_mask); - kfree(fh); - - dprintk(4, KERN_INFO "%s: %s done\n", ZR_DEVNAME(zr), __func__); - - return 0; -} - - -static ssize_t -zoran_read (struct file *file, - char __user *data, - size_t count, - loff_t *ppos) -{ - /* we simply don't support read() (yet)... */ - - return -EINVAL; -} - -static ssize_t -zoran_write (struct file *file, - const char __user *data, - size_t count, - loff_t *ppos) -{ - /* ...and the same goes for write() */ - - return -EINVAL; -} - -static int setup_fbuffer(struct zoran_fh *fh, - void *base, - const struct zoran_format *fmt, - int width, - int height, - int bytesperline) -{ - struct zoran *zr = fh->zr; - - /* (Ronald) v4l/v4l2 guidelines */ - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* Don't allow frame buffer overlay if PCI or AGP is buggy, or on - ALi Magik (that needs very low latency while the card needs a - higher value always) */ - - if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK)) - return -ENXIO; - - /* we need a bytesperline value, even if not given */ - if (!bytesperline) - bytesperline = width * ((fmt->depth + 7) & ~7) / 8; - -#if 0 - if (zr->overlay_active) { - /* dzjee... stupid users... don't even bother to turn off - * overlay before changing the memory location... - * normally, we would return errors here. However, one of - * the tools that does this is... xawtv! and since xawtv - * is used by +/- 99% of the users, we'd rather be user- - * friendly and silently do as if nothing went wrong */ - dprintk(3, - KERN_ERR - "%s: %s - forced overlay turnoff because framebuffer changed\n", - ZR_DEVNAME(zr), __func__); - zr36057_overlay(zr, 0); - } -#endif - - if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) { - dprintk(1, - KERN_ERR - "%s: %s - no valid overlay format given\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - if (height <= 0 || width <= 0 || bytesperline <= 0) { - dprintk(1, - KERN_ERR - "%s: %s - invalid height/width/bpl value (%d|%d|%d)\n", - ZR_DEVNAME(zr), __func__, width, height, bytesperline); - return -EINVAL; - } - if (bytesperline & 3) { - dprintk(1, - KERN_ERR - "%s: %s - bytesperline (%d) must be 4-byte aligned\n", - ZR_DEVNAME(zr), __func__, bytesperline); - return -EINVAL; - } - - zr->vbuf_base = (void *) ((unsigned long) base & ~3); - zr->vbuf_height = height; - zr->vbuf_width = width; - zr->vbuf_depth = fmt->depth; - zr->overlay_settings.format = fmt; - zr->vbuf_bytesperline = bytesperline; - - /* The user should set new window parameters */ - zr->overlay_settings.is_set = 0; - - return 0; -} - - -static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height, - struct v4l2_clip __user *clips, int clipcount, void __user *bitmap) -{ - struct zoran *zr = fh->zr; - struct v4l2_clip *vcp = NULL; - int on, end; - - - if (!zr->vbuf_base) { - dprintk(1, - KERN_ERR - "%s: %s - frame buffer has to be set first\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - if (!fh->overlay_settings.format) { - dprintk(1, - KERN_ERR - "%s: %s - no overlay format set\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - /* - * The video front end needs 4-byte alinged line sizes, we correct that - * silently here if necessary - */ - if (zr->vbuf_depth == 15 || zr->vbuf_depth == 16) { - end = (x + width) & ~1; /* round down */ - x = (x + 1) & ~1; /* round up */ - width = end - x; - } - - if (zr->vbuf_depth == 24) { - end = (x + width) & ~3; /* round down */ - x = (x + 3) & ~3; /* round up */ - width = end - x; - } - - if (width > BUZ_MAX_WIDTH) - width = BUZ_MAX_WIDTH; - if (height > BUZ_MAX_HEIGHT) - height = BUZ_MAX_HEIGHT; - - /* Check for invalid parameters */ - if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT || - width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) { - dprintk(1, - KERN_ERR - "%s: %s - width = %d or height = %d invalid\n", - ZR_DEVNAME(zr), __func__, width, height); - return -EINVAL; - } - - fh->overlay_settings.x = x; - fh->overlay_settings.y = y; - fh->overlay_settings.width = width; - fh->overlay_settings.height = height; - fh->overlay_settings.clipcount = clipcount; - - /* - * If an overlay is running, we have to switch it off - * and switch it on again in order to get the new settings in effect. - * - * We also want to avoid that the overlay mask is written - * when an overlay is running. - */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active && - zr->overlay_active != ZORAN_FREE && - fh->overlay_active != ZORAN_FREE; - if (on) - zr36057_overlay(zr, 0); - - /* - * Write the overlay mask if clips are wanted. - * We prefer a bitmap. - */ - if (bitmap) { - /* fake value - it just means we want clips */ - fh->overlay_settings.clipcount = 1; - - if (copy_from_user(fh->overlay_mask, bitmap, - (width * height + 7) / 8)) { - return -EFAULT; - } - } else if (clipcount > 0) { - /* write our own bitmap from the clips */ - vcp = vmalloc(sizeof(struct v4l2_clip) * (clipcount + 4)); - if (vcp == NULL) { - dprintk(1, - KERN_ERR - "%s: %s - Alloc of clip mask failed\n", - ZR_DEVNAME(zr), __func__); - return -ENOMEM; - } - if (copy_from_user - (vcp, clips, sizeof(struct v4l2_clip) * clipcount)) { - vfree(vcp); - return -EFAULT; - } - write_overlay_mask(fh, vcp, clipcount); - vfree(vcp); - } - - fh->overlay_settings.is_set = 1; - if (fh->overlay_active != ZORAN_FREE && - zr->overlay_active != ZORAN_FREE) - zr->overlay_settings = fh->overlay_settings; - - if (on) - zr36057_overlay(zr, 1); - - /* Make sure the changes come into effect */ - return wait_grab_pending(zr); -} - -static int setup_overlay(struct zoran_fh *fh, int on) -{ - struct zoran *zr = fh->zr; - - /* If there is nothing to do, return immediatly */ - if ((on && fh->overlay_active != ZORAN_FREE) || - (!on && fh->overlay_active == ZORAN_FREE)) - return 0; - - /* check whether we're touching someone else's overlay */ - if (on && zr->overlay_active != ZORAN_FREE && - fh->overlay_active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s - overlay is already active for another session\n", - ZR_DEVNAME(zr), __func__); - return -EBUSY; - } - if (!on && zr->overlay_active != ZORAN_FREE && - fh->overlay_active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s - you cannot cancel someone else's session\n", - ZR_DEVNAME(zr), __func__); - return -EPERM; - } - - if (on == 0) { - zr->overlay_active = fh->overlay_active = ZORAN_FREE; - zr->v4l_overlay_active = 0; - /* When a grab is running, the video simply - * won't be switched on any more */ - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 0); - zr->overlay_mask = NULL; - } else { - if (!zr->vbuf_base || !fh->overlay_settings.is_set) { - dprintk(1, - KERN_ERR - "%s: %s - buffer or window not set\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - if (!fh->overlay_settings.format) { - dprintk(1, - KERN_ERR - "%s: %s - no overlay format set\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - zr->overlay_active = fh->overlay_active = ZORAN_LOCKED; - zr->v4l_overlay_active = 1; - zr->overlay_mask = fh->overlay_mask; - zr->overlay_settings = fh->overlay_settings; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 1); - /* When a grab is running, the video will be - * switched on when grab is finished */ - } - - /* Make sure the changes come into effect */ - return wait_grab_pending(zr); -} - -/* get the status of a buffer in the clients buffer queue */ -static int zoran_v4l2_buffer_status(struct zoran_fh *fh, - struct v4l2_buffer *buf, int num) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - - buf->flags = V4L2_BUF_FLAG_MAPPED; - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: - /* check range */ - if (num < 0 || num >= fh->buffers.num_buffers || - !fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s - wrong number or buffers not allocated\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - spin_lock_irqsave(&zr->spinlock, flags); - dprintk(3, - KERN_DEBUG - "%s: %s() - raw active=%c, buffer %d: state=%c, map=%c\n", - ZR_DEVNAME(zr), __func__, - "FAL"[fh->buffers.active], num, - "UPMD"[zr->v4l_buffers.buffer[num].state], - fh->buffers.buffer[num].map ? 'Y' : 'N'); - spin_unlock_irqrestore(&zr->spinlock, flags); - - buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->length = fh->buffers.buffer_size; - - /* get buffer */ - buf->bytesused = fh->buffers.buffer[num].bs.length; - if (fh->buffers.buffer[num].state == BUZ_STATE_DONE || - fh->buffers.buffer[num].state == BUZ_STATE_USER) { - buf->sequence = fh->buffers.buffer[num].bs.seq; - buf->flags |= V4L2_BUF_FLAG_DONE; - buf->timestamp = fh->buffers.buffer[num].bs.timestamp; - } else { - buf->flags |= V4L2_BUF_FLAG_QUEUED; - } - - if (fh->v4l_settings.height <= BUZ_MAX_HEIGHT / 2) - buf->field = V4L2_FIELD_TOP; - else - buf->field = V4L2_FIELD_INTERLACED; - - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - - /* check range */ - if (num < 0 || num >= fh->buffers.num_buffers || - !fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s - wrong number or buffers not allocated\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ? - V4L2_BUF_TYPE_VIDEO_CAPTURE : - V4L2_BUF_TYPE_VIDEO_OUTPUT; - buf->length = fh->buffers.buffer_size; - - /* these variables are only written after frame has been captured */ - if (fh->buffers.buffer[num].state == BUZ_STATE_DONE || - fh->buffers.buffer[num].state == BUZ_STATE_USER) { - buf->sequence = fh->buffers.buffer[num].bs.seq; - buf->timestamp = fh->buffers.buffer[num].bs.timestamp; - buf->bytesused = fh->buffers.buffer[num].bs.length; - buf->flags |= V4L2_BUF_FLAG_DONE; - } else { - buf->flags |= V4L2_BUF_FLAG_QUEUED; - } - - /* which fields are these? */ - if (fh->jpg_settings.TmpDcm != 1) - buf->field = fh->jpg_settings.odd_even ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; - else - buf->field = fh->jpg_settings.odd_even ? - V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT; - - break; - - default: - - dprintk(5, - KERN_ERR - "%s: %s - invalid buffer type|map_mode (%d|%d)\n", - ZR_DEVNAME(zr), __func__, buf->type, fh->map_mode); - return -EINVAL; - } - - buf->memory = V4L2_MEMORY_MMAP; - buf->index = num; - buf->m.offset = buf->length * num; - - return 0; -} - -static int -zoran_set_norm (struct zoran *zr, - v4l2_std_id norm) -{ - int on; - - if (zr->v4l_buffers.active != ZORAN_FREE || - zr->jpg_buffers.active != ZORAN_FREE) { - dprintk(1, - KERN_WARNING - "%s: %s called while in playback/capture mode\n", - ZR_DEVNAME(zr), __func__); - return -EBUSY; - } - - if (!(norm & zr->card.norms)) { - dprintk(1, - KERN_ERR "%s: %s - unsupported norm %llx\n", - ZR_DEVNAME(zr), __func__, norm); - return -EINVAL; - } - - if (norm == V4L2_STD_ALL) { - unsigned int status = 0; - v4l2_std_id std = 0; - - decoder_call(zr, video, querystd, &std); - decoder_call(zr, core, s_std, std); - - /* let changes come into effect */ - ssleep(2); - - decoder_call(zr, video, g_input_status, &status); - if (status & V4L2_IN_ST_NO_SIGNAL) { - dprintk(1, - KERN_ERR - "%s: %s - no norm detected\n", - ZR_DEVNAME(zr), __func__); - /* reset norm */ - decoder_call(zr, core, s_std, zr->norm); - return -EIO; - } - - norm = std; - } - if (norm & V4L2_STD_SECAM) - zr->timing = zr->card.tvn[2]; - else if (norm & V4L2_STD_NTSC) - zr->timing = zr->card.tvn[1]; - else - zr->timing = zr->card.tvn[0]; - - /* We switch overlay off and on since a change in the - * norm needs different VFE settings */ - on = zr->overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - decoder_call(zr, core, s_std, norm); - encoder_call(zr, video, s_std_output, norm); - - if (on) - zr36057_overlay(zr, 1); - - /* Make sure the changes come into effect */ - zr->norm = norm; - - return 0; -} - -static int -zoran_set_input (struct zoran *zr, - int input) -{ - if (input == zr->input) { - return 0; - } - - if (zr->v4l_buffers.active != ZORAN_FREE || - zr->jpg_buffers.active != ZORAN_FREE) { - dprintk(1, - KERN_WARNING - "%s: %s called while in playback/capture mode\n", - ZR_DEVNAME(zr), __func__); - return -EBUSY; - } - - if (input < 0 || input >= zr->card.inputs) { - dprintk(1, - KERN_ERR - "%s: %s - unnsupported input %d\n", - ZR_DEVNAME(zr), __func__, input); - return -EINVAL; - } - - zr->input = input; - - decoder_call(zr, video, s_routing, - zr->card.input[input].muxsel, 0, 0); - - return 0; -} - -/* - * ioctl routine - */ - -static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - memset(cap, 0, sizeof(*cap)); - strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1); - strncpy(cap->driver, "zoran", sizeof(cap->driver)-1); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", - pci_name(zr->pci_dev)); - cap->version = KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION, - RELEASE_VERSION); - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY; - return 0; -} - -static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag) -{ - unsigned int num, i; - - for (num = i = 0; i < NUM_FORMATS; i++) { - if (zoran_formats[i].flags & flag && num++ == fmt->index) { - strncpy(fmt->description, zoran_formats[i].name, - sizeof(fmt->description) - 1); - /* fmt struct pre-zeroed, so adding '\0' not neeed */ - fmt->pixelformat = zoran_formats[i].fourcc; - if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED) - fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; - return 0; - } - } - return -EINVAL; -} - -static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_fmtdesc *f) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE); -} - -static int zoran_enum_fmt_vid_out(struct file *file, void *__fh, - struct v4l2_fmtdesc *f) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK); -} - -static int zoran_enum_fmt_vid_overlay(struct file *file, void *__fh, - struct v4l2_fmtdesc *f) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - return zoran_enum_fmt(zr, f, ZORAN_FORMAT_OVERLAY); -} - -static int zoran_g_fmt_vid_out(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - mutex_lock(&zr->resource_lock); - - fmt->fmt.pix.width = fh->jpg_settings.img_width / fh->jpg_settings.HorDcm; - fmt->fmt.pix.height = fh->jpg_settings.img_height * 2 / - (fh->jpg_settings.VerDcm * fh->jpg_settings.TmpDcm); - fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&fh->jpg_settings); - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; - if (fh->jpg_settings.TmpDcm == 1) - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); - else - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); - fmt->fmt.pix.bytesperline = 0; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - - mutex_unlock(&zr->resource_lock); - return 0; -} - -static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - if (fh->map_mode != ZORAN_MAP_MODE_RAW) - return zoran_g_fmt_vid_out(file, fh, fmt); - - mutex_lock(&zr->resource_lock); - fmt->fmt.pix.width = fh->v4l_settings.width; - fmt->fmt.pix.height = fh->v4l_settings.height; - fmt->fmt.pix.sizeimage = fh->v4l_settings.bytesperline * - fh->v4l_settings.height; - fmt->fmt.pix.pixelformat = fh->v4l_settings.format->fourcc; - fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace; - fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline; - if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2)) - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - else - fmt->fmt.pix.field = V4L2_FIELD_TOP; - mutex_unlock(&zr->resource_lock); - return 0; -} - -static int zoran_g_fmt_vid_overlay(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - mutex_lock(&zr->resource_lock); - - fmt->fmt.win.w.left = fh->overlay_settings.x; - fmt->fmt.win.w.top = fh->overlay_settings.y; - fmt->fmt.win.w.width = fh->overlay_settings.width; - fmt->fmt.win.w.height = fh->overlay_settings.height; - if (fh->overlay_settings.width * 2 > BUZ_MAX_HEIGHT) - fmt->fmt.win.field = V4L2_FIELD_INTERLACED; - else - fmt->fmt.win.field = V4L2_FIELD_TOP; - - mutex_unlock(&zr->resource_lock); - return 0; -} - -static int zoran_try_fmt_vid_overlay(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - mutex_lock(&zr->resource_lock); - - if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH) - fmt->fmt.win.w.width = BUZ_MAX_WIDTH; - if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH) - fmt->fmt.win.w.width = BUZ_MIN_WIDTH; - if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT) - fmt->fmt.win.w.height = BUZ_MAX_HEIGHT; - if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT) - fmt->fmt.win.w.height = BUZ_MIN_HEIGHT; - - mutex_unlock(&zr->resource_lock); - return 0; -} - -static int zoran_try_fmt_vid_out(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - struct zoran_jpg_settings settings; - int res = 0; - - if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - mutex_lock(&zr->resource_lock); - settings = fh->jpg_settings; - - /* we actually need to set 'real' parameters now */ - if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT) - settings.TmpDcm = 1; - else - settings.TmpDcm = 2; - settings.decimation = 0; - if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2) - settings.VerDcm = 2; - else - settings.VerDcm = 1; - if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4) - settings.HorDcm = 4; - else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2) - settings.HorDcm = 2; - else - settings.HorDcm = 1; - if (settings.TmpDcm == 1) - settings.field_per_buff = 2; - else - settings.field_per_buff = 1; - - if (settings.HorDcm > 1) { - settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; - settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; - } else { - settings.img_x = 0; - settings.img_width = BUZ_MAX_WIDTH; - } - - /* check */ - res = zoran_check_jpg_settings(zr, &settings, 1); - if (res) - goto tryfmt_unlock_and_return; - - /* tell the user what we actually did */ - fmt->fmt.pix.width = settings.img_width / settings.HorDcm; - fmt->fmt.pix.height = settings.img_height * 2 / - (settings.TmpDcm * settings.VerDcm); - if (settings.TmpDcm == 1) - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); - else - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); - - fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings); - fmt->fmt.pix.bytesperline = 0; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; -tryfmt_unlock_and_return: - mutex_unlock(&zr->resource_lock); - return res; -} - -static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int bpp; - int i; - - if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) - return zoran_try_fmt_vid_out(file, fh, fmt); - - mutex_lock(&zr->resource_lock); - - for (i = 0; i < NUM_FORMATS; i++) - if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat) - break; - - if (i == NUM_FORMATS) { - mutex_unlock(&zr->resource_lock); - return -EINVAL; - } - - bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8); - v4l_bound_align_image( - &fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, bpp == 2 ? 1 : 2, - &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, 0, 0); - mutex_unlock(&zr->resource_lock); - - return 0; -} - -static int zoran_s_fmt_vid_overlay(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res; - - dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n", - fmt->fmt.win.w.left, fmt->fmt.win.w.top, - fmt->fmt.win.w.width, - fmt->fmt.win.w.height, - fmt->fmt.win.clipcount, - fmt->fmt.win.bitmap); - mutex_lock(&zr->resource_lock); - res = setup_window(fh, fmt->fmt.win.w.left, fmt->fmt.win.w.top, - fmt->fmt.win.w.width, fmt->fmt.win.w.height, - (struct v4l2_clip __user *)fmt->fmt.win.clips, - fmt->fmt.win.clipcount, fmt->fmt.win.bitmap); - mutex_unlock(&zr->resource_lock); - return res; -} - -static int zoran_s_fmt_vid_out(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - __le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat); - struct zoran_jpg_settings settings; - int res = 0; - - dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n", - fmt->fmt.pix.width, fmt->fmt.pix.height, - fmt->fmt.pix.pixelformat, - (char *) &printformat); - if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - mutex_lock(&zr->resource_lock); - - if (fh->buffers.allocated) { - dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n", - ZR_DEVNAME(zr)); - res = -EBUSY; - goto sfmtjpg_unlock_and_return; - } - - settings = fh->jpg_settings; - - /* we actually need to set 'real' parameters now */ - if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT) - settings.TmpDcm = 1; - else - settings.TmpDcm = 2; - settings.decimation = 0; - if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2) - settings.VerDcm = 2; - else - settings.VerDcm = 1; - if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4) - settings.HorDcm = 4; - else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2) - settings.HorDcm = 2; - else - settings.HorDcm = 1; - if (settings.TmpDcm == 1) - settings.field_per_buff = 2; - else - settings.field_per_buff = 1; - - if (settings.HorDcm > 1) { - settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; - settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; - } else { - settings.img_x = 0; - settings.img_width = BUZ_MAX_WIDTH; - } - - /* check */ - res = zoran_check_jpg_settings(zr, &settings, 0); - if (res) - goto sfmtjpg_unlock_and_return; - - /* it's ok, so set them */ - fh->jpg_settings = settings; - - map_mode_jpg(fh, fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); - fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings); - - /* tell the user what we actually did */ - fmt->fmt.pix.width = settings.img_width / settings.HorDcm; - fmt->fmt.pix.height = settings.img_height * 2 / - (settings.TmpDcm * settings.VerDcm); - if (settings.TmpDcm == 1) - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); - else - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); - fmt->fmt.pix.bytesperline = 0; - fmt->fmt.pix.sizeimage = fh->buffers.buffer_size; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - -sfmtjpg_unlock_and_return: - mutex_unlock(&zr->resource_lock); - return res; -} - -static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int i; - int res = 0; - - if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) - return zoran_s_fmt_vid_out(file, fh, fmt); - - for (i = 0; i < NUM_FORMATS; i++) - if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc) - break; - if (i == NUM_FORMATS) { - dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x\n", - ZR_DEVNAME(zr), fmt->fmt.pix.pixelformat); - return -EINVAL; - } - - mutex_lock(&zr->resource_lock); - - if ((fh->map_mode != ZORAN_MAP_MODE_RAW && fh->buffers.allocated) || - fh->buffers.active != ZORAN_FREE) { - dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n", - ZR_DEVNAME(zr)); - res = -EBUSY; - goto sfmtv4l_unlock_and_return; - } - if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT) - fmt->fmt.pix.height = BUZ_MAX_HEIGHT; - if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) - fmt->fmt.pix.width = BUZ_MAX_WIDTH; - - map_mode_raw(fh); - - res = zoran_v4l_set_format(fh, fmt->fmt.pix.width, fmt->fmt.pix.height, - &zoran_formats[i]); - if (res) - goto sfmtv4l_unlock_and_return; - - /* tell the user the results/missing stuff */ - fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline; - fmt->fmt.pix.sizeimage = fh->v4l_settings.height * fh->v4l_settings.bytesperline; - fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace; - if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2)) - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - else - fmt->fmt.pix.field = V4L2_FIELD_TOP; - -sfmtv4l_unlock_and_return: - mutex_unlock(&zr->resource_lock); - return res; -} - -static int zoran_g_fbuf(struct file *file, void *__fh, - struct v4l2_framebuffer *fb) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - memset(fb, 0, sizeof(*fb)); - mutex_lock(&zr->resource_lock); - fb->base = zr->vbuf_base; - fb->fmt.width = zr->vbuf_width; - fb->fmt.height = zr->vbuf_height; - if (zr->overlay_settings.format) - fb->fmt.pixelformat = fh->overlay_settings.format->fourcc; - fb->fmt.bytesperline = zr->vbuf_bytesperline; - mutex_unlock(&zr->resource_lock); - fb->fmt.colorspace = V4L2_COLORSPACE_SRGB; - fb->fmt.field = V4L2_FIELD_INTERLACED; - fb->flags = V4L2_FBUF_FLAG_OVERLAY; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - - return 0; -} - -static int zoran_s_fbuf(struct file *file, void *__fh, - struct v4l2_framebuffer *fb) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int i, res = 0; - __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat); - - for (i = 0; i < NUM_FORMATS; i++) - if (zoran_formats[i].fourcc == fb->fmt.pixelformat) - break; - if (i == NUM_FORMATS) { - dprintk(1, KERN_ERR "%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n", - ZR_DEVNAME(zr), fb->fmt.pixelformat, - (char *)&printformat); - return -EINVAL; - } - - mutex_lock(&zr->resource_lock); - res = setup_fbuffer(fh, fb->base, &zoran_formats[i], fb->fmt.width, - fb->fmt.height, fb->fmt.bytesperline); - mutex_unlock(&zr->resource_lock); - - return res; -} - -static int zoran_overlay(struct file *file, void *__fh, unsigned int on) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res; - - mutex_lock(&zr->resource_lock); - res = setup_overlay(fh, on); - mutex_unlock(&zr->resource_lock); - - return res; -} - -static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type); - -static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *req) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0; - - if (req->memory != V4L2_MEMORY_MMAP) { - dprintk(2, - KERN_ERR - "%s: only MEMORY_MMAP capture is supported, not %d\n", - ZR_DEVNAME(zr), req->memory); - return -EINVAL; - } - - if (req->count == 0) - return zoran_streamoff(file, fh, req->type); - - mutex_lock(&zr->resource_lock); - if (fh->buffers.allocated) { - dprintk(2, - KERN_ERR - "%s: VIDIOC_REQBUFS - buffers already allocated\n", - ZR_DEVNAME(zr)); - res = -EBUSY; - goto v4l2reqbuf_unlock_and_return; - } - - if (fh->map_mode == ZORAN_MAP_MODE_RAW && - req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - /* control user input */ - if (req->count < 2) - req->count = 2; - if (req->count > v4l_nbufs) - req->count = v4l_nbufs; - - /* The next mmap will map the V4L buffers */ - map_mode_raw(fh); - fh->buffers.num_buffers = req->count; - - if (v4l_fbuffer_alloc(fh)) { - res = -ENOMEM; - goto v4l2reqbuf_unlock_and_return; - } - } else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC || - fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) { - /* we need to calculate size ourselves now */ - if (req->count < 4) - req->count = 4; - if (req->count > jpg_nbufs) - req->count = jpg_nbufs; - - /* The next mmap will map the MJPEG buffers */ - map_mode_jpg(fh, req->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); - fh->buffers.num_buffers = req->count; - fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings); - - if (jpg_fbuffer_alloc(fh)) { - res = -ENOMEM; - goto v4l2reqbuf_unlock_and_return; - } - } else { - dprintk(1, - KERN_ERR - "%s: VIDIOC_REQBUFS - unknown type %d\n", - ZR_DEVNAME(zr), req->type); - res = -EINVAL; - goto v4l2reqbuf_unlock_and_return; - } -v4l2reqbuf_unlock_and_return: - mutex_unlock(&zr->resource_lock); - - return res; -} - -static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res; - - mutex_lock(&zr->resource_lock); - res = zoran_v4l2_buffer_status(fh, buf, buf->index); - mutex_unlock(&zr->resource_lock); - - return res; -} - -static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0, codec_mode, buf_type; - - mutex_lock(&zr->resource_lock); - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", - ZR_DEVNAME(zr), buf->type, fh->map_mode); - res = -EINVAL; - goto qbuf_unlock_and_return; - } - - res = zoran_v4l_queue_frame(fh, buf->index); - if (res) - goto qbuf_unlock_and_return; - if (!zr->v4l_memgrab_active && fh->buffers.active == ZORAN_LOCKED) - zr36057_set_memgrab(zr, 1); - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) { - buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - codec_mode = BUZ_MODE_MOTION_DECOMPRESS; - } else { - buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - codec_mode = BUZ_MODE_MOTION_COMPRESS; - } - - if (buf->type != buf_type) { - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", - ZR_DEVNAME(zr), buf->type, fh->map_mode); - res = -EINVAL; - goto qbuf_unlock_and_return; - } - - res = zoran_jpg_queue_frame(fh, buf->index, codec_mode); - if (res != 0) - goto qbuf_unlock_and_return; - if (zr->codec_mode == BUZ_MODE_IDLE && - fh->buffers.active == ZORAN_LOCKED) - zr36057_enable_jpg(zr, codec_mode); - - break; - - default: - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - unsupported type %d\n", - ZR_DEVNAME(zr), buf->type); - res = -EINVAL; - break; - } -qbuf_unlock_and_return: - mutex_unlock(&zr->resource_lock); - - return res; -} - -static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0, buf_type, num = -1; /* compiler borks here (?) */ - - mutex_lock(&zr->resource_lock); - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", - ZR_DEVNAME(zr), buf->type, fh->map_mode); - res = -EINVAL; - goto dqbuf_unlock_and_return; - } - - num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME]; - if (file->f_flags & O_NONBLOCK && - zr->v4l_buffers.buffer[num].state != BUZ_STATE_DONE) { - res = -EAGAIN; - goto dqbuf_unlock_and_return; - } - res = v4l_sync(fh, num); - if (res) - goto dqbuf_unlock_and_return; - zr->v4l_sync_tail++; - res = zoran_v4l2_buffer_status(fh, buf, num); - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - { - struct zoran_sync bs; - - if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) - buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - else - buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (buf->type != buf_type) { - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", - ZR_DEVNAME(zr), buf->type, fh->map_mode); - res = -EINVAL; - goto dqbuf_unlock_and_return; - } - - num = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; - - if (file->f_flags & O_NONBLOCK && - zr->jpg_buffers.buffer[num].state != BUZ_STATE_DONE) { - res = -EAGAIN; - goto dqbuf_unlock_and_return; - } - bs.frame = 0; /* suppress compiler warning */ - res = jpg_sync(fh, &bs); - if (res) - goto dqbuf_unlock_and_return; - res = zoran_v4l2_buffer_status(fh, buf, bs.frame); - break; - } - - default: - dprintk(1, KERN_ERR - "%s: VIDIOC_DQBUF - unsupported type %d\n", - ZR_DEVNAME(zr), buf->type); - res = -EINVAL; - break; - } -dqbuf_unlock_and_return: - mutex_unlock(&zr->resource_lock); - - return res; -} - -static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0; - - mutex_lock(&zr->resource_lock); - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: /* raw capture */ - if (zr->v4l_buffers.active != ZORAN_ACTIVE || - fh->buffers.active != ZORAN_ACTIVE) { - res = -EBUSY; - goto strmon_unlock_and_return; - } - - zr->v4l_buffers.active = fh->buffers.active = ZORAN_LOCKED; - zr->v4l_settings = fh->v4l_settings; - - zr->v4l_sync_tail = zr->v4l_pend_tail; - if (!zr->v4l_memgrab_active && - zr->v4l_pend_head != zr->v4l_pend_tail) { - zr36057_set_memgrab(zr, 1); - } - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - /* what is the codec mode right now? */ - if (zr->jpg_buffers.active != ZORAN_ACTIVE || - fh->buffers.active != ZORAN_ACTIVE) { - res = -EBUSY; - goto strmon_unlock_and_return; - } - - zr->jpg_buffers.active = fh->buffers.active = ZORAN_LOCKED; - - if (zr->jpg_que_head != zr->jpg_que_tail) { - /* Start the jpeg codec when the first frame is queued */ - jpeg_start(zr); - } - break; - - default: - dprintk(1, - KERN_ERR - "%s: VIDIOC_STREAMON - invalid map mode %d\n", - ZR_DEVNAME(zr), fh->map_mode); - res = -EINVAL; - break; - } -strmon_unlock_and_return: - mutex_unlock(&zr->resource_lock); - - return res; -} - -static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int i, res = 0; - unsigned long flags; - - mutex_lock(&zr->resource_lock); - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: /* raw capture */ - if (fh->buffers.active == ZORAN_FREE && - zr->v4l_buffers.active != ZORAN_FREE) { - res = -EPERM; /* stay off other's settings! */ - goto strmoff_unlock_and_return; - } - if (zr->v4l_buffers.active == ZORAN_FREE) - goto strmoff_unlock_and_return; - - spin_lock_irqsave(&zr->spinlock, flags); - /* unload capture */ - if (zr->v4l_memgrab_active) { - - zr36057_set_memgrab(zr, 0); - } - - for (i = 0; i < fh->buffers.num_buffers; i++) - zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER; - fh->buffers = zr->v4l_buffers; - - zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE; - - zr->v4l_grab_seq = 0; - zr->v4l_pend_head = zr->v4l_pend_tail = 0; - zr->v4l_sync_tail = 0; - - spin_unlock_irqrestore(&zr->spinlock, flags); - - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - if (fh->buffers.active == ZORAN_FREE && - zr->jpg_buffers.active != ZORAN_FREE) { - res = -EPERM; /* stay off other's settings! */ - goto strmoff_unlock_and_return; - } - if (zr->jpg_buffers.active == ZORAN_FREE) - goto strmoff_unlock_and_return; - - res = jpg_qbuf(fh, -1, - (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ? - BUZ_MODE_MOTION_COMPRESS : - BUZ_MODE_MOTION_DECOMPRESS); - if (res) - goto strmoff_unlock_and_return; - break; - default: - dprintk(1, KERN_ERR - "%s: VIDIOC_STREAMOFF - invalid map mode %d\n", - ZR_DEVNAME(zr), fh->map_mode); - res = -EINVAL; - break; - } -strmoff_unlock_and_return: - mutex_unlock(&zr->resource_lock); - - return res; -} - -static int zoran_queryctrl(struct file *file, void *__fh, - struct v4l2_queryctrl *ctrl) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - /* we only support hue/saturation/contrast/brightness */ - if (ctrl->id < V4L2_CID_BRIGHTNESS || - ctrl->id > V4L2_CID_HUE) - return -EINVAL; - - decoder_call(zr, core, queryctrl, ctrl); - - return 0; -} - -static int zoran_g_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - /* we only support hue/saturation/contrast/brightness */ - if (ctrl->id < V4L2_CID_BRIGHTNESS || - ctrl->id > V4L2_CID_HUE) - return -EINVAL; - - mutex_lock(&zr->resource_lock); - decoder_call(zr, core, g_ctrl, ctrl); - mutex_unlock(&zr->resource_lock); - - return 0; -} - -static int zoran_s_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - /* we only support hue/saturation/contrast/brightness */ - if (ctrl->id < V4L2_CID_BRIGHTNESS || - ctrl->id > V4L2_CID_HUE) - return -EINVAL; - - mutex_lock(&zr->resource_lock); - decoder_call(zr, core, s_ctrl, ctrl); - mutex_unlock(&zr->resource_lock); - - return 0; -} - -static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - mutex_lock(&zr->resource_lock); - *std = zr->norm; - mutex_unlock(&zr->resource_lock); - return 0; -} - -static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0; - - mutex_lock(&zr->resource_lock); - res = zoran_set_norm(zr, *std); - if (res) - goto sstd_unlock_and_return; - - res = wait_grab_pending(zr); -sstd_unlock_and_return: - mutex_unlock(&zr->resource_lock); - return res; -} - -static int zoran_enum_input(struct file *file, void *__fh, - struct v4l2_input *inp) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - if (inp->index >= zr->card.inputs) - return -EINVAL; - - strncpy(inp->name, zr->card.input[inp->index].name, - sizeof(inp->name) - 1); - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = V4L2_STD_ALL; - - /* Get status of video decoder */ - mutex_lock(&zr->resource_lock); - decoder_call(zr, video, g_input_status, &inp->status); - mutex_unlock(&zr->resource_lock); - return 0; -} - -static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - mutex_lock(&zr->resource_lock); - *input = zr->input; - mutex_unlock(&zr->resource_lock); - - return 0; -} - -static int zoran_s_input(struct file *file, void *__fh, unsigned int input) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res; - - mutex_lock(&zr->resource_lock); - res = zoran_set_input(zr, input); - if (res) - goto sinput_unlock_and_return; - - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); -sinput_unlock_and_return: - mutex_unlock(&zr->resource_lock); - return res; -} - -static int zoran_enum_output(struct file *file, void *__fh, - struct v4l2_output *outp) -{ - if (outp->index != 0) - return -EINVAL; - - outp->index = 0; - outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; - strncpy(outp->name, "Autodetect", sizeof(outp->name)-1); - - return 0; -} - -static int zoran_g_output(struct file *file, void *__fh, unsigned int *output) -{ - *output = 0; - - return 0; -} - -static int zoran_s_output(struct file *file, void *__fh, unsigned int output) -{ - if (output != 0) - return -EINVAL; - - return 0; -} - -/* cropping (sub-frame capture) */ -static int zoran_cropcap(struct file *file, void *__fh, - struct v4l2_cropcap *cropcap) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int type = cropcap->type, res = 0; - - memset(cropcap, 0, sizeof(*cropcap)); - cropcap->type = type; - - mutex_lock(&zr->resource_lock); - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && - (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - fh->map_mode == ZORAN_MAP_MODE_RAW)) { - dprintk(1, KERN_ERR - "%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n", - ZR_DEVNAME(zr)); - res = -EINVAL; - goto cropcap_unlock_and_return; - } - - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = BUZ_MAX_WIDTH; - cropcap->bounds.height = BUZ_MAX_HEIGHT; - cropcap->defrect.top = cropcap->defrect.left = 0; - cropcap->defrect.width = BUZ_MIN_WIDTH; - cropcap->defrect.height = BUZ_MIN_HEIGHT; -cropcap_unlock_and_return: - mutex_unlock(&zr->resource_lock); - return res; -} - -static int zoran_g_crop(struct file *file, void *__fh, struct v4l2_crop *crop) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int type = crop->type, res = 0; - - memset(crop, 0, sizeof(*crop)); - crop->type = type; - - mutex_lock(&zr->resource_lock); - - if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && - (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - fh->map_mode == ZORAN_MAP_MODE_RAW)) { - dprintk(1, - KERN_ERR - "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n", - ZR_DEVNAME(zr)); - res = -EINVAL; - goto gcrop_unlock_and_return; - } - - crop->c.top = fh->jpg_settings.img_y; - crop->c.left = fh->jpg_settings.img_x; - crop->c.width = fh->jpg_settings.img_width; - crop->c.height = fh->jpg_settings.img_height; - -gcrop_unlock_and_return: - mutex_unlock(&zr->resource_lock); - - return res; -} - -static int zoran_s_crop(struct file *file, void *__fh, struct v4l2_crop *crop) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0; - struct zoran_jpg_settings settings; - - settings = fh->jpg_settings; - - mutex_lock(&zr->resource_lock); - - if (fh->buffers.allocated) { - dprintk(1, KERN_ERR - "%s: VIDIOC_S_CROP - cannot change settings while active\n", - ZR_DEVNAME(zr)); - res = -EBUSY; - goto scrop_unlock_and_return; - } - - if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && - (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - fh->map_mode == ZORAN_MAP_MODE_RAW)) { - dprintk(1, KERN_ERR - "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n", - ZR_DEVNAME(zr)); - res = -EINVAL; - goto scrop_unlock_and_return; - } - - /* move into a form that we understand */ - settings.img_x = crop->c.left; - settings.img_y = crop->c.top; - settings.img_width = crop->c.width; - settings.img_height = crop->c.height; - - /* check validity */ - res = zoran_check_jpg_settings(zr, &settings, 0); - if (res) - goto scrop_unlock_and_return; - - /* accept */ - fh->jpg_settings = settings; - -scrop_unlock_and_return: - mutex_unlock(&zr->resource_lock); - return res; -} - -static int zoran_g_jpegcomp(struct file *file, void *__fh, - struct v4l2_jpegcompression *params) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - memset(params, 0, sizeof(*params)); - - mutex_lock(&zr->resource_lock); - - params->quality = fh->jpg_settings.jpg_comp.quality; - params->APPn = fh->jpg_settings.jpg_comp.APPn; - memcpy(params->APP_data, - fh->jpg_settings.jpg_comp.APP_data, - fh->jpg_settings.jpg_comp.APP_len); - params->APP_len = fh->jpg_settings.jpg_comp.APP_len; - memcpy(params->COM_data, - fh->jpg_settings.jpg_comp.COM_data, - fh->jpg_settings.jpg_comp.COM_len); - params->COM_len = fh->jpg_settings.jpg_comp.COM_len; - params->jpeg_markers = - fh->jpg_settings.jpg_comp.jpeg_markers; - - mutex_unlock(&zr->resource_lock); - - return 0; -} - -static int zoran_s_jpegcomp(struct file *file, void *__fh, - struct v4l2_jpegcompression *params) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0; - struct zoran_jpg_settings settings; - - settings = fh->jpg_settings; - - settings.jpg_comp = *params; - - mutex_lock(&zr->resource_lock); - - if (fh->buffers.active != ZORAN_FREE) { - dprintk(1, KERN_WARNING - "%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n", - ZR_DEVNAME(zr)); - res = -EBUSY; - goto sjpegc_unlock_and_return; - } - - res = zoran_check_jpg_settings(zr, &settings, 0); - if (res) - goto sjpegc_unlock_and_return; - if (!fh->buffers.allocated) - fh->buffers.buffer_size = - zoran_v4l2_calc_bufsize(&fh->jpg_settings); - fh->jpg_settings.jpg_comp = *params = settings.jpg_comp; -sjpegc_unlock_and_return: - mutex_unlock(&zr->resource_lock); - - return res; -} - -static unsigned int -zoran_poll (struct file *file, - poll_table *wait) -{ - struct zoran_fh *fh = file->private_data; - struct zoran *zr = fh->zr; - int res = 0, frame; - unsigned long flags; - - /* we should check whether buffers are ready to be synced on - * (w/o waits - O_NONBLOCK) here - * if ready for read (sync), return POLLIN|POLLRDNORM, - * if ready for write (sync), return POLLOUT|POLLWRNORM, - * if error, return POLLERR, - * if no buffers queued or so, return POLLNVAL - */ - - mutex_lock(&zr->resource_lock); - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: - poll_wait(file, &zr->v4l_capq, wait); - frame = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME]; - - spin_lock_irqsave(&zr->spinlock, flags); - dprintk(3, - KERN_DEBUG - "%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n", - ZR_DEVNAME(zr), __func__, - "FAL"[fh->buffers.active], zr->v4l_sync_tail, - "UPMD"[zr->v4l_buffers.buffer[frame].state], - zr->v4l_pend_tail, zr->v4l_pend_head); - /* Process is the one capturing? */ - if (fh->buffers.active != ZORAN_FREE && - /* Buffer ready to DQBUF? */ - zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE) - res = POLLIN | POLLRDNORM; - spin_unlock_irqrestore(&zr->spinlock, flags); - - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - poll_wait(file, &zr->jpg_capq, wait); - frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; - - spin_lock_irqsave(&zr->spinlock, flags); - dprintk(3, - KERN_DEBUG - "%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n", - ZR_DEVNAME(zr), __func__, - "FAL"[fh->buffers.active], zr->jpg_que_tail, - "UPMD"[zr->jpg_buffers.buffer[frame].state], - zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head); - if (fh->buffers.active != ZORAN_FREE && - zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) { - if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) - res = POLLIN | POLLRDNORM; - else - res = POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&zr->spinlock, flags); - - break; - - default: - dprintk(1, - KERN_ERR - "%s: %s - internal error, unknown map_mode=%d\n", - ZR_DEVNAME(zr), __func__, fh->map_mode); - res = POLLNVAL; - } - - mutex_unlock(&zr->resource_lock); - - return res; -} - - -/* - * This maps the buffers to user space. - * - * Depending on the state of fh->map_mode - * the V4L or the MJPEG buffers are mapped - * per buffer or all together - * - * Note that we need to connect to some - * unmap signal event to unmap the de-allocate - * the buffer accordingly (zoran_vm_close()) - */ - -static void -zoran_vm_open (struct vm_area_struct *vma) -{ - struct zoran_mapping *map = vma->vm_private_data; - - map->count++; -} - -static void -zoran_vm_close (struct vm_area_struct *vma) -{ - struct zoran_mapping *map = vma->vm_private_data; - struct zoran_fh *fh = map->file->private_data; - struct zoran *zr = fh->zr; - int i; - - if (--map->count > 0) - return; - - dprintk(3, KERN_INFO "%s: %s - munmap(%s)\n", ZR_DEVNAME(zr), - __func__, mode_name(fh->map_mode)); - - for (i = 0; i < fh->buffers.num_buffers; i++) { - if (fh->buffers.buffer[i].map == map) - fh->buffers.buffer[i].map = NULL; - } - kfree(map); - - /* Any buffers still mapped? */ - for (i = 0; i < fh->buffers.num_buffers; i++) - if (fh->buffers.buffer[i].map) - return; - - dprintk(3, KERN_INFO "%s: %s - free %s buffers\n", ZR_DEVNAME(zr), - __func__, mode_name(fh->map_mode)); - - mutex_lock(&zr->resource_lock); - - if (fh->map_mode == ZORAN_MAP_MODE_RAW) { - if (fh->buffers.active != ZORAN_FREE) { - unsigned long flags; - - spin_lock_irqsave(&zr->spinlock, flags); - zr36057_set_memgrab(zr, 0); - zr->v4l_buffers.allocated = 0; - zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE; - spin_unlock_irqrestore(&zr->spinlock, flags); - } - v4l_fbuffer_free(fh); - } else { - if (fh->buffers.active != ZORAN_FREE) { - jpg_qbuf(fh, -1, zr->codec_mode); - zr->jpg_buffers.allocated = 0; - zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE; - } - jpg_fbuffer_free(fh); - } - - mutex_unlock(&zr->resource_lock); -} - -static const struct vm_operations_struct zoran_vm_ops = { - .open = zoran_vm_open, - .close = zoran_vm_close, -}; - -static int -zoran_mmap (struct file *file, - struct vm_area_struct *vma) -{ - struct zoran_fh *fh = file->private_data; - struct zoran *zr = fh->zr; - unsigned long size = (vma->vm_end - vma->vm_start); - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int i, j; - unsigned long page, start = vma->vm_start, todo, pos, fraglen; - int first, last; - struct zoran_mapping *map; - int res = 0; - - dprintk(3, - KERN_INFO "%s: %s(%s) of 0x%08lx-0x%08lx (size=%lu)\n", - ZR_DEVNAME(zr), __func__, - mode_name(fh->map_mode), vma->vm_start, vma->vm_end, size); - - if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) || - !(vma->vm_flags & VM_WRITE)) { - dprintk(1, - KERN_ERR - "%s: %s - no MAP_SHARED/PROT_{READ,WRITE} given\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - mutex_lock(&zr->resource_lock); - - if (!fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s(%s) - buffers not yet allocated\n", - ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode)); - res = -ENOMEM; - goto mmap_unlock_and_return; - } - - first = offset / fh->buffers.buffer_size; - last = first - 1 + size / fh->buffers.buffer_size; - if (offset % fh->buffers.buffer_size != 0 || - size % fh->buffers.buffer_size != 0 || first < 0 || - last < 0 || first >= fh->buffers.num_buffers || - last >= fh->buffers.buffer_size) { - dprintk(1, - KERN_ERR - "%s: %s(%s) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n", - ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), offset, size, - fh->buffers.buffer_size, - fh->buffers.num_buffers); - res = -EINVAL; - goto mmap_unlock_and_return; - } - - /* Check if any buffers are already mapped */ - for (i = first; i <= last; i++) { - if (fh->buffers.buffer[i].map) { - dprintk(1, - KERN_ERR - "%s: %s(%s) - buffer %d already mapped\n", - ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), i); - res = -EBUSY; - goto mmap_unlock_and_return; - } - } - - /* map these buffers */ - map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL); - if (!map) { - res = -ENOMEM; - goto mmap_unlock_and_return; - } - map->file = file; - map->count = 1; - - vma->vm_ops = &zoran_vm_ops; - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_private_data = map; - - if (fh->map_mode == ZORAN_MAP_MODE_RAW) { - for (i = first; i <= last; i++) { - todo = size; - if (todo > fh->buffers.buffer_size) - todo = fh->buffers.buffer_size; - page = fh->buffers.buffer[i].v4l.fbuffer_phys; - if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, - todo, PAGE_SHARED)) { - dprintk(1, - KERN_ERR - "%s: %s(V4L) - remap_pfn_range failed\n", - ZR_DEVNAME(zr), __func__); - res = -EAGAIN; - goto mmap_unlock_and_return; - } - size -= todo; - start += todo; - fh->buffers.buffer[i].map = map; - if (size == 0) - break; - } - } else { - for (i = first; i <= last; i++) { - for (j = 0; - j < fh->buffers.buffer_size / PAGE_SIZE; - j++) { - fraglen = - (le32_to_cpu(fh->buffers.buffer[i].jpg. - frag_tab[2 * j + 1]) & ~1) << 1; - todo = size; - if (todo > fraglen) - todo = fraglen; - pos = - le32_to_cpu(fh->buffers. - buffer[i].jpg.frag_tab[2 * j]); - /* should just be pos on i386 */ - page = virt_to_phys(bus_to_virt(pos)) - >> PAGE_SHIFT; - if (remap_pfn_range(vma, start, page, - todo, PAGE_SHARED)) { - dprintk(1, - KERN_ERR - "%s: %s(V4L) - remap_pfn_range failed\n", - ZR_DEVNAME(zr), __func__); - res = -EAGAIN; - goto mmap_unlock_and_return; - } - size -= todo; - start += todo; - if (size == 0) - break; - if (le32_to_cpu(fh->buffers.buffer[i].jpg. - frag_tab[2 * j + 1]) & 1) - break; /* was last fragment */ - } - fh->buffers.buffer[i].map = map; - if (size == 0) - break; - - } - } - -mmap_unlock_and_return: - mutex_unlock(&zr->resource_lock); - - return res; -} - -static const struct v4l2_ioctl_ops zoran_ioctl_ops = { - .vidioc_querycap = zoran_querycap, - .vidioc_cropcap = zoran_cropcap, - .vidioc_s_crop = zoran_s_crop, - .vidioc_g_crop = zoran_g_crop, - .vidioc_enum_input = zoran_enum_input, - .vidioc_g_input = zoran_g_input, - .vidioc_s_input = zoran_s_input, - .vidioc_enum_output = zoran_enum_output, - .vidioc_g_output = zoran_g_output, - .vidioc_s_output = zoran_s_output, - .vidioc_g_fbuf = zoran_g_fbuf, - .vidioc_s_fbuf = zoran_s_fbuf, - .vidioc_g_std = zoran_g_std, - .vidioc_s_std = zoran_s_std, - .vidioc_g_jpegcomp = zoran_g_jpegcomp, - .vidioc_s_jpegcomp = zoran_s_jpegcomp, - .vidioc_overlay = zoran_overlay, - .vidioc_reqbufs = zoran_reqbufs, - .vidioc_querybuf = zoran_querybuf, - .vidioc_qbuf = zoran_qbuf, - .vidioc_dqbuf = zoran_dqbuf, - .vidioc_streamon = zoran_streamon, - .vidioc_streamoff = zoran_streamoff, - .vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = zoran_enum_fmt_vid_out, - .vidioc_enum_fmt_vid_overlay = zoran_enum_fmt_vid_overlay, - .vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap, - .vidioc_g_fmt_vid_out = zoran_g_fmt_vid_out, - .vidioc_g_fmt_vid_overlay = zoran_g_fmt_vid_overlay, - .vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap, - .vidioc_s_fmt_vid_out = zoran_s_fmt_vid_out, - .vidioc_s_fmt_vid_overlay = zoran_s_fmt_vid_overlay, - .vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap, - .vidioc_try_fmt_vid_out = zoran_try_fmt_vid_out, - .vidioc_try_fmt_vid_overlay = zoran_try_fmt_vid_overlay, - .vidioc_queryctrl = zoran_queryctrl, - .vidioc_s_ctrl = zoran_s_ctrl, - .vidioc_g_ctrl = zoran_g_ctrl, -}; - -/* please use zr->resource_lock consistently and kill this wrapper */ -static long zoran_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct zoran_fh *fh = file->private_data; - struct zoran *zr = fh->zr; - int ret; - - mutex_lock(&zr->other_lock); - ret = video_ioctl2(file, cmd, arg); - mutex_unlock(&zr->other_lock); - - return ret; -} - -static const struct v4l2_file_operations zoran_fops = { - .owner = THIS_MODULE, - .open = zoran_open, - .release = zoran_close, - .unlocked_ioctl = zoran_ioctl, - .read = zoran_read, - .write = zoran_write, - .mmap = zoran_mmap, - .poll = zoran_poll, -}; - -struct video_device zoran_template __devinitdata = { - .name = ZORAN_NAME, - .fops = &zoran_fops, - .ioctl_ops = &zoran_ioctl_ops, - .release = &zoran_vdev_release, - .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, -}; - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,405 +0,0 @@ -/* - * zoran - Iomega Buz driver - * - * Copyright (C) 1999 Rainer Johanni - * - * based on - * - * zoran.0.0.3 Copyright (C) 1998 Dave Perks - * - * and - * - * bttv - Bt848 frame grabber driver - * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - * & Marcus Metzler (mocm@thp.uni-koeln.de) - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _BUZ_H_ -#define _BUZ_H_ - -#include - -struct zoran_sync { - unsigned long frame; /* number of buffer that has been free'd */ - unsigned long length; /* number of code bytes in buffer (capture only) */ - unsigned long seq; /* frame sequence number */ - struct timeval timestamp; /* timestamp */ -}; - - -#define MAJOR_VERSION 0 /* driver major version */ -#define MINOR_VERSION 10 /* driver minor version */ -#define RELEASE_VERSION 0 /* release version */ - -#define ZORAN_NAME "ZORAN" /* name of the device */ - -#define ZR_DEVNAME(zr) ((zr)->name) - -#define BUZ_MAX_WIDTH (zr->timing->Wa) -#define BUZ_MAX_HEIGHT (zr->timing->Ha) -#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ -#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ - -#define BUZ_NUM_STAT_COM 4 -#define BUZ_MASK_STAT_COM 3 - -#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ -#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ - -#define BUZ_MAX_INPUT 16 - -#if VIDEO_MAX_FRAME <= 32 -# define V4L_MAX_FRAME 32 -#elif VIDEO_MAX_FRAME <= 64 -# define V4L_MAX_FRAME 64 -#else -# error "Too many video frame buffers to handle" -#endif -#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) - -#define MAX_FRAME (BUZ_MAX_FRAME > VIDEO_MAX_FRAME ? BUZ_MAX_FRAME : VIDEO_MAX_FRAME) - -#include "zr36057.h" - -enum card_type { - UNKNOWN = -1, - - /* Pinnacle/Miro */ - DC10_old, /* DC30 like */ - DC10_new, /* DC10plus like */ - DC10plus, - DC30, - DC30plus, - - /* Linux Media Labs */ - LML33, - LML33R10, - - /* Iomega */ - BUZ, - - /* AverMedia */ - AVS6EYES, - - /* total number of cards */ - NUM_CARDS -}; - -enum zoran_codec_mode { - BUZ_MODE_IDLE, /* nothing going on */ - BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ - BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ - BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ - BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ -}; - -enum zoran_buffer_state { - BUZ_STATE_USER, /* buffer is owned by application */ - BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ - BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ - BUZ_STATE_DONE /* buffer is ready to return to application */ -}; - -enum zoran_map_mode { - ZORAN_MAP_MODE_RAW, - ZORAN_MAP_MODE_JPG_REC, -#define ZORAN_MAP_MODE_JPG ZORAN_MAP_MODE_JPG_REC - ZORAN_MAP_MODE_JPG_PLAY, -}; - -enum gpio_type { - ZR_GPIO_JPEG_SLEEP = 0, - ZR_GPIO_JPEG_RESET, - ZR_GPIO_JPEG_FRAME, - ZR_GPIO_VID_DIR, - ZR_GPIO_VID_EN, - ZR_GPIO_VID_RESET, - ZR_GPIO_CLK_SEL1, - ZR_GPIO_CLK_SEL2, - ZR_GPIO_MAX, -}; - -enum gpcs_type { - GPCS_JPEG_RESET = 0, - GPCS_JPEG_START, - GPCS_MAX, -}; - -struct zoran_format { - char *name; - __u32 fourcc; - int colorspace; - int depth; - __u32 flags; - __u32 vfespfr; -}; -/* flags */ -#define ZORAN_FORMAT_COMPRESSED 1<<0 -#define ZORAN_FORMAT_OVERLAY 1<<1 -#define ZORAN_FORMAT_CAPTURE 1<<2 -#define ZORAN_FORMAT_PLAYBACK 1<<3 - -/* overlay-settings */ -struct zoran_overlay_settings { - int is_set; - int x, y, width, height; /* position */ - int clipcount; /* position and number of clips */ - const struct zoran_format *format; /* overlay format */ -}; - -/* v4l-capture settings */ -struct zoran_v4l_settings { - int width, height, bytesperline; /* capture size */ - const struct zoran_format *format; /* capture format */ -}; - -/* jpg-capture/-playback settings */ -struct zoran_jpg_settings { - int decimation; /* this bit is used to set everything to default */ - int HorDcm, VerDcm, TmpDcm; /* capture decimation settings (TmpDcm=1 means both fields) */ - int field_per_buff, odd_even; /* field-settings (odd_even=1 (+TmpDcm=1) means top-field-first) */ - int img_x, img_y, img_width, img_height; /* crop settings (subframe capture) */ - struct v4l2_jpegcompression jpg_comp; /* JPEG-specific capture settings */ -}; - -struct zoran_mapping { - struct file *file; - int count; -}; - -struct zoran_buffer { - struct zoran_mapping *map; - enum zoran_buffer_state state; /* state: unused/pending/dma/done */ - struct zoran_sync bs; /* DONE: info to return to application */ - union { - struct { - __le32 *frag_tab; /* addresses of frag table */ - u32 frag_tab_bus; /* same value cached to save time in ISR */ - } jpg; - struct { - char *fbuffer; /* virtual address of frame buffer */ - unsigned long fbuffer_phys;/* physical address of frame buffer */ - unsigned long fbuffer_bus;/* bus address of frame buffer */ - } v4l; - }; -}; - -enum zoran_lock_activity { - ZORAN_FREE, /* free for use */ - ZORAN_ACTIVE, /* active but unlocked */ - ZORAN_LOCKED, /* locked */ -}; - -/* buffer collections */ -struct zoran_buffer_col { - enum zoran_lock_activity active; /* feature currently in use? */ - unsigned int num_buffers, buffer_size; - struct zoran_buffer buffer[MAX_FRAME]; /* buffers */ - u8 allocated; /* Flag if buffers are allocated */ - u8 need_contiguous; /* Flag if contiguous buffers are needed */ - /* only applies to jpg buffers, raw buffers are always contiguous */ -}; - -struct zoran; - -/* zoran_fh contains per-open() settings */ -struct zoran_fh { - struct zoran *zr; - - enum zoran_map_mode map_mode; /* Flag which bufferset will map by next mmap() */ - - struct zoran_overlay_settings overlay_settings; - u32 *overlay_mask; /* overlay mask */ - enum zoran_lock_activity overlay_active;/* feature currently in use? */ - - struct zoran_buffer_col buffers; /* buffers' info */ - - struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */ - struct zoran_jpg_settings jpg_settings; /* structure with a lot of things to play with */ -}; - -struct card_info { - enum card_type type; - char name[32]; - const char *i2c_decoder; /* i2c decoder device */ - const unsigned short *addrs_decoder; - const char *i2c_encoder; /* i2c encoder device */ - const unsigned short *addrs_encoder; - u16 video_vfe, video_codec; /* videocodec types */ - u16 audio_chip; /* audio type */ - - int inputs; /* number of video inputs */ - struct input { - int muxsel; - char name[32]; - } input[BUZ_MAX_INPUT]; - - v4l2_std_id norms; - struct tvnorm *tvn[3]; /* supported TV norms */ - - u32 jpeg_int; /* JPEG interrupt */ - u32 vsync_int; /* VSYNC interrupt */ - s8 gpio[ZR_GPIO_MAX]; - u8 gpcs[GPCS_MAX]; - - struct vfe_polarity vfe_pol; - u8 gpio_pol[ZR_GPIO_MAX]; - - /* is the /GWS line conected? */ - u8 gws_not_connected; - - /* avs6eyes mux setting */ - u8 input_mux; - - void (*init) (struct zoran * zr); -}; - -struct zoran { - struct v4l2_device v4l2_dev; - struct video_device *video_dev; - - struct i2c_adapter i2c_adapter; /* */ - struct i2c_algo_bit_data i2c_algo; /* */ - u32 i2cbr; - - struct v4l2_subdev *decoder; /* video decoder sub-device */ - struct v4l2_subdev *encoder; /* video encoder sub-device */ - - struct videocodec *codec; /* video codec */ - struct videocodec *vfe; /* video front end */ - - struct mutex resource_lock; /* prevent evil stuff */ - struct mutex other_lock; /* please merge with above */ - - u8 initialized; /* flag if zoran has been correctly initialized */ - int user; /* number of current users */ - struct card_info card; - struct tvnorm *timing; - - unsigned short id; /* number of this device */ - char name[32]; /* name of this device */ - struct pci_dev *pci_dev; /* PCI device */ - unsigned char revision; /* revision of zr36057 */ - unsigned char __iomem *zr36057_mem;/* pointer to mapped IO memory */ - - spinlock_t spinlock; /* Spinlock */ - - /* Video for Linux parameters */ - int input; /* card's norm and input */ - v4l2_std_id norm; - - /* Current buffer params */ - void *vbuf_base; - int vbuf_height, vbuf_width; - int vbuf_depth; - int vbuf_bytesperline; - - struct zoran_overlay_settings overlay_settings; - u32 *overlay_mask; /* overlay mask */ - enum zoran_lock_activity overlay_active; /* feature currently in use? */ - - wait_queue_head_t v4l_capq; - - int v4l_overlay_active; /* Overlay grab is activated */ - int v4l_memgrab_active; /* Memory grab is activated */ - - int v4l_grab_frame; /* Frame number being currently grabbed */ -#define NO_GRAB_ACTIVE (-1) - unsigned long v4l_grab_seq; /* Number of frames grabbed */ - struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */ - - /* V4L grab queue of frames pending */ - unsigned long v4l_pend_head; - unsigned long v4l_pend_tail; - unsigned long v4l_sync_tail; - int v4l_pend[V4L_MAX_FRAME]; - struct zoran_buffer_col v4l_buffers; /* V4L buffers' info */ - - /* Buz MJPEG parameters */ - enum zoran_codec_mode codec_mode; /* status of codec */ - struct zoran_jpg_settings jpg_settings; /* structure with a lot of things to play with */ - - wait_queue_head_t jpg_capq; /* wait here for grab to finish */ - - /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ - /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ - /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ - unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ - unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ - unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ - unsigned long jpg_que_tail; /* Index of last buffer in queue */ - unsigned long jpg_seq_num; /* count of frames since grab/play started */ - unsigned long jpg_err_seq; /* last seq_num before error */ - unsigned long jpg_err_shift; - unsigned long jpg_queued_num; /* count of frames queued since grab/play started */ - - /* zr36057's code buffer table */ - __le32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ - - /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ - int jpg_pend[BUZ_MAX_FRAME]; - - /* array indexed by frame number */ - struct zoran_buffer_col jpg_buffers; /* MJPEG buffers' info */ - - /* Additional stuff for testing */ -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *zoran_proc; -#else - void *zoran_proc; -#endif - int testing; - int jpeg_error; - int intr_counter_GIRQ1; - int intr_counter_GIRQ0; - int intr_counter_CodRepIRQ; - int intr_counter_JPEGRepIRQ; - int field_counter; - int IRQ1_in; - int IRQ1_out; - int JPEG_in; - int JPEG_out; - int JPEG_0; - int JPEG_1; - int END_event_missed; - int JPEG_missed; - int JPEG_error; - int num_errors; - int JPEG_max_missed; - int JPEG_min_missed; - - u32 last_isr; - unsigned long frame_num; - - wait_queue_head_t test_q; -}; - -static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct zoran, v4l2_dev); -} - -/* There was something called _ALPHA_BUZ that used the PCI address instead of - * the kernel iomapped address for btread/btwrite. */ -#define btwrite(dat,adr) writel((dat), zr->zr36057_mem+(adr)) -#define btread(adr) readl(zr->zr36057_mem+(adr)) - -#define btand(dat,adr) btwrite((dat) & btread(adr), adr) -#define btor(dat,adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_procfs.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_procfs.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_procfs.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_procfs.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles the procFS entries (/proc/ZORAN[%d]) - * - * Copyright (C) 2000 Serguei Miridonov - * - * Currently maintained by: - * Ronald Bultje - * Laurent Pinchart - * Mailinglist - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "videocodec.h" -#include "zoran.h" -#include "zoran_procfs.h" -#include "zoran_card.h" - -#ifdef CONFIG_PROC_FS -struct procfs_params_zr36067 { - char *name; - short reg; - u32 mask; - short bit; -}; - -static const struct procfs_params_zr36067 zr67[] = { - {"HSPol", 0x000, 1, 30}, - {"HStart", 0x000, 0x3ff, 10}, - {"HEnd", 0x000, 0x3ff, 0}, - - {"VSPol", 0x004, 1, 30}, - {"VStart", 0x004, 0x3ff, 10}, - {"VEnd", 0x004, 0x3ff, 0}, - - {"ExtFl", 0x008, 1, 26}, - {"TopField", 0x008, 1, 25}, - {"VCLKPol", 0x008, 1, 24}, - {"DupFld", 0x008, 1, 20}, - {"LittleEndian", 0x008, 1, 0}, - - {"HsyncStart", 0x10c, 0xffff, 16}, - {"LineTot", 0x10c, 0xffff, 0}, - - {"NAX", 0x110, 0xffff, 16}, - {"PAX", 0x110, 0xffff, 0}, - - {"NAY", 0x114, 0xffff, 16}, - {"PAY", 0x114, 0xffff, 0}, - - /* {"",,,}, */ - - {NULL, 0, 0, 0}, -}; - -static void -setparam (struct zoran *zr, - char *name, - char *sval) -{ - int i = 0, reg0, reg, val; - - while (zr67[i].name != NULL) { - if (!strncmp(name, zr67[i].name, strlen(zr67[i].name))) { - reg = reg0 = btread(zr67[i].reg); - reg &= ~(zr67[i].mask << zr67[i].bit); - if (!isdigit(sval[0])) - break; - val = simple_strtoul(sval, NULL, 0); - if ((val & ~zr67[i].mask)) - break; - reg |= (val & zr67[i].mask) << zr67[i].bit; - dprintk(4, - KERN_INFO - "%s: setparam: setting ZR36067 register 0x%03x: 0x%08x=>0x%08x %s=%d\n", - ZR_DEVNAME(zr), zr67[i].reg, reg0, reg, - zr67[i].name, val); - btwrite(reg, zr67[i].reg); - break; - } - i++; - } -} - -static int zoran_show(struct seq_file *p, void *v) -{ - struct zoran *zr = p->private; - int i; - - seq_printf(p, "ZR36067 registers:\n"); - for (i = 0; i < 0x130; i += 16) - seq_printf(p, "%03X %08X %08X %08X %08X \n", i, - btread(i), btread(i+4), btread(i+8), btread(i+12)); - return 0; -} - -static int zoran_open(struct inode *inode, struct file *file) -{ - struct zoran *data = PDE(inode)->data; - return single_open(file, zoran_show, data); -} - -static ssize_t zoran_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - struct zoran *zr = PDE(file->f_path.dentry->d_inode)->data; - char *string, *sp; - char *line, *ldelim, *varname, *svar, *tdelim; - - if (count > 32768) /* Stupidity filter */ - return -EINVAL; - - string = sp = vmalloc(count + 1); - if (!string) { - dprintk(1, - KERN_ERR - "%s: write_proc: can not allocate memory\n", - ZR_DEVNAME(zr)); - return -ENOMEM; - } - if (copy_from_user(string, buffer, count)) { - vfree (string); - return -EFAULT; - } - string[count] = 0; - dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n", - ZR_DEVNAME(zr), file->f_path.dentry->d_name.name, count, zr); - ldelim = " \t\n"; - tdelim = "="; - line = strpbrk(sp, ldelim); - while (line) { - *line = 0; - svar = strpbrk(sp, tdelim); - if (svar) { - *svar = 0; - varname = sp; - svar++; - setparam(zr, varname, svar); - } - sp = line + 1; - line = strpbrk(sp, ldelim); - } - vfree(string); - - return count; -} - -static const struct file_operations zoran_operations = { - .owner = THIS_MODULE, - .open = zoran_open, - .read = seq_read, - .write = zoran_write, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -int -zoran_proc_init (struct zoran *zr) -{ -#ifdef CONFIG_PROC_FS - char name[8]; - - snprintf(name, 7, "zoran%d", zr->id); - zr->zoran_proc = proc_create_data(name, 0, NULL, &zoran_operations, zr); - if (zr->zoran_proc != NULL) { - dprintk(2, - KERN_INFO - "%s: procfs entry /proc/%s allocated. data=%p\n", - ZR_DEVNAME(zr), name, zr->zoran_proc->data); - } else { - dprintk(1, KERN_ERR "%s: Unable to initialise /proc/%s\n", - ZR_DEVNAME(zr), name); - return 1; - } -#endif - return 0; -} - -void -zoran_proc_cleanup (struct zoran *zr) -{ -#ifdef CONFIG_PROC_FS - char name[8]; - - snprintf(name, 7, "zoran%d", zr->id); - if (zr->zoran_proc) - remove_proc_entry(name, NULL); - zr->zoran_proc = NULL; -#endif -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_procfs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_procfs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_procfs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zoran_procfs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles card-specific data and detection - * - * Copyright (C) 2000 Serguei Miridonov - * - * Currently maintained by: - * Ronald Bultje - * Laurent Pinchart - * Mailinglist - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ZORAN_PROCFS_H__ -#define __ZORAN_PROCFS_H__ - -extern int zoran_proc_init(struct zoran *zr); -extern void zoran_proc_cleanup(struct zoran *zr); - -#endif /* __ZORAN_PROCFS_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36016.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36016.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36016.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36016.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,524 +0,0 @@ -/* - * Zoran ZR36016 basic configuration functions - * - * Copyright (C) 2001 Wolfgang Scherr - * - * $Id: zr36016.c,v 1.1.2.14 2003/08/20 19:46:55 rbultje Exp $ - * - * ------------------------------------------------------------------------ - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ------------------------------------------------------------------------ - */ - -#define ZR016_VERSION "v0.7" - -#include -#include -#include -#include - -#include -#include - -/* I/O commands, error codes */ -#include - -/* v4l API */ - -/* headerfile of this module */ -#include"zr36016.h" - -/* codec io API */ -#include"videocodec.h" - -/* it doesn't make sense to have more than 20 or so, - just to prevent some unwanted loops */ -#define MAX_CODECS 20 - -/* amount of chips attached via this driver */ -static int zr36016_codecs; - -/* debugging is available via module parameter */ -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) - -/* ========================================================================= - Local hardware I/O functions: - - read/write via codec layer (registers are located in the master device) - ========================================================================= */ - -/* read and write functions */ -static u8 -zr36016_read (struct zr36016 *ptr, - u16 reg) -{ - u8 value = 0; - - // just in case something is wrong... - if (ptr->codec->master_data->readreg) - value = - (ptr->codec->master_data-> - readreg(ptr->codec, reg)) & 0xFF; - else - dprintk(1, - KERN_ERR "%s: invalid I/O setup, nothing read!\n", - ptr->name); - - dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, - value); - - return value; -} - -static void -zr36016_write (struct zr36016 *ptr, - u16 reg, - u8 value) -{ - dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, - reg); - - // just in case something is wrong... - if (ptr->codec->master_data->writereg) { - ptr->codec->master_data->writereg(ptr->codec, reg, value); - } else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing written!\n", - ptr->name); -} - -/* indirect read and write functions */ -/* the 016 supports auto-addr-increment, but - * writing it all time cost not much and is safer... */ -static u8 -zr36016_readi (struct zr36016 *ptr, - u16 reg) -{ - u8 value = 0; - - // just in case something is wrong... - if ((ptr->codec->master_data->writereg) && - (ptr->codec->master_data->readreg)) { - ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR - value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; // DATA - } else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing read (i)!\n", - ptr->name); - - dprintk(4, "%s: reading indirect from 0x%04x: %02x\n", ptr->name, - reg, value); - return value; -} - -static void -zr36016_writei (struct zr36016 *ptr, - u16 reg, - u8 value) -{ - dprintk(4, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name, - value, reg); - - // just in case something is wrong... - if (ptr->codec->master_data->writereg) { - ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR - ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); // DATA - } else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing written (i)!\n", - ptr->name); -} - -/* ========================================================================= - Local helper function: - - version read - ========================================================================= */ - -/* version kept in datastructure */ -static u8 -zr36016_read_version (struct zr36016 *ptr) -{ - ptr->version = zr36016_read(ptr, 0) >> 4; - return ptr->version; -} - -/* ========================================================================= - Local helper function: - - basic test of "connectivity", writes/reads to/from PAX-Lo register - ========================================================================= */ - -static int -zr36016_basic_test (struct zr36016 *ptr) -{ - if (debug) { - int i; - zr36016_writei(ptr, ZR016I_PAX_LO, 0x55); - dprintk(1, KERN_INFO "%s: registers: ", ptr->name); - for (i = 0; i <= 0x0b; i++) - dprintk(1, "%02x ", zr36016_readi(ptr, i)); - dprintk(1, "\n"); - } - // for testing just write 0, then the default value to a register and read - // it back in both cases - zr36016_writei(ptr, ZR016I_PAX_LO, 0x00); - if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to vfe processor!\n", - ptr->name); - return -ENXIO; - } - zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0); - if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to vfe processor!\n", - ptr->name); - return -ENXIO; - } - // we allow version numbers from 0-3, should be enough, though - zr36016_read_version(ptr); - if (ptr->version & 0x0c) { - dprintk(1, - KERN_ERR - "%s: attach failed, suspicious version %d found...\n", - ptr->name, ptr->version); - return -ENXIO; - } - - return 0; /* looks good! */ -} - -/* ========================================================================= - Local helper function: - - simple loop for pushing the init datasets - NO USE -- - ========================================================================= */ - -#if 0 -static int zr36016_pushit (struct zr36016 *ptr, - u16 startreg, - u16 len, - const char *data) -{ - int i=0; - - dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", - ptr->name, startreg,len); - while (imode == CODEC_DO_COMPRESSION ? - ZR016_COMPRESSION : ZR016_EXPANSION)); - - // misc setup - zr36016_writei(ptr, ZR016I_SETUP1, - (ptr->xdec ? (ZR016_HRFL | ZR016_HORZ) : 0) | - (ptr->ydec ? ZR016_VERT : 0) | ZR016_CNTI); - zr36016_writei(ptr, ZR016I_SETUP2, ZR016_CCIR); - - // Window setup - // (no extra offset for now, norm defines offset, default width height) - zr36016_writei(ptr, ZR016I_PAX_HI, ptr->width >> 8); - zr36016_writei(ptr, ZR016I_PAX_LO, ptr->width & 0xFF); - zr36016_writei(ptr, ZR016I_PAY_HI, ptr->height >> 8); - zr36016_writei(ptr, ZR016I_PAY_LO, ptr->height & 0xFF); - zr36016_writei(ptr, ZR016I_NAX_HI, ptr->xoff >> 8); - zr36016_writei(ptr, ZR016I_NAX_LO, ptr->xoff & 0xFF); - zr36016_writei(ptr, ZR016I_NAY_HI, ptr->yoff >> 8); - zr36016_writei(ptr, ZR016I_NAY_LO, ptr->yoff & 0xFF); - - /* shall we continue now, please? */ - zr36016_write(ptr, ZR016_GOSTOP, 1); -} - -/* ========================================================================= - CODEC API FUNCTIONS - - this functions are accessed by the master via the API structure - ========================================================================= */ - -/* set compression/expansion mode and launches codec - - this should be the last call from the master before starting processing */ -static int -zr36016_set_mode (struct videocodec *codec, - int mode) -{ - struct zr36016 *ptr = (struct zr36016 *) codec->data; - - dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); - - if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) - return -EINVAL; - - ptr->mode = mode; - zr36016_init(ptr); - - return 0; -} - -/* set picture size */ -static int -zr36016_set_video (struct videocodec *codec, - struct tvnorm *norm, - struct vfe_settings *cap, - struct vfe_polarity *pol) -{ - struct zr36016 *ptr = (struct zr36016 *) codec->data; - - dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n", - ptr->name, norm->HStart, norm->VStart, - cap->x, cap->y, cap->width, cap->height, - cap->decimation); - - /* if () return -EINVAL; - * trust the master driver that it knows what it does - so - * we allow invalid startx/y for now ... */ - ptr->width = cap->width; - ptr->height = cap->height; - /* (Ronald) This is ugly. zoran_device.c, line 387 - * already mentions what happens if HStart is even - * (blue faces, etc., cr/cb inversed). There's probably - * some good reason why HStart is 0 instead of 1, so I'm - * leaving it to this for now, but really... This can be - * done a lot simpler */ - ptr->xoff = (norm->HStart ? norm->HStart : 1) + cap->x; - /* Something to note here (I don't understand it), setting - * VStart too high will cause the codec to 'not work'. I - * really don't get it. values of 16 (VStart) already break - * it here. Just '0' seems to work. More testing needed! */ - ptr->yoff = norm->VStart + cap->y; - /* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */ - ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1; - ptr->ydec = (((cap->decimation >> 8) & 0xff) == 1) ? 0 : 1; - - return 0; -} - -/* additional control functions */ -static int -zr36016_control (struct videocodec *codec, - int type, - int size, - void *data) -{ - struct zr36016 *ptr = (struct zr36016 *) codec->data; - int *ival = (int *) data; - - dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, - size); - - switch (type) { - case CODEC_G_STATUS: /* get last status - we don't know it ... */ - if (size != sizeof(int)) - return -EFAULT; - *ival = 0; - break; - - case CODEC_G_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - *ival = 0; - break; - - case CODEC_S_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - if (*ival != 0) - return -EINVAL; - /* not needed, do nothing */ - return 0; - - case CODEC_G_VFE: - case CODEC_S_VFE: - return 0; - - case CODEC_S_MMAP: - /* not available, give an error */ - return -ENXIO; - - default: - return -EINVAL; - } - - return size; -} - -/* ========================================================================= - Exit and unregister function: - - Deinitializes Zoran's JPEG processor - ========================================================================= */ - -static int -zr36016_unset (struct videocodec *codec) -{ - struct zr36016 *ptr = codec->data; - - if (ptr) { - /* do wee need some codec deinit here, too ???? */ - - dprintk(1, "%s: finished codec #%d\n", ptr->name, - ptr->num); - kfree(ptr); - codec->data = NULL; - - zr36016_codecs--; - return 0; - } - - return -EFAULT; -} - -/* ========================================================================= - Setup and registry function: - - Initializes Zoran's JPEG processor - - Also sets pixel size, average code size, mode (compr./decompr.) - (the given size is determined by the processor with the video interface) - ========================================================================= */ - -static int -zr36016_setup (struct videocodec *codec) -{ - struct zr36016 *ptr; - int res; - - dprintk(2, "zr36016: initializing VFE subsystem #%d.\n", - zr36016_codecs); - - if (zr36016_codecs == MAX_CODECS) { - dprintk(1, - KERN_ERR "zr36016: Can't attach more codecs!\n"); - return -ENOSPC; - } - //mem structure init - codec->data = ptr = kzalloc(sizeof(struct zr36016), GFP_KERNEL); - if (NULL == ptr) { - dprintk(1, KERN_ERR "zr36016: Can't get enough memory!\n"); - return -ENOMEM; - } - - snprintf(ptr->name, sizeof(ptr->name), "zr36016[%d]", - zr36016_codecs); - ptr->num = zr36016_codecs++; - ptr->codec = codec; - - //testing - res = zr36016_basic_test(ptr); - if (res < 0) { - zr36016_unset(codec); - return res; - } - //final setup - ptr->mode = CODEC_DO_COMPRESSION; - ptr->width = 768; - ptr->height = 288; - ptr->xdec = 1; - ptr->ydec = 0; - zr36016_init(ptr); - - dprintk(1, KERN_INFO "%s: codec v%d attached and running\n", - ptr->name, ptr->version); - - return 0; -} - -static const struct videocodec zr36016_codec = { - .owner = THIS_MODULE, - .name = "zr36016", - .magic = 0L, // magic not used - .flags = - CODEC_FLAG_HARDWARE | CODEC_FLAG_VFE | CODEC_FLAG_ENCODER | - CODEC_FLAG_DECODER, - .type = CODEC_TYPE_ZR36016, - .setup = zr36016_setup, // functionality - .unset = zr36016_unset, - .set_mode = zr36016_set_mode, - .set_video = zr36016_set_video, - .control = zr36016_control, - // others are not used -}; - -/* ========================================================================= - HOOK IN DRIVER AS KERNEL MODULE - ========================================================================= */ - -static int __init -zr36016_init_module (void) -{ - //dprintk(1, "ZR36016 driver %s\n",ZR016_VERSION); - zr36016_codecs = 0; - return videocodec_register(&zr36016_codec); -} - -static void __exit -zr36016_cleanup_module (void) -{ - if (zr36016_codecs) { - dprintk(1, - "zr36016: something's wrong - %d codecs left somehow.\n", - zr36016_codecs); - } - videocodec_unregister(&zr36016_codec); -} - -module_init(zr36016_init_module); -module_exit(zr36016_cleanup_module); - -MODULE_AUTHOR("Wolfgang Scherr "); -MODULE_DESCRIPTION("Driver module for ZR36016 video frontends " - ZR016_VERSION); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36016.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36016.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36016.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36016.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/* - * Zoran ZR36016 basic configuration functions - header file - * - * Copyright (C) 2001 Wolfgang Scherr - * - * $Id: zr36016.h,v 1.1.2.3 2003/01/14 21:18:07 rbultje Exp $ - * - * ------------------------------------------------------------------------ - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ------------------------------------------------------------------------ - */ - -#ifndef ZR36016_H -#define ZR36016_H - -/* data stored for each zoran jpeg codec chip */ -struct zr36016 { - char name[32]; - int num; - /* io datastructure */ - struct videocodec *codec; - // coder status - __u8 version; - // actual coder setup - int mode; - - __u16 xoff; - __u16 yoff; - __u16 width; - __u16 height; - __u16 xdec; - __u16 ydec; -}; - -/* direct register addresses */ -#define ZR016_GOSTOP 0x00 -#define ZR016_MODE 0x01 -#define ZR016_IADDR 0x02 -#define ZR016_IDATA 0x03 - -/* indirect register addresses */ -#define ZR016I_SETUP1 0x00 -#define ZR016I_SETUP2 0x01 -#define ZR016I_NAX_LO 0x02 -#define ZR016I_NAX_HI 0x03 -#define ZR016I_PAX_LO 0x04 -#define ZR016I_PAX_HI 0x05 -#define ZR016I_NAY_LO 0x06 -#define ZR016I_NAY_HI 0x07 -#define ZR016I_PAY_LO 0x08 -#define ZR016I_PAY_HI 0x09 -#define ZR016I_NOL_LO 0x0a -#define ZR016I_NOL_HI 0x0b - -/* possible values for mode register */ -#define ZR016_RGB444_YUV444 0x00 -#define ZR016_RGB444_YUV422 0x01 -#define ZR016_RGB444_YUV411 0x02 -#define ZR016_RGB444_Y400 0x03 -#define ZR016_RGB444_RGB444 0x04 -#define ZR016_YUV444_YUV444 0x08 -#define ZR016_YUV444_YUV422 0x09 -#define ZR016_YUV444_YUV411 0x0a -#define ZR016_YUV444_Y400 0x0b -#define ZR016_YUV444_RGB444 0x0c -#define ZR016_YUV422_YUV422 0x11 -#define ZR016_YUV422_YUV411 0x12 -#define ZR016_YUV422_Y400 0x13 -#define ZR016_YUV411_YUV411 0x16 -#define ZR016_YUV411_Y400 0x17 -#define ZR016_4444_4444 0x19 -#define ZR016_100_100 0x1b - -#define ZR016_RGB444 0x00 -#define ZR016_YUV444 0x20 -#define ZR016_YUV422 0x40 - -#define ZR016_COMPRESSION 0x80 -#define ZR016_EXPANSION 0x80 - -/* possible values for setup 1 register */ -#define ZR016_CKRT 0x80 -#define ZR016_VERT 0x40 -#define ZR016_HORZ 0x20 -#define ZR016_HRFL 0x10 -#define ZR016_DSFL 0x08 -#define ZR016_SBFL 0x04 -#define ZR016_RSTR 0x02 -#define ZR016_CNTI 0x01 - -/* possible values for setup 2 register */ -#define ZR016_SYEN 0x40 -#define ZR016_CCIR 0x04 -#define ZR016_SIGN 0x02 -#define ZR016_YMCS 0x01 - -#endif /*fndef ZR36016_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36050.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36050.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36050.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36050.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,900 +0,0 @@ -/* - * Zoran ZR36050 basic configuration functions - * - * Copyright (C) 2001 Wolfgang Scherr - * - * $Id: zr36050.c,v 1.1.2.11 2003/08/03 14:54:53 rbultje Exp $ - * - * ------------------------------------------------------------------------ - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ------------------------------------------------------------------------ - */ - -#define ZR050_VERSION "v0.7.1" - -#include -#include -#include -#include - -#include -#include - -/* I/O commands, error codes */ -#include - -/* headerfile of this module */ -#include "zr36050.h" - -/* codec io API */ -#include "videocodec.h" - -/* it doesn't make sense to have more than 20 or so, - just to prevent some unwanted loops */ -#define MAX_CODECS 20 - -/* amount of chips attached via this driver */ -static int zr36050_codecs; - -/* debugging is available via module parameter */ -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) - -/* ========================================================================= - Local hardware I/O functions: - - read/write via codec layer (registers are located in the master device) - ========================================================================= */ - -/* read and write functions */ -static u8 -zr36050_read (struct zr36050 *ptr, - u16 reg) -{ - u8 value = 0; - - // just in case something is wrong... - if (ptr->codec->master_data->readreg) - value = (ptr->codec->master_data->readreg(ptr->codec, - reg)) & 0xFF; - else - dprintk(1, - KERN_ERR "%s: invalid I/O setup, nothing read!\n", - ptr->name); - - dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, - value); - - return value; -} - -static void -zr36050_write (struct zr36050 *ptr, - u16 reg, - u8 value) -{ - dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, - reg); - - // just in case something is wrong... - if (ptr->codec->master_data->writereg) - ptr->codec->master_data->writereg(ptr->codec, reg, value); - else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing written!\n", - ptr->name); -} - -/* ========================================================================= - Local helper function: - - status read - ========================================================================= */ - -/* status is kept in datastructure */ -static u8 -zr36050_read_status1 (struct zr36050 *ptr) -{ - ptr->status1 = zr36050_read(ptr, ZR050_STATUS_1); - - zr36050_read(ptr, 0); - return ptr->status1; -} - -/* ========================================================================= - Local helper function: - - scale factor read - ========================================================================= */ - -/* scale factor is kept in datastructure */ -static u16 -zr36050_read_scalefactor (struct zr36050 *ptr) -{ - ptr->scalefact = (zr36050_read(ptr, ZR050_SF_HI) << 8) | - (zr36050_read(ptr, ZR050_SF_LO) & 0xFF); - - /* leave 0 selected for an eventually GO from master */ - zr36050_read(ptr, 0); - return ptr->scalefact; -} - -/* ========================================================================= - Local helper function: - - wait if codec is ready to proceed (end of processing) or time is over - ========================================================================= */ - -static void -zr36050_wait_end (struct zr36050 *ptr) -{ - int i = 0; - - while (!(zr36050_read_status1(ptr) & 0x4)) { - udelay(1); - if (i++ > 200000) { // 200ms, there is for sure something wrong!!! - dprintk(1, - "%s: timeout at wait_end (last status: 0x%02x)\n", - ptr->name, ptr->status1); - break; - } - } -} - -/* ========================================================================= - Local helper function: - - basic test of "connectivity", writes/reads to/from memory the SOF marker - ========================================================================= */ - -static int -zr36050_basic_test (struct zr36050 *ptr) -{ - zr36050_write(ptr, ZR050_SOF_IDX, 0x00); - zr36050_write(ptr, ZR050_SOF_IDX + 1, 0x00); - if ((zr36050_read(ptr, ZR050_SOF_IDX) | - zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0x0000) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to jpeg processor!\n", - ptr->name); - return -ENXIO; - } - zr36050_write(ptr, ZR050_SOF_IDX, 0xff); - zr36050_write(ptr, ZR050_SOF_IDX + 1, 0xc0); - if (((zr36050_read(ptr, ZR050_SOF_IDX) << 8) | - zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0xffc0) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to jpeg processor!\n", - ptr->name); - return -ENXIO; - } - - zr36050_wait_end(ptr); - if ((ptr->status1 & 0x4) == 0) { - dprintk(1, - KERN_ERR - "%s: attach failed, jpeg processor failed (end flag)!\n", - ptr->name); - return -EBUSY; - } - - return 0; /* looks good! */ -} - -/* ========================================================================= - Local helper function: - - simple loop for pushing the init datasets - ========================================================================= */ - -static int -zr36050_pushit (struct zr36050 *ptr, - u16 startreg, - u16 len, - const char *data) -{ - int i = 0; - - dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, - startreg, len); - while (i < len) { - zr36050_write(ptr, startreg++, data[i++]); - } - - return i; -} - -/* ========================================================================= - Basic datasets: - - jpeg baseline setup data (you find it on lots places in internet, or just - extract it from any regular .jpg image...) - - Could be variable, but until it's not needed it they are just fixed to save - memory. Otherwise expand zr36050 structure with arrays, push the values to - it and initialize from there, as e.g. the linux zr36057/60 driver does it. - ========================================================================= */ - -static const char zr36050_dqt[0x86] = { - 0xff, 0xdb, //Marker: DQT - 0x00, 0x84, //Length: 2*65+2 - 0x00, //Pq,Tq first table - 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, - 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, - 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, - 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, - 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, - 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, - 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, - 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, - 0x01, //Pq,Tq second table - 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, - 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 -}; - -static const char zr36050_dht[0x1a4] = { - 0xff, 0xc4, //Marker: DHT - 0x01, 0xa2, //Length: 2*AC, 2*DC - 0x00, //DC first table - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x01, //DC second table - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x10, //AC first table - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, - 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, - 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, - 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, - 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, - 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, - 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, - 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, - 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, - 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, - 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0xFA, - 0x11, //AC second table - 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, - 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, - 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, - 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, - 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, - 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, - 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, - 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, - 0xF9, 0xFA -}; - -/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */ -#define NO_OF_COMPONENTS 0x3 //Y,U,V -#define BASELINE_PRECISION 0x8 //MCU size (?) -static const char zr36050_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's QT -static const char zr36050_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's DC -static const char zr36050_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC - -/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */ -static const char zr36050_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 }; -static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; - -/* ========================================================================= - Local helper functions: - - calculation and setup of parameter-dependent JPEG baseline segments - (needed for compression only) - ========================================================================= */ - -/* ------------------------------------------------------------------------- */ - -/* SOF (start of frame) segment depends on width, height and sampling ratio - of each color component */ - -static int -zr36050_set_sof (struct zr36050 *ptr) -{ - char sof_data[34]; // max. size of register set - int i; - - dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name, - ptr->width, ptr->height, NO_OF_COMPONENTS); - sof_data[0] = 0xff; - sof_data[1] = 0xc0; - sof_data[2] = 0x00; - sof_data[3] = (3 * NO_OF_COMPONENTS) + 8; - sof_data[4] = BASELINE_PRECISION; // only '8' possible with zr36050 - sof_data[5] = (ptr->height) >> 8; - sof_data[6] = (ptr->height) & 0xff; - sof_data[7] = (ptr->width) >> 8; - sof_data[8] = (ptr->width) & 0xff; - sof_data[9] = NO_OF_COMPONENTS; - for (i = 0; i < NO_OF_COMPONENTS; i++) { - sof_data[10 + (i * 3)] = i; // index identifier - sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | (ptr->v_samp_ratio[i]); // sampling ratios - sof_data[12 + (i * 3)] = zr36050_tq[i]; // Q table selection - } - return zr36050_pushit(ptr, ZR050_SOF_IDX, - (3 * NO_OF_COMPONENTS) + 10, sof_data); -} - -/* ------------------------------------------------------------------------- */ - -/* SOS (start of scan) segment depends on the used scan components - of each color component */ - -static int -zr36050_set_sos (struct zr36050 *ptr) -{ - char sos_data[16]; // max. size of register set - int i; - - dprintk(3, "%s: write SOS\n", ptr->name); - sos_data[0] = 0xff; - sos_data[1] = 0xda; - sos_data[2] = 0x00; - sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3; - sos_data[4] = NO_OF_COMPONENTS; - for (i = 0; i < NO_OF_COMPONENTS; i++) { - sos_data[5 + (i * 2)] = i; // index - sos_data[6 + (i * 2)] = (zr36050_td[i] << 4) | zr36050_ta[i]; // AC/DC tbl.sel. - } - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00; // scan start - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3F; - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00; - return zr36050_pushit(ptr, ZR050_SOS1_IDX, - 4 + 1 + (2 * NO_OF_COMPONENTS) + 3, - sos_data); -} - -/* ------------------------------------------------------------------------- */ - -/* DRI (define restart interval) */ - -static int -zr36050_set_dri (struct zr36050 *ptr) -{ - char dri_data[6]; // max. size of register set - - dprintk(3, "%s: write DRI\n", ptr->name); - dri_data[0] = 0xff; - dri_data[1] = 0xdd; - dri_data[2] = 0x00; - dri_data[3] = 0x04; - dri_data[4] = ptr->dri >> 8; - dri_data[5] = ptr->dri & 0xff; - return zr36050_pushit(ptr, ZR050_DRI_IDX, 6, dri_data); -} - -/* ========================================================================= - Setup function: - - Setup compression/decompression of Zoran's JPEG processor - ( see also zoran 36050 manual ) - - ... sorry for the spaghetti code ... - ========================================================================= */ -static void -zr36050_init (struct zr36050 *ptr) -{ - int sum = 0; - long bitcnt, tmp; - - if (ptr->mode == CODEC_DO_COMPRESSION) { - dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name); - - /* 050 communicates with 057 in master mode */ - zr36050_write(ptr, ZR050_HARDWARE, ZR050_HW_MSTR); - - /* encoding table preload for compression */ - zr36050_write(ptr, ZR050_MODE, - ZR050_MO_COMP | ZR050_MO_TLM); - zr36050_write(ptr, ZR050_OPTIONS, 0); - - /* disable all IRQs */ - zr36050_write(ptr, ZR050_INT_REQ_0, 0); - zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1 - - /* volume control settings */ - /*zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol);*/ - zr36050_write(ptr, ZR050_SF_HI, ptr->scalefact >> 8); - zr36050_write(ptr, ZR050_SF_LO, ptr->scalefact & 0xff); - - zr36050_write(ptr, ZR050_AF_HI, 0xff); - zr36050_write(ptr, ZR050_AF_M, 0xff); - zr36050_write(ptr, ZR050_AF_LO, 0xff); - - /* setup the variable jpeg tables */ - sum += zr36050_set_sof(ptr); - sum += zr36050_set_sos(ptr); - sum += zr36050_set_dri(ptr); - - /* setup the fixed jpeg tables - maybe variable, though - - * (see table init section above) */ - dprintk(3, "%s: write DQT, DHT, APP\n", ptr->name); - sum += zr36050_pushit(ptr, ZR050_DQT_IDX, - sizeof(zr36050_dqt), zr36050_dqt); - sum += zr36050_pushit(ptr, ZR050_DHT_IDX, - sizeof(zr36050_dht), zr36050_dht); - zr36050_write(ptr, ZR050_APP_IDX, 0xff); - zr36050_write(ptr, ZR050_APP_IDX + 1, 0xe0 + ptr->app.appn); - zr36050_write(ptr, ZR050_APP_IDX + 2, 0x00); - zr36050_write(ptr, ZR050_APP_IDX + 3, ptr->app.len + 2); - sum += zr36050_pushit(ptr, ZR050_APP_IDX + 4, 60, - ptr->app.data) + 4; - zr36050_write(ptr, ZR050_COM_IDX, 0xff); - zr36050_write(ptr, ZR050_COM_IDX + 1, 0xfe); - zr36050_write(ptr, ZR050_COM_IDX + 2, 0x00); - zr36050_write(ptr, ZR050_COM_IDX + 3, ptr->com.len + 2); - sum += zr36050_pushit(ptr, ZR050_COM_IDX + 4, 60, - ptr->com.data) + 4; - - /* do the internal huffman table preload */ - zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI); - - zr36050_write(ptr, ZR050_GO, 1); // launch codec - zr36050_wait_end(ptr); - dprintk(2, "%s: Status after table preload: 0x%02x\n", - ptr->name, ptr->status1); - - if ((ptr->status1 & 0x4) == 0) { - dprintk(1, KERN_ERR "%s: init aborted!\n", - ptr->name); - return; // something is wrong, its timed out!!!! - } - - /* setup misc. data for compression (target code sizes) */ - - /* size of compressed code to reach without header data */ - sum = ptr->real_code_vol - sum; - bitcnt = sum << 3; /* need the size in bits */ - - tmp = bitcnt >> 16; - dprintk(3, - "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", - ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); - zr36050_write(ptr, ZR050_TCV_NET_HI, tmp >> 8); - zr36050_write(ptr, ZR050_TCV_NET_MH, tmp & 0xff); - tmp = bitcnt & 0xffff; - zr36050_write(ptr, ZR050_TCV_NET_ML, tmp >> 8); - zr36050_write(ptr, ZR050_TCV_NET_LO, tmp & 0xff); - - bitcnt -= bitcnt >> 7; // bits without stuffing - bitcnt -= ((bitcnt * 5) >> 6); // bits without eob - - tmp = bitcnt >> 16; - dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n", - ptr->name, bitcnt, tmp); - zr36050_write(ptr, ZR050_TCV_DATA_HI, tmp >> 8); - zr36050_write(ptr, ZR050_TCV_DATA_MH, tmp & 0xff); - tmp = bitcnt & 0xffff; - zr36050_write(ptr, ZR050_TCV_DATA_ML, tmp >> 8); - zr36050_write(ptr, ZR050_TCV_DATA_LO, tmp & 0xff); - - /* compression setup with or without bitrate control */ - zr36050_write(ptr, ZR050_MODE, - ZR050_MO_COMP | ZR050_MO_PASS2 | - (ptr->bitrate_ctrl ? ZR050_MO_BRC : 0)); - - /* this headers seem to deliver "valid AVI" jpeg frames */ - zr36050_write(ptr, ZR050_MARKERS_EN, - ZR050_ME_DQT | ZR050_ME_DHT | - ((ptr->app.len > 0) ? ZR050_ME_APP : 0) | - ((ptr->com.len > 0) ? ZR050_ME_COM : 0)); - } else { - dprintk(2, "%s: EXPANSION SETUP\n", ptr->name); - - /* 050 communicates with 055 in master mode */ - zr36050_write(ptr, ZR050_HARDWARE, - ZR050_HW_MSTR | ZR050_HW_CFIS_2_CLK); - - /* encoding table preload */ - zr36050_write(ptr, ZR050_MODE, ZR050_MO_TLM); - - /* disable all IRQs */ - zr36050_write(ptr, ZR050_INT_REQ_0, 0); - zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1 - - dprintk(3, "%s: write DHT\n", ptr->name); - zr36050_pushit(ptr, ZR050_DHT_IDX, sizeof(zr36050_dht), - zr36050_dht); - - /* do the internal huffman table preload */ - zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI); - - zr36050_write(ptr, ZR050_GO, 1); // launch codec - zr36050_wait_end(ptr); - dprintk(2, "%s: Status after table preload: 0x%02x\n", - ptr->name, ptr->status1); - - if ((ptr->status1 & 0x4) == 0) { - dprintk(1, KERN_ERR "%s: init aborted!\n", - ptr->name); - return; // something is wrong, its timed out!!!! - } - - /* setup misc. data for expansion */ - zr36050_write(ptr, ZR050_MODE, 0); - zr36050_write(ptr, ZR050_MARKERS_EN, 0); - } - - /* adr on selected, to allow GO from master */ - zr36050_read(ptr, 0); -} - -/* ========================================================================= - CODEC API FUNCTIONS - - this functions are accessed by the master via the API structure - ========================================================================= */ - -/* set compression/expansion mode and launches codec - - this should be the last call from the master before starting processing */ -static int -zr36050_set_mode (struct videocodec *codec, - int mode) -{ - struct zr36050 *ptr = (struct zr36050 *) codec->data; - - dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); - - if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) - return -EINVAL; - - ptr->mode = mode; - zr36050_init(ptr); - - return 0; -} - -/* set picture size (norm is ignored as the codec doesn't know about it) */ -static int -zr36050_set_video (struct videocodec *codec, - struct tvnorm *norm, - struct vfe_settings *cap, - struct vfe_polarity *pol) -{ - struct zr36050 *ptr = (struct zr36050 *) codec->data; - int size; - - dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) q%d call\n", - ptr->name, norm->HStart, norm->VStart, - cap->x, cap->y, cap->width, cap->height, - cap->decimation, cap->quality); - /* if () return -EINVAL; - * trust the master driver that it knows what it does - so - * we allow invalid startx/y and norm for now ... */ - ptr->width = cap->width / (cap->decimation & 0xff); - ptr->height = cap->height / ((cap->decimation >> 8) & 0xff); - - /* (KM) JPEG quality */ - size = ptr->width * ptr->height; - size *= 16; /* size in bits */ - /* apply quality setting */ - size = size * cap->quality / 200; - - /* Minimum: 1kb */ - if (size < 8192) - size = 8192; - /* Maximum: 7/8 of code buffer */ - if (size > ptr->total_code_vol * 7) - size = ptr->total_code_vol * 7; - - ptr->real_code_vol = size >> 3; /* in bytes */ - - /* Set max_block_vol here (previously in zr36050_init, moved - * here for consistency with zr36060 code */ - zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol); - - return 0; -} - -/* additional control functions */ -static int -zr36050_control (struct videocodec *codec, - int type, - int size, - void *data) -{ - struct zr36050 *ptr = (struct zr36050 *) codec->data; - int *ival = (int *) data; - - dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, - size); - - switch (type) { - case CODEC_G_STATUS: /* get last status */ - if (size != sizeof(int)) - return -EFAULT; - zr36050_read_status1(ptr); - *ival = ptr->status1; - break; - - case CODEC_G_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - *ival = CODEC_MODE_BJPG; - break; - - case CODEC_S_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - if (*ival != CODEC_MODE_BJPG) - return -EINVAL; - /* not needed, do nothing */ - return 0; - - case CODEC_G_VFE: - case CODEC_S_VFE: - /* not needed, do nothing */ - return 0; - - case CODEC_S_MMAP: - /* not available, give an error */ - return -ENXIO; - - case CODEC_G_JPEG_TDS_BYTE: /* get target volume in byte */ - if (size != sizeof(int)) - return -EFAULT; - *ival = ptr->total_code_vol; - break; - - case CODEC_S_JPEG_TDS_BYTE: /* get target volume in byte */ - if (size != sizeof(int)) - return -EFAULT; - ptr->total_code_vol = *ival; - /* (Kieran Morrissey) - * code copied from zr36060.c to ensure proper bitrate */ - ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; - break; - - case CODEC_G_JPEG_SCALE: /* get scaling factor */ - if (size != sizeof(int)) - return -EFAULT; - *ival = zr36050_read_scalefactor(ptr); - break; - - case CODEC_S_JPEG_SCALE: /* set scaling factor */ - if (size != sizeof(int)) - return -EFAULT; - ptr->scalefact = *ival; - break; - - case CODEC_G_JPEG_APP_DATA: { /* get appn marker data */ - struct jpeg_app_marker *app = data; - - if (size != sizeof(struct jpeg_app_marker)) - return -EFAULT; - - *app = ptr->app; - break; - } - - case CODEC_S_JPEG_APP_DATA: { /* set appn marker data */ - struct jpeg_app_marker *app = data; - - if (size != sizeof(struct jpeg_app_marker)) - return -EFAULT; - - ptr->app = *app; - break; - } - - case CODEC_G_JPEG_COM_DATA: { /* get comment marker data */ - struct jpeg_com_marker *com = data; - - if (size != sizeof(struct jpeg_com_marker)) - return -EFAULT; - - *com = ptr->com; - break; - } - - case CODEC_S_JPEG_COM_DATA: { /* set comment marker data */ - struct jpeg_com_marker *com = data; - - if (size != sizeof(struct jpeg_com_marker)) - return -EFAULT; - - ptr->com = *com; - break; - } - - default: - return -EINVAL; - } - - return size; -} - -/* ========================================================================= - Exit and unregister function: - - Deinitializes Zoran's JPEG processor - ========================================================================= */ - -static int -zr36050_unset (struct videocodec *codec) -{ - struct zr36050 *ptr = codec->data; - - if (ptr) { - /* do wee need some codec deinit here, too ???? */ - - dprintk(1, "%s: finished codec #%d\n", ptr->name, - ptr->num); - kfree(ptr); - codec->data = NULL; - - zr36050_codecs--; - return 0; - } - - return -EFAULT; -} - -/* ========================================================================= - Setup and registry function: - - Initializes Zoran's JPEG processor - - Also sets pixel size, average code size, mode (compr./decompr.) - (the given size is determined by the processor with the video interface) - ========================================================================= */ - -static int -zr36050_setup (struct videocodec *codec) -{ - struct zr36050 *ptr; - int res; - - dprintk(2, "zr36050: initializing MJPEG subsystem #%d.\n", - zr36050_codecs); - - if (zr36050_codecs == MAX_CODECS) { - dprintk(1, - KERN_ERR "zr36050: Can't attach more codecs!\n"); - return -ENOSPC; - } - //mem structure init - codec->data = ptr = kzalloc(sizeof(struct zr36050), GFP_KERNEL); - if (NULL == ptr) { - dprintk(1, KERN_ERR "zr36050: Can't get enough memory!\n"); - return -ENOMEM; - } - - snprintf(ptr->name, sizeof(ptr->name), "zr36050[%d]", - zr36050_codecs); - ptr->num = zr36050_codecs++; - ptr->codec = codec; - - //testing - res = zr36050_basic_test(ptr); - if (res < 0) { - zr36050_unset(codec); - return res; - } - //final setup - memcpy(ptr->h_samp_ratio, zr36050_decimation_h, 8); - memcpy(ptr->v_samp_ratio, zr36050_decimation_v, 8); - - ptr->bitrate_ctrl = 0; /* 0 or 1 - fixed file size flag - * (what is the difference?) */ - ptr->mode = CODEC_DO_COMPRESSION; - ptr->width = 384; - ptr->height = 288; - ptr->total_code_vol = 16000; - ptr->max_block_vol = 240; - ptr->scalefact = 0x100; - ptr->dri = 1; - - /* no app/com marker by default */ - ptr->app.appn = 0; - ptr->app.len = 0; - ptr->com.len = 0; - - zr36050_init(ptr); - - dprintk(1, KERN_INFO "%s: codec attached and running\n", - ptr->name); - - return 0; -} - -static const struct videocodec zr36050_codec = { - .owner = THIS_MODULE, - .name = "zr36050", - .magic = 0L, // magic not used - .flags = - CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER | - CODEC_FLAG_DECODER, - .type = CODEC_TYPE_ZR36050, - .setup = zr36050_setup, // functionality - .unset = zr36050_unset, - .set_mode = zr36050_set_mode, - .set_video = zr36050_set_video, - .control = zr36050_control, - // others are not used -}; - -/* ========================================================================= - HOOK IN DRIVER AS KERNEL MODULE - ========================================================================= */ - -static int __init -zr36050_init_module (void) -{ - //dprintk(1, "ZR36050 driver %s\n",ZR050_VERSION); - zr36050_codecs = 0; - return videocodec_register(&zr36050_codec); -} - -static void __exit -zr36050_cleanup_module (void) -{ - if (zr36050_codecs) { - dprintk(1, - "zr36050: something's wrong - %d codecs left somehow.\n", - zr36050_codecs); - } - videocodec_unregister(&zr36050_codec); -} - -module_init(zr36050_init_module); -module_exit(zr36050_cleanup_module); - -MODULE_AUTHOR("Wolfgang Scherr "); -MODULE_DESCRIPTION("Driver module for ZR36050 jpeg processors " - ZR050_VERSION); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36050.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36050.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36050.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36050.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,184 +0,0 @@ -/* - * Zoran ZR36050 basic configuration functions - header file - * - * Copyright (C) 2001 Wolfgang Scherr - * - * $Id: zr36050.h,v 1.1.2.2 2003/01/14 21:18:22 rbultje Exp $ - * - * ------------------------------------------------------------------------ - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ------------------------------------------------------------------------ - */ - -#ifndef ZR36050_H -#define ZR36050_H - -#include "videocodec.h" - -/* data stored for each zoran jpeg codec chip */ -struct zr36050 { - char name[32]; - int num; - /* io datastructure */ - struct videocodec *codec; - // last coder status - __u8 status1; - // actual coder setup - int mode; - - __u16 width; - __u16 height; - - __u16 bitrate_ctrl; - - __u32 total_code_vol; - __u32 real_code_vol; - __u16 max_block_vol; - - __u8 h_samp_ratio[8]; - __u8 v_samp_ratio[8]; - __u16 scalefact; - __u16 dri; - - /* com/app marker */ - struct jpeg_com_marker com; - struct jpeg_app_marker app; -}; - -/* zr36050 register addresses */ -#define ZR050_GO 0x000 -#define ZR050_HARDWARE 0x002 -#define ZR050_MODE 0x003 -#define ZR050_OPTIONS 0x004 -#define ZR050_MBCV 0x005 -#define ZR050_MARKERS_EN 0x006 -#define ZR050_INT_REQ_0 0x007 -#define ZR050_INT_REQ_1 0x008 -#define ZR050_TCV_NET_HI 0x009 -#define ZR050_TCV_NET_MH 0x00a -#define ZR050_TCV_NET_ML 0x00b -#define ZR050_TCV_NET_LO 0x00c -#define ZR050_TCV_DATA_HI 0x00d -#define ZR050_TCV_DATA_MH 0x00e -#define ZR050_TCV_DATA_ML 0x00f -#define ZR050_TCV_DATA_LO 0x010 -#define ZR050_SF_HI 0x011 -#define ZR050_SF_LO 0x012 -#define ZR050_AF_HI 0x013 -#define ZR050_AF_M 0x014 -#define ZR050_AF_LO 0x015 -#define ZR050_ACV_HI 0x016 -#define ZR050_ACV_MH 0x017 -#define ZR050_ACV_ML 0x018 -#define ZR050_ACV_LO 0x019 -#define ZR050_ACT_HI 0x01a -#define ZR050_ACT_MH 0x01b -#define ZR050_ACT_ML 0x01c -#define ZR050_ACT_LO 0x01d -#define ZR050_ACV_TRUN_HI 0x01e -#define ZR050_ACV_TRUN_MH 0x01f -#define ZR050_ACV_TRUN_ML 0x020 -#define ZR050_ACV_TRUN_LO 0x021 -#define ZR050_STATUS_0 0x02e -#define ZR050_STATUS_1 0x02f - -#define ZR050_SOF_IDX 0x040 -#define ZR050_SOS1_IDX 0x07a -#define ZR050_SOS2_IDX 0x08a -#define ZR050_SOS3_IDX 0x09a -#define ZR050_SOS4_IDX 0x0aa -#define ZR050_DRI_IDX 0x0c0 -#define ZR050_DNL_IDX 0x0c6 -#define ZR050_DQT_IDX 0x0cc -#define ZR050_DHT_IDX 0x1d4 -#define ZR050_APP_IDX 0x380 -#define ZR050_COM_IDX 0x3c0 - -/* zr36050 hardware register bits */ - -#define ZR050_HW_BSWD 0x80 -#define ZR050_HW_MSTR 0x40 -#define ZR050_HW_DMA 0x20 -#define ZR050_HW_CFIS_1_CLK 0x00 -#define ZR050_HW_CFIS_2_CLK 0x04 -#define ZR050_HW_CFIS_3_CLK 0x08 -#define ZR050_HW_CFIS_4_CLK 0x0C -#define ZR050_HW_CFIS_5_CLK 0x10 -#define ZR050_HW_CFIS_6_CLK 0x14 -#define ZR050_HW_CFIS_7_CLK 0x18 -#define ZR050_HW_CFIS_8_CLK 0x1C -#define ZR050_HW_BELE 0x01 - -/* zr36050 mode register bits */ - -#define ZR050_MO_COMP 0x80 -#define ZR050_MO_COMP 0x80 -#define ZR050_MO_ATP 0x40 -#define ZR050_MO_PASS2 0x20 -#define ZR050_MO_TLM 0x10 -#define ZR050_MO_DCONLY 0x08 -#define ZR050_MO_BRC 0x04 - -#define ZR050_MO_ATP 0x40 -#define ZR050_MO_PASS2 0x20 -#define ZR050_MO_TLM 0x10 -#define ZR050_MO_DCONLY 0x08 - -/* zr36050 option register bits */ - -#define ZR050_OP_NSCN_1 0x00 -#define ZR050_OP_NSCN_2 0x20 -#define ZR050_OP_NSCN_3 0x40 -#define ZR050_OP_NSCN_4 0x60 -#define ZR050_OP_NSCN_5 0x80 -#define ZR050_OP_NSCN_6 0xA0 -#define ZR050_OP_NSCN_7 0xC0 -#define ZR050_OP_NSCN_8 0xE0 -#define ZR050_OP_OVF 0x10 - - -/* zr36050 markers-enable register bits */ - -#define ZR050_ME_APP 0x80 -#define ZR050_ME_COM 0x40 -#define ZR050_ME_DRI 0x20 -#define ZR050_ME_DQT 0x10 -#define ZR050_ME_DHT 0x08 -#define ZR050_ME_DNL 0x04 -#define ZR050_ME_DQTI 0x02 -#define ZR050_ME_DHTI 0x01 - -/* zr36050 status0/1 register bit masks */ - -#define ZR050_ST_RST_MASK 0x20 -#define ZR050_ST_SOF_MASK 0x02 -#define ZR050_ST_SOS_MASK 0x02 -#define ZR050_ST_DATRDY_MASK 0x80 -#define ZR050_ST_MRKDET_MASK 0x40 -#define ZR050_ST_RFM_MASK 0x10 -#define ZR050_ST_RFD_MASK 0x08 -#define ZR050_ST_END_MASK 0x04 -#define ZR050_ST_TCVOVF_MASK 0x02 -#define ZR050_ST_DATOVF_MASK 0x01 - -/* pixel component idx */ - -#define ZR050_Y_COMPONENT 0 -#define ZR050_U_COMPONENT 1 -#define ZR050_V_COMPONENT 2 - -#endif /*fndef ZR36050_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36057.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36057.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36057.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36057.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,168 +0,0 @@ -/* - * zr36057.h - zr36057 register offsets - * - * Copyright (C) 1998 Dave Perks - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _ZR36057_H_ -#define _ZR36057_H_ - - -/* Zoran ZR36057 registers */ - -#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ -#define ZR36057_VFEHCR_HSPol (1<<30) -#define ZR36057_VFEHCR_HStart 10 -#define ZR36057_VFEHCR_HEnd 0 -#define ZR36057_VFEHCR_Hmask 0x3ff - -#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ -#define ZR36057_VFEVCR_VSPol (1<<30) -#define ZR36057_VFEVCR_VStart 10 -#define ZR36057_VFEVCR_VEnd 0 -#define ZR36057_VFEVCR_Vmask 0x3ff - -#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ -#define ZR36057_VFESPFR_ExtFl (1<<26) -#define ZR36057_VFESPFR_TopField (1<<25) -#define ZR36057_VFESPFR_VCLKPol (1<<24) -#define ZR36057_VFESPFR_HFilter 21 -#define ZR36057_VFESPFR_HorDcm 14 -#define ZR36057_VFESPFR_VerDcm 8 -#define ZR36057_VFESPFR_DispMode 6 -#define ZR36057_VFESPFR_YUV422 (0<<3) -#define ZR36057_VFESPFR_RGB888 (1<<3) -#define ZR36057_VFESPFR_RGB565 (2<<3) -#define ZR36057_VFESPFR_RGB555 (3<<3) -#define ZR36057_VFESPFR_ErrDif (1<<2) -#define ZR36057_VFESPFR_Pack24 (1<<1) -#define ZR36057_VFESPFR_LittleEndian (1<<0) - -#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ - -#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ - -#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ -#define ZR36057_VSSFGR_DispStride 16 -#define ZR36057_VSSFGR_VidOvf (1<<8) -#define ZR36057_VSSFGR_SnapShot (1<<1) -#define ZR36057_VSSFGR_FrameGrab (1<<0) - -#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ -#define ZR36057_VDCR_VidEn (1<<31) -#define ZR36057_VDCR_MinPix 24 -#define ZR36057_VDCR_Triton (1<<24) -#define ZR36057_VDCR_VidWinHt 12 -#define ZR36057_VDCR_VidWinWid 0 - -#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ - -#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ - -#define ZR36057_OCR 0x024 /* Overlay Control Register */ -#define ZR36057_OCR_OvlEnable (1 << 15) -#define ZR36057_OCR_MaskStride 0 - -#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ -#define ZR36057_SPGPPCR_SoftReset (1<<24) - -#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ - -#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ - -#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ -#define ZR36057_MCTCR_CodTime (1 << 30) -#define ZR36057_MCTCR_CEmpty (1 << 29) -#define ZR36057_MCTCR_CFlush (1 << 28) -#define ZR36057_MCTCR_CodGuestID 20 -#define ZR36057_MCTCR_CodGuestReg 16 - -#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ - -#define ZR36057_ISR 0x03c /* Interrupt Status Register */ -#define ZR36057_ISR_GIRQ1 (1<<30) -#define ZR36057_ISR_GIRQ0 (1<<29) -#define ZR36057_ISR_CodRepIRQ (1<<28) -#define ZR36057_ISR_JPEGRepIRQ (1<<27) - -#define ZR36057_ICR 0x040 /* Interrupt Control Register */ -#define ZR36057_ICR_GIRQ1 (1<<30) -#define ZR36057_ICR_GIRQ0 (1<<29) -#define ZR36057_ICR_CodRepIRQ (1<<28) -#define ZR36057_ICR_JPEGRepIRQ (1<<27) -#define ZR36057_ICR_IntPinEn (1<<24) - -#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ -#define ZR36057_I2CBR_SDA (1<<1) -#define ZR36057_I2CBR_SCL (1<<0) - -#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ -#define ZR36057_JMC_JPG (1 << 31) -#define ZR36057_JMC_JPGExpMode (0 << 29) -#define ZR36057_JMC_JPGCmpMode (1 << 29) -#define ZR36057_JMC_MJPGExpMode (2 << 29) -#define ZR36057_JMC_MJPGCmpMode (3 << 29) -#define ZR36057_JMC_RTBUSY_FB (1 << 6) -#define ZR36057_JMC_Go_en (1 << 5) -#define ZR36057_JMC_SyncMstr (1 << 4) -#define ZR36057_JMC_Fld_per_buff (1 << 3) -#define ZR36057_JMC_VFIFO_FB (1 << 2) -#define ZR36057_JMC_CFIFO_FB (1 << 1) -#define ZR36057_JMC_Stll_LitEndian (1 << 0) - -#define ZR36057_JPC 0x104 /* JPEG Process Control */ -#define ZR36057_JPC_P_Reset (1 << 7) -#define ZR36057_JPC_CodTrnsEn (1 << 5) -#define ZR36057_JPC_Active (1 << 0) - -#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ -#define ZR36057_VSP_VsyncSize 16 -#define ZR36057_VSP_FrmTot 0 - -#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ -#define ZR36057_HSP_HsyncStart 16 -#define ZR36057_HSP_LineTot 0 - -#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ -#define ZR36057_FHAP_NAX 16 -#define ZR36057_FHAP_PAX 0 - -#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ -#define ZR36057_FVAP_NAY 16 -#define ZR36057_FVAP_PAY 0 - -#define ZR36057_FPP 0x118 /* Field Process Parameters */ -#define ZR36057_FPP_Odd_Even (1 << 0) - -#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ - -#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ - -#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ -#define ZR36057_JCGI_JPEGuestID 4 -#define ZR36057_JCGI_JPEGuestReg 0 - -#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ - -#define ZR36057_POR 0x200 /* Post Office Register */ -#define ZR36057_POR_POPen (1<<25) -#define ZR36057_POR_POTime (1<<24) -#define ZR36057_POR_PODir (1<<23) - -#define ZR36057_STR 0x300 /* "Still" Transfer Register */ - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36060.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36060.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36060.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36060.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1010 +0,0 @@ -/* - * Zoran ZR36060 basic configuration functions - * - * Copyright (C) 2002 Laurent Pinchart - * - * $Id: zr36060.c,v 1.1.2.22 2003/05/06 09:35:36 rbultje Exp $ - * - * ------------------------------------------------------------------------ - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ------------------------------------------------------------------------ - */ - -#define ZR060_VERSION "v0.7" - -#include -#include -#include -#include - -#include -#include - -/* I/O commands, error codes */ -#include - -/* headerfile of this module */ -#include "zr36060.h" - -/* codec io API */ -#include "videocodec.h" - -/* it doesn't make sense to have more than 20 or so, - just to prevent some unwanted loops */ -#define MAX_CODECS 20 - -/* amount of chips attached via this driver */ -static int zr36060_codecs; - -static int low_bitrate; -module_param(low_bitrate, bool, 0); -MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate"); - -/* debugging is available via module parameter */ -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) - -/* ========================================================================= - Local hardware I/O functions: - - read/write via codec layer (registers are located in the master device) - ========================================================================= */ - -/* read and write functions */ -static u8 -zr36060_read (struct zr36060 *ptr, - u16 reg) -{ - u8 value = 0; - - // just in case something is wrong... - if (ptr->codec->master_data->readreg) - value = (ptr->codec->master_data->readreg(ptr->codec, - reg)) & 0xff; - else - dprintk(1, - KERN_ERR "%s: invalid I/O setup, nothing read!\n", - ptr->name); - - //dprintk(4, "%s: reading from 0x%04x: %02x\n",ptr->name,reg,value); - - return value; -} - -static void -zr36060_write(struct zr36060 *ptr, - u16 reg, - u8 value) -{ - //dprintk(4, "%s: writing 0x%02x to 0x%04x\n",ptr->name,value,reg); - dprintk(4, "0x%02x @0x%04x\n", value, reg); - - // just in case something is wrong... - if (ptr->codec->master_data->writereg) - ptr->codec->master_data->writereg(ptr->codec, reg, value); - else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing written!\n", - ptr->name); -} - -/* ========================================================================= - Local helper function: - - status read - ========================================================================= */ - -/* status is kept in datastructure */ -static u8 -zr36060_read_status (struct zr36060 *ptr) -{ - ptr->status = zr36060_read(ptr, ZR060_CFSR); - - zr36060_read(ptr, 0); - return ptr->status; -} - -/* ========================================================================= - Local helper function: - - scale factor read - ========================================================================= */ - -/* scale factor is kept in datastructure */ -static u16 -zr36060_read_scalefactor (struct zr36060 *ptr) -{ - ptr->scalefact = (zr36060_read(ptr, ZR060_SF_HI) << 8) | - (zr36060_read(ptr, ZR060_SF_LO) & 0xFF); - - /* leave 0 selected for an eventually GO from master */ - zr36060_read(ptr, 0); - return ptr->scalefact; -} - -/* ========================================================================= - Local helper function: - - wait if codec is ready to proceed (end of processing) or time is over - ========================================================================= */ - -static void -zr36060_wait_end (struct zr36060 *ptr) -{ - int i = 0; - - while (zr36060_read_status(ptr) & ZR060_CFSR_Busy) { - udelay(1); - if (i++ > 200000) { // 200ms, there is for sure something wrong!!! - dprintk(1, - "%s: timeout at wait_end (last status: 0x%02x)\n", - ptr->name, ptr->status); - break; - } - } -} - -/* ========================================================================= - Local helper function: - - basic test of "connectivity", writes/reads to/from memory the SOF marker - ========================================================================= */ - -static int -zr36060_basic_test (struct zr36060 *ptr) -{ - if ((zr36060_read(ptr, ZR060_IDR_DEV) != 0x33) && - (zr36060_read(ptr, ZR060_IDR_REV) != 0x01)) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to jpeg processor!\n", - ptr->name); - return -ENXIO; - } - - zr36060_wait_end(ptr); - if (ptr->status & ZR060_CFSR_Busy) { - dprintk(1, - KERN_ERR - "%s: attach failed, jpeg processor failed (end flag)!\n", - ptr->name); - return -EBUSY; - } - - return 0; /* looks good! */ -} - -/* ========================================================================= - Local helper function: - - simple loop for pushing the init datasets - ========================================================================= */ - -static int -zr36060_pushit (struct zr36060 *ptr, - u16 startreg, - u16 len, - const char *data) -{ - int i = 0; - - dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, - startreg, len); - while (i < len) { - zr36060_write(ptr, startreg++, data[i++]); - } - - return i; -} - -/* ========================================================================= - Basic datasets: - - jpeg baseline setup data (you find it on lots places in internet, or just - extract it from any regular .jpg image...) - - Could be variable, but until it's not needed it they are just fixed to save - memory. Otherwise expand zr36060 structure with arrays, push the values to - it and initialize from there, as e.g. the linux zr36057/60 driver does it. - ========================================================================= */ - -static const char zr36060_dqt[0x86] = { - 0xff, 0xdb, //Marker: DQT - 0x00, 0x84, //Length: 2*65+2 - 0x00, //Pq,Tq first table - 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, - 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, - 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, - 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, - 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, - 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, - 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, - 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, - 0x01, //Pq,Tq second table - 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, - 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 -}; - -static const char zr36060_dht[0x1a4] = { - 0xff, 0xc4, //Marker: DHT - 0x01, 0xa2, //Length: 2*AC, 2*DC - 0x00, //DC first table - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x01, //DC second table - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x10, //AC first table - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, - 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, - 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, - 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, - 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, - 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, - 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, - 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, - 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, - 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, - 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0xFA, - 0x11, //AC second table - 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, - 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, - 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, - 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, - 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, - 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, - 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, - 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, - 0xF9, 0xFA -}; - -/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */ -#define NO_OF_COMPONENTS 0x3 //Y,U,V -#define BASELINE_PRECISION 0x8 //MCU size (?) -static const char zr36060_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's QT -static const char zr36060_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's DC -static const char zr36060_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC - -/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */ -static const char zr36060_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 }; -static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; - -/* ========================================================================= - Local helper functions: - - calculation and setup of parameter-dependent JPEG baseline segments - (needed for compression only) - ========================================================================= */ - -/* ------------------------------------------------------------------------- */ - -/* SOF (start of frame) segment depends on width, height and sampling ratio - of each color component */ - -static int -zr36060_set_sof (struct zr36060 *ptr) -{ - char sof_data[34]; // max. size of register set - int i; - - dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name, - ptr->width, ptr->height, NO_OF_COMPONENTS); - sof_data[0] = 0xff; - sof_data[1] = 0xc0; - sof_data[2] = 0x00; - sof_data[3] = (3 * NO_OF_COMPONENTS) + 8; - sof_data[4] = BASELINE_PRECISION; // only '8' possible with zr36060 - sof_data[5] = (ptr->height) >> 8; - sof_data[6] = (ptr->height) & 0xff; - sof_data[7] = (ptr->width) >> 8; - sof_data[8] = (ptr->width) & 0xff; - sof_data[9] = NO_OF_COMPONENTS; - for (i = 0; i < NO_OF_COMPONENTS; i++) { - sof_data[10 + (i * 3)] = i; // index identifier - sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | - (ptr->v_samp_ratio[i]); // sampling ratios - sof_data[12 + (i * 3)] = zr36060_tq[i]; // Q table selection - } - return zr36060_pushit(ptr, ZR060_SOF_IDX, - (3 * NO_OF_COMPONENTS) + 10, sof_data); -} - -/* ------------------------------------------------------------------------- */ - -/* SOS (start of scan) segment depends on the used scan components - of each color component */ - -static int -zr36060_set_sos (struct zr36060 *ptr) -{ - char sos_data[16]; // max. size of register set - int i; - - dprintk(3, "%s: write SOS\n", ptr->name); - sos_data[0] = 0xff; - sos_data[1] = 0xda; - sos_data[2] = 0x00; - sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3; - sos_data[4] = NO_OF_COMPONENTS; - for (i = 0; i < NO_OF_COMPONENTS; i++) { - sos_data[5 + (i * 2)] = i; // index - sos_data[6 + (i * 2)] = (zr36060_td[i] << 4) | - zr36060_ta[i]; // AC/DC tbl.sel. - } - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00; // scan start - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3f; - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00; - return zr36060_pushit(ptr, ZR060_SOS_IDX, - 4 + 1 + (2 * NO_OF_COMPONENTS) + 3, - sos_data); -} - -/* ------------------------------------------------------------------------- */ - -/* DRI (define restart interval) */ - -static int -zr36060_set_dri (struct zr36060 *ptr) -{ - char dri_data[6]; // max. size of register set - - dprintk(3, "%s: write DRI\n", ptr->name); - dri_data[0] = 0xff; - dri_data[1] = 0xdd; - dri_data[2] = 0x00; - dri_data[3] = 0x04; - dri_data[4] = (ptr->dri) >> 8; - dri_data[5] = (ptr->dri) & 0xff; - return zr36060_pushit(ptr, ZR060_DRI_IDX, 6, dri_data); -} - -/* ========================================================================= - Setup function: - - Setup compression/decompression of Zoran's JPEG processor - ( see also zoran 36060 manual ) - - ... sorry for the spaghetti code ... - ========================================================================= */ -static void -zr36060_init (struct zr36060 *ptr) -{ - int sum = 0; - long bitcnt, tmp; - - if (ptr->mode == CODEC_DO_COMPRESSION) { - dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name); - - zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst); - - /* 060 communicates with 067 in master mode */ - zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CodeMstr); - - /* Compression with or without variable scale factor */ - /*FIXME: What about ptr->bitrate_ctrl? */ - zr36060_write(ptr, ZR060_CMR, - ZR060_CMR_Comp | ZR060_CMR_Pass2 | - ZR060_CMR_BRB); - - /* Must be zero */ - zr36060_write(ptr, ZR060_MBZ, 0x00); - zr36060_write(ptr, ZR060_TCR_HI, 0x00); - zr36060_write(ptr, ZR060_TCR_LO, 0x00); - - /* Disable all IRQs - no DataErr means autoreset */ - zr36060_write(ptr, ZR060_IMR, 0); - - /* volume control settings */ - zr36060_write(ptr, ZR060_SF_HI, ptr->scalefact >> 8); - zr36060_write(ptr, ZR060_SF_LO, ptr->scalefact & 0xff); - - zr36060_write(ptr, ZR060_AF_HI, 0xff); - zr36060_write(ptr, ZR060_AF_M, 0xff); - zr36060_write(ptr, ZR060_AF_LO, 0xff); - - /* setup the variable jpeg tables */ - sum += zr36060_set_sof(ptr); - sum += zr36060_set_sos(ptr); - sum += zr36060_set_dri(ptr); - - /* setup the fixed jpeg tables - maybe variable, though - - * (see table init section above) */ - sum += - zr36060_pushit(ptr, ZR060_DQT_IDX, sizeof(zr36060_dqt), - zr36060_dqt); - sum += - zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht), - zr36060_dht); - zr36060_write(ptr, ZR060_APP_IDX, 0xff); - zr36060_write(ptr, ZR060_APP_IDX + 1, 0xe0 + ptr->app.appn); - zr36060_write(ptr, ZR060_APP_IDX + 2, 0x00); - zr36060_write(ptr, ZR060_APP_IDX + 3, ptr->app.len + 2); - sum += zr36060_pushit(ptr, ZR060_APP_IDX + 4, 60, - ptr->app.data) + 4; - zr36060_write(ptr, ZR060_COM_IDX, 0xff); - zr36060_write(ptr, ZR060_COM_IDX + 1, 0xfe); - zr36060_write(ptr, ZR060_COM_IDX + 2, 0x00); - zr36060_write(ptr, ZR060_COM_IDX + 3, ptr->com.len + 2); - sum += zr36060_pushit(ptr, ZR060_COM_IDX + 4, 60, - ptr->com.data) + 4; - - /* setup misc. data for compression (target code sizes) */ - - /* size of compressed code to reach without header data */ - sum = ptr->real_code_vol - sum; - bitcnt = sum << 3; /* need the size in bits */ - - tmp = bitcnt >> 16; - dprintk(3, - "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", - ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); - zr36060_write(ptr, ZR060_TCV_NET_HI, tmp >> 8); - zr36060_write(ptr, ZR060_TCV_NET_MH, tmp & 0xff); - tmp = bitcnt & 0xffff; - zr36060_write(ptr, ZR060_TCV_NET_ML, tmp >> 8); - zr36060_write(ptr, ZR060_TCV_NET_LO, tmp & 0xff); - - bitcnt -= bitcnt >> 7; // bits without stuffing - bitcnt -= ((bitcnt * 5) >> 6); // bits without eob - - tmp = bitcnt >> 16; - dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n", - ptr->name, bitcnt, tmp); - zr36060_write(ptr, ZR060_TCV_DATA_HI, tmp >> 8); - zr36060_write(ptr, ZR060_TCV_DATA_MH, tmp & 0xff); - tmp = bitcnt & 0xffff; - zr36060_write(ptr, ZR060_TCV_DATA_ML, tmp >> 8); - zr36060_write(ptr, ZR060_TCV_DATA_LO, tmp & 0xff); - - /* JPEG markers to be included in the compressed stream */ - zr36060_write(ptr, ZR060_MER, - ZR060_MER_DQT | ZR060_MER_DHT | - ((ptr->com.len > 0) ? ZR060_MER_Com : 0) | - ((ptr->app.len > 0) ? ZR060_MER_App : 0)); - - /* Setup the Video Frontend */ - /* Limit pixel range to 16..235 as per CCIR-601 */ - zr36060_write(ptr, ZR060_VCR, ZR060_VCR_Range); - - } else { - dprintk(2, "%s: EXPANSION SETUP\n", ptr->name); - - zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst); - - /* 060 communicates with 067 in master mode */ - zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CodeMstr); - - /* Decompression */ - zr36060_write(ptr, ZR060_CMR, 0); - - /* Must be zero */ - zr36060_write(ptr, ZR060_MBZ, 0x00); - zr36060_write(ptr, ZR060_TCR_HI, 0x00); - zr36060_write(ptr, ZR060_TCR_LO, 0x00); - - /* Disable all IRQs - no DataErr means autoreset */ - zr36060_write(ptr, ZR060_IMR, 0); - - /* setup misc. data for expansion */ - zr36060_write(ptr, ZR060_MER, 0); - - /* setup the fixed jpeg tables - maybe variable, though - - * (see table init section above) */ - zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht), - zr36060_dht); - - /* Setup the Video Frontend */ - //zr36060_write(ptr, ZR060_VCR, ZR060_VCR_FIExt); - //this doesn't seem right and doesn't work... - zr36060_write(ptr, ZR060_VCR, ZR060_VCR_Range); - } - - /* Load the tables */ - zr36060_write(ptr, ZR060_LOAD, - ZR060_LOAD_SyncRst | ZR060_LOAD_Load); - zr36060_wait_end(ptr); - dprintk(2, "%s: Status after table preload: 0x%02x\n", ptr->name, - ptr->status); - - if (ptr->status & ZR060_CFSR_Busy) { - dprintk(1, KERN_ERR "%s: init aborted!\n", ptr->name); - return; // something is wrong, its timed out!!!! - } -} - -/* ========================================================================= - CODEC API FUNCTIONS - - this functions are accessed by the master via the API structure - ========================================================================= */ - -/* set compression/expansion mode and launches codec - - this should be the last call from the master before starting processing */ -static int -zr36060_set_mode (struct videocodec *codec, - int mode) -{ - struct zr36060 *ptr = (struct zr36060 *) codec->data; - - dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); - - if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) - return -EINVAL; - - ptr->mode = mode; - zr36060_init(ptr); - - return 0; -} - -/* set picture size (norm is ignored as the codec doesn't know about it) */ -static int -zr36060_set_video (struct videocodec *codec, - struct tvnorm *norm, - struct vfe_settings *cap, - struct vfe_polarity *pol) -{ - struct zr36060 *ptr = (struct zr36060 *) codec->data; - u32 reg; - int size; - - dprintk(2, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr->name, - cap->x, cap->y, cap->width, cap->height, cap->decimation); - - /* if () return -EINVAL; - * trust the master driver that it knows what it does - so - * we allow invalid startx/y and norm for now ... */ - ptr->width = cap->width / (cap->decimation & 0xff); - ptr->height = cap->height / (cap->decimation >> 8); - - zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst); - - /* Note that VSPol/HSPol bits in zr36060 have the opposite - * meaning of their zr360x7 counterparts with the same names - * N.b. for VSPol this is only true if FIVEdge = 0 (default, - * left unchanged here - in accordance with datasheet). - */ - reg = (!pol->vsync_pol ? ZR060_VPR_VSPol : 0) - | (!pol->hsync_pol ? ZR060_VPR_HSPol : 0) - | (pol->field_pol ? ZR060_VPR_FIPol : 0) - | (pol->blank_pol ? ZR060_VPR_BLPol : 0) - | (pol->subimg_pol ? ZR060_VPR_SImgPol : 0) - | (pol->poe_pol ? ZR060_VPR_PoePol : 0) - | (pol->pvalid_pol ? ZR060_VPR_PValPol : 0) - | (pol->vclk_pol ? ZR060_VPR_VCLKPol : 0); - zr36060_write(ptr, ZR060_VPR, reg); - - reg = 0; - switch (cap->decimation & 0xff) { - default: - case 1: - break; - - case 2: - reg |= ZR060_SR_HScale2; - break; - - case 4: - reg |= ZR060_SR_HScale4; - break; - } - - switch (cap->decimation >> 8) { - default: - case 1: - break; - - case 2: - reg |= ZR060_SR_VScale; - break; - } - zr36060_write(ptr, ZR060_SR, reg); - - zr36060_write(ptr, ZR060_BCR_Y, 0x00); - zr36060_write(ptr, ZR060_BCR_U, 0x80); - zr36060_write(ptr, ZR060_BCR_V, 0x80); - - /* sync generator */ - - reg = norm->Ht - 1; /* Vtotal */ - zr36060_write(ptr, ZR060_SGR_VTOTAL_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SGR_VTOTAL_LO, (reg >> 0) & 0xff); - - reg = norm->Wt - 1; /* Htotal */ - zr36060_write(ptr, ZR060_SGR_HTOTAL_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SGR_HTOTAL_LO, (reg >> 0) & 0xff); - - reg = 6 - 1; /* VsyncSize */ - zr36060_write(ptr, ZR060_SGR_VSYNC, reg); - - //reg = 30 - 1; /* HsyncSize */ -///*CP*/ reg = (zr->params.norm == 1 ? 57 : 68); - reg = 68; - zr36060_write(ptr, ZR060_SGR_HSYNC, reg); - - reg = norm->VStart - 1; /* BVstart */ - zr36060_write(ptr, ZR060_SGR_BVSTART, reg); - - reg += norm->Ha / 2; /* BVend */ - zr36060_write(ptr, ZR060_SGR_BVEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SGR_BVEND_LO, (reg >> 0) & 0xff); - - reg = norm->HStart - 1; /* BHstart */ - zr36060_write(ptr, ZR060_SGR_BHSTART, reg); - - reg += norm->Wa; /* BHend */ - zr36060_write(ptr, ZR060_SGR_BHEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SGR_BHEND_LO, (reg >> 0) & 0xff); - - /* active area */ - reg = cap->y + norm->VStart; /* Vstart */ - zr36060_write(ptr, ZR060_AAR_VSTART_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_AAR_VSTART_LO, (reg >> 0) & 0xff); - - reg += cap->height; /* Vend */ - zr36060_write(ptr, ZR060_AAR_VEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_AAR_VEND_LO, (reg >> 0) & 0xff); - - reg = cap->x + norm->HStart; /* Hstart */ - zr36060_write(ptr, ZR060_AAR_HSTART_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_AAR_HSTART_LO, (reg >> 0) & 0xff); - - reg += cap->width; /* Hend */ - zr36060_write(ptr, ZR060_AAR_HEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_AAR_HEND_LO, (reg >> 0) & 0xff); - - /* subimage area */ - reg = norm->VStart - 4; /* SVstart */ - zr36060_write(ptr, ZR060_SWR_VSTART_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SWR_VSTART_LO, (reg >> 0) & 0xff); - - reg += norm->Ha / 2 + 8; /* SVend */ - zr36060_write(ptr, ZR060_SWR_VEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SWR_VEND_LO, (reg >> 0) & 0xff); - - reg = norm->HStart /*+ 64 */ - 4; /* SHstart */ - zr36060_write(ptr, ZR060_SWR_HSTART_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SWR_HSTART_LO, (reg >> 0) & 0xff); - - reg += norm->Wa + 8; /* SHend */ - zr36060_write(ptr, ZR060_SWR_HEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SWR_HEND_LO, (reg >> 0) & 0xff); - - size = ptr->width * ptr->height; - /* Target compressed field size in bits: */ - size = size * 16; /* uncompressed size in bits */ - /* (Ronald) by default, quality = 100 is a compression - * ratio 1:2. Setting low_bitrate (insmod option) sets - * it to 1:4 (instead of 1:2, zr36060 max) as limit because the - * buz can't handle more at decimation=1... Use low_bitrate if - * you have a Buz, unless you know what you're doing */ - size = size * cap->quality / (low_bitrate ? 400 : 200); - /* Lower limit (arbitrary, 1 KB) */ - if (size < 8192) - size = 8192; - /* Upper limit: 7/8 of the code buffers */ - if (size > ptr->total_code_vol * 7) - size = ptr->total_code_vol * 7; - - ptr->real_code_vol = size >> 3; /* in bytes */ - - /* the MBCVR is the *maximum* block volume, according to the - * JPEG ISO specs, this shouldn't be used, since that allows - * for the best encoding quality. So set it to it's max value */ - reg = ptr->max_block_vol; - zr36060_write(ptr, ZR060_MBCVR, reg); - - return 0; -} - -/* additional control functions */ -static int -zr36060_control (struct videocodec *codec, - int type, - int size, - void *data) -{ - struct zr36060 *ptr = (struct zr36060 *) codec->data; - int *ival = (int *) data; - - dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, - size); - - switch (type) { - case CODEC_G_STATUS: /* get last status */ - if (size != sizeof(int)) - return -EFAULT; - zr36060_read_status(ptr); - *ival = ptr->status; - break; - - case CODEC_G_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - *ival = CODEC_MODE_BJPG; - break; - - case CODEC_S_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - if (*ival != CODEC_MODE_BJPG) - return -EINVAL; - /* not needed, do nothing */ - return 0; - - case CODEC_G_VFE: - case CODEC_S_VFE: - /* not needed, do nothing */ - return 0; - - case CODEC_S_MMAP: - /* not available, give an error */ - return -ENXIO; - - case CODEC_G_JPEG_TDS_BYTE: /* get target volume in byte */ - if (size != sizeof(int)) - return -EFAULT; - *ival = ptr->total_code_vol; - break; - - case CODEC_S_JPEG_TDS_BYTE: /* get target volume in byte */ - if (size != sizeof(int)) - return -EFAULT; - ptr->total_code_vol = *ival; - ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; - break; - - case CODEC_G_JPEG_SCALE: /* get scaling factor */ - if (size != sizeof(int)) - return -EFAULT; - *ival = zr36060_read_scalefactor(ptr); - break; - - case CODEC_S_JPEG_SCALE: /* set scaling factor */ - if (size != sizeof(int)) - return -EFAULT; - ptr->scalefact = *ival; - break; - - case CODEC_G_JPEG_APP_DATA: { /* get appn marker data */ - struct jpeg_app_marker *app = data; - - if (size != sizeof(struct jpeg_app_marker)) - return -EFAULT; - - *app = ptr->app; - break; - } - - case CODEC_S_JPEG_APP_DATA: { /* set appn marker data */ - struct jpeg_app_marker *app = data; - - if (size != sizeof(struct jpeg_app_marker)) - return -EFAULT; - - ptr->app = *app; - break; - } - - case CODEC_G_JPEG_COM_DATA: { /* get comment marker data */ - struct jpeg_com_marker *com = data; - - if (size != sizeof(struct jpeg_com_marker)) - return -EFAULT; - - *com = ptr->com; - break; - } - - case CODEC_S_JPEG_COM_DATA: { /* set comment marker data */ - struct jpeg_com_marker *com = data; - - if (size != sizeof(struct jpeg_com_marker)) - return -EFAULT; - - ptr->com = *com; - break; - } - - default: - return -EINVAL; - } - - return size; -} - -/* ========================================================================= - Exit and unregister function: - - Deinitializes Zoran's JPEG processor - ========================================================================= */ - -static int -zr36060_unset (struct videocodec *codec) -{ - struct zr36060 *ptr = codec->data; - - if (ptr) { - /* do wee need some codec deinit here, too ???? */ - - dprintk(1, "%s: finished codec #%d\n", ptr->name, - ptr->num); - kfree(ptr); - codec->data = NULL; - - zr36060_codecs--; - return 0; - } - - return -EFAULT; -} - -/* ========================================================================= - Setup and registry function: - - Initializes Zoran's JPEG processor - - Also sets pixel size, average code size, mode (compr./decompr.) - (the given size is determined by the processor with the video interface) - ========================================================================= */ - -static int -zr36060_setup (struct videocodec *codec) -{ - struct zr36060 *ptr; - int res; - - dprintk(2, "zr36060: initializing MJPEG subsystem #%d.\n", - zr36060_codecs); - - if (zr36060_codecs == MAX_CODECS) { - dprintk(1, - KERN_ERR "zr36060: Can't attach more codecs!\n"); - return -ENOSPC; - } - //mem structure init - codec->data = ptr = kzalloc(sizeof(struct zr36060), GFP_KERNEL); - if (NULL == ptr) { - dprintk(1, KERN_ERR "zr36060: Can't get enough memory!\n"); - return -ENOMEM; - } - - snprintf(ptr->name, sizeof(ptr->name), "zr36060[%d]", - zr36060_codecs); - ptr->num = zr36060_codecs++; - ptr->codec = codec; - - //testing - res = zr36060_basic_test(ptr); - if (res < 0) { - zr36060_unset(codec); - return res; - } - //final setup - memcpy(ptr->h_samp_ratio, zr36060_decimation_h, 8); - memcpy(ptr->v_samp_ratio, zr36060_decimation_v, 8); - - ptr->bitrate_ctrl = 0; /* 0 or 1 - fixed file size flag - * (what is the difference?) */ - ptr->mode = CODEC_DO_COMPRESSION; - ptr->width = 384; - ptr->height = 288; - ptr->total_code_vol = 16000; /* CHECKME */ - ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; - ptr->max_block_vol = 240; /* CHECKME, was 120 is 240 */ - ptr->scalefact = 0x100; - ptr->dri = 1; /* CHECKME, was 8 is 1 */ - - /* by default, no COM or APP markers - app should set those */ - ptr->com.len = 0; - ptr->app.appn = 0; - ptr->app.len = 0; - - zr36060_init(ptr); - - dprintk(1, KERN_INFO "%s: codec attached and running\n", - ptr->name); - - return 0; -} - -static const struct videocodec zr36060_codec = { - .owner = THIS_MODULE, - .name = "zr36060", - .magic = 0L, // magic not used - .flags = - CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER | - CODEC_FLAG_DECODER | CODEC_FLAG_VFE, - .type = CODEC_TYPE_ZR36060, - .setup = zr36060_setup, // functionality - .unset = zr36060_unset, - .set_mode = zr36060_set_mode, - .set_video = zr36060_set_video, - .control = zr36060_control, - // others are not used -}; - -/* ========================================================================= - HOOK IN DRIVER AS KERNEL MODULE - ========================================================================= */ - -static int __init -zr36060_init_module (void) -{ - //dprintk(1, "zr36060 driver %s\n",ZR060_VERSION); - zr36060_codecs = 0; - return videocodec_register(&zr36060_codec); -} - -static void __exit -zr36060_cleanup_module (void) -{ - if (zr36060_codecs) { - dprintk(1, - "zr36060: something's wrong - %d codecs left somehow.\n", - zr36060_codecs); - } - - /* however, we can't just stay alive */ - videocodec_unregister(&zr36060_codec); -} - -module_init(zr36060_init_module); -module_exit(zr36060_cleanup_module); - -MODULE_AUTHOR("Laurent Pinchart "); -MODULE_DESCRIPTION("Driver module for ZR36060 jpeg processors " - ZR060_VERSION); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36060.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36060.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36060.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zoran/zr36060.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,220 +0,0 @@ -/* - * Zoran ZR36060 basic configuration functions - header file - * - * Copyright (C) 2002 Laurent Pinchart - * - * $Id: zr36060.h,v 1.1.1.1.2.3 2003/01/14 21:18:47 rbultje Exp $ - * - * ------------------------------------------------------------------------ - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ------------------------------------------------------------------------ - */ - -#ifndef ZR36060_H -#define ZR36060_H - -#include "videocodec.h" - -/* data stored for each zoran jpeg codec chip */ -struct zr36060 { - char name[32]; - int num; - /* io datastructure */ - struct videocodec *codec; - // last coder status - __u8 status; - // actual coder setup - int mode; - - __u16 width; - __u16 height; - - __u16 bitrate_ctrl; - - __u32 total_code_vol; - __u32 real_code_vol; - __u16 max_block_vol; - - __u8 h_samp_ratio[8]; - __u8 v_samp_ratio[8]; - __u16 scalefact; - __u16 dri; - - /* app/com marker data */ - struct jpeg_app_marker app; - struct jpeg_com_marker com; -}; - -/* ZR36060 register addresses */ -#define ZR060_LOAD 0x000 -#define ZR060_CFSR 0x001 -#define ZR060_CIR 0x002 -#define ZR060_CMR 0x003 -#define ZR060_MBZ 0x004 -#define ZR060_MBCVR 0x005 -#define ZR060_MER 0x006 -#define ZR060_IMR 0x007 -#define ZR060_ISR 0x008 -#define ZR060_TCV_NET_HI 0x009 -#define ZR060_TCV_NET_MH 0x00a -#define ZR060_TCV_NET_ML 0x00b -#define ZR060_TCV_NET_LO 0x00c -#define ZR060_TCV_DATA_HI 0x00d -#define ZR060_TCV_DATA_MH 0x00e -#define ZR060_TCV_DATA_ML 0x00f -#define ZR060_TCV_DATA_LO 0x010 -#define ZR060_SF_HI 0x011 -#define ZR060_SF_LO 0x012 -#define ZR060_AF_HI 0x013 -#define ZR060_AF_M 0x014 -#define ZR060_AF_LO 0x015 -#define ZR060_ACV_HI 0x016 -#define ZR060_ACV_MH 0x017 -#define ZR060_ACV_ML 0x018 -#define ZR060_ACV_LO 0x019 -#define ZR060_ACT_HI 0x01a -#define ZR060_ACT_MH 0x01b -#define ZR060_ACT_ML 0x01c -#define ZR060_ACT_LO 0x01d -#define ZR060_ACV_TRUN_HI 0x01e -#define ZR060_ACV_TRUN_MH 0x01f -#define ZR060_ACV_TRUN_ML 0x020 -#define ZR060_ACV_TRUN_LO 0x021 -#define ZR060_IDR_DEV 0x022 -#define ZR060_IDR_REV 0x023 -#define ZR060_TCR_HI 0x024 -#define ZR060_TCR_LO 0x025 -#define ZR060_VCR 0x030 -#define ZR060_VPR 0x031 -#define ZR060_SR 0x032 -#define ZR060_BCR_Y 0x033 -#define ZR060_BCR_U 0x034 -#define ZR060_BCR_V 0x035 -#define ZR060_SGR_VTOTAL_HI 0x036 -#define ZR060_SGR_VTOTAL_LO 0x037 -#define ZR060_SGR_HTOTAL_HI 0x038 -#define ZR060_SGR_HTOTAL_LO 0x039 -#define ZR060_SGR_VSYNC 0x03a -#define ZR060_SGR_HSYNC 0x03b -#define ZR060_SGR_BVSTART 0x03c -#define ZR060_SGR_BHSTART 0x03d -#define ZR060_SGR_BVEND_HI 0x03e -#define ZR060_SGR_BVEND_LO 0x03f -#define ZR060_SGR_BHEND_HI 0x040 -#define ZR060_SGR_BHEND_LO 0x041 -#define ZR060_AAR_VSTART_HI 0x042 -#define ZR060_AAR_VSTART_LO 0x043 -#define ZR060_AAR_VEND_HI 0x044 -#define ZR060_AAR_VEND_LO 0x045 -#define ZR060_AAR_HSTART_HI 0x046 -#define ZR060_AAR_HSTART_LO 0x047 -#define ZR060_AAR_HEND_HI 0x048 -#define ZR060_AAR_HEND_LO 0x049 -#define ZR060_SWR_VSTART_HI 0x04a -#define ZR060_SWR_VSTART_LO 0x04b -#define ZR060_SWR_VEND_HI 0x04c -#define ZR060_SWR_VEND_LO 0x04d -#define ZR060_SWR_HSTART_HI 0x04e -#define ZR060_SWR_HSTART_LO 0x04f -#define ZR060_SWR_HEND_HI 0x050 -#define ZR060_SWR_HEND_LO 0x051 - -#define ZR060_SOF_IDX 0x060 -#define ZR060_SOS_IDX 0x07a -#define ZR060_DRI_IDX 0x0c0 -#define ZR060_DQT_IDX 0x0cc -#define ZR060_DHT_IDX 0x1d4 -#define ZR060_APP_IDX 0x380 -#define ZR060_COM_IDX 0x3c0 - -/* ZR36060 LOAD register bits */ - -#define ZR060_LOAD_Load (1 << 7) -#define ZR060_LOAD_SyncRst (1 << 0) - -/* ZR36060 Code FIFO Status register bits */ - -#define ZR060_CFSR_Busy (1 << 7) -#define ZR060_CFSR_CBusy (1 << 2) -#define ZR060_CFSR_CFIFO (3 << 0) - -/* ZR36060 Code Interface register */ - -#define ZR060_CIR_Code16 (1 << 7) -#define ZR060_CIR_Endian (1 << 6) -#define ZR060_CIR_CFIS (1 << 2) -#define ZR060_CIR_CodeMstr (1 << 0) - -/* ZR36060 Codec Mode register */ - -#define ZR060_CMR_Comp (1 << 7) -#define ZR060_CMR_ATP (1 << 6) -#define ZR060_CMR_Pass2 (1 << 5) -#define ZR060_CMR_TLM (1 << 4) -#define ZR060_CMR_BRB (1 << 2) -#define ZR060_CMR_FSF (1 << 1) - -/* ZR36060 Markers Enable register */ - -#define ZR060_MER_App (1 << 7) -#define ZR060_MER_Com (1 << 6) -#define ZR060_MER_DRI (1 << 5) -#define ZR060_MER_DQT (1 << 4) -#define ZR060_MER_DHT (1 << 3) - -/* ZR36060 Interrupt Mask register */ - -#define ZR060_IMR_EOAV (1 << 3) -#define ZR060_IMR_EOI (1 << 2) -#define ZR060_IMR_End (1 << 1) -#define ZR060_IMR_DataErr (1 << 0) - -/* ZR36060 Interrupt Status register */ - -#define ZR060_ISR_ProCnt (3 << 6) -#define ZR060_ISR_EOAV (1 << 3) -#define ZR060_ISR_EOI (1 << 2) -#define ZR060_ISR_End (1 << 1) -#define ZR060_ISR_DataErr (1 << 0) - -/* ZR36060 Video Control register */ - -#define ZR060_VCR_Video8 (1 << 7) -#define ZR060_VCR_Range (1 << 6) -#define ZR060_VCR_FIDet (1 << 3) -#define ZR060_VCR_FIVedge (1 << 2) -#define ZR060_VCR_FIExt (1 << 1) -#define ZR060_VCR_SyncMstr (1 << 0) - -/* ZR36060 Video Polarity register */ - -#define ZR060_VPR_VCLKPol (1 << 7) -#define ZR060_VPR_PValPol (1 << 6) -#define ZR060_VPR_PoePol (1 << 5) -#define ZR060_VPR_SImgPol (1 << 4) -#define ZR060_VPR_BLPol (1 << 3) -#define ZR060_VPR_FIPol (1 << 2) -#define ZR060_VPR_HSPol (1 << 1) -#define ZR060_VPR_VSPol (1 << 0) - -/* ZR36060 Scaling register */ - -#define ZR060_SR_VScale (1 << 2) -#define ZR060_SR_HScale2 (1 << 0) -#define ZR060_SR_HScale4 (2 << 0) - -#endif /*fndef ZR36060_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zr364xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zr364xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zr364xx.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/media/video/zr364xx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1723 +0,0 @@ -/* - * Zoran 364xx based USB webcam module version 0.73 - * - * Allows you to use your USB webcam with V4L2 applications - * This is still in heavy developpement ! - * - * Copyright (C) 2004 Antoine Jacquet - * http://royale.zerezo.com/zr364xx/ - * - * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers - * V4L2 version inspired by meye.c driver - * - * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers. - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Version Information */ -#define DRIVER_VERSION "v0.73" -#define ZR364XX_VERSION_CODE KERNEL_VERSION(0, 7, 3) -#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" -#define DRIVER_DESC "Zoran 364xx" - - -/* Camera */ -#define FRAMES 1 -#define MAX_FRAME_SIZE 200000 -#define BUFFER_SIZE 0x1000 -#define CTRL_TIMEOUT 500 - -#define ZR364XX_DEF_BUFS 4 -#define ZR364XX_READ_IDLE 0 -#define ZR364XX_READ_FRAME 1 - -/* Debug macro */ -#define DBG(fmt, args...) \ - do { \ - if (debug) { \ - printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \ - } \ - } while (0) - -/*#define FULL_DEBUG 1*/ -#ifdef FULL_DEBUG -#define _DBG DBG -#else -#define _DBG(fmt, args...) -#endif - -/* Init methods, need to find nicer names for these - * the exact names of the chipsets would be the best if someone finds it */ -#define METHOD0 0 -#define METHOD1 1 -#define METHOD2 2 -#define METHOD3 3 - - -/* Module parameters */ -static int debug; -static int mode; - - -/* Module parameters interface */ -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level"); -module_param(mode, int, 0644); -MODULE_PARM_DESC(mode, "0 = 320x240, 1 = 160x120, 2 = 640x480"); - - -/* Devices supported by this driver - * .driver_info contains the init method used by the camera */ -static struct usb_device_id device_table[] = { - {USB_DEVICE(0x08ca, 0x0109), .driver_info = METHOD0 }, - {USB_DEVICE(0x041e, 0x4024), .driver_info = METHOD0 }, - {USB_DEVICE(0x0d64, 0x0108), .driver_info = METHOD0 }, - {USB_DEVICE(0x0546, 0x3187), .driver_info = METHOD0 }, - {USB_DEVICE(0x0d64, 0x3108), .driver_info = METHOD0 }, - {USB_DEVICE(0x0595, 0x4343), .driver_info = METHOD0 }, - {USB_DEVICE(0x0bb0, 0x500d), .driver_info = METHOD0 }, - {USB_DEVICE(0x0feb, 0x2004), .driver_info = METHOD0 }, - {USB_DEVICE(0x055f, 0xb500), .driver_info = METHOD0 }, - {USB_DEVICE(0x08ca, 0x2062), .driver_info = METHOD2 }, - {USB_DEVICE(0x052b, 0x1a18), .driver_info = METHOD1 }, - {USB_DEVICE(0x04c8, 0x0729), .driver_info = METHOD0 }, - {USB_DEVICE(0x04f2, 0xa208), .driver_info = METHOD0 }, - {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 }, - {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 }, - {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 }, - {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 }, - {USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 }, - {USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 }, - {USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD3 }, - {USB_DEVICE(0x06d6, 0x003d), .driver_info = METHOD0 }, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -struct zr364xx_mode { - u32 color; /* output video color format */ - u32 brightness; /* brightness */ -}; - -/* frame structure */ -struct zr364xx_framei { - unsigned long ulState; /* ulState:ZR364XX_READ_IDLE, - ZR364XX_READ_FRAME */ - void *lpvbits; /* image data */ - unsigned long cur_size; /* current data copied to it */ -}; - -/* image buffer structure */ -struct zr364xx_bufferi { - unsigned long dwFrames; /* number of frames in buffer */ - struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */ -}; - -struct zr364xx_dmaqueue { - struct list_head active; - struct zr364xx_camera *cam; -}; - -struct zr364xx_pipeinfo { - u32 transfer_size; - u8 *transfer_buffer; - u32 state; - void *stream_urb; - void *cam; /* back pointer to zr364xx_camera struct */ - u32 err_count; - u32 idx; -}; - -struct zr364xx_fmt { - char *name; - u32 fourcc; - int depth; -}; - -/* image formats. */ -static const struct zr364xx_fmt formats[] = { - { - .name = "JPG", - .fourcc = V4L2_PIX_FMT_JPEG, - .depth = 24 - } -}; - -/* Camera stuff */ -struct zr364xx_camera { - struct usb_device *udev; /* save off the usb device pointer */ - struct usb_interface *interface;/* the interface for this device */ - struct video_device *vdev; /* v4l video device */ - int nb; - struct zr364xx_bufferi buffer; - int skip; - int width; - int height; - int method; - struct mutex lock; - struct mutex open_lock; - int users; - - spinlock_t slock; - struct zr364xx_dmaqueue vidq; - int resources; - int last_frame; - int cur_frame; - unsigned long frame_count; - int b_acquire; - struct zr364xx_pipeinfo pipe[1]; - - u8 read_endpoint; - - const struct zr364xx_fmt *fmt; - struct videobuf_queue vb_vidq; - enum v4l2_buf_type type; - struct zr364xx_mode mode; -}; - -/* buffer for one video frame */ -struct zr364xx_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - const struct zr364xx_fmt *fmt; -}; - -/* function used to send initialisation commands to the camera */ -static int send_control_msg(struct usb_device *udev, u8 request, u16 value, - u16 index, unsigned char *cp, u16 size) -{ - int status; - - unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&udev->dev, "kmalloc(%d) failed\n", size); - return -ENOMEM; - } - - memcpy(transfer_buffer, cp, size); - - status = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, value, index, - transfer_buffer, size, CTRL_TIMEOUT); - - kfree(transfer_buffer); - - if (status < 0) - dev_err(&udev->dev, - "Failed sending control message, error %d.\n", status); - - return status; -} - - -/* Control messages sent to the camera to initialize it - * and launch the capture */ -typedef struct { - unsigned int value; - unsigned int size; - unsigned char *bytes; -} message; - -/* method 0 */ -static unsigned char m0d1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static unsigned char m0d2[] = { 0, 0, 0, 0, 0, 0 }; -static unsigned char m0d3[] = { 0, 0 }; -static message m0[] = { - {0x1f30, 0, NULL}, - {0xd000, 0, NULL}, - {0x3370, sizeof(m0d1), m0d1}, - {0x2000, 0, NULL}, - {0x2f0f, 0, NULL}, - {0x2610, sizeof(m0d2), m0d2}, - {0xe107, 0, NULL}, - {0x2502, 0, NULL}, - {0x1f70, 0, NULL}, - {0xd000, 0, NULL}, - {0x9a01, sizeof(m0d3), m0d3}, - {-1, -1, NULL} -}; - -/* method 1 */ -static unsigned char m1d1[] = { 0xff, 0xff }; -static unsigned char m1d2[] = { 0x00, 0x00 }; -static message m1[] = { - {0x1f30, 0, NULL}, - {0xd000, 0, NULL}, - {0xf000, 0, NULL}, - {0x2000, 0, NULL}, - {0x2f0f, 0, NULL}, - {0x2650, 0, NULL}, - {0xe107, 0, NULL}, - {0x2502, sizeof(m1d1), m1d1}, - {0x1f70, 0, NULL}, - {0xd000, 0, NULL}, - {0xd000, 0, NULL}, - {0xd000, 0, NULL}, - {0x9a01, sizeof(m1d2), m1d2}, - {-1, -1, NULL} -}; - -/* method 2 */ -static unsigned char m2d1[] = { 0xff, 0xff }; -static message m2[] = { - {0x1f30, 0, NULL}, - {0xf000, 0, NULL}, - {0x2000, 0, NULL}, - {0x2f0f, 0, NULL}, - {0x2650, 0, NULL}, - {0xe107, 0, NULL}, - {0x2502, sizeof(m2d1), m2d1}, - {0x1f70, 0, NULL}, - {-1, -1, NULL} -}; - -/* init table */ -static message *init[4] = { m0, m1, m2, m2 }; - - -/* JPEG static data in header (Huffman table, etc) */ -static unsigned char header1[] = { - 0xFF, 0xD8, - /* - 0xFF, 0xE0, 0x00, 0x10, 'J', 'F', 'I', 'F', - 0x00, 0x01, 0x01, 0x00, 0x33, 0x8A, 0x00, 0x00, 0x33, 0x88, - */ - 0xFF, 0xDB, 0x00, 0x84 -}; -static unsigned char header2[] = { - 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, - 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, - 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, - 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, - 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, - 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, - 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, - 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, - 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, - 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, - 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, - 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, - 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, - 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, - 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, - 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, - 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, - 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, - 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, - 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, - 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, - 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, - 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, - 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0xFA, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, - 0x40, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, - 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, - 0x00, 0x3F, 0x00 -}; -static unsigned char header3; - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ - -static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct zr364xx_camera *cam = vq->priv_data; - - *size = cam->width * cam->height * (cam->fmt->depth >> 3); - - if (*count == 0) - *count = ZR364XX_DEF_BUFS; - - if (*size * *count > ZR364XX_DEF_BUFS * 1024 * 1024) - *count = (ZR364XX_DEF_BUFS * 1024 * 1024) / *size; - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf) -{ - _DBG("%s\n", __func__); - - if (in_interrupt()) - BUG(); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct zr364xx_camera *cam = vq->priv_data; - struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, - vb); - int rc; - - DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ? - cam->fmt->name : ""); - if (cam->fmt == NULL) - return -EINVAL; - - buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3); - - if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) { - DBG("invalid buffer prepare\n"); - return -EINVAL; - } - - buf->fmt = cam->fmt; - buf->vb.width = cam->width; - buf->vb.height = cam->height; - buf->vb.field = field; - - if (buf->vb.state == VIDEOBUF_NEEDS_INIT) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; -fail: - free_buffer(vq, buf); - return rc; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, - vb); - struct zr364xx_camera *cam = vq->priv_data; - - _DBG("%s\n", __func__); - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &cam->vidq.active); -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, - vb); - - _DBG("%s\n", __func__); - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops zr364xx_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/********************/ -/* V4L2 integration */ -/********************/ -static int zr364xx_vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type); - -static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count, - loff_t * ppos) -{ - struct zr364xx_camera *cam = video_drvdata(file); - - _DBG("%s\n", __func__); - - if (!buf) - return -EINVAL; - - if (!count) - return -EINVAL; - - if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - zr364xx_vidioc_streamon(file, cam, cam->type) == 0) { - DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count, - (int) *ppos); - - /* NoMan Sux ! */ - return videobuf_read_one(&cam->vb_vidq, buf, count, ppos, - file->f_flags & O_NONBLOCK); - } - - return 0; -} - -/* video buffer vmalloc implementation based partly on VIVI driver which is - * Copyright (c) 2006 by - * Mauro Carvalho Chehab - * Ted Walther - * John Sokol - * http://v4l.videotechnology.com/ - * - */ -static void zr364xx_fillbuff(struct zr364xx_camera *cam, - struct zr364xx_buffer *buf, - int jpgsize) -{ - int pos = 0; - struct timeval ts; - const char *tmpbuf; - char *vbuf = videobuf_to_vmalloc(&buf->vb); - unsigned long last_frame; - struct zr364xx_framei *frm; - - if (!vbuf) - return; - - last_frame = cam->last_frame; - if (last_frame != -1) { - frm = &cam->buffer.frame[last_frame]; - tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits; - switch (buf->fmt->fourcc) { - case V4L2_PIX_FMT_JPEG: - buf->vb.size = jpgsize; - memcpy(vbuf, tmpbuf, buf->vb.size); - break; - default: - printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n"); - } - cam->last_frame = -1; - } else { - printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n"); - return; - } - DBG("%s: Buffer 0x%08lx size= %d\n", __func__, - (unsigned long)vbuf, pos); - /* tell v4l buffer was filled */ - - buf->vb.field_count = cam->frame_count * 2; - do_gettimeofday(&ts); - buf->vb.ts = ts; - buf->vb.state = VIDEOBUF_DONE; -} - -static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize) -{ - struct zr364xx_dmaqueue *dma_q = &cam->vidq; - struct zr364xx_buffer *buf; - unsigned long flags = 0; - int rc = 0; - - DBG("wakeup: %p\n", &dma_q); - spin_lock_irqsave(&cam->slock, flags); - - if (list_empty(&dma_q->active)) { - DBG("No active queue to serve\n"); - rc = -1; - goto unlock; - } - buf = list_entry(dma_q->active.next, - struct zr364xx_buffer, vb.queue); - - if (!waitqueue_active(&buf->vb.done)) { - /* no one active */ - rc = -1; - goto unlock; - } - list_del(&buf->vb.queue); - do_gettimeofday(&buf->vb.ts); - DBG("[%p/%d] wakeup\n", buf, buf->vb.i); - zr364xx_fillbuff(cam, buf, jpgsize); - wake_up(&buf->vb.done); - DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i); -unlock: - spin_unlock_irqrestore(&cam->slock, flags); - return rc; -} - -/* this function moves the usb stream read pipe data - * into the system buffers. - * returns 0 on success, EAGAIN if more data to process (call this - * function again). - */ -static int zr364xx_read_video_callback(struct zr364xx_camera *cam, - struct zr364xx_pipeinfo *pipe_info, - struct urb *purb) -{ - unsigned char *pdest; - unsigned char *psrc; - s32 idx = -1; - struct zr364xx_framei *frm; - int i = 0; - unsigned char *ptr = NULL; - - _DBG("buffer to user\n"); - idx = cam->cur_frame; - frm = &cam->buffer.frame[idx]; - - /* swap bytes if camera needs it */ - if (cam->method == METHOD0) { - u16 *buf = (u16 *)pipe_info->transfer_buffer; - for (i = 0; i < purb->actual_length/2; i++) - swab16s(buf + i); - } - - /* search done. now find out if should be acquiring */ - if (!cam->b_acquire) { - /* we found a frame, but this channel is turned off */ - frm->ulState = ZR364XX_READ_IDLE; - return -EINVAL; - } - - psrc = (u8 *)pipe_info->transfer_buffer; - ptr = pdest = frm->lpvbits; - - if (frm->ulState == ZR364XX_READ_IDLE) { - frm->ulState = ZR364XX_READ_FRAME; - frm->cur_size = 0; - - _DBG("jpeg header, "); - memcpy(ptr, header1, sizeof(header1)); - ptr += sizeof(header1); - header3 = 0; - memcpy(ptr, &header3, 1); - ptr++; - memcpy(ptr, psrc, 64); - ptr += 64; - header3 = 1; - memcpy(ptr, &header3, 1); - ptr++; - memcpy(ptr, psrc + 64, 64); - ptr += 64; - memcpy(ptr, header2, sizeof(header2)); - ptr += sizeof(header2); - memcpy(ptr, psrc + 128, - purb->actual_length - 128); - ptr += purb->actual_length - 128; - _DBG("header : %d %d %d %d %d %d %d %d %d\n", - psrc[0], psrc[1], psrc[2], - psrc[3], psrc[4], psrc[5], - psrc[6], psrc[7], psrc[8]); - frm->cur_size = ptr - pdest; - } else { - if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) { - dev_info(&cam->udev->dev, - "%s: buffer (%d bytes) too small to hold " - "frame data. Discarding frame data.\n", - __func__, MAX_FRAME_SIZE); - } else { - pdest += frm->cur_size; - memcpy(pdest, psrc, purb->actual_length); - frm->cur_size += purb->actual_length; - } - } - /*_DBG("cur_size %lu urb size %d\n", frm->cur_size, - purb->actual_length);*/ - - if (purb->actual_length < pipe_info->transfer_size) { - _DBG("****************Buffer[%d]full*************\n", idx); - cam->last_frame = cam->cur_frame; - cam->cur_frame++; - /* end of system frame ring buffer, start at zero */ - if (cam->cur_frame == cam->buffer.dwFrames) - cam->cur_frame = 0; - - /* frame ready */ - /* go back to find the JPEG EOI marker */ - ptr = pdest = frm->lpvbits; - ptr += frm->cur_size - 2; - while (ptr > pdest) { - if (*ptr == 0xFF && *(ptr + 1) == 0xD9 - && *(ptr + 2) == 0xFF) - break; - ptr--; - } - if (ptr == pdest) - DBG("No EOI marker\n"); - - /* Sometimes there is junk data in the middle of the picture, - * we want to skip this bogus frames */ - while (ptr > pdest) { - if (*ptr == 0xFF && *(ptr + 1) == 0xFF - && *(ptr + 2) == 0xFF) - break; - ptr--; - } - if (ptr != pdest) { - DBG("Bogus frame ? %d\n", ++(cam->nb)); - } else if (cam->b_acquire) { - /* we skip the 2 first frames which are usually buggy */ - if (cam->skip) - cam->skip--; - else { - _DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n", - frm->cur_size, - pdest[0], pdest[1], pdest[2], pdest[3], - pdest[4], pdest[5], pdest[6], pdest[7]); - - zr364xx_got_frame(cam, frm->cur_size); - } - } - cam->frame_count++; - frm->ulState = ZR364XX_READ_IDLE; - frm->cur_size = 0; - } - /* done successfully */ - return 0; -} - -static int res_get(struct zr364xx_camera *cam) -{ - /* is it free? */ - mutex_lock(&cam->lock); - if (cam->resources) { - /* no, someone else uses it */ - mutex_unlock(&cam->lock); - return 0; - } - /* it's free, grab it */ - cam->resources = 1; - _DBG("res: get\n"); - mutex_unlock(&cam->lock); - return 1; -} - -static inline int res_check(struct zr364xx_camera *cam) -{ - return cam->resources; -} - -static void res_free(struct zr364xx_camera *cam) -{ - mutex_lock(&cam->lock); - cam->resources = 0; - mutex_unlock(&cam->lock); - _DBG("res: put\n"); -} - -static int zr364xx_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct zr364xx_camera *cam = video_drvdata(file); - - strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver)); - strlcpy(cap->card, cam->udev->product, sizeof(cap->card)); - strlcpy(cap->bus_info, dev_name(&cam->udev->dev), - sizeof(cap->bus_info)); - cap->version = ZR364XX_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - return 0; -} - -static int zr364xx_vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - strcpy(i->name, DRIVER_DESC " Camera"); - i->type = V4L2_INPUT_TYPE_CAMERA; - return 0; -} - -static int zr364xx_vidioc_g_input(struct file *file, void *priv, - unsigned int *i) -{ - *i = 0; - return 0; -} - -static int zr364xx_vidioc_s_input(struct file *file, void *priv, - unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int zr364xx_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct zr364xx_camera *cam; - - if (file == NULL) - return -ENODEV; - cam = video_drvdata(file); - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Brightness"); - c->minimum = 0; - c->maximum = 127; - c->step = 1; - c->default_value = cam->mode.brightness; - c->flags = 0; - break; - default: - return -EINVAL; - } - return 0; -} - -static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct zr364xx_camera *cam; - int temp; - - if (file == NULL) - return -ENODEV; - cam = video_drvdata(file); - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - cam->mode.brightness = c->value; - /* hardware brightness */ - mutex_lock(&cam->lock); - send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0); - temp = (0x60 << 8) + 127 - cam->mode.brightness; - send_control_msg(cam->udev, 1, temp, 0, NULL, 0); - mutex_unlock(&cam->lock); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct zr364xx_camera *cam; - - if (file == NULL) - return -ENODEV; - cam = video_drvdata(file); - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = cam->mode.brightness; - break; - default: - return -EINVAL; - } - return 0; -} - -static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file, - void *priv, struct v4l2_fmtdesc *f) -{ - if (f->index > 0) - return -EINVAL; - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strcpy(f->description, formats[0].name); - f->pixelformat = formats[0].fourcc; - return 0; -} - -static char *decode_fourcc(__u32 pixelformat, char *buf) -{ - buf[0] = pixelformat & 0xff; - buf[1] = (pixelformat >> 8) & 0xff; - buf[2] = (pixelformat >> 16) & 0xff; - buf[3] = (pixelformat >> 24) & 0xff; - buf[4] = '\0'; - return buf; -} - -static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct zr364xx_camera *cam = video_drvdata(file); - char pixelformat_name[5]; - - if (cam == NULL) - return -ENODEV; - - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) { - DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__, - decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name)); - return -EINVAL; - } - - if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) && - !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) { - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - } - - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - f->fmt.pix.priv = 0; - DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, - decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), - f->fmt.pix.field); - return 0; -} - -static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct zr364xx_camera *cam; - - if (file == NULL) - return -ENODEV; - cam = video_drvdata(file); - - f->fmt.pix.pixelformat = formats[0].fourcc; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.width = cam->width; - f->fmt.pix.height = cam->height; - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - f->fmt.pix.priv = 0; - return 0; -} - -static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct zr364xx_camera *cam = video_drvdata(file); - struct videobuf_queue *q = &cam->vb_vidq; - char pixelformat_name[5]; - int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f); - int i; - - if (ret < 0) - return ret; - - mutex_lock(&q->vb_lock); - - if (videobuf_queue_is_busy(&cam->vb_vidq)) { - DBG("%s queue busy\n", __func__); - ret = -EBUSY; - goto out; - } - - if (res_check(cam)) { - DBG("%s can't change format after started\n", __func__); - ret = -EBUSY; - goto out; - } - - cam->width = f->fmt.pix.width; - cam->height = f->fmt.pix.height; - dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__, - cam->width, cam->height); - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - f->fmt.pix.priv = 0; - cam->vb_vidq.field = f->fmt.pix.field; - cam->mode.color = V4L2_PIX_FMT_JPEG; - - if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120) - mode = 1; - else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480) - mode = 2; - else - mode = 0; - - m0d1[0] = mode; - m1[2].value = 0xf000 + mode; - m2[1].value = 0xf000 + mode; - - /* special case for METHOD3, the modes are different */ - if (cam->method == METHOD3) { - switch (mode) { - case 1: - m2[1].value = 0xf000 + 4; - break; - case 2: - m2[1].value = 0xf000 + 0; - break; - default: - m2[1].value = 0xf000 + 1; - break; - } - } - - header2[437] = cam->height / 256; - header2[438] = cam->height % 256; - header2[439] = cam->width / 256; - header2[440] = cam->width % 256; - - for (i = 0; init[cam->method][i].size != -1; i++) { - ret = - send_control_msg(cam->udev, 1, init[cam->method][i].value, - 0, init[cam->method][i].bytes, - init[cam->method][i].size); - if (ret < 0) { - dev_err(&cam->udev->dev, - "error during resolution change sequence: %d\n", i); - goto out; - } - } - - /* Added some delay here, since opening/closing the camera quickly, - * like Ekiga does during its startup, can crash the webcam - */ - mdelay(100); - cam->skip = 2; - ret = 0; - -out: - mutex_unlock(&q->vb_lock); - - DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, - decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), - f->fmt.pix.field); - return ret; -} - -static int zr364xx_vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - int rc; - struct zr364xx_camera *cam = video_drvdata(file); - rc = videobuf_reqbufs(&cam->vb_vidq, p); - return rc; -} - -static int zr364xx_vidioc_querybuf(struct file *file, - void *priv, - struct v4l2_buffer *p) -{ - int rc; - struct zr364xx_camera *cam = video_drvdata(file); - rc = videobuf_querybuf(&cam->vb_vidq, p); - return rc; -} - -static int zr364xx_vidioc_qbuf(struct file *file, - void *priv, - struct v4l2_buffer *p) -{ - int rc; - struct zr364xx_camera *cam = video_drvdata(file); - _DBG("%s\n", __func__); - rc = videobuf_qbuf(&cam->vb_vidq, p); - return rc; -} - -static int zr364xx_vidioc_dqbuf(struct file *file, - void *priv, - struct v4l2_buffer *p) -{ - int rc; - struct zr364xx_camera *cam = video_drvdata(file); - _DBG("%s\n", __func__); - rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK); - return rc; -} - -static void read_pipe_completion(struct urb *purb) -{ - struct zr364xx_pipeinfo *pipe_info; - struct zr364xx_camera *cam; - int pipe; - - pipe_info = purb->context; - _DBG("%s %p, status %d\n", __func__, purb, purb->status); - if (pipe_info == NULL) { - printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); - return; - } - - cam = pipe_info->cam; - if (cam == NULL) { - printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); - return; - } - - /* if shutting down, do not resubmit, exit immediately */ - if (purb->status == -ESHUTDOWN) { - DBG("%s, err shutdown\n", __func__); - pipe_info->err_count++; - return; - } - - if (pipe_info->state == 0) { - DBG("exiting USB pipe\n"); - return; - } - - if (purb->actual_length < 0 || - purb->actual_length > pipe_info->transfer_size) { - dev_err(&cam->udev->dev, "wrong number of bytes\n"); - return; - } - - if (purb->status == 0) - zr364xx_read_video_callback(cam, pipe_info, purb); - else { - pipe_info->err_count++; - DBG("%s: failed URB %d\n", __func__, purb->status); - } - - pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint); - - /* reuse urb */ - usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev, - pipe, - pipe_info->transfer_buffer, - pipe_info->transfer_size, - read_pipe_completion, pipe_info); - - if (pipe_info->state != 0) { - purb->status = usb_submit_urb(pipe_info->stream_urb, - GFP_ATOMIC); - - if (purb->status) - dev_err(&cam->udev->dev, - "error submitting urb (error=%i)\n", - purb->status); - } else - DBG("read pipe complete state 0\n"); -} - -static int zr364xx_start_readpipe(struct zr364xx_camera *cam) -{ - int pipe; - int retval; - struct zr364xx_pipeinfo *pipe_info = cam->pipe; - pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint); - DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint); - - pipe_info->state = 1; - pipe_info->err_count = 0; - pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pipe_info->stream_urb) { - dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n"); - return -ENOMEM; - } - /* transfer buffer allocated in board_init */ - usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev, - pipe, - pipe_info->transfer_buffer, - pipe_info->transfer_size, - read_pipe_completion, pipe_info); - - DBG("submitting URB %p\n", pipe_info->stream_urb); - retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); - if (retval) { - printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n"); - return retval; - } - - return 0; -} - -static void zr364xx_stop_readpipe(struct zr364xx_camera *cam) -{ - struct zr364xx_pipeinfo *pipe_info; - - if (cam == NULL) { - printk(KERN_ERR KBUILD_MODNAME ": invalid device\n"); - return; - } - DBG("stop read pipe\n"); - pipe_info = cam->pipe; - if (pipe_info) { - if (pipe_info->state != 0) - pipe_info->state = 0; - - if (pipe_info->stream_urb) { - /* cancel urb */ - usb_kill_urb(pipe_info->stream_urb); - usb_free_urb(pipe_info->stream_urb); - pipe_info->stream_urb = NULL; - } - } - return; -} - -/* starts acquisition process */ -static int zr364xx_start_acquire(struct zr364xx_camera *cam) -{ - int j; - - DBG("start acquire\n"); - - cam->last_frame = -1; - cam->cur_frame = 0; - for (j = 0; j < FRAMES; j++) { - cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE; - cam->buffer.frame[j].cur_size = 0; - } - cam->b_acquire = 1; - return 0; -} - -static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam) -{ - cam->b_acquire = 0; - return 0; -} - -static int zr364xx_vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct zr364xx_camera *cam = video_drvdata(file); - int j; - int res; - - DBG("%s\n", __func__); - - if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&cam->udev->dev, "invalid fh type0\n"); - return -EINVAL; - } - if (cam->type != type) { - dev_err(&cam->udev->dev, "invalid fh type1\n"); - return -EINVAL; - } - - if (!res_get(cam)) { - dev_err(&cam->udev->dev, "stream busy\n"); - return -EBUSY; - } - - cam->last_frame = -1; - cam->cur_frame = 0; - cam->frame_count = 0; - for (j = 0; j < FRAMES; j++) { - cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE; - cam->buffer.frame[j].cur_size = 0; - } - res = videobuf_streamon(&cam->vb_vidq); - if (res == 0) { - zr364xx_start_acquire(cam); - } else { - res_free(cam); - } - return res; -} - -static int zr364xx_vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - int res; - struct zr364xx_camera *cam = video_drvdata(file); - - DBG("%s\n", __func__); - if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&cam->udev->dev, "invalid fh type0\n"); - return -EINVAL; - } - if (cam->type != type) { - dev_err(&cam->udev->dev, "invalid fh type1\n"); - return -EINVAL; - } - zr364xx_stop_acquire(cam); - res = videobuf_streamoff(&cam->vb_vidq); - if (res < 0) - return res; - res_free(cam); - return 0; -} - - -/* open the camera */ -static int zr364xx_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct zr364xx_camera *cam = video_drvdata(file); - struct usb_device *udev = cam->udev; - int i, err; - - DBG("%s\n", __func__); - - mutex_lock(&cam->open_lock); - - if (cam->users) { - err = -EBUSY; - goto out; - } - - for (i = 0; init[cam->method][i].size != -1; i++) { - err = - send_control_msg(udev, 1, init[cam->method][i].value, - 0, init[cam->method][i].bytes, - init[cam->method][i].size); - if (err < 0) { - dev_err(&cam->udev->dev, - "error during open sequence: %d\n", i); - goto out; - } - } - - cam->skip = 2; - cam->users++; - file->private_data = vdev; - cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cam->fmt = formats; - - videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops, - NULL, &cam->slock, - cam->type, - V4L2_FIELD_NONE, - sizeof(struct zr364xx_buffer), cam, NULL); - - /* Added some delay here, since opening/closing the camera quickly, - * like Ekiga does during its startup, can crash the webcam - */ - mdelay(100); - err = 0; - -out: - mutex_unlock(&cam->open_lock); - DBG("%s: %d\n", __func__, err); - return err; -} - -static void zr364xx_destroy(struct zr364xx_camera *cam) -{ - unsigned long i; - - if (!cam) { - printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__); - return; - } - mutex_lock(&cam->open_lock); - if (cam->vdev) - video_unregister_device(cam->vdev); - cam->vdev = NULL; - - /* stops the read pipe if it is running */ - if (cam->b_acquire) - zr364xx_stop_acquire(cam); - - zr364xx_stop_readpipe(cam); - - /* release sys buffers */ - for (i = 0; i < FRAMES; i++) { - if (cam->buffer.frame[i].lpvbits) { - DBG("vfree %p\n", cam->buffer.frame[i].lpvbits); - vfree(cam->buffer.frame[i].lpvbits); - } - cam->buffer.frame[i].lpvbits = NULL; - } - - /* release transfer buffer */ - kfree(cam->pipe->transfer_buffer); - cam->pipe->transfer_buffer = NULL; - mutex_unlock(&cam->open_lock); - kfree(cam); - cam = NULL; -} - -/* release the camera */ -static int zr364xx_release(struct file *file) -{ - struct zr364xx_camera *cam; - struct usb_device *udev; - int i, err; - - DBG("%s\n", __func__); - cam = video_drvdata(file); - - if (!cam) - return -ENODEV; - - mutex_lock(&cam->open_lock); - udev = cam->udev; - - /* turn off stream */ - if (res_check(cam)) { - if (cam->b_acquire) - zr364xx_stop_acquire(cam); - videobuf_streamoff(&cam->vb_vidq); - res_free(cam); - } - - cam->users--; - file->private_data = NULL; - - for (i = 0; i < 2; i++) { - err = - send_control_msg(udev, 1, init[cam->method][i].value, - 0, init[cam->method][i].bytes, - init[cam->method][i].size); - if (err < 0) { - dev_err(&udev->dev, "error during release sequence\n"); - goto out; - } - } - - /* Added some delay here, since opening/closing the camera quickly, - * like Ekiga does during its startup, can crash the webcam - */ - mdelay(100); - err = 0; - -out: - mutex_unlock(&cam->open_lock); - - return err; -} - - -static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct zr364xx_camera *cam = video_drvdata(file); - int ret; - - if (cam == NULL) { - DBG("%s: cam == NULL\n", __func__); - return -ENODEV; - } - DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma); - - ret = videobuf_mmap_mapper(&cam->vb_vidq, vma); - - DBG("vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret); - return ret; -} - -static unsigned int zr364xx_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct zr364xx_camera *cam = video_drvdata(file); - struct videobuf_queue *q = &cam->vb_vidq; - _DBG("%s\n", __func__); - - if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return POLLERR; - - return videobuf_poll_stream(file, q, wait); -} - -static const struct v4l2_file_operations zr364xx_fops = { - .owner = THIS_MODULE, - .open = zr364xx_open, - .release = zr364xx_release, - .read = zr364xx_read, - .mmap = zr364xx_mmap, - .ioctl = video_ioctl2, - .poll = zr364xx_poll, -}; - -static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = { - .vidioc_querycap = zr364xx_vidioc_querycap, - .vidioc_enum_fmt_vid_cap = zr364xx_vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = zr364xx_vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = zr364xx_vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = zr364xx_vidioc_g_fmt_vid_cap, - .vidioc_enum_input = zr364xx_vidioc_enum_input, - .vidioc_g_input = zr364xx_vidioc_g_input, - .vidioc_s_input = zr364xx_vidioc_s_input, - .vidioc_streamon = zr364xx_vidioc_streamon, - .vidioc_streamoff = zr364xx_vidioc_streamoff, - .vidioc_queryctrl = zr364xx_vidioc_queryctrl, - .vidioc_g_ctrl = zr364xx_vidioc_g_ctrl, - .vidioc_s_ctrl = zr364xx_vidioc_s_ctrl, - .vidioc_reqbufs = zr364xx_vidioc_reqbufs, - .vidioc_querybuf = zr364xx_vidioc_querybuf, - .vidioc_qbuf = zr364xx_vidioc_qbuf, - .vidioc_dqbuf = zr364xx_vidioc_dqbuf, -}; - -static struct video_device zr364xx_template = { - .name = DRIVER_DESC, - .fops = &zr364xx_fops, - .ioctl_ops = &zr364xx_ioctl_ops, - .release = video_device_release, -}; - - - -/*******************/ -/* USB integration */ -/*******************/ -static int zr364xx_board_init(struct zr364xx_camera *cam) -{ - struct zr364xx_pipeinfo *pipe = cam->pipe; - unsigned long i; - - DBG("board init: %p\n", cam); - memset(pipe, 0, sizeof(*pipe)); - pipe->cam = cam; - pipe->transfer_size = BUFFER_SIZE; - - pipe->transfer_buffer = kzalloc(pipe->transfer_size, - GFP_KERNEL); - if (pipe->transfer_buffer == NULL) { - DBG("out of memory!\n"); - return -ENOMEM; - } - - cam->b_acquire = 0; - cam->frame_count = 0; - - /*** start create system buffers ***/ - for (i = 0; i < FRAMES; i++) { - /* always allocate maximum size for system buffers */ - cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE); - - DBG("valloc %p, idx %lu, pdata %p\n", - &cam->buffer.frame[i], i, - cam->buffer.frame[i].lpvbits); - if (cam->buffer.frame[i].lpvbits == NULL) { - printk(KERN_INFO KBUILD_MODNAME ": out of memory. " - "Using less frames\n"); - break; - } - } - - if (i == 0) { - printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n"); - kfree(cam->pipe->transfer_buffer); - cam->pipe->transfer_buffer = NULL; - return -ENOMEM; - } else - cam->buffer.dwFrames = i; - - /* make sure internal states are set */ - for (i = 0; i < FRAMES; i++) { - cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE; - cam->buffer.frame[i].cur_size = 0; - } - - cam->cur_frame = 0; - cam->last_frame = -1; - /*** end create system buffers ***/ - - /* start read pipe */ - zr364xx_start_readpipe(cam); - DBG(": board initialized\n"); - return 0; -} - -static int zr364xx_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct zr364xx_camera *cam = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int err; - int i; - - DBG("probing...\n"); - - dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n"); - dev_info(&intf->dev, "model %04x:%04x detected\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - - cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL); - if (cam == NULL) { - dev_err(&udev->dev, "cam: out of memory !\n"); - return -ENOMEM; - } - /* save the init method used by this camera */ - cam->method = id->driver_info; - - cam->vdev = video_device_alloc(); - if (cam->vdev == NULL) { - dev_err(&udev->dev, "cam->vdev: out of memory !\n"); - kfree(cam); - cam = NULL; - return -ENOMEM; - } - memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template)); - cam->vdev->parent = &intf->dev; - video_set_drvdata(cam->vdev, cam); - if (debug) - cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; - - cam->udev = udev; - - switch (mode) { - case 1: - dev_info(&udev->dev, "160x120 mode selected\n"); - cam->width = 160; - cam->height = 120; - break; - case 2: - dev_info(&udev->dev, "640x480 mode selected\n"); - cam->width = 640; - cam->height = 480; - break; - default: - dev_info(&udev->dev, "320x240 mode selected\n"); - cam->width = 320; - cam->height = 240; - break; - } - - m0d1[0] = mode; - m1[2].value = 0xf000 + mode; - m2[1].value = 0xf000 + mode; - - /* special case for METHOD3, the modes are different */ - if (cam->method == METHOD3) { - switch (mode) { - case 1: - m2[1].value = 0xf000 + 4; - break; - case 2: - m2[1].value = 0xf000 + 0; - break; - default: - m2[1].value = 0xf000 + 1; - break; - } - } - - header2[437] = cam->height / 256; - header2[438] = cam->height % 256; - header2[439] = cam->width / 256; - header2[440] = cam->width % 256; - - cam->users = 0; - cam->nb = 0; - cam->mode.brightness = 64; - mutex_init(&cam->lock); - mutex_init(&cam->open_lock); - - DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf); - - /* set up the endpoint information */ - iface_desc = intf->cur_altsetting; - DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints); - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { - /* we found the bulk in endpoint */ - cam->read_endpoint = endpoint->bEndpointAddress; - } - } - - if (!cam->read_endpoint) { - dev_err(&intf->dev, "Could not find bulk-in endpoint\n"); - return -ENOMEM; - } - - /* v4l */ - INIT_LIST_HEAD(&cam->vidq.active); - cam->vidq.cam = cam; - err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1); - if (err) { - dev_err(&udev->dev, "video_register_device failed\n"); - video_device_release(cam->vdev); - kfree(cam); - cam = NULL; - return err; - } - - usb_set_intfdata(intf, cam); - - /* load zr364xx board specific */ - err = zr364xx_board_init(cam); - if (err) { - spin_lock_init(&cam->slock); - return err; - } - - spin_lock_init(&cam->slock); - - dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n", - video_device_node_name(cam->vdev)); - return 0; -} - - -static void zr364xx_disconnect(struct usb_interface *intf) -{ - struct zr364xx_camera *cam = usb_get_intfdata(intf); - videobuf_mmap_free(&cam->vb_vidq); - usb_set_intfdata(intf, NULL); - dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n"); - zr364xx_destroy(cam); -} - - - -/**********************/ -/* Module integration */ -/**********************/ - -static struct usb_driver zr364xx_driver = { - .name = "zr364xx", - .probe = zr364xx_probe, - .disconnect = zr364xx_disconnect, - .id_table = device_table -}; - - -static int __init zr364xx_init(void) -{ - int retval; - retval = usb_register(&zr364xx_driver); - if (retval) - printk(KERN_ERR KBUILD_MODNAME ": usb_register failed!\n"); - else - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - return retval; -} - - -static void __exit zr364xx_exit(void) -{ - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC " module unloaded\n"); - usb_deregister(&zr364xx_driver); -} - - -module_init(zr364xx_init); -module_exit(zr364xx_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2527 +0,0 @@ -/* - * altera.c - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010,2011 NetUP Inc. - * Copyright (C) 2010,2011 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include "altera-exprt.h" -#include "altera-jtag.h" - -static int debug = 1; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debugging information"); - -MODULE_DESCRIPTION("altera FPGA kernel module"); -MODULE_AUTHOR("Igor M. Liplianin "); -MODULE_LICENSE("GPL"); - -#define dprintk(args...) \ - if (debug) { \ - printk(KERN_DEBUG args); \ - } - -enum altera_fpga_opcode { - OP_NOP = 0, - OP_DUP, - OP_SWP, - OP_ADD, - OP_SUB, - OP_MULT, - OP_DIV, - OP_MOD, - OP_SHL, - OP_SHR, - OP_NOT, - OP_AND, - OP_OR, - OP_XOR, - OP_INV, - OP_GT, - OP_LT, - OP_RET, - OP_CMPS, - OP_PINT, - OP_PRNT, - OP_DSS, - OP_DSSC, - OP_ISS, - OP_ISSC, - OP_DPR = 0x1c, - OP_DPRL, - OP_DPO, - OP_DPOL, - OP_IPR, - OP_IPRL, - OP_IPO, - OP_IPOL, - OP_PCHR, - OP_EXIT, - OP_EQU, - OP_POPT, - OP_ABS = 0x2c, - OP_BCH0, - OP_PSH0 = 0x2f, - OP_PSHL = 0x40, - OP_PSHV, - OP_JMP, - OP_CALL, - OP_NEXT, - OP_PSTR, - OP_SINT = 0x47, - OP_ST, - OP_ISTP, - OP_DSTP, - OP_SWPN, - OP_DUPN, - OP_POPV, - OP_POPE, - OP_POPA, - OP_JMPZ, - OP_DS, - OP_IS, - OP_DPRA, - OP_DPOA, - OP_IPRA, - OP_IPOA, - OP_EXPT, - OP_PSHE, - OP_PSHA, - OP_DYNA, - OP_EXPV = 0x5c, - OP_COPY = 0x80, - OP_REVA, - OP_DSC, - OP_ISC, - OP_WAIT, - OP_VS, - OP_CMPA = 0xc0, - OP_VSC, -}; - -struct altera_procinfo { - char *name; - u8 attrs; - struct altera_procinfo *next; -}; - -/* This function checks if enough parameters are available on the stack. */ -static int altera_check_stack(int stack_ptr, int count, int *status) -{ - if (stack_ptr < count) { - *status = -EOVERFLOW; - return 0; - } - - return 1; -} - -static void altera_export_int(char *key, s32 value) -{ - dprintk("Export: key = \"%s\", value = %d\n", key, value); -} - -#define HEX_LINE_CHARS 72 -#define HEX_LINE_BITS (HEX_LINE_CHARS * 4) - -static void altera_export_bool_array(char *key, u8 *data, s32 count) -{ - char string[HEX_LINE_CHARS + 1]; - s32 i, offset; - u32 size, line, lines, linebits, value, j, k; - - if (count > HEX_LINE_BITS) { - dprintk("Export: key = \"%s\", %d bits, value = HEX\n", - key, count); - lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS; - - for (line = 0; line < lines; ++line) { - if (line < (lines - 1)) { - linebits = HEX_LINE_BITS; - size = HEX_LINE_CHARS; - offset = count - ((line + 1) * HEX_LINE_BITS); - } else { - linebits = - count - ((lines - 1) * HEX_LINE_BITS); - size = (linebits + 3) / 4; - offset = 0L; - } - - string[size] = '\0'; - j = size - 1; - value = 0; - - for (k = 0; k < linebits; ++k) { - i = k + offset; - if (data[i >> 3] & (1 << (i & 7))) - value |= (1 << (i & 3)); - if ((i & 3) == 3) { - sprintf(&string[j], "%1x", value); - value = 0; - --j; - } - } - if ((k & 3) > 0) - sprintf(&string[j], "%1x", value); - - dprintk("%s\n", string); - } - - } else { - size = (count + 3) / 4; - string[size] = '\0'; - j = size - 1; - value = 0; - - for (i = 0; i < count; ++i) { - if (data[i >> 3] & (1 << (i & 7))) - value |= (1 << (i & 3)); - if ((i & 3) == 3) { - sprintf(&string[j], "%1x", value); - value = 0; - --j; - } - } - if ((i & 3) > 0) - sprintf(&string[j], "%1x", value); - - dprintk("Export: key = \"%s\", %d bits, value = HEX %s\n", - key, count, string); - } -} - -static int altera_execute(struct altera_state *astate, - u8 *p, - s32 program_size, - s32 *error_address, - int *exit_code, - int *format_version) -{ - struct altera_config *aconf = astate->config; - char *msg_buff = astate->msg_buff; - long *stack = astate->stack; - int status = 0; - u32 first_word = 0L; - u32 action_table = 0L; - u32 proc_table = 0L; - u32 str_table = 0L; - u32 sym_table = 0L; - u32 data_sect = 0L; - u32 code_sect = 0L; - u32 debug_sect = 0L; - u32 action_count = 0L; - u32 proc_count = 0L; - u32 sym_count = 0L; - long *vars = NULL; - s32 *var_size = NULL; - char *attrs = NULL; - u8 *proc_attributes = NULL; - u32 pc; - u32 opcode_address; - u32 args[3]; - u32 opcode; - u32 name_id; - u8 charbuf[4]; - long long_tmp; - u32 variable_id; - u8 *charptr_tmp; - u8 *charptr_tmp2; - long *longptr_tmp; - int version = 0; - int delta = 0; - int stack_ptr = 0; - u32 arg_count; - int done = 0; - int bad_opcode = 0; - u32 count; - u32 index; - u32 index2; - s32 long_count; - s32 long_idx; - s32 long_idx2; - u32 i; - u32 j; - u32 uncomp_size; - u32 offset; - u32 value; - int current_proc = 0; - int reverse; - - char *name; - - dprintk("%s\n", __func__); - - /* Read header information */ - if (program_size > 52L) { - first_word = get_unaligned_be32(&p[0]); - version = (first_word & 1L); - *format_version = version + 1; - delta = version * 8; - - action_table = get_unaligned_be32(&p[4]); - proc_table = get_unaligned_be32(&p[8]); - str_table = get_unaligned_be32(&p[4 + delta]); - sym_table = get_unaligned_be32(&p[16 + delta]); - data_sect = get_unaligned_be32(&p[20 + delta]); - code_sect = get_unaligned_be32(&p[24 + delta]); - debug_sect = get_unaligned_be32(&p[28 + delta]); - action_count = get_unaligned_be32(&p[40 + delta]); - proc_count = get_unaligned_be32(&p[44 + delta]); - sym_count = get_unaligned_be32(&p[48 + (2 * delta)]); - } - - if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) { - done = 1; - status = -EIO; - goto exit_done; - } - - if (sym_count <= 0) - goto exit_done; - - vars = kzalloc(sym_count * sizeof(long), GFP_KERNEL); - - if (vars == NULL) - status = -ENOMEM; - - if (status == 0) { - var_size = kzalloc(sym_count * sizeof(s32), GFP_KERNEL); - - if (var_size == NULL) - status = -ENOMEM; - } - - if (status == 0) { - attrs = kzalloc(sym_count, GFP_KERNEL); - - if (attrs == NULL) - status = -ENOMEM; - } - - if ((status == 0) && (version > 0)) { - proc_attributes = kzalloc(proc_count, GFP_KERNEL); - - if (proc_attributes == NULL) - status = -ENOMEM; - } - - if (status != 0) - goto exit_done; - - delta = version * 2; - - for (i = 0; i < sym_count; ++i) { - offset = (sym_table + ((11 + delta) * i)); - - value = get_unaligned_be32(&p[offset + 3 + delta]); - - attrs[i] = p[offset]; - - /* - * use bit 7 of attribute byte to indicate that - * this buffer was dynamically allocated - * and should be freed later - */ - attrs[i] &= 0x7f; - - var_size[i] = get_unaligned_be32(&p[offset + 7 + delta]); - - /* - * Attribute bits: - * bit 0: 0 = read-only, 1 = read-write - * bit 1: 0 = not compressed, 1 = compressed - * bit 2: 0 = not initialized, 1 = initialized - * bit 3: 0 = scalar, 1 = array - * bit 4: 0 = Boolean, 1 = integer - * bit 5: 0 = declared variable, - * 1 = compiler created temporary variable - */ - - if ((attrs[i] & 0x0c) == 0x04) - /* initialized scalar variable */ - vars[i] = value; - else if ((attrs[i] & 0x1e) == 0x0e) { - /* initialized compressed Boolean array */ - uncomp_size = get_unaligned_le32(&p[data_sect + value]); - - /* allocate a buffer for the uncompressed data */ - vars[i] = (long)kzalloc(uncomp_size, GFP_KERNEL); - if (vars[i] == 0L) - status = -ENOMEM; - else { - /* set flag so buffer will be freed later */ - attrs[i] |= 0x80; - - /* uncompress the data */ - if (altera_shrink(&p[data_sect + value], - var_size[i], - (u8 *)vars[i], - uncomp_size, - version) != uncomp_size) - /* decompression failed */ - status = -EIO; - else - var_size[i] = uncomp_size * 8L; - - } - } else if ((attrs[i] & 0x1e) == 0x0c) { - /* initialized Boolean array */ - vars[i] = value + data_sect + (long)p; - } else if ((attrs[i] & 0x1c) == 0x1c) { - /* initialized integer array */ - vars[i] = value + data_sect; - } else if ((attrs[i] & 0x0c) == 0x08) { - /* uninitialized array */ - - /* flag attrs so that memory is freed */ - attrs[i] |= 0x80; - - if (var_size[i] > 0) { - u32 size; - - if (attrs[i] & 0x10) - /* integer array */ - size = (var_size[i] * sizeof(s32)); - else - /* Boolean array */ - size = ((var_size[i] + 7L) / 8L); - - vars[i] = (long)kzalloc(size, GFP_KERNEL); - - if (vars[i] == 0) { - status = -ENOMEM; - } else { - /* zero out memory */ - for (j = 0; j < size; ++j) - ((u8 *)(vars[i]))[j] = 0; - - } - } else - vars[i] = 0; - - } else - vars[i] = 0; - - } - -exit_done: - if (status != 0) - done = 1; - - altera_jinit(astate); - - pc = code_sect; - msg_buff[0] = '\0'; - - /* - * For JBC version 2, we will execute the procedures corresponding to - * the selected ACTION - */ - if (version > 0) { - if (aconf->action == NULL) { - status = -EINVAL; - done = 1; - } else { - int action_found = 0; - for (i = 0; (i < action_count) && !action_found; ++i) { - name_id = get_unaligned_be32(&p[action_table + - (12 * i)]); - - name = &p[str_table + name_id]; - - if (strnicmp(aconf->action, name, strlen(name)) == 0) { - action_found = 1; - current_proc = - get_unaligned_be32(&p[action_table + - (12 * i) + 8]); - } - } - - if (!action_found) { - status = -EINVAL; - done = 1; - } - } - - if (status == 0) { - int first_time = 1; - i = current_proc; - while ((i != 0) || first_time) { - first_time = 0; - /* check procedure attribute byte */ - proc_attributes[i] = - (p[proc_table + - (13 * i) + 8] & - 0x03); - - /* - * BIT0 - OPTIONAL - * BIT1 - RECOMMENDED - * BIT6 - FORCED OFF - * BIT7 - FORCED ON - */ - - i = get_unaligned_be32(&p[proc_table + - (13 * i) + 4]); - } - - /* - * Set current_proc to the first procedure - * to be executed - */ - i = current_proc; - while ((i != 0) && - ((proc_attributes[i] == 1) || - ((proc_attributes[i] & 0xc0) == 0x40))) { - i = get_unaligned_be32(&p[proc_table + - (13 * i) + 4]); - } - - if ((i != 0) || ((i == 0) && (current_proc == 0) && - ((proc_attributes[0] != 1) && - ((proc_attributes[0] & 0xc0) != 0x40)))) { - current_proc = i; - pc = code_sect + - get_unaligned_be32(&p[proc_table + - (13 * i) + 9]); - if ((pc < code_sect) || (pc >= debug_sect)) - status = -ERANGE; - } else - /* there are no procedures to execute! */ - done = 1; - - } - } - - msg_buff[0] = '\0'; - - while (!done) { - opcode = (p[pc] & 0xff); - opcode_address = pc; - ++pc; - - if (debug > 1) - printk("opcode: %02x\n", opcode); - - arg_count = (opcode >> 6) & 3; - for (i = 0; i < arg_count; ++i) { - args[i] = get_unaligned_be32(&p[pc]); - pc += 4; - } - - switch (opcode) { - case OP_NOP: - break; - case OP_DUP: - if (altera_check_stack(stack_ptr, 1, &status)) { - stack[stack_ptr] = stack[stack_ptr - 1]; - ++stack_ptr; - } - break; - case OP_SWP: - if (altera_check_stack(stack_ptr, 2, &status)) { - long_tmp = stack[stack_ptr - 2]; - stack[stack_ptr - 2] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - break; - case OP_ADD: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] += stack[stack_ptr]; - } - break; - case OP_SUB: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] -= stack[stack_ptr]; - } - break; - case OP_MULT: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] *= stack[stack_ptr]; - } - break; - case OP_DIV: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] /= stack[stack_ptr]; - } - break; - case OP_MOD: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] %= stack[stack_ptr]; - } - break; - case OP_SHL: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] <<= stack[stack_ptr]; - } - break; - case OP_SHR: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] >>= stack[stack_ptr]; - } - break; - case OP_NOT: - if (altera_check_stack(stack_ptr, 1, &status)) - stack[stack_ptr - 1] ^= (-1L); - - break; - case OP_AND: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] &= stack[stack_ptr]; - } - break; - case OP_OR: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] |= stack[stack_ptr]; - } - break; - case OP_XOR: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] ^= stack[stack_ptr]; - } - break; - case OP_INV: - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - stack[stack_ptr - 1] = stack[stack_ptr - 1] ? 0L : 1L; - break; - case OP_GT: - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - --stack_ptr; - stack[stack_ptr - 1] = - (stack[stack_ptr - 1] > stack[stack_ptr]) ? - 1L : 0L; - - break; - case OP_LT: - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - --stack_ptr; - stack[stack_ptr - 1] = - (stack[stack_ptr - 1] < stack[stack_ptr]) ? - 1L : 0L; - - break; - case OP_RET: - if ((version > 0) && (stack_ptr == 0)) { - /* - * We completed one of the main procedures - * of an ACTION. - * Find the next procedure - * to be executed and jump to it. - * If there are no more procedures, then EXIT. - */ - i = get_unaligned_be32(&p[proc_table + - (13 * current_proc) + 4]); - while ((i != 0) && - ((proc_attributes[i] == 1) || - ((proc_attributes[i] & 0xc0) == 0x40))) - i = get_unaligned_be32(&p[proc_table + - (13 * i) + 4]); - - if (i == 0) { - /* no procedures to execute! */ - done = 1; - *exit_code = 0; /* success */ - } else { - current_proc = i; - pc = code_sect + get_unaligned_be32( - &p[proc_table + - (13 * i) + 9]); - if ((pc < code_sect) || - (pc >= debug_sect)) - status = -ERANGE; - } - - } else - if (altera_check_stack(stack_ptr, 1, &status)) { - pc = stack[--stack_ptr] + code_sect; - if ((pc <= code_sect) || - (pc >= debug_sect)) - status = -ERANGE; - - } - - break; - case OP_CMPS: - /* - * Array short compare - * ...stack 0 is source 1 value - * ...stack 1 is source 2 value - * ...stack 2 is mask value - * ...stack 3 is count - */ - if (altera_check_stack(stack_ptr, 4, &status)) { - s32 a = stack[--stack_ptr]; - s32 b = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - count = stack[stack_ptr - 1]; - - if ((count < 1) || (count > 32)) - status = -ERANGE; - else { - long_tmp &= ((-1L) >> (32 - count)); - - stack[stack_ptr - 1] = - ((a & long_tmp) == (b & long_tmp)) - ? 1L : 0L; - } - } - break; - case OP_PINT: - /* - * PRINT add integer - * ...stack 0 is integer value - */ - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - sprintf(&msg_buff[strlen(msg_buff)], - "%ld", stack[--stack_ptr]); - break; - case OP_PRNT: - /* PRINT finish */ - if (debug) - printk(msg_buff, "\n"); - - msg_buff[0] = '\0'; - break; - case OP_DSS: - /* - * DRSCAN short - * ...stack 0 is scan data - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - count = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_drscan(astate, count, charbuf, 0); - break; - case OP_DSSC: - /* - * DRSCAN short with capture - * ...stack 0 is scan data - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - count = stack[stack_ptr - 1]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_swap_dr(astate, count, charbuf, - 0, charbuf, 0); - stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); - break; - case OP_ISS: - /* - * IRSCAN short - * ...stack 0 is scan data - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - count = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_irscan(astate, count, charbuf, 0); - break; - case OP_ISSC: - /* - * IRSCAN short with capture - * ...stack 0 is scan data - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - count = stack[stack_ptr - 1]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_swap_ir(astate, count, charbuf, - 0, charbuf, 0); - stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); - break; - case OP_DPR: - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - count = stack[--stack_ptr]; - status = altera_set_dr_pre(&astate->js, count, 0, NULL); - break; - case OP_DPRL: - /* - * DRPRE with literal data - * ...stack 0 is count - * ...stack 1 is literal data - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - count = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_set_dr_pre(&astate->js, count, 0, - charbuf); - break; - case OP_DPO: - /* - * DRPOST - * ...stack 0 is count - */ - if (altera_check_stack(stack_ptr, 1, &status)) { - count = stack[--stack_ptr]; - status = altera_set_dr_post(&astate->js, count, - 0, NULL); - } - break; - case OP_DPOL: - /* - * DRPOST with literal data - * ...stack 0 is count - * ...stack 1 is literal data - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - count = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_set_dr_post(&astate->js, count, 0, - charbuf); - break; - case OP_IPR: - if (altera_check_stack(stack_ptr, 1, &status)) { - count = stack[--stack_ptr]; - status = altera_set_ir_pre(&astate->js, count, - 0, NULL); - } - break; - case OP_IPRL: - /* - * IRPRE with literal data - * ...stack 0 is count - * ...stack 1 is literal data - */ - if (altera_check_stack(stack_ptr, 2, &status)) { - count = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_set_ir_pre(&astate->js, count, - 0, charbuf); - } - break; - case OP_IPO: - /* - * IRPOST - * ...stack 0 is count - */ - if (altera_check_stack(stack_ptr, 1, &status)) { - count = stack[--stack_ptr]; - status = altera_set_ir_post(&astate->js, count, - 0, NULL); - } - break; - case OP_IPOL: - /* - * IRPOST with literal data - * ...stack 0 is count - * ...stack 1 is literal data - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - count = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_set_ir_post(&astate->js, count, 0, - charbuf); - break; - case OP_PCHR: - if (altera_check_stack(stack_ptr, 1, &status)) { - u8 ch; - count = strlen(msg_buff); - ch = (char) stack[--stack_ptr]; - if ((ch < 1) || (ch > 127)) { - /* - * character code out of range - * instead of flagging an error, - * force the value to 127 - */ - ch = 127; - } - msg_buff[count] = ch; - msg_buff[count + 1] = '\0'; - } - break; - case OP_EXIT: - if (altera_check_stack(stack_ptr, 1, &status)) - *exit_code = stack[--stack_ptr]; - - done = 1; - break; - case OP_EQU: - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - --stack_ptr; - stack[stack_ptr - 1] = - (stack[stack_ptr - 1] == stack[stack_ptr]) ? - 1L : 0L; - break; - case OP_POPT: - if (altera_check_stack(stack_ptr, 1, &status)) - --stack_ptr; - - break; - case OP_ABS: - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - if (stack[stack_ptr - 1] < 0) - stack[stack_ptr - 1] = 0 - stack[stack_ptr - 1]; - - break; - case OP_BCH0: - /* - * Batch operation 0 - * SWP - * SWPN 7 - * SWP - * SWPN 6 - * DUPN 8 - * SWPN 2 - * SWP - * DUPN 6 - * DUPN 6 - */ - - /* SWP */ - if (altera_check_stack(stack_ptr, 2, &status)) { - long_tmp = stack[stack_ptr - 2]; - stack[stack_ptr - 2] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* SWPN 7 */ - index = 7 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - long_tmp = stack[stack_ptr - index]; - stack[stack_ptr - index] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* SWP */ - if (altera_check_stack(stack_ptr, 2, &status)) { - long_tmp = stack[stack_ptr - 2]; - stack[stack_ptr - 2] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* SWPN 6 */ - index = 6 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - long_tmp = stack[stack_ptr - index]; - stack[stack_ptr - index] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* DUPN 8 */ - index = 8 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - stack[stack_ptr] = stack[stack_ptr - index]; - ++stack_ptr; - } - - /* SWPN 2 */ - index = 2 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - long_tmp = stack[stack_ptr - index]; - stack[stack_ptr - index] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* SWP */ - if (altera_check_stack(stack_ptr, 2, &status)) { - long_tmp = stack[stack_ptr - 2]; - stack[stack_ptr - 2] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* DUPN 6 */ - index = 6 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - stack[stack_ptr] = stack[stack_ptr - index]; - ++stack_ptr; - } - - /* DUPN 6 */ - index = 6 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - stack[stack_ptr] = stack[stack_ptr - index]; - ++stack_ptr; - } - break; - case OP_PSH0: - stack[stack_ptr++] = 0; - break; - case OP_PSHL: - stack[stack_ptr++] = (s32) args[0]; - break; - case OP_PSHV: - stack[stack_ptr++] = vars[args[0]]; - break; - case OP_JMP: - pc = args[0] + code_sect; - if ((pc < code_sect) || (pc >= debug_sect)) - status = -ERANGE; - break; - case OP_CALL: - stack[stack_ptr++] = pc; - pc = args[0] + code_sect; - if ((pc < code_sect) || (pc >= debug_sect)) - status = -ERANGE; - break; - case OP_NEXT: - /* - * Process FOR / NEXT loop - * ...argument 0 is variable ID - * ...stack 0 is step value - * ...stack 1 is end value - * ...stack 2 is top address - */ - if (altera_check_stack(stack_ptr, 3, &status)) { - s32 step = stack[stack_ptr - 1]; - s32 end = stack[stack_ptr - 2]; - s32 top = stack[stack_ptr - 3]; - s32 iterator = vars[args[0]]; - int break_out = 0; - - if (step < 0) { - if (iterator <= end) - break_out = 1; - } else if (iterator >= end) - break_out = 1; - - if (break_out) { - stack_ptr -= 3; - } else { - vars[args[0]] = iterator + step; - pc = top + code_sect; - if ((pc < code_sect) || - (pc >= debug_sect)) - status = -ERANGE; - } - } - break; - case OP_PSTR: - /* - * PRINT add string - * ...argument 0 is string ID - */ - count = strlen(msg_buff); - strlcpy(&msg_buff[count], - &p[str_table + args[0]], - ALTERA_MESSAGE_LENGTH - count); - break; - case OP_SINT: - /* - * STATE intermediate state - * ...argument 0 is state code - */ - status = altera_goto_jstate(astate, args[0]); - break; - case OP_ST: - /* - * STATE final state - * ...argument 0 is state code - */ - status = altera_goto_jstate(astate, args[0]); - break; - case OP_ISTP: - /* - * IRSTOP state - * ...argument 0 is state code - */ - status = altera_set_irstop(&astate->js, args[0]); - break; - case OP_DSTP: - /* - * DRSTOP state - * ...argument 0 is state code - */ - status = altera_set_drstop(&astate->js, args[0]); - break; - - case OP_SWPN: - /* - * Exchange top with Nth stack value - * ...argument 0 is 0-based stack entry - * to swap with top element - */ - index = (args[0]) + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - long_tmp = stack[stack_ptr - index]; - stack[stack_ptr - index] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - break; - case OP_DUPN: - /* - * Duplicate Nth stack value - * ...argument 0 is 0-based stack entry to duplicate - */ - index = (args[0]) + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - stack[stack_ptr] = stack[stack_ptr - index]; - ++stack_ptr; - } - break; - case OP_POPV: - /* - * Pop stack into scalar variable - * ...argument 0 is variable ID - * ...stack 0 is value - */ - if (altera_check_stack(stack_ptr, 1, &status)) - vars[args[0]] = stack[--stack_ptr]; - - break; - case OP_POPE: - /* - * Pop stack into integer array element - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is value - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - variable_id = args[0]; - - /* - * If variable is read-only, - * convert to writable array - */ - if ((version > 0) && - ((attrs[variable_id] & 0x9c) == 0x1c)) { - /* Allocate a writable buffer for this array */ - count = var_size[variable_id]; - long_tmp = vars[variable_id]; - longptr_tmp = kzalloc(count * sizeof(long), - GFP_KERNEL); - vars[variable_id] = (long)longptr_tmp; - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* copy previous contents into buffer */ - for (i = 0; i < count; ++i) { - longptr_tmp[i] = - get_unaligned_be32(&p[long_tmp]); - long_tmp += sizeof(long); - } - - /* - * set bit 7 - buffer was - * dynamically allocated - */ - attrs[variable_id] |= 0x80; - - /* clear bit 2 - variable is writable */ - attrs[variable_id] &= ~0x04; - attrs[variable_id] |= 0x01; - - } - - /* check that variable is a writable integer array */ - if ((attrs[variable_id] & 0x1c) != 0x18) - status = -ERANGE; - else { - longptr_tmp = (long *)vars[variable_id]; - - /* pop the array index */ - index = stack[--stack_ptr]; - - /* pop the value and store it into the array */ - longptr_tmp[index] = stack[--stack_ptr]; - } - - break; - case OP_POPA: - /* - * Pop stack into Boolean array - * ...argument 0 is variable ID - * ...stack 0 is count - * ...stack 1 is array index - * ...stack 2 is value - */ - if (!altera_check_stack(stack_ptr, 3, &status)) - break; - variable_id = args[0]; - - /* - * If variable is read-only, - * convert to writable array - */ - if ((version > 0) && - ((attrs[variable_id] & 0x9c) == 0x0c)) { - /* Allocate a writable buffer for this array */ - long_tmp = - (var_size[variable_id] + 7L) >> 3L; - charptr_tmp2 = (u8 *)vars[variable_id]; - charptr_tmp = - kzalloc(long_tmp, GFP_KERNEL); - vars[variable_id] = (long)charptr_tmp; - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* zero the buffer */ - for (long_idx = 0L; - long_idx < long_tmp; - ++long_idx) { - charptr_tmp[long_idx] = 0; - } - - /* copy previous contents into buffer */ - for (long_idx = 0L; - long_idx < var_size[variable_id]; - ++long_idx) { - long_idx2 = long_idx; - - if (charptr_tmp2[long_idx2 >> 3] & - (1 << (long_idx2 & 7))) { - charptr_tmp[long_idx >> 3] |= - (1 << (long_idx & 7)); - } - } - - /* - * set bit 7 - buffer was - * dynamically allocated - */ - attrs[variable_id] |= 0x80; - - /* clear bit 2 - variable is writable */ - attrs[variable_id] &= ~0x04; - attrs[variable_id] |= 0x01; - - } - - /* - * check that variable is - * a writable Boolean array - */ - if ((attrs[variable_id] & 0x1c) != 0x08) { - status = -ERANGE; - break; - } - - charptr_tmp = (u8 *)vars[variable_id]; - - /* pop the count (number of bits to copy) */ - long_count = stack[--stack_ptr]; - - /* pop the array index */ - long_idx = stack[--stack_ptr]; - - reverse = 0; - - if (version > 0) { - /* - * stack 0 = array right index - * stack 1 = array left index - */ - - if (long_idx > long_count) { - reverse = 1; - long_tmp = long_count; - long_count = 1 + long_idx - - long_count; - long_idx = long_tmp; - - /* reverse POPA is not supported */ - status = -ERANGE; - break; - } else - long_count = 1 + long_count - - long_idx; - - } - - /* pop the data */ - long_tmp = stack[--stack_ptr]; - - if (long_count < 1) { - status = -ERANGE; - break; - } - - for (i = 0; i < long_count; ++i) { - if (long_tmp & (1L << (s32) i)) - charptr_tmp[long_idx >> 3L] |= - (1L << (long_idx & 7L)); - else - charptr_tmp[long_idx >> 3L] &= - ~(1L << (long_idx & 7L)); - - ++long_idx; - } - - break; - case OP_JMPZ: - /* - * Pop stack and branch if zero - * ...argument 0 is address - * ...stack 0 is condition value - */ - if (altera_check_stack(stack_ptr, 1, &status)) { - if (stack[--stack_ptr] == 0) { - pc = args[0] + code_sect; - if ((pc < code_sect) || - (pc >= debug_sect)) - status = -ERANGE; - } - } - break; - case OP_DS: - case OP_IS: - /* - * DRSCAN - * IRSCAN - * ...argument 0 is scan data variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_idx = stack[--stack_ptr]; - long_count = stack[--stack_ptr]; - reverse = 0; - if (version > 0) { - /* - * stack 0 = array right index - * stack 1 = array left index - * stack 2 = count - */ - long_tmp = long_count; - long_count = stack[--stack_ptr]; - - if (long_idx > long_tmp) { - reverse = 1; - long_idx = long_tmp; - } - } - - charptr_tmp = (u8 *)vars[args[0]]; - - if (reverse) { - /* - * allocate a buffer - * and reverse the data order - */ - charptr_tmp2 = charptr_tmp; - charptr_tmp = kzalloc((long_count >> 3) + 1, - GFP_KERNEL); - if (charptr_tmp == NULL) { - status = -ENOMEM; - break; - } - - long_tmp = long_idx + long_count - 1; - long_idx2 = 0; - while (long_idx2 < long_count) { - if (charptr_tmp2[long_tmp >> 3] & - (1 << (long_tmp & 7))) - charptr_tmp[long_idx2 >> 3] |= - (1 << (long_idx2 & 7)); - else - charptr_tmp[long_idx2 >> 3] &= - ~(1 << (long_idx2 & 7)); - - --long_tmp; - ++long_idx2; - } - } - - if (opcode == 0x51) /* DS */ - status = altera_drscan(astate, long_count, - charptr_tmp, long_idx); - else /* IS */ - status = altera_irscan(astate, long_count, - charptr_tmp, long_idx); - - if (reverse) - kfree(charptr_tmp); - - break; - case OP_DPRA: - /* - * DRPRE with array data - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - index = stack[--stack_ptr]; - count = stack[--stack_ptr]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - charptr_tmp = (u8 *)vars[args[0]]; - status = altera_set_dr_pre(&astate->js, count, index, - charptr_tmp); - break; - case OP_DPOA: - /* - * DRPOST with array data - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - index = stack[--stack_ptr]; - count = stack[--stack_ptr]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - charptr_tmp = (u8 *)vars[args[0]]; - status = altera_set_dr_post(&astate->js, count, index, - charptr_tmp); - break; - case OP_IPRA: - /* - * IRPRE with array data - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - index = stack[--stack_ptr]; - count = stack[--stack_ptr]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - charptr_tmp = (u8 *)vars[args[0]]; - status = altera_set_ir_pre(&astate->js, count, index, - charptr_tmp); - - break; - case OP_IPOA: - /* - * IRPOST with array data - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - index = stack[--stack_ptr]; - count = stack[--stack_ptr]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - charptr_tmp = (u8 *)vars[args[0]]; - status = altera_set_ir_post(&astate->js, count, index, - charptr_tmp); - - break; - case OP_EXPT: - /* - * EXPORT - * ...argument 0 is string ID - * ...stack 0 is integer expression - */ - if (altera_check_stack(stack_ptr, 1, &status)) { - name = &p[str_table + args[0]]; - long_tmp = stack[--stack_ptr]; - altera_export_int(name, long_tmp); - } - break; - case OP_PSHE: - /* - * Push integer array element - * ...argument 0 is variable ID - * ...stack 0 is array index - */ - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - variable_id = args[0]; - index = stack[stack_ptr - 1]; - - /* check variable type */ - if ((attrs[variable_id] & 0x1f) == 0x19) { - /* writable integer array */ - longptr_tmp = (long *)vars[variable_id]; - stack[stack_ptr - 1] = longptr_tmp[index]; - } else if ((attrs[variable_id] & 0x1f) == 0x1c) { - /* read-only integer array */ - long_tmp = vars[variable_id] + - (index * sizeof(long)); - stack[stack_ptr - 1] = - get_unaligned_be32(&p[long_tmp]); - } else - status = -ERANGE; - - break; - case OP_PSHA: - /* - * Push Boolean array - * ...argument 0 is variable ID - * ...stack 0 is count - * ...stack 1 is array index - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - variable_id = args[0]; - - /* check that variable is a Boolean array */ - if ((attrs[variable_id] & 0x18) != 0x08) { - status = -ERANGE; - break; - } - - charptr_tmp = (u8 *)vars[variable_id]; - - /* pop the count (number of bits to copy) */ - count = stack[--stack_ptr]; - - /* pop the array index */ - index = stack[stack_ptr - 1]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - if ((count < 1) || (count > 32)) { - status = -ERANGE; - break; - } - - long_tmp = 0L; - - for (i = 0; i < count; ++i) - if (charptr_tmp[(i + index) >> 3] & - (1 << ((i + index) & 7))) - long_tmp |= (1L << i); - - stack[stack_ptr - 1] = long_tmp; - - break; - case OP_DYNA: - /* - * Dynamically change size of array - * ...argument 0 is variable ID - * ...stack 0 is new size - */ - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - variable_id = args[0]; - long_tmp = stack[--stack_ptr]; - - if (long_tmp > var_size[variable_id]) { - var_size[variable_id] = long_tmp; - - if (attrs[variable_id] & 0x10) - /* allocate integer array */ - long_tmp *= sizeof(long); - else - /* allocate Boolean array */ - long_tmp = (long_tmp + 7) >> 3; - - /* - * If the buffer was previously allocated, - * free it - */ - if (attrs[variable_id] & 0x80) { - kfree((void *)vars[variable_id]); - vars[variable_id] = 0; - } - - /* - * Allocate a new buffer - * of the requested size - */ - vars[variable_id] = (long) - kzalloc(long_tmp, GFP_KERNEL); - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* - * Set the attribute bit to indicate that - * this buffer was dynamically allocated and - * should be freed later - */ - attrs[variable_id] |= 0x80; - - /* zero out memory */ - count = ((var_size[variable_id] + 7L) / - 8L); - charptr_tmp = (u8 *)(vars[variable_id]); - for (index = 0; index < count; ++index) - charptr_tmp[index] = 0; - - } - - break; - case OP_EXPV: - /* - * Export Boolean array - * ...argument 0 is string ID - * ...stack 0 is variable ID - * ...stack 1 is array right index - * ...stack 2 is array left index - */ - if (!altera_check_stack(stack_ptr, 3, &status)) - break; - if (version == 0) { - /* EXPV is not supported in JBC 1.0 */ - bad_opcode = 1; - break; - } - name = &p[str_table + args[0]]; - variable_id = stack[--stack_ptr]; - long_idx = stack[--stack_ptr];/* right indx */ - long_idx2 = stack[--stack_ptr];/* left indx */ - - if (long_idx > long_idx2) { - /* reverse indices not supported */ - status = -ERANGE; - break; - } - - long_count = 1 + long_idx2 - long_idx; - - charptr_tmp = (u8 *)vars[variable_id]; - charptr_tmp2 = NULL; - - if ((long_idx & 7L) != 0) { - s32 k = long_idx; - charptr_tmp2 = - kzalloc(((long_count + 7L) / 8L), - GFP_KERNEL); - if (charptr_tmp2 == NULL) { - status = -ENOMEM; - break; - } - - for (i = 0; i < long_count; ++i) { - if (charptr_tmp[k >> 3] & - (1 << (k & 7))) - charptr_tmp2[i >> 3] |= - (1 << (i & 7)); - else - charptr_tmp2[i >> 3] &= - ~(1 << (i & 7)); - - ++k; - } - charptr_tmp = charptr_tmp2; - - } else if (long_idx != 0) - charptr_tmp = &charptr_tmp[long_idx >> 3]; - - altera_export_bool_array(name, charptr_tmp, - long_count); - - /* free allocated buffer */ - if ((long_idx & 7L) != 0) - kfree(charptr_tmp2); - - break; - case OP_COPY: { - /* - * Array copy - * ...argument 0 is dest ID - * ...argument 1 is source ID - * ...stack 0 is count - * ...stack 1 is dest index - * ...stack 2 is source index - */ - s32 copy_count; - s32 copy_index; - s32 copy_index2; - s32 destleft; - s32 src_count; - s32 dest_count; - int src_reverse = 0; - int dest_reverse = 0; - - if (!altera_check_stack(stack_ptr, 3, &status)) - break; - - copy_count = stack[--stack_ptr]; - copy_index = stack[--stack_ptr]; - copy_index2 = stack[--stack_ptr]; - reverse = 0; - - if (version > 0) { - /* - * stack 0 = source right index - * stack 1 = source left index - * stack 2 = destination right index - * stack 3 = destination left index - */ - destleft = stack[--stack_ptr]; - - if (copy_count > copy_index) { - src_reverse = 1; - reverse = 1; - src_count = 1 + copy_count - copy_index; - /* copy_index = source start index */ - } else { - src_count = 1 + copy_index - copy_count; - /* source start index */ - copy_index = copy_count; - } - - if (copy_index2 > destleft) { - dest_reverse = 1; - reverse = !reverse; - dest_count = 1 + copy_index2 - destleft; - /* destination start index */ - copy_index2 = destleft; - } else - dest_count = 1 + destleft - copy_index2; - - copy_count = (src_count < dest_count) ? - src_count : dest_count; - - if ((src_reverse || dest_reverse) && - (src_count != dest_count)) - /* - * If either the source or destination - * is reversed, we can't tolerate - * a length mismatch, because we - * "left justify" arrays when copying. - * This won't work correctly - * with reversed arrays. - */ - status = -ERANGE; - - } - - count = copy_count; - index = copy_index; - index2 = copy_index2; - - /* - * If destination is a read-only array, - * allocate a buffer and convert it to a writable array - */ - variable_id = args[1]; - if ((version > 0) && - ((attrs[variable_id] & 0x9c) == 0x0c)) { - /* Allocate a writable buffer for this array */ - long_tmp = - (var_size[variable_id] + 7L) >> 3L; - charptr_tmp2 = (u8 *)vars[variable_id]; - charptr_tmp = - kzalloc(long_tmp, GFP_KERNEL); - vars[variable_id] = (long)charptr_tmp; - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* zero the buffer */ - for (long_idx = 0L; long_idx < long_tmp; - ++long_idx) - charptr_tmp[long_idx] = 0; - - /* copy previous contents into buffer */ - for (long_idx = 0L; - long_idx < var_size[variable_id]; - ++long_idx) { - long_idx2 = long_idx; - - if (charptr_tmp2[long_idx2 >> 3] & - (1 << (long_idx2 & 7))) - charptr_tmp[long_idx >> 3] |= - (1 << (long_idx & 7)); - - } - - /* - set bit 7 - buffer was dynamically allocated */ - attrs[variable_id] |= 0x80; - - /* clear bit 2 - variable is writable */ - attrs[variable_id] &= ~0x04; - attrs[variable_id] |= 0x01; - } - - charptr_tmp = (u8 *)vars[args[1]]; - charptr_tmp2 = (u8 *)vars[args[0]]; - - /* check if destination is a writable Boolean array */ - if ((attrs[args[1]] & 0x1c) != 0x08) { - status = -ERANGE; - break; - } - - if (count < 1) { - status = -ERANGE; - break; - } - - if (reverse) - index2 += (count - 1); - - for (i = 0; i < count; ++i) { - if (charptr_tmp2[index >> 3] & - (1 << (index & 7))) - charptr_tmp[index2 >> 3] |= - (1 << (index2 & 7)); - else - charptr_tmp[index2 >> 3] &= - ~(1 << (index2 & 7)); - - ++index; - if (reverse) - --index2; - else - ++index2; - } - - break; - } - case OP_DSC: - case OP_ISC: { - /* - * DRSCAN with capture - * IRSCAN with capture - * ...argument 0 is scan data variable ID - * ...argument 1 is capture variable ID - * ...stack 0 is capture index - * ...stack 1 is scan data index - * ...stack 2 is count - */ - s32 scan_right, scan_left; - s32 capture_count = 0; - s32 scan_count = 0; - s32 capture_index; - s32 scan_index; - - if (!altera_check_stack(stack_ptr, 3, &status)) - break; - - capture_index = stack[--stack_ptr]; - scan_index = stack[--stack_ptr]; - - if (version > 0) { - /* - * stack 0 = capture right index - * stack 1 = capture left index - * stack 2 = scan right index - * stack 3 = scan left index - * stack 4 = count - */ - scan_right = stack[--stack_ptr]; - scan_left = stack[--stack_ptr]; - capture_count = 1 + scan_index - capture_index; - scan_count = 1 + scan_left - scan_right; - scan_index = scan_right; - } - - long_count = stack[--stack_ptr]; - /* - * If capture array is read-only, allocate a buffer - * and convert it to a writable array - */ - variable_id = args[1]; - if ((version > 0) && - ((attrs[variable_id] & 0x9c) == 0x0c)) { - /* Allocate a writable buffer for this array */ - long_tmp = - (var_size[variable_id] + 7L) >> 3L; - charptr_tmp2 = (u8 *)vars[variable_id]; - charptr_tmp = - kzalloc(long_tmp, GFP_KERNEL); - vars[variable_id] = (long)charptr_tmp; - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* zero the buffer */ - for (long_idx = 0L; long_idx < long_tmp; - ++long_idx) - charptr_tmp[long_idx] = 0; - - /* copy previous contents into buffer */ - for (long_idx = 0L; - long_idx < var_size[variable_id]; - ++long_idx) { - long_idx2 = long_idx; - - if (charptr_tmp2[long_idx2 >> 3] & - (1 << (long_idx2 & 7))) - charptr_tmp[long_idx >> 3] |= - (1 << (long_idx & 7)); - - } - - /* - * set bit 7 - buffer was - * dynamically allocated - */ - attrs[variable_id] |= 0x80; - - /* clear bit 2 - variable is writable */ - attrs[variable_id] &= ~0x04; - attrs[variable_id] |= 0x01; - - } - - charptr_tmp = (u8 *)vars[args[0]]; - charptr_tmp2 = (u8 *)vars[args[1]]; - - if ((version > 0) && - ((long_count > capture_count) || - (long_count > scan_count))) { - status = -ERANGE; - break; - } - - /* - * check that capture array - * is a writable Boolean array - */ - if ((attrs[args[1]] & 0x1c) != 0x08) { - status = -ERANGE; - break; - } - - if (status == 0) { - if (opcode == 0x82) /* DSC */ - status = altera_swap_dr(astate, - long_count, - charptr_tmp, - scan_index, - charptr_tmp2, - capture_index); - else /* ISC */ - status = altera_swap_ir(astate, - long_count, - charptr_tmp, - scan_index, - charptr_tmp2, - capture_index); - - } - - break; - } - case OP_WAIT: - /* - * WAIT - * ...argument 0 is wait state - * ...argument 1 is end state - * ...stack 0 is cycles - * ...stack 1 is microseconds - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - - if (long_tmp != 0L) - status = altera_wait_cycles(astate, long_tmp, - args[0]); - - long_tmp = stack[--stack_ptr]; - - if ((status == 0) && (long_tmp != 0L)) - status = altera_wait_msecs(astate, - long_tmp, - args[0]); - - if ((status == 0) && (args[1] != args[0])) - status = altera_goto_jstate(astate, - args[1]); - - if (version > 0) { - --stack_ptr; /* throw away MAX cycles */ - --stack_ptr; /* throw away MAX microseconds */ - } - break; - case OP_CMPA: { - /* - * Array compare - * ...argument 0 is source 1 ID - * ...argument 1 is source 2 ID - * ...argument 2 is mask ID - * ...stack 0 is source 1 index - * ...stack 1 is source 2 index - * ...stack 2 is mask index - * ...stack 3 is count - */ - s32 a, b; - u8 *source1 = (u8 *)vars[args[0]]; - u8 *source2 = (u8 *)vars[args[1]]; - u8 *mask = (u8 *)vars[args[2]]; - u32 index1; - u32 index2; - u32 mask_index; - - if (!altera_check_stack(stack_ptr, 4, &status)) - break; - - index1 = stack[--stack_ptr]; - index2 = stack[--stack_ptr]; - mask_index = stack[--stack_ptr]; - long_count = stack[--stack_ptr]; - - if (version > 0) { - /* - * stack 0 = source 1 right index - * stack 1 = source 1 left index - * stack 2 = source 2 right index - * stack 3 = source 2 left index - * stack 4 = mask right index - * stack 5 = mask left index - */ - s32 mask_right = stack[--stack_ptr]; - s32 mask_left = stack[--stack_ptr]; - /* source 1 count */ - a = 1 + index2 - index1; - /* source 2 count */ - b = 1 + long_count - mask_index; - a = (a < b) ? a : b; - /* mask count */ - b = 1 + mask_left - mask_right; - a = (a < b) ? a : b; - /* source 2 start index */ - index2 = mask_index; - /* mask start index */ - mask_index = mask_right; - long_count = a; - } - - long_tmp = 1L; - - if (long_count < 1) - status = -ERANGE; - else { - count = long_count; - - for (i = 0; i < count; ++i) { - if (mask[mask_index >> 3] & - (1 << (mask_index & 7))) { - a = source1[index1 >> 3] & - (1 << (index1 & 7)) - ? 1 : 0; - b = source2[index2 >> 3] & - (1 << (index2 & 7)) - ? 1 : 0; - - if (a != b) /* failure */ - long_tmp = 0L; - } - ++index1; - ++index2; - ++mask_index; - } - } - - stack[stack_ptr++] = long_tmp; - - break; - } - default: - /* Unrecognized opcode -- ERROR! */ - bad_opcode = 1; - break; - } - - if (bad_opcode) - status = -ENOSYS; - - if ((stack_ptr < 0) || (stack_ptr >= ALTERA_STACK_SIZE)) - status = -EOVERFLOW; - - if (status != 0) { - done = 1; - *error_address = (s32)(opcode_address - code_sect); - } - } - - altera_free_buffers(astate); - - /* Free all dynamically allocated arrays */ - if ((attrs != NULL) && (vars != NULL)) - for (i = 0; i < sym_count; ++i) - if (attrs[i] & 0x80) - kfree((void *)vars[i]); - - kfree(vars); - kfree(var_size); - kfree(attrs); - kfree(proc_attributes); - - return status; -} - -static int altera_get_note(u8 *p, s32 program_size, - s32 *offset, char *key, char *value, int length) -/* - * Gets key and value of NOTE fields in the JBC file. - * Can be called in two modes: if offset pointer is NULL, - * then the function searches for note fields which match - * the key string provided. If offset is not NULL, then - * the function finds the next note field of any key, - * starting at the offset specified by the offset pointer. - * Returns 0 for success, else appropriate error code - */ -{ - int status = -ENODATA; - u32 note_strings = 0L; - u32 note_table = 0L; - u32 note_count = 0L; - u32 first_word = 0L; - int version = 0; - int delta = 0; - char *key_ptr; - char *value_ptr; - int i; - - /* Read header information */ - if (program_size > 52L) { - first_word = get_unaligned_be32(&p[0]); - version = (first_word & 1L); - delta = version * 8; - - note_strings = get_unaligned_be32(&p[8 + delta]); - note_table = get_unaligned_be32(&p[12 + delta]); - note_count = get_unaligned_be32(&p[44 + (2 * delta)]); - } - - if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) - return -EIO; - - if (note_count <= 0L) - return status; - - if (offset == NULL) { - /* - * We will search for the first note with a specific key, - * and return only the value - */ - for (i = 0; (i < note_count) && - (status != 0); ++i) { - key_ptr = &p[note_strings + - get_unaligned_be32( - &p[note_table + (8 * i)])]; - if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) && - (key != NULL)) { - status = 0; - - value_ptr = &p[note_strings + - get_unaligned_be32( - &p[note_table + (8 * i) + 4])]; - - if (value != NULL) - strlcpy(value, value_ptr, length); - - } - } - } else { - /* - * We will search for the next note, regardless of the key, - * and return both the value and the key - */ - - i = *offset; - - if ((i >= 0) && (i < note_count)) { - status = 0; - - if (key != NULL) - strlcpy(key, &p[note_strings + - get_unaligned_be32( - &p[note_table + (8 * i)])], - length); - - if (value != NULL) - strlcpy(value, &p[note_strings + - get_unaligned_be32( - &p[note_table + (8 * i) + 4])], - length); - - *offset = i + 1; - } - } - - return status; -} - -static int altera_check_crc(u8 *p, s32 program_size) -{ - int status = 0; - u16 local_expected = 0, - local_actual = 0, - shift_reg = 0xffff; - int bit, feedback; - u8 databyte; - u32 i; - u32 crc_section = 0L; - u32 first_word = 0L; - int version = 0; - int delta = 0; - - if (program_size > 52L) { - first_word = get_unaligned_be32(&p[0]); - version = (first_word & 1L); - delta = version * 8; - - crc_section = get_unaligned_be32(&p[32 + delta]); - } - - if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) - status = -EIO; - - if (crc_section >= program_size) - status = -EIO; - - if (status == 0) { - local_expected = (u16)get_unaligned_be16(&p[crc_section]); - - for (i = 0; i < crc_section; ++i) { - databyte = p[i]; - for (bit = 0; bit < 8; bit++) { - feedback = (databyte ^ shift_reg) & 0x01; - shift_reg >>= 1; - if (feedback) - shift_reg ^= 0x8408; - - databyte >>= 1; - } - } - - local_actual = (u16)~shift_reg; - - if (local_expected != local_actual) - status = -EILSEQ; - - } - - if (debug || status) { - switch (status) { - case 0: - printk(KERN_INFO "%s: CRC matched: %04x\n", __func__, - local_actual); - break; - case -EILSEQ: - printk(KERN_ERR "%s: CRC mismatch: expected %04x, " - "actual %04x\n", __func__, local_expected, - local_actual); - break; - case -ENODATA: - printk(KERN_ERR "%s: expected CRC not found, " - "actual CRC = %04x\n", __func__, - local_actual); - break; - case -EIO: - printk(KERN_ERR "%s: error: format isn't " - "recognized.\n", __func__); - break; - default: - printk(KERN_ERR "%s: CRC function returned error " - "code %d\n", __func__, status); - break; - } - } - - return status; -} - -static int altera_get_file_info(u8 *p, - s32 program_size, - int *format_version, - int *action_count, - int *procedure_count) -{ - int status = -EIO; - u32 first_word = 0; - int version = 0; - - if (program_size <= 52L) - return status; - - first_word = get_unaligned_be32(&p[0]); - - if ((first_word == 0x4A414D00L) || (first_word == 0x4A414D01L)) { - status = 0; - - version = (first_word & 1L); - *format_version = version + 1; - - if (version > 0) { - *action_count = get_unaligned_be32(&p[48]); - *procedure_count = get_unaligned_be32(&p[52]); - } - } - - return status; -} - -static int altera_get_act_info(u8 *p, - s32 program_size, - int index, - char **name, - char **description, - struct altera_procinfo **proc_list) -{ - int status = -EIO; - struct altera_procinfo *procptr = NULL; - struct altera_procinfo *tmpptr = NULL; - u32 first_word = 0L; - u32 action_table = 0L; - u32 proc_table = 0L; - u32 str_table = 0L; - u32 note_strings = 0L; - u32 action_count = 0L; - u32 proc_count = 0L; - u32 act_name_id = 0L; - u32 act_desc_id = 0L; - u32 act_proc_id = 0L; - u32 act_proc_name = 0L; - u8 act_proc_attribute = 0; - - if (program_size <= 52L) - return status; - /* Read header information */ - first_word = get_unaligned_be32(&p[0]); - - if (first_word != 0x4A414D01L) - return status; - - action_table = get_unaligned_be32(&p[4]); - proc_table = get_unaligned_be32(&p[8]); - str_table = get_unaligned_be32(&p[12]); - note_strings = get_unaligned_be32(&p[16]); - action_count = get_unaligned_be32(&p[48]); - proc_count = get_unaligned_be32(&p[52]); - - if (index >= action_count) - return status; - - act_name_id = get_unaligned_be32(&p[action_table + (12 * index)]); - act_desc_id = get_unaligned_be32(&p[action_table + (12 * index) + 4]); - act_proc_id = get_unaligned_be32(&p[action_table + (12 * index) + 8]); - - *name = &p[str_table + act_name_id]; - - if (act_desc_id < (note_strings - str_table)) - *description = &p[str_table + act_desc_id]; - - do { - act_proc_name = get_unaligned_be32( - &p[proc_table + (13 * act_proc_id)]); - act_proc_attribute = - (p[proc_table + (13 * act_proc_id) + 8] & 0x03); - - procptr = (struct altera_procinfo *) - kzalloc(sizeof(struct altera_procinfo), - GFP_KERNEL); - - if (procptr == NULL) - status = -ENOMEM; - else { - procptr->name = &p[str_table + act_proc_name]; - procptr->attrs = act_proc_attribute; - procptr->next = NULL; - - /* add record to end of linked list */ - if (*proc_list == NULL) - *proc_list = procptr; - else { - tmpptr = *proc_list; - while (tmpptr->next != NULL) - tmpptr = tmpptr->next; - tmpptr->next = procptr; - } - } - - act_proc_id = get_unaligned_be32( - &p[proc_table + (13 * act_proc_id) + 4]); - } while ((act_proc_id != 0) && (act_proc_id < proc_count)); - - return status; -} - -int altera_init(struct altera_config *config, const struct firmware *fw) -{ - struct altera_state *astate = NULL; - struct altera_procinfo *proc_list = NULL; - struct altera_procinfo *procptr = NULL; - char *key = NULL; - char *value = NULL; - char *action_name = NULL; - char *description = NULL; - int exec_result = 0; - int exit_code = 0; - int format_version = 0; - int action_count = 0; - int procedure_count = 0; - int index = 0; - s32 offset = 0L; - s32 error_address = 0L; - - key = kzalloc(33 * sizeof(char), GFP_KERNEL); - if (!key) - return -ENOMEM; - value = kzalloc(257 * sizeof(char), GFP_KERNEL); - if (!value) - return -ENOMEM; - astate = kzalloc(sizeof(struct altera_state), GFP_KERNEL); - if (!astate) - return -ENOMEM; - - astate->config = config; - if (!astate->config->jtag_io) { - dprintk(KERN_INFO "%s: using byteblaster!\n", __func__); - astate->config->jtag_io = netup_jtag_io_lpt; - } - - altera_check_crc((u8 *)fw->data, fw->size); - - if (debug) { - altera_get_file_info((u8 *)fw->data, fw->size, &format_version, - &action_count, &procedure_count); - printk(KERN_INFO "%s: File format is %s ByteCode format\n", - __func__, (format_version == 2) ? "Jam STAPL" : - "pre-standardized Jam 1.1"); - while (altera_get_note((u8 *)fw->data, fw->size, - &offset, key, value, 256) == 0) - printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n", - __func__, key, value); - } - - if (debug && (format_version == 2) && (action_count > 0)) { - printk(KERN_INFO "%s: Actions available:\n", __func__); - for (index = 0; index < action_count; ++index) { - altera_get_act_info((u8 *)fw->data, fw->size, - index, &action_name, - &description, - &proc_list); - - if (description == NULL) - printk(KERN_INFO "%s: %s\n", - __func__, - action_name); - else - printk(KERN_INFO "%s: %s \"%s\"\n", - __func__, - action_name, - description); - - procptr = proc_list; - while (procptr != NULL) { - if (procptr->attrs != 0) - printk(KERN_INFO "%s: %s (%s)\n", - __func__, - procptr->name, - (procptr->attrs == 1) ? - "optional" : "recommended"); - - proc_list = procptr->next; - kfree(procptr); - procptr = proc_list; - } - } - - printk(KERN_INFO "\n"); - } - - exec_result = altera_execute(astate, (u8 *)fw->data, fw->size, - &error_address, &exit_code, &format_version); - - if (exit_code) - exec_result = -EREMOTEIO; - - if ((format_version == 2) && (exec_result == -EINVAL)) { - if (astate->config->action == NULL) - printk(KERN_ERR "%s: error: no action specified for " - "Jam STAPL file.\nprogram terminated.\n", - __func__); - else - printk(KERN_ERR "%s: error: action \"%s\"" - " is not supported " - "for this Jam STAPL file.\n" - "Program terminated.\n", __func__, - astate->config->action); - - } else if (exec_result) - printk(KERN_ERR "%s: error %d\n", __func__, exec_result); - - kfree(key); - kfree(value); - kfree(astate); - - return 0; -} -EXPORT_SYMBOL(altera_init); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-comp.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-comp.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-comp.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-comp.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,142 +0,0 @@ -/* - * altera-comp.c - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "altera-exprt.h" - -#define SHORT_BITS 16 -#define CHAR_BITS 8 -#define DATA_BLOB_LENGTH 3 -#define MATCH_DATA_LENGTH 8192 -#define ALTERA_REQUEST_SIZE 1024 -#define ALTERA_BUFFER_SIZE (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE) - -static u32 altera_bits_req(u32 n) -{ - u32 result = SHORT_BITS; - - if (n == 0) - result = 1; - else { - /* Look for the highest non-zero bit position */ - while ((n & (1 << (SHORT_BITS - 1))) == 0) { - n <<= 1; - --result; - } - } - - return result; -} - -static u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail, - u32 *in_index) -{ - u32 result = 0; - u32 shift = 0; - u32 databyte = 0; - - while (bits > 0) { - databyte = buffer[*in_index]; - result |= (((databyte >> (CHAR_BITS - *bits_avail)) - & (0xff >> (CHAR_BITS - *bits_avail))) << shift); - - if (bits <= *bits_avail) { - result &= (0xffff >> (SHORT_BITS - (bits + shift))); - *bits_avail -= bits; - bits = 0; - } else { - ++(*in_index); - shift += *bits_avail; - bits -= *bits_avail; - *bits_avail = CHAR_BITS; - } - } - - return result; -} - -u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version) -{ - u32 i, j, data_length = 0L; - u32 offset, length; - u32 match_data_length = MATCH_DATA_LENGTH; - u32 bits_avail = CHAR_BITS; - u32 in_index = 0L; - - if (version > 0) - --match_data_length; - - for (i = 0; i < out_length; ++i) - out[i] = 0; - - /* Read number of bytes in data. */ - for (i = 0; i < sizeof(in_length); ++i) { - data_length = data_length | ( - altera_read_packed(in, - CHAR_BITS, - &bits_avail, - &in_index) << (i * CHAR_BITS)); - } - - if (data_length > out_length) { - data_length = 0L; - return data_length; - } - - i = 0; - while (i < data_length) { - /* A 0 bit indicates literal data. */ - if (altera_read_packed(in, 1, &bits_avail, - &in_index) == 0) { - for (j = 0; j < DATA_BLOB_LENGTH; ++j) { - if (i < data_length) { - out[i] = (u8)altera_read_packed(in, - CHAR_BITS, - &bits_avail, - &in_index); - i++; - } - } - } else { - /* A 1 bit indicates offset/length to follow. */ - offset = altera_read_packed(in, altera_bits_req((s16) - (i > match_data_length ? - match_data_length : i)), - &bits_avail, - &in_index); - length = altera_read_packed(in, CHAR_BITS, - &bits_avail, - &in_index); - for (j = 0; j < length; ++j) { - if (i < data_length) { - out[i] = out[i - offset]; - i++; - } - } - } - } - - return data_length; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-exprt.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-exprt.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-exprt.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-exprt.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - * altera-exprt.h - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef ALTERA_EXPRT_H -#define ALTERA_EXPRT_H - - -u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version); -int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo); - -#endif /* ALTERA_EXPRT_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-jtag.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-jtag.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-jtag.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-jtag.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1020 +0,0 @@ -/* - * altera-jtag.c - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include "altera-exprt.h" -#include "altera-jtag.h" - -#define alt_jtag_io(a, b, c)\ - astate->config->jtag_io(astate->config->dev, a, b, c); - -#define alt_malloc(a) kzalloc(a, GFP_KERNEL); - -/* - * This structure shows, for each JTAG state, which state is reached after - * a single TCK clock cycle with TMS high or TMS low, respectively. This - * describes all possible state transitions in the JTAG state machine. - */ -struct altera_jtag_machine { - enum altera_jtag_state tms_high; - enum altera_jtag_state tms_low; -}; - -static const struct altera_jtag_machine altera_transitions[] = { - /* RESET */ { RESET, IDLE }, - /* IDLE */ { DRSELECT, IDLE }, - /* DRSELECT */ { IRSELECT, DRCAPTURE }, - /* DRCAPTURE */ { DREXIT1, DRSHIFT }, - /* DRSHIFT */ { DREXIT1, DRSHIFT }, - /* DREXIT1 */ { DRUPDATE, DRPAUSE }, - /* DRPAUSE */ { DREXIT2, DRPAUSE }, - /* DREXIT2 */ { DRUPDATE, DRSHIFT }, - /* DRUPDATE */ { DRSELECT, IDLE }, - /* IRSELECT */ { RESET, IRCAPTURE }, - /* IRCAPTURE */ { IREXIT1, IRSHIFT }, - /* IRSHIFT */ { IREXIT1, IRSHIFT }, - /* IREXIT1 */ { IRUPDATE, IRPAUSE }, - /* IRPAUSE */ { IREXIT2, IRPAUSE }, - /* IREXIT2 */ { IRUPDATE, IRSHIFT }, - /* IRUPDATE */ { DRSELECT, IDLE } -}; - -/* - * This table contains the TMS value to be used to take the NEXT STEP on - * the path to the desired state. The array index is the current state, - * and the bit position is the desired endstate. To find out which state - * is used as the intermediate state, look up the TMS value in the - * altera_transitions[] table. - */ -static const u16 altera_jtag_path_map[16] = { - /* RST RTI SDRS CDR SDR E1DR PDR E2DR */ - 0x0001, 0xFFFD, 0xFE01, 0xFFE7, 0xFFEF, 0xFF0F, 0xFFBF, 0xFFFF, - /* UDR SIRS CIR SIR E1IR PIR E2IR UIR */ - 0xFEFD, 0x0001, 0xF3FF, 0xF7FF, 0x87FF, 0xDFFF, 0xFFFF, 0x7FFD -}; - -/* Flag bits for alt_jtag_io() function */ -#define TMS_HIGH 1 -#define TMS_LOW 0 -#define TDI_HIGH 1 -#define TDI_LOW 0 -#define READ_TDO 1 -#define IGNORE_TDO 0 - -int altera_jinit(struct altera_state *astate) -{ - struct altera_jtag *js = &astate->js; - - /* initial JTAG state is unknown */ - js->jtag_state = ILLEGAL_JTAG_STATE; - - /* initialize to default state */ - js->drstop_state = IDLE; - js->irstop_state = IDLE; - js->dr_pre = 0; - js->dr_post = 0; - js->ir_pre = 0; - js->ir_post = 0; - js->dr_length = 0; - js->ir_length = 0; - - js->dr_pre_data = NULL; - js->dr_post_data = NULL; - js->ir_pre_data = NULL; - js->ir_post_data = NULL; - js->dr_buffer = NULL; - js->ir_buffer = NULL; - - return 0; -} - -int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state) -{ - js->drstop_state = state; - - return 0; -} - -int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state) -{ - js->irstop_state = state; - - return 0; -} - -int altera_set_dr_pre(struct altera_jtag *js, - u32 count, u32 start_index, - u8 *preamble_data) -{ - int status = 0; - u32 i; - u32 j; - - if (count > js->dr_pre) { - kfree(js->dr_pre_data); - js->dr_pre_data = (u8 *)alt_malloc((count + 7) >> 3); - if (js->dr_pre_data == NULL) - status = -ENOMEM; - else - js->dr_pre = count; - } else - js->dr_pre = count; - - if (status == 0) { - for (i = 0; i < count; ++i) { - j = i + start_index; - - if (preamble_data == NULL) - js->dr_pre_data[i >> 3] |= (1 << (i & 7)); - else { - if (preamble_data[j >> 3] & (1 << (j & 7))) - js->dr_pre_data[i >> 3] |= - (1 << (i & 7)); - else - js->dr_pre_data[i >> 3] &= - ~(u32)(1 << (i & 7)); - - } - } - } - - return status; -} - -int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, - u8 *preamble_data) -{ - int status = 0; - u32 i; - u32 j; - - if (count > js->ir_pre) { - kfree(js->ir_pre_data); - js->ir_pre_data = (u8 *)alt_malloc((count + 7) >> 3); - if (js->ir_pre_data == NULL) - status = -ENOMEM; - else - js->ir_pre = count; - - } else - js->ir_pre = count; - - if (status == 0) { - for (i = 0; i < count; ++i) { - j = i + start_index; - if (preamble_data == NULL) - js->ir_pre_data[i >> 3] |= (1 << (i & 7)); - else { - if (preamble_data[j >> 3] & (1 << (j & 7))) - js->ir_pre_data[i >> 3] |= - (1 << (i & 7)); - else - js->ir_pre_data[i >> 3] &= - ~(u32)(1 << (i & 7)); - - } - } - } - - return status; -} - -int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, - u8 *postamble_data) -{ - int status = 0; - u32 i; - u32 j; - - if (count > js->dr_post) { - kfree(js->dr_post_data); - js->dr_post_data = (u8 *)alt_malloc((count + 7) >> 3); - - if (js->dr_post_data == NULL) - status = -ENOMEM; - else - js->dr_post = count; - - } else - js->dr_post = count; - - if (status == 0) { - for (i = 0; i < count; ++i) { - j = i + start_index; - - if (postamble_data == NULL) - js->dr_post_data[i >> 3] |= (1 << (i & 7)); - else { - if (postamble_data[j >> 3] & (1 << (j & 7))) - js->dr_post_data[i >> 3] |= - (1 << (i & 7)); - else - js->dr_post_data[i >> 3] &= - ~(u32)(1 << (i & 7)); - - } - } - } - - return status; -} - -int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, - u8 *postamble_data) -{ - int status = 0; - u32 i; - u32 j; - - if (count > js->ir_post) { - kfree(js->ir_post_data); - js->ir_post_data = (u8 *)alt_malloc((count + 7) >> 3); - if (js->ir_post_data == NULL) - status = -ENOMEM; - else - js->ir_post = count; - - } else - js->ir_post = count; - - if (status != 0) - return status; - - for (i = 0; i < count; ++i) { - j = i + start_index; - - if (postamble_data == NULL) - js->ir_post_data[i >> 3] |= (1 << (i & 7)); - else { - if (postamble_data[j >> 3] & (1 << (j & 7))) - js->ir_post_data[i >> 3] |= (1 << (i & 7)); - else - js->ir_post_data[i >> 3] &= - ~(u32)(1 << (i & 7)); - - } - } - - return status; -} - -static void altera_jreset_idle(struct altera_state *astate) -{ - struct altera_jtag *js = &astate->js; - int i; - /* Go to Test Logic Reset (no matter what the starting state may be) */ - for (i = 0; i < 5; ++i) - alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); - - /* Now step to Run Test / Idle */ - alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); - js->jtag_state = IDLE; -} - -int altera_goto_jstate(struct altera_state *astate, - enum altera_jtag_state state) -{ - struct altera_jtag *js = &astate->js; - int tms; - int count = 0; - int status = 0; - - if (js->jtag_state == ILLEGAL_JTAG_STATE) - /* initialize JTAG chain to known state */ - altera_jreset_idle(astate); - - if (js->jtag_state == state) { - /* - * We are already in the desired state. - * If it is a stable state, loop here. - * Otherwise do nothing (no clock cycles). - */ - if ((state == IDLE) || (state == DRSHIFT) || - (state == DRPAUSE) || (state == IRSHIFT) || - (state == IRPAUSE)) { - alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); - } else if (state == RESET) - alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); - - } else { - while ((js->jtag_state != state) && (count < 9)) { - /* Get TMS value to take a step toward desired state */ - tms = (altera_jtag_path_map[js->jtag_state] & - (1 << state)) - ? TMS_HIGH : TMS_LOW; - - /* Take a step */ - alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); - - if (tms) - js->jtag_state = - altera_transitions[js->jtag_state].tms_high; - else - js->jtag_state = - altera_transitions[js->jtag_state].tms_low; - - ++count; - } - } - - if (js->jtag_state != state) - status = -EREMOTEIO; - - return status; -} - -int altera_wait_cycles(struct altera_state *astate, - s32 cycles, - enum altera_jtag_state wait_state) -{ - struct altera_jtag *js = &astate->js; - int tms; - s32 count; - int status = 0; - - if (js->jtag_state != wait_state) - status = altera_goto_jstate(astate, wait_state); - - if (status == 0) { - /* - * Set TMS high to loop in RESET state - * Set TMS low to loop in any other stable state - */ - tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW; - - for (count = 0L; count < cycles; count++) - alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); - - } - - return status; -} - -int altera_wait_msecs(struct altera_state *astate, - s32 microseconds, enum altera_jtag_state wait_state) -/* - * Causes JTAG hardware to sit in the specified stable - * state for the specified duration of real time. If - * no JTAG operations have been performed yet, then only - * a delay is performed. This permits the WAIT USECS - * statement to be used in VECTOR programs without causing - * any JTAG operations. - * Returns 0 for success, else appropriate error code. - */ -{ - struct altera_jtag *js = &astate->js; - int status = 0; - - if ((js->jtag_state != ILLEGAL_JTAG_STATE) && - (js->jtag_state != wait_state)) - status = altera_goto_jstate(astate, wait_state); - - if (status == 0) - /* Wait for specified time interval */ - udelay(microseconds); - - return status; -} - -static void altera_concatenate_data(u8 *buffer, - u8 *preamble_data, - u32 preamble_count, - u8 *target_data, - u32 start_index, - u32 target_count, - u8 *postamble_data, - u32 postamble_count) -/* - * Copies preamble data, target data, and postamble data - * into one buffer for IR or DR scans. - */ -{ - u32 i, j, k; - - for (i = 0L; i < preamble_count; ++i) { - if (preamble_data[i >> 3L] & (1L << (i & 7L))) - buffer[i >> 3L] |= (1L << (i & 7L)); - else - buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); - - } - - j = start_index; - k = preamble_count + target_count; - for (; i < k; ++i, ++j) { - if (target_data[j >> 3L] & (1L << (j & 7L))) - buffer[i >> 3L] |= (1L << (i & 7L)); - else - buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); - - } - - j = 0L; - k = preamble_count + target_count + postamble_count; - for (; i < k; ++i, ++j) { - if (postamble_data[j >> 3L] & (1L << (j & 7L))) - buffer[i >> 3L] |= (1L << (i & 7L)); - else - buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); - - } -} - -static int alt_jtag_drscan(struct altera_state *astate, - int start_state, - int count, - u8 *tdi, - u8 *tdo) -{ - int i = 0; - int tdo_bit = 0; - int status = 1; - - /* First go to DRSHIFT state */ - switch (start_state) { - case 0: /* IDLE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(0, 0, 0); /* DRCAPTURE */ - alt_jtag_io(0, 0, 0); /* DRSHIFT */ - break; - - case 1: /* DRPAUSE */ - alt_jtag_io(1, 0, 0); /* DREXIT2 */ - alt_jtag_io(1, 0, 0); /* DRUPDATE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(0, 0, 0); /* DRCAPTURE */ - alt_jtag_io(0, 0, 0); /* DRSHIFT */ - break; - - case 2: /* IRPAUSE */ - alt_jtag_io(1, 0, 0); /* IREXIT2 */ - alt_jtag_io(1, 0, 0); /* IRUPDATE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(0, 0, 0); /* DRCAPTURE */ - alt_jtag_io(0, 0, 0); /* DRSHIFT */ - break; - - default: - status = 0; - } - - if (status) { - /* loop in the SHIFT-DR state */ - for (i = 0; i < count; i++) { - tdo_bit = alt_jtag_io( - (i == count - 1), - tdi[i >> 3] & (1 << (i & 7)), - (tdo != NULL)); - - if (tdo != NULL) { - if (tdo_bit) - tdo[i >> 3] |= (1 << (i & 7)); - else - tdo[i >> 3] &= ~(u32)(1 << (i & 7)); - - } - } - - alt_jtag_io(0, 0, 0); /* DRPAUSE */ - } - - return status; -} - -static int alt_jtag_irscan(struct altera_state *astate, - int start_state, - int count, - u8 *tdi, - u8 *tdo) -{ - int i = 0; - int tdo_bit = 0; - int status = 1; - - /* First go to IRSHIFT state */ - switch (start_state) { - case 0: /* IDLE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(1, 0, 0); /* IRSELECT */ - alt_jtag_io(0, 0, 0); /* IRCAPTURE */ - alt_jtag_io(0, 0, 0); /* IRSHIFT */ - break; - - case 1: /* DRPAUSE */ - alt_jtag_io(1, 0, 0); /* DREXIT2 */ - alt_jtag_io(1, 0, 0); /* DRUPDATE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(1, 0, 0); /* IRSELECT */ - alt_jtag_io(0, 0, 0); /* IRCAPTURE */ - alt_jtag_io(0, 0, 0); /* IRSHIFT */ - break; - - case 2: /* IRPAUSE */ - alt_jtag_io(1, 0, 0); /* IREXIT2 */ - alt_jtag_io(1, 0, 0); /* IRUPDATE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(1, 0, 0); /* IRSELECT */ - alt_jtag_io(0, 0, 0); /* IRCAPTURE */ - alt_jtag_io(0, 0, 0); /* IRSHIFT */ - break; - - default: - status = 0; - } - - if (status) { - /* loop in the SHIFT-IR state */ - for (i = 0; i < count; i++) { - tdo_bit = alt_jtag_io( - (i == count - 1), - tdi[i >> 3] & (1 << (i & 7)), - (tdo != NULL)); - if (tdo != NULL) { - if (tdo_bit) - tdo[i >> 3] |= (1 << (i & 7)); - else - tdo[i >> 3] &= ~(u32)(1 << (i & 7)); - - } - } - - alt_jtag_io(0, 0, 0); /* IRPAUSE */ - } - - return status; -} - -static void altera_extract_target_data(u8 *buffer, - u8 *target_data, - u32 start_index, - u32 preamble_count, - u32 target_count) -/* - * Copies target data from scan buffer, filtering out - * preamble and postamble data. - */ -{ - u32 i; - u32 j; - u32 k; - - j = preamble_count; - k = start_index + target_count; - for (i = start_index; i < k; ++i, ++j) { - if (buffer[j >> 3] & (1 << (j & 7))) - target_data[i >> 3] |= (1 << (i & 7)); - else - target_data[i >> 3] &= ~(u32)(1 << (i & 7)); - - } -} - -int altera_irscan(struct altera_state *astate, - u32 count, - u8 *tdi_data, - u32 start_index) -/* Shifts data into instruction register */ -{ - struct altera_jtag *js = &astate->js; - int start_code = 0; - u32 alloc_chars = 0; - u32 shift_count = js->ir_pre + count + js->ir_post; - int status = 0; - enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; - - switch (js->jtag_state) { - case ILLEGAL_JTAG_STATE: - case RESET: - case IDLE: - start_code = 0; - start_state = IDLE; - break; - - case DRSELECT: - case DRCAPTURE: - case DRSHIFT: - case DREXIT1: - case DRPAUSE: - case DREXIT2: - case DRUPDATE: - start_code = 1; - start_state = DRPAUSE; - break; - - case IRSELECT: - case IRCAPTURE: - case IRSHIFT: - case IREXIT1: - case IRPAUSE: - case IREXIT2: - case IRUPDATE: - start_code = 2; - start_state = IRPAUSE; - break; - - default: - status = -EREMOTEIO; - break; - } - - if (status == 0) - if (js->jtag_state != start_state) - status = altera_goto_jstate(astate, start_state); - - if (status == 0) { - if (shift_count > js->ir_length) { - alloc_chars = (shift_count + 7) >> 3; - kfree(js->ir_buffer); - js->ir_buffer = (u8 *)alt_malloc(alloc_chars); - if (js->ir_buffer == NULL) - status = -ENOMEM; - else - js->ir_length = alloc_chars * 8; - - } - } - - if (status == 0) { - /* - * Copy preamble data, IR data, - * and postamble data into a buffer - */ - altera_concatenate_data(js->ir_buffer, - js->ir_pre_data, - js->ir_pre, - tdi_data, - start_index, - count, - js->ir_post_data, - js->ir_post); - /* Do the IRSCAN */ - alt_jtag_irscan(astate, - start_code, - shift_count, - js->ir_buffer, - NULL); - - /* alt_jtag_irscan() always ends in IRPAUSE state */ - js->jtag_state = IRPAUSE; - } - - if (status == 0) - if (js->irstop_state != IRPAUSE) - status = altera_goto_jstate(astate, js->irstop_state); - - - return status; -} - -int altera_swap_ir(struct altera_state *astate, - u32 count, - u8 *in_data, - u32 in_index, - u8 *out_data, - u32 out_index) -/* Shifts data into instruction register, capturing output data */ -{ - struct altera_jtag *js = &astate->js; - int start_code = 0; - u32 alloc_chars = 0; - u32 shift_count = js->ir_pre + count + js->ir_post; - int status = 0; - enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; - - switch (js->jtag_state) { - case ILLEGAL_JTAG_STATE: - case RESET: - case IDLE: - start_code = 0; - start_state = IDLE; - break; - - case DRSELECT: - case DRCAPTURE: - case DRSHIFT: - case DREXIT1: - case DRPAUSE: - case DREXIT2: - case DRUPDATE: - start_code = 1; - start_state = DRPAUSE; - break; - - case IRSELECT: - case IRCAPTURE: - case IRSHIFT: - case IREXIT1: - case IRPAUSE: - case IREXIT2: - case IRUPDATE: - start_code = 2; - start_state = IRPAUSE; - break; - - default: - status = -EREMOTEIO; - break; - } - - if (status == 0) - if (js->jtag_state != start_state) - status = altera_goto_jstate(astate, start_state); - - if (status == 0) { - if (shift_count > js->ir_length) { - alloc_chars = (shift_count + 7) >> 3; - kfree(js->ir_buffer); - js->ir_buffer = (u8 *)alt_malloc(alloc_chars); - if (js->ir_buffer == NULL) - status = -ENOMEM; - else - js->ir_length = alloc_chars * 8; - - } - } - - if (status == 0) { - /* - * Copy preamble data, IR data, - * and postamble data into a buffer - */ - altera_concatenate_data(js->ir_buffer, - js->ir_pre_data, - js->ir_pre, - in_data, - in_index, - count, - js->ir_post_data, - js->ir_post); - - /* Do the IRSCAN */ - alt_jtag_irscan(astate, - start_code, - shift_count, - js->ir_buffer, - js->ir_buffer); - - /* alt_jtag_irscan() always ends in IRPAUSE state */ - js->jtag_state = IRPAUSE; - } - - if (status == 0) - if (js->irstop_state != IRPAUSE) - status = altera_goto_jstate(astate, js->irstop_state); - - - if (status == 0) - /* Now extract the returned data from the buffer */ - altera_extract_target_data(js->ir_buffer, - out_data, out_index, - js->ir_pre, count); - - return status; -} - -int altera_drscan(struct altera_state *astate, - u32 count, - u8 *tdi_data, - u32 start_index) -/* Shifts data into data register (ignoring output data) */ -{ - struct altera_jtag *js = &astate->js; - int start_code = 0; - u32 alloc_chars = 0; - u32 shift_count = js->dr_pre + count + js->dr_post; - int status = 0; - enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; - - switch (js->jtag_state) { - case ILLEGAL_JTAG_STATE: - case RESET: - case IDLE: - start_code = 0; - start_state = IDLE; - break; - - case DRSELECT: - case DRCAPTURE: - case DRSHIFT: - case DREXIT1: - case DRPAUSE: - case DREXIT2: - case DRUPDATE: - start_code = 1; - start_state = DRPAUSE; - break; - - case IRSELECT: - case IRCAPTURE: - case IRSHIFT: - case IREXIT1: - case IRPAUSE: - case IREXIT2: - case IRUPDATE: - start_code = 2; - start_state = IRPAUSE; - break; - - default: - status = -EREMOTEIO; - break; - } - - if (status == 0) - if (js->jtag_state != start_state) - status = altera_goto_jstate(astate, start_state); - - if (status == 0) { - if (shift_count > js->dr_length) { - alloc_chars = (shift_count + 7) >> 3; - kfree(js->dr_buffer); - js->dr_buffer = (u8 *)alt_malloc(alloc_chars); - if (js->dr_buffer == NULL) - status = -ENOMEM; - else - js->dr_length = alloc_chars * 8; - - } - } - - if (status == 0) { - /* - * Copy preamble data, DR data, - * and postamble data into a buffer - */ - altera_concatenate_data(js->dr_buffer, - js->dr_pre_data, - js->dr_pre, - tdi_data, - start_index, - count, - js->dr_post_data, - js->dr_post); - /* Do the DRSCAN */ - alt_jtag_drscan(astate, start_code, shift_count, - js->dr_buffer, NULL); - /* alt_jtag_drscan() always ends in DRPAUSE state */ - js->jtag_state = DRPAUSE; - } - - if (status == 0) - if (js->drstop_state != DRPAUSE) - status = altera_goto_jstate(astate, js->drstop_state); - - return status; -} - -int altera_swap_dr(struct altera_state *astate, u32 count, - u8 *in_data, u32 in_index, - u8 *out_data, u32 out_index) -/* Shifts data into data register, capturing output data */ -{ - struct altera_jtag *js = &astate->js; - int start_code = 0; - u32 alloc_chars = 0; - u32 shift_count = js->dr_pre + count + js->dr_post; - int status = 0; - enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; - - switch (js->jtag_state) { - case ILLEGAL_JTAG_STATE: - case RESET: - case IDLE: - start_code = 0; - start_state = IDLE; - break; - - case DRSELECT: - case DRCAPTURE: - case DRSHIFT: - case DREXIT1: - case DRPAUSE: - case DREXIT2: - case DRUPDATE: - start_code = 1; - start_state = DRPAUSE; - break; - - case IRSELECT: - case IRCAPTURE: - case IRSHIFT: - case IREXIT1: - case IRPAUSE: - case IREXIT2: - case IRUPDATE: - start_code = 2; - start_state = IRPAUSE; - break; - - default: - status = -EREMOTEIO; - break; - } - - if (status == 0) - if (js->jtag_state != start_state) - status = altera_goto_jstate(astate, start_state); - - if (status == 0) { - if (shift_count > js->dr_length) { - alloc_chars = (shift_count + 7) >> 3; - kfree(js->dr_buffer); - js->dr_buffer = (u8 *)alt_malloc(alloc_chars); - - if (js->dr_buffer == NULL) - status = -ENOMEM; - else - js->dr_length = alloc_chars * 8; - - } - } - - if (status == 0) { - /* - * Copy preamble data, DR data, - * and postamble data into a buffer - */ - altera_concatenate_data(js->dr_buffer, - js->dr_pre_data, - js->dr_pre, - in_data, - in_index, - count, - js->dr_post_data, - js->dr_post); - - /* Do the DRSCAN */ - alt_jtag_drscan(astate, - start_code, - shift_count, - js->dr_buffer, - js->dr_buffer); - - /* alt_jtag_drscan() always ends in DRPAUSE state */ - js->jtag_state = DRPAUSE; - } - - if (status == 0) - if (js->drstop_state != DRPAUSE) - status = altera_goto_jstate(astate, js->drstop_state); - - if (status == 0) - /* Now extract the returned data from the buffer */ - altera_extract_target_data(js->dr_buffer, - out_data, - out_index, - js->dr_pre, - count); - - return status; -} - -void altera_free_buffers(struct altera_state *astate) -{ - struct altera_jtag *js = &astate->js; - /* If the JTAG interface was used, reset it to TLR */ - if (js->jtag_state != ILLEGAL_JTAG_STATE) - altera_jreset_idle(astate); - - kfree(js->dr_pre_data); - js->dr_pre_data = NULL; - - kfree(js->dr_post_data); - js->dr_post_data = NULL; - - kfree(js->dr_buffer); - js->dr_buffer = NULL; - - kfree(js->ir_pre_data); - js->ir_pre_data = NULL; - - kfree(js->ir_post_data); - js->ir_post_data = NULL; - - kfree(js->ir_buffer); - js->ir_buffer = NULL; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-jtag.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-jtag.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-jtag.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-jtag.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -/* - * altera-jtag.h - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef ALTERA_JTAG_H -#define ALTERA_JTAG_H - -/* Function Prototypes */ -enum altera_jtag_state { - ILLEGAL_JTAG_STATE = -1, - RESET = 0, - IDLE = 1, - DRSELECT = 2, - DRCAPTURE = 3, - DRSHIFT = 4, - DREXIT1 = 5, - DRPAUSE = 6, - DREXIT2 = 7, - DRUPDATE = 8, - IRSELECT = 9, - IRCAPTURE = 10, - IRSHIFT = 11, - IREXIT1 = 12, - IRPAUSE = 13, - IREXIT2 = 14, - IRUPDATE = 15 - -}; - -struct altera_jtag { - /* Global variable to store the current JTAG state */ - enum altera_jtag_state jtag_state; - - /* Store current stop-state for DR and IR scan commands */ - enum altera_jtag_state drstop_state; - enum altera_jtag_state irstop_state; - - /* Store current padding values */ - u32 dr_pre; - u32 dr_post; - u32 ir_pre; - u32 ir_post; - u32 dr_length; - u32 ir_length; - u8 *dr_pre_data; - u8 *dr_post_data; - u8 *ir_pre_data; - u8 *ir_post_data; - u8 *dr_buffer; - u8 *ir_buffer; -}; - -#define ALTERA_STACK_SIZE 128 -#define ALTERA_MESSAGE_LENGTH 1024 - -struct altera_state { - struct altera_config *config; - struct altera_jtag js; - char msg_buff[ALTERA_MESSAGE_LENGTH + 1]; - long stack[ALTERA_STACK_SIZE]; -}; - -int altera_jinit(struct altera_state *astate); -int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state); -int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state); -int altera_set_dr_pre(struct altera_jtag *js, u32 count, u32 start_index, - u8 *preamble_data); -int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, - u8 *preamble_data); -int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, - u8 *postamble_data); -int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, - u8 *postamble_data); -int altera_goto_jstate(struct altera_state *astate, - enum altera_jtag_state state); -int altera_wait_cycles(struct altera_state *astate, s32 cycles, - enum altera_jtag_state wait_state); -int altera_wait_msecs(struct altera_state *astate, s32 microseconds, - enum altera_jtag_state wait_state); -int altera_irscan(struct altera_state *astate, u32 count, - u8 *tdi_data, u32 start_index); -int altera_swap_ir(struct altera_state *astate, - u32 count, u8 *in_data, - u32 in_index, u8 *out_data, - u32 out_index); -int altera_drscan(struct altera_state *astate, u32 count, - u8 *tdi_data, u32 start_index); -int altera_swap_dr(struct altera_state *astate, u32 count, - u8 *in_data, u32 in_index, - u8 *out_data, u32 out_index); -void altera_free_buffers(struct altera_state *astate); -#endif /* ALTERA_JTAG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-lpt.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-lpt.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-lpt.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/altera-lpt.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/* - * altera-lpt.c - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Abylay Ospan - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include "altera-exprt.h" - -static int lpt_hardware_initialized; - -static void byteblaster_write(int port, int data) -{ - outb((u8)data, (u16)(port + 0x378)); -}; - -static int byteblaster_read(int port) -{ - int data = 0; - data = inb((u16)(port + 0x378)); - return data & 0xff; -}; - -int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo) -{ - int data = 0; - int tdo = 0; - int initial_lpt_ctrl = 0; - - if (!lpt_hardware_initialized) { - initial_lpt_ctrl = byteblaster_read(2); - byteblaster_write(2, (initial_lpt_ctrl | 0x02) & 0xdf); - lpt_hardware_initialized = 1; - } - - data = ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0)); - - byteblaster_write(0, data); - - if (read_tdo) { - tdo = byteblaster_read(1); - tdo = ((tdo & 0x80) ? 0 : 1); - } - - byteblaster_write(0, data | 0x01); - - byteblaster_write(0, data); - - return tdo; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -comment "Altera FPGA firmware download module" - -config ALTERA_STAPL - tristate "Altera FPGA firmware download module" - depends on I2C - default n - help - An Altera FPGA module. Say Y when you want to support this tool. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/altera-stapl/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -altera-stapl-objs = altera-lpt.o altera-jtag.o altera-comp.o altera.o - -obj-$(CONFIG_ALTERA_STAPL) += altera-stapl.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-alsa.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-alsa.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-alsa.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-alsa.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,795 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * Based on SAA713x ALSA driver and CX88 driver - * - * 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, version 2 - * - * 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 - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "cx25821.h" -#include "cx25821-reg.h" - -#define AUDIO_SRAM_CHANNEL SRAM_CH08 - -#define dprintk(level, fmt, arg...) \ -do { \ - if (debug >= level) \ - pr_info("%s/1: " fmt, chip->dev->name, ##arg); \ -} while (0) -#define dprintk_core(level, fmt, arg...) \ -do { \ - if (debug >= level) \ - printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name, ##arg); \ -} while (0) - -/**************************************************************************** - Data type declarations - Can be moded to a header file later - ****************************************************************************/ - -static struct snd_card *snd_cx25821_cards[SNDRV_CARDS]; -static int devno; - -struct cx25821_audio_buffer { - unsigned int bpl; - struct btcx_riscmem risc; - struct videobuf_dmabuf dma; -}; - -struct cx25821_audio_dev { - struct cx25821_dev *dev; - struct cx25821_dmaqueue q; - - /* pci i/o */ - struct pci_dev *pci; - - /* audio controls */ - int irq; - - struct snd_card *card; - - unsigned long iobase; - spinlock_t reg_lock; - atomic_t count; - - unsigned int dma_size; - unsigned int period_size; - unsigned int num_periods; - - struct videobuf_dmabuf *dma_risc; - - struct cx25821_audio_buffer *buf; - - struct snd_pcm_substream *substream; -}; - - -/**************************************************************************** - Module global static vars - ****************************************************************************/ - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 }; - -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled."); - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for cx25821 capture interface(s)."); - -/**************************************************************************** - Module macros - ****************************************************************************/ - -MODULE_DESCRIPTION("ALSA driver module for cx25821 based capture cards"); -MODULE_AUTHOR("Hiep Huynh"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Conexant,25821}"); /* "{{Conexant,23881}," */ - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); - -/**************************************************************************** - Module specific funtions - ****************************************************************************/ -/* Constants taken from cx88-reg.h */ -#define AUD_INT_DN_RISCI1 (1 << 0) -#define AUD_INT_UP_RISCI1 (1 << 1) -#define AUD_INT_RDS_DN_RISCI1 (1 << 2) -#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ -#define AUD_INT_UP_RISCI2 (1 << 5) -#define AUD_INT_RDS_DN_RISCI2 (1 << 6) -#define AUD_INT_DN_SYNC (1 << 12) -#define AUD_INT_UP_SYNC (1 << 13) -#define AUD_INT_RDS_DN_SYNC (1 << 14) -#define AUD_INT_OPC_ERR (1 << 16) -#define AUD_INT_BER_IRQ (1 << 20) -#define AUD_INT_MCHG_IRQ (1 << 21) -#define GP_COUNT_CONTROL_RESET 0x3 - -#define PCI_MSK_AUD_EXT (1 << 4) -#define PCI_MSK_AUD_INT (1 << 3) -/* - * BOARD Specific: Sets audio DMA - */ - -static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) -{ - struct cx25821_audio_buffer *buf = chip->buf; - struct cx25821_dev *dev = chip->dev; - struct sram_channel *audio_ch = - &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]; - u32 tmp = 0; - - /* enable output on the GPIO 0 for the MCLK ADC (Audio) */ - cx25821_set_gpiopin_direction(chip->dev, 0, 0); - - /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ - cx_clear(AUD_INT_DMA_CTL, - FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); - - /* setup fifo + format - out channel */ - cx25821_sram_channel_setup_audio(chip->dev, audio_ch, buf->bpl, - buf->risc.dma); - - /* sets bpl size */ - cx_write(AUD_A_LNGTH, buf->bpl); - - /* reset counter */ - /* GP_COUNT_CONTROL_RESET = 0x3 */ - cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); - atomic_set(&chip->count, 0); - - /* Set the input mode to 16-bit */ - tmp = cx_read(AUD_A_CFG); - cx_write(AUD_A_CFG, - tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE | - FLD_AUD_CLK_ENABLE); - - /* - pr_info("DEBUG: Start audio DMA, %d B/line, cmds_start(0x%x)= %d lines/FIFO, %d periods, %d byte buffer\n", - buf->bpl, audio_ch->cmds_start, - cx_read(audio_ch->cmds_start + 12)>>1, - chip->num_periods, buf->bpl * chip->num_periods); - */ - - /* Enables corresponding bits at AUD_INT_STAT */ - cx_write(AUD_A_INT_MSK, - FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | FLD_AUD_DST_SYNC | - FLD_AUD_DST_OPC_ERR); - - /* Clean any pending interrupt bits already set */ - cx_write(AUD_A_INT_STAT, ~0); - - /* enable audio irqs */ - cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT); - - /* Turn on audio downstream fifo and risc enable 0x101 */ - tmp = cx_read(AUD_INT_DMA_CTL); - cx_set(AUD_INT_DMA_CTL, - tmp | (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN)); - - mdelay(100); - return 0; -} - -/* - * BOARD Specific: Resets audio DMA - */ -static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip) -{ - struct cx25821_dev *dev = chip->dev; - - /* stop dma */ - cx_clear(AUD_INT_DMA_CTL, - FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); - - /* disable irqs */ - cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT); - cx_clear(AUD_A_INT_MSK, - AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | AUD_INT_DN_RISCI2 | - AUD_INT_DN_RISCI1); - - return 0; -} - -#define MAX_IRQ_LOOP 50 - -/* - * BOARD Specific: IRQ dma bits - */ -static char *cx25821_aud_irqs[32] = { - "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */ - NULL, /* reserved */ - "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */ - NULL, /* reserved */ - "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ - NULL, /* reserved */ - "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ - NULL, /* reserved */ - "opc_err", "par_err", "rip_err", /* 16-18 */ - "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ -}; - -/* - * BOARD Specific: Threats IRQ audio specific calls - */ -static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status, - u32 mask) -{ - struct cx25821_dev *dev = chip->dev; - - if (0 == (status & mask)) - return; - - cx_write(AUD_A_INT_STAT, status); - if (debug > 1 || (status & mask & ~0xff)) - cx25821_print_irqbits(dev->name, "irq aud", - cx25821_aud_irqs, - ARRAY_SIZE(cx25821_aud_irqs), status, - mask); - - /* risc op code error */ - if (status & AUD_INT_OPC_ERR) { - pr_warn("WARNING %s/1: Audio risc op code error\n", dev->name); - - cx_clear(AUD_INT_DMA_CTL, - FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); - cx25821_sram_channel_dump_audio(dev, - &cx25821_sram_channels - [AUDIO_SRAM_CHANNEL]); - } - if (status & AUD_INT_DN_SYNC) { - pr_warn("WARNING %s: Downstream sync error!\n", dev->name); - cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); - return; - } - - /* risc1 downstream */ - if (status & AUD_INT_DN_RISCI1) { - atomic_set(&chip->count, cx_read(AUD_A_GPCNT)); - snd_pcm_period_elapsed(chip->substream); - } -} - -/* - * BOARD Specific: Handles IRQ calls - */ -static irqreturn_t cx25821_irq(int irq, void *dev_id) -{ - struct cx25821_audio_dev *chip = dev_id; - struct cx25821_dev *dev = chip->dev; - u32 status, pci_status; - u32 audint_status, audint_mask; - int loop, handled = 0; - int audint_count = 0; - - audint_status = cx_read(AUD_A_INT_STAT); - audint_mask = cx_read(AUD_A_INT_MSK); - audint_count = cx_read(AUD_A_GPCNT); - status = cx_read(PCI_INT_STAT); - - for (loop = 0; loop < 1; loop++) { - status = cx_read(PCI_INT_STAT); - if (0 == status) { - status = cx_read(PCI_INT_STAT); - audint_status = cx_read(AUD_A_INT_STAT); - audint_mask = cx_read(AUD_A_INT_MSK); - - if (status) { - handled = 1; - cx_write(PCI_INT_STAT, status); - - cx25821_aud_irq(chip, audint_status, - audint_mask); - break; - } else - goto out; - } - - handled = 1; - cx_write(PCI_INT_STAT, status); - - cx25821_aud_irq(chip, audint_status, audint_mask); - } - - pci_status = cx_read(PCI_INT_STAT); - - if (handled) - cx_write(PCI_INT_STAT, pci_status); - -out: - return IRQ_RETVAL(handled); -} - -static int dsp_buffer_free(struct cx25821_audio_dev *chip) -{ - BUG_ON(!chip->dma_size); - - dprintk(2, "Freeing buffer\n"); - videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); - videobuf_dma_free(chip->dma_risc); - btcx_riscmem_free(chip->pci, &chip->buf->risc); - kfree(chip->buf); - - chip->dma_risc = NULL; - chip->dma_size = 0; - - return 0; -} - -/**************************************************************************** - ALSA PCM Interface - ****************************************************************************/ - -/* - * Digital hardware definition - */ -#define DEFAULT_FIFO_SIZE 384 -static struct snd_pcm_hardware snd_cx25821_digital_hw = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - /* Analog audio output will be full of clicks and pops if there - are not exactly four lines in the SRAM FIFO buffer. */ - .period_bytes_min = DEFAULT_FIFO_SIZE / 3, - .period_bytes_max = DEFAULT_FIFO_SIZE / 3, - .periods_min = 1, - .periods_max = AUDIO_LINE_SIZE, - /* 128 * 128 = 16384 = 1024 * 16 */ - .buffer_bytes_max = (AUDIO_LINE_SIZE * AUDIO_LINE_SIZE), -}; - -/* - * audio pcm capture open callback - */ -static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream) -{ - struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - unsigned int bpl = 0; - - if (!chip) { - pr_err("DEBUG: cx25821 can't find device struct. Can't proceed with open\n"); - return -ENODEV; - } - - err = - snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) - goto _error; - - chip->substream = substream; - - runtime->hw = snd_cx25821_digital_hw; - - if (cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size != - DEFAULT_FIFO_SIZE) { - /* since there are 3 audio Clusters */ - bpl = cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 3; - bpl &= ~7; /* must be multiple of 8 */ - - if (bpl > AUDIO_LINE_SIZE) - bpl = AUDIO_LINE_SIZE; - - runtime->hw.period_bytes_min = bpl; - runtime->hw.period_bytes_max = bpl; - } - - return 0; -_error: - dprintk(1, "Error opening PCM!\n"); - return err; -} - -/* - * audio close callback - */ -static int snd_cx25821_close(struct snd_pcm_substream *substream) -{ - return 0; -} - -/* - * hw_params callback - */ -static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); - struct videobuf_dmabuf *dma; - - struct cx25821_audio_buffer *buf; - int ret; - - if (substream->runtime->dma_area) { - dsp_buffer_free(chip); - substream->runtime->dma_area = NULL; - } - - chip->period_size = params_period_bytes(hw_params); - chip->num_periods = params_periods(hw_params); - chip->dma_size = chip->period_size * params_periods(hw_params); - - BUG_ON(!chip->dma_size); - BUG_ON(chip->num_periods & (chip->num_periods - 1)); - - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (NULL == buf) - return -ENOMEM; - - if (chip->period_size > AUDIO_LINE_SIZE) - chip->period_size = AUDIO_LINE_SIZE; - - buf->bpl = chip->period_size; - - dma = &buf->dma; - videobuf_dma_init(dma); - ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, - (PAGE_ALIGN(chip->dma_size) >> - PAGE_SHIFT)); - if (ret < 0) - goto error; - - ret = videobuf_dma_map(&chip->pci->dev, dma); - if (ret < 0) - goto error; - - ret = - cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, - chip->period_size, chip->num_periods, - 1); - if (ret < 0) { - pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n"); - goto error; - } - - /* Loop back to start of program */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - - chip->buf = buf; - chip->dma_risc = dma; - - substream->runtime->dma_area = chip->dma_risc->vaddr; - substream->runtime->dma_bytes = chip->dma_size; - substream->runtime->dma_addr = 0; - - return 0; - -error: - kfree(buf); - return ret; -} - -/* - * hw free callback - */ -static int snd_cx25821_hw_free(struct snd_pcm_substream *substream) -{ - struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); - - if (substream->runtime->dma_area) { - dsp_buffer_free(chip); - substream->runtime->dma_area = NULL; - } - - return 0; -} - -/* - * prepare callback - */ -static int snd_cx25821_prepare(struct snd_pcm_substream *substream) -{ - return 0; -} - -/* - * trigger callback - */ -static int snd_cx25821_card_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); - int err = 0; - - /* Local interrupts are already disabled by ALSA */ - spin_lock(&chip->reg_lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - err = _cx25821_start_audio_dma(chip); - break; - case SNDRV_PCM_TRIGGER_STOP: - err = _cx25821_stop_audio_dma(chip); - break; - default: - err = -EINVAL; - break; - } - - spin_unlock(&chip->reg_lock); - - return err; -} - -/* - * pointer callback - */ -static snd_pcm_uframes_t snd_cx25821_pointer(struct snd_pcm_substream - *substream) -{ - struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - u16 count; - - count = atomic_read(&chip->count); - - return runtime->period_size * (count & (runtime->periods - 1)); -} - -/* - * page callback (needed for mmap) - */ -static struct page *snd_cx25821_page(struct snd_pcm_substream *substream, - unsigned long offset) -{ - void *pageptr = substream->runtime->dma_area + offset; - - return vmalloc_to_page(pageptr); -} - -/* - * operators - */ -static struct snd_pcm_ops snd_cx25821_pcm_ops = { - .open = snd_cx25821_pcm_open, - .close = snd_cx25821_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_cx25821_hw_params, - .hw_free = snd_cx25821_hw_free, - .prepare = snd_cx25821_prepare, - .trigger = snd_cx25821_card_trigger, - .pointer = snd_cx25821_pointer, - .page = snd_cx25821_page, -}; - -/* - * ALSA create a PCM device: Called when initializing the board. - * Sets up the name and hooks up the callbacks - */ -static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device, - char *name) -{ - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); - if (err < 0) { - pr_info("ERROR: FAILED snd_pcm_new() in %s\n", __func__); - return err; - } - pcm->private_data = chip; - pcm->info_flags = 0; - strcpy(pcm->name, name); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx25821_pcm_ops); - - return 0; -} - -/**************************************************************************** - Basic Flow for Sound Devices - ****************************************************************************/ - -/* - * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio - * Only boards with eeprom and byte 1 at eeprom=1 have it - */ - -static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = { - {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl); - -/* - * Not used in the function snd_cx25821_dev_free so removing - * from the file. - */ -/* -static int snd_cx25821_free(struct cx25821_audio_dev *chip) -{ - if (chip->irq >= 0) - free_irq(chip->irq, chip); - - cx25821_dev_unregister(chip->dev); - pci_disable_device(chip->pci); - - return 0; -} -*/ - -/* - * Component Destructor - */ -static void snd_cx25821_dev_free(struct snd_card *card) -{ - struct cx25821_audio_dev *chip = card->private_data; - - /* snd_cx25821_free(chip); */ - snd_card_free(chip->card); -} - -/* - * Alsa Constructor - Component probe - */ -static int cx25821_audio_initdev(struct cx25821_dev *dev) -{ - struct snd_card *card; - struct cx25821_audio_dev *chip; - int err; - - if (devno >= SNDRV_CARDS) { - pr_info("DEBUG ERROR: devno >= SNDRV_CARDS %s\n", __func__); - return -ENODEV; - } - - if (!enable[devno]) { - ++devno; - pr_info("DEBUG ERROR: !enable[devno] %s\n", __func__); - return -ENOENT; - } - - err = snd_card_create(index[devno], id[devno], THIS_MODULE, - sizeof(struct cx25821_audio_dev), &card); - if (err < 0) { - pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n", - __func__); - return err; - } - - strcpy(card->driver, "cx25821"); - - /* Card "creation" */ - card->private_free = snd_cx25821_dev_free; - chip = card->private_data; - spin_lock_init(&chip->reg_lock); - - chip->dev = dev; - chip->card = card; - chip->pci = dev->pci; - chip->iobase = pci_resource_start(dev->pci, 0); - - chip->irq = dev->pci->irq; - - err = request_irq(dev->pci->irq, cx25821_irq, - IRQF_SHARED | IRQF_DISABLED, chip->dev->name, chip); - - if (err < 0) { - pr_err("ERROR %s: can't get IRQ %d for ALSA\n", - chip->dev->name, dev->pci->irq); - goto error; - } - - err = snd_cx25821_pcm(chip, 0, "cx25821 Digital"); - if (err < 0) { - pr_info("DEBUG ERROR: cannot create snd_cx25821_pcm %s\n", - __func__); - goto error; - } - - snd_card_set_dev(card, &chip->pci->dev); - - strcpy(card->shortname, "cx25821"); - sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name, - chip->iobase, chip->irq); - strcpy(card->mixername, "CX25821"); - - pr_info("%s/%i: ALSA support for cx25821 boards\n", - card->driver, devno); - - err = snd_card_register(card); - if (err < 0) { - pr_info("DEBUG ERROR: cannot register sound card %s\n", - __func__); - goto error; - } - - snd_cx25821_cards[devno] = card; - - devno++; - return 0; - -error: - snd_card_free(card); - return err; -} - -/**************************************************************************** - LINUX MODULE INIT - ****************************************************************************/ -static void cx25821_audio_fini(void) -{ - snd_card_free(snd_cx25821_cards[0]); -} - -/* - * Module initializer - * - * Loops through present saa7134 cards, and assigns an ALSA device - * to each one - * - */ -static int cx25821_alsa_init(void) -{ - struct cx25821_dev *dev = NULL; - struct list_head *list; - - mutex_lock(&cx25821_devlist_mutex); - list_for_each(list, &cx25821_devlist) { - dev = list_entry(list, struct cx25821_dev, devlist); - cx25821_audio_initdev(dev); - } - mutex_unlock(&cx25821_devlist_mutex); - - if (dev == NULL) - pr_info("ERROR ALSA: no cx25821 cards found\n"); - - return 0; - -} - -late_initcall(cx25821_alsa_init); -module_exit(cx25821_audio_fini); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __CX25821_AUDIO_H__ -#define __CX25821_AUDIO_H__ - -#define USE_RISC_NOOP 1 -#define LINES_PER_BUFFER 15 -#define AUDIO_LINE_SIZE 128 - -/* Number of buffer programs to use at once. */ -#define NUMBER_OF_PROGRAMS 8 - -/* - * Max size of the RISC program for a buffer. - worst case is 2 writes per line - * Space is also added for the 4 no-op instructions added on the end. - */ -#ifndef USE_RISC_NOOP -#define MAX_BUFFER_PROGRAM_SIZE \ - (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE*4) -#endif - -/* MAE 12 July 2005 Try to use NOOP RISC instruction instead */ -#ifdef USE_RISC_NOOP -#define MAX_BUFFER_PROGRAM_SIZE \ - (2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_NOOP_INSTRUCTION_SIZE*4) -#endif - -/* Sizes of various instructions in bytes. Used when adding instructions. */ -#define RISC_WRITE_INSTRUCTION_SIZE 12 -#define RISC_JUMP_INSTRUCTION_SIZE 12 -#define RISC_SKIP_INSTRUCTION_SIZE 4 -#define RISC_SYNC_INSTRUCTION_SIZE 4 -#define RISC_WRITECR_INSTRUCTION_SIZE 16 -#define RISC_NOOP_INSTRUCTION_SIZE 4 - -#define MAX_AUDIO_DMA_BUFFER_SIZE \ -(MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + RISC_SYNC_INSTRUCTION_SIZE) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio-upstream.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio-upstream.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio-upstream.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio-upstream.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,802 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "cx25821-video.h" -#include "cx25821-audio-upstream.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); -MODULE_AUTHOR("Hiep Huynh "); -MODULE_LICENSE("GPL"); - -static int _intr_msk = FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF | - FLD_AUD_SRC_SYNC | FLD_AUD_SRC_OPC_ERR; - -int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) -{ - unsigned int i, lines; - u32 cdt; - - if (ch->cmds_start == 0) { - cx_write(ch->ptr1_reg, 0); - cx_write(ch->ptr2_reg, 0); - cx_write(ch->cnt2_reg, 0); - cx_write(ch->cnt1_reg, 0); - return 0; - } - - bpl = (bpl + 7) & ~7; /* alignment */ - cdt = ch->cdt; - lines = ch->fifo_size / bpl; - - if (lines > 3) - lines = 3; - - BUG_ON(lines < 2); - - /* write CDT */ - for (i = 0; i < lines; i++) { - cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); - cx_write(cdt + 16 * i + 4, 0); - cx_write(cdt + 16 * i + 8, 0); - cx_write(cdt + 16 * i + 12, 0); - } - - /* write CMDS */ - cx_write(ch->cmds_start + 0, risc); - - cx_write(ch->cmds_start + 4, 0); - cx_write(ch->cmds_start + 8, cdt); - cx_write(ch->cmds_start + 12, AUDIO_CDT_SIZE_QW); - cx_write(ch->cmds_start + 16, ch->ctrl_start); - - /* IQ size */ - cx_write(ch->cmds_start + 20, AUDIO_IQ_SIZE_DW); - - for (i = 24; i < 80; i += 4) - cx_write(ch->cmds_start + i, 0); - - /* fill registers */ - cx_write(ch->ptr1_reg, ch->fifo_start); - cx_write(ch->ptr2_reg, cdt); - cx_write(ch->cnt2_reg, AUDIO_CDT_SIZE_QW); - cx_write(ch->cnt1_reg, AUDIO_CLUSTER_SIZE_QW - 1); - - return 0; -} - -static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev, - __le32 *rp, - dma_addr_t databuf_phys_addr, - unsigned int bpl, - int fifo_enable) -{ - unsigned int line; - struct sram_channel *sram_ch = - dev->channels[dev->_audio_upstream_channel_select].sram_channels; - int offset = 0; - - /* scan lines */ - for (line = 0; line < LINES_PER_AUDIO_BUFFER; line++) { - *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(databuf_phys_addr + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - - /* Check if we need to enable the FIFO - * after the first 3 lines. - * For the upstream audio channel, - * the risc engine will enable the FIFO */ - if (fifo_enable && line == 2) { - *(rp++) = RISC_WRITECR; - *(rp++) = sram_ch->dma_ctl; - *(rp++) = sram_ch->fld_aud_fifo_en; - *(rp++) = 0x00000020; - } - - offset += AUDIO_LINE_SIZE; - } - - return rp; -} - -int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, - struct pci_dev *pci, - unsigned int bpl, unsigned int lines) -{ - __le32 *rp; - int fifo_enable = 0; - int frame = 0, i = 0; - int frame_size = AUDIO_DATA_BUF_SZ; - int databuf_offset = 0; - int risc_flag = RISC_CNT_INC; - dma_addr_t risc_phys_jump_addr; - - /* Virtual address of Risc buffer program */ - rp = dev->_risc_virt_addr; - - /* sync instruction */ - *(rp++) = cpu_to_le32(RISC_RESYNC | AUDIO_SYNC_LINE); - - for (frame = 0; frame < NUM_AUDIO_FRAMES; frame++) { - databuf_offset = frame_size * frame; - - if (frame == 0) { - fifo_enable = 1; - risc_flag = RISC_CNT_RESET; - } else { - fifo_enable = 0; - risc_flag = RISC_CNT_INC; - } - - /* Calculate physical jump address */ - if ((frame + 1) == NUM_AUDIO_FRAMES) { - risc_phys_jump_addr = - dev->_risc_phys_start_addr + - RISC_SYNC_INSTRUCTION_SIZE; - } else { - risc_phys_jump_addr = - dev->_risc_phys_start_addr + - RISC_SYNC_INSTRUCTION_SIZE + - AUDIO_RISC_DMA_BUF_SIZE * (frame + 1); - } - - rp = cx25821_risc_field_upstream_audio(dev, rp, - dev-> - _audiodata_buf_phys_addr - + databuf_offset, bpl, - fifo_enable); - - if (USE_RISC_NOOP_AUDIO) { - for (i = 0; i < NUM_NO_OPS; i++) - *(rp++) = cpu_to_le32(RISC_NOOP); - } - - /* Loop to (Nth)FrameRISC or to Start of Risc program & - * generate IRQ */ - *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); - *(rp++) = cpu_to_le32(risc_phys_jump_addr); - *(rp++) = cpu_to_le32(0); - - /* Recalculate virtual address based on frame index */ - rp = dev->_risc_virt_addr + RISC_SYNC_INSTRUCTION_SIZE / 4 + - (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4); - } - - return 0; -} - -void cx25821_free_memory_audio(struct cx25821_dev *dev) -{ - if (dev->_risc_virt_addr) { - pci_free_consistent(dev->pci, dev->_audiorisc_size, - dev->_risc_virt_addr, dev->_risc_phys_addr); - dev->_risc_virt_addr = NULL; - } - - if (dev->_audiodata_buf_virt_addr) { - pci_free_consistent(dev->pci, dev->_audiodata_buf_size, - dev->_audiodata_buf_virt_addr, - dev->_audiodata_buf_phys_addr); - dev->_audiodata_buf_virt_addr = NULL; - } -} - -void cx25821_stop_upstream_audio(struct cx25821_dev *dev) -{ - struct sram_channel *sram_ch = - dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels; - u32 tmp = 0; - - if (!dev->_audio_is_running) { - printk(KERN_DEBUG - pr_fmt("No audio file is currently running so return!\n")); - return; - } - /* Disable RISC interrupts */ - cx_write(sram_ch->int_msk, 0); - - /* Turn OFF risc and fifo enable in AUD_DMA_CNTRL */ - tmp = cx_read(sram_ch->dma_ctl); - cx_write(sram_ch->dma_ctl, - tmp & ~(sram_ch->fld_aud_fifo_en | sram_ch->fld_aud_risc_en)); - - /* Clear data buffer memory */ - if (dev->_audiodata_buf_virt_addr) - memset(dev->_audiodata_buf_virt_addr, 0, - dev->_audiodata_buf_size); - - dev->_audio_is_running = 0; - dev->_is_first_audio_frame = 0; - dev->_audioframe_count = 0; - dev->_audiofile_status = END_OF_FILE; - - if (dev->_irq_audio_queues) { - kfree(dev->_irq_audio_queues); - dev->_irq_audio_queues = NULL; - } - - if (dev->_audiofilename != NULL) - kfree(dev->_audiofilename); -} - -void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev) -{ - if (dev->_audio_is_running) - cx25821_stop_upstream_audio(dev); - - cx25821_free_memory_audio(dev); -} - -int cx25821_get_audio_data(struct cx25821_dev *dev, - struct sram_channel *sram_ch) -{ - struct file *myfile; - int frame_index_temp = dev->_audioframe_index; - int i = 0; - int line_size = AUDIO_LINE_SIZE; - int frame_size = AUDIO_DATA_BUF_SZ; - int frame_offset = frame_size * frame_index_temp; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t file_offset = dev->_audioframe_count * frame_size; - loff_t pos; - mm_segment_t old_fs; - - if (dev->_audiofile_status == END_OF_FILE) - return 0; - - myfile = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0); - - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_audiofilename, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (i = 0; i < dev->_audio_lines_count; i++) { - pos = file_offset; - - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); - - if (vfs_read_retval > 0 && vfs_read_retval == line_size - && dev->_audiodata_buf_virt_addr != NULL) { - memcpy((void *)(dev->_audiodata_buf_virt_addr + - frame_offset / 4), mybuf, - vfs_read_retval); - } - - file_offset += vfs_read_retval; - frame_offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Audio file\n", - __func__); - break; - } - } - - if (i > 0) - dev->_audioframe_count++; - - dev->_audiofile_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - filp_close(myfile, NULL); - } - - return 0; -} - -static void cx25821_audioups_handler(struct work_struct *work) -{ - struct cx25821_dev *dev = - container_of(work, struct cx25821_dev, _audio_work_entry); - - if (!dev) { - pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", - __func__); - return; - } - - cx25821_get_audio_data(dev, - dev->channels[dev-> - _audio_upstream_channel_select]. - sram_channels); -} - -int cx25821_openfile_audio(struct cx25821_dev *dev, - struct sram_channel *sram_ch) -{ - struct file *myfile; - int i = 0, j = 0; - int line_size = AUDIO_LINE_SIZE; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t pos; - loff_t offset = (unsigned long)0; - mm_segment_t old_fs; - - myfile = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0); - - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_audiofilename, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (j = 0; j < NUM_AUDIO_FRAMES; j++) { - for (i = 0; i < dev->_audio_lines_count; i++) { - pos = offset; - - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); - - if (vfs_read_retval > 0 - && vfs_read_retval == line_size - && dev->_audiodata_buf_virt_addr != NULL) { - memcpy((void *)(dev-> - _audiodata_buf_virt_addr - + offset / 4), mybuf, - vfs_read_retval); - } - - offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Audio file\n", - __func__); - break; - } - } - - if (i > 0) - dev->_audioframe_count++; - - if (vfs_read_retval < line_size) - break; - } - - dev->_audiofile_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - myfile->f_pos = 0; - filp_close(myfile, NULL); - } - - return 0; -} - -static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, - struct sram_channel *sram_ch, - int bpl) -{ - int ret = 0; - dma_addr_t dma_addr; - dma_addr_t data_dma_addr; - - cx25821_free_memory_audio(dev); - - dev->_risc_virt_addr = - pci_alloc_consistent(dev->pci, dev->audio_upstream_riscbuf_size, - &dma_addr); - dev->_risc_virt_start_addr = dev->_risc_virt_addr; - dev->_risc_phys_start_addr = dma_addr; - dev->_risc_phys_addr = dma_addr; - dev->_audiorisc_size = dev->audio_upstream_riscbuf_size; - - if (!dev->_risc_virt_addr) { - printk(KERN_DEBUG - pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n")); - return -ENOMEM; - } - /* Clear out memory at address */ - memset(dev->_risc_virt_addr, 0, dev->_audiorisc_size); - - /* For Audio Data buffer allocation */ - dev->_audiodata_buf_virt_addr = - pci_alloc_consistent(dev->pci, dev->audio_upstream_databuf_size, - &data_dma_addr); - dev->_audiodata_buf_phys_addr = data_dma_addr; - dev->_audiodata_buf_size = dev->audio_upstream_databuf_size; - - if (!dev->_audiodata_buf_virt_addr) { - printk(KERN_DEBUG - pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n")); - return -ENOMEM; - } - /* Clear out memory at address */ - memset(dev->_audiodata_buf_virt_addr, 0, dev->_audiodata_buf_size); - - ret = cx25821_openfile_audio(dev, sram_ch); - if (ret < 0) - return ret; - - /* Creating RISC programs */ - ret = - cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl, - dev->_audio_lines_count); - if (ret < 0) { - printk(KERN_DEBUG - pr_fmt("ERROR creating audio upstream RISC programs!\n")); - goto error; - } - - return 0; - -error: - return ret; -} - -int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num, - u32 status) -{ - int i = 0; - u32 int_msk_tmp; - struct sram_channel *channel = dev->channels[chan_num].sram_channels; - dma_addr_t risc_phys_jump_addr; - __le32 *rp; - - if (status & FLD_AUD_SRC_RISCI1) { - /* Get interrupt_index of the program that interrupted */ - u32 prog_cnt = cx_read(channel->gpcnt); - - /* Since we've identified our IRQ, clear our bits from the - * interrupt mask and interrupt status registers */ - cx_write(channel->int_msk, 0); - cx_write(channel->int_stat, cx_read(channel->int_stat)); - - spin_lock(&dev->slock); - - while (prog_cnt != dev->_last_index_irq) { - /* Update _last_index_irq */ - if (dev->_last_index_irq < (NUMBER_OF_PROGRAMS - 1)) - dev->_last_index_irq++; - else - dev->_last_index_irq = 0; - - dev->_audioframe_index = dev->_last_index_irq; - - queue_work(dev->_irq_audio_queues, - &dev->_audio_work_entry); - } - - if (dev->_is_first_audio_frame) { - dev->_is_first_audio_frame = 0; - - if (dev->_risc_virt_start_addr != NULL) { - risc_phys_jump_addr = - dev->_risc_phys_start_addr + - RISC_SYNC_INSTRUCTION_SIZE + - AUDIO_RISC_DMA_BUF_SIZE; - - rp = cx25821_risc_field_upstream_audio(dev, - dev-> - _risc_virt_start_addr - + 1, - dev-> - _audiodata_buf_phys_addr, - AUDIO_LINE_SIZE, - FIFO_DISABLE); - - if (USE_RISC_NOOP_AUDIO) { - for (i = 0; i < NUM_NO_OPS; i++) { - *(rp++) = - cpu_to_le32(RISC_NOOP); - } - } - /* Jump to 2nd Audio Frame */ - *(rp++) = - cpu_to_le32(RISC_JUMP | RISC_IRQ1 | - RISC_CNT_RESET); - *(rp++) = cpu_to_le32(risc_phys_jump_addr); - *(rp++) = cpu_to_le32(0); - } - } - - spin_unlock(&dev->slock); - } else { - if (status & FLD_AUD_SRC_OF) - pr_warn("%s(): Audio Received Overflow Error Interrupt!\n", - __func__); - - if (status & FLD_AUD_SRC_SYNC) - pr_warn("%s(): Audio Received Sync Error Interrupt!\n", - __func__); - - if (status & FLD_AUD_SRC_OPC_ERR) - pr_warn("%s(): Audio Received OpCode Error Interrupt!\n", - __func__); - - /* Read and write back the interrupt status register to clear - * our bits */ - cx_write(channel->int_stat, cx_read(channel->int_stat)); - } - - if (dev->_audiofile_status == END_OF_FILE) { - pr_warn("EOF Channel Audio Framecount = %d\n", - dev->_audioframe_count); - return -1; - } - /* ElSE, set the interrupt mask register, re-enable irq. */ - int_msk_tmp = cx_read(channel->int_msk); - cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); - - return 0; -} - -static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id) -{ - struct cx25821_dev *dev = dev_id; - u32 msk_stat, audio_status; - int handled = 0; - struct sram_channel *sram_ch; - - if (!dev) - return -1; - - sram_ch = dev->channels[dev->_audio_upstream_channel_select].sram_channels; - - msk_stat = cx_read(sram_ch->int_mstat); - audio_status = cx_read(sram_ch->int_stat); - - /* Only deal with our interrupt */ - if (audio_status) { - handled = - cx25821_audio_upstream_irq(dev, - dev-> - _audio_upstream_channel_select, - audio_status); - } - - if (handled < 0) - cx25821_stop_upstream_audio(dev); - else - handled += handled; - - return IRQ_RETVAL(handled); -} - -static void cx25821_wait_fifo_enable(struct cx25821_dev *dev, - struct sram_channel *sram_ch) -{ - int count = 0; - u32 tmp; - - do { - /* Wait 10 microsecond before checking to see if the FIFO is - * turned ON. */ - udelay(10); - - tmp = cx_read(sram_ch->dma_ctl); - - /* 10 millisecond timeout */ - if (count++ > 1000) { - pr_err("ERROR: %s() fifo is NOT turned on. Timeout!\n", - __func__); - return; - } - - } while (!(tmp & sram_ch->fld_aud_fifo_en)); - -} - -int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, - struct sram_channel *sram_ch) -{ - u32 tmp = 0; - int err = 0; - - /* Set the physical start address of the RISC program in the initial - * program counter(IPC) member of the CMDS. */ - cx_write(sram_ch->cmds_start + 0, dev->_risc_phys_addr); - /* Risc IPC High 64 bits 63-32 */ - cx_write(sram_ch->cmds_start + 4, 0); - - /* reset counter */ - cx_write(sram_ch->gpcnt_ctl, 3); - - /* Set the line length (It looks like we do not need to set the - * line length) */ - cx_write(sram_ch->aud_length, AUDIO_LINE_SIZE & FLD_AUD_DST_LN_LNGTH); - - /* Set the input mode to 16-bit */ - tmp = cx_read(sram_ch->aud_cfg); - tmp |= - FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE | - FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | FLD_AUD_SONY_MODE; - cx_write(sram_ch->aud_cfg, tmp); - - /* Read and write back the interrupt status register to clear it */ - tmp = cx_read(sram_ch->int_stat); - cx_write(sram_ch->int_stat, tmp); - - /* Clear our bits from the interrupt status register. */ - cx_write(sram_ch->int_stat, _intr_msk); - - /* Set the interrupt mask register, enable irq. */ - cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); - tmp = cx_read(sram_ch->int_msk); - cx_write(sram_ch->int_msk, tmp |= _intr_msk); - - err = - request_irq(dev->pci->irq, cx25821_upstream_irq_audio, - IRQF_SHARED | IRQF_DISABLED, dev->name, dev); - if (err < 0) { - pr_err("%s: can't get upstream IRQ %d\n", - dev->name, dev->pci->irq); - goto fail_irq; - } - - /* Start the DMA engine */ - tmp = cx_read(sram_ch->dma_ctl); - cx_set(sram_ch->dma_ctl, tmp | sram_ch->fld_aud_risc_en); - - dev->_audio_is_running = 1; - dev->_is_first_audio_frame = 1; - - /* The fifo_en bit turns on by the first Risc program */ - cx25821_wait_fifo_enable(dev, sram_ch); - - return 0; - -fail_irq: - cx25821_dev_unregister(dev); - return err; -} - -int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) -{ - struct sram_channel *sram_ch; - int retval = 0; - int err = 0; - int str_length = 0; - - if (dev->_audio_is_running) { - pr_warn("Audio Channel is still running so return!\n"); - return 0; - } - - dev->_audio_upstream_channel_select = channel_select; - sram_ch = dev->channels[channel_select].sram_channels; - - /* Work queue */ - INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler); - dev->_irq_audio_queues = - create_singlethread_workqueue("cx25821_audioworkqueue"); - - if (!dev->_irq_audio_queues) { - printk(KERN_DEBUG - pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n")); - return -ENOMEM; - } - - dev->_last_index_irq = 0; - dev->_audio_is_running = 0; - dev->_audioframe_count = 0; - dev->_audiofile_status = RESET_STATUS; - dev->_audio_lines_count = LINES_PER_AUDIO_BUFFER; - _line_size = AUDIO_LINE_SIZE; - - if (dev->input_audiofilename) { - str_length = strlen(dev->input_audiofilename); - dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL); - - if (!dev->_audiofilename) - goto error; - - memcpy(dev->_audiofilename, dev->input_audiofilename, - str_length + 1); - - /* Default if filename is empty string */ - if (strcmp(dev->input_audiofilename, "") == 0) - dev->_audiofilename = "/root/audioGOOD.wav"; - } else { - str_length = strlen(_defaultAudioName); - dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL); - - if (!dev->_audiofilename) - goto error; - - memcpy(dev->_audiofilename, _defaultAudioName, str_length + 1); - } - - retval = - cx25821_sram_channel_setup_upstream_audio(dev, sram_ch, _line_size, - 0); - - dev->audio_upstream_riscbuf_size = - AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS + - RISC_SYNC_INSTRUCTION_SIZE; - dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS; - - /* Allocating buffers and prepare RISC program */ - retval = - cx25821_audio_upstream_buffer_prepare(dev, sram_ch, _line_size); - if (retval < 0) { - pr_err("%s: Failed to set up Audio upstream buffers!\n", - dev->name); - goto error; - } - /* Start RISC engine */ - cx25821_start_audio_dma_upstream(dev, sram_ch); - - return 0; - -error: - cx25821_dev_unregister(dev); - - return err; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio-upstream.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio-upstream.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio-upstream.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-audio-upstream.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#define NUM_AUDIO_PROGS 8 -#define NUM_AUDIO_FRAMES 8 -#define END_OF_FILE 0 -#define IN_PROGRESS 1 -#define RESET_STATUS -1 -#define FIFO_DISABLE 0 -#define FIFO_ENABLE 1 -#define NUM_NO_OPS 4 - -#define RISC_READ_INSTRUCTION_SIZE 12 -#define RISC_JUMP_INSTRUCTION_SIZE 12 -#define RISC_WRITECR_INSTRUCTION_SIZE 16 -#define RISC_SYNC_INSTRUCTION_SIZE 4 -#define DWORD_SIZE 4 -#define AUDIO_SYNC_LINE 4 - -#define LINES_PER_AUDIO_BUFFER 15 -#define AUDIO_LINE_SIZE 128 -#define AUDIO_DATA_BUF_SZ (AUDIO_LINE_SIZE * LINES_PER_AUDIO_BUFFER) - -#define USE_RISC_NOOP_AUDIO 1 - -#ifdef USE_RISC_NOOP_AUDIO -#define AUDIO_RISC_DMA_BUF_SIZE (LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE + RISC_JUMP_INSTRUCTION_SIZE) -#endif - -#ifndef USE_RISC_NOOP_AUDIO -#define AUDIO_RISC_DMA_BUF_SIZE (LINES_PER_AUDIO_BUFFER*RISC_READ_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + RISC_JUMP_INSTRUCTION_SIZE) -#endif - -static int _line_size; -char *_defaultAudioName = "/root/audioGOOD.wav"; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-biffuncs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-biffuncs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-biffuncs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-biffuncs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _BITFUNCS_H -#define _BITFUNCS_H - -#define SetBit(Bit) (1 << Bit) - -inline u8 getBit(u32 sample, u8 index) -{ - return (u8) ((sample >> index) & 1); -} - -inline u32 clearBitAtPos(u32 value, u8 bit) -{ - return value & ~(1 << bit); -} - -inline u32 setBitAtPos(u32 sample, u8 bit) -{ - sample |= (1 << bit); - return sample; - -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-cards.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * Based on Steven Toth cx23885 driver - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include - -#include "cx25821.h" -#include "tuner-xc2028.h" - -/* board config info */ - -struct cx25821_board cx25821_boards[] = { - [UNKNOWN_BOARD] = { - .name = "UNKNOWN/GENERIC", - /* Ensure safe default for unknown boards */ - .clk_freq = 0, - }, - - [CX25821_BOARD] = { - .name = "CX25821", - .portb = CX25821_RAW, - .portc = CX25821_264, - .input[0].type = CX25821_VMUX_COMPOSITE, - }, - -}; - -const unsigned int cx25821_bcount = ARRAY_SIZE(cx25821_boards); - -struct cx25821_subid cx25821_subids[] = { - { - .subvendor = 0x14f1, - .subdevice = 0x0920, - .card = CX25821_BOARD, - }, -}; - -void cx25821_card_setup(struct cx25821_dev *dev) -{ - static u8 eeprom[256]; - - if (dev->i2c_bus[0].i2c_rc == 0) { - dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, - sizeof(eeprom)); - } -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1518 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * Based on Steven Toth cx23885 driver - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include "cx25821.h" -#include "cx25821-sram.h" -#include "cx25821-video.h" - -MODULE_DESCRIPTION("Driver for Athena cards"); -MODULE_AUTHOR("Shu Lin - Hiep Huynh"); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); - -static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; -module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card, "card type"); - -static unsigned int cx25821_devcount; - -DEFINE_MUTEX(cx25821_devlist_mutex); -EXPORT_SYMBOL(cx25821_devlist_mutex); -LIST_HEAD(cx25821_devlist); -EXPORT_SYMBOL(cx25821_devlist); - -struct sram_channel cx25821_sram_channels[] = { - [SRAM_CH00] = { - .i = SRAM_CH00, - .name = "VID A", - .cmds_start = VID_A_DOWN_CMDS, - .ctrl_start = VID_A_IQ, - .cdt = VID_A_CDT, - .fifo_start = VID_A_DOWN_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA1_PTR1, - .ptr2_reg = DMA1_PTR2, - .cnt1_reg = DMA1_CNT1, - .cnt2_reg = DMA1_CNT2, - .int_msk = VID_A_INT_MSK, - .int_stat = VID_A_INT_STAT, - .int_mstat = VID_A_INT_MSTAT, - .dma_ctl = VID_DST_A_DMA_CTL, - .gpcnt_ctl = VID_DST_A_GPCNT_CTL, - .gpcnt = VID_DST_A_GPCNT, - .vip_ctl = VID_DST_A_VIP_CTL, - .pix_frmt = VID_DST_A_PIX_FRMT, - }, - - [SRAM_CH01] = { - .i = SRAM_CH01, - .name = "VID B", - .cmds_start = VID_B_DOWN_CMDS, - .ctrl_start = VID_B_IQ, - .cdt = VID_B_CDT, - .fifo_start = VID_B_DOWN_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA2_PTR1, - .ptr2_reg = DMA2_PTR2, - .cnt1_reg = DMA2_CNT1, - .cnt2_reg = DMA2_CNT2, - .int_msk = VID_B_INT_MSK, - .int_stat = VID_B_INT_STAT, - .int_mstat = VID_B_INT_MSTAT, - .dma_ctl = VID_DST_B_DMA_CTL, - .gpcnt_ctl = VID_DST_B_GPCNT_CTL, - .gpcnt = VID_DST_B_GPCNT, - .vip_ctl = VID_DST_B_VIP_CTL, - .pix_frmt = VID_DST_B_PIX_FRMT, - }, - - [SRAM_CH02] = { - .i = SRAM_CH02, - .name = "VID C", - .cmds_start = VID_C_DOWN_CMDS, - .ctrl_start = VID_C_IQ, - .cdt = VID_C_CDT, - .fifo_start = VID_C_DOWN_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA3_PTR1, - .ptr2_reg = DMA3_PTR2, - .cnt1_reg = DMA3_CNT1, - .cnt2_reg = DMA3_CNT2, - .int_msk = VID_C_INT_MSK, - .int_stat = VID_C_INT_STAT, - .int_mstat = VID_C_INT_MSTAT, - .dma_ctl = VID_DST_C_DMA_CTL, - .gpcnt_ctl = VID_DST_C_GPCNT_CTL, - .gpcnt = VID_DST_C_GPCNT, - .vip_ctl = VID_DST_C_VIP_CTL, - .pix_frmt = VID_DST_C_PIX_FRMT, - }, - - [SRAM_CH03] = { - .i = SRAM_CH03, - .name = "VID D", - .cmds_start = VID_D_DOWN_CMDS, - .ctrl_start = VID_D_IQ, - .cdt = VID_D_CDT, - .fifo_start = VID_D_DOWN_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA4_PTR1, - .ptr2_reg = DMA4_PTR2, - .cnt1_reg = DMA4_CNT1, - .cnt2_reg = DMA4_CNT2, - .int_msk = VID_D_INT_MSK, - .int_stat = VID_D_INT_STAT, - .int_mstat = VID_D_INT_MSTAT, - .dma_ctl = VID_DST_D_DMA_CTL, - .gpcnt_ctl = VID_DST_D_GPCNT_CTL, - .gpcnt = VID_DST_D_GPCNT, - .vip_ctl = VID_DST_D_VIP_CTL, - .pix_frmt = VID_DST_D_PIX_FRMT, - }, - - [SRAM_CH04] = { - .i = SRAM_CH04, - .name = "VID E", - .cmds_start = VID_E_DOWN_CMDS, - .ctrl_start = VID_E_IQ, - .cdt = VID_E_CDT, - .fifo_start = VID_E_DOWN_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA5_PTR1, - .ptr2_reg = DMA5_PTR2, - .cnt1_reg = DMA5_CNT1, - .cnt2_reg = DMA5_CNT2, - .int_msk = VID_E_INT_MSK, - .int_stat = VID_E_INT_STAT, - .int_mstat = VID_E_INT_MSTAT, - .dma_ctl = VID_DST_E_DMA_CTL, - .gpcnt_ctl = VID_DST_E_GPCNT_CTL, - .gpcnt = VID_DST_E_GPCNT, - .vip_ctl = VID_DST_E_VIP_CTL, - .pix_frmt = VID_DST_E_PIX_FRMT, - }, - - [SRAM_CH05] = { - .i = SRAM_CH05, - .name = "VID F", - .cmds_start = VID_F_DOWN_CMDS, - .ctrl_start = VID_F_IQ, - .cdt = VID_F_CDT, - .fifo_start = VID_F_DOWN_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA6_PTR1, - .ptr2_reg = DMA6_PTR2, - .cnt1_reg = DMA6_CNT1, - .cnt2_reg = DMA6_CNT2, - .int_msk = VID_F_INT_MSK, - .int_stat = VID_F_INT_STAT, - .int_mstat = VID_F_INT_MSTAT, - .dma_ctl = VID_DST_F_DMA_CTL, - .gpcnt_ctl = VID_DST_F_GPCNT_CTL, - .gpcnt = VID_DST_F_GPCNT, - .vip_ctl = VID_DST_F_VIP_CTL, - .pix_frmt = VID_DST_F_PIX_FRMT, - }, - - [SRAM_CH06] = { - .i = SRAM_CH06, - .name = "VID G", - .cmds_start = VID_G_DOWN_CMDS, - .ctrl_start = VID_G_IQ, - .cdt = VID_G_CDT, - .fifo_start = VID_G_DOWN_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA7_PTR1, - .ptr2_reg = DMA7_PTR2, - .cnt1_reg = DMA7_CNT1, - .cnt2_reg = DMA7_CNT2, - .int_msk = VID_G_INT_MSK, - .int_stat = VID_G_INT_STAT, - .int_mstat = VID_G_INT_MSTAT, - .dma_ctl = VID_DST_G_DMA_CTL, - .gpcnt_ctl = VID_DST_G_GPCNT_CTL, - .gpcnt = VID_DST_G_GPCNT, - .vip_ctl = VID_DST_G_VIP_CTL, - .pix_frmt = VID_DST_G_PIX_FRMT, - }, - - [SRAM_CH07] = { - .i = SRAM_CH07, - .name = "VID H", - .cmds_start = VID_H_DOWN_CMDS, - .ctrl_start = VID_H_IQ, - .cdt = VID_H_CDT, - .fifo_start = VID_H_DOWN_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA8_PTR1, - .ptr2_reg = DMA8_PTR2, - .cnt1_reg = DMA8_CNT1, - .cnt2_reg = DMA8_CNT2, - .int_msk = VID_H_INT_MSK, - .int_stat = VID_H_INT_STAT, - .int_mstat = VID_H_INT_MSTAT, - .dma_ctl = VID_DST_H_DMA_CTL, - .gpcnt_ctl = VID_DST_H_GPCNT_CTL, - .gpcnt = VID_DST_H_GPCNT, - .vip_ctl = VID_DST_H_VIP_CTL, - .pix_frmt = VID_DST_H_PIX_FRMT, - }, - - [SRAM_CH08] = { - .name = "audio from", - .cmds_start = AUD_A_DOWN_CMDS, - .ctrl_start = AUD_A_IQ, - .cdt = AUD_A_CDT, - .fifo_start = AUD_A_DOWN_CLUSTER_1, - .fifo_size = AUDIO_CLUSTER_SIZE * 3, - .ptr1_reg = DMA17_PTR1, - .ptr2_reg = DMA17_PTR2, - .cnt1_reg = DMA17_CNT1, - .cnt2_reg = DMA17_CNT2, - }, - - [SRAM_CH09] = { - .i = SRAM_CH09, - .name = "VID Upstream I", - .cmds_start = VID_I_UP_CMDS, - .ctrl_start = VID_I_IQ, - .cdt = VID_I_CDT, - .fifo_start = VID_I_UP_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA15_PTR1, - .ptr2_reg = DMA15_PTR2, - .cnt1_reg = DMA15_CNT1, - .cnt2_reg = DMA15_CNT2, - .int_msk = VID_I_INT_MSK, - .int_stat = VID_I_INT_STAT, - .int_mstat = VID_I_INT_MSTAT, - .dma_ctl = VID_SRC_I_DMA_CTL, - .gpcnt_ctl = VID_SRC_I_GPCNT_CTL, - .gpcnt = VID_SRC_I_GPCNT, - - .vid_fmt_ctl = VID_SRC_I_FMT_CTL, - .vid_active_ctl1 = VID_SRC_I_ACTIVE_CTL1, - .vid_active_ctl2 = VID_SRC_I_ACTIVE_CTL2, - .vid_cdt_size = VID_SRC_I_CDT_SZ, - .irq_bit = 8, - }, - - [SRAM_CH10] = { - .i = SRAM_CH10, - .name = "VID Upstream J", - .cmds_start = VID_J_UP_CMDS, - .ctrl_start = VID_J_IQ, - .cdt = VID_J_CDT, - .fifo_start = VID_J_UP_CLUSTER_1, - .fifo_size = (VID_CLUSTER_SIZE << 2), - .ptr1_reg = DMA16_PTR1, - .ptr2_reg = DMA16_PTR2, - .cnt1_reg = DMA16_CNT1, - .cnt2_reg = DMA16_CNT2, - .int_msk = VID_J_INT_MSK, - .int_stat = VID_J_INT_STAT, - .int_mstat = VID_J_INT_MSTAT, - .dma_ctl = VID_SRC_J_DMA_CTL, - .gpcnt_ctl = VID_SRC_J_GPCNT_CTL, - .gpcnt = VID_SRC_J_GPCNT, - - .vid_fmt_ctl = VID_SRC_J_FMT_CTL, - .vid_active_ctl1 = VID_SRC_J_ACTIVE_CTL1, - .vid_active_ctl2 = VID_SRC_J_ACTIVE_CTL2, - .vid_cdt_size = VID_SRC_J_CDT_SZ, - .irq_bit = 9, - }, - - [SRAM_CH11] = { - .i = SRAM_CH11, - .name = "Audio Upstream Channel B", - .cmds_start = AUD_B_UP_CMDS, - .ctrl_start = AUD_B_IQ, - .cdt = AUD_B_CDT, - .fifo_start = AUD_B_UP_CLUSTER_1, - .fifo_size = (AUDIO_CLUSTER_SIZE * 3), - .ptr1_reg = DMA22_PTR1, - .ptr2_reg = DMA22_PTR2, - .cnt1_reg = DMA22_CNT1, - .cnt2_reg = DMA22_CNT2, - .int_msk = AUD_B_INT_MSK, - .int_stat = AUD_B_INT_STAT, - .int_mstat = AUD_B_INT_MSTAT, - .dma_ctl = AUD_INT_DMA_CTL, - .gpcnt_ctl = AUD_B_GPCNT_CTL, - .gpcnt = AUD_B_GPCNT, - .aud_length = AUD_B_LNGTH, - .aud_cfg = AUD_B_CFG, - .fld_aud_fifo_en = FLD_AUD_SRC_B_FIFO_EN, - .fld_aud_risc_en = FLD_AUD_SRC_B_RISC_EN, - .irq_bit = 11, - }, -}; -EXPORT_SYMBOL(cx25821_sram_channels); - -struct sram_channel *channel0 = &cx25821_sram_channels[SRAM_CH00]; -struct sram_channel *channel1 = &cx25821_sram_channels[SRAM_CH01]; -struct sram_channel *channel2 = &cx25821_sram_channels[SRAM_CH02]; -struct sram_channel *channel3 = &cx25821_sram_channels[SRAM_CH03]; -struct sram_channel *channel4 = &cx25821_sram_channels[SRAM_CH04]; -struct sram_channel *channel5 = &cx25821_sram_channels[SRAM_CH05]; -struct sram_channel *channel6 = &cx25821_sram_channels[SRAM_CH06]; -struct sram_channel *channel7 = &cx25821_sram_channels[SRAM_CH07]; -struct sram_channel *channel9 = &cx25821_sram_channels[SRAM_CH09]; -struct sram_channel *channel10 = &cx25821_sram_channels[SRAM_CH10]; -struct sram_channel *channel11 = &cx25821_sram_channels[SRAM_CH11]; - -struct cx25821_dmaqueue mpegq; - -static int cx25821_risc_decode(u32 risc) -{ - static const char * const instr[16] = { - [RISC_SYNC >> 28] = "sync", - [RISC_WRITE >> 28] = "write", - [RISC_WRITEC >> 28] = "writec", - [RISC_READ >> 28] = "read", - [RISC_READC >> 28] = "readc", - [RISC_JUMP >> 28] = "jump", - [RISC_SKIP >> 28] = "skip", - [RISC_WRITERM >> 28] = "writerm", - [RISC_WRITECM >> 28] = "writecm", - [RISC_WRITECR >> 28] = "writecr", - }; - static const int incr[16] = { - [RISC_WRITE >> 28] = 3, - [RISC_JUMP >> 28] = 3, - [RISC_SKIP >> 28] = 1, - [RISC_SYNC >> 28] = 1, - [RISC_WRITERM >> 28] = 3, - [RISC_WRITECM >> 28] = 3, - [RISC_WRITECR >> 28] = 4, - }; - static const char * const bits[] = { - "12", "13", "14", "resync", - "cnt0", "cnt1", "18", "19", - "20", "21", "22", "23", - "irq1", "irq2", "eol", "sol", - }; - int i; - - pr_cont("0x%08x [ %s", - risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); - for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) { - if (risc & (1 << (i + 12))) - pr_cont(" %s", bits[i]); - } - pr_cont(" count=%d ]\n", risc & 0xfff); - return incr[risc >> 28] ? incr[risc >> 28] : 1; -} - -static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) -{ - struct cx25821_i2c *bus = i2c_adap->algo_data; - struct cx25821_dev *dev = bus->dev; - return cx_read(bus->reg_stat) & 0x01; -} - -void cx_i2c_read_print(struct cx25821_dev *dev, u32 reg, const char *reg_string) -{ - int tmp = 0; - u32 value = 0; - - value = cx25821_i2c_read(&dev->i2c_bus[0], reg, &tmp); -} - -static void cx25821_registers_init(struct cx25821_dev *dev) -{ - u32 tmp; - - /* enable RUN_RISC in Pecos */ - cx_write(DEV_CNTRL2, 0x20); - - /* Set the master PCI interrupt masks to enable video, audio, MBIF, - * and GPIO interrupts - * I2C interrupt masking is handled by the I2C objects themselves. */ - cx_write(PCI_INT_MSK, 0x2001FFFF); - - tmp = cx_read(RDR_TLCTL0); - tmp &= ~FLD_CFG_RCB_CK_EN; /* Clear the RCB_CK_EN bit */ - cx_write(RDR_TLCTL0, tmp); - - /* PLL-A setting for the Audio Master Clock */ - cx_write(PLL_A_INT_FRAC, 0x9807A58B); - - /* PLL_A_POST = 0x1C, PLL_A_OUT_TO_PIN = 0x1 */ - cx_write(PLL_A_POST_STAT_BIST, 0x8000019C); - - /* clear reset bit [31] */ - tmp = cx_read(PLL_A_INT_FRAC); - cx_write(PLL_A_INT_FRAC, tmp & 0x7FFFFFFF); - - /* PLL-B setting for Mobilygen Host Bus Interface */ - cx_write(PLL_B_INT_FRAC, 0x9883A86F); - - /* PLL_B_POST = 0xD, PLL_B_OUT_TO_PIN = 0x0 */ - cx_write(PLL_B_POST_STAT_BIST, 0x8000018D); - - /* clear reset bit [31] */ - tmp = cx_read(PLL_B_INT_FRAC); - cx_write(PLL_B_INT_FRAC, tmp & 0x7FFFFFFF); - - /* PLL-C setting for video upstream channel */ - cx_write(PLL_C_INT_FRAC, 0x96A0EA3F); - - /* PLL_C_POST = 0x3, PLL_C_OUT_TO_PIN = 0x0 */ - cx_write(PLL_C_POST_STAT_BIST, 0x80000103); - - /* clear reset bit [31] */ - tmp = cx_read(PLL_C_INT_FRAC); - cx_write(PLL_C_INT_FRAC, tmp & 0x7FFFFFFF); - - /* PLL-D setting for audio upstream channel */ - cx_write(PLL_D_INT_FRAC, 0x98757F5B); - - /* PLL_D_POST = 0x13, PLL_D_OUT_TO_PIN = 0x0 */ - cx_write(PLL_D_POST_STAT_BIST, 0x80000113); - - /* clear reset bit [31] */ - tmp = cx_read(PLL_D_INT_FRAC); - cx_write(PLL_D_INT_FRAC, tmp & 0x7FFFFFFF); - - /* This selects the PLL C clock source for the video upstream channel - * I and J */ - tmp = cx_read(VID_CH_CLK_SEL); - cx_write(VID_CH_CLK_SEL, (tmp & 0x00FFFFFF) | 0x24000000); - - /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for - * channel A-C - * select 656/VIP DST for downstream Channel A - C */ - tmp = cx_read(VID_CH_MODE_SEL); - /* cx_write( VID_CH_MODE_SEL, tmp | 0x1B0001FF); */ - cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); - - /* enables 656 port I and J as output */ - tmp = cx_read(CLK_RST); - /* use external ALT_PLL_REF pin as its reference clock instead */ - tmp |= FLD_USE_ALT_PLL_REF; - cx_write(CLK_RST, tmp & ~(FLD_VID_I_CLK_NOE | FLD_VID_J_CLK_NOE)); - - mdelay(100); -} - -int cx25821_sram_channel_setup(struct cx25821_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) -{ - unsigned int i, lines; - u32 cdt; - - if (ch->cmds_start == 0) { - cx_write(ch->ptr1_reg, 0); - cx_write(ch->ptr2_reg, 0); - cx_write(ch->cnt2_reg, 0); - cx_write(ch->cnt1_reg, 0); - return 0; - } - - bpl = (bpl + 7) & ~7; /* alignment */ - cdt = ch->cdt; - lines = ch->fifo_size / bpl; - - if (lines > 4) - lines = 4; - - BUG_ON(lines < 2); - - cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - cx_write(8 + 4, 8); - cx_write(8 + 8, 0); - - /* write CDT */ - for (i = 0; i < lines; i++) { - cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); - cx_write(cdt + 16 * i + 4, 0); - cx_write(cdt + 16 * i + 8, 0); - cx_write(cdt + 16 * i + 12, 0); - } - - /* init the first cdt buffer */ - for (i = 0; i < 128; i++) - cx_write(ch->fifo_start + 4 * i, i); - - /* write CMDS */ - if (ch->jumponly) - cx_write(ch->cmds_start + 0, 8); - else - cx_write(ch->cmds_start + 0, risc); - - cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ - cx_write(ch->cmds_start + 8, cdt); - cx_write(ch->cmds_start + 12, (lines * 16) >> 3); - cx_write(ch->cmds_start + 16, ch->ctrl_start); - - if (ch->jumponly) - cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); - else - cx_write(ch->cmds_start + 20, 64 >> 2); - - for (i = 24; i < 80; i += 4) - cx_write(ch->cmds_start + i, 0); - - /* fill registers */ - cx_write(ch->ptr1_reg, ch->fifo_start); - cx_write(ch->ptr2_reg, cdt); - cx_write(ch->cnt2_reg, (lines * 16) >> 3); - cx_write(ch->cnt1_reg, (bpl >> 3) - 1); - - return 0; -} -EXPORT_SYMBOL(cx25821_sram_channel_setup); - -int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) -{ - unsigned int i, lines; - u32 cdt; - - if (ch->cmds_start == 0) { - cx_write(ch->ptr1_reg, 0); - cx_write(ch->ptr2_reg, 0); - cx_write(ch->cnt2_reg, 0); - cx_write(ch->cnt1_reg, 0); - return 0; - } - - bpl = (bpl + 7) & ~7; /* alignment */ - cdt = ch->cdt; - lines = ch->fifo_size / bpl; - - if (lines > 3) - lines = 3; /* for AUDIO */ - - BUG_ON(lines < 2); - - cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - cx_write(8 + 4, 8); - cx_write(8 + 8, 0); - - /* write CDT */ - for (i = 0; i < lines; i++) { - cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); - cx_write(cdt + 16 * i + 4, 0); - cx_write(cdt + 16 * i + 8, 0); - cx_write(cdt + 16 * i + 12, 0); - } - - /* write CMDS */ - if (ch->jumponly) - cx_write(ch->cmds_start + 0, 8); - else - cx_write(ch->cmds_start + 0, risc); - - cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ - cx_write(ch->cmds_start + 8, cdt); - cx_write(ch->cmds_start + 12, (lines * 16) >> 3); - cx_write(ch->cmds_start + 16, ch->ctrl_start); - - /* IQ size */ - if (ch->jumponly) - cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); - else - cx_write(ch->cmds_start + 20, 64 >> 2); - - /* zero out */ - for (i = 24; i < 80; i += 4) - cx_write(ch->cmds_start + i, 0); - - /* fill registers */ - cx_write(ch->ptr1_reg, ch->fifo_start); - cx_write(ch->ptr2_reg, cdt); - cx_write(ch->cnt2_reg, (lines * 16) >> 3); - cx_write(ch->cnt1_reg, (bpl >> 3) - 1); - - return 0; -} -EXPORT_SYMBOL(cx25821_sram_channel_setup_audio); - -void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch) -{ - static char *name[] = { - "init risc lo", - "init risc hi", - "cdt base", - "cdt size", - "iq base", - "iq size", - "risc pc lo", - "risc pc hi", - "iq wr ptr", - "iq rd ptr", - "cdt current", - "pci target lo", - "pci target hi", - "line / byte", - }; - u32 risc; - unsigned int i, j, n; - - pr_warn("%s: %s - dma channel status dump\n", dev->name, ch->name); - for (i = 0; i < ARRAY_SIZE(name); i++) - pr_warn("cmds + 0x%2x: %-15s: 0x%08x\n", - i * 4, name[i], cx_read(ch->cmds_start + 4 * i)); - - j = i * 4; - for (i = 0; i < 4;) { - risc = cx_read(ch->cmds_start + 4 * (i + 14)); - pr_warn("cmds + 0x%2x: risc%d: ", j + i * 4, i); - i += cx25821_risc_decode(risc); - } - - for (i = 0; i < (64 >> 2); i += n) { - risc = cx_read(ch->ctrl_start + 4 * i); - /* No consideration for bits 63-32 */ - - pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ", - i * 4, ch->ctrl_start + 4 * i, i); - n = cx25821_risc_decode(risc); - for (j = 1; j < n; j++) { - risc = cx_read(ch->ctrl_start + 4 * (i + j)); - pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n", - 4 * (i + j), i + j, risc, j); - } - } - - pr_warn(" : fifo: 0x%08x -> 0x%x\n", - ch->fifo_start, ch->fifo_start + ch->fifo_size); - pr_warn(" : ctrl: 0x%08x -> 0x%x\n", - ch->ctrl_start, ch->ctrl_start + 6 * 16); - pr_warn(" : ptr1_reg: 0x%08x\n", - cx_read(ch->ptr1_reg)); - pr_warn(" : ptr2_reg: 0x%08x\n", - cx_read(ch->ptr2_reg)); - pr_warn(" : cnt1_reg: 0x%08x\n", - cx_read(ch->cnt1_reg)); - pr_warn(" : cnt2_reg: 0x%08x\n", - cx_read(ch->cnt2_reg)); -} -EXPORT_SYMBOL(cx25821_sram_channel_dump); - -void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, - struct sram_channel *ch) -{ - static const char * const name[] = { - "init risc lo", - "init risc hi", - "cdt base", - "cdt size", - "iq base", - "iq size", - "risc pc lo", - "risc pc hi", - "iq wr ptr", - "iq rd ptr", - "cdt current", - "pci target lo", - "pci target hi", - "line / byte", - }; - - u32 risc, value, tmp; - unsigned int i, j, n; - - pr_info("\n%s: %s - dma Audio channel status dump\n", - dev->name, ch->name); - - for (i = 0; i < ARRAY_SIZE(name); i++) - pr_info("%s: cmds + 0x%2x: %-15s: 0x%08x\n", - dev->name, i * 4, name[i], - cx_read(ch->cmds_start + 4 * i)); - - j = i * 4; - for (i = 0; i < 4;) { - risc = cx_read(ch->cmds_start + 4 * (i + 14)); - pr_warn("cmds + 0x%2x: risc%d: ", j + i * 4, i); - i += cx25821_risc_decode(risc); - } - - for (i = 0; i < (64 >> 2); i += n) { - risc = cx_read(ch->ctrl_start + 4 * i); - /* No consideration for bits 63-32 */ - - pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ", - i * 4, ch->ctrl_start + 4 * i, i); - n = cx25821_risc_decode(risc); - - for (j = 1; j < n; j++) { - risc = cx_read(ch->ctrl_start + 4 * (i + j)); - pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n", - 4 * (i + j), i + j, risc, j); - } - } - - pr_warn(" : fifo: 0x%08x -> 0x%x\n", - ch->fifo_start, ch->fifo_start + ch->fifo_size); - pr_warn(" : ctrl: 0x%08x -> 0x%x\n", - ch->ctrl_start, ch->ctrl_start + 6 * 16); - pr_warn(" : ptr1_reg: 0x%08x\n", - cx_read(ch->ptr1_reg)); - pr_warn(" : ptr2_reg: 0x%08x\n", - cx_read(ch->ptr2_reg)); - pr_warn(" : cnt1_reg: 0x%08x\n", - cx_read(ch->cnt1_reg)); - pr_warn(" : cnt2_reg: 0x%08x\n", - cx_read(ch->cnt2_reg)); - - for (i = 0; i < 4; i++) { - risc = cx_read(ch->cmds_start + 56 + (i * 4)); - pr_warn("instruction %d = 0x%x\n", i, risc); - } - - /* read data from the first cdt buffer */ - risc = cx_read(AUD_A_CDT); - pr_warn("\nread cdt loc=0x%x\n", risc); - for (i = 0; i < 8; i++) { - n = cx_read(risc + i * 4); - pr_cont("0x%x ", n); - } - pr_cont("\n\n"); - - value = cx_read(CLK_RST); - CX25821_INFO(" CLK_RST = 0x%x\n\n", value); - - value = cx_read(PLL_A_POST_STAT_BIST); - CX25821_INFO(" PLL_A_POST_STAT_BIST = 0x%x\n\n", value); - value = cx_read(PLL_A_INT_FRAC); - CX25821_INFO(" PLL_A_INT_FRAC = 0x%x\n\n", value); - - value = cx_read(PLL_B_POST_STAT_BIST); - CX25821_INFO(" PLL_B_POST_STAT_BIST = 0x%x\n\n", value); - value = cx_read(PLL_B_INT_FRAC); - CX25821_INFO(" PLL_B_INT_FRAC = 0x%x\n\n", value); - - value = cx_read(PLL_C_POST_STAT_BIST); - CX25821_INFO(" PLL_C_POST_STAT_BIST = 0x%x\n\n", value); - value = cx_read(PLL_C_INT_FRAC); - CX25821_INFO(" PLL_C_INT_FRAC = 0x%x\n\n", value); - - value = cx_read(PLL_D_POST_STAT_BIST); - CX25821_INFO(" PLL_D_POST_STAT_BIST = 0x%x\n\n", value); - value = cx_read(PLL_D_INT_FRAC); - CX25821_INFO(" PLL_D_INT_FRAC = 0x%x\n\n", value); - - value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp); - CX25821_INFO(" AFE_AB_DIAG_CTRL (0x10900090) = 0x%x\n\n", value); -} -EXPORT_SYMBOL(cx25821_sram_channel_dump_audio); - -static void cx25821_shutdown(struct cx25821_dev *dev) -{ - int i; - - /* disable RISC controller */ - cx_write(DEV_CNTRL2, 0); - - /* Disable Video A/B activity */ - for (i = 0; i < VID_CHANNEL_NUM; i++) { - cx_write(dev->channels[i].sram_channels->dma_ctl, 0); - cx_write(dev->channels[i].sram_channels->int_msk, 0); - } - - for (i = VID_UPSTREAM_SRAM_CHANNEL_I; - i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) { - cx_write(dev->channels[i].sram_channels->dma_ctl, 0); - cx_write(dev->channels[i].sram_channels->int_msk, 0); - } - - /* Disable Audio activity */ - cx_write(AUD_INT_DMA_CTL, 0); - - /* Disable Serial port */ - cx_write(UART_CTL, 0); - - /* Disable Interrupts */ - cx_write(PCI_INT_MSK, 0); - cx_write(AUD_A_INT_MSK, 0); -} - -void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select, - u32 format) -{ - if (channel_select <= 7 && channel_select >= 0) { - cx_write(dev->channels[channel_select]. - sram_channels->pix_frmt, format); - dev->channels[channel_select].pixel_formats = format; - } -} - -static void cx25821_set_vip_mode(struct cx25821_dev *dev, - struct sram_channel *ch) -{ - cx_write(ch->pix_frmt, PIXEL_FRMT_422); - cx_write(ch->vip_ctl, PIXEL_ENGINE_VIP1); -} - -static void cx25821_initialize(struct cx25821_dev *dev) -{ - int i; - - dprintk(1, "%s()\n", __func__); - - cx25821_shutdown(dev); - cx_write(PCI_INT_STAT, 0xffffffff); - - for (i = 0; i < VID_CHANNEL_NUM; i++) - cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); - - cx_write(AUD_A_INT_STAT, 0xffffffff); - cx_write(AUD_B_INT_STAT, 0xffffffff); - cx_write(AUD_C_INT_STAT, 0xffffffff); - cx_write(AUD_D_INT_STAT, 0xffffffff); - cx_write(AUD_E_INT_STAT, 0xffffffff); - - cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); - cx_write(PAD_CTRL, 0x12); /* for I2C */ - cx25821_registers_init(dev); /* init Pecos registers */ - mdelay(100); - - for (i = 0; i < VID_CHANNEL_NUM; i++) { - cx25821_set_vip_mode(dev, dev->channels[i].sram_channels); - cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels, - 1440, 0); - dev->channels[i].pixel_formats = PIXEL_FRMT_422; - dev->channels[i].use_cif_resolution = FALSE; - } - - /* Probably only affect Downstream */ - for (i = VID_UPSTREAM_SRAM_CHANNEL_I; - i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) { - cx25821_set_vip_mode(dev, dev->channels[i].sram_channels); - } - - cx25821_sram_channel_setup_audio(dev, - dev->channels[SRAM_CH08].sram_channels, - 128, 0); - - cx25821_gpio_init(dev); -} - -static int cx25821_get_resources(struct cx25821_dev *dev) -{ - if (request_mem_region - (pci_resource_start(dev->pci, 0), pci_resource_len(dev->pci, 0), - dev->name)) - return 0; - - pr_err("%s: can't get MMIO memory @ 0x%llx\n", - dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); - - return -EBUSY; -} - -static void cx25821_dev_checkrevision(struct cx25821_dev *dev) -{ - dev->hwrevision = cx_read(RDR_CFG2) & 0xff; - - pr_info("%s(): Hardware revision = 0x%02x\n", - __func__, dev->hwrevision); -} - -static void cx25821_iounmap(struct cx25821_dev *dev) -{ - if (dev == NULL) - return; - - /* Releasing IO memory */ - if (dev->lmmio != NULL) { - CX25821_INFO("Releasing lmmio.\n"); - iounmap(dev->lmmio); - dev->lmmio = NULL; - } -} - -static int cx25821_dev_setup(struct cx25821_dev *dev) -{ - int io_size = 0, i; - - pr_info("\n***********************************\n"); - pr_info("cx25821 set up\n"); - pr_info("***********************************\n\n"); - - mutex_init(&dev->lock); - - atomic_inc(&dev->refcount); - - dev->nr = ++cx25821_devcount; - sprintf(dev->name, "cx25821[%d]", dev->nr); - - mutex_lock(&cx25821_devlist_mutex); - list_add_tail(&dev->devlist, &cx25821_devlist); - mutex_unlock(&cx25821_devlist_mutex); - - strcpy(cx25821_boards[UNKNOWN_BOARD].name, "unknown"); - strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821"); - - if (dev->pci->device != 0x8210) { - pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", - __func__, dev->pci->device); - return -1; - } else { - pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device); - } - - /* Apply a sensible clock frequency for the PCIe bridge */ - dev->clk_freq = 28000000; - for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) - dev->channels[i].sram_channels = &cx25821_sram_channels[i]; - - if (dev->nr > 1) - CX25821_INFO("dev->nr > 1!"); - - /* board config */ - dev->board = 1; /* card[dev->nr]; */ - dev->_max_num_decoders = MAX_DECODERS; - - dev->pci_bus = dev->pci->bus->number; - dev->pci_slot = PCI_SLOT(dev->pci->devfn); - dev->pci_irqmask = 0x001f00; - - /* External Master 1 Bus */ - dev->i2c_bus[0].nr = 0; - dev->i2c_bus[0].dev = dev; - dev->i2c_bus[0].reg_stat = I2C1_STAT; - dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; - dev->i2c_bus[0].reg_addr = I2C1_ADDR; - dev->i2c_bus[0].reg_rdata = I2C1_RDATA; - dev->i2c_bus[0].reg_wdata = I2C1_WDATA; - dev->i2c_bus[0].i2c_period = (0x07 << 24); /* 1.95MHz */ - - if (cx25821_get_resources(dev) < 0) { - pr_err("%s: No more PCIe resources for subsystem: %04x:%04x\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device); - - cx25821_devcount--; - return -EBUSY; - } - - /* PCIe stuff */ - dev->base_io_addr = pci_resource_start(dev->pci, 0); - io_size = pci_resource_len(dev->pci, 0); - - if (!dev->base_io_addr) { - CX25821_ERR("No PCI Memory resources, exiting!\n"); - return -ENODEV; - } - - dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0)); - - if (!dev->lmmio) { - CX25821_ERR - ("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n"); - cx25821_iounmap(dev); - return -ENOMEM; - } - - dev->bmmio = (u8 __iomem *) dev->lmmio; - - pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, cx25821_boards[dev->board].name, - dev->board, card[dev->nr] == dev->board ? - "insmod option" : "autodetected"); - - /* init hardware */ - cx25821_initialize(dev); - - cx25821_i2c_register(&dev->i2c_bus[0]); -/* cx25821_i2c_register(&dev->i2c_bus[1]); - * cx25821_i2c_register(&dev->i2c_bus[2]); */ - - CX25821_INFO("i2c register! bus->i2c_rc = %d\n", - dev->i2c_bus[0].i2c_rc); - - cx25821_card_setup(dev); - - if (medusa_video_init(dev) < 0) - CX25821_ERR("%s(): Failed to initialize medusa!\n", __func__); - - cx25821_video_register(dev); - - /* register IOCTL device */ - dev->ioctl_dev = - cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template, - "video"); - - if (video_register_device - (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) { - cx25821_videoioctl_unregister(dev); - pr_err("%s(): Failed to register video adapter for IOCTL, so unregistering videoioctl device\n", - __func__); - } - - cx25821_dev_checkrevision(dev); - CX25821_INFO("setup done!\n"); - - return 0; -} - -void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev, - struct upstream_user_struct *up_data) -{ - dev->_isNTSC = !strcmp(dev->vid_stdname, "NTSC") ? 1 : 0; - - dev->tvnorm = !dev->_isNTSC ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M; - medusa_set_videostandard(dev); - - cx25821_vidupstream_init_ch1(dev, dev->channel_select, - dev->pixel_format); -} - -void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev, - struct upstream_user_struct *up_data) -{ - dev->_isNTSC_ch2 = !strcmp(dev->vid_stdname_ch2, "NTSC") ? 1 : 0; - - dev->tvnorm = !dev->_isNTSC_ch2 ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M; - medusa_set_videostandard(dev); - - cx25821_vidupstream_init_ch2(dev, dev->channel_select_ch2, - dev->pixel_format_ch2); -} - -void cx25821_start_upstream_audio(struct cx25821_dev *dev, - struct upstream_user_struct *up_data) -{ - cx25821_audio_upstream_init(dev, AUDIO_UPSTREAM_SRAM_CHANNEL_B); -} - -void cx25821_dev_unregister(struct cx25821_dev *dev) -{ - int i; - - if (!dev->base_io_addr) - return; - - cx25821_free_mem_upstream_ch1(dev); - cx25821_free_mem_upstream_ch2(dev); - cx25821_free_mem_upstream_audio(dev); - - release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0)); - - if (!atomic_dec_and_test(&dev->refcount)) - return; - - for (i = 0; i < VID_CHANNEL_NUM; i++) - cx25821_video_unregister(dev, i); - - for (i = VID_UPSTREAM_SRAM_CHANNEL_I; - i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) { - cx25821_video_unregister(dev, i); - } - - cx25821_videoioctl_unregister(dev); - - cx25821_i2c_unregister(&dev->i2c_bus[0]); - cx25821_iounmap(dev); -} -EXPORT_SYMBOL(cx25821_dev_unregister); - -static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, - unsigned int offset, u32 sync_line, - unsigned int bpl, unsigned int padding, - unsigned int lines) -{ - struct scatterlist *sg; - unsigned int line, todo; - - /* sync instruction */ - if (sync_line != NO_SYNC_LINE) - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - /* scan lines */ - sg = sglist; - for (line = 0; line < lines; line++) { - while (offset && offset >= sg_dma_len(sg)) { - offset -= sg_dma_len(sg); - sg++; - } - if (bpl <= sg_dma_len(sg) - offset) { - /* fits into current chunk */ - *(rp++) = - cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - offset += bpl; - } else { - /* scanline needs to be split */ - todo = bpl; - *(rp++) = - cpu_to_le32(RISC_WRITE | RISC_SOL | - (sg_dma_len(sg) - offset)); - *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - todo -= (sg_dma_len(sg) - offset); - offset = 0; - sg++; - while (todo > sg_dma_len(sg)) { - *(rp++) = - cpu_to_le32(RISC_WRITE | sg_dma_len(sg)); - *(rp++) = cpu_to_le32(sg_dma_address(sg)); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - todo -= sg_dma_len(sg); - sg++; - } - *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo); - *(rp++) = cpu_to_le32(sg_dma_address(sg)); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - offset += todo; - } - - offset += padding; - } - - return rp; -} - -int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int top_offset, - unsigned int bottom_offset, unsigned int bpl, - unsigned int padding, unsigned int lines) -{ - u32 instructions; - u32 fields; - __le32 *rp; - int rc; - - fields = 0; - if (UNSET != top_offset) - fields++; - if (UNSET != bottom_offset) - fields++; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Padding - can cause next bpl to start close to a page border. First DMA - region may be smaller than PAGE_SIZE */ - /* write and jump need and extra dword */ - instructions = - fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; - rc = btcx_riscmem_alloc(pci, risc, instructions * 12); - - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - - if (UNSET != top_offset) { - rp = cx25821_risc_field(rp, sglist, top_offset, 0, bpl, padding, - lines); - } - - if (UNSET != bottom_offset) { - rp = cx25821_risc_field(rp, sglist, bottom_offset, 0x200, bpl, - padding, lines); - } - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - - return 0; -} - -static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, - unsigned int offset, u32 sync_line, - unsigned int bpl, unsigned int padding, - unsigned int lines, unsigned int lpi) -{ - struct scatterlist *sg; - unsigned int line, todo, sol; - - /* sync instruction */ - if (sync_line != NO_SYNC_LINE) - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - /* scan lines */ - sg = sglist; - for (line = 0; line < lines; line++) { - while (offset && offset >= sg_dma_len(sg)) { - offset -= sg_dma_len(sg); - sg++; - } - - if (lpi && line > 0 && !(line % lpi)) - sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; - else - sol = RISC_SOL; - - if (bpl <= sg_dma_len(sg) - offset) { - /* fits into current chunk */ - *(rp++) = - cpu_to_le32(RISC_WRITE | sol | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - offset += bpl; - } else { - /* scanline needs to be split */ - todo = bpl; - *(rp++) = cpu_to_le32(RISC_WRITE | sol | - (sg_dma_len(sg) - offset)); - *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - todo -= (sg_dma_len(sg) - offset); - offset = 0; - sg++; - while (todo > sg_dma_len(sg)) { - *(rp++) = cpu_to_le32(RISC_WRITE | - sg_dma_len(sg)); - *(rp++) = cpu_to_le32(sg_dma_address(sg)); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - todo -= sg_dma_len(sg); - sg++; - } - *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo); - *(rp++) = cpu_to_le32(sg_dma_address(sg)); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - offset += todo; - } - offset += padding; - } - - return rp; -} - -int cx25821_risc_databuffer_audio(struct pci_dev *pci, - struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int bpl, - unsigned int lines, unsigned int lpi) -{ - u32 instructions; - __le32 *rp; - int rc; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Here - there is no padding and no sync. First DMA region may be smaller - than PAGE_SIZE */ - /* Jump and write need an extra dword */ - instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; - instructions += 1; - - rc = btcx_riscmem_alloc(pci, risc, instructions * 12); - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - rp = cx25821_risc_field_audio(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, - lines, lpi); - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - return 0; -} -EXPORT_SYMBOL(cx25821_risc_databuffer_audio); - -int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) -{ - __le32 *rp; - int rc; - - rc = btcx_riscmem_alloc(pci, risc, 4 * 16); - - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - - *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ1); - *(rp++) = cpu_to_le32(reg); - *(rp++) = cpu_to_le32(value); - *(rp++) = cpu_to_le32(mask); - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - return 0; -} - -void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - - BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static irqreturn_t cx25821_irq(int irq, void *dev_id) -{ - struct cx25821_dev *dev = dev_id; - u32 pci_status, pci_mask; - u32 vid_status; - int i, handled = 0; - u32 mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; - - pci_status = cx_read(PCI_INT_STAT); - pci_mask = cx_read(PCI_INT_MSK); - - if (pci_status == 0) - goto out; - - for (i = 0; i < VID_CHANNEL_NUM; i++) { - if (pci_status & mask[i]) { - vid_status = cx_read(dev->channels[i]. - sram_channels->int_stat); - - if (vid_status) - handled += - cx25821_video_irq(dev, i, vid_status); - - cx_write(PCI_INT_STAT, mask[i]); - } - } - -out: - return IRQ_RETVAL(handled); -} - -void cx25821_print_irqbits(char *name, char *tag, char **strings, - int len, u32 bits, u32 mask) -{ - unsigned int i; - - printk(KERN_DEBUG pr_fmt("%s: %s [0x%x]"), name, tag, bits); - - for (i = 0; i < len; i++) { - if (!(bits & (1 << i))) - continue; - if (strings[i]) - pr_cont(" %s", strings[i]); - else - pr_cont(" %d", i); - if (!(mask & (1 << i))) - continue; - pr_cont("*"); - } - pr_cont("\n"); -} -EXPORT_SYMBOL(cx25821_print_irqbits); - -struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci) -{ - struct cx25821_dev *dev = pci_get_drvdata(pci); - return dev; -} -EXPORT_SYMBOL(cx25821_dev_get); - -static int __devinit cx25821_initdev(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - struct cx25821_dev *dev; - int err = 0; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (NULL == dev) - return -ENOMEM; - - err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); - if (err < 0) - goto fail_free; - - /* pci init */ - dev->pci = pci_dev; - if (pci_enable_device(pci_dev)) { - err = -EIO; - - pr_info("pci enable failed!\n"); - - goto fail_unregister_device; - } - - pr_info("Athena pci enable !\n"); - - err = cx25821_dev_setup(dev); - if (err) { - if (err == -EBUSY) - goto fail_unregister_device; - else - goto fail_unregister_pci; - } - - /* print pci info */ - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - pr_info("%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", - dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, - dev->pci_lat, (unsigned long long)dev->base_io_addr); - - pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev, 0xffffffff)) { - pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); - err = -EIO; - goto fail_irq; - } - - err = - request_irq(pci_dev->irq, cx25821_irq, IRQF_SHARED | IRQF_DISABLED, - dev->name, dev); - - if (err < 0) { - pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); - goto fail_irq; - } - - return 0; - -fail_irq: - pr_info("cx25821_initdev() can't get IRQ !\n"); - cx25821_dev_unregister(dev); - -fail_unregister_pci: - pci_disable_device(pci_dev); -fail_unregister_device: - v4l2_device_unregister(&dev->v4l2_dev); - -fail_free: - kfree(dev); - return err; -} - -static void __devexit cx25821_finidev(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct cx25821_dev *dev = get_cx25821(v4l2_dev); - - cx25821_shutdown(dev); - pci_disable_device(pci_dev); - - /* unregister stuff */ - if (pci_dev->irq) - free_irq(pci_dev->irq, dev); - - mutex_lock(&cx25821_devlist_mutex); - list_del(&dev->devlist); - mutex_unlock(&cx25821_devlist_mutex); - - cx25821_dev_unregister(dev); - v4l2_device_unregister(v4l2_dev); - kfree(dev); -} - -static struct pci_device_id cx25821_pci_tbl[] = { - { - /* CX25821 Athena */ - .vendor = 0x14f1, - .device = 0x8210, - .subvendor = 0x14f1, - .subdevice = 0x0920, - }, - { - /* --- end of list --- */ - } -}; - -MODULE_DEVICE_TABLE(pci, cx25821_pci_tbl); - -static struct pci_driver cx25821_pci_driver = { - .name = "cx25821", - .id_table = cx25821_pci_tbl, - .probe = cx25821_initdev, - .remove = __devexit_p(cx25821_finidev), - /* TODO */ - .suspend = NULL, - .resume = NULL, -}; - -static int __init cx25821_init(void) -{ - pr_info("driver version %d.%d.%d loaded\n", - (CX25821_VERSION_CODE >> 16) & 0xff, - (CX25821_VERSION_CODE >> 8) & 0xff, - CX25821_VERSION_CODE & 0xff); - return pci_register_driver(&cx25821_pci_driver); -} - -static void __exit cx25821_fini(void) -{ - pci_unregister_driver(&cx25821_pci_driver); -} - -EXPORT_SYMBOL(cx25821_set_gpiopin_direction); - -module_init(cx25821_init); -module_exit(cx25821_fini); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-gpio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-gpio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-gpio.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-gpio.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx25821.h" - -/********************* GPIO stuffs *********************/ -void cx25821_set_gpiopin_direction(struct cx25821_dev *dev, - int pin_number, int pin_logic_value) -{ - int bit = pin_number; - u32 gpio_oe_reg = GPIO_LO_OE; - u32 gpio_register = 0; - u32 value = 0; - - /* Check for valid pinNumber */ - if (pin_number >= 47) - return; - - if (pin_number > 31) { - bit = pin_number - 31; - gpio_oe_reg = GPIO_HI_OE; - } - /* Here we will make sure that the GPIOs 0 and 1 are output. keep the - * rest as is */ - gpio_register = cx_read(gpio_oe_reg); - - if (pin_logic_value == 1) - value = gpio_register | Set_GPIO_Bit(bit); - else - value = gpio_register & Clear_GPIO_Bit(bit); - - cx_write(gpio_oe_reg, value); -} - -static void cx25821_set_gpiopin_logicvalue(struct cx25821_dev *dev, - int pin_number, int pin_logic_value) -{ - int bit = pin_number; - u32 gpio_reg = GPIO_LO; - u32 value = 0; - - /* Check for valid pinNumber */ - if (pin_number >= 47) - return; - - /* change to output direction */ - cx25821_set_gpiopin_direction(dev, pin_number, 0); - - if (pin_number > 31) { - bit = pin_number - 31; - gpio_reg = GPIO_HI; - } - - value = cx_read(gpio_reg); - - if (pin_logic_value == 0) - value &= Clear_GPIO_Bit(bit); - else - value |= Set_GPIO_Bit(bit); - - cx_write(gpio_reg, value); -} - -void cx25821_gpio_init(struct cx25821_dev *dev) -{ - if (dev == NULL) - return; - - switch (dev->board) { - case CX25821_BOARD_CONEXANT_ATHENA10: - default: - /* set GPIO 5 to select the path for Medusa/Athena */ - cx25821_set_gpiopin_logicvalue(dev, 5, 1); - mdelay(20); - break; - } - -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-gpio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-gpio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-gpio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-gpio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ - -void cx25821_gpio_init(struct athena_dev *dev); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,614 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * Based on Steven Toth cx23885 driver - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef CX25821_H_ -#define CX25821_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "btcx-risc.h" -#include "cx25821-reg.h" -#include "cx25821-medusa-reg.h" -#include "cx25821-sram.h" -#include "cx25821-audio.h" -#include "media/cx2341x.h" - -#include -#include - -#define CX25821_VERSION_CODE KERNEL_VERSION(0, 0, 106) - -#define UNSET (-1U) -#define NO_SYNC_LINE (-1U) - -#define CX25821_MAXBOARDS 2 - -#define TRUE 1 -#define FALSE 0 -#define LINE_SIZE_D1 1440 - -/* Number of decoders and encoders */ -#define MAX_DECODERS 8 -#define MAX_ENCODERS 2 -#define QUAD_DECODERS 4 -#define MAX_CAMERAS 16 - -/* Max number of inputs by card */ -#define MAX_CX25821_INPUT 8 -#define INPUT(nr) (&cx25821_boards[dev->board].input[nr]) -#define RESOURCE_VIDEO0 1 -#define RESOURCE_VIDEO1 2 -#define RESOURCE_VIDEO2 4 -#define RESOURCE_VIDEO3 8 -#define RESOURCE_VIDEO4 16 -#define RESOURCE_VIDEO5 32 -#define RESOURCE_VIDEO6 64 -#define RESOURCE_VIDEO7 128 -#define RESOURCE_VIDEO8 256 -#define RESOURCE_VIDEO9 512 -#define RESOURCE_VIDEO10 1024 -#define RESOURCE_VIDEO11 2048 -#define RESOURCE_VIDEO_IOCTL 4096 - -#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ - -#define UNKNOWN_BOARD 0 -#define CX25821_BOARD 1 - -/* Currently supported by the driver */ -#define CX25821_NORMS (\ - V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR | \ - V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ - V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_H | \ - V4L2_STD_PAL_Nc) - -#define CX25821_BOARD_CONEXANT_ATHENA10 1 -#define MAX_VID_CHANNEL_NUM 12 -#define VID_CHANNEL_NUM 8 - -struct cx25821_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int flags; - u32 cxformat; -}; - -struct cx25821_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 mask; - u32 shift; -}; - -struct cx25821_tvnorm { - char *name; - v4l2_std_id id; - u32 cxiformat; - u32 cxoformat; -}; - -struct cx25821_fh { - struct cx25821_dev *dev; - enum v4l2_buf_type type; - int radio; - u32 resources; - - enum v4l2_priority prio; - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - - /* video capture */ - struct cx25821_fmt *fmt; - unsigned int width, height; - int channel_id; - - /* vbi capture */ - struct videobuf_queue vidq; - struct videobuf_queue vbiq; - - /* H264 Encoder specifics ONLY */ - struct videobuf_queue mpegq; - atomic_t v4l_reading; -}; - -enum cx25821_itype { - CX25821_VMUX_COMPOSITE = 1, - CX25821_VMUX_SVIDEO, - CX25821_VMUX_DEBUG, - CX25821_RADIO, -}; - -enum cx25821_src_sel_type { - CX25821_SRC_SEL_EXT_656_VIDEO = 0, - CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO -}; - -/* buffer for one video frame */ -struct cx25821_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* cx25821 specific */ - unsigned int bpl; - struct btcx_riscmem risc; - struct cx25821_fmt *fmt; - u32 count; -}; - -struct cx25821_input { - enum cx25821_itype type; - unsigned int vmux; - u32 gpio0, gpio1, gpio2, gpio3; -}; - -typedef enum { - CX25821_UNDEFINED = 0, - CX25821_RAW, - CX25821_264 -} port_t; - -struct cx25821_board { - char *name; - port_t porta, portb, portc; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - - u32 clk_freq; - struct cx25821_input input[2]; -}; - -struct cx25821_subid { - u16 subvendor; - u16 subdevice; - u32 card; -}; - -struct cx25821_i2c { - struct cx25821_dev *dev; - - int nr; - - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - u32 i2c_rc; - - /* cx25821 registers used for raw addess */ - u32 i2c_period; - u32 reg_ctrl; - u32 reg_stat; - u32 reg_addr; - u32 reg_rdata; - u32 reg_wdata; -}; - -struct cx25821_dmaqueue { - struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; - u32 count; -}; - -struct cx25821_data { - struct cx25821_dev *dev; - struct sram_channel *channel; -}; - -struct cx25821_channel { - struct v4l2_prio_state prio; - - int ctl_bright; - int ctl_contrast; - int ctl_hue; - int ctl_saturation; - struct cx25821_data timeout_data; - - struct video_device *video_dev; - struct cx25821_dmaqueue vidq; - - struct sram_channel *sram_channels; - - struct mutex lock; - int resources; - - int pixel_formats; - int use_cif_resolution; - int cif_width; -}; - -struct cx25821_dev { - struct list_head devlist; - atomic_t refcount; - struct v4l2_device v4l2_dev; - - /* pci stuff */ - struct pci_dev *pci; - unsigned char pci_rev, pci_lat; - int pci_bus, pci_slot; - u32 base_io_addr; - u32 __iomem *lmmio; - u8 __iomem *bmmio; - int pci_irqmask; - int hwrevision; - - u32 clk_freq; - - /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ - struct cx25821_i2c i2c_bus[3]; - - int nr; - struct mutex lock; - - struct cx25821_channel channels[MAX_VID_CHANNEL_NUM]; - - /* board details */ - unsigned int board; - char name[32]; - - /* Analog video */ - u32 resources; - unsigned int input; - u32 tvaudio; - v4l2_std_id tvnorm; - unsigned int tuner_type; - unsigned char tuner_addr; - unsigned int radio_type; - unsigned char radio_addr; - unsigned int has_radio; - unsigned int videc_type; - unsigned char videc_addr; - unsigned short _max_num_decoders; - - /* Analog Audio Upstream */ - int _audio_is_running; - int _audiopixel_format; - int _is_first_audio_frame; - int _audiofile_status; - int _audio_lines_count; - int _audioframe_count; - int _audio_upstream_channel_select; - int _last_index_irq; /* The last interrupt index processed. */ - - __le32 *_risc_audio_jmp_addr; - __le32 *_risc_virt_start_addr; - __le32 *_risc_virt_addr; - dma_addr_t _risc_phys_addr; - dma_addr_t _risc_phys_start_addr; - - unsigned int _audiorisc_size; - unsigned int _audiodata_buf_size; - __le32 *_audiodata_buf_virt_addr; - dma_addr_t _audiodata_buf_phys_addr; - char *_audiofilename; - - /* V4l */ - u32 freq; - struct video_device *vbi_dev; - struct video_device *radio_dev; - struct video_device *ioctl_dev; - - spinlock_t slock; - - /* Video Upstream */ - int _line_size; - int _prog_cnt; - int _pixel_format; - int _is_first_frame; - int _is_running; - int _file_status; - int _lines_count; - int _frame_count; - int _channel_upstream_select; - unsigned int _risc_size; - - __le32 *_dma_virt_start_addr; - __le32 *_dma_virt_addr; - dma_addr_t _dma_phys_addr; - dma_addr_t _dma_phys_start_addr; - - unsigned int _data_buf_size; - __le32 *_data_buf_virt_addr; - dma_addr_t _data_buf_phys_addr; - char *_filename; - char *_defaultname; - - int _line_size_ch2; - int _prog_cnt_ch2; - int _pixel_format_ch2; - int _is_first_frame_ch2; - int _is_running_ch2; - int _file_status_ch2; - int _lines_count_ch2; - int _frame_count_ch2; - int _channel2_upstream_select; - unsigned int _risc_size_ch2; - - __le32 *_dma_virt_start_addr_ch2; - __le32 *_dma_virt_addr_ch2; - dma_addr_t _dma_phys_addr_ch2; - dma_addr_t _dma_phys_start_addr_ch2; - - unsigned int _data_buf_size_ch2; - __le32 *_data_buf_virt_addr_ch2; - dma_addr_t _data_buf_phys_addr_ch2; - char *_filename_ch2; - char *_defaultname_ch2; - - /* MPEG Encoder ONLY settings */ - u32 cx23417_mailbox; - struct cx2341x_mpeg_params mpeg_params; - struct video_device *v4l_device; - atomic_t v4l_reader_count; - struct cx25821_tvnorm encodernorm; - - u32 upstream_riscbuf_size; - u32 upstream_databuf_size; - u32 upstream_riscbuf_size_ch2; - u32 upstream_databuf_size_ch2; - u32 audio_upstream_riscbuf_size; - u32 audio_upstream_databuf_size; - int _isNTSC; - int _frame_index; - int _audioframe_index; - struct workqueue_struct *_irq_queues; - struct work_struct _irq_work_entry; - struct workqueue_struct *_irq_queues_ch2; - struct work_struct _irq_work_entry_ch2; - struct workqueue_struct *_irq_audio_queues; - struct work_struct _audio_work_entry; - char *input_filename; - char *input_filename_ch2; - int _frame_index_ch2; - int _isNTSC_ch2; - char *vid_stdname_ch2; - int pixel_format_ch2; - int channel_select_ch2; - int command_ch2; - char *input_audiofilename; - char *vid_stdname; - int pixel_format; - int channel_select; - int command; - int channel_opened; -}; - -struct upstream_user_struct { - char *input_filename; - char *vid_stdname; - int pixel_format; - int channel_select; - int command; -}; - -struct downstream_user_struct { - char *vid_stdname; - int pixel_format; - int cif_resolution_enable; - int cif_width; - int decoder_select; - int command; - int reg_address; - int reg_data; -}; - -extern struct upstream_user_struct *up_data; - -static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct cx25821_dev, v4l2_dev); -} - -#define cx25821_call_all(dev, o, f, args...) \ - v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) - -extern struct list_head cx25821_devlist; -extern struct mutex cx25821_devlist_mutex; - -extern struct cx25821_board cx25821_boards[]; -extern struct cx25821_subid cx25821_subids[]; - -#define SRAM_CH00 0 /* Video A */ -#define SRAM_CH01 1 /* Video B */ -#define SRAM_CH02 2 /* Video C */ -#define SRAM_CH03 3 /* Video D */ -#define SRAM_CH04 4 /* Video E */ -#define SRAM_CH05 5 /* Video F */ -#define SRAM_CH06 6 /* Video G */ -#define SRAM_CH07 7 /* Video H */ - -#define SRAM_CH08 8 /* Audio A */ -#define SRAM_CH09 9 /* Video Upstream I */ -#define SRAM_CH10 10 /* Video Upstream J */ -#define SRAM_CH11 11 /* Audio Upstream AUD_CHANNEL_B */ - -#define VID_UPSTREAM_SRAM_CHANNEL_I SRAM_CH09 -#define VID_UPSTREAM_SRAM_CHANNEL_J SRAM_CH10 -#define AUDIO_UPSTREAM_SRAM_CHANNEL_B SRAM_CH11 -#define VIDEO_IOCTL_CH 11 - -struct sram_channel { - char *name; - u32 i; - u32 cmds_start; - u32 ctrl_start; - u32 cdt; - u32 fifo_start; - u32 fifo_size; - u32 ptr1_reg; - u32 ptr2_reg; - u32 cnt1_reg; - u32 cnt2_reg; - u32 int_msk; - u32 int_stat; - u32 int_mstat; - u32 dma_ctl; - u32 gpcnt_ctl; - u32 gpcnt; - u32 aud_length; - u32 aud_cfg; - u32 fld_aud_fifo_en; - u32 fld_aud_risc_en; - - /* For Upstream Video */ - u32 vid_fmt_ctl; - u32 vid_active_ctl1; - u32 vid_active_ctl2; - u32 vid_cdt_size; - - u32 vip_ctl; - u32 pix_frmt; - u32 jumponly; - u32 irq_bit; -}; -extern struct sram_channel cx25821_sram_channels[]; - -#define STATUS_SUCCESS 0 -#define STATUS_UNSUCCESSFUL -1 - -#define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) -#define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) - -#define cx_andor(reg, mask, value) \ - writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ - ((value) & (mask)), dev->lmmio+((reg)>>2)) - -#define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) -#define cx_clear(reg, bit) cx_andor((reg), (bit), 0) - -#define Set_GPIO_Bit(Bit) (1 << Bit) -#define Clear_GPIO_Bit(Bit) (~(1 << Bit)) - -#define CX25821_ERR(fmt, args...) \ - pr_err("(%d): " fmt, dev->board, ##args) -#define CX25821_WARN(fmt, args...) \ - pr_warn("(%d): " fmt, dev->board, ##args) -#define CX25821_INFO(fmt, args...) \ - pr_info("(%d): " fmt, dev->board, ##args) - -extern int cx25821_i2c_register(struct cx25821_i2c *bus); -extern void cx25821_card_setup(struct cx25821_dev *dev); -extern int cx25821_ir_init(struct cx25821_dev *dev); -extern int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value); -extern int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value); -extern int cx25821_i2c_unregister(struct cx25821_i2c *bus); -extern void cx25821_gpio_init(struct cx25821_dev *dev); -extern void cx25821_set_gpiopin_direction(struct cx25821_dev *dev, - int pin_number, int pin_logic_value); - -extern int medusa_video_init(struct cx25821_dev *dev); -extern int medusa_set_videostandard(struct cx25821_dev *dev); -extern void medusa_set_resolution(struct cx25821_dev *dev, int width, - int decoder_select); -extern int medusa_set_brightness(struct cx25821_dev *dev, int brightness, - int decoder); -extern int medusa_set_contrast(struct cx25821_dev *dev, int contrast, - int decoder); -extern int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder); -extern int medusa_set_saturation(struct cx25821_dev *dev, int saturation, - int decoder); - -extern int cx25821_sram_channel_setup(struct cx25821_dev *dev, - struct sram_channel *ch, unsigned int bpl, - u32 risc); - -extern int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int top_offset, - unsigned int bottom_offset, - unsigned int bpl, - unsigned int padding, unsigned int lines); -extern int cx25821_risc_databuffer_audio(struct pci_dev *pci, - struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int bpl, - unsigned int lines, unsigned int lpi); -extern void cx25821_free_buffer(struct videobuf_queue *q, - struct cx25821_buffer *buf); -extern int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); -extern void cx25821_sram_channel_dump(struct cx25821_dev *dev, - struct sram_channel *ch); -extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, - struct sram_channel *ch); - -extern struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci); -extern void cx25821_print_irqbits(char *name, char *tag, char **strings, - int len, u32 bits, u32 mask); -extern void cx25821_dev_unregister(struct cx25821_dev *dev); -extern int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc); - -extern int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, - int channel_select, int pixel_format); -extern int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, - int channel_select, int pixel_format); -extern int cx25821_audio_upstream_init(struct cx25821_dev *dev, - int channel_select); -extern void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev); -extern void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev); -extern void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev); -extern void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev, - struct upstream_user_struct - *up_data); -extern void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev, - struct upstream_user_struct - *up_data); -extern void cx25821_start_upstream_audio(struct cx25821_dev *dev, - struct upstream_user_struct *up_data); -extern void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev); -extern void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev); -extern void cx25821_stop_upstream_audio(struct cx25821_dev *dev); -extern int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc); -extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel, - u32 format); -extern void cx25821_videoioctl_unregister(struct cx25821_dev *dev); -extern struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, - struct pci_dev *pci, - struct video_device *template, - char *type); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,425 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * Based on Steven Toth cx23885 driver - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "cx25821.h" -#include - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -static unsigned int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); - -#define dprintk(level, fmt, arg...) \ -do { \ - if (i2c_debug >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \ -} while (0) - -#define I2C_WAIT_DELAY 32 -#define I2C_WAIT_RETRY 64 - -#define I2C_EXTEND (1 << 3) -#define I2C_NOSTOP (1 << 4) - -static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) -{ - struct cx25821_i2c *bus = i2c_adap->algo_data; - struct cx25821_dev *dev = bus->dev; - return cx_read(bus->reg_stat) & 0x01; -} - -static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) -{ - struct cx25821_i2c *bus = i2c_adap->algo_data; - struct cx25821_dev *dev = bus->dev; - return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; -} - -static int i2c_wait_done(struct i2c_adapter *i2c_adap) -{ - int count; - - for (count = 0; count < I2C_WAIT_RETRY; count++) { - if (!i2c_is_busy(i2c_adap)) - break; - udelay(I2C_WAIT_DELAY); - } - - if (I2C_WAIT_RETRY == count) - return 0; - - return 1; -} - -static int i2c_sendbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int joined_rlen) -{ - struct cx25821_i2c *bus = i2c_adap->algo_data; - struct cx25821_dev *dev = bus->dev; - u32 wdata, addr, ctrl; - int retval, cnt; - - if (joined_rlen) - dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__, - msg->len, joined_rlen); - else - dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len); - - /* Deal with i2c probe functions with zero payload */ - if (msg->len == 0) { - cx_write(bus->reg_addr, msg->addr << 25); - cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); - - if (!i2c_wait_done(i2c_adap)) - return -EIO; - - if (!i2c_slave_did_ack(i2c_adap)) - return -EIO; - - dprintk(1, "%s(): returns 0\n", __func__); - return 0; - } - - /* dev, reg + first byte */ - addr = (msg->addr << 25) | msg->buf[0]; - wdata = msg->buf[0]; - - ctrl = bus->i2c_period | (1 << 12) | (1 << 2); - - if (msg->len > 1) - ctrl |= I2C_NOSTOP | I2C_EXTEND; - else if (joined_rlen) - ctrl |= I2C_NOSTOP; - - cx_write(bus->reg_addr, addr); - cx_write(bus->reg_wdata, wdata); - cx_write(bus->reg_ctrl, ctrl); - - retval = i2c_wait_done(i2c_adap); - if (retval < 0) - goto err; - - if (retval == 0) - goto eio; - - if (i2c_debug) { - if (!(ctrl & I2C_NOSTOP)) - printk(" >\n"); - } - - for (cnt = 1; cnt < msg->len; cnt++) { - /* following bytes */ - wdata = msg->buf[cnt]; - ctrl = bus->i2c_period | (1 << 12) | (1 << 2); - - if (cnt < msg->len - 1) - ctrl |= I2C_NOSTOP | I2C_EXTEND; - else if (joined_rlen) - ctrl |= I2C_NOSTOP; - - cx_write(bus->reg_addr, addr); - cx_write(bus->reg_wdata, wdata); - cx_write(bus->reg_ctrl, ctrl); - - retval = i2c_wait_done(i2c_adap); - if (retval < 0) - goto err; - - if (retval == 0) - goto eio; - - if (i2c_debug) { - dprintk(1, " %02x", msg->buf[cnt]); - if (!(ctrl & I2C_NOSTOP)) - dprintk(1, " >\n"); - } - } - - return msg->len; - -eio: - retval = -EIO; -err: - if (i2c_debug) - pr_err(" ERR: %d\n", retval); - return retval; -} - -static int i2c_readbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int joined) -{ - struct cx25821_i2c *bus = i2c_adap->algo_data; - struct cx25821_dev *dev = bus->dev; - u32 ctrl, cnt; - int retval; - - if (i2c_debug && !joined) - dprintk(1, "6-%s(msg->len=%d)\n", __func__, msg->len); - - /* Deal with i2c probe functions with zero payload */ - if (msg->len == 0) { - cx_write(bus->reg_addr, msg->addr << 25); - cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); - if (!i2c_wait_done(i2c_adap)) - return -EIO; - if (!i2c_slave_did_ack(i2c_adap)) - return -EIO; - - dprintk(1, "%s(): returns 0\n", __func__); - return 0; - } - - if (i2c_debug) { - if (joined) - dprintk(1, " R"); - else - dprintk(1, " addr << 1) + 1); - } - - for (cnt = 0; cnt < msg->len; cnt++) { - - ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; - - if (cnt < msg->len - 1) - ctrl |= I2C_NOSTOP | I2C_EXTEND; - - cx_write(bus->reg_addr, msg->addr << 25); - cx_write(bus->reg_ctrl, ctrl); - - retval = i2c_wait_done(i2c_adap); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; - - if (i2c_debug) { - dprintk(1, " %02x", msg->buf[cnt]); - if (!(ctrl & I2C_NOSTOP)) - dprintk(1, " >\n"); - } - } - - return msg->len; -eio: - retval = -EIO; -err: - if (i2c_debug) - pr_err(" ERR: %d\n", retval); - return retval; -} - -static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) -{ - struct cx25821_i2c *bus = i2c_adap->algo_data; - struct cx25821_dev *dev = bus->dev; - int i, retval = 0; - - dprintk(1, "%s(num = %d)\n", __func__, num); - - for (i = 0; i < num; i++) { - dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n", - __func__, num, msgs[i].addr, msgs[i].len); - - if (msgs[i].flags & I2C_M_RD) { - /* read */ - retval = i2c_readbytes(i2c_adap, &msgs[i], 0); - } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && - msgs[i].addr == msgs[i + 1].addr) { - /* write then read from same address */ - retval = - i2c_sendbytes(i2c_adap, &msgs[i], msgs[i + 1].len); - - if (retval < 0) - goto err; - i++; - retval = i2c_readbytes(i2c_adap, &msgs[i], 1); - } else { - /* write */ - retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); - } - - if (retval < 0) - goto err; - } - return num; - -err: - return retval; -} - - -static u32 cx25821_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL | - I2C_FUNC_I2C | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; -} - -static struct i2c_algorithm cx25821_i2c_algo_template = { - .master_xfer = i2c_xfer, - .functionality = cx25821_functionality, -#ifdef NEED_ALGO_CONTROL - .algo_control = dummy_algo_control, -#endif -}; - -static struct i2c_adapter cx25821_i2c_adap_template = { - .name = "cx25821", - .owner = THIS_MODULE, - .algo = &cx25821_i2c_algo_template, -}; - -static struct i2c_client cx25821_i2c_client_template = { - .name = "cx25821 internal", -}; - -/* init + register i2c algo-bit adapter */ -int cx25821_i2c_register(struct cx25821_i2c *bus) -{ - struct cx25821_dev *dev = bus->dev; - - dprintk(1, "%s(bus = %d)\n", __func__, bus->nr); - - memcpy(&bus->i2c_adap, &cx25821_i2c_adap_template, - sizeof(bus->i2c_adap)); - memcpy(&bus->i2c_algo, &cx25821_i2c_algo_template, - sizeof(bus->i2c_algo)); - memcpy(&bus->i2c_client, &cx25821_i2c_client_template, - sizeof(bus->i2c_client)); - - bus->i2c_adap.dev.parent = &dev->pci->dev; - - strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); - - bus->i2c_algo.data = bus; - bus->i2c_adap.algo_data = bus; - i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); - i2c_add_adapter(&bus->i2c_adap); - - bus->i2c_client.adapter = &bus->i2c_adap; - - /* set up the I2c */ - bus->i2c_client.addr = (0x88 >> 1); - - return bus->i2c_rc; -} - -int cx25821_i2c_unregister(struct cx25821_i2c *bus) -{ - i2c_del_adapter(&bus->i2c_adap); - return 0; -} - -void cx25821_av_clk(struct cx25821_dev *dev, int enable) -{ - /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ - char buffer[3]; - struct i2c_msg msg; - dprintk(1, "%s(enabled = %d)\n", __func__, enable); - - /* Register 0x144 */ - buffer[0] = 0x01; - buffer[1] = 0x44; - if (enable == 1) - buffer[2] = 0x05; - else - buffer[2] = 0x00; - - msg.addr = 0x44; - msg.flags = I2C_M_TEN; - msg.len = 3; - msg.buf = buffer; - - i2c_xfer(&dev->i2c_bus[0].i2c_adap, &msg, 1); -} - -int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value) -{ - struct i2c_client *client = &bus->i2c_client; - int retval = 0; - int v = 0; - u8 addr[2] = { 0, 0 }; - u8 buf[4] = { 0, 0, 0, 0 }; - - struct i2c_msg msgs[2] = { - { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = addr, - }, { - .addr = client->addr, - .flags = I2C_M_RD, - .len = 4, - .buf = buf, - } - }; - - addr[0] = (reg_addr >> 8); - addr[1] = (reg_addr & 0xff); - msgs[0].addr = 0x44; - msgs[1].addr = 0x44; - - retval = i2c_xfer(client->adapter, msgs, 2); - - v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; - *value = v; - - return v; -} - -int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value) -{ - struct i2c_client *client = &bus->i2c_client; - int retval = 0; - u8 buf[6] = { 0, 0, 0, 0, 0, 0 }; - - struct i2c_msg msgs[1] = { - { - .addr = client->addr, - .flags = 0, - .len = 6, - .buf = buf, - } - }; - - buf[0] = reg_addr >> 8; - buf[1] = reg_addr & 0xff; - buf[5] = (value >> 24) & 0xff; - buf[4] = (value >> 16) & 0xff; - buf[3] = (value >> 8) & 0xff; - buf[2] = value & 0xff; - client->flags = 0; - msgs[0].addr = 0x44; - - retval = i2c_xfer(client->adapter, msgs, 1); - - return retval; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-defines.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-defines.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-defines.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-defines.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _MEDUSA_DEF_H_ -#define _MEDUSA_DEF_H_ - -/* Video deocder that we supported */ -#define VDEC_A 0 -#define VDEC_B 1 -#define VDEC_C 2 -#define VDEC_D 3 -#define VDEC_E 4 -#define VDEC_F 5 -#define VDEC_G 6 -#define VDEC_H 7 - -/* end of display sequence */ -#define END_OF_SEQ 0xF; - -/* registry string size */ -#define MAX_REGISTRY_SZ 40; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,455 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __MEDUSA_REGISTERS__ -#define __MEDUSA_REGISTERS__ - -/* Serial Slave Registers */ -#define HOST_REGISTER1 0x0000 -#define HOST_REGISTER2 0x0001 - -/* Chip Configuration Registers */ -#define CHIP_CTRL 0x0100 -#define AFE_AB_CTRL 0x0104 -#define AFE_CD_CTRL 0x0108 -#define AFE_EF_CTRL 0x010C -#define AFE_GH_CTRL 0x0110 -#define DENC_AB_CTRL 0x0114 -#define BYP_AB_CTRL 0x0118 -#define MON_A_CTRL 0x011C -#define DISP_SEQ_A 0x0120 -#define DISP_SEQ_B 0x0124 -#define DISP_AB_CNT 0x0128 -#define DISP_CD_CNT 0x012C -#define DISP_EF_CNT 0x0130 -#define DISP_GH_CNT 0x0134 -#define DISP_IJ_CNT 0x0138 -#define PIN_OE_CTRL 0x013C -#define PIN_SPD_CTRL 0x0140 -#define PIN_SPD_CTRL2 0x0144 -#define IRQ_STAT_CTRL 0x0148 -#define POWER_CTRL_AB 0x014C -#define POWER_CTRL_CD 0x0150 -#define POWER_CTRL_EF 0x0154 -#define POWER_CTRL_GH 0x0158 -#define TUNE_CTRL 0x015C -#define BIAS_CTRL 0x0160 -#define AFE_AB_DIAG_CTRL 0x0164 -#define AFE_CD_DIAG_CTRL 0x0168 -#define AFE_EF_DIAG_CTRL 0x016C -#define AFE_GH_DIAG_CTRL 0x0170 -#define PLL_AB_DIAG_CTRL 0x0174 -#define PLL_CD_DIAG_CTRL 0x0178 -#define PLL_EF_DIAG_CTRL 0x017C -#define PLL_GH_DIAG_CTRL 0x0180 -#define TEST_CTRL 0x0184 -#define BIST_STAT 0x0188 -#define BIST_STAT2 0x018C -#define BIST_VID_PLL_AB_STAT 0x0190 -#define BIST_VID_PLL_CD_STAT 0x0194 -#define BIST_VID_PLL_EF_STAT 0x0198 -#define BIST_VID_PLL_GH_STAT 0x019C -#define DLL_DIAG_CTRL 0x01A0 -#define DEV_CH_ID_CTRL 0x01A4 -#define ABIST_CTRL_STATUS 0x01A8 -#define ABIST_FREQ 0x01AC -#define ABIST_GOERT_SHIFT 0x01B0 -#define ABIST_COEF12 0x01B4 -#define ABIST_COEF34 0x01B8 -#define ABIST_COEF56 0x01BC -#define ABIST_COEF7_SNR 0x01C0 -#define ABIST_ADC_CAL 0x01C4 -#define ABIST_BIN1_VGA0 0x01C8 -#define ABIST_BIN2_VGA1 0x01CC -#define ABIST_BIN3_VGA2 0x01D0 -#define ABIST_BIN4_VGA3 0x01D4 -#define ABIST_BIN5_VGA4 0x01D8 -#define ABIST_BIN6_VGA5 0x01DC -#define ABIST_BIN7_VGA6 0x0x1E0 -#define ABIST_CLAMP_A 0x0x1E4 -#define ABIST_CLAMP_B 0x0x1E8 -#define ABIST_CLAMP_C 0x01EC -#define ABIST_CLAMP_D 0x01F0 -#define ABIST_CLAMP_E 0x01F4 -#define ABIST_CLAMP_F 0x01F8 - -/* Digital Video Encoder A Registers */ -#define DENC_A_REG_1 0x0200 -#define DENC_A_REG_2 0x0204 -#define DENC_A_REG_3 0x0208 -#define DENC_A_REG_4 0x020C -#define DENC_A_REG_5 0x0210 -#define DENC_A_REG_6 0x0214 -#define DENC_A_REG_7 0x0218 -#define DENC_A_REG_8 0x021C - -/* Digital Video Encoder B Registers */ -#define DENC_B_REG_1 0x0300 -#define DENC_B_REG_2 0x0304 -#define DENC_B_REG_3 0x0308 -#define DENC_B_REG_4 0x030C -#define DENC_B_REG_5 0x0310 -#define DENC_B_REG_6 0x0314 -#define DENC_B_REG_7 0x0318 -#define DENC_B_REG_8 0x031C - -/* Video Decoder A Registers */ -#define MODE_CTRL 0x1000 -#define OUT_CTRL1 0x1004 -#define OUT_CTRL_NS 0x1008 -#define GEN_STAT 0x100C -#define INT_STAT_MASK 0x1010 -#define LUMA_CTRL 0x1014 -#define CHROMA_CTRL 0x1018 -#define CRUSH_CTRL 0x101C -#define HORIZ_TIM_CTRL 0x1020 -#define VERT_TIM_CTRL 0x1024 -#define MISC_TIM_CTRL 0x1028 -#define FIELD_COUNT 0x102C -#define HSCALE_CTRL 0x1030 -#define VSCALE_CTRL 0x1034 -#define MAN_VGA_CTRL 0x1038 -#define MAN_AGC_CTRL 0x103C -#define DFE_CTRL1 0x1040 -#define DFE_CTRL2 0x1044 -#define DFE_CTRL3 0x1048 -#define PLL_CTRL 0x104C -#define PLL_CTRL_FAST 0x1050 -#define HTL_CTRL 0x1054 -#define SRC_CFG 0x1058 -#define SC_STEP_SIZE 0x105C -#define SC_CONVERGE_CTRL 0x1060 -#define SC_LOOP_CTRL 0x1064 -#define COMB_2D_HFS_CFG 0x1068 -#define COMB_2D_HFD_CFG 0x106C -#define COMB_2D_LF_CFG 0x1070 -#define COMB_2D_BLEND 0x1074 -#define COMB_MISC_CTRL 0x1078 -#define COMB_FLAT_THRESH_CTRL 0x107C -#define COMB_TEST 0x1080 -#define BP_MISC_CTRL 0x1084 -#define VCR_DET_CTRL 0x1088 -#define NOISE_DET_CTRL 0x108C -#define COMB_FLAT_NOISE_CTRL 0x1090 -#define VERSION 0x11F8 -#define SOFT_RST_CTRL 0x11FC - -/* Video Decoder B Registers */ -#define VDEC_B_MODE_CTRL 0x1200 -#define VDEC_B_OUT_CTRL1 0x1204 -#define VDEC_B_OUT_CTRL_NS 0x1208 -#define VDEC_B_GEN_STAT 0x120C -#define VDEC_B_INT_STAT_MASK 0x1210 -#define VDEC_B_LUMA_CTRL 0x1214 -#define VDEC_B_CHROMA_CTRL 0x1218 -#define VDEC_B_CRUSH_CTRL 0x121C -#define VDEC_B_HORIZ_TIM_CTRL 0x1220 -#define VDEC_B_VERT_TIM_CTRL 0x1224 -#define VDEC_B_MISC_TIM_CTRL 0x1228 -#define VDEC_B_FIELD_COUNT 0x122C -#define VDEC_B_HSCALE_CTRL 0x1230 -#define VDEC_B_VSCALE_CTRL 0x1234 -#define VDEC_B_MAN_VGA_CTRL 0x1238 -#define VDEC_B_MAN_AGC_CTRL 0x123C -#define VDEC_B_DFE_CTRL1 0x1240 -#define VDEC_B_DFE_CTRL2 0x1244 -#define VDEC_B_DFE_CTRL3 0x1248 -#define VDEC_B_PLL_CTRL 0x124C -#define VDEC_B_PLL_CTRL_FAST 0x1250 -#define VDEC_B_HTL_CTRL 0x1254 -#define VDEC_B_SRC_CFG 0x1258 -#define VDEC_B_SC_STEP_SIZE 0x125C -#define VDEC_B_SC_CONVERGE_CTRL 0x1260 -#define VDEC_B_SC_LOOP_CTRL 0x1264 -#define VDEC_B_COMB_2D_HFS_CFG 0x1268 -#define VDEC_B_COMB_2D_HFD_CFG 0x126C -#define VDEC_B_COMB_2D_LF_CFG 0x1270 -#define VDEC_B_COMB_2D_BLEND 0x1274 -#define VDEC_B_COMB_MISC_CTRL 0x1278 -#define VDEC_B_COMB_FLAT_THRESH_CTRL 0x127C -#define VDEC_B_COMB_TEST 0x1280 -#define VDEC_B_BP_MISC_CTRL 0x1284 -#define VDEC_B_VCR_DET_CTRL 0x1288 -#define VDEC_B_NOISE_DET_CTRL 0x128C -#define VDEC_B_COMB_FLAT_NOISE_CTRL 0x1290 -#define VDEC_B_VERSION 0x13F8 -#define VDEC_B_SOFT_RST_CTRL 0x13FC - -/* Video Decoder C Registers */ -#define VDEC_C_MODE_CTRL 0x1400 -#define VDEC_C_OUT_CTRL1 0x1404 -#define VDEC_C_OUT_CTRL_NS 0x1408 -#define VDEC_C_GEN_STAT 0x140C -#define VDEC_C_INT_STAT_MASK 0x1410 -#define VDEC_C_LUMA_CTRL 0x1414 -#define VDEC_C_CHROMA_CTRL 0x1418 -#define VDEC_C_CRUSH_CTRL 0x141C -#define VDEC_C_HORIZ_TIM_CTRL 0x1420 -#define VDEC_C_VERT_TIM_CTRL 0x1424 -#define VDEC_C_MISC_TIM_CTRL 0x1428 -#define VDEC_C_FIELD_COUNT 0x142C -#define VDEC_C_HSCALE_CTRL 0x1430 -#define VDEC_C_VSCALE_CTRL 0x1434 -#define VDEC_C_MAN_VGA_CTRL 0x1438 -#define VDEC_C_MAN_AGC_CTRL 0x143C -#define VDEC_C_DFE_CTRL1 0x1440 -#define VDEC_C_DFE_CTRL2 0x1444 -#define VDEC_C_DFE_CTRL3 0x1448 -#define VDEC_C_PLL_CTRL 0x144C -#define VDEC_C_PLL_CTRL_FAST 0x1450 -#define VDEC_C_HTL_CTRL 0x1454 -#define VDEC_C_SRC_CFG 0x1458 -#define VDEC_C_SC_STEP_SIZE 0x145C -#define VDEC_C_SC_CONVERGE_CTRL 0x1460 -#define VDEC_C_SC_LOOP_CTRL 0x1464 -#define VDEC_C_COMB_2D_HFS_CFG 0x1468 -#define VDEC_C_COMB_2D_HFD_CFG 0x146C -#define VDEC_C_COMB_2D_LF_CFG 0x1470 -#define VDEC_C_COMB_2D_BLEND 0x1474 -#define VDEC_C_COMB_MISC_CTRL 0x1478 -#define VDEC_C_COMB_FLAT_THRESH_CTRL 0x147C -#define VDEC_C_COMB_TEST 0x1480 -#define VDEC_C_BP_MISC_CTRL 0x1484 -#define VDEC_C_VCR_DET_CTRL 0x1488 -#define VDEC_C_NOISE_DET_CTRL 0x148C -#define VDEC_C_COMB_FLAT_NOISE_CTRL 0x1490 -#define VDEC_C_VERSION 0x15F8 -#define VDEC_C_SOFT_RST_CTRL 0x15FC - -/* Video Decoder D Registers */ -#define VDEC_D_MODE_CTRL 0x1600 -#define VDEC_D_OUT_CTRL1 0x1604 -#define VDEC_D_OUT_CTRL_NS 0x1608 -#define VDEC_D_GEN_STAT 0x160C -#define VDEC_D_INT_STAT_MASK 0x1610 -#define VDEC_D_LUMA_CTRL 0x1614 -#define VDEC_D_CHROMA_CTRL 0x1618 -#define VDEC_D_CRUSH_CTRL 0x161C -#define VDEC_D_HORIZ_TIM_CTRL 0x1620 -#define VDEC_D_VERT_TIM_CTRL 0x1624 -#define VDEC_D_MISC_TIM_CTRL 0x1628 -#define VDEC_D_FIELD_COUNT 0x162C -#define VDEC_D_HSCALE_CTRL 0x1630 -#define VDEC_D_VSCALE_CTRL 0x1634 -#define VDEC_D_MAN_VGA_CTRL 0x1638 -#define VDEC_D_MAN_AGC_CTRL 0x163C -#define VDEC_D_DFE_CTRL1 0x1640 -#define VDEC_D_DFE_CTRL2 0x1644 -#define VDEC_D_DFE_CTRL3 0x1648 -#define VDEC_D_PLL_CTRL 0x164C -#define VDEC_D_PLL_CTRL_FAST 0x1650 -#define VDEC_D_HTL_CTRL 0x1654 -#define VDEC_D_SRC_CFG 0x1658 -#define VDEC_D_SC_STEP_SIZE 0x165C -#define VDEC_D_SC_CONVERGE_CTRL 0x1660 -#define VDEC_D_SC_LOOP_CTRL 0x1664 -#define VDEC_D_COMB_2D_HFS_CFG 0x1668 -#define VDEC_D_COMB_2D_HFD_CFG 0x166C -#define VDEC_D_COMB_2D_LF_CFG 0x1670 -#define VDEC_D_COMB_2D_BLEND 0x1674 -#define VDEC_D_COMB_MISC_CTRL 0x1678 -#define VDEC_D_COMB_FLAT_THRESH_CTRL 0x167C -#define VDEC_D_COMB_TEST 0x1680 -#define VDEC_D_BP_MISC_CTRL 0x1684 -#define VDEC_D_VCR_DET_CTRL 0x1688 -#define VDEC_D_NOISE_DET_CTRL 0x168C -#define VDEC_D_COMB_FLAT_NOISE_CTRL 0x1690 -#define VDEC_D_VERSION 0x17F8 -#define VDEC_D_SOFT_RST_CTRL 0x17FC - -/* Video Decoder E Registers */ -#define VDEC_E_MODE_CTRL 0x1800 -#define VDEC_E_OUT_CTRL1 0x1804 -#define VDEC_E_OUT_CTRL_NS 0x1808 -#define VDEC_E_GEN_STAT 0x180C -#define VDEC_E_INT_STAT_MASK 0x1810 -#define VDEC_E_LUMA_CTRL 0x1814 -#define VDEC_E_CHROMA_CTRL 0x1818 -#define VDEC_E_CRUSH_CTRL 0x181C -#define VDEC_E_HORIZ_TIM_CTRL 0x1820 -#define VDEC_E_VERT_TIM_CTRL 0x1824 -#define VDEC_E_MISC_TIM_CTRL 0x1828 -#define VDEC_E_FIELD_COUNT 0x182C -#define VDEC_E_HSCALE_CTRL 0x1830 -#define VDEC_E_VSCALE_CTRL 0x1834 -#define VDEC_E_MAN_VGA_CTRL 0x1838 -#define VDEC_E_MAN_AGC_CTRL 0x183C -#define VDEC_E_DFE_CTRL1 0x1840 -#define VDEC_E_DFE_CTRL2 0x1844 -#define VDEC_E_DFE_CTRL3 0x1848 -#define VDEC_E_PLL_CTRL 0x184C -#define VDEC_E_PLL_CTRL_FAST 0x1850 -#define VDEC_E_HTL_CTRL 0x1854 -#define VDEC_E_SRC_CFG 0x1858 -#define VDEC_E_SC_STEP_SIZE 0x185C -#define VDEC_E_SC_CONVERGE_CTRL 0x1860 -#define VDEC_E_SC_LOOP_CTRL 0x1864 -#define VDEC_E_COMB_2D_HFS_CFG 0x1868 -#define VDEC_E_COMB_2D_HFD_CFG 0x186C -#define VDEC_E_COMB_2D_LF_CFG 0x1870 -#define VDEC_E_COMB_2D_BLEND 0x1874 -#define VDEC_E_COMB_MISC_CTRL 0x1878 -#define VDEC_E_COMB_FLAT_THRESH_CTRL 0x187C -#define VDEC_E_COMB_TEST 0x1880 -#define VDEC_E_BP_MISC_CTRL 0x1884 -#define VDEC_E_VCR_DET_CTRL 0x1888 -#define VDEC_E_NOISE_DET_CTRL 0x188C -#define VDEC_E_COMB_FLAT_NOISE_CTRL 0x1890 -#define VDEC_E_VERSION 0x19F8 -#define VDEC_E_SOFT_RST_CTRL 0x19FC - -/* Video Decoder F Registers */ -#define VDEC_F_MODE_CTRL 0x1A00 -#define VDEC_F_OUT_CTRL1 0x1A04 -#define VDEC_F_OUT_CTRL_NS 0x1A08 -#define VDEC_F_GEN_STAT 0x1A0C -#define VDEC_F_INT_STAT_MASK 0x1A10 -#define VDEC_F_LUMA_CTRL 0x1A14 -#define VDEC_F_CHROMA_CTRL 0x1A18 -#define VDEC_F_CRUSH_CTRL 0x1A1C -#define VDEC_F_HORIZ_TIM_CTRL 0x1A20 -#define VDEC_F_VERT_TIM_CTRL 0x1A24 -#define VDEC_F_MISC_TIM_CTRL 0x1A28 -#define VDEC_F_FIELD_COUNT 0x1A2C -#define VDEC_F_HSCALE_CTRL 0x1A30 -#define VDEC_F_VSCALE_CTRL 0x1A34 -#define VDEC_F_MAN_VGA_CTRL 0x1A38 -#define VDEC_F_MAN_AGC_CTRL 0x1A3C -#define VDEC_F_DFE_CTRL1 0x1A40 -#define VDEC_F_DFE_CTRL2 0x1A44 -#define VDEC_F_DFE_CTRL3 0x1A48 -#define VDEC_F_PLL_CTRL 0x1A4C -#define VDEC_F_PLL_CTRL_FAST 0x1A50 -#define VDEC_F_HTL_CTRL 0x1A54 -#define VDEC_F_SRC_CFG 0x1A58 -#define VDEC_F_SC_STEP_SIZE 0x1A5C -#define VDEC_F_SC_CONVERGE_CTRL 0x1A60 -#define VDEC_F_SC_LOOP_CTRL 0x1A64 -#define VDEC_F_COMB_2D_HFS_CFG 0x1A68 -#define VDEC_F_COMB_2D_HFD_CFG 0x1A6C -#define VDEC_F_COMB_2D_LF_CFG 0x1A70 -#define VDEC_F_COMB_2D_BLEND 0x1A74 -#define VDEC_F_COMB_MISC_CTRL 0x1A78 -#define VDEC_F_COMB_FLAT_THRESH_CTRL 0x1A7C -#define VDEC_F_COMB_TEST 0x1A80 -#define VDEC_F_BP_MISC_CTRL 0x1A84 -#define VDEC_F_VCR_DET_CTRL 0x1A88 -#define VDEC_F_NOISE_DET_CTRL 0x1A8C -#define VDEC_F_COMB_FLAT_NOISE_CTRL 0x1A90 -#define VDEC_F_VERSION 0x1BF8 -#define VDEC_F_SOFT_RST_CTRL 0x1BFC - -/* Video Decoder G Registers */ -#define VDEC_G_MODE_CTRL 0x1C00 -#define VDEC_G_OUT_CTRL1 0x1C04 -#define VDEC_G_OUT_CTRL_NS 0x1C08 -#define VDEC_G_GEN_STAT 0x1C0C -#define VDEC_G_INT_STAT_MASK 0x1C10 -#define VDEC_G_LUMA_CTRL 0x1C14 -#define VDEC_G_CHROMA_CTRL 0x1C18 -#define VDEC_G_CRUSH_CTRL 0x1C1C -#define VDEC_G_HORIZ_TIM_CTRL 0x1C20 -#define VDEC_G_VERT_TIM_CTRL 0x1C24 -#define VDEC_G_MISC_TIM_CTRL 0x1C28 -#define VDEC_G_FIELD_COUNT 0x1C2C -#define VDEC_G_HSCALE_CTRL 0x1C30 -#define VDEC_G_VSCALE_CTRL 0x1C34 -#define VDEC_G_MAN_VGA_CTRL 0x1C38 -#define VDEC_G_MAN_AGC_CTRL 0x1C3C -#define VDEC_G_DFE_CTRL1 0x1C40 -#define VDEC_G_DFE_CTRL2 0x1C44 -#define VDEC_G_DFE_CTRL3 0x1C48 -#define VDEC_G_PLL_CTRL 0x1C4C -#define VDEC_G_PLL_CTRL_FAST 0x1C50 -#define VDEC_G_HTL_CTRL 0x1C54 -#define VDEC_G_SRC_CFG 0x1C58 -#define VDEC_G_SC_STEP_SIZE 0x1C5C -#define VDEC_G_SC_CONVERGE_CTRL 0x1C60 -#define VDEC_G_SC_LOOP_CTRL 0x1C64 -#define VDEC_G_COMB_2D_HFS_CFG 0x1C68 -#define VDEC_G_COMB_2D_HFD_CFG 0x1C6C -#define VDEC_G_COMB_2D_LF_CFG 0x1C70 -#define VDEC_G_COMB_2D_BLEND 0x1C74 -#define VDEC_G_COMB_MISC_CTRL 0x1C78 -#define VDEC_G_COMB_FLAT_THRESH_CTRL 0x1C7C -#define VDEC_G_COMB_TEST 0x1C80 -#define VDEC_G_BP_MISC_CTRL 0x1C84 -#define VDEC_G_VCR_DET_CTRL 0x1C88 -#define VDEC_G_NOISE_DET_CTRL 0x1C8C -#define VDEC_G_COMB_FLAT_NOISE_CTRL 0x1C90 -#define VDEC_G_VERSION 0x1DF8 -#define VDEC_G_SOFT_RST_CTRL 0x1DFC - -/* Video Decoder H Registers */ -#define VDEC_H_MODE_CTRL 0x1E00 -#define VDEC_H_OUT_CTRL1 0x1E04 -#define VDEC_H_OUT_CTRL_NS 0x1E08 -#define VDEC_H_GEN_STAT 0x1E0C -#define VDEC_H_INT_STAT_MASK 0x1E1E -#define VDEC_H_LUMA_CTRL 0x1E14 -#define VDEC_H_CHROMA_CTRL 0x1E18 -#define VDEC_H_CRUSH_CTRL 0x1E1C -#define VDEC_H_HORIZ_TIM_CTRL 0x1E20 -#define VDEC_H_VERT_TIM_CTRL 0x1E24 -#define VDEC_H_MISC_TIM_CTRL 0x1E28 -#define VDEC_H_FIELD_COUNT 0x1E2C -#define VDEC_H_HSCALE_CTRL 0x1E30 -#define VDEC_H_VSCALE_CTRL 0x1E34 -#define VDEC_H_MAN_VGA_CTRL 0x1E38 -#define VDEC_H_MAN_AGC_CTRL 0x1E3C -#define VDEC_H_DFE_CTRL1 0x1E40 -#define VDEC_H_DFE_CTRL2 0x1E44 -#define VDEC_H_DFE_CTRL3 0x1E48 -#define VDEC_H_PLL_CTRL 0x1E4C -#define VDEC_H_PLL_CTRL_FAST 0x1E50 -#define VDEC_H_HTL_CTRL 0x1E54 -#define VDEC_H_SRC_CFG 0x1E58 -#define VDEC_H_SC_STEP_SIZE 0x1E5C -#define VDEC_H_SC_CONVERGE_CTRL 0x1E60 -#define VDEC_H_SC_LOOP_CTRL 0x1E64 -#define VDEC_H_COMB_2D_HFS_CFG 0x1E68 -#define VDEC_H_COMB_2D_HFD_CFG 0x1E6C -#define VDEC_H_COMB_2D_LF_CFG 0x1E70 -#define VDEC_H_COMB_2D_BLEND 0x1E74 -#define VDEC_H_COMB_MISC_CTRL 0x1E78 -#define VDEC_H_COMB_FLAT_THRESH_CTRL 0x1E7C -#define VDEC_H_COMB_TEST 0x1E80 -#define VDEC_H_BP_MISC_CTRL 0x1E84 -#define VDEC_H_VCR_DET_CTRL 0x1E88 -#define VDEC_H_NOISE_DET_CTRL 0x1E8C -#define VDEC_H_COMB_FLAT_NOISE_CTRL 0x1E90 -#define VDEC_H_VERSION 0x1FF8 -#define VDEC_H_SOFT_RST_CTRL 0x1FFC - -/*****************************************************************************/ -/* LUMA_CTRL register fields */ -#define VDEC_A_BRITE_CTRL 0x1014 -#define VDEC_A_CNTRST_CTRL 0x1015 -#define VDEC_A_PEAK_SEL 0x1016 - -/*****************************************************************************/ -/* CHROMA_CTRL register fields */ -#define VDEC_A_USAT_CTRL 0x1018 -#define VDEC_A_VSAT_CTRL 0x1019 -#define VDEC_A_HUE_CTRL 0x101A - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,872 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "cx25821.h" -#include "cx25821-medusa-video.h" -#include "cx25821-biffuncs.h" - -/* - * medusa_enable_bluefield_output() - * - * Enable the generation of blue filed output if no video - * - */ -static void medusa_enable_bluefield_output(struct cx25821_dev *dev, int channel, - int enable) -{ - int ret_val = 1; - u32 value = 0; - u32 tmp = 0; - int out_ctrl = OUT_CTRL1; - int out_ctrl_ns = OUT_CTRL_NS; - - switch (channel) { - default: - case VDEC_A: - break; - case VDEC_B: - out_ctrl = VDEC_B_OUT_CTRL1; - out_ctrl_ns = VDEC_B_OUT_CTRL_NS; - break; - case VDEC_C: - out_ctrl = VDEC_C_OUT_CTRL1; - out_ctrl_ns = VDEC_C_OUT_CTRL_NS; - break; - case VDEC_D: - out_ctrl = VDEC_D_OUT_CTRL1; - out_ctrl_ns = VDEC_D_OUT_CTRL_NS; - break; - case VDEC_E: - out_ctrl = VDEC_E_OUT_CTRL1; - out_ctrl_ns = VDEC_E_OUT_CTRL_NS; - return; - case VDEC_F: - out_ctrl = VDEC_F_OUT_CTRL1; - out_ctrl_ns = VDEC_F_OUT_CTRL_NS; - return; - case VDEC_G: - out_ctrl = VDEC_G_OUT_CTRL1; - out_ctrl_ns = VDEC_G_OUT_CTRL_NS; - return; - case VDEC_H: - out_ctrl = VDEC_H_OUT_CTRL1; - out_ctrl_ns = VDEC_H_OUT_CTRL_NS; - return; - } - - value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl, &tmp); - value &= 0xFFFFFF7F; /* clear BLUE_FIELD_EN */ - if (enable) - value |= 0x00000080; /* set BLUE_FIELD_EN */ - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl, value); - - value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl_ns, &tmp); - value &= 0xFFFFFF7F; - if (enable) - value |= 0x00000080; /* set BLUE_FIELD_EN */ - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl_ns, value); -} - -static int medusa_initialize_ntsc(struct cx25821_dev *dev) -{ - int ret_val = 0; - int i = 0; - u32 value = 0; - u32 tmp = 0; - - mutex_lock(&dev->lock); - - for (i = 0; i < MAX_DECODERS; i++) { - /* set video format NTSC-M */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - &tmp); - value &= 0xFFFFFFF0; - /* enable the fast locking mode bit[16] */ - value |= 0x10001; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - value); - - /* resolution NTSC 720x480 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), &tmp); - value &= 0x00C00C00; - value |= 0x612D0074; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), value); - - value = - cx25821_i2c_read(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), &tmp); - value &= 0x00C00C00; - value |= 0x1C1E001A; /* vblank_cnt + 2 to get camera ID */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), value); - - /* chroma subcarrier step size */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - SC_STEP_SIZE + (0x200 * i), 0x43E00000); - - /* enable VIP optional active */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), &tmp); - value &= 0xFFFBFFFF; - value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), value); - - /* enable VIP optional active (VIP_OPT_AL) for direct output. */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - &tmp); - value &= 0xFFFBFFFF; - value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - value); - - /* - * clear VPRES_VERT_EN bit, fixes the chroma run away problem - * when the input switching rate < 16 fields - */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), &tmp); - /* disable special play detection */ - value = setBitAtPos(value, 14); - value = clearBitAtPos(value, 15); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), value); - - /* set vbi_gate_en to 0 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - &tmp); - value = clearBitAtPos(value, 29); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - value); - - /* Enable the generation of blue field output if no video */ - medusa_enable_bluefield_output(dev, i, 1); - } - - for (i = 0; i < MAX_ENCODERS; i++) { - /* NTSC hclock */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), &tmp); - value &= 0xF000FC00; - value |= 0x06B402D0; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), value); - - /* burst begin and burst end */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), &tmp); - value &= 0xFF000000; - value |= 0x007E9054; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), value); - - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), &tmp); - value &= 0xFC00FE00; - value |= 0x00EC00F0; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), value); - - /* set NTSC vblank, no phase alternation, 7.5 IRE pedestal */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), &tmp); - value &= 0x00FCFFFF; - value |= 0x13020000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), value); - - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), &tmp); - value &= 0xFFFF0000; - value |= 0x0000E575; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), value); - - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_6 + (0x100 * i), 0x009A89C1); - - /* Subcarrier Increment */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_7 + (0x100 * i), 0x21F07C1F); - } - - /* set picture resolutions */ - /* 0 - 720 */ - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0); - /* 0 - 480 */ - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0); - - /* set Bypass input format to NTSC 525 lines */ - value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp); - value |= 0x00080200; - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); - - mutex_unlock(&dev->lock); - - return ret_val; -} - -static int medusa_PALCombInit(struct cx25821_dev *dev, int dec) -{ - int ret_val = -1; - u32 value = 0, tmp = 0; - - /* Setup for 2D threshold */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFS_CFG + (0x200 * dec), - 0x20002861); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFD_CFG + (0x200 * dec), - 0x20002861); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_LF_CFG + (0x200 * dec), - 0x200A1023); - - /* Setup flat chroma and luma thresholds */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp); - value &= 0x06230000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - COMB_FLAT_THRESH_CTRL + (0x200 * dec), value); - - /* set comb 2D blend */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_BLEND + (0x200 * dec), - 0x210F0F0F); - - /* COMB MISC CONTROL */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_MISC_CTRL + (0x200 * dec), - 0x41120A7F); - - return ret_val; -} - -static int medusa_initialize_pal(struct cx25821_dev *dev) -{ - int ret_val = 0; - int i = 0; - u32 value = 0; - u32 tmp = 0; - - mutex_lock(&dev->lock); - - for (i = 0; i < MAX_DECODERS; i++) { - /* set video format PAL-BDGHI */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - &tmp); - value &= 0xFFFFFFF0; - /* enable the fast locking mode bit[16] */ - value |= 0x10004; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - value); - - /* resolution PAL 720x576 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), &tmp); - value &= 0x00C00C00; - value |= 0x632D007D; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), value); - - /* vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), &tmp); - value &= 0x00C00C00; - value |= 0x28240026; /* vblank_cnt + 2 to get camera ID */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), value); - - /* chroma subcarrier step size */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - SC_STEP_SIZE + (0x200 * i), 0x5411E2D0); - - /* enable VIP optional active */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), &tmp); - value &= 0xFFFBFFFF; - value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), value); - - /* enable VIP optional active (VIP_OPT_AL) for direct output. */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - &tmp); - value &= 0xFFFBFFFF; - value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - value); - - /* - * clear VPRES_VERT_EN bit, fixes the chroma run away problem - * when the input switching rate < 16 fields - */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), &tmp); - /* disable special play detection */ - value = setBitAtPos(value, 14); - value = clearBitAtPos(value, 15); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), value); - - /* set vbi_gate_en to 0 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - &tmp); - value = clearBitAtPos(value, 29); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - value); - - medusa_PALCombInit(dev, i); - - /* Enable the generation of blue field output if no video */ - medusa_enable_bluefield_output(dev, i, 1); - } - - for (i = 0; i < MAX_ENCODERS; i++) { - /* PAL hclock */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), &tmp); - value &= 0xF000FC00; - value |= 0x06C002D0; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), value); - - /* burst begin and burst end */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), &tmp); - value &= 0xFF000000; - value |= 0x007E9754; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), value); - - /* hblank and vactive */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), &tmp); - value &= 0xFC00FE00; - value |= 0x00FC0120; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), value); - - /* set PAL vblank, phase alternation, 0 IRE pedestal */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), &tmp); - value &= 0x00FCFFFF; - value |= 0x14010000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), value); - - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), &tmp); - value &= 0xFFFF0000; - value |= 0x0000F078; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), value); - - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_6 + (0x100 * i), 0x00A493CF); - - /* Subcarrier Increment */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_7 + (0x100 * i), 0x2A098ACB); - } - - /* set picture resolutions */ - /* 0 - 720 */ - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0); - /* 0 - 576 */ - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0); - - /* set Bypass input format to PAL 625 lines */ - value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp); - value &= 0xFFF7FDFF; - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); - - mutex_unlock(&dev->lock); - - return ret_val; -} - -int medusa_set_videostandard(struct cx25821_dev *dev) -{ - int status = STATUS_SUCCESS; - u32 value = 0, tmp = 0; - - if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK) - status = medusa_initialize_pal(dev); - else - status = medusa_initialize_ntsc(dev); - - /* Enable DENC_A output */ - value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_A_REG_4, &tmp); - value = setBitAtPos(value, 4); - status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_A_REG_4, value); - - /* Enable DENC_B output */ - value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_B_REG_4, &tmp); - value = setBitAtPos(value, 4); - status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_B_REG_4, value); - - return status; -} - -void medusa_set_resolution(struct cx25821_dev *dev, int width, - int decoder_select) -{ - int decoder = 0; - int decoder_count = 0; - int ret_val = 0; - u32 hscale = 0x0; - u32 vscale = 0x0; - const int MAX_WIDTH = 720; - - mutex_lock(&dev->lock); - - /* validate the width - cannot be negative */ - if (width > MAX_WIDTH) { - pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n", - __func__, width, MAX_WIDTH); - width = MAX_WIDTH; - } - - if (decoder_select <= 7 && decoder_select >= 0) { - decoder = decoder_select; - decoder_count = decoder_select + 1; - } else { - decoder = 0; - decoder_count = _num_decoders; - } - - switch (width) { - case 320: - hscale = 0x13E34B; - vscale = 0x0; - break; - - case 352: - hscale = 0x10A273; - vscale = 0x0; - break; - - case 176: - hscale = 0x3115B2; - vscale = 0x1E00; - break; - - case 160: - hscale = 0x378D84; - vscale = 0x1E00; - break; - - default: /* 720 */ - hscale = 0x0; - vscale = 0x0; - break; - } - - for (; decoder < decoder_count; decoder++) { - /* write scaling values for each decoder */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - HSCALE_CTRL + (0x200 * decoder), hscale); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - VSCALE_CTRL + (0x200 * decoder), vscale); - } - - mutex_unlock(&dev->lock); -} - -static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder, - int duration) -{ - int ret_val = 0; - u32 fld_cnt = 0; - u32 tmp = 0; - u32 disp_cnt_reg = DISP_AB_CNT; - - mutex_lock(&dev->lock); - - /* no support */ - if (decoder < VDEC_A && decoder > VDEC_H) { - mutex_unlock(&dev->lock); - return; - } - - switch (decoder) { - default: - break; - case VDEC_C: - case VDEC_D: - disp_cnt_reg = DISP_CD_CNT; - break; - case VDEC_E: - case VDEC_F: - disp_cnt_reg = DISP_EF_CNT; - break; - case VDEC_G: - case VDEC_H: - disp_cnt_reg = DISP_GH_CNT; - break; - } - - _display_field_cnt[decoder] = duration; - - /* update hardware */ - fld_cnt = cx25821_i2c_read(&dev->i2c_bus[0], disp_cnt_reg, &tmp); - - if (!(decoder % 2)) { /* EVEN decoder */ - fld_cnt &= 0xFFFF0000; - fld_cnt |= duration; - } else { - fld_cnt &= 0x0000FFFF; - fld_cnt |= ((u32) duration) << 16; - } - - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt); - - mutex_unlock(&dev->lock); -} - -/* Map to Medusa register setting */ -static int mapM(int srcMin, - int srcMax, int srcVal, int dstMin, int dstMax, int *dstVal) -{ - int numerator; - int denominator; - int quotient; - - if ((srcMin == srcMax) || (srcVal < srcMin) || (srcVal > srcMax)) - return -1; - /* - * This is the overall expression used: - * *dstVal = - * (srcVal - srcMin)*(dstMax - dstMin) / (srcMax - srcMin) + dstMin; - * but we need to account for rounding so below we use the modulus - * operator to find the remainder and increment if necessary. - */ - numerator = (srcVal - srcMin) * (dstMax - dstMin); - denominator = srcMax - srcMin; - quotient = numerator / denominator; - - if (2 * (numerator % denominator) >= denominator) - quotient++; - - *dstVal = quotient + dstMin; - - return 0; -} - -static unsigned long convert_to_twos(long numeric, unsigned long bits_len) -{ - unsigned char temp; - - if (numeric >= 0) - return numeric; - else { - temp = ~(abs(numeric) & 0xFF); - temp += 1; - return temp; - } -} - -int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder) -{ - int ret_val = 0; - int value = 0; - u32 val = 0, tmp = 0; - - mutex_lock(&dev->lock); - if ((brightness > VIDEO_PROCAMP_MAX) - || (brightness < VIDEO_PROCAMP_MIN)) { - mutex_unlock(&dev->lock); - return -1; - } - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness, - SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); - value = convert_to_twos(value, 8); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp); - val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_BRITE_CTRL + (0x200 * decoder), - val | value); - mutex_unlock(&dev->lock); - return ret_val; -} - -int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder) -{ - int ret_val = 0; - int value = 0; - u32 val = 0, tmp = 0; - - mutex_lock(&dev->lock); - - if ((contrast > VIDEO_PROCAMP_MAX) || (contrast < VIDEO_PROCAMP_MIN)) { - mutex_unlock(&dev->lock); - return -1; - } - - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast, - UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp); - val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_CNTRST_CTRL + (0x200 * decoder), - val | value); - - mutex_unlock(&dev->lock); - return ret_val; -} - -int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder) -{ - int ret_val = 0; - int value = 0; - u32 val = 0, tmp = 0; - - mutex_lock(&dev->lock); - - if ((hue > VIDEO_PROCAMP_MAX) || (hue < VIDEO_PROCAMP_MIN)) { - mutex_unlock(&dev->lock); - return -1; - } - - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue, SIGNED_BYTE_MIN, - SIGNED_BYTE_MAX, &value); - - value = convert_to_twos(value, 8); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp); - val &= 0xFFFFFF00; - - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_HUE_CTRL + (0x200 * decoder), val | value); - - mutex_unlock(&dev->lock); - return ret_val; -} - -int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder) -{ - int ret_val = 0; - int value = 0; - u32 val = 0, tmp = 0; - - mutex_lock(&dev->lock); - - if ((saturation > VIDEO_PROCAMP_MAX) - || (saturation < VIDEO_PROCAMP_MIN)) { - mutex_unlock(&dev->lock); - return -1; - } - - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation, - UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); - - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp); - val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_USAT_CTRL + (0x200 * decoder), - val | value); - - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp); - val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_VSAT_CTRL + (0x200 * decoder), - val | value); - - mutex_unlock(&dev->lock); - return ret_val; -} - -/* Program the display sequence and monitor output. */ - -int medusa_video_init(struct cx25821_dev *dev) -{ - u32 value = 0, tmp = 0; - int ret_val = 0; - int i = 0; - - mutex_lock(&dev->lock); - - _num_decoders = dev->_max_num_decoders; - - /* disable Auto source selection on all video decoders */ - value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp); - value &= 0xFFFFF0FF; - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value); - - if (ret_val < 0) - goto error; - - /* Turn off Master source switch enable */ - value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp); - value &= 0xFFFFFFDF; - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value); - - if (ret_val < 0) - goto error; - - mutex_unlock(&dev->lock); - - for (i = 0; i < _num_decoders; i++) - medusa_set_decoderduration(dev, i, _display_field_cnt[i]); - - mutex_lock(&dev->lock); - - /* Select monitor as DENC A input, power up the DAC */ - value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_AB_CTRL, &tmp); - value &= 0xFF70FF70; - value |= 0x00090008; /* set en_active */ - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], DENC_AB_CTRL, value); - - if (ret_val < 0) - goto error; - - /* enable input is VIP/656 */ - value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp); - value |= 0x00040100; /* enable VIP */ - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); - - if (ret_val < 0) - goto error; - - /* select AFE clock to output mode */ - value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp); - value &= 0x83FFFFFF; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, - value | 0x10000000); - - if (ret_val < 0) - goto error; - - /* Turn on all of the data out and control output pins. */ - value = cx25821_i2c_read(&dev->i2c_bus[0], PIN_OE_CTRL, &tmp); - value &= 0xFEF0FE00; - if (_num_decoders == MAX_DECODERS) { - /* - * Note: The octal board does not support control pins(bit16-19) - * These bits are ignored in the octal board. - * - * disable VDEC A-C port, default to Mobilygen Interface - */ - value |= 0x010001F8; - } else { - /* disable VDEC A-C port, default to Mobilygen Interface */ - value |= 0x010F0108; - } - - value |= 7; - ret_val = cx25821_i2c_write(&dev->i2c_bus[0], PIN_OE_CTRL, value); - - if (ret_val < 0) - goto error; - - - mutex_unlock(&dev->lock); - - ret_val = medusa_set_videostandard(dev); - - return ret_val; - -error: - mutex_unlock(&dev->lock); - return ret_val; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-video.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-video.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-video.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-medusa-video.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _MEDUSA_VIDEO_H -#define _MEDUSA_VIDEO_H - -#include "cx25821-medusa-defines.h" - -/* Color control constants */ -#define VIDEO_PROCAMP_MIN 0 -#define VIDEO_PROCAMP_MAX 10000 -#define UNSIGNED_BYTE_MIN 0 -#define UNSIGNED_BYTE_MAX 0xFF -#define SIGNED_BYTE_MIN -128 -#define SIGNED_BYTE_MAX 127 - -/* Default video color settings */ -#define SHARPNESS_DEFAULT 50 -#define SATURATION_DEFAULT 5000 -#define BRIGHTNESS_DEFAULT 6200 -#define CONTRAST_DEFAULT 5000 -#define HUE_DEFAULT 5000 - -unsigned short _num_decoders; -unsigned short _num_cameras; - -unsigned int _video_standard; -int _display_field_cnt[MAX_DECODERS]; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-reg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-reg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1592 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __CX25821_REGISTERS__ -#define __CX25821_REGISTERS__ - -/* Risc Instructions */ -#define RISC_CNT_INC 0x00010000 -#define RISC_CNT_RESET 0x00030000 -#define RISC_IRQ1 0x01000000 -#define RISC_IRQ2 0x02000000 -#define RISC_EOL 0x04000000 -#define RISC_SOL 0x08000000 -#define RISC_WRITE 0x10000000 -#define RISC_SKIP 0x20000000 -#define RISC_JUMP 0x70000000 -#define RISC_SYNC 0x80000000 -#define RISC_RESYNC 0x80008000 -#define RISC_READ 0x90000000 -#define RISC_WRITERM 0xB0000000 -#define RISC_WRITECM 0xC0000000 -#define RISC_WRITECR 0xD0000000 -#define RISC_WRITEC 0x50000000 -#define RISC_READC 0xA0000000 - -#define RISC_SYNC_ODD 0x00000000 -#define RISC_SYNC_EVEN 0x00000200 -#define RISC_SYNC_ODD_VBI 0x00000006 -#define RISC_SYNC_EVEN_VBI 0x00000207 -#define RISC_NOOP 0xF0000000 - -/***************************************************************************** -* ASB SRAM - *****************************************************************************/ -#define TX_SRAM 0x000000 /* Transmit SRAM */ - -/*****************************************************************************/ -#define RX_RAM 0x010000 /* Receive SRAM */ - -/***************************************************************************** -* Application Layer (AL) - *****************************************************************************/ -#define DEV_CNTRL2 0x040000 /* Device control */ -#define FLD_RUN_RISC 0x00000020 - -/* ***************************************************************************** */ -#define PCI_INT_MSK 0x040010 /* PCI interrupt mask */ -#define PCI_INT_STAT 0x040014 /* PCI interrupt status */ -#define PCI_INT_MSTAT 0x040018 /* PCI interrupt masked status */ -#define FLD_HAMMERHEAD_INT (1 << 27) -#define FLD_UART_INT (1 << 26) -#define FLD_IRQN_INT (1 << 25) -#define FLD_TM_INT (1 << 28) -#define FLD_I2C_3_RACK (1 << 27) -#define FLD_I2C_3_INT (1 << 26) -#define FLD_I2C_2_RACK (1 << 25) -#define FLD_I2C_2_INT (1 << 24) -#define FLD_I2C_1_RACK (1 << 23) -#define FLD_I2C_1_INT (1 << 22) - -#define FLD_APB_DMA_BERR_INT (1 << 21) -#define FLD_AL_WR_BERR_INT (1 << 20) -#define FLD_AL_RD_BERR_INT (1 << 19) -#define FLD_RISC_WR_BERR_INT (1 << 18) -#define FLD_RISC_RD_BERR_INT (1 << 17) - -#define FLD_VID_I_INT (1 << 8) -#define FLD_VID_H_INT (1 << 7) -#define FLD_VID_G_INT (1 << 6) -#define FLD_VID_F_INT (1 << 5) -#define FLD_VID_E_INT (1 << 4) -#define FLD_VID_D_INT (1 << 3) -#define FLD_VID_C_INT (1 << 2) -#define FLD_VID_B_INT (1 << 1) -#define FLD_VID_A_INT (1 << 0) - -/* ***************************************************************************** */ -#define VID_A_INT_MSK 0x040020 /* Video A interrupt mask */ -#define VID_A_INT_STAT 0x040024 /* Video A interrupt status */ -#define VID_A_INT_MSTAT 0x040028 /* Video A interrupt masked status */ -#define VID_A_INT_SSTAT 0x04002C /* Video A interrupt set status */ - -/* ***************************************************************************** */ -#define VID_B_INT_MSK 0x040030 /* Video B interrupt mask */ -#define VID_B_INT_STAT 0x040034 /* Video B interrupt status */ -#define VID_B_INT_MSTAT 0x040038 /* Video B interrupt masked status */ -#define VID_B_INT_SSTAT 0x04003C /* Video B interrupt set status */ - -/* ***************************************************************************** */ -#define VID_C_INT_MSK 0x040040 /* Video C interrupt mask */ -#define VID_C_INT_STAT 0x040044 /* Video C interrupt status */ -#define VID_C_INT_MSTAT 0x040048 /* Video C interrupt masked status */ -#define VID_C_INT_SSTAT 0x04004C /* Video C interrupt set status */ - -/* ***************************************************************************** */ -#define VID_D_INT_MSK 0x040050 /* Video D interrupt mask */ -#define VID_D_INT_STAT 0x040054 /* Video D interrupt status */ -#define VID_D_INT_MSTAT 0x040058 /* Video D interrupt masked status */ -#define VID_D_INT_SSTAT 0x04005C /* Video D interrupt set status */ - -/* ***************************************************************************** */ -#define VID_E_INT_MSK 0x040060 /* Video E interrupt mask */ -#define VID_E_INT_STAT 0x040064 /* Video E interrupt status */ -#define VID_E_INT_MSTAT 0x040068 /* Video E interrupt masked status */ -#define VID_E_INT_SSTAT 0x04006C /* Video E interrupt set status */ - -/* ***************************************************************************** */ -#define VID_F_INT_MSK 0x040070 /* Video F interrupt mask */ -#define VID_F_INT_STAT 0x040074 /* Video F interrupt status */ -#define VID_F_INT_MSTAT 0x040078 /* Video F interrupt masked status */ -#define VID_F_INT_SSTAT 0x04007C /* Video F interrupt set status */ - -/* ***************************************************************************** */ -#define VID_G_INT_MSK 0x040080 /* Video G interrupt mask */ -#define VID_G_INT_STAT 0x040084 /* Video G interrupt status */ -#define VID_G_INT_MSTAT 0x040088 /* Video G interrupt masked status */ -#define VID_G_INT_SSTAT 0x04008C /* Video G interrupt set status */ - -/* ***************************************************************************** */ -#define VID_H_INT_MSK 0x040090 /* Video H interrupt mask */ -#define VID_H_INT_STAT 0x040094 /* Video H interrupt status */ -#define VID_H_INT_MSTAT 0x040098 /* Video H interrupt masked status */ -#define VID_H_INT_SSTAT 0x04009C /* Video H interrupt set status */ - -/* ***************************************************************************** */ -#define VID_I_INT_MSK 0x0400A0 /* Video I interrupt mask */ -#define VID_I_INT_STAT 0x0400A4 /* Video I interrupt status */ -#define VID_I_INT_MSTAT 0x0400A8 /* Video I interrupt masked status */ -#define VID_I_INT_SSTAT 0x0400AC /* Video I interrupt set status */ - -/* ***************************************************************************** */ -#define VID_J_INT_MSK 0x0400B0 /* Video J interrupt mask */ -#define VID_J_INT_STAT 0x0400B4 /* Video J interrupt status */ -#define VID_J_INT_MSTAT 0x0400B8 /* Video J interrupt masked status */ -#define VID_J_INT_SSTAT 0x0400BC /* Video J interrupt set status */ - -#define FLD_VID_SRC_OPC_ERR 0x00020000 -#define FLD_VID_DST_OPC_ERR 0x00010000 -#define FLD_VID_SRC_SYNC 0x00002000 -#define FLD_VID_DST_SYNC 0x00001000 -#define FLD_VID_SRC_UF 0x00000200 -#define FLD_VID_DST_OF 0x00000100 -#define FLD_VID_SRC_RISC2 0x00000020 -#define FLD_VID_DST_RISC2 0x00000010 -#define FLD_VID_SRC_RISC1 0x00000002 -#define FLD_VID_DST_RISC1 0x00000001 -#define FLD_VID_SRC_ERRORS (FLD_VID_SRC_OPC_ERR | FLD_VID_SRC_SYNC | FLD_VID_SRC_UF) -#define FLD_VID_DST_ERRORS (FLD_VID_DST_OPC_ERR | FLD_VID_DST_SYNC | FLD_VID_DST_OF) - -/* ***************************************************************************** */ -#define AUD_A_INT_MSK 0x0400C0 /* Audio Int interrupt mask */ -#define AUD_A_INT_STAT 0x0400C4 /* Audio Int interrupt status */ -#define AUD_A_INT_MSTAT 0x0400C8 /* Audio Int interrupt masked status */ -#define AUD_A_INT_SSTAT 0x0400CC /* Audio Int interrupt set status */ - -/* ***************************************************************************** */ -#define AUD_B_INT_MSK 0x0400D0 /* Audio Int interrupt mask */ -#define AUD_B_INT_STAT 0x0400D4 /* Audio Int interrupt status */ -#define AUD_B_INT_MSTAT 0x0400D8 /* Audio Int interrupt masked status */ -#define AUD_B_INT_SSTAT 0x0400DC /* Audio Int interrupt set status */ - -/* ***************************************************************************** */ -#define AUD_C_INT_MSK 0x0400E0 /* Audio Int interrupt mask */ -#define AUD_C_INT_STAT 0x0400E4 /* Audio Int interrupt status */ -#define AUD_C_INT_MSTAT 0x0400E8 /* Audio Int interrupt masked status */ -#define AUD_C_INT_SSTAT 0x0400EC /* Audio Int interrupt set status */ - -/* ***************************************************************************** */ -#define AUD_D_INT_MSK 0x0400F0 /* Audio Int interrupt mask */ -#define AUD_D_INT_STAT 0x0400F4 /* Audio Int interrupt status */ -#define AUD_D_INT_MSTAT 0x0400F8 /* Audio Int interrupt masked status */ -#define AUD_D_INT_SSTAT 0x0400FC /* Audio Int interrupt set status */ - -/* ***************************************************************************** */ -#define AUD_E_INT_MSK 0x040100 /* Audio Int interrupt mask */ -#define AUD_E_INT_STAT 0x040104 /* Audio Int interrupt status */ -#define AUD_E_INT_MSTAT 0x040108 /* Audio Int interrupt masked status */ -#define AUD_E_INT_SSTAT 0x04010C /* Audio Int interrupt set status */ - -#define FLD_AUD_SRC_OPC_ERR 0x00020000 -#define FLD_AUD_DST_OPC_ERR 0x00010000 -#define FLD_AUD_SRC_SYNC 0x00002000 -#define FLD_AUD_DST_SYNC 0x00001000 -#define FLD_AUD_SRC_OF 0x00000200 -#define FLD_AUD_DST_OF 0x00000100 -#define FLD_AUD_SRC_RISCI2 0x00000020 -#define FLD_AUD_DST_RISCI2 0x00000010 -#define FLD_AUD_SRC_RISCI1 0x00000002 -#define FLD_AUD_DST_RISCI1 0x00000001 - -/* ***************************************************************************** */ -#define MBIF_A_INT_MSK 0x040110 /* MBIF Int interrupt mask */ -#define MBIF_A_INT_STAT 0x040114 /* MBIF Int interrupt status */ -#define MBIF_A_INT_MSTAT 0x040118 /* MBIF Int interrupt masked status */ -#define MBIF_A_INT_SSTAT 0x04011C /* MBIF Int interrupt set status */ - -/* ***************************************************************************** */ -#define MBIF_B_INT_MSK 0x040120 /* MBIF Int interrupt mask */ -#define MBIF_B_INT_STAT 0x040124 /* MBIF Int interrupt status */ -#define MBIF_B_INT_MSTAT 0x040128 /* MBIF Int interrupt masked status */ -#define MBIF_B_INT_SSTAT 0x04012C /* MBIF Int interrupt set status */ - -#define FLD_MBIF_DST_OPC_ERR 0x00010000 -#define FLD_MBIF_DST_SYNC 0x00001000 -#define FLD_MBIF_DST_OF 0x00000100 -#define FLD_MBIF_DST_RISCI2 0x00000010 -#define FLD_MBIF_DST_RISCI1 0x00000001 - -/* ***************************************************************************** */ -#define AUD_EXT_INT_MSK 0x040060 /* Audio Ext interrupt mask */ -#define AUD_EXT_INT_STAT 0x040064 /* Audio Ext interrupt status */ -#define AUD_EXT_INT_MSTAT 0x040068 /* Audio Ext interrupt masked status */ -#define AUD_EXT_INT_SSTAT 0x04006C /* Audio Ext interrupt set status */ -#define FLD_AUD_EXT_OPC_ERR 0x00010000 -#define FLD_AUD_EXT_SYNC 0x00001000 -#define FLD_AUD_EXT_OF 0x00000100 -#define FLD_AUD_EXT_RISCI2 0x00000010 -#define FLD_AUD_EXT_RISCI1 0x00000001 - -/* ***************************************************************************** */ -#define GPIO_LO 0x110010 /* Lower of GPIO pins [31:0] */ -#define GPIO_HI 0x110014 /* Upper WORD of GPIO pins [47:31] */ - -#define GPIO_LO_OE 0x110018 /* Lower of GPIO output enable [31:0] */ -#define GPIO_HI_OE 0x11001C /* Upper word of GPIO output enable [47:32] */ - -#define GPIO_LO_INT_MSK 0x11003C /* GPIO interrupt mask */ -#define GPIO_LO_INT_STAT 0x110044 /* GPIO interrupt status */ -#define GPIO_LO_INT_MSTAT 0x11004C /* GPIO interrupt masked status */ -#define GPIO_LO_ISM_SNS 0x110054 /* GPIO interrupt sensitivity */ -#define GPIO_LO_ISM_POL 0x11005C /* GPIO interrupt polarity */ - -#define GPIO_HI_INT_MSK 0x110040 /* GPIO interrupt mask */ -#define GPIO_HI_INT_STAT 0x110048 /* GPIO interrupt status */ -#define GPIO_HI_INT_MSTAT 0x110050 /* GPIO interrupt masked status */ -#define GPIO_HI_ISM_SNS 0x110058 /* GPIO interrupt sensitivity */ -#define GPIO_HI_ISM_POL 0x110060 /* GPIO interrupt polarity */ - -#define FLD_GPIO43_INT (1 << 11) -#define FLD_GPIO42_INT (1 << 10) -#define FLD_GPIO41_INT (1 << 9) -#define FLD_GPIO40_INT (1 << 8) - -#define FLD_GPIO9_INT (1 << 9) -#define FLD_GPIO8_INT (1 << 8) -#define FLD_GPIO7_INT (1 << 7) -#define FLD_GPIO6_INT (1 << 6) -#define FLD_GPIO5_INT (1 << 5) -#define FLD_GPIO4_INT (1 << 4) -#define FLD_GPIO3_INT (1 << 3) -#define FLD_GPIO2_INT (1 << 2) -#define FLD_GPIO1_INT (1 << 1) -#define FLD_GPIO0_INT (1 << 0) - -/* ***************************************************************************** */ -#define TC_REQ 0x040090 /* Rider PCI Express traFFic class request */ - -/* ***************************************************************************** */ -#define TC_REQ_SET 0x040094 /* Rider PCI Express traFFic class request set */ - -/* ***************************************************************************** */ -/* Rider */ -/* ***************************************************************************** */ - -/* PCI Compatible Header */ -/* ***************************************************************************** */ -#define RDR_CFG0 0x050000 -#define RDR_VENDOR_DEVICE_ID_CFG 0x050000 - -/* ***************************************************************************** */ -#define RDR_CFG1 0x050004 - -/* ***************************************************************************** */ -#define RDR_CFG2 0x050008 - -/* ***************************************************************************** */ -#define RDR_CFG3 0x05000C - -/* ***************************************************************************** */ -#define RDR_CFG4 0x050010 - -/* ***************************************************************************** */ -#define RDR_CFG5 0x050014 - -/* ***************************************************************************** */ -#define RDR_CFG6 0x050018 - -/* ***************************************************************************** */ -#define RDR_CFG7 0x05001C - -/* ***************************************************************************** */ -#define RDR_CFG8 0x050020 - -/* ***************************************************************************** */ -#define RDR_CFG9 0x050024 - -/* ***************************************************************************** */ -#define RDR_CFGA 0x050028 - -/* ***************************************************************************** */ -#define RDR_CFGB 0x05002C -#define RDR_SUSSYSTEM_ID_CFG 0x05002C - -/* ***************************************************************************** */ -#define RDR_CFGC 0x050030 - -/* ***************************************************************************** */ -#define RDR_CFGD 0x050034 - -/* ***************************************************************************** */ -#define RDR_CFGE 0x050038 - -/* ***************************************************************************** */ -#define RDR_CFGF 0x05003C - -/* ***************************************************************************** */ -/* PCI-Express Capabilities */ -/* ***************************************************************************** */ -#define RDR_PECAP 0x050040 - -/* ***************************************************************************** */ -#define RDR_PEDEVCAP 0x050044 - -/* ***************************************************************************** */ -#define RDR_PEDEVSC 0x050048 - -/* ***************************************************************************** */ -#define RDR_PELINKCAP 0x05004C - -/* ***************************************************************************** */ -#define RDR_PELINKSC 0x050050 - -/* ***************************************************************************** */ -#define RDR_PMICAP 0x050080 - -/* ***************************************************************************** */ -#define RDR_PMCSR 0x050084 - -/* ***************************************************************************** */ -#define RDR_VPDCAP 0x050090 - -/* ***************************************************************************** */ -#define RDR_VPDDATA 0x050094 - -/* ***************************************************************************** */ -#define RDR_MSICAP 0x0500A0 - -/* ***************************************************************************** */ -#define RDR_MSIARL 0x0500A4 - -/* ***************************************************************************** */ -#define RDR_MSIARU 0x0500A8 - -/* ***************************************************************************** */ -#define RDR_MSIDATA 0x0500AC - -/* ***************************************************************************** */ -/* PCI Express Extended Capabilities */ -/* ***************************************************************************** */ -#define RDR_AERXCAP 0x050100 - -/* ***************************************************************************** */ -#define RDR_AERUESTA 0x050104 - -/* ***************************************************************************** */ -#define RDR_AERUEMSK 0x050108 - -/* ***************************************************************************** */ -#define RDR_AERUESEV 0x05010C - -/* ***************************************************************************** */ -#define RDR_AERCESTA 0x050110 - -/* ***************************************************************************** */ -#define RDR_AERCEMSK 0x050114 - -/* ***************************************************************************** */ -#define RDR_AERCC 0x050118 - -/* ***************************************************************************** */ -#define RDR_AERHL0 0x05011C - -/* ***************************************************************************** */ -#define RDR_AERHL1 0x050120 - -/* ***************************************************************************** */ -#define RDR_AERHL2 0x050124 - -/* ***************************************************************************** */ -#define RDR_AERHL3 0x050128 - -/* ***************************************************************************** */ -#define RDR_VCXCAP 0x050200 - -/* ***************************************************************************** */ -#define RDR_VCCAP1 0x050204 - -/* ***************************************************************************** */ -#define RDR_VCCAP2 0x050208 - -/* ***************************************************************************** */ -#define RDR_VCSC 0x05020C - -/* ***************************************************************************** */ -#define RDR_VCR0_CAP 0x050210 - -/* ***************************************************************************** */ -#define RDR_VCR0_CTRL 0x050214 - -/* ***************************************************************************** */ -#define RDR_VCR0_STAT 0x050218 - -/* ***************************************************************************** */ -#define RDR_VCR1_CAP 0x05021C - -/* ***************************************************************************** */ -#define RDR_VCR1_CTRL 0x050220 - -/* ***************************************************************************** */ -#define RDR_VCR1_STAT 0x050224 - -/* ***************************************************************************** */ -#define RDR_VCR2_CAP 0x050228 - -/* ***************************************************************************** */ -#define RDR_VCR2_CTRL 0x05022C - -/* ***************************************************************************** */ -#define RDR_VCR2_STAT 0x050230 - -/* ***************************************************************************** */ -#define RDR_VCR3_CAP 0x050234 - -/* ***************************************************************************** */ -#define RDR_VCR3_CTRL 0x050238 - -/* ***************************************************************************** */ -#define RDR_VCR3_STAT 0x05023C - -/* ***************************************************************************** */ -#define RDR_VCARB0 0x050240 - -/* ***************************************************************************** */ -#define RDR_VCARB1 0x050244 - -/* ***************************************************************************** */ -#define RDR_VCARB2 0x050248 - -/* ***************************************************************************** */ -#define RDR_VCARB3 0x05024C - -/* ***************************************************************************** */ -#define RDR_VCARB4 0x050250 - -/* ***************************************************************************** */ -#define RDR_VCARB5 0x050254 - -/* ***************************************************************************** */ -#define RDR_VCARB6 0x050258 - -/* ***************************************************************************** */ -#define RDR_VCARB7 0x05025C - -/* ***************************************************************************** */ -#define RDR_RDRSTAT0 0x050300 - -/* ***************************************************************************** */ -#define RDR_RDRSTAT1 0x050304 - -/* ***************************************************************************** */ -#define RDR_RDRCTL0 0x050308 - -/* ***************************************************************************** */ -#define RDR_RDRCTL1 0x05030C - -/* ***************************************************************************** */ -/* Transaction Layer Registers */ -/* ***************************************************************************** */ -#define RDR_TLSTAT0 0x050310 - -/* ***************************************************************************** */ -#define RDR_TLSTAT1 0x050314 - -/* ***************************************************************************** */ -#define RDR_TLCTL0 0x050318 -#define FLD_CFG_UR_CPL_MODE 0x00000040 -#define FLD_CFG_CORR_ERR_QUITE 0x00000020 -#define FLD_CFG_RCB_CK_EN 0x00000010 -#define FLD_CFG_BNDRY_CK_EN 0x00000008 -#define FLD_CFG_BYTE_EN_CK_EN 0x00000004 -#define FLD_CFG_RELAX_ORDER_MSK 0x00000002 -#define FLD_CFG_TAG_ORDER_EN 0x00000001 - -/* ***************************************************************************** */ -#define RDR_TLCTL1 0x05031C - -/* ***************************************************************************** */ -#define RDR_REQRCAL 0x050320 - -/* ***************************************************************************** */ -#define RDR_REQRCAU 0x050324 - -/* ***************************************************************************** */ -#define RDR_REQEPA 0x050328 - -/* ***************************************************************************** */ -#define RDR_REQCTRL 0x05032C - -/* ***************************************************************************** */ -#define RDR_REQSTAT 0x050330 - -/* ***************************************************************************** */ -#define RDR_TL_TEST 0x050334 - -/* ***************************************************************************** */ -#define RDR_VCR01_CTL 0x050348 - -/* ***************************************************************************** */ -#define RDR_VCR23_CTL 0x05034C - -/* ***************************************************************************** */ -#define RDR_RX_VCR0_FC 0x050350 - -/* ***************************************************************************** */ -#define RDR_RX_VCR1_FC 0x050354 - -/* ***************************************************************************** */ -#define RDR_RX_VCR2_FC 0x050358 - -/* ***************************************************************************** */ -#define RDR_RX_VCR3_FC 0x05035C - -/* ***************************************************************************** */ -/* Data Link Layer Registers */ -/* ***************************************************************************** */ -#define RDR_DLLSTAT 0x050360 - -/* ***************************************************************************** */ -#define RDR_DLLCTRL 0x050364 - -/* ***************************************************************************** */ -#define RDR_REPLAYTO 0x050368 - -/* ***************************************************************************** */ -#define RDR_ACKLATTO 0x05036C - -/* ***************************************************************************** */ -/* MAC Layer Registers */ -/* ***************************************************************************** */ -#define RDR_MACSTAT0 0x050380 - -/* ***************************************************************************** */ -#define RDR_MACSTAT1 0x050384 - -/* ***************************************************************************** */ -#define RDR_MACCTRL0 0x050388 - -/* ***************************************************************************** */ -#define RDR_MACCTRL1 0x05038C - -/* ***************************************************************************** */ -#define RDR_MACCTRL2 0x050390 - -/* ***************************************************************************** */ -#define RDR_MAC_LB_DATA 0x050394 - -/* ***************************************************************************** */ -#define RDR_L0S_EXIT_LAT 0x050398 - -/* ***************************************************************************** */ -/* DMAC */ -/* ***************************************************************************** */ -#define DMA1_PTR1 0x100000 /* DMA Current Ptr : Ch#1 */ - -/* ***************************************************************************** */ -#define DMA2_PTR1 0x100004 /* DMA Current Ptr : Ch#2 */ - -/* ***************************************************************************** */ -#define DMA3_PTR1 0x100008 /* DMA Current Ptr : Ch#3 */ - -/* ***************************************************************************** */ -#define DMA4_PTR1 0x10000C /* DMA Current Ptr : Ch#4 */ - -/* ***************************************************************************** */ -#define DMA5_PTR1 0x100010 /* DMA Current Ptr : Ch#5 */ - -/* ***************************************************************************** */ -#define DMA6_PTR1 0x100014 /* DMA Current Ptr : Ch#6 */ - -/* ***************************************************************************** */ -#define DMA7_PTR1 0x100018 /* DMA Current Ptr : Ch#7 */ - -/* ***************************************************************************** */ -#define DMA8_PTR1 0x10001C /* DMA Current Ptr : Ch#8 */ - -/* ***************************************************************************** */ -#define DMA9_PTR1 0x100020 /* DMA Current Ptr : Ch#9 */ - -/* ***************************************************************************** */ -#define DMA10_PTR1 0x100024 /* DMA Current Ptr : Ch#10 */ - -/* ***************************************************************************** */ -#define DMA11_PTR1 0x100028 /* DMA Current Ptr : Ch#11 */ - -/* ***************************************************************************** */ -#define DMA12_PTR1 0x10002C /* DMA Current Ptr : Ch#12 */ - -/* ***************************************************************************** */ -#define DMA13_PTR1 0x100030 /* DMA Current Ptr : Ch#13 */ - -/* ***************************************************************************** */ -#define DMA14_PTR1 0x100034 /* DMA Current Ptr : Ch#14 */ - -/* ***************************************************************************** */ -#define DMA15_PTR1 0x100038 /* DMA Current Ptr : Ch#15 */ - -/* ***************************************************************************** */ -#define DMA16_PTR1 0x10003C /* DMA Current Ptr : Ch#16 */ - -/* ***************************************************************************** */ -#define DMA17_PTR1 0x100040 /* DMA Current Ptr : Ch#17 */ - -/* ***************************************************************************** */ -#define DMA18_PTR1 0x100044 /* DMA Current Ptr : Ch#18 */ - -/* ***************************************************************************** */ -#define DMA19_PTR1 0x100048 /* DMA Current Ptr : Ch#19 */ - -/* ***************************************************************************** */ -#define DMA20_PTR1 0x10004C /* DMA Current Ptr : Ch#20 */ - -/* ***************************************************************************** */ -#define DMA21_PTR1 0x100050 /* DMA Current Ptr : Ch#21 */ - -/* ***************************************************************************** */ -#define DMA22_PTR1 0x100054 /* DMA Current Ptr : Ch#22 */ - -/* ***************************************************************************** */ -#define DMA23_PTR1 0x100058 /* DMA Current Ptr : Ch#23 */ - -/* ***************************************************************************** */ -#define DMA24_PTR1 0x10005C /* DMA Current Ptr : Ch#24 */ - -/* ***************************************************************************** */ -#define DMA25_PTR1 0x100060 /* DMA Current Ptr : Ch#25 */ - -/* ***************************************************************************** */ -#define DMA26_PTR1 0x100064 /* DMA Current Ptr : Ch#26 */ - -/* ***************************************************************************** */ -#define DMA1_PTR2 0x100080 /* DMA Tab Ptr : Ch#1 */ - -/* ***************************************************************************** */ -#define DMA2_PTR2 0x100084 /* DMA Tab Ptr : Ch#2 */ - -/* ***************************************************************************** */ -#define DMA3_PTR2 0x100088 /* DMA Tab Ptr : Ch#3 */ - -/* ***************************************************************************** */ -#define DMA4_PTR2 0x10008C /* DMA Tab Ptr : Ch#4 */ - -/* ***************************************************************************** */ -#define DMA5_PTR2 0x100090 /* DMA Tab Ptr : Ch#5 */ - -/* ***************************************************************************** */ -#define DMA6_PTR2 0x100094 /* DMA Tab Ptr : Ch#6 */ - -/* ***************************************************************************** */ -#define DMA7_PTR2 0x100098 /* DMA Tab Ptr : Ch#7 */ - -/* ***************************************************************************** */ -#define DMA8_PTR2 0x10009C /* DMA Tab Ptr : Ch#8 */ - -/* ***************************************************************************** */ -#define DMA9_PTR2 0x1000A0 /* DMA Tab Ptr : Ch#9 */ - -/* ***************************************************************************** */ -#define DMA10_PTR2 0x1000A4 /* DMA Tab Ptr : Ch#10 */ - -/* ***************************************************************************** */ -#define DMA11_PTR2 0x1000A8 /* DMA Tab Ptr : Ch#11 */ - -/* ***************************************************************************** */ -#define DMA12_PTR2 0x1000AC /* DMA Tab Ptr : Ch#12 */ - -/* ***************************************************************************** */ -#define DMA13_PTR2 0x1000B0 /* DMA Tab Ptr : Ch#13 */ - -/* ***************************************************************************** */ -#define DMA14_PTR2 0x1000B4 /* DMA Tab Ptr : Ch#14 */ - -/* ***************************************************************************** */ -#define DMA15_PTR2 0x1000B8 /* DMA Tab Ptr : Ch#15 */ - -/* ***************************************************************************** */ -#define DMA16_PTR2 0x1000BC /* DMA Tab Ptr : Ch#16 */ - -/* ***************************************************************************** */ -#define DMA17_PTR2 0x1000C0 /* DMA Tab Ptr : Ch#17 */ - -/* ***************************************************************************** */ -#define DMA18_PTR2 0x1000C4 /* DMA Tab Ptr : Ch#18 */ - -/* ***************************************************************************** */ -#define DMA19_PTR2 0x1000C8 /* DMA Tab Ptr : Ch#19 */ - -/* ***************************************************************************** */ -#define DMA20_PTR2 0x1000CC /* DMA Tab Ptr : Ch#20 */ - -/* ***************************************************************************** */ -#define DMA21_PTR2 0x1000D0 /* DMA Tab Ptr : Ch#21 */ - -/* ***************************************************************************** */ -#define DMA22_PTR2 0x1000D4 /* DMA Tab Ptr : Ch#22 */ - -/* ***************************************************************************** */ -#define DMA23_PTR2 0x1000D8 /* DMA Tab Ptr : Ch#23 */ - -/* ***************************************************************************** */ -#define DMA24_PTR2 0x1000DC /* DMA Tab Ptr : Ch#24 */ - -/* ***************************************************************************** */ -#define DMA25_PTR2 0x1000E0 /* DMA Tab Ptr : Ch#25 */ - -/* ***************************************************************************** */ -#define DMA26_PTR2 0x1000E4 /* DMA Tab Ptr : Ch#26 */ - -/* ***************************************************************************** */ -#define DMA1_CNT1 0x100100 /* DMA BuFFer Size : Ch#1 */ - -/* ***************************************************************************** */ -#define DMA2_CNT1 0x100104 /* DMA BuFFer Size : Ch#2 */ - -/* ***************************************************************************** */ -#define DMA3_CNT1 0x100108 /* DMA BuFFer Size : Ch#3 */ - -/* ***************************************************************************** */ -#define DMA4_CNT1 0x10010C /* DMA BuFFer Size : Ch#4 */ - -/* ***************************************************************************** */ -#define DMA5_CNT1 0x100110 /* DMA BuFFer Size : Ch#5 */ - -/* ***************************************************************************** */ -#define DMA6_CNT1 0x100114 /* DMA BuFFer Size : Ch#6 */ - -/* ***************************************************************************** */ -#define DMA7_CNT1 0x100118 /* DMA BuFFer Size : Ch#7 */ - -/* ***************************************************************************** */ -#define DMA8_CNT1 0x10011C /* DMA BuFFer Size : Ch#8 */ - -/* ***************************************************************************** */ -#define DMA9_CNT1 0x100120 /* DMA BuFFer Size : Ch#9 */ - -/* ***************************************************************************** */ -#define DMA10_CNT1 0x100124 /* DMA BuFFer Size : Ch#10 */ - -/* ***************************************************************************** */ -#define DMA11_CNT1 0x100128 /* DMA BuFFer Size : Ch#11 */ - -/* ***************************************************************************** */ -#define DMA12_CNT1 0x10012C /* DMA BuFFer Size : Ch#12 */ - -/* ***************************************************************************** */ -#define DMA13_CNT1 0x100130 /* DMA BuFFer Size : Ch#13 */ - -/* ***************************************************************************** */ -#define DMA14_CNT1 0x100134 /* DMA BuFFer Size : Ch#14 */ - -/* ***************************************************************************** */ -#define DMA15_CNT1 0x100138 /* DMA BuFFer Size : Ch#15 */ - -/* ***************************************************************************** */ -#define DMA16_CNT1 0x10013C /* DMA BuFFer Size : Ch#16 */ - -/* ***************************************************************************** */ -#define DMA17_CNT1 0x100140 /* DMA BuFFer Size : Ch#17 */ - -/* ***************************************************************************** */ -#define DMA18_CNT1 0x100144 /* DMA BuFFer Size : Ch#18 */ - -/* ***************************************************************************** */ -#define DMA19_CNT1 0x100148 /* DMA BuFFer Size : Ch#19 */ - -/* ***************************************************************************** */ -#define DMA20_CNT1 0x10014C /* DMA BuFFer Size : Ch#20 */ - -/* ***************************************************************************** */ -#define DMA21_CNT1 0x100150 /* DMA BuFFer Size : Ch#21 */ - -/* ***************************************************************************** */ -#define DMA22_CNT1 0x100154 /* DMA BuFFer Size : Ch#22 */ - -/* ***************************************************************************** */ -#define DMA23_CNT1 0x100158 /* DMA BuFFer Size : Ch#23 */ - -/* ***************************************************************************** */ -#define DMA24_CNT1 0x10015C /* DMA BuFFer Size : Ch#24 */ - -/* ***************************************************************************** */ -#define DMA25_CNT1 0x100160 /* DMA BuFFer Size : Ch#25 */ - -/* ***************************************************************************** */ -#define DMA26_CNT1 0x100164 /* DMA BuFFer Size : Ch#26 */ - -/* ***************************************************************************** */ -#define DMA1_CNT2 0x100180 /* DMA Table Size : Ch#1 */ - -/* ***************************************************************************** */ -#define DMA2_CNT2 0x100184 /* DMA Table Size : Ch#2 */ - -/* ***************************************************************************** */ -#define DMA3_CNT2 0x100188 /* DMA Table Size : Ch#3 */ - -/* ***************************************************************************** */ -#define DMA4_CNT2 0x10018C /* DMA Table Size : Ch#4 */ - -/* ***************************************************************************** */ -#define DMA5_CNT2 0x100190 /* DMA Table Size : Ch#5 */ - -/* ***************************************************************************** */ -#define DMA6_CNT2 0x100194 /* DMA Table Size : Ch#6 */ - -/* ***************************************************************************** */ -#define DMA7_CNT2 0x100198 /* DMA Table Size : Ch#7 */ - -/* ***************************************************************************** */ -#define DMA8_CNT2 0x10019C /* DMA Table Size : Ch#8 */ - -/* ***************************************************************************** */ -#define DMA9_CNT2 0x1001A0 /* DMA Table Size : Ch#9 */ - -/* ***************************************************************************** */ -#define DMA10_CNT2 0x1001A4 /* DMA Table Size : Ch#10 */ - -/* ***************************************************************************** */ -#define DMA11_CNT2 0x1001A8 /* DMA Table Size : Ch#11 */ - -/* ***************************************************************************** */ -#define DMA12_CNT2 0x1001AC /* DMA Table Size : Ch#12 */ - -/* ***************************************************************************** */ -#define DMA13_CNT2 0x1001B0 /* DMA Table Size : Ch#13 */ - -/* ***************************************************************************** */ -#define DMA14_CNT2 0x1001B4 /* DMA Table Size : Ch#14 */ - -/* ***************************************************************************** */ -#define DMA15_CNT2 0x1001B8 /* DMA Table Size : Ch#15 */ - -/* ***************************************************************************** */ -#define DMA16_CNT2 0x1001BC /* DMA Table Size : Ch#16 */ - -/* ***************************************************************************** */ -#define DMA17_CNT2 0x1001C0 /* DMA Table Size : Ch#17 */ - -/* ***************************************************************************** */ -#define DMA18_CNT2 0x1001C4 /* DMA Table Size : Ch#18 */ - -/* ***************************************************************************** */ -#define DMA19_CNT2 0x1001C8 /* DMA Table Size : Ch#19 */ - -/* ***************************************************************************** */ -#define DMA20_CNT2 0x1001CC /* DMA Table Size : Ch#20 */ - -/* ***************************************************************************** */ -#define DMA21_CNT2 0x1001D0 /* DMA Table Size : Ch#21 */ - -/* ***************************************************************************** */ -#define DMA22_CNT2 0x1001D4 /* DMA Table Size : Ch#22 */ - -/* ***************************************************************************** */ -#define DMA23_CNT2 0x1001D8 /* DMA Table Size : Ch#23 */ - -/* ***************************************************************************** */ -#define DMA24_CNT2 0x1001DC /* DMA Table Size : Ch#24 */ - -/* ***************************************************************************** */ -#define DMA25_CNT2 0x1001E0 /* DMA Table Size : Ch#25 */ - -/* ***************************************************************************** */ -#define DMA26_CNT2 0x1001E4 /* DMA Table Size : Ch#26 */ - -/* ***************************************************************************** */ - /* ITG */ -/* ***************************************************************************** */ -#define TM_CNT_LDW 0x110000 /* Timer : Counter low */ - -/* ***************************************************************************** */ -#define TM_CNT_UW 0x110004 /* Timer : Counter high word */ - -/* ***************************************************************************** */ -#define TM_LMT_LDW 0x110008 /* Timer : Limit low */ - -/* ***************************************************************************** */ -#define TM_LMT_UW 0x11000C /* Timer : Limit high word */ - -/* ***************************************************************************** */ -#define GP0_IO 0x110010 /* GPIO output enables data I/O */ -#define FLD_GP_OE 0x00FF0000 /* GPIO: GP_OE output enable */ -#define FLD_GP_IN 0x0000FF00 /* GPIO: GP_IN status */ -#define FLD_GP_OUT 0x000000FF /* GPIO: GP_OUT control */ - -/* ***************************************************************************** */ -#define GPIO_ISM 0x110014 /* GPIO interrupt sensitivity mode */ -#define FLD_GP_ISM_SNS 0x00000070 -#define FLD_GP_ISM_POL 0x00000007 - -/* ***************************************************************************** */ -#define SOFT_RESET 0x11001C /* Output system reset reg */ -#define FLD_PECOS_SOFT_RESET 0x00000001 - -/* ***************************************************************************** */ -#define MC416_RWD 0x110020 /* MC416 GPIO[18:3] pin */ -#define MC416_OEN 0x110024 /* Output enable of GPIO[18:3] */ -#define MC416_CTL 0x110028 - -/* ***************************************************************************** */ -#define ALT_PIN_OUT_SEL 0x11002C /* Alternate GPIO output select */ - -#define FLD_ALT_GPIO_OUT_SEL 0xF0000000 -/* 0 Disabled <-- default */ -/* 1 GPIO[0] */ -/* 2 GPIO[10] */ -/* 3 VIP_656_DATA_VAL */ -/* 4 VIP_656_DATA[0] */ -/* 5 VIP_656_CLK */ -/* 6 VIP_656_DATA_EXT[1] */ -/* 7 VIP_656_DATA_EXT[0] */ -/* 8 ATT_IF */ - -#define FLD_AUX_PLL_CLK_ALT_SEL 0x0F000000 -/* 0 AUX_PLL_CLK<-- default */ -/* 1 GPIO[2] */ -/* 2 GPIO[10] */ -/* 3 VIP_656_DATA_VAL */ -/* 4 VIP_656_DATA[0] */ -/* 5 VIP_656_CLK */ -/* 6 VIP_656_DATA_EXT[1] */ -/* 7 VIP_656_DATA_EXT[0] */ - -#define FLD_IR_TX_ALT_SEL 0x00F00000 -/* 0 IR_TX <-- default */ -/* 1 GPIO[1] */ -/* 2 GPIO[10] */ -/* 3 VIP_656_DATA_VAL */ -/* 4 VIP_656_DATA[0] */ -/* 5 VIP_656_CLK */ -/* 6 VIP_656_DATA_EXT[1] */ -/* 7 VIP_656_DATA_EXT[0] */ - -#define FLD_IR_RX_ALT_SEL 0x000F0000 -/* 0 IR_RX <-- default */ -/* 1 GPIO[0] */ -/* 2 GPIO[10] */ -/* 3 VIP_656_DATA_VAL */ -/* 4 VIP_656_DATA[0] */ -/* 5 VIP_656_CLK */ -/* 6 VIP_656_DATA_EXT[1] */ -/* 7 VIP_656_DATA_EXT[0] */ - -#define FLD_GPIO10_ALT_SEL 0x0000F000 -/* 0 GPIO[10] <-- default */ -/* 1 GPIO[0] */ -/* 2 GPIO[10] */ -/* 3 VIP_656_DATA_VAL */ -/* 4 VIP_656_DATA[0] */ -/* 5 VIP_656_CLK */ -/* 6 VIP_656_DATA_EXT[1] */ -/* 7 VIP_656_DATA_EXT[0] */ - -#define FLD_GPIO2_ALT_SEL 0x00000F00 -/* 0 GPIO[2] <-- default */ -/* 1 GPIO[1] */ -/* 2 GPIO[10] */ -/* 3 VIP_656_DATA_VAL */ -/* 4 VIP_656_DATA[0] */ -/* 5 VIP_656_CLK */ -/* 6 VIP_656_DATA_EXT[1] */ -/* 7 VIP_656_DATA_EXT[0] */ - -#define FLD_GPIO1_ALT_SEL 0x000000F0 -/* 0 GPIO[1] <-- default */ -/* 1 GPIO[0] */ -/* 2 GPIO[10] */ -/* 3 VIP_656_DATA_VAL */ -/* 4 VIP_656_DATA[0] */ -/* 5 VIP_656_CLK */ -/* 6 VIP_656_DATA_EXT[1] */ -/* 7 VIP_656_DATA_EXT[0] */ - -#define FLD_GPIO0_ALT_SEL 0x0000000F -/* 0 GPIO[0] <-- default */ -/* 1 GPIO[1] */ -/* 2 GPIO[10] */ -/* 3 VIP_656_DATA_VAL */ -/* 4 VIP_656_DATA[0] */ -/* 5 VIP_656_CLK */ -/* 6 VIP_656_DATA_EXT[1] */ -/* 7 VIP_656_DATA_EXT[0] */ - -#define ALT_PIN_IN_SEL 0x110030 /* Alternate GPIO input select */ - -#define FLD_GPIO10_ALT_IN_SEL 0x0000F000 -/* 0 GPIO[10] <-- default */ -/* 1 IR_RX */ -/* 2 IR_TX */ -/* 3 AUX_PLL_CLK */ -/* 4 IF_ATT_SEL */ -/* 5 GPIO[0] */ -/* 6 GPIO[1] */ -/* 7 GPIO[2] */ - -#define FLD_GPIO2_ALT_IN_SEL 0x00000F00 -/* 0 GPIO[2] <-- default */ -/* 1 IR_RX */ -/* 2 IR_TX */ -/* 3 AUX_PLL_CLK */ -/* 4 IF_ATT_SEL */ - -#define FLD_GPIO1_ALT_IN_SEL 0x000000F0 -/* 0 GPIO[1] <-- default */ -/* 1 IR_RX */ -/* 2 IR_TX */ -/* 3 AUX_PLL_CLK */ -/* 4 IF_ATT_SEL */ - -#define FLD_GPIO0_ALT_IN_SEL 0x0000000F -/* 0 GPIO[0] <-- default */ -/* 1 IR_RX */ -/* 2 IR_TX */ -/* 3 AUX_PLL_CLK */ -/* 4 IF_ATT_SEL */ - -/* ***************************************************************************** */ -#define TEST_BUS_CTL1 0x110040 /* Test bus control register #1 */ - -/* ***************************************************************************** */ -#define TEST_BUS_CTL2 0x110044 /* Test bus control register #2 */ - -/* ***************************************************************************** */ -#define CLK_DELAY 0x110048 /* Clock delay */ -#define FLD_MOE_CLK_DIS 0x80000000 /* Disable MoE clock */ - -/* ***************************************************************************** */ -#define PAD_CTRL 0x110068 /* Pad drive strength control */ - -/* ***************************************************************************** */ -#define MBIST_CTRL 0x110050 /* SRAM memory built-in self test control */ - -/* ***************************************************************************** */ -#define MBIST_STAT 0x110054 /* SRAM memory built-in self test status */ - -/* ***************************************************************************** */ -/* PLL registers */ -/* ***************************************************************************** */ -#define PLL_A_INT_FRAC 0x110088 -#define PLL_A_POST_STAT_BIST 0x11008C -#define PLL_B_INT_FRAC 0x110090 -#define PLL_B_POST_STAT_BIST 0x110094 -#define PLL_C_INT_FRAC 0x110098 -#define PLL_C_POST_STAT_BIST 0x11009C -#define PLL_D_INT_FRAC 0x1100A0 -#define PLL_D_POST_STAT_BIST 0x1100A4 - -#define CLK_RST 0x11002C -#define FLD_VID_I_CLK_NOE 0x00001000 -#define FLD_VID_J_CLK_NOE 0x00002000 -#define FLD_USE_ALT_PLL_REF 0x00004000 - -#define VID_CH_MODE_SEL 0x110078 -#define VID_CH_CLK_SEL 0x11007C - -/* ***************************************************************************** */ -#define VBI_A_DMA 0x130008 /* VBI A DMA data port */ - -/* ***************************************************************************** */ -#define VID_A_VIP_CTL 0x130080 /* Video A VIP format control */ -#define FLD_VIP_MODE 0x00000001 - -/* ***************************************************************************** */ -#define VID_A_PIXEL_FRMT 0x130084 /* Video A pixel format */ -#define FLD_VID_A_GAMMA_DIS 0x00000008 -#define FLD_VID_A_FORMAT 0x00000007 -#define FLD_VID_A_GAMMA_FACTOR 0x00000010 - -/* ***************************************************************************** */ -#define VID_A_VBI_CTL 0x130088 /* Video A VBI miscellaneous control */ -#define FLD_VID_A_VIP_EXT 0x00000003 - -/* ***************************************************************************** */ -#define VID_B_DMA 0x130100 /* Video B DMA data port */ - -/* ***************************************************************************** */ -#define VBI_B_DMA 0x130108 /* VBI B DMA data port */ - -/* ***************************************************************************** */ -#define VID_B_SRC_SEL 0x130144 /* Video B source select */ -#define FLD_VID_B_SRC_SEL 0x00000000 - -/* ***************************************************************************** */ -#define VID_B_LNGTH 0x130150 /* Video B line length */ -#define FLD_VID_B_LN_LNGTH 0x00000FFF - -/* ***************************************************************************** */ -#define VID_B_VIP_CTL 0x130180 /* Video B VIP format control */ - -/* ***************************************************************************** */ -#define VID_B_PIXEL_FRMT 0x130184 /* Video B pixel format */ -#define FLD_VID_B_GAMMA_DIS 0x00000008 -#define FLD_VID_B_FORMAT 0x00000007 -#define FLD_VID_B_GAMMA_FACTOR 0x00000010 - -/* ***************************************************************************** */ -#define VID_C_DMA 0x130200 /* Video C DMA data port */ - -/* ***************************************************************************** */ -#define VID_C_LNGTH 0x130250 /* Video C line length */ -#define FLD_VID_C_LN_LNGTH 0x00000FFF - -/* ***************************************************************************** */ -/* Video Destination Channels */ -/* ***************************************************************************** */ - -#define VID_DST_A_GPCNT 0x130020 /* Video A general purpose counter */ -#define VID_DST_B_GPCNT 0x130120 /* Video B general purpose counter */ -#define VID_DST_C_GPCNT 0x130220 /* Video C general purpose counter */ -#define VID_DST_D_GPCNT 0x130320 /* Video D general purpose counter */ -#define VID_DST_E_GPCNT 0x130420 /* Video E general purpose counter */ -#define VID_DST_F_GPCNT 0x130520 /* Video F general purpose counter */ -#define VID_DST_G_GPCNT 0x130620 /* Video G general purpose counter */ -#define VID_DST_H_GPCNT 0x130720 /* Video H general purpose counter */ - -/* ***************************************************************************** */ - -#define VID_DST_A_GPCNT_CTL 0x130030 /* Video A general purpose control */ -#define VID_DST_B_GPCNT_CTL 0x130130 /* Video B general purpose control */ -#define VID_DST_C_GPCNT_CTL 0x130230 /* Video C general purpose control */ -#define VID_DST_D_GPCNT_CTL 0x130330 /* Video D general purpose control */ -#define VID_DST_E_GPCNT_CTL 0x130430 /* Video E general purpose control */ -#define VID_DST_F_GPCNT_CTL 0x130530 /* Video F general purpose control */ -#define VID_DST_G_GPCNT_CTL 0x130630 /* Video G general purpose control */ -#define VID_DST_H_GPCNT_CTL 0x130730 /* Video H general purpose control */ - -/* ***************************************************************************** */ - -#define VID_DST_A_DMA_CTL 0x130040 /* Video A DMA control */ -#define VID_DST_B_DMA_CTL 0x130140 /* Video B DMA control */ -#define VID_DST_C_DMA_CTL 0x130240 /* Video C DMA control */ -#define VID_DST_D_DMA_CTL 0x130340 /* Video D DMA control */ -#define VID_DST_E_DMA_CTL 0x130440 /* Video E DMA control */ -#define VID_DST_F_DMA_CTL 0x130540 /* Video F DMA control */ -#define VID_DST_G_DMA_CTL 0x130640 /* Video G DMA control */ -#define VID_DST_H_DMA_CTL 0x130740 /* Video H DMA control */ - -#define FLD_VID_RISC_EN 0x00000010 -#define FLD_VID_FIFO_EN 0x00000001 - -/* ***************************************************************************** */ - -#define VID_DST_A_VIP_CTL 0x130080 /* Video A VIP control */ -#define VID_DST_B_VIP_CTL 0x130180 /* Video B VIP control */ -#define VID_DST_C_VIP_CTL 0x130280 /* Video C VIP control */ -#define VID_DST_D_VIP_CTL 0x130380 /* Video D VIP control */ -#define VID_DST_E_VIP_CTL 0x130480 /* Video E VIP control */ -#define VID_DST_F_VIP_CTL 0x130580 /* Video F VIP control */ -#define VID_DST_G_VIP_CTL 0x130680 /* Video G VIP control */ -#define VID_DST_H_VIP_CTL 0x130780 /* Video H VIP control */ - -/* ***************************************************************************** */ - -#define VID_DST_A_PIX_FRMT 0x130084 /* Video A Pixel format */ -#define VID_DST_B_PIX_FRMT 0x130184 /* Video B Pixel format */ -#define VID_DST_C_PIX_FRMT 0x130284 /* Video C Pixel format */ -#define VID_DST_D_PIX_FRMT 0x130384 /* Video D Pixel format */ -#define VID_DST_E_PIX_FRMT 0x130484 /* Video E Pixel format */ -#define VID_DST_F_PIX_FRMT 0x130584 /* Video F Pixel format */ -#define VID_DST_G_PIX_FRMT 0x130684 /* Video G Pixel format */ -#define VID_DST_H_PIX_FRMT 0x130784 /* Video H Pixel format */ - -/* ***************************************************************************** */ -/* Video Source Channels */ -/* ***************************************************************************** */ - -#define VID_SRC_A_GPCNT_CTL 0x130804 /* Video A general purpose control */ -#define VID_SRC_B_GPCNT_CTL 0x130904 /* Video B general purpose control */ -#define VID_SRC_C_GPCNT_CTL 0x130A04 /* Video C general purpose control */ -#define VID_SRC_D_GPCNT_CTL 0x130B04 /* Video D general purpose control */ -#define VID_SRC_E_GPCNT_CTL 0x130C04 /* Video E general purpose control */ -#define VID_SRC_F_GPCNT_CTL 0x130D04 /* Video F general purpose control */ -#define VID_SRC_I_GPCNT_CTL 0x130E04 /* Video I general purpose control */ -#define VID_SRC_J_GPCNT_CTL 0x130F04 /* Video J general purpose control */ - -/* ***************************************************************************** */ - -#define VID_SRC_A_GPCNT 0x130808 /* Video A general purpose counter */ -#define VID_SRC_B_GPCNT 0x130908 /* Video B general purpose counter */ -#define VID_SRC_C_GPCNT 0x130A08 /* Video C general purpose counter */ -#define VID_SRC_D_GPCNT 0x130B08 /* Video D general purpose counter */ -#define VID_SRC_E_GPCNT 0x130C08 /* Video E general purpose counter */ -#define VID_SRC_F_GPCNT 0x130D08 /* Video F general purpose counter */ -#define VID_SRC_I_GPCNT 0x130E08 /* Video I general purpose counter */ -#define VID_SRC_J_GPCNT 0x130F08 /* Video J general purpose counter */ - -/* ***************************************************************************** */ - -#define VID_SRC_A_DMA_CTL 0x13080C /* Video A DMA control */ -#define VID_SRC_B_DMA_CTL 0x13090C /* Video B DMA control */ -#define VID_SRC_C_DMA_CTL 0x130A0C /* Video C DMA control */ -#define VID_SRC_D_DMA_CTL 0x130B0C /* Video D DMA control */ -#define VID_SRC_E_DMA_CTL 0x130C0C /* Video E DMA control */ -#define VID_SRC_F_DMA_CTL 0x130D0C /* Video F DMA control */ -#define VID_SRC_I_DMA_CTL 0x130E0C /* Video I DMA control */ -#define VID_SRC_J_DMA_CTL 0x130F0C /* Video J DMA control */ - -#define FLD_APB_RISC_EN 0x00000010 -#define FLD_APB_FIFO_EN 0x00000001 - -/* ***************************************************************************** */ - -#define VID_SRC_A_FMT_CTL 0x130810 /* Video A format control */ -#define VID_SRC_B_FMT_CTL 0x130910 /* Video B format control */ -#define VID_SRC_C_FMT_CTL 0x130A10 /* Video C format control */ -#define VID_SRC_D_FMT_CTL 0x130B10 /* Video D format control */ -#define VID_SRC_E_FMT_CTL 0x130C10 /* Video E format control */ -#define VID_SRC_F_FMT_CTL 0x130D10 /* Video F format control */ -#define VID_SRC_I_FMT_CTL 0x130E10 /* Video I format control */ -#define VID_SRC_J_FMT_CTL 0x130F10 /* Video J format control */ - -/* ***************************************************************************** */ - -#define VID_SRC_A_ACTIVE_CTL1 0x130814 /* Video A active control 1 */ -#define VID_SRC_B_ACTIVE_CTL1 0x130914 /* Video B active control 1 */ -#define VID_SRC_C_ACTIVE_CTL1 0x130A14 /* Video C active control 1 */ -#define VID_SRC_D_ACTIVE_CTL1 0x130B14 /* Video D active control 1 */ -#define VID_SRC_E_ACTIVE_CTL1 0x130C14 /* Video E active control 1 */ -#define VID_SRC_F_ACTIVE_CTL1 0x130D14 /* Video F active control 1 */ -#define VID_SRC_I_ACTIVE_CTL1 0x130E14 /* Video I active control 1 */ -#define VID_SRC_J_ACTIVE_CTL1 0x130F14 /* Video J active control 1 */ - -/* ***************************************************************************** */ - -#define VID_SRC_A_ACTIVE_CTL2 0x130818 /* Video A active control 2 */ -#define VID_SRC_B_ACTIVE_CTL2 0x130918 /* Video B active control 2 */ -#define VID_SRC_C_ACTIVE_CTL2 0x130A18 /* Video C active control 2 */ -#define VID_SRC_D_ACTIVE_CTL2 0x130B18 /* Video D active control 2 */ -#define VID_SRC_E_ACTIVE_CTL2 0x130C18 /* Video E active control 2 */ -#define VID_SRC_F_ACTIVE_CTL2 0x130D18 /* Video F active control 2 */ -#define VID_SRC_I_ACTIVE_CTL2 0x130E18 /* Video I active control 2 */ -#define VID_SRC_J_ACTIVE_CTL2 0x130F18 /* Video J active control 2 */ - -/* ***************************************************************************** */ - -#define VID_SRC_A_CDT_SZ 0x13081C /* Video A CDT size */ -#define VID_SRC_B_CDT_SZ 0x13091C /* Video B CDT size */ -#define VID_SRC_C_CDT_SZ 0x130A1C /* Video C CDT size */ -#define VID_SRC_D_CDT_SZ 0x130B1C /* Video D CDT size */ -#define VID_SRC_E_CDT_SZ 0x130C1C /* Video E CDT size */ -#define VID_SRC_F_CDT_SZ 0x130D1C /* Video F CDT size */ -#define VID_SRC_I_CDT_SZ 0x130E1C /* Video I CDT size */ -#define VID_SRC_J_CDT_SZ 0x130F1C /* Video J CDT size */ - -/* ***************************************************************************** */ -/* Audio I/F */ -/* ***************************************************************************** */ -#define AUD_DST_A_DMA 0x140000 /* Audio Int A DMA data port */ -#define AUD_SRC_A_DMA 0x140008 /* Audio Int A DMA data port */ - -#define AUD_A_GPCNT 0x140010 /* Audio Int A gp counter */ -#define FLD_AUD_A_GP_CNT 0x0000FFFF - -#define AUD_A_GPCNT_CTL 0x140014 /* Audio Int A gp control */ - -#define AUD_A_LNGTH 0x140018 /* Audio Int A line length */ - -#define AUD_A_CFG 0x14001C /* Audio Int A configuration */ - -/* ***************************************************************************** */ -#define AUD_DST_B_DMA 0x140100 /* Audio Int B DMA data port */ -#define AUD_SRC_B_DMA 0x140108 /* Audio Int B DMA data port */ - -#define AUD_B_GPCNT 0x140110 /* Audio Int B gp counter */ -#define FLD_AUD_B_GP_CNT 0x0000FFFF - -#define AUD_B_GPCNT_CTL 0x140114 /* Audio Int B gp control */ - -#define AUD_B_LNGTH 0x140118 /* Audio Int B line length */ - -#define AUD_B_CFG 0x14011C /* Audio Int B configuration */ - -/* ***************************************************************************** */ -#define AUD_DST_C_DMA 0x140200 /* Audio Int C DMA data port */ -#define AUD_SRC_C_DMA 0x140208 /* Audio Int C DMA data port */ - -#define AUD_C_GPCNT 0x140210 /* Audio Int C gp counter */ -#define FLD_AUD_C_GP_CNT 0x0000FFFF - -#define AUD_C_GPCNT_CTL 0x140214 /* Audio Int C gp control */ - -#define AUD_C_LNGTH 0x140218 /* Audio Int C line length */ - -#define AUD_C_CFG 0x14021C /* Audio Int C configuration */ - -/* ***************************************************************************** */ -#define AUD_DST_D_DMA 0x140300 /* Audio Int D DMA data port */ -#define AUD_SRC_D_DMA 0x140308 /* Audio Int D DMA data port */ - -#define AUD_D_GPCNT 0x140310 /* Audio Int D gp counter */ -#define FLD_AUD_D_GP_CNT 0x0000FFFF - -#define AUD_D_GPCNT_CTL 0x140314 /* Audio Int D gp control */ - -#define AUD_D_LNGTH 0x140318 /* Audio Int D line length */ - -#define AUD_D_CFG 0x14031C /* Audio Int D configuration */ - -/* ***************************************************************************** */ -#define AUD_SRC_E_DMA 0x140400 /* Audio Int E DMA data port */ - -#define AUD_E_GPCNT 0x140410 /* Audio Int E gp counter */ -#define FLD_AUD_E_GP_CNT 0x0000FFFF - -#define AUD_E_GPCNT_CTL 0x140414 /* Audio Int E gp control */ - -#define AUD_E_CFG 0x14041C /* Audio Int E configuration */ - -/* ***************************************************************************** */ - -#define FLD_AUD_DST_LN_LNGTH 0x00000FFF - -#define FLD_AUD_DST_PK_MODE 0x00004000 - -#define FLD_AUD_CLK_ENABLE 0x00000200 - -#define FLD_AUD_MASTER_MODE 0x00000002 - -#define FLD_AUD_SONY_MODE 0x00000001 - -#define FLD_AUD_CLK_SELECT_PLL_D 0x00001800 - -#define FLD_AUD_DST_ENABLE 0x00020000 - -#define FLD_AUD_SRC_ENABLE 0x00010000 - -/* ***************************************************************************** */ -#define AUD_INT_DMA_CTL 0x140500 /* Audio Int DMA control */ - -#define FLD_AUD_SRC_E_RISC_EN 0x00008000 -#define FLD_AUD_SRC_C_RISC_EN 0x00004000 -#define FLD_AUD_SRC_B_RISC_EN 0x00002000 -#define FLD_AUD_SRC_A_RISC_EN 0x00001000 - -#define FLD_AUD_DST_D_RISC_EN 0x00000800 -#define FLD_AUD_DST_C_RISC_EN 0x00000400 -#define FLD_AUD_DST_B_RISC_EN 0x00000200 -#define FLD_AUD_DST_A_RISC_EN 0x00000100 - -#define FLD_AUD_SRC_E_FIFO_EN 0x00000080 -#define FLD_AUD_SRC_C_FIFO_EN 0x00000040 -#define FLD_AUD_SRC_B_FIFO_EN 0x00000020 -#define FLD_AUD_SRC_A_FIFO_EN 0x00000010 - -#define FLD_AUD_DST_D_FIFO_EN 0x00000008 -#define FLD_AUD_DST_C_FIFO_EN 0x00000004 -#define FLD_AUD_DST_B_FIFO_EN 0x00000002 -#define FLD_AUD_DST_A_FIFO_EN 0x00000001 - -/* ***************************************************************************** */ -/* */ -/* Mobilygen Interface Registers */ -/* */ -/* ***************************************************************************** */ -/* Mobilygen Interface A */ -/* ***************************************************************************** */ -#define MB_IF_A_DMA 0x150000 /* MBIF A DMA data port */ -#define MB_IF_A_GPCN 0x150008 /* MBIF A GP counter */ -#define MB_IF_A_GPCN_CTRL 0x15000C -#define MB_IF_A_DMA_CTRL 0x150010 -#define MB_IF_A_LENGTH 0x150014 -#define MB_IF_A_HDMA_XFER_SZ 0x150018 -#define MB_IF_A_HCMD 0x15001C -#define MB_IF_A_HCONFIG 0x150020 -#define MB_IF_A_DATA_STRUCT_0 0x150024 -#define MB_IF_A_DATA_STRUCT_1 0x150028 -#define MB_IF_A_DATA_STRUCT_2 0x15002C -#define MB_IF_A_DATA_STRUCT_3 0x150030 -#define MB_IF_A_DATA_STRUCT_4 0x150034 -#define MB_IF_A_DATA_STRUCT_5 0x150038 -#define MB_IF_A_DATA_STRUCT_6 0x15003C -#define MB_IF_A_DATA_STRUCT_7 0x150040 -#define MB_IF_A_DATA_STRUCT_8 0x150044 -#define MB_IF_A_DATA_STRUCT_9 0x150048 -#define MB_IF_A_DATA_STRUCT_A 0x15004C -#define MB_IF_A_DATA_STRUCT_B 0x150050 -#define MB_IF_A_DATA_STRUCT_C 0x150054 -#define MB_IF_A_DATA_STRUCT_D 0x150058 -#define MB_IF_A_DATA_STRUCT_E 0x15005C -#define MB_IF_A_DATA_STRUCT_F 0x150060 -/* ***************************************************************************** */ -/* Mobilygen Interface B */ -/* ***************************************************************************** */ -#define MB_IF_B_DMA 0x160000 /* MBIF A DMA data port */ -#define MB_IF_B_GPCN 0x160008 /* MBIF A GP counter */ -#define MB_IF_B_GPCN_CTRL 0x16000C -#define MB_IF_B_DMA_CTRL 0x160010 -#define MB_IF_B_LENGTH 0x160014 -#define MB_IF_B_HDMA_XFER_SZ 0x160018 -#define MB_IF_B_HCMD 0x16001C -#define MB_IF_B_HCONFIG 0x160020 -#define MB_IF_B_DATA_STRUCT_0 0x160024 -#define MB_IF_B_DATA_STRUCT_1 0x160028 -#define MB_IF_B_DATA_STRUCT_2 0x16002C -#define MB_IF_B_DATA_STRUCT_3 0x160030 -#define MB_IF_B_DATA_STRUCT_4 0x160034 -#define MB_IF_B_DATA_STRUCT_5 0x160038 -#define MB_IF_B_DATA_STRUCT_6 0x16003C -#define MB_IF_B_DATA_STRUCT_7 0x160040 -#define MB_IF_B_DATA_STRUCT_8 0x160044 -#define MB_IF_B_DATA_STRUCT_9 0x160048 -#define MB_IF_B_DATA_STRUCT_A 0x16004C -#define MB_IF_B_DATA_STRUCT_B 0x160050 -#define MB_IF_B_DATA_STRUCT_C 0x160054 -#define MB_IF_B_DATA_STRUCT_D 0x160058 -#define MB_IF_B_DATA_STRUCT_E 0x16005C -#define MB_IF_B_DATA_STRUCT_F 0x160060 - -/* MB_DMA_CTRL */ -#define FLD_MB_IF_RISC_EN 0x00000010 -#define FLD_MB_IF_FIFO_EN 0x00000001 - -/* MB_LENGTH */ -#define FLD_MB_IF_LN_LNGTH 0x00000FFF - -/* MB_HCMD register */ -#define FLD_MB_HCMD_H_GO 0x80000000 -#define FLD_MB_HCMD_H_BUSY 0x40000000 -#define FLD_MB_HCMD_H_DMA_HOLD 0x10000000 -#define FLD_MB_HCMD_H_DMA_BUSY 0x08000000 -#define FLD_MB_HCMD_H_DMA_TYPE 0x04000000 -#define FLD_MB_HCMD_H_DMA_XACT 0x02000000 -#define FLD_MB_HCMD_H_RW_N 0x01000000 -#define FLD_MB_HCMD_H_ADDR 0x00FF0000 -#define FLD_MB_HCMD_H_DATA 0x0000FFFF - -/* ***************************************************************************** */ -/* I2C #1 */ -/* ***************************************************************************** */ -#define I2C1_ADDR 0x180000 /* I2C #1 address */ -#define FLD_I2C_DADDR 0xfe000000 /* RW [31:25] I2C Device Address */ - /* RO [24] reserved */ -/* ***************************************************************************** */ -#define FLD_I2C_SADDR 0x00FFFFFF /* RW [23:0] I2C Sub-address */ - -/* ***************************************************************************** */ -#define I2C1_WDATA 0x180004 /* I2C #1 write data */ -#define FLD_I2C_WDATA 0xFFFFFFFF /* RW [31:0] */ - -/* ***************************************************************************** */ -#define I2C1_CTRL 0x180008 /* I2C #1 control */ -#define FLD_I2C_PERIOD 0xFF000000 /* RW [31:24] */ -#define FLD_I2C_SCL_IN 0x00200000 /* RW [21] */ -#define FLD_I2C_SDA_IN 0x00100000 /* RW [20] */ - /* RO [19:18] reserved */ -#define FLD_I2C_SCL_OUT 0x00020000 /* RW [17] */ -#define FLD_I2C_SDA_OUT 0x00010000 /* RW [16] */ - /* RO [15] reserved */ -#define FLD_I2C_DATA_LEN 0x00007000 /* RW [14:12] */ -#define FLD_I2C_SADDR_INC 0x00000800 /* RW [11] */ - /* RO [10:9] reserved */ -#define FLD_I2C_SADDR_LEN 0x00000300 /* RW [9:8] */ - /* RO [7:6] reserved */ -#define FLD_I2C_SOFT 0x00000020 /* RW [5] */ -#define FLD_I2C_NOSTOP 0x00000010 /* RW [4] */ -#define FLD_I2C_EXTEND 0x00000008 /* RW [3] */ -#define FLD_I2C_SYNC 0x00000004 /* RW [2] */ -#define FLD_I2C_READ_SA 0x00000002 /* RW [1] */ -#define FLD_I2C_READ_WRN 0x00000001 /* RW [0] */ - -/* ***************************************************************************** */ -#define I2C1_RDATA 0x18000C /* I2C #1 read data */ -#define FLD_I2C_RDATA 0xFFFFFFFF /* RO [31:0] */ - -/* ***************************************************************************** */ -#define I2C1_STAT 0x180010 /* I2C #1 status */ -#define FLD_I2C_XFER_IN_PROG 0x00000002 /* RO [1] */ -#define FLD_I2C_RACK 0x00000001 /* RO [0] */ - -/* ***************************************************************************** */ -/* I2C #2 */ -/* ***************************************************************************** */ -#define I2C2_ADDR 0x190000 /* I2C #2 address */ - -/* ***************************************************************************** */ -#define I2C2_WDATA 0x190004 /* I2C #2 write data */ - -/* ***************************************************************************** */ -#define I2C2_CTRL 0x190008 /* I2C #2 control */ - -/* ***************************************************************************** */ -#define I2C2_RDATA 0x19000C /* I2C #2 read data */ - -/* ***************************************************************************** */ -#define I2C2_STAT 0x190010 /* I2C #2 status */ - -/* ***************************************************************************** */ -/* I2C #3 */ -/* ***************************************************************************** */ -#define I2C3_ADDR 0x1A0000 /* I2C #3 address */ - -/* ***************************************************************************** */ -#define I2C3_WDATA 0x1A0004 /* I2C #3 write data */ - -/* ***************************************************************************** */ -#define I2C3_CTRL 0x1A0008 /* I2C #3 control */ - -/* ***************************************************************************** */ -#define I2C3_RDATA 0x1A000C /* I2C #3 read data */ - -/* ***************************************************************************** */ -#define I2C3_STAT 0x1A0010 /* I2C #3 status */ - -/* ***************************************************************************** */ -/* UART */ -/* ***************************************************************************** */ -#define UART_CTL 0x1B0000 /* UART Control Register */ -#define FLD_LOOP_BACK_EN (1 << 7) /* RW field - default 0 */ -#define FLD_RX_TRG_SZ (3 << 2) /* RW field - default 0 */ -#define FLD_RX_EN (1 << 1) /* RW field - default 0 */ -#define FLD_TX_EN (1 << 0) /* RW field - default 0 */ - -/* ***************************************************************************** */ -#define UART_BRD 0x1B0004 /* UART Baud Rate Divisor */ -#define FLD_BRD 0x0000FFFF /* RW field - default 0x197 */ - -/* ***************************************************************************** */ -#define UART_DBUF 0x1B0008 /* UART Tx/Rx Data BuFFer */ -#define FLD_DB 0xFFFFFFFF /* RW field - default 0 */ - -/* ***************************************************************************** */ -#define UART_ISR 0x1B000C /* UART Interrupt Status */ -#define FLD_RXD_TIMEOUT_EN (1 << 7) /* RW field - default 0 */ -#define FLD_FRM_ERR_EN (1 << 6) /* RW field - default 0 */ -#define FLD_RXD_RDY_EN (1 << 5) /* RW field - default 0 */ -#define FLD_TXD_EMPTY_EN (1 << 4) /* RW field - default 0 */ -#define FLD_RXD_OVERFLOW (1 << 3) /* RW field - default 0 */ -#define FLD_FRM_ERR (1 << 2) /* RW field - default 0 */ -#define FLD_RXD_RDY (1 << 1) /* RW field - default 0 */ -#define FLD_TXD_EMPTY (1 << 0) /* RW field - default 0 */ - -/* ***************************************************************************** */ -#define UART_CNT 0x1B0010 /* UART Tx/Rx FIFO Byte Count */ -#define FLD_TXD_CNT (0x1F << 8) /* RW field - default 0 */ -#define FLD_RXD_CNT (0x1F << 0) /* RW field - default 0 */ - -/* ***************************************************************************** */ -/* Motion Detection */ -#define MD_CH0_GRID_BLOCK_YCNT 0x170014 -#define MD_CH1_GRID_BLOCK_YCNT 0x170094 -#define MD_CH2_GRID_BLOCK_YCNT 0x170114 -#define MD_CH3_GRID_BLOCK_YCNT 0x170194 -#define MD_CH4_GRID_BLOCK_YCNT 0x170214 -#define MD_CH5_GRID_BLOCK_YCNT 0x170294 -#define MD_CH6_GRID_BLOCK_YCNT 0x170314 -#define MD_CH7_GRID_BLOCK_YCNT 0x170394 - -#define PIXEL_FRMT_422 4 -#define PIXEL_FRMT_411 5 -#define PIXEL_FRMT_Y8 6 - -#define PIXEL_ENGINE_VIP1 0 -#define PIXEL_ENGINE_VIP2 1 - -#endif /* Athena_REGISTERS */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-sram.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-sram.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-sram.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-sram.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,261 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ATHENA_SRAM_H__ -#define __ATHENA_SRAM_H__ - -/* #define RX_SRAM_START_SIZE = 0; // Start of reserved SRAM */ -#define VID_CMDS_SIZE 80 /* Video CMDS size in bytes */ -#define AUDIO_CMDS_SIZE 80 /* AUDIO CMDS size in bytes */ -#define MBIF_CMDS_SIZE 80 /* MBIF CMDS size in bytes */ - -/* #define RX_SRAM_POOL_START_SIZE = 0; // Start of useable RX SRAM for buffers */ -#define VID_IQ_SIZE 64 /* VID instruction queue size in bytes */ -#define MBIF_IQ_SIZE 64 -#define AUDIO_IQ_SIZE 64 /* AUD instruction queue size in bytes */ - -#define VID_CDT_SIZE 64 /* VID cluster descriptor table size in bytes */ -#define MBIF_CDT_SIZE 64 /* MBIF/HBI cluster descriptor table size in bytes */ -#define AUDIO_CDT_SIZE 48 /* AUD cluster descriptor table size in bytes */ - -/* #define RX_SRAM_POOL_FREE_SIZE = 16; // Start of available RX SRAM */ -/* #define RX_SRAM_END_SIZE = 0; // End of RX SRAM */ - -/* #define TX_SRAM_POOL_START_SIZE = 0; // Start of transmit pool SRAM */ -/* #define MSI_DATA_SIZE = 64; // Reserved (MSI Data, RISC working stora */ - -#define VID_CLUSTER_SIZE 1440 /* VID cluster data line */ -#define AUDIO_CLUSTER_SIZE 128 /* AUDIO cluster data line */ -#define MBIF_CLUSTER_SIZE 1440 /* MBIF/HBI cluster data line */ - -/* #define TX_SRAM_POOL_FREE_SIZE = 704; // Start of available TX SRAM */ -/* #define TX_SRAM_END_SIZE = 0; // End of TX SRAM */ - -/* Receive SRAM */ -#define RX_SRAM_START 0x10000 -#define VID_A_DOWN_CMDS 0x10000 -#define VID_B_DOWN_CMDS 0x10050 -#define VID_C_DOWN_CMDS 0x100A0 -#define VID_D_DOWN_CMDS 0x100F0 -#define VID_E_DOWN_CMDS 0x10140 -#define VID_F_DOWN_CMDS 0x10190 -#define VID_G_DOWN_CMDS 0x101E0 -#define VID_H_DOWN_CMDS 0x10230 -#define VID_A_UP_CMDS 0x10280 -#define VID_B_UP_CMDS 0x102D0 -#define VID_C_UP_CMDS 0x10320 -#define VID_D_UP_CMDS 0x10370 -#define VID_E_UP_CMDS 0x103C0 -#define VID_F_UP_CMDS 0x10410 -#define VID_I_UP_CMDS 0x10460 -#define VID_J_UP_CMDS 0x104B0 -#define AUD_A_DOWN_CMDS 0x10500 -#define AUD_B_DOWN_CMDS 0x10550 -#define AUD_C_DOWN_CMDS 0x105A0 -#define AUD_D_DOWN_CMDS 0x105F0 -#define AUD_A_UP_CMDS 0x10640 -#define AUD_B_UP_CMDS 0x10690 -#define AUD_C_UP_CMDS 0x106E0 -#define AUD_E_UP_CMDS 0x10730 -#define MBIF_A_DOWN_CMDS 0x10780 -#define MBIF_B_DOWN_CMDS 0x107D0 -#define DMA_SCRATCH_PAD 0x10820 /* Scratch pad area from 0x10820 to 0x10B40 */ - -/* #define RX_SRAM_POOL_START = 0x105B0; */ - -#define VID_A_IQ 0x11000 -#define VID_B_IQ 0x11040 -#define VID_C_IQ 0x11080 -#define VID_D_IQ 0x110C0 -#define VID_E_IQ 0x11100 -#define VID_F_IQ 0x11140 -#define VID_G_IQ 0x11180 -#define VID_H_IQ 0x111C0 -#define VID_I_IQ 0x11200 -#define VID_J_IQ 0x11240 -#define AUD_A_IQ 0x11280 -#define AUD_B_IQ 0x112C0 -#define AUD_C_IQ 0x11300 -#define AUD_D_IQ 0x11340 -#define AUD_E_IQ 0x11380 -#define MBIF_A_IQ 0x11000 -#define MBIF_B_IQ 0x110C0 - -#define VID_A_CDT 0x10C00 -#define VID_B_CDT 0x10C40 -#define VID_C_CDT 0x10C80 -#define VID_D_CDT 0x10CC0 -#define VID_E_CDT 0x10D00 -#define VID_F_CDT 0x10D40 -#define VID_G_CDT 0x10D80 -#define VID_H_CDT 0x10DC0 -#define VID_I_CDT 0x10E00 -#define VID_J_CDT 0x10E40 -#define AUD_A_CDT 0x10E80 -#define AUD_B_CDT 0x10EB0 -#define AUD_C_CDT 0x10EE0 -#define AUD_D_CDT 0x10F10 -#define AUD_E_CDT 0x10F40 -#define MBIF_A_CDT 0x10C00 -#define MBIF_B_CDT 0x10CC0 - -/* Cluster Buffer for RX */ -#define VID_A_UP_CLUSTER_1 0x11400 -#define VID_A_UP_CLUSTER_2 0x119A0 -#define VID_A_UP_CLUSTER_3 0x11F40 -#define VID_A_UP_CLUSTER_4 0x124E0 - -#define VID_B_UP_CLUSTER_1 0x12A80 -#define VID_B_UP_CLUSTER_2 0x13020 -#define VID_B_UP_CLUSTER_3 0x135C0 -#define VID_B_UP_CLUSTER_4 0x13B60 - -#define VID_C_UP_CLUSTER_1 0x14100 -#define VID_C_UP_CLUSTER_2 0x146A0 -#define VID_C_UP_CLUSTER_3 0x14C40 -#define VID_C_UP_CLUSTER_4 0x151E0 - -#define VID_D_UP_CLUSTER_1 0x15780 -#define VID_D_UP_CLUSTER_2 0x15D20 -#define VID_D_UP_CLUSTER_3 0x162C0 -#define VID_D_UP_CLUSTER_4 0x16860 - -#define VID_E_UP_CLUSTER_1 0x16E00 -#define VID_E_UP_CLUSTER_2 0x173A0 -#define VID_E_UP_CLUSTER_3 0x17940 -#define VID_E_UP_CLUSTER_4 0x17EE0 - -#define VID_F_UP_CLUSTER_1 0x18480 -#define VID_F_UP_CLUSTER_2 0x18A20 -#define VID_F_UP_CLUSTER_3 0x18FC0 -#define VID_F_UP_CLUSTER_4 0x19560 - -#define VID_I_UP_CLUSTER_1 0x19B00 -#define VID_I_UP_CLUSTER_2 0x1A0A0 -#define VID_I_UP_CLUSTER_3 0x1A640 -#define VID_I_UP_CLUSTER_4 0x1ABE0 - -#define VID_J_UP_CLUSTER_1 0x1B180 -#define VID_J_UP_CLUSTER_2 0x1B720 -#define VID_J_UP_CLUSTER_3 0x1BCC0 -#define VID_J_UP_CLUSTER_4 0x1C260 - -#define AUD_A_UP_CLUSTER_1 0x1C800 -#define AUD_A_UP_CLUSTER_2 0x1C880 -#define AUD_A_UP_CLUSTER_3 0x1C900 - -#define AUD_B_UP_CLUSTER_1 0x1C980 -#define AUD_B_UP_CLUSTER_2 0x1CA00 -#define AUD_B_UP_CLUSTER_3 0x1CA80 - -#define AUD_C_UP_CLUSTER_1 0x1CB00 -#define AUD_C_UP_CLUSTER_2 0x1CB80 -#define AUD_C_UP_CLUSTER_3 0x1CC00 - -#define AUD_E_UP_CLUSTER_1 0x1CC80 -#define AUD_E_UP_CLUSTER_2 0x1CD00 -#define AUD_E_UP_CLUSTER_3 0x1CD80 - -#define RX_SRAM_POOL_FREE 0x1CE00 -#define RX_SRAM_END 0x1D000 - -/* Free Receive SRAM 144 Bytes */ - -/* Transmit SRAM */ -#define TX_SRAM_POOL_START 0x00000 - -#define VID_A_DOWN_CLUSTER_1 0x00040 -#define VID_A_DOWN_CLUSTER_2 0x005E0 -#define VID_A_DOWN_CLUSTER_3 0x00B80 -#define VID_A_DOWN_CLUSTER_4 0x01120 - -#define VID_B_DOWN_CLUSTER_1 0x016C0 -#define VID_B_DOWN_CLUSTER_2 0x01C60 -#define VID_B_DOWN_CLUSTER_3 0x02200 -#define VID_B_DOWN_CLUSTER_4 0x027A0 - -#define VID_C_DOWN_CLUSTER_1 0x02D40 -#define VID_C_DOWN_CLUSTER_2 0x032E0 -#define VID_C_DOWN_CLUSTER_3 0x03880 -#define VID_C_DOWN_CLUSTER_4 0x03E20 - -#define VID_D_DOWN_CLUSTER_1 0x043C0 -#define VID_D_DOWN_CLUSTER_2 0x04960 -#define VID_D_DOWN_CLUSTER_3 0x04F00 -#define VID_D_DOWN_CLUSTER_4 0x054A0 - -#define VID_E_DOWN_CLUSTER_1 0x05a40 -#define VID_E_DOWN_CLUSTER_2 0x05FE0 -#define VID_E_DOWN_CLUSTER_3 0x06580 -#define VID_E_DOWN_CLUSTER_4 0x06B20 - -#define VID_F_DOWN_CLUSTER_1 0x070C0 -#define VID_F_DOWN_CLUSTER_2 0x07660 -#define VID_F_DOWN_CLUSTER_3 0x07C00 -#define VID_F_DOWN_CLUSTER_4 0x081A0 - -#define VID_G_DOWN_CLUSTER_1 0x08740 -#define VID_G_DOWN_CLUSTER_2 0x08CE0 -#define VID_G_DOWN_CLUSTER_3 0x09280 -#define VID_G_DOWN_CLUSTER_4 0x09820 - -#define VID_H_DOWN_CLUSTER_1 0x09DC0 -#define VID_H_DOWN_CLUSTER_2 0x0A360 -#define VID_H_DOWN_CLUSTER_3 0x0A900 -#define VID_H_DOWN_CLUSTER_4 0x0AEA0 - -#define AUD_A_DOWN_CLUSTER_1 0x0B500 -#define AUD_A_DOWN_CLUSTER_2 0x0B580 -#define AUD_A_DOWN_CLUSTER_3 0x0B600 - -#define AUD_B_DOWN_CLUSTER_1 0x0B680 -#define AUD_B_DOWN_CLUSTER_2 0x0B700 -#define AUD_B_DOWN_CLUSTER_3 0x0B780 - -#define AUD_C_DOWN_CLUSTER_1 0x0B800 -#define AUD_C_DOWN_CLUSTER_2 0x0B880 -#define AUD_C_DOWN_CLUSTER_3 0x0B900 - -#define AUD_D_DOWN_CLUSTER_1 0x0B980 -#define AUD_D_DOWN_CLUSTER_2 0x0BA00 -#define AUD_D_DOWN_CLUSTER_3 0x0BA80 - -#define TX_SRAM_POOL_FREE 0x0BB00 -#define TX_SRAM_END 0x0C000 - -#define BYTES_TO_DWORDS(bcount) ((bcount) >> 2) -#define BYTES_TO_QWORDS(bcount) ((bcount) >> 3) -#define BYTES_TO_OWORDS(bcount) ((bcount) >> 4) - -#define VID_IQ_SIZE_DW BYTES_TO_DWORDS(VID_IQ_SIZE) -#define VID_CDT_SIZE_QW BYTES_TO_QWORDS(VID_CDT_SIZE) -#define VID_CLUSTER_SIZE_OW BYTES_TO_OWORDS(VID_CLUSTER_SIZE) - -#define AUDIO_IQ_SIZE_DW BYTES_TO_DWORDS(AUDIO_IQ_SIZE) -#define AUDIO_CDT_SIZE_QW BYTES_TO_QWORDS(AUDIO_CDT_SIZE) -#define AUDIO_CLUSTER_SIZE_QW BYTES_TO_QWORDS(AUDIO_CLUSTER_SIZE) - -#define MBIF_IQ_SIZE_DW BYTES_TO_DWORDS(MBIF_IQ_SIZE) -#define MBIF_CDT_SIZE_QW BYTES_TO_QWORDS(MBIF_CDT_SIZE) -#define MBIF_CLUSTER_SIZE_OW BYTES_TO_OWORDS(MBIF_CLUSTER_SIZE) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2007 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * Based on Steven Toth cx23885 driver - * Parts adapted/taken from Eduardo Moscoso Rubino - * Copyright (C) 2009 Eduardo Moscoso Rubino - * - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "cx25821-video.h" - -MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); -MODULE_AUTHOR("Hiep Huynh "); -MODULE_LICENSE("GPL"); - -static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; - -module_param_array(video_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); - -MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); - -static unsigned int video_debug = VIDEO_DEBUG; -module_param(video_debug, int, 0644); -MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); - -static unsigned int irq_debug; -module_param(irq_debug, int, 0644); -MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); - -unsigned int vid_limit = 16; -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); - -static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num); - -static const struct v4l2_file_operations video_fops; -static const struct v4l2_ioctl_ops video_ioctl_ops; - -#define FORMAT_FLAGS_PACKED 0x01 - -struct cx25821_fmt formats[] = { - { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:1:1, packed, Y41P", - .fourcc = V4L2_PIX_FMT_Y41P, - .depth = 12, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:0, YUV", - .fourcc = V4L2_PIX_FMT_YUV420, - .depth = 12, - .flags = FORMAT_FLAGS_PACKED, - }, -}; - -int cx25821_get_format_size(void) -{ - return ARRAY_SIZE(formats); -} - -struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - if (fourcc == V4L2_PIX_FMT_Y41P || fourcc == V4L2_PIX_FMT_YUV411P) { - return formats + 1; - } - - for (i = 0; i < ARRAY_SIZE(formats); i++) - if (formats[i].fourcc == fourcc) - return formats + i; - - pr_err("%s(0x%08x) NOT FOUND\n", __func__, fourcc); - return NULL; -} - -void cx25821_dump_video_queue(struct cx25821_dev *dev, struct cx25821_dmaqueue *q) -{ - struct cx25821_buffer *buf; - struct list_head *item; - dprintk(1, "%s()\n", __func__); - - if (!list_empty(&q->active)) { - list_for_each(item, &q->active) - buf = list_entry(item, struct cx25821_buffer, vb.queue); - } - - if (!list_empty(&q->queued)) { - list_for_each(item, &q->queued) - buf = list_entry(item, struct cx25821_buffer, vb.queue); - } - -} - -void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, - u32 count) -{ - struct cx25821_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) { - dprintk(1, "bc=%d (=0: active empty)\n", bc); - break; - } - - buf = - list_entry(q->active.next, struct cx25821_buffer, vb.queue); - - /* count comes from the hw and it is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) { - break; - } - - do_gettimeofday(&buf->vb.ts); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } - - if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - if (bc != 1) - pr_err("%s: %d buffers handled (should be 1)\n", - __func__, bc); -} - -#ifdef TUNER_FLAG -int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) -{ - dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", - __func__, (unsigned int)norm, v4l2_norm_to_name(norm)); - - dev->tvnorm = norm; - - /* Tell the internal A/V decoder */ - cx25821_call_all(dev, core, s_std, norm); - - return 0; -} -#endif - -struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, - struct pci_dev *pci, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - dprintk(1, "%s()\n", __func__); - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, - cx25821_boards[dev->board].name); - video_set_drvdata(vfd, dev); - return vfd; -} - -/* -static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX25821_CTLS; i++) - if (cx25821_ctls[i].v.id == qctrl->id) - break; - if (i == CX25821_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx25821_ctls[i].v; - return 0; -} -*/ - -/* resource management */ -int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bit) -{ - dprintk(1, "%s()\n", __func__); - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->channels[fh->channel_id].resources & bit) { - /* no, someone else uses it */ - mutex_unlock(&dev->lock); - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->channels[fh->channel_id].resources |= bit; - dprintk(1, "res: get %d\n", bit); - mutex_unlock(&dev->lock); - return 1; -} - -int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit) -{ - return fh->dev->channels[fh->channel_id].resources & bit; -} - -void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bits) -{ - BUG_ON((fh->resources & bits) != bits); - dprintk(1, "%s()\n", __func__); - - mutex_lock(&dev->lock); - fh->resources &= ~bits; - dev->channels[fh->channel_id].resources &= ~bits; - dprintk(1, "res: put %d\n", bits); - mutex_unlock(&dev->lock); -} - -int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input) -{ - struct v4l2_routing route; - memset(&route, 0, sizeof(route)); - - dprintk(1, "%s(): video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", - __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0, - INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3); - dev->input = input; - - route.input = INPUT(input)->vmux; - - /* Tell the internal A/V decoder */ - cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0); - - return 0; -} - -int cx25821_start_video_dma(struct cx25821_dev *dev, - struct cx25821_dmaqueue *q, - struct cx25821_buffer *buf, - struct sram_channel *channel) -{ - int tmp = 0; - - /* setup fifo + format */ - cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma); - - /* reset counter */ - cx_write(channel->gpcnt_ctl, 3); - q->count = 1; - - /* enable irq */ - cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i)); - cx_set(channel->int_msk, 0x11); - - /* start dma */ - cx_write(channel->dma_ctl, 0x11); /* FIFO and RISC enable */ - - /* make sure upstream setting if any is reversed */ - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); - - return 0; -} - -int cx25821_restart_video_queue(struct cx25821_dev *dev, - struct cx25821_dmaqueue *q, - struct sram_channel *channel) -{ - struct cx25821_buffer *buf, *prev; - struct list_head *item; - - if (!list_empty(&q->active)) { - buf = - list_entry(q->active.next, struct cx25821_buffer, vb.queue); - - cx25821_start_video_dma(dev, q, buf, channel); - - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx25821_buffer, vb.queue); - buf->count = q->count++; - } - - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - - buf = - list_entry(q->queued.next, struct cx25821_buffer, vb.queue); - - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx25821_start_video_dma(dev, q, buf, channel); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ - } else { - return 0; - } - prev = buf; - } -} - -void cx25821_vid_timeout(unsigned long data) -{ - struct cx25821_data *timeout_data = (struct cx25821_data *)data; - struct cx25821_dev *dev = timeout_data->dev; - struct sram_channel *channel = timeout_data->channel; - struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq; - struct cx25821_buffer *buf; - unsigned long flags; - - /* cx25821_sram_channel_dump(dev, channel); */ - cx_clear(channel->dma_ctl, 0x11); - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = - list_entry(q->active.next, struct cx25821_buffer, vb.queue); - list_del(&buf->vb.queue); - - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - } - - cx25821_restart_video_queue(dev, q, channel); - spin_unlock_irqrestore(&dev->slock, flags); -} - -int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) -{ - u32 count = 0; - int handled = 0; - u32 mask; - struct sram_channel *channel = dev->channels[chan_num].sram_channels; - - mask = cx_read(channel->int_msk); - if (0 == (status & mask)) - return handled; - - cx_write(channel->int_stat, status); - - /* risc op code error */ - if (status & (1 << 16)) { - pr_warn("%s, %s: video risc op code error\n", - dev->name, channel->name); - cx_clear(channel->dma_ctl, 0x11); - cx25821_sram_channel_dump(dev, channel); - } - - /* risc1 y */ - if (status & FLD_VID_DST_RISC1) { - spin_lock(&dev->slock); - count = cx_read(channel->gpcnt); - cx25821_video_wakeup(dev, - &dev->channels[channel->i].vidq, count); - spin_unlock(&dev->slock); - handled++; - } - - /* risc2 y */ - if (status & 0x10) { - dprintk(2, "stopper video\n"); - spin_lock(&dev->slock); - cx25821_restart_video_queue(dev, - &dev->channels[channel->i].vidq, - channel); - spin_unlock(&dev->slock); - handled++; - } - return handled; -} - -void cx25821_videoioctl_unregister(struct cx25821_dev *dev) -{ - if (dev->ioctl_dev) { - if (video_is_registered(dev->ioctl_dev)) - video_unregister_device(dev->ioctl_dev); - else - video_device_release(dev->ioctl_dev); - - dev->ioctl_dev = NULL; - } -} - -void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) -{ - cx_clear(PCI_INT_MSK, 1); - - if (dev->channels[chan_num].video_dev) { - if (video_is_registered(dev->channels[chan_num].video_dev)) - video_unregister_device( - dev->channels[chan_num].video_dev); - else - video_device_release( - dev->channels[chan_num].video_dev); - - dev->channels[chan_num].video_dev = NULL; - - btcx_riscmem_free(dev->pci, - &dev->channels[chan_num].vidq.stopper); - - pr_warn("device %d released!\n", chan_num); - } - -} - -int cx25821_video_register(struct cx25821_dev *dev) -{ - int err; - int i; - - struct video_device cx25821_video_device = { - .name = "cx25821-video", - .fops = &video_fops, - .minor = -1, - .ioctl_ops = &video_ioctl_ops, - .tvnorms = CX25821_NORMS, - .current_norm = V4L2_STD_NTSC_M, - }; - - spin_lock_init(&dev->slock); - - for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) { - cx25821_init_controls(dev, i); - - cx25821_risc_stopper(dev->pci, - &dev->channels[i].vidq.stopper, - dev->channels[i].sram_channels->dma_ctl, - 0x11, 0); - - dev->channels[i].sram_channels = &cx25821_sram_channels[i]; - dev->channels[i].video_dev = NULL; - dev->channels[i].resources = 0; - - cx_write(dev->channels[i].sram_channels->int_stat, - 0xffffffff); - - INIT_LIST_HEAD(&dev->channels[i].vidq.active); - INIT_LIST_HEAD(&dev->channels[i].vidq.queued); - - dev->channels[i].timeout_data.dev = dev; - dev->channels[i].timeout_data.channel = - &cx25821_sram_channels[i]; - dev->channels[i].vidq.timeout.function = - cx25821_vid_timeout; - dev->channels[i].vidq.timeout.data = - (unsigned long)&dev->channels[i].timeout_data; - init_timer(&dev->channels[i].vidq.timeout); - - /* register v4l devices */ - dev->channels[i].video_dev = cx25821_vdev_init(dev, - dev->pci, &cx25821_video_device, "video"); - - err = video_register_device(dev->channels[i].video_dev, - VFL_TYPE_GRABBER, video_nr[dev->nr]); - - if (err < 0) - goto fail_unreg; - - } - - /* set PCI interrupt */ - cx_set(PCI_INT_MSK, 0xff); - - /* initial device configuration */ - mutex_lock(&dev->lock); -#ifdef TUNER_FLAG - dev->tvnorm = cx25821_video_device.current_norm; - cx25821_set_tvnorm(dev, dev->tvnorm); -#endif - mutex_unlock(&dev->lock); - - - return 0; - -fail_unreg: - cx25821_video_unregister(dev, i); - return err; -} - -int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct cx25821_fh *fh = q->priv_data; - - *size = fh->fmt->depth * fh->width * fh->height >> 3; - - if (0 == *count) - *count = 32; - - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; - - return 0; -} - -int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx25821_fh *fh = q->priv_data; - struct cx25821_dev *dev = fh->dev; - struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); - int rc, init_buffer = 0; - u32 line0_offset, line1_offset; - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - int bpl_local = LINE_SIZE_D1; - int channel_opened = fh->channel_id; - - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > 720 || - fh->height < 32 || fh->height > 576) - return -EINVAL; - - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; - - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - init_buffer = 1; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) { - printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n")); - goto fail; - } - } - - dprintk(1, "init_buffer=%d\n", init_buffer); - - if (init_buffer) { - - channel_opened = dev->channel_opened; - channel_opened = (channel_opened < 0 - || channel_opened > 7) ? 7 : channel_opened; - - if (dev->channels[channel_opened] - .pixel_formats == PIXEL_FRMT_411) - buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3; - else - buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width); - - if (dev->channels[channel_opened] - .pixel_formats == PIXEL_FRMT_411) { - bpl_local = buf->bpl; - } else { - bpl_local = buf->bpl; /* Default */ - - if (channel_opened >= 0 && channel_opened <= 7) { - if (dev->channels[channel_opened] - .use_cif_resolution) { - if (dev->tvnorm & V4L2_STD_PAL_BG - || dev->tvnorm & V4L2_STD_PAL_DK) - bpl_local = 352 << 1; - else - bpl_local = - dev->channels[channel_opened]. - cif_width << - 1; - } - } - } - - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - /* All other formats are top field first */ - line0_offset = 0; - line1_offset = buf->bpl; - dprintk(1, "top field first\n"); - - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, line0_offset, - bpl_local, bpl_local, bpl_local, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, buf->vb.height >> 1); - break; - default: - BUG(); - } - } - - dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, fh->width, fh->height, fh->fmt->depth, - fh->fmt->name, (unsigned long)buf->risc.dma); - - buf->vb.state = VIDEOBUF_PREPARED; - - return 0; - - fail: - cx25821_free_buffer(q, buf); - return rc; -} - -void cx25821_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); - - cx25821_free_buffer(q, buf); -} - -struct videobuf_queue *get_queue(struct cx25821_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &fh->vidq; - default: - BUG(); - return NULL; - } -} - -int cx25821_get_resource(struct cx25821_fh *fh, int resource) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return resource; - default: - BUG(); - return 0; - } -} - -int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx25821_fh *fh = file->private_data; - - return videobuf_mmap_mapper(get_queue(fh), vma); -} - - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); - struct cx25821_buffer *prev; - struct cx25821_fh *fh = vq->priv_data; - struct cx25821_dev *dev = fh->dev; - struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - - dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]); - - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf, - buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx25821_start_video_dma(dev, q, buf, - dev->channels[fh->channel_id]. - sram_channels); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - dprintk(2, - "[%p/%d] buffer_queue - first active, buf cnt = %d, \ - q->count = %d\n", - buf, buf->vb.i, buf->count, q->count); - } else { - prev = - list_entry(q->active.prev, struct cx25821_buffer, vb.queue); - if (prev->vb.width == buf->vb.width - && prev->vb.height == buf->vb.height - && prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(2, - "[%p/%d] buffer_queue - append to active, \ - buf->count=%d\n", - buf, buf->vb.i, buf->count); - - } else { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf, - buf->vb.i); - } - } - - if (list_empty(&q->active)) - dprintk(2, "active queue empty!\n"); -} - -static struct videobuf_queue_ops cx25821_video_qops = { - .buf_setup = cx25821_buffer_setup, - .buf_prepare = cx25821_buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = cx25821_buffer_release, -}; - -static int video_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct cx25821_dev *h, *dev = video_drvdata(file); - struct cx25821_fh *fh; - struct list_head *list; - int minor = video_devdata(file)->minor; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - u32 pix_format; - int ch_id = 0; - int i; - - dprintk(1, "open dev=%s type=%s\n", - video_device_node_name(vdev), - v4l2_type_names[type]); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - mutex_lock(&cx25821_devlist_mutex); - - list_for_each(list, &cx25821_devlist) - { - h = list_entry(list, struct cx25821_dev, devlist); - - for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) { - if (h->channels[i].video_dev && - h->channels[i].video_dev->minor == minor) { - dev = h; - ch_id = i; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - } - } - - if (NULL == dev) { - mutex_unlock(&cx25821_devlist_mutex); - return -ENODEV; - } - - file->private_data = fh; - fh->dev = dev; - fh->type = type; - fh->width = 720; - fh->channel_id = ch_id; - - if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK) - fh->height = 576; - else - fh->height = 480; - - dev->channel_opened = fh->channel_id; - pix_format = - (dev->channels[ch_id].pixel_formats == - PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV; - fh->fmt = cx25821_format_by_fourcc(pix_format); - - v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio); - - videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx25821_buffer), fh, NULL); - - dprintk(1, "post videobuf_queue_init()\n"); - mutex_unlock(&cx25821_devlist_mutex); - - return 0; -} - -static ssize_t video_read(struct file *file, char __user * data, size_t count, - loff_t *ppos) -{ - struct cx25821_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (cx25821_res_locked(fh, RESOURCE_VIDEO0)) - return -EBUSY; - - return videobuf_read_one(&fh->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - - default: - BUG(); - return 0; - } -} - -static unsigned int video_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx25821_fh *fh = file->private_data; - struct cx25821_buffer *buf; - - if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { - /* streaming capture */ - if (list_empty(&fh->vidq.stream)) - return POLLERR; - buf = list_entry(fh->vidq.stream.next, - struct cx25821_buffer, vb.stream); - } else { - /* read() capture */ - buf = (struct cx25821_buffer *)fh->vidq.read_buf; - if (NULL == buf) - return POLLERR; - } - - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) { - if (buf->vb.state == VIDEOBUF_DONE) { - struct cx25821_dev *dev = fh->dev; - - if (dev && dev->channels[fh->channel_id] - .use_cif_resolution) { - u8 cam_id = *((char *)buf->vb.baddr + 3); - memcpy((char *)buf->vb.baddr, - (char *)buf->vb.baddr + (fh->width * 2), - (fh->width * 2)); - *((char *)buf->vb.baddr + 3) = cam_id; - } - } - - return POLLIN | POLLRDNORM; - } - - return 0; -} - -static int video_release(struct file *file) -{ - struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; - - /* stop the risc engine and fifo */ - cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */ - - /* stop video capture */ - if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { - videobuf_queue_cancel(&fh->vidq); - cx25821_res_free(dev, fh, RESOURCE_VIDEO0); - } - - if (fh->vidq.read_buf) { - cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf); - kfree(fh->vidq.read_buf); - } - - videobuf_mmap_free(&fh->vidq); - - v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio); - file->private_data = NULL; - kfree(fh); - - return 0; -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = fh->dev; - - if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) - return -EINVAL; - - if (unlikely(i != fh->type)) - return -EINVAL; - - if (unlikely(!cx25821_res_get(dev, fh, - cx25821_get_resource(fh, RESOURCE_VIDEO0)))) - return -EBUSY; - - return videobuf_streamon(get_queue(fh)); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = fh->dev; - int err, res; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (i != fh->type) - return -EINVAL; - - res = cx25821_get_resource(fh, RESOURCE_VIDEO0); - err = videobuf_streamoff(get_queue(fh)); - if (err < 0) - return err; - cx25821_res_free(dev, fh, res); - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct v4l2_mbus_framefmt mbus_fmt; - int err; - int pix_format = PIXEL_FRMT_422; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id] - .prio, fh->prio); - if (0 != err) - return err; - } - - dprintk(2, "%s()\n", __func__); - err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f); - - if (0 != err) - return err; - - fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); - fh->vidq.field = f->fmt.pix.field; - - /* check if width and height is valid based on set standard */ - if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) - fh->width = f->fmt.pix.width; - - if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) - fh->height = f->fmt.pix.height; - - if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P) - pix_format = PIXEL_FRMT_411; - else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) - pix_format = PIXEL_FRMT_422; - else - return -EINVAL; - - cx25821_set_pixel_format(dev, SRAM_CH00, pix_format); - - /* check if cif resolution */ - if (fh->width == 320 || fh->width == 352) - dev->channels[fh->channel_id].use_cif_resolution = 1; - else - dev->channels[fh->channel_id].use_cif_resolution = 0; - - dev->channels[fh->channel_id].cif_width = fh->width; - medusa_set_resolution(dev, fh->width, SRAM_CH00); - - dprintk(2, "%s(): width=%d height=%d field=%d\n", __func__, fh->width, - fh->height, fh->vidq.field); - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); - cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt); - - return 0; -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - int ret_val = 0; - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - - ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK); - - p->sequence = dev->channels[fh->channel_id].vidq.count; - - return ret_val; -} - -static int vidioc_log_status(struct file *file, void *priv) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct cx25821_fh *fh = priv; - char name[32 + 2]; - - struct sram_channel *sram_ch = dev->channels[fh->channel_id] - .sram_channels; - u32 tmp = 0; - - snprintf(name, sizeof(name), "%s/2", dev->name); - pr_info("%s/2: ============ START LOG STATUS ============\n", - dev->name); - cx25821_call_all(dev, core, log_status); - tmp = cx_read(sram_ch->dma_ctl); - pr_info("Video input 0 is %s\n", - (tmp & 0x11) ? "streaming" : "stopped"); - pr_info("%s/2: ============= END LOG STATUS =============\n", - dev->name); - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - int err; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id] - .prio, fh->prio); - if (0 != err) - return err; - } - - return cx25821_set_control(dev, ctl, fh->channel_id); -} - -/* VIDEO IOCTLS */ -int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) -{ - struct cx25821_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) -{ - struct cx25821_fmt *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; - - fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - maxw = 720; - maxh = 576; - - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh / 2) - ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; - } - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - f->fmt.pix.field = field; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -int cx25821_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - - strcpy(cap->driver, "cx25821"); - strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->version = CX25821_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (UNSET != dev->tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; -} - -int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (unlikely(f->index >= ARRAY_SIZE(formats))) - return -EINVAL; - - strlcpy(f->description, formats[f->index].name, sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; - - return 0; -} - -int cx25821_vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) -{ - struct cx25821_fh *fh = priv; - return videobuf_reqbufs(get_queue(fh), p); -} - -int cx25821_vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx25821_fh *fh = priv; - return videobuf_querybuf(get_queue(fh), p); -} - -int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx25821_fh *fh = priv; - return videobuf_qbuf(get_queue(fh), p); -} - -int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev; - struct cx25821_fh *fh = f; - - *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio); - - return 0; -} - -int cx25821_vidioc_s_priority(struct file *file, void *f, enum v4l2_priority prio) -{ - struct cx25821_fh *fh = f; - struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev; - - return v4l2_prio_change(&dev->channels[fh->channel_id] - .prio, &fh->prio, prio); -} - -#ifdef TUNER_FLAG -int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - int err; - - dprintk(1, "%s()\n", __func__); - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id] - .prio, fh->prio); - if (0 != err) - return err; - } - - if (dev->tvnorm == *tvnorms) { - return 0; - } - - mutex_lock(&dev->lock); - cx25821_set_tvnorm(dev, *tvnorms); - mutex_unlock(&dev->lock); - - medusa_set_videostandard(dev); - - return 0; -} -#endif - -int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i) -{ - static const char *iname[] = { - [CX25821_VMUX_COMPOSITE] = "Composite", - [CX25821_VMUX_SVIDEO] = "S-Video", - [CX25821_VMUX_DEBUG] = "for debug only", - }; - unsigned int n; - dprintk(1, "%s()\n", __func__); - - n = i->index; - if (n >= 2) - return -EINVAL; - - if (0 == INPUT(n)->type) - return -EINVAL; - - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, iname[INPUT(n)->type]); - - i->std = CX25821_NORMS; - return 0; -} - -int cx25821_vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - dprintk(1, "%s()\n", __func__); - return cx25821_enum_input(dev, i); -} - -int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - - *i = dev->input; - dprintk(1, "%s(): returns %d\n", __func__, *i); - return 0; -} - -int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - int err; - - dprintk(1, "%s(%d)\n", __func__, i); - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id] - .prio, fh->prio); - if (0 != err) - return err; - } - - if (i > 2) { - dprintk(1, "%s(): -EINVAL\n", __func__); - return -EINVAL; - } - - mutex_lock(&dev->lock); - cx25821_video_mux(dev, i); - mutex_unlock(&dev->lock); - return 0; -} - -#ifdef TUNER_FLAG -int cx25821_vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = fh->dev; - - f->frequency = dev->freq; - - cx25821_call_all(dev, tuner, g_frequency, f); - - return 0; -} - -int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f) -{ - mutex_lock(&dev->lock); - dev->freq = f->frequency; - - cx25821_call_all(dev, tuner, s_frequency, f); - - /* When changing channels it is required to reset TVAUDIO */ - msleep(10); - - mutex_unlock(&dev->lock); - - return 0; -} - -int cx25821_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev; - int err; - - if (fh) { - dev = fh->dev; - err = v4l2_prio_check(&dev->channels[fh->channel_id] - .prio, fh->prio); - if (0 != err) - return err; - } else { - pr_err("Invalid fh pointer!\n"); - return -EINVAL; - } - - return cx25821_set_freq(dev, f); -} -#endif - -#ifdef CONFIG_VIDEO_ADV_DEBUG -int cx25821_vidioc_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - - cx25821_call_all(dev, core, g_register, reg); - - return 0; -} - -int cx25821_vidioc_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - - cx25821_call_all(dev, core, s_register, reg); - - return 0; -} - -#endif - -#ifdef TUNER_FLAG -int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - - t->signal = 0xffff; /* LOCKED */ - return 0; -} - -int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct cx25821_fh *fh = priv; - int err; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id] - .prio, fh->prio); - if (0 != err) - return err; - } - - dprintk(1, "%s()\n", __func__); - if (UNSET == dev->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - return 0; -} - -#endif -/*****************************************************************************/ -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static struct v4l2_queryctrl cx25821_ctls[] = { - /* --- video --- */ - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 6200, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; -static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls); - -static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX25821_CTLS; i++) - if (cx25821_ctls[i].id == qctrl->id) - break; - if (i == CX25821_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx25821_ctls[i]; - return 0; -} - -int cx25821_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - return cx25821_ctrl_query(qctrl); -} - -/* ------------------------------------------------------------------ */ -/* VIDEO CTRL IOCTLS */ - -static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) -{ - unsigned int i; - - for (i = 0; i < CX25821_CTLS; i++) - if (cx25821_ctls[i].id == id) - return cx25821_ctls + i; - return NULL; -} - -int cx25821_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctl) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct cx25821_fh *fh = priv; - - const struct v4l2_queryctrl *ctrl; - - ctrl = ctrl_by_id(ctl->id); - - if (NULL == ctrl) - return -EINVAL; - switch (ctl->id) { - case V4L2_CID_BRIGHTNESS: - ctl->value = dev->channels[fh->channel_id].ctl_bright; - break; - case V4L2_CID_HUE: - ctl->value = dev->channels[fh->channel_id].ctl_hue; - break; - case V4L2_CID_CONTRAST: - ctl->value = dev->channels[fh->channel_id].ctl_contrast; - break; - case V4L2_CID_SATURATION: - ctl->value = dev->channels[fh->channel_id].ctl_saturation; - break; - } - return 0; -} - -int cx25821_set_control(struct cx25821_dev *dev, - struct v4l2_control *ctl, int chan_num) -{ - int err; - const struct v4l2_queryctrl *ctrl; - - err = -EINVAL; - - ctrl = ctrl_by_id(ctl->id); - - if (NULL == ctrl) - return err; - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER: - if (ctl->value < ctrl->minimum) - ctl->value = ctrl->minimum; - if (ctl->value > ctrl->maximum) - ctl->value = ctrl->maximum; - break; - default: - /* nothing */ ; - }; - - switch (ctl->id) { - case V4L2_CID_BRIGHTNESS: - dev->channels[chan_num].ctl_bright = ctl->value; - medusa_set_brightness(dev, ctl->value, chan_num); - break; - case V4L2_CID_HUE: - dev->channels[chan_num].ctl_hue = ctl->value; - medusa_set_hue(dev, ctl->value, chan_num); - break; - case V4L2_CID_CONTRAST: - dev->channels[chan_num].ctl_contrast = ctl->value; - medusa_set_contrast(dev, ctl->value, chan_num); - break; - case V4L2_CID_SATURATION: - dev->channels[chan_num].ctl_saturation = ctl->value; - medusa_set_saturation(dev, ctl->value, chan_num); - break; - } - - err = 0; - - return err; -} - -static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num) -{ - struct v4l2_control ctrl; - int i; - for (i = 0; i < CX25821_CTLS; i++) { - ctrl.id = cx25821_ctls[i].id; - ctrl.value = cx25821_ctls[i].default_value; - - cx25821_set_control(dev, &ctrl, chan_num); - } -} - -int cx25821_vidioc_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cropcap) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480; - cropcap->pixelaspect.numerator = - dev->tvnorm == V4L2_STD_PAL_BG ? 59 : 10; - cropcap->pixelaspect.denominator = - dev->tvnorm == V4L2_STD_PAL_BG ? 54 : 11; - cropcap->defrect = cropcap->bounds; - return 0; -} - -int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct cx25821_fh *fh = priv; - int err; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id]. - prio, fh->prio); - if (0 != err) - return err; - } - /* cx25821_vidioc_s_crop not supported */ - return -EINVAL; -} - -int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) -{ - /* cx25821_vidioc_g_crop not supported */ - return -EINVAL; -} - -int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm) -{ - /* medusa does not support video standard sensing of current input */ - *norm = CX25821_NORMS; - - return 0; -} - -int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm) -{ - if (tvnorm == V4L2_STD_PAL_BG) { - if (width == 352 || width == 720) - return 1; - else - return 0; - } - - if (tvnorm == V4L2_STD_NTSC_M) { - if (width == 320 || width == 352 || width == 720) - return 1; - else - return 0; - } - return 0; -} - -int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm) -{ - if (tvnorm == V4L2_STD_PAL_BG) { - if (height == 576 || height == 288) - return 1; - else - return 0; - } - - if (tvnorm == V4L2_STD_NTSC_M) { - if (height == 480 || height == 240) - return 1; - else - return 0; - } - - return 0; -} - -static long video_ioctl_upstream9(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; - int command = 0; - struct upstream_user_struct *data_from_user; - - data_from_user = (struct upstream_user_struct *)arg; - - if (!data_from_user) { - pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); - return 0; - } - - command = data_from_user->command; - - if (command != UPSTREAM_START_VIDEO && - command != UPSTREAM_STOP_VIDEO) - return 0; - - dev->input_filename = data_from_user->input_filename; - dev->input_audiofilename = data_from_user->input_filename; - dev->vid_stdname = data_from_user->vid_stdname; - dev->pixel_format = data_from_user->pixel_format; - dev->channel_select = data_from_user->channel_select; - dev->command = data_from_user->command; - - switch (command) { - case UPSTREAM_START_VIDEO: - cx25821_start_upstream_video_ch1(dev, data_from_user); - break; - - case UPSTREAM_STOP_VIDEO: - cx25821_stop_upstream_video_ch1(dev); - break; - } - - return 0; -} - -static long video_ioctl_upstream10(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; - int command = 0; - struct upstream_user_struct *data_from_user; - - data_from_user = (struct upstream_user_struct *)arg; - - if (!data_from_user) { - pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); - return 0; - } - - command = data_from_user->command; - - if (command != UPSTREAM_START_VIDEO && - command != UPSTREAM_STOP_VIDEO) - return 0; - - dev->input_filename_ch2 = data_from_user->input_filename; - dev->input_audiofilename = data_from_user->input_filename; - dev->vid_stdname_ch2 = data_from_user->vid_stdname; - dev->pixel_format_ch2 = data_from_user->pixel_format; - dev->channel_select_ch2 = data_from_user->channel_select; - dev->command_ch2 = data_from_user->command; - - switch (command) { - case UPSTREAM_START_VIDEO: - cx25821_start_upstream_video_ch2(dev, data_from_user); - break; - - case UPSTREAM_STOP_VIDEO: - cx25821_stop_upstream_video_ch2(dev); - break; - } - - return 0; -} - -static long video_ioctl_upstream11(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; - int command = 0; - struct upstream_user_struct *data_from_user; - - data_from_user = (struct upstream_user_struct *)arg; - - if (!data_from_user) { - pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); - return 0; - } - - command = data_from_user->command; - - if (command != UPSTREAM_START_AUDIO && - command != UPSTREAM_STOP_AUDIO) - return 0; - - dev->input_filename = data_from_user->input_filename; - dev->input_audiofilename = data_from_user->input_filename; - dev->vid_stdname = data_from_user->vid_stdname; - dev->pixel_format = data_from_user->pixel_format; - dev->channel_select = data_from_user->channel_select; - dev->command = data_from_user->command; - - switch (command) { - case UPSTREAM_START_AUDIO: - cx25821_start_upstream_audio(dev, data_from_user); - break; - - case UPSTREAM_STOP_AUDIO: - cx25821_stop_upstream_audio(dev); - break; - } - - return 0; -} - -static long video_ioctl_set(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; - struct downstream_user_struct *data_from_user; - int command; - int width = 720; - int selected_channel = 0, pix_format = 0, i = 0; - int cif_enable = 0, cif_width = 0; - u32 value = 0; - - data_from_user = (struct downstream_user_struct *)arg; - - if (!data_from_user) { - pr_err("%s(): User data is INVALID. Returning\n", __func__); - return 0; - } - - command = data_from_user->command; - - if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT - && command != ENABLE_CIF_RESOLUTION && command != REG_READ - && command != REG_WRITE && command != MEDUSA_READ - && command != MEDUSA_WRITE) { - return 0; - } - - switch (command) { - case SET_VIDEO_STD: - dev->tvnorm = - !strcmp(data_from_user->vid_stdname, - "PAL") ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M; - medusa_set_videostandard(dev); - break; - - case SET_PIXEL_FORMAT: - selected_channel = data_from_user->decoder_select; - pix_format = data_from_user->pixel_format; - - if (!(selected_channel <= 7 && selected_channel >= 0)) { - selected_channel -= 4; - selected_channel = selected_channel % 8; - } - - if (selected_channel >= 0) - cx25821_set_pixel_format(dev, selected_channel, - pix_format); - - break; - - case ENABLE_CIF_RESOLUTION: - selected_channel = data_from_user->decoder_select; - cif_enable = data_from_user->cif_resolution_enable; - cif_width = data_from_user->cif_width; - - if (cif_enable) { - if (dev->tvnorm & V4L2_STD_PAL_BG - || dev->tvnorm & V4L2_STD_PAL_DK) - width = 352; - else - width = (cif_width == 320 - || cif_width == 352) ? cif_width : 320; - } - - if (!(selected_channel <= 7 && selected_channel >= 0)) { - selected_channel -= 4; - selected_channel = selected_channel % 8; - } - - if (selected_channel <= 7 && selected_channel >= 0) { - dev->channels[selected_channel]. - use_cif_resolution = cif_enable; - dev->channels[selected_channel].cif_width = width; - } else { - for (i = 0; i < VID_CHANNEL_NUM; i++) { - dev->channels[i].use_cif_resolution = - cif_enable; - dev->channels[i].cif_width = width; - } - } - - medusa_set_resolution(dev, width, selected_channel); - break; - case REG_READ: - data_from_user->reg_data = cx_read(data_from_user->reg_address); - break; - case REG_WRITE: - cx_write(data_from_user->reg_address, data_from_user->reg_data); - break; - case MEDUSA_READ: - value = - cx25821_i2c_read(&dev->i2c_bus[0], - (u16) data_from_user->reg_address, - &data_from_user->reg_data); - break; - case MEDUSA_WRITE: - cx25821_i2c_write(&dev->i2c_bus[0], - (u16) data_from_user->reg_address, - data_from_user->reg_data); - break; - } - - return 0; -} - -static long cx25821_video_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - int ret = 0; - - struct cx25821_fh *fh = file->private_data; - - /* check to see if it's the video upstream */ - if (fh->channel_id == SRAM_CH09) { - ret = video_ioctl_upstream9(file, cmd, arg); - return ret; - } else if (fh->channel_id == SRAM_CH10) { - ret = video_ioctl_upstream10(file, cmd, arg); - return ret; - } else if (fh->channel_id == SRAM_CH11) { - ret = video_ioctl_upstream11(file, cmd, arg); - ret = video_ioctl_set(file, cmd, arg); - return ret; - } - - return video_ioctl2(file, cmd, arg); -} - -/* exported stuff */ -static const struct v4l2_file_operations video_fops = { - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = cx25821_video_mmap, - .ioctl = cx25821_video_ioctl, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = cx25821_vidioc_querycap, - .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = cx25821_vidioc_reqbufs, - .vidioc_querybuf = cx25821_vidioc_querybuf, - .vidioc_qbuf = cx25821_vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, -#ifdef TUNER_FLAG - .vidioc_s_std = cx25821_vidioc_s_std, - .vidioc_querystd = cx25821_vidioc_querystd, -#endif - .vidioc_cropcap = cx25821_vidioc_cropcap, - .vidioc_s_crop = cx25821_vidioc_s_crop, - .vidioc_g_crop = cx25821_vidioc_g_crop, - .vidioc_enum_input = cx25821_vidioc_enum_input, - .vidioc_g_input = cx25821_vidioc_g_input, - .vidioc_s_input = cx25821_vidioc_s_input, - .vidioc_g_ctrl = cx25821_vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_queryctrl = cx25821_vidioc_queryctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_log_status = vidioc_log_status, - .vidioc_g_priority = cx25821_vidioc_g_priority, - .vidioc_s_priority = cx25821_vidioc_s_priority, -#ifdef TUNER_FLAG - .vidioc_g_tuner = cx25821_vidioc_g_tuner, - .vidioc_s_tuner = cx25821_vidioc_s_tuner, - .vidioc_g_frequency = cx25821_vidioc_g_frequency, - .vidioc_s_frequency = cx25821_vidioc_s_frequency, -#endif -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = cx25821_vidioc_g_register, - .vidioc_s_register = cx25821_vidioc_s_register, -#endif -}; - -struct video_device cx25821_videoioctl_template = { - .name = "cx25821-videoioctl", - .fops = &video_fops, - .ioctl_ops = &video_ioctl_ops, - .tvnorms = CX25821_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,177 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * Based on Steven Toth cx23885 driver - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef CX25821_VIDEO_H_ -#define CX25821_VIDEO_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx25821.h" -#include -#include - -#define TUNER_FLAG - -#define VIDEO_DEBUG 0 - -#define dprintk(level, fmt, arg...) \ -do { \ - if (VIDEO_DEBUG >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \ -} while (0) - -/* For IOCTL to identify running upstream */ -#define UPSTREAM_START_VIDEO 700 -#define UPSTREAM_STOP_VIDEO 701 -#define UPSTREAM_START_AUDIO 702 -#define UPSTREAM_STOP_AUDIO 703 -#define UPSTREAM_DUMP_REGISTERS 702 -#define SET_VIDEO_STD 800 -#define SET_PIXEL_FORMAT 1000 -#define ENABLE_CIF_RESOLUTION 1001 - -#define REG_READ 900 -#define REG_WRITE 901 -#define MEDUSA_READ 910 -#define MEDUSA_WRITE 911 - -extern struct sram_channel *channel0; -extern struct sram_channel *channel1; -extern struct sram_channel *channel2; -extern struct sram_channel *channel3; -extern struct sram_channel *channel4; -extern struct sram_channel *channel5; -extern struct sram_channel *channel6; -extern struct sram_channel *channel7; -extern struct sram_channel *channel9; -extern struct sram_channel *channel10; -extern struct sram_channel *channel11; -extern struct video_device cx25821_videoioctl_template; -/* extern const u32 *ctrl_classes[]; */ - -extern unsigned int vid_limit; - -#define FORMAT_FLAGS_PACKED 0x01 -extern struct cx25821_fmt formats[]; -extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc); -extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM]; - -extern void cx25821_dump_video_queue(struct cx25821_dev *dev, - struct cx25821_dmaqueue *q); -extern void cx25821_video_wakeup(struct cx25821_dev *dev, - struct cx25821_dmaqueue *q, u32 count); - -#ifdef TUNER_FLAG -extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm); -#endif - -extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, - unsigned int bit); -extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit); -extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit); -extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, - unsigned int bits); -extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input); -extern int cx25821_start_video_dma(struct cx25821_dev *dev, - struct cx25821_dmaqueue *q, - struct cx25821_buffer *buf, - struct sram_channel *channel); - -extern int cx25821_set_scale(struct cx25821_dev *dev, unsigned int width, - unsigned int height, enum v4l2_field field); -extern int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status); -extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num); -extern int cx25821_video_register(struct cx25821_dev *dev); -extern int cx25821_get_format_size(void); - -extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size); -extern int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field); -extern void cx25821_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb); -extern struct videobuf_queue *get_queue(struct cx25821_fh *fh); -extern int cx25821_get_resource(struct cx25821_fh *fh, int resource); -extern int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma); -extern int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f); -extern int cx25821_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap); -extern int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f); -extern int cx25821_vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p); -extern int cx25821_vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p); -extern int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p); -extern int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms); -extern int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i); -extern int cx25821_vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i); -extern int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i); -extern int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i); -extern int cx25821_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl); -extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f); -extern int cx25821_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f); -extern int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f); -extern int cx25821_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f); -extern int cx25821_vidioc_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg); -extern int cx25821_vidioc_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg); -extern int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t); -extern int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t); - -extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm); -extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm); - -extern int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p); -extern int cx25821_vidioc_s_priority(struct file *file, void *f, - enum v4l2_priority prio); - -extern int cx25821_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl); -extern int cx25821_set_control(struct cx25821_dev *dev, - struct v4l2_control *ctrl, int chan_num); - -extern int cx25821_vidioc_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cropcap); -extern int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop); -extern int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop); - -extern int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,892 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "cx25821-video.h" -#include "cx25821-video-upstream.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); -MODULE_AUTHOR("Hiep Huynh "); -MODULE_LICENSE("GPL"); - -static int _intr_msk = - FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR; - -int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) -{ - unsigned int i, lines; - u32 cdt; - - if (ch->cmds_start == 0) { - cx_write(ch->ptr1_reg, 0); - cx_write(ch->ptr2_reg, 0); - cx_write(ch->cnt2_reg, 0); - cx_write(ch->cnt1_reg, 0); - return 0; - } - - bpl = (bpl + 7) & ~7; /* alignment */ - cdt = ch->cdt; - lines = ch->fifo_size / bpl; - - if (lines > 4) - lines = 4; - - BUG_ON(lines < 2); - - /* write CDT */ - for (i = 0; i < lines; i++) { - cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); - cx_write(cdt + 16 * i + 4, 0); - cx_write(cdt + 16 * i + 8, 0); - cx_write(cdt + 16 * i + 12, 0); - } - - /* write CMDS */ - cx_write(ch->cmds_start + 0, risc); - - cx_write(ch->cmds_start + 4, 0); - cx_write(ch->cmds_start + 8, cdt); - cx_write(ch->cmds_start + 12, (lines * 16) >> 3); - cx_write(ch->cmds_start + 16, ch->ctrl_start); - - cx_write(ch->cmds_start + 20, VID_IQ_SIZE_DW); - - for (i = 24; i < 80; i += 4) - cx_write(ch->cmds_start + i, 0); - - /* fill registers */ - cx_write(ch->ptr1_reg, ch->fifo_start); - cx_write(ch->ptr2_reg, cdt); - cx_write(ch->cnt2_reg, (lines * 16) >> 3); - cx_write(ch->cnt1_reg, (bpl >> 3) - 1); - - return 0; -} - -static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev, - __le32 *rp, unsigned int offset, - unsigned int bpl, u32 sync_line, - unsigned int lines, int fifo_enable, - int field_type) -{ - unsigned int line, i; - int dist_betwn_starts = bpl * 2; - - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - if (USE_RISC_NOOP_VIDEO) { - for (i = 0; i < NUM_NO_OPS; i++) - *(rp++) = cpu_to_le32(RISC_NOOP); - } - - /* scan lines */ - for (line = 0; line < lines; line++) { - *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - - if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) { - offset += dist_betwn_starts; - } - } - - return rp; -} - -static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, - dma_addr_t databuf_phys_addr, - unsigned int offset, u32 sync_line, - unsigned int bpl, unsigned int lines, - int fifo_enable, int field_type) -{ - unsigned int line, i; - struct sram_channel *sram_ch = - dev->channels[dev->_channel_upstream_select].sram_channels; - int dist_betwn_starts = bpl * 2; - - /* sync instruction */ - if (sync_line != NO_SYNC_LINE) - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - if (USE_RISC_NOOP_VIDEO) { - for (i = 0; i < NUM_NO_OPS; i++) - *(rp++) = cpu_to_le32(RISC_NOOP); - } - - /* scan lines */ - for (line = 0; line < lines; line++) { - *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(databuf_phys_addr + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - - if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) - /* to skip the other field line */ - offset += dist_betwn_starts; - - /* check if we need to enable the FIFO after the first 4 lines - * For the upstream video channel, the risc engine will enable - * the FIFO. */ - if (fifo_enable && line == 3) { - *(rp++) = RISC_WRITECR; - *(rp++) = sram_ch->dma_ctl; - *(rp++) = FLD_VID_FIFO_EN; - *(rp++) = 0x00000001; - } - } - - return rp; -} - -int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, - struct pci_dev *pci, - unsigned int top_offset, - unsigned int bpl, unsigned int lines) -{ - __le32 *rp; - int fifo_enable = 0; - /* get line count for single field */ - int singlefield_lines = lines >> 1; - int odd_num_lines = singlefield_lines; - int frame = 0; - int frame_size = 0; - int databuf_offset = 0; - int risc_program_size = 0; - int risc_flag = RISC_CNT_RESET; - unsigned int bottom_offset = bpl; - dma_addr_t risc_phys_jump_addr; - - if (dev->_isNTSC) { - odd_num_lines = singlefield_lines + 1; - risc_program_size = FRAME1_VID_PROG_SIZE; - frame_size = - (bpl == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; - } else { - risc_program_size = PAL_VID_PROG_SIZE; - frame_size = - (bpl == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; - } - - /* Virtual address of Risc buffer program */ - rp = dev->_dma_virt_addr; - - for (frame = 0; frame < NUM_FRAMES; frame++) { - databuf_offset = frame_size * frame; - - if (UNSET != top_offset) { - fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; - rp = cx25821_risc_field_upstream(dev, rp, - dev-> - _data_buf_phys_addr + - databuf_offset, - top_offset, 0, bpl, - odd_num_lines, - fifo_enable, - ODD_FIELD); - } - - fifo_enable = FIFO_DISABLE; - - /* Even Field */ - rp = cx25821_risc_field_upstream(dev, rp, - dev->_data_buf_phys_addr + - databuf_offset, bottom_offset, - 0x200, bpl, singlefield_lines, - fifo_enable, EVEN_FIELD); - - if (frame == 0) { - risc_flag = RISC_CNT_RESET; - risc_phys_jump_addr = - dev->_dma_phys_start_addr + risc_program_size; - } else { - risc_phys_jump_addr = dev->_dma_phys_start_addr; - risc_flag = RISC_CNT_INC; - } - - /* Loop to 2ndFrameRISC or to Start of Risc - * program & generate IRQ - */ - *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); - *(rp++) = cpu_to_le32(risc_phys_jump_addr); - *(rp++) = cpu_to_le32(0); - } - - return 0; -} - -void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev) -{ - struct sram_channel *sram_ch = - dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels; - u32 tmp = 0; - - if (!dev->_is_running) { - pr_info("No video file is currently running so return!\n"); - return; - } - /* Disable RISC interrupts */ - tmp = cx_read(sram_ch->int_msk); - cx_write(sram_ch->int_msk, tmp & ~_intr_msk); - - /* Turn OFF risc and fifo enable */ - tmp = cx_read(sram_ch->dma_ctl); - cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); - - /* Clear data buffer memory */ - if (dev->_data_buf_virt_addr) - memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); - - dev->_is_running = 0; - dev->_is_first_frame = 0; - dev->_frame_count = 0; - dev->_file_status = END_OF_FILE; - - if (dev->_irq_queues) { - kfree(dev->_irq_queues); - dev->_irq_queues = NULL; - } - - if (dev->_filename != NULL) - kfree(dev->_filename); - - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); -} - -void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev) -{ - if (dev->_is_running) - cx25821_stop_upstream_video_ch1(dev); - - if (dev->_dma_virt_addr) { - pci_free_consistent(dev->pci, dev->_risc_size, - dev->_dma_virt_addr, dev->_dma_phys_addr); - dev->_dma_virt_addr = NULL; - } - - if (dev->_data_buf_virt_addr) { - pci_free_consistent(dev->pci, dev->_data_buf_size, - dev->_data_buf_virt_addr, - dev->_data_buf_phys_addr); - dev->_data_buf_virt_addr = NULL; - } -} - -int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) -{ - struct file *myfile; - int frame_index_temp = dev->_frame_index; - int i = 0; - int line_size = - (dev->_pixel_format == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; - int frame_size = 0; - int frame_offset = 0; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t file_offset; - loff_t pos; - mm_segment_t old_fs; - - if (dev->_file_status == END_OF_FILE) - return 0; - - if (dev->_isNTSC) { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; - } else { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; - } - - frame_offset = (frame_index_temp > 0) ? frame_size : 0; - file_offset = dev->_frame_count * frame_size; - - myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); - - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_filename, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (i = 0; i < dev->_lines_count; i++) { - pos = file_offset; - - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); - - if (vfs_read_retval > 0 && vfs_read_retval == line_size - && dev->_data_buf_virt_addr != NULL) { - memcpy((void *)(dev->_data_buf_virt_addr + - frame_offset / 4), mybuf, - vfs_read_retval); - } - - file_offset += vfs_read_retval; - frame_offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Video file\n", - __func__); - break; - } - } - - if (i > 0) - dev->_frame_count++; - - dev->_file_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - filp_close(myfile, NULL); - } - - return 0; -} - -static void cx25821_vidups_handler(struct work_struct *work) -{ - struct cx25821_dev *dev = - container_of(work, struct cx25821_dev, _irq_work_entry); - - if (!dev) { - pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", - __func__); - return; - } - - cx25821_get_frame(dev, - dev->channels[dev->_channel_upstream_select]. - sram_channels); -} - -int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) -{ - struct file *myfile; - int i = 0, j = 0; - int line_size = - (dev->_pixel_format == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t pos; - loff_t offset = (unsigned long)0; - mm_segment_t old_fs; - - myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); - - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_filename, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered! Returning\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (j = 0; j < NUM_FRAMES; j++) { - for (i = 0; i < dev->_lines_count; i++) { - pos = offset; - - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); - - if (vfs_read_retval > 0 - && vfs_read_retval == line_size - && dev->_data_buf_virt_addr != NULL) { - memcpy((void *)(dev-> - _data_buf_virt_addr + - offset / 4), mybuf, - vfs_read_retval); - } - - offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Video file\n", - __func__); - break; - } - } - - if (i > 0) - dev->_frame_count++; - - if (vfs_read_retval < line_size) - break; - } - - dev->_file_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - myfile->f_pos = 0; - filp_close(myfile, NULL); - } - - return 0; -} - -int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, - struct sram_channel *sram_ch, int bpl) -{ - int ret = 0; - dma_addr_t dma_addr; - dma_addr_t data_dma_addr; - - if (dev->_dma_virt_addr != NULL) { - pci_free_consistent(dev->pci, dev->upstream_riscbuf_size, - dev->_dma_virt_addr, dev->_dma_phys_addr); - } - - dev->_dma_virt_addr = - pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size, - &dma_addr); - dev->_dma_virt_start_addr = dev->_dma_virt_addr; - dev->_dma_phys_start_addr = dma_addr; - dev->_dma_phys_addr = dma_addr; - dev->_risc_size = dev->upstream_riscbuf_size; - - if (!dev->_dma_virt_addr) { - pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); - return -ENOMEM; - } - - /* Clear memory at address */ - memset(dev->_dma_virt_addr, 0, dev->_risc_size); - - if (dev->_data_buf_virt_addr != NULL) { - pci_free_consistent(dev->pci, dev->upstream_databuf_size, - dev->_data_buf_virt_addr, - dev->_data_buf_phys_addr); - } - /* For Video Data buffer allocation */ - dev->_data_buf_virt_addr = - pci_alloc_consistent(dev->pci, dev->upstream_databuf_size, - &data_dma_addr); - dev->_data_buf_phys_addr = data_dma_addr; - dev->_data_buf_size = dev->upstream_databuf_size; - - if (!dev->_data_buf_virt_addr) { - pr_err("FAILED to allocate memory for data buffer! Returning\n"); - return -ENOMEM; - } - - /* Clear memory at address */ - memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); - - ret = cx25821_openfile(dev, sram_ch); - if (ret < 0) - return ret; - - /* Create RISC programs */ - ret = - cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl, - dev->_lines_count); - if (ret < 0) { - pr_info("Failed creating Video Upstream Risc programs!\n"); - goto error; - } - - return 0; - -error: - return ret; -} - -int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, - u32 status) -{ - u32 int_msk_tmp; - struct sram_channel *channel = dev->channels[chan_num].sram_channels; - int singlefield_lines = NTSC_FIELD_HEIGHT; - int line_size_in_bytes = Y422_LINE_SZ; - int odd_risc_prog_size = 0; - dma_addr_t risc_phys_jump_addr; - __le32 *rp; - - if (status & FLD_VID_SRC_RISC1) { - /* We should only process one program per call */ - u32 prog_cnt = cx_read(channel->gpcnt); - - /* Since we've identified our IRQ, clear our bits from the - * interrupt mask and interrupt status registers */ - int_msk_tmp = cx_read(channel->int_msk); - cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); - cx_write(channel->int_stat, _intr_msk); - - spin_lock(&dev->slock); - - dev->_frame_index = prog_cnt; - - queue_work(dev->_irq_queues, &dev->_irq_work_entry); - - if (dev->_is_first_frame) { - dev->_is_first_frame = 0; - - if (dev->_isNTSC) { - singlefield_lines += 1; - odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; - } else { - singlefield_lines = PAL_FIELD_HEIGHT; - odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; - } - - if (dev->_dma_virt_start_addr != NULL) { - line_size_in_bytes = - (dev->_pixel_format == - PIXEL_FRMT_411) ? Y411_LINE_SZ : - Y422_LINE_SZ; - risc_phys_jump_addr = - dev->_dma_phys_start_addr + - odd_risc_prog_size; - - rp = cx25821_update_riscprogram(dev, - dev-> - _dma_virt_start_addr, - TOP_OFFSET, - line_size_in_bytes, - 0x0, - singlefield_lines, - FIFO_DISABLE, - ODD_FIELD); - - /* Jump to Even Risc program of 1st Frame */ - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc_phys_jump_addr); - *(rp++) = cpu_to_le32(0); - } - } - - spin_unlock(&dev->slock); - } else { - if (status & FLD_VID_SRC_UF) - pr_err("%s(): Video Received Underflow Error Interrupt!\n", - __func__); - - if (status & FLD_VID_SRC_SYNC) - pr_err("%s(): Video Received Sync Error Interrupt!\n", - __func__); - - if (status & FLD_VID_SRC_OPC_ERR) - pr_err("%s(): Video Received OpCode Error Interrupt!\n", - __func__); - } - - if (dev->_file_status == END_OF_FILE) { - pr_err("EOF Channel 1 Framecount = %d\n", dev->_frame_count); - return -1; - } - /* ElSE, set the interrupt mask register, re-enable irq. */ - int_msk_tmp = cx_read(channel->int_msk); - cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); - - return 0; -} - -static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) -{ - struct cx25821_dev *dev = dev_id; - u32 msk_stat, vid_status; - int handled = 0; - int channel_num = 0; - struct sram_channel *sram_ch; - - if (!dev) - return -1; - - channel_num = VID_UPSTREAM_SRAM_CHANNEL_I; - - sram_ch = dev->channels[channel_num].sram_channels; - - msk_stat = cx_read(sram_ch->int_mstat); - vid_status = cx_read(sram_ch->int_stat); - - /* Only deal with our interrupt */ - if (vid_status) { - handled = - cx25821_video_upstream_irq(dev, channel_num, vid_status); - } - - if (handled < 0) - cx25821_stop_upstream_video_ch1(dev); - else - handled += handled; - - return IRQ_RETVAL(handled); -} - -void cx25821_set_pixelengine(struct cx25821_dev *dev, struct sram_channel *ch, - int pix_format) -{ - int width = WIDTH_D1; - int height = dev->_lines_count; - int num_lines, odd_num_lines; - u32 value; - int vip_mode = OUTPUT_FRMT_656; - - value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); - value &= 0xFFFFFFEF; - value |= dev->_isNTSC ? 0 : 0x10; - cx_write(ch->vid_fmt_ctl, value); - - /* set number of active pixels in each line. - * Default is 720 pixels in both NTSC and PAL format */ - cx_write(ch->vid_active_ctl1, width); - - num_lines = (height / 2) & 0x3FF; - odd_num_lines = num_lines; - - if (dev->_isNTSC) - odd_num_lines += 1; - - value = (num_lines << 16) | odd_num_lines; - - /* set number of active lines in field 0 (top) and field 1 (bottom) */ - cx_write(ch->vid_active_ctl2, value); - - cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); -} - -int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, - struct sram_channel *sram_ch) -{ - u32 tmp = 0; - int err = 0; - - /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for - * channel A-C - */ - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); - - /* Set the physical start address of the RISC program in the initial - * program counter(IPC) member of the cmds. - */ - cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr); - /* Risc IPC High 64 bits 63-32 */ - cx_write(sram_ch->cmds_start + 4, 0); - - /* reset counter */ - cx_write(sram_ch->gpcnt_ctl, 3); - - /* Clear our bits from the interrupt status register. */ - cx_write(sram_ch->int_stat, _intr_msk); - - /* Set the interrupt mask register, enable irq. */ - cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); - tmp = cx_read(sram_ch->int_msk); - cx_write(sram_ch->int_msk, tmp |= _intr_msk); - - err = - request_irq(dev->pci->irq, cx25821_upstream_irq, - IRQF_SHARED | IRQF_DISABLED, dev->name, dev); - if (err < 0) { - pr_err("%s: can't get upstream IRQ %d\n", - dev->name, dev->pci->irq); - goto fail_irq; - } - - /* Start the DMA engine */ - tmp = cx_read(sram_ch->dma_ctl); - cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); - - dev->_is_running = 1; - dev->_is_first_frame = 1; - - return 0; - -fail_irq: - cx25821_dev_unregister(dev); - return err; -} - -int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, - int pixel_format) -{ - struct sram_channel *sram_ch; - u32 tmp; - int retval = 0; - int err = 0; - int data_frame_size = 0; - int risc_buffer_size = 0; - int str_length = 0; - - if (dev->_is_running) { - pr_info("Video Channel is still running so return!\n"); - return 0; - } - - dev->_channel_upstream_select = channel_select; - sram_ch = dev->channels[channel_select].sram_channels; - - INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler); - dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue"); - - if (!dev->_irq_queues) { - pr_err("create_singlethread_workqueue() for Video FAILED!\n"); - return -ENOMEM; - } - /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for - * channel A-C - */ - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); - - dev->_is_running = 0; - dev->_frame_count = 0; - dev->_file_status = RESET_STATUS; - dev->_lines_count = dev->_isNTSC ? 480 : 576; - dev->_pixel_format = pixel_format; - dev->_line_size = - (dev->_pixel_format == - PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; - data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; - risc_buffer_size = - dev->_isNTSC ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; - - if (dev->input_filename) { - str_length = strlen(dev->input_filename); - dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); - - if (!dev->_filename) - goto error; - - memcpy(dev->_filename, dev->input_filename, str_length + 1); - } else { - str_length = strlen(dev->_defaultname); - dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); - - if (!dev->_filename) - goto error; - - memcpy(dev->_filename, dev->_defaultname, str_length + 1); - } - - /* Default if filename is empty string */ - if (strcmp(dev->input_filename, "") == 0) { - if (dev->_isNTSC) { - dev->_filename = - (dev->_pixel_format == - PIXEL_FRMT_411) ? "/root/vid411.yuv" : - "/root/vidtest.yuv"; - } else { - dev->_filename = - (dev->_pixel_format == - PIXEL_FRMT_411) ? "/root/pal411.yuv" : - "/root/pal422.yuv"; - } - } - - dev->_is_running = 0; - dev->_frame_count = 0; - dev->_file_status = RESET_STATUS; - dev->_lines_count = dev->_isNTSC ? 480 : 576; - dev->_pixel_format = pixel_format; - dev->_line_size = - (dev->_pixel_format == - PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; - - retval = - cx25821_sram_channel_setup_upstream(dev, sram_ch, dev->_line_size, - 0); - - /* setup fifo + format */ - cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format); - - dev->upstream_riscbuf_size = risc_buffer_size * 2; - dev->upstream_databuf_size = data_frame_size * 2; - - /* Allocating buffers and prepare RISC program */ - retval = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size); - if (retval < 0) { - pr_err("%s: Failed to set up Video upstream buffers!\n", - dev->name); - goto error; - } - - cx25821_start_video_dma_upstream(dev, sram_ch); - - return 0; - -error: - cx25821_dev_unregister(dev); - - return err; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream-ch2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream-ch2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream-ch2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream-ch2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,839 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "cx25821-video.h" -#include "cx25821-video-upstream-ch2.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); -MODULE_AUTHOR("Hiep Huynh "); -MODULE_LICENSE("GPL"); - -static int _intr_msk = - FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR; - -static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev, - __le32 *rp, unsigned int offset, - unsigned int bpl, u32 sync_line, - unsigned int lines, - int fifo_enable, int field_type) -{ - unsigned int line, i; - int dist_betwn_starts = bpl * 2; - - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - if (USE_RISC_NOOP_VIDEO) { - for (i = 0; i < NUM_NO_OPS; i++) - *(rp++) = cpu_to_le32(RISC_NOOP); - } - - /* scan lines */ - for (line = 0; line < lines; line++) { - *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - - if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) - || !(dev->_isNTSC_ch2)) { - offset += dist_betwn_starts; - } - } - - return rp; -} - -static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, - __le32 *rp, - dma_addr_t databuf_phys_addr, - unsigned int offset, - u32 sync_line, unsigned int bpl, - unsigned int lines, - int fifo_enable, int field_type) -{ - unsigned int line, i; - struct sram_channel *sram_ch = - dev->channels[dev->_channel2_upstream_select].sram_channels; - int dist_betwn_starts = bpl * 2; - - /* sync instruction */ - if (sync_line != NO_SYNC_LINE) - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - if (USE_RISC_NOOP_VIDEO) { - for (i = 0; i < NUM_NO_OPS; i++) - *(rp++) = cpu_to_le32(RISC_NOOP); - } - - /* scan lines */ - for (line = 0; line < lines; line++) { - *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(databuf_phys_addr + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - - if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) - || !(dev->_isNTSC_ch2)) { - offset += dist_betwn_starts; - } - - /* - check if we need to enable the FIFO after the first 4 lines - For the upstream video channel, the risc engine will enable - the FIFO. - */ - if (fifo_enable && line == 3) { - *(rp++) = RISC_WRITECR; - *(rp++) = sram_ch->dma_ctl; - *(rp++) = FLD_VID_FIFO_EN; - *(rp++) = 0x00000001; - } - } - - return rp; -} - -int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, - struct pci_dev *pci, - unsigned int top_offset, unsigned int bpl, - unsigned int lines) -{ - __le32 *rp; - int fifo_enable = 0; - int singlefield_lines = lines >> 1; /*get line count for single field */ - int odd_num_lines = singlefield_lines; - int frame = 0; - int frame_size = 0; - int databuf_offset = 0; - int risc_program_size = 0; - int risc_flag = RISC_CNT_RESET; - unsigned int bottom_offset = bpl; - dma_addr_t risc_phys_jump_addr; - - if (dev->_isNTSC_ch2) { - odd_num_lines = singlefield_lines + 1; - risc_program_size = FRAME1_VID_PROG_SIZE; - frame_size = - (bpl == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; - } else { - risc_program_size = PAL_VID_PROG_SIZE; - frame_size = - (bpl == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; - } - - /* Virtual address of Risc buffer program */ - rp = dev->_dma_virt_addr_ch2; - - for (frame = 0; frame < NUM_FRAMES; frame++) { - databuf_offset = frame_size * frame; - - if (UNSET != top_offset) { - fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; - rp = cx25821_risc_field_upstream_ch2(dev, rp, - dev-> - _data_buf_phys_addr_ch2 - + databuf_offset, - top_offset, 0, bpl, - odd_num_lines, - fifo_enable, - ODD_FIELD); - } - - fifo_enable = FIFO_DISABLE; - - /* Even field */ - rp = cx25821_risc_field_upstream_ch2(dev, rp, - dev-> - _data_buf_phys_addr_ch2 + - databuf_offset, - bottom_offset, 0x200, bpl, - singlefield_lines, - fifo_enable, EVEN_FIELD); - - if (frame == 0) { - risc_flag = RISC_CNT_RESET; - risc_phys_jump_addr = - dev->_dma_phys_start_addr_ch2 + risc_program_size; - } else { - risc_flag = RISC_CNT_INC; - risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2; - } - - /* - Loop to 2ndFrameRISC or to Start of - Risc program & generate IRQ - */ - *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); - *(rp++) = cpu_to_le32(risc_phys_jump_addr); - *(rp++) = cpu_to_le32(0); - } - - return 0; -} - -void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) -{ - struct sram_channel *sram_ch = - dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; - u32 tmp = 0; - - if (!dev->_is_running_ch2) { - pr_info("No video file is currently running so return!\n"); - return; - } - /* Disable RISC interrupts */ - tmp = cx_read(sram_ch->int_msk); - cx_write(sram_ch->int_msk, tmp & ~_intr_msk); - - /* Turn OFF risc and fifo */ - tmp = cx_read(sram_ch->dma_ctl); - cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); - - /* Clear data buffer memory */ - if (dev->_data_buf_virt_addr_ch2) - memset(dev->_data_buf_virt_addr_ch2, 0, - dev->_data_buf_size_ch2); - - dev->_is_running_ch2 = 0; - dev->_is_first_frame_ch2 = 0; - dev->_frame_count_ch2 = 0; - dev->_file_status_ch2 = END_OF_FILE; - - if (dev->_irq_queues_ch2) { - kfree(dev->_irq_queues_ch2); - dev->_irq_queues_ch2 = NULL; - } - - if (dev->_filename_ch2 != NULL) - kfree(dev->_filename_ch2); - - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); -} - -void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev) -{ - if (dev->_is_running_ch2) - cx25821_stop_upstream_video_ch2(dev); - - if (dev->_dma_virt_addr_ch2) { - pci_free_consistent(dev->pci, dev->_risc_size_ch2, - dev->_dma_virt_addr_ch2, - dev->_dma_phys_addr_ch2); - dev->_dma_virt_addr_ch2 = NULL; - } - - if (dev->_data_buf_virt_addr_ch2) { - pci_free_consistent(dev->pci, dev->_data_buf_size_ch2, - dev->_data_buf_virt_addr_ch2, - dev->_data_buf_phys_addr_ch2); - dev->_data_buf_virt_addr_ch2 = NULL; - } -} - -int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) -{ - struct file *myfile; - int frame_index_temp = dev->_frame_index_ch2; - int i = 0; - int line_size = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; - int frame_size = 0; - int frame_offset = 0; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t file_offset; - loff_t pos; - mm_segment_t old_fs; - - if (dev->_file_status_ch2 == END_OF_FILE) - return 0; - - if (dev->_isNTSC_ch2) { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; - } else { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; - } - - frame_offset = (frame_index_temp > 0) ? frame_size : 0; - file_offset = dev->_frame_count_ch2 * frame_size; - - myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_filename_ch2, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (i = 0; i < dev->_lines_count_ch2; i++) { - pos = file_offset; - - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); - - if (vfs_read_retval > 0 && vfs_read_retval == line_size - && dev->_data_buf_virt_addr_ch2 != NULL) { - memcpy((void *)(dev->_data_buf_virt_addr_ch2 + - frame_offset / 4), mybuf, - vfs_read_retval); - } - - file_offset += vfs_read_retval; - frame_offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Video file\n", - __func__); - break; - } - } - - if (i > 0) - dev->_frame_count_ch2++; - - dev->_file_status_ch2 = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - filp_close(myfile, NULL); - } - - return 0; -} - -static void cx25821_vidups_handler_ch2(struct work_struct *work) -{ - struct cx25821_dev *dev = - container_of(work, struct cx25821_dev, _irq_work_entry_ch2); - - if (!dev) { - pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", - __func__); - return; - } - - cx25821_get_frame_ch2(dev, - dev->channels[dev-> - _channel2_upstream_select].sram_channels); -} - -int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) -{ - struct file *myfile; - int i = 0, j = 0; - int line_size = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t pos; - loff_t offset = (unsigned long)0; - mm_segment_t old_fs; - - myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); - - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_filename_ch2, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered! Returning\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (j = 0; j < NUM_FRAMES; j++) { - for (i = 0; i < dev->_lines_count_ch2; i++) { - pos = offset; - - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); - - if (vfs_read_retval > 0 - && vfs_read_retval == line_size - && dev->_data_buf_virt_addr_ch2 != NULL) { - memcpy((void *)(dev-> - _data_buf_virt_addr_ch2 - + offset / 4), mybuf, - vfs_read_retval); - } - - offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Video file\n", - __func__); - break; - } - } - - if (i > 0) - dev->_frame_count_ch2++; - - if (vfs_read_retval < line_size) - break; - } - - dev->_file_status_ch2 = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - myfile->f_pos = 0; - filp_close(myfile, NULL); - } - - return 0; -} - -static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, - struct sram_channel *sram_ch, - int bpl) -{ - int ret = 0; - dma_addr_t dma_addr; - dma_addr_t data_dma_addr; - - if (dev->_dma_virt_addr_ch2 != NULL) { - pci_free_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, - dev->_dma_virt_addr_ch2, - dev->_dma_phys_addr_ch2); - } - - dev->_dma_virt_addr_ch2 = - pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, - &dma_addr); - dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2; - dev->_dma_phys_start_addr_ch2 = dma_addr; - dev->_dma_phys_addr_ch2 = dma_addr; - dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2; - - if (!dev->_dma_virt_addr_ch2) { - pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); - return -ENOMEM; - } - - /* Iniitize at this address until n bytes to 0 */ - memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2); - - if (dev->_data_buf_virt_addr_ch2 != NULL) { - pci_free_consistent(dev->pci, dev->upstream_databuf_size_ch2, - dev->_data_buf_virt_addr_ch2, - dev->_data_buf_phys_addr_ch2); - } - /* For Video Data buffer allocation */ - dev->_data_buf_virt_addr_ch2 = - pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2, - &data_dma_addr); - dev->_data_buf_phys_addr_ch2 = data_dma_addr; - dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2; - - if (!dev->_data_buf_virt_addr_ch2) { - pr_err("FAILED to allocate memory for data buffer! Returning\n"); - return -ENOMEM; - } - - /* Initialize at this address until n bytes to 0 */ - memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2); - - ret = cx25821_openfile_ch2(dev, sram_ch); - if (ret < 0) - return ret; - - /* Creating RISC programs */ - ret = - cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl, - dev->_lines_count_ch2); - if (ret < 0) { - pr_info("Failed creating Video Upstream Risc programs!\n"); - goto error; - } - - return 0; - - error: - return ret; -} - -int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num, - u32 status) -{ - u32 int_msk_tmp; - struct sram_channel *channel = dev->channels[chan_num].sram_channels; - int singlefield_lines = NTSC_FIELD_HEIGHT; - int line_size_in_bytes = Y422_LINE_SZ; - int odd_risc_prog_size = 0; - dma_addr_t risc_phys_jump_addr; - __le32 *rp; - - if (status & FLD_VID_SRC_RISC1) { - /* We should only process one program per call */ - u32 prog_cnt = cx_read(channel->gpcnt); - - /* - * Since we've identified our IRQ, clear our bits from the - * interrupt mask and interrupt status registers - */ - int_msk_tmp = cx_read(channel->int_msk); - cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); - cx_write(channel->int_stat, _intr_msk); - - spin_lock(&dev->slock); - - dev->_frame_index_ch2 = prog_cnt; - - queue_work(dev->_irq_queues_ch2, &dev->_irq_work_entry_ch2); - - if (dev->_is_first_frame_ch2) { - dev->_is_first_frame_ch2 = 0; - - if (dev->_isNTSC_ch2) { - singlefield_lines += 1; - odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; - } else { - singlefield_lines = PAL_FIELD_HEIGHT; - odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; - } - - if (dev->_dma_virt_start_addr_ch2 != NULL) { - line_size_in_bytes = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? Y411_LINE_SZ : - Y422_LINE_SZ; - risc_phys_jump_addr = - dev->_dma_phys_start_addr_ch2 + - odd_risc_prog_size; - - rp = cx25821_update_riscprogram_ch2(dev, - dev-> - _dma_virt_start_addr_ch2, - TOP_OFFSET, - line_size_in_bytes, - 0x0, - singlefield_lines, - FIFO_DISABLE, - ODD_FIELD); - - /* Jump to Even Risc program of 1st Frame */ - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc_phys_jump_addr); - *(rp++) = cpu_to_le32(0); - } - } - - spin_unlock(&dev->slock); - } - - if (dev->_file_status_ch2 == END_OF_FILE) { - pr_info("EOF Channel 2 Framecount = %d\n", - dev->_frame_count_ch2); - return -1; - } - /* ElSE, set the interrupt mask register, re-enable irq. */ - int_msk_tmp = cx_read(channel->int_msk); - cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); - - return 0; -} - -static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) -{ - struct cx25821_dev *dev = dev_id; - u32 msk_stat, vid_status; - int handled = 0; - int channel_num = 0; - struct sram_channel *sram_ch; - - if (!dev) - return -1; - - channel_num = VID_UPSTREAM_SRAM_CHANNEL_J; - sram_ch = dev->channels[channel_num].sram_channels; - - msk_stat = cx_read(sram_ch->int_mstat); - vid_status = cx_read(sram_ch->int_stat); - - /* Only deal with our interrupt */ - if (vid_status) { - handled = - cx25821_video_upstream_irq_ch2(dev, channel_num, - vid_status); - } - - if (handled < 0) - cx25821_stop_upstream_video_ch2(dev); - else - handled += handled; - - return IRQ_RETVAL(handled); -} - -static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, - struct sram_channel *ch, int pix_format) -{ - int width = WIDTH_D1; - int height = dev->_lines_count_ch2; - int num_lines, odd_num_lines; - u32 value; - int vip_mode = PIXEL_ENGINE_VIP1; - - value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); - value &= 0xFFFFFFEF; - value |= dev->_isNTSC_ch2 ? 0 : 0x10; - cx_write(ch->vid_fmt_ctl, value); - - /* - * set number of active pixels in each line. Default is 720 - * pixels in both NTSC and PAL format - */ - cx_write(ch->vid_active_ctl1, width); - - num_lines = (height / 2) & 0x3FF; - odd_num_lines = num_lines; - - if (dev->_isNTSC_ch2) - odd_num_lines += 1; - - value = (num_lines << 16) | odd_num_lines; - - /* set number of active lines in field 0 (top) and field 1 (bottom) */ - cx_write(ch->vid_active_ctl2, value); - - cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); -} - -int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, - struct sram_channel *sram_ch) -{ - u32 tmp = 0; - int err = 0; - - /* - * 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface - * for channel A-C - */ - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); - - /* - * Set the physical start address of the RISC program in the initial - * program counter(IPC) member of the cmds. - */ - cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2); - cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */ - - /* reset counter */ - cx_write(sram_ch->gpcnt_ctl, 3); - - /* Clear our bits from the interrupt status register. */ - cx_write(sram_ch->int_stat, _intr_msk); - - /* Set the interrupt mask register, enable irq. */ - cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); - tmp = cx_read(sram_ch->int_msk); - cx_write(sram_ch->int_msk, tmp |= _intr_msk); - - err = - request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, - IRQF_SHARED | IRQF_DISABLED, dev->name, dev); - if (err < 0) { - pr_err("%s: can't get upstream IRQ %d\n", - dev->name, dev->pci->irq); - goto fail_irq; - } - /* Start the DMA engine */ - tmp = cx_read(sram_ch->dma_ctl); - cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); - - dev->_is_running_ch2 = 1; - dev->_is_first_frame_ch2 = 1; - - return 0; - - fail_irq: - cx25821_dev_unregister(dev); - return err; -} - -int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, - int pixel_format) -{ - struct sram_channel *sram_ch; - u32 tmp; - int retval = 0; - int err = 0; - int data_frame_size = 0; - int risc_buffer_size = 0; - int str_length = 0; - - if (dev->_is_running_ch2) { - pr_info("Video Channel is still running so return!\n"); - return 0; - } - - dev->_channel2_upstream_select = channel_select; - sram_ch = dev->channels[channel_select].sram_channels; - - INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2); - dev->_irq_queues_ch2 = - create_singlethread_workqueue("cx25821_workqueue2"); - - if (!dev->_irq_queues_ch2) { - pr_err("create_singlethread_workqueue() for Video FAILED!\n"); - return -ENOMEM; - } - /* - * 656/VIP SRC Upstream Channel I & J and 7 - - * Host Bus Interface for channel A-C - */ - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); - - dev->_is_running_ch2 = 0; - dev->_frame_count_ch2 = 0; - dev->_file_status_ch2 = RESET_STATUS; - dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576; - dev->_pixel_format_ch2 = pixel_format; - dev->_line_size_ch2 = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; - data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; - risc_buffer_size = - dev->_isNTSC_ch2 ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; - - if (dev->input_filename_ch2) { - str_length = strlen(dev->input_filename_ch2); - dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); - - if (!dev->_filename_ch2) - goto error; - - memcpy(dev->_filename_ch2, dev->input_filename_ch2, - str_length + 1); - } else { - str_length = strlen(dev->_defaultname_ch2); - dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); - - if (!dev->_filename_ch2) - goto error; - - memcpy(dev->_filename_ch2, dev->_defaultname_ch2, - str_length + 1); - } - - /* Default if filename is empty string */ - if (strcmp(dev->input_filename_ch2, "") == 0) { - if (dev->_isNTSC_ch2) { - dev->_filename_ch2 = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? "/root/vid411.yuv" : - "/root/vidtest.yuv"; - } else { - dev->_filename_ch2 = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? "/root/pal411.yuv" : - "/root/pal422.yuv"; - } - } - - retval = - cx25821_sram_channel_setup_upstream(dev, sram_ch, - dev->_line_size_ch2, 0); - - /* setup fifo + format */ - cx25821_set_pixelengine_ch2(dev, sram_ch, dev->_pixel_format_ch2); - - dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2; - dev->upstream_databuf_size_ch2 = data_frame_size * 2; - - /* Allocating buffers and prepare RISC program */ - retval = - cx25821_upstream_buffer_prepare_ch2(dev, sram_ch, - dev->_line_size_ch2); - if (retval < 0) { - pr_err("%s: Failed to set up Video upstream buffers!\n", - dev->name); - goto error; - } - - cx25821_start_video_dma_upstream_ch2(dev, sram_ch); - - return 0; - - error: - cx25821_dev_unregister(dev); - - return err; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream-ch2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream-ch2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream-ch2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream-ch2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#define OPEN_FILE_1 0 -#define NUM_PROGS 8 -#define NUM_FRAMES 2 -#define ODD_FIELD 0 -#define EVEN_FIELD 1 -#define TOP_OFFSET 0 -#define FIFO_DISABLE 0 -#define FIFO_ENABLE 1 -#define TEST_FRAMES 5 -#define END_OF_FILE 0 -#define IN_PROGRESS 1 -#define RESET_STATUS -1 -#define NUM_NO_OPS 5 - -/* PAL and NTSC line sizes and number of lines. */ -#define WIDTH_D1 720 -#define NTSC_LINES_PER_FRAME 480 -#define PAL_LINES_PER_FRAME 576 -#define PAL_LINE_SZ 1440 -#define Y422_LINE_SZ 1440 -#define Y411_LINE_SZ 1080 -#define NTSC_FIELD_HEIGHT 240 -#define NTSC_ODD_FLD_LINES 241 -#define PAL_FIELD_HEIGHT 288 - -#define FRAME_SIZE_NTSC_Y422 (NTSC_LINES_PER_FRAME * Y422_LINE_SZ) -#define FRAME_SIZE_NTSC_Y411 (NTSC_LINES_PER_FRAME * Y411_LINE_SZ) -#define FRAME_SIZE_PAL_Y422 (PAL_LINES_PER_FRAME * Y422_LINE_SZ) -#define FRAME_SIZE_PAL_Y411 (PAL_LINES_PER_FRAME * Y411_LINE_SZ) - -#define NTSC_DATA_BUF_SZ (Y422_LINE_SZ * NTSC_LINES_PER_FRAME) -#define PAL_DATA_BUF_SZ (Y422_LINE_SZ * PAL_LINES_PER_FRAME) - -#define RISC_WRITECR_INSTRUCTION_SIZE 16 -#define RISC_SYNC_INSTRUCTION_SIZE 4 -#define JUMP_INSTRUCTION_SIZE 12 -#define MAXSIZE_NO_OPS 36 -#define DWORD_SIZE 4 - -#define USE_RISC_NOOP_VIDEO 1 - -#ifdef USE_RISC_NOOP_VIDEO -#define PAL_US_VID_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ - RISC_SYNC_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE) - -#define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) - -#define PAL_VID_PROG_SIZE ((PAL_FIELD_HEIGHT*2) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + 2*NUM_NO_OPS*DWORD_SIZE) - -#define ODD_FLD_PAL_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE) - -#define NTSC_US_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ - JUMP_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE) - -#define NTSC_RISC_BUF_SIZE (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) - -#define FRAME1_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + 2*NUM_NO_OPS*DWORD_SIZE) -#define ODD_FLD_NTSC_PROG_SIZE ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE) -#endif - -#ifndef USE_RISC_NOOP_VIDEO -#define PAL_US_VID_PROG_SIZE ((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) -#define PAL_RISC_BUF_SIZE (2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE)) -#define PAL_VID_PROG_SIZE ((PAL_FIELD_HEIGHT*2) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) -#define ODD_FLD_PAL_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) -#define ODD_FLD_NTSC_PROG_SIZE ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) -#define NTSC_US_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) -#define NTSC_RISC_BUF_SIZE (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) -#define FRAME1_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/cx25821-video-upstream.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#define OUTPUT_FRMT_656 0 -#define OPEN_FILE_1 0 -#define NUM_PROGS 8 -#define NUM_FRAMES 2 -#define ODD_FIELD 0 -#define EVEN_FIELD 1 -#define TOP_OFFSET 0 -#define FIFO_DISABLE 0 -#define FIFO_ENABLE 1 -#define TEST_FRAMES 5 -#define END_OF_FILE 0 -#define IN_PROGRESS 1 -#define RESET_STATUS -1 -#define NUM_NO_OPS 5 - -/* PAL and NTSC line sizes and number of lines. */ -#define WIDTH_D1 720 -#define NTSC_LINES_PER_FRAME 480 -#define PAL_LINES_PER_FRAME 576 -#define PAL_LINE_SZ 1440 -#define Y422_LINE_SZ 1440 -#define Y411_LINE_SZ 1080 -#define NTSC_FIELD_HEIGHT 240 -#define NTSC_ODD_FLD_LINES 241 -#define PAL_FIELD_HEIGHT 288 - -#define FRAME_SIZE_NTSC_Y422 (NTSC_LINES_PER_FRAME * Y422_LINE_SZ) -#define FRAME_SIZE_NTSC_Y411 (NTSC_LINES_PER_FRAME * Y411_LINE_SZ) -#define FRAME_SIZE_PAL_Y422 (PAL_LINES_PER_FRAME * Y422_LINE_SZ) -#define FRAME_SIZE_PAL_Y411 (PAL_LINES_PER_FRAME * Y411_LINE_SZ) - -#define NTSC_DATA_BUF_SZ (Y422_LINE_SZ * NTSC_LINES_PER_FRAME) -#define PAL_DATA_BUF_SZ (Y422_LINE_SZ * PAL_LINES_PER_FRAME) - -#define RISC_WRITECR_INSTRUCTION_SIZE 16 -#define RISC_SYNC_INSTRUCTION_SIZE 4 -#define JUMP_INSTRUCTION_SIZE 12 -#define MAXSIZE_NO_OPS 36 -#define DWORD_SIZE 4 - -#define USE_RISC_NOOP_VIDEO 1 - -#ifdef USE_RISC_NOOP_VIDEO -#define PAL_US_VID_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ - RISC_SYNC_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE) - -#define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) - -#define PAL_VID_PROG_SIZE ((PAL_FIELD_HEIGHT*2) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + 2*NUM_NO_OPS*DWORD_SIZE) - -#define ODD_FLD_PAL_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE) - -#define ODD_FLD_NTSC_PROG_SIZE ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE) - -#define NTSC_US_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ - JUMP_INSTRUCTION_SIZE + NUM_NO_OPS*DWORD_SIZE) - -#define NTSC_RISC_BUF_SIZE (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) - -#define FRAME1_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + 2*NUM_NO_OPS*DWORD_SIZE) - -#endif - -#ifndef USE_RISC_NOOP_VIDEO -#define PAL_US_VID_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ - RISC_SYNC_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) - -#define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) - -#define PAL_VID_PROG_SIZE ((PAL_FIELD_HEIGHT*2) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) - -#define ODD_FLD_PAL_PROG_SIZE ((PAL_FIELD_HEIGHT) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) -#define ODD_FLD_NTSC_PROG_SIZE ((NTSC_ODD_FLD_LINES) * 3 * DWORD_SIZE + RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) - -#define NTSC_US_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) -#define NTSC_RISC_BUF_SIZE (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) -#define FRAME1_VID_PROG_SIZE ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + 2*RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -config VIDEO_CX25821 - tristate "Conexant cx25821 support" - depends on DVB_CORE && VIDEO_DEV && PCI && I2C - select I2C_ALGOBIT - select VIDEO_BTCX - select VIDEO_TVEEPROM - depends on RC_CORE - select VIDEOBUF_DVB - select VIDEOBUF_DMA_SG - select VIDEO_CX25840 - select VIDEO_CX2341X - ---help--- - This is a video4linux driver for Conexant 25821 based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx25821 - -config VIDEO_CX25821_ALSA - tristate "Conexant 25821 DMA audio support" - depends on VIDEO_CX25821 && SND && EXPERIMENTAL - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio on - Conexant 25821 based capture cards using ALSA. - - It only works with boards with function 01 enabled. - To check if your board supports, use lspci -n. - If supported, you should see 14f1:8801 or 14f1:8811 - PCI device. - - To compile this driver as a module, choose M here: the - module will be called cx25821-alsa. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cx25821/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \ - cx25821-gpio.o cx25821-medusa-video.o \ - cx25821-video.o cx25821-video-upstream.o \ - cx25821-video-upstream-ch2.o \ - cx25821-audio-upstream.o - -obj-$(CONFIG_VIDEO_CX25821) += cx25821.o -obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o - -ccflags-y := -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners -ccflags-y += -Idrivers/media/dvb/dvb-core -ccflags-y += -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/cxd2099.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/cxd2099.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/cxd2099.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/cxd2099.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,574 +0,0 @@ -/* - * cxd2099.c: Driver for the CXD2099AR Common Interface Controller - * - * Copyright (C) 2010 DigitalDevices UG - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cxd2099.h" - -#define MAX_BUFFER_SIZE 248 - -struct cxd { - struct dvb_ca_en50221 en; - - struct i2c_adapter *i2c; - u8 adr; - u8 regs[0x23]; - u8 lastaddress; - u8 clk_reg_f; - u8 clk_reg_b; - int mode; - u32 bitrate; - int ready; - int dr; - int slot_stat; - - u8 amem[1024]; - int amem_read; - - int cammode; - struct mutex lock; -}; - -static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 data) -{ - u8 m[2] = {reg, data}; - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - printk(KERN_ERR "Failed to write to I2C register %02x@%02x!\n", - reg, adr); - return -1; - } - return 0; -} - -static int i2c_write(struct i2c_adapter *adapter, u8 adr, - u8 *data, u8 len) -{ - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - printk(KERN_ERR "Failed to write to I2C!\n"); - return -1; - } - return 0; -} - -static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *val) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1 }, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - printk(KERN_ERR "error in i2c_read_reg\n"); - return -1; - } - return 0; -} - -static int i2c_read(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *data, u8 n) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1 }, - {.addr = adr, .flags = I2C_M_RD, - .buf = data, .len = n } }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - printk(KERN_ERR "error in i2c_read\n"); - return -1; - } - return 0; -} - -static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n) -{ - int status; - - status = i2c_write_reg(ci->i2c, ci->adr, 0, adr); - if (!status) { - ci->lastaddress = adr; - status = i2c_read(ci->i2c, ci->adr, 1, data, n); - } - return status; -} - -static int read_reg(struct cxd *ci, u8 reg, u8 *val) -{ - return read_block(ci, reg, val, 1); -} - - -static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) -{ - int status; - u8 addr[3] = { 2, address&0xff, address>>8 }; - - status = i2c_write(ci->i2c, ci->adr, addr, 3); - if (!status) - status = i2c_read(ci->i2c, ci->adr, 3, data, n); - return status; -} - -static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) -{ - int status; - u8 addr[3] = { 2, address&0xff, address>>8 }; - - status = i2c_write(ci->i2c, ci->adr, addr, 3); - if (!status) { - u8 buf[256] = {3}; - memcpy(buf+1, data, n); - status = i2c_write(ci->i2c, ci->adr, buf, n+1); - } - return status; -} - -static int read_io(struct cxd *ci, u16 address, u8 *val) -{ - int status; - u8 addr[3] = { 2, address&0xff, address>>8 }; - - status = i2c_write(ci->i2c, ci->adr, addr, 3); - if (!status) - status = i2c_read(ci->i2c, ci->adr, 3, val, 1); - return status; -} - -static int write_io(struct cxd *ci, u16 address, u8 val) -{ - int status; - u8 addr[3] = { 2, address&0xff, address>>8 }; - u8 buf[2] = { 3, val }; - - status = i2c_write(ci->i2c, ci->adr, addr, 3); - if (!status) - status = i2c_write(ci->i2c, ci->adr, buf, 2); - - return status; -} - - -static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask) -{ - int status; - - status = i2c_write_reg(ci->i2c, ci->adr, 0, reg); - if (!status && reg >= 6 && reg <= 8 && mask != 0xff) - status = i2c_read_reg(ci->i2c, ci->adr, 1, &ci->regs[reg]); - ci->regs[reg] = (ci->regs[reg]&(~mask))|val; - if (!status) { - ci->lastaddress = reg; - status = i2c_write_reg(ci->i2c, ci->adr, 1, ci->regs[reg]); - } - if (reg == 0x20) - ci->regs[reg] &= 0x7f; - return status; -} - -static int write_reg(struct cxd *ci, u8 reg, u8 val) -{ - return write_regm(ci, reg, val, 0xff); -} - -#ifdef BUFFER_MODE -static int write_block(struct cxd *ci, u8 adr, u8 *data, int n) -{ - int status; - u8 buf[256] = {1}; - - status = i2c_write_reg(ci->i2c, ci->adr, 0, adr); - if (!status) { - ci->lastaddress = adr; - memcpy(buf+1, data, n); - status = i2c_write(ci->i2c, ci->adr, buf, n+1); - } - return status; -} -#endif - -static void set_mode(struct cxd *ci, int mode) -{ - if (mode == ci->mode) - return; - - switch (mode) { - case 0x00: /* IO mem */ - write_regm(ci, 0x06, 0x00, 0x07); - break; - case 0x01: /* ATT mem */ - write_regm(ci, 0x06, 0x02, 0x07); - break; - default: - break; - } - ci->mode = mode; -} - -static void cam_mode(struct cxd *ci, int mode) -{ - if (mode == ci->cammode) - return; - - switch (mode) { - case 0x00: - write_regm(ci, 0x20, 0x80, 0x80); - break; - case 0x01: - printk(KERN_INFO "enable cam buffer mode\n"); - /* write_reg(ci, 0x0d, 0x00); */ - /* write_reg(ci, 0x0e, 0x01); */ - write_regm(ci, 0x08, 0x40, 0x40); - /* read_reg(ci, 0x12, &dummy); */ - write_regm(ci, 0x08, 0x80, 0x80); - break; - default: - break; - } - ci->cammode = mode; -} - - - -#define CHK_ERROR(s) if ((status = s)) break - -static int init(struct cxd *ci) -{ - int status; - - mutex_lock(&ci->lock); - ci->mode = -1; - do { - CHK_ERROR(write_reg(ci, 0x00, 0x00)); - CHK_ERROR(write_reg(ci, 0x01, 0x00)); - CHK_ERROR(write_reg(ci, 0x02, 0x10)); - CHK_ERROR(write_reg(ci, 0x03, 0x00)); - CHK_ERROR(write_reg(ci, 0x05, 0xFF)); - CHK_ERROR(write_reg(ci, 0x06, 0x1F)); - CHK_ERROR(write_reg(ci, 0x07, 0x1F)); - CHK_ERROR(write_reg(ci, 0x08, 0x28)); - CHK_ERROR(write_reg(ci, 0x14, 0x20)); - - CHK_ERROR(write_reg(ci, 0x09, 0x4D)); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */ - CHK_ERROR(write_reg(ci, 0x0A, 0xA7)); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */ - - /* Sync detector */ - CHK_ERROR(write_reg(ci, 0x0B, 0x33)); - CHK_ERROR(write_reg(ci, 0x0C, 0x33)); - - CHK_ERROR(write_regm(ci, 0x14, 0x00, 0x0F)); - CHK_ERROR(write_reg(ci, 0x15, ci->clk_reg_b)); - CHK_ERROR(write_regm(ci, 0x16, 0x00, 0x0F)); - CHK_ERROR(write_reg(ci, 0x17, ci->clk_reg_f)); - - CHK_ERROR(write_reg(ci, 0x20, 0x28)); /* Integer Divider, Falling Edge, Internal Sync, */ - CHK_ERROR(write_reg(ci, 0x21, 0x00)); /* MCLKI = TICLK/8 */ - CHK_ERROR(write_reg(ci, 0x22, 0x07)); /* MCLKI = TICLK/8 */ - - - CHK_ERROR(write_regm(ci, 0x20, 0x80, 0x80)); /* Reset CAM state machine */ - - CHK_ERROR(write_regm(ci, 0x03, 0x02, 02)); /* Enable IREQA Interrupt */ - CHK_ERROR(write_reg(ci, 0x01, 0x04)); /* Enable CD Interrupt */ - CHK_ERROR(write_reg(ci, 0x00, 0x31)); /* Enable TS1,Hot Swap,Slot A */ - CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08)); /* Put TS in bypass */ - ci->cammode = -1; -#ifdef BUFFER_MODE - cam_mode(ci, 0); -#endif - } while (0); - mutex_unlock(&ci->lock); - - return 0; -} - - -static int read_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, int address) -{ - struct cxd *ci = ca->data; - u8 val; - mutex_lock(&ci->lock); - set_mode(ci, 1); - read_pccard(ci, address, &val, 1); - mutex_unlock(&ci->lock); - return val; -} - - -static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, - int address, u8 value) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - set_mode(ci, 1); - write_pccard(ci, address, &value, 1); - mutex_unlock(&ci->lock); - return 0; -} - -static int read_cam_control(struct dvb_ca_en50221 *ca, - int slot, u8 address) -{ - struct cxd *ci = ca->data; - u8 val; - - mutex_lock(&ci->lock); - set_mode(ci, 0); - read_io(ci, address, &val); - mutex_unlock(&ci->lock); - return val; -} - -static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, - u8 address, u8 value) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - set_mode(ci, 0); - write_io(ci, address, value); - mutex_unlock(&ci->lock); - return 0; -} - -static int slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - cam_mode(ci, 0); - write_reg(ci, 0x00, 0x21); - write_reg(ci, 0x06, 0x1F); - write_reg(ci, 0x00, 0x31); - write_regm(ci, 0x20, 0x80, 0x80); - write_reg(ci, 0x03, 0x02); - ci->ready = 0; - ci->mode = -1; - { - int i; - for (i = 0; i < 100; i++) { - msleep(10); - if (ci->ready) - break; - } - } - mutex_unlock(&ci->lock); - /* msleep(500); */ - return 0; -} - -static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - struct cxd *ci = ca->data; - - printk(KERN_INFO "slot_shutdown\n"); - mutex_lock(&ci->lock); - /* write_regm(ci, 0x09, 0x08, 0x08); */ - write_regm(ci, 0x20, 0x80, 0x80); - write_regm(ci, 0x06, 0x07, 0x07); - ci->mode = -1; - mutex_unlock(&ci->lock); - return 0; /* shutdown(ci); */ -} - -static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - write_regm(ci, 0x09, 0x00, 0x08); - set_mode(ci, 0); -#ifdef BUFFER_MODE - cam_mode(ci, 1); -#endif - mutex_unlock(&ci->lock); - return 0; -} - - -static int campoll(struct cxd *ci) -{ - u8 istat; - - read_reg(ci, 0x04, &istat); - if (!istat) - return 0; - write_reg(ci, 0x05, istat); - - if (istat&0x40) { - ci->dr = 1; - printk(KERN_INFO "DR\n"); - } - if (istat&0x20) - printk(KERN_INFO "WC\n"); - - if (istat&2) { - u8 slotstat; - - read_reg(ci, 0x01, &slotstat); - if (!(2&slotstat)) { - if (!ci->slot_stat) { - ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; - write_regm(ci, 0x03, 0x08, 0x08); - } - - } else { - if (ci->slot_stat) { - ci->slot_stat = 0; - write_regm(ci, 0x03, 0x00, 0x08); - printk(KERN_INFO "NO CAM\n"); - ci->ready = 0; - } - } - if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) { - ci->ready = 1; - ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY; - printk(KERN_INFO "READY\n"); - } - } - return 0; -} - - -static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct cxd *ci = ca->data; - u8 slotstat; - - mutex_lock(&ci->lock); - campoll(ci); - read_reg(ci, 0x01, &slotstat); - mutex_unlock(&ci->lock); - - return ci->slot_stat; -} - -#ifdef BUFFER_MODE -static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) -{ - struct cxd *ci = ca->data; - u8 msb, lsb; - u16 len; - - mutex_lock(&ci->lock); - campoll(ci); - mutex_unlock(&ci->lock); - - printk(KERN_INFO "read_data\n"); - if (!ci->dr) - return 0; - - mutex_lock(&ci->lock); - read_reg(ci, 0x0f, &msb); - read_reg(ci, 0x10, &lsb); - len = (msb<<8)|lsb; - read_block(ci, 0x12, ebuf, len); - ci->dr = 0; - mutex_unlock(&ci->lock); - - return len; -} - -static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - printk(KERN_INFO "write_data %d\n", ecount); - write_reg(ci, 0x0d, ecount>>8); - write_reg(ci, 0x0e, ecount&0xff); - write_block(ci, 0x11, ebuf, ecount); - mutex_unlock(&ci->lock); - return ecount; -} -#endif - -static struct dvb_ca_en50221 en_templ = { - .read_attribute_mem = read_attribute_mem, - .write_attribute_mem = write_attribute_mem, - .read_cam_control = read_cam_control, - .write_cam_control = write_cam_control, - .slot_reset = slot_reset, - .slot_shutdown = slot_shutdown, - .slot_ts_enable = slot_ts_enable, - .poll_slot_status = poll_slot_status, -#ifdef BUFFER_MODE - .read_data = read_data, - .write_data = write_data, -#endif - -}; - -struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, - struct i2c_adapter *i2c) -{ - struct cxd *ci = 0; - u32 bitrate = 62000000; - u8 val; - - if (i2c_read_reg(i2c, adr, 0, &val) < 0) { - printk(KERN_ERR "No CXD2099 detected at %02x\n", adr); - return 0; - } - - ci = kmalloc(sizeof(struct cxd), GFP_KERNEL); - if (!ci) - return 0; - memset(ci, 0, sizeof(*ci)); - - mutex_init(&ci->lock); - ci->i2c = i2c; - ci->adr = adr; - ci->lastaddress = 0xff; - ci->clk_reg_b = 0x4a; - ci->clk_reg_f = 0x1b; - ci->bitrate = bitrate; - - memcpy(&ci->en, &en_templ, sizeof(en_templ)); - ci->en.data = ci; - init(ci); - printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->adr); - return &ci->en; -} -EXPORT_SYMBOL(cxd2099_attach); - -MODULE_DESCRIPTION("cxd2099"); -MODULE_AUTHOR("Ralph Metzler "); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/cxd2099.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/cxd2099.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/cxd2099.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/cxd2099.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* - * cxd2099.h: Driver for the CXD2099AR Common Interface Controller - * - * Copyright (C) 2010 DigitalDevices UG - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#ifndef _CXD2099_H_ -#define _CXD2099_H_ - -#include - -#if defined(CONFIG_DVB_CXD2099) || \ - (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE)) -struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c); -#else -static inline struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -config DVB_CXD2099 - tristate "CXD2099AR Common Interface driver" - depends on DVB_CORE && PCI && I2C && DVB_NGENE - ---help--- - Support for the CI module found on cineS2 DVB-S2, supported by - the Micronas PCIe device driver (ngene). - - For now, data is passed through '/dev/dvb/adapterX/sec0': - - Encrypted data must be written to 'sec0'. - - Decrypted data can be read from 'sec0'. - - Setup the CAM using device 'ca0'. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/cxd2099/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -obj-$(CONFIG_DVB_CXD2099) += cxd2099.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-driver.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-driver.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,659 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "go7007-priv.h" -#include "wis-i2c.h" - -/* - * Wait for an interrupt to be delivered from the GO7007SB and return - * the associated value and data. - * - * Must be called with the hw_lock held. - */ -int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data) -{ - go->interrupt_available = 0; - go->hpi_ops->read_interrupt(go); - if (wait_event_timeout(go->interrupt_waitq, - go->interrupt_available, 5*HZ) < 0) { - v4l2_err(&go->v4l2_dev, "timeout waiting for read interrupt\n"); - return -1; - } - if (!go->interrupt_available) - return -1; - go->interrupt_available = 0; - *value = go->interrupt_value & 0xfffe; - *data = go->interrupt_data; - return 0; -} -EXPORT_SYMBOL(go7007_read_interrupt); - -/* - * Read a register/address on the GO7007SB. - * - * Must be called with the hw_lock held. - */ -int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data) -{ - int count = 100; - u16 value; - - if (go7007_write_interrupt(go, 0x0010, addr) < 0) - return -EIO; - while (count-- > 0) { - if (go7007_read_interrupt(go, &value, data) == 0 && - value == 0xa000) - return 0; - } - return -EIO; -} -EXPORT_SYMBOL(go7007_read_addr); - -/* - * Send the boot firmware to the encoder, which just wakes it up and lets - * us talk to the GPIO pins and on-board I2C adapter. - * - * Must be called with the hw_lock held. - */ -static int go7007_load_encoder(struct go7007 *go) -{ - const struct firmware *fw_entry; - char fw_name[] = "go7007fw.bin"; - void *bounce; - int fw_len, rv = 0; - u16 intr_val, intr_data; - - if (request_firmware(&fw_entry, fw_name, go->dev)) { - v4l2_err(go, "unable to load firmware from file " - "\"%s\"\n", fw_name); - return -1; - } - if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) { - v4l2_err(go, "file \"%s\" does not appear to be " - "go7007 firmware\n", fw_name); - release_firmware(fw_entry); - return -1; - } - fw_len = fw_entry->size - 16; - bounce = kmalloc(fw_len, GFP_KERNEL); - if (bounce == NULL) { - v4l2_err(go, "unable to allocate %d bytes for " - "firmware transfer\n", fw_len); - release_firmware(fw_entry); - return -1; - } - memcpy(bounce, fw_entry->data + 16, fw_len); - release_firmware(fw_entry); - if (go7007_interface_reset(go) < 0 || - go7007_send_firmware(go, bounce, fw_len) < 0 || - go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || - (intr_val & ~0x1) != 0x5a5a) { - v4l2_err(go, "error transferring firmware\n"); - rv = -1; - } - kfree(bounce); - return rv; -} - -MODULE_FIRMWARE("go7007fw.bin"); - -/* - * Boot the encoder and register the I2C adapter if requested. Do the - * minimum initialization necessary, since the board-specific code may - * still need to probe the board ID. - * - * Must NOT be called with the hw_lock held. - */ -int go7007_boot_encoder(struct go7007 *go, int init_i2c) -{ - int ret; - - mutex_lock(&go->hw_lock); - ret = go7007_load_encoder(go); - mutex_unlock(&go->hw_lock); - if (ret < 0) - return -1; - if (!init_i2c) - return 0; - if (go7007_i2c_init(go) < 0) - return -1; - go->i2c_adapter_online = 1; - return 0; -} -EXPORT_SYMBOL(go7007_boot_encoder); - -/* - * Configure any hardware-related registers in the GO7007, such as GPIO - * pins and bus parameters, which are board-specific. This assumes - * the boot firmware has already been downloaded. - * - * Must be called with the hw_lock held. - */ -static int go7007_init_encoder(struct go7007 *go) -{ - if (go->board_info->audio_flags & GO7007_AUDIO_I2S_MASTER) { - go7007_write_addr(go, 0x1000, 0x0811); - go7007_write_addr(go, 0x1000, 0x0c11); - } - if (go->board_id == GO7007_BOARDID_MATRIX_REV) { - /* Set GPIO pin 0 to be an output (audio clock control) */ - go7007_write_addr(go, 0x3c82, 0x0001); - go7007_write_addr(go, 0x3c80, 0x00fe); - } - return 0; -} - -/* - * Send the boot firmware to the GO7007 and configure the registers. This - * is the only way to stop the encoder once it has started streaming video. - * - * Must be called with the hw_lock held. - */ -int go7007_reset_encoder(struct go7007 *go) -{ - if (go7007_load_encoder(go) < 0) - return -1; - return go7007_init_encoder(go); -} - -/* - * Attempt to instantiate an I2C client by ID, probably loading a module. - */ -static int init_i2c_module(struct i2c_adapter *adapter, const char *type, - int addr) -{ - struct go7007 *go = i2c_get_adapdata(adapter); - struct v4l2_device *v4l2_dev = &go->v4l2_dev; - - if (v4l2_i2c_new_subdev(v4l2_dev, adapter, type, addr, NULL)) - return 0; - - printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type); - return -1; -} - -/* - * Finalize the GO7007 hardware setup, register the on-board I2C adapter - * (if used on this board), load the I2C client driver for the sensor - * (SAA7115 or whatever) and other devices, and register the ALSA and V4L2 - * interfaces. - * - * Must NOT be called with the hw_lock held. - */ -int go7007_register_encoder(struct go7007 *go) -{ - int i, ret; - - printk(KERN_INFO "go7007: registering new %s\n", go->name); - - mutex_lock(&go->hw_lock); - ret = go7007_init_encoder(go); - mutex_unlock(&go->hw_lock); - if (ret < 0) - return -1; - - /* v4l2 init must happen before i2c subdevs */ - ret = go7007_v4l2_init(go); - if (ret < 0) - return ret; - - if (!go->i2c_adapter_online && - go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) { - if (go7007_i2c_init(go) < 0) - return -1; - go->i2c_adapter_online = 1; - } - if (go->i2c_adapter_online) { - for (i = 0; i < go->board_info->num_i2c_devs; ++i) - init_i2c_module(&go->i2c_adapter, - go->board_info->i2c_devs[i].type, - go->board_info->i2c_devs[i].addr); - if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) - i2c_clients_command(&go->i2c_adapter, - DECODER_SET_CHANNEL, &go->channel_number); - } - if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) { - go->audio_enabled = 1; - go7007_snd_init(go); - } - return 0; -} -EXPORT_SYMBOL(go7007_register_encoder); - -/* - * Send the encode firmware to the encoder, which will cause it - * to immediately start delivering the video and audio streams. - * - * Must be called with the hw_lock held. - */ -int go7007_start_encoder(struct go7007 *go) -{ - u8 *fw; - int fw_len, rv = 0, i; - u16 intr_val, intr_data; - - go->modet_enable = 0; - if (!go->dvd_mode) - for (i = 0; i < 4; ++i) { - if (go->modet[i].enable) { - go->modet_enable = 1; - continue; - } - go->modet[i].pixel_threshold = 32767; - go->modet[i].motion_threshold = 32767; - go->modet[i].mb_threshold = 32767; - } - - if (go7007_construct_fw_image(go, &fw, &fw_len) < 0) - return -1; - - if (go7007_send_firmware(go, fw, fw_len) < 0 || - go7007_read_interrupt(go, &intr_val, &intr_data) < 0) { - v4l2_err(&go->v4l2_dev, "error transferring firmware\n"); - rv = -1; - goto start_error; - } - - go->state = STATE_DATA; - go->parse_length = 0; - go->seen_frame = 0; - if (go7007_stream_start(go) < 0) { - v4l2_err(&go->v4l2_dev, "error starting stream transfer\n"); - rv = -1; - goto start_error; - } - -start_error: - kfree(fw); - return rv; -} - -/* - * Store a byte in the current video buffer, if there is one. - */ -static inline void store_byte(struct go7007_buffer *gobuf, u8 byte) -{ - if (gobuf != NULL && gobuf->bytesused < GO7007_BUF_SIZE) { - unsigned int pgidx = gobuf->offset >> PAGE_SHIFT; - unsigned int pgoff = gobuf->offset & ~PAGE_MASK; - - *((u8 *)page_address(gobuf->pages[pgidx]) + pgoff) = byte; - ++gobuf->offset; - ++gobuf->bytesused; - } -} - -/* - * Deliver the last video buffer and get a new one to start writing to. - */ -static void frame_boundary(struct go7007 *go) -{ - struct go7007_buffer *gobuf; - int i; - - if (go->active_buf) { - if (go->active_buf->modet_active) { - if (go->active_buf->bytesused + 216 < GO7007_BUF_SIZE) { - for (i = 0; i < 216; ++i) - store_byte(go->active_buf, - go->active_map[i]); - go->active_buf->bytesused -= 216; - } else - go->active_buf->modet_active = 0; - } - go->active_buf->state = BUF_STATE_DONE; - wake_up_interruptible(&go->frame_waitq); - go->active_buf = NULL; - } - list_for_each_entry(gobuf, &go->stream, stream) - if (gobuf->state == BUF_STATE_QUEUED) { - gobuf->seq = go->next_seq; - do_gettimeofday(&gobuf->timestamp); - go->active_buf = gobuf; - break; - } - ++go->next_seq; -} - -static void write_bitmap_word(struct go7007 *go) -{ - int x, y, i, stride = ((go->width >> 4) + 7) >> 3; - - for (i = 0; i < 16; ++i) { - y = (((go->parse_length - 1) << 3) + i) / (go->width >> 4); - x = (((go->parse_length - 1) << 3) + i) % (go->width >> 4); - if (stride * y + (x >> 3) < sizeof(go->active_map)) - go->active_map[stride * y + (x >> 3)] |= - (go->modet_word & 1) << (x & 0x7); - go->modet_word >>= 1; - } -} - -/* - * Parse a chunk of the video stream into frames. The frames are not - * delimited by the hardware, so we have to parse the frame boundaries - * based on the type of video stream we're receiving. - */ -void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) -{ - int i, seq_start_code = -1, frame_start_code = -1; - - spin_lock(&go->spinlock); - - switch (go->format) { - case GO7007_FORMAT_MPEG4: - seq_start_code = 0xB0; - frame_start_code = 0xB6; - break; - case GO7007_FORMAT_MPEG1: - case GO7007_FORMAT_MPEG2: - seq_start_code = 0xB3; - frame_start_code = 0x00; - break; - } - - for (i = 0; i < length; ++i) { - if (go->active_buf != NULL && - go->active_buf->bytesused >= GO7007_BUF_SIZE - 3) { - v4l2_info(&go->v4l2_dev, "dropping oversized frame\n"); - go->active_buf->offset -= go->active_buf->bytesused; - go->active_buf->bytesused = 0; - go->active_buf->modet_active = 0; - go->active_buf = NULL; - } - - switch (go->state) { - case STATE_DATA: - switch (buf[i]) { - case 0x00: - go->state = STATE_00; - break; - case 0xFF: - go->state = STATE_FF; - break; - default: - store_byte(go->active_buf, buf[i]); - break; - } - break; - case STATE_00: - switch (buf[i]) { - case 0x00: - go->state = STATE_00_00; - break; - case 0xFF: - store_byte(go->active_buf, 0x00); - go->state = STATE_FF; - break; - default: - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, buf[i]); - go->state = STATE_DATA; - break; - } - break; - case STATE_00_00: - switch (buf[i]) { - case 0x00: - store_byte(go->active_buf, 0x00); - /* go->state remains STATE_00_00 */ - break; - case 0x01: - go->state = STATE_00_00_01; - break; - case 0xFF: - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); - go->state = STATE_FF; - break; - default: - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, buf[i]); - go->state = STATE_DATA; - break; - } - break; - case STATE_00_00_01: - if (buf[i] == 0xF8 && go->modet_enable == 0) { - /* MODET start code, but MODET not enabled */ - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x01); - store_byte(go->active_buf, 0xF8); - go->state = STATE_DATA; - break; - } - /* If this is the start of a new MPEG frame, - * get a new buffer */ - if ((go->format == GO7007_FORMAT_MPEG1 || - go->format == GO7007_FORMAT_MPEG2 || - go->format == GO7007_FORMAT_MPEG4) && - (buf[i] == seq_start_code || - buf[i] == 0xB8 || /* GOP code */ - buf[i] == frame_start_code)) { - if (go->active_buf == NULL || go->seen_frame) - frame_boundary(go); - if (buf[i] == frame_start_code) { - if (go->active_buf != NULL) - go->active_buf->frame_offset = - go->active_buf->offset; - go->seen_frame = 1; - } else { - go->seen_frame = 0; - } - } - /* Handle any special chunk types, or just write the - * start code to the (potentially new) buffer */ - switch (buf[i]) { - case 0xF5: /* timestamp */ - go->parse_length = 12; - go->state = STATE_UNPARSED; - break; - case 0xF6: /* vbi */ - go->state = STATE_VBI_LEN_A; - break; - case 0xF8: /* MD map */ - go->parse_length = 0; - memset(go->active_map, 0, - sizeof(go->active_map)); - go->state = STATE_MODET_MAP; - break; - case 0xFF: /* Potential JPEG start code */ - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x01); - go->state = STATE_FF; - break; - default: - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x01); - store_byte(go->active_buf, buf[i]); - go->state = STATE_DATA; - break; - } - break; - case STATE_FF: - switch (buf[i]) { - case 0x00: - store_byte(go->active_buf, 0xFF); - go->state = STATE_00; - break; - case 0xFF: - store_byte(go->active_buf, 0xFF); - /* go->state remains STATE_FF */ - break; - case 0xD8: - if (go->format == GO7007_FORMAT_MJPEG) - frame_boundary(go); - /* fall through */ - default: - store_byte(go->active_buf, 0xFF); - store_byte(go->active_buf, buf[i]); - go->state = STATE_DATA; - break; - } - break; - case STATE_VBI_LEN_A: - go->parse_length = buf[i] << 8; - go->state = STATE_VBI_LEN_B; - break; - case STATE_VBI_LEN_B: - go->parse_length |= buf[i]; - if (go->parse_length > 0) - go->state = STATE_UNPARSED; - else - go->state = STATE_DATA; - break; - case STATE_MODET_MAP: - if (go->parse_length < 204) { - if (go->parse_length & 1) { - go->modet_word |= buf[i]; - write_bitmap_word(go); - } else - go->modet_word = buf[i] << 8; - } else if (go->parse_length == 207 && go->active_buf) { - go->active_buf->modet_active = buf[i]; - } - if (++go->parse_length == 208) - go->state = STATE_DATA; - break; - case STATE_UNPARSED: - if (--go->parse_length == 0) - go->state = STATE_DATA; - break; - } - } - - spin_unlock(&go->spinlock); -} -EXPORT_SYMBOL(go7007_parse_video_stream); - -/* - * Allocate a new go7007 struct. Used by the hardware-specific probe. - */ -struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) -{ - struct go7007 *go; - int i; - - go = kmalloc(sizeof(struct go7007), GFP_KERNEL); - if (go == NULL) - return NULL; - go->dev = dev; - go->board_info = board; - go->board_id = 0; - go->tuner_type = -1; - go->channel_number = 0; - go->name[0] = 0; - mutex_init(&go->hw_lock); - init_waitqueue_head(&go->frame_waitq); - spin_lock_init(&go->spinlock); - go->video_dev = NULL; - go->ref_count = 0; - go->status = STATUS_INIT; - memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter)); - go->i2c_adapter_online = 0; - go->interrupt_available = 0; - init_waitqueue_head(&go->interrupt_waitq); - go->in_use = 0; - go->input = 0; - if (board->sensor_flags & GO7007_SENSOR_TV) { - go->standard = GO7007_STD_NTSC; - go->width = 720; - go->height = 480; - go->sensor_framerate = 30000; - } else { - go->standard = GO7007_STD_OTHER; - go->width = board->sensor_width; - go->height = board->sensor_height; - go->sensor_framerate = board->sensor_framerate; - } - go->encoder_v_offset = board->sensor_v_offset; - go->encoder_h_offset = board->sensor_h_offset; - go->encoder_h_halve = 0; - go->encoder_v_halve = 0; - go->encoder_subsample = 0; - go->streaming = 0; - go->format = GO7007_FORMAT_MJPEG; - go->bitrate = 1500000; - go->fps_scale = 1; - go->pali = 0; - go->aspect_ratio = GO7007_RATIO_1_1; - go->gop_size = 0; - go->ipb = 0; - go->closed_gop = 0; - go->repeat_seqhead = 0; - go->seq_header_enable = 0; - go->gop_header_enable = 0; - go->dvd_mode = 0; - go->interlace_coding = 0; - for (i = 0; i < 4; ++i) - go->modet[i].enable = 0; - for (i = 0; i < 1624; ++i) - go->modet_map[i] = 0; - go->audio_deliver = NULL; - go->audio_enabled = 0; - INIT_LIST_HEAD(&go->stream); - - return go; -} -EXPORT_SYMBOL(go7007_alloc); - -/* - * Detach and unregister the encoder. The go7007 struct won't be freed - * until v4l2 finishes releasing its resources and all associated fds are - * closed by applications. - */ -void go7007_remove(struct go7007 *go) -{ - if (go->i2c_adapter_online) { - if (i2c_del_adapter(&go->i2c_adapter) == 0) - go->i2c_adapter_online = 0; - else - v4l2_err(&go->v4l2_dev, - "error removing I2C adapter!\n"); - } - - if (go->audio_enabled) - go7007_snd_remove(go); - go7007_v4l2_remove(go); -} -EXPORT_SYMBOL(go7007_remove); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-fw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-fw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-fw.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-fw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1636 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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. - */ - -/* - * This file contains code to generate a firmware image for the GO7007SB - * encoder. Much of the firmware is read verbatim from a file, but some of - * it concerning bitrate control and other things that can be configured at - * run-time are generated dynamically. Note that the format headers - * generated here do not affect the functioning of the encoder; they are - * merely parroted back to the host at the start of each frame. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "go7007-priv.h" - -/* Constants used in the source firmware image to describe code segments */ - -#define FLAG_MODE_MJPEG (1) -#define FLAG_MODE_MPEG1 (1<<1) -#define FLAG_MODE_MPEG2 (1<<2) -#define FLAG_MODE_MPEG4 (1<<3) -#define FLAG_MODE_H263 (1<<4) -#define FLAG_MODE_ALL (FLAG_MODE_MJPEG | FLAG_MODE_MPEG1 | \ - FLAG_MODE_MPEG2 | FLAG_MODE_MPEG4 | \ - FLAG_MODE_H263) -#define FLAG_SPECIAL (1<<8) - -#define SPECIAL_FRM_HEAD 0 -#define SPECIAL_BRC_CTRL 1 -#define SPECIAL_CONFIG 2 -#define SPECIAL_SEQHEAD 3 -#define SPECIAL_AV_SYNC 4 -#define SPECIAL_FINAL 5 -#define SPECIAL_AUDIO 6 -#define SPECIAL_MODET 7 - -/* Little data class for creating MPEG headers bit-by-bit */ - -struct code_gen { - unsigned char *p; /* destination */ - u32 a; /* collects bits at the top of the variable */ - int b; /* bit position of most recently-written bit */ - int len; /* written out so far */ -}; - -#define CODE_GEN(name, dest) struct code_gen name = { dest, 0, 32, 0 } - -#define CODE_ADD(name, val, length) do { \ - name.b -= (length); \ - name.a |= (val) << name.b; \ - while (name.b <= 24) { \ - *name.p = name.a >> 24; \ - ++name.p; \ - name.a <<= 8; \ - name.b += 8; \ - name.len += 8; \ - } \ -} while (0) - -#define CODE_LENGTH(name) (name.len + (32 - name.b)) - -/* Tables for creating the bitrate control data */ - -static const s16 converge_speed_ip[101] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, - 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, - 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, - 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, - 19, 20, 22, 23, 25, 27, 30, 32, 35, 38, - 41, 45, 49, 53, 58, 63, 69, 76, 83, 91, - 100 -}; - -static const s16 converge_speed_ipb[101] = { - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, - 6, 6, 6, 7, 7, 7, 7, 8, 8, 9, - 9, 9, 10, 10, 11, 12, 12, 13, 14, 14, - 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, - 28, 30, 32, 34, 37, 40, 42, 46, 49, 53, - 57, 61, 66, 71, 77, 83, 90, 97, 106, 115, - 125, 135, 147, 161, 175, 191, 209, 228, 249, 273, - 300 -}; - -static const s16 LAMBDA_table[4][101] = { - { 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, - 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, - 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, - 27, 27, 28, 28, 29, 29, 30, 31, 31, 32, - 32, 33, 33, 34, 35, 35, 36, 37, 37, 38, - 39, 39, 40, 41, 42, 42, 43, 44, 45, 46, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 67, 68, 69, 70, 72, 73, 74, 76, 77, 78, - 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, - 96 - }, - { - 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, - 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, - 28, 29, 29, 30, 30, 31, 31, 32, 33, 33, - 34, 34, 35, 36, 36, 37, 38, 38, 39, 40, - 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, - 70, 71, 72, 73, 75, 76, 78, 79, 80, 82, - 83, 85, 86, 88, 90, 91, 93, 95, 96, 98, - 100, 102, 103, 105, 107, 109, 111, 113, 115, 117, - 120 - }, - { - 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, - 28, 29, 29, 30, 30, 31, 31, 32, 33, 33, - 34, 34, 35, 36, 36, 37, 38, 38, 39, 40, - 41, 41, 42, 43, 44, 44, 45, 46, 47, 48, - 49, 50, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 62, 63, 64, 65, 66, 67, 69, - 70, 71, 72, 74, 75, 76, 78, 79, 81, 82, - 84, 85, 87, 88, 90, 92, 93, 95, 97, 98, - 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, - 120, 122, 124, 127, 129, 131, 134, 136, 138, 141, - 144 - }, - { - 32, 32, 33, 33, 34, 34, 35, 36, 36, 37, - 38, 38, 39, 40, 41, 41, 42, 43, 44, 44, - 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 62, 63, 64, - 65, 66, 67, 69, 70, 71, 72, 74, 75, 76, - 78, 79, 81, 82, 84, 85, 87, 88, 90, 92, - 93, 95, 97, 98, 100, 102, 104, 106, 108, 110, - 112, 114, 116, 118, 120, 122, 124, 127, 129, 131, - 134, 136, 139, 141, 144, 146, 149, 152, 154, 157, - 160, 163, 166, 169, 172, 175, 178, 181, 185, 188, - 192 - } -}; - -/* MPEG blank frame generation tables */ - -enum mpeg_frame_type { - PFRAME, - BFRAME_PRE, - BFRAME_POST, - BFRAME_BIDIR, - BFRAME_EMPTY -}; - -static const u32 addrinctab[33][2] = { - { 0x01, 1 }, { 0x03, 3 }, { 0x02, 3 }, { 0x03, 4 }, - { 0x02, 4 }, { 0x03, 5 }, { 0x02, 5 }, { 0x07, 7 }, - { 0x06, 7 }, { 0x0b, 8 }, { 0x0a, 8 }, { 0x09, 8 }, - { 0x08, 8 }, { 0x07, 8 }, { 0x06, 8 }, { 0x17, 10 }, - { 0x16, 10 }, { 0x15, 10 }, { 0x14, 10 }, { 0x13, 10 }, - { 0x12, 10 }, { 0x23, 11 }, { 0x22, 11 }, { 0x21, 11 }, - { 0x20, 11 }, { 0x1f, 11 }, { 0x1e, 11 }, { 0x1d, 11 }, - { 0x1c, 11 }, { 0x1b, 11 }, { 0x1a, 11 }, { 0x19, 11 }, - { 0x18, 11 } -}; - -/* Standard JPEG tables */ - -static const u8 default_intra_quant_table[] = { - 8, 16, 19, 22, 26, 27, 29, 34, - 16, 16, 22, 24, 27, 29, 34, 37, - 19, 22, 26, 27, 29, 34, 34, 38, - 22, 22, 26, 27, 29, 34, 37, 40, - 22, 26, 27, 29, 32, 35, 40, 48, - 26, 27, 29, 32, 35, 40, 48, 58, - 26, 27, 29, 34, 38, 46, 56, 69, - 27, 29, 35, 38, 46, 56, 69, 83 -}; - -static const u8 bits_dc_luminance[] = { - 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 -}; - -static const u8 val_dc_luminance[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 -}; - -static const u8 bits_dc_chrominance[] = { - 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 -}; - -static const u8 val_dc_chrominance[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 -}; - -static const u8 bits_ac_luminance[] = { - 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d -}; - -static const u8 val_ac_luminance[] = { - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa -}; - -static const u8 bits_ac_chrominance[] = { - 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 -}; - -static const u8 val_ac_chrominance[] = { - 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, - 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, - 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, - 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, - 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa -}; - -/* Zig-zag mapping for quant table - * - * OK, let's do this mapping on the actual table above so it doesn't have - * to be done on the fly. - */ -static const int zz[64] = { - 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 -}; - -static int copy_packages(__le16 *dest, u16 *src, int pkg_cnt, int space) -{ - int i, cnt = pkg_cnt * 32; - - if (space < cnt) - return -1; - - for (i = 0; i < cnt; ++i) - dest[i] = cpu_to_le16p(src + i); - - return cnt; -} - -static int mjpeg_frame_header(struct go7007 *go, unsigned char *buf, int q) -{ - int i, p = 0; - - buf[p++] = 0xff; - buf[p++] = 0xd8; - buf[p++] = 0xff; - buf[p++] = 0xdb; - buf[p++] = 0; - buf[p++] = 2 + 65; - buf[p++] = 0; - buf[p++] = default_intra_quant_table[0]; - for (i = 1; i < 64; ++i) - /* buf[p++] = (default_intra_quant_table[i] * q) >> 3; */ - buf[p++] = (default_intra_quant_table[zz[i]] * q) >> 3; - buf[p++] = 0xff; - buf[p++] = 0xc0; - buf[p++] = 0; - buf[p++] = 17; - buf[p++] = 8; - buf[p++] = go->height >> 8; - buf[p++] = go->height & 0xff; - buf[p++] = go->width >> 8; - buf[p++] = go->width & 0xff; - buf[p++] = 3; - buf[p++] = 1; - buf[p++] = 0x22; - buf[p++] = 0; - buf[p++] = 2; - buf[p++] = 0x11; - buf[p++] = 0; - buf[p++] = 3; - buf[p++] = 0x11; - buf[p++] = 0; - buf[p++] = 0xff; - buf[p++] = 0xc4; - buf[p++] = 418 >> 8; - buf[p++] = 418 & 0xff; - buf[p++] = 0x00; - memcpy(buf + p, bits_dc_luminance + 1, 16); - p += 16; - memcpy(buf + p, val_dc_luminance, sizeof(val_dc_luminance)); - p += sizeof(val_dc_luminance); - buf[p++] = 0x01; - memcpy(buf + p, bits_dc_chrominance + 1, 16); - p += 16; - memcpy(buf + p, val_dc_chrominance, sizeof(val_dc_chrominance)); - p += sizeof(val_dc_chrominance); - buf[p++] = 0x10; - memcpy(buf + p, bits_ac_luminance + 1, 16); - p += 16; - memcpy(buf + p, val_ac_luminance, sizeof(val_ac_luminance)); - p += sizeof(val_ac_luminance); - buf[p++] = 0x11; - memcpy(buf + p, bits_ac_chrominance + 1, 16); - p += 16; - memcpy(buf + p, val_ac_chrominance, sizeof(val_ac_chrominance)); - p += sizeof(val_ac_chrominance); - buf[p++] = 0xff; - buf[p++] = 0xda; - buf[p++] = 0; - buf[p++] = 12; - buf[p++] = 3; - buf[p++] = 1; - buf[p++] = 0x00; - buf[p++] = 2; - buf[p++] = 0x11; - buf[p++] = 3; - buf[p++] = 0x11; - buf[p++] = 0; - buf[p++] = 63; - buf[p++] = 0; - return p; -} - -static int gen_mjpeghdr_to_package(struct go7007 *go, __le16 *code, int space) -{ - u8 *buf; - u16 mem = 0x3e00; - unsigned int addr = 0x19; - int size = 0, i, off = 0, chunk; - - buf = kzalloc(4096, GFP_KERNEL); - if (buf == NULL) { - printk(KERN_ERR "go7007: unable to allocate 4096 bytes for " - "firmware construction\n"); - return -1; - } - - for (i = 1; i < 32; ++i) { - mjpeg_frame_header(go, buf + size, i); - size += 80; - } - chunk = mjpeg_frame_header(go, buf + size, 1); - memmove(buf + size, buf + size + 80, chunk - 80); - size += chunk - 80; - - for (i = 0; i < size; i += chunk * 2) { - if (space - off < 32) { - off = -1; - goto done; - } - - code[off + 1] = __cpu_to_le16(0x8000 | mem); - - chunk = 28; - if (mem + chunk > 0x4000) - chunk = 0x4000 - mem; - if (i + 2 * chunk > size) - chunk = (size - i) / 2; - - if (chunk < 28) { - code[off] = __cpu_to_le16(0x4000 | chunk); - code[off + 31] = __cpu_to_le16(addr++); - mem = 0x3e00; - } else { - code[off] = __cpu_to_le16(0x1000 | 28); - code[off + 31] = 0; - mem += 28; - } - - memcpy(&code[off + 2], buf + i, chunk * 2); - off += 32; - } -done: - kfree(buf); - return off; -} - -static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf, - int modulo, int pict_struct, enum mpeg_frame_type frame) -{ - int i, j, mb_code, mb_len; - int rows = go->interlace_coding ? go->height / 32 : go->height / 16; - CODE_GEN(c, buf + 6); - - switch (frame) { - case PFRAME: - mb_code = 0x1; - mb_len = 3; - break; - case BFRAME_PRE: - mb_code = 0x2; - mb_len = 4; - break; - case BFRAME_POST: - mb_code = 0x2; - mb_len = 3; - break; - case BFRAME_BIDIR: - mb_code = 0x2; - mb_len = 2; - break; - default: /* keep the compiler happy */ - mb_code = mb_len = 0; - break; - } - - CODE_ADD(c, frame == PFRAME ? 0x2 : 0x3, 13); - CODE_ADD(c, 0xffff, 16); - CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4); - if (frame != PFRAME) - CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4); - else - CODE_ADD(c, 0, 4); /* Is this supposed to be here?? */ - CODE_ADD(c, 0, 3); /* What is this?? */ - /* Byte-align with zeros */ - j = 8 - (CODE_LENGTH(c) % 8); - if (j != 8) - CODE_ADD(c, 0, j); - - if (go->format == GO7007_FORMAT_MPEG2) { - CODE_ADD(c, 0x1, 24); - CODE_ADD(c, 0xb5, 8); - CODE_ADD(c, 0x844, 12); - CODE_ADD(c, frame == PFRAME ? 0xff : 0x44, 8); - if (go->interlace_coding) { - CODE_ADD(c, pict_struct, 4); - if (go->dvd_mode) - CODE_ADD(c, 0x000, 11); - else - CODE_ADD(c, 0x200, 11); - } else { - CODE_ADD(c, 0x3, 4); - CODE_ADD(c, 0x20c, 11); - } - /* Byte-align with zeros */ - j = 8 - (CODE_LENGTH(c) % 8); - if (j != 8) - CODE_ADD(c, 0, j); - } - - for (i = 0; i < rows; ++i) { - CODE_ADD(c, 1, 24); - CODE_ADD(c, i + 1, 8); - CODE_ADD(c, 0x2, 6); - CODE_ADD(c, 0x1, 1); - CODE_ADD(c, mb_code, mb_len); - if (go->interlace_coding) { - CODE_ADD(c, 0x1, 2); - CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); - } - if (frame == BFRAME_BIDIR) { - CODE_ADD(c, 0x3, 2); - if (go->interlace_coding) - CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); - } - CODE_ADD(c, 0x3, 2); - for (j = (go->width >> 4) - 2; j >= 33; j -= 33) - CODE_ADD(c, 0x8, 11); - CODE_ADD(c, addrinctab[j][0], addrinctab[j][1]); - CODE_ADD(c, mb_code, mb_len); - if (go->interlace_coding) { - CODE_ADD(c, 0x1, 2); - CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); - } - if (frame == BFRAME_BIDIR) { - CODE_ADD(c, 0x3, 2); - if (go->interlace_coding) - CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); - } - CODE_ADD(c, 0x3, 2); - - /* Byte-align with zeros */ - j = 8 - (CODE_LENGTH(c) % 8); - if (j != 8) - CODE_ADD(c, 0, j); - } - - i = CODE_LENGTH(c) + 4 * 8; - buf[2] = 0x00; - buf[3] = 0x00; - buf[4] = 0x01; - buf[5] = 0x00; - return i; -} - -static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext) -{ - int i, aspect_ratio, picture_rate; - CODE_GEN(c, buf + 6); - - if (go->format == GO7007_FORMAT_MPEG1) { - switch (go->aspect_ratio) { - case GO7007_RATIO_4_3: - aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2; - break; - case GO7007_RATIO_16_9: - aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4; - break; - default: - aspect_ratio = 1; - break; - } - } else { - switch (go->aspect_ratio) { - case GO7007_RATIO_4_3: - aspect_ratio = 2; - break; - case GO7007_RATIO_16_9: - aspect_ratio = 3; - break; - default: - aspect_ratio = 1; - break; - } - } - switch (go->sensor_framerate) { - case 24000: - picture_rate = 1; - break; - case 24024: - picture_rate = 2; - break; - case 25025: - picture_rate = go->interlace_coding ? 6 : 3; - break; - case 30000: - picture_rate = go->interlace_coding ? 7 : 4; - break; - case 30030: - picture_rate = go->interlace_coding ? 8 : 5; - break; - default: - picture_rate = 5; /* 30 fps seems like a reasonable default */ - break; - } - - CODE_ADD(c, go->width, 12); - CODE_ADD(c, go->height, 12); - CODE_ADD(c, aspect_ratio, 4); - CODE_ADD(c, picture_rate, 4); - CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 20000 : 0x3ffff, 18); - CODE_ADD(c, 1, 1); - CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 112 : 20, 10); - CODE_ADD(c, 0, 3); - - /* Byte-align with zeros */ - i = 8 - (CODE_LENGTH(c) % 8); - if (i != 8) - CODE_ADD(c, 0, i); - - if (go->format == GO7007_FORMAT_MPEG2) { - CODE_ADD(c, 0x1, 24); - CODE_ADD(c, 0xb5, 8); - CODE_ADD(c, 0x148, 12); - if (go->interlace_coding) - CODE_ADD(c, 0x20001, 20); - else - CODE_ADD(c, 0xa0001, 20); - CODE_ADD(c, 0, 16); - - /* Byte-align with zeros */ - i = 8 - (CODE_LENGTH(c) % 8); - if (i != 8) - CODE_ADD(c, 0, i); - - if (ext) { - CODE_ADD(c, 0x1, 24); - CODE_ADD(c, 0xb52, 12); - CODE_ADD(c, go->standard == GO7007_STD_NTSC ? 2 : 1, 3); - CODE_ADD(c, 0x105, 9); - CODE_ADD(c, 0x505, 16); - CODE_ADD(c, go->width, 14); - CODE_ADD(c, 1, 1); - CODE_ADD(c, go->height, 14); - - /* Byte-align with zeros */ - i = 8 - (CODE_LENGTH(c) % 8); - if (i != 8) - CODE_ADD(c, 0, i); - } - } - - i = CODE_LENGTH(c) + 4 * 8; - buf[0] = i & 0xff; - buf[1] = i >> 8; - buf[2] = 0x00; - buf[3] = 0x00; - buf[4] = 0x01; - buf[5] = 0xb3; - return i; -} - -static int gen_mpeg1hdr_to_package(struct go7007 *go, - __le16 *code, int space, int *framelen) -{ - u8 *buf; - u16 mem = 0x3e00; - unsigned int addr = 0x19; - int i, off = 0, chunk; - - buf = kzalloc(5120, GFP_KERNEL); - if (buf == NULL) { - printk(KERN_ERR "go7007: unable to allocate 5120 bytes for " - "firmware construction\n"); - return -1; - } - framelen[0] = mpeg1_frame_header(go, buf, 0, 1, PFRAME); - if (go->interlace_coding) - framelen[0] += mpeg1_frame_header(go, buf + framelen[0] / 8, - 0, 2, PFRAME); - buf[0] = framelen[0] & 0xff; - buf[1] = framelen[0] >> 8; - i = 368; - framelen[1] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_PRE); - if (go->interlace_coding) - framelen[1] += mpeg1_frame_header(go, buf + i + framelen[1] / 8, - 0, 2, BFRAME_PRE); - buf[i] = framelen[1] & 0xff; - buf[i + 1] = framelen[1] >> 8; - i += 1632; - framelen[2] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_POST); - if (go->interlace_coding) - framelen[2] += mpeg1_frame_header(go, buf + i + framelen[2] / 8, - 0, 2, BFRAME_POST); - buf[i] = framelen[2] & 0xff; - buf[i + 1] = framelen[2] >> 8; - i += 1432; - framelen[3] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_BIDIR); - if (go->interlace_coding) - framelen[3] += mpeg1_frame_header(go, buf + i + framelen[3] / 8, - 0, 2, BFRAME_BIDIR); - buf[i] = framelen[3] & 0xff; - buf[i + 1] = framelen[3] >> 8; - i += 1632 + 16; - mpeg1_sequence_header(go, buf + i, 0); - i += 40; - for (i = 0; i < 5120; i += chunk * 2) { - if (space - off < 32) { - off = -1; - goto done; - } - - code[off + 1] = __cpu_to_le16(0x8000 | mem); - - chunk = 28; - if (mem + chunk > 0x4000) - chunk = 0x4000 - mem; - if (i + 2 * chunk > 5120) - chunk = (5120 - i) / 2; - - if (chunk < 28) { - code[off] = __cpu_to_le16(0x4000 | chunk); - code[off + 31] = __cpu_to_le16(addr); - if (mem + chunk == 0x4000) { - mem = 0x3e00; - ++addr; - } - } else { - code[off] = __cpu_to_le16(0x1000 | 28); - code[off + 31] = 0; - mem += 28; - } - - memcpy(&code[off + 2], buf + i, chunk * 2); - off += 32; - } -done: - kfree(buf); - return off; -} - -static int vti_bitlen(struct go7007 *go) -{ - unsigned int i, max_time_incr = go->sensor_framerate / go->fps_scale; - - for (i = 31; (max_time_incr & ((1 << i) - 1)) == max_time_incr; --i); - return i + 1; -} - -static int mpeg4_frame_header(struct go7007 *go, unsigned char *buf, - int modulo, enum mpeg_frame_type frame) -{ - int i; - CODE_GEN(c, buf + 6); - int mb_count = (go->width >> 4) * (go->height >> 4); - - CODE_ADD(c, frame == PFRAME ? 0x1 : 0x2, 2); - if (modulo) - CODE_ADD(c, 0x1, 1); - CODE_ADD(c, 0x1, 2); - CODE_ADD(c, 0, vti_bitlen(go)); - CODE_ADD(c, 0x3, 2); - if (frame == PFRAME) - CODE_ADD(c, 0, 1); - CODE_ADD(c, 0xc, 11); - if (frame != PFRAME) - CODE_ADD(c, 0x4, 3); - if (frame != BFRAME_EMPTY) { - for (i = 0; i < mb_count; ++i) { - switch (frame) { - case PFRAME: - CODE_ADD(c, 0x1, 1); - break; - case BFRAME_PRE: - CODE_ADD(c, 0x47, 8); - break; - case BFRAME_POST: - CODE_ADD(c, 0x27, 7); - break; - case BFRAME_BIDIR: - CODE_ADD(c, 0x5f, 8); - break; - case BFRAME_EMPTY: /* keep compiler quiet */ - break; - } - } - } - - /* Byte-align with a zero followed by ones */ - i = 8 - (CODE_LENGTH(c) % 8); - CODE_ADD(c, 0, 1); - CODE_ADD(c, (1 << (i - 1)) - 1, i - 1); - - i = CODE_LENGTH(c) + 4 * 8; - buf[0] = i & 0xff; - buf[1] = i >> 8; - buf[2] = 0x00; - buf[3] = 0x00; - buf[4] = 0x01; - buf[5] = 0xb6; - return i; -} - -static int mpeg4_sequence_header(struct go7007 *go, unsigned char *buf, int ext) -{ - const unsigned char head[] = { 0x00, 0x00, 0x01, 0xb0, go->pali, - 0x00, 0x00, 0x01, 0xb5, 0x09, - 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x20, }; - int i, aspect_ratio; - int fps = go->sensor_framerate / go->fps_scale; - CODE_GEN(c, buf + 2 + sizeof(head)); - - switch (go->aspect_ratio) { - case GO7007_RATIO_4_3: - aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2; - break; - case GO7007_RATIO_16_9: - aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4; - break; - default: - aspect_ratio = 1; - break; - } - - memcpy(buf + 2, head, sizeof(head)); - CODE_ADD(c, 0x191, 17); - CODE_ADD(c, aspect_ratio, 4); - CODE_ADD(c, 0x1, 4); - CODE_ADD(c, fps, 16); - CODE_ADD(c, 0x3, 2); - CODE_ADD(c, 1001, vti_bitlen(go)); - CODE_ADD(c, 1, 1); - CODE_ADD(c, go->width, 13); - CODE_ADD(c, 1, 1); - CODE_ADD(c, go->height, 13); - CODE_ADD(c, 0x2830, 14); - - /* Byte-align */ - i = 8 - (CODE_LENGTH(c) % 8); - CODE_ADD(c, 0, 1); - CODE_ADD(c, (1 << (i - 1)) - 1, i - 1); - - i = CODE_LENGTH(c) + sizeof(head) * 8; - buf[0] = i & 0xff; - buf[1] = i >> 8; - return i; -} - -static int gen_mpeg4hdr_to_package(struct go7007 *go, - __le16 *code, int space, int *framelen) -{ - u8 *buf; - u16 mem = 0x3e00; - unsigned int addr = 0x19; - int i, off = 0, chunk; - - buf = kzalloc(5120, GFP_KERNEL); - if (buf == NULL) { - printk(KERN_ERR "go7007: unable to allocate 5120 bytes for " - "firmware construction\n"); - return -1; - } - framelen[0] = mpeg4_frame_header(go, buf, 0, PFRAME); - i = 368; - framelen[1] = mpeg4_frame_header(go, buf + i, 0, BFRAME_PRE); - i += 1632; - framelen[2] = mpeg4_frame_header(go, buf + i, 0, BFRAME_POST); - i += 1432; - framelen[3] = mpeg4_frame_header(go, buf + i, 0, BFRAME_BIDIR); - i += 1632; - mpeg4_frame_header(go, buf + i, 0, BFRAME_EMPTY); - i += 16; - mpeg4_sequence_header(go, buf + i, 0); - i += 40; - for (i = 0; i < 5120; i += chunk * 2) { - if (space - off < 32) { - off = -1; - goto done; - } - - code[off + 1] = __cpu_to_le16(0x8000 | mem); - - chunk = 28; - if (mem + chunk > 0x4000) - chunk = 0x4000 - mem; - if (i + 2 * chunk > 5120) - chunk = (5120 - i) / 2; - - if (chunk < 28) { - code[off] = __cpu_to_le16(0x4000 | chunk); - code[off + 31] = __cpu_to_le16(addr); - if (mem + chunk == 0x4000) { - mem = 0x3e00; - ++addr; - } - } else { - code[off] = __cpu_to_le16(0x1000 | 28); - code[off + 31] = 0; - mem += 28; - } - - memcpy(&code[off + 2], buf + i, chunk * 2); - off += 32; - } - mem = 0x3e00; - addr = go->ipb ? 0x14f9 : 0x0af9; - memset(buf, 0, 5120); - framelen[4] = mpeg4_frame_header(go, buf, 1, PFRAME); - i = 368; - framelen[5] = mpeg4_frame_header(go, buf + i, 1, BFRAME_PRE); - i += 1632; - framelen[6] = mpeg4_frame_header(go, buf + i, 1, BFRAME_POST); - i += 1432; - framelen[7] = mpeg4_frame_header(go, buf + i, 1, BFRAME_BIDIR); - i += 1632; - mpeg4_frame_header(go, buf + i, 1, BFRAME_EMPTY); - i += 16; - for (i = 0; i < 5120; i += chunk * 2) { - if (space - off < 32) { - off = -1; - goto done; - } - - code[off + 1] = __cpu_to_le16(0x8000 | mem); - - chunk = 28; - if (mem + chunk > 0x4000) - chunk = 0x4000 - mem; - if (i + 2 * chunk > 5120) - chunk = (5120 - i) / 2; - - if (chunk < 28) { - code[off] = __cpu_to_le16(0x4000 | chunk); - code[off + 31] = __cpu_to_le16(addr); - if (mem + chunk == 0x4000) { - mem = 0x3e00; - ++addr; - } - } else { - code[off] = __cpu_to_le16(0x1000 | 28); - code[off + 31] = 0; - mem += 28; - } - - memcpy(&code[off + 2], buf + i, chunk * 2); - off += 32; - } -done: - kfree(buf); - return off; -} - -static int brctrl_to_package(struct go7007 *go, - __le16 *code, int space, int *framelen) -{ - int converge_speed = 0; - int lambda = (go->format == GO7007_FORMAT_MJPEG || go->dvd_mode) ? - 100 : 0; - int peak_rate = 6 * go->bitrate / 5; - int vbv_buffer = go->format == GO7007_FORMAT_MJPEG ? - go->bitrate : - (go->dvd_mode ? 900000 : peak_rate); - int fps = go->sensor_framerate / go->fps_scale; - int q = 0; - /* Bizarre math below depends on rounding errors in division */ - u32 sgop_expt_addr = go->bitrate / 32 * (go->ipb ? 3 : 1) * 1001 / fps; - u32 sgop_peak_addr = peak_rate / 32 * 1001 / fps; - u32 total_expt_addr = go->bitrate / 32 * 1000 / fps * (fps / 1000); - u32 vbv_alert_addr = vbv_buffer * 3 / (4 * 32); - u32 cplx[] = { - q > 0 ? sgop_expt_addr * q : - 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, - q > 0 ? sgop_expt_addr * q : - 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, - q > 0 ? sgop_expt_addr * q : - 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, - q > 0 ? sgop_expt_addr * q : - 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, - }; - u32 calc_q = q > 0 ? q : cplx[0] / sgop_expt_addr; - u16 pack[] = { - 0x200e, 0x0000, - 0xBF20, go->ipb ? converge_speed_ipb[converge_speed] - : converge_speed_ip[converge_speed], - 0xBF21, go->ipb ? 2 : 0, - 0xBF22, go->ipb ? LAMBDA_table[0][lambda / 2 + 50] - : 32767, - 0xBF23, go->ipb ? LAMBDA_table[1][lambda] : 32767, - 0xBF24, 32767, - 0xBF25, lambda > 99 ? 32767 : LAMBDA_table[3][lambda], - 0xBF26, sgop_expt_addr & 0x0000FFFF, - 0xBF27, sgop_expt_addr >> 16, - 0xBF28, sgop_peak_addr & 0x0000FFFF, - 0xBF29, sgop_peak_addr >> 16, - 0xBF2A, vbv_alert_addr & 0x0000FFFF, - 0xBF2B, vbv_alert_addr >> 16, - 0xBF2C, 0, - 0xBF2D, 0, - 0, 0, - - 0x200e, 0x0000, - 0xBF2E, vbv_alert_addr & 0x0000FFFF, - 0xBF2F, vbv_alert_addr >> 16, - 0xBF30, cplx[0] & 0x0000FFFF, - 0xBF31, cplx[0] >> 16, - 0xBF32, cplx[1] & 0x0000FFFF, - 0xBF33, cplx[1] >> 16, - 0xBF34, cplx[2] & 0x0000FFFF, - 0xBF35, cplx[2] >> 16, - 0xBF36, cplx[3] & 0x0000FFFF, - 0xBF37, cplx[3] >> 16, - 0xBF38, 0, - 0xBF39, 0, - 0xBF3A, total_expt_addr & 0x0000FFFF, - 0xBF3B, total_expt_addr >> 16, - 0, 0, - - 0x200e, 0x0000, - 0xBF3C, total_expt_addr & 0x0000FFFF, - 0xBF3D, total_expt_addr >> 16, - 0xBF3E, 0, - 0xBF3F, 0, - 0xBF48, 0, - 0xBF49, 0, - 0xBF4A, calc_q < 4 ? 4 : (calc_q > 124 ? 124 : calc_q), - 0xBF4B, 4, - 0xBF4C, 0, - 0xBF4D, 0, - 0xBF4E, 0, - 0xBF4F, 0, - 0xBF50, 0, - 0xBF51, 0, - 0, 0, - - 0x200e, 0x0000, - 0xBF40, sgop_expt_addr & 0x0000FFFF, - 0xBF41, sgop_expt_addr >> 16, - 0xBF42, 0, - 0xBF43, 0, - 0xBF44, 0, - 0xBF45, 0, - 0xBF46, (go->width >> 4) * (go->height >> 4), - 0xBF47, 0, - 0xBF64, 0, - 0xBF65, 0, - 0xBF18, framelen[4], - 0xBF19, framelen[5], - 0xBF1A, framelen[6], - 0xBF1B, framelen[7], - 0, 0, - -#if 0 - /* Remove once we don't care about matching */ - 0x200e, 0x0000, - 0xBF56, 4, - 0xBF57, 0, - 0xBF58, 5, - 0xBF59, 0, - 0xBF5A, 6, - 0xBF5B, 0, - 0xBF5C, 8, - 0xBF5D, 0, - 0xBF5E, 1, - 0xBF5F, 0, - 0xBF60, 1, - 0xBF61, 0, - 0xBF62, 0, - 0xBF63, 0, - 0, 0, -#else - 0x2008, 0x0000, - 0xBF56, 4, - 0xBF57, 0, - 0xBF58, 5, - 0xBF59, 0, - 0xBF5A, 6, - 0xBF5B, 0, - 0xBF5C, 8, - 0xBF5D, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, -#endif - - 0x200e, 0x0000, - 0xBF10, 0, - 0xBF11, 0, - 0xBF12, 0, - 0xBF13, 0, - 0xBF14, 0, - 0xBF15, 0, - 0xBF16, 0, - 0xBF17, 0, - 0xBF7E, 0, - 0xBF7F, 1, - 0xBF52, framelen[0], - 0xBF53, framelen[1], - 0xBF54, framelen[2], - 0xBF55, framelen[3], - 0, 0, - }; - - return copy_packages(code, pack, 6, space); -} - -static int config_package(struct go7007 *go, __le16 *code, int space) -{ - int fps = go->sensor_framerate / go->fps_scale / 1000; - int rows = go->interlace_coding ? go->height / 32 : go->height / 16; - int brc_window_size = fps; - int q_min = 2, q_max = 31; - int THACCoeffSet0 = 0; - u16 pack[] = { - 0x200e, 0x0000, - 0xc002, 0x14b4, - 0xc003, 0x28b4, - 0xc004, 0x3c5a, - 0xdc05, 0x2a77, - 0xc6c3, go->format == GO7007_FORMAT_MPEG4 ? 0 : - (go->format == GO7007_FORMAT_H263 ? 0 : 1), - 0xc680, go->format == GO7007_FORMAT_MPEG4 ? 0xf1 : - (go->format == GO7007_FORMAT_H263 ? 0x61 : - 0xd3), - 0xc780, 0x0140, - 0xe009, 0x0001, - 0xc60f, 0x0008, - 0xd4ff, 0x0002, - 0xe403, 2340, - 0xe406, 75, - 0xd411, 0x0001, - 0xd410, 0xa1d6, - 0x0001, 0x2801, - - 0x200d, 0x0000, - 0xe402, 0x018b, - 0xe401, 0x8b01, - 0xd472, (go->board_info->sensor_flags & - GO7007_SENSOR_TV) && - (!go->interlace_coding) ? - 0x01b0 : 0x0170, - 0xd475, (go->board_info->sensor_flags & - GO7007_SENSOR_TV) && - (!go->interlace_coding) ? - 0x0008 : 0x0009, - 0xc404, go->interlace_coding ? 0x44 : - (go->format == GO7007_FORMAT_MPEG4 ? 0x11 : - (go->format == GO7007_FORMAT_MPEG1 ? 0x02 : - (go->format == GO7007_FORMAT_MPEG2 ? 0x04 : - (go->format == GO7007_FORMAT_H263 ? 0x08 : - 0x20)))), - 0xbf0a, (go->format == GO7007_FORMAT_MPEG4 ? 8 : - (go->format == GO7007_FORMAT_MPEG1 ? 1 : - (go->format == GO7007_FORMAT_MPEG2 ? 2 : - (go->format == GO7007_FORMAT_H263 ? 4 : 16)))) | - ((go->repeat_seqhead ? 1 : 0) << 6) | - ((go->dvd_mode ? 1 : 0) << 9) | - ((go->gop_header_enable ? 1 : 0) << 10), - 0xbf0b, 0, - 0xdd5a, go->ipb ? 0x14 : 0x0a, - 0xbf0c, 0, - 0xbf0d, 0, - 0xc683, THACCoeffSet0, - 0xc40a, (go->width << 4) | rows, - 0xe01a, go->board_info->hpi_buffer_cap, - 0, 0, - 0, 0, - - 0x2008, 0, - 0xe402, 0x88, - 0xe401, 0x8f01, - 0xbf6a, 0, - 0xbf6b, 0, - 0xbf6c, 0, - 0xbf6d, 0, - 0xbf6e, 0, - 0xbf6f, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - - 0x200e, 0, - 0xbf66, brc_window_size, - 0xbf67, 0, - 0xbf68, q_min, - 0xbf69, q_max, - 0xbfe0, 0, - 0xbfe1, 0, - 0xbfe2, 0, - 0xbfe3, go->ipb ? 3 : 1, - 0xc031, go->board_info->sensor_flags & - GO7007_SENSOR_VBI ? 1 : 0, - 0xc01c, 0x1f, - 0xdd8c, 0x15, - 0xdd94, 0x15, - 0xdd88, go->ipb ? 0x1401 : 0x0a01, - 0xdd90, go->ipb ? 0x1401 : 0x0a01, - 0, 0, - - 0x200e, 0, - 0xbfe4, 0, - 0xbfe5, 0, - 0xbfe6, 0, - 0xbfe7, fps << 8, - 0xbfe8, 0x3a00, - 0xbfe9, 0, - 0xbfea, 0, - 0xbfeb, 0, - 0xbfec, (go->interlace_coding ? 1 << 15 : 0) | - (go->modet_enable ? 0xa : 0) | - (go->board_info->sensor_flags & - GO7007_SENSOR_VBI ? 1 : 0), - 0xbfed, 0, - 0xbfee, 0, - 0xbfef, 0, - 0xbff0, go->board_info->sensor_flags & - GO7007_SENSOR_TV ? 0xf060 : 0xb060, - 0xbff1, 0, - 0, 0, - }; - - return copy_packages(code, pack, 5, space); -} - -static int seqhead_to_package(struct go7007 *go, __le16 *code, int space, - int (*sequence_header_func)(struct go7007 *go, - unsigned char *buf, int ext)) -{ - int vop_time_increment_bitlength = vti_bitlen(go); - int fps = go->sensor_framerate / go->fps_scale * - (go->interlace_coding ? 2 : 1); - unsigned char buf[40] = { }; - int len = sequence_header_func(go, buf, 1); - u16 pack[] = { - 0x2006, 0, - 0xbf08, fps, - 0xbf09, 0, - 0xbff2, vop_time_increment_bitlength, - 0xbff3, (1 << vop_time_increment_bitlength) - 1, - 0xbfe6, 0, - 0xbfe7, (fps / 1000) << 8, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - - 0x2007, 0, - 0xc800, buf[2] << 8 | buf[3], - 0xc801, buf[4] << 8 | buf[5], - 0xc802, buf[6] << 8 | buf[7], - 0xc803, buf[8] << 8 | buf[9], - 0xc406, 64, - 0xc407, len - 64, - 0xc61b, 1, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - - 0x200e, 0, - 0xc808, buf[10] << 8 | buf[11], - 0xc809, buf[12] << 8 | buf[13], - 0xc80a, buf[14] << 8 | buf[15], - 0xc80b, buf[16] << 8 | buf[17], - 0xc80c, buf[18] << 8 | buf[19], - 0xc80d, buf[20] << 8 | buf[21], - 0xc80e, buf[22] << 8 | buf[23], - 0xc80f, buf[24] << 8 | buf[25], - 0xc810, buf[26] << 8 | buf[27], - 0xc811, buf[28] << 8 | buf[29], - 0xc812, buf[30] << 8 | buf[31], - 0xc813, buf[32] << 8 | buf[33], - 0xc814, buf[34] << 8 | buf[35], - 0xc815, buf[36] << 8 | buf[37], - 0, 0, - 0, 0, - 0, 0, - }; - - return copy_packages(code, pack, 3, space); -} - -static int relative_prime(int big, int little) -{ - int remainder; - - while (little != 0) { - remainder = big % little; - big = little; - little = remainder; - } - return big; -} - -static int avsync_to_package(struct go7007 *go, __le16 *code, int space) -{ - int arate = go->board_info->audio_rate * 1001 * go->fps_scale; - int ratio = arate / go->sensor_framerate; - int adjratio = ratio * 215 / 100; - int rprime = relative_prime(go->sensor_framerate, - arate % go->sensor_framerate); - int f1 = (arate % go->sensor_framerate) / rprime; - int f2 = (go->sensor_framerate - arate % go->sensor_framerate) / rprime; - u16 pack[] = { - 0x200e, 0, - 0xbf98, (u16)((-adjratio) & 0xffff), - 0xbf99, (u16)((-adjratio) >> 16), - 0xbf92, 0, - 0xbf93, 0, - 0xbff4, f1 > f2 ? f1 : f2, - 0xbff5, f1 < f2 ? f1 : f2, - 0xbff6, f1 < f2 ? ratio : ratio + 1, - 0xbff7, f1 > f2 ? ratio : ratio + 1, - 0xbff8, 0, - 0xbff9, 0, - 0xbffa, adjratio & 0xffff, - 0xbffb, adjratio >> 16, - 0xbf94, 0, - 0xbf95, 0, - 0, 0, - }; - - return copy_packages(code, pack, 1, space); -} - -static int final_package(struct go7007 *go, __le16 *code, int space) -{ - int rows = go->interlace_coding ? go->height / 32 : go->height / 16; - u16 pack[] = { - 0x8000, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - ((go->board_info->sensor_flags & GO7007_SENSOR_TV) && - (!go->interlace_coding) ? - (1 << 14) | (1 << 9) : 0) | - ((go->encoder_subsample ? 1 : 0) << 8) | - (go->board_info->sensor_flags & - GO7007_SENSOR_CONFIG_MASK), - ((go->encoder_v_halve ? 1 : 0) << 14) | - (go->encoder_v_halve ? rows << 9 : rows << 8) | - (go->encoder_h_halve ? 1 << 6 : 0) | - (go->encoder_h_halve ? go->width >> 3 : go->width >> 4), - (1 << 15) | (go->encoder_v_offset << 6) | - (1 << 7) | (go->encoder_h_offset >> 2), - (1 << 6), - 0, - 0, - ((go->fps_scale - 1) << 8) | - (go->board_info->sensor_flags & GO7007_SENSOR_TV ? - (1 << 7) : 0) | - 0x41, - go->ipb ? 0xd4c : 0x36b, - (rows << 8) | (go->width >> 4), - go->format == GO7007_FORMAT_MPEG4 ? 0x0404 : 0, - (1 << 15) | ((go->interlace_coding ? 1 : 0) << 13) | - ((go->closed_gop ? 1 : 0) << 12) | - ((go->format == GO7007_FORMAT_MPEG4 ? 1 : 0) << 11) | - /* (1 << 9) | */ - ((go->ipb ? 3 : 0) << 7) | - ((go->modet_enable ? 1 : 0) << 2) | - ((go->dvd_mode ? 1 : 0) << 1) | 1, - (go->format == GO7007_FORMAT_MPEG1 ? 0x89a0 : - (go->format == GO7007_FORMAT_MPEG2 ? 0x89a0 : - (go->format == GO7007_FORMAT_MJPEG ? 0x89a0 : - (go->format == GO7007_FORMAT_MPEG4 ? 0x8920 : - (go->format == GO7007_FORMAT_H263 ? 0x8920 : 0))))), - go->ipb ? 0x1f15 : 0x1f0b, - go->ipb ? 0x0015 : 0x000b, - go->ipb ? 0xa800 : 0x5800, - 0xffff, - 0x0020 + 0x034b * 0, - 0x0020 + 0x034b * 1, - 0x0020 + 0x034b * 2, - 0x0020 + 0x034b * 3, - 0x0020 + 0x034b * 4, - 0x0020 + 0x034b * 5, - go->ipb ? (go->gop_size / 3) : go->gop_size, - (go->height >> 4) * (go->width >> 4) * 110 / 100, - }; - - return copy_packages(code, pack, 1, space); -} - -static int audio_to_package(struct go7007 *go, __le16 *code, int space) -{ - int clock_config = ((go->board_info->audio_flags & - GO7007_AUDIO_I2S_MASTER ? 1 : 0) << 11) | - ((go->board_info->audio_flags & - GO7007_AUDIO_OKI_MODE ? 1 : 0) << 8) | - (((go->board_info->audio_bclk_div / 4) - 1) << 4) | - (go->board_info->audio_main_div - 1); - u16 pack[] = { - 0x200d, 0, - 0x9002, 0, - 0x9002, 0, - 0x9031, 0, - 0x9032, 0, - 0x9033, 0, - 0x9034, 0, - 0x9035, 0, - 0x9036, 0, - 0x9037, 0, - 0x9040, 0, - 0x9000, clock_config, - 0x9001, (go->board_info->audio_flags & 0xffff) | - (1 << 9), - 0x9000, ((go->board_info->audio_flags & - GO7007_AUDIO_I2S_MASTER ? - 1 : 0) << 10) | - clock_config, - 0, 0, - 0, 0, - 0x2005, 0, - 0x9041, 0, - 0x9042, 256, - 0x9043, 0, - 0x9044, 16, - 0x9045, 16, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - }; - - return copy_packages(code, pack, 2, space); -} - -static int modet_to_package(struct go7007 *go, __le16 *code, int space) -{ - int ret, mb, i, addr, cnt = 0; - u16 pack[32]; - u16 thresholds[] = { - 0x200e, 0, - 0xbf82, go->modet[0].pixel_threshold, - 0xbf83, go->modet[1].pixel_threshold, - 0xbf84, go->modet[2].pixel_threshold, - 0xbf85, go->modet[3].pixel_threshold, - 0xbf86, go->modet[0].motion_threshold, - 0xbf87, go->modet[1].motion_threshold, - 0xbf88, go->modet[2].motion_threshold, - 0xbf89, go->modet[3].motion_threshold, - 0xbf8a, go->modet[0].mb_threshold, - 0xbf8b, go->modet[1].mb_threshold, - 0xbf8c, go->modet[2].mb_threshold, - 0xbf8d, go->modet[3].mb_threshold, - 0xbf8e, 0, - 0xbf8f, 0, - 0, 0, - }; - - ret = copy_packages(code, thresholds, 1, space); - if (ret < 0) - return -1; - cnt += ret; - - addr = 0xbac0; - memset(pack, 0, 64); - i = 0; - for (mb = 0; mb < 1624; ++mb) { - pack[i * 2 + 3] <<= 2; - pack[i * 2 + 3] |= go->modet_map[mb]; - if (mb % 8 != 7) - continue; - pack[i * 2 + 2] = addr++; - ++i; - if (i == 10 || mb == 1623) { - pack[0] = 0x2000 | i; - ret = copy_packages(code + cnt, pack, 1, space - cnt); - if (ret < 0) - return -1; - cnt += ret; - i = 0; - memset(pack, 0, 64); - } - pack[i * 2 + 3] = 0; - } - - memset(pack, 0, 64); - i = 0; - for (addr = 0xbb90; addr < 0xbbfa; ++addr) { - pack[i * 2 + 2] = addr; - pack[i * 2 + 3] = 0; - ++i; - if (i == 10 || addr == 0xbbf9) { - pack[0] = 0x2000 | i; - ret = copy_packages(code + cnt, pack, 1, space - cnt); - if (ret < 0) - return -1; - cnt += ret; - i = 0; - memset(pack, 0, 64); - } - } - return cnt; -} - -static int do_special(struct go7007 *go, u16 type, __le16 *code, int space, - int *framelen) -{ - switch (type) { - case SPECIAL_FRM_HEAD: - switch (go->format) { - case GO7007_FORMAT_MJPEG: - return gen_mjpeghdr_to_package(go, code, space); - case GO7007_FORMAT_MPEG1: - case GO7007_FORMAT_MPEG2: - return gen_mpeg1hdr_to_package(go, code, space, - framelen); - case GO7007_FORMAT_MPEG4: - return gen_mpeg4hdr_to_package(go, code, space, - framelen); - } - case SPECIAL_BRC_CTRL: - return brctrl_to_package(go, code, space, framelen); - case SPECIAL_CONFIG: - return config_package(go, code, space); - case SPECIAL_SEQHEAD: - switch (go->format) { - case GO7007_FORMAT_MPEG1: - case GO7007_FORMAT_MPEG2: - return seqhead_to_package(go, code, space, - mpeg1_sequence_header); - case GO7007_FORMAT_MPEG4: - return seqhead_to_package(go, code, space, - mpeg4_sequence_header); - default: - return 0; - } - case SPECIAL_AV_SYNC: - return avsync_to_package(go, code, space); - case SPECIAL_FINAL: - return final_package(go, code, space); - case SPECIAL_AUDIO: - return audio_to_package(go, code, space); - case SPECIAL_MODET: - return modet_to_package(go, code, space); - } - printk(KERN_ERR - "go7007: firmware file contains unsupported feature %04x\n", - type); - return -1; -} - -int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) -{ - const struct firmware *fw_entry; - __le16 *code, *src; - int framelen[8] = { }; /* holds the lengths of empty frame templates */ - int codespace = 64 * 1024, i = 0, srclen, chunk_len, chunk_flags; - int mode_flag; - int ret; - - switch (go->format) { - case GO7007_FORMAT_MJPEG: - mode_flag = FLAG_MODE_MJPEG; - break; - case GO7007_FORMAT_MPEG1: - mode_flag = FLAG_MODE_MPEG1; - break; - case GO7007_FORMAT_MPEG2: - mode_flag = FLAG_MODE_MPEG2; - break; - case GO7007_FORMAT_MPEG4: - mode_flag = FLAG_MODE_MPEG4; - break; - default: - return -1; - } - if (request_firmware(&fw_entry, go->board_info->firmware, go->dev)) { - printk(KERN_ERR - "go7007: unable to load firmware from file \"%s\"\n", - go->board_info->firmware); - return -1; - } - code = kzalloc(codespace * 2, GFP_KERNEL); - if (code == NULL) { - printk(KERN_ERR "go7007: unable to allocate %d bytes for " - "firmware construction\n", codespace * 2); - goto fw_failed; - } - src = (__le16 *)fw_entry->data; - srclen = fw_entry->size / 2; - while (srclen >= 2) { - chunk_flags = __le16_to_cpu(src[0]); - chunk_len = __le16_to_cpu(src[1]); - if (chunk_len + 2 > srclen) { - printk(KERN_ERR "go7007: firmware file \"%s\" " - "appears to be corrupted\n", - go->board_info->firmware); - goto fw_failed; - } - if (chunk_flags & mode_flag) { - if (chunk_flags & FLAG_SPECIAL) { - ret = do_special(go, __le16_to_cpu(src[2]), - &code[i], codespace - i, framelen); - if (ret < 0) { - printk(KERN_ERR "go7007: insufficient " - "memory for firmware " - "construction\n"); - goto fw_failed; - } - i += ret; - } else { - if (codespace - i < chunk_len) { - printk(KERN_ERR "go7007: insufficient " - "memory for firmware " - "construction\n"); - goto fw_failed; - } - memcpy(&code[i], &src[2], chunk_len * 2); - i += chunk_len; - } - } - srclen -= chunk_len + 2; - src += chunk_len + 2; - } - release_firmware(fw_entry); - *fw = (u8 *)code; - *fwlen = i * 2; - return 0; - -fw_failed: - kfree(code); - release_firmware(fw_entry); - return -1; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and the associated README documentation file (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* DEPRECATED -- use V4L2_PIX_FMT_MPEG and then call GO7007IOC_S_MPEG_PARAMS - * to select between MPEG1, MPEG2, and MPEG4 */ -#define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4') /* MPEG4 */ - -/* These will be replaced with a better interface - * soon, so don't get too attached to them */ -#define GO7007IOC_S_BITRATE _IOW('V', BASE_VIDIOC_PRIVATE + 0, int) -#define GO7007IOC_G_BITRATE _IOR('V', BASE_VIDIOC_PRIVATE + 1, int) - -enum go7007_aspect_ratio { - GO7007_ASPECT_RATIO_1_1 = 0, - GO7007_ASPECT_RATIO_4_3_NTSC = 1, - GO7007_ASPECT_RATIO_4_3_PAL = 2, - GO7007_ASPECT_RATIO_16_9_NTSC = 3, - GO7007_ASPECT_RATIO_16_9_PAL = 4, -}; - -/* Used to set generic compression parameters */ -struct go7007_comp_params { - __u32 gop_size; - __u32 max_b_frames; - enum go7007_aspect_ratio aspect_ratio; - __u32 flags; - __u32 reserved[8]; -}; - -#define GO7007_COMP_CLOSED_GOP 0x00000001 -#define GO7007_COMP_OMIT_SEQ_HEADER 0x00000002 - -enum go7007_mpeg_video_standard { - GO7007_MPEG_VIDEO_MPEG1 = 0, - GO7007_MPEG_VIDEO_MPEG2 = 1, - GO7007_MPEG_VIDEO_MPEG4 = 2, -}; - -/* Used to set parameters for V4L2_PIX_FMT_MPEG format */ -struct go7007_mpeg_params { - enum go7007_mpeg_video_standard mpeg_video_standard; - __u32 flags; - __u32 pali; - __u32 reserved[8]; -}; - -#define GO7007_MPEG_FORCE_DVD_MODE 0x00000001 -#define GO7007_MPEG_OMIT_GOP_HEADER 0x00000002 -#define GO7007_MPEG_REPEAT_SEQHEADER 0x00000004 - -#define GO7007_MPEG_PROFILE(format, pali) (((format)<<24)|(pali)) - -#define GO7007_MPEG2_PROFILE_MAIN_MAIN GO7007_MPEG_PROFILE(2, 0x48) - -#define GO7007_MPEG4_PROFILE_S_L0 GO7007_MPEG_PROFILE(4, 0x08) -#define GO7007_MPEG4_PROFILE_S_L1 GO7007_MPEG_PROFILE(4, 0x01) -#define GO7007_MPEG4_PROFILE_S_L2 GO7007_MPEG_PROFILE(4, 0x02) -#define GO7007_MPEG4_PROFILE_S_L3 GO7007_MPEG_PROFILE(4, 0x03) -#define GO7007_MPEG4_PROFILE_ARTS_L1 GO7007_MPEG_PROFILE(4, 0x91) -#define GO7007_MPEG4_PROFILE_ARTS_L2 GO7007_MPEG_PROFILE(4, 0x92) -#define GO7007_MPEG4_PROFILE_ARTS_L3 GO7007_MPEG_PROFILE(4, 0x93) -#define GO7007_MPEG4_PROFILE_ARTS_L4 GO7007_MPEG_PROFILE(4, 0x94) -#define GO7007_MPEG4_PROFILE_AS_L0 GO7007_MPEG_PROFILE(4, 0xf0) -#define GO7007_MPEG4_PROFILE_AS_L1 GO7007_MPEG_PROFILE(4, 0xf1) -#define GO7007_MPEG4_PROFILE_AS_L2 GO7007_MPEG_PROFILE(4, 0xf2) -#define GO7007_MPEG4_PROFILE_AS_L3 GO7007_MPEG_PROFILE(4, 0xf3) -#define GO7007_MPEG4_PROFILE_AS_L4 GO7007_MPEG_PROFILE(4, 0xf4) -#define GO7007_MPEG4_PROFILE_AS_L5 GO7007_MPEG_PROFILE(4, 0xf5) - -struct go7007_md_params { - __u16 region; - __u16 trigger; - __u16 pixel_threshold; - __u16 motion_threshold; - __u32 reserved[8]; -}; - -struct go7007_md_region { - __u16 region; - __u16 flags; - struct v4l2_clip *clips; - __u32 reserved[8]; -}; - -#define GO7007IOC_S_MPEG_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 2, \ - struct go7007_mpeg_params) -#define GO7007IOC_G_MPEG_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 3, \ - struct go7007_mpeg_params) -#define GO7007IOC_S_COMP_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 4, \ - struct go7007_comp_params) -#define GO7007IOC_G_COMP_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 5, \ - struct go7007_comp_params) -#define GO7007IOC_S_MD_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 6, \ - struct go7007_md_params) -#define GO7007IOC_G_MD_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 7, \ - struct go7007_md_params) -#define GO7007IOC_S_MD_REGION _IOW('V', BASE_VIDIOC_PRIVATE + 8, \ - struct go7007_md_region) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "go7007-priv.h" -#include "wis-i2c.h" - -/********************* Driver for on-board I2C adapter *********************/ - -/* #define GO7007_I2C_DEBUG */ - -#define SPI_I2C_ADDR_BASE 0x1400 -#define STATUS_REG_ADDR (SPI_I2C_ADDR_BASE + 0x2) -#define I2C_CTRL_REG_ADDR (SPI_I2C_ADDR_BASE + 0x6) -#define I2C_DEV_UP_ADDR_REG_ADDR (SPI_I2C_ADDR_BASE + 0x7) -#define I2C_LO_ADDR_REG_ADDR (SPI_I2C_ADDR_BASE + 0x8) -#define I2C_DATA_REG_ADDR (SPI_I2C_ADDR_BASE + 0x9) -#define I2C_CLKFREQ_REG_ADDR (SPI_I2C_ADDR_BASE + 0xa) - -#define I2C_STATE_MASK 0x0007 -#define I2C_READ_READY_MASK 0x0008 - -/* There is only one I2C port on the TW2804 that feeds all four GO7007 VIPs - * on the Adlink PCI-MPG24, so access is shared between all of them. */ -static DEFINE_MUTEX(adlink_mpg24_i2c_lock); - -static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read, - u16 command, int flags, u8 *data) -{ - int i, ret = -1; - u16 val; - - if (go->status == STATUS_SHUTDOWN) - return -1; - -#ifdef GO7007_I2C_DEBUG - if (read) - printk(KERN_DEBUG "go7007-i2c: reading 0x%02x on 0x%02x\n", - command, addr); - else - printk(KERN_DEBUG - "go7007-i2c: writing 0x%02x to 0x%02x on 0x%02x\n", - *data, command, addr); -#endif - - mutex_lock(&go->hw_lock); - - if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) { - /* Bridge the I2C port on this GO7007 to the shared bus */ - mutex_lock(&adlink_mpg24_i2c_lock); - go7007_write_addr(go, 0x3c82, 0x0020); - } - - /* Wait for I2C adapter to be ready */ - for (i = 0; i < 10; ++i) { - if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0) - goto i2c_done; - if (!(val & I2C_STATE_MASK)) - break; - msleep(100); - } - if (i == 10) { - printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n"); - goto i2c_done; - } - - /* Set target register (command) */ - go7007_write_addr(go, I2C_CTRL_REG_ADDR, flags); - go7007_write_addr(go, I2C_LO_ADDR_REG_ADDR, command); - - /* If we're writing, send the data and target address and we're done */ - if (!read) { - go7007_write_addr(go, I2C_DATA_REG_ADDR, *data); - go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR, - (addr << 9) | (command >> 8)); - ret = 0; - goto i2c_done; - } - - /* Otherwise, we're reading. First clear i2c_rx_data_rdy. */ - if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0) - goto i2c_done; - - /* Send the target address plus read flag */ - go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR, - (addr << 9) | 0x0100 | (command >> 8)); - - /* Wait for i2c_rx_data_rdy */ - for (i = 0; i < 10; ++i) { - if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0) - goto i2c_done; - if (val & I2C_READ_READY_MASK) - break; - msleep(100); - } - if (i == 10) { - printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n"); - goto i2c_done; - } - - /* Retrieve the read byte */ - if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0) - goto i2c_done; - *data = val; - ret = 0; - -i2c_done: - if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) { - /* Isolate the I2C port on this GO7007 from the shared bus */ - go7007_write_addr(go, 0x3c82, 0x0000); - mutex_unlock(&adlink_mpg24_i2c_lock); - } - mutex_unlock(&go->hw_lock); - return ret; -} - -static int go7007_smbus_xfer(struct i2c_adapter *adapter, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data) -{ - struct go7007 *go = i2c_get_adapdata(adapter); - - if (size != I2C_SMBUS_BYTE_DATA) - return -1; - return go7007_i2c_xfer(go, addr, read_write == I2C_SMBUS_READ, command, - flags & I2C_CLIENT_SCCB ? 0x10 : 0x00, &data->byte); -} - -/* VERY LIMITED I2C master xfer function -- only needed because the - * SMBus functions only support 8-bit commands and the SAA7135 uses - * 16-bit commands. The I2C interface on the GO7007, as limited as - * it is, does support this mode. */ - -static int go7007_i2c_master_xfer(struct i2c_adapter *adapter, - struct i2c_msg msgs[], int num) -{ - struct go7007 *go = i2c_get_adapdata(adapter); - int i; - - for (i = 0; i < num; ++i) { - /* We can only do two things here -- write three bytes, or - * write two bytes and read one byte. */ - if (msgs[i].len == 2) { - if (i + 1 == num || msgs[i].addr != msgs[i + 1].addr || - (msgs[i].flags & I2C_M_RD) || - !(msgs[i + 1].flags & I2C_M_RD) || - msgs[i + 1].len != 1) - return -1; - if (go7007_i2c_xfer(go, msgs[i].addr, 1, - (msgs[i].buf[0] << 8) | msgs[i].buf[1], - 0x01, &msgs[i + 1].buf[0]) < 0) - return -1; - ++i; - } else if (msgs[i].len == 3) { - if (msgs[i].flags & I2C_M_RD) - return -1; - if (msgs[i].len != 3) - return -1; - if (go7007_i2c_xfer(go, msgs[i].addr, 0, - (msgs[i].buf[0] << 8) | msgs[i].buf[1], - 0x01, &msgs[i].buf[2]) < 0) - return -1; - } else - return -1; - } - - return 0; -} - -static u32 go7007_functionality(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_BYTE_DATA; -} - -static struct i2c_algorithm go7007_algo = { - .smbus_xfer = go7007_smbus_xfer, - .master_xfer = go7007_i2c_master_xfer, - .functionality = go7007_functionality, -}; - -static struct i2c_adapter go7007_adap_templ = { - .owner = THIS_MODULE, - .name = "WIS GO7007SB", - .algo = &go7007_algo, -}; - -int go7007_i2c_init(struct go7007 *go) -{ - memcpy(&go->i2c_adapter, &go7007_adap_templ, - sizeof(go7007_adap_templ)); - go->i2c_adapter.dev.parent = go->dev; - i2c_set_adapdata(&go->i2c_adapter, go); - if (i2c_add_adapter(&go->i2c_adapter) < 0) { - printk(KERN_ERR - "go7007-i2c: error: i2c_add_adapter failed\n"); - return -1; - } - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-priv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-priv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,290 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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. - */ - -/* - * This is the private include file for the go7007 driver. It should not - * be included by anybody but the driver itself, and especially not by - * user-space applications. - */ - -#include - -struct go7007; - -/* IDs to activate board-specific support code */ -#define GO7007_BOARDID_MATRIX_II 0 -#define GO7007_BOARDID_MATRIX_RELOAD 1 -#define GO7007_BOARDID_STAR_TREK 2 -#define GO7007_BOARDID_PCI_VOYAGER 3 -#define GO7007_BOARDID_XMEN 4 -#define GO7007_BOARDID_XMEN_II 5 -#define GO7007_BOARDID_XMEN_III 6 -#define GO7007_BOARDID_MATRIX_REV 7 -#define GO7007_BOARDID_PX_M402U 16 -#define GO7007_BOARDID_PX_TV402U_ANY 17 /* need to check tuner model */ -#define GO7007_BOARDID_PX_TV402U_NA 18 /* detected NTSC tuner */ -#define GO7007_BOARDID_PX_TV402U_EU 19 /* detected PAL tuner */ -#define GO7007_BOARDID_PX_TV402U_JP 20 /* detected NTSC-J tuner */ -#define GO7007_BOARDID_LIFEVIEW_LR192 21 /* TV Walker Ultra */ -#define GO7007_BOARDID_ENDURA 22 -#define GO7007_BOARDID_ADLINK_MPG24 23 -#define GO7007_BOARDID_SENSORAY_2250 24 /* Sensoray 2250/2251 */ - -/* Various characteristics of each board */ -#define GO7007_BOARD_HAS_AUDIO (1<<0) -#define GO7007_BOARD_USE_ONBOARD_I2C (1<<1) -#define GO7007_BOARD_HAS_TUNER (1<<2) - -/* Characteristics of sensor devices */ -#define GO7007_SENSOR_VALID_POLAR (1<<0) -#define GO7007_SENSOR_HREF_POLAR (1<<1) -#define GO7007_SENSOR_VREF_POLAR (1<<2) -#define GO7007_SENSOR_FIELD_ID_POLAR (1<<3) -#define GO7007_SENSOR_BIT_WIDTH (1<<4) -#define GO7007_SENSOR_VALID_ENABLE (1<<5) -#define GO7007_SENSOR_656 (1<<6) -#define GO7007_SENSOR_CONFIG_MASK 0x7f -#define GO7007_SENSOR_TV (1<<7) -#define GO7007_SENSOR_VBI (1<<8) -#define GO7007_SENSOR_SCALING (1<<9) - -/* Characteristics of audio sensor devices */ -#define GO7007_AUDIO_I2S_MODE_1 (1) -#define GO7007_AUDIO_I2S_MODE_2 (2) -#define GO7007_AUDIO_I2S_MODE_3 (3) -#define GO7007_AUDIO_BCLK_POLAR (1<<2) -#define GO7007_AUDIO_WORD_14 (14<<4) -#define GO7007_AUDIO_WORD_16 (16<<4) -#define GO7007_AUDIO_ONE_CHANNEL (1<<11) -#define GO7007_AUDIO_I2S_MASTER (1<<16) -#define GO7007_AUDIO_OKI_MODE (1<<17) - -struct go7007_board_info { - char *firmware; - unsigned int flags; - int hpi_buffer_cap; - unsigned int sensor_flags; - int sensor_width; - int sensor_height; - int sensor_framerate; - int sensor_h_offset; - int sensor_v_offset; - unsigned int audio_flags; - int audio_rate; - int audio_bclk_div; - int audio_main_div; - int num_i2c_devs; - struct { - const char *type; - int id; - int addr; - } i2c_devs[4]; - int num_inputs; - struct { - int video_input; - int audio_input; - char *name; - } inputs[4]; -}; - -struct go7007_hpi_ops { - int (*interface_reset)(struct go7007 *go); - int (*write_interrupt)(struct go7007 *go, int addr, int data); - int (*read_interrupt)(struct go7007 *go); - int (*stream_start)(struct go7007 *go); - int (*stream_stop)(struct go7007 *go); - int (*send_firmware)(struct go7007 *go, u8 *data, int len); - int (*send_command)(struct go7007 *go, unsigned int cmd, void *arg); -}; - -/* The video buffer size must be a multiple of PAGE_SIZE */ -#define GO7007_BUF_PAGES (128 * 1024 / PAGE_SIZE) -#define GO7007_BUF_SIZE (GO7007_BUF_PAGES << PAGE_SHIFT) - -struct go7007_buffer { - struct go7007 *go; /* Reverse reference for VMA ops */ - int index; /* Reverse reference for DQBUF */ - enum { BUF_STATE_IDLE, BUF_STATE_QUEUED, BUF_STATE_DONE } state; - u32 seq; - struct timeval timestamp; - struct list_head stream; - struct page *pages[GO7007_BUF_PAGES + 1]; /* extra for straddling */ - unsigned long user_addr; - unsigned int page_count; - unsigned int offset; - unsigned int bytesused; - unsigned int frame_offset; - u32 modet_active; - int mapped; -}; - -struct go7007_file { - struct go7007 *go; - struct mutex lock; - int buf_count; - struct go7007_buffer *bufs; -}; - -#define GO7007_FORMAT_MJPEG 0 -#define GO7007_FORMAT_MPEG4 1 -#define GO7007_FORMAT_MPEG1 2 -#define GO7007_FORMAT_MPEG2 3 -#define GO7007_FORMAT_H263 4 - -#define GO7007_RATIO_1_1 0 -#define GO7007_RATIO_4_3 1 -#define GO7007_RATIO_16_9 2 - -enum go7007_parser_state { - STATE_DATA, - STATE_00, - STATE_00_00, - STATE_00_00_01, - STATE_FF, - STATE_VBI_LEN_A, - STATE_VBI_LEN_B, - STATE_MODET_MAP, - STATE_UNPARSED, -}; - -struct go7007 { - struct device *dev; - struct go7007_board_info *board_info; - unsigned int board_id; - int tuner_type; - int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */ - char name[64]; - struct video_device *video_dev; - struct v4l2_device v4l2_dev; - int ref_count; - enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; - spinlock_t spinlock; - struct mutex hw_lock; - int streaming; - int in_use; - int audio_enabled; - - /* Video input */ - int input; - enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard; - int sensor_framerate; - int width; - int height; - int encoder_h_offset; - int encoder_v_offset; - unsigned int encoder_h_halve:1; - unsigned int encoder_v_halve:1; - unsigned int encoder_subsample:1; - - /* Encoder config */ - int format; - int bitrate; - int fps_scale; - int pali; - int aspect_ratio; - int gop_size; - unsigned int ipb:1; - unsigned int closed_gop:1; - unsigned int repeat_seqhead:1; - unsigned int seq_header_enable:1; - unsigned int gop_header_enable:1; - unsigned int dvd_mode:1; - unsigned int interlace_coding:1; - - /* Motion detection */ - unsigned int modet_enable:1; - struct { - unsigned int enable:1; - int pixel_threshold; - int motion_threshold; - int mb_threshold; - } modet[4]; - unsigned char modet_map[1624]; - unsigned char active_map[216]; - - /* Video streaming */ - struct go7007_buffer *active_buf; - enum go7007_parser_state state; - int parse_length; - u16 modet_word; - int seen_frame; - u32 next_seq; - struct list_head stream; - wait_queue_head_t frame_waitq; - - /* Audio streaming */ - void (*audio_deliver)(struct go7007 *go, u8 *buf, int length); - void *snd_context; - - /* I2C */ - int i2c_adapter_online; - struct i2c_adapter i2c_adapter; - - /* HPI driver */ - struct go7007_hpi_ops *hpi_ops; - void *hpi_context; - int interrupt_available; - wait_queue_head_t interrupt_waitq; - unsigned short interrupt_value; - unsigned short interrupt_data; -}; - -static inline struct go7007 *to_go7007(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct go7007, v4l2_dev); -} - -/* All of these must be called with the hpi_lock mutex held! */ -#define go7007_interface_reset(go) \ - ((go)->hpi_ops->interface_reset(go)) -#define go7007_write_interrupt(go, x, y) \ - ((go)->hpi_ops->write_interrupt)((go), (x), (y)) -#define go7007_stream_start(go) \ - ((go)->hpi_ops->stream_start(go)) -#define go7007_stream_stop(go) \ - ((go)->hpi_ops->stream_stop(go)) -#define go7007_send_firmware(go, x, y) \ - ((go)->hpi_ops->send_firmware)((go), (x), (y)) -#define go7007_write_addr(go, x, y) \ - ((go)->hpi_ops->write_interrupt)((go), (x)|0x8000, (y)) - -/* go7007-driver.c */ -int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data); -int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data); -int go7007_boot_encoder(struct go7007 *go, int init_i2c); -int go7007_reset_encoder(struct go7007 *go); -int go7007_register_encoder(struct go7007 *go); -int go7007_start_encoder(struct go7007 *go); -void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length); -struct go7007 *go7007_alloc(struct go7007_board_info *board, - struct device *dev); -void go7007_remove(struct go7007 *go); - -/* go7007-fw.c */ -int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen); - -/* go7007-i2c.c */ -int go7007_i2c_init(struct go7007 *go); -int go7007_i2c_remove(struct go7007 *go); - -/* go7007-v4l2.c */ -int go7007_v4l2_init(struct go7007 *go); -void go7007_v4l2_remove(struct go7007 *go); - -/* snd-go7007.c */ -int go7007_snd_init(struct go7007 *go); -int go7007_snd_remove(struct go7007 *go); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-usb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-usb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-usb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-usb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1290 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "go7007-priv.h" -#include "wis-i2c.h" - -static unsigned int assume_endura; -module_param(assume_endura, int, 0644); -MODULE_PARM_DESC(assume_endura, "when probing fails, " - "hardware is a Pelco Endura"); - -/* #define GO7007_USB_DEBUG */ -/* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */ - -#define HPI_STATUS_ADDR 0xFFF4 -#define INT_PARAM_ADDR 0xFFF6 -#define INT_INDEX_ADDR 0xFFF8 - -/* - * Pipes on EZ-USB interface: - * 0 snd - Control - * 0 rcv - Control - * 2 snd - Download firmware (control) - * 4 rcv - Read Interrupt (interrupt) - * 6 rcv - Read Video (bulk) - * 8 rcv - Read Audio (bulk) - */ - -#define GO7007_USB_EZUSB (1<<0) -#define GO7007_USB_EZUSB_I2C (1<<1) - -struct go7007_usb_board { - unsigned int flags; - struct go7007_board_info main_info; -}; - -struct go7007_usb { - struct go7007_usb_board *board; - struct mutex i2c_lock; - struct usb_device *usbdev; - struct urb *video_urbs[8]; - struct urb *audio_urbs[8]; - struct urb *intr_urb; -}; - -/*********************** Product specification data ***********************/ - -static struct go7007_usb_board board_matrix_ii = { - .flags = GO7007_USB_EZUSB, - .main_info = { - .firmware = "go7007tv.bin", - .flags = GO7007_BOARD_HAS_AUDIO | - GO7007_BOARD_USE_ONBOARD_I2C, - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_WORD_16, - .audio_rate = 48000, - .audio_bclk_div = 8, - .audio_main_div = 2, - .hpi_buffer_cap = 7, - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_VALID_ENABLE | - GO7007_SENSOR_TV | - GO7007_SENSOR_VBI | - GO7007_SENSOR_SCALING, - .num_i2c_devs = 1, - .i2c_devs = { - { - .type = "wis_saa7115", - .id = I2C_DRIVERID_WIS_SAA7115, - .addr = 0x20, - }, - }, - .num_inputs = 2, - .inputs = { - { - .video_input = 0, - .name = "Composite", - }, - { - .video_input = 9, - .name = "S-Video", - }, - }, - }, -}; - -static struct go7007_usb_board board_matrix_reload = { - .flags = GO7007_USB_EZUSB, - .main_info = { - .firmware = "go7007tv.bin", - .flags = GO7007_BOARD_HAS_AUDIO | - GO7007_BOARD_USE_ONBOARD_I2C, - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_I2S_MASTER | - GO7007_AUDIO_WORD_16, - .audio_rate = 48000, - .audio_bclk_div = 8, - .audio_main_div = 2, - .hpi_buffer_cap = 7, - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_TV, - .num_i2c_devs = 1, - .i2c_devs = { - { - .type = "wis_saa7113", - .id = I2C_DRIVERID_WIS_SAA7113, - .addr = 0x25, - }, - }, - .num_inputs = 2, - .inputs = { - { - .video_input = 0, - .name = "Composite", - }, - { - .video_input = 9, - .name = "S-Video", - }, - }, - }, -}; - -static struct go7007_usb_board board_star_trek = { - .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, - .main_info = { - .firmware = "go7007tv.bin", - .flags = GO7007_BOARD_HAS_AUDIO, /* | - GO7007_BOARD_HAS_TUNER, */ - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_VALID_ENABLE | - GO7007_SENSOR_TV | - GO7007_SENSOR_VBI | - GO7007_SENSOR_SCALING, - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_WORD_16, - .audio_bclk_div = 8, - .audio_main_div = 2, - .hpi_buffer_cap = 7, - .num_i2c_devs = 1, - .i2c_devs = { - { - .type = "wis_saa7115", - .id = I2C_DRIVERID_WIS_SAA7115, - .addr = 0x20, - }, - }, - .num_inputs = 2, - .inputs = { - { - .video_input = 1, - /* .audio_input = AUDIO_EXTERN, */ - .name = "Composite", - }, - { - .video_input = 8, - /* .audio_input = AUDIO_EXTERN, */ - .name = "S-Video", - }, - /* { - * .video_input = 3, - * .audio_input = AUDIO_TUNER, - * .name = "Tuner", - * }, - */ - }, - }, -}; - -static struct go7007_usb_board board_px_tv402u = { - .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, - .main_info = { - .firmware = "go7007tv.bin", - .flags = GO7007_BOARD_HAS_AUDIO | - GO7007_BOARD_HAS_TUNER, - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_VALID_ENABLE | - GO7007_SENSOR_TV | - GO7007_SENSOR_VBI | - GO7007_SENSOR_SCALING, - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_WORD_16, - .audio_bclk_div = 8, - .audio_main_div = 2, - .hpi_buffer_cap = 7, - .num_i2c_devs = 3, - .i2c_devs = { - { - .type = "wis_saa7115", - .id = I2C_DRIVERID_WIS_SAA7115, - .addr = 0x20, - }, - { - .type = "wis_uda1342", - .id = I2C_DRIVERID_WIS_UDA1342, - .addr = 0x1a, - }, - { - .type = "wis_sony_tuner", - .id = I2C_DRIVERID_WIS_SONY_TUNER, - .addr = 0x60, - }, - }, - .num_inputs = 3, - .inputs = { - { - .video_input = 1, - .audio_input = TVAUDIO_INPUT_EXTERN, - .name = "Composite", - }, - { - .video_input = 8, - .audio_input = TVAUDIO_INPUT_EXTERN, - .name = "S-Video", - }, - { - .video_input = 3, - .audio_input = TVAUDIO_INPUT_TUNER, - .name = "Tuner", - }, - }, - }, -}; - -static struct go7007_usb_board board_xmen = { - .flags = 0, - .main_info = { - .firmware = "go7007tv.bin", - .flags = GO7007_BOARD_USE_ONBOARD_I2C, - .hpi_buffer_cap = 0, - .sensor_flags = GO7007_SENSOR_VREF_POLAR, - .sensor_width = 320, - .sensor_height = 240, - .sensor_framerate = 30030, - .audio_flags = GO7007_AUDIO_ONE_CHANNEL | - GO7007_AUDIO_I2S_MODE_3 | - GO7007_AUDIO_WORD_14 | - GO7007_AUDIO_I2S_MASTER | - GO7007_AUDIO_BCLK_POLAR | - GO7007_AUDIO_OKI_MODE, - .audio_rate = 8000, - .audio_bclk_div = 48, - .audio_main_div = 1, - .num_i2c_devs = 1, - .i2c_devs = { - { - .type = "wis_ov7640", - .id = I2C_DRIVERID_WIS_OV7640, - .addr = 0x21, - }, - }, - .num_inputs = 1, - .inputs = { - { - .name = "Camera", - }, - }, - }, -}; - -static struct go7007_usb_board board_matrix_revolution = { - .flags = GO7007_USB_EZUSB, - .main_info = { - .firmware = "go7007tv.bin", - .flags = GO7007_BOARD_HAS_AUDIO | - GO7007_BOARD_USE_ONBOARD_I2C, - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_I2S_MASTER | - GO7007_AUDIO_WORD_16, - .audio_rate = 48000, - .audio_bclk_div = 8, - .audio_main_div = 2, - .hpi_buffer_cap = 7, - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_TV | - GO7007_SENSOR_VBI, - .num_i2c_devs = 1, - .i2c_devs = { - { - .type = "wis_tw9903", - .id = I2C_DRIVERID_WIS_TW9903, - .addr = 0x44, - }, - }, - .num_inputs = 2, - .inputs = { - { - .video_input = 2, - .name = "Composite", - }, - { - .video_input = 8, - .name = "S-Video", - }, - }, - }, -}; - -static struct go7007_usb_board board_lifeview_lr192 = { - .flags = GO7007_USB_EZUSB, - .main_info = { - .firmware = "go7007tv.bin", - .flags = GO7007_BOARD_HAS_AUDIO | - GO7007_BOARD_USE_ONBOARD_I2C, - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_WORD_16, - .audio_rate = 48000, - .audio_bclk_div = 8, - .audio_main_div = 2, - .hpi_buffer_cap = 7, - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_VALID_ENABLE | - GO7007_SENSOR_TV | - GO7007_SENSOR_VBI | - GO7007_SENSOR_SCALING, - .num_i2c_devs = 0, - .num_inputs = 1, - .inputs = { - { - .video_input = 0, - .name = "Composite", - }, - }, - }, -}; - -static struct go7007_usb_board board_endura = { - .flags = 0, - .main_info = { - .firmware = "go7007tv.bin", - .flags = 0, - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_I2S_MASTER | - GO7007_AUDIO_WORD_16, - .audio_rate = 8000, - .audio_bclk_div = 48, - .audio_main_div = 8, - .hpi_buffer_cap = 0, - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_TV, - .sensor_h_offset = 8, - .num_i2c_devs = 0, - .num_inputs = 1, - .inputs = { - { - .name = "Camera", - }, - }, - }, -}; - -static struct go7007_usb_board board_adlink_mpg24 = { - .flags = 0, - .main_info = { - .firmware = "go7007tv.bin", - .flags = GO7007_BOARD_USE_ONBOARD_I2C, - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_I2S_MASTER | - GO7007_AUDIO_WORD_16, - .audio_rate = 48000, - .audio_bclk_div = 8, - .audio_main_div = 2, - .hpi_buffer_cap = 0, - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_TV | - GO7007_SENSOR_VBI, - .num_i2c_devs = 1, - .i2c_devs = { - { - .type = "wis_tw2804", - .id = I2C_DRIVERID_WIS_TW2804, - .addr = 0x00, /* yes, really */ - }, - }, - .num_inputs = 1, - .inputs = { - { - .name = "Composite", - }, - }, - }, -}; - -static struct go7007_usb_board board_sensoray_2250 = { - .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, - .main_info = { - .firmware = "go7007tv.bin", - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_I2S_MASTER | - GO7007_AUDIO_WORD_16, - .flags = GO7007_BOARD_HAS_AUDIO, - .audio_rate = 48000, - .audio_bclk_div = 8, - .audio_main_div = 2, - .hpi_buffer_cap = 7, - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_TV, - .num_i2c_devs = 1, - .i2c_devs = { - { - .type = "s2250", - .id = I2C_DRIVERID_S2250, - .addr = 0x43, - }, - }, - .num_inputs = 2, - .inputs = { - { - .video_input = 0, - .name = "Composite", - }, - { - .video_input = 1, - .name = "S-Video", - }, - }, - }, -}; - -MODULE_FIRMWARE("go7007tv.bin"); - -static const struct usb_device_id go7007_usb_id_table[] = { - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | - USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ - .idProduct = 0x7007, /* Product ID of GO7007SB chip */ - .bcdDevice_lo = 0x200, /* Revision number of XMen */ - .bcdDevice_hi = 0x200, - .bInterfaceClass = 255, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 255, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, - .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ - .idProduct = 0x7007, /* Product ID of GO7007SB chip */ - .bcdDevice_lo = 0x202, /* Revision number of Matrix II */ - .bcdDevice_hi = 0x202, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, - .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ - .idProduct = 0x7007, /* Product ID of GO7007SB chip */ - .bcdDevice_lo = 0x204, /* Revision number of Matrix */ - .bcdDevice_hi = 0x204, /* Reloaded */ - .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | - USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ - .idProduct = 0x7007, /* Product ID of GO7007SB chip */ - .bcdDevice_lo = 0x205, /* Revision number of XMen-II */ - .bcdDevice_hi = 0x205, - .bInterfaceClass = 255, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 255, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_II, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, - .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ - .idProduct = 0x7007, /* Product ID of GO7007SB chip */ - .bcdDevice_lo = 0x208, /* Revision number of Star Trek */ - .bcdDevice_hi = 0x208, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | - USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ - .idProduct = 0x7007, /* Product ID of GO7007SB chip */ - .bcdDevice_lo = 0x209, /* Revision number of XMen-III */ - .bcdDevice_hi = 0x209, - .bInterfaceClass = 255, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 255, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_III, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, - .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ - .idProduct = 0x7007, /* Product ID of GO7007SB chip */ - .bcdDevice_lo = 0x210, /* Revision number of Matrix */ - .bcdDevice_hi = 0x210, /* Revolution */ - .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, - .idVendor = 0x093b, /* Vendor ID of Plextor */ - .idProduct = 0xa102, /* Product ID of M402U */ - .bcdDevice_lo = 0x1, /* revision number of Blueberry */ - .bcdDevice_hi = 0x1, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_M402U, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, - .idVendor = 0x093b, /* Vendor ID of Plextor */ - .idProduct = 0xa104, /* Product ID of TV402U */ - .bcdDevice_lo = 0x1, - .bcdDevice_hi = 0x1, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U_ANY, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, - .idVendor = 0x10fd, /* Vendor ID of Anubis Electronics */ - .idProduct = 0xde00, /* Product ID of Lifeview LR192 */ - .bcdDevice_lo = 0x1, - .bcdDevice_hi = 0x1, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192, - }, - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, - .idVendor = 0x1943, /* Vendor ID Sensoray */ - .idProduct = 0x2250, /* Product ID of 2250/2251 */ - .bcdDevice_lo = 0x1, - .bcdDevice_hi = 0x1, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250, - }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, go7007_usb_id_table); - -/********************* Driver for EZ-USB HPI interface *********************/ - -static int go7007_usb_vendor_request(struct go7007 *go, int request, - int value, int index, void *transfer_buffer, int length, int in) -{ - struct go7007_usb *usb = go->hpi_context; - int timeout = 5000; - - if (in) { - return usb_control_msg(usb->usbdev, - usb_rcvctrlpipe(usb->usbdev, 0), request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - value, index, transfer_buffer, length, timeout); - } else { - return usb_control_msg(usb->usbdev, - usb_sndctrlpipe(usb->usbdev, 0), request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, transfer_buffer, length, timeout); - } -} - -static int go7007_usb_interface_reset(struct go7007 *go) -{ - struct go7007_usb *usb = go->hpi_context; - u16 intr_val, intr_data; - - /* Reset encoder */ - if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0) - return -1; - msleep(100); - - if (usb->board->flags & GO7007_USB_EZUSB) { - /* Reset buffer in EZ-USB */ -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG "go7007-usb: resetting EZ-USB buffers\n"); -#endif - if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 || - go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0) - return -1; - - /* Reset encoder again */ - if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0) - return -1; - msleep(100); - } - - /* Wait for an interrupt to indicate successful hardware reset */ - if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || - (intr_val & ~0x1) != 0x55aa) { - printk(KERN_ERR - "go7007-usb: unable to reset the USB interface\n"); - return -1; - } - return 0; -} - -static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, - int addr, int data) -{ - struct go7007_usb *usb = go->hpi_context; - int i, r; - u16 status_reg; - int timeout = 500; - -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG - "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data); -#endif - - for (i = 0; i < 100; ++i) { - r = usb_control_msg(usb->usbdev, - usb_rcvctrlpipe(usb->usbdev, 0), 0x14, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0, HPI_STATUS_ADDR, &status_reg, - sizeof(status_reg), timeout); - if (r < 0) - goto write_int_error; - __le16_to_cpus(&status_reg); - if (!(status_reg & 0x0010)) - break; - msleep(10); - } - if (i == 100) { - printk(KERN_ERR - "go7007-usb: device is hung, status reg = 0x%04x\n", - status_reg); - return -1; - } - r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12, - USB_TYPE_VENDOR | USB_RECIP_DEVICE, data, - INT_PARAM_ADDR, NULL, 0, timeout); - if (r < 0) - goto write_int_error; - r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), - 0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr, - INT_INDEX_ADDR, NULL, 0, timeout); - if (r < 0) - goto write_int_error; - return 0; - -write_int_error: - printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r); - return r; -} - -static int go7007_usb_onboard_write_interrupt(struct go7007 *go, - int addr, int data) -{ - struct go7007_usb *usb = go->hpi_context; - u8 *tbuf; - int r; - int timeout = 500; - -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG - "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data); -#endif - - tbuf = kzalloc(8, GFP_KERNEL); - if (tbuf == NULL) - return -ENOMEM; - tbuf[0] = data & 0xff; - tbuf[1] = data >> 8; - tbuf[2] = addr & 0xff; - tbuf[3] = addr >> 8; - r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa, - 0xf0f0, tbuf, 8, timeout); - kfree(tbuf); - if (r < 0) { - printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r); - return r; - } - return 0; -} - -static void go7007_usb_readinterrupt_complete(struct urb *urb) -{ - struct go7007 *go = (struct go7007 *)urb->context; - u16 *regs = (u16 *)urb->transfer_buffer; - int status = urb->status; - - if (status) { - if (status != -ESHUTDOWN && - go->status != STATUS_SHUTDOWN) { - printk(KERN_ERR - "go7007-usb: error in read interrupt: %d\n", - urb->status); - } else { - wake_up(&go->interrupt_waitq); - return; - } - } else if (urb->actual_length != urb->transfer_buffer_length) { - printk(KERN_ERR "go7007-usb: short read in interrupt pipe!\n"); - } else { - go->interrupt_available = 1; - go->interrupt_data = __le16_to_cpu(regs[0]); - go->interrupt_value = __le16_to_cpu(regs[1]); -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG "go7007-usb: ReadInterrupt: %04x %04x\n", - go->interrupt_value, go->interrupt_data); -#endif - } - - wake_up(&go->interrupt_waitq); -} - -static int go7007_usb_read_interrupt(struct go7007 *go) -{ - struct go7007_usb *usb = go->hpi_context; - int r; - - r = usb_submit_urb(usb->intr_urb, GFP_KERNEL); - if (r < 0) { - printk(KERN_ERR - "go7007-usb: unable to submit interrupt urb: %d\n", r); - return r; - } - return 0; -} - -static void go7007_usb_read_video_pipe_complete(struct urb *urb) -{ - struct go7007 *go = (struct go7007 *)urb->context; - int r, status = urb->status; - - if (!go->streaming) { - wake_up_interruptible(&go->frame_waitq); - return; - } - if (status) { - printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", - status); - return; - } - if (urb->actual_length != urb->transfer_buffer_length) { - printk(KERN_ERR "go7007-usb: short read in video pipe!\n"); - return; - } - go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length); - r = usb_submit_urb(urb, GFP_ATOMIC); - if (r < 0) - printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", r); -} - -static void go7007_usb_read_audio_pipe_complete(struct urb *urb) -{ - struct go7007 *go = (struct go7007 *)urb->context; - int r, status = urb->status; - - if (!go->streaming) - return; - if (status) { - printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", - status); - return; - } - if (urb->actual_length != urb->transfer_buffer_length) { - printk(KERN_ERR "go7007-usb: short read in audio pipe!\n"); - return; - } - if (go->audio_deliver != NULL) - go->audio_deliver(go, urb->transfer_buffer, urb->actual_length); - r = usb_submit_urb(urb, GFP_ATOMIC); - if (r < 0) - printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", r); -} - -static int go7007_usb_stream_start(struct go7007 *go) -{ - struct go7007_usb *usb = go->hpi_context; - int i, r; - - for (i = 0; i < 8; ++i) { - r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL); - if (r < 0) { - printk(KERN_ERR "go7007-usb: error submitting video " - "urb %d: %d\n", i, r); - goto video_submit_failed; - } - } - if (!go->audio_enabled) - return 0; - - for (i = 0; i < 8; ++i) { - r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL); - if (r < 0) { - printk(KERN_ERR "go7007-usb: error submitting audio " - "urb %d: %d\n", i, r); - goto audio_submit_failed; - } - } - return 0; - -audio_submit_failed: - for (i = 0; i < 7; ++i) - usb_kill_urb(usb->audio_urbs[i]); -video_submit_failed: - for (i = 0; i < 8; ++i) - usb_kill_urb(usb->video_urbs[i]); - return -1; -} - -static int go7007_usb_stream_stop(struct go7007 *go) -{ - struct go7007_usb *usb = go->hpi_context; - int i; - - if (go->status == STATUS_SHUTDOWN) - return 0; - for (i = 0; i < 8; ++i) - usb_kill_urb(usb->video_urbs[i]); - if (go->audio_enabled) - for (i = 0; i < 8; ++i) - usb_kill_urb(usb->audio_urbs[i]); - return 0; -} - -static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len) -{ - struct go7007_usb *usb = go->hpi_context; - int transferred, pipe; - int timeout = 500; - -#ifdef GO7007_USB_DEBUG - printk(KERN_DEBUG "go7007-usb: DownloadBuffer sending %d bytes\n", len); -#endif - - if (usb->board->flags & GO7007_USB_EZUSB) - pipe = usb_sndbulkpipe(usb->usbdev, 2); - else - pipe = usb_sndbulkpipe(usb->usbdev, 3); - - return usb_bulk_msg(usb->usbdev, pipe, data, len, - &transferred, timeout); -} - -static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = { - .interface_reset = go7007_usb_interface_reset, - .write_interrupt = go7007_usb_ezusb_write_interrupt, - .read_interrupt = go7007_usb_read_interrupt, - .stream_start = go7007_usb_stream_start, - .stream_stop = go7007_usb_stream_stop, - .send_firmware = go7007_usb_send_firmware, -}; - -static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = { - .interface_reset = go7007_usb_interface_reset, - .write_interrupt = go7007_usb_onboard_write_interrupt, - .read_interrupt = go7007_usb_read_interrupt, - .stream_start = go7007_usb_stream_start, - .stream_stop = go7007_usb_stream_stop, - .send_firmware = go7007_usb_send_firmware, -}; - -/********************* Driver for EZ-USB I2C adapter *********************/ - -static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, - struct i2c_msg msgs[], int num) -{ - struct go7007 *go = i2c_get_adapdata(adapter); - struct go7007_usb *usb = go->hpi_context; - u8 buf[16]; - int buf_len, i; - int ret = -1; - - if (go->status == STATUS_SHUTDOWN) - return -1; - - mutex_lock(&usb->i2c_lock); - - for (i = 0; i < num; ++i) { - /* The hardware command is "write some bytes then read some - * bytes", so we try to coalesce a write followed by a read - * into a single USB transaction */ - if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr && - !(msgs[i].flags & I2C_M_RD) && - (msgs[i + 1].flags & I2C_M_RD)) { -#ifdef GO7007_I2C_DEBUG - printk(KERN_DEBUG "go7007-usb: i2c write/read %d/%d " - "bytes on %02x\n", msgs[i].len, - msgs[i + 1].len, msgs[i].addr); -#endif - buf[0] = 0x01; - buf[1] = msgs[i].len + 1; - buf[2] = msgs[i].addr << 1; - memcpy(&buf[3], msgs[i].buf, msgs[i].len); - buf_len = msgs[i].len + 3; - buf[buf_len++] = msgs[++i].len; - } else if (msgs[i].flags & I2C_M_RD) { -#ifdef GO7007_I2C_DEBUG - printk(KERN_DEBUG "go7007-usb: i2c read %d " - "bytes on %02x\n", msgs[i].len, - msgs[i].addr); -#endif - buf[0] = 0x01; - buf[1] = 1; - buf[2] = msgs[i].addr << 1; - buf[3] = msgs[i].len; - buf_len = 4; - } else { -#ifdef GO7007_I2C_DEBUG - printk(KERN_DEBUG "go7007-usb: i2c write %d " - "bytes on %02x\n", msgs[i].len, - msgs[i].addr); -#endif - buf[0] = 0x00; - buf[1] = msgs[i].len + 1; - buf[2] = msgs[i].addr << 1; - memcpy(&buf[3], msgs[i].buf, msgs[i].len); - buf_len = msgs[i].len + 3; - buf[buf_len++] = 0; - } - if (go7007_usb_vendor_request(go, 0x24, 0, 0, - buf, buf_len, 0) < 0) - goto i2c_done; - if (msgs[i].flags & I2C_M_RD) { - memset(buf, 0, sizeof(buf)); - if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf, - msgs[i].len + 1, 1) < 0) - goto i2c_done; - memcpy(msgs[i].buf, buf + 1, msgs[i].len); - } - } - ret = 0; - -i2c_done: - mutex_unlock(&usb->i2c_lock); - return ret; -} - -static u32 go7007_usb_functionality(struct i2c_adapter *adapter) -{ - /* No errors are reported by the hardware, so we don't bother - * supporting quick writes to avoid confusing probing */ - return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK; -} - -static struct i2c_algorithm go7007_usb_algo = { - .master_xfer = go7007_usb_i2c_master_xfer, - .functionality = go7007_usb_functionality, -}; - -static struct i2c_adapter go7007_usb_adap_templ = { - .owner = THIS_MODULE, - .name = "WIS GO7007SB EZ-USB", - .algo = &go7007_usb_algo, -}; - -/********************* USB add/remove functions *********************/ - -static int go7007_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct go7007 *go; - struct go7007_usb *usb; - struct go7007_usb_board *board; - struct usb_device *usbdev = interface_to_usbdev(intf); - char *name; - int video_pipe, i, v_urb_len; - - printk(KERN_DEBUG "go7007-usb: probing new GO7007 USB board\n"); - - switch (id->driver_info) { - case GO7007_BOARDID_MATRIX_II: - name = "WIS Matrix II or compatible"; - board = &board_matrix_ii; - break; - case GO7007_BOARDID_MATRIX_RELOAD: - name = "WIS Matrix Reloaded or compatible"; - board = &board_matrix_reload; - break; - case GO7007_BOARDID_MATRIX_REV: - name = "WIS Matrix Revolution or compatible"; - board = &board_matrix_revolution; - break; - case GO7007_BOARDID_STAR_TREK: - name = "WIS Star Trek or compatible"; - board = &board_star_trek; - break; - case GO7007_BOARDID_XMEN: - name = "WIS XMen or compatible"; - board = &board_xmen; - break; - case GO7007_BOARDID_XMEN_II: - name = "WIS XMen II or compatible"; - board = &board_xmen; - break; - case GO7007_BOARDID_XMEN_III: - name = "WIS XMen III or compatible"; - board = &board_xmen; - break; - case GO7007_BOARDID_PX_M402U: - name = "Plextor PX-M402U"; - board = &board_matrix_ii; - break; - case GO7007_BOARDID_PX_TV402U_ANY: - name = "Plextor PX-TV402U (unknown tuner)"; - board = &board_px_tv402u; - break; - case GO7007_BOARDID_LIFEVIEW_LR192: - printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra " - "is not supported. Sorry!\n"); - return 0; - name = "Lifeview TV Walker Ultra"; - board = &board_lifeview_lr192; - break; - case GO7007_BOARDID_SENSORAY_2250: - printk(KERN_INFO "Sensoray 2250 found\n"); - name = "Sensoray 2250/2251"; - board = &board_sensoray_2250; - break; - default: - printk(KERN_ERR "go7007-usb: unknown board ID %d!\n", - (unsigned int)id->driver_info); - return 0; - } - - usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL); - if (usb == NULL) - return -ENOMEM; - - /* Allocate the URB and buffer for receiving incoming interrupts */ - usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if (usb->intr_urb == NULL) - goto allocfail; - usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL); - if (usb->intr_urb->transfer_buffer == NULL) - goto allocfail; - - go = go7007_alloc(&board->main_info, &intf->dev); - if (go == NULL) - goto allocfail; - usb->board = board; - usb->usbdev = usbdev; - go->board_id = id->driver_info; - strncpy(go->name, name, sizeof(go->name)); - if (board->flags & GO7007_USB_EZUSB) - go->hpi_ops = &go7007_usb_ezusb_hpi_ops; - else - go->hpi_ops = &go7007_usb_onboard_hpi_ops; - go->hpi_context = usb; - usb_fill_int_urb(usb->intr_urb, usb->usbdev, - usb_rcvintpipe(usb->usbdev, 4), - usb->intr_urb->transfer_buffer, 2*sizeof(u16), - go7007_usb_readinterrupt_complete, go, 8); - usb_set_intfdata(intf, &go->v4l2_dev); - - /* Boot the GO7007 */ - if (go7007_boot_encoder(go, go->board_info->flags & - GO7007_BOARD_USE_ONBOARD_I2C) < 0) - goto initfail; - - /* Register the EZ-USB I2C adapter, if we're using it */ - if (board->flags & GO7007_USB_EZUSB_I2C) { - memcpy(&go->i2c_adapter, &go7007_usb_adap_templ, - sizeof(go7007_usb_adap_templ)); - mutex_init(&usb->i2c_lock); - go->i2c_adapter.dev.parent = go->dev; - i2c_set_adapdata(&go->i2c_adapter, go); - if (i2c_add_adapter(&go->i2c_adapter) < 0) { - printk(KERN_ERR - "go7007-usb: error: i2c_add_adapter failed\n"); - goto initfail; - } - go->i2c_adapter_online = 1; - } - - /* Pelco and Adlink reused the XMen and XMen-III vendor and product - * IDs for their own incompatible designs. We can detect XMen boards - * by probing the sensor, but there is no way to probe the sensors on - * the Pelco and Adlink designs so we default to the Adlink. If it - * is actually a Pelco, the user must set the assume_endura module - * parameter. */ - if ((go->board_id == GO7007_BOARDID_XMEN || - go->board_id == GO7007_BOARDID_XMEN_III) && - go->i2c_adapter_online) { - union i2c_smbus_data data; - - /* Check to see if register 0x0A is 0x76 */ - i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB, - I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data); - if (data.byte != 0x76) { - if (assume_endura) { - go->board_id = GO7007_BOARDID_ENDURA; - usb->board = board = &board_endura; - go->board_info = &board->main_info; - strncpy(go->name, "Pelco Endura", - sizeof(go->name)); - } else { - u16 channel; - - /* set GPIO5 to be an output, currently low */ - go7007_write_addr(go, 0x3c82, 0x0000); - go7007_write_addr(go, 0x3c80, 0x00df); - /* read channel number from GPIO[1:0] */ - go7007_read_addr(go, 0x3c81, &channel); - channel &= 0x3; - go->board_id = GO7007_BOARDID_ADLINK_MPG24; - usb->board = board = &board_adlink_mpg24; - go->board_info = &board->main_info; - go->channel_number = channel; - snprintf(go->name, sizeof(go->name), - "Adlink PCI-MPG24, channel #%d", - channel); - } - } - } - - /* Probe the tuner model on the TV402U */ - if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) { - u8 data[3]; - - /* Board strapping indicates tuner model */ - if (go7007_usb_vendor_request(go, 0x41, 0, 0, data, 3, 1) < 0) { - printk(KERN_ERR "go7007-usb: GPIO read failed!\n"); - goto initfail; - } - switch (data[0] >> 6) { - case 1: - go->board_id = GO7007_BOARDID_PX_TV402U_EU; - go->tuner_type = TUNER_SONY_BTF_PG472Z; - strncpy(go->name, "Plextor PX-TV402U-EU", - sizeof(go->name)); - break; - case 2: - go->board_id = GO7007_BOARDID_PX_TV402U_JP; - go->tuner_type = TUNER_SONY_BTF_PK467Z; - strncpy(go->name, "Plextor PX-TV402U-JP", - sizeof(go->name)); - break; - case 3: - go->board_id = GO7007_BOARDID_PX_TV402U_NA; - go->tuner_type = TUNER_SONY_BTF_PB463Z; - strncpy(go->name, "Plextor PX-TV402U-NA", - sizeof(go->name)); - break; - default: - printk(KERN_DEBUG "go7007-usb: unable to detect " - "tuner type!\n"); - break; - } - /* Configure tuner mode selection inputs connected - * to the EZ-USB GPIO output pins */ - if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0, - NULL, 0, 0) < 0) { - printk(KERN_ERR "go7007-usb: GPIO write failed!\n"); - goto initfail; - } - } - - /* Print a nasty message if the user attempts to use a USB2.0 device in - * a USB1.1 port. There will be silent corruption of the stream. */ - if ((board->flags & GO7007_USB_EZUSB) && - usbdev->speed != USB_SPEED_HIGH) - printk(KERN_ERR "go7007-usb: *** WARNING *** This device " - "must be connected to a USB 2.0 port! " - "Attempting to capture video through a USB 1.1 " - "port will result in stream corruption, even " - "at low bitrates!\n"); - - /* Do any final GO7007 initialization, then register the - * V4L2 and ALSA interfaces */ - if (go7007_register_encoder(go) < 0) - goto initfail; - - /* Allocate the URBs and buffers for receiving the video stream */ - if (board->flags & GO7007_USB_EZUSB) { - v_urb_len = 1024; - video_pipe = usb_rcvbulkpipe(usb->usbdev, 6); - } else { - v_urb_len = 512; - video_pipe = usb_rcvbulkpipe(usb->usbdev, 1); - } - for (i = 0; i < 8; ++i) { - usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); - if (usb->video_urbs[i] == NULL) - goto initfail; - usb->video_urbs[i]->transfer_buffer = - kmalloc(v_urb_len, GFP_KERNEL); - if (usb->video_urbs[i]->transfer_buffer == NULL) - goto initfail; - usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe, - usb->video_urbs[i]->transfer_buffer, v_urb_len, - go7007_usb_read_video_pipe_complete, go); - } - - /* Allocate the URBs and buffers for receiving the audio stream */ - if ((board->flags & GO7007_USB_EZUSB) && go->audio_enabled) - for (i = 0; i < 8; ++i) { - usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); - if (usb->audio_urbs[i] == NULL) - goto initfail; - usb->audio_urbs[i]->transfer_buffer = kmalloc(4096, - GFP_KERNEL); - if (usb->audio_urbs[i]->transfer_buffer == NULL) - goto initfail; - usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev, - usb_rcvbulkpipe(usb->usbdev, 8), - usb->audio_urbs[i]->transfer_buffer, 4096, - go7007_usb_read_audio_pipe_complete, go); - } - - - go->status = STATUS_ONLINE; - return 0; - -initfail: - go->status = STATUS_SHUTDOWN; - return 0; - -allocfail: - if (usb->intr_urb) { - kfree(usb->intr_urb->transfer_buffer); - usb_free_urb(usb->intr_urb); - } - kfree(usb); - return -ENOMEM; -} - -static void go7007_usb_disconnect(struct usb_interface *intf) -{ - struct go7007 *go = to_go7007(usb_get_intfdata(intf)); - struct go7007_usb *usb = go->hpi_context; - struct urb *vurb, *aurb; - int i; - - go->status = STATUS_SHUTDOWN; - usb_kill_urb(usb->intr_urb); - - /* Free USB-related structs */ - for (i = 0; i < 8; ++i) { - vurb = usb->video_urbs[i]; - if (vurb) { - usb_kill_urb(vurb); - if (vurb->transfer_buffer) - kfree(vurb->transfer_buffer); - usb_free_urb(vurb); - } - aurb = usb->audio_urbs[i]; - if (aurb) { - usb_kill_urb(aurb); - if (aurb->transfer_buffer) - kfree(aurb->transfer_buffer); - usb_free_urb(aurb); - } - } - kfree(usb->intr_urb->transfer_buffer); - usb_free_urb(usb->intr_urb); - - kfree(go->hpi_context); - - go7007_remove(go); -} - -static struct usb_driver go7007_usb_driver = { - .name = "go7007", - .probe = go7007_usb_probe, - .disconnect = go7007_usb_disconnect, - .id_table = go7007_usb_id_table, -}; - -static int __init go7007_usb_init(void) -{ - return usb_register(&go7007_usb_driver); -} - -static void __exit go7007_usb_cleanup(void) -{ - usb_deregister(&go7007_usb_driver); -} - -module_init(go7007_usb_init); -module_exit(go7007_usb_cleanup); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-v4l2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-v4l2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-v4l2.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/go7007-v4l2.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1839 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "go7007.h" -#include "go7007-priv.h" -#include "wis-i2c.h" - -/* Temporary defines until accepted in v4l-dvb */ -#ifndef V4L2_MPEG_STREAM_TYPE_MPEG_ELEM -#define V4L2_MPEG_STREAM_TYPE_MPEG_ELEM 6 /* MPEG elementary stream */ -#endif -#ifndef V4L2_MPEG_VIDEO_ENCODING_MPEG_4 -#define V4L2_MPEG_VIDEO_ENCODING_MPEG_4 3 -#endif - -#define call_all(dev, o, f, args...) \ - v4l2_device_call_until_err(dev, 0, o, f, ##args) - -static void deactivate_buffer(struct go7007_buffer *gobuf) -{ - int i; - - if (gobuf->state != BUF_STATE_IDLE) { - list_del(&gobuf->stream); - gobuf->state = BUF_STATE_IDLE; - } - if (gobuf->page_count > 0) { - for (i = 0; i < gobuf->page_count; ++i) - page_cache_release(gobuf->pages[i]); - gobuf->page_count = 0; - } -} - -static void abort_queued(struct go7007 *go) -{ - struct go7007_buffer *gobuf, *next; - - list_for_each_entry_safe(gobuf, next, &go->stream, stream) { - deactivate_buffer(gobuf); - } -} - -static int go7007_streamoff(struct go7007 *go) -{ - int retval = -EINVAL; - unsigned long flags; - - mutex_lock(&go->hw_lock); - if (go->streaming) { - go->streaming = 0; - go7007_stream_stop(go); - spin_lock_irqsave(&go->spinlock, flags); - abort_queued(go); - spin_unlock_irqrestore(&go->spinlock, flags); - go7007_reset_encoder(go); - retval = 0; - } - mutex_unlock(&go->hw_lock); - return 0; -} - -static int go7007_open(struct file *file) -{ - struct go7007 *go = video_get_drvdata(video_devdata(file)); - struct go7007_file *gofh; - - if (go->status != STATUS_ONLINE) - return -EBUSY; - gofh = kmalloc(sizeof(struct go7007_file), GFP_KERNEL); - if (gofh == NULL) - return -ENOMEM; - ++go->ref_count; - gofh->go = go; - mutex_init(&gofh->lock); - gofh->buf_count = 0; - file->private_data = gofh; - return 0; -} - -static int go7007_release(struct file *file) -{ - struct go7007_file *gofh = file->private_data; - struct go7007 *go = gofh->go; - - if (gofh->buf_count > 0) { - go7007_streamoff(go); - go->in_use = 0; - kfree(gofh->bufs); - gofh->buf_count = 0; - } - kfree(gofh); - if (--go->ref_count == 0) - kfree(go); - file->private_data = NULL; - return 0; -} - -static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format) -{ - u8 *f = page_address(gobuf->pages[0]); - - switch (format) { - case GO7007_FORMAT_MJPEG: - return V4L2_BUF_FLAG_KEYFRAME; - case GO7007_FORMAT_MPEG4: - switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) { - case 0: - return V4L2_BUF_FLAG_KEYFRAME; - case 1: - return V4L2_BUF_FLAG_PFRAME; - case 2: - return V4L2_BUF_FLAG_BFRAME; - default: - return 0; - } - case GO7007_FORMAT_MPEG1: - case GO7007_FORMAT_MPEG2: - switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) { - case 1: - return V4L2_BUF_FLAG_KEYFRAME; - case 2: - return V4L2_BUF_FLAG_PFRAME; - case 3: - return V4L2_BUF_FLAG_BFRAME; - default: - return 0; - } - } - - return 0; -} - -static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) -{ - int sensor_height = 0, sensor_width = 0; - int width, height, i; - - if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && - fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG && - fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG4) - return -EINVAL; - - switch (go->standard) { - case GO7007_STD_NTSC: - sensor_width = 720; - sensor_height = 480; - break; - case GO7007_STD_PAL: - sensor_width = 720; - sensor_height = 576; - break; - case GO7007_STD_OTHER: - sensor_width = go->board_info->sensor_width; - sensor_height = go->board_info->sensor_height; - break; - } - - if (fmt == NULL) { - width = sensor_width; - height = sensor_height; - } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { - if (fmt->fmt.pix.width > sensor_width) - width = sensor_width; - else if (fmt->fmt.pix.width < 144) - width = 144; - else - width = fmt->fmt.pix.width & ~0x0f; - - if (fmt->fmt.pix.height > sensor_height) - height = sensor_height; - else if (fmt->fmt.pix.height < 96) - height = 96; - else - height = fmt->fmt.pix.height & ~0x0f; - } else { - int requested_size = fmt->fmt.pix.width * fmt->fmt.pix.height; - int sensor_size = sensor_width * sensor_height; - - if (64 * requested_size < 9 * sensor_size) { - width = sensor_width / 4; - height = sensor_height / 4; - } else if (64 * requested_size < 36 * sensor_size) { - width = sensor_width / 2; - height = sensor_height / 2; - } else { - width = sensor_width; - height = sensor_height; - } - width &= ~0xf; - height &= ~0xf; - } - - if (fmt != NULL) { - u32 pixelformat = fmt->fmt.pix.pixelformat; - - memset(fmt, 0, sizeof(*fmt)); - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt->fmt.pix.width = width; - fmt->fmt.pix.height = height; - fmt->fmt.pix.pixelformat = pixelformat; - fmt->fmt.pix.field = V4L2_FIELD_NONE; - fmt->fmt.pix.bytesperline = 0; - fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */ - } - - if (try) - return 0; - - go->width = width; - go->height = height; - go->encoder_h_offset = go->board_info->sensor_h_offset; - go->encoder_v_offset = go->board_info->sensor_v_offset; - for (i = 0; i < 4; ++i) - go->modet[i].enable = 0; - for (i = 0; i < 1624; ++i) - go->modet_map[i] = 0; - - if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { - struct v4l2_mbus_framefmt mbus_fmt; - - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - if (fmt != NULL) - mbus_fmt.width = fmt->fmt.pix.width; - else - mbus_fmt.width = width; - - if (height > sensor_height / 2) { - mbus_fmt.height = height / 2; - go->encoder_v_halve = 0; - } else { - mbus_fmt.height = height; - go->encoder_v_halve = 1; - } - call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt); - } else { - if (width <= sensor_width / 4) { - go->encoder_h_halve = 1; - go->encoder_v_halve = 1; - go->encoder_subsample = 1; - } else if (width <= sensor_width / 2) { - go->encoder_h_halve = 1; - go->encoder_v_halve = 1; - go->encoder_subsample = 0; - } else { - go->encoder_h_halve = 0; - go->encoder_v_halve = 0; - go->encoder_subsample = 0; - } - } - - if (fmt == NULL) - return 0; - - switch (fmt->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_MPEG: - if (go->format == GO7007_FORMAT_MPEG1 || - go->format == GO7007_FORMAT_MPEG2 || - go->format == GO7007_FORMAT_MPEG4) - break; - go->format = GO7007_FORMAT_MPEG1; - go->pali = 0; - go->aspect_ratio = GO7007_RATIO_1_1; - go->gop_size = go->sensor_framerate / 1000; - go->ipb = 0; - go->closed_gop = 1; - go->repeat_seqhead = 1; - go->seq_header_enable = 1; - go->gop_header_enable = 1; - go->dvd_mode = 0; - break; - /* Backwards compatibility only! */ - case V4L2_PIX_FMT_MPEG4: - if (go->format == GO7007_FORMAT_MPEG4) - break; - go->format = GO7007_FORMAT_MPEG4; - go->pali = 0xf5; - go->aspect_ratio = GO7007_RATIO_1_1; - go->gop_size = go->sensor_framerate / 1000; - go->ipb = 0; - go->closed_gop = 1; - go->repeat_seqhead = 1; - go->seq_header_enable = 1; - go->gop_header_enable = 1; - go->dvd_mode = 0; - break; - case V4L2_PIX_FMT_MJPEG: - go->format = GO7007_FORMAT_MJPEG; - go->pali = 0; - go->aspect_ratio = GO7007_RATIO_1_1; - go->gop_size = 0; - go->ipb = 0; - go->closed_gop = 0; - go->repeat_seqhead = 0; - go->seq_header_enable = 0; - go->gop_header_enable = 0; - go->dvd_mode = 0; - break; - } - return 0; -} - -#if 0 -static int clip_to_modet_map(struct go7007 *go, int region, - struct v4l2_clip *clip_list) -{ - struct v4l2_clip clip, *clip_ptr; - int x, y, mbnum; - - /* Check if coordinates are OK and if any macroblocks are already - * used by other regions (besides 0) */ - clip_ptr = clip_list; - while (clip_ptr) { - if (copy_from_user(&clip, clip_ptr, sizeof(clip))) - return -EFAULT; - if (clip.c.left < 0 || (clip.c.left & 0xF) || - clip.c.width <= 0 || (clip.c.width & 0xF)) - return -EINVAL; - if (clip.c.left + clip.c.width > go->width) - return -EINVAL; - if (clip.c.top < 0 || (clip.c.top & 0xF) || - clip.c.height <= 0 || (clip.c.height & 0xF)) - return -EINVAL; - if (clip.c.top + clip.c.height > go->height) - return -EINVAL; - for (y = 0; y < clip.c.height; y += 16) - for (x = 0; x < clip.c.width; x += 16) { - mbnum = (go->width >> 4) * - ((clip.c.top + y) >> 4) + - ((clip.c.left + x) >> 4); - if (go->modet_map[mbnum] != 0 && - go->modet_map[mbnum] != region) - return -EBUSY; - } - clip_ptr = clip.next; - } - - /* Clear old region macroblocks */ - for (mbnum = 0; mbnum < 1624; ++mbnum) - if (go->modet_map[mbnum] == region) - go->modet_map[mbnum] = 0; - - /* Claim macroblocks in this list */ - clip_ptr = clip_list; - while (clip_ptr) { - if (copy_from_user(&clip, clip_ptr, sizeof(clip))) - return -EFAULT; - for (y = 0; y < clip.c.height; y += 16) - for (x = 0; x < clip.c.width; x += 16) { - mbnum = (go->width >> 4) * - ((clip.c.top + y) >> 4) + - ((clip.c.left + x) >> 4); - go->modet_map[mbnum] = region; - } - clip_ptr = clip.next; - } - return 0; -} -#endif - -static int mpeg_query_ctrl(struct v4l2_queryctrl *ctrl) -{ - static const u32 mpeg_ctrls[] = { - V4L2_CID_MPEG_CLASS, - V4L2_CID_MPEG_STREAM_TYPE, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_CID_MPEG_VIDEO_ASPECT, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, - V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, - V4L2_CID_MPEG_VIDEO_BITRATE, - 0 - }; - static const u32 *ctrl_classes[] = { - mpeg_ctrls, - NULL - }; - - ctrl->id = v4l2_ctrl_next(ctrl_classes, ctrl->id); - - switch (ctrl->id) { - case V4L2_CID_MPEG_CLASS: - return v4l2_ctrl_query_fill(ctrl, 0, 0, 0, 0); - case V4L2_CID_MPEG_STREAM_TYPE: - return v4l2_ctrl_query_fill(ctrl, - V4L2_MPEG_STREAM_TYPE_MPEG2_DVD, - V4L2_MPEG_STREAM_TYPE_MPEG_ELEM, 1, - V4L2_MPEG_STREAM_TYPE_MPEG_ELEM); - case V4L2_CID_MPEG_VIDEO_ENCODING: - return v4l2_ctrl_query_fill(ctrl, - V4L2_MPEG_VIDEO_ENCODING_MPEG_1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4, 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2); - case V4L2_CID_MPEG_VIDEO_ASPECT: - return v4l2_ctrl_query_fill(ctrl, - V4L2_MPEG_VIDEO_ASPECT_1x1, - V4L2_MPEG_VIDEO_ASPECT_16x9, 1, - V4L2_MPEG_VIDEO_ASPECT_1x1); - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - return v4l2_ctrl_query_fill(ctrl, 0, 34, 1, 15); - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - return v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0); - case V4L2_CID_MPEG_VIDEO_BITRATE: - return v4l2_ctrl_query_fill(ctrl, - 64000, - 10000000, 1, - 1500000); - default: - return -EINVAL; - } - return 0; -} - -static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go) -{ - /* pretty sure we can't change any of these while streaming */ - if (go->streaming) - return -EBUSY; - - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - switch (ctrl->value) { - case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD: - go->format = GO7007_FORMAT_MPEG2; - go->bitrate = 9800000; - go->gop_size = 15; - go->pali = 0x48; - go->closed_gop = 1; - go->repeat_seqhead = 0; - go->seq_header_enable = 1; - go->gop_header_enable = 1; - go->dvd_mode = 1; - break; - case V4L2_MPEG_STREAM_TYPE_MPEG_ELEM: - /* todo: */ - break; - default: - return -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - switch (ctrl->value) { - case V4L2_MPEG_VIDEO_ENCODING_MPEG_1: - go->format = GO7007_FORMAT_MPEG1; - go->pali = 0; - break; - case V4L2_MPEG_VIDEO_ENCODING_MPEG_2: - go->format = GO7007_FORMAT_MPEG2; - /*if (mpeg->pali >> 24 == 2) - go->pali = mpeg->pali & 0xff; - else*/ - go->pali = 0x48; - break; - case V4L2_MPEG_VIDEO_ENCODING_MPEG_4: - go->format = GO7007_FORMAT_MPEG4; - /*if (mpeg->pali >> 24 == 4) - go->pali = mpeg->pali & 0xff; - else*/ - go->pali = 0xf5; - break; - default: - return -EINVAL; - } - go->gop_header_enable = - /*mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER - ? 0 :*/ 1; - /*if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER) - go->repeat_seqhead = 1; - else*/ - go->repeat_seqhead = 0; - go->dvd_mode = 0; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - if (go->format == GO7007_FORMAT_MJPEG) - return -EINVAL; - switch (ctrl->value) { - case V4L2_MPEG_VIDEO_ASPECT_1x1: - go->aspect_ratio = GO7007_RATIO_1_1; - break; - case V4L2_MPEG_VIDEO_ASPECT_4x3: - go->aspect_ratio = GO7007_RATIO_4_3; - break; - case V4L2_MPEG_VIDEO_ASPECT_16x9: - go->aspect_ratio = GO7007_RATIO_16_9; - break; - case V4L2_MPEG_VIDEO_ASPECT_221x100: - default: - return -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - if (ctrl->value < 0 || ctrl->value > 34) - return -EINVAL; - go->gop_size = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - if (ctrl->value != 0 && ctrl->value != 1) - return -EINVAL; - go->closed_gop = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - /* Upper bound is kind of arbitrary here */ - if (ctrl->value < 64000 || ctrl->value > 10000000) - return -EINVAL; - go->bitrate = ctrl->value; - break; - default: - return -EINVAL; - } - return 0; -} - -static int mpeg_g_ctrl(struct v4l2_control *ctrl, struct go7007 *go) -{ - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - if (go->dvd_mode) - ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_DVD; - else - ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG_ELEM; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - switch (go->format) { - case GO7007_FORMAT_MPEG1: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - break; - case GO7007_FORMAT_MPEG2: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - break; - case GO7007_FORMAT_MPEG4: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4; - break; - default: - return -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - switch (go->aspect_ratio) { - case GO7007_RATIO_1_1: - ctrl->value = V4L2_MPEG_VIDEO_ASPECT_1x1; - break; - case GO7007_RATIO_4_3: - ctrl->value = V4L2_MPEG_VIDEO_ASPECT_4x3; - break; - case GO7007_RATIO_16_9: - ctrl->value = V4L2_MPEG_VIDEO_ASPECT_16x9; - break; - default: - return -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - ctrl->value = go->gop_size; - break; - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - ctrl->value = go->closed_gop; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - ctrl->value = go->bitrate; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - strlcpy(cap->driver, "go7007", sizeof(cap->driver)); - strlcpy(cap->card, go->name, sizeof(cap->card)); -#if 0 - strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info)); -#endif - - cap->version = KERNEL_VERSION(0, 9, 8); - - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */ - - if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) - cap->capabilities |= V4L2_CAP_TUNER; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - char *desc = NULL; - - switch (fmt->index) { - case 0: - fmt->pixelformat = V4L2_PIX_FMT_MJPEG; - desc = "Motion-JPEG"; - break; - case 1: - fmt->pixelformat = V4L2_PIX_FMT_MPEG; - desc = "MPEG1/MPEG2/MPEG4"; - break; - default: - return -EINVAL; - } - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt->flags = V4L2_FMT_FLAG_COMPRESSED; - - strncpy(fmt->description, desc, sizeof(fmt->description)); - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt->fmt.pix.width = go->width; - fmt->fmt.pix.height = go->height; - fmt->fmt.pix.pixelformat = (go->format == GO7007_FORMAT_MJPEG) ? - V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG; - fmt->fmt.pix.field = V4L2_FIELD_NONE; - fmt->fmt.pix.bytesperline = 0; - fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - return set_capture_size(go, fmt, 1); -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (go->streaming) - return -EBUSY; - - return set_capture_size(go, fmt, 0); -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req) -{ - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; - int retval = -EBUSY; - unsigned int count, i; - - if (go->streaming) - return retval; - - if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - req->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - mutex_lock(&gofh->lock); - for (i = 0; i < gofh->buf_count; ++i) - if (gofh->bufs[i].mapped > 0) - goto unlock_and_return; - - mutex_lock(&go->hw_lock); - if (go->in_use > 0 && gofh->buf_count == 0) { - mutex_unlock(&go->hw_lock); - goto unlock_and_return; - } - - if (gofh->buf_count > 0) - kfree(gofh->bufs); - - retval = -ENOMEM; - count = req->count; - if (count > 0) { - if (count < 2) - count = 2; - if (count > 32) - count = 32; - - gofh->bufs = kcalloc(count, sizeof(struct go7007_buffer), - GFP_KERNEL); - - if (!gofh->bufs) { - mutex_unlock(&go->hw_lock); - goto unlock_and_return; - } - - for (i = 0; i < count; ++i) { - gofh->bufs[i].go = go; - gofh->bufs[i].index = i; - gofh->bufs[i].state = BUF_STATE_IDLE; - gofh->bufs[i].mapped = 0; - } - - go->in_use = 1; - } else { - go->in_use = 0; - } - - gofh->buf_count = count; - mutex_unlock(&go->hw_lock); - mutex_unlock(&gofh->lock); - - memset(req, 0, sizeof(*req)); - - req->count = count; - req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - req->memory = V4L2_MEMORY_MMAP; - - return 0; - -unlock_and_return: - mutex_unlock(&gofh->lock); - return retval; -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct go7007_file *gofh = priv; - int retval = -EINVAL; - unsigned int index; - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return retval; - - index = buf->index; - - mutex_lock(&gofh->lock); - if (index >= gofh->buf_count) - goto unlock_and_return; - - memset(buf, 0, sizeof(*buf)); - buf->index = index; - buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - switch (gofh->bufs[index].state) { - case BUF_STATE_QUEUED: - buf->flags = V4L2_BUF_FLAG_QUEUED; - break; - case BUF_STATE_DONE: - buf->flags = V4L2_BUF_FLAG_DONE; - break; - default: - buf->flags = 0; - } - - if (gofh->bufs[index].mapped) - buf->flags |= V4L2_BUF_FLAG_MAPPED; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = index * GO7007_BUF_SIZE; - buf->length = GO7007_BUF_SIZE; - mutex_unlock(&gofh->lock); - - return 0; - -unlock_and_return: - mutex_unlock(&gofh->lock); - return retval; -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; - struct go7007_buffer *gobuf; - unsigned long flags; - int retval = -EINVAL; - int ret; - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->memory != V4L2_MEMORY_MMAP) - return retval; - - mutex_lock(&gofh->lock); - if (buf->index < 0 || buf->index >= gofh->buf_count) - goto unlock_and_return; - - gobuf = &gofh->bufs[buf->index]; - if (!gobuf->mapped) - goto unlock_and_return; - - retval = -EBUSY; - if (gobuf->state != BUF_STATE_IDLE) - goto unlock_and_return; - - /* offset will be 0 until we really support USERPTR streaming */ - gobuf->offset = gobuf->user_addr & ~PAGE_MASK; - gobuf->bytesused = 0; - gobuf->frame_offset = 0; - gobuf->modet_active = 0; - if (gobuf->offset > 0) - gobuf->page_count = GO7007_BUF_PAGES + 1; - else - gobuf->page_count = GO7007_BUF_PAGES; - - retval = -ENOMEM; - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, - gobuf->user_addr & PAGE_MASK, gobuf->page_count, - 1, 1, gobuf->pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (ret != gobuf->page_count) { - int i; - for (i = 0; i < ret; ++i) - page_cache_release(gobuf->pages[i]); - gobuf->page_count = 0; - goto unlock_and_return; - } - - gobuf->state = BUF_STATE_QUEUED; - spin_lock_irqsave(&go->spinlock, flags); - list_add_tail(&gobuf->stream, &go->stream); - spin_unlock_irqrestore(&go->spinlock, flags); - mutex_unlock(&gofh->lock); - - return 0; - -unlock_and_return: - mutex_unlock(&gofh->lock); - return retval; -} - - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; - struct go7007_buffer *gobuf; - int retval = -EINVAL; - unsigned long flags; - u32 frame_type_flag; - DEFINE_WAIT(wait); - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return retval; - if (buf->memory != V4L2_MEMORY_MMAP) - return retval; - - mutex_lock(&gofh->lock); - if (list_empty(&go->stream)) - goto unlock_and_return; - gobuf = list_entry(go->stream.next, - struct go7007_buffer, stream); - - retval = -EAGAIN; - if (gobuf->state != BUF_STATE_DONE && - !(file->f_flags & O_NONBLOCK)) { - for (;;) { - prepare_to_wait(&go->frame_waitq, &wait, - TASK_INTERRUPTIBLE); - if (gobuf->state == BUF_STATE_DONE) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - } - finish_wait(&go->frame_waitq, &wait); - } - if (gobuf->state != BUF_STATE_DONE) - goto unlock_and_return; - - spin_lock_irqsave(&go->spinlock, flags); - deactivate_buffer(gobuf); - spin_unlock_irqrestore(&go->spinlock, flags); - frame_type_flag = get_frame_type_flag(gobuf, go->format); - gobuf->state = BUF_STATE_IDLE; - - memset(buf, 0, sizeof(*buf)); - buf->index = gobuf->index; - buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->bytesused = gobuf->bytesused; - buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag; - buf->field = V4L2_FIELD_NONE; - buf->timestamp = gobuf->timestamp; - buf->sequence = gobuf->seq; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = gobuf->index * GO7007_BUF_SIZE; - buf->length = GO7007_BUF_SIZE; - buf->reserved = gobuf->modet_active; - - mutex_unlock(&gofh->lock); - return 0; - -unlock_and_return: - mutex_unlock(&gofh->lock); - return retval; -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; - int retval = 0; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - mutex_lock(&gofh->lock); - mutex_lock(&go->hw_lock); - - if (!go->streaming) { - go->streaming = 1; - go->next_seq = 0; - go->active_buf = NULL; - if (go7007_start_encoder(go) < 0) - retval = -EIO; - else - retval = 0; - } - mutex_unlock(&go->hw_lock); - mutex_unlock(&gofh->lock); - - return retval; -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - mutex_lock(&gofh->lock); - go7007_streamoff(go); - mutex_unlock(&gofh->lock); - - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *query) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - int id = query->id; - - if (0 == call_all(&go->v4l2_dev, core, queryctrl, query)) - return 0; - - query->id = id; - return mpeg_query_ctrl(query); -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (0 == call_all(&go->v4l2_dev, core, g_ctrl, ctrl)) - return 0; - - return mpeg_g_ctrl(ctrl, go); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (0 == call_all(&go->v4l2_dev, core, s_ctrl, ctrl)) - return 0; - - return mpeg_s_ctrl(ctrl, go); -} - -static int vidioc_g_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parm) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - struct v4l2_fract timeperframe = { - .numerator = 1001 * go->fps_scale, - .denominator = go->sensor_framerate, - }; - - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME; - parm->parm.capture.timeperframe = timeperframe; - - return 0; -} - -static int vidioc_s_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parm) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - unsigned int n, d; - - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (parm->parm.capture.capturemode != 0) - return -EINVAL; - - n = go->sensor_framerate * - parm->parm.capture.timeperframe.numerator; - d = 1001 * parm->parm.capture.timeperframe.denominator; - if (n != 0 && d != 0 && n > d) - go->fps_scale = (n + d/2) / d; - else - go->fps_scale = 1; - - return 0; -} - -/* VIDIOC_ENUMSTD on go7007 were used for enumberating the supported fps and - its resolution, when the device is not connected to TV. - This were an API abuse, probably used by the lack of specific IOCTL's to - enumberate it, by the time the driver were written. - - However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS - and VIDIOC_ENUM_FRAMESIZES) were added for this purpose. - - The two functions bellow implements the newer ioctls -*/ -static int vidioc_enum_framesizes(struct file *filp, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - /* Return -EINVAL, if it is a TV board */ - if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) || - (go->board_info->sensor_flags & GO7007_SENSOR_TV)) - return -EINVAL; - - if (fsize->index > 0) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = go->board_info->sensor_width; - fsize->discrete.height = go->board_info->sensor_height; - - return 0; -} - -static int vidioc_enum_frameintervals(struct file *filp, void *priv, - struct v4l2_frmivalenum *fival) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - /* Return -EINVAL, if it is a TV board */ - if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) || - (go->board_info->sensor_flags & GO7007_SENSOR_TV)) - return -EINVAL; - - if (fival->index > 0) - return -EINVAL; - - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete.numerator = 1001; - fival->discrete.denominator = go->board_info->sensor_framerate; - - return 0; -} - -static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - switch (go->standard) { - case GO7007_STD_NTSC: - *std = V4L2_STD_NTSC; - break; - case GO7007_STD_PAL: - *std = V4L2_STD_PAL; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (go->streaming) - return -EBUSY; - - if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && *std != 0) - return -EINVAL; - - if (*std == 0) - return -EINVAL; - - if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && - go->input == go->board_info->num_inputs - 1) { - if (!go->i2c_adapter_online) - return -EIO; - if (call_all(&go->v4l2_dev, core, s_std, *std) < 0) - return -EINVAL; - } - - if (*std & V4L2_STD_NTSC) { - go->standard = GO7007_STD_NTSC; - go->sensor_framerate = 30000; - } else if (*std & V4L2_STD_PAL) { - go->standard = GO7007_STD_PAL; - go->sensor_framerate = 25025; - } else if (*std & V4L2_STD_SECAM) { - go->standard = GO7007_STD_PAL; - go->sensor_framerate = 25025; - } else - return -EINVAL; - - call_all(&go->v4l2_dev, core, s_std, *std); - set_capture_size(go, NULL, 0); - - return 0; -} - -static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && - go->input == go->board_info->num_inputs - 1) { - if (!go->i2c_adapter_online) - return -EIO; - return call_all(&go->v4l2_dev, video, querystd, std); - } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) - *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; - else - *std = 0; - - return 0; -} - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (inp->index >= go->board_info->num_inputs) - return -EINVAL; - - strncpy(inp->name, go->board_info->inputs[inp->index].name, - sizeof(inp->name)); - - /* If this board has a tuner, it will be the last input */ - if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && - inp->index == go->board_info->num_inputs - 1) - inp->type = V4L2_INPUT_TYPE_TUNER; - else - inp->type = V4L2_INPUT_TYPE_CAMERA; - - inp->audioset = 0; - inp->tuner = 0; - if (go->board_info->sensor_flags & GO7007_SENSOR_TV) - inp->std = V4L2_STD_NTSC | V4L2_STD_PAL | - V4L2_STD_SECAM; - else - inp->std = 0; - - return 0; -} - - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *input) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - *input = go->input; - - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int input) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (input >= go->board_info->num_inputs) - return -EINVAL; - if (go->streaming) - return -EBUSY; - - go->input = input; - - return call_all(&go->v4l2_dev, video, s_routing, input, 0, 0); -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) - return -EINVAL; - if (t->index != 0) - return -EINVAL; - if (!go->i2c_adapter_online) - return -EIO; - - return call_all(&go->v4l2_dev, tuner, g_tuner, t); -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) - return -EINVAL; - if (t->index != 0) - return -EINVAL; - if (!go->i2c_adapter_online) - return -EIO; - - switch (go->board_id) { - case GO7007_BOARDID_PX_TV402U_NA: - case GO7007_BOARDID_PX_TV402U_JP: - /* No selectable options currently */ - if (t->audmode != V4L2_TUNER_MODE_STEREO) - return -EINVAL; - break; - } - - return call_all(&go->v4l2_dev, tuner, s_tuner, t); -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) - return -EINVAL; - if (!go->i2c_adapter_online) - return -EIO; - - f->type = V4L2_TUNER_ANALOG_TV; - - return call_all(&go->v4l2_dev, tuner, g_frequency, f); -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) - return -EINVAL; - if (!go->i2c_adapter_online) - return -EIO; - - return call_all(&go->v4l2_dev, tuner, s_frequency, f); -} - -static int vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cropcap) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - /* These specify the raw input of the sensor */ - switch (go->standard) { - case GO7007_STD_NTSC: - cropcap->bounds.top = 0; - cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = 480; - cropcap->defrect.top = 0; - cropcap->defrect.left = 0; - cropcap->defrect.width = 720; - cropcap->defrect.height = 480; - break; - case GO7007_STD_PAL: - cropcap->bounds.top = 0; - cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = 576; - cropcap->defrect.top = 0; - cropcap->defrect.left = 0; - cropcap->defrect.width = 720; - cropcap->defrect.height = 576; - break; - case GO7007_STD_OTHER: - cropcap->bounds.top = 0; - cropcap->bounds.left = 0; - cropcap->bounds.width = go->board_info->sensor_width; - cropcap->bounds.height = go->board_info->sensor_height; - cropcap->defrect.top = 0; - cropcap->defrect.left = 0; - cropcap->defrect.width = go->board_info->sensor_width; - cropcap->defrect.height = go->board_info->sensor_height; - break; - } - - return 0; -} - -static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - /* These specify the raw input of the sensor */ - switch (go->standard) { - case GO7007_STD_NTSC: - crop->c.top = 0; - crop->c.left = 0; - crop->c.width = 720; - crop->c.height = 480; - break; - case GO7007_STD_PAL: - crop->c.top = 0; - crop->c.left = 0; - crop->c.width = 720; - crop->c.height = 576; - break; - case GO7007_STD_OTHER: - crop->c.top = 0; - crop->c.left = 0; - crop->c.width = go->board_info->sensor_width; - crop->c.height = go->board_info->sensor_height; - break; - } - - return 0; -} - -/* FIXME: vidioc_s_crop is not really implemented!!! - */ -static int vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) -{ - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return 0; -} - -static int vidioc_g_jpegcomp(struct file *file, void *priv, - struct v4l2_jpegcompression *params) -{ - memset(params, 0, sizeof(*params)); - params->quality = 50; /* ?? */ - params->jpeg_markers = V4L2_JPEG_MARKER_DHT | - V4L2_JPEG_MARKER_DQT; - - return 0; -} - -static int vidioc_s_jpegcomp(struct file *file, void *priv, - struct v4l2_jpegcompression *params) -{ - if (params->quality != 50 || - params->jpeg_markers != (V4L2_JPEG_MARKER_DHT | - V4L2_JPEG_MARKER_DQT)) - return -EINVAL; - - return 0; -} - -/* FIXME: - Those ioctls are private, and not needed, since several standard - extended controls already provide streaming control. - So, those ioctls should be converted into vidioc_g_ext_ctrls() - and vidioc_s_ext_ctrls() - */ - -#if 0 - /* Temporary ioctls for controlling compression characteristics */ - case GO7007IOC_S_BITRATE: - { - int *bitrate = arg; - - if (go->streaming) - return -EINVAL; - /* Upper bound is kind of arbitrary here */ - if (*bitrate < 64000 || *bitrate > 10000000) - return -EINVAL; - go->bitrate = *bitrate; - return 0; - } - case GO7007IOC_G_BITRATE: - { - int *bitrate = arg; - - *bitrate = go->bitrate; - return 0; - } - case GO7007IOC_S_COMP_PARAMS: - { - struct go7007_comp_params *comp = arg; - - if (go->format == GO7007_FORMAT_MJPEG) - return -EINVAL; - if (comp->gop_size > 0) - go->gop_size = comp->gop_size; - else - go->gop_size = go->sensor_framerate / 1000; - if (go->gop_size != 15) - go->dvd_mode = 0; - /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */ - if (go->board_info->sensor_flags & GO7007_SENSOR_TV) { - switch (comp->aspect_ratio) { - case GO7007_ASPECT_RATIO_4_3_NTSC: - case GO7007_ASPECT_RATIO_4_3_PAL: - go->aspect_ratio = GO7007_RATIO_4_3; - break; - case GO7007_ASPECT_RATIO_16_9_NTSC: - case GO7007_ASPECT_RATIO_16_9_PAL: - go->aspect_ratio = GO7007_RATIO_16_9; - break; - default: - go->aspect_ratio = GO7007_RATIO_1_1; - break; - } - } - if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) { - go->dvd_mode = 0; - go->seq_header_enable = 0; - } else { - go->seq_header_enable = 1; - } - /* fall-through */ - } - case GO7007IOC_G_COMP_PARAMS: - { - struct go7007_comp_params *comp = arg; - - if (go->format == GO7007_FORMAT_MJPEG) - return -EINVAL; - memset(comp, 0, sizeof(*comp)); - comp->gop_size = go->gop_size; - comp->max_b_frames = go->ipb ? 2 : 0; - switch (go->aspect_ratio) { - case GO7007_RATIO_4_3: - if (go->standard == GO7007_STD_NTSC) - comp->aspect_ratio = - GO7007_ASPECT_RATIO_4_3_NTSC; - else - comp->aspect_ratio = - GO7007_ASPECT_RATIO_4_3_PAL; - break; - case GO7007_RATIO_16_9: - if (go->standard == GO7007_STD_NTSC) - comp->aspect_ratio = - GO7007_ASPECT_RATIO_16_9_NTSC; - else - comp->aspect_ratio = - GO7007_ASPECT_RATIO_16_9_PAL; - break; - default: - comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1; - break; - } - if (go->closed_gop) - comp->flags |= GO7007_COMP_CLOSED_GOP; - if (!go->seq_header_enable) - comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER; - return 0; - } - case GO7007IOC_S_MPEG_PARAMS: - { - struct go7007_mpeg_params *mpeg = arg; - - if (go->format != GO7007_FORMAT_MPEG1 && - go->format != GO7007_FORMAT_MPEG2 && - go->format != GO7007_FORMAT_MPEG4) - return -EINVAL; - - if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) { - go->format = GO7007_FORMAT_MPEG2; - go->bitrate = 9800000; - go->gop_size = 15; - go->pali = 0x48; - go->closed_gop = 1; - go->repeat_seqhead = 0; - go->seq_header_enable = 1; - go->gop_header_enable = 1; - go->dvd_mode = 1; - } else { - switch (mpeg->mpeg_video_standard) { - case GO7007_MPEG_VIDEO_MPEG1: - go->format = GO7007_FORMAT_MPEG1; - go->pali = 0; - break; - case GO7007_MPEG_VIDEO_MPEG2: - go->format = GO7007_FORMAT_MPEG2; - if (mpeg->pali >> 24 == 2) - go->pali = mpeg->pali & 0xff; - else - go->pali = 0x48; - break; - case GO7007_MPEG_VIDEO_MPEG4: - go->format = GO7007_FORMAT_MPEG4; - if (mpeg->pali >> 24 == 4) - go->pali = mpeg->pali & 0xff; - else - go->pali = 0xf5; - break; - default: - return -EINVAL; - } - go->gop_header_enable = - mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER - ? 0 : 1; - if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER) - go->repeat_seqhead = 1; - else - go->repeat_seqhead = 0; - go->dvd_mode = 0; - } - /* fall-through */ - } - case GO7007IOC_G_MPEG_PARAMS: - { - struct go7007_mpeg_params *mpeg = arg; - - memset(mpeg, 0, sizeof(*mpeg)); - switch (go->format) { - case GO7007_FORMAT_MPEG1: - mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1; - mpeg->pali = 0; - break; - case GO7007_FORMAT_MPEG2: - mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2; - mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali); - break; - case GO7007_FORMAT_MPEG4: - mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4; - mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali); - break; - default: - return -EINVAL; - } - if (!go->gop_header_enable) - mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER; - if (go->repeat_seqhead) - mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER; - if (go->dvd_mode) - mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE; - return 0; - } - case GO7007IOC_S_MD_PARAMS: - { - struct go7007_md_params *mdp = arg; - - if (mdp->region > 3) - return -EINVAL; - if (mdp->trigger > 0) { - go->modet[mdp->region].pixel_threshold = - mdp->pixel_threshold >> 1; - go->modet[mdp->region].motion_threshold = - mdp->motion_threshold >> 1; - go->modet[mdp->region].mb_threshold = - mdp->trigger >> 1; - go->modet[mdp->region].enable = 1; - } else - go->modet[mdp->region].enable = 0; - /* fall-through */ - } - case GO7007IOC_G_MD_PARAMS: - { - struct go7007_md_params *mdp = arg; - int region = mdp->region; - - if (mdp->region > 3) - return -EINVAL; - memset(mdp, 0, sizeof(struct go7007_md_params)); - mdp->region = region; - if (!go->modet[region].enable) - return 0; - mdp->pixel_threshold = - (go->modet[region].pixel_threshold << 1) + 1; - mdp->motion_threshold = - (go->modet[region].motion_threshold << 1) + 1; - mdp->trigger = - (go->modet[region].mb_threshold << 1) + 1; - return 0; - } - case GO7007IOC_S_MD_REGION: - { - struct go7007_md_region *region = arg; - - if (region->region < 1 || region->region > 3) - return -EINVAL; - return clip_to_modet_map(go, region->region, region->clips); - } -#endif - -static ssize_t go7007_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static void go7007_vm_open(struct vm_area_struct *vma) -{ - struct go7007_buffer *gobuf = vma->vm_private_data; - - ++gobuf->mapped; -} - -static void go7007_vm_close(struct vm_area_struct *vma) -{ - struct go7007_buffer *gobuf = vma->vm_private_data; - unsigned long flags; - - if (--gobuf->mapped == 0) { - spin_lock_irqsave(&gobuf->go->spinlock, flags); - deactivate_buffer(gobuf); - spin_unlock_irqrestore(&gobuf->go->spinlock, flags); - } -} - -/* Copied from videobuf-dma-sg.c */ -static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct page *page; - - page = alloc_page(GFP_USER | __GFP_DMA32); - if (!page) - return VM_FAULT_OOM; - clear_user_highpage(page, (unsigned long)vmf->virtual_address); - vmf->page = page; - return 0; -} - -static struct vm_operations_struct go7007_vm_ops = { - .open = go7007_vm_open, - .close = go7007_vm_close, - .fault = go7007_vm_fault, -}; - -static int go7007_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct go7007_file *gofh = file->private_data; - unsigned int index; - - if (gofh->go->status != STATUS_ONLINE) - return -EIO; - if (!(vma->vm_flags & VM_SHARED)) - return -EINVAL; /* only support VM_SHARED mapping */ - if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE) - return -EINVAL; /* must map exactly one full buffer */ - mutex_lock(&gofh->lock); - index = vma->vm_pgoff / GO7007_BUF_PAGES; - if (index >= gofh->buf_count) { - mutex_unlock(&gofh->lock); - return -EINVAL; /* trying to map beyond requested buffers */ - } - if (index * GO7007_BUF_PAGES != vma->vm_pgoff) { - mutex_unlock(&gofh->lock); - return -EINVAL; /* offset is not aligned on buffer boundary */ - } - if (gofh->bufs[index].mapped > 0) { - mutex_unlock(&gofh->lock); - return -EBUSY; - } - gofh->bufs[index].mapped = 1; - gofh->bufs[index].user_addr = vma->vm_start; - vma->vm_ops = &go7007_vm_ops; - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_flags &= ~VM_IO; - vma->vm_private_data = &gofh->bufs[index]; - mutex_unlock(&gofh->lock); - return 0; -} - -static unsigned int go7007_poll(struct file *file, poll_table *wait) -{ - struct go7007_file *gofh = file->private_data; - struct go7007_buffer *gobuf; - - if (list_empty(&gofh->go->stream)) - return POLLERR; - gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream); - poll_wait(file, &gofh->go->frame_waitq, wait); - if (gobuf->state == BUF_STATE_DONE) - return POLLIN | POLLRDNORM; - return 0; -} - -static void go7007_vfl_release(struct video_device *vfd) -{ - struct go7007 *go = video_get_drvdata(vfd); - - video_device_release(vfd); - if (--go->ref_count == 0) - kfree(go); -} - -static struct v4l2_file_operations go7007_fops = { - .owner = THIS_MODULE, - .open = go7007_open, - .release = go7007_release, - .ioctl = video_ioctl2, - .read = go7007_read, - .mmap = go7007_mmap, - .poll = go7007_poll, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_g_std = vidioc_g_std, - .vidioc_s_std = vidioc_s_std, - .vidioc_querystd = vidioc_querystd, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_s_parm = vidioc_s_parm, - .vidioc_enum_framesizes = vidioc_enum_framesizes, - .vidioc_enum_frameintervals = vidioc_enum_frameintervals, - .vidioc_cropcap = vidioc_cropcap, - .vidioc_g_crop = vidioc_g_crop, - .vidioc_s_crop = vidioc_s_crop, - .vidioc_g_jpegcomp = vidioc_g_jpegcomp, - .vidioc_s_jpegcomp = vidioc_s_jpegcomp, -}; - -static struct video_device go7007_template = { - .name = "go7007", - .fops = &go7007_fops, - .release = go7007_vfl_release, - .ioctl_ops = &video_ioctl_ops, - .tvnorms = V4L2_STD_ALL, - .current_norm = V4L2_STD_NTSC, -}; - -int go7007_v4l2_init(struct go7007 *go) -{ - int rv; - - go->video_dev = video_device_alloc(); - if (go->video_dev == NULL) - return -ENOMEM; - *go->video_dev = go7007_template; - go->video_dev->parent = go->dev; - rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1); - if (rv < 0) { - video_device_release(go->video_dev); - go->video_dev = NULL; - return rv; - } - rv = v4l2_device_register(go->dev, &go->v4l2_dev); - if (rv < 0) { - video_device_release(go->video_dev); - go->video_dev = NULL; - return rv; - } - video_set_drvdata(go->video_dev, go); - ++go->ref_count; - printk(KERN_INFO "%s: registered device %s [v4l2]\n", - go->video_dev->name, video_device_node_name(go->video_dev)); - - return 0; -} - -void go7007_v4l2_remove(struct go7007 *go) -{ - unsigned long flags; - - mutex_lock(&go->hw_lock); - if (go->streaming) { - go->streaming = 0; - go7007_stream_stop(go); - spin_lock_irqsave(&go->spinlock, flags); - abort_queued(go); - spin_unlock_irqrestore(&go->spinlock, flags); - } - mutex_unlock(&go->hw_lock); - if (go->video_dev) - video_unregister_device(go->video_dev); - v4l2_device_unregister(&go->v4l2_dev); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -config VIDEO_GO7007 - tristate "WIS GO7007 MPEG encoder support" - depends on VIDEO_DEV && PCI && I2C - depends on BKL # please fix - depends on SND - select VIDEOBUF_DMA_SG - depends on RC_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - select SND_PCM - select CRC32 - default N - ---help--- - This is a video4linux driver for the WIS GO7007 MPEG - encoder chip. - - To compile this driver as a module, choose M here: the - module will be called go7007 - -config VIDEO_GO7007_USB - tristate "WIS GO7007 USB support" - depends on VIDEO_GO7007 && USB - default N - ---help--- - This is a video4linux driver for the WIS GO7007 MPEG - encoder chip over USB. - - To compile this driver as a module, choose M here: the - module will be called go7007-usb - -config VIDEO_GO7007_USB_S2250_BOARD - tristate "Sensoray 2250/2251 support" - depends on VIDEO_GO7007_USB && DVB_USB - default N - ---help--- - This is a video4linux driver for the Sensoray 2250/2251 device. - - To compile this driver as a module, choose M here: the - module will be called s2250 - -config VIDEO_GO7007_OV7640 - tristate "OV7640 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the OV7640 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-ov7640 - -config VIDEO_GO7007_SAA7113 - tristate "SAA7113 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the SAA7113 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-saa7113 - -config VIDEO_GO7007_SAA7115 - tristate "SAA7115 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the SAA7115 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-saa7115 - -config VIDEO_GO7007_TW9903 - tristate "TW9903 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the TW9903 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-tw9903 - -config VIDEO_GO7007_UDA1342 - tristate "UDA1342 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the UDA1342 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-uda1342 - -config VIDEO_GO7007_SONY_TUNER - tristate "Sony tuner subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the Sony Tuner sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-sony-tuner - -config VIDEO_GO7007_TW2804 - tristate "TW2804 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the TW2804 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-tw2804 - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -#obj-m += go7007.o go7007-usb.o snd-go7007.o wis-saa7115.o wis-tw9903.o \ - wis-uda1342.o wis-sony-tuner.o wis-saa7113.o wis-ov7640.o \ - wis-tw2804.o - - -obj-$(CONFIG_VIDEO_GO7007) += go7007.o -obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o -obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o s2250-loader.o -obj-$(CONFIG_VIDEO_GO7007_SAA7113) += wis-saa7113.o -obj-$(CONFIG_VIDEO_GO7007_OV7640) += wis-ov7640.o -obj-$(CONFIG_VIDEO_GO7007_SAA7115) += wis-saa7115.o -obj-$(CONFIG_VIDEO_GO7007_TW9903) += wis-tw9903.o -obj-$(CONFIG_VIDEO_GO7007_UDA1342) += wis-uda1342.o -obj-$(CONFIG_VIDEO_GO7007_SONY_TUNER) += wis-sony-tuner.o -obj-$(CONFIG_VIDEO_GO7007_TW2804) += wis-tw2804.o - -go7007-y := go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \ - snd-go7007.o - -s2250-y := s2250-board.o - -# Uncomment when the saa7134 patches get into upstream -#ifneq ($(CONFIG_VIDEO_SAA7134),) -#obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o -#EXTRA_CFLAGS += -Idrivers/media/video/saa7134 -DSAA7134_MPEG_GO7007=3 -#endif - -# S2250 needs cypress ezusb loader from dvb-usb -ifneq ($(CONFIG_VIDEO_GO7007_USB_S2250_BOARD),) -ccflags-y := -Idrivers/media/dvb/dvb-usb -endif - -ccflags-y += -Idrivers/media/dvb/frontends -ccflags-y += -Idrivers/media/dvb/dvb-core diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-board.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-board.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-board.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-board.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,698 +0,0 @@ -/* - * Copyright (C) 2008 Sensoray Company Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "go7007-priv.h" - -MODULE_DESCRIPTION("Sensoray 2250/2251 i2c v4l2 subdev driver"); -MODULE_LICENSE("GPL v2"); - -#define TLV320_ADDRESS 0x34 -#define VPX322_ADDR_ANALOGCONTROL1 0x02 -#define VPX322_ADDR_BRIGHTNESS0 0x0127 -#define VPX322_ADDR_BRIGHTNESS1 0x0131 -#define VPX322_ADDR_CONTRAST0 0x0128 -#define VPX322_ADDR_CONTRAST1 0x0132 -#define VPX322_ADDR_HUE 0x00dc -#define VPX322_ADDR_SAT 0x0030 - -struct go7007_usb_board { - unsigned int flags; - struct go7007_board_info main_info; -}; - -struct go7007_usb { - struct go7007_usb_board *board; - struct mutex i2c_lock; - struct usb_device *usbdev; - struct urb *video_urbs[8]; - struct urb *audio_urbs[8]; - struct urb *intr_urb; -}; - -static unsigned char aud_regs[] = { - 0x1e, 0x00, - 0x00, 0x17, - 0x02, 0x17, - 0x04, 0xf9, - 0x06, 0xf9, - 0x08, 0x02, - 0x0a, 0x00, - 0x0c, 0x00, - 0x0a, 0x00, - 0x0c, 0x00, - 0x0e, 0x02, - 0x10, 0x00, - 0x12, 0x01, - 0x00, 0x00, -}; - - -static unsigned char vid_regs[] = { - 0xF2, 0x0f, - 0xAA, 0x00, - 0xF8, 0xff, - 0x00, 0x00, -}; - -static u16 vid_regs_fp[] = { - 0x028, 0x067, - 0x120, 0x016, - 0x121, 0xcF2, - 0x122, 0x0F2, - 0x123, 0x00c, - 0x124, 0x2d0, - 0x125, 0x2e0, - 0x126, 0x004, - 0x128, 0x1E0, - 0x12A, 0x016, - 0x12B, 0x0F2, - 0x12C, 0x0F2, - 0x12D, 0x00c, - 0x12E, 0x2d0, - 0x12F, 0x2e0, - 0x130, 0x004, - 0x132, 0x1E0, - 0x140, 0x060, - 0x153, 0x00C, - 0x154, 0x200, - 0x150, 0x801, - 0x000, 0x000 -}; - -/* PAL specific values */ -static u16 vid_regs_fp_pal[] = -{ - 0x120, 0x017, - 0x121, 0xd22, - 0x122, 0x122, - 0x12A, 0x017, - 0x12B, 0x122, - 0x12C, 0x122, - 0x140, 0x060, - 0x000, 0x000, -}; - -struct s2250 { - struct v4l2_subdev sd; - v4l2_std_id std; - int input; - int brightness; - int contrast; - int saturation; - int hue; - int reg12b_val; - int audio_input; - struct i2c_client *audio; -}; - -static inline struct s2250 *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct s2250, sd); -} - -/* from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/ -static int go7007_usb_vendor_request(struct go7007 *go, u16 request, - u16 value, u16 index, void *transfer_buffer, int length, int in) -{ - struct go7007_usb *usb = go->hpi_context; - int timeout = 5000; - - if (in) { - return usb_control_msg(usb->usbdev, - usb_rcvctrlpipe(usb->usbdev, 0), request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - value, index, transfer_buffer, length, timeout); - } else { - return usb_control_msg(usb->usbdev, - usb_sndctrlpipe(usb->usbdev, 0), request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, transfer_buffer, length, timeout); - } -} -/* end from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/ - -static int write_reg(struct i2c_client *client, u8 reg, u8 value) -{ - struct go7007 *go = i2c_get_adapdata(client->adapter); - struct go7007_usb *usb; - int rc; - int dev_addr = client->addr << 1; /* firmware wants 8-bit address */ - u8 *buf; - - if (go == NULL) - return -ENODEV; - - if (go->status == STATUS_SHUTDOWN) - return -EBUSY; - - buf = kzalloc(16, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - usb = go->hpi_context; - if (mutex_lock_interruptible(&usb->i2c_lock) != 0) { - printk(KERN_INFO "i2c lock failed\n"); - kfree(buf); - return -EINTR; - } - rc = go7007_usb_vendor_request(go, 0x55, dev_addr, - (reg<<8 | value), - buf, - 16, 1); - - mutex_unlock(&usb->i2c_lock); - kfree(buf); - return rc; -} - -static int write_reg_fp(struct i2c_client *client, u16 addr, u16 val) -{ - struct go7007 *go = i2c_get_adapdata(client->adapter); - struct go7007_usb *usb; - u8 *buf; - struct s2250 *dec = i2c_get_clientdata(client); - - if (go == NULL) - return -ENODEV; - - if (go->status == STATUS_SHUTDOWN) - return -EBUSY; - - buf = kzalloc(16, GFP_KERNEL); - - if (buf == NULL) - return -ENOMEM; - - - - memset(buf, 0xcd, 6); - - usb = go->hpi_context; - if (mutex_lock_interruptible(&usb->i2c_lock) != 0) { - printk(KERN_INFO "i2c lock failed\n"); - kfree(buf); - return -EINTR; - } - if (go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1) < 0) { - kfree(buf); - return -EFAULT; - } - - mutex_unlock(&usb->i2c_lock); - if (buf[0] == 0) { - unsigned int subaddr, val_read; - - subaddr = (buf[4] << 8) + buf[5]; - val_read = (buf[2] << 8) + buf[3]; - kfree(buf); - if (val_read != val) { - printk(KERN_INFO "invalid fp write %x %x\n", - val_read, val); - return -EFAULT; - } - if (subaddr != addr) { - printk(KERN_INFO "invalid fp write addr %x %x\n", - subaddr, addr); - return -EFAULT; - } - } else { - kfree(buf); - return -EFAULT; - } - - /* save last 12b value */ - if (addr == 0x12b) - dec->reg12b_val = val; - - return 0; -} - -static int read_reg_fp(struct i2c_client *client, u16 addr, u16 *val) -{ - struct go7007 *go = i2c_get_adapdata(client->adapter); - struct go7007_usb *usb; - u8 *buf; - - if (go == NULL) - return -ENODEV; - - if (go->status == STATUS_SHUTDOWN) - return -EBUSY; - - buf = kzalloc(16, GFP_KERNEL); - - if (buf == NULL) - return -ENOMEM; - - - - memset(buf, 0xcd, 6); - usb = go->hpi_context; - if (mutex_lock_interruptible(&usb->i2c_lock) != 0) { - printk(KERN_INFO "i2c lock failed\n"); - kfree(buf); - return -EINTR; - } - if (go7007_usb_vendor_request(go, 0x58, addr, 0, buf, 16, 1) < 0) { - kfree(buf); - return -EFAULT; - } - mutex_unlock(&usb->i2c_lock); - - *val = (buf[0] << 8) | buf[1]; - kfree(buf); - - return 0; -} - - -static int write_regs(struct i2c_client *client, u8 *regs) -{ - int i; - - for (i = 0; !((regs[i] == 0x00) && (regs[i+1] == 0x00)); i += 2) { - if (write_reg(client, regs[i], regs[i+1]) < 0) { - printk(KERN_INFO "s2250: failed\n"); - return -1; - } - } - return 0; -} - -static int write_regs_fp(struct i2c_client *client, u16 *regs) -{ - int i; - - for (i = 0; !((regs[i] == 0x00) && (regs[i+1] == 0x00)); i += 2) { - if (write_reg_fp(client, regs[i], regs[i+1]) < 0) { - printk(KERN_INFO "s2250: failed fp\n"); - return -1; - } - } - return 0; -} - - -/* ------------------------------------------------------------------------- */ - -static int s2250_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output, - u32 config) -{ - struct s2250 *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int vidsys; - - vidsys = (state->std == V4L2_STD_NTSC) ? 0x01 : 0x00; - if (input == 0) { - /* composite */ - write_reg_fp(client, 0x20, 0x020 | vidsys); - write_reg_fp(client, 0x21, 0x662); - write_reg_fp(client, 0x140, 0x060); - } else if (input == 1) { - /* S-Video */ - write_reg_fp(client, 0x20, 0x040 | vidsys); - write_reg_fp(client, 0x21, 0x666); - write_reg_fp(client, 0x140, 0x060); - } else { - return -EINVAL; - } - state->input = input; - return 0; -} - -static int s2250_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - struct s2250 *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 vidsource; - - vidsource = (state->input == 1) ? 0x040 : 0x020; - switch (norm) { - case V4L2_STD_NTSC: - write_regs_fp(client, vid_regs_fp); - write_reg_fp(client, 0x20, vidsource | 1); - break; - case V4L2_STD_PAL: - write_regs_fp(client, vid_regs_fp); - write_regs_fp(client, vid_regs_fp_pal); - write_reg_fp(client, 0x20, vidsource); - break; - default: - return -EINVAL; - } - state->std = norm; - return 0; -} - -static int s2250_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *query) -{ - switch (query->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(query, 0, 100, 1, 50); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(query, 0, 100, 1, 50); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(query, 0, 100, 1, 50); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(query, -50, 50, 1, 0); - default: - return -EINVAL; - } - return 0; -} - -static int s2250_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct s2250 *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int value1; - u16 oldvalue; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 100) - state->brightness = 100; - else if (ctrl->value < 0) - state->brightness = 0; - else - state->brightness = ctrl->value; - value1 = (state->brightness - 50) * 255 / 100; - read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue); - write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, - value1 | (oldvalue & ~0xff)); - read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue); - write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, - value1 | (oldvalue & ~0xff)); - write_reg_fp(client, 0x140, 0x60); - break; - case V4L2_CID_CONTRAST: - if (ctrl->value > 100) - state->contrast = 100; - else if (ctrl->value < 0) - state->contrast = 0; - else - state->contrast = ctrl->value; - value1 = state->contrast * 0x40 / 100; - if (value1 > 0x3f) - value1 = 0x3f; /* max */ - read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue); - write_reg_fp(client, VPX322_ADDR_CONTRAST0, - value1 | (oldvalue & ~0x3f)); - read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue); - write_reg_fp(client, VPX322_ADDR_CONTRAST1, - value1 | (oldvalue & ~0x3f)); - write_reg_fp(client, 0x140, 0x60); - break; - case V4L2_CID_SATURATION: - if (ctrl->value > 100) - state->saturation = 100; - else if (ctrl->value < 0) - state->saturation = 0; - else - state->saturation = ctrl->value; - value1 = state->saturation * 4140 / 100; - if (value1 > 4094) - value1 = 4094; - write_reg_fp(client, VPX322_ADDR_SAT, value1); - break; - case V4L2_CID_HUE: - if (ctrl->value > 50) - state->hue = 50; - else if (ctrl->value < -50) - state->hue = -50; - else - state->hue = ctrl->value; - /* clamp the hue range */ - value1 = state->hue * 280 / 50; - write_reg_fp(client, VPX322_ADDR_HUE, value1); - break; - default: - return -EINVAL; - } - return 0; -} - -static int s2250_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct s2250 *state = to_state(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = state->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = state->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = state->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = state->hue; - break; - default: - return -EINVAL; - } - return 0; -} - -static int s2250_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) -{ - struct s2250 *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (fmt->height < 640) { - write_reg_fp(client, 0x12b, state->reg12b_val | 0x400); - write_reg_fp(client, 0x140, 0x060); - } else { - write_reg_fp(client, 0x12b, state->reg12b_val & ~0x400); - write_reg_fp(client, 0x140, 0x060); - } - return 0; -} - -static int s2250_s_audio_routing(struct v4l2_subdev *sd, u32 input, u32 output, - u32 config) -{ - struct s2250 *state = to_state(sd); - - switch (input) { - case 0: - write_reg(state->audio, 0x08, 0x02); /* Line In */ - break; - case 1: - write_reg(state->audio, 0x08, 0x04); /* Mic */ - break; - case 2: - write_reg(state->audio, 0x08, 0x05); /* Mic Boost */ - break; - default: - return -EINVAL; - } - state->audio_input = input; - return 0; -} - - -static int s2250_log_status(struct v4l2_subdev *sd) -{ - struct s2250 *state = to_state(sd); - - v4l2_info(sd, "Standard: %s\n", state->std == V4L2_STD_NTSC ? "NTSC" : - state->std == V4L2_STD_PAL ? "PAL" : - state->std == V4L2_STD_SECAM ? "SECAM" : - "unknown"); - v4l2_info(sd, "Input: %s\n", state->input == 0 ? "Composite" : - state->input == 1 ? "S-video" : - "error"); - v4l2_info(sd, "Brightness: %d\n", state->brightness); - v4l2_info(sd, "Contrast: %d\n", state->contrast); - v4l2_info(sd, "Saturation: %d\n", state->saturation); - v4l2_info(sd, "Hue: %d\n", state->hue); return 0; - v4l2_info(sd, "Audio input: %s\n", state->audio_input == 0 ? "Line In" : - state->audio_input == 1 ? "Mic" : - state->audio_input == 2 ? "Mic Boost" : - "error"); - return 0; -} - -/* --------------------------------------------------------------------------*/ - -static const struct v4l2_subdev_core_ops s2250_core_ops = { - .log_status = s2250_log_status, - .g_ctrl = s2250_g_ctrl, - .s_ctrl = s2250_s_ctrl, - .queryctrl = s2250_queryctrl, - .s_std = s2250_s_std, -}; - -static const struct v4l2_subdev_audio_ops s2250_audio_ops = { - .s_routing = s2250_s_audio_routing, -}; - -static const struct v4l2_subdev_video_ops s2250_video_ops = { - .s_routing = s2250_s_video_routing, - .s_mbus_fmt = s2250_s_mbus_fmt, -}; - -static const struct v4l2_subdev_ops s2250_ops = { - .core = &s2250_core_ops, - .audio = &s2250_audio_ops, - .video = &s2250_video_ops, -}; - -/* --------------------------------------------------------------------------*/ - -static int s2250_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_client *audio; - struct i2c_adapter *adapter = client->adapter; - struct s2250 *state; - struct v4l2_subdev *sd; - u8 *data; - struct go7007 *go = i2c_get_adapdata(adapter); - struct go7007_usb *usb = go->hpi_context; - - audio = i2c_new_dummy(adapter, TLV320_ADDRESS >> 1); - if (audio == NULL) - return -ENOMEM; - - state = kmalloc(sizeof(struct s2250), GFP_KERNEL); - if (state == NULL) { - i2c_unregister_device(audio); - return -ENOMEM; - } - - sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &s2250_ops); - - v4l2_info(sd, "initializing %s at address 0x%x on %s\n", - "Sensoray 2250/2251", client->addr, client->adapter->name); - - state->std = V4L2_STD_NTSC; - state->brightness = 50; - state->contrast = 50; - state->saturation = 50; - state->hue = 0; - state->audio = audio; - - /* initialize the audio */ - if (write_regs(audio, aud_regs) < 0) { - printk(KERN_ERR - "s2250: error initializing audio\n"); - i2c_unregister_device(audio); - kfree(state); - return 0; - } - - if (write_regs(client, vid_regs) < 0) { - printk(KERN_ERR - "s2250: error initializing decoder\n"); - i2c_unregister_device(audio); - kfree(state); - return 0; - } - if (write_regs_fp(client, vid_regs_fp) < 0) { - printk(KERN_ERR - "s2250: error initializing decoder\n"); - i2c_unregister_device(audio); - kfree(state); - return 0; - } - /* set default channel */ - /* composite */ - write_reg_fp(client, 0x20, 0x020 | 1); - write_reg_fp(client, 0x21, 0x662); - write_reg_fp(client, 0x140, 0x060); - - /* set default audio input */ - state->audio_input = 0; - write_reg(client, 0x08, 0x02); /* Line In */ - - if (mutex_lock_interruptible(&usb->i2c_lock) == 0) { - data = kzalloc(16, GFP_KERNEL); - if (data != NULL) { - int rc; - rc = go7007_usb_vendor_request(go, 0x41, 0, 0, - data, 16, 1); - if (rc > 0) { - u8 mask; - data[0] = 0; - mask = 1<<5; - data[0] &= ~mask; - data[1] |= mask; - go7007_usb_vendor_request(go, 0x40, 0, - (data[1]<<8) - + data[1], - data, 16, 0); - } - kfree(data); - } - mutex_unlock(&usb->i2c_lock); - } - - v4l2_info(sd, "initialized successfully\n"); - return 0; -} - -static int s2250_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id s2250_id[] = { - { "s2250", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, s2250_id); - -static struct i2c_driver s2250_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "s2250", - }, - .probe = s2250_probe, - .remove = s2250_remove, - .id_table = s2250_id, -}; - -static __init int init_s2250(void) -{ - return i2c_add_driver(&s2250_driver); -} - -static __exit void exit_s2250(void) -{ - i2c_del_driver(&s2250_driver); -} - -module_init(init_s2250); -module_exit(exit_s2250); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-loader.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-loader.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-loader.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-loader.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2008 Sensoray Company Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include - -#define S2250_LOADER_FIRMWARE "s2250_loader.fw" -#define S2250_FIRMWARE "s2250.fw" - -typedef struct device_extension_s { - struct kref kref; - int minor; - struct usb_device *usbdev; -} device_extension_t, *pdevice_extension_t; - -#define USB_s2250loader_MAJOR 240 -#define USB_s2250loader_MINOR_BASE 0 -#define MAX_DEVICES 256 - -static pdevice_extension_t s2250_dev_table[MAX_DEVICES]; -static DEFINE_MUTEX(s2250_dev_table_mutex); - -#define to_s2250loader_dev_common(d) container_of(d, device_extension_t, kref) -static void s2250loader_delete(struct kref *kref) -{ - pdevice_extension_t s = to_s2250loader_dev_common(kref); - s2250_dev_table[s->minor] = NULL; - kfree(s); -} - -static int s2250loader_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *usbdev; - int minor, ret; - pdevice_extension_t s = NULL; - const struct firmware *fw; - - usbdev = usb_get_dev(interface_to_usbdev(interface)); - if (!usbdev) { - printk(KERN_ERR "Enter s2250loader_probe failed\n"); - return -1; - } - printk(KERN_INFO "Enter s2250loader_probe 2.6 kernel\n"); - printk(KERN_INFO "vendor id 0x%x, device id 0x%x devnum:%d\n", - usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, - usbdev->devnum); - - if (usbdev->descriptor.bNumConfigurations != 1) { - printk(KERN_ERR "can't handle multiple config\n"); - return -1; - } - mutex_lock(&s2250_dev_table_mutex); - - for (minor = 0; minor < MAX_DEVICES; minor++) { - if (s2250_dev_table[minor] == NULL) - break; - } - - if (minor < 0 || minor >= MAX_DEVICES) { - printk(KERN_ERR "Invalid minor: %d\n", minor); - goto failed; - } - - /* Allocate dev data structure */ - s = kmalloc(sizeof(device_extension_t), GFP_KERNEL); - if (s == NULL) { - printk(KERN_ERR "Out of memory\n"); - goto failed; - } - s2250_dev_table[minor] = s; - - printk(KERN_INFO "s2250loader_probe: Device %d on Bus %d Minor %d\n", - usbdev->devnum, usbdev->bus->busnum, minor); - - memset(s, 0, sizeof(device_extension_t)); - s->usbdev = usbdev; - printk(KERN_INFO "loading 2250 loader\n"); - - kref_init(&(s->kref)); - - mutex_unlock(&s2250_dev_table_mutex); - - if (request_firmware(&fw, S2250_LOADER_FIRMWARE, &usbdev->dev)) { - printk(KERN_ERR - "s2250: unable to load firmware from file \"%s\"\n", - S2250_LOADER_FIRMWARE); - goto failed2; - } - ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); - release_firmware(fw); - if (0 != ret) { - printk(KERN_ERR "loader download failed\n"); - goto failed2; - } - - if (request_firmware(&fw, S2250_FIRMWARE, &usbdev->dev)) { - printk(KERN_ERR - "s2250: unable to load firmware from file \"%s\"\n", - S2250_FIRMWARE); - goto failed2; - } - ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); - release_firmware(fw); - if (0 != ret) { - printk(KERN_ERR "firmware_s2250 download failed\n"); - goto failed2; - } - - usb_set_intfdata(interface, s); - return 0; - -failed: - mutex_unlock(&s2250_dev_table_mutex); -failed2: - if (s) - kref_put(&(s->kref), s2250loader_delete); - - printk(KERN_ERR "probe failed\n"); - return -1; -} - -static void s2250loader_disconnect(struct usb_interface *interface) -{ - pdevice_extension_t s; - printk(KERN_INFO "s2250: disconnect\n"); - lock_kernel(); - s = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - kref_put(&(s->kref), s2250loader_delete); - unlock_kernel(); -} - -static const struct usb_device_id s2250loader_ids[] = { - {USB_DEVICE(0x1943, 0xa250)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, s2250loader_ids); - -static struct usb_driver s2250loader_driver = { - .name = "s2250-loader", - .probe = s2250loader_probe, - .disconnect = s2250loader_disconnect, - .id_table = s2250loader_ids, -}; - -static int __init s2250loader_init(void) -{ - int r; - unsigned i = 0; - - for (i = 0; i < MAX_DEVICES; i++) - s2250_dev_table[i] = NULL; - - r = usb_register(&s2250loader_driver); - if (r) { - printk(KERN_ERR "usb_register failed. Error number %d\n", r); - return -1; - } - - printk(KERN_INFO "s2250loader_init: driver registered\n"); - return 0; -} -module_init(s2250loader_init); - -static void __exit s2250loader_cleanup(void) -{ - printk(KERN_INFO "s2250loader_cleanup\n"); - usb_deregister(&s2250loader_driver); -} -module_exit(s2250loader_cleanup); - -MODULE_AUTHOR(""); -MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251"); -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-loader.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-loader.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-loader.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/s2250-loader.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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. - */ - -#ifndef _S2250_LOADER_H_ -#define _S2250_LOADER_H_ - -extern int s2250loader_init(void); -extern void s2250loader_cleanup(void); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/saa7134-go7007.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/saa7134-go7007.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/saa7134-go7007.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/saa7134-go7007.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,532 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" -#include "go7007-priv.h" - -#define GO7007_HPI_DEBUG - -enum hpi_address { - HPI_ADDR_VIDEO_BUFFER = 0xe4, - HPI_ADDR_INIT_BUFFER = 0xea, - HPI_ADDR_INTR_RET_VALUE = 0xee, - HPI_ADDR_INTR_RET_DATA = 0xec, - HPI_ADDR_INTR_STATUS = 0xf4, - HPI_ADDR_INTR_WR_PARAM = 0xf6, - HPI_ADDR_INTR_WR_INDEX = 0xf8, -}; - -enum gpio_command { - GPIO_COMMAND_RESET = 0x00, /* 000b */ - GPIO_COMMAND_REQ1 = 0x04, /* 001b */ - GPIO_COMMAND_WRITE = 0x20, /* 010b */ - GPIO_COMMAND_REQ2 = 0x24, /* 011b */ - GPIO_COMMAND_READ = 0x80, /* 100b */ - GPIO_COMMAND_VIDEO = 0x84, /* 101b */ - GPIO_COMMAND_IDLE = 0xA0, /* 110b */ - GPIO_COMMAND_ADDR = 0xA4, /* 111b */ -}; - -struct saa7134_go7007 { - struct saa7134_dev *dev; - u8 *top; - u8 *bottom; - dma_addr_t top_dma; - dma_addr_t bottom_dma; -}; - -static struct go7007_board_info board_voyager = { - .firmware = "go7007tv.bin", - .flags = 0, - .sensor_flags = GO7007_SENSOR_656 | - GO7007_SENSOR_VALID_ENABLE | - GO7007_SENSOR_TV | - GO7007_SENSOR_VBI, - .audio_flags = GO7007_AUDIO_I2S_MODE_1 | - GO7007_AUDIO_WORD_16, - .audio_rate = 48000, - .audio_bclk_div = 8, - .audio_main_div = 2, - .hpi_buffer_cap = 7, - .num_inputs = 1, - .inputs = { - { - .name = "SAA7134", - }, - }, -}; -MODULE_FIRMWARE("go7007tv.bin"); - -/********************* Driver for GPIO HPI interface *********************/ - -static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data) -{ - saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); - - /* Write HPI address */ - saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); - - /* Write low byte */ - saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); - - /* Write high byte */ - saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); - - return 0; -} - -static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data) -{ - saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); - - /* Write HPI address */ - saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); - - saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); - - /* Read low byte */ - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); - saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - *data = saa_readb(SAA7134_GPIO_GPSTATUS0); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); - - /* Read high byte */ - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); - saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8; - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); - - return 0; -} - -static int saa7134_go7007_interface_reset(struct go7007 *go) -{ - struct saa7134_go7007 *saa = go->hpi_context; - struct saa7134_dev *dev = saa->dev; - u32 status; - u16 intr_val, intr_data; - int count = 20; - - saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */ - saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4); - saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); - - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET); - msleep(1); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); - msleep(10); - - saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - - status = saa_readb(SAA7134_GPIO_GPSTATUS2); - /*printk(KERN_DEBUG "status is %s\n", status & 0x40 ? "OK" : "not OK"); */ - - /* enter command mode...(?) */ - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); - - do { - saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - status = saa_readb(SAA7134_GPIO_GPSTATUS2); - /*printk(KERN_INFO "gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */ - } while (--count > 0); - - /* Wait for an interrupt to indicate successful hardware reset */ - if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || - (intr_val & ~0x1) != 0x55aa) { - printk(KERN_ERR - "saa7134-go7007: unable to reset the GO7007\n"); - return -1; - } - return 0; -} - -static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data) -{ - struct saa7134_go7007 *saa = go->hpi_context; - struct saa7134_dev *dev = saa->dev; - int i; - u16 status_reg; - -#ifdef GO7007_HPI_DEBUG - printk(KERN_DEBUG - "saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data); -#endif - - for (i = 0; i < 100; ++i) { - gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); - if (!(status_reg & 0x0010)) - break; - msleep(10); - } - if (i == 100) { - printk(KERN_ERR - "saa7134-go7007: device is hung, status reg = 0x%04x\n", - status_reg); - return -1; - } - gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data); - gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr); - - return 0; -} - -static int saa7134_go7007_read_interrupt(struct go7007 *go) -{ - struct saa7134_go7007 *saa = go->hpi_context; - struct saa7134_dev *dev = saa->dev; - - /* XXX we need to wait if there is no interrupt available */ - go->interrupt_available = 1; - gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value); - gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data); -#ifdef GO7007_HPI_DEBUG - printk(KERN_DEBUG "saa7134-go7007: ReadInterrupt: %04x %04x\n", - go->interrupt_value, go->interrupt_data); -#endif - return 0; -} - -static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev, - unsigned long status) -{ - struct go7007 *go = video_get_drvdata(dev->empress_dev); - struct saa7134_go7007 *saa = go->hpi_context; - - if (!go->streaming) - return; - if (0 != (status & 0x000f0000)) - printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n", - (status >> 16) & 0x0f); - if (status & 0x100000) { - dma_sync_single_for_cpu(&dev->pci->dev, - saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE); - go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE); - saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); - } else { - dma_sync_single_for_cpu(&dev->pci->dev, - saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE); - go7007_parse_video_stream(go, saa->top, PAGE_SIZE); - saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); - } -} - -static int saa7134_go7007_stream_start(struct go7007 *go) -{ - struct saa7134_go7007 *saa = go->hpi_context; - struct saa7134_dev *dev = saa->dev; - - saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top), - 0, PAGE_SIZE, DMA_FROM_DEVICE); - if (!saa->top_dma) - return -ENOMEM; - saa->bottom_dma = dma_map_page(&dev->pci->dev, - virt_to_page(saa->bottom), - 0, PAGE_SIZE, DMA_FROM_DEVICE); - if (!saa->bottom_dma) { - dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, - DMA_FROM_DEVICE); - return -ENOMEM; - } - - saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000); - saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200); - - /* Set HPI interface for video */ - saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); - saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); - saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); - - /* Enable TS interface */ - saa_writeb(SAA7134_TS_PARALLEL, 0xe6); - - /* Reset TS interface */ - saa_setb(SAA7134_TS_SERIAL1, 0x01); - saa_clearb(SAA7134_TS_SERIAL1, 0x01); - - /* Set up transfer block size */ - saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1); - saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1); - saa_writeb(SAA7134_TS_DMA1, 0); - saa_writeb(SAA7134_TS_DMA2, 0); - - /* Enable video streaming mode */ - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); - - saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); - saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); - saa_writel(SAA7134_RS_PITCH(5), 128); - saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX); - - /* Enable TS FIFO */ - saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); - - /* Enable DMA IRQ */ - saa_setl(SAA7134_IRQ1, - SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); - - return 0; -} - -static int saa7134_go7007_stream_stop(struct go7007 *go) -{ - struct saa7134_go7007 *saa = go->hpi_context; - struct saa7134_dev *dev; - - if (!saa) - return -EINVAL; - dev = saa->dev; - if (!dev) - return -EINVAL; - - /* Shut down TS FIFO */ - saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); - - /* Disable DMA IRQ */ - saa_clearl(SAA7134_IRQ1, - SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); - - /* Disable TS interface */ - saa_clearb(SAA7134_TS_PARALLEL, 0x80); - - dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, - DMA_FROM_DEVICE); - dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE, - DMA_FROM_DEVICE); - - return 0; -} - -static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len) -{ - struct saa7134_go7007 *saa = go->hpi_context; - struct saa7134_dev *dev = saa->dev; - u16 status_reg; - int i; - -#ifdef GO7007_HPI_DEBUG - printk(KERN_DEBUG "saa7134-go7007: DownloadBuffer " - "sending %d bytes\n", len); -#endif - - while (len > 0) { - i = len > 64 ? 64 : len; - saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); - saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); - while (i-- > 0) { - saa_writeb(SAA7134_GPIO_GPSTATUS0, *data); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); - saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); - ++data; - --len; - } - for (i = 0; i < 100; ++i) { - gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); - if (!(status_reg & 0x0002)) - break; - } - if (i == 100) { - printk(KERN_ERR "saa7134-go7007: device is hung, " - "status reg = 0x%04x\n", status_reg); - return -1; - } - } - return 0; -} - -static int saa7134_go7007_send_command(struct go7007 *go, unsigned int cmd, - void *arg) -{ - struct saa7134_go7007 *saa = go->hpi_context; - struct saa7134_dev *dev = saa->dev; - - switch (cmd) { - case VIDIOC_S_STD: - { - v4l2_std_id *std = arg; - return saa7134_s_std_internal(dev, NULL, std); - } - case VIDIOC_G_STD: - { - v4l2_std_id *std = arg; - *std = dev->tvnorm->id; - return 0; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER) - return saa7134_queryctrl(NULL, NULL, ctrl); - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER) - return saa7134_g_ctrl_internal(dev, NULL, ctrl); - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER) - return saa7134_s_ctrl_internal(dev, NULL, ctrl); - } - } - return -EINVAL; - -} - -static struct go7007_hpi_ops saa7134_go7007_hpi_ops = { - .interface_reset = saa7134_go7007_interface_reset, - .write_interrupt = saa7134_go7007_write_interrupt, - .read_interrupt = saa7134_go7007_read_interrupt, - .stream_start = saa7134_go7007_stream_start, - .stream_stop = saa7134_go7007_stream_stop, - .send_firmware = saa7134_go7007_send_firmware, - .send_command = saa7134_go7007_send_command, -}; - -/********************* Add/remove functions *********************/ - -static int saa7134_go7007_init(struct saa7134_dev *dev) -{ - struct go7007 *go; - struct saa7134_go7007 *saa; - - printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n"); - - saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL); - if (saa == NULL) - return -ENOMEM; - - /* Allocate a couple pages for receiving the compressed stream */ - saa->top = (u8 *)get_zeroed_page(GFP_KERNEL); - if (!saa->top) - goto allocfail; - saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL); - if (!saa->bottom) - goto allocfail; - - go = go7007_alloc(&board_voyager, &dev->pci->dev); - if (go == NULL) - goto allocfail; - go->board_id = GO7007_BOARDID_PCI_VOYAGER; - strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); - go->hpi_ops = &saa7134_go7007_hpi_ops; - go->hpi_context = saa; - saa->dev = dev; - - /* Boot the GO7007 */ - if (go7007_boot_encoder(go, go->board_info->flags & - GO7007_BOARD_USE_ONBOARD_I2C) < 0) - goto initfail; - - /* Do any final GO7007 initialization, then register the - * V4L2 and ALSA interfaces */ - if (go7007_register_encoder(go) < 0) - goto initfail; - dev->empress_dev = go->video_dev; - video_set_drvdata(dev->empress_dev, go); - - go->status = STATUS_ONLINE; - return 0; - -initfail: - go->status = STATUS_SHUTDOWN; - return 0; - -allocfail: - if (saa->top) - free_page((unsigned long)saa->top); - if (saa->bottom) - free_page((unsigned long)saa->bottom); - kfree(saa); - return -ENOMEM; -} - -static int saa7134_go7007_fini(struct saa7134_dev *dev) -{ - struct go7007 *go; - struct saa7134_go7007 *saa; - - if (NULL == dev->empress_dev) - return 0; - - go = video_get_drvdata(dev->empress_dev); - saa = go->hpi_context; - go->status = STATUS_SHUTDOWN; - free_page((unsigned long)saa->top); - free_page((unsigned long)saa->bottom); - kfree(saa); - go7007_remove(go); - dev->empress_dev = NULL; - - return 0; -} - -static struct saa7134_mpeg_ops saa7134_go7007_ops = { - .type = SAA7134_MPEG_GO7007, - .init = saa7134_go7007_init, - .fini = saa7134_go7007_fini, - .irq_ts_done = saa7134_go7007_irq_ts_done, -}; - -static int __init saa7134_go7007_mod_init(void) -{ - return saa7134_ts_register(&saa7134_go7007_ops); -} - -static void __exit saa7134_go7007_mod_cleanup(void) -{ - saa7134_ts_unregister(&saa7134_go7007_ops); -} - -module_init(saa7134_go7007_mod_init); -module_exit(saa7134_go7007_mod_cleanup); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/snd-go7007.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/snd-go7007.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/snd-go7007.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/snd-go7007.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "go7007-priv.h" - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; - -module_param_array(index, int, NULL, 0444); -module_param_array(id, charp, NULL, 0444); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for the go7007 audio driver"); -MODULE_PARM_DESC(id, "ID string for the go7007 audio driver"); -MODULE_PARM_DESC(enable, "Enable for the go7007 audio driver"); - -struct go7007_snd { - struct snd_card *card; - struct snd_pcm *pcm; - struct snd_pcm_substream *substream; - spinlock_t lock; - int w_idx; - int hw_ptr; - int avail; - int capturing; -}; - -static struct snd_pcm_hardware go7007_snd_capture_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = (128*1024), - .period_bytes_min = 4096, - .period_bytes_max = (128*1024), - .periods_min = 1, - .periods_max = 32, -}; - -static void parse_audio_stream_data(struct go7007 *go, u8 *buf, int length) -{ - struct go7007_snd *gosnd = go->snd_context; - struct snd_pcm_runtime *runtime = gosnd->substream->runtime; - int frames = bytes_to_frames(runtime, length); - - spin_lock(&gosnd->lock); - gosnd->hw_ptr += frames; - if (gosnd->hw_ptr >= runtime->buffer_size) - gosnd->hw_ptr -= runtime->buffer_size; - gosnd->avail += frames; - spin_unlock(&gosnd->lock); - if (gosnd->w_idx + length > runtime->dma_bytes) { - int cpy = runtime->dma_bytes - gosnd->w_idx; - - memcpy(runtime->dma_area + gosnd->w_idx, buf, cpy); - length -= cpy; - buf += cpy; - gosnd->w_idx = 0; - } - memcpy(runtime->dma_area + gosnd->w_idx, buf, length); - gosnd->w_idx += length; - spin_lock(&gosnd->lock); - if (gosnd->avail < runtime->period_size) { - spin_unlock(&gosnd->lock); - return; - } - gosnd->avail -= runtime->period_size; - spin_unlock(&gosnd->lock); - if (gosnd->capturing) - snd_pcm_period_elapsed(gosnd->substream); -} - -static int go7007_snd_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct go7007 *go = snd_pcm_substream_chip(substream); - unsigned int bytes; - - bytes = params_buffer_bytes(hw_params); - if (substream->runtime->dma_bytes > 0) - vfree(substream->runtime->dma_area); - substream->runtime->dma_bytes = 0; - substream->runtime->dma_area = vmalloc(bytes); - if (substream->runtime->dma_area == NULL) - return -ENOMEM; - substream->runtime->dma_bytes = bytes; - go->audio_deliver = parse_audio_stream_data; - return 0; -} - -static int go7007_snd_hw_free(struct snd_pcm_substream *substream) -{ - struct go7007 *go = snd_pcm_substream_chip(substream); - - go->audio_deliver = NULL; - if (substream->runtime->dma_bytes > 0) - vfree(substream->runtime->dma_area); - substream->runtime->dma_bytes = 0; - return 0; -} - -static int go7007_snd_capture_open(struct snd_pcm_substream *substream) -{ - struct go7007 *go = snd_pcm_substream_chip(substream); - struct go7007_snd *gosnd = go->snd_context; - unsigned long flags; - int r; - - spin_lock_irqsave(&gosnd->lock, flags); - if (gosnd->substream == NULL) { - gosnd->substream = substream; - substream->runtime->hw = go7007_snd_capture_hw; - r = 0; - } else - r = -EBUSY; - spin_unlock_irqrestore(&gosnd->lock, flags); - return r; -} - -static int go7007_snd_capture_close(struct snd_pcm_substream *substream) -{ - struct go7007 *go = snd_pcm_substream_chip(substream); - struct go7007_snd *gosnd = go->snd_context; - - gosnd->substream = NULL; - return 0; -} - -static int go7007_snd_pcm_prepare(struct snd_pcm_substream *substream) -{ - return 0; -} - -static int go7007_snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct go7007 *go = snd_pcm_substream_chip(substream); - struct go7007_snd *gosnd = go->snd_context; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - /* Just set a flag to indicate we should signal ALSA when - * sound comes in */ - gosnd->capturing = 1; - return 0; - case SNDRV_PCM_TRIGGER_STOP: - gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0; - gosnd->capturing = 0; - return 0; - default: - return -EINVAL; - } -} - -static snd_pcm_uframes_t go7007_snd_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct go7007 *go = snd_pcm_substream_chip(substream); - struct go7007_snd *gosnd = go->snd_context; - - return gosnd->hw_ptr; -} - -static struct page *go7007_snd_pcm_page(struct snd_pcm_substream *substream, - unsigned long offset) -{ - return vmalloc_to_page(substream->runtime->dma_area + offset); -} - -static struct snd_pcm_ops go7007_snd_capture_ops = { - .open = go7007_snd_capture_open, - .close = go7007_snd_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = go7007_snd_hw_params, - .hw_free = go7007_snd_hw_free, - .prepare = go7007_snd_pcm_prepare, - .trigger = go7007_snd_pcm_trigger, - .pointer = go7007_snd_pcm_pointer, - .page = go7007_snd_pcm_page, -}; - -static int go7007_snd_free(struct snd_device *device) -{ - struct go7007 *go = device->device_data; - - kfree(go->snd_context); - go->snd_context = NULL; - if (--go->ref_count == 0) - kfree(go); - return 0; -} - -static struct snd_device_ops go7007_snd_device_ops = { - .dev_free = go7007_snd_free, -}; - -int go7007_snd_init(struct go7007 *go) -{ - static int dev; - struct go7007_snd *gosnd; - int ret = 0; - - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - gosnd = kmalloc(sizeof(struct go7007_snd), GFP_KERNEL); - if (gosnd == NULL) - return -ENOMEM; - spin_lock_init(&gosnd->lock); - gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0; - gosnd->capturing = 0; - ret = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, - &gosnd->card); - if (ret < 0) { - kfree(gosnd); - return ret; - } - ret = snd_device_new(gosnd->card, SNDRV_DEV_LOWLEVEL, go, - &go7007_snd_device_ops); - if (ret < 0) { - kfree(gosnd); - return ret; - } - snd_card_set_dev(gosnd->card, go->dev); - ret = snd_pcm_new(gosnd->card, "go7007", 0, 0, 1, &gosnd->pcm); - if (ret < 0) { - snd_card_free(gosnd->card); - kfree(gosnd); - return ret; - } - strncpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver)); - strncpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver)); - strncpy(gosnd->card->longname, gosnd->card->shortname, - sizeof(gosnd->card->longname)); - - gosnd->pcm->private_data = go; - snd_pcm_set_ops(gosnd->pcm, SNDRV_PCM_STREAM_CAPTURE, - &go7007_snd_capture_ops); - - ret = snd_card_register(gosnd->card); - if (ret < 0) { - snd_card_free(gosnd->card); - kfree(gosnd); - return ret; - } - - gosnd->substream = NULL; - go->snd_context = gosnd; - ++dev; - ++go->ref_count; - - return 0; -} -EXPORT_SYMBOL(go7007_snd_init); - -int go7007_snd_remove(struct go7007 *go) -{ - struct go7007_snd *gosnd = go->snd_context; - - snd_card_disconnect(gosnd->card); - snd_card_free_when_closed(gosnd->card); - return 0; -} -EXPORT_SYMBOL(go7007_snd_remove); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-i2c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-i2c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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. - */ - -/* Temporary I2C IDs -- these need to be replaced with real registered IDs */ -#define I2C_DRIVERID_WIS_SAA7115 0xf0f0 -#define I2C_DRIVERID_WIS_UDA1342 0xf0f1 -#define I2C_DRIVERID_WIS_SONY_TUNER 0xf0f2 -#define I2C_DRIVERID_WIS_TW9903 0xf0f3 -#define I2C_DRIVERID_WIS_SAA7113 0xf0f4 -#define I2C_DRIVERID_WIS_OV7640 0xf0f5 -#define I2C_DRIVERID_WIS_TW2804 0xf0f6 -#define I2C_DRIVERID_S2250 0xf0f7 - -/* Flag to indicate that the client needs to be accessed with SCCB semantics */ -/* We re-use the I2C_M_TEN value so the flag passes through the masks in the - * core I2C code. Major kludge, but the I2C layer ain't exactly flexible. */ -#define I2C_CLIENT_SCCB 0x10 - -/* Definitions for new video decoder commands */ - -struct video_decoder_resolution { - unsigned int width; - unsigned int height; -}; - -#define DECODER_SET_RESOLUTION _IOW('d', 200, struct video_decoder_resolution) -#define DECODER_SET_CHANNEL _IOW('d', 201, int) - -/* Sony tuner types */ - -#define TUNER_SONY_BTF_PG472Z 200 -#define TUNER_SONY_BTF_PK467Z 201 -#define TUNER_SONY_BTF_PB463Z 202 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-ov7640.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-ov7640.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-ov7640.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-ov7640.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include - -#include "wis-i2c.h" - -struct wis_ov7640 { - int brightness; - int contrast; - int saturation; - int hue; -}; - -static u8 initial_registers[] = -{ - 0x12, 0x80, - 0x12, 0x54, - 0x14, 0x24, - 0x15, 0x01, - 0x28, 0x20, - 0x75, 0x82, - 0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */ -}; - -static int write_regs(struct i2c_client *client, u8 *regs) -{ - int i; - - for (i = 0; regs[i] != 0xFF; i += 2) - if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) - return -1; - return 0; -} - -static int wis_ov7640_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - client->flags = I2C_CLIENT_SCCB; - - printk(KERN_DEBUG - "wis-ov7640: initializing OV7640 at address %d on %s\n", - client->addr, adapter->name); - - if (write_regs(client, initial_registers) < 0) { - printk(KERN_ERR "wis-ov7640: error initializing OV7640\n"); - return -ENODEV; - } - - return 0; -} - -static int wis_ov7640_remove(struct i2c_client *client) -{ - return 0; -} - -static const struct i2c_device_id wis_ov7640_id[] = { - { "wis_ov7640", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_ov7640_id); - -static struct i2c_driver wis_ov7640_driver = { - .driver = { - .name = "WIS OV7640 I2C driver", - }, - .probe = wis_ov7640_probe, - .remove = wis_ov7640_remove, - .id_table = wis_ov7640_id, -}; - -static int __init wis_ov7640_init(void) -{ - return i2c_add_driver(&wis_ov7640_driver); -} - -static void __exit wis_ov7640_cleanup(void) -{ - i2c_del_driver(&wis_ov7640_driver); -} - -module_init(wis_ov7640_init); -module_exit(wis_ov7640_cleanup); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-saa7113.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-saa7113.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-saa7113.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-saa7113.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,336 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include - -#include "wis-i2c.h" - -struct wis_saa7113 { - int norm; - int brightness; - int contrast; - int saturation; - int hue; -}; - -static u8 initial_registers[] = -{ - 0x01, 0x08, - 0x02, 0xc0, - 0x03, 0x33, - 0x04, 0x00, - 0x05, 0x00, - 0x06, 0xe9, - 0x07, 0x0d, - 0x08, 0xd8, - 0x09, 0x40, - 0x0a, 0x80, - 0x0b, 0x47, - 0x0c, 0x40, - 0x0d, 0x00, - 0x0e, 0x01, - 0x0f, 0x2a, - 0x10, 0x40, - 0x11, 0x0c, - 0x12, 0xfe, - 0x13, 0x00, - 0x14, 0x00, - 0x15, 0x04, - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1b, 0x00, - 0x1c, 0x00, - 0x1d, 0x00, - 0x1e, 0x00, - 0x1f, 0xc8, - 0x40, 0x00, - 0x41, 0xff, - 0x42, 0xff, - 0x43, 0xff, - 0x44, 0xff, - 0x45, 0xff, - 0x46, 0xff, - 0x47, 0xff, - 0x48, 0xff, - 0x49, 0xff, - 0x4a, 0xff, - 0x4b, 0xff, - 0x4c, 0xff, - 0x4d, 0xff, - 0x4e, 0xff, - 0x4f, 0xff, - 0x50, 0xff, - 0x51, 0xff, - 0x52, 0xff, - 0x53, 0xff, - 0x54, 0xff, - 0x55, 0xff, - 0x56, 0xff, - 0x57, 0xff, - 0x58, 0x00, - 0x59, 0x54, - 0x5a, 0x07, - 0x5b, 0x83, - 0x5c, 0x00, - 0x5d, 0x00, - 0x5e, 0x00, - 0x5f, 0x00, - 0x60, 0x00, - 0x61, 0x00, - 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ -}; - -static int write_reg(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int write_regs(struct i2c_client *client, u8 *regs) -{ - int i; - - for (i = 0; regs[i] != 0x00; i += 2) - if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) - return -1; - return 0; -} - -static int wis_saa7113_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct wis_saa7113 *dec = i2c_get_clientdata(client); - - switch (cmd) { - case VIDIOC_S_INPUT: - { - int *input = arg; - - i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input); - i2c_smbus_write_byte_data(client, 0x09, - *input < 6 ? 0x40 : 0x80); - break; - } - case VIDIOC_S_STD: - { - v4l2_std_id *input = arg; - dec->norm = *input; - if (dec->norm & V4L2_STD_NTSC) { - write_reg(client, 0x0e, 0x01); - write_reg(client, 0x10, 0x40); - } else if (dec->norm & V4L2_STD_PAL) { - write_reg(client, 0x0e, 0x01); - write_reg(client, 0x10, 0x48); - } else if (dec->norm * V4L2_STD_SECAM) { - write_reg(client, 0x0e, 0x50); - write_reg(client, 0x10, 0x48); - } - break; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_CONTRAST: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 71; - ctrl->flags = 0; - break; - case V4L2_CID_SATURATION: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 64; - ctrl->flags = 0; - break; - case V4L2_CID_HUE: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); - ctrl->minimum = -128; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 0; - ctrl->flags = 0; - break; - } - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 255) - dec->brightness = 255; - else if (ctrl->value < 0) - dec->brightness = 0; - else - dec->brightness = ctrl->value; - write_reg(client, 0x0a, dec->brightness); - break; - case V4L2_CID_CONTRAST: - if (ctrl->value > 127) - dec->contrast = 127; - else if (ctrl->value < 0) - dec->contrast = 0; - else - dec->contrast = ctrl->value; - write_reg(client, 0x0b, dec->contrast); - break; - case V4L2_CID_SATURATION: - if (ctrl->value > 127) - dec->saturation = 127; - else if (ctrl->value < 0) - dec->saturation = 0; - else - dec->saturation = ctrl->value; - write_reg(client, 0x0c, dec->saturation); - break; - case V4L2_CID_HUE: - if (ctrl->value > 127) - dec->hue = 127; - else if (ctrl->value < -128) - dec->hue = -128; - else - dec->hue = ctrl->value; - write_reg(client, 0x0d, dec->hue); - break; - } - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dec->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dec->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = dec->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = dec->hue; - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_saa7113_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_saa7113 *dec; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - dec = kmalloc(sizeof(struct wis_saa7113), GFP_KERNEL); - if (dec == NULL) - return -ENOMEM; - - dec->norm = V4L2_STD_NTSC; - dec->brightness = 128; - dec->contrast = 71; - dec->saturation = 64; - dec->hue = 0; - i2c_set_clientdata(client, dec); - - printk(KERN_DEBUG - "wis-saa7113: initializing SAA7113 at address %d on %s\n", - client->addr, adapter->name); - - if (write_regs(client, initial_registers) < 0) { - printk(KERN_ERR - "wis-saa7113: error initializing SAA7113\n"); - kfree(dec); - return -ENODEV; - } - - return 0; -} - -static int wis_saa7113_remove(struct i2c_client *client) -{ - struct wis_saa7113 *dec = i2c_get_clientdata(client); - - kfree(dec); - return 0; -} - -static const struct i2c_device_id wis_saa7113_id[] = { - { "wis_saa7113", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_saa7113_id); - -static struct i2c_driver wis_saa7113_driver = { - .driver = { - .name = "WIS SAA7113 I2C driver", - }, - .probe = wis_saa7113_probe, - .remove = wis_saa7113_remove, - .command = wis_saa7113_command, - .id_table = wis_saa7113_id, -}; - -static int __init wis_saa7113_init(void) -{ - return i2c_add_driver(&wis_saa7113_driver); -} - -static void __exit wis_saa7113_cleanup(void) -{ - i2c_del_driver(&wis_saa7113_driver); -} - -module_init(wis_saa7113_init); -module_exit(wis_saa7113_cleanup); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-saa7115.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-saa7115.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-saa7115.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-saa7115.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,469 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include - -#include "wis-i2c.h" - -struct wis_saa7115 { - int norm; - int brightness; - int contrast; - int saturation; - int hue; -}; - -static u8 initial_registers[] = -{ - 0x01, 0x08, - 0x02, 0xc0, - 0x03, 0x20, - 0x04, 0x80, - 0x05, 0x80, - 0x06, 0xeb, - 0x07, 0xe0, - 0x08, 0xf0, /* always toggle FID */ - 0x09, 0x40, - 0x0a, 0x80, - 0x0b, 0x40, - 0x0c, 0x40, - 0x0d, 0x00, - 0x0e, 0x03, - 0x0f, 0x2a, - 0x10, 0x0e, - 0x11, 0x00, - 0x12, 0x8d, - 0x13, 0x00, - 0x14, 0x00, - 0x15, 0x11, - 0x16, 0x01, - 0x17, 0xda, - 0x18, 0x40, - 0x19, 0x80, - 0x1a, 0x00, - 0x1b, 0x42, - 0x1c, 0xa9, - 0x30, 0x66, - 0x31, 0x90, - 0x32, 0x01, - 0x34, 0x00, - 0x35, 0x00, - 0x36, 0x20, - 0x38, 0x03, - 0x39, 0x20, - 0x3a, 0x88, - 0x40, 0x00, - 0x41, 0xff, - 0x42, 0xff, - 0x43, 0xff, - 0x44, 0xff, - 0x45, 0xff, - 0x46, 0xff, - 0x47, 0xff, - 0x48, 0xff, - 0x49, 0xff, - 0x4a, 0xff, - 0x4b, 0xff, - 0x4c, 0xff, - 0x4d, 0xff, - 0x4e, 0xff, - 0x4f, 0xff, - 0x50, 0xff, - 0x51, 0xff, - 0x52, 0xff, - 0x53, 0xff, - 0x54, 0xf4 /*0xff*/, - 0x55, 0xff, - 0x56, 0xff, - 0x57, 0xff, - 0x58, 0x40, - 0x59, 0x47, - 0x5a, 0x06 /*0x03*/, - 0x5b, 0x83, - 0x5d, 0x06, - 0x5e, 0x00, - 0x80, 0x30, /* window defined scaler operation, task A and B enabled */ - 0x81, 0x03, /* use scaler datapath generated V */ - 0x83, 0x00, - 0x84, 0x00, - 0x85, 0x00, - 0x86, 0x45, - 0x87, 0x31, - 0x88, 0xc0, - 0x90, 0x02, /* task A process top field */ - 0x91, 0x08, - 0x92, 0x09, - 0x93, 0x80, - 0x94, 0x06, - 0x95, 0x00, - 0x96, 0xc0, - 0x97, 0x02, - 0x98, 0x12, - 0x99, 0x00, - 0x9a, 0xf2, - 0x9b, 0x00, - 0x9c, 0xd0, - 0x9d, 0x02, - 0x9e, 0xf2, - 0x9f, 0x00, - 0xa0, 0x01, - 0xa1, 0x01, - 0xa2, 0x01, - 0xa4, 0x80, - 0xa5, 0x40, - 0xa6, 0x40, - 0xa8, 0x00, - 0xa9, 0x04, - 0xaa, 0x00, - 0xac, 0x00, - 0xad, 0x02, - 0xae, 0x00, - 0xb0, 0x00, - 0xb1, 0x04, - 0xb2, 0x00, - 0xb3, 0x04, - 0xb4, 0x00, - 0xb8, 0x00, - 0xbc, 0x00, - 0xc0, 0x03, /* task B process bottom field */ - 0xc1, 0x08, - 0xc2, 0x09, - 0xc3, 0x80, - 0xc4, 0x06, - 0xc5, 0x00, - 0xc6, 0xc0, - 0xc7, 0x02, - 0xc8, 0x12, - 0xc9, 0x00, - 0xca, 0xf2, - 0xcb, 0x00, - 0xcc, 0xd0, - 0xcd, 0x02, - 0xce, 0xf2, - 0xcf, 0x00, - 0xd0, 0x01, - 0xd1, 0x01, - 0xd2, 0x01, - 0xd4, 0x80, - 0xd5, 0x40, - 0xd6, 0x40, - 0xd8, 0x00, - 0xd9, 0x04, - 0xda, 0x00, - 0xdc, 0x00, - 0xdd, 0x02, - 0xde, 0x00, - 0xe0, 0x00, - 0xe1, 0x04, - 0xe2, 0x00, - 0xe3, 0x04, - 0xe4, 0x00, - 0xe8, 0x00, - 0x88, 0xf0, /* End of original static list */ - 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ -}; - -static int write_reg(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int write_regs(struct i2c_client *client, u8 *regs) -{ - int i; - - for (i = 0; regs[i] != 0x00; i += 2) - if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) - return -1; - return 0; -} - -static int wis_saa7115_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct wis_saa7115 *dec = i2c_get_clientdata(client); - - switch (cmd) { - case VIDIOC_S_INPUT: - { - int *input = arg; - - i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input); - i2c_smbus_write_byte_data(client, 0x09, - *input < 6 ? 0x40 : 0xC0); - break; - } - case DECODER_SET_RESOLUTION: - { - struct video_decoder_resolution *res = arg; - /* Course-grained scaler */ - int h_integer_scaler = res->width < 704 ? 704 / res->width : 1; - /* Fine-grained scaler to take care of remainder */ - int h_scaling_increment = (704 / h_integer_scaler) * - 1024 / res->width; - /* Fine-grained scaler only */ - int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ? - 240 : 288) * 1024 / res->height; - u8 regs[] = { - 0x88, 0xc0, - 0x9c, res->width & 0xff, - 0x9d, res->width >> 8, - 0x9e, res->height & 0xff, - 0x9f, res->height >> 8, - 0xa0, h_integer_scaler, - 0xa1, 1, - 0xa2, 1, - 0xa8, h_scaling_increment & 0xff, - 0xa9, h_scaling_increment >> 8, - 0xac, (h_scaling_increment / 2) & 0xff, - 0xad, (h_scaling_increment / 2) >> 8, - 0xb0, v_scaling_increment & 0xff, - 0xb1, v_scaling_increment >> 8, - 0xb2, v_scaling_increment & 0xff, - 0xb3, v_scaling_increment >> 8, - 0xcc, res->width & 0xff, - 0xcd, res->width >> 8, - 0xce, res->height & 0xff, - 0xcf, res->height >> 8, - 0xd0, h_integer_scaler, - 0xd1, 1, - 0xd2, 1, - 0xd8, h_scaling_increment & 0xff, - 0xd9, h_scaling_increment >> 8, - 0xdc, (h_scaling_increment / 2) & 0xff, - 0xdd, (h_scaling_increment / 2) >> 8, - 0xe0, v_scaling_increment & 0xff, - 0xe1, v_scaling_increment >> 8, - 0xe2, v_scaling_increment & 0xff, - 0xe3, v_scaling_increment >> 8, - 0x88, 0xf0, - 0, 0, - }; - write_regs(client, regs); - break; - } - case VIDIOC_S_STD: - { - v4l2_std_id *input = arg; - u8 regs[] = { - 0x88, 0xc0, - 0x98, *input & V4L2_STD_NTSC ? 0x12 : 0x16, - 0x9a, *input & V4L2_STD_NTSC ? 0xf2 : 0x20, - 0x9b, *input & V4L2_STD_NTSC ? 0x00 : 0x01, - 0xc8, *input & V4L2_STD_NTSC ? 0x12 : 0x16, - 0xca, *input & V4L2_STD_NTSC ? 0xf2 : 0x20, - 0xcb, *input & V4L2_STD_NTSC ? 0x00 : 0x01, - 0x88, 0xf0, - 0x30, *input & V4L2_STD_NTSC ? 0x66 : 0x00, - 0x31, *input & V4L2_STD_NTSC ? 0x90 : 0xe0, - 0, 0, - }; - write_regs(client, regs); - dec->norm = *input; - break; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_CONTRAST: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 64; - ctrl->flags = 0; - break; - case V4L2_CID_SATURATION: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 64; - ctrl->flags = 0; - break; - case V4L2_CID_HUE: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); - ctrl->minimum = -128; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 0; - ctrl->flags = 0; - break; - } - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 255) - dec->brightness = 255; - else if (ctrl->value < 0) - dec->brightness = 0; - else - dec->brightness = ctrl->value; - write_reg(client, 0x0a, dec->brightness); - break; - case V4L2_CID_CONTRAST: - if (ctrl->value > 127) - dec->contrast = 127; - else if (ctrl->value < 0) - dec->contrast = 0; - else - dec->contrast = ctrl->value; - write_reg(client, 0x0b, dec->contrast); - break; - case V4L2_CID_SATURATION: - if (ctrl->value > 127) - dec->saturation = 127; - else if (ctrl->value < 0) - dec->saturation = 0; - else - dec->saturation = ctrl->value; - write_reg(client, 0x0c, dec->saturation); - break; - case V4L2_CID_HUE: - if (ctrl->value > 127) - dec->hue = 127; - else if (ctrl->value < -128) - dec->hue = -128; - else - dec->hue = ctrl->value; - write_reg(client, 0x0d, dec->hue); - break; - } - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dec->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dec->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = dec->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = dec->hue; - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_saa7115_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_saa7115 *dec; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL); - if (dec == NULL) - return -ENOMEM; - - dec->norm = V4L2_STD_NTSC; - dec->brightness = 128; - dec->contrast = 64; - dec->saturation = 64; - dec->hue = 0; - i2c_set_clientdata(client, dec); - - printk(KERN_DEBUG - "wis-saa7115: initializing SAA7115 at address %d on %s\n", - client->addr, adapter->name); - - if (write_regs(client, initial_registers) < 0) { - printk(KERN_ERR - "wis-saa7115: error initializing SAA7115\n"); - kfree(dec); - return -ENODEV; - } - - return 0; -} - -static int wis_saa7115_remove(struct i2c_client *client) -{ - struct wis_saa7115 *dec = i2c_get_clientdata(client); - - kfree(dec); - return 0; -} - -static const struct i2c_device_id wis_saa7115_id[] = { - { "wis_saa7115", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_saa7115_id); - -static struct i2c_driver wis_saa7115_driver = { - .driver = { - .name = "WIS SAA7115 I2C driver", - }, - .probe = wis_saa7115_probe, - .remove = wis_saa7115_remove, - .command = wis_saa7115_command, - .id_table = wis_saa7115_id, -}; - -static int __init wis_saa7115_init(void) -{ - return i2c_add_driver(&wis_saa7115_driver); -} - -static void __exit wis_saa7115_cleanup(void) -{ - i2c_del_driver(&wis_saa7115_driver); -} - -module_init(wis_saa7115_init); -module_exit(wis_saa7115_cleanup); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-sony-tuner.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-sony-tuner.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-sony-tuner.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-sony-tuner.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,720 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "wis-i2c.h" - -/* #define MPX_DEBUG */ - -/* AS(IF/MPX) pin: LOW HIGH/OPEN - * IF/MPX address: 0x42/0x40 0x43/0x44 - */ -#define IF_I2C_ADDR 0x43 -#define MPX_I2C_ADDR 0x44 - -static v4l2_std_id force_band; -static char force_band_str[] = "-"; -module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644); -static int force_mpx_mode = -1; -module_param(force_mpx_mode, int, 0644); - -/* Store tuner info in the same format as tuner.c, so maybe we can put the - * Sony tuner support in there. */ -struct sony_tunertype { - char *name; - unsigned char Vendor; /* unused here */ - unsigned char Type; /* unused here */ - - unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ - unsigned short thresh2; /* band switch VHF_HI <=> UHF */ - unsigned char VHF_L; - unsigned char VHF_H; - unsigned char UHF; - unsigned char config; - unsigned short IFPCoff; -}; - -/* This array is indexed by (tuner_type - 200) */ -static struct sony_tunertype sony_tuners[] = { - { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0, - 16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623}, - { "Sony NTSC_JP (BTF-PK467Z)", 0, 0, - 16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940}, - { "Sony NTSC (BTF-PB463Z)", 0, 0, - 16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732}, -}; - -struct wis_sony_tuner { - int type; - v4l2_std_id std; - unsigned int freq; - int mpxmode; - u32 audmode; -}; - -/* Basically the same as default_set_tv_freq() in tuner.c */ -static int set_freq(struct i2c_client *client, int freq) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - char *band_name; - int n; - int band_select; - struct sony_tunertype *tun; - u8 buffer[4]; - - tun = &sony_tuners[t->type - 200]; - if (freq < tun->thresh1) { - band_name = "VHF_L"; - band_select = tun->VHF_L; - } else if (freq < tun->thresh2) { - band_name = "VHF_H"; - band_select = tun->VHF_H; - } else { - band_name = "UHF"; - band_select = tun->UHF; - } - printk(KERN_DEBUG "wis-sony-tuner: tuning to frequency %d.%04d (%s)\n", - freq / 16, (freq % 16) * 625, band_name); - n = freq + tun->IFPCoff; - - buffer[0] = n >> 8; - buffer[1] = n & 0xff; - buffer[2] = tun->config; - buffer[3] = band_select; - i2c_master_send(client, buffer, 4); - - return 0; -} - -static int mpx_write(struct i2c_client *client, int dev, int addr, int val) -{ - u8 buffer[5]; - struct i2c_msg msg; - - buffer[0] = dev; - buffer[1] = addr >> 8; - buffer[2] = addr & 0xff; - buffer[3] = val >> 8; - buffer[4] = val & 0xff; - msg.addr = MPX_I2C_ADDR; - msg.flags = 0; - msg.len = 5; - msg.buf = buffer; - i2c_transfer(client->adapter, &msg, 1); - return 0; -} - -/* - * MPX register values for the BTF-PG472Z: - * - * FM_ NICAM_ SCART_ - * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME - * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000 - * --------------------------------------------------------------- - * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500 - * - * B/G - * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500 - * A2 1003 0020 0100 2601 5000 XXXX 0003 7500 - * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500 - * - * I - * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500 - * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500 - * - * D/K - * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500 - * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500 - * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500 - * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500 - * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500 - * - * L/L' - * Mono 0003 0200 0100 7C03 5000 2200 0009 7500 - * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500 - * - * M - * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500 - * - * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX. - * - * Bilingual selection in A2/NICAM: - * - * High byte of SOURCE Left chan Right chan - * 0x01 MAIN SUB - * 0x03 MAIN MAIN - * 0x04 SUB SUB - * - * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or - * 0x00 (all other bands). Force mono in A2 with FMONO_A2: - * - * FMONO_A2 - * 10/0022 - * -------- - * Forced mono ON 07F0 - * Forced mono OFF 0190 - */ - -static struct { - enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode; - u16 modus; - u16 source; - u16 acb; - u16 fm_prescale; - u16 nicam_prescale; - u16 scart_prescale; - u16 system; - u16 volume; -} mpx_audio_modes[] = { - /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, - 0x5000, 0x0000, 0x0001, 0x7500 }, - /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, - 0x5000, 0x0000, 0x0003, 0x7500 }, - /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, - 0x5000, 0x0000, 0x0003, 0x7500 }, - /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, - 0x5000, 0x0000, 0x0008, 0x7500 }, - /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, - 0x7900, 0x0000, 0x000A, 0x7500 }, - /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, - 0x7900, 0x0000, 0x000A, 0x7500 }, - /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, - 0x5000, 0x0000, 0x0004, 0x7500 }, - /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, - 0x5000, 0x0000, 0x0004, 0x7500 }, - /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, - 0x5000, 0x0000, 0x0005, 0x7500 }, - /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, - 0x5000, 0x0000, 0x0007, 0x7500 }, - /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, - 0x5000, 0x0000, 0x000B, 0x7500 }, - /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03, - 0x5000, 0x2200, 0x0009, 0x7500 }, - /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03, - 0x5000, 0x0000, 0x0009, 0x7500 }, -}; - -#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes) - -static int mpx_setup(struct i2c_client *client) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - u16 source = 0; - u8 buffer[3]; - struct i2c_msg msg; - - /* reset MPX */ - buffer[0] = 0x00; - buffer[1] = 0x80; - buffer[2] = 0x00; - msg.addr = MPX_I2C_ADDR; - msg.flags = 0; - msg.len = 3; - msg.buf = buffer; - i2c_transfer(client->adapter, &msg, 1); - buffer[1] = 0x00; - i2c_transfer(client->adapter, &msg, 1); - - if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) { - switch (t->audmode) { - case V4L2_TUNER_MODE_MONO: - switch (mpx_audio_modes[t->mpxmode].audio_mode) { - case AUD_A2: - source = mpx_audio_modes[t->mpxmode].source; - break; - case AUD_NICAM: - source = 0x0000; - break; - case AUD_NICAM_L: - source = 0x0200; - break; - default: - break; - } - break; - case V4L2_TUNER_MODE_STEREO: - source = mpx_audio_modes[t->mpxmode].source; - break; - case V4L2_TUNER_MODE_LANG1: - source = 0x0300; - break; - case V4L2_TUNER_MODE_LANG2: - source = 0x0400; - break; - } - source |= mpx_audio_modes[t->mpxmode].source & 0x00ff; - } else - source = mpx_audio_modes[t->mpxmode].source; - - mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus); - mpx_write(client, 0x12, 0x0008, source); - mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb); - mpx_write(client, 0x12, 0x000e, - mpx_audio_modes[t->mpxmode].fm_prescale); - mpx_write(client, 0x12, 0x0010, - mpx_audio_modes[t->mpxmode].nicam_prescale); - mpx_write(client, 0x12, 0x000d, - mpx_audio_modes[t->mpxmode].scart_prescale); - mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system); - mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume); - if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2) - mpx_write(client, 0x10, 0x0022, - t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190); - -#ifdef MPX_DEBUG - { - u8 buf1[3], buf2[2]; - struct i2c_msg msgs[2]; - - printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x " - "%04x %04x %04x %04x %04x %04x\n", - mpx_audio_modes[t->mpxmode].modus, - source, - mpx_audio_modes[t->mpxmode].acb, - mpx_audio_modes[t->mpxmode].fm_prescale, - mpx_audio_modes[t->mpxmode].nicam_prescale, - mpx_audio_modes[t->mpxmode].scart_prescale, - mpx_audio_modes[t->mpxmode].system, - mpx_audio_modes[t->mpxmode].volume); - buf1[0] = 0x11; - buf1[1] = 0x00; - buf1[2] = 0x7e; - msgs[0].addr = MPX_I2C_ADDR; - msgs[0].flags = 0; - msgs[0].len = 3; - msgs[0].buf = buf1; - msgs[1].addr = MPX_I2C_ADDR; - msgs[1].flags = I2C_M_RD; - msgs[1].len = 2; - msgs[1].buf = buf2; - i2c_transfer(client->adapter, msgs, 2); - printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n", - buf2[0], buf2[1]); - buf1[0] = 0x11; - buf1[1] = 0x02; - buf1[2] = 0x00; - i2c_transfer(client->adapter, msgs, 2); - printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n", - buf2[0], buf2[1]); - } -#endif - return 0; -} - -/* - * IF configuration values for the BTF-PG472Z: - * - * B/G: 0x94 0x70 0x49 - * I: 0x14 0x70 0x4a - * D/K: 0x14 0x70 0x4b - * L: 0x04 0x70 0x4b - * L': 0x44 0x70 0x53 - * M: 0x50 0x30 0x4c - */ - -static int set_if(struct i2c_client *client) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - u8 buffer[4]; - struct i2c_msg msg; - int default_mpx_mode = 0; - - /* configure IF */ - buffer[0] = 0; - if (t->std & V4L2_STD_PAL_BG) { - buffer[1] = 0x94; - buffer[2] = 0x70; - buffer[3] = 0x49; - default_mpx_mode = 1; - } else if (t->std & V4L2_STD_PAL_I) { - buffer[1] = 0x14; - buffer[2] = 0x70; - buffer[3] = 0x4a; - default_mpx_mode = 4; - } else if (t->std & V4L2_STD_PAL_DK) { - buffer[1] = 0x14; - buffer[2] = 0x70; - buffer[3] = 0x4b; - default_mpx_mode = 6; - } else if (t->std & V4L2_STD_SECAM_L) { - buffer[1] = 0x04; - buffer[2] = 0x70; - buffer[3] = 0x4b; - default_mpx_mode = 11; - } - msg.addr = IF_I2C_ADDR; - msg.flags = 0; - msg.len = 4; - msg.buf = buffer; - i2c_transfer(client->adapter, &msg, 1); - - /* Select MPX mode if not forced by the user */ - if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES) - t->mpxmode = force_mpx_mode; - else - t->mpxmode = default_mpx_mode; - printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n", - t->mpxmode); - mpx_setup(client); - - return 0; -} - -static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - - switch (cmd) { -#if 0 -#ifdef TUNER_SET_TYPE_ADDR - case TUNER_SET_TYPE_ADDR: - { - struct tuner_setup *tun_setup = arg; - int *type = &tun_setup->type; -#else - case TUNER_SET_TYPE: - { - int *type = arg; -#endif - - if (t->type >= 0) { - if (t->type != *type) - printk(KERN_ERR "wis-sony-tuner: type already " - "set to %d, ignoring request for %d\n", - t->type, *type); - break; - } - t->type = *type; - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - switch (force_band_str[0]) { - case 'b': - case 'B': - case 'g': - case 'G': - printk(KERN_INFO "wis-sony-tuner: forcing " - "tuner to PAL-B/G bands\n"); - force_band = V4L2_STD_PAL_BG; - break; - case 'i': - case 'I': - printk(KERN_INFO "wis-sony-tuner: forcing " - "tuner to PAL-I band\n"); - force_band = V4L2_STD_PAL_I; - break; - case 'd': - case 'D': - case 'k': - case 'K': - printk(KERN_INFO "wis-sony-tuner: forcing " - "tuner to PAL-D/K bands\n"); - force_band = V4L2_STD_PAL_I; - break; - case 'l': - case 'L': - printk(KERN_INFO "wis-sony-tuner: forcing " - "tuner to SECAM-L band\n"); - force_band = V4L2_STD_SECAM_L; - break; - default: - force_band = 0; - break; - } - if (force_band) - t->std = force_band; - else - t->std = V4L2_STD_PAL_BG; - set_if(client); - break; - case TUNER_SONY_BTF_PK467Z: - t->std = V4L2_STD_NTSC_M_JP; - break; - case TUNER_SONY_BTF_PB463Z: - t->std = V4L2_STD_NTSC_M; - break; - default: - printk(KERN_ERR "wis-sony-tuner: tuner type %d is not " - "supported by this module\n", *type); - break; - } - if (type >= 0) - printk(KERN_INFO - "wis-sony-tuner: type set to %d (%s)\n", - t->type, sony_tuners[t->type - 200].name); - break; - } -#endif - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - f->frequency = t->freq; - break; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - t->freq = f->frequency; - set_freq(client, t->freq); - break; - } - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *std = arg; - - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - switch (std->index) { - case 0: - v4l2_video_std_construct(std, - V4L2_STD_PAL_BG, "PAL-B/G"); - break; - case 1: - v4l2_video_std_construct(std, - V4L2_STD_PAL_I, "PAL-I"); - break; - case 2: - v4l2_video_std_construct(std, - V4L2_STD_PAL_DK, "PAL-D/K"); - break; - case 3: - v4l2_video_std_construct(std, - V4L2_STD_SECAM_L, "SECAM-L"); - break; - default: - std->id = 0; /* hack to indicate EINVAL */ - break; - } - break; - case TUNER_SONY_BTF_PK467Z: - if (std->index != 0) { - std->id = 0; /* hack to indicate EINVAL */ - break; - } - v4l2_video_std_construct(std, - V4L2_STD_NTSC_M_JP, "NTSC-J"); - break; - case TUNER_SONY_BTF_PB463Z: - if (std->index != 0) { - std->id = 0; /* hack to indicate EINVAL */ - break; - } - v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC"); - break; - } - break; - } - case VIDIOC_G_STD: - { - v4l2_std_id *std = arg; - - *std = t->std; - break; - } - case VIDIOC_S_STD: - { - v4l2_std_id *std = arg; - v4l2_std_id old = t->std; - - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - if (force_band && (*std & force_band) != *std && - *std != V4L2_STD_PAL && - *std != V4L2_STD_SECAM) { - printk(KERN_DEBUG "wis-sony-tuner: ignoring " - "requested TV standard in " - "favor of force_band value\n"); - t->std = force_band; - } else if (*std & V4L2_STD_PAL_BG) { /* default */ - t->std = V4L2_STD_PAL_BG; - } else if (*std & V4L2_STD_PAL_I) { - t->std = V4L2_STD_PAL_I; - } else if (*std & V4L2_STD_PAL_DK) { - t->std = V4L2_STD_PAL_DK; - } else if (*std & V4L2_STD_SECAM_L) { - t->std = V4L2_STD_SECAM_L; - } else { - printk(KERN_ERR "wis-sony-tuner: TV standard " - "not supported\n"); - *std = 0; /* hack to indicate EINVAL */ - break; - } - if (old != t->std) - set_if(client); - break; - case TUNER_SONY_BTF_PK467Z: - if (!(*std & V4L2_STD_NTSC_M_JP)) { - printk(KERN_ERR "wis-sony-tuner: TV standard " - "not supported\n"); - *std = 0; /* hack to indicate EINVAL */ - } - break; - case TUNER_SONY_BTF_PB463Z: - if (!(*std & V4L2_STD_NTSC_M)) { - printk(KERN_ERR "wis-sony-tuner: TV standard " - "not supported\n"); - *std = 0; /* hack to indicate EINVAL */ - } - break; - } - break; - } - case VIDIOC_QUERYSTD: - { - v4l2_std_id *std = arg; - - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - if (force_band) - *std = force_band; - else - *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I | - V4L2_STD_PAL_DK | V4L2_STD_SECAM_L; - break; - case TUNER_SONY_BTF_PK467Z: - *std = V4L2_STD_NTSC_M_JP; - break; - case TUNER_SONY_BTF_PB463Z: - *std = V4L2_STD_NTSC_M; - break; - } - break; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *tun = arg; - - memset(tun, 0, sizeof(*tun)); - strcpy(tun->name, "Television"); - tun->type = V4L2_TUNER_ANALOG_TV; - tun->rangelow = 0UL; /* does anything use these? */ - tun->rangehigh = 0xffffffffUL; - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - tun->capability = V4L2_TUNER_CAP_NORM | - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2; - tun->rxsubchans = V4L2_TUNER_SUB_MONO | - V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 | - V4L2_TUNER_SUB_LANG2; - break; - case TUNER_SONY_BTF_PK467Z: - case TUNER_SONY_BTF_PB463Z: - tun->capability = V4L2_TUNER_CAP_STEREO; - tun->rxsubchans = V4L2_TUNER_SUB_MONO | - V4L2_TUNER_SUB_STEREO; - break; - } - tun->audmode = t->audmode; - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *tun = arg; - - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - if (tun->audmode != t->audmode) { - t->audmode = tun->audmode; - mpx_setup(client); - } - break; - case TUNER_SONY_BTF_PK467Z: - case TUNER_SONY_BTF_PB463Z: - break; - } - return 0; - } - default: - break; - } - return 0; -} - -static int wis_sony_tuner_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_sony_tuner *t; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) - return -ENODEV; - - t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL); - if (t == NULL) - return -ENOMEM; - - t->type = -1; - t->freq = 0; - t->mpxmode = 0; - t->audmode = V4L2_TUNER_MODE_STEREO; - i2c_set_clientdata(client, t); - - printk(KERN_DEBUG - "wis-sony-tuner: initializing tuner at address %d on %s\n", - client->addr, adapter->name); - - return 0; -} - -static int wis_sony_tuner_remove(struct i2c_client *client) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - - kfree(t); - return 0; -} - -static const struct i2c_device_id wis_sony_tuner_id[] = { - { "wis_sony_tuner", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_sony_tuner_id); - -static struct i2c_driver wis_sony_tuner_driver = { - .driver = { - .name = "WIS Sony TV Tuner I2C driver", - }, - .probe = wis_sony_tuner_probe, - .remove = wis_sony_tuner_remove, - .command = tuner_command, - .id_table = wis_sony_tuner_id, -}; - -static int __init wis_sony_tuner_init(void) -{ - return i2c_add_driver(&wis_sony_tuner_driver); -} - -static void __exit wis_sony_tuner_cleanup(void) -{ - i2c_del_driver(&wis_sony_tuner_driver); -} - -module_init(wis_sony_tuner_init); -module_exit(wis_sony_tuner_cleanup); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-tw2804.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-tw2804.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-tw2804.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-tw2804.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,359 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include - -#include "wis-i2c.h" - -struct wis_tw2804 { - int channel; - int norm; - int brightness; - int contrast; - int saturation; - int hue; -}; - -static u8 global_registers[] = -{ - 0x39, 0x00, - 0x3a, 0xff, - 0x3b, 0x84, - 0x3c, 0x80, - 0x3d, 0x80, - 0x3e, 0x82, - 0x3f, 0x82, - 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ -}; - -static u8 channel_registers[] = -{ - 0x01, 0xc4, - 0x02, 0xa5, - 0x03, 0x20, - 0x04, 0xd0, - 0x05, 0x20, - 0x06, 0xd0, - 0x07, 0x88, - 0x08, 0x20, - 0x09, 0x07, - 0x0a, 0xf0, - 0x0b, 0x07, - 0x0c, 0xf0, - 0x0d, 0x40, - 0x0e, 0xd2, - 0x0f, 0x80, - 0x10, 0x80, - 0x11, 0x80, - 0x12, 0x80, - 0x13, 0x1f, - 0x14, 0x00, - 0x15, 0x00, - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0xff, - 0x19, 0xff, - 0x1a, 0xff, - 0x1b, 0xff, - 0x1c, 0xff, - 0x1d, 0xff, - 0x1e, 0xff, - 0x1f, 0xff, - 0x20, 0x07, - 0x21, 0x07, - 0x22, 0x00, - 0x23, 0x91, - 0x24, 0x51, - 0x25, 0x03, - 0x26, 0x00, - 0x27, 0x00, - 0x28, 0x00, - 0x29, 0x00, - 0x2a, 0x00, - 0x2b, 0x00, - 0x2c, 0x00, - 0x2d, 0x00, - 0x2e, 0x00, - 0x2f, 0x00, - 0x30, 0x00, - 0x31, 0x00, - 0x32, 0x00, - 0x33, 0x00, - 0x34, 0x00, - 0x35, 0x00, - 0x36, 0x00, - 0x37, 0x00, - 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ -}; - -static int write_reg(struct i2c_client *client, u8 reg, u8 value, int channel) -{ - return i2c_smbus_write_byte_data(client, reg | (channel << 6), value); -} - -static int write_regs(struct i2c_client *client, u8 *regs, int channel) -{ - int i; - - for (i = 0; regs[i] != 0xff; i += 2) - if (i2c_smbus_write_byte_data(client, - regs[i] | (channel << 6), regs[i + 1]) < 0) - return -1; - return 0; -} - -static int wis_tw2804_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct wis_tw2804 *dec = i2c_get_clientdata(client); - - if (cmd == DECODER_SET_CHANNEL) { - int *input = arg; - - if (*input < 0 || *input > 3) { - printk(KERN_ERR "wis-tw2804: channel %d is not " - "between 0 and 3!\n", *input); - return 0; - } - dec->channel = *input; - printk(KERN_DEBUG "wis-tw2804: initializing TW2804 " - "channel %d\n", dec->channel); - if (dec->channel == 0 && - write_regs(client, global_registers, 0) < 0) { - printk(KERN_ERR "wis-tw2804: error initializing " - "TW2804 global registers\n"); - return 0; - } - if (write_regs(client, channel_registers, dec->channel) < 0) { - printk(KERN_ERR "wis-tw2804: error initializing " - "TW2804 channel %d\n", dec->channel); - return 0; - } - return 0; - } - - if (dec->channel < 0) { - printk(KERN_DEBUG "wis-tw2804: ignoring command %08x until " - "channel number is set\n", cmd); - return 0; - } - - switch (cmd) { - case VIDIOC_S_STD: - { - v4l2_std_id *input = arg; - u8 regs[] = { - 0x01, *input & V4L2_STD_NTSC ? 0xc4 : 0x84, - 0x09, *input & V4L2_STD_NTSC ? 0x07 : 0x04, - 0x0a, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, - 0x0b, *input & V4L2_STD_NTSC ? 0x07 : 0x04, - 0x0c, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, - 0x0d, *input & V4L2_STD_NTSC ? 0x40 : 0x4a, - 0x16, *input & V4L2_STD_NTSC ? 0x00 : 0x40, - 0x17, *input & V4L2_STD_NTSC ? 0x00 : 0x40, - 0x20, *input & V4L2_STD_NTSC ? 0x07 : 0x0f, - 0x21, *input & V4L2_STD_NTSC ? 0x07 : 0x0f, - 0xff, 0xff, - }; - write_regs(client, regs, dec->channel); - dec->norm = *input; - break; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_CONTRAST: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_SATURATION: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_HUE: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - } - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 255) - dec->brightness = 255; - else if (ctrl->value < 0) - dec->brightness = 0; - else - dec->brightness = ctrl->value; - write_reg(client, 0x12, dec->brightness, dec->channel); - break; - case V4L2_CID_CONTRAST: - if (ctrl->value > 255) - dec->contrast = 255; - else if (ctrl->value < 0) - dec->contrast = 0; - else - dec->contrast = ctrl->value; - write_reg(client, 0x11, dec->contrast, dec->channel); - break; - case V4L2_CID_SATURATION: - if (ctrl->value > 255) - dec->saturation = 255; - else if (ctrl->value < 0) - dec->saturation = 0; - else - dec->saturation = ctrl->value; - write_reg(client, 0x10, dec->saturation, dec->channel); - break; - case V4L2_CID_HUE: - if (ctrl->value > 255) - dec->hue = 255; - else if (ctrl->value < 0) - dec->hue = 0; - else - dec->hue = ctrl->value; - write_reg(client, 0x0f, dec->hue, dec->channel); - break; - } - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dec->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dec->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = dec->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = dec->hue; - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_tw2804_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_tw2804 *dec; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL); - if (dec == NULL) - return -ENOMEM; - - dec->channel = -1; - dec->norm = V4L2_STD_NTSC; - dec->brightness = 128; - dec->contrast = 128; - dec->saturation = 128; - dec->hue = 128; - i2c_set_clientdata(client, dec); - - printk(KERN_DEBUG "wis-tw2804: creating TW2804 at address %d on %s\n", - client->addr, adapter->name); - - return 0; -} - -static int wis_tw2804_remove(struct i2c_client *client) -{ - struct wis_tw2804 *dec = i2c_get_clientdata(client); - - kfree(dec); - return 0; -} - -static const struct i2c_device_id wis_tw2804_id[] = { - { "wis_tw2804", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_tw2804_id); - -static struct i2c_driver wis_tw2804_driver = { - .driver = { - .name = "WIS TW2804 I2C driver", - }, - .probe = wis_tw2804_probe, - .remove = wis_tw2804_remove, - .command = wis_tw2804_command, - .id_table = wis_tw2804_id, -}; - -static int __init wis_tw2804_init(void) -{ - return i2c_add_driver(&wis_tw2804_driver); -} - -static void __exit wis_tw2804_cleanup(void) -{ - i2c_del_driver(&wis_tw2804_driver); -} - -module_init(wis_tw2804_init); -module_exit(wis_tw2804_cleanup); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-tw9903.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-tw9903.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-tw9903.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-tw9903.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,341 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include - -#include "wis-i2c.h" - -struct wis_tw9903 { - int norm; - int brightness; - int contrast; - int hue; -}; - -static u8 initial_registers[] = -{ - 0x02, 0x44, /* input 1, composite */ - 0x03, 0x92, /* correct digital format */ - 0x04, 0x00, - 0x05, 0x80, /* or 0x00 for PAL */ - 0x06, 0x40, /* second internal current reference */ - 0x07, 0x02, /* window */ - 0x08, 0x14, /* window */ - 0x09, 0xf0, /* window */ - 0x0a, 0x81, /* window */ - 0x0b, 0xd0, /* window */ - 0x0c, 0x8c, - 0x0d, 0x00, /* scaling */ - 0x0e, 0x11, /* scaling */ - 0x0f, 0x00, /* scaling */ - 0x10, 0x00, /* brightness */ - 0x11, 0x60, /* contrast */ - 0x12, 0x01, /* sharpness */ - 0x13, 0x7f, /* U gain */ - 0x14, 0x5a, /* V gain */ - 0x15, 0x00, /* hue */ - 0x16, 0xc3, /* sharpness */ - 0x18, 0x00, - 0x19, 0x58, /* vbi */ - 0x1a, 0x80, - 0x1c, 0x0f, /* video norm */ - 0x1d, 0x7f, /* video norm */ - 0x20, 0xa0, /* clamping gain (working 0x50) */ - 0x21, 0x22, - 0x22, 0xf0, - 0x23, 0xfe, - 0x24, 0x3c, - 0x25, 0x38, - 0x26, 0x44, - 0x27, 0x20, - 0x28, 0x00, - 0x29, 0x15, - 0x2a, 0xa0, - 0x2b, 0x44, - 0x2c, 0x37, - 0x2d, 0x00, - 0x2e, 0xa5, /* burst PLL control (working: a9) */ - 0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */ - 0x31, 0x00, - 0x33, 0x22, - 0x34, 0x11, - 0x35, 0x35, - 0x3b, 0x05, - 0x06, 0xc0, /* reset device */ - 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ -}; - -static int write_reg(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int write_regs(struct i2c_client *client, u8 *regs) -{ - int i; - - for (i = 0; regs[i] != 0x00; i += 2) - if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) - return -1; - return 0; -} - -static int wis_tw9903_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct wis_tw9903 *dec = i2c_get_clientdata(client); - - switch (cmd) { - case VIDIOC_S_INPUT: - { - int *input = arg; - - i2c_smbus_write_byte_data(client, 0x02, 0x40 | (*input << 1)); - break; - } -#if 0 - /* The scaler on this thing seems to be horribly broken */ - case DECODER_SET_RESOLUTION: - { - struct video_decoder_resolution *res = arg; - /*int hscale = 256 * 720 / res->width;*/ - int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8)); - int vscale = 256 * (dec->norm & V4L2_STD_NTSC ? 240 : 288) - / res->height; - u8 regs[] = { - 0x0d, vscale & 0xff, - 0x0f, hscale & 0xff, - 0x0e, ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8), - 0x06, 0xc0, /* reset device */ - 0, 0, - }; - printk(KERN_DEBUG "vscale is %04x, hscale is %04x\n", - vscale, hscale); - /*write_regs(client, regs);*/ - break; - } -#endif - case VIDIOC_S_STD: - { - v4l2_std_id *input = arg; - u8 regs[] = { - 0x05, *input & V4L2_STD_NTSC ? 0x80 : 0x00, - 0x07, *input & V4L2_STD_NTSC ? 0x02 : 0x12, - 0x08, *input & V4L2_STD_NTSC ? 0x14 : 0x18, - 0x09, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, - 0, 0, - }; - write_regs(client, regs); - dec->norm = *input; - break; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); - ctrl->minimum = -128; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 0x00; - ctrl->flags = 0; - break; - case V4L2_CID_CONTRAST: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 0x60; - ctrl->flags = 0; - break; -#if 0 - /* I don't understand how the Chroma Gain registers work... */ - case V4L2_CID_SATURATION: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 64; - ctrl->flags = 0; - break; -#endif - case V4L2_CID_HUE: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); - ctrl->minimum = -128; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 0; - ctrl->flags = 0; - break; - } - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 127) - dec->brightness = 127; - else if (ctrl->value < -128) - dec->brightness = -128; - else - dec->brightness = ctrl->value; - write_reg(client, 0x10, dec->brightness); - break; - case V4L2_CID_CONTRAST: - if (ctrl->value > 255) - dec->contrast = 255; - else if (ctrl->value < 0) - dec->contrast = 0; - else - dec->contrast = ctrl->value; - write_reg(client, 0x11, dec->contrast); - break; -#if 0 - case V4L2_CID_SATURATION: - if (ctrl->value > 127) - dec->saturation = 127; - else if (ctrl->value < 0) - dec->saturation = 0; - else - dec->saturation = ctrl->value; - /*write_reg(client, 0x0c, dec->saturation);*/ - break; -#endif - case V4L2_CID_HUE: - if (ctrl->value > 127) - dec->hue = 127; - else if (ctrl->value < -128) - dec->hue = -128; - else - dec->hue = ctrl->value; - write_reg(client, 0x15, dec->hue); - break; - } - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dec->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dec->contrast; - break; -#if 0 - case V4L2_CID_SATURATION: - ctrl->value = dec->saturation; - break; -#endif - case V4L2_CID_HUE: - ctrl->value = dec->hue; - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_tw9903_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_tw9903 *dec; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL); - if (dec == NULL) - return -ENOMEM; - - dec->norm = V4L2_STD_NTSC; - dec->brightness = 0; - dec->contrast = 0x60; - dec->hue = 0; - i2c_set_clientdata(client, dec); - - printk(KERN_DEBUG - "wis-tw9903: initializing TW9903 at address %d on %s\n", - client->addr, adapter->name); - - if (write_regs(client, initial_registers) < 0) { - printk(KERN_ERR "wis-tw9903: error initializing TW9903\n"); - kfree(dec); - return -ENODEV; - } - - return 0; -} - -static int wis_tw9903_remove(struct i2c_client *client) -{ - struct wis_tw9903 *dec = i2c_get_clientdata(client); - - kfree(dec); - return 0; -} - -static const struct i2c_device_id wis_tw9903_id[] = { - { "wis_tw9903", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_tw9903_id); - -static struct i2c_driver wis_tw9903_driver = { - .driver = { - .name = "WIS TW9903 I2C driver", - }, - .probe = wis_tw9903_probe, - .remove = wis_tw9903_remove, - .command = wis_tw9903_command, - .id_table = wis_tw9903_id, -}; - -static int __init wis_tw9903_init(void) -{ - return i2c_add_driver(&wis_tw9903_driver); -} - -static void __exit wis_tw9903_cleanup(void) -{ - i2c_del_driver(&wis_tw9903_driver); -} - -module_init(wis_tw9903_init); -module_exit(wis_tw9903_cleanup); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-uda1342.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-uda1342.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-uda1342.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/go7007/wis-uda1342.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2005-2006 Micronas USA Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include - -#include "wis-i2c.h" - -static int write_reg(struct i2c_client *client, int reg, int value) -{ - /* UDA1342 wants MSB first, but SMBus sends LSB first */ - i2c_smbus_write_word_data(client, reg, swab16(value)); - return 0; -} - -static int wis_uda1342_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - switch (cmd) { - case VIDIOC_S_AUDIO: - { - int *inp = arg; - - switch (*inp) { - case TVAUDIO_INPUT_TUNER: - write_reg(client, 0x00, 0x1441); /* select input 2 */ - break; - case TVAUDIO_INPUT_EXTERN: - write_reg(client, 0x00, 0x1241); /* select input 1 */ - break; - default: - printk(KERN_ERR "wis-uda1342: input %d not supported\n", - *inp); - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_uda1342_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) - return -ENODEV; - - printk(KERN_DEBUG - "wis-uda1342: initializing UDA1342 at address %d on %s\n", - client->addr, adapter->name); - - write_reg(client, 0x00, 0x8000); /* reset registers */ - write_reg(client, 0x00, 0x1241); /* select input 1 */ - - return 0; -} - -static int wis_uda1342_remove(struct i2c_client *client) -{ - return 0; -} - -static const struct i2c_device_id wis_uda1342_id[] = { - { "wis_uda1342", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_uda1342_id); - -static struct i2c_driver wis_uda1342_driver = { - .driver = { - .name = "WIS UDA1342 I2C driver", - }, - .probe = wis_uda1342_probe, - .remove = wis_uda1342_remove, - .command = wis_uda1342_command, - .id_table = wis_uda1342_id, -}; - -static int __init wis_uda1342_init(void) -{ - return i2c_add_driver(&wis_uda1342_driver); -} - -static void __exit wis_uda1342_cleanup(void) -{ - i2c_del_driver(&wis_uda1342_driver); -} - -module_init(wis_uda1342_init); -module_exit(wis_uda1342_cleanup); - -MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -# -# LIRC driver(s) configuration -# -menuconfig LIRC_STAGING - bool "Linux Infrared Remote Control IR receiver/transmitter drivers" - depends on LIRC - help - Say Y here, and all supported Linux Infrared Remote Control IR and - RF receiver and transmitter drivers will be displayed. When paired - with a remote control and the lirc daemon, the receiver drivers - allow control of your Linux system via remote control. - -if LIRC_STAGING - -config LIRC_BT829 - tristate "BT829 based hardware" - depends on LIRC && PCI - help - Driver for the IR interface on BT829-based hardware - -config LIRC_IGORPLUGUSB - tristate "Igor Cesko's USB IR Receiver" - depends on LIRC && USB - help - Driver for Igor Cesko's USB IR Receiver - -config LIRC_IMON - tristate "Legacy SoundGraph iMON Receiver and Display" - depends on LIRC && USB - help - Driver for the original SoundGraph iMON IR Receiver and Display - - Current generation iMON devices use the input layer imon driver. - -config LIRC_PARALLEL - tristate "Homebrew Parallel Port Receiver" - depends on LIRC && PARPORT - help - Driver for Homebrew Parallel Port Receivers - -config LIRC_SASEM - tristate "Sasem USB IR Remote" - depends on LIRC && USB - help - Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module - -config LIRC_SERIAL - tristate "Homebrew Serial Port Receiver" - depends on LIRC - help - Driver for Homebrew Serial Port Receivers - -config LIRC_SERIAL_TRANSMITTER - bool "Serial Port Transmitter" - default y - depends on LIRC_SERIAL - help - Serial Port Transmitter support - -config LIRC_SIR - tristate "Built-in SIR IrDA port" - depends on LIRC - help - Driver for the SIR IrDA port - -config LIRC_TTUSBIR - tristate "Technotrend USB IR Receiver" - depends on LIRC && USB - help - Driver for the Technotrend USB IR Receiver - -config LIRC_ZILOG - tristate "Zilog/Hauppauge IR Transmitter" - depends on LIRC && I2C - help - Driver for the Zilog/Hauppauge IR Transmitter, found on - PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards -endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_bt829.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_bt829.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_bt829.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_bt829.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,383 +0,0 @@ -/* - * Remote control driver for the TV-card based on bt829 - * - * by Leonid Froenchenko - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include - -#include - -static int poll_main(void); -static int atir_init_start(void); - -static void write_index(unsigned char index, unsigned int value); -static unsigned int read_index(unsigned char index); - -static void do_i2c_start(void); -static void do_i2c_stop(void); - -static void seems_wr_byte(unsigned char al); -static unsigned char seems_rd_byte(void); - -static unsigned int read_index(unsigned char al); -static void write_index(unsigned char ah, unsigned int edx); - -static void cycle_delay(int cycle); - -static void do_set_bits(unsigned char bl); -static unsigned char do_get_bits(void); - -#define DATA_PCI_OFF 0x7FFC00 -#define WAIT_CYCLE 20 - -#define DRIVER_NAME "lirc_bt829" - -static int debug; -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \ - } while (0) - -static int atir_minor; -static unsigned long pci_addr_phys; -static unsigned char *pci_addr_lin; - -static struct lirc_driver atir_driver; - -static struct pci_dev *do_pci_probe(void) -{ - struct pci_dev *my_dev; - my_dev = pci_get_device(PCI_VENDOR_ID_ATI, - PCI_DEVICE_ID_ATI_264VT, NULL); - if (my_dev) { - printk(KERN_ERR DRIVER_NAME ": Using device: %s\n", - pci_name(my_dev)); - pci_addr_phys = 0; - if (my_dev->resource[0].flags & IORESOURCE_MEM) { - pci_addr_phys = my_dev->resource[0].start; - printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X\n", - (unsigned int)pci_addr_phys); - } - if (pci_addr_phys == 0) { - printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n"); - return NULL; - } - } else { - printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n"); - return NULL; - } - return my_dev; -} - -static int atir_add_to_buf(void *data, struct lirc_buffer *buf) -{ - unsigned char key; - int status; - status = poll_main(); - key = (status >> 8) & 0xFF; - if (status & 0xFF) { - dprintk("reading key %02X\n", key); - lirc_buffer_write(buf, &key); - return 0; - } - return -ENODATA; -} - -static int atir_set_use_inc(void *data) -{ - dprintk("driver is opened\n"); - return 0; -} - -static void atir_set_use_dec(void *data) -{ - dprintk("driver is closed\n"); -} - -int init_module(void) -{ - struct pci_dev *pdev; - - pdev = do_pci_probe(); - if (pdev == NULL) - return 1; - - if (!atir_init_start()) - return 1; - - strcpy(atir_driver.name, "ATIR"); - atir_driver.minor = -1; - atir_driver.code_length = 8; - atir_driver.sample_rate = 10; - atir_driver.data = 0; - atir_driver.add_to_buf = atir_add_to_buf; - atir_driver.set_use_inc = atir_set_use_inc; - atir_driver.set_use_dec = atir_set_use_dec; - atir_driver.dev = &pdev->dev; - atir_driver.owner = THIS_MODULE; - - atir_minor = lirc_register_driver(&atir_driver); - if (atir_minor < 0) { - printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n"); - return atir_minor; - } - dprintk("driver is registered on minor %d\n", atir_minor); - - return 0; -} - - -void cleanup_module(void) -{ - lirc_unregister_driver(atir_minor); -} - - -static int atir_init_start(void) -{ - pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400); - if (pci_addr_lin == 0) { - printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n"); - return 0; - } - return 1; -} - -static void cycle_delay(int cycle) -{ - udelay(WAIT_CYCLE*cycle); -} - - -static int poll_main() -{ - unsigned char status_high, status_low; - - do_i2c_start(); - - seems_wr_byte(0xAA); - seems_wr_byte(0x01); - - do_i2c_start(); - - seems_wr_byte(0xAB); - - status_low = seems_rd_byte(); - status_high = seems_rd_byte(); - - do_i2c_stop(); - - return (status_high << 8) | status_low; -} - -static void do_i2c_start(void) -{ - do_set_bits(3); - cycle_delay(4); - - do_set_bits(1); - cycle_delay(7); - - do_set_bits(0); - cycle_delay(2); -} - -static void do_i2c_stop(void) -{ - unsigned char bits; - bits = do_get_bits() & 0xFD; - do_set_bits(bits); - cycle_delay(1); - - bits |= 1; - do_set_bits(bits); - cycle_delay(2); - - bits |= 2; - do_set_bits(bits); - bits = 3; - do_set_bits(bits); - cycle_delay(2); -} - -static void seems_wr_byte(unsigned char value) -{ - int i; - unsigned char reg; - - reg = do_get_bits(); - for (i = 0; i < 8; i++) { - if (value & 0x80) - reg |= 0x02; - else - reg &= 0xFD; - - do_set_bits(reg); - cycle_delay(1); - - reg |= 1; - do_set_bits(reg); - cycle_delay(1); - - reg &= 0xFE; - do_set_bits(reg); - cycle_delay(1); - value <<= 1; - } - cycle_delay(2); - - reg |= 2; - do_set_bits(reg); - - reg |= 1; - do_set_bits(reg); - - cycle_delay(1); - do_get_bits(); - - reg &= 0xFE; - do_set_bits(reg); - cycle_delay(3); -} - -static unsigned char seems_rd_byte(void) -{ - int i; - int rd_byte; - unsigned char bits_2, bits_1; - - bits_1 = do_get_bits() | 2; - do_set_bits(bits_1); - - rd_byte = 0; - for (i = 0; i < 8; i++) { - bits_1 &= 0xFE; - do_set_bits(bits_1); - cycle_delay(2); - - bits_1 |= 1; - do_set_bits(bits_1); - cycle_delay(1); - - bits_2 = do_get_bits(); - if (bits_2 & 2) - rd_byte |= 1; - - rd_byte <<= 1; - } - - bits_1 = 0; - if (bits_2 == 0) - bits_1 |= 2; - - do_set_bits(bits_1); - cycle_delay(2); - - bits_1 |= 1; - do_set_bits(bits_1); - cycle_delay(3); - - bits_1 &= 0xFE; - do_set_bits(bits_1); - cycle_delay(2); - - rd_byte >>= 1; - rd_byte &= 0xFF; - return rd_byte; -} - -static void do_set_bits(unsigned char new_bits) -{ - int reg_val; - reg_val = read_index(0x34); - if (new_bits & 2) { - reg_val &= 0xFFFFFFDF; - reg_val |= 1; - } else { - reg_val &= 0xFFFFFFFE; - reg_val |= 0x20; - } - reg_val |= 0x10; - write_index(0x34, reg_val); - - reg_val = read_index(0x31); - if (new_bits & 1) - reg_val |= 0x1000000; - else - reg_val &= 0xFEFFFFFF; - - reg_val |= 0x8000000; - write_index(0x31, reg_val); -} - -static unsigned char do_get_bits(void) -{ - unsigned char bits; - int reg_val; - - reg_val = read_index(0x34); - reg_val |= 0x10; - reg_val &= 0xFFFFFFDF; - write_index(0x34, reg_val); - - reg_val = read_index(0x34); - bits = 0; - if (reg_val & 8) - bits |= 2; - else - bits &= 0xFD; - - reg_val = read_index(0x31); - if (reg_val & 0x1000000) - bits |= 1; - else - bits &= 0xFE; - - return bits; -} - -static unsigned int read_index(unsigned char index) -{ - unsigned char *addr; - unsigned int value; - /* addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */ - addr = pci_addr_lin + ((index & 0xFF) << 2); - value = readl(addr); - return value; -} - -static void write_index(unsigned char index, unsigned int reg_val) -{ - unsigned char *addr; - addr = pci_addr_lin + ((index & 0xFF) << 2); - writel(reg_val, addr); -} - -MODULE_AUTHOR("Froenchenko Leonid"); -MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards"); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ene0100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ene0100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ene0100.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ene0100.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -/* - * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) - * - * Copyright (C) 2009 Maxim Levitsky - * - * 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, or (at your option) any later version. - * - * 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 -#include - -/* hardware address */ -#define ENE_STATUS 0 /* hardware status - unused */ -#define ENE_ADDR_HI 1 /* hi byte of register address */ -#define ENE_ADDR_LO 2 /* low byte of register address */ -#define ENE_IO 3 /* read/write window */ -#define ENE_MAX_IO 4 - -/* 8 bytes of samples, divided in 2 halfs*/ -#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */ -#define ENE_SAMPLE_SPC_MASK (1 << 7) /* sample is space */ -#define ENE_SAMPLE_VALUE_MASK 0x7F -#define ENE_SAMPLE_OVERFLOW 0x7F -#define ENE_SAMPLES_SIZE 4 - -/* fan input sample buffer */ -#define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */ - /* each sample of normal buffer */ - -#define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */ - /* if set, says that sample is pulse */ -#define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */ - -/* first firmware register */ -#define ENE_FW1 0xF8F8 -#define ENE_FW1_ENABLE (1 << 0) /* enable fw processing */ -#define ENE_FW1_TXIRQ (1 << 1) /* TX interrupt pending */ -#define ENE_FW1_WAKE (1 << 6) /* enable wake from S3 */ -#define ENE_FW1_IRQ (1 << 7) /* enable interrupt */ - -/* second firmware register */ -#define ENE_FW2 0xF8F9 -#define ENE_FW2_BUF_HIGH (1 << 0) /* which half of the buffer to read */ -#define ENE_FW2_IRQ_CLR (1 << 2) /* clear this on IRQ */ -#define ENE_FW2_GP40_AS_LEARN (1 << 4) /* normal input is used as */ - /* learning input */ -#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */ -#define ENE_FW2_LEARNING (1 << 7) /* hardware supports learning and TX */ - -/* fan as input settings - only if learning capable */ -#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ -#define ENE_FAN_AS_IN1_EN 0xCD -#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ -#define ENE_FAN_AS_IN2_EN 0x03 -#define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */ - -/* IRQ registers block (for revision B) */ -#define ENEB_IRQ 0xFD09 /* IRQ number */ -#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ -#define ENEB_IRQ_STATUS 0xFD80 /* irq status */ -#define ENEB_IRQ_STATUS_IR (1 << 5) /* IR irq */ - -/* IRQ registers block (for revision C,D) */ -#define ENEC_IRQ 0xFE9B /* new irq settings register */ -#define ENEC_IRQ_MASK 0x0F /* irq number mask */ -#define ENEC_IRQ_UNK_EN (1 << 4) /* always enabled */ -#define ENEC_IRQ_STATUS (1 << 5) /* irq status and ACK */ - -/* CIR block settings */ -#define ENE_CIR_CONF1 0xFEC0 -#define ENE_CIR_CONF1_ADC_ON 0x7 /* reciever on gpio40 enabled */ -#define ENE_CIR_CONF1_LEARN1 (1 << 3) /* enabled on learning mode */ -#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ -#define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */ - -#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */ -#define ENE_CIR_CONF2_LEARN2 (1 << 4) /* set on enable learning */ -#define ENE_CIR_CONF2_GPIO40DIS (1 << 5) /* disable normal input via gpio40 */ - -#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */ -#define ENE_CIR_SAMPLE_OVERFLOW (1 << 7) /* interrupt on overflows if set */ - - -/* transmitter - not implemented yet */ -/* KB3926C and higher */ -/* transmission is very similiar to recieving, a byte is written to */ -/* ENE_TX_INPUT, in same manner as it is read from sample buffer */ -/* sample period is fixed*/ - - -/* transmitter ports */ -#define ENE_TX_PORT1 0xFC01 /* this enables one or both */ -#define ENE_TX_PORT1_EN (1 << 5) /* TX ports */ -#define ENE_TX_PORT2 0xFC08 -#define ENE_TX_PORT2_EN (1 << 1) - -#define ENE_TX_INPUT 0xFEC9 /* next byte to transmit */ -#define ENE_TX_SPC_MASK (1 << 7) /* Transmitted sample is space */ -#define ENE_TX_UNK1 0xFECB /* set to 0x63 */ -#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period */ - - -#define ENE_TX_CARRIER 0xFECE /* TX carrier * 2 (khz) */ -#define ENE_TX_CARRIER_UNKBIT 0x80 /* This bit set on transmit */ -#define ENE_TX_CARRIER_LOW 0xFECF /* TX carrier / 2 */ - -/* Hardware versions */ -#define ENE_HW_VERSION 0xFF00 /* hardware revision */ -#define ENE_HW_UNK 0xFF1D -#define ENE_HW_UNK_CLR (1 << 2) -#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */ -#define ENE_HW_VER_MINOR 0xFF1F -#define ENE_HW_VER_OLD 0xFD00 - -#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0)) - -#define ENE_DRIVER_NAME "enecir" -#define ENE_MAXGAP 250000 /* this is amount of time we wait - before turning the sampler, chosen - arbitry */ - -#define space(len) (-(len)) /* add a space */ - -/* software defines */ -#define ENE_IRQ_RX 1 -#define ENE_IRQ_TX 2 - -#define ENE_HW_B 1 /* 3926B */ -#define ENE_HW_C 2 /* 3926C */ -#define ENE_HW_D 3 /* 3926D */ - -#define ene_printk(level, text, ...) \ - printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__) - -struct ene_device { - struct pnp_dev *pnp_dev; - struct lirc_driver *lirc_driver; - - /* hw settings */ - unsigned long hw_io; - int irq; - - int hw_revision; /* hardware revision */ - int hw_learning_and_tx_capable; /* learning capable */ - int hw_gpio40_learning; /* gpio40 is learning */ - int hw_fan_as_normal_input; /* fan input is used as regular input */ - - /* device data */ - int idle; - int fan_input_inuse; - - int sample; - int in_use; - - struct timeval gap_start; -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_igorplugusb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_igorplugusb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_igorplugusb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_igorplugusb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,577 +0,0 @@ -/* - * lirc_igorplugusb - USB remote support for LIRC - * - * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware. - * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm - * - * The device can only record bursts of up to 36 pulses/spaces. - * Works fine with RC5. Longer commands lead to device buffer overrun. - * (Maybe a better firmware or a microcontroller with more ram can help?) - * - * Version 0.1 [beta status] - * - * Copyright (C) 2004 Jan M. Hochstein - * - * - * This driver was derived from: - * Paul Miller - * "lirc_atiusb" module - * Vladimir Dergachev 's 2002 - * "USB ATI Remote support" (input device) - * Adrian Dewhurst 's 2002 - * "USB StreamZap remote driver" (LIRC) - * Artur Lipowski 's 2002 - * "lirc_dev" and "lirc_gpio" LIRC modules - */ - -/* - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/* module identification */ -#define DRIVER_VERSION "0.2" -#define DRIVER_AUTHOR \ - "Jan M. Hochstein " -#define DRIVER_DESC "Igorplug USB remote driver for LIRC" -#define DRIVER_NAME "lirc_igorplugusb" - -/* debugging support */ -#ifdef CONFIG_USB_DEBUG -static int debug = 1; -#else -static int debug; -#endif - -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG fmt, ## args); \ - } while (0) - -/* One mode2 pulse/space has 4 bytes. */ -#define CODE_LENGTH sizeof(int) - -/* Igor's firmware cannot record bursts longer than 36. */ -#define DEVICE_BUFLEN 36 - -/* - * Header at the beginning of the device's buffer: - * unsigned char data_length - * unsigned char data_start (!=0 means ring-buffer overrun) - * unsigned char counter (incremented by each burst) - */ -#define DEVICE_HEADERLEN 3 - -/* This is for the gap */ -#define ADDITIONAL_LIRC_BYTES 2 - -/* times to poll per second */ -#define SAMPLE_RATE 100 -static int sample_rate = SAMPLE_RATE; - - -/**** Igor's USB Request Codes */ - -#define SET_INFRABUFFER_EMPTY 1 -/** - * Params: none - * Answer: empty - */ - -#define GET_INFRACODE 2 -/** - * Params: - * wValue: offset to begin reading infra buffer - * - * Answer: infra data - */ - -#define SET_DATAPORT_DIRECTION 3 -/** - * Params: - * wValue: (byte) 1 bit for each data port pin (0=in, 1=out) - * - * Answer: empty - */ - -#define GET_DATAPORT_DIRECTION 4 -/** - * Params: none - * - * Answer: (byte) 1 bit for each data port pin (0=in, 1=out) - */ - -#define SET_OUT_DATAPORT 5 -/** - * Params: - * wValue: byte to write to output data port - * - * Answer: empty - */ - -#define GET_OUT_DATAPORT 6 -/** - * Params: none - * - * Answer: least significant 3 bits read from output data port - */ - -#define GET_IN_DATAPORT 7 -/** - * Params: none - * - * Answer: least significant 3 bits read from input data port - */ - -#define READ_EEPROM 8 -/** - * Params: - * wValue: offset to begin reading EEPROM - * - * Answer: EEPROM bytes - */ - -#define WRITE_EEPROM 9 -/** - * Params: - * wValue: offset to EEPROM byte - * wIndex: byte to write - * - * Answer: empty - */ - -#define SEND_RS232 10 -/** - * Params: - * wValue: byte to send - * - * Answer: empty - */ - -#define RECV_RS232 11 -/** - * Params: none - * - * Answer: byte received - */ - -#define SET_RS232_BAUD 12 -/** - * Params: - * wValue: byte to write to UART bit rate register (UBRR) - * - * Answer: empty - */ - -#define GET_RS232_BAUD 13 -/** - * Params: none - * - * Answer: byte read from UART bit rate register (UBRR) - */ - - -/* data structure for each usb remote */ -struct igorplug { - - /* usb */ - struct usb_device *usbdev; - int devnum; - - unsigned char *buf_in; - unsigned int len_in; - int in_space; - struct timeval last_time; - - dma_addr_t dma_in; - - /* lirc */ - struct lirc_driver *d; - - /* handle sending (init strings) */ - int send_flags; -}; - -static int unregister_from_lirc(struct igorplug *ir) -{ - struct lirc_driver *d; - int devnum; - - if (!ir) { - printk(KERN_ERR "%s: called with NULL device struct!\n", - __func__); - return -EINVAL; - } - - devnum = ir->devnum; - d = ir->d; - - if (!d) { - printk(KERN_ERR "%s: called with NULL lirc driver struct!\n", - __func__); - return -EINVAL; - } - - dprintk(DRIVER_NAME "[%d]: calling lirc_unregister_driver\n", devnum); - lirc_unregister_driver(d->minor); - - kfree(d); - ir->d = NULL; - kfree(ir); - - return devnum; -} - -static int set_use_inc(void *data) -{ - struct igorplug *ir = data; - - if (!ir) { - printk(DRIVER_NAME "[?]: set_use_inc called with no context\n"); - return -EIO; - } - - dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum); - - if (!ir->usbdev) - return -ENODEV; - - return 0; -} - -static void set_use_dec(void *data) -{ - struct igorplug *ir = data; - - if (!ir) { - printk(DRIVER_NAME "[?]: set_use_dec called with no context\n"); - return; - } - - dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); -} - -static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf, - int i, int max) -{ - int code; - - /* MODE2: pulse/space (PULSE_BIT) in 1us units */ - while (i < max) { - /* 1 Igor-tick = 85.333333 us */ - code = (unsigned int)ir->buf_in[i] * 85 + - (unsigned int)ir->buf_in[i] / 3; - ir->last_time.tv_usec += code; - if (ir->in_space) - code |= PULSE_BIT; - lirc_buffer_write(buf, (unsigned char *)&code); - /* 1 chunk = CODE_LENGTH bytes */ - ir->in_space ^= 1; - ++i; - } -} - -/** - * Called in user context. - * return 0 if data was added to the buffer and - * -ENODATA if none was available. This should add some number of bits - * evenly divisible by code_length to the buffer - */ -static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf) -{ - int ret; - struct igorplug *ir = (struct igorplug *)data; - - if (!ir || !ir->usbdev) /* Has the device been removed? */ - return -ENODEV; - - memset(ir->buf_in, 0, ir->len_in); - - ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), - GET_INFRACODE, USB_TYPE_VENDOR | USB_DIR_IN, - 0/* offset */, /*unused*/0, - ir->buf_in, ir->len_in, - /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); - if (ret > 0) { - int code, timediff; - struct timeval now; - - /* ACK packet has 1 byte --> ignore */ - if (ret < DEVICE_HEADERLEN) - return -ENODATA; - - dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n", - ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]); - - do_gettimeofday(&now); - timediff = now.tv_sec - ir->last_time.tv_sec; - if (timediff + 1 > PULSE_MASK / 1000000) - timediff = PULSE_MASK; - else { - timediff *= 1000000; - timediff += now.tv_usec - ir->last_time.tv_usec; - } - ir->last_time.tv_sec = now.tv_sec; - ir->last_time.tv_usec = now.tv_usec; - - /* create leading gap */ - code = timediff; - lirc_buffer_write(buf, (unsigned char *)&code); - ir->in_space = 1; /* next comes a pulse */ - - if (ir->buf_in[2] == 0) - send_fragment(ir, buf, DEVICE_HEADERLEN, ret); - else { - printk(KERN_WARNING DRIVER_NAME - "[%d]: Device buffer overrun.\n", ir->devnum); - /* HHHNNNNNNNNNNNOOOOOOOO H = header - <---[2]---> N = newer - <---------ret--------> O = older */ - ir->buf_in[2] %= ret - DEVICE_HEADERLEN; /* sanitize */ - /* keep even-ness to not desync pulse/pause */ - send_fragment(ir, buf, DEVICE_HEADERLEN + - ir->buf_in[2] - (ir->buf_in[2] & 1), ret); - send_fragment(ir, buf, DEVICE_HEADERLEN, - DEVICE_HEADERLEN + ir->buf_in[2]); - } - - ret = usb_control_msg( - ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), - SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, - /*unused*/0, /*unused*/0, - /*dummy*/ir->buf_in, /*dummy*/ir->len_in, - /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); - if (ret < 0) - printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: " - "error %d\n", ir->devnum, ret); - return 0; - } else if (ret < 0) - printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n", - ir->devnum, ret); - - return -ENODATA; -} - - - -static int igorplugusb_remote_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = NULL; - struct usb_host_interface *idesc = NULL; - struct usb_endpoint_descriptor *ep; - struct igorplug *ir = NULL; - struct lirc_driver *driver = NULL; - int devnum, pipe, maxp; - int minor = 0; - char buf[63], name[128] = ""; - int mem_failure = 0; - int ret; - - dprintk(DRIVER_NAME ": usb probe called.\n"); - - dev = interface_to_usbdev(intf); - - idesc = intf->cur_altsetting; - - if (idesc->desc.bNumEndpoints != 1) - return -ENODEV; - - ep = &idesc->endpoint->desc; - if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - != USB_DIR_IN) - || (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_CONTROL) - return -ENODEV; - - pipe = usb_rcvctrlpipe(dev, ep->bEndpointAddress); - devnum = dev->devnum; - maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - dprintk(DRIVER_NAME "[%d]: bytes_in_key=%zu maxp=%d\n", - devnum, CODE_LENGTH, maxp); - - mem_failure = 0; - ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL); - if (!ir) { - mem_failure = 1; - goto mem_failure_switch; - } - driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); - if (!driver) { - mem_failure = 2; - goto mem_failure_switch; - } - - ir->buf_in = usb_alloc_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN, - GFP_ATOMIC, &ir->dma_in); - if (!ir->buf_in) { - mem_failure = 3; - goto mem_failure_switch; - } - - strcpy(driver->name, DRIVER_NAME " "); - driver->minor = -1; - driver->code_length = CODE_LENGTH * 8; /* in bits */ - driver->features = LIRC_CAN_REC_MODE2; - driver->data = ir; - driver->chunk_size = CODE_LENGTH; - driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES; - driver->set_use_inc = &set_use_inc; - driver->set_use_dec = &set_use_dec; - driver->sample_rate = sample_rate; /* per second */ - driver->add_to_buf = &igorplugusb_remote_poll; - driver->dev = &intf->dev; - driver->owner = THIS_MODULE; - - minor = lirc_register_driver(driver); - if (minor < 0) - mem_failure = 9; - -mem_failure_switch: - - switch (mem_failure) { - case 9: - usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN, - ir->buf_in, ir->dma_in); - case 3: - kfree(driver); - case 2: - kfree(ir); - case 1: - printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n", - devnum, mem_failure); - return -ENOMEM; - } - - driver->minor = minor; - ir->d = driver; - ir->devnum = devnum; - ir->usbdev = dev; - ir->len_in = DEVICE_BUFLEN + DEVICE_HEADERLEN; - ir->in_space = 1; /* First mode2 event is a space. */ - do_gettimeofday(&ir->last_time); - - if (dev->descriptor.iManufacturer - && usb_string(dev, dev->descriptor.iManufacturer, - buf, sizeof(buf)) > 0) - strlcpy(name, buf, sizeof(name)); - if (dev->descriptor.iProduct - && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0) - snprintf(name + strlen(name), sizeof(name) - strlen(name), - " %s", buf); - printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name, - dev->bus->busnum, devnum); - - /* clear device buffer */ - ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), - SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, - /*unused*/0, /*unused*/0, - /*dummy*/ir->buf_in, /*dummy*/ir->len_in, - /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); - if (ret < 0) - printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n", - devnum, ret); - - usb_set_intfdata(intf, ir); - return 0; -} - - -static void igorplugusb_remote_disconnect(struct usb_interface *intf) -{ - struct usb_device *usbdev = interface_to_usbdev(intf); - struct igorplug *ir = usb_get_intfdata(intf); - struct device *dev = &intf->dev; - int devnum; - - usb_set_intfdata(intf, NULL); - - if (!ir || !ir->d) - return; - - ir->usbdev = NULL; - - usb_free_coherent(usbdev, ir->len_in, ir->buf_in, ir->dma_in); - - devnum = unregister_from_lirc(ir); - - dev_info(dev, DRIVER_NAME "[%d]: %s done\n", devnum, __func__); -} - -static struct usb_device_id igorplugusb_remote_id_table[] = { - /* Igor Plug USB (Atmel's Manufact. ID) */ - { USB_DEVICE(0x03eb, 0x0002) }, - /* Fit PC2 Infrared Adapter */ - { USB_DEVICE(0x03eb, 0x21fe) }, - - /* Terminating entry */ - { } -}; - -static struct usb_driver igorplugusb_remote_driver = { - .name = DRIVER_NAME, - .probe = igorplugusb_remote_probe, - .disconnect = igorplugusb_remote_disconnect, - .id_table = igorplugusb_remote_id_table -}; - -static int __init igorplugusb_remote_init(void) -{ - int ret = 0; - - dprintk(DRIVER_NAME ": loaded, debug mode enabled\n"); - - ret = usb_register(&igorplugusb_remote_driver); - if (ret) - printk(KERN_ERR DRIVER_NAME ": usb register failed!\n"); - - return ret; -} - -static void __exit igorplugusb_remote_exit(void) -{ - usb_deregister(&igorplugusb_remote_driver); -} - -module_init(igorplugusb_remote_init); -module_exit(igorplugusb_remote_exit); - -#include -MODULE_INFO(vermagic, VERMAGIC_STRING); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, igorplugusb_remote_id_table); - -module_param(sample_rate, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_imon.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_imon.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_imon.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_imon.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1057 +0,0 @@ -/* - * lirc_imon.c: LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD - * including the iMON PAD model - * - * Copyright(C) 2004 Venky Raju(dev@venky.ws) - * Copyright(C) 2009 Jarod Wilson - * - * lirc_imon 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -#define MOD_AUTHOR "Venky Raju " -#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" -#define MOD_NAME "lirc_imon" -#define MOD_VERSION "0.8" - -#define DISPLAY_MINOR_BASE 144 -#define DEVICE_NAME "lcd%d" - -#define BUF_CHUNK_SIZE 4 -#define BUF_SIZE 128 - -#define BIT_DURATION 250 /* each bit received is 250us */ - -/*** P R O T O T Y P E S ***/ - -/* USB Callback prototypes */ -static int imon_probe(struct usb_interface *interface, - const struct usb_device_id *id); -static void imon_disconnect(struct usb_interface *interface); -static void usb_rx_callback(struct urb *urb); -static void usb_tx_callback(struct urb *urb); - -/* suspend/resume support */ -static int imon_resume(struct usb_interface *intf); -static int imon_suspend(struct usb_interface *intf, pm_message_t message); - -/* Display file_operations function prototypes */ -static int display_open(struct inode *inode, struct file *file); -static int display_close(struct inode *inode, struct file *file); - -/* VFD write operation */ -static ssize_t vfd_write(struct file *file, const char *buf, - size_t n_bytes, loff_t *pos); - -/* LIRC driver function prototypes */ -static int ir_open(void *data); -static void ir_close(void *data); - -/* Driver init/exit prototypes */ -static int __init imon_init(void); -static void __exit imon_exit(void); - -/*** G L O B A L S ***/ -#define IMON_DATA_BUF_SZ 35 - -struct imon_context { - struct usb_device *usbdev; - /* Newer devices have two interfaces */ - int display; /* not all controllers do */ - int display_isopen; /* display port has been opened */ - int ir_isopen; /* IR port open */ - int dev_present; /* USB device presence */ - struct mutex ctx_lock; /* to lock this object */ - wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ - - int vfd_proto_6p; /* some VFD require a 6th packet */ - - struct lirc_driver *driver; - struct usb_endpoint_descriptor *rx_endpoint; - struct usb_endpoint_descriptor *tx_endpoint; - struct urb *rx_urb; - struct urb *tx_urb; - unsigned char usb_rx_buf[8]; - unsigned char usb_tx_buf[8]; - - struct rx_data { - int count; /* length of 0 or 1 sequence */ - int prev_bit; /* logic level of sequence */ - int initial_space; /* initial space flag */ - } rx; - - struct tx_t { - unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */ - struct completion finished; /* wait for write to finish */ - atomic_t busy; /* write in progress */ - int status; /* status of tx completion */ - } tx; -}; - -static const struct file_operations display_fops = { - .owner = THIS_MODULE, - .open = &display_open, - .write = &vfd_write, - .release = &display_close, - .llseek = noop_llseek, -}; - -/* - * USB Device ID for iMON USB Control Boards - * - * The Windows drivers contain 6 different inf files, more or less one for - * each new device until the 0x0034-0x0046 devices, which all use the same - * driver. Some of the devices in the 34-46 range haven't been definitively - * identified yet. Early devices have either a TriGem Computer, Inc. or a - * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later - * devices use the SoundGraph vendor ID (0x15c2). - */ -static struct usb_device_id imon_usb_id_table[] = { - /* TriGem iMON (IR only) -- TG_iMON.inf */ - { USB_DEVICE(0x0aa8, 0x8001) }, - - /* SoundGraph iMON (IR only) -- sg_imon.inf */ - { USB_DEVICE(0x04e8, 0xff30) }, - - /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */ - { USB_DEVICE(0x0aa8, 0xffda) }, - - /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */ - { USB_DEVICE(0x15c2, 0xffda) }, - - {} -}; - -/* Some iMON VFD models requires a 6th packet for VFD writes */ -static struct usb_device_id vfd_proto_6p_list[] = { - { USB_DEVICE(0x15c2, 0xffda) }, - {} -}; - -/* Some iMON devices have no lcd/vfd, don't set one up */ -static struct usb_device_id ir_only_list[] = { - { USB_DEVICE(0x0aa8, 0x8001) }, - { USB_DEVICE(0x04e8, 0xff30) }, - {} -}; - -/* USB Device data */ -static struct usb_driver imon_driver = { - .name = MOD_NAME, - .probe = imon_probe, - .disconnect = imon_disconnect, - .suspend = imon_suspend, - .resume = imon_resume, - .id_table = imon_usb_id_table, -}; - -static struct usb_class_driver imon_class = { - .name = DEVICE_NAME, - .fops = &display_fops, - .minor_base = DISPLAY_MINOR_BASE, -}; - -/* to prevent races between open() and disconnect(), probing, etc */ -static DEFINE_MUTEX(driver_lock); - -static int debug; - -/*** M O D U L E C O D E ***/ - -MODULE_AUTHOR(MOD_AUTHOR); -MODULE_DESCRIPTION(MOD_DESC); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, imon_usb_id_table); -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)"); - -static void free_imon_context(struct imon_context *context) -{ - struct device *dev = context->driver->dev; - usb_free_urb(context->tx_urb); - usb_free_urb(context->rx_urb); - lirc_buffer_free(context->driver->rbuf); - kfree(context->driver->rbuf); - kfree(context->driver); - kfree(context); - - dev_dbg(dev, "%s: iMON context freed\n", __func__); -} - -static void deregister_from_lirc(struct imon_context *context) -{ - int retval; - int minor = context->driver->minor; - - retval = lirc_unregister_driver(minor); - if (retval) - err("%s: unable to deregister from lirc(%d)", - __func__, retval); - else - printk(KERN_INFO MOD_NAME ": Deregistered iMON driver " - "(minor:%d)\n", minor); - -} - -/** - * Called when the Display device (e.g. /dev/lcd0) - * is opened by the application. - */ -static int display_open(struct inode *inode, struct file *file) -{ - struct usb_interface *interface; - struct imon_context *context = NULL; - int subminor; - int retval = 0; - - /* prevent races with disconnect */ - mutex_lock(&driver_lock); - - subminor = iminor(inode); - interface = usb_find_interface(&imon_driver, subminor); - if (!interface) { - err("%s: could not find interface for minor %d", - __func__, subminor); - retval = -ENODEV; - goto exit; - } - context = usb_get_intfdata(interface); - - if (!context) { - err("%s: no context found for minor %d", - __func__, subminor); - retval = -ENODEV; - goto exit; - } - - mutex_lock(&context->ctx_lock); - - if (!context->display) { - err("%s: display not supported by device", __func__); - retval = -ENODEV; - } else if (context->display_isopen) { - err("%s: display port is already open", __func__); - retval = -EBUSY; - } else { - context->display_isopen = 1; - file->private_data = context; - dev_info(context->driver->dev, "display port opened\n"); - } - - mutex_unlock(&context->ctx_lock); - -exit: - mutex_unlock(&driver_lock); - return retval; -} - -/** - * Called when the display device (e.g. /dev/lcd0) - * is closed by the application. - */ -static int display_close(struct inode *inode, struct file *file) -{ - struct imon_context *context = NULL; - int retval = 0; - - context = file->private_data; - - if (!context) { - err("%s: no context for device", __func__); - return -ENODEV; - } - - mutex_lock(&context->ctx_lock); - - if (!context->display) { - err("%s: display not supported by device", __func__); - retval = -ENODEV; - } else if (!context->display_isopen) { - err("%s: display is not open", __func__); - retval = -EIO; - } else { - context->display_isopen = 0; - dev_info(context->driver->dev, "display port closed\n"); - if (!context->dev_present && !context->ir_isopen) { - /* - * Device disconnected before close and IR port is not - * open. If IR port is open, context will be deleted by - * ir_close. - */ - mutex_unlock(&context->ctx_lock); - free_imon_context(context); - return retval; - } - } - - mutex_unlock(&context->ctx_lock); - return retval; -} - -/** - * Sends a packet to the device -- this function must be called - * with context->ctx_lock held. - */ -static int send_packet(struct imon_context *context) -{ - unsigned int pipe; - int interval = 0; - int retval = 0; - - /* Check if we need to use control or interrupt urb */ - pipe = usb_sndintpipe(context->usbdev, - context->tx_endpoint->bEndpointAddress); - interval = context->tx_endpoint->bInterval; - - usb_fill_int_urb(context->tx_urb, context->usbdev, pipe, - context->usb_tx_buf, - sizeof(context->usb_tx_buf), - usb_tx_callback, context, interval); - - context->tx_urb->actual_length = 0; - - init_completion(&context->tx.finished); - atomic_set(&(context->tx.busy), 1); - - retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); - if (retval) { - atomic_set(&(context->tx.busy), 0); - err("%s: error submitting urb(%d)", __func__, retval); - } else { - /* Wait for transmission to complete (or abort) */ - mutex_unlock(&context->ctx_lock); - retval = wait_for_completion_interruptible( - &context->tx.finished); - if (retval) - err("%s: task interrupted", __func__); - mutex_lock(&context->ctx_lock); - - retval = context->tx.status; - if (retval) - err("%s: packet tx failed (%d)", __func__, retval); - } - - return retval; -} - -/** - * Writes data to the VFD. The iMON VFD is 2x16 characters - * and requires data in 5 consecutive USB interrupt packets, - * each packet but the last carrying 7 bytes. - * - * I don't know if the VFD board supports features such as - * scrolling, clearing rows, blanking, etc. so at - * the caller must provide a full screen of data. If fewer - * than 32 bytes are provided spaces will be appended to - * generate a full screen. - */ -static ssize_t vfd_write(struct file *file, const char *buf, - size_t n_bytes, loff_t *pos) -{ - int i; - int offset; - int seq; - int retval = 0; - struct imon_context *context; - const unsigned char vfd_packet6[] = { - 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; - int *data_buf = NULL; - - context = file->private_data; - if (!context) { - err("%s: no context for device", __func__); - return -ENODEV; - } - - mutex_lock(&context->ctx_lock); - - if (!context->dev_present) { - err("%s: no iMON device present", __func__); - retval = -ENODEV; - goto exit; - } - - if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) { - err("%s: invalid payload size", __func__); - retval = -EINVAL; - goto exit; - } - - data_buf = memdup_user(buf, n_bytes); - if (IS_ERR(data_buf)) { - retval = PTR_ERR(data_buf); - goto exit; - } - - memcpy(context->tx.data_buf, data_buf, n_bytes); - - /* Pad with spaces */ - for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i) - context->tx.data_buf[i] = ' '; - - for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i) - context->tx.data_buf[i] = 0xFF; - - offset = 0; - seq = 0; - - do { - memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7); - context->usb_tx_buf[7] = (unsigned char) seq; - - retval = send_packet(context); - if (retval) { - err("%s: send packet failed for packet #%d", - __func__, seq/2); - goto exit; - } else { - seq += 2; - offset += 7; - } - - } while (offset < IMON_DATA_BUF_SZ); - - if (context->vfd_proto_6p) { - /* Send packet #6 */ - memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); - context->usb_tx_buf[7] = (unsigned char) seq; - retval = send_packet(context); - if (retval) - err("%s: send packet failed for packet #%d", - __func__, seq/2); - } - -exit: - mutex_unlock(&context->ctx_lock); - kfree(data_buf); - - return (!retval) ? n_bytes : retval; -} - -/** - * Callback function for USB core API: transmit data - */ -static void usb_tx_callback(struct urb *urb) -{ - struct imon_context *context; - - if (!urb) - return; - context = (struct imon_context *)urb->context; - if (!context) - return; - - context->tx.status = urb->status; - - /* notify waiters that write has finished */ - atomic_set(&context->tx.busy, 0); - complete(&context->tx.finished); - - return; -} - -/** - * Called by lirc_dev when the application opens /dev/lirc - */ -static int ir_open(void *data) -{ - int retval = 0; - struct imon_context *context; - - /* prevent races with disconnect */ - mutex_lock(&driver_lock); - - context = (struct imon_context *)data; - - /* initial IR protocol decode variables */ - context->rx.count = 0; - context->rx.initial_space = 1; - context->rx.prev_bit = 0; - - context->ir_isopen = 1; - dev_info(context->driver->dev, "IR port opened\n"); - - mutex_unlock(&driver_lock); - return retval; -} - -/** - * Called by lirc_dev when the application closes /dev/lirc - */ -static void ir_close(void *data) -{ - struct imon_context *context; - - context = (struct imon_context *)data; - if (!context) { - err("%s: no context for device", __func__); - return; - } - - mutex_lock(&context->ctx_lock); - - context->ir_isopen = 0; - dev_info(context->driver->dev, "IR port closed\n"); - - if (!context->dev_present) { - /* - * Device disconnected while IR port was still open. Driver - * was not deregistered at disconnect time, so do it now. - */ - deregister_from_lirc(context); - - if (!context->display_isopen) { - mutex_unlock(&context->ctx_lock); - free_imon_context(context); - return; - } - /* - * If display port is open, context will be deleted by - * display_close - */ - } - - mutex_unlock(&context->ctx_lock); - return; -} - -/** - * Convert bit count to time duration (in us) and submit - * the value to lirc_dev. - */ -static void submit_data(struct imon_context *context) -{ - unsigned char buf[4]; - int value = context->rx.count; - int i; - - dev_dbg(context->driver->dev, "submitting data to LIRC\n"); - - value *= BIT_DURATION; - value &= PULSE_MASK; - if (context->rx.prev_bit) - value |= PULSE_BIT; - - for (i = 0; i < 4; ++i) - buf[i] = value>>(i*8); - - lirc_buffer_write(context->driver->rbuf, buf); - wake_up(&context->driver->rbuf->wait_poll); - return; -} - -static inline int tv2int(const struct timeval *a, const struct timeval *b) -{ - int usecs = 0; - int sec = 0; - - if (b->tv_usec > a->tv_usec) { - usecs = 1000000; - sec--; - } - - usecs += a->tv_usec - b->tv_usec; - - sec += a->tv_sec - b->tv_sec; - sec *= 1000; - usecs /= 1000; - sec += usecs; - - if (sec < 0) - sec = 1000; - - return sec; -} - -/** - * Process the incoming packet - */ -static void imon_incoming_packet(struct imon_context *context, - struct urb *urb, int intf) -{ - int len = urb->actual_length; - unsigned char *buf = urb->transfer_buffer; - struct device *dev = context->driver->dev; - int octet, bit; - unsigned char mask; - int i; - - /* - * just bail out if no listening IR client - */ - if (!context->ir_isopen) - return; - - if (len != 8) { - dev_warn(dev, "imon %s: invalid incoming packet " - "size (len = %d, intf%d)\n", __func__, len, intf); - return; - } - - if (debug) { - printk(KERN_INFO "raw packet: "); - for (i = 0; i < len; ++i) - printk("%02x ", buf[i]); - printk("\n"); - } - - /* - * Translate received data to pulse and space lengths. - * Received data is active low, i.e. pulses are 0 and - * spaces are 1. - * - * My original algorithm was essentially similar to - * Changwoo Ryu's with the exception that he switched - * the incoming bits to active high and also fed an - * initial space to LIRC at the start of a new sequence - * if the previous bit was a pulse. - * - * I've decided to adopt his algorithm. - */ - - if (buf[7] == 1 && context->rx.initial_space) { - /* LIRC requires a leading space */ - context->rx.prev_bit = 0; - context->rx.count = 4; - submit_data(context); - context->rx.count = 0; - } - - for (octet = 0; octet < 5; ++octet) { - mask = 0x80; - for (bit = 0; bit < 8; ++bit) { - int curr_bit = !(buf[octet] & mask); - if (curr_bit != context->rx.prev_bit) { - if (context->rx.count) { - submit_data(context); - context->rx.count = 0; - } - context->rx.prev_bit = curr_bit; - } - ++context->rx.count; - mask >>= 1; - } - } - - if (buf[7] == 10) { - if (context->rx.count) { - submit_data(context); - context->rx.count = 0; - } - context->rx.initial_space = context->rx.prev_bit; - } -} - -/** - * Callback function for USB core API: receive data - */ -static void usb_rx_callback(struct urb *urb) -{ - struct imon_context *context; - unsigned char *buf; - int len; - int intfnum = 0; - - if (!urb) - return; - - context = (struct imon_context *)urb->context; - if (!context) - return; - - buf = urb->transfer_buffer; - len = urb->actual_length; - - switch (urb->status) { - case -ENOENT: /* usbcore unlink successful! */ - return; - - case 0: - imon_incoming_packet(context, urb, intfnum); - break; - - default: - dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n", - __func__, urb->status); - break; - } - - usb_submit_urb(context->rx_urb, GFP_ATOMIC); - - return; -} - -/** - * Callback function for USB core API: Probe - */ -static int imon_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *usbdev = NULL; - struct usb_host_interface *iface_desc = NULL; - struct usb_endpoint_descriptor *rx_endpoint = NULL; - struct usb_endpoint_descriptor *tx_endpoint = NULL; - struct urb *rx_urb = NULL; - struct urb *tx_urb = NULL; - struct lirc_driver *driver = NULL; - struct lirc_buffer *rbuf = NULL; - struct device *dev = &interface->dev; - int ifnum; - int lirc_minor = 0; - int num_endpts; - int retval = 0; - int display_ep_found = 0; - int ir_ep_found = 0; - int alloc_status = 0; - int vfd_proto_6p = 0; - int code_length; - struct imon_context *context = NULL; - int i; - u16 vendor, product; - - context = kzalloc(sizeof(struct imon_context), GFP_KERNEL); - if (!context) { - err("%s: kzalloc failed for context", __func__); - alloc_status = 1; - goto alloc_status_switch; - } - - /* - * Try to auto-detect the type of display if the user hasn't set - * it by hand via the display_type modparam. Default is VFD. - */ - if (usb_match_id(interface, ir_only_list)) - context->display = 0; - else - context->display = 1; - - code_length = BUF_CHUNK_SIZE * 8; - - usbdev = usb_get_dev(interface_to_usbdev(interface)); - iface_desc = interface->cur_altsetting; - num_endpts = iface_desc->desc.bNumEndpoints; - ifnum = iface_desc->desc.bInterfaceNumber; - vendor = le16_to_cpu(usbdev->descriptor.idVendor); - product = le16_to_cpu(usbdev->descriptor.idProduct); - - dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", - __func__, vendor, product, ifnum); - - /* prevent races probing devices w/multiple interfaces */ - mutex_lock(&driver_lock); - - /* - * Scan the endpoint list and set: - * first input endpoint = IR endpoint - * first output endpoint = display endpoint - */ - for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { - struct usb_endpoint_descriptor *ep; - int ep_dir; - int ep_type; - ep = &iface_desc->endpoint[i].desc; - ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; - ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - - if (!ir_ep_found && - ep_dir == USB_DIR_IN && - ep_type == USB_ENDPOINT_XFER_INT) { - - rx_endpoint = ep; - ir_ep_found = 1; - dev_dbg(dev, "%s: found IR endpoint\n", __func__); - - } else if (!display_ep_found && ep_dir == USB_DIR_OUT && - ep_type == USB_ENDPOINT_XFER_INT) { - tx_endpoint = ep; - display_ep_found = 1; - dev_dbg(dev, "%s: found display endpoint\n", __func__); - } - } - - /* - * Some iMON receivers have no display. Unfortunately, it seems - * that SoundGraph recycles device IDs between devices both with - * and without... :\ - */ - if (context->display == 0) { - display_ep_found = 0; - dev_dbg(dev, "%s: device has no display\n", __func__); - } - - /* Input endpoint is mandatory */ - if (!ir_ep_found) { - err("%s: no valid input (IR) endpoint found.", __func__); - retval = -ENODEV; - alloc_status = 2; - goto alloc_status_switch; - } - - /* Determine if display requires 6 packets */ - if (display_ep_found) { - if (usb_match_id(interface, vfd_proto_6p_list)) - vfd_proto_6p = 1; - - dev_dbg(dev, "%s: vfd_proto_6p: %d\n", - __func__, vfd_proto_6p); - } - - driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); - if (!driver) { - err("%s: kzalloc failed for lirc_driver", __func__); - alloc_status = 2; - goto alloc_status_switch; - } - rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); - if (!rbuf) { - err("%s: kmalloc failed for lirc_buffer", __func__); - alloc_status = 3; - goto alloc_status_switch; - } - if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { - err("%s: lirc_buffer_init failed", __func__); - alloc_status = 4; - goto alloc_status_switch; - } - rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rx_urb) { - err("%s: usb_alloc_urb failed for IR urb", __func__); - alloc_status = 5; - goto alloc_status_switch; - } - tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!tx_urb) { - err("%s: usb_alloc_urb failed for display urb", - __func__); - alloc_status = 6; - goto alloc_status_switch; - } - - mutex_init(&context->ctx_lock); - context->vfd_proto_6p = vfd_proto_6p; - - strcpy(driver->name, MOD_NAME); - driver->minor = -1; - driver->code_length = sizeof(int) * 8; - driver->sample_rate = 0; - driver->features = LIRC_CAN_REC_MODE2; - driver->data = context; - driver->rbuf = rbuf; - driver->set_use_inc = ir_open; - driver->set_use_dec = ir_close; - driver->dev = &interface->dev; - driver->owner = THIS_MODULE; - - mutex_lock(&context->ctx_lock); - - context->driver = driver; - /* start out in keyboard mode */ - - lirc_minor = lirc_register_driver(driver); - if (lirc_minor < 0) { - err("%s: lirc_register_driver failed", __func__); - alloc_status = 7; - goto unlock; - } else - dev_info(dev, "Registered iMON driver " - "(lirc minor: %d)\n", lirc_minor); - - /* Needed while unregistering! */ - driver->minor = lirc_minor; - - context->usbdev = usbdev; - context->dev_present = 1; - context->rx_endpoint = rx_endpoint; - context->rx_urb = rx_urb; - - /* - * tx is used to send characters to lcd/vfd, associate RF - * remotes, set IR protocol, and maybe more... - */ - context->tx_endpoint = tx_endpoint; - context->tx_urb = tx_urb; - - if (display_ep_found) - context->display = 1; - - usb_fill_int_urb(context->rx_urb, context->usbdev, - usb_rcvintpipe(context->usbdev, - context->rx_endpoint->bEndpointAddress), - context->usb_rx_buf, sizeof(context->usb_rx_buf), - usb_rx_callback, context, - context->rx_endpoint->bInterval); - - retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); - - if (retval) { - err("%s: usb_submit_urb failed for intf0 (%d)", - __func__, retval); - mutex_unlock(&context->ctx_lock); - goto exit; - } - - usb_set_intfdata(interface, context); - - if (context->display && ifnum == 0) { - dev_dbg(dev, "%s: Registering iMON display with sysfs\n", - __func__); - - if (usb_register_dev(interface, &imon_class)) { - /* Not a fatal error, so ignore */ - dev_info(dev, "%s: could not get a minor number for " - "display\n", __func__); - } - } - - dev_info(dev, "iMON device (%04x:%04x, intf%d) on " - "usb<%d:%d> initialized\n", vendor, product, ifnum, - usbdev->bus->busnum, usbdev->devnum); - -unlock: - mutex_unlock(&context->ctx_lock); -alloc_status_switch: - - switch (alloc_status) { - case 7: - usb_free_urb(tx_urb); - case 6: - usb_free_urb(rx_urb); - case 5: - if (rbuf) - lirc_buffer_free(rbuf); - case 4: - kfree(rbuf); - case 3: - kfree(driver); - case 2: - kfree(context); - context = NULL; - case 1: - if (retval != -ENODEV) - retval = -ENOMEM; - break; - case 0: - retval = 0; - } - -exit: - mutex_unlock(&driver_lock); - - return retval; -} - -/** - * Callback function for USB core API: disconnect - */ -static void imon_disconnect(struct usb_interface *interface) -{ - struct imon_context *context; - int ifnum; - - /* prevent races with ir_open()/display_open() */ - mutex_lock(&driver_lock); - - context = usb_get_intfdata(interface); - ifnum = interface->cur_altsetting->desc.bInterfaceNumber; - - mutex_lock(&context->ctx_lock); - - usb_set_intfdata(interface, NULL); - - /* Abort ongoing write */ - if (atomic_read(&context->tx.busy)) { - usb_kill_urb(context->tx_urb); - complete_all(&context->tx.finished); - } - - context->dev_present = 0; - usb_kill_urb(context->rx_urb); - if (context->display) - usb_deregister_dev(interface, &imon_class); - - if (!context->ir_isopen && !context->dev_present) { - deregister_from_lirc(context); - mutex_unlock(&context->ctx_lock); - if (!context->display_isopen) - free_imon_context(context); - } else - mutex_unlock(&context->ctx_lock); - - mutex_unlock(&driver_lock); - - printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n", - __func__, ifnum); -} - -static int imon_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct imon_context *context = usb_get_intfdata(intf); - - usb_kill_urb(context->rx_urb); - - return 0; -} - -static int imon_resume(struct usb_interface *intf) -{ - int rc = 0; - struct imon_context *context = usb_get_intfdata(intf); - - usb_fill_int_urb(context->rx_urb, context->usbdev, - usb_rcvintpipe(context->usbdev, - context->rx_endpoint->bEndpointAddress), - context->usb_rx_buf, sizeof(context->usb_rx_buf), - usb_rx_callback, context, - context->rx_endpoint->bInterval); - - rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC); - - return rc; -} - -static int __init imon_init(void) -{ - int rc; - - printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n"); - - rc = usb_register(&imon_driver); - if (rc) { - err("%s: usb register failed(%d)", __func__, rc); - return -ENODEV; - } - - return 0; -} - -static void __exit imon_exit(void) -{ - usb_deregister(&imon_driver); - printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n"); -} - -module_init(imon_init); -module_exit(imon_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_it87.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_it87.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_it87.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_it87.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1027 +0,0 @@ -/* - * LIRC driver for ITE IT8712/IT8705 CIR port - * - * Copyright (C) 2001 Hans-Gunter Lutke Uphues - * - * 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, or (at your option) any later version. - * - * 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 - * - * ITE IT8705 and IT8712(not tested) and IT8720 CIR-port support for lirc based - * via cut and paste from lirc_sir.c (C) 2000 Milan Pikula - * - * Attention: Sendmode only tested with debugging logs - * - * 2001/02/27 Christoph Bartelmus : - * reimplemented read function - * 2005/06/05 Andrew Calkin implemented support for Asus Digimatrix, - * based on work of the following member of the Outertrack Digimatrix - * Forum: Art103 - * 2009/12/24 James Edwards implemeted support - * for ITE8704/ITE8718, on my machine, the DSDT reports 8704, but the - * chip identifies as 18. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "lirc_it87.h" - -#ifdef LIRC_IT87_DIGIMATRIX -static int digimatrix = 1; -static int it87_freq = 36; /* kHz */ -static int irq = 9; -#else -static int digimatrix; -static int it87_freq = 38; /* kHz */ -static int irq = IT87_CIR_DEFAULT_IRQ; -#endif - -static unsigned long it87_bits_in_byte_out; -static unsigned long it87_send_counter; -static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN; - -#define RBUF_LEN 1024 - -#define LIRC_DRIVER_NAME "lirc_it87" - -/* timeout for sequences in jiffies (=5/100s) */ -/* must be longer than TIME_CONST */ -#define IT87_TIMEOUT (HZ*5/100) - -/* module parameters */ -static int debug; -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ - fmt, ## args); \ - } while (0) - -static int io = IT87_CIR_DEFAULT_IOBASE; -/* receiver demodulator default: off */ -static int it87_enable_demodulator; - -static int timer_enabled; -static DEFINE_SPINLOCK(timer_lock); -static struct timer_list timerlist; -/* time of last signal change detected */ -static struct timeval last_tv = {0, 0}; -/* time of last UART data ready interrupt */ -static struct timeval last_intr_tv = {0, 0}; -static int last_value; - -static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); - -static DEFINE_SPINLOCK(hardware_lock); -static DEFINE_SPINLOCK(dev_lock); -static bool device_open; - -static int rx_buf[RBUF_LEN]; -unsigned int rx_tail, rx_head; - -static struct pnp_driver it87_pnp_driver; - -/* SECTION: Prototypes */ - -/* Communication with user-space */ -static int lirc_open(struct inode *inode, struct file *file); -static int lirc_close(struct inode *inode, struct file *file); -static unsigned int lirc_poll(struct file *file, poll_table *wait); -static ssize_t lirc_read(struct file *file, char *buf, - size_t count, loff_t *ppos); -static ssize_t lirc_write(struct file *file, const char *buf, - size_t n, loff_t *pos); -static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); -static void add_read_queue(int flag, unsigned long val); -static int init_chrdev(void); -static void drop_chrdev(void); -/* Hardware */ -static irqreturn_t it87_interrupt(int irq, void *dev_id); -static void send_space(unsigned long len); -static void send_pulse(unsigned long len); -static void init_send(void); -static void terminate_send(unsigned long len); -static int init_hardware(void); -static void drop_hardware(void); -/* Initialisation */ -static int init_port(void); -static void drop_port(void); - - -/* SECTION: Communication with user-space */ - -static int lirc_open(struct inode *inode, struct file *file) -{ - spin_lock(&dev_lock); - if (device_open) { - spin_unlock(&dev_lock); - return -EBUSY; - } - device_open = true; - spin_unlock(&dev_lock); - return 0; -} - - -static int lirc_close(struct inode *inode, struct file *file) -{ - spin_lock(&dev_lock); - device_open = false; - spin_unlock(&dev_lock); - return 0; -} - - -static unsigned int lirc_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &lirc_read_queue, wait); - if (rx_head != rx_tail) - return POLLIN | POLLRDNORM; - return 0; -} - - -static ssize_t lirc_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - int n = 0; - int retval = 0; - - while (n < count) { - if (file->f_flags & O_NONBLOCK && rx_head == rx_tail) { - retval = -EAGAIN; - break; - } - retval = wait_event_interruptible(lirc_read_queue, - rx_head != rx_tail); - if (retval) - break; - - if (copy_to_user((void *) buf + n, (void *) (rx_buf + rx_head), - sizeof(int))) { - retval = -EFAULT; - break; - } - rx_head = (rx_head + 1) & (RBUF_LEN - 1); - n += sizeof(int); - } - if (n) - return n; - return retval; -} - - -static ssize_t lirc_write(struct file *file, const char *buf, - size_t n, loff_t *pos) -{ - int i = 0; - int *tx_buf; - - if (n % sizeof(int)) - return -EINVAL; - tx_buf = memdup_user(buf, n); - if (IS_ERR(tx_buf)) - return PTR_ERR(tx_buf); - n /= sizeof(int); - init_send(); - while (1) { - if (i >= n) - break; - if (tx_buf[i]) - send_pulse(tx_buf[i]); - i++; - if (i >= n) - break; - if (tx_buf[i]) - send_space(tx_buf[i]); - i++; - } - terminate_send(tx_buf[i - 1]); - kfree(tx_buf); - return n; -} - - -static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - int retval = 0; - __u32 value = 0; - unsigned long hw_flags; - - if (cmd == LIRC_GET_FEATURES) - value = LIRC_CAN_SEND_PULSE | - LIRC_CAN_SET_SEND_CARRIER | - LIRC_CAN_REC_MODE2; - else if (cmd == LIRC_GET_SEND_MODE) - value = LIRC_MODE_PULSE; - else if (cmd == LIRC_GET_REC_MODE) - value = LIRC_MODE_MODE2; - - switch (cmd) { - case LIRC_GET_FEATURES: - case LIRC_GET_SEND_MODE: - case LIRC_GET_REC_MODE: - retval = put_user(value, (__u32 *) arg); - break; - - case LIRC_SET_SEND_MODE: - case LIRC_SET_REC_MODE: - retval = get_user(value, (__u32 *) arg); - break; - - case LIRC_SET_SEND_CARRIER: - retval = get_user(value, (__u32 *) arg); - if (retval) - return retval; - value /= 1000; - if (value > IT87_CIR_FREQ_MAX || - value < IT87_CIR_FREQ_MIN) - return -EINVAL; - - it87_freq = value; - - spin_lock_irqsave(&hardware_lock, hw_flags); - outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) | - (it87_freq - IT87_CIR_FREQ_MIN) << 3), - io + IT87_CIR_TCR2); - spin_unlock_irqrestore(&hardware_lock, hw_flags); - dprintk("demodulation frequency: %d kHz\n", it87_freq); - - break; - - default: - retval = -EINVAL; - } - - if (retval) - return retval; - - if (cmd == LIRC_SET_REC_MODE) { - if (value != LIRC_MODE_MODE2) - retval = -ENOSYS; - } else if (cmd == LIRC_SET_SEND_MODE) { - if (value != LIRC_MODE_PULSE) - retval = -ENOSYS; - } - return retval; -} - -static void add_read_queue(int flag, unsigned long val) -{ - unsigned int new_rx_tail; - int newval; - - dprintk("add flag %d with val %lu\n", flag, val); - - newval = val & PULSE_MASK; - - /* - * statistically, pulses are ~TIME_CONST/2 too long. we could - * maybe make this more exact, but this is good enough - */ - if (flag) { - /* pulse */ - if (newval > TIME_CONST / 2) - newval -= TIME_CONST / 2; - else /* should not ever happen */ - newval = 1; - newval |= PULSE_BIT; - } else - newval += TIME_CONST / 2; - new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); - if (new_rx_tail == rx_head) { - dprintk("Buffer overrun.\n"); - return; - } - rx_buf[rx_tail] = newval; - rx_tail = new_rx_tail; - wake_up_interruptible(&lirc_read_queue); -} - - -static const struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .read = lirc_read, - .write = lirc_write, - .poll = lirc_poll, - .unlocked_ioctl = lirc_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = lirc_ioctl, -#endif - .open = lirc_open, - .release = lirc_close, - .llseek = noop_llseek, -}; - -static int set_use_inc(void *data) -{ - return 0; -} - -static void set_use_dec(void *data) -{ -} - -static struct lirc_driver driver = { - .name = LIRC_DRIVER_NAME, - .minor = -1, - .code_length = 1, - .sample_rate = 0, - .data = NULL, - .add_to_buf = NULL, - .set_use_inc = set_use_inc, - .set_use_dec = set_use_dec, - .fops = &lirc_fops, - .dev = NULL, - .owner = THIS_MODULE, -}; - - -static int init_chrdev(void) -{ - driver.minor = lirc_register_driver(&driver); - - if (driver.minor < 0) { - printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); - return -EIO; - } - return 0; -} - - -static void drop_chrdev(void) -{ - lirc_unregister_driver(driver.minor); -} - - -/* SECTION: Hardware */ -static long delta(struct timeval *tv1, struct timeval *tv2) -{ - unsigned long deltv; - - deltv = tv2->tv_sec - tv1->tv_sec; - if (deltv > 15) - deltv = 0xFFFFFF; - else - deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec; - return deltv; -} - -static void it87_timeout(unsigned long data) -{ - unsigned long flags; - - /* avoid interference with interrupt */ - spin_lock_irqsave(&timer_lock, flags); - - if (digimatrix) { - /* We have timed out. Disable the RX mechanism. */ - - outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) | - IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR); - if (it87_RXEN_mask) - outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, - io + IT87_CIR_RCR); - dprintk(" TIMEOUT\n"); - timer_enabled = 0; - - /* fifo clear */ - outb(inb(io + IT87_CIR_TCR1) | IT87_CIR_TCR1_FIFOCLR, - io+IT87_CIR_TCR1); - - } else { - /* - * if last received signal was a pulse, but receiving stopped - * within the 9 bit frame, we need to finish this pulse and - * simulate a signal change to from pulse to space. Otherwise - * upper layers will receive two sequences next time. - */ - - if (last_value) { - unsigned long pulse_end; - - /* determine 'virtual' pulse end: */ - pulse_end = delta(&last_tv, &last_intr_tv); - dprintk("timeout add %d for %lu usec\n", - last_value, pulse_end); - add_read_queue(last_value, pulse_end); - last_value = 0; - last_tv = last_intr_tv; - } - } - spin_unlock_irqrestore(&timer_lock, flags); -} - -static irqreturn_t it87_interrupt(int irq, void *dev_id) -{ - unsigned char data; - struct timeval curr_tv; - static unsigned long deltv; - unsigned long deltintrtv; - unsigned long flags, hw_flags; - int iir, lsr; - int fifo = 0; - static char lastbit; - char bit; - - /* Bit duration in microseconds */ - const unsigned long bit_duration = 1000000ul / - (115200 / IT87_CIR_BAUDRATE_DIVISOR); - - - iir = inb(io + IT87_CIR_IIR); - - switch (iir & IT87_CIR_IIR_IID) { - case 0x4: - case 0x6: - lsr = inb(io + IT87_CIR_RSR) & (IT87_CIR_RSR_RXFTO | - IT87_CIR_RSR_RXFBC); - fifo = lsr & IT87_CIR_RSR_RXFBC; - dprintk("iir: 0x%x fifo: 0x%x\n", iir, lsr); - - /* avoid interference with timer */ - spin_lock_irqsave(&timer_lock, flags); - spin_lock_irqsave(&hardware_lock, hw_flags); - if (digimatrix) { - static unsigned long acc_pulse; - static unsigned long acc_space; - - do { - data = inb(io + IT87_CIR_DR); - data = ~data; - fifo--; - if (data != 0x00) { - if (timer_enabled) - del_timer(&timerlist); - /* - * start timer for end of - * sequence detection - */ - timerlist.expires = jiffies + - IT87_TIMEOUT; - add_timer(&timerlist); - timer_enabled = 1; - } - /* Loop through */ - for (bit = 0; bit < 8; ++bit) { - if ((data >> bit) & 1) { - ++acc_pulse; - if (lastbit == 0) { - add_read_queue(0, - acc_space * - bit_duration); - acc_space = 0; - } - } else { - ++acc_space; - if (lastbit == 1) { - add_read_queue(1, - acc_pulse * - bit_duration); - acc_pulse = 0; - } - } - lastbit = (data >> bit) & 1; - } - - } while (fifo != 0); - } else { /* Normal Operation */ - do { - del_timer(&timerlist); - data = inb(io + IT87_CIR_DR); - - dprintk("data=%02x\n", data); - do_gettimeofday(&curr_tv); - deltv = delta(&last_tv, &curr_tv); - deltintrtv = delta(&last_intr_tv, &curr_tv); - - dprintk("t %lu , d %d\n", - deltintrtv, (int)data); - - /* - * if nothing came in last 2 cycles, - * it was gap - */ - if (deltintrtv > TIME_CONST * 2) { - if (last_value) { - dprintk("GAP\n"); - - /* simulate signal change */ - add_read_queue(last_value, - deltv - - deltintrtv); - last_value = 0; - last_tv.tv_sec = - last_intr_tv.tv_sec; - last_tv.tv_usec = - last_intr_tv.tv_usec; - deltv = deltintrtv; - } - } - data = 1; - if (data ^ last_value) { - /* - * deltintrtv > 2*TIME_CONST, - * remember ? the other case is - * timeout - */ - add_read_queue(last_value, - deltv-TIME_CONST); - last_value = data; - last_tv = curr_tv; - if (last_tv.tv_usec >= TIME_CONST) - last_tv.tv_usec -= TIME_CONST; - else { - last_tv.tv_sec--; - last_tv.tv_usec += 1000000 - - TIME_CONST; - } - } - last_intr_tv = curr_tv; - if (data) { - /* - * start timer for end of - * sequence detection - */ - timerlist.expires = - jiffies + IT87_TIMEOUT; - add_timer(&timerlist); - } - outb((inb(io + IT87_CIR_RCR) & - ~IT87_CIR_RCR_RXEN) | - IT87_CIR_RCR_RXACT, - io + IT87_CIR_RCR); - if (it87_RXEN_mask) - outb(inb(io + IT87_CIR_RCR) | - IT87_CIR_RCR_RXEN, - io + IT87_CIR_RCR); - fifo--; - } while (fifo != 0); - } - spin_unlock_irqrestore(&hardware_lock, hw_flags); - spin_unlock_irqrestore(&timer_lock, flags); - - return IRQ_RETVAL(IRQ_HANDLED); - - default: - /* not our irq */ - dprintk("unknown IRQ (shouldn't happen) !!\n"); - return IRQ_RETVAL(IRQ_NONE); - } -} - - -static void send_it87(unsigned long len, unsigned long stime, - unsigned char send_byte, unsigned int count_bits) -{ - long count = len / stime; - long time_left = 0; - static unsigned char byte_out; - unsigned long hw_flags; - - dprintk("%s: len=%ld, sb=%d\n", __func__, len, send_byte); - - time_left = (long)len - (long)count * (long)stime; - count += ((2 * time_left) / stime); - while (count) { - long i = 0; - for (i = 0; i < count_bits; i++) { - byte_out = (byte_out << 1) | (send_byte & 1); - it87_bits_in_byte_out++; - } - if (it87_bits_in_byte_out == 8) { - dprintk("out=0x%x, tsr_txfbc: 0x%x\n", - byte_out, - inb(io + IT87_CIR_TSR) & - IT87_CIR_TSR_TXFBC); - - while ((inb(io + IT87_CIR_TSR) & - IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE) - ; - - spin_lock_irqsave(&hardware_lock, hw_flags); - outb(byte_out, io + IT87_CIR_DR); - spin_unlock_irqrestore(&hardware_lock, hw_flags); - - it87_bits_in_byte_out = 0; - it87_send_counter++; - byte_out = 0; - } - count--; - } -} - - -/*TODO: maybe exchange space and pulse because it8705 only modulates 0-bits */ - -static void send_space(unsigned long len) -{ - send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR); -} - -static void send_pulse(unsigned long len) -{ - send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR); -} - - -static void init_send() -{ - unsigned long flags; - - spin_lock_irqsave(&hardware_lock, flags); - /* RXEN=0: receiver disable */ - it87_RXEN_mask = 0; - outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN, - io + IT87_CIR_RCR); - spin_unlock_irqrestore(&hardware_lock, flags); - it87_bits_in_byte_out = 0; - it87_send_counter = 0; -} - - -static void terminate_send(unsigned long len) -{ - unsigned long flags; - unsigned long last = 0; - - last = it87_send_counter; - /* make sure all necessary data has been sent */ - while (last == it87_send_counter) - send_space(len); - /* wait until all data sent */ - while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0) - ; - /* then re-enable receiver */ - spin_lock_irqsave(&hardware_lock, flags); - it87_RXEN_mask = IT87_CIR_RCR_RXEN; - outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, - io + IT87_CIR_RCR); - spin_unlock_irqrestore(&hardware_lock, flags); -} - - -static int init_hardware(void) -{ - unsigned long flags; - unsigned char it87_rcr = 0; - - spin_lock_irqsave(&hardware_lock, flags); - /* init cir-port */ - /* enable r/w-access to Baudrate-Register */ - outb(IT87_CIR_IER_BR, io + IT87_CIR_IER); - outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR); - outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR); - /* Baudrate Register off, define IRQs: Input only */ - if (digimatrix) { - outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RFOIE, io + IT87_CIR_IER); - /* RX: HCFS=0, RXDCR = 001b (33,75..38,25 kHz), RXEN=1 */ - } else { - outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER); - /* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */ - } - it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1; - if (it87_enable_demodulator) - it87_rcr |= IT87_CIR_RCR_RXEND; - outb(it87_rcr, io + IT87_CIR_RCR); - if (digimatrix) { - /* Set FIFO depth to 1 byte, and disable TX */ - outb(inb(io + IT87_CIR_TCR1) | 0x00, - io + IT87_CIR_TCR1); - - /* - * TX: it87_freq (36kHz), 'reserved' sensitivity - * setting (0x00) - */ - outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x00, - io + IT87_CIR_TCR2); - } else { - /* TX: 38kHz, 13,3us (pulse-width) */ - outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06, - io + IT87_CIR_TCR2); - } - spin_unlock_irqrestore(&hardware_lock, flags); - return 0; -} - - -static void drop_hardware(void) -{ - unsigned long flags; - - spin_lock_irqsave(&hardware_lock, flags); - disable_irq(irq); - /* receiver disable */ - it87_RXEN_mask = 0; - outb(0x1, io + IT87_CIR_RCR); - /* turn off irqs */ - outb(0, io + IT87_CIR_IER); - /* fifo clear */ - outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1); - /* reset */ - outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); - enable_irq(irq); - spin_unlock_irqrestore(&hardware_lock, flags); -} - - -static unsigned char it87_read(unsigned char port) -{ - outb(port, IT87_ADRPORT); - return inb(IT87_DATAPORT); -} - - -static void it87_write(unsigned char port, unsigned char data) -{ - outb(port, IT87_ADRPORT); - outb(data, IT87_DATAPORT); -} - - -/* SECTION: Initialisation */ - -static int init_port(void) -{ - unsigned long hw_flags; - int retval = 0; - - unsigned char init_bytes[4] = IT87_INIT; - unsigned char it87_chipid = 0; - unsigned char ldn = 0; - unsigned int it87_io = 0; - unsigned int it87_irq = 0; - - /* Enter MB PnP Mode */ - outb(init_bytes[0], IT87_ADRPORT); - outb(init_bytes[1], IT87_ADRPORT); - outb(init_bytes[2], IT87_ADRPORT); - outb(init_bytes[3], IT87_ADRPORT); - - /* 8712 or 8705 ? */ - it87_chipid = it87_read(IT87_CHIP_ID1); - if (it87_chipid != 0x87) { - retval = -ENXIO; - return retval; - } - it87_chipid = it87_read(IT87_CHIP_ID2); - if ((it87_chipid != 0x05) && - (it87_chipid != 0x12) && - (it87_chipid != 0x18) && - (it87_chipid != 0x20)) { - printk(KERN_INFO LIRC_DRIVER_NAME - ": no IT8704/05/12/18/20 found (claimed IT87%02x), " - "exiting..\n", it87_chipid); - retval = -ENXIO; - return retval; - } - printk(KERN_INFO LIRC_DRIVER_NAME - ": found IT87%02x.\n", - it87_chipid); - - /* get I/O-Port and IRQ */ - if (it87_chipid == 0x12 || it87_chipid == 0x18) - ldn = IT8712_CIR_LDN; - else - ldn = IT8705_CIR_LDN; - it87_write(IT87_LDN, ldn); - - it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 + - it87_read(IT87_CIR_BASE_LSB); - if (it87_io == 0) { - if (io == 0) - io = IT87_CIR_DEFAULT_IOBASE; - printk(KERN_INFO LIRC_DRIVER_NAME - ": set default io 0x%x\n", - io); - it87_write(IT87_CIR_BASE_MSB, io / 0x100); - it87_write(IT87_CIR_BASE_LSB, io % 0x100); - } else - io = it87_io; - - it87_irq = it87_read(IT87_CIR_IRQ); - if (digimatrix || it87_irq == 0) { - if (irq == 0) - irq = IT87_CIR_DEFAULT_IRQ; - printk(KERN_INFO LIRC_DRIVER_NAME - ": set default irq 0x%x\n", - irq); - it87_write(IT87_CIR_IRQ, irq); - } else - irq = it87_irq; - - spin_lock_irqsave(&hardware_lock, hw_flags); - /* reset */ - outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); - /* fifo clear */ - outb(IT87_CIR_TCR1_FIFOCLR | - /* IT87_CIR_TCR1_ILE | */ - IT87_CIR_TCR1_TXRLE | - IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1); - spin_unlock_irqrestore(&hardware_lock, hw_flags); - - /* get I/O port access and IRQ line */ - if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { - printk(KERN_ERR LIRC_DRIVER_NAME - ": i/o port 0x%.4x already in use.\n", io); - /* Leaving MB PnP Mode */ - it87_write(IT87_CFGCTRL, 0x2); - return -EBUSY; - } - - /* activate CIR-Device */ - it87_write(IT87_CIR_ACT, 0x1); - - /* Leaving MB PnP Mode */ - it87_write(IT87_CFGCTRL, 0x2); - - retval = request_irq(irq, it87_interrupt, 0 /*IRQF_DISABLED*/, - LIRC_DRIVER_NAME, NULL); - if (retval < 0) { - printk(KERN_ERR LIRC_DRIVER_NAME - ": IRQ %d already in use.\n", - irq); - release_region(io, 8); - return retval; - } - - printk(KERN_INFO LIRC_DRIVER_NAME - ": I/O port 0x%.4x, IRQ %d.\n", io, irq); - - init_timer(&timerlist); - timerlist.function = it87_timeout; - timerlist.data = 0xabadcafe; - - return 0; -} - - -static void drop_port(void) -{ -#if 0 - unsigned char init_bytes[4] = IT87_INIT; - - /* Enter MB PnP Mode */ - outb(init_bytes[0], IT87_ADRPORT); - outb(init_bytes[1], IT87_ADRPORT); - outb(init_bytes[2], IT87_ADRPORT); - outb(init_bytes[3], IT87_ADRPORT); - - /* deactivate CIR-Device */ - it87_write(IT87_CIR_ACT, 0x0); - - /* Leaving MB PnP Mode */ - it87_write(IT87_CFGCTRL, 0x2); -#endif - - del_timer_sync(&timerlist); - free_irq(irq, NULL); - release_region(io, 8); -} - - -static int init_lirc_it87(void) -{ - int retval; - - init_waitqueue_head(&lirc_read_queue); - retval = init_port(); - if (retval < 0) - return retval; - init_hardware(); - printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n"); - return 0; -} - -static int it87_probe(struct pnp_dev *pnp_dev, - const struct pnp_device_id *dev_id) -{ - int retval; - - driver.dev = &pnp_dev->dev; - - retval = init_chrdev(); - if (retval < 0) - return retval; - - retval = init_lirc_it87(); - if (retval) - goto init_lirc_it87_failed; - - return 0; - -init_lirc_it87_failed: - drop_chrdev(); - - return retval; -} - -static int __init lirc_it87_init(void) -{ - return pnp_register_driver(&it87_pnp_driver); -} - - -static void __exit lirc_it87_exit(void) -{ - drop_hardware(); - drop_chrdev(); - drop_port(); - pnp_unregister_driver(&it87_pnp_driver); - printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); -} - -/* SECTION: PNP for ITE8704/13/18 */ - -static const struct pnp_device_id pnp_dev_table[] = { - {"ITE8704", 0}, - {"ITE8713", 0}, - {} -}; - -MODULE_DEVICE_TABLE(pnp, pnp_dev_table); - -static struct pnp_driver it87_pnp_driver = { - .name = LIRC_DRIVER_NAME, - .id_table = pnp_dev_table, - .probe = it87_probe, -}; - -module_init(lirc_it87_init); -module_exit(lirc_it87_exit); - -MODULE_DESCRIPTION("LIRC driver for ITE IT8704/05/12/18/20 CIR port"); -MODULE_AUTHOR("Hans-Gunter Lutke Uphues"); -MODULE_LICENSE("GPL"); - -module_param(io, int, S_IRUGO); -MODULE_PARM_DESC(io, "I/O base address (default: 0x310)"); - -module_param(irq, int, S_IRUGO); -#ifdef LIRC_IT87_DIGIMATRIX -MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 9)"); -#else -MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)"); -#endif - -module_param(it87_enable_demodulator, bool, S_IRUGO); -MODULE_PARM_DESC(it87_enable_demodulator, - "Receiver demodulator enable/disable (1/0), default: 0"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); - -module_param(digimatrix, bool, S_IRUGO | S_IWUSR); -#ifdef LIRC_IT87_DIGIMATRIX -MODULE_PARM_DESC(digimatrix, - "Asus Digimatrix it87 compat. enable/disable (1/0), default: 1"); -#else -MODULE_PARM_DESC(digimatrix, - "Asus Digimatrix it87 compat. enable/disable (1/0), default: 0"); -#endif - - -module_param(it87_freq, int, S_IRUGO); -#ifdef LIRC_IT87_DIGIMATRIX -MODULE_PARM_DESC(it87_freq, - "Carrier demodulator frequency (kHz), (default: 36)"); -#else -MODULE_PARM_DESC(it87_freq, - "Carrier demodulator frequency (kHz), (default: 38)"); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_it87.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_it87.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_it87.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_it87.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -/* lirc_it87.h */ -/* SECTION: Definitions */ - -/********************************* ITE IT87xx ************************/ - -/* based on the following documentation from ITE: - a) IT8712F Preliminary CIR Programming Guide V0.1 - b) IT8705F Simple LPC I/O Preliminary Specification V0.3 - c) IT8712F EC-LPC I/O Preliminary Specification V0.5 -*/ - -/* IT8712/05 Ports: */ -#define IT87_ADRPORT 0x2e -#define IT87_DATAPORT 0x2f -#define IT87_INIT {0x87, 0x01, 0x55, 0x55} - -/* alternate Ports: */ -/* -#define IT87_ADRPORT 0x4e -#define IT87_DATAPORT 0x4f -#define IT87_INIT {0x87, 0x01, 0x55, 0xaa} - */ - -/* IT8712/05 Registers */ -#define IT87_CFGCTRL 0x2 -#define IT87_LDN 0x7 -#define IT87_CHIP_ID1 0x20 -#define IT87_CHIP_ID2 0x21 -#define IT87_CFG_VERSION 0x22 -#define IT87_SWSUSPEND 0x23 - -#define IT8712_CIR_LDN 0xa -#define IT8705_CIR_LDN 0x7 - -/* CIR Configuration Registers: */ -#define IT87_CIR_ACT 0x30 -#define IT87_CIR_BASE_MSB 0x60 -#define IT87_CIR_BASE_LSB 0x61 -#define IT87_CIR_IRQ 0x70 -#define IT87_CIR_CONFIG 0xf0 - -/* List of IT87_CIR registers: offset to BaseAddr */ -#define IT87_CIR_DR 0 -#define IT87_CIR_IER 1 -#define IT87_CIR_RCR 2 -#define IT87_CIR_TCR1 3 -#define IT87_CIR_TCR2 4 -#define IT87_CIR_TSR 5 -#define IT87_CIR_RSR 6 -#define IT87_CIR_BDLR 5 -#define IT87_CIR_BDHR 6 -#define IT87_CIR_IIR 7 - -/* Bit Definition */ -/* IER: */ -#define IT87_CIR_IER_TM_EN 0x80 -#define IT87_CIR_IER_RESEVED 0x40 -#define IT87_CIR_IER_RESET 0x20 -#define IT87_CIR_IER_BR 0x10 -#define IT87_CIR_IER_IEC 0x8 -#define IT87_CIR_IER_RFOIE 0x4 -#define IT87_CIR_IER_RDAIE 0x2 -#define IT87_CIR_IER_TLDLIE 0x1 - -/* RCR: */ -#define IT87_CIR_RCR_RDWOS 0x80 -#define IT87_CIR_RCR_HCFS 0x40 -#define IT87_CIR_RCR_RXEN 0x20 -#define IT87_CIR_RCR_RXEND 0x10 -#define IT87_CIR_RCR_RXACT 0x8 -#define IT87_CIR_RCR_RXDCR 0x7 - -/* TCR1: */ -#define IT87_CIR_TCR1_FIFOCLR 0x80 -#define IT87_CIR_TCR1_ILE 0x40 -#define IT87_CIR_TCR1_FIFOTL 0x30 -#define IT87_CIR_TCR1_TXRLE 0x8 -#define IT87_CIR_TCR1_TXENDF 0x4 -#define IT87_CIR_TCR1_TXMPM 0x3 - -/* TCR2: */ -#define IT87_CIR_TCR2_CFQ 0xf8 -#define IT87_CIR_TCR2_TXMPW 0x7 - -/* TSR: */ -#define IT87_CIR_TSR_RESERVED 0xc0 -#define IT87_CIR_TSR_TXFBC 0x3f - -/* RSR: */ -#define IT87_CIR_RSR_RXFTO 0x80 -#define IT87_CIR_RSR_RESERVED 0x40 -#define IT87_CIR_RSR_RXFBC 0x3f - -/* IIR: */ -#define IT87_CIR_IIR_RESERVED 0xf8 -#define IT87_CIR_IIR_IID 0x6 -#define IT87_CIR_IIR_IIP 0x1 - -/* TM: */ -#define IT87_CIR_TM_IL_SEL 0x80 -#define IT87_CIR_TM_RESERVED 0x40 -#define IT87_CIR_TM_TM_REG 0x3f - -#define IT87_CIR_FIFO_SIZE 32 - -/* Baudratedivisor for IT87: power of 2: only 1,2,4 or 8) */ -#define IT87_CIR_BAUDRATE_DIVISOR 0x1 -#define IT87_CIR_DEFAULT_IOBASE 0x310 -#define IT87_CIR_DEFAULT_IRQ 0x7 -#define IT87_CIR_SPACE 0x00 -#define IT87_CIR_PULSE 0xff -#define IT87_CIR_FREQ_MIN 27 -#define IT87_CIR_FREQ_MAX 58 -#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul) - -/********************************* ITE IT87xx ************************/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ite8709.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ite8709.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ite8709.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ite8709.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,542 +0,0 @@ -/* - * LIRC driver for ITE8709 CIR port - * - * Copyright (C) 2008 Grégory Lardière - * - * 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, or (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include - -#include -#include - -#define LIRC_DRIVER_NAME "lirc_ite8709" - -#define BUF_CHUNK_SIZE sizeof(int) -#define BUF_SIZE (128*BUF_CHUNK_SIZE) - -/* - * The ITE8709 device seems to be the combination of IT8512 superIO chip and - * a specific firmware running on the IT8512's embedded micro-controller. - * In addition of the embedded micro-controller, the IT8512 chip contains a - * CIR module and several other modules. A few modules are directly accessible - * by the host CPU, but most of them are only accessible by the - * micro-controller. The CIR module is only accessible by the micro-controller. - * The battery-backed SRAM module is accessible by the host CPU and the - * micro-controller. So one of the MC's firmware role is to act as a bridge - * between the host CPU and the CIR module. The firmware implements a kind of - * communication protocol using the SRAM module as a shared memory. The IT8512 - * specification is publicly available on ITE's web site, but the communication - * protocol is not, so it was reverse-engineered. - */ - -/* ITE8709 Registers addresses and values (reverse-engineered) */ -#define ITE8709_MODE 0x1a -#define ITE8709_REG_ADR 0x1b -#define ITE8709_REG_VAL 0x1c -#define ITE8709_IIR 0x1e /* Interrupt identification register */ -#define ITE8709_RFSR 0x1f /* Receiver FIFO status register */ -#define ITE8709_FIFO_START 0x20 - -#define ITE8709_MODE_READY 0X00 -#define ITE8709_MODE_WRITE 0X01 -#define ITE8709_MODE_READ 0X02 -#define ITE8709_IIR_RDAI 0x02 /* Receiver data available interrupt */ -#define ITE8709_IIR_RFOI 0x04 /* Receiver FIFO overrun interrupt */ -#define ITE8709_RFSR_MASK 0x3f /* FIFO byte count mask */ - -/* - * IT8512 CIR-module registers addresses and values - * (from IT8512 E/F specification v0.4.1) - */ -#define IT8512_REG_MSTCR 0x01 /* Master control register */ -#define IT8512_REG_IER 0x02 /* Interrupt enable register */ -#define IT8512_REG_CFR 0x04 /* Carrier frequency register */ -#define IT8512_REG_RCR 0x05 /* Receive control register */ -#define IT8512_REG_BDLR 0x08 /* Baud rate divisor low byte register */ -#define IT8512_REG_BDHR 0x09 /* Baud rate divisor high byte register */ - -#define IT8512_MSTCR_RESET 0x01 /* Reset registers to default value */ -#define IT8512_MSTCR_FIFOCLR 0x02 /* Clear FIFO */ -#define IT8512_MSTCR_FIFOTL_7 0x04 /* FIFO threshold level : 7 */ -#define IT8512_MSTCR_FIFOTL_25 0x0c /* FIFO threshold level : 25 */ -#define IT8512_IER_RDAIE 0x02 /* Enable data interrupt request */ -#define IT8512_IER_RFOIE 0x04 /* Enable FIFO overrun interrupt req */ -#define IT8512_IER_IEC 0x80 /* Enable interrupt request */ -#define IT8512_CFR_CF_36KHZ 0x09 /* Carrier freq : low speed, 36kHz */ -#define IT8512_RCR_RXDCR_1 0x01 /* Demodulation carrier range : 1 */ -#define IT8512_RCR_RXACT 0x08 /* Receiver active */ -#define IT8512_RCR_RXEN 0x80 /* Receiver enable */ -#define IT8512_BDR_6 6 /* Baud rate divisor : 6 */ - -/* Actual values used by this driver */ -#define CFG_FIFOTL IT8512_MSTCR_FIFOTL_25 -#define CFG_CR_FREQ IT8512_CFR_CF_36KHZ -#define CFG_DCR IT8512_RCR_RXDCR_1 -#define CFG_BDR IT8512_BDR_6 -#define CFG_TIMEOUT 100000 /* Rearm interrupt when a space is > 100 ms */ - -static int debug; - -struct ite8709_device { - int use_count; - int io; - int irq; - spinlock_t hardware_lock; - __u64 acc_pulse; - __u64 acc_space; - char lastbit; - struct timeval last_tv; - struct lirc_driver driver; - struct tasklet_struct tasklet; - char force_rearm; - char rearmed; - char device_busy; -}; - -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ - fmt, ## args); \ - } while (0) - - -static unsigned char ite8709_read(struct ite8709_device *dev, - unsigned char port) -{ - outb(port, dev->io); - return inb(dev->io+1); -} - -static void ite8709_write(struct ite8709_device *dev, unsigned char port, - unsigned char data) -{ - outb(port, dev->io); - outb(data, dev->io+1); -} - -static void ite8709_wait_device(struct ite8709_device *dev) -{ - int i = 0; - /* - * loop until device tells it's ready to continue - * iterations count is usually ~750 but can sometimes achieve 13000 - */ - for (i = 0; i < 15000; i++) { - udelay(2); - if (ite8709_read(dev, ITE8709_MODE) == ITE8709_MODE_READY) - break; - } -} - -static void ite8709_write_register(struct ite8709_device *dev, - unsigned char reg_adr, unsigned char reg_value) -{ - ite8709_wait_device(dev); - - ite8709_write(dev, ITE8709_REG_VAL, reg_value); - ite8709_write(dev, ITE8709_REG_ADR, reg_adr); - ite8709_write(dev, ITE8709_MODE, ITE8709_MODE_WRITE); -} - -static void ite8709_init_hardware(struct ite8709_device *dev) -{ - spin_lock_irq(&dev->hardware_lock); - dev->device_busy = 1; - spin_unlock_irq(&dev->hardware_lock); - - ite8709_write_register(dev, IT8512_REG_BDHR, (CFG_BDR >> 8) & 0xff); - ite8709_write_register(dev, IT8512_REG_BDLR, CFG_BDR & 0xff); - ite8709_write_register(dev, IT8512_REG_CFR, CFG_CR_FREQ); - ite8709_write_register(dev, IT8512_REG_IER, - IT8512_IER_IEC | IT8512_IER_RFOIE | IT8512_IER_RDAIE); - ite8709_write_register(dev, IT8512_REG_RCR, CFG_DCR); - ite8709_write_register(dev, IT8512_REG_MSTCR, - CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); - ite8709_write_register(dev, IT8512_REG_RCR, - IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); - - spin_lock_irq(&dev->hardware_lock); - dev->device_busy = 0; - spin_unlock_irq(&dev->hardware_lock); - - tasklet_enable(&dev->tasklet); -} - -static void ite8709_drop_hardware(struct ite8709_device *dev) -{ - tasklet_disable(&dev->tasklet); - - spin_lock_irq(&dev->hardware_lock); - dev->device_busy = 1; - spin_unlock_irq(&dev->hardware_lock); - - ite8709_write_register(dev, IT8512_REG_RCR, 0); - ite8709_write_register(dev, IT8512_REG_MSTCR, - IT8512_MSTCR_RESET | IT8512_MSTCR_FIFOCLR); - - spin_lock_irq(&dev->hardware_lock); - dev->device_busy = 0; - spin_unlock_irq(&dev->hardware_lock); -} - -static int ite8709_set_use_inc(void *data) -{ - struct ite8709_device *dev; - dev = data; - if (dev->use_count == 0) - ite8709_init_hardware(dev); - dev->use_count++; - return 0; -} - -static void ite8709_set_use_dec(void *data) -{ - struct ite8709_device *dev; - dev = data; - dev->use_count--; - if (dev->use_count == 0) - ite8709_drop_hardware(dev); -} - -static void ite8709_add_read_queue(struct ite8709_device *dev, int flag, - __u64 val) -{ - int value; - - dprintk("add a %llu usec %s\n", val, flag ? "pulse" : "space"); - - value = (val > PULSE_MASK) ? PULSE_MASK : val; - if (flag) - value |= PULSE_BIT; - - if (!lirc_buffer_full(dev->driver.rbuf)) { - lirc_buffer_write(dev->driver.rbuf, (void *) &value); - wake_up(&dev->driver.rbuf->wait_poll); - } -} - -static irqreturn_t ite8709_interrupt(int irq, void *dev_id) -{ - unsigned char data; - int iir, rfsr, i; - int fifo = 0; - char bit; - struct timeval curr_tv; - - /* Bit duration in microseconds */ - const unsigned long bit_duration = 1000000ul / (115200 / CFG_BDR); - - struct ite8709_device *dev; - dev = dev_id; - - /* - * If device is busy, we simply discard data because we are in one of - * these two cases : shutting down or rearming the device, so this - * doesn't really matter and this avoids waiting too long in IRQ ctx - */ - spin_lock(&dev->hardware_lock); - if (dev->device_busy) { - spin_unlock(&dev->hardware_lock); - return IRQ_RETVAL(IRQ_HANDLED); - } - - iir = ite8709_read(dev, ITE8709_IIR); - - switch (iir) { - case ITE8709_IIR_RFOI: - dprintk("fifo overrun, scheduling forced rearm just in case\n"); - dev->force_rearm = 1; - tasklet_schedule(&dev->tasklet); - spin_unlock(&dev->hardware_lock); - return IRQ_RETVAL(IRQ_HANDLED); - - case ITE8709_IIR_RDAI: - rfsr = ite8709_read(dev, ITE8709_RFSR); - fifo = rfsr & ITE8709_RFSR_MASK; - if (fifo > 32) - fifo = 32; - dprintk("iir: 0x%x rfsr: 0x%x fifo: %d\n", iir, rfsr, fifo); - - if (dev->rearmed) { - do_gettimeofday(&curr_tv); - dev->acc_space += 1000000ull - * (curr_tv.tv_sec - dev->last_tv.tv_sec) - + (curr_tv.tv_usec - dev->last_tv.tv_usec); - dev->rearmed = 0; - } - for (i = 0; i < fifo; i++) { - data = ite8709_read(dev, i+ITE8709_FIFO_START); - data = ~data; - /* Loop through */ - for (bit = 0; bit < 8; ++bit) { - if ((data >> bit) & 1) { - dev->acc_pulse += bit_duration; - if (dev->lastbit == 0) { - ite8709_add_read_queue(dev, 0, - dev->acc_space); - dev->acc_space = 0; - } - } else { - dev->acc_space += bit_duration; - if (dev->lastbit == 1) { - ite8709_add_read_queue(dev, 1, - dev->acc_pulse); - dev->acc_pulse = 0; - } - } - dev->lastbit = (data >> bit) & 1; - } - } - ite8709_write(dev, ITE8709_RFSR, 0); - - if (dev->acc_space > CFG_TIMEOUT) { - dprintk("scheduling rearm IRQ\n"); - do_gettimeofday(&dev->last_tv); - dev->force_rearm = 0; - tasklet_schedule(&dev->tasklet); - } - - spin_unlock(&dev->hardware_lock); - return IRQ_RETVAL(IRQ_HANDLED); - - default: - /* not our irq */ - dprintk("unknown IRQ (shouldn't happen) !!\n"); - spin_unlock(&dev->hardware_lock); - return IRQ_RETVAL(IRQ_NONE); - } -} - -static void ite8709_rearm_irq(unsigned long data) -{ - struct ite8709_device *dev; - unsigned long flags; - dev = (struct ite8709_device *) data; - - spin_lock_irqsave(&dev->hardware_lock, flags); - dev->device_busy = 1; - spin_unlock_irqrestore(&dev->hardware_lock, flags); - - if (dev->force_rearm || dev->acc_space > CFG_TIMEOUT) { - dprintk("rearming IRQ\n"); - ite8709_write_register(dev, IT8512_REG_RCR, - IT8512_RCR_RXACT | CFG_DCR); - ite8709_write_register(dev, IT8512_REG_MSTCR, - CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); - ite8709_write_register(dev, IT8512_REG_RCR, - IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); - if (!dev->force_rearm) - dev->rearmed = 1; - dev->force_rearm = 0; - } - - spin_lock_irqsave(&dev->hardware_lock, flags); - dev->device_busy = 0; - spin_unlock_irqrestore(&dev->hardware_lock, flags); -} - -static int ite8709_cleanup(struct ite8709_device *dev, int stage, int errno, - char *msg) -{ - if (msg != NULL) - printk(KERN_ERR LIRC_DRIVER_NAME ": %s\n", msg); - - switch (stage) { - case 6: - if (dev->use_count > 0) - ite8709_drop_hardware(dev); - case 5: - free_irq(dev->irq, dev); - case 4: - release_region(dev->io, 2); - case 3: - lirc_unregister_driver(dev->driver.minor); - case 2: - lirc_buffer_free(dev->driver.rbuf); - kfree(dev->driver.rbuf); - case 1: - kfree(dev); - case 0: - ; - } - - return errno; -} - -static int __devinit ite8709_pnp_probe(struct pnp_dev *dev, - const struct pnp_device_id *dev_id) -{ - struct lirc_driver *driver; - struct ite8709_device *ite8709_dev; - int ret; - - /* Check resources validity */ - if (!pnp_irq_valid(dev, 0)) - return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IRQ"); - if (!pnp_port_valid(dev, 2)) - return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IO port"); - - /* Allocate memory for device struct */ - ite8709_dev = kzalloc(sizeof(struct ite8709_device), GFP_KERNEL); - if (ite8709_dev == NULL) - return ite8709_cleanup(NULL, 0, -ENOMEM, "kzalloc failed"); - pnp_set_drvdata(dev, ite8709_dev); - - /* Initialize device struct */ - ite8709_dev->use_count = 0; - ite8709_dev->irq = pnp_irq(dev, 0); - ite8709_dev->io = pnp_port_start(dev, 2); - ite8709_dev->hardware_lock = - __SPIN_LOCK_UNLOCKED(ite8709_dev->hardware_lock); - ite8709_dev->acc_pulse = 0; - ite8709_dev->acc_space = 0; - ite8709_dev->lastbit = 0; - do_gettimeofday(&ite8709_dev->last_tv); - tasklet_init(&ite8709_dev->tasklet, ite8709_rearm_irq, - (long) ite8709_dev); - ite8709_dev->force_rearm = 0; - ite8709_dev->rearmed = 0; - ite8709_dev->device_busy = 0; - - /* Initialize driver struct */ - driver = &ite8709_dev->driver; - strcpy(driver->name, LIRC_DRIVER_NAME); - driver->minor = -1; - driver->code_length = sizeof(int) * 8; - driver->sample_rate = 0; - driver->features = LIRC_CAN_REC_MODE2; - driver->data = ite8709_dev; - driver->add_to_buf = NULL; - driver->set_use_inc = ite8709_set_use_inc; - driver->set_use_dec = ite8709_set_use_dec; - driver->dev = &dev->dev; - driver->owner = THIS_MODULE; - - /* Initialize LIRC buffer */ - driver->rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); - if (!driver->rbuf) - return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, - "can't allocate lirc_buffer"); - if (lirc_buffer_init(driver->rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) - return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, - "lirc_buffer_init() failed"); - - /* Register LIRC driver */ - ret = lirc_register_driver(driver); - if (ret < 0) - return ite8709_cleanup(ite8709_dev, 2, ret, - "lirc_register_driver() failed"); - - /* Reserve I/O port access */ - if (!request_region(ite8709_dev->io, 2, LIRC_DRIVER_NAME)) - return ite8709_cleanup(ite8709_dev, 3, -EBUSY, - "i/o port already in use"); - - /* Reserve IRQ line */ - ret = request_irq(ite8709_dev->irq, ite8709_interrupt, 0, - LIRC_DRIVER_NAME, ite8709_dev); - if (ret < 0) - return ite8709_cleanup(ite8709_dev, 4, ret, - "IRQ already in use"); - - /* Initialize hardware */ - ite8709_drop_hardware(ite8709_dev); /* Shutdown hw until first use */ - - printk(KERN_INFO LIRC_DRIVER_NAME ": device found : irq=%d io=0x%x\n", - ite8709_dev->irq, ite8709_dev->io); - - return 0; -} - -static void __devexit ite8709_pnp_remove(struct pnp_dev *dev) -{ - struct ite8709_device *ite8709_dev; - ite8709_dev = pnp_get_drvdata(dev); - - ite8709_cleanup(ite8709_dev, 6, 0, NULL); - - printk(KERN_INFO LIRC_DRIVER_NAME ": device removed\n"); -} - -#ifdef CONFIG_PM -static int ite8709_pnp_suspend(struct pnp_dev *dev, pm_message_t state) -{ - struct ite8709_device *ite8709_dev; - ite8709_dev = pnp_get_drvdata(dev); - - if (ite8709_dev->use_count > 0) - ite8709_drop_hardware(ite8709_dev); - - return 0; -} - -static int ite8709_pnp_resume(struct pnp_dev *dev) -{ - struct ite8709_device *ite8709_dev; - ite8709_dev = pnp_get_drvdata(dev); - - if (ite8709_dev->use_count > 0) - ite8709_init_hardware(ite8709_dev); - - return 0; -} -#else -#define ite8709_pnp_suspend NULL -#define ite8709_pnp_resume NULL -#endif - -static const struct pnp_device_id pnp_dev_table[] = { - {"ITE8709", 0}, - {} -}; - -MODULE_DEVICE_TABLE(pnp, pnp_dev_table); - -static struct pnp_driver ite8709_pnp_driver = { - .name = LIRC_DRIVER_NAME, - .probe = ite8709_pnp_probe, - .remove = __devexit_p(ite8709_pnp_remove), - .suspend = ite8709_pnp_suspend, - .resume = ite8709_pnp_resume, - .id_table = pnp_dev_table, -}; - -static int __init ite8709_init_module(void) -{ - return pnp_register_driver(&ite8709_pnp_driver); -} -module_init(ite8709_init_module); - -static void __exit ite8709_cleanup_module(void) -{ - pnp_unregister_driver(&ite8709_pnp_driver); -} -module_exit(ite8709_cleanup_module); - -MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port"); -MODULE_AUTHOR("Grégory Lardière"); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_parallel.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_parallel.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_parallel.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_parallel.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,690 +0,0 @@ -/* - * lirc_parallel.c - * - * lirc_parallel - device driver for infra-red signal receiving and - * transmitting unit built by the author - * - * Copyright (C) 1998 Christoph Bartelmus - * - * 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, or - * (at your option) any later version. - * - * 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 - * - */ - -/*** Includes ***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "lirc_parallel.h" - -#define LIRC_DRIVER_NAME "lirc_parallel" - -#ifndef LIRC_IRQ -#define LIRC_IRQ 7 -#endif -#ifndef LIRC_PORT -#define LIRC_PORT 0x378 -#endif -#ifndef LIRC_TIMER -#define LIRC_TIMER 65536 -#endif - -/*** Global Variables ***/ - -static int debug; -static int check_pselecd; - -unsigned int irq = LIRC_IRQ; -unsigned int io = LIRC_PORT; -#ifdef LIRC_TIMER -unsigned int timer; -unsigned int default_timer = LIRC_TIMER; -#endif - -#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */ - -static int rbuf[RBUF_SIZE]; - -DECLARE_WAIT_QUEUE_HEAD(lirc_wait); - -unsigned int rptr; -unsigned int wptr; -unsigned int lost_irqs; -int is_open; - -struct parport *pport; -struct pardevice *ppdevice; -int is_claimed; - -unsigned int tx_mask = 1; - -/*** Internal Functions ***/ - -static unsigned int in(int offset) -{ - switch (offset) { - case LIRC_LP_BASE: - return parport_read_data(pport); - case LIRC_LP_STATUS: - return parport_read_status(pport); - case LIRC_LP_CONTROL: - return parport_read_control(pport); - } - return 0; /* make compiler happy */ -} - -static void out(int offset, int value) -{ - switch (offset) { - case LIRC_LP_BASE: - parport_write_data(pport, value); - break; - case LIRC_LP_CONTROL: - parport_write_control(pport, value); - break; - case LIRC_LP_STATUS: - printk(KERN_INFO "%s: attempt to write to status register\n", - LIRC_DRIVER_NAME); - break; - } -} - -static unsigned int lirc_get_timer(void) -{ - return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT; -} - -static unsigned int lirc_get_signal(void) -{ - return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT; -} - -static void lirc_on(void) -{ - out(LIRC_PORT_DATA, tx_mask); -} - -static void lirc_off(void) -{ - out(LIRC_PORT_DATA, 0); -} - -static unsigned int init_lirc_timer(void) -{ - struct timeval tv, now; - unsigned int level, newlevel, timeelapsed, newtimer; - int count = 0; - - do_gettimeofday(&tv); - tv.tv_sec++; /* wait max. 1 sec. */ - level = lirc_get_timer(); - do { - newlevel = lirc_get_timer(); - if (level == 0 && newlevel != 0) - count++; - level = newlevel; - do_gettimeofday(&now); - } while (count < 1000 && (now.tv_sec < tv.tv_sec - || (now.tv_sec == tv.tv_sec - && now.tv_usec < tv.tv_usec))); - - timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000 - + (now.tv_usec - tv.tv_usec)); - if (count >= 1000 && timeelapsed > 0) { - if (default_timer == 0) { - /* autodetect timer */ - newtimer = (1000000*count)/timeelapsed; - printk(KERN_INFO "%s: %u Hz timer detected\n", - LIRC_DRIVER_NAME, newtimer); - return newtimer; - } else { - newtimer = (1000000*count)/timeelapsed; - if (abs(newtimer - default_timer) > default_timer/10) { - /* bad timer */ - printk(KERN_NOTICE "%s: bad timer: %u Hz\n", - LIRC_DRIVER_NAME, newtimer); - printk(KERN_NOTICE "%s: using default timer: " - "%u Hz\n", - LIRC_DRIVER_NAME, default_timer); - return default_timer; - } else { - printk(KERN_INFO "%s: %u Hz timer detected\n", - LIRC_DRIVER_NAME, newtimer); - return newtimer; /* use detected value */ - } - } - } else { - printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME); - return 0; - } -} - -static int lirc_claim(void) -{ - if (parport_claim(ppdevice) != 0) { - printk(KERN_WARNING "%s: could not claim port\n", - LIRC_DRIVER_NAME); - printk(KERN_WARNING "%s: waiting for port becoming available" - "\n", LIRC_DRIVER_NAME); - if (parport_claim_or_block(ppdevice) < 0) { - printk(KERN_NOTICE "%s: could not claim port, giving" - " up\n", LIRC_DRIVER_NAME); - return 0; - } - } - out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); - is_claimed = 1; - return 1; -} - -/*** interrupt handler ***/ - -static void rbuf_write(int signal) -{ - unsigned int nwptr; - - nwptr = (wptr + 1) & (RBUF_SIZE - 1); - if (nwptr == rptr) { - /* no new signals will be accepted */ - lost_irqs++; - printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME); - return; - } - rbuf[wptr] = signal; - wptr = nwptr; -} - -static void irq_handler(void *blah) -{ - struct timeval tv; - static struct timeval lasttv; - static int init; - long signal; - int data; - unsigned int level, newlevel; - unsigned int timeout; - - if (!is_open) - return; - - if (!is_claimed) - return; - -#if 0 - /* disable interrupt */ - disable_irq(irq); - out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); -#endif - if (check_pselecd && (in(1) & LP_PSELECD)) - return; - -#ifdef LIRC_TIMER - if (init) { - do_gettimeofday(&tv); - - signal = tv.tv_sec - lasttv.tv_sec; - if (signal > 15) - /* really long time */ - data = PULSE_MASK; - else - data = (int) (signal*1000000 + - tv.tv_usec - lasttv.tv_usec + - LIRC_SFH506_DELAY); - - rbuf_write(data); /* space */ - } else { - if (timer == 0) { - /* - * wake up; we'll lose this signal, but it will be - * garbage if the device is turned on anyway - */ - timer = init_lirc_timer(); - /* enable_irq(irq); */ - return; - } - init = 1; - } - - timeout = timer/10; /* timeout after 1/10 sec. */ - signal = 1; - level = lirc_get_timer(); - do { - newlevel = lirc_get_timer(); - if (level == 0 && newlevel != 0) - signal++; - level = newlevel; - - /* giving up */ - if (signal > timeout - || (check_pselecd && (in(1) & LP_PSELECD))) { - signal = 0; - printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME); - break; - } - } while (lirc_get_signal()); - - if (signal != 0) { - /* ajust value to usecs */ - __u64 helper; - - helper = ((__u64) signal)*1000000; - do_div(helper, timer); - signal = (long) helper; - - if (signal > LIRC_SFH506_DELAY) - data = signal - LIRC_SFH506_DELAY; - else - data = 1; - rbuf_write(PULSE_BIT|data); /* pulse */ - } - do_gettimeofday(&lasttv); -#else - /* add your code here */ -#endif - - wake_up_interruptible(&lirc_wait); - - /* enable interrupt */ - /* - enable_irq(irq); - out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN); - */ -} - -/*** file operations ***/ - -static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig) -{ - return -ESPIPE; -} - -static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos) -{ - int result = 0; - int count = 0; - DECLARE_WAITQUEUE(wait, current); - - if (n % sizeof(int)) - return -EINVAL; - - add_wait_queue(&lirc_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - while (count < n) { - if (rptr != wptr) { - if (copy_to_user(buf+count, (char *) &rbuf[rptr], - sizeof(int))) { - result = -EFAULT; - break; - } - rptr = (rptr + 1) & (RBUF_SIZE - 1); - count += sizeof(int); - } else { - if (filep->f_flags & O_NONBLOCK) { - result = -EAGAIN; - break; - } - if (signal_pending(current)) { - result = -ERESTARTSYS; - break; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - } - remove_wait_queue(&lirc_wait, &wait); - set_current_state(TASK_RUNNING); - return count ? count : result; -} - -static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, - loff_t *ppos) -{ - int count; - unsigned int i; - unsigned int level, newlevel; - unsigned long flags; - int counttimer; - int *wbuf; - ssize_t ret; - - if (!is_claimed) - return -EBUSY; - - count = n / sizeof(int); - - if (n % sizeof(int) || count % 2 == 0) - return -EINVAL; - - wbuf = memdup_user(buf, n); - if (IS_ERR(wbuf)) - return PTR_ERR(wbuf); - -#ifdef LIRC_TIMER - if (timer == 0) { - /* try again if device is ready */ - timer = init_lirc_timer(); - if (timer == 0) { - ret = -EIO; - goto out; - } - } - - /* adjust values from usecs */ - for (i = 0; i < count; i++) { - __u64 helper; - - helper = ((__u64) wbuf[i])*timer; - do_div(helper, 1000000); - wbuf[i] = (int) helper; - } - - local_irq_save(flags); - i = 0; - while (i < count) { - level = lirc_get_timer(); - counttimer = 0; - lirc_on(); - do { - newlevel = lirc_get_timer(); - if (level == 0 && newlevel != 0) - counttimer++; - level = newlevel; - if (check_pselecd && (in(1) & LP_PSELECD)) { - lirc_off(); - local_irq_restore(flags); - ret = -EIO; - goto out; - } - } while (counttimer < wbuf[i]); - i++; - - lirc_off(); - if (i == count) - break; - counttimer = 0; - do { - newlevel = lirc_get_timer(); - if (level == 0 && newlevel != 0) - counttimer++; - level = newlevel; - if (check_pselecd && (in(1) & LP_PSELECD)) { - local_irq_restore(flags); - ret = -EIO; - goto out; - } - } while (counttimer < wbuf[i]); - i++; - } - local_irq_restore(flags); -#else - /* place code that handles write without external timer here */ -#endif - ret = n; -out: - kfree(wbuf); - - return ret; -} - -static unsigned int lirc_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &lirc_wait, wait); - if (rptr != wptr) - return POLLIN | POLLRDNORM; - return 0; -} - -static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - int result; - __u32 features = LIRC_CAN_SET_TRANSMITTER_MASK | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; - __u32 mode; - __u32 value; - - switch (cmd) { - case LIRC_GET_FEATURES: - result = put_user(features, (__u32 *) arg); - if (result) - return result; - break; - case LIRC_GET_SEND_MODE: - result = put_user(LIRC_MODE_PULSE, (__u32 *) arg); - if (result) - return result; - break; - case LIRC_GET_REC_MODE: - result = put_user(LIRC_MODE_MODE2, (__u32 *) arg); - if (result) - return result; - break; - case LIRC_SET_SEND_MODE: - result = get_user(mode, (__u32 *) arg); - if (result) - return result; - if (mode != LIRC_MODE_PULSE) - return -EINVAL; - break; - case LIRC_SET_REC_MODE: - result = get_user(mode, (__u32 *) arg); - if (result) - return result; - if (mode != LIRC_MODE_MODE2) - return -ENOSYS; - break; - case LIRC_SET_TRANSMITTER_MASK: - result = get_user(value, (__u32 *) arg); - if (result) - return result; - if ((value & LIRC_PARALLEL_TRANSMITTER_MASK) != value) - return LIRC_PARALLEL_MAX_TRANSMITTERS; - tx_mask = value; - break; - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static int lirc_open(struct inode *node, struct file *filep) -{ - if (is_open || !lirc_claim()) - return -EBUSY; - - parport_enable_irq(pport); - - /* init read ptr */ - rptr = 0; - wptr = 0; - lost_irqs = 0; - - is_open = 1; - return 0; -} - -static int lirc_close(struct inode *node, struct file *filep) -{ - if (is_claimed) { - is_claimed = 0; - parport_release(ppdevice); - } - is_open = 0; - return 0; -} - -static const struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .llseek = lirc_lseek, - .read = lirc_read, - .write = lirc_write, - .poll = lirc_poll, - .unlocked_ioctl = lirc_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = lirc_ioctl, -#endif - .open = lirc_open, - .release = lirc_close -}; - -static int set_use_inc(void *data) -{ - return 0; -} - -static void set_use_dec(void *data) -{ -} - -static struct lirc_driver driver = { - .name = LIRC_DRIVER_NAME, - .minor = -1, - .code_length = 1, - .sample_rate = 0, - .data = NULL, - .add_to_buf = NULL, - .set_use_inc = set_use_inc, - .set_use_dec = set_use_dec, - .fops = &lirc_fops, - .dev = NULL, - .owner = THIS_MODULE, -}; - -static int pf(void *handle); -static void kf(void *handle); - -static int pf(void *handle) -{ - parport_disable_irq(pport); - is_claimed = 0; - return 0; -} - -static void kf(void *handle) -{ - if (!is_open) - return; - if (!lirc_claim()) - return; - parport_enable_irq(pport); - lirc_off(); - /* this is a bit annoying when you actually print...*/ - /* - printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME); - */ -} - -/*** module initialization and cleanup ***/ - -static int __init lirc_parallel_init(void) -{ - pport = parport_find_base(io); - if (pport == NULL) { - printk(KERN_NOTICE "%s: no port at %x found\n", - LIRC_DRIVER_NAME, io); - return -ENXIO; - } - ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME, - pf, kf, irq_handler, 0, NULL); - parport_put_port(pport); - if (ppdevice == NULL) { - printk(KERN_NOTICE "%s: parport_register_device() failed\n", - LIRC_DRIVER_NAME); - return -ENXIO; - } - if (parport_claim(ppdevice) != 0) - goto skip_init; - is_claimed = 1; - out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); - -#ifdef LIRC_TIMER - if (debug) - out(LIRC_PORT_DATA, tx_mask); - - timer = init_lirc_timer(); - -#if 0 /* continue even if device is offline */ - if (timer == 0) { - is_claimed = 0; - parport_release(pport); - parport_unregister_device(ppdevice); - return -EIO; - } - -#endif - if (debug) - out(LIRC_PORT_DATA, 0); -#endif - - is_claimed = 0; - parport_release(ppdevice); - skip_init: - driver.minor = lirc_register_driver(&driver); - if (driver.minor < 0) { - printk(KERN_NOTICE "%s: register_chrdev() failed\n", - LIRC_DRIVER_NAME); - parport_unregister_device(ppdevice); - return -EIO; - } - printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n", - LIRC_DRIVER_NAME, io, irq); - return 0; -} - -static void __exit lirc_parallel_exit(void) -{ - parport_unregister_device(ppdevice); - lirc_unregister_driver(driver.minor); -} - -module_init(lirc_parallel_init); -module_exit(lirc_parallel_exit); - -MODULE_DESCRIPTION("Infrared receiver driver for parallel ports."); -MODULE_AUTHOR("Christoph Bartelmus"); -MODULE_LICENSE("GPL"); - -module_param(io, int, S_IRUGO); -MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)"); - -module_param(irq, int, S_IRUGO); -MODULE_PARM_DESC(irq, "Interrupt (7 or 5)"); - -module_param(tx_mask, int, S_IRUGO); -MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); - -module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_parallel.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_parallel.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_parallel.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_parallel.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -/* lirc_parallel.h */ - -#ifndef _LIRC_PARALLEL_H -#define _LIRC_PARALLEL_H - -#include - -#define LIRC_PORT_LEN 3 - -#define LIRC_LP_BASE 0 -#define LIRC_LP_STATUS 1 -#define LIRC_LP_CONTROL 2 - -#define LIRC_PORT_DATA LIRC_LP_BASE /* base */ -#define LIRC_PORT_TIMER LIRC_LP_STATUS /* status port */ -#define LIRC_PORT_TIMER_BIT LP_PBUSY /* busy signal */ -#define LIRC_PORT_SIGNAL LIRC_LP_STATUS /* status port */ -#define LIRC_PORT_SIGNAL_BIT LP_PACK /* ack signal */ -#define LIRC_PORT_IRQ LIRC_LP_CONTROL /* control port */ - -#define LIRC_SFH506_DELAY 0 /* delay t_phl in usecs */ - -#define LIRC_PARALLEL_MAX_TRANSMITTERS 8 -#define LIRC_PARALLEL_TRANSMITTER_MASK ((1< - * Tim Davies - * - * This driver was derived from: - * Venky Raju - * "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD" - * Paul Miller 's 2003-2004 - * "lirc_atiusb - USB remote support for LIRC" - * Culver Consulting Services 's 2003 - * "Sasem OnAir VFD/IR USB driver" - * - * - * NOTE - The LCDproc iMon driver should work with this module. More info at - * http://www.frogstorm.info/sasem - */ - -/* - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include - -#include -#include - - -#define MOD_AUTHOR "Oliver Stabel , " \ - "Tim Davies " -#define MOD_DESC "USB Driver for Sasem Remote Controller V1.1" -#define MOD_NAME "lirc_sasem" -#define MOD_VERSION "0.5" - -#define VFD_MINOR_BASE 144 /* Same as LCD */ -#define DEVICE_NAME "lcd%d" - -#define BUF_CHUNK_SIZE 8 -#define BUF_SIZE 128 - -#define IOCTL_LCD_CONTRAST 1 - -/*** P R O T O T Y P E S ***/ - -/* USB Callback prototypes */ -static int sasem_probe(struct usb_interface *interface, - const struct usb_device_id *id); -static void sasem_disconnect(struct usb_interface *interface); -static void usb_rx_callback(struct urb *urb); -static void usb_tx_callback(struct urb *urb); - -/* VFD file_operations function prototypes */ -static int vfd_open(struct inode *inode, struct file *file); -static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg); -static int vfd_close(struct inode *inode, struct file *file); -static ssize_t vfd_write(struct file *file, const char *buf, - size_t n_bytes, loff_t *pos); - -/* LIRC driver function prototypes */ -static int ir_open(void *data); -static void ir_close(void *data); - -/* Driver init/exit prototypes */ -static int __init sasem_init(void); -static void __exit sasem_exit(void); - -/*** G L O B A L S ***/ -#define SASEM_DATA_BUF_SZ 32 - -struct sasem_context { - - struct usb_device *dev; - int vfd_isopen; /* VFD port has been opened */ - unsigned int vfd_contrast; /* VFD contrast */ - int ir_isopen; /* IR port has been opened */ - int dev_present; /* USB device presence */ - struct mutex ctx_lock; /* to lock this object */ - wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ - - struct lirc_driver *driver; - struct usb_endpoint_descriptor *rx_endpoint; - struct usb_endpoint_descriptor *tx_endpoint; - struct urb *rx_urb; - struct urb *tx_urb; - unsigned char usb_rx_buf[8]; - unsigned char usb_tx_buf[8]; - - struct tx_t { - unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */ - struct completion finished; /* wait for write to finish */ - atomic_t busy; /* write in progress */ - int status; /* status of tx completion */ - } tx; - - /* for dealing with repeat codes (wish there was a toggle bit!) */ - struct timeval presstime; - char lastcode[8]; - int codesaved; -}; - -/* VFD file operations */ -static const struct file_operations vfd_fops = { - .owner = THIS_MODULE, - .open = &vfd_open, - .write = &vfd_write, - .unlocked_ioctl = &vfd_ioctl, - .release = &vfd_close, - .llseek = noop_llseek, -}; - -/* USB Device ID for Sasem USB Control Board */ -static struct usb_device_id sasem_usb_id_table[] = { - /* Sasem USB Control Board */ - { USB_DEVICE(0x11ba, 0x0101) }, - /* Terminating entry */ - {} -}; - -/* USB Device data */ -static struct usb_driver sasem_driver = { - .name = MOD_NAME, - .probe = sasem_probe, - .disconnect = sasem_disconnect, - .id_table = sasem_usb_id_table, -}; - -static struct usb_class_driver sasem_class = { - .name = DEVICE_NAME, - .fops = &vfd_fops, - .minor_base = VFD_MINOR_BASE, -}; - -/* to prevent races between open() and disconnect() */ -static DEFINE_MUTEX(disconnect_lock); - -static int debug; - - -/*** M O D U L E C O D E ***/ - -MODULE_AUTHOR(MOD_AUTHOR); -MODULE_DESCRIPTION(MOD_DESC); -MODULE_LICENSE("GPL"); -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); - -static void delete_context(struct sasem_context *context) -{ - usb_free_urb(context->tx_urb); /* VFD */ - usb_free_urb(context->rx_urb); /* IR */ - lirc_buffer_free(context->driver->rbuf); - kfree(context->driver->rbuf); - kfree(context->driver); - kfree(context); - - if (debug) - printk(KERN_INFO "%s: context deleted\n", __func__); -} - -static void deregister_from_lirc(struct sasem_context *context) -{ - int retval; - int minor = context->driver->minor; - - retval = lirc_unregister_driver(minor); - if (retval) - err("%s: unable to deregister from lirc (%d)", - __func__, retval); - else - printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n", - minor); - -} - -/** - * Called when the VFD device (e.g. /dev/usb/lcd) - * is opened by the application. - */ -static int vfd_open(struct inode *inode, struct file *file) -{ - struct usb_interface *interface; - struct sasem_context *context = NULL; - int subminor; - int retval = 0; - - /* prevent races with disconnect */ - mutex_lock(&disconnect_lock); - - subminor = iminor(inode); - interface = usb_find_interface(&sasem_driver, subminor); - if (!interface) { - err("%s: could not find interface for minor %d", - __func__, subminor); - retval = -ENODEV; - goto exit; - } - context = usb_get_intfdata(interface); - - if (!context) { - err("%s: no context found for minor %d", - __func__, subminor); - retval = -ENODEV; - goto exit; - } - - mutex_lock(&context->ctx_lock); - - if (context->vfd_isopen) { - err("%s: VFD port is already open", __func__); - retval = -EBUSY; - } else { - context->vfd_isopen = 1; - file->private_data = context; - printk(KERN_INFO "VFD port opened\n"); - } - - mutex_unlock(&context->ctx_lock); - -exit: - mutex_unlock(&disconnect_lock); - return retval; -} - -/** - * Called when the VFD device (e.g. /dev/usb/lcd) - * is closed by the application. - */ -static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg) -{ - struct sasem_context *context = NULL; - - context = (struct sasem_context *) file->private_data; - - if (!context) { - err("%s: no context for device", __func__); - return -ENODEV; - } - - mutex_lock(&context->ctx_lock); - - switch (cmd) { - case IOCTL_LCD_CONTRAST: - if (arg > 1000) - arg = 1000; - context->vfd_contrast = (unsigned int)arg; - break; - default: - printk(KERN_INFO "Unknown IOCTL command\n"); - mutex_unlock(&context->ctx_lock); - return -ENOIOCTLCMD; /* not supported */ - } - - mutex_unlock(&context->ctx_lock); - return 0; -} - -/** - * Called when the VFD device (e.g. /dev/usb/lcd) - * is closed by the application. - */ -static int vfd_close(struct inode *inode, struct file *file) -{ - struct sasem_context *context = NULL; - int retval = 0; - - context = (struct sasem_context *) file->private_data; - - if (!context) { - err("%s: no context for device", __func__); - return -ENODEV; - } - - mutex_lock(&context->ctx_lock); - - if (!context->vfd_isopen) { - err("%s: VFD is not open", __func__); - retval = -EIO; - } else { - context->vfd_isopen = 0; - printk(KERN_INFO "VFD port closed\n"); - if (!context->dev_present && !context->ir_isopen) { - - /* Device disconnected before close and IR port is - * not open. If IR port is open, context will be - * deleted by ir_close. */ - mutex_unlock(&context->ctx_lock); - delete_context(context); - return retval; - } - } - - mutex_unlock(&context->ctx_lock); - return retval; -} - -/** - * Sends a packet to the VFD. - */ -static int send_packet(struct sasem_context *context) -{ - unsigned int pipe; - int interval = 0; - int retval = 0; - - pipe = usb_sndintpipe(context->dev, - context->tx_endpoint->bEndpointAddress); - interval = context->tx_endpoint->bInterval; - - usb_fill_int_urb(context->tx_urb, context->dev, pipe, - context->usb_tx_buf, sizeof(context->usb_tx_buf), - usb_tx_callback, context, interval); - - context->tx_urb->actual_length = 0; - - init_completion(&context->tx.finished); - atomic_set(&(context->tx.busy), 1); - - retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); - if (retval) { - atomic_set(&(context->tx.busy), 0); - err("%s: error submitting urb (%d)", __func__, retval); - } else { - /* Wait for transmission to complete (or abort) */ - mutex_unlock(&context->ctx_lock); - wait_for_completion(&context->tx.finished); - mutex_lock(&context->ctx_lock); - - retval = context->tx.status; - if (retval) - err("%s: packet tx failed (%d)", __func__, retval); - } - - return retval; -} - -/** - * Writes data to the VFD. The Sasem VFD is 2x16 characters - * and requires data in 9 consecutive USB interrupt packets, - * each packet carrying 8 bytes. - */ -static ssize_t vfd_write(struct file *file, const char *buf, - size_t n_bytes, loff_t *pos) -{ - int i; - int retval = 0; - struct sasem_context *context; - int *data_buf = NULL; - - context = (struct sasem_context *) file->private_data; - if (!context) { - err("%s: no context for device", __func__); - return -ENODEV; - } - - mutex_lock(&context->ctx_lock); - - if (!context->dev_present) { - err("%s: no Sasem device present", __func__); - retval = -ENODEV; - goto exit; - } - - if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) { - err("%s: invalid payload size", __func__); - retval = -EINVAL; - goto exit; - } - - data_buf = memdup_user(buf, n_bytes); - if (IS_ERR(data_buf)) { - retval = PTR_ERR(data_buf); - goto exit; - } - - memcpy(context->tx.data_buf, data_buf, n_bytes); - - /* Pad with spaces */ - for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i) - context->tx.data_buf[i] = ' '; - - /* Nine 8 byte packets to be sent */ - /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0" - * will clear the VFD */ - for (i = 0; i < 9; i++) { - switch (i) { - case 0: - memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8); - context->usb_tx_buf[1] = (context->vfd_contrast) ? - (0x2B - (context->vfd_contrast - 1) / 250) - : 0x2B; - break; - case 1: - memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); - break; - case 2: - memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8); - break; - case 3: - memcpy(context->usb_tx_buf, context->tx.data_buf, 8); - break; - case 4: - memcpy(context->usb_tx_buf, - context->tx.data_buf + 8, 8); - break; - case 5: - memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); - break; - case 6: - memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8); - break; - case 7: - memcpy(context->usb_tx_buf, - context->tx.data_buf + 16, 8); - break; - case 8: - memcpy(context->usb_tx_buf, - context->tx.data_buf + 24, 8); - break; - } - retval = send_packet(context); - if (retval) { - - err("%s: send packet failed for packet #%d", - __func__, i); - goto exit; - } - } -exit: - - mutex_unlock(&context->ctx_lock); - kfree(data_buf); - - return (!retval) ? n_bytes : retval; -} - -/** - * Callback function for USB core API: transmit data - */ -static void usb_tx_callback(struct urb *urb) -{ - struct sasem_context *context; - - if (!urb) - return; - context = (struct sasem_context *) urb->context; - if (!context) - return; - - context->tx.status = urb->status; - - /* notify waiters that write has finished */ - atomic_set(&context->tx.busy, 0); - complete(&context->tx.finished); - - return; -} - -/** - * Called by lirc_dev when the application opens /dev/lirc - */ -static int ir_open(void *data) -{ - int retval = 0; - struct sasem_context *context; - - /* prevent races with disconnect */ - mutex_lock(&disconnect_lock); - - context = (struct sasem_context *) data; - - mutex_lock(&context->ctx_lock); - - if (context->ir_isopen) { - err("%s: IR port is already open", __func__); - retval = -EBUSY; - goto exit; - } - - usb_fill_int_urb(context->rx_urb, context->dev, - usb_rcvintpipe(context->dev, - context->rx_endpoint->bEndpointAddress), - context->usb_rx_buf, sizeof(context->usb_rx_buf), - usb_rx_callback, context, context->rx_endpoint->bInterval); - - retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); - - if (retval) - err("%s: usb_submit_urb failed for ir_open (%d)", - __func__, retval); - else { - context->ir_isopen = 1; - printk(KERN_INFO "IR port opened\n"); - } - -exit: - mutex_unlock(&context->ctx_lock); - - mutex_unlock(&disconnect_lock); - return retval; -} - -/** - * Called by lirc_dev when the application closes /dev/lirc - */ -static void ir_close(void *data) -{ - struct sasem_context *context; - - context = (struct sasem_context *)data; - if (!context) { - err("%s: no context for device", __func__); - return; - } - - mutex_lock(&context->ctx_lock); - - usb_kill_urb(context->rx_urb); - context->ir_isopen = 0; - printk(KERN_INFO "IR port closed\n"); - - if (!context->dev_present) { - - /* - * Device disconnected while IR port was - * still open. Driver was not deregistered - * at disconnect time, so do it now. - */ - deregister_from_lirc(context); - - if (!context->vfd_isopen) { - - mutex_unlock(&context->ctx_lock); - delete_context(context); - return; - } - /* If VFD port is open, context will be deleted by vfd_close */ - } - - mutex_unlock(&context->ctx_lock); - return; -} - -/** - * Process the incoming packet - */ -static void incoming_packet(struct sasem_context *context, - struct urb *urb) -{ - int len = urb->actual_length; - unsigned char *buf = urb->transfer_buffer; - long ms; - struct timeval tv; - - if (len != 8) { - printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n", - __func__, len); - return; - } - -#ifdef DEBUG - int i; - for (i = 0; i < 8; ++i) - printk(KERN_INFO "%02x ", buf[i]); - printk(KERN_INFO "\n"); -#endif - - /* - * Lirc could deal with the repeat code, but we really need to block it - * if it arrives too late. Otherwise we could repeat the wrong code. - */ - - /* get the time since the last button press */ - do_gettimeofday(&tv); - ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 + - (tv.tv_usec - context->presstime.tv_usec) / 1000; - - if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) { - /* - * the repeat code is being sent, so we copy - * the old code to LIRC - */ - - /* - * NOTE: Only if the last code was less than 250ms ago - * - no one should be able to push another (undetected) button - * in that time and then get a false repeat of the previous - * press but it is long enough for a genuine repeat - */ - if ((ms < 250) && (context->codesaved != 0)) { - memcpy(buf, &context->lastcode, 8); - context->presstime.tv_sec = tv.tv_sec; - context->presstime.tv_usec = tv.tv_usec; - } - } else { - /* save the current valid code for repeats */ - memcpy(&context->lastcode, buf, 8); - /* - * set flag to signal a valid code was save; - * just for safety reasons - */ - context->codesaved = 1; - context->presstime.tv_sec = tv.tv_sec; - context->presstime.tv_usec = tv.tv_usec; - } - - lirc_buffer_write(context->driver->rbuf, buf); - wake_up(&context->driver->rbuf->wait_poll); -} - -/** - * Callback function for USB core API: receive data - */ -static void usb_rx_callback(struct urb *urb) -{ - struct sasem_context *context; - - if (!urb) - return; - context = (struct sasem_context *) urb->context; - if (!context) - return; - - switch (urb->status) { - - case -ENOENT: /* usbcore unlink successful! */ - return; - - case 0: - if (context->ir_isopen) - incoming_packet(context, urb); - break; - - default: - printk(KERN_WARNING "%s: status (%d): ignored", - __func__, urb->status); - break; - } - - usb_submit_urb(context->rx_urb, GFP_ATOMIC); - return; -} - - - -/** - * Callback function for USB core API: Probe - */ -static int sasem_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *dev = NULL; - struct usb_host_interface *iface_desc = NULL; - struct usb_endpoint_descriptor *rx_endpoint = NULL; - struct usb_endpoint_descriptor *tx_endpoint = NULL; - struct urb *rx_urb = NULL; - struct urb *tx_urb = NULL; - struct lirc_driver *driver = NULL; - struct lirc_buffer *rbuf = NULL; - int lirc_minor = 0; - int num_endpoints; - int retval = 0; - int vfd_ep_found; - int ir_ep_found; - int alloc_status; - struct sasem_context *context = NULL; - int i; - - printk(KERN_INFO "%s: found Sasem device\n", __func__); - - - dev = usb_get_dev(interface_to_usbdev(interface)); - iface_desc = interface->cur_altsetting; - num_endpoints = iface_desc->desc.bNumEndpoints; - - /* - * Scan the endpoint list and set: - * first input endpoint = IR endpoint - * first output endpoint = VFD endpoint - */ - - ir_ep_found = 0; - vfd_ep_found = 0; - - for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) { - - struct usb_endpoint_descriptor *ep; - int ep_dir; - int ep_type; - ep = &iface_desc->endpoint [i].desc; - ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; - ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - - if (!ir_ep_found && - ep_dir == USB_DIR_IN && - ep_type == USB_ENDPOINT_XFER_INT) { - - rx_endpoint = ep; - ir_ep_found = 1; - if (debug) - printk(KERN_INFO "%s: found IR endpoint\n", - __func__); - - } else if (!vfd_ep_found && - ep_dir == USB_DIR_OUT && - ep_type == USB_ENDPOINT_XFER_INT) { - - tx_endpoint = ep; - vfd_ep_found = 1; - if (debug) - printk(KERN_INFO "%s: found VFD endpoint\n", - __func__); - } - } - - /* Input endpoint is mandatory */ - if (!ir_ep_found) { - - err("%s: no valid input (IR) endpoint found.", __func__); - retval = -ENODEV; - goto exit; - } - - if (!vfd_ep_found) - printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n", - __func__); - - - /* Allocate memory */ - alloc_status = 0; - - context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL); - if (!context) { - err("%s: kzalloc failed for context", __func__); - alloc_status = 1; - goto alloc_status_switch; - } - driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); - if (!driver) { - err("%s: kzalloc failed for lirc_driver", __func__); - alloc_status = 2; - goto alloc_status_switch; - } - rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); - if (!rbuf) { - err("%s: kmalloc failed for lirc_buffer", __func__); - alloc_status = 3; - goto alloc_status_switch; - } - if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { - err("%s: lirc_buffer_init failed", __func__); - alloc_status = 4; - goto alloc_status_switch; - } - rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rx_urb) { - err("%s: usb_alloc_urb failed for IR urb", __func__); - alloc_status = 5; - goto alloc_status_switch; - } - if (vfd_ep_found) { - tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!tx_urb) { - err("%s: usb_alloc_urb failed for VFD urb", - __func__); - alloc_status = 6; - goto alloc_status_switch; - } - } - - mutex_init(&context->ctx_lock); - - strcpy(driver->name, MOD_NAME); - driver->minor = -1; - driver->code_length = 64; - driver->sample_rate = 0; - driver->features = LIRC_CAN_REC_LIRCCODE; - driver->data = context; - driver->rbuf = rbuf; - driver->set_use_inc = ir_open; - driver->set_use_dec = ir_close; - driver->dev = &interface->dev; - driver->owner = THIS_MODULE; - - mutex_lock(&context->ctx_lock); - - lirc_minor = lirc_register_driver(driver); - if (lirc_minor < 0) { - err("%s: lirc_register_driver failed", __func__); - alloc_status = 7; - retval = lirc_minor; - goto unlock; - } else - printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n", - __func__, lirc_minor); - -alloc_status_switch: - - switch (alloc_status) { - - case 7: - if (vfd_ep_found) - usb_free_urb(tx_urb); - case 6: - usb_free_urb(rx_urb); - case 5: - lirc_buffer_free(rbuf); - case 4: - kfree(rbuf); - case 3: - kfree(driver); - case 2: - kfree(context); - context = NULL; - case 1: - retval = -ENOMEM; - goto unlock; - } - - /* Needed while unregistering! */ - driver->minor = lirc_minor; - - context->dev = dev; - context->dev_present = 1; - context->rx_endpoint = rx_endpoint; - context->rx_urb = rx_urb; - if (vfd_ep_found) { - context->tx_endpoint = tx_endpoint; - context->tx_urb = tx_urb; - context->vfd_contrast = 1000; /* range 0 - 1000 */ - } - context->driver = driver; - - usb_set_intfdata(interface, context); - - if (vfd_ep_found) { - - if (debug) - printk(KERN_INFO "Registering VFD with sysfs\n"); - if (usb_register_dev(interface, &sasem_class)) - /* Not a fatal error, so ignore */ - printk(KERN_INFO "%s: could not get a minor number " - "for VFD\n", __func__); - } - - printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n", - __func__, dev->bus->busnum, dev->devnum); -unlock: - mutex_unlock(&context->ctx_lock); -exit: - return retval; -} - -/** - * Callback function for USB core API: disonnect - */ -static void sasem_disconnect(struct usb_interface *interface) -{ - struct sasem_context *context; - - /* prevent races with ir_open()/vfd_open() */ - mutex_lock(&disconnect_lock); - - context = usb_get_intfdata(interface); - mutex_lock(&context->ctx_lock); - - printk(KERN_INFO "%s: Sasem device disconnected\n", __func__); - - usb_set_intfdata(interface, NULL); - context->dev_present = 0; - - /* Stop reception */ - usb_kill_urb(context->rx_urb); - - /* Abort ongoing write */ - if (atomic_read(&context->tx.busy)) { - - usb_kill_urb(context->tx_urb); - wait_for_completion(&context->tx.finished); - } - - /* De-register from lirc_dev if IR port is not open */ - if (!context->ir_isopen) - deregister_from_lirc(context); - - usb_deregister_dev(interface, &sasem_class); - - mutex_unlock(&context->ctx_lock); - - if (!context->ir_isopen && !context->vfd_isopen) - delete_context(context); - - mutex_unlock(&disconnect_lock); -} - -static int __init sasem_init(void) -{ - int rc; - - printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n"); - printk(KERN_INFO MOD_AUTHOR "\n"); - - rc = usb_register(&sasem_driver); - if (rc < 0) { - err("%s: usb register failed (%d)", __func__, rc); - return -ENODEV; - } - return 0; -} - -static void __exit sasem_exit(void) -{ - usb_deregister(&sasem_driver); - printk(KERN_INFO "module removed. Goodbye!\n"); -} - - -module_init(sasem_init); -module_exit(sasem_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_serial.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_serial.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_serial.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_serial.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1317 +0,0 @@ -/* - * lirc_serial.c - * - * lirc_serial - Device driver that records pulse- and pause-lengths - * (space-lengths) between DDCD event on a serial port. - * - * Copyright (C) 1996,97 Ralph Metzler - * Copyright (C) 1998 Trent Piepho - * Copyright (C) 1998 Ben Pfaff - * Copyright (C) 1999 Christoph Bartelmus - * Copyright (C) 2007 Andrei Tanas (suspend/resume support) - * 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, or - * (at your option) any later version. - * - * 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 - * - */ - -/* - * Steve's changes to improve transmission fidelity: - * - for systems with the rdtsc instruction and the clock counter, a - * send_pule that times the pulses directly using the counter. - * This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is - * not needed. Measurement shows very stable waveform, even where - * PCI activity slows the access to the UART, which trips up other - * versions. - * - For other system, non-integer-microsecond pulse/space lengths, - * done using fixed point binary. So, much more accurate carrier - * frequency. - * - fine tuned transmitter latency, taking advantage of fractional - * microseconds in previous change - * - Fixed bug in the way transmitter latency was accounted for by - * tuning the pulse lengths down - the send_pulse routine ignored - * this overhead as it timed the overall pulse length - so the - * pulse frequency was right but overall pulse length was too - * long. Fixed by accounting for latency on each pulse/space - * iteration. - * - * Steve Davies July 2001 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifdef CONFIG_LIRC_SERIAL_NSLU2 -#include -#endif -/* From Intel IXP42X Developer's Manual (#252480-005): */ -/* ftp://download.intel.com/design/network/manuals/25248005.pdf */ -#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ -#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ - -#include -#include - -#define LIRC_DRIVER_NAME "lirc_serial" - -struct lirc_serial { - int signal_pin; - int signal_pin_change; - u8 on; - u8 off; - long (*send_pulse)(unsigned long length); - void (*send_space)(long length); - int features; - spinlock_t lock; -}; - -#define LIRC_HOMEBREW 0 -#define LIRC_IRDEO 1 -#define LIRC_IRDEO_REMOTE 2 -#define LIRC_ANIMAX 3 -#define LIRC_IGOR 4 -#define LIRC_NSLU2 5 - -/*** module parameters ***/ -static int type; -static int io; -static int irq; -static int iommap; -static int ioshift; -static int softcarrier = 1; -static int share_irq; -static int debug; -static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ -static int txsense; /* 0 = active high, 1 = active low */ - -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ - fmt, ## args); \ - } while (0) - -/* forward declarations */ -static long send_pulse_irdeo(unsigned long length); -static long send_pulse_homebrew(unsigned long length); -static void send_space_irdeo(long length); -static void send_space_homebrew(long length); - -static struct lirc_serial hardware[] = { - [LIRC_HOMEBREW] = { - .signal_pin = UART_MSR_DCD, - .signal_pin_change = UART_MSR_DDCD, - .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), - .off = (UART_MCR_RTS | UART_MCR_OUT2), - .send_pulse = send_pulse_homebrew, - .send_space = send_space_homebrew, -#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER - .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SET_SEND_CARRIER | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -#else - .features = LIRC_CAN_REC_MODE2 -#endif - }, - - [LIRC_IRDEO] = { - .signal_pin = UART_MSR_DSR, - .signal_pin_change = UART_MSR_DDSR, - .on = UART_MCR_OUT2, - .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .send_pulse = send_pulse_irdeo, - .send_space = send_space_irdeo, - .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) - }, - - [LIRC_IRDEO_REMOTE] = { - .signal_pin = UART_MSR_DSR, - .signal_pin_change = UART_MSR_DDSR, - .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .send_pulse = send_pulse_irdeo, - .send_space = send_space_irdeo, - .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) - }, - - [LIRC_ANIMAX] = { - .signal_pin = UART_MSR_DCD, - .signal_pin_change = UART_MSR_DDCD, - .on = 0, - .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .send_pulse = NULL, - .send_space = NULL, - .features = LIRC_CAN_REC_MODE2 - }, - - [LIRC_IGOR] = { - .signal_pin = UART_MSR_DSR, - .signal_pin_change = UART_MSR_DDSR, - .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), - .off = (UART_MCR_RTS | UART_MCR_OUT2), - .send_pulse = send_pulse_homebrew, - .send_space = send_space_homebrew, -#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER - .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SET_SEND_CARRIER | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -#else - .features = LIRC_CAN_REC_MODE2 -#endif - }, - -#ifdef CONFIG_LIRC_SERIAL_NSLU2 - /* - * Modified Linksys Network Storage Link USB 2.0 (NSLU2): - * We receive on CTS of the 2nd serial port (R142,LHS), we - * transmit with a IR diode between GPIO[1] (green status LED), - * and ground (Matthias Goebl ). - * See also http://www.nslu2-linux.org for this device - */ - [LIRC_NSLU2] = { - .signal_pin = UART_MSR_CTS, - .signal_pin_change = UART_MSR_DCTS, - .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), - .off = (UART_MCR_RTS | UART_MCR_OUT2), - .send_pulse = send_pulse_homebrew, - .send_space = send_space_homebrew, -#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER - .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SET_SEND_CARRIER | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -#else - .features = LIRC_CAN_REC_MODE2 -#endif - }, -#endif - -}; - -#define RS_ISR_PASS_LIMIT 256 - -/* - * A long pulse code from a remote might take up to 300 bytes. The - * daemon should read the bytes as soon as they are generated, so take - * the number of keys you think you can push before the daemon runs - * and multiply by 300. The driver will warn you if you overrun this - * buffer. If you have a slow computer or non-busmastering IDE disks, - * maybe you will need to increase this. - */ - -/* This MUST be a power of two! It has to be larger than 1 as well. */ - -#define RBUF_LEN 256 - -static struct timeval lasttv = {0, 0}; - -static struct lirc_buffer rbuf; - -static unsigned int freq = 38000; -static unsigned int duty_cycle = 50; - -/* Initialized in init_timing_params() */ -static unsigned long period; -static unsigned long pulse_width; -static unsigned long space_width; - -#if defined(__i386__) -/* - * From: - * Linux I/O port programming mini-HOWTO - * Author: Riku Saikkonen - * v, 28 December 1997 - * - * [...] - * Actually, a port I/O instruction on most ports in the 0-0x3ff range - * takes almost exactly 1 microsecond, so if you're, for example, using - * the parallel port directly, just do additional inb()s from that port - * to delay. - * [...] - */ -/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from - * comment above plus trimming to match actual measured frequency. - * This will be sensitive to cpu speed, though hopefully most of the 1.5us - * is spent in the uart access. Still - for reference test machine was a - * 1.13GHz Athlon system - Steve - */ - -/* - * changed from 400 to 450 as this works better on slower machines; - * faster machines will use the rdtsc code anyway - */ -#define LIRC_SERIAL_TRANSMITTER_LATENCY 450 - -#else - -/* does anybody have information on other platforms ? */ -/* 256 = 1<<8 */ -#define LIRC_SERIAL_TRANSMITTER_LATENCY 256 - -#endif /* __i386__ */ -/* - * FIXME: should we be using hrtimers instead of this - * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense? - */ - -/* fetch serial input packet (1 byte) from register offset */ -static u8 sinp(int offset) -{ - if (iommap != 0) - /* the register is memory-mapped */ - offset <<= ioshift; - - return inb(io + offset); -} - -/* write serial output packet (1 byte) of value to register offset */ -static void soutp(int offset, u8 value) -{ - if (iommap != 0) - /* the register is memory-mapped */ - offset <<= ioshift; - - outb(value, io + offset); -} - -static void on(void) -{ -#ifdef CONFIG_LIRC_SERIAL_NSLU2 - /* - * On NSLU2, we put the transmit diode between the output of the green - * status LED and ground - */ - if (type == LIRC_NSLU2) { - gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW); - return; - } -#endif - if (txsense) - soutp(UART_MCR, hardware[type].off); - else - soutp(UART_MCR, hardware[type].on); -} - -static void off(void) -{ -#ifdef CONFIG_LIRC_SERIAL_NSLU2 - if (type == LIRC_NSLU2) { - gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH); - return; - } -#endif - if (txsense) - soutp(UART_MCR, hardware[type].on); - else - soutp(UART_MCR, hardware[type].off); -} - -#ifndef MAX_UDELAY_MS -#define MAX_UDELAY_US 5000 -#else -#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -#endif - -static void safe_udelay(unsigned long usecs) -{ - while (usecs > MAX_UDELAY_US) { - udelay(MAX_UDELAY_US); - usecs -= MAX_UDELAY_US; - } - udelay(usecs); -} - -#ifdef USE_RDTSC -/* - * This is an overflow/precision juggle, complicated in that we can't - * do long long divide in the kernel - */ - -/* - * When we use the rdtsc instruction to measure clocks, we keep the - * pulse and space widths as clock cycles. As this is CPU speed - * dependent, the widths must be calculated in init_port and ioctl - * time - */ - -/* So send_pulse can quickly convert microseconds to clocks */ -static unsigned long conv_us_to_clocks; - -static int init_timing_params(unsigned int new_duty_cycle, - unsigned int new_freq) -{ - __u64 loops_per_sec, work; - - duty_cycle = new_duty_cycle; - freq = new_freq; - - loops_per_sec = __this_cpu_read(cpu.info.loops_per_jiffy); - loops_per_sec *= HZ; - - /* How many clocks in a microsecond?, avoiding long long divide */ - work = loops_per_sec; - work *= 4295; /* 4295 = 2^32 / 1e6 */ - conv_us_to_clocks = (work >> 32); - - /* - * Carrier period in clocks, approach good up to 32GHz clock, - * gets carrier frequency within 8Hz - */ - period = loops_per_sec >> 3; - period /= (freq >> 3); - - /* Derive pulse and space from the period */ - pulse_width = period * duty_cycle / 100; - space_width = period - pulse_width; - dprintk("in init_timing_params, freq=%d, duty_cycle=%d, " - "clk/jiffy=%ld, pulse=%ld, space=%ld, " - "conv_us_to_clocks=%ld\n", - freq, duty_cycle, __this_cpu_read(cpu_info.loops_per_jiffy), - pulse_width, space_width, conv_us_to_clocks); - return 0; -} -#else /* ! USE_RDTSC */ -static int init_timing_params(unsigned int new_duty_cycle, - unsigned int new_freq) -{ -/* - * period, pulse/space width are kept with 8 binary places - - * IE multiplied by 256. - */ - if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= - LIRC_SERIAL_TRANSMITTER_LATENCY) - return -EINVAL; - if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= - LIRC_SERIAL_TRANSMITTER_LATENCY) - return -EINVAL; - duty_cycle = new_duty_cycle; - freq = new_freq; - period = 256 * 1000000L / freq; - pulse_width = period * duty_cycle / 100; - space_width = period - pulse_width; - dprintk("in init_timing_params, freq=%d pulse=%ld, " - "space=%ld\n", freq, pulse_width, space_width); - return 0; -} -#endif /* USE_RDTSC */ - - -/* return value: space length delta */ - -static long send_pulse_irdeo(unsigned long length) -{ - long rawbits, ret; - int i; - unsigned char output; - unsigned char chunk, shifted; - - /* how many bits have to be sent ? */ - rawbits = length * 1152 / 10000; - if (duty_cycle > 50) - chunk = 3; - else - chunk = 1; - for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { - shifted = chunk << (i * 3); - shifted >>= 1; - output &= (~shifted); - i++; - if (i == 3) { - soutp(UART_TX, output); - while (!(sinp(UART_LSR) & UART_LSR_THRE)) - ; - output = 0x7f; - i = 0; - } - } - if (i != 0) { - soutp(UART_TX, output); - while (!(sinp(UART_LSR) & UART_LSR_TEMT)) - ; - } - - if (i == 0) - ret = (-rawbits) * 10000 / 1152; - else - ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152; - - return ret; -} - -#ifdef USE_RDTSC -/* Version that uses Pentium rdtsc instruction to measure clocks */ - -/* - * This version does sub-microsecond timing using rdtsc instruction, - * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY - * Implicitly i586 architecture... - Steve - */ - -static long send_pulse_homebrew_softcarrier(unsigned long length) -{ - int flag; - unsigned long target, start, now; - - /* Get going quick as we can */ - rdtscl(start); - on(); - /* Convert length from microseconds to clocks */ - length *= conv_us_to_clocks; - /* And loop till time is up - flipping at right intervals */ - now = start; - target = pulse_width; - flag = 1; - /* - * FIXME: This looks like a hard busy wait, without even an occasional, - * polite, cpu_relax() call. There's got to be a better way? - * - * The i2c code has the result of a lot of bit-banging work, I wonder if - * there's something there which could be helpful here. - */ - while ((now - start) < length) { - /* Delay till flip time */ - do { - rdtscl(now); - } while ((now - start) < target); - - /* flip */ - if (flag) { - rdtscl(now); - off(); - target += space_width; - } else { - rdtscl(now); on(); - target += pulse_width; - } - flag = !flag; - } - rdtscl(now); - return ((now - start) - length) / conv_us_to_clocks; -} -#else /* ! USE_RDTSC */ -/* Version using udelay() */ - -/* - * here we use fixed point arithmetic, with 8 - * fractional bits. that gets us within 0.1% or so of the right average - * frequency, albeit with some jitter in pulse length - Steve - */ - -/* To match 8 fractional bits used for pulse/space length */ - -static long send_pulse_homebrew_softcarrier(unsigned long length) -{ - int flag; - unsigned long actual, target, d; - length <<= 8; - - actual = 0; target = 0; flag = 0; - while (actual < length) { - if (flag) { - off(); - target += space_width; - } else { - on(); - target += pulse_width; - } - d = (target - actual - - LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8; - /* - * Note - we've checked in ioctl that the pulse/space - * widths are big enough so that d is > 0 - */ - udelay(d); - actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY; - flag = !flag; - } - return (actual-length) >> 8; -} -#endif /* USE_RDTSC */ - -static long send_pulse_homebrew(unsigned long length) -{ - if (length <= 0) - return 0; - - if (softcarrier) - return send_pulse_homebrew_softcarrier(length); - else { - on(); - safe_udelay(length); - return 0; - } -} - -static void send_space_irdeo(long length) -{ - if (length <= 0) - return; - - safe_udelay(length); -} - -static void send_space_homebrew(long length) -{ - off(); - if (length <= 0) - return; - safe_udelay(length); -} - -static void rbwrite(int l) -{ - if (lirc_buffer_full(&rbuf)) { - /* no new signals will be accepted */ - dprintk("Buffer overrun\n"); - return; - } - lirc_buffer_write(&rbuf, (void *)&l); -} - -static void frbwrite(int l) -{ - /* simple noise filter */ - static int pulse, space; - static unsigned int ptr; - - if (ptr > 0 && (l & PULSE_BIT)) { - pulse += l & PULSE_MASK; - if (pulse > 250) { - rbwrite(space); - rbwrite(pulse | PULSE_BIT); - ptr = 0; - pulse = 0; - } - return; - } - if (!(l & PULSE_BIT)) { - if (ptr == 0) { - if (l > 20000) { - space = l; - ptr++; - return; - } - } else { - if (l > 20000) { - space += pulse; - if (space > PULSE_MASK) - space = PULSE_MASK; - space += l; - if (space > PULSE_MASK) - space = PULSE_MASK; - pulse = 0; - return; - } - rbwrite(space); - rbwrite(pulse | PULSE_BIT); - ptr = 0; - pulse = 0; - } - } - rbwrite(l); -} - -static irqreturn_t irq_handler(int i, void *blah) -{ - struct timeval tv; - int counter, dcd; - u8 status; - long deltv; - int data; - static int last_dcd = -1; - - if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { - /* not our interrupt */ - return IRQ_NONE; - } - - counter = 0; - do { - counter++; - status = sinp(UART_MSR); - if (counter > RS_ISR_PASS_LIMIT) { - printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " - "We're caught!\n"); - break; - } - if ((status & hardware[type].signal_pin_change) - && sense != -1) { - /* get current time */ - do_gettimeofday(&tv); - - /* New mode, written by Trent Piepho - . */ - - /* - * The old format was not very portable. - * We now use an int to pass pulses - * and spaces to user space. - * - * If PULSE_BIT is set a pulse has been - * received, otherwise a space has been - * received. The driver needs to know if your - * receiver is active high or active low, or - * the space/pulse sense could be - * inverted. The bits denoted by PULSE_MASK are - * the length in microseconds. Lengths greater - * than or equal to 16 seconds are clamped to - * PULSE_MASK. All other bits are unused. - * This is a much simpler interface for user - * programs, as well as eliminating "out of - * phase" errors with space/pulse - * autodetection. - */ - - /* calc time since last interrupt in microseconds */ - dcd = (status & hardware[type].signal_pin) ? 1 : 0; - - if (dcd == last_dcd) { - printk(KERN_WARNING LIRC_DRIVER_NAME - ": ignoring spike: %d %d %lx %lx %lx %lx\n", - dcd, sense, - tv.tv_sec, lasttv.tv_sec, - tv.tv_usec, lasttv.tv_usec); - continue; - } - - deltv = tv.tv_sec-lasttv.tv_sec; - if (tv.tv_sec < lasttv.tv_sec || - (tv.tv_sec == lasttv.tv_sec && - tv.tv_usec < lasttv.tv_usec)) { - printk(KERN_WARNING LIRC_DRIVER_NAME - ": AIEEEE: your clock just jumped " - "backwards\n"); - printk(KERN_WARNING LIRC_DRIVER_NAME - ": %d %d %lx %lx %lx %lx\n", - dcd, sense, - tv.tv_sec, lasttv.tv_sec, - tv.tv_usec, lasttv.tv_usec); - data = PULSE_MASK; - } else if (deltv > 15) { - data = PULSE_MASK; /* really long time */ - if (!(dcd^sense)) { - /* sanity check */ - printk(KERN_WARNING LIRC_DRIVER_NAME - ": AIEEEE: " - "%d %d %lx %lx %lx %lx\n", - dcd, sense, - tv.tv_sec, lasttv.tv_sec, - tv.tv_usec, lasttv.tv_usec); - /* - * detecting pulse while this - * MUST be a space! - */ - sense = sense ? 0 : 1; - } - } else - data = (int) (deltv*1000000 + - tv.tv_usec - - lasttv.tv_usec); - frbwrite(dcd^sense ? data : (data|PULSE_BIT)); - lasttv = tv; - last_dcd = dcd; - wake_up_interruptible(&rbuf.wait_poll); - } - } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ - return IRQ_HANDLED; -} - - -static int hardware_init_port(void) -{ - u8 scratch, scratch2, scratch3; - - /* - * This is a simple port existence test, borrowed from the autoconfig - * function in drivers/serial/8250.c - */ - scratch = sinp(UART_IER); - soutp(UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - scratch2 = sinp(UART_IER) & 0x0f; - soutp(UART_IER, 0x0f); -#ifdef __i386__ - outb(0x00, 0x080); -#endif - scratch3 = sinp(UART_IER) & 0x0f; - soutp(UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0f) { - /* we fail, there's nothing here */ - printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test " - "failed, cannot continue\n"); - return -EINVAL; - } - - - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* First of all, disable all interrupts */ - soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); - - /* Clear registers. */ - sinp(UART_LSR); - sinp(UART_RX); - sinp(UART_IIR); - sinp(UART_MSR); - -#ifdef CONFIG_LIRC_SERIAL_NSLU2 - if (type == LIRC_NSLU2) { - /* Setup NSLU2 UART */ - - /* Enable UART */ - soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE); - /* Disable Receiver data Time out interrupt */ - soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE); - /* set out2 = interrupt unmask; off() doesn't set MCR - on NSLU2 */ - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); - } -#endif - - /* Set line for power source */ - off(); - - /* Clear registers again to be sure. */ - sinp(UART_LSR); - sinp(UART_RX); - sinp(UART_IIR); - sinp(UART_MSR); - - switch (type) { - case LIRC_IRDEO: - case LIRC_IRDEO_REMOTE: - /* setup port to 7N1 @ 115200 Baud */ - /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ - - /* Set DLAB 1. */ - soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); - /* Set divisor to 1 => 115200 Baud */ - soutp(UART_DLM, 0); - soutp(UART_DLL, 1); - /* Set DLAB 0 + 7N1 */ - soutp(UART_LCR, UART_LCR_WLEN7); - /* THR interrupt already disabled at this point */ - break; - default: - break; - } - - return 0; -} - -static int init_port(void) -{ - int i, nlow, nhigh; - - /* Reserve io region. */ - /* - * Future MMAP-Developers: Attention! - * For memory mapped I/O you *might* need to use ioremap() first, - * for the NSLU2 it's done in boot code. - */ - if (((iommap != 0) - && (request_mem_region(iommap, 8 << ioshift, - LIRC_DRIVER_NAME) == NULL)) - || ((iommap == 0) - && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) { - printk(KERN_ERR LIRC_DRIVER_NAME - ": port %04x already in use\n", io); - printk(KERN_WARNING LIRC_DRIVER_NAME - ": use 'setserial /dev/ttySX uart none'\n"); - printk(KERN_WARNING LIRC_DRIVER_NAME - ": or compile the serial port driver as module and\n"); - printk(KERN_WARNING LIRC_DRIVER_NAME - ": make sure this module is loaded first\n"); - return -EBUSY; - } - - if (hardware_init_port() < 0) - return -EINVAL; - - /* Initialize pulse/space widths */ - init_timing_params(duty_cycle, freq); - - /* If pin is high, then this must be an active low receiver. */ - if (sense == -1) { - /* wait 1/2 sec for the power supply */ - msleep(500); - - /* - * probe 9 times every 0.04s, collect "votes" for - * active high/low - */ - nlow = 0; - nhigh = 0; - for (i = 0; i < 9; i++) { - if (sinp(UART_MSR) & hardware[type].signal_pin) - nlow++; - else - nhigh++; - msleep(40); - } - sense = (nlow >= nhigh ? 1 : 0); - printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " - "%s receiver\n", sense ? "low" : "high"); - } else - printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " - "%s receiver\n", sense ? "low" : "high"); - - return 0; -} - -static int set_use_inc(void *data) -{ - int result; - unsigned long flags; - - /* initialize timestamp */ - do_gettimeofday(&lasttv); - - result = request_irq(irq, irq_handler, - IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0), - LIRC_DRIVER_NAME, (void *)&hardware); - - switch (result) { - case -EBUSY: - printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); - return -EBUSY; - case -EINVAL: - printk(KERN_ERR LIRC_DRIVER_NAME - ": Bad irq number or handler\n"); - return -EINVAL; - default: - dprintk("Interrupt %d, port %04x obtained\n", irq, io); - break; - }; - - spin_lock_irqsave(&hardware[type].lock, flags); - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); - - spin_unlock_irqrestore(&hardware[type].lock, flags); - - return 0; -} - -static void set_use_dec(void *data) -{ unsigned long flags; - - spin_lock_irqsave(&hardware[type].lock, flags); - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* First of all, disable all interrupts */ - soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); - spin_unlock_irqrestore(&hardware[type].lock, flags); - - free_irq(irq, (void *)&hardware); - - dprintk("freed IRQ %d\n", irq); -} - -static ssize_t lirc_write(struct file *file, const char *buf, - size_t n, loff_t *ppos) -{ - int i, count; - unsigned long flags; - long delta = 0; - int *wbuf; - - if (!(hardware[type].features & LIRC_CAN_SEND_PULSE)) - return -EBADF; - - count = n / sizeof(int); - if (n % sizeof(int) || count % 2 == 0) - return -EINVAL; - wbuf = memdup_user(buf, n); - if (IS_ERR(wbuf)) - return PTR_ERR(wbuf); - spin_lock_irqsave(&hardware[type].lock, flags); - if (type == LIRC_IRDEO) { - /* DTR, RTS down */ - on(); - } - for (i = 0; i < count; i++) { - if (i%2) - hardware[type].send_space(wbuf[i] - delta); - else - delta = hardware[type].send_pulse(wbuf[i]); - } - off(); - spin_unlock_irqrestore(&hardware[type].lock, flags); - kfree(wbuf); - return n; -} - -static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - int result; - __u32 value; - - switch (cmd) { - case LIRC_GET_SEND_MODE: - if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) - return -ENOIOCTLCMD; - - result = put_user(LIRC_SEND2MODE - (hardware[type].features&LIRC_CAN_SEND_MASK), - (__u32 *) arg); - if (result) - return result; - break; - - case LIRC_SET_SEND_MODE: - if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) - return -ENOIOCTLCMD; - - result = get_user(value, (__u32 *) arg); - if (result) - return result; - /* only LIRC_MODE_PULSE supported */ - if (value != LIRC_MODE_PULSE) - return -ENOSYS; - break; - - case LIRC_GET_LENGTH: - return -ENOSYS; - break; - - case LIRC_SET_SEND_DUTY_CYCLE: - dprintk("SET_SEND_DUTY_CYCLE\n"); - if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) - return -ENOIOCTLCMD; - - result = get_user(value, (__u32 *) arg); - if (result) - return result; - if (value <= 0 || value > 100) - return -EINVAL; - return init_timing_params(value, freq); - break; - - case LIRC_SET_SEND_CARRIER: - dprintk("SET_SEND_CARRIER\n"); - if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) - return -ENOIOCTLCMD; - - result = get_user(value, (__u32 *) arg); - if (result) - return result; - if (value > 500000 || value < 20000) - return -EINVAL; - return init_timing_params(duty_cycle, value); - break; - - default: - return lirc_dev_fop_ioctl(filep, cmd, arg); - } - return 0; -} - -static const struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .write = lirc_write, - .unlocked_ioctl = lirc_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = lirc_ioctl, -#endif - .read = lirc_dev_fop_read, - .poll = lirc_dev_fop_poll, - .open = lirc_dev_fop_open, - .release = lirc_dev_fop_close, - .llseek = no_llseek, -}; - -static struct lirc_driver driver = { - .name = LIRC_DRIVER_NAME, - .minor = -1, - .code_length = 1, - .sample_rate = 0, - .data = NULL, - .add_to_buf = NULL, - .rbuf = &rbuf, - .set_use_inc = set_use_inc, - .set_use_dec = set_use_dec, - .fops = &lirc_fops, - .dev = NULL, - .owner = THIS_MODULE, -}; - -static struct platform_device *lirc_serial_dev; - -static int __devinit lirc_serial_probe(struct platform_device *dev) -{ - return 0; -} - -static int __devexit lirc_serial_remove(struct platform_device *dev) -{ - return 0; -} - -static int lirc_serial_suspend(struct platform_device *dev, - pm_message_t state) -{ - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* Disable all interrupts */ - soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); - - /* Clear registers. */ - sinp(UART_LSR); - sinp(UART_RX); - sinp(UART_IIR); - sinp(UART_MSR); - - return 0; -} - -/* twisty maze... need a forward-declaration here... */ -static void lirc_serial_exit(void); - -static int lirc_serial_resume(struct platform_device *dev) -{ - unsigned long flags; - - if (hardware_init_port() < 0) { - lirc_serial_exit(); - return -EINVAL; - } - - spin_lock_irqsave(&hardware[type].lock, flags); - /* Enable Interrupt */ - do_gettimeofday(&lasttv); - soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); - off(); - - lirc_buffer_clear(&rbuf); - - spin_unlock_irqrestore(&hardware[type].lock, flags); - - return 0; -} - -static struct platform_driver lirc_serial_driver = { - .probe = lirc_serial_probe, - .remove = __devexit_p(lirc_serial_remove), - .suspend = lirc_serial_suspend, - .resume = lirc_serial_resume, - .driver = { - .name = "lirc_serial", - .owner = THIS_MODULE, - }, -}; - -static int __init lirc_serial_init(void) -{ - int result; - - /* Init read buffer. */ - result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); - if (result < 0) - return -ENOMEM; - - result = platform_driver_register(&lirc_serial_driver); - if (result) { - printk("lirc register returned %d\n", result); - goto exit_buffer_free; - } - - lirc_serial_dev = platform_device_alloc("lirc_serial", 0); - if (!lirc_serial_dev) { - result = -ENOMEM; - goto exit_driver_unregister; - } - - result = platform_device_add(lirc_serial_dev); - if (result) - goto exit_device_put; - - return 0; - -exit_device_put: - platform_device_put(lirc_serial_dev); -exit_driver_unregister: - platform_driver_unregister(&lirc_serial_driver); -exit_buffer_free: - lirc_buffer_free(&rbuf); - return result; -} - -static void lirc_serial_exit(void) -{ - platform_device_unregister(lirc_serial_dev); - platform_driver_unregister(&lirc_serial_driver); - lirc_buffer_free(&rbuf); -} - -static int __init lirc_serial_init_module(void) -{ - int result; - - result = lirc_serial_init(); - if (result) - return result; - - switch (type) { - case LIRC_HOMEBREW: - case LIRC_IRDEO: - case LIRC_IRDEO_REMOTE: - case LIRC_ANIMAX: - case LIRC_IGOR: - /* if nothing specified, use ttyS0/com1 and irq 4 */ - io = io ? io : 0x3f8; - irq = irq ? irq : 4; - break; -#ifdef CONFIG_LIRC_SERIAL_NSLU2 - case LIRC_NSLU2: - io = io ? io : IRQ_IXP4XX_UART2; - irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET); - iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS; - ioshift = ioshift ? ioshift : 2; - break; -#endif - default: - result = -EINVAL; - goto exit_serial_exit; - } - if (!softcarrier) { - switch (type) { - case LIRC_HOMEBREW: - case LIRC_IGOR: -#ifdef CONFIG_LIRC_SERIAL_NSLU2 - case LIRC_NSLU2: -#endif - hardware[type].features &= - ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| - LIRC_CAN_SET_SEND_CARRIER); - break; - } - } - - result = init_port(); - if (result < 0) - goto exit_serial_exit; - driver.features = hardware[type].features; - driver.dev = &lirc_serial_dev->dev; - driver.minor = lirc_register_driver(&driver); - if (driver.minor < 0) { - printk(KERN_ERR LIRC_DRIVER_NAME - ": register_chrdev failed!\n"); - result = -EIO; - goto exit_release; - } - return 0; -exit_release: - release_region(io, 8); -exit_serial_exit: - lirc_serial_exit(); - return result; -} - -static void __exit lirc_serial_exit_module(void) -{ - lirc_serial_exit(); - if (iommap != 0) - release_mem_region(iommap, 8 << ioshift); - else - release_region(io, 8); - lirc_unregister_driver(driver.minor); - dprintk("cleaned up module\n"); -} - - -module_init(lirc_serial_init_module); -module_exit(lirc_serial_exit_module); - -MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); -MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, " - "Christoph Bartelmus, Andrei Tanas"); -MODULE_LICENSE("GPL"); - -module_param(type, int, S_IRUGO); -MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo," - " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug," - " 5 = NSLU2 RX:CTS2/TX:GreenLED)"); - -module_param(io, int, S_IRUGO); -MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); - -/* some architectures (e.g. intel xscale) have memory mapped registers */ -module_param(iommap, bool, S_IRUGO); -MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O" - " (0 = no memory mapped io)"); - -/* - * some architectures (e.g. intel xscale) align the 8bit serial registers - * on 32bit word boundaries. - * See linux-kernel/serial/8250.c serial_in()/out() - */ -module_param(ioshift, int, S_IRUGO); -MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); - -module_param(irq, int, S_IRUGO); -MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); - -module_param(share_irq, bool, S_IRUGO); -MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); - -module_param(sense, bool, S_IRUGO); -MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" - " (0 = active high, 1 = active low )"); - -#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -module_param(txsense, bool, S_IRUGO); -MODULE_PARM_DESC(txsense, "Sense of transmitter circuit" - " (0 = active high, 1 = active low )"); -#endif - -module_param(softcarrier, bool, S_IRUGO); -MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_sir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_sir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_sir.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_sir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1286 +0,0 @@ -/* - * LIRC SIR driver, (C) 2000 Milan Pikula - * - * lirc_sir - Device driver for use with SIR (serial infra red) - * mode of IrDA on many notebooks. - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * - * 2000/09/16 Frank Przybylski : - * added timeout and relaxed pulse detection, removed gap bug - * - * 2000/12/15 Christoph Bartelmus : - * added support for Tekram Irmate 210 (sending does not work yet, - * kind of disappointing that nobody was able to implement that - * before), - * major clean-up - * - * 2001/02/27 Christoph Bartelmus : - * added support for StrongARM SA1100 embedded microprocessor - * parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef LIRC_ON_SA1100 -#include -#ifdef CONFIG_SA1100_COLLIE -#include -#include -#endif -#endif - -#include - -#include -#include - -/* SECTION: Definitions */ - -/*** Tekram dongle ***/ -#ifdef LIRC_SIR_TEKRAM -/* stolen from kernel source */ -/* definitions for Tekram dongle */ -#define TEKRAM_115200 0x00 -#define TEKRAM_57600 0x01 -#define TEKRAM_38400 0x02 -#define TEKRAM_19200 0x03 -#define TEKRAM_9600 0x04 -#define TEKRAM_2400 0x08 - -#define TEKRAM_PW 0x10 /* Pulse select bit */ - -/* 10bit * 1s/115200bit in milliseconds = 87ms*/ -#define TIME_CONST (10000000ul/115200ul) - -#endif - -#ifdef LIRC_SIR_ACTISYS_ACT200L -static void init_act200(void); -#elif defined(LIRC_SIR_ACTISYS_ACT220L) -static void init_act220(void); -#endif - -/*** SA1100 ***/ -#ifdef LIRC_ON_SA1100 -struct sa1100_ser2_registers { - /* HSSP control register */ - unsigned char hscr0; - /* UART registers */ - unsigned char utcr0; - unsigned char utcr1; - unsigned char utcr2; - unsigned char utcr3; - unsigned char utcr4; - unsigned char utdr; - unsigned char utsr0; - unsigned char utsr1; -} sr; - -static int irq = IRQ_Ser2ICP; - -#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0 - -/* pulse/space ratio of 50/50 */ -static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); -/* 1000000/freq-pulse_width */ -static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); -static unsigned int freq = 38000; /* modulation frequency */ -static unsigned int duty_cycle = 50; /* duty cycle of 50% */ - -#endif - -#define RBUF_LEN 1024 -#define WBUF_LEN 1024 - -#define LIRC_DRIVER_NAME "lirc_sir" - -#define PULSE '[' - -#ifndef LIRC_SIR_TEKRAM -/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/ -#define TIME_CONST (9000000ul/115200ul) -#endif - - -/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */ -#define SIR_TIMEOUT (HZ*5/100) - -#ifndef LIRC_ON_SA1100 -#ifndef LIRC_IRQ -#define LIRC_IRQ 4 -#endif -#ifndef LIRC_PORT -/* for external dongles, default to com1 */ -#if defined(LIRC_SIR_ACTISYS_ACT200L) || \ - defined(LIRC_SIR_ACTISYS_ACT220L) || \ - defined(LIRC_SIR_TEKRAM) -#define LIRC_PORT 0x3f8 -#else -/* onboard sir ports are typically com3 */ -#define LIRC_PORT 0x3e8 -#endif -#endif - -static int io = LIRC_PORT; -static int irq = LIRC_IRQ; -static int threshold = 3; -#endif - -static DEFINE_SPINLOCK(timer_lock); -static struct timer_list timerlist; -/* time of last signal change detected */ -static struct timeval last_tv = {0, 0}; -/* time of last UART data ready interrupt */ -static struct timeval last_intr_tv = {0, 0}; -static int last_value; - -static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); - -static DEFINE_SPINLOCK(hardware_lock); - -static int rx_buf[RBUF_LEN]; -static unsigned int rx_tail, rx_head; - -static int debug; -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ - fmt, ## args); \ - } while (0) - -/* SECTION: Prototypes */ - -/* Communication with user-space */ -static unsigned int lirc_poll(struct file *file, poll_table *wait); -static ssize_t lirc_read(struct file *file, char *buf, size_t count, - loff_t *ppos); -static ssize_t lirc_write(struct file *file, const char *buf, size_t n, - loff_t *pos); -static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); -static void add_read_queue(int flag, unsigned long val); -static int init_chrdev(void); -static void drop_chrdev(void); -/* Hardware */ -static irqreturn_t sir_interrupt(int irq, void *dev_id); -static void send_space(unsigned long len); -static void send_pulse(unsigned long len); -static int init_hardware(void); -static void drop_hardware(void); -/* Initialisation */ -static int init_port(void); -static void drop_port(void); - -#ifdef LIRC_ON_SA1100 -static void on(void) -{ - PPSR |= PPC_TXD2; -} - -static void off(void) -{ - PPSR &= ~PPC_TXD2; -} -#else -static inline unsigned int sinp(int offset) -{ - return inb(io + offset); -} - -static inline void soutp(int offset, int value) -{ - outb(value, io + offset); -} -#endif - -#ifndef MAX_UDELAY_MS -#define MAX_UDELAY_US 5000 -#else -#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -#endif - -static void safe_udelay(unsigned long usecs) -{ - while (usecs > MAX_UDELAY_US) { - udelay(MAX_UDELAY_US); - usecs -= MAX_UDELAY_US; - } - udelay(usecs); -} - -/* SECTION: Communication with user-space */ - -static unsigned int lirc_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &lirc_read_queue, wait); - if (rx_head != rx_tail) - return POLLIN | POLLRDNORM; - return 0; -} - -static ssize_t lirc_read(struct file *file, char *buf, size_t count, - loff_t *ppos) -{ - int n = 0; - int retval = 0; - DECLARE_WAITQUEUE(wait, current); - - if (count % sizeof(int)) - return -EINVAL; - - add_wait_queue(&lirc_read_queue, &wait); - set_current_state(TASK_INTERRUPTIBLE); - while (n < count) { - if (rx_head != rx_tail) { - if (copy_to_user((void *) buf + n, - (void *) (rx_buf + rx_head), - sizeof(int))) { - retval = -EFAULT; - break; - } - rx_head = (rx_head + 1) & (RBUF_LEN - 1); - n += sizeof(int); - } else { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - } - remove_wait_queue(&lirc_read_queue, &wait); - set_current_state(TASK_RUNNING); - return n ? n : retval; -} -static ssize_t lirc_write(struct file *file, const char *buf, size_t n, - loff_t *pos) -{ - unsigned long flags; - int i, count; - int *tx_buf; - - count = n / sizeof(int); - if (n % sizeof(int) || count % 2 == 0) - return -EINVAL; - tx_buf = memdup_user(buf, n); - if (IS_ERR(tx_buf)) - return PTR_ERR(tx_buf); - i = 0; -#ifdef LIRC_ON_SA1100 - /* disable receiver */ - Ser2UTCR3 = 0; -#endif - local_irq_save(flags); - while (1) { - if (i >= count) - break; - if (tx_buf[i]) - send_pulse(tx_buf[i]); - i++; - if (i >= count) - break; - if (tx_buf[i]) - send_space(tx_buf[i]); - i++; - } - local_irq_restore(flags); -#ifdef LIRC_ON_SA1100 - off(); - udelay(1000); /* wait 1ms for IR diode to recover */ - Ser2UTCR3 = 0; - /* clear status register to prevent unwanted interrupts */ - Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); - /* enable receiver */ - Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; -#endif - kfree(tx_buf); - return count; -} - -static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - int retval = 0; - __u32 value = 0; -#ifdef LIRC_ON_SA1100 - - if (cmd == LIRC_GET_FEATURES) - value = LIRC_CAN_SEND_PULSE | - LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SET_SEND_CARRIER | - LIRC_CAN_REC_MODE2; - else if (cmd == LIRC_GET_SEND_MODE) - value = LIRC_MODE_PULSE; - else if (cmd == LIRC_GET_REC_MODE) - value = LIRC_MODE_MODE2; -#else - if (cmd == LIRC_GET_FEATURES) - value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; - else if (cmd == LIRC_GET_SEND_MODE) - value = LIRC_MODE_PULSE; - else if (cmd == LIRC_GET_REC_MODE) - value = LIRC_MODE_MODE2; -#endif - - switch (cmd) { - case LIRC_GET_FEATURES: - case LIRC_GET_SEND_MODE: - case LIRC_GET_REC_MODE: - retval = put_user(value, (__u32 *) arg); - break; - - case LIRC_SET_SEND_MODE: - case LIRC_SET_REC_MODE: - retval = get_user(value, (__u32 *) arg); - break; -#ifdef LIRC_ON_SA1100 - case LIRC_SET_SEND_DUTY_CYCLE: - retval = get_user(value, (__u32 *) arg); - if (retval) - return retval; - if (value <= 0 || value > 100) - return -EINVAL; - /* (value/100)*(1000000/freq) */ - duty_cycle = value; - pulse_width = (unsigned long) duty_cycle*10000/freq; - space_width = (unsigned long) 1000000L/freq-pulse_width; - if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) - pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; - if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) - space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; - break; - case LIRC_SET_SEND_CARRIER: - retval = get_user(value, (__u32 *) arg); - if (retval) - return retval; - if (value > 500000 || value < 20000) - return -EINVAL; - freq = value; - pulse_width = (unsigned long) duty_cycle*10000/freq; - space_width = (unsigned long) 1000000L/freq-pulse_width; - if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) - pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; - if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) - space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; - break; -#endif - default: - retval = -ENOIOCTLCMD; - - } - - if (retval) - return retval; - if (cmd == LIRC_SET_REC_MODE) { - if (value != LIRC_MODE_MODE2) - retval = -ENOSYS; - } else if (cmd == LIRC_SET_SEND_MODE) { - if (value != LIRC_MODE_PULSE) - retval = -ENOSYS; - } - - return retval; -} - -static void add_read_queue(int flag, unsigned long val) -{ - unsigned int new_rx_tail; - int newval; - - dprintk("add flag %d with val %lu\n", flag, val); - - newval = val & PULSE_MASK; - - /* - * statistically, pulses are ~TIME_CONST/2 too long. we could - * maybe make this more exact, but this is good enough - */ - if (flag) { - /* pulse */ - if (newval > TIME_CONST/2) - newval -= TIME_CONST/2; - else /* should not ever happen */ - newval = 1; - newval |= PULSE_BIT; - } else { - newval += TIME_CONST/2; - } - new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); - if (new_rx_tail == rx_head) { - dprintk("Buffer overrun.\n"); - return; - } - rx_buf[rx_tail] = newval; - rx_tail = new_rx_tail; - wake_up_interruptible(&lirc_read_queue); -} - -static const struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .read = lirc_read, - .write = lirc_write, - .poll = lirc_poll, - .unlocked_ioctl = lirc_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = lirc_ioctl, -#endif - .open = lirc_dev_fop_open, - .release = lirc_dev_fop_close, - .llseek = no_llseek, -}; - -static int set_use_inc(void *data) -{ - return 0; -} - -static void set_use_dec(void *data) -{ -} - -static struct lirc_driver driver = { - .name = LIRC_DRIVER_NAME, - .minor = -1, - .code_length = 1, - .sample_rate = 0, - .data = NULL, - .add_to_buf = NULL, - .set_use_inc = set_use_inc, - .set_use_dec = set_use_dec, - .fops = &lirc_fops, - .dev = NULL, - .owner = THIS_MODULE, -}; - - -static int init_chrdev(void) -{ - driver.minor = lirc_register_driver(&driver); - if (driver.minor < 0) { - printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); - return -EIO; - } - return 0; -} - -static void drop_chrdev(void) -{ - lirc_unregister_driver(driver.minor); -} - -/* SECTION: Hardware */ -static long delta(struct timeval *tv1, struct timeval *tv2) -{ - unsigned long deltv; - - deltv = tv2->tv_sec - tv1->tv_sec; - if (deltv > 15) - deltv = 0xFFFFFF; - else - deltv = deltv*1000000 + - tv2->tv_usec - - tv1->tv_usec; - return deltv; -} - -static void sir_timeout(unsigned long data) -{ - /* - * if last received signal was a pulse, but receiving stopped - * within the 9 bit frame, we need to finish this pulse and - * simulate a signal change to from pulse to space. Otherwise - * upper layers will receive two sequences next time. - */ - - unsigned long flags; - unsigned long pulse_end; - - /* avoid interference with interrupt */ - spin_lock_irqsave(&timer_lock, flags); - if (last_value) { -#ifndef LIRC_ON_SA1100 - /* clear unread bits in UART and restart */ - outb(UART_FCR_CLEAR_RCVR, io + UART_FCR); -#endif - /* determine 'virtual' pulse end: */ - pulse_end = delta(&last_tv, &last_intr_tv); - dprintk("timeout add %d for %lu usec\n", last_value, pulse_end); - add_read_queue(last_value, pulse_end); - last_value = 0; - last_tv = last_intr_tv; - } - spin_unlock_irqrestore(&timer_lock, flags); -} - -static irqreturn_t sir_interrupt(int irq, void *dev_id) -{ - unsigned char data; - struct timeval curr_tv; - static unsigned long deltv; -#ifdef LIRC_ON_SA1100 - int status; - static int n; - - status = Ser2UTSR0; - /* - * Deal with any receive errors first. The bytes in error may be - * the only bytes in the receive FIFO, so we do this first. - */ - while (status & UTSR0_EIF) { - int bstat; - - if (debug) { - dprintk("EIF\n"); - bstat = Ser2UTSR1; - - if (bstat & UTSR1_FRE) - dprintk("frame error\n"); - if (bstat & UTSR1_ROR) - dprintk("receive fifo overrun\n"); - if (bstat & UTSR1_PRE) - dprintk("parity error\n"); - } - - bstat = Ser2UTDR; - n++; - status = Ser2UTSR0; - } - - if (status & (UTSR0_RFS | UTSR0_RID)) { - do_gettimeofday(&curr_tv); - deltv = delta(&last_tv, &curr_tv); - do { - data = Ser2UTDR; - dprintk("%d data: %u\n", n, (unsigned int) data); - n++; - } while (status & UTSR0_RID && /* do not empty fifo in order to - * get UTSR0_RID in any case */ - Ser2UTSR1 & UTSR1_RNE); /* data ready */ - - if (status&UTSR0_RID) { - add_read_queue(0 , deltv - n * TIME_CONST); /*space*/ - add_read_queue(1, n * TIME_CONST); /*pulse*/ - n = 0; - last_tv = curr_tv; - } - } - - if (status & UTSR0_TFS) - printk(KERN_ERR "transmit fifo not full, shouldn't happen\n"); - - /* We must clear certain bits. */ - status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); - if (status) - Ser2UTSR0 = status; -#else - unsigned long deltintrtv; - unsigned long flags; - int iir, lsr; - - while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { - switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */ - case UART_IIR_MSI: - (void) inb(io + UART_MSR); - break; - case UART_IIR_RLSI: - (void) inb(io + UART_LSR); - break; - case UART_IIR_THRI: -#if 0 - if (lsr & UART_LSR_THRE) /* FIFO is empty */ - outb(data, io + UART_TX) -#endif - break; - case UART_IIR_RDI: - /* avoid interference with timer */ - spin_lock_irqsave(&timer_lock, flags); - do { - del_timer(&timerlist); - data = inb(io + UART_RX); - do_gettimeofday(&curr_tv); - deltv = delta(&last_tv, &curr_tv); - deltintrtv = delta(&last_intr_tv, &curr_tv); - dprintk("t %lu, d %d\n", deltintrtv, (int)data); - /* - * if nothing came in last X cycles, - * it was gap - */ - if (deltintrtv > TIME_CONST * threshold) { - if (last_value) { - dprintk("GAP\n"); - /* simulate signal change */ - add_read_queue(last_value, - deltv - - deltintrtv); - last_value = 0; - last_tv.tv_sec = - last_intr_tv.tv_sec; - last_tv.tv_usec = - last_intr_tv.tv_usec; - deltv = deltintrtv; - } - } - data = 1; - if (data ^ last_value) { - /* - * deltintrtv > 2*TIME_CONST, remember? - * the other case is timeout - */ - add_read_queue(last_value, - deltv-TIME_CONST); - last_value = data; - last_tv = curr_tv; - if (last_tv.tv_usec >= TIME_CONST) { - last_tv.tv_usec -= TIME_CONST; - } else { - last_tv.tv_sec--; - last_tv.tv_usec += 1000000 - - TIME_CONST; - } - } - last_intr_tv = curr_tv; - if (data) { - /* - * start timer for end of - * sequence detection - */ - timerlist.expires = jiffies + - SIR_TIMEOUT; - add_timer(&timerlist); - } - - lsr = inb(io + UART_LSR); - } while (lsr & UART_LSR_DR); /* data ready */ - spin_unlock_irqrestore(&timer_lock, flags); - break; - default: - break; - } - } -#endif - return IRQ_RETVAL(IRQ_HANDLED); -} - -#ifdef LIRC_ON_SA1100 -static void send_pulse(unsigned long length) -{ - unsigned long k, delay; - int flag; - - if (length == 0) - return; - /* - * this won't give us the carrier frequency we really want - * due to integer arithmetic, but we can accept this inaccuracy - */ - - for (k = flag = 0; k < length; k += delay, flag = !flag) { - if (flag) { - off(); - delay = space_width; - } else { - on(); - delay = pulse_width; - } - safe_udelay(delay); - } - off(); -} - -static void send_space(unsigned long length) -{ - if (length == 0) - return; - off(); - safe_udelay(length); -} -#else -static void send_space(unsigned long len) -{ - safe_udelay(len); -} - -static void send_pulse(unsigned long len) -{ - long bytes_out = len / TIME_CONST; - long time_left; - - time_left = (long)len - (long)bytes_out * (long)TIME_CONST; - if (bytes_out == 0) { - bytes_out++; - time_left = 0; - } - while (bytes_out--) { - outb(PULSE, io + UART_TX); - /* FIXME treba seriozne cakanie z char/serial.c */ - while (!(inb(io + UART_LSR) & UART_LSR_THRE)) - ; - } -#if 0 - if (time_left > 0) - safe_udelay(time_left); -#endif -} -#endif - -#ifdef CONFIG_SA1100_COLLIE -static int sa1100_irda_set_power_collie(int state) -{ - if (state) { - /* - * 0 - off - * 1 - short range, lowest power - * 2 - medium range, medium power - * 3 - maximum range, high power - */ - ucb1200_set_io_direction(TC35143_GPIO_IR_ON, - TC35143_IODIR_OUTPUT); - ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW); - udelay(100); - } else { - /* OFF */ - ucb1200_set_io_direction(TC35143_GPIO_IR_ON, - TC35143_IODIR_OUTPUT); - ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH); - } - return 0; -} -#endif - -static int init_hardware(void) -{ - unsigned long flags; - - spin_lock_irqsave(&hardware_lock, flags); - /* reset UART */ -#ifdef LIRC_ON_SA1100 -#ifdef CONFIG_SA1100_BITSY - if (machine_is_bitsy()) { - printk(KERN_INFO "Power on IR module\n"); - set_bitsy_egpio(EGPIO_BITSY_IR_ON); - } -#endif -#ifdef CONFIG_SA1100_COLLIE - sa1100_irda_set_power_collie(3); /* power on */ -#endif - sr.hscr0 = Ser2HSCR0; - - sr.utcr0 = Ser2UTCR0; - sr.utcr1 = Ser2UTCR1; - sr.utcr2 = Ser2UTCR2; - sr.utcr3 = Ser2UTCR3; - sr.utcr4 = Ser2UTCR4; - - sr.utdr = Ser2UTDR; - sr.utsr0 = Ser2UTSR0; - sr.utsr1 = Ser2UTSR1; - - /* configure GPIO */ - /* output */ - PPDR |= PPC_TXD2; - PSDR |= PPC_TXD2; - /* set output to 0 */ - off(); - - /* Enable HP-SIR modulation, and ensure that the port is disabled. */ - Ser2UTCR3 = 0; - Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP); - - /* clear status register to prevent unwanted interrupts */ - Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); - - /* 7N1 */ - Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData; - /* 115200 */ - Ser2UTCR1 = 0; - Ser2UTCR2 = 1; - /* use HPSIR, 1.6 usec pulses */ - Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us; - - /* enable receiver, receive fifo interrupt */ - Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; - - /* clear status register to prevent unwanted interrupts */ - Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); - -#elif defined(LIRC_SIR_TEKRAM) - /* disable FIFO */ - soutp(UART_FCR, - UART_FCR_CLEAR_RCVR| - UART_FCR_CLEAR_XMIT| - UART_FCR_TRIGGER_1); - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* First of all, disable all interrupts */ - soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); - - /* Set DLAB 1. */ - soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); - - /* Set divisor to 12 => 9600 Baud */ - soutp(UART_DLM, 0); - soutp(UART_DLL, 12); - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* power supply */ - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); - safe_udelay(50*1000); - - /* -DTR low -> reset PIC */ - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); - udelay(1*1000); - - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); - udelay(100); - - - /* -RTS low -> send control byte */ - soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); - udelay(7); - soutp(UART_TX, TEKRAM_115200|TEKRAM_PW); - - /* one byte takes ~1042 usec to transmit at 9600,8N1 */ - udelay(1500); - - /* back to normal operation */ - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); - udelay(50); - - udelay(1500); - - /* read previous control byte */ - printk(KERN_INFO LIRC_DRIVER_NAME - ": 0x%02x\n", sinp(UART_RX)); - - /* Set DLAB 1. */ - soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); - - /* Set divisor to 1 => 115200 Baud */ - soutp(UART_DLM, 0); - soutp(UART_DLL, 1); - - /* Set DLAB 0, 8 Bit */ - soutp(UART_LCR, UART_LCR_WLEN8); - /* enable interrupts */ - soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); -#else - outb(0, io + UART_MCR); - outb(0, io + UART_IER); - /* init UART */ - /* set DLAB, speed = 115200 */ - outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR); - outb(1, io + UART_DLL); outb(0, io + UART_DLM); - /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */ - outb(UART_LCR_WLEN7, io + UART_LCR); - /* FIFO operation */ - outb(UART_FCR_ENABLE_FIFO, io + UART_FCR); - /* interrupts */ - /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */ - outb(UART_IER_RDI, io + UART_IER); - /* turn on UART */ - outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR); -#ifdef LIRC_SIR_ACTISYS_ACT200L - init_act200(); -#elif defined(LIRC_SIR_ACTISYS_ACT220L) - init_act220(); -#endif -#endif - spin_unlock_irqrestore(&hardware_lock, flags); - return 0; -} - -static void drop_hardware(void) -{ - unsigned long flags; - - spin_lock_irqsave(&hardware_lock, flags); - -#ifdef LIRC_ON_SA1100 - Ser2UTCR3 = 0; - - Ser2UTCR0 = sr.utcr0; - Ser2UTCR1 = sr.utcr1; - Ser2UTCR2 = sr.utcr2; - Ser2UTCR4 = sr.utcr4; - Ser2UTCR3 = sr.utcr3; - - Ser2HSCR0 = sr.hscr0; -#ifdef CONFIG_SA1100_BITSY - if (machine_is_bitsy()) - clr_bitsy_egpio(EGPIO_BITSY_IR_ON); -#endif -#ifdef CONFIG_SA1100_COLLIE - sa1100_irda_set_power_collie(0); /* power off */ -#endif -#else - /* turn off interrupts */ - outb(0, io + UART_IER); -#endif - spin_unlock_irqrestore(&hardware_lock, flags); -} - -/* SECTION: Initialisation */ - -static int init_port(void) -{ - int retval; - - /* get I/O port access and IRQ line */ -#ifndef LIRC_ON_SA1100 - if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { - printk(KERN_ERR LIRC_DRIVER_NAME - ": i/o port 0x%.4x already in use.\n", io); - return -EBUSY; - } -#endif - retval = request_irq(irq, sir_interrupt, IRQF_DISABLED, - LIRC_DRIVER_NAME, NULL); - if (retval < 0) { -# ifndef LIRC_ON_SA1100 - release_region(io, 8); -# endif - printk(KERN_ERR LIRC_DRIVER_NAME - ": IRQ %d already in use.\n", - irq); - return retval; - } -#ifndef LIRC_ON_SA1100 - printk(KERN_INFO LIRC_DRIVER_NAME - ": I/O port 0x%.4x, IRQ %d.\n", - io, irq); -#endif - - init_timer(&timerlist); - timerlist.function = sir_timeout; - timerlist.data = 0xabadcafe; - - return 0; -} - -static void drop_port(void) -{ - free_irq(irq, NULL); - del_timer_sync(&timerlist); -#ifndef LIRC_ON_SA1100 - release_region(io, 8); -#endif -} - -#ifdef LIRC_SIR_ACTISYS_ACT200L -/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */ -/* some code borrowed from Linux IRDA driver */ - -/* Register 0: Control register #1 */ -#define ACT200L_REG0 0x00 -#define ACT200L_TXEN 0x01 /* Enable transmitter */ -#define ACT200L_RXEN 0x02 /* Enable receiver */ -#define ACT200L_ECHO 0x08 /* Echo control chars */ - -/* Register 1: Control register #2 */ -#define ACT200L_REG1 0x10 -#define ACT200L_LODB 0x01 /* Load new baud rate count value */ -#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */ - -/* Register 3: Transmit mode register #2 */ -#define ACT200L_REG3 0x30 -#define ACT200L_B0 0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ -#define ACT200L_B1 0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ -#define ACT200L_CHSY 0x04 /* StartBit Synced 0=bittime, 1=startbit */ - -/* Register 4: Output Power register */ -#define ACT200L_REG4 0x40 -#define ACT200L_OP0 0x01 /* Enable LED1C output */ -#define ACT200L_OP1 0x02 /* Enable LED2C output */ -#define ACT200L_BLKR 0x04 - -/* Register 5: Receive Mode register */ -#define ACT200L_REG5 0x50 -#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */ - /*.. other various IRDA bit modes, and TV remote modes..*/ - -/* Register 6: Receive Sensitivity register #1 */ -#define ACT200L_REG6 0x60 -#define ACT200L_RS0 0x01 /* receive threshold bit 0 */ -#define ACT200L_RS1 0x02 /* receive threshold bit 1 */ - -/* Register 7: Receive Sensitivity register #2 */ -#define ACT200L_REG7 0x70 -#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */ - -/* Register 8,9: Baud Rate Divider register #1,#2 */ -#define ACT200L_REG8 0x80 -#define ACT200L_REG9 0x90 - -#define ACT200L_2400 0x5f -#define ACT200L_9600 0x17 -#define ACT200L_19200 0x0b -#define ACT200L_38400 0x05 -#define ACT200L_57600 0x03 -#define ACT200L_115200 0x01 - -/* Register 13: Control register #3 */ -#define ACT200L_REG13 0xd0 -#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */ - -/* Register 15: Status register */ -#define ACT200L_REG15 0xf0 - -/* Register 21: Control register #4 */ -#define ACT200L_REG21 0x50 -#define ACT200L_EXCK 0x02 /* Disable clock output driver */ -#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ - -static void init_act200(void) -{ - int i; - __u8 control[] = { - ACT200L_REG15, - ACT200L_REG13 | ACT200L_SHDW, - ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL, - ACT200L_REG13, - ACT200L_REG7 | ACT200L_ENPOS, - ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1, - ACT200L_REG5 | ACT200L_RWIDL, - ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR, - ACT200L_REG3 | ACT200L_B0, - ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN, - ACT200L_REG8 | (ACT200L_115200 & 0x0f), - ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f), - ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE - }; - - /* Set DLAB 1. */ - soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); - - /* Set divisor to 12 => 9600 Baud */ - soutp(UART_DLM, 0); - soutp(UART_DLL, 12); - - /* Set DLAB 0. */ - soutp(UART_LCR, UART_LCR_WLEN8); - /* Set divisor to 12 => 9600 Baud */ - - /* power supply */ - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); - for (i = 0; i < 50; i++) - safe_udelay(1000); - - /* Reset the dongle : set RTS low for 25 ms */ - soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); - for (i = 0; i < 25; i++) - udelay(1000); - - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); - udelay(100); - - /* Clear DTR and set RTS to enter command mode */ - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); - udelay(7); - - /* send out the control register settings for 115K 7N1 SIR operation */ - for (i = 0; i < sizeof(control); i++) { - soutp(UART_TX, control[i]); - /* one byte takes ~1042 usec to transmit at 9600,8N1 */ - udelay(1500); - } - - /* back to normal operation */ - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); - udelay(50); - - udelay(1500); - soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); - - /* Set DLAB 1. */ - soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); - - /* Set divisor to 1 => 115200 Baud */ - soutp(UART_DLM, 0); - soutp(UART_DLL, 1); - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* Set DLAB 0, 7 Bit */ - soutp(UART_LCR, UART_LCR_WLEN7); - - /* enable interrupts */ - soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); -} -#endif - -#ifdef LIRC_SIR_ACTISYS_ACT220L -/* - * Derived from linux IrDA driver (net/irda/actisys.c) - * Drop me a mail for any kind of comment: maxx@spaceboyz.net - */ - -void init_act220(void) -{ - int i; - - /* DLAB 1 */ - soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7); - - /* 9600 baud */ - soutp(UART_DLM, 0); - soutp(UART_DLL, 12); - - /* DLAB 0 */ - soutp(UART_LCR, UART_LCR_WLEN7); - - /* reset the dongle, set DTR low for 10us */ - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); - udelay(10); - - /* back to normal (still 9600) */ - soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2); - - /* - * send RTS pulses until we reach 115200 - * i hope this is really the same for act220l/act220l+ - */ - for (i = 0; i < 3; i++) { - udelay(10); - /* set RTS low for 10 us */ - soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); - udelay(10); - /* set RTS high for 10 us */ - soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); - } - - /* back to normal operation */ - udelay(1500); /* better safe than sorry ;) */ - - /* Set DLAB 1. */ - soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); - - /* Set divisor to 1 => 115200 Baud */ - soutp(UART_DLM, 0); - soutp(UART_DLL, 1); - - /* Set DLAB 0, 7 Bit */ - /* The dongle doesn't seem to have any problems with operation at 7N1 */ - soutp(UART_LCR, UART_LCR_WLEN7); - - /* enable interrupts */ - soutp(UART_IER, UART_IER_RDI); -} -#endif - -static int init_lirc_sir(void) -{ - int retval; - - init_waitqueue_head(&lirc_read_queue); - retval = init_port(); - if (retval < 0) - return retval; - init_hardware(); - printk(KERN_INFO LIRC_DRIVER_NAME - ": Installed.\n"); - return 0; -} - - -static int __init lirc_sir_init(void) -{ - int retval; - - retval = init_chrdev(); - if (retval < 0) - return retval; - retval = init_lirc_sir(); - if (retval) { - drop_chrdev(); - return retval; - } - return 0; -} - -static void __exit lirc_sir_exit(void) -{ - drop_hardware(); - drop_chrdev(); - drop_port(); - printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); -} - -module_init(lirc_sir_init); -module_exit(lirc_sir_exit); - -#ifdef LIRC_SIR_TEKRAM -MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210"); -MODULE_AUTHOR("Christoph Bartelmus"); -#elif defined(LIRC_ON_SA1100) -MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor"); -MODULE_AUTHOR("Christoph Bartelmus"); -#elif defined(LIRC_SIR_ACTISYS_ACT200L) -MODULE_DESCRIPTION("LIRC driver for Actisys Act200L"); -MODULE_AUTHOR("Karl Bongers"); -#elif defined(LIRC_SIR_ACTISYS_ACT220L) -MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)"); -MODULE_AUTHOR("Jan Roemisch"); -#else -MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports"); -MODULE_AUTHOR("Milan Pikula"); -#endif -MODULE_LICENSE("GPL"); - -#ifdef LIRC_ON_SA1100 -module_param(irq, int, S_IRUGO); -MODULE_PARM_DESC(irq, "Interrupt (16)"); -#else -module_param(io, int, S_IRUGO); -MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); - -module_param(irq, int, S_IRUGO); -MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); - -module_param(threshold, int, S_IRUGO); -MODULE_PARM_DESC(threshold, "space detection threshold (3)"); -#endif - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ttusbir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ttusbir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ttusbir.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_ttusbir.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,396 +0,0 @@ -/* - * lirc_ttusbir.c - * - * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver - * - * Copyright (C) 2007 Stefan Macher - * - * This LIRC driver provides access to the TechnoTrend USB IR Receiver. - * The receiver delivers the IR signal as raw sampled true/false data in - * isochronous USB packets each of size 128 byte. - * Currently the driver reduces the sampling rate by factor of 8 as this - * is still more than enough to decode RC-5 - others should be analyzed. - * But the driver does not rely on RC-5 it should be able to decode every - * IR signal that is not too fast. - */ - -/* - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include - -#include -#include - -MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC"); -MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)"); -MODULE_LICENSE("GPL"); - -/* #define DEBUG */ -#ifdef DEBUG -#define DPRINTK printk -#else -#define DPRINTK(_x_, a...) -#endif - -/* function declarations */ -static int probe(struct usb_interface *intf, const struct usb_device_id *id); -static void disconnect(struct usb_interface *intf); -static void urb_complete(struct urb *urb); -static int set_use_inc(void *data); -static void set_use_dec(void *data); - -static int num_urbs = 2; -module_param(num_urbs, int, S_IRUGO); -MODULE_PARM_DESC(num_urbs, - "Number of URBs in queue. Try to increase to 4 in case " - "of problems (default: 2; minimum: 2)"); - -/* table of devices that work with this driver */ -static struct usb_device_id device_id_table[] = { - /* TechnoTrend USB IR Receiver */ - { USB_DEVICE(0x0B48, 0x2003) }, - /* Terminating entry */ - { } -}; -MODULE_DEVICE_TABLE(usb, device_id_table); - -/* USB driver definition */ -static struct usb_driver usb_driver = { - .name = "TTUSBIR", - .id_table = &(device_id_table[0]), - .probe = probe, - .disconnect = disconnect, -}; - -/* USB device definition */ -struct ttusbir_device { - struct usb_driver *usb_driver; - struct usb_device *udev; - struct usb_interface *interf; - struct usb_class_driver class_driver; - unsigned int ifnum; /* Interface number to use */ - unsigned int alt_setting; /* alternate setting to use */ - unsigned int endpoint; /* Endpoint to use */ - struct urb **urb; /* num_urb URB pointers*/ - char **buffer; /* 128 byte buffer for each URB */ - struct lirc_buffer rbuf; /* Buffer towards LIRC */ - struct lirc_driver driver; - int minor; - int last_pulse; /* remembers if last received byte was pulse or space */ - int last_num; /* remembers how many last bytes appeared */ - int opened; -}; - -/*** LIRC specific functions ***/ -static int set_use_inc(void *data) -{ - int i, retval; - struct ttusbir_device *ttusbir = data; - - DPRINTK("Sending first URBs\n"); - /* @TODO Do I need to check if I am already opened */ - ttusbir->opened = 1; - - for (i = 0; i < num_urbs; i++) { - retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL); - if (retval) { - err("%s: usb_submit_urb failed on urb %d", - __func__, i); - return retval; - } - } - return 0; -} - -static void set_use_dec(void *data) -{ - struct ttusbir_device *ttusbir = data; - - DPRINTK("Device closed\n"); - - ttusbir->opened = 0; -} - -/*** USB specific functions ***/ - -/* - * This mapping table is used to do a very simple filtering of the - * input signal. - * For a value with at least 4 bits set it returns 0xFF otherwise - * 0x00. For faster IR signals this can not be used. But for RC-5 we - * still have about 14 samples per pulse/space, i.e. we sample with 14 - * times higher frequency than the signal frequency - */ -const unsigned char map_table[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -static void urb_complete(struct urb *urb) -{ - struct ttusbir_device *ttusbir; - unsigned char *buf; - int i; - int l; - - ttusbir = urb->context; - - if (!ttusbir->opened) - return; - - buf = (unsigned char *)urb->transfer_buffer; - - for (i = 0; i < 128; i++) { - /* Here we do the filtering and some kind of down sampling */ - buf[i] = ~map_table[buf[i]]; - if (ttusbir->last_pulse == buf[i]) { - if (ttusbir->last_num < PULSE_MASK/63) - ttusbir->last_num++; - /* - * else we are in a idle period and do not need to - * increment any longer - */ - } else { - l = ttusbir->last_num * 62; /* about 62 = us/byte */ - if (ttusbir->last_pulse) /* pulse or space? */ - l |= PULSE_BIT; - if (!lirc_buffer_full(&ttusbir->rbuf)) { - lirc_buffer_write(&ttusbir->rbuf, (void *)&l); - wake_up_interruptible(&ttusbir->rbuf.wait_poll); - } - ttusbir->last_num = 0; - ttusbir->last_pulse = buf[i]; - } - } - usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */ -} - -/* - * Called whenever the USB subsystem thinks we could be the right driver - * to handle this device - */ -static int probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - int alt_set, endp; - int found = 0; - int i, j; - int struct_size; - struct usb_host_interface *host_interf; - struct usb_interface_descriptor *interf_desc; - struct usb_host_endpoint *host_endpoint; - struct ttusbir_device *ttusbir; - - DPRINTK("Module ttusbir probe\n"); - - /* To reduce memory fragmentation we use only one allocation */ - struct_size = sizeof(struct ttusbir_device) + - (sizeof(struct urb *) * num_urbs) + - (sizeof(char *) * num_urbs) + - (num_urbs * 128); - ttusbir = kzalloc(struct_size, GFP_KERNEL); - if (!ttusbir) - return -ENOMEM; - - ttusbir->urb = (struct urb **)((char *)ttusbir + - sizeof(struct ttusbir_device)); - ttusbir->buffer = (char **)((char *)ttusbir->urb + - (sizeof(struct urb *) * num_urbs)); - for (i = 0; i < num_urbs; i++) - ttusbir->buffer[i] = (char *)ttusbir->buffer + - (sizeof(char *)*num_urbs) + (i * 128); - - ttusbir->usb_driver = &usb_driver; - ttusbir->alt_setting = -1; - /* @TODO check if error can be returned */ - ttusbir->udev = usb_get_dev(interface_to_usbdev(intf)); - ttusbir->interf = intf; - ttusbir->last_pulse = 0x00; - ttusbir->last_num = 0; - - /* - * Now look for interface setting we can handle - * We are searching for the alt setting where end point - * 0x82 has max packet size 16 - */ - for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) { - host_interf = &intf->altsetting[alt_set]; - interf_desc = &host_interf->desc; - for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) { - host_endpoint = &host_interf->endpoint[endp]; - if ((host_endpoint->desc.bEndpointAddress == 0x82) && - (host_endpoint->desc.wMaxPacketSize == 0x10)) { - ttusbir->alt_setting = alt_set; - ttusbir->endpoint = endp; - found = 1; - break; - } - } - } - if (ttusbir->alt_setting != -1) - DPRINTK("alt setting: %d\n", ttusbir->alt_setting); - else { - err("Could not find alternate setting\n"); - kfree(ttusbir); - return -EINVAL; - } - - /* OK lets setup this interface setting */ - usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting); - - /* Store device info in interface structure */ - usb_set_intfdata(intf, ttusbir); - - /* Register as a LIRC driver */ - if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) { - err("Could not get memory for LIRC data buffer\n"); - usb_set_intfdata(intf, NULL); - kfree(ttusbir); - return -ENOMEM; - } - strcpy(ttusbir->driver.name, "TTUSBIR"); - ttusbir->driver.minor = -1; - ttusbir->driver.code_length = 1; - ttusbir->driver.sample_rate = 0; - ttusbir->driver.data = ttusbir; - ttusbir->driver.add_to_buf = NULL; - ttusbir->driver.rbuf = &ttusbir->rbuf; - ttusbir->driver.set_use_inc = set_use_inc; - ttusbir->driver.set_use_dec = set_use_dec; - ttusbir->driver.dev = &intf->dev; - ttusbir->driver.owner = THIS_MODULE; - ttusbir->driver.features = LIRC_CAN_REC_MODE2; - ttusbir->minor = lirc_register_driver(&ttusbir->driver); - if (ttusbir->minor < 0) { - err("Error registering as LIRC driver\n"); - usb_set_intfdata(intf, NULL); - lirc_buffer_free(&ttusbir->rbuf); - kfree(ttusbir); - return -EIO; - } - - /* Allocate and setup the URB that we will use to talk to the device */ - for (i = 0; i < num_urbs; i++) { - ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL); - if (!ttusbir->urb[i]) { - err("Could not allocate memory for the URB\n"); - for (j = i - 1; j >= 0; j--) - kfree(ttusbir->urb[j]); - lirc_buffer_free(&ttusbir->rbuf); - lirc_unregister_driver(ttusbir->minor); - kfree(ttusbir); - usb_set_intfdata(intf, NULL); - return -ENOMEM; - } - ttusbir->urb[i]->dev = ttusbir->udev; - ttusbir->urb[i]->context = ttusbir; - ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev, - ttusbir->endpoint); - ttusbir->urb[i]->interval = 1; - ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP; - ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0]; - ttusbir->urb[i]->complete = urb_complete; - ttusbir->urb[i]->number_of_packets = 8; - ttusbir->urb[i]->transfer_buffer_length = 128; - for (j = 0; j < 8; j++) { - ttusbir->urb[i]->iso_frame_desc[j].offset = j*16; - ttusbir->urb[i]->iso_frame_desc[j].length = 16; - } - } - return 0; -} - -/** - * Called when the driver is unloaded or the device is unplugged - */ -static void disconnect(struct usb_interface *intf) -{ - int i; - struct ttusbir_device *ttusbir; - - DPRINTK("Module ttusbir disconnect\n"); - - ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - lirc_unregister_driver(ttusbir->minor); - DPRINTK("unregistered\n"); - - for (i = 0; i < num_urbs; i++) { - usb_kill_urb(ttusbir->urb[i]); - usb_free_urb(ttusbir->urb[i]); - } - DPRINTK("URBs killed\n"); - lirc_buffer_free(&ttusbir->rbuf); - kfree(ttusbir); -} - -static int ttusbir_init_module(void) -{ - int result; - - DPRINTK(KERN_DEBUG "Module ttusbir init\n"); - - /* register this driver with the USB subsystem */ - result = usb_register(&usb_driver); - if (result) - err("usb_register failed. Error number %d", result); - return result; -} - -static void ttusbir_exit_module(void) -{ - printk(KERN_DEBUG "Module ttusbir exit\n"); - usb_deregister(&usb_driver); -} - -module_init(ttusbir_init_module); -module_exit(ttusbir_exit_module); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_zilog.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_zilog.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_zilog.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/lirc_zilog.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1678 +0,0 @@ -/* - * i2c IR lirc driver for devices with zilog IR processors - * - * Copyright (c) 2000 Gerd Knorr - * modified for PixelView (BT878P+W/FM) by - * Michal Kochanowicz - * Christoph Bartelmus - * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by - * Ulrich Mueller - * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by - * Stefan Jahn - * modified for inclusion into kernel sources by - * Jerome Brock - * modified for Leadtek Winfast PVR2000 by - * Thomas Reitmayr (treitmayr@yahoo.com) - * modified for Hauppauge PVR-150 IR TX device by - * Mark Weaver - * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150 - * Jarod Wilson - * - * parts are cut&pasted from the lirc_i2c.c driver - * - * Numerous changes updating lirc_zilog.c in kernel 2.6.38 and later are - * Copyright (C) 2011 Andy Walls - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -struct IR; - -struct IR_rx { - struct kref ref; - struct IR *ir; - - /* RX device */ - struct mutex client_lock; - struct i2c_client *c; - - /* RX polling thread data */ - struct task_struct *task; - - /* RX read data */ - unsigned char b[3]; - bool hdpvr_data_fmt; -}; - -struct IR_tx { - struct kref ref; - struct IR *ir; - - /* TX device */ - struct mutex client_lock; - struct i2c_client *c; - - /* TX additional actions needed */ - int need_boot; - bool post_tx_ready_poll; -}; - -struct IR { - struct kref ref; - struct list_head list; - - /* FIXME spinlock access to l.features */ - struct lirc_driver l; - struct lirc_buffer rbuf; - - struct mutex ir_lock; - atomic_t open_count; - - struct i2c_adapter *adapter; - - spinlock_t rx_ref_lock; /* struct IR_rx kref get()/put() */ - struct IR_rx *rx; - - spinlock_t tx_ref_lock; /* struct IR_tx kref get()/put() */ - struct IR_tx *tx; -}; - -/* IR transceiver instance object list */ -/* - * This lock is used for the following: - * a. ir_devices_list access, insertions, deletions - * b. struct IR kref get()s and put()s - * c. serialization of ir_probe() for the two i2c_clients for a Z8 - */ -static DEFINE_MUTEX(ir_devices_lock); -static LIST_HEAD(ir_devices_list); - -/* Block size for IR transmitter */ -#define TX_BLOCK_SIZE 99 - -/* Hauppauge IR transmitter data */ -struct tx_data_struct { - /* Boot block */ - unsigned char *boot_data; - - /* Start of binary data block */ - unsigned char *datap; - - /* End of binary data block */ - unsigned char *endp; - - /* Number of installed codesets */ - unsigned int num_code_sets; - - /* Pointers to codesets */ - unsigned char **code_sets; - - /* Global fixed data template */ - int fixed[TX_BLOCK_SIZE]; -}; - -static struct tx_data_struct *tx_data; -static struct mutex tx_data_lock; - -#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \ - ## args) -#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) -#define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args) - -/* module parameters */ -static int debug; /* debug output */ -static int tx_only; /* only handle the IR Tx function */ -static int minor = -1; /* minor number */ - -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG KBUILD_MODNAME ": " fmt, \ - ## args); \ - } while (0) - - -/* struct IR reference counting */ -static struct IR *get_ir_device(struct IR *ir, bool ir_devices_lock_held) -{ - if (ir_devices_lock_held) { - kref_get(&ir->ref); - } else { - mutex_lock(&ir_devices_lock); - kref_get(&ir->ref); - mutex_unlock(&ir_devices_lock); - } - return ir; -} - -static void release_ir_device(struct kref *ref) -{ - struct IR *ir = container_of(ref, struct IR, ref); - - /* - * Things should be in this state by now: - * ir->rx set to NULL and deallocated - happens before ir->rx->ir put() - * ir->rx->task kthread stopped - happens before ir->rx->ir put() - * ir->tx set to NULL and deallocated - happens before ir->tx->ir put() - * ir->open_count == 0 - happens on final close() - * ir_lock, tx_ref_lock, rx_ref_lock, all released - */ - if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) { - lirc_unregister_driver(ir->l.minor); - ir->l.minor = MAX_IRCTL_DEVICES; - } - if (ir->rbuf.fifo_initialized) - lirc_buffer_free(&ir->rbuf); - list_del(&ir->list); - kfree(ir); -} - -static int put_ir_device(struct IR *ir, bool ir_devices_lock_held) -{ - int released; - - if (ir_devices_lock_held) - return kref_put(&ir->ref, release_ir_device); - - mutex_lock(&ir_devices_lock); - released = kref_put(&ir->ref, release_ir_device); - mutex_unlock(&ir_devices_lock); - - return released; -} - -/* struct IR_rx reference counting */ -static struct IR_rx *get_ir_rx(struct IR *ir) -{ - struct IR_rx *rx; - - spin_lock(&ir->rx_ref_lock); - rx = ir->rx; - if (rx != NULL) - kref_get(&rx->ref); - spin_unlock(&ir->rx_ref_lock); - return rx; -} - -static void destroy_rx_kthread(struct IR_rx *rx, bool ir_devices_lock_held) -{ - /* end up polling thread */ - if (!IS_ERR_OR_NULL(rx->task)) { - kthread_stop(rx->task); - rx->task = NULL; - /* Put the ir ptr that ir_probe() gave to the rx poll thread */ - put_ir_device(rx->ir, ir_devices_lock_held); - } -} - -static void release_ir_rx(struct kref *ref) -{ - struct IR_rx *rx = container_of(ref, struct IR_rx, ref); - struct IR *ir = rx->ir; - - /* - * This release function can't do all the work, as we want - * to keep the rx_ref_lock a spinlock, and killing the poll thread - * and releasing the ir reference can cause a sleep. That work is - * performed by put_ir_rx() - */ - ir->l.features &= ~LIRC_CAN_REC_LIRCCODE; - /* Don't put_ir_device(rx->ir) here; lock can't be freed yet */ - ir->rx = NULL; - /* Don't do the kfree(rx) here; we still need to kill the poll thread */ - return; -} - -static int put_ir_rx(struct IR_rx *rx, bool ir_devices_lock_held) -{ - int released; - struct IR *ir = rx->ir; - - spin_lock(&ir->rx_ref_lock); - released = kref_put(&rx->ref, release_ir_rx); - spin_unlock(&ir->rx_ref_lock); - /* Destroy the rx kthread while not holding the spinlock */ - if (released) { - destroy_rx_kthread(rx, ir_devices_lock_held); - kfree(rx); - /* Make sure we're not still in a poll_table somewhere */ - wake_up_interruptible(&ir->rbuf.wait_poll); - } - /* Do a reference put() for the rx->ir reference, if we released rx */ - if (released) - put_ir_device(ir, ir_devices_lock_held); - return released; -} - -/* struct IR_tx reference counting */ -static struct IR_tx *get_ir_tx(struct IR *ir) -{ - struct IR_tx *tx; - - spin_lock(&ir->tx_ref_lock); - tx = ir->tx; - if (tx != NULL) - kref_get(&tx->ref); - spin_unlock(&ir->tx_ref_lock); - return tx; -} - -static void release_ir_tx(struct kref *ref) -{ - struct IR_tx *tx = container_of(ref, struct IR_tx, ref); - struct IR *ir = tx->ir; - - ir->l.features &= ~LIRC_CAN_SEND_PULSE; - /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */ - ir->tx = NULL; - kfree(tx); -} - -static int put_ir_tx(struct IR_tx *tx, bool ir_devices_lock_held) -{ - int released; - struct IR *ir = tx->ir; - - spin_lock(&ir->tx_ref_lock); - released = kref_put(&tx->ref, release_ir_tx); - spin_unlock(&ir->tx_ref_lock); - /* Do a reference put() for the tx->ir reference, if we released tx */ - if (released) - put_ir_device(ir, ir_devices_lock_held); - return released; -} - -static int add_to_buf(struct IR *ir) -{ - __u16 code; - unsigned char codes[2]; - unsigned char keybuf[6]; - int got_data = 0; - int ret; - int failures = 0; - unsigned char sendbuf[1] = { 0 }; - struct lirc_buffer *rbuf = ir->l.rbuf; - struct IR_rx *rx; - struct IR_tx *tx; - - if (lirc_buffer_full(rbuf)) { - dprintk("buffer overflow\n"); - return -EOVERFLOW; - } - - rx = get_ir_rx(ir); - if (rx == NULL) - return -ENXIO; - - /* Ensure our rx->c i2c_client remains valid for the duration */ - mutex_lock(&rx->client_lock); - if (rx->c == NULL) { - mutex_unlock(&rx->client_lock); - put_ir_rx(rx, false); - return -ENXIO; - } - - tx = get_ir_tx(ir); - - /* - * service the device as long as it is returning - * data and we have space - */ - do { - if (kthread_should_stop()) { - ret = -ENODATA; - break; - } - - /* - * Lock i2c bus for the duration. RX/TX chips interfere so - * this is worth it - */ - mutex_lock(&ir->ir_lock); - - if (kthread_should_stop()) { - mutex_unlock(&ir->ir_lock); - ret = -ENODATA; - break; - } - - /* - * Send random "poll command" (?) Windows driver does this - * and it is a good point to detect chip failure. - */ - ret = i2c_master_send(rx->c, sendbuf, 1); - if (ret != 1) { - zilog_error("i2c_master_send failed with %d\n", ret); - if (failures >= 3) { - mutex_unlock(&ir->ir_lock); - zilog_error("unable to read from the IR chip " - "after 3 resets, giving up\n"); - break; - } - - /* Looks like the chip crashed, reset it */ - zilog_error("polling the IR receiver chip failed, " - "trying reset\n"); - - set_current_state(TASK_UNINTERRUPTIBLE); - if (kthread_should_stop()) { - mutex_unlock(&ir->ir_lock); - ret = -ENODATA; - break; - } - schedule_timeout((100 * HZ + 999) / 1000); - if (tx != NULL) - tx->need_boot = 1; - - ++failures; - mutex_unlock(&ir->ir_lock); - ret = 0; - continue; - } - - if (kthread_should_stop()) { - mutex_unlock(&ir->ir_lock); - ret = -ENODATA; - break; - } - ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf)); - mutex_unlock(&ir->ir_lock); - if (ret != sizeof(keybuf)) { - zilog_error("i2c_master_recv failed with %d -- " - "keeping last read buffer\n", ret); - } else { - rx->b[0] = keybuf[3]; - rx->b[1] = keybuf[4]; - rx->b[2] = keybuf[5]; - dprintk("key (0x%02x/0x%02x)\n", rx->b[0], rx->b[1]); - } - - /* key pressed ? */ - if (rx->hdpvr_data_fmt) { - if (got_data && (keybuf[0] == 0x80)) { - ret = 0; - break; - } else if (got_data && (keybuf[0] == 0x00)) { - ret = -ENODATA; - break; - } - } else if ((rx->b[0] & 0x80) == 0) { - ret = got_data ? 0 : -ENODATA; - break; - } - - /* look what we have */ - code = (((__u16)rx->b[0] & 0x7f) << 6) | (rx->b[1] >> 2); - - codes[0] = (code >> 8) & 0xff; - codes[1] = code & 0xff; - - /* return it */ - lirc_buffer_write(rbuf, codes); - ++got_data; - ret = 0; - } while (!lirc_buffer_full(rbuf)); - - mutex_unlock(&rx->client_lock); - if (tx != NULL) - put_ir_tx(tx, false); - put_ir_rx(rx, false); - return ret; -} - -/* - * Main function of the polling thread -- from lirc_dev. - * We don't fit the LIRC model at all anymore. This is horrible, but - * basically we have a single RX/TX device with a nasty failure mode - * that needs to be accounted for across the pair. lirc lets us provide - * fops, but prevents us from using the internal polling, etc. if we do - * so. Hence the replication. Might be neater to extend the LIRC model - * to account for this but I'd think it's a very special case of seriously - * messed up hardware. - */ -static int lirc_thread(void *arg) -{ - struct IR *ir = arg; - struct lirc_buffer *rbuf = ir->l.rbuf; - - dprintk("poll thread started\n"); - - while (!kthread_should_stop()) { - /* if device not opened, we can sleep half a second */ - if (atomic_read(&ir->open_count) == 0) { - schedule_timeout(HZ/2); - continue; - } - - set_current_state(TASK_INTERRUPTIBLE); - - /* - * This is ~113*2 + 24 + jitter (2*repeat gap + code length). - * We use this interval as the chip resets every time you poll - * it (bad!). This is therefore just sufficient to catch all - * of the button presses. It makes the remote much more - * responsive. You can see the difference by running irw and - * holding down a button. With 100ms, the old polling - * interval, you'll notice breaks in the repeat sequence - * corresponding to lost keypresses. - */ - schedule_timeout((260 * HZ) / 1000); - if (kthread_should_stop()) - break; - if (!add_to_buf(ir)) - wake_up_interruptible(&rbuf->wait_poll); - } - - dprintk("poll thread ended\n"); - return 0; -} - -static int set_use_inc(void *data) -{ - return 0; -} - -static void set_use_dec(void *data) -{ - return; -} - -/* safe read of a uint32 (always network byte order) */ -static int read_uint32(unsigned char **data, - unsigned char *endp, unsigned int *val) -{ - if (*data + 4 > endp) - return 0; - *val = ((*data)[0] << 24) | ((*data)[1] << 16) | - ((*data)[2] << 8) | (*data)[3]; - *data += 4; - return 1; -} - -/* safe read of a uint8 */ -static int read_uint8(unsigned char **data, - unsigned char *endp, unsigned char *val) -{ - if (*data + 1 > endp) - return 0; - *val = *((*data)++); - return 1; -} - -/* safe skipping of N bytes */ -static int skip(unsigned char **data, - unsigned char *endp, unsigned int distance) -{ - if (*data + distance > endp) - return 0; - *data += distance; - return 1; -} - -/* decompress key data into the given buffer */ -static int get_key_data(unsigned char *buf, - unsigned int codeset, unsigned int key) -{ - unsigned char *data, *endp, *diffs, *key_block; - unsigned char keys, ndiffs, id; - unsigned int base, lim, pos, i; - - /* Binary search for the codeset */ - for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) { - pos = base + (lim >> 1); - data = tx_data->code_sets[pos]; - - if (!read_uint32(&data, tx_data->endp, &i)) - goto corrupt; - - if (i == codeset) - break; - else if (codeset > i) { - base = pos + 1; - --lim; - } - } - /* Not found? */ - if (!lim) - return -EPROTO; - - /* Set end of data block */ - endp = pos < tx_data->num_code_sets - 1 ? - tx_data->code_sets[pos + 1] : tx_data->endp; - - /* Read the block header */ - if (!read_uint8(&data, endp, &keys) || - !read_uint8(&data, endp, &ndiffs) || - ndiffs > TX_BLOCK_SIZE || keys == 0) - goto corrupt; - - /* Save diffs & skip */ - diffs = data; - if (!skip(&data, endp, ndiffs)) - goto corrupt; - - /* Read the id of the first key */ - if (!read_uint8(&data, endp, &id)) - goto corrupt; - - /* Unpack the first key's data */ - for (i = 0; i < TX_BLOCK_SIZE; ++i) { - if (tx_data->fixed[i] == -1) { - if (!read_uint8(&data, endp, &buf[i])) - goto corrupt; - } else { - buf[i] = (unsigned char)tx_data->fixed[i]; - } - } - - /* Early out key found/not found */ - if (key == id) - return 0; - if (keys == 1) - return -EPROTO; - - /* Sanity check */ - key_block = data; - if (!skip(&data, endp, (keys - 1) * (ndiffs + 1))) - goto corrupt; - - /* Binary search for the key */ - for (base = 0, lim = keys - 1; lim; lim >>= 1) { - /* Seek to block */ - unsigned char *key_data; - pos = base + (lim >> 1); - key_data = key_block + (ndiffs + 1) * pos; - - if (*key_data == key) { - /* skip key id */ - ++key_data; - - /* found, so unpack the diffs */ - for (i = 0; i < ndiffs; ++i) { - unsigned char val; - if (!read_uint8(&key_data, endp, &val) || - diffs[i] >= TX_BLOCK_SIZE) - goto corrupt; - buf[diffs[i]] = val; - } - - return 0; - } else if (key > *key_data) { - base = pos + 1; - --lim; - } - } - /* Key not found */ - return -EPROTO; - -corrupt: - zilog_error("firmware is corrupt\n"); - return -EFAULT; -} - -/* send a block of data to the IR TX device */ -static int send_data_block(struct IR_tx *tx, unsigned char *data_block) -{ - int i, j, ret; - unsigned char buf[5]; - - for (i = 0; i < TX_BLOCK_SIZE;) { - int tosend = TX_BLOCK_SIZE - i; - if (tosend > 4) - tosend = 4; - buf[0] = (unsigned char)(i + 1); - for (j = 0; j < tosend; ++j) - buf[1 + j] = data_block[i + j]; - dprintk("%02x %02x %02x %02x %02x", - buf[0], buf[1], buf[2], buf[3], buf[4]); - ret = i2c_master_send(tx->c, buf, tosend + 1); - if (ret != tosend + 1) { - zilog_error("i2c_master_send failed with %d\n", ret); - return ret < 0 ? ret : -EFAULT; - } - i += tosend; - } - return 0; -} - -/* send boot data to the IR TX device */ -static int send_boot_data(struct IR_tx *tx) -{ - int ret, i; - unsigned char buf[4]; - - /* send the boot block */ - ret = send_data_block(tx, tx_data->boot_data); - if (ret != 0) - return ret; - - /* Hit the go button to activate the new boot data */ - buf[0] = 0x00; - buf[1] = 0x20; - ret = i2c_master_send(tx->c, buf, 2); - if (ret != 2) { - zilog_error("i2c_master_send failed with %d\n", ret); - return ret < 0 ? ret : -EFAULT; - } - - /* - * Wait for zilog to settle after hitting go post boot block upload. - * Without this delay, the HD-PVR and HVR-1950 both return an -EIO - * upon attempting to get firmware revision, and tx probe thus fails. - */ - for (i = 0; i < 10; i++) { - ret = i2c_master_send(tx->c, buf, 1); - if (ret == 1) - break; - udelay(100); - } - - if (ret != 1) { - zilog_error("i2c_master_send failed with %d\n", ret); - return ret < 0 ? ret : -EFAULT; - } - - /* Here comes the firmware version... (hopefully) */ - ret = i2c_master_recv(tx->c, buf, 4); - if (ret != 4) { - zilog_error("i2c_master_recv failed with %d\n", ret); - return 0; - } - if ((buf[0] != 0x80) && (buf[0] != 0xa0)) { - zilog_error("unexpected IR TX init response: %02x\n", buf[0]); - return 0; - } - zilog_notify("Zilog/Hauppauge IR blaster firmware version " - "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]); - - return 0; -} - -/* unload "firmware", lock held */ -static void fw_unload_locked(void) -{ - if (tx_data) { - if (tx_data->code_sets) - vfree(tx_data->code_sets); - - if (tx_data->datap) - vfree(tx_data->datap); - - vfree(tx_data); - tx_data = NULL; - dprintk("successfully unloaded IR blaster firmware\n"); - } -} - -/* unload "firmware" for the IR TX device */ -static void fw_unload(void) -{ - mutex_lock(&tx_data_lock); - fw_unload_locked(); - mutex_unlock(&tx_data_lock); -} - -/* load "firmware" for the IR TX device */ -static int fw_load(struct IR_tx *tx) -{ - int ret; - unsigned int i; - unsigned char *data, version, num_global_fixed; - const struct firmware *fw_entry; - - /* Already loaded? */ - mutex_lock(&tx_data_lock); - if (tx_data) { - ret = 0; - goto out; - } - - /* Request codeset data file */ - ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev); - if (ret != 0) { - zilog_error("firmware haup-ir-blaster.bin not available " - "(%d)\n", ret); - ret = ret < 0 ? ret : -EFAULT; - goto out; - } - dprintk("firmware of size %zu loaded\n", fw_entry->size); - - /* Parse the file */ - tx_data = vmalloc(sizeof(*tx_data)); - if (tx_data == NULL) { - zilog_error("out of memory\n"); - release_firmware(fw_entry); - ret = -ENOMEM; - goto out; - } - tx_data->code_sets = NULL; - - /* Copy the data so hotplug doesn't get confused and timeout */ - tx_data->datap = vmalloc(fw_entry->size); - if (tx_data->datap == NULL) { - zilog_error("out of memory\n"); - release_firmware(fw_entry); - vfree(tx_data); - ret = -ENOMEM; - goto out; - } - memcpy(tx_data->datap, fw_entry->data, fw_entry->size); - tx_data->endp = tx_data->datap + fw_entry->size; - release_firmware(fw_entry); fw_entry = NULL; - - /* Check version */ - data = tx_data->datap; - if (!read_uint8(&data, tx_data->endp, &version)) - goto corrupt; - if (version != 1) { - zilog_error("unsupported code set file version (%u, expected" - "1) -- please upgrade to a newer driver", - version); - fw_unload_locked(); - ret = -EFAULT; - goto out; - } - - /* Save boot block for later */ - tx_data->boot_data = data; - if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE)) - goto corrupt; - - if (!read_uint32(&data, tx_data->endp, - &tx_data->num_code_sets)) - goto corrupt; - - dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets); - - tx_data->code_sets = vmalloc( - tx_data->num_code_sets * sizeof(char *)); - if (tx_data->code_sets == NULL) { - fw_unload_locked(); - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < TX_BLOCK_SIZE; ++i) - tx_data->fixed[i] = -1; - - /* Read global fixed data template */ - if (!read_uint8(&data, tx_data->endp, &num_global_fixed) || - num_global_fixed > TX_BLOCK_SIZE) - goto corrupt; - for (i = 0; i < num_global_fixed; ++i) { - unsigned char pos, val; - if (!read_uint8(&data, tx_data->endp, &pos) || - !read_uint8(&data, tx_data->endp, &val) || - pos >= TX_BLOCK_SIZE) - goto corrupt; - tx_data->fixed[pos] = (int)val; - } - - /* Filch out the position of each code set */ - for (i = 0; i < tx_data->num_code_sets; ++i) { - unsigned int id; - unsigned char keys; - unsigned char ndiffs; - - /* Save the codeset position */ - tx_data->code_sets[i] = data; - - /* Read header */ - if (!read_uint32(&data, tx_data->endp, &id) || - !read_uint8(&data, tx_data->endp, &keys) || - !read_uint8(&data, tx_data->endp, &ndiffs) || - ndiffs > TX_BLOCK_SIZE || keys == 0) - goto corrupt; - - /* skip diff positions */ - if (!skip(&data, tx_data->endp, ndiffs)) - goto corrupt; - - /* - * After the diffs we have the first key id + data - - * global fixed - */ - if (!skip(&data, tx_data->endp, - 1 + TX_BLOCK_SIZE - num_global_fixed)) - goto corrupt; - - /* Then we have keys-1 blocks of key id+diffs */ - if (!skip(&data, tx_data->endp, - (ndiffs + 1) * (keys - 1))) - goto corrupt; - } - ret = 0; - goto out; - -corrupt: - zilog_error("firmware is corrupt\n"); - fw_unload_locked(); - ret = -EFAULT; - -out: - mutex_unlock(&tx_data_lock); - return ret; -} - -/* copied from lirc_dev */ -static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) -{ - struct IR *ir = filep->private_data; - struct IR_rx *rx; - struct lirc_buffer *rbuf = ir->l.rbuf; - int ret = 0, written = 0, retries = 0; - unsigned int m; - DECLARE_WAITQUEUE(wait, current); - - dprintk("read called\n"); - if (n % rbuf->chunk_size) { - dprintk("read result = -EINVAL\n"); - return -EINVAL; - } - - rx = get_ir_rx(ir); - if (rx == NULL) - return -ENXIO; - - /* - * we add ourselves to the task queue before buffer check - * to avoid losing scan code (in case when queue is awaken somewhere - * between while condition checking and scheduling) - */ - add_wait_queue(&rbuf->wait_poll, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - /* - * while we didn't provide 'length' bytes, device is opened in blocking - * mode and 'copy_to_user' is happy, wait for data. - */ - while (written < n && ret == 0) { - if (lirc_buffer_empty(rbuf)) { - /* - * According to the read(2) man page, 'written' can be - * returned as less than 'n', instead of blocking - * again, returning -EWOULDBLOCK, or returning - * -ERESTARTSYS - */ - if (written) - break; - if (filep->f_flags & O_NONBLOCK) { - ret = -EWOULDBLOCK; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } else { - unsigned char buf[rbuf->chunk_size]; - m = lirc_buffer_read(rbuf, buf); - if (m == rbuf->chunk_size) { - ret = copy_to_user((void *)outbuf+written, buf, - rbuf->chunk_size); - written += rbuf->chunk_size; - } else { - retries++; - } - if (retries >= 5) { - zilog_error("Buffer read failed!\n"); - ret = -EIO; - } - } - } - - remove_wait_queue(&rbuf->wait_poll, &wait); - put_ir_rx(rx, false); - set_current_state(TASK_RUNNING); - - dprintk("read result = %d (%s)\n", ret, ret ? "Error" : "OK"); - - return ret ? ret : written; -} - -/* send a keypress to the IR TX device */ -static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) -{ - unsigned char data_block[TX_BLOCK_SIZE]; - unsigned char buf[2]; - int i, ret; - - /* Get data for the codeset/key */ - ret = get_key_data(data_block, code, key); - - if (ret == -EPROTO) { - zilog_error("failed to get data for code %u, key %u -- check " - "lircd.conf entries\n", code, key); - return ret; - } else if (ret != 0) - return ret; - - /* Send the data block */ - ret = send_data_block(tx, data_block); - if (ret != 0) - return ret; - - /* Send data block length? */ - buf[0] = 0x00; - buf[1] = 0x40; - ret = i2c_master_send(tx->c, buf, 2); - if (ret != 2) { - zilog_error("i2c_master_send failed with %d\n", ret); - return ret < 0 ? ret : -EFAULT; - } - - /* Give the z8 a moment to process data block */ - for (i = 0; i < 10; i++) { - ret = i2c_master_send(tx->c, buf, 1); - if (ret == 1) - break; - udelay(100); - } - - if (ret != 1) { - zilog_error("i2c_master_send failed with %d\n", ret); - return ret < 0 ? ret : -EFAULT; - } - - /* Send finished download? */ - ret = i2c_master_recv(tx->c, buf, 1); - if (ret != 1) { - zilog_error("i2c_master_recv failed with %d\n", ret); - return ret < 0 ? ret : -EFAULT; - } - if (buf[0] != 0xA0) { - zilog_error("unexpected IR TX response #1: %02x\n", - buf[0]); - return -EFAULT; - } - - /* Send prepare command? */ - buf[0] = 0x00; - buf[1] = 0x80; - ret = i2c_master_send(tx->c, buf, 2); - if (ret != 2) { - zilog_error("i2c_master_send failed with %d\n", ret); - return ret < 0 ? ret : -EFAULT; - } - - /* - * The sleep bits aren't necessary on the HD PVR, and in fact, the - * last i2c_master_recv always fails with a -5, so for now, we're - * going to skip this whole mess and say we're done on the HD PVR - */ - if (!tx->post_tx_ready_poll) { - dprintk("sent code %u, key %u\n", code, key); - return 0; - } - - /* - * This bit NAKs until the device is ready, so we retry it - * sleeping a bit each time. This seems to be what the windows - * driver does, approximately. - * Try for up to 1s. - */ - for (i = 0; i < 20; ++i) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((50 * HZ + 999) / 1000); - ret = i2c_master_send(tx->c, buf, 1); - if (ret == 1) - break; - dprintk("NAK expected: i2c_master_send " - "failed with %d (try %d)\n", ret, i+1); - } - if (ret != 1) { - zilog_error("IR TX chip never got ready: last i2c_master_send " - "failed with %d\n", ret); - return ret < 0 ? ret : -EFAULT; - } - - /* Seems to be an 'ok' response */ - i = i2c_master_recv(tx->c, buf, 1); - if (i != 1) { - zilog_error("i2c_master_recv failed with %d\n", ret); - return -EFAULT; - } - if (buf[0] != 0x80) { - zilog_error("unexpected IR TX response #2: %02x\n", buf[0]); - return -EFAULT; - } - - /* Oh good, it worked */ - dprintk("sent code %u, key %u\n", code, key); - return 0; -} - -/* - * Write a code to the device. We take in a 32-bit number (an int) and then - * decode this to a codeset/key index. The key data is then decompressed and - * sent to the device. We have a spin lock as per i2c documentation to prevent - * multiple concurrent sends which would probably cause the device to explode. - */ -static ssize_t write(struct file *filep, const char *buf, size_t n, - loff_t *ppos) -{ - struct IR *ir = filep->private_data; - struct IR_tx *tx; - size_t i; - int failures = 0; - - /* Validate user parameters */ - if (n % sizeof(int)) - return -EINVAL; - - /* Get a struct IR_tx reference */ - tx = get_ir_tx(ir); - if (tx == NULL) - return -ENXIO; - - /* Ensure our tx->c i2c_client remains valid for the duration */ - mutex_lock(&tx->client_lock); - if (tx->c == NULL) { - mutex_unlock(&tx->client_lock); - put_ir_tx(tx, false); - return -ENXIO; - } - - /* Lock i2c bus for the duration */ - mutex_lock(&ir->ir_lock); - - /* Send each keypress */ - for (i = 0; i < n;) { - int ret = 0; - int command; - - if (copy_from_user(&command, buf + i, sizeof(command))) { - mutex_unlock(&ir->ir_lock); - mutex_unlock(&tx->client_lock); - put_ir_tx(tx, false); - return -EFAULT; - } - - /* Send boot data first if required */ - if (tx->need_boot == 1) { - /* Make sure we have the 'firmware' loaded, first */ - ret = fw_load(tx); - if (ret != 0) { - mutex_unlock(&ir->ir_lock); - mutex_unlock(&tx->client_lock); - put_ir_tx(tx, false); - if (ret != -ENOMEM) - ret = -EIO; - return ret; - } - /* Prep the chip for transmitting codes */ - ret = send_boot_data(tx); - if (ret == 0) - tx->need_boot = 0; - } - - /* Send the code */ - if (ret == 0) { - ret = send_code(tx, (unsigned)command >> 16, - (unsigned)command & 0xFFFF); - if (ret == -EPROTO) { - mutex_unlock(&ir->ir_lock); - mutex_unlock(&tx->client_lock); - put_ir_tx(tx, false); - return ret; - } - } - - /* - * Hmm, a failure. If we've had a few then give up, otherwise - * try a reset - */ - if (ret != 0) { - /* Looks like the chip crashed, reset it */ - zilog_error("sending to the IR transmitter chip " - "failed, trying reset\n"); - - if (failures >= 3) { - zilog_error("unable to send to the IR chip " - "after 3 resets, giving up\n"); - mutex_unlock(&ir->ir_lock); - mutex_unlock(&tx->client_lock); - put_ir_tx(tx, false); - return ret; - } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((100 * HZ + 999) / 1000); - tx->need_boot = 1; - ++failures; - } else - i += sizeof(int); - } - - /* Release i2c bus */ - mutex_unlock(&ir->ir_lock); - - mutex_unlock(&tx->client_lock); - - /* Give back our struct IR_tx reference */ - put_ir_tx(tx, false); - - /* All looks good */ - return n; -} - -/* copied from lirc_dev */ -static unsigned int poll(struct file *filep, poll_table *wait) -{ - struct IR *ir = filep->private_data; - struct IR_rx *rx; - struct lirc_buffer *rbuf = ir->l.rbuf; - unsigned int ret; - - dprintk("poll called\n"); - - rx = get_ir_rx(ir); - if (rx == NULL) { - /* - * Revisit this, if our poll function ever reports writeable - * status for Tx - */ - dprintk("poll result = POLLERR\n"); - return POLLERR; - } - - /* - * Add our lirc_buffer's wait_queue to the poll_table. A wake up on - * that buffer's wait queue indicates we may have a new poll status. - */ - poll_wait(filep, &rbuf->wait_poll, wait); - - /* Indicate what ops could happen immediately without blocking */ - ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM); - - dprintk("poll result = %s\n", ret ? "POLLIN|POLLRDNORM" : "none"); - return ret; -} - -static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - struct IR *ir = filep->private_data; - int result; - unsigned long mode, features; - - features = ir->l.features; - - switch (cmd) { - case LIRC_GET_LENGTH: - result = put_user((unsigned long)13, - (unsigned long *)arg); - break; - case LIRC_GET_FEATURES: - result = put_user(features, (unsigned long *) arg); - break; - case LIRC_GET_REC_MODE: - if (!(features&LIRC_CAN_REC_MASK)) - return -ENOSYS; - - result = put_user(LIRC_REC2MODE - (features&LIRC_CAN_REC_MASK), - (unsigned long *)arg); - break; - case LIRC_SET_REC_MODE: - if (!(features&LIRC_CAN_REC_MASK)) - return -ENOSYS; - - result = get_user(mode, (unsigned long *)arg); - if (!result && !(LIRC_MODE2REC(mode) & features)) - result = -EINVAL; - break; - case LIRC_GET_SEND_MODE: - if (!(features&LIRC_CAN_SEND_MASK)) - return -ENOSYS; - - result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); - break; - case LIRC_SET_SEND_MODE: - if (!(features&LIRC_CAN_SEND_MASK)) - return -ENOSYS; - - result = get_user(mode, (unsigned long *) arg); - if (!result && mode != LIRC_MODE_PULSE) - return -EINVAL; - break; - default: - return -EINVAL; - } - return result; -} - -static struct IR *get_ir_device_by_minor(unsigned int minor) -{ - struct IR *ir; - struct IR *ret = NULL; - - mutex_lock(&ir_devices_lock); - - if (!list_empty(&ir_devices_list)) { - list_for_each_entry(ir, &ir_devices_list, list) { - if (ir->l.minor == minor) { - ret = get_ir_device(ir, true); - break; - } - } - } - - mutex_unlock(&ir_devices_lock); - return ret; -} - -/* - * Open the IR device. Get hold of our IR structure and - * stash it in private_data for the file - */ -static int open(struct inode *node, struct file *filep) -{ - struct IR *ir; - unsigned int minor = MINOR(node->i_rdev); - - /* find our IR struct */ - ir = get_ir_device_by_minor(minor); - - if (ir == NULL) - return -ENODEV; - - atomic_inc(&ir->open_count); - - /* stash our IR struct */ - filep->private_data = ir; - - nonseekable_open(node, filep); - return 0; -} - -/* Close the IR device */ -static int close(struct inode *node, struct file *filep) -{ - /* find our IR struct */ - struct IR *ir = filep->private_data; - if (ir == NULL) { - zilog_error("close: no private_data attached to the file!\n"); - return -ENODEV; - } - - atomic_dec(&ir->open_count); - - put_ir_device(ir, false); - return 0; -} - -static int ir_remove(struct i2c_client *client); -static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); - -#define ID_FLAG_TX 0x01 -#define ID_FLAG_HDPVR 0x02 - -static const struct i2c_device_id ir_transceiver_id[] = { - { "ir_tx_z8f0811_haup", ID_FLAG_TX }, - { "ir_rx_z8f0811_haup", 0 }, - { "ir_tx_z8f0811_hdpvr", ID_FLAG_HDPVR | ID_FLAG_TX }, - { "ir_rx_z8f0811_hdpvr", ID_FLAG_HDPVR }, - { } -}; - -static struct i2c_driver driver = { - .driver = { - .owner = THIS_MODULE, - .name = "Zilog/Hauppauge i2c IR", - }, - .probe = ir_probe, - .remove = ir_remove, - .id_table = ir_transceiver_id, -}; - -static const struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = read, - .write = write, - .poll = poll, - .unlocked_ioctl = ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ioctl, -#endif - .open = open, - .release = close -}; - -static struct lirc_driver lirc_template = { - .name = "lirc_zilog", - .minor = -1, - .code_length = 13, - .buffer_size = BUFLEN / 2, - .sample_rate = 0, /* tell lirc_dev to not start its own kthread */ - .chunk_size = 2, - .set_use_inc = set_use_inc, - .set_use_dec = set_use_dec, - .fops = &lirc_fops, - .owner = THIS_MODULE, -}; - -static int ir_remove(struct i2c_client *client) -{ - if (strncmp("ir_tx_z8", client->name, 8) == 0) { - struct IR_tx *tx = i2c_get_clientdata(client); - if (tx != NULL) { - mutex_lock(&tx->client_lock); - tx->c = NULL; - mutex_unlock(&tx->client_lock); - put_ir_tx(tx, false); - } - } else if (strncmp("ir_rx_z8", client->name, 8) == 0) { - struct IR_rx *rx = i2c_get_clientdata(client); - if (rx != NULL) { - mutex_lock(&rx->client_lock); - rx->c = NULL; - mutex_unlock(&rx->client_lock); - put_ir_rx(rx, false); - } - } - return 0; -} - - -/* ir_devices_lock must be held */ -static struct IR *get_ir_device_by_adapter(struct i2c_adapter *adapter) -{ - struct IR *ir; - - if (list_empty(&ir_devices_list)) - return NULL; - - list_for_each_entry(ir, &ir_devices_list, list) - if (ir->adapter == adapter) { - get_ir_device(ir, true); - return ir; - } - - return NULL; -} - -static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct IR *ir; - struct IR_tx *tx; - struct IR_rx *rx; - struct i2c_adapter *adap = client->adapter; - int ret; - bool tx_probe = false; - - dprintk("%s: %s on i2c-%d (%s), client addr=0x%02x\n", - __func__, id->name, adap->nr, adap->name, client->addr); - - /* - * The IR receiver is at i2c address 0x71. - * The IR transmitter is at i2c address 0x70. - */ - - if (id->driver_data & ID_FLAG_TX) - tx_probe = true; - else if (tx_only) /* module option */ - return -ENXIO; - - zilog_info("probing IR %s on %s (i2c-%d)\n", - tx_probe ? "Tx" : "Rx", adap->name, adap->nr); - - mutex_lock(&ir_devices_lock); - - /* Use a single struct IR instance for both the Rx and Tx functions */ - ir = get_ir_device_by_adapter(adap); - if (ir == NULL) { - ir = kzalloc(sizeof(struct IR), GFP_KERNEL); - if (ir == NULL) { - ret = -ENOMEM; - goto out_no_ir; - } - kref_init(&ir->ref); - - /* store for use in ir_probe() again, and open() later on */ - INIT_LIST_HEAD(&ir->list); - list_add_tail(&ir->list, &ir_devices_list); - - ir->adapter = adap; - mutex_init(&ir->ir_lock); - atomic_set(&ir->open_count, 0); - spin_lock_init(&ir->tx_ref_lock); - spin_lock_init(&ir->rx_ref_lock); - - /* set lirc_dev stuff */ - memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); - /* - * FIXME this is a pointer reference to us, but no refcount. - * - * This OK for now, since lirc_dev currently won't touch this - * buffer as we provide our own lirc_fops. - * - * Currently our own lirc_fops rely on this ir->l.rbuf pointer - */ - ir->l.rbuf = &ir->rbuf; - ir->l.dev = &adap->dev; - ret = lirc_buffer_init(ir->l.rbuf, - ir->l.chunk_size, ir->l.buffer_size); - if (ret) - goto out_put_ir; - } - - if (tx_probe) { - /* Get the IR_rx instance for later, if already allocated */ - rx = get_ir_rx(ir); - - /* Set up a struct IR_tx instance */ - tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL); - if (tx == NULL) { - ret = -ENOMEM; - goto out_put_xx; - } - kref_init(&tx->ref); - ir->tx = tx; - - ir->l.features |= LIRC_CAN_SEND_PULSE; - mutex_init(&tx->client_lock); - tx->c = client; - tx->need_boot = 1; - tx->post_tx_ready_poll = - (id->driver_data & ID_FLAG_HDPVR) ? false : true; - - /* An ir ref goes to the struct IR_tx instance */ - tx->ir = get_ir_device(ir, true); - - /* A tx ref goes to the i2c_client */ - i2c_set_clientdata(client, get_ir_tx(ir)); - - /* - * Load the 'firmware'. We do this before registering with - * lirc_dev, so the first firmware load attempt does not happen - * after a open() or write() call on the device. - * - * Failure here is not deemed catastrophic, so the receiver will - * still be usable. Firmware load will be retried in write(), - * if it is needed. - */ - fw_load(tx); - - /* Proceed only if the Rx client is also ready or not needed */ - if (rx == NULL && !tx_only) { - zilog_info("probe of IR Tx on %s (i2c-%d) done. Waiting" - " on IR Rx.\n", adap->name, adap->nr); - goto out_ok; - } - } else { - /* Get the IR_tx instance for later, if already allocated */ - tx = get_ir_tx(ir); - - /* Set up a struct IR_rx instance */ - rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL); - if (rx == NULL) { - ret = -ENOMEM; - goto out_put_xx; - } - kref_init(&rx->ref); - ir->rx = rx; - - ir->l.features |= LIRC_CAN_REC_LIRCCODE; - mutex_init(&rx->client_lock); - rx->c = client; - rx->hdpvr_data_fmt = - (id->driver_data & ID_FLAG_HDPVR) ? true : false; - - /* An ir ref goes to the struct IR_rx instance */ - rx->ir = get_ir_device(ir, true); - - /* An rx ref goes to the i2c_client */ - i2c_set_clientdata(client, get_ir_rx(ir)); - - /* - * Start the polling thread. - * It will only perform an empty loop around schedule_timeout() - * until we register with lirc_dev and the first user open() - */ - /* An ir ref goes to the new rx polling kthread */ - rx->task = kthread_run(lirc_thread, get_ir_device(ir, true), - "zilog-rx-i2c-%d", adap->nr); - if (IS_ERR(rx->task)) { - ret = PTR_ERR(rx->task); - zilog_error("%s: could not start IR Rx polling thread" - "\n", __func__); - /* Failed kthread, so put back the ir ref */ - put_ir_device(ir, true); - /* Failure exit, so put back rx ref from i2c_client */ - i2c_set_clientdata(client, NULL); - put_ir_rx(rx, true); - ir->l.features &= ~LIRC_CAN_REC_LIRCCODE; - goto out_put_xx; - } - - /* Proceed only if the Tx client is also ready */ - if (tx == NULL) { - zilog_info("probe of IR Rx on %s (i2c-%d) done. Waiting" - " on IR Tx.\n", adap->name, adap->nr); - goto out_ok; - } - } - - /* register with lirc */ - ir->l.minor = minor; /* module option: user requested minor number */ - ir->l.minor = lirc_register_driver(&ir->l); - if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { - zilog_error("%s: \"minor\" must be between 0 and %d (%d)!\n", - __func__, MAX_IRCTL_DEVICES-1, ir->l.minor); - ret = -EBADRQC; - goto out_put_xx; - } - zilog_info("IR unit on %s (i2c-%d) registered as lirc%d and ready\n", - adap->name, adap->nr, ir->l.minor); - -out_ok: - if (rx != NULL) - put_ir_rx(rx, true); - if (tx != NULL) - put_ir_tx(tx, true); - put_ir_device(ir, true); - zilog_info("probe of IR %s on %s (i2c-%d) done\n", - tx_probe ? "Tx" : "Rx", adap->name, adap->nr); - mutex_unlock(&ir_devices_lock); - return 0; - -out_put_xx: - if (rx != NULL) - put_ir_rx(rx, true); - if (tx != NULL) - put_ir_tx(tx, true); -out_put_ir: - put_ir_device(ir, true); -out_no_ir: - zilog_error("%s: probing IR %s on %s (i2c-%d) failed with %d\n", - __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr, - ret); - mutex_unlock(&ir_devices_lock); - return ret; -} - -static int __init zilog_init(void) -{ - int ret; - - zilog_notify("Zilog/Hauppauge IR driver initializing\n"); - - mutex_init(&tx_data_lock); - - request_module("firmware_class"); - - ret = i2c_add_driver(&driver); - if (ret) - zilog_error("initialization failed\n"); - else - zilog_notify("initialization complete\n"); - - return ret; -} - -static void __exit zilog_exit(void) -{ - i2c_del_driver(&driver); - /* if loaded */ - fw_unload(); - zilog_notify("Zilog/Hauppauge IR driver unloaded\n"); -} - -module_init(zilog_init); -module_exit(zilog_exit); - -MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)"); -MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " - "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, " - "Andy Walls"); -MODULE_LICENSE("GPL"); -/* for compat with old name, which isn't all that accurate anymore */ -MODULE_ALIAS("lirc_pvr150"); - -module_param(minor, int, 0444); -MODULE_PARM_DESC(minor, "Preferred minor device number"); - -module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "Enable debugging messages"); - -module_param(tx_only, bool, 0644); -MODULE_PARM_DESC(tx_only, "Only handle the IR transmit function"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/lirc/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -# Makefile for the lirc drivers. -# - -# Each configuration option enables a list of files. - -obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o -obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o -obj-$(CONFIG_LIRC_IMON) += lirc_imon.o -obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o -obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o -obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o -obj-$(CONFIG_LIRC_SIR) += lirc_sir.o -obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o -obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/Kconfig 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -config VIDEO_TM6000 - tristate "TV Master TM5600/6000/6010 driver" - depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL - select VIDEO_TUNER - select MEDIA_TUNER_XC2028 - select MEDIA_TUNER_XC5000 - select VIDEOBUF_VMALLOC - help - Support for TM5600/TM6000/TM6010 USB Device - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the usb bus, so you need - an external software decoder to watch TV on your computer. - - Say Y if you own such a device and want to use it. - -config VIDEO_TM6000_ALSA - tristate "TV Master TM5600/6000/6010 audio support" - depends on VIDEO_TM6000 && SND && EXPERIMENTAL - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio for - TM5600/TM6000/TM6010 USB Devices. - - To compile this driver as a module, choose M here: the - module will be called tm6000-alsa. - -config VIDEO_TM6000_DVB - tristate "DVB Support for tm6000 based TV cards" - depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL - select DVB_ZL10353 - ---help--- - This adds support for DVB cards based on the tm5600/tm6000 chip. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -tm6000-y := tm6000-cards.o \ - tm6000-core.o \ - tm6000-i2c.o \ - tm6000-video.o \ - tm6000-stds.o \ - tm6000-input.o - -obj-$(CONFIG_VIDEO_TM6000) += tm6000.o -obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o -obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o - -ccflags-y := -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners -ccflags-y += -Idrivers/media/dvb/dvb-core -ccflags-y += -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-alsa.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-alsa.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-alsa.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-alsa.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,519 +0,0 @@ -/* - * - * Support for audio capture for tm5600/6000/6010 - * (c) 2007-2008 Mauro Carvalho Chehab - * - * Based on cx88-alsa.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -#include "tm6000.h" -#include "tm6000-regs.h" - -#undef dprintk - -#define dprintk(level, fmt, arg...) do { \ - if (debug >= level) \ - printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \ - } while (0) - -/**************************************************************************** - Module global static vars - ****************************************************************************/ - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ - -static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; - -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled."); - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s)."); - - -/**************************************************************************** - Module macros - ****************************************************************************/ - -MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Trident,tm5600}," - "{{Trident,tm6000}," - "{{Trident,tm6010}"); -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); - -/**************************************************************************** - Module specific funtions - ****************************************************************************/ - -/* - * BOARD Specific: Sets audio DMA - */ - -static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip) -{ - struct tm6000_core *core = chip->core; - - dprintk(1, "Starting audio DMA\n"); - - /* Enables audio */ - tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x40, 0x40); - - tm6000_set_audio_bitrate(core, 48000); - - tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0x80); - - return 0; -} - -/* - * BOARD Specific: Resets audio DMA - */ -static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip) -{ - struct tm6000_core *core = chip->core; - - dprintk(1, "Stopping audio DMA\n"); - - /* Disables audio */ - tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x00, 0x40); - - tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0); - - return 0; -} - -static void dsp_buffer_free(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - dprintk(2, "Freeing buffer\n"); - - vfree(substream->runtime->dma_area); - substream->runtime->dma_area = NULL; - substream->runtime->dma_bytes = 0; -} - -static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - dprintk(2, "Allocating buffer\n"); - - if (substream->runtime->dma_area) { - if (substream->runtime->dma_bytes > size) - return 0; - dsp_buffer_free(substream); - } - - substream->runtime->dma_area = vmalloc(size); - if (!substream->runtime->dma_area) - return -ENOMEM; - - substream->runtime->dma_bytes = size; - - return 0; -} - - -/**************************************************************************** - ALSA PCM Interface - ****************************************************************************/ - -/* - * Digital hardware definition - */ -#define DEFAULT_FIFO_SIZE 4096 - -static struct snd_pcm_hardware snd_tm6000_digital_hw = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_CONTINUOUS, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .period_bytes_min = 64, - .period_bytes_max = 12544, - .periods_min = 1, - .periods_max = 98, - .buffer_bytes_max = 62720 * 8, -}; - -/* - * audio pcm capture open callback - */ -static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - err = snd_pcm_hw_constraint_pow2(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) - goto _error; - - chip->substream = substream; - - runtime->hw = snd_tm6000_digital_hw; - - return 0; -_error: - dprintk(1, "Error opening PCM!\n"); - return err; -} - -/* - * audio close callback - */ -static int snd_tm6000_close(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct tm6000_core *core = chip->core; - - if (atomic_read(&core->stream_started) > 0) { - atomic_set(&core->stream_started, 0); - schedule_work(&core->wq_trigger); - } - - return 0; -} - -static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size) -{ - struct snd_tm6000_card *chip = core->adev; - struct snd_pcm_substream *substream = chip->substream; - struct snd_pcm_runtime *runtime; - int period_elapsed = 0; - unsigned int stride, buf_pos; - int length; - - if (atomic_read(&core->stream_started) == 0) - return 0; - - if (!size || !substream) { - dprintk(1, "substream was NULL\n"); - return -EINVAL; - } - - runtime = substream->runtime; - if (!runtime || !runtime->dma_area) { - dprintk(1, "runtime was NULL\n"); - return -EINVAL; - } - - buf_pos = chip->buf_pos; - stride = runtime->frame_bits >> 3; - - if (stride == 0) { - dprintk(1, "stride is zero\n"); - return -EINVAL; - } - - length = size / stride; - if (length == 0) { - dprintk(1, "%s: length was zero\n", __func__); - return -EINVAL; - } - - dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size, - runtime->dma_area, buf_pos, - (unsigned int)runtime->buffer_size, stride); - - if (buf_pos + length >= runtime->buffer_size) { - unsigned int cnt = runtime->buffer_size - buf_pos; - memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride); - memcpy(runtime->dma_area, buf + cnt * stride, - length * stride - cnt * stride); - } else - memcpy(runtime->dma_area + buf_pos * stride, buf, - length * stride); - -#ifndef NO_PCM_LOCK - snd_pcm_stream_lock(substream); -#endif - - chip->buf_pos += length; - if (chip->buf_pos >= runtime->buffer_size) - chip->buf_pos -= runtime->buffer_size; - - chip->period_pos += length; - if (chip->period_pos >= runtime->period_size) { - chip->period_pos -= runtime->period_size; - period_elapsed = 1; - } - -#ifndef NO_PCM_LOCK - snd_pcm_stream_unlock(substream); -#endif - - if (period_elapsed) - snd_pcm_period_elapsed(substream); - - return 0; -} - -/* - * hw_params callback - */ -static int snd_tm6000_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - int size, rc; - - size = params_period_bytes(hw_params) * params_periods(hw_params); - - rc = dsp_buffer_alloc(substream, size); - if (rc < 0) - return rc; - - return 0; -} - -/* - * hw free callback - */ -static int snd_tm6000_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct tm6000_core *core = chip->core; - - if (atomic_read(&core->stream_started) > 0) { - atomic_set(&core->stream_started, 0); - schedule_work(&core->wq_trigger); - } - - return 0; -} - -/* - * prepare callback - */ -static int snd_tm6000_prepare(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - chip->buf_pos = 0; - chip->period_pos = 0; - - return 0; -} - - -/* - * trigger callback - */ -static void audio_trigger(struct work_struct *work) -{ - struct tm6000_core *core = container_of(work, struct tm6000_core, - wq_trigger); - struct snd_tm6000_card *chip = core->adev; - - if (atomic_read(&core->stream_started)) { - dprintk(1, "starting capture"); - _tm6000_start_audio_dma(chip); - } else { - dprintk(1, "stopping capture"); - _tm6000_stop_audio_dma(chip); - } -} - -static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct tm6000_core *core = chip->core; - int err = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - atomic_set(&core->stream_started, 1); - break; - case SNDRV_PCM_TRIGGER_STOP: - atomic_set(&core->stream_started, 0); - break; - default: - err = -EINVAL; - break; - } - schedule_work(&core->wq_trigger); - - return err; -} -/* - * pointer callback - */ -static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - return chip->buf_pos; -} - -/* - * operators - */ -static struct snd_pcm_ops snd_tm6000_pcm_ops = { - .open = snd_tm6000_pcm_open, - .close = snd_tm6000_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_tm6000_hw_params, - .hw_free = snd_tm6000_hw_free, - .prepare = snd_tm6000_prepare, - .trigger = snd_tm6000_card_trigger, - .pointer = snd_tm6000_pointer, -}; - -/* - * create a PCM device - */ - -/* FIXME: Control interface - How to control volume/mute? */ - -/**************************************************************************** - Basic Flow for Sound Devices - ****************************************************************************/ - -/* - * Alsa Constructor - Component probe - */ -int tm6000_audio_init(struct tm6000_core *dev) -{ - struct snd_card *card; - struct snd_tm6000_card *chip; - int rc; - static int devnr; - char component[14]; - struct snd_pcm *pcm; - - if (!dev) - return 0; - - if (devnr >= SNDRV_CARDS) - return -ENODEV; - - if (!enable[devnr]) - return -ENOENT; - - rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card); - if (rc < 0) { - snd_printk(KERN_ERR "cannot create card instance %d\n", devnr); - return rc; - } - strcpy(card->driver, "tm6000-alsa"); - strcpy(card->shortname, "TM5600/60x0"); - sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d", - dev->udev->bus->busnum, dev->udev->devnum); - - sprintf(component, "USB%04x:%04x", - le16_to_cpu(dev->udev->descriptor.idVendor), - le16_to_cpu(dev->udev->descriptor.idProduct)); - snd_component_add(card, component); - snd_card_set_dev(card, &dev->udev->dev); - - chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL); - if (!chip) { - rc = -ENOMEM; - goto error; - } - - chip->core = dev; - chip->card = card; - dev->adev = chip; - spin_lock_init(&chip->reg_lock); - - rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm); - if (rc < 0) - goto error_chip; - - pcm->info_flags = 0; - pcm->private_data = chip; - strcpy(pcm->name, "Trident TM5600/60x0"); - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops); - - INIT_WORK(&dev->wq_trigger, audio_trigger); - rc = snd_card_register(card); - if (rc < 0) - goto error_chip; - - dprintk(1,"Registered audio driver for %s\n", card->longname); - - return 0; - -error_chip: - kfree(chip); - dev->adev = NULL; -error: - snd_card_free(card); - return rc; -} - -static int tm6000_audio_fini(struct tm6000_core *dev) -{ - struct snd_tm6000_card *chip = dev->adev; - - if (!dev) - return 0; - - if (!chip) - return 0; - - if (!chip->card) - return 0; - - snd_card_free(chip->card); - chip->card = NULL; - kfree(chip); - dev->adev = NULL; - - return 0; -} - -struct tm6000_ops audio_ops = { - .type = TM6000_AUDIO, - .name = "TM6000 Audio Extension", - .init = tm6000_audio_init, - .fini = tm6000_audio_fini, - .fillbuf = tm6000_fillbuf, -}; - -static int __init tm6000_alsa_register(void) -{ - return tm6000_register_extension(&audio_ops); -} - -static void __exit tm6000_alsa_unregister(void) -{ - tm6000_unregister_extension(&audio_ops); -} - -module_init(tm6000_alsa_register); -module_exit(tm6000_alsa_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-cards.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-cards.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1090 +0,0 @@ -/* - * tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tm6000.h" -#include "tm6000-regs.h" -#include "tuner-xc2028.h" -#include "xc5000.h" - -#define TM6000_BOARD_UNKNOWN 0 -#define TM5600_BOARD_GENERIC 1 -#define TM6000_BOARD_GENERIC 2 -#define TM6010_BOARD_GENERIC 3 -#define TM5600_BOARD_10MOONS_UT821 4 -#define TM5600_BOARD_10MOONS_UT330 5 -#define TM6000_BOARD_ADSTECH_DUAL_TV 6 -#define TM6000_BOARD_FREECOM_AND_SIMILAR 7 -#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8 -#define TM6010_BOARD_HAUPPAUGE_900H 9 -#define TM6010_BOARD_BEHOLD_WANDER 10 -#define TM6010_BOARD_BEHOLD_VOYAGER 11 -#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12 -#define TM6010_BOARD_TWINHAN_TU501 13 -#define TM6010_BOARD_BEHOLD_WANDER_LITE 14 -#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15 -#define TM5600_BOARD_TERRATEC_GRABSTER 16 - -#define TM6000_MAXBOARDS 16 -static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET }; - -module_param_array(card, int, NULL, 0444); - -static unsigned long tm6000_devused; - - -struct tm6000_board { - char *name; - - struct tm6000_capabilities caps; - enum tm6000_inaudio aradio; - enum tm6000_inaudio avideo; - - enum tm6000_devtype type; /* variant of the chipset */ - int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - int demod_addr; /* demodulator address */ - - struct tm6000_gpio gpio; - - char *ir_codes; -}; - -struct tm6000_board tm6000_boards[] = { - [TM6000_BOARD_UNKNOWN] = { - .name = "Unknown tm6000 video grabber", - .caps = { - .has_tuner = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - }, - [TM5600_BOARD_GENERIC] = { - .name = "Generic tm5600 board", - .type = TM5600, - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc2 >> 1, - .caps = { - .has_tuner = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - }, - [TM6000_BOARD_GENERIC] = { - .name = "Generic tm6000 board", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc2 >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - }, - [TM6010_BOARD_GENERIC] = { - .name = "Generic tm6010 board", - .type = TM6010, - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - }, - [TM5600_BOARD_10MOONS_UT821] = { - .name = "10Moons UT 821", - .tuner_type = TUNER_XC2028, - .type = TM5600, - .tuner_addr = 0xc2 >> 1, - .caps = { - .has_tuner = 1, - .has_eeprom = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - }, - [TM5600_BOARD_10MOONS_UT330] = { - .name = "10Moons UT 330", - .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4, - .tuner_addr = 0xc8 >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - }, - }, - [TM6000_BOARD_ADSTECH_DUAL_TV] = { - .name = "ADSTECH Dual TV USB", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc8 >> 1, - .caps = { - .has_tuner = 1, - .has_tda9874 = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - }, - }, - [TM6000_BOARD_FREECOM_AND_SIMILAR] = { - .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 0, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_4, - }, - }, - [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = { - .name = "ADSTECH Mini Dual TV USB", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc8 >> 1, - .demod_addr = 0x1e >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 0, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_4, - }, - }, - [TM6010_BOARD_HAUPPAUGE_900H] = { - .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - }, - [TM6010_BOARD_BEHOLD_WANDER] = { - .name = "Beholder Wander DVB-T/TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .avideo = TM6000_AIP_SIF1, - .aradio = TM6000_AIP_LINE1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - .has_input_comp = 1, - .has_input_svid = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .demod_reset = TM6010_GPIO_1, - .power_led = TM6010_GPIO_6, - }, - }, - [TM6010_BOARD_BEHOLD_VOYAGER] = { - .name = "Beholder Voyager TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .type = TM6010, - .avideo = TM6000_AIP_SIF1, - .aradio = TM6000_AIP_LINE1, - .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - .has_remote = 1, - .has_input_comp = 1, - .has_input_svid = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .power_led = TM6010_GPIO_6, - }, - }, - [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = { - .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, - }, - [TM5600_BOARD_TERRATEC_GRABSTER] = { - .name = "Terratec Grabster AV 150/250 MX", - .type = TM5600, - .tuner_type = TUNER_ABSENT, - }, - [TM6010_BOARD_TWINHAN_TU501] = { - .name = "Twinhan TU501(704D1)", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - }, - [TM6010_BOARD_BEHOLD_WANDER_LITE] = { - .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .avideo = TM6000_AIP_SIF1, - .aradio = TM6000_AIP_LINE1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 0, - .has_input_comp = 0, - .has_input_svid = 0, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .demod_reset = TM6010_GPIO_1, - .power_led = TM6010_GPIO_6, - }, - }, - [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = { - .name = "Beholder Voyager Lite TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .type = TM6010, - .avideo = TM6000_AIP_SIF1, - .aradio = TM6000_AIP_LINE1, - .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - .has_remote = 0, - .has_input_comp = 0, - .has_input_svid = 0, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .power_led = TM6010_GPIO_6, - }, - }, -}; - -/* table of devices that work with this driver */ -struct usb_device_id tm6000_id_table[] = { - { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_10MOONS_UT821 }, - { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC }, - { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV }, - { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR }, - { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV }, - { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER }, - { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER }, - { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, - { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, - { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER }, - { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE }, - { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, - { }, -}; - -/* Control power led for show some activity */ -void tm6000_flash_led(struct tm6000_core *dev, u8 state) -{ - /* Power LED unconfigured */ - if (!dev->gpio.power_led) - return; - - /* ON Power LED */ - if (state) { - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x00); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x01); - break; - } - } - /* OFF Power LED */ - else { - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x01); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x00); - break; - } - } -} - -/* Tuner callback to provide the proper gpio changes needed for xc5000 */ -int tm6000_xc5000_callback(void *ptr, int component, int command, int arg) -{ - int rc = 0; - struct tm6000_core *dev = ptr; - - if (dev->tuner_type != TUNER_XC5000) - return 0; - - switch (command) { - case XC5000_TUNER_RESET: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(15); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - msleep(15); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - break; - } - return rc; -} -EXPORT_SYMBOL_GPL(tm6000_xc5000_callback); - -/* Tuner callback to provide the proper gpio changes needed for xc2028 */ - -int tm6000_tuner_callback(void *ptr, int component, int command, int arg) -{ - int rc = 0; - struct tm6000_core *dev = ptr; - - if (dev->tuner_type != TUNER_XC2028) - return 0; - - switch (command) { - case XC2028_RESET_CLK: - tm6000_ir_wait(dev, 0); - - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, - 0x02, arg); - msleep(10); - rc = tm6000_i2c_reset(dev, 10); - break; - case XC2028_TUNER_RESET: - /* Reset codes during load firmware */ - switch (arg) { - case 0: - /* newer tuner can faster reset */ - switch (dev->model) { - case TM5600_BOARD_10MOONS_UT821: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - 0x300, 0x01); - msleep(10); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - 0x300, 0x00); - msleep(10); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - 0x300, 0x01); - break; - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(60); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - msleep(75); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(60); - break; - default: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - msleep(130); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(130); - break; - } - - tm6000_ir_wait(dev, 1); - break; - case 1: - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, - 0x02, 0x01); - msleep(10); - break; - case 2: - rc = tm6000_i2c_reset(dev, 100); - break; - } - } - return rc; -} -EXPORT_SYMBOL_GPL(tm6000_tuner_callback); - -int tm6000_cards_setup(struct tm6000_core *dev) -{ - int i, rc; - - /* - * Board-specific initialization sequence. Handles all GPIO - * initialization sequences that are board-specific. - * Up to now, all found devices use GPIO1 and GPIO4 at the same way. - * Probably, they're all based on some reference device. Due to that, - * there's a common routine at the end to handle those GPIO's. Devices - * that use different pinups or init sequences can just return at - * the board-specific session. - */ - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - case TM6010_BOARD_GENERIC: - /* Turn xceive 3028 on */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01); - msleep(15); - /* Turn zarlink zl10353 on */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); - msleep(15); - /* Reset zarlink zl10353 */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); - msleep(50); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); - msleep(15); - /* Turn zarlink zl10353 off */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01); - msleep(15); - /* ir ? */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01); - msleep(15); - /* Power led on (blue) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00); - msleep(15); - /* DVB led off (orange) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01); - msleep(15); - /* Turn zarlink zl10353 on */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); - msleep(15); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - /* Power led on (blue) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); - msleep(15); - /* Reset zarlink zl10353 */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); - msleep(50); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); - msleep(15); - break; - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - /* Power led on (blue) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); - msleep(15); - break; - default: - break; - } - - /* - * Default initialization. Most of the devices seem to use GPIO1 - * and GPIO4.on the same way, so, this handles the common sequence - * used by most devices. - * If a device uses a different sequence or different GPIO pins for - * reset, just add the code at the board-specific part - */ - - if (dev->gpio.tuner_reset) { - for (i = 0; i < 2; i++) { - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - if (rc < 0) { - printk(KERN_ERR "Error %i doing tuner reset\n", rc); - return rc; - } - - msleep(10); /* Just to be conservative */ - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - if (rc < 0) { - printk(KERN_ERR "Error %i doing tuner reset\n", rc); - return rc; - } - } - } else { - printk(KERN_ERR "Tuner reset is not configured\n"); - return -1; - } - - msleep(50); - - return 0; -}; - -static void tm6000_config_tuner(struct tm6000_core *dev) -{ - struct tuner_setup tun_setup; - - /* Load tuner module */ - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tuner", dev->tuner_addr, NULL); - - memset(&tun_setup, 0, sizeof(tun_setup)); - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - - tun_setup.mode_mask = 0; - if (dev->caps.has_tuner) - tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO); - - switch (dev->tuner_type) { - case TUNER_XC2028: - tun_setup.tuner_callback = tm6000_tuner_callback; - break; - case TUNER_XC5000: - tun_setup.tuner_callback = tm6000_xc5000_callback; - break; - } - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); - - switch (dev->tuner_type) { - case TUNER_XC2028: { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); - memset(&ctl, 0, sizeof(ctl)); - - ctl.input1 = 1; - ctl.read_not_reliable = 0; - ctl.msleep = 10; - ctl.demod = XC3028_FE_ZARLINK456; - ctl.vhfbw7 = 1; - ctl.uhfbw8 = 1; - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - ctl.fname = "xc3028L-v36.fw"; - break; - default: - if (dev->dev_type == TM6010) - ctl.fname = "xc3028-v27.fw"; - else - ctl.fname = "xc3028-v24.fw"; - } - - printk(KERN_INFO "Setting firmware parameters for xc2028\n"); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, - &xc2028_cfg); - - } - break; - case TUNER_XC5000: - { - struct v4l2_priv_tun_config xc5000_cfg; - struct xc5000_config ctl = { - .i2c_address = dev->tuner_addr, - .if_khz = 4570, - .radio_input = XC5000_RADIO_FM1_MONO, - }; - - xc5000_cfg.tuner = TUNER_XC5000; - xc5000_cfg.priv = &ctl; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, - &xc5000_cfg); - } - break; - default: - printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n"); - break; - } -} - -static int tm6000_init_dev(struct tm6000_core *dev) -{ - struct v4l2_frequency f; - int rc = 0; - - mutex_init(&dev->lock); - - mutex_lock(&dev->lock); - - /* Initializa board-specific data */ - dev->dev_type = tm6000_boards[dev->model].type; - dev->tuner_type = tm6000_boards[dev->model].tuner_type; - dev->tuner_addr = tm6000_boards[dev->model].tuner_addr; - - dev->gpio = tm6000_boards[dev->model].gpio; - - dev->ir_codes = tm6000_boards[dev->model].ir_codes; - - dev->demod_addr = tm6000_boards[dev->model].demod_addr; - - dev->caps = tm6000_boards[dev->model].caps; - - dev->avideo = tm6000_boards[dev->model].avideo; - dev->aradio = tm6000_boards[dev->model].aradio; - /* initialize hardware */ - rc = tm6000_init(dev); - if (rc < 0) - goto err; - - rc = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev); - if (rc < 0) - goto err; - - /* register i2c bus */ - rc = tm6000_i2c_register(dev); - if (rc < 0) - goto err; - - /* Default values for STD and resolutions */ - dev->width = 720; - dev->height = 480; - dev->norm = V4L2_STD_PAL_M; - - /* Configure tuner */ - tm6000_config_tuner(dev); - - /* Set video standard */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); - - /* Set tuner frequency - also loads firmware on xc2028/xc3028 */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 3092; /* 193.25 MHz */ - dev->freq = f.frequency; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); - - if (dev->caps.has_tda9874) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tvaudio", I2C_ADDR_TDA9874, NULL); - - /* register and initialize V4L2 */ - rc = tm6000_v4l2_register(dev); - if (rc < 0) - goto err; - - tm6000_add_into_devlist(dev); - tm6000_init_extension(dev); - - tm6000_ir_init(dev); - - mutex_unlock(&dev->lock); - return 0; - -err: - mutex_unlock(&dev->lock); - return rc; -} - -/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ -#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) - -static void get_max_endpoint(struct usb_device *udev, - struct usb_host_interface *alt, - char *msgtype, - struct usb_host_endpoint *curr_e, - struct tm6000_endpoint *tm_ep) -{ - u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize); - unsigned int size = tmp & 0x7ff; - - if (udev->speed == USB_SPEED_HIGH) - size = size * hb_mult(tmp); - - if (size > tm_ep->maxsize) { - tm_ep->endp = curr_e; - tm_ep->maxsize = size; - tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber; - tm_ep->bAlternateSetting = alt->desc.bAlternateSetting; - - printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n", - msgtype, curr_e->desc.bEndpointAddress, - size); - } -} - -/* - * tm6000_usb_probe() - * checks for supported devices - */ -static int tm6000_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *usbdev; - struct tm6000_core *dev = NULL; - int i, rc = 0; - int nr = 0; - char *speed; - - usbdev = usb_get_dev(interface_to_usbdev(interface)); - - /* Selects the proper interface */ - rc = usb_set_interface(usbdev, 0, 1); - if (rc < 0) - goto err; - - /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS); - if (nr >= TM6000_MAXBOARDS) { - printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS); - usb_put_dev(usbdev); - return -ENOMEM; - } - - /* Create and initialize dev struct */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - printk(KERN_ERR "tm6000" ": out of memory!\n"); - usb_put_dev(usbdev); - return -ENOMEM; - } - spin_lock_init(&dev->slock); - - /* Increment usage count */ - tm6000_devused |= 1<name, 29, "tm6000 #%d", nr); - - dev->model = id->driver_info; - if ((card[nr] >= 0) && (card[nr] < ARRAY_SIZE(tm6000_boards))) - dev->model = card[nr]; - - dev->udev = usbdev; - dev->devno = nr; - - switch (usbdev->speed) { - case USB_SPEED_LOW: - speed = "1.5"; - break; - case USB_SPEED_UNKNOWN: - case USB_SPEED_FULL: - speed = "12"; - break; - case USB_SPEED_HIGH: - speed = "480"; - break; - default: - speed = "unknown"; - } - - - - /* Get endpoints */ - for (i = 0; i < interface->num_altsetting; i++) { - int ep; - - for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { - struct usb_host_endpoint *e; - int dir_out; - - e = &interface->altsetting[i].endpoint[ep]; - - dir_out = ((e->desc.bEndpointAddress & - USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); - - printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n", - i, - interface->altsetting[i].desc.bInterfaceNumber, - interface->altsetting[i].desc.bInterfaceClass); - - switch (e->desc.bmAttributes) { - case USB_ENDPOINT_XFER_BULK: - if (!dir_out) { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "Bulk IN", e, - &dev->bulk_in); - } else { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "Bulk OUT", e, - &dev->bulk_out); - } - break; - case USB_ENDPOINT_XFER_ISOC: - if (!dir_out) { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "ISOC IN", e, - &dev->isoc_in); - } else { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "ISOC OUT", e, - &dev->isoc_out); - } - break; - case USB_ENDPOINT_XFER_INT: - if (!dir_out) { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "INT IN", e, - &dev->int_in); - } else { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "INT OUT", e, - &dev->int_out); - } - break; - } - } - } - - - printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n", - speed, - le16_to_cpu(dev->udev->descriptor.idVendor), - le16_to_cpu(dev->udev->descriptor.idProduct), - interface->altsetting->desc.bInterfaceNumber); - -/* check if the the device has the iso in endpoint at the correct place */ - if (!dev->isoc_in.endp) { - printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n"); - rc = -ENODEV; - - goto err; - } - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name); - - rc = tm6000_init_dev(dev); - - if (rc < 0) - goto err; - - return 0; - -err: - printk(KERN_ERR "tm6000: Error %d while registering\n", rc); - - tm6000_devused &= ~(1<name); - - tm6000_ir_fini(dev); - - if (dev->gpio.power_led) { - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - /* Power led off */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x01); - msleep(15); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - /* Power led off */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x00); - msleep(15); - break; - } - } - tm6000_v4l2_unregister(dev); - - tm6000_i2c_unregister(dev); - - v4l2_device_unregister(&dev->v4l2_dev); - - dev->state |= DEV_DISCONNECTED; - - usb_put_dev(dev->udev); - - tm6000_close_extension(dev); - tm6000_remove_from_devlist(dev); - - kfree(dev); -} - -static struct usb_driver tm6000_usb_driver = { - .name = "tm6000", - .probe = tm6000_usb_probe, - .disconnect = tm6000_usb_disconnect, - .id_table = tm6000_id_table, -}; - -static int __init tm6000_module_init(void) -{ - int result; - - printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n", - (TM6000_VERSION >> 16) & 0xff, - (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff); - - /* register this driver with the USB subsystem */ - result = usb_register(&tm6000_usb_driver); - if (result) - printk(KERN_ERR "tm6000" - " usb_register failed. Error number %d.\n", result); - - return result; -} - -static void __exit tm6000_module_exit(void) -{ - /* deregister at USB subsystem */ - usb_deregister(&tm6000_usb_driver); -} - -module_init(tm6000_module_init); -module_exit(tm6000_module_exit); - -MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter"); -MODULE_AUTHOR("Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-core.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-core.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,928 +0,0 @@ -/* - * tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * Copyright (C) 2007 Michel Ludwig - * - DVB-T support - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "tm6000.h" -#include "tm6000-regs.h" -#include -#include - -#define USB_TIMEOUT (5 * HZ) /* ms */ - -int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, - u16 value, u16 index, u8 *buf, u16 len) -{ - int ret, i; - unsigned int pipe; - u8 *data = NULL; - - if (len) - data = kzalloc(len, GFP_KERNEL); - - - if (req_type & USB_DIR_IN) - pipe = usb_rcvctrlpipe(dev->udev, 0); - else { - pipe = usb_sndctrlpipe(dev->udev, 0); - memcpy(data, buf, len); - } - - if (tm6000_debug & V4L2_DEBUG_I2C) { - printk("(dev %p, pipe %08x): ", dev->udev, pipe); - - printk("%s: %02x %02x %02x %02x %02x %02x %02x %02x ", - (req_type & USB_DIR_IN) ? " IN" : "OUT", - req_type, req, value&0xff, value>>8, index&0xff, - index>>8, len&0xff, len>>8); - - if (!(req_type & USB_DIR_IN)) { - printk(">>> "); - for (i = 0; i < len; i++) - printk(" %02x", buf[i]); - printk("\n"); - } - } - - ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, - data, len, USB_TIMEOUT); - - if (req_type & USB_DIR_IN) - memcpy(buf, data, len); - - if (tm6000_debug & V4L2_DEBUG_I2C) { - if (ret < 0) { - if (req_type & USB_DIR_IN) - printk("<<< (len=%d)\n", len); - - printk("%s: Error #%d\n", __FUNCTION__, ret); - } else if (req_type & USB_DIR_IN) { - printk("<<< "); - for (i = 0; i < len; i++) - printk(" %02x", buf[i]); - printk("\n"); - } - } - - kfree(data); - - msleep(5); - - return ret; -} - -int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - return - tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, - req, value, index, NULL, 0); -} -EXPORT_SYMBOL_GPL(tm6000_set_reg); - -int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - int rc; - u8 buf[1]; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 1); - - if (rc < 0) - return rc; - - return *buf; -} -EXPORT_SYMBOL_GPL(tm6000_get_reg); - -int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, - u16 index, u16 mask) -{ - int rc; - u8 buf[1]; - u8 new_index; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 1); - - if (rc < 0) - return rc; - - new_index = (buf[0] & ~mask) | (index & mask); - - if (new_index == index) - return 0; - - return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, - req, value, new_index, NULL, 0); -} -EXPORT_SYMBOL_GPL(tm6000_set_reg_mask); - -int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - int rc; - u8 buf[2]; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 2); - - if (rc < 0) - return rc; - - return buf[1]|buf[0]<<8; -} - -int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - int rc; - u8 buf[4]; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 4); - - if (rc < 0) - return rc; - - return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24; -} - -int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep) -{ - int rc; - - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0); - if (rc < 0) - return rc; - - msleep(tsleep); - - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1); - msleep(tsleep); - - return rc; -} - -void tm6000_set_fourcc_format(struct tm6000_core *dev) -{ - if (dev->dev_type == TM6010) { - int val; - - val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0) & 0xfc; - if (dev->fourcc == V4L2_PIX_FMT_UYVY) - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val); - else - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val | 1); - } else { - if (dev->fourcc == V4L2_PIX_FMT_UYVY) - tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); - else - tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90); - } -} - -static void tm6000_set_vbi(struct tm6000_core *dev) -{ - /* - * FIXME: - * VBI lines and start/end are different between 60Hz and 50Hz - * So, it is very likely that we need to change the config to - * something that takes it into account, doing something different - * if (dev->norm & V4L2_STD_525_60) - */ - - if (dev->dev_type == TM6010) { - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27); - tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55); - tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66); - tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66); - tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00); - tm6000_set_reg(dev, - TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00); - tm6000_set_reg(dev, - TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01); - tm6000_set_reg(dev, - TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00); - tm6000_set_reg(dev, - TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02); - tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35); - tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0); - tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11); - tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c); - tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01); - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); - } -} - -int tm6000_init_analog_mode(struct tm6000_core *dev) -{ - struct v4l2_frequency f; - - if (dev->dev_type == TM6010) { - /* Enable video */ - - tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, - 0x60, 0x60); - tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, - 0x00, 0x40); - tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc); - - } else { - /* Enables soft reset */ - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - - if (dev->scaler) - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20); - else /* Enable Hfilter and disable TS Drop err */ - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80); - - tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88); - tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23); - tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0); - tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8); - tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06); - tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f); - - /* AP Software reset */ - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); - - tm6000_set_fourcc_format(dev); - - /* Disables soft reset */ - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); - - /* E3: Select input 0 - TV tuner */ - tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00); - tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x60); - - /* This controls input */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_2, 0x0); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_3, 0x01); - } - msleep(20); - - /* Tuner firmware can now be loaded */ - - /* - * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected - * for more than a few seconds. Not sure why, as this behavior does - * not happen on other devices with xc3028. So, I suspect that it - * is yet another bug at tm6000. After start sleeping, decoding - * doesn't start automatically. Instead, it requires some - * I2C commands to wake it up. As we want to have image at the - * beginning, we needed to add this hack. The better would be to - * discover some way to make tm6000 to wake up without this hack. - */ - f.frequency = dev->freq; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); - - msleep(100); - tm6000_set_standard(dev, &dev->norm); - tm6000_set_vbi(dev); - tm6000_set_audio_bitrate(dev, 48000); - - /* switch dvb led off */ - if (dev->gpio.dvb_led) { - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.dvb_led, 0x01); - } - - return 0; -} - -int tm6000_init_digital_mode(struct tm6000_core *dev) -{ - if (dev->dev_type == TM6010) { - int val; - u8 buf[2]; - - /* digital init */ - val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0); - val &= ~0x60; - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val); - val = tm6000_get_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0); - val |= 0x40; - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val); - tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28); - tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc); - tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff); - tm6000_read_write_usb(dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2); - printk(KERN_INFO"buf %#x %#x\n", buf[0], buf[1]); - } else { - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08); - tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); - tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8); - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40); - tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); - tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09); - tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37); - tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8); - tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0); - tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60); - - tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); - tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08); - msleep(50); - - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); - msleep(50); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01); - msleep(50); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); - msleep(100); - } - - /* switch dvb led on */ - if (dev->gpio.dvb_led) { - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.dvb_led, 0x00); - } - - return 0; -} -EXPORT_SYMBOL(tm6000_init_digital_mode); - -struct reg_init { - u8 req; - u8 reg; - u8 val; -}; - -/* The meaning of those initializations are unknown */ -struct reg_init tm6000_init_tab[] = { - /* REG VALUE */ - { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f }, - { TM6010_REQ07_RFF_SOFT_RESET, 0x08 }, - { TM6010_REQ07_RFF_SOFT_RESET, 0x00 }, - { TM6010_REQ07_RD5_POWERSAVE, 0x4f }, - { TM6000_REQ07_RDA_CLK_SEL, 0x23 }, - { TM6000_REQ07_RDB_OUT_SEL, 0x08 }, - { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 }, - { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 }, - { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 }, - { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 }, - { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 }, /* 48000 bits/sample, external input */ - { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 }, - - { TM6010_REQ07_R3F_RESET, 0x01 }, /* Start of soft reset */ - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, - { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, - { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, - { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, - { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, - { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, - { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, - { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, - { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, - { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, - { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, - { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, - { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, - { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, - { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, - { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, - { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, - { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, - { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, - { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, - { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, - { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, - { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, - { TM6010_REQ07_RC3_HSTART1, 0x88 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, /* End of the soft reset */ - { TM6010_REQ05_R18_IMASK7, 0x00 }, -}; - -struct reg_init tm6010_init_tab[] = { - { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 }, - { TM6010_REQ07_RC4_HSTART0, 0xa0 }, - { TM6010_REQ07_RC6_HEND0, 0x40 }, - { TM6010_REQ07_RCA_VEND0, 0x31 }, - { TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0xe1 }, - { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 }, - { TM6010_REQ07_RFE_POWER_DOWN, 0x7f }, - - { TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 }, - { TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 }, - { TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 }, - { TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 }, - { TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 }, - { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 }, - { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 }, - { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 }, - { TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00}, - { TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80}, - { TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a}, - { TM6010_REQ08_R0D_A_AMD_THRES, 0x40}, - { TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64}, - { TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20}, - { TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe}, - { TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01}, - { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc }, - - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, - { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, - { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, - { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, - { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, - { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, - { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, - { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, - { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, - { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, - { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, - { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, - { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, - { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, - { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, - { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, - { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, - { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, - { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, - { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, - { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, - { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, - { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, - { TM6010_REQ07_RC3_HSTART1, 0x88 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - - { TM6010_REQ05_R18_IMASK7, 0x00 }, - - { TM6010_REQ07_RD8_IR_LEADER1, 0xaa }, - { TM6010_REQ07_RD8_IR_LEADER0, 0x30 }, - { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 }, - { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 }, - { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 }, - { TM6010_REQ07_RD8_IR, 0x2f }, - - /* set remote wakeup key:any key wakeup */ - { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe }, - { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff }, -}; - -int tm6000_init(struct tm6000_core *dev) -{ - int board, rc = 0, i, size; - struct reg_init *tab; - - /* Check board revision */ - board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0); - if (board >= 0) { - switch (board & 0xff) { - case 0xf3: - printk(KERN_INFO "Found tm6000\n"); - if (dev->dev_type != TM6000) - dev->dev_type = TM6000; - break; - case 0xf4: - printk(KERN_INFO "Found tm6010\n"); - if (dev->dev_type != TM6010) - dev->dev_type = TM6010; - break; - default: - printk(KERN_INFO "Unknown board version = 0x%08x\n", board); - } - } else - printk(KERN_ERR "Error %i while retrieving board version\n", board); - - if (dev->dev_type == TM6010) { - tab = tm6010_init_tab; - size = ARRAY_SIZE(tm6010_init_tab); - } else { - tab = tm6000_init_tab; - size = ARRAY_SIZE(tm6000_init_tab); - } - - /* Load board's initialization table */ - for (i = 0; i < size; i++) { - rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val); - if (rc < 0) { - printk(KERN_ERR "Error %i while setting req %d, " - "reg %d to value %d\n", rc, - tab[i].req, tab[i].reg, tab[i].val); - return rc; - } - } - - msleep(5); /* Just to be conservative */ - - rc = tm6000_cards_setup(dev); - - return rc; -} - -int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) -{ - int val = 0; - u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ - u8 areg_0a = 0x91; /* SIF 48KHz */ - - switch (bitrate) { - case 48000: - areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ - areg_0a = 0x91; /* SIF 48KHz */ - dev->audio_bitrate = bitrate; - break; - case 32000: - areg_f0 = 0x00; /* ADC MCLK = 375 Fs */ - areg_0a = 0x90; /* SIF 32KHz */ - dev->audio_bitrate = bitrate; - break; - default: - return -EINVAL; - } - - - /* enable I2S, if we use sif or external I2S device */ - if (dev->dev_type == TM6010) { - val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a); - if (val < 0) - return val; - - val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - areg_f0, 0xf0); - if (val < 0) - return val; - } else { - val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, - areg_f0, 0xf0); - if (val < 0) - return val; - } - return 0; -} -EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); - -int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp) -{ - if (dev->dev_type == TM6010) { - /* Audio crossbar setting, default SIF1 */ - u8 areg_f0 = 0x03; - - switch (ainp) { - case TM6000_AIP_SIF1: - case TM6000_AIP_SIF2: - areg_f0 = 0x03; - break; - case TM6000_AIP_LINE1: - areg_f0 = 0x00; - break; - case TM6000_AIP_LINE2: - areg_f0 = 0x08; - break; - default: - return 0; - break; - } - /* Set audio input crossbar */ - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - areg_f0, 0x0f); - } else { - /* Audio setting, default LINE1 */ - u8 areg_eb = 0x00; - - switch (ainp) { - case TM6000_AIP_LINE1: - areg_eb = 0x00; - break; - case TM6000_AIP_LINE2: - areg_eb = 0x04; - break; - default: - return 0; - break; - } - /* Set audio input */ - tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, - areg_eb, 0x0f); - } - return 0; -} -EXPORT_SYMBOL_GPL(tm6000_set_audio_input); - -void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute) -{ - u8 mute_reg = 0; - - if (mute) - mute_reg = 0x08; - - tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08); -} - -void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute) -{ - u8 mute_reg = 0; - - if (mute) - mute_reg = 0x20; - - if (dev->dev_type == TM6010) { - tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, - mute_reg, 0x20); - tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, - mute_reg, 0x20); - } else { - tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, - mute_reg, 0x20); - tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, - mute_reg, 0x20); - } -} - -int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute) -{ - enum tm6000_inaudio ainp; - - if (dev->radio) - ainp = dev->aradio; - else - ainp = dev->avideo; - - switch (ainp) { - case TM6000_AIP_SIF1: - case TM6000_AIP_SIF2: - if (dev->dev_type == TM6010) - tm6010_set_mute_sif(dev, mute); - else { - printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" - " SIF audio inputs. Please check the %s" - " configuration.\n", dev->name); - return -EINVAL; - } - break; - case TM6000_AIP_LINE1: - case TM6000_AIP_LINE2: - tm6010_set_mute_adc(dev, mute); - break; - default: - return -EINVAL; - break; - } - return 0; -} -EXPORT_SYMBOL_GPL(tm6000_tvaudio_set_mute); - -void tm6010_set_volume_sif(struct tm6000_core *dev, int vol) -{ - u8 vol_reg; - - vol_reg = vol & 0x0F; - - if (vol < 0) - vol_reg |= 0x40; - - tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg); - tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg); -} - -void tm6010_set_volume_adc(struct tm6000_core *dev, int vol) -{ - u8 vol_reg; - - vol_reg = (vol + 0x10) & 0x1f; - - if (dev->dev_type == TM6010) { - tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg); - tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg); - } else { - tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg); - tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg); - } -} - -void tm6000_set_volume(struct tm6000_core *dev, int vol) -{ - enum tm6000_inaudio ainp; - - if (dev->radio) { - ainp = dev->aradio; - vol += 8; /* Offset to 0 dB */ - } else - ainp = dev->avideo; - - switch (ainp) { - case TM6000_AIP_SIF1: - case TM6000_AIP_SIF2: - if (dev->dev_type == TM6010) - tm6010_set_volume_sif(dev, vol); - else - printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" - " SIF audio inputs. Please check the %s" - " configuration.\n", dev->name); - break; - case TM6000_AIP_LINE1: - case TM6000_AIP_LINE2: - tm6010_set_volume_adc(dev, vol); - break; - default: - break; - } -} -EXPORT_SYMBOL_GPL(tm6000_set_volume); - -static LIST_HEAD(tm6000_devlist); -static DEFINE_MUTEX(tm6000_devlist_mutex); - -/* - * tm6000_realease_resource() - */ - -void tm6000_remove_from_devlist(struct tm6000_core *dev) -{ - mutex_lock(&tm6000_devlist_mutex); - list_del(&dev->devlist); - mutex_unlock(&tm6000_devlist_mutex); -}; - -void tm6000_add_into_devlist(struct tm6000_core *dev) -{ - mutex_lock(&tm6000_devlist_mutex); - list_add_tail(&dev->devlist, &tm6000_devlist); - mutex_unlock(&tm6000_devlist_mutex); -}; - -/* - * Extension interface - */ - -static LIST_HEAD(tm6000_extension_devlist); - -int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type, - char *buf, int size) -{ - struct tm6000_ops *ops = NULL; - - /* FIXME: tm6000_extension_devlist_lock should be a spinlock */ - - if (!list_empty(&tm6000_extension_devlist)) { - list_for_each_entry(ops, &tm6000_extension_devlist, next) { - if (ops->fillbuf && ops->type == type) - ops->fillbuf(dev, buf, size); - } - } - - return 0; -} - -int tm6000_register_extension(struct tm6000_ops *ops) -{ - struct tm6000_core *dev = NULL; - - mutex_lock(&tm6000_devlist_mutex); - list_add_tail(&ops->next, &tm6000_extension_devlist); - list_for_each_entry(dev, &tm6000_devlist, devlist) { - ops->init(dev); - printk(KERN_INFO "%s: Initialized (%s) extension\n", - dev->name, ops->name); - } - mutex_unlock(&tm6000_devlist_mutex); - return 0; -} -EXPORT_SYMBOL(tm6000_register_extension); - -void tm6000_unregister_extension(struct tm6000_ops *ops) -{ - struct tm6000_core *dev = NULL; - - mutex_lock(&tm6000_devlist_mutex); - list_for_each_entry(dev, &tm6000_devlist, devlist) - ops->fini(dev); - - printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name); - list_del(&ops->next); - mutex_unlock(&tm6000_devlist_mutex); -} -EXPORT_SYMBOL(tm6000_unregister_extension); - -void tm6000_init_extension(struct tm6000_core *dev) -{ - struct tm6000_ops *ops = NULL; - - mutex_lock(&tm6000_devlist_mutex); - if (!list_empty(&tm6000_extension_devlist)) { - list_for_each_entry(ops, &tm6000_extension_devlist, next) { - if (ops->init) - ops->init(dev); - } - } - mutex_unlock(&tm6000_devlist_mutex); -} - -void tm6000_close_extension(struct tm6000_core *dev) -{ - struct tm6000_ops *ops = NULL; - - mutex_lock(&tm6000_devlist_mutex); - if (!list_empty(&tm6000_extension_devlist)) { - list_for_each_entry(ops, &tm6000_extension_devlist, next) { - if (ops->fini) - ops->fini(dev); - } - } - mutex_unlock(&tm6000_devlist_mutex); -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-dvb.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-dvb.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,452 +0,0 @@ -/* - * tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2007 Michel Ludwig - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include - -#include "tm6000.h" -#include "tm6000-regs.h" - -#include "zl10353.h" - -#include - -#include "tuner-xc2028.h" -#include "xc5000.h" - -MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -MODULE_SUPPORTED_DEVICE("{{Trident, tm5600}," - "{{Trident, tm6000}," - "{{Trident, tm6010}"); - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug message"); - -static inline void print_err_status(struct tm6000_core *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - dprintk(dev, 1, "URB status %d [%s].\n", - status, errmsg); - } else { - dprintk(dev, 1, "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -static void tm6000_urb_received(struct urb *urb) -{ - int ret; - struct tm6000_core *dev = urb->context; - - if (urb->status != 0) - print_err_status(dev, 0, urb->status); - else if (urb->actual_length > 0) - dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer, - urb->actual_length); - - if (dev->dvb->streams > 0) { - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) { - printk(KERN_ERR "tm6000: error %s\n", __FUNCTION__); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } - } -} - -int tm6000_start_stream(struct tm6000_core *dev) -{ - int ret; - unsigned int pipe, size; - struct tm6000_dvb *dvb = dev->dvb; - - printk(KERN_INFO "tm6000: got start stream request %s\n", __FUNCTION__); - - if (dev->mode != TM6000_MODE_DIGITAL) { - tm6000_init_digital_mode(dev); - dev->mode = TM6000_MODE_DIGITAL; - } - - dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); - if (dvb->bulk_urb == NULL) { - printk(KERN_ERR "tm6000: couldn't allocate urb\n"); - return -ENOMEM; - } - - pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); - size = size * 15; /* 512 x 8 or 12 or 15 */ - - dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); - if (dvb->bulk_urb->transfer_buffer == NULL) { - usb_free_urb(dvb->bulk_urb); - printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n"); - return -ENOMEM; - } - - usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe, - dvb->bulk_urb->transfer_buffer, - size, - tm6000_urb_received, dev); - - ret = usb_clear_halt(dev->udev, pipe); - if (ret < 0) { - printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n", - ret, __FUNCTION__); - return ret; - } else - printk(KERN_ERR "tm6000: pipe resetted\n"); - -/* mutex_lock(&tm6000_driver.open_close_mutex); */ - ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL); - -/* mutex_unlock(&tm6000_driver.open_close_mutex); */ - if (ret) { - printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n", - ret); - - kfree(dvb->bulk_urb->transfer_buffer); - usb_free_urb(dvb->bulk_urb); - return ret; - } - - return 0; -} - -void tm6000_stop_stream(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb = dev->dvb; - - if (dvb->bulk_urb) { - printk(KERN_INFO "urb killing\n"); - usb_kill_urb(dvb->bulk_urb); - printk(KERN_INFO "urb buffer free\n"); - kfree(dvb->bulk_urb->transfer_buffer); - usb_free_urb(dvb->bulk_urb); - dvb->bulk_urb = NULL; - } -} - -int tm6000_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct tm6000_core *dev = demux->priv; - struct tm6000_dvb *dvb = dev->dvb; - printk(KERN_INFO "tm6000: got start feed request %s\n", __FUNCTION__); - - mutex_lock(&dvb->mutex); - if (dvb->streams == 0) { - dvb->streams = 1; -/* mutex_init(&tm6000_dev->streming_mutex); */ - tm6000_start_stream(dev); - } else - ++(dvb->streams); - mutex_unlock(&dvb->mutex); - - return 0; -} - -int tm6000_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct tm6000_core *dev = demux->priv; - struct tm6000_dvb *dvb = dev->dvb; - - printk(KERN_INFO "tm6000: got stop feed request %s\n", __FUNCTION__); - - mutex_lock(&dvb->mutex); - - printk(KERN_INFO "stream %#x\n", dvb->streams); - --(dvb->streams); - if (dvb->streams == 0) { - printk(KERN_INFO "stop stream\n"); - tm6000_stop_stream(dev); -/* mutex_destroy(&tm6000_dev->streaming_mutex); */ - } - mutex_unlock(&dvb->mutex); -/* mutex_destroy(&tm6000_dev->streaming_mutex); */ - - return 0; -} - -int tm6000_dvb_attach_frontend(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb = dev->dvb; - - if (dev->caps.has_zl10353) { - struct zl10353_config config = { - .demod_address = dev->demod_addr, - .no_tuner = 1, - .parallel_ts = 1, - .if2 = 45700, - .disable_i2c_gate_ctrl = 1, - }; - - dvb->frontend = dvb_attach(zl10353_attach, &config, - &dev->i2c_adap); - } else { - printk(KERN_ERR "tm6000: no frontend defined for the device!\n"); - return -1; - } - - return (!dvb->frontend) ? -1 : 0; -} - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -int register_dvb(struct tm6000_core *dev) -{ - int ret = -1; - struct tm6000_dvb *dvb = dev->dvb; - - mutex_init(&dvb->mutex); - - dvb->streams = 0; - - /* attach the frontend */ - ret = tm6000_dvb_attach_frontend(dev); - if (ret < 0) { - printk(KERN_ERR "tm6000: couldn't attach the frontend!\n"); - goto err; - } - - ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T", - THIS_MODULE, &dev->udev->dev, adapter_nr); - dvb->adapter.priv = dev; - - if (dvb->frontend) { - switch (dev->tuner_type) { - case TUNER_XC2028: { - struct xc2028_config cfg = { - .i2c_adap = &dev->i2c_adap, - .i2c_addr = dev->tuner_addr, - }; - - dvb->frontend->callback = tm6000_tuner_callback; - ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (ret < 0) { - printk(KERN_ERR - "tm6000: couldn't register frontend\n"); - goto adapter_err; - } - - if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register " - "frontend (xc3028)\n"); - ret = -EINVAL; - goto frontend_err; - } - printk(KERN_INFO "tm6000: XC2028/3028 asked to be " - "attached to frontend!\n"); - break; - } - case TUNER_XC5000: { - struct xc5000_config cfg = { - .i2c_address = dev->tuner_addr, - }; - - dvb->frontend->callback = tm6000_xc5000_callback; - ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (ret < 0) { - printk(KERN_ERR - "tm6000: couldn't register frontend\n"); - goto adapter_err; - } - - if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register " - "frontend (xc5000)\n"); - ret = -EINVAL; - goto frontend_err; - } - printk(KERN_INFO "tm6000: XC5000 asked to be " - "attached to frontend!\n"); - break; - } - } - } else - printk(KERN_ERR "tm6000: no frontend found\n"); - - dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING - | DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dev; - dvb->demux.filternum = 8; - dvb->demux.feednum = 8; - dvb->demux.start_feed = tm6000_start_feed; - dvb->demux.stop_feed = tm6000_stop_feed; - dvb->demux.write_to_decoder = NULL; - ret = dvb_dmx_init(&dvb->demux); - if (ret < 0) { - printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret); - goto frontend_err; - } - - dvb->dmxdev.filternum = dev->dvb->demux.filternum; - dvb->dmxdev.demux = &dev->dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (ret < 0) { - printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret); - goto dvb_dmx_err; - } - - return 0; - -dvb_dmx_err: - dvb_dmx_release(&dvb->demux); -frontend_err: - if (dvb->frontend) { - dvb_frontend_detach(dvb->frontend); - dvb_unregister_frontend(dvb->frontend); - } -adapter_err: - dvb_unregister_adapter(&dvb->adapter); -err: - return ret; -} - -void unregister_dvb(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb = dev->dvb; - - if (dvb->bulk_urb != NULL) { - struct urb *bulk_urb = dvb->bulk_urb; - - kfree(bulk_urb->transfer_buffer); - bulk_urb->transfer_buffer = NULL; - usb_unlink_urb(bulk_urb); - usb_free_urb(bulk_urb); - } - -/* mutex_lock(&tm6000_driver.open_close_mutex); */ - if (dvb->frontend) { - dvb_frontend_detach(dvb->frontend); - dvb_unregister_frontend(dvb->frontend); - } - - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_adapter(&dvb->adapter); - mutex_destroy(&dvb->mutex); -/* mutex_unlock(&tm6000_driver.open_close_mutex); */ -} - -static int dvb_init(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb; - int rc; - - if (!dev) - return 0; - - if (!dev->caps.has_dvb) - return 0; - - dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL); - if (!dvb) { - printk(KERN_INFO "Cannot allocate memory\n"); - return -ENOMEM; - } - - dev->dvb = dvb; - - rc = register_dvb(dev); - if (rc < 0) { - kfree(dvb); - dev->dvb = NULL; - return 0; - } - - return 0; -} - -static int dvb_fini(struct tm6000_core *dev) -{ - if (!dev) - return 0; - - if (!dev->caps.has_dvb) - return 0; - - if (dev->dvb) { - unregister_dvb(dev); - kfree(dev->dvb); - dev->dvb = NULL; - } - - return 0; -} - -static struct tm6000_ops dvb_ops = { - .type = TM6000_DVB, - .name = "TM6000 dvb Extension", - .init = dvb_init, - .fini = dvb_fini, -}; - -static int __init tm6000_dvb_register(void) -{ - return tm6000_register_extension(&dvb_ops); -} - -static void __exit tm6000_dvb_unregister(void) -{ - tm6000_unregister_extension(&dvb_ops); -} - -module_init(tm6000_dvb_register); -module_exit(tm6000_dvb_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,380 +0,0 @@ -/* - * tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * Copyright (C) 2007 Michel Ludwig - * - DVB-T support - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Use the tm6000-hack, instead of the proper initialization code i*/ -/* #define HACK 1 */ - -#include -#include -#include -#include "tm6000-usb-isoc.h" -#include -#include -#include - - -#include -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dmxdev.h" - -#define TM6000_VERSION KERNEL_VERSION(0, 0, 2) - -/* Inputs */ - -enum tm6000_itype { - TM6000_INPUT_TV = 0, - TM6000_INPUT_COMPOSITE, - TM6000_INPUT_SVIDEO, -}; - -enum tm6000_devtype { - TM6000 = 0, - TM5600, - TM6010, -}; - -enum tm6000_inaudio { - TM6000_AIP_UNK = 0, - TM6000_AIP_SIF1, - TM6000_AIP_SIF2, - TM6000_AIP_LINE1, - TM6000_AIP_LINE2, -}; - -/* ------------------------------------------------------------------ - * Basic structures - * ------------------------------------------------------------------ - */ - -struct tm6000_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; -}; - -/* buffer for one video frame */ -struct tm6000_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - struct tm6000_fmt *fmt; -}; - -struct tm6000_dmaqueue { - struct list_head active; - struct list_head queued; - - /* thread for generating video stream*/ - struct task_struct *kthread; - wait_queue_head_t wq; - /* Counters to control fps rate */ - int frame; - int ini_jiffies; -}; - -/* device states */ -enum tm6000_core_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -/* io methods */ -enum tm6000_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -enum tm6000_mode { - TM6000_MODE_UNKNOWN = 0, - TM6000_MODE_ANALOG, - TM6000_MODE_DIGITAL, -}; - -struct tm6000_gpio { - int tuner_reset; - int tuner_on; - int demod_reset; - int demod_on; - int power_led; - int dvb_led; - int ir; -}; - -struct tm6000_capabilities { - unsigned int has_tuner:1; - unsigned int has_tda9874:1; - unsigned int has_dvb:1; - unsigned int has_zl10353:1; - unsigned int has_eeprom:1; - unsigned int has_remote:1; - unsigned int has_input_comp:1; - unsigned int has_input_svid:1; -}; - -struct tm6000_dvb { - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dvb_frontend *frontend; - struct dmxdev dmxdev; - unsigned int streams; - struct urb *bulk_urb; - struct mutex mutex; -}; - -struct snd_tm6000_card { - struct snd_card *card; - spinlock_t reg_lock; - struct tm6000_core *core; - struct snd_pcm_substream *substream; - - /* temporary data for buffer fill processing */ - unsigned buf_pos; - unsigned period_pos; -}; - -struct tm6000_endpoint { - struct usb_host_endpoint *endp; - __u8 bInterfaceNumber; - __u8 bAlternateSetting; - unsigned maxsize; -}; - -struct tm6000_core { - /* generic device properties */ - char name[30]; /* name (including minor) of the device */ - int model; /* index in the device_data struct */ - int devno; /* marks the number of this device */ - enum tm6000_devtype dev_type; /* type of device */ - - v4l2_std_id norm; /* Current norm */ - int width, height; /* Selected resolution */ - - enum tm6000_core_state state; - - /* Device Capabilities*/ - struct tm6000_capabilities caps; - - /* Tuner configuration */ - int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - - struct tm6000_gpio gpio; - - char *ir_codes; - - __u8 radio; - - /* Demodulator configuration */ - int demod_addr; /* demodulator address */ - - int audio_bitrate; - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; - - - /* extension */ - struct list_head devlist; - - /* video for linux */ - int users; - - /* various device info */ - struct tm6000_fh *resources; /* Points to fh that is streaming */ - bool is_res_read; - - struct video_device *vfd; - struct video_device *radio_dev; - struct tm6000_dmaqueue vidq; - struct v4l2_device v4l2_dev; - - int input; - int freq; - unsigned int fourcc; - - enum tm6000_mode mode; - - int ctl_mute; /* audio */ - int ctl_volume; - - /* DVB-T support */ - struct tm6000_dvb *dvb; - - /* audio support */ - struct snd_tm6000_card *adev; - struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ - atomic_t stream_started; /* stream should be running if true */ - enum tm6000_inaudio avideo; - enum tm6000_inaudio aradio; - - struct tm6000_IR *ir; - - /* locks */ - struct mutex lock; - - /* usb transfer */ - struct usb_device *udev; /* the usb device */ - - struct tm6000_endpoint bulk_in, bulk_out, isoc_in, isoc_out; - struct tm6000_endpoint int_in, int_out; - - /* scaler!=0 if scaler is active*/ - int scaler; - - /* Isoc control struct */ - struct usb_isoc_ctl isoc_ctl; - - spinlock_t slock; -}; - -enum tm6000_ops_type { - TM6000_AUDIO = 0x10, - TM6000_DVB = 0x20, -}; - -struct tm6000_ops { - struct list_head next; - char *name; - enum tm6000_ops_type type; - int (*init)(struct tm6000_core *); - int (*fini)(struct tm6000_core *); - int (*fillbuf)(struct tm6000_core *, char *buf, int size); -}; - -struct tm6000_fh { - struct tm6000_core *dev; - unsigned int radio; - - /* video capture */ - struct tm6000_fmt *fmt; - unsigned int width, height; - struct videobuf_queue vb_vidq; - - enum v4l2_buf_type type; -}; - -#define TM6000_STD (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc| \ - V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \ - V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM) - -/* In tm6000-cards.c */ - -int tm6000_tuner_callback(void *ptr, int component, int command, int arg); -int tm6000_xc5000_callback(void *ptr, int component, int command, int arg); -int tm6000_cards_setup(struct tm6000_core *dev); -void tm6000_flash_led(struct tm6000_core *dev, u8 state); - -/* In tm6000-core.c */ - -int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req, - u16 value, u16 index, u8 *buf, u16 len); -int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, - u16 index, u16 mask); -int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep); -int tm6000_init(struct tm6000_core *dev); - -int tm6000_init_analog_mode(struct tm6000_core *dev); -int tm6000_init_digital_mode(struct tm6000_core *dev); -int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate); -int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp); -int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute); -void tm6000_set_volume(struct tm6000_core *dev, int vol); - -int tm6000_v4l2_register(struct tm6000_core *dev); -int tm6000_v4l2_unregister(struct tm6000_core *dev); -int tm6000_v4l2_exit(void); -void tm6000_set_fourcc_format(struct tm6000_core *dev); - -void tm6000_remove_from_devlist(struct tm6000_core *dev); -void tm6000_add_into_devlist(struct tm6000_core *dev); -int tm6000_register_extension(struct tm6000_ops *ops); -void tm6000_unregister_extension(struct tm6000_ops *ops); -void tm6000_init_extension(struct tm6000_core *dev); -void tm6000_close_extension(struct tm6000_core *dev); -int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type, - char *buf, int size); - - -/* In tm6000-stds.c */ -void tm6000_get_std_res(struct tm6000_core *dev); -int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id *norm); - -/* In tm6000-i2c.c */ -int tm6000_i2c_register(struct tm6000_core *dev); -int tm6000_i2c_unregister(struct tm6000_core *dev); - -/* In tm6000-queue.c */ - -int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma); - -int tm6000_vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i); -int tm6000_vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type i); -int tm6000_vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb); -int tm6000_vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b); -int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b); -int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b); -ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count, - loff_t *f_pos); -unsigned int tm6000_v4l2_poll(struct file *file, - struct poll_table_struct *wait); -int tm6000_queue_init(struct tm6000_core *dev); - -/* In tm6000-alsa.c */ -/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/ - -/* In tm6000-input.c */ -int tm6000_ir_init(struct tm6000_core *dev); -int tm6000_ir_fini(struct tm6000_core *dev); -void tm6000_ir_wait(struct tm6000_core *dev, u8 state); -int tm6000_ir_int_start(struct tm6000_core *dev); -void tm6000_ir_int_stop(struct tm6000_core *dev); - -/* Debug stuff */ - -extern int tm6000_debug; - -#define dprintk(dev, level, fmt, arg...) do {\ - if (tm6000_debug & level) \ - printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \ - dev->name, __FUNCTION__ , ##arg); } while (0) - -#define V4L2_DEBUG_REG 0x0004 -#define V4L2_DEBUG_I2C 0x0008 -#define V4L2_DEBUG_QUEUE 0x0010 -#define V4L2_DEBUG_ISOC 0x0020 -#define V4L2_DEBUG_RES_LOCK 0x0040 /* Resource locking */ -#define V4L2_DEBUG_OPEN 0x0080 /* video open/close debug */ - -#define tm6000_err(fmt, arg...) do {\ - printk(KERN_ERR "tm6000 %s :"fmt, \ - __FUNCTION__ , ##arg); } while (0) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-i2c.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-i2c.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,346 +0,0 @@ -/* - * tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * Copyright (C) 2007 Michel Ludwig - * - Fix SMBus Read Byte command - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "tm6000.h" -#include "tm6000-regs.h" -#include -#include -#include "tuner-xc2028.h" - - -/* ----------------------------------------------------------- */ - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \ - printk(KERN_DEBUG "%s at %s: " fmt, \ - dev->name, __FUNCTION__ , ##args); } while (0) - -static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr, - __u8 reg, char *buf, int len) -{ - int rc; - unsigned int tsleep; - unsigned int i2c_packet_limit = 16; - - if (dev->dev_type == TM6010) - i2c_packet_limit = 64; - - if (!buf) - return -1; - - if (len < 1 || len > i2c_packet_limit) { - printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", - len, i2c_packet_limit); - return -1; - } - - /* capture mutex */ - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, - addr | reg << 8, 0, buf, len); - - if (rc < 0) { - /* release mutex */ - return rc; - } - - /* Calculate delay time, 14000us for 64 bytes */ - tsleep = ((len * 200) + 200 + 1000) / 1000; - msleep(tsleep); - - /* release mutex */ - return rc; -} - -/* Generic read - doesn't work fine with 16bit registers */ -static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr, - __u8 reg, char *buf, int len) -{ - int rc; - u8 b[2]; - unsigned int i2c_packet_limit = 16; - - if (dev->dev_type == TM6010) - i2c_packet_limit = 64; - - if (!buf) - return -1; - - if (len < 1 || len > i2c_packet_limit) { - printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", - len, i2c_packet_limit); - return -1; - } - - /* capture mutex */ - if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) { - /* - * Workaround an I2C bug when reading from zl10353 - */ - reg -= 1; - len += 1; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len); - - *buf = b[1]; - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len); - } - - /* release mutex */ - return rc; -} - -/* - * read from a 16bit register - * for example xc2028, xc3028 or xc3028L - */ -static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr, - __u16 reg, char *buf, int len) -{ - int rc; - unsigned char ureg; - - if (!buf || len != 2) - return -1; - - /* capture mutex */ - if (dev->dev_type == TM6010) { - ureg = reg & 0xFF; - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, - addr | (reg & 0xFF00), 0, &ureg, 1); - - if (rc < 0) { - /* release mutex */ - return rc; - } - - msleep(1400 / 1000); - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ, - reg, 0, buf, len); - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN, - addr, reg, buf, len); - } - - /* release mutex */ - return rc; -} - -static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) -{ - struct tm6000_core *dev = i2c_adap->algo_data; - int addr, rc, i, byte; - - if (num <= 0) - return 0; - for (i = 0; i < num; i++) { - addr = (msgs[i].addr << 1) & 0xff; - i2c_dprintk(2, "%s %s addr=0x%x len=%d:", - (msgs[i].flags & I2C_M_RD) ? "read" : "write", - i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); - if (msgs[i].flags & I2C_M_RD) { - /* read request without preceding register selection */ - /* - * The TM6000 only supports a read transaction - * immediately after a 1 or 2 byte write to select - * a register. We cannot fulfil this request. - */ - i2c_dprintk(2, " read without preceding write not" - " supported"); - rc = -EOPNOTSUPP; - goto err; - } else if (i + 1 < num && msgs[i].len <= 2 && - (msgs[i + 1].flags & I2C_M_RD) && - msgs[i].addr == msgs[i + 1].addr) { - /* 1 or 2 byte write followed by a read */ - if (i2c_debug >= 2) - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - i2c_dprintk(2, "; joined to read %s len=%d:", - i == num - 2 ? "stop" : "nonstop", - msgs[i + 1].len); - - if (msgs[i].len == 2) { - rc = tm6000_i2c_recv_regs16(dev, addr, - msgs[i].buf[0] << 8 | msgs[i].buf[1], - msgs[i + 1].buf, msgs[i + 1].len); - } else { - rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0], - msgs[i + 1].buf, msgs[i + 1].len); - } - - i++; - - if (addr == dev->tuner_addr << 1) { - tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); - tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); - } - if (i2c_debug >= 2) - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } else { - /* write bytes */ - if (i2c_debug >= 2) - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0], - msgs[i].buf + 1, msgs[i].len - 1); - - if (addr == dev->tuner_addr << 1) { - tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); - tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); - } - } - if (i2c_debug >= 2) - printk("\n"); - if (rc < 0) - goto err; - } - - return num; -err: - i2c_dprintk(2, " ERROR: %i\n", rc); - return rc; -} - -static int tm6000_i2c_eeprom(struct tm6000_core *dev, - unsigned char *eedata, int len) -{ - int i, rc; - unsigned char *p = eedata; - unsigned char bytes[17]; - - dev->i2c_client.addr = 0xa0 >> 1; - - bytes[16] = '\0'; - for (i = 0; i < len; ) { - *p = i; - rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1); - if (rc < 1) { - if (p == eedata) - goto noeeprom; - else { - printk(KERN_WARNING - "%s: i2c eeprom read error (err=%d)\n", - dev->name, rc); - } - return -1; - } - p++; - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); - printk(" %02x", eedata[i]); - if ((eedata[i] >= ' ') && (eedata[i] <= 'z')) - bytes[i%16] = eedata[i]; - else - bytes[i%16] = '.'; - - i++; - - if (0 == (i % 16)) { - bytes[16] = '\0'; - printk(" %s\n", bytes); - } - } - if (0 != (i%16)) { - bytes[i%16] = '\0'; - for (i %= 16; i < 16; i++) - printk(" "); - } - printk(" %s\n", bytes); - - return 0; - -noeeprom: - printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", - dev->name, rc); - return rc; -} - -/* ----------------------------------------------------------- */ - -/* - * functionality() - */ -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm tm6000_algo = { - .master_xfer = tm6000_i2c_xfer, - .functionality = functionality, -}; - -/* ----------------------------------------------------------- */ - -/* - * tm6000_i2c_register() - * register i2c bus - */ -int tm6000_i2c_register(struct tm6000_core *dev) -{ - unsigned char eedata[256]; - int rc; - - dev->i2c_adap.owner = THIS_MODULE; - dev->i2c_adap.algo = &tm6000_algo; - dev->i2c_adap.dev.parent = &dev->udev->dev; - strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name)); - dev->i2c_adap.algo_data = dev; - i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); - rc = i2c_add_adapter(&dev->i2c_adap); - if (rc) - return rc; - - dev->i2c_client.adapter = &dev->i2c_adap; - strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE); - - tm6000_i2c_eeprom(dev, eedata, sizeof(eedata)); - - return 0; -} - -/* - * tm6000_i2c_unregister() - * unregister i2c_bus - */ -int tm6000_i2c_unregister(struct tm6000_core *dev) -{ - i2c_del_adapter(&dev->i2c_adap); - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-input.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-input.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,458 +0,0 @@ -/* - * tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2010 Stefan Ringel - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include - -#include -#include - -#include - -#include "tm6000.h" -#include "tm6000-regs.h" - -static unsigned int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debug message [IR]"); - -static unsigned int enable_ir = 1; -module_param(enable_ir, int, 0644); -MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)"); - -/* number of 50ms for ON-OFF-ON power led */ -/* show IR activity */ -#define PWLED_OFF 2 - -#undef dprintk - -#define dprintk(fmt, arg...) \ - if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ - } - -struct tm6000_ir_poll_result { - u16 rc_data; -}; - -struct tm6000_IR { - struct tm6000_core *dev; - struct rc_dev *rc; - char name[32]; - char phys[32]; - - /* poll expernal decoder */ - int polling; - struct delayed_work work; - u8 wait:1; - u8 key:1; - u8 pwled:1; - u8 pwledcnt; - u16 key_addr; - struct urb *int_urb; - u8 *urb_data; - - int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *); - - /* IR device properties */ - u64 rc_type; -}; - - -void tm6000_ir_wait(struct tm6000_core *dev, u8 state) -{ - struct tm6000_IR *ir = dev->ir; - - if (!dev->ir) - return; - - if (state) - ir->wait = 1; - else - ir->wait = 0; -} - - -static int tm6000_ir_config(struct tm6000_IR *ir) -{ - struct tm6000_core *dev = ir->dev; - u8 buf[10]; - int rc; - - switch (ir->rc_type) { - case RC_TYPE_NEC: - /* Setup IR decoder for NEC standard 12MHz system clock */ - /* IR_LEADER_CNT = 0.9ms */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30); - /* IR_PULSE_CNT = 0.7ms */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0); - /* Remote WAKEUP = enable */ - tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe); - /* IR_WKUP_SEL = Low byte in decoded IR data */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff); - /* IR_WKU_ADD code */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff); - tm6000_flash_led(dev, 0); - msleep(100); - tm6000_flash_led(dev, 1); - break; - default: - /* hack */ - buf[0] = 0xff; - buf[1] = 0xff; - buf[2] = 0xf2; - buf[3] = 0x2b; - buf[4] = 0x20; - buf[5] = 0x35; - buf[6] = 0x60; - buf[7] = 0x04; - buf[8] = 0xc0; - buf[9] = 0x08; - - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a); - msleep(100); - - if (rc < 0) { - printk(KERN_INFO "IR configuration failed"); - return rc; - } - break; - } - - return 0; -} - -static void tm6000_ir_urb_received(struct urb *urb) -{ - struct tm6000_core *dev = urb->context; - struct tm6000_IR *ir = dev->ir; - int rc; - - if (urb->status != 0) - printk(KERN_INFO "not ready\n"); - else if (urb->actual_length > 0) { - memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length); - - dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0], - ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]); - - ir->key = 1; - } - - rc = usb_submit_urb(urb, GFP_ATOMIC); -} - -static int default_polling_getkey(struct tm6000_IR *ir, - struct tm6000_ir_poll_result *poll_result) -{ - struct tm6000_core *dev = ir->dev; - int rc; - u8 buf[2]; - - if (ir->wait && !&dev->int_in) - return 0; - - if (&dev->int_in) { - switch (ir->rc_type) { - case RC_TYPE_RC5: - poll_result->rc_data = ir->urb_data[0]; - break; - case RC_TYPE_NEC: - if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) { - poll_result->rc_data = ir->urb_data[0] - | ir->urb_data[1] << 8; - } - break; - default: - poll_result->rc_data = ir->urb_data[0] - | ir->urb_data[1] << 8; - break; - } - } else { - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); - msleep(10); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1); - msleep(10); - - if (ir->rc_type == RC_TYPE_RC5) { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_02_GET_IR_CODE, 0, 0, buf, 1); - - msleep(10); - - dprintk("read data=%02x\n", buf[0]); - if (rc < 0) - return rc; - - poll_result->rc_data = buf[0]; - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_02_GET_IR_CODE, 0, 0, buf, 2); - - msleep(10); - - dprintk("read data=%04x\n", buf[0] | buf[1] << 8); - if (rc < 0) - return rc; - - poll_result->rc_data = buf[0] | buf[1] << 8; - } - if ((poll_result->rc_data & 0x00ff) != 0xff) - ir->key = 1; - } - return 0; -} - -static void tm6000_ir_handle_key(struct tm6000_IR *ir) -{ - struct tm6000_core *dev = ir->dev; - int result; - struct tm6000_ir_poll_result poll_result; - - /* read the registers containing the IR status */ - result = ir->get_key(ir, &poll_result); - if (result < 0) { - printk(KERN_INFO "ir->get_key() failed %d\n", result); - return; - } - - dprintk("ir->get_key result data=%04x\n", poll_result.rc_data); - - if (ir->pwled) { - if (ir->pwledcnt >= PWLED_OFF) { - ir->pwled = 0; - ir->pwledcnt = 0; - tm6000_flash_led(dev, 1); - } else - ir->pwledcnt += 1; - } - - if (ir->key) { - rc_keydown(ir->rc, poll_result.rc_data, 0); - ir->key = 0; - ir->pwled = 1; - ir->pwledcnt = 0; - tm6000_flash_led(dev, 0); - } - return; -} - -static void tm6000_ir_work(struct work_struct *work) -{ - struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); - - tm6000_ir_handle_key(ir); - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); -} - -static int tm6000_ir_start(struct rc_dev *rc) -{ - struct tm6000_IR *ir = rc->priv; - - INIT_DELAYED_WORK(&ir->work, tm6000_ir_work); - schedule_delayed_work(&ir->work, 0); - - return 0; -} - -static void tm6000_ir_stop(struct rc_dev *rc) -{ - struct tm6000_IR *ir = rc->priv; - - cancel_delayed_work_sync(&ir->work); -} - -int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) -{ - struct tm6000_IR *ir = rc->priv; - - if (!ir) - return 0; - - if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC)) - ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff); - - ir->get_key = default_polling_getkey; - ir->rc_type = rc_type; - - tm6000_ir_config(ir); - /* TODO */ - return 0; -} - -int tm6000_ir_int_start(struct tm6000_core *dev) -{ - struct tm6000_IR *ir = dev->ir; - int pipe, size; - int err = -ENOMEM; - - - if (!ir) - return -ENODEV; - - ir->int_urb = usb_alloc_urb(0, GFP_KERNEL); - - pipe = usb_rcvintpipe(dev->udev, - dev->int_in.endp->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); - dprintk("IR max size: %d\n", size); - - ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); - if (ir->int_urb->transfer_buffer == NULL) { - usb_free_urb(ir->int_urb); - return err; - } - dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval); - usb_fill_int_urb(ir->int_urb, dev->udev, pipe, - ir->int_urb->transfer_buffer, size, - tm6000_ir_urb_received, dev, - dev->int_in.endp->desc.bInterval); - err = usb_submit_urb(ir->int_urb, GFP_KERNEL); - if (err) { - kfree(ir->int_urb->transfer_buffer); - usb_free_urb(ir->int_urb); - return err; - } - ir->urb_data = kzalloc(size, GFP_KERNEL); - - return 0; -} - -void tm6000_ir_int_stop(struct tm6000_core *dev) -{ - struct tm6000_IR *ir = dev->ir; - - if (!ir) - return; - - usb_kill_urb(ir->int_urb); - kfree(ir->int_urb->transfer_buffer); - usb_free_urb(ir->int_urb); - ir->int_urb = NULL; - kfree(ir->urb_data); - ir->urb_data = NULL; -} - -int tm6000_ir_init(struct tm6000_core *dev) -{ - struct tm6000_IR *ir; - struct rc_dev *rc; - int err = -ENOMEM; - - if (!enable_ir) - return -ENODEV; - - if (!dev->caps.has_remote) - return 0; - - if (!dev->ir_codes) - return 0; - - ir = kzalloc(sizeof(*ir), GFP_KERNEL); - rc = rc_allocate_device(); - if (!ir | !rc) - goto out; - - /* record handles to ourself */ - ir->dev = dev; - dev->ir = ir; - ir->rc = rc; - - /* input einrichten */ - rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; - rc->priv = ir; - rc->change_protocol = tm6000_ir_change_protocol; - rc->open = tm6000_ir_start; - rc->close = tm6000_ir_stop; - rc->driver_type = RC_DRIVER_SCANCODE; - - ir->polling = 50; - ir->pwled = 0; - ir->pwledcnt = 0; - - - snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)", - dev->name); - - usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); - strlcat(ir->phys, "/input0", sizeof(ir->phys)); - - tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN); - - rc->input_name = ir->name; - rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_USB; - rc->input_id.version = 1; - rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); - rc->map_name = dev->ir_codes; - rc->driver_name = "tm6000"; - rc->dev.parent = &dev->udev->dev; - - if (&dev->int_in) { - dprintk("IR over int\n"); - - err = tm6000_ir_int_start(dev); - - if (err) - goto out; - } - - /* ir register */ - err = rc_register_device(rc); - if (err) - goto out; - - return 0; - -out: - dev->ir = NULL; - rc_free_device(rc); - kfree(ir); - return err; -} - -int tm6000_ir_fini(struct tm6000_core *dev) -{ - struct tm6000_IR *ir = dev->ir; - - /* skip detach on non attached board */ - - if (!ir) - return 0; - - rc_unregister_device(ir->rc); - - if (ir->int_urb) { - tm6000_ir_int_stop(dev); - } - - kfree(ir); - dev->ir = NULL; - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-regs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-regs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,598 +0,0 @@ -/* - * tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Define TV Master TM5600/TM6000/TM6010 Request codes - */ -#define REQ_00_SET_IR_VALUE 0 -#define REQ_01_SET_WAKEUP_IRCODE 1 -#define REQ_02_GET_IR_CODE 2 -#define REQ_03_SET_GET_MCU_PIN 3 -#define REQ_04_EN_DISABLE_MCU_INT 4 -#define REQ_05_SET_GET_USBREG 5 - /* Write: RegNum, Value, 0 */ - /* Read : RegNum, Value, 1, RegStatus */ -#define REQ_06_SET_GET_USBREG_BIT 6 -#define REQ_07_SET_GET_AVREG 7 - /* Write: RegNum, Value, 0 */ - /* Read : RegNum, Value, 1, RegStatus */ -#define REQ_08_SET_GET_AVREG_BIT 8 -#define REQ_09_SET_GET_TUNER_FQ 9 -#define REQ_10_SET_TUNER_SYSTEM 10 -#define REQ_11_SET_EEPROM_ADDR 11 -#define REQ_12_SET_GET_EEPROMBYTE 12 -#define REQ_13_GET_EEPROM_SEQREAD 13 -#define REQ_14_SET_GET_I2C_WR2_RDN 14 -#define REQ_15_SET_GET_I2CBYTE 15 - /* Write: Subaddr, Slave Addr, value, 0 */ - /* Read : Subaddr, Slave Addr, value, 1 */ -#define REQ_16_SET_GET_I2C_WR1_RDN 16 - /* Subaddr, Slave Addr, 0, length */ -#define REQ_17_SET_GET_I2CFP 17 - /* Write: Slave Addr, register, value */ - /* Read : Slave Addr, register, 2, data */ -#define REQ_20_DATA_TRANSFER 20 -#define REQ_30_I2C_WRITE 30 -#define REQ_31_I2C_READ 31 -#define REQ_35_AFTEK_TUNER_READ 35 -#define REQ_40_GET_VERSION 40 -#define REQ_50_SET_START 50 -#define REQ_51_SET_STOP 51 -#define REQ_52_TRANSMIT_DATA 52 -#define REQ_53_SPI_INITIAL 53 -#define REQ_54_SPI_SETSTART 54 -#define REQ_55_SPI_INOUTDATA 55 -#define REQ_56_SPI_SETSTOP 56 - -/* - * Define TV Master TM5600/TM6000/TM6010 GPIO lines - */ - -#define TM6000_GPIO_CLK 0x101 -#define TM6000_GPIO_DATA 0x100 - -#define TM6000_GPIO_1 0x102 -#define TM6000_GPIO_2 0x103 -#define TM6000_GPIO_3 0x104 -#define TM6000_GPIO_4 0x300 -#define TM6000_GPIO_5 0x301 -#define TM6000_GPIO_6 0x304 -#define TM6000_GPIO_7 0x305 - -/* tm6010 defines GPIO with different values */ -#define TM6010_GPIO_0 0x0102 -#define TM6010_GPIO_1 0x0103 -#define TM6010_GPIO_2 0x0104 -#define TM6010_GPIO_3 0x0105 -#define TM6010_GPIO_4 0x0106 -#define TM6010_GPIO_5 0x0107 -#define TM6010_GPIO_6 0x0300 -#define TM6010_GPIO_7 0x0301 -#define TM6010_GPIO_9 0x0305 -/* - * Define TV Master TM5600/TM6000/TM6010 URB message codes and length - */ - -enum { - TM6000_URB_MSG_VIDEO=1, - TM6000_URB_MSG_AUDIO, - TM6000_URB_MSG_VBI, - TM6000_URB_MSG_PTS, - TM6000_URB_MSG_ERR, -}; - -/* Define specific TM6000 Video decoder registers */ -#define TM6000_REQ07_RD8_TEST_SEL 0x07, 0xd8 -#define TM6000_REQ07_RD9_A_SIM_SEL 0x07, 0xd9 -#define TM6000_REQ07_RDA_CLK_SEL 0x07, 0xda -#define TM6000_REQ07_RDB_OUT_SEL 0x07, 0xdb -#define TM6000_REQ07_RDC_NSEL_I2S 0x07, 0xdc -#define TM6000_REQ07_RDD_GPIO2_MDRV 0x07, 0xdd -#define TM6000_REQ07_RDE_GPIO1_MDRV 0x07, 0xde -#define TM6000_REQ07_RDF_PWDOWN_ACLK 0x07, 0xdf -#define TM6000_REQ07_RE0_VADC_REF_CTL 0x07, 0xe0 -#define TM6000_REQ07_RE1_VADC_DACLIMP 0x07, 0xe1 -#define TM6000_REQ07_RE2_VADC_STATUS_CTL 0x07, 0xe2 -#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1 0x07, 0xe3 -#define TM6000_REQ07_RE4_VADC_TARGET1 0x07, 0xe4 -#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2 0x07, 0xe5 -#define TM6000_REQ07_RE6_VADC_TARGET2 0x07, 0xe6 -#define TM6000_REQ07_RE7_VADC_AGAIN_CTL 0x07, 0xe7 -#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL 0x07, 0xe8 -#define TM6000_REQ07_RE9_VADC_INPUT_CTL1 0x07, 0xe9 -#define TM6000_REQ07_REA_VADC_INPUT_CTL2 0x07, 0xea -#define TM6000_REQ07_REB_VADC_AADC_MODE 0x07, 0xeb -#define TM6000_REQ07_REC_VADC_AADC_LVOL 0x07, 0xec -#define TM6000_REQ07_RED_VADC_AADC_RVOL 0x07, 0xed -#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL 0x07, 0xee -#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL 0x07, 0xef -#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW 0x07, 0xfd -#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH 0x07, 0xfe - -/* Define TM6000/TM6010 Video decoder registers */ -#define TM6010_REQ07_R00_VIDEO_CONTROL0 0x07, 0x00 -#define TM6010_REQ07_R01_VIDEO_CONTROL1 0x07, 0x01 -#define TM6010_REQ07_R02_VIDEO_CONTROL2 0x07, 0x02 -#define TM6010_REQ07_R03_YC_SEP_CONTROL 0x07, 0x03 -#define TM6010_REQ07_R04_LUMA_HAGC_CONTROL 0x07, 0x04 -#define TM6010_REQ07_R05_NOISE_THRESHOLD 0x07, 0x05 -#define TM6010_REQ07_R06_AGC_GATE_THRESHOLD 0x07, 0x06 -#define TM6010_REQ07_R07_OUTPUT_CONTROL 0x07, 0x07 -#define TM6010_REQ07_R08_LUMA_CONTRAST_ADJ 0x07, 0x08 -#define TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ 0x07, 0x09 -#define TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ 0x07, 0x0a -#define TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ 0x07, 0x0b -#define TM6010_REQ07_R0C_CHROMA_AGC_CONTROL 0x07, 0x0c -#define TM6010_REQ07_R0D_CHROMA_KILL_LEVEL 0x07, 0x0d -#define TM6010_REQ07_R0F_CHROMA_AUTO_POSITION 0x07, 0x0f -#define TM6010_REQ07_R10_AGC_PEAK_NOMINAL 0x07, 0x10 -#define TM6010_REQ07_R11_AGC_PEAK_CONTROL 0x07, 0x11 -#define TM6010_REQ07_R12_AGC_GATE_STARTH 0x07, 0x12 -#define TM6010_REQ07_R13_AGC_GATE_STARTL 0x07, 0x13 -#define TM6010_REQ07_R14_AGC_GATE_WIDTH 0x07, 0x14 -#define TM6010_REQ07_R15_AGC_BP_DELAY 0x07, 0x15 -#define TM6010_REQ07_R16_LOCK_COUNT 0x07, 0x16 -#define TM6010_REQ07_R17_HLOOP_MAXSTATE 0x07, 0x17 -#define TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3 0x07, 0x18 -#define TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2 0x07, 0x19 -#define TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1 0x07, 0x1a -#define TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0 0x07, 0x1b -#define TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3 0x07, 0x1c -#define TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2 0x07, 0x1d -#define TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1 0x07, 0x1e -#define TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0 0x07, 0x1f -#define TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME 0x07, 0x20 -#define TM6010_REQ07_R21_HSYNC_PHASE_OFFSET 0x07, 0x21 -#define TM6010_REQ07_R22_HSYNC_PLL_START_TIME 0x07, 0x22 -#define TM6010_REQ07_R23_HSYNC_PLL_END_TIME 0x07, 0x23 -#define TM6010_REQ07_R24_HSYNC_TIP_START_TIME 0x07, 0x24 -#define TM6010_REQ07_R25_HSYNC_TIP_END_TIME 0x07, 0x25 -#define TM6010_REQ07_R26_HSYNC_RISING_EDGE_START 0x07, 0x26 -#define TM6010_REQ07_R27_HSYNC_RISING_EDGE_END 0x07, 0x27 -#define TM6010_REQ07_R28_BACKPORCH_START 0x07, 0x28 -#define TM6010_REQ07_R29_BACKPORCH_END 0x07, 0x29 -#define TM6010_REQ07_R2A_HSYNC_FILTER_START 0x07, 0x2a -#define TM6010_REQ07_R2B_HSYNC_FILTER_END 0x07, 0x2b -#define TM6010_REQ07_R2C_CHROMA_BURST_START 0x07, 0x2c -#define TM6010_REQ07_R2D_CHROMA_BURST_END 0x07, 0x2d -#define TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART 0x07, 0x2e -#define TM6010_REQ07_R2F_ACTIVE_VIDEO_HWIDTH 0x07, 0x2f -#define TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART 0x07, 0x30 -#define TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT 0x07, 0x31 -#define TM6010_REQ07_R32_VSYNC_HLOCK_MIN 0x07, 0x32 -#define TM6010_REQ07_R33_VSYNC_HLOCK_MAX 0x07, 0x33 -#define TM6010_REQ07_R34_VSYNC_AGC_MIN 0x07, 0x34 -#define TM6010_REQ07_R35_VSYNC_AGC_MAX 0x07, 0x35 -#define TM6010_REQ07_R36_VSYNC_VBI_MIN 0x07, 0x36 -#define TM6010_REQ07_R37_VSYNC_VBI_MAX 0x07, 0x37 -#define TM6010_REQ07_R38_VSYNC_THRESHOLD 0x07, 0x38 -#define TM6010_REQ07_R39_VSYNC_TIME_CONSTANT 0x07, 0x39 -#define TM6010_REQ07_R3A_STATUS1 0x07, 0x3a -#define TM6010_REQ07_R3B_STATUS2 0x07, 0x3b -#define TM6010_REQ07_R3C_STATUS3 0x07, 0x3c -#define TM6010_REQ07_R3F_RESET 0x07, 0x3f -#define TM6010_REQ07_R40_TELETEXT_VBI_CODE0 0x07, 0x40 -#define TM6010_REQ07_R41_TELETEXT_VBI_CODE1 0x07, 0x41 -#define TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL 0x07, 0x42 -#define TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7 0x07, 0x43 -#define TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8 0x07, 0x44 -#define TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9 0x07, 0x45 -#define TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10 0x07, 0x46 -#define TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11 0x07, 0x47 -#define TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12 0x07, 0x48 -#define TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13 0x07, 0x49 -#define TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14 0x07, 0x4a -#define TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15 0x07, 0x4b -#define TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16 0x07, 0x4c -#define TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17 0x07, 0x4d -#define TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18 0x07, 0x4e -#define TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19 0x07, 0x4f -#define TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20 0x07, 0x50 -#define TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21 0x07, 0x51 -#define TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22 0x07, 0x52 -#define TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23 0x07, 0x53 -#define TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES 0x07, 0x54 -#define TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN 0x07, 0x55 -#define TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN 0x07, 0x56 -#define TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN 0x07, 0x57 -#define TM6010_REQ07_R58_VBI_CAPTION_DTO1 0x07, 0x58 -#define TM6010_REQ07_R59_VBI_CAPTION_DTO0 0x07, 0x59 -#define TM6010_REQ07_R5A_VBI_TELETEXT_DTO1 0x07, 0x5a -#define TM6010_REQ07_R5B_VBI_TELETEXT_DTO0 0x07, 0x5b -#define TM6010_REQ07_R5C_VBI_WSS625_DTO1 0x07, 0x5c -#define TM6010_REQ07_R5D_VBI_WSS625_DTO0 0x07, 0x5d -#define TM6010_REQ07_R5E_VBI_CAPTION_FRAME_START 0x07, 0x5e -#define TM6010_REQ07_R5F_VBI_WSS625_FRAME_START 0x07, 0x5f -#define TM6010_REQ07_R60_TELETEXT_FRAME_START 0x07, 0x60 -#define TM6010_REQ07_R61_VBI_CCDATA1 0x07, 0x61 -#define TM6010_REQ07_R62_VBI_CCDATA2 0x07, 0x62 -#define TM6010_REQ07_R63_VBI_WSS625_DATA1 0x07, 0x63 -#define TM6010_REQ07_R64_VBI_WSS625_DATA2 0x07, 0x64 -#define TM6010_REQ07_R65_VBI_DATA_STATUS 0x07, 0x65 -#define TM6010_REQ07_R66_VBI_CAPTION_START 0x07, 0x66 -#define TM6010_REQ07_R67_VBI_WSS625_START 0x07, 0x67 -#define TM6010_REQ07_R68_VBI_TELETEXT_START 0x07, 0x68 -#define TM6010_REQ07_R70_HSYNC_DTO_INC_STATUS3 0x07, 0x70 -#define TM6010_REQ07_R71_HSYNC_DTO_INC_STATUS2 0x07, 0x71 -#define TM6010_REQ07_R72_HSYNC_DTO_INC_STATUS1 0x07, 0x72 -#define TM6010_REQ07_R73_HSYNC_DTO_INC_STATUS0 0x07, 0x73 -#define TM6010_REQ07_R74_CHROMA_DTO_INC_STATUS3 0x07, 0x74 -#define TM6010_REQ07_R75_CHROMA_DTO_INC_STATUS2 0x07, 0x75 -#define TM6010_REQ07_R76_CHROMA_DTO_INC_STATUS1 0x07, 0x76 -#define TM6010_REQ07_R77_CHROMA_DTO_INC_STATUS0 0x07, 0x77 -#define TM6010_REQ07_R78_AGC_AGAIN_STATUS 0x07, 0x78 -#define TM6010_REQ07_R79_AGC_DGAIN_STATUS 0x07, 0x79 -#define TM6010_REQ07_R7A_CHROMA_MAG_STATUS 0x07, 0x7a -#define TM6010_REQ07_R7B_CHROMA_GAIN_STATUS1 0x07, 0x7b -#define TM6010_REQ07_R7C_CHROMA_GAIN_STATUS0 0x07, 0x7c -#define TM6010_REQ07_R7D_CORDIC_FREQ_STATUS 0x07, 0x7d -#define TM6010_REQ07_R7F_STATUS_NOISE 0x07, 0x7f -#define TM6010_REQ07_R80_COMB_FILTER_TRESHOLD 0x07, 0x80 -#define TM6010_REQ07_R82_COMB_FILTER_CONFIG 0x07, 0x82 -#define TM6010_REQ07_R83_CHROMA_LOCK_CONFIG 0x07, 0x83 -#define TM6010_REQ07_R84_NOISE_NTSC_C 0x07, 0x84 -#define TM6010_REQ07_R85_NOISE_PAL_C 0x07, 0x85 -#define TM6010_REQ07_R86_NOISE_PHASE_C 0x07, 0x86 -#define TM6010_REQ07_R87_NOISE_PHASE_Y 0x07, 0x87 -#define TM6010_REQ07_R8A_CHROMA_LOOPFILTER_STATE 0x07, 0x8a -#define TM6010_REQ07_R8B_CHROMA_HRESAMPLER 0x07, 0x8b -#define TM6010_REQ07_R8D_CPUMP_DELAY_ADJ 0x07, 0x8d -#define TM6010_REQ07_R8E_CPUMP_ADJ 0x07, 0x8e -#define TM6010_REQ07_R8F_CPUMP_DELAY 0x07, 0x8f - -/* Define TM6000/TM6010 Miscellaneous registers */ -#define TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE 0x07, 0xc0 -#define TM6010_REQ07_RC1_TRESHOLD 0x07, 0xc1 -#define TM6010_REQ07_RC2_HSYNC_WIDTH 0x07, 0xc2 -#define TM6010_REQ07_RC3_HSTART1 0x07, 0xc3 -#define TM6010_REQ07_RC4_HSTART0 0x07, 0xc4 -#define TM6010_REQ07_RC5_HEND1 0x07, 0xc5 -#define TM6010_REQ07_RC6_HEND0 0x07, 0xc6 -#define TM6010_REQ07_RC7_VSTART1 0x07, 0xc7 -#define TM6010_REQ07_RC8_VSTART0 0x07, 0xc8 -#define TM6010_REQ07_RC9_VEND1 0x07, 0xc9 -#define TM6010_REQ07_RCA_VEND0 0x07, 0xca -#define TM6010_REQ07_RCB_DELAY 0x07, 0xcb -/* ONLY for TM6010 */ -#define TM6010_REQ07_RCC_ACTIVE_VIDEO_IF 0x07, 0xcc -#define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL 0x07, 0xd0 -#define TM6010_REQ07_RD1_ADDR_FOR_REQ1 0x07, 0xd1 -#define TM6010_REQ07_RD2_ADDR_FOR_REQ2 0x07, 0xd2 -#define TM6010_REQ07_RD3_ADDR_FOR_REQ3 0x07, 0xd3 -#define TM6010_REQ07_RD4_ADDR_FOR_REQ4 0x07, 0xd4 -#define TM6010_REQ07_RD5_POWERSAVE 0x07, 0xd5 -#define TM6010_REQ07_RD6_ENDP_REQ1_REQ2 0x07, 0xd6 -#define TM6010_REQ07_RD7_ENDP_REQ3_REQ4 0x07, 0xd7 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR 0x07, 0xd8 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_BSIZE 0x07, 0xd9 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_WAKEUP_SEL 0x07, 0xda -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_WAKEUP_ADD 0x07, 0xdb -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_LEADER1 0x07, 0xdc -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_LEADER0 0x07, 0xdd -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_PULSE_CNT1 0x07, 0xde -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_PULSE_CNT0 0x07, 0xdf -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF 0x07, 0xe1 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE2_OUT_SEL2 0x07, 0xe2 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE3_OUT_SEL1 0x07, 0xe3 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE4_OUT_SEL0 0x07, 0xe4 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE5_REMOTE_WAKEUP 0x07, 0xe5 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE7_PUB_GPIO 0x07, 0xe7 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE8_TYPESEL_MOS_I2S 0x07, 0xe8 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE9_TYPESEL_MOS_TS 0x07, 0xe9 -/* ONLY for TM6010 */ -#define TM6010_REQ07_REA_TYPESEL_MOS_CCIR 0x07, 0xea -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF0_BIST_CRC_RESULT0 0x07, 0xf0 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF1_BIST_CRC_RESULT1 0x07, 0xf1 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF2_BIST_CRC_RESULT2 0x07, 0xf2 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF3_BIST_CRC_RESULT3 0x07, 0xf3 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF4_BIST_ERR_VST2 0x07, 0xf4 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF5_BIST_ERR_VST1 0x07, 0xf5 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF6_BIST_ERR_VST0 0x07, 0xf6 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF7_BIST 0x07, 0xf7 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RFE_POWER_DOWN 0x07, 0xfe -#define TM6010_REQ07_RFF_SOFT_RESET 0x07, 0xff - -/* Define TM6000/TM6010 USB registers */ -#define TM6010_REQ05_R00_MAIN_CTRL 0x05, 0x00 -#define TM6010_REQ05_R01_DEVADDR 0x05, 0x01 -#define TM6010_REQ05_R02_TEST 0x05, 0x02 -#define TM6010_REQ05_R04_SOFN0 0x05, 0x04 -#define TM6010_REQ05_R05_SOFN1 0x05, 0x05 -#define TM6010_REQ05_R06_SOFTM0 0x05, 0x06 -#define TM6010_REQ05_R07_SOFTM1 0x05, 0x07 -#define TM6010_REQ05_R08_PHY_TEST 0x05, 0x08 -#define TM6010_REQ05_R09_VCTL 0x05, 0x09 -#define TM6010_REQ05_R0A_VSTA 0x05, 0x0a -#define TM6010_REQ05_R0B_CX_CFG 0x05, 0x0b -#define TM6010_REQ05_R0C_ENDP0_REG0 0x05, 0x0c -#define TM6010_REQ05_R10_GMASK 0x05, 0x10 -#define TM6010_REQ05_R11_IMASK0 0x05, 0x11 -#define TM6010_REQ05_R12_IMASK1 0x05, 0x12 -#define TM6010_REQ05_R13_IMASK2 0x05, 0x13 -#define TM6010_REQ05_R14_IMASK3 0x05, 0x14 -#define TM6010_REQ05_R15_IMASK4 0x05, 0x15 -#define TM6010_REQ05_R16_IMASK5 0x05, 0x16 -#define TM6010_REQ05_R17_IMASK6 0x05, 0x17 -#define TM6010_REQ05_R18_IMASK7 0x05, 0x18 -#define TM6010_REQ05_R19_ZEROP0 0x05, 0x19 -#define TM6010_REQ05_R1A_ZEROP1 0x05, 0x1a -#define TM6010_REQ05_R1C_FIFO_EMP0 0x05, 0x1c -#define TM6010_REQ05_R1D_FIFO_EMP1 0x05, 0x1d -#define TM6010_REQ05_R20_IRQ_GROUP 0x05, 0x20 -#define TM6010_REQ05_R21_IRQ_SOURCE0 0x05, 0x21 -#define TM6010_REQ05_R22_IRQ_SOURCE1 0x05, 0x22 -#define TM6010_REQ05_R23_IRQ_SOURCE2 0x05, 0x23 -#define TM6010_REQ05_R24_IRQ_SOURCE3 0x05, 0x24 -#define TM6010_REQ05_R25_IRQ_SOURCE4 0x05, 0x25 -#define TM6010_REQ05_R26_IRQ_SOURCE5 0x05, 0x26 -#define TM6010_REQ05_R27_IRQ_SOURCE6 0x05, 0x27 -#define TM6010_REQ05_R28_IRQ_SOURCE7 0x05, 0x28 -#define TM6010_REQ05_R29_SEQ_ERR0 0x05, 0x29 -#define TM6010_REQ05_R2A_SEQ_ERR1 0x05, 0x2a -#define TM6010_REQ05_R2B_SEQ_ABORT0 0x05, 0x2b -#define TM6010_REQ05_R2C_SEQ_ABORT1 0x05, 0x2c -#define TM6010_REQ05_R2D_TX_ZERO0 0x05, 0x2d -#define TM6010_REQ05_R2E_TX_ZERO1 0x05, 0x2e -#define TM6010_REQ05_R2F_IDLE_CNT 0x05, 0x2f -#define TM6010_REQ05_R30_FNO_P1 0x05, 0x30 -#define TM6010_REQ05_R31_FNO_P2 0x05, 0x31 -#define TM6010_REQ05_R32_FNO_P3 0x05, 0x32 -#define TM6010_REQ05_R33_FNO_P4 0x05, 0x33 -#define TM6010_REQ05_R34_FNO_P5 0x05, 0x34 -#define TM6010_REQ05_R35_FNO_P6 0x05, 0x35 -#define TM6010_REQ05_R36_FNO_P7 0x05, 0x36 -#define TM6010_REQ05_R37_FNO_P8 0x05, 0x37 -#define TM6010_REQ05_R38_FNO_P9 0x05, 0x38 -#define TM6010_REQ05_R30_FNO_P10 0x05, 0x39 -#define TM6010_REQ05_R30_FNO_P11 0x05, 0x3a -#define TM6010_REQ05_R30_FNO_P12 0x05, 0x3b -#define TM6010_REQ05_R30_FNO_P13 0x05, 0x3c -#define TM6010_REQ05_R30_FNO_P14 0x05, 0x3d -#define TM6010_REQ05_R30_FNO_P15 0x05, 0x3e -#define TM6010_REQ05_R40_IN_MAXPS_LOW1 0x05, 0x40 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH1 0x05, 0x41 -#define TM6010_REQ05_R42_IN_MAXPS_LOW2 0x05, 0x42 -#define TM6010_REQ05_R43_IN_MAXPS_HIGH2 0x05, 0x43 -#define TM6010_REQ05_R44_IN_MAXPS_LOW3 0x05, 0x44 -#define TM6010_REQ05_R45_IN_MAXPS_HIGH3 0x05, 0x45 -#define TM6010_REQ05_R46_IN_MAXPS_LOW4 0x05, 0x46 -#define TM6010_REQ05_R47_IN_MAXPS_HIGH4 0x05, 0x47 -#define TM6010_REQ05_R48_IN_MAXPS_LOW5 0x05, 0x48 -#define TM6010_REQ05_R49_IN_MAXPS_HIGH5 0x05, 0x49 -#define TM6010_REQ05_R4A_IN_MAXPS_LOW6 0x05, 0x4a -#define TM6010_REQ05_R4B_IN_MAXPS_HIGH6 0x05, 0x4b -#define TM6010_REQ05_R4C_IN_MAXPS_LOW7 0x05, 0x4c -#define TM6010_REQ05_R4D_IN_MAXPS_HIGH7 0x05, 0x4d -#define TM6010_REQ05_R4E_IN_MAXPS_LOW8 0x05, 0x4e -#define TM6010_REQ05_R4F_IN_MAXPS_HIGH8 0x05, 0x4f -#define TM6010_REQ05_R50_IN_MAXPS_LOW9 0x05, 0x50 -#define TM6010_REQ05_R51_IN_MAXPS_HIGH9 0x05, 0x51 -#define TM6010_REQ05_R40_IN_MAXPS_LOW10 0x05, 0x52 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH10 0x05, 0x53 -#define TM6010_REQ05_R40_IN_MAXPS_LOW11 0x05, 0x54 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH11 0x05, 0x55 -#define TM6010_REQ05_R40_IN_MAXPS_LOW12 0x05, 0x56 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH12 0x05, 0x57 -#define TM6010_REQ05_R40_IN_MAXPS_LOW13 0x05, 0x58 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH13 0x05, 0x59 -#define TM6010_REQ05_R40_IN_MAXPS_LOW14 0x05, 0x5a -#define TM6010_REQ05_R41_IN_MAXPS_HIGH14 0x05, 0x5b -#define TM6010_REQ05_R40_IN_MAXPS_LOW15 0x05, 0x5c -#define TM6010_REQ05_R41_IN_MAXPS_HIGH15 0x05, 0x5d -#define TM6010_REQ05_R60_OUT_MAXPS_LOW1 0x05, 0x60 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH1 0x05, 0x61 -#define TM6010_REQ05_R62_OUT_MAXPS_LOW2 0x05, 0x62 -#define TM6010_REQ05_R63_OUT_MAXPS_HIGH2 0x05, 0x63 -#define TM6010_REQ05_R64_OUT_MAXPS_LOW3 0x05, 0x64 -#define TM6010_REQ05_R65_OUT_MAXPS_HIGH3 0x05, 0x65 -#define TM6010_REQ05_R66_OUT_MAXPS_LOW4 0x05, 0x66 -#define TM6010_REQ05_R67_OUT_MAXPS_HIGH4 0x05, 0x67 -#define TM6010_REQ05_R68_OUT_MAXPS_LOW5 0x05, 0x68 -#define TM6010_REQ05_R69_OUT_MAXPS_HIGH5 0x05, 0x69 -#define TM6010_REQ05_R6A_OUT_MAXPS_LOW6 0x05, 0x6a -#define TM6010_REQ05_R6B_OUT_MAXPS_HIGH6 0x05, 0x6b -#define TM6010_REQ05_R6C_OUT_MAXPS_LOW7 0x05, 0x6c -#define TM6010_REQ05_R6D_OUT_MAXPS_HIGH7 0x05, 0x6d -#define TM6010_REQ05_R6E_OUT_MAXPS_LOW8 0x05, 0x6e -#define TM6010_REQ05_R6F_OUT_MAXPS_HIGH8 0x05, 0x6f -#define TM6010_REQ05_R70_OUT_MAXPS_LOW9 0x05, 0x70 -#define TM6010_REQ05_R71_OUT_MAXPS_HIGH9 0x05, 0x71 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW10 0x05, 0x72 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH10 0x05, 0x73 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW11 0x05, 0x74 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH11 0x05, 0x75 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW12 0x05, 0x76 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH12 0x05, 0x77 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW13 0x05, 0x78 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH13 0x05, 0x79 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW14 0x05, 0x7a -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH14 0x05, 0x7b -#define TM6010_REQ05_R60_OUT_MAXPS_LOW15 0x05, 0x7c -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH15 0x05, 0x7d -#define TM6010_REQ05_R80_FIFO0 0x05, 0x80 -#define TM6010_REQ05_R81_FIFO1 0x05, 0x81 -#define TM6010_REQ05_R82_FIFO2 0x05, 0x82 -#define TM6010_REQ05_R83_FIFO3 0x05, 0x83 -#define TM6010_REQ05_R84_FIFO4 0x05, 0x84 -#define TM6010_REQ05_R85_FIFO5 0x05, 0x85 -#define TM6010_REQ05_R86_FIFO6 0x05, 0x86 -#define TM6010_REQ05_R87_FIFO7 0x05, 0x87 -#define TM6010_REQ05_R88_FIFO8 0x05, 0x88 -#define TM6010_REQ05_R89_FIFO9 0x05, 0x89 -#define TM6010_REQ05_R81_FIFO10 0x05, 0x8a -#define TM6010_REQ05_R81_FIFO11 0x05, 0x8b -#define TM6010_REQ05_R81_FIFO12 0x05, 0x8c -#define TM6010_REQ05_R81_FIFO13 0x05, 0x8d -#define TM6010_REQ05_R81_FIFO14 0x05, 0x8e -#define TM6010_REQ05_R81_FIFO15 0x05, 0x8f -#define TM6010_REQ05_R90_CFG_FIFO0 0x05, 0x90 -#define TM6010_REQ05_R91_CFG_FIFO1 0x05, 0x91 -#define TM6010_REQ05_R92_CFG_FIFO2 0x05, 0x92 -#define TM6010_REQ05_R93_CFG_FIFO3 0x05, 0x93 -#define TM6010_REQ05_R94_CFG_FIFO4 0x05, 0x94 -#define TM6010_REQ05_R95_CFG_FIFO5 0x05, 0x95 -#define TM6010_REQ05_R96_CFG_FIFO6 0x05, 0x96 -#define TM6010_REQ05_R97_CFG_FIFO7 0x05, 0x97 -#define TM6010_REQ05_R98_CFG_FIFO8 0x05, 0x98 -#define TM6010_REQ05_R99_CFG_FIFO9 0x05, 0x99 -#define TM6010_REQ05_R91_CFG_FIFO10 0x05, 0x9a -#define TM6010_REQ05_R91_CFG_FIFO11 0x05, 0x9b -#define TM6010_REQ05_R91_CFG_FIFO12 0x05, 0x9c -#define TM6010_REQ05_R91_CFG_FIFO13 0x05, 0x9d -#define TM6010_REQ05_R91_CFG_FIFO14 0x05, 0x9e -#define TM6010_REQ05_R91_CFG_FIFO15 0x05, 0x9f -#define TM6010_REQ05_RA0_CTL_FIFO0 0x05, 0xa0 -#define TM6010_REQ05_RA1_CTL_FIFO1 0x05, 0xa1 -#define TM6010_REQ05_RA2_CTL_FIFO2 0x05, 0xa2 -#define TM6010_REQ05_RA3_CTL_FIFO3 0x05, 0xa3 -#define TM6010_REQ05_RA4_CTL_FIFO4 0x05, 0xa4 -#define TM6010_REQ05_RA5_CTL_FIFO5 0x05, 0xa5 -#define TM6010_REQ05_RA6_CTL_FIFO6 0x05, 0xa6 -#define TM6010_REQ05_RA7_CTL_FIFO7 0x05, 0xa7 -#define TM6010_REQ05_RA8_CTL_FIFO8 0x05, 0xa8 -#define TM6010_REQ05_RA9_CTL_FIFO9 0x05, 0xa9 -#define TM6010_REQ05_RA1_CTL_FIFO10 0x05, 0xaa -#define TM6010_REQ05_RA1_CTL_FIFO11 0x05, 0xab -#define TM6010_REQ05_RA1_CTL_FIFO12 0x05, 0xac -#define TM6010_REQ05_RA1_CTL_FIFO13 0x05, 0xad -#define TM6010_REQ05_RA1_CTL_FIFO14 0x05, 0xae -#define TM6010_REQ05_RA1_CTL_FIFO15 0x05, 0xaf -#define TM6010_REQ05_RB0_BC_LOW_FIFO0 0x05, 0xb0 -#define TM6010_REQ05_RB1_BC_LOW_FIFO1 0x05, 0xb1 -#define TM6010_REQ05_RB2_BC_LOW_FIFO2 0x05, 0xb2 -#define TM6010_REQ05_RB3_BC_LOW_FIFO3 0x05, 0xb3 -#define TM6010_REQ05_RB4_BC_LOW_FIFO4 0x05, 0xb4 -#define TM6010_REQ05_RB5_BC_LOW_FIFO5 0x05, 0xb5 -#define TM6010_REQ05_RB6_BC_LOW_FIFO6 0x05, 0xb6 -#define TM6010_REQ05_RB7_BC_LOW_FIFO7 0x05, 0xb7 -#define TM6010_REQ05_RB8_BC_LOW_FIFO8 0x05, 0xb8 -#define TM6010_REQ05_RB9_BC_LOW_FIFO9 0x05, 0xb9 -#define TM6010_REQ05_RB1_BC_LOW_FIFO10 0x05, 0xba -#define TM6010_REQ05_RB1_BC_LOW_FIFO11 0x05, 0xbb -#define TM6010_REQ05_RB1_BC_LOW_FIFO12 0x05, 0xbc -#define TM6010_REQ05_RB1_BC_LOW_FIFO13 0x05, 0xbd -#define TM6010_REQ05_RB1_BC_LOW_FIFO14 0x05, 0xbe -#define TM6010_REQ05_RB1_BC_LOW_FIFO15 0x05, 0xbf -#define TM6010_REQ05_RC0_DATA_FIFO0 0x05, 0xc0 -#define TM6010_REQ05_RC4_DATA_FIFO1 0x05, 0xc4 -#define TM6010_REQ05_RC8_DATA_FIFO2 0x05, 0xc8 -#define TM6010_REQ05_RCC_DATA_FIFO3 0x05, 0xcc -#define TM6010_REQ05_RD0_DATA_FIFO4 0x05, 0xd0 -#define TM6010_REQ05_RD4_DATA_FIFO5 0x05, 0xd4 -#define TM6010_REQ05_RD8_DATA_FIFO6 0x05, 0xd8 -#define TM6010_REQ05_RDC_DATA_FIFO7 0x05, 0xdc -#define TM6010_REQ05_RE0_DATA_FIFO8 0x05, 0xe0 -#define TM6010_REQ05_RE4_DATA_FIFO9 0x05, 0xe4 -#define TM6010_REQ05_RC4_DATA_FIFO10 0x05, 0xe8 -#define TM6010_REQ05_RC4_DATA_FIFO11 0x05, 0xec -#define TM6010_REQ05_RC4_DATA_FIFO12 0x05, 0xf0 -#define TM6010_REQ05_RC4_DATA_FIFO13 0x05, 0xf4 -#define TM6010_REQ05_RC4_DATA_FIFO14 0x05, 0xf8 -#define TM6010_REQ05_RC4_DATA_FIFO15 0x05, 0xfc - -/* Define TM6010 Audio decoder registers */ -/* This core available only in TM6010 */ -#define TM6010_REQ08_R00_A_VERSION 0x08, 0x00 -#define TM6010_REQ08_R01_A_INIT 0x08, 0x01 -#define TM6010_REQ08_R02_A_FIX_GAIN_CTRL 0x08, 0x02 -#define TM6010_REQ08_R03_A_AUTO_GAIN_CTRL 0x08, 0x03 -#define TM6010_REQ08_R04_A_SIF_AMP_CTRL 0x08, 0x04 -#define TM6010_REQ08_R05_A_STANDARD_MOD 0x08, 0x05 -#define TM6010_REQ08_R06_A_SOUND_MOD 0x08, 0x06 -#define TM6010_REQ08_R07_A_LEFT_VOL 0x08, 0x07 -#define TM6010_REQ08_R08_A_RIGHT_VOL 0x08, 0x08 -#define TM6010_REQ08_R09_A_MAIN_VOL 0x08, 0x09 -#define TM6010_REQ08_R0A_A_I2S_MOD 0x08, 0x0a -#define TM6010_REQ08_R0B_A_ASD_THRES1 0x08, 0x0b -#define TM6010_REQ08_R0C_A_ASD_THRES2 0x08, 0x0c -#define TM6010_REQ08_R0D_A_AMD_THRES 0x08, 0x0d -#define TM6010_REQ08_R0E_A_MONO_THRES1 0x08, 0x0e -#define TM6010_REQ08_R0F_A_MONO_THRES2 0x08, 0x0f -#define TM6010_REQ08_R10_A_MUTE_THRES1 0x08, 0x10 -#define TM6010_REQ08_R11_A_MUTE_THRES2 0x08, 0x11 -#define TM6010_REQ08_R12_A_AGC_U 0x08, 0x12 -#define TM6010_REQ08_R13_A_AGC_ERR_T 0x08, 0x13 -#define TM6010_REQ08_R14_A_AGC_GAIN_INIT 0x08, 0x14 -#define TM6010_REQ08_R15_A_AGC_STEP_THR 0x08, 0x15 -#define TM6010_REQ08_R16_A_AGC_GAIN_MAX 0x08, 0x16 -#define TM6010_REQ08_R17_A_AGC_GAIN_MIN 0x08, 0x17 -#define TM6010_REQ08_R18_A_TR_CTRL 0x08, 0x18 -#define TM6010_REQ08_R19_A_FH_2FH_GAIN 0x08, 0x19 -#define TM6010_REQ08_R1A_A_NICAM_SER_MAX 0x08, 0x1a -#define TM6010_REQ08_R1B_A_NICAM_SER_MIN 0x08, 0x1b -#define TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT 0x08, 0x1e -#define TM6010_REQ08_R1F_A_TEST_INTF_SEL 0x08, 0x1f -#define TM6010_REQ08_R20_A_TEST_PIN_SEL 0x08, 0x20 -#define TM6010_REQ08_R21_A_AGC_ERR 0x08, 0x21 -#define TM6010_REQ08_R22_A_AGC_GAIN 0x08, 0x22 -#define TM6010_REQ08_R23_A_NICAM_INFO 0x08, 0x23 -#define TM6010_REQ08_R24_A_SER 0x08, 0x24 -#define TM6010_REQ08_R25_A_C1_AMP 0x08, 0x25 -#define TM6010_REQ08_R26_A_C2_AMP 0x08, 0x26 -#define TM6010_REQ08_R27_A_NOISE_AMP 0x08, 0x27 -#define TM6010_REQ08_R28_A_AUDIO_MODE_RES 0x08, 0x28 - -/* Define TM6010 Video ADC registers */ -#define TM6010_REQ08_RE0_ADC_REF 0x08, 0xe0 -#define TM6010_REQ08_RE1_DAC_CLMP 0x08, 0xe1 -#define TM6010_REQ08_RE2_POWER_DOWN_CTRL1 0x08, 0xe2 -#define TM6010_REQ08_RE3_ADC_IN1_SEL 0x08, 0xe3 -#define TM6010_REQ08_RE4_ADC_IN2_SEL 0x08, 0xe4 -#define TM6010_REQ08_RE5_GAIN_PARAM 0x08, 0xe5 -#define TM6010_REQ08_RE6_POWER_DOWN_CTRL2 0x08, 0xe6 -#define TM6010_REQ08_RE7_REG_GAIN_Y 0x08, 0xe7 -#define TM6010_REQ08_RE8_REG_GAIN_C 0x08, 0xe8 -#define TM6010_REQ08_RE9_BIAS_CTRL 0x08, 0xe9 -#define TM6010_REQ08_REA_BUFF_DRV_CTRL 0x08, 0xea -#define TM6010_REQ08_REB_SIF_GAIN_CTRL 0x08, 0xeb -#define TM6010_REQ08_REC_REVERSE_YC_CTRL 0x08, 0xec -#define TM6010_REQ08_RED_GAIN_SEL 0x08, 0xed - -/* Define TM6010 Audio ADC registers */ -#define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG 0x08, 0xf0 -#define TM6010_REQ08_RF1_AADC_POWER_DOWN 0x08, 0xf1 -#define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL 0x08, 0xf2 -#define TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL 0x08, 0xf3 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-stds.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-stds.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-stds.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-stds.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1190 +0,0 @@ -/* - * tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2007 Mauro Carvalho Chehab - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include "tm6000.h" -#include "tm6000-regs.h" - -struct tm6000_reg_settings { - unsigned char req; - unsigned char reg; - unsigned char value; -}; - -enum tm6000_audio_std { - BG_NICAM, - BTSC, - BG_A2, - DK_NICAM, - EIAJ, - FM_RADIO, - I_NICAM, - KOREA_A2, - L_NICAM, -}; - -struct tm6000_std_tv_settings { - v4l2_std_id id; - enum tm6000_audio_std audio_default_std; - - struct tm6000_reg_settings sif[12]; - struct tm6000_reg_settings nosif[12]; - struct tm6000_reg_settings common[26]; -}; - -struct tm6000_std_settings { - v4l2_std_id id; - enum tm6000_audio_std audio_default_std; - struct tm6000_reg_settings common[37]; -}; - -static struct tm6000_std_tv_settings tv_stds[] = { - { - .id = V4L2_STD_PAL_M, - .audio_default_std = BTSC, - .sif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe}, - {TM6010_REQ07_RFE_POWER_DOWN, 0xcb}, - {0, 0, 0}, - }, - .nosif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - {0, 0, 0}, - }, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - - {TM6010_REQ07_R3F_RESET, 0x00}, - - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL_Nc, - .audio_default_std = BTSC, - .sif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe}, - {TM6010_REQ07_RFE_POWER_DOWN, 0xcb}, - {0, 0, 0}, - }, - .nosif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - {0, 0, 0}, - }, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - - {TM6010_REQ07_R3F_RESET, 0x00}, - - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL, - .audio_default_std = BG_A2, - .sif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe}, - {TM6010_REQ07_RFE_POWER_DOWN, 0xcb}, - {0, 0, 0} - }, - .nosif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - {0, 0, 0}, - }, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - - {TM6010_REQ07_R3F_RESET, 0x00}, - - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G, - .audio_default_std = BG_NICAM, - .sif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe}, - {TM6010_REQ07_RFE_POWER_DOWN, 0xcb}, - {0, 0, 0}, - }, - .nosif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - {0, 0, 0}, - }, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF}, - - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_SECAM_DK, - .audio_default_std = DK_NICAM, - .sif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe}, - {TM6010_REQ07_RFE_POWER_DOWN, 0xcb}, - {0, 0, 0}, - }, - .nosif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - {0, 0, 0}, - }, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF}, - - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_NTSC, - .audio_default_std = BTSC, - .sif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf2}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x08}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x62}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe}, - {TM6010_REQ07_RFE_POWER_DOWN, 0xcb}, - {0, 0, 0}, - }, - .nosif = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - {0, 0, 0}, - }, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - - {TM6010_REQ07_R3F_RESET, 0x00}, - - {0, 0, 0}, - }, - }, -}; - -static struct tm6000_std_settings composite_stds[] = { - { - .id = V4L2_STD_PAL_M, - .audio_default_std = BTSC, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL_Nc, - .audio_default_std = BTSC, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL, - .audio_default_std = BG_A2, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_SECAM, - .audio_default_std = BG_NICAM, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF}, - - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_SECAM_DK, - .audio_default_std = DK_NICAM, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF}, - - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_NTSC, - .audio_default_std = BTSC, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x0f}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe8}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8b}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, -}; - -static struct tm6000_std_settings svideo_stds[] = { - { - .id = V4L2_STD_PAL_M, - .audio_default_std = BTSC, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe0}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8a}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL_Nc, - .audio_default_std = BTSC, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe0}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8a}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL, - .audio_default_std = BG_A2, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe0}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8a}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_SECAM, - .audio_default_std = BG_NICAM, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe0}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8a}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF}, - - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_SECAM_DK, - .audio_default_std = DK_NICAM, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe0}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8a}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF}, - - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_NTSC, - .audio_default_std = BTSC, - .common = { - {TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0}, - {TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc}, - {TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8}, - {TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00}, - {TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2}, - {TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0}, - {TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2}, - {TM6010_REQ08_RED_GAIN_SEL, 0xe0}, - {TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x68}, - {TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc}, - {TM6010_REQ07_RFE_POWER_DOWN, 0x8a}, - - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30}, - {TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, -}; - - -static int tm6000_set_audio_std(struct tm6000_core *dev, - enum tm6000_audio_std std) -{ - uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */ - uint8_t areg_05 = 0x09; /* Auto 4.5 = M Japan, Auto 6.5 = DK */ - uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */ - uint8_t mono_flag = 0; /* No mono */ - uint8_t nicam_flag = 0; /* No NICAM */ - - if (dev->radio) { - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04); - tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80); - tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c); - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18); - tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a); - tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40); - tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc); - tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); - return 0; - } - - switch (std) { -#if 0 - case DK_MONO: - mono_flag = 1; - break; - case DK_A2_1: - break; - case DK_A2_3: - areg_05 = 0x0b; - break; - case BG_MONO: - mono_flag = 1; - areg_05 = 0x05; - break; -#endif - case BG_NICAM: - areg_05 = 0x07; - nicam_flag = 1; - break; - case BTSC: - areg_05 = 0x02; - break; - case BG_A2: - areg_05 = 0x05; - break; - case DK_NICAM: - areg_05 = 0x06; - nicam_flag = 1; - break; - case EIAJ: - areg_05 = 0x02; - break; - case I_NICAM: - areg_05 = 0x08; - nicam_flag = 1; - break; - case KOREA_A2: - areg_05 = 0x04; - break; - case L_NICAM: - areg_02 = 0x02; /* GC1 Fixed gain +12dB */ - areg_05 = 0x0a; - nicam_flag = 1; - break; - default: - /* do nothink */ - break; - } - -#if 0 - switch (tv_audio_mode) { - case TV_MONO: - areg_06 = (nicam_flag) ? 0x03 : 0x00; - break; - case TV_LANG_A: - areg_06 = 0x00; - break; - case TV_LANG_B: - areg_06 = 0x01; - break; - } -#endif - - if (mono_flag) - areg_06 = 0x00; - - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02); - tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0); - tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05); - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06); - tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08); - tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91); - tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20); - tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12); - tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20); - tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0); - tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80); - tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0); - tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80); - tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12); - tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe); - tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20); - tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14); - tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe); - tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01); - tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0); - tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32); - tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64); - tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20); - tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00); - tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); - tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3); - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc); - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); - - return 0; -} - -void tm6000_get_std_res(struct tm6000_core *dev) -{ - /* Currently, those are the only supported resoltions */ - if (dev->norm & V4L2_STD_525_60) - dev->height = 480; - else - dev->height = 576; - - dev->width = 720; -} - -static int tm6000_load_std(struct tm6000_core *dev, - struct tm6000_reg_settings *set, int max_size) -{ - int i, rc; - - /* Load board's initialization table */ - for (i = 0; max_size; i++) { - if (!set[i].req) - return 0; - - if ((dev->dev_type != TM6010) && - (set[i].req == REQ_08_SET_GET_AVREG_BIT)) - continue; - - rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value); - if (rc < 0) { - printk(KERN_ERR "Error %i while setting " - "req %d, reg %d to value %d\n", - rc, set[i].req, set[i].reg, set[i].value); - return rc; - } - } - - return 0; -} - -static int tm6000_set_tv(struct tm6000_core *dev, int pos) -{ - int rc; - - /* FIXME: This code is for tm6010 - not tested yet - doesn't work with - tm5600 - */ - - /* FIXME: This is tuner-dependent */ - int nosif = 0; - - if (nosif) { - rc = tm6000_load_std(dev, tv_stds[pos].nosif, - sizeof(tv_stds[pos].nosif)); - } else { - rc = tm6000_load_std(dev, tv_stds[pos].sif, - sizeof(tv_stds[pos].sif)); - } - if (rc < 0) - return rc; - rc = tm6000_load_std(dev, tv_stds[pos].common, - sizeof(tv_stds[pos].common)); - - tm6000_set_audio_std(dev, tv_stds[pos].audio_default_std); - - return rc; -} - -int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm) -{ - int i, rc = 0; - - dev->norm = *norm; - tm6000_get_std_res(dev); - - switch (dev->input) { - case TM6000_INPUT_TV: - for (i = 0; i < ARRAY_SIZE(tv_stds); i++) { - if (*norm & tv_stds[i].id) { - rc = tm6000_set_tv(dev, i); - goto ret; - } - } - return -EINVAL; - case TM6000_INPUT_SVIDEO: - for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) { - if (*norm & svideo_stds[i].id) { - rc = tm6000_load_std(dev, svideo_stds[i].common, - sizeof(svideo_stds[i]. - common)); - goto ret; - } - } - return -EINVAL; - case TM6000_INPUT_COMPOSITE: - for (i = 0; i < ARRAY_SIZE(composite_stds); i++) { - if (*norm & composite_stds[i].id) { - rc = tm6000_load_std(dev, - composite_stds[i].common, - sizeof(composite_stds[i]. - common)); - tm6000_set_audio_std(dev, composite_stds[i].audio_default_std); - goto ret; - } - } - return -EINVAL; - } - -ret: - if (rc < 0) - return rc; - - msleep(40); - - - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-usb-isoc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-usb-isoc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-usb-isoc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-usb-isoc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - * tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#define TM6000_URB_MSG_LEN 180 - -struct usb_isoc_ctl { - /* max packet size of isoc transaction */ - int max_pkt_size; - - /* number of allocated urbs */ - int num_bufs; - - /* urb for isoc transfers */ - struct urb **urb; - - /* transfer buffers for isoc transfer */ - char **transfer_buffer; - - /* Last buffer command and region */ - u8 cmd; - int pos, size, pktsize; - - /* Last field: ODD or EVEN? */ - int vfield; - - /* Stores incomplete commands */ - u32 tmp_buf; - int tmp_buf_len; - - /* Stores already requested buffers */ - struct tm6000_buffer *buf; -}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-video.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/drivers/staging/tm6000/tm6000-video.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1784 +0,0 @@ -/* - * tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * Copyright (C) 2007 Michel Ludwig - * - Fixed module load/unload - * - * 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 version 2 - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tm6000-regs.h" -#include "tm6000.h" - -#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ - -/* Limits minimum and default number of buffers */ -#define TM6000_MIN_BUF 4 -#define TM6000_DEF_BUF 8 - -#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */ - -/* Declare static vars that will be used as parameters */ -static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ -static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ -static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */ - -/* Debug level */ -int tm6000_debug; -EXPORT_SYMBOL_GPL(tm6000_debug); - -static const struct v4l2_queryctrl no_ctrl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -/* supported controls */ -static struct v4l2_queryctrl tm6000_qctrl[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 54, - .flags = 0, - }, { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 0x1, - .default_value = 119, - .flags = 0, - }, { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 0x1, - .default_value = 112, - .flags = 0, - }, { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = -128, - .maximum = 127, - .step = 0x1, - .default_value = 0, - .flags = 0, - }, - /* --- audio --- */ - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = -15, - .maximum = 15, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; - -static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl); -static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)]; - -static struct tm6000_fmt format[] = { - { - .name = "4:2:2, packed, YVY2", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - }, { - .name = "A/V + VBI mux packet", - .fourcc = V4L2_PIX_FMT_TM6000, - .depth = 16, - } -}; - -static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) -{ - unsigned int i; - - for (i = 0; i < CTRLS; i++) - if (tm6000_qctrl[i].id == id) - return tm6000_qctrl+i; - return NULL; -} - -/* ------------------------------------------------------------------ - * DMA and thread functions - * ------------------------------------------------------------------ - */ - -#define norm_maxw(a) 720 -#define norm_maxh(a) 576 - -#define norm_minw(a) norm_maxw(a) -#define norm_minh(a) norm_maxh(a) - -/* - * video-buf generic routine to get the next available buffer - */ -static inline void get_next_buf(struct tm6000_dmaqueue *dma_q, - struct tm6000_buffer **buf) -{ - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - char *outp; - - if (list_empty(&dma_q->active)) { - dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n"); - *buf = NULL; - return; - } - - *buf = list_entry(dma_q->active.next, - struct tm6000_buffer, vb.queue); - - if (!buf) - return; - - /* Cleans up buffer - Usefull for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - - return; -} - -/* - * Announces that a buffer were filled and request the next - */ -static inline void buffer_filled(struct tm6000_core *dev, - struct tm6000_dmaqueue *dma_q, - struct tm6000_buffer *buf) -{ - /* Advice that buffer was filled */ - dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -const char *tm6000_msg_type[] = { - "unknown(0)", /* 0 */ - "video", /* 1 */ - "audio", /* 2 */ - "vbi", /* 3 */ - "pts", /* 4 */ - "err", /* 5 */ - "unknown(6)", /* 6 */ - "unknown(7)", /* 7 */ -}; - -/* - * Identify the tm5600/6000 buffer header type and properly handles - */ -static int copy_streams(u8 *data, unsigned long len, - struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - u8 *ptr = data, *endp = data+len, c; - unsigned long header = 0; - int rc = 0; - unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0; - struct tm6000_buffer *vbuf; - char *voutp = NULL; - unsigned int linewidth; - - if (!dev->radio) { - /* get video buffer */ - get_next_buf(dma_q, &vbuf); - - if (!vbuf) - return rc; - voutp = videobuf_to_vmalloc(&vbuf->vb); - - if (!voutp) - return 0; - } - - for (ptr = data; ptr < endp;) { - if (!dev->isoc_ctl.cmd) { - /* Header */ - if (dev->isoc_ctl.tmp_buf_len > 0) { - /* from last urb or packet */ - header = dev->isoc_ctl.tmp_buf; - if (4 - dev->isoc_ctl.tmp_buf_len > 0) { - memcpy((u8 *)&header + - dev->isoc_ctl.tmp_buf_len, - ptr, - 4 - dev->isoc_ctl.tmp_buf_len); - ptr += 4 - dev->isoc_ctl.tmp_buf_len; - } - dev->isoc_ctl.tmp_buf_len = 0; - } else { - if (ptr + 3 >= endp) { - /* have incomplete header */ - dev->isoc_ctl.tmp_buf_len = endp - ptr; - memcpy(&dev->isoc_ctl.tmp_buf, ptr, - dev->isoc_ctl.tmp_buf_len); - return rc; - } - /* Seek for sync */ - for (; ptr < endp - 3; ptr++) { - if (*(ptr + 3) == 0x47) - break; - } - /* Get message header */ - header = *(unsigned long *)ptr; - ptr += 4; - } - - /* split the header fields */ - c = (header >> 24) & 0xff; - size = ((header & 0x7e) << 1); - if (size > 0) - size -= 4; - block = (header >> 7) & 0xf; - field = (header >> 11) & 0x1; - line = (header >> 12) & 0x1ff; - cmd = (header >> 21) & 0x7; - /* Validates haeder fields */ - if (size > TM6000_URB_MSG_LEN) - size = TM6000_URB_MSG_LEN; - pktsize = TM6000_URB_MSG_LEN; - /* calculate position in buffer - * and change the buffer - */ - switch (cmd) { - case TM6000_URB_MSG_VIDEO: - if (!dev->radio) { - if ((dev->isoc_ctl.vfield != field) && - (field == 1)) { - /* Announces that a new buffer - * were filled - */ - buffer_filled(dev, dma_q, vbuf); - dprintk(dev, V4L2_DEBUG_ISOC, - "new buffer filled\n"); - get_next_buf(dma_q, &vbuf); - if (!vbuf) - return rc; - voutp = videobuf_to_vmalloc(&vbuf->vb); - if (!voutp) - return rc; - memset(voutp, 0, vbuf->vb.size); - } - linewidth = vbuf->vb.width << 1; - pos = ((line << 1) - field - 1) * - linewidth + block * TM6000_URB_MSG_LEN; - /* Don't allow to write out of the buffer */ - if (pos + size > vbuf->vb.size) - cmd = TM6000_URB_MSG_ERR; - dev->isoc_ctl.vfield = field; - } - break; - case TM6000_URB_MSG_VBI: - break; - case TM6000_URB_MSG_AUDIO: - case TM6000_URB_MSG_PTS: - size = pktsize; /* Size is always 180 bytes */ - break; - } - } else { - /* Continue the last copy */ - cmd = dev->isoc_ctl.cmd; - size = dev->isoc_ctl.size; - pos = dev->isoc_ctl.pos; - pktsize = dev->isoc_ctl.pktsize; - } - cpysize = (endp - ptr > size) ? size : endp - ptr; - if (cpysize) { - /* copy data in different buffers */ - switch (cmd) { - case TM6000_URB_MSG_VIDEO: - /* Fills video buffer */ - if (vbuf) - memcpy(&voutp[pos], ptr, cpysize); - break; - case TM6000_URB_MSG_AUDIO: - /* Need some code to copy audio buffer */ - if (dev->fourcc == V4L2_PIX_FMT_YUYV) { - /* Swap word bytes */ - int i; - - for (i = 0; i < cpysize; i += 2) - swab16s((u16 *)(ptr + i)); - } - tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize); - break; - case TM6000_URB_MSG_VBI: - /* Need some code to copy vbi buffer */ - break; - case TM6000_URB_MSG_PTS: - /* Need some code to copy pts */ - break; - } - } - if (ptr + pktsize > endp) { - /* End of URB packet, but cmd processing is not - * complete. Preserve the state for a next packet - */ - dev->isoc_ctl.pos = pos + cpysize; - dev->isoc_ctl.size = size - cpysize; - dev->isoc_ctl.cmd = cmd; - dev->isoc_ctl.pktsize = pktsize - (endp - ptr); - ptr += endp - ptr; - } else { - dev->isoc_ctl.cmd = 0; - ptr += pktsize; - } - } - return 0; -} - -/* - * Identify the tm5600/6000 buffer header type and properly handles - */ -static int copy_multiplexed(u8 *ptr, unsigned long len, - struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - unsigned int pos = dev->isoc_ctl.pos, cpysize; - int rc = 1; - struct tm6000_buffer *buf; - char *outp = NULL; - - get_next_buf(dma_q, &buf); - if (buf) - outp = videobuf_to_vmalloc(&buf->vb); - - if (!outp) - return 0; - - while (len > 0) { - cpysize = min(len, buf->vb.size-pos); - memcpy(&outp[pos], ptr, cpysize); - pos += cpysize; - ptr += cpysize; - len -= cpysize; - if (pos >= buf->vb.size) { - pos = 0; - /* Announces that a new buffer were filled */ - buffer_filled(dev, dma_q, buf); - dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); - get_next_buf(dma_q, &buf); - if (!buf) - break; - outp = videobuf_to_vmalloc(&(buf->vb)); - if (!outp) - return rc; - pos = 0; - } - } - - dev->isoc_ctl.pos = pos; - return rc; -} - -static inline void print_err_status(struct tm6000_core *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n", - status, errmsg); - } else { - dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - - -/* - * Controls the isoc copy of each urb packet - */ -static inline int tm6000_isoc_copy(struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - int i, len = 0, rc = 1, status; - char *p; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - return 0; - } - - for (i = 0; i < urb->number_of_packets; i++) { - status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - continue; - } - - len = urb->iso_frame_desc[i].actual_length; - - if (len > 0) { - p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - if (!urb->iso_frame_desc[i].status) { - if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) { - rc = copy_multiplexed(p, len, urb); - if (rc <= 0) - return rc; - } else { - copy_streams(p, len, urb); - } - } - } - } - return rc; -} - -/* ------------------------------------------------------------------ - * URB control - * ------------------------------------------------------------------ - */ - -/* - * IRQ callback, called by URB callback - */ -static void tm6000_irq_callback(struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - int i; - - if (!dev) - return; - - spin_lock(&dev->slock); - tm6000_isoc_copy(urb); - spin_unlock(&dev->slock); - - /* Reset urb buffers */ - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) - tm6000_err("urb resubmit failed (error=%i)\n", - urb->status); -} - -/* - * Stop and Deallocate URBs - */ -static void tm6000_uninit_isoc(struct tm6000_core *dev) -{ - struct urb *urb; - int i; - - dev->isoc_ctl.buf = NULL; - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = dev->isoc_ctl.urb[i]; - if (urb) { - usb_kill_urb(urb); - usb_unlink_urb(urb); - if (dev->isoc_ctl.transfer_buffer[i]) { - usb_free_coherent(dev->udev, - urb->transfer_buffer_length, - dev->isoc_ctl.transfer_buffer[i], - urb->transfer_dma); - } - usb_free_urb(urb); - dev->isoc_ctl.urb[i] = NULL; - } - dev->isoc_ctl.transfer_buffer[i] = NULL; - } - - kfree(dev->isoc_ctl.urb); - kfree(dev->isoc_ctl.transfer_buffer); - - dev->isoc_ctl.urb = NULL; - dev->isoc_ctl.transfer_buffer = NULL; - dev->isoc_ctl.num_bufs = 0; -} - -/* - * Allocate URBs and start IRQ - */ -static int tm6000_prepare_isoc(struct tm6000_core *dev) -{ - struct tm6000_dmaqueue *dma_q = &dev->vidq; - int i, j, sb_size, pipe, size, max_packets, num_bufs = 8; - struct urb *urb; - - /* De-allocates all pending stuff */ - tm6000_uninit_isoc(dev); - /* Stop interrupt USB pipe */ - tm6000_ir_int_stop(dev); - - usb_set_interface(dev->udev, - dev->isoc_in.bInterfaceNumber, - dev->isoc_in.bAlternateSetting); - - /* Start interrupt USB pipe */ - tm6000_ir_int_start(dev); - - pipe = usb_rcvisocpipe(dev->udev, - dev->isoc_in.endp->desc.bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); - - if (size > dev->isoc_in.maxsize) - size = dev->isoc_in.maxsize; - - dev->isoc_ctl.max_pkt_size = size; - - max_packets = TM6000_MAX_ISO_PACKETS; - sb_size = max_packets * size; - - dev->isoc_ctl.num_bufs = num_bufs; - - dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL); - if (!dev->isoc_ctl.urb) { - tm6000_err("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - - dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); - if (!dev->isoc_ctl.transfer_buffer) { - tm6000_err("cannot allocate memory for usbtransfer\n"); - kfree(dev->isoc_ctl.urb); - return -ENOMEM; - } - - dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets" - " (%d bytes) of %d bytes each to handle %u size\n", - max_packets, num_bufs, sb_size, - dev->isoc_in.maxsize, size); - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = usb_alloc_urb(max_packets, GFP_KERNEL); - if (!urb) { - tm6000_err("cannot alloc isoc_ctl.urb %i\n", i); - tm6000_uninit_isoc(dev); - usb_free_urb(urb); - return -ENOMEM; - } - dev->isoc_ctl.urb[i] = urb; - - dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, - sb_size, GFP_KERNEL, &urb->transfer_dma); - if (!dev->isoc_ctl.transfer_buffer[i]) { - tm6000_err("unable to allocate %i bytes for transfer" - " buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); - tm6000_uninit_isoc(dev); - return -ENOMEM; - } - memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); - - usb_fill_bulk_urb(urb, dev->udev, pipe, - dev->isoc_ctl.transfer_buffer[i], sb_size, - tm6000_irq_callback, dma_q); - urb->interval = dev->isoc_in.endp->desc.bInterval; - urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - - for (j = 0; j < max_packets; j++) { - urb->iso_frame_desc[j].offset = size * j; - urb->iso_frame_desc[j].length = size; - } - } - - return 0; -} - -static int tm6000_start_thread(struct tm6000_core *dev) -{ - struct tm6000_dmaqueue *dma_q = &dev->vidq; - int i; - - dma_q->frame = 0; - dma_q->ini_jiffies = jiffies; - - init_waitqueue_head(&dma_q->wq); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); - if (rc) { - tm6000_err("submit of urb %i failed (error=%i)\n", i, - rc); - tm6000_uninit_isoc(dev); - return rc; - } - } - - return 0; -} - -/* ------------------------------------------------------------------ - * Videobuf operations - * ------------------------------------------------------------------ - */ - -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) -{ - struct tm6000_fh *fh = vq->priv_data; - - *size = fh->fmt->depth * fh->width * fh->height >> 3; - if (0 == *count) - *count = TM6000_DEF_BUF; - - if (*count < TM6000_MIN_BUF) - *count = TM6000_MIN_BUF; - - while (*size * *count > vid_limit * 1024 * 1024) - (*count)--; - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf) -{ - struct tm6000_fh *fh = vq->priv_data; - struct tm6000_core *dev = fh->dev; - unsigned long flags; - - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.buf == buf) - dev->isoc_ctl.buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct tm6000_fh *fh = vq->priv_data; - struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); - struct tm6000_core *dev = fh->dev; - int rc = 0, urb_init = 0; - - BUG_ON(NULL == fh->fmt); - - - /* FIXME: It assumes depth=2 */ - /* The only currently supported format is 16 bits/pixel */ - buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - buf->vb.state = VIDEOBUF_NEEDS_INIT; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - if (0 != (rc = videobuf_iolock(vq, &buf->vb, NULL))) - goto fail; - urb_init = 1; - } - - if (!dev->isoc_ctl.num_bufs) - urb_init = 1; - - if (urb_init) { - rc = tm6000_prepare_isoc(dev); - if (rc < 0) - goto fail; - - rc = tm6000_start_thread(dev); - if (rc < 0) - goto fail; - - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); - struct tm6000_fh *fh = vq->priv_data; - struct tm6000_core *dev = fh->dev; - struct tm6000_dmaqueue *vidq = &dev->vidq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); -} - -static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); - - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops tm6000_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ - * IOCTL handling - * ------------------------------------------------------------------ - */ - -static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources == fh && dev->is_res_read) - return true; - - return false; -} - -static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources == fh) - return true; - - return false; -} - -static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh, - bool is_res_read) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources == fh && dev->is_res_read == is_res_read) - return true; - - /* is it free? */ - if (dev->resources) - return false; - - /* grab it */ - dev->resources = fh; - dev->is_res_read = is_res_read; - dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n"); - return true; -} - -static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources != fh) - return; - - dev->resources = NULL; - dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n"); -} - -/* ------------------------------------------------------------------ - * IOCTL vidioc handling - * ------------------------------------------------------------------ - */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - - strlcpy(cap->driver, "tm6000", sizeof(cap->driver)); - strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card)); - cap->version = TM6000_VERSION; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER | - V4L2_CAP_READWRITE; - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (unlikely(f->index >= ARRAY_SIZE(format))) - return -EINVAL; - - strlcpy(f->description, format[f->index].name, sizeof(f->description)); - f->pixelformat = format[f->index].fourcc; - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tm6000_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vb_vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(format); i++) - if (format[i].fourcc == fourcc) - return format+i; - return NULL; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; - struct tm6000_fmt *fmt; - enum v4l2_field field; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) { - dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)" - " invalid.\n", f->fmt.pix.pixelformat); - return -EINVAL; - } - - field = f->fmt.pix.field; - - if (field == V4L2_FIELD_ANY) - field = V4L2_FIELD_SEQ_TB; - else if (V4L2_FIELD_INTERLACED != field) { - dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n"); - return -EINVAL; - } - - tm6000_get_std_res(dev); - - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - - f->fmt.pix.width &= ~0x01; - - f->fmt.pix.field = field; - - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -/*FIXME: This seems to be generic enough to be at videodev2 */ -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - int ret = vidioc_try_fmt_vid_cap(file, fh, f); - if (ret < 0) - return ret; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->vb_vidq.field = f->fmt.pix.field; - fh->type = f->type; - - dev->fourcc = f->fmt.pix.pixelformat; - - tm6000_set_fourcc_format(dev); - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_reqbufs(&fh->vb_vidq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_querybuf(&fh->vb_vidq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_qbuf(&fh->vb_vidq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_dqbuf(&fh->vb_vidq, p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (i != fh->type) - return -EINVAL; - - if (!res_get(dev, fh, false)) - return -EBUSY; - return (videobuf_streamon(&fh->vb_vidq)); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct tm6000_fh *fh=priv; - struct tm6000_core *dev = fh->dev; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (i != fh->type) - return -EINVAL; - - videobuf_streamoff(&fh->vb_vidq); - res_free(dev,fh); - - return (0); -} - -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm) -{ - int rc=0; - struct tm6000_fh *fh=priv; - struct tm6000_core *dev = fh->dev; - - dev->norm = *norm; - rc = tm6000_init_analog_mode(dev); - - fh->width = dev->width; - fh->height = dev->height; - - if (rc<0) - return rc; - - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); - - return 0; -} - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - switch (inp->index) { - case TM6000_INPUT_TV: - inp->type = V4L2_INPUT_TYPE_TUNER; - strcpy(inp->name, "Television"); - break; - case TM6000_INPUT_COMPOSITE: - if (dev->caps.has_input_comp) { - inp->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(inp->name, "Composite"); - } else - return -EINVAL; - break; - case TM6000_INPUT_SVIDEO: - if (dev->caps.has_input_svid) { - inp->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(inp->name, "S-Video"); - } else - return -EINVAL; - break; - default: - return -EINVAL; - } - inp->std = TM6000_STD; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - *i = dev->input; - - return 0; -} -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - int rc = 0; - char buf[1]; - - switch (i) { - case TM6000_INPUT_TV: - dev->input = i; - *buf = 0; - break; - case TM6000_INPUT_COMPOSITE: - case TM6000_INPUT_SVIDEO: - dev->input = i; - *buf = 1; - break; - default: - return -EINVAL; - } - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, - REQ_03_SET_GET_MCU_PIN, 0x03, 1, buf, 1); - - if (!rc) { - dev->input = i; - rc = vidioc_s_std(file, priv, &dev->vfd->current_norm); - } - - return rc; -} - - /* --- controls ---------------------------------------------- */ -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++) - if (qc->id && qc->id == tm6000_qctrl[i].id) { - memcpy(qc, &(tm6000_qctrl[i]), - sizeof(*qc)); - return 0; - } - - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - int val; - - /* FIXME: Probably, those won't work! Maybe we need shadow regs */ - switch (ctrl->id) { - case V4L2_CID_CONTRAST: - val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0); - break; - case V4L2_CID_BRIGHTNESS: - val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0); - return 0; - case V4L2_CID_SATURATION: - val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0); - return 0; - case V4L2_CID_HUE: - val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0); - return 0; - case V4L2_CID_AUDIO_MUTE: - val = dev->ctl_mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - val = dev->ctl_volume; - return 0; - default: - return -EINVAL; - } - - if (val < 0) - return val; - - ctrl->value = val; - - return 0; -} -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - u8 val = ctrl->value; - - switch (ctrl->id) { - case V4L2_CID_CONTRAST: - tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val); - return 0; - case V4L2_CID_BRIGHTNESS: - tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val); - return 0; - case V4L2_CID_SATURATION: - tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val); - return 0; - case V4L2_CID_HUE: - tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val); - return 0; - case V4L2_CID_AUDIO_MUTE: - dev->ctl_mute = val; - tm6000_tvaudio_set_mute(dev, val); - return 0; - case V4L2_CID_AUDIO_VOLUME: - dev->ctl_volume = val; - tm6000_set_volume(dev, val); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - t->rxsubchans = V4L2_TUNER_SUB_MONO; - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (UNSET == dev->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->freq; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (unlikely(f->tuner != 0)) - return -EINVAL; - if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) - return -EINVAL; - - dev->freq = f->frequency; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); - - return 0; -} - -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - - strcpy(cap->driver, "tm6000"); - strlcpy(cap->card, dev->name, sizeof(dev->name)); - sprintf(cap->bus_info, "USB%04x:%04x", - le16_to_cpu(dev->udev->descriptor.idVendor), - le16_to_cpu(dev->udev->descriptor.idProduct)); - cap->version = dev->dev_type; - cap->capabilities = V4L2_CAP_TUNER; - - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - - if (0 != t->index) - return -EINVAL; - - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); - - if ((dev->aradio == TM6000_AIP_LINE1) || - (dev->aradio == TM6000_AIP_LINE2)) { - t->rxsubchans = V4L2_TUNER_SUB_MONO; - } - else { - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - } - - return 0; -} - -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - - if (0 != t->index) - return -EINVAL; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - memset(a, 0, sizeof(*a)); - strcpy(a->name, "Radio"); - return 0; -} - -static int radio_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input(struct file *filp, void *priv, unsigned int i) -{ - return 0; -} - -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - return 0; -} - -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctrl; - - return 0; -} - -/* ------------------------------------------------------------------ - File operations for the device - ------------------------------------------------------------------*/ - -static int tm6000_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct tm6000_core *dev = video_drvdata(file); - struct tm6000_fh *fh; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - int i, rc; - int radio = 0; - - printk(KERN_INFO "tm6000: open called (dev=%s)\n", - video_device_node_name(vdev)); - - dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n", - video_device_node_name(vdev)); - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - } - - /* If more than one user, mutex should be added */ - dev->users++; - - dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n", - video_device_node_name(vdev), v4l2_type_names[type], - dev->users); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) { - dev->users--; - return -ENOMEM; - } - - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - dev->radio = radio; - fh->type = type; - dev->fourcc = format[0].fourcc; - - fh->fmt = format_by_fourcc(dev->fourcc); - - tm6000_get_std_res (dev); - - fh->width = dev->width; - fh->height = dev->height; - - dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, " - "dev->vidq=0x%08lx\n", - (unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq); - dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " - "queued=%d\n",list_empty(&dev->vidq.queued)); - dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " - "active=%d\n",list_empty(&dev->vidq.active)); - - /* initialize hardware on analog mode */ - rc = tm6000_init_analog_mode(dev); - if (rc < 0) - return rc; - - if (dev->mode != TM6000_MODE_ANALOG) { - /* Put all controls at a sane state */ - for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++) - qctl_regs[i] = tm6000_qctrl[i].default_value; - - dev->mode = TM6000_MODE_ANALOG; - } - - videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops, - NULL, &dev->slock, - fh->type, - V4L2_FIELD_INTERLACED, - sizeof(struct tm6000_buffer), fh, &dev->lock); - - if (fh->radio) { - dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n"); - tm6000_set_audio_input(dev, dev->aradio); - tm6000_set_volume(dev, dev->ctl_volume); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); - tm6000_prepare_isoc(dev); - tm6000_start_thread(dev); - } - else { - tm6000_set_audio_input(dev, dev->avideo); - tm6000_set_volume(dev, dev->ctl_volume); - } - - return 0; -} - -static ssize_t -tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos) -{ - struct tm6000_fh *fh = file->private_data; - - if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (!res_get(fh->dev, fh, true)) - return -EBUSY; - - return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0, - file->f_flags & O_NONBLOCK); - } - return 0; -} - -static unsigned int -tm6000_poll(struct file *file, struct poll_table_struct *wait) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_buffer *buf; - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) - return POLLERR; - - if (!!is_res_streaming(fh->dev, fh)) - return POLLERR; - - if (!is_res_read(fh->dev, fh)) { - /* streaming capture */ - if (list_empty(&fh->vb_vidq.stream)) - return POLLERR; - buf = list_entry(fh->vb_vidq.stream.next,struct tm6000_buffer,vb.stream); - } else { - /* read() capture */ - return videobuf_poll_stream(file, &fh->vb_vidq, - wait); - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - return POLLIN | POLLRDNORM; - return 0; -} - -static int tm6000_release(struct file *file) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - struct video_device *vdev = video_devdata(file); - - dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n", - video_device_node_name(vdev), dev->users); - - dev->users--; - - res_free(dev, fh); - if (!dev->users) { - tm6000_uninit_isoc(dev); - videobuf_mmap_free(&fh->vb_vidq); - } - - kfree(fh); - - return 0; -} - -static int tm6000_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct tm6000_fh *fh = file->private_data; - int ret; - - ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); - - return ret; -} - -static struct v4l2_file_operations tm6000_fops = { - .owner = THIS_MODULE, - .open = tm6000_open, - .release = tm6000_release, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .read = tm6000_read, - .poll = tm6000_poll, - .mmap = tm6000_mmap, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, -}; - -static struct video_device tm6000_template = { - .name = "tm6000", - .fops = &tm6000_fops, - .ioctl_ops = &video_ioctl_ops, - .release = video_device_release, - .tvnorms = TM6000_STD, - .current_norm = V4L2_STD_NTSC_M, -}; - -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = tm6000_open, - .release = tm6000_release, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_s_std = radio_s_std, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_input = radio_g_input, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -}; - -struct video_device tm6000_radio_template = { - .name = "tm6000", - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, -}; - -/* ----------------------------------------------------------------- - * Initialization and module stuff - * ------------------------------------------------------------------ - */ - -static struct video_device *vdev_init(struct tm6000_core *dev, - const struct video_device - *template, const char *type_name) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - - *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; - vfd->debug = tm6000_debug; - vfd->lock = &dev->lock; - - snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); - - video_set_drvdata(vfd, dev); - return vfd; -} - -int tm6000_v4l2_register(struct tm6000_core *dev) -{ - int ret = -1; - - dev->vfd = vdev_init(dev, &tm6000_template, "video"); - - if (!dev->vfd) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - return -ENOMEM; - } - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - - ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr); - - if (ret < 0) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - return ret; - } - - printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(dev->vfd)); - - dev->radio_dev = vdev_init(dev, &tm6000_radio_template, - "radio"); - if (!dev->radio_dev) { - printk(KERN_INFO "%s: can't register radio device\n", - dev->name); - return ret; /* FIXME release resource */ - } - - ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr); - if (ret < 0) { - printk(KERN_INFO "%s: can't register radio device\n", - dev->name); - return ret; /* FIXME release resource */ - } - - printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(dev->radio_dev)); - - printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret); - return ret; -} - -int tm6000_v4l2_unregister(struct tm6000_core *dev) -{ - video_unregister_device(dev->vfd); - - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - - return 0; -} - -int tm6000_v4l2_exit(void) -{ - return 0; -} - -module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr, "Allow changing video device number"); - -module_param_named(debug, tm6000_debug, int, 0444); -MODULE_PARM_DESC(debug, "activates debug info"); - -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/av7110/bootcode.bin.ihex v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/av7110/bootcode.bin.ihex --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/av7110/bootcode.bin.ihex 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/av7110/bootcode.bin.ihex 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -:10000000EA00000EE1B0F00EE25EF004E25EF00401 -:10001000E25EF008E25EF004E25EF004E25EF0040C -:100020002C0000240000000C000000002C00003414 -:1000300000000000A5A55A5A001F15550000000930 -:10004000E59FD07CE59F4074E3A00000E5840000BC -:10005000E5840004E59F1070E59F2070E59F306403 -:10006000E8B11FE0E8A31FE0E1510002DAFFFFFB67 -:10007000E59FF050E1D410B0E35100000AFFFFFC0F -:10008000E1A0100DE5943004E1D420B2E282203FDB -:10009000E1B0232203A00002E1C400B00AFFFFF494 -:1000A000E8B11FE0E8A31FE0E8B11FE0E8A31FE00C -:1000B000E25220011AFFFFF9E22DDB05EAFFFFEC17 -:1000C0002C0003F82C0004009E0008002C00007493 -:0400D0002C0000C040 -:00000001FF diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/av7110/Boot.S v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/av7110/Boot.S --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/av7110/Boot.S 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/av7110/Boot.S 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -/* - Boot.S: boot loader for Siemens DVB-S card - - Copyright (C) 2001 Convergence integrated media GmbH - Written by Ralph Metzler - - Copyright (C) 2006 Matthieu CASTET - - 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, or (at your option) any later version. - - 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - -*/ - -/* - check AV711x_3_1.pdf for some hardware infos - build it with : - $ cc -mbig-endian -c Boot.S - $ ld -Ttext 0x2c000000 -EB -o Boot Boot.o - $ objcopy -Obinary Boot -*/ - - .text - .align - .globl _start -_start: - b reset // reset vector - movs pc, r14 // undefined - subs pc, r14, #4 // SWI - subs pc, r14, #4 // prefetch abort - subs pc, r14, #8 // data abort - subs pc, r14, #4 // reserved - subs pc, r14, #4 // IRQ - subs pc, r14, #4 // FIQ - - .word tbl // table needed by firmware ROM -tbl: .word (endtbl - tbl) - .word 0 - .word conf -endtbl: .word 0 -conf: .word 0xa5a55a5a - .word 0x001f1555 - .word 0x00000009 - -reset: ldr r13, buffer - ldr r4, flag - mov r0, #0 - str r0, [r4] - str r0, [r4, #4] - - ldr r1, wait_address - ldr r2, flag_address - ldr r3, sram - -copycode: // copy the code HW Sram - ldmia r1!, {r5-r12} - stmia r3!, {r5-r12} - cmp r1, r2 - ble copycode - ldr pc, sram // jump to the copied code - -wait: ldrh r1, [r4] // wait for flag!=0 - cmp r1, #0 - beq wait - - mov r1, r13 // buffer address - ldr r3, [r4,#4] // destaddr - - ldrh r2, [r4,#2] // get segment length - add r2, r2, #63 // round length to next 64 bytes - movs r2, r2, lsr #6 // and divide by 64 - moveq r0, #2 // if 0, set flag to 2, else signal - strh r0, [r4] // that buffer is accepted by setting to 0 - beq wait - -copyloop: - ldmia r1!, {r5-r12} - stmia r3!, {r5-r12} - ldmia r1!, {r5-r12} - stmia r3!, {r5-r12} - subs r2, r2, #1 - bne copyloop - - eor r13, r13, #0x1400 // switch to other buffer - b wait - -// flag is stored at 0x2c0003f8, length at 0x2c0003fa, -// destaddr at 0x2c0003fc - -flag: .word 0x2c0003f8 - - -// buffer 1 is at 0x2c000400, buffer 2 at 0x2c001000 - -buffer: .word 0x2c000400 - -sram: .word 0x9e000800 -wait_address: .word wait -flag_address: .word flag diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/cpia2/stv0672_vp4.bin.ihex v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/cpia2/stv0672_vp4.bin.ihex --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/cpia2/stv0672_vp4.bin.ihex 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/cpia2/stv0672_vp4.bin.ihex 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -:1000000001BCE302E303E304E305E306E3079344EF -:1000100056D4934E5651934E51D6934E4F54934EC1 -:10002000924F92A4930592F4931B929291E692368A -:100030009274924A928C928EC8D00B4202A0CA92BD -:100040000902C9100A0A0A81E3B8E3B0E3A8E3A0F1 -:10005000E398E390E100CFD70A12CC9508B20A18D2 -:10006000E10001EE0C084A12C818F09AC022F31CF5 -:100070004A13F314C8A0F214F21CEB13D3A26316B4 -:10008000489EF018A403F393C058F713519CE9203D -:10009000CFEF63F9922ED35F63FA922ED36763FB9F -:1000A000922ED36FE91A631648A7F020A406F394A2 -:1000B000C027F714F513519DF6136318C420CBEF36 -:1000C00063FC922ED37763FD922ED37F63FE922E34 -:1000D000D38763FF922ED38F6438922ED3976439DF -:1000E000922ED39FE100F53AF43BF7BFF2BCF23D0C -:1000F000E1008087908051D5022202324BD3F71164 -:100100000BDAE1000E0202400DB5E3024855E5129C -:10011000A401E81BE390F018A401E8BF8DB84BD10F -:100120004BD80BCB0BC2E100E302E30352D360597F -:10013000E6930D2252D4E6930D2AE398E390E10072 -:10014000025D0263E302C81202CAC85202C2826898 -:10015000E302C81402CAC89002C20AD0C9930ADADC -:10016000CCD20AE2631202DA0A980AA00AA8E39043 -:10017000E100E3020AD0C9930ADACCD20AE26312A0 -:1001800002DA0A980AA00AA84991E56AA404C812EA -:1001900002CAC8528289C81402CAC89002C2E39037 -:1001A000E1000860E1004853E897085AE100E302E3 -:1001B000E30354D36059E6930D52E398E390E100D2 -:1001C000029CE3025513931755139317E390E10034 -:1001D0007530E302E30355556059E6930DB2E39899 -:1001E000E390E10002AEE792E918EA9AE898E81095 -:1001F000E811E851D2DAD2F3E813D2FAE850D2EAA1 -:10020000E8D0E8D1D30A03094823E52CA003482409 -:10021000EA1C0308D2E3D303D313E10002CB059316 -:100220005793F09AAC0BE30792EAE29FE506E3B03E -:10023000A002EB1E82D7EA1EE23B859BE91EC89016 -:10024000859402DE05805793F0BAAC0692EAE2BFCD -:10025000E506A001EBBF8588E93EC8908581E93EAF -:10026000F0BAF339F03A6017F03AC090F0BAE10012 -:10027000003FE302E30358106059E6930DA25812C1 -:10028000E6930DAAE398E390E1000301E100030384 -:100290009B7D8B8BE302E30358566059E6930DBABE -:1002A000E398E390E100030F9311E100E3024A11A8 -:1002B0000B4291AFE390E100F291F091A3FEE100D7 -:1002C0006092C05FF013F013595BE213F0115A19FA -:1002D000E213E10000000327686176616E610006A9 -:1002E000032CE302E303E9385915595AF29ABC0B7F -:1002F000A40A591EF311F01AE2BB5915F011192A7C -:10030000E502A401EBBFE398E390E1000342192862 -:10031000E100E9306079E100E303E3076079934E9F -:10032000E3B8E398E100E91AF01FE233F091E292BA -:08033000E032F031E1000000B1 -:00000001FF - - Copyright 2001, STMicrolectronics, Inc. - Contact: steve.miller@st.com - - Description: - This file contains patch data for the CPiA2 (stv0672) VP4. - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/dabusb/bitstream.bin.ihex v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/dabusb/bitstream.bin.ihex --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/dabusb/bitstream.bin.ihex 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/dabusb/bitstream.bin.ihex 1970-01-01 00:00:00.000000000 +0000 @@ -1,761 +0,0 @@ -:1000000000090FF00FF00FF00FF000000161000D7C -:1000100064616275736274722E6E63640062000BB9 -:10002000733130786C76713130300063000B3139C8 -:1000300039392F30392F32340064000931303A34E5 -:10004000323A3436006500002EC0FF20175F9F5BF8 -:10005000FEFBBBB7BBBBFBBFAFEFFBDFB7FBFB7F61 -:10006000BFB7EFF2FFFBFEFFFFEFFFFEFFBFFFFF9B -:10007000FFFFAFFFFAFFFFFFC9FFFFFFDFFFFFFF3B -:10008000FFFFFFFFFFFFFFFFFFFFFFFBFFA3FFFBE4 -:10009000FEFFBFEFE3FEFFBFE3FEFFBF6FFBF6FF18 -:1000A000BFFF47FFFF9FEEF9FECF9FEFFBCF9BEE19 -:1000B000F8FEEF8FEEFBFE0BFFFFFFFFFFFFFFFFE2 -:1000C000FFFFBFFFFFFBFFFFBFFFFFFC17FFFFFFAF -:1000D000FFFFFF7FFFFFFF7FFFFFFBFFFF7FFFFFB4 -:1000E000FC3FFFFFFFFFFFFFFFFFFFFBFFFFFFFFE7 -:1000F000FFFFFFFFFFFE5FFFFFFDFFFFDBFFFDFFD9 -:1001000077FFFDFFFFDFFEFDFFFFF2FFFFFFFFFFB9 -:10011000FFFDFFFFFFFDFFFFFFFFFFFFFFFFFFE111 -:100120007FFFFFFFFFFFFFFFFFFFFFFFFF3FFFFF1F -:10013000FFFFFFFFE3FFFFFFFFFFFFFFFFFFFFBF2B -:10014000FFFEFFFFFFFFFFFFFF67FFFFFFFFFFFF58 -:100150007FFFFFFF7FFFFFFFFFFFDFFFFFFF2FFF9F -:10016000F3FDFF7FDEF7FDFF7FF77DFF7FDFF7BD4C -:10017000FF7FFF1FFFEFFBFEFFBFEFFBFEFFEFFB6D -:10018000FEFFBFEFFBFEFFFF3FFE7F9FE7F9FE7F15 -:100190009FE7FA7F9FE7F9FE7F9FE7FFFC7FBFBFE6 -:1001A000EFFBFEFFBFEFFBB7BFEFFBFEFFBFEFFBB9 -:1001B000FFE0FDF9FE7F9FE7F9FE7F9DF9FE7D9D43 -:1001C000E7F9FE7F9FEDEDFFFDFF7FDFF7FDFF7F8E -:1001D000DFFDFF7FDFF7FDFF7FDFFF9BFFEFFBFE14 -:1001E000FBBFEFBBFEFFAFBBBEFFBFEFFBFEFFFFE2 -:1001F000B7BFDBF6BDBF6BDBF6F9BF5BD6F9BF6FF0 -:10020000DBF6FDBFFF0EFFFFFFFF5FFFF7FFFF7F86 -:10021000F7BDFFFFFFFFFFFFFFDF9FFFFFFFFEFFB9 -:10022000FFEFFEFEFFFF77FFFBFBFFFFFFFFF83F47 -:10023000FFFDFFFFFFFDFFFFFFFFFFFFFFFFFFFFD2 -:10024000FFFFFFF47FFFFEFDBEFFDFFEFFFFEF7F3E -:10025000FFCFFFCFFFFFFFDFE6FFFF7FDFF7DD7F91 -:100260007FDFF7FF7FDFD7FDFF7FDFF7FFCDFFF2F7 -:10027000FFFF4F7FF4FFFFFFE7EFFFFFFFFFFFFFF1 -:10028000FFFFBBFFEFFFFEFFFFFFEFFFFFEFFFFBF7 -:10029000FFFFFFFFFFFFFF65EFFFFF7FFFFDEFFFAA -:1002A000FFFFFEFFFFFFFFFFFFFFFFFECFDFFEFFB1 -:1002B000FFFBFFFFFFFFF3FFFFFFFFFFFFFFFFFF5E -:1002C000FEDFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F -:1002D000FFFFFFFFFFFEBFFFFFFFE37FFFFFFFFF0B -:1002E000FFFFEFEBFFFEBFFFEBFFFC7FFFFFFFEE2B -:1002F000FFFFFFFFFFFFDDFFD6FFFDBFFFFBFFFEA0 -:10030000FDFFFFFDEFFFFFFFFFFFFFDEFFFFFFFF32 -:10031000FFFFBFFFFDFF7FBFFF5FDFFFFFBF77FF77 -:10032000FFFF7FD7FFFFFFFFFFC3FFFFFFFFDFEFF1 -:10033000FFFFFEFBFFFFDFBFFFFFFFFFEDFFB7FF8C -:10034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD -:10035000FFFFFFAF7FFFFFFFFFFFFFFFFFFFFFFF7D -:10036000FFFFFFFFFFFFFFFFDFBFDFF3FDFBFF5BD3 -:10037000FDFFBFEFF7FFFF7DFFFFFFFFF83BFFBF74 -:100380006FFFFEFFBFFFEB7DFFEFFBFEFFFFFFFFF9 -:10039000FFF27FFCFF3FDFEDFEFFFFFFFFEF5FF7A8 -:1003A000B5FFEFFFFFFFE03F9F9EFFFFEFFFDFFF87 -:1003B000BF5FBFCFF3FFFFFFFFFFFF69AF33FDFF5D -:1003C000FBFFFFFFFFFCFF7FD9FFDFFFFFFFFFF514 -:1003D000A3DF6EDEFFFFBDFFFFFEFFFFFFFEE7FDB9 -:1003E000FFFFFFF9EFC6FEB7ADE5F9FFFFFFCFFF57 -:1003F000FFFFCDFB7FFFFFFFF9F60FDFECCF7FFFA5 -:10040000FB7FFFFFFFFDFFFEF9FD7FFF7FFFF95B35 -:10041000FF73DCFD7BDFFFFFFF7BFFFFF753D6FFA2 -:10042000FFFFFFD89FFEFFEF7FEEFFFFFFFBEDED2D -:10043000FDFFFEFFFFFB7FFFE27FFF6FD857F7FF57 -:10044000FFFFDFFFE8FFFFFDFFFFFC7FFFE4FFFB97 -:10045000EFFBFEDFB7EDFFFEDF7FFFFE7FB7FFFFA5 -:10046000FFFF89FFFFCFF3FE7FFFEFFFFE7E7FFBE5 -:10047000FFFFFFFFFFFFFFF1FFEB7AD5BF6FDBBE92 -:10048000FDB7D8F6E5BF6FFBFEF5BD7E06FFDFF7D3 -:10049000FBF6FF3FFFDBFFFF6FFBF7FFFFFFFBFEFE -:1004A000F7AFFFB7EDEFF7FEFFFFDFFFFEFFEFFF58 -:1004B000FFFFFFBFF7FC1FEEFBFEBDFF7F5FD7FD19 -:1004C000FB43FFFFFDFF5FFFF7FFF93FFFCFF3FDAA -:1004D000F77EEFA7F9FE8FA7E9F37E9FFBF8FFFFFA -:1004E0003FFD7F5FDFFDFFFF5FFFFD5FFFFF7FFDE4 -:1004F0007FFD9FFFE0FFFAF8BE6F9FE6F8BE3F9AD0 -:10050000F9BE6F9FE2F9FE6F9FF9FFF5FD7FCFDF28 -:10051000FDFD7FFFF5FFFFFFF7F5FD0FDBFFD3FFCD -:10052000EBFAFFFFBFFFFAFFFFCBFBFEFFFFEBFA8B -:10053000FEFFFFB7FFFFFFFFBFFFDFF5FFFFD7FFA6 -:10054000FFFFDFD7F5FF7FFE4FFFFDFF7F7FFFAD92 -:10055000EBFBFFADFFFFFFFFAFEBFBFFFC0DFFFF72 -:10056000DFD2FDFFFFFDF6FFFF7FFFFF1FFFFFFF55 -:10057000FFFB3F7DEB32FEBF2FEBFAAEBDE0FA7E14 -:10058000BFADEBFAFEBFF57FFFDEFEE3FBFFFFFF33 -:10059000DFEF4FDFFF7FDFFFF7FFFFF87FFFFFEFAA -:1005A000FBFFFFFFEFFFFFDFEDFBDFFFBFFFFFFF05 -:1005B00081FFFFFFFF3FFFFFFFFFFEDDFEEFFDFFBF -:1005C000FFFBFEF7FF93FDFB7EFFFE87E9FF7FB396 -:1005D0009FFEFEFFAFFDFE7E3FFE67FFFFF7FFFFC2 -:1005E000FCF7DFFDFF7FFFFF7F6DFFFFFEFFFF2FAB -:1005F000FFBFFFFFEEFFBEFFFFFEFFEFFFFFFEFFAF -:10060000EFFFFFFA5FFFFFFBFFFFEFFFFBFEFDFFCA -:10061000FEFFFBFFFFFF7FFFFEBFDFFFFBFFFFF7DC -:10062000FCFDFFFFFFFFFF7FFFFFFFFFFFF27FFFEC -:10063000FFFFFF7FFFFFFFFFF3FFFFFFEFFBFFFF6A -:10064000FFDFE2FFFFFBFFFFFFFFFFFFFBE7FFFD19 -:10065000FFFFFFBFFFFFFFEDEFFDFFFFDFD7F5FD62 -:100660007F5DFDFF7FDF97F4FD7B5FFFC9FFFBFE32 -:10067000FFBFFF5FFFFFF7FFEFFDFFEFFFFFFFFF94 -:10068000FFF7FFD7FD7D7FFFFFFFFFEFDFF7FDFFE8 -:10069000BBFFFF7FFFFEE3FFF9FE7FBFEFFBFEFF27 -:1006A000BFF9FEFF9FEFF9FEFFBFF3DAFF37CDF38F -:1006B0007CDF37CDF37F37CDF37CDF37CCF37F5A48 -:1006C000BDF6FDBF6FDBF6FDBF6FDEFDBF6FDBF676 -:1006D000FDBF6FFEF16FEB7ADEB7ADEB7ADEB7AF41 -:1006E0007ADEB7ADEB7ADEB7FF7EFFFECDB36CDB13 -:1006F00036CDB36CDECDB36CDB36CDB36CDFC9BFAA -:10070000F7BDEF7A9EA7A9EA7AB7BDEA7BDEA7BD5F -:10071000CA728D91FFEFFBFEFFBFEFFBFEF7EFFB11 -:10072000FEFFBFEFFBFEFFFE87FFF6FDBF6FDBF6B0 -:10073000FDBF6FF6FDBF6FDBF6FDBF6FFE4FFFBF66 -:10074000EFBBEEFBBEEFBBEFBEEFBBEEFBBEEFBB06 -:10075000EFFC5FFFFFFF3FCFF3FCFF3FCFFCFF3F0E -:10076000CFF3FCFF3FCFFD9FFEBFAFEBFAFEBFAF65 -:10077000EBFEBFAFEBFAFEBFAFEBFFE16FFDFF7F1C -:10078000DFF7FDFF7FDFFDFF7FDFF7FDFF7FDFFF8F -:100790007ABFFBFEDFB7EDFB7EDFB7FB7EDFB7ED99 -:1007A000FB7EDFB7FFC9FFFFBFEFFBFEFFBFEFFB25 -:1007B000FFBFEFFBFEFFBFEEFBFEBBFFFEFFBFEF89 -:1007C000FBFEFFBFEFFEFFBFEFFBFEFF3FCFFFE7EC -:1007D000FEFFF5FD775DD735DD77D7F5CD7B5DD7AE -:1007E000F5DD77FE27FFFF8BE2F8BE2F8BE2F9AF36 -:1007F0008BE2F8BE2F8BE2F9FE1FFF5FD7F5FD7F7E -:100800005FD7F5FF5FD7F5FD7F5FD7F5FFFA3FFEB6 -:10081000BFAFEBFAFEBFAFEBECBFAFEBFAFEBFAF83 -:10082000EBFFFE7FFD7FFFFFFFFFFFFFFFFFFFFFEF -:10083000FFFFFFFFFFFFFFE6FFFADFF7FDFF7FDFB0 -:10084000F7FCFFDFF7FDFF7FDFF7FDFFF5FFFFFFA1 -:10085000FFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFAC -:10086000FF02FFFEBFABEBFABEBF23EBDE1FAFEA1A -:10087000FAFEAFAFEBFD97FFF3FC7B1FCFF1FC7FE0 -:100880001FF1FC771FCDF1FCFF1FFE87FFAFEFFAD2 -:10089000FEFFAFEFFAFDBF2BFB7EBFBFEBFBFBFB09 -:1008A000DFFFFBF7FFFF7FF7F7FFFDDFFEFCDFFF5A -:1008B000DFFFFDFFDABFFFBBEFFBF9FFBEEFFBFB86 -:1008C000BFEFFBFEFFBFEFFBFFF77FFDD7FFFF7F13 -:1008D000FFFFFFFEF7FFFEFFF7FFFF7FFFFFECFFCD -:1008E000FFFEDFBFFFFBFEFFBB68AE1FAEFBFBFFE3 -:1008F000FFBFFFD5FF7FFFFFF7FEFEFFBFEF9FFDAE -:100900007FFFCBFFFFDFFFFFBBF7BFFFFFFFFFDF77 -:10091000FFBFFBFFFFFFDE3FFFFFFFFFFFA7FFFF64 -:10092000FFFFEFFF7FFBFDFB7FFFFFFFFFCFF37CB0 -:10093000FF7F8D7FFFFFFFFFFBFFF7FBFEFDFFFF4C -:10094000FFFFF7FDFF7FFD1FFDFFFFFFFFBFDFFF85 -:10095000FFFE5CFF6DFF7FABE7F1FFFD9FFFFFAD8B -:10096000EB7A3F1FFFFFFEBFAFF3DEF5FF8FFBDF2C -:10097000E67FFFDFF3FDFF7EFFFFFFFFFFFDF7F3E5 -:100980007FDFF7EFFFF63F9FDFFFFFEEFFFFEFFB9D -:10099000FFFFF9FBFE4FBFEFBBFF69AFAFFCFF3FAF -:1009A000DDFFFCBF8FFFFDF3BFED9EFCBF6FF5D3F6 -:1009B000DFFFDBD6F5EFFDFEFFB9FF1FD2A9AFFFCA -:1009C000DBF7BFEF46FFFFADEB7ADFEFF7FF7FF717 -:1009D0009FEDFF7FFFADEB7FF56FFFFDFBD6F4F7DB -:1009E000FBF97E7FFF5FC2FEBFFDFB33DFF95BFFDC -:1009F000FFDD677DCFEFDBECFF77DDF7FDFFFFDE8F -:100A0000A7BFD49FFFFFBFEFFEFFDFEFBBFFFFEFEE -:100A1000EBFAFFEFBDFBFFE27FFFDFDFF7FDBFBBC0 -:100A200073F7FD7FDFDEF7BFEADBF6FFD6FFFF6679 -:100A3000FFBEFFBF6BD9F6DFFFFB7E7FB77EFFFEF9 -:100A4000FFCDFFFE7FFFFCFD3FFBFBF7FFFFFBF64B -:100A50007DFE7FFFFCFFB9FFF9FAFEBFAF5BD6ED6D -:100A6000AD7BF6F9BFEFF8FAFEBFFEE6FFFFF7FD3C -:100A7000FF7FBFEFF3FFFF6FF7FEFFFFF7FDFEF70E -:100A8000EFFFFBEFFB7EDEFEFFBFFFFEFFFFFBFF86 -:100A9000FFEFFB6FFC1FFEE7FFFFFFEFFFD3B4BBD1 -:100AA000FFFFFDBF6FE3FEFFBFFCBFF7CFF7FDFF0A -:100AB0002FDFABEAFFDFE7EA9AAFEFFBFEFFF53F80 -:100AC000FD7EFFD7F5FBFFFDF7FF7FFEF7FDFFD7AC -:100AD000FFD77FEE7FFA79FE2F8BE6F9FE3F9EF976 -:100AE000BE2F0BE7F9FE2F9FFDFFFE7D7F5FD7FF37 -:100AF000FF7FFFFDFF7F5F97FFFD7F5FFFE3FFFF4E -:100B0000FAFEBFAFFBFBFFFFCFEBFEBFAFFFFAFE6E -:100B1000BFFF87FFFFF5FFFFFFFFFDFF7FFFFFFF29 -:100B2000FBFFFFF5FFFFFE0FFFFDEBFFFFF7FFEF02 -:100B30007BDFFEFFFFDFF7FDEB7FDFFF5FFFFFFFE8 -:100B4000FFFDBFFF7EFABFC7DBF7BD3FFBFFF6FF30 -:100B5000FAAFFFEBFAFE3F2FEAFA3EADC9BAF6ADA7 -:100B6000AFEBFAF6BFFE7FFFFFFDFFF17F3FCFF156 -:100B7000EFFF7FFFBCDFDFF7DDFFE07FFFFFFEFF62 -:100B8000FAECBB7F5FFFFBECFFEFB7FFF7FFFFB5B2 -:100B9000FFFF7FFFFFFFEEDF5FDFDEFFAEE777FFE8 -:100BA000FFDFF7FFE3FFFABBFEFFAFFDFBFEBFABCE -:100BB000F9FEFFBF7FBFFEBDFED7FF9FFDFFBEEF6B -:100BC000FFEEFDBB5BEFFF7FEFFFEFFF7FFF4FFF10 -:100BD000EFFBBCFCFFFFFFFEFEFDFAFEFBFFFDF39B -:100BE000FBFFF85FFFFFD7F5FDDFEFFFF3DC5FCE24 -:100BF000F5BDFFFFD7FFFFF93FFFDFF7FFFEFFFD6A -:100C0000FFFBFFF7B97DFEDFFFFFFFFFF97FFFFE70 -:100C1000FFFF7FFFFEFFFFF7F6FFBFF1F8FFFFFFCB -:100C2000FFE0FFFFFFFFF9FFFFFFFFFFEFEFFFFF19 -:100C30009BFB7FFFFFFFC1FFDFFF3F5FD7BFEFBB26 -:100C4000DEEEFF7FDFFFFEF57FDFFF99FFFFFAFF9C -:100C5000BFFDEB7AFFB7FEFEFFFFEFFFFFFDBFFF1B -:100C600097FFFDF7FF7FF7FFFFFD5FFEF3F9DFDF83 -:100C7000FFFFFCFFFF83FFFFFEFF9EECFBEEFF9FED -:100C8000BFEFFFFEED7BFFFFFFF15AFFFFFDFF7C93 -:100C9000693BDFFF7F1FDFFFFDBAFFFFFBFF5BBD8F -:100CA000FFFFFFFFD7B6EDE9FFD6BD6F5FFBFFEF9C -:100CB000FF5FFEF66FFFFFFFFFF7EB7ADFFF9F7F1F -:100CC0007FFFB7FFFFFEDFFF6CFFFBFFBB6FEBFE9D -:100CD000CCF7A5FA5CF575BBB7DFFE6F5FC5BFFD4E -:100CE0007BFEFF95E729CF4FF591EE6BDFEFFD54CB -:100CF000F5BDB1FFEFEEFBBEBFAFFEDEBD6FDAF2BA -:100D0000FFAFBEFFFFFD7EA7FFF7FFBFEF7BF6FD46 -:100D1000BD4AF28585BF5BFEB5FDFAFF4FFFFEDFE2 -:100D2000FFEDFFBFFFBF7FFEFFB76DFFF7BFBFEF58 -:100D3000FD1FFFFE7DFF67FFFFFF3F7FFEBFFFE759 -:100D4000DFE7FFEF6BFC1FFFBFEFFBFEDEBFAFFA7D -:100D5000FFB6EFF9FEFF8FEFDBEFAB6FFBFEFFFFA0 -:100D6000EFFDFF7FFFFFDEFFFFEFFFFFFF3FFF6CA9 -:100D7000FFBFFBFFFEFFFBFEDFFFFFEFFFFFBFFF3D -:100D8000FFFEFBFFD57FFFFFEFFBFFFFBFEF43B58C -:100D9000FD6FCFD6BE3F7FDBFEC3FFFDFFAFEBFB9A -:100DA000FCFF3EEFE8FABDCDAAFEFE7DCFFFB7FF08 -:100DB000F7FFFFFFFDFF75CD52D7FDFBF7DDFBEF22 -:100DC000EBFFFF4FFFBF9FE7F9FC7F8BC3F9AF8FAE -:100DD000E7E9BE7F9FE6F9FC5FFFFFF7FDFF7A5F63 -:100DE000D7EDFFFFD7FFDD7FE7FFFCFFFC3FFFFFF5 -:100DF000FFFBFFFEBFAFFFFDFFEFFFEBFFFFFFFFBE -:100E0000FFF77FFF7FDFFFFDFD7FFEF7FD7FDFFF49 -:100E1000FDFFFFDFFBFFEEFFFBFFF7FDFF7ADFF5D6 -:100E2000FDFADFF7FCFF7FDFBFEDFFC9FFDFFFBF8C -:100E30002FFBFFBCADFFF7FFFFEFD3FF7DBF6FFFC1 -:100E4000FAFFFEBFAEEAFABEADA5EBCEBFA7EB5AE6 -:100E5000DEBDAF6BFD57FFFFF47F1F7FFDFF7F36C9 -:100E6000F0DF79FFFFFFF7FDBFFF87FFFBF3FCFF1C -:100E7000FFFFFF7EFFBFDFFFFFFFFFFFFDBFF89F0C -:100E8000FFFFFFFFBFFFFFFDF7FCBDFFFEFFFFFF02 -:100E9000FFFFFBF9BFFFFFEBE2FEFFBFEFA9BA2F99 -:100EA000EBF9FE77DFF7FFFFF97FFFFF7FEFD7FF5B -:100EB000FDFFFBF5FFBF6FDFFFFFFDFFFFF0FFFF53 -:100EC000FF3FCFFFBAEE9BBFEED7FECDEFFFDFBFF8 -:100ED000FFFFC5FFFFFD7F4FFDF6D9FF4FD6FDBFDA -:100EE0006EFFFFF47FFF7F8BFFFFFFFFF7FFF9FE31 -:100EF00037FFD9FBF5AFFDFFFFFBFFFF07FFFFFF4C -:100F0000FBF7FFFDFF7CFA7E4FFCDF1DC7FFFFFFF5 -:100F1000FFAEFFFFFFFFFDFBFFFFFEFEFCFF7F7F3D -:100F2000BFEFFEFFFFFF5FFDFFFFFFFD6F5AD77BA7 -:100F3000BE5FFE39FFF7FFF7FDFEAA1FFFFFFFFFB1 -:100F4000FEFEABAFFDFEBFFFF7FF7FFE8FE3FBEEC4 -:100F50007FFFFFFFFFEBFBFFFDBFEFDFFFFFFFFFAB -:100F6000FFFFFFFBE43FFFDFFFFFFFFFF3EFBBFBF4 -:100F7000BFEFBBFFD7BFFFFFFF29AFF7FFFFFBFFAF -:100F8000FBE6FF0FFB3FDF0FFFAFFFFFFFF5C3DF08 -:100F90005FFFFFFFFE6BCABEBCFF9FF2BFFFFEFA02 -:100FA000FFFFEF16FFFFFFFFFFFCDF97FD79FF3725 -:100FB000E77FFFFFB5FFFFF62FFFFDFBFEFFFFFD05 -:100FC0005F575FFFDB52DFFFFDBFFFFFFCDBFF7BF7 -:100FD000B5FD7FFF719C6EFFF635A59BFFFFFDFF02 -:100FE000FFDB9E7FFEEFFBFFFFBDEFFFDEB7F94BA0 -:100FF000FFF5EFFFFFFFE87EFFEADFF7FFFD695B2C -:10100000FC9FEF78D6FFEBEFFFFFFFE8FFFFEDFF60 -:10101000FFFFFFE3F9F6BFFFFFFEDFFF7FFFFFFFEC -:10102000D1FFFFE7FFFFFFFFE7F9FFBF7FD9FFFD1C -:10103000FE7FFFFEFFF9FFFBD6DFBFEF5BD6FFBFF2 -:10104000FBF6FFBFEFF8F6DDBEFE16FFBFEFFFFEBB -:10105000FFBFEFFFFFFF6FFBFFFFFF6FF3FFF7EF38 -:10106000FBFFBFFFEFFEFFBFFFFFFFBEBFFFEFFFB6 -:101070007FEFFFFD17FB7BFFFFFD7FDBF6F47FFAC1 -:10108000FEF5BFEBE3F7FFFFE9BFFFAFF7FDF37E30 -:101090008FA3EAFFCBF3EEFFBFEFF7F9FFFE7FFF71 -:1010A000FFFFFFF5FBF6FFF52FFEFBD7BFFFBEDF0F -:1010B0009FFFF0FFFFF9FE7F8FA3F8FE6F9FF9F609 -:1010C0002F9FE7F9FE2F9FE1FFFFFF7FDFF7F5FD81 -:1010D0007F7FF5FF9F5FFBFEFF7FFFFFCBFFFFFBE7 -:1010E000FEFFBFAFFBFEFFDFFEFEBFF7FFFFFFFF10 -:1010F000FFC7FFFFFDFF7FDDF7FDFFFFD7FFFD7F90 -:10110000FFFBFDFFFFFEEF7FFDEFFBFEFBFDFF7F23 -:10111000DFFDFF7ADFF7FDFFFFFFFF1FFFFFD3F7C4 -:10112000FFFF6FDBFFFFEFCBF4FFFFFFFFFFFFFED3 -:1011300029FFE8DA769FAF6ADAFE35EBDAD6BFAB85 -:10114000EB7ADEBFD77FFFFEFFBFEFFDDF77BFFD8E -:1011500037EFFFEFFF3FFFFFFFFE7FFFFFFFF77E51 -:10116000DFFFFFFFFAB77FFFFFFEFFFFFFFF89FFF3 -:10117000FFFFFFFFFFFFFFFFFF9FFBFFFFFFE7FFFB -:10118000FFFFFFAAFFABFBFAEFBFFFDFFA7BB9FE61 -:10119000FEFFFDFFF7FE3FFFB7FFF7EEFF7FEFFF1C -:1011A000FF7FFF1FFBFFBFFBFEFFBDFFFF2FFFBF4A -:1011B000FF7FDFFAFFFFFCEEF5F3BEFB0FEFF3BEA0 -:1011C000EFFC5FFF5AFFF7DFFFFFFED5FC5FFBF28E -:1011D000FFFF2FBBF3FFFFBFFFEFFFEFFFFFFFFF9F -:1011E000BFFFFFFD7BFFDFB9FFFBFFD87FFFFFFFE6 -:1011F000FBFFFC7F1FBFE0DFF7EFFFFD7FFEDFFFA0 -:10120000E0FFFFFDEFFBFFFEF7DFFFEB5FFFF7FF08 -:10121000FFFFFFBFFFFDFFFDFFFFFFF7FDFF3BDC13 -:10122000FD6D7B5F57F5FD7F5FFFB1FFEBFFFFFFBC -:10123000FBFBFEFFBFFBBEFFBFEFFBFEFFAFFEF7FA -:10124000DFDFFFFFFF7FCFF3F8FFD7FBFF5FBFF7C5 -:10125000FBFF7FFE23FFFFFE7FF3FFFBFEFFFFF39D -:10126000FFFFF5F9FF3FFFFFF09AFFBE7FFFFCF99C -:10127000FFFDAFEBFEBFFFCFF3FE7FFFFF5BBDFFC8 -:10128000BCEBFFD7D4AFAFFDFFCFF7FDFF7FDFF79C -:10129000FDFEFF6FFFFBFFFFFFFD7F5EFDBFDBF687 -:1012A000FDBF6FFBEEFDFF7AFFFAFBFF3FFBB75F71 -:1012B000D6F71F71DC771DC731DC77DFF9BFF55B2F -:1012C000F4D79DAEFFBFFDBFDBF6FDBF6FDBF6FEC3 -:1012D0003D81FFEBFEFEFEFFEB7ADF7D777DF5794A -:1012E000DF57DDF57D7EE6FFD63FBF7FFFD4F53FBC -:1012F000BFFBBEEFB3EEFB9EEFBBFE8BFFFEDFB787 -:10130000EDFFF7FDFEFFEFBBEEFFBEEFBBEEEBFC2C -:101310001FFFFFFDFFE7FFF7FDFFEFFEFFBFEFFB46 -:10132000FEFFBFEBFA1FFFB7EF5BFEFFAFEBDDE7A2 -:10133000DE779DE779DE779DBFE66FFFFEFFBFEFAB -:10134000FBFEFDBF6FF6FDBF6FDBF6FDBFFF7EFF4F -:10135000FFFBFEFEFFEFFBFDEF7EF7BDEF7BDEF751 -:10136000BDEFFFD5FFBFFFEFFEFFFC3F0FE7FE7FA6 -:101370009FE7F9FE7F9FE7FEF3FFFEDFADDF67EE3D -:10138000FBBFEFFEFFBFEFFBFEFFBFEFFF23FFFF43 -:10139000FFFF7FFFF3BCDBFEFBFFFBBEF7FBFF7F26 -:1013A000DFFFCFFBFF9FE3F9BE3F8FE779FF9DE7AC -:1013B000F9FE7F9FE7F9FE5FFFCFF7FFFFFFDFF743 -:1013C000FE7FE7F9FE7FFFFFFBFEFFFFBFFFBFBF12 -:1013D000FFFEFFBFEFFFFDFFFFFFFFFFFFF7FDFF7A -:1013E000FF3FFFBFFFF7FFFF7FDFFFFFFFFFFFFFB5 -:1013F000FFFFFFFFFFE8EFFF5FF7BFF9FEDFB7FD7D -:10140000FFDFF7FDFF7FDFF7FDFFDDFFF2FFBFFF2F -:10141000FFBFFFFF2FF2FFBF2F7BD2F7BF2FFFBB16 -:10142000FFEE8FAFEBFAFE3FA769CE8FA4EAFAEE8C -:10143000B7AEEBFDC7FFF7F7FFFFFFFFFF7F3EF300 -:1014400074FF3F4FFFE7FF3FFEA7FFFFDFF7B7FF48 -:10145000F7FFBAEF37EBFBFEBFFBFEF3FFF9DFFF51 -:10146000BFFFFFFFBFFFFFFFFDDFFFFDFFFFFBFE35 -:10147000FDFFFBBFFE3FEDFFDFBE3DA7FBFA3FE6F2 -:10148000E1FEFE3FEFE3DFF57FFEFF7EFFFFFFFFA4 -:10149000EF6FF6FF7DEFD7DEFF7DEFFFF2FFFFFF7F -:1014A000FFFFFF7BDEFBE6EEEF376EF37EEB37EF01 -:1014B000FFC1FFFEFFF7EFFFFFFFBF3FD2DFBF2FF0 -:1014C0007BE2FFFE3BBDDBFFFEFFFFFFFFFFEFFE0A -:1014D000FFFBFFFFBFFFFBDFFFBFFFB7FFFFBFEF5C -:1014E000FFFFFFFFFFFF0FFF7FFF1FEFF1FDFFF685 -:1014F000AFFFFFFFFFFFEFFFFFFFFE9FFFFFFF7745 -:10150000EFF7FBFFFE5FFFFFBFCFFBF7DDF7F5FF58 -:101510005FD5F5FD7F5FD7F5FFFB0FFFFFA9EA7AE7 -:10152000FFAF8FFEDFAFEFFBFEFFBFEFFBDFE55F3F -:10153000FFFFFFFFFFBD57FFFF6F77BFF7FBFF7F89 -:10154000BFF7FFFCBFFF9FFFFFEFFFFEFFFFFF1F87 -:10155000CFFFFCFFFFFFFFFB65AFF37CFF3FDFFF2B -:10156000FDE9FE7FE7FFFE7FFFFFFFFFFDE3DFFBFF -:10157000DBF6FDEF5BFBFFDFFCFF3FDFF3FDFF7FF3 -:10158000DFEF66FFDFADEB7ADEF7F7E7D9FD9F67A8 -:10159000D9F67D9FE7DFF547FD655BD6F4FEFFEFEB -:1015A000FF6DF6DDB76DDB76DCB77DFA9BF66D9DE2 -:1015B0006759DFF7DDFFEBFEBFAFEBFAFEBFAFE32E -:1015C000D19FFFBDBFEFFEF7BFBFF7D77FDDF79D10 -:1015D000DF7FDFF7FFE07FFDC1DFF7FDC77F7FFB28 -:1015E000FFBBECFB3EFFBFECFBFFD87FBF6CFFBE39 -:1015F000FFBFEDFFEFFEFBBFEFFBFEFFBFEEFFC542 -:10160000FFAF6FFFFCFD3FE7FFFEFFEFFBFEFFBFFD -:10161000EFFBFEBF89FEFABAFEBFAFFBF6F5D97D40 -:101620009765D9745D9765D3FED6FFBFF7FDFF7F41 -:10163000BFCFFBFEFFEFFBFEFFBFEFFBFFF68FFB15 -:10164000FFEFFB7EDBFEFFBEEFEEFBBEEFBBEEFB74 -:10165000BEFFFFDFFF43FFFFFBEF5FB7FE7FE7F952 -:10166000FE7F9FE7F9FE7FF9BFFEAF77FDFF2FAF4B -:10167000A7FEFFEFFBFEFFBFEFFBFEFFF17FEFDFFB -:10168000FF97F5EFFFDFFFFFBFFFBFFFFFFEFFFF8D -:10169000FFE0FFFFF9FE2F8BE3F8BE779FF9DA77C3 -:1016A0009DE779DE779FDDFFFDFD7F5FD7FDFF7F43 -:1016B000E7FE7F97E7FBFEFFBFEFFFABFFEFFAFE12 -:1016C000BFAFFFFAFFFFDFFFFBFFF7FDFF7FDFFF8D -:1016D00067FFF7F5FFFFFFDFFDFFFFFFFFFFFFFFE6 -:1016E000FFFFFFFFFFEFFFBDEBFFFFF7ADEBFFDFFE -:1016F000FDFF3FDFF7FDFF7FDFFF5FFFF7FFFFFD30 -:10170000BFFFCBF4FF7FD3F7FD3F7FD3F7FFFC3F55 -:10171000FFEAFABEAFABEBBAF4956B52D4AD2F4AE9 -:10172000D2F6BFD27FF73FFFFFF37FFFFFF7FFBA8D -:10173000DFFBFDFFBFFFFBFFF87FEAFFFEFEDFFFE1 -:10174000F7FF7FBBFFFFBFDFFBFFFFBFFFB17FFFE7 -:10175000FBEFFFFFFFFFFFBFCFFEFFFFEFFFF7FF36 -:10176000FFFFF1FF69BEFABFAFE2FFFEFDAFF3FE80 -:10177000FFBFEFFBFCFFFF07FD95DBDF7FDFAFFF68 -:10178000F7AF36FEBF65EBF6FE9F6FFE07FFCFFF9C -:10179000F8FEFFCFFFF6FAE7FBFEFFBBEDF9FFFF18 -:1017A000FF5FFFFFFF75FFEF7EFDE0E85ED3E5F929 -:1017B0003E5FD7F7FFFA2FFBFFFFFFFFFEFFFF7F24 -:1017C0007FD7F57D5F57D5F5EFFFF37FFC7FFFC730 -:1017D000F1FFFF1FCFB0FF3FCFF3FCFF3FCEFFE491 -:1017E000FFDF7FFEF7BBFFFFDFEFEEFFBFEFFBFE8C -:1017F000BFBFEFFFD1FFFFFFFDFBFFFDFFFB9FE939 -:10180000FE7F9FE7F9FE7FBFFFB3FFFFF7FFFFAF4C -:10181000F7FFB63FEBFAFEBFAFEBFAFEBFFEA7FF46 -:10182000FFFFFFFFF7FFFFFFFE9FF7F9FF7F9FE737 -:10183000FFFFFEAF6FFFFFFF9FFFDFFF7D5FDDFF5D -:10184000FBBFE7BBFFFBDF6D5F7EFFFFFFFFFFFF1F -:10185000EBF7FFE7EFF7FFFF7FFFF7FFFC8FFFEFEF -:10186000FDFEFFBEF4F27DD7CFFF3FFFFFFFFFFF7E -:10187000FFCF6BFFBF3FFBF2FC7FEBFF9FFAFFFF49 -:101880003FFFF3FFFFFD70F7FFFFBFFFFBD7FEF544 -:1018900077FF15DD77FDFF7FDFF7FBCDBFFFFDFF96 -:1018A000FFDF37CDF9ECFEEFBBF4FB3F4FB3FFFD9D -:1018B000CBFFE97E549FE54BB7FFDD7DC771DD7738 -:1018C0005DD775CD7FD6FFD3F6F93F6D95AF7FFE1F -:1018D000FFEFFBFEFFBFEFFBFEF6C7FFAD7BCAFFCE -:1018E000BFBFEFFDE3DFB7EDFB7EDF37EDE3FBDFEF -:1018F000FF525C15FDCF7FDFFEEFEFFBFEFFBFEC7D -:101900007BFEFFFE3E7FDAF7FDFF7FFFFFFBEFBBB5 -:101910006FFBFEFFBFEFFBFFF77DFFD8FFFDBF7F33 -:10192000FBFFFF9FFBFE7F9FE7F9FE7F9FEA7FF6AD -:10193000BFBD6A5AF6E5BF775F6DDD775DD775DDB0 -:1019400077FFA5BFCFFBFFFFBFCFFBFDFFBFF3FEC0 -:10195000FFBFEFFBFEFFFDABFFBFBFFFFBFF7FEF56 -:10196000FFBEFBEEFBBEEFBBEEFBBFFFB5FFD0BC87 -:10197000FD2F4BF7FFFF9FF9FE7F9FE7F9FE7F9F4B -:10198000FA8FFDABFADABFAFB3FDFFBFFBFEFFBFBF -:10199000EFFBFEF7BFFF9FFF77F7BDFD77DFFF7E11 -:1019A000DFEDBBFEFFBEEFFBFEFFFA3FFFBE6F8F1A -:1019B000E6F9FE7F9FC7FE7F9FE7F9FE7F9FE7FB6B -:1019C0007FFF7FCFFFFDFFFFDFFBAFBFEFFFFEFF1E -:1019D0009FEFFBFFFCFFFBFEFFFFFFFFFEFFFFF79C -:1019E000FFFFFFFFFFFFFFFFFFF5FFFFFF3FDFF7F9 -:1019F000FFFF7FEFFEFFBFFFFBFFFFBFEFFFB37FE8 -:101A0000FF7B5EF7FDFF7B7FF7FF7FDFF7FDFF7F4B -:101A1000DFF7FF17FFFFFF7FFFFFDDF6FCBFCBF215 -:101A2000BCBF2FCBF2FCBFFE8FFFFA7EBFA7EBDA65 -:101A3000FCBFAF7AFEBFAFEAFAFEBFAFF4DFFEFF36 -:101A4000F33C7F3EFFCFF8BF8FE3F8FE3F8FE7E820 -:101A5000FFFC9FFFFFCFEBB3E7FB7BF3FEFFCFDB8A -:101A6000FBFBBF6F6FDFEC7FFFFFF7FDFDFFFFFFAD -:101A7000FFB2BFFFDEFDBDEFFBF6DFEAE7DBFEBB3B -:101A8000FFEBFBBF9F8FE8FE3F8FA3F8FE3F8FFF6A -:101A9000F87EFDFD7FFFFBCDFFFDFF5FEFFDFFFF4C -:101AA000DFF7FDFFBE90FFFFEEFF3FBFF3BBFEB7CA -:101AB000ABFAFEAFADEAFADEABFF63FFFEF2FFB3B7 -:101AC000FFDFEE7DFF03F1F43F1FC3F1EC7FFE6FFC -:101AD000FFFBFBFF9FFFBFFF7B5FFDFFDFF7FDFD10 -:101AE0007F7FDFFECFFBFFFFAFFBFF1FEFA5FDBF3B -:101AF000DFFB7DFFBFDFFBFFFD3BFFFFFFFFFFFDC8 -:101B0000AFF3FFFB7FBFD7FBBF7FBBF7FFF87FFFC4 -:101B1000FA5FD7FFDF7FEFFFFF7FDBF7FDFF7FDFA0 -:101B2000B7FBECFFFFF7BFEFFDFCFBFFEFF0FE3F65 -:101B30008FE3F8FE3F8FEF8DFFFFEF7FBFFFFBFFCF -:101B4000DBBFFFFFFFFFFFFFFFFFFFEFD8FF2E7F91 -:101B5000BEEFFE6EFFBFF9FFFFF3FFFFFFFFFFFFCA -:101B6000FC66BE47F37FDFFE879FFFFFFFFFE7FFB7 -:101B7000FFFFFFFFFFD66F7CFB4FD2FFFD2BFEFF69 -:101B8000FFFD5FD7D5F57DFFFFFFBF9BFFFFDFB7F1 -:101B9000FFFFDFFF3FCFFE7FBFEFFBFCFF3FFFD923 -:101BA000BFFE97EC8FB7FE9B7DFDB7DD771DC7713C -:101BB000DD775DD7F36FFD3F73DDAFFD7AFFFFAFDC -:101BC000FEFDBFEFFBFEFFBFEF667FFFFFBFBFFF66 -:101BD000FBFFF7DFFDFB7DDFB7CDF37C5F3F913F80 -:101BE000FF3DEF7BFFFCFFCAEFFEFFBDEFFB1EE7F3 -:101BF000BBEC7FB3FFFD9FFFFFFEFFFF7FBFFBFE40 -:101C0000FFBFEFFBEEFBBFDF67FFFFBFEFDBFFBCFC -:101C1000FE7FFBFF9FEFF9FE7F9FE7F9FE87FFEE58 -:101C2000FBBEE5BFEFF9D765F7DDE77DDF775DD771 -:101C30007FF89BFEFFBFEFFBFFFFBFEFFBFF7FCFF8 -:101C4000F3FCFFBFEFFFDB3FEFFBFEFFDFFFFEFB21 -:101C5000BBEFBFEFBBEEFBBEEFBBFFFC7FFD3B5B13 -:101C6000D6E5FD4FC3FBFFBFEFFBFEFFBFEFFBFF62 -:101C7000B4FFFABC8FB2E9D22ECFFBFFBFEFFBFE61 -:101C8000FFBFEFFBFFECFFFDFD7FDFF7E4DF5FFF52 -:101C9000FFFBFFFFFFFFFFFFFFFFC3FFEFE6F8FEC5 -:101CA0003F8B83F9FE7FE7F9FE7F9FE7F9FE7F1701 -:101CB000FDFFFFFF7F5FF72CFFFFFFFE7FFFE7F9D0 -:101CC000FE7F9FFE2FFFFFEFFFFEBFEFADFFFF7F09 -:101CD000FFFFFFFFFFFFFFFFFEDFFFDFFFFDFD7FD9 -:101CE000DFF7FFFFFFFFFFFFFFFFFFFFFFFA3FFEF2 -:101CF000F7FDEF7AFFB1BDFF7FF7FDFF7FDFF7FD57 -:101D0000FF7FF327FFDFFFDDFFFC9BFFCBFCBF2F37 -:101D1000CBF2FCBF2FC9FFDEFFDFAFEBDAFEBBAFBC -:101D2000EBF8F7AFE8FAFEBFAFEBF2FFFDFFFFEF16 -:101D3000BDD7BFFFFFDE8FB8DE378DA378DA3F8FC8 -:101D4000FFA1FFFFFBFBFFFFFFFFA7BDFB76FDBF72 -:101D5000EFDBFEBBBFFE277FFFFEFEFDF5FFEFF5CD -:101D6000DF1FE7FDFF7FDFF7FDFFFFCDFDAEFFFAD1 -:101D70003E3FABFDF87E8FE3F8FE3E8FE3F8FFFEBB -:101D80001FEFDFBFFEDEDFD9FFDFBCFFFF7FFFEF0E -:101D9000FD7FDFF7F93FFEFFFF6FFEDEBFF7EDEAE5 -:101DA000FD8F83F8EA3F8FEFFFF47FFFEFEF7BF3C8 -:101DB000F15FFFFFF13B7FDFF7FDFFFFFFFFE0FF7C -:101DC000FFFFF7FF6FFF7FFFFFF7DEF7BFEFFBF7C8 -:101DD000FDFFFFF5FAFFFFFBE7FFF3F87FF3DFFFFF -:101DE000FFFFFFFFFFFF1FEFBBFFFFFFFFFFFFFD39 -:101DF000FF7FFF9FFFFFFFFFFFFFFFCFFF37FFFFCB -:101E00007FDF775DE7FCFFBFF7F5FBFFFFD7F5FB53 -:101E1000FFFF45FD7FEAFDBEBFDFF7FFFFDBFBFEF7 -:101E2000FFBFEFFFFFFFFB5F7FFFFEFFFFFFFFFF37 -:101E3000FFFEFFEFFDFF7FDFFFEFFBF80FF3FFF982 -:101E40002EFBFEFCF3EFFFFFBFFFFBE7FFFE7EFF75 -:101E5000C06BCFFF34DFF1FDFFEFFFFFFFDFF7FDCA -:101E6000CF7F9CFDFD6CF7FFF6FDEB2B9FFFFCFE8B -:101E70007EFFFFFFFFD7F3F7FFFBE1BFFFEB7ADE4B -:101E8000D7FBFFF9FEFFFFF3DE7FFDE77FFFFDBB22 -:101E9000FFFF7ECCF6AF5F7FFEF47DF7FDBB6EDB10 -:101EA000B7FFF7DF66FFFFF73DCFDEBDFFFFDEDBED -:101EB0008DF77EDFB7EF7FFFF687FFFFEFFEDEBF18 -:101EC000FFFFFFBBEFFDFF7BDEF73FFFBFFBDBFF4D -:101ED000F2B6FDBD7FE7FFFFFF6FF7FFFFFFFE7765 -:101EE000FFBFF8AFFFDFBFFFBF7FFBFFFFFFDBFEE2 -:101EF000FFBFFFFAFFFDFFF67FFF9FFFFF3FEFF8F9 -:101F0000EE7E9FBAFEBF8FEFFEFEF9FFFA7FFE7EE8 -:101F1000BFAFFB96FD9FEF5E65BEEF5BB6FFBEE316 -:101F2000FFB5BFFFFDFF7FFFEFDFFEFFBFFBFEFF43 -:101F3000BFCFFFFFFFFD9BFFFEFBFEDFFF7FFFF735 -:101F4000FEFFDFFBFBFEFFFFFFFFFFB7FEFAFFAB6D -:101F5000EFFFFDB57B7FFBF7FDFFFFDDFFEF8FFFA1 -:101F60002FFFFB7CFF3FDF73EBFE3FFFEFFBFEFF2E -:101F7000EFFDFFBFFD0FFFFFFFF5F9FF7FD7FDFF6F -:101F8000DFFFF7FBFF7FBFFFFFF09FFFFE7F8BE3CD -:101F9000F9DE279BE6BE7F9BC3F8DE7F9DE7FE7FD1 -:101FA000FFFF5FD7FFFFFF4FFBFFFF7FFFAFFF9FED -:101FB0007FFBFFE8FFFFFEBFAFFFFFFEBFEFF7FFB6 -:101FC000BFFFFFFFFFFFF7FFFCFFFFFD7FFFFFFFEE -:101FD000FD3FCFFFFFFFFFF7FFFD7FFFFF93FFFFF9 -:101FE0007ADFF7FFFF7B7FB7EFFFFFFDBFFDFBFF52 -:101FF000F7FFD7FFFFFFFC9F6FCBFFF4BBDFD6FDE2 -:10200000BF2FD3F7FFDFFFCFFFFABEBDAF6ADABE47 -:10201000BBAB3ABE2DAEEBDAF63FADF5DDFFCFF14F -:10202000FFF97FFF73FEFFCFC3F4F72FF3FFFCFF31 -:102030007C1FFF3F4FFF7EFFEFBDF6FEFF2BEFDC67 -:10204000FBFDFFFBFFEA7BFFFFFFFFFFFBF7DFFF6F -:10205000E37DFFB7FFBFFFFFDFFFF8FFBFFFBFEB71 -:10206000E7FAFE3DBFE9FCBFFFFAFBFEFFFFFFD929 -:10207000FFFFFFF67FFFF67DFFDFCFFDBFFBEF7EAB -:10208000FF7FFFFFD3FFFDFBFFFBFFFFFFEFFFBF66 -:10209000FEFFF7EFFFFFFFFBFF87FFFDFFFFFFFFE7 -:1020A0007BFEFFFE3BF7F7FF3FFFFFFFFFFF0FFF4A -:1020B000FFFFFFFBFFFFFFF7FFFFADFFFEF7FFFF97 -:1020C0005FFFFFDFFFFDFFF5FFDFFFBDFFE9FFC79C -:1020D000F3FFFFF7FFF3FFF83BFFFF7BDFBFFBEFF3 -:1020E000FBFFFBF7F7BBFFFFFFFFFBFFFE7FF37F6D -:1020F0005EB7BFFD7FFFF97FFBFFEBFD7F7FFFEF4B -:10210000FBE03FFEBFBFDFFF7EFFF7FFFFFEBFFF2D -:10211000DB78FFFFFFEEA1BFF5DEFBF7FFFBFFFF64 -:10212000FFFFFBFFFFD7FFFFFFFFEFF0FFFFFFF316 -:10213000F7FFEFFFE7CFFFFBFFEFFFFF9F9FEFFCF6 -:1021400016BFFEF3E4FFFFC6FFE7FFFFFDFFBFFF83 -:10215000FF3FFFBFD6AF7FFE6B7E7FFFAFFFFFBFAE -:10216000FF5FFFFEFFFFFEFFFFBDDBFFFE5FF2FF35 -:10217000FF5FFFFFFFFFFFFFEF7FFFFFFFFFDEBF00 -:10218000FFFFEFFB77FEBD7F5FFFFFFFDF6FEDFF20 -:10219000FDFF7FFD6FFFFF77DACFFD5FFFBFFFFF22 -:1021A000DF7FFFFBFFFFFFFF667FFFFEBFE7BFFA9A -:1021B000FFFEFFFFFFDFFF59EFFFEFFB7F89FFFF10 -:1021C000E9FF6FFFF5FFFFFFFFFF7FF2F7FFFFEF74 -:1021D000F87FFBFFFDFFFFD9FFEFBBFFFFFFBFEF66 -:1021E000DEFFFF9F7FDFFFF7FFFFFFFFDFFFFFAF98 -:1021F000FFFFF73FEB9FFE7F9E7F9FFE87FFEDDB9C -:1022000056FFBFAF0BD2FFEFDB6E7DBD6FF8FE3F19 -:10221000FA5BFFFDBFEFFFBF6FDBE6FFFF3FFFDFB6 -:10222000FEFFFFFFFFDA3FFFFBFEFEFFFFDFF7BD14 -:10223000FFFDFFFEFFFBFFFFFFFFF15FFD9FDFFDE7 -:10224000FFFD7FFFFFFFFF76FAFFFF7FE3F8FFAEA2 -:10225000FFFB7E9D73FFFA7FDFFFFF7FFFFBCDFF5C -:102260007FEFFBFFFDFFF77F7FEFFFEDFFFFFFB588 -:10227000FFBFFFBFFDEFDBF7FF93FFEFE2F9BE7F8C -:102280008BE7F9FE6BE7F9FE7F9FE7F9FE7F47FFDB -:10229000FFFDFF9FFFD7FFFFFFFFF5FF9FFFF7FE4B -:1022A000FFBFFE6FFFFFFBFFFFFFAFFFFFFF7FFBE7 -:1022B000FFFEFFFFFFFFFFFDDFFFFFF7FFFFFFDF79 -:1022C000FFFFFF5FFFFFFFFF5FFBFEFFF837FFFF32 -:1022D000EFFF7FFEBFFFFFFEBFFFFF7FFFBFFDFFE2 -:1022E0007FFA7FFFFF6FFFFF7DFFCFFFFFFF4FFFF5 -:1022F000F2FFFFFFFFFFFABFFFAEEBFAFEBBADEB55 -:10230000FAF7AF6BFAF6BF25E9F27F45FFFFFDF75D -:10231000F7BFFFDFFFFFBFFBFFDFF3FFF73FCFFF9D -:10232000A1FFFFBFE7FFFF7FFF3DFFFFFFF7FF2F8D -:10233000FFFBF57FFE57FFFFFFFFFFFFFFFFFFF7EC -:102340003FFFFEFFFFFFFDFEF7EEAFFEEEE7FAFFF9 -:10235000FE9DF95EFEFFEBFFFFDFA7FFFFFFFCDB4B -:10236000FFFFFF7EFBFFFFEFFBFDFFDBFFFFFFEF4C -:10237000FFFFFFFDBFFEBFFF6F7FFFF7FFFFF9FF0E -:10238000F7FFBFDEF7FFFFFFFA7FFDBF5FFFFFBF75 -:10239000FFEDFFF7BFFFFFEFFFDFFFFFFFE6FFFBF4 -:1023A0007FFFFFFFFFFFF7FFFFFFFFFFFFFFEBFFD9 -:1023B000FDFFF5FFF67FDFBDCFFFFFFFFFDFFFFF74 -:1023C000FFF9FFFFFFFFFFE3FFEEBFFF7DEFFEFF23 -:1023D000FFFFBFFFFFFFFFFEFFFFFFFFE7FFB5AE01 -:1023E000FFFFB6FEBFFFFFBFFFFFFFFFFFFFFFFFC7 -:1023F000FF27FFEFFE7FDFFF7EFFFFFFFFFFFFFFF7 -:10240000FFFFFDFFF7F99FFF5FFFFFFFFFFFFF7F6C -:10241000FFFFFEFFFFFFFFFFFFFFFF0FFFE7BFFE16 -:10242000FFBFFFFFFFFFFCBFFFFFFEFFFFFFFFC47B -:102430006BFF291FFBAFFFFFFFFFFFEF1BFEFFFC42 -:102440006FFFFFFD6AF7D7F5BFFFFEFFFFFFFFFF3E -:10245000FEBFFFFFFAFFFFF7FBDDBFFFE7FFFFFF58 -:10246000FFFFFFFFFFFD7FFFFFF5FFFFF7FDB3EF6E -:10247000FD7E5DFFFDFFFFFFFD7FD2F5FB7ECBB74D -:10248000FFFFFFC6FFFDEE63FFFFFFFFFFF6FD65E9 -:102490005BDFFFD5FFFFFFF6E7BFF7A9FFFFEDFF0B -:1024A000FFFFFFFFEBFFFFFFAFFFFFFFF81BFFE3A7 -:1024B000D0BFFFE1FFFFFFFFFFD7FFFFFF5FFFFF81 -:1024C000FFFFAFFFDB76BFFF7FFFBFEFFEFFBFEF7A -:1024D000FBFEFFFFFFBFF27FFF9FFEBDFE7FFFFF02 -:1024E000FFFFFFFFFFFFFFFFFFF73FEC7FF695BB0E -:1024F000EFF8FEFCBF2FDAFCBF2FCBF2FCBFEFFFE3 -:10250000A9BFCFFBFFFFFFFEDDB76DF6D9B66D9B10 -:1025100076D9BFFBFDA3FFBFEFFFEFFFFFFF7FDF1C -:10252000FDEF7BDEF7FDEF7FFFFF05FFFAFE7FEF9C -:10253000E3FFFFFD7FFFFFFFFF5FFFFFFD7FFBAFBF -:10254000FF63C8FFBFEFFFFFFA7FFFFFFFFE9FF7AC -:10255000FFFABFFE9FFB7FFFFFEFD7FFFFF5FFFFF7 -:10256000FFFFFD7FFFFFBFFFF9BFFFBE279FE7F91A -:10257000FE7F8BE7FE7F9FE2F9FE7F9FE7F17FFF03 -:10258000FFFFFBFEFFFFFFD7FFFFFFFFF5FFFFFF92 -:10259000D7FFFAFFFEFFFFFFFDFFFFFFAFF7FFFFD3 -:1025A000FFEBFFFFFFAFFFC4FFF7FFFFEFFFFFFFF2 -:1025B000FF5FFFFFFFFFD7FFFFFFFFFFEBFFFB7A90 -:1025C000DFF7FDFFFFFEBFFFFF7FFFAFFFFFFFF75E -:1025D000EFE3FFDDD2FFDFFFFFF2FCBFCBF6FDBF75 -:1025E0002FCBFF7FDFDEAFFFDAEEBFAFE9FAF4BD3E -:1025F000AF5AAEBBAB6BDADEBFADD75EFFFFBFFC41 -:10260000FFDFFDFFFFFFFFDFF7FFFFFFFFFDFFFA2B -:102610001FFFFEFBEFBFFDFFFDBD77FFFFFFFF9D2F -:10262000EFFFFFFFEF7DFFFBFEEFFFFFFFFFFFF779 -:10263000FFFFFFFFFFFFFFEEBFE4FBFFFE3FFEFFDC -:10264000FFFFFFAFEAFEBFAFEBFAFEFFFFFF55F65D -:10265000FFFEF7FF7FFFEBF75FC5FD7F5FD7F5FF5D -:102660006FFBFF8AFFFFFFFFEBFFFFFFFFFBBFBF1B -:10267000EFFBFFFFFFFFFBFF77DFFBFFFD7FEFFFC0 -:10268000FFFFBF7FFFDFBFFFFBFFFFFFFEEFDFFFAF -:10269000FEFF9FEF7DFFF7FF7FFFFFDFF7FDFFEFFF -:1026A000DFFFDFFFFFFFFFFFFFFFFFFFFDFFFFFB80 -:1026B000FDFFBFDFD1FFF83BFFFFFFFFFFFFFFFF85 -:1026C0007EDBFDFF77DBB77DBFFBFFF87FED7B5E39 -:1026D000FFFEFFFF4FD7FD7FDFD7F5FF7FFFFFFF37 -:1026E000F23FFEFFBFFFFFFFFFBFEFFEFF3BEEFF2E -:1026F000FCEFFFFFFF85FFFDFEFFF5FFFFFEFFDFA5 -:10270000FBFF5FBFFFFDFFFFFFFFA8FFFF9F9EFFD7 -:10271000FFFF7FF3FFFFCFFFF7FDFF7FFFFFFC16FB -:10272000BFCFA3E5EF7FFFF3E4FFCF93FCFF3FCFE5 -:10273000FFFFFFD60F7DBF6EFBF4FCAF6DDB77B7FD -:102740006DDBF6FDBFFFFFFFBF9BFADEB7B7EDF90C -:102750007EB7ACEBD6B3ADEB7ADFFFFFFFD8BFFFA0 -:10276000B7ED9F6FDDF768DB37B36CDB36CDB37F3A -:10277000FF7FF56FFDEF793DF793E47A9EADEA7A3E -:102780009EF7BDEFFFFFFF767FFBC6FFBBEFDAFED4 -:10279000FDBFFBFEFFBFEFFBFFFFFBFFA5FFFDAB98 -:1027A0006F78DE178F79DFFDFF7FDFF7FDFFFFFB1F -:1027B000FFFBFFEFFBEFFBFEFFBBDAF3EF3BCEF3DC -:1027C000BCEF3FCFDFFFB7FFFFFFCF73FFBFEFFFD0 -:1027D000F3FF3FCFF3FCFF3DCF9FFE07FFAFEBFEC4 -:1027E000FDBFEFEBFAFFAFEBFAFEBFAFFBFE3FFB27 -:1027F0009BFF7FDFFFF3FEFFDEF7BF7BDEF7BDEF62 -:102800007BFEFFFFDF3FFEFFB7FFEFF7FFBFEDFEF1 -:10281000DFB7EDFB7EDFFFFFFFFD5FEFEBFAFEF5BD -:10282000BF6FFFFFFFFFFFFFFFFFFFFEF8FFA8FFE7 -:10283000FFBFEFFB6AFBB7EFFBFFBFEFFBFEFFBF86 -:10284000EFFBFFE0FFFFFD7F5CD77DDFF35CF5CDA5 -:10285000735ED7B5FD7FEFFFDBFFFFE2F8BE2F8F82 -:10286000E7F8BE6BE2F8BE2F8BE2F9FE7FE7FFD7F9 -:10287000F5FD7FFFF7F5FD7FD7F5FD7F5FD7F5FF0E -:10288000FFFF8FFFAFEBFAFFFFBFEBFAFF2FEBFA73 -:10289000FEBFAFEBFFFFFE5FFF5FFFFFFDFFFFD758 -:1028A000FFFFFFFFFFFFFFFFFFFFFFFFBFFEB7FDC3 -:1028B000FF7EDFF7ADFF7FF7FDFF7FDFF7FDFF7FD7 -:1028C000F67FFFFFFFDBF6FCAFFFFFFFFFF7FFFF29 -:1028D000FFFFFFFFFFECBFFFAFEBFAF6AB8FEBFAAA -:1028E000F7A5EBFABEBFAFEBFAFF6DFFFF7FDF335B -:1028F000DDFF7FFEF7FC7FFBFFFFFFFFFFFFFFA970 -:10290000FFFDFFFFFEFFFFDFFFFFEFEFFDFF7FFF9C -:10291000FFFFFFFEA7FFFFFF77DFF7FD9F7FFE773B -:10292000EFFFFFFFFFFFFFFFFFAFBFAFFFF9BEBF2E -:102930008FFBFEFEEFFBFEFFBFEFFBFFFFFDDF6F38 -:10294000EFFF7FFFBFBFDFFFFCFFDFF7FDEF7FDFA4 -:10295000FFFFFF3FF6FFCFFFDBFBF7FFEB7AFFFF49 -:10296000FFBFEFFBFFFFFFFE6DFDFF5FFBFFFFF70C -:10297000FF5FF5FFFFFFFFFFFFFFFFFFF8FFFBFF1C -:10298000FFFDFFFFFFFFE7F6BFFFFFFFFFFBFFFFBE -:10299000FFC9FFFFFFBDFFBFAFEFEF3FD1FC7FFBE4 -:1029A000C7FFFFFFFFFFE3FFFFFFFFFDFFFF77FF15 -:1029B000DFB7FDF7FDF7FFFFFFFFFF57FFF7A5FDAF -:1029C0003FDFBFBFFE7FFFFFFFDFFAFDFFFFFFFE20 -:1029D00087FFE9FFFEEFBFEFFEFEFFEFFFFFFFFF08 -:1029E000FFFFFFFFFA9FFF3FFFFDFD57DFFDF3FFF6 -:1029F000DFFDFF5FDFF5FDFFFFF98FFFFFFFEE7FDC -:102A0000FFFFBF5EFEECFB3F7F9FEFF9FFFFCD6B4B -:102A1000FFFFFFC5F3FCFA38FFAF3FEE7F9FFFD902 -:102A2000FFFFFD7AF7FFF3FFAF6FDBF2B9E9FBFFC2 -:102A3000FFFFFEFFFFEFFFFBC5BFFFEFFF5EB7AD80 -:102A4000CD797CFFFFFFFFFFFFFFFFFFFD93FFEF4F -:102A5000EAFEBFEF5BD2CDF56D77DFF7FDFF7FDFDD -:102A6000FFFF66FFD5657D5F759D657FD6FB4FFFD8 -:102A7000FFFFFFFFFFFFF6C7FFBFEFFAFEFFBFEB51 -:102A8000FFDFFF7EFFFFEFFD7ED7FF78DFFF5FDF19 -:102A9000F5BF7FDFC5FF3FF67EFF0FEFF23EBFFFC2 -:102AA000FB3FFFFB7FFFB3FEFBF6FDFFDAF7FDFF09 -:102AB0007FDFF7BFFFFA7FFFFFFFFF9FFFF3DCF928 -:102AC000BFCEE7F9FE7F9FE7FFFFE27FFEFFBFEF8C -:102AD000EBFAFF9F671EFF8FE7F8FE7F8FEFFFBDCA -:102AE000BFFFFBFFFFDFF7FFFCFFBFFFFFFFFFFFA5 -:102AF000FFFFFFFDB3FFFFEFFFFFBFEDFFFBEEFEAC -:102B0000FFFFEFFFFEFFFFFFFFB5FFB7FDFD6EFF0D -:102B1000FFFEFD2FD8FEBF8FEBF9FE3FFFFACFFF80 -:102B2000E7D9FABFDF77FCFB3FABFEFFBFEFFBFE51 -:102B3000FFFFEE1FFFDFF7FFFFFF5F9735BF5EFE72 -:102B4000BFEFFFF7FDFFFFFABFFFBE6F9FE7F8BEC5 -:102B50002F8B66947D9DE7F9FE7F9FE7F17FFFFF56 -:102B6000FFF7F5FD7F5FFBFD9EFFFBFEFFFFEFFF25 -:102B7000FFA0FFFFFFBFEFEBFAFEBFB7F7F7FFFFC6 -:102B8000FDFFFFFFFFFFDDFFFDFFFFFFD7FFFFFFA3 -:102B90007FF5FFFFEFFFFFFFBFFFFFABFEFBFEFF79 -:102BA000F7AFFFFFDEF7EB5FDFF7FDFF7FDFFFFF34 -:102BB000B3FFC9FEFFFFFFFFD6FFFFCBFFFFDFFF25 -:102BC000FFFFFFFFFC8FFFBABEBFAFEB78FEB7ADD4 -:102BD0003AFEB7AFEB7AFEBFAFFF9FFFFFDFFCFF10 -:102BE000FFFEC3FEFFFF33FCFFBFDFF3FFFFBB9F12 -:102BF000FFFFFFEBDFFFFFAFF76FF9BFEFFDFFFF59 -:102C0000FFFFFFE37FFFFFFFFBFFFFBFFDFBF7FFC2 -:102C1000DFF7FFFEEF5FBDFFFAFFF8FFBFAFFBFE80 -:102C2000FE3FEFE8FFDFF3FDFFFFFFFFFFEDFFFBE0 -:102C3000FDFFAFFFFFFEFEBFDBFFFFFFBFFFDFFFBC -:102C4000FDFFCBFFFFFFFFFFBF6FFF7FB7B3FFFFAE -:102C5000DFFFFBEFFFFFFF07FFFBFFFFFFEDFFF5D0 -:102C60007CFF7FFEFFFFEFCFFFFBFFFF2FFFFFFF8C -:102C7000FFF3FFFBFFFEFFFFFFFFFFFFBFFFFFFFB5 -:102C8000FD1BFFFFFFFFFFFFFFFFFE7CFFFFFFFFBE -:102C9000EFFFFFFFFFFBBF7FFDFFFFFFFFFFFFFF1A -:102CA000DBFFFFFFFFFFFFFDFFFFF07FFFFFFFFFE9 -:102CB000FFFFFFFFFFFBFFDFFFFFFFFFFFFDBFFE8B -:102CC0007FFFFFFFFFFFFFFFFFEFFEFFBFFFFFFFE5 -:102CD000FFFFEFFAB5FFFFFFF7F7FFFFFFFFDFFB97 -:102CE000FCFFFFFEFF7FDFBFFFCBBFF9FE7F9FE74B -:102CF000F9FE7F97E1FE799FE7FDFE7FDFFE37FF5C -:102D0000FBDEDEBDEFF3FEFBAFEBFEFFFFCFFFFE12 -:102D1000FFBFFF8FFFEFFBFEFFBFE7F95E7FEFFB1B -:102D2000DAFFBFEFFBFEFFFD1FFFFFFFFFFFFFDF2F -:102D3000FFFF7FFFFFF7FB7FFFFFFFFFFC3FFFBFB2 -:102D4000EFFBFEFFBFEF7B7FBFEFFBFEFFB5EFFBAF -:102D5000BFFA7FFCFF3FCFF3FCFF3FCFBCFF3FEF4D -:102D6000F3FCFE3FCFFFEEEFFBFEFFBFEFFB6AD7AA -:102D7000B7FBF8FFB7EFBAFEFFBF7FE9FFF97E5F51 -:102D800097E5F9FE7FBFF97E5F9FE5FBFE5FB7FF2A -:102D9000A3FFF7FDFF7FDFF7FDFF5EF77DFF77DF26 -:102DA000F7FDFF7FFFD7FFFFFFFFFFFFFDDFFB7F8B -:102DB000FFFFEFFFFEFBFFFFBFFE8FFFDFF7FDFD15 -:102DC0007FDFF7FD3EDFF5BDFF7FDFF7FDF7FF9FFC -:102DD000FFFFFFFFFFFFFFFFFFFDFFBEFFFFFFFF46 -:102DE000FFFFFFFD3FFFDFF7FDFF7FDFF7FDFFCFB9 -:102DF00077FCFF5FDFF7FDFFF47FFFFFFFFFFFFFC3 -:102E0000FFFFFFFFFFFFFFFFFFFDFFFFFFEEFFFFE5 -:102E1000FFFFFFFFFFFFFFFFEDFBFFFFBFFFFFFF18 -:102E2000FFFFE9FFFFFFFFFFFFFBFFFFFFD3FFFFF8 -:102E3000BF3FFBFFFFFFFBF3FFFFFFFFFFFFFFFFB6 -:102E4000FFFFFFFFFFFEFFF7FFFFFFFF17FFFFFF83 -:102E5000DFFFFDFFFFFFFFFFDFDFFFFDFFFFDFF70E -:102E6000FF4FFFFFFFFFFFFFFFFFFFFEFFFFFFFD25 -:102E7000FFFFFFFFFEFF9FFFFFFFFFFFFFFFFFFFC3 -:102E8000FDFFFFFFFFFF7FFFFFFF7A3FFFFFFFFF19 -:102E9000FFFFFF7FFFFFFFFFFFFFFFFFFFFFFFF2CF -:102EA0007FFFFBFEFFBFEFF8FEFFBFFBFEFF8FECD7 -:102EB000FBFEFFBFF8F7FEFFBFEFFBFEFDBFCFEC51 -:102EC000FF3FEFDBF8FFBFCFFFF9FFFFBFFFFBFFC7 -:102ED000FFFFEFFBDFFFFFFFFFFFBFFFFFFFBBFFBA -:102EE000EFFBFEEFBFEEEBFBFEFFEFFEEEBFFEEBF8 -:102EF000FFEFFF17FF7EEBBBFEBFBEFBEF5BF7BD37 -:0A2F0000FBCFBFBFBBFB7ECCEFFF91 -:00000001FF - - * Copyright (C) 1999 BayCom GmbH - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that redistributions of source - * code retain the above copyright notice and this comment without - * modification. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/dabusb/firmware.HEX v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/dabusb/firmware.HEX --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/dabusb/firmware.HEX 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/dabusb/firmware.HEX 1970-01-01 00:00:00.000000000 +0000 @@ -1,649 +0,0 @@ -:02000000215786 -:0300030002016691 -:03000B0002016689 -:0300130002016681 -:03001B0002016679 -:0300230002016671 -:03002B0002016669 -:0300330002030FB6 -:03003B0002016659 -:03004300020100B7 -:03004B0002016649 -:0300530002016641 -:03005B000204BDDF -:0300630002016730 -:03010000020C5A94 -:030104000201ED08 -:030108000202519F -:03010C0002027C70 -:030110000202E404 -:0101140032B8 -:0101180032B4 -:03011C000205FDDC -:03012000020000DA -:03012400020000D6 -:0301280002043C92 -:03012C0002046A60 -:03013000020000CA -:03013400020000C6 -:03013800020000C2 -:03013C00020000BE -:03014000020000BA -:03014400020000B6 -:03014800020000B2 -:03014C00020000AE -:03015000020000AA -:03015400020000A6 -:0A01570075817FE5826003020161FB -:0501610012076F21648C -:010166003266 -:0E016700C0D0C086C082C083C0E0907F97E009 -:0E0175004480F0907F69F0F0F0F0F0F0F0F0D0 -:0E018300F0F0F0F0F0F0F0F0F0F0F0F0F0F04E -:0E019100F0F0F0F0F0F0F0F0F0F0907F97E07A -:03019F00557FF099 -:0E01A200907F9AE030E423907F68F0F0F0F058 -:0E01B000F0F0F0F0F0F0F0F0F0F0F0F0F0F021 -:0E01BE00F0F0F0F0F0F0F0F0F0F0F0F0F0F013 -:0E01CC00E5D8C2E3F5D8D0E0D083D082D0864B -:0301DA00D0D03250 -:0801DD0075860090FFC37C054C -:0701E500A3E582458370F9D8 -:0101EC0022F0 -:0E01ED00C0E0C0F0C082C083C002C003C0D01A -:0E01FB0075D000C086758600E591C2E4F591CE -:0D020900908800E0F541907FAB7402F0900A -:090216007FAB7402F0E5326021B7 -:04021F007A007B00E6 -:0B022300C3EA9418EB64809480501232 -:0E022E00907F69F0F0F0F0F0F0F0F00ABA0006 -:02023C00010BB4 -:02023E0080E35B -:02024000D08666 -:0E024200D0D0D003D002D083D082D0F0D0E054 -:01025000327B -:0E025100C0E0C0F0C082C083C0D075D000C035 -:0E025F0086758600E591C2E4F591907FAB7440 -:04026D0004F0D08643 -:0B027100D0D0D083D082D0F0D0E0329B -:0E027C00C0E0C0F0C082C083C002C003C00456 -:0E028A00C005C006C007C000C001C0D075D0BE -:0D02980000C086758600E591C2E4F59190E6 -:0C02A5007FAB7408F0756E00756F0212DC -:0602B1001144757039755F -:0602B700710C75720212C9 -:0C02BD001175907FD6E4F075D820D08633 -:0E02C900D0D0D001D000D007D006D005D00490 -:0D02D700D003D002D083D082D0F0D0E0322E -:0E02E400C0E0C0F0C082C083C0D075D000C0A2 -:0E02F20086758600E591C2E4F591907FAB74AD -:0403000010F0D086A3 -:0B030400D0D0D083D082D0F0D0E03207 -:0E030F00C0E0C0F0C082C083C002C003C004C2 -:0E031D00C005C006C007C000C001C0D075D02A -:0C032B0000C086758600756E00756F02BC -:0703370012114475704075BE -:06033E00710C7572021241 -:0E0344001175907FD67402F0907FD67406F08B -:0503520075D810D086F3 -:0E035700D0D0D001D000D007D006D005D00401 -:0D036500D003D002D083D082D0F0D0E0329F -:0D037200907FA57480F0907FA6749AF01221 -:0C037F00101B907FA6E542F012101B90AE -:0D038B007FA6E543F012101B907FA5744083 -:01039800F074 -:010399002241 -:0D039A00907FA57480F0907FA6749AF012F9 -:0C03A700101B907FA6E544F012101B9084 -:0C03B3007FA6E545F012101B907FA6E528 -:0B03BF0046F012101B907FA57440F068 -:0103CA002210 -:0A03CB0075440275450075460012E6 -:0903D500039A75420375430012FE -:0203DE000372A8 -:0103E00022FA -:0C03E100908800E536F09088007410252C -:0903ED0036F01201DD75420175C4 -:0903F600431812037275440275EC -:0903FF00450075460012039A75D1 -:08040800420375434412037224 -:0104100022C9 -:0E041100C0E0C0F0C082C083C0D075D000C073 -:0E041F0086758600E591C2E4F591907FAA747F -:04042D0002F0D08683 -:0B043100D0D0D083D082D0F0D0E032D9 -:0E043C00C0E0C0F0C082C083C0D075D000C048 -:0E044A0086758600E591C2E4F591907FA97455 -:0704580004F0753001D086AD -:0B045F00D0D0D083D082D0F0D0E032AB -:0E046A00C0E0C0F0C082C083C0D075D000C01A -:0E04780086758600E591C2E4F591907FAA7426 -:0704860004F0753101D0867E -:0B048D00D0D0D083D082D0F0D0E0327D -:0E049800C0E0C0F0C082C083C0D075D000C0EC -:0C04A60086758600E591C2E5F591D086D0 -:0B04B200D0D0D083D082D0F0D0E03258 -:0E04BD00C0E0C0F0C082C083C0D075D000C0C7 -:0C04CB0086758600E591C2E7F591D086A9 -:0B04D700D0D0D083D082D0F0D0E03233 -:0C04E200907FEAE0FA8A20907F96E4F018 -:0104EE0022EB -:0704EF00907FEAE0FA8A2188 -:0104F60022E3 -:0E04F700901713E0FA901715E0FB74802AFAB4 -:0E05050074802BFBEA0303543FFCEAC423542A -:0E0513001FFA2CFAEB0303543FFCEBC42354F5 -:0B0521001FFB2CFB90170AE0FC60029F -:02052C007A0053 -:07052E0090170CE0FC6002D5 -:020535007B0049 -:0B053700EA2BFCC313F53A7544028B5D -:07054200458A4612039A7579 -:090549006E08756F001211447573 -:040552007047757108 -:080556000C757202121175858B -:05055E003A731211A028 -:010563002275 -:0E056400907F96E0FA907F9674806502F0908A -:0E0572007FEBE0FA907FEAE0FB907FEFE0FC89 -:0E0580003395E0FD8C057C00907FEEE0FE33AD -:0E058E0095E0FFEC2EFCED3FFD907FE9E0FED6 -:05059C00BE0102800316 -:0305A1000205F957 -:0605A400BC0121BD001E98 -:0E05AA00EAC40354F8FCEB25E0FD2C2400FC11 -:0E05B800E43417FD907EC0E0FE8C828D83F04F -:0205C600803182 -:0E05C800EAC40354F8FAEB25E0FB2AFA2400FB -:0E05D600FBE43417FC907EC0E0FD8B828C832A -:0E05E400F074012A2400FAE43417FB907EC163 -:0705F200E0FC8A828B83F01C -:0305F90075380151 -:0105FC0022DC -:0E05FD00C0E0C0F0C082C083C002C003C004D2 -:0E060B00C005C006C007C000C001C0D075D039 -:0D06190000C086758600E591C2E4F5919061 -:0D0626007FAA7401F0120564753700D086BC -:0E063300D0D0D001D000D007D006D005D00422 -:0D064100D003D002D083D082D0F0D0E032C0 -:0E064E00907FEBE0FA907FEAE0FB907FEEE019 -:0E065C00FC3395E0FD907F96E0FE907F967453 -:0E066A00806506F0907F007401F0EAC403542E -:0E067800F8FEEB25E0FB2EFE2400FBE4341719 -:0E068600FF8B828F83E0FB74012E2400FEE4C4 -:0E0694003417FF8E828F83E0FE907FE9E0FF37 -:0306A200BF810A0B -:0A06A500907F00EBF0907F01EEF073 -:0806AF00907FE9E0FBBB821A19 -:0306B700BA010C79 -:0C06BA00907F00E4F0907F01E4F0800BE2 -:0B06C600907F00E4F0907F0174B5F01D -:0806D100907FE9E0FBBB831BF5 -:0306D900BA010D56 -:0D06DC00907F007401F0907F01E4F0800B2E -:0B06E900907F00E4F0907F017412F09D -:0806F400907FE9E0FBBB841CD0 -:0306FC00BA010D33 -:0D06FF00907F007401F0907F01E4F0800C0A -:0C070C00907F007480F0907F017401F079 -:05071800907FB5ECF03C -:01071D0022B9 -:0C071E0075360D908800741DF0756B801E -:0A072A00756C3C1210E2756B8075CF -:090734006C0F1210E2756B807568 -:09073D006C061210E2756B807568 -:070746006C011210E27A00C1 -:03074D00BAFF00F0 -:02075000500A4D -:0A075200C0021201DDD0020A80F19E -:0A075C00756B80756C3C1210E2759D -:080766006B80756C0F1210E2AC -:01076E002268 -:0E076F00907FA1E4F0907FAF7401F0907F9234 -:0E077D007402F0758E3175892175880075C87B -:0E078B0000758D4075984075C04075870075EB -:0907990020007521007522007595 -:0507A200230075470073 -:0707A700C3E5479420501147 -:0D07AE00E5472400F582E43417F583E4F0FC -:0407BB00054780E886 -:0907BF00E4F540F53FE4F53CF5DA -:0707C8003BE4F53EF53D7531 -:0B07CF003200753700753900907F93F1 -:0E07DA00743CF0907F9C74FFF0907F967480CA -:0E07E800F0907F947470F0907F9D748FF0906D -:0E07F6007F97E4F0907F9574C2F0907F987426 -:0E08040028F0907F9E7428F0907FF0E4F09032 -:0E0812007FF1E4F0907FF2E4F0907FF3E4F0E9 -:0E082000907FF4E4F0907FF5E4F0907FF6E432 -:0E082E00F0907FF7E4F0907FF8E4F0907FF90F -:0E083C007438F0907FFA74A0F0907FFB74A0E7 -:0E084A00F0907FFC74A0F0907FFD74A0F09001 -:0E0858007FFE74A0F0907FFF74A0F0907FE010 -:0E0866007403F0907FE17401F0907FDD7480E8 -:0B087400F012124312071E7A007B00F6 -:09087F00C3EA941EEB940050172B -:0C088800908800E0F54790880BE0F547F1 -:09089400907F68F00ABA00010B24 -:02089D0080E0F9 -:0C089F001203E1907FD6E4F07A007B00A9 -:0D08AB008A048B05C3EA94E0EB942E501AEA -:0E08B800C002C003C004C0051201DDD005D08F -:0A08C60004D003D0020ABA00010BAF -:0208D00080D9CD -:0D08D200907FD67402F0907FD67406F090EF -:0E08DF007FDE7405F0907FDF7405F0907FAC33 -:0E08ED00E4F0907FAD7405F075A88075F810EA -:0D08FB00907FAE740BF0907FE27488F09057 -:0C0908007FAB7408F075E81175320175C2 -:0C0914003100753000C004C0051204F76B -:0A092000D005D004753400753501D0 -:0D092A00907FAE7403F08C02BA00028003CF -:03093700020A3F72 -:0C093A00853334907F9D748FF0907F9780 -:0E0946007408F0907F9D7488F0907F9AE0FA1C -:0C09540074055AF533907F9D748FF0906D -:0D0960007F977402F0907F9D7482F0E53364 -:0D096D0025E0FA907F9AE05405FB4AF5332F -:02097A00600C0F -:0C097C00907F96E0FA907F9674804AF01D -:0B098800756E00756F00C004C0051202 -:0E0993001144D005D004901713E0FA74802AA6 -:0609A100FAE533B404295D -:0309A700BAA000F3 -:0209AA005024D7 -:0D09AC00901713E004FB0B901713EBF09075 -:0E09B9001713E0FB901715F0C002C004C00534 -:0909C7001204F7D005D004D0029F -:0509D000E533B402262E -:0609D500C374049A5020D7 -:0D09DB00901713E0FA1A1A901713EAF09023 -:0D09E8001713E0FA901715F0C004C00512B7 -:0609F50004F7D005D00458 -:0509FB00E533B4081D06 -:040A0000E534701950 -:0A0A040074012535540FF5358535D2 -:0C0A0E0075757600C004C0051213FED000 -:030A1A0005D00400 -:050A1D00E533B4011DEA -:040A2200E53470192E -:0A0A2600E53524FF540FF535853542 -:0C0A300075757600C004C0051213FED0DE -:030A3C0005D004DE -:0E0A3F00C004C0051201DDD005D004907F96E2 -:0E0A4D00E0FA907F96747F5AF0907F977408BD -:0A0A5B00F0C3EC9400ED9402400893 -:080A6500907F96E0FA20E608FC -:080A6D00C3E49C74089D5013C2 -:0E0A7500907F96E0FA907F9674406502F07CC8 -:050A8300007D0080056C -:050A88000CBC00010D93 -:050A8D00E538B4010E84 -:0D0A9200C004C0051204F7D005D00475386B -:010A9F000056 -:070AA000E531700302092A91 -:0A0AA700907FC9E0FA7003020C2DE5 -:0E0AB100907F96E0FA907F9674806502F09038 -:090ABF007DC0E0FABA2C028003AC -:030AC800020B36E8 -:050ACB007532007B0004 -:030AD000BB640004 -:020AD300501CB5 -:0E0AD500C002C003C004C0051201DDD005D070 -:0D0AE30004D003D00290880FE0F5470B808F -:010AF000DF26 -:0D0AF100C002C004C00512071E1203E1126E -:0C0AFE0004F7D005D004D002756E00751E -:0D0B0A006F01C002C004C005121144D005E7 -:090B1700D004D00275704D757117 -:0B0B20000C757202C002C004C0051278 -:0B0B2B001175D005D004D002020C2D83 -:030B3600BA2A3B9D -:0D0B3900907F987420F0C002C004C0051227 -:0E0B460001DDD005D004D002907F987428F015 -:020B54007B0024 -:030B5600BB0A00D7 -:050B59004003020C2D19 -:0E0B5E00C002C003C004C0051201DDD005D0E6 -:080B6C0004D003D0020B80E26B -:030B7400BA2B1A7F -:080B7700907FC9E0FBBB4012B6 -:0E0B7F00C002C004C005121205D005D004D07B -:040B8D0002020C2D27 -:030B9100BA101F78 -:0E0B9400907F96E0FB907F9674806503F0C022 -:0E0BA20002C004C00512103DD005D004D002E0 -:030BB000020C2D07 -:030BB300BA111262 -:0E0BB600C002C004C00512106AD005D004D0E1 -:040BC40002020C2DF0 -:030BC800BA12124C -:0E0BCB00C002C004C00512108FD005D004D0A7 -:040BD90002020C2DDB -:030BDD00BA130B3D -:0B0BE000907DC1E0FB908800F0804297 -:030BEB00BA141128 -:0E0BEE00C002C004C0051211DDD005D004D035 -:030BFC0002802E46 -:030BFF00BA151D07 -:0C0C0200907DC1E0F575907DC2E0F576B4 -:0E0C0E00C002C004C0051213FED005D004D0F1 -:030C1C0002800E45 -:030C1F00BA160BF7 -:0B0C2200C004C0051213A3D005D004CD -:0B0C2D00907FC9E4F075310002092A35 -:010C38002299 -:070C3900535550454E4400E5 -:070C4000524553554D4500DC -:060C470020566F6C200036 -:0D0C4D004441425553422076312E30300094 -:0E0C5A00C0E0C0F0C082C083C002C003C0046E -:0E0C6800C005C006C007C000C001C0D075D0D6 -:0D0C760000C086758600E591C2E4F59190FE -:0E0C83007FAB7401F0907FE8E0FA907FE9E02B -:060C9100FBBB0002800322 -:030C9700020D3813 -:030C9A00BA801409 -:0E0C9D00907F007401F0907F01E4F0907FB52D -:060CAB007402F0020ECD00 -:050CB100BA820280037D -:030CB600020D1D0F -:080CB900907FECE0FCBC01009F -:020CC1004021D0 -:060CC300C374079C401BF6 -:0E0CC900EC24FF25E0FD24C6F582E4347FF51F -:0D0CD70083E0FD530501907F00EDF0802BC0 -:030CE400BC8100D0 -:020CE7004021AA -:060CE900C374879C401B50 -:0E0CEF00EC247F25E0FC24B6F582E4347FF58A -:0D0CFD0083E0FC530401907F00ECF08005C3 -:050D0A00907F00E4F001 -:0E0D0F00907F01E4F0907FB57402F0020ECDEB -:050D1D00BA8102800311 -:030D2200020EC5F9 -:0E0D2500907F00E4F0907F01E4F0907FB574C1 -:050D330002F0020ECDEC -:030D3800BB012DCF -:060D3B00BA0003020ECD18 -:030D4100BA0211E2 -:0D0D4400755900C002C003120EF0D003D09C -:040D510002020ECDBF -:050D5500BA2102800339 -:030D5A00020ECDB9 -:0B0D5D00753701907FC5E4F0020ECD59 -:030D6800BB031FAB -:060D6B00BA0003020ECDE8 -:050D7100BA020280033C -:030D7600020ECD9D -:0D0D7900755901C002C003120EF0D003D066 -:040D860002020ECD8A -:030D8A00BB065451 -:050D8D00BA80028003A2 -:030D9200020EC589 -:080D9500907FEBE0FCBC0115AE -:0C0D9D007CFB7D0F8D067F00907FD4EE64 -:090DA900F0907FD5ECF0020ECDB4 -:0A0DB200907FEBE0FCBC020280031E -:030DBC00020EC55F -:0A0DBF00907FEAE0FCBC0002800314 -:030DC900020EC552 -:0C0DCC007C3B7D0F8D067F00907FD4EEF5 -:090DD800F0907FD5ECF0020ECD85 -:060DE100BB0703020EC572 -:030DE700BB081036 -:0D0DEA00AC48907F00ECF0907FB57401F0F4 -:030DF700020ECD1C -:030DFA00BB093101 -:050DFD00BA00028003B2 -:030E0200020EC518 -:0E0E0500907FEAE0FCC374019C5003020EC50E -:080E1300907FEAE0FCBC000A3C -:0A0E1B00901721E4F0901722E4F094 -:090E2500907FEAE0F548020ECDD1 -:030E2E00BB0A27D5 -:050E3100BA81028003FC -:030E3600020EC5E4 -:0E0E3900907FECE0FA2420FAE43417FC8A8261 -:0E0E47008C83E0FA907F00F0907FB57401F08C -:030E5500020ECDBD -:050E5800BB0B0280034A -:030E5D00020EA9D9 -:0D0E6000901720E4F0907FECE0FABA011A40 -:080E6D00907FEDE0FABA0012DB -:0E0E7500907FEAE0FA901721F0C0031204E229 -:040E8300D0038046D2 -:080E8700907FECE0FABA023E94 -:080E8F00907FEDE0FABA003695 -:0D0E9700C0031204EFD003907FEAE0FA9050 -:050EA4001722F080247C -:050EA900BB12028017DE -:050EAE00BB8102800D74 -:050EB300BB8302800872 -:050EB800BB8202800373 -:030EBD00BB8405EE -:050EC00012064E80083F -:080EC500907FB47403F0800675 -:060ECD00907FB47402F0F6 -:020ED300D086C7 -:0E0ED500D0D0D001D000D007D006D005D00478 -:0D0EE300D003D002D083D082D0F0D0E03216 -:0B0EF000907FECE0F55AC39401401D18 -:070EFB00C37407955A40166D -:0D0F0200E55A24FF25E0FA24C6F582E43408 -:090F0F007FF583AA59EAF0802263 -:070F1800C3E55A9481401B60 -:070F1F00C37487955A4014CA -:0D0F2600E55A24FF25E0FA24B6F582E434F4 -:070F33007FF583AA59EAF0E3 -:010F3A002294 -:0E0F3B000902BA000301004000090400000092 -:0E0F49000101000009240100013D0001010C1E -:0E0F570024020110070002030000000D240612 -:0E0F650003010215000300030000092403022B -:0E0F7300010100010009240304020300030031 -:0E0F8100092403050306000100090401000015 -:0E0F8F00010200000904010101010200000737 -:0E0F9D002401020101000B24020102021001D6 -:0E0FAB0080BB00090588050001010000072534 -:0E0FB900010000000009040200020000000018 -:0E0FC7000705820240000007050202400000FC -:0E0FD50009040201030000000007058202402B -:0E0FE30000000705020240000009058905A074 -:0A0FF1000101000000FFFFFFFF00F8 -:0E0FFB00120100010000004047059999000115 -:0E10090000000001000000000000000902BA13 -:0410170000030100D1 -:02101B007A0059 -:03101D00BA050011 -:02102000501767 -:08102200907FA5E0FB30E00522 -:05102A00900001800DA3 -:0A102F00C0021201DDD0020A80E4C5 -:0310390090000123 -:01103C002291 -:0E103D00907DC1E0F9A3E0FAA3E0FB7C007D0A -:04104B007EEB6012C6 -:0E104F0089828A83E0A3A982AA838C828D8382 -:04105D00F00CDBEECA -:08106100907DC3E0907FB9F01F -:011069002264 -:0E106A00907DC1E0F9A3E0FAA3E0FB7CC47D19 -:041078007DEB60E5C7 -:0E107C008C828D83E00C89828A83F0A3A98286 -:04108A00AA83DBEE6C -:01108E00223F -:0E108F00907FA57480F00586907DC1E00586F7 -:0E109D00A3F012101B907FA60586A3A3E0F916 -:0510AB006016A305869C -:0D10B000907FA60586E0A30586F0C0011222 -:0610BD00101BD001D9ED6B -:0610C300907FA57440F0CF -:0110C9002204 -:0810CA009088027401F07A0025 -:0310D200BAFF0062 -:0210D500500ABF -:0A10D700C0021201DDD0020A80F110 -:0110E10022EC -:0510E200E56BB4C0083D -:0810E700908803E56CF080061F -:0610EF00908802E56CF0A0 -:0410F5007A007B0002 -:0B10F900C3EA9432EB6480948050073F -:051104000ABA00010B16 -:0211090080EE76 -:01110B0022C1 -:0A110C00908803E56DF005397A00C4 -:03111600BA2800F4 -:02111900500381 -:03111B000A80F84F -:05111E00E539B41008E2 -:0811230090880274C0F0800EF8 -:05112B00E539B42009C4 -:091130009088027480F07539000A -:021139007A003A -:03113B00BA2800CF -:02113E0050035C -:031140000A80F82A -:011143002289 -:04114400E56F6002F1 -:0211480080071E -:07114A007A007539008005F1 -:051151007A4075391021 -:09115600E56E2AFAE56E2539F573 -:0A115F003990880274802AF07A00AB -:08116900C3EA648094A850035E -:031171000A80F5FC -:011174002258 -:06117500AA70AB71AC7220 -:0C117B008A828B838CF01214EEFD601849 -:0D1187008D6DC002C003C00412110CD00415 -:09119400D003D0020ABA00010BDD -:02119D0080DCF4 -:01119F00222D -:0D11A000E573C4540FFA53020FC374099A8B -:0211AD005006EA -:0611AF0074372AFB8004E6 -:0411B50074302AFB6D -:0C11B9008B6DC00312110CD003AA7353FD -:0811C500020FC374099A5006E1 -:0611CD0074372AFB8004C8 -:0411D30074302AFB4F -:0511D7008B6D12110CEC -:0111DC0022F0 -:0711DD00907DC3E0FA600FF2 -:0C11E400907DC1E0F56E907DC2E0F56FDB -:0311F00012114495 -:0C11F300907DFFE4F07570C475717D758F -:0511FF007201121175E0 -:0112040022C7 -:021205007A0469 -:03120700BA4000EA -:02120A0050365C -:0E120C00EA24C0F582E4347DF583E0FB7C002B -:03121A00BC08000D -:02121D0050205F -:06121F008B05ED30E70B2A -:0B122500907F967442F074C3F08008C4 -:08123000907F96E4F07481F058 -:07123800EB25E0FB0C80DB5D -:03123F000A80C55D -:011242002289 -:041243007A007BEFC3 -:03124700BA1000DA -:02124A00502032 -:0E124C0074112BFB2400FCE43418FD8C828D01 -:0E125A0083E4F0EA2400F582E43419F583E41D -:04126800F00A80DB2D -:01126C00225F -:0E126D0074F82400F58274033484F583E4F0F1 -:0E127B0074F92400F58274033484F583E4F0E2 -:0E12890074FA2400F58274033484F583E4F0D3 -:0E12970074FB2400F58274033484F583E4F0C4 -:0E12A50074FF2400F58274033484F583E4F0B2 -:0112B3002218 -:0E12B4001203CB12126D7AC07B877C0174018D -:0E12C2002AFDE43BFE8C078A828B838CF0743D -:0E12D000011214BF2DFAE43EFB8F048D828EB6 -:0E12DE00838FF074061214BF74012AFDE43BE6 -:0E12EC00FE8C078A828B838CF0E41214BF7490 -:0E12FA00012DFAE43EFB8F048D828E838FF06F -:0E130800740B1214BF74012AFDE43BFE8C0727 -:0E1316008A828B838CF074081214BF74012D30 -:0E132400FAE43EFB8F048D828E838FF07401FD -:0E1332001214BF2AFDE43BFE8C078A828B83D7 -:0E1340008CF0E41214BF74012DFAE43EFB8F12 -:0E134E00048D828E838FF074031214BF7D0015 -:03135C00BD0600CB -:02135F0050122A -:0B1361008A828B838CF00ABA00010B1B -:07136C00E41214BF0D80E93B -:0D1373008A828B838CF0E5741214BF74F92C -:0E1380002400F58274033484F583740FF07436 -:0E138E00FE2400F58274033484F5837401F0AC -:06139C001203E11204F748 -:0113A2002228 -:0D13A300907DC1E0FA2400FBE43419FC90B9 -:0E13B0007DC2E0FD8B828C83F075F011EAA403 -:0313BE00FA7B00B7 -:0313C100BB10005E -:0213C4005024B3 -:0E13C600EA2400FCE43418FDEB2CFCE43DFDB1 -:0E13D40074042B24C0F582E4347DF583E0FE22 -:0813E2008C828D83F00B80D793 -:0E13EA00EA2400FAE43418FB74102AF582E4B9 -:0513F8003BF583E4F069 -:0113FD0022CD -:0413FE00E57660022E -:02140200801652 -:0C140400740F5575FA8A752400F582E417 -:0A1410003419F583E0F5741212B4EC -:0A141A001210CA756E00756F001203 -:0614240011447570B9755A -:06142A007114757202123C -:0B1430001175E576B402047401800120 -:01143B00E4CC -:03143C00FA700F34 -:0C143F0074012575F573C0021211A0D0D5 -:03144B0002800A12 -:0A144E00857573C0021211A0D002D0 -:0C145800756E00756F01C002121144D0C7 -:0414640002EA701A0E -:0D14680075F011E575A4FA2400FAE43418BB -:09147500FB8A708B717572011283 -:04147E00117580362E -:021482007A00EE -:03148400BA10009B -:02148700502FE4 -:0D148900EA2400F582E43419F583E0FBE568 -:0414960075B5031B0A -:0E149A0075F011EAA4FB2400FBE43418FC8B6F -:0914A800708C71757201C0021212 -:0414B1001175D002DF -:0314B5000A80CCDE -:0114B8002211 -:0614B90050726F67200075 -:0E14BF00C8C0E0C8C0E0E5F0600B14600F1478 -:0714CD00601114601280158C -:0714D400D0E0A882F6800EB3 -:0514DB00D0E0F08009E3 -:0414E000D0E08005D3 -:0514E400D0E0A882F237 -:0414E900C8D0E0C8BF -:0114ED0022DC -:0E14EE00C8C0E0E5F0600D14600F14600F142C -:0614FC00601074FF800F78 -:05150200A882E6800A4A -:03150700E080077A -:04150A00E4938003E3 -:03150E00A882E2CE -:04151100F8D0E0C866 -:0115150022B3 -:00000001FF - - * Copyright (C) 1999 BayCom GmbH - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that redistributions of source - * code retain the above copyright notice and this comment without - * modification. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/ihex2fw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/ihex2fw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/ihex2fw.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/ihex2fw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,280 +0,0 @@ -/* - * Parser/loader for IHEX formatted data. - * - * Copyright © 2008 David Woodhouse - * Copyright © 2005 Jan Harkes - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define _GNU_SOURCE -#include - - -struct ihex_binrec { - struct ihex_binrec *next; /* not part of the real data structure */ - uint32_t addr; - uint16_t len; - uint8_t data[]; -}; - -/** - * nybble/hex are little helpers to parse hexadecimal numbers to a byte value - **/ -static uint8_t nybble(const uint8_t n) -{ - if (n >= '0' && n <= '9') return n - '0'; - else if (n >= 'A' && n <= 'F') return n - ('A' - 10); - else if (n >= 'a' && n <= 'f') return n - ('a' - 10); - return 0; -} - -static uint8_t hex(const uint8_t *data, uint8_t *crc) -{ - uint8_t val = (nybble(data[0]) << 4) | nybble(data[1]); - *crc += val; - return val; -} - -static int process_ihex(uint8_t *data, ssize_t size); -static void file_record(struct ihex_binrec *record); -static int output_records(int outfd); - -static int sort_records = 0; -static int wide_records = 0; -static int include_jump = 0; - -static int usage(void) -{ - fprintf(stderr, "ihex2fw: Convert ihex files into binary " - "representation for use by Linux kernel\n"); - fprintf(stderr, "usage: ihex2fw [] \n"); - fprintf(stderr, " -w: wide records (16-bit length)\n"); - fprintf(stderr, " -s: sort records by address\n"); - fprintf(stderr, " -j: include records for CS:IP/EIP address\n"); - return 1; -} - -int main(int argc, char **argv) -{ - int infd, outfd; - struct stat st; - uint8_t *data; - int opt; - - while ((opt = getopt(argc, argv, "wsj")) != -1) { - switch (opt) { - case 'w': - wide_records = 1; - break; - case 's': - sort_records = 1; - break; - case 'j': - include_jump = 1; - break; - return usage(); - } - } - - if (optind + 2 != argc) - return usage(); - - if (!strcmp(argv[optind], "-")) - infd = 0; - else - infd = open(argv[optind], O_RDONLY); - if (infd == -1) { - fprintf(stderr, "Failed to open source file: %s", - strerror(errno)); - return usage(); - } - if (fstat(infd, &st)) { - perror("stat"); - return 1; - } - data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, infd, 0); - if (data == MAP_FAILED) { - perror("mmap"); - return 1; - } - - if (!strcmp(argv[optind+1], "-")) - outfd = 1; - else - outfd = open(argv[optind+1], O_TRUNC|O_CREAT|O_WRONLY, 0644); - if (outfd == -1) { - fprintf(stderr, "Failed to open destination file: %s", - strerror(errno)); - return usage(); - } - if (process_ihex(data, st.st_size)) - return 1; - - return output_records(outfd); -} - -static int process_ihex(uint8_t *data, ssize_t size) -{ - struct ihex_binrec *record; - uint32_t offset = 0; - uint32_t data32; - uint8_t type, crc = 0, crcbyte = 0; - int i, j; - int line = 1; - int len; - - i = 0; -next_record: - /* search for the start of record character */ - while (i < size) { - if (data[i] == '\n') line++; - if (data[i++] == ':') break; - } - - /* Minimum record length would be about 10 characters */ - if (i + 10 > size) { - fprintf(stderr, "Can't find valid record at line %d\n", line); - return -EINVAL; - } - - len = hex(data + i, &crc); i += 2; - if (wide_records) { - len <<= 8; - len += hex(data + i, &crc); i += 2; - } - record = malloc((sizeof (*record) + len + 3) & ~3); - if (!record) { - fprintf(stderr, "out of memory for records\n"); - return -ENOMEM; - } - memset(record, 0, (sizeof(*record) + len + 3) & ~3); - record->len = len; - - /* now check if we have enough data to read everything */ - if (i + 8 + (record->len * 2) > size) { - fprintf(stderr, "Not enough data to read complete record at line %d\n", - line); - return -EINVAL; - } - - record->addr = hex(data + i, &crc) << 8; i += 2; - record->addr |= hex(data + i, &crc); i += 2; - type = hex(data + i, &crc); i += 2; - - for (j = 0; j < record->len; j++, i += 2) - record->data[j] = hex(data + i, &crc); - - /* check CRC */ - crcbyte = hex(data + i, &crc); i += 2; - if (crc != 0) { - fprintf(stderr, "CRC failure at line %d: got 0x%X, expected 0x%X\n", - line, crcbyte, (unsigned char)(crcbyte-crc)); - return -EINVAL; - } - - /* Done reading the record */ - switch (type) { - case 0: - /* old style EOF record? */ - if (!record->len) - break; - - record->addr += offset; - file_record(record); - goto next_record; - - case 1: /* End-Of-File Record */ - if (record->addr || record->len) { - fprintf(stderr, "Bad EOF record (type 01) format at line %d", - line); - return -EINVAL; - } - break; - - case 2: /* Extended Segment Address Record (HEX86) */ - case 4: /* Extended Linear Address Record (HEX386) */ - if (record->addr || record->len != 2) { - fprintf(stderr, "Bad HEX86/HEX386 record (type %02X) at line %d\n", - type, line); - return -EINVAL; - } - - /* We shouldn't really be using the offset for HEX86 because - * the wraparound case is specified quite differently. */ - offset = record->data[0] << 8 | record->data[1]; - offset <<= (type == 2 ? 4 : 16); - goto next_record; - - case 3: /* Start Segment Address Record */ - case 5: /* Start Linear Address Record */ - if (record->addr || record->len != 4) { - fprintf(stderr, "Bad Start Address record (type %02X) at line %d\n", - type, line); - return -EINVAL; - } - - memcpy(&data32, &record->data[0], sizeof(data32)); - data32 = htonl(data32); - memcpy(&record->data[0], &data32, sizeof(data32)); - - /* These records contain the CS/IP or EIP where execution - * starts. If requested output this as a record. */ - if (include_jump) - file_record(record); - goto next_record; - - default: - fprintf(stderr, "Unknown record (type %02X)\n", type); - return -EINVAL; - } - - return 0; -} - -static struct ihex_binrec *records; - -static void file_record(struct ihex_binrec *record) -{ - struct ihex_binrec **p = &records; - - while ((*p) && (!sort_records || (*p)->addr < record->addr)) - p = &((*p)->next); - - record->next = *p; - *p = record; -} - -static int output_records(int outfd) -{ - unsigned char zeroes[6] = {0, 0, 0, 0, 0, 0}; - struct ihex_binrec *p = records; - - while (p) { - uint16_t writelen = (p->len + 9) & ~3; - - p->addr = htonl(p->addr); - p->len = htons(p->len); - if (write(outfd, &p->addr, writelen) != writelen) - return 1; - p = p->next; - } - /* EOF record is zero length, since we don't bother to represent - the type field in the binary version */ - if (write(outfd, zeroes, 6) != 6) - return 1; - return 0; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/ttusb-budget/dspbootcode.bin.ihex v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/ttusb-budget/dspbootcode.bin.ihex --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/ttusb-budget/dspbootcode.bin.ihex 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/ttusb-budget/dspbootcode.bin.ihex 1970-01-01 00:00:00.000000000 +0000 @@ -1,820 +0,0 @@ -:1000000008AA001800030800001000000180185F13 -:100010000000018077182AEB6BF8001803FF68F8DE -:100020000018FFFEF7B8F7BEF6B9F4A0F6B7F6B5BC -:10003000F6B6F02019DFF1000001F84D01ABF6B87B -:10004000F02019DFF07301A57EF80012F000000126 -:1000500047F800117E9200F80011F00000017EF8D0 -:100060000011F00000016C89019AF7B8EEFCF02055 -:10007000FFFFF1000001F84D01BFF27301B94E021C -:10008000F495F5E356027E001100FA4C01B76B03BC -:100090000001F6B8EE04F0740DA7F07401C54A1122 -:1000A0004A1672112AE610F80011FA4501DBF495A0 -:1000B000EEFF4811F0002AC68816F495F49510EE6C -:1000C000FFFFF4E36CE9FFFF01D510F82AE7F845DC -:1000D00001E210F82AE7F4E3F07401FFEE018A165A -:1000E0008A11FC00F7B8E9204A1109F82AE6F84E0F -:1000F00001F3F27301FDF495E80172112AE649114A -:1001000080E12AC6F3000001E80081F82AE68A119E -:10011000FC00F495F073020010F82A0FFC004A115D -:10012000F074020280F82A107308000940F82A15BA -:1001300082F80011F495771003E8F5A9F830022150 -:1001400071F82A102A1556F82A0CF0E34EF82A16F0 -:10015000E8004EF82A0C8A11FC004A064A074A1D9C -:1001600068F800077D3F69F80007400068F8001D47 -:10017000FFFC6BF82A0F00018A1D8A078A06F4EB40 -:10018000EEFD76F82A0F000076000000FB80194C87 -:10019000F495E80080F82A11F980190780F82A0EF2 -:1001A000F980166676002A1210F82A11F98018E3F1 -:1001B00010F82A0EF980166610F82A0EF9801687B4 -:1001C000EE03FC004A11F6B8F495F020800011F817 -:1001D0002A5AF84D029311F82A9FF84C027C7712A4 -:1001E0002A39491201F82A9F8911F495F4957181F1 -:1001F00000116CE1FFAB02936BF82A9F0001E90547 -:1002000001E2000381F82AA0F073029572112A9F7F -:10021000F49510E12A396BF82A9F000111F82A9F02 -:1002200009F82AA0F84C029376F82A5A000076F8CA -:100230002A9F000076F82AA000008811F495481142 -:100240008A11FC004A11EEFE10F82A5AF84402B254 -:1002500076F82A5A0001F07402588811F495771044 -:100260008000F4A9F83002B24811F03000FF80009D -:1002700010F82A5BF98018D6EE028A11FC00F4957A -:100280004A084A094A0A4A0B4A0C4A0D4A104A11BE -:100290004A124A134A144A154A164A174A174A1963 -:1002A0004A0E4A064A074A1A4A1D4A1B4A1C68F85F -:1002B00000077D3F69F80007400068F8001DFFFC5B -:1002C000481868F80018FFFEF495F4954A08EEFD0A -:1002D000F07402588811F49577108000F4A9F83072 -:1002E00002EF4811F03000FF800010F82A5BF9801F -:1002F00018D6EE038A18F4958A1C8A1B8A1D8A1A5E -:100300008A078A068A0E8A198A178A178A168A1510 -:100310008A148A138A128A118A108A0D8A0C8A0B0F -:100320008A0A8A098A08F4EB4A1177112A397681F8 -:10033000005577122A1810E2000180E1000110E256 -:10034000000280E1000276E10003000076E1000493 -:1003500000AAF07402988A11FC004A118811F495E1 -:10036000F49510816FF82A9E0C88E8FF18E10001CF -:100370001AF82A9EF0301FFF80F82A9E8A11FC008E -:100380004A1177112A397681005577122A1811E21D -:10039000000181E1000111E2000281E1000276E149 -:1003A0000003000248086FE100040C98F03000FFE1 -:1003B00080E1000576E1000600AAF07402988A1137 -:1003C000FC004A1177112A397681005577122A18D4 -:1003D00010E2000180E1000110E2000280E1000271 -:1003E00076E1000300044811F00000048812F4953F -:1003F00077132A76E900E598F3000001F6B8480B78 -:1004000008F82A3CF8430371768200AAF074029837 -:100410008A11FC004A11EEF08811F495F49571816F -:10042000001471E1000100154911F3000002891167 -:10043000E7826DEA0004E7836DEB000A771A000596 -:10044000F07203AA1181F2E88082E9FF19E100014C -:10045000F1A0819211E1000CF2E88083E9FF19E13B -:10046000000DF1A081936DE9000248184918700051 -:100470000015F0000004F300000A80018102F2740C -:100480000E54F4954814EE108A11FC004A11F074D1 -:100490000C5E80F82A5C77122A3976820055771133 -:1004A0002A1810E1000180E2000110E1000280E260 -:1004B000000276E20003001CF6B856F82A16F0F0A7 -:1004C000F0F880E2000756F82A16F1F0E8FFF28013 -:1004D00080E2000656F82A16F1F8E8FFF28080E282 -:1004E000000557F82A16E8FFF28080E2000456F86B -:1004F000276CF0F0F0F880E2000B56F8276CF1F072 -:10050000E8FFF28080E2000A56F8276CF1F8E8FF75 -:10051000F28080E20009E8FF57F8276CF28080E261 -:10052000000856F8276AF0F0F0F880E2000F56F85D -:10053000276AF1F0E8FFF28080E2000E56F8276AA1 -:10054000F1F8E8FFF28080E2000D57F8276AE8FF33 -:10055000F28080E2000C76E20013000076E20012E6 -:1005600000006FF82A5C0C5880E20011E8FF18F8D0 -:100570002A5C80E2001076E20017000076E20016A6 -:1005800000006FF82A9E0C5880E20015E8FF18F86A -:100590002A9E80E2001476E2001B000076E2001A38 -:1005A000000076E20019000070E20018276E76E283 -:1005B000001F000076E2001E000076E2001D000031 -:1005C00076E2001C000076E2002000AAF074029897 -:1005D0008A11FC004A11EEFE10F82A38F84504EDA5 -:1005E00077122A1810E200028811F495771000089B -:1005F0006DE9FFDFF6A9F8200475F073047DF010B3 -:100600000021F0001A8348087EF80008F4E2F07434 -:10061000030AF07304EA4812F2740323F0000004A2 -:10062000F2740336F495E800F07304EA77112A189F -:10063000E8FF6FE100040D4818E10005F274096954 -:10064000F495F2A0F0740336F07304EA77112A18D7 -:10065000E8FF6FE100040D4818E10005F27409415C -:10066000F495F2A0F0740336F07304EAF0740357C3 -:10067000F07304EA10F82A1CF07412A4F274033622 -:10068000F495E800F07304EA4812F2740380F00075 -:100690000004F2740336F495E800F07304EA10F8ED -:1006A0002A1CF07412C5F2740336F495E800F07356 -:1006B00004EA77112A18E8FF6FE100060D4818E1F7 -:1006C000000771E100050012F2A070000012800125 -:1006D00010E10004F0740E7AF2740336F495E80029 -:1006E000F07304EAF07403BC76F82A380000EE02D6 -:1006F0008A11FC004A1177112A3976810055771248 -:100700002A1810E2000180E1000110E2000280E1FD -:10071000000276E1000300094811F000000488128D -:10072000F49577132A86E900E598F3000001F6B8FE -:10073000480B08F82A3CF843050A768200AAF074B0 -:1007400002988A11FC004A1177112A3976810055E6 -:1007500077132A1810E3000180E1000110E3000282 -:1007600080E1000213E3000381E1000348117711E7 -:100770000000F84D0544F000000488124813F00012 -:1007800000048813F495F495E5986D91F6B8481136 -:1007900008F82A3CF843053AF0202A394911F500B7 -:1007A0008911F495F49576E1000400AAF07402989A -:1007B0008A11FC004A1177112A3976810055771287 -:1007C0002A1810E2000180E1000110E2000280E13D -:1007D000000276E10003000C4811F00000048812CA -:1007E000F49577132A7AE900E598F3000001F6B84A -:1007F000480B08F82A3CF843056A768200AAF07490 -:1008000002988A11FC004A1177112A397681005525 -:1008100077122A1810E2000180E1000110E20002C4 -:1008200080E1000276E1000300194811F0000004A5 -:100830008812F49577132A5DE900E598F30000012A -:10084000F6B8480B08F82A3CF8430593768200AACC -:10085000F07402988A11FC004A11881110F82A38A5 -:10086000F84405E310F82AA1F84405BA6CE1FF56F4 -:1008700005E372122AA1F49570E22A1800116BF8B0 -:100880002AA10001F07305E372122AA1F49570E227 -:100890002A18001110F82AA1F00000018812F4951E -:1008A000F4956EE2FFFC05D173122AA14811F00005 -:1008B000000580F82AA210F82AA108F82AA2F84414 -:1008C00005E36CE1FFAB05DD76F82A38000176F828 -:1008D0002AA1000076F82AA200008A11FC00F495F3 -:1008E0004A084A094A0A4A0B4A0C4A0D4A104A1158 -:1008F0004A124A134A144A154A164A174A174A19FD -:100900004A0E4A064A074A1A4A1D4A1B4A1C68F8F8 -:1009100000077D3F69F80007400068F8001DFFFCF4 -:10092000481868F80018FFFEF495F4954A08EEFFA1 -:1009300010F82A5BF9801804F07405A2EE018A18F9 -:10094000F4958A1C8A1B8A1D8A1A8A078A068A0ECF -:100950008A198A178A178A168A158A148A138A129C -:100960008A118A108A0D8A0C8A0B8A0A8A098A08D7 -:10097000F4EBEEFD76F82A38000076F82A5A0000EB -:10098000E8014E00FB8017D6F495E80180F82A5B59 -:1009900076002A8FF98016AA10F82A5BF980175C76 -:1009A00010F82A5BF980176FFB801666F495E81A39 -:1009B000FB801687F495E81AFB801666F495E81B11 -:1009C000FB801687F495E81BEE03FC004A11F495B2 -:1009D00013028811E800F84D066AF3100001891A25 -:1009E000F495F07206691C918A11FC004A11881175 -:1009F00012031102F8450679F0100001881AF495E7 -:100A0000F072067881918A11FC004A11F495710206 -:100A10000011110361F800110001F8300691F6B8D9 -:100A20006FF800110C1F8811F3E8E8FF1881F1A09E -:100A30008181F073069DF6B86FF800110C1F8811C4 -:100A4000F33000FFF020FF001881F1A081818A11AE -:100A5000FC004A11F495110261F8000B0001F82026 -:100A600006B1490BF61F8811F495F4951081F273C5 -:100A700006B8F03000FF490BF61F8811F495F49585 -:100A80001281F4788A11FC004A11F4957102001267 -:100A900013038811E800F84D06CCF3100001891A01 -:100AA000F495F07206CB1192F2C081918A11FC008C -:100AB0008812120271010013F84506DBF0100001E4 -:100AC000881AF495F07206DAE598FC004A11EEFEF9 -:100AD0008811110410067105001261F8001200015E -:100AE000F82006EAF0000001F6B8F00000016FF807 -:100AF00000120F1F48088100F47F8001F27406BACB -:100B0000F4954811EE028A11FC004A11EEFE88129B -:100B1000110410067105001361F800130001F8209C -:100B20000709F0000001F00000018811F6B86FF825 -:100B300000130F1F81004811F47F8001F27406CE6C -:100B4000F49548124811F030FFFEEE028A11FC00C5 -:100B50004A114A164A17EEFCF495800271080016F5 -:100B60001009710B00178003710A00114817F8452E -:100B7000073F700000111003F074069F80017000A1 -:100B800000161002F074067B6D916D966CEFFFFFFE -:100B9000072FEE048A178A168A11FC004A11EEFE0E -:100BA00010F82AE808F82AE9F845076476000001F9 -:100BB00062F82AE9005EF274120BF0003040721104 -:100BC0002AE97710000FF5A9F82007616BF82AE9E8 -:100BD0000001F073076476F82AE90000EE028A113A -:100BE000FC004A118811E80075F800080008E800C8 -:100BF00075F800080009F6B8F495F020FC3F75F888 -:100C00000008000DF0200C3075F80008000C76F894 -:100C10002AE8000076F82AE900006C81079276F84D -:100C20002AEA0000FB801676F495E810E80075F8D3 -:100C300000080000F07307A876F82AEA0001FB809C -:100C40001666F495E810FB801687F495E810E80026 -:100C500075F800080000F6B8F495F020FFFF75F86D -:100C6000000800008A11FC00F4954A084A094A0A63 -:100C70004A064A074A1D68F800077D3F69F80007E1 -:100C8000400068F8001DFFFC10F82AEAF84507E16B -:100C900010F82AE8F0000001F030000F80F82AE890 -:100CA00010F82AE8F84407D6F6B8F495F020FC3F8F -:100CB00075F80008000DF0200C3075F80008000CE5 -:100CC000E80075F800080000F6B8F495F020FFFF82 -:100CD00075F8000800008A1D8A078A068A0A8A09B0 -:100CE0008A08F4EBEEFFF2740767F495E801EE0171 -:100CF000FC004A074A1D68F800077D3F69F80007B5 -:100D0000400068F8001DFFFC8A1D8A07F4EB4A11B9 -:100D10007711002876812400E80075F800080001AA -:100D2000F2740767F495E8007711001D6881007F71 -:100D3000F6B8F495F020FF807711001DF030010027 -:100D40001A818081F0740A33F07411ACF980132594 -:100D5000F9801653F9801782F074062FF98014B2C7 -:100D6000F9801910F0740DE3F07407E8F07402369E -:100D70008A11FC004A1160F8277BFFFFF830083920 -:100D800071F8277B277960F82779FFFFF83008B2E0 -:100D900010F8298608F82779F0307FFF8811F4953C -:100DA00077104000F6A9F830085810F8277908F8AD -:100DB000277AF0307FFF8811F49577104000F6A96C -:100DC000F820086376F82779FFFF76F8277BFFFF86 -:100DD000F7B8F27308D9F020FFFFF6B856F8277479 -:100DE000F0F9881156F82772F0F98812F495F49505 -:100DF000E720F4A9F830088FF120277C4811F6008D -:100E00008813F495F495108308F82779F0307FFF64 -:100E10008813F49577104000F5ABF830088F6D918A -:100E20004811F03001FF8811F495E720F7A9F83058 -:100E300008746D894811F03001FFF0E7F495480817 -:100E40004EF827744808F1F98911F495F49571E189 -:100E5000277C277A60F8277BFFFFF83008AB48082B -:100E60004EF8277276F8277BFFFF76F82779FFFF89 -:100E7000F27308D9F495E80044F8277340F8277511 -:100E800082F80011F49577108000F6A9F82008D8B0 -:100E9000F6B810F82773F000800048084EF8277461 -:100EA0004808F0F98811F495F49571E1277C277AC8 -:100EB000F7B857F82774F062FFFFF040FF80F28028 -:100EC0004EF82774E8008A11FC004A114A16EEFB1E -:100ED00011F8277109F8277389118810F495F49592 -:100EE000F6A9F82008EDF273090EF495E800F62053 -:100EF00076000041F07412EE8816F495F7B86D96FE -:100F000010F80016F847090AE7617600000076013C -:100F10000080760200FF76030000F2740CB9F495AD -:100F2000E8006CE9FFFF08FB7316000EF066004155 -:100F3000EE058A168A11FC004A11F495710200131D -:100F4000F6B877117FFF57F827724811F280F0004A -:100F500080008811F640F0E0F1F1E801F28080F8BD -:100F600027787712800057F827724812F28088128B -:100F7000F495F4956C820938E80075F800080001D2 -:100F8000F073093DF020800175F8000800017081C0 -:100F900000138A11FC004A11F0307FFF11F82986F6 -:100FA000F520F3307FFF8911F49577104000F6A902 -:100FB000F8200954F2730967F495E8026FF8277A6C -:100FC0000D20F3307FFF8911F49577104000F6A9CA -:100FD000F8200964F2730967F495E80180F8277B2B -:100FE000E8008A11FC004A1111F82986F520F33037 -:100FF0007FFF8911F49577104000F6A9F820097A4F -:10100000F273098DF495E8026FF8277A0D20F3301A -:101010007FFF8911F49577104000F6A9F820098A1E -:10102000F273098DF495E80180F82779E8008A11B8 -:10103000FC004A11F495710200128811F6B857F8B5 -:101040002772F0207FFFF280F0008000808157F847 -:101050002772E801F3F1F28080F827787711800099 -:10106000481157F82772F2808811F495F4956C8135 -:1010700009B5E80075F800080001F07309BAF0201E -:10108000800175F80008000145F8277143F82773BF -:1010900083F80011F495E720F6A9F83009C9F27336 -:1010A00009E47712000057F82772F0207FFFF280E2 -:1010B0004912F500F300800061F8000B8000F83061 -:1010C00009DCF1208000F5208912F49548126FF8B0 -:1010D00027730D00F495490B4FF827728A11FE0013 -:1010E0004812F4954A114A164A17EEFCF495710815 -:1010F00000168817F0740830481870000016F27453 -:10110000098FF00000028811F495F4956C810A0AA9 -:10111000F27408DBF4954816481870000016F27453 -:10112000098FF00000028811100270010011800088 -:10113000F27406CEF495481749114817F60088173F -:10114000E760F5A9F8200A2D4816F62088114818FE -:1011500070000011F274098FF00000028811700114 -:10116000001110028000F27406CEF4954817EE04C8 -:1011700048168A178A168A11FC00EEFDE8004EF820 -:101180002770E8004EF82772E8004EF82774E80050 -:101190004EF8277676F82779FFFF76F8277A000051 -:1011A00076F8277BFFFF76F827780000E80075F8CF -:1011B000000800017600000076010200F27412DCE3 -:1011C000F020277CEE03FC004A11EEFCF4954E0063 -:1011D00077127FFFF6B84912F180F3008000891280 -:1011E000F0E0F1F14F02E901F495480BF5405602A9 -:1011F000F18081F827787711800056004911F1803D -:101200008911F495F4956C810A81E80075F800085D -:101210000001F0730A86F020800175F800080001D3 -:101220001082EE048A11FC004A11EEFEF4954E0085 -:1012300077117FFFF6B84911F180F3008000891122 -:10124000F0E0F1F1E801F28080F827785600F12013 -:101250008000F180F495490BF84D0AABF020800135 -:1012600075F800080001F0730AAFE80075F800088F -:101270000001EE0248118A11FC004A118812130283 -:1012800077110000F84D0ACBF3100001891AF4958C -:10129000F0720ACA48111CF8297E881111F8297EBB -:1012A000F200000180F8297E819248118A11FC0029 -:1012B0004A11F495710200118812F6B8F0207FFFF0 -:1012C00057F82770F280F0008000808257F827706E -:1012D000E801F3F1F28080F8277877128000481255 -:1012E00057F82770F2808812F495F4956C820AF40E -:1012F000E80075F800080001F0730AF9F020800199 -:1013000075F80008000145F82775E71043F82771C4 -:1013100083F800126DE800046D8AF6AAF8300B0A13 -:10132000F2730B257711000057F82770F0207FFF2C -:10133000F2804911F500F300800061F8000B800095 -:10134000F8300B1DF1208000F5208911F49548112B -:101350006FF827710D00F495490B4FF8277048116D -:101360008A11FC004A114A164A17EEF08817101726 -:1013700080051016800610158007711400111005E5 -:10138000F030000188101006F0300001800849118B -:101390001005F6018009100661F800080001F82028 -:1013A0000B4B1009F0000001800971080012F4AA2B -:1013B000F8300B541009F00000018009120949119E -:1013C000F47F8009F620800A56F827704E0C100929 -:1013D00080004818F2740ACEF00000048816F495D4 -:1013E000F4956C860B6DF2730C59F495E800F6B821 -:1013F000F495560CF0F98812F495F49570E2277C78 -:101400002986E800800E4811F8450BCC77100001C2 -:10141000F4A9F8300B896CE1FFFD0B8B10E700029B -:10142000800EF0730B8B1087800EE710F5AEF8205E -:101430000BB270000017700100161004F07406CE95 -:1014400048174916F60088174811F6208811100928 -:10145000F62080004818F2740ACEF00000048816C6 -:1014600010047000001770010011F07406CE4811CE -:1014700000048004F0730BBC7000001770010011B1 -:101480001004F07406CE4811000480044911481677 -:10149000F6208816F495F4956C860BCC100A800023 -:1014A0004818F2740ACEF00000048816120AF845B3 -:1014B0000C33710A0010F4AEF8300C1C4816F0E141 -:1014C00088111208F8450BDB6D891207F8450BE906 -:1014D0001007800070020011100680011004F074E3 -:1014E00006DCF0730BEF48116F000C9F1004F074D2 -:1014F0000AB3110EF1C0810E10064911F6008006E4 -:101500001005F6208811F000000148086F000C9FBC -:101510004818F2740ACEF00000041207F8450C11C6 -:101520001007800070020011100680011004F07492 -:1015300006DCF0730C1748116F000C9F1004F07458 -:101540000AB3110EF1C0810EF0730C331207F84587 -:101550000C2A10078000100680011005800210047C -:10156000F07406DCF0730C3012056F000C9F100451 -:10157000F0740AB3110EF1C0810E76000001481814 -:10158000F2740ACEF0000004710400117081298603 -:10159000100E1CF82986800E760000014818F2749F -:1015A0000ACEF0000004100E71040011808110F8C2 -:1015B0002986F0000001F0307FFF80F829861009AD -:1015C000F00000028009EE108A178A168A11FC00CA -:1015D00010F8277508F82771F01000014808FC0082 -:1015E0004A114A16EEFFF49571040016F00000014E -:1015F00048084EF8297C6DEEFFFD4816F8450C9919 -:1016000056F8297CF0740A5A881110F8297DF000E8 -:10161000000148084EF8297C10F82982F0000001EA -:101620008810F495F495F4A9FA300C9680F8298284 -:1016300056F82980F00000014EF8298073112982A4 -:101640006CEEFFFF0C76EE018A168A11FC004A113F -:1016500076F82984000076F829850001E8004EF824 -:101660002A0C76F82986000076F829870000771181 -:1016700029887681AAAA76E10001AAAA76E1000269 -:1016800000008A11FC004A11EEFCF495710600146A -:10169000710700137108001271090015771000FF1F -:1016A000F4AAF8300D44491353F82A0C4FF82A0CC9 -:1016B0007312000EF166000D8911F4957710000188 -:1016C00071E124000011F4A9F8300D177710000221 -:1016D000F4A9F8300CEC7711298A76810000E80033 -:1016E0007714000077130000F0730D486C830CFA38 -:1016F0007711298A4812F0E8F04080008081E800E4 -:1017000077140000F0730D484913F340800081F80E -:10171000298A61F800150001F8200D0769F8298A67 -:10172000400061F800140001F8200D0F69F8298AC3 -:1017300020007711298A4912F3E81B818181F07317 -:101740000D4811F82984F84C0D37771129887681D6 -:10175000AAAA11F82985F3100001F340AA0081E13B -:101760000001760000028001700200147003001373 -:10177000F2740B28F495481171F829852984F073C7 -:101780000D737600000080017602000070030013E4 -:10179000F2740B28F495E800F0730D737711298A21 -:1017A0007081001311F82984F84C0D68771129888D -:1017B0007681AAAA11F82985F3100001F340AA0046 -:1017C00081E10001760000038001700200147003C3 -:1017D0000013F2740B28F495481171F829852984B7 -:1017E000F0730D7376000001800170020014700325 -:1017F0000013F2740B28F49548116BF82984FFFF4D -:10180000EE048A11FC004A11F540F495480BF47877 -:101810008811F495F4956CE1FFB90D88F2730DA56C -:10182000F495E860F200000661F800110020F8303D -:101830000D9861F8000B0001F8200DA3F2000007DD -:10184000F0730DA361F8000B0001F8200DA1F273F5 -:101850000DA3F0000001F00000024808F47F8A1197 -:10186000FC00EEFFF07407FDF0740744F0740DB453 -:10187000F0740205F0740460F0730DAAEEFD10F828 -:101880002AA3F8440DCB10F82AA4F8450DD776000A -:101890000200F27409E8F020220076F82AA4000081 -:1018A00076F82AA70000F0730DD776000200F274D4 -:1018B00009E8F020200076F82AA3000076F82AA78D -:1018C0000001F0740C5EF0E0F0103A98F8470DE17A -:1018D00076F8276E0000EE03FC004A11EEFE771149 -:1018E00020007600AAAA76010200F274066CF49534 -:1018F000481176005555760102004811F274066CC5 -:10190000F000020076F82AA3000076F82AA400006E -:10191000E8004E00FB80153EF495E80480F82AA507 -:1019200076002AA8F980148776002AADFB8013621E -:10193000F495E80210F82AA5F9801463FB80166676 -:10194000F495E81CFB801687F495E81CE8014E002E -:10195000FB8017D6F495E80080F82AA676002AB70F -:10196000F98016AA10F82AA6F980175C10F82AA6A2 -:10197000F980176FEE028A11FC00F4954A084A09B3 -:101980004A0A4A074A1D68F800077D3F69F80007C0 -:10199000400068F8001DFFFC10F82AA7F8440E4B21 -:1019A00076F82AA30001F0730E4E76F82AA40001FF -:1019B0008A1D8A078A0A8A098A08F4EB4A114A169C -:1019C0004A17EEFE880E71080016710600171107FF -:1019D000F066000DF00025A0881176010006810058 -:1019E000F27406CEF00000017601000670000016C9 -:1019F0004811F27406CEF000000770810017EE0265 -:101A00008A178A168A11FC004A11880E7102001288 -:101A10001103F066000DF00024008811F495708128 -:101A200000126EE2FFFE0E8DF495E800E80180E101 -:101A3000000276E1000300FF76E10004000076E199 -:101A4000000B000076E1000C000081E100018A112A -:101A5000FC004A11EEFC880EF495F166000DF300CF -:101A600024008911F495F49576E1000C000076E1EC -:101A7000000B000076E10002000176000000760114 -:101A80000000800276030000F2740CB9F495E800BF -:101A9000EE048A11FC004A118819F4957319000E9E -:101AA000F166000DF2002400771525A077140000E0 -:101AB000771A001FF0720F14F6B849190985F84C0F -:101AC0000F13F100000589114915F3000001891376 -:101AD0004915F3000007891211931D91199289107D -:101AE000F495F4956C800F1311931D911992891040 -:101AF000F495F4956C800F1311931D911992891030 -:101B0000F495F4956C800F1311931D91199289101F -:101B1000F495F4956C800F1311931D91199289100F -:101B2000F495F4956C800F1311931D9119928911FE -:101B3000F495F4956C810F136D946DED000D4814C0 -:101B40008A11FC004A114A164A17EEF88817100D40 -:101B50008004100C8005710E00167317000EF066DD -:101B6000000DF0002400881110F82763F8450F32AB -:101B7000F2740E9FF495481710F82760F8440F3D53 -:101B800060E100020001F8200F6DF07311331004C2 -:101B900080001005F074069F1104F3000001810419 -:101BA0006D8E7710000171E100020012F4AAF83086 -:101BB0000F6277100002F4AAF8300F6D45E1000BB8 -:101BC000881043E1000C83F80012F495F495F4AA10 -:101BD000F8300F6DF0730F96F50081044916F5206B -:101BE000891676E1000C000076E10004000048163A -:101BF000F8451133F7B871E10002001210F8001235 -:101C0000F0100003F8460F8C10F80012F0100003DB -:101C1000F845101677100001F4AAF8300F9C7710E1 -:101C20000002F4AAF8300FA8F0730F9677100004A2 -:101C3000F4AAF83010B777100005F4AAF83010BCF9 -:101C4000F2740E9FF4954817F073113176E1000C91 -:101C5000000076E1000B000076E10004000076E170 -:101C60000002000211E1000CE803F6208912F4954D -:101C700077100003F5AAF8300FB66BF8276F000154 -:101C80008810F495F495F5AEF8200FBD481680063F -:101C90008813F49577100003F6ABF8200FC86BF8A3 -:101CA000276F00011206F845100010E100048000C3 -:101CB0001005800110048002100680034811F274A0 -:101CC000071EF0000005100600E1000480E100049A -:101CD000100600E1000C80E1000C881211061004CF -:101CE000F60080044816F62088168913F4957710BC -:101CF0000003F6ABF8200FF56BF8276F00017710A3 -:101D0000000C71E100040013F6ABF82010006BF832 -:101D1000276F00016CE2FFFD1131F6B86FE100059D -:101D20000C486FE100060C18F0300FFFF0000003C4 -:101D300080E1000B76E1000200034816F8451133FC -:101D400071E1000C001210E1000B4912F62088131B -:101D5000E80CF6208810F495F495F5ABF8201027E0 -:101D6000481380068810F495F495F5AEF8201030ED -:101D7000700600161206F845105F10E1000480009E -:101D80001005800110048002100680034811F274CF -:101D9000071EF0000005100600E1000480E10004C9 -:101DA000100600E1000C80E1000C881211061004FE -:101DB000F60080044816F6208816F4957710000C7B -:101DC00071E100040013F6ABF820105F6BF8276F89 -:101DD00000017710000CF6AAF820106BF2740E9F29 -:101DE000F495481771E1000C00127710000CF4AA6A -:101DF000F830107C7710000C71E1000B0013F6AB8B -:101E0000F83010B4E730F7AAF83010B4F2740EC10D -:101E1000F49548178812F495F4956C82108D76E14C -:101E20000004000076E100020005F07310B476E1D2 -:101E3000000200047710000C71E1000B0012F5AAFB -:101E4000F820109AF073109C7712000C76000000B6 -:101E50007001001270020017760300014811F2743D -:101E60000CB9F000000576E1000400007710000CCA -:101E700071E1000B0012F6AAF820111C4816F84573 -:101E8000113360E100020005F82010DF10E1000BC3 -:101E900008E1000C11E10004F84D10C76BF8276F42 -:101EA00000018810F495F495F5AEF82010CF48168F -:101EB000F4954808F84511166FE1000C0D0081E11A -:101EC000000C1104F50081044916F5208916F07301 -:101ED000110E10E1000B71E1000C00128810F49556 -:101EE000F495F6AAF83011164912F6208810F495E8 -:101EF000F495F5AEF82010F3481680064808F8452A -:101F000011161004700200178000760300001006FE -:101F100080011005F0740CB9100600E1000C80E19E -:101F2000000C11061004F60080044816F6208816EE -:101F300010E1000C08E1000BF845111CF0731131A1 -:101F4000F2740E9FF4954817F073113376E1000C8C -:101F5000000076E1000B000076E1000200011004B1 -:101F600080001005F074069F8812F495771000FF2A -:101F7000F4AAF83011336C860F70EE088A178A16AF -:101F80008A11FC004A11EEFCF495710600128811CA -:101F90007312000EF166000DF30024008914138102 -:101FA000F77AF330000181F8276013E10001F77C34 -:101FB000F330000381F82761E90F19E1000181F88E -:101FC000276271E400030013F6B84913F30000011F -:101FD000F330000F490B09F82762F84D117577109F -:101FE00000FFF4ABF830117557F8276CF3000001CF -:101FF0004FF8276C76F827630001F073117876F8B4 -:102000002763000070E40003276276F8276400006D -:1020100011F8276161F8000B0002F820118DE90129 -:102020006FE100020F1881F8276411F8276161F849 -:10203000000B0001F82011A910F82764F10000043A -:102040008913E9B8F52081F8276560840002F8203B -:1020500011A9700000117001001370022765F2745D -:102060000F18F4954812EE048A11FC004A114A1622 -:102070004A17EEFCE8004EF82766E8004EF827689D -:10208000E8004EF8276CE8004EF8276A77122740E0 -:1020900077112400771A001FF07211DB7092001183 -:1020A00076E10001FFFF7681000076E1000200008A -:1020B00076E1000300FF76E1000C000076E1000B02 -:1020C000000076E1000400006DE9000DF02025A07D -:1020D000F10000078911F100000181028816F495D2 -:1020E00077170020768600FF760000007601000654 -:1020F0001002F074066C7600000076010006F2749F -:10210000066CF49548111002F000000D80026DE994 -:10211000000D6DEE000D6CEFFFFF11E8F0740C9DEB -:10212000EE048A178A168A11FC004A114A164A17C9 -:10213000EEFA8811100A4911F84D129F4808F84527 -:10214000129F80041281F5788912F495F4956CE25F -:10215000FFB9128A61F800080080F830128A13E192 -:102160000001F0E8F778F1A0F2301FFF8817F4952E -:10217000771224007716000077130020F6B848176E -:1021800008E20001F84512426DEA000D6D966CEB15 -:10219000FFFF1234F073129056F8276AF000000126 -:1021A0004EF8276A60820001F83012547000001661 -:1021B000F2741138F4954811F07312907000001603 -:1021C000F2741138F495481172102A9EF495F4AF08 -:1021D000F830126E76000000760100BC7002001626 -:1021E00076030000F2740CB9F4954811F073129064 -:1021F00010F8276EF844129076000000760100BCBB -:102200007002001676030000F2740CB9F4954811C0 -:10221000F0740C5EF0E0F0101388F842129076F83B -:10222000276E0001F073129056F82766F000000147 -:102230004EF827666DE9005E56F82768F000000149 -:102240004EF82768710400126EEAFFFF121870043E -:102250000012EE068A178A168A11FC004A11EEFE59 -:10226000880EF495F066000DF00025A08811F49515 -:10227000F495768100FF7600000076010006F27486 -:10228000066CF0000001760000007601000648119F -:10229000F274066CF0000007EE028A11FC004A118D -:1022A000880EF495F066000DF00024008811F49576 -:1022B000F49576E10001FFFF7681000076E10002EF -:1022C000000076E1000300FF8A11FC004A11F4953A -:1022D00013038811FA4D12EC71020012F310000181 -:1022E000891AF495F07212EB709100128A11FC00B9 -:1022F000F4954A0B4A0C4A0DF7B8EEFE10F80008A8 -:102300001106F1C08300F4851106F7858106F6B841 -:10231000EC0F1E0661008000F8201305F484EE0225 -:102320008A0D8A0C8A0BFC00F4954A0B4A0C4A0D64 -:10233000EEFEF7B8800010F80008F4851106F78566 -:102340008106F6B8EC0F1E06F0F061008000F82060 -:102350001320F484EE028A0D8A0C8A0BFC004A11C9 -:102360007711007B76812EEC7711007BEEFF718177 -:102370000011EE0176E10001000076E100040000AA -:1023800076E10006000076E10062000076E100766A -:10239000000076E10092000076E10094000076E112 -:1023A00000B0000076E100B3000076E100BE00005E -:1023B00076E100BF000076E100C1000076E100C3D5 -:1023C000000076E100C5000076E100C700007681DC -:1023D00000008A11F495F4E44A114A164A17EEFFF8 -:1023E000F49571060016FB8016A28817F495F7B8CD -:1023F00010F80017F0100002FA4613887711000059 -:1024000010F80017F0100002F84513F910F8001743 -:10241000F845143910F80017F0100001F845141FA2 -:10242000F073145210F80017F0100003F84513D39E -:1024300010F80017F0100006F84414527712007BD1 -:102440007182001461E400070040F830145249140E -:102450004817F6008812F495771300557711005746 -:102460006DEA003BE50110E600068081481400F8A3 -:1024700000178812F4957711005510E20040808112 -:102480007711005710E6000780817711005510E2A0 -:102490000045808110E60008771100578081771190 -:1024A000005510E2004A80817711005710E60009BC -:1024B0008081F2731452771103C07712007B10826F -:1024C000F00000078813F495F495961BF830145229 -:1024D00010E300357712005580827712005710E61E -:1024E000000480827712005510E300378082771253 -:1024F000005710E6000580824811F0400010F2738A -:102500001450F04000207712007B1082F00000078A -:102510008812F495F495960DF830145210E20034B8 -:102520007713005580837713005710E600028083ED -:1025300010E200367712005580827712005710E6BD -:10254000000380824811F0400004F2731450F04000 -:1025500000087712007B1082F00000078812F495C3 -:10256000F495960EF830145210E2003377120055AD -:1025700080827712005710E6000180824811F273C2 -:102580001450F04000027712007B1082F000000728 -:102590008812F495F495960FF830145210E2003238 -:1025A000771200557713005780824811E762F04098 -:1025B0000001E5018811F4957712007B48117182C2 -:1025C00000121AE2000780E20007F980169AEE0175 -:1025D0008A1748118A168A11F4E44A118811770E75 -:1025E000000577120055E804F6B828E10002EEFF76 -:1025F000808277120057F0208000EE011A82771255 -:1026000000578082E80132E10002F5827711005420 -:10261000F693188177110054F2A080818A11F49505 -:10262000F4E44A114A16F49571040011FB8016A2D5 -:102630008816F4957712005510E600038082771211 -:10264000005610E100027713005680827712005680 -:1026500010E10003808210E10004771200568082AE -:102660007712005610E100018082E712E501F9803F -:10267000169A8A168A11F4E44A114A164A17EEF994 -:102680007711007B76000016760100177602001A9B -:102690007603001B7604001C7605001D718100176F -:1026A00071E7000600111081F84414DFF980165319 -:1026B000F6B8FB801585F020FFFFF6B8FB80160802 -:1026C000F020FFFF7711007B7181001776E700068D -:1026D00000014817771600007710000477150003F3 -:1026E0007714000277130001F000003976E7000844 -:1026F000001F76E700070000880E771A00054817CC -:10270000F0000009881248188819E800F072152CAA -:10271000731900117682000011917311001970E293 -:102720000003001670E20004001370E200050014BC -:1027300081E2000170E20006001570E2000700105F -:1027400080E20002730E0011F100001E6DEE000524 -:102750006DEB00056DEC00056DED00056DE8000505 -:10276000F000000181916DEA00087311000EEE0780 -:1027700076E70041002476E70046002576E7004B27 -:10278000002676E7005000278A178A168A11F4E49B -:102790004A114A16EEFE881156064E00F98016A21E -:1027A000F7B810F80011F010FFFFFA451560771622 -:1027B000FFFF7712007B49111082F603F000000939 -:1027C0008811F495F4951081F8441571F273157120 -:1027D000F495E7167711007B1081F000000988114D -:1027E000F495771200061081F845155C6EEAFFFF3C -:1027F00015696DE9000876860001E9015600F1804F -:1028000010F8000BF845157EFB801585F4954816E9 -:10281000F980169AEE0248168A168A11F4E44A11D3 -:10282000EEFFFB8016A28811F4957710FFFFF4A944 -:10283000F83015C410E1000377120055808277123A -:1028400000567682000077120056768200007712DA -:1028500000567682000077120056768200007712CA -:1028600000567682000010E10002F000000832F805 -:10287000000877120054E801F482F493188277126A -:102880000054F0400000808210E10001F9801676CB -:1028900010E10001F9801666F07316037711007BD2 -:1028A0007181001171E1000700127682000010E1D1 -:1028B0000009F98015857711007B7181001110E105 -:1028C0000009FB801585F00000087711007B7181FD -:1028D000001110E10009FB801585F0000010771150 -:1028E000007B7181001110E10009FB801585F0006B -:1028F00000187711007B7181001110E10009FB8045 -:102900001585F00000207711007B7181001110E126 -:102910000009FB801585F0000028F980169AEE0169 -:102920008A11F4E44A11EEFFFB8016A28811F49597 -:102930007710FFFFF4A9F830164177110055768122 -:10294000001E7711005676810000771100567681BF -:1029500000007711005676810000771100567681CD -:1029600000007711005676810000771100567681BD -:1029700000007711005676810000771100567681AD -:102980000000771100567681000077110056F2732F -:10299000164E768100007711007B7181001171E184 -:1029A000000700127682000010E10039F980160855 -:1029B000F980169AEE018A11F4E44A117711007B2E -:1029C0001081F00000048811F495F4951081FA4408 -:1029D0001663F495EEFF76810001EE018A11F4E4AE -:1029E000F01000104A1132F80008EEFF77110001D4 -:1029F000E801EE01F4821A8180818A11F495F4E4F1 -:102A0000F01000104A1132F80008EEFFE8017711CB -:102A10000000F482EE01F493188180818A11F4950C -:102A2000F4E44A11F01000107711000032F80008A9 -:102A3000EEFF1181E801EE0177110000F482F2A0AF -:102A400080818A11F495F4E4F273169EF6BBF49536 -:102A5000F495F495F495F4E4F27316A6F7BBF495A7 -:102A6000F495F495F495F4E44A114A16F49571043A -:102A70000016FB8016A28811F49571E10005001282 -:102A80007682000E10E6000E71E1000600128082D0 -:102A900071E1000500127682000D71E1000600125E -:102AA00010E6000D808271E1000500127682000CB4 -:102AB00010E6000C71E100060012808271E1000551 -:102AC00000127682000B10E6000B71E10006001286 -:102AD000808271E1000500127682000A71E1000631 -:102AE000001210E6000A808271E100050012768271 -:102AF000000910E6000971E100060012808271E110 -:102B0000000500127682000871E10006001210E64E -:102B10000008808271E1000500127682000710E64D -:102B2000000771E100060012808271E100050012C9 -:102B30007682000671E10006001210E6000680822F -:102B400071E1000500127682000571E100060012B5 -:102B500010E60005808271E1000500127682000413 -:102B600071E10006001210E60004808271E10005A8 -:102B700000127682000371E10006001210E60003E5 -:102B8000808271E1000500127682000210E60002E8 -:102B900071E100060012808271E100050012768268 -:102BA000000110E6000171E100060012808271E16F -:102BB000000500127682000071E100060013E76252 -:102BC000E501F980169A8A168A11F4E44A118811EF -:102BD000F495F49571E100050012EEFF7682000095 -:102BE000EE0171E100060011698100018A11F4957E -:102BF000F4E44A118811F495F49571E1000500128E -:102C0000EEFF76820001EE0171E10006001169819C -:102C100000018A11F495F4E44A117711007B1081C8 -:102C2000F00000948811F495F4951081FA44179CF3 -:102C3000F495EEFFF98016537711007B1081F000B8 -:102C400000948811F495F49576810001EE0176E107 -:102C50000001000076E10002002176E1000300207F -:102C600076E10004002376E10005002276E100060B -:102C7000003876E10007003976E10008001576E1BA -:102C80000009001476E1000A000076E1000B004123 -:102C900076E1000C004076E1000D004376E1000E85 -:102CA000004276E1000F004876E10010004976E12D -:102CB0000011001B76E10012001A8A11F495F4E469 -:102CC0004A11EEFD881156064E00F98016A27712C1 -:102CD000007B770E0009108228F80011F0000095A3 -:102CE0008811F495F4951081F84517F0F27317FDEB -:102CF0007711FFFF76810001E9015600F18010F89D -:102D0000000BF84517FDFB801810F4954811F98069 -:102D1000169AEE0348118A11F495F4E44A118811C9 -:102D2000F495EEFF71E100010011EE0110818A11AE -:102D3000F495F4E44A11EEFFFB8016A28811F49595 -:102D40007710FFFFF4A9F83018C371E100050012F5 -:102D50007682000071E1000600127682000071E1C7 -:102D6000000500127682000171E1000600127682F1 -:102D7000000071E1000500127682000271E1000698 -:102D800000127682000071E10005001276820003D5 -:102D900071E1000600127682000071E10005001268 -:102DA0007682000471E1000600127682000071E173 -:102DB000000500127682000571E10006001276829D -:102DC000000071E1000500127682000671E1000644 -:102DD00000127682000171E1000500127682000780 -:102DE00071E1000600127682200071E100050012F8 -:102DF0007682000871E1000600127682000071E11F -:102E0000000500127682000971E100060012768248 -:102E1000000071E1000500127682000A71E10006EF -:102E200000127682000071E1000500127682000B2C -:102E300071E1000600127682000071E100050012C7 -:102E40007682000C71E1000600127682000071E1CA -:102E5000000500127682000D71E1000600127682F4 -:102E6000000071E1000500127682000E71E100069B -:102E700000127682000010E10007F980167610E15A -:102E80000008F980167610E10007F980166610E157 -:102E90000008F9801666F07318D17711007B108155 -:102EA000FB801810F00000957711007B1081FB80EB -:102EB0001810F000009EF980169AEE018A11F4E4D1 -:102EC0004A118811EEFFF495100471E1000300111E -:102ED000EE0180818A11F495F4E44A114A16F495C2 -:102EE00071040016FB8016A28811F49571E10002AE -:102EF00000127682001010E6000171E1000300125A -:102F0000808271E10004001210E600028082E76214 -:102F100071E100020013E501F980169A8A168A1100 -:102F2000F4E44A118811EEFFEE0110E100018A116C -:102F3000F495F4E44A117711007B1081F00000B39E -:102F40008811F495F4951081FA44192AF495EEFF4E -:102F5000F98016537711007B1081F00000B38811BF -:102F6000F495F49576810001EE0176E10001000010 -:102F700076E10002001376E10003002676E100040A -:102F8000002576E10005002476E10006000076E1E8 -:102F90000007001776E10008003276E100090031F1 -:102FA00076E1000A00308A11F495F4E44A114A16D9 -:102FB0004A17EEFFF49571060017FB8016A28811E0 -:102FC000F495F7B810F80011F010FFFFFA451973E7 -:102FD0007716FFFF7712007B770E0005108228F826 -:102FE0000011F00000B48811F495F4951081F844B4 -:102FF0001984F2731984F495E7167711007B108118 -:10300000F00000B48811F495771200021081F845A1 -:10301000196F6EEAFFFF197C6DE9000561F8001772 -:103020000001FA20198F76860001FB801997F4952C -:103030004816F980169AEE018A1748168A168A11E0 -:10304000F4E44A11EEFFFB8016A28811F495771084 -:10305000FFFFF4A9F83019CC71E100020012698277 -:10306000001071E1000200126882F7FF71E10002B6 -:1030700000126882FBFF71E1000200126882FFF01B -:1030800071E1000300127682FFFF71E1000400127B -:103090007682FFFF71E1000200126982002071E177 -:1030A00000020011F27319DA6881FFEF7711007BDB -:1030B0001081FB801997F00000B47711007B10811C -:1030C000FB801997F00000B9F980169AEE018A1179 -:1030D000F4E400A4000019DF00012AE6000000016A -:1030E0002AE7000000032A120C01C34F0000000170 -:1030F0002A15000000022A160000000000192A5DAF -:103100000043006F0070007900720069006700687A -:10311000007400200054006500630068006E006FBA -:10312000005400720065006E0064002000410047FA -:10313000000000042A760030002E00300000000C51 -:103140002A7A004600650062002000320037002025 -:103150000032003000300031000000092A860031C2 -:103160000034003A00330035003A003300330000E9 -:10317000000F2A8F00000000000000010000000185 -:10318000000000000000000000000000000000003F -:10319000000000012A9E000000012A9F000000019B -:1031A0002AA0000000012AA1000000012AA20000BC -:1031B0000001297E000000022980000000000001BB -:1031C0002982FFFF00012AA7000000052AA87141FB -:1031D0002000200000230400000A2AAD00000000A7 -:1031E00000000000000000000000000000000000DF -:1031F000000F2AB7000000000000004000A082403D -:103200000008307F00800180000000000000000006 -:1032100000000001276E00000001276F0000000081 -:10322000000900001A8304E804CF04C504BA04B0FE -:1032300004AC049C048C0481007800000100F2734B -:1032400007EFF495F495F27307EFF495F495F273A4 -:1032500007EFF495F495F27307EFF495F495F27394 -:1032600007EFF495F495F27307EFF495F495F27384 -:1032700007EFF495F495F27307EFF495F495F27374 -:1032800007EFF495F495F27307EFF495F495F27364 -:1032900007EFF495F495F27307EFF495F495F27354 -:1032A00007EFF495F495F27307EFF495F495F27344 -:1032B00007EFF495F495F27307EFF495F495F27334 -:1032C00007AAF495F495F27307EFF495F495F27369 -:1032D00007EFF495F495F2730223F495F495F273E5 -:1032E00007EFF495F495F27307EFF495F495F27304 -:1032F00007EFF495F495F27307EFF495F495F273F4 -:1033000007EFF495F495F27307EFF495F495F273E3 -:1033100005E5F495F495F27302B5F495F495F2731E -:103320000E33F495F495F27307EFF495F4950000DD -:00000001FF diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/vicam/firmware.H16 v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/vicam/firmware.H16 --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/firmware/vicam/firmware.H16 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/firmware/vicam/firmware.H16 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -:0026000000B6C31F000264E767FDFF0EC0E709DE008E00C0094003C01744034BAFC00700004BAF97CF00001D -:000A000000B6C30300036418000000FB -:0008000000B6C301000664000014 -:0696000000B6C38F060264E707000008C0E70700003EC0E7075401AA00E707C805B600E7074201D200E7077C001600E70756001800E707060092C0E70700001EC0E707FFFF22C0E707040024C0E707EC2728C0E70716018E00E78701000EC097CFD70900C0E777010092C009C1E709FE052401E70904062601E707070092C0E70500C0C0DF97CF170057001702D70900C0E777010092C00AC1E757FFFFFA050DC0E7570000FA050FC09FAFC600E70500C0C805C105C005C0DF97CF27DAFA05EF0701000B0673CF9FAF78019FAF1A036ECFE709FC052401E70902062601E707070092C0E709FC05FE05E70902060406E7090006FC05E709FE05000627DAFA05E7570100FA0502CA04C097CF9FAF660597CFE70740000206C809FC059FAFDA0297CFCF170200EF57810009069FA0B601EF57800009069FA04002EF5701000B069FA04603E70701000AC046AF47AF9FAF4002E7072E000AC0EF878000090697CF000E0100C05751009FC09E02C057500020C0C057550012C0C05756009FC072029FCFD602C10B080601D06F900806C0070800C10B08069FAF280597CF2F0E02000806C0070800C10B08069FAF28059FCFD6022F0E02000906EF87800009069FCFD602EF677FFF0906E767FFFD22C0E767EFFF24C0E787100028C09FAFB805E787E02124C09FAFA805E787080024C0E767DFFF24C0C8070A00C0070000C10701009FAF28059FAFB805C0079E009FAF4405E767FFFE24C0C00920C0E787000124C0C07700020FC1E767F7FF24C0E767F7FF24C0E787080024C008DA5EC1EF078000090697CFEF0701000A0697CFEF0700000B06EF0700000A06EF677FFF0906EF0700000D06E767EFFF28C0E76717D824C0E70700001EC0E707FFFF22C097CFC8070E069FAFDA02E7070000F205E7071000F605E7070E06F405E707D602F805C807F205C107008050AF97CF2F0C020007062F0C04000606E7070000F205E7071000F605E707E205F405E707CE02F805C807F205C107008051AF97CF9FAF66049FAF1A0359AF97CFC0070E00C10B0C0641D19FAF2805C0073C009FAF44056800C0073B009FAF44056F000C066800E0070401E80B0A06E8070000E0070002E007EC01E007FCFF97CFE707FFFFFA05EF0700000B06E7070E062401E7070E06FE05E70740002601E70740000406E707070092C097CFEF0702000B069FAF7801EF77800007069FC01404EF770100070637C0EF7701000D060FC1EF0701000D06C0070200C10730009FAF2805C0070100C10702009FAF2805C807FF4F9FAFA805C00738009FAF4405C177030002C108DA75C1C17701000AC1C0070100C10702009FAF2805EF07010006062CCFC0070100C10704009FAF2805EF070000060622CFEF0700000D06EF57010006061BC0C0070100C10701009FAF2805C0070200C10730009FAF2805C807FF4F9FAFA805C00738009FAF4405C1670300C157030002C008DA73C1C0070200C1071200EF570000060602C0C10723009FAF2805C0071400C10BEA059FAF2805C0073E009FAF0A05E709E405FA0527D8FA05E7070E06FC05E7074E060006E707400002069FAF66059FAFC60097CFC10BE20541D001D2C11723009FAFDC04C0070400C10BE3059FAF2805C0070600C109E6059FAF2805C0070700C109E605C1D19FAF2805C0070B00C109E8059FAF2805C0070C00C109E805C1D19FAF2805C0070D00C10709009FAF2805C0070300C10732009FAF2805C0070F00C10700009FAF280597CFE767FFD924C0C8070A004000C0670002278024C0E787000424C0E767FFF924C001D208DA72C1E787002024C097CF27001EC0E787FF0022C0E7677FFF24C0E787800024C0E787800024C097CF9FAF0A0567001EC0E767BFFF24C0E787400024C0E787400024C097CF9FAF0A05E76700FF22C0E767FFFE24C0E767FFFE24C0C10920C0E787000124C097CFC0074000C809FC05E76700FF22C0E767FFFE24C0E767BFFF24C0E767BFFF24C000DAE80920C0E787400024C0E787400024C000DAE80920C06DC1E787000124C097CFE707320012C0E777008012C07CC097CFE707204E12C0E777008012C07CC097CF0902190001010080960904000001000000000705810240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A1 -:0136000000B6C32F0103640E0014001A00200026004A0064006A0092009A00A000B200B800BE00C200C800CE00DC00DA00E200E000E800E600EE00EC00F200F80002010A010E0112011E01220128012C0132013601440150015E01720176017A01800188018C0194019C01A001A401AA01B001B401BA01D001DA01F601FA01020234023C0244024A0250025602740278027E0284028A02880290028E029402A202A802AE02B402BA02B802C002BE02C402D002D402E002E602EE02F802FC0206031E032403280330032E033C034A034E03540358035E0366036E037A0386038E039603B203B803C603CC03D403DA03E803F403FC03040420042A04320436043E044404420448044E044C04540452045A045E046204680474047C04800488048C0494049A04A204A604AE04B404C004CC04D8042A0546056C0500005E -:0008000000B6C301000664000014 -:0000000001FF diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/.gitignore v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/.gitignore --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/.gitignore 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -linux-media.tar.bz2* -.patches_applied -.linked_dir -.git_log.md5 -git_log -drivers/ -firmware/ -include/ -sound/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/git_log v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/git_log --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/git_log 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/git_log 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -f772f016e15a0b93b5aa9680203107ab8cb9bdc6 [media] media-devnode: don't depend on BKL stuff -a871fbb3014f3d64c926b19f3b7503350d0cb22e [media] videobuf2-dma-contig: make cookie() return a pointer to dma_addr_t -9c9dcf95c9ecafbe68a27046290f64d7ae3f1af7 [media] sh_mobile_ceu_camera: Do not call vb2's mem_ops directly diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/audio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/audio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/audio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/audio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -/* - * audio.h - * - * Copyright (C) 2000 Ralph Metzler - * & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Lesser Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVBAUDIO_H_ -#define _DVBAUDIO_H_ - -#include - -typedef enum { - AUDIO_SOURCE_DEMUX, /* Select the demux as the main source */ - AUDIO_SOURCE_MEMORY /* Select internal memory as the main source */ -} audio_stream_source_t; - - -typedef enum { - AUDIO_STOPPED, /* Device is stopped */ - AUDIO_PLAYING, /* Device is currently playing */ - AUDIO_PAUSED /* Device is paused */ -} audio_play_state_t; - - -typedef enum { - AUDIO_STEREO, - AUDIO_MONO_LEFT, - AUDIO_MONO_RIGHT, - AUDIO_MONO, - AUDIO_STEREO_SWAPPED -} audio_channel_select_t; - - -typedef struct audio_mixer { - unsigned int volume_left; - unsigned int volume_right; - // what else do we need? bass, pass-through, ... -} audio_mixer_t; - - -typedef struct audio_status { - int AV_sync_state; /* sync audio and video? */ - int mute_state; /* audio is muted */ - audio_play_state_t play_state; /* current playback state */ - audio_stream_source_t stream_source; /* current stream source */ - audio_channel_select_t channel_select; /* currently selected channel */ - int bypass_mode; /* pass on audio data to */ - audio_mixer_t mixer_state; /* current mixer state */ -} audio_status_t; /* separate decoder hardware */ - - -typedef -struct audio_karaoke{ /* if Vocal1 or Vocal2 are non-zero, they get mixed */ - int vocal1; /* into left and right t at 70% each */ - int vocal2; /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/ - int melody; /* mixed into the left channel and */ - /* Vocal2 into the right channel at 100% each. */ - /* if Melody is non-zero, the melody channel gets mixed*/ -} audio_karaoke_t; /* into left and right */ - - -typedef __u16 audio_attributes_t; -/* bits: descr. */ -/* 15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, */ -/* 12 multichannel extension */ -/* 11-10 audio type (0=not spec, 1=language included) */ -/* 9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) */ -/* 7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit, */ -/* 5- 4 Sample frequency fs (0=48kHz, 1=96kHz) */ -/* 2- 0 number of audio channels (n+1 channels) */ - - -/* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */ -#define AUDIO_CAP_DTS 1 -#define AUDIO_CAP_LPCM 2 -#define AUDIO_CAP_MP1 4 -#define AUDIO_CAP_MP2 8 -#define AUDIO_CAP_MP3 16 -#define AUDIO_CAP_AAC 32 -#define AUDIO_CAP_OGG 64 -#define AUDIO_CAP_SDDS 128 -#define AUDIO_CAP_AC3 256 - -#define AUDIO_STOP _IO('o', 1) -#define AUDIO_PLAY _IO('o', 2) -#define AUDIO_PAUSE _IO('o', 3) -#define AUDIO_CONTINUE _IO('o', 4) -#define AUDIO_SELECT_SOURCE _IO('o', 5) -#define AUDIO_SET_MUTE _IO('o', 6) -#define AUDIO_SET_AV_SYNC _IO('o', 7) -#define AUDIO_SET_BYPASS_MODE _IO('o', 8) -#define AUDIO_CHANNEL_SELECT _IO('o', 9) -#define AUDIO_GET_STATUS _IOR('o', 10, audio_status_t) - -#define AUDIO_GET_CAPABILITIES _IOR('o', 11, unsigned int) -#define AUDIO_CLEAR_BUFFER _IO('o', 12) -#define AUDIO_SET_ID _IO('o', 13) -#define AUDIO_SET_MIXER _IOW('o', 14, audio_mixer_t) -#define AUDIO_SET_STREAMTYPE _IO('o', 15) -#define AUDIO_SET_EXT_ID _IO('o', 16) -#define AUDIO_SET_ATTRIBUTES _IOW('o', 17, audio_attributes_t) -#define AUDIO_SET_KARAOKE _IOW('o', 18, audio_karaoke_t) - -/** - * AUDIO_GET_PTS - * - * Read the 33 bit presentation time stamp as defined - * in ITU T-REC-H.222.0 / ISO/IEC 13818-1. - * - * The PTS should belong to the currently played - * frame if possible, but may also be a value close to it - * like the PTS of the last decoded frame or the last PTS - * extracted by the PES parser. - */ -#define AUDIO_GET_PTS _IOR('o', 19, __u64) -#define AUDIO_BILINGUAL_CHANNEL_SELECT _IO('o', 20) - -#endif /* _DVBAUDIO_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/ca.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/ca.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/ca.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/ca.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -/* - * ca.h - * - * Copyright (C) 2000 Ralph Metzler - * & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Lesser Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVBCA_H_ -#define _DVBCA_H_ - -/* slot interface types and info */ - -typedef struct ca_slot_info { - int num; /* slot number */ - - int type; /* CA interface this slot supports */ -#define CA_CI 1 /* CI high level interface */ -#define CA_CI_LINK 2 /* CI link layer level interface */ -#define CA_CI_PHYS 4 /* CI physical layer level interface */ -#define CA_DESCR 8 /* built-in descrambler */ -#define CA_SC 128 /* simple smart card interface */ - - unsigned int flags; -#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */ -#define CA_CI_MODULE_READY 2 -} ca_slot_info_t; - - -/* descrambler types and info */ - -typedef struct ca_descr_info { - unsigned int num; /* number of available descramblers (keys) */ - unsigned int type; /* type of supported scrambling system */ -#define CA_ECD 1 -#define CA_NDS 2 -#define CA_DSS 4 -} ca_descr_info_t; - -typedef struct ca_caps { - unsigned int slot_num; /* total number of CA card and module slots */ - unsigned int slot_type; /* OR of all supported types */ - unsigned int descr_num; /* total number of descrambler slots (keys) */ - unsigned int descr_type; /* OR of all supported types */ -} ca_caps_t; - -/* a message to/from a CI-CAM */ -typedef struct ca_msg { - unsigned int index; - unsigned int type; - unsigned int length; - unsigned char msg[256]; -} ca_msg_t; - -typedef struct ca_descr { - unsigned int index; - unsigned int parity; /* 0 == even, 1 == odd */ - unsigned char cw[8]; -} ca_descr_t; - -typedef struct ca_pid { - unsigned int pid; - int index; /* -1 == disable*/ -} ca_pid_t; - -#define CA_RESET _IO('o', 128) -#define CA_GET_CAP _IOR('o', 129, ca_caps_t) -#define CA_GET_SLOT_INFO _IOR('o', 130, ca_slot_info_t) -#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t) -#define CA_GET_MSG _IOR('o', 132, ca_msg_t) -#define CA_SEND_MSG _IOW('o', 133, ca_msg_t) -#define CA_SET_DESCR _IOW('o', 134, ca_descr_t) -#define CA_SET_PID _IOW('o', 135, ca_pid_t) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/dmx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/dmx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/dmx.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/dmx.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -/* - * dmx.h - * - * Copyright (C) 2000 Marcus Metzler - * & Ralph Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVBDMX_H_ -#define _DVBDMX_H_ - -#include -#ifdef __KERNEL__ -#include -#else -#include -#endif - - -#define DMX_FILTER_SIZE 16 - -typedef enum -{ - DMX_OUT_DECODER, /* Streaming directly to decoder. */ - DMX_OUT_TAP, /* Output going to a memory buffer */ - /* (to be retrieved via the read command).*/ - DMX_OUT_TS_TAP, /* Output multiplexed into a new TS */ - /* (to be retrieved by reading from the */ - /* logical DVR device). */ - DMX_OUT_TSDEMUX_TAP /* Like TS_TAP but retrieved from the DMX device */ -} dmx_output_t; - - -typedef enum -{ - DMX_IN_FRONTEND, /* Input from a front-end device. */ - DMX_IN_DVR /* Input from the logical DVR device. */ -} dmx_input_t; - - -typedef enum -{ - DMX_PES_AUDIO0, - DMX_PES_VIDEO0, - DMX_PES_TELETEXT0, - DMX_PES_SUBTITLE0, - DMX_PES_PCR0, - - DMX_PES_AUDIO1, - DMX_PES_VIDEO1, - DMX_PES_TELETEXT1, - DMX_PES_SUBTITLE1, - DMX_PES_PCR1, - - DMX_PES_AUDIO2, - DMX_PES_VIDEO2, - DMX_PES_TELETEXT2, - DMX_PES_SUBTITLE2, - DMX_PES_PCR2, - - DMX_PES_AUDIO3, - DMX_PES_VIDEO3, - DMX_PES_TELETEXT3, - DMX_PES_SUBTITLE3, - DMX_PES_PCR3, - - DMX_PES_OTHER -} dmx_pes_type_t; - -#define DMX_PES_AUDIO DMX_PES_AUDIO0 -#define DMX_PES_VIDEO DMX_PES_VIDEO0 -#define DMX_PES_TELETEXT DMX_PES_TELETEXT0 -#define DMX_PES_SUBTITLE DMX_PES_SUBTITLE0 -#define DMX_PES_PCR DMX_PES_PCR0 - - -typedef struct dmx_filter -{ - __u8 filter[DMX_FILTER_SIZE]; - __u8 mask[DMX_FILTER_SIZE]; - __u8 mode[DMX_FILTER_SIZE]; -} dmx_filter_t; - - -struct dmx_sct_filter_params -{ - __u16 pid; - dmx_filter_t filter; - __u32 timeout; - __u32 flags; -#define DMX_CHECK_CRC 1 -#define DMX_ONESHOT 2 -#define DMX_IMMEDIATE_START 4 -#define DMX_KERNEL_CLIENT 0x8000 -}; - - -struct dmx_pes_filter_params -{ - __u16 pid; - dmx_input_t input; - dmx_output_t output; - dmx_pes_type_t pes_type; - __u32 flags; -}; - -typedef struct dmx_caps { - __u32 caps; - int num_decoders; -} dmx_caps_t; - -typedef enum { - DMX_SOURCE_FRONT0 = 0, - DMX_SOURCE_FRONT1, - DMX_SOURCE_FRONT2, - DMX_SOURCE_FRONT3, - DMX_SOURCE_DVR0 = 16, - DMX_SOURCE_DVR1, - DMX_SOURCE_DVR2, - DMX_SOURCE_DVR3 -} dmx_source_t; - -struct dmx_stc { - unsigned int num; /* input : which STC? 0..N */ - unsigned int base; /* output: divisor for stc to get 90 kHz clock */ - __u64 stc; /* output: stc in 'base'*90 kHz units */ -}; - - -#define DMX_START _IO('o', 41) -#define DMX_STOP _IO('o', 42) -#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params) -#define DMX_SET_PES_FILTER _IOW('o', 44, struct dmx_pes_filter_params) -#define DMX_SET_BUFFER_SIZE _IO('o', 45) -#define DMX_GET_PES_PIDS _IOR('o', 47, __u16[5]) -#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t) -#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t) -#define DMX_GET_STC _IOWR('o', 50, struct dmx_stc) -#define DMX_ADD_PID _IOW('o', 51, __u16) -#define DMX_REMOVE_PID _IOW('o', 52, __u16) - -#endif /*_DVBDMX_H_*/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/frontend.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/frontend.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/frontend.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/frontend.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,414 +0,0 @@ -/* - * frontend.h - * - * Copyright (C) 2000 Marcus Metzler - * Ralph Metzler - * Holger Waechtler - * Andre Draszik - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVBFRONTEND_H_ -#define _DVBFRONTEND_H_ - -#include - -typedef enum fe_type { - FE_QPSK, - FE_QAM, - FE_OFDM, - FE_ATSC -} fe_type_t; - - -typedef enum fe_caps { - FE_IS_STUPID = 0, - FE_CAN_INVERSION_AUTO = 0x1, - FE_CAN_FEC_1_2 = 0x2, - FE_CAN_FEC_2_3 = 0x4, - FE_CAN_FEC_3_4 = 0x8, - FE_CAN_FEC_4_5 = 0x10, - FE_CAN_FEC_5_6 = 0x20, - FE_CAN_FEC_6_7 = 0x40, - FE_CAN_FEC_7_8 = 0x80, - FE_CAN_FEC_8_9 = 0x100, - FE_CAN_FEC_AUTO = 0x200, - FE_CAN_QPSK = 0x400, - FE_CAN_QAM_16 = 0x800, - FE_CAN_QAM_32 = 0x1000, - FE_CAN_QAM_64 = 0x2000, - FE_CAN_QAM_128 = 0x4000, - FE_CAN_QAM_256 = 0x8000, - FE_CAN_QAM_AUTO = 0x10000, - FE_CAN_TRANSMISSION_MODE_AUTO = 0x20000, - FE_CAN_BANDWIDTH_AUTO = 0x40000, - FE_CAN_GUARD_INTERVAL_AUTO = 0x80000, - FE_CAN_HIERARCHY_AUTO = 0x100000, - FE_CAN_8VSB = 0x200000, - FE_CAN_16VSB = 0x400000, - FE_HAS_EXTENDED_CAPS = 0x800000, /* We need more bitspace for newer APIs, indicate this. */ - FE_CAN_TURBO_FEC = 0x8000000, /* frontend supports "turbo fec modulation" */ - FE_CAN_2G_MODULATION = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */ - FE_NEEDS_BENDING = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */ - FE_CAN_RECOVER = 0x40000000, /* frontend can recover from a cable unplug automatically */ - FE_CAN_MUTE_TS = 0x80000000 /* frontend can stop spurious TS data output */ -} fe_caps_t; - - -struct dvb_frontend_info { - char name[128]; - fe_type_t type; - __u32 frequency_min; - __u32 frequency_max; - __u32 frequency_stepsize; - __u32 frequency_tolerance; - __u32 symbol_rate_min; - __u32 symbol_rate_max; - __u32 symbol_rate_tolerance; /* ppm */ - __u32 notifier_delay; /* DEPRECATED */ - fe_caps_t caps; -}; - - -/** - * Check out the DiSEqC bus spec available on http://www.eutelsat.org/ for - * the meaning of this struct... - */ -struct dvb_diseqc_master_cmd { - __u8 msg [6]; /* { framing, address, command, data [3] } */ - __u8 msg_len; /* valid values are 3...6 */ -}; - - -struct dvb_diseqc_slave_reply { - __u8 msg [4]; /* { framing, data [3] } */ - __u8 msg_len; /* valid values are 0...4, 0 means no msg */ - int timeout; /* return from ioctl after timeout ms with */ -}; /* errorcode when no message was received */ - - -typedef enum fe_sec_voltage { - SEC_VOLTAGE_13, - SEC_VOLTAGE_18, - SEC_VOLTAGE_OFF -} fe_sec_voltage_t; - - -typedef enum fe_sec_tone_mode { - SEC_TONE_ON, - SEC_TONE_OFF -} fe_sec_tone_mode_t; - - -typedef enum fe_sec_mini_cmd { - SEC_MINI_A, - SEC_MINI_B -} fe_sec_mini_cmd_t; - - -typedef enum fe_status { - FE_HAS_SIGNAL = 0x01, /* found something above the noise level */ - FE_HAS_CARRIER = 0x02, /* found a DVB signal */ - FE_HAS_VITERBI = 0x04, /* FEC is stable */ - FE_HAS_SYNC = 0x08, /* found sync bytes */ - FE_HAS_LOCK = 0x10, /* everything's working... */ - FE_TIMEDOUT = 0x20, /* no lock within the last ~2 seconds */ - FE_REINIT = 0x40 /* frontend was reinitialized, */ -} fe_status_t; /* application is recommended to reset */ - /* DiSEqC, tone and parameters */ - -typedef enum fe_spectral_inversion { - INVERSION_OFF, - INVERSION_ON, - INVERSION_AUTO -} fe_spectral_inversion_t; - - -typedef enum fe_code_rate { - FEC_NONE = 0, - FEC_1_2, - FEC_2_3, - FEC_3_4, - FEC_4_5, - FEC_5_6, - FEC_6_7, - FEC_7_8, - FEC_8_9, - FEC_AUTO, - FEC_3_5, - FEC_9_10, -} fe_code_rate_t; - - -typedef enum fe_modulation { - QPSK, - QAM_16, - QAM_32, - QAM_64, - QAM_128, - QAM_256, - QAM_AUTO, - VSB_8, - VSB_16, - PSK_8, - APSK_16, - APSK_32, - DQPSK, -} fe_modulation_t; - -typedef enum fe_transmit_mode { - TRANSMISSION_MODE_2K, - TRANSMISSION_MODE_8K, - TRANSMISSION_MODE_AUTO, - TRANSMISSION_MODE_4K -} fe_transmit_mode_t; - -typedef enum fe_bandwidth { - BANDWIDTH_8_MHZ, - BANDWIDTH_7_MHZ, - BANDWIDTH_6_MHZ, - BANDWIDTH_AUTO -} fe_bandwidth_t; - - -typedef enum fe_guard_interval { - GUARD_INTERVAL_1_32, - GUARD_INTERVAL_1_16, - GUARD_INTERVAL_1_8, - GUARD_INTERVAL_1_4, - GUARD_INTERVAL_AUTO -} fe_guard_interval_t; - - -typedef enum fe_hierarchy { - HIERARCHY_NONE, - HIERARCHY_1, - HIERARCHY_2, - HIERARCHY_4, - HIERARCHY_AUTO -} fe_hierarchy_t; - - -struct dvb_qpsk_parameters { - __u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec_inner; /* forward error correction (see above) */ -}; - -struct dvb_qam_parameters { - __u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec_inner; /* forward error correction (see above) */ - fe_modulation_t modulation; /* modulation type (see above) */ -}; - -struct dvb_vsb_parameters { - fe_modulation_t modulation; /* modulation type (see above) */ -}; - -struct dvb_ofdm_parameters { - fe_bandwidth_t bandwidth; - fe_code_rate_t code_rate_HP; /* high priority stream code rate */ - fe_code_rate_t code_rate_LP; /* low priority stream code rate */ - fe_modulation_t constellation; /* modulation type (see above) */ - fe_transmit_mode_t transmission_mode; - fe_guard_interval_t guard_interval; - fe_hierarchy_t hierarchy_information; -}; - - -struct dvb_frontend_parameters { - __u32 frequency; /* (absolute) frequency in Hz for QAM/OFDM/ATSC */ - /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; - union { - struct dvb_qpsk_parameters qpsk; - struct dvb_qam_parameters qam; - struct dvb_ofdm_parameters ofdm; - struct dvb_vsb_parameters vsb; - } u; -}; - - -struct dvb_frontend_event { - fe_status_t status; - struct dvb_frontend_parameters parameters; -}; - -/* S2API Commands */ -#define DTV_UNDEFINED 0 -#define DTV_TUNE 1 -#define DTV_CLEAR 2 -#define DTV_FREQUENCY 3 -#define DTV_MODULATION 4 -#define DTV_BANDWIDTH_HZ 5 -#define DTV_INVERSION 6 -#define DTV_DISEQC_MASTER 7 -#define DTV_SYMBOL_RATE 8 -#define DTV_INNER_FEC 9 -#define DTV_VOLTAGE 10 -#define DTV_TONE 11 -#define DTV_PILOT 12 -#define DTV_ROLLOFF 13 -#define DTV_DISEQC_SLAVE_REPLY 14 - -/* Basic enumeration set for querying unlimited capabilities */ -#define DTV_FE_CAPABILITY_COUNT 15 -#define DTV_FE_CAPABILITY 16 -#define DTV_DELIVERY_SYSTEM 17 - -/* ISDB-T and ISDB-Tsb */ -#define DTV_ISDBT_PARTIAL_RECEPTION 18 -#define DTV_ISDBT_SOUND_BROADCASTING 19 - -#define DTV_ISDBT_SB_SUBCHANNEL_ID 20 -#define DTV_ISDBT_SB_SEGMENT_IDX 21 -#define DTV_ISDBT_SB_SEGMENT_COUNT 22 - -#define DTV_ISDBT_LAYERA_FEC 23 -#define DTV_ISDBT_LAYERA_MODULATION 24 -#define DTV_ISDBT_LAYERA_SEGMENT_COUNT 25 -#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING 26 - -#define DTV_ISDBT_LAYERB_FEC 27 -#define DTV_ISDBT_LAYERB_MODULATION 28 -#define DTV_ISDBT_LAYERB_SEGMENT_COUNT 29 -#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING 30 - -#define DTV_ISDBT_LAYERC_FEC 31 -#define DTV_ISDBT_LAYERC_MODULATION 32 -#define DTV_ISDBT_LAYERC_SEGMENT_COUNT 33 -#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING 34 - -#define DTV_API_VERSION 35 - -#define DTV_CODE_RATE_HP 36 -#define DTV_CODE_RATE_LP 37 -#define DTV_GUARD_INTERVAL 38 -#define DTV_TRANSMISSION_MODE 39 -#define DTV_HIERARCHY 40 - -#define DTV_ISDBT_LAYER_ENABLED 41 - -#define DTV_ISDBS_TS_ID 42 - -#define DTV_MAX_COMMAND DTV_ISDBS_TS_ID - -typedef enum fe_pilot { - PILOT_ON, - PILOT_OFF, - PILOT_AUTO, -} fe_pilot_t; - -typedef enum fe_rolloff { - ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */ - ROLLOFF_20, - ROLLOFF_25, - ROLLOFF_AUTO, -} fe_rolloff_t; - -typedef enum fe_delivery_system { - SYS_UNDEFINED, - SYS_DVBC_ANNEX_AC, - SYS_DVBC_ANNEX_B, - SYS_DVBT, - SYS_DSS, - SYS_DVBS, - SYS_DVBS2, - SYS_DVBH, - SYS_ISDBT, - SYS_ISDBS, - SYS_ISDBC, - SYS_ATSC, - SYS_ATSCMH, - SYS_DMBTH, - SYS_CMMB, - SYS_DAB, -} fe_delivery_system_t; - -struct dtv_cmds_h { - char *name; /* A display name for debugging purposes */ - - __u32 cmd; /* A unique ID */ - - /* Flags */ - __u32 set:1; /* Either a set or get property */ - __u32 buffer:1; /* Does this property use the buffer? */ - __u32 reserved:30; /* Align */ -}; - -struct dtv_property { - __u32 cmd; - __u32 reserved[3]; - union { - __u32 data; - struct { - __u8 data[32]; - __u32 len; - __u32 reserved1[3]; - void *reserved2; - } buffer; - } u; - int result; -} __attribute__ ((packed)); - -/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */ -#define DTV_IOCTL_MAX_MSGS 64 - -struct dtv_properties { - __u32 num; - struct dtv_property *props; -}; - -#define FE_SET_PROPERTY _IOW('o', 82, struct dtv_properties) -#define FE_GET_PROPERTY _IOR('o', 83, struct dtv_properties) - - -/** - * When set, this flag will disable any zigzagging or other "normal" tuning - * behaviour. Additionally, there will be no automatic monitoring of the lock - * status, and hence no frontend events will be generated. If a frontend device - * is closed, this flag will be automatically turned off when the device is - * reopened read-write. - */ -#define FE_TUNE_MODE_ONESHOT 0x01 - - -#define FE_GET_INFO _IOR('o', 61, struct dvb_frontend_info) - -#define FE_DISEQC_RESET_OVERLOAD _IO('o', 62) -#define FE_DISEQC_SEND_MASTER_CMD _IOW('o', 63, struct dvb_diseqc_master_cmd) -#define FE_DISEQC_RECV_SLAVE_REPLY _IOR('o', 64, struct dvb_diseqc_slave_reply) -#define FE_DISEQC_SEND_BURST _IO('o', 65) /* fe_sec_mini_cmd_t */ - -#define FE_SET_TONE _IO('o', 66) /* fe_sec_tone_mode_t */ -#define FE_SET_VOLTAGE _IO('o', 67) /* fe_sec_voltage_t */ -#define FE_ENABLE_HIGH_LNB_VOLTAGE _IO('o', 68) /* int */ - -#define FE_READ_STATUS _IOR('o', 69, fe_status_t) -#define FE_READ_BER _IOR('o', 70, __u32) -#define FE_READ_SIGNAL_STRENGTH _IOR('o', 71, __u16) -#define FE_READ_SNR _IOR('o', 72, __u16) -#define FE_READ_UNCORRECTED_BLOCKS _IOR('o', 73, __u32) - -#define FE_SET_FRONTEND _IOW('o', 76, struct dvb_frontend_parameters) -#define FE_GET_FRONTEND _IOR('o', 77, struct dvb_frontend_parameters) -#define FE_SET_FRONTEND_TUNE_MODE _IO('o', 81) /* unsigned int */ -#define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event) - -#define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */ - -#endif /*_DVBFRONTEND_H_*/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/net.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/net.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/net.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/net.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * net.h - * - * Copyright (C) 2000 Marcus Metzler - * & Ralph Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVBNET_H_ -#define _DVBNET_H_ - -#include - -struct dvb_net_if { - __u16 pid; - __u16 if_num; - __u8 feedtype; -#define DVB_NET_FEEDTYPE_MPE 0 /* multi protocol encapsulation */ -#define DVB_NET_FEEDTYPE_ULE 1 /* ultra lightweight encapsulation */ -}; - - -#define NET_ADD_IF _IOWR('o', 52, struct dvb_net_if) -#define NET_REMOVE_IF _IO('o', 53) -#define NET_GET_IF _IOWR('o', 54, struct dvb_net_if) - - -/* binary compatibility cruft: */ -struct __dvb_net_if_old { - __u16 pid; - __u16 if_num; -}; -#define __NET_ADD_IF_OLD _IOWR('o', 52, struct __dvb_net_if_old) -#define __NET_GET_IF_OLD _IOWR('o', 54, struct __dvb_net_if_old) - - -#endif /*_DVBNET_H_*/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/osd.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/osd.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/osd.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/osd.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,144 +0,0 @@ -/* - * osd.h - * - * Copyright (C) 2001 Ralph Metzler - * & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Lesser Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVBOSD_H_ -#define _DVBOSD_H_ - -#include - -typedef enum { - // All functions return -2 on "not open" - OSD_Close=1, // () - // Disables OSD and releases the buffers - // returns 0 on success - OSD_Open, // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) - // Opens OSD with this size and bit depth - // returns 0 on success, -1 on DRAM allocation error, -2 on "already open" - OSD_Show, // () - // enables OSD mode - // returns 0 on success - OSD_Hide, // () - // disables OSD mode - // returns 0 on success - OSD_Clear, // () - // Sets all pixel to color 0 - // returns 0 on success - OSD_Fill, // (color) - // Sets all pixel to color - // returns 0 on success - OSD_SetColor, // (color,R{x0},G{y0},B{x1},opacity{y1}) - // set palette entry to , and apply - // R,G,B: 0..255 - // R=Red, G=Green, B=Blue - // opacity=0: pixel opacity 0% (only video pixel shows) - // opacity=1..254: pixel opacity as specified in header - // opacity=255: pixel opacity 100% (only OSD pixel shows) - // returns 0 on success, -1 on error - OSD_SetPalette, // (firstcolor{color},lastcolor{x0},data) - // Set a number of entries in the palette - // sets the entries "firstcolor" through "lastcolor" from the array "data" - // data has 4 byte for each color: - // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel - OSD_SetTrans, // (transparency{color}) - // Sets transparency of mixed pixel (0..15) - // returns 0 on success - OSD_SetPixel, // (x0,y0,color) - // sets pixel , to color number - // returns 0 on success, -1 on error - OSD_GetPixel, // (x0,y0) - // returns color number of pixel ,, or -1 - OSD_SetRow, // (x0,y0,x1,data) - // fills pixels x0,y through x1,y with the content of data[] - // returns 0 on success, -1 on clipping all pixel (no pixel drawn) - OSD_SetBlock, // (x0,y0,x1,y1,increment{color},data) - // fills pixels x0,y0 through x1,y1 with the content of data[] - // inc contains the width of one line in the data block, - // inc<=0 uses blockwidth as linewidth - // returns 0 on success, -1 on clipping all pixel - OSD_FillRow, // (x0,y0,x1,color) - // fills pixels x0,y through x1,y with the color - // returns 0 on success, -1 on clipping all pixel - OSD_FillBlock, // (x0,y0,x1,y1,color) - // fills pixels x0,y0 through x1,y1 with the color - // returns 0 on success, -1 on clipping all pixel - OSD_Line, // (x0,y0,x1,y1,color) - // draw a line from x0,y0 to x1,y1 with the color - // returns 0 on success - OSD_Query, // (x0,y0,x1,y1,xasp{color}}), yasp=11 - // fills parameters with the picture dimensions and the pixel aspect ratio - // returns 0 on success - OSD_Test, // () - // draws a test picture. for debugging purposes only - // returns 0 on success -// TODO: remove "test" in final version - OSD_Text, // (x0,y0,size,color,text) - OSD_SetWindow, // (x0) set window with number 0 - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVBVERSION_H_ -#define _DVBVERSION_H_ - -#define DVB_API_VERSION 5 -#define DVB_API_VERSION_MINOR 2 - -#endif /*_DVBVERSION_H_*/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/video.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/video.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/video.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/dvb/video.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,276 +0,0 @@ -/* - * video.h - * - * Copyright (C) 2000 Marcus Metzler - * & Ralph Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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 Lesser 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. - * - */ - -#ifndef _DVBVIDEO_H_ -#define _DVBVIDEO_H_ - -#include -#ifdef __KERNEL__ -#include -#else -#include -#include -#endif - -typedef enum { - VIDEO_FORMAT_4_3, /* Select 4:3 format */ - VIDEO_FORMAT_16_9, /* Select 16:9 format. */ - VIDEO_FORMAT_221_1 /* 2.21:1 */ -} video_format_t; - - -typedef enum { - VIDEO_SYSTEM_PAL, - VIDEO_SYSTEM_NTSC, - VIDEO_SYSTEM_PALN, - VIDEO_SYSTEM_PALNc, - VIDEO_SYSTEM_PALM, - VIDEO_SYSTEM_NTSC60, - VIDEO_SYSTEM_PAL60, - VIDEO_SYSTEM_PALM60 -} video_system_t; - - -typedef enum { - VIDEO_PAN_SCAN, /* use pan and scan format */ - VIDEO_LETTER_BOX, /* use letterbox format */ - VIDEO_CENTER_CUT_OUT /* use center cut out format */ -} video_displayformat_t; - -typedef struct { - int w; - int h; - video_format_t aspect_ratio; -} video_size_t; - -typedef enum { - VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ - VIDEO_SOURCE_MEMORY /* If this source is selected, the stream - comes from the user through the write - system call */ -} video_stream_source_t; - - -typedef enum { - VIDEO_STOPPED, /* Video is stopped */ - VIDEO_PLAYING, /* Video is currently playing */ - VIDEO_FREEZED /* Video is freezed */ -} video_play_state_t; - - -/* Decoder commands */ -#define VIDEO_CMD_PLAY (0) -#define VIDEO_CMD_STOP (1) -#define VIDEO_CMD_FREEZE (2) -#define VIDEO_CMD_CONTINUE (3) - -/* Flags for VIDEO_CMD_FREEZE */ -#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0) - -/* Flags for VIDEO_CMD_STOP */ -#define VIDEO_CMD_STOP_TO_BLACK (1 << 0) -#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1) - -/* Play input formats: */ -/* The decoder has no special format requirements */ -#define VIDEO_PLAY_FMT_NONE (0) -/* The decoder requires full GOPs */ -#define VIDEO_PLAY_FMT_GOP (1) - -/* The structure must be zeroed before use by the application - This ensures it can be extended safely in the future. */ -struct video_command { - __u32 cmd; - __u32 flags; - union { - struct { - __u64 pts; - } stop; - - struct { - /* 0 or 1000 specifies normal speed, - 1 specifies forward single stepping, - -1 specifies backward single stepping, - >1: playback at speed/1000 of the normal speed, - <-1: reverse playback at (-speed/1000) of the normal speed. */ - __s32 speed; - __u32 format; - } play; - - struct { - __u32 data[16]; - } raw; - }; -}; - -/* FIELD_UNKNOWN can be used if the hardware does not know whether - the Vsync is for an odd, even or progressive (i.e. non-interlaced) - field. */ -#define VIDEO_VSYNC_FIELD_UNKNOWN (0) -#define VIDEO_VSYNC_FIELD_ODD (1) -#define VIDEO_VSYNC_FIELD_EVEN (2) -#define VIDEO_VSYNC_FIELD_PROGRESSIVE (3) - -struct video_event { - __s32 type; -#define VIDEO_EVENT_SIZE_CHANGED 1 -#define VIDEO_EVENT_FRAME_RATE_CHANGED 2 -#define VIDEO_EVENT_DECODER_STOPPED 3 -#define VIDEO_EVENT_VSYNC 4 - __kernel_time_t timestamp; - union { - video_size_t size; - unsigned int frame_rate; /* in frames per 1000sec */ - unsigned char vsync_field; /* unknown/odd/even/progressive */ - } u; -}; - - -struct video_status { - int video_blank; /* blank video on freeze? */ - video_play_state_t play_state; /* current state of playback */ - video_stream_source_t stream_source; /* current source (demux/memory) */ - video_format_t video_format; /* current aspect ratio of stream*/ - video_displayformat_t display_format;/* selected cropping mode */ -}; - - -struct video_still_picture { - char __user *iFrame; /* pointer to a single iframe in memory */ - __s32 size; -}; - - -typedef -struct video_highlight { - int active; /* 1=show highlight, 0=hide highlight */ - __u8 contrast1; /* 7- 4 Pattern pixel contrast */ - /* 3- 0 Background pixel contrast */ - __u8 contrast2; /* 7- 4 Emphasis pixel-2 contrast */ - /* 3- 0 Emphasis pixel-1 contrast */ - __u8 color1; /* 7- 4 Pattern pixel color */ - /* 3- 0 Background pixel color */ - __u8 color2; /* 7- 4 Emphasis pixel-2 color */ - /* 3- 0 Emphasis pixel-1 color */ - __u32 ypos; /* 23-22 auto action mode */ - /* 21-12 start y */ - /* 9- 0 end y */ - __u32 xpos; /* 23-22 button color number */ - /* 21-12 start x */ - /* 9- 0 end x */ -} video_highlight_t; - - -typedef struct video_spu { - int active; - int stream_id; -} video_spu_t; - - -typedef struct video_spu_palette { /* SPU Palette information */ - int length; - __u8 __user *palette; -} video_spu_palette_t; - - -typedef struct video_navi_pack { - int length; /* 0 ... 1024 */ - __u8 data[1024]; -} video_navi_pack_t; - - -typedef __u16 video_attributes_t; -/* bits: descr. */ -/* 15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */ -/* 13-12 TV system (0=525/60, 1=625/50) */ -/* 11-10 Aspect ratio (0=4:3, 3=16:9) */ -/* 9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca */ -/* 7 line 21-1 data present in GOP (1=yes, 0=no) */ -/* 6 line 21-2 data present in GOP (1=yes, 0=no) */ -/* 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */ -/* 2 source letterboxed (1=yes, 0=no) */ -/* 0 film/camera mode (0=camera, 1=film (625/50 only)) */ - - -/* bit definitions for capabilities: */ -/* can the hardware decode MPEG1 and/or MPEG2? */ -#define VIDEO_CAP_MPEG1 1 -#define VIDEO_CAP_MPEG2 2 -/* can you send a system and/or program stream to video device? - (you still have to open the video and the audio device but only - send the stream to the video device) */ -#define VIDEO_CAP_SYS 4 -#define VIDEO_CAP_PROG 8 -/* can the driver also handle SPU, NAVI and CSS encoded data? - (CSS API is not present yet) */ -#define VIDEO_CAP_SPU 16 -#define VIDEO_CAP_NAVI 32 -#define VIDEO_CAP_CSS 64 - - -#define VIDEO_STOP _IO('o', 21) -#define VIDEO_PLAY _IO('o', 22) -#define VIDEO_FREEZE _IO('o', 23) -#define VIDEO_CONTINUE _IO('o', 24) -#define VIDEO_SELECT_SOURCE _IO('o', 25) -#define VIDEO_SET_BLANK _IO('o', 26) -#define VIDEO_GET_STATUS _IOR('o', 27, struct video_status) -#define VIDEO_GET_EVENT _IOR('o', 28, struct video_event) -#define VIDEO_SET_DISPLAY_FORMAT _IO('o', 29) -#define VIDEO_STILLPICTURE _IOW('o', 30, struct video_still_picture) -#define VIDEO_FAST_FORWARD _IO('o', 31) -#define VIDEO_SLOWMOTION _IO('o', 32) -#define VIDEO_GET_CAPABILITIES _IOR('o', 33, unsigned int) -#define VIDEO_CLEAR_BUFFER _IO('o', 34) -#define VIDEO_SET_ID _IO('o', 35) -#define VIDEO_SET_STREAMTYPE _IO('o', 36) -#define VIDEO_SET_FORMAT _IO('o', 37) -#define VIDEO_SET_SYSTEM _IO('o', 38) -#define VIDEO_SET_HIGHLIGHT _IOW('o', 39, video_highlight_t) -#define VIDEO_SET_SPU _IOW('o', 50, video_spu_t) -#define VIDEO_SET_SPU_PALETTE _IOW('o', 51, video_spu_palette_t) -#define VIDEO_GET_NAVI _IOR('o', 52, video_navi_pack_t) -#define VIDEO_SET_ATTRIBUTES _IO('o', 53) -#define VIDEO_GET_SIZE _IOR('o', 55, video_size_t) -#define VIDEO_GET_FRAME_RATE _IOR('o', 56, unsigned int) - -/** - * VIDEO_GET_PTS - * - * Read the 33 bit presentation time stamp as defined - * in ITU T-REC-H.222.0 / ISO/IEC 13818-1. - * - * The PTS should belong to the currently played - * frame if possible, but may also be a value close to it - * like the PTS of the last decoded frame or the last PTS - * extracted by the PES parser. - */ -#define VIDEO_GET_PTS _IOR('o', 57, __u64) - -/* Read the number of displayed frames since the decoder was started */ -#define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64) - -#define VIDEO_COMMAND _IOWR('o', 59, struct video_command) -#define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command) - -#endif /*_DVBVIDEO_H_*/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/i2c-id.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/i2c-id.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/i2c-id.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/i2c-id.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* ------------------------------------------------------------------------- */ -/* */ -/* i2c-id.h - identifier values for i2c drivers and adapters */ -/* */ -/* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-1999 Simon G. Vogl - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* ------------------------------------------------------------------------- */ - -#ifndef LINUX_I2C_ID_H -#define LINUX_I2C_ID_H - -/* Please note that I2C driver IDs are optional. They are only needed if a - legacy chip driver needs to identify a bus or a bus driver needs to - identify a legacy client. If you don't need them, just don't set them. */ - -/* - * ---- Adapter types ---------------------------------------------------- - */ - -/* --- Bit algorithm adapters */ -#define I2C_HW_B_CX2388x 0x01001b /* connexant 2388x based tv cards */ - -#endif /* LINUX_I2C_ID_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ivtvfb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ivtvfb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ivtvfb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ivtvfb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* - On Screen Display cx23415 Framebuffer driver - - Copyright (C) 2006, 2007 Ian Armstrong - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef __LINUX_IVTVFB_H__ -#define __LINUX_IVTVFB_H__ - -#include -#include - -/* Framebuffer external API */ - -struct ivtvfb_dma_frame { - void __user *source; - unsigned long dest_offset; - int count; -}; - -#define IVTVFB_IOC_DMA_FRAME _IOW('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ivtv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ivtv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ivtv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ivtv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* - Public ivtv API header - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004-2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef __LINUX_IVTV_H__ -#define __LINUX_IVTV_H__ - -#include -#include -#include - -/* ivtv knows several distinct output modes: MPEG streaming, - YUV streaming, YUV updates through user DMA and the passthrough - mode. - - In order to clearly tell the driver that we are in user DMA - YUV mode you need to call IVTV_IOC_DMA_FRAME with y_source == NULL - first (althrough if you don't then the first time - DMA_FRAME is called the mode switch is done automatically). - - When you close the file handle the user DMA mode is exited again. - - While in one mode, you cannot use another mode (EBUSY is returned). - - All this means that if you want to change the YUV interlacing - for the user DMA YUV mode you first need to do call IVTV_IOC_DMA_FRAME - with y_source == NULL before you can set the correct format using - VIDIOC_S_FMT. - - Eventually all this should be replaced with a proper V4L2 API, - but for now we have to do it this way. */ - -struct ivtv_dma_frame { - enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_OUTPUT */ - __u32 pixelformat; /* 0 == same as destination */ - void __user *y_source; /* if NULL and type == V4L2_BUF_TYPE_VIDEO_OUTPUT, - then just switch to user DMA YUV output mode */ - void __user *uv_source; /* Unused for RGB pixelformats */ - struct v4l2_rect src; - struct v4l2_rect dst; - __u32 src_width; - __u32 src_height; -}; - -#define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame) - -/* Deprecated defines: applications should use the defines from videodev2.h */ -#define IVTV_SLICED_TYPE_TELETEXT_B V4L2_MPEG_VBI_IVTV_TELETEXT_B -#define IVTV_SLICED_TYPE_CAPTION_525 V4L2_MPEG_VBI_IVTV_CAPTION_525 -#define IVTV_SLICED_TYPE_WSS_625 V4L2_MPEG_VBI_IVTV_WSS_625 -#define IVTV_SLICED_TYPE_VPS V4L2_MPEG_VBI_IVTV_VPS - -#endif /* _LINUX_IVTV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/media.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/media.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/media.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/media.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,132 +0,0 @@ -/* - * Multimedia device API - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - */ - -#ifndef __LINUX_MEDIA_H -#define __LINUX_MEDIA_H - -#include -#include -#include - -#define MEDIA_API_VERSION KERNEL_VERSION(0, 1, 0) - -struct media_device_info { - char driver[16]; - char model[32]; - char serial[40]; - char bus_info[32]; - __u32 media_version; - __u32 hw_revision; - __u32 driver_version; - __u32 reserved[31]; -}; - -#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31) - -#define MEDIA_ENT_TYPE_SHIFT 16 -#define MEDIA_ENT_TYPE_MASK 0x00ff0000 -#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff - -#define MEDIA_ENT_T_DEVNODE (1 << MEDIA_ENT_TYPE_SHIFT) -#define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENT_T_DEVNODE + 1) -#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2) -#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3) -#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4) - -#define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENT_TYPE_SHIFT) -#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1) -#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2) -#define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENT_T_V4L2_SUBDEV + 3) - -#define MEDIA_ENT_FL_DEFAULT (1 << 0) - -struct media_entity_desc { - __u32 id; - char name[32]; - __u32 type; - __u32 revision; - __u32 flags; - __u32 group_id; - __u16 pads; - __u16 links; - - __u32 reserved[4]; - - union { - /* Node specifications */ - struct { - __u32 major; - __u32 minor; - } v4l; - struct { - __u32 major; - __u32 minor; - } fb; - struct { - __u32 card; - __u32 device; - __u32 subdevice; - } alsa; - int dvb; - - /* Sub-device specifications */ - /* Nothing needed yet */ - __u8 raw[184]; - }; -}; - -#define MEDIA_PAD_FL_SINK (1 << 0) -#define MEDIA_PAD_FL_SOURCE (1 << 1) - -struct media_pad_desc { - __u32 entity; /* entity ID */ - __u16 index; /* pad index */ - __u32 flags; /* pad flags */ - __u32 reserved[2]; -}; - -#define MEDIA_LNK_FL_ENABLED (1 << 0) -#define MEDIA_LNK_FL_IMMUTABLE (1 << 1) -#define MEDIA_LNK_FL_DYNAMIC (1 << 2) - -struct media_link_desc { - struct media_pad_desc source; - struct media_pad_desc sink; - __u32 flags; - __u32 reserved[2]; -}; - -struct media_links_enum { - __u32 entity; - /* Should have enough room for pads elements */ - struct media_pad_desc __user *pads; - /* Should have enough room for links elements */ - struct media_link_desc __user *links; - __u32 reserved[4]; -}; - -#define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info) -#define MEDIA_IOC_ENUM_ENTITIES _IOWR('|', 0x01, struct media_entity_desc) -#define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum) -#define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc) - -#endif /* __LINUX_MEDIA_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/meye.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/meye.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/meye.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/meye.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/* - * Motion Eye video4linux driver for Sony Vaio PictureBook - * - * Copyright (C) 2001-2003 Stelian Pop - * - * Copyright (C) 2001-2002 Alcôve - * - * Copyright (C) 2000 Andrew Tridgell - * - * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. - * - * Some parts borrowed from various video4linux drivers, especially - * bttv-driver.c and zoran.c, see original files for credits. - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _MEYE_H_ -#define _MEYE_H_ - -/****************************************************************************/ -/* Private API for handling mjpeg capture / playback. */ -/****************************************************************************/ - -struct meye_params { - unsigned char subsample; - unsigned char quality; - unsigned char sharpness; - unsigned char agc; - unsigned char picture; - unsigned char framerate; -}; - -/* query the extended parameters */ -#define MEYEIOC_G_PARAMS _IOR ('v', BASE_VIDIOC_PRIVATE+0, struct meye_params) -/* set the extended parameters */ -#define MEYEIOC_S_PARAMS _IOW ('v', BASE_VIDIOC_PRIVATE+1, struct meye_params) -/* queue a buffer for mjpeg capture */ -#define MEYEIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOC_PRIVATE+2, int) -/* sync a previously queued mjpeg buffer */ -#define MEYEIOC_SYNC _IOWR('v', BASE_VIDIOC_PRIVATE+3, int) -/* get a still uncompressed snapshot */ -#define MEYEIOC_STILLCAPT _IO ('v', BASE_VIDIOC_PRIVATE+4) -/* get a jpeg compressed snapshot */ -#define MEYEIOC_STILLJCAPT _IOR ('v', BASE_VIDIOC_PRIVATE+5, int) - -/* V4L2 private controls */ -#define V4L2_CID_AGC V4L2_CID_PRIVATE_BASE -#define V4L2_CID_MEYE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PICTURE (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_JPEGQUAL (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_FRAMERATE (V4L2_CID_PRIVATE_BASE + 4) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/mmc/sdio_ids.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/mmc/sdio_ids.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/mmc/sdio_ids.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/mmc/sdio_ids.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * SDIO Classes, Interface Types, Manufacturer IDs, etc. - */ - -#ifndef MMC_SDIO_IDS_H -#define MMC_SDIO_IDS_H - -/* - * Standard SDIO Function Interfaces - */ - -#define SDIO_CLASS_NONE 0x00 /* Not a SDIO standard interface */ -#define SDIO_CLASS_UART 0x01 /* standard UART interface */ -#define SDIO_CLASS_BT_A 0x02 /* Type-A BlueTooth std interface */ -#define SDIO_CLASS_BT_B 0x03 /* Type-B BlueTooth std interface */ -#define SDIO_CLASS_GPS 0x04 /* GPS standard interface */ -#define SDIO_CLASS_CAMERA 0x05 /* Camera standard interface */ -#define SDIO_CLASS_PHS 0x06 /* PHS standard interface */ -#define SDIO_CLASS_WLAN 0x07 /* WLAN interface */ -#define SDIO_CLASS_ATA 0x08 /* Embedded SDIO-ATA std interface */ -#define SDIO_CLASS_BT_AMP 0x09 /* Type-A Bluetooth AMP interface */ - -/* - * Vendors and devices. Sort key: vendor first, device next. - */ -#define SDIO_VENDOR_ID_INTEL 0x0089 -#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402 -#define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI 0x1403 -#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404 -#define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405 -#define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406 -#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5 0x1407 - -#define SDIO_VENDOR_ID_MARVELL 0x02df -#define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 -#define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104 -#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105 - -#define SDIO_VENDOR_ID_SIANO 0x039a -#define SDIO_DEVICE_ID_SIANO_NOVA_B0 0x0201 -#define SDIO_DEVICE_ID_SIANO_NICE 0x0202 -#define SDIO_DEVICE_ID_SIANO_VEGA_A0 0x0300 -#define SDIO_DEVICE_ID_SIANO_VENICE 0x0301 -#define SDIO_DEVICE_ID_SIANO_NOVA_A0 0x1100 -#define SDIO_DEVICE_ID_SIANO_STELLAR 0x5347 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ti_wilink_st.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ti_wilink_st.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ti_wilink_st.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/ti_wilink_st.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,400 +0,0 @@ -/* - * Shared Transport Header file - * To be included by the protocol stack drivers for - * Texas Instruments BT,FM and GPS combo chip drivers - * and also serves the sub-modules of the shared transport driver. - * - * Copyright (C) 2009-2010 Texas Instruments - * Author: Pavan Savoy - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - * - */ - -#ifndef TI_WILINK_ST_H -#define TI_WILINK_ST_H - -/** - * enum kim_gpio_state - Few protocols such as FM have ACTIVE LOW - * gpio states for their chip/core enable gpios - */ -enum kim_gpio_state { - KIM_GPIO_INACTIVE, - KIM_GPIO_ACTIVE, -}; - -/** - * enum proto-type - The protocol on WiLink chips which share a - * common physical interface like UART. - */ -enum proto_type { - ST_BT, - ST_FM, - ST_GPS, - ST_MAX, -}; - -/** - * struct st_proto_s - Per Protocol structure from BT/FM/GPS to ST - * @type: type of the protocol being registered among the - * available proto_type(BT, FM, GPS the protocol which share TTY). - * @recv: the receiver callback pointing to a function in the - * protocol drivers called by the ST driver upon receiving - * relevant data. - * @match_packet: reserved for future use, to make ST more generic - * @reg_complete_cb: callback handler pointing to a function in protocol - * handler called by ST when the pending registrations are complete. - * The registrations are marked pending, in situations when fw - * download is in progress. - * @write: pointer to function in ST provided to protocol drivers from ST, - * to be made use when protocol drivers have data to send to TTY. - * @priv_data: privdate data holder for the protocol drivers, sent - * from the protocol drivers during registration, and sent back on - * reg_complete_cb and recv. - */ -struct st_proto_s { - enum proto_type type; - long (*recv) (void *, struct sk_buff *); - unsigned char (*match_packet) (const unsigned char *data); - void (*reg_complete_cb) (void *, char data); - long (*write) (struct sk_buff *skb); - void *priv_data; -}; - -extern long st_register(struct st_proto_s *); -extern long st_unregister(enum proto_type); - - -/* - * header information used by st_core.c - */ - -/* states of protocol list */ -#define ST_NOTEMPTY 1 -#define ST_EMPTY 0 - -/* - * possible st_states - */ -#define ST_INITIALIZING 1 -#define ST_REG_IN_PROGRESS 2 -#define ST_REG_PENDING 3 -#define ST_WAITING_FOR_RESP 4 - -/** - * struct st_data_s - ST core internal structure - * @st_state: different states of ST like initializing, registration - * in progress, this is mainly used to return relevant err codes - * when protocol drivers are registering. It is also used to track - * the recv function, as in during fw download only HCI events - * can occur , where as during other times other events CH8, CH9 - * can occur. - * @tty: tty provided by the TTY core for line disciplines. - * @tx_skb: If for some reason the tty's write returns lesser bytes written - * then to maintain the rest of data to be written on next instance. - * This needs to be protected, hence the lock inside wakeup func. - * @tx_state: if the data is being written onto the TTY and protocol driver - * wants to send more, queue up data and mark that there is - * more data to send. - * @list: the list of protocols registered, only MAX can exist, one protocol - * can register only once. - * @rx_state: states to be maintained inside st's tty receive - * @rx_count: count to be maintained inside st's tty receieve - * @rx_skb: the skb where all data for a protocol gets accumulated, - * since tty might not call receive when a complete event packet - * is received, the states, count and the skb needs to be maintained. - * @txq: the list of skbs which needs to be sent onto the TTY. - * @tx_waitq: if the chip is not in AWAKE state, the skbs needs to be queued - * up in here, PM(WAKEUP_IND) data needs to be sent and then the skbs - * from waitq can be moved onto the txq. - * Needs locking too. - * @lock: the lock to protect skbs, queues, and ST states. - * @protos_registered: count of the protocols registered, also when 0 the - * chip enable gpio can be toggled, and when it changes to 1 the fw - * needs to be downloaded to initialize chip side ST. - * @ll_state: the various PM states the chip can be, the states are notified - * to us, when the chip sends relevant PM packets(SLEEP_IND, WAKE_IND). - * @kim_data: reference to the parent encapsulating structure. - * - */ -struct st_data_s { - unsigned long st_state; - struct tty_struct *tty; - struct sk_buff *tx_skb; -#define ST_TX_SENDING 1 -#define ST_TX_WAKEUP 2 - unsigned long tx_state; - struct st_proto_s *list[ST_MAX]; - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; - struct sk_buff_head txq, tx_waitq; - spinlock_t lock; - unsigned char protos_registered; - unsigned long ll_state; - void *kim_data; -}; - -/** - * st_int_write - - * point this to tty->driver->write or tty->ops->write - * depending upon the kernel version - */ -int st_int_write(struct st_data_s*, const unsigned char*, int); - -/** - * st_write - - * internal write function, passed onto protocol drivers - * via the write function ptr of protocol struct - */ -long st_write(struct sk_buff *); - -/* function to be called from ST-LL */ -void st_ll_send_frame(enum proto_type, struct sk_buff *); - -/* internal wake up function */ -void st_tx_wakeup(struct st_data_s *st_data); - -/* init, exit entry funcs called from KIM */ -int st_core_init(struct st_data_s **); -void st_core_exit(struct st_data_s *); - -/* ask for reference from KIM */ -void st_kim_ref(struct st_data_s **, int); - -#define GPS_STUB_TEST -#ifdef GPS_STUB_TEST -int gps_chrdrv_stub_write(const unsigned char*, int); -void gps_chrdrv_stub_init(void); -#endif - -/* - * header information used by st_kim.c - */ - -/* time in msec to wait for - * line discipline to be installed - */ -#define LDISC_TIME 500 -#define CMD_RESP_TIME 500 -#define MAKEWORD(a, b) ((unsigned short)(((unsigned char)(a)) \ - | ((unsigned short)((unsigned char)(b))) << 8)) - -#define GPIO_HIGH 1 -#define GPIO_LOW 0 - -/* the Power-On-Reset logic, requires to attempt - * to download firmware onto chip more than once - * since the self-test for chip takes a while - */ -#define POR_RETRY_COUNT 5 - -/** - * struct chip_version - save the chip version - */ -struct chip_version { - unsigned short full; - unsigned short chip; - unsigned short min_ver; - unsigned short maj_ver; -}; - -/** - * struct kim_data_s - the KIM internal data, embedded as the - * platform's drv data. One for each ST device in the system. - * @uim_pid: KIM needs to communicate with UIM to request to install - * the ldisc by opening UART when protocol drivers register. - * @kim_pdev: the platform device added in one of the board-XX.c file - * in arch/XX/ directory, 1 for each ST device. - * @kim_rcvd: completion handler to notify when data was received, - * mainly used during fw download, which involves multiple send/wait - * for each of the HCI-VS commands. - * @ldisc_installed: completion handler to notify that the UIM accepted - * the request to install ldisc, notify from tty_open which suggests - * the ldisc was properly installed. - * @resp_buffer: data buffer for the .bts fw file name. - * @fw_entry: firmware class struct to request/release the fw. - * @gpios: the list of core/chip enable gpios for BT, FM and GPS cores. - * @rx_state: the rx state for kim's receive func during fw download. - * @rx_count: the rx count for the kim's receive func during fw download. - * @rx_skb: all of fw data might not come at once, and hence data storage for - * whole of the fw response, only HCI_EVENTs and hence diff from ST's - * response. - * @rfkill: rfkill data for each of the cores to be registered with rfkill. - * @rf_protos: proto types of the data registered with rfkill sub-system. - * @core_data: ST core's data, which mainly is the tty's disc_data - * @version: chip version available via a sysfs entry. - * - */ -struct kim_data_s { - long uim_pid; - struct platform_device *kim_pdev; - struct completion kim_rcvd, ldisc_installed; - char resp_buffer[30]; - const struct firmware *fw_entry; - long gpios[ST_MAX]; - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; - struct rfkill *rfkill[ST_MAX]; - enum proto_type rf_protos[ST_MAX]; - struct st_data_s *core_data; - struct chip_version version; -}; - -/** - * functions called when 1 of the protocol drivers gets - * registered, these need to communicate with UIM to request - * ldisc installed, read chip_version, download relevant fw - */ -long st_kim_start(void *); -long st_kim_stop(void *); - -void st_kim_recv(void *, const unsigned char *, long count); -void st_kim_chip_toggle(enum proto_type, enum kim_gpio_state); -void st_kim_complete(void *); -void kim_st_list_protocols(struct st_data_s *, void *); - -/* - * BTS headers - */ -#define ACTION_SEND_COMMAND 1 -#define ACTION_WAIT_EVENT 2 -#define ACTION_SERIAL 3 -#define ACTION_DELAY 4 -#define ACTION_RUN_SCRIPT 5 -#define ACTION_REMARKS 6 - -/** - * struct bts_header - the fw file is NOT binary which can - * be sent onto TTY as is. The .bts is more a script - * file which has different types of actions. - * Each such action needs to be parsed by the KIM and - * relevant procedure to be called. - */ -struct bts_header { - u32 magic; - u32 version; - u8 future[24]; - u8 actions[0]; -} __attribute__ ((packed)); - -/** - * struct bts_action - Each .bts action has its own type of - * data. - */ -struct bts_action { - u16 type; - u16 size; - u8 data[0]; -} __attribute__ ((packed)); - -struct bts_action_send { - u8 data[0]; -} __attribute__ ((packed)); - -struct bts_action_wait { - u32 msec; - u32 size; - u8 data[0]; -} __attribute__ ((packed)); - -struct bts_action_delay { - u32 msec; -} __attribute__ ((packed)); - -struct bts_action_serial { - u32 baud; - u32 flow_control; -} __attribute__ ((packed)); - -/** - * struct hci_command - the HCI-VS for intrepreting - * the change baud rate of host-side UART, which - * needs to be ignored, since UIM would do that - * when it receives request from KIM for ldisc installation. - */ -struct hci_command { - u8 prefix; - u16 opcode; - u8 plen; - u32 speed; -} __attribute__ ((packed)); - -/* - * header information used by st_ll.c - */ - -/* ST LL receiver states */ -#define ST_W4_PACKET_TYPE 0 -#define ST_BT_W4_EVENT_HDR 1 -#define ST_BT_W4_ACL_HDR 2 -#define ST_BT_W4_SCO_HDR 3 -#define ST_BT_W4_DATA 4 -#define ST_FM_W4_EVENT_HDR 5 -#define ST_GPS_W4_EVENT_HDR 6 - -/* ST LL state machines */ -#define ST_LL_ASLEEP 0 -#define ST_LL_ASLEEP_TO_AWAKE 1 -#define ST_LL_AWAKE 2 -#define ST_LL_AWAKE_TO_ASLEEP 3 -#define ST_LL_INVALID 4 - -/* different PM notifications coming from chip */ -#define LL_SLEEP_IND 0x30 -#define LL_SLEEP_ACK 0x31 -#define LL_WAKE_UP_IND 0x32 -#define LL_WAKE_UP_ACK 0x33 - -/* initialize and de-init ST LL */ -long st_ll_init(struct st_data_s *); -long st_ll_deinit(struct st_data_s *); - -/** - * enable/disable ST LL along with KIM start/stop - * called by ST Core - */ -void st_ll_enable(struct st_data_s *); -void st_ll_disable(struct st_data_s *); - -/** - * various funcs used by ST core to set/get the various PM states - * of the chip. - */ -unsigned long st_ll_getstate(struct st_data_s *); -unsigned long st_ll_sleep_state(struct st_data_s *, unsigned char); -void st_ll_wakeup(struct st_data_s *); - -/* - * header information used by st_core.c for FM and GPS - * packet parsing, the bluetooth headers are already available - * at net/bluetooth/ - */ - -struct fm_event_hdr { - u8 plen; -} __attribute__ ((packed)); - -#define FM_MAX_FRAME_SIZE 0xFF /* TODO: */ -#define FM_EVENT_HDR_SIZE 1 /* size of fm_event_hdr */ -#define ST_FM_CH8_PKT 0x8 - -/* gps stuff */ -struct gps_event_hdr { - u8 opcode; - u16 plen; -} __attribute__ ((packed)); - -#endif /* TI_WILINK_ST_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/usb/video.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/usb/video.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/usb/video.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/usb/video.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,568 +0,0 @@ -/* - * USB Video Class definitions. - * - * Copyright (C) 2009 Laurent Pinchart - * - * This file holds USB constants and structures defined by the USB Device - * Class Definition for Video Devices. Unless otherwise stated, comments - * below reference relevant sections of the USB Video Class 1.1 specification - * available at - * - * http://www.usb.org/developers/devclass_docs/USB_Video_Class_1_1.zip - */ - -#ifndef __LINUX_USB_VIDEO_H -#define __LINUX_USB_VIDEO_H - -#include - -/* -------------------------------------------------------------------------- - * UVC constants - */ - -/* A.2. Video Interface Subclass Codes */ -#define UVC_SC_UNDEFINED 0x00 -#define UVC_SC_VIDEOCONTROL 0x01 -#define UVC_SC_VIDEOSTREAMING 0x02 -#define UVC_SC_VIDEO_INTERFACE_COLLECTION 0x03 - -/* A.3. Video Interface Protocol Codes */ -#define UVC_PC_PROTOCOL_UNDEFINED 0x00 - -/* A.5. Video Class-Specific VC Interface Descriptor Subtypes */ -#define UVC_VC_DESCRIPTOR_UNDEFINED 0x00 -#define UVC_VC_HEADER 0x01 -#define UVC_VC_INPUT_TERMINAL 0x02 -#define UVC_VC_OUTPUT_TERMINAL 0x03 -#define UVC_VC_SELECTOR_UNIT 0x04 -#define UVC_VC_PROCESSING_UNIT 0x05 -#define UVC_VC_EXTENSION_UNIT 0x06 - -/* A.6. Video Class-Specific VS Interface Descriptor Subtypes */ -#define UVC_VS_UNDEFINED 0x00 -#define UVC_VS_INPUT_HEADER 0x01 -#define UVC_VS_OUTPUT_HEADER 0x02 -#define UVC_VS_STILL_IMAGE_FRAME 0x03 -#define UVC_VS_FORMAT_UNCOMPRESSED 0x04 -#define UVC_VS_FRAME_UNCOMPRESSED 0x05 -#define UVC_VS_FORMAT_MJPEG 0x06 -#define UVC_VS_FRAME_MJPEG 0x07 -#define UVC_VS_FORMAT_MPEG2TS 0x0a -#define UVC_VS_FORMAT_DV 0x0c -#define UVC_VS_COLORFORMAT 0x0d -#define UVC_VS_FORMAT_FRAME_BASED 0x10 -#define UVC_VS_FRAME_FRAME_BASED 0x11 -#define UVC_VS_FORMAT_STREAM_BASED 0x12 - -/* A.7. Video Class-Specific Endpoint Descriptor Subtypes */ -#define UVC_EP_UNDEFINED 0x00 -#define UVC_EP_GENERAL 0x01 -#define UVC_EP_ENDPOINT 0x02 -#define UVC_EP_INTERRUPT 0x03 - -/* A.8. Video Class-Specific Request Codes */ -#define UVC_RC_UNDEFINED 0x00 -#define UVC_SET_CUR 0x01 -#define UVC_GET_CUR 0x81 -#define UVC_GET_MIN 0x82 -#define UVC_GET_MAX 0x83 -#define UVC_GET_RES 0x84 -#define UVC_GET_LEN 0x85 -#define UVC_GET_INFO 0x86 -#define UVC_GET_DEF 0x87 - -/* A.9.1. VideoControl Interface Control Selectors */ -#define UVC_VC_CONTROL_UNDEFINED 0x00 -#define UVC_VC_VIDEO_POWER_MODE_CONTROL 0x01 -#define UVC_VC_REQUEST_ERROR_CODE_CONTROL 0x02 - -/* A.9.2. Terminal Control Selectors */ -#define UVC_TE_CONTROL_UNDEFINED 0x00 - -/* A.9.3. Selector Unit Control Selectors */ -#define UVC_SU_CONTROL_UNDEFINED 0x00 -#define UVC_SU_INPUT_SELECT_CONTROL 0x01 - -/* A.9.4. Camera Terminal Control Selectors */ -#define UVC_CT_CONTROL_UNDEFINED 0x00 -#define UVC_CT_SCANNING_MODE_CONTROL 0x01 -#define UVC_CT_AE_MODE_CONTROL 0x02 -#define UVC_CT_AE_PRIORITY_CONTROL 0x03 -#define UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 -#define UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 -#define UVC_CT_FOCUS_ABSOLUTE_CONTROL 0x06 -#define UVC_CT_FOCUS_RELATIVE_CONTROL 0x07 -#define UVC_CT_FOCUS_AUTO_CONTROL 0x08 -#define UVC_CT_IRIS_ABSOLUTE_CONTROL 0x09 -#define UVC_CT_IRIS_RELATIVE_CONTROL 0x0a -#define UVC_CT_ZOOM_ABSOLUTE_CONTROL 0x0b -#define UVC_CT_ZOOM_RELATIVE_CONTROL 0x0c -#define UVC_CT_PANTILT_ABSOLUTE_CONTROL 0x0d -#define UVC_CT_PANTILT_RELATIVE_CONTROL 0x0e -#define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f -#define UVC_CT_ROLL_RELATIVE_CONTROL 0x10 -#define UVC_CT_PRIVACY_CONTROL 0x11 - -/* A.9.5. Processing Unit Control Selectors */ -#define UVC_PU_CONTROL_UNDEFINED 0x00 -#define UVC_PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 -#define UVC_PU_BRIGHTNESS_CONTROL 0x02 -#define UVC_PU_CONTRAST_CONTROL 0x03 -#define UVC_PU_GAIN_CONTROL 0x04 -#define UVC_PU_POWER_LINE_FREQUENCY_CONTROL 0x05 -#define UVC_PU_HUE_CONTROL 0x06 -#define UVC_PU_SATURATION_CONTROL 0x07 -#define UVC_PU_SHARPNESS_CONTROL 0x08 -#define UVC_PU_GAMMA_CONTROL 0x09 -#define UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a -#define UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b -#define UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c -#define UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d -#define UVC_PU_DIGITAL_MULTIPLIER_CONTROL 0x0e -#define UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f -#define UVC_PU_HUE_AUTO_CONTROL 0x10 -#define UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11 -#define UVC_PU_ANALOG_LOCK_STATUS_CONTROL 0x12 - -/* A.9.7. VideoStreaming Interface Control Selectors */ -#define UVC_VS_CONTROL_UNDEFINED 0x00 -#define UVC_VS_PROBE_CONTROL 0x01 -#define UVC_VS_COMMIT_CONTROL 0x02 -#define UVC_VS_STILL_PROBE_CONTROL 0x03 -#define UVC_VS_STILL_COMMIT_CONTROL 0x04 -#define UVC_VS_STILL_IMAGE_TRIGGER_CONTROL 0x05 -#define UVC_VS_STREAM_ERROR_CODE_CONTROL 0x06 -#define UVC_VS_GENERATE_KEY_FRAME_CONTROL 0x07 -#define UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08 -#define UVC_VS_SYNC_DELAY_CONTROL 0x09 - -/* B.1. USB Terminal Types */ -#define UVC_TT_VENDOR_SPECIFIC 0x0100 -#define UVC_TT_STREAMING 0x0101 - -/* B.2. Input Terminal Types */ -#define UVC_ITT_VENDOR_SPECIFIC 0x0200 -#define UVC_ITT_CAMERA 0x0201 -#define UVC_ITT_MEDIA_TRANSPORT_INPUT 0x0202 - -/* B.3. Output Terminal Types */ -#define UVC_OTT_VENDOR_SPECIFIC 0x0300 -#define UVC_OTT_DISPLAY 0x0301 -#define UVC_OTT_MEDIA_TRANSPORT_OUTPUT 0x0302 - -/* B.4. External Terminal Types */ -#define UVC_EXTERNAL_VENDOR_SPECIFIC 0x0400 -#define UVC_COMPOSITE_CONNECTOR 0x0401 -#define UVC_SVIDEO_CONNECTOR 0x0402 -#define UVC_COMPONENT_CONNECTOR 0x0403 - -/* 2.4.2.2. Status Packet Type */ -#define UVC_STATUS_TYPE_CONTROL 1 -#define UVC_STATUS_TYPE_STREAMING 2 - -/* 2.4.3.3. Payload Header Information */ -#define UVC_STREAM_EOH (1 << 7) -#define UVC_STREAM_ERR (1 << 6) -#define UVC_STREAM_STI (1 << 5) -#define UVC_STREAM_RES (1 << 4) -#define UVC_STREAM_SCR (1 << 3) -#define UVC_STREAM_PTS (1 << 2) -#define UVC_STREAM_EOF (1 << 1) -#define UVC_STREAM_FID (1 << 0) - -/* 4.1.2. Control Capabilities */ -#define UVC_CONTROL_CAP_GET (1 << 0) -#define UVC_CONTROL_CAP_SET (1 << 1) -#define UVC_CONTROL_CAP_DISABLED (1 << 2) -#define UVC_CONTROL_CAP_AUTOUPDATE (1 << 3) -#define UVC_CONTROL_CAP_ASYNCHRONOUS (1 << 4) - -/* ------------------------------------------------------------------------ - * UVC structures - */ - -/* All UVC descriptors have these 3 fields at the beginning */ -struct uvc_descriptor_header { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; -} __attribute__((packed)); - -/* 3.7.2. Video Control Interface Header Descriptor */ -struct uvc_header_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u16 bcdUVC; - __u16 wTotalLength; - __u32 dwClockFrequency; - __u8 bInCollection; - __u8 baInterfaceNr[]; -} __attribute__((__packed__)); - -#define UVC_DT_HEADER_SIZE(n) (12+(n)) - -#define UVC_HEADER_DESCRIPTOR(n) \ - uvc_header_descriptor_##n - -#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \ -struct UVC_HEADER_DESCRIPTOR(n) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u16 bcdUVC; \ - __u16 wTotalLength; \ - __u32 dwClockFrequency; \ - __u8 bInCollection; \ - __u8 baInterfaceNr[n]; \ -} __attribute__ ((packed)) - -/* 3.7.2.1. Input Terminal Descriptor */ -struct uvc_input_terminal_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bTerminalID; - __u16 wTerminalType; - __u8 bAssocTerminal; - __u8 iTerminal; -} __attribute__((__packed__)); - -#define UVC_DT_INPUT_TERMINAL_SIZE 8 - -/* 3.7.2.2. Output Terminal Descriptor */ -struct uvc_output_terminal_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bTerminalID; - __u16 wTerminalType; - __u8 bAssocTerminal; - __u8 bSourceID; - __u8 iTerminal; -} __attribute__((__packed__)); - -#define UVC_DT_OUTPUT_TERMINAL_SIZE 9 - -/* 3.7.2.3. Camera Terminal Descriptor */ -struct uvc_camera_terminal_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bTerminalID; - __u16 wTerminalType; - __u8 bAssocTerminal; - __u8 iTerminal; - __u16 wObjectiveFocalLengthMin; - __u16 wObjectiveFocalLengthMax; - __u16 wOcularFocalLength; - __u8 bControlSize; - __u8 bmControls[3]; -} __attribute__((__packed__)); - -#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n)) - -/* 3.7.2.4. Selector Unit Descriptor */ -struct uvc_selector_unit_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bUnitID; - __u8 bNrInPins; - __u8 baSourceID[0]; - __u8 iSelector; -} __attribute__((__packed__)); - -#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n)) - -#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \ - uvc_selector_unit_descriptor_##n - -#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \ -struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bUnitID; \ - __u8 bNrInPins; \ - __u8 baSourceID[n]; \ - __u8 iSelector; \ -} __attribute__ ((packed)) - -/* 3.7.2.5. Processing Unit Descriptor */ -struct uvc_processing_unit_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bUnitID; - __u8 bSourceID; - __u16 wMaxMultiplier; - __u8 bControlSize; - __u8 bmControls[2]; - __u8 iProcessing; -} __attribute__((__packed__)); - -#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) - -/* 3.7.2.6. Extension Unit Descriptor */ -struct uvc_extension_unit_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bUnitID; - __u8 guidExtensionCode[16]; - __u8 bNumControls; - __u8 bNrInPins; - __u8 baSourceID[0]; - __u8 bControlSize; - __u8 bmControls[0]; - __u8 iExtension; -} __attribute__((__packed__)); - -#define UVC_DT_EXTENSION_UNIT_SIZE(p, n) (24+(p)+(n)) - -#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \ - uvc_extension_unit_descriptor_##p_##n - -#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \ -struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bUnitID; \ - __u8 guidExtensionCode[16]; \ - __u8 bNumControls; \ - __u8 bNrInPins; \ - __u8 baSourceID[p]; \ - __u8 bControlSize; \ - __u8 bmControls[n]; \ - __u8 iExtension; \ -} __attribute__ ((packed)) - -/* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */ -struct uvc_control_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u16 wMaxTransferSize; -} __attribute__((__packed__)); - -#define UVC_DT_CONTROL_ENDPOINT_SIZE 5 - -/* 3.9.2.1. Input Header Descriptor */ -struct uvc_input_header_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bNumFormats; - __u16 wTotalLength; - __u8 bEndpointAddress; - __u8 bmInfo; - __u8 bTerminalLink; - __u8 bStillCaptureMethod; - __u8 bTriggerSupport; - __u8 bTriggerUsage; - __u8 bControlSize; - __u8 bmaControls[]; -} __attribute__((__packed__)); - -#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p)) - -#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ - uvc_input_header_descriptor_##n_##p - -#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ -struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bNumFormats; \ - __u16 wTotalLength; \ - __u8 bEndpointAddress; \ - __u8 bmInfo; \ - __u8 bTerminalLink; \ - __u8 bStillCaptureMethod; \ - __u8 bTriggerSupport; \ - __u8 bTriggerUsage; \ - __u8 bControlSize; \ - __u8 bmaControls[p][n]; \ -} __attribute__ ((packed)) - -/* 3.9.2.2. Output Header Descriptor */ -struct uvc_output_header_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bNumFormats; - __u16 wTotalLength; - __u8 bEndpointAddress; - __u8 bTerminalLink; - __u8 bControlSize; - __u8 bmaControls[]; -} __attribute__((__packed__)); - -#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p)) - -#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ - uvc_output_header_descriptor_##n_##p - -#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ -struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bNumFormats; \ - __u16 wTotalLength; \ - __u8 bEndpointAddress; \ - __u8 bTerminalLink; \ - __u8 bControlSize; \ - __u8 bmaControls[p][n]; \ -} __attribute__ ((packed)) - -/* 3.9.2.6. Color matching descriptor */ -struct uvc_color_matching_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bColorPrimaries; - __u8 bTransferCharacteristics; - __u8 bMatrixCoefficients; -} __attribute__((__packed__)); - -#define UVC_DT_COLOR_MATCHING_SIZE 6 - -/* 4.3.1.1. Video Probe and Commit Controls */ -struct uvc_streaming_control { - __u16 bmHint; - __u8 bFormatIndex; - __u8 bFrameIndex; - __u32 dwFrameInterval; - __u16 wKeyFrameRate; - __u16 wPFrameRate; - __u16 wCompQuality; - __u16 wCompWindowSize; - __u16 wDelay; - __u32 dwMaxVideoFrameSize; - __u32 dwMaxPayloadTransferSize; - __u32 dwClockFrequency; - __u8 bmFramingInfo; - __u8 bPreferedVersion; - __u8 bMinVersion; - __u8 bMaxVersion; -} __attribute__((__packed__)); - -/* Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor */ -struct uvc_format_uncompressed { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bFormatIndex; - __u8 bNumFrameDescriptors; - __u8 guidFormat[16]; - __u8 bBitsPerPixel; - __u8 bDefaultFrameIndex; - __u8 bAspectRatioX; - __u8 bAspectRatioY; - __u8 bmInterfaceFlags; - __u8 bCopyProtect; -} __attribute__((__packed__)); - -#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27 - -/* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */ -struct uvc_frame_uncompressed { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bFrameIndex; - __u8 bmCapabilities; - __u16 wWidth; - __u16 wHeight; - __u32 dwMinBitRate; - __u32 dwMaxBitRate; - __u32 dwMaxVideoFrameBufferSize; - __u32 dwDefaultFrameInterval; - __u8 bFrameIntervalType; - __u32 dwFrameInterval[]; -} __attribute__((__packed__)); - -#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n)) - -#define UVC_FRAME_UNCOMPRESSED(n) \ - uvc_frame_uncompressed_##n - -#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \ -struct UVC_FRAME_UNCOMPRESSED(n) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bFrameIndex; \ - __u8 bmCapabilities; \ - __u16 wWidth; \ - __u16 wHeight; \ - __u32 dwMinBitRate; \ - __u32 dwMaxBitRate; \ - __u32 dwMaxVideoFrameBufferSize; \ - __u32 dwDefaultFrameInterval; \ - __u8 bFrameIntervalType; \ - __u32 dwFrameInterval[n]; \ -} __attribute__ ((packed)) - -/* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */ -struct uvc_format_mjpeg { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bFormatIndex; - __u8 bNumFrameDescriptors; - __u8 bmFlags; - __u8 bDefaultFrameIndex; - __u8 bAspectRatioX; - __u8 bAspectRatioY; - __u8 bmInterfaceFlags; - __u8 bCopyProtect; -} __attribute__((__packed__)); - -#define UVC_DT_FORMAT_MJPEG_SIZE 11 - -/* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */ -struct uvc_frame_mjpeg { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bFrameIndex; - __u8 bmCapabilities; - __u16 wWidth; - __u16 wHeight; - __u32 dwMinBitRate; - __u32 dwMaxBitRate; - __u32 dwMaxVideoFrameBufferSize; - __u32 dwDefaultFrameInterval; - __u8 bFrameIntervalType; - __u32 dwFrameInterval[]; -} __attribute__((__packed__)); - -#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n)) - -#define UVC_FRAME_MJPEG(n) \ - uvc_frame_mjpeg_##n - -#define DECLARE_UVC_FRAME_MJPEG(n) \ -struct UVC_FRAME_MJPEG(n) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bFrameIndex; \ - __u8 bmCapabilities; \ - __u16 wWidth; \ - __u16 wHeight; \ - __u32 dwMinBitRate; \ - __u32 dwMaxBitRate; \ - __u32 dwMaxVideoFrameBufferSize; \ - __u32 dwDefaultFrameInterval; \ - __u8 bFrameIntervalType; \ - __u32 dwFrameInterval[n]; \ -} __attribute__ ((packed)) - -#endif /* __LINUX_USB_VIDEO_H */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/v4l2-mediabus.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/v4l2-mediabus.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/v4l2-mediabus.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/v4l2-mediabus.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/* - * Media Bus API header - * - * Copyright (C) 2009, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __LINUX_V4L2_MEDIABUS_H -#define __LINUX_V4L2_MEDIABUS_H - -#include -#include - -/* - * These pixel codes uniquely identify data formats on the media bus. Mostly - * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is - * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the - * data format is fixed. Additionally, "2X8" means that one pixel is transferred - * in two 8-bit samples, "BE" or "LE" specify in which order those samples are - * transferred over the bus: "LE" means that the least significant bits are - * transferred first, "BE" means that the most significant bits are transferred - * first, and "PADHI" and "PADLO" define which bits - low or high, in the - * incomplete high byte, are filled with padding bits. - * - * The pixel codes are grouped by type, bus_width, bits per component, samples - * per pixel and order of subsamples. Numerical values are sorted using generic - * numerical sort order (8 thus comes before 10). - * - * As their value can't change when a new pixel code is inserted in the - * enumeration, the pixel codes are explicitly given a numerical value. The next - * free values for each category are listed below, update them when inserting - * new pixel codes. - */ -enum v4l2_mbus_pixelcode { - V4L2_MBUS_FMT_FIXED = 0x0001, - - /* RGB - next is 0x1009 */ - V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001, - V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002, - V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003, - V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE = 0x1004, - V4L2_MBUS_FMT_BGR565_2X8_BE = 0x1005, - V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006, - V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007, - V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008, - - /* YUV (including grey) - next is 0x2013 */ - V4L2_MBUS_FMT_Y8_1X8 = 0x2001, - V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002, - V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003, - V4L2_MBUS_FMT_YUYV8_1_5X8 = 0x2004, - V4L2_MBUS_FMT_YVYU8_1_5X8 = 0x2005, - V4L2_MBUS_FMT_UYVY8_2X8 = 0x2006, - V4L2_MBUS_FMT_VYUY8_2X8 = 0x2007, - V4L2_MBUS_FMT_YUYV8_2X8 = 0x2008, - V4L2_MBUS_FMT_YVYU8_2X8 = 0x2009, - V4L2_MBUS_FMT_Y10_1X10 = 0x200a, - V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b, - V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c, - V4L2_MBUS_FMT_UYVY8_1X16 = 0x200f, - V4L2_MBUS_FMT_VYUY8_1X16 = 0x2010, - V4L2_MBUS_FMT_YUYV8_1X16 = 0x2011, - V4L2_MBUS_FMT_YVYU8_1X16 = 0x2012, - V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d, - V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e, - - /* Bayer - next is 0x3013 */ - V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001, - V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002, - V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 = 0x300b, - V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 = 0x300c, - V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 = 0x3009, - V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 = 0x300d, - V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003, - V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004, - V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005, - V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006, - V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007, - V4L2_MBUS_FMT_SGBRG10_1X10 = 0x300e, - V4L2_MBUS_FMT_SGRBG10_1X10 = 0x300a, - V4L2_MBUS_FMT_SRGGB10_1X10 = 0x300f, - V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008, - V4L2_MBUS_FMT_SGBRG12_1X12 = 0x3010, - V4L2_MBUS_FMT_SGRBG12_1X12 = 0x3011, - V4L2_MBUS_FMT_SRGGB12_1X12 = 0x3012, -}; - -/** - * struct v4l2_mbus_framefmt - frame format on the media bus - * @width: frame width - * @height: frame height - * @code: data format code (from enum v4l2_mbus_pixelcode) - * @field: used interlacing type (from enum v4l2_field) - * @colorspace: colorspace of the data (from enum v4l2_colorspace) - */ -struct v4l2_mbus_framefmt { - __u32 width; - __u32 height; - __u32 code; - __u32 field; - __u32 colorspace; - __u32 reserved[7]; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/v4l2-subdev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/v4l2-subdev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/v4l2-subdev.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/v4l2-subdev.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/* - * V4L2 subdev userspace API - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - */ - -#ifndef __LINUX_V4L2_SUBDEV_H -#define __LINUX_V4L2_SUBDEV_H - -#include -#include -#include - -/** - * enum v4l2_subdev_format_whence - Media bus format type - * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only - * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device - */ -enum v4l2_subdev_format_whence { - V4L2_SUBDEV_FORMAT_TRY = 0, - V4L2_SUBDEV_FORMAT_ACTIVE = 1, -}; - -/** - * struct v4l2_subdev_format - Pad-level media bus format - * @which: format type (from enum v4l2_subdev_format_whence) - * @pad: pad number, as reported by the media API - * @format: media bus format (format code and frame size) - */ -struct v4l2_subdev_format { - __u32 which; - __u32 pad; - struct v4l2_mbus_framefmt format; - __u32 reserved[8]; -}; - -/** - * struct v4l2_subdev_crop - Pad-level crop settings - * @which: format type (from enum v4l2_subdev_format_whence) - * @pad: pad number, as reported by the media API - * @rect: pad crop rectangle boundaries - */ -struct v4l2_subdev_crop { - __u32 which; - __u32 pad; - struct v4l2_rect rect; - __u32 reserved[8]; -}; - -/** - * struct v4l2_subdev_mbus_code_enum - Media bus format enumeration - * @pad: pad number, as reported by the media API - * @index: format index during enumeration - * @code: format code (from enum v4l2_mbus_pixelcode) - */ -struct v4l2_subdev_mbus_code_enum { - __u32 pad; - __u32 index; - __u32 code; - __u32 reserved[9]; -}; - -/** - * struct v4l2_subdev_frame_size_enum - Media bus format enumeration - * @pad: pad number, as reported by the media API - * @index: format index during enumeration - * @code: format code (from enum v4l2_mbus_pixelcode) - */ -struct v4l2_subdev_frame_size_enum { - __u32 index; - __u32 pad; - __u32 code; - __u32 min_width; - __u32 max_width; - __u32 min_height; - __u32 max_height; - __u32 reserved[9]; -}; - -/** - * struct v4l2_subdev_frame_interval - Pad-level frame rate - * @pad: pad number, as reported by the media API - * @interval: frame interval in seconds - */ -struct v4l2_subdev_frame_interval { - __u32 pad; - struct v4l2_fract interval; - __u32 reserved[9]; -}; - -/** - * struct v4l2_subdev_frame_interval_enum - Frame interval enumeration - * @pad: pad number, as reported by the media API - * @index: frame interval index during enumeration - * @code: format code (from enum v4l2_mbus_pixelcode) - * @width: frame width in pixels - * @height: frame height in pixels - * @interval: frame interval in seconds - */ -struct v4l2_subdev_frame_interval_enum { - __u32 index; - __u32 pad; - __u32 code; - __u32 width; - __u32 height; - struct v4l2_fract interval; - __u32 reserved[9]; -}; - -#define VIDIOC_SUBDEV_G_FMT _IOWR('V', 4, struct v4l2_subdev_format) -#define VIDIOC_SUBDEV_S_FMT _IOWR('V', 5, struct v4l2_subdev_format) -#define VIDIOC_SUBDEV_G_FRAME_INTERVAL \ - _IOWR('V', 21, struct v4l2_subdev_frame_interval) -#define VIDIOC_SUBDEV_S_FRAME_INTERVAL \ - _IOWR('V', 22, struct v4l2_subdev_frame_interval) -#define VIDIOC_SUBDEV_ENUM_MBUS_CODE \ - _IOWR('V', 2, struct v4l2_subdev_mbus_code_enum) -#define VIDIOC_SUBDEV_ENUM_FRAME_SIZE \ - _IOWR('V', 74, struct v4l2_subdev_frame_size_enum) -#define VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \ - _IOWR('V', 75, struct v4l2_subdev_frame_interval_enum) -#define VIDIOC_SUBDEV_G_CROP _IOWR('V', 59, struct v4l2_subdev_crop) -#define VIDIOC_SUBDEV_S_CROP _IOWR('V', 60, struct v4l2_subdev_crop) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/via-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/via-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/via-core.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/via-core.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,236 +0,0 @@ -/* - * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. - * Copyright 2009-2010 Jonathan Corbet - * Copyright 2010 Florian Tobias Schandinat - * - * 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, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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. - */ - -#ifndef __VIA_CORE_H__ -#define __VIA_CORE_H__ -#include -#include -#include -#include - -/* - * A description of each known serial I2C/GPIO port. - */ -enum via_port_type { - VIA_PORT_NONE = 0, - VIA_PORT_I2C, - VIA_PORT_GPIO, -}; - -enum via_port_mode { - VIA_MODE_OFF = 0, - VIA_MODE_I2C, /* Used as I2C port */ - VIA_MODE_GPIO, /* Two GPIO ports */ -}; - -enum viafb_i2c_adap { - VIA_PORT_26 = 0, - VIA_PORT_31, - VIA_PORT_25, - VIA_PORT_2C, - VIA_PORT_3D, -}; -#define VIAFB_NUM_PORTS 5 - -struct via_port_cfg { - enum via_port_type type; - enum via_port_mode mode; - u16 io_port; - u8 ioport_index; -}; - -/* - * Allow subdevs to register suspend/resume hooks. - */ -#ifdef CONFIG_PM -struct viafb_pm_hooks { - struct list_head list; - int (*suspend)(void *private); - int (*resume)(void *private); - void *private; -}; - -void viafb_pm_register(struct viafb_pm_hooks *hooks); -void viafb_pm_unregister(struct viafb_pm_hooks *hooks); -#endif /* CONFIG_PM */ - -/* - * This is the global viafb "device" containing stuff needed by - * all subdevs. - */ -struct viafb_dev { - struct pci_dev *pdev; - int chip_type; - struct via_port_cfg *port_cfg; - /* - * Spinlock for access to device registers. Not yet - * globally used. - */ - spinlock_t reg_lock; - /* - * The framebuffer MMIO region. Little, if anything, touches - * this memory directly, and certainly nothing outside of the - * framebuffer device itself. We *do* have to be able to allocate - * chunks of this memory for other devices, though. - */ - unsigned long fbmem_start; - long fbmem_len; - void __iomem *fbmem; -#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE) - long camera_fbmem_offset; - long camera_fbmem_size; -#endif - /* - * The MMIO region for device registers. - */ - unsigned long engine_start; - unsigned long engine_len; - void __iomem *engine_mmio; - -}; - -/* - * Interrupt management. - */ - -void viafb_irq_enable(u32 mask); -void viafb_irq_disable(u32 mask); - -/* - * The global interrupt control register and its bits. - */ -#define VDE_INTERRUPT 0x200 /* Video interrupt flags/masks */ -#define VDE_I_DVISENSE 0x00000001 /* DVI sense int status */ -#define VDE_I_VBLANK 0x00000002 /* Vertical blank status */ -#define VDE_I_MCCFI 0x00000004 /* MCE compl. frame int status */ -#define VDE_I_VSYNC 0x00000008 /* VGA VSYNC int status */ -#define VDE_I_DMA0DDONE 0x00000010 /* DMA 0 descr done */ -#define VDE_I_DMA0TDONE 0x00000020 /* DMA 0 transfer done */ -#define VDE_I_DMA1DDONE 0x00000040 /* DMA 1 descr done */ -#define VDE_I_DMA1TDONE 0x00000080 /* DMA 1 transfer done */ -#define VDE_I_C1AV 0x00000100 /* Cap Eng 1 act vid end */ -#define VDE_I_HQV0 0x00000200 /* First HQV engine */ -#define VDE_I_HQV1 0x00000400 /* Second HQV engine */ -#define VDE_I_HQV1EN 0x00000800 /* Second HQV engine enable */ -#define VDE_I_C0AV 0x00001000 /* Cap Eng 0 act vid end */ -#define VDE_I_C0VBI 0x00002000 /* Cap Eng 0 VBI end */ -#define VDE_I_C1VBI 0x00004000 /* Cap Eng 1 VBI end */ -#define VDE_I_VSYNC2 0x00008000 /* Sec. Disp. VSYNC */ -#define VDE_I_DVISNSEN 0x00010000 /* DVI sense enable */ -#define VDE_I_VSYNC2EN 0x00020000 /* Sec Disp VSYNC enable */ -#define VDE_I_MCCFIEN 0x00040000 /* MC comp frame int mask enable */ -#define VDE_I_VSYNCEN 0x00080000 /* VSYNC enable */ -#define VDE_I_DMA0DDEN 0x00100000 /* DMA 0 descr done enable */ -#define VDE_I_DMA0TDEN 0x00200000 /* DMA 0 trans done enable */ -#define VDE_I_DMA1DDEN 0x00400000 /* DMA 1 descr done enable */ -#define VDE_I_DMA1TDEN 0x00800000 /* DMA 1 trans done enable */ -#define VDE_I_C1AVEN 0x01000000 /* cap 1 act vid end enable */ -#define VDE_I_HQV0EN 0x02000000 /* First hqv engine enable */ -#define VDE_I_C1VBIEN 0x04000000 /* Cap 1 VBI end enable */ -#define VDE_I_LVDSSI 0x08000000 /* LVDS sense interrupt */ -#define VDE_I_C0AVEN 0x10000000 /* Cap 0 act vid end enable */ -#define VDE_I_C0VBIEN 0x20000000 /* Cap 0 VBI end enable */ -#define VDE_I_LVDSSIEN 0x40000000 /* LVDS Sense enable */ -#define VDE_I_ENABLE 0x80000000 /* Global interrupt enable */ - -#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE) -/* - * DMA management. - */ -int viafb_request_dma(void); -void viafb_release_dma(void); -/* void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len); */ -int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg); - -/* - * DMA Controller registers. - */ -#define VDMA_MR0 0xe00 /* Mod reg 0 */ -#define VDMA_MR_CHAIN 0x01 /* Chaining mode */ -#define VDMA_MR_TDIE 0x02 /* Transfer done int enable */ -#define VDMA_CSR0 0xe04 /* Control/status */ -#define VDMA_C_ENABLE 0x01 /* DMA Enable */ -#define VDMA_C_START 0x02 /* Start a transfer */ -#define VDMA_C_ABORT 0x04 /* Abort a transfer */ -#define VDMA_C_DONE 0x08 /* Transfer is done */ -#define VDMA_MARL0 0xe20 /* Mem addr low */ -#define VDMA_MARH0 0xe24 /* Mem addr high */ -#define VDMA_DAR0 0xe28 /* Device address */ -#define VDMA_DQWCR0 0xe2c /* Count (16-byte) */ -#define VDMA_TMR0 0xe30 /* Tile mode reg */ -#define VDMA_DPRL0 0xe34 /* Not sure */ -#define VDMA_DPR_IN 0x08 /* Inbound transfer to FB */ -#define VDMA_DPRH0 0xe38 -#define VDMA_PMR0 (0xe00 + 0x134) /* Pitch mode */ - -/* - * Useful stuff that probably belongs somewhere global. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#endif /* CONFIG_VIDEO_VIA_CAMERA */ - -/* - * Indexed port operations. Note that these are all multi-op - * functions; every invocation will be racy if you're not holding - * reg_lock. - */ - -#define VIAStatus 0x3DA /* Non-indexed port */ -#define VIACR 0x3D4 -#define VIASR 0x3C4 -#define VIAGR 0x3CE -#define VIAAR 0x3C0 - -static inline u8 via_read_reg(u16 port, u8 index) -{ - outb(index, port); - return inb(port + 1); -} - -static inline void via_write_reg(u16 port, u8 index, u8 data) -{ - outb(index, port); - outb(data, port + 1); -} - -static inline void via_write_reg_mask(u16 port, u8 index, u8 data, u8 mask) -{ - u8 old; - - outb(index, port); - old = inb(port + 1); - outb((data & mask) | (old & ~mask), port + 1); -} - -#define VIA_MISC_REG_READ 0x03CC -#define VIA_MISC_REG_WRITE 0x03C2 - -static inline void via_write_misc_reg_mask(u8 data, u8 mask) -{ - u8 old = inb(VIA_MISC_REG_READ); - outb((data & mask) | (old & ~mask), VIA_MISC_REG_WRITE); -} - - -#endif /* __VIA_CORE_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/videodev2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/videodev2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/linux/videodev2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/linux/videodev2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1945 +0,0 @@ -/* - * Video for Linux Two header file - * - * Copyright (C) 1999-2007 the contributors - * - * 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, or - * (at your option) any later version. - * - * 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. - * - * Alternatively you can redistribute this file under the terms of the - * BSD license as stated below: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. The names of its contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Header file for v4l or V4L2 drivers and applications - * with public API. - * All kernel-specific stuff were moved to media/v4l2-dev.h, so - * no #if __KERNEL tests are allowed here - * - * See http://linuxtv.org for more info - * - * Author: Bill Dirks - * Justin Schoeman - * Hans Verkuil - * et al. - */ -#ifndef __LINUX_VIDEODEV2_H -#define __LINUX_VIDEODEV2_H - -#ifdef __KERNEL__ -#include /* need struct timeval */ -#else -#include -#endif -#include -#include -#include - -/* - * Common stuff for both V4L1 and V4L2 - * Moved from videodev.h - */ -#define VIDEO_MAX_FRAME 32 -#define VIDEO_MAX_PLANES 8 - -#ifndef __KERNEL__ - -/* These defines are V4L1 specific and should not be used with the V4L2 API! - They will be removed from this header in the future. */ - -#define VID_TYPE_CAPTURE 1 /* Can capture */ -#define VID_TYPE_TUNER 2 /* Can tune */ -#define VID_TYPE_TELETEXT 4 /* Does teletext */ -#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ -#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ -#define VID_TYPE_CLIPPING 32 /* Can clip */ -#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ -#define VID_TYPE_SCALES 128 /* Scalable */ -#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ -#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ -#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ -#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ -#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ -#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ -#endif - -/* - * M I S C E L L A N E O U S - */ - -/* Four-character-code (FOURCC) */ -#define v4l2_fourcc(a, b, c, d)\ - ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) - -/* - * E N U M S - */ -enum v4l2_field { - V4L2_FIELD_ANY = 0, /* driver can choose from none, - top, bottom, interlaced - depending on whatever it thinks - is approximate ... */ - V4L2_FIELD_NONE = 1, /* this device has no fields ... */ - V4L2_FIELD_TOP = 2, /* top field only */ - V4L2_FIELD_BOTTOM = 3, /* bottom field only */ - V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */ - V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one - buffer, top-bottom order */ - V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */ - V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into - separate buffers */ - V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field - first and the top field is - transmitted first */ - V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field - first and the bottom field is - transmitted first */ -}; -#define V4L2_FIELD_HAS_TOP(field) \ - ((field) == V4L2_FIELD_TOP ||\ - (field) == V4L2_FIELD_INTERLACED ||\ - (field) == V4L2_FIELD_INTERLACED_TB ||\ - (field) == V4L2_FIELD_INTERLACED_BT ||\ - (field) == V4L2_FIELD_SEQ_TB ||\ - (field) == V4L2_FIELD_SEQ_BT) -#define V4L2_FIELD_HAS_BOTTOM(field) \ - ((field) == V4L2_FIELD_BOTTOM ||\ - (field) == V4L2_FIELD_INTERLACED ||\ - (field) == V4L2_FIELD_INTERLACED_TB ||\ - (field) == V4L2_FIELD_INTERLACED_BT ||\ - (field) == V4L2_FIELD_SEQ_TB ||\ - (field) == V4L2_FIELD_SEQ_BT) -#define V4L2_FIELD_HAS_BOTH(field) \ - ((field) == V4L2_FIELD_INTERLACED ||\ - (field) == V4L2_FIELD_INTERLACED_TB ||\ - (field) == V4L2_FIELD_INTERLACED_BT ||\ - (field) == V4L2_FIELD_SEQ_TB ||\ - (field) == V4L2_FIELD_SEQ_BT) - -enum v4l2_buf_type { - V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, - V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, - V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, - V4L2_BUF_TYPE_VBI_CAPTURE = 4, - V4L2_BUF_TYPE_VBI_OUTPUT = 5, - V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, - V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, -#if 1 - /* Experimental */ - V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, -#endif - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10, - V4L2_BUF_TYPE_PRIVATE = 0x80, -}; - -#define V4L2_TYPE_IS_MULTIPLANAR(type) \ - ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE \ - || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - -#define V4L2_TYPE_IS_OUTPUT(type) \ - ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT \ - || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE \ - || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY \ - || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY \ - || (type) == V4L2_BUF_TYPE_VBI_OUTPUT \ - || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) - -enum v4l2_tuner_type { - V4L2_TUNER_RADIO = 1, - V4L2_TUNER_ANALOG_TV = 2, - V4L2_TUNER_DIGITAL_TV = 3, -}; - -enum v4l2_memory { - V4L2_MEMORY_MMAP = 1, - V4L2_MEMORY_USERPTR = 2, - V4L2_MEMORY_OVERLAY = 3, -}; - -/* see also http://vektor.theorem.ca/graphics/ycbcr/ */ -enum v4l2_colorspace { - /* ITU-R 601 -- broadcast NTSC/PAL */ - V4L2_COLORSPACE_SMPTE170M = 1, - - /* 1125-Line (US) HDTV */ - V4L2_COLORSPACE_SMPTE240M = 2, - - /* HD and modern captures. */ - V4L2_COLORSPACE_REC709 = 3, - - /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */ - V4L2_COLORSPACE_BT878 = 4, - - /* These should be useful. Assume 601 extents. */ - V4L2_COLORSPACE_470_SYSTEM_M = 5, - V4L2_COLORSPACE_470_SYSTEM_BG = 6, - - /* I know there will be cameras that send this. So, this is - * unspecified chromaticities and full 0-255 on each of the - * Y'CbCr components - */ - V4L2_COLORSPACE_JPEG = 7, - - /* For RGB colourspaces, this is probably a good start. */ - V4L2_COLORSPACE_SRGB = 8, -}; - -enum v4l2_priority { - V4L2_PRIORITY_UNSET = 0, /* not initialized */ - V4L2_PRIORITY_BACKGROUND = 1, - V4L2_PRIORITY_INTERACTIVE = 2, - V4L2_PRIORITY_RECORD = 3, - V4L2_PRIORITY_DEFAULT = V4L2_PRIORITY_INTERACTIVE, -}; - -struct v4l2_rect { - __s32 left; - __s32 top; - __s32 width; - __s32 height; -}; - -struct v4l2_fract { - __u32 numerator; - __u32 denominator; -}; - -/* - * D R I V E R C A P A B I L I T I E S - */ -struct v4l2_capability { - __u8 driver[16]; /* i.e. "bttv" */ - __u8 card[32]; /* i.e. "Hauppauge WinTV" */ - __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ - __u32 version; /* should use KERNEL_VERSION() */ - __u32 capabilities; /* Device capabilities */ - __u32 reserved[4]; -}; - -/* Values for 'capabilities' field */ -#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ -#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ -#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ -#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a raw VBI capture device */ -#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a raw VBI output device */ -#define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 /* Is a sliced VBI capture device */ -#define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 /* Is a sliced VBI output device */ -#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ -#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 /* Can do video output overlay */ -#define V4L2_CAP_HW_FREQ_SEEK 0x00000400 /* Can do hardware frequency seek */ -#define V4L2_CAP_RDS_OUTPUT 0x00000800 /* Is an RDS encoder */ - -/* Is a video capture device that supports multiplanar formats */ -#define V4L2_CAP_VIDEO_CAPTURE_MPLANE 0x00001000 -/* Is a video output device that supports multiplanar formats */ -#define V4L2_CAP_VIDEO_OUTPUT_MPLANE 0x00002000 - -#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ -#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ -#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */ -#define V4L2_CAP_MODULATOR 0x00080000 /* has a modulator */ - -#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ -#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ -#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ - -/* - * V I D E O I M A G E F O R M A T - */ -struct v4l2_pix_format { - __u32 width; - __u32 height; - __u32 pixelformat; - enum v4l2_field field; - __u32 bytesperline; /* for padding, zero if unused */ - __u32 sizeimage; - enum v4l2_colorspace colorspace; - __u32 priv; /* private data, depends on pixelformat */ -}; - -/* Pixel format FOURCC depth Description */ - -/* RGB formats */ -#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R', 'G', 'B', '1') /* 8 RGB-3-3-2 */ -#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R', '4', '4', '4') /* 16 xxxxrrrr ggggbbbb */ -#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R', 'G', 'B', 'O') /* 16 RGB-5-5-5 */ -#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */ -#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */ -#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */ -#define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */ -#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */ -#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */ -#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */ -#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4') /* 32 RGB-8-8-8-8 */ - -/* Grey formats */ -#define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ -#define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */ -#define V4L2_PIX_FMT_Y6 v4l2_fourcc('Y', '0', '6', ' ') /* 6 Greyscale */ -#define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */ -#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ - -/* Palette formats */ -#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */ - -/* Luminance+Chrominance formats */ -#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') /* 9 YVU 4:1:0 */ -#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ -#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */ -#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */ -#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */ -#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P') /* 12 YUV 4:1:1 */ -#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4') /* 16 xxxxyyyy uuuuvvvv */ -#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y', 'U', 'V', 'O') /* 16 YUV-5-5-5 */ -#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y', 'U', 'V', 'P') /* 16 YUV-5-6-5 */ -#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y', 'U', 'V', '4') /* 32 YUV-8-8-8-8 */ -#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */ -#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ -#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */ -#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ - -/* two planes -- one Y, one Cr + Cb interleaved */ -#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */ -#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */ -#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */ -#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ - -/* two non contiguous planes - one Y, one Cr + Cb interleaved */ -#define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ -#define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ - -/* three non contiguous planes - Y, Cb, Cr */ -#define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ - -/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ -#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ -#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */ -#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B') /* 8 RGRG.. GBGB.. */ -#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0') /* 10 BGBG.. GRGR.. */ -#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */ -#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */ -#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12 BGBG.. GRGR.. */ -#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12 GRGR.. BGBG.. */ -#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */ - /* 10bit raw bayer DPCM compressed to 8 bits */ -#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0') - /* - * 10bit raw bayer, expanded to 16 bits - * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb... - */ -#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */ - -/* compressed formats */ -#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */ -#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG */ -#define V4L2_PIX_FMT_DV v4l2_fourcc('d', 'v', 's', 'd') /* 1394 */ -#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 */ - -/* Vendor-specific formats */ -#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ -#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */ -#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */ -#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */ -#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */ -#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */ -#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */ -#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S', '5', '0', '1') /* YUYV per line */ -#define V4L2_PIX_FMT_SPCA505 v4l2_fourcc('S', '5', '0', '5') /* YYUV per line */ -#define V4L2_PIX_FMT_SPCA508 v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */ -#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */ -#define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */ -#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */ -#define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */ -#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */ -#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */ -#define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */ -#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */ -#define V4L2_PIX_FMT_STV0680 v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */ -#define V4L2_PIX_FMT_TM6000 v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */ -#define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */ -#define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */ -#define V4L2_PIX_FMT_JPGL v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */ - -/* - * F O R M A T E N U M E R A T I O N - */ -struct v4l2_fmtdesc { - __u32 index; /* Format number */ - enum v4l2_buf_type type; /* buffer type */ - __u32 flags; - __u8 description[32]; /* Description string */ - __u32 pixelformat; /* Format fourcc */ - __u32 reserved[4]; -}; - -#define V4L2_FMT_FLAG_COMPRESSED 0x0001 -#define V4L2_FMT_FLAG_EMULATED 0x0002 - -#if 1 - /* Experimental Frame Size and frame rate enumeration */ -/* - * F R A M E S I Z E E N U M E R A T I O N - */ -enum v4l2_frmsizetypes { - V4L2_FRMSIZE_TYPE_DISCRETE = 1, - V4L2_FRMSIZE_TYPE_CONTINUOUS = 2, - V4L2_FRMSIZE_TYPE_STEPWISE = 3, -}; - -struct v4l2_frmsize_discrete { - __u32 width; /* Frame width [pixel] */ - __u32 height; /* Frame height [pixel] */ -}; - -struct v4l2_frmsize_stepwise { - __u32 min_width; /* Minimum frame width [pixel] */ - __u32 max_width; /* Maximum frame width [pixel] */ - __u32 step_width; /* Frame width step size [pixel] */ - __u32 min_height; /* Minimum frame height [pixel] */ - __u32 max_height; /* Maximum frame height [pixel] */ - __u32 step_height; /* Frame height step size [pixel] */ -}; - -struct v4l2_frmsizeenum { - __u32 index; /* Frame size number */ - __u32 pixel_format; /* Pixel format */ - __u32 type; /* Frame size type the device supports. */ - - union { /* Frame size */ - struct v4l2_frmsize_discrete discrete; - struct v4l2_frmsize_stepwise stepwise; - }; - - __u32 reserved[2]; /* Reserved space for future use */ -}; - -/* - * F R A M E R A T E E N U M E R A T I O N - */ -enum v4l2_frmivaltypes { - V4L2_FRMIVAL_TYPE_DISCRETE = 1, - V4L2_FRMIVAL_TYPE_CONTINUOUS = 2, - V4L2_FRMIVAL_TYPE_STEPWISE = 3, -}; - -struct v4l2_frmival_stepwise { - struct v4l2_fract min; /* Minimum frame interval [s] */ - struct v4l2_fract max; /* Maximum frame interval [s] */ - struct v4l2_fract step; /* Frame interval step size [s] */ -}; - -struct v4l2_frmivalenum { - __u32 index; /* Frame format index */ - __u32 pixel_format; /* Pixel format */ - __u32 width; /* Frame width */ - __u32 height; /* Frame height */ - __u32 type; /* Frame interval type the device supports. */ - - union { /* Frame interval */ - struct v4l2_fract discrete; - struct v4l2_frmival_stepwise stepwise; - }; - - __u32 reserved[2]; /* Reserved space for future use */ -}; -#endif - -/* - * T I M E C O D E - */ -struct v4l2_timecode { - __u32 type; - __u32 flags; - __u8 frames; - __u8 seconds; - __u8 minutes; - __u8 hours; - __u8 userbits[4]; -}; - -/* Type */ -#define V4L2_TC_TYPE_24FPS 1 -#define V4L2_TC_TYPE_25FPS 2 -#define V4L2_TC_TYPE_30FPS 3 -#define V4L2_TC_TYPE_50FPS 4 -#define V4L2_TC_TYPE_60FPS 5 - -/* Flags */ -#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ -#define V4L2_TC_FLAG_COLORFRAME 0x0002 -#define V4L2_TC_USERBITS_field 0x000C -#define V4L2_TC_USERBITS_USERDEFINED 0x0000 -#define V4L2_TC_USERBITS_8BITCHARS 0x0008 -/* The above is based on SMPTE timecodes */ - -struct v4l2_jpegcompression { - int quality; - - int APPn; /* Number of APP segment to be written, - * must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ - - __u32 jpeg_markers; /* Which markers should go into the JPEG - * output. Unless you exactly know what - * you do, leave them untouched. - * Inluding less markers will make the - * resulting code smaller, but there will - * be fewer applications which can read it. - * The presence of the APP and COM marker - * is influenced by APP_len and COM_len - * ONLY, not by this property! */ - -#define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ -#define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ -#define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ -#define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */ -#define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will - * allways use APP0 */ -}; - -/* - * M E M O R Y - M A P P I N G B U F F E R S - */ -struct v4l2_requestbuffers { - __u32 count; - enum v4l2_buf_type type; - enum v4l2_memory memory; - __u32 reserved[2]; -}; - -/** - * struct v4l2_plane - plane info for multi-planar buffers - * @bytesused: number of bytes occupied by data in the plane (payload) - * @length: size of this plane (NOT the payload) in bytes - * @mem_offset: when memory in the associated struct v4l2_buffer is - * V4L2_MEMORY_MMAP, equals the offset from the start of - * the device memory for this plane (or is a "cookie" that - * should be passed to mmap() called on the video node) - * @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer - * pointing to this plane - * @data_offset: offset in the plane to the start of data; usually 0, - * unless there is a header in front of the data - * - * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer - * with two planes can have one plane for Y, and another for interleaved CbCr - * components. Each plane can reside in a separate memory buffer, or even in - * a completely separate memory node (e.g. in embedded devices). - */ -struct v4l2_plane { - __u32 bytesused; - __u32 length; - union { - __u32 mem_offset; - unsigned long userptr; - } m; - __u32 data_offset; - __u32 reserved[11]; -}; - -/** - * struct v4l2_buffer - video buffer info - * @index: id number of the buffer - * @type: buffer type (type == *_MPLANE for multiplanar buffers) - * @bytesused: number of bytes occupied by data in the buffer (payload); - * unused (set to 0) for multiplanar buffers - * @flags: buffer informational flags - * @field: field order of the image in the buffer - * @timestamp: frame timestamp - * @timecode: frame timecode - * @sequence: sequence count of this frame - * @memory: the method, in which the actual video data is passed - * @offset: for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP; - * offset from the start of the device memory for this plane, - * (or a "cookie" that should be passed to mmap() as offset) - * @userptr: for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR; - * a userspace pointer pointing to this buffer - * @planes: for multiplanar buffers; userspace pointer to the array of plane - * info structs for this buffer - * @length: size in bytes of the buffer (NOT its payload) for single-plane - * buffers (when type != *_MPLANE); number of elements in the - * planes array for multi-plane buffers - * @input: input number from which the video data has has been captured - * - * Contains data exchanged by application and driver using one of the Streaming - * I/O methods. - */ -struct v4l2_buffer { - __u32 index; - enum v4l2_buf_type type; - __u32 bytesused; - __u32 flags; - enum v4l2_field field; - struct timeval timestamp; - struct v4l2_timecode timecode; - __u32 sequence; - - /* memory location */ - enum v4l2_memory memory; - union { - __u32 offset; - unsigned long userptr; - struct v4l2_plane *planes; - } m; - __u32 length; - __u32 input; - __u32 reserved; -}; - -/* Flags for 'flags' field */ -#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ -#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ -#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ -#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ -#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ -#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ -/* Buffer is ready, but the data contained within is corrupted. */ -#define V4L2_BUF_FLAG_ERROR 0x0040 -#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ -#define V4L2_BUF_FLAG_INPUT 0x0200 /* input field is valid */ - -/* - * O V E R L A Y P R E V I E W - */ -struct v4l2_framebuffer { - __u32 capability; - __u32 flags; -/* FIXME: in theory we should pass something like PCI device + memory - * region + offset instead of some physical address */ - void *base; - struct v4l2_pix_format fmt; -}; -/* Flags for the 'capability' field. Read only */ -#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 -#define V4L2_FBUF_CAP_CHROMAKEY 0x0002 -#define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004 -#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008 -#define V4L2_FBUF_CAP_LOCAL_ALPHA 0x0010 -#define V4L2_FBUF_CAP_GLOBAL_ALPHA 0x0020 -#define V4L2_FBUF_CAP_LOCAL_INV_ALPHA 0x0040 -#define V4L2_FBUF_CAP_SRC_CHROMAKEY 0x0080 -/* Flags for the 'flags' field. */ -#define V4L2_FBUF_FLAG_PRIMARY 0x0001 -#define V4L2_FBUF_FLAG_OVERLAY 0x0002 -#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 -#define V4L2_FBUF_FLAG_LOCAL_ALPHA 0x0008 -#define V4L2_FBUF_FLAG_GLOBAL_ALPHA 0x0010 -#define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA 0x0020 -#define V4L2_FBUF_FLAG_SRC_CHROMAKEY 0x0040 - -struct v4l2_clip { - struct v4l2_rect c; - struct v4l2_clip __user *next; -}; - -struct v4l2_window { - struct v4l2_rect w; - enum v4l2_field field; - __u32 chromakey; - struct v4l2_clip __user *clips; - __u32 clipcount; - void __user *bitmap; - __u8 global_alpha; -}; - -/* - * C A P T U R E P A R A M E T E R S - */ -struct v4l2_captureparm { - __u32 capability; /* Supported modes */ - __u32 capturemode; /* Current mode */ - struct v4l2_fract timeperframe; /* Time per frame in .1us units */ - __u32 extendedmode; /* Driver-specific extensions */ - __u32 readbuffers; /* # of buffers for read */ - __u32 reserved[4]; -}; - -/* Flags for 'capability' and 'capturemode' fields */ -#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ -#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ - -struct v4l2_outputparm { - __u32 capability; /* Supported modes */ - __u32 outputmode; /* Current mode */ - struct v4l2_fract timeperframe; /* Time per frame in seconds */ - __u32 extendedmode; /* Driver-specific extensions */ - __u32 writebuffers; /* # of buffers for write */ - __u32 reserved[4]; -}; - -/* - * I N P U T I M A G E C R O P P I N G - */ -struct v4l2_cropcap { - enum v4l2_buf_type type; - struct v4l2_rect bounds; - struct v4l2_rect defrect; - struct v4l2_fract pixelaspect; -}; - -struct v4l2_crop { - enum v4l2_buf_type type; - struct v4l2_rect c; -}; - -/* - * A N A L O G V I D E O S T A N D A R D - */ - -typedef __u64 v4l2_std_id; - -/* one bit for each */ -#define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001) -#define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002) -#define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004) -#define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008) -#define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010) -#define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020) -#define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040) -#define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080) - -#define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100) -#define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200) -#define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400) -#define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800) - -#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) -#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) -#define V4L2_STD_NTSC_443 ((v4l2_std_id)0x00004000) -#define V4L2_STD_NTSC_M_KR ((v4l2_std_id)0x00008000) - -#define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000) -#define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000) -#define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000) -#define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000) -#define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000) -#define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000) -#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000) -#define V4L2_STD_SECAM_LC ((v4l2_std_id)0x00800000) - -/* ATSC/HDTV */ -#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) -#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000) - -/* FIXME: - Although std_id is 64 bits, there is an issue on PPC32 architecture that - makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding - this value to 32 bits. - As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide), - it should work fine. However, if needed to add more than two standards, - v4l2-common.c should be fixed. - */ - -/* some merged standards */ -#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC) -#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B) -#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H) -#define V4L2_STD_DK (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK) - -/* some common needed stuff */ -#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ - V4L2_STD_PAL_B1 |\ - V4L2_STD_PAL_G) -#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ - V4L2_STD_PAL_D1 |\ - V4L2_STD_PAL_K) -#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ - V4L2_STD_PAL_DK |\ - V4L2_STD_PAL_H |\ - V4L2_STD_PAL_I) -#define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\ - V4L2_STD_NTSC_M_JP |\ - V4L2_STD_NTSC_M_KR) -#define V4L2_STD_SECAM_DK (V4L2_STD_SECAM_D |\ - V4L2_STD_SECAM_K |\ - V4L2_STD_SECAM_K1) -#define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\ - V4L2_STD_SECAM_G |\ - V4L2_STD_SECAM_H |\ - V4L2_STD_SECAM_DK |\ - V4L2_STD_SECAM_L |\ - V4L2_STD_SECAM_LC) - -#define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ - V4L2_STD_PAL_60 |\ - V4L2_STD_NTSC |\ - V4L2_STD_NTSC_443) -#define V4L2_STD_625_50 (V4L2_STD_PAL |\ - V4L2_STD_PAL_N |\ - V4L2_STD_PAL_Nc |\ - V4L2_STD_SECAM) -#define V4L2_STD_ATSC (V4L2_STD_ATSC_8_VSB |\ - V4L2_STD_ATSC_16_VSB) - -#define V4L2_STD_UNKNOWN 0 -#define V4L2_STD_ALL (V4L2_STD_525_60 |\ - V4L2_STD_625_50) - -struct v4l2_standard { - __u32 index; - v4l2_std_id id; - __u8 name[24]; - struct v4l2_fract frameperiod; /* Frames, not fields */ - __u32 framelines; - __u32 reserved[4]; -}; - -/* - * V I D E O T I M I N G S D V P R E S E T - */ -struct v4l2_dv_preset { - __u32 preset; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T S E N U M E R A T I O N - */ -struct v4l2_dv_enum_preset { - __u32 index; - __u32 preset; - __u8 name[32]; /* Name of the preset timing */ - __u32 width; - __u32 height; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T V A L U E S - */ -#define V4L2_DV_INVALID 0 -#define V4L2_DV_480P59_94 1 /* BT.1362 */ -#define V4L2_DV_576P50 2 /* BT.1362 */ -#define V4L2_DV_720P24 3 /* SMPTE 296M */ -#define V4L2_DV_720P25 4 /* SMPTE 296M */ -#define V4L2_DV_720P30 5 /* SMPTE 296M */ -#define V4L2_DV_720P50 6 /* SMPTE 296M */ -#define V4L2_DV_720P59_94 7 /* SMPTE 274M */ -#define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ -#define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I25 11 /* BT.1120 */ -#define V4L2_DV_1080I50 12 /* SMPTE 296M */ -#define V4L2_DV_1080I60 13 /* SMPTE 296M */ -#define V4L2_DV_1080P24 14 /* SMPTE 296M */ -#define V4L2_DV_1080P25 15 /* SMPTE 296M */ -#define V4L2_DV_1080P30 16 /* SMPTE 296M */ -#define V4L2_DV_1080P50 17 /* BT.1120 */ -#define V4L2_DV_1080P60 18 /* BT.1120 */ - -/* - * D V B T T I M I N G S - */ - -/* BT.656/BT.1120 timing data */ -struct v4l2_bt_timings { - __u32 width; /* width in pixels */ - __u32 height; /* height in lines */ - __u32 interlaced; /* Interlaced or progressive */ - __u32 polarities; /* Positive or negative polarity */ - __u64 pixelclock; /* Pixel clock in HZ. Ex. 74.25MHz->74250000 */ - __u32 hfrontporch; /* Horizpontal front porch in pixels */ - __u32 hsync; /* Horizontal Sync length in pixels */ - __u32 hbackporch; /* Horizontal back porch in pixels */ - __u32 vfrontporch; /* Vertical front porch in pixels */ - __u32 vsync; /* Vertical Sync length in lines */ - __u32 vbackporch; /* Vertical back porch in lines */ - __u32 il_vfrontporch; /* Vertical front porch for bottom field of - * interlaced field formats - */ - __u32 il_vsync; /* Vertical sync length for bottom field of - * interlaced field formats - */ - __u32 il_vbackporch; /* Vertical back porch for bottom field of - * interlaced field formats - */ - __u32 reserved[16]; -} __attribute__ ((packed)); - -/* Interlaced or progressive format */ -#define V4L2_DV_PROGRESSIVE 0 -#define V4L2_DV_INTERLACED 1 - -/* Polarities. If bit is not set, it is assumed to be negative polarity */ -#define V4L2_DV_VSYNC_POS_POL 0x00000001 -#define V4L2_DV_HSYNC_POS_POL 0x00000002 - - -/* DV timings */ -struct v4l2_dv_timings { - __u32 type; - union { - struct v4l2_bt_timings bt; - __u32 reserved[32]; - }; -} __attribute__ ((packed)); - -/* Values for the type field */ -#define V4L2_DV_BT_656_1120 0 /* BT.656/1120 timing type */ - -/* - * V I D E O I N P U T S - */ -struct v4l2_input { - __u32 index; /* Which input */ - __u8 name[32]; /* Label */ - __u32 type; /* Type of input */ - __u32 audioset; /* Associated audios (bitfield) */ - __u32 tuner; /* Associated tuner */ - v4l2_std_id std; - __u32 status; - __u32 capabilities; - __u32 reserved[3]; -}; - -/* Values for the 'type' field */ -#define V4L2_INPUT_TYPE_TUNER 1 -#define V4L2_INPUT_TYPE_CAMERA 2 - -/* field 'status' - general */ -#define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */ -#define V4L2_IN_ST_NO_SIGNAL 0x00000002 -#define V4L2_IN_ST_NO_COLOR 0x00000004 - -/* field 'status' - sensor orientation */ -/* If sensor is mounted upside down set both bits */ -#define V4L2_IN_ST_HFLIP 0x00000010 /* Frames are flipped horizontally */ -#define V4L2_IN_ST_VFLIP 0x00000020 /* Frames are flipped vertically */ - -/* field 'status' - analog */ -#define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */ -#define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */ - -/* field 'status' - digital */ -#define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */ -#define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */ -#define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */ - -/* field 'status' - VCR and set-top box */ -#define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */ -#define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ -#define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ - -/* capabilities flags */ -#define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ -#define V4L2_IN_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ -#define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ - -/* - * V I D E O O U T P U T S - */ -struct v4l2_output { - __u32 index; /* Which output */ - __u8 name[32]; /* Label */ - __u32 type; /* Type of output */ - __u32 audioset; /* Associated audios (bitfield) */ - __u32 modulator; /* Associated modulator */ - v4l2_std_id std; - __u32 capabilities; - __u32 reserved[3]; -}; -/* Values for the 'type' field */ -#define V4L2_OUTPUT_TYPE_MODULATOR 1 -#define V4L2_OUTPUT_TYPE_ANALOG 2 -#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 - -/* capabilities flags */ -#define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ -#define V4L2_OUT_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ -#define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ - -/* - * C O N T R O L S - */ -struct v4l2_control { - __u32 id; - __s32 value; -}; - -struct v4l2_ext_control { - __u32 id; - __u32 size; - __u32 reserved2[1]; - union { - __s32 value; - __s64 value64; - char *string; - }; -} __attribute__ ((packed)); - -struct v4l2_ext_controls { - __u32 ctrl_class; - __u32 count; - __u32 error_idx; - __u32 reserved[2]; - struct v4l2_ext_control *controls; -}; - -/* Values for ctrl_class field */ -#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */ -#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */ -#define V4L2_CTRL_CLASS_CAMERA 0x009a0000 /* Camera class controls */ -#define V4L2_CTRL_CLASS_FM_TX 0x009b0000 /* FM Modulator control class */ - -#define V4L2_CTRL_ID_MASK (0x0fffffff) -#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL) -#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000) - -enum v4l2_ctrl_type { - V4L2_CTRL_TYPE_INTEGER = 1, - V4L2_CTRL_TYPE_BOOLEAN = 2, - V4L2_CTRL_TYPE_MENU = 3, - V4L2_CTRL_TYPE_BUTTON = 4, - V4L2_CTRL_TYPE_INTEGER64 = 5, - V4L2_CTRL_TYPE_CTRL_CLASS = 6, - V4L2_CTRL_TYPE_STRING = 7, -}; - -/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ -struct v4l2_queryctrl { - __u32 id; - enum v4l2_ctrl_type type; - __u8 name[32]; /* Whatever */ - __s32 minimum; /* Note signedness */ - __s32 maximum; - __s32 step; - __s32 default_value; - __u32 flags; - __u32 reserved[2]; -}; - -/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ -struct v4l2_querymenu { - __u32 id; - __u32 index; - __u8 name[32]; /* Whatever */ - __u32 reserved; -}; - -/* Control flags */ -#define V4L2_CTRL_FLAG_DISABLED 0x0001 -#define V4L2_CTRL_FLAG_GRABBED 0x0002 -#define V4L2_CTRL_FLAG_READ_ONLY 0x0004 -#define V4L2_CTRL_FLAG_UPDATE 0x0008 -#define V4L2_CTRL_FLAG_INACTIVE 0x0010 -#define V4L2_CTRL_FLAG_SLIDER 0x0020 -#define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040 - -/* Query flag, to be ORed with the control ID */ -#define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 - -/* User-class control IDs defined by V4L2 */ -#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) -#define V4L2_CID_USER_BASE V4L2_CID_BASE -/* IDs reserved for driver specific controls */ -#define V4L2_CID_PRIVATE_BASE 0x08000000 - -#define V4L2_CID_USER_CLASS (V4L2_CTRL_CLASS_USER | 1) -#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) -#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) -#define V4L2_CID_SATURATION (V4L2_CID_BASE+2) -#define V4L2_CID_HUE (V4L2_CID_BASE+3) -#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) -#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) -#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) -#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) -#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) -#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) -#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) /* Deprecated */ -#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) -#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) -#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) -#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) -#define V4L2_CID_GAMMA (V4L2_CID_BASE+16) -#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* Deprecated */ -#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) -#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) -#define V4L2_CID_GAIN (V4L2_CID_BASE+19) -#define V4L2_CID_HFLIP (V4L2_CID_BASE+20) -#define V4L2_CID_VFLIP (V4L2_CID_BASE+21) - -/* Deprecated; use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET */ -#define V4L2_CID_HCENTER (V4L2_CID_BASE+22) -#define V4L2_CID_VCENTER (V4L2_CID_BASE+23) - -#define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_BASE+24) -enum v4l2_power_line_frequency { - V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0, - V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1, - V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2, -}; -#define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25) -#define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26) -#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27) -#define V4L2_CID_BACKLIGHT_COMPENSATION (V4L2_CID_BASE+28) -#define V4L2_CID_CHROMA_AGC (V4L2_CID_BASE+29) -#define V4L2_CID_COLOR_KILLER (V4L2_CID_BASE+30) -#define V4L2_CID_COLORFX (V4L2_CID_BASE+31) -enum v4l2_colorfx { - V4L2_COLORFX_NONE = 0, - V4L2_COLORFX_BW = 1, - V4L2_COLORFX_SEPIA = 2, - V4L2_COLORFX_NEGATIVE = 3, - V4L2_COLORFX_EMBOSS = 4, - V4L2_COLORFX_SKETCH = 5, - V4L2_COLORFX_SKY_BLUE = 6, - V4L2_COLORFX_GRASS_GREEN = 7, - V4L2_COLORFX_SKIN_WHITEN = 8, - V4L2_COLORFX_VIVID = 9, -}; -#define V4L2_CID_AUTOBRIGHTNESS (V4L2_CID_BASE+32) -#define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33) - -#define V4L2_CID_ROTATE (V4L2_CID_BASE+34) -#define V4L2_CID_BG_COLOR (V4L2_CID_BASE+35) - -#define V4L2_CID_CHROMA_GAIN (V4L2_CID_BASE+36) - -#define V4L2_CID_ILLUMINATORS_1 (V4L2_CID_BASE+37) -#define V4L2_CID_ILLUMINATORS_2 (V4L2_CID_BASE+38) - -/* last CID + 1 */ -#define V4L2_CID_LASTP1 (V4L2_CID_BASE+39) - -/* MPEG-class control IDs defined by V4L2 */ -#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -#define V4L2_CID_MPEG_CLASS (V4L2_CTRL_CLASS_MPEG | 1) - -/* MPEG streams */ -#define V4L2_CID_MPEG_STREAM_TYPE (V4L2_CID_MPEG_BASE+0) -enum v4l2_mpeg_stream_type { - V4L2_MPEG_STREAM_TYPE_MPEG2_PS = 0, /* MPEG-2 program stream */ - V4L2_MPEG_STREAM_TYPE_MPEG2_TS = 1, /* MPEG-2 transport stream */ - V4L2_MPEG_STREAM_TYPE_MPEG1_SS = 2, /* MPEG-1 system stream */ - V4L2_MPEG_STREAM_TYPE_MPEG2_DVD = 3, /* MPEG-2 DVD-compatible stream */ - V4L2_MPEG_STREAM_TYPE_MPEG1_VCD = 4, /* MPEG-1 VCD-compatible stream */ - V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */ -}; -#define V4L2_CID_MPEG_STREAM_PID_PMT (V4L2_CID_MPEG_BASE+1) -#define V4L2_CID_MPEG_STREAM_PID_AUDIO (V4L2_CID_MPEG_BASE+2) -#define V4L2_CID_MPEG_STREAM_PID_VIDEO (V4L2_CID_MPEG_BASE+3) -#define V4L2_CID_MPEG_STREAM_PID_PCR (V4L2_CID_MPEG_BASE+4) -#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO (V4L2_CID_MPEG_BASE+5) -#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO (V4L2_CID_MPEG_BASE+6) -#define V4L2_CID_MPEG_STREAM_VBI_FMT (V4L2_CID_MPEG_BASE+7) -enum v4l2_mpeg_stream_vbi_fmt { - V4L2_MPEG_STREAM_VBI_FMT_NONE = 0, /* No VBI in the MPEG stream */ - V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1, /* VBI in private packets, IVTV format */ -}; - -/* MPEG audio */ -#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ (V4L2_CID_MPEG_BASE+100) -enum v4l2_mpeg_audio_sampling_freq { - V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2, -}; -#define V4L2_CID_MPEG_AUDIO_ENCODING (V4L2_CID_MPEG_BASE+101) -enum v4l2_mpeg_audio_encoding { - V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1, - V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2, - V4L2_MPEG_AUDIO_ENCODING_AAC = 3, - V4L2_MPEG_AUDIO_ENCODING_AC3 = 4, -}; -#define V4L2_CID_MPEG_AUDIO_L1_BITRATE (V4L2_CID_MPEG_BASE+102) -enum v4l2_mpeg_audio_l1_bitrate { - V4L2_MPEG_AUDIO_L1_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_L1_BITRATE_64K = 1, - V4L2_MPEG_AUDIO_L1_BITRATE_96K = 2, - V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3, - V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4, - V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5, - V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6, - V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7, - V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8, - V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9, - V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10, - V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11, - V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12, - V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13, -}; -#define V4L2_CID_MPEG_AUDIO_L2_BITRATE (V4L2_CID_MPEG_BASE+103) -enum v4l2_mpeg_audio_l2_bitrate { - V4L2_MPEG_AUDIO_L2_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_L2_BITRATE_48K = 1, - V4L2_MPEG_AUDIO_L2_BITRATE_56K = 2, - V4L2_MPEG_AUDIO_L2_BITRATE_64K = 3, - V4L2_MPEG_AUDIO_L2_BITRATE_80K = 4, - V4L2_MPEG_AUDIO_L2_BITRATE_96K = 5, - V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6, - V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7, - V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8, - V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9, - V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10, - V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11, - V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12, - V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13, -}; -#define V4L2_CID_MPEG_AUDIO_L3_BITRATE (V4L2_CID_MPEG_BASE+104) -enum v4l2_mpeg_audio_l3_bitrate { - V4L2_MPEG_AUDIO_L3_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_L3_BITRATE_40K = 1, - V4L2_MPEG_AUDIO_L3_BITRATE_48K = 2, - V4L2_MPEG_AUDIO_L3_BITRATE_56K = 3, - V4L2_MPEG_AUDIO_L3_BITRATE_64K = 4, - V4L2_MPEG_AUDIO_L3_BITRATE_80K = 5, - V4L2_MPEG_AUDIO_L3_BITRATE_96K = 6, - V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7, - V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8, - V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9, - V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10, - V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11, - V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12, - V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13, -}; -#define V4L2_CID_MPEG_AUDIO_MODE (V4L2_CID_MPEG_BASE+105) -enum v4l2_mpeg_audio_mode { - V4L2_MPEG_AUDIO_MODE_STEREO = 0, - V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1, - V4L2_MPEG_AUDIO_MODE_DUAL = 2, - V4L2_MPEG_AUDIO_MODE_MONO = 3, -}; -#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION (V4L2_CID_MPEG_BASE+106) -enum v4l2_mpeg_audio_mode_extension { - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4 = 0, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8 = 1, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3, -}; -#define V4L2_CID_MPEG_AUDIO_EMPHASIS (V4L2_CID_MPEG_BASE+107) -enum v4l2_mpeg_audio_emphasis { - V4L2_MPEG_AUDIO_EMPHASIS_NONE = 0, - V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1, - V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17 = 2, -}; -#define V4L2_CID_MPEG_AUDIO_CRC (V4L2_CID_MPEG_BASE+108) -enum v4l2_mpeg_audio_crc { - V4L2_MPEG_AUDIO_CRC_NONE = 0, - V4L2_MPEG_AUDIO_CRC_CRC16 = 1, -}; -#define V4L2_CID_MPEG_AUDIO_MUTE (V4L2_CID_MPEG_BASE+109) -#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE (V4L2_CID_MPEG_BASE+110) -#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE (V4L2_CID_MPEG_BASE+111) -enum v4l2_mpeg_audio_ac3_bitrate { - V4L2_MPEG_AUDIO_AC3_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_AC3_BITRATE_40K = 1, - V4L2_MPEG_AUDIO_AC3_BITRATE_48K = 2, - V4L2_MPEG_AUDIO_AC3_BITRATE_56K = 3, - V4L2_MPEG_AUDIO_AC3_BITRATE_64K = 4, - V4L2_MPEG_AUDIO_AC3_BITRATE_80K = 5, - V4L2_MPEG_AUDIO_AC3_BITRATE_96K = 6, - V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7, - V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8, - V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9, - V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10, - V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11, - V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12, - V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13, - V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14, - V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15, - V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16, - V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17, - V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18, -}; - -/* MPEG video */ -#define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200) -enum v4l2_mpeg_video_encoding { - V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2, -}; -#define V4L2_CID_MPEG_VIDEO_ASPECT (V4L2_CID_MPEG_BASE+201) -enum v4l2_mpeg_video_aspect { - V4L2_MPEG_VIDEO_ASPECT_1x1 = 0, - V4L2_MPEG_VIDEO_ASPECT_4x3 = 1, - V4L2_MPEG_VIDEO_ASPECT_16x9 = 2, - V4L2_MPEG_VIDEO_ASPECT_221x100 = 3, -}; -#define V4L2_CID_MPEG_VIDEO_B_FRAMES (V4L2_CID_MPEG_BASE+202) -#define V4L2_CID_MPEG_VIDEO_GOP_SIZE (V4L2_CID_MPEG_BASE+203) -#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE (V4L2_CID_MPEG_BASE+204) -#define V4L2_CID_MPEG_VIDEO_PULLDOWN (V4L2_CID_MPEG_BASE+205) -#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE (V4L2_CID_MPEG_BASE+206) -enum v4l2_mpeg_video_bitrate_mode { - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1, -}; -#define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_MPEG_BASE+207) -#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_MPEG_BASE+208) -#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209) -#define V4L2_CID_MPEG_VIDEO_MUTE (V4L2_CID_MPEG_BASE+210) -#define V4L2_CID_MPEG_VIDEO_MUTE_YUV (V4L2_CID_MPEG_BASE+211) - -/* MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */ -#define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000) -#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0) -enum v4l2_mpeg_cx2341x_video_spatial_filter_mode { - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO = 1, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+1) -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+2) -enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type { - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF = 0, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT = 2, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE = 3, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+3) -enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type { - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF = 0, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+4) -enum v4l2_mpeg_cx2341x_video_temporal_filter_mode { - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO = 1, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+5) -#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+6) -enum v4l2_mpeg_cx2341x_video_median_filter_type { - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF = 0, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR = 1, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT = 2, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG = 4, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+7) -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+8) -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9) -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10) -#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS (V4L2_CID_MPEG_CX2341X_BASE+11) - -/* Camera class control IDs */ -#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) -#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1) - -#define V4L2_CID_EXPOSURE_AUTO (V4L2_CID_CAMERA_CLASS_BASE+1) -enum v4l2_exposure_auto_type { - V4L2_EXPOSURE_AUTO = 0, - V4L2_EXPOSURE_MANUAL = 1, - V4L2_EXPOSURE_SHUTTER_PRIORITY = 2, - V4L2_EXPOSURE_APERTURE_PRIORITY = 3 -}; -#define V4L2_CID_EXPOSURE_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+2) -#define V4L2_CID_EXPOSURE_AUTO_PRIORITY (V4L2_CID_CAMERA_CLASS_BASE+3) - -#define V4L2_CID_PAN_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+4) -#define V4L2_CID_TILT_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+5) -#define V4L2_CID_PAN_RESET (V4L2_CID_CAMERA_CLASS_BASE+6) -#define V4L2_CID_TILT_RESET (V4L2_CID_CAMERA_CLASS_BASE+7) - -#define V4L2_CID_PAN_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+8) -#define V4L2_CID_TILT_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+9) - -#define V4L2_CID_FOCUS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+10) -#define V4L2_CID_FOCUS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+11) -#define V4L2_CID_FOCUS_AUTO (V4L2_CID_CAMERA_CLASS_BASE+12) - -#define V4L2_CID_ZOOM_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+13) -#define V4L2_CID_ZOOM_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+14) -#define V4L2_CID_ZOOM_CONTINUOUS (V4L2_CID_CAMERA_CLASS_BASE+15) - -#define V4L2_CID_PRIVACY (V4L2_CID_CAMERA_CLASS_BASE+16) - -#define V4L2_CID_IRIS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+17) -#define V4L2_CID_IRIS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+18) - -/* FM Modulator class control IDs */ -#define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900) -#define V4L2_CID_FM_TX_CLASS (V4L2_CTRL_CLASS_FM_TX | 1) - -#define V4L2_CID_RDS_TX_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 1) -#define V4L2_CID_RDS_TX_PI (V4L2_CID_FM_TX_CLASS_BASE + 2) -#define V4L2_CID_RDS_TX_PTY (V4L2_CID_FM_TX_CLASS_BASE + 3) -#define V4L2_CID_RDS_TX_PS_NAME (V4L2_CID_FM_TX_CLASS_BASE + 5) -#define V4L2_CID_RDS_TX_RADIO_TEXT (V4L2_CID_FM_TX_CLASS_BASE + 6) - -#define V4L2_CID_AUDIO_LIMITER_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 64) -#define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 65) -#define V4L2_CID_AUDIO_LIMITER_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 66) - -#define V4L2_CID_AUDIO_COMPRESSION_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 80) -#define V4L2_CID_AUDIO_COMPRESSION_GAIN (V4L2_CID_FM_TX_CLASS_BASE + 81) -#define V4L2_CID_AUDIO_COMPRESSION_THRESHOLD (V4L2_CID_FM_TX_CLASS_BASE + 82) -#define V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME (V4L2_CID_FM_TX_CLASS_BASE + 83) -#define V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 84) - -#define V4L2_CID_PILOT_TONE_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 96) -#define V4L2_CID_PILOT_TONE_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 97) -#define V4L2_CID_PILOT_TONE_FREQUENCY (V4L2_CID_FM_TX_CLASS_BASE + 98) - -#define V4L2_CID_TUNE_PREEMPHASIS (V4L2_CID_FM_TX_CLASS_BASE + 112) -enum v4l2_preemphasis { - V4L2_PREEMPHASIS_DISABLED = 0, - V4L2_PREEMPHASIS_50_uS = 1, - V4L2_PREEMPHASIS_75_uS = 2, -}; -#define V4L2_CID_TUNE_POWER_LEVEL (V4L2_CID_FM_TX_CLASS_BASE + 113) -#define V4L2_CID_TUNE_ANTENNA_CAPACITOR (V4L2_CID_FM_TX_CLASS_BASE + 114) - -/* - * T U N I N G - */ -struct v4l2_tuner { - __u32 index; - __u8 name[32]; - enum v4l2_tuner_type type; - __u32 capability; - __u32 rangelow; - __u32 rangehigh; - __u32 rxsubchans; - __u32 audmode; - __s32 signal; - __s32 afc; - __u32 reserved[4]; -}; - -struct v4l2_modulator { - __u32 index; - __u8 name[32]; - __u32 capability; - __u32 rangelow; - __u32 rangehigh; - __u32 txsubchans; - __u32 reserved[4]; -}; - -/* Flags for the 'capability' field */ -#define V4L2_TUNER_CAP_LOW 0x0001 -#define V4L2_TUNER_CAP_NORM 0x0002 -#define V4L2_TUNER_CAP_STEREO 0x0010 -#define V4L2_TUNER_CAP_LANG2 0x0020 -#define V4L2_TUNER_CAP_SAP 0x0020 -#define V4L2_TUNER_CAP_LANG1 0x0040 -#define V4L2_TUNER_CAP_RDS 0x0080 -#define V4L2_TUNER_CAP_RDS_BLOCK_IO 0x0100 -#define V4L2_TUNER_CAP_RDS_CONTROLS 0x0200 - -/* Flags for the 'rxsubchans' field */ -#define V4L2_TUNER_SUB_MONO 0x0001 -#define V4L2_TUNER_SUB_STEREO 0x0002 -#define V4L2_TUNER_SUB_LANG2 0x0004 -#define V4L2_TUNER_SUB_SAP 0x0004 -#define V4L2_TUNER_SUB_LANG1 0x0008 -#define V4L2_TUNER_SUB_RDS 0x0010 - -/* Values for the 'audmode' field */ -#define V4L2_TUNER_MODE_MONO 0x0000 -#define V4L2_TUNER_MODE_STEREO 0x0001 -#define V4L2_TUNER_MODE_LANG2 0x0002 -#define V4L2_TUNER_MODE_SAP 0x0002 -#define V4L2_TUNER_MODE_LANG1 0x0003 -#define V4L2_TUNER_MODE_LANG1_LANG2 0x0004 - -struct v4l2_frequency { - __u32 tuner; - enum v4l2_tuner_type type; - __u32 frequency; - __u32 reserved[8]; -}; - -struct v4l2_hw_freq_seek { - __u32 tuner; - enum v4l2_tuner_type type; - __u32 seek_upward; - __u32 wrap_around; - __u32 spacing; - __u32 reserved[7]; -}; - -/* - * R D S - */ - -struct v4l2_rds_data { - __u8 lsb; - __u8 msb; - __u8 block; -} __attribute__ ((packed)); - -#define V4L2_RDS_BLOCK_MSK 0x7 -#define V4L2_RDS_BLOCK_A 0 -#define V4L2_RDS_BLOCK_B 1 -#define V4L2_RDS_BLOCK_C 2 -#define V4L2_RDS_BLOCK_D 3 -#define V4L2_RDS_BLOCK_C_ALT 4 -#define V4L2_RDS_BLOCK_INVALID 7 - -#define V4L2_RDS_BLOCK_CORRECTED 0x40 -#define V4L2_RDS_BLOCK_ERROR 0x80 - -/* - * A U D I O - */ -struct v4l2_audio { - __u32 index; - __u8 name[32]; - __u32 capability; - __u32 mode; - __u32 reserved[2]; -}; - -/* Flags for the 'capability' field */ -#define V4L2_AUDCAP_STEREO 0x00001 -#define V4L2_AUDCAP_AVL 0x00002 - -/* Flags for the 'mode' field */ -#define V4L2_AUDMODE_AVL 0x00001 - -struct v4l2_audioout { - __u32 index; - __u8 name[32]; - __u32 capability; - __u32 mode; - __u32 reserved[2]; -}; - -/* - * M P E G S E R V I C E S - * - * NOTE: EXPERIMENTAL API - */ -#if 1 -#define V4L2_ENC_IDX_FRAME_I (0) -#define V4L2_ENC_IDX_FRAME_P (1) -#define V4L2_ENC_IDX_FRAME_B (2) -#define V4L2_ENC_IDX_FRAME_MASK (0xf) - -struct v4l2_enc_idx_entry { - __u64 offset; - __u64 pts; - __u32 length; - __u32 flags; - __u32 reserved[2]; -}; - -#define V4L2_ENC_IDX_ENTRIES (64) -struct v4l2_enc_idx { - __u32 entries; - __u32 entries_cap; - __u32 reserved[4]; - struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES]; -}; - - -#define V4L2_ENC_CMD_START (0) -#define V4L2_ENC_CMD_STOP (1) -#define V4L2_ENC_CMD_PAUSE (2) -#define V4L2_ENC_CMD_RESUME (3) - -/* Flags for V4L2_ENC_CMD_STOP */ -#define V4L2_ENC_CMD_STOP_AT_GOP_END (1 << 0) - -struct v4l2_encoder_cmd { - __u32 cmd; - __u32 flags; - union { - struct { - __u32 data[8]; - } raw; - }; -}; - -#endif - - -/* - * D A T A S E R V I C E S ( V B I ) - * - * Data services API by Michael Schimek - */ - -/* Raw VBI */ -struct v4l2_vbi_format { - __u32 sampling_rate; /* in 1 Hz */ - __u32 offset; - __u32 samples_per_line; - __u32 sample_format; /* V4L2_PIX_FMT_* */ - __s32 start[2]; - __u32 count[2]; - __u32 flags; /* V4L2_VBI_* */ - __u32 reserved[2]; /* must be zero */ -}; - -/* VBI flags */ -#define V4L2_VBI_UNSYNC (1 << 0) -#define V4L2_VBI_INTERLACED (1 << 1) - -/* Sliced VBI - * - * This implements is a proposal V4L2 API to allow SLICED VBI - * required for some hardware encoders. It should change without - * notice in the definitive implementation. - */ - -struct v4l2_sliced_vbi_format { - __u16 service_set; - /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field - service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field - (equals frame lines 313-336 for 625 line video - standards, 263-286 for 525 line standards) */ - __u16 service_lines[2][24]; - __u32 io_size; - __u32 reserved[2]; /* must be zero */ -}; - -/* Teletext World System Teletext - (WST), defined on ITU-R BT.653-2 */ -#define V4L2_SLICED_TELETEXT_B (0x0001) -/* Video Program System, defined on ETS 300 231*/ -#define V4L2_SLICED_VPS (0x0400) -/* Closed Caption, defined on EIA-608 */ -#define V4L2_SLICED_CAPTION_525 (0x1000) -/* Wide Screen System, defined on ITU-R BT1119.1 */ -#define V4L2_SLICED_WSS_625 (0x4000) - -#define V4L2_SLICED_VBI_525 (V4L2_SLICED_CAPTION_525) -#define V4L2_SLICED_VBI_625 (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625) - -struct v4l2_sliced_vbi_cap { - __u16 service_set; - /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field - service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field - (equals frame lines 313-336 for 625 line video - standards, 263-286 for 525 line standards) */ - __u16 service_lines[2][24]; - enum v4l2_buf_type type; - __u32 reserved[3]; /* must be 0 */ -}; - -struct v4l2_sliced_vbi_data { - __u32 id; - __u32 field; /* 0: first field, 1: second field */ - __u32 line; /* 1-23 */ - __u32 reserved; /* must be 0 */ - __u8 data[48]; -}; - -/* - * Sliced VBI data inserted into MPEG Streams - */ - -/* - * V4L2_MPEG_STREAM_VBI_FMT_IVTV: - * - * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an - * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI - * data - * - * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header - * definitions are not included here. See the MPEG-2 specifications for details - * on these headers. - */ - -/* Line type IDs */ -#define V4L2_MPEG_VBI_IVTV_TELETEXT_B (1) -#define V4L2_MPEG_VBI_IVTV_CAPTION_525 (4) -#define V4L2_MPEG_VBI_IVTV_WSS_625 (5) -#define V4L2_MPEG_VBI_IVTV_VPS (7) - -struct v4l2_mpeg_vbi_itv0_line { - __u8 id; /* One of V4L2_MPEG_VBI_IVTV_* above */ - __u8 data[42]; /* Sliced VBI data for the line */ -} __attribute__ ((packed)); - -struct v4l2_mpeg_vbi_itv0 { - __le32 linemask[2]; /* Bitmasks of VBI service lines present */ - struct v4l2_mpeg_vbi_itv0_line line[35]; -} __attribute__ ((packed)); - -struct v4l2_mpeg_vbi_ITV0 { - struct v4l2_mpeg_vbi_itv0_line line[36]; -} __attribute__ ((packed)); - -#define V4L2_MPEG_VBI_IVTV_MAGIC0 "itv0" -#define V4L2_MPEG_VBI_IVTV_MAGIC1 "ITV0" - -struct v4l2_mpeg_vbi_fmt_ivtv { - __u8 magic[4]; - union { - struct v4l2_mpeg_vbi_itv0 itv0; - struct v4l2_mpeg_vbi_ITV0 ITV0; - }; -} __attribute__ ((packed)); - -/* - * A G G R E G A T E S T R U C T U R E S - */ - -/** - * struct v4l2_plane_pix_format - additional, per-plane format definition - * @sizeimage: maximum size in bytes required for data, for which - * this plane will be used - * @bytesperline: distance in bytes between the leftmost pixels in two - * adjacent lines - */ -struct v4l2_plane_pix_format { - __u32 sizeimage; - __u16 bytesperline; - __u16 reserved[7]; -} __attribute__ ((packed)); - -/** - * struct v4l2_pix_format_mplane - multiplanar format definition - * @width: image width in pixels - * @height: image height in pixels - * @pixelformat: little endian four character code (fourcc) - * @field: field order (for interlaced video) - * @colorspace: supplemental to pixelformat - * @plane_fmt: per-plane information - * @num_planes: number of planes for this format - */ -struct v4l2_pix_format_mplane { - __u32 width; - __u32 height; - __u32 pixelformat; - enum v4l2_field field; - enum v4l2_colorspace colorspace; - - struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES]; - __u8 num_planes; - __u8 reserved[11]; -} __attribute__ ((packed)); - -/** - * struct v4l2_format - stream data format - * @type: type of the data stream - * @pix: definition of an image format - * @pix_mp: definition of a multiplanar image format - * @win: definition of an overlaid image - * @vbi: raw VBI capture or output parameters - * @sliced: sliced VBI capture or output parameters - * @raw_data: placeholder for future extensions and custom formats - */ -struct v4l2_format { - enum v4l2_buf_type type; - union { - struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ - struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */ - struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ - struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ - struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ - __u8 raw_data[200]; /* user-defined */ - } fmt; -}; - -/* Stream type-dependent parameters - */ -struct v4l2_streamparm { - enum v4l2_buf_type type; - union { - struct v4l2_captureparm capture; - struct v4l2_outputparm output; - __u8 raw_data[200]; /* user-defined */ - } parm; -}; - -/* - * E V E N T S - */ - -#define V4L2_EVENT_ALL 0 -#define V4L2_EVENT_VSYNC 1 -#define V4L2_EVENT_EOS 2 -#define V4L2_EVENT_PRIVATE_START 0x08000000 - -/* Payload for V4L2_EVENT_VSYNC */ -struct v4l2_event_vsync { - /* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */ - __u8 field; -} __attribute__ ((packed)); - -struct v4l2_event { - __u32 type; - union { - struct v4l2_event_vsync vsync; - __u8 data[64]; - } u; - __u32 pending; - __u32 sequence; - struct timespec timestamp; - __u32 reserved[9]; -}; - -struct v4l2_event_subscription { - __u32 type; - __u32 reserved[7]; -}; - -/* - * A D V A N C E D D E B U G G I N G - * - * NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS! - * FOR DEBUGGING, TESTING AND INTERNAL USE ONLY! - */ - -/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */ - -#define V4L2_CHIP_MATCH_HOST 0 /* Match against chip ID on host (0 for the host) */ -#define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ -#define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ -#define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ - -struct v4l2_dbg_match { - __u32 type; /* Match type */ - union { /* Match this chip, meaning determined by type */ - __u32 addr; - char name[32]; - }; -} __attribute__ ((packed)); - -struct v4l2_dbg_register { - struct v4l2_dbg_match match; - __u32 size; /* register size in bytes */ - __u64 reg; - __u64 val; -} __attribute__ ((packed)); - -/* VIDIOC_DBG_G_CHIP_IDENT */ -struct v4l2_dbg_chip_ident { - struct v4l2_dbg_match match; - __u32 ident; /* chip identifier as specified in */ - __u32 revision; /* chip revision, chip specific */ -} __attribute__ ((packed)); - -/* - * I O C T L C O D E S F O R V I D E O D E V I C E S - * - */ -#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability) -#define VIDIOC_RESERVED _IO('V', 1) -#define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc) -#define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format) -#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) -#define VIDIOC_REQBUFS _IOWR('V', 8, struct v4l2_requestbuffers) -#define VIDIOC_QUERYBUF _IOWR('V', 9, struct v4l2_buffer) -#define VIDIOC_G_FBUF _IOR('V', 10, struct v4l2_framebuffer) -#define VIDIOC_S_FBUF _IOW('V', 11, struct v4l2_framebuffer) -#define VIDIOC_OVERLAY _IOW('V', 14, int) -#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) -#define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer) -#define VIDIOC_STREAMON _IOW('V', 18, int) -#define VIDIOC_STREAMOFF _IOW('V', 19, int) -#define VIDIOC_G_PARM _IOWR('V', 21, struct v4l2_streamparm) -#define VIDIOC_S_PARM _IOWR('V', 22, struct v4l2_streamparm) -#define VIDIOC_G_STD _IOR('V', 23, v4l2_std_id) -#define VIDIOC_S_STD _IOW('V', 24, v4l2_std_id) -#define VIDIOC_ENUMSTD _IOWR('V', 25, struct v4l2_standard) -#define VIDIOC_ENUMINPUT _IOWR('V', 26, struct v4l2_input) -#define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control) -#define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control) -#define VIDIOC_G_TUNER _IOWR('V', 29, struct v4l2_tuner) -#define VIDIOC_S_TUNER _IOW('V', 30, struct v4l2_tuner) -#define VIDIOC_G_AUDIO _IOR('V', 33, struct v4l2_audio) -#define VIDIOC_S_AUDIO _IOW('V', 34, struct v4l2_audio) -#define VIDIOC_QUERYCTRL _IOWR('V', 36, struct v4l2_queryctrl) -#define VIDIOC_QUERYMENU _IOWR('V', 37, struct v4l2_querymenu) -#define VIDIOC_G_INPUT _IOR('V', 38, int) -#define VIDIOC_S_INPUT _IOWR('V', 39, int) -#define VIDIOC_G_OUTPUT _IOR('V', 46, int) -#define VIDIOC_S_OUTPUT _IOWR('V', 47, int) -#define VIDIOC_ENUMOUTPUT _IOWR('V', 48, struct v4l2_output) -#define VIDIOC_G_AUDOUT _IOR('V', 49, struct v4l2_audioout) -#define VIDIOC_S_AUDOUT _IOW('V', 50, struct v4l2_audioout) -#define VIDIOC_G_MODULATOR _IOWR('V', 54, struct v4l2_modulator) -#define VIDIOC_S_MODULATOR _IOW('V', 55, struct v4l2_modulator) -#define VIDIOC_G_FREQUENCY _IOWR('V', 56, struct v4l2_frequency) -#define VIDIOC_S_FREQUENCY _IOW('V', 57, struct v4l2_frequency) -#define VIDIOC_CROPCAP _IOWR('V', 58, struct v4l2_cropcap) -#define VIDIOC_G_CROP _IOWR('V', 59, struct v4l2_crop) -#define VIDIOC_S_CROP _IOW('V', 60, struct v4l2_crop) -#define VIDIOC_G_JPEGCOMP _IOR('V', 61, struct v4l2_jpegcompression) -#define VIDIOC_S_JPEGCOMP _IOW('V', 62, struct v4l2_jpegcompression) -#define VIDIOC_QUERYSTD _IOR('V', 63, v4l2_std_id) -#define VIDIOC_TRY_FMT _IOWR('V', 64, struct v4l2_format) -#define VIDIOC_ENUMAUDIO _IOWR('V', 65, struct v4l2_audio) -#define VIDIOC_ENUMAUDOUT _IOWR('V', 66, struct v4l2_audioout) -#define VIDIOC_G_PRIORITY _IOR('V', 67, enum v4l2_priority) -#define VIDIOC_S_PRIORITY _IOW('V', 68, enum v4l2_priority) -#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap) -#define VIDIOC_LOG_STATUS _IO('V', 70) -#define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls) -#define VIDIOC_S_EXT_CTRLS _IOWR('V', 72, struct v4l2_ext_controls) -#define VIDIOC_TRY_EXT_CTRLS _IOWR('V', 73, struct v4l2_ext_controls) -#if 1 -#define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum) -#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum) -#define VIDIOC_G_ENC_INDEX _IOR('V', 76, struct v4l2_enc_idx) -#define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) -#define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) -#endif - -#if 1 -/* Experimental, meant for debugging, testing and internal use. - Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. - You must be root to use these ioctls. Never use these in applications! */ -#define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) -#define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) - -/* Experimental, meant for debugging, testing and internal use. - Never use this ioctl in applications! */ -#define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident) -#endif - -#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) -#define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset) -#define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset) -#define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset) -#define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset) -#define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) -#define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) -#define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) -#define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) -#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) - -/* Reminder: when adding new ioctls please add support for them to - drivers/media/video/v4l2-compat-ioctl32.c as well! */ - -#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ - -#endif /* __LINUX_VIDEODEV2_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/adv7343.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/adv7343.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/adv7343.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/adv7343.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * ADV7343 header file - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef ADV7343_H -#define ADV7343_H - -#define ADV7343_COMPOSITE_ID (0) -#define ADV7343_COMPONENT_ID (1) -#define ADV7343_SVIDEO_ID (2) - -#endif /* End of #ifndef ADV7343_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/ak881x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/ak881x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/ak881x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/ak881x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -/* - * Header for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM) - * - * Copyright (C) 2010, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef AK881X_H -#define AK881X_H - -#define AK881X_IF_MODE_MASK (3 << 0) -#define AK881X_IF_MODE_BT656 (0 << 0) -#define AK881X_IF_MODE_MASTER (1 << 0) -#define AK881X_IF_MODE_SLAVE (2 << 0) -#define AK881X_FIELD (1 << 2) -#define AK881X_COMPONENT (1 << 3) - -struct ak881x_pdata { - unsigned long flags; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/bt819.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/bt819.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/bt819.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/bt819.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* - bt819.h - bt819 notifications - - Copyright (C) 2009 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _BT819_H_ -#define _BT819_H_ - -#include - -/* v4l2_device notifications. */ - -/* Needed to reset the FIFO buffer when changing the input - or the video standard. - - Note: these ioctls that internal to the kernel and are never called - from userspace. */ -#define BT819_FIFO_RESET_LOW _IO('b', 0) -#define BT819_FIFO_RESET_HIGH _IO('b', 1) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/cs5345.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/cs5345.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/cs5345.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/cs5345.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - cs5345.h - definition for cs5345 inputs and outputs - - Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _CS5345_H_ -#define _CS5345_H_ - -/* CS5345 HW inputs */ -#define CS5345_IN_MIC 0 -#define CS5345_IN_1 1 -#define CS5345_IN_2 2 -#define CS5345_IN_3 3 -#define CS5345_IN_4 4 -#define CS5345_IN_5 5 -#define CS5345_IN_6 6 - -#define CS5345_MCLK_1 0x00 -#define CS5345_MCLK_1_5 0x10 -#define CS5345_MCLK_2 0x20 -#define CS5345_MCLK_3 0x30 -#define CS5345_MCLK_4 0x40 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/cs53l32a.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/cs53l32a.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/cs53l32a.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/cs53l32a.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - cs53l32a.h - definition for cs53l32a inputs and outputs - - Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _CS53L32A_H_ -#define _CS53L32A_H_ - -/* There are 2 physical inputs, but the second input can be - placed in two modes, the first mode bypasses the PGA (gain), - the second goes through the PGA. Hence there are three - possible inputs to choose from. */ - -/* CS53L32A HW inputs */ -#define CS53L32A_IN0 0 -#define CS53L32A_IN1 1 -#define CS53L32A_IN2 2 - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/cx2341x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/cx2341x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/cx2341x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/cx2341x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,295 +0,0 @@ -/* - cx23415/6/8 header containing common defines. - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef CX2341X_H -#define CX2341X_H - -#include - -enum cx2341x_port { - CX2341X_PORT_MEMORY = 0, - CX2341X_PORT_STREAMING = 1, - CX2341X_PORT_SERIAL = 2 -}; - -enum cx2341x_cap { - CX2341X_CAP_HAS_SLICED_VBI = 1 << 0, - CX2341X_CAP_HAS_TS = 1 << 1, - CX2341X_CAP_HAS_AC3 = 1 << 2, -}; - -struct cx2341x_mpeg_params { - /* misc */ - u32 capabilities; - enum cx2341x_port port; - u16 width; - u16 height; - u16 is_50hz; - - /* stream */ - enum v4l2_mpeg_stream_type stream_type; - enum v4l2_mpeg_stream_vbi_fmt stream_vbi_fmt; - u16 stream_insert_nav_packets; - - /* audio */ - enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq; - enum v4l2_mpeg_audio_encoding audio_encoding; - enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate; - enum v4l2_mpeg_audio_ac3_bitrate audio_ac3_bitrate; - enum v4l2_mpeg_audio_mode audio_mode; - enum v4l2_mpeg_audio_mode_extension audio_mode_extension; - enum v4l2_mpeg_audio_emphasis audio_emphasis; - enum v4l2_mpeg_audio_crc audio_crc; - u32 audio_properties; - u16 audio_mute; - - /* video */ - enum v4l2_mpeg_video_encoding video_encoding; - enum v4l2_mpeg_video_aspect video_aspect; - u16 video_b_frames; - u16 video_gop_size; - u16 video_gop_closure; - enum v4l2_mpeg_video_bitrate_mode video_bitrate_mode; - u32 video_bitrate; - u32 video_bitrate_peak; - u16 video_temporal_decimation; - u16 video_mute; - u32 video_mute_yuv; - - /* encoding filters */ - enum v4l2_mpeg_cx2341x_video_spatial_filter_mode video_spatial_filter_mode; - u16 video_spatial_filter; - enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type video_luma_spatial_filter_type; - enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type video_chroma_spatial_filter_type; - enum v4l2_mpeg_cx2341x_video_temporal_filter_mode video_temporal_filter_mode; - u16 video_temporal_filter; - enum v4l2_mpeg_cx2341x_video_median_filter_type video_median_filter_type; - u16 video_luma_median_filter_top; - u16 video_luma_median_filter_bottom; - u16 video_chroma_median_filter_top; - u16 video_chroma_median_filter_bottom; -}; - -#define CX2341X_MBOX_MAX_DATA 16 - -extern const u32 cx2341x_mpeg_ctrls[]; -typedef int (*cx2341x_mbox_func)(void *priv, u32 cmd, int in, int out, - u32 data[CX2341X_MBOX_MAX_DATA]); -int cx2341x_update(void *priv, cx2341x_mbox_func func, - const struct cx2341x_mpeg_params *old, - const struct cx2341x_mpeg_params *new); -int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, - struct v4l2_queryctrl *qctrl); -const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id); -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, - struct v4l2_ext_controls *ctrls, unsigned int cmd); -void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p); -void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix); - -struct cx2341x_handler; - -struct cx2341x_handler_ops { - /* needed for the video clock freq */ - int (*s_audio_sampling_freq)(struct cx2341x_handler *hdl, u32 val); - /* needed for dualwatch */ - int (*s_audio_mode)(struct cx2341x_handler *hdl, u32 val); - /* needed for setting up the video resolution */ - int (*s_video_encoding)(struct cx2341x_handler *hdl, u32 val); - /* needed for setting up the sliced vbi insertion data structures */ - int (*s_stream_vbi_fmt)(struct cx2341x_handler *hdl, u32 val); -}; - -struct cx2341x_handler { - u32 capabilities; - enum cx2341x_port port; - u16 width; - u16 height; - u16 is_50hz; - u32 audio_properties; - - struct v4l2_ctrl_handler hdl; - void *priv; - cx2341x_mbox_func func; - const struct cx2341x_handler_ops *ops; - - struct v4l2_ctrl *stream_vbi_fmt; - - struct { - /* audio cluster */ - struct v4l2_ctrl *audio_sampling_freq; - struct v4l2_ctrl *audio_encoding; - struct v4l2_ctrl *audio_l2_bitrate; - struct v4l2_ctrl *audio_mode; - struct v4l2_ctrl *audio_mode_extension; - struct v4l2_ctrl *audio_emphasis; - struct v4l2_ctrl *audio_crc; - struct v4l2_ctrl *audio_ac3_bitrate; - }; - - struct { - /* video gop cluster */ - struct v4l2_ctrl *video_b_frames; - struct v4l2_ctrl *video_gop_size; - }; - - struct { - /* stream type cluster */ - struct v4l2_ctrl *stream_type; - struct v4l2_ctrl *video_encoding; - struct v4l2_ctrl *video_bitrate_mode; - struct v4l2_ctrl *video_bitrate; - struct v4l2_ctrl *video_bitrate_peak; - }; - - struct { - /* video mute cluster */ - struct v4l2_ctrl *video_mute; - struct v4l2_ctrl *video_mute_yuv; - }; - - struct { - /* video filter mode cluster */ - struct v4l2_ctrl *video_spatial_filter_mode; - struct v4l2_ctrl *video_temporal_filter_mode; - struct v4l2_ctrl *video_median_filter_type; - }; - - struct { - /* video filter type cluster */ - struct v4l2_ctrl *video_luma_spatial_filter_type; - struct v4l2_ctrl *video_chroma_spatial_filter_type; - }; - - struct { - /* video filter cluster */ - struct v4l2_ctrl *video_spatial_filter; - struct v4l2_ctrl *video_temporal_filter; - }; - - struct { - /* video median cluster */ - struct v4l2_ctrl *video_luma_median_filter_top; - struct v4l2_ctrl *video_luma_median_filter_bottom; - struct v4l2_ctrl *video_chroma_median_filter_top; - struct v4l2_ctrl *video_chroma_median_filter_bottom; - }; -}; - -int cx2341x_handler_init(struct cx2341x_handler *cxhdl, - unsigned nr_of_controls_hint); -void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz); -int cx2341x_handler_setup(struct cx2341x_handler *cxhdl); -void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy); - -/* Firmware names */ -#define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw" -/* Decoder firmware for the cx23415 only */ -#define CX2341X_FIRM_DEC_FILENAME "v4l-cx2341x-dec.fw" - -/* Firmware API commands */ - -/* MPEG decoder API, specific to the cx23415 */ -#define CX2341X_DEC_PING_FW 0x00 -#define CX2341X_DEC_START_PLAYBACK 0x01 -#define CX2341X_DEC_STOP_PLAYBACK 0x02 -#define CX2341X_DEC_SET_PLAYBACK_SPEED 0x03 -#define CX2341X_DEC_STEP_VIDEO 0x05 -#define CX2341X_DEC_SET_DMA_BLOCK_SIZE 0x08 -#define CX2341X_DEC_GET_XFER_INFO 0x09 -#define CX2341X_DEC_GET_DMA_STATUS 0x0a -#define CX2341X_DEC_SCHED_DMA_FROM_HOST 0x0b -#define CX2341X_DEC_PAUSE_PLAYBACK 0x0d -#define CX2341X_DEC_HALT_FW 0x0e -#define CX2341X_DEC_SET_STANDARD 0x10 -#define CX2341X_DEC_GET_VERSION 0x11 -#define CX2341X_DEC_SET_STREAM_INPUT 0x14 -#define CX2341X_DEC_GET_TIMING_INFO 0x15 -#define CX2341X_DEC_SET_AUDIO_MODE 0x16 -#define CX2341X_DEC_SET_EVENT_NOTIFICATION 0x17 -#define CX2341X_DEC_SET_DISPLAY_BUFFERS 0x18 -#define CX2341X_DEC_EXTRACT_VBI 0x19 -#define CX2341X_DEC_SET_DECODER_SOURCE 0x1a -#define CX2341X_DEC_SET_PREBUFFERING 0x1e - -/* MPEG encoder API */ -#define CX2341X_ENC_PING_FW 0x80 -#define CX2341X_ENC_START_CAPTURE 0x81 -#define CX2341X_ENC_STOP_CAPTURE 0x82 -#define CX2341X_ENC_SET_AUDIO_ID 0x89 -#define CX2341X_ENC_SET_VIDEO_ID 0x8b -#define CX2341X_ENC_SET_PCR_ID 0x8d -#define CX2341X_ENC_SET_FRAME_RATE 0x8f -#define CX2341X_ENC_SET_FRAME_SIZE 0x91 -#define CX2341X_ENC_SET_BIT_RATE 0x95 -#define CX2341X_ENC_SET_GOP_PROPERTIES 0x97 -#define CX2341X_ENC_SET_ASPECT_RATIO 0x99 -#define CX2341X_ENC_SET_DNR_FILTER_MODE 0x9b -#define CX2341X_ENC_SET_DNR_FILTER_PROPS 0x9d -#define CX2341X_ENC_SET_CORING_LEVELS 0x9f -#define CX2341X_ENC_SET_SPATIAL_FILTER_TYPE 0xa1 -#define CX2341X_ENC_SET_VBI_LINE 0xb7 -#define CX2341X_ENC_SET_STREAM_TYPE 0xb9 -#define CX2341X_ENC_SET_OUTPUT_PORT 0xbb -#define CX2341X_ENC_SET_AUDIO_PROPERTIES 0xbd -#define CX2341X_ENC_HALT_FW 0xc3 -#define CX2341X_ENC_GET_VERSION 0xc4 -#define CX2341X_ENC_SET_GOP_CLOSURE 0xc5 -#define CX2341X_ENC_GET_SEQ_END 0xc6 -#define CX2341X_ENC_SET_PGM_INDEX_INFO 0xc7 -#define CX2341X_ENC_SET_VBI_CONFIG 0xc8 -#define CX2341X_ENC_SET_DMA_BLOCK_SIZE 0xc9 -#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_10 0xca -#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_9 0xcb -#define CX2341X_ENC_SCHED_DMA_TO_HOST 0xcc -#define CX2341X_ENC_INITIALIZE_INPUT 0xcd -#define CX2341X_ENC_SET_FRAME_DROP_RATE 0xd0 -#define CX2341X_ENC_PAUSE_ENCODER 0xd2 -#define CX2341X_ENC_REFRESH_INPUT 0xd3 -#define CX2341X_ENC_SET_COPYRIGHT 0xd4 -#define CX2341X_ENC_SET_EVENT_NOTIFICATION 0xd5 -#define CX2341X_ENC_SET_NUM_VSYNC_LINES 0xd6 -#define CX2341X_ENC_SET_PLACEHOLDER 0xd7 -#define CX2341X_ENC_MUTE_VIDEO 0xd9 -#define CX2341X_ENC_MUTE_AUDIO 0xda -#define CX2341X_ENC_SET_VERT_CROP_LINE 0xdb -#define CX2341X_ENC_MISC 0xdc - -/* OSD API, specific to the cx23415 */ -#define CX2341X_OSD_GET_FRAMEBUFFER 0x41 -#define CX2341X_OSD_GET_PIXEL_FORMAT 0x42 -#define CX2341X_OSD_SET_PIXEL_FORMAT 0x43 -#define CX2341X_OSD_GET_STATE 0x44 -#define CX2341X_OSD_SET_STATE 0x45 -#define CX2341X_OSD_GET_OSD_COORDS 0x46 -#define CX2341X_OSD_SET_OSD_COORDS 0x47 -#define CX2341X_OSD_GET_SCREEN_COORDS 0x48 -#define CX2341X_OSD_SET_SCREEN_COORDS 0x49 -#define CX2341X_OSD_GET_GLOBAL_ALPHA 0x4a -#define CX2341X_OSD_SET_GLOBAL_ALPHA 0x4b -#define CX2341X_OSD_SET_BLEND_COORDS 0x4c -#define CX2341X_OSD_GET_FLICKER_STATE 0x4f -#define CX2341X_OSD_SET_FLICKER_STATE 0x50 -#define CX2341X_OSD_BLT_COPY 0x52 -#define CX2341X_OSD_BLT_FILL 0x53 -#define CX2341X_OSD_BLT_TEXT 0x54 -#define CX2341X_OSD_SET_FRAMEBUFFER_WINDOW 0x56 -#define CX2341X_OSD_SET_CHROMA_KEY 0x60 -#define CX2341X_OSD_GET_ALPHA_CONTENT_INDEX 0x61 -#define CX2341X_OSD_SET_ALPHA_CONTENT_INDEX 0x62 - -#endif /* CX2341X_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/cx25840.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/cx25840.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/cx25840.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/cx25840.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -/* - cx25840.h - definition for cx25840/1/2/3 inputs - - Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _CX25840_H_ -#define _CX25840_H_ - -/* Note that the cx25840 driver requires that the bridge driver calls the - v4l2_subdev's init operation in order to load the driver's firmware. - Without this the audio standard detection will fail and you will - only get mono. - - Since loading the firmware is often problematic when the driver is - compiled into the kernel I recommend postponing calling this function - until the first open of the video device. Another reason for - postponing it is that loading this firmware takes a long time (seconds) - due to the slow i2c bus speed. So it will speed up the boot process if - you can avoid loading the fw as long as the video device isn't used. */ - -enum cx25840_video_input { - /* Composite video inputs In1-In8 */ - CX25840_COMPOSITE1 = 1, - CX25840_COMPOSITE2, - CX25840_COMPOSITE3, - CX25840_COMPOSITE4, - CX25840_COMPOSITE5, - CX25840_COMPOSITE6, - CX25840_COMPOSITE7, - CX25840_COMPOSITE8, - - /* S-Video inputs consist of one luma input (In1-In8) ORed with one - chroma input (In5-In8) */ - CX25840_SVIDEO_LUMA1 = 0x10, - CX25840_SVIDEO_LUMA2 = 0x20, - CX25840_SVIDEO_LUMA3 = 0x30, - CX25840_SVIDEO_LUMA4 = 0x40, - CX25840_SVIDEO_LUMA5 = 0x50, - CX25840_SVIDEO_LUMA6 = 0x60, - CX25840_SVIDEO_LUMA7 = 0x70, - CX25840_SVIDEO_LUMA8 = 0x80, - CX25840_SVIDEO_CHROMA4 = 0x400, - CX25840_SVIDEO_CHROMA5 = 0x500, - CX25840_SVIDEO_CHROMA6 = 0x600, - CX25840_SVIDEO_CHROMA7 = 0x700, - CX25840_SVIDEO_CHROMA8 = 0x800, - - /* S-Video aliases for common luma/chroma combinations */ - CX25840_SVIDEO1 = 0x510, - CX25840_SVIDEO2 = 0x620, - CX25840_SVIDEO3 = 0x730, - CX25840_SVIDEO4 = 0x840, - - /* Allow frames to specify specific input configurations */ - CX25840_VIN1_CH1 = 0x80000000, - CX25840_VIN2_CH1 = 0x80000001, - CX25840_VIN3_CH1 = 0x80000002, - CX25840_VIN4_CH1 = 0x80000003, - CX25840_VIN5_CH1 = 0x80000004, - CX25840_VIN6_CH1 = 0x80000005, - CX25840_VIN7_CH1 = 0x80000006, - CX25840_VIN8_CH1 = 0x80000007, - CX25840_VIN4_CH2 = 0x80000000, - CX25840_VIN5_CH2 = 0x80000010, - CX25840_VIN6_CH2 = 0x80000020, - CX25840_NONE_CH2 = 0x80000030, - CX25840_VIN7_CH3 = 0x80000000, - CX25840_VIN8_CH3 = 0x80000040, - CX25840_NONE0_CH3 = 0x80000080, - CX25840_NONE1_CH3 = 0x800000c0, - CX25840_SVIDEO_ON = 0x80000100, - CX25840_COMPONENT_ON = 0x80000200, -}; - -enum cx25840_audio_input { - /* Audio inputs: serial or In4-In8 */ - CX25840_AUDIO_SERIAL, - CX25840_AUDIO4 = 4, - CX25840_AUDIO5, - CX25840_AUDIO6, - CX25840_AUDIO7, - CX25840_AUDIO8, -}; - -enum cx25840_io_pin { - CX25840_PIN_DVALID_PRGM0 = 0, - CX25840_PIN_FIELD_PRGM1, - CX25840_PIN_HRESET_PRGM2, - CX25840_PIN_VRESET_HCTL_PRGM3, - CX25840_PIN_IRQ_N_PRGM4, - CX25840_PIN_IR_TX_PRGM6, - CX25840_PIN_IR_RX_PRGM5, - CX25840_PIN_GPIO0_PRGM8, - CX25840_PIN_GPIO1_PRGM9, - CX25840_PIN_SA_SDIN, /* Alternate GP Input only */ - CX25840_PIN_SA_SDOUT, /* Alternate GP Input only */ - CX25840_PIN_PLL_CLK_PRGM7, - CX25840_PIN_CHIP_SEL_VIPCLK, /* Output only */ -}; - -enum cx25840_io_pad { - /* Output pads */ - CX25840_PAD_DEFAULT = 0, - CX25840_PAD_ACTIVE, - CX25840_PAD_VACTIVE, - CX25840_PAD_CBFLAG, - CX25840_PAD_VID_DATA_EXT0, - CX25840_PAD_VID_DATA_EXT1, - CX25840_PAD_GPO0, - CX25840_PAD_GPO1, - CX25840_PAD_GPO2, - CX25840_PAD_GPO3, - CX25840_PAD_IRQ_N, - CX25840_PAD_AC_SYNC, - CX25840_PAD_AC_SDOUT, - CX25840_PAD_PLL_CLK, - CX25840_PAD_VRESET, - CX25840_PAD_RESERVED, - /* Pads for PLL_CLK output only */ - CX25840_PAD_XTI_X5_DLL, - CX25840_PAD_AUX_PLL, - CX25840_PAD_VID_PLL, - CX25840_PAD_XTI, - /* Input Pads */ - CX25840_PAD_GPI0, - CX25840_PAD_GPI1, - CX25840_PAD_GPI2, - CX25840_PAD_GPI3, -}; - -enum cx25840_io_pin_strength { - CX25840_PIN_DRIVE_MEDIUM = 0, - CX25840_PIN_DRIVE_SLOW, - CX25840_PIN_DRIVE_FAST, -}; - -enum cx23885_io_pin { - CX23885_PIN_IR_RX_GPIO19, - CX23885_PIN_IR_TX_GPIO20, - CX23885_PIN_I2S_SDAT_GPIO21, - CX23885_PIN_I2S_WCLK_GPIO22, - CX23885_PIN_I2S_BCLK_GPIO23, - CX23885_PIN_IRQ_N_GPIO16, -}; - -enum cx23885_io_pad { - CX23885_PAD_IR_RX, - CX23885_PAD_GPIO19, - CX23885_PAD_IR_TX, - CX23885_PAD_GPIO20, - CX23885_PAD_I2S_SDAT, - CX23885_PAD_GPIO21, - CX23885_PAD_I2S_WCLK, - CX23885_PAD_GPIO22, - CX23885_PAD_I2S_BCLK, - CX23885_PAD_GPIO23, - CX23885_PAD_IRQ_N, - CX23885_PAD_GPIO16, -}; - -/* pvr150_workaround activates a workaround for a hardware bug that is - present in Hauppauge PVR-150 (and possibly PVR-500) cards that have - certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The - audio autodetect fails on some channels for these models and the workaround - is to select the audio standard explicitly. Many thanks to Hauppauge for - providing this information. - This platform data only needs to be supplied by the ivtv driver. */ -struct cx25840_platform_data { - int pvr150_workaround; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/ccdc_types.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/ccdc_types.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/ccdc_types.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/ccdc_types.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - * - **************************************************************************/ -#ifndef _CCDC_TYPES_H -#define _CCDC_TYPES_H -enum ccdc_pixfmt { - CCDC_PIXFMT_RAW, - CCDC_PIXFMT_YCBCR_16BIT, - CCDC_PIXFMT_YCBCR_8BIT -}; - -enum ccdc_frmfmt { - CCDC_FRMFMT_PROGRESSIVE, - CCDC_FRMFMT_INTERLACED -}; - -/* PIXEL ORDER IN MEMORY from LSB to MSB */ -/* only applicable for 8-bit input mode */ -enum ccdc_pixorder { - CCDC_PIXORDER_YCBYCR, - CCDC_PIXORDER_CBYCRY, -}; - -enum ccdc_buftype { - CCDC_BUFTYPE_FLD_INTERLEAVED, - CCDC_BUFTYPE_FLD_SEPARATED -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/dm355_ccdc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/dm355_ccdc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/dm355_ccdc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/dm355_ccdc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2005-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - */ -#ifndef _DM355_CCDC_H -#define _DM355_CCDC_H -#include -#include - -/* enum for No of pixel per line to be avg. in Black Clamping */ -enum ccdc_sample_length { - CCDC_SAMPLE_1PIXELS, - CCDC_SAMPLE_2PIXELS, - CCDC_SAMPLE_4PIXELS, - CCDC_SAMPLE_8PIXELS, - CCDC_SAMPLE_16PIXELS -}; - -/* enum for No of lines in Black Clamping */ -enum ccdc_sample_line { - CCDC_SAMPLE_1LINES, - CCDC_SAMPLE_2LINES, - CCDC_SAMPLE_4LINES, - CCDC_SAMPLE_8LINES, - CCDC_SAMPLE_16LINES -}; - -/* enum for Alaw gama width */ -enum ccdc_gamma_width { - CCDC_GAMMA_BITS_13_4, - CCDC_GAMMA_BITS_12_3, - CCDC_GAMMA_BITS_11_2, - CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_BITS_09_0 -}; - -enum ccdc_colpats { - CCDC_RED, - CCDC_GREEN_RED, - CCDC_GREEN_BLUE, - CCDC_BLUE -}; - -struct ccdc_col_pat { - enum ccdc_colpats olop; - enum ccdc_colpats olep; - enum ccdc_colpats elop; - enum ccdc_colpats elep; -}; - -enum ccdc_datasft { - CCDC_DATA_NO_SHIFT, - CCDC_DATA_SHIFT_1BIT, - CCDC_DATA_SHIFT_2BIT, - CCDC_DATA_SHIFT_3BIT, - CCDC_DATA_SHIFT_4BIT, - CCDC_DATA_SHIFT_5BIT, - CCDC_DATA_SHIFT_6BIT -}; - -enum ccdc_data_size { - CCDC_DATA_16BITS, - CCDC_DATA_15BITS, - CCDC_DATA_14BITS, - CCDC_DATA_13BITS, - CCDC_DATA_12BITS, - CCDC_DATA_11BITS, - CCDC_DATA_10BITS, - CCDC_DATA_8BITS -}; -enum ccdc_mfilt1 { - CCDC_NO_MEDIAN_FILTER1, - CCDC_AVERAGE_FILTER1, - CCDC_MEDIAN_FILTER1 -}; - -enum ccdc_mfilt2 { - CCDC_NO_MEDIAN_FILTER2, - CCDC_AVERAGE_FILTER2, - CCDC_MEDIAN_FILTER2 -}; - -/* structure for ALaw */ -struct ccdc_a_law { - /* Enable/disable A-Law */ - unsigned char enable; - /* Gama Width Input */ - enum ccdc_gamma_width gama_wd; -}; - -/* structure for Black Clamping */ -struct ccdc_black_clamp { - /* only if bClampEnable is TRUE */ - unsigned char b_clamp_enable; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_length sample_pixel; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_line sample_ln; - /* only if bClampEnable is TRUE */ - unsigned short start_pixel; - /* only if bClampEnable is FALSE */ - unsigned short sgain; - unsigned short dc_sub; -}; - -/* structure for Black Level Compensation */ -struct ccdc_black_compensation { - /* Constant value to subtract from Red component */ - unsigned char r; - /* Constant value to subtract from Gr component */ - unsigned char gr; - /* Constant value to subtract from Blue component */ - unsigned char b; - /* Constant value to subtract from Gb component */ - unsigned char gb; -}; - -struct ccdc_float { - int integer; - unsigned int decimal; -}; - -#define CCDC_CSC_COEFF_TABLE_SIZE 16 -/* structure for color space converter */ -struct ccdc_csc { - unsigned char enable; - /* - * S8Q5. Use 2 decimal precision, user values range from -3.00 to 3.99. - * example - to use 1.03, set integer part as 1, and decimal part as 3 - * to use -1.03, set integer part as -1 and decimal part as 3 - */ - struct ccdc_float coeff[CCDC_CSC_COEFF_TABLE_SIZE]; -}; - -/* Structures for Vertical Defect Correction*/ -enum ccdc_vdf_csl { - CCDC_VDF_NORMAL, - CCDC_VDF_HORZ_INTERPOL_SAT, - CCDC_VDF_HORZ_INTERPOL -}; - -enum ccdc_vdf_cuda { - CCDC_VDF_WHOLE_LINE_CORRECT, - CCDC_VDF_UPPER_DISABLE -}; - -enum ccdc_dfc_mwr { - CCDC_DFC_MWR_WRITE_COMPLETE, - CCDC_DFC_WRITE_REG -}; - -enum ccdc_dfc_mrd { - CCDC_DFC_READ_COMPLETE, - CCDC_DFC_READ_REG -}; - -enum ccdc_dfc_ma_rst { - CCDC_DFC_INCR_ADDR, - CCDC_DFC_CLR_ADDR -}; - -enum ccdc_dfc_mclr { - CCDC_DFC_CLEAR_COMPLETE, - CCDC_DFC_CLEAR -}; - -struct ccdc_dft_corr_ctl { - enum ccdc_vdf_csl vdfcsl; - enum ccdc_vdf_cuda vdfcuda; - unsigned int vdflsft; -}; - -struct ccdc_dft_corr_mem_ctl { - enum ccdc_dfc_mwr dfcmwr; - enum ccdc_dfc_mrd dfcmrd; - enum ccdc_dfc_ma_rst dfcmarst; - enum ccdc_dfc_mclr dfcmclr; -}; - -#define CCDC_DFT_TABLE_SIZE 16 -/* - * Main Structure for vertical defect correction. Vertical defect - * correction can correct upto 16 defects if defects less than 16 - * then pad the rest with 0 - */ -struct ccdc_vertical_dft { - unsigned char ver_dft_en; - unsigned char gen_dft_en; - unsigned int saturation_ctl; - struct ccdc_dft_corr_ctl dft_corr_ctl; - struct ccdc_dft_corr_mem_ctl dft_corr_mem_ctl; - int table_size; - unsigned int dft_corr_horz[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_vert[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub1[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub2[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub3[CCDC_DFT_TABLE_SIZE]; -}; - -struct ccdc_data_offset { - unsigned char horz_offset; - unsigned char vert_offset; -}; - -/* - * Structure for CCDC configuration parameters for raw capture mode passed - * by application - */ -struct ccdc_config_params_raw { - /* data shift to be applied before storing */ - enum ccdc_datasft datasft; - /* data size value from 8 to 16 bits */ - enum ccdc_data_size data_sz; - /* median filter for sdram */ - enum ccdc_mfilt1 mfilt1; - enum ccdc_mfilt2 mfilt2; - /* low pass filter enable/disable */ - unsigned char lpf_enable; - /* Threshold of median filter */ - int med_filt_thres; - /* - * horz and vertical data offset. Appliable for defect correction - * and lsc - */ - struct ccdc_data_offset data_offset; - /* Structure for Optional A-Law */ - struct ccdc_a_law alaw; - /* Structure for Optical Black Clamp */ - struct ccdc_black_clamp blk_clamp; - /* Structure for Black Compensation */ - struct ccdc_black_compensation blk_comp; - /* struture for vertical Defect Correction Module Configuration */ - struct ccdc_vertical_dft vertical_dft; - /* structure for color space converter Module Configuration */ - struct ccdc_csc csc; - /* color patters for bayer capture */ - struct ccdc_col_pat col_pat_field0; - struct ccdc_col_pat col_pat_field1; -}; - -#ifdef __KERNEL__ -#include - -#define CCDC_WIN_PAL {0, 0, 720, 576} -#define CCDC_WIN_VGA {0, 0, 640, 480} - -struct ccdc_params_ycbcr { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* enable BT.656 embedded sync mode */ - int bt656_enable; - /* cb:y:cr:y or y:cb:y:cr in memory */ - enum ccdc_pixorder pix_order; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; -}; - -/* Gain applied to Raw Bayer data */ -struct ccdc_gain { - unsigned short r_ye; - unsigned short gr_cy; - unsigned short gb_g; - unsigned short b_mg; -}; - -/* Structure for CCDC configuration parameters for raw capture mode */ -struct ccdc_params_raw { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; - /* Gain values */ - struct ccdc_gain gain; - /* offset */ - unsigned int ccdc_offset; - /* horizontal flip enable */ - unsigned char horz_flip_enable; - /* - * enable to store the image in inverse order in memory - * (bottom to top) - */ - unsigned char image_invert_enable; - /* Configurable part of raw data */ - struct ccdc_config_params_raw config_params; -}; - -#endif -#endif /* DM355_CCDC_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/dm644x_ccdc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/dm644x_ccdc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/dm644x_ccdc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/dm644x_ccdc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2006-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - */ -#ifndef _DM644X_CCDC_H -#define _DM644X_CCDC_H -#include -#include - -/* enum for No of pixel per line to be avg. in Black Clamping*/ -enum ccdc_sample_length { - CCDC_SAMPLE_1PIXELS, - CCDC_SAMPLE_2PIXELS, - CCDC_SAMPLE_4PIXELS, - CCDC_SAMPLE_8PIXELS, - CCDC_SAMPLE_16PIXELS -}; - -/* enum for No of lines in Black Clamping */ -enum ccdc_sample_line { - CCDC_SAMPLE_1LINES, - CCDC_SAMPLE_2LINES, - CCDC_SAMPLE_4LINES, - CCDC_SAMPLE_8LINES, - CCDC_SAMPLE_16LINES -}; - -/* enum for Alaw gama width */ -enum ccdc_gama_width { - CCDC_GAMMA_BITS_15_6, - CCDC_GAMMA_BITS_14_5, - CCDC_GAMMA_BITS_13_4, - CCDC_GAMMA_BITS_12_3, - CCDC_GAMMA_BITS_11_2, - CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_BITS_09_0 -}; - -enum ccdc_data_size { - CCDC_DATA_16BITS, - CCDC_DATA_15BITS, - CCDC_DATA_14BITS, - CCDC_DATA_13BITS, - CCDC_DATA_12BITS, - CCDC_DATA_11BITS, - CCDC_DATA_10BITS, - CCDC_DATA_8BITS -}; - -/* structure for ALaw */ -struct ccdc_a_law { - /* Enable/disable A-Law */ - unsigned char enable; - /* Gama Width Input */ - enum ccdc_gama_width gama_wd; -}; - -/* structure for Black Clamping */ -struct ccdc_black_clamp { - unsigned char enable; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_length sample_pixel; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_line sample_ln; - /* only if bClampEnable is TRUE */ - unsigned short start_pixel; - /* only if bClampEnable is TRUE */ - unsigned short sgain; - /* only if bClampEnable is FALSE */ - unsigned short dc_sub; -}; - -/* structure for Black Level Compensation */ -struct ccdc_black_compensation { - /* Constant value to subtract from Red component */ - char r; - /* Constant value to subtract from Gr component */ - char gr; - /* Constant value to subtract from Blue component */ - char b; - /* Constant value to subtract from Gb component */ - char gb; -}; - -/* structure for fault pixel correction */ -struct ccdc_fault_pixel { - /* Enable or Disable fault pixel correction */ - unsigned char enable; - /* Number of fault pixel */ - unsigned short fp_num; - /* Address of fault pixel table */ - unsigned int fpc_table_addr; -}; - -/* Structure for CCDC configuration parameters for raw capture mode passed - * by application - */ -struct ccdc_config_params_raw { - /* data size value from 8 to 16 bits */ - enum ccdc_data_size data_sz; - /* Structure for Optional A-Law */ - struct ccdc_a_law alaw; - /* Structure for Optical Black Clamp */ - struct ccdc_black_clamp blk_clamp; - /* Structure for Black Compensation */ - struct ccdc_black_compensation blk_comp; - /* Structure for Fault Pixel Module Configuration */ - struct ccdc_fault_pixel fault_pxl; -}; - - -#ifdef __KERNEL__ -#include -/* Define to enable/disable video port */ -#define FP_NUM_BYTES 4 -/* Define for extra pixel/line and extra lines/frame */ -#define NUM_EXTRAPIXELS 8 -#define NUM_EXTRALINES 8 - -/* settings for commonly used video formats */ -#define CCDC_WIN_PAL {0, 0, 720, 576} -/* ntsc square pixel */ -#define CCDC_WIN_VGA {0, 0, (640 + NUM_EXTRAPIXELS), (480 + NUM_EXTRALINES)} - -/* Structure for CCDC configuration parameters for raw capture mode */ -struct ccdc_params_raw { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; - /* - * enable to store the image in inverse - * order in memory(bottom to top) - */ - unsigned char image_invert_enable; - /* configurable paramaters */ - struct ccdc_config_params_raw config_params; -}; - -struct ccdc_params_ycbcr { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* enable BT.656 embedded sync mode */ - int bt656_enable; - /* cb:y:cr:y or y:cb:y:cr in memory */ - enum ccdc_pixorder pix_order; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; -}; -#endif -#endif /* _DM644X_CCDC_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/isif.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/isif.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/isif.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/isif.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,531 +0,0 @@ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * isif header file - */ -#ifndef _ISIF_H -#define _ISIF_H - -#include -#include - -/* isif float type S8Q8/U8Q8 */ -struct isif_float_8 { - /* 8 bit integer part */ - __u8 integer; - /* 8 bit decimal part */ - __u8 decimal; -}; - -/* isif float type U16Q16/S16Q16 */ -struct isif_float_16 { - /* 16 bit integer part */ - __u16 integer; - /* 16 bit decimal part */ - __u16 decimal; -}; - -/************************************************************************ - * Vertical Defect Correction parameters - ***********************************************************************/ -/* Defect Correction (DFC) table entry */ -struct isif_vdfc_entry { - /* vertical position of defect */ - __u16 pos_vert; - /* horizontal position of defect */ - __u16 pos_horz; - /* - * Defect level of Vertical line defect position. This is subtracted - * from the data at the defect position - */ - __u8 level_at_pos; - /* - * Defect level of the pixels upper than the vertical line defect. - * This is subtracted from the data - */ - __u8 level_up_pixels; - /* - * Defect level of the pixels lower than the vertical line defect. - * This is subtracted from the data - */ - __u8 level_low_pixels; -}; - -#define ISIF_VDFC_TABLE_SIZE 8 -struct isif_dfc { - /* enable vertical defect correction */ - __u8 en; - /* Defect level subtraction. Just fed through if saturating */ -#define ISIF_VDFC_NORMAL 0 - /* - * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2 - * if data saturating - */ -#define ISIF_VDFC_HORZ_INTERPOL_IF_SAT 1 - /* Horizontal interpolation (((i-2)+(i+2))/2) */ -#define ISIF_VDFC_HORZ_INTERPOL 2 - /* one of the vertical defect correction modes above */ - __u8 corr_mode; - /* 0 - whole line corrected, 1 - not pixels upper than the defect */ - __u8 corr_whole_line; -#define ISIF_VDFC_NO_SHIFT 0 -#define ISIF_VDFC_SHIFT_1 1 -#define ISIF_VDFC_SHIFT_2 2 -#define ISIF_VDFC_SHIFT_3 3 -#define ISIF_VDFC_SHIFT_4 4 - /* - * defect level shift value. level_at_pos, level_upper_pos, - * and level_lower_pos can be shifted up by this value. Choose - * one of the values above - */ - __u8 def_level_shift; - /* defect saturation level */ - __u16 def_sat_level; - /* number of vertical defects. Max is ISIF_VDFC_TABLE_SIZE */ - __u16 num_vdefects; - /* VDFC table ptr */ - struct isif_vdfc_entry table[ISIF_VDFC_TABLE_SIZE]; -}; - -struct isif_horz_bclamp { - - /* Horizontal clamp disabled. Only vertical clamp value is subtracted */ -#define ISIF_HORZ_BC_DISABLE 0 - /* - * Horizontal clamp value is calculated and subtracted from image data - * along with vertical clamp value - */ -#define ISIF_HORZ_BC_CLAMP_CALC_ENABLED 1 - /* - * Horizontal clamp value calculated from previous image is subtracted - * from image data along with vertical clamp value. - */ -#define ISIF_HORZ_BC_CLAMP_NOT_UPDATED 2 - /* horizontal clamp mode. One of the values above */ - __u8 mode; - /* - * pixel value limit enable. - * 0 - limit disabled - * 1 - pixel value limited to 1023 - */ - __u8 clamp_pix_limit; - /* Select Most left window for bc calculation */ -#define ISIF_SEL_MOST_LEFT_WIN 0 - /* Select Most right window for bc calculation */ -#define ISIF_SEL_MOST_RIGHT_WIN 1 - /* Select most left or right window for clamp val calculation */ - __u8 base_win_sel_calc; - /* Window count per color for calculation. range 1-32 */ - __u8 win_count_calc; - /* Window start position - horizontal for calculation. 0 - 8191 */ - __u16 win_start_h_calc; - /* Window start position - vertical for calculation 0 - 8191 */ - __u16 win_start_v_calc; -#define ISIF_HORZ_BC_SZ_H_2PIXELS 0 -#define ISIF_HORZ_BC_SZ_H_4PIXELS 1 -#define ISIF_HORZ_BC_SZ_H_8PIXELS 2 -#define ISIF_HORZ_BC_SZ_H_16PIXELS 3 - /* Width of the sample window in pixels for calculation */ - __u8 win_h_sz_calc; -#define ISIF_HORZ_BC_SZ_V_32PIXELS 0 -#define ISIF_HORZ_BC_SZ_V_64PIXELS 1 -#define ISIF_HORZ_BC_SZ_V_128PIXELS 2 -#define ISIF_HORZ_BC_SZ_V_256PIXELS 3 - /* Height of the sample window in pixels for calculation */ - __u8 win_v_sz_calc; -}; - -/************************************************************************ - * Black Clamp parameters - ***********************************************************************/ -struct isif_vert_bclamp { - /* Reset value used is the clamp value calculated */ -#define ISIF_VERT_BC_USE_HORZ_CLAMP_VAL 0 - /* Reset value used is reset_clamp_val configured */ -#define ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL 1 - /* No update, previous image value is used */ -#define ISIF_VERT_BC_NO_UPDATE 2 - /* - * Reset value selector for vertical clamp calculation. Use one of - * the above values - */ - __u8 reset_val_sel; - /* U8Q8. Line average coefficient used in vertical clamp calculation */ - __u8 line_ave_coef; - /* Height of the optical black region for calculation */ - __u16 ob_v_sz_calc; - /* Optical black region start position - horizontal. 0 - 8191 */ - __u16 ob_start_h; - /* Optical black region start position - vertical 0 - 8191 */ - __u16 ob_start_v; -}; - -struct isif_black_clamp { - /* - * This offset value is added irrespective of the clamp enable status. - * S13 - */ - __u16 dc_offset; - /* - * Enable black/digital clamp value to be subtracted from the image data - */ - __u8 en; - /* - * black clamp mode. same/separate clamp for 4 colors - * 0 - disable - same clamp value for all colors - * 1 - clamp value calculated separately for all colors - */ - __u8 bc_mode_color; - /* Vrtical start position for bc subtraction */ - __u16 vert_start_sub; - /* Black clamp for horizontal direction */ - struct isif_horz_bclamp horz; - /* Black clamp for vertical direction */ - struct isif_vert_bclamp vert; -}; - -/************************************************************************* -** Color Space Convertion (CSC) -*************************************************************************/ -#define ISIF_CSC_NUM_COEFF 16 -struct isif_color_space_conv { - /* Enable color space conversion */ - __u8 en; - /* - * csc coeffient table. S8Q5, M00 at index 0, M01 at index 1, and - * so forth - */ - struct isif_float_8 coeff[ISIF_CSC_NUM_COEFF]; -}; - - -/************************************************************************* -** Black Compensation parameters -*************************************************************************/ -struct isif_black_comp { - /* Comp for Red */ - __s8 r_comp; - /* Comp for Gr */ - __s8 gr_comp; - /* Comp for Blue */ - __s8 b_comp; - /* Comp for Gb */ - __s8 gb_comp; -}; - -/************************************************************************* -** Gain parameters -*************************************************************************/ -struct isif_gain { - /* Gain for Red or ye */ - struct isif_float_16 r_ye; - /* Gain for Gr or cy */ - struct isif_float_16 gr_cy; - /* Gain for Gb or g */ - struct isif_float_16 gb_g; - /* Gain for Blue or mg */ - struct isif_float_16 b_mg; -}; - -#define ISIF_LINEAR_TAB_SIZE 192 -/************************************************************************* -** Linearization parameters -*************************************************************************/ -struct isif_linearize { - /* Enable or Disable linearization of data */ - __u8 en; - /* Shift value applied */ - __u8 corr_shft; - /* scale factor applied U11Q10 */ - struct isif_float_16 scale_fact; - /* Size of the linear table */ - __u16 table[ISIF_LINEAR_TAB_SIZE]; -}; - -/* Color patterns */ -#define ISIF_RED 0 -#define ISIF_GREEN_RED 1 -#define ISIF_GREEN_BLUE 2 -#define ISIF_BLUE 3 -struct isif_col_pat { - __u8 olop; - __u8 olep; - __u8 elop; - __u8 elep; -}; - -/************************************************************************* -** Data formatter parameters -*************************************************************************/ -struct isif_fmtplen { - /* - * number of program entries for SET0, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen0; - /* - * number of program entries for SET1, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen1; - /** - * number of program entries for SET2, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen2; - /** - * number of program entries for SET3, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen3; -}; - -struct isif_fmt_cfg { -#define ISIF_SPLIT 0 -#define ISIF_COMBINE 1 - /* Split or combine or line alternate */ - __u8 fmtmode; - /* enable or disable line alternating mode */ - __u8 ln_alter_en; -#define ISIF_1LINE 0 -#define ISIF_2LINES 1 -#define ISIF_3LINES 2 -#define ISIF_4LINES 3 - /* Split/combine line number */ - __u8 lnum; - /* Address increment Range 1 - 16 */ - __u8 addrinc; -}; - -struct isif_fmt_addr_ptr { - /* Initial address */ - __u32 init_addr; - /* output line number */ -#define ISIF_1STLINE 0 -#define ISIF_2NDLINE 1 -#define ISIF_3RDLINE 2 -#define ISIF_4THLINE 3 - __u8 out_line; -}; - -struct isif_fmtpgm_ap { - /* program address pointer */ - __u8 pgm_aptr; - /* program address increment or decrement */ - __u8 pgmupdt; -}; - -struct isif_data_formatter { - /* Enable/Disable data formatter */ - __u8 en; - /* data formatter configuration */ - struct isif_fmt_cfg cfg; - /* Formatter program entries length */ - struct isif_fmtplen plen; - /* first pixel in a line fed to formatter */ - __u16 fmtrlen; - /* HD interval for output line. Only valid when split line */ - __u16 fmthcnt; - /* formatter address pointers */ - struct isif_fmt_addr_ptr fmtaddr_ptr[16]; - /* program enable/disable */ - __u8 pgm_en[32]; - /* program address pointers */ - struct isif_fmtpgm_ap fmtpgm_ap[32]; -}; - -struct isif_df_csc { - /* Color Space Conversion confguration, 0 - csc, 1 - df */ - __u8 df_or_csc; - /* csc configuration valid if df_or_csc is 0 */ - struct isif_color_space_conv csc; - /* data formatter configuration valid if df_or_csc is 1 */ - struct isif_data_formatter df; - /* start pixel in a line at the input */ - __u32 start_pix; - /* number of pixels in input line */ - __u32 num_pixels; - /* start line at the input */ - __u32 start_line; - /* number of lines at the input */ - __u32 num_lines; -}; - -struct isif_gain_offsets_adj { - /* Gain adjustment per color */ - struct isif_gain gain; - /* Offset adjustment */ - __u16 offset; - /* Enable or Disable Gain adjustment for SDRAM data */ - __u8 gain_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - __u8 gain_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - __u8 gain_h3a_en; - /* Enable or Disable Gain adjustment for SDRAM data */ - __u8 offset_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - __u8 offset_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - __u8 offset_h3a_en; -}; - -struct isif_cul { - /* Horizontal Cull pattern for odd lines */ - __u8 hcpat_odd; - /* Horizontal Cull pattern for even lines */ - __u8 hcpat_even; - /* Vertical Cull pattern */ - __u8 vcpat; - /* Enable or disable lpf. Apply when cull is enabled */ - __u8 en_lpf; -}; - -struct isif_compress { -#define ISIF_ALAW 0 -#define ISIF_DPCM 1 -#define ISIF_NO_COMPRESSION 2 - /* Compression Algorithm used */ - __u8 alg; - /* Choose Predictor1 for DPCM compression */ -#define ISIF_DPCM_PRED1 0 - /* Choose Predictor2 for DPCM compression */ -#define ISIF_DPCM_PRED2 1 - /* Predictor for DPCM compression */ - __u8 pred; -}; - -/* all the stuff in this struct will be provided by userland */ -struct isif_config_params_raw { - /* Linearization parameters for image sensor data input */ - struct isif_linearize linearize; - /* Data formatter or CSC */ - struct isif_df_csc df_csc; - /* Defect Pixel Correction (DFC) confguration */ - struct isif_dfc dfc; - /* Black/Digital Clamp configuration */ - struct isif_black_clamp bclamp; - /* Gain, offset adjustments */ - struct isif_gain_offsets_adj gain_offset; - /* Culling */ - struct isif_cul culling; - /* A-Law and DPCM compression options */ - struct isif_compress compress; - /* horizontal offset for Gain/LSC/DFC */ - __u16 horz_offset; - /* vertical offset for Gain/LSC/DFC */ - __u16 vert_offset; - /* color pattern for field 0 */ - struct isif_col_pat col_pat_field0; - /* color pattern for field 1 */ - struct isif_col_pat col_pat_field1; -#define ISIF_NO_SHIFT 0 -#define ISIF_1BIT_SHIFT 1 -#define ISIF_2BIT_SHIFT 2 -#define ISIF_3BIT_SHIFT 3 -#define ISIF_4BIT_SHIFT 4 -#define ISIF_5BIT_SHIFT 5 -#define ISIF_6BIT_SHIFT 6 - /* Data shift applied before storing to SDRAM */ - __u8 data_shift; - /* enable input test pattern generation */ - __u8 test_pat_gen; -}; - -#ifdef __KERNEL__ -struct isif_ycbcr_config { - /* isif pixel format */ - enum ccdc_pixfmt pix_fmt; - /* isif frame format */ - enum ccdc_frmfmt frm_fmt; - /* ISIF crop window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* isif pix order. Only used for ycbcr capture */ - enum ccdc_pixorder pix_order; - /* isif buffer type. Only used for ycbcr capture */ - enum ccdc_buftype buf_type; -}; - -/* MSB of image data connected to sensor port */ -enum isif_data_msb { - ISIF_BIT_MSB_15, - ISIF_BIT_MSB_14, - ISIF_BIT_MSB_13, - ISIF_BIT_MSB_12, - ISIF_BIT_MSB_11, - ISIF_BIT_MSB_10, - ISIF_BIT_MSB_9, - ISIF_BIT_MSB_8, - ISIF_BIT_MSB_7 -}; - -enum isif_cfa_pattern { - ISIF_CFA_PAT_MOSAIC, - ISIF_CFA_PAT_STRIPE -}; - -struct isif_params_raw { - /* isif pixel format */ - enum ccdc_pixfmt pix_fmt; - /* isif frame format */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* buffer type. Applicable for interlaced mode */ - enum ccdc_buftype buf_type; - /* Gain values */ - struct isif_gain gain; - /* cfa pattern */ - enum isif_cfa_pattern cfa_pat; - /* Data MSB position */ - enum isif_data_msb data_msb; - /* Enable horizontal flip */ - unsigned char horz_flip_en; - /* Enable image invert vertically */ - unsigned char image_invert_en; - - /* all the userland defined stuff*/ - struct isif_config_params_raw config_params; -}; - -enum isif_data_pack { - ISIF_PACK_16BIT, - ISIF_PACK_12BIT, - ISIF_PACK_8BIT -}; - -#define ISIF_WIN_NTSC {0, 0, 720, 480} -#define ISIF_WIN_VGA {0, 0, 640, 480} - -#endif -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpfe_capture.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpfe_capture.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpfe_capture.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpfe_capture.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - */ - -#ifndef _VPFE_CAPTURE_H -#define _VPFE_CAPTURE_H - -#ifdef __KERNEL__ - -/* Header files */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define VPFE_CAPTURE_NUM_DECODERS 5 - -/* Macros */ -#define VPFE_MAJOR_RELEASE 0 -#define VPFE_MINOR_RELEASE 0 -#define VPFE_BUILD 1 -#define VPFE_CAPTURE_VERSION_CODE ((VPFE_MAJOR_RELEASE << 16) | \ - (VPFE_MINOR_RELEASE << 8) | \ - VPFE_BUILD) - -#define CAPTURE_DRV_NAME "vpfe-capture" - -struct vpfe_pixel_format { - struct v4l2_fmtdesc fmtdesc; - /* bytes per pixel */ - int bpp; -}; - -struct vpfe_std_info { - int active_pixels; - int active_lines; - /* current frame format */ - int frame_format; -}; - -struct vpfe_route { - u32 input; - u32 output; -}; - -struct vpfe_subdev_info { - /* Sub device name */ - char name[32]; - /* Sub device group id */ - int grp_id; - /* Number of inputs supported */ - int num_inputs; - /* inputs available at the sub device */ - struct v4l2_input *inputs; - /* Sub dev routing information for each input */ - struct vpfe_route *routes; - /* check if sub dev supports routing */ - int can_route; - /* ccdc bus/interface configuration */ - struct vpfe_hw_if_param ccdc_if_params; - /* i2c subdevice board info */ - struct i2c_board_info board_info; -}; - -struct vpfe_config { - /* Number of sub devices connected to vpfe */ - int num_subdevs; - /* i2c bus adapter no */ - int i2c_adapter_id; - /* information about each subdev */ - struct vpfe_subdev_info *sub_devs; - /* evm card info */ - char *card_name; - /* ccdc name */ - char *ccdc; - /* vpfe clock */ - struct clk *vpssclk; - struct clk *slaveclk; - /* Function for Clearing the interrupt */ - void (*clr_intr)(int vdint); -}; - -struct vpfe_device { - /* V4l2 specific parameters */ - /* Identifies video device for this channel */ - struct video_device *video_dev; - /* sub devices */ - struct v4l2_subdev **sd; - /* vpfe cfg */ - struct vpfe_config *cfg; - /* V4l2 device */ - struct v4l2_device v4l2_dev; - /* parent device */ - struct device *pdev; - /* Used to keep track of state of the priority */ - struct v4l2_prio_state prio; - /* number of open instances of the channel */ - u32 usrs; - /* Indicates id of the field which is being displayed */ - u32 field_id; - /* flag to indicate whether decoder is initialized */ - u8 initialized; - /* current interface type */ - struct vpfe_hw_if_param vpfe_if_params; - /* ptr to currently selected sub device */ - struct vpfe_subdev_info *current_subdev; - /* current input at the sub device */ - int current_input; - /* Keeps track of the information about the standard */ - struct vpfe_std_info std_info; - /* std index into std table */ - int std_index; - /* CCDC IRQs used when CCDC/ISIF output to SDRAM */ - unsigned int ccdc_irq0; - unsigned int ccdc_irq1; - /* number of buffers in fbuffers */ - u32 numbuffers; - /* List of buffer pointers for storing frames */ - u8 *fbuffers[VIDEO_MAX_FRAME]; - /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *cur_frm; - /* Pointer pointing to next v4l2_buffer */ - struct videobuf_buffer *next_frm; - /* - * This field keeps track of type of buffer exchange mechanism - * user has selected - */ - enum v4l2_memory memory; - /* Used to store pixel format */ - struct v4l2_format fmt; - /* - * used when IMP is chained to store the crop window which - * is different from the image window - */ - struct v4l2_rect crop; - /* Buffer queue used in video-buf */ - struct videobuf_queue buffer_queue; - /* Queue of filled frames */ - struct list_head dma_queue; - /* Used in video-buf */ - spinlock_t irqlock; - /* IRQ lock for DMA queue */ - spinlock_t dma_queue_lock; - /* lock used to access this structure */ - struct mutex lock; - /* number of users performing IO */ - u32 io_usrs; - /* Indicates whether streaming started */ - u8 started; - /* - * offset where second field starts from the starting of the - * buffer for field separated YCbCr formats - */ - u32 field_off; -}; - -/* File handle structure */ -struct vpfe_fh { - struct vpfe_device *vpfe_dev; - /* Indicates whether this file handle is doing IO */ - u8 io_allowed; - /* Used to keep track priority of this instance */ - enum v4l2_priority prio; -}; - -struct vpfe_config_params { - u8 min_numbuffers; - u8 numbuffers; - u32 min_bufsize; - u32 device_bufsize; -}; - -#endif /* End of __KERNEL__ */ -/** - * VPFE_CMD_S_CCDC_RAW_PARAMS - EXPERIMENTAL IOCTL to set raw capture params - * This can be used to configure modules such as defect pixel correction, - * color space conversion, culling etc. This is an experimental ioctl that - * will change in future kernels. So use this ioctl with care ! - * TODO: This is to be split into multiple ioctls and also explore the - * possibility of extending the v4l2 api to include this - **/ -#define VPFE_CMD_S_CCDC_RAW_PARAMS _IOW('V', BASE_VIDIOC_PRIVATE + 1, \ - void *) -#endif /* _DAVINCI_VPFE_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpfe_types.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpfe_types.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpfe_types.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpfe_types.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * 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, or - * (at your option)any later version. - * - * 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 - */ -#ifndef _VPFE_TYPES_H -#define _VPFE_TYPES_H - -#ifdef __KERNEL__ - -enum vpfe_pin_pol { - VPFE_PINPOL_POSITIVE, - VPFE_PINPOL_NEGATIVE -}; - -enum vpfe_hw_if_type { - /* BT656 - 8 bit */ - VPFE_BT656, - /* BT1120 - 16 bit */ - VPFE_BT1120, - /* Raw Bayer */ - VPFE_RAW_BAYER, - /* YCbCr - 8 bit with external sync */ - VPFE_YCBCR_SYNC_8, - /* YCbCr - 16 bit with external sync */ - VPFE_YCBCR_SYNC_16, - /* BT656 - 10 bit */ - VPFE_BT656_10BIT -}; - -/* interface description */ -struct vpfe_hw_if_param { - enum vpfe_hw_if_type if_type; - enum vpfe_pin_pol hdpol; - enum vpfe_pin_pol vdpol; -}; - -#endif -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpss.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpss.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpss.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/davinci/vpss.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2009 Texas Instruments Inc - * - * 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, or - * (at your option) any later version. - * - * 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 - * - * vpss - video processing subsystem module header file. - * - * Include this header file if a driver needs to configure vpss system - * module. It exports a set of library functions for video drivers to - * configure vpss system module functions such as clock enable/disable, - * vpss interrupt mux to arm, and other common vpss system module - * functions. - */ -#ifndef _VPSS_H -#define _VPSS_H - -/* selector for ccdc input selection on DM355 */ -enum vpss_ccdc_source_sel { - VPSS_CCDCIN, - VPSS_HSSIIN, - VPSS_PGLPBK, /* for DM365 only */ - VPSS_CCDCPG /* for DM365 only */ -}; - -struct vpss_sync_pol { - unsigned int ccdpg_hdpol:1; - unsigned int ccdpg_vdpol:1; -}; - -struct vpss_pg_frame_size { - short hlpfr; - short pplen; -}; - -/* Used for enable/disable VPSS Clock */ -enum vpss_clock_sel { - /* DM355/DM365 */ - VPSS_CCDC_CLOCK, - VPSS_IPIPE_CLOCK, - VPSS_H3A_CLOCK, - VPSS_CFALD_CLOCK, - /* - * When using VPSS_VENC_CLOCK_SEL in vpss_enable_clock() api - * following applies:- - * en = 0 selects ENC_CLK - * en = 1 selects ENC_CLK/2 - */ - VPSS_VENC_CLOCK_SEL, - VPSS_VPBE_CLOCK, - /* DM365 only clocks */ - VPSS_IPIPEIF_CLOCK, - VPSS_RSZ_CLOCK, - VPSS_BL_CLOCK, - /* - * When using VPSS_PCLK_INTERNAL in vpss_enable_clock() api - * following applies:- - * en = 0 disable internal PCLK - * en = 1 enables internal PCLK - */ - VPSS_PCLK_INTERNAL, - /* - * When using VPSS_PSYNC_CLOCK_SEL in vpss_enable_clock() api - * following applies:- - * en = 0 enables MMR clock - * en = 1 enables VPSS clock - */ - VPSS_PSYNC_CLOCK_SEL, - VPSS_LDC_CLOCK_SEL, - VPSS_OSD_CLOCK_SEL, - VPSS_FDIF_CLOCK, - VPSS_LDC_CLOCK -}; - -/* select input to ccdc on dm355 */ -int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel); -/* enable/disable a vpss clock, 0 - success, -1 - failure */ -int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en); -/* set sync polarity, only for DM365*/ -void dm365_vpss_set_sync_pol(struct vpss_sync_pol); -/* set the PG_FRAME_SIZE register, only for DM365 */ -void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size); - -/* wbl reset for dm644x */ -enum vpss_wbl_sel { - VPSS_PCR_AEW_WBL_0 = 16, - VPSS_PCR_AF_WBL_0, - VPSS_PCR_RSZ4_WBL_0, - VPSS_PCR_RSZ3_WBL_0, - VPSS_PCR_RSZ2_WBL_0, - VPSS_PCR_RSZ1_WBL_0, - VPSS_PCR_PREV_WBL_0, - VPSS_PCR_CCDC_WBL_O, -}; -/* clear wbl overflow flag for DM6446 */ -int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel); -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/i2c-addr.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/i2c-addr.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/i2c-addr.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/i2c-addr.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - * V4L I2C address list - * - * - * Copyright (C) 2006 Mauro Carvalho Chehab - * Based on a previous mapping by - * Ralph Metzler (rjkm@thp.uni-koeln.de) - * Gerd Knorr - * - */ - -/* bttv address list */ -#define I2C_ADDR_TSA5522 0xc2 -#define I2C_ADDR_TDA7432 0x8a -#define I2C_ADDR_TDA8425 0x82 -#define I2C_ADDR_TDA9840 0x84 -#define I2C_ADDR_TDA9850 0xb6 /* also used by 9855,9873 */ -#define I2C_ADDR_TDA9874 0xb0 /* also used by 9875 */ -#define I2C_ADDR_TDA9875 0xb0 -#define I2C_ADDR_HAUPEE 0xa0 -#define I2C_ADDR_STBEE 0xae -#define I2C_ADDR_VHX 0xc0 -#define I2C_ADDR_MSP3400 0x80 -#define I2C_ADDR_MSP3400_ALT 0x88 -#define I2C_ADDR_TEA6300 0x80 /* also used by 6320 */ -#define I2C_ADDR_DPL3518 0x84 -#define I2C_ADDR_TDA9887 0x86 - -/* - * i2c bus addresses for the chips supported by tvaudio.c - */ - -#define I2C_ADDR_TDA8425 0x82 -#define I2C_ADDR_TDA9840 0x84 /* also used by TA8874Z */ -#define I2C_ADDR_TDA985x_L 0xb4 /* also used by 9873 */ -#define I2C_ADDR_TDA985x_H 0xb6 -#define I2C_ADDR_TDA9874 0xb0 /* also used by 9875 */ - -#define I2C_ADDR_TEA6300 0x80 /* also used by 6320 */ -#define I2C_ADDR_TEA6420 0x98 - -#define I2C_ADDR_PIC16C54 0x96 /* PV951 */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/ir-kbd-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/ir-kbd-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/ir-kbd-i2c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/ir-kbd-i2c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -#ifndef _IR_I2C -#define _IR_I2C - -#include - -#define DEFAULT_POLLING_INTERVAL 100 /* ms */ - -struct IR_i2c; - -struct IR_i2c { - char *ir_codes; - struct i2c_client *c; - struct rc_dev *rc; - - /* Used to avoid fast repeating */ - unsigned char old; - - u32 polling_interval; /* in ms */ - - struct delayed_work work; - char name[32]; - char phys[32]; - int (*get_key)(struct IR_i2c*, u32*, u32*); -}; - -enum ir_kbd_get_key_fn { - IR_KBD_GET_KEY_CUSTOM = 0, - IR_KBD_GET_KEY_PIXELVIEW, - IR_KBD_GET_KEY_HAUP, - IR_KBD_GET_KEY_KNC1, - IR_KBD_GET_KEY_FUSIONHDTV, - IR_KBD_GET_KEY_HAUP_XVR, - IR_KBD_GET_KEY_AVERMEDIA_CARDBUS, -}; - -/* Can be passed when instantiating an ir_video i2c device */ -struct IR_i2c_init_data { - char *ir_codes; - const char *name; - u64 type; /* RC_TYPE_RC5, etc */ - u32 polling_interval; /* 0 means DEFAULT_POLLING_INTERVAL */ - - /* - * Specify either a function pointer or a value indicating one of - * ir_kbd_i2c's internal get_key functions - */ - int (*get_key)(struct IR_i2c*, u32*, u32*); - enum ir_kbd_get_key_fn internal_get_key_func; - - struct rc_dev *rc_dev; -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/lirc_dev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/lirc_dev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/lirc_dev.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/lirc_dev.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,225 +0,0 @@ -/* - * LIRC base driver - * - * by Artur Lipowski - * This code is licensed under GNU GPL - * - */ - -#ifndef _LINUX_LIRC_DEV_H -#define _LINUX_LIRC_DEV_H - -#define MAX_IRCTL_DEVICES 4 -#define BUFLEN 16 - -#define mod(n, div) ((n) % (div)) - -#include -#include -#include -#include -#include -#include - -struct lirc_buffer { - wait_queue_head_t wait_poll; - spinlock_t fifo_lock; - unsigned int chunk_size; - unsigned int size; /* in chunks */ - /* Using chunks instead of bytes pretends to simplify boundary checking - * And should allow for some performance fine tunning later */ - struct kfifo fifo; - u8 fifo_initialized; -}; - -static inline void lirc_buffer_clear(struct lirc_buffer *buf) -{ - unsigned long flags; - - if (buf->fifo_initialized) { - spin_lock_irqsave(&buf->fifo_lock, flags); - kfifo_reset(&buf->fifo); - spin_unlock_irqrestore(&buf->fifo_lock, flags); - } else - WARN(1, "calling %s on an uninitialized lirc_buffer\n", - __func__); -} - -static inline int lirc_buffer_init(struct lirc_buffer *buf, - unsigned int chunk_size, - unsigned int size) -{ - int ret; - - init_waitqueue_head(&buf->wait_poll); - spin_lock_init(&buf->fifo_lock); - buf->chunk_size = chunk_size; - buf->size = size; - ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL); - if (ret == 0) - buf->fifo_initialized = 1; - - return ret; -} - -static inline void lirc_buffer_free(struct lirc_buffer *buf) -{ - if (buf->fifo_initialized) { - kfifo_free(&buf->fifo); - buf->fifo_initialized = 0; - } else - WARN(1, "calling %s on an uninitialized lirc_buffer\n", - __func__); -} - -static inline int lirc_buffer_len(struct lirc_buffer *buf) -{ - int len; - unsigned long flags; - - spin_lock_irqsave(&buf->fifo_lock, flags); - len = kfifo_len(&buf->fifo); - spin_unlock_irqrestore(&buf->fifo_lock, flags); - - return len; -} - -static inline int lirc_buffer_full(struct lirc_buffer *buf) -{ - return lirc_buffer_len(buf) == buf->size * buf->chunk_size; -} - -static inline int lirc_buffer_empty(struct lirc_buffer *buf) -{ - return !lirc_buffer_len(buf); -} - -static inline int lirc_buffer_available(struct lirc_buffer *buf) -{ - return buf->size - (lirc_buffer_len(buf) / buf->chunk_size); -} - -static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf, - unsigned char *dest) -{ - unsigned int ret = 0; - - if (lirc_buffer_len(buf) >= buf->chunk_size) - ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size, - &buf->fifo_lock); - return ret; - -} - -static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, - unsigned char *orig) -{ - unsigned int ret; - - ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size, - &buf->fifo_lock); - - return ret; -} - -struct lirc_driver { - char name[40]; - int minor; - __u32 code_length; - unsigned int buffer_size; /* in chunks holding one code each */ - int sample_rate; - __u32 features; - - unsigned int chunk_size; - - void *data; - int min_timeout; - int max_timeout; - int (*add_to_buf) (void *data, struct lirc_buffer *buf); - struct lirc_buffer *rbuf; - int (*set_use_inc) (void *data); - void (*set_use_dec) (void *data); - const struct file_operations *fops; - struct device *dev; - struct module *owner; -}; - -/* name: - * this string will be used for logs - * - * minor: - * indicates minor device (/dev/lirc) number for registered driver - * if caller fills it with negative value, then the first free minor - * number will be used (if available) - * - * code_length: - * length of the remote control key code expressed in bits - * - * sample_rate: - * - * data: - * it may point to any driver data and this pointer will be passed to - * all callback functions - * - * add_to_buf: - * add_to_buf will be called after specified period of the time or - * triggered by the external event, this behavior depends on value of - * the sample_rate this function will be called in user context. This - * routine should return 0 if data was added to the buffer and - * -ENODATA if none was available. This should add some number of bits - * evenly divisible by code_length to the buffer - * - * rbuf: - * if not NULL, it will be used as a read buffer, you will have to - * write to the buffer by other means, like irq's (see also - * lirc_serial.c). - * - * set_use_inc: - * set_use_inc will be called after device is opened - * - * set_use_dec: - * set_use_dec will be called after device is closed - * - * fops: - * file_operations for drivers which don't fit the current driver model. - * - * Some ioctl's can be directly handled by lirc_dev if the driver's - * ioctl function is NULL or if it returns -ENOIOCTLCMD (see also - * lirc_serial.c). - * - * owner: - * the module owning this struct - * - */ - - -/* following functions can be called ONLY from user context - * - * returns negative value on error or minor number - * of the registered device if success - * contents of the structure pointed by p is copied - */ -extern int lirc_register_driver(struct lirc_driver *d); - -/* returns negative value on error or 0 if success -*/ -extern int lirc_unregister_driver(int minor); - -/* Returns the private data stored in the lirc_driver - * associated with the given device file pointer. - */ -void *lirc_get_pdata(struct file *file); - -/* default file operations - * used by drivers if they override only some operations - */ -int lirc_dev_fop_open(struct inode *inode, struct file *file); -int lirc_dev_fop_close(struct inode *inode, struct file *file); -unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait); -long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -ssize_t lirc_dev_fop_read(struct file *file, char __user *buffer, size_t length, - loff_t *ppos); -ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer, - size_t length, loff_t *ppos); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/lirc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/lirc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/lirc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/lirc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,168 +0,0 @@ -/* - * lirc.h - linux infrared remote control header file - * last modified 2010/07/13 by Jarod Wilson - */ - -#ifndef _LINUX_LIRC_H -#define _LINUX_LIRC_H - -#include -#include - -#define PULSE_BIT 0x01000000 -#define PULSE_MASK 0x00FFFFFF - -#define LIRC_MODE2_SPACE 0x00000000 -#define LIRC_MODE2_PULSE 0x01000000 -#define LIRC_MODE2_FREQUENCY 0x02000000 -#define LIRC_MODE2_TIMEOUT 0x03000000 - -#define LIRC_VALUE_MASK 0x00FFFFFF -#define LIRC_MODE2_MASK 0xFF000000 - -#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE) -#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE) -#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY) -#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT) - -#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK) -#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK) - -#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE) -#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE) -#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY) -#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT) - -/* used heavily by lirc userspace */ -#define lirc_t int - -/*** lirc compatible hardware features ***/ - -#define LIRC_MODE2SEND(x) (x) -#define LIRC_SEND2MODE(x) (x) -#define LIRC_MODE2REC(x) ((x) << 16) -#define LIRC_REC2MODE(x) ((x) >> 16) - -#define LIRC_MODE_RAW 0x00000001 -#define LIRC_MODE_PULSE 0x00000002 -#define LIRC_MODE_MODE2 0x00000004 -#define LIRC_MODE_LIRCCODE 0x00000010 - - -#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW) -#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE) -#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2) -#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE) - -#define LIRC_CAN_SEND_MASK 0x0000003f - -#define LIRC_CAN_SET_SEND_CARRIER 0x00000100 -#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200 -#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400 - -#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW) -#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE) -#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2) -#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE) - -#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK) - -#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16) -#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16) - -#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000 -#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000 -#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000 -#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000 -#define LIRC_CAN_SET_REC_FILTER 0x08000000 - -#define LIRC_CAN_MEASURE_CARRIER 0x02000000 -#define LIRC_CAN_USE_WIDEBAND_RECEIVER 0x04000000 - -#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK) -#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK) - -#define LIRC_CAN_NOTIFY_DECODE 0x01000000 - -/*** IOCTL commands for lirc driver ***/ - -#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) - -#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32) -#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) -#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32) -#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32) -#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32) -#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32) -#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, __u32) - -#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, __u32) -#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, __u32) - -#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, __u32) -#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, __u32) -#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, __u32) -#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, __u32) - -/* code length in bits, currently only for LIRC_MODE_LIRCCODE */ -#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32) - -#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32) -#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) -/* Note: these can reset the according pulse_width */ -#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32) -#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32) -#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32) -#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32) -#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, __u32) - -/* - * when a timeout != 0 is set the driver will send a - * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is - * never sent, timeout is disabled by default - */ -#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, __u32) - -/* 1 enables, 0 disables timeout reports in MODE2 */ -#define LIRC_SET_REC_TIMEOUT_REPORTS _IOW('i', 0x00000019, __u32) - -/* - * pulses shorter than this are filtered out by hardware (software - * emulation in lirc_dev?) - */ -#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x0000001a, __u32) -/* - * spaces shorter than this are filtered out by hardware (software - * emulation in lirc_dev?) - */ -#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001b, __u32) -/* - * if filter cannot be set independantly for pulse/space, this should - * be used - */ -#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001c, __u32) - -/* - * if enabled from the next key press on the driver will send - * LIRC_MODE2_FREQUENCY packets - */ -#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32) - -/* - * to set a range use - * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the - * lower bound first and later - * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound - */ - -#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, __u32) -#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32) - -#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020) - -#define LIRC_SETUP_START _IO('i', 0x00000021) -#define LIRC_SETUP_END _IO('i', 0x00000022) - -#define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/m52790.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/m52790.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/m52790.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/m52790.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/* - m52790.h - definition for m52790 inputs and outputs - - Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _M52790_H_ -#define _M52790_H_ - -/* Input routing switch 1 */ - -#define M52790_SW1_IN_MASK 0x0003 -#define M52790_SW1_IN_TUNER 0x0000 -#define M52790_SW1_IN_V2 0x0001 -#define M52790_SW1_IN_V3 0x0002 -#define M52790_SW1_IN_V4 0x0003 - -/* Selects component input instead of composite */ -#define M52790_SW1_YCMIX 0x0004 - - -/* Input routing switch 2 */ - -#define M52790_SW2_IN_MASK 0x0300 -#define M52790_SW2_IN_TUNER 0x0000 -#define M52790_SW2_IN_V2 0x0100 -#define M52790_SW2_IN_V3 0x0200 -#define M52790_SW2_IN_V4 0x0300 - -/* Selects component input instead of composite */ -#define M52790_SW2_YCMIX 0x0400 - - -/* Output routing switch 1 */ - -/* Enable 6dB amplifier for composite out */ -#define M52790_SW1_V_AMP 0x0008 - -/* Enable 6dB amplifier for component out */ -#define M52790_SW1_YC_AMP 0x0010 - -/* Audio output mode */ -#define M52790_SW1_AUDIO_MASK 0x00c0 -#define M52790_SW1_AUDIO_MUTE 0x0000 -#define M52790_SW1_AUDIO_R 0x0040 -#define M52790_SW1_AUDIO_L 0x0080 -#define M52790_SW1_AUDIO_STEREO 0x00c0 - - -/* Output routing switch 2 */ - -/* Enable 6dB amplifier for composite out */ -#define M52790_SW2_V_AMP 0x0800 - -/* Enable 6dB amplifier for component out */ -#define M52790_SW2_YC_AMP 0x1000 - -/* Audio output mode */ -#define M52790_SW2_AUDIO_MASK 0xc000 -#define M52790_SW2_AUDIO_MUTE 0x0000 -#define M52790_SW2_AUDIO_R 0x4000 -#define M52790_SW2_AUDIO_L 0x8000 -#define M52790_SW2_AUDIO_STEREO 0xc000 - - -/* Common values */ -#define M52790_IN_TUNER (M52790_SW1_IN_TUNER | M52790_SW2_IN_TUNER) -#define M52790_IN_V2 (M52790_SW1_IN_V2 | M52790_SW2_IN_V2) -#define M52790_IN_V3 (M52790_SW1_IN_V3 | M52790_SW2_IN_V3) -#define M52790_IN_V4 (M52790_SW1_IN_V4 | M52790_SW2_IN_V4) - -#define M52790_OUT_STEREO (M52790_SW1_AUDIO_STEREO | \ - M52790_SW2_AUDIO_STEREO) -#define M52790_OUT_AMP_STEREO (M52790_SW1_AUDIO_STEREO | \ - M52790_SW1_V_AMP | \ - M52790_SW2_AUDIO_STEREO | \ - M52790_SW2_V_AMP) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-device.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-device.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-device.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* - * Media device - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - */ - -#ifndef _MEDIA_DEVICE_H -#define _MEDIA_DEVICE_H - -#include -#include -#include -#include - -#include -#include - -/** - * struct media_device - Media device - * @dev: Parent device - * @devnode: Media device node - * @model: Device model name - * @serial: Device serial number (optional) - * @bus_info: Unique and stable device location identifier - * @hw_revision: Hardware device revision - * @driver_version: Device driver version - * @entity_id: ID of the next entity to be registered - * @entities: List of registered entities - * @lock: Entities list lock - * @graph_mutex: Entities graph operation lock - * - * This structure represents an abstract high-level media device. It allows easy - * access to entities and provides basic media device-level support. The - * structure can be allocated directly or embedded in a larger structure. - * - * The parent @dev is a physical device. It must be set before registering the - * media device. - * - * @model is a descriptive model name exported through sysfs. It doesn't have to - * be unique. - */ -struct media_device { - /* dev->driver_data points to this struct. */ - struct device *dev; - struct media_devnode devnode; - - char model[32]; - char serial[40]; - char bus_info[32]; - u32 hw_revision; - u32 driver_version; - - u32 entity_id; - struct list_head entities; - - /* Protects the entities list */ - spinlock_t lock; - /* Serializes graph operations. */ - struct mutex graph_mutex; - - int (*link_notify)(struct media_pad *source, - struct media_pad *sink, u32 flags); -}; - -/* media_devnode to media_device */ -#define to_media_device(node) container_of(node, struct media_device, devnode) - -int __must_check media_device_register(struct media_device *mdev); -void media_device_unregister(struct media_device *mdev); - -int __must_check media_device_register_entity(struct media_device *mdev, - struct media_entity *entity); -void media_device_unregister_entity(struct media_entity *entity); - -/* Iterate over all entities. */ -#define media_device_for_each_entity(entity, mdev) \ - list_for_each_entry(entity, &(mdev)->entities, list) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-devnode.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-devnode.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-devnode.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-devnode.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/* - * Media device node - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - * - * -- - * - * Common functions for media-related drivers to register and unregister media - * device nodes. - */ - -#ifndef _MEDIA_DEVNODE_H -#define _MEDIA_DEVNODE_H - -#include -#include -#include -#include - -/* - * Flag to mark the media_devnode struct as registered. Drivers must not touch - * this flag directly, it will be set and cleared by media_devnode_register and - * media_devnode_unregister. - */ -#define MEDIA_FLAG_REGISTERED 0 - -struct media_file_operations { - struct module *owner; - ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); - ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); - unsigned int (*poll) (struct file *, struct poll_table_struct *); - long (*ioctl) (struct file *, unsigned int, unsigned long); - int (*open) (struct file *); - int (*release) (struct file *); -}; - -/** - * struct media_devnode - Media device node - * @parent: parent device - * @minor: device node minor number - * @flags: flags, combination of the MEDIA_FLAG_* constants - * - * This structure represents a media-related device node. - * - * The @parent is a physical device. It must be set by core or device drivers - * before registering the node. - */ -struct media_devnode { - /* device ops */ - const struct media_file_operations *fops; - - /* sysfs */ - struct device dev; /* media device */ - struct cdev cdev; /* character device */ - struct device *parent; /* device parent */ - - /* device info */ - int minor; - unsigned long flags; /* Use bitops to access flags */ - - /* callbacks */ - void (*release)(struct media_devnode *mdev); -}; - -/* dev to media_devnode */ -#define to_media_devnode(cd) container_of(cd, struct media_devnode, dev) - -int __must_check media_devnode_register(struct media_devnode *mdev); -void media_devnode_unregister(struct media_devnode *mdev); - -static inline struct media_devnode *media_devnode_data(struct file *filp) -{ - return filp->private_data; -} - -static inline int media_devnode_is_registered(struct media_devnode *mdev) -{ - return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); -} - -#endif /* _MEDIA_DEVNODE_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-entity.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-entity.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-entity.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/media-entity.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,151 +0,0 @@ -/* - * Media entity - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 - */ - -#ifndef _MEDIA_ENTITY_H -#define _MEDIA_ENTITY_H - -#include -#include - -struct media_pipeline { -}; - -struct media_link { - struct media_pad *source; /* Source pad */ - struct media_pad *sink; /* Sink pad */ - struct media_link *reverse; /* Link in the reverse direction */ - unsigned long flags; /* Link flags (MEDIA_LNK_FL_*) */ -}; - -struct media_pad { - struct media_entity *entity; /* Entity this pad belongs to */ - u16 index; /* Pad index in the entity pads array */ - unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */ -}; - -struct media_entity_operations { - int (*link_setup)(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags); -}; - -struct media_entity { - struct list_head list; - struct media_device *parent; /* Media device this entity belongs to*/ - u32 id; /* Entity ID, unique in the parent media - * device context */ - const char *name; /* Entity name */ - u32 type; /* Entity type (MEDIA_ENT_T_*) */ - u32 revision; /* Entity revision, driver specific */ - unsigned long flags; /* Entity flags (MEDIA_ENT_FL_*) */ - u32 group_id; /* Entity group ID */ - - u16 num_pads; /* Number of sink and source pads */ - u16 num_links; /* Number of existing links, both - * enabled and disabled */ - u16 num_backlinks; /* Number of backlinks */ - u16 max_links; /* Maximum number of links */ - - struct media_pad *pads; /* Pads array (num_pads elements) */ - struct media_link *links; /* Links array (max_links elements)*/ - - const struct media_entity_operations *ops; /* Entity operations */ - - /* Reference counts must never be negative, but are signed integers on - * purpose: a simple WARN_ON(<0) check can be used to detect reference - * count bugs that would make them negative. - */ - int stream_count; /* Stream count for the entity. */ - int use_count; /* Use count for the entity. */ - - struct media_pipeline *pipe; /* Pipeline this entity belongs to. */ - - union { - /* Node specifications */ - struct { - u32 major; - u32 minor; - } v4l; - struct { - u32 major; - u32 minor; - } fb; - struct { - u32 card; - u32 device; - u32 subdevice; - } alsa; - int dvb; - - /* Sub-device specifications */ - /* Nothing needed yet */ - }; -}; - -static inline u32 media_entity_type(struct media_entity *entity) -{ - return entity->type & MEDIA_ENT_TYPE_MASK; -} - -static inline u32 media_entity_subtype(struct media_entity *entity) -{ - return entity->type & MEDIA_ENT_SUBTYPE_MASK; -} - -#define MEDIA_ENTITY_ENUM_MAX_DEPTH 16 - -struct media_entity_graph { - struct { - struct media_entity *entity; - int link; - } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH]; - int top; -}; - -int media_entity_init(struct media_entity *entity, u16 num_pads, - struct media_pad *pads, u16 extra_links); -void media_entity_cleanup(struct media_entity *entity); - -int media_entity_create_link(struct media_entity *source, u16 source_pad, - struct media_entity *sink, u16 sink_pad, u32 flags); -int __media_entity_setup_link(struct media_link *link, u32 flags); -int media_entity_setup_link(struct media_link *link, u32 flags); -struct media_link *media_entity_find_link(struct media_pad *source, - struct media_pad *sink); -struct media_pad *media_entity_remote_source(struct media_pad *pad); - -struct media_entity *media_entity_get(struct media_entity *entity); -void media_entity_put(struct media_entity *entity); - -void media_entity_graph_walk_start(struct media_entity_graph *graph, - struct media_entity *entity); -struct media_entity * -media_entity_graph_walk_next(struct media_entity_graph *graph); -void media_entity_pipeline_start(struct media_entity *entity, - struct media_pipeline *pipe); -void media_entity_pipeline_stop(struct media_entity *entity); - -#define media_entity_call(entity, operation, args...) \ - (((entity)->ops && (entity)->ops->operation) ? \ - (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/msp3400.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/msp3400.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/msp3400.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/msp3400.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,226 +0,0 @@ -/* - msp3400.h - definition for msp3400 inputs and outputs - - Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _MSP3400_H_ -#define _MSP3400_H_ - -/* msp3400 routing - =============== - - The msp3400 has a complicated routing scheme with many possible - combinations. The details are all in the datasheets but I will try - to give a short description here. - - Inputs - ====== - - There are 1) tuner inputs, 2) I2S inputs, 3) SCART inputs. You will have - to select which tuner input to use and which SCART input to use. The - selected tuner input, the selected SCART input and all I2S inputs go to - the DSP (the tuner input first goes through the demodulator). - - The DSP handles things like volume, bass/treble, balance, and some chips - have support for surround sound. It has several outputs: MAIN, AUX, I2S - and SCART1/2. Each output can select which DSP input to use. So the MAIN - output can select the tuner input while at the same time the SCART1 output - uses the I2S input. - - Outputs - ======= - - Most DSP outputs are also the outputs of the msp3400. However, the SCART - outputs of the msp3400 can select which input to use: either the SCART1 or - SCART2 output from the DSP, or the msp3400 SCART inputs, thus completely - bypassing the DSP. - - Summary - ======= - - So to specify a complete routing scheme for the msp3400 you will have to - specify in the 'input' arg of the s_routing function: - - 1) which tuner input to use - 2) which SCART input to use - 3) which DSP input to use for each DSP output - - And in the 'output' arg of the s_routing function you specify: - - 1) which SCART input to use for each SCART output - - Depending on how the msp is wired to the other components you can - ignore or mute certain inputs or outputs. - - Also, depending on the msp version only a subset of the inputs or - outputs may be present. At the end of this header some tables are - added containing a list of what is available for each msp version. - */ - -/* Inputs to the DSP unit: two independent selections have to be made: - 1) the tuner (SIF) input - 2) the SCART input - Bits 0-2 are used for the SCART input select, bit 3 is used for the tuner - input, bits 4-7 are reserved. - */ - -/* SCART input to DSP selection */ -#define MSP_IN_SCART1 0 /* Pin SC1_IN */ -#define MSP_IN_SCART2 1 /* Pin SC2_IN */ -#define MSP_IN_SCART3 2 /* Pin SC3_IN */ -#define MSP_IN_SCART4 3 /* Pin SC4_IN */ -#define MSP_IN_MONO 6 /* Pin MONO_IN */ -#define MSP_IN_MUTE 7 /* Mute DSP input */ -#define MSP_SCART_TO_DSP(in) (in) -/* Tuner input to demodulator and DSP selection */ -#define MSP_IN_TUNER1 0 /* Analog Sound IF input pin ANA_IN1 */ -#define MSP_IN_TUNER2 1 /* Analog Sound IF input pin ANA_IN2 */ -#define MSP_TUNER_TO_DSP(in) ((in) << 3) - -/* The msp has up to 5 DSP outputs, each output can independently select - a DSP input. - - The DSP outputs are: loudspeaker output (aka MAIN), headphones output - (aka AUX), SCART1 DA output, SCART2 DA output and an I2S output. - There also is a quasi-peak detector output, but that is not used by - this driver and is set to the same input as the loudspeaker output. - Not all outputs are supported by all msp models. Setting the input - of an unsupported output will be ignored by the driver. - - There are up to 16 DSP inputs to choose from, so each output is - assigned 4 bits. - - Note: the 44x8G can mix two inputs and feed the result back to the - DSP. This is currently not implemented. Also not implemented is the - multi-channel capable I2S3 input of the 44x0G. If someone can demonstrate - a need for one of those features then additional support can be added. */ -#define MSP_DSP_IN_TUNER 0 /* Tuner DSP input */ -#define MSP_DSP_IN_SCART 2 /* SCART DSP input */ -#define MSP_DSP_IN_I2S1 5 /* I2S1 DSP input */ -#define MSP_DSP_IN_I2S2 6 /* I2S2 DSP input */ -#define MSP_DSP_IN_I2S3 7 /* I2S3 DSP input */ -#define MSP_DSP_IN_MAIN_AVC 11 /* MAIN AVC processed DSP input */ -#define MSP_DSP_IN_MAIN 12 /* MAIN DSP input */ -#define MSP_DSP_IN_AUX 13 /* AUX DSP input */ -#define MSP_DSP_TO_MAIN(in) ((in) << 4) -#define MSP_DSP_TO_AUX(in) ((in) << 8) -#define MSP_DSP_TO_SCART1(in) ((in) << 12) -#define MSP_DSP_TO_SCART2(in) ((in) << 16) -#define MSP_DSP_TO_I2S(in) ((in) << 20) - -/* Output SCART select: the SCART outputs can select which input - to use. */ -#define MSP_SC_IN_SCART1 0 /* SCART1 input, bypassing the DSP */ -#define MSP_SC_IN_SCART2 1 /* SCART2 input, bypassing the DSP */ -#define MSP_SC_IN_SCART3 2 /* SCART3 input, bypassing the DSP */ -#define MSP_SC_IN_SCART4 3 /* SCART4 input, bypassing the DSP */ -#define MSP_SC_IN_DSP_SCART1 4 /* DSP SCART1 input */ -#define MSP_SC_IN_DSP_SCART2 5 /* DSP SCART2 input */ -#define MSP_SC_IN_MONO 6 /* MONO input, bypassing the DSP */ -#define MSP_SC_IN_MUTE 7 /* MUTE output */ -#define MSP_SC_TO_SCART1(in) (in) -#define MSP_SC_TO_SCART2(in) ((in) << 4) - -/* Shortcut macros */ -#define MSP_INPUT(sc, t, main_aux_src, sc_i2s_src) \ - (MSP_SCART_TO_DSP(sc) | \ - MSP_TUNER_TO_DSP(t) | \ - MSP_DSP_TO_MAIN(main_aux_src) | \ - MSP_DSP_TO_AUX(main_aux_src) | \ - MSP_DSP_TO_SCART1(sc_i2s_src) | \ - MSP_DSP_TO_SCART2(sc_i2s_src) | \ - MSP_DSP_TO_I2S(sc_i2s_src)) -#define MSP_INPUT_DEFAULT MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ - MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER) -#define MSP_OUTPUT(sc) \ - (MSP_SC_TO_SCART1(sc) | \ - MSP_SC_TO_SCART2(sc)) -/* This equals the RESET position of the msp3400 ACB register */ -#define MSP_OUTPUT_DEFAULT (MSP_SC_TO_SCART1(MSP_SC_IN_SCART3) | \ - MSP_SC_TO_SCART2(MSP_SC_IN_DSP_SCART1)) - -/* Tuner inputs vs. msp version */ -/* Chip TUNER_1 TUNER_2 - ------------------------- - msp34x0b y y - msp34x0c y y - msp34x0d y y - msp34x5d y n - msp34x7d y n - msp34x0g y y - msp34x1g y y - msp34x2g y y - msp34x5g y n - msp34x7g y n - msp44x0g y y - msp44x8g y y - */ - -/* SCART inputs vs. msp version */ -/* Chip SC1 SC2 SC3 SC4 - ------------------------- - msp34x0b y y y n - msp34x0c y y y n - msp34x0d y y y y - msp34x5d y y n n - msp34x7d y n n n - msp34x0g y y y y - msp34x1g y y y y - msp34x2g y y y y - msp34x5g y y n n - msp34x7g y n n n - msp44x0g y y y y - msp44x8g y y y y - */ - -/* DSP inputs vs. msp version (tuner and SCART inputs are always available) */ -/* Chip I2S1 I2S2 I2S3 MAIN_AVC MAIN AUX - ------------------------------------------ - msp34x0b y n n n n n - msp34x0c y y n n n n - msp34x0d y y n n n n - msp34x5d y y n n n n - msp34x7d n n n n n n - msp34x0g y y n n n n - msp34x1g y y n n n n - msp34x2g y y n y y y - msp34x5g y y n n n n - msp34x7g n n n n n n - msp44x0g y y y y y y - msp44x8g y y y n n n - */ - -/* DSP outputs vs. msp version */ -/* Chip MAIN AUX SCART1 SCART2 I2S - ------------------------------------ - msp34x0b y y y n y - msp34x0c y y y n y - msp34x0d y y y y y - msp34x5d y n y n y - msp34x7d y n y n n - msp34x0g y y y y y - msp34x1g y y y y y - msp34x2g y y y y y - msp34x5g y n y n y - msp34x7g y n y n n - msp44x0g y y y y y - msp44x8g y y y y y - */ - -#endif /* MSP3400_H */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/mt9t112.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/mt9t112.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/mt9t112.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/mt9t112.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* mt9t112 Camera - * - * Copyright (C) 2009 Renesas Solutions Corp. - * Kuninori Morimoto - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __MT9T112_H__ -#define __MT9T112_H__ - -#define MT9T112_FLAG_PCLK_RISING_EDGE (1 << 0) -#define MT9T112_FLAG_DATAWIDTH_8 (1 << 1) /* default width is 10 */ - -struct mt9t112_pll_divider { - u8 m, n; - u8 p1, p2, p3, p4, p5, p6, p7; -}; - -/* - * mt9t112 camera info - */ -struct mt9t112_camera_info { - u32 flags; - struct mt9t112_pll_divider divider; -}; - -#endif /* __MT9T112_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/mt9v011.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/mt9v011.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/mt9v011.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/mt9v011.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -/* mt9v011 sensor - * - * Copyright (C) 2011 Hans Verkuil - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __MT9V011_H__ -#define __MT9V011_H__ - -struct mt9v011_platform_data { - unsigned xtal; /* Hz */ -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/noon010pc30.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/noon010pc30.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/noon010pc30.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/noon010pc30.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -/* - * Driver header for NOON010PC30L camera sensor chip. - * - * Copyright (c) 2010 Samsung Electronics, Co. Ltd - * Contact: Sylwester Nawrocki - * - * 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, or - * (at your option) any later version. - */ - -#ifndef NOON010PC30_H -#define NOON010PC30_H - -/** - * @clk_rate: the clock frequency in Hz - * @gpio_nreset: GPIO driving nRESET pin - * @gpio_nstby: GPIO driving nSTBY pin - */ - -struct noon010pc30_platform_data { - unsigned long clk_rate; - int gpio_nreset; - int gpio_nstby; -}; - -#endif /* NOON010PC30_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/omap1_camera.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/omap1_camera.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/omap1_camera.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/omap1_camera.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - * Header for V4L2 SoC Camera driver for OMAP1 Camera Interface - * - * Copyright (C) 2010, Janusz Krzysztofik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __MEDIA_OMAP1_CAMERA_H_ -#define __MEDIA_OMAP1_CAMERA_H_ - -#include - -#define OMAP1_CAMERA_IOSIZE 0x1c - -enum omap1_cam_vb_mode { - OMAP1_CAM_DMA_CONTIG = 0, - OMAP1_CAM_DMA_SG, -}; - -#define OMAP1_CAMERA_MIN_BUF_COUNT(x) ((x) == OMAP1_CAM_DMA_CONTIG ? 3 : 2) - -struct omap1_cam_platform_data { - unsigned long camexclk_khz; - unsigned long lclk_khz_max; - unsigned long flags; -}; - -#define OMAP1_CAMERA_LCLK_RISING BIT(0) -#define OMAP1_CAMERA_RST_LOW BIT(1) -#define OMAP1_CAMERA_RST_HIGH BIT(2) - -#endif /* __MEDIA_OMAP1_CAMERA_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/ov772x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/ov772x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/ov772x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/ov772x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* - * ov772x Camera - * - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __OV772X_H__ -#define __OV772X_H__ - -#include - -/* for flags */ -#define OV772X_FLAG_VFLIP (1 << 0) /* Vertical flip image */ -#define OV772X_FLAG_HFLIP (1 << 1) /* Horizontal flip image */ -#define OV772X_FLAG_8BIT (1 << 2) /* default 10 bit */ - -/* - * for Edge ctrl - * - * strength also control Auto or Manual Edge Control Mode - * see also OV772X_MANUAL_EDGE_CTRL - */ -struct ov772x_edge_ctrl { - unsigned char strength; - unsigned char threshold; - unsigned char upper; - unsigned char lower; -}; - -#define OV772X_MANUAL_EDGE_CTRL 0x80 /* un-used bit of strength */ -#define EDGE_STRENGTH_MASK 0x1F -#define EDGE_THRESHOLD_MASK 0x0F -#define EDGE_UPPER_MASK 0xFF -#define EDGE_LOWER_MASK 0xFF - -#define OV772X_AUTO_EDGECTRL(u, l) \ -{ \ - .upper = (u & EDGE_UPPER_MASK), \ - .lower = (l & EDGE_LOWER_MASK), \ -} - -#define OV772X_MANUAL_EDGECTRL(s, t) \ -{ \ - .strength = (s & EDGE_STRENGTH_MASK) | OV772X_MANUAL_EDGE_CTRL,\ - .threshold = (t & EDGE_THRESHOLD_MASK), \ -} - -/* - * ov772x camera info - */ -struct ov772x_camera_info { - unsigned long flags; - struct ov772x_edge_ctrl edgectrl; -}; - -#endif /* __OV772X_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/pwc-ioctl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/pwc-ioctl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/pwc-ioctl.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/pwc-ioctl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,324 +0,0 @@ -#ifndef PWC_IOCTL_H -#define PWC_IOCTL_H - -/* (C) 2001-2004 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - 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, or - (at your option) any later version. - - 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 -*/ - -/* This is pwc-ioctl.h belonging to PWC 10.0.10 - It contains structures and defines to communicate from user space - directly to the driver. - */ - -/* - Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for - changing white balance and red/blue gains - 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE - 2003/12/13 Nemosft Unv. Some modifications to make interfacing to - PWCX easier - 2006/01/01 Luc Saillard Add raw format definition - */ - -/* These are private ioctl() commands, specific for the Philips webcams. - They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - - The #define names are built up like follows: - VIDIOC VIDeo IOCtl prefix - PWC Philps WebCam - G optional: Get - S optional: Set - ... the function - */ - -#include -#include - -/* Enumeration of image sizes */ -#define PSZ_SQCIF 0x00 -#define PSZ_QSIF 0x01 -#define PSZ_QCIF 0x02 -#define PSZ_SIF 0x03 -#define PSZ_CIF 0x04 -#define PSZ_VGA 0x05 -#define PSZ_MAX 6 - - -/* The frame rate is encoded in the video_window.flags parameter using - the upper 16 bits, since some flags are defined nowadays. The following - defines provide a mask and shift to filter out this value. - This value can also be passing using the private flag when using v4l2 and - VIDIOC_S_FMT ioctl. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour - balance controls. - */ -#define PWC_FPS_SHIFT 16 -#define PWC_FPS_MASK 0x00FF0000 -#define PWC_FPS_FRMASK 0x003F0000 -#define PWC_FPS_SNAPSHOT 0x00400000 -#define PWC_QLT_MASK 0x03000000 -#define PWC_QLT_SHIFT 24 - - -/* structure for transferring x & y coordinates */ -struct pwc_coord -{ - int x, y; /* guess what */ - int size; /* size, or offset */ -}; - - -/* Used with VIDIOCPWCPROBE */ -struct pwc_probe -{ - char name[32]; - int type; -}; - -struct pwc_serial -{ - char serial[30]; /* String with serial number. Contains terminating 0 */ -}; - -/* pwc_whitebalance.mode values */ -#define PWC_WB_INDOOR 0 -#define PWC_WB_OUTDOOR 1 -#define PWC_WB_FL 2 -#define PWC_WB_MANUAL 3 -#define PWC_WB_AUTO 4 - -/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). - Set mode to one of the PWC_WB_* values above. - *red and *blue are the respective gains of these colour components inside - the camera; range 0..65535 - When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; - otherwise undefined. - 'read_red' and 'read_blue' are read-only. -*/ -struct pwc_whitebalance -{ - int mode; - int manual_red, manual_blue; /* R/W */ - int read_red, read_blue; /* R/O */ -}; - -/* - 'control_speed' and 'control_delay' are used in automatic whitebalance mode, - and tell the camera how fast it should react to changes in lighting, and - with how much delay. Valid values are 0..65535. -*/ -struct pwc_wb_speed -{ - int control_speed; - int control_delay; - -}; - -/* Used with VIDIOCPWC[SG]LED */ -struct pwc_leds -{ - int led_on; /* Led on-time; range = 0..25000 */ - int led_off; /* Led off-time; range = 0..25000 */ -}; - -/* Image size (used with GREALSIZE) */ -struct pwc_imagesize -{ - int width; - int height; -}; - -/* Defines and structures for Motorized Pan & Tilt */ -#define PWC_MPT_PAN 0x01 -#define PWC_MPT_TILT 0x02 -#define PWC_MPT_TIMEOUT 0x04 /* for status */ - -/* Set angles; when absolute != 0, the angle is absolute and the - driver calculates the relative offset for you. This can only - be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns - absolute angles. - */ -struct pwc_mpt_angles -{ - int absolute; /* write-only */ - int pan; /* degrees * 100 */ - int tilt; /* degress * 100 */ -}; - -/* Range of angles of the camera, both horizontally and vertically. - */ -struct pwc_mpt_range -{ - int pan_min, pan_max; /* degrees * 100 */ - int tilt_min, tilt_max; -}; - -struct pwc_mpt_status -{ - int status; - int time_pan; - int time_tilt; -}; - - -/* This is used for out-of-kernel decompression. With it, you can get - all the necessary information to initialize and use the decompressor - routines in standalone applications. - */ -struct pwc_video_command -{ - int type; /* camera type (645, 675, 730, etc.) */ - int release; /* release number */ - - int size; /* one of PSZ_* */ - int alternate; - int command_len; /* length of USB video command */ - unsigned char command_buf[13]; /* Actual USB video command */ - int bandlength; /* >0 = compressed */ - int frame_size; /* Size of one (un)compressed frame */ -}; - -/* Flags for PWCX subroutines. Not all modules honour all flags. */ -#define PWCX_FLAG_PLANAR 0x0001 -#define PWCX_FLAG_BAYER 0x0008 - - -/* IOCTL definitions */ - - /* Restore user settings */ -#define VIDIOCPWCRUSER _IO('v', 192) - /* Save user settings */ -#define VIDIOCPWCSUSER _IO('v', 193) - /* Restore factory settings */ -#define VIDIOCPWCFACTORY _IO('v', 194) - - /* You can manipulate the compression factor. A compression preference of 0 - means use uncompressed modes when available; 1 is low compression, 2 is - medium and 3 is high compression preferred. Of course, the higher the - compression, the lower the bandwidth used but more chance of artefacts - in the image. The driver automatically chooses a higher compression when - the preferred mode is not available. - */ - /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ -#define VIDIOCPWCSCQUAL _IOW('v', 195, int) - /* Get preferred compression quality */ -#define VIDIOCPWCGCQUAL _IOR('v', 195, int) - - -/* Retrieve serial number of camera */ -#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) - - /* This is a probe function; since so many devices are supported, it - becomes difficult to include all the names in programs that want to - check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding - Philips type. - To use, fill the structure with zeroes, call PROBE and if that succeeds, - compare the name with that returned from VIDIOCGCAP; they should be the - same. If so, you can be assured it is a Philips (OEM) cam and the type - is valid. - */ -#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) - - /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ -#define VIDIOCPWCSAGC _IOW('v', 200, int) - /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCGAGC _IOR('v', 200, int) - /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) - - /* Color compensation (Auto White Balance) */ -#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) -#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - - /* Auto WB speed */ -#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) -#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) - - /* LEDs on/off/blink; int range 0..65535 */ -#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) -#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) - - /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ -#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) -#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) - - /* Backlight compensation; 0 = off, otherwise on */ -#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) -#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) - - /* Flickerless mode; = 0 off, otherwise on */ -#define VIDIOCPWCSFLICKER _IOW('v', 208, int) -#define VIDIOCPWCGFLICKER _IOR('v', 208, int) - - /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ -#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) -#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) - - /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ -#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) - - /* Motorized pan & tilt functions */ -#define VIDIOCPWCMPTRESET _IOW('v', 211, int) -#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) -#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - - /* Get the USB set-video command; needed for initializing libpwcx */ -#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) -struct pwc_table_init_buffer { - int len; - char *buffer; - -}; -#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) - -/* - * This is private command used when communicating with v4l2. - * In the future all private ioctl will be remove/replace to - * use interface offer by v4l2. - */ - -#define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4) -#define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6) -#define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8) - -struct pwc_raw_frame { - __le16 type; /* type of the webcam */ - __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */ - __u8 cmd[4]; /* the four byte of the command (in case of nala, - only the first 3 bytes is filled) */ - __u8 rawframe[0]; /* frame_size = H/4*vbandlength */ -} __attribute__ ((packed)); - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/radio-si4713.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/radio-si4713.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/radio-si4713.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/radio-si4713.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - * include/media/radio-si4713.h - * - * Board related data definitions for Si4713 radio transmitter chip. - * - * Copyright (c) 2009 Nokia Corporation - * Contact: Eduardo Valentin - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - */ - -#ifndef RADIO_SI4713_H -#define RADIO_SI4713_H - -#include - -#define SI4713_NAME "radio-si4713" - -/* - * Platform dependent definition - */ -struct radio_si4713_platform_data { - int i2c_bus; - struct i2c_board_info *subdev_board_info; -}; - -#endif /* ifndef RADIO_SI4713_H*/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/rc-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/rc-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/rc-core.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/rc-core.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,223 +0,0 @@ -/* - * Remote Controller core header - * - * Copyright (C) 2009-2010 by Mauro Carvalho Chehab - * - * 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 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. - */ - -#ifndef _RC_CORE -#define _RC_CORE - -#include -#include -#include -#include -#include - -extern int rc_core_debug; -#define IR_dprintk(level, fmt, arg...) if (rc_core_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt , __func__, ## arg) - -enum rc_driver_type { - RC_DRIVER_SCANCODE = 0, /* Driver or hardware generates a scancode */ - RC_DRIVER_IR_RAW, /* Needs a Infra-Red pulse/space decoder */ -}; - -/** - * struct rc_dev - represents a remote control device - * @dev: driver model's view of this device - * @input_name: name of the input child device - * @input_phys: physical path to the input child device - * @input_id: id of the input child device (struct input_id) - * @driver_name: name of the hardware driver which registered this device - * @map_name: name of the default keymap - * @rc_map: current scan/key table - * @devno: unique remote control device number - * @raw: additional data for raw pulse/space devices - * @input_dev: the input child device used to communicate events to userspace - * @driver_type: specifies if protocol decoding is done in hardware or software - * @idle: used to keep track of RX state - * @allowed_protos: bitmask with the supported RC_TYPE_* protocols - * @scanmask: some hardware decoders are not capable of providing the full - * scancode to the application. As this is a hardware limit, we can't do - * anything with it. Yet, as the same keycode table can be used with other - * devices, a mask is provided to allow its usage. Drivers should generally - * leave this field in blank - * @priv: driver-specific data - * @keylock: protects the remaining members of the struct - * @keypressed: whether a key is currently pressed - * @keyup_jiffies: time (in jiffies) when the current keypress should be released - * @timer_keyup: timer for releasing a keypress - * @last_keycode: keycode of last keypress - * @last_scancode: scancode of last keypress - * @last_toggle: toggle value of last command - * @timeout: optional time after which device stops sending data - * @min_timeout: minimum timeout supported by device - * @max_timeout: maximum timeout supported by device - * @rx_resolution : resolution (in ns) of input sampler - * @tx_resolution: resolution (in ns) of output sampler - * @change_protocol: allow changing the protocol used on hardware decoders - * @open: callback to allow drivers to enable polling/irq when IR input device - * is opened. - * @close: callback to allow drivers to disable polling/irq when IR input device - * is opened. - * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs) - * @s_tx_carrier: set transmit carrier frequency - * @s_tx_duty_cycle: set transmit duty cycle (0% - 100%) - * @s_rx_carrier: inform driver about carrier it is expected to handle - * @tx_ir: transmit IR - * @s_idle: enable/disable hardware idle mode, upon which, - * device doesn't interrupt host until it sees IR pulses - * @s_learning_mode: enable wide band receiver used for learning - * @s_carrier_report: enable carrier reports - */ -struct rc_dev { - struct device dev; - const char *input_name; - const char *input_phys; - struct input_id input_id; - char *driver_name; - const char *map_name; - struct rc_map rc_map; - unsigned long devno; - struct ir_raw_event_ctrl *raw; - struct input_dev *input_dev; - enum rc_driver_type driver_type; - bool idle; - u64 allowed_protos; - u32 scanmask; - void *priv; - spinlock_t keylock; - bool keypressed; - unsigned long keyup_jiffies; - struct timer_list timer_keyup; - u32 last_keycode; - u32 last_scancode; - u8 last_toggle; - u32 timeout; - u32 min_timeout; - u32 max_timeout; - u32 rx_resolution; - u32 tx_resolution; - int (*change_protocol)(struct rc_dev *dev, u64 rc_type); - int (*open)(struct rc_dev *dev); - void (*close)(struct rc_dev *dev); - int (*s_tx_mask)(struct rc_dev *dev, u32 mask); - int (*s_tx_carrier)(struct rc_dev *dev, u32 carrier); - int (*s_tx_duty_cycle)(struct rc_dev *dev, u32 duty_cycle); - int (*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max); - int (*tx_ir)(struct rc_dev *dev, int *txbuf, u32 n); - void (*s_idle)(struct rc_dev *dev, bool enable); - int (*s_learning_mode)(struct rc_dev *dev, int enable); - int (*s_carrier_report) (struct rc_dev *dev, int enable); -}; - -#define to_rc_dev(d) container_of(d, struct rc_dev, dev) - -/* - * From rc-main.c - * Those functions can be used on any type of Remote Controller. They - * basically creates an input_dev and properly reports the device as a - * Remote Controller, at sys/class/rc. - */ - -struct rc_dev *rc_allocate_device(void); -void rc_free_device(struct rc_dev *dev); -int rc_register_device(struct rc_dev *dev); -void rc_unregister_device(struct rc_dev *dev); - -void rc_repeat(struct rc_dev *dev); -void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle); -void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle); -void rc_keyup(struct rc_dev *dev); -u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode); - -/* - * From rc-raw.c - * The Raw interface is specific to InfraRed. It may be a good idea to - * split it later into a separate header. - */ - -enum raw_event_type { - IR_SPACE = (1 << 0), - IR_PULSE = (1 << 1), - IR_START_EVENT = (1 << 2), - IR_STOP_EVENT = (1 << 3), -}; - -struct ir_raw_event { - union { - u32 duration; - - struct { - u32 carrier; - u8 duty_cycle; - }; - }; - - unsigned pulse:1; - unsigned reset:1; - unsigned timeout:1; - unsigned carrier_report:1; -}; - -#define DEFINE_IR_RAW_EVENT(event) \ - struct ir_raw_event event = { \ - { .duration = 0 } , \ - .pulse = 0, \ - .reset = 0, \ - .timeout = 0, \ - .carrier_report = 0 } - -static inline void init_ir_raw_event(struct ir_raw_event *ev) -{ - memset(ev, 0, sizeof(*ev)); -} - -#define IR_MAX_DURATION 0xFFFFFFFF /* a bit more than 4 seconds */ -#define US_TO_NS(usec) ((usec) * 1000) -#define MS_TO_US(msec) ((msec) * 1000) -#define MS_TO_NS(msec) ((msec) * 1000 * 1000) - -void ir_raw_event_handle(struct rc_dev *dev); -int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev); -int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type); -int ir_raw_event_store_with_filter(struct rc_dev *dev, - struct ir_raw_event *ev); -void ir_raw_event_set_idle(struct rc_dev *dev, bool idle); - -static inline void ir_raw_event_reset(struct rc_dev *dev) -{ - DEFINE_IR_RAW_EVENT(ev); - ev.reset = true; - - ir_raw_event_store(dev, &ev); - ir_raw_event_handle(dev); -} - -/* extract mask bits out of data and pack them into the result */ -static inline u32 ir_extract_bits(u32 data, u32 mask) -{ - u32 vbit = 1, value = 0; - - do { - if (mask & 1) { - if (data & 1) - value |= vbit; - vbit <<= 1; - } - data >>= 1; - } while (mask >>= 1); - - return value; -} - -#endif /* _RC_CORE */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/rc-map.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/rc-map.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/rc-map.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/rc-map.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,152 +0,0 @@ -/* - * rc-map.h - define RC map names used by RC drivers - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * 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, or - * (at your option) any later version. - */ - -#include - -#define RC_TYPE_UNKNOWN 0 -#define RC_TYPE_RC5 (1 << 0) /* Philips RC5 protocol */ -#define RC_TYPE_NEC (1 << 1) -#define RC_TYPE_RC6 (1 << 2) /* Philips RC6 protocol */ -#define RC_TYPE_JVC (1 << 3) /* JVC protocol */ -#define RC_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */ -#define RC_TYPE_RC5_SZ (1 << 5) /* RC5 variant used by Streamzap */ -#define RC_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */ -#define RC_TYPE_OTHER (1u << 31) - -#define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC | RC_TYPE_RC6 | \ - RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \ - RC_TYPE_RC5_SZ | RC_TYPE_OTHER) - -struct rc_map_table { - u32 scancode; - u32 keycode; -}; - -struct rc_map { - struct rc_map_table *scan; - unsigned int size; /* Max number of entries */ - unsigned int len; /* Used number of entries */ - unsigned int alloc; /* Size of *scan in bytes */ - u64 rc_type; - const char *name; - spinlock_t lock; -}; - -struct rc_map_list { - struct list_head list; - struct rc_map map; -}; - -/* Routines from rc-map.c */ - -int rc_map_register(struct rc_map_list *map); -void rc_map_unregister(struct rc_map_list *map); -struct rc_map *rc_map_get(const char *name); -void rc_map_init(void); - -/* Names of the several keytables defined in-kernel */ - -#define RC_MAP_ADSTECH_DVB_T_PCI "rc-adstech-dvb-t-pci" -#define RC_MAP_ALINK_DTU_M "rc-alink-dtu-m" -#define RC_MAP_ANYSEE "rc-anysee" -#define RC_MAP_APAC_VIEWCOMP "rc-apac-viewcomp" -#define RC_MAP_ASUS_PC39 "rc-asus-pc39" -#define RC_MAP_ATI_TV_WONDER_HD_600 "rc-ati-tv-wonder-hd-600" -#define RC_MAP_AVERMEDIA_A16D "rc-avermedia-a16d" -#define RC_MAP_AVERMEDIA_CARDBUS "rc-avermedia-cardbus" -#define RC_MAP_AVERMEDIA_DVBT "rc-avermedia-dvbt" -#define RC_MAP_AVERMEDIA_M135A "rc-avermedia-m135a" -#define RC_MAP_AVERMEDIA_M733A_RM_K6 "rc-avermedia-m733a-rm-k6" -#define RC_MAP_AVERMEDIA_RM_KS "rc-avermedia-rm-ks" -#define RC_MAP_AVERMEDIA "rc-avermedia" -#define RC_MAP_AVERTV_303 "rc-avertv-303" -#define RC_MAP_AZUREWAVE_AD_TU700 "rc-azurewave-ad-tu700" -#define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus" -#define RC_MAP_BEHOLD "rc-behold" -#define RC_MAP_BUDGET_CI_OLD "rc-budget-ci-old" -#define RC_MAP_CINERGY_1400 "rc-cinergy-1400" -#define RC_MAP_CINERGY "rc-cinergy" -#define RC_MAP_DIB0700_NEC_TABLE "rc-dib0700-nec" -#define RC_MAP_DIB0700_RC5_TABLE "rc-dib0700-rc5" -#define RC_MAP_DIGITALNOW_TINYTWIN "rc-digitalnow-tinytwin" -#define RC_MAP_DIGITTRADE "rc-digittrade" -#define RC_MAP_DM1105_NEC "rc-dm1105-nec" -#define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro" -#define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t" -#define RC_MAP_EMPTY "rc-empty" -#define RC_MAP_EM_TERRATEC "rc-em-terratec" -#define RC_MAP_ENCORE_ENLTV2 "rc-encore-enltv2" -#define RC_MAP_ENCORE_ENLTV_FM53 "rc-encore-enltv-fm53" -#define RC_MAP_ENCORE_ENLTV "rc-encore-enltv" -#define RC_MAP_EVGA_INDTUBE "rc-evga-indtube" -#define RC_MAP_EZTV "rc-eztv" -#define RC_MAP_FLYDVB "rc-flydvb" -#define RC_MAP_FLYVIDEO "rc-flyvideo" -#define RC_MAP_FUSIONHDTV_MCE "rc-fusionhdtv-mce" -#define RC_MAP_GADMEI_RM008Z "rc-gadmei-rm008z" -#define RC_MAP_GENIUS_TVGO_A11MCE "rc-genius-tvgo-a11mce" -#define RC_MAP_GOTVIEW7135 "rc-gotview7135" -#define RC_MAP_HAUPPAUGE_NEW "rc-hauppauge" -#define RC_MAP_IMON_MCE "rc-imon-mce" -#define RC_MAP_IMON_PAD "rc-imon-pad" -#define RC_MAP_IODATA_BCTV7E "rc-iodata-bctv7e" -#define RC_MAP_KAIOMY "rc-kaiomy" -#define RC_MAP_KWORLD_315U "rc-kworld-315u" -#define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog" -#define RC_MAP_LEADTEK_Y04G0051 "rc-leadtek-y04g0051" -#define RC_MAP_LIRC "rc-lirc" -#define RC_MAP_LME2510 "rc-lme2510" -#define RC_MAP_MANLI "rc-manli" -#define RC_MAP_MSI_DIGIVOX_II "rc-msi-digivox-ii" -#define RC_MAP_MSI_DIGIVOX_III "rc-msi-digivox-iii" -#define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus" -#define RC_MAP_MSI_TVANYWHERE "rc-msi-tvanywhere" -#define RC_MAP_NEBULA "rc-nebula" -#define RC_MAP_NEC_TERRATEC_CINERGY_XS "rc-nec-terratec-cinergy-xs" -#define RC_MAP_NORWOOD "rc-norwood" -#define RC_MAP_NPGTECH "rc-npgtech" -#define RC_MAP_PCTV_SEDNA "rc-pctv-sedna" -#define RC_MAP_PINNACLE_COLOR "rc-pinnacle-color" -#define RC_MAP_PINNACLE_GREY "rc-pinnacle-grey" -#define RC_MAP_PINNACLE_PCTV_HD "rc-pinnacle-pctv-hd" -#define RC_MAP_PIXELVIEW_NEW "rc-pixelview-new" -#define RC_MAP_PIXELVIEW "rc-pixelview" -#define RC_MAP_PIXELVIEW_002T "rc-pixelview-002t" -#define RC_MAP_PIXELVIEW_MK12 "rc-pixelview-mk12" -#define RC_MAP_POWERCOLOR_REAL_ANGEL "rc-powercolor-real-angel" -#define RC_MAP_PROTEUS_2309 "rc-proteus-2309" -#define RC_MAP_PURPLETV "rc-purpletv" -#define RC_MAP_PV951 "rc-pv951" -#define RC_MAP_HAUPPAUGE "rc-hauppauge" -#define RC_MAP_RC5_TV "rc-rc5-tv" -#define RC_MAP_RC6_MCE "rc-rc6-mce" -#define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" -#define RC_MAP_STREAMZAP "rc-streamzap" -#define RC_MAP_TBS_NEC "rc-tbs-nec" -#define RC_MAP_TECHNISAT_USB2 "rc-technisat-usb2" -#define RC_MAP_TERRATEC_CINERGY_XS "rc-terratec-cinergy-xs" -#define RC_MAP_TERRATEC_SLIM "rc-terratec-slim" -#define RC_MAP_TERRATEC_SLIM_2 "rc-terratec-slim-2" -#define RC_MAP_TEVII_NEC "rc-tevii-nec" -#define RC_MAP_TOTAL_MEDIA_IN_HAND "rc-total-media-in-hand" -#define RC_MAP_TREKSTOR "rc-trekstor" -#define RC_MAP_TT_1500 "rc-tt-1500" -#define RC_MAP_TWINHAN_VP1027_DVBS "rc-twinhan1027" -#define RC_MAP_VIDEOMATE_M1F "rc-videomate-m1f" -#define RC_MAP_VIDEOMATE_S350 "rc-videomate-s350" -#define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr" -#define RC_MAP_WINFAST "rc-winfast" -#define RC_MAP_WINFAST_USBII_DELUXE "rc-winfast-usbii-deluxe" - -/* - * Please, do not just append newer Remote Controller names at the end. - * The names should be ordered in alphabetical order - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/rj54n1cb0c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/rj54n1cb0c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/rj54n1cb0c.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/rj54n1cb0c.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -/* - * RJ54N1CB0C Private data - * - * Copyright (C) 2009, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __RJ54N1CB0C_H__ -#define __RJ54N1CB0C_H__ - -struct rj54n1_pdata { - unsigned int mclk_freq; - bool ioctl_high; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/s5p_fimc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/s5p_fimc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/s5p_fimc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/s5p_fimc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* - * Samsung S5P SoC camera interface driver header - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd - * Author: Sylwester Nawrocki, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef S5P_FIMC_H_ -#define S5P_FIMC_H_ - -enum cam_bus_type { - FIMC_ITU_601 = 1, - FIMC_ITU_656, - FIMC_MIPI_CSI2, - FIMC_LCD_WB, /* FIFO link from LCD mixer */ -}; - -#define FIMC_CLK_INV_PCLK (1 << 0) -#define FIMC_CLK_INV_VSYNC (1 << 1) -#define FIMC_CLK_INV_HREF (1 << 2) -#define FIMC_CLK_INV_HSYNC (1 << 3) - -struct i2c_board_info; - -/** - * struct s5p_fimc_isp_info - image sensor information required for host - * interace configuration. - * - * @board_info: pointer to I2C subdevice's board info - * @clk_frequency: frequency of the clock the host interface provides to sensor - * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc. - * @csi_data_align: MIPI-CSI interface data alignment in bits - * @i2c_bus_num: i2c control bus id the sensor is attached to - * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU) - * @flags: flags defining bus signals polarity inversion (High by default) - */ -struct s5p_fimc_isp_info { - struct i2c_board_info *board_info; - unsigned long clk_frequency; - enum cam_bus_type bus_type; - u16 csi_data_align; - u16 i2c_bus_num; - u16 mux_id; - u16 flags; -}; - -/** - * struct s5p_platform_fimc - camera host interface platform data - * - * @isp_info: properties of camera sensor required for host interface setup - * @num_clients: the number of attached image sensors - */ -struct s5p_platform_fimc { - struct s5p_fimc_isp_info *isp_info; - int num_clients; -}; -#endif /* S5P_FIMC_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa6588.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa6588.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa6588.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa6588.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* - - Types and defines needed for RDS. This is included by - saa6588.c and every driver (e.g. bttv-driver.c) that wants - to use the saa6588 module. - - (c) 2005 by Hans J. Koch - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef _SAA6588_H -#define _SAA6588_H - -struct saa6588_command { - unsigned int block_count; - int result; - unsigned char __user *buffer; - struct file *instance; - poll_table *event_list; -}; - -/* These ioctls are internal to the kernel */ -#define SAA6588_CMD_OPEN _IOW('R', 1, int) -#define SAA6588_CMD_CLOSE _IOW('R', 2, int) -#define SAA6588_CMD_READ _IOR('R', 3, int) -#define SAA6588_CMD_POLL _IOR('R', 4, int) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa6752hs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa6752hs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa6752hs.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa6752hs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -/* - saa6752hs.h - definition for saa6752hs MPEG encoder - - Copyright (C) 2003 Andrew de Quincey - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7115.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7115.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7115.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7115.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* - saa7115.h - definition for saa7111/3/4/5 inputs and frequency flags - - Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _SAA7115_H_ -#define _SAA7115_H_ - -/* SAA7111/3/4/5 HW inputs */ -#define SAA7115_COMPOSITE0 0 -#define SAA7115_COMPOSITE1 1 -#define SAA7115_COMPOSITE2 2 -#define SAA7115_COMPOSITE3 3 -#define SAA7115_COMPOSITE4 4 /* not available for the saa7111/3 */ -#define SAA7115_COMPOSITE5 5 /* not available for the saa7111/3 */ -#define SAA7115_SVIDEO0 6 -#define SAA7115_SVIDEO1 7 -#define SAA7115_SVIDEO2 8 -#define SAA7115_SVIDEO3 9 - -/* SAA7115 v4l2_crystal_freq frequency values */ -#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */ -#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */ - -/* SAA7115 v4l2_crystal_freq audio clock control flags */ -#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */ -#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */ -#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */ - -#define SAA7115_IPORT_ON 1 -#define SAA7115_IPORT_OFF 0 - -/* SAA7111 specific output flags */ -#define SAA7111_VBI_BYPASS 2 -#define SAA7111_FMT_YUV422 0x00 -#define SAA7111_FMT_RGB 0x40 -#define SAA7111_FMT_CCIR 0x80 -#define SAA7111_FMT_YUV411 0xc0 - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7127.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7127.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7127.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7127.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -/* - saa7127.h - definition for saa7126/7/8/9 inputs/outputs - - Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _SAA7127_H_ -#define _SAA7127_H_ - -/* Enumeration for the supported input types */ -enum saa7127_input_type { - SAA7127_INPUT_TYPE_NORMAL, - SAA7127_INPUT_TYPE_TEST_IMAGE -}; - -/* Enumeration for the supported output signal types */ -enum saa7127_output_type { - SAA7127_OUTPUT_TYPE_BOTH, - SAA7127_OUTPUT_TYPE_COMPOSITE, - SAA7127_OUTPUT_TYPE_SVIDEO, - SAA7127_OUTPUT_TYPE_RGB, - SAA7127_OUTPUT_TYPE_YUV_C, - SAA7127_OUTPUT_TYPE_YUV_V -}; - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7146.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7146.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7146.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7146.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,466 +0,0 @@ -#ifndef __SAA7146__ -#define __SAA7146__ - -#include /* for module-version */ -#include /* for delay-stuff */ -#include /* for kmalloc/kfree */ -#include /* for pci-config-stuff, vendor ids etc. */ -#include /* for "__init" */ -#include /* for IMMEDIATE_BH */ -#include /* for kernel module loader */ -#include /* for i2c subsystem */ -#include /* for accessing devices */ -#include -#include -#include -#include - -#include /* for vmalloc() */ -#include /* for vmalloc_to_page() */ - -#define SAA7146_VERSION_CODE 0x000600 /* 0.6.0 */ - -#define saa7146_write(sxy,adr,dat) writel((dat),(sxy->mem+(adr))) -#define saa7146_read(sxy,adr) readl(sxy->mem+(adr)) - -extern unsigned int saa7146_debug; - -//#define DEBUG_PROLOG printk("(0x%08x)(0x%08x) %s: %s(): ",(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,RPS_ADDR0))),(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,IER))),KBUILD_MODNAME,__func__) - -#ifndef DEBUG_VARIABLE - #define DEBUG_VARIABLE saa7146_debug -#endif - -#define DEBUG_PROLOG printk("%s: %s(): ",KBUILD_MODNAME, __func__) -#define INFO(x) { printk("%s: ",KBUILD_MODNAME); printk x; } - -#define ERR(x) { DEBUG_PROLOG; printk x; } - -#define DEB_S(x) if (0!=(DEBUG_VARIABLE&0x01)) { DEBUG_PROLOG; printk x; } /* simple debug messages */ -#define DEB_D(x) if (0!=(DEBUG_VARIABLE&0x02)) { DEBUG_PROLOG; printk x; } /* more detailed debug messages */ -#define DEB_EE(x) if (0!=(DEBUG_VARIABLE&0x04)) { DEBUG_PROLOG; printk x; } /* print enter and exit of functions */ -#define DEB_I2C(x) if (0!=(DEBUG_VARIABLE&0x08)) { DEBUG_PROLOG; printk x; } /* i2c debug messages */ -#define DEB_VBI(x) if (0!=(DEBUG_VARIABLE&0x10)) { DEBUG_PROLOG; printk x; } /* vbi debug messages */ -#define DEB_INT(x) if (0!=(DEBUG_VARIABLE&0x20)) { DEBUG_PROLOG; printk x; } /* interrupt debug messages */ -#define DEB_CAP(x) if (0!=(DEBUG_VARIABLE&0x40)) { DEBUG_PROLOG; printk x; } /* capture debug messages */ - -#define SAA7146_ISR_CLEAR(x,y) \ - saa7146_write(x, ISR, (y)); - -struct saa7146_dev; -struct saa7146_extension; -struct saa7146_vv; - -/* saa7146 page table */ -struct saa7146_pgtable { - unsigned int size; - __le32 *cpu; - dma_addr_t dma; - /* used for offsets for u,v planes for planar capture modes */ - unsigned long offset; - /* used for custom pagetables (used for example by budget dvb cards) */ - struct scatterlist *slist; - int nents; -}; - -struct saa7146_pci_extension_data { - struct saa7146_extension *ext; - void *ext_priv; /* most likely a name string */ -}; - -#define MAKE_EXTENSION_PCI(x_var, x_vendor, x_device) \ - { \ - .vendor = PCI_VENDOR_ID_PHILIPS, \ - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, \ - .subvendor = x_vendor, \ - .subdevice = x_device, \ - .driver_data = (unsigned long)& x_var, \ - } - -struct saa7146_extension -{ - char name[32]; /* name of the device */ -#define SAA7146_USE_I2C_IRQ 0x1 -#define SAA7146_I2C_SHORT_DELAY 0x2 - int flags; - - /* pairs of subvendor and subdevice ids for - supported devices, last entry 0xffff, 0xfff */ - struct module *module; - struct pci_driver driver; - struct pci_device_id *pci_tbl; - - /* extension functions */ - int (*probe)(struct saa7146_dev *); - int (*attach)(struct saa7146_dev *, struct saa7146_pci_extension_data *); - int (*detach)(struct saa7146_dev*); - - u32 irq_mask; /* mask to indicate, which irq-events are handled by the extension */ - void (*irq_func)(struct saa7146_dev*, u32* irq_mask); -}; - -struct saa7146_dma -{ - dma_addr_t dma_handle; - __le32 *cpu_addr; -}; - -struct saa7146_dev -{ - struct module *module; - - struct list_head item; - - struct v4l2_device v4l2_dev; - - /* different device locks */ - spinlock_t slock; - struct mutex v4l2_lock; - - unsigned char __iomem *mem; /* pointer to mapped IO memory */ - u32 revision; /* chip revision; needed for bug-workarounds*/ - - /* pci-device & irq stuff*/ - char name[32]; - struct pci_dev *pci; - u32 int_todo; - spinlock_t int_slock; - - /* extension handling */ - struct saa7146_extension *ext; /* indicates if handled by extension */ - void *ext_priv; /* pointer for extension private use (most likely some private data) */ - struct saa7146_ext_vv *ext_vv_data; - - /* per device video/vbi informations (if available) */ - struct saa7146_vv *vv_data; - void (*vv_callback)(struct saa7146_dev *dev, unsigned long status); - - /* i2c-stuff */ - struct mutex i2c_lock; - - u32 i2c_bitrate; - struct saa7146_dma d_i2c; /* pointer to i2c memory */ - wait_queue_head_t i2c_wq; - int i2c_op; - - /* memories */ - struct saa7146_dma d_rps0; - struct saa7146_dma d_rps1; -}; - -static inline struct saa7146_dev *to_saa7146_dev(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct saa7146_dev, v4l2_dev); -} - -/* from saa7146_i2c.c */ -int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); - -/* from saa7146_core.c */ -extern struct list_head saa7146_devices; -extern struct mutex saa7146_devices_lock; -int saa7146_register_extension(struct saa7146_extension*); -int saa7146_unregister_extension(struct saa7146_extension*); -struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc); -int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt); -void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt); -int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length ); -void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt); -void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt); -void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data); -int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop); - -/* some memory sizes */ -#define SAA7146_I2C_MEM ( 1*PAGE_SIZE) -#define SAA7146_RPS_MEM ( 1*PAGE_SIZE) - -/* some i2c constants */ -#define SAA7146_I2C_TIMEOUT 100 /* i2c-timeout-value in ms */ -#define SAA7146_I2C_RETRIES 3 /* how many times shall we retry an i2c-operation? */ -#define SAA7146_I2C_DELAY 5 /* time we wait after certain i2c-operations */ - -/* unsorted defines */ -#define ME1 0x0000000800 -#define PV1 0x0000000008 - -/* gpio defines */ -#define SAA7146_GPIO_INPUT 0x00 -#define SAA7146_GPIO_IRQHI 0x10 -#define SAA7146_GPIO_IRQLO 0x20 -#define SAA7146_GPIO_IRQHL 0x30 -#define SAA7146_GPIO_OUTLO 0x40 -#define SAA7146_GPIO_OUTHI 0x50 - -/* debi defines */ -#define DEBINOSWAP 0x000e0000 - -/* define for the register programming sequencer (rps) */ -#define CMD_NOP 0x00000000 /* No operation */ -#define CMD_CLR_EVENT 0x00000000 /* Clear event */ -#define CMD_SET_EVENT 0x10000000 /* Set signal event */ -#define CMD_PAUSE 0x20000000 /* Pause */ -#define CMD_CHECK_LATE 0x30000000 /* Check late */ -#define CMD_UPLOAD 0x40000000 /* Upload */ -#define CMD_STOP 0x50000000 /* Stop */ -#define CMD_INTERRUPT 0x60000000 /* Interrupt */ -#define CMD_JUMP 0x80000000 /* Jump */ -#define CMD_WR_REG 0x90000000 /* Write (load) register */ -#define CMD_RD_REG 0xa0000000 /* Read (store) register */ -#define CMD_WR_REG_MASK 0xc0000000 /* Write register with mask */ - -#define CMD_OAN MASK_27 -#define CMD_INV MASK_26 -#define CMD_SIG4 MASK_25 -#define CMD_SIG3 MASK_24 -#define CMD_SIG2 MASK_23 -#define CMD_SIG1 MASK_22 -#define CMD_SIG0 MASK_21 -#define CMD_O_FID_B MASK_14 -#define CMD_E_FID_B MASK_13 -#define CMD_O_FID_A MASK_12 -#define CMD_E_FID_A MASK_11 - -/* some events and command modifiers for rps1 squarewave generator */ -#define EVT_HS (1<<15) // Source Line Threshold reached -#define EVT_VBI_B (1<<9) // VSYNC Event -#define RPS_OAN (1<<27) // 1: OR events, 0: AND events -#define RPS_INV (1<<26) // Invert (compound) event -#define GPIO3_MSK 0xFF000000 // GPIO #3 control bits - -/* Bit mask constants */ -#define MASK_00 0x00000001 /* Mask value for bit 0 */ -#define MASK_01 0x00000002 /* Mask value for bit 1 */ -#define MASK_02 0x00000004 /* Mask value for bit 2 */ -#define MASK_03 0x00000008 /* Mask value for bit 3 */ -#define MASK_04 0x00000010 /* Mask value for bit 4 */ -#define MASK_05 0x00000020 /* Mask value for bit 5 */ -#define MASK_06 0x00000040 /* Mask value for bit 6 */ -#define MASK_07 0x00000080 /* Mask value for bit 7 */ -#define MASK_08 0x00000100 /* Mask value for bit 8 */ -#define MASK_09 0x00000200 /* Mask value for bit 9 */ -#define MASK_10 0x00000400 /* Mask value for bit 10 */ -#define MASK_11 0x00000800 /* Mask value for bit 11 */ -#define MASK_12 0x00001000 /* Mask value for bit 12 */ -#define MASK_13 0x00002000 /* Mask value for bit 13 */ -#define MASK_14 0x00004000 /* Mask value for bit 14 */ -#define MASK_15 0x00008000 /* Mask value for bit 15 */ -#define MASK_16 0x00010000 /* Mask value for bit 16 */ -#define MASK_17 0x00020000 /* Mask value for bit 17 */ -#define MASK_18 0x00040000 /* Mask value for bit 18 */ -#define MASK_19 0x00080000 /* Mask value for bit 19 */ -#define MASK_20 0x00100000 /* Mask value for bit 20 */ -#define MASK_21 0x00200000 /* Mask value for bit 21 */ -#define MASK_22 0x00400000 /* Mask value for bit 22 */ -#define MASK_23 0x00800000 /* Mask value for bit 23 */ -#define MASK_24 0x01000000 /* Mask value for bit 24 */ -#define MASK_25 0x02000000 /* Mask value for bit 25 */ -#define MASK_26 0x04000000 /* Mask value for bit 26 */ -#define MASK_27 0x08000000 /* Mask value for bit 27 */ -#define MASK_28 0x10000000 /* Mask value for bit 28 */ -#define MASK_29 0x20000000 /* Mask value for bit 29 */ -#define MASK_30 0x40000000 /* Mask value for bit 30 */ -#define MASK_31 0x80000000 /* Mask value for bit 31 */ - -#define MASK_B0 0x000000ff /* Mask value for byte 0 */ -#define MASK_B1 0x0000ff00 /* Mask value for byte 1 */ -#define MASK_B2 0x00ff0000 /* Mask value for byte 2 */ -#define MASK_B3 0xff000000 /* Mask value for byte 3 */ - -#define MASK_W0 0x0000ffff /* Mask value for word 0 */ -#define MASK_W1 0xffff0000 /* Mask value for word 1 */ - -#define MASK_PA 0xfffffffc /* Mask value for physical address */ -#define MASK_PR 0xfffffffe /* Mask value for protection register */ -#define MASK_ER 0xffffffff /* Mask value for the entire register */ - -#define MASK_NONE 0x00000000 /* No mask */ - -/* register aliases */ -#define BASE_ODD1 0x00 /* Video DMA 1 registers */ -#define BASE_EVEN1 0x04 -#define PROT_ADDR1 0x08 -#define PITCH1 0x0C -#define BASE_PAGE1 0x10 /* Video DMA 1 base page */ -#define NUM_LINE_BYTE1 0x14 - -#define BASE_ODD2 0x18 /* Video DMA 2 registers */ -#define BASE_EVEN2 0x1C -#define PROT_ADDR2 0x20 -#define PITCH2 0x24 -#define BASE_PAGE2 0x28 /* Video DMA 2 base page */ -#define NUM_LINE_BYTE2 0x2C - -#define BASE_ODD3 0x30 /* Video DMA 3 registers */ -#define BASE_EVEN3 0x34 -#define PROT_ADDR3 0x38 -#define PITCH3 0x3C -#define BASE_PAGE3 0x40 /* Video DMA 3 base page */ -#define NUM_LINE_BYTE3 0x44 - -#define PCI_BT_V1 0x48 /* Video/FIFO 1 */ -#define PCI_BT_V2 0x49 /* Video/FIFO 2 */ -#define PCI_BT_V3 0x4A /* Video/FIFO 3 */ -#define PCI_BT_DEBI 0x4B /* DEBI */ -#define PCI_BT_A 0x4C /* Audio */ - -#define DD1_INIT 0x50 /* Init setting of DD1 interface */ - -#define DD1_STREAM_B 0x54 /* DD1 B video data stream handling */ -#define DD1_STREAM_A 0x56 /* DD1 A video data stream handling */ - -#define BRS_CTRL 0x58 /* BRS control register */ -#define HPS_CTRL 0x5C /* HPS control register */ -#define HPS_V_SCALE 0x60 /* HPS vertical scale */ -#define HPS_V_GAIN 0x64 /* HPS vertical ACL and gain */ -#define HPS_H_PRESCALE 0x68 /* HPS horizontal prescale */ -#define HPS_H_SCALE 0x6C /* HPS horizontal scale */ -#define BCS_CTRL 0x70 /* BCS control */ -#define CHROMA_KEY_RANGE 0x74 -#define CLIP_FORMAT_CTRL 0x78 /* HPS outputs formats & clipping */ - -#define DEBI_CONFIG 0x7C -#define DEBI_COMMAND 0x80 -#define DEBI_PAGE 0x84 -#define DEBI_AD 0x88 - -#define I2C_TRANSFER 0x8C -#define I2C_STATUS 0x90 - -#define BASE_A1_IN 0x94 /* Audio 1 input DMA */ -#define PROT_A1_IN 0x98 -#define PAGE_A1_IN 0x9C - -#define BASE_A1_OUT 0xA0 /* Audio 1 output DMA */ -#define PROT_A1_OUT 0xA4 -#define PAGE_A1_OUT 0xA8 - -#define BASE_A2_IN 0xAC /* Audio 2 input DMA */ -#define PROT_A2_IN 0xB0 -#define PAGE_A2_IN 0xB4 - -#define BASE_A2_OUT 0xB8 /* Audio 2 output DMA */ -#define PROT_A2_OUT 0xBC -#define PAGE_A2_OUT 0xC0 - -#define RPS_PAGE0 0xC4 /* RPS task 0 page register */ -#define RPS_PAGE1 0xC8 /* RPS task 1 page register */ - -#define RPS_THRESH0 0xCC /* HBI threshold for task 0 */ -#define RPS_THRESH1 0xD0 /* HBI threshold for task 1 */ - -#define RPS_TOV0 0xD4 /* RPS timeout for task 0 */ -#define RPS_TOV1 0xD8 /* RPS timeout for task 1 */ - -#define IER 0xDC /* Interrupt enable register */ - -#define GPIO_CTRL 0xE0 /* GPIO 0-3 register */ - -#define EC1SSR 0xE4 /* Event cnt set 1 source select */ -#define EC2SSR 0xE8 /* Event cnt set 2 source select */ -#define ECT1R 0xEC /* Event cnt set 1 thresholds */ -#define ECT2R 0xF0 /* Event cnt set 2 thresholds */ - -#define ACON1 0xF4 -#define ACON2 0xF8 - -#define MC1 0xFC /* Main control register 1 */ -#define MC2 0x100 /* Main control register 2 */ - -#define RPS_ADDR0 0x104 /* RPS task 0 address register */ -#define RPS_ADDR1 0x108 /* RPS task 1 address register */ - -#define ISR 0x10C /* Interrupt status register */ -#define PSR 0x110 /* Primary status register */ -#define SSR 0x114 /* Secondary status register */ - -#define EC1R 0x118 /* Event counter set 1 register */ -#define EC2R 0x11C /* Event counter set 2 register */ - -#define PCI_VDP1 0x120 /* Video DMA pointer of FIFO 1 */ -#define PCI_VDP2 0x124 /* Video DMA pointer of FIFO 2 */ -#define PCI_VDP3 0x128 /* Video DMA pointer of FIFO 3 */ -#define PCI_ADP1 0x12C /* Audio DMA pointer of audio out 1 */ -#define PCI_ADP2 0x130 /* Audio DMA pointer of audio in 1 */ -#define PCI_ADP3 0x134 /* Audio DMA pointer of audio out 2 */ -#define PCI_ADP4 0x138 /* Audio DMA pointer of audio in 2 */ -#define PCI_DMA_DDP 0x13C /* DEBI DMA pointer */ - -#define LEVEL_REP 0x140, -#define A_TIME_SLOT1 0x180, /* from 180 - 1BC */ -#define A_TIME_SLOT2 0x1C0, /* from 1C0 - 1FC */ - -/* isr masks */ -#define SPCI_PPEF 0x80000000 /* PCI parity error */ -#define SPCI_PABO 0x40000000 /* PCI access error (target or master abort) */ -#define SPCI_PPED 0x20000000 /* PCI parity error on 'real time data' */ -#define SPCI_RPS_I1 0x10000000 /* Interrupt issued by RPS1 */ -#define SPCI_RPS_I0 0x08000000 /* Interrupt issued by RPS0 */ -#define SPCI_RPS_LATE1 0x04000000 /* RPS task 1 is late */ -#define SPCI_RPS_LATE0 0x02000000 /* RPS task 0 is late */ -#define SPCI_RPS_E1 0x01000000 /* RPS error from task 1 */ -#define SPCI_RPS_E0 0x00800000 /* RPS error from task 0 */ -#define SPCI_RPS_TO1 0x00400000 /* RPS timeout task 1 */ -#define SPCI_RPS_TO0 0x00200000 /* RPS timeout task 0 */ -#define SPCI_UPLD 0x00100000 /* RPS in upload */ -#define SPCI_DEBI_S 0x00080000 /* DEBI status */ -#define SPCI_DEBI_E 0x00040000 /* DEBI error */ -#define SPCI_IIC_S 0x00020000 /* I2C status */ -#define SPCI_IIC_E 0x00010000 /* I2C error */ -#define SPCI_A2_IN 0x00008000 /* Audio 2 input DMA protection / limit */ -#define SPCI_A2_OUT 0x00004000 /* Audio 2 output DMA protection / limit */ -#define SPCI_A1_IN 0x00002000 /* Audio 1 input DMA protection / limit */ -#define SPCI_A1_OUT 0x00001000 /* Audio 1 output DMA protection / limit */ -#define SPCI_AFOU 0x00000800 /* Audio FIFO over- / underflow */ -#define SPCI_V_PE 0x00000400 /* Video protection address */ -#define SPCI_VFOU 0x00000200 /* Video FIFO over- / underflow */ -#define SPCI_FIDA 0x00000100 /* Field ID video port A */ -#define SPCI_FIDB 0x00000080 /* Field ID video port B */ -#define SPCI_PIN3 0x00000040 /* GPIO pin 3 */ -#define SPCI_PIN2 0x00000020 /* GPIO pin 2 */ -#define SPCI_PIN1 0x00000010 /* GPIO pin 1 */ -#define SPCI_PIN0 0x00000008 /* GPIO pin 0 */ -#define SPCI_ECS 0x00000004 /* Event counter 1, 2, 4, 5 */ -#define SPCI_EC3S 0x00000002 /* Event counter 3 */ -#define SPCI_EC0S 0x00000001 /* Event counter 0 */ - -/* i2c */ -#define SAA7146_I2C_ABORT (1<<7) -#define SAA7146_I2C_SPERR (1<<6) -#define SAA7146_I2C_APERR (1<<5) -#define SAA7146_I2C_DTERR (1<<4) -#define SAA7146_I2C_DRERR (1<<3) -#define SAA7146_I2C_AL (1<<2) -#define SAA7146_I2C_ERR (1<<1) -#define SAA7146_I2C_BUSY (1<<0) - -#define SAA7146_I2C_START (0x3) -#define SAA7146_I2C_CONT (0x2) -#define SAA7146_I2C_STOP (0x1) -#define SAA7146_I2C_NOP (0x0) - -#define SAA7146_I2C_BUS_BIT_RATE_6400 (0x500) -#define SAA7146_I2C_BUS_BIT_RATE_3200 (0x100) -#define SAA7146_I2C_BUS_BIT_RATE_480 (0x400) -#define SAA7146_I2C_BUS_BIT_RATE_320 (0x600) -#define SAA7146_I2C_BUS_BIT_RATE_240 (0x700) -#define SAA7146_I2C_BUS_BIT_RATE_120 (0x000) -#define SAA7146_I2C_BUS_BIT_RATE_80 (0x200) -#define SAA7146_I2C_BUS_BIT_RATE_60 (0x300) - -static inline void SAA7146_IER_DISABLE(struct saa7146_dev *x, unsigned y) -{ - unsigned long flags; - spin_lock_irqsave(&x->int_slock, flags); - saa7146_write(x, IER, saa7146_read(x, IER) & ~y); - spin_unlock_irqrestore(&x->int_slock, flags); -} - -static inline void SAA7146_IER_ENABLE(struct saa7146_dev *x, unsigned y) -{ - unsigned long flags; - spin_lock_irqsave(&x->int_slock, flags); - saa7146_write(x, IER, saa7146_read(x, IER) | y); - spin_unlock_irqrestore(&x->int_slock, flags); -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7146_vv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7146_vv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7146_vv.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/saa7146_vv.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,264 +0,0 @@ -#ifndef __SAA7146_VV__ -#define __SAA7146_VV__ - -#include -#include -#include -#include - -#define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */ -#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ - -#define WRITE_RPS0(x) do { \ - dev->d_rps0.cpu_addr[ count++ ] = cpu_to_le32(x); \ - } while (0); - -#define WRITE_RPS1(x) do { \ - dev->d_rps1.cpu_addr[ count++ ] = cpu_to_le32(x); \ - } while (0); - -struct saa7146_video_dma { - u32 base_odd; - u32 base_even; - u32 prot_addr; - u32 pitch; - u32 base_page; - u32 num_line_byte; -}; - -#define FORMAT_BYTE_SWAP 0x1 -#define FORMAT_IS_PLANAR 0x2 - -struct saa7146_format { - char *name; - u32 pixelformat; - u32 trans; - u8 depth; - u8 flags; - u8 swap; -}; - -struct saa7146_standard -{ - char *name; - v4l2_std_id id; - - int v_offset; /* number of lines of vertical offset before processing */ - int v_field; /* number of lines in a field for HPS to process */ - - int h_offset; /* horizontal offset of processing window */ - int h_pixels; /* number of horizontal pixels to process */ - - int v_max_out; - int h_max_out; -}; - -/* buffer for one video/vbi frame */ -struct saa7146_buf { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* saa7146 specific */ - struct v4l2_pix_format *fmt; - int (*activate)(struct saa7146_dev *dev, - struct saa7146_buf *buf, - struct saa7146_buf *next); - - /* page tables */ - struct saa7146_pgtable pt[3]; -}; - -struct saa7146_dmaqueue { - struct saa7146_dev *dev; - struct saa7146_buf *curr; - struct list_head queue; - struct timer_list timeout; -}; - -struct saa7146_overlay { - struct saa7146_fh *fh; - struct v4l2_window win; - struct v4l2_clip clips[16]; - int nclips; -}; - -/* per open data */ -struct saa7146_fh { - struct saa7146_dev *dev; - /* if this is a vbi or capture open */ - enum v4l2_buf_type type; - - /* video overlay */ - struct saa7146_overlay ov; - - /* video capture */ - struct videobuf_queue video_q; - struct v4l2_pix_format video_fmt; - - /* vbi capture */ - struct videobuf_queue vbi_q; - struct v4l2_vbi_format vbi_fmt; - struct timer_list vbi_read_timeout; - - unsigned int resources; /* resource management for device open */ -}; - -#define STATUS_OVERLAY 0x01 -#define STATUS_CAPTURE 0x02 - -struct saa7146_vv -{ - /* vbi capture */ - struct saa7146_dmaqueue vbi_q; - /* vbi workaround interrupt queue */ - wait_queue_head_t vbi_wq; - int vbi_fieldcount; - struct saa7146_fh *vbi_streaming; - - int video_status; - struct saa7146_fh *video_fh; - - /* video overlay */ - struct v4l2_framebuffer ov_fb; - struct saa7146_format *ov_fmt; - struct saa7146_overlay *ov_data; - struct saa7146_fh *ov_suspend; - - /* video capture */ - struct saa7146_dmaqueue video_q; - enum v4l2_field last_field; - - /* common: fixme? shouldn't this be in saa7146_fh? - (this leads to a more complicated question: shall the driver - store the different settings (for example S_INPUT) for every open - and restore it appropriately, or should all settings be common for - all opens? currently, we do the latter, like all other - drivers do... */ - struct saa7146_standard *standard; - - int vflip; - int hflip; - int current_hps_source; - int current_hps_sync; - - struct saa7146_dma d_clipping; /* pointer to clipping memory */ - - unsigned int resources; /* resource management for device */ -}; - -/* flags */ -#define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */ - -struct saa7146_ext_vv -{ - /* informations about the video capabilities of the device */ - int inputs; - int audios; - u32 capabilities; - int flags; - - /* additionally supported transmission standards */ - struct saa7146_standard *stds; - int num_stds; - int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *); - - /* the extension can override this */ - struct v4l2_ioctl_ops ops; - /* pointer to the saa7146 core ops */ - const struct v4l2_ioctl_ops *core_ops; - - struct v4l2_file_operations vbi_fops; -}; - -struct saa7146_use_ops { - void (*init)(struct saa7146_dev *, struct saa7146_vv *); - int(*open)(struct saa7146_dev *, struct file *); - void (*release)(struct saa7146_dev *, struct file *); - void (*irq_done)(struct saa7146_dev *, unsigned long status); - ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); -}; - -/* from saa7146_fops.c */ -int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, char *name, int type); -int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev); -void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, int state); -void saa7146_buffer_next(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,int vbi); -int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf); -void saa7146_buffer_timeout(unsigned long data); -void saa7146_dma_free(struct saa7146_dev* dev,struct videobuf_queue *q, - struct saa7146_buf *buf); - -int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv); -int saa7146_vv_release(struct saa7146_dev* dev); - -/* from saa7146_hlp.c */ -int saa7146_enable_overlay(struct saa7146_fh *fh); -void saa7146_disable_overlay(struct saa7146_fh *fh); - -void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next); -void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) ; -void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sync); -void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data); - -/* from saa7146_video.c */ -extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops; -extern struct saa7146_use_ops saa7146_video_uops; -int saa7146_start_preview(struct saa7146_fh *fh); -int saa7146_stop_preview(struct saa7146_fh *fh); -long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg); - -/* from saa7146_vbi.c */ -extern struct saa7146_use_ops saa7146_vbi_uops; - -/* resource management functions */ -int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit); -void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits); - -#define RESOURCE_DMA1_HPS 0x1 -#define RESOURCE_DMA2_CLP 0x2 -#define RESOURCE_DMA3_BRS 0x4 - -/* saa7146 source inputs */ -#define SAA7146_HPS_SOURCE_PORT_A 0x00 -#define SAA7146_HPS_SOURCE_PORT_B 0x01 -#define SAA7146_HPS_SOURCE_YPB_CPA 0x02 -#define SAA7146_HPS_SOURCE_YPA_CPB 0x03 - -/* sync inputs */ -#define SAA7146_HPS_SYNC_PORT_A 0x00 -#define SAA7146_HPS_SYNC_PORT_B 0x01 - -/* some memory sizes */ -/* max. 16 clipping rectangles */ -#define SAA7146_CLIPPING_MEM (16 * 4 * sizeof(u32)) - -/* some defines for the various clipping-modes */ -#define SAA7146_CLIPPING_RECT 0x4 -#define SAA7146_CLIPPING_RECT_INVERTED 0x5 -#define SAA7146_CLIPPING_MASK 0x6 -#define SAA7146_CLIPPING_MASK_INVERTED 0x7 - -/* output formats: each entry holds four informations */ -#define RGB08_COMPOSED 0x0217 /* composed is used in the sense of "not-planar" */ -/* this means: planar?=0, yuv2rgb-conversation-mode=2, dither=yes(=1), format-mode = 7 */ -#define RGB15_COMPOSED 0x0213 -#define RGB16_COMPOSED 0x0210 -#define RGB24_COMPOSED 0x0201 -#define RGB32_COMPOSED 0x0202 - -#define Y8 0x0006 -#define YUV411_COMPOSED 0x0003 -#define YUV422_COMPOSED 0x0000 -/* this means: planar?=1, yuv2rgb-conversion-mode=0, dither=no(=0), format-mode = b */ -#define YUV411_DECOMPOSED 0x100b -#define YUV422_DECOMPOSED 0x1009 -#define YUV420_DECOMPOSED 0x100a - -#define IS_PLANAR(x) (x & 0xf000) - -/* misc defines */ -#define SAA7146_NO_SWAP (0x0) -#define SAA7146_TWO_BYTE_SWAP (0x1) -#define SAA7146_FOUR_BYTE_SWAP (0x2) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_mobile_ceu.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_mobile_ceu.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_mobile_ceu.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_mobile_ceu.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -#ifndef __ASM_SH_MOBILE_CEU_H__ -#define __ASM_SH_MOBILE_CEU_H__ - -#define SH_CEU_FLAG_USE_8BIT_BUS (1 << 0) /* use 8bit bus width */ -#define SH_CEU_FLAG_USE_16BIT_BUS (1 << 1) /* use 16bit bus width */ -#define SH_CEU_FLAG_HSYNC_LOW (1 << 2) /* default High if possible */ -#define SH_CEU_FLAG_VSYNC_LOW (1 << 3) /* default High if possible */ - -struct device; - -struct sh_mobile_ceu_info { - unsigned long flags; - struct device *csi2_dev; -}; - -#endif /* __ASM_SH_MOBILE_CEU_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_mobile_csi2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_mobile_csi2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_mobile_csi2.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_mobile_csi2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * Driver header for the SH-Mobile MIPI CSI-2 unit - * - * Copyright (C) 2010, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef SH_MIPI_CSI -#define SH_MIPI_CSI - -enum sh_csi2_phy { - SH_CSI2_PHY_MAIN, - SH_CSI2_PHY_SUB, -}; - -enum sh_csi2_type { - SH_CSI2C, - SH_CSI2I, -}; - -#define SH_CSI2_CRC (1 << 0) -#define SH_CSI2_ECC (1 << 1) - -struct platform_device; - -struct sh_csi2_client_config { - enum sh_csi2_phy phy; - unsigned char lanes; /* bitmask[3:0] */ - unsigned char channel; /* 0..3 */ - struct platform_device *pdev; /* client platform device */ -}; - -struct sh_csi2_pdata { - enum sh_csi2_type type; - unsigned int flags; - struct sh_csi2_client_config *clients; - int num_clients; -}; - -struct device; -struct v4l2_device; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_vou.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_vou.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_vou.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/sh_vou.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - * SuperH Video Output Unit (VOU) driver header - * - * Copyright (C) 2010, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef SH_VOU_H -#define SH_VOU_H - -#include - -/* Bus flags */ -#define SH_VOU_PCLK_FALLING (1 << 0) -#define SH_VOU_HSYNC_LOW (1 << 1) -#define SH_VOU_VSYNC_LOW (1 << 2) - -enum sh_vou_bus_fmt { - SH_VOU_BUS_8BIT, - SH_VOU_BUS_16BIT, - SH_VOU_BUS_BT656, -}; - -struct sh_vou_pdata { - enum sh_vou_bus_fmt bus_fmt; - int i2c_adap; - struct i2c_board_info *board_info; - unsigned long flags; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/si4713.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/si4713.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/si4713.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/si4713.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/* - * include/media/si4713.h - * - * Board related data definitions for Si4713 i2c device driver. - * - * Copyright (c) 2009 Nokia Corporation - * Contact: Eduardo Valentin - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - */ - -#ifndef SI4713_H -#define SI4713_H - -/* The SI4713 I2C sensor chip has a fixed slave address of 0xc6 or 0x22. */ -#define SI4713_I2C_ADDR_BUSEN_HIGH 0x63 -#define SI4713_I2C_ADDR_BUSEN_LOW 0x11 - -/* - * Platform dependent definition - */ -struct si4713_platform_data { - int gpio_reset; /* < 0 if not used */ -}; - -/* - * Structure to query for Received Noise Level (RNL). - */ -struct si4713_rnl { - __u32 index; /* modulator index */ - __u32 frequency; /* frequency to peform rnl measurement */ - __s32 rnl; /* result of measurement in dBuV */ - __u32 reserved[4]; /* drivers and apps must init this to 0 */ -}; - -/* - * This is the ioctl number to query for rnl. Users must pass a - * struct si4713_rnl pointer specifying desired frequency in 'frequency' field - * following driver capabilities (i.e V4L2_TUNER_CAP_LOW). - * Driver must return measured value in the same struture, filling 'rnl' field. - */ -#define SI4713_IOC_MEASURE_RNL _IOWR('V', BASE_VIDIOC_PRIVATE + 0, \ - struct si4713_rnl) - -#endif /* ifndef SI4713_H*/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_camera.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_camera.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_camera.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_camera.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,324 +0,0 @@ -/* - * camera image capture (abstract) bus driver header - * - * Copyright (C) 2006, Sascha Hauer, Pengutronix - * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef SOC_CAMERA_H -#define SOC_CAMERA_H - -#include -#include -#include -#include -#include -#include -#include - -extern struct bus_type soc_camera_bus_type; - -struct file; - -struct soc_camera_device { - struct list_head list; - struct device dev; - struct device *pdev; /* Platform device */ - s32 user_width; - s32 user_height; - u32 bytesperline; /* for padding, zero if unused */ - u32 sizeimage; - enum v4l2_colorspace colorspace; - unsigned char iface; /* Host number */ - unsigned char devnum; /* Device number per host */ - struct soc_camera_sense *sense; /* See comment in struct definition */ - struct soc_camera_ops *ops; - struct video_device *vdev; - const struct soc_camera_format_xlate *current_fmt; - struct soc_camera_format_xlate *user_formats; - int num_user_formats; - enum v4l2_field field; /* Preserve field over close() */ - void *host_priv; /* Per-device host private data */ - /* soc_camera.c private count. Only accessed with .video_lock held */ - int use_count; - struct mutex video_lock; /* Protects device data */ - struct file *streamer; /* stream owner */ - union { - struct videobuf_queue vb_vidq; - struct vb2_queue vb2_vidq; - }; -}; - -struct soc_camera_host { - struct v4l2_device v4l2_dev; - struct list_head list; - unsigned char nr; /* Host number */ - void *priv; - const char *drv_name; - struct soc_camera_host_ops *ops; -}; - -struct soc_camera_host_ops { - struct module *owner; - int (*add)(struct soc_camera_device *); - void (*remove)(struct soc_camera_device *); - int (*suspend)(struct soc_camera_device *, pm_message_t); - int (*resume)(struct soc_camera_device *); - /* - * .get_formats() is called for each client device format, but - * .put_formats() is only called once. Further, if any of the calls to - * .get_formats() fail, .put_formats() will not be called at all, the - * failing .get_formats() must then clean up internally. - */ - int (*get_formats)(struct soc_camera_device *, unsigned int, - struct soc_camera_format_xlate *); - void (*put_formats)(struct soc_camera_device *); - int (*cropcap)(struct soc_camera_device *, struct v4l2_cropcap *); - int (*get_crop)(struct soc_camera_device *, struct v4l2_crop *); - int (*set_crop)(struct soc_camera_device *, struct v4l2_crop *); - int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *); - int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *); - void (*init_videobuf)(struct videobuf_queue *, - struct soc_camera_device *); - int (*init_videobuf2)(struct vb2_queue *, - struct soc_camera_device *); - int (*reqbufs)(struct soc_camera_device *, struct v4l2_requestbuffers *); - int (*querycap)(struct soc_camera_host *, struct v4l2_capability *); - int (*set_bus_param)(struct soc_camera_device *, __u32); - int (*get_ctrl)(struct soc_camera_device *, struct v4l2_control *); - int (*set_ctrl)(struct soc_camera_device *, struct v4l2_control *); - int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *); - int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *); - int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *); - unsigned int (*poll)(struct file *, poll_table *); - const struct v4l2_queryctrl *controls; - int num_controls; -}; - -#define SOCAM_SENSOR_INVERT_PCLK (1 << 0) -#define SOCAM_SENSOR_INVERT_MCLK (1 << 1) -#define SOCAM_SENSOR_INVERT_HSYNC (1 << 2) -#define SOCAM_SENSOR_INVERT_VSYNC (1 << 3) -#define SOCAM_SENSOR_INVERT_DATA (1 << 4) - -struct i2c_board_info; -struct regulator_bulk_data; - -struct soc_camera_link { - /* Camera bus id, used to match a camera and a bus */ - int bus_id; - /* Per camera SOCAM_SENSOR_* bus flags */ - unsigned long flags; - int i2c_adapter_id; - struct i2c_board_info *board_info; - const char *module_name; - void *priv; - - /* Optional regulators that have to be managed on power on/off events */ - struct regulator_bulk_data *regulators; - int num_regulators; - - /* - * For non-I2C devices platform platform has to provide methods to - * add a device to the system and to remove - */ - int (*add_device)(struct soc_camera_link *, struct device *); - void (*del_device)(struct soc_camera_link *); - /* Optional callbacks to power on or off and reset the sensor */ - int (*power)(struct device *, int); - int (*reset)(struct device *); - /* - * some platforms may support different data widths than the sensors - * native ones due to different data line routing. Let the board code - * overwrite the width flags. - */ - int (*set_bus_param)(struct soc_camera_link *, unsigned long flags); - unsigned long (*query_bus_param)(struct soc_camera_link *); - void (*free_bus)(struct soc_camera_link *); -}; - -static inline struct soc_camera_device *to_soc_camera_dev( - const struct device *dev) -{ - return container_of(dev, struct soc_camera_device, dev); -} - -static inline struct soc_camera_host *to_soc_camera_host( - const struct device *dev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); - - return container_of(v4l2_dev, struct soc_camera_host, v4l2_dev); -} - -static inline struct soc_camera_link *to_soc_camera_link( - const struct soc_camera_device *icd) -{ - return icd->dev.platform_data; -} - -static inline struct device *to_soc_camera_control( - const struct soc_camera_device *icd) -{ - return dev_get_drvdata(&icd->dev); -} - -static inline struct v4l2_subdev *soc_camera_to_subdev( - const struct soc_camera_device *icd) -{ - struct device *control = to_soc_camera_control(icd); - return dev_get_drvdata(control); -} - -int soc_camera_host_register(struct soc_camera_host *ici); -void soc_camera_host_unregister(struct soc_camera_host *ici); - -const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( - struct soc_camera_device *icd, unsigned int fourcc); - -/** - * struct soc_camera_format_xlate - match between host and sensor formats - * @code: code of a sensor provided format - * @host_fmt: host format after host translation from code - * - * Host and sensor translation structure. Used in table of host and sensor - * formats matchings in soc_camera_device. A host can override the generic list - * generation by implementing get_formats(), and use it for format checks and - * format setup. - */ -struct soc_camera_format_xlate { - enum v4l2_mbus_pixelcode code; - const struct soc_mbus_pixelfmt *host_fmt; -}; - -struct soc_camera_ops { - int (*suspend)(struct soc_camera_device *, pm_message_t state); - int (*resume)(struct soc_camera_device *); - unsigned long (*query_bus_param)(struct soc_camera_device *); - int (*set_bus_param)(struct soc_camera_device *, unsigned long); - int (*enum_input)(struct soc_camera_device *, struct v4l2_input *); - const struct v4l2_queryctrl *controls; - int num_controls; -}; - -#define SOCAM_SENSE_PCLK_CHANGED (1 << 0) - -/** - * This struct can be attached to struct soc_camera_device by the host driver - * to request sense from the camera, for example, when calling .set_fmt(). The - * host then can check which flags are set and verify respective values if any. - * For example, if SOCAM_SENSE_PCLK_CHANGED is set, it means, pixclock has - * changed during this operation. After completion the host should detach sense. - * - * @flags ored SOCAM_SENSE_* flags - * @master_clock if the host wants to be informed about pixel-clock - * change, it better set master_clock. - * @pixel_clock_max maximum pixel clock frequency supported by the host, - * camera is not allowed to exceed this. - * @pixel_clock if the camera driver changed pixel clock during this - * operation, it sets SOCAM_SENSE_PCLK_CHANGED, uses - * master_clock to calculate the new pixel-clock and - * sets this field. - */ -struct soc_camera_sense { - unsigned long flags; - unsigned long master_clock; - unsigned long pixel_clock_max; - unsigned long pixel_clock; -}; - -static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( - struct soc_camera_ops *ops, int id) -{ - int i; - - for (i = 0; i < ops->num_controls; i++) - if (ops->controls[i].id == id) - return &ops->controls[i]; - - return NULL; -} - -#define SOCAM_MASTER (1 << 0) -#define SOCAM_SLAVE (1 << 1) -#define SOCAM_HSYNC_ACTIVE_HIGH (1 << 2) -#define SOCAM_HSYNC_ACTIVE_LOW (1 << 3) -#define SOCAM_VSYNC_ACTIVE_HIGH (1 << 4) -#define SOCAM_VSYNC_ACTIVE_LOW (1 << 5) -#define SOCAM_DATAWIDTH_4 (1 << 6) -#define SOCAM_DATAWIDTH_8 (1 << 7) -#define SOCAM_DATAWIDTH_9 (1 << 8) -#define SOCAM_DATAWIDTH_10 (1 << 9) -#define SOCAM_DATAWIDTH_15 (1 << 10) -#define SOCAM_DATAWIDTH_16 (1 << 11) -#define SOCAM_PCLK_SAMPLE_RISING (1 << 12) -#define SOCAM_PCLK_SAMPLE_FALLING (1 << 13) -#define SOCAM_DATA_ACTIVE_HIGH (1 << 14) -#define SOCAM_DATA_ACTIVE_LOW (1 << 15) - -#define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \ - SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \ - SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_16) - -static inline unsigned long soc_camera_bus_param_compatible( - unsigned long camera_flags, unsigned long bus_flags) -{ - unsigned long common_flags, hsync, vsync, pclk, data, buswidth, mode; - - common_flags = camera_flags & bus_flags; - - hsync = common_flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW); - vsync = common_flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW); - pclk = common_flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING); - data = common_flags & (SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW); - mode = common_flags & (SOCAM_MASTER | SOCAM_SLAVE); - buswidth = common_flags & SOCAM_DATAWIDTH_MASK; - - return (!hsync || !vsync || !pclk || !data || !mode || !buswidth) ? 0 : - common_flags; -} - -static inline void soc_camera_limit_side(int *start, int *length, - unsigned int start_min, - unsigned int length_min, unsigned int length_max) -{ - if (*length < length_min) - *length = length_min; - else if (*length > length_max) - *length = length_max; - - if (*start < start_min) - *start = start_min; - else if (*start > start_min + length_max - *length) - *start = start_min + length_max - *length; -} - -extern unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, - unsigned long flags); - -/* This is only temporary here - until v4l2-subdev begins to link to video_device */ -#include -static inline struct video_device *soc_camera_i2c_to_vdev(struct i2c_client *client) -{ - struct soc_camera_device *icd = client->dev.platform_data; - return icd->vdev; -} - -static inline struct soc_camera_device *soc_camera_from_vb2q(struct vb2_queue *vq) -{ - return container_of(vq, struct soc_camera_device, vb2_vidq); -} - -static inline struct soc_camera_device *soc_camera_from_vbq(struct videobuf_queue *vq) -{ - return container_of(vq, struct soc_camera_device, vb_vidq); -} - -void soc_camera_lock(struct vb2_queue *vq); -void soc_camera_unlock(struct vb2_queue *vq); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_camera_platform.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_camera_platform.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_camera_platform.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_camera_platform.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -/* - * Generic Platform Camera Driver Header - * - * Copyright (C) 2008 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __SOC_CAMERA_H__ -#define __SOC_CAMERA_H__ - -#include -#include - -struct device; - -struct soc_camera_platform_info { - const char *format_name; - unsigned long format_depth; - struct v4l2_mbus_framefmt format; - unsigned long bus_param; - struct device *dev; - int (*set_capture)(struct soc_camera_platform_info *info, int enable); -}; - -#endif /* __SOC_CAMERA_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_mediabus.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_mediabus.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_mediabus.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/soc_mediabus.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -/* - * SoC-camera Media Bus API extensions - * - * Copyright (C) 2009, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef SOC_MEDIABUS_H -#define SOC_MEDIABUS_H - -#include -#include - -/** - * enum soc_mbus_packing - data packing types on the media-bus - * @SOC_MBUS_PACKING_NONE: no packing, bit-for-bit transfer to RAM - * @SOC_MBUS_PACKING_2X8_PADHI: 16 bits transferred in 2 8-bit samples, in the - * possibly incomplete byte high bits are padding - * @SOC_MBUS_PACKING_2X8_PADLO: as above, but low bits are padding - * @SOC_MBUS_PACKING_EXTEND16: sample width (e.g., 10 bits) has to be extended - * to 16 bits - */ -enum soc_mbus_packing { - SOC_MBUS_PACKING_NONE, - SOC_MBUS_PACKING_2X8_PADHI, - SOC_MBUS_PACKING_2X8_PADLO, - SOC_MBUS_PACKING_EXTEND16, -}; - -/** - * enum soc_mbus_order - sample order on the media bus - * @SOC_MBUS_ORDER_LE: least significant sample first - * @SOC_MBUS_ORDER_BE: most significant sample first - */ -enum soc_mbus_order { - SOC_MBUS_ORDER_LE, - SOC_MBUS_ORDER_BE, -}; - -/** - * struct soc_mbus_pixelfmt - Data format on the media bus - * @name: Name of the format - * @fourcc: Fourcc code, that will be obtained if the data is - * stored in memory in the following way: - * @packing: Type of sample-packing, that has to be used - * @order: Sample order when storing in memory - * @bits_per_sample: How many bits the bridge has to sample - */ -struct soc_mbus_pixelfmt { - const char *name; - u32 fourcc; - enum soc_mbus_packing packing; - enum soc_mbus_order order; - u8 bits_per_sample; -}; - -const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( - enum v4l2_mbus_pixelcode code); -s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf); -int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/sr030pc30.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/sr030pc30.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/sr030pc30.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/sr030pc30.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -/* - * Driver header for SR030PC30 camera sensor - * - * Copyright (c) 2010 Samsung Electronics, Co. Ltd - * Contact: Sylwester Nawrocki - * - * 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, or - * (at your option) any later version. - */ - -#ifndef SR030PC30_H -#define SR030PC30_H - -struct sr030pc30_platform_data { - unsigned long clk_rate; /* master clock frequency in Hz */ - int (*set_power)(struct device *dev, int on); -}; - -#endif /* SR030PC30_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/timb_radio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/timb_radio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/timb_radio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/timb_radio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* - * timb_radio.h Platform struct for the Timberdale radio driver - * Copyright (c) 2009 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _TIMB_RADIO_ -#define _TIMB_RADIO_ 1 - -#include - -struct timb_radio_platform_data { - int i2c_adapter; /* I2C adapter where the tuner and dsp are attached */ - struct { - struct i2c_board_info *info; - } tuner; - struct { - const char *module_name; - struct i2c_board_info *info; - } dsp; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/timb_video.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/timb_video.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/timb_video.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/timb_video.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - * timb_video.h Platform struct for the Timberdale video driver - * Copyright (c) 2009-2010 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _TIMB_VIDEO_ -#define _TIMB_VIDEO_ 1 - -#include - -struct timb_video_platform_data { - int dma_channel; - int i2c_adapter; /* The I2C adapter where the encoder is attached */ - struct { - const char *module_name; - struct i2c_board_info *info; - } encoder; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tuner.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tuner.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tuner.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tuner.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,193 +0,0 @@ -/* - tuner.h - definition for different tuners - - Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de) - minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _TUNER_H -#define _TUNER_H -#ifdef __KERNEL__ - -#include - -#define ADDR_UNSET (255) - -#define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */ -#define TUNER_PHILIPS_PAL_I 1 -#define TUNER_PHILIPS_NTSC 2 -#define TUNER_PHILIPS_SECAM 3 /* you must actively select B/G, L, L` */ - -#define TUNER_ABSENT 4 -#define TUNER_PHILIPS_PAL 5 -#define TUNER_TEMIC_NTSC 6 /* 4032 FY5 (3X 7004, 9498, 9789) */ -#define TUNER_TEMIC_PAL_I 7 /* 4062 FY5 (3X 8501, 9957) */ - -#define TUNER_TEMIC_4036FY5_NTSC 8 /* 4036 FY5 (3X 1223, 1981, 7686) */ -#define TUNER_ALPS_TSBH1_NTSC 9 -#define TUNER_ALPS_TSBE1_PAL 10 -#define TUNER_ALPS_TSBB5_PAL_I 11 - -#define TUNER_ALPS_TSBE5_PAL 12 -#define TUNER_ALPS_TSBC5_PAL 13 -#define TUNER_TEMIC_4006FH5_PAL 14 /* 4006 FH5 (3X 9500, 9501, 7291) */ -#define TUNER_ALPS_TSHC6_NTSC 15 - -#define TUNER_TEMIC_PAL_DK 16 /* 4016 FY5 (3X 1392, 1393) */ -#define TUNER_PHILIPS_NTSC_M 17 -#define TUNER_TEMIC_4066FY5_PAL_I 18 /* 4066 FY5 (3X 7032, 7035) */ -#define TUNER_TEMIC_4006FN5_MULTI_PAL 19 /* B/G, I and D/K autodetected (3X 7595, 7606, 7657) */ - -#define TUNER_TEMIC_4009FR5_PAL 20 /* incl. FM radio (3X 7607, 7488, 7711) */ -#define TUNER_TEMIC_4039FR5_NTSC 21 /* incl. FM radio (3X 7246, 7578, 7732) */ -#define TUNER_TEMIC_4046FM5 22 /* you must actively select B/G, D/K, I, L, L` ! (3X 7804, 7806, 8103, 8104) */ -#define TUNER_PHILIPS_PAL_DK 23 - -#define TUNER_PHILIPS_FQ1216ME 24 /* you must actively select B/G/D/K, I, L, L` */ -#define TUNER_LG_PAL_I_FM 25 -#define TUNER_LG_PAL_I 26 -#define TUNER_LG_NTSC_FM 27 - -#define TUNER_LG_PAL_FM 28 -#define TUNER_LG_PAL 29 -#define TUNER_TEMIC_4009FN5_MULTI_PAL_FM 30 /* B/G, I and D/K autodetected (3X 8155, 8160, 8163) */ -#define TUNER_SHARP_2U5JF5540_NTSC 31 - -#define TUNER_Samsung_PAL_TCPM9091PD27 32 -#define TUNER_MT2032 33 -#define TUNER_TEMIC_4106FH5 34 /* 4106 FH5 (3X 7808, 7865) */ -#define TUNER_TEMIC_4012FY5 35 /* 4012 FY5 (3X 0971, 1099) */ - -#define TUNER_TEMIC_4136FY5 36 /* 4136 FY5 (3X 7708, 7746) */ -#define TUNER_LG_PAL_NEW_TAPC 37 -#define TUNER_PHILIPS_FM1216ME_MK3 38 -#define TUNER_LG_NTSC_NEW_TAPC 39 - -#define TUNER_HITACHI_NTSC 40 -#define TUNER_PHILIPS_PAL_MK 41 -#define TUNER_PHILIPS_FCV1236D 42 -#define TUNER_PHILIPS_FM1236_MK3 43 - -#define TUNER_PHILIPS_4IN1 44 /* ATI TV Wonder Pro - Conexant */ -/* Microtune merged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */ -#define TUNER_MICROTUNE_4049FM5 45 -#define TUNER_PANASONIC_VP27 46 -#define TUNER_LG_NTSC_TAPE 47 - -#define TUNER_TNF_8831BGFF 48 -#define TUNER_MICROTUNE_4042FI5 49 /* DViCO FusionHDTV 3 Gold-Q - 4042 FI5 (3X 8147) */ -#define TUNER_TCL_2002N 50 -#define TUNER_PHILIPS_FM1256_IH3 51 - -#define TUNER_THOMSON_DTT7610 52 -#define TUNER_PHILIPS_FQ1286 53 -#define TUNER_PHILIPS_TDA8290 54 -#define TUNER_TCL_2002MB 55 /* Hauppauge PVR-150 PAL */ - -#define TUNER_PHILIPS_FQ1216AME_MK4 56 /* Hauppauge PVR-150 PAL */ -#define TUNER_PHILIPS_FQ1236A_MK4 57 /* Hauppauge PVR-500MCE NTSC */ -#define TUNER_YMEC_TVF_8531MF 58 -#define TUNER_YMEC_TVF_5533MF 59 /* Pixelview Pro Ultra NTSC */ - -#define TUNER_THOMSON_DTT761X 60 /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ -#define TUNER_TENA_9533_DI 61 -#define TUNER_TEA5767 62 /* Only FM Radio Tuner */ -#define TUNER_PHILIPS_FMD1216ME_MK3 63 - -#define TUNER_LG_TDVS_H06XF 64 /* TDVS H061F, H062F, H064F */ -#define TUNER_YMEC_TVF66T5_B_DFF 65 /* Acorp Y878F */ -#define TUNER_LG_TALN 66 -#define TUNER_PHILIPS_TD1316 67 - -#define TUNER_PHILIPS_TUV1236D 68 /* ATI HDTV Wonder */ -#define TUNER_TNF_5335MF 69 /* Sabrent Bt848 */ -#define TUNER_SAMSUNG_TCPN_2121P30A 70 /* Hauppauge PVR-500MCE NTSC */ -#define TUNER_XC2028 71 - -#define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */ -#define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */ -#define TUNER_TDA9887 74 /* This tuner should be used only internally */ -#define TUNER_TEA5761 75 /* Only FM Radio Tuner */ -#define TUNER_XC5000 76 /* Xceive Silicon Tuner */ -#define TUNER_TCL_MF02GIP_5N 77 /* TCL MF02GIP_5N */ -#define TUNER_PHILIPS_FMD1216MEX_MK3 78 -#define TUNER_PHILIPS_FM1216MK5 79 -#define TUNER_PHILIPS_FQ1216LME_MK3 80 /* Active loopthrough, no FM */ -#define TUNER_PARTSNIC_PTI_5NF05 81 -#define TUNER_PHILIPS_CU1216L 82 -#define TUNER_NXP_TDA18271 83 -#define TUNER_SONY_BTF_PXN01Z 84 -#define TUNER_PHILIPS_FQ1236_MK5 85 /* NTSC, TDA9885, no FM radio */ -#define TUNER_TENA_TNF_5337 86 - -/* tv card specific */ -#define TDA9887_PRESENT (1<<0) -#define TDA9887_PORT1_INACTIVE (1<<1) -#define TDA9887_PORT2_INACTIVE (1<<2) -#define TDA9887_QSS (1<<3) -#define TDA9887_INTERCARRIER (1<<4) -#define TDA9887_PORT1_ACTIVE (1<<5) -#define TDA9887_PORT2_ACTIVE (1<<6) -#define TDA9887_INTERCARRIER_NTSC (1<<7) -/* Tuner takeover point adjustment, in dB, -16 <= top <= 15 */ -#define TDA9887_TOP_MASK (0x3f << 8) -#define TDA9887_TOP_SET (1 << 13) -#define TDA9887_TOP(top) (TDA9887_TOP_SET | (((16 + (top)) & 0x1f) << 8)) - -/* config options */ -#define TDA9887_DEEMPHASIS_MASK (3<<16) -#define TDA9887_DEEMPHASIS_NONE (1<<16) -#define TDA9887_DEEMPHASIS_50 (2<<16) -#define TDA9887_DEEMPHASIS_75 (3<<16) -#define TDA9887_AUTOMUTE (1<<18) -#define TDA9887_GATING_18 (1<<19) -#define TDA9887_GAIN_NORMAL (1<<20) -#define TDA9887_RIF_41_3 (1<<21) /* radio IF1 41.3 vs 33.3 */ - -enum tuner_mode { - T_RADIO = 1 << V4L2_TUNER_RADIO, - T_ANALOG_TV = 1 << V4L2_TUNER_ANALOG_TV, - /* Don't need to map V4L2_TUNER_DIGITAL_TV, as tuner-core won't use it */ -}; - -/* Older boards only had a single tuner device. Nowadays multiple tuner - devices may be present on a single board. Using TUNER_SET_TYPE_ADDR - to pass the tuner_setup structure it is possible to setup each tuner - device in turn. - - Since multiple devices may be present it is no longer sufficient to - send a command to a single i2c device. Instead you should broadcast - the command to all i2c devices. - - By setting the mode_mask correctly you can select which commands are - accepted by a specific tuner device. For example, set mode_mask to - T_RADIO if the device is a radio-only tuner. That specific tuner will - only accept commands when the tuner is in radio mode and ignore them - when the tuner is set to TV mode. - */ - -struct tuner_setup { - unsigned short addr; /* I2C address */ - unsigned int type; /* Tuner type */ - unsigned int mode_mask; /* Allowed tuner modes */ - unsigned int config; /* configuraion for more complex tuners */ - int (*tuner_callback) (void *dev, int component, int cmd, int arg); -}; - -#endif /* __KERNEL__ */ - -#endif /* _TUNER_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tuner-types.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tuner-types.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tuner-types.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tuner-types.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -/* - * descriptions for simple tuners. - */ - -#ifndef __TUNER_TYPES_H__ -#define __TUNER_TYPES_H__ - -enum param_type { - TUNER_PARAM_TYPE_RADIO, - TUNER_PARAM_TYPE_PAL, - TUNER_PARAM_TYPE_SECAM, - TUNER_PARAM_TYPE_NTSC, - TUNER_PARAM_TYPE_DIGITAL, -}; - -struct tuner_range { - unsigned short limit; - unsigned char config; - unsigned char cb; -}; - -struct tuner_params { - enum param_type type; - - /* Many Philips based tuners have a comment like this in their - * datasheet: - * - * For channel selection involving band switching, and to ensure - * smooth tuning to the desired channel without causing - * unnecessary charge pump action, it is recommended to consider - * the difference between wanted channel frequency and the - * current channel frequency. Unnecessary charge pump action - * will result in very low tuning voltage which may drive the - * oscillator to extreme conditions. - * - * Set cb_first_if_lower_freq to 1, if this check is - * required for this tuner. - * - * I tested this for PAL by first setting the TV frequency to - * 203 MHz and then switching to 96.6 MHz FM radio. The result was - * static unless the control byte was sent first. - */ - unsigned int cb_first_if_lower_freq:1; - /* Set to 1 if this tuner uses a tda9887 */ - unsigned int has_tda9887:1; - /* Many Philips tuners use tda9887 PORT1 to select the FM radio - sensitivity. If this setting is 1, then set PORT1 to 1 to - get proper FM reception. */ - unsigned int port1_fm_high_sensitivity:1; - /* Some Philips tuners use tda9887 PORT2 to select the FM radio - sensitivity. If this setting is 1, then set PORT2 to 1 to - get proper FM reception. */ - unsigned int port2_fm_high_sensitivity:1; - /* Some Philips tuners use tda9887 cGainNormal to select the FM radio - sensitivity. If this setting is 1, e register will use cGainNormal - instead of cGainLow. */ - unsigned int fm_gain_normal:1; - /* Most tuners with a tda9887 use QSS mode. Some (cheaper) tuners - use Intercarrier mode. If this setting is 1, then the tuner - needs to be set to intercarrier mode. */ - unsigned int intercarrier_mode:1; - /* This setting sets the default value for PORT1. - 0 means inactive, 1 means active. Note: the actual bit - value written to the tda9887 is inverted. So a 0 here - means a 1 in the B6 bit. */ - unsigned int port1_active:1; - /* This setting sets the default value for PORT2. - 0 means inactive, 1 means active. Note: the actual bit - value written to the tda9887 is inverted. So a 0 here - means a 1 in the B7 bit. */ - unsigned int port2_active:1; - /* Sometimes PORT1 is inverted when the SECAM-L' standard is selected. - Set this bit to 1 if this is needed. */ - unsigned int port1_invert_for_secam_lc:1; - /* Sometimes PORT2 is inverted when the SECAM-L' standard is selected. - Set this bit to 1 if this is needed. */ - unsigned int port2_invert_for_secam_lc:1; - /* Some cards require PORT1 to be 1 for mono Radio FM and 0 for stereo. */ - unsigned int port1_set_for_fm_mono:1; - /* Select 18% (or according to datasheet 0%) L standard PLL gating, - vs the driver default of 36%. */ - unsigned int default_pll_gating_18:1; - /* IF to use in radio mode. Tuners with a separate radio IF filter - seem to use 10.7, while those without use 33.3 for PAL/SECAM tuners - and 41.3 for NTSC tuners. 0 = 10.7, 1 = 33.3, 2 = 41.3 */ - unsigned int radio_if:2; - /* Default tda9887 TOP value in dB for the low band. Default is 0. - Range: -16:+15 */ - signed int default_top_low:5; - /* Default tda9887 TOP value in dB for the mid band. Default is 0. - Range: -16:+15 */ - signed int default_top_mid:5; - /* Default tda9887 TOP value in dB for the high band. Default is 0. - Range: -16:+15 */ - signed int default_top_high:5; - /* Default tda9887 TOP value in dB for SECAM-L/L' for the low band. - Default is 0. Several tuners require a different TOP value for - the SECAM-L/L' standards. Range: -16:+15 */ - signed int default_top_secam_low:5; - /* Default tda9887 TOP value in dB for SECAM-L/L' for the mid band. - Default is 0. Several tuners require a different TOP value for - the SECAM-L/L' standards. Range: -16:+15 */ - signed int default_top_secam_mid:5; - /* Default tda9887 TOP value in dB for SECAM-L/L' for the high band. - Default is 0. Several tuners require a different TOP value for - the SECAM-L/L' standards. Range: -16:+15 */ - signed int default_top_secam_high:5; - - u16 iffreq; - - unsigned int count; - struct tuner_range *ranges; -}; - -struct tunertype { - char *name; - unsigned int count; - struct tuner_params *params; - - u16 min; - u16 max; - u32 stepsize; - - u8 *initdata; - u8 *sleepdata; -}; - -extern struct tunertype tuners[]; -extern unsigned const int tuner_count; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvaudio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvaudio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvaudio.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvaudio.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - tvaudio.h - definition for tvaudio inputs - - Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _TVAUDIO_H -#define _TVAUDIO_H - -#include - -/* The tvaudio module accepts the following inputs: */ -#define TVAUDIO_INPUT_TUNER 0 -#define TVAUDIO_INPUT_RADIO 1 -#define TVAUDIO_INPUT_EXTERN 2 -#define TVAUDIO_INPUT_INTERN 3 - -static inline const unsigned short *tvaudio_addrs(void) -{ - static const unsigned short addrs[] = { - I2C_ADDR_TDA8425 >> 1, - I2C_ADDR_TEA6300 >> 1, - I2C_ADDR_TEA6420 >> 1, - I2C_ADDR_TDA9840 >> 1, - I2C_ADDR_TDA985x_L >> 1, - I2C_ADDR_TDA985x_H >> 1, - I2C_ADDR_TDA9874 >> 1, - I2C_ADDR_PIC16C54 >> 1, - I2C_CLIENT_END - }; - - return addrs; -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tveeprom.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tveeprom.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tveeprom.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tveeprom.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* - */ - -struct tveeprom { - u32 has_radio; - /* If has_ir == 0, then it is unknown what the IR capabilities are, - otherwise: - bit 0: 1 (= IR capabilities are known) - bit 1: IR receiver present - bit 2: IR transmitter (blaster) present */ - u32 has_ir; - u32 has_MAC_address; /* 0: no MAC, 1: MAC present, 2: unknown */ - - u32 tuner_type; - u32 tuner_formats; - u32 tuner_hauppauge_model; - - u32 tuner2_type; - u32 tuner2_formats; - u32 tuner2_hauppauge_model; - - u32 digitizer; - u32 digitizer_formats; - - u32 audio_processor; - u32 decoder_processor; - - u32 model; - u32 revision; - u32 serial_number; - char rev_str[5]; - u8 MAC_address[6]; -}; - -void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, - unsigned char *eeprom_data); - -int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp514x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp514x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp514x.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp514x.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/* - * drivers/media/video/tvp514x.h - * - * Copyright (C) 2008 Texas Instruments Inc - * Author: Vaibhav Hiremath - * - * Contributors: - * Sivaraj R - * Brijesh R Jadav - * Hardik Shah - * Manjunath Hadli - * Karicheri Muralidharan - * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _TVP514X_H -#define _TVP514X_H - -/* - * Other macros - */ -#define TVP514X_MODULE_NAME "tvp514x" - -#define TVP514X_XCLK_BT656 (27000000) - -/* Number of pixels and number of lines per frame for different standards */ -#define NTSC_NUM_ACTIVE_PIXELS (720) -#define NTSC_NUM_ACTIVE_LINES (480) -#define PAL_NUM_ACTIVE_PIXELS (720) -#define PAL_NUM_ACTIVE_LINES (576) - -/** - * enum tvp514x_input - enum for different decoder input pin - * configuration. - */ -enum tvp514x_input { - /* - * CVBS input selection - */ - INPUT_CVBS_VI1A = 0x0, - INPUT_CVBS_VI1B, - INPUT_CVBS_VI1C, - INPUT_CVBS_VI2A = 0x04, - INPUT_CVBS_VI2B, - INPUT_CVBS_VI2C, - INPUT_CVBS_VI3A = 0x08, - INPUT_CVBS_VI3B, - INPUT_CVBS_VI3C, - INPUT_CVBS_VI4A = 0x0C, - /* - * S-Video input selection - */ - INPUT_SVIDEO_VI2A_VI1A = 0x44, - INPUT_SVIDEO_VI2B_VI1B, - INPUT_SVIDEO_VI2C_VI1C, - INPUT_SVIDEO_VI2A_VI3A = 0x54, - INPUT_SVIDEO_VI2B_VI3B, - INPUT_SVIDEO_VI2C_VI3C, - INPUT_SVIDEO_VI4A_VI1A = 0x4C, - INPUT_SVIDEO_VI4A_VI1B, - INPUT_SVIDEO_VI4A_VI1C, - INPUT_SVIDEO_VI4A_VI3A = 0x5C, - INPUT_SVIDEO_VI4A_VI3B, - INPUT_SVIDEO_VI4A_VI3C, - - /* Need to add entries for - * RGB, YPbPr and SCART. - */ - INPUT_INVALID -}; - -/** - * enum tvp514x_output - enum for output format - * supported. - * - */ -enum tvp514x_output { - OUTPUT_10BIT_422_EMBEDDED_SYNC = 0, - OUTPUT_20BIT_422_SEPERATE_SYNC, - OUTPUT_10BIT_422_SEPERATE_SYNC = 3, - OUTPUT_INVALID -}; - -/** - * struct tvp514x_platform_data - Platform data values and access functions. - * @power_set: Power state access function, zero is off, non-zero is on. - * @ifparm: Interface parameters access function. - * @priv_data_set: Device private data (pointer) access function. - * @clk_polarity: Clock polarity of the current interface. - * @ hs_polarity: HSYNC Polarity configuration for current interface. - * @ vs_polarity: VSYNC Polarity configuration for current interface. - */ -struct tvp514x_platform_data { - /* Interface control params */ - bool clk_polarity; - bool hs_polarity; - bool vs_polarity; -}; - - -#endif /* ifndef _TVP514X_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp5150.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp5150.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp5150.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp5150.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - tvp5150.h - definition for tvp5150 inputs - - Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _TVP5150_H_ -#define _TVP5150_H_ - -/* TVP5150 HW inputs */ -#define TVP5150_COMPOSITE0 0 -#define TVP5150_COMPOSITE1 1 -#define TVP5150_SVIDEO 2 - -/* TVP5150 HW outputs */ -#define TVP5150_NORMAL 0 -#define TVP5150_BLACK_SCREEN 1 - -#endif - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp7002.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp7002.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp7002.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tvp7002.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics - * Digitizer with Horizontal PLL registers - * - * Copyright (C) 2009 Texas Instruments Inc - * Author: Santiago Nunez-Corrales - * - * This code is partially based upon the TVP5150 driver - * written by Mauro Carvalho Chehab (mchehab@infradead.org), - * the TVP514x driver written by Vaibhav Hiremath - * and the TVP7002 driver in the TI LSP 2.10.00.14 - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef _TVP7002_H_ -#define _TVP7002_H_ - -/* Platform-dependent data - * - * clk_polarity: - * 0 -> data clocked out on rising edge of DATACLK signal - * 1 -> data clocked out on falling edge of DATACLK signal - * hs_polarity: - * 0 -> active low HSYNC output - * 1 -> active high HSYNC output - * sog_polarity: - * 0 -> normal operation - * 1 -> operation with polarity inverted - * vs_polarity: - * 0 -> active low VSYNC output - * 1 -> active high VSYNC output - * fid_polarity: - * 0 -> the field ID output is set to logic 1 for an odd - * field (field 1) and set to logic 0 for an even - * field (field 0). - * 1 -> operation with polarity inverted. - */ -struct tvp7002_config { - u8 clk_polarity; - u8 hs_polarity; - u8 vs_polarity; - u8 fid_polarity; - u8 sog_polarity; -}; -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tw9910.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tw9910.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/tw9910.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/tw9910.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* - * tw9910 Driver header - * - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto - * - * Based on ov772x.h - * - * Copyright (C) Kuninori Morimoto - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __TW9910_H__ -#define __TW9910_H__ - -#include - -enum tw9910_mpout_pin { - TW9910_MPO_VLOSS, - TW9910_MPO_HLOCK, - TW9910_MPO_SLOCK, - TW9910_MPO_VLOCK, - TW9910_MPO_MONO, - TW9910_MPO_DET50, - TW9910_MPO_FIELD, - TW9910_MPO_RTCO, -}; - -struct tw9910_video_info { - unsigned long buswidth; - enum tw9910_mpout_pin mpout; -}; - - -#endif /* __TW9910_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/upd64031a.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/upd64031a.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/upd64031a.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/upd64031a.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -/* - * upd64031a - NEC Electronics Ghost Reduction input defines - * - * 2006 by Hans Verkuil (hverkuil@xs4all.nl) - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _UPD64031A_H_ -#define _UPD64031A_H_ - -/* Ghost reduction modes */ -#define UPD64031A_GR_ON 0 -#define UPD64031A_GR_OFF 1 -#define UPD64031A_GR_THROUGH 3 - -/* Direct 3D/YCS Connection */ -#define UPD64031A_3DYCS_DISABLE (0 << 2) -#define UPD64031A_3DYCS_COMPOSITE (2 << 2) -#define UPD64031A_3DYCS_SVIDEO (3 << 2) - -/* Composite sync digital separation circuit */ -#define UPD64031A_COMPOSITE_EXTERNAL (1 << 4) - -/* Vertical sync digital separation circuit */ -#define UPD64031A_VERTICAL_EXTERNAL (1 << 5) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/upd64083.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/upd64083.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/upd64083.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/upd64083.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/* - * upd6408x - NEC Electronics 3-Dimensional Y/C separation input defines - * - * 2006 by Hans Verkuil (hverkuil@xs4all.nl) - * - * 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, or (at your option) any later version. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _UPD64083_H_ -#define _UPD64083_H_ - -/* There are two bits of information that the driver needs in order - to select the correct routing: the operating mode and the selection - of the Y input (external or internal). - - The first two operating modes expect a composite signal on the Y input, - the second two operating modes use both the Y and C inputs. - - Normally YCS_MODE is used for tuner and composite inputs, and the - YCNR mode is used for S-Video inputs. - - The external Y-ADC is selected when the composite input comes from a - upd64031a ghost reduction device. If this device is not present, or - the input is a S-Video signal, then the internal Y-ADC input should - be used. */ - -/* Operating modes: */ - -/* YCS mode: Y/C separation (burst locked clocking) */ -#define UPD64083_YCS_MODE 0 -/* YCS+ mode: 2D Y/C separation and YCNR (burst locked clocking) */ -#define UPD64083_YCS_PLUS_MODE 1 - -/* Note: the following two modes cannot be used in combination with the - external Y-ADC. */ -/* MNNR mode: frame comb type YNR+C delay (line locked clocking) */ -#define UPD64083_MNNR_MODE 2 -/* YCNR mode: frame recursive YCNR (burst locked clocking) */ -#define UPD64083_YCNR_MODE 3 - -/* Select external Y-ADC: this should be set if this device is used in - combination with the upd64031a ghost reduction device. - Otherwise leave at 0 (use internal Y-ADC). */ -#define UPD64083_EXT_Y_ADC (1 << 2) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-chip-ident.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-chip-ident.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-chip-ident.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-chip-ident.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,327 +0,0 @@ -/* - v4l2 chip identifiers header - - This header provides a list of chip identifiers that can be returned - through the VIDIOC_DBG_G_CHIP_IDENT ioctl. - - Copyright (C) 2007 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef V4L2_CHIP_IDENT_H_ -#define V4L2_CHIP_IDENT_H_ - -/* VIDIOC_DBG_G_CHIP_IDENT: identifies the actual chip installed on the board */ - -/* KEEP THIS LIST ORDERED BY ID! - Otherwise it will be hard to see which ranges are already in use when - adding support to a new chip family. */ -enum { - /* general idents: reserved range 0-49 */ - V4L2_IDENT_NONE = 0, /* No chip matched */ - V4L2_IDENT_AMBIGUOUS = 1, /* Match too general, multiple chips matched */ - V4L2_IDENT_UNKNOWN = 2, /* Chip found, but cannot identify */ - - /* module tvaudio: reserved range 50-99 */ - V4L2_IDENT_TVAUDIO = 50, /* A tvaudio chip, unknown which it is exactly */ - - /* Sony IMX074 */ - V4L2_IDENT_IMX074 = 74, - - /* module saa7110: just ident 100 */ - V4L2_IDENT_SAA7110 = 100, - - /* module saa7115: reserved range 101-149 */ - V4L2_IDENT_SAA7111 = 101, - V4L2_IDENT_SAA7111A = 102, - V4L2_IDENT_SAA7113 = 103, - V4L2_IDENT_SAA7114 = 104, - V4L2_IDENT_SAA7115 = 105, - V4L2_IDENT_SAA7118 = 108, - - /* module saa7127: reserved range 150-199 */ - V4L2_IDENT_SAA7127 = 157, - V4L2_IDENT_SAA7129 = 159, - - /* module cx25840: reserved range 200-249 */ - V4L2_IDENT_CX25836 = 236, - V4L2_IDENT_CX25837 = 237, - V4L2_IDENT_CX25840 = 240, - V4L2_IDENT_CX25841 = 241, - V4L2_IDENT_CX25842 = 242, - V4L2_IDENT_CX25843 = 243, - - /* OmniVision sensors: reserved range 250-299 */ - V4L2_IDENT_OV7670 = 250, - V4L2_IDENT_OV7720 = 251, - V4L2_IDENT_OV7725 = 252, - V4L2_IDENT_OV7660 = 253, - V4L2_IDENT_OV9650 = 254, - V4L2_IDENT_OV9655 = 255, - V4L2_IDENT_SOI968 = 256, - V4L2_IDENT_OV9640 = 257, - V4L2_IDENT_OV6650 = 258, - V4L2_IDENT_OV2640 = 259, - V4L2_IDENT_OV9740 = 260, - - /* module saa7146: reserved range 300-309 */ - V4L2_IDENT_SAA7146 = 300, - - /* Conexant MPEG encoder/decoders: reserved range 400-420 */ - V4L2_IDENT_CX23418_843 = 403, /* Integrated A/V Decoder on the '418 */ - V4L2_IDENT_CX23415 = 415, - V4L2_IDENT_CX23416 = 416, - V4L2_IDENT_CX23417 = 417, - V4L2_IDENT_CX23418 = 418, - - /* module bt819: reserved range 810-819 */ - V4L2_IDENT_BT815A = 815, - V4L2_IDENT_BT817A = 817, - V4L2_IDENT_BT819A = 819, - - /* module au0828 */ - V4L2_IDENT_AU0828 = 828, - - /* module bt856: just ident 856 */ - V4L2_IDENT_BT856 = 856, - - /* module bt866: just ident 866 */ - V4L2_IDENT_BT866 = 866, - - /* module ks0127: reserved range 1120-1129 */ - V4L2_IDENT_KS0122S = 1122, - V4L2_IDENT_KS0127 = 1127, - V4L2_IDENT_KS0127B = 1128, - - /* module indycam: just ident 2000 */ - V4L2_IDENT_INDYCAM = 2000, - - /* module vp27smpx: just ident 2700 */ - V4L2_IDENT_VP27SMPX = 2700, - - /* module vpx3220: reserved range: 3210-3229 */ - V4L2_IDENT_VPX3214C = 3214, - V4L2_IDENT_VPX3216B = 3216, - V4L2_IDENT_VPX3220A = 3220, - - /* VX855 just ident 3409 */ - /* Other via devs could use 3314, 3324, 3327, 3336, 3364, 3353 */ - V4L2_IDENT_VIA_VX855 = 3409, - - /* module tvp5150 */ - V4L2_IDENT_TVP5150 = 5150, - - /* module saa5246a: just ident 5246 */ - V4L2_IDENT_SAA5246A = 5246, - - /* module saa5249: just ident 5249 */ - V4L2_IDENT_SAA5249 = 5249, - - /* module cs5345: just ident 5345 */ - V4L2_IDENT_CS5345 = 5345, - - /* module tea6415c: just ident 6415 */ - V4L2_IDENT_TEA6415C = 6415, - - /* module tea6420: just ident 6420 */ - V4L2_IDENT_TEA6420 = 6420, - - /* module saa6588: just ident 6588 */ - V4L2_IDENT_SAA6588 = 6588, - - /* module saa6752hs: reserved range 6750-6759 */ - V4L2_IDENT_SAA6752HS = 6752, - V4L2_IDENT_SAA6752HS_AC3 = 6753, - - /* modules tef6862: just ident 6862 */ - V4L2_IDENT_TEF6862 = 6862, - - /* module tvp7002: just ident 7002 */ - V4L2_IDENT_TVP7002 = 7002, - - /* module adv7170: just ident 7170 */ - V4L2_IDENT_ADV7170 = 7170, - - /* module adv7175: just ident 7175 */ - V4L2_IDENT_ADV7175 = 7175, - - /* module adv7180: just ident 7180 */ - V4L2_IDENT_ADV7180 = 7180, - - /* module saa7185: just ident 7185 */ - V4L2_IDENT_SAA7185 = 7185, - - /* module saa7191: just ident 7191 */ - V4L2_IDENT_SAA7191 = 7191, - - /* module ths7303: just ident 7303 */ - V4L2_IDENT_THS7303 = 7303, - - /* module adv7343: just ident 7343 */ - V4L2_IDENT_ADV7343 = 7343, - - /* module saa7706h: just ident 7706 */ - V4L2_IDENT_SAA7706H = 7706, - - /* module mt9v011, just ident 8243 */ - V4L2_IDENT_MT9V011 = 8243, - - /* module wm8739: just ident 8739 */ - V4L2_IDENT_WM8739 = 8739, - - /* module wm8775: just ident 8775 */ - V4L2_IDENT_WM8775 = 8775, - - /* module cafe_ccic, just ident 8801 */ - V4L2_IDENT_CAFE = 8801, - - /* AKM AK8813/AK8814 */ - V4L2_IDENT_AK8813 = 8813, - V4L2_IDENT_AK8814 = 8814, - - /* module cx23885 and cx25840 */ - V4L2_IDENT_CX23885 = 8850, - V4L2_IDENT_CX23885_AV = 8851, /* Integrated A/V decoder */ - V4L2_IDENT_CX23887 = 8870, - V4L2_IDENT_CX23887_AV = 8871, /* Integrated A/V decoder */ - V4L2_IDENT_CX23888 = 8880, - V4L2_IDENT_CX23888_AV = 8881, /* Integrated A/V decoder */ - V4L2_IDENT_CX23888_IR = 8882, /* Integrated infrared controller */ - - /* module tda9840: just ident 9840 */ - V4L2_IDENT_TDA9840 = 9840, - - /* module tw9910: just ident 9910 */ - V4L2_IDENT_TW9910 = 9910, - - /* module sn9c20x: just ident 10000 */ - V4L2_IDENT_SN9C20X = 10000, - - /* Siliconfile sensors: reserved range 10100 - 10199 */ - V4L2_IDENT_NOON010PC30 = 10100, - - /* module cx231xx and cx25840 */ - V4L2_IDENT_CX2310X_AV = 23099, /* Integrated A/V decoder; not in '100 */ - V4L2_IDENT_CX23100 = 23100, - V4L2_IDENT_CX23101 = 23101, - V4L2_IDENT_CX23102 = 23102, - - /* module msp3400: reserved range 34000-34999 for msp34xx */ - V4L2_IDENT_MSPX4XX = 34000, /* generic MSPX4XX identifier, only - use internally (tveeprom.c). */ - - V4L2_IDENT_MSP3400B = 34002, - V4L2_IDENT_MSP3400C = 34003, - V4L2_IDENT_MSP3400D = 34004, - V4L2_IDENT_MSP3400G = 34007, - V4L2_IDENT_MSP3401G = 34017, - V4L2_IDENT_MSP3402G = 34027, - V4L2_IDENT_MSP3405D = 34054, - V4L2_IDENT_MSP3405G = 34057, - V4L2_IDENT_MSP3407D = 34074, - V4L2_IDENT_MSP3407G = 34077, - - V4L2_IDENT_MSP3410B = 34102, - V4L2_IDENT_MSP3410C = 34103, - V4L2_IDENT_MSP3410D = 34104, - V4L2_IDENT_MSP3410G = 34107, - V4L2_IDENT_MSP3411G = 34117, - V4L2_IDENT_MSP3412G = 34127, - V4L2_IDENT_MSP3415D = 34154, - V4L2_IDENT_MSP3415G = 34157, - V4L2_IDENT_MSP3417D = 34174, - V4L2_IDENT_MSP3417G = 34177, - - V4L2_IDENT_MSP3420G = 34207, - V4L2_IDENT_MSP3421G = 34217, - V4L2_IDENT_MSP3422G = 34227, - V4L2_IDENT_MSP3425G = 34257, - V4L2_IDENT_MSP3427G = 34277, - - V4L2_IDENT_MSP3430G = 34307, - V4L2_IDENT_MSP3431G = 34317, - V4L2_IDENT_MSP3435G = 34357, - V4L2_IDENT_MSP3437G = 34377, - - V4L2_IDENT_MSP3440G = 34407, - V4L2_IDENT_MSP3441G = 34417, - V4L2_IDENT_MSP3442G = 34427, - V4L2_IDENT_MSP3445G = 34457, - V4L2_IDENT_MSP3447G = 34477, - - V4L2_IDENT_MSP3450G = 34507, - V4L2_IDENT_MSP3451G = 34517, - V4L2_IDENT_MSP3452G = 34527, - V4L2_IDENT_MSP3455G = 34557, - V4L2_IDENT_MSP3457G = 34577, - - V4L2_IDENT_MSP3460G = 34607, - V4L2_IDENT_MSP3461G = 34617, - V4L2_IDENT_MSP3465G = 34657, - V4L2_IDENT_MSP3467G = 34677, - - /* module msp3400: reserved range 44000-44999 for msp44xx */ - V4L2_IDENT_MSP4400G = 44007, - V4L2_IDENT_MSP4408G = 44087, - V4L2_IDENT_MSP4410G = 44107, - V4L2_IDENT_MSP4418G = 44187, - V4L2_IDENT_MSP4420G = 44207, - V4L2_IDENT_MSP4428G = 44287, - V4L2_IDENT_MSP4440G = 44407, - V4L2_IDENT_MSP4448G = 44487, - V4L2_IDENT_MSP4450G = 44507, - V4L2_IDENT_MSP4458G = 44587, - - /* Micron CMOS sensor chips: 45000-45099 */ - V4L2_IDENT_MT9M001C12ST = 45000, - V4L2_IDENT_MT9M001C12STM = 45005, - V4L2_IDENT_MT9M111 = 45007, - V4L2_IDENT_MT9M112 = 45008, - V4L2_IDENT_MT9V022IX7ATC = 45010, /* No way to detect "normal" I77ATx */ - V4L2_IDENT_MT9V022IX7ATM = 45015, /* and "lead free" IA7ATx chips */ - V4L2_IDENT_MT9T031 = 45020, - V4L2_IDENT_MT9T111 = 45021, - V4L2_IDENT_MT9T112 = 45022, - V4L2_IDENT_MT9V111 = 45031, - V4L2_IDENT_MT9V112 = 45032, - - /* HV7131R CMOS sensor: just ident 46000 */ - V4L2_IDENT_HV7131R = 46000, - - /* Sharp RJ54N1CB0C, 0xCB0C = 51980 */ - V4L2_IDENT_RJ54N1CB0C = 51980, - - /* module m52790: just ident 52790 */ - V4L2_IDENT_M52790 = 52790, - - /* module cs53132a: just ident 53132 */ - V4L2_IDENT_CS53l32A = 53132, - - /* modules upd61151 MPEG2 encoder: just ident 54000 */ - V4L2_IDENT_UPD61161 = 54000, - /* modules upd61152 MPEG2 encoder with AC3: just ident 54001 */ - V4L2_IDENT_UPD61162 = 54001, - - /* module upd64031a: just ident 64031 */ - V4L2_IDENT_UPD64031A = 64031, - - /* module upd64083: just ident 64083 */ - V4L2_IDENT_UPD64083 = 64083, - - /* Don't just add new IDs at the end: KEEP THIS LIST ORDERED BY ID! */ -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-common.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,215 +0,0 @@ -/* - v4l2 common internal API header - - This header contains internal shared ioctl definitions for use by the - internal low-level v4l2 drivers. - Each ioctl begins with VIDIOC_INT_ to clearly mark that it is an internal - define, - - Copyright (C) 2005 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef V4L2_COMMON_H_ -#define V4L2_COMMON_H_ - -#include - -/* Common printk constucts for v4l-i2c drivers. These macros create a unique - prefix consisting of the driver name, the adapter number and the i2c - address. */ -#define v4l_printk(level, name, adapter, addr, fmt, arg...) \ - printk(level "%s %d-%04x: " fmt, name, i2c_adapter_id(adapter), addr , ## arg) - -#define v4l_client_printk(level, client, fmt, arg...) \ - v4l_printk(level, (client)->driver->driver.name, (client)->adapter, \ - (client)->addr, fmt , ## arg) - -#define v4l_err(client, fmt, arg...) \ - v4l_client_printk(KERN_ERR, client, fmt , ## arg) - -#define v4l_warn(client, fmt, arg...) \ - v4l_client_printk(KERN_WARNING, client, fmt , ## arg) - -#define v4l_info(client, fmt, arg...) \ - v4l_client_printk(KERN_INFO, client, fmt , ## arg) - -/* These three macros assume that the debug level is set with a module - parameter called 'debug'. */ -#define v4l_dbg(level, debug, client, fmt, arg...) \ - do { \ - if (debug >= (level)) \ - v4l_client_printk(KERN_DEBUG, client, fmt , ## arg); \ - } while (0) - -/* ------------------------------------------------------------------------- */ - -/* These printk constructs can be used with v4l2_device and v4l2_subdev */ -#define v4l2_printk(level, dev, fmt, arg...) \ - printk(level "%s: " fmt, (dev)->name , ## arg) - -#define v4l2_err(dev, fmt, arg...) \ - v4l2_printk(KERN_ERR, dev, fmt , ## arg) - -#define v4l2_warn(dev, fmt, arg...) \ - v4l2_printk(KERN_WARNING, dev, fmt , ## arg) - -#define v4l2_info(dev, fmt, arg...) \ - v4l2_printk(KERN_INFO, dev, fmt , ## arg) - -/* These three macros assume that the debug level is set with a module - parameter called 'debug'. */ -#define v4l2_dbg(level, debug, dev, fmt, arg...) \ - do { \ - if (debug >= (level)) \ - v4l2_printk(KERN_DEBUG, dev, fmt , ## arg); \ - } while (0) - -/* ------------------------------------------------------------------------- */ - -/* Control helper functions */ - -int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl, - const char * const *menu_items); -const char *v4l2_ctrl_get_name(u32 id); -const char * const *v4l2_ctrl_get_menu(u32 id); -int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def); -int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, - struct v4l2_queryctrl *qctrl, const char * const *menu_items); -#define V4L2_CTRL_MENU_IDS_END (0xffffffff) -int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids); - -/* Note: ctrl_classes points to an array of u32 pointers. Each u32 array is a - 0-terminated array of control IDs. Each array must be sorted low to high - and belong to the same control class. The array of u32 pointers must also - be sorted, from low class IDs to high class IDs. */ -u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id); - -/* ------------------------------------------------------------------------- */ - -/* Register/chip ident helper function */ - -struct i2c_client; /* forward reference */ -int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match); -int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_dbg_chip_ident *chip, - u32 ident, u32 revision); -int v4l2_chip_match_host(const struct v4l2_dbg_match *match); - -/* ------------------------------------------------------------------------- */ - -/* I2C Helper functions */ - -struct i2c_driver; -struct i2c_adapter; -struct i2c_client; -struct i2c_device_id; -struct v4l2_device; -struct v4l2_subdev; -struct v4l2_subdev_ops; - - -/* Load an i2c module and return an initialized v4l2_subdev struct. - The client_type argument is the name of the chip that's on the adapter. */ -struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, const char *client_type, - u8 addr, const unsigned short *probe_addrs); - -struct i2c_board_info; - -struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, struct i2c_board_info *info, - const unsigned short *probe_addrs); - -/* Initialize an v4l2_subdev with data from an i2c_client struct */ -void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, - const struct v4l2_subdev_ops *ops); -/* Return i2c client address of v4l2_subdev. */ -unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd); - -enum v4l2_i2c_tuner_type { - ADDRS_RADIO, /* Radio tuner addresses */ - ADDRS_DEMOD, /* Demod tuner addresses */ - ADDRS_TV, /* TV tuner addresses */ - /* TV tuner addresses if demod is present, this excludes - addresses used by the demodulator from the list of - candidates. */ - ADDRS_TV_WITH_DEMOD, -}; -/* Return a list of I2C tuner addresses to probe. Use only if the tuner - addresses are unknown. */ -const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type); - -/* ------------------------------------------------------------------------- */ - -/* SPI Helper functions */ -#if defined(CONFIG_SPI) - -#include - -struct spi_device; - -/* Load an spi module and return an initialized v4l2_subdev struct. - The client_type argument is the name of the chip that's on the adapter. */ -struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, - struct spi_master *master, struct spi_board_info *info); - -/* Initialize an v4l2_subdev with data from an spi_device struct */ -void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, - const struct v4l2_subdev_ops *ops); -#endif - -/* ------------------------------------------------------------------------- */ - -/* Note: these remaining ioctls/structs should be removed as well, but they are - still used in tuner-simple.c (TUNER_SET_CONFIG), cx18/ivtv (RESET) and - v4l2-int-device.h (v4l2_routing). To remove these ioctls some more cleanup - is needed in those modules. */ - -/* s_config */ -struct v4l2_priv_tun_config { - int tuner; - void *priv; -}; -#define TUNER_SET_CONFIG _IOW('d', 92, struct v4l2_priv_tun_config) - -#define VIDIOC_INT_RESET _IOW ('d', 102, u32) - -struct v4l2_routing { - u32 input; - u32 output; -}; - -/* ------------------------------------------------------------------------- */ - -/* Miscellaneous helper functions */ - -void v4l_bound_align_image(unsigned int *w, unsigned int wmin, - unsigned int wmax, unsigned int walign, - unsigned int *h, unsigned int hmin, - unsigned int hmax, unsigned int halign, - unsigned int salign); -int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info); - -struct v4l2_discrete_probe { - const struct v4l2_frmsize_discrete *sizes; - int num_sizes; -}; - -const struct v4l2_frmsize_discrete *v4l2_find_nearest_format( - const struct v4l2_discrete_probe *probe, - s32 width, s32 height); - -#endif /* V4L2_COMMON_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-ctrls.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-ctrls.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-ctrls.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-ctrls.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,463 +0,0 @@ -/* - V4L2 controls support header. - - Copyright (C) 2010 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef _V4L2_CTRLS_H -#define _V4L2_CTRLS_H - -#include -#include -#include - -/* forward references */ -struct v4l2_ctrl_handler; -struct v4l2_ctrl; -struct video_device; -struct v4l2_subdev; - -/** struct v4l2_ctrl_ops - The control operations that the driver has to provide. - * @g_volatile_ctrl: Get a new value for this control. Generally only relevant - * for volatile (and usually read-only) controls such as a control - * that returns the current signal strength which changes - * continuously. - * If not set, then the currently cached value will be returned. - * @try_ctrl: Test whether the control's value is valid. Only relevant when - * the usual min/max/step checks are not sufficient. - * @s_ctrl: Actually set the new control value. s_ctrl is compulsory. The - * ctrl->handler->lock is held when these ops are called, so no - * one else can access controls owned by that handler. - */ -struct v4l2_ctrl_ops { - int (*g_volatile_ctrl)(struct v4l2_ctrl *ctrl); - int (*try_ctrl)(struct v4l2_ctrl *ctrl); - int (*s_ctrl)(struct v4l2_ctrl *ctrl); -}; - -/** struct v4l2_ctrl - The control structure. - * @node: The list node. - * @handler: The handler that owns the control. - * @cluster: Point to start of cluster array. - * @ncontrols: Number of controls in cluster array. - * @done: Internal flag: set for each processed control. - * @is_new: Set when the user specified a new value for this control. It - * is also set when called from v4l2_ctrl_handler_setup. Drivers - * should never set this flag. - * @is_private: If set, then this control is private to its handler and it - * will not be added to any other handlers. Drivers can set - * this flag. - * @is_volatile: If set, then this control is volatile. This means that the - * control's current value cannot be cached and needs to be - * retrieved through the g_volatile_ctrl op. Drivers can set - * this flag. - * @ops: The control ops. - * @id: The control ID. - * @name: The control name. - * @type: The control type. - * @minimum: The control's minimum value. - * @maximum: The control's maximum value. - * @default_value: The control's default value. - * @step: The control's step value for non-menu controls. - * @menu_skip_mask: The control's skip mask for menu controls. This makes it - * easy to skip menu items that are not valid. If bit X is set, - * then menu item X is skipped. Of course, this only works for - * menus with <= 32 menu items. There are no menus that come - * close to that number, so this is OK. Should we ever need more, - * then this will have to be extended to a u64 or a bit array. - * @qmenu: A const char * array for all menu items. Array entries that are - * empty strings ("") correspond to non-existing menu items (this - * is in addition to the menu_skip_mask above). The last entry - * must be NULL. - * @flags: The control's flags. - * @cur: The control's current value. - * @val: The control's new s32 value. - * @val64: The control's new s64 value. - * @string: The control's new string value. - * @priv: The control's private pointer. For use by the driver. It is - * untouched by the control framework. Note that this pointer is - * not freed when the control is deleted. Should this be needed - * then a new internal bitfield can be added to tell the framework - * to free this pointer. - */ -struct v4l2_ctrl { - /* Administrative fields */ - struct list_head node; - struct v4l2_ctrl_handler *handler; - struct v4l2_ctrl **cluster; - unsigned ncontrols; - unsigned int done:1; - - unsigned int is_new:1; - unsigned int is_private:1; - unsigned int is_volatile:1; - - const struct v4l2_ctrl_ops *ops; - u32 id; - const char *name; - enum v4l2_ctrl_type type; - s32 minimum, maximum, default_value; - union { - u32 step; - u32 menu_skip_mask; - }; - const char * const *qmenu; - unsigned long flags; - union { - s32 val; - s64 val64; - char *string; - } cur; - union { - s32 val; - s64 val64; - char *string; - }; - void *priv; -}; - -/** struct v4l2_ctrl_ref - The control reference. - * @node: List node for the sorted list. - * @next: Single-link list node for the hash. - * @ctrl: The actual control information. - * - * Each control handler has a list of these refs. The list_head is used to - * keep a sorted-by-control-ID list of all controls, while the next pointer - * is used to link the control in the hash's bucket. - */ -struct v4l2_ctrl_ref { - struct list_head node; - struct v4l2_ctrl_ref *next; - struct v4l2_ctrl *ctrl; -}; - -/** struct v4l2_ctrl_handler - The control handler keeps track of all the - * controls: both the controls owned by the handler and those inherited - * from other handlers. - * @lock: Lock to control access to this handler and its controls. - * @ctrls: The list of controls owned by this handler. - * @ctrl_refs: The list of control references. - * @cached: The last found control reference. It is common that the same - * control is needed multiple times, so this is a simple - * optimization. - * @buckets: Buckets for the hashing. Allows for quick control lookup. - * @nr_of_buckets: Total number of buckets in the array. - * @error: The error code of the first failed control addition. - */ -struct v4l2_ctrl_handler { - struct mutex lock; - struct list_head ctrls; - struct list_head ctrl_refs; - struct v4l2_ctrl_ref *cached; - struct v4l2_ctrl_ref **buckets; - u16 nr_of_buckets; - int error; -}; - -/** struct v4l2_ctrl_config - Control configuration structure. - * @ops: The control ops. - * @id: The control ID. - * @name: The control name. - * @type: The control type. - * @min: The control's minimum value. - * @max: The control's maximum value. - * @step: The control's step value for non-menu controls. - * @def: The control's default value. - * @flags: The control's flags. - * @menu_skip_mask: The control's skip mask for menu controls. This makes it - * easy to skip menu items that are not valid. If bit X is set, - * then menu item X is skipped. Of course, this only works for - * menus with <= 32 menu items. There are no menus that come - * close to that number, so this is OK. Should we ever need more, - * then this will have to be extended to a u64 or a bit array. - * @qmenu: A const char * array for all menu items. Array entries that are - * empty strings ("") correspond to non-existing menu items (this - * is in addition to the menu_skip_mask above). The last entry - * must be NULL. - * @is_private: If set, then this control is private to its handler and it - * will not be added to any other handlers. - * @is_volatile: If set, then this control is volatile. This means that the - * control's current value cannot be cached and needs to be - * retrieved through the g_volatile_ctrl op. - */ -struct v4l2_ctrl_config { - const struct v4l2_ctrl_ops *ops; - u32 id; - const char *name; - enum v4l2_ctrl_type type; - s32 min; - s32 max; - u32 step; - s32 def; - u32 flags; - u32 menu_skip_mask; - const char * const *qmenu; - unsigned int is_private:1; - unsigned int is_volatile:1; -}; - -/** v4l2_ctrl_fill() - Fill in the control fields based on the control ID. - * - * This works for all standard V4L2 controls. - * For non-standard controls it will only fill in the given arguments - * and @name will be NULL. - * - * This function will overwrite the contents of @name, @type and @flags. - * The contents of @min, @max, @step and @def may be modified depending on - * the type. - * - * Do not use in drivers! It is used internally for backwards compatibility - * control handling only. Once all drivers are converted to use the new - * control framework this function will no longer be exported. - */ -void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, - s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags); - - -/** v4l2_ctrl_handler_init() - Initialize the control handler. - * @hdl: The control handler. - * @nr_of_controls_hint: A hint of how many controls this handler is - * expected to refer to. This is the total number, so including - * any inherited controls. It doesn't have to be precise, but if - * it is way off, then you either waste memory (too many buckets - * are allocated) or the control lookup becomes slower (not enough - * buckets are allocated, so there are more slow list lookups). - * It will always work, though. - * - * Returns an error if the buckets could not be allocated. This error will - * also be stored in @hdl->error. - */ -int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, - unsigned nr_of_controls_hint); - -/** v4l2_ctrl_handler_free() - Free all controls owned by the handler and free - * the control list. - * @hdl: The control handler. - * - * Does nothing if @hdl == NULL. - */ -void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl); - -/** v4l2_ctrl_handler_setup() - Call the s_ctrl op for all controls belonging - * to the handler to initialize the hardware to the current control values. - * @hdl: The control handler. - * - * Button controls will be skipped, as are read-only controls. - * - * If @hdl == NULL, then this just returns 0. - */ -int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl); - -/** v4l2_ctrl_handler_log_status() - Log all controls owned by the handler. - * @hdl: The control handler. - * @prefix: The prefix to use when logging the control values. If the - * prefix does not end with a space, then ": " will be added - * after the prefix. If @prefix == NULL, then no prefix will be - * used. - * - * For use with VIDIOC_LOG_STATUS. - * - * Does nothing if @hdl == NULL. - */ -void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl, - const char *prefix); - -/** v4l2_ctrl_new_custom() - Allocate and initialize a new custom V4L2 - * control. - * @hdl: The control handler. - * @cfg: The control's configuration data. - * @priv: The control's driver-specific private data. - * - * If the &v4l2_ctrl struct could not be allocated then NULL is returned - * and @hdl->error is set to the error code (if it wasn't set already). - */ -struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_config *cfg, void *priv); - -/** v4l2_ctrl_new_std() - Allocate and initialize a new standard V4L2 non-menu control. - * @hdl: The control handler. - * @ops: The control ops. - * @id: The control ID. - * @min: The control's minimum value. - * @max: The control's maximum value. - * @step: The control's step value - * @def: The control's default value. - * - * If the &v4l2_ctrl struct could not be allocated, or the control - * ID is not known, then NULL is returned and @hdl->error is set to the - * appropriate error code (if it wasn't set already). - * - * If @id refers to a menu control, then this function will return NULL. - * - * Use v4l2_ctrl_new_std_menu() when adding menu controls. - */ -struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, - u32 id, s32 min, s32 max, u32 step, s32 def); - -/** v4l2_ctrl_new_std_menu() - Allocate and initialize a new standard V4L2 menu control. - * @hdl: The control handler. - * @ops: The control ops. - * @id: The control ID. - * @max: The control's maximum value. - * @mask: The control's skip mask for menu controls. This makes it - * easy to skip menu items that are not valid. If bit X is set, - * then menu item X is skipped. Of course, this only works for - * menus with <= 32 menu items. There are no menus that come - * close to that number, so this is OK. Should we ever need more, - * then this will have to be extended to a u64 or a bit array. - * @def: The control's default value. - * - * Same as v4l2_ctrl_new_std(), but @min is set to 0 and the @mask value - * determines which menu items are to be skipped. - * - * If @id refers to a non-menu control, then this function will return NULL. - */ -struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, - const struct v4l2_ctrl_ops *ops, - u32 id, s32 max, s32 mask, s32 def); - -/** v4l2_ctrl_add_ctrl() - Add a control from another handler to this handler. - * @hdl: The control handler. - * @ctrl: The control to add. - * - * It will return NULL if it was unable to add the control reference. - * If the control already belonged to the handler, then it will do - * nothing and just return @ctrl. - */ -struct v4l2_ctrl *v4l2_ctrl_add_ctrl(struct v4l2_ctrl_handler *hdl, - struct v4l2_ctrl *ctrl); - -/** v4l2_ctrl_add_handler() - Add all controls from handler @add to - * handler @hdl. - * @hdl: The control handler. - * @add: The control handler whose controls you want to add to - * the @hdl control handler. - * - * Does nothing if either of the two is a NULL pointer. - * In case of an error @hdl->error will be set to the error code (if it - * wasn't set already). - */ -int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, - struct v4l2_ctrl_handler *add); - - -/** v4l2_ctrl_cluster() - Mark all controls in the cluster as belonging to that cluster. - * @ncontrols: The number of controls in this cluster. - * @controls: The cluster control array of size @ncontrols. - */ -void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls); - - -/** v4l2_ctrl_find() - Find a control with the given ID. - * @hdl: The control handler. - * @id: The control ID to find. - * - * If @hdl == NULL this will return NULL as well. Will lock the handler so - * do not use from inside &v4l2_ctrl_ops. - */ -struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id); - -/** v4l2_ctrl_activate() - Make the control active or inactive. - * @ctrl: The control to (de)activate. - * @active: True if the control should become active. - * - * This sets or clears the V4L2_CTRL_FLAG_INACTIVE flag atomically. - * Does nothing if @ctrl == NULL. - * This will usually be called from within the s_ctrl op. - * - * This function can be called regardless of whether the control handler - * is locked or not. - */ -void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active); - -/** v4l2_ctrl_grab() - Mark the control as grabbed or not grabbed. - * @ctrl: The control to (de)activate. - * @grabbed: True if the control should become grabbed. - * - * This sets or clears the V4L2_CTRL_FLAG_GRABBED flag atomically. - * Does nothing if @ctrl == NULL. - * This will usually be called when starting or stopping streaming in the - * driver. - * - * This function can be called regardless of whether the control handler - * is locked or not. - */ -void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed); - -/** v4l2_ctrl_lock() - Helper function to lock the handler - * associated with the control. - * @ctrl: The control to lock. - */ -static inline void v4l2_ctrl_lock(struct v4l2_ctrl *ctrl) -{ - mutex_lock(&ctrl->handler->lock); -} - -/** v4l2_ctrl_lock() - Helper function to unlock the handler - * associated with the control. - * @ctrl: The control to unlock. - */ -static inline void v4l2_ctrl_unlock(struct v4l2_ctrl *ctrl) -{ - mutex_unlock(&ctrl->handler->lock); -} - -/** v4l2_ctrl_g_ctrl() - Helper function to get the control's value from within a driver. - * @ctrl: The control. - * - * This returns the control's value safely by going through the control - * framework. This function will lock the control's handler, so it cannot be - * used from within the &v4l2_ctrl_ops functions. - * - * This function is for integer type controls only. - */ -s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl); - -/** v4l2_ctrl_s_ctrl() - Helper function to set the control's value from within a driver. - * @ctrl: The control. - * @val: The new value. - * - * This set the control's new value safely by going through the control - * framework. This function will lock the control's handler, so it cannot be - * used from within the &v4l2_ctrl_ops functions. - * - * This function is for integer type controls only. - */ -int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val); - - -/* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */ -int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc); -int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm); -int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl); -int v4l2_s_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl); -int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c); -int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c); -int v4l2_s_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c); - -/* Helpers for subdevices. If the associated ctrl_handler == NULL then they - will all return -EINVAL. */ -int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc); -int v4l2_subdev_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm); -int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs); -int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs); -int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs); -int v4l2_subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl); -int v4l2_subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-dev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-dev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-dev.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-dev.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,201 +0,0 @@ -/* - * - * V 4 L 2 D R I V E R H E L P E R A P I - * - * Moved from videodev2.h - * - * Some commonly needed functions for drivers (v4l2-common.o module) - */ -#ifndef _V4L2_DEV_H -#define _V4L2_DEV_H - -#include -#include -#include -#include -#include -#include - -#include - -#define VIDEO_MAJOR 81 - -#define VFL_TYPE_GRABBER 0 -#define VFL_TYPE_VBI 1 -#define VFL_TYPE_RADIO 2 -#define VFL_TYPE_SUBDEV 3 -#define VFL_TYPE_MAX 4 - -struct v4l2_ioctl_callbacks; -struct video_device; -struct v4l2_device; -struct v4l2_ctrl_handler; - -/* Flag to mark the video_device struct as registered. - Drivers can clear this flag if they want to block all future - device access. It is cleared by video_unregister_device. */ -#define V4L2_FL_REGISTERED (0) -/* file->private_data points to struct v4l2_fh */ -#define V4L2_FL_USES_V4L2_FH (1) -/* Use the prio field of v4l2_fh for core priority checking */ -#define V4L2_FL_USE_FH_PRIO (2) - -/* Priority helper functions */ - -struct v4l2_prio_state { - atomic_t prios[4]; -}; - -void v4l2_prio_init(struct v4l2_prio_state *global); -int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, - enum v4l2_priority new); -void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local); -void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local); -enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global); -int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local); - - -struct v4l2_file_operations { - struct module *owner; - ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); - ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); - unsigned int (*poll) (struct file *, struct poll_table_struct *); - long (*ioctl) (struct file *, unsigned int, unsigned long); - long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); - int (*mmap) (struct file *, struct vm_area_struct *); - int (*open) (struct file *); - int (*release) (struct file *); -}; - -/* - * Newer version of video_device, handled by videodev2.c - * This version moves redundant code from video device code to - * the common handler - */ - -struct video_device -{ -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity entity; -#endif - /* device ops */ - const struct v4l2_file_operations *fops; - - /* sysfs */ - struct device dev; /* v4l device */ - struct cdev *cdev; /* character device */ - - /* Set either parent or v4l2_dev if your driver uses v4l2_device */ - struct device *parent; /* device parent */ - struct v4l2_device *v4l2_dev; /* v4l2_device parent */ - - /* Control handler associated with this device node. May be NULL. */ - struct v4l2_ctrl_handler *ctrl_handler; - - /* Priority state. If NULL, then v4l2_dev->prio will be used. */ - struct v4l2_prio_state *prio; - - /* device info */ - char name[32]; - int vfl_type; - /* 'minor' is set to -1 if the registration failed */ - int minor; - u16 num; - /* use bitops to set/clear/test flags */ - unsigned long flags; - /* attribute to differentiate multiple indices on one physical device */ - int index; - - /* V4L2 file handles */ - spinlock_t fh_lock; /* Lock for all v4l2_fhs */ - struct list_head fh_list; /* List of struct v4l2_fh */ - - int debug; /* Activates debug level*/ - - /* Video standard vars */ - v4l2_std_id tvnorms; /* Supported tv norms */ - v4l2_std_id current_norm; /* Current tvnorm */ - - /* callbacks */ - void (*release)(struct video_device *vdev); - - /* ioctl callbacks */ - const struct v4l2_ioctl_ops *ioctl_ops; - - /* serialization lock */ - struct mutex *lock; -}; - -#define media_entity_to_video_device(entity) \ - container_of(entity, struct video_device, entity) -/* dev to video-device */ -#define to_video_device(cd) container_of(cd, struct video_device, dev) - -int __must_check __video_register_device(struct video_device *vdev, int type, - int nr, int warn_if_nr_in_use, struct module *owner); - -/* Register video devices. Note that if video_register_device fails, - the release() callback of the video_device structure is *not* called, so - the caller is responsible for freeing any data. Usually that means that - you call video_device_release() on failure. */ -static inline int __must_check video_register_device(struct video_device *vdev, - int type, int nr) -{ - return __video_register_device(vdev, type, nr, 1, vdev->fops->owner); -} - -/* Same as video_register_device, but no warning is issued if the desired - device node number was already in use. */ -static inline int __must_check video_register_device_no_warn( - struct video_device *vdev, int type, int nr) -{ - return __video_register_device(vdev, type, nr, 0, vdev->fops->owner); -} - -/* Unregister video devices. Will do nothing if vdev == NULL or - video_is_registered() returns false. */ -void video_unregister_device(struct video_device *vdev); - -/* helper functions to alloc/release struct video_device, the - latter can also be used for video_device->release(). */ -struct video_device * __must_check video_device_alloc(void); - -/* this release function frees the vdev pointer */ -void video_device_release(struct video_device *vdev); - -/* this release function does nothing, use when the video_device is a - static global struct. Note that having a static video_device is - a dubious construction at best. */ -void video_device_release_empty(struct video_device *vdev); - -/* helper functions to access driver private data. */ -static inline void *video_get_drvdata(struct video_device *vdev) -{ - return dev_get_drvdata(&vdev->dev); -} - -static inline void video_set_drvdata(struct video_device *vdev, void *data) -{ - dev_set_drvdata(&vdev->dev, data); -} - -struct video_device *video_devdata(struct file *file); - -/* Combine video_get_drvdata and video_devdata as this is - used very often. */ -static inline void *video_drvdata(struct file *file) -{ - return video_get_drvdata(video_devdata(file)); -} - -static inline const char *video_device_node_name(struct video_device *vdev) -{ - return dev_name(&vdev->dev); -} - -static inline int video_is_registered(struct video_device *vdev) -{ - return test_bit(V4L2_FL_REGISTERED, &vdev->flags); -} - -#endif /* _V4L2_DEV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-device.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-device.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-device.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,193 +0,0 @@ -/* - V4L2 device support header. - - Copyright (C) 2008 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef _V4L2_DEVICE_H -#define _V4L2_DEVICE_H - -#include -#include -#include - -/* Each instance of a V4L2 device should create the v4l2_device struct, - either stand-alone or embedded in a larger struct. - - It allows easy access to sub-devices (see v4l2-subdev.h) and provides - basic V4L2 device-level support. - */ - -#define V4L2_DEVICE_NAME_SIZE (20 + 16) - -struct v4l2_ctrl_handler; - -struct v4l2_device { - /* dev->driver_data points to this struct. - Note: dev might be NULL if there is no parent device - as is the case with e.g. ISA devices. */ - struct device *dev; -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_device *mdev; -#endif - /* used to keep track of the registered subdevs */ - struct list_head subdevs; - /* lock this struct; can be used by the driver as well if this - struct is embedded into a larger struct. */ - spinlock_t lock; - /* unique device name, by default the driver name + bus ID */ - char name[V4L2_DEVICE_NAME_SIZE]; - /* notify callback called by some sub-devices. */ - void (*notify)(struct v4l2_subdev *sd, - unsigned int notification, void *arg); - /* The control handler. May be NULL. */ - struct v4l2_ctrl_handler *ctrl_handler; - /* Device's priority state */ - struct v4l2_prio_state prio; - /* BKL replacement mutex. Temporary solution only. */ - struct mutex ioctl_lock; - /* Keep track of the references to this struct. */ - struct kref ref; - /* Release function that is called when the ref count goes to 0. */ - void (*release)(struct v4l2_device *v4l2_dev); -}; - -static inline void v4l2_device_get(struct v4l2_device *v4l2_dev) -{ - kref_get(&v4l2_dev->ref); -} - -int v4l2_device_put(struct v4l2_device *v4l2_dev); - -/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev. - dev may be NULL in rare cases (ISA devices). In that case you - must fill in the v4l2_dev->name field before calling this function. */ -int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev); - -/* Optional function to initialize the name field of struct v4l2_device using - the driver name and a driver-global atomic_t instance. - This function will increment the instance counter and returns the instance - value used in the name. - - Example: - - static atomic_t drv_instance = ATOMIC_INIT(0); - - ... - - instance = v4l2_device_set_name(&v4l2_dev, "foo", &drv_instance); - - The first time this is called the name field will be set to foo0 and - this function returns 0. If the name ends with a digit (e.g. cx18), - then the name will be set to cx18-0 since cx180 looks really odd. */ -int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename, - atomic_t *instance); - -/* Set v4l2_dev->dev to NULL. Call when the USB parent disconnects. - Since the parent disappears this ensures that v4l2_dev doesn't have an - invalid parent pointer. */ -void v4l2_device_disconnect(struct v4l2_device *v4l2_dev); - -/* Unregister all sub-devices and any other resources related to v4l2_dev. */ -void v4l2_device_unregister(struct v4l2_device *v4l2_dev); - -/* Register a subdev with a v4l2 device. While registered the subdev module - is marked as in-use. An error is returned if the module is no longer - loaded when you attempt to register it. */ -int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, - struct v4l2_subdev *sd); -/* Unregister a subdev with a v4l2 device. Can also be called if the subdev - wasn't registered. In that case it will do nothing. */ -void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); - -/* Register device nodes for all subdev of the v4l2 device that are marked with - * the V4L2_SUBDEV_FL_HAS_DEVNODE flag. - */ -int __must_check -v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev); - -/* Iterate over all subdevs. */ -#define v4l2_device_for_each_subdev(sd, v4l2_dev) \ - list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) - -/* Call the specified callback for all subdevs matching the condition. - Ignore any errors. Note that you cannot add or delete a subdev - while walking the subdevs list. */ -#define __v4l2_device_call_subdevs_p(v4l2_dev, sd, cond, o, f, args...) \ - do { \ - list_for_each_entry((sd), &(v4l2_dev)->subdevs, list) \ - if ((cond) && (sd)->ops->o && (sd)->ops->o->f) \ - (sd)->ops->o->f((sd) , ##args); \ - } while (0) - -#define __v4l2_device_call_subdevs(v4l2_dev, cond, o, f, args...) \ - do { \ - struct v4l2_subdev *__sd; \ - \ - __v4l2_device_call_subdevs_p(v4l2_dev, __sd, cond, o, \ - f , ##args); \ - } while (0) - -/* Call the specified callback for all subdevs matching the condition. - If the callback returns an error other than 0 or -ENOIOCTLCMD, then - return with that error code. Note that you cannot add or delete a - subdev while walking the subdevs list. */ -#define __v4l2_device_call_subdevs_until_err_p(v4l2_dev, sd, cond, o, f, args...) \ -({ \ - long __err = 0; \ - \ - list_for_each_entry((sd), &(v4l2_dev)->subdevs, list) { \ - if ((cond) && (sd)->ops->o && (sd)->ops->o->f) \ - __err = (sd)->ops->o->f((sd) , ##args); \ - if (__err && __err != -ENOIOCTLCMD) \ - break; \ - } \ - (__err == -ENOIOCTLCMD) ? 0 : __err; \ -}) - -#define __v4l2_device_call_subdevs_until_err(v4l2_dev, cond, o, f, args...) \ -({ \ - struct v4l2_subdev *__sd; \ - __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd, cond, o, \ - f, args...); \ -}) - -/* Call the specified callback for all subdevs matching grp_id (if 0, then - match them all). Ignore any errors. Note that you cannot add or delete - a subdev while walking the subdevs list. */ -#define v4l2_device_call_all(v4l2_dev, grpid, o, f, args...) \ - do { \ - struct v4l2_subdev *__sd; \ - \ - __v4l2_device_call_subdevs_p(v4l2_dev, __sd, \ - !(grpid) || __sd->grp_id == (grpid), o, f , \ - ##args); \ - } while (0) - -/* Call the specified callback for all subdevs matching grp_id (if 0, then - match them all). If the callback returns an error other than 0 or - -ENOIOCTLCMD, then return with that error code. Note that you cannot - add or delete a subdev while walking the subdevs list. */ -#define v4l2_device_call_until_err(v4l2_dev, grpid, o, f, args...) \ -({ \ - struct v4l2_subdev *__sd; \ - __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd, \ - !(grpid) || __sd->grp_id == (grpid), o, f , \ - ##args); \ -}) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-event.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-event.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-event.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-event.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -/* - * v4l2-event.h - * - * V4L2 events. - * - * Copyright (C) 2009--2010 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef V4L2_EVENT_H -#define V4L2_EVENT_H - -#include -#include -#include - -struct v4l2_fh; -struct video_device; - -struct v4l2_kevent { - struct list_head list; - struct v4l2_event event; -}; - -struct v4l2_subscribed_event { - struct list_head list; - u32 type; -}; - -struct v4l2_events { - wait_queue_head_t wait; - struct list_head subscribed; /* Subscribed events */ - struct list_head free; /* Events ready for use */ - struct list_head available; /* Dequeueable event */ - unsigned int navailable; - unsigned int nallocated; /* Number of allocated events */ - u32 sequence; -}; - -int v4l2_event_init(struct v4l2_fh *fh); -int v4l2_event_alloc(struct v4l2_fh *fh, unsigned int n); -void v4l2_event_free(struct v4l2_fh *fh); -int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event, - int nonblocking); -void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev); -int v4l2_event_pending(struct v4l2_fh *fh); -int v4l2_event_subscribe(struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); -int v4l2_event_unsubscribe(struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); - -#endif /* V4L2_EVENT_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-fh.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-fh.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-fh.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-fh.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -/* - * v4l2-fh.h - * - * V4L2 file handle. Store per file handle data for the V4L2 - * framework. Using file handles is optional for the drivers. - * - * Copyright (C) 2009--2010 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef V4L2_FH_H -#define V4L2_FH_H - -#include - -struct video_device; -struct v4l2_events; - -struct v4l2_fh { - struct list_head list; - struct video_device *vdev; - struct v4l2_events *events; /* events, pending and subscribed */ - enum v4l2_priority prio; -}; - -/* - * Initialise the file handle. Parts of the V4L2 framework using the - * file handles should be initialised in this function. Must be called - * from driver's v4l2_file_operations->open() handler if the driver - * uses v4l2_fh. - */ -int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev); -/* - * Add the fh to the list of file handles on a video_device. The file - * handle must be initialised first. - */ -void v4l2_fh_add(struct v4l2_fh *fh); -/* - * Can be used as the open() op of v4l2_file_operations. - * It allocates a v4l2_fh and inits and adds it to the video_device associated - * with the file pointer. - */ -int v4l2_fh_open(struct file *filp); -/* - * Remove file handle from the list of file handles. Must be called in - * v4l2_file_operations->release() handler if the driver uses v4l2_fh. - * On error filp->private_data will be NULL, otherwise it will point to - * the v4l2_fh struct. - */ -void v4l2_fh_del(struct v4l2_fh *fh); -/* - * Release resources related to a file handle. Parts of the V4L2 - * framework using the v4l2_fh must release their resources here, too. - * Must be called in v4l2_file_operations->release() handler if the - * driver uses v4l2_fh. - */ -void v4l2_fh_exit(struct v4l2_fh *fh); -/* - * Can be used as the release() op of v4l2_file_operations. - * It deletes and exits the v4l2_fh associated with the file pointer and - * frees it. It will do nothing if filp->private_data (the pointer to the - * v4l2_fh struct) is NULL. This function always returns 0. - */ -int v4l2_fh_release(struct file *filp); -/* - * Returns 1 if this filehandle is the only filehandle opened for the - * associated video_device. If fh is NULL, then it returns 0. - */ -int v4l2_fh_is_singular(struct v4l2_fh *fh); -/* - * Helper function with struct file as argument. If filp->private_data is - * NULL, then it will return 0. - */ -static inline int v4l2_fh_is_singular_file(struct file *filp) -{ - return v4l2_fh_is_singular(filp->private_data); -} - -#endif /* V4L2_EVENT_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-int-device.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-int-device.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-int-device.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-int-device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,307 +0,0 @@ -/* - * include/media/v4l2-int-device.h - * - * V4L2 internal ioctl interface. - * - * Copyright (C) 2007 Nokia Corporation. - * - * Contact: Sakari Ailus - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef V4L2_INT_DEVICE_H -#define V4L2_INT_DEVICE_H - -#include -#include - -#define V4L2NAMESIZE 32 - -/* - * - * The internal V4L2 device interface core. - * - */ - -enum v4l2_int_type { - v4l2_int_type_master = 1, - v4l2_int_type_slave -}; - -struct v4l2_int_device; - -struct v4l2_int_master { - int (*attach)(struct v4l2_int_device *slave); - void (*detach)(struct v4l2_int_device *slave); -}; - -typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); -typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); -typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); - -struct v4l2_int_ioctl_desc { - int num; - v4l2_int_ioctl_func *func; -}; - -struct v4l2_int_slave { - /* Don't touch master. */ - struct v4l2_int_device *master; - - char attach_to[V4L2NAMESIZE]; - - int num_ioctls; - struct v4l2_int_ioctl_desc *ioctls; -}; - -struct v4l2_int_device { - /* Don't touch head. */ - struct list_head head; - - struct module *module; - - char name[V4L2NAMESIZE]; - - enum v4l2_int_type type; - union { - struct v4l2_int_master *master; - struct v4l2_int_slave *slave; - } u; - - void *priv; -}; - -void v4l2_int_device_try_attach_all(void); - -int v4l2_int_device_register(struct v4l2_int_device *d); -void v4l2_int_device_unregister(struct v4l2_int_device *d); - -int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); -int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); - -/* - * - * Types and definitions for IOCTL commands. - * - */ - -enum v4l2_power { - V4L2_POWER_OFF = 0, - V4L2_POWER_ON, - V4L2_POWER_STANDBY, -}; - -/* Slave interface type. */ -enum v4l2_if_type { - /* - * Parallel 8-, 10- or 12-bit interface, used by for example - * on certain image sensors. - */ - V4L2_IF_TYPE_BT656, -}; - -enum v4l2_if_type_bt656_mode { - /* - * Modes without Bt synchronisation codes. Separate - * synchronisation signal lines are used. - */ - V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT, - V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT, - V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT, - /* - * Use Bt synchronisation codes. The vertical and horizontal - * synchronisation is done based on synchronisation codes. - */ - V4L2_IF_TYPE_BT656_MODE_BT_8BIT, - V4L2_IF_TYPE_BT656_MODE_BT_10BIT, -}; - -struct v4l2_if_type_bt656 { - /* - * 0: Frame begins when vsync is high. - * 1: Frame begins when vsync changes from low to high. - */ - unsigned frame_start_on_rising_vs:1; - /* Use Bt synchronisation codes for sync correction. */ - unsigned bt_sync_correct:1; - /* Swap every two adjacent image data elements. */ - unsigned swap:1; - /* Inverted latch clock polarity from slave. */ - unsigned latch_clk_inv:1; - /* Hs polarity. 0 is active high, 1 active low. */ - unsigned nobt_hs_inv:1; - /* Vs polarity. 0 is active high, 1 active low. */ - unsigned nobt_vs_inv:1; - enum v4l2_if_type_bt656_mode mode; - /* Minimum accepted bus clock for slave (in Hz). */ - u32 clock_min; - /* Maximum accepted bus clock for slave. */ - u32 clock_max; - /* - * Current wish of the slave. May only change in response to - * ioctls that affect image capture. - */ - u32 clock_curr; -}; - -struct v4l2_ifparm { - enum v4l2_if_type if_type; - union { - struct v4l2_if_type_bt656 bt656; - } u; -}; - -/* IOCTL command numbers. */ -enum v4l2_int_ioctl_num { - /* - * - * "Proper" V4L ioctls, as in struct video_device. - * - */ - vidioc_int_enum_fmt_cap_num = 1, - vidioc_int_g_fmt_cap_num, - vidioc_int_s_fmt_cap_num, - vidioc_int_try_fmt_cap_num, - vidioc_int_queryctrl_num, - vidioc_int_g_ctrl_num, - vidioc_int_s_ctrl_num, - vidioc_int_cropcap_num, - vidioc_int_g_crop_num, - vidioc_int_s_crop_num, - vidioc_int_g_parm_num, - vidioc_int_s_parm_num, - vidioc_int_querystd_num, - vidioc_int_s_std_num, - vidioc_int_s_video_routing_num, - - /* - * - * Strictly internal ioctls. - * - */ - /* Initialise the device when slave attaches to the master. */ - vidioc_int_dev_init_num = 1000, - /* Delinitialise the device at slave detach. */ - vidioc_int_dev_exit_num, - /* Set device power state. */ - vidioc_int_s_power_num, - /* - * Get slave private data, e.g. platform-specific slave - * configuration used by the master. - */ - vidioc_int_g_priv_num, - /* Get slave interface parameters. */ - vidioc_int_g_ifparm_num, - /* Does the slave need to be reset after VIDIOC_DQBUF? */ - vidioc_int_g_needs_reset_num, - vidioc_int_enum_framesizes_num, - vidioc_int_enum_frameintervals_num, - - /* - * - * VIDIOC_INT_* ioctls. - * - */ - /* VIDIOC_INT_RESET */ - vidioc_int_reset_num, - /* VIDIOC_INT_INIT */ - vidioc_int_init_num, - /* VIDIOC_DBG_G_CHIP_IDENT */ - vidioc_int_g_chip_ident_num, - - /* - * - * Start of private ioctls. - * - */ - vidioc_int_priv_start_num = 2000, -}; - -/* - * - * IOCTL wrapper functions for better type checking. - * - */ - -#define V4L2_INT_WRAPPER_0(name) \ - static inline int vidioc_int_##name(struct v4l2_int_device *d) \ - { \ - return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \ - } \ - \ - static inline struct v4l2_int_ioctl_desc \ - vidioc_int_##name##_cb(int (*func) \ - (struct v4l2_int_device *)) \ - { \ - struct v4l2_int_ioctl_desc desc; \ - \ - desc.num = vidioc_int_##name##_num; \ - desc.func = (v4l2_int_ioctl_func *)func; \ - \ - return desc; \ - } - -#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \ - static inline int vidioc_int_##name(struct v4l2_int_device *d, \ - arg_type asterisk arg) \ - { \ - return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ - (void *)(unsigned long)arg); \ - } \ - \ - static inline struct v4l2_int_ioctl_desc \ - vidioc_int_##name##_cb(int (*func) \ - (struct v4l2_int_device *, \ - arg_type asterisk)) \ - { \ - struct v4l2_int_ioctl_desc desc; \ - \ - desc.num = vidioc_int_##name##_num; \ - desc.func = (v4l2_int_ioctl_func *)func; \ - \ - return desc; \ - } - -V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *); -V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *); -V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *); -V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *); -V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *); -V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *); -V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *); -V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *); -V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *); -V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *); -V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *); -V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); -V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *); -V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *); -V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *); - -V4L2_INT_WRAPPER_0(dev_init); -V4L2_INT_WRAPPER_0(dev_exit); -V4L2_INT_WRAPPER_1(s_power, enum v4l2_power, ); -V4L2_INT_WRAPPER_1(g_priv, void, *); -V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); -V4L2_INT_WRAPPER_1(g_needs_reset, void, *); -V4L2_INT_WRAPPER_1(enum_framesizes, struct v4l2_frmsizeenum, *); -V4L2_INT_WRAPPER_1(enum_frameintervals, struct v4l2_frmivalenum, *); - -V4L2_INT_WRAPPER_0(reset); -V4L2_INT_WRAPPER_0(init); -V4L2_INT_WRAPPER_1(g_chip_ident, int, *); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-ioctl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-ioctl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-ioctl.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-ioctl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,327 +0,0 @@ -/* - * - * V 4 L 2 D R I V E R H E L P E R A P I - * - * Moved from videodev2.h - * - * Some commonly needed functions for drivers (v4l2-common.o module) - */ -#ifndef _V4L2_IOCTL_H -#define _V4L2_IOCTL_H - -#include -#include -#include -#include -#include /* need __user */ -#include - -struct v4l2_fh; - -struct v4l2_ioctl_ops { - /* ioctl callbacks */ - - /* VIDIOC_QUERYCAP handler */ - int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap); - - /* Priority handling */ - int (*vidioc_g_priority) (struct file *file, void *fh, - enum v4l2_priority *p); - int (*vidioc_s_priority) (struct file *file, void *fh, - enum v4l2_priority p); - - /* VIDIOC_ENUM_FMT handlers */ - int (*vidioc_enum_fmt_vid_cap) (struct file *file, void *fh, - struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vid_overlay) (struct file *file, void *fh, - struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vid_out) (struct file *file, void *fh, - struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vid_cap_mplane)(struct file *file, void *fh, - struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vid_out_mplane)(struct file *file, void *fh, - struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh, - struct v4l2_fmtdesc *f); - - /* VIDIOC_G_FMT handlers */ - int (*vidioc_g_fmt_vid_cap) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_vid_out) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_vbi_cap) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_vbi_out) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_vid_cap_mplane)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_vid_out_mplane)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_g_fmt_type_private)(struct file *file, void *fh, - struct v4l2_format *f); - - /* VIDIOC_S_FMT handlers */ - int (*vidioc_s_fmt_vid_cap) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_vid_out) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_vbi_cap) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_vbi_out) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_vid_cap_mplane)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_vid_out_mplane)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_s_fmt_type_private)(struct file *file, void *fh, - struct v4l2_format *f); - - /* VIDIOC_TRY_FMT handlers */ - int (*vidioc_try_fmt_vid_cap) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_vid_out) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_vbi_cap) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_vbi_out) (struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_vid_cap_mplane)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_vid_out_mplane)(struct file *file, void *fh, - struct v4l2_format *f); - int (*vidioc_try_fmt_type_private)(struct file *file, void *fh, - struct v4l2_format *f); - - /* Buffer handlers */ - int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b); - int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b); - int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b); - int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b); - - - int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i); - int (*vidioc_g_fbuf) (struct file *file, void *fh, - struct v4l2_framebuffer *a); - int (*vidioc_s_fbuf) (struct file *file, void *fh, - struct v4l2_framebuffer *a); - - /* Stream on/off */ - int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i); - int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i); - - /* Standard handling - ENUMSTD is handled by videodev.c - */ - int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm); - int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm); - int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a); - - /* Input handling */ - int (*vidioc_enum_input)(struct file *file, void *fh, - struct v4l2_input *inp); - int (*vidioc_g_input) (struct file *file, void *fh, unsigned int *i); - int (*vidioc_s_input) (struct file *file, void *fh, unsigned int i); - - /* Output handling */ - int (*vidioc_enum_output) (struct file *file, void *fh, - struct v4l2_output *a); - int (*vidioc_g_output) (struct file *file, void *fh, unsigned int *i); - int (*vidioc_s_output) (struct file *file, void *fh, unsigned int i); - - /* Control handling */ - int (*vidioc_queryctrl) (struct file *file, void *fh, - struct v4l2_queryctrl *a); - int (*vidioc_g_ctrl) (struct file *file, void *fh, - struct v4l2_control *a); - int (*vidioc_s_ctrl) (struct file *file, void *fh, - struct v4l2_control *a); - int (*vidioc_g_ext_ctrls) (struct file *file, void *fh, - struct v4l2_ext_controls *a); - int (*vidioc_s_ext_ctrls) (struct file *file, void *fh, - struct v4l2_ext_controls *a); - int (*vidioc_try_ext_ctrls) (struct file *file, void *fh, - struct v4l2_ext_controls *a); - int (*vidioc_querymenu) (struct file *file, void *fh, - struct v4l2_querymenu *a); - - /* Audio ioctls */ - int (*vidioc_enumaudio) (struct file *file, void *fh, - struct v4l2_audio *a); - int (*vidioc_g_audio) (struct file *file, void *fh, - struct v4l2_audio *a); - int (*vidioc_s_audio) (struct file *file, void *fh, - struct v4l2_audio *a); - - /* Audio out ioctls */ - int (*vidioc_enumaudout) (struct file *file, void *fh, - struct v4l2_audioout *a); - int (*vidioc_g_audout) (struct file *file, void *fh, - struct v4l2_audioout *a); - int (*vidioc_s_audout) (struct file *file, void *fh, - struct v4l2_audioout *a); - int (*vidioc_g_modulator) (struct file *file, void *fh, - struct v4l2_modulator *a); - int (*vidioc_s_modulator) (struct file *file, void *fh, - struct v4l2_modulator *a); - /* Crop ioctls */ - int (*vidioc_cropcap) (struct file *file, void *fh, - struct v4l2_cropcap *a); - int (*vidioc_g_crop) (struct file *file, void *fh, - struct v4l2_crop *a); - int (*vidioc_s_crop) (struct file *file, void *fh, - struct v4l2_crop *a); - /* Compression ioctls */ - int (*vidioc_g_jpegcomp) (struct file *file, void *fh, - struct v4l2_jpegcompression *a); - int (*vidioc_s_jpegcomp) (struct file *file, void *fh, - struct v4l2_jpegcompression *a); - int (*vidioc_g_enc_index) (struct file *file, void *fh, - struct v4l2_enc_idx *a); - int (*vidioc_encoder_cmd) (struct file *file, void *fh, - struct v4l2_encoder_cmd *a); - int (*vidioc_try_encoder_cmd) (struct file *file, void *fh, - struct v4l2_encoder_cmd *a); - - /* Stream type-dependent parameter ioctls */ - int (*vidioc_g_parm) (struct file *file, void *fh, - struct v4l2_streamparm *a); - int (*vidioc_s_parm) (struct file *file, void *fh, - struct v4l2_streamparm *a); - - /* Tuner ioctls */ - int (*vidioc_g_tuner) (struct file *file, void *fh, - struct v4l2_tuner *a); - int (*vidioc_s_tuner) (struct file *file, void *fh, - struct v4l2_tuner *a); - int (*vidioc_g_frequency) (struct file *file, void *fh, - struct v4l2_frequency *a); - int (*vidioc_s_frequency) (struct file *file, void *fh, - struct v4l2_frequency *a); - - /* Sliced VBI cap */ - int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh, - struct v4l2_sliced_vbi_cap *a); - - /* Log status ioctl */ - int (*vidioc_log_status) (struct file *file, void *fh); - - int (*vidioc_s_hw_freq_seek) (struct file *file, void *fh, - struct v4l2_hw_freq_seek *a); - - /* Debugging ioctls */ -#ifdef CONFIG_VIDEO_ADV_DEBUG - int (*vidioc_g_register) (struct file *file, void *fh, - struct v4l2_dbg_register *reg); - int (*vidioc_s_register) (struct file *file, void *fh, - struct v4l2_dbg_register *reg); -#endif - int (*vidioc_g_chip_ident) (struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip); - - int (*vidioc_enum_framesizes) (struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize); - - int (*vidioc_enum_frameintervals) (struct file *file, void *fh, - struct v4l2_frmivalenum *fival); - - /* DV Timings IOCTLs */ - int (*vidioc_enum_dv_presets) (struct file *file, void *fh, - struct v4l2_dv_enum_preset *preset); - - int (*vidioc_s_dv_preset) (struct file *file, void *fh, - struct v4l2_dv_preset *preset); - int (*vidioc_g_dv_preset) (struct file *file, void *fh, - struct v4l2_dv_preset *preset); - int (*vidioc_query_dv_preset) (struct file *file, void *fh, - struct v4l2_dv_preset *qpreset); - int (*vidioc_s_dv_timings) (struct file *file, void *fh, - struct v4l2_dv_timings *timings); - int (*vidioc_g_dv_timings) (struct file *file, void *fh, - struct v4l2_dv_timings *timings); - - int (*vidioc_subscribe_event) (struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); - int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); - - /* For other private ioctls */ - long (*vidioc_default) (struct file *file, void *fh, - bool valid_prio, int cmd, void *arg); -}; - - -/* v4l debugging and diagnostics */ - -/* Debug bitmask flags to be used on V4L2 */ -#define V4L2_DEBUG_IOCTL 0x01 -#define V4L2_DEBUG_IOCTL_ARG 0x02 - -/* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */ -#define v4l_print_ioctl(name, cmd) \ - do { \ - printk(KERN_DEBUG "%s: ", name); \ - v4l_printk_ioctl(cmd); \ - } while (0) - -/* Use this macro in I2C drivers where 'client' is the struct i2c_client - pointer */ -#define v4l_i2c_print_ioctl(client, cmd) \ - do { \ - v4l_client_printk(KERN_DEBUG, client, ""); \ - v4l_printk_ioctl(cmd); \ - } while (0) - -/* Video standard functions */ -extern const char *v4l2_norm_to_name(v4l2_std_id id); -extern void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod); -extern int v4l2_video_std_construct(struct v4l2_standard *vs, - int id, const char *name); -/* Prints the ioctl in a human-readable format */ -extern void v4l_printk_ioctl(unsigned int cmd); - -/* names for fancy debug output */ -extern const char *v4l2_field_names[]; -extern const char *v4l2_type_names[]; - -#ifdef CONFIG_COMPAT -/* 32 Bits compatibility layer for 64 bits processors */ -extern long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, - unsigned long arg); -#endif - -typedef long (*v4l2_kioctl)(struct file *file, - unsigned int cmd, void *arg); - -/* Include support for obsoleted stuff */ -extern long video_usercopy(struct file *file, unsigned int cmd, - unsigned long arg, v4l2_kioctl func); - -/* Standard handlers for V4L ioctl's */ -extern long video_ioctl2(struct file *file, - unsigned int cmd, unsigned long arg); - -#endif /* _V4L2_IOCTL_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-mediabus.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-mediabus.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-mediabus.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-mediabus.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* - * Media Bus API header - * - * Copyright (C) 2009, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef V4L2_MEDIABUS_H -#define V4L2_MEDIABUS_H - -#include - -static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt, - const struct v4l2_mbus_framefmt *mbus_fmt) -{ - pix_fmt->width = mbus_fmt->width; - pix_fmt->height = mbus_fmt->height; - pix_fmt->field = mbus_fmt->field; - pix_fmt->colorspace = mbus_fmt->colorspace; -} - -static inline void v4l2_fill_mbus_format(struct v4l2_mbus_framefmt *mbus_fmt, - const struct v4l2_pix_format *pix_fmt, - enum v4l2_mbus_pixelcode code) -{ - mbus_fmt->width = pix_fmt->width; - mbus_fmt->height = pix_fmt->height; - mbus_fmt->field = pix_fmt->field; - mbus_fmt->colorspace = pix_fmt->colorspace; - mbus_fmt->code = code; -} - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-mem2mem.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-mem2mem.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-mem2mem.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-mem2mem.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,215 +0,0 @@ -/* - * Memory-to-memory device framework for Video for Linux 2. - * - * Helper functions for devices that use memory buffers for both source - * and destination. - * - * Copyright (c) 2009 Samsung Electronics Co., Ltd. - * Pawel Osciak, - * Marek Szyprowski, - * - * 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, or (at your option) any later version - */ - -#ifndef _MEDIA_V4L2_MEM2MEM_H -#define _MEDIA_V4L2_MEM2MEM_H - -#include - -/** - * struct v4l2_m2m_ops - mem-to-mem device driver callbacks - * @device_run: required. Begin the actual job (transaction) inside this - * callback. - * The job does NOT have to end before this callback returns - * (and it will be the usual case). When the job finishes, - * v4l2_m2m_job_finish() has to be called. - * @job_ready: optional. Should return 0 if the driver does not have a job - * fully prepared to run yet (i.e. it will not be able to finish a - * transaction without sleeping). If not provided, it will be - * assumed that one source and one destination buffer are all - * that is required for the driver to perform one full transaction. - * This method may not sleep. - * @job_abort: required. Informs the driver that it has to abort the currently - * running transaction as soon as possible (i.e. as soon as it can - * stop the device safely; e.g. in the next interrupt handler), - * even if the transaction would not have been finished by then. - * After the driver performs the necessary steps, it has to call - * v4l2_m2m_job_finish() (as if the transaction ended normally). - * This function does not have to (and will usually not) wait - * until the device enters a state when it can be stopped. - */ -struct v4l2_m2m_ops { - void (*device_run)(void *priv); - int (*job_ready)(void *priv); - void (*job_abort)(void *priv); - void (*lock)(void *priv); - void (*unlock)(void *priv); -}; - -struct v4l2_m2m_dev; - -struct v4l2_m2m_queue_ctx { -/* private: internal use only */ - struct vb2_queue q; - - /* Queue for buffers ready to be processed as soon as this - * instance receives access to the device */ - struct list_head rdy_queue; - spinlock_t rdy_spinlock; - u8 num_rdy; -}; - -struct v4l2_m2m_ctx { -/* private: internal use only */ - struct v4l2_m2m_dev *m2m_dev; - - /* Capture (output to memory) queue context */ - struct v4l2_m2m_queue_ctx cap_q_ctx; - - /* Output (input from memory) queue context */ - struct v4l2_m2m_queue_ctx out_q_ctx; - - /* For device job queue */ - struct list_head queue; - unsigned long job_flags; - wait_queue_head_t finished; - - /* Instance private data */ - void *priv; -}; - -struct v4l2_m2m_buffer { - struct vb2_buffer vb; - struct list_head list; -}; - -void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev); - -struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, - enum v4l2_buf_type type); - -void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, - struct v4l2_m2m_ctx *m2m_ctx); - -static inline void -v4l2_m2m_buf_done(struct vb2_buffer *buf, enum vb2_buffer_state state) -{ - vb2_buffer_done(buf, state); -} - -int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct v4l2_requestbuffers *reqbufs); - -int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct v4l2_buffer *buf); - -int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct v4l2_buffer *buf); -int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct v4l2_buffer *buf); - -int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - enum v4l2_buf_type type); -int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - enum v4l2_buf_type type); - -unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct poll_table_struct *wait); - -int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, - struct vm_area_struct *vma); - -struct v4l2_m2m_dev *v4l2_m2m_init(struct v4l2_m2m_ops *m2m_ops); -void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev); - -struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev, - void *drv_priv, - int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)); - -void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx); - -void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb); - -/** - * v4l2_m2m_num_src_bufs_ready() - return the number of source buffers ready for - * use - */ -static inline -unsigned int v4l2_m2m_num_src_bufs_ready(struct v4l2_m2m_ctx *m2m_ctx) -{ - return m2m_ctx->cap_q_ctx.num_rdy; -} - -/** - * v4l2_m2m_num_src_bufs_ready() - return the number of destination buffers - * ready for use - */ -static inline -unsigned int v4l2_m2m_num_dst_bufs_ready(struct v4l2_m2m_ctx *m2m_ctx) -{ - return m2m_ctx->out_q_ctx.num_rdy; -} - -void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx); - -/** - * v4l2_m2m_next_src_buf() - return next source buffer from the list of ready - * buffers - */ -static inline void *v4l2_m2m_next_src_buf(struct v4l2_m2m_ctx *m2m_ctx) -{ - return v4l2_m2m_next_buf(&m2m_ctx->out_q_ctx); -} - -/** - * v4l2_m2m_next_dst_buf() - return next destination buffer from the list of - * ready buffers - */ -static inline void *v4l2_m2m_next_dst_buf(struct v4l2_m2m_ctx *m2m_ctx) -{ - return v4l2_m2m_next_buf(&m2m_ctx->cap_q_ctx); -} - -/** - * v4l2_m2m_get_src_vq() - return vb2_queue for source buffers - */ -static inline -struct vb2_queue *v4l2_m2m_get_src_vq(struct v4l2_m2m_ctx *m2m_ctx) -{ - return &m2m_ctx->out_q_ctx.q; -} - -/** - * v4l2_m2m_get_dst_vq() - return vb2_queue for destination buffers - */ -static inline -struct vb2_queue *v4l2_m2m_get_dst_vq(struct v4l2_m2m_ctx *m2m_ctx) -{ - return &m2m_ctx->cap_q_ctx.q; -} - -void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx); - -/** - * v4l2_m2m_src_buf_remove() - take off a source buffer from the list of ready - * buffers and return it - */ -static inline void *v4l2_m2m_src_buf_remove(struct v4l2_m2m_ctx *m2m_ctx) -{ - return v4l2_m2m_buf_remove(&m2m_ctx->out_q_ctx); -} - -/** - * v4l2_m2m_dst_buf_remove() - take off a destination buffer from the list of - * ready buffers and return it - */ -static inline void *v4l2_m2m_dst_buf_remove(struct v4l2_m2m_ctx *m2m_ctx) -{ - return v4l2_m2m_buf_remove(&m2m_ctx->cap_q_ctx); -} - -#endif /* _MEDIA_V4L2_MEM2MEM_H */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-subdev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-subdev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-subdev.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/v4l2-subdev.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,588 +0,0 @@ -/* - V4L2 sub-device support header. - - Copyright (C) 2008 Hans Verkuil - - 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, or - (at your option) any later version. - - 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 - */ - -#ifndef _V4L2_SUBDEV_H -#define _V4L2_SUBDEV_H - -#include -#include -#include -#include -#include -#include - -/* generic v4l2_device notify callback notification values */ -#define V4L2_SUBDEV_IR_RX_NOTIFY _IOW('v', 0, u32) -#define V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ 0x00000001 -#define V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED 0x00000002 -#define V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN 0x00000004 -#define V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN 0x00000008 - -#define V4L2_SUBDEV_IR_TX_NOTIFY _IOW('v', 1, u32) -#define V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ 0x00000001 - -struct v4l2_device; -struct v4l2_ctrl_handler; -struct v4l2_event_subscription; -struct v4l2_fh; -struct v4l2_subdev; -struct v4l2_subdev_fh; -struct tuner_setup; - -/* decode_vbi_line */ -struct v4l2_decode_vbi_line { - u32 is_second_field; /* Set to 0 for the first (odd) field, - set to 1 for the second (even) field. */ - u8 *p; /* Pointer to the sliced VBI data from the decoder. - On exit points to the start of the payload. */ - u32 line; /* Line number of the sliced VBI data (1-23) */ - u32 type; /* VBI service type (V4L2_SLICED_*). 0 if no service found */ -}; - -/* Sub-devices are devices that are connected somehow to the main bridge - device. These devices are usually audio/video muxers/encoders/decoders or - sensors and webcam controllers. - - Usually these devices are controlled through an i2c bus, but other busses - may also be used. - - The v4l2_subdev struct provides a way of accessing these devices in a - generic manner. Most operations that these sub-devices support fall in - a few categories: core ops, audio ops, video ops and tuner ops. - - More categories can be added if needed, although this should remain a - limited set (no more than approx. 8 categories). - - Each category has its own set of ops that subdev drivers can implement. - - A subdev driver can leave the pointer to the category ops NULL if - it does not implement them (e.g. an audio subdev will generally not - implement the video category ops). The exception is the core category: - this must always be present. - - These ops are all used internally so it is no problem to change, remove - or add ops or move ops from one to another category. Currently these - ops are based on the original ioctls, but since ops are not limited to - one argument there is room for improvement here once all i2c subdev - drivers are converted to use these ops. - */ - -/* Core ops: it is highly recommended to implement at least these ops: - - g_chip_ident - log_status - g_register - s_register - - This provides basic debugging support. - - The ioctl ops is meant for generic ioctl-like commands. Depending on - the use-case it might be better to use subdev-specific ops (currently - not yet implemented) since ops provide proper type-checking. - */ - -/* Subdevice external IO pin configuration */ -#define V4L2_SUBDEV_IO_PIN_DISABLE (1 << 0) /* ENABLE assumed */ -#define V4L2_SUBDEV_IO_PIN_OUTPUT (1 << 1) -#define V4L2_SUBDEV_IO_PIN_INPUT (1 << 2) -#define V4L2_SUBDEV_IO_PIN_SET_VALUE (1 << 3) /* Set output value */ -#define V4L2_SUBDEV_IO_PIN_ACTIVE_LOW (1 << 4) /* ACTIVE HIGH assumed */ - -struct v4l2_subdev_io_pin_config { - u32 flags; /* V4L2_SUBDEV_IO_PIN_* flags for this pin's config */ - u8 pin; /* Chip external IO pin to configure */ - u8 function; /* Internal signal pad/function to route to IO pin */ - u8 value; /* Initial value for pin - e.g. GPIO output value */ - u8 strength; /* Pin drive strength */ -}; - -/* - s_io_pin_config: configure one or more chip I/O pins for chips that - multiplex different internal signal pads out to IO pins. This function - takes a pointer to an array of 'n' pin configuration entries, one for - each pin being configured. This function could be called at times - other than just subdevice initialization. - - init: initialize the sensor registors to some sort of reasonable default - values. Do not use for new drivers and should be removed in existing - drivers. - - load_fw: load firmware. - - reset: generic reset command. The argument selects which subsystems to - reset. Passing 0 will always reset the whole chip. Do not use for new - drivers without discussing this first on the linux-media mailinglist. - There should be no reason normally to reset a device. - - s_gpio: set GPIO pins. Very simple right now, might need to be extended with - a direction argument if needed. - - s_power: puts subdevice in power saving mode (on == 0) or normal operation - mode (on == 1). - - interrupt_service_routine: Called by the bridge chip's interrupt service - handler, when an interrupt status has be raised due to this subdev, - so that this subdev can handle the details. It may schedule work to be - performed later. It must not sleep. *Called from an IRQ context*. - */ -struct v4l2_subdev_core_ops { - int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip); - int (*log_status)(struct v4l2_subdev *sd); - int (*s_io_pin_config)(struct v4l2_subdev *sd, size_t n, - struct v4l2_subdev_io_pin_config *pincfg); - int (*init)(struct v4l2_subdev *sd, u32 val); - int (*load_fw)(struct v4l2_subdev *sd); - int (*reset)(struct v4l2_subdev *sd, u32 val); - int (*s_gpio)(struct v4l2_subdev *sd, u32 val); - int (*queryctrl)(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc); - int (*g_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl); - int (*s_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl); - int (*g_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); - int (*s_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); - int (*try_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); - int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm); - int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm); - long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); -#ifdef CONFIG_VIDEO_ADV_DEBUG - int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg); - int (*s_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg); -#endif - int (*s_power)(struct v4l2_subdev *sd, int on); - int (*interrupt_service_routine)(struct v4l2_subdev *sd, - u32 status, bool *handled); - int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); - int (*unsubscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); -}; - -/* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio. - - s_radio: v4l device was opened in Radio mode, to be replaced by s_mode. - - s_type_addr: sets tuner type and its I2C addr. - - s_config: sets tda9887 specific stuff, like port1, port2 and qss - */ -struct v4l2_subdev_tuner_ops { - int (*s_mode)(struct v4l2_subdev *sd, enum v4l2_tuner_type); - int (*s_radio)(struct v4l2_subdev *sd); - int (*s_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); - int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); - int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); - int (*s_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); - int (*g_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm); - int (*s_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm); - int (*s_type_addr)(struct v4l2_subdev *sd, struct tuner_setup *type); - int (*s_config)(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *config); -}; - -/* s_clock_freq: set the frequency (in Hz) of the audio clock output. - Used to slave an audio processor to the video decoder, ensuring that - audio and video remain synchronized. Usual values for the frequency - are 48000, 44100 or 32000 Hz. If the frequency is not supported, then - -EINVAL is returned. - - s_i2s_clock_freq: sets I2S speed in bps. This is used to provide a standard - way to select I2S clock used by driving digital audio streams at some - board designs. Usual values for the frequency are 1024000 and 2048000. - If the frequency is not supported, then -EINVAL is returned. - - s_routing: used to define the input and/or output pins of an audio chip, - and any additional configuration data. - Never attempt to use user-level input IDs (e.g. Composite, S-Video, - Tuner) at this level. An i2c device shouldn't know about whether an - input pin is connected to a Composite connector, become on another - board or platform it might be connected to something else entirely. - The calling driver is responsible for mapping a user-level input to - the right pins on the i2c device. - */ -struct v4l2_subdev_audio_ops { - int (*s_clock_freq)(struct v4l2_subdev *sd, u32 freq); - int (*s_i2s_clock_freq)(struct v4l2_subdev *sd, u32 freq); - int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); - int (*s_stream)(struct v4l2_subdev *sd, int enable); -}; - -/* - s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by - video input devices. - - s_crystal_freq: sets the frequency of the crystal used to generate the - clocks in Hz. An extra flags field allows device specific configuration - regarding clock frequency dividers, etc. If not used, then set flags - to 0. If the frequency is not supported, then -EINVAL is returned. - - g_input_status: get input status. Same as the status field in the v4l2_input - struct. - - s_routing: see s_routing in audio_ops, except this version is for video - devices. - - s_dv_preset: set dv (Digital Video) preset in the sub device. Similar to - s_std() - - query_dv_preset: query dv preset in the sub device. This is similar to - querystd() - - s_dv_timings(): Set custom dv timings in the sub device. This is used - when sub device is capable of setting detailed timing information - in the hardware to generate/detect the video signal. - - g_dv_timings(): Get custom dv timings in the sub device. - - enum_mbus_fmt: enumerate pixel formats, provided by a video data source - - g_mbus_fmt: get the current pixel format, provided by a video data source - - try_mbus_fmt: try to set a pixel format on a video data source - - s_mbus_fmt: set a pixel format on a video data source - */ -struct v4l2_subdev_video_ops { - int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); - int (*s_crystal_freq)(struct v4l2_subdev *sd, u32 freq, u32 flags); - int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std); - int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std); - int (*g_input_status)(struct v4l2_subdev *sd, u32 *status); - int (*s_stream)(struct v4l2_subdev *sd, int enable); - int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc); - int (*g_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop); - int (*s_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop); - int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); - int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); - int (*g_frame_interval)(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval); - int (*s_frame_interval)(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval); - int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize); - int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival); - int (*enum_dv_presets) (struct v4l2_subdev *sd, - struct v4l2_dv_enum_preset *preset); - int (*s_dv_preset)(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset); - int (*query_dv_preset)(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset); - int (*s_dv_timings)(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings); - int (*g_dv_timings)(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings); - int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code); - int (*enum_mbus_fsizes)(struct v4l2_subdev *sd, - struct v4l2_frmsizeenum *fsize); - int (*g_mbus_fmt)(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt); - int (*try_mbus_fmt)(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt); - int (*s_mbus_fmt)(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt); -}; - -/* - decode_vbi_line: video decoders that support sliced VBI need to implement - this ioctl. Field p of the v4l2_sliced_vbi_line struct is set to the - start of the VBI data that was generated by the decoder. The driver - then parses the sliced VBI data and sets the other fields in the - struct accordingly. The pointer p is updated to point to the start of - the payload which can be copied verbatim into the data field of the - v4l2_sliced_vbi_data struct. If no valid VBI data was found, then the - type field is set to 0 on return. - - s_vbi_data: used to generate VBI signals on a video signal. - v4l2_sliced_vbi_data is filled with the data packets that should be - output. Note that if you set the line field to 0, then that VBI signal - is disabled. If no valid VBI data was found, then the type field is - set to 0 on return. - - g_vbi_data: used to obtain the sliced VBI packet from a readback register. - Not all video decoders support this. If no data is available because - the readback register contains invalid or erroneous data -EIO is - returned. Note that you must fill in the 'id' member and the 'field' - member (to determine whether CC data from the first or second field - should be obtained). - - s_raw_fmt: setup the video encoder/decoder for raw VBI. - - g_sliced_fmt: retrieve the current sliced VBI settings. - - s_sliced_fmt: setup the sliced VBI settings. - */ -struct v4l2_subdev_vbi_ops { - int (*decode_vbi_line)(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi_line); - int (*s_vbi_data)(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *vbi_data); - int (*g_vbi_data)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *vbi_data); - int (*g_sliced_vbi_cap)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap); - int (*s_raw_fmt)(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt); - int (*g_sliced_fmt)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); - int (*s_sliced_fmt)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); -}; - -/** - * struct v4l2_subdev_sensor_ops - v4l2-subdev sensor operations - * @g_skip_top_lines: number of lines at the top of the image to be skipped. - * This is needed for some sensors, which always corrupt - * several top lines of the output image, or which send their - * metadata in them. - * @g_skip_frames: number of frames to skip at stream start. This is needed for - * buggy sensors that generate faulty frames when they are - * turned on. - */ -struct v4l2_subdev_sensor_ops { - int (*g_skip_top_lines)(struct v4l2_subdev *sd, u32 *lines); - int (*g_skip_frames)(struct v4l2_subdev *sd, u32 *frames); -}; - -/* - [rt]x_g_parameters: Get the current operating parameters and state of the - the IR receiver or transmitter. - - [rt]x_s_parameters: Set the current operating parameters and state of the - the IR receiver or transmitter. It is recommended to call - [rt]x_g_parameters first to fill out the current state, and only change - the fields that need to be changed. Upon return, the actual device - operating parameters and state will be returned. Note that hardware - limitations may prevent the actual settings from matching the requested - settings - e.g. an actual carrier setting of 35,904 Hz when 36,000 Hz - was requested. An exception is when the shutdown parameter is true. - The last used operational parameters will be returned, but the actual - state of the hardware be different to minimize power consumption and - processing when shutdown is true. - - rx_read: Reads received codes or pulse width data. - The semantics are similar to a non-blocking read() call. - - tx_write: Writes codes or pulse width data for transmission. - The semantics are similar to a non-blocking write() call. - */ - -enum v4l2_subdev_ir_mode { - V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, /* uses struct ir_raw_event records */ -}; - -struct v4l2_subdev_ir_parameters { - /* Either Rx or Tx */ - unsigned int bytes_per_data_element; /* of data in read or write call */ - enum v4l2_subdev_ir_mode mode; - - bool enable; - bool interrupt_enable; - bool shutdown; /* true: set hardware to low/no power, false: normal */ - - bool modulation; /* true: uses carrier, false: baseband */ - u32 max_pulse_width; /* ns, valid only for baseband signal */ - unsigned int carrier_freq; /* Hz, valid only for modulated signal*/ - unsigned int duty_cycle; /* percent, valid only for modulated signal*/ - bool invert_level; /* invert signal level */ - - /* Tx only */ - bool invert_carrier_sense; /* Send 0/space as a carrier burst */ - - /* Rx only */ - u32 noise_filter_min_width; /* ns, min time of a valid pulse */ - unsigned int carrier_range_lower; /* Hz, valid only for modulated sig */ - unsigned int carrier_range_upper; /* Hz, valid only for modulated sig */ - u32 resolution; /* ns */ -}; - -struct v4l2_subdev_ir_ops { - /* Receiver */ - int (*rx_read)(struct v4l2_subdev *sd, u8 *buf, size_t count, - ssize_t *num); - - int (*rx_g_parameters)(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *params); - int (*rx_s_parameters)(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *params); - - /* Transmitter */ - int (*tx_write)(struct v4l2_subdev *sd, u8 *buf, size_t count, - ssize_t *num); - - int (*tx_g_parameters)(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *params); - int (*tx_s_parameters)(struct v4l2_subdev *sd, - struct v4l2_subdev_ir_parameters *params); -}; - -struct v4l2_subdev_pad_ops { - int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code); - int (*enum_frame_size)(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_frame_size_enum *fse); - int (*enum_frame_interval)(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_frame_interval_enum *fie); - int (*get_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *format); - int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *format); - int (*set_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop); - int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop); -}; - -struct v4l2_subdev_ops { - const struct v4l2_subdev_core_ops *core; - const struct v4l2_subdev_tuner_ops *tuner; - const struct v4l2_subdev_audio_ops *audio; - const struct v4l2_subdev_video_ops *video; - const struct v4l2_subdev_vbi_ops *vbi; - const struct v4l2_subdev_ir_ops *ir; - const struct v4l2_subdev_sensor_ops *sensor; - const struct v4l2_subdev_pad_ops *pad; -}; - -/* - * Internal ops. Never call this from drivers, only the v4l2 framework can call - * these ops. - * - * registered: called when this subdev is registered. When called the v4l2_dev - * field is set to the correct v4l2_device. - * - * unregistered: called when this subdev is unregistered. When called the - * v4l2_dev field is still set to the correct v4l2_device. - * - * open: called when the subdev device node is opened by an application. - * - * close: called when the subdev device node is closed. - */ -struct v4l2_subdev_internal_ops { - int (*registered)(struct v4l2_subdev *sd); - void (*unregistered)(struct v4l2_subdev *sd); - int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); - int (*close)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); -}; - -#define V4L2_SUBDEV_NAME_SIZE 32 - -/* Set this flag if this subdev is a i2c device. */ -#define V4L2_SUBDEV_FL_IS_I2C (1U << 0) -/* Set this flag if this subdev is a spi device. */ -#define V4L2_SUBDEV_FL_IS_SPI (1U << 1) -/* Set this flag if this subdev needs a device node. */ -#define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2) -/* Set this flag if this subdev generates events. */ -#define V4L2_SUBDEV_FL_HAS_EVENTS (1U << 3) - -/* Each instance of a subdev driver should create this struct, either - stand-alone or embedded in a larger struct. - */ -struct v4l2_subdev { -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity entity; -#endif - struct list_head list; - struct module *owner; - u32 flags; - struct v4l2_device *v4l2_dev; - const struct v4l2_subdev_ops *ops; - /* Never call these internal ops from within a driver! */ - const struct v4l2_subdev_internal_ops *internal_ops; - /* The control handler of this subdev. May be NULL. */ - struct v4l2_ctrl_handler *ctrl_handler; - /* name must be unique */ - char name[V4L2_SUBDEV_NAME_SIZE]; - /* can be used to group similar subdevs, value is driver-specific */ - u32 grp_id; - /* pointer to private data */ - void *dev_priv; - void *host_priv; - /* subdev device node */ - struct video_device devnode; - /* number of events to be allocated on open */ - unsigned int nevents; -}; - -#define media_entity_to_v4l2_subdev(ent) \ - container_of(ent, struct v4l2_subdev, entity) -#define vdev_to_v4l2_subdev(vdev) \ - container_of(vdev, struct v4l2_subdev, devnode) - -/* - * Used for storing subdev information per file handle - */ -struct v4l2_subdev_fh { - struct v4l2_fh vfh; -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - struct v4l2_mbus_framefmt *try_fmt; - struct v4l2_rect *try_crop; -#endif -}; - -#define to_v4l2_subdev_fh(fh) \ - container_of(fh, struct v4l2_subdev_fh, vfh) - -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) -static inline struct v4l2_mbus_framefmt * -v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad) -{ - return &fh->try_fmt[pad]; -} - -static inline struct v4l2_rect * -v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad) -{ - return &fh->try_crop[pad]; -} -#endif - -extern const struct v4l2_file_operations v4l2_subdev_fops; - -static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p) -{ - sd->dev_priv = p; -} - -static inline void *v4l2_get_subdevdata(const struct v4l2_subdev *sd) -{ - return sd->dev_priv; -} - -static inline void v4l2_set_subdev_hostdata(struct v4l2_subdev *sd, void *p) -{ - sd->host_priv = p; -} - -static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd) -{ - return sd->host_priv; -} - -void v4l2_subdev_init(struct v4l2_subdev *sd, - const struct v4l2_subdev_ops *ops); - -/* Call an ops of a v4l2_subdev, doing the right checks against - NULL pointers. - - Example: err = v4l2_subdev_call(sd, core, g_chip_ident, &chip); - */ -#define v4l2_subdev_call(sd, o, f, args...) \ - (!(sd) ? -ENODEV : (((sd)->ops->o && (sd)->ops->o->f) ? \ - (sd)->ops->o->f((sd) , ##args) : -ENOIOCTLCMD)) - -/* Send a notification to v4l2_device. */ -#define v4l2_subdev_notify(sd, notification, arg) \ - ((!(sd) || !(sd)->v4l2_dev || !(sd)->v4l2_dev->notify) ? -ENODEV : \ - (sd)->v4l2_dev->notify((sd), (notification), (arg))) - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-core.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-core.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,380 +0,0 @@ -/* - * videobuf2-core.h - V4L2 driver helper framework - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Pawel Osciak - * - * 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. - */ -#ifndef _MEDIA_VIDEOBUF2_CORE_H -#define _MEDIA_VIDEOBUF2_CORE_H - -#include -#include -#include -#include - -struct vb2_alloc_ctx; -struct vb2_fileio_data; - -/** - * struct vb2_mem_ops - memory handling/memory allocator operations - * @alloc: allocate video memory and, optionally, allocator private data, - * return NULL on failure or a pointer to allocator private, - * per-buffer data on success; the returned private structure - * will then be passed as buf_priv argument to other ops in this - * structure - * @put: inform the allocator that the buffer will no longer be used; - * usually will result in the allocator freeing the buffer (if - * no other users of this buffer are present); the buf_priv - * argument is the allocator private per-buffer structure - * previously returned from the alloc callback - * @get_userptr: acquire userspace memory for a hardware operation; used for - * USERPTR memory types; vaddr is the address passed to the - * videobuf layer when queuing a video buffer of USERPTR type; - * should return an allocator private per-buffer structure - * associated with the buffer on success, NULL on failure; - * the returned private structure will then be passed as buf_priv - * argument to other ops in this structure - * @put_userptr: inform the allocator that a USERPTR buffer will no longer - * be used - * @vaddr: return a kernel virtual address to a given memory buffer - * associated with the passed private structure or NULL if no - * such mapping exists - * @cookie: return allocator specific cookie for a given memory buffer - * associated with the passed private structure or NULL if not - * available - * @num_users: return the current number of users of a memory buffer; - * return 1 if the videobuf layer (or actually the driver using - * it) is the only user - * @mmap: setup a userspace mapping for a given memory buffer under - * the provided virtual memory region - * - * Required ops for USERPTR types: get_userptr, put_userptr. - * Required ops for MMAP types: alloc, put, num_users, mmap. - * Required ops for read/write access types: alloc, put, num_users, vaddr - */ -struct vb2_mem_ops { - void *(*alloc)(void *alloc_ctx, unsigned long size); - void (*put)(void *buf_priv); - - void *(*get_userptr)(void *alloc_ctx, unsigned long vaddr, - unsigned long size, int write); - void (*put_userptr)(void *buf_priv); - - void *(*vaddr)(void *buf_priv); - void *(*cookie)(void *buf_priv); - - unsigned int (*num_users)(void *buf_priv); - - int (*mmap)(void *buf_priv, struct vm_area_struct *vma); -}; - -struct vb2_plane { - void *mem_priv; - int mapped:1; -}; - -/** - * enum vb2_io_modes - queue access methods - * @VB2_MMAP: driver supports MMAP with streaming API - * @VB2_USERPTR: driver supports USERPTR with streaming API - * @VB2_READ: driver supports read() style access - * @VB2_WRITE: driver supports write() style access - */ -enum vb2_io_modes { - VB2_MMAP = (1 << 0), - VB2_USERPTR = (1 << 1), - VB2_READ = (1 << 2), - VB2_WRITE = (1 << 3), -}; - -/** - * enum vb2_fileio_flags - flags for selecting a mode of the file io emulator, - * by default the 'streaming' style is used by the file io emulator - * @VB2_FILEIO_READ_ONCE: report EOF after reading the first buffer - * @VB2_FILEIO_WRITE_IMMEDIATELY: queue buffer after each write() call - */ -enum vb2_fileio_flags { - VB2_FILEIO_READ_ONCE = (1 << 0), - VB2_FILEIO_WRITE_IMMEDIATELY = (1 << 1), -}; - -/** - * enum vb2_buffer_state - current video buffer state - * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control - * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver - * @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used - * in a hardware operation - * @VB2_BUF_STATE_DONE: buffer returned from driver to videobuf, but - * not yet dequeued to userspace - * @VB2_BUF_STATE_ERROR: same as above, but the operation on the buffer - * has ended with an error, which will be reported - * to the userspace when it is dequeued - */ -enum vb2_buffer_state { - VB2_BUF_STATE_DEQUEUED, - VB2_BUF_STATE_QUEUED, - VB2_BUF_STATE_ACTIVE, - VB2_BUF_STATE_DONE, - VB2_BUF_STATE_ERROR, -}; - -struct vb2_queue; - -/** - * struct vb2_buffer - represents a video buffer - * @v4l2_buf: struct v4l2_buffer associated with this buffer; can - * be read by the driver and relevant entries can be - * changed by the driver in case of CAPTURE types - * (such as timestamp) - * @v4l2_planes: struct v4l2_planes associated with this buffer; can - * be read by the driver and relevant entries can be - * changed by the driver in case of CAPTURE types - * (such as bytesused); NOTE that even for single-planar - * types, the v4l2_planes[0] struct should be used - * instead of v4l2_buf for filling bytesused - drivers - * should use the vb2_set_plane_payload() function for that - * @vb2_queue: the queue to which this driver belongs - * @num_planes: number of planes in the buffer - * on an internal driver queue - * @state: current buffer state; do not change - * @queued_entry: entry on the queued buffers list, which holds all - * buffers queued from userspace - * @done_entry: entry on the list that stores all buffers ready to - * be dequeued to userspace - * @planes: private per-plane information; do not change - * @num_planes_mapped: number of mapped planes; do not change - */ -struct vb2_buffer { - struct v4l2_buffer v4l2_buf; - struct v4l2_plane v4l2_planes[VIDEO_MAX_PLANES]; - - struct vb2_queue *vb2_queue; - - unsigned int num_planes; - -/* Private: internal use only */ - enum vb2_buffer_state state; - - struct list_head queued_entry; - struct list_head done_entry; - - struct vb2_plane planes[VIDEO_MAX_PLANES]; - unsigned int num_planes_mapped; -}; - -/** - * struct vb2_ops - driver-specific callbacks - * - * @queue_setup: called from a VIDIOC_REQBUFS handler, before - * memory allocation; driver should return the required - * number of buffers in num_buffers, the required number - * of planes per buffer in num_planes; the size of each - * plane should be set in the sizes[] array and optional - * per-plane allocator specific context in alloc_ctxs[] - * array - * @wait_prepare: release any locks taken while calling vb2 functions; - * it is called before an ioctl needs to wait for a new - * buffer to arrive; required to avoid a deadlock in - * blocking access type - * @wait_finish: reacquire all locks released in the previous callback; - * required to continue operation after sleeping while - * waiting for a new buffer to arrive - * @buf_init: called once after allocating a buffer (in MMAP case) - * or after acquiring a new USERPTR buffer; drivers may - * perform additional buffer-related initialization; - * initialization failure (return != 0) will prevent - * queue setup from completing successfully; optional - * @buf_prepare: called every time the buffer is queued from userspace; - * drivers may perform any initialization required before - * each hardware operation in this callback; - * if an error is returned, the buffer will not be queued - * in driver; optional - * @buf_finish: called before every dequeue of the buffer back to - * userspace; drivers may perform any operations required - * before userspace accesses the buffer; optional - * @buf_cleanup: called once before the buffer is freed; drivers may - * perform any additional cleanup; optional - * @start_streaming: called once before entering 'streaming' state; enables - * driver to receive buffers over buf_queue() callback - * @stop_streaming: called when 'streaming' state must be disabled; driver - * should stop any DMA transactions or wait until they - * finish and give back all buffers it got from buf_queue() - * callback; may use vb2_wait_for_all_buffers() function - * @buf_queue: passes buffer vb to the driver; driver may start - * hardware operation on this buffer; driver should give - * the buffer back by calling vb2_buffer_done() function - */ -struct vb2_ops { - int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers, - unsigned int *num_planes, unsigned long sizes[], - void *alloc_ctxs[]); - - void (*wait_prepare)(struct vb2_queue *q); - void (*wait_finish)(struct vb2_queue *q); - - int (*buf_init)(struct vb2_buffer *vb); - int (*buf_prepare)(struct vb2_buffer *vb); - int (*buf_finish)(struct vb2_buffer *vb); - void (*buf_cleanup)(struct vb2_buffer *vb); - - int (*start_streaming)(struct vb2_queue *q); - int (*stop_streaming)(struct vb2_queue *q); - - void (*buf_queue)(struct vb2_buffer *vb); -}; - -/** - * struct vb2_queue - a videobuf queue - * - * @type: queue type (see V4L2_BUF_TYPE_* in linux/videodev2.h - * @io_modes: supported io methods (see vb2_io_modes enum) - * @io_flags: additional io flags (see vb2_fileio_flags enum) - * @ops: driver-specific callbacks - * @mem_ops: memory allocator specific callbacks - * @drv_priv: driver private data - * @buf_struct_size: size of the driver-specific buffer structure; - * "0" indicates the driver doesn't want to use a custom buffer - * structure type, so sizeof(struct vb2_buffer) will is used - * - * @memory: current memory type used - * @bufs: videobuf buffer structures - * @num_buffers: number of allocated/used buffers - * @queued_list: list of buffers currently queued from userspace - * @queued_count: number of buffers owned by the driver - * @done_list: list of buffers ready to be dequeued to userspace - * @done_lock: lock to protect done_list list - * @done_wq: waitqueue for processes waiting for buffers ready to be dequeued - * @alloc_ctx: memory type/allocator-specific contexts for each plane - * @streaming: current streaming state - * @fileio: file io emulator internal data, used only if emulator is active - */ -struct vb2_queue { - enum v4l2_buf_type type; - unsigned int io_modes; - unsigned int io_flags; - - const struct vb2_ops *ops; - const struct vb2_mem_ops *mem_ops; - void *drv_priv; - unsigned int buf_struct_size; - -/* private: internal use only */ - enum v4l2_memory memory; - struct vb2_buffer *bufs[VIDEO_MAX_FRAME]; - unsigned int num_buffers; - - struct list_head queued_list; - - atomic_t queued_count; - struct list_head done_list; - spinlock_t done_lock; - wait_queue_head_t done_wq; - - void *alloc_ctx[VIDEO_MAX_PLANES]; - - unsigned int streaming:1; - - struct vb2_fileio_data *fileio; -}; - -void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no); -void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no); - -void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state); -int vb2_wait_for_all_buffers(struct vb2_queue *q); - -int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b); -int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req); - -int vb2_queue_init(struct vb2_queue *q); - -void vb2_queue_release(struct vb2_queue *q); - -int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b); -int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking); - -int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type); -int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type); - -int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma); -unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait); -size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, - loff_t *ppos, int nonblock); -size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count, - loff_t *ppos, int nonblock); - -/** - * vb2_is_streaming() - return streaming status of the queue - * @q: videobuf queue - */ -static inline bool vb2_is_streaming(struct vb2_queue *q) -{ - return q->streaming; -} - -/** - * vb2_is_busy() - return busy status of the queue - * @q: videobuf queue - * - * This function checks if queue has any buffers allocated. - */ -static inline bool vb2_is_busy(struct vb2_queue *q) -{ - return (q->num_buffers > 0); -} - -/** - * vb2_get_drv_priv() - return driver private data associated with the queue - * @q: videobuf queue - */ -static inline void *vb2_get_drv_priv(struct vb2_queue *q) -{ - return q->drv_priv; -} - -/** - * vb2_set_plane_payload() - set bytesused for the plane plane_no - * @vb: buffer for which plane payload should be set - * @plane_no: plane number for which payload should be set - * @size: payload in bytes - */ -static inline void vb2_set_plane_payload(struct vb2_buffer *vb, - unsigned int plane_no, unsigned long size) -{ - if (plane_no < vb->num_planes) - vb->v4l2_planes[plane_no].bytesused = size; -} - -/** - * vb2_get_plane_payload() - get bytesused for the plane plane_no - * @vb: buffer for which plane payload should be set - * @plane_no: plane number for which payload should be set - * @size: payload in bytes - */ -static inline unsigned long vb2_get_plane_payload(struct vb2_buffer *vb, - unsigned int plane_no) -{ - if (plane_no < vb->num_planes) - return vb->v4l2_planes[plane_no].bytesused; - return 0; -} - -/** - * vb2_plane_size() - return plane size in bytes - * @vb: buffer for which plane size should be returned - * @plane_no: plane number for which size should be returned - */ -static inline unsigned long -vb2_plane_size(struct vb2_buffer *vb, unsigned int plane_no) -{ - if (plane_no < vb->num_planes) - return vb->v4l2_planes[plane_no].length; - return 0; -} - -#endif /* _MEDIA_VIDEOBUF2_CORE_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-dma-contig.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-dma-contig.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-dma-contig.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-dma-contig.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/* - * videobuf2-dma-coherent.h - DMA coherent memory allocator for videobuf2 - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Pawel Osciak - * - * 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. - */ - -#ifndef _MEDIA_VIDEOBUF2_DMA_COHERENT_H -#define _MEDIA_VIDEOBUF2_DMA_COHERENT_H - -#include -#include - -static inline dma_addr_t -vb2_dma_contig_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no) -{ - dma_addr_t *paddr = vb2_plane_cookie(vb, plane_no); - - return *paddr; -} - -void *vb2_dma_contig_init_ctx(struct device *dev); -void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); - -extern const struct vb2_mem_ops vb2_dma_contig_memops; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-dma-sg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-dma-sg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-dma-sg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-dma-sg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/* - * videobuf2-dma-sg.h - DMA scatter/gather memory allocator for videobuf2 - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Andrzej Pietrasiewicz - * - * 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. - */ - -#ifndef _MEDIA_VIDEOBUF2_DMA_SG_H -#define _MEDIA_VIDEOBUF2_DMA_SG_H - -#include - -struct vb2_dma_sg_desc { - unsigned long size; - unsigned int num_pages; - struct scatterlist *sglist; -}; - -static inline struct vb2_dma_sg_desc *vb2_dma_sg_plane_desc( - struct vb2_buffer *vb, unsigned int plane_no) -{ - return (struct vb2_dma_sg_desc *)vb2_plane_cookie(vb, plane_no); -} - -extern const struct vb2_mem_ops vb2_dma_sg_memops; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-memops.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-memops.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-memops.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-memops.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/* - * videobuf2-memops.h - generic memory handling routines for videobuf2 - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Pawel Osciak - * Marek Szyprowski - * - * 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. - */ - -#ifndef _MEDIA_VIDEOBUF2_MEMOPS_H -#define _MEDIA_VIDEOBUF2_MEMOPS_H - -#include - -/** - * vb2_vmarea_handler - common vma refcount tracking handler - * @refcount: pointer to refcount entry in the buffer - * @put: callback to function that decreases buffer refcount - * @arg: argument for @put callback - */ -struct vb2_vmarea_handler { - atomic_t *refcount; - void (*put)(void *arg); - void *arg; -}; - -extern const struct vm_operations_struct vb2_common_vm_ops; - -int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, - struct vm_area_struct **res_vma, dma_addr_t *res_pa); - -int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, - unsigned long size, - const struct vm_operations_struct *vm_ops, - void *priv); - -struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma); -void vb2_put_vma(struct vm_area_struct *vma); - - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-vmalloc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-vmalloc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-vmalloc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf2-vmalloc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -/* - * videobuf2-vmalloc.h - vmalloc memory allocator for videobuf2 - * - * Copyright (C) 2010 Samsung Electronics - * - * Author: Pawel Osciak - * - * 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. - */ - -#ifndef _MEDIA_VIDEOBUF2_VMALLOC_H -#define _MEDIA_VIDEOBUF2_VMALLOC_H - -#include - -extern const struct vb2_mem_ops vb2_vmalloc_memops; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-core.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-core.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,238 +0,0 @@ -/* - * generic helper functions for handling video4linux capture buffers - * - * (c) 2007 Mauro Carvalho Chehab, - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - * - * 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 - */ - -#ifndef _VIDEOBUF_CORE_H -#define _VIDEOBUF_CORE_H - -#include -#include - -#define UNSET (-1U) - - -struct videobuf_buffer; -struct videobuf_queue; - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage video4linux buffers. - * - * struct videobuf_buffer holds the data structures used by the helper - * functions, additionally some commonly used fields for v4l buffers - * (width, height, lists, waitqueue) are in there. That struct should - * be used as first element in the drivers buffer struct. - * - * about the mmap helpers (videobuf_mmap_*): - * - * The mmaper function allows to map any subset of contingous buffers. - * This includes one mmap() call for all buffers (which the original - * video4linux API uses) as well as one mmap() for every single buffer - * (which v4l2 uses). - * - * If there is a valid mapping for a buffer, buffer->baddr/bsize holds - * userspace address + size which can be feeded into the - * videobuf_dma_init_user function listed above. - * - */ - -struct videobuf_mapping { - unsigned int count; - struct videobuf_queue *q; -}; - -enum videobuf_state { - VIDEOBUF_NEEDS_INIT = 0, - VIDEOBUF_PREPARED = 1, - VIDEOBUF_QUEUED = 2, - VIDEOBUF_ACTIVE = 3, - VIDEOBUF_DONE = 4, - VIDEOBUF_ERROR = 5, - VIDEOBUF_IDLE = 6, -}; - -struct videobuf_buffer { - unsigned int i; - u32 magic; - - /* info about the buffer */ - unsigned int width; - unsigned int height; - unsigned int bytesperline; /* use only if != 0 */ - unsigned long size; - unsigned int input; - enum v4l2_field field; - enum videobuf_state state; - struct list_head stream; /* QBUF/DQBUF list */ - - /* touched by irq handler */ - struct list_head queue; - wait_queue_head_t done; - unsigned int field_count; - struct timeval ts; - - /* Memory type */ - enum v4l2_memory memory; - - /* buffer size */ - size_t bsize; - - /* buffer offset (mmap + overlay) */ - size_t boff; - - /* buffer addr (userland ptr!) */ - unsigned long baddr; - - /* for mmap'ed buffers */ - struct videobuf_mapping *map; - - /* Private pointer to allow specific methods to store their data */ - int privsize; - void *priv; -}; - -struct videobuf_queue_ops { - int (*buf_setup)(struct videobuf_queue *q, - unsigned int *count, unsigned int *size); - int (*buf_prepare)(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field); - void (*buf_queue)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - void (*buf_release)(struct videobuf_queue *q, - struct videobuf_buffer *vb); -}; - -#define MAGIC_QTYPE_OPS 0x12261003 - -/* Helper operations - device type dependent */ -struct videobuf_qtype_ops { - u32 magic; - - struct videobuf_buffer *(*alloc_vb)(size_t size); - void *(*vaddr) (struct videobuf_buffer *buf); - int (*iolock) (struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf); - int (*sync) (struct videobuf_queue *q, - struct videobuf_buffer *buf); - int (*mmap_mapper) (struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma); -}; - -struct videobuf_queue { - struct mutex vb_lock; - struct mutex *ext_lock; - spinlock_t *irqlock; - struct device *dev; - - wait_queue_head_t wait; /* wait if queue is empty */ - - enum v4l2_buf_type type; - unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ - unsigned int msize; - enum v4l2_field field; - enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ - struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; - const struct videobuf_queue_ops *ops; - struct videobuf_qtype_ops *int_ops; - - unsigned int streaming:1; - unsigned int reading:1; - - /* capture via mmap() + ioctl(QBUF/DQBUF) */ - struct list_head stream; - - /* capture via read() */ - unsigned int read_off; - struct videobuf_buffer *read_buf; - - /* driver private data */ - void *priv_data; -}; - -static inline void videobuf_queue_lock(struct videobuf_queue *q) -{ - if (!q->ext_lock) - mutex_lock(&q->vb_lock); -} - -static inline void videobuf_queue_unlock(struct videobuf_queue *q) -{ - if (!q->ext_lock) - mutex_unlock(&q->vb_lock); -} - -int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb, - int non_blocking, int intr); -int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf); - -struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q); - -/* Used on videobuf-dvb */ -void *videobuf_queue_to_vaddr(struct videobuf_queue *q, - struct videobuf_buffer *buf); - -void videobuf_queue_core_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct videobuf_qtype_ops *int_ops, - struct mutex *ext_lock); -int videobuf_queue_is_busy(struct videobuf_queue *q); -void videobuf_queue_cancel(struct videobuf_queue *q); - -enum v4l2_field videobuf_next_field(struct videobuf_queue *q); -int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req); -int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); -int videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b); -int videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking); -int videobuf_streamon(struct videobuf_queue *q); -int videobuf_streamoff(struct videobuf_queue *q); - -void videobuf_stop(struct videobuf_queue *q); - -int videobuf_read_start(struct videobuf_queue *q); -void videobuf_read_stop(struct videobuf_queue *q); -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking); -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking); -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait); - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory); -int __videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory); -int videobuf_mmap_free(struct videobuf_queue *q); -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dma-contig.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dma-contig.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dma-contig.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dma-contig.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -/* - * helper functions for physically contiguous capture buffers - * - * The functions support hardware lacking scatter gather support - * (i.e. the buffers must be linear in physical memory) - * - * Copyright (c) 2008 Magnus Damm - * - * 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 - */ -#ifndef _VIDEOBUF_DMA_CONTIG_H -#define _VIDEOBUF_DMA_CONTIG_H - -#include -#include - -void videobuf_queue_dma_contig_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock); - -dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf); -void videobuf_dma_contig_free(struct videobuf_queue *q, - struct videobuf_buffer *buf); - -#endif /* _VIDEOBUF_DMA_CONTIG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dma-sg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dma-sg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dma-sg.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dma-sg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -/* - * helper functions for SG DMA video4linux capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab, - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - * - * 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 - */ -#ifndef _VIDEOBUF_DMA_SG_H -#define _VIDEOBUF_DMA_SG_H - -#include - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage buffers (both userland - * and kernel) for DMA. - * - * videobuf_dma_init_*() - * creates a buffer. The userland version takes a userspace - * pointer + length. The kernel version just wants the size and - * does memory allocation too using vmalloc_32(). - * - * videobuf_dma_*() - * see Documentation/PCI/PCI-DMA-mapping.txt, these functions to - * basically the same. The map function does also build a - * scatterlist for the buffer (and unmap frees it ...) - * - * videobuf_dma_free() - * no comment ... - * - */ - -struct videobuf_dmabuf { - u32 magic; - - /* for userland buffer */ - int offset; - size_t size; - struct page **pages; - - /* for kernel buffers */ - void *vaddr; - - /* for overlay buffers (pci-pci dma) */ - dma_addr_t bus_addr; - - /* common */ - struct scatterlist *sglist; - int sglen; - int nr_pages; - int direction; -}; - -struct videobuf_dma_sg_memory { - u32 magic; - - /* for mmap'ed buffers */ - struct videobuf_dmabuf dma; -}; - -/* - * Scatter-gather DMA buffer API. - * - * These functions provide a simple way to create a page list and a - * scatter-gather list from a kernel, userspace of physical address and map the - * memory for DMA operation. - * - * Despite the name, this is totally unrelated to videobuf, except that - * videobuf-dma-sg uses the same API internally. - */ -void videobuf_dma_init(struct videobuf_dmabuf *dma); -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size); -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages); -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages); -int videobuf_dma_free(struct videobuf_dmabuf *dma); - -int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma); -int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma); -struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf); - -void *videobuf_sg_alloc(size_t size); - -void videobuf_queue_sg_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock); - -#endif /* _VIDEOBUF_DMA_SG_H */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dvb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dvb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dvb.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-dvb.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -#include -#include -#include -#include -#include - -struct videobuf_dvb { - /* filling that the job of the driver */ - char *name; - struct dvb_frontend *frontend; - struct videobuf_queue dvbq; - - /* video-buf-dvb state info */ - struct mutex lock; - struct task_struct *thread; - int nfeeds; - - /* videobuf_dvb_(un)register manges this */ - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net net; -}; - -struct videobuf_dvb_frontend { - struct list_head felist; - int id; - struct videobuf_dvb dvb; -}; - -struct videobuf_dvb_frontends { - struct list_head felist; - struct mutex lock; - struct dvb_adapter adapter; - int active_fe_id; /* Indicates which frontend in the felist is in use */ - int gate; /* Frontend with gate control 0=!MFE,1=fe0,2=fe1 etc */ -}; - -int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, - struct module *module, - void *adapter_priv, - struct device *device, - short *adapter_nr, - int mfe_shared, - int (*fe_ioctl_override)(struct dvb_frontend *, - unsigned int, void *, unsigned int)); - -void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f); - -struct videobuf_dvb_frontend * videobuf_dvb_alloc_frontend(struct videobuf_dvb_frontends *f, int id); -void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f); - -struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id); -int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p); - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-vmalloc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-vmalloc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-vmalloc.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/videobuf-vmalloc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * helper functions for vmalloc capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab, - * - * 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 - */ -#ifndef _VIDEOBUF_VMALLOC_H -#define _VIDEOBUF_VMALLOC_H - -#include - -/* --------------------------------------------------------------------- */ - -struct videobuf_vmalloc_memory { - u32 magic; - - void *vaddr; - - /* remap_vmalloc_range seems to need to run - * after mmap() on some cases */ - struct vm_area_struct *vma; -}; - -void videobuf_queue_vmalloc_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock); - -void *videobuf_to_vmalloc(struct videobuf_buffer *buf); - -void videobuf_vmalloc_free(struct videobuf_buffer *buf); - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/wm8775.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/wm8775.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/media/wm8775.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/media/wm8775.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -/* - wm8775.h - definition for wm8775 inputs and outputs - - Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _WM8775_H_ -#define _WM8775_H_ - -/* The WM8775 has 4 inputs and one output. Zero or more inputs - are multiplexed together to the output. Hence there are - 16 combinations. - If only one input is active (the normal case) then the - input values 1, 2, 4 or 8 should be used. */ - -#define WM8775_AIN1 1 -#define WM8775_AIN2 2 -#define WM8775_AIN3 4 -#define WM8775_AIN4 8 - - -struct wm8775_platform_data { - /* - * FIXME: Instead, we should parametrize the params - * that need different settings between ivtv, pvrusb2, and Nova-S - */ - bool is_nova_s; -}; - -#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/sound/aci.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/sound/aci.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/sound/aci.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/sound/aci.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -#ifndef _ACI_H_ -#define _ACI_H_ - -#define ACI_REG_COMMAND 0 /* write register offset */ -#define ACI_REG_STATUS 1 /* read register offset */ -#define ACI_REG_BUSY 2 /* busy register offset */ -#define ACI_REG_RDS 2 /* PCM20: RDS register offset */ -#define ACI_MINTIME 500 /* ACI time out limit */ - -#define ACI_SET_MUTE 0x0d -#define ACI_SET_POWERAMP 0x0f -#define ACI_SET_TUNERMUTE 0xa3 -#define ACI_SET_TUNERMONO 0xa4 -#define ACI_SET_IDE 0xd0 -#define ACI_SET_WSS 0xd1 -#define ACI_SET_SOLOMODE 0xd2 -#define ACI_SET_PREAMP 0x03 -#define ACI_GET_PREAMP 0x21 -#define ACI_WRITE_TUNE 0xa7 -#define ACI_READ_TUNERSTEREO 0xa8 -#define ACI_READ_TUNERSTATION 0xa9 -#define ACI_READ_VERSION 0xf1 -#define ACI_READ_IDCODE 0xf2 -#define ACI_INIT 0xff -#define ACI_STATUS 0xf0 -#define ACI_S_GENERAL 0x00 -#define ACI_ERROR_OP 0xdf - -/* ACI Mixer */ - -/* These are the values for the right channel GET registers. - Add an offset of 0x01 for the left channel register. - (left=right+0x01) */ - -#define ACI_GET_MASTER 0x03 -#define ACI_GET_MIC 0x05 -#define ACI_GET_LINE 0x07 -#define ACI_GET_CD 0x09 -#define ACI_GET_SYNTH 0x0b -#define ACI_GET_PCM 0x0d -#define ACI_GET_LINE1 0x10 /* Radio on PCM20 */ -#define ACI_GET_LINE2 0x12 - -#define ACI_GET_EQ1 0x22 /* from Bass ... */ -#define ACI_GET_EQ2 0x24 -#define ACI_GET_EQ3 0x26 -#define ACI_GET_EQ4 0x28 -#define ACI_GET_EQ5 0x2a -#define ACI_GET_EQ6 0x2c -#define ACI_GET_EQ7 0x2e /* ... to Treble */ - -/* And these are the values for the right channel SET registers. - For left channel access you have to add an offset of 0x08. - MASTER is an exception, which needs an offset of 0x01 */ - -#define ACI_SET_MASTER 0x00 -#define ACI_SET_MIC 0x30 -#define ACI_SET_LINE 0x31 -#define ACI_SET_CD 0x34 -#define ACI_SET_SYNTH 0x33 -#define ACI_SET_PCM 0x32 -#define ACI_SET_LINE1 0x35 /* Radio on PCM20 */ -#define ACI_SET_LINE2 0x36 - -#define ACI_SET_EQ1 0x40 /* from Bass ... */ -#define ACI_SET_EQ2 0x41 -#define ACI_SET_EQ3 0x42 -#define ACI_SET_EQ4 0x43 -#define ACI_SET_EQ5 0x44 -#define ACI_SET_EQ6 0x45 -#define ACI_SET_EQ7 0x46 /* ... to Treble */ - -struct snd_miro_aci { - unsigned long aci_port; - int aci_vendor; - int aci_product; - int aci_version; - int aci_amp; - int aci_preamp; - int aci_solomode; - - struct mutex aci_mutex; -}; - -int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3); - -struct snd_miro_aci *snd_aci_get_aci(void); - -#endif /* _ACI_H_ */ - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/sound/tea575x-tuner.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/sound/tea575x-tuner.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/sound/tea575x-tuner.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/sound/tea575x-tuner.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -#ifndef __SOUND_TEA575X_TUNER_H -#define __SOUND_TEA575X_TUNER_H - -/* - * ALSA driver for TEA5757/5759 Philips AM/FM tuner chips - * - * Copyright (c) 2004 Jaroslav Kysela - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include - -struct snd_tea575x; - -struct snd_tea575x_ops { - void (*write)(struct snd_tea575x *tea, unsigned int val); - unsigned int (*read)(struct snd_tea575x *tea); - void (*mute)(struct snd_tea575x *tea, unsigned int mute); -}; - -struct snd_tea575x { - struct snd_card *card; - struct video_device *vd; /* video device */ - int dev_nr; /* requested device number + 1 */ - int tea5759; /* 5759 chip is present */ - int mute; /* Device is muted? */ - unsigned int freq_fixup; /* crystal onboard */ - unsigned int val; /* hw value */ - unsigned long freq; /* frequency */ - unsigned long in_use; /* set if the device is in use */ - struct snd_tea575x_ops *ops; - void *private_data; -}; - -void snd_tea575x_init(struct snd_tea575x *tea); -void snd_tea575x_exit(struct snd_tea575x *tea); - -#endif /* __SOUND_TEA575X_TUNER_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/staging/altera.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/staging/altera.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/include/staging/altera.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/include/staging/altera.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* - * altera.h - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _ALTERA_H_ -#define _ALTERA_H_ - -struct altera_config { - void *dev; - u8 *action; - int (*jtag_io) (void *dev, int tms, int tdi, int tdo); -}; - -#if defined(CONFIG_ALTERA_STAPL) || \ - (defined(CONFIG_ALTERA_STAPL_MODULE) && defined(MODULE)) - -extern int altera_init(struct altera_config *config, const struct firmware *fw); -#else - -static inline int altera_init(struct altera_config *config, - const struct firmware *fw) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} -#endif /* CONFIG_ALTERA_STAPL */ - -#endif /* _ALTERA_H_ */ Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/linux-media.tar.bz2 and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/linux-media.tar.bz2 differ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -# -# Files that need to be bundled with the building system -# - --include ../v4l/.version - -MAINDIRS += drivers firmware include sound - -# Media drivers -TARDIR += drivers/media/ -TARDIR += drivers/staging/cx25821/ -TARDIR += drivers/staging/go7007/ -TARDIR += drivers/staging/tm6000/ -TARDIR += drivers/staging/lirc/ -TARDIR += drivers/staging/cxd2099/ -TARDIR += drivers/staging/altera-stapl/ -TARFILES += sound/pci/bt87x.c -TARFILES += sound/i2c/other/tea575x-tuner.c - -# Includes -TARDIR += include/media/ -TARDIR += include/linux/dvb/ -TARFILES += include/linux/usb/video.h -TARFILES += include/linux/i2c-id.h -TARFILES += include/linux/ivtv.h -TARFILES += include/linux/mmc/sdio_ids.h -TARFILES += include/linux/ivtvfb.h -TARFILES += include/linux/videodev2.h -TARFILES += include/linux/meye.h -TARFILES += include/sound/tea575x-tuner.h -TARFILES += include/sound/aci.h -TARFILES += include/staging/altera.h -TARFILES += include/linux/via-core.h -TARFILES += include/linux/ti_wilink_st.h -TARFILES += include/linux/media.h -TARFILES += include/linux/v4l2-subdev.h -TARFILES += include/linux/v4l2-mediabus.h - -# Firmware -TARFILES += firmware/av7110/bootcode.bin.ihex -TARFILES += firmware/av7110/Boot.S -TARFILES += firmware/cpia2/stv0672_vp4.bin.ihex -TARFILES += firmware/ihex2fw.c -TARFILES += firmware/vicam/firmware.H16 -TARFILES += firmware/dabusb/bitstream.bin.ihex -TARFILES += firmware/dabusb/firmware.HEX -TARFILES += firmware/ttusb-budget/dspbootcode.bin.ihex - -TODAY_TAR := linux-media-`date "+%Y-%m-%d"`.tar -TODAY_TAR_MD5 := linux-media-`date "+%Y-%m-%d"`.tar.bz2.md5 -LATEST_TAR := http://linuxtv.org/downloads/drivers/linux-media-LATEST.tar.bz2 -LATEST_TAR_MD5 := http://linuxtv.org/downloads/drivers/linux-media-LATEST.tar.bz2.md5 - -default: - make -C .. - -help: - @echo "Use: make tar DIR=" - @echo " untar|clean|distclean" - -todaytar: - @if [ "$(DIR)" = "" ]; then echo "make $@ DIR="; exit -1; fi - -rm -f $(PWD)/$(TODAY_TAR).bz2 - tar cf $(PWD)/$(TODAY_TAR) -C $(DIR) $(TARFILES) - git --git-dir $(DIR)/.git log --pretty=oneline HEAD^1^1^1..HEAD >git_log - tar rvf $(PWD)/$(TODAY_TAR) git_log - for i in $(TARDIR); do \ - if [ "`echo $$i|grep Documentation`" = "" ]; then \ - dir="`(cd $(DIR); find $$i -type f -name '*.[ch]')`"; \ - dir="$$dir `(cd $(DIR); find $$i -type f -name Makefile)`"; \ - dir="$$dir `(cd $(DIR); find $$i -type f -name Kconfig)`"; \ - tar rvf $(PWD)/$(TODAY_TAR) -C $(DIR) $$dir; \ - else \ - tar rvf $(PWD)/$(TODAY_TAR) -C $(DIR) $$i; \ - fi; done; bzip2 $(PWD)/$(TODAY_TAR) - md5sum $(PWD)/$(TODAY_TAR).bz2 > $(PWD)/$(TODAY_TAR_MD5) - -tar: - @if [ "$(DIR)" = "" ]; then echo "make $@ DIR="; exit -1; fi - -rm -f $(PWD)/linux-media.tar.bz2 - tar cf $(PWD)/linux-media.tar -C $(DIR) $(TARFILES) - git --git-dir $(DIR)/.git log --pretty=oneline HEAD^1^1^1..HEAD >git_log - tar rvf $(PWD)/linux-media.tar git_log - for i in $(TARDIR); do \ - if [ "`echo $$i|grep Documentation`" = "" ]; then \ - dir="`(cd $(DIR); find $$i -type f -name '*.[ch]')`"; \ - dir="$$dir `(cd $(DIR); find $$i -type f -name Makefile)`"; \ - dir="$$dir `(cd $(DIR); find $$i -type f -name Kconfig)`"; \ - tar rvf $(PWD)/linux-media.tar -C $(DIR) $$dir; \ - else \ - tar rvf $(PWD)/linux-media.tar -C $(DIR) $$i; \ - fi; done; bzip2 $(PWD)/linux-media.tar - -untar: linux-media.tar.bz2 - tar xfj linux-media.tar.bz2 - -rm -f .patches_applied .linked_dir .git_log.md5 - -clean: - -rm -rf $(MAINDIRS) .patches_applied .linked_dir .git_log.md5 - -dir: clean - @lsdiff --version >/dev/null # Make 'make dir' fail if lsdiff is not installed - @if [ "$(DIR)" = "" ]; then echo "make $@ DIR="; exit -1; fi - @if [ ! -f "$(DIR)/include/linux/videodev2.h" ]; then echo "$(DIR) does not contain kernel sources"; exit -1; fi - @echo "Searching in $(DIR)/Makefile for kernel version." - ./use_dir.pl $(DIR) - -distclean: clean - -rm -f linux-media.tar.bz2 linux-media.tar.bz2.md5 - -apply_patches apply-patches: - @if [ -e .linked_dir ]; then ./use_dir.pl --recheck --silent; fi - @if [ "$(KERNELRELEASE)" != "" ]; then \ - if [ -e ../backports/v$(KERNELRELEASE)_series ]; then \ - dir="v$(KERNELRELEASE)"; \ - else \ - dir="v$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)"; \ - fi; \ - fi; \ - if [ "$(VER)" != "" ]; then dir="v$(VER)"; fi; \ - if [ "$$dir" = "" ]; then echo "make $@ VER="; exit -1; fi; \ - if [ -e .patches_applied ]; then \ - if [ "`cat .patches_applied|grep ^#`" = "#$$dir" ]; then \ - echo "Patches for $$dir already applied."; exit; \ - else \ - $(MAKE) unapply_patches; \ - fi; \ - fi; \ - if [ ! -e ../backports/$$dir_series ]; then echo "Version $$dir not supported."; exit 1; fi; \ - echo "Applying patches for kernel $$dir"; \ - touch .patches_applied; \ - for i in `cat ../backports/$${dir}_series`; do \ - echo patch -s -f -N -p1 -i ../backports/$$i; \ - patch -s -f -N -p1 -i ../backports/$$i --dry-run || exit 1; \ - patch -s -f -N -p1 -i ../backports/$$i; \ - mv .patches_applied .patches_applied.old; \ - echo $$i > .patches_applied; \ - cat .patches_applied.old >> .patches_applied; \ - done; \ - mv .patches_applied .patches_applied.old; \ - echo "#$$dir" > .patches_applied; \ - cat .patches_applied.old >> .patches_applied; \ - rm -f .patches_applied.old; \ - ./version_patch.pl; \ - if [ -e .linked_dir ]; then ./use_dir.pl --get_patched; fi - -unapply_patches unapply-patches: - @if [ -e .patches_applied ]; then \ - echo "Unapplying patches"; \ - for i in `cat .patches_applied|grep -v ^#`; do \ - echo patch -s -f -R -p1 -i ../backports/$$i; \ - patch -s -f -R -p1 -i ../backports/$$i || break; \ - done; \ - rm -f .patches_applied; fi - -download: - wget $(LATEST_TAR_MD5) -O linux-media.tar.bz2.md5.tmp - - @if [ "`cat linux-media.tar.bz2.md5.tmp`" != "`cat linux-media.tar.bz2.md5`" ]; then \ - wget $(LATEST_TAR) -O linux-media.tar.bz2; \ - mv linux-media.tar.bz2.md5.tmp linux-media.tar.bz2.md5; \ - fi diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/sound/i2c/other/tea575x-tuner.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/sound/i2c/other/tea575x-tuner.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/sound/i2c/other/tea575x-tuner.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/sound/i2c/other/tea575x-tuner.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,365 +0,0 @@ -/* - * ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips - * - * Copyright (c) 2004 Jaroslav Kysela - * - * - * 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, or - * (at your option) any later version. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Jaroslav Kysela "); -MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); -MODULE_LICENSE("GPL"); - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) -#define FREQ_LO (87 * 16000) -#define FREQ_HI (108 * 16000) - -/* - * definitions - */ - -#define TEA575X_BIT_SEARCH (1<<24) /* 1 = search action, 0 = tuned */ -#define TEA575X_BIT_UPDOWN (1<<23) /* 0 = search down, 1 = search up */ -#define TEA575X_BIT_MONO (1<<22) /* 0 = stereo, 1 = mono */ -#define TEA575X_BIT_BAND_MASK (3<<20) -#define TEA575X_BIT_BAND_FM (0<<20) -#define TEA575X_BIT_BAND_MW (1<<20) -#define TEA575X_BIT_BAND_LW (1<<21) -#define TEA575X_BIT_BAND_SW (1<<22) -#define TEA575X_BIT_PORT_0 (1<<19) /* user bit */ -#define TEA575X_BIT_PORT_1 (1<<18) /* user bit */ -#define TEA575X_BIT_SEARCH_MASK (3<<16) /* search level */ -#define TEA575X_BIT_SEARCH_5_28 (0<<16) /* FM >5uV, AM >28uV */ -#define TEA575X_BIT_SEARCH_10_40 (1<<16) /* FM >10uV, AM > 40uV */ -#define TEA575X_BIT_SEARCH_30_63 (2<<16) /* FM >30uV, AM > 63uV */ -#define TEA575X_BIT_SEARCH_150_1000 (3<<16) /* FM > 150uV, AM > 1000uV */ -#define TEA575X_BIT_DUMMY (1<<15) /* buffer */ -#define TEA575X_BIT_FREQ_MASK 0x7fff - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - } -}; - -/* - * lowlevel part - */ - -static void snd_tea575x_set_freq(struct snd_tea575x *tea) -{ - unsigned long freq; - - freq = tea->freq / 16; /* to kHz */ - if (freq > 108000) - freq = 108000; - if (freq < 87000) - freq = 87000; - /* crystal fixup */ - if (tea->tea5759) - freq -= tea->freq_fixup; - else - freq += tea->freq_fixup; - /* freq /= 12.5 */ - freq *= 10; - freq /= 125; - - tea->val &= ~TEA575X_BIT_FREQ_MASK; - tea->val |= freq & TEA575X_BIT_FREQ_MASK; - tea->ops->write(tea, tea->val); -} - -/* - * Linux Video interface - */ - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - struct snd_tea575x *tea = video_drvdata(file); - - strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757"); - strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); - strlcpy(v->card, "Maestro Radio", sizeof(v->card)); - sprintf(v->bus_info, "PCI"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - v->rangelow = FREQ_LO; - v->rangehigh = FREQ_HI; - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff; - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - if (v->index > 0) - return -EINVAL; - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct snd_tea575x *tea = video_drvdata(file); - - f->type = V4L2_TUNER_RADIO; - f->frequency = tea->freq; - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct snd_tea575x *tea = video_drvdata(file); - - if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) - return -EINVAL; - - tea->freq = f->frequency; - - snd_tea575x_set_freq(tea); - - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct snd_tea575x *tea = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (tea->ops->mute) { - ctrl->value = tea->mute; - return 0; - } - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct snd_tea575x *tea = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (tea->ops->mute) { - tea->ops->mute(tea, ctrl->value); - tea->mute = ctrl->value; - return 0; - } - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int snd_tea575x_exclusive_open(struct file *file) -{ - struct snd_tea575x *tea = video_drvdata(file); - - return test_and_set_bit(0, &tea->in_use) ? -EBUSY : 0; -} - -static int snd_tea575x_exclusive_release(struct file *file) -{ - struct snd_tea575x *tea = video_drvdata(file); - - clear_bit(0, &tea->in_use); - return 0; -} - -static const struct v4l2_file_operations tea575x_fops = { - .owner = THIS_MODULE, - .open = snd_tea575x_exclusive_open, - .release = snd_tea575x_exclusive_release, - .ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops tea575x_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static struct video_device tea575x_radio = { - .name = "tea575x-tuner", - .fops = &tea575x_fops, - .ioctl_ops = &tea575x_ioctl_ops, - .release = video_device_release, -}; - -/* - * initialize all the tea575x chips - */ -void snd_tea575x_init(struct snd_tea575x *tea) -{ - int retval; - unsigned int val; - struct video_device *tea575x_radio_inst; - - val = tea->ops->read(tea); - if (val == 0x1ffffff || val == 0) { - snd_printk(KERN_ERR - "tea575x-tuner: Cannot find TEA575x chip\n"); - return; - } - - tea->in_use = 0; - tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; - tea->freq = 90500 * 16; /* 90.5Mhz default */ - - tea575x_radio_inst = video_device_alloc(); - if (tea575x_radio_inst == NULL) { - printk(KERN_ERR "tea575x-tuner: not enough memory\n"); - return; - } - - memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio)); - - strcpy(tea575x_radio.name, tea->tea5759 ? - "TEA5759 radio" : "TEA5757 radio"); - - video_set_drvdata(tea575x_radio_inst, tea); - - retval = video_register_device(tea575x_radio_inst, - VFL_TYPE_RADIO, radio_nr); - if (retval) { - printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); - kfree(tea575x_radio_inst); - return; - } - - snd_tea575x_set_freq(tea); - - /* mute on init */ - if (tea->ops->mute) { - tea->ops->mute(tea, 1); - tea->mute = 1; - } - tea->vd = tea575x_radio_inst; -} - -void snd_tea575x_exit(struct snd_tea575x *tea) -{ - if (tea->vd) { - video_unregister_device(tea->vd); - tea->vd = NULL; - } -} - -static int __init alsa_tea575x_module_init(void) -{ - return 0; -} - -static void __exit alsa_tea575x_module_exit(void) -{ -} - -module_init(alsa_tea575x_module_init) -module_exit(alsa_tea575x_module_exit) - -EXPORT_SYMBOL(snd_tea575x_init); -EXPORT_SYMBOL(snd_tea575x_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/sound/pci/bt87x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/sound/pci/bt87x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/sound/pci/bt87x.c 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/sound/pci/bt87x.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,987 +0,0 @@ -/* - * bt87x.c - Brooktree Bt878/Bt879 driver for ALSA - * - * Copyright (c) Clemens Ladisch - * - * based on btaudio.c by Gerd Knorr - * - * - * This driver 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, or - * (at your option) any later version. - * - * This driver 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Clemens Ladisch "); -MODULE_DESCRIPTION("Brooktree Bt87x audio driver"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Brooktree,Bt878}," - "{Brooktree,Bt879}}"); - -static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int digital_rate[SNDRV_CARDS]; /* digital input rate */ -static int load_all; /* allow to load the non-whitelisted cards */ - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for Bt87x soundcard"); -module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for Bt87x soundcard"); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable Bt87x soundcard"); -module_param_array(digital_rate, int, NULL, 0444); -MODULE_PARM_DESC(digital_rate, "Digital input rate for Bt87x soundcard"); -module_param(load_all, bool, 0444); -MODULE_PARM_DESC(load_all, "Allow to load the non-whitelisted cards"); - - -/* register offsets */ -#define REG_INT_STAT 0x100 /* interrupt status */ -#define REG_INT_MASK 0x104 /* interrupt mask */ -#define REG_GPIO_DMA_CTL 0x10c /* audio control */ -#define REG_PACKET_LEN 0x110 /* audio packet lengths */ -#define REG_RISC_STRT_ADD 0x114 /* RISC program start address */ -#define REG_RISC_COUNT 0x120 /* RISC program counter */ - -/* interrupt bits */ -#define INT_OFLOW (1 << 3) /* audio A/D overflow */ -#define INT_RISCI (1 << 11) /* RISC instruction IRQ bit set */ -#define INT_FBUS (1 << 12) /* FIFO overrun due to bus access latency */ -#define INT_FTRGT (1 << 13) /* FIFO overrun due to target latency */ -#define INT_FDSR (1 << 14) /* FIFO data stream resynchronization */ -#define INT_PPERR (1 << 15) /* PCI parity error */ -#define INT_RIPERR (1 << 16) /* RISC instruction parity error */ -#define INT_PABORT (1 << 17) /* PCI master or target abort */ -#define INT_OCERR (1 << 18) /* invalid opcode */ -#define INT_SCERR (1 << 19) /* sync counter overflow */ -#define INT_RISC_EN (1 << 27) /* DMA controller running */ -#define INT_RISCS_SHIFT 28 /* RISC status bits */ - -/* audio control bits */ -#define CTL_FIFO_ENABLE (1 << 0) /* enable audio data FIFO */ -#define CTL_RISC_ENABLE (1 << 1) /* enable audio DMA controller */ -#define CTL_PKTP_4 (0 << 2) /* packet mode FIFO trigger point - 4 DWORDs */ -#define CTL_PKTP_8 (1 << 2) /* 8 DWORDs */ -#define CTL_PKTP_16 (2 << 2) /* 16 DWORDs */ -#define CTL_ACAP_EN (1 << 4) /* enable audio capture */ -#define CTL_DA_APP (1 << 5) /* GPIO input */ -#define CTL_DA_IOM_AFE (0 << 6) /* audio A/D input */ -#define CTL_DA_IOM_DA (1 << 6) /* digital audio input */ -#define CTL_DA_SDR_SHIFT 8 /* DDF first stage decimation rate */ -#define CTL_DA_SDR_MASK (0xf<< 8) -#define CTL_DA_LMT (1 << 12) /* limit audio data values */ -#define CTL_DA_ES2 (1 << 13) /* enable DDF stage 2 */ -#define CTL_DA_SBR (1 << 14) /* samples rounded to 8 bits */ -#define CTL_DA_DPM (1 << 15) /* data packet mode */ -#define CTL_DA_LRD_SHIFT 16 /* ALRCK delay */ -#define CTL_DA_MLB (1 << 21) /* MSB/LSB format */ -#define CTL_DA_LRI (1 << 22) /* left/right indication */ -#define CTL_DA_SCE (1 << 23) /* sample clock edge */ -#define CTL_A_SEL_STV (0 << 24) /* TV tuner audio input */ -#define CTL_A_SEL_SFM (1 << 24) /* FM audio input */ -#define CTL_A_SEL_SML (2 << 24) /* mic/line audio input */ -#define CTL_A_SEL_SMXC (3 << 24) /* MUX bypass */ -#define CTL_A_SEL_SHIFT 24 -#define CTL_A_SEL_MASK (3 << 24) -#define CTL_A_PWRDN (1 << 26) /* analog audio power-down */ -#define CTL_A_G2X (1 << 27) /* audio gain boost */ -#define CTL_A_GAIN_SHIFT 28 /* audio input gain */ -#define CTL_A_GAIN_MASK (0xf<<28) - -/* RISC instruction opcodes */ -#define RISC_WRITE (0x1 << 28) /* write FIFO data to memory at address */ -#define RISC_WRITEC (0x5 << 28) /* write FIFO data to memory at current address */ -#define RISC_SKIP (0x2 << 28) /* skip FIFO data */ -#define RISC_JUMP (0x7 << 28) /* jump to address */ -#define RISC_SYNC (0x8 << 28) /* synchronize with FIFO */ - -/* RISC instruction bits */ -#define RISC_BYTES_ENABLE (0xf << 12) /* byte enable bits */ -#define RISC_RESYNC ( 1 << 15) /* disable FDSR errors */ -#define RISC_SET_STATUS_SHIFT 16 /* set status bits */ -#define RISC_RESET_STATUS_SHIFT 20 /* clear status bits */ -#define RISC_IRQ ( 1 << 24) /* interrupt */ -#define RISC_EOL ( 1 << 26) /* end of line */ -#define RISC_SOL ( 1 << 27) /* start of line */ - -/* SYNC status bits values */ -#define RISC_SYNC_FM1 0x6 -#define RISC_SYNC_VRO 0xc - -#define ANALOG_CLOCK 1792000 -#ifdef CONFIG_SND_BT87X_OVERCLOCK -#define CLOCK_DIV_MIN 1 -#else -#define CLOCK_DIV_MIN 4 -#endif -#define CLOCK_DIV_MAX 15 - -#define ERROR_INTERRUPTS (INT_FBUS | INT_FTRGT | INT_PPERR | \ - INT_RIPERR | INT_PABORT | INT_OCERR) -#define MY_INTERRUPTS (INT_RISCI | ERROR_INTERRUPTS) - -/* SYNC, one WRITE per line, one extra WRITE per page boundary, SYNC, JUMP */ -#define MAX_RISC_SIZE ((1 + 255 + (PAGE_ALIGN(255 * 4092) / PAGE_SIZE - 1) + 1 + 1) * 8) - -/* Cards with configuration information */ -enum snd_bt87x_boardid { - SND_BT87X_BOARD_UNKNOWN, - SND_BT87X_BOARD_GENERIC, /* both an & dig interfaces, 32kHz */ - SND_BT87X_BOARD_ANALOG, /* board with no external A/D */ - SND_BT87X_BOARD_OSPREY2x0, - SND_BT87X_BOARD_OSPREY440, - SND_BT87X_BOARD_AVPHONE98, -}; - -/* Card configuration */ -struct snd_bt87x_board { - int dig_rate; /* Digital input sampling rate */ - u32 digital_fmt; /* Register settings for digital input */ - unsigned no_analog:1; /* No analog input */ - unsigned no_digital:1; /* No digital input */ -}; - -static __devinitdata struct snd_bt87x_board snd_bt87x_boards[] = { - [SND_BT87X_BOARD_UNKNOWN] = { - .dig_rate = 32000, /* just a guess */ - }, - [SND_BT87X_BOARD_GENERIC] = { - .dig_rate = 32000, - }, - [SND_BT87X_BOARD_ANALOG] = { - .no_digital = 1, - }, - [SND_BT87X_BOARD_OSPREY2x0] = { - .dig_rate = 44100, - .digital_fmt = CTL_DA_LRI | (1 << CTL_DA_LRD_SHIFT), - }, - [SND_BT87X_BOARD_OSPREY440] = { - .dig_rate = 32000, - .digital_fmt = CTL_DA_LRI | (1 << CTL_DA_LRD_SHIFT), - .no_analog = 1, - }, - [SND_BT87X_BOARD_AVPHONE98] = { - .dig_rate = 48000, - }, -}; - -struct snd_bt87x { - struct snd_card *card; - struct pci_dev *pci; - struct snd_bt87x_board board; - - void __iomem *mmio; - int irq; - - spinlock_t reg_lock; - unsigned long opened; - struct snd_pcm_substream *substream; - - struct snd_dma_buffer dma_risc; - unsigned int line_bytes; - unsigned int lines; - - u32 reg_control; - u32 interrupt_mask; - - int current_line; - - int pci_parity_errors; -}; - -enum { DEVICE_DIGITAL, DEVICE_ANALOG }; - -static inline u32 snd_bt87x_readl(struct snd_bt87x *chip, u32 reg) -{ - return readl(chip->mmio + reg); -} - -static inline void snd_bt87x_writel(struct snd_bt87x *chip, u32 reg, u32 value) -{ - writel(value, chip->mmio + reg); -} - -static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substream *substream, - unsigned int periods, unsigned int period_bytes) -{ - unsigned int i, offset; - u32 *risc; - - if (chip->dma_risc.area == NULL) { - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - PAGE_ALIGN(MAX_RISC_SIZE), &chip->dma_risc) < 0) - return -ENOMEM; - } - risc = (u32 *)chip->dma_risc.area; - offset = 0; - *risc++ = cpu_to_le32(RISC_SYNC | RISC_SYNC_FM1); - *risc++ = cpu_to_le32(0); - for (i = 0; i < periods; ++i) { - u32 rest; - - rest = period_bytes; - do { - u32 cmd, len; - unsigned int addr; - - len = PAGE_SIZE - (offset % PAGE_SIZE); - if (len > rest) - len = rest; - cmd = RISC_WRITE | len; - if (rest == period_bytes) { - u32 block = i * 16 / periods; - cmd |= RISC_SOL; - cmd |= block << RISC_SET_STATUS_SHIFT; - cmd |= (~block & 0xf) << RISC_RESET_STATUS_SHIFT; - } - if (len == rest) - cmd |= RISC_EOL | RISC_IRQ; - *risc++ = cpu_to_le32(cmd); - addr = snd_pcm_sgbuf_get_addr(substream, offset); - *risc++ = cpu_to_le32(addr); - offset += len; - rest -= len; - } while (rest > 0); - } - *risc++ = cpu_to_le32(RISC_SYNC | RISC_SYNC_VRO); - *risc++ = cpu_to_le32(0); - *risc++ = cpu_to_le32(RISC_JUMP); - *risc++ = cpu_to_le32(chip->dma_risc.addr); - chip->line_bytes = period_bytes; - chip->lines = periods; - return 0; -} - -static void snd_bt87x_free_risc(struct snd_bt87x *chip) -{ - if (chip->dma_risc.area) { - snd_dma_free_pages(&chip->dma_risc); - chip->dma_risc.area = NULL; - } -} - -static void snd_bt87x_pci_error(struct snd_bt87x *chip, unsigned int status) -{ - u16 pci_status; - - pci_read_config_word(chip->pci, PCI_STATUS, &pci_status); - pci_status &= PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | - PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | - PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY; - pci_write_config_word(chip->pci, PCI_STATUS, pci_status); - if (pci_status != PCI_STATUS_DETECTED_PARITY) - snd_printk(KERN_ERR "Aieee - PCI error! status %#08x, PCI status %#04x\n", - status & ERROR_INTERRUPTS, pci_status); - else { - snd_printk(KERN_ERR "Aieee - PCI parity error detected!\n"); - /* error 'handling' similar to aic7xxx_pci.c: */ - chip->pci_parity_errors++; - if (chip->pci_parity_errors > 20) { - snd_printk(KERN_ERR "Too many PCI parity errors observed.\n"); - snd_printk(KERN_ERR "Some device on this bus is generating bad parity.\n"); - snd_printk(KERN_ERR "This is an error *observed by*, not *generated by*, this card.\n"); - snd_printk(KERN_ERR "PCI parity error checking has been disabled.\n"); - chip->interrupt_mask &= ~(INT_PPERR | INT_RIPERR); - snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask); - } - } -} - -static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id) -{ - struct snd_bt87x *chip = dev_id; - unsigned int status, irq_status; - - status = snd_bt87x_readl(chip, REG_INT_STAT); - irq_status = status & chip->interrupt_mask; - if (!irq_status) - return IRQ_NONE; - snd_bt87x_writel(chip, REG_INT_STAT, irq_status); - - if (irq_status & ERROR_INTERRUPTS) { - if (irq_status & (INT_FBUS | INT_FTRGT)) - snd_printk(KERN_WARNING "FIFO overrun, status %#08x\n", status); - if (irq_status & INT_OCERR) - snd_printk(KERN_ERR "internal RISC error, status %#08x\n", status); - if (irq_status & (INT_PPERR | INT_RIPERR | INT_PABORT)) - snd_bt87x_pci_error(chip, irq_status); - } - if ((irq_status & INT_RISCI) && (chip->reg_control & CTL_ACAP_EN)) { - int current_block, irq_block; - - /* assume that exactly one line has been recorded */ - chip->current_line = (chip->current_line + 1) % chip->lines; - /* but check if some interrupts have been skipped */ - current_block = chip->current_line * 16 / chip->lines; - irq_block = status >> INT_RISCS_SHIFT; - if (current_block != irq_block) - chip->current_line = (irq_block * chip->lines + 15) / 16; - - snd_pcm_period_elapsed(chip->substream); - } - return IRQ_HANDLED; -} - -static struct snd_pcm_hardware snd_bt87x_digital_hw = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = 0, /* set at runtime */ - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 255 * 4092, - .period_bytes_min = 32, - .period_bytes_max = 4092, - .periods_min = 2, - .periods_max = 255, -}; - -static struct snd_pcm_hardware snd_bt87x_analog_hw = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, - .rates = SNDRV_PCM_RATE_KNOT, - .rate_min = ANALOG_CLOCK / CLOCK_DIV_MAX, - .rate_max = ANALOG_CLOCK / CLOCK_DIV_MIN, - .channels_min = 1, - .channels_max = 1, - .buffer_bytes_max = 255 * 4092, - .period_bytes_min = 32, - .period_bytes_max = 4092, - .periods_min = 2, - .periods_max = 255, -}; - -static int snd_bt87x_set_digital_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime) -{ - chip->reg_control |= CTL_DA_IOM_DA | CTL_A_PWRDN; - runtime->hw = snd_bt87x_digital_hw; - runtime->hw.rates = snd_pcm_rate_to_rate_bit(chip->board.dig_rate); - runtime->hw.rate_min = chip->board.dig_rate; - runtime->hw.rate_max = chip->board.dig_rate; - return 0; -} - -static int snd_bt87x_set_analog_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime) -{ - static struct snd_ratnum analog_clock = { - .num = ANALOG_CLOCK, - .den_min = CLOCK_DIV_MIN, - .den_max = CLOCK_DIV_MAX, - .den_step = 1 - }; - static struct snd_pcm_hw_constraint_ratnums constraint_rates = { - .nrats = 1, - .rats = &analog_clock - }; - - chip->reg_control &= ~(CTL_DA_IOM_DA | CTL_A_PWRDN); - runtime->hw = snd_bt87x_analog_hw; - return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &constraint_rates); -} - -static int snd_bt87x_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_bt87x *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - if (test_and_set_bit(0, &chip->opened)) - return -EBUSY; - - if (substream->pcm->device == DEVICE_DIGITAL) - err = snd_bt87x_set_digital_hw(chip, runtime); - else - err = snd_bt87x_set_analog_hw(chip, runtime); - if (err < 0) - goto _error; - - err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) - goto _error; - - chip->substream = substream; - return 0; - -_error: - clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); - return err; -} - -static int snd_bt87x_close(struct snd_pcm_substream *substream) -{ - struct snd_bt87x *chip = snd_pcm_substream_chip(substream); - - spin_lock_irq(&chip->reg_lock); - chip->reg_control |= CTL_A_PWRDN; - snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - spin_unlock_irq(&chip->reg_lock); - - chip->substream = NULL; - clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); - return 0; -} - -static int snd_bt87x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_bt87x *chip = snd_pcm_substream_chip(substream); - int err; - - err = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; - return snd_bt87x_create_risc(chip, substream, - params_periods(hw_params), - params_period_bytes(hw_params)); -} - -static int snd_bt87x_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_bt87x *chip = snd_pcm_substream_chip(substream); - - snd_bt87x_free_risc(chip); - snd_pcm_lib_free_pages(substream); - return 0; -} - -static int snd_bt87x_prepare(struct snd_pcm_substream *substream) -{ - struct snd_bt87x *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int decimation; - - spin_lock_irq(&chip->reg_lock); - chip->reg_control &= ~(CTL_DA_SDR_MASK | CTL_DA_SBR); - decimation = (ANALOG_CLOCK + runtime->rate / 4) / runtime->rate; - chip->reg_control |= decimation << CTL_DA_SDR_SHIFT; - if (runtime->format == SNDRV_PCM_FORMAT_S8) - chip->reg_control |= CTL_DA_SBR; - snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - spin_unlock_irq(&chip->reg_lock); - return 0; -} - -static int snd_bt87x_start(struct snd_bt87x *chip) -{ - spin_lock(&chip->reg_lock); - chip->current_line = 0; - chip->reg_control |= CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN; - snd_bt87x_writel(chip, REG_RISC_STRT_ADD, chip->dma_risc.addr); - snd_bt87x_writel(chip, REG_PACKET_LEN, - chip->line_bytes | (chip->lines << 16)); - snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask); - snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - spin_unlock(&chip->reg_lock); - return 0; -} - -static int snd_bt87x_stop(struct snd_bt87x *chip) -{ - spin_lock(&chip->reg_lock); - chip->reg_control &= ~(CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN); - snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - snd_bt87x_writel(chip, REG_INT_MASK, 0); - snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); - spin_unlock(&chip->reg_lock); - return 0; -} - -static int snd_bt87x_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_bt87x *chip = snd_pcm_substream_chip(substream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - return snd_bt87x_start(chip); - case SNDRV_PCM_TRIGGER_STOP: - return snd_bt87x_stop(chip); - default: - return -EINVAL; - } -} - -static snd_pcm_uframes_t snd_bt87x_pointer(struct snd_pcm_substream *substream) -{ - struct snd_bt87x *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - return (snd_pcm_uframes_t)bytes_to_frames(runtime, chip->current_line * chip->line_bytes); -} - -static struct snd_pcm_ops snd_bt87x_pcm_ops = { - .open = snd_bt87x_pcm_open, - .close = snd_bt87x_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_bt87x_hw_params, - .hw_free = snd_bt87x_hw_free, - .prepare = snd_bt87x_prepare, - .trigger = snd_bt87x_trigger, - .pointer = snd_bt87x_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - -static int snd_bt87x_capture_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 1; - info->value.integer.min = 0; - info->value.integer.max = 15; - return 0; -} - -static int snd_bt87x_capture_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); - - value->value.integer.value[0] = (chip->reg_control & CTL_A_GAIN_MASK) >> CTL_A_GAIN_SHIFT; - return 0; -} - -static int snd_bt87x_capture_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); - u32 old_control; - int changed; - - spin_lock_irq(&chip->reg_lock); - old_control = chip->reg_control; - chip->reg_control = (chip->reg_control & ~CTL_A_GAIN_MASK) - | (value->value.integer.value[0] << CTL_A_GAIN_SHIFT); - snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - changed = old_control != chip->reg_control; - spin_unlock_irq(&chip->reg_lock); - return changed; -} - -static struct snd_kcontrol_new snd_bt87x_capture_volume = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Volume", - .info = snd_bt87x_capture_volume_info, - .get = snd_bt87x_capture_volume_get, - .put = snd_bt87x_capture_volume_put, -}; - -#define snd_bt87x_capture_boost_info snd_ctl_boolean_mono_info - -static int snd_bt87x_capture_boost_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); - - value->value.integer.value[0] = !! (chip->reg_control & CTL_A_G2X); - return 0; -} - -static int snd_bt87x_capture_boost_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); - u32 old_control; - int changed; - - spin_lock_irq(&chip->reg_lock); - old_control = chip->reg_control; - chip->reg_control = (chip->reg_control & ~CTL_A_G2X) - | (value->value.integer.value[0] ? CTL_A_G2X : 0); - snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - changed = chip->reg_control != old_control; - spin_unlock_irq(&chip->reg_lock); - return changed; -} - -static struct snd_kcontrol_new snd_bt87x_capture_boost = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Boost", - .info = snd_bt87x_capture_boost_info, - .get = snd_bt87x_capture_boost_get, - .put = snd_bt87x_capture_boost_put, -}; - -static int snd_bt87x_capture_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - static const char *const texts[3] = {"TV Tuner", "FM", "Mic/Line"}; - - return snd_ctl_enum_info(info, 1, 3, texts); -} - -static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); - - value->value.enumerated.item[0] = (chip->reg_control & CTL_A_SEL_MASK) >> CTL_A_SEL_SHIFT; - return 0; -} - -static int snd_bt87x_capture_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); - u32 old_control; - int changed; - - spin_lock_irq(&chip->reg_lock); - old_control = chip->reg_control; - chip->reg_control = (chip->reg_control & ~CTL_A_SEL_MASK) - | (value->value.enumerated.item[0] << CTL_A_SEL_SHIFT); - snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - changed = chip->reg_control != old_control; - spin_unlock_irq(&chip->reg_lock); - return changed; -} - -static struct snd_kcontrol_new snd_bt87x_capture_source = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = snd_bt87x_capture_source_info, - .get = snd_bt87x_capture_source_get, - .put = snd_bt87x_capture_source_put, -}; - -static int snd_bt87x_free(struct snd_bt87x *chip) -{ - if (chip->mmio) - snd_bt87x_stop(chip); - if (chip->irq >= 0) - free_irq(chip->irq, chip); - if (chip->mmio) - iounmap(chip->mmio); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - kfree(chip); - return 0; -} - -static int snd_bt87x_dev_free(struct snd_device *device) -{ - struct snd_bt87x *chip = device->device_data; - return snd_bt87x_free(chip); -} - -static int __devinit snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name) -{ - int err; - struct snd_pcm *pcm; - - err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); - if (err < 0) - return err; - pcm->private_data = chip; - strcpy(pcm->name, name); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_bt87x_pcm_ops); - return snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), - 128 * 1024, - ALIGN(255 * 4092, 1024)); -} - -static int __devinit snd_bt87x_create(struct snd_card *card, - struct pci_dev *pci, - struct snd_bt87x **rchip) -{ - struct snd_bt87x *chip; - int err; - static struct snd_device_ops ops = { - .dev_free = snd_bt87x_dev_free - }; - - *rchip = NULL; - - err = pci_enable_device(pci); - if (err < 0) - return err; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) { - pci_disable_device(pci); - return -ENOMEM; - } - chip->card = card; - chip->pci = pci; - chip->irq = -1; - spin_lock_init(&chip->reg_lock); - - if ((err = pci_request_regions(pci, "Bt87x audio")) < 0) { - kfree(chip); - pci_disable_device(pci); - return err; - } - chip->mmio = pci_ioremap_bar(pci, 0); - if (!chip->mmio) { - snd_printk(KERN_ERR "cannot remap io memory\n"); - err = -ENOMEM; - goto fail; - } - - chip->reg_control = CTL_A_PWRDN | CTL_DA_ES2 | - CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT); - chip->interrupt_mask = MY_INTERRUPTS; - snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); - snd_bt87x_writel(chip, REG_INT_MASK, 0); - snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); - - err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED, - "Bt87x audio", chip); - if (err < 0) { - snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq); - goto fail; - } - chip->irq = pci->irq; - pci_set_master(pci); - synchronize_irq(chip->irq); - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err < 0) - goto fail; - - snd_card_set_dev(card, &pci->dev); - *rchip = chip; - return 0; - -fail: - snd_bt87x_free(chip); - return err; -} - -#define BT_DEVICE(chip, subvend, subdev, id) \ - { .vendor = PCI_VENDOR_ID_BROOKTREE, \ - .device = chip, \ - .subvendor = subvend, .subdevice = subdev, \ - .driver_data = SND_BT87X_BOARD_ ## id } -/* driver_data is the card id for that device */ - -static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = { - /* Hauppauge WinTV series */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), - /* Hauppauge WinTV series */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, GENERIC), - /* Viewcast Osprey 200 */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, OSPREY2x0), - /* Viewcast Osprey 440 (rate is configurable via gpio) */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff07, OSPREY440), - /* ATI TV-Wonder */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, GENERIC), - /* Leadtek Winfast tv 2000xp delux */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC), - /* Pinnacle PCTV */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x11bd, 0x0012, GENERIC), - /* Voodoo TV 200 */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC), - /* Askey Computer Corp. MagicTView'99 */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x144f, 0x3000, GENERIC), - /* AVerMedia Studio No. 103, 203, ...? */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98), - /* Prolink PixelView PV-M4900 */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1554, 0x4011, GENERIC), - /* Pinnacle Studio PCTV rave */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0xbd11, 0x1200, GENERIC), - { } -}; -MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); - -/* cards known not to have audio - * (DVB cards use the audio function to transfer MPEG data) */ -static struct { - unsigned short subvendor, subdevice; -} blacklist[] __devinitdata = { - {0x0071, 0x0101}, /* Nebula Electronics DigiTV */ - {0x11bd, 0x001c}, /* Pinnacle PCTV Sat */ - {0x11bd, 0x0026}, /* Pinnacle PCTV SAT CI */ - {0x1461, 0x0761}, /* AVermedia AverTV DVB-T */ - {0x1461, 0x0771}, /* AVermedia DVB-T 771 */ - {0x1822, 0x0001}, /* Twinhan VisionPlus DVB-T */ - {0x18ac, 0xd500}, /* DVICO FusionHDTV 5 Lite */ - {0x18ac, 0xdb10}, /* DVICO FusionHDTV DVB-T Lite */ - {0x18ac, 0xdb11}, /* Ultraview DVB-T Lite */ - {0x270f, 0xfc00}, /* Chaintech Digitop DST-1000 DVB-S */ - {0x7063, 0x2000}, /* pcHDTV HD-2000 TV */ -}; - -static struct pci_driver driver; - -/* return the id of the card, or a negative value if it's blacklisted */ -static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) -{ - int i; - const struct pci_device_id *supported; - - supported = pci_match_id(snd_bt87x_ids, pci); - if (supported && supported->driver_data > 0) - return supported->driver_data; - - for (i = 0; i < ARRAY_SIZE(blacklist); ++i) - if (blacklist[i].subvendor == pci->subsystem_vendor && - blacklist[i].subdevice == pci->subsystem_device) { - snd_printdd(KERN_INFO "card %#04x-%#04x:%#04x has no audio\n", - pci->device, pci->subsystem_vendor, pci->subsystem_device); - return -EBUSY; - } - - snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x\n", - pci->device, pci->subsystem_vendor, pci->subsystem_device); - snd_printk(KERN_DEBUG "please mail id, board name, and, " - "if it works, the correct digital_rate option to " - "\n"); - return SND_BT87X_BOARD_UNKNOWN; -} - -static int __devinit snd_bt87x_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) -{ - static int dev; - struct snd_card *card; - struct snd_bt87x *chip; - int err; - enum snd_bt87x_boardid boardid; - - if (!pci_id->driver_data) { - err = snd_bt87x_detect_card(pci); - if (err < 0) - return -ENODEV; - boardid = err; - } else - boardid = pci_id->driver_data; - - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - ++dev; - return -ENOENT; - } - - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); - if (err < 0) - return err; - - err = snd_bt87x_create(card, pci, &chip); - if (err < 0) - goto _error; - - memcpy(&chip->board, &snd_bt87x_boards[boardid], sizeof(chip->board)); - - if (!chip->board.no_digital) { - if (digital_rate[dev] > 0) - chip->board.dig_rate = digital_rate[dev]; - - chip->reg_control |= chip->board.digital_fmt; - - err = snd_bt87x_pcm(chip, DEVICE_DIGITAL, "Bt87x Digital"); - if (err < 0) - goto _error; - } - if (!chip->board.no_analog) { - err = snd_bt87x_pcm(chip, DEVICE_ANALOG, "Bt87x Analog"); - if (err < 0) - goto _error; - err = snd_ctl_add(card, snd_ctl_new1( - &snd_bt87x_capture_volume, chip)); - if (err < 0) - goto _error; - err = snd_ctl_add(card, snd_ctl_new1( - &snd_bt87x_capture_boost, chip)); - if (err < 0) - goto _error; - err = snd_ctl_add(card, snd_ctl_new1( - &snd_bt87x_capture_source, chip)); - if (err < 0) - goto _error; - } - snd_printk(KERN_INFO "bt87x%d: Using board %d, %sanalog, %sdigital " - "(rate %d Hz)\n", dev, boardid, - chip->board.no_analog ? "no " : "", - chip->board.no_digital ? "no " : "", chip->board.dig_rate); - - strcpy(card->driver, "Bt87x"); - sprintf(card->shortname, "Brooktree Bt%x", pci->device); - sprintf(card->longname, "%s at %#llx, irq %i", - card->shortname, (unsigned long long)pci_resource_start(pci, 0), - chip->irq); - strcpy(card->mixername, "Bt87x"); - - err = snd_card_register(card); - if (err < 0) - goto _error; - - pci_set_drvdata(pci, card); - ++dev; - return 0; - -_error: - snd_card_free(card); - return err; -} - -static void __devexit snd_bt87x_remove(struct pci_dev *pci) -{ - snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); -} - -/* default entries for all Bt87x cards - it's not exported */ -/* driver_data is set to 0 to call detection */ -static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), - { } -}; - -static struct pci_driver driver = { - .name = "Bt87x", - .id_table = snd_bt87x_ids, - .probe = snd_bt87x_probe, - .remove = __devexit_p(snd_bt87x_remove), -}; - -static int __init alsa_card_bt87x_init(void) -{ - if (load_all) - driver.id_table = snd_bt87x_default_ids; - return pci_register_driver(&driver); -} - -static void __exit alsa_card_bt87x_exit(void) -{ - pci_unregister_driver(&driver); -} - -module_init(alsa_card_bt87x_init) -module_exit(alsa_card_bt87x_exit) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/use_dir.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/use_dir.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/use_dir.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/use_dir.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,315 +0,0 @@ -#!/usr/bin/perl -use strict; -use File::Find; -use File::Path; -use File::Copy; -use Fcntl ':mode'; -use Getopt::Long; -use Digest::SHA1; - -my $silent = 0; -my $debug = 0; -my $recheck = 0; -my $get_patched = 0; -GetOptions( "--debug" => \$debug, - "--silent" => \$silent, - "--recheck" => \$recheck, - "--get_patched" => \$get_patched, - ); - -my $dir = shift; - -my $ctlfile = ".linked_dir"; -my $patchfile = ".patches_applied"; - -my $sync_patched = 0; -my %dirs; -my %files; -my $patches_applied; - -######################################### -# Control info stored at the control file -my $path; -my %fhash; -my %fhash_patched; -######################################### - -sub read_ctlfile() -{ - my $line; - - open IN, $ctlfile or return; - while () { - next if (m/^\s*\#/); - next if (m/^\n$/); - if (m/^path:\s*([^\s]+)/) { - $path = $1; - } elsif (m/^hash\:\s*([^\s]+)\s*=\s*([^\s]+)/) { - $fhash{$1} = $2; - } elsif (m/^hash_patched\:\s*([^\s]+)\s*=\s*([^\s]+)/) { - $fhash_patched{$1} = $2; - } else { - printf("Parse error on this line of $ctlfile:\n\t$_"); - die; - } - } - close IN; -} - -sub write_ctlfile() -{ - open OUT, ">$ctlfile" or print "Error: Can't write to $ctlfile\n"; - print OUT "path: $path\n"; - foreach my $file (keys %fhash) { - printf OUT "hash: %s=%s\n", $file, $fhash{$file}; - } - foreach my $file (keys %fhash_patched) { - printf OUT "hash_patched: %s=%s\n", $file, $fhash_patched{$file}; - } - close OUT; -} - -sub add_dirs($) -{ - my $data = shift; - my @dirs = split(' ', $data); - - foreach my $val (@dirs) { - $dirs{$val} = 1; - } -} - -sub add_files($) -{ - my $data = shift; - my @dirs = split(' ', $data); - - foreach my $val (@dirs) { - $files{$val} = 1; - } -} - -sub get_file_dir_names() -{ - open IN, "Makefile" or die "Couldn't open Makefile"; - while () { - if (m/^\s*TARDIR\s*[\+\:]*=\s*([A-Za-z_].*)/) { - add_dirs($1); - } elsif (m/^\s*TARFILES\s*[\+\:]*=\s*([A-Za-z_].*)/) { - add_files($1); - } - } - close IN; -} - - -sub hash_calc($) -{ - my $file = shift; - - my $ctx = Digest::SHA1->new; - - my $rc = open INHASH, $file; - if (!$rc) { - print "Couldn't open file $file\n" if ($debug); - return 0; - } - $ctx->addfile(*INHASH); - my $digest = $ctx->hexdigest; - close INHASH; - - return $digest; -} - -sub sync_files($) -{ - my $file = shift; - my $path = $file; - my $check_hash; - my $need_sync; - my $filehash; - my $cpfilehash; - my $patched_file; - - $path =~ s,/[^/]+$,,; - - $filehash = hash_calc("$dir/$file"); - $need_sync = 1 if ($filehash ne $fhash{$file}); - - if (!$need_sync && $recheck) { - $cpfilehash = hash_calc("$file"); - if ($patches_applied && exists($fhash_patched{$file})) { - $patched_file = 1; - $need_sync = 1 if ($cpfilehash ne $fhash_patched{$file}); - } else { - $need_sync = 1 if ($cpfilehash ne $fhash{$file}); - } - } - - if ($need_sync) { - printf "Sync'ing file $file (orig = %s, copy = %s, patched = %s)\n", - $filehash, $cpfilehash, $fhash_patched{$file} if ($debug || $recheck); - - if (exists($fhash_patched{$file})) { - $sync_patched = 1; - } else { - $fhash{$file} = $filehash; - mkpath($path); - copy("$dir/$file", $file); - } - } else { - print "Skipping file $file, as is already synchronized\n" if ($debug); - } -} - -sub get_patched_files() -{ - my %files; - - open IN, $patchfile or return %files; - - # Those files are always patched to add warnings about the usage of experimental version - $files{"drivers/media/dvb/dvb-core/dvbdev.c"} = 1; - $files{"drivers/media/video/v4l2-dev.c"} = 1; - $files{"drivers/media/rc/rc-main.c"} = 1; - - while () { - next if (/^\s*#/); - - if (m/(.*)\n/) { - print ("Backport ../backports/$1 touch(es) file(s):\n") if ($debug); - open IN2, "lsdiff -h --strip 1 ../backports/$1 |"; - while () { - my $f = $_; - $f =~ s/\n//; - $files{$f} = 1; - print ("\t$f\n") if ($debug); - } - close IN2; - } - } - close IN; - - return %files; -} - -sub sync_patched_files() -{ - my %patches = get_patched_files(); - return if (!%patches); - - foreach my $file (keys %patches) { -printf "sync patched file $file\n"; - $fhash{$file} = hash_calc("$dir/$file"); - mkpath($path); - copy("$dir/$file", $file); - } - close IN; -} - -sub get_patched_hashes() -{ - my %patches = get_patched_files(); - return if (!%patches); - - foreach my $file (keys %patches) { - $fhash_patched{$file} = hash_calc("$file"); - printf "Hash for patched file $file = %s\n", $fhash_patched{$file} if ($debug); - } - close IN; -} - -sub remove_deleted() -{ - my $file = $File::Find::name; - my $mode = (stat($file))[2]; - - return if ($mode & S_IFDIR); - - return if ($file =~ /^\./); - return if ($file =~ /\.mod\.c/); - - if ($file =~ /Makefile$/ || $file =~ /Kconfig$/ || $file =~ /\.[ch]$/ ) { - if (! -e "$dir/$file") { - printf "Removing file $file\n" if (!$silent); - delete $fhash{$file} if exists($fhash{$file}); - delete $fhash_patched{$file} if exists($fhash_patched{$file}); - unlink $file; - return; - } - } -} - -sub parse_dir() -{ - my $file = $File::Find::name; - my $mode = (stat($file))[2]; - - return if ($mode & S_IFDIR); - - $file =~ s,^($dir/),,; - - return if ($file =~ /^\./); - return if ($file =~ /\.mod\.c/); - - if ($file =~ /Makefile$/ || $file =~ /Kconfig$/ || $file =~ /\.[ch]$/ ) { - sync_files $file; - return; - } - - printf "Skipping bogus file $file\n" if ($debug); -} - -sub sync_dirs($) -{ - my $subdir = shift; - - print "sync dir: $subdir\n" if (!$silent); - find({wanted => \&parse_dir, no_chdir => 1}, "$dir/$subdir"); - find({wanted => \&remove_deleted, no_chdir => 1}, "$subdir"); -} - -sub sync_all() -{ - foreach my $val (keys %files) { - print "sync file: $val\n" if (!$silent); - sync_files($val); - } - foreach my $val (keys %dirs) { - sync_dirs($val); - } -} - -# Main - -if (!$dir) { - read_ctlfile(); - die "Please provide a directory to use" if !($path); - $dir = $path; - - printf "Syncing with dir $dir\n"; -} else { - read_ctlfile(); -} - -if ($path ne $dir) { - $path = $dir; - %fhash = (); -} - -$patches_applied = 1 if (-e $patchfile); - -if ($get_patched && $patches_applied) { - get_patched_hashes(); -} else { - get_file_dir_names(); - sync_all(); - - if ($sync_patched) { - sync_patched_files(); - unlink $patchfile; - } -} - -write_ctlfile(); -system "git --git-dir $dir/.git log --pretty=oneline HEAD^1^1^1^1^1^1..HEAD >git_log" diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/version_patch.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/version_patch.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/linux/version_patch.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/linux/version_patch.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -#!/usr/bin/perl -use strict; - - -sub patch_file($$$$) -{ - my $filename = shift; - my $function = shift; - my $after_line = shift; - my $media_build_version = shift; - my $patched; - my $warning = "WARNING: You are using an experimental version of the media stack."; - - open IN, "$filename" or die "can't open $filename"; - my $is_function; - my $file; - while () { - next if (m/($warning)/); - $file .= $_; - if (m/($function)/) { - $is_function = 1; - next; - }; - next if (!$is_function); - if (/\}/) { - $is_function--; - next; - }; - if (m/\{/) { - $is_function++; - next; - }; - if ($is_function && m/($after_line)/) { - $file .= "\tprintk(KERN_ERR \"$warning\\n" . - "\\tAs the driver is backported to an older kernel, it doesn't offer\\n" . - "\\tenough quality for its usage in production.\\n" . - "\\tUse it with care.\\n$media_build_version\\n\");\n"; - $is_function = 0; - $patched++; - next; - }; - } - close IN; - - open OUT, ">$filename.new" or die "Can't open $filename.new"; - print OUT $file; - close OUT; - rename "$filename", "$filename~" or die "Can't rename $filename to $filename~"; - rename "$filename.new", "$filename" or die "Can't rename $filename.new to $filename"; - if ($patched) { - print "Patched $filename\n"; - } else { - die "$filename was not patched.\n"; - } -} - -# -# Main -# - -# Prepare patches message -open IN, "git_log" or die "can't open git_log"; -my $logs; -$logs.=$_ while (); -close IN; -$logs =~ s/\s+$//; -$logs =~ s,\n,\\n\\t,g; -$logs =~ s,\",\\\",g; -$logs = "Latest git patches (needed if you report a bug to linux-media\@vger.kernel.org):\\n\\t$logs"; - -my $need_patch; -open IN, "md5sum git_log|" or die "can't find git_log"; -my $hash = ; -close IN; -open IN, ".git_log.md5" or $need_patch = 1; -if (!$need_patch) { - $need_patch = 1 if ($hash ne ); -} - -if ($need_patch) { - # Patch dvbdev - patch_file "drivers/media/dvb/dvb-core/dvbdev.c", "__init init_dvbdev", "MKDEV", $logs; - # Patch v4l2-dev - patch_file "drivers/media/video/v4l2-dev.c", "__init videodev_init", "printk", $logs; - # Patch rc core - patch_file "drivers/media/rc/rc-main.c", "__init rc_core_init", "rc_map_register", $logs; - - open OUT,">.git_log.md5"; - print OUT $hash; - close OUT; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -BUILD_DIR := $(shell pwd)/v4l -TMP ?= /tmp -REPO_PULL := http://linuxtv.org/hg/v4l-dvb - -ifeq ($(EDITOR),) - ifeq ($(VISUAL),) - EDITOR := vi - else - EDITOR := $(VISUAL) -w - endif -endif - -all: - -install: - $(MAKE) -C $(BUILD_DIR) install - -# Hmm, .PHONY does not work with wildcard rules :-( -SPECS = media-specs - -.PHONY: $(SPECS) - -$(SPECS): - $(MAKE) -C $(BUILD_DIR) $(MAKECMDGOALS) - -%:: - $(MAKE) -C $(BUILD_DIR) $(MAKECMDGOALS) - -commit cvscommit hgcommit change changes changelog:: whitespace - @cd $(BUILD_DIR); scripts/cardlist; scripts/do_commit.sh $(EDITOR) $(TMP)/v4l_hg_whitespace; cd .. - -qrefresh: Q=q -qrefresh:: whitespace - cd $(BUILD_DIR); scripts/cardlist; cd .. - v4l/scripts/prep_commit_msg.pl -q $(TMP)/v4l_hg_whitespace > \ - $(TMP)/v4l_hg_commit.msg - $(EDITOR) $(TMP)/v4l_hg_commit.msg - grep -v '^#' $(TMP)/v4l_hg_commit.msg | hg qrefresh -g -l - - -whitespace whitespaces: - @echo "Cleaning bad whitespaces" - @v4l/scripts/strip-trailing-whitespaces.sh $(Q)fast | \ - tee $(TMP)/v4l_hg_whitespace | patch -p0 - -download untar:: - $(MAKE) -C linux/ $(MAKECMDGOALS) - -dir:: - $(MAKE) -C linux/ $(MAKECMDGOALS) DIR="../$(DIR)" diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/Avoid-unnecessary-data-copying-inside-dvb_dmx_swfilter_204-function.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/Avoid-unnecessary-data-copying-inside-dvb_dmx_swfilter_204-function.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/Avoid-unnecessary-data-copying-inside-dvb_dmx_swfilter_204-function.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/Avoid-unnecessary-data-copying-inside-dvb_dmx_swfilter_204-function.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -diff --git a/linux/drivers/media/dvb/dvb-core/dvb_demux.c b/linux/drivers/media/dvb/dvb-core/dvb_demux.c -index 977ddba..b71d77d 100644 ---- a/linux/drivers/media/dvb/dvb-core/dvb_demux.c -+++ b/linux/drivers/media/dvb/dvb-core/dvb_demux.c -@@ -478,97 +478,96 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, - - EXPORT_SYMBOL(dvb_dmx_swfilter_packets); - --void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) -+static inline int findNextPacket(const u8 *buf, int pos, size_t count, -+ const int pktsize) - { -- int p = 0, i, j; -+ int start = pos, lost; - -- spin_lock(&demux->lock); -- -- if (demux->tsbufp) { -- i = demux->tsbufp; -- j = 188 - i; -- if (count < j) { -- memcpy(&demux->tsbuf[i], buf, count); -- demux->tsbufp += count; -- goto bailout; -- } -- memcpy(&demux->tsbuf[i], buf, j); -- if (demux->tsbuf[0] == 0x47) -- dvb_dmx_swfilter_packet(demux, demux->tsbuf); -- demux->tsbufp = 0; -- p += j; -+ while(likely(pos < count)) { -+ if (likely(buf[pos] == 0x47 || -+ (pktsize == 204 && buf[pos] == 0xB8))) -+ break; -+ pos++; - } - -- while (p < count) { -- if (buf[p] == 0x47) { -- if (count - p >= 188) { -- dvb_dmx_swfilter_packet(demux, &buf[p]); -- p += 188; -- } else { -- i = count - p; -- memcpy(demux->tsbuf, &buf[p], i); -- demux->tsbufp = i; -- goto bailout; -- } -- } else -- p++; -+ if (unlikely(lost = pos - start)) { -+ /* This garbage is part of a valid packet? */ -+ int backtrack = pos - pktsize; -+ if (backtrack >= 0 && (buf[backtrack] == 0x47 || -+ (pktsize == 204 && buf[backtrack] == 0xB8))) { -+ /* printk("demux: backtracked %d bytes" -+ * "\n", start - backtrack); */ -+ return backtrack; -+ } -+ /*printk("demux: skipped %d bytes at %d\n", lost, start); */ - } - --bailout: -- spin_unlock(&demux->lock); -+ return pos; - } - --EXPORT_SYMBOL(dvb_dmx_swfilter); -- --void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) -+/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */ -+static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, -+ size_t count, const int pktsize) - { - int p = 0, i, j; -- u8 tmppack[188]; -+ const u8 *q; - - spin_lock(&demux->lock); - -- if (demux->tsbufp) { -+ if (likely(demux->tsbufp)) { /* tsbuf[0] is now 0x47. */ - i = demux->tsbufp; -- j = 204 - i; -- if (count < j) { -+ j = pktsize - i; -+ if (unlikely(count < j)) { - memcpy(&demux->tsbuf[i], buf, count); - demux->tsbufp += count; - goto bailout; - } - memcpy(&demux->tsbuf[i], buf, j); -- if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) { -- memcpy(tmppack, demux->tsbuf, 188); -- if (tmppack[0] == 0xB8) -- tmppack[0] = 0x47; -- dvb_dmx_swfilter_packet(demux, tmppack); -- } -+ if (likely(demux->tsbuf[0] == 0x47)) /* double check */ -+ dvb_dmx_swfilter_packet(demux, demux->tsbuf); - demux->tsbufp = 0; - p += j; - } - -- while (p < count) { -- if ((buf[p] == 0x47) || (buf[p] == 0xB8)) { -- if (count - p >= 204) { -- memcpy(tmppack, &buf[p], 188); -- if (tmppack[0] == 0xB8) -- tmppack[0] = 0x47; -- dvb_dmx_swfilter_packet(demux, tmppack); -- p += 204; -- } else { -- i = count - p; -- memcpy(demux->tsbuf, &buf[p], i); -- demux->tsbufp = i; -- goto bailout; -- } -- } else { -- p++; -+ while (likely((p = findNextPacket(buf, p, count, pktsize)) < count)) { -+ if (unlikely(count - p < pktsize)) -+ break; -+ -+ q = &buf[p]; -+ -+ if (unlikely(pktsize == 204 && (*q == 0xB8))) { -+ memcpy(demux->tsbuf, q, 188); -+ demux->tsbuf[0] = 0x47; -+ q = demux->tsbuf; - } -+ dvb_dmx_swfilter_packet(demux, q); -+ p += pktsize; -+ } -+ -+ i = count - p; -+ if (likely(i)) { -+ memcpy(demux->tsbuf, &buf[p], i); -+ demux->tsbufp = i; -+ if (unlikely(pktsize == 204 && demux->tsbuf[0] == 0xB8)) -+ demux->tsbuf[0] = 0x47; - } - - bailout: - spin_unlock(&demux->lock); - } - -+void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) -+{ -+ _dvb_dmx_swfilter(demux, buf, count, 188); -+} -+ -+EXPORT_SYMBOL(dvb_dmx_swfilter); -+ -+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) -+{ -+ _dvb_dmx_swfilter(demux, buf, count, 204); -+} -+ - EXPORT_SYMBOL(dvb_dmx_swfilter_204); - - static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/Refactor-Mantis-DMA-transfer-to-deliver-16Kb-TS-data-per-interrupt.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/Refactor-Mantis-DMA-transfer-to-deliver-16Kb-TS-data-per-interrupt.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/Refactor-Mantis-DMA-transfer-to-deliver-16Kb-TS-data-per-interrupt.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/Refactor-Mantis-DMA-transfer-to-deliver-16Kb-TS-data-per-interrupt.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,187 +0,0 @@ -diff --git a/linux/drivers/media/dvb/mantis/hopper_cards.c b/linux/drivers/media/dvb/mantis/hopper_cards.c -index 09e9fc7..3b7e376 100644 ---- a/linux/drivers/media/dvb/mantis/hopper_cards.c -+++ b/linux/drivers/media/dvb/mantis/hopper_cards.c -@@ -126,7 +126,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) - } - if (stat & MANTIS_INT_RISCI) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); -- mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; -+ mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; - tasklet_schedule(&mantis->tasklet); - } - if (stat & MANTIS_INT_I2CDONE) { -diff --git a/linux/drivers/media/dvb/mantis/mantis_cards.c b/linux/drivers/media/dvb/mantis/mantis_cards.c -index cf4b39f..8f048d5 100644 ---- a/linux/drivers/media/dvb/mantis/mantis_cards.c -+++ b/linux/drivers/media/dvb/mantis/mantis_cards.c -@@ -134,7 +134,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) - } - if (stat & MANTIS_INT_RISCI) { - dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); -- mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; -+ mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; - tasklet_schedule(&mantis->tasklet); - } - if (stat & MANTIS_INT_I2CDONE) { -diff --git a/linux/drivers/media/dvb/mantis/mantis_common.h b/linux/drivers/media/dvb/mantis/mantis_common.h -index d0b645a..23b23b7 100644 ---- a/linux/drivers/media/dvb/mantis/mantis_common.h -+++ b/linux/drivers/media/dvb/mantis/mantis_common.h -@@ -122,11 +122,8 @@ struct mantis_pci { - unsigned int num; - - /* RISC Core */ -- u32 finished_block; -+ u32 busy_block; - u32 last_block; -- u32 line_bytes; -- u32 line_count; -- u32 risc_pos; - u8 *buf_cpu; - dma_addr_t buf_dma; - u32 *risc_cpu; -diff --git a/linux/drivers/media/dvb/mantis/mantis_dma.c b/linux/drivers/media/dvb/mantis/mantis_dma.c -index 46202a4..c61ca7d 100644 ---- a/linux/drivers/media/dvb/mantis/mantis_dma.c -+++ b/linux/drivers/media/dvb/mantis/mantis_dma.c -@@ -43,13 +43,17 @@ - #define RISC_IRQ (0x01 << 24) - - #define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) --#define RISC_FLUSH() (mantis->risc_pos = 0) --#define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode)) -+#define RISC_FLUSH(risc_pos) (risc_pos = 0) -+#define RISC_INSTR(risc_pos, opcode) (mantis->risc_cpu[risc_pos++] = cpu_to_le32(opcode)) - - #define MANTIS_BUF_SIZE (64 * 1024) --#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4) --#define MANTIS_BLOCK_COUNT (1 << 4) --#define MANTIS_RISC_SIZE PAGE_SIZE -+#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE / 4) -+#define MANTIS_DMA_TR_BYTES (2 * 1024) /* upper limit: 4095 bytes. */ -+#define MANTIS_BLOCK_COUNT (MANTIS_BUF_SIZE / MANTIS_BLOCK_BYTES) -+ -+#define MANTIS_DMA_TR_UNITS (MANTIS_BLOCK_BYTES / MANTIS_DMA_TR_BYTES) -+/* MANTIS_BUF_SIZE / MANTIS_DMA_TR_UNITS must not exceed MANTIS_RISC_SIZE (4k RISC cmd buffer) */ -+#define MANTIS_RISC_SIZE PAGE_SIZE /* RISC program must fit here. */ - - int mantis_dma_exit(struct mantis_pci *mantis) - { -@@ -124,27 +128,6 @@ err: - return -ENOMEM; - } - --static inline int mantis_calc_lines(struct mantis_pci *mantis) --{ -- mantis->line_bytes = MANTIS_BLOCK_BYTES; -- mantis->line_count = MANTIS_BLOCK_COUNT; -- -- while (mantis->line_bytes > 4095) { -- mantis->line_bytes >>= 1; -- mantis->line_count <<= 1; -- } -- -- dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]", -- MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count); -- -- if (mantis->line_count > 255) { -- dprintk(MANTIS_ERROR, 1, "Buffer size error"); -- return -EINVAL; -- } -- -- return 0; --} -- - int mantis_dma_init(struct mantis_pci *mantis) - { - int err = 0; -@@ -158,12 +141,6 @@ int mantis_dma_init(struct mantis_pci *mantis) - - goto err; - } -- err = mantis_calc_lines(mantis); -- if (err < 0) { -- dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed"); -- -- goto err; -- } - - return 0; - err: -@@ -174,31 +151,32 @@ EXPORT_SYMBOL_GPL(mantis_dma_init); - static inline void mantis_risc_program(struct mantis_pci *mantis) - { - u32 buf_pos = 0; -- u32 line; -+ u32 line, step; -+ u32 risc_pos; - - dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program"); -- RISC_FLUSH(); -- -- dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u", -- mantis->line_count, mantis->line_bytes); -- -- for (line = 0; line < mantis->line_count; line++) { -- dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line); -- if (!(buf_pos % MANTIS_BLOCK_BYTES)) { -- RISC_INSTR(RISC_WRITE | -- RISC_IRQ | -- RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) + -- (MANTIS_BLOCK_COUNT - 1)) % -- MANTIS_BLOCK_COUNT) | -- mantis->line_bytes); -- } else { -- RISC_INSTR(RISC_WRITE | mantis->line_bytes); -- } -- RISC_INSTR(mantis->buf_dma + buf_pos); -- buf_pos += mantis->line_bytes; -+ RISC_FLUSH(risc_pos); -+ -+ dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u, bytes per DMA tr %u", -+ MANTIS_BLOCK_COUNT, MANTIS_BLOCK_BYTES, MANTIS_DMA_TR_BYTES); -+ -+ for (line = 0; line < MANTIS_BLOCK_COUNT; line++) { -+ for (step = 0; step < MANTIS_DMA_TR_UNITS; step++) { -+ dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d], step=[%d]", line, step); -+ if (step == 0) { -+ RISC_INSTR(risc_pos, RISC_WRITE | -+ RISC_IRQ | -+ RISC_STATUS(line) | -+ MANTIS_DMA_TR_BYTES); -+ } else { -+ RISC_INSTR(risc_pos, RISC_WRITE | MANTIS_DMA_TR_BYTES); -+ } -+ RISC_INSTR(risc_pos, mantis->buf_dma + buf_pos); -+ buf_pos += MANTIS_DMA_TR_BYTES; -+ } - } -- RISC_INSTR(RISC_JUMP); -- RISC_INSTR(mantis->risc_dma); -+ RISC_INSTR(risc_pos, RISC_JUMP); -+ RISC_INSTR(risc_pos, mantis->risc_dma); - } - - void mantis_dma_start(struct mantis_pci *mantis) -@@ -210,7 +188,7 @@ void mantis_dma_start(struct mantis_pci *mantis) - mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); - - mmwrite(0, MANTIS_DMA_CTL); -- mantis->last_block = mantis->finished_block = 0; -+ mantis->last_block = mantis->busy_block = 0; - - mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); - -@@ -245,9 +223,9 @@ void mantis_dma_xfer(unsigned long data) - struct mantis_pci *mantis = (struct mantis_pci *) data; - struct mantis_hwconfig *config = mantis->hwconfig; - -- while (mantis->last_block != mantis->finished_block) { -+ while (mantis->last_block != mantis->busy_block) { - dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]", -- mantis->last_block, mantis->finished_block); -+ mantis->last_block, mantis->busy_block); - - (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) - (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/tt-s2-double-fix.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/tt-s2-double-fix.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/tt-s2-double-fix.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/tt-s2-double-fix.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -diff -r 7c0b887911cf linux/drivers/media/dvb/frontends/stv090x.c ---- a/linux/drivers/media/dvb/frontends/stv090x.c Mon Apr 05 22:56:43 2010 -0400 -+++ b/linux/drivers/media/dvb/frontends/stv090x.c Sun Apr 11 13:46:43 2010 +0200 -@@ -4664,7 +4664,7 @@ - if (stv090x_i2c_gate_ctrl(state, 1) < 0) - goto err; - -- if (state->config->tuner_sleep) { -+ if (fe->tuner_priv && state->config->tuner_sleep) { - if (state->config->tuner_sleep(fe) < 0) - goto err_gateoff; - } - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.31_device_type.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.31_device_type.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.31_device_type.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.31_device_type.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ ---- linux/drivers/media/rc/rc-main.c.orig 2011-03-11 18:44:43.734443972 +0100 -+++ linux/drivers/media/rc/rc-main.c 2011-03-11 18:44:56.371948200 +0100 -@@ -904,7 +904,7 @@ - .attrs = rc_dev_attrs, - }; - --static const struct attribute_group *rc_dev_attr_groups[] = { -+static struct attribute_group *rc_dev_attr_groups[] = { - &rc_dev_attr_grp, - NULL - }; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.31_nodename.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.31_nodename.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.31_nodename.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.31_nodename.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.c b/linux/drivers/media/dvb/dvb-core/dvbdev.c ---- a/linux/drivers/media/dvb/dvb-core/dvbdev.c -+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.c -@@ -449,7 +449,7 @@ static int dvb_uevent(struct device *dev - return 0; - } - --static char *dvb_devnode(struct device *dev, mode_t *mode) -+static char *dvb_nodename(struct device *dev) - { - struct dvb_device *dvbdev = dev_get_drvdata(dev); - -@@ -480,7 +480,7 @@ static int __init init_dvbdev(void) - goto error; - } - dvb_class->dev_uevent = dvb_uevent; -- dvb_class->devnode = dvb_devnode; -+ dvb_class->nodename = dvb_nodename; - return 0; - - error: -diff --git a/linux/drivers/media/rc/rc-main.c b/linux/drivers/media/rc/rc-main.c ---- a/linux/drivers/media/rc/rc-main.c -+++ b/linux/drivers/media/rc/rc-main.c -@@ -673,14 +673,14 @@ static void ir_close(struct input_dev *i - } - - /* class for /sys/class/rc */ --static char *ir_devnode(struct device *dev, mode_t *mode) -+static char *ir_nodename(struct device *dev) - { - return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev)); - } - - static struct class ir_input_class = { - .name = "rc", -- .devnode = ir_devnode, -+ .nodename = ir_nodename, - }; - - static struct { diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.32_kfifo.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.32_kfifo.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.32_kfifo.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.32_kfifo.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,540 +0,0 @@ -diff -r c4cd3d2e5902 linux/drivers/media/rc/rc-core-priv.h ---- a/linux/drivers/media/rc/rc-core-priv.h Mon Nov 29 08:40:01 2010 -0200 -+++ b/linux/drivers/media/rc/rc-core-priv.h Mon Nov 29 08:42:43 2010 -0200 -@@ -35,7 +35,7 @@ struct ir_raw_event_ctrl { - struct list_head list; /* to keep track of raw clients */ - struct task_struct *thread; - spinlock_t lock; -- struct kfifo kfifo; /* fifo for the pulse/space durations */ -+ struct kfifo *kfifo; /* fifo for the pulse/space durations */ - ktime_t last_event; /* when last event occurred */ - enum raw_event_type last_type; /* last event type */ - struct rc_dev *dev; /* pointer to the parent rc_dev */ -diff -r c4cd3d2e5902 linux/drivers/media/rc/ir-raw.c ---- a/linux/drivers/media/rc/ir-raw.c Mon Nov 29 08:40:01 2010 -0200 -+++ b/linux/drivers/media/rc/ir-raw.c Mon Nov 29 08:42:43 2010 -0200 -@@ -44,7 +44,7 @@ static int ir_raw_event_thread(void *dat - while (!kthread_should_stop()) { - - spin_lock_irq(&raw->lock); -- retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev)); -+ retval = __kfifo_get(raw->kfifo, (void *)&ev, sizeof(ev)); - - if (!retval) { - set_current_state(TASK_INTERRUPTIBLE); -@@ -90,7 +90,7 @@ int ir_raw_event_store(struct rc_dev *de - IR_dprintk(2, "sample: (%05dus %s)\n", - TO_US(ev->duration), TO_STR(ev->pulse)); - -- if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) -+ if (__kfifo_put(dev->raw->kfifo, (void *)ev, sizeof(*ev)) != sizeof(*ev)) - return -ENOMEM; - - return 0; -@@ -259,11 +259,11 @@ int ir_raw_event_register(struct rc_dev - - dev->raw->dev = dev; - dev->raw->enabled_protocols = ~0; -- rc = kfifo_alloc(&dev->raw->kfifo, -- sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, -- GFP_KERNEL); -- if (rc < 0) -+ dev->raw->kfifo = kfifo_alloc(sizeof(s64) * MAX_IR_EVENT_SIZE, GFP_KERNEL, NULL); -+ if (IS_ERR(dev->raw->kfifo)) { -+ rc = PTR_ERR(dev->raw->kfifo); - goto out; -+ } - - spin_lock_init(&dev->raw->lock); - dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, -@@ -305,7 +305,7 @@ void ir_raw_event_unregister(struct rc_d - handler->raw_unregister(dev); - mutex_unlock(&ir_raw_handler_lock); - -- kfifo_free(&dev->raw->kfifo); -+ kfifo_free(dev->raw->kfifo); - kfree(dev->raw); - dev->raw = NULL; - } -diff -r c4cd3d2e5902 linux/drivers/media/video/cx23885/cx23888-ir.c ---- a/linux/drivers/media/video/cx23885/cx23888-ir.c Mon Nov 29 08:40:01 2010 -0200 -+++ b/linux/drivers/media/video/cx23885/cx23888-ir.c Mon Nov 29 08:42:43 2010 -0200 -@@ -138,7 +138,7 @@ struct cx23888_ir_state { - atomic_t rxclk_divider; - atomic_t rx_invert; - -- struct kfifo rx_kfifo; -+ struct kfifo *rx_kfifo; - spinlock_t rx_kfifo_lock; - - struct v4l2_subdev_ir_parameters tx_params; -@@ -540,7 +540,6 @@ static int cx23888_ir_irq_handler(struct - { - struct cx23888_ir_state *state = to_state(sd); - struct cx23885_dev *dev = state->dev; -- unsigned long flags; - - u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); - u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); -@@ -613,10 +612,9 @@ static int cx23888_ir_irq_handler(struct - } - if (i == 0) - break; -- j = i * sizeof(union cx23888_ir_fifo_rec); -- k = kfifo_in_locked(&state->rx_kfifo, -- (unsigned char *) rx_data, j, -- &state->rx_kfifo_lock); -+ j = i * sizeof(u32); -+ k = kfifo_put(state->rx_kfifo, -+ (unsigned char *) rx_data, j); - if (k != j) - kror++; /* rx_kfifo over run */ - } -@@ -653,10 +651,8 @@ static int cx23888_ir_irq_handler(struct - *handled = true; - } - -- spin_lock_irqsave(&state->rx_kfifo_lock, flags); -- if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) -+ if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) - events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; -- spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); - - if (events) - v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); -@@ -682,7 +678,7 @@ static int cx23888_ir_rx_read(struct v4l - return 0; - } - -- n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock); -+ n = kfifo_get(state->rx_kfifo, buf, n); - - n /= sizeof(union cx23888_ir_fifo_rec); - *num = n * sizeof(union cx23888_ir_fifo_rec); -@@ -817,12 +813,7 @@ static int cx23888_ir_rx_s_parameters(st - o->interrupt_enable = p->interrupt_enable; - o->enable = p->enable; - if (p->enable) { -- unsigned long flags; -- -- spin_lock_irqsave(&state->rx_kfifo_lock, flags); -- kfifo_reset(&state->rx_kfifo); -- /* reset tx_fifo too if there is one... */ -- spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); -+ kfifo_reset(state->rx_kfifo); - if (p->interrupt_enable) - irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); - control_rx_enable(dev, p->enable); -@@ -1210,8 +1201,10 @@ int cx23888_ir_probe(struct cx23885_dev - return -ENOMEM; - - spin_lock_init(&state->rx_kfifo_lock); -- if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL)) -- return -ENOMEM; -+ state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL, -+ &state->rx_kfifo_lock); -+ if (IS_ERR(state->rx_kfifo)) -+ return IS_ERR(state->rx_kfifo); - - state->dev = dev; - state->id = V4L2_IDENT_CX23888_IR; -@@ -1243,7 +1236,7 @@ int cx23888_ir_probe(struct cx23885_dev - sizeof(struct v4l2_subdev_ir_parameters)); - v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); - } else { -- kfifo_free(&state->rx_kfifo); -+ kfifo_free(state->rx_kfifo); - } - return ret; - } -@@ -1262,7 +1255,7 @@ int cx23888_ir_remove(struct cx23885_dev - - state = to_state(sd); - v4l2_device_unregister_subdev(sd); -- kfifo_free(&state->rx_kfifo); -+ kfifo_free(state->rx_kfifo); - kfree(state); - /* Nothing more to free() as state held the actual v4l2_subdev object */ - return 0; -diff -r c4cd3d2e5902 linux/drivers/media/video/cx25840/cx25840-ir.c ---- a/linux/drivers/media/video/cx25840/cx25840-ir.c Mon Nov 29 08:40:01 2010 -0200 -+++ b/linux/drivers/media/video/cx25840/cx25840-ir.c Mon Nov 29 08:42:43 2010 -0200 -@@ -116,7 +116,7 @@ struct cx25840_ir_state { - atomic_t rxclk_divider; - atomic_t rx_invert; - -- struct kfifo rx_kfifo; -+ struct kfifo *rx_kfifo; - spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */ - - struct v4l2_subdev_ir_parameters tx_params; -@@ -525,7 +525,6 @@ int cx25840_ir_irq_handler(struct v4l2_s - struct cx25840_state *state = to_state(sd); - struct cx25840_ir_state *ir_state = to_ir_state(sd); - struct i2c_client *c = NULL; -- unsigned long flags; - - union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; - unsigned int i, j, k; -@@ -611,9 +610,8 @@ int cx25840_ir_irq_handler(struct v4l2_s - if (i == 0) - break; - j = i * sizeof(union cx25840_ir_fifo_rec); -- k = kfifo_in_locked(&ir_state->rx_kfifo, -- (unsigned char *) rx_data, j, -- &ir_state->rx_kfifo_lock); -+ k = kfifo_put(ir_state->rx_kfifo, -+ (unsigned char *) rx_data, j); - if (k != j) - kror++; /* rx_kfifo over run */ - } -@@ -649,10 +647,8 @@ int cx25840_ir_irq_handler(struct v4l2_s - cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl); - *handled = true; - } -- spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); -- if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) -+ if (kfifo_len(ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) - events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; -- spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); - - if (events) - v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); -@@ -683,8 +679,7 @@ static int cx25840_ir_rx_read(struct v4l - return 0; - } - -- n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n, -- &ir_state->rx_kfifo_lock); -+ n = kfifo_get(ir_state->rx_kfifo, buf, n); - - n /= sizeof(union cx25840_ir_fifo_rec); - *num = n * sizeof(union cx25840_ir_fifo_rec); -@@ -836,11 +831,7 @@ static int cx25840_ir_rx_s_parameters(st - o->interrupt_enable = p->interrupt_enable; - o->enable = p->enable; - if (p->enable) { -- unsigned long flags; -- -- spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); -- kfifo_reset(&ir_state->rx_kfifo); -- spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); -+ kfifo_reset(ir_state->rx_kfifo); - if (p->interrupt_enable) - irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); - control_rx_enable(c, p->enable); -@@ -1234,8 +1225,9 @@ int cx25840_ir_probe(struct v4l2_subdev - return -ENOMEM; - - spin_lock_init(&ir_state->rx_kfifo_lock); -- if (kfifo_alloc(&ir_state->rx_kfifo, -- CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) { -+ ir_state->rx_kfifo = kfifo_alloc(CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL, -+ &ir_state->rx_kfifo_lock); -+ if (IS_ERR(ir_state->rx_kfifo)) { - kfree(ir_state); - return -ENOMEM; - } -@@ -1273,7 +1265,7 @@ int cx25840_ir_remove(struct v4l2_subdev - cx25840_ir_rx_shutdown(sd); - cx25840_ir_tx_shutdown(sd); - -- kfifo_free(&ir_state->rx_kfifo); -+ kfifo_free(ir_state->rx_kfifo); - kfree(ir_state); - state->ir_state = NULL; - return 0; -diff -r c4cd3d2e5902 linux/drivers/media/video/meye.c ---- a/linux/drivers/media/video/meye.c Mon Nov 29 08:40:01 2010 -0200 -+++ b/linux/drivers/media/video/meye.c Mon Nov 29 08:42:43 2010 -0200 -@@ -802,8 +802,8 @@ again: - return IRQ_HANDLED; - - if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) { -- if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, -- sizeof(int), &meye.grabq_lock) != sizeof(int)) { -+ if (kfifo_get(meye.grabq, (unsigned char *)&reqnr, -+ sizeof(int)) != sizeof(int)) { - mchip_free_frame(); - return IRQ_HANDLED; - } -@@ -813,8 +813,7 @@ again: - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); - meye.grab_buffer[reqnr].sequence = sequence++; -- kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, -- sizeof(int), &meye.doneq_lock); -+ kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); - wake_up_interruptible(&meye.proc_list); - } else { - int size; -@@ -823,8 +822,8 @@ again: - mchip_free_frame(); - goto again; - } -- if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, -- sizeof(int), &meye.grabq_lock) != sizeof(int)) { -+ if (kfifo_get(meye.grabq, (unsigned char *)&reqnr, -+ sizeof(int)) != sizeof(int)) { - mchip_free_frame(); - goto again; - } -@@ -834,8 +833,7 @@ again: - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); - meye.grab_buffer[reqnr].sequence = sequence++; -- kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, -- sizeof(int), &meye.doneq_lock); -+ kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); - wake_up_interruptible(&meye.proc_list); - } - mchip_free_frame(); -@@ -863,8 +861,8 @@ static int meye_open(struct file *file) - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; -- kfifo_reset(&meye.grabq); -- kfifo_reset(&meye.doneq); -+ kfifo_reset(meye.grabq); -+ kfifo_reset(meye.doneq); - return 0; - } - -@@ -937,8 +935,7 @@ static int meyeioc_qbuf_capt(int *nb) - mchip_cont_compression_start(); - - meye.grab_buffer[*nb].state = MEYE_BUF_USING; -- kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int), -- &meye.grabq_lock); -+ kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int)); - mutex_unlock(&meye.lock); - - return 0; -@@ -970,9 +967,7 @@ static int meyeioc_sync(struct file *fil - /* fall through */ - case MEYE_BUF_DONE: - meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; -- if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused, -- sizeof(int), &meye.doneq_lock) != sizeof(int)) -- break; -+ kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int)); - } - *i = meye.grab_buffer[*i].size; - mutex_unlock(&meye.lock); -@@ -1459,8 +1454,7 @@ static int vidioc_qbuf(struct file *file - buf->flags |= V4L2_BUF_FLAG_QUEUED; - buf->flags &= ~V4L2_BUF_FLAG_DONE; - meye.grab_buffer[buf->index].state = MEYE_BUF_USING; -- kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index, -- sizeof(int), &meye.grabq_lock); -+ kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int)); - mutex_unlock(&meye.lock); - - return 0; -@@ -1475,19 +1469,19 @@ static int vidioc_dqbuf(struct file *fil - - mutex_lock(&meye.lock); - -- if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { -+ if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - - if (wait_event_interruptible(meye.proc_list, -- kfifo_len(&meye.doneq) != 0) < 0) { -+ kfifo_len(meye.doneq) != 0) < 0) { - mutex_unlock(&meye.lock); - return -EINTR; - } - -- if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr, -- sizeof(int), &meye.doneq_lock)) { -+ if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr, -+ sizeof(int))) { - mutex_unlock(&meye.lock); - return -EBUSY; - } -@@ -1537,8 +1531,8 @@ static int vidioc_streamoff(struct file - { - mutex_lock(&meye.lock); - mchip_hic_stop(); -- kfifo_reset(&meye.grabq); -- kfifo_reset(&meye.doneq); -+ kfifo_reset(meye.grabq); -+ kfifo_reset(meye.doneq); - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; -@@ -1580,7 +1574,7 @@ static unsigned int meye_poll(struct fil - - mutex_lock(&meye.lock); - poll_wait(file, &meye.proc_list, wait); -- if (kfifo_len(&meye.doneq)) -+ if (kfifo_len(meye.doneq)) - res = POLLIN | POLLRDNORM; - mutex_unlock(&meye.lock); - return res; -@@ -1759,14 +1753,16 @@ static int __devinit meye_probe(struct p - } - - spin_lock_init(&meye.grabq_lock); -- if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, -- GFP_KERNEL)) { -+ meye.grabq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL, -+ &meye.grabq_lock); -+ if (IS_ERR(meye.grabq)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); - goto outkfifoalloc1; - } - spin_lock_init(&meye.doneq_lock); -- if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, -- GFP_KERNEL)) { -+ meye.doneq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL, -+ &meye.doneq_lock); -+ if (IS_ERR(meye.doneq)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); - goto outkfifoalloc2; - } -@@ -1877,9 +1873,9 @@ outregions: - outenabledev: - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); - outsonypienable: -- kfifo_free(&meye.doneq); -+ kfifo_free(meye.doneq); - outkfifoalloc2: -- kfifo_free(&meye.grabq); -+ kfifo_free(meye.grabq); - outkfifoalloc1: - vfree(meye.grab_temp); - outvmalloc: -@@ -1910,8 +1906,8 @@ static void __devexit meye_remove(struct - - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); - -- kfifo_free(&meye.doneq); -- kfifo_free(&meye.grabq); -+ kfifo_free(meye.doneq); -+ kfifo_free(meye.grabq); - - vfree(meye.grab_temp); - -diff -r c4cd3d2e5902 linux/drivers/media/video/meye.h ---- a/linux/drivers/media/video/meye.h Mon Nov 29 08:40:01 2010 -0200 -+++ b/linux/drivers/media/video/meye.h Mon Nov 29 08:42:43 2010 -0200 -@@ -304,9 +304,9 @@ struct meye { - struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; - int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */ - struct mutex lock; /* mutex for open/mmap... */ -- struct kfifo grabq; /* queue for buffers to be grabbed */ -+ struct kfifo *grabq; /* queue for buffers to be grabbed */ - spinlock_t grabq_lock; /* lock protecting the queue */ -- struct kfifo doneq; /* queue for grabbed buffers */ -+ struct kfifo *doneq; /* queue for grabbed buffers */ - spinlock_t doneq_lock; /* lock protecting the queue */ - wait_queue_head_t proc_list; /* wait queue */ - struct video_device *vdev; /* video device parameters */ -diff -r c4cd3d2e5902 linux/include/media/lirc_dev.h ---- a/linux/include/media/lirc_dev.h Mon Nov 29 08:40:01 2010 -0200 -+++ b/linux/include/media/lirc_dev.h Mon Nov 29 08:42:43 2010 -0200 -@@ -28,19 +28,15 @@ struct lirc_buffer { - unsigned int size; /* in chunks */ - /* Using chunks instead of bytes pretends to simplify boundary checking - * And should allow for some performance fine tunning later */ -- struct kfifo fifo; -+ struct kfifo *fifo; - u8 fifo_initialized; - }; - - static inline void lirc_buffer_clear(struct lirc_buffer *buf) - { -- unsigned long flags; -- -- if (buf->fifo_initialized) { -- spin_lock_irqsave(&buf->fifo_lock, flags); -- kfifo_reset(&buf->fifo); -- spin_unlock_irqrestore(&buf->fifo_lock, flags); -- } else -+ if (buf->fifo) -+ kfifo_reset(buf->fifo); -+ else - WARN(1, "calling %s on an uninitialized lirc_buffer\n", - __func__); - } -@@ -49,25 +45,23 @@ static inline int lirc_buffer_init(struc - unsigned int chunk_size, - unsigned int size) - { -- int ret; -- - init_waitqueue_head(&buf->wait_poll); - spin_lock_init(&buf->fifo_lock); - buf->chunk_size = chunk_size; - buf->size = size; -- ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL); -- if (ret == 0) -- buf->fifo_initialized = 1; -+ buf->fifo = kfifo_alloc(size * chunk_size, GFP_KERNEL, -+ &buf->fifo_lock); -+ if (IS_ERR(buf->fifo)) -+ return IS_ERR(buf->fifo); - -- return ret; -+ return 0; - } - - static inline void lirc_buffer_free(struct lirc_buffer *buf) - { -- if (buf->fifo_initialized) { -- kfifo_free(&buf->fifo); -- buf->fifo_initialized = 0; -- } else -+ if (buf->fifo) -+ kfifo_free(buf->fifo); -+ else - WARN(1, "calling %s on an uninitialized lirc_buffer\n", - __func__); - } -@@ -75,11 +69,8 @@ static inline void lirc_buffer_free(stru - static inline int lirc_buffer_len(struct lirc_buffer *buf) - { - int len; -- unsigned long flags; - -- spin_lock_irqsave(&buf->fifo_lock, flags); -- len = kfifo_len(&buf->fifo); -- spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ len = kfifo_len(buf->fifo); - - return len; - } -@@ -102,24 +93,19 @@ static inline int lirc_buffer_available( - static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf, - unsigned char *dest) - { -- unsigned int ret = 0; -+ if (lirc_buffer_len(buf) >= buf->chunk_size) -+ kfifo_get(buf->fifo, dest, buf->chunk_size); - -- if (lirc_buffer_len(buf) >= buf->chunk_size) -- ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size, -- &buf->fifo_lock); -- return ret; -+ return 0; - - } - - static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, - unsigned char *orig) - { -- unsigned int ret; -+ kfifo_put(buf->fifo, orig, buf->chunk_size); - -- ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size, -- &buf->fifo_lock); -- -- return ret; -+ return 0; - } - - struct lirc_driver { diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.33_input_handlers_are_int.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.33_input_handlers_are_int.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.33_input_handlers_are_int.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.33_input_handlers_are_int.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -diff --git a/linux/drivers/media/rc/rc-main.c b/linux/drivers/media/rc/rc-main.c ---- a/linux/drivers/media/rc/rc-main.c -+++ b/linux/drivers/media/rc/rc-main.c -@@ -318,7 +318,7 @@ static unsigned int ir_establish_scancod - * This routine is used to handle evdev EVIOCSKEY ioctl. - */ - static int ir_setkeycode(struct input_dev *idev, -- unsigned int scancode, unsigned int keycode) -+ int scancode, int keycode) - { - struct rc_dev *rdev = input_get_drvdata(idev); - struct ir_scancode_table *rc_tab = &rdev->rc_tab; -@@ -423,7 +423,7 @@ static unsigned int ir_lookup_by_scancod - * This routine is used to handle evdev EVIOCGKEY ioctl. - */ - static int ir_getkeycode(struct input_dev *idev, -- unsigned int scancode, unsigned int *keycode) -+ int scancode, int *keycode) - { - struct rc_dev *rdev = input_get_drvdata(idev); - struct ir_scancode_table *rc_tab = &rdev->rc_tab; -diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c ---- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c -+++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c -@@ -9,7 +9,7 @@ - #include - - static int legacy_dvb_usb_getkeycode(struct input_dev *dev, -- unsigned int scancode, unsigned int *keycode) -+ int scancode, int *keycode) - { - struct dvb_usb_device *d = input_get_drvdata(dev); - -@@ -39,7 +39,7 @@ static int legacy_dvb_usb_getkeycode(str - } - - static int legacy_dvb_usb_setkeycode(struct input_dev *dev, -- unsigned int scancode, unsigned int keycode) -+ int scancode, int keycode) - { - struct dvb_usb_device *d = input_get_drvdata(dev); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.33_pvrusb2_sysfs.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.33_pvrusb2_sysfs.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.33_pvrusb2_sysfs.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.33_pvrusb2_sysfs.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -diff -r 5254948f88c4 linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c ---- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c Sun Oct 17 19:59:28 2010 -0200 -+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c Sun Oct 17 20:09:02 2010 -0200 -@@ -423,12 +423,10 @@ - - dip = kzalloc(sizeof(*dip),GFP_KERNEL); - if (!dip) return; -- sysfs_attr_init(&dip->attr_debugcmd.attr); - dip->attr_debugcmd.attr.name = "debugcmd"; - dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP; - dip->attr_debugcmd.show = debugcmd_show; - dip->attr_debugcmd.store = debugcmd_store; -- sysfs_attr_init(&dip->attr_debuginfo.attr); - dip->attr_debuginfo.attr.name = "debuginfo"; - dip->attr_debuginfo.attr.mode = S_IRUGO; - dip->attr_debuginfo.show = debuginfo_show; -@@ -650,8 +648,6 @@ - kfree(class_dev); - return; - } -- -- sysfs_attr_init(&sfp->attr_v4l_minor_number.attr); - sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number"; - sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; - sfp->attr_v4l_minor_number.show = v4l_minor_number_show; -@@ -665,8 +661,6 @@ - } else { - sfp->v4l_minor_number_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_v4l_radio_minor_number.attr); - sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number"; - sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; - sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; -@@ -680,8 +674,6 @@ - } else { - sfp->v4l_radio_minor_number_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_unit_number.attr); - sfp->attr_unit_number.attr.name = "unit_number"; - sfp->attr_unit_number.attr.mode = S_IRUGO; - sfp->attr_unit_number.show = unit_number_show; -@@ -694,8 +686,6 @@ - } else { - sfp->unit_number_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_bus_info.attr); - sfp->attr_bus_info.attr.name = "bus_info_str"; - sfp->attr_bus_info.attr.mode = S_IRUGO; - sfp->attr_bus_info.show = bus_info_show; -@@ -709,8 +699,6 @@ - } else { - sfp->bus_info_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_hdw_name.attr); - sfp->attr_hdw_name.attr.name = "device_hardware_type"; - sfp->attr_hdw_name.attr.mode = S_IRUGO; - sfp->attr_hdw_name.show = hdw_name_show; -@@ -724,8 +712,6 @@ - } else { - sfp->hdw_name_created_ok = !0; - } -- -- sysfs_attr_init(&sfp->attr_hdw_desc.attr); - sfp->attr_hdw_desc.attr.name = "device_hardware_description"; - sfp->attr_hdw_desc.attr.mode = S_IRUGO; - sfp->attr_hdw_desc.show = hdw_desc_show; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.34_dvb_net.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.34_dvb_net.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.34_dvb_net.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.34_dvb_net.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -diff -r 5254948f88c4 linux/drivers/media/dvb/dvb-core/dvb_net.c ---- a/linux/drivers/media/dvb/dvb-core/dvb_net.c Sun Oct 17 19:59:28 2010 -0200 -+++ b/linux/drivers/media/dvb/dvb-core/dvb_net.c Sun Oct 17 20:09:51 2010 -0200 -@@ -1119,14 +1119,14 @@ - } - - --static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr) -+static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) - { - struct dvb_net_priv *priv = netdev_priv(dev); - - if (priv->multi_num == DVB_NET_MULTICAST_MAX) - return -ENOMEM; - -- memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN); -+ memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6); - - priv->multi_num++; - return 0; -@@ -1150,16 +1150,15 @@ - dprintk("%s: allmulti mode\n", dev->name); - priv->rx_mode = RX_MODE_ALL_MULTI; - } else if (!netdev_mc_empty(dev)) { -- struct netdev_hw_addr *ha; -- -+ struct dev_mc_list *mc; - dprintk("%s: set_mc_list, %d entries\n", - dev->name, netdev_mc_count(dev)); - - priv->rx_mode = RX_MODE_MULTI; - priv->multi_num = 0; - -- netdev_for_each_mc_addr(ha, dev) -- dvb_set_mc_filter(dev, ha->addr); -+ netdev_for_each_mc_addr(mc, dev) -+ dvb_set_mc_filter(dev, mc); - } - - netif_addr_unlock_bh(dev); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.34_fix_define_warnings.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.34_fix_define_warnings.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.34_fix_define_warnings.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.34_fix_define_warnings.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -diff -r a0ea01e58ec5 linux/drivers/media/rc/imon.c ---- a/linux/drivers/media/rc/imon.c Wed Oct 27 20:58:38 2010 -0200 -+++ b/linux/drivers/media/rc/imon.c Wed Oct 27 21:07:04 2010 -0200 -@@ -26,6 +26,7 @@ - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -+#undef pr_fmt - #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - - #include -diff -r a0ea01e58ec5 linux/drivers/media/dvb/frontends/tua6100.c ---- a/linux/drivers/media/dvb/frontends/tua6100.c Wed Oct 27 20:58:38 2010 -0200 -+++ b/linux/drivers/media/dvb/frontends/tua6100.c Wed Oct 27 21:07:04 2010 -0200 -@@ -80,6 +80,7 @@ - struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 }; - struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 }; - -+#undef _P - #define _R 4 - #define _P 32 - #define _ri 4000000 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_firedtv_handle_fcp.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_firedtv_handle_fcp.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_firedtv_handle_fcp.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_firedtv_handle_fcp.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -diff -r 22cb011c456d linux/drivers/media/dvb/firewire/firedtv-fw.c ---- a/linux/drivers/media/dvb/firewire/firedtv-fw.c Tue Oct 26 14:18:02 2010 -0200 -+++ b/linux/drivers/media/dvb/firewire/firedtv-fw.c Wed Oct 27 21:35:30 2010 -0200 -@@ -193,9 +193,9 @@ - }; - - static void handle_fcp(struct fw_card *card, struct fw_request *request, -- int tcode, int destination, int source, int generation, -- unsigned long long offset, void *payload, size_t length, -- void *callback_data) -+ int tcode, int destination, int source, int generation, -+ int speed, unsigned long long offset, -+ void *payload, size_t length, void *callback_data) - { - struct firedtv *f, *fdtv = NULL; - struct fw_device *device; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_i2c_new_probed_device.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_i2c_new_probed_device.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_i2c_new_probed_device.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_i2c_new_probed_device.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -diff --git a/linux/drivers/media/video/bt8xx/bttv-input.c b/linux/drivers/media/video/bt8xx/bttv-input.c ---- a/linux/drivers/media/video/bt8xx/bttv-input.c -+++ b/linux/drivers/media/video/bt8xx/bttv-input.c -@@ -401,7 +401,7 @@ void __devinit init_bttv_i2c_ir(struct b - * That's why we probe 0x1a (~0x34) first. CB - */ - -- i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); -+ i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list); - return; - } - -diff --git a/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c ---- a/linux/drivers/media/video/cx18/cx18-i2c.c -+++ b/linux/drivers/media/video/cx18/cx18-i2c.c -@@ -104,7 +104,7 @@ static int cx18_i2c_new_ir(struct cx18 * - break; - } - -- return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? -+ return i2c_new_probed_device(adap, &info, addr_list) == NULL ? - -1 : 0; - } - -diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c ---- a/linux/drivers/media/video/cx23885/cx23885-i2c.c -+++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c -@@ -354,7 +354,8 @@ int cx23885_i2c_register(struct cx23885_ - } else - printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", - dev->name, bus->nr); -- -+#if 0 -+ /* This probe function won't work on older devices */ - /* Instantiate the IR receiver device, if present */ - if (0 == bus->i2c_rc) { - struct i2c_board_info info; -@@ -369,7 +370,7 @@ int cx23885_i2c_register(struct cx23885_ - i2c_new_probed_device(&bus->i2c_adap, &info, addr_list, - i2c_probe_func_quick_read); - } -- -+#endif - return bus->i2c_rc; - } - -diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c ---- a/linux/drivers/media/video/em28xx/em28xx-cards.c -+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c -@@ -2446,7 +2446,7 @@ void em28xx_register_i2c_ir(struct em28x - - if (dev->init_data.name) - info.platform_data = &dev->init_data; -- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL); -+ i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); - } - - void em28xx_card_setup(struct em28xx *dev) -diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c ---- a/linux/drivers/media/video/ivtv/ivtv-i2c.c -+++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c -@@ -186,7 +186,7 @@ static int ivtv_i2c_new_ir(struct ivtv * - return -1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, type, I2C_NAME_SIZE); -- return i2c_new_probed_device(adap, &info, addr_list, NULL) -+ return i2c_new_probed_device(adap, &info, addr_list) - == NULL ? -1 : 0; - } - -@@ -231,7 +231,7 @@ static int ivtv_i2c_new_ir(struct ivtv * - info.platform_data = init_data; - strlcpy(info.type, type, I2C_NAME_SIZE); - -- return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? -+ return i2c_new_probed_device(adap, &info, addr_list) == NULL ? - -1 : 0; - } - -@@ -258,7 +258,7 @@ struct i2c_client *ivtv_i2c_new_ir_legac - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); -- return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list, NULL); -+ return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list); - } - - int ivtv_i2c_register(struct ivtv *itv, unsigned idx) -diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c ---- a/linux/drivers/media/video/v4l2-common.c -+++ b/linux/drivers/media/video/v4l2-common.c -@@ -380,8 +380,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_ - - /* Create the i2c client */ - if (info->addr == 0 && probe_addrs) -- client = i2c_new_probed_device(adapter, info, probe_addrs, -- NULL); -+ client = i2c_new_probed_device(adapter, info, probe_addrs); - else - client = i2c_new_device(adapter, info); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_vm_prev.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_vm_prev.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_vm_prev.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_vm_prev.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -diff --git a/linux/drivers/media/video/videobuf2-memops.c b/linux/drivers/media/video/videobuf2-memops.c -index 053c157..c47f56e 100644 ---- a/linux/drivers/media/video/videobuf2-memops.c -+++ b/linux/drivers/media/video/videobuf2-memops.c -@@ -52,7 +52,6 @@ struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma) - - vma_copy->vm_mm = NULL; - vma_copy->vm_next = NULL; -- vma_copy->vm_prev = NULL; - - return vma_copy; - } diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_work_handler.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_work_handler.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_work_handler.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.35_work_handler.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -diff -r a14b248a9a18 linux/drivers/media/video/ivtv/ivtv-driver.c ---- a/linux/drivers/media/video/ivtv/ivtv-driver.c Tue Oct 26 23:13:59 2010 -0200 -+++ b/linux/drivers/media/video/ivtv/ivtv-driver.c Tue Oct 26 23:16:20 2010 -0200 -@@ -706,8 +706,6 @@ - */ - static int __devinit ivtv_init_struct1(struct ivtv *itv) - { -- struct sched_param param = { .sched_priority = 99 }; -- - itv->base_addr = pci_resource_start(itv->pdev, 0); - itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ - itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ -@@ -719,17 +717,13 @@ - spin_lock_init(&itv->lock); - spin_lock_init(&itv->dma_reg_lock); - -- init_kthread_worker(&itv->irq_worker); -- itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker, -- itv->v4l2_dev.name); -- if (IS_ERR(itv->irq_worker_task)) { -- IVTV_ERR("Could not create ivtv task\n"); -+ itv->irq_work_queues = create_singlethread_workqueue(itv->v4l2_dev.name); -+ if (itv->irq_work_queues == NULL) { -+ IVTV_ERR("Could not create ivtv workqueue\n"); - return -1; - } -- /* must use the FIFO scheduler as it is realtime sensitive */ -- sched_setscheduler(itv->irq_worker_task, SCHED_FIFO, ¶m); - -- init_kthread_work(&itv->irq_work, ivtv_irq_work_handler); -+ INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler); - - /* start counting open_id at 1 */ - itv->open_id = 1; -@@ -1019,7 +1013,7 @@ - /* PCI Device Setup */ - retval = ivtv_setup_pci(itv, pdev, pci_id); - if (retval == -EIO) -- goto free_worker; -+ goto free_workqueue; - if (retval == -ENXIO) - goto free_mem; - -@@ -1231,8 +1225,8 @@ - release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); - if (itv->has_cx23415) - release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); --free_worker: -- kthread_stop(itv->irq_worker_task); -+free_workqueue: -+ destroy_workqueue(itv->irq_work_queues); - err: - if (retval == 0) - retval = -ENODEV; -@@ -1371,9 +1365,9 @@ - ivtv_set_irq_mask(itv, 0xffffffff); - del_timer_sync(&itv->dma_timer); - -- /* Kill irq worker */ -- flush_kthread_worker(&itv->irq_worker); -- kthread_stop(itv->irq_worker_task); -+ /* Stop all Work Queues */ -+ flush_workqueue(itv->irq_work_queues); -+ destroy_workqueue(itv->irq_work_queues); - - ivtv_streams_cleanup(itv, 1); - ivtv_udma_free(itv); -diff -r a14b248a9a18 linux/drivers/media/video/ivtv/ivtv-driver.h ---- a/linux/drivers/media/video/ivtv/ivtv-driver.h Tue Oct 26 23:13:59 2010 -0200 -+++ b/linux/drivers/media/video/ivtv/ivtv-driver.h Tue Oct 26 23:16:20 2010 -0200 -@@ -51,7 +51,7 @@ - #include - #include - #include --#include -+#include - #include - #include - #include -@@ -261,6 +261,7 @@ - #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ - #define IVTV_F_I_INITED 21 /* set after first open */ - #define IVTV_F_I_FAILED 22 /* set if first open failed */ -+#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */ - - /* Event notifications */ - #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ -@@ -667,9 +668,8 @@ - /* Interrupts & DMA */ - u32 irqmask; /* active interrupts */ - u32 irq_rr_idx; /* round-robin stream index */ -- struct kthread_worker irq_worker; /* kthread worker for PIO/YUV/VBI actions */ -- struct task_struct *irq_worker_task; /* task for irq_worker */ -- struct kthread_work irq_work; /* kthread work entry */ -+ struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */ -+ struct work_struct irq_work_queue; /* work entry */ - spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ - int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */ - int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */ -diff -r a14b248a9a18 linux/drivers/media/video/ivtv/ivtv-irq.c ---- a/linux/drivers/media/video/ivtv/ivtv-irq.c Tue Oct 26 23:13:59 2010 -0200 -+++ b/linux/drivers/media/video/ivtv/ivtv-irq.c Tue Oct 26 23:16:20 2010 -0200 -@@ -71,10 +71,19 @@ - write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); - } - --void ivtv_irq_work_handler(struct kthread_work *work) -+void ivtv_irq_work_handler(struct work_struct *work) - { -- struct ivtv *itv = container_of(work, struct ivtv, irq_work); -+ struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue); - -+ DEFINE_WAIT(wait); -+ -+ if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) { -+ struct sched_param param = { .sched_priority = 99 }; -+ -+ /* This thread must use the FIFO scheduler as it -+ is realtime sensitive. */ -+ sched_setscheduler(current, SCHED_FIFO, ¶m); -+ } - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) - ivtv_pio_work_handler(itv); - -@@ -966,7 +975,7 @@ - } - - if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { -- queue_kthread_work(&itv->irq_worker, &itv->irq_work); -+ queue_work(itv->irq_work_queues, &itv->irq_work_queue); - } - - spin_unlock(&itv->dma_reg_lock); -diff -r a14b248a9a18 linux/drivers/media/video/ivtv/ivtv-irq.h ---- a/linux/drivers/media/video/ivtv/ivtv-irq.h Tue Oct 26 23:13:59 2010 -0200 -+++ b/linux/drivers/media/video/ivtv/ivtv-irq.h Tue Oct 26 23:16:20 2010 -0200 -@@ -46,7 +46,7 @@ - - irqreturn_t ivtv_irq_handler(int irq, void *dev_id); - --void ivtv_irq_work_handler(struct kthread_work *work); -+void ivtv_irq_work_handler(struct work_struct *work); - void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); - void ivtv_unfinished_dma(unsigned long arg); - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.36_input_getkeycode.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.36_input_getkeycode.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.36_input_getkeycode.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.36_input_getkeycode.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -diff --git a/linux/drivers/media/rc/rc-main.c b/linux/drivers/media/rc/rc-main.c ---- a/linux/drivers/media/rc/rc-main.c -+++ b/linux/drivers/media/rc/rc-main.c -@@ -318,37 +318,23 @@ - * This routine is used to handle evdev EVIOCSKEY ioctl. - */ - static int ir_setkeycode(struct input_dev *idev, -- const struct input_keymap_entry *ke, -- unsigned int *old_keycode) -+ unsigned int scancode, unsigned int keycode) - { - struct rc_dev *rdev = input_get_drvdata(idev); - struct rc_map *rc_map = &rdev->rc_map; - unsigned int index; -- unsigned int scancode; - int retval = 0; - unsigned long flags; - - spin_lock_irqsave(&rc_map->lock, flags); - -- if (ke->flags & INPUT_KEYMAP_BY_INDEX) { -- index = ke->index; -- if (index >= rc_map->len) { -- retval = -EINVAL; -- goto out; -- } -- } else { -- retval = input_scancode_to_scalar(ke, &scancode); -- if (retval) -- goto out; -- -- index = ir_establish_scancode(rdev, rc_map, scancode, true); -- if (index >= rc_map->len) { -- retval = -ENOMEM; -- goto out; -- } -+ index = ir_establish_scancode(rdev, rc_map, scancode, true); -+ if (index >= rc_map->len) { -+ retval = -ENOMEM; -+ goto out; - } - -- *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode); -+ ir_update_mapping(rdev, rc_map, index, keycode); - - out: - spin_unlock_irqrestore(&rc_map->lock, flags); -@@ -436,48 +422,25 @@ - * This routine is used to handle evdev EVIOCGKEY ioctl. - */ - static int ir_getkeycode(struct input_dev *idev, -- struct input_keymap_entry *ke) -+ unsigned int scancode, unsigned int *keycode) - { - struct rc_dev *rdev = input_get_drvdata(idev); - struct rc_map *rc_map = &rdev->rc_map; -- struct rc_map_table *entry; - unsigned long flags; - unsigned int index; -- unsigned int scancode; - int retval; - - spin_lock_irqsave(&rc_map->lock, flags); - -- if (ke->flags & INPUT_KEYMAP_BY_INDEX) { -- index = ke->index; -- } else { -- retval = input_scancode_to_scalar(ke, &scancode); -- if (retval) -- goto out; -- -- index = ir_lookup_by_scancode(rc_map, scancode); -- } -- -- if (index < rc_map->len) { -- entry = &rc_map->scan[index]; -- -- ke->index = index; -- ke->keycode = entry->keycode; -- ke->len = sizeof(entry->scancode); -- memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode)); -- -- } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) { -- /* -- * We do not really know the valid range of scancodes -- * so let's respond with KEY_RESERVED to anything we -- * do not have mapping for [yet]. -- */ -- ke->index = index; -- ke->keycode = KEY_RESERVED; -- } else { -- retval = -EINVAL; -- goto out; -- } -+ index = ir_lookup_by_scancode(rc_map, scancode); -+ -+ if (index >= rc_map->len) { -+ *keycode = KEY_RESERVED; -+ retval = 0; -+ goto out; -+ } -+ -+ *keycode = rc_map->scan[index].keycode; - - retval = 0; - -@@ -966,8 +929,8 @@ - return NULL; - } - -- dev->input_dev->getkeycode_new = ir_getkeycode; -- dev->input_dev->setkeycode_new = ir_setkeycode; -+ dev->input_dev->getkeycode = ir_getkeycode; -+ dev->input_dev->setkeycode = ir_setkeycode; - input_set_drvdata(dev->input_dev, dev); - - spin_lock_init(&dev->rc_map.lock); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.37_dont_use_alloc_ordered_workqueue.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.37_dont_use_alloc_ordered_workqueue.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2.6.37_dont_use_alloc_ordered_workqueue.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2.6.37_dont_use_alloc_ordered_workqueue.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c -index 869690b..e712607 100644 ---- a/linux/drivers/media/video/cx18/cx18-driver.c -+++ b/linux/drivers/media/video/cx18/cx18-driver.c -@@ -665,7 +665,7 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx) - { - snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", - cx->v4l2_dev.name); -- cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0); -+ cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name); - if (cx->in_work_queue == NULL) { - CX18_ERR("Unable to create incoming mailbox handler thread\n"); - return -ENOMEM; -@@ -673,6 +673,18 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx) - return 0; - } - -+static int __devinit cx18_create_out_workq(struct cx18 *cx) -+{ -+ snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out", -+ cx->v4l2_dev.name); -+ cx->out_work_queue = create_workqueue(cx->out_workq_name); -+ if (cx->out_work_queue == NULL) { -+ CX18_ERR("Unable to create outgoing mailbox handler threads\n"); -+ return -ENOMEM; -+ } -+ return 0; -+} -+ - static void __devinit cx18_init_in_work_orders(struct cx18 *cx) - { - int i; -@@ -699,10 +711,16 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) - mutex_init(&cx->epu2apu_mb_lock); - mutex_init(&cx->epu2cpu_mb_lock); - -- ret = cx18_create_in_workq(cx); -+ ret = cx18_create_out_workq(cx); - if (ret) - return ret; - -+ ret = cx18_create_in_workq(cx); -+ if (ret) { -+ destroy_workqueue(cx->out_work_queue); -+ return ret; -+ } -+ - cx18_init_in_work_orders(cx); - - /* start counting open_id at 1 */ -@@ -1095,6 +1113,7 @@ free_mem: - release_mem_region(cx->base_addr, CX18_MEM_SIZE); - free_workqueues: - destroy_workqueue(cx->in_work_queue); -+ destroy_workqueue(cx->out_work_queue); - err: - if (retval == 0) - retval = -ENODEV; -@@ -1246,6 +1265,7 @@ static void cx18_remove(struct pci_dev *pci_dev) - cx18_halt_firmware(cx); - - destroy_workqueue(cx->in_work_queue); -+ destroy_workqueue(cx->out_work_queue); - - cx18_streams_cleanup(cx, 1); - -diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h -index 26eb910..d050a0a 100644 ---- a/linux/drivers/media/video/cx18/cx18-driver.h -+++ b/linux/drivers/media/video/cx18/cx18-driver.h -@@ -617,6 +617,9 @@ struct cx18 { - struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; - char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ - -+ struct workqueue_struct *out_work_queue; -+ char out_workq_name[12]; /* "cx18-NN-out" */ -+ - /* i2c */ - struct i2c_adapter i2c_adap[2]; - struct i2c_algo_bit_data i2c_algo[2]; -diff --git a/linux/drivers/media/video/cx18/cx18-streams.h b/linux/drivers/media/video/cx18/cx18-streams.h -index 713b0e6..51765eb 100644 ---- a/linux/drivers/media/video/cx18/cx18-streams.h -+++ b/linux/drivers/media/video/cx18/cx18-streams.h -@@ -42,7 +42,8 @@ static inline bool cx18_stream_enabled(struct cx18_stream *s) - /* Related to submission of mdls to firmware */ - static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) - { -- schedule_work(&s->out_work_order); -+ struct cx18 *cx = s->cx; -+ queue_work(cx->out_work_queue, &s->out_work_order); - } - - static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s, diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2-V4L-DVB-faster-DVB-S-lock-for-mantis-cards-using-stb0899-demod.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2-V4L-DVB-faster-DVB-S-lock-for-mantis-cards-using-stb0899-demod.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/patches/v2-V4L-DVB-faster-DVB-S-lock-for-mantis-cards-using-stb0899-demod.patch 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/patches/v2-V4L-DVB-faster-DVB-S-lock-for-mantis-cards-using-stb0899-demod.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -diff --git a/linux/drivers/media/dvb/frontends/stb0899_algo.c b/linux/drivers/media/dvb/frontends/stb0899_algo.c -index 2da55ec..3efde1e 100644 ---- a/linux/drivers/media/dvb/frontends/stb0899_algo.c -+++ b/linux/drivers/media/dvb/frontends/stb0899_algo.c -@@ -206,7 +206,6 @@ static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state) - static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state) - { - struct stb0899_internal *internal = &state->internal; -- struct stb0899_params *params = &state->params; - - short int derot_step, derot_freq = 0, derot_limit, next_loop = 3; - int index = 0; -@@ -216,10 +215,9 @@ static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state) - - /* timing loop computation & symbol rate optimisation */ - derot_limit = (internal->sub_range / 2L) / internal->mclk; -- derot_step = (params->srate / 2L) / internal->mclk; -+ derot_step = internal->derot_step * 4; /* dertot_step = decreasing delta */ - - while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) { -- index++; - derot_freq += index * internal->direction * derot_step; /* next derot zig zag position */ - - if (abs(derot_freq) > derot_limit) -@@ -230,6 +228,7 @@ static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state) - STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); - stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ - } -+ index++; - internal->direction = -internal->direction; /* Change zigzag direction */ - } - -@@ -278,14 +277,18 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state) - { - struct stb0899_internal *internal = &state->internal; - -- short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3; -+ short int derot_freq = 0, last_derot_freq = 0, derot_limit, derot_step, next_loop = 3; - int index = 0; -+ int base_freq; - u8 cfr[2]; - u8 reg; - - internal->status = NOCARRIER; - derot_limit = (internal->sub_range / 2L) / internal->mclk; - derot_freq = internal->derot_freq; -+ derot_step = internal->derot_step * 2; -+ last_derot_freq = internal->derot_freq; -+ base_freq = internal->derot_freq; - - reg = stb0899_read_reg(state, STB0899_CFD); - STB0899_SETFIELD_VAL(CFD_ON, reg, 1); -@@ -294,11 +297,10 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state) - do { - dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk); - if (stb0899_check_carrier(state) == NOCARRIER) { -- index++; - last_derot_freq = derot_freq; -- derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */ -+ derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */ - -- if(abs(derot_freq) > derot_limit) -+ if (derot_freq > base_freq + derot_limit || derot_freq < base_freq - derot_limit) - next_loop--; - - if (next_loop) { -@@ -310,9 +312,10 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state) - STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); - stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ - } -+ index++; -+ internal->direction = -internal->direction; /* Change zigzag direction */ - } - -- internal->direction = -internal->direction; /* Change zigzag direction */ - } while ((internal->status != CARRIEROK) && next_loop); - - if (internal->status == CARRIEROK) { -@@ -338,6 +341,7 @@ static enum stb0899_status stb0899_check_data(struct stb0899_state *state) - int lock = 0, index = 0, dataTime = 500, loop; - u8 reg; - -+ msleep(1); - internal->status = NODATA; - - /* RESET FEC */ -@@ -348,6 +352,7 @@ static enum stb0899_status stb0899_check_data(struct stb0899_state *state) - reg = stb0899_read_reg(state, STB0899_TSTRES); - STB0899_SETFIELD_VAL(FRESACS, reg, 0); - stb0899_write_reg(state, STB0899_TSTRES, reg); -+ msleep(1); - - if (params->srate <= 2000000) - dataTime = 2000; -@@ -360,6 +365,7 @@ static enum stb0899_status stb0899_check_data(struct stb0899_state *state) - - stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop */ - while (1) { -+ msleep(1); // Alex: added 1 mSec - /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP */ - reg = stb0899_read_reg(state, STB0899_VSTATUS); - lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg); -@@ -387,20 +393,21 @@ static enum stb0899_status stb0899_search_data(struct stb0899_state *state) - short int derot_freq, derot_step, derot_limit, next_loop = 3; - u8 cfr[2]; - u8 reg; -- int index = 1; -+ int index = 0; -+ int base_freq; - - struct stb0899_internal *internal = &state->internal; -- struct stb0899_params *params = &state->params; - -- derot_step = (params->srate / 4L) / internal->mclk; -+ derot_step = internal->derot_step; - derot_limit = (internal->sub_range / 2L) / internal->mclk; - derot_freq = internal->derot_freq; -+ base_freq = internal->derot_freq; - - do { - if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) { - - derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */ -- if (abs(derot_freq) > derot_limit) -+ if (derot_freq > base_freq + derot_limit || derot_freq < base_freq - derot_limit) - next_loop--; - - if (next_loop) { -@@ -414,9 +421,9 @@ static enum stb0899_status stb0899_search_data(struct stb0899_state *state) - stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ - - stb0899_check_carrier(state); -- index++; - } - } -+ index++; - internal->direction = -internal->direction; /* change zig zag direction */ - } while ((internal->status != DATAOK) && next_loop); - --- -1.7.1 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/README v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/README --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/README 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -This is an experimental build system for media drivers. - -Usage: - -cd linux -make tar DIR= -make untar - -After that, it will work like the old -hg build system. - -Notes: - -1) There's not much compat stuff here. So, it will likely not work with - legacy kernels. It will probably be fine to use it with the latest stable - kernel. - -2) For now, this is just an experience. I don't intend to maintain any - out-of-tree building system, due to my lack of time. If this interests - someone, feel free to candidate to maintain it. - -3) It shouldn't be hard to support legacy kernels. All that it is needed is - to have patches adding backports that don't fit at compat.h, and let the - building system to apply them, depending on the kernel version. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/README.patches v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/README.patches --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/README.patches 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/README.patches 1970-01-01 00:00:00.000000000 +0000 @@ -1,1273 +0,0 @@ -Mauro Carvalho Chehab - Updated on 2010 January 30 - -This file describes the general procedures used by the LinuxTV team (*) -and by the v4l-dvb community. - -(*) This is just an aka for the main developers involved in V4L/DVB -drivers. They are a volunteer and unremunerated group of people that -have the common interest of providing a good support on Linux for -receiving and capturing video streams from webcams, analog TV, digital -TV and radio broadcast AM/FM. - - CONTENTS - ======== - - Part I - Patch management on LinuxTV - 1. A brief introduction about patch management - 2. Git and Mercurial trees hosted on LinuxTV site - 3. Git and Mercurial trees' relationships with v4l/dvb development - 4. Patch submission process overall - 5. Other Git trees used for v4l/dvb development - 6. Other Mercurial trees used for v4l/dvb development - - Part II - Git trees - 1. Kernel development procedures at the kernel upstream - 1.1 Subsystem procedures for merging patches upstream - 1.2 A practical example - 1.3 Patches for stable - 2. Kernel development procedures for V4L/DVB - 2.1 Fixes and linux-next patches - 2.2 How to solve those issues? - 3. How to submit a -git pull request - 3.1 Tags that a patch receive after its submission - 4. Patches submitted via email - 4.1 Example - - Part III - Best Practices - 1. Community best practices - 2. Mercurial specific procedures - 3. Knowing about newer patches committed at the development repositories - 4. Patch submission from the community - 5. Identifying regressions with Mercurial - 6. Identifying regressions with Git - 7. Creating a newer driver - 7.1. Simple drivers - 7.2. Bigger drivers - -=================================== -PART I. PATCH MANAGEMENT ON LINUXTV -=================================== - - -1. A brief introduction about patch management - =========================================== - -V4L/DVB development is based on modern SCM (Source Code Management) systems -that fits better into kernel development model. - -At the beginning, the usage CVS for of a SCM (Source Code Management) were -choosen on V4L/DVB. Both of the original V4L and DVB trees were developed with -the help of cvs. On that time, upstream Linux kernel used to have another tree -(BitKeeper). - -In 2005, Upstream Kernel development model changed to use git (a SCM tool -developed by Linus Torvalds, the inventor and main maintainer of the Linux -Kernel). - -Also in 2005, both V4L and DVB trees got merged into one cvs repository, and -the community discussed about what would be the better SCM solution. It were -mainly availed the usage of svn, hg and git. On that time, both hg and git were -new technologies, based on the concept of a distributed SCM, where there's no -need to go to the server every time a command is used at the SCM. This speeds -up the development time, and allows descentralized development. - -Mercurial used to be stable and had more projects using, while git were giving -its first steps, being used almost only by the Linux Kernel, and several distros -didn't use to package it. Git objects were stored uncompressed, generating very -large trees. Also, -git tools were complex to use, and some "porcelain" packages -were needed, in order to be used by a normal user. - -So, the decision was made to use Mercurial. However, as time goes by, git got -much more eyes than any other SCM, having all their weakness solved, and being -developed really fast. Also, it got adopted by several other projects, due to -its capability and its number of features. - -Technically speaking, -git is currently the most advanced distributed -open-source SCM application available today. - -Yet, Mercurial has been doing a very good job maintaining the V4L/DVB trees, -and, except for a few points, it does the job. - -However, the entire Linux Kernel development happens around -git. Even the ones -that were adopting other tools (like -alsa, that used to have also Mercurial -repositories) migrated to -git. - -Despite all technical advantages, the rationale for the migration to git is -quite simple: converting patches between different repositories and SCM tools -cause development and merge delays, may cause patch mangling and eats lot of -the time for people that are part of the process. - -Also, every time a patch needs to touch on files outside the incomplete tree -used at the subsystem, an workaround need to be done, in order to avoid troubles -and to be able to send the patch upstream. - -So, it is simpler to just use -git. - -2. Git and Mercurial trees hosted on LinuxTV site - ============================================== - -A list of current available Mercurial repositories used on LinuxTV is available at: - http://linuxtv.org/hg/ - - -A list of current available Git repositories used on LinuxTV is available -at: - http://git.linuxtv.org - -3. Git and Mercurial trees' relationships with v4l/dvb development - =============================================================== - -The main subsystem kernel trees are hosted at http://git.kernel.org. Each tree -is owned by a maintainer. In the case of LinuxTV, the subsystem maintainer is -Mauro Carvalho Chehab, who owns all sybsystem trees. - -The main kernel tree is owned by Linus Torvalds, being located at: - http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git - -The subsystem maintainer's master tree is located at: - http://git.kernel.org/?p=linux/kernel/git/mchehab/linux-2.6.git - -The subsystem maintainer's tree with development patches that aren't ready yet -for upstream is handled at: - http://git.linuxtv.org/git/v4l-dvb.git - -The main function of this tree is to merge patches received via email and from -other Git and Mercurial repositories and to test the entire subsystem with the -finished patches. - -The subsystem maintainer's tree with development patches that will be sent soon -to upstream is located at: - http://git.linuxtv.org/git/fixes.git - -There is also an experimental tree, that contains all experimental patches -from all subsystem trees, called linux-next. Its purpose is to check in -advance if patches from different trees would conflict. The main tree for -linux-next is owned by Stephen Rothwell and it is located at: - http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git - -Warning: linux-next is meant to be used by developers. As it may contain broken -+++++++ patches on several subsystems, it may cause damage if used on - production systems. - -The subsystem maintainer's linux-next tree is located at: - http://www.kernel.org/git/?p=linux/kernel/git/mchehab/linux-next.git - -In general, it contains a replica of the contents of the development tree. - -Michael Krufky maintains a backport tree, containing a subset of the -patches from the subsystem tree that are meant to be sent to kernel --stable team, at: - http://git.kernel.org/http://git.kernel.org/?p=linux/kernel/git/mkrufky/ -v4l-dvb-2.6.x.y.git - -In order to allow testing the LinuxTV drivers with older kernels, a backport -tree is maintained by Douglas Schilling Landgraf . - -The backport tree is at: - http://linuxtv.org/hg/v4l-dvb - - Basically, all patches added at -git -are manually imported on this tree, that also contains some logic to allow -compilation of the core system since kernel 2.6.16. It should be noticed, -however, that some drivers may require newer kernels in order to compile. - -Also, those backports are developped as best efforts, and are mainly against -upstream stable kernels, so they may not compile with distro-patched kernels, -nor they are meant to offer production level of support. So, if you need to -run any prodution machine, you should really be using a Linux distribution -that offers support for the drivers you need and has a Quality Assurance -process when doing backports. You were warned. - -Users are welcome to use, test and report any issues via the mailing -lists or via the Kernel Bug Tracker, available at: - http://bugzilla.kernel.org - -4. Patch submission process overall - ================================ - -When a developer believes that there are done to be merged, he sends a request -for the patches to get merged at the v4l-dvb.git tree, at the linux-media at -vger.kernel.org (the main mailing list for LinuxTV). - -The patches are analyzed and, if they look ok, they got merged into v4l-dvb.git. - -Currently, there are thre ways to submit a patch: - as an email, with the subject [PATCH]; - as a hg pull request, with the subject [PULL]; - as a git pull request, with the subject [GIT FIXES ...] or [GIT UPDATES ...] - -If the patch is developed against the Mercurial repositories, it is converted -to the format git expects and have any backport code removed. - -No matter how the patch is received, after being checked and accepted by the maintainer, -the patch will receive the maintainer's Certificate of Origin (Signed-off-by, -as explained later within this document), and will be added at: - - http://git.linuxtv.org/git/v4l-dvb.git - -Later, it will be backported to the -hg tree. - -The community also reviews the patches and may send emails informing that the -patch has problems or were tested/acked. When those reviews happen after the -patch merge at the tree, the patch is modified before its upstream submission. - -Also, the maintainer may need to modify the patch at his trees, in order to -fix conflicts that may happen with the patch. - -The subsystem maintainer, when preparing the kernel patches to be sent -to mainstream, send the patches first to linux-next tree, and waits for some -to receive contributions from other upstream developers. If, during that period, -he notices a problem, he may correct the patch at his upstream submission tree. - -5. Other Git trees used for v4l/dvb development - ============================================ - -V4L/DVB Git trees are hosted at - git://linuxtv.org. - -There are a number of trees there each owned by a developer of the LinuxTV team. - -The submission emails are generated via the usage of git request-pull, as -described on part II. - -Git is a distributed SCM, which means every developer gets his -own full copy of the repository (including the complete revision -history), and can work and commit locally without network connection. -The resulting changesets can then be exchanged between repositories and -finally merged into a common repository on linuxtv.org. - -The Git trees used on LinuxTV have the entire Linux Kernel tree and history -since kernel 2.6.12. So, it generally takes some time to update it at the -first time. - -There are several good documents on how to use -git, including: - http://git.or.cz/ - http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html - http://www.kernel.org/pub/software/scm/git/docs - -6. Other Mercurial trees used for v4l/dvb development - ================================================== - -V4L/DVB Mercurial trees are hosted at - http://linuxtv.org/hg. - -There are a number of trees there each owned by a developer of the LinuxTV team. - -A script called v4l/scripts/hg-pull-req.pl is included that will generate this -request, providing a list of patches that will be pulled, links to each -patch, and a diffstat of the all patches. It will work best if Hg has -been configured with the correct username (also used by the commit -message generator) and push path. The script is designed to be easy to -modify to produce text for a given contributor's style. - -It is good practice that each developer will have at least one tree -called 'v4l-dvb', which keeps their patches, and periodically update -this tree with the master tree's patches. - -Mercurial is a distributed SCM, which means every developer gets his -own full copy of the repository (including the complete revision -history), and can work and commit locally without network connection. -The resulting changesets can then be exchanged between repositories and -finally merged into a common repository on linuxtv.org. - -There are some tutorials, FAQs and other valuable information at - http://selenic.com/mercurial/ - - -================== -PART II. GIT TREES -================== - - -1. Kernel development procedures at the kernel upstream - ==================================================== - -It is important that people understand how upstream development works. - -Kernel development has 2 phases: - -a) a merge window typically with 2 weeks (although Linus is gave some - indications that he may reduce it on 2.6.34), starting with the release of - a new kernel version; - -b) the -rc period, where the Kernel is tested and receive fixes. - -The length of the -rc period depends on the number and relevance of the fixes. -Considering the recent history, it ranges from -rc6 to -rc8, where each -rc -takes one week. - -Those are the latest -rc kernels since 2.6.12: - kernel latest -rc version - 2.6.12 rc6 - 2.6.13 rc7 - 2.6.14 rc5 - 2.6.15 rc7 - 2.6.16 rc6 - 2.6.17 rc6 - 2.6.18 rc7 - 2.6.19 rc6 - 2.6.20 rc7 - 2.6.21 rc7 - 2.6.22 rc7 - 2.6.23 rc9 - 2.6.24 rc8 - 2.6.25 rc9 - 2.6.26 rc9 - 2.6.27 rc9 - 2.6.28 rc9 - 2.6.29 rc8 - 2.6.30 rc8 - 2.6.31 rc9 - 2.6.32 rc8 - -In general, the announcement of a new -rc kernel gives some hints when that --rc kernel may be the last one. - -1.1. Subsystem procedures for merging patches upstream - ================================================= - -The required procedure on subsystem trees is that: - -a) During -rc period (e.g. latest main kernel available is 2.6.x, the latest - -rc kernel is 2.6.[x+1]-rc): - - * fix patches for the -rc kernel (2.6.[x+1]) should be sent upstream, - being a good idea to send them for some time at linux-next tree, allowing - other people to test it, and check for potential conflicts with the other - arch's; - * patches for 2.6.[x+2] should be sent to linux-next. - -b) the release of 2.6.[x+1] kernel: - - * closes the -rc period and starts the merge window. - -c) During the merge window: - - * the patch that were added on linux-next during the -rc period for - 2.6.[x+2] should be sent upstream; - * new non-fix patches should be hold until the next -rc period starts, so, - they'll be added on 2.6.[x+3]; - * fix patches for 2.6.[x+2] should go to linux-next, wait for a few days - and then send upstream. - -d) the release of 2.6.[x+2]-rc1 kernel: - - * the merge window has closed. No new features are allowed. - * the patches with new features that arrived during the merge window - will be moved to linux-next - -1.2. A practical example - =================== - -Considering that, at the time this document were written, the last main release -is 2.6.32, and the latest -rc release is 2.6.33-rc5, this means that: - - * Stable patches, after adding upstream, are being received for 2.6.32 - kernel series; - * Bug fixes are being received for kernel 2.6.33; - * New feature patches are being received for kernel 2.6.34. - -After the release of kernel 2.6.33, starts the period for receiving patches -for 2.6.35. - -In other words, the features being developed are always meant to be included on -the next 2 kernels. - -In the specific case of new drivers that don't touch on existing features, it -could be possible to send it during the -rc period, but it is safer to assume -that those drivers should follow the above procedure, as a later submission may -be nacked. - -1.3. Patches for stable - ==================== - -Sometimes, a fix patch corrects a problem that happens also on stable kernels -(e. g. on kernel 2.6.x or even 2.6.y, where y < x). In this case, the patch -should be sent to stable@kernel.org, in order to be added on stable kernels. - -In the case of git-submitted patches with fixes, that also need to be send to -stable, all the developer needs to do is to add, a the patch description: - - CC: stable.kernel.org - -At the moment the patch reaches upstream, a copy of the patch will be -automatically be sent to the stable maintainer and will be considered for -inclusion on the next stable kernel (2.6.x.y). - -2. Kernel development procedures for V4L/DVB - ========================================= - -The upsteam procedures should be followed by every kernel subsystem. The -subsystems have their own specific procedures detailing how the development -patches are handled before arriving upstream. In the case of v4l/dvb, those -are the used procedures. - -2.1. Fixes and linux-next patches - ============================ - -One of the big problems of our model used in the past by the subsystem, based on -one Mercurial tree, is that there were just one tree/branch for everything. This -makes hard to send some fix patches for 2.6.[x+1], as they may have conflicts -with the patches for 2.6.[x+2]. So, when the conflict is simple to solve, the -patch is sent as fixes. Otherwise, the patch generally needed to hold to the -next cycle. The fix patches used to get a special tag, added by the developer -("Priority: high", in the body of the description), to give a hint to the -subsystem maintainer that the patch should be sent upstream. - -Unfortunately, sometimes people mark the driver with the wrong tag. For example, -a patch got merged on Jan, 22 2010 that marked with "high". However, that patch -didn't apply at the fixes tree, because it fix a regression introduced by a -driver that weren't merged upstream yet. - -2.2. How to solve those issues? - ========================== - -Well, basically, the subsystem should work with more than one tree (or branch), -on upstream submission: - - * a tree(branch) with the fix patches; - * a tree(branch) with the new feature patches. - -So, the subsystem uses two development -git trees: - - * http://linuxtv.org/git//v4l-dvb.git - for patches that will be sent to the - [x+2] kernel (and merged at upstream linux-next tree) - - * http://linuxtv.org/git//fixes.git - for bug patches that will be sent to - the [x+1] kernel (also, patches that need to go to both [x+1] and [x]) - -While the patches via -hg, due to the merge conflicts its mentioned, the better -is that, even those developers that prefer to develop patches use the old way, -to send the fix patches via -git. This way, if is there a conflict, he is the -one that can better solve it. Also, it avoids the risk of a patch being wrongly -tagged. - -Also, after having a patch added on one of the above trees, it can't simply -remove it, as others will be cloning that tree. So, the only option would be to -send a revert patch, causing the patch history to be dirty and could be -resulting on some troubles when submitting upstream. I've seen some nacks on -receiving patches upstream from dirty git trees. So, we should really avoid -this. - -3. how to submit a -git pull request - ================================= - -As the same git tree may have more than one branch, and we'll have 2 -git trees -for upstream, it is required that people specify what should be done. The -internal maintainer's workflow is based on different mail queues for each type -of requesting received. - -There are some scripts to automate the process, so it is important that everyone -that sends -git pull do it at the same way. - -So, a pull request to be send with the following email tags: - - From: - Subject: [GIT FIXES FOR 2.6.33] Fixes for driver cx88 - To: linux-media@vger.kernel.org - - From: - Subject: [GIT PATCHES FOR 2.6.34] Updates for the driver saa7134 - To: linux-media@vger.kernel.org - -The from line may later be used by the git mailbomb script to send you a copy -when the patch were committed, so it should be your real email. - -The indication between [] on the subject will be handled by the mailer scripts -to put the request at the right queue. So, if tagged wrong, it may not be -committed. - -Don't send a copy of the pull to the maintainer addresses. The pull will be -filtering based on the subject and on the mailing list. If you send a c/c to the -maintainer, it will be simply discarded. - -NEVER send a copy of any pull request to a subscribers-only mailing list. -Everyone is free to answer to the email, reviewing your patches. Don't penalty -people that wants to contribute with you with SPAM bouncing emails, produced by -subscribers only lists. - -When a patch touches on other subsystem codes, please copy the other subsystem -maintainers. This is important for patches that touches on arch files, and also -for -alsa non-trivial patches. - -The email should be generated with the usage of git request-pull: - - git request-pull $ORIGIN $URL - -where $ORIGIN is the commit hash of the tree before your patches, and $URL is -the URL for your repository. - -For example, for the patches merged directly from -hg at the -git trees on Jan, -22 2010, the above commands produced: - - The following changes since commit 2f52713ab3cb9af2eb0f9354dba1421d1497f3e7: - Abylay Ospan (1): - V4L/DVB: 22-kHz set_tone fix for NetUP Dual DVB-S2-CI card. 22kHz logic controlled by demod - - are available in the git repository at: - - git://linuxtv.org/v4l-dvb.git master - - Andy Walls (4): - V4L/DVB: cx25840, v4l2-subdev, ivtv, pvrusb2: Fix ivtv/cx25840 tinny audio - V4L/DVB: ivtv: Adjust msleep() delays used to prevent tinny audio and PCI bus hang - V4L/DVB: cx18-alsa: Initial non-working cx18-alsa files - V4L/DVB: cx18-alsa: Add non-working cx18-alsa-pcm.[ch] files to avoid data loss - - Devin Heitmueller (20): - V4L/DVB: xc3028: fix regression in firmware loading time - V4L/DVB: cx18: rename cx18-alsa.c - V4L/DVB: cx18: make it so cx18-alsa-main.c compiles - V4L/DVB: cx18: export a couple of symbols so they can be shared with cx18-alsa - V4L/DVB: cx18: overhaul ALSA PCM device handling so it works - V4L/DVB: cx18: add cx18-alsa module to Makefile - V4L/DVB: cx18: export more symbols required by cx18-alsa - V4L/DVB: cx18-alsa: remove unneeded debug line - V4L/DVB: cx18: rework cx18-alsa module loading to support automatic loading - V4L/DVB: cx18: cleanup cx18-alsa debug logging - V4L/DVB: cx18-alsa: name alsa device after the actual card - V4L/DVB: cx18-alsa: remove a couple of warnings - V4L/DVB: cx18-alsa: fix memory leak in error condition - V4L/DVB: cx18-alsa: fix codingstyle issue - V4L/DVB: cx18-alsa: codingstyle fixes - V4L/DVB: cx18: codingstyle fixes - V4L/DVB: cx18-alsa: codingstyle cleanup - V4L/DVB: cx18-alsa: codingstyle cleanup - V4L/DVB: cx18: address possible passing of NULL to snd_card_free - V4L/DVB: cx18-alsa: Fix the rates definition and move some buffer freeing code. - - Ian Armstrong (1): - V4L/DVB: ivtv: Fix race condition for queued udma transfers - - Igor M. Liplianin (4): - V4L/DVB: Add Support for DVBWorld DVB-S2 PCI 2004D card - V4L/DVB: dm1105: connect splitted else-if statements - V4L/DVB: dm1105: use dm1105_dev & dev instead of dm1105dvb - V4L/DVB: dm1105: use macro for read/write registers - - JD Louw (1): - V4L/DVB: Compro S350 GPIO change - - drivers/media/common/tuners/tuner-xc2028.c | 11 +- - drivers/media/dvb/dm1105/Kconfig | 1 + - drivers/media/dvb/dm1105/dm1105.c | 501 ++++++++++++++------------- - drivers/media/video/cx18/Kconfig | 11 + - drivers/media/video/cx18/Makefile | 2 + - drivers/media/video/cx18/cx18-alsa-main.c | 293 ++++++++++++++++ - drivers/media/video/cx18/cx18-alsa-mixer.c | 191 ++++++++++ - drivers/media/video/cx18/cx18-alsa-mixer.h | 23 ++ - drivers/media/video/cx18/cx18-alsa-pcm.c | 353 +++++++++++++++++++ - drivers/media/video/cx18/cx18-alsa-pcm.h | 27 ++ - drivers/media/video/cx18/cx18-alsa.h | 59 ++++ - drivers/media/video/cx18/cx18-driver.c | 40 ++- - drivers/media/video/cx18/cx18-driver.h | 10 + - drivers/media/video/cx18/cx18-fileops.c | 6 +- - drivers/media/video/cx18/cx18-fileops.h | 3 + - drivers/media/video/cx18/cx18-mailbox.c | 46 +++- - drivers/media/video/cx18/cx18-streams.c | 2 + - drivers/media/video/cx25840/cx25840-core.c | 48 ++- - drivers/media/video/ivtv/ivtv-irq.c | 5 +- - drivers/media/video/ivtv/ivtv-streams.c | 6 +- - drivers/media/video/ivtv/ivtv-udma.c | 1 + - drivers/media/video/pvrusb2/pvrusb2-hdw.c | 1 + - drivers/media/video/saa7134/saa7134-cards.c | 4 +- - include/media/v4l2-subdev.h | 1 + - 24 files changed, 1380 insertions(+), 265 deletions(-) - create mode 100644 drivers/media/video/cx18/cx18-alsa-main.c - create mode 100644 drivers/media/video/cx18/cx18-alsa-mixer.c - create mode 100644 drivers/media/video/cx18/cx18-alsa-mixer.h - create mode 100644 drivers/media/video/cx18/cx18-alsa-pcm.c - create mode 100644 drivers/media/video/cx18/cx18-alsa-pcm.h - create mode 100644 drivers/media/video/cx18/cx18-alsa.h - -This helps to identify what's expected to be found at the -git tree and to -double check if the merge happened fine. - -3.1. Tags that a patch receive after its submission - ============================================== - -This is probably the most complex issue to solve. - -Signed-off-by/Acked-by/Tested-by/Nacked-by tags may be received after a patch or -a -git submission. This can happen even while the patch is being tested at -linux-next, from people reporting problems on the existing patches, or reporting -that a patch worked fine. - -Also, the driver maintainer and the subsystem maintainer that is committing -those patches should sign each one, to indicate that he reviewed and has -accepted the patch. - -Currently, if a new tag is added to a committed patch, its hash will change. -There were some discussions at Linux Kernel Mailing List about allowing adding -new tags on -git without changing the hash, but I think this weren't implemented -(yet?). - -The same problem occurs with -hg, but, as -hg doesn't support multiple branches -(well, it has a "branch" command, but the concept of branch there is different), -it was opted that the -hg trees won't have all the needed SOBs. Instead, those -would be added only at the submission tree. - -With -git, a better procedure can be used: - -The developer may have two separate branches on his tree. For example, let's -assume that the developer has the following branches on his tree: - - * media-master (associated with "linuxtv" remote) - * fixes - * devel - -His development happens on devel branch. When the patches are ready to -submission will be copied into a new for_submission branch: git branch -for_submission devel - -And a pull request from the branch "for_submission" will be sent. - -Eventually, he'll write new patches on his devel branch. - -After merged, the developer updates the linuxtv remote and drops the -for_submission branch. This way, "media-master" will contain his patches that -got a new hash, due to the maintainer's SOB. However, he has some new patches on -his devel, that applies over the old hashes. - -Fortunately, git has a special command to automatically remove the old objects: -git rebase. - -All the developer needs to do is to run the commands bellow: - git remote update # to update his remotes, including "linuxtv" - git checkout devel # move to devel branch - git pull . media-master # to make a recursive merge from v4l/dvb upstream - git rebase media-master # to remove the legacy hashes - -After this, his development branch will contain only upstream patches + the new -ones he added after sending the patches for upstream submission. - -4. Patches submitted via email - =========================== - -All valid patches submitted via email to linux-media at vger.kernel.org are -automatically stored at http://patchwork.kernel.org/project/linux-media/list. A -patch, to be valid, should be in diff unified format. If you're using a -git -tree, the simplest way to generate unified diff patches is to run: - - git diff - -If you're writing several patches, the better is to create a tag or a branch for -the changes you're working. After that, you can use - - git format-patch - -to create the patches for email submission. - -4.1. Example - ======= - -Suppose that the -git tree were created with: - - git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git v4l-dvb - cd v4l-dvb - git remote add linuxtv git://linuxtv.org/v4l-dvb.git - git remote update - git checkout -b media-master linuxtv/master - - -Before start working, you need to create your work branch: - - git branch work media-master - -And move the working copy to the "work" branch: - - git checkout work - -Some changes were done at the driver and saved by commit: - - git commit -as - -When the patches are ready for submission via email, all that is needed is to -run: - - git format-patch work - -The command will create a series of emails bodies, one file per email. - -Just send the email with the patch inlined for it to ge caught by patchwork. - - BE CAREFUL: several emailers including Thunderdird breaks long lines, causing - patch corruption. - In the specific case of Thunderbird, an extension is needed to send the - patches, called Asalted Patches: - https://hg.mozilla.org/users/clarkbw_gnome.org/asalted-patches/ - - -========================= -Part III - BEST PRACTICES -========================= - - -1. Community best practices - ======================== - -From accumulated experience, there are some basic rules that should -be followed by the community: - -a) Every developer should follow the "rules of thumb" of kernel development - stated at Linux source code, especially those stated at kernel, - under: - Documentation/HOWTO - Documentation/SubmittingPatches - Documentation/SubmittingDrivers - Documentation/SubmitChecklist - Documentation/CodingStyle - -b) All commits at the trees should have a consistent message, describing the - patch. - - When a patch is generated against the git tree, the better is to commit it - with: - git commit -as - - This will automatically add all existing patches that got modified and add - your Certificate of Origin (Signed-off-by). - - It will open an editor for you to provide a description of the patch. - The first line is a short summary describing why the patch is needed, and - the following lines describe what and how the patch does that. - - If you've added new files, don't forget to add them before the commit, with: - git add - - Before committing a patch, you need to check it with checkpatch.pl tool. This - is done by running: - git diff | ./script/checkpatch.pl - - -c) All patches are requested to have their coding style validated by using - ./script/checkpatch.pl. - - On Git, the script checks not only the patch against coding style, but - also checks for the usage of functions that are marked to be removed - from the kernel ABI. - -d) All patches shall have a Developer's Certificate of Origin - version 1.1 in the commit log or the email description, signed by the - patch authors, as postulated in the Linux kernel source at: - - Documentation/SubmittingPatches - - This is done by adding Signed-off-by: fields to the commit message. - - It is not acceptable to use fake signatures, e.g.: - - Signed-off-by: Fake me - - The email must be a valid one. - The author that is submitting the email should be at the button of - the author's signed-off-by (SOB) block. Other SOBs or Acked-by: will be - added at the bottom, marking that somebody else reviewed the patch. - - Each person who is in the kernel patch submission chain (driver author - and/or driver maintainer, subsystem/core maintainers, etc) will - review each patch. If they agree, the patch will be added to their - trees and signed. Otherwise, they may comment on the patch, asking - for some review. - -e) Although not documented at kernel's Documentation/, a common kernel - practice is to use Acked-by: and Tested-by: tags. - - An Acked-by: tag usually means that the acked person didn't write the - patch, nor is in the chain responsible for sending the patch to - kernel, but reviewed the patch and agreed that it was good. - - A Tested-by: tag is a stronger variation of Acked-by. It means that the - person not only reviewed the patch, but also successfully tested it. - - The better is that the patch author submitting his patches via git or hg - to add any acked-by/tested-by tags he received. When a patch is sent via - email, Patchwork tool will automatically include any such tags it receives - in reply together with the patch. - - It is also common to receive acks after having a patch inserted at the - maintainer's trees. In this case, the ack will be added only at -git tree - used to send patches upstream. - -f) Another kernel's practice that is agreed to be good is that a - patchset should be reviewed/tested by other developers. So, a new - tag should be used by testers/reviewers. So, reviewers are welcome. - After reviewing a patchset, please send an e-mail indicating that, if - possible, with some additional data about the testing, with the tag: - Reviewed-by: My Name - This is particularly important for Kernel to userspace ABI changes. - -g) If the patch also affects other parts of kernel (like ALSA - or i2c), it is required that, when submitting upstream, the patch - also goes to the maintainers of that subsystem. To do this, the - developer shall copy the interested parties. - - When submitting a patch via e-mail, it is better to copy all interested - parties directly, by adding them as cc's to the email itself. - - Please note that those changes generally require ack from the - other subsystem maintainers. So, the best practice is to first ask - for their acks, then commit to the development tree or send the - patch via email with their Acked-by: already included. - - NOTE: at Mercurial tree, it used to be possible to use the cc: meta tag to - warn other users/mailing lists about a patch submission. However, this only - works when a patch is merged at the backport tree. So, it's usage is - considered obsolete nowadays. - -h) If the patch modifies the V4L or DVB API's (for example, modifying - include/linux/videodev2.h) file, then it must verify be verified that the - V4L2 specification document still builds. Of course, any changes you make - to the public V4L2 API must be documented anyway. - - Currently, this can be done only with the Mercurial trees, by running: - make spec - - Patches are welcome to migrate this functionality to upstream kernel DocBook - makefile rules. - -i) By submitting a patch to the subsystem maintainer, either via email - or via pull request, the patch author(s) are agreeing that the - submitted code will be added on Kernel, and that the submitted code - are being released as GPLv2. The author may grant additional licenses - to the submitted code (for example, using dual GPL/BSD) or GPLv2 or - later. If no specific clause are added, the added code will be - assumed as GPLv2 only. - -j) "Commit earlier and commit often". This is a common used rule at - Kernel. This means that a sooner submission of a patch will mean that - a review can happen sooner, and help the develop to address the - comments. This helps to reduce the life-cycle for having a changeset - committed at kernel at the proper time. It also means that the one - changeset should ideally address just one issue. So, mixing different - things at the same patch should be avoided. - -k) Sometimes, the maintainer may need to slightly modify patches you receive - in order to merge them, because the code is not exactly the same in your - tree and the submitters'. In order to save time, it may do the changes and - add a line before his SOB, as stated on Documentation/SubmittingPatches, - describing what he did to merge it. Something like: - - Signed-off-by: Random J Developer - [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h] - Signed-off-by: Lucky K Maintainer - -2. Mercurial specific procedures - ============================= - -a) With the -hg trees, some scripts are used to generate the patch. This is - done by running: - - make commit - - This will run some scripts that check changed files, correct - bad whitespace and prepare the last Signed-off-by: field, as - described below. A good comment will have a brief - description at the first line, up to 68 characters wide, a blank - line, the patch author's name on the third line, a blank line, and - then a brief description, with no more than 80 chars per line, e. g.: - - This patch does nothing - - From: nowhere - - This is just a sample commit comment, just for reference purposes. - - This "patch" does nothing. - - Priority: normal - - Signed-off-by: nowhere - - All lines starting with # and all lines starting with HG: will be - removed from the Mercurial commit log. - - *WARNING* Be careful not to leave the first line blank, otherwise hg - will leave subject blank. - - From: line shouldn't be omitted, since it will be used for the - patch author when converting to -git. - - Priority: meta-tag will be used as a hint to the subsystem maintainer, to - help him to identify if the patch is an improvement or board addition - ("normal"), that will follow the normal lifecycle of a patch (e.g. will be - sent upstream on the next merge tree), if the patch is a bug fix tree for a - while without merging upstream ("low"). - Valid values for "Priority:" are "low", "normal" and "high". - -b)For "make commit" to work properly, the HGUSER shell environment var should - be defined (replacing the names at the right): - - HGUSER="My Name " - - If HGUSER is not set, then, if present, the username defined in the - user's ~/.hgrc file will be used. Use of the .hgrc file is preferred - over the HGUSER variable according to the hg man page. - - This name will be used for both the user metadata in the Hg commit - log and the initial values of the "From:" and "Signed-off-by:" lines - in the pre-made commit message. - - It is also possible to use a different login name at the site - hosting the repository, by using: - - CHANGE_LOG_LOGIN=my_log_name - - With this, "make push" will use my_log_name, instead of the name for - the current Unix user. - - Don't forget to export the vars at shell, with something like: - - export CHANGE_LOG_LOGIN HGUSER - - It is strongly recommended to have those lines in .bashrc or .profile. - -b) the CodingStyle compliance check on Mercurial trees are done when - "make check" is called. This happens also when "make commit" is done. - - There's a copy of the kernel tool at the mercurial repository. However, - this copy may be outdated. So, by default, it will try to use the newest - version of the script, between the one found at the kernel tree and - its own copy. - - It is always a good idea to use in-kernel version, since additional tests - are performed when called from the kernel tree. Yet, those tests are - dependent of the kernel version, so, the results of checkpatch may not - reflect the latest rules/deprecated functions, if you're not using -git. - - It is possible to override the in-kernel checkpatch.pl location, by using - the CHECKPATCH shell environment var to something like: - CHECKPATCH="/usr/src/linux/scripts/checkpatch.pl" - - -c) Sometimes, mainstream changes affect the v4l-dvb tree, and must be - backported to the v4l-dvb tree. This kind of commit to the Mercurial - tree should follow the rules above and should also have the line: - - kernel-sync: - - Patches with this line will not be submitted upstream. - -d) Sometimes it is necessary to introduce some testing code inside a - module or remove parts that are not yet finished. Also, compatibility - tests may be required to provide backporting. - - To allow compatibility tests, linux/version.h is automatically - included by the building system. This allows adding tests like: - - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16) - #include - #else - #include - #endif - - It should be noticed, however, that an explicit inclusion of - linux/version.h is required if it is needed to use KERNEL_VERSION() - macro (this is required, for example, by V4L2 VIDIOC_QUERYCAP - ioctl), otherwise, the driver won't compile when submitted to kernel. - - There are several compatibility procedures already defined - in "compat.h" file. If needed, it is better to include it after all - other kernel standard headers, and before any specific header - for that file. Something like: - - #include - #include - ... - #include - #include - - #include "compat.h" - - #include "mydriver-header.h" - - should be included at the files under v4l-dvb tree. This header also - includes linux/version.h. - - To include testing code, #if 0 or #if 1 may be used. If this code - is meant to go also to kernel, a comment with the word "keep" should - be used, e.g: - - #if 0 /* keep */ - or - #if 1 /* keep */ - - The kernel submit scripts will remove the compatibility codes, the - tests for specific kernel versions and the #if 0/1 that doesn't have - the "keep meta tag". - - See the file v4l/scripts/gentree.pl for a more complete description - of what kind of code will be kept and what kind will be removed. - -e) To import contributed stuff to a developer's, a script is provided. - This allows an easy import of mbox-based patch emails. - This is done with (called from the root tree directory): - - ./mailimport - - For it to work properly, git tools need to be installed on the local - machine, since git has a gitimport script that is used by mailimport. - - There's also a helper script to make easier to retrieve patches from - other Mercurial repositories. The syntax is: - ./hgimport - - Also, hg has a feature, called mqueue, that allows having several patches - that can be applied/unapplied for testing. mailimport trusts on it to work, - so, this extension should be enabled for mailimport script to work. - -3. Knowing about newer patches committed at the development repositories - ===================================================================== - -There are patchbomb scripts at linuxtv.org that will send one copy of -each patch applied patch to v4l-dvb.git and v4l-dvb trees to announce -when a patch is received. This announcement goes to the linuxtv-commits mailing list, hosted on linuxtv.org. - -The Mercurial script also currently sends a copy of the patch to: - -1) The patch author (as stated on the From: field in the patch comments); - -2) The patch committer (the "user" at hg metadata); - -3) All people with Signed-off-by:, Acked-by:, or CC: metadata clause - in the patch's comment. - -If, for some reason, there's no "From:" metatag (or it is on the first -line, instead of the second one), sometimes the script may fail, maybe -filling patch authorship wrongly. So people should take care to properly -commit patches with "From:". - -It is recommended that the developers who submit a pull request via Mercurial -to not touch on the submission tree, until he receives the notification email, -since, even after being merged at -git, the backport maintainer will need to -merge it. - -4. Patch submission from the community - =================================== - -Patch submission is open to all the Free Software community. The general -procedure to have a patch accepted in the v4l/dvb subsystem and in the -kernel is the following: - -a. Post your patches to the mailing list for review and test by other people: - linux-media@vger.kernel.org - - This mailing list doesn't require subscription, although - it is recommended to subscribe, expecially if you're - developing V4L/DVB drivers. - -b. Use [PATCH] and a brief description in the email's subject. - This will help the LinuxTV team to better handle it. - -c. Please include a brief description in the headers of your - patch, like described above. Something like: - - This is just a sample commit comment, just for reference purposes. - This does nothing. - - Signed-off-by: nowhere - -d. Every patch shall have a Developer's Certificate of Origin and should - be submitted by one of its authors. All the patch authors should sign - it. - -e. People will eventually comment about the patch. In this case, - please fix problems and repeat until everyone is happy ;) - -f. If the patch is fixing an existing maintained driver, the - low-level driver maintainer will apply to his tree, and at some later - time, ask the subsystem maintainer to pull it. It is a good idea to - send the patch to the maintainer C/C the mailing list for him to know - that you're expecting him to forward the patch. - -g. If it is a newer driver (not yet in one of the development trees), - please send the patch to the subsystem maintainer, C/C the proper - mailing lists. - -h. Prefer to submit your patches against git, especially if it contains fixes - that needs to go upstream. - -5. Identifying regressions with Mercurial - ====================================== - - The better way for you to identify regressions with Mercurial is to - use hg bisect. This is an extension provided with the current - Mercurial versions. For it to work, you need to have the proper setup - at an hgrc file. To test if bisect is working, you can do: - hg bisect help - - If Mercurial answers with - hg: unknown command 'bisect' - - You will need to add the following lines to your ~/.hgrc file: - [extensions] - hgext.hbisect=/usr/lib/python2.5/site-packages/hgext/hbisect.py - - (assuming that hbisect.py is installed under python2.5 default dir) - - The first step is to initialize bisect for a newer regression testing - session. This is done with: - hg bisect init - - If the bisect were previously initialized, you should, instead do: - hg bisect reset - - Supposing that the latest kernel version have some regression, you - should do something like: - hg update -C - - (This will clean any changes you had on your tree, and will update to - the latest patch) - - Then, you will mark the latest version as "bad": - hg bisect bad - - The next step is to find one version where the your board is properly - working. Supposing that review "4000" is ok, you would do: - hg update 4000 - - Test if the review is really ok. If so, you should mark it as good: - hg bisect good - - If everything is ok, it should print something like: - - Testing changeset 4481:a53c7904e47d (944 changesets remaining, ~9 tests) - 405 files updated, 0 files merged, 8 files removed, 0 files unresolved - - The above line shows that Mercurial selected another revision for you - to test. Redo your tests. If this version is ok, you would do: - - hg bisect good - - otherwise, if the version is broken, you should do: - - hg bisect bad - - This should be repeated until you have an answer like: - - The first bad revision is: - changeset: 4593:26d1ce012c5e - user: Someone - date: Thu Feb 31 17:52:53 2006 -0300 - summary: This is the broken patch that we should find - - If, in the middle of the process, you need to know on what revision - you are, you can do something like: - hg log -r `hg id|cut -d' ' -f 1` - -6. Identifying regressions with Git - ================================ - - A similar bisect procedure to identify broken patches exist on git, and it - is used not only by LinuxTV. So, it is very important that any applied - patch at the kernel don't break compilation, to avoid affecting the bisect - procedures. - - There are several good texts explaining how to use bisect with git. Some - recommended procedures can be seen at: - - http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#using-bisect - http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html - - -7. Creating a newer driver - ======================= - - This quick HOWTO explains how to create a new driver using v4l-dvb - tree. - - The v4l-dvb tree have a the following basic structure: - / - |-- Documentation - | |-- dvb <== DVB drivers documentation - | `-- video4linux <== V4L drivers documentation - |-- drivers - | `-- media - | |-- common <== Common stuff, like IR - | |-- dvb <== DVB only drivers - | |-- radio <== V4L Radio only drivers - | `-- video <== V4L Analog TV (plus radio and/or - | DVB) drivers - `-- include - |-- linux <== V4L userspace API files - | `-- dvb <== DVB userspace API files - `-- media <== V4L internal API files - - When using Mercurial trees, an additional /linux prefix should be added - on all patches - -7.1. Simple drivers - ============== - - For very simple drivers that have only one .c and one .h file, the - recommended way is not to create a newer directory, but keep the - driver into an existing one. - - Assuming that the will be V4L+DVB, the better place for it to be is under - /drivers/media/video. Assuming also that the newer driver - will be called as "newdevice", you need to do: - - a) add at /drivers/media/video/Kconfig something like: - -config VIDEO_NEWDEVICE - tristate "newdevice driver" - select VIDEO_V4L2 - select VIDEO_BUF - help - Support for newdevice Device - - Say Y if you own such a device and want to use it. - - b) add at /drivers/media/video/Makefile something like: - -obj-$(CONFIG_VIDEO_NEWDEVICE) += newdevice.o -EXTRA_CFLAGS = -Idrivers/media/video - -7.2. Bigger drivers - ============== - - In this case, a driver will be splitted into several different source - codes. Ideally, a source file should have up to 1000 source code - lines. After that, you should consider splitting it into smaller files. - - In this case, assuming that the will be V4L+DVB, and that the driver - is called "newdevice", all that is needed to add the newer driver is: - - a) create a newer dir with your driver, for example: - /drivers/media/video/newdevice - b) create /drivers/media/video/newdevice/Kconfig with something - like: - -config VIDEO_NEWDEVICE - tristate "newdevice driver" - select VIDEO_V4L2 - select VIDEO_BUF - help - Support for new device Device - - Say Y if you own such a device and want to use it. - - c) create /drivers/media/video/newdevice/Makefile with - something like: - -obj-$(CONFIG_VIDEO_NEWDEVICE) += newdevice.o -EXTRA_CFLAGS = -Idrivers/media/video - - d) Add your driver directory at /drivers/media/Makefile: - -obj-$(CONFIG_VIDEO_NEWDEVICE) += newdevice/ - - e) Add your driver directory at /drivers/media/Kconfig: - -source "drivers/media/video/newdevice/Kconfig" - - After that, you will be able to use v4l-dvb Makefile to compile your - driver. - - In order to test if your patch is properly compiling, you'll need to - enable its compilation by using make menuconfig/make qconfig/make xconfig. - After that, you can test if your patch compiles well with: - - make drivers/media (on git) - or - make (on hg) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/compat.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/compat.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/compat.h 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/compat.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,799 +0,0 @@ -/* - * $Id: compat.h,v 1.44 2006/01/15 09:35:16 mchehab Exp $ - */ - -#ifndef _COMPAT_H -#define _COMPAT_H - -#include -#include -#include "config-compat.h" - -/* In v2.6.19-rc6-118-g52bad64 struct work_struct was was changed to be only for - * non-delayed work and struct delayed_work was created for delayed work. This - * will rename the structures. Hopefully no one will decide to name something - * delayed_work in the same context as something named work_struct. */ -#ifdef NEED_DELAYED_WORK -#define delayed_work work_struct -#define INIT_DELAYED_WORK(a,b,c) INIT_WORK(a,b,c) -#endif - -#define EXPERIMENTAL_TREE - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) -#define usb_alloc_coherent(dev, size, mem_flags, dma) usb_buffer_alloc(dev, size, mem_flags, dma) -#define usb_free_coherent(dev, size, addr, dma) usb_buffer_free(dev, size, addr, dma) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) -#define KERN_CONT "" -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) -#define ir_register_class(a) input_register_device(a) -#define ir_unregister_class(a) input_unregister_device(a) -#endif - -/* To allow I2C compatibility code to work */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -#include -#endif - -#ifdef NEED_HEX_TO_BIN -#include -static inline int hex_to_bin(char ch) -{ - if ((ch >= '0') && (ch <= '9')) - return ch - '0'; - ch = tolower(ch); - if ((ch >= 'a') && (ch <= 'f')) - return ch - 'a' + 10; - return -1; -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) -#define usb_enable_autosuspend(udev) udev->autosuspend_disabled = 0; -#endif - -#ifndef FBIO_WAITFORVSYNC -#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) -#include -#include -#include -static inline void *memdup_user(const void __user *src, size_t len) -{ - void *p; - - /* - * Always use GFP_KERNEL, since copy_from_user() can sleep and - * cause pagefault, which makes it pointless to use GFP_NOFS - * or GFP_ATOMIC. - */ - p = kmalloc_track_caller(len, GFP_KERNEL); - if (!p) - return ERR_PTR(-ENOMEM); - - if (copy_from_user(p, src, len)) { - kfree(p); - return ERR_PTR(-EFAULT); - } - - return p; -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) -static inline int pci_msi_enabled(void) -{ -#ifndef CONFIG_PCI_MSI - return 0; -#else - return 1; -#endif -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) -#ifdef CONFIG_PROC_FS -#include -#include -#include -#endif -#endif - -#ifndef KEY_NUMERIC_0 -#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */ -#define KEY_NUMERIC_1 0x201 /* and other keypads */ -#define KEY_NUMERIC_2 0x202 -#define KEY_NUMERIC_3 0x203 -#define KEY_NUMERIC_4 0x204 -#define KEY_NUMERIC_5 0x205 -#define KEY_NUMERIC_6 0x206 -#define KEY_NUMERIC_7 0x207 -#define KEY_NUMERIC_8 0x208 -#define KEY_NUMERIC_9 0x209 -#define KEY_NUMERIC_STAR 0x20a -#define KEY_NUMERIC_POUND 0x20b -#endif - -#ifndef DEFINE_PCI_DEVICE_TABLE -#define DEFINE_PCI_DEVICE_TABLE(_table) \ - const struct pci_device_id _table[] __devinitconst -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) -#define netdev_mc_count(dev) ((dev)->mc_count) -#define netdev_mc_empty(dev) (netdev_mc_count(dev) == 0) -#define netdev_for_each_mc_addr(mclist, dev) \ - for (mclist = dev->mc_list; mclist; mclist = mclist->next) -#endif - -#ifndef KEY_CONTEXT_MENU -#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ -#endif - -#ifndef BIT_MASK -#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -#endif - -#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,32) && 0 -#include -#undef _P -static inline char *skip_spaces(const char *str) -{ - while (isspace(*str)) - ++str; - return (char *)str; -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) -#define valtype unsigned long -static inline int strict_strtoul(const char *cp, unsigned int base, valtype *res) -{ - char *tail; - valtype val; - size_t len; - - *res = 0; - len = strlen(cp); - if (len == 0) - return -EINVAL; - - val = simple_strtoul(cp, &tail, base); - if ((*tail == '\0') || - ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { - *res = val; - return 0; - } - - return -EINVAL; -} -#endif - -#ifndef KEY_DASHBOARD -#define KEY_DASHBOARD 204 /* AL Dashboard */ -#endif -/* To allow alsa code to work */ -#ifdef NEED_SOUND_DRIVER_H -#include -#endif - -#ifdef NEED_SND_CARD_CREATE -#include -#endif - -#ifdef NEED_ALGO_CONTROL -#include -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) -#define time_is_after_eq_jiffies(a) (time_before_eq(jiffies, a)) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) -#define set_freezable() -#define cancel_delayed_work_sync cancel_rearming_delayed_work -#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) -#endif - -#ifndef __pure -# define __pure __attribute__((pure)) -#endif - -/* device_create/destroy added in 2.6.18 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) -/* on older kernels, class_device_create will in turn be a compat macro */ -# define device_create(a, b, c, d, e, f, g) class_device_create(a, NULL, c, b, d, e, f, g) -# define device_destroy(a, b) class_device_destroy(a, b) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) -#define IRQF_SHARED SA_SHIRQ -#define IRQF_DISABLED SA_INTERRUPT -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) -#define PCIAGP_FAIL 0 -#define vmalloc_32_user(a) vmalloc_32(a) -#endif - -#ifndef DIV_ROUND_CLOSEST -#define DIV_ROUND_CLOSEST(x, divisor)( \ -{ \ - typeof(divisor) __divisor = divisor; \ - (((x) + ((__divisor) / 2)) / (__divisor)); \ -} \ -) -#endif - -#ifdef NEED_BOOL_TYPE -/* bool type and enum-based definition of true and false was added in 2.6.19 */ -typedef int bool; -enum { - false = 0, - true = 1 -}; -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) -#define sony_pic_camera_command(a,b) sonypi_camera_command(a,b) - -#define SONY_PIC_COMMAND_SETCAMERAAGC SONYPI_COMMAND_SETCAMERAAGC -#define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS SONYPI_COMMAND_SETCAMERABRIGHTNESS -#define SONY_PIC_COMMAND_SETCAMERACOLOR SONYPI_COMMAND_SETCAMERACOLOR -#define SONY_PIC_COMMAND_SETCAMERACONTRAST SONYPI_COMMAND_SETCAMERACONTRAST -#define SONY_PIC_COMMAND_SETCAMERAHUE SONYPI_COMMAND_SETCAMERAHUE -#define SONY_PIC_COMMAND_SETCAMERAPICTURE SONYPI_COMMAND_SETCAMERAPICTURE -#define SONY_PIC_COMMAND_SETCAMERASHARPNESS SONYPI_COMMAND_SETCAMERASHARPNESS -#define SONY_PIC_COMMAND_SETCAMERA SONYPI_COMMAND_SETCAMERA -#endif - -/* pci_dev got a new revision field in 2.6.23-rc1 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) && defined(LINUX_PCI_H) -/* Just make it easier to subsitute pci_dev->revision with - * v4l_compat_pci_rev(pci_dev). It's too bad there isn't some kind of context - * sensitive macro in C that could do this for us. */ -static inline u8 v4l_compat_pci_rev(struct pci_dev *pci) -{ u8 rev; pci_read_config_byte(pci, PCI_REVISION_ID, &rev); return rev; } -#endif - -#if defined(COMPAT_PCM_TO_RATE_BIT) && defined(__SOUND_PCM_H) -/* New alsa core utility function */ -static inline unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate) -{ - static const unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, - 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 }; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (rates[i] == rate) - return 1u << i; - return SNDRV_PCM_RATE_KNOT; -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) -# define task_pid_nr(current) ((current)->pid) - -# define sg_init_table(a,b) -# define sg_page(p) (sg->page) -# define sg_set_page(sglist,pg,sz,off) \ -do { \ - struct scatterlist *p=sglist; \ - p->page = pg; \ - p->length = sz; \ - p->offset = off; \ -} while (0) - -#define pr_err(fmt, arg...) \ - printk(KERN_ERR fmt, ##arg) -#endif - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) -#define noop_llseek NULL -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) -#define pr_warn(fmt, arg...) \ - printk(KERN_WARNING fmt, ##arg) -#endif - -#ifndef BIT_MASK -# define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -# define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) -#define i2c_verify_client(dev) \ - ((dev->bus == &i2c_bus_type) ? to_i2c_client(dev) : NULL) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) -#define i2c_verify_client(dev) \ - ((dev->bus && 0 == strcmp(dev->bus->name, "i2c")) ? to_i2c_client(dev) : NULL) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) -/* Construct an I2C_CLIENT_END-terminated array of i2c addresses */ -#define I2C_ADDRS(addr, addrs...) \ - ((const unsigned short []){ addr, ## addrs, I2C_CLIENT_END }) -#endif - -#ifndef USB_DEVICE_AND_INTERFACE_INFO -# define USB_DEVICE_AND_INTERFACE_INFO(vend,prod,cl,sc,pr) \ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ - | USB_DEVICE_ID_MATCH_DEVICE, \ - .idVendor = (vend), .idProduct = (prod), \ - .bInterfaceClass = (cl), \ - .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) -#define get_unaligned_be16(a) \ - be16_to_cpu(get_unaligned((unsigned short *)(a))) -#define put_unaligned_be16(r, a) \ - put_unaligned(cpu_to_be16(r), ((unsigned short *)(a))) -#define get_unaligned_le16(a) \ - le16_to_cpu(get_unaligned((unsigned short *)(a))) -#define put_unaligned_le16(r, a) \ - put_unaligned(cpu_to_le16(r), ((unsigned short *)(a))) -#define get_unaligned_be32(a) \ - be32_to_cpu(get_unaligned((u32 *)(a))) -#define put_unaligned_be32(r, a) \ - put_unaligned(cpu_to_be32(r), ((u32 *)(a))) -#define get_unaligned_le32(a) \ - le32_to_cpu(get_unaligned((u32 *)(a))) -#define put_unaligned_le32(r, a) \ - put_unaligned(cpu_to_le32(r), ((u32 *)(a))) -#define get_unaligned_le64(a) \ - le64_to_cpu(get_unaligned((u64 *)(a))) -#define put_unaligned_le64(r, a) \ - put_unaligned(cpu_to_le64(r), ((u64 *)(a))) -#endif - -#ifdef NEED_PROC_CREATE -#ifdef CONFIG_PROC_FS -static inline struct proc_dir_entry *proc_create(const char *a, - mode_t b, struct proc_dir_entry *c, const struct file_operations *d) -{ - struct proc_dir_entry *e; - - e = create_proc_entry(a, b, c); - if (e) { - e->owner = THIS_MODULE; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - e->proc_fops = d; -#else - e->proc_fops = (struct file_operations *)d; -#endif - } - return e; -} -#endif -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) -#ifdef CONFIG_PROC_FS -static inline struct proc_dir_entry *proc_create_data(const char *a, - mode_t b, struct proc_dir_entry *c, const struct file_operations *d, - void *f) -{ - struct proc_dir_entry *e; - - e = create_proc_entry(a, b, c); - if (e) { - e->owner = THIS_MODULE; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - e->proc_fops = d; -#else - e->proc_fops = (struct file_operations *)d; -#endif - e->data = f; - } - return e; -} -#endif -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) -#define hweight64(x) generic_hweight64(x) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) -typedef unsigned long uintptr_t; -#endif - -#ifdef NEED_IS_SINGULAR -static inline int list_is_singular(const struct list_head *head) -{ - return !list_empty(head) && (head->next == head->prev); -} -#endif - -#ifdef NEED_CLAMP -#define clamp( x, l, h ) max_t( __typeof__( x ), \ - ( l ), \ - min_t( __typeof__( x ), \ - ( h ), \ - ( x ) ) ) -#define clamp_val(val, min, max) ({ \ - typeof(val) __val = (val); \ - typeof(val) __min = (min); \ - typeof(val) __max = (max); \ - __val = __val < __min ? __min : __val; \ - __val > __max ? __max : __val; }) -#endif - -#ifdef NEED_ALGO_CONTROL -static inline int dummy_algo_control(struct i2c_adapter *adapter, - unsigned int cmd, unsigned long arg) -{ - return 0; -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) -#define div64_u64(a,b) div64_64(a,b) - -#define dev_name(dev) ((dev)->bus_id) - -#define dev_set_name(dev, fmt, arg...) ({ \ - snprintf((dev)->bus_id, sizeof((dev)->bus_id), fmt , ## arg); \ - 0; \ -}) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -#define current_uid() (current->uid) -#endif - -#ifndef WARN -#define WARN(condition, format...) ({ \ - int __ret_warn_on = !!(condition); \ - if (unlikely(__ret_warn_on)) \ - printk(KERN_WARNING format); \ - unlikely(__ret_warn_on); \ -}) -#endif - -#ifdef NEED_SND_BUG_ON -#define snd_BUG_ON(cond) WARN((cond), "BUG? (%s)\n", __stringify(cond)) -#endif - -#ifdef NEED_BITOPS -#define BIT(x) (1UL<<((x)%BITS_PER_LONG)) -#endif - -#ifndef PCI_DEVICE_ID_MARVELL_88ALP01_CCIC -#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102 -#endif - -#ifdef __LINUX_USB_H -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -/* - * usb_endpoint_* functions - * - * Included in Linux 2.6.19 - * Backported to 2.6.18 in Red Hat Enterprise Linux 5.2 - */ - -#ifdef RHEL_RELEASE_CODE -#if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5, 2) -#define RHEL_HAS_USB_ENDPOINT -#endif -#endif - -#ifndef RHEL_HAS_USB_ENDPOINT -static inline int -usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) -{ - return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN; -} - -static inline int -usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) -{ - return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_INT; -} - -static inline int -usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) -{ - return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_ISOC; -} - -static inline int -usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) -{ - return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK; -} - -static inline int -usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) -{ - return usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd); -} - -static inline int usb_endpoint_dir_out( - const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); -} - -static inline int usb_endpoint_is_bulk_in( - const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)); -} - -static inline int usb_endpoint_is_bulk_out( - const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)); -} - -static inline int usb_endpoint_is_int_out( - const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); -} - -static inline int usb_endpoint_is_isoc_in( - const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd)); -} - -static inline int usb_endpoint_is_isoc_out( - const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd)); -} -#endif /* RHEL_HAS_USB_ENDPOINT */ -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) -#ifndef RHEL_HAS_USB_ENDPOINT -static inline int usb_endpoint_xfer_control( - const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_CONTROL); -} -#endif /* RHEL_HAS_USB_ENDPOINT */ -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) -static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd) -{ - return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; -} -#endif - -#ifdef NEED_USB_ENDPOINT_TYPE -static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd) -{ - return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -} -#endif -#endif /* __LINUX_USB_H */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) -/* - * Linked list API - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/* - * uninitialized_var() macro - */ -#define uninitialized_var(x) x = x -#endif - -#ifdef NEED_NETDEV_PRIV -#define netdev_priv(dev) ((dev)->priv) -#endif - -#ifdef NEED_PCI_IOREMAP_BAR -#define pci_ioremap_bar(pdev, bar) \ - ioremap_nocache(pci_resource_start(pdev, bar), \ - pci_resource_len(pdev, bar)) -#endif - -#ifdef NEED_POLL_SCHEDULE -#define poll_schedule(pwq, task) \ - do { \ - set_current_state(task); \ - schedule(); \ - set_current_state(TASK_RUNNING); \ - } while (0) -#endif - -#ifdef NEED_SND_CARD_CREATE -static inline int snd_card_create(int idx, const char *id, - struct module *module, int extra_size, - struct snd_card **card) -{ - *card = snd_card_new(idx, id, module, extra_size); - - if (*card == NULL) - return -ENOMEM; - return 0; -} -#endif - -/* This macro was added in commit v2.6.23-5792-g34c6538 */ -#ifndef DMA_BIT_MASK -#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) -#endif - -/* __fls() was added for generic code in 2.6.29, existed for just 64-bit arches - * since 2.6.26 (v2.6.25-5228-g56a6b1e), and was x86-64 only before then. We - * only want this compat code when __fls doesn't exist, which 2.6.29 or later, - * non x86-64, and non 64-bit that's 2.6.26 or later. */ -#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) || \ - defined(__x86_64__) || \ - (BITS_PER_LONG == 64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26))) -/* This define will prevent breakage if __fls was already defined. */ -#undef __fls -#define __fls v4l_compat_fls -static inline unsigned long v4l_compat_fls(unsigned long x) -{ - return fls(x) - 1; -} -#endif - -/* - * Compatibility code for hrtimer API - * This will make hrtimer usable for kernels 2.6.22 and later. - * For earlier kernels, not all required functions are exported - * so there's nothing we can do. - */ - -#ifdef _LINUX_HRTIMER_H -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -/* Forward a hrtimer so it expires after the hrtimer's current now */ -static inline unsigned long hrtimer_forward_now(struct hrtimer *timer, - ktime_t interval) -{ - return hrtimer_forward(timer, timer->base->get_time(), interval); -} -#endif -#endif /* _LINUX_HRTIMER_H */ - -#ifndef PCI_VDEVICE -#define PCI_VDEVICE(vendor, device) \ - PCI_VENDOR_ID_##vendor, (device), \ - PCI_ANY_ID, PCI_ANY_ID, 0, 0 -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) -#define __devinitconst -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) -#define strncasecmp(a, b, c) strnicmp(a, b, c) -#define strcasecmp(a, b) strnicmp(a, b, sizeof(a)) -#endif - -#ifdef NEED_FW_CSR_STRING - -#include -#include - -static inline int fw_csr_string(u32 *directory, int search_key, char *buf, size_t size) -{ - struct fw_csr_iterator ci; - int last_key = 0, key, value; - const u32 *block = NULL; - unsigned int quadlets, i; - - fw_csr_iterator_init(&ci, directory); - while (fw_csr_iterator_next(&ci, &key, &value)) { - if (last_key == search_key && - key == (CSR_DESCRIPTOR | CSR_LEAF)) { - block = ci.p - 1 + value; - break; - } - - last_key = key; - } - - if (!block) - return -ENOENT; - - quadlets = min(block[0] >> 16, 256U); - if (quadlets < 2) - return -ENODATA; - - if (block[1] != 0 || block[2] != 0) - /* unknown language/character set */ - return -ENODATA; - - block += 3; - quadlets -= 2; - for (i = 0; i < quadlets * 4 && i < size - 1; i++) { - char c = block[i / 4] >> (24 - 8 * (i % 4)); - if (c == '\0') - break; - buf[i] = c; - } - buf[i] = '\0'; - - return i; -} -#endif - -#ifdef NEED_VZALLOC -#include - -static inline void *vzalloc(unsigned long size) -{ - void *p = vmalloc(size); - if (!p) - return NULL; - memset (p, '\0', size); - return p; -} - -#endif - -#ifdef NEED_FLUSH_WORK_SYNC -#define flush_work_sync(dev) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) - -#ifdef NEED_AUTOSUSPEND_DELAY -#define pm_runtime_set_autosuspend_delay(dev, delay) { \ - struct usb_device *udev = to_usb_device(dev); \ - udev->autosuspend_delay = delay; \ -} -#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 37) -/* usb.h includes this from 2.6.38 onwards */ -#include -#endif -#endif - -#ifndef KEY_10CHANNELSUP -#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ -#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ -#endif - -#ifdef NEED_SND_CTL_ENUM_INFO -#include -static inline int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, - unsigned int items, const char *const names[]) -{ - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = channels; - info->value.enumerated.items = items; - if (info->value.enumerated.item >= items) - info->value.enumerated.item = items - 1; - strlcpy(info->value.enumerated.name, - names[info->value.enumerated.item], - sizeof(info->value.enumerated.name)); - return 0; -} -#endif - -#ifdef NEED_SYSFS_ATTR_INIT -#define sysfs_attr_init(a) -#endif - -#ifdef NEED_USLEEP_RANGE -#define usleep_range(min, max) msleep(min/1000) -#endif - -#endif /* _COMPAT_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/.config v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/.config --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/.config 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/.config 1970-01-01 00:00:00.000000000 +0000 @@ -1,461 +0,0 @@ -# CONFIG_VIDEO_GO7007 is not set -# CONFIG_VIDEO_TM6000_ALSA is not set -CONFIG_MEDIA_TUNER_TDA18271=m -CONFIG_IR_MCEUSB=m -# CONFIG_LIRC_ZILOG is not set -CONFIG_USB_DSBR=m -CONFIG_VIDEO_CX88_VP3054=m -# CONFIG_SOC_CAMERA_OV6650 is not set -CONFIG_DVB_USB=m -CONFIG_USB_GSPCA_XIRLINK_CIT=m -CONFIG_IR_NUVOTON=m -CONFIG_DVB_DUMMY_FE=m -CONFIG_USB_GSPCA_OV534=m -# CONFIG_VIDEO_OMAP1 is not set -CONFIG_USB_STKWEBCAM=m -CONFIG_DVB_S5H1420=m -CONFIG_DVB_CX22700=m -# CONFIG_SOC_CAMERA is not set -CONFIG_VIDEO_CX88_BLACKBIRD=m -CONFIG_VIDEO_USBVISION=m -CONFIG_DVB_NGENE=m -CONFIG_DVB_SP8870=m -CONFIG_DVB_BUDGET_AV=m -CONFIG_MEDIA_TUNER=m -CONFIG_DVB_TUNER_DIB0070=m -CONFIG_VIDEO_VPX3220=m -CONFIG_MEDIA_TUNER_TDA827X=m -CONFIG_USB_GSPCA_OV534_9=m -# CONFIG_LIRC_TTUSBIR is not set -CONFIG_USB_GSPCA_SPCA561=m -CONFIG_USB_STV06XX=m -# CONFIG_SOC_CAMERA_RJ54N1 is not set -CONFIG_VIDEO_SAA7110=m -# CONFIG_VIDEO_SH_VOU is not set -CONFIG_VIDEO_ZORAN_BUZ=m -CONFIG_DVB_STV6110x=m -CONFIG_DVB_BT8XX=m -CONFIG_VIDEO_SAA7127=m -CONFIG_DVB_USB_AF9005=m -CONFIG_VIDEO_CX231XX=m -CONFIG_USB_GSPCA_PAC7311=m -CONFIG_VIDEO_UPD64083=m -CONFIG_VIDEO_WM8739=m -CONFIG_RADIO_MAESTRO=m -CONFIG_VIDEO_SAA7164=m -CONFIG_DVB_CX22702=m -CONFIG_VIDEOBUF_GEN=m -CONFIG_IR_NEC_DECODER=m -CONFIG_DVB_B2C2_FLEXCOP_PCI=m -CONFIG_RADIO_AZTECH=m -# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set -CONFIG_VIDEO_BT848=m -CONFIG_VIDEO_VIVI=m -CONFIG_DVB_USB_CXUSB=m -CONFIG_I2C_SI4713=m -# CONFIG_V4L2_MEM2MEM_DEV is not set -CONFIG_IR_SONY_DECODER=m -CONFIG_DVB_STV0367=m -CONFIG_USB_GSPCA_FINEPIX=m -# CONFIG_LIRC_SIR is not set -# CONFIG_SOC_CAMERA_MT9V022 is not set -CONFIG_RADIO_SF16FMI=m -# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set -CONFIG_DVB_ISL6405=m -CONFIG_VIDEO_ADV7343=m -CONFIG_DVB_USB_VP702X=m -CONFIG_DVB_USB_DEBUG=y -# CONFIG_VIDEO_TIMBERDALE is not set -CONFIG_MEDIA_TUNER_XC2028=m -CONFIG_DVB_USB_ANYSEE=m -CONFIG_VIDEO_BT856=m -CONFIG_RADIO_CADET=m -CONFIG_USB_M5602=m -CONFIG_VIDEO_PVRUSB2_DEBUGIFC=y -CONFIG_USB_GSPCA_SONIXJ=m -CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y -CONFIG_RC_LOOPBACK=m -CONFIG_DVB_DRX397XD=m -# CONFIG_STAGING_BROKEN is not set -CONFIG_DVB_MANTIS=m -CONFIG_VIDEO_CX25840=m -CONFIG_VIDEO_VP27SMPX=m -CONFIG_DVB_B2C2_FLEXCOP_USB=m -CONFIG_VIDEO_TVP5150=m -CONFIG_MEDIA_TUNER_SIMPLE=m -CONFIG_VIDEO_CX18_ALSA=m -CONFIG_VIDEO_TEA6415C=m -CONFIG_DVB_OR51211=m -# CONFIG_VIDEO_VIU is not set -CONFIG_VIDEOBUF2_DMA_SG=m -CONFIG_SMS_SIANO_MDTV=m -CONFIG_DVB_AV7110_OSD=y -CONFIG_VIDEO_ZORAN_LML33=m -CONFIG_USB_PWC_INPUT_EVDEV=y -# CONFIG_SOC_CAMERA_MT9M111 is not set -CONFIG_VIDEO_OV7670=m -CONFIG_USB_GSPCA_MARS=m -# CONFIG_SOC_CAMERA_OV772X is not set -CONFIG_VIDEO_CX88=m -CONFIG_VIDEO_W9966=m -CONFIG_DVB_S5H1411=m -CONFIG_VIDEO_TCM825X=m -CONFIG_USB_S2255=m -CONFIG_RADIO_ZOLTRIX=m -CONFIG_DVB_PLL=m -CONFIG_DVB_LGDT330X=m -# CONFIG_VIDEO_GO7007_TW2804 is not set -CONFIG_DVB_STB0899=m -CONFIG_RC_MAP=m -CONFIG_USB_GSPCA_JEILINJ=m -CONFIG_VIDEO_MT9V011=m -CONFIG_DVB_LNBP21=m -CONFIG_DVB_B2C2_FLEXCOP=m -# CONFIG_VIDEO_TM6000 is not set -CONFIG_VIDEOBUF2_CORE=m -CONFIG_USB_GSPCA_SONIXB=m -# CONFIG_STAGING is not set -CONFIG_USB_GSPCA_ZC3XX=m -CONFIG_V4L_MEM2MEM_DRIVERS=y -CONFIG_VIDEO_BT848_DVB=y -CONFIG_VIDEO_ZORAN_DC10=m -CONFIG_DVB_USB_CINERGY_T2=m -CONFIG_RADIO_TERRATEC=m -CONFIG_VIDEO_KS0127=m -# CONFIG_RADIO_WL1273 is not set -CONFIG_MX1_VIDEO=y -# CONFIG_VIDEO_TVP7002 is not set -CONFIG_DVB_VES1820=m -CONFIG_VIDEO_PVRUSB2_DVB=y -CONFIG_VIDEO_DEV=m -CONFIG_VIDEO_SAA717X=m -CONFIG_RADIO_TEA5764=m -CONFIG_VIDEO_CX23885=m -CONFIG_MEDIA_TUNER_MT20XX=m -CONFIG_DVB_BUDGET=m -# CONFIG_CAPTURE_DAVINCI_DM646X_EVM is not set -CONFIG_DVB_VES1X93=m -CONFIG_VIDEO_CS5345=m -# CONFIG_RADIO_GEMTEK_PROBE is not set -CONFIG_USB_GSPCA_SPCA506=m -CONFIG_DVB_ISL6421=m -# CONFIG_VIDEO_VPSS_SYSTEM is not set -CONFIG_USB_GSPCA_PAC207=m -CONFIG_DVB_NXT6000=m -CONFIG_DVB_TTUSB_DEC=m -CONFIG_SND_FM801_TEA575X=m -CONFIG_SMS_USB_DRV=m -CONFIG_DVB_USB_NOVA_T_USB2=m -CONFIG_DVB_DIB9000=m -# CONFIG_SOC_CAMERA_MT9T112 is not set -CONFIG_MEDIA_TUNER_XC5000=m -CONFIG_RADIO_MAXIRADIO=m -CONFIG_DVB_TDA10048=m -CONFIG_MEDIA_TUNER_MXL5005S=m -CONFIG_MEDIA_TUNER_TEA5761=m -# CONFIG_LIRC_IMON is not set -CONFIG_VIDEO_TDA7432=m -CONFIG_DVB_EC100=m -CONFIG_VIDEO_CX18=m -CONFIG_MEDIA_TUNER_MT2266=m -CONFIG_VIDEOBUF_DMA_SG=m -CONFIG_VIDEO_ADV7180=m -CONFIG_DVB_TDA1004X=m -CONFIG_VIDEO_MXB=m -# CONFIG_LIRC_SERIAL_TRANSMITTER is not set -CONFIG_DVB_STV6110=m -CONFIG_VIDEO_ADV7170=m -CONFIG_DVB_DYNAMIC_MINORS=y -# CONFIG_SOC_CAMERA_PLATFORM is not set -CONFIG_VIDEO_TDA9840=m -# CONFIG_VIDEO_PXA27x is not set -CONFIG_DVB_TDA10023=m -CONFIG_VIDEO_V4L2=m -CONFIG_USB_GSPCA_SQ905C=m -CONFIG_DVB_S5H1409=m -# CONFIG_SOC_CAMERA_IMX074 is not set -CONFIG_DVB_USB_DIBUSB_MB=m -CONFIG_VIDEO_SAA7134_ALSA=m -CONFIG_VIDEO_IR_I2C=m -CONFIG_DVB_USB_AF9015=m -CONFIG_DVB_B2C2_FLEXCOP_DEBUG=y -# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set -CONFIG_MX3_VIDEO=y -CONFIG_VIDEO_SAA6588=m -# CONFIG_VIDEO_MX3 is not set -CONFIG_DVB_DS3000=m -CONFIG_MEDIA_TUNER_TEA5767=m -CONFIG_DVB_L64781=m -CONFIG_DVB_CAPTURE_DRIVERS=y -CONFIG_USB_GSPCA_TV8532=m -CONFIG_RADIO_ADAPTERS=y -CONFIG_DVB_USB_OPERA1=m -# CONFIG_RADIO_SAA7706H is not set -CONFIG_DVB_MT352=m -CONFIG_MANTIS_CORE=m -CONFIG_DVB_USB_M920X=m -CONFIG_VIDEO_PVRUSB2_SYSFS=y -CONFIG_DVB_USB_DIGITV=m -CONFIG_VIDEO_MSP3400=m -# CONFIG_VIDEO_DM355_CCDC is not set -CONFIG_VIDEO_BWQCAM=m -CONFIG_DVB_USB_UMT_010=m -CONFIG_USB_GSPCA_SUNPLUS=m -# CONFIG_SOC_CAMERA_TW9910 is not set -CONFIG_MEDIA_TUNER_MXL5007T=m -CONFIG_USB_SN9C102=m -CONFIG_SMS_SDIO_DRV=m -# CONFIG_SOC_CAMERA_MT9M001 is not set -CONFIG_DVB_USB_FRIIO=m -# CONFIG_VIDEO_TM6000_DVB is not set -# CONFIG_VIDEO_AK881X is not set -CONFIG_DVB_DIB3000MB=m -CONFIG_RADIO_GEMTEK=m -CONFIG_VIDEO_CQCAM=m -CONFIG_DVB_LGS8GL5=m -CONFIG_RADIO_RTRACK2=m -CONFIG_USB_GSPCA_PAC7302=m -CONFIG_VIDEO_TUNER=m -CONFIG_USB_GSPCA_OV519=m -CONFIG_DVB_USB_CE6230=m -CONFIG_DVB_USB_DIBUSB_MC=m -CONFIG_RADIO_TEF6862=m -CONFIG_VIDEO_PMS=m -CONFIG_DVB_FE_CUSTOMISE=y -# CONFIG_DISPLAY_DAVINCI_DM646X_EVM is not set -CONFIG_VIDEO_CAPTURE_DRIVERS=y -CONFIG_VIDEOBUF_DMA_CONTIG=m -CONFIG_DVB_STV090x=m -CONFIG_DVB_AF9013=m -CONFIG_VIDEO_ADV_DEBUG=y -CONFIG_VIDEO_SAA711X=m -CONFIG_DVB_MT312=m -CONFIG_VIDEO_CX88_ALSA=m -# CONFIG_VIDEO_OMAP2 is not set -CONFIG_DVB_CX24116=m -CONFIG_DVB_USB_DW2102=m -CONFIG_VIDEOBUF2_VMALLOC=m -CONFIG_SND_BT87X=m -CONFIG_VIDEO_MEDIA=m -#CONFIG_IR_LIRC_CODEC is not set -CONFIG_VIDEO_EM28XX=m -# CONFIG_LIRC_IGORPLUGUSB is not set -CONFIG_USB_GL860=m -CONFIG_VIDEO_V4L2_COMMON=m -CONFIG_VIDEO_BT866=m -CONFIG_DVB_FIREDTV=m -CONFIG_USB_GSPCA_T613=m -# CONFIG_VIDEO_GO7007_USB is not set -# CONFIG_SOC_CAMERA_OV2640 is not set -# CONFIG_LIRC is not set -# CONFIG_VIDEO_VPFE_CAPTURE is not set -CONFIG_USB_SI470X=m -CONFIG_VIDEO_SR030PC30=m -CONFIG_DVB_OR51132=m -# CONFIG_VIDEO_GO7007_SAA7115 is not set -CONFIG_VIDEO_CX88_DVB=m -# CONFIG_VIDEO_CX25821_ALSA is not set -CONFIG_USB_GSPCA_SN9C20X=m -CONFIG_DVB_LGDT3305=m -CONFIG_USB_GSPCA_SPCA501=m -CONFIG_IR_WINBOND_CIR=m -# CONFIG_LIRC_IT87 is not set -CONFIG_USB_GSPCA_SPCA508=m -CONFIG_USB_GSPCA_SPCA505=m -# CONFIG_VIDEO_GO7007_SAA7113 is not set -# CONFIG_LIRC_BT829 is not set -CONFIG_MEDIA_TUNER_MT2060=m -CONFIG_MEDIA_SUPPORT=m -CONFIG_USB_GSPCA_STV0680=m -CONFIG_VIDEO_SAA7134_RC=y -CONFIG_DVB_AU8522=m -CONFIG_RADIO_TYPHOON=m -CONFIG_DVB_ISL6423=m -CONFIG_IR_RC5_SZ_DECODER=m -CONFIG_DVB_BUDGET_PATCH=m -CONFIG_VIDEO_CS53L32A=m -# CONFIG_SOC_CAMERA_MT9T031 is not set -# CONFIG_LIRC_PARALLEL is not set -CONFIG_DVB_ZL10353=m -CONFIG_DVB_CX24110=m -CONFIG_USB_GSPCA=m -CONFIG_DVB_DIB7000M=m -CONFIG_VIDEO_SAA7134_DVB=m -# CONFIG_SOC_CAMERA_OV9740 is not set -CONFIG_USB_GSPCA_SPCA1528=m -CONFIG_USB_GSPCA_VC032X=m -CONFIG_DVB_MB86A20S=m -CONFIG_VIDEO_ADV7175=m -CONFIG_VIDEO_EM28XX_ALSA=m -CONFIG_DVB_DIB3000MC=m -CONFIG_DVB_PT1=m -CONFIG_DVB_USB_TECHNISAT_USB2=m -CONFIG_MEDIA_TUNER_MC44S803=m -# CONFIG_VIDEO_VIA_CAMERA is not set -CONFIG_DVB_TDA8261=m -CONFIG_VIDEO_MEYE=m -CONFIG_VIDEO_CX88_MPEG=m -CONFIG_DVB_USB_AZ6027=m -CONFIG_DVB_BUDGET_CORE=m -CONFIG_DVB_TDA8083=m -CONFIG_VIDEO_CX2341X=m -# CONFIG_VIDEO_SH_MOBILE_CEU is not set -CONFIG_DVB_CORE=m -CONFIG_IR_RC6_DECODER=m -CONFIG_VIDEO_IVTV=m -CONFIG_DVB_HOPPER=m -# CONFIG_VIDEO_OMAP2_VOUT is not set -CONFIG_USB_GSPCA_SQ905=m -# CONFIG_VIDEO_GO7007_OV7640 is not set -CONFIG_RADIO_SI4713=m -CONFIG_DVB_IX2505V=m -CONFIG_DVB_TUNER_CX24113=m -# CONFIG_LIRC_SASEM is not set -CONFIG_IR_ENE=m -CONFIG_DVB_STB6100=m -# CONFIG_MEDIA_ALTERA_CI is not set -CONFIG_DVB_AV7110=m -CONFIG_VIDEO_EM28XX_DVB=m -CONFIG_DVB_STV0299=m -CONFIG_MEDIA_TUNER_QT1010=m -# CONFIG_VIDEO_M32R_AR is not set -CONFIG_VIDEO_CPIA2=m -CONFIG_VIDEO_SAA7146_VV=m -CONFIG_IR_STREAMZAP=m -CONFIG_DVB_USB_DIB0700=m -CONFIG_VIDEO_PVRUSB2=m -CONFIG_DVB_MB86A16=m -CONFIG_VIDEO_SAA7134=m -CONFIG_VIDEO_TVP514X=m -CONFIG_DVB_TUA6100=m -CONFIG_VIDEO_CAFE_CCIC=m -# CONFIG_VIDEO_GO7007_SONY_TUNER is not set -CONFIG_USB_PWC_DEBUG=y -CONFIG_USB_GSPCA_SPCA500=m -CONFIG_TTPCI_EEPROM=m -CONFIG_VIDEO_THS7303=m -CONFIG_DVB_NXT200X=m -CONFIG_VIDEO_ZORAN_ZR36060=m -CONFIG_MEDIA_TUNER_TDA8290=m -CONFIG_VIDEO_SAA7185=m -CONFIG_VIDEO_TEA6420=m -CONFIG_DVB_S5H1432=m -# CONFIG_VIDEO_DAVINCI_VPIF is not set -# CONFIG_RADIO_WL128X is not set -CONFIG_DVB_STV0297=m -CONFIG_RADIO_SF16FMR2=m -CONFIG_USB_ZR364XX=m -# CONFIG_VIDEO_GO7007_TW9903 is not set -# CONFIG_LIRC_STAGING is not set -CONFIG_VIDEOBUF_VMALLOC=m -CONFIG_DVB_USB_DTV5100=m -CONFIG_USB_PWC=m -CONFIG_USB_GSPCA_SN9C2028=m -CONFIG_DVB_DM1105=m -# CONFIG_RADIO_TEA5764_XTAL is not set -CONFIG_IR_RC5_DECODER=m -CONFIG_DVB_USB_DTT200U=m -CONFIG_VIDEO_CX231XX_ALSA=m -CONFIG_VIDEO_TVEEPROM=m -CONFIG_USB_GSPCA_STK014=m -CONFIG_VIDEO_CX231XX_RC=y -CONFIG_DVB_ATBM8830=m -CONFIG_VIDEO_HEXIUM_GEMINI=m -# CONFIG_VIDEO_MX2 is not set -CONFIG_VIDEO_ZORAN_LML33R10=m -# CONFIG_I2C_SI470X is not set -CONFIG_DVB_TDA10021=m -CONFIG_MEDIA_TUNER_TDA9887=m -CONFIG_VIDEO_ZORAN_AVS6EYES=m -CONFIG_DVB_USB_AU6610=m -CONFIG_VIDEO_SAA7191=m -CONFIG_MEDIA_ATTACH=y -CONFIG_DVB_USB_GL861=m -CONFIG_RADIO_TRUST=m -# CONFIG_RADIO_TIMBERDALE is not set -CONFIG_USB_GSPCA_SQ930X=m -CONFIG_RADIO_SI470X=y -CONFIG_USB_GSPCA_ETOMS=m -CONFIG_DVB_USB_EC168=m -CONFIG_VIDEOBUF2_DMA_CONTIG=m -CONFIG_VIDEO_FB_IVTV=m -CONFIG_RADIO_MIROPCM20=m -CONFIG_VIDEO_BT819=m -CONFIG_VIDEO_SAA7146=m -CONFIG_DVB_TUNER_ITD1000=m -CONFIG_VIDEO_BTCX=m -CONFIG_MEDIA_TUNER_CUSTOMISE=y -CONFIG_VIDEOBUF_DVB=m -CONFIG_DVB_S921=m -# CONFIG_VIDEO_ISIF is not set -# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set -CONFIG_DVB_USB_LME2510=m -CONFIG_DVB_USB_VP7045=m -CONFIG_VIDEO_ZORAN=m -CONFIG_USB_GSPCA_CPIA1=m -CONFIG_DVB_CX24123=m -CONFIG_VIDEO_CX231XX_DVB=m -# CONFIG_VIDEO_GO7007_USB_S2250_BOARD is not set -CONFIG_DVB_TUNER_DIB0090=m -CONFIG_MEDIA_TUNER_MAX2165=m -CONFIG_IR_IMON=m -CONFIG_USB_MR800=m -CONFIG_RADIO_RTRACK=m -# CONFIG_VIDEO_DM6446_CCDC is not set -CONFIG_MEDIA_TUNER_MT2131=m -# CONFIG_LIRC_ITE8709 is not set -# CONFIG_VIDEO_CX25821 is not set -CONFIG_DVB_STV0288=m -# CONFIG_VIDEO_MX1 is not set -CONFIG_USB_VIDEO_CLASS=m -CONFIG_VIDEO_HEXIUM_ORION=m -CONFIG_VIDEO_M52790=m -CONFIG_USB_GSPCA_MR97310A=m -# CONFIG_SOC_CAMERA_OV9640 is not set -CONFIG_VIDEO_UPD64031A=m -CONFIG_VIDEO_TVAUDIO=m -CONFIG_VIDEO_MX2_HOSTSUPPORT=y -CONFIG_VIDEO_TLG2300=m -CONFIG_DVB_PLUTO2=m -CONFIG_DVB_STB6000=m -CONFIG_DVB_TDA665x=m -CONFIG_DVB_BUDGET_CI=m -CONFIG_DVB_USB_GP8PSK=m -CONFIG_SND_BT87X_OVERCLOCK=y -CONFIG_USB_GSPCA_VICAM=m -CONFIG_DVB_DIB8000=m -CONFIG_DVB_USB_TTUSB2=m -CONFIG_DVB_TDA826X=m -# CONFIG_VIDEO_GO7007_UDA1342 is not set -CONFIG_DVB_TDA10086=m -CONFIG_DVB_TTUSB_BUDGET=m -CONFIG_VIDEO_NOON010PC30=m -CONFIG_VIDEO_WM8775=m -CONFIG_VIDEO_TLV320AIC23B=m -CONFIG_RC_CORE=m -CONFIG_USB_GSPCA_KONICA=m -# CONFIG_VIDEO_VINO is not set -CONFIG_VIDEOBUF2_MEMOPS=m -CONFIG_DVB_SP887X=m -CONFIG_DVB_DIB7000P=m -CONFIG_USB_GSPCA_BENQ=m -CONFIG_USB_GSPCA_CONEX=m -CONFIG_USB_ET61X251=m -CONFIG_VIDEO_HDPVR=m -CONFIG_IR_JVC_DECODER=m -# CONFIG_VIDEO_M32R_AR_M64278 is not set -CONFIG_DVB_LGS8GXX=m -CONFIG_DVB_SI21XX=m -CONFIG_DVB_ZL10036=m -CONFIG_DVB_BCM3510=m -CONFIG_DVB_STV0900=m -CONFIG_DVB_ZL10039=m -CONFIG_DVB_USB_AF9005_REMOTE=m -CONFIG_VIDEO_AU0828=m -# CONFIG_LIRC_SERIAL is not set -CONFIG_DVB_USB_A800=m -CONFIG_VIDEO_ZORAN_DC30=m -CONFIG_MEDIA_TUNER_TDA18218=m -CONFIG_V4L_USB_DRIVERS=y -CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y -CONFIG_DVB_MAX_ADAPTERS=8 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/firmware/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/firmware/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/firmware/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/firmware/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -TARGETS = vicam/firmware.fw dabusb/firmware.fw dabusb/bitstream.bin ttusb-budget/dspbootcode.bin cpia2/stv0672_vp4.bin av7110/bootcode.bin -FW_DIR = $(DESTDIR)/lib/firmware - -#### - -DIRS = $(sort $(dir $(TARGETS))) - -.PHONY = default clean distclean install rminstall prep - -default: $(TARGETS) - -$(TARGETS):: ihex2fw - -clean: - -rm -f ihex2fw - -rm -f $(TARGETS) - -distclean: clean - -for i in $(DIRS); do if [ -d $$i ]; then rm -rf $$i; fi; done - - -install: default - @echo -n "Installing firmwares at $(FW_DIR): " - -@for i in $(DIRS); do if [ ! -d $(FW_DIR)/$$i ]; then mkdir -p $(FW_DIR)/$$i; fi; done - -@for i in $(TARGETS); do echo -n "$$i "; cp $$i $(FW_DIR)/$$i; done - @echo - -rminstall: - @echo "Removing firmwares at $(FW_DIR) " - -for i in $(DIRS); do if [ -d $(FW_DIR)/$$i ]; then rm -rf $(FW_DIR)/$$i; fi; done - -###### - -ihex2fw: ../../linux/firmware/ihex2fw.c - @echo " CC $@" - @gcc -Wall -o $@ $< - -prep: - @for i in $(DIRS); do \ - if [ ! -d $$i ]; then mkdir -p $$i; fi; \ - for j in ../../linux/firmware/$$i/*; do \ - n=`echo $$j | sed s,../../linux/firmware/,,`; \ - if [ ! -e $$n ]; then \ - ln -f $$j $$n; \ - fi; \ - done; done - -%.fw: %.H16 - @echo Generating $@ - @./ihex2fw -w $< $@ - -%.fw: %.HEX - @echo Generating $@ - @./ihex2fw $< $@ - -%.bin: %.bin.ihex - @echo Generating $@ - @objcopy -Iihex -Obinary $< $@ - -# TODO: Use the Firmware Kconfig dependencies -#fw-$(CONFIG_USB_VICAM) += vicam/firmware.fw -#fw-$(CONFIG_USB_DABUSB) += dabusb/firmware.fw dabusb/bitstream.bin -#fw-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin -#fw-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin -#fw-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/.gitignore v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/.gitignore --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/.gitignore 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -*.c -*.h -!compat.h -*.cmd -.config -.config.old -firmware/av7110/ -firmware/cpia2/ -firmware/dabusb/ -firmware/ttusb-budget/ -firmware/vicam/ -firmware/ihex2fw -Kconfig -.kconfig.dep -Kconfig.kern -*.ko -*.ko.unsigned -Makefile.media -modules.order -Module.symvers -.myconfig -*.o -.*.o.d -oss -.*.o.tmp -.tmp* -.version diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Kconfig.sound v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Kconfig.sound --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Kconfig.sound 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Kconfig.sound 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -menu "Audio devices for multimedia" - -# This is part of sound/pci/Kconfig -comment "ALSA sound" - -config SND_BT87X - tristate "Bt87x Audio Capture" - depends on SND && PCI - select SND_PCM - help - If you want to record audio from TV cards based on - Brooktree Bt878/Bt879 chips, say Y here and read - . - - To compile this driver as a module, choose M here: the module - will be called snd-bt87x. - -config SND_BT87X_OVERCLOCK - bool "Bt87x Audio overclocking" - depends on SND_BT87X - help - Say Y here if 448000 Hz isn't enough for you and you want to - record from the analog input with up to 1792000 Hz. - - Higher sample rates won't hurt your hardware, but audio - quality may suffer. - -config SND_FM801_TEA575X - tristate "ForteMedia FM801 TEA5757 tuner" - depends on VIDEO_V4L1 && SND_FM801 - - help - Say Y here to include support for soundcards based on the ForteMedia - FM801 chip with a TEA5757 tuner connected to GPIO1-3 pins (Media - Forte SF256-PCS-02) into the snd-fm801 driver. - - This will enable support for the old V4L1 API. - -endmenu diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Kconfig.staging v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Kconfig.staging --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Kconfig.staging 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Kconfig.staging 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -menuconfig STAGING - bool "Staging drivers" - default n - ---help--- - This option allows you to select a number of drivers that are - not of the "normal" Linux kernel quality level. These drivers - are placed here in order to get a wider audience for use of - them. Please note that these drivers are under heavy - development, may or may not work, and may contain userspace - interfaces that most likely will be changed in the near - future. - - Using any of these drivers will taint your kernel which might - affect support options from both the community, and various - commercial support orginizations. - - If you wish to work on these drivers, to help improve them, or - to report problems you have with them, please see the - driver_name.README file in the drivers/staging/ directory to - see what needs to be worked on, and who to contact. - - If in doubt, say N here. - -if STAGING -menu "Media devices in staging" - -config STAGING_BROKEN - bool "Enable drivers that are known to not compile" - default n - --- help --- - Say N here, except if you will be fixing the drivers - compilation. - -source "../linux/drivers/staging/go7007/Kconfig" -source "../linux/drivers/staging/cx25821/Kconfig" -source "../linux/drivers/staging/tm6000/Kconfig" -source "../linux/drivers/staging/lirc/Kconfig" -source "../linux/drivers/staging/altera-stapl/Kconfig" -# Currently, there are no broken staging drivers with Kernel 2.6.31 -# if STAGING_BROKEN -# endif - -endmenu - -endif # STAGING diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Makefile 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,471 +0,0 @@ -ifeq ($(wildcard ../linux/include/linux/videodev2.h),) - -# No kernel source! User needs to download one -def: - @echo 'No kernel files. You need to run "make download untar" or "make dir DIR=" first!' - exit 1 -endif - -ifeq ($(obj),) -obj = . -endif - -################################################# -# This Makefile is used from two contexts. It is used directly when one runs -# 'make' from the v4l-dvb tree. It used used again when the kernel build -# process includes this file into the kernel Makefile. -ifneq ($(TOPDIR),) -# We are being include from the Kernel --include $(TOPDIR)/Rules.make -else -# We are running directly, not from the Kernel - -# take version info from last module build if available -# if .version doesn't exist, make will create it for us and restart --include $(obj)/.version - -ifneq ($(SRCDIR),) - OUTDIR ?= $(SRCDIR) -endif -OUTDIR ?= /lib/modules/$(KERNELRELEASE)/build -SRCDIR ?= /lib/modules/$(KERNELRELEASE)/source -ifeq ($(wildcard $(SRCDIR)/Makefile),) - # No kernel source, but headers should be in OUTDIR - SRCDIR := $(OUTDIR) -endif - -ifneq ($(origin KDIR), undefined) -ifneq ($(KDIR),$(SRCDIR)) -KERNELRELEASE := -override DIR := $(KDIR) -.PHONY: $(obj)/.version -endif -endif - -endif # TOPDIR - -################################################# -# default compilation rule - -default:: prepare firmware - @echo Kernel build directory is $(OUTDIR) - $(MAKE) -C ../linux apply_patches - $(MAKE) -C $(OUTDIR) SUBDIRS=$(PWD) $(MYCFLAGS) modules - ./scripts/rmmod.pl check -# $(MAKE) checkpatch - -mismatch:: prepare firmware - @echo Kernel build directory is $(OUTDIR) - $(MAKE) -Wfatal-errors -C $(OUTDIR) SUBDIRS=$(PWD) $(MYCFLAGS) CONFIG_DEBUG_SECTION_MISMATCH=y modules - ./scripts/rmmod.pl check - -# Anything in this target shouldn't be build in parallel. -prepare:: config-compat.h Makefile.media links - -firmware:: - $(MAKE) -C firmware prep - $(MAKE) -C firmware - -################################################# -# Object specific rules - -# Targets which don't need Makefile.media's rules -no-makefile-media-targets := %config clean distclean snapshot snap \ - tarball release %links start insmod load stop rmmod unload reload \ - card% update push %commit help debug cx88-ivtv lxdialog - -# Targets which don't need .myconfig to exist, to keep us from including it -no-dot-config-targets := $(no-makefile-media-targets) %install remove - -dot-config := 1 -ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) - ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) - dot-config := 0 - endif -endif - -makefile-media := 1 -ifneq ($(filter $(no-makefile-media-targets), $(MAKECMDGOALS)),) - ifeq ($(filter-out $(no-makefile-media-targets), $(MAKECMDGOALS)),) - makefile-media := 0 - endif -endif - -# If version not yet detected, we can't create/have these files yet -ifeq ($(KERNELRELEASE),) - makefile-media := 0 - dot-config := 0 -endif - -ifeq ($(dot-config),1) --include $(obj)/.myconfig -endif - -ifeq ($(makefile-media),1) --include $(obj)/Makefile.media --include $(obj)/Makefile.sound -endif - --include $(obj)/.kconfig.dep - -# make will try to automatically rebuild the Makefile and all includes, -# and if any of them change, make will start over with the updated files - -$(obj)/.myconfig: $(obj)/.config $(obj)/Kconfig - ./scripts/make_myconfig.pl - -# If it doesn't exist, this rule will build Makefile.media. If it does -# exist, it will have dependency information in it, and only be rebuilt -# when necessary. -Makefile.media: - scripts/make_makefile.pl - -################################################# -# CFLAGS configuration - -ifeq ($(CONFIG_DVB_FIRESAT),m) - EXTRA_CFLAGS += -I$(srctree)/drivers/ieee1394/ -endif - -EXTRA_CFLAGS += -g - -EXTRA_CFLAGS += $(if $(wildcard $(srctree)/.mm), -DMM_KERNEL) - -# Make sure to use the backport header for common stuff -EXTRA_CFLAGS += -include $(obj)/compat.h - -################################################# -# Kernel 2.4/2.6 specific rules - -ifneq ($(KERNELRELEASE),) - -ifeq ($(VERSION).$(PATCHLEVEL),2.6) - export-objs := - list-multi := -else -include $(obj)/Makefile.kern24 - - multi-m := $(filter $(list-multi), $(obj-m)) - int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) - export-objs := $(filter $(int-m) $(obj-m),$(export-objs)) -endif - -endif - -################################################# -# Directories to be used - -snapshot := $(wildcard $(obj)/.snapshot) -ifneq ($(snapshot),) -SNAPSHOT_CFLAGS := -DSNAPSHOT='$(shell cat $(snapshot))' -EXTRA_CFLAGS += $(SNAPSHOT_CFLAGS) -endif - -PWD := $(shell pwd) -DEST := /lib/modules/$(KERNELRELEASE)/v4l2 -KDIR26 := /lib/modules/$(KERNELRELEASE)/kernel/drivers/media - -################################################# -# Compiler fixup rules - -HOSTCC:=$(CC) -CC += -I$(obj) - -ifeq ($(VERSION).$(PATCHLEVEL),2.6) - CPPFLAGS := -I$(SUBDIRS)/../linux/include $(CPPFLAGS) -I$(SUBDIRS)/ - - # Needed for kernel 2.6.24 or up - KBUILD_CPPFLAGS := -I$(SUBDIRS)/../linux/include $(KBUILD_CPPFLAGS) -I$(SUBDIRS)/ - - # Needed for kernel 2.6.29 or up - LINUXINCLUDE := -I$(SUBDIRS)/../linux/include $(LINUXINCLUDE) -I$(SUBDIRS)/ - - MYCFLAGS := -else - MYCFLAGS := CFLAGS="-I../linux/include -D__KERNEL__ -I$(KDIR)/include -DEXPORT_SYMTAB" -endif - - -################################################# -# which files to install? - -inst-m := $(wildcard *.ko) -ifeq ($(inst-m),) - inst-m := $(obj-m) -endif - -v4l_modules := $(shell /sbin/lsmod|cut -d' ' -f1 ) $(patsubst %.ko,%,$(inst-m)) - -################################################# -# locales seem to cause trouble sometimes. -LC_ALL = POSIX -export LC_ALL - - -################################################# -# Generic wildcard rules - -%.asm: %.o - objdump -S $< > $@ - -################################################# -# all file compilation rule - -all:: default - -################################################# -# installation invocation rules - -modules_install install:: media-install firmware_install - -remove rminstall:: media-rminstall - -firmware_install:: - make -C firmware install - -################################################# -# Compiling preparation rules - -.PHONY: release -ifneq ($(filter release,$(MAKECMDGOALS)),) -.PHONY: $(obj)/.version -endif -release: - @true - -$(obj)/.version: -ifneq ($(DIR),) - @echo "Searching in $(DIR)/Makefile for kernel version." - @perl \ - -e '$$d="$(DIR)"; ' \ - -e 'S: open IN,"$$d/Makefile"; ' \ - -e 'while () {' \ - -e ' if (/^VERSION\s*=\s*(\d+)/){ $$version=$$1; }' \ - -e ' elsif (/^PATCHLEVEL\s*=\s*(\d+)/){ $$level=$$1; }' \ - -e ' elsif (/^SUBLEVEL\s*=\s*(\d+)/){ $$sublevel=$$1; }' \ - -e ' elsif (/^EXTRAVERSION\s*=\s*(\S+)\n/){ $$extra=$$1; }' \ - -e ' elsif (/^KERNELSRC\s*:=\s*(\S.*)\n/ || /^MAKEARGS\s*:=\s*-C\s*(\S.*)\n/)' \ - -e ' { $$o=$$d; $$d=$$1; goto S; }' \ - -e '};' \ - -e 'printf ("VERSION=%s\nPATCHLEVEL:=%s\nSUBLEVEL:=%s\nKERNELRELEASE:=%s.%s.%s%s\n",' \ - -e ' $$version,$$level,$$sublevel,$$version,$$level,$$sublevel,$$extra);' \ - -e 'print "OUTDIR:=$$o\n" if($$o);' \ - -e 'print "SRCDIR:=$$d\n";' > $(obj)/.version - @cat .version|grep KERNELRELEASE:|sed s,'KERNELRELEASE:=','Forcing compiling to version ', - - @if [ ! -f $(DIR)/scripts/kallsyms ]; then \ - echo "*** Warning: You should configure and build kernel before compiling V4L"; \ - fi -else -ifneq ($(VER),) - @echo "Forcing kernel version to $(VER)." - @echo $(VER)|perl -ne 'if (/^([0-9]*)\.([0-9])*\.([0-9]*)(.*)$$/) { printf ("VERSION=%s\nPATCHLEVEL:=%s\nSUBLEVEL:=%s\nKERNELRELEASE:=%s.%s.%s%s\n",$$1,$$2,$$3,$$1,$$2,$$3,$$4); };' > $(obj)/.version -else - @echo No version yet, using `uname -r` - @uname -r|perl -ne 'if (/^([0-9]*)\.([0-9])*\.([0-9]*)(.*)$$/) { printf ("VERSION=%s\nPATCHLEVEL:=%s\nSUBLEVEL:=%s\nKERNELRELEASE:=%s.%s.%s%s\n",$$1,$$2,$$3,$$1,$$2,$$3,$$4); };' > $(obj)/.version -endif -endif - -links:: - @echo creating symbolic links... - @find ../linux/drivers/media -name '*.[ch]' -type f -print0 | xargs -0n 255 ln -sf --target-directory=. - @find ../linux/sound -name '*.[ch]' -type f -print0 | xargs -0n 255 ln -sf --target-directory=. - @find ../linux/drivers/staging -name '*.[ch]' -type f -print0 | xargs -0n 255 ln -sf --target-directory=. - -config-compat.h:: $(obj)/.version .myconfig scripts/make_config_compat.pl - perl scripts/make_config_compat.pl $(SRCDIR) $(obj)/.myconfig $(obj)/config-compat.h - -kernel-links makelinks:: - cd ..; v4l/scripts/makelinks.sh $(SRCDIR) - - -################################################# -# Cardlist updating rule - -card cardlist cardlists:: - scripts/cardlist - -################################################# -# Cleaning rules - -clean:: - @find . -name '*.c' -type l -exec rm '{}' \; - @find . -name '*.h' -type l -exec rm '{}' \; - -rm -f *~ *.o *.ko .*.o.cmd .*.ko.cmd *.mod.c av7110_firm.h fdump \ - config-compat.h Module.symvers Module.markers modules.order \ - *.unsigned .*.ko.unsigned.cmd - $(MAKE) -C firmware $@ - -distclean:: clean - -rm -f .version .*.o.flags .*.o.d Makefile.media \ - Kconfig Kconfig.kern .config .config.cmd .myconfig \ - .kconfig.dep - -rm -rf .tmp_versions .tmp*.ver .tmp*.o - -rm -f scripts/lxdialog scripts/kconfig - @find .. -name '*.orig' -exec rm '{}' \; - @find .. -name '*.rej' -exec rm '{}' \; - $(MAKE) -C firmware $@ - -################################################# -# Kernel module insert/removal rules - -start insmod load:: - scripts/rmmod.pl load - -stop rmmod unload:: - scripts/rmmod.pl unload - -reload:: - scripts/rmmod.pl reload - -debug:: - scripts/rmmod.pl debug - -################################################# -# Configuration rules - -# Kernel config programs -QCONF := $(OUTDIR)/scripts/kconfig/qconf -GCONF := $(OUTDIR)/scripts/kconfig/gconf -MCONF := $(OUTDIR)/scripts/kconfig/mconf -CONF := $(OUTDIR)/scripts/kconfig/conf - -# lxdialog can be in either scripts/lxdialog or scripts/kconfig/lxdialog -LXDIALOG_DIR := $(shell if [ -d $(OUTDIR)/scripts/kconfig/lxdialog ]; then echo kconfig/ ; fi) -# lxdialog might not be a separate program that needs to be built, check -# for lxdialog/Makefile to find out. -ifneq ($(wildcard $(SRCDIR)/scripts/$(LXDIALOG_DIR)lxdialog/Makefile),) - # lxdialog must be built - LXDIALOG_LNK := $(if $(LXDIALOG_DIR),scripts/kconfig,scripts/lxdialog) - LXDIALOG := $(OUTDIR)/scripts/$(LXDIALOG_DIR)lxdialog/lxdialog -endif - -# Ideally, some kind of oldconfig process would be used to update .config -# without destroying the user's configuration. Lacking that, we will -# just touch .config if it already exists, and run make_kconfig if it -# doesn't. -$(obj)/.config: $(obj)/.version - @echo Updating/Creating .config - @if [ -e $(obj)/.config ]; then touch $(obj)/.config ; else \ - $(MAKE) -C ../linux apply_patches; \ - ./scripts/make_kconfig.pl $(OUTDIR) $(SRCDIR); fi - -$(obj)/Kconfig: $(obj)/.version - @$(MAKE) -C ../linux apply_patches - ./scripts/make_kconfig.pl $(OUTDIR) $(SRCDIR) - -# With make -j, it's possible that both the .config and Kconfig rules -# will run at the same time, running make_kconfig.pl twice. There -# doesn't appear to be any way around this, but it doesn't cause a -# failure. One make_kconfig.pl will just overwrite the other's output. - -xconfig:: $(QCONF) $(obj)/Kconfig - $(QCONF) $(obj)/Kconfig - ./scripts/fix_kconfig.pl - -gconfig:: $(GCONF) $(obj)/Kconfig - $(GCONF) $(obj)/Kconfig - ./scripts/fix_kconfig.pl - -config:: $(CONF) $(obj)/Kconfig - $(CONF) $(obj)/Kconfig - ./scripts/fix_kconfig.pl - -menuconfig:: $(MCONF) lxdialog $(obj)/Kconfig - $(MCONF) $(obj)/Kconfig - ./scripts/fix_kconfig.pl - -allyesconfig allmodconfig:: $(obj)/.version - @$(MAKE) -C ../linux apply_patches - ./scripts/make_kconfig.pl $(OUTDIR) $(SRCDIR) 1 - ./scripts/fix_kconfig.pl - -stagingconfig:: $(obj)/.version - @$(MAKE) -C ../linux apply_patches - ./scripts/make_kconfig.pl $(OUTDIR) $(SRCDIR) 1 1 - ./scripts/fix_kconfig.pl - -# rule to build kernel conf programs -KMAKEVARS := config-targets=1 mixed-targets=0 dot-config=0 SRCDIR=$(SRCDIR) -$(QCONF) $(GCONF) $(MCONF) $(CONF): - $(MAKE) -C $(OUTDIR) -f $(PWD)/Makefile.kernel $(KMAKEVARS) v4l-$(notdir $@) - -# lxdialog has two parts, a symlink and the actual binary -.PHONY: lxdialog -lxdialog: $(LXDIALOG) $(LXDIALOG_LNK) - -ifdef LXDIALOG -$(LXDIALOG_LNK): - ln -snf $(OUTDIR)/$(LXDIALOG_LNK) $(LXDIALOG_LNK) - -$(LXDIALOG): - $(MAKE) -C $(SRCDIR) -f $(PWD)/Makefile.kernel $(KMAKEVARS) v4l-$(LXDIALOG) -endif - -cx88-ivtv:: - @echo creating cx88-ivtv symbolic links... - @ln -sf ../v4l_experimental/cx88-ivtv.c . - -################################################# -# Old instalation rule - -old-install:: rminstall - @echo -e "\nInstalling new V4L modules at $(DEST)..." - - @strip --strip-debug $(inst-m) - - -install -d $(DEST) - -install -m 644 -c $(inst-m) $(DEST) - - /sbin/depmod -a ${KERNELRELEASE} - -################################################# -# Tree management rules - -update:: - make -C .. update - -commit cvscommit hgcommit:: - make -C .. commit - -push:: - make -C .. push - -################################################# -# Consistency checks -checkemacs:: - scripts/check.pl - -checketerse:: - scripts/check.pl -t - -checkpatch:: - scripts/check.pl -c - -################################################# -# Help -help:: - @cat ../INSTALL - -################################################# -# build tarballs rules - -RPWD := $(shell cd .. && pwd) -thisdir := $(notdir $(RPWD)) -name := v4l-dvb -date := $(shell date +%Y%m%d) -tardest ?= . - -snapdir := $(HOME)/snapshot -snap := $(name) - -snapshot snap tarball:: update distclean - echo $(thisdir) - echo $(name) - echo $(date) > .snapshot - (cd ..; tar czf $(snapdir)/$(snap)-$(date).tar.gz .) - hg history --style scripts/map-changelog > /$(snapdir)/$(snap)-ChangeLog-$(date) - $(MAKE) -C $(snapdir) - -dir download apply-patches unapply-patches untar:: - make -C ../linux $@ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.kern24 v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.kern24 --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.kern24 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.kern24 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -# -# Need to compile with kernel 2.4 -# - -bttv.o: $(bttv-objs) - $(LD) -r -o $@ $(bttv-objs) - -cx25840.o: $(cx25840-objs) - $(LD) -g -r -o $@ $(cx25840-objs) - -cx8800.o: $(cx8800-objs) - $(LD) -g -r -o $@ $(cx8800-objs) - -cx8802.o: $(cx8802-objs) - $(LD) -g -r -o $@ $(cx8802-objs) - -cx88xx.o: $(cx88xx-objs) - $(LD) -g -r -o $@ $(cx88xx-objs) - -em28xx.o: $(em28xx-objs) - $(LD) -g -r -o $@ $(em28xx-objs) - -saa7134.o: $(saa7134-objs) - $(LD) -g -r -o $@ $(saa7134-objs) - -tuner.o: $(tuner-objs) - $(LD) -g -r -o $@ $(tuner-objs) - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.kernel v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.kernel --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.kernel 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.kernel 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -# This Makefile is used to build sources that are part of the kernel tree. -# What we want are the various programs used by the kconfig system. We can't -# just directly call the top-level kernel Makefile, as it doesn't provide -# targets to only build the kconfig system. It provides targets to build -# the kconfig system *and then configure the kernel*. - -# What we do is include the top-level kernel Makefile here, to get all the -# variables and rules it defines, and then add our own targets to just build -# the kconfig system. You can think of this file as a modified version of the -# top-level kernel Makefile that has "kconfig build only" targets added to it. -# Each of these new targets has the prefix v4l- so it doesn't conflict with -# any targets in the kernel Makefile. - -# Like the kernel Makefile, this Makefile should have the cwd be the root -# of the kernel source. - -# These should be defined on the command line, to override the kernel Makefile -# config-targets := 1 -# mixed-targets := 0 -# dot-config := 0 - -KBUILD_SRC := $(SRCDIR) -include $(SRCDIR)/Makefile - -# Used by the config target -v4l-conf: scripts_basic - $(MAKE) $(build)=scripts/kconfig scripts/kconfig/conf - -# Used by the xconfig target -v4l-qconf: scripts_basic - $(MAKE) $(build)=scripts/kconfig qconf-target=1 scripts/kconfig/qconf - -# Used by the qconfig target -v4l-gconf: scripts_basic - $(MAKE) $(build)=scripts/kconfig gconf-target=1 scripts/kconfig/gconf - -# Used by the menuconfig target, also needs lxdialog -v4l-mconf: scripts_basic - $(MAKE) $(build)=scripts/kconfig hostprogs-y=mconf scripts/kconfig/mconf - -# Rule used for kernel where lxdialog is in directory scripts/lxdialog -v4l-%/scripts/lxdialog/lxdialog: scripts_basic - $(MAKE) $(build)=scripts/lxdialog - -# Rule used for kernel where lxdialog is in directory scripts/kconfig/lxdialog -v4l-%/scripts/kconfig/lxdialog/lxdialog: scripts_basic - $(MAKE) $(build)=scripts/kconfig/lxdialog diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.sound v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.sound --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.sound 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/Makefile.sound 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -# From sound/pci/Makefile - -snd-bt87x-objs := bt87x.o -obj-$(CONFIG_SND_BT87X) += snd-bt87x.o - -# From sound/i2c/other/Makefile -snd-tea575x-tuner-objs := tea575x-tuner.o -obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o - -KDIRA := /lib/modules/$(KERNELRELEASE)/kernel - - -sound-install install-sound:: - @dir="sound/pci"; \ - files='snd-bt87x.ko'; \ - echo -e "\nInstalling $(KDIRA)/$$dir files:"; \ - install -d $(KDIRA)/$$dir; \ - for i in $$files;do if [ -e $$i ]; then echo -n "$$i "; \ - install -m 644 -c $$i $(KDIRA)/$$dir; fi; done; echo; - - @dir="sound/i2c/other"; \ - files='snd-tea575x-tuner.ko'; \ - echo -e "\nInstalling $(KDIRA)/$$dir files:"; \ - install -d $(KDIRA)/$$dir; \ - for i in $$files;do if [ -e $$i ]; then echo -n "$$i "; \ - install -m 644 -c $$i $(KDIRA)/$$dir; fi; done; echo; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/obsolete.txt v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/obsolete.txt --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/obsolete.txt 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/obsolete.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -# This file was renamed to v4l2_compat_ioctl32 -video/compat-ioctl32 - -# This file were replaced by videobuf-dma-sg and videobuf-core -video/video-buf - -# This file were replaced by videobuf-dvb -video/video-buf-dvb - -#This driver has been reworked and moved to dvb-usb -dvb/cinergyT2/cinergyT2 - -# Those drivers were moved to common/tuners -dvb/frontends/mt2060 -dvb/frontends/mt2131 -dvb/frontends/mt2266 -dvb/frontends/qt1010 -dvb/frontends/tda18271 -dvb/frontends/tda827x -dvb/frontends/xc5000 -video/mt20xx -video/tda8290 -video/tda9887 -video/tea5761 -video/tea5767 -video/tuner-simple -video/tuner-types -video/tuner-xc2028 - -# This were moved to IR/ -common/ir-common - -# Those were moved from IR/ into rc/ - -IR/keymaps/rc-adstech-dvb-t-pci -IR/keymaps/rc-winfast-usbii-deluxe -IR/keymaps/rc-winfast -IR/keymaps/rc-kaiomy -IR/keymaps/rc-asus-pc39 -IR/keymaps/rc-ati-tv-wonder-hd-600 -IR/keymaps/rc-avermedia-a16d -IR/keymaps/rc-pinnacle-pctv-hd -IR/keymaps/rc-digitalnow-tinytwin -IR/keymaps/rc-avermedia-rm-ks -IR/keymaps/rc-pixelview-mk12 -IR/keymaps/rc-avermedia-m135a -IR/keymaps/rc-azurewave-ad-tu700 -IR/keymaps/rc-avermedia-m733a-rm-k6 -IR/keymaps/rc-total-media-in-hand -IR/keymaps/rc-avertv-303 -IR/keymaps/rc-rc6-mce -IR/keymaps/rc-avermedia-cardbus -IR/keymaps/rc-behold -IR/keymaps/rc-pinnacle-color -IR/keymaps/rc-budget-ci-old -IR/keymaps/rc-cinergy-1400 -IR/keymaps/rc-leadtek-y04g0051 -IR/keymaps/rc-cinergy -IR/keymaps/rc-manli -IR/keymaps/rc-twinhan1027 -IR/keymaps/rc-dib0700-rc5 -IR/keymaps/rc-dm1105-nec -IR/keymaps/rc-real-audio-220-32-keys -IR/keymaps/rc-streamzap -IR/keymaps/rc-dntv-live-dvbt-pro -IR/keymaps/rc-gadmei-rm008z -IR/keymaps/rc-tbs-nec -IR/keymaps/rc-encore-enltv-fm53 -IR/keymaps/rc-msi-digivox-ii -IR/keymaps/rc-encore-enltv -IR/keymaps/rc-encore-enltv2 -IR/keymaps/rc-evga-indtube -IR/keymaps/rc-alink-dtu-m -IR/keymaps/rc-eztv -IR/keymaps/rc-lme2510 -IR/keymaps/rc-npgtech -IR/keymaps/rc-flydvb -IR/keymaps/rc-pinnacle-grey -IR/keymaps/rc-flyvideo -IR/keymaps/rc-fusionhdtv-mce -IR/keymaps/rc-dntv-live-dvb-t -IR/keymaps/rc-terratec-cinergy-xs -IR/keymaps/rc-genius-tvgo-a11mce -IR/keymaps/rc-gotview7135 -IR/keymaps/rc-hauppauge-new -IR/keymaps/rc-pctv-sedna -IR/keymaps/rc-imon-mce -IR/keymaps/rc-em-terratec -IR/keymaps/rc-trekstor -IR/keymaps/rc-imon-pad -IR/keymaps/rc-iodata-bctv7e -IR/keymaps/rc-avermedia -IR/keymaps/rc-dib0700-nec -IR/keymaps/rc-kworld-315u -IR/keymaps/rc-terratec-slim -IR/keymaps/rc-kworld-plus-tv-analog -IR/keymaps/rc-pixelview-new -IR/keymaps/rc-tt-1500 -IR/keymaps/rc-videomate-tv-pvr -IR/keymaps/rc-msi-tvanywhere-plus -IR/keymaps/rc-msi-tvanywhere -IR/keymaps/rc-digittrade -IR/keymaps/rc-nebula -IR/keymaps/rc-tevii-nec -IR/keymaps/rc-nec-terratec-cinergy-xs -IR/keymaps/rc-norwood -IR/keymaps/rc-rc5-tv -IR/keymaps/rc-apac-viewcomp -IR/keymaps/rc-pixelview -IR/keymaps/rc-anysee -IR/keymaps/rc-videomate-s350 -IR/keymaps/rc-powercolor-real-angel -IR/keymaps/rc-behold-columbus -IR/keymaps/rc-proteus-2309 -IR/keymaps/rc-avermedia-dvbt -IR/keymaps/rc-purpletv -IR/keymaps/rc-pv951 -IR/keymaps/rc-lirc -IR/keymaps/rc-rc5-hauppauge-new -IR/keymaps/rc-msi-digivox-iii -IR/lirc_dev -IR/ir-rc6-decoder -IR/ir-sony-decoder -IR/ir-jvc-decoder -IR/ene_ir -IR/nuvoton-cir -IR/mceusb -IR/ir-core -IR/streamzap -IR/ir-common -IR/ir-nec-decoder -IR/ir-rc5-sz-decoder -IR/imon -IR/ir-lirc-codec -IR/ir-rc5-decoder diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/analyze_build.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/analyze_build.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/analyze_build.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/analyze_build.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,185 +0,0 @@ -#!/usr/bin/perl - -# Copyright (C) 2006 Trent Piepho -# Scans a tree of Linux Kernel style Makefiles, and builds lists of what -# builds what. -# Outputs three lists: -# 1. Kconfig variables associated with the kernel module(s) they turn on -# 2. Kernel modules associated with their source file(s) -# 3. Kconfig variables associated with all the source file(s) they turn on -# -# Optional options: -# Prefix relative to source tree root to start scanning in. This -# will be stripped from the beginnings of all filenames printed out. -# Default is 'linux/drivers/media' -# Root of source tree -# Default is to use 'hg root' command and if that fails the cwd -# -# Most usefull with grep, for example -# List of modules and source files used by DVB_BUDGET_AV -# deps.pl | grep DVB_BUDGET_AV -# -# Kconfig variable and kernel module that use dvb-usb-init.c -# deps.pl | grep dvb-usb-init.c -# -# Kconfig variable and source files that make dvb-core.ko -# deps.pl | grep dvb-core.ko -# -# Also has some ability to check Makefiles for errors -use strict; -use FileHandle; - -# Print out some extra checks of Makefile correctness -my $check = 0; - -# Directory to start in. Will be stripped from all filenames printed out. -my $prefix = 'linux/drivers/media/'; - -# Root of source tree -my $root; - -# List of Makefile's opened -my %makefiles = (); - -# For each Kconfig variable, a list of modules it builds -my %config = (); - -# For each module that is made up of multiple source files, list of sources -my %multi = (); - -sub open_makefile($) { - my $file = shift; - - # only open a given Makefile once - return if exists $makefiles{$file}; - $makefiles{$file} = 1; - - $file =~ m|^(.*)/[^/]*$|; - my $dir = $1; - -# print STDERR "opening $root$file (dir=$dir)\n"; - my $in = new FileHandle; - open $in, '<', "$root$file" or die "Unable to open Makefile '$root$file': $!"; - - while (<$in>) { - # print STDERR "Line: $_"; - # Skip comment and blank lines - next if (/^\s*(#.*)?$/); - m/^\s*\-?include/ and die "Can't handle includes! In $file"; - - # Handle line continuations - if (/\\\n$/) { - $_ .= <$in>; - redo; - } - # Eat line continuations in string we will parse - s/\s*\\\n\s*/ /g; - # Eat comments - s/#.*$//; - - if (/^\s*obj-(\S+)\s*([:+]?)=\s*(\S.*?)\s*$/) { - print STDERR "Should use '+=' in $file:$.\n$_\n" if ($check && $2 ne '+'); - my ($var,$targets) = ($1, $3); - if ($var =~ /\$\(CONFIG_(\S+)\)$/) { - $var = $1; - } elsif ($var !~ /^[ym]$/) { - print STDERR "Confused by obj assignment '$var' in $file:$.\n$_"; - } - foreach(split(/\s+/, $targets)) { - if (m|/$|) { # Ends in /, means it's a directory - open_makefile("$dir/$_".'Makefile'); - } elsif (/^(\S+)\.o$/) { - push @{$config{$var}}, "$dir/$1"; - } else { - print STDERR "Confused by target '$_' in $file:$.\n"; - } - } - next; - } - if (/(\S+)-objs\s*([:+]?)=\s*(\S.*?)\s*$/) { - my @files = split(/\s+/, $3); - map { s|^(.*)\.o$|$dir/\1| } @files; - if ($2 eq '+') { - # Adding to files - print STDERR "Should use ':=' in $file:$.\n$_\n" if ($check && !exists $multi{"$dir/$1"}); - push @files, @{$multi{"$dir/$1"}}; - } else { - print STDERR "Setting objects twice in $file:$.\n$_\n" if ($check && exists $multi{"$dir/$1"}); - } - $multi{"$dir/$1"} = \@files; - next; - } - if (/^\s*EXTRA_CFLAGS\s*([:+]?)=\s*(\S.*?)\s*$/) { - if ($check) { - sub allI { /^-I/ or return 0 foreach split(/\s+/, $_[0]);return 1; } - my $use = allI($2) ? ':' : '+'; - print STDERR "Should use '$use=' with EXTRA_CFLAGS in $file:$.\n$_\n" - if ($1 ne $use); - } - next; - } - print STDERR "Odd line $file:$.\n$_\n" if ($check); - } -} - -if ($#ARGV >= 0) { - $prefix = $ARGV[0]; - $prefix .= '/' unless ($prefix =~ m|/$|); -} - -# Find root of source tree: command line, then Hg command, lastly cwd -if ($#ARGV >= 1) { - $root = $ARGV[1]; - $root .= '/' unless ($root =~ m|/$|); -} else { - $root = `hg root 2>/dev/null`; - if($? == 0) { - chomp $root; - $root .= '/'; - } else { - $root = ''; - } -} -print "# Using source tree root '$root'\n" if ($root ne ''); - -open_makefile($prefix."Makefile"); - -print "# Kconfig variable = kernel modules built\n"; -foreach my $var (keys %config) { - my @list = @{$config{$var}}; - map { s/^$prefix(.*)$/\1.ko/ } @list; - printf "%-22s= %s\n", $var, join(' ', @list); -} - -print "\n# kernel module = source files\n"; -my %modules = (); -foreach my $mods (values %config) { - $modules{$_} = 1 foreach @$mods; -} -foreach (keys %modules) { - /$prefix(.*)$/; - printf "%-30s = ", "$1.ko"; - if (exists $multi{$_}) { - my @list = @{$multi{$_}}; - map { s/^$prefix(.*)$/\1.c/ } @list; - print join(' ', @list), "\n"; - } else { - print "$1.c\n"; - } -} - -print "\n# Kconfig varible = source files\n"; -while (my ($var, $list) = each %config) { - my @outlist = (); - foreach (@$list) { - if (exists $multi{$_}) { - push @outlist, @{$multi{$_}}; - } else { - push @outlist, $_; - } - } - map { s/^$prefix(.*)$/\1.c/ } @outlist; - printf "%-22s= %s\n", $var, join(' ', @outlist); -} - -exit; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/au0828.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/au0828.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/au0828.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/au0828.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my $new_entry = -1; -my $nr = 0; -my ($id,$subvendor,$subdevice); -my %data; - -while (<>) { - # defines in header file - if (/#define\s+(AU08[\d]._BOARD_\w+)\s+(\d+)/) { - $data{$1}->{nr} = $2; - next; - } - # au0828_boards - if (/\[(AU0828_BOARD_\w+)\]/) { - $id = $1; - $data{$id}->{id} = $id; - $data{$id}->{type} = "(au0828)"; -# $data{$id}->{nr} = $nr++; - }; - - next unless defined($id); - - if (/USB_DEVICE.*0x([0-9a-fA-F]*).*0x([0-9a-fA-F]*)/ ) { - $subvendor=$1; - $subdevice=$2; - } - - if (/.*driver_info.*(AU08[\d]._BOARD_\w+)/ ) { - push @{$data{$1}->{subid}}, "$subvendor:$subdevice"; - } - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - } - - # au0828_USB_tbl - - -} - -foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) { - printf("%3d -> %-40s %-15s", $data{$item}->{nr}, $data{$item}->{name},$data{$item}->{type}); - printf(" [%s]",join(",",@{$data{$item}->{subid}})) - if defined($data{$item}->{subid}); - print "\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/bttv.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/bttv.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/bttv.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/bttv.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my $new_entry = -1; -my $nr = 0; -my ($id,$subvendor,$subdevice); -my %data; -my $pciid=0; - -while (<>) { - # defines in header file - if (/#define\s+(BTTV_BOARD_\w+)\s+0x([0-9a-fA-F]*).*/) { - $data{$1}->{nr} = hex $2; - - next; - } - # cx88_boards - if (/\[(BTTV_BOARD_\w+)\]/) { - $id = $1; - $data{$id}->{id} = $id; -# $data{$id}->{nr} = $nr++; - }; - if (/0x([0-9a-fA-F]...)([0-9a-fA-F]...)/) { - $subvendor = $2; - $subdevice = $1; - if (/(BTTV_BOARD_\w+)/) { - push @{$data{$1}->{subid}}, "$subvendor:$subdevice"; - undef $subvendor; - undef $subdevice; - } - } - - next unless defined($id); - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - } - - if (/0x([0-9]...)([0-9]...)/) { - $subvendor = $1; - $subdevice = $2; - } - -} - -foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) { - printf("%3d -> %-51s", $data{$item}->{nr}, $data{$item}->{name}); - printf(" [%s]",join(",",@{$data{$item}->{subid}})) - if defined($data{$item}->{subid}); - print "\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cardlist v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cardlist --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cardlist 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cardlist 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -#!/bin/sh - -scripts/bttv.pl ../linux/drivers/media/video/bt8xx/bttv.h ../linux/drivers/media/video/bt8xx/bttv-cards.c \ - | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.bttv - -scripts/cx88.pl ../linux/drivers/media/video/cx88/cx88.h ../linux/drivers/media/video/cx88/cx88-cards.c \ - | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.cx88 - -scripts/em28xx.pl ../linux/drivers/media/video/em28xx/em28xx-cards.c ../linux/drivers/media/video/em28xx/em28xx.h \ - | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.em28xx - -scripts/tuner.pl ../linux/include/media/tuner.h ../linux/drivers/media/common/tuners/tuner-types.c \ - | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.tuner - -scripts/saa7134.pl ../linux/drivers/media/video/saa7134/saa7134.h ../linux/drivers/media/video/saa7134/saa7134-cards.c \ - | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.saa7134 - -scripts/usbvision.pl ../linux/drivers/media/video/usbvision/usbvision-cards.h ../linux/drivers/media/video/usbvision/usbvision-cards.c \ - | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.usbvision - -scripts/cx23885.pl ../linux/drivers/media/video/cx23885/cx23885.h ../linux/drivers/media/video/cx23885/cx23885-cards.c \ - | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.cx23885 - -scripts/au0828.pl ../linux/drivers/media/video/au0828/au0828-cards.h ../linux/drivers/media/video/au0828/au0828-cards.c \ - | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.au0828 - -scripts/saa7164.pl ../linux/drivers/media/video/saa7164/saa7164.h ../linux/drivers/media/video/saa7164/saa7164-cards.c \ - | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.saa7164 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/changelog.tmpl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/changelog.tmpl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/changelog.tmpl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/changelog.tmpl 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -User #author# -Date #date|date# -#desc# - ---- diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/check_config_defines.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/check_config_defines.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/check_config_defines.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/check_config_defines.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -#!/usr/bin/perl -# Copyright (C) 2006 Trent Piepho -# -# Look for lines in C files like "#ifdef CONFIG_SOME_KCONF_VAR" and make -# sure CONFIG_SOME_KCONF_VAR is something that exists. - -use strict; - -if($#ARGV < 0) { - print "Usage: $0 kernel_dir [files to check ...]\n\n"; - print "If no files are listed, checks all files from hg manifest\n"; - exit; -} -my $kdir = shift; - -if($#ARGV < 0) { - @ARGV = `hg manifest | cut "-d " -f3 | grep \\.[ch]\$`; - $? != 0 and die "Error getting manifest: $!"; - chomp @ARGV; -} - -my %kconfigs; # List of Kconfig files read in already -my %vars; # List of defined variables -sub readkconfig($$) -{ - my $fn = "$_[0]/$_[1]"; - # Don't read the same kconfig file more than once. This also means - # the drivers/media/Kconfig file from kernel won't be read in addition - # to the one from v4l-dvb. - return if exists $kconfigs{$_[1]}; - $kconfigs{$_[1]} = 1; -# print "Reading $fn\n"; - my $fh; - open $fh, '<', "$fn" or die "Can't read Kconfig file $fn: $!"; - while(<$fh>) { - if (/^\s*source\s+"([^"]+)"\s*$/ || /^\s*source\s+(\S+)\s*$/) { - readkconfig($_[0], $1); - } elsif(/^(?:menu)?config\s+(\w+)$/) { - $vars{"CONFIG_$1"}=1; - } - } - close $fh; -} - -readkconfig('linux', 'drivers/media/Kconfig'); -foreach(glob "$kdir/arch/*/Kconfig") { - s|^\Q$kdir/\E||; - next if(m|arch/um/Kconfig|); - readkconfig($kdir, $_); -} - -while(<>) { - if(/^\s*#ifn?def\s+(CONFIG_\w+?)(:?_MODULE)?\W*$/) { -# print "Found $1\n"; - print "Unknown config $1 in $ARGV:$.\n" unless(exists $vars{$1}); - next; - } - if(/^\s*#if/) { - $_ .= <> while(/\\$/); # Handle line continuations - my $last; - while(/defined\(\s*(CONFIG_\w+?)(_MODULE)?\s*\)/) { - $_ = $'; - next if($last eq $1); - $last = $1; - print "Unknown config $1 in $ARGV:$.\n" unless(exists $vars{$1}); - } - } -} continue { - close ARGV if eof; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/check_deps.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/check_deps.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/check_deps.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/check_deps.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,228 +0,0 @@ -#!/usr/bin/perl - -# Copyright (C) 2008 Mauro Carvalho Chehab - - -use strict; -use File::Find; -use Fcntl ':mode'; -use FileHandle; - -my $debug=0; - -my $SRC = 'linux'; - -my %export; - -############# -# open_makefile were adapted from analyze_build.pl -# by Copyright (C) 2006 Trent Piepho - -# Print out some extra checks of Makefile correctness -my $check = 0; - -# Root of source tree -my $root; - -# List of Makefile's opened -my %makefiles = (); - -# For each module that is made up of multiple source files, list of sources -my %multi = (); -my $multi_count = 0; - -my %config; - -my %associate; - -sub open_makefile($) { - my $file = shift; - - # only open a given Makefile once - return if exists $makefiles{$file}; - $makefiles{$file} = 1; - - $file =~ m|^(.*)/[^/]*$|; - my $dir = $1; - - print "opening $root$file (dir=$dir)\n" if ($debug > 2); - my $in = new FileHandle; - open $in, '<', "$root$file" or die "Unable to open Makefile '$root$file': $!"; - - while (<$in>) { - # print STDERR "Line: $_"; - # Skip comment and blank lines - next if (/^\s*(#.*)?$/); - m/^\s*\-?include/ and die "Can't handle includes! In $file"; - - # Handle line continuations - if (/\\\n$/) { - $_ .= <$in>; - redo; - } - # Eat line continuations in string we will parse - s/\s*\\\n\s*/ /g; - # Eat comments - s/#.*$//; - - if (/^\s*obj-(\S+)\s*([:+]?)=\s*(\S.*?)\s*$/) { - print STDERR "Should use '+=' in $file:$.\n$_\n" if ($check && $2 ne '+'); - my ($var,$targets) = ($1, $3); - if ($var =~ /\$\(CONFIG_(\S+)\)$/) { - $var = $1; - } elsif ($var !~ /^[ym]$/) { - print STDERR "Confused by obj assignment '$var' in $file:$.\n$_"; - } - foreach(split(/\s+/, $targets)) { - if (m|/$|) { # Ends in /, means it's a directory - open_makefile("$dir/$_".'Makefile'); - } elsif (/^(\S+)\.o$/) { - $config{"$dir/$1"} = $var; -# printf "%s -> %s\n", $var, $1 if $debug > 1; - } else { - print STDERR "Confused by target '$_' in $file:$.\n"; - } - } - next; - } - if (/(\S+)-objs\s*([:+]?)=\s*(\S.*?)\s*$/) { - my @files = split(/\s+/, $3); - map { s|^(.*)\.o$|$dir/\1| } @files; - if ($2 eq '+') { - # Adding to files - print STDERR "Should use ':=' in $file:$.\n$_\n" if ($check && !exists $multi{"$dir/$1"}); - push @files, @{$multi{"$dir/$1"}}; - } else { - print STDERR "Setting objects twice in $file:$.\n$_\n" if ($check && exists $multi{"$dir/$1"}); - } - $multi{"$dir/$1"} = \@files; - next; - } - if (/^\s*EXTRA_CFLAGS\s*([:+]?)=\s*(\S.*?)\s*$/) { - if ($check) { - sub allI { /^-I/ or return 0 foreach split(/\s+/, $_[0]);return 1; } - my $use = allI($2) ? ':' : '+'; - print STDERR "Should use '$use=' with EXTRA_CFLAGS in $file:$.\n$_\n" - if ($1 ne $use); - } - next; - } - print STDERR "Odd line $file:$.\n$_\n" if ($check); - } - close IN; -} - -# -############# - -sub associate_multi() -{ - foreach (keys %multi) { - my $name = $_; - my @files = @{$multi{$_}}; - map { s/^(.*)$/\1.c/ } @files; - - foreach (@files) { - my $file = $_; - my $var = $config{$name}; - $associate{$file} = $var; - printf "$var -> $file\n" if $debug > 1; - } - delete $config{$name}; - } - foreach my $file (keys %config) { - my $var = $config{$file}; - $file .= ".c"; - $associate{$file} = $var; - printf "$var -> $file\n" if $debug > 1; - } -} - -sub build_exported_symbol_list { - my $file = $File::Find::name; - - return if (!($file =~ /\.c$/)); - - open IN, $file; - while () { - if (m/EXPORT_SYMBOL.*\(\s*([^\s\)]+)/) { - $export{$1} = $file; - printf "%s -> %s\n", $file , $1 if $debug > 1; - } - } - close IN; -} - - -sub find_usage_list { - my %depend; - my $file = $File::Find::name; - my $s; - - return if (!($file =~ /\.c$/)); - - open IN, $file; - printf "Checking symbols at $file\n" if $debug; - while () { - foreach my $symbol (keys %export) { - my $symb_file = $export{$symbol}; - - # Doesn't search the symbol at the file that defines it - next if ($symb_file eq $file); - - if (m/($symbol)/) { - my $var = $associate{$symb_file}; - if (!$depend{$var}) { - printf "$symbol found at $file. It depends on %s\n", $associate{$symb_file} if $debug; - $depend{$var} = 1; - } - } - } - } - close IN; - - foreach (%depend) { $s .= "$_ && "; }; - $s =~ s/\&\&\ $//; - if ($s ne "") { - print $associate{$file}." depends on $s\n"; - } -} - -print < -This code is licenced under the terms of GPLv2. - -This script seeks all .c files under linux/ for their exported symbols. For -each exported symbol, it will check what Kconfig symbol is associated. Then, it -will cross-check that symbol usage and output a Kconfig depencency table. - -WARNING: The result of this tool should be used just as a hint, since, due to -performance issues, and to simplify the tool, the checks will use a simple grep -for the symbol string at the .c files, instead of a real symbol cross-check. - -Also, the same symbol may appear twice with different dependencies. This is due -to the way it checks for symbols. The final dependency is the union (AND) of -all showed ones for that symbol. - -Further patches improving this tool are welcome. - -EOL - -print "Checking makefile rules..." if $debug; -open_makefile("$SRC/drivers/media/Makefile"); -print " ok\n" if $debug; - -print "Associating symbols with c files..." if $debug; -associate_multi(); -print " ok\n" if $debug; - -print "finding exported symbols at $SRC..." if $debug; -find({wanted => \&build_exported_symbol_list, no_chdir => 1}, $SRC); -print " ok\n" if $debug; - -print "finding usage of symbols at $SRC\n" if $debug; -find({wanted => \&find_usage_list, no_chdir => 1}, $SRC); -print "finished\n" if $debug; - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/checkpatch.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/checkpatch.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/checkpatch.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/checkpatch.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,2721 +0,0 @@ -#!/usr/bin/perl -w -# (c) 2001, Dave Jones. (the file handling bit) -# (c) 2005, Joel Schopp (the ugly bit) -# (c) 2007,2008, Andy Whitcroft (new conditions, test suite) -# (c) 2008,2009, Andy Whitcroft -# Licensed under the terms of the GNU GPL License version 2 - -use strict; - -my $P = $0; -$P =~ s@.*/@@g; - -my $V = '0.30'; - -use Getopt::Long qw(:config no_auto_abbrev); - -my $quiet = 0; -my $tree = 1; -my $chk_signoff = 1; -my $chk_patch = 1; -my $tst_only; -my $emacs = 0; -my $terse = 0; -my $file = 0; -my $check = 0; -my $summary = 1; -my $mailback = 0; -my $summary_file = 0; -my $root; -my %debug; -my $help = 0; - -sub help { - my ($exitcode) = @_; - - print << "EOM"; -Usage: $P [OPTION]... [FILE]... -Version: $V - -Options: - -q, --quiet quiet - --no-tree run without a kernel tree - --no-signoff do not check for 'Signed-off-by' line - --patch treat FILE as patchfile (default) - --emacs emacs compile window format - --terse one line per report - -f, --file treat FILE as regular source file - --subjective, --strict enable more subjective tests - --root=PATH PATH to the kernel tree root - --no-summary suppress the per-file summary - --mailback only produce a report in case of warnings/errors - --summary-file include the filename in summary - --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of - 'values', 'possible', 'type', and 'attr' (default - is all off) - --test-only=WORD report only warnings/errors containing WORD - literally - -h, --help, --version display this help and exit - -When FILE is - read standard input. -EOM - - exit($exitcode); -} - -GetOptions( - 'q|quiet+' => \$quiet, - 'tree!' => \$tree, - 'signoff!' => \$chk_signoff, - 'patch!' => \$chk_patch, - 'emacs!' => \$emacs, - 'terse!' => \$terse, - 'f|file!' => \$file, - 'subjective!' => \$check, - 'strict!' => \$check, - 'root=s' => \$root, - 'summary!' => \$summary, - 'mailback!' => \$mailback, - 'summary-file!' => \$summary_file, - - 'debug=s' => \%debug, - 'test-only=s' => \$tst_only, - 'h|help' => \$help, - 'version' => \$help -) or help(1); - -help(0) if ($help); - -my $exit = 0; - -if ($#ARGV < 0) { - print "$P: no input files\n"; - exit(1); -} - -my $dbg_values = 0; -my $dbg_possible = 0; -my $dbg_type = 0; -my $dbg_attr = 0; -for my $key (keys %debug) { - ## no critic - eval "\${dbg_$key} = '$debug{$key}';"; - die "$@" if ($@); -} - -if ($terse) { - $emacs = 1; - $quiet++; -} - -if ($tree) { - if (defined $root) { - if (!top_of_kernel_tree($root)) { - die "$P: $root: --root does not point at a valid tree\n"; - } - } else { - if (top_of_kernel_tree('.')) { - $root = '.'; - } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ && - top_of_kernel_tree($1)) { - $root = $1; - } - } - - if (!defined $root) { - print "Must be run from the top-level dir. of a kernel tree\n"; - exit(2); - } -} - -my $emitted_corrupt = 0; - -our $Ident = qr{ - [A-Za-z_][A-Za-z\d_]* - (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)* - }x; -our $Storage = qr{extern|static|asmlinkage}; -our $Sparse = qr{ - __user| - __kernel| - __force| - __iomem| - __must_check| - __init_refok| - __kprobes| - __ref - }x; -our $Attribute = qr{ - const| - __read_mostly| - __kprobes| - __(?:mem|cpu|dev|)(?:initdata|init)| - ____cacheline_aligned| - ____cacheline_aligned_in_smp| - ____cacheline_internodealigned_in_smp| - __weak - }x; -our $Modifier; -our $Inline = qr{inline|__always_inline|noinline}; -our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; -our $Lval = qr{$Ident(?:$Member)*}; - -our $Constant = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*}; -our $Assignment = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)}; -our $Compare = qr{<=|>=|==|!=|<|>}; -our $Operators = qr{ - <=|>=|==|!=| - =>|->|<<|>>|<|>|!|~| - &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|% - }x; - -our $NonptrType; -our $Type; -our $Declare; - -our $UTF8 = qr { - [\x09\x0A\x0D\x20-\x7E] # ASCII - | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte - | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs - | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte - | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates - | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 - | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 - | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 -}x; - -our $typeTypedefs = qr{(?x: - (?:__)?(?:u|s|be|le)(?:8|16|32|64)| - atomic_t -)}; - -our @typeList = ( - qr{void}, - qr{(?:unsigned\s+)?char}, - qr{(?:unsigned\s+)?short}, - qr{(?:unsigned\s+)?int}, - qr{(?:unsigned\s+)?long}, - qr{(?:unsigned\s+)?long\s+int}, - qr{(?:unsigned\s+)?long\s+long}, - qr{(?:unsigned\s+)?long\s+long\s+int}, - qr{unsigned}, - qr{float}, - qr{double}, - qr{bool}, - qr{struct\s+$Ident}, - qr{union\s+$Ident}, - qr{enum\s+$Ident}, - qr{${Ident}_t}, - qr{${Ident}_handler}, - qr{${Ident}_handler_fn}, -); -our @modifierList = ( - qr{fastcall}, -); - -sub build_types { - my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)"; - my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)"; - $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; - $NonptrType = qr{ - (?:$Modifier\s+|const\s+)* - (?: - (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)| - (?:$typeTypedefs\b)| - (?:${all}\b) - ) - (?:\s+$Modifier|\s+const)* - }x; - $Type = qr{ - $NonptrType - (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)? - (?:\s+$Inline|\s+$Modifier)* - }x; - $Declare = qr{(?:$Storage\s+)?$Type}; -} -build_types(); - -$chk_signoff = 0 if ($file); - -my @dep_includes = (); -my @dep_functions = (); -my $removal = "Documentation/feature-removal-schedule.txt"; -if ($tree && -f "$root/$removal") { - open(my $REMOVE, '<', "$root/$removal") || - die "$P: $removal: open failed - $!\n"; - while (<$REMOVE>) { - if (/^Check:\s+(.*\S)/) { - for my $entry (split(/[, ]+/, $1)) { - if ($entry =~ m@include/(.*)@) { - push(@dep_includes, $1); - - } elsif ($entry !~ m@/@) { - push(@dep_functions, $entry); - } - } - } - } - close($REMOVE); -} - -my @rawlines = (); -my @lines = (); -my $vname; -for my $filename (@ARGV) { - my $FILE; - if ($file) { - open($FILE, '-|', "diff -u /dev/null $filename") || - die "$P: $filename: diff failed - $!\n"; - } elsif ($filename eq '-') { - open($FILE, '<&STDIN'); - } else { - open($FILE, '<', "$filename") || - die "$P: $filename: open failed - $!\n"; - } - if ($filename eq '-') { - $vname = 'Your patch'; - } else { - $vname = $filename; - } - while (<$FILE>) { - chomp; - push(@rawlines, $_); - } - close($FILE); - if (!process($filename)) { - $exit = 1; - } - @rawlines = (); - @lines = (); -} - -exit($exit); - -sub top_of_kernel_tree { - my ($root) = @_; - - my @tree_check = ( - "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile", - "README", "Documentation", "arch", "include", "drivers", - "fs", "init", "ipc", "kernel", "lib", "scripts", - ); - - foreach my $check (@tree_check) { - if (! -e $root . '/' . $check) { - return 0; - } - } - return 1; -} - -sub expand_tabs { - my ($str) = @_; - - my $res = ''; - my $n = 0; - for my $c (split(//, $str)) { - if ($c eq "\t") { - $res .= ' '; - $n++; - for (; ($n % 8) != 0; $n++) { - $res .= ' '; - } - next; - } - $res .= $c; - $n++; - } - - return $res; -} -sub copy_spacing { - (my $res = shift) =~ tr/\t/ /c; - return $res; -} - -sub line_stats { - my ($line) = @_; - - # Drop the diff line leader and expand tabs - $line =~ s/^.//; - $line = expand_tabs($line); - - # Pick the indent from the front of the line. - my ($white) = ($line =~ /^(\s*)/); - - return (length($line), length($white)); -} - -my $sanitise_quote = ''; - -sub sanitise_line_reset { - my ($in_comment) = @_; - - if ($in_comment) { - $sanitise_quote = '*/'; - } else { - $sanitise_quote = ''; - } -} -sub sanitise_line { - my ($line) = @_; - - my $res = ''; - my $l = ''; - - my $qlen = 0; - my $off = 0; - my $c; - - # Always copy over the diff marker. - $res = substr($line, 0, 1); - - for ($off = 1; $off < length($line); $off++) { - $c = substr($line, $off, 1); - - # Comments we are wacking completly including the begin - # and end, all to $;. - if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { - $sanitise_quote = '*/'; - - substr($res, $off, 2, "$;$;"); - $off++; - next; - } - if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { - $sanitise_quote = ''; - substr($res, $off, 2, "$;$;"); - $off++; - next; - } - if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') { - $sanitise_quote = '//'; - - substr($res, $off, 2, $sanitise_quote); - $off++; - next; - } - - # A \ in a string means ignore the next character. - if (($sanitise_quote eq "'" || $sanitise_quote eq '"') && - $c eq "\\") { - substr($res, $off, 2, 'XX'); - $off++; - next; - } - # Regular quotes. - if ($c eq "'" || $c eq '"') { - if ($sanitise_quote eq '') { - $sanitise_quote = $c; - - substr($res, $off, 1, $c); - next; - } elsif ($sanitise_quote eq $c) { - $sanitise_quote = ''; - } - } - - #print "c<$c> SQ<$sanitise_quote>\n"; - if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") { - substr($res, $off, 1, $;); - } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") { - substr($res, $off, 1, $;); - } elsif ($off != 0 && $sanitise_quote && $c ne "\t") { - substr($res, $off, 1, 'X'); - } else { - substr($res, $off, 1, $c); - } - } - - if ($sanitise_quote eq '//') { - $sanitise_quote = ''; - } - - # The pathname on a #include may be surrounded by '<' and '>'. - if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) { - my $clean = 'X' x length($1); - $res =~ s@\<.*\>@<$clean>@; - - # The whole of a #error is a string. - } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) { - my $clean = 'X' x length($1); - $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; - } - - return $res; -} - -sub ctx_statement_block { - my ($linenr, $remain, $off) = @_; - my $line = $linenr - 1; - my $blk = ''; - my $soff = $off; - my $coff = $off - 1; - my $coff_set = 0; - - my $loff = 0; - - my $type = ''; - my $level = 0; - my @stack = (); - my $p; - my $c; - my $len = 0; - - my $remainder; - while (1) { - @stack = (['', 0]) if ($#stack == -1); - - #warn "CSB: blk<$blk> remain<$remain>\n"; - # If we are about to drop off the end, pull in more - # context. - if ($off >= $len) { - for (; $remain > 0; $line++) { - last if (!defined $lines[$line]); - next if ($lines[$line] =~ /^-/); - $remain--; - $loff = $len; - $blk .= $lines[$line] . "\n"; - $len = length($blk); - $line++; - last; - } - # Bail if there is no further context. - #warn "CSB: blk<$blk> off<$off> len<$len>\n"; - if ($off >= $len) { - last; - } - } - $p = $c; - $c = substr($blk, $off, 1); - $remainder = substr($blk, $off); - - #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n"; - - # Handle nested #if/#else. - if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { - push(@stack, [ $type, $level ]); - } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { - ($type, $level) = @{$stack[$#stack - 1]}; - } elsif ($remainder =~ /^#\s*endif\b/) { - ($type, $level) = @{pop(@stack)}; - } - - # Statement ends at the ';' or a close '}' at the - # outermost level. - if ($level == 0 && $c eq ';') { - last; - } - - # An else is really a conditional as long as its not else if - if ($level == 0 && $coff_set == 0 && - (!defined($p) || $p =~ /(?:\s|\}|\+)/) && - $remainder =~ /^(else)(?:\s|{)/ && - $remainder !~ /^else\s+if\b/) { - $coff = $off + length($1) - 1; - $coff_set = 1; - #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n"; - #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n"; - } - - if (($type eq '' || $type eq '(') && $c eq '(') { - $level++; - $type = '('; - } - if ($type eq '(' && $c eq ')') { - $level--; - $type = ($level != 0)? '(' : ''; - - if ($level == 0 && $coff < $soff) { - $coff = $off; - $coff_set = 1; - #warn "CSB: mark coff<$coff>\n"; - } - } - if (($type eq '' || $type eq '{') && $c eq '{') { - $level++; - $type = '{'; - } - if ($type eq '{' && $c eq '}') { - $level--; - $type = ($level != 0)? '{' : ''; - - if ($level == 0) { - last; - } - } - $off++; - } - # We are truly at the end, so shuffle to the next line. - if ($off == $len) { - $loff = $len + 1; - $line++; - $remain--; - } - - my $statement = substr($blk, $soff, $off - $soff + 1); - my $condition = substr($blk, $soff, $coff - $soff + 1); - - #warn "STATEMENT<$statement>\n"; - #warn "CONDITION<$condition>\n"; - - #print "coff<$coff> soff<$off> loff<$loff>\n"; - - return ($statement, $condition, - $line, $remain + 1, $off - $loff + 1, $level); -} - -sub statement_lines { - my ($stmt) = @_; - - # Strip the diff line prefixes and rip blank lines at start and end. - $stmt =~ s/(^|\n)./$1/g; - $stmt =~ s/^\s*//; - $stmt =~ s/\s*$//; - - my @stmt_lines = ($stmt =~ /\n/g); - - return $#stmt_lines + 2; -} - -sub statement_rawlines { - my ($stmt) = @_; - - my @stmt_lines = ($stmt =~ /\n/g); - - return $#stmt_lines + 2; -} - -sub statement_block_size { - my ($stmt) = @_; - - $stmt =~ s/(^|\n)./$1/g; - $stmt =~ s/^\s*{//; - $stmt =~ s/}\s*$//; - $stmt =~ s/^\s*//; - $stmt =~ s/\s*$//; - - my @stmt_lines = ($stmt =~ /\n/g); - my @stmt_statements = ($stmt =~ /;/g); - - my $stmt_lines = $#stmt_lines + 2; - my $stmt_statements = $#stmt_statements + 1; - - if ($stmt_lines > $stmt_statements) { - return $stmt_lines; - } else { - return $stmt_statements; - } -} - -sub ctx_statement_full { - my ($linenr, $remain, $off) = @_; - my ($statement, $condition, $level); - - my (@chunks); - - # Grab the first conditional/block pair. - ($statement, $condition, $linenr, $remain, $off, $level) = - ctx_statement_block($linenr, $remain, $off); - #print "F: c<$condition> s<$statement> remain<$remain>\n"; - push(@chunks, [ $condition, $statement ]); - if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) { - return ($level, $linenr, @chunks); - } - - # Pull in the following conditional/block pairs and see if they - # could continue the statement. - for (;;) { - ($statement, $condition, $linenr, $remain, $off, $level) = - ctx_statement_block($linenr, $remain, $off); - #print "C: c<$condition> s<$statement> remain<$remain>\n"; - last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s)); - #print "C: push\n"; - push(@chunks, [ $condition, $statement ]); - } - - return ($level, $linenr, @chunks); -} - -sub ctx_block_get { - my ($linenr, $remain, $outer, $open, $close, $off) = @_; - my $line; - my $start = $linenr - 1; - my $blk = ''; - my @o; - my @c; - my @res = (); - - my $level = 0; - my @stack = ($level); - for ($line = $start; $remain > 0; $line++) { - next if ($rawlines[$line] =~ /^-/); - $remain--; - - $blk .= $rawlines[$line]; - - # Handle nested #if/#else. - if ($rawlines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { - push(@stack, $level); - } elsif ($rawlines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { - $level = $stack[$#stack - 1]; - } elsif ($rawlines[$line] =~ /^.\s*#\s*endif\b/) { - $level = pop(@stack); - } - - foreach my $c (split(//, $rawlines[$line])) { - ##print "C<$c>L<$level><$open$close>O<$off>\n"; - if ($off > 0) { - $off--; - next; - } - - if ($c eq $close && $level > 0) { - $level--; - last if ($level == 0); - } elsif ($c eq $open) { - $level++; - } - } - - if (!$outer || $level <= 1) { - push(@res, $rawlines[$line]); - } - - last if ($level == 0); - } - - return ($level, @res); -} -sub ctx_block_outer { - my ($linenr, $remain) = @_; - - my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0); - return @r; -} -sub ctx_block { - my ($linenr, $remain) = @_; - - my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0); - return @r; -} -sub ctx_statement { - my ($linenr, $remain, $off) = @_; - - my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off); - return @r; -} -sub ctx_block_level { - my ($linenr, $remain) = @_; - - return ctx_block_get($linenr, $remain, 0, '{', '}', 0); -} -sub ctx_statement_level { - my ($linenr, $remain, $off) = @_; - - return ctx_block_get($linenr, $remain, 0, '(', ')', $off); -} - -sub ctx_locate_comment { - my ($first_line, $end_line) = @_; - - # Catch a comment on the end of the line itself. - my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); - return $current_comment if (defined $current_comment); - - # Look through the context and try and figure out if there is a - # comment. - my $in_comment = 0; - $current_comment = ''; - for (my $linenr = $first_line; $linenr < $end_line; $linenr++) { - my $line = $rawlines[$linenr - 1]; - #warn " $line\n"; - if ($linenr == $first_line and $line =~ m@^.\s*\*@) { - $in_comment = 1; - } - if ($line =~ m@/\*@) { - $in_comment = 1; - } - if (!$in_comment && $current_comment ne '') { - $current_comment = ''; - } - $current_comment .= $line . "\n" if ($in_comment); - if ($line =~ m@\*/@) { - $in_comment = 0; - } - } - - chomp($current_comment); - return($current_comment); -} -sub ctx_has_comment { - my ($first_line, $end_line) = @_; - my $cmt = ctx_locate_comment($first_line, $end_line); - - ##print "LINE: $rawlines[$end_line - 1 ]\n"; - ##print "CMMT: $cmt\n"; - - return ($cmt ne ''); -} - -sub raw_line { - my ($linenr, $cnt) = @_; - - my $offset = $linenr - 1; - $cnt++; - - my $line; - while ($cnt) { - $line = $rawlines[$offset++]; - next if (defined($line) && $line =~ /^-/); - $cnt--; - } - - return $line; -} - -sub cat_vet { - my ($vet) = @_; - my ($res, $coded); - - $res = ''; - while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) { - $res .= $1; - if ($2 ne '') { - $coded = sprintf("^%c", unpack('C', $2) + 64); - $res .= $coded; - } - } - $res =~ s/$/\$/; - - return $res; -} - -my $av_preprocessor = 0; -my $av_pending; -my @av_paren_type; -my $av_pend_colon; - -sub annotate_reset { - $av_preprocessor = 0; - $av_pending = '_'; - @av_paren_type = ('E'); - $av_pend_colon = 'O'; -} - -sub annotate_values { - my ($stream, $type) = @_; - - my $res; - my $var = '_' x length($stream); - my $cur = $stream; - - print "$stream\n" if ($dbg_values > 1); - - while (length($cur)) { - @av_paren_type = ('E') if ($#av_paren_type < 0); - print " <" . join('', @av_paren_type) . - "> <$type> <$av_pending>" if ($dbg_values > 1); - if ($cur =~ /^(\s+)/o) { - print "WS($1)\n" if ($dbg_values > 1); - if ($1 =~ /\n/ && $av_preprocessor) { - $type = pop(@av_paren_type); - $av_preprocessor = 0; - } - - } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\()/) { - print "DECLARE($1)\n" if ($dbg_values > 1); - $type = 'T'; - - } elsif ($cur =~ /^($Modifier)\s*/) { - print "MODIFIER($1)\n" if ($dbg_values > 1); - $type = 'T'; - - } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) { - print "DEFINE($1,$2)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - push(@av_paren_type, $type); - if ($2 ne '') { - $av_pending = 'N'; - } - $type = 'E'; - - } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) { - print "UNDEF($1)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - push(@av_paren_type, $type); - - } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) { - print "PRE_START($1)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - - push(@av_paren_type, $type); - push(@av_paren_type, $type); - $type = 'E'; - - } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) { - print "PRE_RESTART($1)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - - push(@av_paren_type, $av_paren_type[$#av_paren_type]); - - $type = 'E'; - - } elsif ($cur =~ /^(\#\s*(?:endif))/o) { - print "PRE_END($1)\n" if ($dbg_values > 1); - - $av_preprocessor = 1; - - # Assume all arms of the conditional end as this - # one does, and continue as if the #endif was not here. - pop(@av_paren_type); - push(@av_paren_type, $type); - $type = 'E'; - - } elsif ($cur =~ /^(\\\n)/o) { - print "PRECONT($1)\n" if ($dbg_values > 1); - - } elsif ($cur =~ /^(__attribute__)\s*\(?/o) { - print "ATTR($1)\n" if ($dbg_values > 1); - $av_pending = $type; - $type = 'N'; - - } elsif ($cur =~ /^(sizeof)\s*(\()?/o) { - print "SIZEOF($1)\n" if ($dbg_values > 1); - if (defined $2) { - $av_pending = 'V'; - } - $type = 'N'; - - } elsif ($cur =~ /^(if|while|for)\b/o) { - print "COND($1)\n" if ($dbg_values > 1); - $av_pending = 'E'; - $type = 'N'; - - } elsif ($cur =~/^(case)/o) { - print "CASE($1)\n" if ($dbg_values > 1); - $av_pend_colon = 'C'; - $type = 'N'; - - } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { - print "KEYWORD($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~ /^(\()/o) { - print "PAREN('$1')\n" if ($dbg_values > 1); - push(@av_paren_type, $av_pending); - $av_pending = '_'; - $type = 'N'; - - } elsif ($cur =~ /^(\))/o) { - my $new_type = pop(@av_paren_type); - if ($new_type ne '_') { - $type = $new_type; - print "PAREN('$1') -> $type\n" - if ($dbg_values > 1); - } else { - print "PAREN('$1')\n" if ($dbg_values > 1); - } - - } elsif ($cur =~ /^($Ident)\s*\(/o) { - print "FUNC($1)\n" if ($dbg_values > 1); - $type = 'V'; - $av_pending = 'V'; - - } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) { - if (defined $2 && $type eq 'C' || $type eq 'T') { - $av_pend_colon = 'B'; - } elsif ($type eq 'E') { - $av_pend_colon = 'L'; - } - print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1); - $type = 'V'; - - } elsif ($cur =~ /^($Ident|$Constant)/o) { - print "IDENT($1)\n" if ($dbg_values > 1); - $type = 'V'; - - } elsif ($cur =~ /^($Assignment)/o) { - print "ASSIGN($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~/^(;|{|})/) { - print "END($1)\n" if ($dbg_values > 1); - $type = 'E'; - $av_pend_colon = 'O'; - - } elsif ($cur =~/^(,)/) { - print "COMMA($1)\n" if ($dbg_values > 1); - $type = 'C'; - - } elsif ($cur =~ /^(\?)/o) { - print "QUESTION($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~ /^(:)/o) { - print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1); - - substr($var, length($res), 1, $av_pend_colon); - if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') { - $type = 'E'; - } else { - $type = 'N'; - } - $av_pend_colon = 'O'; - - } elsif ($cur =~ /^(\[)/o) { - print "CLOSE($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { - my $variant; - - print "OPV($1)\n" if ($dbg_values > 1); - if ($type eq 'V') { - $variant = 'B'; - } else { - $variant = 'U'; - } - - substr($var, length($res), 1, $variant); - $type = 'N'; - - } elsif ($cur =~ /^($Operators)/o) { - print "OP($1)\n" if ($dbg_values > 1); - if ($1 ne '++' && $1 ne '--') { - $type = 'N'; - } - - } elsif ($cur =~ /(^.)/o) { - print "C($1)\n" if ($dbg_values > 1); - } - if (defined $1) { - $cur = substr($cur, length($1)); - $res .= $type x length($1); - } - } - - return ($res, $var); -} - -sub possible { - my ($possible, $line) = @_; - my $notPermitted = qr{(?: - ^(?: - $Modifier| - $Storage| - $Type| - DEFINE_\S+ - )$| - ^(?: - goto| - return| - case| - else| - asm|__asm__| - do - )(?:\s|$)| - ^(?:typedef|struct|enum)\b - )}x; - warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); - if ($possible !~ $notPermitted) { - # Check for modifiers. - $possible =~ s/\s*$Storage\s*//g; - $possible =~ s/\s*$Sparse\s*//g; - if ($possible =~ /^\s*$/) { - - } elsif ($possible =~ /\s/) { - $possible =~ s/\s*$Type\s*//g; - for my $modifier (split(' ', $possible)) { - if ($modifier !~ $notPermitted) { - warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); - push(@modifierList, $modifier); - } - } - - } else { - warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); - push(@typeList, $possible); - } - build_types(); - } else { - warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); - } -} - -my $prefix = ''; - -sub report { - if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) { - return 0; - } - my $line = $prefix . $_[0]; - - $line = (split('\n', $line))[0] . "\n" if ($terse); - - push(our @report, $line); - - return 1; -} -sub report_dump { - our @report; -} -sub ERROR { - if (report("ERROR: $_[0]\n")) { - our $clean = 0; - our $cnt_error++; - } -} -sub WARN { - if (report("WARNING: $_[0]\n")) { - our $clean = 0; - our $cnt_warn++; - } -} -sub CHK { - if ($check && report("CHECK: $_[0]\n")) { - our $clean = 0; - our $cnt_chk++; - } -} - -sub check_absolute_file { - my ($absolute, $herecurr) = @_; - my $file = $absolute; - - ##print "absolute<$absolute>\n"; - - # See if any suffix of this path is a path within the tree. - while ($file =~ s@^[^/]*/@@) { - if (-f "$root/$file") { - ##print "file<$file>\n"; - last; - } - } - if (! -f _) { - return 0; - } - - # It is, so see if the prefix is acceptable. - my $prefix = $absolute; - substr($prefix, -length($file)) = ''; - - ##print "prefix<$prefix>\n"; - if ($prefix ne ".../") { - WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr); - } -} - -sub process { - my $filename = shift; - - my $linenr=0; - my $prevline=""; - my $prevrawline=""; - my $stashline=""; - my $stashrawline=""; - - my $length; - my $indent; - my $previndent=0; - my $stashindent=0; - - our $clean = 1; - my $signoff = 0; - my $is_patch = 0; - - our @report = (); - our $cnt_lines = 0; - our $cnt_error = 0; - our $cnt_warn = 0; - our $cnt_chk = 0; - - # Trace the real file/line as we go. - my $realfile = ''; - my $realline = 0; - my $realcnt = 0; - my $here = ''; - my $in_comment = 0; - my $comment_edge = 0; - my $first_line = 0; - my $p1_prefix = ''; - - my $prev_values = 'E'; - - # suppression flags - my %suppress_ifbraces; - my %suppress_whiletrailers; - my %suppress_export; - - # Pre-scan the patch sanitizing the lines. - # Pre-scan the patch looking for any __setup documentation. - # - my @setup_docs = (); - my $setup_docs = 0; - - sanitise_line_reset(); - my $line; - foreach my $rawline (@rawlines) { - $linenr++; - $line = $rawline; - - if ($rawline=~/^\+\+\+\s+(\S+)/) { - $setup_docs = 0; - if ($1 =~ m@Documentation/kernel-parameters.txt$@) { - $setup_docs = 1; - } - #next; - } - if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { - $realline=$1-1; - if (defined $2) { - $realcnt=$3+1; - } else { - $realcnt=1+1; - } - $in_comment = 0; - - # Guestimate if this is a continuing comment. Run - # the context looking for a comment "edge". If this - # edge is a close comment then we must be in a comment - # at context start. - my $edge; - my $cnt = $realcnt; - for (my $ln = $linenr + 1; $cnt > 0; $ln++) { - next if (defined $rawlines[$ln - 1] && - $rawlines[$ln - 1] =~ /^-/); - $cnt--; - #print "RAW<$rawlines[$ln - 1]>\n"; - last if (!defined $rawlines[$ln - 1]); - if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ && - $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) { - ($edge) = $1; - last; - } - } - if (defined $edge && $edge eq '*/') { - $in_comment = 1; - } - - # Guestimate if this is a continuing comment. If this - # is the start of a diff block and this line starts - # ' *' then it is very likely a comment. - if (!defined $edge && - $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@) - { - $in_comment = 1; - } - - ##print "COMMENT:$in_comment edge<$edge> $rawline\n"; - sanitise_line_reset($in_comment); - - } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) { - # Standardise the strings and chars within the input to - # simplify matching -- only bother with positive lines. - $line = sanitise_line($rawline); - } - push(@lines, $line); - - if ($realcnt > 1) { - $realcnt-- if ($line =~ /^(?:\+| |$)/); - } else { - $realcnt = 0; - } - - #print "==>$rawline\n"; - #print "-->$line\n"; - - if ($setup_docs && $line =~ /^\+/) { - push(@setup_docs, $line); - } - } - - $prefix = ''; - - $realcnt = 0; - $linenr = 0; - foreach my $line (@lines) { - $linenr++; - - my $rawline = $rawlines[$linenr - 1]; - -#extract the line range in the file after the patch is applied - if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { - $is_patch = 1; - $first_line = $linenr + 1; - $realline=$1-1; - if (defined $2) { - $realcnt=$3+1; - } else { - $realcnt=1+1; - } - annotate_reset(); - $prev_values = 'E'; - - %suppress_ifbraces = (); - %suppress_whiletrailers = (); - %suppress_export = (); - next; - -# track the line number as we move through the hunk, note that -# new versions of GNU diff omit the leading space on completely -# blank context lines so we need to count that too. - } elsif ($line =~ /^( |\+|$)/) { - $realline++; - $realcnt-- if ($realcnt != 0); - - # Measure the line length and indent. - ($length, $indent) = line_stats($rawline); - - # Track the previous line. - ($prevline, $stashline) = ($stashline, $line); - ($previndent, $stashindent) = ($stashindent, $indent); - ($prevrawline, $stashrawline) = ($stashrawline, $rawline); - - #warn "line<$line>\n"; - - } elsif ($realcnt == 1) { - $realcnt--; - } - - my $hunk_line = ($realcnt != 0); - -#make up the handle for any error we report on this line - $prefix = "$filename:$realline: " if ($emacs && $file); - $prefix = "$filename:$linenr: " if ($emacs && !$file); - - $here = "#$linenr: " if (!$file); - $here = "#$realline: " if ($file); - - # extract the filename as it passes - if ($line=~/^\+\+\+\s+(\S+)/) { - $realfile = $1; - $realfile =~ s@^([^/]*)/@@; - - $p1_prefix = $1; - if (!$file && $tree && $p1_prefix ne '' && - -e "$root/$p1_prefix") { - WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); - } - - if ($realfile =~ m@^include/asm/@) { - ERROR("do not modify files in include/asm, change architecture specific files in include/asm-\n" . "$here$rawline\n"); - } - next; - } - - $here .= "FILE: $realfile:$realline:" if ($realcnt != 0); - - my $hereline = "$here\n$rawline\n"; - my $herecurr = "$here\n$rawline\n"; - my $hereprev = "$here\n$prevrawline\n$rawline\n"; - - $cnt_lines++ if ($realcnt != 0); - -#check the patch for a signoff: - if ($line =~ /^\s*signed-off-by:/i) { - # This is a signoff, if ugly, so do not double report. - $signoff++; - if (!($line =~ /^\s*Signed-off-by:/)) { - WARN("Signed-off-by: is the preferred form\n" . - $herecurr); - } - if ($line =~ /^\s*signed-off-by:\S/i) { - WARN("space required after Signed-off-by:\n" . - $herecurr); - } - } - -# Check for wrappage within a valid hunk of the file - if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { - ERROR("patch seems to be corrupt (line wrapped?)\n" . - $herecurr) if (!$emitted_corrupt++); - } - -# Check for absolute kernel paths. - if ($tree) { - while ($line =~ m{(?:^|\s)(/\S*)}g) { - my $file = $1; - - if ($file =~ m{^(.*?)(?::\d+)+:?$} && - check_absolute_file($1, $herecurr)) { - # - } else { - check_absolute_file($file, $herecurr); - } - } - } - -# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php - if (($realfile =~ /^$/ || $line =~ /^\+/) && - $rawline !~ m/^$UTF8*$/) { - my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/); - - my $blank = copy_spacing($rawline); - my $ptr = substr($blank, 0, length($utf8_prefix)) . "^"; - my $hereptr = "$hereline$ptr\n"; - - ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); - } - -# ignore non-hunk lines and lines being removed - next if (!$hunk_line || $line =~ /^-/); - -#trailing whitespace - if ($line =~ /^\+.*\015/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("DOS line endings\n" . $herevet); - - } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("trailing whitespace\n" . $herevet); - } - -# check we are in a valid source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); - -#80 column limit - if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ && - $rawline !~ /^.\s*\*\s*\@$Ident\s/ && - $line !~ /^\+\s*printk\s*\(\s*(?:KERN_\S+\s*)?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ && - $length > 80) - { - WARN("line over 80 characters\n" . $herecurr); - } - -# check for adding lines without a newline. - if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { - WARN("adding a line without newline at end of file\n" . $herecurr); - } - -# Blackfin: use hi/lo macros - if ($realfile =~ m@arch/blackfin/.*\.S$@) { - if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("use the LO() macro, not (... & 0xFFFF)\n" . $herevet); - } - if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("use the HI() macro, not (... >> 16)\n" . $herevet); - } - } - -# check we are in a valid source file C or perl if not then ignore this hunk - next if ($realfile !~ /\.(h|c|pl)$/); - -# at the beginning of a line any tabs must come first and anything -# more than 8 must use tabs. - if ($rawline =~ /^\+\s* \t\s*\S/ || - $rawline =~ /^\+\s* \s*/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("code indent should use tabs where possible\n" . $herevet); - } - -# check we are in a valid C source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c)$/); - -# check for RCS/CVS revision markers - if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { - WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr); - } - -# Blackfin: don't use __builtin_bfin_[cs]sync - if ($line =~ /__builtin_bfin_csync/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("use the CSYNC() macro in asm/blackfin.h\n" . $herevet); - } - if ($line =~ /__builtin_bfin_ssync/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("use the SSYNC() macro in asm/blackfin.h\n" . $herevet); - } - -# Check for potential 'bare' types - my ($stat, $cond, $line_nr_next, $remain_next, $off_next, - $realline_next); - if ($realcnt && $line =~ /.\s*\S/) { - ($stat, $cond, $line_nr_next, $remain_next, $off_next) = - ctx_statement_block($linenr, $realcnt, 0); - $stat =~ s/\n./\n /g; - $cond =~ s/\n./\n /g; - - # Find the real next line. - $realline_next = $line_nr_next; - if (defined $realline_next && - (!defined $lines[$realline_next - 1] || - substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) { - $realline_next++; - } - - my $s = $stat; - $s =~ s/{.*$//s; - - # Ignore goto labels. - if ($s =~ /$Ident:\*$/s) { - - # Ignore functions being called - } elsif ($s =~ /^.\s*$Ident\s*\(/s) { - - } elsif ($s =~ /^.\s*else\b/s) { - - # declarations always start with types - } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) { - my $type = $1; - $type =~ s/\s+/ /g; - possible($type, "A:" . $s); - - # definitions in global scope can only start with types - } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { - possible($1, "B:" . $s); - } - - # any (foo ... *) is a pointer cast, and foo is a type - while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) { - possible($1, "C:" . $s); - } - - # Check for any sort of function declaration. - # int foo(something bar, other baz); - # void (*store_gdt)(x86_descr_ptr *); - if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { - my ($name_len) = length($1); - - my $ctx = $s; - substr($ctx, 0, $name_len + 1, ''); - $ctx =~ s/\)[^\)]*$//; - - for my $arg (split(/\s*,\s*/, $ctx)) { - if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) { - - possible($1, "D:" . $s); - } - } - } - - } - -# -# Checks which may be anchored in the context. -# - -# Check for switch () and associated case and default -# statements should be at the same indent. - if ($line=~/\bswitch\s*\(.*\)/) { - my $err = ''; - my $sep = ''; - my @ctx = ctx_block_outer($linenr, $realcnt); - shift(@ctx); - for my $ctx (@ctx) { - my ($clen, $cindent) = line_stats($ctx); - if ($ctx =~ /^\+\s*(case\s+|default:)/ && - $indent != $cindent) { - $err .= "$sep$ctx\n"; - $sep = ''; - } else { - $sep = "[...]\n"; - } - } - if ($err ne '') { - ERROR("switch and case should be at the same indent\n$hereline$err"); - } - } - -# if/while/etc brace do not go on next line, unless defining a do while loop, -# or if that brace on the next line is for something else - if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { - my $pre_ctx = "$1$2"; - - my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); - my $ctx_cnt = $realcnt - $#ctx - 1; - my $ctx = join("\n", @ctx); - - my $ctx_ln = $linenr; - my $ctx_skip = $realcnt; - - while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt && - defined $lines[$ctx_ln - 1] && - $lines[$ctx_ln - 1] =~ /^-/)) { - ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n"; - $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/); - $ctx_ln++; - } - - #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; - #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; - - if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { - ERROR("that open brace { should be on the previous line\n" . - "$here\n$ctx\n$lines[$ctx_ln - 1]\n"); - } - if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && - $ctx =~ /\)\s*\;\s*$/ && - defined $lines[$ctx_ln - 1]) - { - my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); - if ($nindent > $indent) { - WARN("trailing semicolon indicates no statements, indent implies otherwise\n" . - "$here\n$ctx\n$lines[$ctx_ln - 1]\n"); - } - } - } - -# Check relative indent for conditionals and blocks. - if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { - my ($s, $c) = ($stat, $cond); - - substr($s, 0, length($c), ''); - - # Make sure we remove the line prefixes as we have - # none on the first line, and are going to readd them - # where necessary. - $s =~ s/\n./\n/gs; - - # Find out how long the conditional actually is. - my @newlines = ($c =~ /\n/gs); - my $cond_lines = 1 + $#newlines; - - # We want to check the first line inside the block - # starting at the end of the conditional, so remove: - # 1) any blank line termination - # 2) any opening brace { on end of the line - # 3) any do (...) { - my $continuation = 0; - my $check = 0; - $s =~ s/^.*\bdo\b//; - $s =~ s/^\s*{//; - if ($s =~ s/^\s*\\//) { - $continuation = 1; - } - if ($s =~ s/^\s*?\n//) { - $check = 1; - $cond_lines++; - } - - # Also ignore a loop construct at the end of a - # preprocessor statement. - if (($prevline =~ /^.\s*#\s*define\s/ || - $prevline =~ /\\\s*$/) && $continuation == 0) { - $check = 0; - } - - my $cond_ptr = -1; - $continuation = 0; - while ($cond_ptr != $cond_lines) { - $cond_ptr = $cond_lines; - - # If we see an #else/#elif then the code - # is not linear. - if ($s =~ /^\s*\#\s*(?:else|elif)/) { - $check = 0; - } - - # Ignore: - # 1) blank lines, they should be at 0, - # 2) preprocessor lines, and - # 3) labels. - if ($continuation || - $s =~ /^\s*?\n/ || - $s =~ /^\s*#\s*?/ || - $s =~ /^\s*$Ident\s*:/) { - $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0; - if ($s =~ s/^.*?\n//) { - $cond_lines++; - } - } - } - - my (undef, $sindent) = line_stats("+" . $s); - my $stat_real = raw_line($linenr, $cond_lines); - - # Check if either of these lines are modified, else - # this is not this patch's fault. - if (!defined($stat_real) || - $stat !~ /^\+/ && $stat_real !~ /^\+/) { - $check = 0; - } - if (defined($stat_real) && $cond_lines > 1) { - $stat_real = "[...]\n$stat_real"; - } - - #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; - - if ($check && (($sindent % 8) != 0 || - ($sindent <= $indent && $s ne ''))) { - WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); - } - } - - # Track the 'values' across context and added lines. - my $opline = $line; $opline =~ s/^./ /; - my ($curr_values, $curr_vars) = - annotate_values($opline . "\n", $prev_values); - $curr_values = $prev_values . $curr_values; - if ($dbg_values) { - my $outline = $opline; $outline =~ s/\t/ /g; - print "$linenr > .$outline\n"; - print "$linenr > $curr_values\n"; - print "$linenr > $curr_vars\n"; - } - $prev_values = substr($curr_values, -1); - -#ignore lines not being added - if ($line=~/^[^\+]/) {next;} - -# TEST: allow direct testing of the type matcher. - if ($dbg_type) { - if ($line =~ /^.\s*$Declare\s*$/) { - ERROR("TEST: is type\n" . $herecurr); - } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) { - ERROR("TEST: is not type ($1 is)\n". $herecurr); - } - next; - } -# TEST: allow direct testing of the attribute matcher. - if ($dbg_attr) { - if ($line =~ /^.\s*$Modifier\s*$/) { - ERROR("TEST: is attr\n" . $herecurr); - } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) { - ERROR("TEST: is not attr ($1 is)\n". $herecurr); - } - next; - } - -# check for initialisation to aggregates open brace on the next line - if ($line =~ /^.\s*{/ && - $prevline =~ /(?:^|[^=])=\s*$/) { - ERROR("that open brace { should be on the previous line\n" . $hereprev); - } - -# -# Checks which are anchored on the added line. -# - -# check for malformed paths in #include statements (uses RAW line) - if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) { - my $path = $1; - if ($path =~ m{//}) { - ERROR("malformed #include filename\n" . - $herecurr); - } - } - -# no C99 // comments - if ($line =~ m{//}) { - ERROR("do not use C99 // comments\n" . $herecurr); - } - # Remove C99 comments. - $line =~ s@//.*@@; - $opline =~ s@//.*@@; - -# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider -# the whole statement. -#print "APW <$lines[$realline_next - 1]>\n"; - if (defined $realline_next && - exists $lines[$realline_next - 1] && - !defined $suppress_export{$realline_next} && - ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ || - $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { - my $name = $1; - if ($stat !~ /(?: - \n.}\s*$| - ^.DEFINE_$Ident\(\Q$name\E\)| - ^.DECLARE_$Ident\(\Q$name\E\)| - ^.LIST_HEAD\(\Q$name\E\)| - ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(| - \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\() - )/x) { -#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n"; - $suppress_export{$realline_next} = 2; - } else { - $suppress_export{$realline_next} = 1; - } - } - if (!defined $suppress_export{$linenr} && - $prevline =~ /^.\s*$/ && - ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ || - $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { -#print "FOO B <$lines[$linenr - 1]>\n"; - $suppress_export{$linenr} = 2; - } - if (defined $suppress_export{$linenr} && - $suppress_export{$linenr} == 2) { - WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr); - } - -# check for external initialisers. - if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) { - ERROR("do not initialise externals to 0 or NULL\n" . - $herecurr); - } -# check for static initialisers. - if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) { - ERROR("do not initialise statics to 0 or NULL\n" . - $herecurr); - } - -# check for new typedefs, only function parameters and sparse annotations -# make sense. - if ($line =~ /\btypedef\s/ && - $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && - $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && - $line !~ /\b$typeTypedefs\b/ && - $line !~ /\b__bitwise(?:__|)\b/) { - WARN("do not add new typedefs\n" . $herecurr); - } - -# * goes on variable not on type - # (char*[ const]) - if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) { - my ($from, $to) = ($1, $1); - - # Should start with a space. - $to =~ s/^(\S)/ $1/; - # Should not end with a space. - $to =~ s/\s+$//; - # '*'s should not have spaces between. - while ($to =~ s/\*\s+\*/\*\*/) { - } - - #print "from<$from> to<$to>\n"; - if ($from ne $to) { - ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr); - } - } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) { - my ($from, $to, $ident) = ($1, $1, $2); - - # Should start with a space. - $to =~ s/^(\S)/ $1/; - # Should not end with a space. - $to =~ s/\s+$//; - # '*'s should not have spaces between. - while ($to =~ s/\*\s+\*/\*\*/) { - } - # Modifiers should have spaces. - $to =~ s/(\b$Modifier$)/$1 /; - - #print "from<$from> to<$to> ident<$ident>\n"; - if ($from ne $to && $ident !~ /^$Modifier$/) { - ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr); - } - } - -# # no BUG() or BUG_ON() -# if ($line =~ /\b(BUG|BUG_ON)\b/) { -# print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n"; -# print "$herecurr"; -# $clean = 0; -# } - - if ($line =~ /\bLINUX_VERSION_CODE\b/) { - WARN("LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); - } - -# printk should use KERN_* levels. Note that follow on printk's on the -# same line do not need a level, so we use the current block context -# to try and find and validate the current printk. In summary the current -# printk includes all preceeding printk's which have no newline on the end. -# we assume the first bad printk is the one to report. - if ($line =~ /\bprintk\((?!KERN_)\s*"/) { - my $ok = 0; - for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) { - #print "CHECK<$lines[$ln - 1]\n"; - # we have a preceeding printk if it ends - # with "\n" ignore it, else it is to blame - if ($lines[$ln - 1] =~ m{\bprintk\(}) { - if ($rawlines[$ln - 1] !~ m{\\n"}) { - $ok = 1; - } - last; - } - } - if ($ok == 0) { - WARN("printk() should include KERN_ facility level\n" . $herecurr); - } - } - -# function brace can't be on same line, except for #defines of do while, -# or if closed on same line - if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and - !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) { - ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr); - } - -# open braces for enum, union and struct go on the same line. - if ($line =~ /^.\s*{/ && - $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { - ERROR("open brace '{' following $1 go on the same line\n" . $hereprev); - } - -# check for spacing round square brackets; allowed: -# 1. with a type on the left -- int [] a; -# 2. at the beginning of a line for slice initialisers -- [0...10] = 5, -# 3. inside a curly brace -- = { [0...10] = 5 } - while ($line =~ /(.*?\s)\[/g) { - my ($where, $prefix) = ($-[1], $1); - if ($prefix !~ /$Type\s+$/ && - ($where != 0 || $prefix !~ /^.\s+$/) && - $prefix !~ /{\s+$/) { - ERROR("space prohibited before open square bracket '['\n" . $herecurr); - } - } - -# check for spaces between functions and their parentheses. - while ($line =~ /($Ident)\s+\(/g) { - my $name = $1; - my $ctx_before = substr($line, 0, $-[1]); - my $ctx = "$ctx_before$name"; - - # Ignore those directives where spaces _are_ permitted. - if ($name =~ /^(?: - if|for|while|switch|return|case| - volatile|__volatile__| - __attribute__|format|__extension__| - asm|__asm__)$/x) - { - - # cpp #define statements have non-optional spaces, ie - # if there is a space between the name and the open - # parenthesis it is simply not a parameter group. - } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) { - - # cpp #elif statement condition may start with a ( - } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) { - - # If this whole things ends with a type its most - # likely a typedef for a function. - } elsif ($ctx =~ /$Type$/) { - - } else { - WARN("space prohibited between function name and open parenthesis '('\n" . $herecurr); - } - } -# Check operator spacing. - if (!($line=~/\#\s*include/)) { - my $ops = qr{ - <<=|>>=|<=|>=|==|!=| - \+=|-=|\*=|\/=|%=|\^=|\|=|&=| - =>|->|<<|>>|<|>|=|!|~| - &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| - \?|: - }x; - my @elements = split(/($ops|;)/, $opline); - my $off = 0; - - my $blank = copy_spacing($opline); - - for (my $n = 0; $n < $#elements; $n += 2) { - $off += length($elements[$n]); - - # Pick up the preceeding and succeeding characters. - my $ca = substr($opline, 0, $off); - my $cc = ''; - if (length($opline) >= ($off + length($elements[$n + 1]))) { - $cc = substr($opline, $off + length($elements[$n + 1])); - } - my $cb = "$ca$;$cc"; - - my $a = ''; - $a = 'V' if ($elements[$n] ne ''); - $a = 'W' if ($elements[$n] =~ /\s$/); - $a = 'C' if ($elements[$n] =~ /$;$/); - $a = 'B' if ($elements[$n] =~ /(\[|\()$/); - $a = 'O' if ($elements[$n] eq ''); - $a = 'E' if ($ca =~ /^\s*$/); - - my $op = $elements[$n + 1]; - - my $c = ''; - if (defined $elements[$n + 2]) { - $c = 'V' if ($elements[$n + 2] ne ''); - $c = 'W' if ($elements[$n + 2] =~ /^\s/); - $c = 'C' if ($elements[$n + 2] =~ /^$;/); - $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/); - $c = 'O' if ($elements[$n + 2] eq ''); - $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/); - } else { - $c = 'E'; - } - - my $ctx = "${a}x${c}"; - - my $at = "(ctx:$ctx)"; - - my $ptr = substr($blank, 0, $off) . "^"; - my $hereptr = "$hereline$ptr\n"; - - # Pull out the value of this operator. - my $op_type = substr($curr_values, $off + 1, 1); - - # Get the full operator variant. - my $opv = $op . substr($curr_vars, $off, 1); - - # Ignore operators passed as parameters. - if ($op_type ne 'V' && - $ca =~ /\s$/ && $cc =~ /^\s*,/) { - -# # Ignore comments -# } elsif ($op =~ /^$;+$/) { - - # ; should have either the end of line or a space or \ after it - } elsif ($op eq ';') { - if ($ctx !~ /.x[WEBC]/ && - $cc !~ /^\\/ && $cc !~ /^;/) { - ERROR("space required after that '$op' $at\n" . $hereptr); - } - - # // is a comment - } elsif ($op eq '//') { - - # No spaces for: - # -> - # : when part of a bitfield - } elsif ($op eq '->' || $opv eq ':B') { - if ($ctx =~ /Wx.|.xW/) { - ERROR("spaces prohibited around that '$op' $at\n" . $hereptr); - } - - # , must have a space on the right. - } elsif ($op eq ',') { - if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { - ERROR("space required after that '$op' $at\n" . $hereptr); - } - - # '*' as part of a type definition -- reported already. - } elsif ($opv eq '*_') { - #warn "'*' is part of type\n"; - - # unary operators should have a space before and - # none after. May be left adjacent to another - # unary operator, or a cast - } elsif ($op eq '!' || $op eq '~' || - $opv eq '*U' || $opv eq '-U' || - $opv eq '&U' || $opv eq '&&U') { - if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { - ERROR("space required before that '$op' $at\n" . $hereptr); - } - if ($op eq '*' && $cc =~/\s*$Modifier\b/) { - # A unary '*' may be const - - } elsif ($ctx =~ /.xW/) { - ERROR("space prohibited after that '$op' $at\n" . $hereptr); - } - - # unary ++ and unary -- are allowed no space on one side. - } elsif ($op eq '++' or $op eq '--') { - if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { - ERROR("space required one side of that '$op' $at\n" . $hereptr); - } - if ($ctx =~ /Wx[BE]/ || - ($ctx =~ /Wx./ && $cc =~ /^;/)) { - ERROR("space prohibited before that '$op' $at\n" . $hereptr); - } - if ($ctx =~ /ExW/) { - ERROR("space prohibited after that '$op' $at\n" . $hereptr); - } - - - # << and >> may either have or not have spaces both sides - } elsif ($op eq '<<' or $op eq '>>' or - $op eq '&' or $op eq '^' or $op eq '|' or - $op eq '+' or $op eq '-' or - $op eq '*' or $op eq '/' or - $op eq '%') - { - if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { - ERROR("need consistent spacing around '$op' $at\n" . - $hereptr); - } - - # A colon needs no spaces before when it is - # terminating a case value or a label. - } elsif ($opv eq ':C' || $opv eq ':L') { - if ($ctx =~ /Wx./) { - ERROR("space prohibited before that '$op' $at\n" . $hereptr); - } - - # All the others need spaces both sides. - } elsif ($ctx !~ /[EWC]x[CWE]/) { - my $ok = 0; - - # Ignore email addresses - if (($op eq '<' && - $cc =~ /^\S+\@\S+>/) || - ($op eq '>' && - $ca =~ /<\S+\@\S+$/)) - { - $ok = 1; - } - - # Ignore ?: - if (($opv eq ':O' && $ca =~ /\?$/) || - ($op eq '?' && $cc =~ /^:/)) { - $ok = 1; - } - - if ($ok == 0) { - ERROR("spaces required around that '$op' $at\n" . $hereptr); - } - } - $off += length($elements[$n + 1]); - } - } - -# check for multiple assignments - if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) { - CHK("multiple assignments should be avoided\n" . $herecurr); - } - -## # check for multiple declarations, allowing for a function declaration -## # continuation. -## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ && -## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) { -## -## # Remove any bracketed sections to ensure we do not -## # falsly report the parameters of functions. -## my $ln = $line; -## while ($ln =~ s/\([^\(\)]*\)//g) { -## } -## if ($ln =~ /,/) { -## WARN("declaring multiple variables together should be avoided\n" . $herecurr); -## } -## } - -#need space before brace following if, while, etc - if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) || - $line =~ /do{/) { - ERROR("space required before the open brace '{'\n" . $herecurr); - } - -# closing brace should have a space following it when it has anything -# on the line - if ($line =~ /}(?!(?:,|;|\)))\S/) { - ERROR("space required after that close brace '}'\n" . $herecurr); - } - -# check spacing on square brackets - if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { - ERROR("space prohibited after that open square bracket '['\n" . $herecurr); - } - if ($line =~ /\s\]/) { - ERROR("space prohibited before that close square bracket ']'\n" . $herecurr); - } - -# check spacing on parentheses - if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && - $line !~ /for\s*\(\s+;/) { - ERROR("space prohibited after that open parenthesis '('\n" . $herecurr); - } - if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && - $line !~ /for\s*\(.*;\s+\)/ && - $line !~ /:\s+\)/) { - ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr); - } - -#goto labels aren't indented, allow a single space however - if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and - !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) { - WARN("labels should not be indented\n" . $herecurr); - } - -# Return is not a function. - if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) { - my $spacing = $1; - my $value = $2; - - # Flatten any parentheses - $value =~ s/\)\(/\) \(/g; - while ($value =~ s/\[[^\{\}]*\]/1/ || - $value !~ /(?:$Ident|-?$Constant)\s* - $Compare\s* - (?:$Ident|-?$Constant)/x && - $value =~ s/\([^\(\)]*\)/1/) { - } - - if ($value =~ /^(?:$Ident|-?$Constant)$/) { - ERROR("return is not a function, parentheses are not required\n" . $herecurr); - - } elsif ($spacing !~ /\s+/) { - ERROR("space required before the open parenthesis '('\n" . $herecurr); - } - } - -# Need a space before open parenthesis after if, while etc - if ($line=~/\b(if|while|for|switch)\(/) { - ERROR("space required before the open parenthesis '('\n" . $herecurr); - } - -# Check for illegal assignment in if conditional -- and check for trailing -# statements after the conditional. - if ($line =~ /do\s*(?!{)/) { - my ($stat_next) = ctx_statement_block($line_nr_next, - $remain_next, $off_next); - $stat_next =~ s/\n./\n /g; - ##print "stat<$stat> stat_next<$stat_next>\n"; - - if ($stat_next =~ /^\s*while\b/) { - # If the statement carries leading newlines, - # then count those as offsets. - my ($whitespace) = - ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s); - my $offset = - statement_rawlines($whitespace) - 1; - - $suppress_whiletrailers{$line_nr_next + - $offset} = 1; - } - } - if (!defined $suppress_whiletrailers{$linenr} && - $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { - my ($s, $c) = ($stat, $cond); - - if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { - ERROR("do not use assignment in if condition\n" . $herecurr); - } - - # Find out what is on the end of the line after the - # conditional. - substr($s, 0, length($c), ''); - $s =~ s/\n.*//g; - $s =~ s/$;//g; # Remove any comments - if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && - $c !~ /}\s*while\s*/) - { - # Find out how long the conditional actually is. - my @newlines = ($c =~ /\n/gs); - my $cond_lines = 1 + $#newlines; - - my $stat_real = raw_line($linenr, $cond_lines); - if (defined($stat_real) && $cond_lines > 1) { - $stat_real = "[...]\n$stat_real"; - } - - ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real); - } - } - -# Check for bitwise tests written as boolean - if ($line =~ / - (?: - (?:\[|\(|\&\&|\|\|) - \s*0[xX][0-9]+\s* - (?:\&\&|\|\|) - | - (?:\&\&|\|\|) - \s*0[xX][0-9]+\s* - (?:\&\&|\|\||\)|\]) - )/x) - { - WARN("boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr); - } - -# if and else should not have general statements after it - if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { - my $s = $1; - $s =~ s/$;//g; # Remove any comments - if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { - ERROR("trailing statements should be on next line\n" . $herecurr); - } - } -# if should not continue a brace - if ($line =~ /}\s*if\b/) { - ERROR("trailing statements should be on next line\n" . - $herecurr); - } -# case and default should not have general statements after them - if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && - $line !~ /\G(?: - (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$| - \s*return\s+ - )/xg) - { - ERROR("trailing statements should be on next line\n" . $herecurr); - } - - # Check for }else {, these must be at the same - # indent level to be relevant to each other. - if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and - $previndent == $indent) { - ERROR("else should follow close brace '}'\n" . $hereprev); - } - - if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and - $previndent == $indent) { - my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); - - # Find out what is on the end of the line after the - # conditional. - substr($s, 0, length($c), ''); - $s =~ s/\n.*//g; - - if ($s =~ /^\s*;/) { - ERROR("while should follow close brace '}'\n" . $hereprev); - } - } - -#studly caps, commented out until figure out how to distinguish between use of existing and adding new -# if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) { -# print "No studly caps, use _\n"; -# print "$herecurr"; -# $clean = 0; -# } - -#no spaces allowed after \ in define - if ($line=~/\#\s*define.*\\\s$/) { - WARN("Whitepspace after \\ makes next lines useless\n" . $herecurr); - } - -#warn if is #included and is available (uses RAW line) - if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\}) { - my $file = "$1.h"; - my $checkfile = "include/linux/$file"; - if (-f "$root/$checkfile" && - $realfile ne $checkfile && - $1 ne 'irq') - { - if ($realfile =~ m{^arch/}) { - CHK("Consider using #include instead of \n" . $herecurr); - } else { - WARN("Use #include instead of \n" . $herecurr); - } - } - } - -# multi-statement macros should be enclosed in a do while loop, grab the -# first statement and ensure its the whole macro if its not enclosed -# in a known good container - if ($realfile !~ m@/vmlinux.lds.h$@ && - $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { - my $ln = $linenr; - my $cnt = $realcnt; - my ($off, $dstat, $dcond, $rest); - my $ctx = ''; - - my $args = defined($1); - - # Find the end of the macro and limit our statement - # search to that. - while ($cnt > 0 && defined $lines[$ln - 1] && - $lines[$ln - 1] =~ /^(?:-|..*\\$)/) - { - $ctx .= $rawlines[$ln - 1] . "\n"; - $cnt-- if ($lines[$ln - 1] !~ /^-/); - $ln++; - } - $ctx .= $rawlines[$ln - 1]; - - ($dstat, $dcond, $ln, $cnt, $off) = - ctx_statement_block($linenr, $ln - $linenr + 1, 0); - #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; - #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; - - # Extract the remainder of the define (if any) and - # rip off surrounding spaces, and trailing \'s. - $rest = ''; - while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) { - #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n"; - if ($off != 0 || $lines[$ln - 1] !~ /^-/) { - $rest .= substr($lines[$ln - 1], $off) . "\n"; - $cnt--; - } - $ln++; - $off = 0; - } - $rest =~ s/\\\n.//g; - $rest =~ s/^\s*//s; - $rest =~ s/\s*$//s; - - # Clean up the original statement. - if ($args) { - substr($dstat, 0, length($dcond), ''); - } else { - $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//; - } - $dstat =~ s/$;//g; - $dstat =~ s/\\\n.//g; - $dstat =~ s/^\s*//s; - $dstat =~ s/\s*$//s; - - # Flatten any parentheses and braces - while ($dstat =~ s/\([^\(\)]*\)/1/ || - $dstat =~ s/\{[^\{\}]*\}/1/ || - $dstat =~ s/\[[^\{\}]*\]/1/) - { - } - - my $exceptions = qr{ - $Declare| - module_param_named| - MODULE_PARAM_DESC| - DECLARE_PER_CPU| - DEFINE_PER_CPU| - __typeof__\(| - \.$Ident\s*=\s*| - ^\"|\"$ - }x; - #print "REST<$rest> dstat<$dstat>\n"; - if ($rest ne '') { - if ($rest !~ /while\s*\(/ && - $dstat !~ /$exceptions/) - { - ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n"); - } - - } elsif ($ctx !~ /;/) { - if ($dstat ne '' && - $dstat !~ /^(?:$Ident|-?$Constant)$/ && - $dstat !~ /$exceptions/ && - $dstat !~ /^\.$Ident\s*=/ && - $dstat =~ /$Operators/) - { - ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n"); - } - } - } - -# make sure symbols are always wrapped with VMLINUX_SYMBOL() ... -# all assignments may have only one of the following with an assignment: -# . -# ALIGN(...) -# VMLINUX_SYMBOL(...) - if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) { - WARN("vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr); - } - -# check for redundant bracing round if etc - if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { - my ($level, $endln, @chunks) = - ctx_statement_full($linenr, $realcnt, 1); - #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; - #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; - if ($#chunks > 0 && $level == 0) { - my $allowed = 0; - my $seen = 0; - my $herectx = $here . "\n"; - my $ln = $linenr - 1; - for my $chunk (@chunks) { - my ($cond, $block) = @{$chunk}; - - # If the condition carries leading newlines, then count those as offsets. - my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); - my $offset = statement_rawlines($whitespace) - 1; - - #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; - - # We have looked at and allowed this specific line. - $suppress_ifbraces{$ln + $offset} = 1; - - $herectx .= "$rawlines[$ln + $offset]\n[...]\n"; - $ln += statement_rawlines($block) - 1; - - substr($block, 0, length($cond), ''); - - $seen++ if ($block =~ /^\s*{/); - - #print "cond<$cond> block<$block> allowed<$allowed>\n"; - if (statement_lines($cond) > 1) { - #print "APW: ALLOWED: cond<$cond>\n"; - $allowed = 1; - } - if ($block =~/\b(?:if|for|while)\b/) { - #print "APW: ALLOWED: block<$block>\n"; - $allowed = 1; - } - if (statement_block_size($block) > 1) { - #print "APW: ALLOWED: lines block<$block>\n"; - $allowed = 1; - } - } - if ($seen && !$allowed) { - WARN("braces {} are not necessary for any arm of this statement\n" . $herectx); - } - } - } - if (!defined $suppress_ifbraces{$linenr - 1} && - $line =~ /\b(if|while|for|else)\b/) { - my $allowed = 0; - - # Check the pre-context. - if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { - #print "APW: ALLOWED: pre<$1>\n"; - $allowed = 1; - } - - my ($level, $endln, @chunks) = - ctx_statement_full($linenr, $realcnt, $-[0]); - - # Check the condition. - my ($cond, $block) = @{$chunks[0]}; - #print "CHECKING<$linenr> cond<$cond> block<$block>\n"; - if (defined $cond) { - substr($block, 0, length($cond), ''); - } - if (statement_lines($cond) > 1) { - #print "APW: ALLOWED: cond<$cond>\n"; - $allowed = 1; - } - if ($block =~/\b(?:if|for|while)\b/) { - #print "APW: ALLOWED: block<$block>\n"; - $allowed = 1; - } - if (statement_block_size($block) > 1) { - #print "APW: ALLOWED: lines block<$block>\n"; - $allowed = 1; - } - # Check the post-context. - if (defined $chunks[1]) { - my ($cond, $block) = @{$chunks[1]}; - if (defined $cond) { - substr($block, 0, length($cond), ''); - } - if ($block =~ /^\s*\{/) { - #print "APW: ALLOWED: chunk-1 block<$block>\n"; - $allowed = 1; - } - } - if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { - my $herectx = $here . "\n";; - my $cnt = statement_rawlines($block); - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n";; - } - - WARN("braces {} are not necessary for single statement blocks\n" . $herectx); - } - } - -# don't include deprecated include files (uses RAW line) - for my $inc (@dep_includes) { - if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) { - ERROR("Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr); - } - } - -# don't use deprecated functions - for my $func (@dep_functions) { - if ($line =~ /\b$func\b/) { - ERROR("Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr); - } - } - -# no volatiles please - my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; - if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { - WARN("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr); - } - -# SPIN_LOCK_UNLOCKED & RW_LOCK_UNLOCKED are deprecated - if ($line =~ /\b(SPIN_LOCK_UNLOCKED|RW_LOCK_UNLOCKED)/) { - ERROR("Use of $1 is deprecated: see Documentation/spinlocks.txt\n" . $herecurr); - } - -# warn about #if 0 - if ($line =~ /^.\s*\#\s*if\s+0\b/) { - CHK("if this code is redundant consider removing it\n" . - $herecurr); - } - -# check for needless kfree() checks - if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { - my $expr = $1; - if ($line =~ /\bkfree\(\Q$expr\E\);/) { - WARN("kfree(NULL) is safe this check is probably not required\n" . $hereprev); - } - } -# check for needless usb_free_urb() checks - if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { - my $expr = $1; - if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) { - WARN("usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev); - } - } - -# warn about #ifdefs in C files -# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { -# print "#ifdef in C files should be avoided\n"; -# print "$herecurr"; -# $clean = 0; -# } - -# warn about spacing in #ifdefs - if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { - ERROR("exactly one space required after that #$1\n" . $herecurr); - } - -# check for spinlock_t definitions without a comment. - if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ || - $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) { - my $which = $1; - if (!ctx_has_comment($first_line, $linenr)) { - CHK("$1 definition without comment\n" . $herecurr); - } - } -# check for memory barriers without a comment. - if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) { - if (!ctx_has_comment($first_line, $linenr)) { - CHK("memory barrier without comment\n" . $herecurr); - } - } -# check of hardware specific defines - if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) { - CHK("architecture specific defines should be avoided\n" . $herecurr); - } - -# check the location of the inline attribute, that it is between -# storage class and type. - if ($line =~ /\b$Type\s+$Inline\b/ || - $line =~ /\b$Inline\s+$Storage\b/) { - ERROR("inline keyword should sit between storage class and type\n" . $herecurr); - } - -# Check for __inline__ and __inline, prefer inline - if ($line =~ /\b(__inline__|__inline)\b/) { - WARN("plain inline is preferred over $1\n" . $herecurr); - } - -# check for new externs in .c files. - if ($realfile =~ /\.c$/ && defined $stat && - $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) - { - my $function_name = $1; - my $paren_space = $2; - - my $s = $stat; - if (defined $cond) { - substr($s, 0, length($cond), ''); - } - if ($s =~ /^\s*;/ && - $function_name ne 'uninitialized_var') - { - WARN("externs should be avoided in .c files\n" . $herecurr); - } - - if ($paren_space =~ /\n/) { - WARN("arguments for function declarations should follow identifier\n" . $herecurr); - } - - } elsif ($realfile =~ /\.c$/ && defined $stat && - $stat =~ /^.\s*extern\s+/) - { - WARN("externs should be avoided in .c files\n" . $herecurr); - } - -# checks for new __setup's - if ($rawline =~ /\b__setup\("([^"]*)"/) { - my $name = $1; - - if (!grep(/$name/, @setup_docs)) { - CHK("__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr); - } - } - -# check for pointless casting of kmalloc return - if ($line =~ /\*\s*\)\s*k[czm]alloc\b/) { - WARN("unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); - } - -# check for gcc specific __FUNCTION__ - if ($line =~ /__FUNCTION__/) { - WARN("__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr); - } - -# check for semaphores used as mutexes - if ($line =~ /^.\s*(DECLARE_MUTEX|init_MUTEX)\s*\(/) { - WARN("mutexes are preferred for single holder semaphores\n" . $herecurr); - } -# check for semaphores used as mutexes - if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) { - WARN("consider using a completion\n" . $herecurr); - } -# recommend strict_strto* over simple_strto* - if ($line =~ /\bsimple_(strto.*?)\s*\(/) { - WARN("consider using strict_$1 in preference to simple_$1\n" . $herecurr); - } -# check for __initcall(), use device_initcall() explicitly please - if ($line =~ /^.\s*__initcall\s*\(/) { - WARN("please use device_initcall() instead of __initcall()\n" . $herecurr); - } -# check for struct file_operations, ensure they are const. - if ($line !~ /\bconst\b/ && - $line =~ /\bstruct\s+(file_operations|seq_operations)\b/) { - WARN("struct $1 should normally be const\n" . - $herecurr); - } - -# use of NR_CPUS is usually wrong -# ignore definitions of NR_CPUS and usage to define arrays as likely right - if ($line =~ /\bNR_CPUS\b/ && - $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && - $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && - $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && - $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && - $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/) - { - WARN("usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); - } - -# check for %L{u,d,i} in strings - my $string; - while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { - $string = substr($rawline, $-[1], $+[1] - $-[1]); - $string =~ s/%%/__/g; - if ($string =~ /(?] []\n". - "\t-c\tc style\n". - "\t-e\emacs style (default)\n". - "\t-t\terse style (default)\n". - "\t\tfile name to open. If file not specified, uses hg diff\n\n", $name; - - exit -1; -} - -if (not getopts('cet',\%opt) or defined $opt{'h'}) { - usage($0); -} - -my $cmd=shift; - -if ($opt{'c'}) { - $c_syntax=1; -} - -if ($opt{'t'}) { - $fmt="--terse"; - $c_syntax=0; -} - -if ($cmd) { - $cmd="diff -upr /dev/null $cmd"; -} else { - $cmd="hg diff"; -} - -my $checkpatch=$ENV{CHECKPATCH}; - -if (!$checkpatch) { - $checkpatch="/lib/modules/`uname -r`/build/scripts/checkpatch.pl"; -} - -my $cp_version; -open IN,"$checkpatch|"; -while () { - tr/A-Z/a-z/; - if (m/version\s*:\s*([\d\.]+)/) { - $cp_version = $1; - } -} -close IN; - -my $intree_checkpatch = "scripts/checkpatch.pl --version "; -if (!open IN,"$intree_checkpatch|") { - $intree_checkpatch = "v4l/".$intree_checkpatch; - open IN,"$intree_checkpatch|"; -} -$intree_checkpatch =~ s/--version/--no-tree --strict/; - -while () { - tr/A-Z/a-z/; - if (m/version\s*:\s*([\d\.]+)/) { - if ($1 > $cp_version) { - print "# WARNING: $checkpatch version $cp_version is\n" - ."# older than $intree_checkpatch version" - ." $1.\n# Using in-tree one.\n#\n"; - $cp_version = $1; - $checkpatch = $intree_checkpatch; - } - } -} -close IN; - -open IN,"$cmd | $checkpatch -q --nosignoff $fmt -|"; - -my $err=""; -my $errline=""; -my $file=""; -my $ln_numb; - -my $pwd=`pwd`; -$pwd =~ s|/[^/]+\n$||; - -sub print_err() -{ - if ($err =~ m/LINUX_VERSION_CODE/) { - return; - } - - if ($err) { - printf STDERR "%s/%s: In '%s':\n", $pwd, $file, $errline; - printf STDERR "%s/%s:%d: %s\n", $pwd, $file, $ln_numb, $err; - $err=""; - } -} - -if ($c_syntax == 0) { - while () { - s|^#[\d]+:\s*FILE:\s*|../|; - print "$_"; - } -} else { - while () { - if (m/^\+(.*)\n/) { - $errline=$1; - } elsif (m/^\#\s*[\d]+\s*:\s*FILE:\s*([^\:]+)\:([\d]+)/) { - $file=$1; - $ln_numb=$2; - } elsif (m/^\-\s*\:\d+\:\s*(.*)\n/) { - print_err(); - $err = $1; - $err =~ s/WARNING/warning/; - } -# print "# $_"; - } -} -close IN; -print_err(); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.bttv v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.bttv --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.bttv 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.bttv 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -MDIR := v4l2 -snap := video4linux - -CONFIG_VIDEO_BTTV := m -CONFIG_VIDEO_CX88 := n -CONFIG_VIDEO_SAA7134 := n -CONFIG_VIDEO_IR := m -CONFIG_VIDEO_TUNER := m -CONFIG_VIDEO_TVAUDIO := m diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.cx88 v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.cx88 --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.cx88 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.cx88 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -MDIR := v4l2 -snap := video4linux - -CONFIG_VIDEO_BTTV := n -CONFIG_VIDEO_CX88 := m -CONFIG_VIDEO_SAA7134 := n -CONFIG_VIDEO_IR := n -CONFIG_VIDEO_TUNER := m -CONFIG_VIDEO_TVAUDIO := n diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.saa7134 v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.saa7134 --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.saa7134 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/config.saa7134 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -MDIR := v4l2 -snap := video4linux - -CONFIG_VIDEO_BTTV := n -CONFIG_VIDEO_CX88 := n -CONFIG_VIDEO_SAA7134 := m -CONFIG_VIDEO_IR := m -CONFIG_VIDEO_TUNER := m -CONFIG_VIDEO_TVAUDIO := m diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cx23885.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cx23885.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cx23885.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cx23885.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my %map = ( - "PCI_ANY_ID" => "0", -); - -sub fix_id($) { - my $id = shift; - $id = $map{$id} if defined($map{$id}); - $id =~ s/^0x//; - return $id; -} - -my $new_entry = -1; -my $nr = 0; -my ($id,$subvendor,$subdevice); -my %data; - -while (<>) { - # defines in header file - if (/#define\s+(CX23885_BOARD_\w+)\s+(\d+)/) { - $data{$1}->{nr} = $2; - next; - } - # cx88_boards - if (/\[(CX23885_BOARD_\w+)\]/) { - $id = $1; - $data{$id}->{id} = $id; -# $data{$id}->{nr} = $nr++; - }; - next unless defined($id); - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - } - - # cx88_pci_tbl - $subvendor = fix_id($1) if (/\.subvendor\s*=\s*(\w+),/); - $subdevice = fix_id($1) if (/\.subdevice\s*=\s*(\w+),/); - if (/.card\s*=\s*(\w+),/) { - if (defined($data{$1}) && - defined($subvendor) && $subvendor ne "0" && - defined($subdevice) && $subdevice ne "0") { - push @{$data{$1}->{subid}}, "$subvendor:$subdevice"; - undef $subvendor; - undef $subdevice; - } - } -} - -foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) { - printf("%3d -> %-51s", $data{$item}->{nr}, $data{$item}->{name}); - printf(" [%s]",join(",",@{$data{$item}->{subid}})) - if defined($data{$item}->{subid}); - print "\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cx88.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cx88.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cx88.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/cx88.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my %map = ( - "PCI_ANY_ID" => "0", - "PCI_VENDOR_ID_PHILIPS" => "1131", - "PCI_VENDOR_ID_ASUSTEK" => "1043", - "PCI_VENDOR_ID_MATROX" => "102B", - "PCI_VENDOR_ID_ATI" => "1002", -); - -sub fix_id($) { - my $id = shift; - $id = $map{$id} if defined($map{$id}); - $id =~ s/^0x//; - return $id; -} - -my $new_entry = -1; -my $nr = 0; -my ($id,$subvendor,$subdevice); -my %data; - -while (<>) { - # defines in header file - if (/#define\s+(CX88_BOARD_\w+)\s+(\d+)/) { - $data{$1}->{nr} = $2; - next; - } - # cx88_boards - if (/\[(CX88_BOARD_\w+)\]/) { - $id = $1; - $data{$id}->{id} = $id; -# $data{$id}->{nr} = $nr++; - }; - next unless defined($id); - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - } - - # cx88_pci_tbl - $subvendor = fix_id($1) if (/\.subvendor\s*=\s*(\w+),/); - $subdevice = fix_id($1) if (/\.subdevice\s*=\s*(\w+),/); - if (/.card\s*=\s*(\w+),/) { - if (defined($data{$1}) && - defined($subvendor) && $subvendor ne "0" && - defined($subdevice) && $subdevice ne "0") { - push @{$data{$1}->{subid}}, "$subvendor:$subdevice"; - undef $subvendor; - undef $subdevice; - } - } -} - -foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) { - printf("%3d -> %-51s", $data{$item}->{nr}, $data{$item}->{name}); - printf(" [%s]",join(",",@{$data{$item}->{subid}})) - if defined($data{$item}->{subid}); - print "\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/diffrev.sh v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/diffrev.sh --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/diffrev.sh 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/diffrev.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -#/bin/bash - -# Set default tree locations, if you want, at the shell ENV -#GIT_TREE=$HOME/v4l-dvb -#HG_TREE=$HOME/v4l-dvb-hg - -# Should be adjusted to the environment -TMP_TREE=/tmp/oldtree -KERNVER_FILE=./v4l/scripts/etc/kern_version -FIXPATCHES=./v4l/scripts/etc/fixdiffs/* -BLACKLIST=./v4l/scripts/etc/blacklist.txt -GENTREE=./v4l/scripts/gentree.pl - -if [ "$1" == "--strip-dead-code" ]; then - GENTREE_ARGS="$1" - shift -fi - -if [ "$2" != "" ]; then - # - # Two arguments were given. One tree should be hg and the other git - # - if [ -e $1/.hg/hgrc ]; then - HG_TREE=$1 - GIT_TREE=$2 - else - HG_TREE=$2 - GIT_TREE=$1 - fi -else - # - # If just one argument is selected, and it is called from one tree - # use the other argument for the other tree type - # otherwise, use default plus the given tree name - # - if [ "$1" != "" ]; then - if [ -e $1/.hg/hgrc ]; then - HG_TREE=$1 - if [ -e .git/config ]; then - GIT_TREE=. - fi - elif [ -e $1/.git/config ]; then - GIT_TREE=$1 - if [ -e .hg/hgrc ]; then - HG_TREE=. - fi - fi - fi -fi - -if [ "$GIT_TREE" == "" ]; then - echo "No git tree were provided." - ERROR=1 -fi - -if [ "$HG_TREE" == "" ]; then - echo "No mercurial tree were provided." - ERROR=1 -fi - -if [ "$ERROR" != "" ]; then - echo "Usage: $0 [--strip-dead-code] []" - exit -1 -fi - -if [ ! -e "$GIT_TREE/.git/config" ]; then - echo "$GIT_TREE is not a git tree. Should specify a git tree to compare with the $HG_TREE mercurial tree" - exit -1 -fi - -if [ ! -e "$HG_TREE/.hg/hgrc" ]; then - echo "$HG_TREE is not a mercurial tree. Should specify -hg tree to compare with the $GIT_TREE git tree" - exit -1 -fi - -echo "comparing $HG_TREE -hg tree with $GIT_TREE -git tree." - - -run() { - echo $@ - $@ -} - -echo removing oldtree.. -run rm -rf $TMP_TREE -echo creating an oldtree.. -run $GENTREE $GENTREE_ARGS `cat $KERNVER_FILE` $HG_TREE/linux $TMP_TREE >/dev/null - -echo applying the fix patches -for i in $FIXPATCHES; do - echo $i - run patch --no-backup-if-mismatch -R -d $TMP_TREE -p2 -i $i -s - diffstat -p1 $i -done - -echo removing rej/orig from $GIT_TREE -run find $GIT_TREE -name '*.rej' -exec rm '{}' \; -run find $GIT_TREE -name '*.orig' -exec rm '{}' \; - -echo removing rej/orig from oldtree -run find $TMP_TREE -name '*.rej' -exec rm '{}' \; -run find $TMP_TREE -name '*.orig' -exec rm '{}' \; - -echo generating "/tmp/diff" -diff -upr $TMP_TREE $GIT_TREE|grep -v ^Somente |grep -v ^Only>/tmp/diff -echo "generating /tmp/diff2 (loose diff0)" -diff -uprBw $TMP_TREE $GIT_TREE|grep -v Somente |grep -v ^Only>/tmp/diff2 -echo generating /tmp/somente2 for a complete oldtree-only files -diff -upr $TMP_TREE $GIT_TREE|grep ^Somente|grep "drivers/media" |grep -vr ".o$" |grep -v ".mod.c"|grep -v ".o.cmd" |grep -v modules.order >/tmp/somente2 -diff -upr $TMP_TREE $GIT_TREE|grep ^Only|grep "drivers/media" |grep -vr ".o$" |grep -v ".mod.c"|grep -v ".o.cmd" |grep -v modules.order >>/tmp/somente2 - -echo generating /tmp/somente for oldtree-only files -cp /tmp/somente2 /tmp/s$$ -for i in `cat $BLACKLIST`; do - cat /tmp/s$$ | grep -v "Somente.* $i" >/tmp/s2$$ - mv /tmp/s2$$ /tmp/s$$ -done -mv /tmp/s$$ /tmp/somente -echo -echo diffstat -p1 /tmp/diff -diffstat -p1 /tmp/diff diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/do_commit.sh v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/do_commit.sh --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/do_commit.sh 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/do_commit.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -#!/bin/bash - -EDITOR=$1 -WHITESPCE=$2 - -if [ "$WHITESPCE" == "" ]; then - exit 13 -fi - -TMPMSG=$1 - -scripts/cardlist -scripts/prep_commit_msg.pl $WHITESPCE > $TMPMSG - -#trap 'rm -rf $TMPMSG' EXIT - -CHECKSUM=`md5sum "$TMPMSG"` -$EDITOR $TMPMSG || exit $? -echo "$CHECKSUM" | md5sum -c --status && echo "*** commit message not changed. Aborting. ***" && exit 13 -DATE="`scripts/hghead.pl $TMPMSG|perl -ne 'if (m/\#[dD]ate:\s+(.*)/) { print $1; }'`" - -if [ "$DATE" != "" ]; then - echo Patch date is $DATE - scripts/hghead.pl $TMPMSG| grep -v '^#' | hg commit -d "$DATE" -l - -else - scripts/hghead.pl $TMPMSG| grep -v '^#' | hg commit -l - -fi - -if [ "$?" != "0" ]; then - echo "Couldn't apply the patch" - exit 13 -fi - -echo "*** PLEASE CHECK IF LOG IS OK:" -hg log -v -r -1 -echo "*** If not ok, do \"hg rollback\" and \"make commit\" again" diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/do_merge.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/do_merge.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/do_merge.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/do_merge.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,178 +0,0 @@ -#!/usr/bin/perl - -my $merge_tree=shift or die "Should specify the pulled tree"; - -sub hgrcuser($) -{ - my $file = shift; - my $ui = 0; - open IN, '<', $file; - while () { - $ui = 1 if (/^\s*\[ui\]/); - if ($ui && /^\s*username\s*=\s*(\S.*?)\s*$/) { - close IN; - return($1); - } - } - close IN; - return(""); -} - -sub check_heads() -{ - my $count=0; - open IN, 'hg heads|'; - while () { - if (m/^[Cc]hangeset:/) { - $count++; - } - } - close IN; - return $count; -} - -sub curr_changeset() -{ - my $changeset = -1; - - open IN, 'hg heads|'; - while () { - if (m/^[Cc]hangeset:\s*(\d+)/) { - if ($changeset < 0) { - $changeset = $1; - } else { - if ($1 < $changeset) { - $changeset = $1; - } - } - } - } - close IN; - return $changeset; -} - -sub check_status() -{ - my $count=0; - open IN, 'hg status -m -a -d -r|'; - while () { - $count++; - } - close IN; - return $count; -} - -sub rollback() -{ - print "*** ERROR *** Rolling back hg pull $merge_tree\n"; - system("hg rollback"); - system("hg update -C"); - exit -1; -} - -#################### -# Determine username - -# Get Hg username from environment -my $user = $ENV{HGUSER}; - -# Didn't work? Try the repo's .hgrc file -if ($user eq "") { - my $hgroot = `hg root`; - chomp($hgroot); - $user = hgrcuser("$hgroot/.hg/hgrc"); -} -# Ok, try ~/.hgrc next -if ($user eq "") { - $user = hgrcuser("$ENV{HOME}/.hgrc"); -} - -# Still no luck? Try some other environment variables -if ($user eq "") { - my $name = $ENV{CHANGE_LOG_NAME}; - my $email = $ENV{CHANGE_LOG_EMAIL_ADDRESS}; - $user = "$name <$email>" if ($name ne "" || $email ne ""); -} - -# Last try to come up with something -if ($user eq "") { - print "*** ERROR *** User not known. Can't procceed\n"; - exit -1; -} - -###################### -# Do some sanity tests - -print "Checking if everything is ok, before applying the new tree.\n"; - -my $n_heads = check_heads(); -die "Your tree currently have more than one head (it has $n_heads heads). Can't procceed\n" if ($n_heads > 1); - -my $dirty = check_status(); -die "Your tree currently has changes. Can't procceed\n" if ($dirty); - -my $curr_cs = curr_changeset(); - -########### -# Pull tree - -print "hg pull -u $merge_tree\n"; - -my $ret = system("hg pull $merge_tree"); -die "Couldn't pull from $merge_tree\n" if ($ret); - -############################# -# Merge and commit, if needed - -$n_heads = check_heads(); -if ($n_heads > 2) { - print "The merged tree have more than one head (it has $n_heads heads). Can't procceed.\n"; - rollback(); -} - -if ($n_heads == 2) { - print "Merging the new changesets\n"; - - $ret = system("hg merge"); - if ($ret) { - print "hg merge failed. Can't procceed.\n"; - rollback(); - } - - print "Committing the new tree\n"; - # Write the commit message - $msg= "merge: $merge_tree\n\nFrom: $user\n\nSigned-off-by: $user\n"; - $ret=system("hg commit -m '$msg'"); - if ($ret) { - print "hg commit failed. Can't procceed.\n"; - rollback(); - } -} - -##################### -# Test resulting tree - -print "Testing if the build didn't break compilation. Only errors and warnings will be displayed. Please wait.\n"; -$ret = system ('make allmodconfig'); -if (!ret) { - $ret = system ('make mismatch|egrep -v "^\s*CC"|egrep -v "^\s*LD"'); -} -if ($ret) { - print "*** ERROR *** Build failed. Can't procceed.\n"; - - # To avoid the risk of doing something really bad, let's ask the user to run hg strip - print "Your tree is dirty. Since hg has only one rollback level, you'll need to use, instead:"; - print "\thg strip $curr_cs; hg update -C"; - print "You'll need to have hg mq extension enabled for hg strip to work.\n"; - - exit -1; -} - -############################## -# Everything is ok, let's push - -print "Pushing the new tree at the remote repository specified at .hg/hgrc\n"; -$ret=system ("hg push"); -if ($ret) { - print "hg push failed. Don't forget to do the push later.\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/em28xx.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/em28xx.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/em28xx.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/em28xx.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my $new_entry = -1; -my $nr = 0; -my ($id,$subvendor,$subdevice); -my %data; - -my $debug = 0; - -while (<>) { - # defines in header file - if (/#define\s+(EM2[\d][\d][\d]_BOARD_[\w\d_]+)\s+(\d+)/) { - printf("$1 = $2\n") if ($debug); - $data{$1}->{nr} = $2; - next; - } - # em2820_boards - if (/\[(EM2820_BOARD_[\w\d_]+)\]/) { - $id = $1; - printf("ID = $id\n") if $debug; - $data{$id}->{id} = $id; - $data{$id}->{type} = "(em2820/em2840)"; -# $data{$id}->{nr} = $nr++; - } elsif (/\[(EM)(2[\d]..)(_BOARD_[\w\d_]+)\]/) { - $id = "$1$2$3"; - printf("ID = $id\n") if $debug; - $data{$id}->{id} = $id; - $data{$id}->{type} = "(em$2)"; -# $data{$id}->{nr} = $nr++; - }; - - next unless defined($id); - - if (/USB_DEVICE.*0x([0-9a-fA-F]*).*0x([0-9a-fA-F]*)/ ) { - $subvendor=$1; - $subdevice=$2; - } - - if (/.*driver_info.*(EM2[\d].._BOARD_[\w\d_]+)/ ) { - push @{$data{$1}->{subid}}, "$subvendor:$subdevice"; - } - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - if (defined $data{$id}->{name} && $debug) { - printf("name[$id] = %s\n", $data{$id}->{name}); - } - } - - # em2820_USB_tbl - - -} - -foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) { - printf("%3d -> %-40s %-15s", $data{$item}->{nr}, $data{$item}->{name}, $data{$item}->{type}); - printf(" [%s]",join(",",@{$data{$item}->{subid}})) - if defined($data{$item}->{subid}); - print "\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/blacklist.txt v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/blacklist.txt --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/blacklist.txt 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/blacklist.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -\.orig -\.rej -\.cvsignore -bt87x.c -i2c-compat.h -at76c651[.][ch] -tda80xx[.][ch] -tvmixer.c -aci.[ch] -btaudio.c -dvb-ttusb-dspbootcode.h -cpia2patch.h -dabfirmware.h -^firmware/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/fixdiffs/98.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/fixdiffs/98.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/fixdiffs/98.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/fixdiffs/98.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ - -diff -upr oldtree/drivers/media/dvb/dvb-core/dvb_net.c /home/v4l/tokernel/wrk/linux-next/drivers/media/dvb/dvb-core/dvb_net.c ---- next/drivers/media/dvb/dvb-core/dvb_net.c 2010-01-15 19:05:35.000000000 -0200 -+++ ../oldtree/drivers/media/dvb/dvb-core/dvb_net.c 2010-01-15 19:11:43.000000000 -0200 -@@ -949,11 +949,8 @@ static int dvb_net_filter_sec_set(struct - (*secfilter)->filter_mask[10] = mac_mask[1]; - (*secfilter)->filter_mask[11]=mac_mask[0]; - -+ dprintk("%s: filter mac=%pM\n", dev->name, mac); -+ dprintk("%s: filter mask=%pM\n", dev->name, mac_mask); -- dprintk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n", -- dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); -- dprintk("%s: filter mask=%02x %02x %02x %02x %02x %02x\n", -- dev->name, mac_mask[0], mac_mask[1], mac_mask[2], -- mac_mask[3], mac_mask[4], mac_mask[5]); - - return 0; - } diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/fixdiffs/99.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/fixdiffs/99.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/fixdiffs/99.patch 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/fixdiffs/99.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -Whitespace cleanup - ---- git/sound/pci/bt87x.c 2007-10-16 23:42:25.000000000 -0200 -+++ ../oldtree/sound/pci/bt87x.c 2007-10-17 12:46:18.000000000 -0200 -@@ -122,8 +122,8 @@ MODULE_PARM_DESC(load_all, "Allow to loa - /* RISC instruction bits */ - #define RISC_BYTES_ENABLE (0xf << 12) /* byte enable bits */ - #define RISC_RESYNC ( 1 << 15) /* disable FDSR errors */ --#define RISC_SET_STATUS_SHIFT 16 /* set status bits */ --#define RISC_RESET_STATUS_SHIFT 20 /* clear status bits */ -+#define RISC_SET_STATUS_SHIFT 16 /* set status bits */ -+#define RISC_RESET_STATUS_SHIFT 20 /* clear status bits */ - #define RISC_IRQ ( 1 << 24) /* interrupt */ - #define RISC_EOL ( 1 << 26) /* end of line */ - #define RISC_SOL ( 1 << 27) /* start of line */ -@@ -226,7 +226,7 @@ static inline void snd_bt87x_writel(stru - } - - static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substream *substream, -- unsigned int periods, unsigned int period_bytes) -+ unsigned int periods, unsigned int period_bytes) - { - struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); - unsigned int i, offset; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/kern_version v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/kern_version --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/kern_version 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/etc/kern_version 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -2.6.33 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/fix_dvb_customise.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/fix_dvb_customise.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/fix_dvb_customise.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/fix_dvb_customise.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,335 +0,0 @@ -#!/usr/bin/perl -use strict; -use warnings; -use File::Find; -use Fcntl ':mode'; - -my $debug = 0; - -my $SRC = "../linux"; -my $fname = "$SRC/drivers/media/dvb/frontends/Makefile"; - -#################### -# Get Makefile rules -# -sub get_makefile($) -{ - my $file = shift; - my %rules; - my %composite; - - open IN, $file or die "Can't find $file\n"; - while () { - # Handle line continuations - if (/\\\n$/) { - $_ .= ; - redo; - } - # Eat line continuations in string we will parse - s/\s*\\\n\s*/ /g; - - if (m/(^\s*[[\da-zA-Z-_]+)-objs\s*[\:\+]*\=\s*(.*)\n/) { - my $dep=$1; - my $file = $2; - $file =~ s/\.o / /g; - $file =~ s/\.o$//; - - if ($file eq "") { - die "broken dep on file $file for $dep\n"; - } - - $composite{$dep} = $file; - printf "MULTI: $dep = $file\n" if ($debug > 1); - } - - if (m/^\s*obj\-\$\(CONFIG_([^\)]+)\)\s*[\:\+]*\=\s*(.*)\n/) { - my $rule = $1; - my $file = $2; - - $file =~ s/\.o / /g; - $file =~ s/\.o$//; - - $rules{$rule} = $file; - printf "RULE: $rule = $file\n" if ($debug > 1); - } - } - close IN; - - return (\%rules, \%composite); -} - -########################### -# Seeks header dependencies -# -my %header_deps; - -# For a more complete check, use: -# my $hfiles = "*.c"; -my $hfiles = "av7110_av.c av7110.c av7110_ca.c av7110_hw.c av7110_ipack.c av7110_ir.c av7110_v4l.c budget-patch.c dvb_ringbuffer.c nova-t-usb2.c umt-010.c"; - -sub get_header_deps() -{ - my $file = shift; - my %rules; - my %composite; - - open IN, "gcc -I ../linux/include -I . -DCONFIG_PCI -D__LITTLE_ENDIAN -D_COMPAT_H -DKERNEL_VERSION\\(a,b,c\\) -MM $hfiles|"; - while () { - # Handle line continuations - if (/\\\n$/) { - $_ .= ; - redo; - } - # Eat line continuations in string we will parse - s/\s*\\\n\s*/ /g; - - if (m/^([^\:]+)\s*\:\s*(.*)/) { - my $dep = $1; - my $file = $2; - - $dep =~ s|.*/||; - $dep =~ s/\.o$//; - - my @files = split(/\s/, $file); - foreach my $f (@files) { - $f =~ s|.*/||; - - if (!defined($header_deps{$f})) { - $header_deps{$f} = $dep; - } else { - $header_deps{$f} .= " " . $dep; - } - - } - } - } - close IN; - - if ($debug > 1) { - print "Header deps for: "; - print "$_ " foreach %header_deps; - print "\n"; - } -} - - -########################### -# Seeks files for Makefiles -# - -my %driver_config; - -sub parse_makefiles() -{ - my $fname = $File::Find::name; - - return if !($fname =~ m|/Makefile$|); - return if ($fname =~ m|drivers/media/dvb/frontends/|); - - - my ($refs, $mult) = get_makefile($fname); - - foreach my $ref (keys %$refs) { - my $file=$$refs{$ref}; - - my @files = split(/\s/, $file); - foreach my $f (@files) { - if (defined($$mult{$f})) { - $file .= " " . $$mult{$f}; - } - } - - $file =~ s|/||g; - - @files = split(/\s/, $file); - foreach my $f (@files) { - $driver_config{$f} = $ref; - } - if ($debug > 1) { - print "$ref = "; - print "$_ " foreach @files; - print "\n"; - } - } -} - - -######################## -# Seeks files for header -# -my %select; - -sub found_ref($$) -{ - my $file = shift; - my $header = shift; - my $found = 0; - my $name = $file; - $name =~ s|.*/||; - - $name =~ s/flexcop-fe-tuner.c/b2c2-flexcop/; - $name =~ s/av7110.c/av7110.h/; - - if (defined ($header_deps{$name})) { - $name = $header_deps{$name}; - } else { - $name =~ s/\.[ch]$//; - } - - my @files = split(/\s/, $name); - foreach my $n (@files) { - if (defined($driver_config{$n})) { - my $ref = $driver_config{$n}; - printf "$ref needs %s\n", $header if ($debug); - - if ($ref =~ m/(PVRUSB2|CX23885|CX88|EM28XX|SAA3134 - |SAA7164)/) { - $ref .="_DVB"; - } - - if (!defined($select{$ref})) { - $select{$ref} = $header; - } else { - $select{$ref} .= " " . $header; - } - $found = 1; - } - } - - if (!$found) { - printf "$file needs %s\n", $header; - } -} - -######################## -# Seeks files for header -# - -my %header; - -sub parse_headers() -{ - my $file = $File::Find::name; - - return if !($file =~ m/\.[ch]$/); - return if ($file =~ m|drivers/media/dvb/frontends/|); - - open IN, $file or die "Can't open $file\n"; - while () { - if (m/^\s*\#include\s+\"([^\"]+)\"/) { - if (defined($header{$1})) { - my $head = $header{$1}; - found_ref ($file, $head); - } - } - } - close IN; -} - -######################## -# Rewrite Kconfig's -# - -sub parse_kconfigs() -{ - my $file = $File::Find::name; - my $conf; - my $out = ""; - my $tmp = ""; - my $all_sels; - - return if !($file =~ m/Kconfig$/); - return if ($file =~ m|drivers/media/dvb/frontends/|); - - open IN, $file or die "Can't open $file\n"; - while () { - if (m/^config\s([A-Za-z_\-\d]+)/) { - $out .= $tmp; - if (defined($select{$1})) { - $conf = $select{$1}; - $all_sels = " ". $conf. " "; - $tmp = $_; - - printf "$file: rewriting headers for $1. It should select: %s\n", $all_sels if ($debug); - } else { - $conf = ""; - $out .= $_; - $tmp = ""; - } - next; - } - if (!$conf) { - $out .= $_; - next; - } - - if (m/^\s*select\s+([A-Za-z_\-\d]+)/) { - my $op = $1; - - if (!$all_sels =~ m/\s($op)\s/) { - # Drops line - printf "$file: droppingg line $_\n"; - - next; - } else { - $all_sels =~ s/\s($op)\s/ /; - } - } - if (m/^[\s\-]*help/) { - my @sel = split(/\s/, $all_sels); - foreach my $s (@sel) { - if ($s ne "") { - printf "$file: Adding select for $s\n"; - $tmp .= "\tselect $s if !DVB_FE_CUSTOMISE\n"; - } - } - } - $tmp .= $_; - } - close IN; - - $out .=$tmp; - open OUT, ">$file" or die "Can't open $file\n"; - print OUT $out; - close OUT; -} - -##### -#main - -get_header_deps(); - -my ($FEs, $mult) = get_makefile($fname); - -foreach my $fe (keys %$FEs) { - my $file=$$FEs{$fe}; - my $found = 0; - - # Special cases - $file =~ s/tda10021/tda1002x/; - $file =~ s/tda10023/tda1002x/; - $file =~ s/dib3000mb/dib3000/; - - if (defined($$mult{$file})) { - $file .= " ".$$mult{$file}; - } - - my @files = split(/\s/, $file); - foreach my $f (@files) { - if (stat("$f.h")) { - printf "$fe = $f.h\n" if ($debug); - $found = 1; - $header {"$f.h"} = $fe; - last; - } - } - - if (!$found) { - printf "$file.h ($fe) not found in $file\n"; - exit -1; - } -} - -find({wanted => \&parse_makefiles, no_chdir => 1}, $SRC); -find({wanted => \&parse_headers, no_chdir => 1}, $SRC); -find({wanted => \&parse_kconfigs, no_chdir => 1}, $SRC); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/fix_kconfig.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/fix_kconfig.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/fix_kconfig.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/fix_kconfig.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -#!/usr/bin/perl -use strict; - -my $need_changes = 0; -my $out; - -open IN, '<.config'; -while () { - s/CONFIG_VIDEO_CX88_MPEG=y/CONFIG_VIDEO_CX88_MPEG=m/ and $need_changes=1; - $out .= $_; -} -close IN; - -if ($need_changes) { - printf("There's a known bug with the building system with this kernel. Working around.\n"); - open OUT, '>.config'; - print OUT $out; - close OUT; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/gentree.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/gentree.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/gentree.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/gentree.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,264 +0,0 @@ -#!/usr/bin/perl -# -# Original version were part of Gerd Knorr's v4l scripts. -# -# Several improvements by (c) 2005-2007 Mauro Carvalho Chehab -# -# Largely re-written (C) 2007 Trent Piepho -# -# Theory of Operation -# -# This acts as a sort of mini version of cpp, which will process -# #if/#elif/#ifdef/etc directives to strip out code used to support -# multiple kernel versions or otherwise not wanted to be sent upstream to -# git. -# -# Conditional compilation directives fall into two catagories, -# "processed" and "other". The "other" directives are ignored and simply -# output as they come in without changes (see 'keep' exception). The -# "processed" variaty are evaluated and only the lines in the 'true' part -# are kept, like cpp would do. -# -# If gentree knows the result of an expression, that directive will be -# "processed", otherwise it will be an "other". gentree knows the value -# of LINUX_VERSION_CODE, BTTV_VERSION_CODE, the KERNEL_VERSION(x,y,z) -# macro, numeric constants like 0 and 1, and a few defines like -# I2C_CLASS_TV_DIGITAL -# -# An exception is if the comment "/*KEEP*/" appears after the expression, -# in which case that directive will be considered an "other" and not -# processed, other than to remove the keep comment. -# -# Known bugs: -# don't specify the root directory e.g. '/' or even '////' -# directives continued with a back-slash will always be ignored -# you can't modify a source tree in-place, i.e. source dir == dest dir - -use strict; -use File::Find; -use Fcntl ':mode'; -use Getopt::Long; - -my $DEBUG = 0; -my $dead_code = 0; - -GetOptions( "--debug" => \$DEBUG, - "--strip-dead-code" => \$dead_code ); - -my $VERSION = shift; -my $SRC = shift; -my $DESTDIR = shift; -my $BTTVCODE = KERNEL_VERSION(0,9,17); -my ($LINUXCODE, $extra) = kernel_version($VERSION); - -if (!defined($DESTDIR)) { - print "Usage:\ngentree.pl\t[--debug] \n\n"; - exit; -} - -my %defs = ( - 'LINUX_VERSION_CODE' => $LINUXCODE, - 'BTTV_VERSION_CODE' => $BTTVCODE, - '_COMPAT_H' => 0, - 'I2C_CLASS_TV_ANALOG' => 1, - 'I2C_CLASS_TV_DIGITAL' => 1, - 'OLD_XMIT_LOCK' => 0, - 'COMPAT_SND_CTL_BOOLEAN_MONO' => 0, - 'NEED_SOUND_DRIVER_H' => 0, - 'TTUSB_KERNEL' => 1, - 'NO_PCM_LOCK' => 0, - 'NEED_ALGO_CONTROL' => 0, -); - -################################################################# -# helpers - -sub kernel_version($) { - $_[0] =~ m/(\d+)\.(\d+)\.(\d+)(.*)/; - return ($1*65536 + $2*256 + $3, $4); -} - -# used in eval() -sub KERNEL_VERSION($$$) { return $_[0]*65536 + $_[1]*256 + $_[2]; } - -sub evalexp($) { - local $_ = shift; - s|/\*.*?\*/||go; # delete /* */ comments - s|//.*$||o; # delete // comments - s/\bdefined\s*\(/(/go; # defined(foo) to (foo) - while (/\b([_A-Za-z]\w*)\b/go) { - if (exists $defs{$1}) { - my $id = $1; my $pos = $-[0]; - s/$id/$defs{$id}/; - pos = $-[0]; - } elsif ($1 ne 'KERNEL_VERSION') { - return(undef); - } - } - return(eval($_) ? 1 : 0); -} - -################################################################# -# filter out version-specific code - -sub filter_source ($$) { - my ($in,$out) = @_; - my $line; - my $level=0; - my %if = (); - my %state = (); - - my @dbgargs = \($level, %state, %if, $line); - sub dbgline($\@) { - my $level = ${$_[1][0]}; - printf STDERR ("/* BP %4d $_[0] state=$_[1][1]->{$level} if=$_[1][2]->{$level} level=$level (${$_[1][3]}) */\n", $.) if $DEBUG; - } - - open IN, '<', $in or die "Error opening $in: $!\n"; - open OUT, '>', $out or die "Error opening $out: $!\n"; - - print STDERR "File: $in, for kernel $VERSION($LINUXCODE)/\n" if $DEBUG; - - while ($line = ) { - chomp $line; - next if ($line =~ m/^#include \"compat.h\"/o); -# next if ($line =~ m/[\$]Id:/); - - # For "#if 0 /*KEEP*/;" the ; should be dropped too - if ($line =~ m@^\s*#\s*if(n?def)?\s.*?(\s*/\*\s*(?i)keep\s*\*/;?)@) { - $state{$level} = "ifother"; - $if{$level} = 1; - dbgline "#if$1 (keep)", @dbgargs; - $line =~ s/\Q$2\E//; - $level++; - } - # preserve #if 0/#if 1, if $dead_code = 0 - elsif (!$dead_code && $line =~ m@^\s*#\s*if\s*([01])[^\d]@) { - $state{$level} = "ifother"; - $if{$level} = 1; - dbgline "#if $1", @dbgargs; - $level++; - } - # handle all ifdef/ifndef lines - elsif ($line =~ /^\s*#\s*if(n?)def\s*(\w+)/o) { - if (exists $defs{$2}) { - $state{$level} = 'if'; - $if{$level} = ($1 eq 'n') ? !$defs{$2} : $defs{$2}; - dbgline "#if$1def $2", @dbgargs; - $level++; - next; - } - $state{$level} = "ifother"; - $if{$level} = 1; - dbgline "#if$1def (other)", @dbgargs; - $level++; - } - # handle all ifs - elsif ($line =~ /^\s*#\s*if\s+(.*)$/o) { - my $res = evalexp($1); - if (defined $res) { - $state{$level} = 'if'; - $if{$level} = $res; - dbgline '#if '.($res?'(yes)':'(no)'), @dbgargs; - $level++; - next; - } else { - $state{$level} = 'ifother'; - $if{$level} = 1; - dbgline '#if (other)', @dbgargs; - $level++; - } - } - # handle all elifs - elsif ($line =~ /^\s*#\s*elif\s+(.*)$/o || $line =~ /^\s*#\s*elseif\s+(.*)$/o) { - my $exp = $1; - $level--; - $level < 0 and die "more elifs than ifs"; - $state{$level} =~ /if/ or die "unmatched elif"; - - if ($state{$level} eq 'if' && !$if{$level}) { - my $res = evalexp($exp); - defined $res or die 'moving from if to ifother'; - $state{$level} = 'if'; - $if{$level} = $res; - dbgline '#elif1 '.($res?'(yes)':'(no)'), @dbgargs; - $level++; - next; - } elsif ($state{$level} ne 'ifother') { - $if{$level} = 0; - $state{$level} = 'elif'; - dbgline '#elif0', @dbgargs; - $level++; - next; - } - $level++; - } - elsif ($line =~ /^\s*#\s*else/o) { - $level--; - $level < 0 and die "more elses than ifs"; - $state{$level} =~ /if/ or die "unmatched else"; - $if{$level} = !$if{$level} if ($state{$level} eq 'if'); - $state{$level} =~ s/^if/else/o; # if -> else, ifother -> elseother, elif -> elif - dbgline '#else', @dbgargs; - $level++; - next if $state{$level-1} !~ /other$/o; - } - elsif ($line =~ /^\s*#\s*endif/o) { - $level--; - $level < 0 and die "more endifs than ifs"; - dbgline '#endif', @dbgargs; - next if $state{$level} !~ /other$/o; - } - - my $print = 1; - for (my $i=0;$i<$level;$i++) { - next if $state{$i} =~ /other$/o; # keep code in ifother/elseother blocks - if (!$if{$i}) { - $print = 0; - dbgline 'DEL', @{[\$i, \%state, \%if, \$line]}; - last; - } - } - print OUT "$line\n" if $print; - } - close IN; - close OUT; -} - -################################################################# - -sub parse_dir { - my $file = $File::Find::name; - - return if ($file =~ /CVS/); - return if ($file =~ /~$/); - - my $f2 = $file; - $f2 =~ s/^\Q$SRC\E/$DESTDIR/; - - my $mode = (stat($file))[2]; - if ($mode & S_IFDIR) { - print("mkdir -p '$f2'\n"); - system("mkdir -p '$f2'"); # should check for error - return; - } - print "from $file to $f2\n"; - - if ($file =~ m/.*\.[ch]$/) { - filter_source($file, $f2); - } else { - system("cp $file $f2"); - } -} - - -# main - -printf "kernel is %s (0x%x)\n",$VERSION,$LINUXCODE; - -# remove any trailing slashes from dir names. don't pass in just '/' -$SRC =~ s|/*$||; $DESTDIR =~ s|/*$||; - -print "finding files at $SRC\n"; - -find({wanted => \&parse_dir, no_chdir => 1}, $SRC); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/headers_convert.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/headers_convert.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/headers_convert.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/headers_convert.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -#!/usr/bin/perl -# -# headers_install prepare the listed header files for use in -# user space and copy the files to their destination. -# - -use strict; -use warnings; - -foreach (@ARGV) { - my $file = $_; - my $tmpfile = $file . ".tmp"; - - open(my $infile, '<', "$file") - or die "$file: $!\n"; - open(my $outfile, '>', "$tmpfile") or die "$tmpfile: $!\n"; - while (my $line = <$infile>) { - $line =~ s/([\s(])__user\s/$1/g; - $line =~ s/([\s(])__force\s/$1/g; - $line =~ s/([\s(])__iomem\s/$1/g; - $line =~ s/\s__attribute_const__\s/ /g; - $line =~ s/\s__attribute_const__$//g; - $line =~ s/^#include //; - printf $outfile "%s", $line; - } - close $outfile; - close $infile; - system "mv $tmpfile $file"; -} -exit 0; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/hghead.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/hghead.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/hghead.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/hghead.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,221 +0,0 @@ -#!/usr/bin/perl -use strict; - -################################################################# -# analyse diffs - -my $in = shift; -my $line; -my $subject; -my $sub_ok=0; -my $init=0; -my $num=0; -my $hgimport=0; -my $mmimport=0; -my $maint_ok=0; -my $noblank=1; -my $maintainer_name=$ENV{CHANGE_LOG_NAME}; -my $maintainer_email=$ENV{CHANGE_LOG_EMAIL_ADDRESS}; -my $from=""; -my $body=""; -my $priority=""; -my $signed=""; -my $fromname=""; - -open IN, "<$in"; - -while ($line = ) { - if ($line =~ m/^\s*Index.*/) { - last; - } - if ($line =~ m/^diff .*/) { - last; - } - if ($line =~ m/^\-\-\- .*/) { - last; - } - if ($line =~ m/^\-\-\-\-.*/) { - $body=""; - next; - } - if ($line =~ m/^\-\-\-.*/) { - last; - } - if ($line =~ m/^\+\+\+ .*/) { - last; - } - - if ($line =~ m/^#\s*Date\s*(.*)/) { - print "#Date: $1\n"; - next; - } - - if ($line =~ m/^Date:\s*(.*)/) { - print "#Date: $1\n"; - next; - } - - $line =~ s/^#\sUser/From:/; - - my $tag=$line; - my $arg=$line; - $tag =~ s/\s*([^\s]+:)\s*(.*)\n/\1/; - $arg =~ s/\s*([^\s]+:)\s*(.*)\n/\2/; - - $tag =~ tr/A-Z/a-z/; - - if ($tag =~ m/^from:/) { - if ($arg =~ m/^[\s\"]*([^\"]*)[\s\"]*<(.*)>/) { - if ($1 eq "") { - next; - } - my $name=$1; - my $email=$2; - $name =~ s/\s+$//; - $email =~ s/\s+$//; - $fromname="$name <$email>"; - $from= "From: $fromname\n"; - next; - } - if ($line =~ m/^From:\sakpm\@osdl.org/) { - $mmimport=1; - next; - } - print "Bad: author line have a wrong syntax: $line\n"; - die; - } - - if ($tag =~ m/^subject:/) { - $subject = "$arg\n"; - $sub_ok = 1; - next; - } - - if ($tag =~ m/^priority:/) { - $arg =~ tr/A-Z/a-z/; - - # Replace the -git branch names for high/normal/low - $arg =~ s/^fixes$/high/; - $arg =~ s/^fix$/high/; - $arg =~ s/^working$/normal/; - $arg =~ s/^work$/normal/; - $arg =~ s/^pending$/low/; - $priority = "Priority: $arg"; - next; - } - - if ($line =~ m;^ .*\/.*\| *[0-9]*;) { - next; - } - if ($line =~m/\d+\s*file.* changed, /) { - next; - } - - if ($tag =~ m/^signed-off-by:.*/) { - $noblank=1; - if ($line =~ m/$maintainer_name/) { - $maint_ok=1; - } - - $signed="$signed$line"; - next; - } - if ( ($line =~ m/^\# HG changeset patch/) || - ($line =~ m/^has been added to the -mm tree. Its filename is/) ) { - $sub_ok=0; - $init=0; - $num=0; - $maint_ok=0; - $noblank=1; - $from=""; - $body=""; - $subject=""; - $hgimport=1; - next; - } - - if ($tag =~ m/^(acked-by|thanks-to|reviewed-by|noticed-by|tested-by|cc):/) { - $signed="$signed$line"; - next; - } - - # Keep review lines together with the signatures - if ($line =~ m/^\[.*\@.*\:.*\]\n/) { - $signed="$signed$line"; - next; - } - - if ($tag =~ m/changeset:\s*(.*)\n/) { - $num=$1; - } - - if ($line =~ m|^(V4L\/DVB\s*\(.+\)\s*:.*\n)|) { - $subject=$1; - $sub_ok = 1; - $line="\n"; - } - - if ($line =~ m/^#/) { - next; - } - if ($sub_ok == 0) { - if ($line =~ m/^\s*\n/) { - next; - } - $sub_ok=1; - if ($subject =~ m|V4L\/DVB\s*(.+)|) { - $subject=$1; - } - $subject=$line; - next; - } - - if ($noblank) { - if ($line =~ m/^\n/) { - next; - } - } - if (!$init) { - $init=1; - $noblank=0; - } - $body="$body$line"; -} -close IN; - -if ($from eq "") { - print "Bad: author doesn't exist!\n"; - die; -} - -if (!$maint_ok && $maintainer_name && $maintainer_email) { - print "#No maintainer's signature. Adding it.\n"; - $signed=$signed."Signed-off-by: $maintainer_name <$maintainer_email>\n"; -} - -if (!$signed =~ m/$from/) { - print "Bad: Author didn't signed his patch!\n"; - die; -} - -$from=~s/^[\n\s]+//; -$from=~s/[\n\s]+$//; - -$subject=~s/^[\n\s]+//; -$subject=~s/[\n\s]+$//; - -$body=~s/^[\n]+//; -$body=~s/[\n\s]+$//; - -if ($priority ne "") { - $body="$body\n\n$priority"; -} - -$body="$body\n\n$signed"; - -$body=~s/^[\n\s]+//; -$body=~s/[\n\s]+$//; - -# First from is used by hg to recognize commiter name -print "#Committer: $maintainer_name <$maintainer_email>\n"; -print "$subject\n\n$from\n\n$body\n"; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/hg-pull-req.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/hg-pull-req.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/hg-pull-req.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/hg-pull-req.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -#!/usr/bin/perl - -# Copyright (C) 2006 Trent Piepho -# Automatic pull request generator - -# Generates a pull request for all changesets in current Hg repository, that -# do not appear in a remote repository. -# -# There are _three_ repositories involved in this operation. -# -# The first is the remote repository that you want your changes to be pulled -# into. The default is the master repository at -# http://linuxtv.org/hg/v4l-dvb, but you can specify something else if you -# want. This repository is called the "to repo". -# -# The next two repositories should be copies of each other. The first is your -# local repository. You must run this script from some directory in that -# repository. The second repository is a remote copy on some public server, -# e.g. linuxtv.org. This is called the "from repo". The default for the from -# repo is the "default-push" path from the Hg configuration, which is where hg -# will push to if you don't specify a path to "hg push". The script will do -# some checks to make sure these two repositories are copies of each other. -# -# The repository used to the changesets are comming from is local repository, -# due to Mercurial's limitations. However, links to your local repository -# would be useless in a pull request, because no one else can see your local -# repository. So, the links are change to use the "from repo" instead. This -# is why your local repo and the from repo must be copies of each other. -# Running "hg push" before generating the pull request should be enough. - -$maintainer = 'Mauro'; -$to_repo = 'http://linuxtv.org/hg/v4l-dvb'; -# Default for when a default-push path wasn't defined -$from_repo_base = 'http://linuxtv.org/hg/~username/'; - -# What to open for the pull request -$output_file = '>&STDOUT'; -# Example, to a local file: '>pull_req' -# Example, file on remote host: '|ssh remote.host.com cat \\> pull_req' - -# Text of the pull request. $nstr is e.g. "changeset" or "42 changesets" -$salutation = <<'EOF'; -$maintainer, - -Please pull from $from_repo - -for the following $nstr: - -EOF - -# The closing of the request, name and fname taken from hg username setting -$valediction = <<'EOF'; - -Thanks, -$fname -EOF - -if($#ARGV < 0) { - if(`hg showconfig paths` =~ m/^paths\.default-push=(.*)$/m) { - $from_repo = $1; - $from_repo =~ s/^ssh:/http:/; - } else { - `hg root` =~ m|/([^/]+)\n$|; - my $repo = $1; - $from_repo = $from_repo_base . $repo; - } -} - -$from_repo = $ARGV[0] if($#ARGV >= 0); -$to_repo = $ARGV[1] if($#ARGV >= 1); - -open OUT, $output_file or die "Opening: $!"; - -if (`hg outgoing $from_repo` !~ /^no changes found$/m || - `hg incoming $from_repo` !~ /^no changes found$/m) { - my $cur = `hg root`; chomp $cur; - print "$cur and $from_repo do not match!\n"; - print "Prehaps you forgot to push your changes?\n"; - exit; -} - -open IN, "hg outgoing -M $to_repo |"; -while() { - if(/^changeset:\s+\d+:([[:xdigit:]]{12})$/) { - push @changesets, $1; - } elsif(/^summary:\s+(\S.*)$/) { - if ($1 =~ /^merge:/) { - # Skip merge changesets - pop @changesets; - } else { - push @summaries, $1; - } - } -} -close IN; -$#changesets == $#summaries or die "Confused by hg outgoing output"; - -foreach (0 .. $#summaries) { - if($summaries[$_] =~ /^merge:/) { - splice @summaries, $_, 1; - splice @changesets, $_, 1; - } -} - -$n = $#changesets + 1; -$n > 0 or die "Nothing to pull!"; -$nstr = ($n==1)?"changeset":"$n changesets"; - -print OUT eval qq("$salutation"); - -for (0 .. $#summaries) { - printf OUT "%02d/%02d: $summaries[$_]\n", $_+1, $n; - print OUT "$from_repo?cmd=changeset;node=$changesets[$_]\n"; - print OUT "\n"; -} - -print OUT "\n"; - -open IN, 'hg export ' . join(' ', @changesets) . '| diffstat |'; -print OUT while(); -close IN; - -`hg showconfig ui.username` =~ m/((\S+).*)\s+ "0", - "PCI_VENDOR_ID_PHILIPS" => "1131", - "PCI_VENDOR_ID_ASUSTEK" => "1043", - "PCI_VENDOR_ID_MATROX" => "102B", - "PCI_VENDOR_ID_ATI" => "1002", -); - -sub fix_id($) { - my $id = shift; - $id = $map{$id} if defined($map{$id}); - $id =~ s/^0x//; - return $id; -} - -open ($input, "../saa7134-cards.c"); - -print ("\n"); -print ("1131 Philips Semiconductors\n"); - -my %data; - -while (<$input>) { - - if (/\[(SAA7134_BOARD_\w+)\]/) { - $id = $1; - $data{$id}->{id} = $id; - $data{$id}->{subvendor} = "0"; - }; - next unless defined($id); - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - } - - # saa7134_pci_tbl - $device = $1 if (/\.device\s*=\s*(\w+),/); - $subvendor = fix_id($1) if (/\.subvendor\s*=\s*(\w+),/); - $subdevice = fix_id($1) if (/\.subdevice\s*=\s*(\w+),/); - if (/.driver_data\s*=\s*(\w+),/) { - if (defined($data{$1}) && - defined($subvendor) && $subvendor ne "0" && - defined($subdevice) && $subdevice ne "0" && - defined($device)) { - $data{$1}->{device} = $device; - $data{$1}->{subvendor} = $subvendor; - $data{$1}->{subdevice} = $subdevice; - undef $device; - undef $subvendor; - undef $subdevice; - } - } -} - -sub print_cards ($) { - my $filter = shift; - foreach my $item (sort {$data{$a}->{subvendor} cmp $data{$b}->{subvendor}} keys (%data)) - { - if (defined ($data{$item}->{device}) && ($data{$item}->{device} eq $filter)) { - printf("\t\t"); - printf("%s %s %s", $data{$item}->{subvendor}, $data{$item}->{subdevice}, $data{$item}->{name}); - print "\n"; - } - } -} - -print ("\t7130 SAA7130 Video Broadcast Decoder\n"); -print_cards ("PCI_DEVICE_ID_PHILIPS_SAA7130"); -print ("\t7133 SAA7133/SAA7135 Video Broadcast Decoder\n"); -print_cards ("PCI_DEVICE_ID_PHILIPS_SAA7133"); -print ("\t7134 SAA7134 Video Broadcast Decoder\n"); -print_cards ("PCI_DEVICE_ID_PHILIPS_SAA7134"); - -open ($input, "../cx88-cards.c"); - -%data=(); - -while (<$input>) { - if (/\[(CX88_BOARD_\w+)\]/) { - $id = $1; - $data{$id}->{id} = $id; - $data{$id}->{subvendor} = "0"; - }; - next unless defined($id); - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - } - - $subvendor = fix_id($1) if (/\.subvendor\s*=\s*(\w+),/); - $subdevice = fix_id($1) if (/\.subdevice\s*=\s*(\w+),/); - if (/.card\s*=\s*(\w+),/) { - if (defined($data{$1}) && - defined($subvendor) && $subvendor ne "0" && - defined($subdevice) && $subdevice ne "0") { - $data{$1}->{subvendor} = $subvendor; - $data{$1}->{subdevice} = $subdevice; - undef $subvendor; - undef $subdevice; - } - } -} - -print ("14f1 Conexant\n"); -print ("\t8800 CX23880/1/2/3 PCI Video and Audio Decoder\n"); - -foreach my $item (sort {$data{$a}->{subvendor} cmp $data{$b}->{subvendor}} keys (%data)) -{ - if (defined ($data{$item}->{subdevice}) && ($data{$item}->{subvendor} ne "0")) { - printf("\t\t"); - printf("%s %s %s", $data{$item}->{subvendor}, $data{$item}->{subdevice}, $data{$item}->{name}); - print "\n"; - } -} - -print ("109e Brooktree Corporation\n"); -print ("\t032e Bt878 Video Capture\n"); -%data=(); - -open ($input, "../bttv-cards.c"); -while (<$input>) { - if (/\{\s*0x(\w{4})(\w{4}),.*\"([^\"]+)\"\s\},/) - { - printf ("\t\t%s %s %s\n", $2, $1, $3); - } -} - -printf ("\n"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_config_compat.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_config_compat.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_config_compat.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_config_compat.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,536 +0,0 @@ -#!/usr/bin/perl -use strict; - -my $kdir=shift or die "should specify a kernel dir"; -my $infile=shift or die "should specify an input config file"; -my $outfile=shift or die "should specify an output config file"; - -my $out; - -sub check_spin_lock() -{ - my $file = "$kdir/include/linux/netdevice.h"; - my $old_syntax = 1; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/netif_tx_lock_bh/) { - $old_syntax = 0; - last; - } - } - - if ($old_syntax) { - $out.= "\n#define OLD_XMIT_LOCK 1\n"; - } - close INNET; -} - -sub check_sound_driver_h() -{ - my $file = "$kdir/include/sound/driver.h"; - my $old_syntax = 1; - - open INNET, "<$file" or return; - while () { - if (m/This file is deprecated/) { - $old_syntax = 0; - last; - } - } - - if ($old_syntax) { - $out.= "\n#define NEED_SOUND_DRIVER_H 1\n"; - } - close INNET; -} - -sub check_snd_pcm_rate_to_rate_bit() -{ - my $file = "$kdir/include/sound/pcm.h"; - my $old_syntax = 1; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/snd_pcm_rate_to_rate_bit/) { - $old_syntax = 0; - last; - } - } - - if ($old_syntax) { - $out.= "\n#define COMPAT_PCM_TO_RATE_BIT 1\n"; - } - close INNET; -} - -sub check_snd_ctl_boolean_mono_info() -{ - my $file = "$kdir/include/sound/control.h"; - my $old_syntax = 1; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/snd_ctl_boolean_mono_info/) { - $old_syntax = 0; - last; - } - } - - if ($old_syntax) { - $out.= "\n#define COMPAT_SND_CTL_BOOLEAN_MONO 1\n"; - } - close INNET; -} - -sub check_bool() -{ - my $file = "$kdir/include/linux/types.h"; - my $old_syntax = 1; - - open INDEP, "<$file" or die "File not found: $file"; - while () { - if (m/^\s*typedef.*bool;/) { - $old_syntax = 0; - last; - } - } - - if ($old_syntax) { - $out.= "\n#define NEED_BOOL_TYPE 1\n"; - } - close INDEP; -} - -sub check_is_singular() -{ - my $file = "$kdir/include/linux/list.h"; - my $need_compat = 1; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/list_is_singular/) { - $need_compat = 0; - last; - } - } - - if ($need_compat) { - $out.= "\n#define NEED_IS_SINGULAR 1\n"; - } - close INNET; -} - -sub check_clamp() -{ - my $file = "$kdir/include/linux/kernel.h"; - my $need_compat = 1; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/define\s+clamp/) { - $need_compat = 0; - last; - } - } - - if ($need_compat) { - $out.= "\n#define NEED_CLAMP 1\n"; - } - close INNET; -} - -sub check_proc_create() -{ - my $file = "$kdir/include/linux/proc_fs.h"; - my $need_compat = 1; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/proc_create/) { - $need_compat = 0; - last; - } - } - - if ($need_compat) { - $out.= "\n#define NEED_PROC_CREATE 1\n"; - } - close INNET; -} - -sub check_pcm_lock() -{ - my $file = "$kdir/include/sound/pcm.h"; - my $need_compat = 1; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/pcm_stream_lock/) { - $need_compat = 0; - last; - } - } - - if ($need_compat) { - $out.= "\n#define NO_PCM_LOCK 1\n"; - } - close INNET; -} - -sub check_algo_control() -{ - my $file = "$kdir/include/linux/i2c.h"; - my $need_compat = 0; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/algo_control/) { - $need_compat = 1; - last; - } - } - - if ($need_compat) { - $out.= "\n#define NEED_ALGO_CONTROL 1\n"; - } - close INNET; -} - -sub check_net_dev() -{ - my $file = "$kdir/include/linux/netdevice.h"; - my $need_compat = 1; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/netdev_priv/) { - $need_compat = 0; - last; - } - } - - if ($need_compat) { - $out.= "\n#define NEED_NETDEV_PRIV 1\n"; - } - close INNET; -} - -sub check_usb_endpoint_type() -{ - my $nfiles = 0; - my @files = ( "$kdir/include/linux/usb.h", "$kdir/include/linux/usb/ch9.h" ); - - foreach my $file ( @files ) { - open IN, "<$file" or next; - $nfiles++; - while () { - if (m/usb_endpoint_type/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - die "Usb headers not found" if (!$nfiles); - - # definition not found. This means that we need compat - $out.= "\n#define NEED_USB_ENDPOINT_TYPE 1\n"; -} - -sub check_pci_ioremap_bar() -{ - my $file = "$kdir/include/linux/pci.h"; - my $need_compat = 1; - - open INNET, "<$file" or die "File not found: $file"; - while () { - if (m/pci_ioremap_bar/) { - $need_compat = 0; - last; - } - } - - if ($need_compat) { - $out.= "\n#define NEED_PCI_IOREMAP_BAR 1\n"; - } - close INNET; -} - -sub check_snd_card_create() -{ - my $file = "$kdir/include/sound/core.h"; - my $need_compat = 1; - - open IN, "<$file" or die "File not found: $file"; - while () { - if (m/snd_card_create/) { - $need_compat = 0; - last; - } - } - - if ($need_compat) { - $out.= "\n#define NEED_SND_CARD_CREATE\n"; - } - close IN; -} - -sub check_poll_schedule() -{ - my @files = ( "$kdir/include/linux/poll.h" ); - - foreach my $file ( @files ) { - open IN, "<$file" or die "File not found: $file"; - while () { - if (m/poll_schedule/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - # definition not found. This means that we need compat - $out.= "\n#define NEED_POLL_SCHEDULE 1\n"; -} - -sub check_snd_BUG_ON() -{ - my @files = ( "$kdir/include/sound/core.h" ); - - foreach my $file ( @files ) { - open IN, "<$file" or die "File not found: $file"; - while () { - if (m/snd_BUG_ON/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - # definition not found. This means that we need compat - $out.= "\n#define NEED_SND_BUG_ON 1\n"; -} - -sub check_bitops() -{ - my @files = ( "$kdir/include/linux/bitops.h" ); - - foreach my $file ( @files ) { - open IN, "<$file" or next; - while () { - if (m/#define\s+BIT\(/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - # definition not found. This means that we need compat - $out.= "\n#define NEED_BITOPS 1\n"; -} - -sub check_fw_csr_string() -{ - my @files = ( "$kdir/include/linux/firewire.h" ); - - foreach my $file ( @files ) { - open IN, "<$file" or next; - while () { - if (m/fw_csr_string\(/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - # definition not found. This means that we need compat - $out.= "\n#define NEED_FW_CSR_STRING 1\n"; -} - - -sub check_delayed_work() -{ - my @files = ( "$kdir//include/linux/workqueue.h" ); - - foreach my $file ( @files ) { - open IN, "<$file" or die "File not found: $file"; - while () { - if (m/struct\s+delayed_work/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - # definition not found. This means that we need compat - $out.= "\n#define NEED_DELAYED_WORK 1\n"; -} - -sub check_vzalloc() -{ - my @files = ( "$kdir/include/linux/vmalloc.h" ); - - foreach my $file ( @files ) { - open IN, "<$file" or die "File not found: $file"; - while () { - if (m/vzalloc/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - # definition not found. This means that we need compat - $out.= "\n#define NEED_VZALLOC 1\n"; -} - -sub check_flush_work_sync() -{ - my @files = ( "$kdir/include/linux/workqueue.h" ); - - foreach my $file ( @files ) { - open IN, "<$file" or die "File not found: $file"; - while () { - if (m/flush_work_sync/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - # definition not found. This means that we need compat - $out.= "\n#define NEED_FLUSH_WORK_SYNC 1\n"; -} - -sub check_autosuspend_delay() -{ - my @files = ( "$kdir/include/linux/pm_runtime.h" ); - - foreach my $file ( @files ) { - open IN, "<$file" or next; - while () { - if (m/pm_runtime_set_autosuspend_delay/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - # definition not found. This means that we need compat - $out.= "\n#define NEED_AUTOSUSPEND_DELAY 1\n"; -} - - -sub check_file_for_func($$$) -{ - my $incfile = shift; - my $function = shift; - my $define = shift; - - my @files = ( "$kdir/$incfile" ); - - foreach my $file ( @files ) { - open IN, "<$file" or die "File not found: $file"; - while () { - if (m/($function)/) { - close IN; - # definition found. No need for compat - return; - } - } - close IN; - } - - # definition not found. This means that we need compat - $out.= "\n#define $define 1\n"; -} - -sub check_other_dependencies() -{ - check_spin_lock(); - check_sound_driver_h(); - check_snd_ctl_boolean_mono_info(); - check_snd_pcm_rate_to_rate_bit(); - check_bool(); - check_is_singular(); - check_clamp(); - check_proc_create(); - check_pcm_lock(); - check_algo_control(); - check_net_dev(); - check_usb_endpoint_type(); - check_pci_ioremap_bar(); - check_snd_card_create(); - check_poll_schedule(); - check_snd_BUG_ON(); - check_bitops(); - check_delayed_work(); - check_fw_csr_string(); - check_vzalloc(); - check_flush_work_sync(); - check_autosuspend_delay(); - check_file_for_func("include/linux/kernel.h", "hex_to_bin", "NEED_HEX_TO_BIN"); - check_file_for_func("include/sound/control.h", "snd_ctl_enum_info", "NEED_SND_CTL_ENUM_INFO"); - check_file_for_func("include/linux/sysfs.h", "sysfs_attr_init", "NEED_SYSFS_ATTR_INIT"); - check_file_for_func("include/linux/delay.h", "usleep_range", "NEED_USLEEP_RANGE"); -} - -# Do the basic rules -open IN, "<$infile" or die "File not found: $infile"; - -$out.= "#ifndef __CONFIG_COMPAT_H__\n"; -$out.= "#define __CONFIG_COMPAT_H__\n\n"; - -$out.= "#include \n\n"; -$out.= "#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)\n"; -$out.= "#include \n"; -$out.= "#else\n"; -$out.= "#include \n"; -$out.= "#endif\n\n"; - -# mmdebug.h includes autoconf.h. So if this header exists, -# then include it before our config is set. -if (-f "$kdir/include/linux/mmdebug.h") { - $out.= "#include \n\n"; -} - -while() { - next unless /^(\S+)\s*:= (\S+)$/; - $out.= "#undef $1\n"; - $out.= "#undef $1_MODULE\n"; - if($2 eq "n") { - next; - } elsif($2 eq "m") { - $out.= "#define $1_MODULE 1\n"; - } elsif($2 eq "y") { - $out.= "#define $1 1\n"; - } else { - $out.= "#define $1 $2\n"; - } -} -close IN; - -check_other_dependencies(); - -open OUT, ">$outfile" or die 'Unable to write $outfile'; -print OUT "$out\n#endif\n"; -close OUT diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_kconfig.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_kconfig.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_kconfig.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_kconfig.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,695 +0,0 @@ -#!/usr/bin/perl -use FileHandle; -use strict; - -my %depend = (); -my %minver = (); -my %config = (); -my %stringopt = (); -my %intopt = (); -my %hexopt = (); -my %tristate = (); -my %kernopts = (); -my %depmods = (); -my ($version, $level, $sublevel, $kernver); - -my $kernel = shift; -my $kernsrc = shift; -my $force_kconfig = shift; -my $enable_staging = shift; - -my $debug=0; - -########################################################### -# Read a .config file (first argument) and put the resulting options in a -# hash, which is returned. This subroutine should be called in a hash -# context or it will not be very useful. -sub process_config($) -{ - my $filename = shift; - my %conf; - my $in = new FileHandle; - - open $in, $filename or die "File not found: $filename"; - while (<$in>) { - if (/^CONFIG_(\w+)\s*=\s*(\S.*?)\s*$/) { - my $c = \($conf{$1} = $2); - $$c =~ y/nmy/012/ if $$c =~ /^.$/; - next; - } - if (/^# CONFIG_(\w+) is not set$/) { - $conf{$1} = 0; - next; - } - unless (/^#|$/) { - print "Confused by this line in $filename:\n$_"; - } - } - close $in; - return %conf; -} - -sub add_bool($) -{ - my $arg=shift; - - exists $config{$arg} or die "Adding unknown boolean '$arg'"; - print "Boolean: $arg\n" if $debug; - $tristate{$arg} = "bool"; -} - -sub add_tristate($) -{ - my $arg=shift; - - exists $config{$arg} or die "Adding unknown tristate '$arg'"; - print "Tristate: $arg\n" if $debug; - $tristate{$arg}="tristate"; - # tri default is 'm' - $config{$arg} = 1 if($config{$arg}); -} - -sub add_int($) -{ - my $arg=shift; - - print "Int: $arg\n" if $debug; - exists $config{$arg} or die "Adding unknown int '$arg'"; - $intopt{$arg} = 0; -} - -sub add_hex($) -{ - my $arg=shift; - - print "Hex: $arg\n" if $debug; - exists $config{$arg} or die "Adding unknown hex '$arg'"; - $hexopt{$arg} = 0; -} - -sub add_string($) -{ - my $arg=shift; - - print "String: $arg\n" if $debug; - exists $config{$arg} or die "Adding unknown string '$arg'"; - $stringopt{$arg} = ""; -} - -sub set_int_value($$) -{ - my $key = shift; - my $val = shift; - - exists $intopt{$key} or die "Default for unknown int option '$key'"; - $intopt{$key} = $val; -} - -sub set_hex_value($$) -{ - my $key = shift; - my $val = shift; - - exists $hexopt{$key} or die "Default for unknown hex option '$key'"; - $hexopt{$key} = "0x$val"; -} - -sub set_string_value($$) -{ - my $key = shift; - my $val = shift; - - exists $stringopt{$key} or die "Default for unknown string option '$key'"; - $stringopt{$key} = "\"$val\""; -} - -sub add_config($) -{ - my $arg = shift; - - if ($arg =~ /^(\w+)\s*$/) { - $config{$1} = 2; - } else { - die "Do not understand config variable '$arg'"; - } -} - -######################################## -# Turn option off, iff it already exists -sub disable_config($) -{ - my $key = shift; - - $config{$key} = 0 if (exists $config{$key}); -} - -# %{$depend{'FOO'}} lists all variables which depend on FOO. This is the -# reverse of the variables that FOO depends on. -my %depend = (); -sub finddeps($$) -{ - my $key = shift; - my $deps = shift; - - $deps =~ s/^\W+//; - $depend{$_}{$key} = 1 foreach(split(/\W[\Wynm]*/, $deps)); -} - -# @{$depends{'FOO'}} is a list of dependency expressions that FOO depends -# on. This is the reverse of the variables that depend on FOO. -my %depends = (); -sub depends($$) -{ - my $key = shift; - my $deps = shift; - - (!defined $key || $key eq '') and - die "Got bad key with $deps\n"; - finddeps($key, $deps); - push @{$depends{$key}}, $deps; -} - -sub selects($$$) -{ - my $key = shift; - my $select = shift; - my $if = shift; - - finddeps($key, $select); - if(defined $if) { - finddeps($key, $if); - # Transform "select X if Y" into "depends on !Y || X" - $select = "!($if) || ($select)"; - } - push @{$depends{$key}}, $select; -} - -# Needs: -# %depend <- %depend{FOO} lists the variables that depend on FOO -# %depends <- %depends{FOO} lists the dependency expressions for FOO -# %config <- the value of all media variables -# %kernopts <- the value of all kernel variables (including media ones) -# -# Checks the dependencies of all media variables, recursively. Returns -# a new hash that has the new values of all media variables. -sub checkdeps() -{ - my %allconfig; - - @allconfig{keys %depend} = @kernopts{keys %depend}; - @allconfig{keys %config} = values %config; - # Set undef values to 0 - map { defined $_ or $_ = 0 } values %allconfig; - - # First run, check deps for all the v4l-dvb variables. Following - # runs, check all variables which depend on a variable that was - # changed. Stop when no more variables change. - for(my %changed = (), my @tocheck = keys %config; @tocheck; - @tocheck = keys %changed, %changed = ()) { - foreach (@tocheck) { - next unless($allconfig{$_}); # skip disabled vars - if (!checkvardeps($_)) { - $changed{$_} = 1 foreach keys %{$depend{$_}}; - } - } - } - return map { $_ => $allconfig{$_} } keys %config; - - # Check the dependencies of a variable, if one fails the variable - # is set to 0. Returns 0 if the variable failed, 1 if it passed. - sub checkvardeps($) { - my $key = shift; - my $deps = $depends{$key}; - foreach (@$deps) { - next if($_ eq ''); - if (!eval(toperl($_))) { - print "Disabling $key, dependency '$_' not met\n" if $debug; - $allconfig{$key} = 0; - return 0; - } - } - return 1; - } - - # Convert a Kconfig expression to a Perl expression - sub toperl($) - { - local $_ = shift; - - # Turn n,m,y into 0,1,2 - s/\bn\b/0/g; s/\bm\b/1/g; s/\by\b/2/g; - - # Turn = into ==, but keep != as != (ie. not !==) - s/(?) { - $line = $_; - # In our Kconfig files, the first non-help line after the - # help text always has no indention. Technically, the - # help text is ended by just by the indention decreasing, - # but that is a pain to keep track of. - if ($in_help && /^\S/) { - $in_help = 0; - } elsif ($in_help) { - # Still inside help text - next; - } - - # Start of help text - if (/^\s*(---)?help(---)?\s*$/) { - $in_help = 1; - # Insert VIDEO_KERNEL_VERSION dependency, default - # n line, and help text note for disabled drivers. - if ($disabled) { - if(exists $tristate{$key} && !$default_seen) { - print OUT "\tdefault n\n"; - } - print OUT "\tdepends on VIDEO_KERNEL_VERSION\n"; - $line = sprintf($disabled_msg, $minver{$key}); - } - next; - } - # No help text should get processed past this point - $in_help and die "I'm very confused"; - - # start of a new stanza, reset - if (/^\w/) { - $disabled = 0; - $default_seen = 0; - $key = undef; - $if = ""; - } - next if (/^\s*#/ || /^\s*$/); # skip comments and blank lines - - # Erase any comments on this line - s/(? 0) { - $disabled = 1; - disable_config($key); - print "$key: Requires at least kernel $minver{$key}\n"; - print OUT "# $key disabled for insufficient kernel version\n"; - } else { - $disabled=0; - } - # Add dependencies from enclosing if/endif blocks - depends($key, $_) foreach (@kifs); - } elsif (m|^\s*comment\s+"[^"]*"\s*$|) { - $key = 'comment'; - } elsif (m|^\s*menu\s+"[^"]*"\s*$|) { - $key = 'menu'; - push @kifs, ''; # placeholder for any depends on clauses - } elsif (m|^\s*if\s+(.+?)\s*$|) { - push @kifs, $1; - } elsif (/^\s*end(if|menu)\s*(?:#.*)?$/) { - # Won't handle menu/if blocks that aren't strictly - # nested, but no one should do that! - $#kifs >= 0 or die "Unmatched end$1 at $file:$.\n"; - pop @kifs; - } else { - $nothandled = 1; - } - next unless ($nothandled); - # Remaining Kconfig directives only makse sense inside Kconfig blocks - unless(defined $key) { - print "Skipping $file:$. $_" if $debug; - next; - } - - # Don't process any directives in comment blocks - next if ($key eq 'comment'); - - # Only depends on lines are accepted in menus - if ($key eq 'menu') { - if (m|^\s*depends on\s+(.+?)\s*$|) { - my $x = pop @kifs; - $x .= ' && ' if($x ne ''); - $x .= "($1)"; - push @kifs, $x; - } else { - print "Skipping unexpected line in menu stanza $file:$.$_" if $debug; - } - next; - } - - # config type - if(/^\s*bool(ean)?\s/) { - add_bool($key); - if (m|if (.*)\s*$|) { - printf("Boolean $key with if '$1'\n") if $debug; - if ($if eq "") { - $if = "($1)"; - } else { - $if .= " && ($1)"; - } - } - } elsif (/^\s*tristate\s/) { - add_tristate($key); - if (m|if (.*)\s*$|) { - printf("Boolean $key with if '$1'\n") if $debug; - if ($if eq "") { - $if = "($1)"; - } else { - $if .= " && ($1)"; - } - } - } elsif (/^\s*int\s/) { - add_int($key); - } elsif (/^\s*hex\s/) { - add_hex($key); - } elsif (/^\s*string\s/) { - add_string($key); - - # select and depend lines - } elsif (m|^\s*depends on\s+(.+?)\s*$|) { - depends($key, $1); - } elsif (m|^\s*select\s+(\w+)(\s+if\s+(.+?))?\s*$|) { - selects($key, $1, $3); - - # default lines - } elsif (m|^\s*default\s+(.+?)(?:\s+if .*)?\s*$|) { - my $o = $1; - if ($2 ne "") { - if ($if eq "") { - $if = "($2)"; - } else { - $if .= " && ($2)"; - } - } - - # Get default for int options - if ($o =~ m|^"(\d+)"$| && exists $intopt{$key}) { - set_int_value($key, $1); - # Get default for hex options - } elsif ($o =~ m|^"(0x)?([[:xdigit:]]+)"$| && exists $hexopt{$key}) { - set_hex_value($key, $2); - # Get default for string options - } elsif ($o =~ m|^"(.*)"$| && exists $stringopt{$key}) { - set_string_value($key, $1); - - # Override default for disabled tri/bool options - # We don't care about the default for tri/bool options otherwise - } elsif (!$o =~ /^(y|n|m|"yes"|"no")$/i && exists $tristate{$key}) { - print "Default is an expression at $file:$. $_\n" if $debug; - if ($if eq "") { - depends($key, "$o"); - } - } - if ($if ne "") { - # FIXME: What happens if no default clause exists? - # the $if won't be handled - depends($key, "$if || $o"); - } - - if ($disabled) { - $default_seen = 1; - $line = "\tdefault n\n"; - } - } else { - print "Skipping $file:$. $_" if $debug; - } - } continue { - if (cmp_ver($kernver, '2.6.37') < 0 && $line =~ m/visible\sif\s.*/) { - $line =~ s/visible\sif\s(.*)//; - print OUT $line; - print OUT "\tdepends on $1\n"; - } else { - print OUT $line; - } - } - close $in; -} - -sub parse_versions() -{ - my $in = new FileHandle; - my $ver; - - open $in, ') { - if (/\[(\d+\.\d+\.\d+)\]/) { - $ver = $1; - } elsif (/^\s*(\w+)/) { - $minver{$1} = $ver; - print "minimal version for $1 is $ver\n" if $debug; - } - } - close $in; -} - -# Read in the .version file to get the kernel version -sub get_version() -{ - open IN, '<.version' or die 'File not found: .version'; - while () { - if (/KERNELRELEASE\s*[:]*[=]+\s*(\d+)\.(\d+)\.(\d+)/) { - $version=$1; - $level=$2; - $sublevel=$3; - return $kernver="$version.$level.$sublevel"; - } - } - close IN; -} - -# Like ver1 <=> ver2, but understands X.Y.Z version strings -sub cmp_ver($$) -{ - shift =~ /(\d+)\.(\d+)\.(\d+)/; - my ($v1_ver,$v1_level,$v1_sublevel) = ($1,$2,$3); - shift =~ /(\d+)\.(\d+)\.(\d+)/; - my ($v2_ver,$v2_level,$v2_sublevel) = ($1,$2,$3); - - my $cmp = $v1_ver <=> $v2_ver; - return $cmp unless($cmp == 0); - $cmp = $v1_level <=> $v2_level; - return $cmp unless($cmp == 0); - return $v1_sublevel <=> $v2_sublevel; -} - -# Get kernel version -get_version(); -print "Preparing to compile for kernel version $kernver\n"; - -# Get Kernel's config settings -%kernopts = process_config("$kernel/.config"); - -# Modules must be on, or building out of tree drivers makes no sense -if(!$kernopts{MODULES}) { - print <<"EOF"; -You appear to have loadable modules turned off in your kernel. You can -not compile the v4l-dvb drivers, as modules, and use them with a kernel -that has modules disabled. - -If you want to compile these drivers into your kernel, you should -use 'make kernel-links' to link the source for these drivers into -your kernel tree. Then configure and compile the kernel. -EOF - exit -1; -} - -# Kernel < 2.6.22 is missing the HAS_IOMEM option -if (!defined $kernopts{HAS_IOMEM} && cmp_ver($kernver, '2.6.22') < 0) { - $kernopts{HAS_IOMEM} = 2; -} - -# Kernel < 2.6.22 is missing the HAS_DMA option -if (!defined $kernopts{HAS_DMA} && cmp_ver($kernver, '2.6.22') < 0) { - $kernopts{HAS_DMA} = 2; -} - -# Kernel < 2.6.23 is missing the VIRT_TO_BUS option -if (!defined $kernopts{VIRT_TO_BUS} && cmp_ver($kernver, '2.6.23') < 0) { - # VIRT_TO_BUS -> !PPC64 - $kernopts{VIRT_TO_BUS} = 2 - $kernopts{PPC64}; -} - -# Kernel < 2.6.37 is missing the BKL option -if (!defined $kernopts{BKL} && cmp_ver($kernver, '2.6.37') < 0) { - $kernopts{BKL} = 2; -} - -# Get minimum kernel version for our variables -parse_versions(); - -kernelcheck(); - -open OUT, ">Kconfig" or die "Cannot write Kconfig file"; -print OUT <<"EOF"; -mainmenu "V4L/DVB menu" -source Kconfig.kern -config VIDEO_KERNEL_VERSION - bool "Enable drivers not supported by this kernel" - default n - ---help--- - Normally drivers that require a kernel newer $version.$level.$sublevel, - the kernel you are compiling for now, will be disabled. - - Turning this switch on will let you enabled them, but be warned - they may not work properly or even compile. - - They may also work fine, and the only reason they are listed as - requiring a newer kernel is that no one has tested them with an - older one yet. - - If the driver works, please post a report to the V4L mailing list: - linux-media\@vger.kernel.org. - - Unless you know what you are doing, you should answer N. - -EOF - -open_kconfig('../linux', '../linux/drivers/media/Kconfig'); -open_kconfig('.', './Kconfig.sound'); -open_kconfig('.', './Kconfig.staging'); -close OUT; - -# These options should default to off -disable_config('DVB_AV7110_FIRMWARE'); -disable_config('DVB_CINERGYT2_TUNING'); -disable_config('VIDEO_HELPER_CHIPS_AUTO'); -disable_config('VIDEO_FIXED_MINOR_RANGES'); -disable_config('STAGING') if (!$enable_staging); -disable_config('STAGING_BROKEN'); -$intopt { "DVB_MAX_ADAPTERS" } = 8; - -# Check dependencies -my %newconfig = checkdeps(); - -# TODO: tell the user which options were disabled at this point -%config = %newconfig; - -# Create Kconfig.kern, listing all non-media (i.e. kernel) variables -# that something depended on. -$depend{MODULES}{always} = 1; # Make sure MODULES will appear -open OUT, '>Kconfig.kern' or die "Cannot write Kconfig.kern file: $!"; -while (my ($key, $deps) = each %depend) { - next if exists $config{$key}; # Skip media variables - - print OUT "# Needed by ", join(', ', keys %$deps), "\n"; - print OUT "config $key\n\ttristate\n"; - print OUT "\tdefault ", qw(n m y)[$kernopts{$key}], "\n\n"; -} -close OUT; - -# Create make dependency rules for the Kconfig file -open OUT, '>.kconfig.dep' or die "Cannot write .kconfig.dep file: $!"; -print OUT 'Kconfig: '; -print OUT join(" \\\n\t", @kconfigfiles), "\n"; -close OUT; - -# Produce a .config file if forced or one doesn't already exist -if ($force_kconfig==1 || !-e '.config') { - open OUT, '>.config' or die "Cannot write .config file: $!"; - foreach (keys %tristate) { - if ($config{$_}) { - print OUT "CONFIG_$_=", qw(n m y)[$config{$_}], "\n"; - } else { - print OUT "# CONFIG_$_ is not set\n"; - } - } - while (my ($key,$value) = each %intopt) { - print OUT "CONFIG_$key=$value\n" if($config{$key}); - } - while (my ($key,$value) = each %hexopt) { - print OUT "CONFIG_$key=$value\n" if($config{$key}); - } - while (my ($key,$value) = each %stringopt) { - print OUT "CONFIG_$key=$value\n" if($config{$key}); - } - close OUT; - print "Created default (all yes) .config file\n"; -} - -# Check for full kernel sources and print a warning -sub kernelcheck() -{ - my $fullkernel="$kernsrc/fs/fcntl.c"; - if (! -e $fullkernel) { - print <<"EOF2"; - -***WARNING:*** You do not have the full kernel sources installed. -This does not prevent you from building the v4l-dvb tree if you have the -kernel headers, but the full kernel source may be required in order to use -make menuconfig / xconfig / qconfig. - -If you are experiencing problems building the v4l-dvb tree, please try -building against a vanilla kernel before reporting a bug. - -Vanilla kernels are available at http://kernel.org. -On most distros, this will compile a newly downloaded kernel: - -cp /boot/config-`uname -r` /.config -cd -make all modules_install install - -Please see your distro's web site for instructions to build a new kernel. - -EOF2 - } -print << "EOF3"; -WARNING: This is the V4L/DVB backport tree, with experimental drivers - backported to run on legacy kernels from the development tree at: - http://git.linuxtv.org/media-tree.git. - It is generally safe to use it for testing a new driver or - feature, but its usage on production environments is risky. - Don't use it in production. You've been warned. -EOF3 - sleep 5; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/makelinks.sh v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/makelinks.sh --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/makelinks.sh 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/makelinks.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -#!/bin/sh -# link drivers sources from CVS or release tarball into your 2.6.x kernel sources; - -if test -z $1 || ! test -d $1 ; then - echo - echo " usage: $0 " - echo - exit -fi - -echo "patching $1..." - -cd linux -PWD=`pwd` -FINDDIR="-name CVS -prune -o -type d" -FINDFILE="-name CVS -prune -o -type f -not -name .cvsignore\ - -not -name '*.rej' -not -name '*.orig'" - -for dir in drivers include Documentation; do - find $dir $FINDDIR -exec mkdir -p -v $1/{} \; - find $dir $FINDFILE -exec ln -f -s $PWD/{} $1/{} \; -done - -for dir in drivers/media include; do - find $dir $FINDDIR -exec ln -f -s $PWD/../v4l/compat.h $1/{} \; \ - -exec touch $1/{}/config-compat.h \; -done - -cat > $1/drivers/media/Kbuild <) { - # print STDERR "Line: $_"; - # Skip comment lines - if (/^\s*#/) { - print OUT $_; - next; - } - m/^\s*-?include/ and die "Can't handle includes! In $file"; - - # Handle line continuations - if (/\\\n$/) { - $_ .= <$in>; - redo; - } - - # $orig is what we will print, $_ is what we will parse - $orig = $_; - # Eat line continuations in string we will parse - s/\s*\\\n\s*/ /g; - # Eat comments - s/#.*$//; - - if (/^\s*obj-.*:?=\s*(\S.*?)\s*$/) { - # print STDERR "obj matched '$1'\n"; - check_line($dir, $1, $orig); # will print line for us - next; - } - if (/^\s*EXTRA_CFLAGS\s+\+?=\s*(\S.*?)\s*$/) { - # print STDERR "cflags matched '$1'\n"; - remove_includes($1, $orig); # will print line for us - next; - } - # Any flags should be added to already existing flags - $orig =~ s/ccflags-y\s*:=/ccflags-y +=/; - print OUT $orig; - } - close $in; -} - -my %obsolete; -sub getobsolete() -{ - open OBSOLETE, ') { - next if (/^\s*#/ || /^\s*$/); - chomp; - if (m|^(.*)/([^/]*)$|) { - $obsolete{$1}{"$2.ko"} = 1; - } else { - print "Unable to parse obsolete.txt:$.\n$_\n"; - } - } - - close OBSOLETE; -} - -sub removeobsolete() -{ - while ( my ($dir, $files) = each(%obsolete) ) { - print OUT "\t\@echo -e \"\\nRemoving obsolete files from \$(KDIR26)/$dir:\"\n"; - print OUT "\t\@files='", join(' ', keys %$files), "'; "; - - print OUT "for i in \$\$files;do if [ -e \$(DESTDIR)\$(KDIR26)/$dir/\$\$i ]; then "; - print OUT "echo -n \"\$\$i \";"; - print OUT " rm \$(DESTDIR)\$(KDIR26)/$dir/\$\$i; fi; done; "; - - print OUT "for i in \$\$files;do if [ -e \$(DESTDIR)\$(KDIR26)/$dir/\$\$i.gz ]; then "; - print OUT "echo -n \"\$\$i.gz \";"; - print OUT " rm \$(DESTDIR)\$(KDIR26)/$dir/\$\$i.gz; fi; done; echo;\n\n"; - } -} - -# -# Special hack for Ubuntu with their non-standard dir -# -sub removeubuntu() -{ - my $dest = "/lib/modules/\$(KERNELRELEASE)/ubuntu/media"; - my $filelist; - - while ( my ($dir, $files) = each(%instdir) ) { - $filelist .= ' '. join(' ', keys %$files); - } - while ( my ($dir, $files) = each(%obsolete) ) { - $filelist .= ' ' . join(' ', keys %$files); - } - $filelist =~ s/\s+$//; - - print OUT "\t\@if [ -d $dest ]; then "; - print OUT "printf \"\\nHmm... distro kernel with a non-standard place for module backports detected.\\n"; - print OUT "Please always prefer to use vanilla upstream kernel with V4L/DVB\\n"; - print OUT "I'll try to remove old/obsolete LUM files from $dest:\\n\"; "; - print OUT "files='", $filelist, "'; "; - - print OUT "for i in \$\$files;do find \"$dest\" \-name \"\$\$i\" \-exec echo \'{}\' \';\' ;"; - print OUT " find \"$dest\" \-name \"\$\$i\" \-exec rm \'{}\' \';\' ;"; - print OUT " done;"; - print OUT " fi\n"; -} - -sub parse_dir() -{ - my $file = $File::Find::name; - - return if (!($file =~ /Makefile$/)); - open_makefile($file); -} - -############################################################################## - -getobsolete(); - -open OUT, '>Makefile.media' or die 'Unable to write Makefile.media'; -open_makefile('../linux/drivers/media/Makefile'); - -find({wanted => \&parse_dir, no_chdir => 1}, '../linux/drivers/staging'); - -# Creating Install rule -print OUT "media-install::\n"; - -removeobsolete(); -removeubuntu(); - -print OUT "\t\@echo \"Installing kernel modules under \$(DESTDIR)\$(KDIR26)/:\"\n"; - -while (my ($dir, $files) = each %instdir) { - print OUT "\t\@n=0;for i in ", join(' ', keys %$files), ";do "; - print OUT "if [ -e \"\$\$i\" ]; then "; - print OUT "if [ \$\$n -eq 0 ]; then "; - print OUT "echo -n \"\t$dir/: \"; "; - print OUT "install -d \$(DESTDIR)\$(KDIR26)/$dir; fi; "; - print OUT "n=\$\$\(\(\$\$n+1\)\); "; - print OUT "if [ \$\$n -eq 4 ]; then echo; echo -n \"\t\t\"; n=1; fi; "; - print OUT "echo -n \"\$\$i \"; "; - print OUT "install -m 644 -c \$\$i \$(DESTDIR)\$(KDIR26)/$dir; fi; done; "; - print OUT "if [ \$\$n -ne 0 ]; then echo; "; - print OUT "strip --strip-debug \$(DESTDIR)\$(KDIR26)/$dir/*.ko; "; - print OUT "fi;\n\n"; -} -print OUT "\t@echo\n"; -print OUT "\t/sbin/depmod -a \$(KERNELRELEASE) \$(if \$(DESTDIR),-b \$(DESTDIR))\n\n"; - -# Creating Remove rule -print OUT "media-rminstall::\n"; - -removeobsolete(); -removeubuntu(); - -while ( my ($dir, $files) = each(%instdir) ) { - print OUT "\t\@echo -e \"\\nRemoving old \$(KDIR26)/$dir files:\"\n"; - print OUT "\t\@files='", join(' ', keys %$files), "'; "; - - print OUT "for i in \$\$files;do if [ -e \$(DESTDIR)\$(KDIR26)/$dir/\$\$i ]; then "; - print OUT "echo -n \"\$\$i \";"; - print OUT " rm \$(DESTDIR)\$(KDIR26)/$dir/\$\$i; fi; done; "; - - print OUT "for i in \$\$files;do if [ -e \$(DESTDIR)\$(KDIR26)/$dir/\$\$i.gz ]; then "; - print OUT "echo -n \"\$\$i.gz \";"; - print OUT " rm \$(DESTDIR)\$(KDIR26)/$dir/\$\$i.gz; fi; done; echo;\n\n"; -} - -my $mediadeps = join(" \\\n", map("\t../linux/drivers/media/$_/Makefile", keys %instdir)); -$mediadeps =~ s,\.\./linux/drivers/media/\.\.,..,g; - -# Print dependencies of Makefile.media -print OUT "Makefile.media: ../linux/drivers/media/Makefile \\\n"; -print OUT "\tobsolete.txt \\\n"; -print OUT $mediadeps; -print OUT "\n"; -close OUT; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_myconfig.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_myconfig.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_myconfig.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/make_myconfig.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -#!/usr/bin/perl - -# The purpose of this script is to produce a file named '.myconfig', in -# the same style as the '.config' file. Except .myconfig has disabled -# options explicitly set to 'n' rather than just omitted. This is to -# make sure they override any corresponding options that may be turned on -# in the Kernel's config files. -# The .myconfig file is what will be included in the v4l-dvb Makefile -# to control which drivers are built. - -my %config = (); -my %allconfig = (); - -open IN,".config"; -while () { - if (m/\s*(\w+)=\s*(\S*)/) { -#printf "%s=%s\n",$1,$2; - $config { $1 } = $2; - } -} -close IN; - -# Build table of _all_ bool and tristate config variables -my $key = 0; -open IN,"Kconfig"; -while () { - if (/^(?:menu)?config\s+(\w+)\s*$/) { - $key == 0 or die "Couldn't find type of config '$key'"; - $key = "CONFIG_$1"; - } elsif (/^\s+bool(ean)?\s/) { - $allconfig{$key} = 'bool'; - $key = 0; - } elsif (/^\s+tristate\s/) { - $allconfig{$key} = 'tristate'; - $key = 0; - } elsif (/^\s+(int|hex|string)\s/) { - $allconfig{$key} = 'data'; - $key = 0; - } -} -close IN; - -exists $allconfig{0} and die "Unable to correctly parse Kconfig file"; - -# Produce output for including in a Makefile -# Explicitly set bool/tri options that didn't appear in .config to n -# 'data' options are only output if they appeared in .config -open OUT,">.myconfig"; -while ( my ($key, $value) = each(%allconfig) ) { - if ($value eq 'data') { - next unless (exists $config{$key}); - $value = $config{$key}; - } else { - $value = exists $config{$key} ? $config{$key} : 'n'; - } - printf OUT "%-44s := %s\n",$key,$value; -} -close OUT; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/map-changelog v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/map-changelog --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/map-changelog 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/map-changelog 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -changeset = changelog.tmpl diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/modules.sh v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/modules.sh --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/modules.sh 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/modules.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -#!/bin/sh - -function xrmmod() { - local module regex - module="$1" - regex=`echo $module | sed -e 's/[-_]/[-_]/g'` - grep -qe "$regex" /proc/modules || return 0 - echo "unload $module" - if test "$UID" = "0"; then - /sbin/rmmod $module - else - sudo /sbin/rmmod $module - fi -} - -function xinsmod() { - local module regex file args - module="$1" - shift - args="$*" - regex=`echo $module | sed -e 's/[-_]/[-_]/g'` - grep -qe "$regex" /proc/modules && return - file="" - test -f "$module.o" && file="$module.o" - test -f "$module.ko" && file="$module.ko" - if test "$file" != ""; then - echo "load $file $args" - if test "$UID" = "0"; then - /sbin/insmod $file $args - else - sudo /sbin/insmod $file $args - fi - else - echo "load $module $args" - if test "$UID" = "0"; then - /sbin/modprobe $module $args - else - sudo /sbin/modprobe $module $args - fi - fi -} - -function v4l2basic() { - for module in i2c-core i2c-algo-bit \ - videodev v4l2-common v4l1-compat \ - video-buf \ - soundcore - do - xinsmod $module - done -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/prepare-ChangeLog.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/prepare-ChangeLog.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/prepare-ChangeLog.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/prepare-ChangeLog.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,586 +0,0 @@ -#!/usr/bin/perl -w -# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 2 -*- - -# Perl script to create a ChangeLog entry with names of files -# and functions from a hg diff. -# -# Darin Adler , started 20 April 2000 -# Java support added by Maciej Stachowiak -# last updated 28 December 2000 -# -# Mauro Carvalho Chehab : modified to -# allow signed-off-by tags, GMT Time and V4L format. -# CHANVE_LOG Env variables now are mandatory. -# Updated at 15 January 2005 -# -# Mauro Carvalho Chehab : modified to -# work with Mercurial -# Updated at 29 August 2005 -# -# Mauro Carvalho Chehab : modified to -# just generate a changelog entry -# Updated at 01 January 2006 -## -# (Someone put a license in here, like maybe GPL.) -# -# TODO: -# Provide option to put new ChangeLog into a separate file -# instead of editing the ChangeLog. -# For new files, just say "New file" instead of listing -# function names. -# List functions that have been removed too. -# Decide what a good logical order is for the changed files -# other than a normal text "sort" (top level first?) -# (group directories?) (.h before .c?) -# Leave a diff file behind if asked, but in unified format. -# Handle C++ and yacc source files too (other languages?). -# Help merge when there are ChangeLog conflicts or if there's -# already a partly written ChangeLog entry. -# Find appropriate ChangeLog to edit for each changed file -# instead of always using ChangeLog in current directory. -# Add command line option to put the ChangeLog into a separate -# file or just spew it out stdout. -# Figure out how to allow -z options from .cvsrc to work without -# letting other bad options work. Currently the -f disables -# everything from the .cvsrc. -# Add CVS version numbers for each file too (can't do that until -# the changes are checked in, though). -# Work around diff stupidity where deleting a function that starts -# with a comment makes diff think that the following function -# has been changed (if the following function starts with a comment -# with the same first line, such as /**) -# Work around diff stupidity where deleting an entire function and -# the blank lines before it makes diff think you've changed the -# previous function. - -use diagnostics; -use strict; - -use English; -use Text::Wrap; - -# Get environment variables required. -my $name = $ENV{CHANGE_LOG_NAME}; -my $email_address = $ENV{CHANGE_LOG_EMAIL_ADDRESS}; -my $login = $ENV{CHANGE_LOG_LOGIN}; - -my $outfile = shift || ""; - -if (!defined $name) - { - print STDERR "Please, define env var CHANGE_LOG_NAME.\n"; - exit; - } -if (!defined $email_address) - { - print STDERR "Please, define env var CHANGE_LOG_EMAIL_ADDRESS.\n"; - exit; - } -if (!defined $login) - { - print STDERR "Please, define env var CHANGE_LOG_LOGIN.\n"; - exit; - } - -# For each file, build a list of modified lines. -# Use line numbers from the "after" side of each diff. -print STDERR " Running hg diff to find changes.\n"; -my %changed_line_ranges; -my $file; -open DIFF, "hg diff |" or die "The hg diff failed: $OS_ERROR.\n"; -while () - { - $file = $1 if /^diff -r .* (\S+)$/; - if (defined $file) - { - push @{$changed_line_ranges{$file}}, [ $2, $4 || $2 ]; - } - } -close DIFF; -if (!%changed_line_ranges) - { - print STDERR " No changes found.\n"; - exit; - } - -# For each ".c" file, convert line range to function list. -print STDERR " Extracting affected function names from C source files.\n"; -my %function_lists; -foreach my $file (keys %changed_line_ranges) - { - # An empty function list still indicates that something changed. - $function_lists{$file} = ""; - - # Only look for function names in .c files. - next unless $file =~ /\.(c|java)/; - - # Find all the functions in the file. - open SOURCE, $file or next; - my @function_ranges = get_function_line_ranges(\*SOURCE, $file); - close SOURCE; - - # Find all the modified functions. - my @functions; - my %saw_function; - my @change_ranges = (@{$changed_line_ranges{$file}}, []); - my @change_range = (0, 0); - FUNCTION: foreach my $function_range_ref (@function_ranges) - { - my @function_range = @$function_range_ref; - - # Advance to successive change ranges. - for (;; @change_range = @{shift @change_ranges}) - { - last FUNCTION unless @change_range; - - # If past this function, move on to the next one. - next FUNCTION if $change_range[0] > $function_range[1]; - - # If an overlap with this function range, record the function name. - if ($change_range[1] >= $function_range[0] - and $change_range[0] <= $function_range[1]) - { - if (!$saw_function{$function_range[2]}) - { - $saw_function{$function_range[2]} = 1; - push @functions, $function_range[2]; - } - next FUNCTION; - } - } - } - - # Format the list of functions now. - $function_lists{$file} = " (" . join("), (", @functions) . "):" if @functions; - } - -# Write out a new ChangeLog file. -print STDERR " Editing the ChangeLog file.\n"; -my $date = sprintf "%d-%02d-%02d %02d:%02d", - 1900 + (gmtime $BASETIME)[5], # year - 1 + (gmtime $BASETIME)[4], # month - (gmtime $BASETIME)[3], # day within month - (gmtime $BASETIME)[2], # hour - (gmtime $BASETIME)[1]; # min - -if ($outfile eq "") { - open CHANGE_LOG, ">&STDOUT"; -} else { - open CHANGE_LOG, "> $outfile" or die "Could not write to $outfile\n."; -} -print CHANGE_LOG "$date $login\n\n"; -foreach my $file (sort keys %function_lists) - { - my $lines = wrap("\t", "\t", "XX$file:$function_lists{$file}"); - $lines =~ s/^\tXX/\t* /; - print CHANGE_LOG "$lines\n"; - } -print CHANGE_LOG "\n\tSigned-off-by: $name <$email_address>\n"; -close CHANGE_LOG; - -# Done. -print STDERR " Done editing ChangeLog.\n"; -exit; - - - -sub get_function_line_ranges - { - my ($file_handle, $file_name) = @_; - - if ($file_name =~ /\.c$/) { - return get_function_line_ranges_for_c ($file_handle, $file_name); - } elsif ($file_name =~ /\.java$/) { - return get_function_line_ranges_for_java ($file_handle, $file_name); - } - return (); - } - -# Read a file and get all the line ranges of the things that look like C functions. -# A function name is the last word before an open parenthesis before the outer -# level open brace. A function starts at the first character after the last close -# brace or semicolon before the function name and ends at the close brace. -# Comment handling is simple-minded but will work for all but pathological cases. -# -# Result is a list of triples: [ start_line, end_line, function_name ]. - -sub get_function_line_ranges_for_c - { - my ($file_handle, $file_name) = @_; - - my @ranges; - - my $in_comment = 0; - my $in_macro = 0; - my $in_parentheses = 0; - my $in_braces = 0; - - my $word = ""; - - my $potential_start = 0; - my $potential_name = ""; - - my $start = 0; - my $name = ""; - - while (<$file_handle>) - { - # Handle continued multi-line comment. - if ($in_comment) - { - next unless s-.*\*/--; - $in_comment = 0; - } - - # Handle continued macro. - if ($in_macro) - { - $in_macro = 0 unless /\\$/; - next; - } - - # Handle start of macro (or any preprocessor directive). - if (/^\s*\#/) - { - $in_macro = 1 if /^([^\\]|\\.)*\\$/; - next; - } - - # Handle comments and quoted text. - while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy - { - my $match = $1; - if ($match eq "/*") - { - if (!s-/\*.*?\*/--) - { - s-/\*.*--; - $in_comment = 1; - } - } - elsif ($match eq "//") - { - s-//.*--; - } - else # ' or " - { - if (!s-$match([^\\]|\\.)*?$match--) - { - warn "mismatched quotes at line $INPUT_LINE_NUMBER in $file_name\n"; - s-$match.*--; - } - } - } - - # Find function names. - while (m-(\w+|[(){};])-g) - { - # Open parenthesis. - if ($1 eq "(") - { - $potential_name = $word unless $in_parentheses; - $in_parentheses++; - next; - } - - # Close parenthesis. - if ($1 eq ")") - { - $in_parentheses--; - next; - } - - # Open brace. - if ($1 eq "{") - { - # Promote potiential name to real function name at the - # start of the outer level set of braces (function body?). - if (!$in_braces and $potential_start) - { - $start = $potential_start; - $name = $potential_name; - } - - $in_braces++; - next; - } - - # Close brace. - if ($1 eq "}") - { - $in_braces--; - - # End of an outer level set of braces. - # This could be a function body. - if (!$in_braces and $name) - { - push @ranges, [ $start, $INPUT_LINE_NUMBER, $name ]; - $name = ""; - } - - $potential_start = 0; - $potential_name = ""; - next; - } - - # Semicolon. - if ($1 eq ";") - { - $potential_start = 0; - $potential_name = ""; - next; - } - - # Word. - $word = $1; - if (!$in_parentheses) - { - $potential_start = 0; - $potential_name = ""; - } - if (!$potential_start) - { - $potential_start = $INPUT_LINE_NUMBER; - $potential_name = ""; - } - } - } - - warn "mismatched braces in $file_name\n" if $in_braces; - warn "mismatched parentheses in $file_name\n" if $in_parentheses; - - return @ranges; - } - - - -# Read a file and get all the line ranges of the things that look like Java -# classes, interfaces and methods. -# -# A class or interface name is the word that immediately follows -# `class' or `interface' when followed by an open curly brace and not -# a semicolon. It can appear at the top level, or inside another class -# or interface block, but not inside a function block -# -# A class or interface starts at the first character after the first close -# brace or after the function name and ends at the close brace. -# -# A function name is the last word before an open parenthesis before -# an open brace rather than a semicolon. It can appear at top level or -# inside a class or interface block, but not inside a function block. -# -# A function starts at the first character after the first close -# brace or after the function name and ends at the close brace. -# -# Comment handling is simple-minded but will work for all but pathological cases. -# -# Result is a list of triples: [ start_line, end_line, function_name ]. - -sub get_function_line_ranges_for_java - { - my ($file_handle, $file_name) = @_; - - my @current_scopes; - - my @ranges; - - my $in_comment = 0; - my $in_macro = 0; - my $in_parentheses = 0; - my $in_braces = 0; - my $in_non_block_braces = 0; - my $class_or_interface_just_seen = 0; - - my $word = ""; - - my $potential_start = 0; - my $potential_name = ""; - my $potential_name_is_class_or_interface = 0; - - my $start = 0; - my $name = ""; - my $current_name_is_class_or_interface = 0; - - while (<$file_handle>) - { - # Handle continued multi-line comment. - if ($in_comment) - { - next unless s-.*\*/--; - $in_comment = 0; - } - - # Handle continued macro. - if ($in_macro) - { - $in_macro = 0 unless /\\$/; - next; - } - - # Handle start of macro (or any preprocessor directive). - if (/^\s*\#/) - { - $in_macro = 1 if /^([^\\]|\\.)*\\$/; - next; - } - - # Handle comments and quoted text. - while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy - { - my $match = $1; - if ($match eq "/*") - { - if (!s-/\*.*?\*/--) - { - s-/\*.*--; - $in_comment = 1; - } - } - elsif ($match eq "//") - { - s-//.*--; - } - else # ' or " - { - if (!s-$match([^\\]|\\.)*?$match--) - { - warn "mismatched quotes at line $INPUT_LINE_NUMBER in $file_name\n"; - s-$match.*--; - } - } - } - - # Find function names. - while (m-(\w+|[(){};])-g) - { - # Open parenthesis. - if ($1 eq "(") - { - if (!$in_parentheses) { - $potential_name = $word; - $potential_name_is_class_or_interface = 0; - } - $in_parentheses++; - next; - } - - # Close parenthesis. - if ($1 eq ")") - { - $in_parentheses--; - next; - } - - # Open brace. - if ($1 eq "{") - { - # Promote potiential name to real function name at the - # start of the outer level set of braces (function/class/interface body?). - if (!$in_non_block_braces - and (!$in_braces or $current_name_is_class_or_interface) - and $potential_start) - { - if ($name) - { - push @ranges, [ $start, ($INPUT_LINE_NUMBER - 1), - join ('.', @current_scopes) ]; - } - - - $current_name_is_class_or_interface = $potential_name_is_class_or_interface; - - $start = $potential_start; - $name = $potential_name; - - push (@current_scopes, $name); - } else { - $in_non_block_braces++; - } - - $potential_name = ""; - $potential_start = 0; - - $in_braces++; - next; - } - - # Close brace. - if ($1 eq "}") - { - $in_braces--; - - # End of an outer level set of braces. - # This could be a function body. - if (!$in_non_block_braces) - { - if ($name) - { - push @ranges, [ $start, $INPUT_LINE_NUMBER, - join ('.', @current_scopes) ]; - - pop (@current_scopes); - - if (@current_scopes) - { - $current_name_is_class_or_interface = 1; - - $start = $INPUT_LINE_NUMBER + 1; - $name = $current_scopes[$#current_scopes-1]; - } - else - { - $current_name_is_class_or_interface = 0; - $start = 0; - $name = ""; - } - } - } - else - { - $in_non_block_braces-- if $in_non_block_braces; - } - - $potential_start = 0; - $potential_name = ""; - next; - } - - # Semicolon. - if ($1 eq ";") - { - $potential_start = 0; - $potential_name = ""; - next; - } - - if ($1 eq "class" or $1 eq "interface") { - $class_or_interface_just_seen = 1; - next; - } - - # Word. - $word = $1; - if (!$in_parentheses) - { - if ($class_or_interface_just_seen) { - $potential_name = $word; - $potential_start = $INPUT_LINE_NUMBER; - $class_or_interface_just_seen = 0; - $potential_name_is_class_or_interface = 1; - next; - } - } - if (!$potential_start) - { - $potential_start = $INPUT_LINE_NUMBER; - $potential_name = ""; - } - $class_or_interface_just_seen = 0; - } - } - - warn "mismatched braces in $file_name\n" if $in_braces; - warn "mismatched parentheses in $file_name\n" if $in_parentheses; - - return @ranges; - } diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/prep_commit_msg.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/prep_commit_msg.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/prep_commit_msg.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/prep_commit_msg.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -#!/usr/bin/perl - -my $diff = 'diff'; -if ($ARGV[0] eq '-q') { - $diff = 'qdiff'; - shift; -} -my $autopatch = shift; - -# Get Hg username from environment -my $user = $ENV{HGUSER}; - -sub hgrcuser($) -{ - my $file = shift; - my $ui = 0; - open IN, '<', $file; - while () { - $ui = 1 if (/^\s*\[ui\]/); - if ($ui && /^\s*username\s*=\s*(\S.*?)\s*$/) { - close IN; - return($1); - } - } - close IN; - return(""); -} - -# Didn't work? Try the repo's .hgrc file -if ($user eq "") { - my $hgroot = `hg root`; - chomp($hgroot); - $user = hgrcuser("$hgroot/.hg/hgrc"); -} -# Ok, try ~/.hgrc next -if ($user eq "") { - $user = hgrcuser("$ENV{HOME}/.hgrc"); -} - -# Still no luck? Try some other environment variables -if ($user eq "") { - my $name = $ENV{CHANGE_LOG_NAME}; - my $email = $ENV{CHANGE_LOG_EMAIL_ADDRESS}; - $user = "$name <$email>" if ($name ne "" || $email ne ""); -} - -# Last try to come up with something -if ($user eq "") { - $user = "$ENV{USER} <>"; -} - -$checkpatch=$ENV{CHECKPATCH}; - -if (!$checkpatch) { - $checkpatch="/lib/modules/`uname -r`/build/scripts/checkpatch.pl"; -} - -my $cp_version; -open IN,"$checkpatch|"; -while () { - tr/A-Z/a-z/; - if (m/version\s*:\s*([\d\.]+)/) { - $cp_version = $1; - } -} -close IN; - -my $intree_checkpatch = "scripts/checkpatch.pl --no-tree"; -if (!open IN,"$intree_checkpatch|") { - $intree_checkpatch = "v4l/".$intree_checkpatch; - open IN,"$intree_checkpatch|"; -} -while () { - tr/A-Z/a-z/; - if (m/version\s*:\s*([\d\.]+)/) { - if ($1 > $cp_version) { - print "# WARNING: $checkpatch version $cp_version is\n" - ."# older than $intree_checkpatch version" - ." $1.\n# Using in-tree one.\n#\n"; - $cp_version = $1; - $checkpatch = $intree_checkpatch; - } - } -} -close IN; - -print "# Added/removed/changed files:\n"; -system "hg $diff | diffstat -p1 -c"; - -open IN,"hg $diff | $checkpatch -q --nosignoff -|"; -my $err=0; -while () { - if (!$err) { - print "#\n# WARNING: $checkpatch version $cp_version returned ". - "some errors.\n# Please fix.\n#\n"; - - - $err=1; - } - print "# $_"; -} -close IN; - - -if (-s $autopatch) { - print "#\n# Note, a problem with your patch was detected! These changes were made\n"; - print "# automatically: $autopatch\n"; - system "diffstat -p0 -c $autopatch"; - print "#\n# Please review these changes and see if they belong in your patch or not.\n"; -} -if ($diff eq 'qdiff') { - # Use existing mq patch logfile? - open IN, "hg qheader |"; - my @header = ; - close IN; - - if ($#header > 0) { - # Use existing header - print @header; - exit; - } - # No header, use pre-made log message below - - # Hg will strip lines that start with "From: " from mq patch headers! - # In order to stop it, we insert this extra From line at the top, - # Hg will strip it and then leave the real from line alone. - print "From: $user\n\n"; -} -print <<"EOF"; -# -# Patch Subject (a brief description with less than 74 chars): - - -# From Line, identifying the name of the patch author -From: $user - -# A detailed description: - -# NEW: Please change the priority of the patch to "high" if the patch is -# a bug fix, or are meant to be applied at the first upstream -# version of a new driver whose changes don't depend on changes on -# core modules -Priority: normal - -# At the end Signed-off-by: fields by patch author and committer, at least. -Signed-off-by: $user -EOF diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/release.sh v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/release.sh --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/release.sh 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/release.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -#!/bin/sh - -# config -release="$HOME/kernel/release" -ver_bt="0.9.15" -ver_sa="0.2.12" -ver_cx="0.0.4" - -# common files -files_v4l="v4l*.[ch] video-buf.[ch] videodev*.h" -files_tuner="tuner.[ch] tda9887.[ch]" -files_i2c="id.h audiochip.h" -files_common="$files_v4l $files_tuner $files_i2c doc" - -# other files -files_ir="ir-common.[ch]" -files_audio="msp3400.[ch] tvaudio.[ch]" - -files_bttv="bt848.h btcx*.[ch] bttv*.[ch] ir-kbd*.c" -files_saa="saa7134*.[ch] saa6752hs.[ch] ir-kbd-i2c.c" -files_cx="btcx*.[ch] cx*.[ch]" - - -###################################################################################### -# helpers - -function build_release () { - local name="$1"; shift - local version="$1"; shift - local files="$*" - local dest="$WORK/$name-$version" - local tarball="$release/$name-$version.tar.gz" - - # copy / prepare stuff - mkdir "$dest" - cp -av $files "$dest" || exit 1 - cp -v Makefile "$dest" - cp -v "scripts/config.$name" "$dest"/Make.config - - # build test - (cd $dest; make) || exit 1 -# (cd $dest; ls *.o; sleep 5) - (cd $dest; make clean) - - # build tarball - tar czCf "$WORK" "$tarball" "$name-$version" -} - - -###################################################################################### -# main - -# tmp dir for my files -WORK="${TMPDIR-/tmp}/${0##*/}-$$" -mkdir "$WORK" || exit 1 -trap 'rm -rf "$WORK"' EXIT - -build_release "bttv" "$ver_bt" \ - "$files_common" "$files_ir" "$files_audio" "$files_bttv" -build_release "saa7134" "$ver_sa" \ - "$files_common" "$files_ir" "$files_audio" "$files_saa" -build_release "cx88" "$ver_cx" \ - "$files_common" "$files_cx" diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/rmmod.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/rmmod.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/rmmod.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/rmmod.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,222 +0,0 @@ -#!/usr/bin/perl -use strict; -use File::Find; - -my %depend = (); -my %depend2 = (); -my %rmlist = (); -my @nodep; -my @modlist; -my @allmodules; -my %reqmodules; -my %loaded = (); -my $i=0; - -# Device debug parameters -# Module name Debug option -my %debug = ( "tuner" => "tuner_debug=1", - "dvb-core" => "cam_debug=1", - "dvb-ttpci" => "debug=247", - "b2c2-flexcop" => "debug=0x01", - "b2c2-flexcop-usb" => "debug=0x01", - "b2c2-flexcop-pci" => "debug=0x01", - "dvb-usb" => "debug=0x33", - "dvb-usb-gp8psk" => "debug=0x03", - "dvb-usb-vp7045" => "debug=0x03", - "dvb-usb-dtt200u" => "debug=0x03", - "dvb-usb-dibusb-common" => "debug=0x03", - ); - -sub getobsolete() -{ - my @obsolete; - open OBSOLETE, ') { - next if (/^\s*#/ || /^\s*$/); - chomp; - m|^.*/([^/]+)$| and push @obsolete, $1; - } - - close OBSOLETE; - return @obsolete; -} - -sub findprog($) -{ - foreach(split(/:/, $ENV{PATH}),qw(/sbin /usr/sbin /usr/local/sbin)) { - return "$_/$_[0]" if(-x "$_/$_[0]"); - } - die "Can't find needed utility '$_[0]'"; -} - -sub parse_dir { - my $file = $File::Find::name; - my $modinfo = findprog('modinfo'); - - if (!($file =~ /[.]ko$/)) { - return; - } - - my $module = $file; - $module =~ s|^[./]*(.*)[.]ko|\1|; - - open IN, "$modinfo $file|grep depends|cut -b 17-|"; - while () { - my $deps = $_; - $deps =~ s/\n//; - $deps =~ s/[,]/ /g; - $deps = " $deps "; - $depend{$module} = $deps; - push @allmodules, $module; - $i++; - } - close IN; -} - -sub parse_loaded { - open IN, "/proc/modules"; - while () { - m/^([\w\d_-]+)/; - $loaded{$1}=1; - } - close IN; -} - -sub cleandep() -{ - my $dep; - - while ( my ($k, $v) = each(%depend) ) { - my $arg=$v; - my $arg2=" "; - while (!($arg =~ m/^\s*$/)) { - if ($arg =~ m/^ ([^ ]+) /) { - my $val=$1; - if (exists($depend{$val})) { - $arg2="$arg2 $val "; - } else { - $reqmodules{$val}=1; - } - } - $arg =~ s/^ [^ ]+//; - $arg2 =~ s/\s\s+/ /; - } - $depend2 { $k } = $arg2; - } - -} - -sub rmdep() -{ - my $dep; - - while ($dep=pop @nodep) { - while ( my ($k, $v) = each(%depend2) ) { - if ($v =~ m/\s($dep)\s/) { - $v =~ s/\s${dep}\s/ /; - $v =~ s/\s${dep}\s/ /; - $v =~ s/\s${dep}\s/ /; - $depend2 {$k} = $v; - } - } - } -} - -sub orderdep () -{ - my $old; - do { - $old=$i; - while ( my ($key, $value) = each(%depend2) ) { - if ($value =~ m/^\s*$/) { - push @nodep, $key; - push @modlist, $key; - $i=$i-1; - delete $depend2 {$key}; - } - } - rmdep(); - } until ($old==$i); - while ( my ($key, $value) = each(%depend2) ) { - printf "ERROR: bad dependencies - $key ($value)\n"; - } -} - -sub insmod ($) -{ - my $debug=shift; - my $modprobe = findprog('modprobe'); - my $insmod = findprog('insmod'); - - while ( my ($key, $value) = each(%reqmodules) ) { - print ("$modprobe $key\n"); - system ("$modprobe $key"); - } - - foreach my $key (@modlist) { - if ($debug) { - my $dbg=$debug{$key}; - - print "$insmod ./$key.ko $dbg\n"; - system "$insmod ./$key.ko $dbg\n"; - } else { - print "$insmod ./$key.ko\n"; - system "$insmod ./$key.ko\n"; - } - } -} - -sub rmmod(@) -{ - my $rmmod = findprog('rmmod'); - my @not; - foreach (reverse @_) { - s/-/_/g; - if (exists ($loaded{$_})) { - print "$rmmod $_\n"; - unshift @not, $_ if (system "$rmmod $_"); - } - } - return @not; -} - -sub prepare_cmd() -{ - find(\&parse_dir, "."); - printf "found $i modules\n"; - - cleandep(); - orderdep(); -} - -# main -my $mode=shift; -if ($mode eq "load") { - prepare_cmd; - insmod(0); -} else { - if ($mode eq "unload") { - prepare_cmd; - parse_loaded; - my @notunloaded = rmmod(@modlist, getobsolete()); - @notunloaded = rmmod(@notunloaded) if (@notunloaded); - if (@notunloaded) { - print "Couldn't unload: ", join(' ', @notunloaded), "\n"; - } - } elsif ($mode eq "reload") { - prepare_cmd; - parse_loaded; - rmmod(@modlist); - insmod(0); - } elsif ($mode eq "debug") { - prepare_cmd; - parse_loaded; - insmod(1); - } elsif ($mode eq "check") { - prepare_cmd; - parse_loaded; - } else { - printf "Usage: $0 [load|unload|reload|debug|check]\n"; - } -} - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/saa7134.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/saa7134.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/saa7134.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/saa7134.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my %map = ( - "PCI_ANY_ID" => "0", - "PCI_VENDOR_ID_PHILIPS" => "1131", - "PCI_VENDOR_ID_ASUSTEK" => "1043", - "PCI_VENDOR_ID_MATROX" => "102B", -); - -sub fix_id($) { - my $id = shift; - $id = $map{$id} if defined($map{$id}); - $id =~ s/^0x//; - return $id; -} - -my $new_entry = -1; -my $nr = 0; -my ($id,$subvendor,$subdevice); -my %data; - -while (<>) { - # defines in header file - if (/#define\s+(SAA7134_BOARD_\w+)\s+(\d+)/) { - $data{$1}->{nr} = $2; - next; - } - # saa7134_boards - if (/\[(SAA7134_BOARD_\w+)\]/) { - $id = $1; - $data{$id}->{id} = $id; -# $data{$id}->{nr} = $nr++; - }; - next unless defined($id); - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - } - - # saa7134_pci_tbl - $subvendor = fix_id($1) if (/\.subvendor\s*=\s*(\w+)\s*,*/); - $subdevice = fix_id($1) if (/\.subdevice\s*=\s*(\w+)\s*,*/); - if (/.driver_data\s*=\s*(\w+)\s*,*/) { - if (defined($data{$1}) && - defined($subvendor) && $subvendor ne "0" && - defined($subdevice) && $subdevice ne "0") { - push @{$data{$1}->{subid}}, "$subvendor:$subdevice"; - undef $subvendor; - undef $subdevice; - } - } -} - -foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) { - printf("%3d -> %-40s", $data{$item}->{nr}, $data{$item}->{name}); - printf(" [%s]",join(",",@{$data{$item}->{subid}})) - if defined($data{$item}->{subid}); - print "\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/saa7164.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/saa7164.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/saa7164.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/saa7164.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my %map = ( - "PCI_ANY_ID" => "0", -); - -sub fix_id($) { - my $id = shift; - $id = $map{$id} if defined($map{$id}); - $id =~ s/^0x//; - return $id; -} - -my $new_entry = -1; -my $nr = 0; -my ($id,$subvendor,$subdevice); -my %data; - -while (<>) { - # defines in header file - if (/#define\s+(SAA7164_BOARD_\w+)\s+(\d+)/) { - $data{$1}->{nr} = $2; - next; - } - # saa7164_boards - if (/\[(SAA7164_BOARD_\w+)\]/) { - $id = $1; - $data{$id}->{id} = $id; -# $data{$id}->{nr} = $nr++; - }; - next unless defined($id); - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - } - - # saa7164_pci_tbl - $subvendor = fix_id($1) if (/\.subvendor\s*=\s*(\w+),/); - $subdevice = fix_id($1) if (/\.subdevice\s*=\s*(\w+),/); - if (/.card\s*=\s*(\w+),/) { - if (defined($data{$1}) && - defined($subvendor) && $subvendor ne "0" && - defined($subdevice) && $subdevice ne "0") { - push @{$data{$1}->{subid}}, "$subvendor:$subdevice"; - undef $subvendor; - undef $subdevice; - } - } -} - -foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) { - printf("%3d -> %-51s", $data{$item}->{nr}, $data{$item}->{name}); - printf(" [%s]",join(",",@{$data{$item}->{subid}})) - if defined($data{$item}->{subid}); - print "\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/strip-trailing-whitespaces.sh v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/strip-trailing-whitespaces.sh --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/strip-trailing-whitespaces.sh 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/strip-trailing-whitespaces.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -#!/bin/sh -# Strips trailing whitespace. Leading spaces and spaces after tabs are -# converted to the equivalent sequence of tabs only. - -# Use the option "fast" to only check files Hg thinks are new or modified. -# The option "manifest" will use Hg's manifest command to check all files -# under Hg revision control. -# Otherwise, all files under the linux tree are checked, except files in CVS -# directories and .cvsignore files. This is the historical behavior. - - -if [ "x$1" = "xfast" ]; then - files="hg status -man" -elif [ "x$1" = "xqfast" ]; then - files="hg status --rev -2 -man" -elif [ "x$1" = "xmanifest" ]; then - files="hg manifest | cut '-d ' -f3" -else - files="find linux -type f -print" -fi - -for file in `eval $files`; do - case "$file" in - *.gif | *.pdf | *.patch | *.h.xml | *.c.xml) - continue - ;; - esac - - perl -ne ' - s/[ \t]+$//; - s<^ {8}> <\t>; - s<^ {1,7}\t> <\t>; - while( s<\t {8}> <\t\t>g || s<\t {1,7}\t> <\t\t>g ) {}; - print' < "${file}" | \ - diff -u --label="$file" "$file" --label="$file" - -done diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/tuner.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/tuner.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/tuner.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/tuner.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my $new_entry = -1; -my $nr = 0; -my ($id,$subvendor,$subdevice); -my %data; - -my $H = shift; -my $C = shift; -my %blacklist; - -open IN, "<$H"; -while () { - # defines in header file - if (/#define\s+(TUNER_\w+)\s+(\d+)/) { - my $num=$2; - $data{$1}->{nr} = $num; - if (/#define\s+TUNER_TDA9887/) { - $blacklist{$num}=1; - } - next; - } -} -close IN; - -open IN, "<$C"; -while () { - # tuners - if (/\[(TUNER_\w+)\]/) { - $id = $1; - if ($id =~ m/TUNER_MAX/) { - next; - } - $data{$id}->{id} = $id; - }; - next unless defined($id); - - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/); - } -} - -foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) { - if ($blacklist{$data{$item}->{nr}}) { - next; - } - - printf("tuner=%d - %s", $data{$item}->{nr}, $data{$item}->{name}); - print "\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/update v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/update --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/update 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/update 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -#!/bin/sh -source scripts/modules.sh -set -e - -case "`hostname --short`" in - eskarina) -# btopt="card=10" -# btopt="card=6 remote=1" - ;; - bogomips) - saopt="card=7" - ;; -esac - -########################################################################### -# unload - -# bttv -xrmmod dst -xrmmod bt878 -xrmmod ir-kbd-gpio -xrmmod ir-kbd-i2c -xrmmod bttv - -# cx88 -xrmmod cx88-dvb -xrmmod cx88-blackbird -xrmmod cx8802 -xrmmod cx8801 -xrmmod cx8800 -xrmmod cx88xx - -# saa7134 -xrmmod saa7134-dvb -xrmmod saa7134-empress -xrmmod saa7134 - -# saa7146 -xrmmod dvb_ttpci -xrmmod saa7146_vv - -# dvb -xrmmod or51132 -xrmmod cx22702 -xrmmod mt352 -xrmmod dvb-pll - -# common -xrmmod btcx-risc -xrmmod ir-common -xrmmod video-buf-dvb -xrmmod video-buf - -# i2c -xrmmod tuner -xrmmod msp3400 -xrmmod tvaudio -xrmmod tda9887 -xrmmod tveeprom - -########################################################################## -# reload - -sync; sleep 1; - -# common -v4l2basic -#xrmmod video-buf -#xinsmod video-buf debug=0 -#xrmmod v4l1-compat -#xinsmod v4l1-compat debug=1 - -xinsmod tveeprom debug=0 -xinsmod dvb-pll debug=0 -xinsmod btcx-risc debug=0 -xinsmod ir-common debug=0 repeat=0 -xinsmod tuner tuner_debug=0 -xinsmod tda9887 debug=0 qss=1 -xinsmod msp3400 debug=0 - -# bttv -xinsmod ir-kbd-i2c debug=0 -xinsmod bttv bttv_debug=0 vbi_debug=0 irq_debug=0 \ - fdsr=0 chroma_agc=1 vbibufs=4 irq_iswitch=0 i2c_scan=1 $btopt -xinsmod ir-kbd-gpio debug=0 - -# cx88 -xinsmod cx88xx core_debug=0 audio_debug=0 ir_debug=1 \ - i2c_debug=1 i2c_scan=1 -xinsmod cx8800 video_debug=0 vbi_debug=0 -xinsmod cx8801 -xinsmod cx8802 -xinsmod cx88-blackbird - -# saa7134 -xinsmod saa7134 audio_debug=0 i2c_scan=0 i2c_debug=0 oss=1 $saopt -xinsmod saa7134-empress - -# dvb stuff -xinsmod cx22702 debug=0 -xinsmod mt352 debug=1 -xinsmod or51132 -xinsmod tda1004x -xinsmod video-buf-dvb -xinsmod cx88-dvb -xinsmod saa7134-dvb diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/usbaudio_setup.sh v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/usbaudio_setup.sh --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/usbaudio_setup.sh 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/usbaudio_setup.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2006 Markus Rechberger -# -# 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, or -# (at your option) any later version. -# -# 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., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -which /usr/bin/dialog >/dev/null -if [ "0" != "$?" ]; then -echo "this tool requires \"dialog\" (http://hightek.org/dialog/)" -exit 1 -fi -uid=`id -u` -if [ "0" != "$uid" ]; then -echo "this tool must be run as root, you can disable this message by editing the script but only do that unless you know what you're doing!" -exit 1 -fi -which gcc > /dev/null -if [ "0" != "$?" ]; then -echo "this tool won't work unless you install gcc" -exit 1 -fi -test -f ossid -if [ "0" != "$?" ]; then -cat > ossid.c <<_EOF -#include -#include -#include -#include -#include -#include - -int main(int argc, char **argv){ - int fd; - struct mixer_info *info; - fd=open(argv[1],O_RDONLY); - if(fd>=0){ - info=malloc(sizeof(struct mixer_info)); - ioctl(fd,SOUND_MIXER_INFO,info); - printf("%c \"%s %s\"\n",(argv[1][strlen(argv[1])-1]=='p')?'0':(argv[1][strlen(argv[1])-1]+1),info->name,info->id); - free(info); - close(fd); - } else { - return 1; - } - return 0; -} -_EOF -gcc ossid.c -o ossid -rm ossid.c -fi - -test -f /proc/asound/cards -if [ "0" != "$?" ]; then -dialog --title "Welcome" --backtitle "Empia Sound Configuration" \ ---msgbox "Your system doesn't support ALSA, please have a look at \ -www.alsa-project.org and set it up properly \ - - -Press any key to continue... " 11 50 -exit 1; -fi - -dialog --title "Welcome" --backtitle "Empia Sound Configuration" \ ---msgbox "This tool was written to ease up sound configuration for -* Terratec Hybrid XS -* Terratec Cinergy 250 USB 2.0 -* Hauppauge HVR 900 -* and possible others :) - -first select an usb audio source, as target choose your soundcard -Press any key to continue... " 13 60 - -ls /dev/dsp* | while read a; do ./ossid $a; done | xargs dialog --menu "Choose your TV Audio source:" 12 60 5 2>/tmp/em2880_source.$$ -ls /dev/dsp* | while read a; do ./ossid $a; done | xargs dialog --menu "Choose your output soundcard device:" 12 60 5 2>/tmp/em2880_dst.$$ - -source=`egrep '^[0-9p]' /tmp/em2880_source.$$` -dst=`egrep '^[0-9p]' /tmp/em2880_dst.$$` - -echo "playing $source to $dst"; -if [ "$source" = "0" ]; then - device="/dev/dsp" -else - device="/dev/dsp`expr $source - 1`" -fi - -if [ "$dst" = "0" ]; then - device2="/dev/dsp" -else - device2="/dev/dsp`expr $source - 1`" -fi -clear -echo "Using command: sox -r 48000 -w -c 2 -t ossdsp $device -t ossdsp $device2" -sox -r 48000 -w -c 2 -t ossdsp $device -t ossdsp $device2 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/usbvision.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/usbvision.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/scripts/usbvision.pl 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/scripts/usbvision.pl 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -#!/usr/bin/perl -w -use strict; - -my $new_entry = -1; -my $nr = 0; -my ($id,$subvendor,$subdevice); -my %data; - -while (<>) { - # defines in header file - if (/#define\s*(\w+)\s*(\d+)/) { - $data{$1}->{nr} = $2; - next; - } - # boards - if (/^\s*\[([\w\d_]+)\]\s*=\s*{/) { - $id = $1; - $data{$id}->{id} = $id; - }; - - next unless defined($id); - - if (/USB_DEVICE.*0x([0-9a-fA-F]*).*0x([0-9a-fA-F]*).*/) - { - $subvendor=$1; - $subdevice=$2; - } - if(/driver_info\s*=\s*([\w\d_]+)/) - { - push @{$data{$1}->{subid}}, "$subvendor:$subdevice"; - } - if (!defined($data{$id}) || !defined($data{$id}->{name})) { - $data{$id}->{name} = $1 if (/\.ModelString\s*=\s*\"([^\"]+)\"/); - } -} - -foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) { - printf("%3d -> %-56s", $data{$item}->{nr}, $data{$item}->{name}); - printf(" [%s]",join(",",@{$data{$item}->{subid}})) - if defined($data{$item}->{subid}); - print "\n"; -} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/versions.txt v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/versions.txt --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l/versions.txt 2011-03-24 07:51:36.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l/versions.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -# Use this for stuff for drivers that don't compile -[2.6.99] - -[2.6.39] -# mfd header changes for 2.6.39 prevents compilation on 2.6.38. -RADIO_WL1273 - -[2.6.37] -# Some stuff at viafb struct -VIDEO_VIA_CAMERA - -[2.6.36] - -[2.6.34] -MACH_DAVINCI_DM6467_EVM -MFD_TIMBERDALE -RADIO_SAA7706H -VIDEO_TVP7002 - -[2.6.33] -SOC_CAMERA -SOC_CAMERA_MT9V022 -SOC_CAMERA_MT9M001 -SOC_CAMERA_MT9M111 -SOC_CAMERA_MT9T031 -SOC_CAMERA_OV772X -SOC_CAMERA_TW9910 -SOC_CAMERA_PLATFORM -VIDEO_AK881X -V4L2_MEM2MEM_DEV - -[2.6.32] -# These rely on arch support that wasn't available until 2.6.32 -VIDEO_SH_MOBILE_CEU -VIDEO_PXA27x -VIDEO_TLG2300 -# Relies on some changes at Firewire API -DVB_FIREDTV -# Relies on some changes at PnP API -IR_NUVOTON -IR_ENE -IR_WINBOND_CIR - -[2.6.31] -# These rely on arch support that wasn't available until 2.6.31 -VIDEO_VPSS_SYSTEM -VIDEO_VPFE_CAPTURE -VIDEO_DM6446_CCDC -VIDEO_DM355_CCDC -# Start version for those drivers - probably compile with older versions -VIDEO_CX25821 -VIDEO_CX25821_ALSA -VIDEO_ADV7180 -RADIO_TEF6862 -# follow_pfn needed by VIDEOBUF_DMA_CONTIG and drivers that use it -VIDEOBUF_DMA_CONTIG -VIDEOBUF_VMALLOC -DISPLAY_DAVINCI_DM646X_EVM -VIDEO_VPFE_CAPTURE -VIDEO_MX1 -VIDEO_MX3 - -[2.6.26] -# Requires struct i2c_device_id -VIDEO_TVP514X -VIDEO_ADV7180 -# requires id_table and new i2c stuff -RADIO_TEA5764 -VIDEO_THS7303 -VIDEO_ADV7343 -RADIO_SI4713 -I2C_SI4713 - -[2.6.24] -# Some freezer routines -USB_GSPCA_SN9C20X_EVDEV -DVB_PT1 -# Requires linux/mmc/sdio_func.h -SMS_SDIO_DRV -VIDEO_SAA7164 - -[2.6.23] -# Needs field intf_assoc in struct usb_host_config -VIDEO_CX231XX -# writel/readl headers moved -DVB_MANTIS -MANTIS_CORE - - -[2.6.22] -#This driver requires I2C probe/remove fields -VIDEO_TCM825X -# This driver requires list_first_entry -USB_STKWEBCAM -# This driver needs div64_64 -DVB_DRX397XD -# Assumes struct input_dev has a dev field -DVB_DM1105 -# This driver needs hrtimer API -VIDEO_CX88 - -[2.6.20] -#This driver requires HID_REQ_GET_REPORT -USB_SI470X -RADIO_SI470X -# use of struct delayed_work -USB_GSPCA_FINEPIX -USB_GSPCA_JEILINJ -# uses linux/hid.h and struct delayed_work -USB_SI470X -# due to INIT_WORK changes -USB_GSPCA_SQ905 -USB_GSPCA_SQ905C -VIDEO_HDPVR -# due to device_move -VIDEO_PVRUSB2 -# due to struct file.f_path -VIDEO_CPIA - -[2.6.19] -# requires vmalloc_user/remap_vmalloc_range -VIDEO_CAFE_CCIC -VIDEO_TM6000 -#struct device vs struct class_device issues -USB_ET61X251 -USB_SN9C102 -USB_PWC -USB_PWC_DEBUG -USB_OV511 -USB_STV680 -USB_S2255 -VIDEO_USBVISION -# Uses supports_autosuspend -USB_MR800 -USB_DSBR -# Uses MODULE_FIRMWARE -DVB_AV7110 -# usb_complete_t changed prototype -USB_ZR364XX - -[2.6.18] -# Uses remap_vmalloc_range() -VIDEOBUF_VMALLOC -# Uses new class interface, which did not start to appear until 2.6.18. -VIDEO_PVRUSB2_SYSFS -# linux/uaccess.h -VIDEO_PMS - -[2.6.17] -# DVB_CORE_ATTACH relies on symbol_put_addr which hangs pre-2.6.17 -DVB_CORE_ATTACH -# Various changes to ALSA structs -VIDEO_CX18_ALSA -# cx18 needs list_for_each_entry_from -VIDEO_CX18 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/changelog v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/changelog --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/changelog 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/changelog 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -DEBIAN_PACKAGE-dkms (MODULE_VERSION) lucid; urgency=low - * Automatically packaged by DKMS. - - -- Steffen Barszus DATE_STAMP diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/compat v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/compat --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/compat 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -7 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/control v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/control --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/control 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/control 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -Source: DEBIAN_PACKAGE-dkms -Section: misc -Priority: optional -Maintainer: Dynamic Kernel Modules Support Team -Build-Depends: debhelper (>= 7), dkms -Standards-Version: 3.8.1 - -Package: DEBIAN_PACKAGE-dkms -Architecture: all -Depends: dkms (>= 1.95), ${misc:Depends} -Description: DEBIAN_PACKAGE driver in DKMS format. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/copyright v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/copyright --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/copyright 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/copyright 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ - -This copyright has not been completed by the author of this package. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/dirs v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/dirs --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/dirs 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/src diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/postinst v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/postinst --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/postinst 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/postinst 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#!/bin/sh -# Copyright (C) 2002-2005 Flavio Stanchina -# Copyright (C) 2005-2006 Aric Cyr -# Copyright (C) 2007 Mario Limonciello -# Copyright (C) 2009 Alberto Milone - -set -e - -NAME=MODULE_NAME -PACKAGE_NAME=$NAME-dkms -CVERSION=`dpkg-query -W -f='${Version}' $PACKAGE_NAME | awk -F "-" '{print $1}' | cut -d\: -f2` -ARCH=`dpkg --print-architecture` - -dkms_configure () { - for POSTINST in /usr/lib/dkms/common.postinst "/usr/share/$PACKAGE_NAME/postinst"; do - if [ -f "$POSTINST" ]; then - "$POSTINST" "$NAME" "$CVERSION" "/usr/share/$PACKAGE_NAME" "$ARCH" "$2" - return $? - fi - echo "WARNING: $POSTINST does not exist." >&2 - done - echo "ERROR: DKMS version is too old and $PACKAGE_NAME was not" >&2 - echo "built with legacy DKMS support." >&2 - echo "You must either rebuild $PACKAGE_NAME with legacy postinst" >&2 - echo "support or upgrade DKMS to a more current version." >&2 - return 1 -} - -case "$1" in - configure) - dkms_configure - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/prerm v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/prerm --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/prerm 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/prerm 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -#!/bin/sh - -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -set -e - -case "$1" in - remove|upgrade|deconfigure) - if [ "`dkms status -m $NAME`" ]; then - dkms remove -m $NAME -v $VERSION --all - fi - ;; - - failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/README.Debian v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/README.Debian --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/README.Debian 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/README.Debian 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -MODULE_NAME DKMS module for Debian - -This package was automatically generated by the DKMS system, -for distribution on Debian based operating systems. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/rules v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/rules --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/rules 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/rules 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -DEB_NAME=DEBIAN_PACKAGE -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -configure: configure-stamp -configure-stamp: - dh_testdir - touch configure-stamp - - -build: build-stamp - -build-stamp: configure-stamp - dh_testdir - $(MAKE) - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-stamp configure-stamp - -$(MAKE) clean - dh_clean - -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs - $(MAKE) DESTDIR=$(CURDIR)/debian/$(DEB_NAME)-dkms NAME=$(NAME) VERSION=$(VERSION) install - -binary-arch: build install - -binary-indep: build install - dh_testdir - dh_testroot - dh_link - dh_strip - dh_compress - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install configure diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/all-wcprops v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/all-wcprops --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/all-wcprops 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/all-wcprops 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 66 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian -END -control -K 25 -svn:wc:ra_dav:version-url -V 74 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/control -END -dirs -K 25 -svn:wc:ra_dav:version-url -V 71 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/dirs -END -compat -K 25 -svn:wc:ra_dav:version-url -V 73 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/compat -END -postinst -K 25 -svn:wc:ra_dav:version-url -V 75 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/postinst -END -prerm -K 25 -svn:wc:ra_dav:version-url -V 72 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/prerm -END -changelog -K 25 -svn:wc:ra_dav:version-url -V 76 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/changelog -END -copyright -K 25 -svn:wc:ra_dav:version-url -V 76 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/copyright -END -rules -K 25 -svn:wc:ra_dav:version-url -V 72 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/rules -END -README.Debian -K 25 -svn:wc:ra_dav:version-url -V 80 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/README.Debian -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/entries v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/entries --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/entries 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/entries 1970-01-01 00:00:00.000000000 +0000 @@ -1,334 +0,0 @@ -10 - -dir -2682 -https://svn.origo.ethz.ch/yavdr/trunk/misc/make-dkms/templates/v4l-dvb/debian -https://svn.origo.ethz.ch/yavdr - - - -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - -4b10c2f0-612b-4a6c-a5b7-95c0885a526e - -control -file - - - - -2011-02-26T06:31:32.000000Z -932cd11859c7c153a8c458325e74497f -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -353 - -dirs -file - - - - -2011-02-26T06:31:32.000000Z -ea7a90f4a1be2e0054c3d4920c29e33f -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -8 - -compat -file - - - - -2011-02-26T06:31:32.000000Z -84bc3da1b3e33a18e8d5e1bdd7a18d7a -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -2 - -postinst -file - - - - -2011-02-26T06:31:32.000000Z -9332e9792ca4b1d4f79a2f79fe32b9a3 -2011-02-06T14:38:24.074405Z -2612 -steffen_b -has-props - - - - - - - - - - - - - - - - - - - - -1191 - -prerm -file - - - - -2011-02-26T06:31:32.000000Z -e7c0c39003edb2255d22a775efa907e5 -2011-02-06T14:38:24.074405Z -2612 -steffen_b -has-props - - - - - - - - - - - - - - - - - - - - -360 - -changelog -file - - - - -2011-02-26T06:31:32.000000Z -d967421f6c040076e29a8e3c594c9f1d -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -151 - -copyright -file - - - - -2011-02-26T06:31:32.000000Z -de471e376ba2c3886424b5c4649c42d6 -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -70 - -rules -file - - - - -2011-02-26T06:31:32.000000Z -c385ec9e8f6c6745ad9b9665c38cbd84 -2011-02-06T14:38:24.074405Z -2612 -steffen_b -has-props - - - - - - - - - - - - - - - - - - - - -881 - -README.Debian -file - - - - -2011-02-26T06:31:32.000000Z -6707f5716bc3a2d65fa1b05d81ba8add -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -150 - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/postinst.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/postinst.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/postinst.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/postinst.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -K 14 -svn:executable -V 1 -* -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/prerm.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/prerm.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/prerm.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/prerm.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -K 14 -svn:executable -V 1 -* -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/rules.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/rules.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/rules.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/prop-base/rules.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -K 14 -svn:executable -V 1 -* -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/changelog.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/changelog.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/changelog.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/changelog.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -DEBIAN_PACKAGE-dkms (MODULE_VERSION) lucid; urgency=low - * Automatically packaged by DKMS. - - -- Steffen Barszus DATE_STAMP diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/compat.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/compat.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/compat.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/compat.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -7 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/control.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/control.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/control.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/control.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -Source: DEBIAN_PACKAGE-dkms -Section: misc -Priority: optional -Maintainer: Dynamic Kernel Modules Support Team -Build-Depends: debhelper (>= 7), dkms -Standards-Version: 3.8.1 - -Package: DEBIAN_PACKAGE-dkms -Architecture: all -Depends: dkms (>= 1.95), ${misc:Depends} -Description: DEBIAN_PACKAGE driver in DKMS format. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/copyright.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/copyright.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/copyright.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/copyright.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ - -This copyright has not been completed by the author of this package. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/dirs.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/dirs.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/dirs.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/dirs.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/src diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/postinst.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/postinst.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/postinst.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/postinst.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#!/bin/sh -# Copyright (C) 2002-2005 Flavio Stanchina -# Copyright (C) 2005-2006 Aric Cyr -# Copyright (C) 2007 Mario Limonciello -# Copyright (C) 2009 Alberto Milone - -set -e - -NAME=MODULE_NAME -PACKAGE_NAME=$NAME-dkms -CVERSION=`dpkg-query -W -f='${Version}' $PACKAGE_NAME | awk -F "-" '{print $1}' | cut -d\: -f2` -ARCH=`dpkg --print-architecture` - -dkms_configure () { - for POSTINST in /usr/lib/dkms/common.postinst "/usr/share/$PACKAGE_NAME/postinst"; do - if [ -f "$POSTINST" ]; then - "$POSTINST" "$NAME" "$CVERSION" "/usr/share/$PACKAGE_NAME" "$ARCH" "$2" - return $? - fi - echo "WARNING: $POSTINST does not exist." >&2 - done - echo "ERROR: DKMS version is too old and $PACKAGE_NAME was not" >&2 - echo "built with legacy DKMS support." >&2 - echo "You must either rebuild $PACKAGE_NAME with legacy postinst" >&2 - echo "support or upgrade DKMS to a more current version." >&2 - return 1 -} - -case "$1" in - configure) - dkms_configure - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/prerm.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/prerm.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/prerm.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/prerm.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -#!/bin/sh - -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -set -e - -case "$1" in - remove|upgrade|deconfigure) - if [ "`dkms status -m $NAME`" ]; then - dkms remove -m $NAME -v $VERSION --all - fi - ;; - - failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/README.Debian.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/README.Debian.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/README.Debian.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/README.Debian.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -MODULE_NAME DKMS module for Debian - -This package was automatically generated by the DKMS system, -for distribution on Debian based operating systems. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/rules.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/rules.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/rules.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/debian/.svn/text-base/rules.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -DEB_NAME=DEBIAN_PACKAGE -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -configure: configure-stamp -configure-stamp: - dh_testdir - touch configure-stamp - - -build: build-stamp - -build-stamp: configure-stamp - dh_testdir - $(MAKE) - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-stamp configure-stamp - -$(MAKE) clean - dh_clean - -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs - $(MAKE) DESTDIR=$(CURDIR)/debian/$(DEB_NAME)-dkms NAME=$(NAME) VERSION=$(VERSION) install - -binary-arch: build install - -binary-indep: build install - dh_testdir - dh_testroot - dh_link - dh_strip - dh_compress - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install configure diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/Makefile 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#/usr/bin/make -SRC = $(DESTDIR)/usr/src -SHARE = $(DESTDIR)/usr/share/$(NAME)-dkms - -all: - -clean: - -install: - -#source tree -ifeq ("$(wildcard $(NAME)-$(VERSION))", "$(NAME)-$(VERSION)") - install -d "$(SRC)" - cp -a $(NAME)-$(VERSION) $(SRC) -endif - -#tarball, possibly with binaries -ifeq ("$(wildcard $(NAME)-$(VERSION).dkms.tar.gz)", "$(NAME)-$(VERSION).dkms.tar.gz") - install -d "$(SHARE)" - install -m 644 $(NAME)-$(VERSION).dkms.tar.gz "$(SHARE)" -endif - -#postinst, only if we are supporting legacy mode -ifeq ("$(wildcard common.postinst)", "common.postinst") - install -d "$(SHARE)" - install -m 755 $(PREFIX)/usr/lib/dkms/common.postinst $(SHARE)/postinst -endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/all-wcprops v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/all-wcprops --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/all-wcprops 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/all-wcprops 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 59 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb -END -Makefile -K 25 -svn:wc:ra_dav:version-url -V 68 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/Makefile -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/entries v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/entries --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/entries 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/entries 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -10 - -dir -2682 -https://svn.origo.ethz.ch/yavdr/trunk/misc/make-dkms/templates/v4l-dvb -https://svn.origo.ethz.ch/yavdr - - - -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - -4b10c2f0-612b-4a6c-a5b7-95c0885a526e - -debian -dir - -Makefile -file - - - - -2011-02-26T06:31:32.000000Z -0e59a61816086c652ba76743b3759d3f -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -657 - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/text-base/Makefile.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/text-base/Makefile.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/text-base/Makefile.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdeb/.svn/text-base/Makefile.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#/usr/bin/make -SRC = $(DESTDIR)/usr/src -SHARE = $(DESTDIR)/usr/share/$(NAME)-dkms - -all: - -clean: - -install: - -#source tree -ifeq ("$(wildcard $(NAME)-$(VERSION))", "$(NAME)-$(VERSION)") - install -d "$(SRC)" - cp -a $(NAME)-$(VERSION) $(SRC) -endif - -#tarball, possibly with binaries -ifeq ("$(wildcard $(NAME)-$(VERSION).dkms.tar.gz)", "$(NAME)-$(VERSION).dkms.tar.gz") - install -d "$(SHARE)" - install -m 644 $(NAME)-$(VERSION).dkms.tar.gz "$(SHARE)" -endif - -#postinst, only if we are supporting legacy mode -ifeq ("$(wildcard common.postinst)", "common.postinst") - install -d "$(SHARE)" - install -m 755 $(PREFIX)/usr/lib/dkms/common.postinst $(SHARE)/postinst -endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/changelog v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/changelog --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/changelog 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/changelog 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -DEBIAN_PACKAGE-dkms (MODULE_VERSION) lucid; urgency=low - * Automatically packaged by DKMS. - - -- Steffen Barszus DATE_STAMP diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/compat v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/compat --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/compat 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -7 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/control v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/control --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/control 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/control 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -Source: DEBIAN_PACKAGE-dkms -Section: misc -Priority: optional -Maintainer: Dynamic Kernel Modules Support Team -Build-Depends: debhelper (>= 7), dkms -Standards-Version: 3.8.1 - -Package: DEBIAN_PACKAGE-dkms -Architecture: all -Depends: dkms (>= 1.95), ${misc:Depends} -Description: DEBIAN_PACKAGE driver in DKMS format. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/copyright v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/copyright --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/copyright 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/copyright 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ - -This copyright has not been completed by the author of this package. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/dirs v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/dirs --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/dirs 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/src diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/postinst v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/postinst --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/postinst 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/postinst 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#!/bin/sh -# Copyright (C) 2002-2005 Flavio Stanchina -# Copyright (C) 2005-2006 Aric Cyr -# Copyright (C) 2007 Mario Limonciello -# Copyright (C) 2009 Alberto Milone - -set -e - -NAME=MODULE_NAME -PACKAGE_NAME=$NAME-dkms -CVERSION=`dpkg-query -W -f='${Version}' $PACKAGE_NAME | awk -F "-" '{print $1}' | cut -d\: -f2` -ARCH=`dpkg --print-architecture` - -dkms_configure () { - for POSTINST in /usr/lib/dkms/common.postinst "/usr/share/$PACKAGE_NAME/postinst"; do - if [ -f "$POSTINST" ]; then - "$POSTINST" "$NAME" "$CVERSION" "/usr/share/$PACKAGE_NAME" "$ARCH" "$2" - return $? - fi - echo "WARNING: $POSTINST does not exist." >&2 - done - echo "ERROR: DKMS version is too old and $PACKAGE_NAME was not" >&2 - echo "built with legacy DKMS support." >&2 - echo "You must either rebuild $PACKAGE_NAME with legacy postinst" >&2 - echo "support or upgrade DKMS to a more current version." >&2 - return 1 -} - -case "$1" in - configure) - dkms_configure - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/prerm v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/prerm --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/prerm 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/prerm 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -#!/bin/sh - -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -set -e - -case "$1" in - remove|upgrade|deconfigure) - if [ "`dkms status -m $NAME`" ]; then - dkms remove -m $NAME -v $VERSION --all - fi - ;; - - failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/README.Debian v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/README.Debian --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/README.Debian 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/README.Debian 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -MODULE_NAME DKMS module for Debian - -This package was automatically generated by the DKMS system, -for distribution on Debian based operating systems. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/rules v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/rules --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/rules 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/rules 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -DEB_NAME=DEBIAN_PACKAGE -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -configure: configure-stamp -configure-stamp: - dh_testdir - touch configure-stamp - - -build: build-stamp - -build-stamp: configure-stamp - dh_testdir - $(MAKE) - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-stamp configure-stamp - -$(MAKE) clean - dh_clean - -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs - $(MAKE) DESTDIR=$(CURDIR)/debian/$(DEB_NAME)-dkms NAME=$(NAME) VERSION=$(VERSION) install - -binary-arch: build install - -binary-indep: build install - dh_testdir - dh_testroot - dh_link - dh_strip - dh_compress - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install configure diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/all-wcprops v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/all-wcprops --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/all-wcprops 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/all-wcprops 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 66 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian -END -control -K 25 -svn:wc:ra_dav:version-url -V 74 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/control -END -dirs -K 25 -svn:wc:ra_dav:version-url -V 71 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/dirs -END -compat -K 25 -svn:wc:ra_dav:version-url -V 73 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/compat -END -postinst -K 25 -svn:wc:ra_dav:version-url -V 75 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/postinst -END -prerm -K 25 -svn:wc:ra_dav:version-url -V 72 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/prerm -END -changelog -K 25 -svn:wc:ra_dav:version-url -V 76 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/changelog -END -copyright -K 25 -svn:wc:ra_dav:version-url -V 76 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/copyright -END -rules -K 25 -svn:wc:ra_dav:version-url -V 72 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/rules -END -README.Debian -K 25 -svn:wc:ra_dav:version-url -V 80 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/debian/README.Debian -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/entries v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/entries --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/entries 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/entries 1970-01-01 00:00:00.000000000 +0000 @@ -1,334 +0,0 @@ -10 - -dir -2682 -https://svn.origo.ethz.ch/yavdr/trunk/misc/make-dkms/templates/v4l-dvb/debian -https://svn.origo.ethz.ch/yavdr - - - -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - -4b10c2f0-612b-4a6c-a5b7-95c0885a526e - -control -file - - - - -2011-02-26T06:31:32.000000Z -932cd11859c7c153a8c458325e74497f -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -353 - -dirs -file - - - - -2011-02-26T06:31:32.000000Z -ea7a90f4a1be2e0054c3d4920c29e33f -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -8 - -compat -file - - - - -2011-02-26T06:31:32.000000Z -84bc3da1b3e33a18e8d5e1bdd7a18d7a -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -2 - -postinst -file - - - - -2011-02-26T06:31:32.000000Z -9332e9792ca4b1d4f79a2f79fe32b9a3 -2011-02-06T14:38:24.074405Z -2612 -steffen_b -has-props - - - - - - - - - - - - - - - - - - - - -1191 - -prerm -file - - - - -2011-02-26T06:31:32.000000Z -e7c0c39003edb2255d22a775efa907e5 -2011-02-06T14:38:24.074405Z -2612 -steffen_b -has-props - - - - - - - - - - - - - - - - - - - - -360 - -changelog -file - - - - -2011-02-26T06:31:32.000000Z -d967421f6c040076e29a8e3c594c9f1d -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -151 - -copyright -file - - - - -2011-02-26T06:31:32.000000Z -de471e376ba2c3886424b5c4649c42d6 -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -70 - -rules -file - - - - -2011-02-26T06:31:32.000000Z -c385ec9e8f6c6745ad9b9665c38cbd84 -2011-02-06T14:38:24.074405Z -2612 -steffen_b -has-props - - - - - - - - - - - - - - - - - - - - -881 - -README.Debian -file - - - - -2011-02-26T06:31:32.000000Z -6707f5716bc3a2d65fa1b05d81ba8add -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -150 - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/postinst.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/postinst.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/postinst.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/postinst.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -K 14 -svn:executable -V 1 -* -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/prerm.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/prerm.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/prerm.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/prerm.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -K 14 -svn:executable -V 1 -* -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/rules.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/rules.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/rules.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/prop-base/rules.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -K 14 -svn:executable -V 1 -* -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/changelog.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/changelog.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/changelog.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/changelog.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -DEBIAN_PACKAGE-dkms (MODULE_VERSION) lucid; urgency=low - * Automatically packaged by DKMS. - - -- Steffen Barszus DATE_STAMP diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/compat.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/compat.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/compat.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/compat.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -7 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/control.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/control.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/control.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/control.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -Source: DEBIAN_PACKAGE-dkms -Section: misc -Priority: optional -Maintainer: Dynamic Kernel Modules Support Team -Build-Depends: debhelper (>= 7), dkms -Standards-Version: 3.8.1 - -Package: DEBIAN_PACKAGE-dkms -Architecture: all -Depends: dkms (>= 1.95), ${misc:Depends} -Description: DEBIAN_PACKAGE driver in DKMS format. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/copyright.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/copyright.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/copyright.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/copyright.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ - -This copyright has not been completed by the author of this package. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/dirs.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/dirs.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/dirs.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/dirs.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/src diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/postinst.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/postinst.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/postinst.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/postinst.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#!/bin/sh -# Copyright (C) 2002-2005 Flavio Stanchina -# Copyright (C) 2005-2006 Aric Cyr -# Copyright (C) 2007 Mario Limonciello -# Copyright (C) 2009 Alberto Milone - -set -e - -NAME=MODULE_NAME -PACKAGE_NAME=$NAME-dkms -CVERSION=`dpkg-query -W -f='${Version}' $PACKAGE_NAME | awk -F "-" '{print $1}' | cut -d\: -f2` -ARCH=`dpkg --print-architecture` - -dkms_configure () { - for POSTINST in /usr/lib/dkms/common.postinst "/usr/share/$PACKAGE_NAME/postinst"; do - if [ -f "$POSTINST" ]; then - "$POSTINST" "$NAME" "$CVERSION" "/usr/share/$PACKAGE_NAME" "$ARCH" "$2" - return $? - fi - echo "WARNING: $POSTINST does not exist." >&2 - done - echo "ERROR: DKMS version is too old and $PACKAGE_NAME was not" >&2 - echo "built with legacy DKMS support." >&2 - echo "You must either rebuild $PACKAGE_NAME with legacy postinst" >&2 - echo "support or upgrade DKMS to a more current version." >&2 - return 1 -} - -case "$1" in - configure) - dkms_configure - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/prerm.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/prerm.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/prerm.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/prerm.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -#!/bin/sh - -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -set -e - -case "$1" in - remove|upgrade|deconfigure) - if [ "`dkms status -m $NAME`" ]; then - dkms remove -m $NAME -v $VERSION --all - fi - ;; - - failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/README.Debian.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/README.Debian.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/README.Debian.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/README.Debian.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -MODULE_NAME DKMS module for Debian - -This package was automatically generated by the DKMS system, -for distribution on Debian based operating systems. - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/rules.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/rules.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/rules.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/debian/.svn/text-base/rules.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -DEB_NAME=DEBIAN_PACKAGE -NAME=MODULE_NAME -VERSION=MODULE_VERSION - -configure: configure-stamp -configure-stamp: - dh_testdir - touch configure-stamp - - -build: build-stamp - -build-stamp: configure-stamp - dh_testdir - $(MAKE) - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-stamp configure-stamp - -$(MAKE) clean - dh_clean - -install: build - dh_testdir - dh_testroot - dh_prep - dh_installdirs - $(MAKE) DESTDIR=$(CURDIR)/debian/$(DEB_NAME)-dkms NAME=$(NAME) VERSION=$(VERSION) install - -binary-arch: build install - -binary-indep: build install - dh_testdir - dh_testroot - dh_link - dh_strip - dh_compress - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install configure diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/Makefile 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#/usr/bin/make -SRC = $(DESTDIR)/usr/src -SHARE = $(DESTDIR)/usr/share/$(NAME)-dkms - -all: - -clean: - -install: - -#source tree -ifeq ("$(wildcard $(NAME)-$(VERSION))", "$(NAME)-$(VERSION)") - install -d "$(SRC)" - cp -a $(NAME)-$(VERSION) $(SRC) -endif - -#tarball, possibly with binaries -ifeq ("$(wildcard $(NAME)-$(VERSION).dkms.tar.gz)", "$(NAME)-$(VERSION).dkms.tar.gz") - install -d "$(SHARE)" - install -m 644 $(NAME)-$(VERSION).dkms.tar.gz "$(SHARE)" -endif - -#postinst, only if we are supporting legacy mode -ifeq ("$(wildcard common.postinst)", "common.postinst") - install -d "$(SHARE)" - install -m 755 $(PREFIX)/usr/lib/dkms/common.postinst $(SHARE)/postinst -endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/all-wcprops v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/all-wcprops --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/all-wcprops 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/all-wcprops 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 59 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb -END -Makefile -K 25 -svn:wc:ra_dav:version-url -V 68 -/yavdr/!svn/ver/2612/trunk/misc/make-dkms/templates/v4l-dvb/Makefile -END diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/entries v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/entries --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/entries 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/entries 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -10 - -dir -2682 -https://svn.origo.ethz.ch/yavdr/trunk/misc/make-dkms/templates/v4l-dvb -https://svn.origo.ethz.ch/yavdr - - - -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - -4b10c2f0-612b-4a6c-a5b7-95c0885a526e - -debian -dir - -Makefile -file - - - - -2011-02-26T06:31:32.000000Z -0e59a61816086c652ba76743b3759d3f -2011-02-06T14:38:24.074405Z -2612 -steffen_b - - - - - - - - - - - - - - - - - - - - - -657 - diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/text-base/Makefile.svn-base v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/text-base/Makefile.svn-base --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/text-base/Makefile.svn-base 2011-03-24 07:51:42.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160/v4l-dvb-dkms-mkdsc/.svn/text-base/Makefile.svn-base 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#/usr/bin/make -SRC = $(DESTDIR)/usr/src -SHARE = $(DESTDIR)/usr/share/$(NAME)-dkms - -all: - -clean: - -install: - -#source tree -ifeq ("$(wildcard $(NAME)-$(VERSION))", "$(NAME)-$(VERSION)") - install -d "$(SRC)" - cp -a $(NAME)-$(VERSION) $(SRC) -endif - -#tarball, possibly with binaries -ifeq ("$(wildcard $(NAME)-$(VERSION).dkms.tar.gz)", "$(NAME)-$(VERSION).dkms.tar.gz") - install -d "$(SHARE)" - install -m 644 $(NAME)-$(VERSION).dkms.tar.gz "$(SHARE)" -endif - -#postinst, only if we are supporting legacy mode -ifeq ("$(wildcard common.postinst)", "common.postinst") - install -d "$(SHARE)" - install -m 755 $(PREFIX)/usr/lib/dkms/common.postinst $(SHARE)/postinst -endif Binary files /tmp/Gbywmx2BWf/v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110324.git235676.160.dkms.tar.gz and /tmp/PaNNXAO1sq/v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110324.git235676.160.dkms.tar.gz differ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_device_type.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_device_type.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_device_type.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_device_type.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,11 @@ +--- linux/drivers/media/rc/rc-main.c.orig 2011-03-11 18:44:43.734443972 +0100 ++++ linux/drivers/media/rc/rc-main.c 2011-03-11 18:44:56.371948200 +0100 +@@ -904,7 +904,7 @@ + .attrs = rc_dev_attrs, + }; + +-static const struct attribute_group *rc_dev_attr_groups[] = { ++static struct attribute_group *rc_dev_attr_groups[] = { + &rc_dev_attr_grp, + NULL + }; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_nodename.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_nodename.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_nodename.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_nodename.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,44 @@ +--- + drivers/media/dvb/dvb-core/dvbdev.c | 4 ++-- + drivers/media/rc/rc-main.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- linux.orig/drivers/media/dvb/dvb-core/dvbdev.c ++++ linux/drivers/media/dvb/dvb-core/dvbdev.c +@@ -450,7 +450,7 @@ static int dvb_uevent(struct device *dev + return 0; + } + +-static char *dvb_devnode(struct device *dev, mode_t *mode) ++static char *dvb_nodename(struct device *dev) + { + struct dvb_device *dvbdev = dev_get_drvdata(dev); + +@@ -481,7 +481,7 @@ static int __init init_dvbdev(void) + goto error; + } + dvb_class->dev_uevent = dvb_uevent; +- dvb_class->devnode = dvb_devnode; ++ dvb_class->nodename = dvb_nodename; + return 0; + + error: +--- linux.orig/drivers/media/rc/rc-main.c ++++ linux/drivers/media/rc/rc-main.c +@@ -674,14 +674,14 @@ static void ir_close(struct input_dev *i + } + + /* class for /sys/class/rc */ +-static char *ir_devnode(struct device *dev, mode_t *mode) ++static char *ir_nodename(struct device *dev) + { + return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev)); + } + + static struct class ir_input_class = { + .name = "rc", +- .devnode = ir_devnode, ++ .nodename = ir_nodename, + }; + + static struct { diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_series 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_series 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,15 @@ +v2.6.37_dont_use_alloc_ordered_workqueue.patch +v2.6.36_input_getkeycode.patch +v2.6.36_dvb_usb_input_getkeycode.patch +v2.6.35_vm_prev.patch +v2.6.35_firedtv_handle_fcp.patch +v2.6.35_i2c_new_probed_device.patch +v2.6.35_work_handler.patch +v2.6.34_dvb_net.patch +v2.6.34_fix_define_warnings.patch +v2.6.33_input_handlers_are_int.patch +v2.6.33_pvrusb2_sysfs.patch +v2.6.32_kfifo.patch +v2.6.31_nodename.patch +v2.6.31_vm_ops.patch +v2.6.31_device_type.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_vm_ops.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_vm_ops.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_vm_ops.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.31_vm_ops.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,176 @@ +--- + drivers/media/video/cafe_ccic.c | 2 +- + drivers/media/video/et61x251/et61x251_core.c | 2 +- + drivers/media/video/gspca/gspca.c | 2 +- + drivers/media/video/meye.c | 2 +- + drivers/media/video/sn9c102/sn9c102_core.c | 2 +- + drivers/media/video/stk-webcam.c | 2 +- + drivers/media/video/uvc/uvc_queue.c | 2 +- + drivers/media/video/videobuf-dma-contig.c | 2 +- + drivers/media/video/videobuf-dma-sg.c | 2 +- + drivers/media/video/videobuf-vmalloc.c | 2 +- + drivers/media/video/videobuf2-memops.c | 4 ++-- + drivers/media/video/zoran/zoran_driver.c | 2 +- + include/media/videobuf2-memops.h | 4 ++-- + 13 files changed, 15 insertions(+), 15 deletions(-) + +--- linux.orig/drivers/media/video/cafe_ccic.c ++++ linux/drivers/media/video/cafe_ccic.c +@@ -1368,7 +1368,7 @@ static void cafe_v4l_vm_close(struct vm_ + mutex_unlock(&sbuf->cam->s_mutex); + } + +-static const struct vm_operations_struct cafe_v4l_vm_ops = { ++static struct vm_operations_struct cafe_v4l_vm_ops = { + .open = cafe_v4l_vm_open, + .close = cafe_v4l_vm_close + }; +--- linux.orig/drivers/media/video/et61x251/et61x251_core.c ++++ linux/drivers/media/video/et61x251/et61x251_core.c +@@ -1499,7 +1499,7 @@ static void et61x251_vm_close(struct vm_ + } + + +-static const struct vm_operations_struct et61x251_vm_ops = { ++static struct vm_operations_struct et61x251_vm_ops = { + .open = et61x251_vm_open, + .close = et61x251_vm_close, + }; +--- linux.orig/drivers/media/video/gspca/gspca.c ++++ linux/drivers/media/video/gspca/gspca.c +@@ -107,7 +107,7 @@ static void gspca_vm_close(struct vm_are + frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_MAPPED; + } + +-static const struct vm_operations_struct gspca_vm_ops = { ++static struct vm_operations_struct gspca_vm_ops = { + .open = gspca_vm_open, + .close = gspca_vm_close, + }; +--- linux.orig/drivers/media/video/meye.c ++++ linux/drivers/media/video/meye.c +@@ -1593,7 +1593,7 @@ static void meye_vm_close(struct vm_area + meye.vma_use_count[idx]--; + } + +-static const struct vm_operations_struct meye_vm_ops = { ++static struct vm_operations_struct meye_vm_ops = { + .open = meye_vm_open, + .close = meye_vm_close, + }; +--- linux.orig/drivers/media/video/sn9c102/sn9c102_core.c ++++ linux/drivers/media/video/sn9c102/sn9c102_core.c +@@ -2078,7 +2078,7 @@ static void sn9c102_vm_close(struct vm_a + } + + +-static const struct vm_operations_struct sn9c102_vm_ops = { ++static struct vm_operations_struct sn9c102_vm_ops = { + .open = sn9c102_vm_open, + .close = sn9c102_vm_close, + }; +--- linux.orig/drivers/media/video/stk-webcam.c ++++ linux/drivers/media/video/stk-webcam.c +@@ -672,7 +672,7 @@ static void stk_v4l_vm_close(struct vm_a + if (sbuf->mapcount == 0) + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; + } +-static const struct vm_operations_struct stk_v4l_vm_ops = { ++static struct vm_operations_struct stk_v4l_vm_ops = { + .open = stk_v4l_vm_open, + .close = stk_v4l_vm_close + }; +--- linux.orig/drivers/media/video/uvc/uvc_queue.c ++++ linux/drivers/media/video/uvc/uvc_queue.c +@@ -394,7 +394,7 @@ static void uvc_vm_close(struct vm_area_ + buffer->vma_use_count--; + } + +-static const struct vm_operations_struct uvc_vm_ops = { ++static struct vm_operations_struct uvc_vm_ops = { + .open = uvc_vm_open, + .close = uvc_vm_close, + }; +--- linux.orig/drivers/media/video/videobuf-dma-contig.c ++++ linux/drivers/media/video/videobuf-dma-contig.c +@@ -106,7 +106,7 @@ static void videobuf_vm_close(struct vm_ + } + } + +-static const struct vm_operations_struct videobuf_vm_ops = { ++static struct vm_operations_struct videobuf_vm_ops = { + .open = videobuf_vm_open, + .close = videobuf_vm_close, + }; +--- linux.orig/drivers/media/video/videobuf-dma-sg.c ++++ linux/drivers/media/video/videobuf-dma-sg.c +@@ -402,7 +402,7 @@ static int videobuf_vm_fault(struct vm_a + return 0; + } + +-static const struct vm_operations_struct videobuf_vm_ops = { ++static struct vm_operations_struct videobuf_vm_ops = { + .open = videobuf_vm_open, + .close = videobuf_vm_close, + .fault = videobuf_vm_fault, +--- linux.orig/drivers/media/video/videobuf-vmalloc.c ++++ linux/drivers/media/video/videobuf-vmalloc.c +@@ -120,7 +120,7 @@ static void videobuf_vm_close(struct vm_ + return; + } + +-static const struct vm_operations_struct videobuf_vm_ops = { ++static struct vm_operations_struct videobuf_vm_ops = { + .open = videobuf_vm_open, + .close = videobuf_vm_close, + }; +--- linux.orig/drivers/media/video/videobuf2-memops.c ++++ linux/drivers/media/video/videobuf2-memops.c +@@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(vb2_get_contig_userptr + */ + int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, + unsigned long size, +- const struct vm_operations_struct *vm_ops, ++ struct vm_operations_struct *vm_ops, + void *priv) + { + int ret; +@@ -223,7 +223,7 @@ static void vb2_common_vm_close(struct v + * vb2_common_vm_ops - common vm_ops used for tracking refcount of mmaped + * video buffers + */ +-const struct vm_operations_struct vb2_common_vm_ops = { ++struct vm_operations_struct vb2_common_vm_ops = { + .open = vb2_common_vm_open, + .close = vb2_common_vm_close, + }; +--- linux.orig/drivers/media/video/zoran/zoran_driver.c ++++ linux/drivers/media/video/zoran/zoran_driver.c +@@ -2850,7 +2850,7 @@ zoran_vm_close (struct vm_area_struct *v + mutex_unlock(&zr->resource_lock); + } + +-static const struct vm_operations_struct zoran_vm_ops = { ++static struct vm_operations_struct zoran_vm_ops = { + .open = zoran_vm_open, + .close = zoran_vm_close, + }; +--- linux.orig/include/media/videobuf2-memops.h ++++ linux/include/media/videobuf2-memops.h +@@ -28,14 +28,14 @@ struct vb2_vmarea_handler { + void *arg; + }; + +-extern const struct vm_operations_struct vb2_common_vm_ops; ++extern struct vm_operations_struct vb2_common_vm_ops; + + int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, + struct vm_area_struct **res_vma, dma_addr_t *res_pa); + + int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, + unsigned long size, +- const struct vm_operations_struct *vm_ops, ++ struct vm_operations_struct *vm_ops, + void *priv); + + struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.32_kfifo.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.32_kfifo.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.32_kfifo.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.32_kfifo.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,543 @@ +--- + drivers/media/rc/ir-raw.c | 14 +++---- + drivers/media/rc/rc-core-priv.h | 2 - + drivers/media/video/cx23885/cx23888-ir.c | 33 ++++++----------- + drivers/media/video/cx25840/cx25840-ir.c | 28 +++++--------- + drivers/media/video/meye.c | 60 ++++++++++++++----------------- + drivers/media/video/meye.h | 4 +- + include/media/lirc_dev.h | 50 +++++++++---------------- + 7 files changed, 79 insertions(+), 112 deletions(-) + +--- linux.orig/drivers/media/rc/rc-core-priv.h ++++ linux/drivers/media/rc/rc-core-priv.h +@@ -35,7 +35,7 @@ struct ir_raw_event_ctrl { + struct list_head list; /* to keep track of raw clients */ + struct task_struct *thread; + spinlock_t lock; +- struct kfifo kfifo; /* fifo for the pulse/space durations */ ++ struct kfifo *kfifo; /* fifo for the pulse/space durations */ + ktime_t last_event; /* when last event occurred */ + enum raw_event_type last_type; /* last event type */ + struct rc_dev *dev; /* pointer to the parent rc_dev */ +--- linux.orig/drivers/media/rc/ir-raw.c ++++ linux/drivers/media/rc/ir-raw.c +@@ -44,7 +44,7 @@ static int ir_raw_event_thread(void *dat + while (!kthread_should_stop()) { + + spin_lock_irq(&raw->lock); +- retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev)); ++ retval = __kfifo_get(raw->kfifo, (void *)&ev, sizeof(ev)); + + if (!retval) { + set_current_state(TASK_INTERRUPTIBLE); +@@ -90,7 +90,7 @@ int ir_raw_event_store(struct rc_dev *de + IR_dprintk(2, "sample: (%05dus %s)\n", + TO_US(ev->duration), TO_STR(ev->pulse)); + +- if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) ++ if (__kfifo_put(dev->raw->kfifo, (void *)ev, sizeof(*ev)) != sizeof(*ev)) + return -ENOMEM; + + return 0; +@@ -258,11 +258,11 @@ int ir_raw_event_register(struct rc_dev + + dev->raw->dev = dev; + dev->raw->enabled_protocols = ~0; +- rc = kfifo_alloc(&dev->raw->kfifo, +- sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, +- GFP_KERNEL); +- if (rc < 0) ++ dev->raw->kfifo = kfifo_alloc(sizeof(s64) * MAX_IR_EVENT_SIZE, GFP_KERNEL, NULL); ++ if (IS_ERR(dev->raw->kfifo)) { ++ rc = PTR_ERR(dev->raw->kfifo); + goto out; ++ } + + spin_lock_init(&dev->raw->lock); + dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, +@@ -304,7 +304,7 @@ void ir_raw_event_unregister(struct rc_d + handler->raw_unregister(dev); + mutex_unlock(&ir_raw_handler_lock); + +- kfifo_free(&dev->raw->kfifo); ++ kfifo_free(dev->raw->kfifo); + kfree(dev->raw); + dev->raw = NULL; + } +--- linux.orig/drivers/media/video/cx23885/cx23888-ir.c ++++ linux/drivers/media/video/cx23885/cx23888-ir.c +@@ -138,7 +138,7 @@ struct cx23888_ir_state { + atomic_t rxclk_divider; + atomic_t rx_invert; + +- struct kfifo rx_kfifo; ++ struct kfifo *rx_kfifo; + spinlock_t rx_kfifo_lock; + + struct v4l2_subdev_ir_parameters tx_params; +@@ -540,7 +540,6 @@ static int cx23888_ir_irq_handler(struct + { + struct cx23888_ir_state *state = to_state(sd); + struct cx23885_dev *dev = state->dev; +- unsigned long flags; + + u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); + u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); +@@ -613,10 +612,9 @@ static int cx23888_ir_irq_handler(struct + } + if (i == 0) + break; +- j = i * sizeof(union cx23888_ir_fifo_rec); +- k = kfifo_in_locked(&state->rx_kfifo, +- (unsigned char *) rx_data, j, +- &state->rx_kfifo_lock); ++ j = i * sizeof(u32); ++ k = kfifo_put(state->rx_kfifo, ++ (unsigned char *) rx_data, j); + if (k != j) + kror++; /* rx_kfifo over run */ + } +@@ -653,10 +651,8 @@ static int cx23888_ir_irq_handler(struct + *handled = true; + } + +- spin_lock_irqsave(&state->rx_kfifo_lock, flags); +- if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) ++ if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) + events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; +- spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); + + if (events) + v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); +@@ -682,7 +678,7 @@ static int cx23888_ir_rx_read(struct v4l + return 0; + } + +- n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock); ++ n = kfifo_get(state->rx_kfifo, buf, n); + + n /= sizeof(union cx23888_ir_fifo_rec); + *num = n * sizeof(union cx23888_ir_fifo_rec); +@@ -817,12 +813,7 @@ static int cx23888_ir_rx_s_parameters(st + o->interrupt_enable = p->interrupt_enable; + o->enable = p->enable; + if (p->enable) { +- unsigned long flags; +- +- spin_lock_irqsave(&state->rx_kfifo_lock, flags); +- kfifo_reset(&state->rx_kfifo); +- /* reset tx_fifo too if there is one... */ +- spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); ++ kfifo_reset(state->rx_kfifo); + if (p->interrupt_enable) + irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); + control_rx_enable(dev, p->enable); +@@ -1210,8 +1201,10 @@ int cx23888_ir_probe(struct cx23885_dev + return -ENOMEM; + + spin_lock_init(&state->rx_kfifo_lock); +- if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL)) +- return -ENOMEM; ++ state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL, ++ &state->rx_kfifo_lock); ++ if (IS_ERR(state->rx_kfifo)) ++ return IS_ERR(state->rx_kfifo); + + state->dev = dev; + state->id = V4L2_IDENT_CX23888_IR; +@@ -1243,7 +1236,7 @@ int cx23888_ir_probe(struct cx23885_dev + sizeof(struct v4l2_subdev_ir_parameters)); + v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); + } else { +- kfifo_free(&state->rx_kfifo); ++ kfifo_free(state->rx_kfifo); + } + return ret; + } +@@ -1262,7 +1255,7 @@ int cx23888_ir_remove(struct cx23885_dev + + state = to_state(sd); + v4l2_device_unregister_subdev(sd); +- kfifo_free(&state->rx_kfifo); ++ kfifo_free(state->rx_kfifo); + kfree(state); + /* Nothing more to free() as state held the actual v4l2_subdev object */ + return 0; +--- linux.orig/drivers/media/video/cx25840/cx25840-ir.c ++++ linux/drivers/media/video/cx25840/cx25840-ir.c +@@ -116,7 +116,7 @@ struct cx25840_ir_state { + atomic_t rxclk_divider; + atomic_t rx_invert; + +- struct kfifo rx_kfifo; ++ struct kfifo *rx_kfifo; + spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */ + + struct v4l2_subdev_ir_parameters tx_params; +@@ -525,7 +525,6 @@ int cx25840_ir_irq_handler(struct v4l2_s + struct cx25840_state *state = to_state(sd); + struct cx25840_ir_state *ir_state = to_ir_state(sd); + struct i2c_client *c = NULL; +- unsigned long flags; + + union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; + unsigned int i, j, k; +@@ -611,9 +610,8 @@ int cx25840_ir_irq_handler(struct v4l2_s + if (i == 0) + break; + j = i * sizeof(union cx25840_ir_fifo_rec); +- k = kfifo_in_locked(&ir_state->rx_kfifo, +- (unsigned char *) rx_data, j, +- &ir_state->rx_kfifo_lock); ++ k = kfifo_put(ir_state->rx_kfifo, ++ (unsigned char *) rx_data, j); + if (k != j) + kror++; /* rx_kfifo over run */ + } +@@ -649,10 +647,8 @@ int cx25840_ir_irq_handler(struct v4l2_s + cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl); + *handled = true; + } +- spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); +- if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) ++ if (kfifo_len(ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) + events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; +- spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); + + if (events) + v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); +@@ -683,8 +679,7 @@ static int cx25840_ir_rx_read(struct v4l + return 0; + } + +- n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n, +- &ir_state->rx_kfifo_lock); ++ n = kfifo_get(ir_state->rx_kfifo, buf, n); + + n /= sizeof(union cx25840_ir_fifo_rec); + *num = n * sizeof(union cx25840_ir_fifo_rec); +@@ -836,11 +831,7 @@ static int cx25840_ir_rx_s_parameters(st + o->interrupt_enable = p->interrupt_enable; + o->enable = p->enable; + if (p->enable) { +- unsigned long flags; +- +- spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); +- kfifo_reset(&ir_state->rx_kfifo); +- spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); ++ kfifo_reset(ir_state->rx_kfifo); + if (p->interrupt_enable) + irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); + control_rx_enable(c, p->enable); +@@ -1234,8 +1225,9 @@ int cx25840_ir_probe(struct v4l2_subdev + return -ENOMEM; + + spin_lock_init(&ir_state->rx_kfifo_lock); +- if (kfifo_alloc(&ir_state->rx_kfifo, +- CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) { ++ ir_state->rx_kfifo = kfifo_alloc(CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL, ++ &ir_state->rx_kfifo_lock); ++ if (IS_ERR(ir_state->rx_kfifo)) { + kfree(ir_state); + return -ENOMEM; + } +@@ -1273,7 +1265,7 @@ int cx25840_ir_remove(struct v4l2_subdev + cx25840_ir_rx_shutdown(sd); + cx25840_ir_tx_shutdown(sd); + +- kfifo_free(&ir_state->rx_kfifo); ++ kfifo_free(ir_state->rx_kfifo); + kfree(ir_state); + state->ir_state = NULL; + return 0; +--- linux.orig/drivers/media/video/meye.c ++++ linux/drivers/media/video/meye.c +@@ -802,8 +802,8 @@ again: + return IRQ_HANDLED; + + if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) { +- if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, +- sizeof(int), &meye.grabq_lock) != sizeof(int)) { ++ if (kfifo_get(meye.grabq, (unsigned char *)&reqnr, ++ sizeof(int)) != sizeof(int)) { + mchip_free_frame(); + return IRQ_HANDLED; + } +@@ -813,8 +813,7 @@ again: + meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; + do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); + meye.grab_buffer[reqnr].sequence = sequence++; +- kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, +- sizeof(int), &meye.doneq_lock); ++ kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); + wake_up_interruptible(&meye.proc_list); + } else { + int size; +@@ -823,8 +822,8 @@ again: + mchip_free_frame(); + goto again; + } +- if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, +- sizeof(int), &meye.grabq_lock) != sizeof(int)) { ++ if (kfifo_get(meye.grabq, (unsigned char *)&reqnr, ++ sizeof(int)) != sizeof(int)) { + mchip_free_frame(); + goto again; + } +@@ -834,8 +833,7 @@ again: + meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; + do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); + meye.grab_buffer[reqnr].sequence = sequence++; +- kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, +- sizeof(int), &meye.doneq_lock); ++ kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); + wake_up_interruptible(&meye.proc_list); + } + mchip_free_frame(); +@@ -863,8 +861,8 @@ static int meye_open(struct file *file) + + for (i = 0; i < MEYE_MAX_BUFNBRS; i++) + meye.grab_buffer[i].state = MEYE_BUF_UNUSED; +- kfifo_reset(&meye.grabq); +- kfifo_reset(&meye.doneq); ++ kfifo_reset(meye.grabq); ++ kfifo_reset(meye.doneq); + return 0; + } + +@@ -937,8 +935,7 @@ static int meyeioc_qbuf_capt(int *nb) + mchip_cont_compression_start(); + + meye.grab_buffer[*nb].state = MEYE_BUF_USING; +- kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int), +- &meye.grabq_lock); ++ kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int)); + mutex_unlock(&meye.lock); + + return 0; +@@ -970,9 +967,7 @@ static int meyeioc_sync(struct file *fil + /* fall through */ + case MEYE_BUF_DONE: + meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; +- if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused, +- sizeof(int), &meye.doneq_lock) != sizeof(int)) +- break; ++ kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int)); + } + *i = meye.grab_buffer[*i].size; + mutex_unlock(&meye.lock); +@@ -1459,8 +1454,7 @@ static int vidioc_qbuf(struct file *file + buf->flags |= V4L2_BUF_FLAG_QUEUED; + buf->flags &= ~V4L2_BUF_FLAG_DONE; + meye.grab_buffer[buf->index].state = MEYE_BUF_USING; +- kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index, +- sizeof(int), &meye.grabq_lock); ++ kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int)); + mutex_unlock(&meye.lock); + + return 0; +@@ -1475,19 +1469,19 @@ static int vidioc_dqbuf(struct file *fil + + mutex_lock(&meye.lock); + +- if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { ++ if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { + mutex_unlock(&meye.lock); + return -EAGAIN; + } + + if (wait_event_interruptible(meye.proc_list, +- kfifo_len(&meye.doneq) != 0) < 0) { ++ kfifo_len(meye.doneq) != 0) < 0) { + mutex_unlock(&meye.lock); + return -EINTR; + } + +- if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr, +- sizeof(int), &meye.doneq_lock)) { ++ if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr, ++ sizeof(int))) { + mutex_unlock(&meye.lock); + return -EBUSY; + } +@@ -1537,8 +1531,8 @@ static int vidioc_streamoff(struct file + { + mutex_lock(&meye.lock); + mchip_hic_stop(); +- kfifo_reset(&meye.grabq); +- kfifo_reset(&meye.doneq); ++ kfifo_reset(meye.grabq); ++ kfifo_reset(meye.doneq); + + for (i = 0; i < MEYE_MAX_BUFNBRS; i++) + meye.grab_buffer[i].state = MEYE_BUF_UNUSED; +@@ -1581,7 +1575,7 @@ static unsigned int meye_poll(struct fil + + mutex_lock(&meye.lock); + poll_wait(file, &meye.proc_list, wait); +- if (kfifo_len(&meye.doneq)) ++ if (kfifo_len(meye.doneq)) + res = POLLIN | POLLRDNORM; + mutex_unlock(&meye.lock); + return res; +@@ -1760,14 +1754,16 @@ static int __devinit meye_probe(struct p + } + + spin_lock_init(&meye.grabq_lock); +- if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, +- GFP_KERNEL)) { ++ meye.grabq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL, ++ &meye.grabq_lock); ++ if (IS_ERR(meye.grabq)) { + v4l2_err(v4l2_dev, "fifo allocation failed\n"); + goto outkfifoalloc1; + } + spin_lock_init(&meye.doneq_lock); +- if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, +- GFP_KERNEL)) { ++ meye.doneq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL, ++ &meye.doneq_lock); ++ if (IS_ERR(meye.doneq)) { + v4l2_err(v4l2_dev, "fifo allocation failed\n"); + goto outkfifoalloc2; + } +@@ -1878,9 +1874,9 @@ outregions: + outenabledev: + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); + outsonypienable: +- kfifo_free(&meye.doneq); ++ kfifo_free(meye.doneq); + outkfifoalloc2: +- kfifo_free(&meye.grabq); ++ kfifo_free(meye.grabq); + outkfifoalloc1: + vfree(meye.grab_temp); + outvmalloc: +@@ -1911,8 +1907,8 @@ static void __devexit meye_remove(struct + + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); + +- kfifo_free(&meye.doneq); +- kfifo_free(&meye.grabq); ++ kfifo_free(meye.doneq); ++ kfifo_free(meye.grabq); + + vfree(meye.grab_temp); + +--- linux.orig/drivers/media/video/meye.h ++++ linux/drivers/media/video/meye.h +@@ -304,9 +304,9 @@ struct meye { + struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; + int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */ + struct mutex lock; /* mutex for open/mmap... */ +- struct kfifo grabq; /* queue for buffers to be grabbed */ ++ struct kfifo *grabq; /* queue for buffers to be grabbed */ + spinlock_t grabq_lock; /* lock protecting the queue */ +- struct kfifo doneq; /* queue for grabbed buffers */ ++ struct kfifo *doneq; /* queue for grabbed buffers */ + spinlock_t doneq_lock; /* lock protecting the queue */ + wait_queue_head_t proc_list; /* wait queue */ + struct video_device *vdev; /* video device parameters */ +--- linux.orig/include/media/lirc_dev.h ++++ linux/include/media/lirc_dev.h +@@ -28,19 +28,15 @@ struct lirc_buffer { + unsigned int size; /* in chunks */ + /* Using chunks instead of bytes pretends to simplify boundary checking + * And should allow for some performance fine tunning later */ +- struct kfifo fifo; ++ struct kfifo *fifo; + u8 fifo_initialized; + }; + + static inline void lirc_buffer_clear(struct lirc_buffer *buf) + { +- unsigned long flags; +- +- if (buf->fifo_initialized) { +- spin_lock_irqsave(&buf->fifo_lock, flags); +- kfifo_reset(&buf->fifo); +- spin_unlock_irqrestore(&buf->fifo_lock, flags); +- } else ++ if (buf->fifo) ++ kfifo_reset(buf->fifo); ++ else + WARN(1, "calling %s on an uninitialized lirc_buffer\n", + __func__); + } +@@ -49,25 +45,23 @@ static inline int lirc_buffer_init(struc + unsigned int chunk_size, + unsigned int size) + { +- int ret; +- + init_waitqueue_head(&buf->wait_poll); + spin_lock_init(&buf->fifo_lock); + buf->chunk_size = chunk_size; + buf->size = size; +- ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL); +- if (ret == 0) +- buf->fifo_initialized = 1; ++ buf->fifo = kfifo_alloc(size * chunk_size, GFP_KERNEL, ++ &buf->fifo_lock); ++ if (IS_ERR(buf->fifo)) ++ return IS_ERR(buf->fifo); + +- return ret; ++ return 0; + } + + static inline void lirc_buffer_free(struct lirc_buffer *buf) + { +- if (buf->fifo_initialized) { +- kfifo_free(&buf->fifo); +- buf->fifo_initialized = 0; +- } else ++ if (buf->fifo) ++ kfifo_free(buf->fifo); ++ else + WARN(1, "calling %s on an uninitialized lirc_buffer\n", + __func__); + } +@@ -75,11 +69,8 @@ static inline void lirc_buffer_free(stru + static inline int lirc_buffer_len(struct lirc_buffer *buf) + { + int len; +- unsigned long flags; + +- spin_lock_irqsave(&buf->fifo_lock, flags); +- len = kfifo_len(&buf->fifo); +- spin_unlock_irqrestore(&buf->fifo_lock, flags); ++ len = kfifo_len(buf->fifo); + + return len; + } +@@ -102,24 +93,19 @@ static inline int lirc_buffer_available( + static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf, + unsigned char *dest) + { +- unsigned int ret = 0; +- + if (lirc_buffer_len(buf) >= buf->chunk_size) +- ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size, +- &buf->fifo_lock); +- return ret; ++ kfifo_get(buf->fifo, dest, buf->chunk_size); ++ ++ return 0; + + } + + static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, + unsigned char *orig) + { +- unsigned int ret; +- +- ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size, +- &buf->fifo_lock); ++ kfifo_put(buf->fifo, orig, buf->chunk_size); + +- return ret; ++ return 0; + } + + struct lirc_driver { diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.32_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.32_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.32_series 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.32_series 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,12 @@ +v2.6.37_dont_use_alloc_ordered_workqueue.patch +v2.6.36_input_getkeycode.patch +v2.6.36_dvb_usb_input_getkeycode.patch +v2.6.35_vm_prev.patch +v2.6.35_firedtv_handle_fcp.patch +v2.6.35_i2c_new_probed_device.patch +v2.6.35_work_handler.patch +v2.6.34_dvb_net.patch +v2.6.34_fix_define_warnings.patch +v2.6.33_input_handlers_are_int.patch +v2.6.33_pvrusb2_sysfs.patch +v2.6.32_kfifo.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_input_handlers_are_int.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_input_handlers_are_int.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_input_handlers_are_int.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_input_handlers_are_int.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,45 @@ +--- + drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 4 ++-- + drivers/media/rc/rc-main.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- linux.orig/drivers/media/rc/rc-main.c ++++ linux/drivers/media/rc/rc-main.c +@@ -318,7 +318,7 @@ static unsigned int ir_establish_scancod + * This routine is used to handle evdev EVIOCSKEY ioctl. + */ + static int ir_setkeycode(struct input_dev *idev, +- unsigned int scancode, unsigned int keycode) ++ int scancode, int keycode) + { + struct rc_dev *rdev = input_get_drvdata(idev); + struct rc_map *rc_map = &rdev->rc_map; +@@ -422,7 +422,7 @@ static unsigned int ir_lookup_by_scancod + * This routine is used to handle evdev EVIOCGKEY ioctl. + */ + static int ir_getkeycode(struct input_dev *idev, +- unsigned int scancode, unsigned int *keycode) ++ int scancode, int *keycode) + { + struct rc_dev *rdev = input_get_drvdata(idev); + struct rc_map *rc_map = &rdev->rc_map; +--- linux.orig/drivers/media/dvb/dvb-usb/dvb-usb-remote.c ++++ linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +@@ -9,7 +9,7 @@ + #include + + static int legacy_dvb_usb_getkeycode(struct input_dev *dev, +- unsigned int scancode, unsigned int *keycode) ++ int scancode, int *keycode) + { + struct dvb_usb_device *d = input_get_drvdata(dev); + +@@ -39,7 +39,7 @@ static int legacy_dvb_usb_getkeycode(str + } + + static int legacy_dvb_usb_setkeycode(struct input_dev *dev, +- unsigned int scancode, unsigned int keycode) ++ int scancode, int keycode) + { + struct dvb_usb_device *d = input_get_drvdata(dev); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_pvrusb2_sysfs.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_pvrusb2_sysfs.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_pvrusb2_sysfs.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_pvrusb2_sysfs.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,73 @@ +--- + drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 14 -------------- + 1 file changed, 14 deletions(-) + +--- linux.orig/drivers/media/video/pvrusb2/pvrusb2-sysfs.c ++++ linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +@@ -432,12 +432,10 @@ static void pvr2_sysfs_add_debugifc(stru + + dip = kzalloc(sizeof(*dip),GFP_KERNEL); + if (!dip) return; +- sysfs_attr_init(&dip->attr_debugcmd.attr); + dip->attr_debugcmd.attr.name = "debugcmd"; + dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP; + dip->attr_debugcmd.show = debugcmd_show; + dip->attr_debugcmd.store = debugcmd_store; +- sysfs_attr_init(&dip->attr_debuginfo.attr); + dip->attr_debuginfo.attr.name = "debuginfo"; + dip->attr_debuginfo.attr.mode = S_IRUGO; + dip->attr_debuginfo.show = debuginfo_show; +@@ -659,8 +657,6 @@ static void class_dev_create(struct pvr2 + put_device(class_dev); + return; + } +- +- sysfs_attr_init(&sfp->attr_v4l_minor_number.attr); + sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number"; + sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; + sfp->attr_v4l_minor_number.show = v4l_minor_number_show; +@@ -674,8 +670,6 @@ static void class_dev_create(struct pvr2 + } else { + sfp->v4l_minor_number_created_ok = !0; + } +- +- sysfs_attr_init(&sfp->attr_v4l_radio_minor_number.attr); + sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number"; + sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; + sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; +@@ -689,8 +683,6 @@ static void class_dev_create(struct pvr2 + } else { + sfp->v4l_radio_minor_number_created_ok = !0; + } +- +- sysfs_attr_init(&sfp->attr_unit_number.attr); + sfp->attr_unit_number.attr.name = "unit_number"; + sfp->attr_unit_number.attr.mode = S_IRUGO; + sfp->attr_unit_number.show = unit_number_show; +@@ -703,8 +695,6 @@ static void class_dev_create(struct pvr2 + } else { + sfp->unit_number_created_ok = !0; + } +- +- sysfs_attr_init(&sfp->attr_bus_info.attr); + sfp->attr_bus_info.attr.name = "bus_info_str"; + sfp->attr_bus_info.attr.mode = S_IRUGO; + sfp->attr_bus_info.show = bus_info_show; +@@ -718,8 +708,6 @@ static void class_dev_create(struct pvr2 + } else { + sfp->bus_info_created_ok = !0; + } +- +- sysfs_attr_init(&sfp->attr_hdw_name.attr); + sfp->attr_hdw_name.attr.name = "device_hardware_type"; + sfp->attr_hdw_name.attr.mode = S_IRUGO; + sfp->attr_hdw_name.show = hdw_name_show; +@@ -733,8 +721,6 @@ static void class_dev_create(struct pvr2 + } else { + sfp->hdw_name_created_ok = !0; + } +- +- sysfs_attr_init(&sfp->attr_hdw_desc.attr); + sfp->attr_hdw_desc.attr.name = "device_hardware_description"; + sfp->attr_hdw_desc.attr.mode = S_IRUGO; + sfp->attr_hdw_desc.show = hdw_desc_show; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_series 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.33_series 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,11 @@ +v2.6.37_dont_use_alloc_ordered_workqueue.patch +v2.6.36_input_getkeycode.patch +v2.6.36_dvb_usb_input_getkeycode.patch +v2.6.35_vm_prev.patch +v2.6.35_firedtv_handle_fcp.patch +v2.6.35_i2c_new_probed_device.patch +v2.6.35_work_handler.patch +v2.6.34_dvb_net.patch +v2.6.34_fix_define_warnings.patch +v2.6.33_input_handlers_are_int.patch +v2.6.33_pvrusb2_sysfs.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_dvb_net.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_dvb_net.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_dvb_net.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_dvb_net.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,40 @@ +diff -r 5254948f88c4 drivers/media/dvb/dvb-core/dvb_net.c +--- a/drivers/media/dvb/dvb-core/dvb_net.c Sun Oct 17 19:59:28 2010 -0200 ++++ b/drivers/media/dvb/dvb-core/dvb_net.c Sun Oct 17 20:09:51 2010 -0200 +@@ -1119,14 +1119,14 @@ + } + + +-static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr) ++static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) + { + struct dvb_net_priv *priv = netdev_priv(dev); + + if (priv->multi_num == DVB_NET_MULTICAST_MAX) + return -ENOMEM; + +- memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN); ++ memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6); + + priv->multi_num++; + return 0; +@@ -1150,16 +1150,15 @@ + dprintk("%s: allmulti mode\n", dev->name); + priv->rx_mode = RX_MODE_ALL_MULTI; + } else if (!netdev_mc_empty(dev)) { +- struct netdev_hw_addr *ha; +- ++ struct dev_mc_list *mc; + dprintk("%s: set_mc_list, %d entries\n", + dev->name, netdev_mc_count(dev)); + + priv->rx_mode = RX_MODE_MULTI; + priv->multi_num = 0; + +- netdev_for_each_mc_addr(ha, dev) +- dvb_set_mc_filter(dev, ha->addr); ++ netdev_for_each_mc_addr(mc, dev) ++ dvb_set_mc_filter(dev, mc); + } + + netif_addr_unlock_bh(dev); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_fix_define_warnings.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_fix_define_warnings.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_fix_define_warnings.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_fix_define_warnings.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,22 @@ +diff -r a0ea01e58ec5 drivers/media/rc/imon.c +--- a/drivers/media/rc/imon.c Wed Oct 27 20:58:38 2010 -0200 ++++ b/drivers/media/rc/imon.c Wed Oct 27 21:07:04 2010 -0200 +@@ -26,6 +26,7 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + ++#undef pr_fmt + #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + + #include +diff -r a0ea01e58ec5 drivers/media/dvb/frontends/tua6100.c +--- a/drivers/media/dvb/frontends/tua6100.c Wed Oct 27 20:58:38 2010 -0200 ++++ b/drivers/media/dvb/frontends/tua6100.c Wed Oct 27 21:07:04 2010 -0200 +@@ -80,6 +80,7 @@ + struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 }; + struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 }; + ++#undef _P + #define _R 4 + #define _P 32 + #define _ri 4000000 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_series 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.34_series 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,9 @@ +v2.6.37_dont_use_alloc_ordered_workqueue.patch +v2.6.36_input_getkeycode.patch +v2.6.36_dvb_usb_input_getkeycode.patch +v2.6.35_vm_prev.patch +v2.6.35_firedtv_handle_fcp.patch +v2.6.35_i2c_new_probed_device.patch +v2.6.35_work_handler.patch +v2.6.34_dvb_net.patch +v2.6.34_fix_define_warnings.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_firedtv_handle_fcp.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_firedtv_handle_fcp.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_firedtv_handle_fcp.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_firedtv_handle_fcp.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,19 @@ +--- + drivers/media/dvb/firewire/firedtv-fw.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- linux.orig/drivers/media/dvb/firewire/firedtv-fw.c ++++ linux/drivers/media/dvb/firewire/firedtv-fw.c +@@ -192,9 +192,9 @@ void fdtv_stop_iso(struct firedtv *fdtv) + } + + static void handle_fcp(struct fw_card *card, struct fw_request *request, +- int tcode, int destination, int source, int generation, +- unsigned long long offset, void *payload, size_t length, +- void *callback_data) ++ int tcode, int destination, int source, int generation, ++ int speed, unsigned long long offset, ++ void *payload, size_t length, void *callback_data) + { + struct firedtv *f, *fdtv = NULL; + struct fw_device *device; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_i2c_new_probed_device.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_i2c_new_probed_device.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_i2c_new_probed_device.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_i2c_new_probed_device.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,104 @@ +--- + drivers/media/video/bt8xx/bttv-input.c | 2 +- + drivers/media/video/cx18/cx18-i2c.c | 2 +- + drivers/media/video/cx23885/cx23885-i2c.c | 5 +++-- + drivers/media/video/em28xx/em28xx-cards.c | 2 +- + drivers/media/video/ivtv/ivtv-i2c.c | 6 +++--- + drivers/media/video/v4l2-common.c | 3 +-- + 6 files changed, 10 insertions(+), 10 deletions(-) + +--- linux.orig/drivers/media/video/bt8xx/bttv-input.c ++++ linux/drivers/media/video/bt8xx/bttv-input.c +@@ -399,7 +399,7 @@ void __devinit init_bttv_i2c_ir(struct b + * That's why we probe 0x1a (~0x34) first. CB + */ + +- i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); ++ i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list); + return; + } + +--- linux.orig/drivers/media/video/cx18/cx18-i2c.c ++++ linux/drivers/media/video/cx18/cx18-i2c.c +@@ -104,7 +104,7 @@ static int cx18_i2c_new_ir(struct cx18 * + break; + } + +- return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? ++ return i2c_new_probed_device(adap, &info, addr_list) == NULL ? + -1 : 0; + } + +--- linux.orig/drivers/media/video/cx23885/cx23885-i2c.c ++++ linux/drivers/media/video/cx23885/cx23885-i2c.c +@@ -344,7 +344,8 @@ int cx23885_i2c_register(struct cx23885_ + } else + printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", + dev->name, bus->nr); +- ++#if 0 ++ /* This probe function won't work on older devices */ + /* Instantiate the IR receiver device, if present */ + if (0 == bus->i2c_rc) { + struct i2c_board_info info; +@@ -359,7 +360,7 @@ int cx23885_i2c_register(struct cx23885_ + i2c_new_probed_device(&bus->i2c_adap, &info, addr_list, + i2c_probe_func_quick_read); + } +- ++#endif + return bus->i2c_rc; + } + +--- linux.orig/drivers/media/video/em28xx/em28xx-cards.c ++++ linux/drivers/media/video/em28xx/em28xx-cards.c +@@ -2454,7 +2454,7 @@ void em28xx_register_i2c_ir(struct em28x + + if (dev->init_data.name) + info.platform_data = &dev->init_data; +- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL); ++ i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); + } + + void em28xx_card_setup(struct em28xx *dev) +--- linux.orig/drivers/media/video/ivtv/ivtv-i2c.c ++++ linux/drivers/media/video/ivtv/ivtv-i2c.c +@@ -186,7 +186,7 @@ static int ivtv_i2c_new_ir(struct ivtv * + return -1; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, type, I2C_NAME_SIZE); +- return i2c_new_probed_device(adap, &info, addr_list, NULL) ++ return i2c_new_probed_device(adap, &info, addr_list) + == NULL ? -1 : 0; + } + +@@ -230,7 +230,7 @@ static int ivtv_i2c_new_ir(struct ivtv * + info.platform_data = init_data; + strlcpy(info.type, type, I2C_NAME_SIZE); + +- return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? ++ return i2c_new_probed_device(adap, &info, addr_list) == NULL ? + -1 : 0; + } + +@@ -257,7 +257,7 @@ struct i2c_client *ivtv_i2c_new_ir_legac + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); +- return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list, NULL); ++ return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list); + } + + int ivtv_i2c_register(struct ivtv *itv, unsigned idx) +--- linux.orig/drivers/media/video/v4l2-common.c ++++ linux/drivers/media/video/v4l2-common.c +@@ -316,8 +316,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_ + + /* Create the i2c client */ + if (info->addr == 0 && probe_addrs) +- client = i2c_new_probed_device(adapter, info, probe_addrs, +- NULL); ++ client = i2c_new_probed_device(adapter, info, probe_addrs); + else + client = i2c_new_device(adapter, info); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_series 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_series 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,7 @@ +v2.6.37_dont_use_alloc_ordered_workqueue.patch +v2.6.36_input_getkeycode.patch +v2.6.36_dvb_usb_input_getkeycode.patch +v2.6.35_vm_prev.patch +v2.6.35_firedtv_handle_fcp.patch +v2.6.35_i2c_new_probed_device.patch +v2.6.35_work_handler.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_vm_prev.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_vm_prev.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_vm_prev.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_vm_prev.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,12 @@ +diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c +index 053c157..c47f56e 100644 +--- a/drivers/media/video/videobuf2-memops.c ++++ b/drivers/media/video/videobuf2-memops.c +@@ -52,7 +52,6 @@ struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma) + + vma_copy->vm_mm = NULL; + vma_copy->vm_next = NULL; +- vma_copy->vm_prev = NULL; + + return vma_copy; + } diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_work_handler.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_work_handler.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_work_handler.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.35_work_handler.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,148 @@ +--- + drivers/media/video/ivtv/ivtv-driver.c | 26 ++++++++++---------------- + drivers/media/video/ivtv/ivtv-driver.h | 8 ++++---- + drivers/media/video/ivtv/ivtv-irq.c | 15 ++++++++++++--- + drivers/media/video/ivtv/ivtv-irq.h | 2 +- + 4 files changed, 27 insertions(+), 24 deletions(-) + +--- linux.orig/drivers/media/video/ivtv/ivtv-driver.c ++++ linux/drivers/media/video/ivtv/ivtv-driver.c +@@ -706,8 +706,6 @@ done: + */ + static int __devinit ivtv_init_struct1(struct ivtv *itv) + { +- struct sched_param param = { .sched_priority = 99 }; +- + itv->base_addr = pci_resource_start(itv->pdev, 0); + itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ + itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ +@@ -719,17 +717,13 @@ static int __devinit ivtv_init_struct1(s + spin_lock_init(&itv->lock); + spin_lock_init(&itv->dma_reg_lock); + +- init_kthread_worker(&itv->irq_worker); +- itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker, +- itv->v4l2_dev.name); +- if (IS_ERR(itv->irq_worker_task)) { +- IVTV_ERR("Could not create ivtv task\n"); ++ itv->irq_work_queues = create_singlethread_workqueue(itv->v4l2_dev.name); ++ if (itv->irq_work_queues == NULL) { ++ IVTV_ERR("Could not create ivtv workqueue\n"); + return -1; + } +- /* must use the FIFO scheduler as it is realtime sensitive */ +- sched_setscheduler(itv->irq_worker_task, SCHED_FIFO, ¶m); + +- init_kthread_work(&itv->irq_work, ivtv_irq_work_handler); ++ INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler); + + /* start counting open_id at 1 */ + itv->open_id = 1; +@@ -1017,7 +1011,7 @@ static int __devinit ivtv_probe(struct p + /* PCI Device Setup */ + retval = ivtv_setup_pci(itv, pdev, pci_id); + if (retval == -EIO) +- goto free_worker; ++ goto free_workqueue; + if (retval == -ENXIO) + goto free_mem; + +@@ -1245,8 +1239,8 @@ free_mem: + release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); + if (itv->has_cx23415) + release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); +-free_worker: +- kthread_stop(itv->irq_worker_task); ++free_workqueue: ++ destroy_workqueue(itv->irq_work_queues); + err: + if (retval == 0) + retval = -ENODEV; +@@ -1385,9 +1379,9 @@ static void ivtv_remove(struct pci_dev * + ivtv_set_irq_mask(itv, 0xffffffff); + del_timer_sync(&itv->dma_timer); + +- /* Kill irq worker */ +- flush_kthread_worker(&itv->irq_worker); +- kthread_stop(itv->irq_worker_task); ++ /* Stop all Work Queues */ ++ flush_workqueue(itv->irq_work_queues); ++ destroy_workqueue(itv->irq_work_queues); + + ivtv_streams_cleanup(itv, 1); + ivtv_udma_free(itv); +--- linux.orig/drivers/media/video/ivtv/ivtv-driver.h ++++ linux/drivers/media/video/ivtv/ivtv-driver.h +@@ -51,7 +51,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -261,6 +261,7 @@ struct ivtv_mailbox_data { + #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ + #define IVTV_F_I_INITED 21 /* set after first open */ + #define IVTV_F_I_FAILED 22 /* set if first open failed */ ++#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */ + + /* Event notifications */ + #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ +@@ -666,9 +667,8 @@ struct ivtv { + /* Interrupts & DMA */ + u32 irqmask; /* active interrupts */ + u32 irq_rr_idx; /* round-robin stream index */ +- struct kthread_worker irq_worker; /* kthread worker for PIO/YUV/VBI actions */ +- struct task_struct *irq_worker_task; /* task for irq_worker */ +- struct kthread_work irq_work; /* kthread work entry */ ++ struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */ ++ struct work_struct irq_work_queue; /* work entry */ + spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ + int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */ + int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */ +--- linux.orig/drivers/media/video/ivtv/ivtv-irq.c ++++ linux/drivers/media/video/ivtv/ivtv-irq.c +@@ -71,10 +71,19 @@ static void ivtv_pio_work_handler(struct + write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); + } + +-void ivtv_irq_work_handler(struct kthread_work *work) ++void ivtv_irq_work_handler(struct work_struct *work) + { +- struct ivtv *itv = container_of(work, struct ivtv, irq_work); ++ struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue); + ++ DEFINE_WAIT(wait); ++ ++ if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) { ++ struct sched_param param = { .sched_priority = 99 }; ++ ++ /* This thread must use the FIFO scheduler as it ++ is realtime sensitive. */ ++ sched_setscheduler(current, SCHED_FIFO, ¶m); ++ } + if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) + ivtv_pio_work_handler(itv); + +@@ -1010,7 +1019,7 @@ irqreturn_t ivtv_irq_handler(int irq, vo + } + + if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { +- queue_kthread_work(&itv->irq_worker, &itv->irq_work); ++ queue_work(itv->irq_work_queues, &itv->irq_work_queue); + } + + spin_unlock(&itv->dma_reg_lock); +--- linux.orig/drivers/media/video/ivtv/ivtv-irq.h ++++ linux/drivers/media/video/ivtv/ivtv-irq.h +@@ -46,7 +46,7 @@ + + irqreturn_t ivtv_irq_handler(int irq, void *dev_id); + +-void ivtv_irq_work_handler(struct kthread_work *work); ++void ivtv_irq_work_handler(struct work_struct *work); + void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); + void ivtv_unfinished_dma(unsigned long arg); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_dvb_usb_input_getkeycode.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_dvb_usb_input_getkeycode.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_dvb_usb_input_getkeycode.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_dvb_usb_input_getkeycode.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,145 @@ +--- + drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 111 ++++++++++------------------- + 1 file changed, 42 insertions(+), 69 deletions(-) + +--- linux.orig/drivers/media/dvb/dvb-usb/dvb-usb-remote.c ++++ linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +@@ -8,71 +8,60 @@ + #include "dvb-usb-common.h" + #include + +-static unsigned int +-legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke, +- struct rc_map_table *keymap, +- unsigned int keymap_size) +-{ +- unsigned int index; +- unsigned int scancode; +- +- if (ke->flags & INPUT_KEYMAP_BY_INDEX) { +- index = ke->index; +- } else { +- if (input_scancode_to_scalar(ke, &scancode)) +- return keymap_size; +- +- /* See if we can match the raw key code. */ +- for (index = 0; index < keymap_size; index++) +- if (keymap[index].scancode == scancode) +- break; +- +- /* See if there is an unused hole in the map */ +- if (index >= keymap_size) { +- for (index = 0; index < keymap_size; index++) { +- if (keymap[index].keycode == KEY_RESERVED || +- keymap[index].keycode == KEY_UNKNOWN) { +- break; +- } +- } +- } +- } +- +- return index; +-} +- + static int legacy_dvb_usb_getkeycode(struct input_dev *dev, +- struct input_keymap_entry *ke) ++ unsigned int scancode, unsigned int *keycode) + { + struct dvb_usb_device *d = input_get_drvdata(dev); ++ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; +- unsigned int keymap_size = d->props.rc.legacy.rc_map_size; +- unsigned int index; ++ int i; + +- index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); +- if (index >= keymap_size) +- return -EINVAL; +- +- ke->keycode = keymap[index].keycode; +- if (ke->keycode == KEY_UNKNOWN) +- ke->keycode = KEY_RESERVED; +- ke->len = sizeof(keymap[index].scancode); +- memcpy(&ke->scancode, &keymap[index].scancode, ke->len); +- ke->index = index; ++ /* See if we can match the raw key code. */ ++ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) ++ if (keymap[i].scancode == scancode) { ++ *keycode = keymap[i].keycode; ++ return 0; ++ } + +- return 0; ++ /* ++ * If is there extra space, returns KEY_RESERVED, ++ * otherwise, input core won't let legacy_dvb_usb_setkeycode ++ * to work ++ */ ++ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) ++ if (keymap[i].keycode == KEY_RESERVED || ++ keymap[i].keycode == KEY_UNKNOWN) { ++ *keycode = KEY_RESERVED; ++ return 0; ++ } ++ ++ return -EINVAL; + } + + static int legacy_dvb_usb_setkeycode(struct input_dev *dev, +- const struct input_keymap_entry *ke, +- unsigned int *old_keycode) ++ unsigned int scancode, unsigned int keycode) + { + struct dvb_usb_device *d = input_get_drvdata(dev); ++ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; +- unsigned int keymap_size = d->props.rc.legacy.rc_map_size; +- unsigned int index; ++ int i; ++ ++ /* Search if it is replacing an existing keycode */ ++ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) ++ if (keymap[i].scancode == scancode) { ++ keymap[i].keycode = keycode; ++ return 0; ++ } ++ ++ /* Search if is there a clean entry. If so, use it */ ++ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) ++ if (keymap[i].keycode == KEY_RESERVED || ++ keymap[i].keycode == KEY_UNKNOWN) { ++ keymap[i].scancode = scancode; ++ keymap[i].keycode = keycode; ++ return 0; ++ } + +- index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); + /* + * FIXME: Currently, it is not possible to increase the size of + * scancode table. For it to happen, one possibility +@@ -80,24 +69,8 @@ static int legacy_dvb_usb_setkeycode(str + * copying data, appending the new key on it, and freeing + * the old one - or maybe just allocating some spare space + */ +- if (index >= keymap_size) +- return -EINVAL; + +- *old_keycode = keymap[index].keycode; +- keymap->keycode = ke->keycode; +- __set_bit(ke->keycode, dev->keybit); +- +- if (*old_keycode != KEY_RESERVED) { +- __clear_bit(*old_keycode, dev->keybit); +- for (index = 0; index < keymap_size; index++) { +- if (keymap[index].keycode == *old_keycode) { +- __set_bit(*old_keycode, dev->keybit); +- break; +- } +- } +- } +- +- return 0; ++ return -EINVAL; + } + + /* Remote-control poll function - called every dib->rc_query_interval ms to see diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_input_getkeycode.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_input_getkeycode.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_input_getkeycode.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_input_getkeycode.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,109 @@ +--- + drivers/media/rc/rc-main.c | 69 ++++++++++----------------------------------- + 1 file changed, 16 insertions(+), 53 deletions(-) + +--- linux.orig/drivers/media/rc/rc-main.c ++++ linux/drivers/media/rc/rc-main.c +@@ -318,37 +318,23 @@ static unsigned int ir_establish_scancod + * This routine is used to handle evdev EVIOCSKEY ioctl. + */ + static int ir_setkeycode(struct input_dev *idev, +- const struct input_keymap_entry *ke, +- unsigned int *old_keycode) ++ unsigned int scancode, unsigned int keycode) + { + struct rc_dev *rdev = input_get_drvdata(idev); + struct rc_map *rc_map = &rdev->rc_map; + unsigned int index; +- unsigned int scancode; + int retval = 0; + unsigned long flags; + + spin_lock_irqsave(&rc_map->lock, flags); + +- if (ke->flags & INPUT_KEYMAP_BY_INDEX) { +- index = ke->index; +- if (index >= rc_map->len) { +- retval = -EINVAL; +- goto out; +- } +- } else { +- retval = input_scancode_to_scalar(ke, &scancode); +- if (retval) +- goto out; +- +- index = ir_establish_scancode(rdev, rc_map, scancode, true); +- if (index >= rc_map->len) { +- retval = -ENOMEM; +- goto out; +- } ++ index = ir_establish_scancode(rdev, rc_map, scancode, true); ++ if (index >= rc_map->len) { ++ retval = -ENOMEM; ++ goto out; + } + +- *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode); ++ ir_update_mapping(rdev, rc_map, index, keycode); + + out: + spin_unlock_irqrestore(&rc_map->lock, flags); +@@ -436,48 +422,25 @@ static unsigned int ir_lookup_by_scancod + * This routine is used to handle evdev EVIOCGKEY ioctl. + */ + static int ir_getkeycode(struct input_dev *idev, +- struct input_keymap_entry *ke) ++ unsigned int scancode, unsigned int *keycode) + { + struct rc_dev *rdev = input_get_drvdata(idev); + struct rc_map *rc_map = &rdev->rc_map; +- struct rc_map_table *entry; + unsigned long flags; + unsigned int index; +- unsigned int scancode; + int retval; + + spin_lock_irqsave(&rc_map->lock, flags); + +- if (ke->flags & INPUT_KEYMAP_BY_INDEX) { +- index = ke->index; +- } else { +- retval = input_scancode_to_scalar(ke, &scancode); +- if (retval) +- goto out; +- +- index = ir_lookup_by_scancode(rc_map, scancode); +- } +- +- if (index < rc_map->len) { +- entry = &rc_map->scan[index]; +- +- ke->index = index; +- ke->keycode = entry->keycode; +- ke->len = sizeof(entry->scancode); +- memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode)); +- +- } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) { +- /* +- * We do not really know the valid range of scancodes +- * so let's respond with KEY_RESERVED to anything we +- * do not have mapping for [yet]. +- */ +- ke->index = index; +- ke->keycode = KEY_RESERVED; +- } else { +- retval = -EINVAL; +- goto out; +- } ++ index = ir_lookup_by_scancode(rc_map, scancode); ++ ++ if (index >= rc_map->len) { ++ *keycode = KEY_RESERVED; ++ retval = 0; ++ goto out; ++ } ++ ++ *keycode = rc_map->scan[index].keycode; + + retval = 0; + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_series 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.36_series 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3 @@ +v2.6.37_dont_use_alloc_ordered_workqueue.patch +v2.6.36_input_getkeycode.patch +v2.6.36_dvb_usb_input_getkeycode.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.37_dont_use_alloc_ordered_workqueue.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.37_dont_use_alloc_ordered_workqueue.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.37_dont_use_alloc_ordered_workqueue.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.37_dont_use_alloc_ordered_workqueue.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,94 @@ +--- + drivers/media/video/cx18/cx18-driver.c | 24 ++++++++++++++++++++++-- + drivers/media/video/cx18/cx18-driver.h | 3 +++ + drivers/media/video/cx18/cx18-streams.h | 3 ++- + 3 files changed, 27 insertions(+), 3 deletions(-) + +--- linux.orig/drivers/media/video/cx18/cx18-driver.c ++++ linux/drivers/media/video/cx18/cx18-driver.c +@@ -686,7 +686,7 @@ static int __devinit cx18_create_in_work + { + snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", + cx->v4l2_dev.name); +- cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0); ++ cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name); + if (cx->in_work_queue == NULL) { + CX18_ERR("Unable to create incoming mailbox handler thread\n"); + return -ENOMEM; +@@ -694,6 +694,18 @@ static int __devinit cx18_create_in_work + return 0; + } + ++static int __devinit cx18_create_out_workq(struct cx18 *cx) ++{ ++ snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out", ++ cx->v4l2_dev.name); ++ cx->out_work_queue = create_workqueue(cx->out_workq_name); ++ if (cx->out_work_queue == NULL) { ++ CX18_ERR("Unable to create outgoing mailbox handler threads\n"); ++ return -ENOMEM; ++ } ++ return 0; ++} ++ + static void __devinit cx18_init_in_work_orders(struct cx18 *cx) + { + int i; +@@ -720,10 +732,16 @@ static int __devinit cx18_init_struct1(s + mutex_init(&cx->epu2apu_mb_lock); + mutex_init(&cx->epu2cpu_mb_lock); + +- ret = cx18_create_in_workq(cx); ++ ret = cx18_create_out_workq(cx); + if (ret) + return ret; + ++ ret = cx18_create_in_workq(cx); ++ if (ret) { ++ destroy_workqueue(cx->out_work_queue); ++ return ret; ++ } ++ + cx18_init_in_work_orders(cx); + + /* start counting open_id at 1 */ +@@ -1117,6 +1135,7 @@ free_mem: + release_mem_region(cx->base_addr, CX18_MEM_SIZE); + free_workqueues: + destroy_workqueue(cx->in_work_queue); ++ destroy_workqueue(cx->out_work_queue); + err: + if (retval == 0) + retval = -ENODEV; +@@ -1268,6 +1287,7 @@ static void cx18_remove(struct pci_dev * + cx18_halt_firmware(cx); + + destroy_workqueue(cx->in_work_queue); ++ destroy_workqueue(cx->out_work_queue); + + cx18_streams_cleanup(cx, 1); + +--- linux.orig/drivers/media/video/cx18/cx18-driver.h ++++ linux/drivers/media/video/cx18/cx18-driver.h +@@ -628,6 +628,9 @@ struct cx18 { + struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; + char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ + ++ struct workqueue_struct *out_work_queue; ++ char out_workq_name[12]; /* "cx18-NN-out" */ ++ + /* i2c */ + struct i2c_adapter i2c_adap[2]; + struct i2c_algo_bit_data i2c_algo[2]; +--- linux.orig/drivers/media/video/cx18/cx18-streams.h ++++ linux/drivers/media/video/cx18/cx18-streams.h +@@ -42,7 +42,8 @@ static inline bool cx18_stream_enabled(s + /* Related to submission of mdls to firmware */ + static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) + { +- schedule_work(&s->out_work_order); ++ struct cx18 *cx = s->cx; ++ queue_work(cx->out_work_queue, &s->out_work_order); + } + + static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s, diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.37_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.37_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.37_series 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.37_series 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3 @@ +v2.6.38_use_getkeycode_new_setkeycode_new.patch +v2.6.37_dont_use_alloc_ordered_workqueue.patch + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.38_series v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.38_series --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.38_series 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.38_series 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1 @@ +v2.6.38_use_getkeycode_new_setkeycode_new.patch diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.38_use_getkeycode_new_setkeycode_new.patch v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.38_use_getkeycode_new_setkeycode_new.patch --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.38_use_getkeycode_new_setkeycode_new.patch 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/backports/v2.6.38_use_getkeycode_new_setkeycode_new.patch 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,34 @@ + drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 4 ++-- + drivers/media/rc/rc-main.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +index 41bacff..a031975 100644 +--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c ++++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +@@ -198,8 +198,8 @@ static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) + d->input_dev = input_dev; + d->rc_dev = NULL; + +- input_dev->getkeycode = legacy_dvb_usb_getkeycode; +- input_dev->setkeycode = legacy_dvb_usb_setkeycode; ++ input_dev->getkeycode_new = legacy_dvb_usb_getkeycode; ++ input_dev->setkeycode_new = legacy_dvb_usb_setkeycode; + + /* set the bits for the keys */ + deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size); +diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c +index 0497e06..1202f0d 100644 +--- a/drivers/media/rc/rc-main.c ++++ b/drivers/media/rc/rc-main.c +@@ -989,8 +989,8 @@ struct rc_dev *rc_allocate_device(void) + return NULL; + } + +- dev->input_dev->getkeycode = ir_getkeycode; +- dev->input_dev->setkeycode = ir_setkeycode; ++ dev->input_dev->getkeycode_new = ir_getkeycode; ++ dev->input_dev->setkeycode_new = ir_setkeycode; + input_set_drvdata(dev->input_dev, dev); + + spin_lock_init(&dev->rc_map.lock); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/build.sh v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/build.sh --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/build.sh 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/build.sh 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,33 @@ +run () +{ + echo $@ + $@ + if [ "$?" != "0" ]; then + echo "*** ERROR. Aborting ***" + exit -1 + fi +} + +echo "Checking if the needed tools are present" +run ./check_needs.pl +echo +echo "************************************************************" +echo "* This script will download the latest tarball and build it*" +echo "* Assuming that your kernel is compatible with the latest *" +echo "* drivers. If not, you'll need to add some extra backports,*" +echo "* ./backports/ directory. *" +echo "* It will also update this tree to be sure that all compat *" +echo "* bits are there, to avoid compilation failures *" +echo "************************************************************" +echo +sleep 5 +run git pull git://linuxtv.org/media_build.git master + +run make -C linux/ download +run make -C linux/ untar +run make + +echo "**********************************************************" +echo "* Compilation finished. Use "make install" to install them" +echo "**********************************************************" + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/check_needs.pl v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/check_needs.pl --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/check_needs.pl 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/check_needs.pl 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,99 @@ +#!/usr/bin/perl + +my @missing; + +my $system_release = qx(cat /etc/system-release); +$system_release = qx(cat /etc/redhat-release) if !$system_release; + +sub give_redhat_hints +{ + my $install; + + my %map = ( + "lsdiff" => "patchutils", + "Digest::SHA1" => "perl-Digest-SHA1", + "Proc::ProcessTable" => "perl-Proc-ProcessTable", + ); + + foreach my $prog (@missing) { + print "ERROR: please install \"$prog\", otherwise, build won't work.\n"; + if (defined($map{$prog})) { + $install .= " " . $map{$prog}; + } else { + $install .= " " . $prog; + } + } + + printf("You should run:\n\tyum install -y $install\n"); +} + +sub give_hints +{ + + # Distro-specific hints + if ($system_release =~ /Red Hat Enterprise Linux Workstation/) { + give_redhat_hints; + return; + } + if ($system_release =~ /Fedora/) { + give_redhat_hints; + return; + } + + # Fall-back to generic hint code + foreach my $prog (@missing) { + print "ERROR: please install \"$prog\", otherwise, build won't work.\n"; + } + print "I don't know distro $system_release. So, I can't provide you a hint with the package names.\n"; + print "Be welcome to contribute with a patch for media-build, by submitting a distro-specific hint\n"; + print "to linux-media\@vger.kernel.org\n"; +} + +my $need = 0; +sub findprog($) +{ + foreach(split(/:/, $ENV{PATH})) { + return "$_/$_[0]" if(-x "$_/$_[0]"); + } +} + +sub need_program +{ + my $prog = shift; + my $pkgname = shift; + + return if findprog($prog); + + push @missing, $prog; + + $need++; +} + +sub need_perl_module +{ + my $prog = shift; + my $pkgname = shift; + + my $err = system("perl -M$prog -e 1 2>/dev/null /dev/null"); + return if ($err == 0); + + push @missing, $prog; + + $need++; +} + +# Check for needed programs/tools +need_program "git"; +need_program "make"; +need_program "gcc"; +need_program "patch"; +need_program "lsdiff"; + +# Check for needed perl modules +need_perl_module "Digest::SHA1"; +need_perl_module "Proc::ProcessTable"; + +give_hints if ($need); + +die "Build can't procceed as $need dependency is missing" if ($need == 1); +die "Build can't procceed as $need dependencies are missing" if ($need); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/dkms.conf v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/dkms.conf --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/dkms.conf 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/dkms.conf 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,1344 @@ +PACKAGE_NAME=v4l-dvb +PACKAGE_VERSION=0~20110625.git255868.188~lucid +AUTOINSTALL=y +MAKE[0]="make -j5 VER=$kernelver" +PATCH[0]=v2.6.37_dont_use_alloc_ordered_workqueue.patch +PATCH_MATCH[0]="^2\.6\.([0-9]|[1-2][0-9]|3[2-6])[^0-9]" +PATCH[1]=v2.6.36_input_getkeycode.patch +PATCH_MATCH[1]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[2]=v2.6.36_dvb_usb_input_getkeycode.patch +PATCH_MATCH[2]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[3]=v2.6.35_work_handler.patch +PATCH_MATCH[3]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[4]=v2.6.35_vm_prev.patch +PATCH_MATCH[4]="^2\.6\.([0-9]|[1-2][0-9]|3[3-6])[^0-9]" +PATCH[5]=v2.6.35_i2c_new_probed_device.patch +PATCH_MATCH[5]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[6]=v2.6.35_firedtv_handle_fcp.patch +PATCH_MATCH[6]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[7]=v2.6.34_fix_define_warnings.patch +PATCH_MATCH[7]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[8]=v2.6.34_dvb_net.patch +PATCH_MATCH[8]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[9]=v2.6.33_pvrusb2_sysfs.patch +PATCH_MATCH[9]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[10]=v2.6.33_input_handlers_are_int.patch +PATCH_MATCH[10]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[11]=v2.6.32_kfifo.patch +PATCH_MATCH[11]="^2\.6\.([0-9]|[1-2][0-9]|3[0-6])[^0-9]" +PATCH[12]=v2.6.31_nodename.patch +PATCH_MATCH[12]="^2\.6\.([0-9]|[1-2][0-9]|3[0-1])[^0-9]" +PATCH[13]=v2.6.31_device_type.patch +PATCH_MATCH[13]="^2\.6\.([0-9]|[1-2][0-9]|3[0-1])[^0-9]" +PATCH[14]=v2-V4L-DVB-faster-DVB-S-lock-for-mantis-cards-using-stb0899-demod.patch +PATCH[15]=tt-s2-double-fix.patch +PATCH[16]=fixes_stb0899_not_locking.patch +PATCH[17]=fec34-fix.patch +PATCH[18]=anysee-keymap.patch +PATCH[19]=Refactor-Mantis-DMA-transfer-to-deliver-16Kb-TS-data-per-interrupt.patch +PATCH[20]=1090-add-driver-saa716x.patch +PATCH[21]=1010-saa716x_keymap.patch +PATCH[22]=0001-Add-remote-control-support-for-mantis.patch +PATCH[23]=0000-stv090x-ber-counter-scaled.patch +BUILT_MODULE_NAME[0]=ir-jvc-decoder +BUILT_MODULE_LOCATION[0]=./v4l +DEST_MODULE_LOCATION[0]=/updates/dkms +BUILT_MODULE_NAME[1]=rc-proteus-2309 +BUILT_MODULE_LOCATION[1]=./v4l +DEST_MODULE_LOCATION[1]=/updates/dkms +BUILT_MODULE_NAME[2]=bt866 +BUILT_MODULE_LOCATION[2]=./v4l +DEST_MODULE_LOCATION[2]=/updates/dkms +BUILT_MODULE_NAME[3]=cx22700 +BUILT_MODULE_LOCATION[3]=./v4l +DEST_MODULE_LOCATION[3]=/updates/dkms +BUILT_MODULE_NAME[4]=dvb-usb-opera +BUILT_MODULE_LOCATION[4]=./v4l +DEST_MODULE_LOCATION[4]=/updates/dkms +BUILT_MODULE_NAME[5]=cx231xx +BUILT_MODULE_LOCATION[5]=./v4l +DEST_MODULE_LOCATION[5]=/updates/dkms +BUILT_MODULE_NAME[6]=b2c2-flexcop-pci +BUILT_MODULE_LOCATION[6]=./v4l +DEST_MODULE_LOCATION[6]=/updates/dkms +BUILT_MODULE_NAME[7]=saa7164 +BUILT_MODULE_LOCATION[7]=./v4l +DEST_MODULE_LOCATION[7]=/updates/dkms +BUILT_MODULE_NAME[8]=dvb-usb-az6027 +BUILT_MODULE_LOCATION[8]=./v4l +DEST_MODULE_LOCATION[8]=/updates/dkms +BUILT_MODULE_NAME[9]=stv0297 +BUILT_MODULE_LOCATION[9]=./v4l +DEST_MODULE_LOCATION[9]=/updates/dkms +BUILT_MODULE_NAME[10]=rc-genius-tvgo-a11mce +BUILT_MODULE_LOCATION[10]=./v4l +DEST_MODULE_LOCATION[10]=/updates/dkms +BUILT_MODULE_NAME[11]=gspca_sunplus +BUILT_MODULE_LOCATION[11]=./v4l +DEST_MODULE_LOCATION[11]=/updates/dkms +BUILT_MODULE_NAME[12]=rc-apac-viewcomp +BUILT_MODULE_LOCATION[12]=./v4l +DEST_MODULE_LOCATION[12]=/updates/dkms +BUILT_MODULE_NAME[13]=zl10039 +BUILT_MODULE_LOCATION[13]=./v4l +DEST_MODULE_LOCATION[13]=/updates/dkms +BUILT_MODULE_NAME[14]=rc-dntv-live-dvbt-pro +BUILT_MODULE_LOCATION[14]=./v4l +DEST_MODULE_LOCATION[14]=/updates/dkms +BUILT_MODULE_NAME[15]=rc-cinergy-1400 +BUILT_MODULE_LOCATION[15]=./v4l +DEST_MODULE_LOCATION[15]=/updates/dkms +BUILT_MODULE_NAME[16]=cx24110 +BUILT_MODULE_LOCATION[16]=./v4l +DEST_MODULE_LOCATION[16]=/updates/dkms +BUILT_MODULE_NAME[17]=rc-pinnacle-pctv-hd +BUILT_MODULE_LOCATION[17]=./v4l +DEST_MODULE_LOCATION[17]=/updates/dkms +BUILT_MODULE_NAME[18]=videobuf-vmalloc +BUILT_MODULE_LOCATION[18]=./v4l +DEST_MODULE_LOCATION[18]=/updates/dkms +BUILT_MODULE_NAME[19]=rc-winfast-usbii-deluxe +BUILT_MODULE_LOCATION[19]=./v4l +DEST_MODULE_LOCATION[19]=/updates/dkms +BUILT_MODULE_NAME[20]=rc-core +BUILT_MODULE_LOCATION[20]=./v4l +DEST_MODULE_LOCATION[20]=/updates/dkms +BUILT_MODULE_NAME[21]=dvb-usb-dw2102 +BUILT_MODULE_LOCATION[21]=./v4l +DEST_MODULE_LOCATION[21]=/updates/dkms +BUILT_MODULE_NAME[22]=wm8775 +BUILT_MODULE_LOCATION[22]=./v4l +DEST_MODULE_LOCATION[22]=/updates/dkms +BUILT_MODULE_NAME[23]=gspca_nw80x +BUILT_MODULE_LOCATION[23]=./v4l +DEST_MODULE_LOCATION[23]=/updates/dkms +BUILT_MODULE_NAME[24]=ir-rc5-decoder +BUILT_MODULE_LOCATION[24]=./v4l +DEST_MODULE_LOCATION[24]=/updates/dkms +BUILT_MODULE_NAME[25]=s5h1420 +BUILT_MODULE_LOCATION[25]=./v4l +DEST_MODULE_LOCATION[25]=/updates/dkms +BUILT_MODULE_NAME[26]=rc-avermedia-m733a-rm-k6 +BUILT_MODULE_LOCATION[26]=./v4l +DEST_MODULE_LOCATION[26]=/updates/dkms +BUILT_MODULE_NAME[27]=tda18271 +BUILT_MODULE_LOCATION[27]=./v4l +DEST_MODULE_LOCATION[27]=/updates/dkms +BUILT_MODULE_NAME[28]=rc-avermedia-m135a +BUILT_MODULE_LOCATION[28]=./v4l +DEST_MODULE_LOCATION[28]=/updates/dkms +BUILT_MODULE_NAME[29]=rc-gotview7135 +BUILT_MODULE_LOCATION[29]=./v4l +DEST_MODULE_LOCATION[29]=/updates/dkms +BUILT_MODULE_NAME[30]=vivi +BUILT_MODULE_LOCATION[30]=./v4l +DEST_MODULE_LOCATION[30]=/updates/dkms +BUILT_MODULE_NAME[31]=ngene +BUILT_MODULE_LOCATION[31]=./v4l +DEST_MODULE_LOCATION[31]=/updates/dkms +BUILT_MODULE_NAME[32]=smssdio +BUILT_MODULE_LOCATION[32]=./v4l +DEST_MODULE_LOCATION[32]=/updates/dkms +BUILT_MODULE_NAME[33]=dvb-usb-m920x +BUILT_MODULE_LOCATION[33]=./v4l +DEST_MODULE_LOCATION[33]=/updates/dkms +BUILT_MODULE_NAME[34]=rc-behold-columbus +BUILT_MODULE_LOCATION[34]=./v4l +DEST_MODULE_LOCATION[34]=/updates/dkms +BUILT_MODULE_NAME[35]=em28xx-alsa +BUILT_MODULE_LOCATION[35]=./v4l +DEST_MODULE_LOCATION[35]=/updates/dkms +BUILT_MODULE_NAME[36]=c-qcam +BUILT_MODULE_LOCATION[36]=./v4l +DEST_MODULE_LOCATION[36]=/updates/dkms +BUILT_MODULE_NAME[37]=saa6588 +BUILT_MODULE_LOCATION[37]=./v4l +DEST_MODULE_LOCATION[37]=/updates/dkms +BUILT_MODULE_NAME[38]=isl6423 +BUILT_MODULE_LOCATION[38]=./v4l +DEST_MODULE_LOCATION[38]=/updates/dkms +BUILT_MODULE_NAME[39]=ttusb_dec +BUILT_MODULE_LOCATION[39]=./v4l +DEST_MODULE_LOCATION[39]=/updates/dkms +BUILT_MODULE_NAME[40]=adv7180 +BUILT_MODULE_LOCATION[40]=./v4l +DEST_MODULE_LOCATION[40]=/updates/dkms +BUILT_MODULE_NAME[41]=tea5767 +BUILT_MODULE_LOCATION[41]=./v4l +DEST_MODULE_LOCATION[41]=/updates/dkms +BUILT_MODULE_NAME[42]=rc-real-audio-220-32-keys +BUILT_MODULE_LOCATION[42]=./v4l +DEST_MODULE_LOCATION[42]=/updates/dkms +BUILT_MODULE_NAME[43]=noon010pc30 +BUILT_MODULE_LOCATION[43]=./v4l +DEST_MODULE_LOCATION[43]=/updates/dkms +BUILT_MODULE_NAME[44]=rc-msi-digivox-iii +BUILT_MODULE_LOCATION[44]=./v4l +DEST_MODULE_LOCATION[44]=/updates/dkms +BUILT_MODULE_NAME[45]=rc-tbs-nec +BUILT_MODULE_LOCATION[45]=./v4l +DEST_MODULE_LOCATION[45]=/updates/dkms +BUILT_MODULE_NAME[46]=bttv +BUILT_MODULE_LOCATION[46]=./v4l +DEST_MODULE_LOCATION[46]=/updates/dkms +BUILT_MODULE_NAME[47]=lirc_dev +BUILT_MODULE_LOCATION[47]=./v4l +DEST_MODULE_LOCATION[47]=/updates/dkms +BUILT_MODULE_NAME[48]=rc-pixelview-002t +BUILT_MODULE_LOCATION[48]=./v4l +DEST_MODULE_LOCATION[48]=/updates/dkms +BUILT_MODULE_NAME[49]=videobuf-core +BUILT_MODULE_LOCATION[49]=./v4l +DEST_MODULE_LOCATION[49]=/updates/dkms +BUILT_MODULE_NAME[50]=rc-avermedia-rm-ks +BUILT_MODULE_LOCATION[50]=./v4l +DEST_MODULE_LOCATION[50]=/updates/dkms +BUILT_MODULE_NAME[51]=rc-behold +BUILT_MODULE_LOCATION[51]=./v4l +DEST_MODULE_LOCATION[51]=/updates/dkms +BUILT_MODULE_NAME[52]=gspca_spca1528 +BUILT_MODULE_LOCATION[52]=./v4l +DEST_MODULE_LOCATION[52]=/updates/dkms +BUILT_MODULE_NAME[53]=rc-loopback +BUILT_MODULE_LOCATION[53]=./v4l +DEST_MODULE_LOCATION[53]=/updates/dkms +BUILT_MODULE_NAME[54]=rc-tt-1500 +BUILT_MODULE_LOCATION[54]=./v4l +DEST_MODULE_LOCATION[54]=/updates/dkms +BUILT_MODULE_NAME[55]=wm8739 +BUILT_MODULE_LOCATION[55]=./v4l +DEST_MODULE_LOCATION[55]=/updates/dkms +BUILT_MODULE_NAME[56]=mantis_core +BUILT_MODULE_LOCATION[56]=./v4l +DEST_MODULE_LOCATION[56]=/updates/dkms +BUILT_MODULE_NAME[57]=stv0288 +BUILT_MODULE_LOCATION[57]=./v4l +DEST_MODULE_LOCATION[57]=/updates/dkms +BUILT_MODULE_NAME[58]=ir-rc6-decoder +BUILT_MODULE_LOCATION[58]=./v4l +DEST_MODULE_LOCATION[58]=/updates/dkms +BUILT_MODULE_NAME[59]=mt20xx +BUILT_MODULE_LOCATION[59]=./v4l +DEST_MODULE_LOCATION[59]=/updates/dkms +BUILT_MODULE_NAME[60]=rc-asus-pc39 +BUILT_MODULE_LOCATION[60]=./v4l +DEST_MODULE_LOCATION[60]=/updates/dkms +BUILT_MODULE_NAME[61]=hdpvr +BUILT_MODULE_LOCATION[61]=./v4l +DEST_MODULE_LOCATION[61]=/updates/dkms +BUILT_MODULE_NAME[62]=dvb_dummy_fe +BUILT_MODULE_LOCATION[62]=./v4l +DEST_MODULE_LOCATION[62]=/updates/dkms +BUILT_MODULE_NAME[63]=mantis +BUILT_MODULE_LOCATION[63]=./v4l +DEST_MODULE_LOCATION[63]=/updates/dkms +BUILT_MODULE_NAME[64]=bcm3510 +BUILT_MODULE_LOCATION[64]=./v4l +DEST_MODULE_LOCATION[64]=/updates/dkms +BUILT_MODULE_NAME[65]=gspca_spca561 +BUILT_MODULE_LOCATION[65]=./v4l +DEST_MODULE_LOCATION[65]=/updates/dkms +BUILT_MODULE_NAME[66]=rc-kworld-plus-tv-analog +BUILT_MODULE_LOCATION[66]=./v4l +DEST_MODULE_LOCATION[66]=/updates/dkms +BUILT_MODULE_NAME[67]=tda827x +BUILT_MODULE_LOCATION[67]=./v4l +DEST_MODULE_LOCATION[67]=/updates/dkms +BUILT_MODULE_NAME[68]=videobuf-dvb +BUILT_MODULE_LOCATION[68]=./v4l +DEST_MODULE_LOCATION[68]=/updates/dkms +BUILT_MODULE_NAME[69]=stv6110x +BUILT_MODULE_LOCATION[69]=./v4l +DEST_MODULE_LOCATION[69]=/updates/dkms +BUILT_MODULE_NAME[70]=dvb-usb-umt-010 +BUILT_MODULE_LOCATION[70]=./v4l +DEST_MODULE_LOCATION[70]=/updates/dkms +BUILT_MODULE_NAME[71]=w9966 +BUILT_MODULE_LOCATION[71]=./v4l +DEST_MODULE_LOCATION[71]=/updates/dkms +BUILT_MODULE_NAME[72]=stv0367 +BUILT_MODULE_LOCATION[72]=./v4l +DEST_MODULE_LOCATION[72]=/updates/dkms +BUILT_MODULE_NAME[73]=saa717x +BUILT_MODULE_LOCATION[73]=./v4l +DEST_MODULE_LOCATION[73]=/updates/dkms +BUILT_MODULE_NAME[74]=saa7146_vv +BUILT_MODULE_LOCATION[74]=./v4l +DEST_MODULE_LOCATION[74]=/updates/dkms +BUILT_MODULE_NAME[75]=xc5000 +BUILT_MODULE_LOCATION[75]=./v4l +DEST_MODULE_LOCATION[75]=/updates/dkms +BUILT_MODULE_NAME[76]=tea5761 +BUILT_MODULE_LOCATION[76]=./v4l +DEST_MODULE_LOCATION[76]=/updates/dkms +BUILT_MODULE_NAME[77]=rc-videomate-tv-pvr +BUILT_MODULE_LOCATION[77]=./v4l +DEST_MODULE_LOCATION[77]=/updates/dkms +BUILT_MODULE_NAME[78]=ds3000 +BUILT_MODULE_LOCATION[78]=./v4l +DEST_MODULE_LOCATION[78]=/updates/dkms +BUILT_MODULE_NAME[79]=rc-flyvideo +BUILT_MODULE_LOCATION[79]=./v4l +DEST_MODULE_LOCATION[79]=/updates/dkms +BUILT_MODULE_NAME[80]=zl10353 +BUILT_MODULE_LOCATION[80]=./v4l +DEST_MODULE_LOCATION[80]=/updates/dkms +BUILT_MODULE_NAME[81]=adv7170 +BUILT_MODULE_LOCATION[81]=./v4l +DEST_MODULE_LOCATION[81]=/updates/dkms +BUILT_MODULE_NAME[82]=uvcvideo +BUILT_MODULE_LOCATION[82]=./v4l +DEST_MODULE_LOCATION[82]=/updates/dkms +BUILT_MODULE_NAME[83]=meye +BUILT_MODULE_LOCATION[83]=./v4l +DEST_MODULE_LOCATION[83]=/updates/dkms +BUILT_MODULE_NAME[84]=adv7343 +BUILT_MODULE_LOCATION[84]=./v4l +DEST_MODULE_LOCATION[84]=/updates/dkms +BUILT_MODULE_NAME[85]=tcm825x +BUILT_MODULE_LOCATION[85]=./v4l +DEST_MODULE_LOCATION[85]=/updates/dkms +BUILT_MODULE_NAME[86]=stb6100 +BUILT_MODULE_LOCATION[86]=./v4l +DEST_MODULE_LOCATION[86]=/updates/dkms +BUILT_MODULE_NAME[87]=mxb +BUILT_MODULE_LOCATION[87]=./v4l +DEST_MODULE_LOCATION[87]=/updates/dkms +BUILT_MODULE_NAME[88]=rc-winfast +BUILT_MODULE_LOCATION[88]=./v4l +DEST_MODULE_LOCATION[88]=/updates/dkms +BUILT_MODULE_NAME[89]=gspca_vc032x +BUILT_MODULE_LOCATION[89]=./v4l +DEST_MODULE_LOCATION[89]=/updates/dkms +BUILT_MODULE_NAME[90]=cx88-dvb +BUILT_MODULE_LOCATION[90]=./v4l +DEST_MODULE_LOCATION[90]=/updates/dkms +BUILT_MODULE_NAME[91]=gspca_sq930x +BUILT_MODULE_LOCATION[91]=./v4l +DEST_MODULE_LOCATION[91]=/updates/dkms +BUILT_MODULE_NAME[92]=rc-imon-pad +BUILT_MODULE_LOCATION[92]=./v4l +DEST_MODULE_LOCATION[92]=/updates/dkms +BUILT_MODULE_NAME[93]=rc-pv951 +BUILT_MODULE_LOCATION[93]=./v4l +DEST_MODULE_LOCATION[93]=/updates/dkms +BUILT_MODULE_NAME[94]=em28xx +BUILT_MODULE_LOCATION[94]=./v4l +DEST_MODULE_LOCATION[94]=/updates/dkms +BUILT_MODULE_NAME[95]=gspca_benq +BUILT_MODULE_LOCATION[95]=./v4l +DEST_MODULE_LOCATION[95]=/updates/dkms +BUILT_MODULE_NAME[96]=gspca_spca505 +BUILT_MODULE_LOCATION[96]=./v4l +DEST_MODULE_LOCATION[96]=/updates/dkms +BUILT_MODULE_NAME[97]=rc-evga-indtube +BUILT_MODULE_LOCATION[97]=./v4l +DEST_MODULE_LOCATION[97]=/updates/dkms +BUILT_MODULE_NAME[98]=tda18218 +BUILT_MODULE_LOCATION[98]=./v4l +DEST_MODULE_LOCATION[98]=/updates/dkms +BUILT_MODULE_NAME[99]=dvb-usb-ce6230 +BUILT_MODULE_LOCATION[99]=./v4l +DEST_MODULE_LOCATION[99]=/updates/dkms +BUILT_MODULE_NAME[100]=tveeprom +BUILT_MODULE_LOCATION[100]=./v4l +DEST_MODULE_LOCATION[100]=/updates/dkms +BUILT_MODULE_NAME[101]=cpia2 +BUILT_MODULE_LOCATION[101]=./v4l +DEST_MODULE_LOCATION[101]=/updates/dkms +BUILT_MODULE_NAME[102]=radio-usb-si470x +BUILT_MODULE_LOCATION[102]=./v4l +DEST_MODULE_LOCATION[102]=/updates/dkms +BUILT_MODULE_NAME[103]=rc-tivo +BUILT_MODULE_LOCATION[103]=./v4l +DEST_MODULE_LOCATION[103]=/updates/dkms +BUILT_MODULE_NAME[104]=gspca_stv06xx +BUILT_MODULE_LOCATION[104]=./v4l +DEST_MODULE_LOCATION[104]=/updates/dkms +BUILT_MODULE_NAME[105]=cx24113 +BUILT_MODULE_LOCATION[105]=./v4l +DEST_MODULE_LOCATION[105]=/updates/dkms +BUILT_MODULE_NAME[106]=dsbr100 +BUILT_MODULE_LOCATION[106]=./v4l +DEST_MODULE_LOCATION[106]=/updates/dkms +BUILT_MODULE_NAME[107]=gspca_stk014 +BUILT_MODULE_LOCATION[107]=./v4l +DEST_MODULE_LOCATION[107]=/updates/dkms +BUILT_MODULE_NAME[108]=pvrusb2 +BUILT_MODULE_LOCATION[108]=./v4l +DEST_MODULE_LOCATION[108]=/updates/dkms +BUILT_MODULE_NAME[109]=poseidon +BUILT_MODULE_LOCATION[109]=./v4l +DEST_MODULE_LOCATION[109]=/updates/dkms +BUILT_MODULE_NAME[110]=dvb-usb-dibusb-mb +BUILT_MODULE_LOCATION[110]=./v4l +DEST_MODULE_LOCATION[110]=/updates/dkms +BUILT_MODULE_NAME[111]=saa7127 +BUILT_MODULE_LOCATION[111]=./v4l +DEST_MODULE_LOCATION[111]=/updates/dkms +BUILT_MODULE_NAME[112]=cx231xx-alsa +BUILT_MODULE_LOCATION[112]=./v4l +DEST_MODULE_LOCATION[112]=/updates/dkms +BUILT_MODULE_NAME[113]=b2c2-flexcop +BUILT_MODULE_LOCATION[113]=./v4l +DEST_MODULE_LOCATION[113]=/updates/dkms +BUILT_MODULE_NAME[114]=gspca_sn9c20x +BUILT_MODULE_LOCATION[114]=./v4l +DEST_MODULE_LOCATION[114]=/updates/dkms +BUILT_MODULE_NAME[115]=tda7432 +BUILT_MODULE_LOCATION[115]=./v4l +DEST_MODULE_LOCATION[115]=/updates/dkms +BUILT_MODULE_NAME[116]=cxd2820r +BUILT_MODULE_LOCATION[116]=./v4l +DEST_MODULE_LOCATION[116]=/updates/dkms +BUILT_MODULE_NAME[117]=rc-digitalnow-tinytwin +BUILT_MODULE_LOCATION[117]=./v4l +DEST_MODULE_LOCATION[117]=/updates/dkms +BUILT_MODULE_NAME[118]=tda8261 +BUILT_MODULE_LOCATION[118]=./v4l +DEST_MODULE_LOCATION[118]=/updates/dkms +BUILT_MODULE_NAME[119]=rc-avermedia-a16d +BUILT_MODULE_LOCATION[119]=./v4l +DEST_MODULE_LOCATION[119]=/updates/dkms +BUILT_MODULE_NAME[120]=gspca_ov534_9 +BUILT_MODULE_LOCATION[120]=./v4l +DEST_MODULE_LOCATION[120]=/updates/dkms +BUILT_MODULE_NAME[121]=rc-manli +BUILT_MODULE_LOCATION[121]=./v4l +DEST_MODULE_LOCATION[121]=/updates/dkms +BUILT_MODULE_NAME[122]=sp8870 +BUILT_MODULE_LOCATION[122]=./v4l +DEST_MODULE_LOCATION[122]=/updates/dkms +BUILT_MODULE_NAME[123]=rc-pixelview-new +BUILT_MODULE_LOCATION[123]=./v4l +DEST_MODULE_LOCATION[123]=/updates/dkms +BUILT_MODULE_NAME[124]=videocodec +BUILT_MODULE_LOCATION[124]=./v4l +DEST_MODULE_LOCATION[124]=/updates/dkms +BUILT_MODULE_NAME[125]=rc-digittrade +BUILT_MODULE_LOCATION[125]=./v4l +DEST_MODULE_LOCATION[125]=/updates/dkms +BUILT_MODULE_NAME[126]=gspca_gl860 +BUILT_MODULE_LOCATION[126]=./v4l +DEST_MODULE_LOCATION[126]=/updates/dkms +BUILT_MODULE_NAME[127]=dvb-usb-technisat-usb2 +BUILT_MODULE_LOCATION[127]=./v4l +DEST_MODULE_LOCATION[127]=/updates/dkms +BUILT_MODULE_NAME[128]=winbond-cir +BUILT_MODULE_LOCATION[128]=./v4l +DEST_MODULE_LOCATION[128]=/updates/dkms +BUILT_MODULE_NAME[129]=rc-encore-enltv +BUILT_MODULE_LOCATION[129]=./v4l +DEST_MODULE_LOCATION[129]=/updates/dkms +BUILT_MODULE_NAME[130]=gspca_main +BUILT_MODULE_LOCATION[130]=./v4l +DEST_MODULE_LOCATION[130]=/updates/dkms +BUILT_MODULE_NAME[131]=rc-adstech-dvb-t-pci +BUILT_MODULE_LOCATION[131]=./v4l +DEST_MODULE_LOCATION[131]=/updates/dkms +BUILT_MODULE_NAME[132]=stb6000 +BUILT_MODULE_LOCATION[132]=./v4l +DEST_MODULE_LOCATION[132]=/updates/dkms +BUILT_MODULE_NAME[133]=rc-pinnacle-color +BUILT_MODULE_LOCATION[133]=./v4l +DEST_MODULE_LOCATION[133]=/updates/dkms +BUILT_MODULE_NAME[134]=gspca_sonixj +BUILT_MODULE_LOCATION[134]=./v4l +DEST_MODULE_LOCATION[134]=/updates/dkms +BUILT_MODULE_NAME[135]=radio-mr800 +BUILT_MODULE_LOCATION[135]=./v4l +DEST_MODULE_LOCATION[135]=/updates/dkms +BUILT_MODULE_NAME[136]=dvb-usb-vp702x +BUILT_MODULE_LOCATION[136]=./v4l +DEST_MODULE_LOCATION[136]=/updates/dkms +BUILT_MODULE_NAME[137]=zr36016 +BUILT_MODULE_LOCATION[137]=./v4l +DEST_MODULE_LOCATION[137]=/updates/dkms +BUILT_MODULE_NAME[138]=rc-rc6-mce +BUILT_MODULE_LOCATION[138]=./v4l +DEST_MODULE_LOCATION[138]=/updates/dkms +BUILT_MODULE_NAME[139]=rc-npgtech +BUILT_MODULE_LOCATION[139]=./v4l +DEST_MODULE_LOCATION[139]=/updates/dkms +BUILT_MODULE_NAME[140]=cs53l32a +BUILT_MODULE_LOCATION[140]=./v4l +DEST_MODULE_LOCATION[140]=/updates/dkms +BUILT_MODULE_NAME[141]=dvb-usb-af9015 +BUILT_MODULE_LOCATION[141]=./v4l +DEST_MODULE_LOCATION[141]=/updates/dkms +BUILT_MODULE_NAME[142]=s921 +BUILT_MODULE_LOCATION[142]=./v4l +DEST_MODULE_LOCATION[142]=/updates/dkms +BUILT_MODULE_NAME[143]=mt2131 +BUILT_MODULE_LOCATION[143]=./v4l +DEST_MODULE_LOCATION[143]=/updates/dkms +BUILT_MODULE_NAME[144]=rc-dib0700-rc5 +BUILT_MODULE_LOCATION[144]=./v4l +DEST_MODULE_LOCATION[144]=/updates/dkms +BUILT_MODULE_NAME[145]=dvb-usb-cxusb +BUILT_MODULE_LOCATION[145]=./v4l +DEST_MODULE_LOCATION[145]=/updates/dkms +BUILT_MODULE_NAME[146]=imon +BUILT_MODULE_LOCATION[146]=./v4l +DEST_MODULE_LOCATION[146]=/updates/dkms +BUILT_MODULE_NAME[147]=ves1820 +BUILT_MODULE_LOCATION[147]=./v4l +DEST_MODULE_LOCATION[147]=/updates/dkms +BUILT_MODULE_NAME[148]=dvb-usb-vp7045 +BUILT_MODULE_LOCATION[148]=./v4l +DEST_MODULE_LOCATION[148]=/updates/dkms +BUILT_MODULE_NAME[149]=gspca_sn9c2028 +BUILT_MODULE_LOCATION[149]=./v4l +DEST_MODULE_LOCATION[149]=/updates/dkms +BUILT_MODULE_NAME[150]=ves1x93 +BUILT_MODULE_LOCATION[150]=./v4l +DEST_MODULE_LOCATION[150]=/updates/dkms +BUILT_MODULE_NAME[151]=ths7303 +BUILT_MODULE_LOCATION[151]=./v4l +DEST_MODULE_LOCATION[151]=/updates/dkms +BUILT_MODULE_NAME[152]=rc-dntv-live-dvb-t +BUILT_MODULE_LOCATION[152]=./v4l +DEST_MODULE_LOCATION[152]=/updates/dkms +BUILT_MODULE_NAME[153]=rc-leadtek-y04g0051 +BUILT_MODULE_LOCATION[153]=./v4l +DEST_MODULE_LOCATION[153]=/updates/dkms +BUILT_MODULE_NAME[154]=lnbp21 +BUILT_MODULE_LOCATION[154]=./v4l +DEST_MODULE_LOCATION[154]=/updates/dkms +BUILT_MODULE_NAME[155]=rc-lme2510 +BUILT_MODULE_LOCATION[155]=./v4l +DEST_MODULE_LOCATION[155]=/updates/dkms +BUILT_MODULE_NAME[156]=rc-kworld-315u +BUILT_MODULE_LOCATION[156]=./v4l +DEST_MODULE_LOCATION[156]=/updates/dkms +BUILT_MODULE_NAME[157]=stkwebcam +BUILT_MODULE_LOCATION[157]=./v4l +DEST_MODULE_LOCATION[157]=/updates/dkms +BUILT_MODULE_NAME[158]=rc-trekstor +BUILT_MODULE_LOCATION[158]=./v4l +DEST_MODULE_LOCATION[158]=/updates/dkms +BUILT_MODULE_NAME[159]=qt1010 +BUILT_MODULE_LOCATION[159]=./v4l +DEST_MODULE_LOCATION[159]=/updates/dkms +BUILT_MODULE_NAME[160]=or51211 +BUILT_MODULE_LOCATION[160]=./v4l +DEST_MODULE_LOCATION[160]=/updates/dkms +BUILT_MODULE_NAME[161]=rc-pinnacle-grey +BUILT_MODULE_LOCATION[161]=./v4l +DEST_MODULE_LOCATION[161]=/updates/dkms +BUILT_MODULE_NAME[162]=cx18 +BUILT_MODULE_LOCATION[162]=./v4l +DEST_MODULE_LOCATION[162]=/updates/dkms +BUILT_MODULE_NAME[163]=saa7146 +BUILT_MODULE_LOCATION[163]=./v4l +DEST_MODULE_LOCATION[163]=/updates/dkms +BUILT_MODULE_NAME[164]=dvb-usb-gl861 +BUILT_MODULE_LOCATION[164]=./v4l +DEST_MODULE_LOCATION[164]=/updates/dkms +BUILT_MODULE_NAME[165]=budget-patch +BUILT_MODULE_LOCATION[165]=./v4l +DEST_MODULE_LOCATION[165]=/updates/dkms +BUILT_MODULE_NAME[166]=saa716x_hybrid +BUILT_MODULE_LOCATION[166]=./v4l +DEST_MODULE_LOCATION[166]=/updates/dkms +BUILT_MODULE_NAME[167]=saa7134-empress +BUILT_MODULE_LOCATION[167]=./v4l +DEST_MODULE_LOCATION[167]=/updates/dkms +BUILT_MODULE_NAME[168]=ec100 +BUILT_MODULE_LOCATION[168]=./v4l +DEST_MODULE_LOCATION[168]=/updates/dkms +BUILT_MODULE_NAME[169]=dib0090 +BUILT_MODULE_LOCATION[169]=./v4l +DEST_MODULE_LOCATION[169]=/updates/dkms +BUILT_MODULE_NAME[170]=cx25840 +BUILT_MODULE_LOCATION[170]=./v4l +DEST_MODULE_LOCATION[170]=/updates/dkms +BUILT_MODULE_NAME[171]=upd64083 +BUILT_MODULE_LOCATION[171]=./v4l +DEST_MODULE_LOCATION[171]=/updates/dkms +BUILT_MODULE_NAME[172]=stv0299 +BUILT_MODULE_LOCATION[172]=./v4l +DEST_MODULE_LOCATION[172]=/updates/dkms +BUILT_MODULE_NAME[173]=dib3000mb +BUILT_MODULE_LOCATION[173]=./v4l +DEST_MODULE_LOCATION[173]=/updates/dkms +BUILT_MODULE_NAME[174]=gspca_stv0680 +BUILT_MODULE_LOCATION[174]=./v4l +DEST_MODULE_LOCATION[174]=/updates/dkms +BUILT_MODULE_NAME[175]=budget-av +BUILT_MODULE_LOCATION[175]=./v4l +DEST_MODULE_LOCATION[175]=/updates/dkms +BUILT_MODULE_NAME[176]=dst_ca +BUILT_MODULE_LOCATION[176]=./v4l +DEST_MODULE_LOCATION[176]=/updates/dkms +BUILT_MODULE_NAME[177]=tvaudio +BUILT_MODULE_LOCATION[177]=./v4l +DEST_MODULE_LOCATION[177]=/updates/dkms +BUILT_MODULE_NAME[178]=rc-avermedia-cardbus +BUILT_MODULE_LOCATION[178]=./v4l +DEST_MODULE_LOCATION[178]=/updates/dkms +BUILT_MODULE_NAME[179]=stv0900 +BUILT_MODULE_LOCATION[179]=./v4l +DEST_MODULE_LOCATION[179]=/updates/dkms +BUILT_MODULE_NAME[180]=videobuf-dma-sg +BUILT_MODULE_LOCATION[180]=./v4l +DEST_MODULE_LOCATION[180]=/updates/dkms +BUILT_MODULE_NAME[181]=rc-gadmei-rm008z +BUILT_MODULE_LOCATION[181]=./v4l +DEST_MODULE_LOCATION[181]=/updates/dkms +BUILT_MODULE_NAME[182]=s2255drv +BUILT_MODULE_LOCATION[182]=./v4l +DEST_MODULE_LOCATION[182]=/updates/dkms +BUILT_MODULE_NAME[183]=rc-pixelview +BUILT_MODULE_LOCATION[183]=./v4l +DEST_MODULE_LOCATION[183]=/updates/dkms +BUILT_MODULE_NAME[184]=saa716x_ff +BUILT_MODULE_LOCATION[184]=./v4l +DEST_MODULE_LOCATION[184]=/updates/dkms +BUILT_MODULE_NAME[185]=videobuf2-core +BUILT_MODULE_LOCATION[185]=./v4l +DEST_MODULE_LOCATION[185]=/updates/dkms +BUILT_MODULE_NAME[186]=cx22702 +BUILT_MODULE_LOCATION[186]=./v4l +DEST_MODULE_LOCATION[186]=/updates/dkms +BUILT_MODULE_NAME[187]=saa7134 +BUILT_MODULE_LOCATION[187]=./v4l +DEST_MODULE_LOCATION[187]=/updates/dkms +BUILT_MODULE_NAME[188]=dvb-usb-af9005-remote +BUILT_MODULE_LOCATION[188]=./v4l +DEST_MODULE_LOCATION[188]=/updates/dkms +BUILT_MODULE_NAME[189]=dvb-usb-friio +BUILT_MODULE_LOCATION[189]=./v4l +DEST_MODULE_LOCATION[189]=/updates/dkms +BUILT_MODULE_NAME[190]=ttpci-eeprom +BUILT_MODULE_LOCATION[190]=./v4l +DEST_MODULE_LOCATION[190]=/updates/dkms +BUILT_MODULE_NAME[191]=rc-ati-tv-wonder-hd-600 +BUILT_MODULE_LOCATION[191]=./v4l +DEST_MODULE_LOCATION[191]=/updates/dkms +BUILT_MODULE_NAME[192]=tuner-types +BUILT_MODULE_LOCATION[192]=./v4l +DEST_MODULE_LOCATION[192]=/updates/dkms +BUILT_MODULE_NAME[193]=nuvoton-cir +BUILT_MODULE_LOCATION[193]=./v4l +DEST_MODULE_LOCATION[193]=/updates/dkms +BUILT_MODULE_NAME[194]=dib9000 +BUILT_MODULE_LOCATION[194]=./v4l +DEST_MODULE_LOCATION[194]=/updates/dkms +BUILT_MODULE_NAME[195]=snd-bt87x +BUILT_MODULE_LOCATION[195]=./v4l +DEST_MODULE_LOCATION[195]=/updates/dkms +BUILT_MODULE_NAME[196]=rc-anysee +BUILT_MODULE_LOCATION[196]=./v4l +DEST_MODULE_LOCATION[196]=/updates/dkms +BUILT_MODULE_NAME[197]=sp887x +BUILT_MODULE_LOCATION[197]=./v4l +DEST_MODULE_LOCATION[197]=/updates/dkms +BUILT_MODULE_NAME[198]=gspca_ov534 +BUILT_MODULE_LOCATION[198]=./v4l +DEST_MODULE_LOCATION[198]=/updates/dkms +BUILT_MODULE_NAME[199]=radio-maxiradio +BUILT_MODULE_LOCATION[199]=./v4l +DEST_MODULE_LOCATION[199]=/updates/dkms +BUILT_MODULE_NAME[200]=dvb-usb-dibusb-common +BUILT_MODULE_LOCATION[200]=./v4l +DEST_MODULE_LOCATION[200]=/updates/dkms +BUILT_MODULE_NAME[201]=msp3400 +BUILT_MODULE_LOCATION[201]=./v4l +DEST_MODULE_LOCATION[201]=/updates/dkms +BUILT_MODULE_NAME[202]=dvb-usb-digitv +BUILT_MODULE_LOCATION[202]=./v4l +DEST_MODULE_LOCATION[202]=/updates/dkms +BUILT_MODULE_NAME[203]=rc-streamzap +BUILT_MODULE_LOCATION[203]=./v4l +DEST_MODULE_LOCATION[203]=/updates/dkms +BUILT_MODULE_NAME[204]=bw-qcam +BUILT_MODULE_LOCATION[204]=./v4l +DEST_MODULE_LOCATION[204]=/updates/dkms +BUILT_MODULE_NAME[205]=videobuf2-vmalloc +BUILT_MODULE_LOCATION[205]=./v4l +DEST_MODULE_LOCATION[205]=/updates/dkms +BUILT_MODULE_NAME[206]=tuner +BUILT_MODULE_LOCATION[206]=./v4l +DEST_MODULE_LOCATION[206]=/updates/dkms +BUILT_MODULE_NAME[207]=radio-tea5764 +BUILT_MODULE_LOCATION[207]=./v4l +DEST_MODULE_LOCATION[207]=/updates/dkms +BUILT_MODULE_NAME[208]=dibx000_common +BUILT_MODULE_LOCATION[208]=./v4l +DEST_MODULE_LOCATION[208]=/updates/dkms +BUILT_MODULE_NAME[209]=mb86a20s +BUILT_MODULE_LOCATION[209]=./v4l +DEST_MODULE_LOCATION[209]=/updates/dkms +BUILT_MODULE_NAME[210]=cx24116 +BUILT_MODULE_LOCATION[210]=./v4l +DEST_MODULE_LOCATION[210]=/updates/dkms +BUILT_MODULE_NAME[211]=rc-twinhan-dtv-cab-ci +BUILT_MODULE_LOCATION[211]=./v4l +DEST_MODULE_LOCATION[211]=/updates/dkms +BUILT_MODULE_NAME[212]=mxl5007t +BUILT_MODULE_LOCATION[212]=./v4l +DEST_MODULE_LOCATION[212]=/updates/dkms +BUILT_MODULE_NAME[213]=stv090x +BUILT_MODULE_LOCATION[213]=./v4l +DEST_MODULE_LOCATION[213]=/updates/dkms +BUILT_MODULE_NAME[214]=rc-flydvb +BUILT_MODULE_LOCATION[214]=./v4l +DEST_MODULE_LOCATION[214]=/updates/dkms +BUILT_MODULE_NAME[215]=hopper +BUILT_MODULE_LOCATION[215]=./v4l +DEST_MODULE_LOCATION[215]=/updates/dkms +BUILT_MODULE_NAME[216]=mt312 +BUILT_MODULE_LOCATION[216]=./v4l +DEST_MODULE_LOCATION[216]=/updates/dkms +BUILT_MODULE_NAME[217]=isl6421 +BUILT_MODULE_LOCATION[217]=./v4l +DEST_MODULE_LOCATION[217]=/updates/dkms +BUILT_MODULE_NAME[218]=gspca_sq905c +BUILT_MODULE_LOCATION[218]=./v4l +DEST_MODULE_LOCATION[218]=/updates/dkms +BUILT_MODULE_NAME[219]=lgs8gl5 +BUILT_MODULE_LOCATION[219]=./v4l +DEST_MODULE_LOCATION[219]=/updates/dkms +BUILT_MODULE_NAME[220]=gspca_spca508 +BUILT_MODULE_LOCATION[220]=./v4l +DEST_MODULE_LOCATION[220]=/updates/dkms +BUILT_MODULE_NAME[221]=tuner-simple +BUILT_MODULE_LOCATION[221]=./v4l +DEST_MODULE_LOCATION[221]=/updates/dkms +BUILT_MODULE_NAME[222]=gspca_etoms +BUILT_MODULE_LOCATION[222]=./v4l +DEST_MODULE_LOCATION[222]=/updates/dkms +BUILT_MODULE_NAME[223]=v4l2-common +BUILT_MODULE_LOCATION[223]=./v4l +DEST_MODULE_LOCATION[223]=/updates/dkms +BUILT_MODULE_NAME[224]=adv7175 +BUILT_MODULE_LOCATION[224]=./v4l +DEST_MODULE_LOCATION[224]=/updates/dkms +BUILT_MODULE_NAME[225]=cx231xx-dvb +BUILT_MODULE_LOCATION[225]=./v4l +DEST_MODULE_LOCATION[225]=/updates/dkms +BUILT_MODULE_NAME[226]=ir-nec-decoder +BUILT_MODULE_LOCATION[226]=./v4l +DEST_MODULE_LOCATION[226]=/updates/dkms +BUILT_MODULE_NAME[227]=rc-tevii-nec +BUILT_MODULE_LOCATION[227]=./v4l +DEST_MODULE_LOCATION[227]=/updates/dkms +BUILT_MODULE_NAME[228]=ivtvfb +BUILT_MODULE_LOCATION[228]=./v4l +DEST_MODULE_LOCATION[228]=/updates/dkms +BUILT_MODULE_NAME[229]=lgs8gxx +BUILT_MODULE_LOCATION[229]=./v4l +DEST_MODULE_LOCATION[229]=/updates/dkms +BUILT_MODULE_NAME[230]=rc-dm1105-nec +BUILT_MODULE_LOCATION[230]=./v4l +DEST_MODULE_LOCATION[230]=/updates/dkms +BUILT_MODULE_NAME[231]=max2165 +BUILT_MODULE_LOCATION[231]=./v4l +DEST_MODULE_LOCATION[231]=/updates/dkms +BUILT_MODULE_NAME[232]=gspca_tv8532 +BUILT_MODULE_LOCATION[232]=./v4l +DEST_MODULE_LOCATION[232]=/updates/dkms +BUILT_MODULE_NAME[233]=cx24123 +BUILT_MODULE_LOCATION[233]=./v4l +DEST_MODULE_LOCATION[233]=/updates/dkms +BUILT_MODULE_NAME[234]=dst +BUILT_MODULE_LOCATION[234]=./v4l +DEST_MODULE_LOCATION[234]=/updates/dkms +BUILT_MODULE_NAME[235]=tda10021 +BUILT_MODULE_LOCATION[235]=./v4l +DEST_MODULE_LOCATION[235]=/updates/dkms +BUILT_MODULE_NAME[236]=tua6100 +BUILT_MODULE_LOCATION[236]=./v4l +DEST_MODULE_LOCATION[236]=/updates/dkms +BUILT_MODULE_NAME[237]=dvb-bt8xx +BUILT_MODULE_LOCATION[237]=./v4l +DEST_MODULE_LOCATION[237]=/updates/dkms +BUILT_MODULE_NAME[238]=si21xx +BUILT_MODULE_LOCATION[238]=./v4l +DEST_MODULE_LOCATION[238]=/updates/dkms +BUILT_MODULE_NAME[239]=rc-msi-digivox-ii +BUILT_MODULE_LOCATION[239]=./v4l +DEST_MODULE_LOCATION[239]=/updates/dkms +BUILT_MODULE_NAME[240]=nxt200x +BUILT_MODULE_LOCATION[240]=./v4l +DEST_MODULE_LOCATION[240]=/updates/dkms +BUILT_MODULE_NAME[241]=cx18-alsa +BUILT_MODULE_LOCATION[241]=./v4l +DEST_MODULE_LOCATION[241]=/updates/dkms +BUILT_MODULE_NAME[242]=saa7185 +BUILT_MODULE_LOCATION[242]=./v4l +DEST_MODULE_LOCATION[242]=/updates/dkms +BUILT_MODULE_NAME[243]=mb86a16 +BUILT_MODULE_LOCATION[243]=./v4l +DEST_MODULE_LOCATION[243]=/updates/dkms +BUILT_MODULE_NAME[244]=tea6420 +BUILT_MODULE_LOCATION[244]=./v4l +DEST_MODULE_LOCATION[244]=/updates/dkms +BUILT_MODULE_NAME[245]=gspca_mr97310a +BUILT_MODULE_LOCATION[245]=./v4l +DEST_MODULE_LOCATION[245]=/updates/dkms +BUILT_MODULE_NAME[246]=m52790 +BUILT_MODULE_LOCATION[246]=./v4l +DEST_MODULE_LOCATION[246]=/updates/dkms +BUILT_MODULE_NAME[247]=gspca_spca506 +BUILT_MODULE_LOCATION[247]=./v4l +DEST_MODULE_LOCATION[247]=/updates/dkms +BUILT_MODULE_NAME[248]=dvb-usb-nova-t-usb2 +BUILT_MODULE_LOCATION[248]=./v4l +DEST_MODULE_LOCATION[248]=/updates/dkms +BUILT_MODULE_NAME[249]=budget +BUILT_MODULE_LOCATION[249]=./v4l +DEST_MODULE_LOCATION[249]=/updates/dkms +BUILT_MODULE_NAME[250]=gspca_sq905 +BUILT_MODULE_LOCATION[250]=./v4l +DEST_MODULE_LOCATION[250]=/updates/dkms +BUILT_MODULE_NAME[251]=rc-terratec-cinergy-s2-hd +BUILT_MODULE_LOCATION[251]=./v4l +DEST_MODULE_LOCATION[251]=/updates/dkms +BUILT_MODULE_NAME[252]=dib0070 +BUILT_MODULE_LOCATION[252]=./v4l +DEST_MODULE_LOCATION[252]=/updates/dkms +BUILT_MODULE_NAME[253]=cx88-blackbird +BUILT_MODULE_LOCATION[253]=./v4l +DEST_MODULE_LOCATION[253]=/updates/dkms +BUILT_MODULE_NAME[254]=gspca_mars +BUILT_MODULE_LOCATION[254]=./v4l +DEST_MODULE_LOCATION[254]=/updates/dkms +BUILT_MODULE_NAME[255]=rc-terratec-cinergy-xs +BUILT_MODULE_LOCATION[255]=./v4l +DEST_MODULE_LOCATION[255]=/updates/dkms +BUILT_MODULE_NAME[256]=gspca_xirlink_cit +BUILT_MODULE_LOCATION[256]=./v4l +DEST_MODULE_LOCATION[256]=/updates/dkms +BUILT_MODULE_NAME[257]=cx8800 +BUILT_MODULE_LOCATION[257]=./v4l +DEST_MODULE_LOCATION[257]=/updates/dkms +BUILT_MODULE_NAME[258]=rc-norwood +BUILT_MODULE_LOCATION[258]=./v4l +DEST_MODULE_LOCATION[258]=/updates/dkms +BUILT_MODULE_NAME[259]=gspca_spca501 +BUILT_MODULE_LOCATION[259]=./v4l +DEST_MODULE_LOCATION[259]=/updates/dkms +BUILT_MODULE_NAME[260]=gspca_vicam +BUILT_MODULE_LOCATION[260]=./v4l +DEST_MODULE_LOCATION[260]=/updates/dkms +BUILT_MODULE_NAME[261]=gspca_jeilinj +BUILT_MODULE_LOCATION[261]=./v4l +DEST_MODULE_LOCATION[261]=/updates/dkms +BUILT_MODULE_NAME[262]=cx23885 +BUILT_MODULE_LOCATION[262]=./v4l +DEST_MODULE_LOCATION[262]=/updates/dkms +BUILT_MODULE_NAME[263]=mxl5005s +BUILT_MODULE_LOCATION[263]=./v4l +DEST_MODULE_LOCATION[263]=/updates/dkms +BUILT_MODULE_NAME[264]=sn9c102 +BUILT_MODULE_LOCATION[264]=./v4l +DEST_MODULE_LOCATION[264]=/updates/dkms +BUILT_MODULE_NAME[265]=dvb-usb-dtv5100 +BUILT_MODULE_LOCATION[265]=./v4l +DEST_MODULE_LOCATION[265]=/updates/dkms +BUILT_MODULE_NAME[266]=isl6405 +BUILT_MODULE_LOCATION[266]=./v4l +DEST_MODULE_LOCATION[266]=/updates/dkms +BUILT_MODULE_NAME[267]=itd1000 +BUILT_MODULE_LOCATION[267]=./v4l +DEST_MODULE_LOCATION[267]=/updates/dkms +BUILT_MODULE_NAME[268]=au8522 +BUILT_MODULE_LOCATION[268]=./v4l +DEST_MODULE_LOCATION[268]=/updates/dkms +BUILT_MODULE_NAME[269]=tda9887 +BUILT_MODULE_LOCATION[269]=./v4l +DEST_MODULE_LOCATION[269]=/updates/dkms +BUILT_MODULE_NAME[270]=dvb-usb-gp8psk +BUILT_MODULE_LOCATION[270]=./v4l +DEST_MODULE_LOCATION[270]=/updates/dkms +BUILT_MODULE_NAME[271]=dvb-usb-anysee +BUILT_MODULE_LOCATION[271]=./v4l +DEST_MODULE_LOCATION[271]=/updates/dkms +BUILT_MODULE_NAME[272]=nxt6000 +BUILT_MODULE_LOCATION[272]=./v4l +DEST_MODULE_LOCATION[272]=/updates/dkms +BUILT_MODULE_NAME[273]=saa7115 +BUILT_MODULE_LOCATION[273]=./v4l +DEST_MODULE_LOCATION[273]=/updates/dkms +BUILT_MODULE_NAME[274]=au0828 +BUILT_MODULE_LOCATION[274]=./v4l +DEST_MODULE_LOCATION[274]=/updates/dkms +BUILT_MODULE_NAME[275]=rc-avermedia +BUILT_MODULE_LOCATION[275]=./v4l +DEST_MODULE_LOCATION[275]=/updates/dkms +BUILT_MODULE_NAME[276]=hexium_gemini +BUILT_MODULE_LOCATION[276]=./v4l +DEST_MODULE_LOCATION[276]=/updates/dkms +BUILT_MODULE_NAME[277]=rc-eztv +BUILT_MODULE_LOCATION[277]=./v4l +DEST_MODULE_LOCATION[277]=/updates/dkms +BUILT_MODULE_NAME[278]=pwc +BUILT_MODULE_LOCATION[278]=./v4l +DEST_MODULE_LOCATION[278]=/updates/dkms +BUILT_MODULE_NAME[279]=rc-encore-enltv-fm53 +BUILT_MODULE_LOCATION[279]=./v4l +DEST_MODULE_LOCATION[279]=/updates/dkms +BUILT_MODULE_NAME[280]=budget-core +BUILT_MODULE_LOCATION[280]=./v4l +DEST_MODULE_LOCATION[280]=/updates/dkms +BUILT_MODULE_NAME[281]=gspca_conex +BUILT_MODULE_LOCATION[281]=./v4l +DEST_MODULE_LOCATION[281]=/updates/dkms +BUILT_MODULE_NAME[282]=gspca_pac7311 +BUILT_MODULE_LOCATION[282]=./v4l +DEST_MODULE_LOCATION[282]=/updates/dkms +BUILT_MODULE_NAME[283]=dvb-ttusb-budget +BUILT_MODULE_LOCATION[283]=./v4l +DEST_MODULE_LOCATION[283]=/updates/dkms +BUILT_MODULE_NAME[284]=tda8083 +BUILT_MODULE_LOCATION[284]=./v4l +DEST_MODULE_LOCATION[284]=/updates/dkms +BUILT_MODULE_NAME[285]=gspca_pac207 +BUILT_MODULE_LOCATION[285]=./v4l +DEST_MODULE_LOCATION[285]=/updates/dkms +BUILT_MODULE_NAME[286]=ix2505v +BUILT_MODULE_LOCATION[286]=./v4l +DEST_MODULE_LOCATION[286]=/updates/dkms +BUILT_MODULE_NAME[287]=zr36060 +BUILT_MODULE_LOCATION[287]=./v4l +DEST_MODULE_LOCATION[287]=/updates/dkms +BUILT_MODULE_NAME[288]=rc-technisat-usb2 +BUILT_MODULE_LOCATION[288]=./v4l +DEST_MODULE_LOCATION[288]=/updates/dkms +BUILT_MODULE_NAME[289]=v4l2-int-device +BUILT_MODULE_LOCATION[289]=./v4l +DEST_MODULE_LOCATION[289]=/updates/dkms +BUILT_MODULE_NAME[290]=gspca_finepix +BUILT_MODULE_LOCATION[290]=./v4l +DEST_MODULE_LOCATION[290]=/updates/dkms +BUILT_MODULE_NAME[291]=dvb-usb-au6610 +BUILT_MODULE_LOCATION[291]=./v4l +DEST_MODULE_LOCATION[291]=/updates/dkms +BUILT_MODULE_NAME[292]=rc-nec-terratec-cinergy-xs +BUILT_MODULE_LOCATION[292]=./v4l +DEST_MODULE_LOCATION[292]=/updates/dkms +BUILT_MODULE_NAME[293]=gspca_t613 +BUILT_MODULE_LOCATION[293]=./v4l +DEST_MODULE_LOCATION[293]=/updates/dkms +BUILT_MODULE_NAME[294]=saa7191 +BUILT_MODULE_LOCATION[294]=./v4l +DEST_MODULE_LOCATION[294]=/updates/dkms +BUILT_MODULE_NAME[295]=vp27smpx +BUILT_MODULE_LOCATION[295]=./v4l +DEST_MODULE_LOCATION[295]=/updates/dkms +BUILT_MODULE_NAME[296]=rc-budget-ci-old +BUILT_MODULE_LOCATION[296]=./v4l +DEST_MODULE_LOCATION[296]=/updates/dkms +BUILT_MODULE_NAME[297]=s5h1411 +BUILT_MODULE_LOCATION[297]=./v4l +DEST_MODULE_LOCATION[297]=/updates/dkms +BUILT_MODULE_NAME[298]=gspca_zc3xx +BUILT_MODULE_LOCATION[298]=./v4l +DEST_MODULE_LOCATION[298]=/updates/dkms +BUILT_MODULE_NAME[299]=dvb-usb +BUILT_MODULE_LOCATION[299]=./v4l +DEST_MODULE_LOCATION[299]=/updates/dkms +BUILT_MODULE_NAME[300]=dvb-usb-dibusb-mc +BUILT_MODULE_LOCATION[300]=./v4l +DEST_MODULE_LOCATION[300]=/updates/dkms +BUILT_MODULE_NAME[301]=dvb-pll +BUILT_MODULE_LOCATION[301]=./v4l +DEST_MODULE_LOCATION[301]=/updates/dkms +BUILT_MODULE_NAME[302]=ir-kbd-i2c +BUILT_MODULE_LOCATION[302]=./v4l +DEST_MODULE_LOCATION[302]=/updates/dkms +BUILT_MODULE_NAME[303]=sr030pc30 +BUILT_MODULE_LOCATION[303]=./v4l +DEST_MODULE_LOCATION[303]=/updates/dkms +BUILT_MODULE_NAME[304]=tda826x +BUILT_MODULE_LOCATION[304]=./v4l +DEST_MODULE_LOCATION[304]=/updates/dkms +BUILT_MODULE_NAME[305]=tea6415c +BUILT_MODULE_LOCATION[305]=./v4l +DEST_MODULE_LOCATION[305]=/updates/dkms +BUILT_MODULE_NAME[306]=zr36050 +BUILT_MODULE_LOCATION[306]=./v4l +DEST_MODULE_LOCATION[306]=/updates/dkms +BUILT_MODULE_NAME[307]=rc-kaiomy +BUILT_MODULE_LOCATION[307]=./v4l +DEST_MODULE_LOCATION[307]=/updates/dkms +BUILT_MODULE_NAME[308]=ov7670 +BUILT_MODULE_LOCATION[308]=./v4l +DEST_MODULE_LOCATION[308]=/updates/dkms +BUILT_MODULE_NAME[309]=rc-videomate-s350 +BUILT_MODULE_LOCATION[309]=./v4l +DEST_MODULE_LOCATION[309]=/updates/dkms +BUILT_MODULE_NAME[310]=lgdt3305 +BUILT_MODULE_LOCATION[310]=./v4l +DEST_MODULE_LOCATION[310]=/updates/dkms +BUILT_MODULE_NAME[311]=rc-azurewave-ad-tu700 +BUILT_MODULE_LOCATION[311]=./v4l +DEST_MODULE_LOCATION[311]=/updates/dkms +BUILT_MODULE_NAME[312]=l64781 +BUILT_MODULE_LOCATION[312]=./v4l +DEST_MODULE_LOCATION[312]=/updates/dkms +BUILT_MODULE_NAME[313]=rc-terratec-slim-2 +BUILT_MODULE_LOCATION[313]=./v4l +DEST_MODULE_LOCATION[313]=/updates/dkms +BUILT_MODULE_NAME[314]=tvp5150 +BUILT_MODULE_LOCATION[314]=./v4l +DEST_MODULE_LOCATION[314]=/updates/dkms +BUILT_MODULE_NAME[315]=rc-hauppauge +BUILT_MODULE_LOCATION[315]=./v4l +DEST_MODULE_LOCATION[315]=/updates/dkms +BUILT_MODULE_NAME[316]=gspca_ov519 +BUILT_MODULE_LOCATION[316]=./v4l +DEST_MODULE_LOCATION[316]=/updates/dkms +BUILT_MODULE_NAME[317]=saa716x_budget +BUILT_MODULE_LOCATION[317]=./v4l +DEST_MODULE_LOCATION[317]=/updates/dkms +BUILT_MODULE_NAME[318]=streamzap +BUILT_MODULE_LOCATION[318]=./v4l +DEST_MODULE_LOCATION[318]=/updates/dkms +BUILT_MODULE_NAME[319]=tda665x +BUILT_MODULE_LOCATION[319]=./v4l +DEST_MODULE_LOCATION[319]=/updates/dkms +BUILT_MODULE_NAME[320]=cx88xx +BUILT_MODULE_LOCATION[320]=./v4l +DEST_MODULE_LOCATION[320]=/updates/dkms +BUILT_MODULE_NAME[321]=mt2060 +BUILT_MODULE_LOCATION[321]=./v4l +DEST_MODULE_LOCATION[321]=/updates/dkms +BUILT_MODULE_NAME[322]=tda8290 +BUILT_MODULE_LOCATION[322]=./v4l +DEST_MODULE_LOCATION[322]=/updates/dkms +BUILT_MODULE_NAME[323]=rc-msi-tvanywhere-plus +BUILT_MODULE_LOCATION[323]=./v4l +DEST_MODULE_LOCATION[323]=/updates/dkms +BUILT_MODULE_NAME[324]=tda10086 +BUILT_MODULE_LOCATION[324]=./v4l +DEST_MODULE_LOCATION[324]=/updates/dkms +BUILT_MODULE_NAME[325]=stv6110 +BUILT_MODULE_LOCATION[325]=./v4l +DEST_MODULE_LOCATION[325]=/updates/dkms +BUILT_MODULE_NAME[326]=dib8000 +BUILT_MODULE_LOCATION[326]=./v4l +DEST_MODULE_LOCATION[326]=/updates/dkms +BUILT_MODULE_NAME[327]=saa7134-alsa +BUILT_MODULE_LOCATION[327]=./v4l +DEST_MODULE_LOCATION[327]=/updates/dkms +BUILT_MODULE_NAME[328]=upd64031a +BUILT_MODULE_LOCATION[328]=./v4l +DEST_MODULE_LOCATION[328]=/updates/dkms +BUILT_MODULE_NAME[329]=ivtv +BUILT_MODULE_LOCATION[329]=./v4l +DEST_MODULE_LOCATION[329]=/updates/dkms +BUILT_MODULE_NAME[330]=videodev +BUILT_MODULE_LOCATION[330]=./v4l +DEST_MODULE_LOCATION[330]=/updates/dkms +BUILT_MODULE_NAME[331]=tda1004x +BUILT_MODULE_LOCATION[331]=./v4l +DEST_MODULE_LOCATION[331]=/updates/dkms +BUILT_MODULE_NAME[332]=gspca_sonixb +BUILT_MODULE_LOCATION[332]=./v4l +DEST_MODULE_LOCATION[332]=/updates/dkms +BUILT_MODULE_NAME[333]=earth-pt1 +BUILT_MODULE_LOCATION[333]=./v4l +DEST_MODULE_LOCATION[333]=/updates/dkms +BUILT_MODULE_NAME[334]=zl10036 +BUILT_MODULE_LOCATION[334]=./v4l +DEST_MODULE_LOCATION[334]=/updates/dkms +BUILT_MODULE_NAME[335]=cx88-vp3054-i2c +BUILT_MODULE_LOCATION[335]=./v4l +DEST_MODULE_LOCATION[335]=/updates/dkms +BUILT_MODULE_NAME[336]=cx2341x +BUILT_MODULE_LOCATION[336]=./v4l +DEST_MODULE_LOCATION[336]=/updates/dkms +BUILT_MODULE_NAME[337]=vpx3220 +BUILT_MODULE_LOCATION[337]=./v4l +DEST_MODULE_LOCATION[337]=/updates/dkms +BUILT_MODULE_NAME[338]=em28xx-dvb +BUILT_MODULE_LOCATION[338]=./v4l +DEST_MODULE_LOCATION[338]=/updates/dkms +BUILT_MODULE_NAME[339]=rc-avermedia-dvbt +BUILT_MODULE_LOCATION[339]=./v4l +DEST_MODULE_LOCATION[339]=/updates/dkms +BUILT_MODULE_NAME[340]=ir-lirc-codec +BUILT_MODULE_LOCATION[340]=./v4l +DEST_MODULE_LOCATION[340]=/updates/dkms +BUILT_MODULE_NAME[341]=bt856 +BUILT_MODULE_LOCATION[341]=./v4l +DEST_MODULE_LOCATION[341]=/updates/dkms +BUILT_MODULE_NAME[342]=tef6862 +BUILT_MODULE_LOCATION[342]=./v4l +DEST_MODULE_LOCATION[342]=/updates/dkms +BUILT_MODULE_NAME[343]=videobuf2-memops +BUILT_MODULE_LOCATION[343]=./v4l +DEST_MODULE_LOCATION[343]=/updates/dkms +BUILT_MODULE_NAME[344]=gspca_konica +BUILT_MODULE_LOCATION[344]=./v4l +DEST_MODULE_LOCATION[344]=/updates/dkms +BUILT_MODULE_NAME[345]=rc-videomate-m1f +BUILT_MODULE_LOCATION[345]=./v4l +DEST_MODULE_LOCATION[345]=/updates/dkms +BUILT_MODULE_NAME[346]=radio-si4713 +BUILT_MODULE_LOCATION[346]=./v4l +DEST_MODULE_LOCATION[346]=/updates/dkms +BUILT_MODULE_NAME[347]=dvb-usb-a800 +BUILT_MODULE_LOCATION[347]=./v4l +DEST_MODULE_LOCATION[347]=/updates/dkms +BUILT_MODULE_NAME[348]=s5h1432 +BUILT_MODULE_LOCATION[348]=./v4l +DEST_MODULE_LOCATION[348]=/updates/dkms +BUILT_MODULE_NAME[349]=ir-sony-decoder +BUILT_MODULE_LOCATION[349]=./v4l +DEST_MODULE_LOCATION[349]=/updates/dkms +BUILT_MODULE_NAME[350]=rc-msi-tvanywhere +BUILT_MODULE_LOCATION[350]=./v4l +DEST_MODULE_LOCATION[350]=/updates/dkms +BUILT_MODULE_NAME[351]=dm1105 +BUILT_MODULE_LOCATION[351]=./v4l +DEST_MODULE_LOCATION[351]=/updates/dkms +BUILT_MODULE_NAME[352]=mt352 +BUILT_MODULE_LOCATION[352]=./v4l +DEST_MODULE_LOCATION[352]=/updates/dkms +BUILT_MODULE_NAME[353]=ir-rc5-sz-decoder +BUILT_MODULE_LOCATION[353]=./v4l +DEST_MODULE_LOCATION[353]=/updates/dkms +BUILT_MODULE_NAME[354]=rc-fusionhdtv-mce +BUILT_MODULE_LOCATION[354]=./v4l +DEST_MODULE_LOCATION[354]=/updates/dkms +BUILT_MODULE_NAME[355]=rc-dib0700-nec +BUILT_MODULE_LOCATION[355]=./v4l +DEST_MODULE_LOCATION[355]=/updates/dkms +BUILT_MODULE_NAME[356]=cafe_ccic +BUILT_MODULE_LOCATION[356]=./v4l +DEST_MODULE_LOCATION[356]=/updates/dkms +BUILT_MODULE_NAME[357]=dvb-usb-dtt200u +BUILT_MODULE_LOCATION[357]=./v4l +DEST_MODULE_LOCATION[357]=/updates/dkms +BUILT_MODULE_NAME[358]=mceusb +BUILT_MODULE_LOCATION[358]=./v4l +DEST_MODULE_LOCATION[358]=/updates/dkms +BUILT_MODULE_NAME[359]=drxd +BUILT_MODULE_LOCATION[359]=./v4l +DEST_MODULE_LOCATION[359]=/updates/dkms +BUILT_MODULE_NAME[360]=smsusb +BUILT_MODULE_LOCATION[360]=./v4l +DEST_MODULE_LOCATION[360]=/updates/dkms +BUILT_MODULE_NAME[361]=bt878 +BUILT_MODULE_LOCATION[361]=./v4l +DEST_MODULE_LOCATION[361]=/updates/dkms +BUILT_MODULE_NAME[362]=pluto2 +BUILT_MODULE_LOCATION[362]=./v4l +DEST_MODULE_LOCATION[362]=/updates/dkms +BUILT_MODULE_NAME[363]=b2c2-flexcop-usb +BUILT_MODULE_LOCATION[363]=./v4l +DEST_MODULE_LOCATION[363]=/updates/dkms +BUILT_MODULE_NAME[364]=mt2266 +BUILT_MODULE_LOCATION[364]=./v4l +DEST_MODULE_LOCATION[364]=/updates/dkms +BUILT_MODULE_NAME[365]=dvb-usb-af9005 +BUILT_MODULE_LOCATION[365]=./v4l +DEST_MODULE_LOCATION[365]=/updates/dkms +BUILT_MODULE_NAME[366]=dvb-core +BUILT_MODULE_LOCATION[366]=./v4l +DEST_MODULE_LOCATION[366]=/updates/dkms +BUILT_MODULE_NAME[367]=rc-total-media-in-hand +BUILT_MODULE_LOCATION[367]=./v4l +DEST_MODULE_LOCATION[367]=/updates/dkms +BUILT_MODULE_NAME[368]=rc-cinergy +BUILT_MODULE_LOCATION[368]=./v4l +DEST_MODULE_LOCATION[368]=/updates/dkms +BUILT_MODULE_NAME[369]=lgdt330x +BUILT_MODULE_LOCATION[369]=./v4l +DEST_MODULE_LOCATION[369]=/updates/dkms +BUILT_MODULE_NAME[370]=dvb-usb-dib0700 +BUILT_MODULE_LOCATION[370]=./v4l +DEST_MODULE_LOCATION[370]=/updates/dkms +BUILT_MODULE_NAME[371]=saa716x_core +BUILT_MODULE_LOCATION[371]=./v4l +DEST_MODULE_LOCATION[371]=/updates/dkms +BUILT_MODULE_NAME[372]=rc-pctv-sedna +BUILT_MODULE_LOCATION[372]=./v4l +DEST_MODULE_LOCATION[372]=/updates/dkms +BUILT_MODULE_NAME[373]=zr36067 +BUILT_MODULE_LOCATION[373]=./v4l +DEST_MODULE_LOCATION[373]=/updates/dkms +BUILT_MODULE_NAME[374]=af9013 +BUILT_MODULE_LOCATION[374]=./v4l +DEST_MODULE_LOCATION[374]=/updates/dkms +BUILT_MODULE_NAME[375]=usbvision +BUILT_MODULE_LOCATION[375]=./v4l +DEST_MODULE_LOCATION[375]=/updates/dkms +BUILT_MODULE_NAME[376]=dvb-usb-ttusb2 +BUILT_MODULE_LOCATION[376]=./v4l +DEST_MODULE_LOCATION[376]=/updates/dkms +BUILT_MODULE_NAME[377]=zr364xx +BUILT_MODULE_LOCATION[377]=./v4l +DEST_MODULE_LOCATION[377]=/updates/dkms +BUILT_MODULE_NAME[378]=tda10048 +BUILT_MODULE_LOCATION[378]=./v4l +DEST_MODULE_LOCATION[378]=/updates/dkms +BUILT_MODULE_NAME[379]=tda10023 +BUILT_MODULE_LOCATION[379]=./v4l +DEST_MODULE_LOCATION[379]=/updates/dkms +BUILT_MODULE_NAME[380]=tda9840 +BUILT_MODULE_LOCATION[380]=./v4l +DEST_MODULE_LOCATION[380]=/updates/dkms +BUILT_MODULE_NAME[381]=bt819 +BUILT_MODULE_LOCATION[381]=./v4l +DEST_MODULE_LOCATION[381]=/updates/dkms +BUILT_MODULE_NAME[382]=smsmdtv +BUILT_MODULE_LOCATION[382]=./v4l +DEST_MODULE_LOCATION[382]=/updates/dkms +BUILT_MODULE_NAME[383]=dib3000mc +BUILT_MODULE_LOCATION[383]=./v4l +DEST_MODULE_LOCATION[383]=/updates/dkms +BUILT_MODULE_NAME[384]=mc44s803 +BUILT_MODULE_LOCATION[384]=./v4l +DEST_MODULE_LOCATION[384]=/updates/dkms +BUILT_MODULE_NAME[385]=rc-em-terratec +BUILT_MODULE_LOCATION[385]=./v4l +DEST_MODULE_LOCATION[385]=/updates/dkms +BUILT_MODULE_NAME[386]=btcx-risc +BUILT_MODULE_LOCATION[386]=./v4l +DEST_MODULE_LOCATION[386]=/updates/dkms +BUILT_MODULE_NAME[387]=dvb-ttpci +BUILT_MODULE_LOCATION[387]=./v4l +DEST_MODULE_LOCATION[387]=/updates/dkms +BUILT_MODULE_NAME[388]=tvp514x +BUILT_MODULE_LOCATION[388]=./v4l +DEST_MODULE_LOCATION[388]=/updates/dkms +BUILT_MODULE_NAME[389]=dib7000p +BUILT_MODULE_LOCATION[389]=./v4l +DEST_MODULE_LOCATION[389]=/updates/dkms +BUILT_MODULE_NAME[390]=rc-avertv-303 +BUILT_MODULE_LOCATION[390]=./v4l +DEST_MODULE_LOCATION[390]=/updates/dkms +BUILT_MODULE_NAME[391]=rc-lirc +BUILT_MODULE_LOCATION[391]=./v4l +DEST_MODULE_LOCATION[391]=/updates/dkms +BUILT_MODULE_NAME[392]=rc-iodata-bctv7e +BUILT_MODULE_LOCATION[392]=./v4l +DEST_MODULE_LOCATION[392]=/updates/dkms +BUILT_MODULE_NAME[393]=s5h1409 +BUILT_MODULE_LOCATION[393]=./v4l +DEST_MODULE_LOCATION[393]=/updates/dkms +BUILT_MODULE_NAME[394]=stb0899 +BUILT_MODULE_LOCATION[394]=./v4l +DEST_MODULE_LOCATION[394]=/updates/dkms +BUILT_MODULE_NAME[395]=smsdvb +BUILT_MODULE_LOCATION[395]=./v4l +DEST_MODULE_LOCATION[395]=/updates/dkms +BUILT_MODULE_NAME[396]=tuner-xc2028 +BUILT_MODULE_LOCATION[396]=./v4l +DEST_MODULE_LOCATION[396]=/updates/dkms +BUILT_MODULE_NAME[397]=hexium_orion +BUILT_MODULE_LOCATION[397]=./v4l +DEST_MODULE_LOCATION[397]=/updates/dkms +BUILT_MODULE_NAME[398]=saa6752hs +BUILT_MODULE_LOCATION[398]=./v4l +DEST_MODULE_LOCATION[398]=/updates/dkms +BUILT_MODULE_NAME[399]=ene_ir +BUILT_MODULE_LOCATION[399]=./v4l +DEST_MODULE_LOCATION[399]=/updates/dkms +BUILT_MODULE_NAME[400]=dvb-usb-cinergyT2 +BUILT_MODULE_LOCATION[400]=./v4l +DEST_MODULE_LOCATION[400]=/updates/dkms +BUILT_MODULE_NAME[401]=si4713-i2c +BUILT_MODULE_LOCATION[401]=./v4l +DEST_MODULE_LOCATION[401]=/updates/dkms +BUILT_MODULE_NAME[402]=tda18212 +BUILT_MODULE_LOCATION[402]=./v4l +DEST_MODULE_LOCATION[402]=/updates/dkms +BUILT_MODULE_NAME[403]=gspca_kinect +BUILT_MODULE_LOCATION[403]=./v4l +DEST_MODULE_LOCATION[403]=/updates/dkms +BUILT_MODULE_NAME[404]=gspca_pac7302 +BUILT_MODULE_LOCATION[404]=./v4l +DEST_MODULE_LOCATION[404]=/updates/dkms +BUILT_MODULE_NAME[405]=ks0127 +BUILT_MODULE_LOCATION[405]=./v4l +DEST_MODULE_LOCATION[405]=/updates/dkms +BUILT_MODULE_NAME[406]=rc-encore-enltv2 +BUILT_MODULE_LOCATION[406]=./v4l +DEST_MODULE_LOCATION[406]=/updates/dkms +BUILT_MODULE_NAME[407]=gspca_m5602 +BUILT_MODULE_LOCATION[407]=./v4l +DEST_MODULE_LOCATION[407]=/updates/dkms +BUILT_MODULE_NAME[408]=cx88-alsa +BUILT_MODULE_LOCATION[408]=./v4l +DEST_MODULE_LOCATION[408]=/updates/dkms +BUILT_MODULE_NAME[409]=dib7000m +BUILT_MODULE_LOCATION[409]=./v4l +DEST_MODULE_LOCATION[409]=/updates/dkms +BUILT_MODULE_NAME[410]=et61x251 +BUILT_MODULE_LOCATION[410]=./v4l +DEST_MODULE_LOCATION[410]=/updates/dkms +BUILT_MODULE_NAME[411]=rc-terratec-slim +BUILT_MODULE_LOCATION[411]=./v4l +DEST_MODULE_LOCATION[411]=/updates/dkms +BUILT_MODULE_NAME[412]=rc-imon-mce +BUILT_MODULE_LOCATION[412]=./v4l +DEST_MODULE_LOCATION[412]=/updates/dkms +BUILT_MODULE_NAME[413]=rc-purpletv +BUILT_MODULE_LOCATION[413]=./v4l +DEST_MODULE_LOCATION[413]=/updates/dkms +BUILT_MODULE_NAME[414]=cx8802 +BUILT_MODULE_LOCATION[414]=./v4l +DEST_MODULE_LOCATION[414]=/updates/dkms +BUILT_MODULE_NAME[415]=rc-terratec-cinergy-c-pci +BUILT_MODULE_LOCATION[415]=./v4l +DEST_MODULE_LOCATION[415]=/updates/dkms +BUILT_MODULE_NAME[416]=rc-nebula +BUILT_MODULE_LOCATION[416]=./v4l +DEST_MODULE_LOCATION[416]=/updates/dkms +BUILT_MODULE_NAME[417]=budget-ci +BUILT_MODULE_LOCATION[417]=./v4l +DEST_MODULE_LOCATION[417]=/updates/dkms +BUILT_MODULE_NAME[418]=saa7110 +BUILT_MODULE_LOCATION[418]=./v4l +DEST_MODULE_LOCATION[418]=/updates/dkms +BUILT_MODULE_NAME[419]=rc-twinhan1027 +BUILT_MODULE_LOCATION[419]=./v4l +DEST_MODULE_LOCATION[419]=/updates/dkms +BUILT_MODULE_NAME[420]=gspca_cpia1 +BUILT_MODULE_LOCATION[420]=./v4l +DEST_MODULE_LOCATION[420]=/updates/dkms +BUILT_MODULE_NAME[421]=atbm8830 +BUILT_MODULE_LOCATION[421]=./v4l +DEST_MODULE_LOCATION[421]=/updates/dkms +BUILT_MODULE_NAME[422]=tlv320aic23b +BUILT_MODULE_LOCATION[422]=./v4l +DEST_MODULE_LOCATION[422]=/updates/dkms +BUILT_MODULE_NAME[423]=dvb-usb-lmedm04 +BUILT_MODULE_LOCATION[423]=./v4l +DEST_MODULE_LOCATION[423]=/updates/dkms +BUILT_MODULE_NAME[424]=or51132 +BUILT_MODULE_LOCATION[424]=./v4l +DEST_MODULE_LOCATION[424]=/updates/dkms +BUILT_MODULE_NAME[425]=cs5345 +BUILT_MODULE_LOCATION[425]=./v4l +DEST_MODULE_LOCATION[425]=/updates/dkms +BUILT_MODULE_NAME[426]=dvb-usb-ec168 +BUILT_MODULE_LOCATION[426]=./v4l +DEST_MODULE_LOCATION[426]=/updates/dkms +BUILT_MODULE_NAME[427]=rc-pixelview-mk12 +BUILT_MODULE_LOCATION[427]=./v4l +DEST_MODULE_LOCATION[427]=/updates/dkms +BUILT_MODULE_NAME[428]=gspca_spca500 +BUILT_MODULE_LOCATION[428]=./v4l +DEST_MODULE_LOCATION[428]=/updates/dkms +BUILT_MODULE_NAME[429]=rc-powercolor-real-angel +BUILT_MODULE_LOCATION[429]=./v4l +DEST_MODULE_LOCATION[429]=/updates/dkms +BUILT_MODULE_NAME[430]=mt9v011 +BUILT_MODULE_LOCATION[430]=./v4l +DEST_MODULE_LOCATION[430]=/updates/dkms +BUILT_MODULE_NAME[431]=ttusbdecfe +BUILT_MODULE_LOCATION[431]=./v4l +DEST_MODULE_LOCATION[431]=/updates/dkms +BUILT_MODULE_NAME[432]=rc-alink-dtu-m +BUILT_MODULE_LOCATION[432]=./v4l +DEST_MODULE_LOCATION[432]=/updates/dkms +BUILT_MODULE_NAME[433]=saa7134-dvb +BUILT_MODULE_LOCATION[433]=./v4l +DEST_MODULE_LOCATION[433]=/updates/dkms diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/INSTALL v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/INSTALL --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/INSTALL 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/INSTALL 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,140 @@ +Mauro Carvalho Chehab 2006 Apr 26 + +V4L/DVB building procedures are based at the use of Makefile rules. +Those rules are close to the ones at Linux Kernel, to allow an easier +usage. + +======================================================================= +Quick building procedure is: + make all +====================================================================== + +For those who may want more than just build all stuff there are some +other interesting parameters to make: + +====================== +Normal building rules: +all - build all modules + +clean - Cleans compiled files from the tree, + but keeping the latest + used configuration and kernel version + +distclean - Cleans compiled files from the tree, + latest used configuration and kernel + version. + +default - Continues building the latest module selection + This is the behavior when just typed: + make + +install - Installs all modules at kernel's default dir + for V4L/DVB. Requires root access. + +rminstall - cleans previous installations of V4L/DVB modules + +sound-install - installs the sound modules related to V4L/DVB + tree. + +====================== +Firmware rules: + +firmware - Create the firmware files that are enclosed at the + tree. + Notice: Only a very few firmwares are currently here + +firmware_install- Install firmware files under /lib/firmware + +======================= +Module selection rules: +(Those may require write access to kernel tree) + +allmodconfig - Called by make all. Selects all modules that are known + to compile against the kernel version used. + +stagingconfig - Select all modules, plus all staging modules. The + staging drivers are there because they may have + bad userspace API's, serious bugs and/or not fill + into Kernel required level of quality. So, be + careful with those drivers. + +xconfig - Generate a xconfig menu. Requires full + kernel source, since it depends on kernel's + qconf stript; + +gconfig - Generate a qt menu. Requires full + kernel source, since it depends on kernel's + gconf stript; + +config - Generate a text-mode menu. Requires full + kernel source, since it depends on kernel's + conf stript; + +menuconfig - Generate a ncurses menu. Requires full + kernel source, since it depends on kernel's + mconf and lxconfig stripts; + +release - Allows changing kernel version. + Typical usage is: + make release VER=2.6.12-18mdk + (to force compiling to 2.6.12-18mdk) + (This will work only if + /lib/modules/2.6.12-18mdk/build/ + points to that kernel version) + Or + make release DIR=~/linux-git + (to force using kernel at a specific dir) + To use current kernel version instead: + make release + +====================== +Module handling rules: +(require root access) + +insmod - inserts all modules from V4L/DVB tree + +rmmod - removes all modules from V4L/DVB tree + +reload - removes then reinserts all modules + +=================== +Tree merging rules: + +ivtv - enable merged ivtv build, using the latest ivtv sources + from ivtvdriver.org (requires subversion) + +cx88-ivtv - enable cx88-blackbird ivtv API emulation + +ivtv-update - update ivtv sources from ivtvdriver.org + +========================================== +Patch preparation and tree handling rules: +(used by developers) + +kernel-links - Generate links to V4L/DVB at kernel tree. + Requires write access to kernel tree. + +cardlist - Updates Documentation/video4linux/CARDLIST.* + +update - updates the tree from master repository + +commit - commits the change, asking for a commit msg + +push - sends outgoing stuff to master repository + +checkemacs - checks codingstyle and reports to emacs + using "make checkemacs" at emacs compile menu, + will report the lines with errors inside emacs. + +checkpatch - checks codingstyle and reports using the same + format as c. This way, c error parsers will + handle it. + +checkterse - checks codingstyle and reports using terse + syntax, used on several compilaton tools. + +mismatch - checks for linker section mismatch. In other words, + check if some driver has functions not properly + declared with __init/__exit, and similar tags. + It will also be more pedantic by dealing with + compilation warnings as if they are errors. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,9 @@ +config VIDEO_SAA7146 + tristate + depends on I2C && PCI + +config VIDEO_SAA7146_VV + tristate + depends on VIDEO_V4L2 + select VIDEOBUF_DMA_SG + select VIDEO_SAA7146 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,6 @@ +saa7146-objs := saa7146_i2c.o saa7146_core.o +saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o + +obj-y += tuners/ +obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o +obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_core.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,595 @@ +/* + saa7146.o - driver for generic saa7146-based hardware + + Copyright (C) 1998-2003 Michael Hunold + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +LIST_HEAD(saa7146_devices); +DEFINE_MUTEX(saa7146_devices_lock); + +static int saa7146_num; + +unsigned int saa7146_debug; + +module_param(saa7146_debug, uint, 0644); +MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)"); + +#if 0 +static void dump_registers(struct saa7146_dev* dev) +{ + int i = 0; + + INFO((" @ %li jiffies:\n",jiffies)); + for(i = 0; i <= 0x148; i+=4) { + printk("0x%03x: 0x%08x\n",i,saa7146_read(dev,i)); + } +} +#endif + +/**************************************************************************** + * gpio and debi helper functions + ****************************************************************************/ + +void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data) +{ + u32 value = 0; + + BUG_ON(port > 3); + + value = saa7146_read(dev, GPIO_CTRL); + value &= ~(0xff << (8*port)); + value |= (data << (8*port)); + saa7146_write(dev, GPIO_CTRL, value); +} + +/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */ +static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev, + unsigned long us1, unsigned long us2) +{ + unsigned long timeout; + int err; + + /* wait for registers to be programmed */ + timeout = jiffies + usecs_to_jiffies(us1); + while (1) { + err = time_after(jiffies, timeout); + if (saa7146_read(dev, MC2) & 2) + break; + if (err) { + printk(KERN_ERR "%s: %s timed out while waiting for " + "registers getting programmed\n", + dev->name, __func__); + return -ETIMEDOUT; + } + msleep(1); + } + + /* wait for transfer to complete */ + timeout = jiffies + usecs_to_jiffies(us2); + while (1) { + err = time_after(jiffies, timeout); + if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) + break; + saa7146_read(dev, MC2); + if (err) { + DEB_S(("%s: %s timed out while waiting for transfer " + "completion\n", dev->name, __func__)); + return -ETIMEDOUT; + } + msleep(1); + } + + return 0; +} + +static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev, + unsigned long us1, unsigned long us2) +{ + unsigned long loops; + + /* wait for registers to be programmed */ + loops = us1; + while (1) { + if (saa7146_read(dev, MC2) & 2) + break; + if (!loops--) { + printk(KERN_ERR "%s: %s timed out while waiting for " + "registers getting programmed\n", + dev->name, __func__); + return -ETIMEDOUT; + } + udelay(1); + } + + /* wait for transfer to complete */ + loops = us2 / 5; + while (1) { + if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) + break; + saa7146_read(dev, MC2); + if (!loops--) { + DEB_S(("%s: %s timed out while waiting for transfer " + "completion\n", dev->name, __func__)); + return -ETIMEDOUT; + } + udelay(5); + } + + return 0; +} + +int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) +{ + if (nobusyloop) + return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000); + else + return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000); +} + +/**************************************************************************** + * general helper functions + ****************************************************************************/ + +/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c + make sure virt has been allocated with vmalloc_32(), otherwise the BUG() + may be triggered on highmem machines */ +static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) +{ + struct scatterlist *sglist; + struct page *pg; + int i; + + sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); + if (NULL == sglist) + return NULL; + sg_init_table(sglist, nr_pages); + for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { + pg = vmalloc_to_page(virt); + if (NULL == pg) + goto err; + BUG_ON(PageHighMem(pg)); + sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); + } + return sglist; + + err: + kfree(sglist); + return NULL; +} + +/********************************************************************************/ +/* common page table functions */ + +void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) +{ + int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; + void *mem = vmalloc_32(length); + int slen = 0; + + if (NULL == mem) + goto err_null; + + if (!(pt->slist = vmalloc_to_sg(mem, pages))) + goto err_free_mem; + + if (saa7146_pgtable_alloc(pci, pt)) + goto err_free_slist; + + pt->nents = pages; + slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE); + if (0 == slen) + goto err_free_pgtable; + + if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) + goto err_unmap_sg; + + return mem; + +err_unmap_sg: + pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); +err_free_pgtable: + saa7146_pgtable_free(pci, pt); +err_free_slist: + kfree(pt->slist); + pt->slist = NULL; +err_free_mem: + vfree(mem); +err_null: + return NULL; +} + +void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt) +{ + pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); + saa7146_pgtable_free(pci, pt); + kfree(pt->slist); + pt->slist = NULL; + vfree(mem); +} + +void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) +{ + if (NULL == pt->cpu) + return; + pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); + pt->cpu = NULL; +} + +int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) +{ + __le32 *cpu; + dma_addr_t dma_addr = 0; + + cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr); + if (NULL == cpu) { + return -ENOMEM; + } + pt->size = PAGE_SIZE; + pt->cpu = cpu; + pt->dma = dma_addr; + + return 0; +} + +int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, + struct scatterlist *list, int sglen ) +{ + __le32 *ptr, fill; + int nr_pages = 0; + int i,p; + + BUG_ON(0 == sglen); + BUG_ON(list->offset > PAGE_SIZE); + + /* if we have a user buffer, the first page may not be + aligned to a page boundary. */ + pt->offset = list->offset; + + ptr = pt->cpu; + for (i = 0; i < sglen; i++, list++) { +/* + printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset); +*/ + for (p = 0; p * 4096 < list->length; p++, ptr++) { + *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096); + nr_pages++; + } + } + + + /* safety; fill the page table up with the last valid page */ + fill = *(ptr-1); + for(i=nr_pages;i<1024;i++) { + *ptr++ = fill; + } + +/* + ptr = pt->cpu; + printk("offset: %d\n",pt->offset); + for(i=0;i<5;i++) { + printk("ptr1 %d: 0x%08x\n",i,ptr[i]); + } +*/ + return 0; +} + +/********************************************************************************/ +/* interrupt handler */ +static irqreturn_t interrupt_hw(int irq, void *dev_id) +{ + struct saa7146_dev *dev = dev_id; + u32 isr; + u32 ack_isr; + + /* read out the interrupt status register */ + ack_isr = isr = saa7146_read(dev, ISR); + + /* is this our interrupt? */ + if ( 0 == isr ) { + /* nope, some other device */ + return IRQ_NONE; + } + + if (dev->ext) { + if (dev->ext->irq_mask & isr) { + if (dev->ext->irq_func) + dev->ext->irq_func(dev, &isr); + isr &= ~dev->ext->irq_mask; + } + } + if (0 != (isr & (MASK_27))) { + DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); + if (dev->vv_data && dev->vv_callback) + dev->vv_callback(dev,isr); + isr &= ~MASK_27; + } + if (0 != (isr & (MASK_28))) { + if (dev->vv_data && dev->vv_callback) + dev->vv_callback(dev,isr); + isr &= ~MASK_28; + } + if (0 != (isr & (MASK_16|MASK_17))) { + SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); + /* only wake up if we expect something */ + if (0 != dev->i2c_op) { + dev->i2c_op = 0; + wake_up(&dev->i2c_wq); + } else { + u32 psr = saa7146_read(dev, PSR); + u32 ssr = saa7146_read(dev, SSR); + printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", + dev->name, isr, psr, ssr); + } + isr &= ~(MASK_16|MASK_17); + } + if( 0 != isr ) { + ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr)); + ERR(("disabling interrupt source(s)!\n")); + SAA7146_IER_DISABLE(dev,isr); + } + saa7146_write(dev, ISR, ack_isr); + return IRQ_HANDLED; +} + +/*********************************************************************************/ +/* configuration-functions */ + +static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent) +{ + struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data; + struct saa7146_extension *ext = pci_ext->ext; + struct saa7146_dev *dev; + int err = -ENOMEM; + + /* clear out mem for sure */ + dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL); + if (!dev) { + ERR(("out of memory.\n")); + goto out; + } + + DEB_EE(("pci:%p\n",pci)); + + err = pci_enable_device(pci); + if (err < 0) { + ERR(("pci_enable_device() failed.\n")); + goto err_free; + } + + /* enable bus-mastering */ + pci_set_master(pci); + + dev->pci = pci; + + /* get chip-revision; this is needed to enable bug-fixes */ + dev->revision = pci->revision; + + /* remap the memory from virtual to physical address */ + + err = pci_request_region(pci, 0, "saa7146"); + if (err < 0) + goto err_disable; + + dev->mem = ioremap(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + if (!dev->mem) { + ERR(("ioremap() failed.\n")); + err = -ENODEV; + goto err_release; + } + + /* we don't do a master reset here anymore, it screws up + some boards that don't have an i2c-eeprom for configuration + values */ +/* + saa7146_write(dev, MC1, MASK_31); +*/ + + /* disable all irqs */ + saa7146_write(dev, IER, 0); + + /* shut down all dma transfers and rps tasks */ + saa7146_write(dev, MC1, 0x30ff0000); + + /* clear out any rps-signals pending */ + saa7146_write(dev, MC2, 0xf8000000); + + /* request an interrupt for the saa7146 */ + err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED, + dev->name, dev); + if (err < 0) { + ERR(("request_irq() failed.\n")); + goto err_unmap; + } + + err = -ENOMEM; + + /* get memory for various stuff */ + dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, + &dev->d_rps0.dma_handle); + if (!dev->d_rps0.cpu_addr) + goto err_free_irq; + memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM); + + dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, + &dev->d_rps1.dma_handle); + if (!dev->d_rps1.cpu_addr) + goto err_free_rps0; + memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM); + + dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, + &dev->d_i2c.dma_handle); + if (!dev->d_i2c.cpu_addr) + goto err_free_rps1; + memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM); + + /* the rest + print status message */ + + /* create a nice device name */ + sprintf(dev->name, "saa7146 (%d)", saa7146_num); + + INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device)); + dev->ext = ext; + + mutex_init(&dev->v4l2_lock); + spin_lock_init(&dev->int_slock); + spin_lock_init(&dev->slock); + + mutex_init(&dev->i2c_lock); + + dev->module = THIS_MODULE; + init_waitqueue_head(&dev->i2c_wq); + + /* set some sane pci arbitrition values */ + saa7146_write(dev, PCI_BT_V1, 0x1c00101f); + + /* TODO: use the status code of the callback */ + + err = -ENODEV; + + if (ext->probe && ext->probe(dev)) { + DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); + goto err_free_i2c; + } + + if (ext->attach(dev, pci_ext)) { + DEB_D(("ext->attach() failed for %p. skipping device.\n",dev)); + goto err_free_i2c; + } + /* V4L extensions will set the pci drvdata to the v4l2_device in the + attach() above. So for those cards that do not use V4L we have to + set it explicitly. */ + pci_set_drvdata(pci, &dev->v4l2_dev); + + INIT_LIST_HEAD(&dev->item); + list_add_tail(&dev->item,&saa7146_devices); + saa7146_num++; + + err = 0; +out: + return err; + +err_free_i2c: + pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, + dev->d_i2c.dma_handle); +err_free_rps1: + pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, + dev->d_rps1.dma_handle); +err_free_rps0: + pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, + dev->d_rps0.dma_handle); +err_free_irq: + free_irq(pci->irq, (void *)dev); +err_unmap: + iounmap(dev->mem); +err_release: + pci_release_region(pci, 0); +err_disable: + pci_disable_device(pci); +err_free: + kfree(dev); + goto out; +} + +static void saa7146_remove_one(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); + struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev); + struct { + void *addr; + dma_addr_t dma; + } dev_map[] = { + { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle }, + { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle }, + { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle }, + { NULL, 0 } + }, *p; + + DEB_EE(("dev:%p\n",dev)); + + dev->ext->detach(dev); + /* Zero the PCI drvdata after use. */ + pci_set_drvdata(pdev, NULL); + + /* shut down all video dma transfers */ + saa7146_write(dev, MC1, 0x00ff0000); + + /* disable all irqs, release irq-routine */ + saa7146_write(dev, IER, 0); + + free_irq(pdev->irq, dev); + + for (p = dev_map; p->addr; p++) + pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma); + + iounmap(dev->mem); + pci_release_region(pdev, 0); + list_del(&dev->item); + pci_disable_device(pdev); + kfree(dev); + + saa7146_num--; +} + +/*********************************************************************************/ +/* extension handling functions */ + +int saa7146_register_extension(struct saa7146_extension* ext) +{ + DEB_EE(("ext:%p\n",ext)); + + ext->driver.name = ext->name; + ext->driver.id_table = ext->pci_tbl; + ext->driver.probe = saa7146_init_one; + ext->driver.remove = saa7146_remove_one; + + printk("saa7146: register extension '%s'.\n",ext->name); + return pci_register_driver(&ext->driver); +} + +int saa7146_unregister_extension(struct saa7146_extension* ext) +{ + DEB_EE(("ext:%p\n",ext)); + printk("saa7146: unregister extension '%s'.\n",ext->name); + pci_unregister_driver(&ext->driver); + return 0; +} + +EXPORT_SYMBOL_GPL(saa7146_register_extension); +EXPORT_SYMBOL_GPL(saa7146_unregister_extension); + +/* misc functions used by extension modules */ +EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc); +EXPORT_SYMBOL_GPL(saa7146_pgtable_free); +EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single); +EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable); +EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable); +EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); + +EXPORT_SYMBOL_GPL(saa7146_setgpio); + +EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); + +EXPORT_SYMBOL_GPL(saa7146_debug); +EXPORT_SYMBOL_GPL(saa7146_devices); +EXPORT_SYMBOL_GPL(saa7146_devices_lock); + +MODULE_AUTHOR("Michael Hunold "); +MODULE_DESCRIPTION("driver for generic saa7146-based hardware"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_fops.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_fops.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_fops.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_fops.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,551 @@ +#include + +/****************************************************************************/ +/* resource management functions, shamelessly stolen from saa7134 driver */ + +int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + + if (fh->resources & bit) { + DEB_D(("already allocated! want: 0x%02x, cur:0x%02x\n",bit,vv->resources)); + /* have it already allocated */ + return 1; + } + + /* is it free? */ + if (vv->resources & bit) { + DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit)); + /* no, someone else uses it */ + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + vv->resources |= bit; + DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources)); + return 1; +} + +void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + + BUG_ON((fh->resources & bits) != bits); + + fh->resources &= ~bits; + vv->resources &= ~bits; + DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources)); +} + + +/********************************************************************************/ +/* common dma functions */ + +void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, + struct saa7146_buf *buf) +{ + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + DEB_EE(("dev:%p, buf:%p\n",dev,buf)); + + BUG_ON(in_interrupt()); + + videobuf_waiton(q, &buf->vb, 0, 0); + videobuf_dma_unmap(q->dev, dma); + videobuf_dma_free(dma); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + + +/********************************************************************************/ +/* common buffer functions */ + +int saa7146_buffer_queue(struct saa7146_dev *dev, + struct saa7146_dmaqueue *q, + struct saa7146_buf *buf) +{ + assert_spin_locked(&dev->slock); + DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf)); + + BUG_ON(!q); + + if (NULL == q->curr) { + q->curr = buf; + DEB_D(("immediately activating buffer %p\n", buf)); + buf->activate(dev,buf,NULL); + } else { + list_add_tail(&buf->vb.queue,&q->queue); + buf->vb.state = VIDEOBUF_QUEUED; + DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); + } + return 0; +} + +void saa7146_buffer_finish(struct saa7146_dev *dev, + struct saa7146_dmaqueue *q, + int state) +{ + assert_spin_locked(&dev->slock); + DEB_EE(("dev:%p, dmaq:%p, state:%d\n", dev, q, state)); + DEB_EE(("q->curr:%p\n",q->curr)); + + BUG_ON(!q->curr); + + /* finish current buffer */ + if (NULL == q->curr) { + DEB_D(("aiii. no current buffer\n")); + return; + } + + q->curr->vb.state = state; + do_gettimeofday(&q->curr->vb.ts); + wake_up(&q->curr->vb.done); + + q->curr = NULL; +} + +void saa7146_buffer_next(struct saa7146_dev *dev, + struct saa7146_dmaqueue *q, int vbi) +{ + struct saa7146_buf *buf,*next = NULL; + + BUG_ON(!q); + + DEB_INT(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi)); + + assert_spin_locked(&dev->slock); + if (!list_empty(&q->queue)) { + /* activate next one from queue */ + buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue); + list_del(&buf->vb.queue); + if (!list_empty(&q->queue)) + next = list_entry(q->queue.next,struct saa7146_buf, vb.queue); + q->curr = buf; + DEB_INT(("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev,q->queue.next)); + buf->activate(dev,buf,next); + } else { + DEB_INT(("no next buffer. stopping.\n")); + if( 0 != vbi ) { + /* turn off video-dma3 */ + saa7146_write(dev,MC1, MASK_20); + } else { + /* nothing to do -- just prevent next video-dma1 transfer + by lowering the protection address */ + + // fixme: fix this for vflip != 0 + + saa7146_write(dev, PROT_ADDR1, 0); + saa7146_write(dev, MC2, (MASK_02|MASK_18)); + + /* write the address of the rps-program */ + saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle); + /* turn on rps */ + saa7146_write(dev, MC1, (MASK_12 | MASK_28)); + +/* + printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); + printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); + printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); + printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); + printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); + printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); +*/ + } + del_timer(&q->timeout); + } +} + +void saa7146_buffer_timeout(unsigned long data) +{ + struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data; + struct saa7146_dev *dev = q->dev; + unsigned long flags; + + DEB_EE(("dev:%p, dmaq:%p\n", dev, q)); + + spin_lock_irqsave(&dev->slock,flags); + if (q->curr) { + DEB_D(("timeout on %p\n", q->curr)); + saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); + } + + /* we don't restart the transfer here like other drivers do. when + a streaming capture is disabled, the timeout function will be + called for the current buffer. if we activate the next buffer now, + we mess up our capture logic. if a timeout occurs on another buffer, + then something is seriously broken before, so no need to buffer the + next capture IMHO... */ +/* + saa7146_buffer_next(dev,q); +*/ + spin_unlock_irqrestore(&dev->slock,flags); +} + +/********************************************************************************/ +/* file operations */ + +static int fops_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct saa7146_dev *dev = video_drvdata(file); + struct saa7146_fh *fh = NULL; + int result = 0; + + enum v4l2_buf_type type; + + DEB_EE(("file:%p, dev:%s\n", file, video_device_node_name(vdev))); + + if (mutex_lock_interruptible(&saa7146_devices_lock)) + return -ERESTARTSYS; + + DEB_D(("using: %p\n",dev)); + + type = vdev->vfl_type == VFL_TYPE_GRABBER + ? V4L2_BUF_TYPE_VIDEO_CAPTURE + : V4L2_BUF_TYPE_VBI_CAPTURE; + + /* check if an extension is registered */ + if( NULL == dev->ext ) { + DEB_S(("no extension registered for this device.\n")); + result = -ENODEV; + goto out; + } + + /* allocate per open data */ + fh = kzalloc(sizeof(*fh),GFP_KERNEL); + if (NULL == fh) { + DEB_S(("cannot allocate memory for per open data.\n")); + result = -ENOMEM; + goto out; + } + + file->private_data = fh; + fh->dev = dev; + fh->type = type; + + if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + DEB_S(("initializing vbi...\n")); + if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) + result = saa7146_vbi_uops.open(dev,file); + if (dev->ext_vv_data->vbi_fops.open) + dev->ext_vv_data->vbi_fops.open(file); + } else { + DEB_S(("initializing video...\n")); + result = saa7146_video_uops.open(dev,file); + } + + if (0 != result) { + goto out; + } + + if( 0 == try_module_get(dev->ext->module)) { + result = -EINVAL; + goto out; + } + + result = 0; +out: + if (fh && result != 0) { + kfree(fh); + file->private_data = NULL; + } + mutex_unlock(&saa7146_devices_lock); + return result; +} + +static int fops_release(struct file *file) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + + DEB_EE(("file:%p\n", file)); + + if (mutex_lock_interruptible(&saa7146_devices_lock)) + return -ERESTARTSYS; + + if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) + saa7146_vbi_uops.release(dev,file); + if (dev->ext_vv_data->vbi_fops.release) + dev->ext_vv_data->vbi_fops.release(file); + } else { + saa7146_video_uops.release(dev,file); + } + + module_put(dev->ext->module); + file->private_data = NULL; + kfree(fh); + + mutex_unlock(&saa7146_devices_lock); + + return 0; +} + +static int fops_mmap(struct file *file, struct vm_area_struct * vma) +{ + struct saa7146_fh *fh = file->private_data; + struct videobuf_queue *q; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",file, vma)); + q = &fh->video_q; + break; + } + case V4L2_BUF_TYPE_VBI_CAPTURE: { + DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",file, vma)); + q = &fh->vbi_q; + break; + } + default: + BUG(); + return 0; + } + + return videobuf_mmap_mapper(q,vma); +} + +static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) +{ + struct saa7146_fh *fh = file->private_data; + struct videobuf_buffer *buf = NULL; + struct videobuf_queue *q; + + DEB_EE(("file:%p, poll:%p\n",file, wait)); + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if( 0 == fh->vbi_q.streaming ) + return videobuf_poll_stream(file, &fh->vbi_q, wait); + q = &fh->vbi_q; + } else { + DEB_D(("using video queue.\n")); + q = &fh->video_q; + } + + if (!list_empty(&q->stream)) + buf = list_entry(q->stream.next, struct videobuf_buffer, stream); + + if (!buf) { + DEB_D(("buf == NULL!\n")); + return POLLERR; + } + + poll_wait(file, &buf->done, wait); + if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { + DEB_D(("poll succeeded!\n")); + return POLLIN|POLLRDNORM; + } + + DEB_D(("nothing to poll for, buf->state:%d\n",buf->state)); + return 0; +} + +static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +{ + struct saa7146_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { +// DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", file, data, (unsigned long)count)); + return saa7146_video_uops.read(file,data,count,ppos); + } + case V4L2_BUF_TYPE_VBI_CAPTURE: { +// DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count)); + if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) + return saa7146_vbi_uops.read(file,data,count,ppos); + else + return -EINVAL; + } + break; + default: + BUG(); + return 0; + } +} + +static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) +{ + struct saa7146_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return -EINVAL; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (fh->dev->ext_vv_data->vbi_fops.write) + return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos); + else + return -EINVAL; + default: + BUG(); + return -EINVAL; + } +} + +static const struct v4l2_file_operations video_fops = +{ + .owner = THIS_MODULE, + .open = fops_open, + .release = fops_release, + .read = fops_read, + .write = fops_write, + .poll = fops_poll, + .mmap = fops_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static void vv_callback(struct saa7146_dev *dev, unsigned long status) +{ + u32 isr = status; + + DEB_INT(("dev:%p, isr:0x%08x\n",dev,(u32)status)); + + if (0 != (isr & (MASK_27))) { + DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); + saa7146_video_uops.irq_done(dev,isr); + } + + if (0 != (isr & (MASK_28))) { + u32 mc2 = saa7146_read(dev, MC2); + if( 0 != (mc2 & MASK_15)) { + DEB_INT(("irq: RPS1 vbi workaround (0x%08x).\n",isr)); + wake_up(&dev->vv_data->vbi_wq); + saa7146_write(dev,MC2, MASK_31); + return; + } + DEB_INT(("irq: RPS1 (0x%08x).\n",isr)); + saa7146_vbi_uops.irq_done(dev,isr); + } +} + +int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) +{ + struct saa7146_vv *vv; + int err; + + err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev); + if (err) + return err; + + vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL); + if (vv == NULL) { + ERR(("out of memory. aborting.\n")); + return -ENOMEM; + } + ext_vv->ops = saa7146_video_ioctl_ops; + ext_vv->core_ops = &saa7146_video_ioctl_ops; + + DEB_EE(("dev:%p\n",dev)); + + /* set default values for video parts of the saa7146 */ + saa7146_write(dev, BCS_CTRL, 0x80400040); + + /* enable video-port pins */ + saa7146_write(dev, MC1, (MASK_10 | MASK_26)); + + /* save per-device extension data (one extension can + handle different devices that might need different + configuration data) */ + dev->ext_vv_data = ext_vv; + + vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle); + if( NULL == vv->d_clipping.cpu_addr ) { + ERR(("out of memory. aborting.\n")); + kfree(vv); + return -1; + } + memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM); + + saa7146_video_uops.init(dev,vv); + if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) + saa7146_vbi_uops.init(dev,vv); + + dev->vv_data = vv; + dev->vv_callback = &vv_callback; + + return 0; +} +EXPORT_SYMBOL_GPL(saa7146_vv_init); + +int saa7146_vv_release(struct saa7146_dev* dev) +{ + struct saa7146_vv *vv = dev->vv_data; + + DEB_EE(("dev:%p\n",dev)); + + v4l2_device_unregister(&dev->v4l2_dev); + pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle); + kfree(vv); + dev->vv_data = NULL; + dev->vv_callback = NULL; + + return 0; +} +EXPORT_SYMBOL_GPL(saa7146_vv_release); + +int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, + char *name, int type) +{ + struct video_device *vfd; + int err; + int i; + + DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type)); + + // released by vfd->release + vfd = video_device_alloc(); + if (vfd == NULL) + return -ENOMEM; + + vfd->fops = &video_fops; + vfd->ioctl_ops = &dev->ext_vv_data->ops; + vfd->release = video_device_release; + vfd->lock = &dev->v4l2_lock; + vfd->tvnorms = 0; + for (i = 0; i < dev->ext_vv_data->num_stds; i++) + vfd->tvnorms |= dev->ext_vv_data->stds[i].id; + strlcpy(vfd->name, name, sizeof(vfd->name)); + video_set_drvdata(vfd, dev); + + err = video_register_device(vfd, type, -1); + if (err < 0) { + ERR(("cannot register v4l2 device. skipping.\n")); + video_device_release(vfd); + return err; + } + + INFO(("%s: registered device %s [v4l2]\n", + dev->name, video_device_node_name(vfd))); + + *vid = vfd; + return 0; +} +EXPORT_SYMBOL_GPL(saa7146_register_device); + +int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) +{ + DEB_EE(("dev:%p\n",dev)); + + video_unregister_device(*vid); + *vid = NULL; + + return 0; +} +EXPORT_SYMBOL_GPL(saa7146_unregister_device); + +static int __init saa7146_vv_init_module(void) +{ + return 0; +} + + +static void __exit saa7146_vv_cleanup_module(void) +{ +} + +module_init(saa7146_vv_init_module); +module_exit(saa7146_vv_cleanup_module); + +MODULE_AUTHOR("Michael Hunold "); +MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_hlp.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_hlp.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_hlp.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_hlp.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1044 @@ +#include +#include + +static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format) +{ + /* clear out the necessary bits */ + *clip_format &= 0x0000ffff; + /* set these bits new */ + *clip_format |= (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16)); +} + +static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl) +{ + *hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28); + *hps_ctrl |= (source << 30) | (sync << 28); +} + +static void calculate_hxo_and_hyo(struct saa7146_vv *vv, u32* hps_h_scale, u32* hps_ctrl) +{ + int hyo = 0, hxo = 0; + + hyo = vv->standard->v_offset; + hxo = vv->standard->h_offset; + + *hps_h_scale &= ~(MASK_B0 | 0xf00); + *hps_h_scale |= (hxo << 0); + + *hps_ctrl &= ~(MASK_W0 | MASK_B2); + *hps_ctrl |= (hyo << 12); +} + +/* helper functions for the calculation of the horizontal- and vertical + scaling registers, clip-format-register etc ... + these functions take pointers to the (most-likely read-out + original-values) and manipulate them according to the requested + changes. +*/ + +/* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */ +static struct { + u16 hps_coeff; + u16 weight_sum; +} hps_h_coeff_tab [] = { + {0x00, 2}, {0x02, 4}, {0x00, 4}, {0x06, 8}, {0x02, 8}, + {0x08, 8}, {0x00, 8}, {0x1E, 16}, {0x0E, 8}, {0x26, 8}, + {0x06, 8}, {0x42, 8}, {0x02, 8}, {0x80, 8}, {0x00, 8}, + {0xFE, 16}, {0xFE, 8}, {0x7E, 8}, {0x7E, 8}, {0x3E, 8}, + {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, {0x0E, 8}, {0x0E, 8}, + {0x06, 8}, {0x06, 8}, {0x02, 8}, {0x02, 8}, {0x00, 8}, + {0x00, 8}, {0xFE, 16}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, + {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, + {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, + {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0x7E, 8}, + {0x7E, 8}, {0x3E, 8}, {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, + {0x0E, 8}, {0x0E, 8}, {0x06, 8}, {0x06, 8}, {0x02, 8}, + {0x02, 8}, {0x00, 8}, {0x00, 8}, {0xFE, 16} +}; + +/* table of attenuation values for horizontal scaling */ +static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0}; + +/* calculate horizontal scale registers */ +static int calculate_h_scale_registers(struct saa7146_dev *dev, + int in_x, int out_x, int flip_lr, + u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale) +{ + /* horizontal prescaler */ + u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0; + /* horizontal scaler */ + u32 xim = 0, xp = 0, xsci =0; + /* vertical scale & gain */ + u32 pfuv = 0; + + /* helper variables */ + u32 h_atten = 0, i = 0; + + if ( 0 == out_x ) { + return -EINVAL; + } + + /* mask out vanity-bit */ + *hps_ctrl &= ~MASK_29; + + /* calculate prescale-(xspc)-value: [n .. 1/2) : 1 + [1/2 .. 1/3) : 2 + [1/3 .. 1/4) : 3 + ... */ + if (in_x > out_x) { + xpsc = in_x / out_x; + } + else { + /* zooming */ + xpsc = 1; + } + + /* if flip_lr-bit is set, number of pixels after + horizontal prescaling must be < 384 */ + if ( 0 != flip_lr ) { + + /* set vanity bit */ + *hps_ctrl |= MASK_29; + + while (in_x / xpsc >= 384 ) + xpsc++; + } + /* if zooming is wanted, number of pixels after + horizontal prescaling must be < 768 */ + else { + while ( in_x / xpsc >= 768 ) + xpsc++; + } + + /* maximum prescale is 64 (p.69) */ + if ( xpsc > 64 ) + xpsc = 64; + + /* keep xacm clear*/ + xacm = 0; + + /* set horizontal filter parameters (CXY = CXUV) */ + cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff; + cxuv = cxy; + + /* calculate and set horizontal fine scale (xsci) */ + + /* bypass the horizontal scaler ? */ + if ( (in_x == out_x) && ( 1 == xpsc ) ) + xsci = 0x400; + else + xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc; + + /* set start phase for horizontal fine scale (xp) to 0 */ + xp = 0; + + /* set xim, if we bypass the horizontal scaler */ + if ( 0x400 == xsci ) + xim = 1; + else + xim = 0; + + /* if the prescaler is bypassed, enable horizontal + accumulation mode (xacm) and clear dcgx */ + if( 1 == xpsc ) { + xacm = 1; + dcgx = 0; + } else { + xacm = 0; + /* get best match in the table of attenuations + for horizontal scaling */ + h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum; + + for (i = 0; h_attenuation[i] != 0; i++) { + if (h_attenuation[i] >= h_atten) + break; + } + + dcgx = i; + } + + /* the horizontal scaling increment controls the UV filter + to reduce the bandwidth to improve the display quality, + so set it ... */ + if ( xsci == 0x400) + pfuv = 0x00; + else if ( xsci < 0x600) + pfuv = 0x01; + else if ( xsci < 0x680) + pfuv = 0x11; + else if ( xsci < 0x700) + pfuv = 0x22; + else + pfuv = 0x33; + + + *hps_v_gain &= MASK_W0|MASK_B2; + *hps_v_gain |= (pfuv << 24); + + *hps_h_scale &= ~(MASK_W1 | 0xf000); + *hps_h_scale |= (xim << 31) | (xp << 24) | (xsci << 12); + + *hps_h_prescale |= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0); + + return 0; +} + +static struct { + u16 hps_coeff; + u16 weight_sum; +} hps_v_coeff_tab [] = { + {0x0100, 2}, {0x0102, 4}, {0x0300, 4}, {0x0106, 8}, {0x0502, 8}, + {0x0708, 8}, {0x0F00, 8}, {0x011E, 16}, {0x110E, 16}, {0x1926, 16}, + {0x3906, 16}, {0x3D42, 16}, {0x7D02, 16}, {0x7F80, 16}, {0xFF00, 16}, + {0x01FE, 32}, {0x01FE, 32}, {0x817E, 32}, {0x817E, 32}, {0xC13E, 32}, + {0xC13E, 32}, {0xE11E, 32}, {0xE11E, 32}, {0xF10E, 32}, {0xF10E, 32}, + {0xF906, 32}, {0xF906, 32}, {0xFD02, 32}, {0xFD02, 32}, {0xFF00, 32}, + {0xFF00, 32}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, + {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, + {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, + {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x817E, 64}, + {0x817E, 64}, {0xC13E, 64}, {0xC13E, 64}, {0xE11E, 64}, {0xE11E, 64}, + {0xF10E, 64}, {0xF10E, 64}, {0xF906, 64}, {0xF906, 64}, {0xFD02, 64}, + {0xFD02, 64}, {0xFF00, 64}, {0xFF00, 64}, {0x01FE, 128} +}; + +/* table of attenuation values for vertical scaling */ +static u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0}; + +/* calculate vertical scale registers */ +static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field, + int in_y, int out_y, u32* hps_v_scale, u32* hps_v_gain) +{ + int lpi = 0; + + /* vertical scaling */ + u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0; + /* vertical scale & gain */ + u32 dcgy = 0, cya_cyb = 0; + + /* helper variables */ + u32 v_atten = 0, i = 0; + + /* error, if vertical zooming */ + if ( in_y < out_y ) { + return -EINVAL; + } + + /* linear phase interpolation may be used + if scaling is between 1 and 1/2 (both fields used) + or scaling is between 1/2 and 1/4 (if only one field is used) */ + + if (V4L2_FIELD_HAS_BOTH(field)) { + if( 2*out_y >= in_y) { + lpi = 1; + } + } else if (field == V4L2_FIELD_TOP + || field == V4L2_FIELD_ALTERNATE + || field == V4L2_FIELD_BOTTOM) { + if( 4*out_y >= in_y ) { + lpi = 1; + } + out_y *= 2; + } + if( 0 != lpi ) { + + yacm = 0; + yacl = 0; + cya_cyb = 0x00ff; + + /* calculate scaling increment */ + if ( in_y > out_y ) + ysci = ((1024 * in_y) / (out_y + 1)) - 1024; + else + ysci = 0; + + dcgy = 0; + + /* calculate ype and ypo */ + ype = ysci / 16; + ypo = ype + (ysci / 64); + + } else { + yacm = 1; + + /* calculate scaling increment */ + ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10; + + /* calculate ype and ypo */ + ypo = ype = ((ysci + 15) / 16); + + /* the sequence length interval (yacl) has to be set according + to the prescale value, e.g. [n .. 1/2) : 0 + [1/2 .. 1/3) : 1 + [1/3 .. 1/4) : 2 + ... */ + if ( ysci < 512) { + yacl = 0; + } else { + yacl = ( ysci / (1024 - ysci) ); + } + + /* get filter coefficients for cya, cyb from table hps_v_coeff_tab */ + cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff; + + /* get best match in the table of attenuations for vertical scaling */ + v_atten = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].weight_sum; + + for (i = 0; v_attenuation[i] != 0; i++) { + if (v_attenuation[i] >= v_atten) + break; + } + + dcgy = i; + } + + /* ypo and ype swapped in spec ? */ + *hps_v_scale |= (yacm << 31) | (ysci << 21) | (yacl << 15) | (ypo << 8 ) | (ype << 1); + + *hps_v_gain &= ~(MASK_W0|MASK_B2); + *hps_v_gain |= (dcgy << 16) | (cya_cyb << 0); + + return 0; +} + +/* simple bubble-sort algorithm with duplicate elimination */ +static int sort_and_eliminate(u32* values, int* count) +{ + int low = 0, high = 0, top = 0, temp = 0; + int cur = 0, next = 0; + + /* sanity checks */ + if( (0 > *count) || (NULL == values) ) { + return -EINVAL; + } + + /* bubble sort the first @count items of the array @values */ + for( top = *count; top > 0; top--) { + for( low = 0, high = 1; high < top; low++, high++) { + if( values[low] > values[high] ) { + temp = values[low]; + values[low] = values[high]; + values[high] = temp; + } + } + } + + /* remove duplicate items */ + for( cur = 0, next = 1; next < *count; next++) { + if( values[cur] != values[next]) + values[++cur] = values[next]; + } + + *count = cur + 1; + + return 0; +} + +static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct saa7146_fh *fh, + struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field) +{ + struct saa7146_vv *vv = dev->vv_data; + __le32 *clipping = vv->d_clipping.cpu_addr; + + int width = fh->ov.win.w.width; + int height = fh->ov.win.w.height; + int clipcount = fh->ov.nclips; + + u32 line_list[32]; + u32 pixel_list[32]; + int numdwords = 0; + + int i = 0, j = 0; + int cnt_line = 0, cnt_pixel = 0; + + int x[32], y[32], w[32], h[32]; + + /* clear out memory */ + memset(&line_list[0], 0x00, sizeof(u32)*32); + memset(&pixel_list[0], 0x00, sizeof(u32)*32); + memset(clipping, 0x00, SAA7146_CLIPPING_MEM); + + /* fill the line and pixel-lists */ + for(i = 0; i < clipcount; i++) { + int l = 0, r = 0, t = 0, b = 0; + + x[i] = fh->ov.clips[i].c.left; + y[i] = fh->ov.clips[i].c.top; + w[i] = fh->ov.clips[i].c.width; + h[i] = fh->ov.clips[i].c.height; + + if( w[i] < 0) { + x[i] += w[i]; w[i] = -w[i]; + } + if( h[i] < 0) { + y[i] += h[i]; h[i] = -h[i]; + } + if( x[i] < 0) { + w[i] += x[i]; x[i] = 0; + } + if( y[i] < 0) { + h[i] += y[i]; y[i] = 0; + } + if( 0 != vv->vflip ) { + y[i] = height - y[i] - h[i]; + } + + l = x[i]; + r = x[i]+w[i]; + t = y[i]; + b = y[i]+h[i]; + + /* insert left/right coordinates */ + pixel_list[ 2*i ] = min_t(int, l, width); + pixel_list[(2*i)+1] = min_t(int, r, width); + /* insert top/bottom coordinates */ + line_list[ 2*i ] = min_t(int, t, height); + line_list[(2*i)+1] = min_t(int, b, height); + } + + /* sort and eliminate lists */ + cnt_line = cnt_pixel = 2*clipcount; + sort_and_eliminate( &pixel_list[0], &cnt_pixel ); + sort_and_eliminate( &line_list[0], &cnt_line ); + + /* calculate the number of used u32s */ + numdwords = max_t(int, (cnt_line+1), (cnt_pixel+1))*2; + numdwords = max_t(int, 4, numdwords); + numdwords = min_t(int, 64, numdwords); + + /* fill up cliptable */ + for(i = 0; i < cnt_pixel; i++) { + clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16); + } + for(i = 0; i < cnt_line; i++) { + clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16); + } + + /* fill up cliptable with the display infos */ + for(j = 0; j < clipcount; j++) { + + for(i = 0; i < cnt_pixel; i++) { + + if( x[j] < 0) + x[j] = 0; + + if( pixel_list[i] < (x[j] + w[j])) { + + if ( pixel_list[i] >= x[j] ) { + clipping[2*i] |= cpu_to_le32(1 << j); + } + } + } + for(i = 0; i < cnt_line; i++) { + + if( y[j] < 0) + y[j] = 0; + + if( line_list[i] < (y[j] + h[j]) ) { + + if( line_list[i] >= y[j] ) { + clipping[(2*i)+1] |= cpu_to_le32(1 << j); + } + } + } + } + + /* adjust arbitration control register */ + *arbtr_ctrl &= 0xffff00ff; + *arbtr_ctrl |= 0x00001c00; + + vdma2->base_even = vv->d_clipping.dma_handle; + vdma2->base_odd = vv->d_clipping.dma_handle; + vdma2->prot_addr = vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords)); + vdma2->base_page = 0x04; + vdma2->pitch = 0x00; + vdma2->num_line_byte = (0 << 16 | (sizeof(u32))*(numdwords-1) ); + + /* set clipping-mode. this depends on the field(s) used */ + *clip_format &= 0xfffffff7; + if (V4L2_FIELD_HAS_BOTH(field)) { + *clip_format |= 0x00000008; + } else { + *clip_format |= 0x00000000; + } +} + +/* disable clipping */ +static void saa7146_disable_clipping(struct saa7146_dev *dev) +{ + u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); + + /* mask out relevant bits (=lower word)*/ + clip_format &= MASK_W1; + + /* upload clipping-registers*/ + saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format); + saa7146_write(dev, MC2, (MASK_05 | MASK_21)); + + /* disable video dma2 */ + saa7146_write(dev, MC1, MASK_21); +} + +static void saa7146_set_clipping_rect(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + enum v4l2_field field = fh->ov.win.field; + struct saa7146_video_dma vdma2; + u32 clip_format; + u32 arbtr_ctrl; + + /* check clipcount, disable clipping if clipcount == 0*/ + if( fh->ov.nclips == 0 ) { + saa7146_disable_clipping(dev); + return; + } + + clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); + arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); + + calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field); + + /* set clipping format */ + clip_format &= 0xffff0008; + clip_format |= (SAA7146_CLIPPING_RECT << 4); + + /* prepare video dma2 */ + saa7146_write(dev, BASE_EVEN2, vdma2.base_even); + saa7146_write(dev, BASE_ODD2, vdma2.base_odd); + saa7146_write(dev, PROT_ADDR2, vdma2.prot_addr); + saa7146_write(dev, BASE_PAGE2, vdma2.base_page); + saa7146_write(dev, PITCH2, vdma2.pitch); + saa7146_write(dev, NUM_LINE_BYTE2, vdma2.num_line_byte); + + /* prepare the rest */ + saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format); + saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); + + /* upload clip_control-register, clipping-registers, enable video dma2 */ + saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19)); + saa7146_write(dev, MC1, (MASK_05 | MASK_21)); +} + +static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field) +{ + struct saa7146_vv *vv = dev->vv_data; + + int source = vv->current_hps_source; + int sync = vv->current_hps_sync; + + u32 hps_v_scale = 0, hps_v_gain = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0; + + /* set vertical scale */ + hps_v_scale = 0; /* all bits get set by the function-call */ + hps_v_gain = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/ + calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain); + + /* set horizontal scale */ + hps_ctrl = 0; + hps_h_prescale = 0; /* all bits get set in the function */ + hps_h_scale = 0; + calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale); + + /* set hyo and hxo */ + calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl); + calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl); + + /* write out new register contents */ + saa7146_write(dev, HPS_V_SCALE, hps_v_scale); + saa7146_write(dev, HPS_V_GAIN, hps_v_gain); + saa7146_write(dev, HPS_CTRL, hps_ctrl); + saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale); + saa7146_write(dev, HPS_H_SCALE, hps_h_scale); + + /* upload shadow-ram registers */ + saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) ); +} + +/* calculate the new memory offsets for a desired position */ +static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat) +{ + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat); + + int b_depth = vv->ov_fmt->depth; + int b_bpl = vv->ov_fb.fmt.bytesperline; + /* The unsigned long cast is to remove a 64-bit compile warning since + it looks like a 64-bit address is cast to a 32-bit value, even + though the base pointer is really a 32-bit physical address that + goes into a 32-bit DMA register. + FIXME: might not work on some 64-bit platforms, but see the FIXME + in struct v4l2_framebuffer (videodev2.h) for that. + */ + u32 base = (u32)(unsigned long)vv->ov_fb.base; + + struct saa7146_video_dma vdma1; + + /* calculate memory offsets for picture, look if we shall top-down-flip */ + vdma1.pitch = 2*b_bpl; + if ( 0 == vv->vflip ) { + vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); + vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2); + vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2)); + } + else { + vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); + vdma1.base_odd = vdma1.base_even - (vdma1.pitch / 2); + vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2)); + } + + if (V4L2_FIELD_HAS_BOTH(field)) { + } else if (field == V4L2_FIELD_ALTERNATE) { + /* fixme */ + vdma1.base_odd = vdma1.prot_addr; + vdma1.pitch /= 2; + } else if (field == V4L2_FIELD_TOP) { + vdma1.base_odd = vdma1.prot_addr; + vdma1.pitch /= 2; + } else if (field == V4L2_FIELD_BOTTOM) { + vdma1.base_odd = vdma1.base_even; + vdma1.base_even = vdma1.prot_addr; + vdma1.pitch /= 2; + } + + if ( 0 != vv->vflip ) { + vdma1.pitch *= -1; + } + + vdma1.base_page = sfmt->swap; + vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels; + + saa7146_write_out_dma(dev, 1, &vdma1); +} + +static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette) +{ + u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); + + /* call helper function */ + calculate_output_format_register(dev,palette,&clip_format); + + /* update the hps registers */ + saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format); + saa7146_write(dev, MC2, (MASK_05 | MASK_21)); +} + +/* select input-source */ +void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync) +{ + struct saa7146_vv *vv = dev->vv_data; + u32 hps_ctrl = 0; + + /* read old state */ + hps_ctrl = saa7146_read(dev, HPS_CTRL); + + hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 ); + hps_ctrl |= (source << 30) | (sync << 28); + + /* write back & upload register */ + saa7146_write(dev, HPS_CTRL, hps_ctrl); + saa7146_write(dev, MC2, (MASK_05 | MASK_21)); + + vv->current_hps_source = source; + vv->current_hps_sync = sync; +} +EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync); + +int saa7146_enable_overlay(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + + saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field); + saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field, vv->ov_fmt->pixelformat); + saa7146_set_output_format(dev, vv->ov_fmt->trans); + saa7146_set_clipping_rect(fh); + + /* enable video dma1 */ + saa7146_write(dev, MC1, (MASK_06 | MASK_22)); + return 0; +} + +void saa7146_disable_overlay(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + + /* disable clipping + video dma1 */ + saa7146_disable_clipping(dev); + saa7146_write(dev, MC1, MASK_22); +} + +void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) +{ + int where = 0; + + if( which < 1 || which > 3) { + return; + } + + /* calculate starting address */ + where = (which-1)*0x18; + + saa7146_write(dev, where, vdma->base_odd); + saa7146_write(dev, where+0x04, vdma->base_even); + saa7146_write(dev, where+0x08, vdma->prot_addr); + saa7146_write(dev, where+0x0c, vdma->pitch); + saa7146_write(dev, where+0x10, vdma->base_page); + saa7146_write(dev, where+0x14, vdma->num_line_byte); + + /* upload */ + saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1))); +/* + printk("vdma%d.base_even: 0x%08x\n", which,vdma->base_even); + printk("vdma%d.base_odd: 0x%08x\n", which,vdma->base_odd); + printk("vdma%d.prot_addr: 0x%08x\n", which,vdma->prot_addr); + printk("vdma%d.base_page: 0x%08x\n", which,vdma->base_page); + printk("vdma%d.pitch: 0x%08x\n", which,vdma->pitch); + printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte); +*/ +} + +static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf) +{ + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_video_dma vdma1; + + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); + + int width = buf->fmt->width; + int height = buf->fmt->height; + int bytesperline = buf->fmt->bytesperline; + enum v4l2_field field = buf->fmt->field; + + int depth = sfmt->depth; + + DEB_CAP(("[size=%dx%d,fields=%s]\n", + width,height,v4l2_field_names[field])); + + if( bytesperline != 0) { + vdma1.pitch = bytesperline*2; + } else { + vdma1.pitch = (width*depth*2)/8; + } + vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); + vdma1.base_page = buf->pt[0].dma | ME1 | sfmt->swap; + + if( 0 != vv->vflip ) { + vdma1.prot_addr = buf->pt[0].offset; + vdma1.base_even = buf->pt[0].offset+(vdma1.pitch/2)*height; + vdma1.base_odd = vdma1.base_even - (vdma1.pitch/2); + } else { + vdma1.base_even = buf->pt[0].offset; + vdma1.base_odd = vdma1.base_even + (vdma1.pitch/2); + vdma1.prot_addr = buf->pt[0].offset+(vdma1.pitch/2)*height; + } + + if (V4L2_FIELD_HAS_BOTH(field)) { + } else if (field == V4L2_FIELD_ALTERNATE) { + /* fixme */ + if ( vv->last_field == V4L2_FIELD_TOP ) { + vdma1.base_odd = vdma1.prot_addr; + vdma1.pitch /= 2; + } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { + vdma1.base_odd = vdma1.base_even; + vdma1.base_even = vdma1.prot_addr; + vdma1.pitch /= 2; + } + } else if (field == V4L2_FIELD_TOP) { + vdma1.base_odd = vdma1.prot_addr; + vdma1.pitch /= 2; + } else if (field == V4L2_FIELD_BOTTOM) { + vdma1.base_odd = vdma1.base_even; + vdma1.base_even = vdma1.prot_addr; + vdma1.pitch /= 2; + } + + if( 0 != vv->vflip ) { + vdma1.pitch *= -1; + } + + saa7146_write_out_dma(dev, 1, &vdma1); + return 0; +} + +static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) +{ + int height = buf->fmt->height; + int width = buf->fmt->width; + + vdma2->pitch = width; + vdma3->pitch = width; + + /* fixme: look at bytesperline! */ + + if( 0 != vv->vflip ) { + vdma2->prot_addr = buf->pt[1].offset; + vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[1].offset; + vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); + + vdma3->prot_addr = buf->pt[2].offset; + vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[2].offset; + vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); + } else { + vdma3->base_even = buf->pt[2].offset; + vdma3->base_odd = vdma3->base_even + (vdma3->pitch/2); + vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; + + vdma2->base_even = buf->pt[1].offset; + vdma2->base_odd = vdma2->base_even + (vdma2->pitch/2); + vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; + } + + return 0; +} + +static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) +{ + int height = buf->fmt->height; + int width = buf->fmt->width; + + vdma2->pitch = width/2; + vdma3->pitch = width/2; + + if( 0 != vv->vflip ) { + vdma2->prot_addr = buf->pt[2].offset; + vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[2].offset; + vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); + + vdma3->prot_addr = buf->pt[1].offset; + vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[1].offset; + vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); + + } else { + vdma3->base_even = buf->pt[2].offset; + vdma3->base_odd = vdma3->base_even + (vdma3->pitch); + vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; + + vdma2->base_even = buf->pt[1].offset; + vdma2->base_odd = vdma2->base_even + (vdma2->pitch); + vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; + } + return 0; +} + +static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf) +{ + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_video_dma vdma1; + struct saa7146_video_dma vdma2; + struct saa7146_video_dma vdma3; + + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); + + int width = buf->fmt->width; + int height = buf->fmt->height; + enum v4l2_field field = buf->fmt->field; + + BUG_ON(0 == buf->pt[0].dma); + BUG_ON(0 == buf->pt[1].dma); + BUG_ON(0 == buf->pt[2].dma); + + DEB_CAP(("[size=%dx%d,fields=%s]\n", + width,height,v4l2_field_names[field])); + + /* fixme: look at bytesperline! */ + + /* fixme: what happens for user space buffers here?. The offsets are + most likely wrong, this version here only works for page-aligned + buffers, modifications to the pagetable-functions are necessary...*/ + + vdma1.pitch = width*2; + vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); + vdma1.base_page = buf->pt[0].dma | ME1; + + if( 0 != vv->vflip ) { + vdma1.prot_addr = buf->pt[0].offset; + vdma1.base_even = ((vdma1.pitch/2)*height)+buf->pt[0].offset; + vdma1.base_odd = vdma1.base_even - (vdma1.pitch/2); + } else { + vdma1.base_even = buf->pt[0].offset; + vdma1.base_odd = vdma1.base_even + (vdma1.pitch/2); + vdma1.prot_addr = (vdma1.pitch/2)*height+buf->pt[0].offset; + } + + vdma2.num_line_byte = 0; /* unused */ + vdma2.base_page = buf->pt[1].dma | ME1; + + vdma3.num_line_byte = 0; /* unused */ + vdma3.base_page = buf->pt[2].dma | ME1; + + switch( sfmt->depth ) { + case 12: { + calc_planar_420(vv,buf,&vdma2,&vdma3); + break; + } + case 16: { + calc_planar_422(vv,buf,&vdma2,&vdma3); + break; + } + default: { + return -1; + } + } + + if (V4L2_FIELD_HAS_BOTH(field)) { + } else if (field == V4L2_FIELD_ALTERNATE) { + /* fixme */ + vdma1.base_odd = vdma1.prot_addr; + vdma1.pitch /= 2; + vdma2.base_odd = vdma2.prot_addr; + vdma2.pitch /= 2; + vdma3.base_odd = vdma3.prot_addr; + vdma3.pitch /= 2; + } else if (field == V4L2_FIELD_TOP) { + vdma1.base_odd = vdma1.prot_addr; + vdma1.pitch /= 2; + vdma2.base_odd = vdma2.prot_addr; + vdma2.pitch /= 2; + vdma3.base_odd = vdma3.prot_addr; + vdma3.pitch /= 2; + } else if (field == V4L2_FIELD_BOTTOM) { + vdma1.base_odd = vdma1.base_even; + vdma1.base_even = vdma1.prot_addr; + vdma1.pitch /= 2; + vdma2.base_odd = vdma2.base_even; + vdma2.base_even = vdma2.prot_addr; + vdma2.pitch /= 2; + vdma3.base_odd = vdma3.base_even; + vdma3.base_even = vdma3.prot_addr; + vdma3.pitch /= 2; + } + + if( 0 != vv->vflip ) { + vdma1.pitch *= -1; + vdma2.pitch *= -1; + vdma3.pitch *= -1; + } + + saa7146_write_out_dma(dev, 1, &vdma1); + if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) { + saa7146_write_out_dma(dev, 3, &vdma2); + saa7146_write_out_dma(dev, 2, &vdma3); + } else { + saa7146_write_out_dma(dev, 2, &vdma2); + saa7146_write_out_dma(dev, 3, &vdma3); + } + return 0; +} + +static void program_capture_engine(struct saa7146_dev *dev, int planar) +{ + struct saa7146_vv *vv = dev->vv_data; + int count = 0; + + unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; + unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; + + /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/ + WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait); + WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait); + + /* set rps register 0 */ + WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4)); + WRITE_RPS0(MASK_27 | MASK_11); + + /* turn on video-dma1 */ + WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); + WRITE_RPS0(MASK_06 | MASK_22); /* => mask */ + WRITE_RPS0(MASK_06 | MASK_22); /* => values */ + if( 0 != planar ) { + /* turn on video-dma2 */ + WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); + WRITE_RPS0(MASK_05 | MASK_21); /* => mask */ + WRITE_RPS0(MASK_05 | MASK_21); /* => values */ + + /* turn on video-dma3 */ + WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); + WRITE_RPS0(MASK_04 | MASK_20); /* => mask */ + WRITE_RPS0(MASK_04 | MASK_20); /* => values */ + } + + /* wait for o_fid_a/b / e_fid_a/b toggle */ + if ( vv->last_field == V4L2_FIELD_INTERLACED ) { + WRITE_RPS0(CMD_PAUSE | o_wait); + WRITE_RPS0(CMD_PAUSE | e_wait); + } else if ( vv->last_field == V4L2_FIELD_TOP ) { + WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09)); + WRITE_RPS0(CMD_PAUSE | o_wait); + } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { + WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09)); + WRITE_RPS0(CMD_PAUSE | e_wait); + } + + /* turn off video-dma1 */ + WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); + WRITE_RPS0(MASK_22 | MASK_06); /* => mask */ + WRITE_RPS0(MASK_22); /* => values */ + if( 0 != planar ) { + /* turn off video-dma2 */ + WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); + WRITE_RPS0(MASK_05 | MASK_21); /* => mask */ + WRITE_RPS0(MASK_21); /* => values */ + + /* turn off video-dma3 */ + WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); + WRITE_RPS0(MASK_04 | MASK_20); /* => mask */ + WRITE_RPS0(MASK_20); /* => values */ + } + + /* generate interrupt */ + WRITE_RPS0(CMD_INTERRUPT); + + /* stop */ + WRITE_RPS0(CMD_STOP); +} + +void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) +{ + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_vv *vv = dev->vv_data; + u32 vdma1_prot_addr; + + DEB_CAP(("buf:%p, next:%p\n",buf,next)); + + vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1); + if( 0 == vdma1_prot_addr ) { + /* clear out beginning of streaming bit (rps register 0)*/ + DEB_CAP(("forcing sync to new frame\n")); + saa7146_write(dev, MC2, MASK_27 ); + } + + saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field); + saa7146_set_output_format(dev, sfmt->trans); + saa7146_disable_clipping(dev); + + if ( vv->last_field == V4L2_FIELD_INTERLACED ) { + } else if ( vv->last_field == V4L2_FIELD_TOP ) { + vv->last_field = V4L2_FIELD_BOTTOM; + } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { + vv->last_field = V4L2_FIELD_TOP; + } + + if( 0 != IS_PLANAR(sfmt->trans)) { + calculate_video_dma_grab_planar(dev, buf); + program_capture_engine(dev,1); + } else { + calculate_video_dma_grab_packed(dev, buf); + program_capture_engine(dev,0); + } + +/* + printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); + printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); + printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); + printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); + printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); + printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); + printk("vdma%d => vptr : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1)); +*/ + + /* write the address of the rps-program */ + saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle); + + /* turn on rps */ + saa7146_write(dev, MC1, (MASK_12 | MASK_28)); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_i2c.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,421 @@ +#include + +static u32 saa7146_i2c_func(struct i2c_adapter *adapter) +{ +//fm DEB_I2C(("'%s'.\n", adapter->name)); + + return I2C_FUNC_I2C + | I2C_FUNC_SMBUS_QUICK + | I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE + | I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; +} + +/* this function returns the status-register of our i2c-device */ +static inline u32 saa7146_i2c_status(struct saa7146_dev *dev) +{ + u32 iicsta = saa7146_read(dev, I2C_STATUS); +/* + DEB_I2C(("status: 0x%08x\n",iicsta)); +*/ + return iicsta; +} + +/* this function runs through the i2c-messages and prepares the data to be + sent through the saa7146. have a look at the specifications p. 122 ff + to understand this. it returns the number of u32s to send, or -1 + in case of an error. */ +static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op) +{ + int h1, h2; + int i, j, addr; + int mem = 0, op_count = 0; + + /* first determine size of needed memory */ + for(i = 0; i < num; i++) { + mem += m[i].len + 1; + } + + /* worst case: we need one u32 for three bytes to be send + plus one extra byte to address the device */ + mem = 1 + ((mem-1) / 3); + + /* we assume that op points to a memory of at least SAA7146_I2C_MEM bytes + size. if we exceed this limit... */ + if ( (4*mem) > SAA7146_I2C_MEM ) { +//fm DEB_I2C(("cannot prepare i2c-message.\n")); + return -ENOMEM; + } + + /* be careful: clear out the i2c-mem first */ + memset(op,0,sizeof(__le32)*mem); + + /* loop through all messages */ + for(i = 0; i < num; i++) { + + /* insert the address of the i2c-slave. + note: we get 7 bit i2c-addresses, + so we have to perform a translation */ + addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0); + h1 = op_count/3; h2 = op_count%3; + op[h1] |= cpu_to_le32( (u8)addr << ((3-h2)*8)); + op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2)); + op_count++; + + /* loop through all bytes of message i */ + for(j = 0; j < m[i].len; j++) { + /* insert the data bytes */ + h1 = op_count/3; h2 = op_count%3; + op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8)); + op[h1] |= cpu_to_le32( SAA7146_I2C_CONT << ((3-h2)*2)); + op_count++; + } + + } + + /* have a look at the last byte inserted: + if it was: ...CONT change it to ...STOP */ + h1 = (op_count-1)/3; h2 = (op_count-1)%3; + if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) { + op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2)); + op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2)); + } + + /* return the number of u32s to send */ + return mem; +} + +/* this functions loops through all i2c-messages. normally, it should determine + which bytes were read through the adapter and write them back to the corresponding + i2c-message. but instead, we simply write back all bytes. + fixme: this could be improved. */ +static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op) +{ + int i, j; + int op_count = 0; + + /* loop through all messages */ + for(i = 0; i < num; i++) { + + op_count++; + + /* loop through all bytes of message i */ + for(j = 0; j < m[i].len; j++) { + /* write back all bytes that could have been read */ + m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8)); + op_count++; + } + } + + return 0; +} + +/* this functions resets the i2c-device and returns 0 if everything was fine, otherwise -1 */ +static int saa7146_i2c_reset(struct saa7146_dev *dev) +{ + /* get current status */ + u32 status = saa7146_i2c_status(dev); + + /* clear registers for sure */ + saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); + saa7146_write(dev, I2C_TRANSFER, 0); + + /* check if any operation is still in progress */ + if ( 0 != ( status & SAA7146_I2C_BUSY) ) { + + /* yes, kill ongoing operation */ + DEB_I2C(("busy_state detected.\n")); + + /* set "ABORT-OPERATION"-bit (bit 7)*/ + saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); + saa7146_write(dev, MC2, (MASK_00 | MASK_16)); + msleep(SAA7146_I2C_DELAY); + + /* clear all error-bits pending; this is needed because p.123, note 1 */ + saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); + saa7146_write(dev, MC2, (MASK_00 | MASK_16)); + msleep(SAA7146_I2C_DELAY); + } + + /* check if any error is (still) present. (this can be necessary because p.123, note 1) */ + status = saa7146_i2c_status(dev); + + if ( dev->i2c_bitrate != status ) { + + DEB_I2C(("error_state detected. status:0x%08x\n",status)); + + /* Repeat the abort operation. This seems to be necessary + after serious protocol errors caused by e.g. the SAA7740 */ + saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); + saa7146_write(dev, MC2, (MASK_00 | MASK_16)); + msleep(SAA7146_I2C_DELAY); + + /* clear all error-bits pending */ + saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); + saa7146_write(dev, MC2, (MASK_00 | MASK_16)); + msleep(SAA7146_I2C_DELAY); + + /* the data sheet says it might be necessary to clear the status + twice after an abort */ + saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); + saa7146_write(dev, MC2, (MASK_00 | MASK_16)); + msleep(SAA7146_I2C_DELAY); + } + + /* if any error is still present, a fatal error has occurred ... */ + status = saa7146_i2c_status(dev); + if ( dev->i2c_bitrate != status ) { + DEB_I2C(("fatal error. status:0x%08x\n",status)); + return -1; + } + + return 0; +} + +/* this functions writes out the data-byte 'dword' to the i2c-device. + it returns 0 if ok, -1 if the transfer failed, -2 if the transfer + failed badly (e.g. address error) */ +static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay) +{ + u32 status = 0, mc2 = 0; + int trial = 0; + unsigned long timeout; + + /* write out i2c-command */ + DEB_I2C(("before: 0x%08x (status: 0x%08x), %d\n",*dword,saa7146_read(dev, I2C_STATUS), dev->i2c_op)); + + if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) { + + saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); + saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword)); + + dev->i2c_op = 1; + SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17); + SAA7146_IER_ENABLE(dev, MASK_16|MASK_17); + saa7146_write(dev, MC2, (MASK_00 | MASK_16)); + + timeout = HZ/100 + 1; /* 10ms */ + timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout); + if (timeout == -ERESTARTSYS || dev->i2c_op) { + SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); + SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17); + if (timeout == -ERESTARTSYS) + /* a signal arrived */ + return -ERESTARTSYS; + + printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n", + dev->name, __func__); + return -EIO; + } + status = saa7146_read(dev, I2C_STATUS); + } else { + saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate); + saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword)); + saa7146_write(dev, MC2, (MASK_00 | MASK_16)); + + /* do not poll for i2c-status before upload is complete */ + timeout = jiffies + HZ/100 + 1; /* 10ms */ + while(1) { + mc2 = (saa7146_read(dev, MC2) & 0x1); + if( 0 != mc2 ) { + break; + } + if (time_after(jiffies,timeout)) { + printk(KERN_WARNING "%s %s: timed out waiting for MC2\n", + dev->name, __func__); + return -EIO; + } + } + /* wait until we get a transfer done or error */ + timeout = jiffies + HZ/100 + 1; /* 10ms */ + /* first read usually delivers bogus results... */ + saa7146_i2c_status(dev); + while(1) { + status = saa7146_i2c_status(dev); + if ((status & 0x3) != 1) + break; + if (time_after(jiffies,timeout)) { + /* this is normal when probing the bus + * (no answer from nonexisistant device...) + */ + printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n", + dev->name, __func__); + return -EIO; + } + if (++trial < 50 && short_delay) + udelay(10); + else + msleep(1); + } + } + + /* give a detailed status report */ + if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR | + SAA7146_I2C_DTERR | SAA7146_I2C_DRERR | + SAA7146_I2C_AL | SAA7146_I2C_ERR | + SAA7146_I2C_BUSY)) ) { + + if ( 0 == (status & SAA7146_I2C_ERR) || + 0 == (status & SAA7146_I2C_BUSY) ) { + /* it may take some time until ERR goes high - ignore */ + DEB_I2C(("unexpected i2c status %04x\n", status)); + } + if( 0 != (status & SAA7146_I2C_SPERR) ) { + DEB_I2C(("error due to invalid start/stop condition.\n")); + } + if( 0 != (status & SAA7146_I2C_DTERR) ) { + DEB_I2C(("error in data transmission.\n")); + } + if( 0 != (status & SAA7146_I2C_DRERR) ) { + DEB_I2C(("error when receiving data.\n")); + } + if( 0 != (status & SAA7146_I2C_AL) ) { + DEB_I2C(("error because arbitration lost.\n")); + } + + /* we handle address-errors here */ + if( 0 != (status & SAA7146_I2C_APERR) ) { + DEB_I2C(("error in address phase.\n")); + return -EREMOTEIO; + } + + return -EIO; + } + + /* read back data, just in case we were reading ... */ + *dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER)); + + DEB_I2C(("after: 0x%08x\n",*dword)); + return 0; +} + +static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) +{ + int i = 0, count = 0; + __le32 *buffer = dev->d_i2c.cpu_addr; + int err = 0; + int short_delay = 0; + + if (mutex_lock_interruptible(&dev->i2c_lock)) + return -ERESTARTSYS; + + for(i=0;i count ) { + err = -1; + goto out; + } + + if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) ) + short_delay = 1; + + do { + /* reset the i2c-device if necessary */ + err = saa7146_i2c_reset(dev); + if ( 0 > err ) { + DEB_I2C(("could not reset i2c-device.\n")); + goto out; + } + + /* write out the u32s one after another */ + for(i = 0; i < count; i++) { + err = saa7146_i2c_writeout(dev, &buffer[i], short_delay); + if ( 0 != err) { + /* this one is unsatisfying: some i2c slaves on some + dvb cards don't acknowledge correctly, so the saa7146 + thinks that an address error occurred. in that case, the + transaction should be retrying, even if an address error + occurred. analog saa7146 based cards extensively rely on + i2c address probing, however, and address errors indicate that a + device is really *not* there. retrying in that case + increases the time the device needs to probe greatly, so + it should be avoided. So we bail out in irq mode after an + address error and trust the saa7146 address error detection. */ + if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) + goto out; + DEB_I2C(("error while sending message(s). starting again.\n")); + break; + } + } + if( 0 == err ) { + err = num; + break; + } + + /* delay a bit before retrying */ + msleep(10); + + } while (err != num && retries--); + + /* quit if any error occurred */ + if (err != num) + goto out; + + /* if any things had to be read, get the results */ + if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) { + DEB_I2C(("could not cleanup i2c-message.\n")); + err = -1; + goto out; + } + + /* return the number of delivered messages */ + DEB_I2C(("transmission successful. (msg:%d).\n",err)); +out: + /* another bug in revision 0: the i2c-registers get uploaded randomly by other + uploads, so we better clear them out before continuing */ + if( 0 == dev->revision ) { + __le32 zero = 0; + saa7146_i2c_reset(dev); + if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) { + INFO(("revision 0 error. this should never happen.\n")); + } + } + + mutex_unlock(&dev->i2c_lock); + return err; +} + +/* utility functions */ +static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) +{ + struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); + struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev); + + /* use helper function to transfer data */ + return saa7146_i2c_transfer(dev, msg, num, adapter->retries); +} + + +/*****************************************************************************/ +/* i2c-adapter helper functions */ + +/* exported algorithm data */ +static struct i2c_algorithm saa7146_algo = { + .master_xfer = saa7146_i2c_xfer, + .functionality = saa7146_i2c_func, +}; + +int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate) +{ + DEB_EE(("bitrate: 0x%08x\n",bitrate)); + + /* enable i2c-port pins */ + saa7146_write(dev, MC1, (MASK_08 | MASK_24)); + + dev->i2c_bitrate = bitrate; + saa7146_i2c_reset(dev); + + if (i2c_adapter) { + i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev); + i2c_adapter->dev.parent = &dev->pci->dev; + i2c_adapter->algo = &saa7146_algo; + i2c_adapter->algo_data = NULL; + i2c_adapter->timeout = SAA7146_I2C_TIMEOUT; + i2c_adapter->retries = SAA7146_I2C_RETRIES; + } + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_vbi.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,510 @@ +#include + +static int vbi_pixel_to_capture = 720 * 2; + +static int vbi_workaround(struct saa7146_dev *dev) +{ + struct saa7146_vv *vv = dev->vv_data; + + u32 *cpu; + dma_addr_t dma_addr; + + int count = 0; + int i; + + DECLARE_WAITQUEUE(wait, current); + + DEB_VBI(("dev:%p\n",dev)); + + /* once again, a bug in the saa7146: the brs acquisition + is buggy and especially the BXO-counter does not work + as specified. there is this workaround, but please + don't let me explain it. ;-) */ + + cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr); + if (NULL == cpu) + return -ENOMEM; + + /* setup some basic programming, just for the workaround */ + saa7146_write(dev, BASE_EVEN3, dma_addr); + saa7146_write(dev, BASE_ODD3, dma_addr+vbi_pixel_to_capture); + saa7146_write(dev, PROT_ADDR3, dma_addr+4096); + saa7146_write(dev, PITCH3, vbi_pixel_to_capture); + saa7146_write(dev, BASE_PAGE3, 0x0); + saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0)); + saa7146_write(dev, MC2, MASK_04|MASK_20); + + /* load brs-control register */ + WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); + /* BXO = 1h, BRS to outbound */ + WRITE_RPS1(0xc000008c); + /* wait for vbi_a or vbi_b*/ + if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { + DEB_D(("...using port b\n")); + WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B); + WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B); +/* + WRITE_RPS1(CMD_PAUSE | MASK_09); +*/ + } else { + DEB_D(("...using port a\n")); + WRITE_RPS1(CMD_PAUSE | MASK_10); + } + /* upload brs */ + WRITE_RPS1(CMD_UPLOAD | MASK_08); + /* load brs-control register */ + WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); + /* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */ + WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19); + /* wait for brs_done */ + WRITE_RPS1(CMD_PAUSE | MASK_08); + /* upload brs */ + WRITE_RPS1(CMD_UPLOAD | MASK_08); + /* load video-dma3 NumLines3 and NumBytes3 */ + WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4)); + /* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */ + WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture)); + /* load brs-control register */ + WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); + /* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */ + WRITE_RPS1((540 << 7) | (5 << 19)); // 5 == vbi_start + /* wait for brs_done */ + WRITE_RPS1(CMD_PAUSE | MASK_08); + /* upload brs and video-dma3*/ + WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04); + /* load mc2 register: enable dma3 */ + WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4)); + WRITE_RPS1(MASK_20 | MASK_04); + /* generate interrupt */ + WRITE_RPS1(CMD_INTERRUPT); + /* stop rps1 */ + WRITE_RPS1(CMD_STOP); + + /* we have to do the workaround twice to be sure that + everything is ok */ + for(i = 0; i < 2; i++) { + + /* indicate to the irq handler that we do the workaround */ + saa7146_write(dev, MC2, MASK_31|MASK_15); + + saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0)); + saa7146_write(dev, MC2, MASK_04|MASK_20); + + /* enable rps1 irqs */ + SAA7146_IER_ENABLE(dev,MASK_28); + + /* prepare to wait to be woken up by the irq-handler */ + add_wait_queue(&vv->vbi_wq, &wait); + current->state = TASK_INTERRUPTIBLE; + + /* start rps1 to enable workaround */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + schedule(); + + DEB_VBI(("brs bug workaround %d/1.\n",i)); + + remove_wait_queue(&vv->vbi_wq, &wait); + current->state = TASK_RUNNING; + + /* disable rps1 irqs */ + SAA7146_IER_DISABLE(dev,MASK_28); + + /* stop video-dma3 */ + saa7146_write(dev, MC1, MASK_20); + + if(signal_pending(current)) { + + DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1))); + + /* stop rps1 for sure */ + saa7146_write(dev, MC1, MASK_29); + + pci_free_consistent(dev->pci, 4096, cpu, dma_addr); + return -EINTR; + } + } + + pci_free_consistent(dev->pci, 4096, cpu, dma_addr); + return 0; +} + +static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) +{ + struct saa7146_vv *vv = dev->vv_data; + + struct saa7146_video_dma vdma3; + + int count = 0; + unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; + unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; + +/* + vdma3.base_even = 0xc8000000+2560*70; + vdma3.base_odd = 0xc8000000; + vdma3.prot_addr = 0xc8000000+2560*164; + vdma3.pitch = 2560; + vdma3.base_page = 0; + vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above! +*/ + vdma3.base_even = buf->pt[2].offset; + vdma3.base_odd = buf->pt[2].offset + 16 * vbi_pixel_to_capture; + vdma3.prot_addr = buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture; + vdma3.pitch = vbi_pixel_to_capture; + vdma3.base_page = buf->pt[2].dma | ME1; + vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture; + + saa7146_write_out_dma(dev, 3, &vdma3); + + /* write beginning of rps-program */ + count = 0; + + /* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */ + + /* we don't wait here for the first field anymore. this is different from the video + capture and might cause that the first buffer is only half filled (with only + one field). but since this is some sort of streaming data, this is not that negative. + but by doing this, we can use the whole engine from videobuf-dma-sg.c... */ + +/* + WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait); + WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait); +*/ + /* set bit 1 */ + WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4)); + WRITE_RPS1(MASK_28 | MASK_12); + + /* turn on video-dma3 */ + WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4)); + WRITE_RPS1(MASK_04 | MASK_20); /* => mask */ + WRITE_RPS1(MASK_04 | MASK_20); /* => values */ + + /* wait for o_fid_a/b / e_fid_a/b toggle */ + WRITE_RPS1(CMD_PAUSE | o_wait); + WRITE_RPS1(CMD_PAUSE | e_wait); + + /* generate interrupt */ + WRITE_RPS1(CMD_INTERRUPT); + + /* stop */ + WRITE_RPS1(CMD_STOP); + + /* enable rps1 irqs */ + SAA7146_IER_ENABLE(dev, MASK_28); + + /* write the address of the rps-program */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + + /* turn on rps */ + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); +} + +static int buffer_activate(struct saa7146_dev *dev, + struct saa7146_buf *buf, + struct saa7146_buf *next) +{ + struct saa7146_vv *vv = dev->vv_data; + buf->vb.state = VIDEOBUF_ACTIVE; + + DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next)); + saa7146_set_vbi_capture(dev,buf,next); + + mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field) +{ + struct file *file = q->priv_data; + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct saa7146_buf *buf = (struct saa7146_buf *)vb; + + int err = 0; + int lines, llength, size; + + lines = 16 * 2 ; /* 2 fields */ + llength = vbi_pixel_to_capture; + size = lines * llength; + + DEB_VBI(("vb:%p\n",vb)); + + if (0 != buf->vb.baddr && buf->vb.bsize < size) { + DEB_VBI(("size mismatch.\n")); + return -EINVAL; + } + + if (buf->vb.size != size) + saa7146_dma_free(dev,q,buf); + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + + buf->vb.width = llength; + buf->vb.height = lines; + buf->vb.size = size; + buf->vb.field = field; // FIXME: check this + + saa7146_pgtable_free(dev->pci, &buf->pt[2]); + saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); + + err = videobuf_iolock(q,&buf->vb, NULL); + if (err) + goto oops; + err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], + dma->sglist, dma->sglen); + if (0 != err) + return err; + } + buf->vb.state = VIDEOBUF_PREPARED; + buf->activate = buffer_activate; + + return 0; + + oops: + DEB_VBI(("error out.\n")); + saa7146_dma_free(dev,q,buf); + + return err; +} + +static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + int llength,lines; + + lines = 16 * 2 ; /* 2 fields */ + llength = vbi_pixel_to_capture; + + *size = lines * llength; + *count = 2; + + DEB_VBI(("count:%d, size:%d\n",*count,*size)); + + return 0; +} + +static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct file *file = q->priv_data; + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_buf *buf = (struct saa7146_buf *)vb; + + DEB_VBI(("vb:%p\n",vb)); + saa7146_buffer_queue(dev,&vv->vbi_q,buf); +} + +static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct file *file = q->priv_data; + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct saa7146_buf *buf = (struct saa7146_buf *)vb; + + DEB_VBI(("vb:%p\n",vb)); + saa7146_dma_free(dev,q,buf); +} + +static struct videobuf_queue_ops vbi_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/* ------------------------------------------------------------------ */ + +static void vbi_stop(struct saa7146_fh *fh, struct file *file) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + unsigned long flags; + DEB_VBI(("dev:%p, fh:%p\n",dev, fh)); + + spin_lock_irqsave(&dev->slock,flags); + + /* disable rps1 */ + saa7146_write(dev, MC1, MASK_29); + + /* disable rps1 irqs */ + SAA7146_IER_DISABLE(dev, MASK_28); + + /* shut down dma 3 transfers */ + saa7146_write(dev, MC1, MASK_20); + + if (vv->vbi_q.curr) { + saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); + } + + videobuf_queue_cancel(&fh->vbi_q); + + vv->vbi_streaming = NULL; + + del_timer(&vv->vbi_q.timeout); + del_timer(&fh->vbi_read_timeout); + + spin_unlock_irqrestore(&dev->slock, flags); +} + +static void vbi_read_timeout(unsigned long data) +{ + struct file *file = (struct file*)data; + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + + DEB_VBI(("dev:%p, fh:%p\n",dev, fh)); + + vbi_stop(fh, file); +} + +static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) +{ + DEB_VBI(("dev:%p\n",dev)); + + INIT_LIST_HEAD(&vv->vbi_q.queue); + + init_timer(&vv->vbi_q.timeout); + vv->vbi_q.timeout.function = saa7146_buffer_timeout; + vv->vbi_q.timeout.data = (unsigned long)(&vv->vbi_q); + vv->vbi_q.dev = dev; + + init_waitqueue_head(&vv->vbi_wq); +} + +static int vbi_open(struct saa7146_dev *dev, struct file *file) +{ + struct saa7146_fh *fh = file->private_data; + + u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); + int ret = 0; + + DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); + + ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS); + if (0 == ret) { + DEB_S(("cannot get vbi RESOURCE_DMA3_BRS resource\n")); + return -EBUSY; + } + + /* adjust arbitrition control for video dma 3 */ + arbtr_ctrl &= ~0x1f0000; + arbtr_ctrl |= 0x1d0000; + saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); + saa7146_write(dev, MC2, (MASK_04|MASK_20)); + + memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt)); + + fh->vbi_fmt.sampling_rate = 27000000; + fh->vbi_fmt.offset = 248; /* todo */ + fh->vbi_fmt.samples_per_line = vbi_pixel_to_capture; + fh->vbi_fmt.sample_format = V4L2_PIX_FMT_GREY; + + /* fixme: this only works for PAL */ + fh->vbi_fmt.start[0] = 5; + fh->vbi_fmt.count[0] = 16; + fh->vbi_fmt.start[1] = 312; + fh->vbi_fmt.count[1] = 16; + + videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, // FIXME: does this really work? + sizeof(struct saa7146_buf), + file, &dev->v4l2_lock); + + init_timer(&fh->vbi_read_timeout); + fh->vbi_read_timeout.function = vbi_read_timeout; + fh->vbi_read_timeout.data = (unsigned long)file; + + /* initialize the brs */ + if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { + saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19)); + } else { + saa7146_write(dev, BRS_CTRL, 0x00000001); + + if (0 != (ret = vbi_workaround(dev))) { + DEB_VBI(("vbi workaround failed!\n")); + /* return ret;*/ + } + } + + /* upload brs register */ + saa7146_write(dev, MC2, (MASK_08|MASK_24)); + return 0; +} + +static void vbi_close(struct saa7146_dev *dev, struct file *file) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_vv *vv = dev->vv_data; + DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); + + if( fh == vv->vbi_streaming ) { + vbi_stop(fh, file); + } + saa7146_res_free(fh, RESOURCE_DMA3_BRS); +} + +static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) +{ + struct saa7146_vv *vv = dev->vv_data; + spin_lock(&dev->slock); + + if (vv->vbi_q.curr) { + DEB_VBI(("dev:%p, curr:%p\n",dev,vv->vbi_q.curr)); + /* this must be += 2, one count for each field */ + vv->vbi_fieldcount+=2; + vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount; + saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); + } else { + DEB_VBI(("dev:%p\n",dev)); + } + saa7146_buffer_next(dev,&vv->vbi_q,1); + + spin_unlock(&dev->slock); +} + +static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + ssize_t ret = 0; + + DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); + + if( NULL == vv->vbi_streaming ) { + // fixme: check if dma3 is available + // fixme: activate vbi engine here if necessary. (really?) + vv->vbi_streaming = fh; + } + + if( fh != vv->vbi_streaming ) { + DEB_VBI(("open %p is already using vbi capture.",vv->vbi_streaming)); + return -EBUSY; + } + + mod_timer(&fh->vbi_read_timeout, jiffies+BUFFER_TIMEOUT); + ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1, + file->f_flags & O_NONBLOCK); +/* + printk("BASE_ODD3: 0x%08x\n", saa7146_read(dev, BASE_ODD3)); + printk("BASE_EVEN3: 0x%08x\n", saa7146_read(dev, BASE_EVEN3)); + printk("PROT_ADDR3: 0x%08x\n", saa7146_read(dev, PROT_ADDR3)); + printk("PITCH3: 0x%08x\n", saa7146_read(dev, PITCH3)); + printk("BASE_PAGE3: 0x%08x\n", saa7146_read(dev, BASE_PAGE3)); + printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3)); + printk("BRS_CTRL: 0x%08x\n", saa7146_read(dev, BRS_CTRL)); +*/ + return ret; +} + +struct saa7146_use_ops saa7146_vbi_uops = { + .init = vbi_init, + .open = vbi_open, + .release = vbi_close, + .irq_done = vbi_irq_done, + .read = vbi_read, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_video.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/saa7146_video.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1429 @@ +#include +#include + +static int max_memory = 32; + +module_param(max_memory, int, 0644); +MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)"); + +#define IS_CAPTURE_ACTIVE(fh) \ + (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh)) + +#define IS_OVERLAY_ACTIVE(fh) \ + (((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh)) + +/* format descriptions for capture and preview */ +static struct saa7146_format formats[] = { + { + .name = "RGB-8 (3-3-2)", + .pixelformat = V4L2_PIX_FMT_RGB332, + .trans = RGB08_COMPOSED, + .depth = 8, + .flags = 0, + }, { + .name = "RGB-16 (5/B-6/G-5/R)", + .pixelformat = V4L2_PIX_FMT_RGB565, + .trans = RGB16_COMPOSED, + .depth = 16, + .flags = 0, + }, { + .name = "RGB-24 (B-G-R)", + .pixelformat = V4L2_PIX_FMT_BGR24, + .trans = RGB24_COMPOSED, + .depth = 24, + .flags = 0, + }, { + .name = "RGB-32 (B-G-R)", + .pixelformat = V4L2_PIX_FMT_BGR32, + .trans = RGB32_COMPOSED, + .depth = 32, + .flags = 0, + }, { + .name = "RGB-32 (R-G-B)", + .pixelformat = V4L2_PIX_FMT_RGB32, + .trans = RGB32_COMPOSED, + .depth = 32, + .flags = 0, + .swap = 0x2, + }, { + .name = "Greyscale-8", + .pixelformat = V4L2_PIX_FMT_GREY, + .trans = Y8, + .depth = 8, + .flags = 0, + }, { + .name = "YUV 4:2:2 planar (Y-Cb-Cr)", + .pixelformat = V4L2_PIX_FMT_YUV422P, + .trans = YUV422_DECOMPOSED, + .depth = 16, + .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, + }, { + .name = "YVU 4:2:0 planar (Y-Cb-Cr)", + .pixelformat = V4L2_PIX_FMT_YVU420, + .trans = YUV420_DECOMPOSED, + .depth = 12, + .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, + }, { + .name = "YUV 4:2:0 planar (Y-Cb-Cr)", + .pixelformat = V4L2_PIX_FMT_YUV420, + .trans = YUV420_DECOMPOSED, + .depth = 12, + .flags = FORMAT_IS_PLANAR, + }, { + .name = "YUV 4:2:2 (U-Y-V-Y)", + .pixelformat = V4L2_PIX_FMT_UYVY, + .trans = YUV422_COMPOSED, + .depth = 16, + .flags = 0, + } +}; + +/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps. + due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped + (like V4L2_PIX_FMT_YUYV) ... 8-( */ + +static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format); + +struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc) +{ + int i, j = NUM_FORMATS; + + for (i = 0; i < j; i++) { + if (formats[i].pixelformat == fourcc) { + return formats+i; + } + } + + DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc)); + return NULL; +} + +static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f); + +int saa7146_start_preview(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct v4l2_format fmt; + int ret = 0, err = 0; + + DEB_EE(("dev:%p, fh:%p\n",dev,fh)); + + /* check if we have overlay informations */ + if( NULL == fh->ov.fh ) { + DEB_D(("no overlay data available. try S_FMT first.\n")); + return -EAGAIN; + } + + /* check if streaming capture is running */ + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_D(("streaming capture is active.\n")); + return -EBUSY; + } + + /* check if overlay is running */ + if (IS_OVERLAY_ACTIVE(fh) != 0) { + if (vv->video_fh == fh) { + DEB_D(("overlay is already active.\n")); + return 0; + } + DEB_D(("overlay is already active in another open.\n")); + return -EBUSY; + } + + if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { + DEB_D(("cannot get necessary overlay resources\n")); + return -EBUSY; + } + + fmt.fmt.win = fh->ov.win; + err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt); + if (0 != err) { + saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); + return -EBUSY; + } + fh->ov.win = fmt.fmt.win; + vv->ov_data = &fh->ov; + + DEB_D(("%dx%d+%d+%d %s field=%s\n", + fh->ov.win.w.width,fh->ov.win.w.height, + fh->ov.win.w.left,fh->ov.win.w.top, + vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field])); + + if (0 != (ret = saa7146_enable_overlay(fh))) { + DEB_D(("enabling overlay failed: %d\n",ret)); + saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); + return ret; + } + + vv->video_status = STATUS_OVERLAY; + vv->video_fh = fh; + + return 0; +} +EXPORT_SYMBOL_GPL(saa7146_start_preview); + +int saa7146_stop_preview(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + + DEB_EE(("dev:%p, fh:%p\n",dev,fh)); + + /* check if streaming capture is running */ + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_D(("streaming capture is active.\n")); + return -EBUSY; + } + + /* check if overlay is running at all */ + if ((vv->video_status & STATUS_OVERLAY) == 0) { + DEB_D(("no active overlay.\n")); + return 0; + } + + if (vv->video_fh != fh) { + DEB_D(("overlay is active, but in another open.\n")); + return -EBUSY; + } + + vv->video_status = 0; + vv->video_fh = NULL; + + saa7146_disable_overlay(fh); + + saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); + + return 0; +} +EXPORT_SYMBOL_GPL(saa7146_stop_preview); + +/********************************************************************************/ +/* device controls */ + +static struct v4l2_queryctrl controls[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128, + .type = V4L2_CTRL_TYPE_INTEGER, + .flags = V4L2_CTRL_FLAG_SLIDER, + },{ + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 64, + .type = V4L2_CTRL_TYPE_INTEGER, + .flags = V4L2_CTRL_FLAG_SLIDER, + },{ + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 64, + .type = V4L2_CTRL_TYPE_INTEGER, + .flags = V4L2_CTRL_FLAG_SLIDER, + },{ + .id = V4L2_CID_VFLIP, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_HFLIP, + .name = "Horizontal Flip", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, +}; +static int NUM_CONTROLS = sizeof(controls)/sizeof(struct v4l2_queryctrl); + +#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 0) + +static struct v4l2_queryctrl* ctrl_by_id(int id) +{ + int i; + + for (i = 0; i < NUM_CONTROLS; i++) + if (controls[i].id == id) + return controls+i; + return NULL; +} + +/********************************************************************************/ +/* common pagetable functions */ + +static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) +{ + struct pci_dev *pci = dev->pci; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + struct scatterlist *list = dma->sglist; + int length = dma->sglen; + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); + + DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); + + if( 0 != IS_PLANAR(sfmt->trans)) { + struct saa7146_pgtable *pt1 = &buf->pt[0]; + struct saa7146_pgtable *pt2 = &buf->pt[1]; + struct saa7146_pgtable *pt3 = &buf->pt[2]; + __le32 *ptr1, *ptr2, *ptr3; + __le32 fill; + + int size = buf->fmt->width*buf->fmt->height; + int i,p,m1,m2,m3,o1,o2; + + switch( sfmt->depth ) { + case 12: { + /* create some offsets inside the page table */ + m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; + m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1; + m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; + o1 = size%PAGE_SIZE; + o2 = (size+(size/4))%PAGE_SIZE; + DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); + break; + } + case 16: { + /* create some offsets inside the page table */ + m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; + m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; + m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1; + o1 = size%PAGE_SIZE; + o2 = (size+(size/2))%PAGE_SIZE; + DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); + break; + } + default: { + return -1; + } + } + + ptr1 = pt1->cpu; + ptr2 = pt2->cpu; + ptr3 = pt3->cpu; + + /* walk all pages, copy all page addresses to ptr1 */ + for (i = 0; i < length; i++, list++) { + for (p = 0; p * 4096 < list->length; p++, ptr1++) { + *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset); + } + } +/* + ptr1 = pt1->cpu; + for(j=0;j<40;j++) { + printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); + } +*/ + + /* if we have a user buffer, the first page may not be + aligned to a page boundary. */ + pt1->offset = dma->sglist->offset; + pt2->offset = pt1->offset+o1; + pt3->offset = pt1->offset+o2; + + /* create video-dma2 page table */ + ptr1 = pt1->cpu; + for(i = m1; i <= m2 ; i++, ptr2++) { + *ptr2 = ptr1[i]; + } + fill = *(ptr2-1); + for(;i<1024;i++,ptr2++) { + *ptr2 = fill; + } + /* create video-dma3 page table */ + ptr1 = pt1->cpu; + for(i = m2; i <= m3; i++,ptr3++) { + *ptr3 = ptr1[i]; + } + fill = *(ptr3-1); + for(;i<1024;i++,ptr3++) { + *ptr3 = fill; + } + /* finally: finish up video-dma1 page table */ + ptr1 = pt1->cpu+m1; + fill = pt1->cpu[m1]; + for(i=m1;i<1024;i++,ptr1++) { + *ptr1 = fill; + } +/* + ptr1 = pt1->cpu; + ptr2 = pt2->cpu; + ptr3 = pt3->cpu; + for(j=0;j<40;j++) { + printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); + } + for(j=0;j<40;j++) { + printk("ptr2 %d: 0x%08x\n",j,ptr2[j]); + } + for(j=0;j<40;j++) { + printk("ptr3 %d: 0x%08x\n",j,ptr3[j]); + } +*/ + } else { + struct saa7146_pgtable *pt = &buf->pt[0]; + return saa7146_pgtable_build_single(pci, pt, list, length); + } + + return 0; +} + + +/********************************************************************************/ +/* file operations */ + +static int video_begin(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_format *fmt = NULL; + unsigned int resource; + int ret = 0, err = 0; + + DEB_EE(("dev:%p, fh:%p\n",dev,fh)); + + if ((vv->video_status & STATUS_CAPTURE) != 0) { + if (vv->video_fh == fh) { + DEB_S(("already capturing.\n")); + return 0; + } + DEB_S(("already capturing in another open.\n")); + return -EBUSY; + } + + if ((vv->video_status & STATUS_OVERLAY) != 0) { + DEB_S(("warning: suspending overlay video for streaming capture.\n")); + vv->ov_suspend = vv->video_fh; + err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ + if (0 != err) { + DEB_D(("suspending video failed. aborting\n")); + return err; + } + } + + fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); + /* we need to have a valid format set here */ + BUG_ON(NULL == fmt); + + if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { + resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; + } else { + resource = RESOURCE_DMA1_HPS; + } + + ret = saa7146_res_get(fh, resource); + if (0 == ret) { + DEB_S(("cannot get capture resource %d\n",resource)); + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } + return -EBUSY; + } + + /* clear out beginning of streaming bit (rps register 0)*/ + saa7146_write(dev, MC2, MASK_27 ); + + /* enable rps0 irqs */ + SAA7146_IER_ENABLE(dev, MASK_27); + + vv->video_fh = fh; + vv->video_status = STATUS_CAPTURE; + + return 0; +} + +static int video_end(struct saa7146_fh *fh, struct file *file) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_format *fmt = NULL; + unsigned long flags; + unsigned int resource; + u32 dmas = 0; + DEB_EE(("dev:%p, fh:%p\n",dev,fh)); + + if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { + DEB_S(("not capturing.\n")); + return 0; + } + + if (vv->video_fh != fh) { + DEB_S(("capturing, but in another open.\n")); + return -EBUSY; + } + + fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); + /* we need to have a valid format set here */ + BUG_ON(NULL == fmt); + + if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { + resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; + dmas = MASK_22 | MASK_21 | MASK_20; + } else { + resource = RESOURCE_DMA1_HPS; + dmas = MASK_22; + } + spin_lock_irqsave(&dev->slock,flags); + + /* disable rps0 */ + saa7146_write(dev, MC1, MASK_28); + + /* disable rps0 irqs */ + SAA7146_IER_DISABLE(dev, MASK_27); + + /* shut down all used video dma transfers */ + saa7146_write(dev, MC1, dmas); + + spin_unlock_irqrestore(&dev->slock, flags); + + vv->video_fh = NULL; + vv->video_status = 0; + + saa7146_res_free(fh, resource); + + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } + + return 0; +} + +static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + + strcpy((char *)cap->driver, "saa7146 v4l2"); + strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); + sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = SAA7146_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + cap->capabilities |= dev->ext_vv_data->capabilities; + return 0; +} + +static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + + *fb = vv->ov_fb; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + return 0; +} + +static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_format *fmt; + + DEB_EE(("VIDIOC_S_FBUF\n")); + + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* check args */ + fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; + + /* planar formats are not allowed for overlay video, clipping and video dma would clash */ + if (fmt->flags & FORMAT_IS_PLANAR) + DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n", + (char *)&fmt->pixelformat)); + + /* check if overlay is running */ + if (IS_OVERLAY_ACTIVE(fh) != 0) { + if (vv->video_fh != fh) { + DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); + return -EBUSY; + } + } + + /* ok, accept it */ + vv->ov_fb = *fb; + vv->ov_fmt = fmt; + + if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) { + vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8; + DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline)); + } + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + if (f->index >= NUM_FORMATS) + return -EINVAL; + strlcpy((char *)f->description, formats[f->index].name, + sizeof(f->description)); + f->pixelformat = formats[f->index].pixelformat; + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; + + ctrl = ctrl_by_id(c->id); + if (ctrl == NULL) + return -EINVAL; + + DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id)); + *c = *ctrl; + return 0; +} + +static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + const struct v4l2_queryctrl *ctrl; + u32 value = 0; + + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) + return -EINVAL; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + value = saa7146_read(dev, BCS_CTRL); + c->value = 0xff & (value >> 24); + DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value)); + break; + case V4L2_CID_CONTRAST: + value = saa7146_read(dev, BCS_CTRL); + c->value = 0x7f & (value >> 16); + DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value)); + break; + case V4L2_CID_SATURATION: + value = saa7146_read(dev, BCS_CTRL); + c->value = 0x7f & (value >> 0); + DEB_D(("V4L2_CID_SATURATION: %d\n", c->value)); + break; + case V4L2_CID_VFLIP: + c->value = vv->vflip; + DEB_D(("V4L2_CID_VFLIP: %d\n", c->value)); + break; + case V4L2_CID_HFLIP: + c->value = vv->hflip; + DEB_D(("V4L2_CID_HFLIP: %d\n", c->value)); + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + const struct v4l2_queryctrl *ctrl; + + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) { + DEB_D(("unknown control %d\n", c->id)); + return -EINVAL; + } + + switch (ctrl->type) { + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER: + if (c->value < ctrl->minimum) + c->value = ctrl->minimum; + if (c->value > ctrl->maximum) + c->value = ctrl->maximum; + break; + default: + /* nothing */; + } + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: { + u32 value = saa7146_read(dev, BCS_CTRL); + value &= 0x00ffffff; + value |= (c->value << 24); + saa7146_write(dev, BCS_CTRL, value); + saa7146_write(dev, MC2, MASK_22 | MASK_06); + break; + } + case V4L2_CID_CONTRAST: { + u32 value = saa7146_read(dev, BCS_CTRL); + value &= 0xff00ffff; + value |= (c->value << 16); + saa7146_write(dev, BCS_CTRL, value); + saa7146_write(dev, MC2, MASK_22 | MASK_06); + break; + } + case V4L2_CID_SATURATION: { + u32 value = saa7146_read(dev, BCS_CTRL); + value &= 0xffffff00; + value |= (c->value << 0); + saa7146_write(dev, BCS_CTRL, value); + saa7146_write(dev, MC2, MASK_22 | MASK_06); + break; + } + case V4L2_CID_HFLIP: + /* fixme: we can support changing VFLIP and HFLIP here... */ + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_D(("V4L2_CID_HFLIP while active capture.\n")); + return -EBUSY; + } + vv->hflip = c->value; + break; + case V4L2_CID_VFLIP: + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_D(("V4L2_CID_VFLIP while active capture.\n")); + return -EBUSY; + } + vv->vflip = c->value; + break; + default: + return -EINVAL; + } + + if (IS_OVERLAY_ACTIVE(fh) != 0) { + saa7146_stop_preview(fh); + saa7146_start_preview(fh); + } + return 0; +} + +static int vidioc_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + + parm->parm.capture.readbuffers = 1; + v4l2_video_std_frame_period(vv->standard->id, + &parm->parm.capture.timeperframe); + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt; + return 0; +} + +static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) +{ + f->fmt.win = ((struct saa7146_fh *)fh)->ov.win; + return 0; +} + +static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt; + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_format *fmt; + enum v4l2_field field; + int maxw, maxh; + int calc_bpl; + + DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); + + fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = vv->standard->h_max_out; + maxh = vv->standard->v_max_out; + + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh / 2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + switch (field) { + case V4L2_FIELD_ALTERNATE: + vv->last_field = V4L2_FIELD_TOP; + maxh = maxh / 2; + break; + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + vv->last_field = V4L2_FIELD_INTERLACED; + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + vv->last_field = V4L2_FIELD_INTERLACED; + break; + default: + DEB_D(("no known field mode '%d'.\n", field)); + return -EINVAL; + } + + f->fmt.pix.field = field; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + + calc_bpl = (f->fmt.pix.width * fmt->depth) / 8; + + if (f->fmt.pix.bytesperline < calc_bpl) + f->fmt.pix.bytesperline = calc_bpl; + + if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */ + f->fmt.pix.bytesperline = calc_bpl; + + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width, + f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage)); + + return 0; +} + + +static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + struct v4l2_window *win = &f->fmt.win; + enum v4l2_field field; + int maxw, maxh; + + DEB_EE(("dev:%p\n", dev)); + + if (NULL == vv->ov_fb.base) { + DEB_D(("no fb base set.\n")); + return -EINVAL; + } + if (NULL == vv->ov_fmt) { + DEB_D(("no fb fmt set.\n")); + return -EINVAL; + } + if (win->w.width < 48 || win->w.height < 32) { + DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height)); + return -EINVAL; + } + if (win->clipcount > 16) { + DEB_D(("clipcount too big.\n")); + return -EINVAL; + } + + field = win->field; + maxw = vv->standard->h_max_out; + maxh = vv->standard->v_max_out; + + if (V4L2_FIELD_ANY == field) { + field = (win->w.height > maxh / 2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + DEB_D(("no known field mode '%d'.\n", field)); + return -EINVAL; + } + + win->field = field; + if (win->w.width > maxw) + win->w.width = maxw; + if (win->w.height > maxh) + win->w.height = maxh; + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f) +{ + struct saa7146_fh *fh = __fh; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + int err; + + DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); + if (IS_CAPTURE_ACTIVE(fh) != 0) { + DEB_EE(("streaming capture is active\n")); + return -EBUSY; + } + err = vidioc_try_fmt_vid_cap(file, fh, f); + if (0 != err) + return err; + fh->video_fmt = f->fmt.pix; + DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat)); + return 0; +} + +static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f) +{ + struct saa7146_fh *fh = __fh; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + int err; + + DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh)); + err = vidioc_try_fmt_vid_overlay(file, fh, f); + if (0 != err) + return err; + fh->ov.win = f->fmt.win; + fh->ov.nclips = f->fmt.win.clipcount; + if (fh->ov.nclips > 16) + fh->ov.nclips = 16; + if (copy_from_user(fh->ov.clips, f->fmt.win.clips, + sizeof(struct v4l2_clip) * fh->ov.nclips)) { + return -EFAULT; + } + + /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ + fh->ov.fh = fh; + + /* check if our current overlay is active */ + if (IS_OVERLAY_ACTIVE(fh) != 0) { + saa7146_stop_preview(fh); + saa7146_start_preview(fh); + } + return 0; +} + +static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + + *norm = vv->standard->id; + return 0; +} + + /* the saa7146 supfhrts (used in conjunction with the saa7111a for example) + PAL / NTSC / SECAM. if your hardware does not (or does more) + -- override this function in your extension */ +/* + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *e = arg; + if (e->index < 0 ) + return -EINVAL; + if( e->index < dev->ext_vv_data->num_stds ) { + DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index)); + v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name); + return 0; + } + return -EINVAL; + } + */ + +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct saa7146_vv *vv = dev->vv_data; + int found = 0; + int err, i; + + DEB_EE(("VIDIOC_S_STD\n")); + + if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { + DEB_D(("cannot change video standard while streaming capture is active\n")); + return -EBUSY; + } + + if ((vv->video_status & STATUS_OVERLAY) != 0) { + vv->ov_suspend = vv->video_fh; + err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ + if (0 != err) { + DEB_D(("suspending video failed. aborting\n")); + return err; + } + } + + for (i = 0; i < dev->ext_vv_data->num_stds; i++) + if (*id & dev->ext_vv_data->stds[i].id) + break; + if (i != dev->ext_vv_data->num_stds) { + vv->standard = &dev->ext_vv_data->stds[i]; + if (NULL != dev->ext_vv_data->std_callback) + dev->ext_vv_data->std_callback(dev, vv->standard); + found = 1; + } + + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } + + if (!found) { + DEB_EE(("VIDIOC_S_STD: standard not found.\n")); + return -EINVAL; + } + + DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name)); + return 0; +} + +static int vidioc_overlay(struct file *file, void *fh, unsigned int on) +{ + int err; + + DEB_D(("VIDIOC_OVERLAY on:%d\n", on)); + if (on) + err = saa7146_start_preview(fh); + else + err = saa7146_stop_preview(fh); + return err; +} + +static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b) +{ + struct saa7146_fh *fh = __fh; + + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_reqbufs(&fh->video_q, b); + if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_reqbufs(&fh->vbi_q, b); + return -EINVAL; +} + +static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) +{ + struct saa7146_fh *fh = __fh; + + if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_querybuf(&fh->video_q, buf); + if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_querybuf(&fh->vbi_q, buf); + return -EINVAL; +} + +static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) +{ + struct saa7146_fh *fh = __fh; + + if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_qbuf(&fh->video_q, buf); + if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_qbuf(&fh->vbi_q, buf); + return -EINVAL; +} + +static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) +{ + struct saa7146_fh *fh = __fh; + + if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK); + if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK); + return -EINVAL; +} + +static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) +{ + struct saa7146_fh *fh = __fh; + int err; + + DEB_D(("VIDIOC_STREAMON, type:%d\n", type)); + + err = video_begin(fh); + if (err) + return err; + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_streamon(&fh->video_q); + if (type == V4L2_BUF_TYPE_VBI_CAPTURE) + return videobuf_streamon(&fh->vbi_q); + return -EINVAL; +} + +static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) +{ + struct saa7146_fh *fh = __fh; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + int err; + + DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type)); + + /* ugly: we need to copy some checks from video_end(), + because videobuf_streamoff() relies on the capture running. + check and fix this */ + if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { + DEB_S(("not capturing.\n")); + return 0; + } + + if (vv->video_fh != fh) { + DEB_S(("capturing, but in another open.\n")); + return -EBUSY; + } + + err = -EINVAL; + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + err = videobuf_streamoff(&fh->video_q); + else if (type == V4L2_BUF_TYPE_VBI_CAPTURE) + err = videobuf_streamoff(&fh->vbi_q); + if (0 != err) { + DEB_D(("warning: videobuf_streamoff() failed.\n")); + video_end(fh, file); + } else { + err = video_end(fh, file); + } + return err; +} + +static int vidioc_g_chip_ident(struct file *file, void *__fh, + struct v4l2_dbg_chip_ident *chip) +{ + struct saa7146_fh *fh = __fh; + struct saa7146_dev *dev = fh->dev; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match.type == V4L2_CHIP_MATCH_HOST && !chip->match.addr) { + chip->ident = V4L2_IDENT_SAA7146; + return 0; + } + return v4l2_device_call_until_err(&dev->v4l2_dev, 0, + core, g_chip_ident, chip); +} + +const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, + .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, + .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, + .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + .vidioc_g_chip_ident = vidioc_g_chip_ident, + + .vidioc_overlay = vidioc_overlay, + .vidioc_g_fbuf = vidioc_g_fbuf, + .vidioc_s_fbuf = vidioc_s_fbuf, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_g_std = vidioc_g_std, + .vidioc_s_std = vidioc_s_std, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_parm = vidioc_g_parm, +}; + +/*********************************************************************************/ +/* buffer handling functions */ + +static int buffer_activate (struct saa7146_dev *dev, + struct saa7146_buf *buf, + struct saa7146_buf *next) +{ + struct saa7146_vv *vv = dev->vv_data; + + buf->vb.state = VIDEOBUF_ACTIVE; + saa7146_set_capture(dev,buf,next); + + mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf) +{ + saa7146_pgtable_free(dev->pci, &buf->pt[0]); + saa7146_pgtable_free(dev->pci, &buf->pt[1]); + saa7146_pgtable_free(dev->pci, &buf->pt[2]); +} + +static int buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) +{ + struct file *file = q->priv_data; + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_buf *buf = (struct saa7146_buf *)vb; + int size,err = 0; + + DEB_CAP(("vbuf:%p\n",vb)); + + /* sanity checks */ + if (fh->video_fmt.width < 48 || + fh->video_fmt.height < 32 || + fh->video_fmt.width > vv->standard->h_max_out || + fh->video_fmt.height > vv->standard->v_max_out) { + DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height)); + return -EINVAL; + } + + size = fh->video_fmt.sizeimage; + if (0 != buf->vb.baddr && buf->vb.bsize < size) { + DEB_D(("size mismatch.\n")); + return -EINVAL; + } + + DEB_CAP(("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n", + fh->video_fmt.width,fh->video_fmt.height,size,v4l2_field_names[fh->video_fmt.field])); + if (buf->vb.width != fh->video_fmt.width || + buf->vb.bytesperline != fh->video_fmt.bytesperline || + buf->vb.height != fh->video_fmt.height || + buf->vb.size != size || + buf->vb.field != field || + buf->vb.field != fh->video_fmt.field || + buf->fmt != &fh->video_fmt) { + saa7146_dma_free(dev,q,buf); + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + struct saa7146_format *sfmt; + + buf->vb.bytesperline = fh->video_fmt.bytesperline; + buf->vb.width = fh->video_fmt.width; + buf->vb.height = fh->video_fmt.height; + buf->vb.size = size; + buf->vb.field = field; + buf->fmt = &fh->video_fmt; + buf->vb.field = fh->video_fmt.field; + + sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); + + release_all_pagetables(dev, buf); + if( 0 != IS_PLANAR(sfmt->trans)) { + saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); + saa7146_pgtable_alloc(dev->pci, &buf->pt[1]); + saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); + } else { + saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); + } + + err = videobuf_iolock(q,&buf->vb, &vv->ov_fb); + if (err) + goto oops; + err = saa7146_pgtable_build(dev,buf); + if (err) + goto oops; + } + buf->vb.state = VIDEOBUF_PREPARED; + buf->activate = buffer_activate; + + return 0; + + oops: + DEB_D(("error out.\n")); + saa7146_dma_free(dev,q,buf); + + return err; +} + +static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + struct file *file = q->priv_data; + struct saa7146_fh *fh = file->private_data; + + if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS) + *count = MAX_SAA7146_CAPTURE_BUFFERS; + + *size = fh->video_fmt.sizeimage; + + /* check if we exceed the "max_memory" parameter */ + if( (*count * *size) > (max_memory*1048576) ) { + *count = (max_memory*1048576) / *size; + } + + DEB_CAP(("%d buffers, %d bytes each.\n",*count,*size)); + + return 0; +} + +static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct file *file = q->priv_data; + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_buf *buf = (struct saa7146_buf *)vb; + + DEB_CAP(("vbuf:%p\n",vb)); + saa7146_buffer_queue(fh->dev,&vv->video_q,buf); +} + +static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct file *file = q->priv_data; + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct saa7146_buf *buf = (struct saa7146_buf *)vb; + + DEB_CAP(("vbuf:%p\n",vb)); + + saa7146_dma_free(dev,q,buf); + + release_all_pagetables(dev, buf); +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/********************************************************************************/ +/* file operations */ + +static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv) +{ + INIT_LIST_HEAD(&vv->video_q.queue); + + init_timer(&vv->video_q.timeout); + vv->video_q.timeout.function = saa7146_buffer_timeout; + vv->video_q.timeout.data = (unsigned long)(&vv->video_q); + vv->video_q.dev = dev; + + /* set some default values */ + vv->standard = &dev->ext_vv_data->stds[0]; + + /* FIXME: what's this? */ + vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A; + vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A; +} + + +static int video_open(struct saa7146_dev *dev, struct file *file) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_format *sfmt; + + fh->video_fmt.width = 384; + fh->video_fmt.height = 288; + fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24; + fh->video_fmt.bytesperline = 0; + fh->video_fmt.field = V4L2_FIELD_ANY; + sfmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); + fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; + + videobuf_queue_sg_init(&fh->video_q, &video_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct saa7146_buf), + file, &dev->v4l2_lock); + + return 0; +} + + +static void video_close(struct saa7146_dev *dev, struct file *file) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_vv *vv = dev->vv_data; + struct videobuf_queue *q = &fh->video_q; + int err; + + if (IS_CAPTURE_ACTIVE(fh) != 0) { + err = video_end(fh, file); + } else if (IS_OVERLAY_ACTIVE(fh) != 0) { + err = saa7146_stop_preview(fh); + } + + videobuf_stop(q); + + /* hmm, why is this function declared void? */ + /* return err */ +} + + +static void video_irq_done(struct saa7146_dev *dev, unsigned long st) +{ + struct saa7146_vv *vv = dev->vv_data; + struct saa7146_dmaqueue *q = &vv->video_q; + + spin_lock(&dev->slock); + DEB_CAP(("called.\n")); + + /* only finish the buffer if we have one... */ + if( NULL != q->curr ) { + saa7146_buffer_finish(dev,q,VIDEOBUF_DONE); + } + saa7146_buffer_next(dev,q,0); + + spin_unlock(&dev->slock); +} + +static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + ssize_t ret = 0; + + DEB_EE(("called.\n")); + + if ((vv->video_status & STATUS_CAPTURE) != 0) { + /* fixme: should we allow read() captures while streaming capture? */ + if (vv->video_fh == fh) { + DEB_S(("already capturing.\n")); + return -EBUSY; + } + DEB_S(("already capturing in another open.\n")); + return -EBUSY; + } + + ret = video_begin(fh); + if( 0 != ret) { + goto out; + } + + ret = videobuf_read_one(&fh->video_q , data, count, ppos, + file->f_flags & O_NONBLOCK); + if (ret != 0) { + video_end(fh, file); + } else { + ret = video_end(fh, file); + } +out: + /* restart overlay if it was active before */ + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } + + return ret; +} + +struct saa7146_use_ops saa7146_video_uops = { + .init = video_init, + .open = video_open, + .release = video_close, + .irq_done = video_irq_done, + .read = video_read, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,207 @@ +config MEDIA_ATTACH + bool "Load and attach frontend and tuner driver modules as needed" + depends on VIDEO_MEDIA + depends on MODULES + help + Remove the static dependency of DVB card drivers on all + frontend modules for all possible card variants. Instead, + allow the card drivers to only load the frontend modules + they require. + + Also, tuner module will automatically load a tuner driver + when needed, for analog mode. + + This saves several KBytes of memory. + + Note: You will need module-init-tools v3.2 or later for this feature. + + If unsure say Y. + +config MEDIA_TUNER + tristate + default VIDEO_MEDIA && I2C + depends on VIDEO_MEDIA && I2C + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE + +config MEDIA_TUNER_CUSTOMISE + bool "Customize analog and hybrid tuner modules to build" + depends on MEDIA_TUNER + default y if EXPERT + help + This allows the user to deselect tuner drivers unnecessary + for their hardware from the build. Use this option with care + as deselecting tuner drivers which are in fact necessary will + result in V4L/DVB devices which cannot be tuned due to lack of + driver support + + If unsure say N. + +menu "Customize TV tuners" + visible if MEDIA_TUNER_CUSTOMISE + +config MEDIA_TUNER_SIMPLE + tristate "Simple tuner support" + depends on VIDEO_MEDIA && I2C + select MEDIA_TUNER_TDA9887 + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for various simple tuners. + +config MEDIA_TUNER_TDA8290 + tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" + depends on VIDEO_MEDIA && I2C + select MEDIA_TUNER_TDA827X + select MEDIA_TUNER_TDA18271 + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for Philips TDA8290+8275(a) tuner. + +config MEDIA_TUNER_TDA827X + tristate "Philips TDA827X silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A DVB-T silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA18271 + tristate "NXP TDA18271 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA9887 + tristate "TDA 9885/6/7 analog IF demodulator" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for Philips TDA9885/6/7 + analog IF demodulator. + +config MEDIA_TUNER_TEA5761 + tristate "TEA 5761 radio tuner (EXPERIMENTAL)" + depends on VIDEO_MEDIA && I2C + depends on EXPERIMENTAL + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for the Philips TEA5761 radio tuner. + +config MEDIA_TUNER_TEA5767 + tristate "TEA 5767 radio tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for the Philips TEA5767 radio tuner. + +config MEDIA_TUNER_MT20XX + tristate "Microtune 2032 / 2050 tuners" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for the MT2032 / MT2050 tuner. + +config MEDIA_TUNER_MT2060 + tristate "Microtune MT2060 silicon IF tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon IF tuner MT2060 from Microtune. + +config MEDIA_TUNER_MT2266 + tristate "Microtune MT2266 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon baseband tuner MT2266 from Microtune. + +config MEDIA_TUNER_MT2131 + tristate "Microtune MT2131 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon baseband tuner MT2131 from Microtune. + +config MEDIA_TUNER_QT1010 + tristate "Quantek QT1010 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner QT1010 from Quantek. + +config MEDIA_TUNER_XC2028 + tristate "XCeive xc2028/xc3028 tuners" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to include support for the xc2028/xc3028 tuners. + +config MEDIA_TUNER_XC5000 + tristate "Xceive XC5000 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner XC5000 from Xceive. + This device is only used inside a SiP called together with a + demodulator for now. + +config MEDIA_TUNER_XC4000 + tristate "Xceive XC4000 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner XC4000 from Xceive. + This device is only used inside a SiP called together with a + demodulator for now. + +config MEDIA_TUNER_MXL5005S + tristate "MaxLinear MSL5005S silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner MXL5005S from MaxLinear. + +config MEDIA_TUNER_MXL5007T + tristate "MaxLinear MxL5007T silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner MxL5007T from MaxLinear. + +config MEDIA_TUNER_MC44S803 + tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Freescale MC44S803 based tuners + +config MEDIA_TUNER_MAX2165 + tristate "Maxim MAX2165 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon tuner MAX2165 from Maxim. + +config MEDIA_TUNER_TDA18218 + tristate "NXP TDA18218 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + NXP TDA18218 silicon tuner driver. + +config MEDIA_TUNER_TDA18212 + tristate "NXP TDA18212 silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + NXP TDA18212 silicon tuner driver. + +endmenu diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,32 @@ +# +# Makefile for common V4L/DVB tuners +# + +tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o + +obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o +# tuner-types will be merged into tuner-simple, in the future +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o +obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o +obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o +obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o +obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o +obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o +obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o +obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o +obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o +obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o +obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o +obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o +obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o +obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o +obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o +obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o +obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o +obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o +obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,441 @@ +/* + * Driver for Maxim MAX2165 silicon tuner + * + * Copyright (c) 2009 David T. L. Wong + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "max2165.h" +#include "max2165_priv.h" +#include "tuner-i2c.h" + +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "max2165: " args); \ + } while (0) + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; + + msg.addr = priv->config->i2c_address; + + if (debug >= 2) + dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data); + + ret = i2c_transfer(priv->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", + __func__, reg, data, ret); + + return (ret != 1) ? -EIO : 0; +} + +static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data) +{ + int ret; + u8 dev_addr = priv->config->i2c_address; + + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 }, + { .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }, + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret != 2) { + dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret); + return -EIO; + } + + *p_data = b1[0]; + if (debug >= 2) + dprintk("%s: reg=0x%02X, data=0x%02X\n", + __func__, reg, b1[0]); + return 0; +} + +static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg, + u8 mask, u8 data) +{ + int ret; + u8 v; + + data &= mask; + ret = max2165_read_reg(priv, reg, &v); + if (ret != 0) + return ret; + v &= ~mask; + v |= data; + ret = max2165_write_reg(priv, reg, v); + + return ret; +} + +static int max2165_read_rom_table(struct max2165_priv *priv) +{ + u8 dat[3]; + int i; + + for (i = 0; i < 3; i++) { + max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1); + max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]); + } + + priv->tf_ntch_low_cfg = dat[0] >> 4; + priv->tf_ntch_hi_cfg = dat[0] & 0x0F; + priv->tf_balun_low_ref = dat[1] & 0x0F; + priv->tf_balun_hi_ref = dat[1] >> 4; + priv->bb_filter_7mhz_cfg = dat[2] & 0x0F; + priv->bb_filter_8mhz_cfg = dat[2] >> 4; + + dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg); + dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg); + dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref); + dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref); + dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg); + dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg); + + return 0; +} + +static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/) +{ + u8 v; + + v = (osc / 2); + if (v == 2) + v = 0x7; + else + v -= 8; + + max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v); + + return 0; +} + +static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw) +{ + u8 val; + + if (bw == BANDWIDTH_8_MHZ) + val = priv->bb_filter_8mhz_cfg; + else + val = priv->bb_filter_7mhz_cfg; + + max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4); + + return 0; +} + +int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction) +{ + u32 remainder; + u32 q, f = 0; + int i; + + if (0 == divisor) + return -1; + + q = dividend / divisor; + remainder = dividend - q * divisor; + + for (i = 0; i < 31; i++) { + remainder <<= 1; + if (remainder >= divisor) { + f += 1; + remainder -= divisor; + } + f <<= 1; + } + + *quotient = q; + *fraction = f; + + return 0; +} + +static int max2165_set_rf(struct max2165_priv *priv, u32 freq) +{ + u8 tf; + u8 tf_ntch; + u32 t; + u32 quotient, fraction; + + /* Set PLL divider according to RF frequency */ + fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, + "ient, &fraction); + + /* 20-bit fraction */ + fraction >>= 12; + + max2165_write_reg(priv, REG_NDIV_INT, quotient); + max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16); + max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8); + max2165_write_reg(priv, REG_NDIV_FRAC0, fraction); + + /* Norch Filter */ + tf_ntch = (freq < 725000000) ? + priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg; + + /* Tracking filter balun */ + t = priv->tf_balun_low_ref; + t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref) + * (freq / 1000 - 470000) / (780000 - 470000); + + tf = t; + dprintk("tf = %X\n", tf); + tf |= tf_ntch << 4; + + max2165_write_reg(priv, REG_TRACK_FILTER, tf); + + return 0; +} + +static void max2165_debug_status(struct max2165_priv *priv) +{ + u8 status, autotune; + u8 auto_vco_success, auto_vco_active; + u8 pll_locked; + u8 dc_offset_low, dc_offset_hi; + u8 signal_lv_over_threshold; + u8 vco, vco_sub_band, adc; + + max2165_read_reg(priv, REG_STATUS, &status); + max2165_read_reg(priv, REG_AUTOTUNE, &autotune); + + auto_vco_success = (status >> 6) & 0x01; + auto_vco_active = (status >> 5) & 0x01; + pll_locked = (status >> 4) & 0x01; + dc_offset_low = (status >> 3) & 0x01; + dc_offset_hi = (status >> 2) & 0x01; + signal_lv_over_threshold = status & 0x01; + + vco = autotune >> 6; + vco_sub_band = (autotune >> 3) & 0x7; + adc = autotune & 0x7; + + dprintk("auto VCO active: %d, auto VCO success: %d\n", + auto_vco_active, auto_vco_success); + dprintk("PLL locked: %d\n", pll_locked); + dprintk("DC offset low: %d, DC offset high: %d\n", + dc_offset_low, dc_offset_hi); + dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold); + dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc); +} + +static int max2165_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct max2165_priv *priv = fe->tuner_priv; + int ret; + + dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency); + if (fe->ops.info.type == FE_ATSC) { + return -EINVAL; + } else if (fe->ops.info.type == FE_OFDM) { + dprintk("%s() OFDM\n", __func__); + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + return -EINVAL; + case BANDWIDTH_7_MHZ: + case BANDWIDTH_8_MHZ: + priv->frequency = params->frequency; + priv->bandwidth = params->u.ofdm.bandwidth; + break; + default: + printk(KERN_ERR "MAX2165 bandwidth not set!\n"); + return -EINVAL; + } + } else { + printk(KERN_ERR "MAX2165 modulation type not supported!\n"); + return -EINVAL; + } + + dprintk("%s() frequency=%d\n", __func__, priv->frequency); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + max2165_set_bandwidth(priv, priv->bandwidth); + ret = max2165_set_rf(priv, priv->frequency); + mdelay(50); + max2165_debug_status(priv); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret != 0) + return -EREMOTEIO; + + return 0; +} + +static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct max2165_priv *priv = fe->tuner_priv; + dprintk("%s()\n", __func__); + *freq = priv->frequency; + return 0; +} + +static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct max2165_priv *priv = fe->tuner_priv; + dprintk("%s()\n", __func__); + + *bw = priv->bandwidth; + return 0; +} + +static int max2165_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct max2165_priv *priv = fe->tuner_priv; + u16 lock_status = 0; + + dprintk("%s()\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + max2165_debug_status(priv); + *status = lock_status; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int max2165_sleep(struct dvb_frontend *fe) +{ + dprintk("%s()\n", __func__); + return 0; +} + +static int max2165_init(struct dvb_frontend *fe) +{ + struct max2165_priv *priv = fe->tuner_priv; + dprintk("%s()\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* Setup initial values */ + /* Fractional Mode on */ + max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18); + /* LNA on */ + max2165_write_reg(priv, REG_LNA, 0x01); + max2165_write_reg(priv, REG_PLL_CFG, 0x7A); + max2165_write_reg(priv, REG_TEST, 0x08); + max2165_write_reg(priv, REG_SHUTDOWN, 0x40); + max2165_write_reg(priv, REG_VCO_CTRL, 0x84); + max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3); + max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75); + max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00); + max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00); + + max2165_set_osc(priv, priv->config->osc_clk); + + max2165_read_rom_table(priv); + + max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int max2165_release(struct dvb_frontend *fe) +{ + struct max2165_priv *priv = fe->tuner_priv; + dprintk("%s()\n", __func__); + + kfree(priv); + fe->tuner_priv = NULL; + + return 0; +} + +static const struct dvb_tuner_ops max2165_tuner_ops = { + .info = { + .name = "Maxim MAX2165", + .frequency_min = 470000000, + .frequency_max = 780000000, + .frequency_step = 50000, + }, + + .release = max2165_release, + .init = max2165_init, + .sleep = max2165_sleep, + + .set_params = max2165_set_params, + .set_analog_params = NULL, + .get_frequency = max2165_get_frequency, + .get_bandwidth = max2165_get_bandwidth, + .get_status = max2165_get_status +}; + +struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct max2165_config *cfg) +{ + struct max2165_priv *priv = NULL; + + dprintk("%s(%d-%04x)\n", __func__, + i2c ? i2c_adapter_id(i2c) : -1, + cfg ? cfg->i2c_address : -1); + + priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + priv->config = cfg; + priv->i2c = i2c; + fe->tuner_priv = priv; + + max2165_init(fe); + max2165_debug_status(priv); + + return fe; +} +EXPORT_SYMBOL(max2165_attach); + +MODULE_AUTHOR("David T. L. Wong "); +MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Driver for Maxim MAX2165 silicon tuner + * + * Copyright (c) 2009 David T. L. Wong + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MAX2165_H__ +#define __MAX2165_H__ + +struct dvb_frontend; +struct i2c_adapter; + +struct max2165_config { + u8 i2c_address; + u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */ +}; + +#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \ + (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE)) +extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct max2165_config *cfg); +#else +static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct max2165_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/max2165_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Driver for Maxim MAX2165 silicon tuner + * + * Copyright (c) 2009 David T. L. Wong + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MAX2165_PRIV_H__ +#define __MAX2165_PRIV_H__ + +#define REG_NDIV_INT 0x00 +#define REG_NDIV_FRAC2 0x01 +#define REG_NDIV_FRAC1 0x02 +#define REG_NDIV_FRAC0 0x03 +#define REG_TRACK_FILTER 0x04 +#define REG_LNA 0x05 +#define REG_PLL_CFG 0x06 +#define REG_TEST 0x07 +#define REG_SHUTDOWN 0x08 +#define REG_VCO_CTRL 0x09 +#define REG_BASEBAND_CTRL 0x0A +#define REG_DC_OFFSET_CTRL 0x0B +#define REG_DC_OFFSET_DAC 0x0C +#define REG_ROM_TABLE_ADDR 0x0D + +/* Read Only Registers */ +#define REG_ROM_TABLE_DATA 0x10 +#define REG_STATUS 0x11 +#define REG_AUTOTUNE 0x12 + +struct max2165_priv { + struct max2165_config *config; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; + + u8 tf_ntch_low_cfg; + u8 tf_ntch_hi_cfg; + u8 tf_balun_low_ref; + u8 tf_balun_hi_ref; + u8 bb_filter_7mhz_cfg; + u8 bb_filter_8mhz_cfg; +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,372 @@ +/* + * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner + * + * Copyright (c) 2009 Jochen Friedrich + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "mc44s803.h" +#include "mc44s803_priv.h" + +#define mc_printk(level, format, arg...) \ + printk(level "mc44s803: " format , ## arg) + +/* Writes a single register */ +static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val) +{ + u8 buf[3]; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3 + }; + + buf[0] = (val & 0xff0000) >> 16; + buf[1] = (val & 0xff00) >> 8; + buf[2] = (val & 0xff); + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + mc_printk(KERN_WARNING, "I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +/* Reads a single register */ +static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val) +{ + u32 wval; + u8 buf[3]; + int ret; + struct i2c_msg msg[] = { + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, + .buf = buf, .len = 3 }, + }; + + wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) | + MC44S803_REG_SM(reg, MC44S803_D); + + ret = mc44s803_writereg(priv, wval); + if (ret) + return ret; + + if (i2c_transfer(priv->i2c, msg, 1) != 1) { + mc_printk(KERN_WARNING, "I2C read failed\n"); + return -EREMOTEIO; + } + + *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + + return 0; +} + +static int mc44s803_release(struct dvb_frontend *fe) +{ + struct mc44s803_priv *priv = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(priv); + + return 0; +} + +static int mc44s803_init(struct dvb_frontend *fe) +{ + struct mc44s803_priv *priv = fe->tuner_priv; + u32 val; + int err; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + +/* Reset chip */ + val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_RS); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + +/* Power Up and Start Osc */ + + val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | + MC44S803_REG_SM(0xC0, MC44S803_REFOSC) | + MC44S803_REG_SM(1, MC44S803_OSCSEL); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) | + MC44S803_REG_SM(0x200, MC44S803_POWER); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + msleep(10); + + val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | + MC44S803_REG_SM(0x40, MC44S803_REFOSC) | + MC44S803_REG_SM(1, MC44S803_OSCSEL); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + msleep(20); + +/* Setup Mixer */ + + val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_TRI_STATE) | + MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + +/* Setup Cirquit Adjust */ + + val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_G1) | + MC44S803_REG_SM(1, MC44S803_G3) | + MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | + MC44S803_REG_SM(1, MC44S803_G6) | + MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | + MC44S803_REG_SM(0x3, MC44S803_LP) | + MC44S803_REG_SM(1, MC44S803_CLRF) | + MC44S803_REG_SM(1, MC44S803_CLIF); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_G1) | + MC44S803_REG_SM(1, MC44S803_G3) | + MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | + MC44S803_REG_SM(1, MC44S803_G6) | + MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | + MC44S803_REG_SM(0x3, MC44S803_LP); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + +/* Setup Digtune */ + + val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | + MC44S803_REG_SM(3, MC44S803_XOD); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + +/* Setup AGC */ + + val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_AT1) | + MC44S803_REG_SM(1, MC44S803_AT2) | + MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) | + MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) | + MC44S803_REG_SM(1, MC44S803_LNA0); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + return 0; + +exit: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + mc_printk(KERN_WARNING, "I/O Error\n"); + return err; +} + +static int mc44s803_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mc44s803_priv *priv = fe->tuner_priv; + u32 r1, r2, n1, n2, lo1, lo2, freq, val; + int err; + + priv->frequency = params->frequency; + + r1 = MC44S803_OSC / 1000000; + r2 = MC44S803_OSC / 100000; + + n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000; + freq = MC44S803_OSC / r1 * n1; + lo1 = ((60 * n1) + (r1 / 2)) / r1; + freq = freq - params->frequency; + + n2 = (freq - MC44S803_IF2 + 50000) / 100000; + lo2 = ((60 * n2) + (r2 / 2)) / r2; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) | + MC44S803_REG_SM(r1-1, MC44S803_R1) | + MC44S803_REG_SM(r2-1, MC44S803_R2) | + MC44S803_REG_SM(1, MC44S803_REFBUF_EN); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) | + MC44S803_REG_SM(n1-2, MC44S803_LO1); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) | + MC44S803_REG_SM(n2-2, MC44S803_LO2); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | + MC44S803_REG_SM(1, MC44S803_DA) | + MC44S803_REG_SM(lo1, MC44S803_LO_REF) | + MC44S803_REG_SM(1, MC44S803_AT); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | + MC44S803_REG_SM(2, MC44S803_DA) | + MC44S803_REG_SM(lo2, MC44S803_LO_REF) | + MC44S803_REG_SM(1, MC44S803_AT); + + err = mc44s803_writereg(priv, val); + if (err) + goto exit; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; + +exit: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + mc_printk(KERN_WARNING, "I/O Error\n"); + return err; +} + +static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mc44s803_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static const struct dvb_tuner_ops mc44s803_tuner_ops = { + .info = { + .name = "Freescale MC44S803", + .frequency_min = 48000000, + .frequency_max = 1000000000, + .frequency_step = 100000, + }, + + .release = mc44s803_release, + .init = mc44s803_init, + .set_params = mc44s803_set_params, + .get_frequency = mc44s803_get_frequency +}; + +/* This functions tries to identify a MC44S803 tuner by reading the ID + register. This is hasty. */ +struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct mc44s803_config *cfg) +{ + struct mc44s803_priv *priv; + u32 reg; + u8 id; + int ret; + + reg = 0; + + priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + priv->fe = fe; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = mc44s803_readreg(priv, MC44S803_REG_ID, ®); + if (ret) + goto error; + + id = MC44S803_REG_MS(reg, MC44S803_ID); + + if (id != 0x14) { + mc_printk(KERN_ERR, "unsupported ID " + "(%x should be 0x14)\n", id); + goto error; + } + + mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id); + memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return fe; + +error: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + kfree(priv); + return NULL; +} +EXPORT_SYMBOL(mc44s803_attach); + +MODULE_AUTHOR("Jochen Friedrich"); +MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner + * + * Copyright (c) 2009 Jochen Friedrich + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef MC44S803_H +#define MC44S803_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mc44s803_config { + u8 i2c_address; + u8 dig_out; +}; + +#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \ + (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE)) +extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct mc44s803_config *cfg); +#else +static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct mc44s803_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_MEDIA_TUNER_MC44S803 */ + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mc44s803_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,208 @@ +/* + * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner + * + * Copyright (c) 2009 Jochen Friedrich + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef MC44S803_PRIV_H +#define MC44S803_PRIV_H + +/* This driver is based on the information available in the datasheet + http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf + + SPI or I2C Address : 0xc0-0xc6 + + Reg.No | Function + ------------------------------------------- + 00 | Power Down + 01 | Reference Oszillator + 02 | Reference Dividers + 03 | Mixer and Reference Buffer + 04 | Reset/Serial Out + 05 | LO 1 + 06 | LO 2 + 07 | Circuit Adjust + 08 | Test + 09 | Digital Tune + 0A | LNA AGC + 0B | Data Register Address + 0C | Regulator Test + 0D | VCO Test + 0E | LNA Gain/Input Power + 0F | ID Bits + +*/ + +#define MC44S803_OSC 26000000 /* 26 MHz */ +#define MC44S803_IF1 1086000000 /* 1086 MHz */ +#define MC44S803_IF2 36125000 /* 36.125 MHz */ + +#define MC44S803_REG_POWER 0 +#define MC44S803_REG_REFOSC 1 +#define MC44S803_REG_REFDIV 2 +#define MC44S803_REG_MIXER 3 +#define MC44S803_REG_RESET 4 +#define MC44S803_REG_LO1 5 +#define MC44S803_REG_LO2 6 +#define MC44S803_REG_CIRCADJ 7 +#define MC44S803_REG_TEST 8 +#define MC44S803_REG_DIGTUNE 9 +#define MC44S803_REG_LNAAGC 0x0A +#define MC44S803_REG_DATAREG 0x0B +#define MC44S803_REG_REGTEST 0x0C +#define MC44S803_REG_VCOTEST 0x0D +#define MC44S803_REG_LNAGAIN 0x0E +#define MC44S803_REG_ID 0x0F + +/* Register definitions */ +#define MC44S803_ADDR 0x0F +#define MC44S803_ADDR_S 0 +/* REG_POWER */ +#define MC44S803_POWER 0xFFFFF0 +#define MC44S803_POWER_S 4 +/* REG_REFOSC */ +#define MC44S803_REFOSC 0x1FF0 +#define MC44S803_REFOSC_S 4 +#define MC44S803_OSCSEL 0x2000 +#define MC44S803_OSCSEL_S 13 +/* REG_REFDIV */ +#define MC44S803_R2 0x1FF0 +#define MC44S803_R2_S 4 +#define MC44S803_REFBUF_EN 0x2000 +#define MC44S803_REFBUF_EN_S 13 +#define MC44S803_R1 0x7C000 +#define MC44S803_R1_S 14 +/* REG_MIXER */ +#define MC44S803_R3 0x70 +#define MC44S803_R3_S 4 +#define MC44S803_MUX3 0x80 +#define MC44S803_MUX3_S 7 +#define MC44S803_MUX4 0x100 +#define MC44S803_MUX4_S 8 +#define MC44S803_OSC_SCR 0x200 +#define MC44S803_OSC_SCR_S 9 +#define MC44S803_TRI_STATE 0x400 +#define MC44S803_TRI_STATE_S 10 +#define MC44S803_BUF_GAIN 0x800 +#define MC44S803_BUF_GAIN_S 11 +#define MC44S803_BUF_IO 0x1000 +#define MC44S803_BUF_IO_S 12 +#define MC44S803_MIXER_RES 0xFE000 +#define MC44S803_MIXER_RES_S 13 +/* REG_RESET */ +#define MC44S803_RS 0x10 +#define MC44S803_RS_S 4 +#define MC44S803_SO 0x20 +#define MC44S803_SO_S 5 +/* REG_LO1 */ +#define MC44S803_LO1 0xFFF0 +#define MC44S803_LO1_S 4 +/* REG_LO2 */ +#define MC44S803_LO2 0x7FFF0 +#define MC44S803_LO2_S 4 +/* REG_CIRCADJ */ +#define MC44S803_G1 0x20 +#define MC44S803_G1_S 5 +#define MC44S803_G3 0x80 +#define MC44S803_G3_S 7 +#define MC44S803_CIRCADJ_RES 0x300 +#define MC44S803_CIRCADJ_RES_S 8 +#define MC44S803_G6 0x400 +#define MC44S803_G6_S 10 +#define MC44S803_G7 0x800 +#define MC44S803_G7_S 11 +#define MC44S803_S1 0x1000 +#define MC44S803_S1_S 12 +#define MC44S803_LP 0x7E000 +#define MC44S803_LP_S 13 +#define MC44S803_CLRF 0x80000 +#define MC44S803_CLRF_S 19 +#define MC44S803_CLIF 0x100000 +#define MC44S803_CLIF_S 20 +/* REG_TEST */ +/* REG_DIGTUNE */ +#define MC44S803_DA 0xF0 +#define MC44S803_DA_S 4 +#define MC44S803_XOD 0x300 +#define MC44S803_XOD_S 8 +#define MC44S803_RST 0x10000 +#define MC44S803_RST_S 16 +#define MC44S803_LO_REF 0x1FFF00 +#define MC44S803_LO_REF_S 8 +#define MC44S803_AT 0x200000 +#define MC44S803_AT_S 21 +#define MC44S803_MT 0x400000 +#define MC44S803_MT_S 22 +/* REG_LNAAGC */ +#define MC44S803_G 0x3F0 +#define MC44S803_G_S 4 +#define MC44S803_AT1 0x400 +#define MC44S803_AT1_S 10 +#define MC44S803_AT2 0x800 +#define MC44S803_AT2_S 11 +#define MC44S803_HL_GR_EN 0x8000 +#define MC44S803_HL_GR_EN_S 15 +#define MC44S803_AGC_AN_DIG 0x10000 +#define MC44S803_AGC_AN_DIG_S 16 +#define MC44S803_ATTEN_EN 0x20000 +#define MC44S803_ATTEN_EN_S 17 +#define MC44S803_AGC_READ_EN 0x40000 +#define MC44S803_AGC_READ_EN_S 18 +#define MC44S803_LNA0 0x80000 +#define MC44S803_LNA0_S 19 +#define MC44S803_AGC_SEL 0x100000 +#define MC44S803_AGC_SEL_S 20 +#define MC44S803_AT0 0x200000 +#define MC44S803_AT0_S 21 +#define MC44S803_B 0xC00000 +#define MC44S803_B_S 22 +/* REG_DATAREG */ +#define MC44S803_D 0xF0 +#define MC44S803_D_S 4 +/* REG_REGTEST */ +/* REG_VCOTEST */ +/* REG_LNAGAIN */ +#define MC44S803_IF_PWR 0x700 +#define MC44S803_IF_PWR_S 8 +#define MC44S803_RF_PWR 0x3800 +#define MC44S803_RF_PWR_S 11 +#define MC44S803_LNA_GAIN 0xFC000 +#define MC44S803_LNA_GAIN_S 14 +/* REG_ID */ +#define MC44S803_ID 0x3E00 +#define MC44S803_ID_S 9 + +/* Some macros to read/write fields */ + +/* First shift, then mask */ +#define MC44S803_REG_SM(_val, _reg) \ + (((_val) << _reg##_S) & (_reg)) + +/* First mask, then shift */ +#define MC44S803_REG_MS(_val, _reg) \ + (((_val) & (_reg)) >> _reg##_S) + +struct mc44s803_priv { + struct mc44s803_config *cfg; + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + + u32 frequency; +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,404 @@ +/* + * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" + * + * Copyright (c) 2006 Olivier DANET + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "mt2060.h" +#include "mt2060_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0) + +// Reads a single register +static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "mt2060 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a single register +static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 + }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2060 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a set of consecutive registers +static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +// Initialisation sequences +// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49 +static u8 mt2060_config1[] = { + REG_LO1C1, + 0x3F, 0x74, 0x00, 0x08, 0x93 +}; + +// FMCG=2, GP2=0, GP1=0 +static u8 mt2060_config2[] = { + REG_MISC_CTRL, + 0x20, 0x1E, 0x30, 0xff, 0x80, 0xff, 0x00, 0x2c, 0x42 +}; + +// VGAG=3, V1CSE=1 + +#ifdef MT2060_SPURCHECK +/* The function below calculates the frequency offset between the output frequency if2 + and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */ +static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2) +{ + int I,J; + int dia,diamin,diff; + diamin=1000000; + for (I = 1; I < 10; I++) { + J = ((2*I*lo1)/lo2+1)/2; + diff = I*(int)lo1-J*(int)lo2; + if (diff < 0) diff=-diff; + dia = (diff-(int)if2); + if (dia < 0) dia=-dia; + if (diamin > dia) diamin=dia; + } + return diamin; +} + +#define BANDWIDTH 4000 // kHz + +/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */ +static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2) +{ + u32 Spur,Sp1,Sp2; + int I,J; + I=0; + J=1000; + + Spur=mt2060_spurcalc(lo1,lo2,if2); + if (Spur < BANDWIDTH) { + /* Potential spurs detected */ + dprintk("Spurs before : f_lo1: %d f_lo2: %d (kHz)", + (int)lo1,(int)lo2); + I=1000; + Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2); + Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2); + + if (Sp1 < Sp2) { + J=-J; I=-I; Spur=Sp2; + } else + Spur=Sp1; + + while (Spur < BANDWIDTH) { + I += J; + Spur = mt2060_spurcalc(lo1+I,lo2+I,if2); + } + dprintk("Spurs after : f_lo1: %d f_lo2: %d (kHz)", + (int)(lo1+I),(int)(lo2+I)); + } + return I; +} +#endif + +#define IF2 36150 // IF2 frequency = 36.150 MHz +#define FREF 16000 // Quartz oscillator 16 MHz + +static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mt2060_priv *priv; + int ret=0; + int i=0; + u32 freq; + u8 lnaband; + u32 f_lo1,f_lo2; + u32 div1,num1,div2,num2; + u8 b[8]; + u32 if1; + + priv = fe->tuner_priv; + + if1 = priv->if1_freq; + b[0] = REG_LO1B1; + b[1] = 0xFF; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + mt2060_writeregs(priv,b,2); + + freq = params->frequency / 1000; // Hz -> kHz + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + + f_lo1 = freq + if1 * 1000; + f_lo1 = (f_lo1 / 250) * 250; + f_lo2 = f_lo1 - freq - IF2; + // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise + f_lo2 = ((f_lo2 + 25) / 50) * 50; + priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000, + +#ifdef MT2060_SPURCHECK + // LO-related spurs detection and correction + num1 = mt2060_spurcheck(f_lo1,f_lo2,IF2); + f_lo1 += num1; + f_lo2 += num1; +#endif + //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 ) + num1 = f_lo1 / (FREF / 64); + div1 = num1 / 64; + num1 &= 0x3f; + + // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) + num2 = f_lo2 * 64 / (FREF / 128); + div2 = num2 / 8192; + num2 &= 0x1fff; + + if (freq <= 95000) lnaband = 0xB0; else + if (freq <= 180000) lnaband = 0xA0; else + if (freq <= 260000) lnaband = 0x90; else + if (freq <= 335000) lnaband = 0x80; else + if (freq <= 425000) lnaband = 0x70; else + if (freq <= 480000) lnaband = 0x60; else + if (freq <= 570000) lnaband = 0x50; else + if (freq <= 645000) lnaband = 0x40; else + if (freq <= 730000) lnaband = 0x30; else + if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10; + + b[0] = REG_LO1C1; + b[1] = lnaband | ((num1 >>2) & 0x0F); + b[2] = div1; + b[3] = (num2 & 0x0F) | ((num1 & 3) << 4); + b[4] = num2 >> 4; + b[5] = ((num2 >>12) & 1) | (div2 << 1); + + dprintk("IF1: %dMHz",(int)if1); + dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2); + dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2); + dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]); + + mt2060_writeregs(priv,b,6); + + //Waits for pll lock or timeout + i = 0; + do { + mt2060_readreg(priv,REG_LO_STATUS,b); + if ((b[0] & 0x88)==0x88) + break; + msleep(4); + i++; + } while (i<10); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return ret; +} + +static void mt2060_calibrate(struct mt2060_priv *priv) +{ + u8 b = 0; + int i = 0; + + if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1))) + return; + if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2))) + return; + + /* initialize the clock output */ + mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30); + + do { + b |= (1 << 6); // FM1SS; + mt2060_writereg(priv, REG_LO2C1,b); + msleep(20); + + if (i == 0) { + b |= (1 << 7); // FM1CA; + mt2060_writereg(priv, REG_LO2C1,b); + b &= ~(1 << 7); // FM1CA; + msleep(20); + } + + b &= ~(1 << 6); // FM1SS + mt2060_writereg(priv, REG_LO2C1,b); + + msleep(20); + i++; + } while (i < 9); + + i = 0; + while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0) + msleep(20); + + if (i <= 10) { + mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :) + dprintk("calibration was successful: %d", (int)priv->fmfreq); + } else + dprintk("FMCAL timed out"); +} + +static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2060_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2060_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2060_init(struct dvb_frontend *fe) +{ + struct mt2060_priv *priv = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = mt2060_writereg(priv, REG_VGAG, + (priv->cfg->clock_out << 6) | 0x33); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return ret; +} + +static int mt2060_sleep(struct dvb_frontend *fe) +{ + struct mt2060_priv *priv = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = mt2060_writereg(priv, REG_VGAG, + (priv->cfg->clock_out << 6) | 0x30); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return ret; +} + +static int mt2060_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2060_tuner_ops = { + .info = { + .name = "Microtune MT2060", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mt2060_release, + + .init = mt2060_init, + .sleep = mt2060_sleep, + + .set_params = mt2060_set_params, + .get_frequency = mt2060_get_frequency, + .get_bandwidth = mt2060_get_bandwidth +}; + +/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ +struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) +{ + struct mt2060_priv *priv = NULL; + u8 id = 0; + + priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + priv->if1_freq = if1; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) { + kfree(priv); + return NULL; + } + + if (id != PART_REV) { + kfree(priv); + return NULL; + } + printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1); + memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + mt2060_calibrate(priv); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return fe; +} +EXPORT_SYMBOL(mt2060_attach); + +MODULE_AUTHOR("Olivier DANET"); +MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" + * + * Copyright (c) 2006 Olivier DANET + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef MT2060_H +#define MT2060_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2060_config { + u8 i2c_address; + u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ +}; + +#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE)) +extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); +#else +static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_MEDIA_TUNER_MT2060 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2060_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,105 @@ +/* + * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" + * + * Copyright (c) 2006 Olivier DANET + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef MT2060_PRIV_H +#define MT2060_PRIV_H + +// Uncomment the #define below to enable spurs checking. The results where quite unconvincing. +// #define MT2060_SPURCHECK + +/* This driver is based on the information available in the datasheet of the + "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map : + + I2C Address : 0x60 + + Reg.No | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | ( defaults ) + -------------------------------------------------------------------------------- + 00 | [ PART ] | [ REV ] | R = 0x63 + 01 | [ LNABAND ] | [ NUM1(5:2) ] | RW = 0x3F + 02 | [ DIV1 ] | RW = 0x74 + 03 | FM1CA | FM1SS | [ NUM1(1:0) ] | [ NUM2(3:0) ] | RW = 0x00 + 04 | NUM2(11:4) ] | RW = 0x08 + 05 | [ DIV2 ] |NUM2(12)| RW = 0x93 + 06 | L1LK | [ TAD1 ] | L2LK | [ TAD2 ] | R + 07 | [ FMF ] | R + 08 | ? | FMCAL | ? | ? | ? | ? | ? | TEMP | R + 09 | 0 | 0 | [ FMGC ] | 0 | GP02 | GP01 | 0 | RW = 0x20 + 0A | ?? + 0B | 0 | 0 | 1 | 1 | 0 | 0 | [ VGAG ] | RW = 0x30 + 0C | V1CSE | 1 | 1 | 1 | 1 | 1 | 1 | 1 | RW = 0xFF + 0D | 1 | 0 | [ V1CS ] | RW = 0xB0 + 0E | ?? + 0F | ?? + 10 | ?? + 11 | [ LOTO ] | 0 | 0 | 1 | 0 | RW = 0x42 + + PART : Part code : 6 for MT2060 + REV : Revision code : 3 for current revision + LNABAND : Input frequency range : ( See code for details ) + NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details ) + FM1CA : Calibration Start Bit + FM1SS : Calibration Single Step bit + L1LK : LO1 Lock Detect + TAD1 : Tune Line ADC ( ? ) + L2LK : LO2 Lock Detect + TAD2 : Tune Line ADC ( ? ) + FMF : Estimated first IF Center frequency Offset ( ? ) + FM1CAL : Calibration done bit + TEMP : On chip temperature sensor + FMCG : Mixer 1 Cap Gain ( ? ) + GP01 / GP02 : Programmable digital outputs. Unconnected pins ? + V1CSE : LO1 VCO Automatic Capacitor Select Enable ( ? ) + V1CS : LO1 Capacitor Selection Value ( ? ) + LOTO : LO Timeout ( ? ) + VGAG : Tuner Output gain +*/ + +#define I2C_ADDRESS 0x60 + +#define REG_PART_REV 0 +#define REG_LO1C1 1 +#define REG_LO1C2 2 +#define REG_LO2C1 3 +#define REG_LO2C2 4 +#define REG_LO2C3 5 +#define REG_LO_STATUS 6 +#define REG_FM_FREQ 7 +#define REG_MISC_STAT 8 +#define REG_MISC_CTRL 9 +#define REG_RESERVED_A 0x0A +#define REG_VGAG 0x0B +#define REG_LO1B1 0x0C +#define REG_LO1B2 0x0D +#define REG_LOTO 0x11 + +#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips + +struct mt2060_priv { + struct mt2060_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; + u16 if1_freq; + u8 fmfreq; +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt20xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt20xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt20xx.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt20xx.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,672 @@ +/* + * i2c tv tuner chip device driver + * controls microtune tuners, mt2032 + mt2050 at the moment. + * + * This "mt20xx" module was split apart from the original "tuner" module. + */ +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "mt20xx.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +/* ---------------------------------------------------------------------- */ + +static unsigned int optimize_vco = 1; +module_param(optimize_vco, int, 0644); + +static unsigned int tv_antenna = 1; +module_param(tv_antenna, int, 0644); + +static unsigned int radio_antenna; +module_param(radio_antenna, int, 0644); + +/* ---------------------------------------------------------------------- */ + +#define MT2032 0x04 +#define MT2030 0x06 +#define MT2040 0x07 +#define MT2050 0x42 + +static char *microtune_part[] = { + [ MT2030 ] = "MT2030", + [ MT2032 ] = "MT2032", + [ MT2040 ] = "MT2040", + [ MT2050 ] = "MT2050", +}; + +struct microtune_priv { + struct tuner_i2c_props i2c_props; + + unsigned int xogc; + //unsigned int radio_if2; + + u32 frequency; +}; + +static int microtune_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct microtune_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +// IsSpurInBand()? +static int mt2032_spurcheck(struct dvb_frontend *fe, + int f1, int f2, int spectrum_from,int spectrum_to) +{ + struct microtune_priv *priv = fe->tuner_priv; + int n1=1,n2,f; + + f1=f1/1000; //scale to kHz to avoid 32bit overflows + f2=f2/1000; + spectrum_from/=1000; + spectrum_to/=1000; + + tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n", + f1,f2,spectrum_from,spectrum_to); + + do { + n2=-n1; + f=n1*(f1-f2); + do { + n2--; + f=f-f2; + tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); + + if( (f>spectrum_from) && (f(f2-spectrum_to)) || (n2>-5)); + n1++; + } while (n1<5); + + return 1; +} + +static int mt2032_compute_freq(struct dvb_frontend *fe, + unsigned int rfin, + unsigned int if1, unsigned int if2, + unsigned int spectrum_from, + unsigned int spectrum_to, + unsigned char *buf, + int *ret_sel, + unsigned int xogc) //all in Hz +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, + desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; + + fref= 5250 *1000; //5.25MHz + desired_lo1=rfin+if1; + + lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); + lo1n=lo1/8; + lo1a=lo1-(lo1n*8); + + s=rfin/1000/1000+1090; + + if(optimize_vco) { + if(s>1890) sel=0; + else if(s>1720) sel=1; + else if(s>1530) sel=2; + else if(s>1370) sel=3; + else sel=4; // >1090 + } + else { + if(s>1790) sel=0; // <1958 + else if(s>1617) sel=1; + else if(s>1449) sel=2; + else if(s>1291) sel=3; + else sel=4; // >1090 + } + *ret_sel=sel; + + lo1freq=(lo1a+8*lo1n)*fref; + + tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", + rfin,lo1,lo1n,lo1a,sel,lo1freq); + + desired_lo2=lo1freq-rfin-if2; + lo2=(desired_lo2)/fref; + lo2n=lo2/8; + lo2a=lo2-(lo2n*8); + lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith + lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; + + tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", + rfin,lo2,lo2n,lo2a,lo2num,lo2freq); + + if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 || + lo2n > 30) { + tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", + lo1a, lo1n, lo2a,lo2n); + return(-1); + } + + mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to); + // should recalculate lo1 (one step up/down) + + // set up MT2032 register map for transfer over i2c + buf[0]=lo1n-1; + buf[1]=lo1a | (sel<<4); + buf[2]=0x86; // LOGC + buf[3]=0x0f; //reserved + buf[4]=0x1f; + buf[5]=(lo2n-1) | (lo2a<<5); + if(rfin >400*1000*1000) + buf[6]=0xe4; + else + buf[6]=0xf4; // set PKEN per rev 1.2 + buf[7]=8+xogc; + buf[8]=0xc3; //reserved + buf[9]=0x4e; //reserved + buf[10]=0xec; //reserved + buf[11]=(lo2num&0xff); + buf[12]=(lo2num>>8) |0x80; // Lo2RST + + return 0; +} + +static int mt2032_check_lo_lock(struct dvb_frontend *fe) +{ + struct microtune_priv *priv = fe->tuner_priv; + int try,lock=0; + unsigned char buf[2]; + + for(try=0;try<10;try++) { + buf[0]=0x0e; + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); + tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); + lock=buf[0] &0x06; + + if (lock==6) + break; + + tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); + udelay(1000); + } + return lock; +} + +static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned char buf[2]; + int tad1; + + buf[0]=0x0f; + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); + tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); + tad1=buf[0]&0x07; + + if(tad1 ==0) return lock; + if(tad1 ==1) return lock; + + if(tad1==2) { + if(sel==0) + return lock; + else sel--; + } + else { + if(sel<4) + sel++; + else + return lock; + } + + tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel); + + buf[0]=0x0f; + buf[1]=sel; + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + lock=mt2032_check_lo_lock(fe); + return lock; +} + + +static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, + unsigned int if1, unsigned int if2, + unsigned int from, unsigned int to) +{ + unsigned char buf[21]; + int lint_try,ret,sel,lock=0; + struct microtune_priv *priv = fe->tuner_priv; + + tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", + rfin,if1,if2,from,to); + + buf[0]=0; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); + + buf[0]=0; + ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); + if (ret<0) + return; + + // send only the relevant registers per Rev. 1.2 + buf[0]=0; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); + buf[5]=5; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); + buf[11]=11; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); + if(ret!=3) + tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); + + // wait for PLLs to lock (per manual), retry LINT if not. + for(lint_try=0; lint_try<2; lint_try++) { + lock=mt2032_check_lo_lock(fe); + + if(optimize_vco) + lock=mt2032_optimize_vco(fe,sel,lock); + if(lock==6) break; + + tuner_dbg("mt2032: re-init PLLs by LINT\n"); + buf[0]=7; + buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + mdelay(10); + buf[1]=8+priv->xogc; + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + } + + if (lock!=6) + tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n"); + + buf[0]=2; + buf[1]=0x20; // LOGC for optimal phase noise + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + if (ret!=2) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); +} + + +static int mt2032_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + int if2,from,to; + + // signal bandwidth and picture carrier + if (params->std & V4L2_STD_525_60) { + // NTSC + from = 40750*1000; + to = 46750*1000; + if2 = 45750*1000; + } else { + // PAL + from = 32900*1000; + to = 39900*1000; + if2 = 38900*1000; + } + + mt2032_set_if_freq(fe, params->frequency*62500, + 1090*1000*1000, if2, from, to); + + return 0; +} + +static int mt2032_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int if2; + + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } + + // per Manual for FM tuning: first if center freq. 1085 MHz + mt2032_set_if_freq(fe, params->frequency * 125 / 2, + 1085*1000*1000,if2,if2,if2); + + return 0; +} + +static int mt2032_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2032_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2032_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + +static struct dvb_tuner_ops mt2032_tuner_ops = { + .set_analog_params = mt2032_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, +}; + +// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 +static int mt2032_init(struct dvb_frontend *fe) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned char buf[21]; + int ret,xogc,xok=0; + + // Initialize Registers per spec. + buf[1]=2; // Index to register 2 + buf[2]=0xff; + buf[3]=0x0f; + buf[4]=0x1f; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); + + buf[5]=6; // Index register 6 + buf[6]=0xe4; + buf[7]=0x8f; + buf[8]=0xc3; + buf[9]=0x4e; + buf[10]=0xec; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); + + buf[12]=13; // Index register 13 + buf[13]=0x32; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); + + // Adjust XOGC (register 7), wait for XOK + xogc=7; + do { + tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); + mdelay(10); + buf[0]=0x0e; + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); + xok=buf[0]&0x01; + tuner_dbg("mt2032: xok = 0x%02x\n",xok); + if (xok == 1) break; + + xogc--; + tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); + if (xogc == 3) { + xogc=4; // min. 4 per spec + break; + } + buf[0]=0x07; + buf[1]=0x88 + xogc; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + if (ret!=2) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); + } while (xok != 1 ); + priv->xogc=xogc; + + memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); + + return(1); +} + +static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned char buf[2]; + int ret; + + buf[0] = 6; + buf[1] = antenna ? 0x11 : 0x10; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); +} + +static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned int if1=1218*1000*1000; + unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; + int ret; + unsigned char buf[6]; + + tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", + freq,if1,if2); + + f_lo1=freq+if1; + f_lo1=(f_lo1/1000000)*1000000; + + f_lo2=f_lo1-freq-if2; + f_lo2=(f_lo2/50000)*50000; + + lo1=f_lo1/4000000; + lo2=f_lo2/4000000; + + f_lo1_modulo= f_lo1-(lo1*4000000); + f_lo2_modulo= f_lo2-(lo2*4000000); + + num1=4*f_lo1_modulo/4000000; + num2=4096*(f_lo2_modulo/1000)/4000; + + // todo spurchecks + + div1a=(lo1/12)-1; + div1b=lo1-(div1a+1)*12; + + div2a=(lo2/8)-1; + div2b=lo2-(div2a+1)*8; + + if (debug > 1) { + tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); + tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", + num1,num2,div1a,div1b,div2a,div2b); + } + + buf[0]=1; + buf[1]= 4*div1b + num1; + if(freq<275*1000*1000) buf[1] = buf[1]|0x80; + + buf[2]=div1a; + buf[3]=32*div2b + num2/256; + buf[4]=num2-(num2/256)*256; + buf[5]=div2a; + if(num2!=0) buf[5]=buf[5]|0x40; + + if (debug > 1) { + int i; + tuner_dbg("bufs is: "); + for(i=0;i<6;i++) + printk("%x ",buf[i]); + printk("\n"); + } + + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); + if (ret!=6) + tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); +} + +static int mt2050_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned int if2; + + if (params->std & V4L2_STD_525_60) { + // NTSC + if2 = 45750*1000; + } else { + // PAL + if2 = 38900*1000; + } + if (V4L2_TUNER_DIGITAL_TV == params->mode) { + // DVB (pinnacle 300i) + if2 = 36150*1000; + } + mt2050_set_if_freq(fe, params->frequency*62500, if2); + mt2050_set_antenna(fe, tv_antenna); + + return 0; +} + +static int mt2050_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int if2; + + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } + + mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); + mt2050_set_antenna(fe, radio_antenna); + + return 0; +} + +static int mt2050_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2050_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2050_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + +static struct dvb_tuner_ops mt2050_tuner_ops = { + .set_analog_params = mt2050_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, +}; + +static int mt2050_init(struct dvb_frontend *fe) +{ + struct microtune_priv *priv = fe->tuner_priv; + unsigned char buf[2]; + int ret; + + buf[0]=6; + buf[1]=0x10; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power + + buf[0]=0x0f; + buf[1]=0x0f; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo + + buf[0]=0x0d; + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); + + tuner_dbg("mt2050: sro is %x\n",buf[0]); + + memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); + + return 0; +} + +struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + struct microtune_priv *priv = NULL; + char *name; + unsigned char buf[21]; + int company_code; + + priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->tuner_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->i2c_props.name = "mt20xx"; + + //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ + + memset(buf,0,sizeof(buf)); + + name = "unknown"; + + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); + if (debug) { + int i; + tuner_dbg("MT20xx hexdump:"); + for(i=0;i<21;i++) { + printk(" %02x",buf[i]); + if(((i+1)%8)==0) printk(" "); + } + printk("\n"); + } + company_code = buf[0x11] << 8 | buf[0x12]; + tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", + company_code,buf[0x13],buf[0x14]); + + + if (buf[0x13] < ARRAY_SIZE(microtune_part) && + NULL != microtune_part[buf[0x13]]) + name = microtune_part[buf[0x13]]; + switch (buf[0x13]) { + case MT2032: + mt2032_init(fe); + break; + case MT2050: + mt2050_init(fe); + break; + default: + tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", + name); + return NULL; + } + + strlcpy(fe->ops.tuner_ops.info.name, name, + sizeof(fe->ops.tuner_ops.info.name)); + tuner_info("microtune %s found, OK\n",name); + return fe; +} + +EXPORT_SYMBOL_GPL(microtune_attach); + +MODULE_DESCRIPTION("Microtune tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt20xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt20xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt20xx.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt20xx.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MT20XX_H__ +#define __MT20XX_H__ + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE)) +extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); +#else +static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __MT20XX_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,315 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "mt2131.h" +#include "mt2131_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) + +static u8 mt2131_config1[] = { + 0x01, + 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, + 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, + 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, + 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 +}; + +static u8 mt2131_config2[] = { + 0x10, + 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 +}; + +static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, + .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "mt2131 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = buf, .len = 2 }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", + (int)len); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mt2131_priv *priv; + int ret=0, i; + u32 freq; + u8 if_band_center; + u32 f_lo1, f_lo2; + u32 div1, num1, div2, num2; + u8 b[8]; + u8 lockval = 0; + + priv = fe->tuner_priv; + if (fe->ops.info.type == FE_OFDM) + priv->bandwidth = params->u.ofdm.bandwidth; + else + priv->bandwidth = 0; + + freq = params->frequency / 1000; // Hz -> kHz + dprintk(1, "%s() freq=%d\n", __func__, freq); + + f_lo1 = freq + MT2131_IF1 * 1000; + f_lo1 = (f_lo1 / 250) * 250; + f_lo2 = f_lo1 - freq - MT2131_IF2; + + priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000; + + /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ + num1 = f_lo1 * 64 / (MT2131_FREF / 128); + div1 = num1 / 8192; + num1 &= 0x1fff; + + /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ + num2 = f_lo2 * 64 / (MT2131_FREF / 128); + div2 = num2 / 8192; + num2 &= 0x1fff; + + if (freq <= 82500) if_band_center = 0x00; else + if (freq <= 137500) if_band_center = 0x01; else + if (freq <= 192500) if_band_center = 0x02; else + if (freq <= 247500) if_band_center = 0x03; else + if (freq <= 302500) if_band_center = 0x04; else + if (freq <= 357500) if_band_center = 0x05; else + if (freq <= 412500) if_band_center = 0x06; else + if (freq <= 467500) if_band_center = 0x07; else + if (freq <= 522500) if_band_center = 0x08; else + if (freq <= 577500) if_band_center = 0x09; else + if (freq <= 632500) if_band_center = 0x0A; else + if (freq <= 687500) if_band_center = 0x0B; else + if (freq <= 742500) if_band_center = 0x0C; else + if (freq <= 797500) if_band_center = 0x0D; else + if (freq <= 852500) if_band_center = 0x0E; else + if (freq <= 907500) if_band_center = 0x0F; else + if (freq <= 962500) if_band_center = 0x10; else + if (freq <= 1017500) if_band_center = 0x11; else + if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; + + b[0] = 1; + b[1] = (num1 >> 5) & 0xFF; + b[2] = (num1 & 0x1F); + b[3] = div1; + b[4] = (num2 >> 5) & 0xFF; + b[5] = num2 & 0x1F; + b[6] = div2; + + dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); + dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); + dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); + dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", + (int)div1, (int)num1, (int)div2, (int)num2); + dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", + (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], + (int)b[6]); + + ret = mt2131_writeregs(priv,b,7); + if (ret < 0) + return ret; + + mt2131_writereg(priv, 0x0b, if_band_center); + + /* Wait for lock */ + i = 0; + do { + mt2131_readreg(priv, 0x08, &lockval); + if ((lockval & 0x88) == 0x88) + break; + msleep(4); + i++; + } while (i < 10); + + return ret; +} + +static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + *frequency = priv->frequency; + return 0; +} + +static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mt2131_priv *priv = fe->tuner_priv; + u8 lock_status = 0; + u8 afc_status = 0; + + *status = 0; + + mt2131_readreg(priv, 0x08, &lock_status); + if ((lock_status & 0x88) == 0x88) + *status = TUNER_STATUS_LOCKED; + + mt2131_readreg(priv, 0x09, &afc_status); + dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", + __func__, lock_status, afc_status); + + return 0; +} + +static int mt2131_init(struct dvb_frontend *fe) +{ + struct mt2131_priv *priv = fe->tuner_priv; + int ret; + dprintk(1, "%s()\n", __func__); + + if ((ret = mt2131_writeregs(priv, mt2131_config1, + sizeof(mt2131_config1))) < 0) + return ret; + + mt2131_writereg(priv, 0x0b, 0x09); + mt2131_writereg(priv, 0x15, 0x47); + mt2131_writereg(priv, 0x07, 0xf2); + mt2131_writereg(priv, 0x0b, 0x01); + + if ((ret = mt2131_writeregs(priv, mt2131_config2, + sizeof(mt2131_config2))) < 0) + return ret; + + return ret; +} + +static int mt2131_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __func__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2131_tuner_ops = { + .info = { + .name = "Microtune MT2131", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mt2131_release, + .init = mt2131_init, + + .set_params = mt2131_set_params, + .get_frequency = mt2131_get_frequency, + .get_bandwidth = mt2131_get_bandwidth, + .get_status = mt2131_get_status +}; + +struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, u16 if1) +{ + struct mt2131_priv *priv = NULL; + u8 id = 0; + + dprintk(1, "%s()\n", __func__); + + priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->bandwidth = 6000000; /* 6MHz */ + priv->i2c = i2c; + + if (mt2131_readreg(priv, 0, &id) != 0) { + kfree(priv); + return NULL; + } + if ( (id != 0x3E) && (id != 0x3F) ) { + printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", + cfg->i2c_address); + kfree(priv); + return NULL; + } + + printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", + cfg->i2c_address); + memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(mt2131_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MT2131_H__ +#define __MT2131_H__ + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2131_config { + u8 i2c_address; + u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ +}; + +#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE)) +extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1); +#else +static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_MEDIA_TUNER_MT2131 */ + +#endif /* __MT2131_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2131_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MT2131_PRIV_H__ +#define __MT2131_PRIV_H__ + +/* Regs */ +#define MT2131_PWR 0x07 +#define MT2131_UPC_1 0x0b +#define MT2131_AGC_RL 0x10 +#define MT2131_MISC_2 0x15 + +/* frequency values in KHz */ +#define MT2131_IF1 1220 +#define MT2131_IF2 44000 +#define MT2131_FREF 16000 + +struct mt2131_priv { + struct mt2131_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; +}; + +#endif /* __MT2131_PRIV_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2266.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2266.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2266.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2266.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,352 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * 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, or + * (at your option) any later version. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "mt2266.h" + +#define I2C_ADDRESS 0x60 + +#define REG_PART_REV 0 +#define REG_TUNE 1 +#define REG_BAND 6 +#define REG_BANDWIDTH 8 +#define REG_LOCK 0x12 + +#define PART_REV 0x85 + +struct mt2266_priv { + struct mt2266_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; + u8 band; +}; + +#define MT2266_VHF 1 +#define MT2266_UHF 0 + +/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) + +// Reads a single register +static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "MT2266 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a single register +static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a set of consecutive registers +static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +// Initialisation sequences +static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, + 0x00, 0x52, 0x99, 0x3f }; + +static u8 mt2266_init2[] = { + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, + 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, + 0xff, 0x00, 0x77, 0x0f, 0x2d +}; + +static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22 }; + +static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32 }; + +static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7 }; + +static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, + 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; + +static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, + 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; + +#define FREF 30000 // Quartz oscillator 30 MHz + +static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mt2266_priv *priv; + int ret=0; + u32 freq; + u32 tune; + u8 lnaband; + u8 b[10]; + int i; + u8 band; + + priv = fe->tuner_priv; + + freq = params->frequency / 1000; // Hz -> kHz + if (freq < 470000 && freq > 230000) + return -EINVAL; /* Gap between VHF and UHF bands */ + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->frequency = freq * 1000; + + tune = 2 * freq * (8192/16) / (FREF/16); + band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; + if (band == MT2266_VHF) + tune *= 2; + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + mt2266_writeregs(priv, mt2266_init_6mhz, + sizeof(mt2266_init_6mhz)); + break; + case BANDWIDTH_7_MHZ: + mt2266_writeregs(priv, mt2266_init_7mhz, + sizeof(mt2266_init_7mhz)); + break; + case BANDWIDTH_8_MHZ: + default: + mt2266_writeregs(priv, mt2266_init_8mhz, + sizeof(mt2266_init_8mhz)); + break; + } + + if (band == MT2266_VHF && priv->band == MT2266_UHF) { + dprintk("Switch from UHF to VHF"); + mt2266_writereg(priv, 0x05, 0x04); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); + } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { + dprintk("Switch from VHF to UHF"); + mt2266_writereg(priv, 0x05, 0x52); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); + } + msleep(10); + + if (freq <= 495000) + lnaband = 0xEE; + else if (freq <= 525000) + lnaband = 0xDD; + else if (freq <= 550000) + lnaband = 0xCC; + else if (freq <= 580000) + lnaband = 0xBB; + else if (freq <= 605000) + lnaband = 0xAA; + else if (freq <= 630000) + lnaband = 0x99; + else if (freq <= 655000) + lnaband = 0x88; + else if (freq <= 685000) + lnaband = 0x77; + else if (freq <= 710000) + lnaband = 0x66; + else if (freq <= 735000) + lnaband = 0x55; + else if (freq <= 765000) + lnaband = 0x44; + else if (freq <= 802000) + lnaband = 0x33; + else if (freq <= 840000) + lnaband = 0x22; + else + lnaband = 0x11; + + b[0] = REG_TUNE; + b[1] = (tune >> 8) & 0x1F; + b[2] = tune & 0xFF; + b[3] = tune >> 13; + mt2266_writeregs(priv,b,4); + + dprintk("set_parms: tune=%d band=%d %s", + (int) tune, (int) lnaband, + (band == MT2266_UHF) ? "UHF" : "VHF"); + dprintk("set_parms: [1..3]: %2x %2x %2x", + (int) b[1], (int) b[2], (int)b[3]); + + if (band == MT2266_UHF) { + b[0] = 0x05; + b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; + b[2] = lnaband; + mt2266_writeregs(priv, b, 3); + } + + /* Wait for pll lock or timeout */ + i = 0; + do { + mt2266_readreg(priv,REG_LOCK,b); + if (b[0] & 0x40) + break; + msleep(10); + i++; + } while (i<10); + dprintk("Lock when i=%i",(int)i); + + if (band == MT2266_UHF && priv->band == MT2266_VHF) + mt2266_writereg(priv, 0x05, 0x62); + + priv->band = band; + + return ret; +} + +static void mt2266_calibrate(struct mt2266_priv *priv) +{ + mt2266_writereg(priv, 0x11, 0x03); + mt2266_writereg(priv, 0x11, 0x01); + mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); + mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); + mt2266_writereg(priv, 0x33, 0x5e); + mt2266_writereg(priv, 0x10, 0x10); + mt2266_writereg(priv, 0x10, 0x00); + mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); + msleep(25); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); + msleep(75); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0xff); +} + +static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2266_init(struct dvb_frontend *fe) +{ + int ret; + struct mt2266_priv *priv = fe->tuner_priv; + ret = mt2266_writereg(priv, 0x17, 0x6d); + if (ret < 0) + return ret; + ret = mt2266_writereg(priv, 0x1c, 0xff); + if (ret < 0) + return ret; + return 0; +} + +static int mt2266_sleep(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); + return 0; +} + +static int mt2266_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2266_tuner_ops = { + .info = { + .name = "Microtune MT2266", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_step = 50000, + }, + .release = mt2266_release, + .init = mt2266_init, + .sleep = mt2266_sleep, + .set_params = mt2266_set_params, + .get_frequency = mt2266_get_frequency, + .get_bandwidth = mt2266_get_bandwidth +}; + +struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + struct mt2266_priv *priv = NULL; + u8 id = 0; + + priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + priv->band = MT2266_UHF; + + if (mt2266_readreg(priv, 0, &id)) { + kfree(priv); + return NULL; + } + if (id != PART_REV) { + kfree(priv); + return NULL; + } + printk(KERN_INFO "MT2266: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + mt2266_calibrate(priv); + return fe; +} +EXPORT_SYMBOL(mt2266_attach); + +MODULE_AUTHOR("Olivier DANET"); +MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2266.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2266.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2266.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mt2266.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * 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, or + * (at your option) any later version. + * + * 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. + */ + +#ifndef MT2266_H +#define MT2266_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2266_config { + u8 i2c_address; +}; + +#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE)) +extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); +#else +static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_MEDIA_TUNER_MT2266 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5005s.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5005s.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5005s.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5005s.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,4118 @@ +/* + MaxLinear MXL5005S VSB/QAM/DVBT tuner driver + + Copyright (C) 2008 MaxLinear + Copyright (C) 2006 Steven Toth + Functions: + mxl5005s_reset() + mxl5005s_writereg() + mxl5005s_writeregs() + mxl5005s_init() + mxl5005s_reconfigure() + mxl5005s_AssignTunerMode() + mxl5005s_set_params() + mxl5005s_get_frequency() + mxl5005s_get_bandwidth() + mxl5005s_release() + mxl5005s_attach() + + Copyright (C) 2008 Realtek + Copyright (C) 2008 Jan Hoogenraad + Functions: + mxl5005s_SetRfFreqHz() + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/* + History of this driver (Steven Toth): + I was given a public release of a linux driver that included + support for the MaxLinear MXL5005S silicon tuner. Analysis of + the tuner driver showed clearly three things. + + 1. The tuner driver didn't support the LinuxTV tuner API + so the code Realtek added had to be removed. + + 2. A significant amount of the driver is reference driver code + from MaxLinear, I felt it was important to identify and + preserve this. + + 3. New code has to be added to interface correctly with the + LinuxTV API, as a regular kernel module. + + Other than the reference driver enum's, I've clearly marked + sections of the code and retained the copyright of the + respective owners. +*/ +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "mxl5005s.h" + +static int debug; + +#define dprintk(level, arg...) do { \ + if (level <= debug) \ + printk(arg); \ + } while (0) + +#define TUNER_REGS_NUM 104 +#define INITCTRL_NUM 40 + +#ifdef _MXL_PRODUCTION +#define CHCTRL_NUM 39 +#else +#define CHCTRL_NUM 36 +#endif + +#define MXLCTRL_NUM 189 +#define MASTER_CONTROL_ADDR 9 + +/* Enumeration of Master Control Register State */ +enum master_control_state { + MC_LOAD_START = 1, + MC_POWER_DOWN, + MC_SYNTH_RESET, + MC_SEQ_OFF +}; + +/* Enumeration of MXL5005 Tuner Modulation Type */ +enum { + MXL_DEFAULT_MODULATION = 0, + MXL_DVBT, + MXL_ATSC, + MXL_QAM, + MXL_ANALOG_CABLE, + MXL_ANALOG_OTA +}; + +/* MXL5005 Tuner Register Struct */ +struct TunerReg { + u16 Reg_Num; /* Tuner Register Address */ + u16 Reg_Val; /* Current sw programmed value waiting to be written */ +}; + +enum { + /* Initialization Control Names */ + DN_IQTN_AMP_CUT = 1, /* 1 */ + BB_MODE, /* 2 */ + BB_BUF, /* 3 */ + BB_BUF_OA, /* 4 */ + BB_ALPF_BANDSELECT, /* 5 */ + BB_IQSWAP, /* 6 */ + BB_DLPF_BANDSEL, /* 7 */ + RFSYN_CHP_GAIN, /* 8 */ + RFSYN_EN_CHP_HIGAIN, /* 9 */ + AGC_IF, /* 10 */ + AGC_RF, /* 11 */ + IF_DIVVAL, /* 12 */ + IF_VCO_BIAS, /* 13 */ + CHCAL_INT_MOD_IF, /* 14 */ + CHCAL_FRAC_MOD_IF, /* 15 */ + DRV_RES_SEL, /* 16 */ + I_DRIVER, /* 17 */ + EN_AAF, /* 18 */ + EN_3P, /* 19 */ + EN_AUX_3P, /* 20 */ + SEL_AAF_BAND, /* 21 */ + SEQ_ENCLK16_CLK_OUT, /* 22 */ + SEQ_SEL4_16B, /* 23 */ + XTAL_CAPSELECT, /* 24 */ + IF_SEL_DBL, /* 25 */ + RFSYN_R_DIV, /* 26 */ + SEQ_EXTSYNTHCALIF, /* 27 */ + SEQ_EXTDCCAL, /* 28 */ + AGC_EN_RSSI, /* 29 */ + RFA_ENCLKRFAGC, /* 30 */ + RFA_RSSI_REFH, /* 31 */ + RFA_RSSI_REF, /* 32 */ + RFA_RSSI_REFL, /* 33 */ + RFA_FLR, /* 34 */ + RFA_CEIL, /* 35 */ + SEQ_EXTIQFSMPULSE, /* 36 */ + OVERRIDE_1, /* 37 */ + BB_INITSTATE_DLPF_TUNE, /* 38 */ + TG_R_DIV, /* 39 */ + EN_CHP_LIN_B, /* 40 */ + + /* Channel Change Control Names */ + DN_POLY = 51, /* 51 */ + DN_RFGAIN, /* 52 */ + DN_CAP_RFLPF, /* 53 */ + DN_EN_VHFUHFBAR, /* 54 */ + DN_GAIN_ADJUST, /* 55 */ + DN_IQTNBUF_AMP, /* 56 */ + DN_IQTNGNBFBIAS_BST, /* 57 */ + RFSYN_EN_OUTMUX, /* 58 */ + RFSYN_SEL_VCO_OUT, /* 59 */ + RFSYN_SEL_VCO_HI, /* 60 */ + RFSYN_SEL_DIVM, /* 61 */ + RFSYN_RF_DIV_BIAS, /* 62 */ + DN_SEL_FREQ, /* 63 */ + RFSYN_VCO_BIAS, /* 64 */ + CHCAL_INT_MOD_RF, /* 65 */ + CHCAL_FRAC_MOD_RF, /* 66 */ + RFSYN_LPF_R, /* 67 */ + CHCAL_EN_INT_RF, /* 68 */ + TG_LO_DIVVAL, /* 69 */ + TG_LO_SELVAL, /* 70 */ + TG_DIV_VAL, /* 71 */ + TG_VCO_BIAS, /* 72 */ + SEQ_EXTPOWERUP, /* 73 */ + OVERRIDE_2, /* 74 */ + OVERRIDE_3, /* 75 */ + OVERRIDE_4, /* 76 */ + SEQ_FSM_PULSE, /* 77 */ + GPIO_4B, /* 78 */ + GPIO_3B, /* 79 */ + GPIO_4, /* 80 */ + GPIO_3, /* 81 */ + GPIO_1B, /* 82 */ + DAC_A_ENABLE, /* 83 */ + DAC_B_ENABLE, /* 84 */ + DAC_DIN_A, /* 85 */ + DAC_DIN_B, /* 86 */ +#ifdef _MXL_PRODUCTION + RFSYN_EN_DIV, /* 87 */ + RFSYN_DIVM, /* 88 */ + DN_BYPASS_AGC_I2C /* 89 */ +#endif +}; + +/* + * The following context is source code provided by MaxLinear. + * MaxLinear source code - Common_MXL.h (?) + */ + +/* Constants */ +#define MXL5005S_REG_WRITING_TABLE_LEN_MAX 104 +#define MXL5005S_LATCH_BYTE 0xfe + +/* Register address, MSB, and LSB */ +#define MXL5005S_BB_IQSWAP_ADDR 59 +#define MXL5005S_BB_IQSWAP_MSB 0 +#define MXL5005S_BB_IQSWAP_LSB 0 + +#define MXL5005S_BB_DLPF_BANDSEL_ADDR 53 +#define MXL5005S_BB_DLPF_BANDSEL_MSB 4 +#define MXL5005S_BB_DLPF_BANDSEL_LSB 3 + +/* Standard modes */ +enum { + MXL5005S_STANDARD_DVBT, + MXL5005S_STANDARD_ATSC, +}; +#define MXL5005S_STANDARD_MODE_NUM 2 + +/* Bandwidth modes */ +enum { + MXL5005S_BANDWIDTH_6MHZ = 6000000, + MXL5005S_BANDWIDTH_7MHZ = 7000000, + MXL5005S_BANDWIDTH_8MHZ = 8000000, +}; +#define MXL5005S_BANDWIDTH_MODE_NUM 3 + +/* MXL5005 Tuner Control Struct */ +struct TunerControl { + u16 Ctrl_Num; /* Control Number */ + u16 size; /* Number of bits to represent Value */ + u16 addr[25]; /* Array of Tuner Register Address for each bit pos */ + u16 bit[25]; /* Array of bit pos in Reg Addr for each bit pos */ + u16 val[25]; /* Binary representation of Value */ +}; + +/* MXL5005 Tuner Struct */ +struct mxl5005s_state { + u8 Mode; /* 0: Analog Mode ; 1: Digital Mode */ + u8 IF_Mode; /* for Analog Mode, 0: zero IF; 1: low IF */ + u32 Chan_Bandwidth; /* filter channel bandwidth (6, 7, 8) */ + u32 IF_OUT; /* Desired IF Out Frequency */ + u16 IF_OUT_LOAD; /* IF Out Load Resistor (200/300 Ohms) */ + u32 RF_IN; /* RF Input Frequency */ + u32 Fxtal; /* XTAL Frequency */ + u8 AGC_Mode; /* AGC Mode 0: Dual AGC; 1: Single AGC */ + u16 TOP; /* Value: take over point */ + u8 CLOCK_OUT; /* 0: turn off clk out; 1: turn on clock out */ + u8 DIV_OUT; /* 4MHz or 16MHz */ + u8 CAPSELECT; /* 0: disable On-Chip pulling cap; 1: enable */ + u8 EN_RSSI; /* 0: disable RSSI; 1: enable RSSI */ + + /* Modulation Type; */ + /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ + u8 Mod_Type; + + /* Tracking Filter Type */ + /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ + u8 TF_Type; + + /* Calculated Settings */ + u32 RF_LO; /* Synth RF LO Frequency */ + u32 IF_LO; /* Synth IF LO Frequency */ + u32 TG_LO; /* Synth TG_LO Frequency */ + + /* Pointers to ControlName Arrays */ + u16 Init_Ctrl_Num; /* Number of INIT Control Names */ + struct TunerControl + Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */ + + u16 CH_Ctrl_Num; /* Number of CH Control Names */ + struct TunerControl + CH_Ctrl[CHCTRL_NUM]; /* CH Control Name Array Pointer */ + + u16 MXL_Ctrl_Num; /* Number of MXL Control Names */ + struct TunerControl + MXL_Ctrl[MXLCTRL_NUM]; /* MXL Control Name Array Pointer */ + + /* Pointer to Tuner Register Array */ + u16 TunerRegs_Num; /* Number of Tuner Registers */ + struct TunerReg + TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */ + + /* Linux driver framework specific */ + struct mxl5005s_config *config; + struct dvb_frontend *frontend; + struct i2c_adapter *i2c; + + /* Cache values */ + u32 current_mode; + +}; + +static u16 MXL_GetMasterControl(u8 *MasterReg, int state); +static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value); +static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value); +static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, + u8 bitVal); +static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count); +static u32 MXL_Ceiling(u32 value, u32 resolution); +static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal); +static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, + u32 value, u16 controlGroup); +static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val); +static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count); +static u32 MXL_GetXtalInt(u32 Xtal_Freq); +static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq); +static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe); +static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe); +static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count); +static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, + u8 *datatable, u8 len); +static u16 MXL_IFSynthInit(struct dvb_frontend *fe); +static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, + u32 bandwidth); +static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, + u32 bandwidth); + +/* ---------------------------------------------------------------- + * Begin: Custom code salvaged from the Realtek driver. + * Copyright (C) 2008 Realtek + * Copyright (C) 2008 Jan Hoogenraad + * This code is placed under the terms of the GNU General Public License + * + * Released by Realtek under GPLv2. + * Thanks to Realtek for a lot of support we received ! + * + * Revision: 080314 - original version + */ + +static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz) +{ + struct mxl5005s_state *state = fe->tuner_priv; + unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; + unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; + int TableLen; + + u32 IfDivval = 0; + unsigned char MasterControlByte; + + dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz); + + /* Set MxL5005S tuner RF frequency according to example code. */ + + /* Tuner RF frequency setting stage 0 */ + MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); + AddrTable[0] = MASTER_CONTROL_ADDR; + ByteTable[0] |= state->config->AgcMasterByte; + + mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); + + /* Tuner RF frequency setting stage 1 */ + MXL_TuneRF(fe, RfFreqHz); + + MXL_ControlRead(fe, IF_DIVVAL, &IfDivval); + + MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0); + MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1); + MXL_ControlWrite(fe, IF_DIVVAL, 8); + MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen); + + MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); + AddrTable[TableLen] = MASTER_CONTROL_ADDR ; + ByteTable[TableLen] = MasterControlByte | + state->config->AgcMasterByte; + TableLen += 1; + + mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); + + /* Wait 30 ms. */ + msleep(150); + + /* Tuner RF frequency setting stage 2 */ + MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1); + MXL_ControlWrite(fe, IF_DIVVAL, IfDivval); + MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen); + + MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); + AddrTable[TableLen] = MASTER_CONTROL_ADDR ; + ByteTable[TableLen] = MasterControlByte | + state->config->AgcMasterByte ; + TableLen += 1; + + mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); + + msleep(100); + + return 0; +} +/* End: Custom code taken from the Realtek driver */ + +/* ---------------------------------------------------------------- + * Begin: Reference driver code found in the Realtek driver. + * Copyright (C) 2008 MaxLinear + */ +static u16 MXL5005_RegisterInit(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + state->TunerRegs_Num = TUNER_REGS_NUM ; + + state->TunerRegs[0].Reg_Num = 9 ; + state->TunerRegs[0].Reg_Val = 0x40 ; + + state->TunerRegs[1].Reg_Num = 11 ; + state->TunerRegs[1].Reg_Val = 0x19 ; + + state->TunerRegs[2].Reg_Num = 12 ; + state->TunerRegs[2].Reg_Val = 0x60 ; + + state->TunerRegs[3].Reg_Num = 13 ; + state->TunerRegs[3].Reg_Val = 0x00 ; + + state->TunerRegs[4].Reg_Num = 14 ; + state->TunerRegs[4].Reg_Val = 0x00 ; + + state->TunerRegs[5].Reg_Num = 15 ; + state->TunerRegs[5].Reg_Val = 0xC0 ; + + state->TunerRegs[6].Reg_Num = 16 ; + state->TunerRegs[6].Reg_Val = 0x00 ; + + state->TunerRegs[7].Reg_Num = 17 ; + state->TunerRegs[7].Reg_Val = 0x00 ; + + state->TunerRegs[8].Reg_Num = 18 ; + state->TunerRegs[8].Reg_Val = 0x00 ; + + state->TunerRegs[9].Reg_Num = 19 ; + state->TunerRegs[9].Reg_Val = 0x34 ; + + state->TunerRegs[10].Reg_Num = 21 ; + state->TunerRegs[10].Reg_Val = 0x00 ; + + state->TunerRegs[11].Reg_Num = 22 ; + state->TunerRegs[11].Reg_Val = 0x6B ; + + state->TunerRegs[12].Reg_Num = 23 ; + state->TunerRegs[12].Reg_Val = 0x35 ; + + state->TunerRegs[13].Reg_Num = 24 ; + state->TunerRegs[13].Reg_Val = 0x70 ; + + state->TunerRegs[14].Reg_Num = 25 ; + state->TunerRegs[14].Reg_Val = 0x3E ; + + state->TunerRegs[15].Reg_Num = 26 ; + state->TunerRegs[15].Reg_Val = 0x82 ; + + state->TunerRegs[16].Reg_Num = 31 ; + state->TunerRegs[16].Reg_Val = 0x00 ; + + state->TunerRegs[17].Reg_Num = 32 ; + state->TunerRegs[17].Reg_Val = 0x40 ; + + state->TunerRegs[18].Reg_Num = 33 ; + state->TunerRegs[18].Reg_Val = 0x53 ; + + state->TunerRegs[19].Reg_Num = 34 ; + state->TunerRegs[19].Reg_Val = 0x81 ; + + state->TunerRegs[20].Reg_Num = 35 ; + state->TunerRegs[20].Reg_Val = 0xC9 ; + + state->TunerRegs[21].Reg_Num = 36 ; + state->TunerRegs[21].Reg_Val = 0x01 ; + + state->TunerRegs[22].Reg_Num = 37 ; + state->TunerRegs[22].Reg_Val = 0x00 ; + + state->TunerRegs[23].Reg_Num = 41 ; + state->TunerRegs[23].Reg_Val = 0x00 ; + + state->TunerRegs[24].Reg_Num = 42 ; + state->TunerRegs[24].Reg_Val = 0xF8 ; + + state->TunerRegs[25].Reg_Num = 43 ; + state->TunerRegs[25].Reg_Val = 0x43 ; + + state->TunerRegs[26].Reg_Num = 44 ; + state->TunerRegs[26].Reg_Val = 0x20 ; + + state->TunerRegs[27].Reg_Num = 45 ; + state->TunerRegs[27].Reg_Val = 0x80 ; + + state->TunerRegs[28].Reg_Num = 46 ; + state->TunerRegs[28].Reg_Val = 0x88 ; + + state->TunerRegs[29].Reg_Num = 47 ; + state->TunerRegs[29].Reg_Val = 0x86 ; + + state->TunerRegs[30].Reg_Num = 48 ; + state->TunerRegs[30].Reg_Val = 0x00 ; + + state->TunerRegs[31].Reg_Num = 49 ; + state->TunerRegs[31].Reg_Val = 0x00 ; + + state->TunerRegs[32].Reg_Num = 53 ; + state->TunerRegs[32].Reg_Val = 0x94 ; + + state->TunerRegs[33].Reg_Num = 54 ; + state->TunerRegs[33].Reg_Val = 0xFA ; + + state->TunerRegs[34].Reg_Num = 55 ; + state->TunerRegs[34].Reg_Val = 0x92 ; + + state->TunerRegs[35].Reg_Num = 56 ; + state->TunerRegs[35].Reg_Val = 0x80 ; + + state->TunerRegs[36].Reg_Num = 57 ; + state->TunerRegs[36].Reg_Val = 0x41 ; + + state->TunerRegs[37].Reg_Num = 58 ; + state->TunerRegs[37].Reg_Val = 0xDB ; + + state->TunerRegs[38].Reg_Num = 59 ; + state->TunerRegs[38].Reg_Val = 0x00 ; + + state->TunerRegs[39].Reg_Num = 60 ; + state->TunerRegs[39].Reg_Val = 0x00 ; + + state->TunerRegs[40].Reg_Num = 61 ; + state->TunerRegs[40].Reg_Val = 0x00 ; + + state->TunerRegs[41].Reg_Num = 62 ; + state->TunerRegs[41].Reg_Val = 0x00 ; + + state->TunerRegs[42].Reg_Num = 65 ; + state->TunerRegs[42].Reg_Val = 0xF8 ; + + state->TunerRegs[43].Reg_Num = 66 ; + state->TunerRegs[43].Reg_Val = 0xE4 ; + + state->TunerRegs[44].Reg_Num = 67 ; + state->TunerRegs[44].Reg_Val = 0x90 ; + + state->TunerRegs[45].Reg_Num = 68 ; + state->TunerRegs[45].Reg_Val = 0xC0 ; + + state->TunerRegs[46].Reg_Num = 69 ; + state->TunerRegs[46].Reg_Val = 0x01 ; + + state->TunerRegs[47].Reg_Num = 70 ; + state->TunerRegs[47].Reg_Val = 0x50 ; + + state->TunerRegs[48].Reg_Num = 71 ; + state->TunerRegs[48].Reg_Val = 0x06 ; + + state->TunerRegs[49].Reg_Num = 72 ; + state->TunerRegs[49].Reg_Val = 0x00 ; + + state->TunerRegs[50].Reg_Num = 73 ; + state->TunerRegs[50].Reg_Val = 0x20 ; + + state->TunerRegs[51].Reg_Num = 76 ; + state->TunerRegs[51].Reg_Val = 0xBB ; + + state->TunerRegs[52].Reg_Num = 77 ; + state->TunerRegs[52].Reg_Val = 0x13 ; + + state->TunerRegs[53].Reg_Num = 81 ; + state->TunerRegs[53].Reg_Val = 0x04 ; + + state->TunerRegs[54].Reg_Num = 82 ; + state->TunerRegs[54].Reg_Val = 0x75 ; + + state->TunerRegs[55].Reg_Num = 83 ; + state->TunerRegs[55].Reg_Val = 0x00 ; + + state->TunerRegs[56].Reg_Num = 84 ; + state->TunerRegs[56].Reg_Val = 0x00 ; + + state->TunerRegs[57].Reg_Num = 85 ; + state->TunerRegs[57].Reg_Val = 0x00 ; + + state->TunerRegs[58].Reg_Num = 91 ; + state->TunerRegs[58].Reg_Val = 0x70 ; + + state->TunerRegs[59].Reg_Num = 92 ; + state->TunerRegs[59].Reg_Val = 0x00 ; + + state->TunerRegs[60].Reg_Num = 93 ; + state->TunerRegs[60].Reg_Val = 0x00 ; + + state->TunerRegs[61].Reg_Num = 94 ; + state->TunerRegs[61].Reg_Val = 0x00 ; + + state->TunerRegs[62].Reg_Num = 95 ; + state->TunerRegs[62].Reg_Val = 0x0C ; + + state->TunerRegs[63].Reg_Num = 96 ; + state->TunerRegs[63].Reg_Val = 0x00 ; + + state->TunerRegs[64].Reg_Num = 97 ; + state->TunerRegs[64].Reg_Val = 0x00 ; + + state->TunerRegs[65].Reg_Num = 98 ; + state->TunerRegs[65].Reg_Val = 0xE2 ; + + state->TunerRegs[66].Reg_Num = 99 ; + state->TunerRegs[66].Reg_Val = 0x00 ; + + state->TunerRegs[67].Reg_Num = 100 ; + state->TunerRegs[67].Reg_Val = 0x00 ; + + state->TunerRegs[68].Reg_Num = 101 ; + state->TunerRegs[68].Reg_Val = 0x12 ; + + state->TunerRegs[69].Reg_Num = 102 ; + state->TunerRegs[69].Reg_Val = 0x80 ; + + state->TunerRegs[70].Reg_Num = 103 ; + state->TunerRegs[70].Reg_Val = 0x32 ; + + state->TunerRegs[71].Reg_Num = 104 ; + state->TunerRegs[71].Reg_Val = 0xB4 ; + + state->TunerRegs[72].Reg_Num = 105 ; + state->TunerRegs[72].Reg_Val = 0x60 ; + + state->TunerRegs[73].Reg_Num = 106 ; + state->TunerRegs[73].Reg_Val = 0x83 ; + + state->TunerRegs[74].Reg_Num = 107 ; + state->TunerRegs[74].Reg_Val = 0x84 ; + + state->TunerRegs[75].Reg_Num = 108 ; + state->TunerRegs[75].Reg_Val = 0x9C ; + + state->TunerRegs[76].Reg_Num = 109 ; + state->TunerRegs[76].Reg_Val = 0x02 ; + + state->TunerRegs[77].Reg_Num = 110 ; + state->TunerRegs[77].Reg_Val = 0x81 ; + + state->TunerRegs[78].Reg_Num = 111 ; + state->TunerRegs[78].Reg_Val = 0xC0 ; + + state->TunerRegs[79].Reg_Num = 112 ; + state->TunerRegs[79].Reg_Val = 0x10 ; + + state->TunerRegs[80].Reg_Num = 131 ; + state->TunerRegs[80].Reg_Val = 0x8A ; + + state->TunerRegs[81].Reg_Num = 132 ; + state->TunerRegs[81].Reg_Val = 0x10 ; + + state->TunerRegs[82].Reg_Num = 133 ; + state->TunerRegs[82].Reg_Val = 0x24 ; + + state->TunerRegs[83].Reg_Num = 134 ; + state->TunerRegs[83].Reg_Val = 0x00 ; + + state->TunerRegs[84].Reg_Num = 135 ; + state->TunerRegs[84].Reg_Val = 0x00 ; + + state->TunerRegs[85].Reg_Num = 136 ; + state->TunerRegs[85].Reg_Val = 0x7E ; + + state->TunerRegs[86].Reg_Num = 137 ; + state->TunerRegs[86].Reg_Val = 0x40 ; + + state->TunerRegs[87].Reg_Num = 138 ; + state->TunerRegs[87].Reg_Val = 0x38 ; + + state->TunerRegs[88].Reg_Num = 146 ; + state->TunerRegs[88].Reg_Val = 0xF6 ; + + state->TunerRegs[89].Reg_Num = 147 ; + state->TunerRegs[89].Reg_Val = 0x1A ; + + state->TunerRegs[90].Reg_Num = 148 ; + state->TunerRegs[90].Reg_Val = 0x62 ; + + state->TunerRegs[91].Reg_Num = 149 ; + state->TunerRegs[91].Reg_Val = 0x33 ; + + state->TunerRegs[92].Reg_Num = 150 ; + state->TunerRegs[92].Reg_Val = 0x80 ; + + state->TunerRegs[93].Reg_Num = 156 ; + state->TunerRegs[93].Reg_Val = 0x56 ; + + state->TunerRegs[94].Reg_Num = 157 ; + state->TunerRegs[94].Reg_Val = 0x17 ; + + state->TunerRegs[95].Reg_Num = 158 ; + state->TunerRegs[95].Reg_Val = 0xA9 ; + + state->TunerRegs[96].Reg_Num = 159 ; + state->TunerRegs[96].Reg_Val = 0x00 ; + + state->TunerRegs[97].Reg_Num = 160 ; + state->TunerRegs[97].Reg_Val = 0x00 ; + + state->TunerRegs[98].Reg_Num = 161 ; + state->TunerRegs[98].Reg_Val = 0x00 ; + + state->TunerRegs[99].Reg_Num = 162 ; + state->TunerRegs[99].Reg_Val = 0x40 ; + + state->TunerRegs[100].Reg_Num = 166 ; + state->TunerRegs[100].Reg_Val = 0xAE ; + + state->TunerRegs[101].Reg_Num = 167 ; + state->TunerRegs[101].Reg_Val = 0x1B ; + + state->TunerRegs[102].Reg_Num = 168 ; + state->TunerRegs[102].Reg_Val = 0xF2 ; + + state->TunerRegs[103].Reg_Num = 195 ; + state->TunerRegs[103].Reg_Val = 0x00 ; + + return 0 ; +} + +static u16 MXL5005_ControlInit(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + state->Init_Ctrl_Num = INITCTRL_NUM; + + state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ; + state->Init_Ctrl[0].size = 1 ; + state->Init_Ctrl[0].addr[0] = 73; + state->Init_Ctrl[0].bit[0] = 7; + state->Init_Ctrl[0].val[0] = 0; + + state->Init_Ctrl[1].Ctrl_Num = BB_MODE ; + state->Init_Ctrl[1].size = 1 ; + state->Init_Ctrl[1].addr[0] = 53; + state->Init_Ctrl[1].bit[0] = 2; + state->Init_Ctrl[1].val[0] = 1; + + state->Init_Ctrl[2].Ctrl_Num = BB_BUF ; + state->Init_Ctrl[2].size = 2 ; + state->Init_Ctrl[2].addr[0] = 53; + state->Init_Ctrl[2].bit[0] = 1; + state->Init_Ctrl[2].val[0] = 0; + state->Init_Ctrl[2].addr[1] = 57; + state->Init_Ctrl[2].bit[1] = 0; + state->Init_Ctrl[2].val[1] = 1; + + state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ; + state->Init_Ctrl[3].size = 1 ; + state->Init_Ctrl[3].addr[0] = 53; + state->Init_Ctrl[3].bit[0] = 0; + state->Init_Ctrl[3].val[0] = 0; + + state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ; + state->Init_Ctrl[4].size = 3 ; + state->Init_Ctrl[4].addr[0] = 53; + state->Init_Ctrl[4].bit[0] = 5; + state->Init_Ctrl[4].val[0] = 0; + state->Init_Ctrl[4].addr[1] = 53; + state->Init_Ctrl[4].bit[1] = 6; + state->Init_Ctrl[4].val[1] = 0; + state->Init_Ctrl[4].addr[2] = 53; + state->Init_Ctrl[4].bit[2] = 7; + state->Init_Ctrl[4].val[2] = 1; + + state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ; + state->Init_Ctrl[5].size = 1 ; + state->Init_Ctrl[5].addr[0] = 59; + state->Init_Ctrl[5].bit[0] = 0; + state->Init_Ctrl[5].val[0] = 0; + + state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ; + state->Init_Ctrl[6].size = 2 ; + state->Init_Ctrl[6].addr[0] = 53; + state->Init_Ctrl[6].bit[0] = 3; + state->Init_Ctrl[6].val[0] = 0; + state->Init_Ctrl[6].addr[1] = 53; + state->Init_Ctrl[6].bit[1] = 4; + state->Init_Ctrl[6].val[1] = 1; + + state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ; + state->Init_Ctrl[7].size = 4 ; + state->Init_Ctrl[7].addr[0] = 22; + state->Init_Ctrl[7].bit[0] = 4; + state->Init_Ctrl[7].val[0] = 0; + state->Init_Ctrl[7].addr[1] = 22; + state->Init_Ctrl[7].bit[1] = 5; + state->Init_Ctrl[7].val[1] = 1; + state->Init_Ctrl[7].addr[2] = 22; + state->Init_Ctrl[7].bit[2] = 6; + state->Init_Ctrl[7].val[2] = 1; + state->Init_Ctrl[7].addr[3] = 22; + state->Init_Ctrl[7].bit[3] = 7; + state->Init_Ctrl[7].val[3] = 0; + + state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ; + state->Init_Ctrl[8].size = 1 ; + state->Init_Ctrl[8].addr[0] = 22; + state->Init_Ctrl[8].bit[0] = 2; + state->Init_Ctrl[8].val[0] = 0; + + state->Init_Ctrl[9].Ctrl_Num = AGC_IF ; + state->Init_Ctrl[9].size = 4 ; + state->Init_Ctrl[9].addr[0] = 76; + state->Init_Ctrl[9].bit[0] = 0; + state->Init_Ctrl[9].val[0] = 1; + state->Init_Ctrl[9].addr[1] = 76; + state->Init_Ctrl[9].bit[1] = 1; + state->Init_Ctrl[9].val[1] = 1; + state->Init_Ctrl[9].addr[2] = 76; + state->Init_Ctrl[9].bit[2] = 2; + state->Init_Ctrl[9].val[2] = 0; + state->Init_Ctrl[9].addr[3] = 76; + state->Init_Ctrl[9].bit[3] = 3; + state->Init_Ctrl[9].val[3] = 1; + + state->Init_Ctrl[10].Ctrl_Num = AGC_RF ; + state->Init_Ctrl[10].size = 4 ; + state->Init_Ctrl[10].addr[0] = 76; + state->Init_Ctrl[10].bit[0] = 4; + state->Init_Ctrl[10].val[0] = 1; + state->Init_Ctrl[10].addr[1] = 76; + state->Init_Ctrl[10].bit[1] = 5; + state->Init_Ctrl[10].val[1] = 1; + state->Init_Ctrl[10].addr[2] = 76; + state->Init_Ctrl[10].bit[2] = 6; + state->Init_Ctrl[10].val[2] = 0; + state->Init_Ctrl[10].addr[3] = 76; + state->Init_Ctrl[10].bit[3] = 7; + state->Init_Ctrl[10].val[3] = 1; + + state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ; + state->Init_Ctrl[11].size = 5 ; + state->Init_Ctrl[11].addr[0] = 43; + state->Init_Ctrl[11].bit[0] = 3; + state->Init_Ctrl[11].val[0] = 0; + state->Init_Ctrl[11].addr[1] = 43; + state->Init_Ctrl[11].bit[1] = 4; + state->Init_Ctrl[11].val[1] = 0; + state->Init_Ctrl[11].addr[2] = 43; + state->Init_Ctrl[11].bit[2] = 5; + state->Init_Ctrl[11].val[2] = 0; + state->Init_Ctrl[11].addr[3] = 43; + state->Init_Ctrl[11].bit[3] = 6; + state->Init_Ctrl[11].val[3] = 1; + state->Init_Ctrl[11].addr[4] = 43; + state->Init_Ctrl[11].bit[4] = 7; + state->Init_Ctrl[11].val[4] = 0; + + state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ; + state->Init_Ctrl[12].size = 6 ; + state->Init_Ctrl[12].addr[0] = 44; + state->Init_Ctrl[12].bit[0] = 2; + state->Init_Ctrl[12].val[0] = 0; + state->Init_Ctrl[12].addr[1] = 44; + state->Init_Ctrl[12].bit[1] = 3; + state->Init_Ctrl[12].val[1] = 0; + state->Init_Ctrl[12].addr[2] = 44; + state->Init_Ctrl[12].bit[2] = 4; + state->Init_Ctrl[12].val[2] = 0; + state->Init_Ctrl[12].addr[3] = 44; + state->Init_Ctrl[12].bit[3] = 5; + state->Init_Ctrl[12].val[3] = 1; + state->Init_Ctrl[12].addr[4] = 44; + state->Init_Ctrl[12].bit[4] = 6; + state->Init_Ctrl[12].val[4] = 0; + state->Init_Ctrl[12].addr[5] = 44; + state->Init_Ctrl[12].bit[5] = 7; + state->Init_Ctrl[12].val[5] = 0; + + state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ; + state->Init_Ctrl[13].size = 7 ; + state->Init_Ctrl[13].addr[0] = 11; + state->Init_Ctrl[13].bit[0] = 0; + state->Init_Ctrl[13].val[0] = 1; + state->Init_Ctrl[13].addr[1] = 11; + state->Init_Ctrl[13].bit[1] = 1; + state->Init_Ctrl[13].val[1] = 0; + state->Init_Ctrl[13].addr[2] = 11; + state->Init_Ctrl[13].bit[2] = 2; + state->Init_Ctrl[13].val[2] = 0; + state->Init_Ctrl[13].addr[3] = 11; + state->Init_Ctrl[13].bit[3] = 3; + state->Init_Ctrl[13].val[3] = 1; + state->Init_Ctrl[13].addr[4] = 11; + state->Init_Ctrl[13].bit[4] = 4; + state->Init_Ctrl[13].val[4] = 1; + state->Init_Ctrl[13].addr[5] = 11; + state->Init_Ctrl[13].bit[5] = 5; + state->Init_Ctrl[13].val[5] = 0; + state->Init_Ctrl[13].addr[6] = 11; + state->Init_Ctrl[13].bit[6] = 6; + state->Init_Ctrl[13].val[6] = 0; + + state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ; + state->Init_Ctrl[14].size = 16 ; + state->Init_Ctrl[14].addr[0] = 13; + state->Init_Ctrl[14].bit[0] = 0; + state->Init_Ctrl[14].val[0] = 0; + state->Init_Ctrl[14].addr[1] = 13; + state->Init_Ctrl[14].bit[1] = 1; + state->Init_Ctrl[14].val[1] = 0; + state->Init_Ctrl[14].addr[2] = 13; + state->Init_Ctrl[14].bit[2] = 2; + state->Init_Ctrl[14].val[2] = 0; + state->Init_Ctrl[14].addr[3] = 13; + state->Init_Ctrl[14].bit[3] = 3; + state->Init_Ctrl[14].val[3] = 0; + state->Init_Ctrl[14].addr[4] = 13; + state->Init_Ctrl[14].bit[4] = 4; + state->Init_Ctrl[14].val[4] = 0; + state->Init_Ctrl[14].addr[5] = 13; + state->Init_Ctrl[14].bit[5] = 5; + state->Init_Ctrl[14].val[5] = 0; + state->Init_Ctrl[14].addr[6] = 13; + state->Init_Ctrl[14].bit[6] = 6; + state->Init_Ctrl[14].val[6] = 0; + state->Init_Ctrl[14].addr[7] = 13; + state->Init_Ctrl[14].bit[7] = 7; + state->Init_Ctrl[14].val[7] = 0; + state->Init_Ctrl[14].addr[8] = 12; + state->Init_Ctrl[14].bit[8] = 0; + state->Init_Ctrl[14].val[8] = 0; + state->Init_Ctrl[14].addr[9] = 12; + state->Init_Ctrl[14].bit[9] = 1; + state->Init_Ctrl[14].val[9] = 0; + state->Init_Ctrl[14].addr[10] = 12; + state->Init_Ctrl[14].bit[10] = 2; + state->Init_Ctrl[14].val[10] = 0; + state->Init_Ctrl[14].addr[11] = 12; + state->Init_Ctrl[14].bit[11] = 3; + state->Init_Ctrl[14].val[11] = 0; + state->Init_Ctrl[14].addr[12] = 12; + state->Init_Ctrl[14].bit[12] = 4; + state->Init_Ctrl[14].val[12] = 0; + state->Init_Ctrl[14].addr[13] = 12; + state->Init_Ctrl[14].bit[13] = 5; + state->Init_Ctrl[14].val[13] = 1; + state->Init_Ctrl[14].addr[14] = 12; + state->Init_Ctrl[14].bit[14] = 6; + state->Init_Ctrl[14].val[14] = 1; + state->Init_Ctrl[14].addr[15] = 12; + state->Init_Ctrl[14].bit[15] = 7; + state->Init_Ctrl[14].val[15] = 0; + + state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ; + state->Init_Ctrl[15].size = 3 ; + state->Init_Ctrl[15].addr[0] = 147; + state->Init_Ctrl[15].bit[0] = 2; + state->Init_Ctrl[15].val[0] = 0; + state->Init_Ctrl[15].addr[1] = 147; + state->Init_Ctrl[15].bit[1] = 3; + state->Init_Ctrl[15].val[1] = 1; + state->Init_Ctrl[15].addr[2] = 147; + state->Init_Ctrl[15].bit[2] = 4; + state->Init_Ctrl[15].val[2] = 1; + + state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ; + state->Init_Ctrl[16].size = 2 ; + state->Init_Ctrl[16].addr[0] = 147; + state->Init_Ctrl[16].bit[0] = 0; + state->Init_Ctrl[16].val[0] = 0; + state->Init_Ctrl[16].addr[1] = 147; + state->Init_Ctrl[16].bit[1] = 1; + state->Init_Ctrl[16].val[1] = 1; + + state->Init_Ctrl[17].Ctrl_Num = EN_AAF ; + state->Init_Ctrl[17].size = 1 ; + state->Init_Ctrl[17].addr[0] = 147; + state->Init_Ctrl[17].bit[0] = 7; + state->Init_Ctrl[17].val[0] = 0; + + state->Init_Ctrl[18].Ctrl_Num = EN_3P ; + state->Init_Ctrl[18].size = 1 ; + state->Init_Ctrl[18].addr[0] = 147; + state->Init_Ctrl[18].bit[0] = 6; + state->Init_Ctrl[18].val[0] = 0; + + state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ; + state->Init_Ctrl[19].size = 1 ; + state->Init_Ctrl[19].addr[0] = 156; + state->Init_Ctrl[19].bit[0] = 0; + state->Init_Ctrl[19].val[0] = 0; + + state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ; + state->Init_Ctrl[20].size = 1 ; + state->Init_Ctrl[20].addr[0] = 147; + state->Init_Ctrl[20].bit[0] = 5; + state->Init_Ctrl[20].val[0] = 0; + + state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ; + state->Init_Ctrl[21].size = 1 ; + state->Init_Ctrl[21].addr[0] = 137; + state->Init_Ctrl[21].bit[0] = 4; + state->Init_Ctrl[21].val[0] = 0; + + state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ; + state->Init_Ctrl[22].size = 1 ; + state->Init_Ctrl[22].addr[0] = 137; + state->Init_Ctrl[22].bit[0] = 7; + state->Init_Ctrl[22].val[0] = 0; + + state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ; + state->Init_Ctrl[23].size = 1 ; + state->Init_Ctrl[23].addr[0] = 91; + state->Init_Ctrl[23].bit[0] = 5; + state->Init_Ctrl[23].val[0] = 1; + + state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ; + state->Init_Ctrl[24].size = 1 ; + state->Init_Ctrl[24].addr[0] = 43; + state->Init_Ctrl[24].bit[0] = 0; + state->Init_Ctrl[24].val[0] = 1; + + state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ; + state->Init_Ctrl[25].size = 2 ; + state->Init_Ctrl[25].addr[0] = 22; + state->Init_Ctrl[25].bit[0] = 0; + state->Init_Ctrl[25].val[0] = 1; + state->Init_Ctrl[25].addr[1] = 22; + state->Init_Ctrl[25].bit[1] = 1; + state->Init_Ctrl[25].val[1] = 1; + + state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ; + state->Init_Ctrl[26].size = 1 ; + state->Init_Ctrl[26].addr[0] = 134; + state->Init_Ctrl[26].bit[0] = 2; + state->Init_Ctrl[26].val[0] = 0; + + state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ; + state->Init_Ctrl[27].size = 1 ; + state->Init_Ctrl[27].addr[0] = 137; + state->Init_Ctrl[27].bit[0] = 3; + state->Init_Ctrl[27].val[0] = 0; + + state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ; + state->Init_Ctrl[28].size = 1 ; + state->Init_Ctrl[28].addr[0] = 77; + state->Init_Ctrl[28].bit[0] = 7; + state->Init_Ctrl[28].val[0] = 0; + + state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ; + state->Init_Ctrl[29].size = 1 ; + state->Init_Ctrl[29].addr[0] = 166; + state->Init_Ctrl[29].bit[0] = 7; + state->Init_Ctrl[29].val[0] = 1; + + state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ; + state->Init_Ctrl[30].size = 3 ; + state->Init_Ctrl[30].addr[0] = 166; + state->Init_Ctrl[30].bit[0] = 0; + state->Init_Ctrl[30].val[0] = 0; + state->Init_Ctrl[30].addr[1] = 166; + state->Init_Ctrl[30].bit[1] = 1; + state->Init_Ctrl[30].val[1] = 1; + state->Init_Ctrl[30].addr[2] = 166; + state->Init_Ctrl[30].bit[2] = 2; + state->Init_Ctrl[30].val[2] = 1; + + state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ; + state->Init_Ctrl[31].size = 3 ; + state->Init_Ctrl[31].addr[0] = 166; + state->Init_Ctrl[31].bit[0] = 3; + state->Init_Ctrl[31].val[0] = 1; + state->Init_Ctrl[31].addr[1] = 166; + state->Init_Ctrl[31].bit[1] = 4; + state->Init_Ctrl[31].val[1] = 0; + state->Init_Ctrl[31].addr[2] = 166; + state->Init_Ctrl[31].bit[2] = 5; + state->Init_Ctrl[31].val[2] = 1; + + state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ; + state->Init_Ctrl[32].size = 3 ; + state->Init_Ctrl[32].addr[0] = 167; + state->Init_Ctrl[32].bit[0] = 0; + state->Init_Ctrl[32].val[0] = 1; + state->Init_Ctrl[32].addr[1] = 167; + state->Init_Ctrl[32].bit[1] = 1; + state->Init_Ctrl[32].val[1] = 1; + state->Init_Ctrl[32].addr[2] = 167; + state->Init_Ctrl[32].bit[2] = 2; + state->Init_Ctrl[32].val[2] = 0; + + state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ; + state->Init_Ctrl[33].size = 4 ; + state->Init_Ctrl[33].addr[0] = 168; + state->Init_Ctrl[33].bit[0] = 0; + state->Init_Ctrl[33].val[0] = 0; + state->Init_Ctrl[33].addr[1] = 168; + state->Init_Ctrl[33].bit[1] = 1; + state->Init_Ctrl[33].val[1] = 1; + state->Init_Ctrl[33].addr[2] = 168; + state->Init_Ctrl[33].bit[2] = 2; + state->Init_Ctrl[33].val[2] = 0; + state->Init_Ctrl[33].addr[3] = 168; + state->Init_Ctrl[33].bit[3] = 3; + state->Init_Ctrl[33].val[3] = 0; + + state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ; + state->Init_Ctrl[34].size = 4 ; + state->Init_Ctrl[34].addr[0] = 168; + state->Init_Ctrl[34].bit[0] = 4; + state->Init_Ctrl[34].val[0] = 1; + state->Init_Ctrl[34].addr[1] = 168; + state->Init_Ctrl[34].bit[1] = 5; + state->Init_Ctrl[34].val[1] = 1; + state->Init_Ctrl[34].addr[2] = 168; + state->Init_Ctrl[34].bit[2] = 6; + state->Init_Ctrl[34].val[2] = 1; + state->Init_Ctrl[34].addr[3] = 168; + state->Init_Ctrl[34].bit[3] = 7; + state->Init_Ctrl[34].val[3] = 1; + + state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ; + state->Init_Ctrl[35].size = 1 ; + state->Init_Ctrl[35].addr[0] = 135; + state->Init_Ctrl[35].bit[0] = 0; + state->Init_Ctrl[35].val[0] = 0; + + state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ; + state->Init_Ctrl[36].size = 1 ; + state->Init_Ctrl[36].addr[0] = 56; + state->Init_Ctrl[36].bit[0] = 3; + state->Init_Ctrl[36].val[0] = 0; + + state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ; + state->Init_Ctrl[37].size = 7 ; + state->Init_Ctrl[37].addr[0] = 59; + state->Init_Ctrl[37].bit[0] = 1; + state->Init_Ctrl[37].val[0] = 0; + state->Init_Ctrl[37].addr[1] = 59; + state->Init_Ctrl[37].bit[1] = 2; + state->Init_Ctrl[37].val[1] = 0; + state->Init_Ctrl[37].addr[2] = 59; + state->Init_Ctrl[37].bit[2] = 3; + state->Init_Ctrl[37].val[2] = 0; + state->Init_Ctrl[37].addr[3] = 59; + state->Init_Ctrl[37].bit[3] = 4; + state->Init_Ctrl[37].val[3] = 0; + state->Init_Ctrl[37].addr[4] = 59; + state->Init_Ctrl[37].bit[4] = 5; + state->Init_Ctrl[37].val[4] = 0; + state->Init_Ctrl[37].addr[5] = 59; + state->Init_Ctrl[37].bit[5] = 6; + state->Init_Ctrl[37].val[5] = 0; + state->Init_Ctrl[37].addr[6] = 59; + state->Init_Ctrl[37].bit[6] = 7; + state->Init_Ctrl[37].val[6] = 0; + + state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ; + state->Init_Ctrl[38].size = 6 ; + state->Init_Ctrl[38].addr[0] = 32; + state->Init_Ctrl[38].bit[0] = 2; + state->Init_Ctrl[38].val[0] = 0; + state->Init_Ctrl[38].addr[1] = 32; + state->Init_Ctrl[38].bit[1] = 3; + state->Init_Ctrl[38].val[1] = 0; + state->Init_Ctrl[38].addr[2] = 32; + state->Init_Ctrl[38].bit[2] = 4; + state->Init_Ctrl[38].val[2] = 0; + state->Init_Ctrl[38].addr[3] = 32; + state->Init_Ctrl[38].bit[3] = 5; + state->Init_Ctrl[38].val[3] = 0; + state->Init_Ctrl[38].addr[4] = 32; + state->Init_Ctrl[38].bit[4] = 6; + state->Init_Ctrl[38].val[4] = 1; + state->Init_Ctrl[38].addr[5] = 32; + state->Init_Ctrl[38].bit[5] = 7; + state->Init_Ctrl[38].val[5] = 0; + + state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ; + state->Init_Ctrl[39].size = 1 ; + state->Init_Ctrl[39].addr[0] = 25; + state->Init_Ctrl[39].bit[0] = 3; + state->Init_Ctrl[39].val[0] = 1; + + + state->CH_Ctrl_Num = CHCTRL_NUM ; + + state->CH_Ctrl[0].Ctrl_Num = DN_POLY ; + state->CH_Ctrl[0].size = 2 ; + state->CH_Ctrl[0].addr[0] = 68; + state->CH_Ctrl[0].bit[0] = 6; + state->CH_Ctrl[0].val[0] = 1; + state->CH_Ctrl[0].addr[1] = 68; + state->CH_Ctrl[0].bit[1] = 7; + state->CH_Ctrl[0].val[1] = 1; + + state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ; + state->CH_Ctrl[1].size = 2 ; + state->CH_Ctrl[1].addr[0] = 70; + state->CH_Ctrl[1].bit[0] = 6; + state->CH_Ctrl[1].val[0] = 1; + state->CH_Ctrl[1].addr[1] = 70; + state->CH_Ctrl[1].bit[1] = 7; + state->CH_Ctrl[1].val[1] = 0; + + state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ; + state->CH_Ctrl[2].size = 9 ; + state->CH_Ctrl[2].addr[0] = 69; + state->CH_Ctrl[2].bit[0] = 5; + state->CH_Ctrl[2].val[0] = 0; + state->CH_Ctrl[2].addr[1] = 69; + state->CH_Ctrl[2].bit[1] = 6; + state->CH_Ctrl[2].val[1] = 0; + state->CH_Ctrl[2].addr[2] = 69; + state->CH_Ctrl[2].bit[2] = 7; + state->CH_Ctrl[2].val[2] = 0; + state->CH_Ctrl[2].addr[3] = 68; + state->CH_Ctrl[2].bit[3] = 0; + state->CH_Ctrl[2].val[3] = 0; + state->CH_Ctrl[2].addr[4] = 68; + state->CH_Ctrl[2].bit[4] = 1; + state->CH_Ctrl[2].val[4] = 0; + state->CH_Ctrl[2].addr[5] = 68; + state->CH_Ctrl[2].bit[5] = 2; + state->CH_Ctrl[2].val[5] = 0; + state->CH_Ctrl[2].addr[6] = 68; + state->CH_Ctrl[2].bit[6] = 3; + state->CH_Ctrl[2].val[6] = 0; + state->CH_Ctrl[2].addr[7] = 68; + state->CH_Ctrl[2].bit[7] = 4; + state->CH_Ctrl[2].val[7] = 0; + state->CH_Ctrl[2].addr[8] = 68; + state->CH_Ctrl[2].bit[8] = 5; + state->CH_Ctrl[2].val[8] = 0; + + state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ; + state->CH_Ctrl[3].size = 1 ; + state->CH_Ctrl[3].addr[0] = 70; + state->CH_Ctrl[3].bit[0] = 5; + state->CH_Ctrl[3].val[0] = 0; + + state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ; + state->CH_Ctrl[4].size = 3 ; + state->CH_Ctrl[4].addr[0] = 73; + state->CH_Ctrl[4].bit[0] = 4; + state->CH_Ctrl[4].val[0] = 0; + state->CH_Ctrl[4].addr[1] = 73; + state->CH_Ctrl[4].bit[1] = 5; + state->CH_Ctrl[4].val[1] = 1; + state->CH_Ctrl[4].addr[2] = 73; + state->CH_Ctrl[4].bit[2] = 6; + state->CH_Ctrl[4].val[2] = 0; + + state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ; + state->CH_Ctrl[5].size = 4 ; + state->CH_Ctrl[5].addr[0] = 70; + state->CH_Ctrl[5].bit[0] = 0; + state->CH_Ctrl[5].val[0] = 0; + state->CH_Ctrl[5].addr[1] = 70; + state->CH_Ctrl[5].bit[1] = 1; + state->CH_Ctrl[5].val[1] = 0; + state->CH_Ctrl[5].addr[2] = 70; + state->CH_Ctrl[5].bit[2] = 2; + state->CH_Ctrl[5].val[2] = 0; + state->CH_Ctrl[5].addr[3] = 70; + state->CH_Ctrl[5].bit[3] = 3; + state->CH_Ctrl[5].val[3] = 0; + + state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ; + state->CH_Ctrl[6].size = 1 ; + state->CH_Ctrl[6].addr[0] = 70; + state->CH_Ctrl[6].bit[0] = 4; + state->CH_Ctrl[6].val[0] = 1; + + state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ; + state->CH_Ctrl[7].size = 1 ; + state->CH_Ctrl[7].addr[0] = 111; + state->CH_Ctrl[7].bit[0] = 4; + state->CH_Ctrl[7].val[0] = 0; + + state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ; + state->CH_Ctrl[8].size = 1 ; + state->CH_Ctrl[8].addr[0] = 111; + state->CH_Ctrl[8].bit[0] = 7; + state->CH_Ctrl[8].val[0] = 1; + + state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ; + state->CH_Ctrl[9].size = 1 ; + state->CH_Ctrl[9].addr[0] = 111; + state->CH_Ctrl[9].bit[0] = 6; + state->CH_Ctrl[9].val[0] = 1; + + state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ; + state->CH_Ctrl[10].size = 1 ; + state->CH_Ctrl[10].addr[0] = 111; + state->CH_Ctrl[10].bit[0] = 5; + state->CH_Ctrl[10].val[0] = 0; + + state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ; + state->CH_Ctrl[11].size = 2 ; + state->CH_Ctrl[11].addr[0] = 110; + state->CH_Ctrl[11].bit[0] = 0; + state->CH_Ctrl[11].val[0] = 1; + state->CH_Ctrl[11].addr[1] = 110; + state->CH_Ctrl[11].bit[1] = 1; + state->CH_Ctrl[11].val[1] = 0; + + state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ; + state->CH_Ctrl[12].size = 3 ; + state->CH_Ctrl[12].addr[0] = 69; + state->CH_Ctrl[12].bit[0] = 2; + state->CH_Ctrl[12].val[0] = 0; + state->CH_Ctrl[12].addr[1] = 69; + state->CH_Ctrl[12].bit[1] = 3; + state->CH_Ctrl[12].val[1] = 0; + state->CH_Ctrl[12].addr[2] = 69; + state->CH_Ctrl[12].bit[2] = 4; + state->CH_Ctrl[12].val[2] = 0; + + state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ; + state->CH_Ctrl[13].size = 6 ; + state->CH_Ctrl[13].addr[0] = 110; + state->CH_Ctrl[13].bit[0] = 2; + state->CH_Ctrl[13].val[0] = 0; + state->CH_Ctrl[13].addr[1] = 110; + state->CH_Ctrl[13].bit[1] = 3; + state->CH_Ctrl[13].val[1] = 0; + state->CH_Ctrl[13].addr[2] = 110; + state->CH_Ctrl[13].bit[2] = 4; + state->CH_Ctrl[13].val[2] = 0; + state->CH_Ctrl[13].addr[3] = 110; + state->CH_Ctrl[13].bit[3] = 5; + state->CH_Ctrl[13].val[3] = 0; + state->CH_Ctrl[13].addr[4] = 110; + state->CH_Ctrl[13].bit[4] = 6; + state->CH_Ctrl[13].val[4] = 0; + state->CH_Ctrl[13].addr[5] = 110; + state->CH_Ctrl[13].bit[5] = 7; + state->CH_Ctrl[13].val[5] = 1; + + state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ; + state->CH_Ctrl[14].size = 7 ; + state->CH_Ctrl[14].addr[0] = 14; + state->CH_Ctrl[14].bit[0] = 0; + state->CH_Ctrl[14].val[0] = 0; + state->CH_Ctrl[14].addr[1] = 14; + state->CH_Ctrl[14].bit[1] = 1; + state->CH_Ctrl[14].val[1] = 0; + state->CH_Ctrl[14].addr[2] = 14; + state->CH_Ctrl[14].bit[2] = 2; + state->CH_Ctrl[14].val[2] = 0; + state->CH_Ctrl[14].addr[3] = 14; + state->CH_Ctrl[14].bit[3] = 3; + state->CH_Ctrl[14].val[3] = 0; + state->CH_Ctrl[14].addr[4] = 14; + state->CH_Ctrl[14].bit[4] = 4; + state->CH_Ctrl[14].val[4] = 0; + state->CH_Ctrl[14].addr[5] = 14; + state->CH_Ctrl[14].bit[5] = 5; + state->CH_Ctrl[14].val[5] = 0; + state->CH_Ctrl[14].addr[6] = 14; + state->CH_Ctrl[14].bit[6] = 6; + state->CH_Ctrl[14].val[6] = 0; + + state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ; + state->CH_Ctrl[15].size = 18 ; + state->CH_Ctrl[15].addr[0] = 17; + state->CH_Ctrl[15].bit[0] = 6; + state->CH_Ctrl[15].val[0] = 0; + state->CH_Ctrl[15].addr[1] = 17; + state->CH_Ctrl[15].bit[1] = 7; + state->CH_Ctrl[15].val[1] = 0; + state->CH_Ctrl[15].addr[2] = 16; + state->CH_Ctrl[15].bit[2] = 0; + state->CH_Ctrl[15].val[2] = 0; + state->CH_Ctrl[15].addr[3] = 16; + state->CH_Ctrl[15].bit[3] = 1; + state->CH_Ctrl[15].val[3] = 0; + state->CH_Ctrl[15].addr[4] = 16; + state->CH_Ctrl[15].bit[4] = 2; + state->CH_Ctrl[15].val[4] = 0; + state->CH_Ctrl[15].addr[5] = 16; + state->CH_Ctrl[15].bit[5] = 3; + state->CH_Ctrl[15].val[5] = 0; + state->CH_Ctrl[15].addr[6] = 16; + state->CH_Ctrl[15].bit[6] = 4; + state->CH_Ctrl[15].val[6] = 0; + state->CH_Ctrl[15].addr[7] = 16; + state->CH_Ctrl[15].bit[7] = 5; + state->CH_Ctrl[15].val[7] = 0; + state->CH_Ctrl[15].addr[8] = 16; + state->CH_Ctrl[15].bit[8] = 6; + state->CH_Ctrl[15].val[8] = 0; + state->CH_Ctrl[15].addr[9] = 16; + state->CH_Ctrl[15].bit[9] = 7; + state->CH_Ctrl[15].val[9] = 0; + state->CH_Ctrl[15].addr[10] = 15; + state->CH_Ctrl[15].bit[10] = 0; + state->CH_Ctrl[15].val[10] = 0; + state->CH_Ctrl[15].addr[11] = 15; + state->CH_Ctrl[15].bit[11] = 1; + state->CH_Ctrl[15].val[11] = 0; + state->CH_Ctrl[15].addr[12] = 15; + state->CH_Ctrl[15].bit[12] = 2; + state->CH_Ctrl[15].val[12] = 0; + state->CH_Ctrl[15].addr[13] = 15; + state->CH_Ctrl[15].bit[13] = 3; + state->CH_Ctrl[15].val[13] = 0; + state->CH_Ctrl[15].addr[14] = 15; + state->CH_Ctrl[15].bit[14] = 4; + state->CH_Ctrl[15].val[14] = 0; + state->CH_Ctrl[15].addr[15] = 15; + state->CH_Ctrl[15].bit[15] = 5; + state->CH_Ctrl[15].val[15] = 0; + state->CH_Ctrl[15].addr[16] = 15; + state->CH_Ctrl[15].bit[16] = 6; + state->CH_Ctrl[15].val[16] = 1; + state->CH_Ctrl[15].addr[17] = 15; + state->CH_Ctrl[15].bit[17] = 7; + state->CH_Ctrl[15].val[17] = 1; + + state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ; + state->CH_Ctrl[16].size = 5 ; + state->CH_Ctrl[16].addr[0] = 112; + state->CH_Ctrl[16].bit[0] = 0; + state->CH_Ctrl[16].val[0] = 0; + state->CH_Ctrl[16].addr[1] = 112; + state->CH_Ctrl[16].bit[1] = 1; + state->CH_Ctrl[16].val[1] = 0; + state->CH_Ctrl[16].addr[2] = 112; + state->CH_Ctrl[16].bit[2] = 2; + state->CH_Ctrl[16].val[2] = 0; + state->CH_Ctrl[16].addr[3] = 112; + state->CH_Ctrl[16].bit[3] = 3; + state->CH_Ctrl[16].val[3] = 0; + state->CH_Ctrl[16].addr[4] = 112; + state->CH_Ctrl[16].bit[4] = 4; + state->CH_Ctrl[16].val[4] = 1; + + state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ; + state->CH_Ctrl[17].size = 1 ; + state->CH_Ctrl[17].addr[0] = 14; + state->CH_Ctrl[17].bit[0] = 7; + state->CH_Ctrl[17].val[0] = 0; + + state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ; + state->CH_Ctrl[18].size = 4 ; + state->CH_Ctrl[18].addr[0] = 107; + state->CH_Ctrl[18].bit[0] = 3; + state->CH_Ctrl[18].val[0] = 0; + state->CH_Ctrl[18].addr[1] = 107; + state->CH_Ctrl[18].bit[1] = 4; + state->CH_Ctrl[18].val[1] = 0; + state->CH_Ctrl[18].addr[2] = 107; + state->CH_Ctrl[18].bit[2] = 5; + state->CH_Ctrl[18].val[2] = 0; + state->CH_Ctrl[18].addr[3] = 107; + state->CH_Ctrl[18].bit[3] = 6; + state->CH_Ctrl[18].val[3] = 0; + + state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ; + state->CH_Ctrl[19].size = 3 ; + state->CH_Ctrl[19].addr[0] = 107; + state->CH_Ctrl[19].bit[0] = 7; + state->CH_Ctrl[19].val[0] = 1; + state->CH_Ctrl[19].addr[1] = 106; + state->CH_Ctrl[19].bit[1] = 0; + state->CH_Ctrl[19].val[1] = 1; + state->CH_Ctrl[19].addr[2] = 106; + state->CH_Ctrl[19].bit[2] = 1; + state->CH_Ctrl[19].val[2] = 1; + + state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ; + state->CH_Ctrl[20].size = 11 ; + state->CH_Ctrl[20].addr[0] = 109; + state->CH_Ctrl[20].bit[0] = 2; + state->CH_Ctrl[20].val[0] = 0; + state->CH_Ctrl[20].addr[1] = 109; + state->CH_Ctrl[20].bit[1] = 3; + state->CH_Ctrl[20].val[1] = 0; + state->CH_Ctrl[20].addr[2] = 109; + state->CH_Ctrl[20].bit[2] = 4; + state->CH_Ctrl[20].val[2] = 0; + state->CH_Ctrl[20].addr[3] = 109; + state->CH_Ctrl[20].bit[3] = 5; + state->CH_Ctrl[20].val[3] = 0; + state->CH_Ctrl[20].addr[4] = 109; + state->CH_Ctrl[20].bit[4] = 6; + state->CH_Ctrl[20].val[4] = 0; + state->CH_Ctrl[20].addr[5] = 109; + state->CH_Ctrl[20].bit[5] = 7; + state->CH_Ctrl[20].val[5] = 0; + state->CH_Ctrl[20].addr[6] = 108; + state->CH_Ctrl[20].bit[6] = 0; + state->CH_Ctrl[20].val[6] = 0; + state->CH_Ctrl[20].addr[7] = 108; + state->CH_Ctrl[20].bit[7] = 1; + state->CH_Ctrl[20].val[7] = 0; + state->CH_Ctrl[20].addr[8] = 108; + state->CH_Ctrl[20].bit[8] = 2; + state->CH_Ctrl[20].val[8] = 1; + state->CH_Ctrl[20].addr[9] = 108; + state->CH_Ctrl[20].bit[9] = 3; + state->CH_Ctrl[20].val[9] = 1; + state->CH_Ctrl[20].addr[10] = 108; + state->CH_Ctrl[20].bit[10] = 4; + state->CH_Ctrl[20].val[10] = 1; + + state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ; + state->CH_Ctrl[21].size = 6 ; + state->CH_Ctrl[21].addr[0] = 106; + state->CH_Ctrl[21].bit[0] = 2; + state->CH_Ctrl[21].val[0] = 0; + state->CH_Ctrl[21].addr[1] = 106; + state->CH_Ctrl[21].bit[1] = 3; + state->CH_Ctrl[21].val[1] = 0; + state->CH_Ctrl[21].addr[2] = 106; + state->CH_Ctrl[21].bit[2] = 4; + state->CH_Ctrl[21].val[2] = 0; + state->CH_Ctrl[21].addr[3] = 106; + state->CH_Ctrl[21].bit[3] = 5; + state->CH_Ctrl[21].val[3] = 0; + state->CH_Ctrl[21].addr[4] = 106; + state->CH_Ctrl[21].bit[4] = 6; + state->CH_Ctrl[21].val[4] = 0; + state->CH_Ctrl[21].addr[5] = 106; + state->CH_Ctrl[21].bit[5] = 7; + state->CH_Ctrl[21].val[5] = 1; + + state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ; + state->CH_Ctrl[22].size = 1 ; + state->CH_Ctrl[22].addr[0] = 138; + state->CH_Ctrl[22].bit[0] = 4; + state->CH_Ctrl[22].val[0] = 1; + + state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ; + state->CH_Ctrl[23].size = 1 ; + state->CH_Ctrl[23].addr[0] = 17; + state->CH_Ctrl[23].bit[0] = 5; + state->CH_Ctrl[23].val[0] = 0; + + state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ; + state->CH_Ctrl[24].size = 1 ; + state->CH_Ctrl[24].addr[0] = 111; + state->CH_Ctrl[24].bit[0] = 3; + state->CH_Ctrl[24].val[0] = 0; + + state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ; + state->CH_Ctrl[25].size = 1 ; + state->CH_Ctrl[25].addr[0] = 112; + state->CH_Ctrl[25].bit[0] = 7; + state->CH_Ctrl[25].val[0] = 0; + + state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ; + state->CH_Ctrl[26].size = 1 ; + state->CH_Ctrl[26].addr[0] = 136; + state->CH_Ctrl[26].bit[0] = 7; + state->CH_Ctrl[26].val[0] = 0; + + state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ; + state->CH_Ctrl[27].size = 1 ; + state->CH_Ctrl[27].addr[0] = 149; + state->CH_Ctrl[27].bit[0] = 7; + state->CH_Ctrl[27].val[0] = 0; + + state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ; + state->CH_Ctrl[28].size = 1 ; + state->CH_Ctrl[28].addr[0] = 149; + state->CH_Ctrl[28].bit[0] = 6; + state->CH_Ctrl[28].val[0] = 0; + + state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ; + state->CH_Ctrl[29].size = 1 ; + state->CH_Ctrl[29].addr[0] = 149; + state->CH_Ctrl[29].bit[0] = 5; + state->CH_Ctrl[29].val[0] = 1; + + state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ; + state->CH_Ctrl[30].size = 1 ; + state->CH_Ctrl[30].addr[0] = 149; + state->CH_Ctrl[30].bit[0] = 4; + state->CH_Ctrl[30].val[0] = 1; + + state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ; + state->CH_Ctrl[31].size = 1 ; + state->CH_Ctrl[31].addr[0] = 149; + state->CH_Ctrl[31].bit[0] = 3; + state->CH_Ctrl[31].val[0] = 0; + + state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ; + state->CH_Ctrl[32].size = 1 ; + state->CH_Ctrl[32].addr[0] = 93; + state->CH_Ctrl[32].bit[0] = 1; + state->CH_Ctrl[32].val[0] = 0; + + state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ; + state->CH_Ctrl[33].size = 1 ; + state->CH_Ctrl[33].addr[0] = 93; + state->CH_Ctrl[33].bit[0] = 0; + state->CH_Ctrl[33].val[0] = 0; + + state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ; + state->CH_Ctrl[34].size = 6 ; + state->CH_Ctrl[34].addr[0] = 92; + state->CH_Ctrl[34].bit[0] = 2; + state->CH_Ctrl[34].val[0] = 0; + state->CH_Ctrl[34].addr[1] = 92; + state->CH_Ctrl[34].bit[1] = 3; + state->CH_Ctrl[34].val[1] = 0; + state->CH_Ctrl[34].addr[2] = 92; + state->CH_Ctrl[34].bit[2] = 4; + state->CH_Ctrl[34].val[2] = 0; + state->CH_Ctrl[34].addr[3] = 92; + state->CH_Ctrl[34].bit[3] = 5; + state->CH_Ctrl[34].val[3] = 0; + state->CH_Ctrl[34].addr[4] = 92; + state->CH_Ctrl[34].bit[4] = 6; + state->CH_Ctrl[34].val[4] = 0; + state->CH_Ctrl[34].addr[5] = 92; + state->CH_Ctrl[34].bit[5] = 7; + state->CH_Ctrl[34].val[5] = 0; + + state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ; + state->CH_Ctrl[35].size = 6 ; + state->CH_Ctrl[35].addr[0] = 93; + state->CH_Ctrl[35].bit[0] = 2; + state->CH_Ctrl[35].val[0] = 0; + state->CH_Ctrl[35].addr[1] = 93; + state->CH_Ctrl[35].bit[1] = 3; + state->CH_Ctrl[35].val[1] = 0; + state->CH_Ctrl[35].addr[2] = 93; + state->CH_Ctrl[35].bit[2] = 4; + state->CH_Ctrl[35].val[2] = 0; + state->CH_Ctrl[35].addr[3] = 93; + state->CH_Ctrl[35].bit[3] = 5; + state->CH_Ctrl[35].val[3] = 0; + state->CH_Ctrl[35].addr[4] = 93; + state->CH_Ctrl[35].bit[4] = 6; + state->CH_Ctrl[35].val[4] = 0; + state->CH_Ctrl[35].addr[5] = 93; + state->CH_Ctrl[35].bit[5] = 7; + state->CH_Ctrl[35].val[5] = 0; + +#ifdef _MXL_PRODUCTION + state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ; + state->CH_Ctrl[36].size = 1 ; + state->CH_Ctrl[36].addr[0] = 109; + state->CH_Ctrl[36].bit[0] = 1; + state->CH_Ctrl[36].val[0] = 1; + + state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ; + state->CH_Ctrl[37].size = 2 ; + state->CH_Ctrl[37].addr[0] = 112; + state->CH_Ctrl[37].bit[0] = 5; + state->CH_Ctrl[37].val[0] = 0; + state->CH_Ctrl[37].addr[1] = 112; + state->CH_Ctrl[37].bit[1] = 6; + state->CH_Ctrl[37].val[1] = 0; + + state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ; + state->CH_Ctrl[38].size = 1 ; + state->CH_Ctrl[38].addr[0] = 65; + state->CH_Ctrl[38].bit[0] = 1; + state->CH_Ctrl[38].val[0] = 0; +#endif + + return 0 ; +} + +static void InitTunerControls(struct dvb_frontend *fe) +{ + MXL5005_RegisterInit(fe); + MXL5005_ControlInit(fe); +#ifdef _MXL_INTERNAL + MXL5005_MXLControlInit(fe); +#endif +} + +static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, + u8 Mode, /* 0: Analog Mode ; 1: Digital Mode */ + u8 IF_mode, /* for Analog Mode, 0: zero IF; 1: low IF */ + u32 Bandwidth, /* filter channel bandwidth (6, 7, 8) */ + u32 IF_out, /* Desired IF Out Frequency */ + u32 Fxtal, /* XTAL Frequency */ + u8 AGC_Mode, /* AGC Mode - Dual AGC: 0, Single AGC: 1 */ + u16 TOP, /* 0: Dual AGC; Value: take over point */ + u16 IF_OUT_LOAD, /* IF Out Load Resistor (200 / 300 Ohms) */ + u8 CLOCK_OUT, /* 0: turn off clk out; 1: turn on clock out */ + u8 DIV_OUT, /* 0: Div-1; 1: Div-4 */ + u8 CAPSELECT, /* 0: disable On-Chip pulling cap; 1: enable */ + u8 EN_RSSI, /* 0: disable RSSI; 1: enable RSSI */ + + /* Modulation Type; */ + /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ + u8 Mod_Type, + + /* Tracking Filter */ + /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ + u8 TF_Type + ) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0; + + state->Mode = Mode; + state->IF_Mode = IF_mode; + state->Chan_Bandwidth = Bandwidth; + state->IF_OUT = IF_out; + state->Fxtal = Fxtal; + state->AGC_Mode = AGC_Mode; + state->TOP = TOP; + state->IF_OUT_LOAD = IF_OUT_LOAD; + state->CLOCK_OUT = CLOCK_OUT; + state->DIV_OUT = DIV_OUT; + state->CAPSELECT = CAPSELECT; + state->EN_RSSI = EN_RSSI; + state->Mod_Type = Mod_Type; + state->TF_Type = TF_Type; + + /* Initialize all the controls and registers */ + InitTunerControls(fe); + + /* Synthesizer LO frequency calculation */ + MXL_SynthIFLO_Calc(fe); + + return status; +} + +static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + if (state->Mode == 1) /* Digital Mode */ + state->IF_LO = state->IF_OUT; + else /* Analog Mode */ { + if (state->IF_Mode == 0) /* Analog Zero IF mode */ + state->IF_LO = state->IF_OUT + 400000; + else /* Analog Low IF mode */ + state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2; + } +} + +static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + + if (state->Mode == 1) /* Digital Mode */ { + /* remove 20.48MHz setting for 2.6.10 */ + state->RF_LO = state->RF_IN; + /* change for 2.6.6 */ + state->TG_LO = state->RF_IN - 750000; + } else /* Analog Mode */ { + if (state->IF_Mode == 0) /* Analog Zero IF mode */ { + state->RF_LO = state->RF_IN - 400000; + state->TG_LO = state->RF_IN - 1750000; + } else /* Analog Low IF mode */ { + state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2; + state->TG_LO = state->RF_IN - + state->Chan_Bandwidth + 500000; + } + } +} + +static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe) +{ + u16 status = 0; + + status += MXL_ControlWrite(fe, OVERRIDE_1, 1); + status += MXL_ControlWrite(fe, OVERRIDE_2, 1); + status += MXL_ControlWrite(fe, OVERRIDE_3, 1); + status += MXL_ControlWrite(fe, OVERRIDE_4, 1); + + return status; +} + +static u16 MXL_BlockInit(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0; + + status += MXL_OverwriteICDefault(fe); + + /* Downconverter Control Dig Ana */ + status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0); + + /* Filter Control Dig Ana */ + status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1); + status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2); + status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0); + status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1); + status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0); + + /* Initialize Low-Pass Filter */ + if (state->Mode) { /* Digital Mode */ + switch (state->Chan_Bandwidth) { + case 8000000: + status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0); + break; + case 7000000: + status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2); + break; + case 6000000: + status += MXL_ControlWrite(fe, + BB_DLPF_BANDSEL, 3); + break; + } + } else { /* Analog Mode */ + switch (state->Chan_Bandwidth) { + case 8000000: /* Low Zero */ + status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, + (state->IF_Mode ? 0 : 3)); + break; + case 7000000: + status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, + (state->IF_Mode ? 1 : 4)); + break; + case 6000000: + status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, + (state->IF_Mode ? 2 : 5)); + break; + } + } + + /* Charge Pump Control Dig Ana */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8); + status += MXL_ControlWrite(fe, + RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1); + status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0); + + /* AGC TOP Control */ + if (state->AGC_Mode == 0) /* Dual AGC */ { + status += MXL_ControlWrite(fe, AGC_IF, 15); + status += MXL_ControlWrite(fe, AGC_RF, 15); + } else /* Single AGC Mode Dig Ana */ + status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12); + + if (state->TOP == 55) /* TOP == 5.5 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x0); + + if (state->TOP == 72) /* TOP == 7.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x1); + + if (state->TOP == 92) /* TOP == 9.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x2); + + if (state->TOP == 110) /* TOP == 11.0 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x3); + + if (state->TOP == 129) /* TOP == 12.9 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x4); + + if (state->TOP == 147) /* TOP == 14.7 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x5); + + if (state->TOP == 168) /* TOP == 16.8 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x6); + + if (state->TOP == 194) /* TOP == 19.4 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x7); + + if (state->TOP == 212) /* TOP == 21.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0x9); + + if (state->TOP == 232) /* TOP == 23.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xA); + + if (state->TOP == 252) /* TOP == 25.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xB); + + if (state->TOP == 271) /* TOP == 27.1 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xC); + + if (state->TOP == 292) /* TOP == 29.2 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xD); + + if (state->TOP == 317) /* TOP == 31.7 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xE); + + if (state->TOP == 349) /* TOP == 34.9 */ + status += MXL_ControlWrite(fe, AGC_IF, 0xF); + + /* IF Synthesizer Control */ + status += MXL_IFSynthInit(fe); + + /* IF UpConverter Control */ + if (state->IF_OUT_LOAD == 200) { + status += MXL_ControlWrite(fe, DRV_RES_SEL, 6); + status += MXL_ControlWrite(fe, I_DRIVER, 2); + } + if (state->IF_OUT_LOAD == 300) { + status += MXL_ControlWrite(fe, DRV_RES_SEL, 4); + status += MXL_ControlWrite(fe, I_DRIVER, 1); + } + + /* Anti-Alias Filtering Control + * initialise Anti-Aliasing Filter + */ + if (state->Mode) { /* Digital Mode */ + if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) { + status += MXL_ControlWrite(fe, EN_AAF, 1); + status += MXL_ControlWrite(fe, EN_3P, 1); + status += MXL_ControlWrite(fe, EN_AUX_3P, 1); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); + } + if ((state->IF_OUT == 36125000UL) || + (state->IF_OUT == 36150000UL)) { + status += MXL_ControlWrite(fe, EN_AAF, 1); + status += MXL_ControlWrite(fe, EN_3P, 1); + status += MXL_ControlWrite(fe, EN_AUX_3P, 1); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); + } + if (state->IF_OUT > 36150000UL) { + status += MXL_ControlWrite(fe, EN_AAF, 0); + status += MXL_ControlWrite(fe, EN_3P, 1); + status += MXL_ControlWrite(fe, EN_AUX_3P, 1); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); + } + } else { /* Analog Mode */ + if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) { + status += MXL_ControlWrite(fe, EN_AAF, 1); + status += MXL_ControlWrite(fe, EN_3P, 1); + status += MXL_ControlWrite(fe, EN_AUX_3P, 1); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); + } + if (state->IF_OUT > 5000000UL) { + status += MXL_ControlWrite(fe, EN_AAF, 0); + status += MXL_ControlWrite(fe, EN_3P, 0); + status += MXL_ControlWrite(fe, EN_AUX_3P, 0); + status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); + } + } + + /* Demod Clock Out */ + if (state->CLOCK_OUT) + status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1); + else + status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0); + + if (state->DIV_OUT == 1) + status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1); + if (state->DIV_OUT == 0) + status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0); + + /* Crystal Control */ + if (state->CAPSELECT) + status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1); + else + status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0); + + if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) + status += MXL_ControlWrite(fe, IF_SEL_DBL, 1); + if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) + status += MXL_ControlWrite(fe, IF_SEL_DBL, 0); + + if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) + status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3); + if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL) + status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0); + + /* Misc Controls */ + if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */ + status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0); + else + status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1); + + /* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */ + + /* Set TG_R_DIV */ + status += MXL_ControlWrite(fe, TG_R_DIV, + MXL_Ceiling(state->Fxtal, 1000000)); + + /* Apply Default value to BB_INITSTATE_DLPF_TUNE */ + + /* RSSI Control */ + if (state->EN_RSSI) { + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); + + /* TOP point */ + status += MXL_ControlWrite(fe, RFA_FLR, 0); + status += MXL_ControlWrite(fe, RFA_CEIL, 12); + } + + /* Modulation type bit settings + * Override the control values preset + */ + if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ { + state->AGC_Mode = 1; /* Single AGC Mode */ + + /* Enable RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); + + /* TOP point */ + status += MXL_ControlWrite(fe, RFA_FLR, 2); + status += MXL_ControlWrite(fe, RFA_CEIL, 13); + if (state->IF_OUT <= 6280000UL) /* Low IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 0); + else /* High IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + + } + if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ { + state->AGC_Mode = 1; /* Single AGC Mode */ + + /* Enable RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); + + /* TOP point */ + status += MXL_ControlWrite(fe, RFA_FLR, 2); + status += MXL_ControlWrite(fe, RFA_CEIL, 13); + status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1); + /* Low Zero */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); + + if (state->IF_OUT <= 6280000UL) /* Low IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 0); + else /* High IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + } + if (state->Mod_Type == MXL_QAM) /* QAM Mode */ { + state->Mode = MXL_DIGITAL_MODE; + + /* state->AGC_Mode = 1; */ /* Single AGC Mode */ + + /* Disable RSSI */ /* change here for v2.6.5 */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); + /* change here for v2.6.5 */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); + + if (state->IF_OUT <= 6280000UL) /* Low IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 0); + else /* High IF */ + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); + + } + if (state->Mod_Type == MXL_ANALOG_CABLE) { + /* Analog Cable Mode */ + /* state->Mode = MXL_DIGITAL_MODE; */ + + state->AGC_Mode = 1; /* Single AGC Mode */ + + /* Disable RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + /* change for 2.6.3 */ + status += MXL_ControlWrite(fe, AGC_IF, 1); + status += MXL_ControlWrite(fe, AGC_RF, 15); + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + } + + if (state->Mod_Type == MXL_ANALOG_OTA) { + /* Analog OTA Terrestrial mode add for 2.6.7 */ + /* state->Mode = MXL_ANALOG_MODE; */ + + /* Enable RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); + status += MXL_ControlWrite(fe, BB_IQSWAP, 1); + } + + /* RSSI disable */ + if (state->EN_RSSI == 0) { + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + } + + return status; +} + +static u16 MXL_IFSynthInit(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0 ; + u32 Fref = 0 ; + u32 Kdbl, intModVal ; + u32 fracModVal ; + Kdbl = 2 ; + + if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) + Kdbl = 2 ; + if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) + Kdbl = 1 ; + + /* IF Synthesizer Control */ + if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ { + if (state->IF_LO == 41000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 328000000UL ; + } + if (state->IF_LO == 47000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 376000000UL ; + } + if (state->IF_LO == 54000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 324000000UL ; + } + if (state->IF_LO == 60000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 39250000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 314000000UL ; + } + if (state->IF_LO == 39650000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 317200000UL ; + } + if (state->IF_LO == 40150000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 321200000UL ; + } + if (state->IF_LO == 40650000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 325200000UL ; + } + } + + if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) { + if (state->IF_LO == 57000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 342000000UL ; + } + if (state->IF_LO == 44000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 352000000UL ; + } + if (state->IF_LO == 43750000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 350000000UL ; + } + if (state->IF_LO == 36650000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 366500000UL ; + } + if (state->IF_LO == 36150000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 361500000UL ; + } + if (state->IF_LO == 36000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 35250000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 352500000UL ; + } + if (state->IF_LO == 34750000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 347500000UL ; + } + if (state->IF_LO == 6280000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 376800000UL ; + } + if (state->IF_LO == 5000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 4500000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 4570000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 365600000UL ; + } + if (state->IF_LO == 4000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 57400000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 344400000UL ; + } + if (state->IF_LO == 44400000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 355200000UL ; + } + if (state->IF_LO == 44150000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 353200000UL ; + } + if (state->IF_LO == 37050000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 370500000UL ; + } + if (state->IF_LO == 36550000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 365500000UL ; + } + if (state->IF_LO == 36125000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 361250000UL ; + } + if (state->IF_LO == 6000000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 360000000UL ; + } + if (state->IF_LO == 5400000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 324000000UL ; + } + if (state->IF_LO == 5380000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); + Fref = 322800000UL ; + } + if (state->IF_LO == 5200000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 374400000UL ; + } + if (state->IF_LO == 4900000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 352800000UL ; + } + if (state->IF_LO == 4400000UL) { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 352000000UL ; + } + if (state->IF_LO == 4063000UL) /* add for 2.6.8 */ { + status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); + status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); + Fref = 365670000UL ; + } + } + /* CHCAL_INT_MOD_IF */ + /* CHCAL_FRAC_MOD_IF */ + intModVal = Fref / (state->Fxtal * Kdbl/2); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal); + + fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) * + intModVal); + + fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000); + status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal); + + return status ; +} + +static u32 MXL_GetXtalInt(u32 Xtal_Freq) +{ + if ((Xtal_Freq % 1000000) == 0) + return (Xtal_Freq / 10000); + else + return (((Xtal_Freq / 1000000) + 1)*100); +} + +static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0; + u32 divider_val, E3, E4, E5, E5A; + u32 Fmax, Fmin, FmaxBin, FminBin; + u32 Kdbl_RF = 2; + u32 tg_divval; + u32 tg_lo; + u32 Xtal_Int; + + u32 Fref_TG; + u32 Fvco; + + Xtal_Int = MXL_GetXtalInt(state->Fxtal); + + state->RF_IN = RF_Freq; + + MXL_SynthRFTGLO_Calc(fe); + + if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) + Kdbl_RF = 2; + if (state->Fxtal > 22000000 && state->Fxtal <= 32000000) + Kdbl_RF = 1; + + /* Downconverter Controls + * Look-Up Table Implementation for: + * DN_POLY + * DN_RFGAIN + * DN_CAP_RFLPF + * DN_EN_VHFUHFBAR + * DN_GAIN_ADJUST + * Change the boundary reference from RF_IN to RF_LO + */ + if (state->RF_LO < 40000000UL) + return -1; + + if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 2); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 423); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); + } + if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 222); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); + } + if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 147); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); + } + if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 9); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); + } + if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 3); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); + } + if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 1); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); + } + if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) { + status += MXL_ControlWrite(fe, DN_POLY, 3); + status += MXL_ControlWrite(fe, DN_RFGAIN, 2); + status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); + status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); + status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); + } + if (state->RF_LO > 900000000UL) + return -1; + + /* DN_IQTNBUF_AMP */ + /* DN_IQTNGNBFBIAS_BST */ + if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); + } + if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); + } + if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) { + status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); + status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); + } + + /* + * Set RF Synth and LO Path Control + * + * Look-Up table implementation for: + * RFSYN_EN_OUTMUX + * RFSYN_SEL_VCO_OUT + * RFSYN_SEL_VCO_HI + * RFSYN_SEL_DIVM + * RFSYN_RF_DIV_BIAS + * DN_SEL_FREQ + * + * Set divider_val, Fmax, Fmix to use in Equations + */ + FminBin = 28000000UL ; + FmaxBin = 42500000UL ; + if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); + divider_val = 64 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 42500000UL ; + FmaxBin = 56000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); + divider_val = 64 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 56000000UL ; + FmaxBin = 85000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); + divider_val = 32 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 85000000UL ; + FmaxBin = 112000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); + divider_val = 32 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 112000000UL ; + FmaxBin = 170000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); + divider_val = 16 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 170000000UL ; + FmaxBin = 225000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); + divider_val = 16 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 225000000UL ; + FmaxBin = 300000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 4); + divider_val = 8 ; + Fmax = 340000000UL ; + Fmin = FminBin ; + } + FminBin = 300000000UL ; + FmaxBin = 340000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + divider_val = 8 ; + Fmax = FmaxBin ; + Fmin = 225000000UL ; + } + FminBin = 340000000UL ; + FmaxBin = 450000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 2); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + divider_val = 8 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 450000000UL ; + FmaxBin = 680000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + divider_val = 4 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 680000000UL ; + FmaxBin = 900000000UL ; + if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + divider_val = 4 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + + /* CHCAL_INT_MOD_RF + * CHCAL_FRAC_MOD_RF + * RFSYN_LPF_R + * CHCAL_EN_INT_RF + */ + /* Equation E3 RFSYN_VCO_BIAS */ + E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ; + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3); + + /* Equation E4 CHCAL_INT_MOD_RF */ + E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000); + MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4); + + /* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */ + E5 = ((2<<17)*(state->RF_LO/10000*divider_val - + (E4*(2*state->Fxtal*Kdbl_RF)/10000))) / + (2*state->Fxtal*Kdbl_RF/10000); + + status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); + + /* Equation E5A RFSYN_LPF_R */ + E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ; + status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A); + + /* Euqation E5B CHCAL_EN_INIT_RF */ + status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0)); + /*if (E5 == 0) + * status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1); + *else + * status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); + */ + + /* + * Set TG Synth + * + * Look-Up table implementation for: + * TG_LO_DIVVAL + * TG_LO_SELVAL + * + * Set divider_val, Fmax, Fmix to use in Equations + */ + if (state->TG_LO < 33000000UL) + return -1; + + FminBin = 33000000UL ; + FmaxBin = 50000000UL ; + if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x6); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); + divider_val = 36 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 50000000UL ; + FmaxBin = 67000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x1); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); + divider_val = 24 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 67000000UL ; + FmaxBin = 100000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0xC); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); + divider_val = 18 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 100000000UL ; + FmaxBin = 150000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); + divider_val = 12 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 150000000UL ; + FmaxBin = 200000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); + divider_val = 8 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 200000000UL ; + FmaxBin = 300000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); + divider_val = 6 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 300000000UL ; + FmaxBin = 400000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); + divider_val = 4 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 400000000UL ; + FmaxBin = 600000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); + divider_val = 3 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + FminBin = 600000000UL ; + FmaxBin = 900000000UL ; + if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { + status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); + status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); + divider_val = 2 ; + Fmax = FmaxBin ; + Fmin = FminBin ; + } + + /* TG_DIV_VAL */ + tg_divval = (state->TG_LO*divider_val/100000) * + (MXL_Ceiling(state->Fxtal, 1000000) * 100) / + (state->Fxtal/1000); + + status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval); + + if (state->TG_LO > 600000000UL) + status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1); + + Fmax = 1800000000UL ; + Fmin = 1200000000UL ; + + /* prevent overflow of 32 bit unsigned integer, use + * following equation. Edit for v2.6.4 + */ + /* Fref_TF = Fref_TG * 1000 */ + Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000); + + /* Fvco = Fvco/10 */ + Fvco = (state->TG_LO/10000) * divider_val * Fref_TG; + + tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8; + + /* below equation is same as above but much harder to debug. + * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) - + * ((state->TG_LO/10000)*divider_val * + * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 * + * Xtal_Int/100) + 8; + */ + + status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo); + + /* add for 2.6.5 Special setting for QAM */ + if (state->Mod_Type == MXL_QAM) { + if (state->config->qam_gain != 0) + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, + state->config->qam_gain); + else if (state->RF_IN < 680000000) + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); + else + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); + } + + /* Off Chip Tracking Filter Control */ + if (state->TF_Type == MXL_TF_OFF) { + /* Tracking Filter Off State; turn off all the banks */ + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */ + status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */ + status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */ + } + + if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_A, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + } + if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 4, 1); + } + if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 4, 0); + } + if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 0); + } + if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 29); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 0); + } + if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 0); + } + if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 16); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + } + if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 7); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + } + if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + } + } + + if (state->TF_Type == MXL_TF_C_H) { + + /* Tracking Filter type C-H for Hauppauge only */ + status += MXL_ControlWrite(fe, DAC_DIN_A, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + } + if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 0); + status += MXL_SetGPIO(fe, 1, 1); + } + if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 0); + status += MXL_SetGPIO(fe, 1, 0); + } + if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + } + if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + } + if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 0); + } + if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + } + if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + } + if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + } + } + + if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */ + + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_D_L) { + + /* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */ + status += MXL_ControlWrite(fe, DAC_DIN_A, 0); + + /* if UHF and terrestrial => Turn off Tracking Filter */ + if (state->RF_IN >= 471000000 && + (state->RF_IN - 471000000)%6000000 != 0) { + /* Turn off all the banks */ + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_ControlWrite(fe, AGC_IF, 10); + } else { + /* if VHF or cable => Turn on Tracking Filter */ + if (state->RF_IN >= 43000000 && + state->RF_IN < 140000000) { + + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 140000000 && + state->RF_IN < 240000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 240000000 && + state->RF_IN < 340000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 340000000 && + state->RF_IN < 430000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 430000000 && + state->RF_IN < 470000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 470000000 && + state->RF_IN < 570000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 570000000 && + state->RF_IN < 620000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 620000000 && + state->RF_IN < 760000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 760000000 && + state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + } + + if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ { + + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_F) { + + /* Tracking Filter type F */ + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_E_2) { + + /* Tracking Filter type E_2 */ + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_G) { + + /* Tracking Filter type G add for v2.6.8 */ + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) { + + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + + if (state->TF_Type == MXL_TF_E_NA) { + + /* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */ + status += MXL_ControlWrite(fe, DAC_DIN_B, 0); + + /* if UHF and terrestrial=> Turn off Tracking Filter */ + if (state->RF_IN >= 471000000 && + (state->RF_IN - 471000000)%6000000 != 0) { + + /* Turn off all the banks */ + status += MXL_SetGPIO(fe, 3, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + + /* 2.6.12 Turn on RSSI */ + status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); + status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); + status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); + + /* RSSI reference point */ + status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); + status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); + status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); + + /* following parameter is from analog OTA mode, + * can be change to seek better performance */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); + } else { + /* if VHF or Cable => Turn on Tracking Filter */ + + /* 2.6.12 Turn off RSSI */ + status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); + + /* change back from above condition */ + status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); + + + if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { + + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 0); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 1); + } + if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 0); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 0); + } + if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { + status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); + status += MXL_SetGPIO(fe, 4, 1); + status += MXL_SetGPIO(fe, 1, 1); + status += MXL_SetGPIO(fe, 3, 1); + } + } + } + return status ; +} + +static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val) +{ + u16 status = 0; + + if (GPIO_Num == 1) + status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1); + + /* GPIO2 is not available */ + + if (GPIO_Num == 3) { + if (GPIO_Val == 1) { + status += MXL_ControlWrite(fe, GPIO_3, 0); + status += MXL_ControlWrite(fe, GPIO_3B, 0); + } + if (GPIO_Val == 0) { + status += MXL_ControlWrite(fe, GPIO_3, 1); + status += MXL_ControlWrite(fe, GPIO_3B, 1); + } + if (GPIO_Val == 3) { /* tri-state */ + status += MXL_ControlWrite(fe, GPIO_3, 0); + status += MXL_ControlWrite(fe, GPIO_3B, 1); + } + } + if (GPIO_Num == 4) { + if (GPIO_Val == 1) { + status += MXL_ControlWrite(fe, GPIO_4, 0); + status += MXL_ControlWrite(fe, GPIO_4B, 0); + } + if (GPIO_Val == 0) { + status += MXL_ControlWrite(fe, GPIO_4, 1); + status += MXL_ControlWrite(fe, GPIO_4B, 1); + } + if (GPIO_Val == 3) { /* tri-state */ + status += MXL_ControlWrite(fe, GPIO_4, 0); + status += MXL_ControlWrite(fe, GPIO_4B, 1); + } + } + + return status; +} + +static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value) +{ + u16 status = 0; + + /* Will write ALL Matching Control Name */ + /* Write Matching INIT Control */ + status += MXL_ControlWrite_Group(fe, ControlNum, value, 1); + /* Write Matching CH Control */ + status += MXL_ControlWrite_Group(fe, ControlNum, value, 2); +#ifdef _MXL_INTERNAL + /* Write Matching MXL Control */ + status += MXL_ControlWrite_Group(fe, ControlNum, value, 3); +#endif + return status; +} + +static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, + u32 value, u16 controlGroup) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 i, j, k; + u32 highLimit; + u32 ctrlVal; + + if (controlGroup == 1) /* Initial Control */ { + + for (i = 0; i < state->Init_Ctrl_Num; i++) { + + if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { + + highLimit = 1 << state->Init_Ctrl[i].size; + if (value < highLimit) { + for (j = 0; j < state->Init_Ctrl[i].size; j++) { + state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); + MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]), + (u8)(state->Init_Ctrl[i].bit[j]), + (u8)((value>>j) & 0x01)); + } + ctrlVal = 0; + for (k = 0; k < state->Init_Ctrl[i].size; k++) + ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k); + } else + return -1; + } + } + } + if (controlGroup == 2) /* Chan change Control */ { + + for (i = 0; i < state->CH_Ctrl_Num; i++) { + + if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { + + highLimit = 1 << state->CH_Ctrl[i].size; + if (value < highLimit) { + for (j = 0; j < state->CH_Ctrl[i].size; j++) { + state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); + MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]), + (u8)(state->CH_Ctrl[i].bit[j]), + (u8)((value>>j) & 0x01)); + } + ctrlVal = 0; + for (k = 0; k < state->CH_Ctrl[i].size; k++) + ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); + } else + return -1; + } + } + } +#ifdef _MXL_INTERNAL + if (controlGroup == 3) /* Maxlinear Control */ { + + for (i = 0; i < state->MXL_Ctrl_Num; i++) { + + if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { + + highLimit = (1 << state->MXL_Ctrl[i].size); + if (value < highLimit) { + for (j = 0; j < state->MXL_Ctrl[i].size; j++) { + state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); + MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]), + (u8)(state->MXL_Ctrl[i].bit[j]), + (u8)((value>>j) & 0x01)); + } + ctrlVal = 0; + for (k = 0; k < state->MXL_Ctrl[i].size; k++) + ctrlVal += state-> + MXL_Ctrl[i].val[k] * + (1 << k); + } else + return -1; + } + } + } +#endif + return 0 ; /* successful return */ +} + +static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal) +{ + struct mxl5005s_state *state = fe->tuner_priv; + int i ; + + for (i = 0; i < 104; i++) { + if (RegNum == state->TunerRegs[i].Reg_Num) { + *RegVal = (u8)(state->TunerRegs[i].Reg_Val); + return 0; + } + } + + return 1; +} + +static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u32 ctrlVal ; + u16 i, k ; + + for (i = 0; i < state->Init_Ctrl_Num ; i++) { + + if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { + + ctrlVal = 0; + for (k = 0; k < state->Init_Ctrl[i].size; k++) + ctrlVal += state->Init_Ctrl[i].val[k] * (1<CH_Ctrl_Num ; i++) { + + if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { + + ctrlVal = 0; + for (k = 0; k < state->CH_Ctrl[i].size; k++) + ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); + *value = ctrlVal; + return 0; + + } + } + +#ifdef _MXL_INTERNAL + for (i = 0; i < state->MXL_Ctrl_Num ; i++) { + + if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { + + ctrlVal = 0; + for (k = 0; k < state->MXL_Ctrl[i].size; k++) + ctrlVal += state->MXL_Ctrl[i].val[k] * (1<tuner_priv; + int i ; + + const u8 AND_MAP[8] = { + 0xFE, 0xFD, 0xFB, 0xF7, + 0xEF, 0xDF, 0xBF, 0x7F } ; + + const u8 OR_MAP[8] = { + 0x01, 0x02, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x80 } ; + + for (i = 0; i < state->TunerRegs_Num; i++) { + if (state->TunerRegs[i].Reg_Num == address) { + if (bitVal) + state->TunerRegs[i].Reg_Val |= OR_MAP[bit]; + else + state->TunerRegs[i].Reg_Val &= AND_MAP[bit]; + break ; + } + } +} + +static u32 MXL_Ceiling(u32 value, u32 resolution) +{ + return value / resolution + (value % resolution > 0 ? 1 : 0); +} + +/* Retrieve the Initialzation Registers */ +static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count) +{ + u16 status = 0; + int i ; + + u8 RegAddr[] = { + 11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73, + 76, 77, 91, 134, 135, 137, 147, + 156, 166, 167, 168, 25 }; + + *count = ARRAY_SIZE(RegAddr); + + status += MXL_BlockInit(fe); + + for (i = 0 ; i < *count; i++) { + RegNum[i] = RegAddr[i]; + status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); + } + + return status; +} + +static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, + int *count) +{ + u16 status = 0; + int i ; + +/* add 77, 166, 167, 168 register for 2.6.12 */ +#ifdef _MXL_PRODUCTION + u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106, + 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; +#else + u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106, + 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; + /* + u8 RegAddr[171]; + for (i = 0; i <= 170; i++) + RegAddr[i] = i; + */ +#endif + + *count = ARRAY_SIZE(RegAddr); + + for (i = 0 ; i < *count; i++) { + RegNum[i] = RegAddr[i]; + status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); + } + + return status; +} + +static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, + u8 *RegVal, int *count) +{ + u16 status = 0; + int i; + + u8 RegAddr[] = {43, 136}; + + *count = ARRAY_SIZE(RegAddr); + + for (i = 0; i < *count; i++) { + RegNum[i] = RegAddr[i]; + status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); + } + + return status; +} + +static u16 MXL_GetMasterControl(u8 *MasterReg, int state) +{ + if (state == 1) /* Load_Start */ + *MasterReg = 0xF3; + if (state == 2) /* Power_Down */ + *MasterReg = 0x41; + if (state == 3) /* Synth_Reset */ + *MasterReg = 0xB1; + if (state == 4) /* Seq_Off */ + *MasterReg = 0xF1; + + return 0; +} + +#ifdef _MXL_PRODUCTION +static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0 ; + + if (VCO_Range == 1) { + status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + if (state->Mode == 0 && state->IF_Mode == 1) { + /* Analog Low IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 180224); + } + if (state->Mode == 0 && state->IF_Mode == 0) { + /* Analog Zero IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 222822); + } + if (state->Mode == 1) /* Digital Mode */ { + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 229376); + } + } + + if (VCO_Range == 2) { + status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); + if (state->Mode == 0 && state->IF_Mode == 1) { + /* Analog Low IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 206438); + } + if (state->Mode == 0 && state->IF_Mode == 0) { + /* Analog Zero IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 206438); + } + if (state->Mode == 1) /* Digital Mode */ { + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 16384); + } + } + + if (VCO_Range == 3) { + status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); + if (state->Mode == 0 && state->IF_Mode == 1) { + /* Analog Low IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 173670); + } + if (state->Mode == 0 && state->IF_Mode == 0) { + /* Analog Zero IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 173670); + } + if (state->Mode == 1) /* Digital Mode */ { + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 245760); + } + } + + if (VCO_Range == 4) { + status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); + status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); + status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); + status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); + status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); + if (state->Mode == 0 && state->IF_Mode == 1) { + /* Analog Low IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 206438); + } + if (state->Mode == 0 && state->IF_Mode == 0) { + /* Analog Zero IF Mode */ + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 206438); + } + if (state->Mode == 1) /* Digital Mode */ { + status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); + status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); + status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); + status += MXL_ControlWrite(fe, + CHCAL_FRAC_MOD_RF, 212992); + } + } + + return status; +} + +static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u16 status = 0; + + if (Hystersis == 1) + status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1); + + return status; +} +#endif +/* End: Reference driver code found in the Realtek driver that + * is copyright MaxLinear */ + +/* ---------------------------------------------------------------- + * Begin: Everything after here is new code to adapt the + * proprietary Realtek driver into a Linux API tuner. + * Copyright (C) 2008 Steven Toth + */ +static int mxl5005s_reset(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + int ret = 0; + + u8 buf[2] = { 0xff, 0x00 }; + struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, + .buf = buf, .len = 2 }; + + dprintk(2, "%s()\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mxl5005s I2C reset failed\n"); + ret = -EREMOTEIO; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* Write a single byte to a single reg, latch the value if required by + * following the transaction with the latch byte. + */ +static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE }; + struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, + .buf = buf, .len = 3 }; + + if (latch == 0) + msg.len = 2; + + dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr); + + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mxl5005s I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, + u8 *datatable, u8 len) +{ + int ret = 0, i; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + for (i = 0 ; i < len-1; i++) { + ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0); + if (ret < 0) + break; + } + + ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +static int mxl5005s_init(struct dvb_frontend *fe) +{ + struct mxl5005s_state *state = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + state->current_mode = MXL_QAM; + return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ); +} + +static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, + u32 bandwidth) +{ + struct mxl5005s_state *state = fe->tuner_priv; + + u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; + u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; + int TableLen; + + dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth); + + mxl5005s_reset(fe); + + /* Tuner initialization stage 0 */ + MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); + AddrTable[0] = MASTER_CONTROL_ADDR; + ByteTable[0] |= state->config->AgcMasterByte; + + mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); + + mxl5005s_AssignTunerMode(fe, mod_type, bandwidth); + + /* Tuner initialization stage 1 */ + MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen); + + mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); + + return 0; +} + +static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, + u32 bandwidth) +{ + struct mxl5005s_state *state = fe->tuner_priv; + struct mxl5005s_config *c = state->config; + + InitTunerControls(fe); + + /* Set MxL5005S parameters. */ + MXL5005_TunerConfig( + fe, + c->mod_mode, + c->if_mode, + bandwidth, + c->if_freq, + c->xtal_freq, + c->agc_mode, + c->top, + c->output_load, + c->clock_out, + c->div_out, + c->cap_select, + c->rssi_enable, + mod_type, + c->tracking_filter); + + return 0; +} + +static int mxl5005s_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mxl5005s_state *state = fe->tuner_priv; + u32 req_mode, req_bw = 0; + int ret; + + dprintk(1, "%s()\n", __func__); + + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + req_mode = MXL_ATSC; break; + default: + case QAM_64: + case QAM_256: + case QAM_AUTO: + req_mode = MXL_QAM; break; + } + } else + req_mode = MXL_DVBT; + + /* Change tuner for new modulation type if reqd */ + if (req_mode != state->current_mode) { + switch (req_mode) { + case MXL_ATSC: + case MXL_QAM: + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + case MXL_DVBT: + default: + /* Assume DVB-T */ + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + case BANDWIDTH_7_MHZ: + req_bw = MXL5005S_BANDWIDTH_7MHZ; + break; + case BANDWIDTH_AUTO: + case BANDWIDTH_8_MHZ: + req_bw = MXL5005S_BANDWIDTH_8MHZ; + break; + default: + return -EINVAL; + } + } + + state->current_mode = req_mode; + ret = mxl5005s_reconfigure(fe, req_mode, req_bw); + + } else + ret = 0; + + if (ret == 0) { + dprintk(1, "%s() freq=%d\n", __func__, params->frequency); + ret = mxl5005s_SetRfFreqHz(fe, params->frequency); + } + + return ret; +} + +static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl5005s_state *state = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + *frequency = state->RF_IN; + + return 0; +} + +static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mxl5005s_state *state = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + *bandwidth = state->Chan_Bandwidth; + + return 0; +} + +static int mxl5005s_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __func__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mxl5005s_tuner_ops = { + .info = { + .name = "MaxLinear MXL5005S", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mxl5005s_release, + .init = mxl5005s_init, + + .set_params = mxl5005s_set_params, + .get_frequency = mxl5005s_get_frequency, + .get_bandwidth = mxl5005s_get_bandwidth, +}; + +struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mxl5005s_config *config) +{ + struct mxl5005s_state *state = NULL; + dprintk(1, "%s()\n", __func__); + + state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->frontend = fe; + state->config = config; + state->i2c = i2c; + + printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n", + config->i2c_address); + + memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; +} +EXPORT_SYMBOL(mxl5005s_attach); + +MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5005s.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5005s.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5005s.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5005s.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,135 @@ +/* + MaxLinear MXL5005S VSB/QAM/DVBT tuner driver + + Copyright (C) 2008 MaxLinear + Copyright (C) 2008 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __MXL5005S_H +#define __MXL5005S_H + +#include +#include "dvb_frontend.h" + +struct mxl5005s_config { + + /* 7 bit i2c address */ + u8 i2c_address; + +#define IF_FREQ_4570000HZ 4570000 +#define IF_FREQ_4571429HZ 4571429 +#define IF_FREQ_5380000HZ 5380000 +#define IF_FREQ_36000000HZ 36000000 +#define IF_FREQ_36125000HZ 36125000 +#define IF_FREQ_36166667HZ 36166667 +#define IF_FREQ_44000000HZ 44000000 + u32 if_freq; + +#define CRYSTAL_FREQ_4000000HZ 4000000 +#define CRYSTAL_FREQ_16000000HZ 16000000 +#define CRYSTAL_FREQ_25000000HZ 25000000 +#define CRYSTAL_FREQ_28800000HZ 28800000 + u32 xtal_freq; + +#define MXL_DUAL_AGC 0 +#define MXL_SINGLE_AGC 1 + u8 agc_mode; + +#define MXL_TF_DEFAULT 0 +#define MXL_TF_OFF 1 +#define MXL_TF_C 2 +#define MXL_TF_C_H 3 +#define MXL_TF_D 4 +#define MXL_TF_D_L 5 +#define MXL_TF_E 6 +#define MXL_TF_F 7 +#define MXL_TF_E_2 8 +#define MXL_TF_E_NA 9 +#define MXL_TF_G 10 + u8 tracking_filter; + +#define MXL_RSSI_DISABLE 0 +#define MXL_RSSI_ENABLE 1 + u8 rssi_enable; + +#define MXL_CAP_SEL_DISABLE 0 +#define MXL_CAP_SEL_ENABLE 1 + u8 cap_select; + +#define MXL_DIV_OUT_1 0 +#define MXL_DIV_OUT_4 1 + u8 div_out; + +#define MXL_CLOCK_OUT_DISABLE 0 +#define MXL_CLOCK_OUT_ENABLE 1 + u8 clock_out; + +#define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200 +#define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300 + u32 output_load; + +#define MXL5005S_TOP_5P5 55 +#define MXL5005S_TOP_7P2 72 +#define MXL5005S_TOP_9P2 92 +#define MXL5005S_TOP_11P0 110 +#define MXL5005S_TOP_12P9 129 +#define MXL5005S_TOP_14P7 147 +#define MXL5005S_TOP_16P8 168 +#define MXL5005S_TOP_19P4 194 +#define MXL5005S_TOP_21P2 212 +#define MXL5005S_TOP_23P2 232 +#define MXL5005S_TOP_25P2 252 +#define MXL5005S_TOP_27P1 271 +#define MXL5005S_TOP_29P2 292 +#define MXL5005S_TOP_31P7 317 +#define MXL5005S_TOP_34P9 349 + u32 top; + +#define MXL_ANALOG_MODE 0 +#define MXL_DIGITAL_MODE 1 + u8 mod_mode; + +#define MXL_ZERO_IF 0 +#define MXL_LOW_IF 1 + u8 if_mode; + + /* Some boards need to override the built-in logic for determining + the gain when in QAM mode (the HVR-1600 is one such case) */ + u8 qam_gain; + + /* Stuff I don't know what to do with */ + u8 AgcMasterByte; +}; + +#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \ + (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE)) +extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mxl5005s_config *config); +#else +static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mxl5005s_config *config) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_TUNER_MXL5005S */ + +#endif /* __MXL5005S_H */ + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5007t.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5007t.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5007t.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5007t.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,882 @@ +/* + * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner + * + * Copyright (C) 2008, 2009 Michael Krufky + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include "tuner-i2c.h" +#include "mxl5007t.h" + +static DEFINE_MUTEX(mxl5007t_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +static int mxl5007t_debug; +module_param_named(debug, mxl5007t_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level"); + +/* ------------------------------------------------------------------------- */ + +#define mxl_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define mxl_err(fmt, arg...) \ + mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) + +#define mxl_warn(fmt, arg...) \ + mxl_printk(KERN_WARNING, fmt, ##arg) + +#define mxl_info(fmt, arg...) \ + mxl_printk(KERN_INFO, fmt, ##arg) + +#define mxl_debug(fmt, arg...) \ +({ \ + if (mxl5007t_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg); \ +}) + +#define mxl_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + mxl_printk(KERN_ERR, "error %d on line %d", \ + ret, __LINE__); \ + __ret; \ +}) + +/* ------------------------------------------------------------------------- */ + +#define MHz 1000000 + +enum mxl5007t_mode { + MxL_MODE_ISDBT = 0, + MxL_MODE_DVBT = 1, + MxL_MODE_ATSC = 2, + MxL_MODE_CABLE = 0x10, +}; + +enum mxl5007t_chip_version { + MxL_UNKNOWN_ID = 0x00, + MxL_5007_V1_F1 = 0x11, + MxL_5007_V1_F2 = 0x12, + MxL_5007_V4 = 0x14, + MxL_5007_V2_100_F1 = 0x21, + MxL_5007_V2_100_F2 = 0x22, + MxL_5007_V2_200_F1 = 0x23, + MxL_5007_V2_200_F2 = 0x24, +}; + +struct reg_pair_t { + u8 reg; + u8 val; +}; + +/* ------------------------------------------------------------------------- */ + +static struct reg_pair_t init_tab[] = { + { 0x02, 0x06 }, + { 0x03, 0x48 }, + { 0x05, 0x04 }, + { 0x06, 0x10 }, + { 0x2e, 0x15 }, /* OVERRIDE */ + { 0x30, 0x10 }, /* OVERRIDE */ + { 0x45, 0x58 }, /* OVERRIDE */ + { 0x48, 0x19 }, /* OVERRIDE */ + { 0x52, 0x03 }, /* OVERRIDE */ + { 0x53, 0x44 }, /* OVERRIDE */ + { 0x6a, 0x4b }, /* OVERRIDE */ + { 0x76, 0x00 }, /* OVERRIDE */ + { 0x78, 0x18 }, /* OVERRIDE */ + { 0x7a, 0x17 }, /* OVERRIDE */ + { 0x85, 0x06 }, /* OVERRIDE */ + { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ + { 0, 0 } +}; + +static struct reg_pair_t init_tab_cable[] = { + { 0x02, 0x06 }, + { 0x03, 0x48 }, + { 0x05, 0x04 }, + { 0x06, 0x10 }, + { 0x09, 0x3f }, + { 0x0a, 0x3f }, + { 0x0b, 0x3f }, + { 0x2e, 0x15 }, /* OVERRIDE */ + { 0x30, 0x10 }, /* OVERRIDE */ + { 0x45, 0x58 }, /* OVERRIDE */ + { 0x48, 0x19 }, /* OVERRIDE */ + { 0x52, 0x03 }, /* OVERRIDE */ + { 0x53, 0x44 }, /* OVERRIDE */ + { 0x6a, 0x4b }, /* OVERRIDE */ + { 0x76, 0x00 }, /* OVERRIDE */ + { 0x78, 0x18 }, /* OVERRIDE */ + { 0x7a, 0x17 }, /* OVERRIDE */ + { 0x85, 0x06 }, /* OVERRIDE */ + { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ + { 0, 0 } +}; + +/* ------------------------------------------------------------------------- */ + +static struct reg_pair_t reg_pair_rftune[] = { + { 0x0f, 0x00 }, /* abort tune */ + { 0x0c, 0x15 }, + { 0x0d, 0x40 }, + { 0x0e, 0x0e }, + { 0x1f, 0x87 }, /* OVERRIDE */ + { 0x20, 0x1f }, /* OVERRIDE */ + { 0x21, 0x87 }, /* OVERRIDE */ + { 0x22, 0x1f }, /* OVERRIDE */ + { 0x80, 0x01 }, /* freq dependent */ + { 0x0f, 0x01 }, /* start tune */ + { 0, 0 } +}; + +/* ------------------------------------------------------------------------- */ + +struct mxl5007t_state { + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + + struct mutex lock; + + struct mxl5007t_config *config; + + enum mxl5007t_chip_version chip_id; + + struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; + struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; + struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; + + u32 frequency; + u32 bandwidth; +}; + +/* ------------------------------------------------------------------------- */ + +/* called by _init and _rftun to manipulate the register arrays */ + +static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) +{ + unsigned int i = 0; + + while (reg_pair[i].reg || reg_pair[i].val) { + if (reg_pair[i].reg == reg) { + reg_pair[i].val &= ~mask; + reg_pair[i].val |= val; + } + i++; + + } + return; +} + +static void copy_reg_bits(struct reg_pair_t *reg_pair1, + struct reg_pair_t *reg_pair2) +{ + unsigned int i, j; + + i = j = 0; + + while (reg_pair1[i].reg || reg_pair1[i].val) { + while (reg_pair2[j].reg || reg_pair2[j].val) { + if (reg_pair1[i].reg != reg_pair2[j].reg) { + j++; + continue; + } + reg_pair2[j].val = reg_pair1[i].val; + break; + } + i++; + } + return; +} + +/* ------------------------------------------------------------------------- */ + +static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, + enum mxl5007t_mode mode, + s32 if_diff_out_level) +{ + switch (mode) { + case MxL_MODE_ATSC: + set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12); + break; + case MxL_MODE_DVBT: + set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11); + break; + case MxL_MODE_ISDBT: + set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10); + break; + case MxL_MODE_CABLE: + set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1); + set_reg_bits(state->tab_init_cable, 0x0a, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17); + break; + default: + mxl_fail(-EINVAL); + } + return; +} + +static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, + enum mxl5007t_if_freq if_freq, + int invert_if) +{ + u8 val; + + switch (if_freq) { + case MxL_IF_4_MHZ: + val = 0x00; + break; + case MxL_IF_4_5_MHZ: + val = 0x02; + break; + case MxL_IF_4_57_MHZ: + val = 0x03; + break; + case MxL_IF_5_MHZ: + val = 0x04; + break; + case MxL_IF_5_38_MHZ: + val = 0x05; + break; + case MxL_IF_6_MHZ: + val = 0x06; + break; + case MxL_IF_6_28_MHZ: + val = 0x07; + break; + case MxL_IF_9_1915_MHZ: + val = 0x08; + break; + case MxL_IF_35_25_MHZ: + val = 0x09; + break; + case MxL_IF_36_15_MHZ: + val = 0x0a; + break; + case MxL_IF_44_MHZ: + val = 0x0b; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_init, 0x02, 0x0f, val); + + /* set inverted IF or normal IF */ + set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); + + return; +} + +static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, + enum mxl5007t_xtal_freq xtal_freq) +{ + switch (xtal_freq) { + case MxL_XTAL_16_MHZ: + /* select xtal freq & ref freq */ + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00); + break; + case MxL_XTAL_20_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01); + break; + case MxL_XTAL_20_25_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02); + break; + case MxL_XTAL_20_48_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03); + break; + case MxL_XTAL_24_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04); + break; + case MxL_XTAL_25_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05); + break; + case MxL_XTAL_25_14_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06); + break; + case MxL_XTAL_27_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07); + break; + case MxL_XTAL_28_8_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08); + break; + case MxL_XTAL_32_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09); + break; + case MxL_XTAL_40_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a); + break; + case MxL_XTAL_44_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b); + break; + case MxL_XTAL_48_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c); + break; + case MxL_XTAL_49_3811_MHZ: + set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0); + set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d); + break; + default: + mxl_fail(-EINVAL); + return; + } + + return; +} + +static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, + enum mxl5007t_mode mode) +{ + struct mxl5007t_config *cfg = state->config; + + memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); + memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); + + mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); + mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); + mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); + + set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable); + set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3); + set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp); + + if (mode >= MxL_MODE_CABLE) { + copy_reg_bits(state->tab_init, state->tab_init_cable); + return state->tab_init_cable; + } else + return state->tab_init; +} + +/* ------------------------------------------------------------------------- */ + +enum mxl5007t_bw_mhz { + MxL_BW_6MHz = 6, + MxL_BW_7MHz = 7, + MxL_BW_8MHz = 8, +}; + +static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, + enum mxl5007t_bw_mhz bw) +{ + u8 val; + + switch (bw) { + case MxL_BW_6MHz: + val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, + * and DIG_MODEINDEX_CSF */ + break; + case MxL_BW_7MHz: + val = 0x2a; + break; + case MxL_BW_8MHz: + val = 0x3f; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val); + + return; +} + +static struct +reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, + u32 rf_freq, enum mxl5007t_bw_mhz bw) +{ + u32 dig_rf_freq = 0; + u32 temp; + u32 frac_divider = 1000000; + unsigned int i; + + memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); + + mxl5007t_set_bw_bits(state, bw); + + /* Convert RF frequency into 16 bits => + * 10 bit integer (MHz) + 6 bit fraction */ + dig_rf_freq = rf_freq / MHz; + + temp = rf_freq % MHz; + + for (i = 0; i < 6; i++) { + dig_rf_freq <<= 1; + frac_divider /= 2; + if (temp > frac_divider) { + temp -= frac_divider; + dig_rf_freq++; + } + } + + /* add to have shift center point by 7.8124 kHz */ + if (temp > 7812) + dig_rf_freq++; + + set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq); + set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8)); + + if (rf_freq >= 333000000) + set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40); + + return state->tab_rftune; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) +{ + u8 buf[] = { reg, val }; + struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, + .buf = buf, .len = 2 }; + int ret; + + ret = i2c_transfer(state->i2c_props.adap, &msg, 1); + if (ret != 1) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_write_regs(struct mxl5007t_state *state, + struct reg_pair_t *reg_pair) +{ + unsigned int i = 0; + int ret = 0; + + while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { + ret = mxl5007t_write_reg(state, + reg_pair[i].reg, reg_pair[i].val); + i++; + } + return ret; +} + +static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) +{ + struct i2c_msg msg[] = { + { .addr = state->i2c_props.addr, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = state->i2c_props.addr, .flags = I2C_M_RD, + .buf = val, .len = 1 }, + }; + int ret; + + ret = i2c_transfer(state->i2c_props.adap, msg, 2); + if (ret != 2) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_soft_reset(struct mxl5007t_state *state) +{ + u8 d = 0xff; + struct i2c_msg msg = { + .addr = state->i2c_props.addr, .flags = 0, + .buf = &d, .len = 1 + }; + int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); + + if (ret != 1) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_tuner_init(struct mxl5007t_state *state, + enum mxl5007t_mode mode) +{ + struct reg_pair_t *init_regs; + int ret; + + ret = mxl5007t_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + + /* calculate initialization reg array */ + init_regs = mxl5007t_calc_init_regs(state, mode); + + ret = mxl5007t_write_regs(state, init_regs); + if (mxl_fail(ret)) + goto fail; + mdelay(1); +fail: + return ret; +} + +static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, + enum mxl5007t_bw_mhz bw) +{ + struct reg_pair_t *rf_tune_regs; + int ret; + + /* calculate channel change reg array */ + rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); + + ret = mxl5007t_write_regs(state, rf_tune_regs); + if (mxl_fail(ret)) + goto fail; + msleep(3); +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, + int *rf_locked, int *ref_locked) +{ + u8 d; + int ret; + + *rf_locked = 0; + *ref_locked = 0; + + ret = mxl5007t_read_reg(state, 0xd8, &d); + if (mxl_fail(ret)) + goto fail; + + if ((d & 0x0c) == 0x0c) + *rf_locked = 1; + + if ((d & 0x03) == 0x03) + *ref_locked = 1; +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int rf_locked, ref_locked, ret; + + *status = 0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); + if (mxl_fail(ret)) + goto fail; + mxl_debug("%s%s", rf_locked ? "rf locked " : "", + ref_locked ? "ref locked" : ""); + + if ((rf_locked) || (ref_locked)) + *status |= TUNER_STATUS_LOCKED; +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mxl5007t_state *state = fe->tuner_priv; + enum mxl5007t_bw_mhz bw; + enum mxl5007t_mode mode; + int ret; + u32 freq = params->frequency; + + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + mode = MxL_MODE_ATSC; + break; + case QAM_64: + case QAM_256: + mode = MxL_MODE_CABLE; + break; + default: + mxl_err("modulation not set!"); + return -EINVAL; + } + bw = MxL_BW_6MHz; + } else if (fe->ops.info.type == FE_OFDM) { + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + bw = MxL_BW_6MHz; + break; + case BANDWIDTH_7_MHZ: + bw = MxL_BW_7MHz; + break; + case BANDWIDTH_8_MHZ: + bw = MxL_BW_8MHz; + break; + default: + mxl_err("bandwidth not set!"); + return -EINVAL; + } + mode = MxL_MODE_DVBT; + } else { + mxl_err("modulation type not supported!"); + return -EINVAL; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + mutex_lock(&state->lock); + + ret = mxl5007t_tuner_init(state, mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_tuner_rf_tune(state, freq, bw); + if (mxl_fail(ret)) + goto fail; + + state->frequency = freq; + state->bandwidth = (fe->ops.info.type == FE_OFDM) ? + params->u.ofdm.bandwidth : 0; +fail: + mutex_unlock(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_init(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* wake from standby */ + ret = mxl5007t_write_reg(state, 0x01, 0x01); + mxl_fail(ret); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +static int mxl5007t_sleep(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* enter standby mode */ + ret = mxl5007t_write_reg(state, 0x01, 0x00); + mxl_fail(ret); + ret = mxl5007t_write_reg(state, 0x0f, 0x00); + mxl_fail(ret); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl5007t_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mxl5007t_state *state = fe->tuner_priv; + *bandwidth = state->bandwidth; + return 0; +} + +static int mxl5007t_release(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + + mutex_lock(&mxl5007t_list_mutex); + + if (state) + hybrid_tuner_release_state(state); + + mutex_unlock(&mxl5007t_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static struct dvb_tuner_ops mxl5007t_tuner_ops = { + .info = { + .name = "MaxLinear MxL5007T", + }, + .init = mxl5007t_init, + .sleep = mxl5007t_sleep, + .set_params = mxl5007t_set_params, + .get_status = mxl5007t_get_status, + .get_frequency = mxl5007t_get_frequency, + .get_bandwidth = mxl5007t_get_bandwidth, + .release = mxl5007t_release, +}; + +static int mxl5007t_get_chip_id(struct mxl5007t_state *state) +{ + char *name; + int ret; + u8 id; + + ret = mxl5007t_read_reg(state, 0xd9, &id); + if (mxl_fail(ret)) + goto fail; + + switch (id) { + case MxL_5007_V1_F1: + name = "MxL5007.v1.f1"; + break; + case MxL_5007_V1_F2: + name = "MxL5007.v1.f2"; + break; + case MxL_5007_V2_100_F1: + name = "MxL5007.v2.100.f1"; + break; + case MxL_5007_V2_100_F2: + name = "MxL5007.v2.100.f2"; + break; + case MxL_5007_V2_200_F1: + name = "MxL5007.v2.200.f1"; + break; + case MxL_5007_V2_200_F2: + name = "MxL5007.v2.200.f2"; + break; + case MxL_5007_V4: + name = "MxL5007T.v4"; + break; + default: + name = "MxL5007T"; + printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id); + id = MxL_UNKNOWN_ID; + } + state->chip_id = id; + mxl_info("%s detected @ %d-%04x", name, + i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr); + return 0; +fail: + mxl_warn("unable to identify device @ %d-%04x", + i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr); + + state->chip_id = MxL_UNKNOWN_ID; + return ret; +} + +struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 addr, + struct mxl5007t_config *cfg) +{ + struct mxl5007t_state *state = NULL; + int instance, ret; + + mutex_lock(&mxl5007t_list_mutex); + instance = hybrid_tuner_request_state(struct mxl5007t_state, state, + hybrid_tuner_instance_list, + i2c, addr, "mxl5007t"); + switch (instance) { + case 0: + goto fail; + case 1: + /* new tuner instance */ + state->config = cfg; + + mutex_init(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_get_chip_id(state); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + /* check return value of mxl5007t_get_chip_id */ + if (mxl_fail(ret)) + goto fail; + break; + default: + /* existing tuner instance */ + break; + } + fe->tuner_priv = state; + mutex_unlock(&mxl5007t_list_mutex); + + memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +fail: + mutex_unlock(&mxl5007t_list_mutex); + + mxl5007t_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(mxl5007t_attach); +MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5007t.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5007t.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5007t.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/mxl5007t.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,104 @@ +/* + * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner + * + * Copyright (C) 2008 Michael Krufky + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MXL5007T_H__ +#define __MXL5007T_H__ + +#include "dvb_frontend.h" + +/* ------------------------------------------------------------------------- */ + +enum mxl5007t_if_freq { + MxL_IF_4_MHZ, /* 4000000 */ + MxL_IF_4_5_MHZ, /* 4500000 */ + MxL_IF_4_57_MHZ, /* 4570000 */ + MxL_IF_5_MHZ, /* 5000000 */ + MxL_IF_5_38_MHZ, /* 5380000 */ + MxL_IF_6_MHZ, /* 6000000 */ + MxL_IF_6_28_MHZ, /* 6280000 */ + MxL_IF_9_1915_MHZ, /* 9191500 */ + MxL_IF_35_25_MHZ, /* 35250000 */ + MxL_IF_36_15_MHZ, /* 36150000 */ + MxL_IF_44_MHZ, /* 44000000 */ +}; + +enum mxl5007t_xtal_freq { + MxL_XTAL_16_MHZ, /* 16000000 */ + MxL_XTAL_20_MHZ, /* 20000000 */ + MxL_XTAL_20_25_MHZ, /* 20250000 */ + MxL_XTAL_20_48_MHZ, /* 20480000 */ + MxL_XTAL_24_MHZ, /* 24000000 */ + MxL_XTAL_25_MHZ, /* 25000000 */ + MxL_XTAL_25_14_MHZ, /* 25140000 */ + MxL_XTAL_27_MHZ, /* 27000000 */ + MxL_XTAL_28_8_MHZ, /* 28800000 */ + MxL_XTAL_32_MHZ, /* 32000000 */ + MxL_XTAL_40_MHZ, /* 40000000 */ + MxL_XTAL_44_MHZ, /* 44000000 */ + MxL_XTAL_48_MHZ, /* 48000000 */ + MxL_XTAL_49_3811_MHZ, /* 49381100 */ +}; + +enum mxl5007t_clkout_amp { + MxL_CLKOUT_AMP_0_94V = 0, + MxL_CLKOUT_AMP_0_53V = 1, + MxL_CLKOUT_AMP_0_37V = 2, + MxL_CLKOUT_AMP_0_28V = 3, + MxL_CLKOUT_AMP_0_23V = 4, + MxL_CLKOUT_AMP_0_20V = 5, + MxL_CLKOUT_AMP_0_17V = 6, + MxL_CLKOUT_AMP_0_15V = 7, +}; + +struct mxl5007t_config { + s32 if_diff_out_level; + enum mxl5007t_clkout_amp clk_out_amp; + enum mxl5007t_xtal_freq xtal_freq_hz; + enum mxl5007t_if_freq if_freq_hz; + unsigned int invert_if:1; + unsigned int loop_thru_enable:1; + unsigned int clk_out_enable:1; +}; + +#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE)) +extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 addr, + struct mxl5007t_config *cfg); +#else +static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + u8 addr, + struct mxl5007t_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __MXL5007T_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,482 @@ +/* + * Driver for Quantek QT1010 silicon tuner + * + * Copyright (C) 2006 Antti Palosaari + * Aapo Tahkola + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "qt1010.h" +#include "qt1010_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "QT1010: " args); \ + } while (0) + +/* read single register */ +static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "qt1010 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +/* write single register */ +static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = 2 }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "qt1010 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +/* dump all registers */ +static void qt1010_dump_regs(struct qt1010_priv *priv) +{ + u8 reg, val; + + for (reg = 0; ; reg++) { + if (reg % 16 == 0) { + if (reg) + printk(KERN_CONT "\n"); + printk(KERN_DEBUG "%02x:", reg); + } + if (qt1010_readreg(priv, reg, &val) == 0) + printk(KERN_CONT " %02x", val); + else + printk(KERN_CONT " --"); + if (reg == 0x2f) + break; + } + printk(KERN_CONT "\n"); +} + +static int qt1010_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct qt1010_priv *priv; + int err; + u32 freq, div, mod1, mod2; + u8 i, tmpval, reg05; + qt1010_i2c_oper_t rd[48] = { + { QT1010_WR, 0x01, 0x80 }, + { QT1010_WR, 0x02, 0x3f }, + { QT1010_WR, 0x05, 0xff }, /* 02 c write */ + { QT1010_WR, 0x06, 0x44 }, + { QT1010_WR, 0x07, 0xff }, /* 04 c write */ + { QT1010_WR, 0x08, 0x08 }, + { QT1010_WR, 0x09, 0xff }, /* 06 c write */ + { QT1010_WR, 0x0a, 0xff }, /* 07 c write */ + { QT1010_WR, 0x0b, 0xff }, /* 08 c write */ + { QT1010_WR, 0x0c, 0xe1 }, + { QT1010_WR, 0x1a, 0xff }, /* 10 c write */ + { QT1010_WR, 0x1b, 0x00 }, + { QT1010_WR, 0x1c, 0x89 }, + { QT1010_WR, 0x11, 0xff }, /* 13 c write */ + { QT1010_WR, 0x12, 0xff }, /* 14 c write */ + { QT1010_WR, 0x22, 0xff }, /* 15 c write */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xd0 }, + { QT1010_RD, 0x22, 0xff }, /* 16 c read */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_RD, 0x05, 0xff }, /* 20 c read */ + { QT1010_RD, 0x22, 0xff }, /* 21 c read */ + { QT1010_WR, 0x23, 0xd0 }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xe0 }, + { QT1010_RD, 0x23, 0xff }, /* 25 c read */ + { QT1010_RD, 0x23, 0xff }, /* 26 c read */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x24, 0xd0 }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xf0 }, + { QT1010_RD, 0x24, 0xff }, /* 31 c read */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x14, 0x7f }, + { QT1010_WR, 0x15, 0x7f }, + { QT1010_WR, 0x05, 0xff }, /* 35 c write */ + { QT1010_WR, 0x06, 0x00 }, + { QT1010_WR, 0x15, 0x1f }, + { QT1010_WR, 0x16, 0xff }, + { QT1010_WR, 0x18, 0xff }, + { QT1010_WR, 0x1f, 0xff }, /* 40 c write */ + { QT1010_WR, 0x20, 0xff }, /* 41 c write */ + { QT1010_WR, 0x21, 0x53 }, + { QT1010_WR, 0x25, 0xff }, /* 43 c write */ + { QT1010_WR, 0x26, 0x15 }, + { QT1010_WR, 0x00, 0xff }, /* 45 c write */ + { QT1010_WR, 0x02, 0x00 }, + { QT1010_WR, 0x01, 0x00 } + }; + +#define FREQ1 32000000 /* 32 MHz */ +#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */ + + priv = fe->tuner_priv; + freq = params->frequency; + div = (freq + QT1010_OFFSET) / QT1010_STEP; + freq = (div * QT1010_STEP) - QT1010_OFFSET; + mod1 = (freq + QT1010_OFFSET) % FREQ1; + mod2 = (freq + QT1010_OFFSET) % FREQ2; + priv->bandwidth = + (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->frequency = freq; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + /* reg 05 base value */ + if (freq < 290000000) reg05 = 0x14; /* 290 MHz */ + else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */ + else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */ + else reg05 = 0x74; + + /* 0x5 */ + rd[2].val = reg05; + + /* 07 - set frequency: 32 MHz scale */ + rd[4].val = (freq + QT1010_OFFSET) / FREQ1; + + /* 09 - changes every 8/24 MHz */ + if (mod1 < 8000000) rd[6].val = 0x1d; + else rd[6].val = 0x1c; + + /* 0a - set frequency: 4 MHz scale (max 28 MHz) */ + if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */ + else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */ + else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */ + else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */ + else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */ + else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */ + else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */ + else rd[7].val = 0x0a; /* +28 MHz */ + + /* 0b - changes every 2/2 MHz */ + if (mod2 < 2000000) rd[8].val = 0x45; + else rd[8].val = 0x44; + + /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/ + tmpval = 0x78; /* byte, overflows intentionally */ + rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08); + + /* 11 */ + rd[13].val = 0xfd; /* TODO: correct value calculation */ + + /* 12 */ + rd[14].val = 0x91; /* TODO: correct value calculation */ + + /* 22 */ + if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */ + else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */ + else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */ + else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */ + else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */ + else rd[15].val = 0xd0; + + /* 05 */ + rd[35].val = (reg05 & 0xf0); + + /* 1f */ + if (mod1 < 8000000) tmpval = 0x00; + else if (mod1 < 12000000) tmpval = 0x01; + else if (mod1 < 16000000) tmpval = 0x02; + else if (mod1 < 24000000) tmpval = 0x03; + else if (mod1 < 28000000) tmpval = 0x04; + else tmpval = 0x05; + rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval); + + /* 20 */ + if (mod1 < 8000000) tmpval = 0x00; + else if (mod1 < 12000000) tmpval = 0x01; + else if (mod1 < 20000000) tmpval = 0x02; + else if (mod1 < 24000000) tmpval = 0x03; + else if (mod1 < 28000000) tmpval = 0x04; + else tmpval = 0x05; + rd[41].val = (priv->reg20_init_val + 0x0d + tmpval); + + /* 25 */ + rd[43].val = priv->reg25_init_val; + + /* 00 */ + rd[45].val = 0x92; /* TODO: correct value calculation */ + + dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \ + "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \ + "20:%02x 25:%02x 00:%02x", \ + freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \ + rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \ + rd[40].val, rd[41].val, rd[43].val, rd[45].val); + + for (i = 0; i < ARRAY_SIZE(rd); i++) { + if (rd[i].oper == QT1010_WR) { + err = qt1010_writereg(priv, rd[i].reg, rd[i].val); + } else { /* read is required to proper locking */ + err = qt1010_readreg(priv, rd[i].reg, &tmpval); + } + if (err) return err; + } + + if (debug) + qt1010_dump_regs(priv); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return 0; +} + +static int qt1010_init_meas1(struct qt1010_priv *priv, + u8 oper, u8 reg, u8 reg_init_val, u8 *retval) +{ + u8 i, val1, val2; + int err; + + qt1010_i2c_oper_t i2c_data[] = { + { QT1010_WR, reg, reg_init_val }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, oper }, + { QT1010_RD, reg, 0xff } + }; + + for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { + if (i2c_data[i].oper == QT1010_WR) { + err = qt1010_writereg(priv, i2c_data[i].reg, + i2c_data[i].val); + } else { + err = qt1010_readreg(priv, i2c_data[i].reg, &val2); + } + if (err) return err; + } + + do { + val1 = val2; + err = qt1010_readreg(priv, reg, &val2); + if (err) return err; + dprintk("compare reg:%02x %02x %02x", reg, val1, val2); + } while (val1 != val2); + *retval = val1; + + return qt1010_writereg(priv, 0x1e, 0x00); +} + +static u8 qt1010_init_meas2(struct qt1010_priv *priv, + u8 reg_init_val, u8 *retval) +{ + u8 i, val; + int err; + qt1010_i2c_oper_t i2c_data[] = { + { QT1010_WR, 0x07, reg_init_val }, + { QT1010_WR, 0x22, 0xd0 }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xd0 }, + { QT1010_RD, 0x22, 0xff }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x22, 0xff } + }; + for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { + if (i2c_data[i].oper == QT1010_WR) { + err = qt1010_writereg(priv, i2c_data[i].reg, + i2c_data[i].val); + } else { + err = qt1010_readreg(priv, i2c_data[i].reg, &val); + } + if (err) return err; + } + *retval = val; + return 0; +} + +static int qt1010_init(struct dvb_frontend *fe) +{ + struct qt1010_priv *priv = fe->tuner_priv; + struct dvb_frontend_parameters params; + int err = 0; + u8 i, tmpval, *valptr = NULL; + + qt1010_i2c_oper_t i2c_data[] = { + { QT1010_WR, 0x01, 0x80 }, + { QT1010_WR, 0x0d, 0x84 }, + { QT1010_WR, 0x0e, 0xb7 }, + { QT1010_WR, 0x2a, 0x23 }, + { QT1010_WR, 0x2c, 0xdc }, + { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */ + { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */ + { QT1010_WR, 0x2b, 0x70 }, + { QT1010_WR, 0x2a, 0x23 }, + { QT1010_M1, 0x26, 0x08 }, + { QT1010_M1, 0x82, 0xff }, + { QT1010_WR, 0x05, 0x14 }, + { QT1010_WR, 0x06, 0x44 }, + { QT1010_WR, 0x07, 0x28 }, + { QT1010_WR, 0x08, 0x0b }, + { QT1010_WR, 0x11, 0xfd }, + { QT1010_M1, 0x22, 0x0d }, + { QT1010_M1, 0xd0, 0xff }, + { QT1010_WR, 0x06, 0x40 }, + { QT1010_WR, 0x16, 0xf0 }, + { QT1010_WR, 0x02, 0x38 }, + { QT1010_WR, 0x03, 0x18 }, + { QT1010_WR, 0x20, 0xe0 }, + { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */ + { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */ + { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */ + { QT1010_WR, 0x03, 0x19 }, + { QT1010_WR, 0x02, 0x3f }, + { QT1010_WR, 0x21, 0x53 }, + { QT1010_RD, 0x21, 0xff }, + { QT1010_WR, 0x11, 0xfd }, + { QT1010_WR, 0x05, 0x34 }, + { QT1010_WR, 0x06, 0x44 }, + { QT1010_WR, 0x08, 0x08 } + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { + switch (i2c_data[i].oper) { + case QT1010_WR: + err = qt1010_writereg(priv, i2c_data[i].reg, + i2c_data[i].val); + break; + case QT1010_RD: + if (i2c_data[i].val == 0x20) + valptr = &priv->reg20_init_val; + else + valptr = &tmpval; + err = qt1010_readreg(priv, i2c_data[i].reg, valptr); + break; + case QT1010_M1: + if (i2c_data[i].val == 0x25) + valptr = &priv->reg25_init_val; + else if (i2c_data[i].val == 0x1f) + valptr = &priv->reg1f_init_val; + else + valptr = &tmpval; + err = qt1010_init_meas1(priv, i2c_data[i+1].reg, + i2c_data[i].reg, + i2c_data[i].val, valptr); + i++; + break; + } + if (err) return err; + } + + for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */ + if ((err = qt1010_init_meas2(priv, i, &tmpval))) + return err; + + params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */ + /* MSI Megasky 580 GL861 533000000 */ + return qt1010_set_params(fe, ¶ms); +} + +static int qt1010_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct qt1010_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct qt1010_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static const struct dvb_tuner_ops qt1010_tuner_ops = { + .info = { + .name = "Quantek QT1010", + .frequency_min = QT1010_MIN_FREQ, + .frequency_max = QT1010_MAX_FREQ, + .frequency_step = QT1010_STEP, + }, + + .release = qt1010_release, + .init = qt1010_init, + /* TODO: implement sleep */ + + .set_params = qt1010_set_params, + .get_frequency = qt1010_get_frequency, + .get_bandwidth = qt1010_get_bandwidth +}; + +struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct qt1010_config *cfg) +{ + struct qt1010_priv *priv = NULL; + u8 id; + + priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + + /* Try to detect tuner chip. Probably this is not correct register. */ + if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) { + kfree(priv); + return NULL; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + printk(KERN_INFO "Quantek QT1010 successfully identified.\n"); + memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(qt1010_attach); + +MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_AUTHOR("Aapo Tahkola "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Driver for Quantek QT1010 silicon tuner + * + * Copyright (C) 2006 Antti Palosaari + * Aapo Tahkola + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef QT1010_H +#define QT1010_H + +#include "dvb_frontend.h" + +struct qt1010_config { + u8 i2c_address; +}; + +/** + * Attach a qt1010 tuner to the supplied frontend structure. + * + * @param fe frontend to attach to + * @param i2c i2c adapter to use + * @param cfg tuner hw based configuration + * @return fe pointer on success, NULL on failure + */ +#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE)) +extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct qt1010_config *cfg); +#else +static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct qt1010_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_MEDIA_TUNER_QT1010 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/qt1010_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,105 @@ +/* + * Driver for Quantek QT1010 silicon tuner + * + * Copyright (C) 2006 Antti Palosaari + * Aapo Tahkola + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef QT1010_PRIV_H +#define QT1010_PRIV_H + +/* +reg def meaning +=== === ======= +00 00 ? +01 a0 ? operation start/stop; start=80, stop=00 +02 00 ? +03 19 ? +04 00 ? +05 00 ? maybe band selection +06 00 ? +07 2b set frequency: 32 MHz scale, n*32 MHz +08 0b ? +09 10 ? changes every 8/24 MHz; values 1d/1c +0a 08 set frequency: 4 MHz scale, n*4 MHz +0b 41 ? changes every 2/2 MHz; values 45/45 +0c e1 ? +0d 94 ? +0e b6 ? +0f 2c ? +10 10 ? +11 f1 ? maybe device specified adjustment +12 11 ? maybe device specified adjustment +13 3f ? +14 1f ? +15 3f ? +16 ff ? +17 ff ? +18 f7 ? +19 80 ? +1a d0 set frequency: 125 kHz scale, n*125 kHz +1b 00 ? +1c 89 ? +1d 00 ? +1e 00 ? looks like operation register; write cmd here, read result from 1f-26 +1f 20 ? chip initialization +20 e0 ? chip initialization +21 20 ? +22 d0 ? +23 d0 ? +24 d0 ? +25 40 ? chip initialization +26 08 ? +27 29 ? +28 55 ? +29 39 ? +2a 13 ? +2b 01 ? +2c ea ? +2d 00 ? +2e 00 ? not used? +2f 00 ? not used? +*/ + +#define QT1010_STEP 125000 /* 125 kHz used by Windows drivers, + hw could be more precise but we don't + know how to use */ +#define QT1010_MIN_FREQ 48000000 /* 48 MHz */ +#define QT1010_MAX_FREQ 860000000 /* 860 MHz */ +#define QT1010_OFFSET 1246000000 /* 1246 MHz */ + +#define QT1010_WR 0 +#define QT1010_RD 1 +#define QT1010_M1 3 + +typedef struct { + u8 oper, reg, val; +} qt1010_i2c_oper_t; + +struct qt1010_priv { + struct qt1010_config *cfg; + struct i2c_adapter *i2c; + + u8 reg1f_init_val; + u8 reg20_init_val; + u8 reg25_init_val; + + u32 frequency; + u32 bandwidth; +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,265 @@ +/* + * NXP TDA18212HN silicon tuner driver + * + * Copyright (C) 2011 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "tda18212_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +/* write multiple registers */ +static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, + int len) +{ + int ret; + u8 buf[len+1]; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg->i2c_address, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = reg; + memcpy(&buf[1], val, len); + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); + ret = -EREMOTEIO; + } + return ret; +} + +/* read multiple registers */ +static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, + int len) +{ + int ret; + u8 buf[len]; + struct i2c_msg msg[2] = { + { + .addr = priv->cfg->i2c_address, + .flags = 0, + .len = 1, + .buf = ®, + }, { + .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, + .len = sizeof(buf), + .buf = buf, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + memcpy(val, buf, len); + ret = 0; + } else { + warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* write single register */ +static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val) +{ + return tda18212_wr_regs(priv, reg, &val, 1); +} + +/* read single register */ +static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val) +{ + return tda18212_rd_regs(priv, reg, val, 1); +} + +#if 0 /* keep, useful when developing driver */ +static void tda18212_dump_regs(struct tda18212_priv *priv) +{ + int i; + u8 buf[256]; + + #define TDA18212_RD_LEN 32 + for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) + tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN); + + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, + sizeof(buf), true); + + return; +} +#endif + +static int tda18212_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct tda18212_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; + u32 if_khz; + u8 buf[9]; + static const u8 bw_params[][3] = { + /* 0f 13 23 */ + { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */ + { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */ + { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */ + { 0x92, 0x53, 0x03 }, /* DVB-C */ + }; + + dbg("%s: delsys=%d RF=%d BW=%d", __func__, + c->delivery_system, c->frequency, c->bandwidth_hz); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + switch (c->delivery_system) { + case SYS_DVBT: + switch (c->bandwidth_hz) { + case 6000000: + if_khz = priv->cfg->if_dvbt_6; + i = 0; + break; + case 7000000: + if_khz = priv->cfg->if_dvbt_7; + i = 1; + break; + case 8000000: + if_khz = priv->cfg->if_dvbt_8; + i = 2; + break; + default: + ret = -EINVAL; + goto error; + } + break; + case SYS_DVBC_ANNEX_AC: + if_khz = priv->cfg->if_dvbc; + i = 3; + break; + default: + ret = -EINVAL; + goto error; + } + + ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]); + if (ret) + goto error; + + ret = tda18212_wr_reg(priv, 0x06, 0x00); + if (ret) + goto error; + + ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]); + if (ret) + goto error; + + buf[0] = 0x02; + buf[1] = bw_params[i][1]; + buf[2] = 0x03; /* default value */ + buf[3] = if_khz / 50; + buf[4] = ((c->frequency / 1000) >> 16) & 0xff; + buf[5] = ((c->frequency / 1000) >> 8) & 0xff; + buf[6] = ((c->frequency / 1000) >> 0) & 0xff; + buf[7] = 0xc1; + buf[8] = 0x01; + ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf)); + if (ret) + goto error; + +exit: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + return ret; + +error: + dbg("%s: failed:%d", __func__, ret); + goto exit; +} + +static int tda18212_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops tda18212_tuner_ops = { + .info = { + .name = "NXP TDA18212", + + .frequency_min = 48000000, + .frequency_max = 864000000, + .frequency_step = 1000, + }, + + .release = tda18212_release, + + .set_params = tda18212_set_params, +}; + +struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18212_config *cfg) +{ + struct tda18212_priv *priv = NULL; + int ret; + u8 val; + + priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + fe->tuner_priv = priv; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* check if the tuner is there */ + ret = tda18212_rd_reg(priv, 0x00, &val); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); + if (ret || val != 0xc7) { + kfree(priv); + return NULL; + } + + info("NXP TDA18212HN successfully identified."); + + memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +} +EXPORT_SYMBOL(tda18212_attach); + +MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * NXP TDA18212HN silicon tuner driver + * + * Copyright (C) 2011 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TDA18212_H +#define TDA18212_H + +#include "dvb_frontend.h" + +struct tda18212_config { + u8 i2c_address; + + u16 if_dvbt_6; + u16 if_dvbt_7; + u16 if_dvbt_8; + u16 if_dvbc; +}; + +#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \ + (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18212_config *cfg); +#else +static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18212_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18212_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * NXP TDA18212HN silicon tuner driver + * + * Copyright (C) 2011 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TDA18212_PRIV_H +#define TDA18212_PRIV_H + +#include "tda18212.h" + +#define LOG_PREFIX "tda18212" + +#undef dbg +#define dbg(f, arg...) \ + if (debug) \ + printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +struct tda18212_priv { + struct tda18212_config *cfg; + struct i2c_adapter *i2c; +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,334 @@ +/* + * NXP TDA18218HN silicon tuner driver + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "tda18218.h" +#include "tda18218_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +/* write multiple registers */ +static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) +{ + int ret = 0; + u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg->i2c_address, + .flags = 0, + .buf = buf, + } + }; + + msg_len_max = priv->cfg->i2c_wr_max - 1; + quotient = len / msg_len_max; + remainder = len % msg_len_max; + msg_len = msg_len_max; + for (i = 0; (i <= quotient && remainder); i++) { + if (i == quotient) /* set len of the last msg */ + msg_len = remainder; + + msg[0].len = msg_len + 1; + buf[0] = reg + i * msg_len_max; + memcpy(&buf[1], &val[i * msg_len_max], msg_len); + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret != 1) + break; + } + + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* read multiple registers */ +static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) +{ + int ret; + u8 buf[reg+len]; /* we must start read always from reg 0x00 */ + struct i2c_msg msg[2] = { + { + .addr = priv->cfg->i2c_address, + .flags = 0, + .len = 1, + .buf = "\x00", + }, { + .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, + .len = sizeof(buf), + .buf = buf, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + memcpy(val, &buf[reg], len); + ret = 0; + } else { + warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* write single register */ +static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val) +{ + return tda18218_wr_regs(priv, reg, &val, 1); +} + +/* read single register */ + +static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val) +{ + return tda18218_rd_regs(priv, reg, val, 1); +} + +static int tda18218_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda18218_priv *priv = fe->tuner_priv; + int ret; + u8 buf[3], i, BP_Filter, LP_Fc; + u32 LO_Frac; + /* TODO: find out correct AGC algorithm */ + u8 agc[][2] = { + { R20_AGC11, 0x60 }, + { R23_AGC21, 0x02 }, + { R20_AGC11, 0xa0 }, + { R23_AGC21, 0x09 }, + { R20_AGC11, 0xe0 }, + { R23_AGC21, 0x0c }, + { R20_AGC11, 0x40 }, + { R23_AGC21, 0x01 }, + { R20_AGC11, 0x80 }, + { R23_AGC21, 0x08 }, + { R20_AGC11, 0xc0 }, + { R23_AGC21, 0x0b }, + { R24_AGC22, 0x1c }, + { R24_AGC22, 0x0c }, + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* low-pass filter cut-off frequency */ + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + LP_Fc = 0; + LO_Frac = params->frequency + 4000000; + break; + case BANDWIDTH_7_MHZ: + LP_Fc = 1; + LO_Frac = params->frequency + 3500000; + break; + case BANDWIDTH_8_MHZ: + default: + LP_Fc = 2; + LO_Frac = params->frequency + 4000000; + break; + } + + /* band-pass filter */ + if (LO_Frac < 188000000) + BP_Filter = 3; + else if (LO_Frac < 253000000) + BP_Filter = 4; + else if (LO_Frac < 343000000) + BP_Filter = 5; + else + BP_Filter = 6; + + buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */ + buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */ + buf[2] = priv->regs[R1C_AGC2B]; + ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3); + if (ret) + goto error; + + buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */ + buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */ + buf[2] = (LO_Frac / 1000) << 4 | + (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */ + ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3); + if (ret) + goto error; + + buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */ + ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); + if (ret) + goto error; + + buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */ + ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); + if (ret) + goto error; + + /* trigger AGC */ + for (i = 0; i < ARRAY_SIZE(agc); i++) { + ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]); + if (ret) + goto error; + } + +error: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (ret) + dbg("%s: failed ret:%d", __func__, ret); + + return ret; +} + +static int tda18218_sleep(struct dvb_frontend *fe) +{ + struct tda18218_priv *priv = fe->tuner_priv; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* standby */ + ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (ret) + dbg("%s: failed ret:%d", __func__, ret); + + return ret; +} + +static int tda18218_init(struct dvb_frontend *fe) +{ + struct tda18218_priv *priv = fe->tuner_priv; + int ret; + + /* TODO: calibrations */ + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + if (ret) + dbg("%s: failed ret:%d", __func__, ret); + + return ret; +} + +static int tda18218_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops tda18218_tuner_ops = { + .info = { + .name = "NXP TDA18218", + + .frequency_min = 174000000, + .frequency_max = 864000000, + .frequency_step = 1000, + }, + + .release = tda18218_release, + .init = tda18218_init, + .sleep = tda18218_sleep, + + .set_params = tda18218_set_params, +}; + +struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18218_config *cfg) +{ + struct tda18218_priv *priv = NULL; + u8 val; + int ret; + /* chip default registers values */ + static u8 def_regs[] = { + 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40, + 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00, + 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01, + 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9, + 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00, + 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6 + }; + + priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + fe->tuner_priv = priv; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ + + /* check if the tuner is there */ + ret = tda18218_rd_reg(priv, R00_ID, &val); + dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); + if (ret || val != def_regs[R00_ID]) { + kfree(priv); + return NULL; + } + + info("NXP TDA18218HN successfully identified."); + + memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops, + sizeof(struct dvb_tuner_ops)); + memcpy(priv->regs, def_regs, sizeof(def_regs)); + + /* loop-through enabled chip default register values */ + if (priv->cfg->loop_through) { + priv->regs[R17_PD1] = 0xb0; + priv->regs[R18_PD2] = 0x59; + } + + /* standby */ + ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); + if (ret) + dbg("%s: failed ret:%d", __func__, ret); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ + + return fe; +} +EXPORT_SYMBOL(tda18218_attach); + +MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * NXP TDA18218HN silicon tuner driver + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TDA18218_H +#define TDA18218_H + +#include "dvb_frontend.h" + +struct tda18218_config { + u8 i2c_address; + u8 i2c_wr_max; + u8 loop_through:1; +}; + +#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \ + (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18218_config *cfg); +#else +static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct tda18218_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18218_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,106 @@ +/* + * NXP TDA18218HN silicon tuner driver + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef TDA18218_PRIV_H +#define TDA18218_PRIV_H + +#define LOG_PREFIX "tda18218" + +#undef dbg +#define dbg(f, arg...) \ + if (debug) \ + printk(KERN_DEBUG LOG_PREFIX": " f "\n" , ## arg) +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +#define R00_ID 0x00 /* ID byte */ +#define R01_R1 0x01 /* Read byte 1 */ +#define R02_R2 0x02 /* Read byte 2 */ +#define R03_R3 0x03 /* Read byte 3 */ +#define R04_R4 0x04 /* Read byte 4 */ +#define R05_R5 0x05 /* Read byte 5 */ +#define R06_R6 0x06 /* Read byte 6 */ +#define R07_MD1 0x07 /* Main divider byte 1 */ +#define R08_PSM1 0x08 /* PSM byte 1 */ +#define R09_MD2 0x09 /* Main divider byte 2 */ +#define R0A_MD3 0x0a /* Main divider byte 1 */ +#define R0B_MD4 0x0b /* Main divider byte 4 */ +#define R0C_MD5 0x0c /* Main divider byte 5 */ +#define R0D_MD6 0x0d /* Main divider byte 6 */ +#define R0E_MD7 0x0e /* Main divider byte 7 */ +#define R0F_MD8 0x0f /* Main divider byte 8 */ +#define R10_CD1 0x10 /* Call divider byte 1 */ +#define R11_CD2 0x11 /* Call divider byte 2 */ +#define R12_CD3 0x12 /* Call divider byte 3 */ +#define R13_CD4 0x13 /* Call divider byte 4 */ +#define R14_CD5 0x14 /* Call divider byte 5 */ +#define R15_CD6 0x15 /* Call divider byte 6 */ +#define R16_CD7 0x16 /* Call divider byte 7 */ +#define R17_PD1 0x17 /* Power-down byte 1 */ +#define R18_PD2 0x18 /* Power-down byte 2 */ +#define R19_XTOUT 0x19 /* XTOUT byte */ +#define R1A_IF1 0x1a /* IF byte 1 */ +#define R1B_IF2 0x1b /* IF byte 2 */ +#define R1C_AGC2B 0x1c /* AGC2b byte */ +#define R1D_PSM2 0x1d /* PSM byte 2 */ +#define R1E_PSM3 0x1e /* PSM byte 3 */ +#define R1F_PSM4 0x1f /* PSM byte 4 */ +#define R20_AGC11 0x20 /* AGC1 byte 1 */ +#define R21_AGC12 0x21 /* AGC1 byte 2 */ +#define R22_AGC13 0x22 /* AGC1 byte 3 */ +#define R23_AGC21 0x23 /* AGC2 byte 1 */ +#define R24_AGC22 0x24 /* AGC2 byte 2 */ +#define R25_AAGC 0x25 /* Analog AGC byte */ +#define R26_RC 0x26 /* RC byte */ +#define R27_RSSI 0x27 /* RSSI byte */ +#define R28_IRCAL1 0x28 /* IR CAL byte 1 */ +#define R29_IRCAL2 0x29 /* IR CAL byte 2 */ +#define R2A_IRCAL3 0x2a /* IR CAL byte 3 */ +#define R2B_IRCAL4 0x2b /* IR CAL byte 4 */ +#define R2C_RFCAL1 0x2c /* RF CAL byte 1 */ +#define R2D_RFCAL2 0x2d /* RF CAL byte 2 */ +#define R2E_RFCAL3 0x2e /* RF CAL byte 3 */ +#define R2F_RFCAL4 0x2f /* RF CAL byte 4 */ +#define R30_RFCAL5 0x30 /* RF CAL byte 5 */ +#define R31_RFCAL6 0x31 /* RF CAL byte 6 */ +#define R32_RFCAL7 0x32 /* RF CAL byte 7 */ +#define R33_RFCAL8 0x33 /* RF CAL byte 8 */ +#define R34_RFCAL9 0x34 /* RF CAL byte 9 */ +#define R35_RFCAL10 0x35 /* RF CAL byte 10 */ +#define R36_RFCALRAM1 0x36 /* RF CAL RAM byte 1 */ +#define R37_RFCALRAM2 0x37 /* RF CAL RAM byte 2 */ +#define R38_MARGIN 0x38 /* Margin byte */ +#define R39_FMAX1 0x39 /* Fmax byte 1 */ +#define R3A_FMAX2 0x3a /* Fmax byte 2 */ + +#define TDA18218_NUM_REGS 59 + +struct tda18218_priv { + struct tda18218_config *cfg; + struct i2c_adapter *i2c; + + u8 regs[TDA18218_NUM_REGS]; +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-common.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-common.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,685 @@ +/* + tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "tda18271-priv.h" + +static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct tda18271_priv *priv = fe->tuner_priv; + enum tda18271_i2c_gate gate; + int ret = 0; + + switch (priv->gate) { + case TDA18271_GATE_DIGITAL: + case TDA18271_GATE_ANALOG: + gate = priv->gate; + break; + case TDA18271_GATE_AUTO: + default: + switch (priv->mode) { + case TDA18271_DIGITAL: + gate = TDA18271_GATE_DIGITAL; + break; + case TDA18271_ANALOG: + default: + gate = TDA18271_GATE_ANALOG; + break; + } + } + + switch (gate) { + case TDA18271_GATE_ANALOG: + if (fe->ops.analog_ops.i2c_gate_ctrl) + ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); + break; + case TDA18271_GATE_DIGITAL: + if (fe->ops.i2c_gate_ctrl) + ret = fe->ops.i2c_gate_ctrl(fe, enable); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +}; + +/*---------------------------------------------------------------------*/ + +static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_reg("=== TDA18271 REG DUMP ===\n"); + tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); + tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); + tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); + tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); + tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); + tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); + tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); + tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); + tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); + tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); + tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); + tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); + tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); + tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); + tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); + tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); + + /* only dump extended regs if DBG_ADV is set */ + if (!(tda18271_debug & DBG_ADV)) + return; + + /* W indicates write-only registers. + * Register dump for write-only registers shows last value written. */ + + tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); + tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); + tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); + tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); + tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); + tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); + tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); + tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); + tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); + tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); + tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); + tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); + tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); + tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); + tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); + tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); + tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); + tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); + tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); + tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); + tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); + tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); + tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); +} + +int tda18271_read_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf = 0x00; + int ret; + struct i2c_msg msg[] = { + { .addr = priv->i2c_props.addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, + .buf = regs, .len = 16 } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_props.adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + if (tda18271_debug & DBG_REG) + tda18271_dump_regs(fe, 0); + + return (ret == 2 ? 0 : ret); +} + +int tda18271_read_extended(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char regdump[TDA18271_NUM_REGS]; + unsigned char buf = 0x00; + int ret, i; + struct i2c_msg msg[] = { + { .addr = priv->i2c_props.addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, + .buf = regdump, .len = TDA18271_NUM_REGS } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_props.adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + for (i = 0; i < TDA18271_NUM_REGS; i++) { + /* don't update write-only registers */ + if ((i != R_EB9) && + (i != R_EB16) && + (i != R_EB17) && + (i != R_EB19) && + (i != R_EB20)) + regs[i] = regdump[i]; + } + + if (tda18271_debug & DBG_REG) + tda18271_dump_regs(fe, 1); + + return (ret == 2 ? 0 : ret); +} + +int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf[TDA18271_NUM_REGS + 1]; + struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0, + .buf = buf }; + int i, ret = 1, max; + + BUG_ON((len == 0) || (idx + len > sizeof(buf))); + + + switch (priv->small_i2c) { + case TDA18271_03_BYTE_CHUNK_INIT: + max = 3; + break; + case TDA18271_08_BYTE_CHUNK_INIT: + max = 8; + break; + case TDA18271_16_BYTE_CHUNK_INIT: + max = 16; + break; + case TDA18271_39_BYTE_CHUNK_INIT: + default: + max = 39; + } + + tda18271_i2c_gate_ctrl(fe, 1); + while (len) { + if (max > len) + max = len; + + buf[0] = idx; + for (i = 1; i <= max; i++) + buf[i] = regs[idx - 1 + i]; + + msg.len = max + 1; + + /* write registers */ + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + if (ret != 1) + break; + + idx += max; + len -= max; + } + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 1) + tda_err("ERROR: idx = 0x%x, len = %d, " + "i2c_transfer returned: %d\n", idx, max, ret); + + return (ret == 1 ? 0 : ret); +} + +/*---------------------------------------------------------------------*/ + +int tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4; + + regs[r_cp] &= ~0x20; + regs[r_cp] |= ((force & 1) << 5); + + return tda18271_write_regs(fe, r_cp, 1); +} + +int tda18271_init_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_dbg("initializing registers for device @ %d-%04x\n", + i2c_adapter_id(priv->i2c_props.adap), + priv->i2c_props.addr); + + /* initialize registers */ + switch (priv->id) { + case TDA18271HDC1: + regs[R_ID] = 0x83; + break; + case TDA18271HDC2: + regs[R_ID] = 0x84; + break; + }; + + regs[R_TM] = 0x08; + regs[R_PL] = 0x80; + regs[R_EP1] = 0xc6; + regs[R_EP2] = 0xdf; + regs[R_EP3] = 0x16; + regs[R_EP4] = 0x60; + regs[R_EP5] = 0x80; + regs[R_CPD] = 0x80; + regs[R_CD1] = 0x00; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x00; + regs[R_MD1] = 0x00; + regs[R_MD2] = 0x00; + regs[R_MD3] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB1] = 0xff; + break; + case TDA18271HDC2: + regs[R_EB1] = 0xfc; + break; + }; + + regs[R_EB2] = 0x01; + regs[R_EB3] = 0x84; + regs[R_EB4] = 0x41; + regs[R_EB5] = 0x01; + regs[R_EB6] = 0x84; + regs[R_EB7] = 0x40; + regs[R_EB8] = 0x07; + regs[R_EB9] = 0x00; + regs[R_EB10] = 0x00; + regs[R_EB11] = 0x96; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB12] = 0x0f; + break; + case TDA18271HDC2: + regs[R_EB12] = 0x33; + break; + }; + + regs[R_EB13] = 0xc1; + regs[R_EB14] = 0x00; + regs[R_EB15] = 0x8f; + regs[R_EB16] = 0x00; + regs[R_EB17] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB18] = 0x00; + break; + case TDA18271HDC2: + regs[R_EB18] = 0x8c; + break; + }; + + regs[R_EB19] = 0x00; + regs[R_EB20] = 0x20; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB21] = 0x33; + break; + case TDA18271HDC2: + regs[R_EB21] = 0xb3; + break; + }; + + regs[R_EB22] = 0x48; + regs[R_EB23] = 0xb0; + + tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + + /* setup agc1 gain */ + regs[R_EB17] = 0x00; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x03; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x43; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x4c; + tda18271_write_regs(fe, R_EB17, 1); + + /* setup agc2 gain */ + if ((priv->id) == TDA18271HDC1) { + regs[R_EB20] = 0xa0; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xa7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xe7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + } + + /* image rejection calibration */ + + /* low-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x81; + regs[R_CPD] = 0xcc; + regs[R_CD1] = 0x6c; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xcd; + regs[R_MD1] = 0x77; + regs[R_MD2] = 0x08; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + + if ((priv->id) == TDA18271HDC2) { + /* main pll cp source on */ + tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); + msleep(1); + + /* main pll cp source off */ + tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); + } + + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted low measurement */ + + regs[R_EP5] = 0x85; + regs[R_CPD] = 0xcb; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x70; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image low optimization completion */ + + /* mid-band */ + regs[R_EP5] = 0x82; + regs[R_CPD] = 0xa8; + regs[R_CD2] = 0x00; + regs[R_MPD] = 0xa9; + regs[R_MD1] = 0x73; + regs[R_MD2] = 0x1a; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted mid measurement */ + + regs[R_EP5] = 0x86; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0xa0; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image mid optimization completion */ + + /* high-band */ + regs[R_EP5] = 0x83; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x00; + regs[R_MPD] = 0x99; + regs[R_MD1] = 0x71; + regs[R_MD2] = 0xcd; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted high measurement */ + + regs[R_EP5] = 0x87; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x50; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image high optimization completion */ + + /* return to normal mode */ + regs[R_EP4] = 0x64; + tda18271_write_regs(fe, R_EP4, 1); + + /* synchronize */ + tda18271_write_regs(fe, R_EP1, 1); + + return 0; +} + +/*---------------------------------------------------------------------*/ + +/* + * Standby modes, EP3 [7:5] + * + * | SM || SM_LT || SM_XT || mode description + * |=====\\=======\\=======\\=================================== + * | 0 || 0 || 0 || normal mode + * |-----||-------||-------||----------------------------------- + * | || || || standby mode w/ slave tuner output + * | 1 || 0 || 0 || & loop thru & xtal oscillator on + * |-----||-------||-------||----------------------------------- + * | 1 || 1 || 0 || standby mode w/ xtal oscillator on + * |-----||-------||-------||----------------------------------- + * | 1 || 1 || 1 || power off + * + */ + +int tda18271_set_standby_mode(struct dvb_frontend *fe, + int sm, int sm_lt, int sm_xt) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + if (tda18271_debug & DBG_ADV) + tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); + + regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ + regs[R_EP3] |= (sm ? (1 << 7) : 0) | + (sm_lt ? (1 << 6) : 0) | + (sm_xt ? (1 << 5) : 0); + + return tda18271_write_regs(fe, R_EP3, 1); +} + +/*---------------------------------------------------------------------*/ + +int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) +{ + /* sets main post divider & divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); + if (tda_fail(ret)) + goto fail; + + regs[R_MPD] = (0x7f & pd); + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_MD1] = 0x7f & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; +fail: + return ret; +} + +int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) +{ + /* sets cal post divider & divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); + if (tda_fail(ret)) + goto fail; + + regs[R_CPD] = pd; + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_CD1] = 0x7f & (div >> 16); + regs[R_CD2] = 0xff & (div >> 8); + regs[R_CD3] = 0xff & div; +fail: + return ret; +} + +/*---------------------------------------------------------------------*/ + +int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) +{ + /* sets bp filter bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EP1] &= ~0x07; /* clear bp filter bits */ + regs[R_EP1] |= (0x07 & val); +fail: + return ret; +} + +int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) +{ + /* sets K & M bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EB13] &= ~0x7c; /* clear k & m bits */ + regs[R_EB13] |= (0x7c & val); +fail: + return ret; +} + +int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) +{ + /* sets rf band bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EP2] &= ~0xe0; /* clear rf band bits */ + regs[R_EP2] |= (0xe0 & (val << 5)); +fail: + return ret; +} + +int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) +{ + /* sets gain taper bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ + regs[R_EP2] |= (0x1f & val); +fail: + return ret; +} + +int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) +{ + /* sets IR Meas bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); + if (tda_fail(ret)) + goto fail; + + regs[R_EP5] &= ~0x07; + regs[R_EP5] |= (0x07 & val); +fail: + return ret; +} + +int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) +{ + /* sets rf cal byte (RFC_Cprog), but does not write it */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); + /* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range + * for frequencies above 61.1 MHz. In these cases, the internal RF + * tracking filters calibration mechanism is used. + * + * There is no need to warn the user about this. + */ + if (ret < 0) + goto fail; + + regs[R_EB14] = val; +fail: + return ret; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-fe.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1345 @@ +/* + tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include "tda18271-priv.h" + +int tda18271_debug; +module_param_named(debug, tda18271_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level " + "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); + +static int tda18271_cal_on_startup = -1; +module_param_named(cal, tda18271_cal_on_startup, int, 0644); +MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); + +static DEFINE_MUTEX(tda18271_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +/*---------------------------------------------------------------------*/ + +static int tda18271_toggle_output(struct dvb_frontend *fe, int standby) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0, + priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0, + priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0); + + if (tda_fail(ret)) + goto fail; + + tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n", + standby ? "standby" : "active", + priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on", + priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on"); +fail: + return ret; +} + +/*---------------------------------------------------------------------*/ + +static inline int charge_pump_source(struct dvb_frontend *fe, int force) +{ + struct tda18271_priv *priv = fe->tuner_priv; + return tda18271_charge_pump_source(fe, + (priv->role == TDA18271_SLAVE) ? + TDA18271_CAL_PLL : + TDA18271_MAIN_PLL, force); +} + +static inline void tda18271_set_if_notch(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x80; /* IF notch = 0 */ + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x80; /* IF notch = 1 */ + break; + } +} + +static int tda18271_channel_configuration(struct dvb_frontend *fe, + struct tda18271_std_map_item *map, + u32 freq, u32 bw) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + u32 N; + + /* update TV broadcast parameters */ + + /* set standard */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + regs[R_EP3] |= (map->agc_mode << 3) | map->std; + + if (priv->id == TDA18271HDC2) { + /* set rfagc to high speed mode */ + regs[R_EP3] &= ~0x04; + } + + /* set cal mode to normal */ + regs[R_EP4] &= ~0x03; + + /* update IF output level */ + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + regs[R_EP4] |= (map->if_lvl << 2); + + /* update FM_RFn */ + regs[R_EP4] &= ~0x80; + regs[R_EP4] |= map->fm_rfn << 7; + + /* update rf top / if top */ + regs[R_EB22] = 0x00; + regs[R_EB22] |= map->rfagc_top; + ret = tda18271_write_regs(fe, R_EB22, 1); + if (tda_fail(ret)) + goto fail; + + /* --------------------------------------------------------------- */ + + /* disable Power Level Indicator */ + regs[R_EP1] |= 0x40; + + /* make sure thermometer is off */ + regs[R_TM] &= ~0x10; + + /* frequency dependent parameters */ + + tda18271_calc_ir_measure(fe, &freq); + + tda18271_calc_bp_filter(fe, &freq); + + tda18271_calc_rf_band(fe, &freq); + + tda18271_calc_gain_taper(fe, &freq); + + /* --------------------------------------------------------------- */ + + /* dual tuner and agc1 extra configuration */ + + switch (priv->role) { + case TDA18271_MASTER: + regs[R_EB1] |= 0x04; /* main vco */ + break; + case TDA18271_SLAVE: + regs[R_EB1] &= ~0x04; /* cal vco */ + break; + } + + /* agc1 always active */ + regs[R_EB1] &= ~0x02; + + /* agc1 has priority on agc2 */ + regs[R_EB1] &= ~0x01; + + ret = tda18271_write_regs(fe, R_EB1, 1); + if (tda_fail(ret)) + goto fail; + + /* --------------------------------------------------------------- */ + + N = map->if_freq * 1000 + freq; + + switch (priv->role) { + case TDA18271_MASTER: + tda18271_calc_main_pll(fe, N); + tda18271_set_if_notch(fe); + tda18271_write_regs(fe, R_MPD, 4); + break; + case TDA18271_SLAVE: + tda18271_calc_cal_pll(fe, N); + tda18271_write_regs(fe, R_CPD, 4); + + regs[R_MPD] = regs[R_CPD] & 0x7f; + tda18271_set_if_notch(fe); + tda18271_write_regs(fe, R_MPD, 1); + break; + } + + ret = tda18271_write_regs(fe, R_TM, 7); + if (tda_fail(ret)) + goto fail; + + /* force charge pump source */ + charge_pump_source(fe, 1); + + msleep(1); + + /* return pll to normal operation */ + charge_pump_source(fe, 0); + + msleep(20); + + if (priv->id == TDA18271HDC2) { + /* set rfagc to normal speed mode */ + if (map->fm_rfn) + regs[R_EP3] &= ~0x04; + else + regs[R_EP3] |= 0x04; + ret = tda18271_write_regs(fe, R_EP3, 1); + } +fail: + return ret; +} + +static int tda18271_read_thermometer(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int tm; + + /* switch thermometer on */ + regs[R_TM] |= 0x10; + tda18271_write_regs(fe, R_TM, 1); + + /* read thermometer info */ + tda18271_read_regs(fe); + + if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || + (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { + + if ((regs[R_TM] & 0x20) == 0x20) + regs[R_TM] &= ~0x20; + else + regs[R_TM] |= 0x20; + + tda18271_write_regs(fe, R_TM, 1); + + msleep(10); /* temperature sensing */ + + /* read thermometer info */ + tda18271_read_regs(fe); + } + + tm = tda18271_lookup_thermometer(fe); + + /* switch thermometer off */ + regs[R_TM] &= ~0x10; + tda18271_write_regs(fe, R_TM, 1); + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + tda18271_write_regs(fe, R_EP4, 1); + + return tm; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, + u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + unsigned char *regs = priv->tda18271_regs; + int i, ret; + u8 tm_current, dc_over_dt, rf_tab; + s32 rfcal_comp, approx; + + /* power up */ + ret = tda18271_set_standby_mode(fe, 0, 0, 0); + if (tda_fail(ret)) + goto fail; + + /* read die current temperature */ + tm_current = tda18271_read_thermometer(fe); + + /* frequency dependent parameters */ + + tda18271_calc_rf_cal(fe, &freq); + rf_tab = regs[R_EB14]; + + i = tda18271_lookup_rf_band(fe, &freq, NULL); + if (tda_fail(i)) + return i; + + if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { + approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) + + map[i].rf_b1 + rf_tab; + } else { + approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) + + map[i].rf_b2 + rf_tab; + } + + if (approx < 0) + approx = 0; + if (approx > 255) + approx = 255; + + tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); + + /* calculate temperature compensation */ + rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000; + + regs[R_EB14] = (unsigned char)(approx + rfcal_comp); + ret = tda18271_write_regs(fe, R_EB14, 1); +fail: + return ret; +} + +static int tda18271_por(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + + /* power up detector 1 */ + regs[R_EB12] &= ~0x20; + ret = tda18271_write_regs(fe, R_EB12, 1); + if (tda_fail(ret)) + goto fail; + + regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + ret = tda18271_write_regs(fe, R_EB18, 1); + if (tda_fail(ret)) + goto fail; + + regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ + + /* POR mode */ + ret = tda18271_set_standby_mode(fe, 1, 0, 0); + if (tda_fail(ret)) + goto fail; + + /* disable 1.5 MHz low pass filter */ + regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ + regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ + ret = tda18271_write_regs(fe, R_EB21, 3); +fail: + return ret; +} + +static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 N; + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + tda18271_write_regs(fe, R_EP4, 1); + + /* switch off agc1 */ + regs[R_EP3] |= 0x40; /* sm_lt = 1 */ + + regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + /* frequency dependent parameters */ + + tda18271_calc_bp_filter(fe, &freq); + tda18271_calc_gain_taper(fe, &freq); + tda18271_calc_rf_band(fe, &freq); + tda18271_calc_km(fe, &freq); + + tda18271_write_regs(fe, R_EP1, 3); + tda18271_write_regs(fe, R_EB13, 1); + + /* main pll charge pump source */ + tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); + + /* cal pll charge pump source */ + tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1); + + /* force dcdc converter to 0 V */ + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + /* disable plls lock */ + regs[R_EB20] &= ~0x20; + tda18271_write_regs(fe, R_EB20, 1); + + /* set CAL mode to RF tracking filter calibration */ + regs[R_EP4] |= 0x03; + tda18271_write_regs(fe, R_EP4, 2); + + /* --------------------------------------------------------------- */ + + /* set the internal calibration signal */ + N = freq; + + tda18271_calc_cal_pll(fe, N); + tda18271_write_regs(fe, R_CPD, 4); + + /* downconvert internal calibration */ + N += 1000000; + + tda18271_calc_main_pll(fe, N); + tda18271_write_regs(fe, R_MPD, 4); + + msleep(5); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + /* --------------------------------------------------------------- */ + + /* normal operation for the main pll */ + tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); + + /* normal operation for the cal pll */ + tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0); + + msleep(10); /* plls locking */ + + /* launch the rf tracking filters calibration */ + regs[R_EB20] |= 0x20; + tda18271_write_regs(fe, R_EB20, 1); + + msleep(60); /* calibration */ + + /* --------------------------------------------------------------- */ + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + + /* switch on agc1 */ + regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ + + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + tda18271_write_regs(fe, R_EP3, 2); + + /* synchronization */ + tda18271_write_regs(fe, R_EP1, 1); + + /* get calibration result */ + tda18271_read_extended(fe); + + return regs[R_EB14]; +} + +static int tda18271_powerscan(struct dvb_frontend *fe, + u32 *freq_in, u32 *freq_out) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int sgn, bcal, count, wait, ret; + u8 cid_target; + u16 count_limit; + u32 freq; + + freq = *freq_in; + + tda18271_calc_rf_band(fe, &freq); + tda18271_calc_rf_cal(fe, &freq); + tda18271_calc_gain_taper(fe, &freq); + tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EB14, 1); + + /* downconvert frequency */ + freq += 1000000; + + tda18271_calc_main_pll(fe, freq); + tda18271_write_regs(fe, R_MPD, 4); + + msleep(5); /* pll locking */ + + /* detection mode */ + regs[R_EP4] &= ~0x03; + regs[R_EP4] |= 0x01; + tda18271_write_regs(fe, R_EP4, 1); + + /* launch power detection measurement */ + tda18271_write_regs(fe, R_EP2, 1); + + /* read power detection info, stored in EB10 */ + ret = tda18271_read_extended(fe); + if (tda_fail(ret)) + return ret; + + /* algorithm initialization */ + sgn = 1; + *freq_out = *freq_in; + bcal = 0; + count = 0; + wait = false; + + while ((regs[R_EB10] & 0x3f) < cid_target) { + /* downconvert updated freq to 1 MHz */ + freq = *freq_in + (sgn * count) + 1000000; + + tda18271_calc_main_pll(fe, freq); + tda18271_write_regs(fe, R_MPD, 4); + + if (wait) { + msleep(5); /* pll locking */ + wait = false; + } else + udelay(100); /* pll locking */ + + /* launch power detection measurement */ + tda18271_write_regs(fe, R_EP2, 1); + + /* read power detection info, stored in EB10 */ + ret = tda18271_read_extended(fe); + if (tda_fail(ret)) + return ret; + + count += 200; + + if (count <= count_limit) + continue; + + if (sgn <= 0) + break; + + sgn = -1 * sgn; + count = 200; + wait = true; + } + + if ((regs[R_EB10] & 0x3f) >= cid_target) { + bcal = 1; + *freq_out = freq - 1000000; + } else + bcal = 0; + + tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", + bcal, *freq_in, *freq_out, freq); + + return bcal; +} + +static int tda18271_powerscan_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + + /* set standard to digital */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + regs[R_EP3] |= 0x12; + + /* set cal mode to normal */ + regs[R_EP4] &= ~0x03; + + /* update IF output level */ + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + + ret = tda18271_write_regs(fe, R_EP3, 2); + if (tda_fail(ret)) + goto fail; + + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + ret = tda18271_write_regs(fe, R_EB18, 1); + if (tda_fail(ret)) + goto fail; + + regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ + + /* 1.5 MHz low pass filter */ + regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ + regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ + + ret = tda18271_write_regs(fe, R_EB21, 3); +fail: + return ret; +} + +static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + unsigned char *regs = priv->tda18271_regs; + int bcal, rf, i; + s32 divisor, dividend; +#define RF1 0 +#define RF2 1 +#define RF3 2 + u32 rf_default[3]; + u32 rf_freq[3]; + s32 prog_cal[3]; + s32 prog_tab[3]; + + i = tda18271_lookup_rf_band(fe, &freq, NULL); + + if (tda_fail(i)) + return i; + + rf_default[RF1] = 1000 * map[i].rf1_def; + rf_default[RF2] = 1000 * map[i].rf2_def; + rf_default[RF3] = 1000 * map[i].rf3_def; + + for (rf = RF1; rf <= RF3; rf++) { + if (0 == rf_default[rf]) + return 0; + tda_cal("freq = %d, rf = %d\n", freq, rf); + + /* look for optimized calibration frequency */ + bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); + if (tda_fail(bcal)) + return bcal; + + tda18271_calc_rf_cal(fe, &rf_freq[rf]); + prog_tab[rf] = (s32)regs[R_EB14]; + + if (1 == bcal) + prog_cal[rf] = + (s32)tda18271_calibrate_rf(fe, rf_freq[rf]); + else + prog_cal[rf] = prog_tab[rf]; + + switch (rf) { + case RF1: + map[i].rf_a1 = 0; + map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]); + map[i].rf1 = rf_freq[RF1] / 1000; + break; + case RF2: + dividend = (prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]); + divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; + map[i].rf_a1 = (dividend / divisor); + map[i].rf2 = rf_freq[RF2] / 1000; + break; + case RF3: + dividend = (prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]); + divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; + map[i].rf_a2 = (dividend / divisor); + map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]); + map[i].rf3 = rf_freq[RF3] / 1000; + break; + default: + BUG(); + } + } + + return 0; +} + +static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned int i; + int ret; + + tda_info("tda18271: performing RF tracking filter calibration\n"); + + /* wait for die temperature stabilization */ + msleep(200); + + ret = tda18271_powerscan_init(fe); + if (tda_fail(ret)) + goto fail; + + /* rf band calibration */ + for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) { + ret = + tda18271_rf_tracking_filters_init(fe, 1000 * + priv->rf_cal_state[i].rfmax); + if (tda_fail(ret)) + goto fail; + } + + priv->tm_rfcal = tda18271_read_thermometer(fe); +fail: + return ret; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271c2_rf_cal_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + + /* test RF_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x10) == 0) + priv->cal_initialized = false; + + if (priv->cal_initialized) + return 0; + + ret = tda18271_calc_rf_filter_curve(fe); + if (tda_fail(ret)) + goto fail; + + ret = tda18271_por(fe); + if (tda_fail(ret)) + goto fail; + + tda_info("tda18271: RF tracking filter calibration complete\n"); + + priv->cal_initialized = true; + goto end; +fail: + tda_info("tda18271: RF tracking filter calibration failed!\n"); +end: + return ret; +} + +static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe, + u32 freq, u32 bw) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + u32 N = 0; + + /* calculate bp filter */ + tda18271_calc_bp_filter(fe, &freq); + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x60; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x60; + tda18271_write_regs(fe, R_EB7, 1); + + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + regs[R_EB20] = 0xcc; + tda18271_write_regs(fe, R_EB20, 1); + + /* set cal mode to RF tracking filter calibration */ + regs[R_EP4] |= 0x03; + + /* calculate cal pll */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 1250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2; + break; + } + + tda18271_calc_cal_pll(fe, N); + + /* calculate main pll */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2 + 1000000; + break; + } + + tda18271_calc_main_pll(fe, N); + + ret = tda18271_write_regs(fe, R_EP3, 11); + if (tda_fail(ret)) + return ret; + + msleep(5); /* RF tracking filter calibration initialization */ + + /* search for K,M,CO for RF calibration */ + tda18271_calc_km(fe, &freq); + tda18271_write_regs(fe, R_EB13, 1); + + /* search for rf band */ + tda18271_calc_rf_band(fe, &freq); + + /* search for gain taper */ + tda18271_calc_gain_taper(fe, &freq); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x40; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x40; + tda18271_write_regs(fe, R_EB7, 1); + msleep(10); /* pll locking */ + + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + msleep(60); /* RF tracking filter calibration completion */ + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + tda18271_write_regs(fe, R_EP4, 1); + + tda18271_write_regs(fe, R_EP1, 1); + + /* RF tracking filter correction for VHF_Low band */ + if (0 == tda18271_calc_rf_cal(fe, &freq)) + tda18271_write_regs(fe, R_EB14, 1); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_ir_cal_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int ret; + + ret = tda18271_read_regs(fe); + if (tda_fail(ret)) + goto fail; + + /* test IR_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x08) == 0) + ret = tda18271_init_regs(fe); +fail: + return ret; +} + +static int tda18271_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret; + + mutex_lock(&priv->lock); + + /* full power up */ + ret = tda18271_set_standby_mode(fe, 0, 0, 0); + if (tda_fail(ret)) + goto fail; + + /* initialization */ + ret = tda18271_ir_cal_init(fe); + if (tda_fail(ret)) + goto fail; + + if (priv->id == TDA18271HDC2) + tda18271c2_rf_cal_init(fe); +fail: + mutex_unlock(&priv->lock); + + return ret; +} + +static int tda18271_sleep(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret; + + mutex_lock(&priv->lock); + + /* enter standby mode, with required output features enabled */ + ret = tda18271_toggle_output(fe, 1); + + mutex_unlock(&priv->lock); + + return ret; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_agc(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret = 0; + + switch (priv->config) { + case 0: + /* no external agc configuration required */ + if (tda18271_debug & DBG_ADV) + tda_dbg("no agc configuration provided\n"); + break; + case 3: + /* switch with GPIO of saa713x */ + tda_dbg("invoking callback\n"); + if (fe->callback) + ret = fe->callback(priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + TDA18271_CALLBACK_CMD_AGC_ENABLE, + priv->mode); + break; + case 1: + case 2: + default: + /* n/a - currently not supported */ + tda_err("unsupported configuration: %d\n", priv->config); + ret = -EINVAL; + break; + } + return ret; +} + +static int tda18271_tune(struct dvb_frontend *fe, + struct tda18271_std_map_item *map, u32 freq, u32 bw) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret; + + tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n", + freq, map->if_freq, bw, map->agc_mode, map->std); + + ret = tda18271_agc(fe); + if (tda_fail(ret)) + tda_warn("failed to configure agc\n"); + + ret = tda18271_init(fe); + if (tda_fail(ret)) + goto fail; + + mutex_lock(&priv->lock); + + switch (priv->id) { + case TDA18271HDC1: + tda18271c1_rf_tracking_filter_calibration(fe, freq, bw); + break; + case TDA18271HDC2: + tda18271c2_rf_tracking_filters_correction(fe, freq); + break; + } + ret = tda18271_channel_configuration(fe, map, freq, bw); + + mutex_unlock(&priv->lock); +fail: + return ret; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std_map = &priv->std; + struct tda18271_std_map_item *map; + int ret; + u32 bw, freq = params->frequency; + + priv->mode = TDA18271_DIGITAL; + + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + map = &std_map->atsc_6; + break; + case QAM_64: + case QAM_256: + map = &std_map->qam_6; + break; + default: + tda_warn("modulation not set!\n"); + return -EINVAL; + } +#if 0 + /* userspace request is already center adjusted */ + freq += 1750000; /* Adjust to center (+1.75MHZ) */ +#endif + bw = 6000000; + } else if (fe->ops.info.type == FE_OFDM) { + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + bw = 6000000; + map = &std_map->dvbt_6; + break; + case BANDWIDTH_7_MHZ: + bw = 7000000; + map = &std_map->dvbt_7; + break; + case BANDWIDTH_8_MHZ: + bw = 8000000; + map = &std_map->dvbt_8; + break; + default: + tda_warn("bandwidth not set!\n"); + return -EINVAL; + } + } else if (fe->ops.info.type == FE_QAM) { + /* DVB-C */ + map = &std_map->qam_8; + bw = 8000000; + } else { + tda_warn("modulation type not supported!\n"); + return -EINVAL; + } + + /* When tuning digital, the analog demod must be tri-stated */ + if (fe->ops.analog_ops.standby) + fe->ops.analog_ops.standby(fe); + + ret = tda18271_tune(fe, map, freq, bw); + + if (tda_fail(ret)) + goto fail; + + priv->frequency = freq; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? + params->u.ofdm.bandwidth : 0; +fail: + return ret; +} + +static int tda18271_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std_map = &priv->std; + struct tda18271_std_map_item *map; + char *mode; + int ret; + u32 freq = params->frequency * 125 * + ((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2; + + priv->mode = TDA18271_ANALOG; + + if (params->mode == V4L2_TUNER_RADIO) { + map = &std_map->fm_radio; + mode = "fm"; + } else if (params->std & V4L2_STD_MN) { + map = &std_map->atv_mn; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + map = &std_map->atv_b; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + map = &std_map->atv_gh; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + map = &std_map->atv_i; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + map = &std_map->atv_dk; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + map = &std_map->atv_l; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + map = &std_map->atv_lc; + mode = "L'"; + } else { + map = &std_map->atv_i; + mode = "xx"; + } + + tda_dbg("setting tda18271 to system %s\n", mode); + + ret = tda18271_tune(fe, map, freq, 0); + + if (tda_fail(ret)) + goto fail; + + priv->frequency = freq; + priv->bandwidth = 0; +fail: + return ret; +} + +static int tda18271_release(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + mutex_lock(&tda18271_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&tda18271_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +/* ------------------------------------------------------------------ */ + +#define tda18271_update_std(std_cfg, name) do { \ + if (map->std_cfg.if_freq + \ + map->std_cfg.agc_mode + map->std_cfg.std + \ + map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) { \ + tda_dbg("Using custom std config for %s\n", name); \ + memcpy(&std->std_cfg, &map->std_cfg, \ + sizeof(struct tda18271_std_map_item)); \ + } } while (0) + +#define tda18271_dump_std_item(std_cfg, name) do { \ + tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, " \ + "if_lvl = %d, rfagc_top = 0x%02x\n", \ + name, std->std_cfg.if_freq, \ + std->std_cfg.agc_mode, std->std_cfg.std, \ + std->std_cfg.if_lvl, std->std_cfg.rfagc_top); \ + } while (0) + +static int tda18271_dump_std_map(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std = &priv->std; + + tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); + tda18271_dump_std_item(fm_radio, " fm "); + tda18271_dump_std_item(atv_b, "atv b "); + tda18271_dump_std_item(atv_dk, "atv dk"); + tda18271_dump_std_item(atv_gh, "atv gh"); + tda18271_dump_std_item(atv_i, "atv i "); + tda18271_dump_std_item(atv_l, "atv l "); + tda18271_dump_std_item(atv_lc, "atv l'"); + tda18271_dump_std_item(atv_mn, "atv mn"); + tda18271_dump_std_item(atsc_6, "atsc 6"); + tda18271_dump_std_item(dvbt_6, "dvbt 6"); + tda18271_dump_std_item(dvbt_7, "dvbt 7"); + tda18271_dump_std_item(dvbt_8, "dvbt 8"); + tda18271_dump_std_item(qam_6, "qam 6 "); + tda18271_dump_std_item(qam_8, "qam 8 "); + + return 0; +} + +static int tda18271_update_std_map(struct dvb_frontend *fe, + struct tda18271_std_map *map) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std = &priv->std; + + if (!map) + return -EINVAL; + + tda18271_update_std(fm_radio, "fm"); + tda18271_update_std(atv_b, "atv b"); + tda18271_update_std(atv_dk, "atv dk"); + tda18271_update_std(atv_gh, "atv gh"); + tda18271_update_std(atv_i, "atv i"); + tda18271_update_std(atv_l, "atv l"); + tda18271_update_std(atv_lc, "atv l'"); + tda18271_update_std(atv_mn, "atv mn"); + tda18271_update_std(atsc_6, "atsc 6"); + tda18271_update_std(dvbt_6, "dvbt 6"); + tda18271_update_std(dvbt_7, "dvbt 7"); + tda18271_update_std(dvbt_8, "dvbt 8"); + tda18271_update_std(qam_6, "qam 6"); + tda18271_update_std(qam_8, "qam 8"); + + return 0; +} + +static int tda18271_get_id(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + char *name; + + mutex_lock(&priv->lock); + tda18271_read_regs(fe); + mutex_unlock(&priv->lock); + + switch (regs[R_ID] & 0x7f) { + case 3: + name = "TDA18271HD/C1"; + priv->id = TDA18271HDC1; + break; + case 4: + name = "TDA18271HD/C2"; + priv->id = TDA18271HDC2; + break; + default: + tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n", + regs[R_ID], i2c_adapter_id(priv->i2c_props.adap), + priv->i2c_props.addr); + return -EINVAL; + } + + tda_info("%s detected @ %d-%04x\n", name, + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); + + return 0; +} + +static int tda18271_setup_configuration(struct dvb_frontend *fe, + struct tda18271_config *cfg) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; + priv->role = (cfg) ? cfg->role : TDA18271_MASTER; + priv->config = (cfg) ? cfg->config : 0; + priv->small_i2c = (cfg) ? + cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT; + priv->output_opt = (cfg) ? + cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON; + + return 0; +} + +static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg) +{ + /* tda18271_cal_on_startup == -1 when cal module option is unset */ + return ((tda18271_cal_on_startup == -1) ? + /* honor configuration setting */ + ((cfg) && (cfg->rf_cal_on_startup)) : + /* module option overrides configuration setting */ + (tda18271_cal_on_startup)) ? 1 : 0; +} + +static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg; + + tda18271_setup_configuration(fe, cfg); + + if (tda18271_need_cal_on_startup(cfg)) + tda18271_init(fe); + + /* override default std map with values in config struct */ + if ((cfg) && (cfg->std_map)) + tda18271_update_std_map(fe, cfg->std_map); + + return 0; +} + +static struct dvb_tuner_ops tda18271_tuner_ops = { + .info = { + .name = "NXP TDA18271HD", + .frequency_min = 45000000, + .frequency_max = 864000000, + .frequency_step = 62500 + }, + .init = tda18271_init, + .sleep = tda18271_sleep, + .set_params = tda18271_set_params, + .set_analog_params = tda18271_set_analog_params, + .release = tda18271_release, + .set_config = tda18271_set_config, + .get_frequency = tda18271_get_frequency, + .get_bandwidth = tda18271_get_bandwidth, +}; + +struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c, + struct tda18271_config *cfg) +{ + struct tda18271_priv *priv = NULL; + int instance, ret; + + mutex_lock(&tda18271_list_mutex); + + instance = hybrid_tuner_request_state(struct tda18271_priv, priv, + hybrid_tuner_instance_list, + i2c, addr, "tda18271"); + switch (instance) { + case 0: + goto fail; + case 1: + /* new tuner instance */ + fe->tuner_priv = priv; + + tda18271_setup_configuration(fe, cfg); + + priv->cal_initialized = false; + mutex_init(&priv->lock); + + ret = tda18271_get_id(fe); + if (tda_fail(ret)) + goto fail; + + ret = tda18271_assign_map_layout(fe); + if (tda_fail(ret)) + goto fail; + + mutex_lock(&priv->lock); + tda18271_init_regs(fe); + + if ((tda18271_need_cal_on_startup(cfg)) && + (priv->id == TDA18271HDC2)) + tda18271c2_rf_cal_init(fe); + + mutex_unlock(&priv->lock); + break; + default: + /* existing tuner instance */ + fe->tuner_priv = priv; + + /* allow dvb driver to override configuration settings */ + if (cfg) { + if (cfg->gate != TDA18271_GATE_ANALOG) + priv->gate = cfg->gate; + if (cfg->role) + priv->role = cfg->role; + if (cfg->config) + priv->config = cfg->config; + if (cfg->small_i2c) + priv->small_i2c = cfg->small_i2c; + if (cfg->output_opt) + priv->output_opt = cfg->output_opt; + if (cfg->std_map) + tda18271_update_std_map(fe, cfg->std_map); + } + if (tda18271_need_cal_on_startup(cfg)) + tda18271_init(fe); + break; + } + + /* override default std map with values in config struct */ + if ((cfg) && (cfg->std_map)) + tda18271_update_std_map(fe, cfg->std_map); + + mutex_unlock(&tda18271_list_mutex); + + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (tda18271_debug & (DBG_MAP | DBG_ADV)) + tda18271_dump_std_map(fe); + + return fe; +fail: + mutex_unlock(&tda18271_list_mutex); + + tda18271_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(tda18271_attach); +MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,133 @@ +/* + tda18271.h - header for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA18271_H__ +#define __TDA18271_H__ + +#include +#include "dvb_frontend.h" + +struct tda18271_std_map_item { + u16 if_freq; + + /* EP3[4:3] */ + unsigned int agc_mode:2; + /* EP3[2:0] */ + unsigned int std:3; + /* EP4[7] */ + unsigned int fm_rfn:1; + /* EP4[4:2] */ + unsigned int if_lvl:3; + /* EB22[6:0] */ + unsigned int rfagc_top:7; +}; + +struct tda18271_std_map { + struct tda18271_std_map_item fm_radio; + struct tda18271_std_map_item atv_b; + struct tda18271_std_map_item atv_dk; + struct tda18271_std_map_item atv_gh; + struct tda18271_std_map_item atv_i; + struct tda18271_std_map_item atv_l; + struct tda18271_std_map_item atv_lc; + struct tda18271_std_map_item atv_mn; + struct tda18271_std_map_item atsc_6; + struct tda18271_std_map_item dvbt_6; + struct tda18271_std_map_item dvbt_7; + struct tda18271_std_map_item dvbt_8; + struct tda18271_std_map_item qam_6; + struct tda18271_std_map_item qam_8; +}; + +enum tda18271_role { + TDA18271_MASTER = 0, + TDA18271_SLAVE, +}; + +enum tda18271_i2c_gate { + TDA18271_GATE_AUTO = 0, + TDA18271_GATE_ANALOG, + TDA18271_GATE_DIGITAL, +}; + +enum tda18271_output_options { + /* slave tuner output & loop thru & xtal oscillator always on */ + TDA18271_OUTPUT_LT_XT_ON = 0, + + /* slave tuner output loop thru off */ + TDA18271_OUTPUT_LT_OFF = 1, + + /* xtal oscillator off */ + TDA18271_OUTPUT_XT_OFF = 2, +}; + +enum tda18271_small_i2c { + TDA18271_39_BYTE_CHUNK_INIT = 0, + TDA18271_16_BYTE_CHUNK_INIT = 16, + TDA18271_08_BYTE_CHUNK_INIT = 8, + TDA18271_03_BYTE_CHUNK_INIT = 3, +}; + +struct tda18271_config { + /* override default if freq / std settings (optional) */ + struct tda18271_std_map *std_map; + + /* master / slave tuner: master uses main pll, slave uses cal pll */ + enum tda18271_role role; + + /* use i2c gate provided by analog or digital demod */ + enum tda18271_i2c_gate gate; + + /* output options that can be disabled */ + enum tda18271_output_options output_opt; + + /* some i2c providers can't write all 39 registers at once */ + enum tda18271_small_i2c small_i2c; + + /* force rf tracking filter calibration on startup */ + unsigned int rf_cal_on_startup:1; + + /* interface to saa713x / tda829x */ + unsigned int config; +}; + +#define TDA18271_CALLBACK_CMD_AGC_ENABLE 0 + +enum tda18271_mode { + TDA18271_ANALOG = 0, + TDA18271_DIGITAL, +}; + +#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c, + struct tda18271_config *cfg); +#else +static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, + u8 addr, + struct i2c_adapter *i2c, + struct tda18271_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TDA18271_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-maps.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-maps.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-maps.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-maps.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1313 @@ +/* + tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "tda18271-priv.h" + +struct tda18271_pll_map { + u32 lomax; + u8 pd; /* post div */ + u8 d; /* div */ +}; + +struct tda18271_map { + u32 rfmax; + u8 val; +}; + +/*---------------------------------------------------------------------*/ + +static struct tda18271_pll_map tda18271c1_main_pll[] = { + { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, + { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, + { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, + { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, + { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, + { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, + { .lomax = 54000, .pd = 0x59, .d = 0x90 }, + { .lomax = 61000, .pd = 0x58, .d = 0x80 }, + { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, + { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, + { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, + { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, + { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, + { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, + { .lomax = 109000, .pd = 0x49, .d = 0x48 }, + { .lomax = 123000, .pd = 0x48, .d = 0x40 }, + { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, + { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, + { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, + { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, + { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, + { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, + { .lomax = 219000, .pd = 0x39, .d = 0x24 }, + { .lomax = 246000, .pd = 0x38, .d = 0x20 }, + { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, + { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, + { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, + { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, + { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, + { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, + { .lomax = 438000, .pd = 0x29, .d = 0x12 }, + { .lomax = 493000, .pd = 0x28, .d = 0x10 }, + { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, + { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, + { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, + { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, + { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, + { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, + { .lomax = 877000, .pd = 0x19, .d = 0x09 }, + { .lomax = 987000, .pd = 0x18, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c2_main_pll[] = { + { .lomax = 33125, .pd = 0x57, .d = 0xf0 }, + { .lomax = 35500, .pd = 0x56, .d = 0xe0 }, + { .lomax = 38188, .pd = 0x55, .d = 0xd0 }, + { .lomax = 41375, .pd = 0x54, .d = 0xc0 }, + { .lomax = 45125, .pd = 0x53, .d = 0xb0 }, + { .lomax = 49688, .pd = 0x52, .d = 0xa0 }, + { .lomax = 55188, .pd = 0x51, .d = 0x90 }, + { .lomax = 62125, .pd = 0x50, .d = 0x80 }, + { .lomax = 66250, .pd = 0x47, .d = 0x78 }, + { .lomax = 71000, .pd = 0x46, .d = 0x70 }, + { .lomax = 76375, .pd = 0x45, .d = 0x68 }, + { .lomax = 82750, .pd = 0x44, .d = 0x60 }, + { .lomax = 90250, .pd = 0x43, .d = 0x58 }, + { .lomax = 99375, .pd = 0x42, .d = 0x50 }, + { .lomax = 110375, .pd = 0x41, .d = 0x48 }, + { .lomax = 124250, .pd = 0x40, .d = 0x40 }, + { .lomax = 132500, .pd = 0x37, .d = 0x3c }, + { .lomax = 142000, .pd = 0x36, .d = 0x38 }, + { .lomax = 152750, .pd = 0x35, .d = 0x34 }, + { .lomax = 165500, .pd = 0x34, .d = 0x30 }, + { .lomax = 180500, .pd = 0x33, .d = 0x2c }, + { .lomax = 198750, .pd = 0x32, .d = 0x28 }, + { .lomax = 220750, .pd = 0x31, .d = 0x24 }, + { .lomax = 248500, .pd = 0x30, .d = 0x20 }, + { .lomax = 265000, .pd = 0x27, .d = 0x1e }, + { .lomax = 284000, .pd = 0x26, .d = 0x1c }, + { .lomax = 305500, .pd = 0x25, .d = 0x1a }, + { .lomax = 331000, .pd = 0x24, .d = 0x18 }, + { .lomax = 361000, .pd = 0x23, .d = 0x16 }, + { .lomax = 397500, .pd = 0x22, .d = 0x14 }, + { .lomax = 441500, .pd = 0x21, .d = 0x12 }, + { .lomax = 497000, .pd = 0x20, .d = 0x10 }, + { .lomax = 530000, .pd = 0x17, .d = 0x0f }, + { .lomax = 568000, .pd = 0x16, .d = 0x0e }, + { .lomax = 611000, .pd = 0x15, .d = 0x0d }, + { .lomax = 662000, .pd = 0x14, .d = 0x0c }, + { .lomax = 722000, .pd = 0x13, .d = 0x0b }, + { .lomax = 795000, .pd = 0x12, .d = 0x0a }, + { .lomax = 883000, .pd = 0x11, .d = 0x09 }, + { .lomax = 994000, .pd = 0x10, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c1_cal_pll[] = { + { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, + { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, + { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, + { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, + { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, + { .lomax = 88000, .pd = 0xca, .d = 0x50 }, + { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, + { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, + { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, + { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, + { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, + { .lomax = 176000, .pd = 0xba, .d = 0x28 }, + { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, + { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, + { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, + { .lomax = 271000, .pd = 0xad, .d = 0x1a }, + { .lomax = 294000, .pd = 0xac, .d = 0x18 }, + { .lomax = 321000, .pd = 0xab, .d = 0x16 }, + { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, + { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, + { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, + { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, + { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 785000, .pd = 0x99, .d = 0x09 }, + { .lomax = 883000, .pd = 0x98, .d = 0x08 }, + { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c2_cal_pll[] = { + { .lomax = 33813, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36625, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 39938, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 43938, .pd = 0xda, .d = 0xa0 }, + { .lomax = 48813, .pd = 0xd9, .d = 0x90 }, + { .lomax = 54938, .pd = 0xd8, .d = 0x80 }, + { .lomax = 62813, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67625, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73250, .pd = 0xcc, .d = 0x60 }, + { .lomax = 79875, .pd = 0xcb, .d = 0x58 }, + { .lomax = 87875, .pd = 0xca, .d = 0x50 }, + { .lomax = 97625, .pd = 0xc9, .d = 0x48 }, + { .lomax = 109875, .pd = 0xc8, .d = 0x40 }, + { .lomax = 125625, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135250, .pd = 0xbd, .d = 0x34 }, + { .lomax = 146500, .pd = 0xbc, .d = 0x30 }, + { .lomax = 159750, .pd = 0xbb, .d = 0x2c }, + { .lomax = 175750, .pd = 0xba, .d = 0x28 }, + { .lomax = 195250, .pd = 0xb9, .d = 0x24 }, + { .lomax = 219750, .pd = 0xb8, .d = 0x20 }, + { .lomax = 251250, .pd = 0xb3, .d = 0x1c }, + { .lomax = 270500, .pd = 0xad, .d = 0x1a }, + { .lomax = 293000, .pd = 0xac, .d = 0x18 }, + { .lomax = 319500, .pd = 0xab, .d = 0x16 }, + { .lomax = 351500, .pd = 0xaa, .d = 0x14 }, + { .lomax = 390500, .pd = 0xa9, .d = 0x12 }, + { .lomax = 439500, .pd = 0xa8, .d = 0x10 }, + { .lomax = 502500, .pd = 0xa3, .d = 0x0e }, + { .lomax = 541000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 586000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 639000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 703000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 781000, .pd = 0x99, .d = 0x09 }, + { .lomax = 879000, .pd = 0x98, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_bp_filter[] = { + { .rfmax = 62000, .val = 0x00 }, + { .rfmax = 84000, .val = 0x01 }, + { .rfmax = 100000, .val = 0x02 }, + { .rfmax = 140000, .val = 0x03 }, + { .rfmax = 170000, .val = 0x04 }, + { .rfmax = 180000, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c1_km[] = { + { .rfmax = 61100, .val = 0x74 }, + { .rfmax = 350000, .val = 0x40 }, + { .rfmax = 720000, .val = 0x30 }, + { .rfmax = 865000, .val = 0x40 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c2_km[] = { + { .rfmax = 47900, .val = 0x38 }, + { .rfmax = 61100, .val = 0x44 }, + { .rfmax = 350000, .val = 0x30 }, + { .rfmax = 720000, .val = 0x24 }, + { .rfmax = 865000, .val = 0x3c }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_band[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 61100, .val = 0x01 }, + { .rfmax = 152600, .val = 0x02 }, + { .rfmax = 164700, .val = 0x03 }, + { .rfmax = 203500, .val = 0x04 }, + { .rfmax = 457800, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_gain_taper[] = { + { .rfmax = 45400, .val = 0x1f }, + { .rfmax = 45800, .val = 0x1e }, + { .rfmax = 46200, .val = 0x1d }, + { .rfmax = 46700, .val = 0x1c }, + { .rfmax = 47100, .val = 0x1b }, + { .rfmax = 47500, .val = 0x1a }, + { .rfmax = 47900, .val = 0x19 }, + { .rfmax = 49600, .val = 0x17 }, + { .rfmax = 51200, .val = 0x16 }, + { .rfmax = 52900, .val = 0x15 }, + { .rfmax = 54500, .val = 0x14 }, + { .rfmax = 56200, .val = 0x13 }, + { .rfmax = 57800, .val = 0x12 }, + { .rfmax = 59500, .val = 0x11 }, + { .rfmax = 61100, .val = 0x10 }, + { .rfmax = 67600, .val = 0x0d }, + { .rfmax = 74200, .val = 0x0c }, + { .rfmax = 80700, .val = 0x0b }, + { .rfmax = 87200, .val = 0x0a }, + { .rfmax = 93800, .val = 0x09 }, + { .rfmax = 100300, .val = 0x08 }, + { .rfmax = 106900, .val = 0x07 }, + { .rfmax = 113400, .val = 0x06 }, + { .rfmax = 119900, .val = 0x05 }, + { .rfmax = 126500, .val = 0x04 }, + { .rfmax = 133000, .val = 0x03 }, + { .rfmax = 139500, .val = 0x02 }, + { .rfmax = 146100, .val = 0x01 }, + { .rfmax = 152600, .val = 0x00 }, + { .rfmax = 154300, .val = 0x1f }, + { .rfmax = 156100, .val = 0x1e }, + { .rfmax = 157800, .val = 0x1d }, + { .rfmax = 159500, .val = 0x1c }, + { .rfmax = 161200, .val = 0x1b }, + { .rfmax = 163000, .val = 0x1a }, + { .rfmax = 164700, .val = 0x19 }, + { .rfmax = 170200, .val = 0x17 }, + { .rfmax = 175800, .val = 0x16 }, + { .rfmax = 181300, .val = 0x15 }, + { .rfmax = 186900, .val = 0x14 }, + { .rfmax = 192400, .val = 0x13 }, + { .rfmax = 198000, .val = 0x12 }, + { .rfmax = 203500, .val = 0x11 }, + { .rfmax = 216200, .val = 0x14 }, + { .rfmax = 228900, .val = 0x13 }, + { .rfmax = 241600, .val = 0x12 }, + { .rfmax = 254400, .val = 0x11 }, + { .rfmax = 267100, .val = 0x10 }, + { .rfmax = 279800, .val = 0x0f }, + { .rfmax = 292500, .val = 0x0e }, + { .rfmax = 305200, .val = 0x0d }, + { .rfmax = 317900, .val = 0x0c }, + { .rfmax = 330700, .val = 0x0b }, + { .rfmax = 343400, .val = 0x0a }, + { .rfmax = 356100, .val = 0x09 }, + { .rfmax = 368800, .val = 0x08 }, + { .rfmax = 381500, .val = 0x07 }, + { .rfmax = 394200, .val = 0x06 }, + { .rfmax = 406900, .val = 0x05 }, + { .rfmax = 419700, .val = 0x04 }, + { .rfmax = 432400, .val = 0x03 }, + { .rfmax = 445100, .val = 0x02 }, + { .rfmax = 457800, .val = 0x01 }, + { .rfmax = 476300, .val = 0x19 }, + { .rfmax = 494800, .val = 0x18 }, + { .rfmax = 513300, .val = 0x17 }, + { .rfmax = 531800, .val = 0x16 }, + { .rfmax = 550300, .val = 0x15 }, + { .rfmax = 568900, .val = 0x14 }, + { .rfmax = 587400, .val = 0x13 }, + { .rfmax = 605900, .val = 0x12 }, + { .rfmax = 624400, .val = 0x11 }, + { .rfmax = 642900, .val = 0x10 }, + { .rfmax = 661400, .val = 0x0f }, + { .rfmax = 679900, .val = 0x0e }, + { .rfmax = 698400, .val = 0x0d }, + { .rfmax = 716900, .val = 0x0c }, + { .rfmax = 735400, .val = 0x0b }, + { .rfmax = 753900, .val = 0x0a }, + { .rfmax = 772500, .val = 0x09 }, + { .rfmax = 791000, .val = 0x08 }, + { .rfmax = 809500, .val = 0x07 }, + { .rfmax = 828000, .val = 0x06 }, + { .rfmax = 846500, .val = 0x05 }, + { .rfmax = 865000, .val = 0x04 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c1_rf_cal[] = { + { .rfmax = 41000, .val = 0x1e }, + { .rfmax = 43000, .val = 0x30 }, + { .rfmax = 45000, .val = 0x43 }, + { .rfmax = 46000, .val = 0x4d }, + { .rfmax = 47000, .val = 0x54 }, + { .rfmax = 47900, .val = 0x64 }, + { .rfmax = 49100, .val = 0x20 }, + { .rfmax = 50000, .val = 0x22 }, + { .rfmax = 51000, .val = 0x2a }, + { .rfmax = 53000, .val = 0x32 }, + { .rfmax = 55000, .val = 0x35 }, + { .rfmax = 56000, .val = 0x3c }, + { .rfmax = 57000, .val = 0x3f }, + { .rfmax = 58000, .val = 0x48 }, + { .rfmax = 59000, .val = 0x4d }, + { .rfmax = 60000, .val = 0x58 }, + { .rfmax = 61100, .val = 0x5f }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c2_rf_cal[] = { + { .rfmax = 41000, .val = 0x0f }, + { .rfmax = 43000, .val = 0x1c }, + { .rfmax = 45000, .val = 0x2f }, + { .rfmax = 46000, .val = 0x39 }, + { .rfmax = 47000, .val = 0x40 }, + { .rfmax = 47900, .val = 0x50 }, + { .rfmax = 49100, .val = 0x16 }, + { .rfmax = 50000, .val = 0x18 }, + { .rfmax = 51000, .val = 0x20 }, + { .rfmax = 53000, .val = 0x28 }, + { .rfmax = 55000, .val = 0x2b }, + { .rfmax = 56000, .val = 0x32 }, + { .rfmax = 57000, .val = 0x35 }, + { .rfmax = 58000, .val = 0x3e }, + { .rfmax = 59000, .val = 0x43 }, + { .rfmax = 60000, .val = 0x4e }, + { .rfmax = 61100, .val = 0x55 }, + { .rfmax = 63000, .val = 0x0f }, + { .rfmax = 64000, .val = 0x11 }, + { .rfmax = 65000, .val = 0x12 }, + { .rfmax = 66000, .val = 0x15 }, + { .rfmax = 67000, .val = 0x16 }, + { .rfmax = 68000, .val = 0x17 }, + { .rfmax = 70000, .val = 0x19 }, + { .rfmax = 71000, .val = 0x1c }, + { .rfmax = 72000, .val = 0x1d }, + { .rfmax = 73000, .val = 0x1f }, + { .rfmax = 74000, .val = 0x20 }, + { .rfmax = 75000, .val = 0x21 }, + { .rfmax = 76000, .val = 0x24 }, + { .rfmax = 77000, .val = 0x25 }, + { .rfmax = 78000, .val = 0x27 }, + { .rfmax = 80000, .val = 0x28 }, + { .rfmax = 81000, .val = 0x29 }, + { .rfmax = 82000, .val = 0x2d }, + { .rfmax = 83000, .val = 0x2e }, + { .rfmax = 84000, .val = 0x2f }, + { .rfmax = 85000, .val = 0x31 }, + { .rfmax = 86000, .val = 0x33 }, + { .rfmax = 87000, .val = 0x34 }, + { .rfmax = 88000, .val = 0x35 }, + { .rfmax = 89000, .val = 0x37 }, + { .rfmax = 90000, .val = 0x38 }, + { .rfmax = 91000, .val = 0x39 }, + { .rfmax = 93000, .val = 0x3c }, + { .rfmax = 94000, .val = 0x3e }, + { .rfmax = 95000, .val = 0x3f }, + { .rfmax = 96000, .val = 0x40 }, + { .rfmax = 97000, .val = 0x42 }, + { .rfmax = 99000, .val = 0x45 }, + { .rfmax = 100000, .val = 0x46 }, + { .rfmax = 102000, .val = 0x48 }, + { .rfmax = 103000, .val = 0x4a }, + { .rfmax = 105000, .val = 0x4d }, + { .rfmax = 106000, .val = 0x4e }, + { .rfmax = 107000, .val = 0x50 }, + { .rfmax = 108000, .val = 0x51 }, + { .rfmax = 110000, .val = 0x54 }, + { .rfmax = 111000, .val = 0x56 }, + { .rfmax = 112000, .val = 0x57 }, + { .rfmax = 113000, .val = 0x58 }, + { .rfmax = 114000, .val = 0x59 }, + { .rfmax = 115000, .val = 0x5c }, + { .rfmax = 116000, .val = 0x5d }, + { .rfmax = 117000, .val = 0x5f }, + { .rfmax = 119000, .val = 0x60 }, + { .rfmax = 120000, .val = 0x64 }, + { .rfmax = 121000, .val = 0x65 }, + { .rfmax = 122000, .val = 0x66 }, + { .rfmax = 123000, .val = 0x68 }, + { .rfmax = 124000, .val = 0x69 }, + { .rfmax = 125000, .val = 0x6c }, + { .rfmax = 126000, .val = 0x6d }, + { .rfmax = 127000, .val = 0x6e }, + { .rfmax = 128000, .val = 0x70 }, + { .rfmax = 129000, .val = 0x71 }, + { .rfmax = 130000, .val = 0x75 }, + { .rfmax = 131000, .val = 0x77 }, + { .rfmax = 132000, .val = 0x78 }, + { .rfmax = 133000, .val = 0x7b }, + { .rfmax = 134000, .val = 0x7e }, + { .rfmax = 135000, .val = 0x81 }, + { .rfmax = 136000, .val = 0x82 }, + { .rfmax = 137000, .val = 0x87 }, + { .rfmax = 138000, .val = 0x88 }, + { .rfmax = 139000, .val = 0x8d }, + { .rfmax = 140000, .val = 0x8e }, + { .rfmax = 141000, .val = 0x91 }, + { .rfmax = 142000, .val = 0x95 }, + { .rfmax = 143000, .val = 0x9a }, + { .rfmax = 144000, .val = 0x9d }, + { .rfmax = 145000, .val = 0xa1 }, + { .rfmax = 146000, .val = 0xa2 }, + { .rfmax = 147000, .val = 0xa4 }, + { .rfmax = 148000, .val = 0xa9 }, + { .rfmax = 149000, .val = 0xae }, + { .rfmax = 150000, .val = 0xb0 }, + { .rfmax = 151000, .val = 0xb1 }, + { .rfmax = 152000, .val = 0xb7 }, + { .rfmax = 152600, .val = 0xbd }, + { .rfmax = 154000, .val = 0x20 }, + { .rfmax = 155000, .val = 0x22 }, + { .rfmax = 156000, .val = 0x24 }, + { .rfmax = 157000, .val = 0x25 }, + { .rfmax = 158000, .val = 0x27 }, + { .rfmax = 159000, .val = 0x29 }, + { .rfmax = 160000, .val = 0x2c }, + { .rfmax = 161000, .val = 0x2d }, + { .rfmax = 163000, .val = 0x2e }, + { .rfmax = 164000, .val = 0x2f }, + { .rfmax = 164700, .val = 0x30 }, + { .rfmax = 166000, .val = 0x11 }, + { .rfmax = 167000, .val = 0x12 }, + { .rfmax = 168000, .val = 0x13 }, + { .rfmax = 169000, .val = 0x14 }, + { .rfmax = 170000, .val = 0x15 }, + { .rfmax = 172000, .val = 0x16 }, + { .rfmax = 173000, .val = 0x17 }, + { .rfmax = 174000, .val = 0x18 }, + { .rfmax = 175000, .val = 0x1a }, + { .rfmax = 176000, .val = 0x1b }, + { .rfmax = 178000, .val = 0x1d }, + { .rfmax = 179000, .val = 0x1e }, + { .rfmax = 180000, .val = 0x1f }, + { .rfmax = 181000, .val = 0x20 }, + { .rfmax = 182000, .val = 0x21 }, + { .rfmax = 183000, .val = 0x22 }, + { .rfmax = 184000, .val = 0x24 }, + { .rfmax = 185000, .val = 0x25 }, + { .rfmax = 186000, .val = 0x26 }, + { .rfmax = 187000, .val = 0x27 }, + { .rfmax = 188000, .val = 0x29 }, + { .rfmax = 189000, .val = 0x2a }, + { .rfmax = 190000, .val = 0x2c }, + { .rfmax = 191000, .val = 0x2d }, + { .rfmax = 192000, .val = 0x2e }, + { .rfmax = 193000, .val = 0x2f }, + { .rfmax = 194000, .val = 0x30 }, + { .rfmax = 195000, .val = 0x33 }, + { .rfmax = 196000, .val = 0x35 }, + { .rfmax = 198000, .val = 0x36 }, + { .rfmax = 200000, .val = 0x38 }, + { .rfmax = 201000, .val = 0x3c }, + { .rfmax = 202000, .val = 0x3d }, + { .rfmax = 203500, .val = 0x3e }, + { .rfmax = 206000, .val = 0x0e }, + { .rfmax = 208000, .val = 0x0f }, + { .rfmax = 212000, .val = 0x10 }, + { .rfmax = 216000, .val = 0x11 }, + { .rfmax = 217000, .val = 0x12 }, + { .rfmax = 218000, .val = 0x13 }, + { .rfmax = 220000, .val = 0x14 }, + { .rfmax = 222000, .val = 0x15 }, + { .rfmax = 225000, .val = 0x16 }, + { .rfmax = 228000, .val = 0x17 }, + { .rfmax = 231000, .val = 0x18 }, + { .rfmax = 234000, .val = 0x19 }, + { .rfmax = 235000, .val = 0x1a }, + { .rfmax = 236000, .val = 0x1b }, + { .rfmax = 237000, .val = 0x1c }, + { .rfmax = 240000, .val = 0x1d }, + { .rfmax = 242000, .val = 0x1e }, + { .rfmax = 244000, .val = 0x1f }, + { .rfmax = 247000, .val = 0x20 }, + { .rfmax = 249000, .val = 0x21 }, + { .rfmax = 252000, .val = 0x22 }, + { .rfmax = 253000, .val = 0x23 }, + { .rfmax = 254000, .val = 0x24 }, + { .rfmax = 256000, .val = 0x25 }, + { .rfmax = 259000, .val = 0x26 }, + { .rfmax = 262000, .val = 0x27 }, + { .rfmax = 264000, .val = 0x28 }, + { .rfmax = 267000, .val = 0x29 }, + { .rfmax = 269000, .val = 0x2a }, + { .rfmax = 271000, .val = 0x2b }, + { .rfmax = 273000, .val = 0x2c }, + { .rfmax = 275000, .val = 0x2d }, + { .rfmax = 277000, .val = 0x2e }, + { .rfmax = 279000, .val = 0x2f }, + { .rfmax = 282000, .val = 0x30 }, + { .rfmax = 284000, .val = 0x31 }, + { .rfmax = 286000, .val = 0x32 }, + { .rfmax = 287000, .val = 0x33 }, + { .rfmax = 290000, .val = 0x34 }, + { .rfmax = 293000, .val = 0x35 }, + { .rfmax = 295000, .val = 0x36 }, + { .rfmax = 297000, .val = 0x37 }, + { .rfmax = 300000, .val = 0x38 }, + { .rfmax = 303000, .val = 0x39 }, + { .rfmax = 305000, .val = 0x3a }, + { .rfmax = 306000, .val = 0x3b }, + { .rfmax = 307000, .val = 0x3c }, + { .rfmax = 310000, .val = 0x3d }, + { .rfmax = 312000, .val = 0x3e }, + { .rfmax = 315000, .val = 0x3f }, + { .rfmax = 318000, .val = 0x40 }, + { .rfmax = 320000, .val = 0x41 }, + { .rfmax = 323000, .val = 0x42 }, + { .rfmax = 324000, .val = 0x43 }, + { .rfmax = 325000, .val = 0x44 }, + { .rfmax = 327000, .val = 0x45 }, + { .rfmax = 331000, .val = 0x46 }, + { .rfmax = 334000, .val = 0x47 }, + { .rfmax = 337000, .val = 0x48 }, + { .rfmax = 339000, .val = 0x49 }, + { .rfmax = 340000, .val = 0x4a }, + { .rfmax = 341000, .val = 0x4b }, + { .rfmax = 343000, .val = 0x4c }, + { .rfmax = 345000, .val = 0x4d }, + { .rfmax = 349000, .val = 0x4e }, + { .rfmax = 352000, .val = 0x4f }, + { .rfmax = 353000, .val = 0x50 }, + { .rfmax = 355000, .val = 0x51 }, + { .rfmax = 357000, .val = 0x52 }, + { .rfmax = 359000, .val = 0x53 }, + { .rfmax = 361000, .val = 0x54 }, + { .rfmax = 362000, .val = 0x55 }, + { .rfmax = 364000, .val = 0x56 }, + { .rfmax = 368000, .val = 0x57 }, + { .rfmax = 370000, .val = 0x58 }, + { .rfmax = 372000, .val = 0x59 }, + { .rfmax = 375000, .val = 0x5a }, + { .rfmax = 376000, .val = 0x5b }, + { .rfmax = 377000, .val = 0x5c }, + { .rfmax = 379000, .val = 0x5d }, + { .rfmax = 382000, .val = 0x5e }, + { .rfmax = 384000, .val = 0x5f }, + { .rfmax = 385000, .val = 0x60 }, + { .rfmax = 386000, .val = 0x61 }, + { .rfmax = 388000, .val = 0x62 }, + { .rfmax = 390000, .val = 0x63 }, + { .rfmax = 393000, .val = 0x64 }, + { .rfmax = 394000, .val = 0x65 }, + { .rfmax = 396000, .val = 0x66 }, + { .rfmax = 397000, .val = 0x67 }, + { .rfmax = 398000, .val = 0x68 }, + { .rfmax = 400000, .val = 0x69 }, + { .rfmax = 402000, .val = 0x6a }, + { .rfmax = 403000, .val = 0x6b }, + { .rfmax = 407000, .val = 0x6c }, + { .rfmax = 408000, .val = 0x6d }, + { .rfmax = 409000, .val = 0x6e }, + { .rfmax = 410000, .val = 0x6f }, + { .rfmax = 411000, .val = 0x70 }, + { .rfmax = 412000, .val = 0x71 }, + { .rfmax = 413000, .val = 0x72 }, + { .rfmax = 414000, .val = 0x73 }, + { .rfmax = 417000, .val = 0x74 }, + { .rfmax = 418000, .val = 0x75 }, + { .rfmax = 420000, .val = 0x76 }, + { .rfmax = 422000, .val = 0x77 }, + { .rfmax = 423000, .val = 0x78 }, + { .rfmax = 424000, .val = 0x79 }, + { .rfmax = 427000, .val = 0x7a }, + { .rfmax = 428000, .val = 0x7b }, + { .rfmax = 429000, .val = 0x7d }, + { .rfmax = 432000, .val = 0x7f }, + { .rfmax = 434000, .val = 0x80 }, + { .rfmax = 435000, .val = 0x81 }, + { .rfmax = 436000, .val = 0x83 }, + { .rfmax = 437000, .val = 0x84 }, + { .rfmax = 438000, .val = 0x85 }, + { .rfmax = 439000, .val = 0x86 }, + { .rfmax = 440000, .val = 0x87 }, + { .rfmax = 441000, .val = 0x88 }, + { .rfmax = 442000, .val = 0x89 }, + { .rfmax = 445000, .val = 0x8a }, + { .rfmax = 446000, .val = 0x8b }, + { .rfmax = 447000, .val = 0x8c }, + { .rfmax = 448000, .val = 0x8e }, + { .rfmax = 449000, .val = 0x8f }, + { .rfmax = 450000, .val = 0x90 }, + { .rfmax = 452000, .val = 0x91 }, + { .rfmax = 453000, .val = 0x93 }, + { .rfmax = 454000, .val = 0x94 }, + { .rfmax = 456000, .val = 0x96 }, + { .rfmax = 457800, .val = 0x98 }, + { .rfmax = 461000, .val = 0x11 }, + { .rfmax = 468000, .val = 0x12 }, + { .rfmax = 472000, .val = 0x13 }, + { .rfmax = 473000, .val = 0x14 }, + { .rfmax = 474000, .val = 0x15 }, + { .rfmax = 481000, .val = 0x16 }, + { .rfmax = 486000, .val = 0x17 }, + { .rfmax = 491000, .val = 0x18 }, + { .rfmax = 498000, .val = 0x19 }, + { .rfmax = 499000, .val = 0x1a }, + { .rfmax = 501000, .val = 0x1b }, + { .rfmax = 506000, .val = 0x1c }, + { .rfmax = 511000, .val = 0x1d }, + { .rfmax = 516000, .val = 0x1e }, + { .rfmax = 520000, .val = 0x1f }, + { .rfmax = 521000, .val = 0x20 }, + { .rfmax = 525000, .val = 0x21 }, + { .rfmax = 529000, .val = 0x22 }, + { .rfmax = 533000, .val = 0x23 }, + { .rfmax = 539000, .val = 0x24 }, + { .rfmax = 541000, .val = 0x25 }, + { .rfmax = 547000, .val = 0x26 }, + { .rfmax = 549000, .val = 0x27 }, + { .rfmax = 551000, .val = 0x28 }, + { .rfmax = 556000, .val = 0x29 }, + { .rfmax = 561000, .val = 0x2a }, + { .rfmax = 563000, .val = 0x2b }, + { .rfmax = 565000, .val = 0x2c }, + { .rfmax = 569000, .val = 0x2d }, + { .rfmax = 571000, .val = 0x2e }, + { .rfmax = 577000, .val = 0x2f }, + { .rfmax = 580000, .val = 0x30 }, + { .rfmax = 582000, .val = 0x31 }, + { .rfmax = 584000, .val = 0x32 }, + { .rfmax = 588000, .val = 0x33 }, + { .rfmax = 591000, .val = 0x34 }, + { .rfmax = 596000, .val = 0x35 }, + { .rfmax = 598000, .val = 0x36 }, + { .rfmax = 603000, .val = 0x37 }, + { .rfmax = 604000, .val = 0x38 }, + { .rfmax = 606000, .val = 0x39 }, + { .rfmax = 612000, .val = 0x3a }, + { .rfmax = 615000, .val = 0x3b }, + { .rfmax = 617000, .val = 0x3c }, + { .rfmax = 621000, .val = 0x3d }, + { .rfmax = 622000, .val = 0x3e }, + { .rfmax = 625000, .val = 0x3f }, + { .rfmax = 632000, .val = 0x40 }, + { .rfmax = 633000, .val = 0x41 }, + { .rfmax = 634000, .val = 0x42 }, + { .rfmax = 642000, .val = 0x43 }, + { .rfmax = 643000, .val = 0x44 }, + { .rfmax = 647000, .val = 0x45 }, + { .rfmax = 650000, .val = 0x46 }, + { .rfmax = 652000, .val = 0x47 }, + { .rfmax = 657000, .val = 0x48 }, + { .rfmax = 661000, .val = 0x49 }, + { .rfmax = 662000, .val = 0x4a }, + { .rfmax = 665000, .val = 0x4b }, + { .rfmax = 667000, .val = 0x4c }, + { .rfmax = 670000, .val = 0x4d }, + { .rfmax = 673000, .val = 0x4e }, + { .rfmax = 676000, .val = 0x4f }, + { .rfmax = 677000, .val = 0x50 }, + { .rfmax = 681000, .val = 0x51 }, + { .rfmax = 683000, .val = 0x52 }, + { .rfmax = 686000, .val = 0x53 }, + { .rfmax = 688000, .val = 0x54 }, + { .rfmax = 689000, .val = 0x55 }, + { .rfmax = 691000, .val = 0x56 }, + { .rfmax = 695000, .val = 0x57 }, + { .rfmax = 698000, .val = 0x58 }, + { .rfmax = 703000, .val = 0x59 }, + { .rfmax = 704000, .val = 0x5a }, + { .rfmax = 705000, .val = 0x5b }, + { .rfmax = 707000, .val = 0x5c }, + { .rfmax = 710000, .val = 0x5d }, + { .rfmax = 712000, .val = 0x5e }, + { .rfmax = 717000, .val = 0x5f }, + { .rfmax = 718000, .val = 0x60 }, + { .rfmax = 721000, .val = 0x61 }, + { .rfmax = 722000, .val = 0x62 }, + { .rfmax = 723000, .val = 0x63 }, + { .rfmax = 725000, .val = 0x64 }, + { .rfmax = 727000, .val = 0x65 }, + { .rfmax = 730000, .val = 0x66 }, + { .rfmax = 732000, .val = 0x67 }, + { .rfmax = 735000, .val = 0x68 }, + { .rfmax = 740000, .val = 0x69 }, + { .rfmax = 741000, .val = 0x6a }, + { .rfmax = 742000, .val = 0x6b }, + { .rfmax = 743000, .val = 0x6c }, + { .rfmax = 745000, .val = 0x6d }, + { .rfmax = 747000, .val = 0x6e }, + { .rfmax = 748000, .val = 0x6f }, + { .rfmax = 750000, .val = 0x70 }, + { .rfmax = 752000, .val = 0x71 }, + { .rfmax = 754000, .val = 0x72 }, + { .rfmax = 757000, .val = 0x73 }, + { .rfmax = 758000, .val = 0x74 }, + { .rfmax = 760000, .val = 0x75 }, + { .rfmax = 763000, .val = 0x76 }, + { .rfmax = 764000, .val = 0x77 }, + { .rfmax = 766000, .val = 0x78 }, + { .rfmax = 767000, .val = 0x79 }, + { .rfmax = 768000, .val = 0x7a }, + { .rfmax = 773000, .val = 0x7b }, + { .rfmax = 774000, .val = 0x7c }, + { .rfmax = 776000, .val = 0x7d }, + { .rfmax = 777000, .val = 0x7e }, + { .rfmax = 778000, .val = 0x7f }, + { .rfmax = 779000, .val = 0x80 }, + { .rfmax = 781000, .val = 0x81 }, + { .rfmax = 783000, .val = 0x82 }, + { .rfmax = 784000, .val = 0x83 }, + { .rfmax = 785000, .val = 0x84 }, + { .rfmax = 786000, .val = 0x85 }, + { .rfmax = 793000, .val = 0x86 }, + { .rfmax = 794000, .val = 0x87 }, + { .rfmax = 795000, .val = 0x88 }, + { .rfmax = 797000, .val = 0x89 }, + { .rfmax = 799000, .val = 0x8a }, + { .rfmax = 801000, .val = 0x8b }, + { .rfmax = 802000, .val = 0x8c }, + { .rfmax = 803000, .val = 0x8d }, + { .rfmax = 804000, .val = 0x8e }, + { .rfmax = 810000, .val = 0x90 }, + { .rfmax = 811000, .val = 0x91 }, + { .rfmax = 812000, .val = 0x92 }, + { .rfmax = 814000, .val = 0x93 }, + { .rfmax = 816000, .val = 0x94 }, + { .rfmax = 817000, .val = 0x96 }, + { .rfmax = 818000, .val = 0x97 }, + { .rfmax = 820000, .val = 0x98 }, + { .rfmax = 821000, .val = 0x99 }, + { .rfmax = 822000, .val = 0x9a }, + { .rfmax = 828000, .val = 0x9b }, + { .rfmax = 829000, .val = 0x9d }, + { .rfmax = 830000, .val = 0x9f }, + { .rfmax = 831000, .val = 0xa0 }, + { .rfmax = 833000, .val = 0xa1 }, + { .rfmax = 835000, .val = 0xa2 }, + { .rfmax = 836000, .val = 0xa3 }, + { .rfmax = 837000, .val = 0xa4 }, + { .rfmax = 838000, .val = 0xa6 }, + { .rfmax = 840000, .val = 0xa8 }, + { .rfmax = 842000, .val = 0xa9 }, + { .rfmax = 845000, .val = 0xaa }, + { .rfmax = 846000, .val = 0xab }, + { .rfmax = 847000, .val = 0xad }, + { .rfmax = 848000, .val = 0xae }, + { .rfmax = 852000, .val = 0xaf }, + { .rfmax = 853000, .val = 0xb0 }, + { .rfmax = 858000, .val = 0xb1 }, + { .rfmax = 860000, .val = 0xb2 }, + { .rfmax = 861000, .val = 0xb3 }, + { .rfmax = 862000, .val = 0xb4 }, + { .rfmax = 863000, .val = 0xb6 }, + { .rfmax = 864000, .val = 0xb8 }, + { .rfmax = 865000, .val = 0xb9 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_ir_measure[] = { + { .rfmax = 30000, .val = 4 }, + { .rfmax = 200000, .val = 5 }, + { .rfmax = 600000, .val = 6 }, + { .rfmax = 865000, .val = 7 }, + { .rfmax = 0, .val = 0 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 55000, .val = 0x00 }, + { .rfmax = 61100, .val = 0x0a }, + { .rfmax = 64000, .val = 0x0a }, + { .rfmax = 82000, .val = 0x14 }, + { .rfmax = 84000, .val = 0x19 }, + { .rfmax = 119000, .val = 0x1c }, + { .rfmax = 124000, .val = 0x20 }, + { .rfmax = 129000, .val = 0x2a }, + { .rfmax = 134000, .val = 0x32 }, + { .rfmax = 139000, .val = 0x39 }, + { .rfmax = 144000, .val = 0x3e }, + { .rfmax = 149000, .val = 0x3f }, + { .rfmax = 152600, .val = 0x40 }, + { .rfmax = 154000, .val = 0x40 }, + { .rfmax = 164700, .val = 0x41 }, + { .rfmax = 203500, .val = 0x32 }, + { .rfmax = 353000, .val = 0x19 }, + { .rfmax = 356000, .val = 0x1a }, + { .rfmax = 359000, .val = 0x1b }, + { .rfmax = 363000, .val = 0x1c }, + { .rfmax = 366000, .val = 0x1d }, + { .rfmax = 369000, .val = 0x1e }, + { .rfmax = 373000, .val = 0x1f }, + { .rfmax = 376000, .val = 0x20 }, + { .rfmax = 379000, .val = 0x21 }, + { .rfmax = 383000, .val = 0x22 }, + { .rfmax = 386000, .val = 0x23 }, + { .rfmax = 389000, .val = 0x24 }, + { .rfmax = 393000, .val = 0x25 }, + { .rfmax = 396000, .val = 0x26 }, + { .rfmax = 399000, .val = 0x27 }, + { .rfmax = 402000, .val = 0x28 }, + { .rfmax = 404000, .val = 0x29 }, + { .rfmax = 407000, .val = 0x2a }, + { .rfmax = 409000, .val = 0x2b }, + { .rfmax = 412000, .val = 0x2c }, + { .rfmax = 414000, .val = 0x2d }, + { .rfmax = 417000, .val = 0x2e }, + { .rfmax = 419000, .val = 0x2f }, + { .rfmax = 422000, .val = 0x30 }, + { .rfmax = 424000, .val = 0x31 }, + { .rfmax = 427000, .val = 0x32 }, + { .rfmax = 429000, .val = 0x33 }, + { .rfmax = 432000, .val = 0x34 }, + { .rfmax = 434000, .val = 0x35 }, + { .rfmax = 437000, .val = 0x36 }, + { .rfmax = 439000, .val = 0x37 }, + { .rfmax = 442000, .val = 0x38 }, + { .rfmax = 444000, .val = 0x39 }, + { .rfmax = 447000, .val = 0x3a }, + { .rfmax = 449000, .val = 0x3b }, + { .rfmax = 457800, .val = 0x3c }, + { .rfmax = 465000, .val = 0x0f }, + { .rfmax = 477000, .val = 0x12 }, + { .rfmax = 483000, .val = 0x14 }, + { .rfmax = 502000, .val = 0x19 }, + { .rfmax = 508000, .val = 0x1b }, + { .rfmax = 519000, .val = 0x1c }, + { .rfmax = 522000, .val = 0x1d }, + { .rfmax = 524000, .val = 0x1e }, + { .rfmax = 534000, .val = 0x1f }, + { .rfmax = 549000, .val = 0x20 }, + { .rfmax = 554000, .val = 0x22 }, + { .rfmax = 584000, .val = 0x24 }, + { .rfmax = 589000, .val = 0x26 }, + { .rfmax = 658000, .val = 0x27 }, + { .rfmax = 664000, .val = 0x2c }, + { .rfmax = 669000, .val = 0x2d }, + { .rfmax = 699000, .val = 0x2e }, + { .rfmax = 704000, .val = 0x30 }, + { .rfmax = 709000, .val = 0x31 }, + { .rfmax = 714000, .val = 0x32 }, + { .rfmax = 724000, .val = 0x33 }, + { .rfmax = 729000, .val = 0x36 }, + { .rfmax = 739000, .val = 0x38 }, + { .rfmax = 744000, .val = 0x39 }, + { .rfmax = 749000, .val = 0x3b }, + { .rfmax = 754000, .val = 0x3c }, + { .rfmax = 759000, .val = 0x3d }, + { .rfmax = 764000, .val = 0x3e }, + { .rfmax = 769000, .val = 0x3f }, + { .rfmax = 774000, .val = 0x40 }, + { .rfmax = 779000, .val = 0x41 }, + { .rfmax = 784000, .val = 0x43 }, + { .rfmax = 789000, .val = 0x46 }, + { .rfmax = 794000, .val = 0x48 }, + { .rfmax = 799000, .val = 0x4b }, + { .rfmax = 804000, .val = 0x4f }, + { .rfmax = 809000, .val = 0x54 }, + { .rfmax = 814000, .val = 0x59 }, + { .rfmax = 819000, .val = 0x5d }, + { .rfmax = 824000, .val = 0x61 }, + { .rfmax = 829000, .val = 0x68 }, + { .rfmax = 834000, .val = 0x6e }, + { .rfmax = 839000, .val = 0x75 }, + { .rfmax = 844000, .val = 0x7e }, + { .rfmax = 849000, .val = 0x82 }, + { .rfmax = 854000, .val = 0x84 }, + { .rfmax = 859000, .val = 0x8f }, + { .rfmax = 865000, .val = 0x9a }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +/*---------------------------------------------------------------------*/ + +struct tda18271_thermo_map { + u8 d; + u8 r0; + u8 r1; +}; + +static struct tda18271_thermo_map tda18271_thermometer[] = { + { .d = 0x00, .r0 = 60, .r1 = 92 }, + { .d = 0x01, .r0 = 62, .r1 = 94 }, + { .d = 0x02, .r0 = 66, .r1 = 98 }, + { .d = 0x03, .r0 = 64, .r1 = 96 }, + { .d = 0x04, .r0 = 74, .r1 = 106 }, + { .d = 0x05, .r0 = 72, .r1 = 104 }, + { .d = 0x06, .r0 = 68, .r1 = 100 }, + { .d = 0x07, .r0 = 70, .r1 = 102 }, + { .d = 0x08, .r0 = 90, .r1 = 122 }, + { .d = 0x09, .r0 = 88, .r1 = 120 }, + { .d = 0x0a, .r0 = 84, .r1 = 116 }, + { .d = 0x0b, .r0 = 86, .r1 = 118 }, + { .d = 0x0c, .r0 = 76, .r1 = 108 }, + { .d = 0x0d, .r0 = 78, .r1 = 110 }, + { .d = 0x0e, .r0 = 82, .r1 = 114 }, + { .d = 0x0f, .r0 = 80, .r1 = 112 }, + { .d = 0x00, .r0 = 0, .r1 = 0 }, /* end */ +}; + +int tda18271_lookup_thermometer(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int val, i = 0; + + while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) { + if (tda18271_thermometer[i + 1].d == 0) + break; + i++; + } + + if ((regs[R_TM] & 0x20) == 0x20) + val = tda18271_thermometer[i].r1; + else + val = tda18271_thermometer[i].r0; + + tda_map("(%d) tm = %d\n", i, val); + + return val; +} + +/*---------------------------------------------------------------------*/ + +struct tda18271_cid_target_map { + u32 rfmax; + u8 target; + u16 limit; +}; + +static struct tda18271_cid_target_map tda18271_cid_target[] = { + { .rfmax = 46000, .target = 0x04, .limit = 1800 }, + { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, + { .rfmax = 70100, .target = 0x01, .limit = 4000 }, + { .rfmax = 136800, .target = 0x18, .limit = 4000 }, + { .rfmax = 156700, .target = 0x18, .limit = 4000 }, + { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, + { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, + { .rfmax = 345000, .target = 0x18, .limit = 4000 }, + { .rfmax = 426000, .target = 0x0e, .limit = 4000 }, + { .rfmax = 489500, .target = 0x1e, .limit = 4000 }, + { .rfmax = 697500, .target = 0x32, .limit = 4000 }, + { .rfmax = 842000, .target = 0x3a, .limit = 4000 }, + { .rfmax = 0, .target = 0x00, .limit = 0 }, /* end */ +}; + +int tda18271_lookup_cid_target(struct dvb_frontend *fe, + u32 *freq, u8 *cid_target, u16 *count_limit) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int i = 0; + + while ((tda18271_cid_target[i].rfmax * 1000) < *freq) { + if (tda18271_cid_target[i + 1].rfmax == 0) + break; + i++; + } + *cid_target = tda18271_cid_target[i].target; + *count_limit = tda18271_cid_target[i].limit; + + tda_map("(%d) cid_target = %02x, count_limit = %d\n", i, + tda18271_cid_target[i].target, tda18271_cid_target[i].limit); + + return 0; +} + +/*---------------------------------------------------------------------*/ + +static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = { + { .rfmax = 47900, .rfband = 0x00, + .rf1_def = 46000, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 61100, .rfband = 0x01, + .rf1_def = 52200, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 152600, .rfband = 0x02, + .rf1_def = 70100, .rf2_def = 136800, .rf3_def = 0 }, + { .rfmax = 164700, .rfband = 0x03, + .rf1_def = 156700, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 203500, .rfband = 0x04, + .rf1_def = 186250, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 457800, .rfband = 0x05, + .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 }, + { .rfmax = 865000, .rfband = 0x06, + .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 }, + { .rfmax = 0, .rfband = 0x00, + .rf1_def = 0, .rf2_def = 0, .rf3_def = 0 }, /* end */ +}; + +int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + int i = 0; + + while ((map[i].rfmax * 1000) < *freq) { + if (tda18271_debug & DBG_ADV) + tda_map("(%d) rfmax = %d < freq = %d, " + "rf1_def = %d, rf2_def = %d, rf3_def = %d, " + "rf1 = %d, rf2 = %d, rf3 = %d, " + "rf_a1 = %d, rf_a2 = %d, " + "rf_b1 = %d, rf_b2 = %d\n", + i, map[i].rfmax * 1000, *freq, + map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, + map[i].rf1, map[i].rf2, map[i].rf3, + map[i].rf_a1, map[i].rf_a2, + map[i].rf_b1, map[i].rf_b2); + if (map[i].rfmax == 0) + return -EINVAL; + i++; + } + if (rf_band) + *rf_band = map[i].rfband; + + tda_map("(%d) rf_band = %02x\n", i, map[i].rfband); + + return i; +} + +/*---------------------------------------------------------------------*/ + +struct tda18271_map_layout { + struct tda18271_pll_map *main_pll; + struct tda18271_pll_map *cal_pll; + + struct tda18271_map *rf_cal; + struct tda18271_map *rf_cal_kmco; + struct tda18271_map *rf_cal_dc_over_dt; + + struct tda18271_map *bp_filter; + struct tda18271_map *rf_band; + struct tda18271_map *gain_taper; + struct tda18271_map *ir_measure; +}; + +/*---------------------------------------------------------------------*/ + +int tda18271_lookup_pll_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *post_div, u8 *div) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_pll_map *map = NULL; + unsigned int i = 0; + char *map_name; + int ret = 0; + + BUG_ON(!priv->maps); + + switch (map_type) { + case MAIN_PLL: + map = priv->maps->main_pll; + map_name = "main_pll"; + break; + case CAL_PLL: + map = priv->maps->cal_pll; + map_name = "cal_pll"; + break; + default: + /* we should never get here */ + map_name = "undefined"; + break; + } + + if (!map) { + tda_warn("%s map is not set!\n", map_name); + ret = -EINVAL; + goto fail; + } + + while ((map[i].lomax * 1000) < *freq) { + if (map[i + 1].lomax == 0) { + tda_map("%s: frequency (%d) out of range\n", + map_name, *freq); + ret = -ERANGE; + break; + } + i++; + } + *post_div = map[i].pd; + *div = map[i].d; + + tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n", + i, map_name, *post_div, *div); +fail: + return ret; +} + +int tda18271_lookup_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *val) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_map *map = NULL; + unsigned int i = 0; + char *map_name; + int ret = 0; + + BUG_ON(!priv->maps); + + switch (map_type) { + case BP_FILTER: + map = priv->maps->bp_filter; + map_name = "bp_filter"; + break; + case RF_CAL_KMCO: + map = priv->maps->rf_cal_kmco; + map_name = "km"; + break; + case RF_BAND: + map = priv->maps->rf_band; + map_name = "rf_band"; + break; + case GAIN_TAPER: + map = priv->maps->gain_taper; + map_name = "gain_taper"; + break; + case RF_CAL: + map = priv->maps->rf_cal; + map_name = "rf_cal"; + break; + case IR_MEASURE: + map = priv->maps->ir_measure; + map_name = "ir_measure"; + break; + case RF_CAL_DC_OVER_DT: + map = priv->maps->rf_cal_dc_over_dt; + map_name = "rf_cal_dc_over_dt"; + break; + default: + /* we should never get here */ + map_name = "undefined"; + break; + } + + if (!map) { + tda_warn("%s map is not set!\n", map_name); + ret = -EINVAL; + goto fail; + } + + while ((map[i].rfmax * 1000) < *freq) { + if (map[i + 1].rfmax == 0) { + tda_map("%s: frequency (%d) out of range\n", + map_name, *freq); + ret = -ERANGE; + break; + } + i++; + } + *val = map[i].val; + + tda_map("(%d) %s: 0x%02x\n", i, map_name, *val); +fail: + return ret; +} + +/*---------------------------------------------------------------------*/ + +static struct tda18271_std_map tda18271c1_std_map = { + .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ + .atv_b = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_dk = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_gh = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_i = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_l = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ + .atv_mn = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ + .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_7 = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .dvbt_8 = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ + .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ +}; + +static struct tda18271_std_map tda18271c2_std_map = { + .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ + .atv_b = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ + .atv_dk = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_gh = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_i = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_l = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ + .atv_mn = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4, + .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */ + .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_7 = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ + .dvbt_8 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ +}; + +/*---------------------------------------------------------------------*/ + +static struct tda18271_map_layout tda18271c1_map_layout = { + .main_pll = tda18271c1_main_pll, + .cal_pll = tda18271c1_cal_pll, + + .rf_cal = tda18271c1_rf_cal, + .rf_cal_kmco = tda18271c1_km, + + .bp_filter = tda18271_bp_filter, + .rf_band = tda18271_rf_band, + .gain_taper = tda18271_gain_taper, + .ir_measure = tda18271_ir_measure, +}; + +static struct tda18271_map_layout tda18271c2_map_layout = { + .main_pll = tda18271c2_main_pll, + .cal_pll = tda18271c2_cal_pll, + + .rf_cal = tda18271c2_rf_cal, + .rf_cal_kmco = tda18271c2_km, + + .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt, + + .bp_filter = tda18271_bp_filter, + .rf_band = tda18271_rf_band, + .gain_taper = tda18271_gain_taper, + .ir_measure = tda18271_ir_measure, +}; + +int tda18271_assign_map_layout(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret = 0; + + switch (priv->id) { + case TDA18271HDC1: + priv->maps = &tda18271c1_map_layout; + memcpy(&priv->std, &tda18271c1_std_map, + sizeof(struct tda18271_std_map)); + break; + case TDA18271HDC2: + priv->maps = &tda18271c2_map_layout; + memcpy(&priv->std, &tda18271c2_std_map, + sizeof(struct tda18271_std_map)); + break; + default: + ret = -EINVAL; + break; + } + memcpy(priv->rf_cal_state, &tda18271_rf_band_template, + sizeof(tda18271_rf_band_template)); + + return ret; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda18271-priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,237 @@ +/* + tda18271-priv.h - private header for the NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA18271_PRIV_H__ +#define __TDA18271_PRIV_H__ + +#include +#include +#include +#include "tuner-i2c.h" +#include "tda18271.h" + +#define R_ID 0x00 /* ID byte */ +#define R_TM 0x01 /* Thermo byte */ +#define R_PL 0x02 /* Power level byte */ +#define R_EP1 0x03 /* Easy Prog byte 1 */ +#define R_EP2 0x04 /* Easy Prog byte 2 */ +#define R_EP3 0x05 /* Easy Prog byte 3 */ +#define R_EP4 0x06 /* Easy Prog byte 4 */ +#define R_EP5 0x07 /* Easy Prog byte 5 */ +#define R_CPD 0x08 /* Cal Post-Divider byte */ +#define R_CD1 0x09 /* Cal Divider byte 1 */ +#define R_CD2 0x0a /* Cal Divider byte 2 */ +#define R_CD3 0x0b /* Cal Divider byte 3 */ +#define R_MPD 0x0c /* Main Post-Divider byte */ +#define R_MD1 0x0d /* Main Divider byte 1 */ +#define R_MD2 0x0e /* Main Divider byte 2 */ +#define R_MD3 0x0f /* Main Divider byte 3 */ +#define R_EB1 0x10 /* Extended byte 1 */ +#define R_EB2 0x11 /* Extended byte 2 */ +#define R_EB3 0x12 /* Extended byte 3 */ +#define R_EB4 0x13 /* Extended byte 4 */ +#define R_EB5 0x14 /* Extended byte 5 */ +#define R_EB6 0x15 /* Extended byte 6 */ +#define R_EB7 0x16 /* Extended byte 7 */ +#define R_EB8 0x17 /* Extended byte 8 */ +#define R_EB9 0x18 /* Extended byte 9 */ +#define R_EB10 0x19 /* Extended byte 10 */ +#define R_EB11 0x1a /* Extended byte 11 */ +#define R_EB12 0x1b /* Extended byte 12 */ +#define R_EB13 0x1c /* Extended byte 13 */ +#define R_EB14 0x1d /* Extended byte 14 */ +#define R_EB15 0x1e /* Extended byte 15 */ +#define R_EB16 0x1f /* Extended byte 16 */ +#define R_EB17 0x20 /* Extended byte 17 */ +#define R_EB18 0x21 /* Extended byte 18 */ +#define R_EB19 0x22 /* Extended byte 19 */ +#define R_EB20 0x23 /* Extended byte 20 */ +#define R_EB21 0x24 /* Extended byte 21 */ +#define R_EB22 0x25 /* Extended byte 22 */ +#define R_EB23 0x26 /* Extended byte 23 */ + +#define TDA18271_NUM_REGS 39 + +/*---------------------------------------------------------------------*/ + +struct tda18271_rf_tracking_filter_cal { + u32 rfmax; + u8 rfband; + u32 rf1_def; + u32 rf2_def; + u32 rf3_def; + u32 rf1; + u32 rf2; + u32 rf3; + s32 rf_a1; + s32 rf_b1; + s32 rf_a2; + s32 rf_b2; +}; + +enum tda18271_pll { + TDA18271_MAIN_PLL, + TDA18271_CAL_PLL, +}; + +struct tda18271_map_layout; + +enum tda18271_ver { + TDA18271HDC1, + TDA18271HDC2, +}; + +struct tda18271_priv { + unsigned char tda18271_regs[TDA18271_NUM_REGS]; + + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + + enum tda18271_mode mode; + enum tda18271_role role; + enum tda18271_i2c_gate gate; + enum tda18271_ver id; + enum tda18271_output_options output_opt; + enum tda18271_small_i2c small_i2c; + + unsigned int config; /* interface to saa713x / tda829x */ + unsigned int cal_initialized:1; + + u8 tm_rfcal; + + struct tda18271_map_layout *maps; + struct tda18271_std_map std; + struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; + + struct mutex lock; + + u32 frequency; + u32 bandwidth; +}; + +/*---------------------------------------------------------------------*/ + +extern int tda18271_debug; + +#define DBG_INFO 1 +#define DBG_MAP 2 +#define DBG_REG 4 +#define DBG_ADV 8 +#define DBG_CAL 16 + +#define tda_printk(st, kern, fmt, arg...) do {\ + if (st) { \ + struct tda18271_priv *state = st; \ + printk(kern "%s: [%d-%04x|%s] " fmt, __func__, \ + i2c_adapter_id(state->i2c_props.adap), \ + state->i2c_props.addr, \ + (state->role == TDA18271_MASTER) \ + ? "M" : "S", ##arg); \ + } else \ + printk(kern "%s: " fmt, __func__, ##arg); \ +} while (0) + +#define tda_dprintk(st, lvl, fmt, arg...) do {\ + if (tda18271_debug & lvl) \ + tda_printk(st, KERN_DEBUG, fmt, ##arg); } while (0) + +#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) +#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg) +#define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg) +#define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg) +#define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg) +#define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg) +#define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg) + +#define tda_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + tda_printk(priv, KERN_ERR, \ + "error %d on line %d\n", ret, __LINE__); \ + __ret; \ +}) + +/*---------------------------------------------------------------------*/ + +enum tda18271_map_type { + /* tda18271_pll_map */ + MAIN_PLL, + CAL_PLL, + /* tda18271_map */ + RF_CAL, + RF_CAL_KMCO, + RF_CAL_DC_OVER_DT, + BP_FILTER, + RF_BAND, + GAIN_TAPER, + IR_MEASURE, +}; + +extern int tda18271_lookup_pll_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *post_div, u8 *div); +extern int tda18271_lookup_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *val); + +extern int tda18271_lookup_thermometer(struct dvb_frontend *fe); + +extern int tda18271_lookup_rf_band(struct dvb_frontend *fe, + u32 *freq, u8 *rf_band); + +extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, + u32 *freq, u8 *cid_target, + u16 *count_limit); + +extern int tda18271_assign_map_layout(struct dvb_frontend *fe); + +/*---------------------------------------------------------------------*/ + +extern int tda18271_read_regs(struct dvb_frontend *fe); +extern int tda18271_read_extended(struct dvb_frontend *fe); +extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); +extern int tda18271_init_regs(struct dvb_frontend *fe); + +extern int tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force); +extern int tda18271_set_standby_mode(struct dvb_frontend *fe, + int sm, int sm_lt, int sm_xt); + +extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); +extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); + +extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); + +#endif /* __TDA18271_PRIV_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda827x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda827x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda827x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda827x.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,913 @@ +/* + * + * (c) 2005 Hartmut Hackmann + * (c) 2007 Michael Krufky + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "tda827x.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "tda827x: " args); \ + } while (0) + +struct tda827x_priv { + int i2c_addr; + struct i2c_adapter *i2c_adap; + struct tda827x_config *cfg; + + unsigned int sgIF; + unsigned char lpsel; + + u32 frequency; + u32 bandwidth; +}; + +static void tda827x_set_std(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + char *mode; + + priv->lpsel = 0; + if (params->std & V4L2_STD_MN) { + priv->sgIF = 92; + priv->lpsel = 1; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->sgIF = 108; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->sgIF = 124; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->sgIF = 124; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->sgIF = 124; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->sgIF = 124; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->sgIF = 20; + mode = "LC"; + } else { + priv->sgIF = 124; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) { + priv->sgIF = 88; /* if frequency is 5.5 MHz */ + dprintk("setting tda827x to radio FM\n"); + } else + dprintk("setting tda827x to system %s\n", mode); +} + + +/* ------------------------------------------------------------------ */ + +struct tda827x_data { + u32 lomax; + u8 spd; + u8 bs; + u8 bp; + u8 cp; + u8 gc3; + u8 div1p5; +}; + +static const struct tda827x_data tda827x_table[] = { + { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} +}; + +static int tuner_transfer(struct dvb_frontend *fe, + struct i2c_msg *msg, + const int size) +{ + int rc; + struct tda827x_priv *priv = fe->tuner_priv; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + rc = i2c_transfer(priv->i2c_adap, msg, size); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (rc >= 0 && rc != size) + return -EIO; + + return rc; +} + +static int tda827xo_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + u8 buf[14]; + int rc; + + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + int i, tuner_freq, if_freq; + u32 N; + + dprintk("%s:\n", __func__); + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + if_freq = 4000000; + break; + case BANDWIDTH_7_MHZ: + if_freq = 4500000; + break; + default: /* 8 MHz or Auto */ + if_freq = 5000000; + break; + } + tuner_freq = params->frequency + if_freq; + + i = 0; + while (tda827x_table[i].lomax < tuner_freq) { + if (tda827x_table[i + 1].lomax == 0) + break; + i++; + } + + N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); + buf[0] = 0; + buf[1] = (N>>8) | 0x40; + buf[2] = N & 0xff; + buf[3] = 0; + buf[4] = 0x52; + buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + + tda827x_table[i].bp; + buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; + buf[7] = 0xbf; + buf[8] = 0x2a; + buf[9] = 0x05; + buf[10] = 0xff; + buf[11] = 0x00; + buf[12] = 0x00; + buf[13] = 0x40; + + msg.len = 14; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + msleep(500); + /* correct CP value */ + buf[0] = 0x30; + buf[1] = 0x50 + tda827x_table[i].cp; + msg.len = 2; + + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + priv->frequency = params->frequency; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + + return 0; + +err: + printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", + __func__, priv->i2c_addr << 1); + return rc; +} + +static int tda827xo_sleep(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + static u8 buf[] = { 0x30, 0xd0 }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + dprintk("%s:\n", __func__); + tuner_transfer(fe, &msg, 1); + + if (priv->cfg && priv->cfg->sleep) + priv->cfg->sleep(fe); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda827xo_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[8]; + unsigned char reg2[2]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; + unsigned int freq = params->frequency; + + tda827x_set_std(fe, params); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->sgIF; + + i = 0; + while (tda827x_table[i].lomax < N * 62500) { + if (tda827x_table[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827x_table[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0x40; + tuner_reg[4] = 0x52 + (priv->lpsel << 5); + tuner_reg[5] = (tda827x_table[i].spd << 6) + + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + tda827x_table[i].bp; + tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); + tuner_reg[7] = 0x8f; + + msg.buf = tuner_reg; + msg.len = 8; + tuner_transfer(fe, &msg, 1); + + msg.buf = reg2; + msg.len = 2; + reg2[0] = 0x80; + reg2[1] = 0; + tuner_transfer(fe, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0xbf; + tuner_transfer(fe, &msg, 1); + + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 0x80; + tuner_transfer(fe, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 4; + tuner_transfer(fe, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4]; + tuner_transfer(fe, &msg, 1); + + msleep(550); + reg2[0] = 0x30; + reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; + tuner_transfer(fe, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0x3f; + tuner_transfer(fe, &msg, 1); + + reg2[0] = 0x80; + reg2[1] = 0x08; /* Vsync en */ + tuner_transfer(fe, &msg, 1); + + priv->frequency = params->frequency; + + return 0; +} + +static void tda827xo_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = { 0x80, 0x0c }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + + tuner_transfer(fe, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + +struct tda827xa_data { + u32 lomax; + u8 svco; + u8 spd; + u8 scr; + u8 sbs; + u8 gc3; +}; + +static struct tda827xa_data tda827xa_dvbt[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + +static struct tda827xa_data tda827xa_dvbc[] = { + { .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, + { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, + { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1}, + { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3}, + { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1}, + { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, + { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, + { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1}, + { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1}, + { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, + { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, + { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, + { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, + { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, + { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + +static struct tda827xa_data tda827xa_analog[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + +static int tda827xa_sleep(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + static u8 buf[] = { 0x30, 0x90 }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + dprintk("%s:\n", __func__); + + tuner_transfer(fe, &msg, 1); + + if (priv->cfg && priv->cfg->sleep) + priv->cfg->sleep(fe); + + return 0; +} + +static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char buf[] = {0x22, 0x01}; + int arg; + int gp_func; + struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) }; + + if (NULL == priv->cfg) { + dprintk("tda827x_config not defined, cannot set LNA gain!\n"); + return; + } + msg.addr = priv->cfg->switch_addr; + if (priv->cfg->config) { + if (high) + dprintk("setting LNA to high gain\n"); + else + dprintk("setting LNA to low gain\n"); + } + switch (priv->cfg->config) { + case 0: /* no LNA */ + break; + case 1: /* switch is GPIO 0 of tda8290 */ + case 2: + if (params == NULL) { + gp_func = 0; + arg = 0; + } else { + /* turn Vsync on */ + gp_func = 1; + if (params->std & V4L2_STD_MN) + arg = 1; + else + arg = 0; + } + if (fe->callback) + fe->callback(priv->i2c_adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + gp_func, arg); + buf[1] = high ? 0 : 1; + if (priv->cfg->config == 2) + buf[1] = high ? 1 : 0; + tuner_transfer(fe, &msg, 1); + break; + case 3: /* switch with GPIO of saa713x */ + if (fe->callback) + fe->callback(priv->i2c_adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, 0, high); + break; + } +} + +static int tda827xa_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + struct tda827xa_data *frequency_map = tda827xa_dvbt; + u8 buf[11]; + + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + int i, tuner_freq, if_freq, rc; + u32 N; + + dprintk("%s:\n", __func__); + + tda827xa_lna_gain(fe, 1, NULL); + msleep(20); + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + if_freq = 4000000; + break; + case BANDWIDTH_7_MHZ: + if_freq = 4500000; + break; + default: /* 8 MHz or Auto */ + if_freq = 5000000; + break; + } + tuner_freq = params->frequency + if_freq; + + if (fe->ops.info.type == FE_QAM) { + dprintk("%s select tda827xa_dvbc\n", __func__); + frequency_map = tda827xa_dvbc; + } + + i = 0; + while (frequency_map[i].lomax < tuner_freq) { + if (frequency_map[i + 1].lomax == 0) + break; + i++; + } + + N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd; + buf[0] = 0; // subaddress + buf[1] = N >> 8; + buf[2] = N & 0xff; + buf[3] = 0; + buf[4] = 0x16; + buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) + + frequency_map[i].sbs; + buf[6] = 0x4b + (frequency_map[i].gc3 << 4); + buf[7] = 0x1c; + buf[8] = 0x06; + buf[9] = 0x24; + buf[10] = 0x00; + msg.len = 11; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + buf[0] = 0x90; + buf[1] = 0xff; + buf[2] = 0x60; + buf[3] = 0x00; + buf[4] = 0x59; // lpsel, for 6MHz + 2 + msg.len = 5; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + buf[0] = 0xa0; + buf[1] = 0x40; + msg.len = 2; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + msleep(11); + msg.flags = I2C_M_RD; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + msg.flags = 0; + + buf[1] >>= 4; + dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); + if ((buf[1]) < 2) { + tda827xa_lna_gain(fe, 0, NULL); + buf[0] = 0x60; + buf[1] = 0x0c; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + } + + buf[0] = 0xc0; + buf[1] = 0x99; // lpsel, for 6MHz + 2 + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + buf[0] = 0x60; + buf[1] = 0x3c; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + /* correct CP value */ + buf[0] = 0x30; + buf[1] = 0x10 + frequency_map[i].scr; + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + msleep(163); + buf[0] = 0xc0; + buf[1] = 0x39; // lpsel, for 6MHz + 2 + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + msleep(3); + /* freeze AGC1 */ + buf[0] = 0x50; + buf[1] = 0x4f + (frequency_map[i].gc3 << 4); + rc = tuner_transfer(fe, &msg, 1); + if (rc < 0) + goto err; + + priv->frequency = params->frequency; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + + + return 0; + +err: + printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", + __func__, priv->i2c_addr << 1); + return rc; +} + + +static int tda827xa_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[11]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = tuner_reg, .len = sizeof(tuner_reg) }; + unsigned int freq = params->frequency; + + tda827x_set_std(fe, params); + + tda827xa_lna_gain(fe, 1, params); + msleep(10); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->sgIF; + + i = 0; + while (tda827xa_analog[i].lomax < N * 62500) { + if (tda827xa_analog[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827xa_analog[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0; + tuner_reg[4] = 0x16; + tuner_reg[5] = (tda827xa_analog[i].spd << 5) + + (tda827xa_analog[i].svco << 3) + + tda827xa_analog[i].sbs; + tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); + tuner_reg[7] = 0x1c; + tuner_reg[8] = 4; + tuner_reg[9] = 0x20; + tuner_reg[10] = 0x00; + msg.len = 11; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0x90; + tuner_reg[1] = 0xff; + tuner_reg[2] = 0xe0; + tuner_reg[3] = 0; + tuner_reg[4] = 0x99 + (priv->lpsel << 1); + msg.len = 5; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0xa0; + tuner_reg[1] = 0xc0; + msg.len = 2; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0x30; + tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; + tuner_transfer(fe, &msg, 1); + + msg.flags = I2C_M_RD; + tuner_transfer(fe, &msg, 1); + msg.flags = 0; + tuner_reg[1] >>= 4; + dprintk("AGC2 gain is: %d\n", tuner_reg[1]); + if (tuner_reg[1] < 1) + tda827xa_lna_gain(fe, 0, params); + + msleep(100); + tuner_reg[0] = 0x60; + tuner_reg[1] = 0x3c; + tuner_transfer(fe, &msg, 1); + + msleep(163); + tuner_reg[0] = 0x50; + tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0x80; + tuner_reg[1] = 0x28; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0xb0; + tuner_reg[1] = 0x01; + tuner_transfer(fe, &msg, 1); + + tuner_reg[0] = 0xc0; + tuner_reg[1] = 0x19 + (priv->lpsel << 1); + tuner_transfer(fe, &msg, 1); + + priv->frequency = params->frequency; + + return 0; +} + +static void tda827xa_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = {0x80, 0x2c}; + struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + tuner_transfer(fe, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + +static int tda827x_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda827x_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tda827x_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int tda827x_init(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + dprintk("%s:\n", __func__); + if (priv->cfg && priv->cfg->init) + priv->cfg->init(fe); + + return 0; +} + +static int tda827x_probe_version(struct dvb_frontend *fe); + +static int tda827x_initial_init(struct dvb_frontend *fe) +{ + int ret; + ret = tda827x_probe_version(fe); + if (ret) + return ret; + return fe->ops.tuner_ops.init(fe); +} + +static int tda827x_initial_sleep(struct dvb_frontend *fe) +{ + int ret; + ret = tda827x_probe_version(fe); + if (ret) + return ret; + return fe->ops.tuner_ops.sleep(fe); +} + +static struct dvb_tuner_ops tda827xo_tuner_ops = { + .info = { + .name = "Philips TDA827X", + .frequency_min = 55000000, + .frequency_max = 860000000, + .frequency_step = 250000 + }, + .release = tda827x_release, + .init = tda827x_initial_init, + .sleep = tda827x_initial_sleep, + .set_params = tda827xo_set_params, + .set_analog_params = tda827xo_set_analog_params, + .get_frequency = tda827x_get_frequency, + .get_bandwidth = tda827x_get_bandwidth, +}; + +static struct dvb_tuner_ops tda827xa_tuner_ops = { + .info = { + .name = "Philips TDA827XA", + .frequency_min = 44000000, + .frequency_max = 906000000, + .frequency_step = 62500 + }, + .release = tda827x_release, + .init = tda827x_init, + .sleep = tda827xa_sleep, + .set_params = tda827xa_set_params, + .set_analog_params = tda827xa_set_analog_params, + .get_frequency = tda827x_get_frequency, + .get_bandwidth = tda827x_get_bandwidth, +}; + +static int tda827x_probe_version(struct dvb_frontend *fe) +{ + u8 data; + int rc; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = &data, .len = 1 }; + + rc = tuner_transfer(fe, &msg, 1); + + if (rc < 0) { + printk("%s: could not read from tuner at addr: 0x%02x\n", + __func__, msg.addr << 1); + return rc; + } + if ((data & 0x3c) == 0) { + dprintk("tda827x tuner found\n"); + fe->ops.tuner_ops.init = tda827x_init; + fe->ops.tuner_ops.sleep = tda827xo_sleep; + if (priv->cfg) + priv->cfg->agcf = tda827xo_agcf; + } else { + dprintk("tda827xa tuner found\n"); + memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); + if (priv->cfg) + priv->cfg->agcf = tda827xa_agcf; + } + return 0; +} + +struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg) +{ + struct tda827x_priv *priv = NULL; + + dprintk("%s:\n", __func__); + priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + priv->cfg = cfg; + memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = priv; + + dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); + + return fe; +} +EXPORT_SYMBOL_GPL(tda827x_attach); + +MODULE_DESCRIPTION("DVB TDA827x driver"); +MODULE_AUTHOR("Hartmut Hackmann "); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda827x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda827x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda827x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda827x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,68 @@ + /* + DVB Driver for Philips tda827x / tda827xa Silicon tuners + + (c) 2005 Hartmut Hackmann + (c) 2007 Michael Krufky + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef __DVB_TDA827X_H__ +#define __DVB_TDA827X_H__ + +#include +#include "dvb_frontend.h" + +struct tda827x_config +{ + /* saa7134 - provided callbacks */ + int (*init) (struct dvb_frontend *fe); + int (*sleep) (struct dvb_frontend *fe); + + /* interface to tda829x driver */ + unsigned int config; + int switch_addr; + + void (*agcf)(struct dvb_frontend *fe); +}; + + +/** + * Attach a tda827x tuner to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param addr i2c address of the tuner. + * @param i2c i2c adapter to use. + * @param cfg optional callback function pointers. + * @return FE pointer on success, NULL on failure. + */ +#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg); +#else +static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, + int addr, + struct i2c_adapter *i2c, + struct tda827x_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_MEDIA_TUNER_TDA827X + +#endif // __DVB_TDA827X_H__ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda8290.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda8290.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda8290.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda8290.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,874 @@ +/* + + i2c tv tuner chip device driver + controls the philips tda8290+75 tuner chip combo. + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + This "tda8290" module was split apart from the original "tuner" module. +*/ + +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tda8290.h" +#include "tda827x.h" +#include "tda18271.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static int deemphasis_50; +module_param(deemphasis_50, int, 0644); +MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis"); + +/* ---------------------------------------------------------------------- */ + +struct tda8290_priv { + struct tuner_i2c_props i2c_props; + + unsigned char tda8290_easy_mode; + + unsigned char tda827x_addr; + + unsigned char ver; +#define TDA8290 1 +#define TDA8295 2 +#define TDA8275 4 +#define TDA8275A 8 +#define TDA18271 16 + + struct tda827x_config cfg; +}; + +/*---------------------------------------------------------------------*/ + +static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char enable[2] = { 0x21, 0xC0 }; + unsigned char disable[2] = { 0x21, 0x00 }; + unsigned char *msg; + + if (close) { + msg = enable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + /* let the bridge stabilize */ + msleep(20); + } else { + msg = disable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + } + + return 0; +} + +static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char enable[2] = { 0x45, 0xc1 }; + unsigned char disable[2] = { 0x46, 0x00 }; + unsigned char buf[3] = { 0x45, 0x01, 0x00 }; + unsigned char *msg; + + if (close) { + msg = enable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + /* let the bridge stabilize */ + msleep(20); + } else { + msg = disable; + tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1); + + buf[2] = msg[1]; + buf[2] &= ~0x04; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); + msleep(5); + + msg[1] |= 0x04; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + } + + return 0; +} + +/*---------------------------------------------------------------------*/ + +static void set_audio(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + char* mode; + + if (params->std & V4L2_STD_MN) { + priv->tda8290_easy_mode = 0x01; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->tda8290_easy_mode = 0x02; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->tda8290_easy_mode = 0x04; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->tda8290_easy_mode = 0x08; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->tda8290_easy_mode = 0x10; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->tda8290_easy_mode = 0x20; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->tda8290_easy_mode = 0x40; + mode = "LC"; + } else { + priv->tda8290_easy_mode = 0x10; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) { + /* Set TDA8295 to FM radio; Start TDA8290 with MN values */ + priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01; + tuner_dbg("setting to radio FM\n"); + } else { + tuner_dbg("setting tda829x to system %s\n", mode); + } +} + +static struct { + unsigned char seq[2]; +} fm_mode[] = { + { { 0x01, 0x81} }, /* Put device into expert mode */ + { { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */ + { { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */ + { { 0x05, 0x04} }, /* ADC headroom */ + { { 0x06, 0x10} }, /* group delay flat */ + + { { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */ + { { 0x08, 0x00} }, + { { 0x09, 0x80} }, + { { 0x0a, 0xda} }, + { { 0x0b, 0x4b} }, + { { 0x0c, 0x68} }, + + { { 0x0d, 0x00} }, /* PLL off, no video carrier detect */ + { { 0x14, 0x00} }, /* disable auto mute if no video */ +}; + +static void tda8290_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char soft_reset[] = { 0x00, 0x00 }; + unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; + unsigned char expert_mode[] = { 0x01, 0x80 }; + unsigned char agc_out_on[] = { 0x02, 0x00 }; + unsigned char gainset_off[] = { 0x28, 0x14 }; + unsigned char if_agc_spd[] = { 0x0f, 0x88 }; + unsigned char adc_head_6[] = { 0x05, 0x04 }; + unsigned char adc_head_9[] = { 0x05, 0x02 }; + unsigned char adc_head_12[] = { 0x05, 0x01 }; + unsigned char pll_bw_nom[] = { 0x0d, 0x47 }; + unsigned char pll_bw_low[] = { 0x0d, 0x27 }; + unsigned char gainset_2[] = { 0x28, 0x64 }; + unsigned char agc_rst_on[] = { 0x0e, 0x0b }; + unsigned char agc_rst_off[] = { 0x0e, 0x09 }; + unsigned char if_agc_set[] = { 0x0f, 0x81 }; + unsigned char addr_adc_sat = 0x1a; + unsigned char addr_agc_stat = 0x1d; + unsigned char addr_pll_stat = 0x1b; + unsigned char adc_sat, agc_stat, + pll_stat; + int i; + + set_audio(fe, params); + + if (priv->cfg.config) + tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config); + tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); + tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); + msleep(1); + + if (params->mode == V4L2_TUNER_RADIO) { + unsigned char deemphasis[] = { 0x13, 1 }; + + /* FIXME: allow using a different deemphasis */ + + if (deemphasis_50) + deemphasis[1] = 2; + + for (i = 0; i < ARRAY_SIZE(fm_mode); i++) + tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2); + + tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2); + } else { + expert_mode[1] = priv->tda8290_easy_mode + 0x80; + tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); + if (priv->tda8290_easy_mode & 0x60) + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); + else + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); + } + + + tda8290_i2c_bridge(fe, 1); + + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, params); + + for (i = 0; i < 3; i++) { + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, &pll_stat, 1); + if (pll_stat & 0x80) { + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_adc_sat, 1, + &adc_sat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_agc_stat, 1, + &agc_stat, 1); + tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); + break; + } else { + tuner_dbg("tda8290 not locked, no signal?\n"); + msleep(100); + } + } + /* adjust headroom resp. gain */ + if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { + tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", + agc_stat, adc_sat, pll_stat & 0x80); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); + msleep(100); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_agc_stat, 1, &agc_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, &pll_stat, 1); + if ((agc_stat > 115) || !(pll_stat & 0x80)) { + tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", + agc_stat, pll_stat & 0x80); + if (priv->cfg.agcf) + priv->cfg.agcf(fe); + msleep(100); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_agc_stat, 1, + &agc_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, + &pll_stat, 1); + if((agc_stat > 115) || !(pll_stat & 0x80)) { + tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); + msleep(100); + } + } + } + + /* l/ l' deadlock? */ + if(priv->tda8290_easy_mode & 0x60) { + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_adc_sat, 1, + &adc_sat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, + &pll_stat, 1); + if ((adc_sat > 20) || !(pll_stat & 0x80)) { + tuner_dbg("trying to resolve SECAM L deadlock\n"); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); + msleep(40); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); + } + } + + tda8290_i2c_bridge(fe, 0); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); +} + +/*---------------------------------------------------------------------*/ + +static void tda8295_power(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ + + tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); + + if (enable) + buf[1] = 0x01; + else + buf[1] = 0x03; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x01, 0x00 }; + + tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); + + if (enable) + buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ + else + buf[1] = 0x00; /* reset active bit */ + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_video_std(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); + + tda8295_set_easy_mode(fe, 1); + msleep(20); + tda8295_set_easy_mode(fe, 0); +} + +/*---------------------------------------------------------------------*/ + +static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ + + tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); + + if (enable) + buf[1] &= ~0x40; + else + buf[1] |= 0x40; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char set_gpio_cf[] = { 0x44, 0x00 }; + unsigned char set_gpio_val[] = { 0x46, 0x00 }; + + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &set_gpio_cf[0], 1, &set_gpio_cf[1], 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &set_gpio_val[0], 1, &set_gpio_val[1], 1); + + set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ + + if (enable) { + set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ + set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ + } + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); +} + +static int tda8295_has_signal(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char hvpll_stat = 0x26; + unsigned char ret; + + tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); + return (ret & 0x01) ? 65535 : 0; +} + +/*---------------------------------------------------------------------*/ + +static void tda8295_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char blanking_mode[] = { 0x1d, 0x00 }; + + set_audio(fe, params); + + tuner_dbg("%s: freq = %d\n", __func__, params->frequency); + + tda8295_power(fe, 1); + tda8295_agc1_out(fe, 1); + + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &blanking_mode[0], 1, &blanking_mode[1], 1); + + tda8295_set_video_std(fe); + + blanking_mode[1] = 0x03; + tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); + msleep(20); + + tda8295_i2c_bridge(fe, 1); + + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, params); + + if (priv->cfg.agcf) + priv->cfg.agcf(fe); + + if (tda8295_has_signal(fe)) + tuner_dbg("tda8295 is locked\n"); + else + tuner_dbg("tda8295 not locked, no signal?\n"); + + tda8295_i2c_bridge(fe, 0); +} + +/*---------------------------------------------------------------------*/ + +static int tda8290_has_signal(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char i2c_get_afc[1] = { 0x1B }; + unsigned char afc = 0; + + tuner_i2c_xfer_send_recv(&priv->i2c_props, + i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); + return (afc & 0x80)? 65535:0; +} + +/*---------------------------------------------------------------------*/ + +static void tda8290_standby(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char cb1[] = { 0x30, 0xD0 }; + unsigned char tda8290_standby[] = { 0x00, 0x02 }; + unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; + + tda8290_i2c_bridge(fe, 1); + if (priv->ver & TDA8275A) + cb1[1] = 0x90; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(fe, 0); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); +} + +static void tda8295_standby(struct dvb_frontend *fe) +{ + tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ + + tda8295_power(fe, 0); +} + +static void tda8290_init_if(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char set_VS[] = { 0x30, 0x6F }; + unsigned char set_GP00_CF[] = { 0x20, 0x01 }; + unsigned char set_GP01_CF[] = { 0x20, 0x0B }; + + if ((priv->cfg.config == 1) || (priv->cfg.config == 2)) + tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); + else + tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); +} + +static void tda8295_init_if(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; + static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; + static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; + static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; + static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; + static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; + static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; + + tda8295_power(fe, 1); + + tda8295_set_easy_mode(fe, 0); + tda8295_set_video_std(fe); + + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); + + tda8295_agc1_out(fe, 0); + tda8295_agc2_out(fe, 0); +} + +static void tda8290_init_tuner(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, + 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; + unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, + 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, + .buf=tda8275_init, .len = 14}; + if (priv->ver & TDA8275A) + msg.buf = tda8275a_init; + + tda8290_i2c_bridge(fe, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(fe, 0); +} + +/*---------------------------------------------------------------------*/ + +static void tda829x_release(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + /* only try to release the tuner if we've + * attached it from within this module */ + if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); + + kfree(fe->analog_demod_priv); + fe->analog_demod_priv = NULL; +} + +static struct tda18271_config tda829x_tda18271_config = { + .gate = TDA18271_GATE_ANALOG, +}; + +static int tda829x_find_tuner(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; + int i, ret, tuners_found; + u32 tuner_addrs; + u8 data; + struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; + + if (!analog_ops->i2c_gate_ctrl) { + printk(KERN_ERR "tda8290: no gate control were provided!\n"); + + return -EINVAL; + } + + analog_ops->i2c_gate_ctrl(fe, 1); + + /* probe for tuner chip */ + tuners_found = 0; + tuner_addrs = 0; + for (i = 0x60; i <= 0x63; i++) { + msg.addr = i; + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + if (ret == 1) { + tuners_found++; + tuner_addrs = (tuner_addrs << 8) + i; + } + } + /* if there is more than one tuner, we expect the right one is + behind the bridge and we choose the highest address that doesn't + give a response now + */ + + analog_ops->i2c_gate_ctrl(fe, 0); + + if (tuners_found > 1) + for (i = 0; i < tuners_found; i++) { + msg.addr = tuner_addrs & 0xff; + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + if (ret == 1) + tuner_addrs = tuner_addrs >> 8; + else + break; + } + + if (tuner_addrs == 0) { + tuner_addrs = 0x60; + tuner_info("could not clearly identify tuner address, " + "defaulting to %x\n", tuner_addrs); + } else { + tuner_addrs = tuner_addrs & 0xff; + tuner_info("setting tuner address to %x\n", tuner_addrs); + } + priv->tda827x_addr = tuner_addrs; + msg.addr = tuner_addrs; + + analog_ops->i2c_gate_ctrl(fe, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + + if (ret != 1) { + tuner_warn("tuner access failed!\n"); + analog_ops->i2c_gate_ctrl(fe, 0); + return -EREMOTEIO; + } + + if ((data == 0x83) || (data == 0x84)) { + priv->ver |= TDA18271; + tda829x_tda18271_config.config = priv->cfg.config; + dvb_attach(tda18271_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &tda829x_tda18271_config); + } else { + if ((data & 0x3c) == 0) + priv->ver |= TDA8275; + else + priv->ver |= TDA8275A; + + dvb_attach(tda827x_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); + priv->cfg.switch_addr = priv->i2c_props.addr; + } + if (fe->ops.tuner_ops.init) + fe->ops.tuner_ops.init(fe); + + if (fe->ops.tuner_ops.sleep) + fe->ops.tuner_ops.sleep(fe); + + analog_ops->i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int tda8290_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8290_ID 0x89 + u8 reg = 0x1f, id; + struct i2c_msg msg_read[] = { + { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, + { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, + }; + + /* detect tda8290 */ + if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { + printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", + __func__, reg); + return -ENODEV; + } + + if (id == TDA8290_ID) { + if (debug) + printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", + __func__, i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; + } + return -ENODEV; +} + +static int tda8295_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8295_ID 0x8a +#define TDA8295C2_ID 0x8b + u8 reg = 0x2f, id; + struct i2c_msg msg_read[] = { + { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, + { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, + }; + + /* detect tda8295 */ + if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { + printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", + __func__, reg); + return -ENODEV; + } + + if ((id & 0xfe) == TDA8295_ID) { + if (debug) + printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n", + __func__, (id == TDA8295_ID) ? + "tda8295c1" : "tda8295c2", + i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; + } + + return -ENODEV; +} + +static struct analog_demod_ops tda8290_ops = { + .set_params = tda8290_set_params, + .has_signal = tda8290_has_signal, + .standby = tda8290_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8290_i2c_bridge, +}; + +static struct analog_demod_ops tda8295_ops = { + .set_params = tda8295_set_params, + .has_signal = tda8295_has_signal, + .standby = tda8295_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8295_i2c_bridge, +}; + +struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, + struct tda829x_config *cfg) +{ + struct tda8290_priv *priv = NULL; + char *name; + + priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->analog_demod_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->i2c_props.name = "tda829x"; + if (cfg) + priv->cfg.config = cfg->lna_cfg; + + if (tda8290_probe(&priv->i2c_props) == 0) { + priv->ver = TDA8290; + memcpy(&fe->ops.analog_ops, &tda8290_ops, + sizeof(struct analog_demod_ops)); + } + + if (tda8295_probe(&priv->i2c_props) == 0) { + priv->ver = TDA8295; + memcpy(&fe->ops.analog_ops, &tda8295_ops, + sizeof(struct analog_demod_ops)); + } + + if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) { + tda8295_power(fe, 1); + if (tda829x_find_tuner(fe) < 0) + goto fail; + } + + switch (priv->ver) { + case TDA8290: + name = "tda8290"; + break; + case TDA8295: + name = "tda8295"; + break; + case TDA8290 | TDA8275: + name = "tda8290+75"; + break; + case TDA8295 | TDA8275: + name = "tda8295+75"; + break; + case TDA8290 | TDA8275A: + name = "tda8290+75a"; + break; + case TDA8295 | TDA8275A: + name = "tda8295+75a"; + break; + case TDA8290 | TDA18271: + name = "tda8290+18271"; + break; + case TDA8295 | TDA18271: + name = "tda8295+18271"; + break; + default: + goto fail; + } + tuner_info("type set to %s\n", name); + + fe->ops.analog_ops.info.name = name; + + if (priv->ver & TDA8290) { + if (priv->ver & (TDA8275 | TDA8275A)) + tda8290_init_tuner(fe); + tda8290_init_if(fe); + } else if (priv->ver & TDA8295) + tda8295_init_if(fe); + + return fe; + +fail: + memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); + + tda829x_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(tda829x_attach); + +int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) +{ + struct tuner_i2c_props i2c_props = { + .adap = i2c_adap, + .addr = i2c_addr, + }; + + unsigned char soft_reset[] = { 0x00, 0x00 }; + unsigned char easy_mode_b[] = { 0x01, 0x02 }; + unsigned char easy_mode_g[] = { 0x01, 0x04 }; + unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; + unsigned char addr_dto_lsb = 0x07; + unsigned char data; +#define PROBE_BUFFER_SIZE 8 + unsigned char buf[PROBE_BUFFER_SIZE]; + int i; + + /* rule out tda9887, which would return the same byte repeatedly */ + tuner_i2c_xfer_send_recv(&i2c_props, + soft_reset, 1, buf, PROBE_BUFFER_SIZE); + for (i = 1; i < PROBE_BUFFER_SIZE; i++) { + if (buf[i] != buf[0]) + break; + } + + /* all bytes are equal, not a tda829x - probably a tda9887 */ + if (i == PROBE_BUFFER_SIZE) + return -ENODEV; + + if ((tda8290_probe(&i2c_props) == 0) || + (tda8295_probe(&i2c_props) == 0)) + return 0; + + /* fall back to old probing method */ + tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1); + if (data == 0) { + tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send_recv(&i2c_props, + &addr_dto_lsb, 1, &data, 1); + if (data == 0x7b) { + return 0; + } + } + tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); + return -ENODEV; +} +EXPORT_SYMBOL_GPL(tda829x_probe); + +MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); +MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda8290.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda8290.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda8290.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda8290.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,56 @@ +/* + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA8290_H__ +#define __TDA8290_H__ + +#include +#include "dvb_frontend.h" + +struct tda829x_config { + unsigned int lna_cfg; + + unsigned int probe_tuner:1; +#define TDA829X_PROBE_TUNER 0 +#define TDA829X_DONT_PROBE 1 +}; + +#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE)) +extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); + +extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct tda829x_config *cfg); +#else +static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -EINVAL; +} + +static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct tda829x_config *cfg) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return NULL; +} +#endif + +#endif /* __TDA8290_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda9887.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda9887.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda9887.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda9887.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,717 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tda9887.h" + + +/* Chips: + TDA9885 (PAL, NTSC) + TDA9886 (PAL, SECAM, NTSC) + TDA9887 (PAL, SECAM, NTSC, FM Radio) + + Used as part of several tuners +*/ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static DEFINE_MUTEX(tda9887_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +struct tda9887_priv { + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + + unsigned char data[4]; + unsigned int config; + unsigned int mode; + unsigned int audmode; + v4l2_std_id std; + + bool standby; +}; + +/* ---------------------------------------------------------------------- */ + +#define UNSET (-1U) + +struct tvnorm { + v4l2_std_id std; + char *name; + unsigned char b; + unsigned char c; + unsigned char e; +}; + +/* ---------------------------------------------------------------------- */ + +// +// TDA defines +// + +//// first reg (b) +#define cVideoTrapBypassOFF 0x00 // bit b0 +#define cVideoTrapBypassON 0x01 // bit b0 + +#define cAutoMuteFmInactive 0x00 // bit b1 +#define cAutoMuteFmActive 0x02 // bit b1 + +#define cIntercarrier 0x00 // bit b2 +#define cQSS 0x04 // bit b2 + +#define cPositiveAmTV 0x00 // bit b3:4 +#define cFmRadio 0x08 // bit b3:4 +#define cNegativeFmTV 0x10 // bit b3:4 + + +#define cForcedMuteAudioON 0x20 // bit b5 +#define cForcedMuteAudioOFF 0x00 // bit b5 + +#define cOutputPort1Active 0x00 // bit b6 +#define cOutputPort1Inactive 0x40 // bit b6 + +#define cOutputPort2Active 0x00 // bit b7 +#define cOutputPort2Inactive 0x80 // bit b7 + + +//// second reg (c) +#define cDeemphasisOFF 0x00 // bit c5 +#define cDeemphasisON 0x20 // bit c5 + +#define cDeemphasis75 0x00 // bit c6 +#define cDeemphasis50 0x40 // bit c6 + +#define cAudioGain0 0x00 // bit c7 +#define cAudioGain6 0x80 // bit c7 + +#define cTopMask 0x1f // bit c0:4 +#define cTopDefault 0x10 // bit c0:4 + +//// third reg (e) +#define cAudioIF_4_5 0x00 // bit e0:1 +#define cAudioIF_5_5 0x01 // bit e0:1 +#define cAudioIF_6_0 0x02 // bit e0:1 +#define cAudioIF_6_5 0x03 // bit e0:1 + + +#define cVideoIFMask 0x1c // bit e2:4 +/* Video IF selection in TV Mode (bit B3=0) */ +#define cVideoIF_58_75 0x00 // bit e2:4 +#define cVideoIF_45_75 0x04 // bit e2:4 +#define cVideoIF_38_90 0x08 // bit e2:4 +#define cVideoIF_38_00 0x0C // bit e2:4 +#define cVideoIF_33_90 0x10 // bit e2:4 +#define cVideoIF_33_40 0x14 // bit e2:4 +#define cRadioIF_45_75 0x18 // bit e2:4 +#define cRadioIF_38_90 0x1C // bit e2:4 + +/* IF1 selection in Radio Mode (bit B3=1) */ +#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) +#define cRadioIF_41_30 0x04 // bit e2,4 + +/* Output of AFC pin in radio mode when bit E7=1 */ +#define cRadioAGC_SIF 0x00 // bit e3 +#define cRadioAGC_FM 0x08 // bit e3 + +#define cTunerGainNormal 0x00 // bit e5 +#define cTunerGainLow 0x20 // bit e5 + +#define cGating_18 0x00 // bit e6 +#define cGating_36 0x40 // bit e6 + +#define cAgcOutON 0x80 // bit e7 +#define cAgcOutOFF 0x00 // bit e7 + +/* ---------------------------------------------------------------------- */ + +static struct tvnorm tvnorms[] = { + { + .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N, + .name = "PAL-BGHN", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_5_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_PAL_I, + .name = "PAL-I", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_0 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_PAL_DK, + .name = "PAL-DK", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc, + .name = "PAL-M/Nc", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis75 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_4_5 | + cVideoIF_45_75 ), + },{ + .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, + .name = "SECAM-BGH", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cTopDefault), + .e = ( cAudioIF_5_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_SECAM_L, + .name = "SECAM-L", + .b = ( cPositiveAmTV | + cQSS ), + .c = ( cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_SECAM_LC, + .name = "SECAM-L'", + .b = ( cOutputPort2Inactive | + cPositiveAmTV | + cQSS ), + .c = ( cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_33_90 ), + },{ + .std = V4L2_STD_SECAM_DK, + .name = "SECAM-DK", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), + },{ + .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, + .name = "NTSC-M", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis75 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_4_5 | + cVideoIF_45_75 ), + },{ + .std = V4L2_STD_NTSC_M_JP, + .name = "NTSC-M-JP", + .b = ( cNegativeFmTV | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis50 | + cTopDefault), + .e = ( cGating_36 | + cAudioIF_4_5 | + cVideoIF_58_75 ), + } +}; + +static struct tvnorm radio_stereo = { + .name = "Radio Stereo", + .b = ( cFmRadio | + cQSS ), + .c = ( cDeemphasisOFF | + cAudioGain6 | + cTopDefault), + .e = ( cTunerGainLow | + cAudioIF_5_5 | + cRadioIF_38_90 ), +}; + +static struct tvnorm radio_mono = { + .name = "Radio Mono", + .b = ( cFmRadio | + cQSS ), + .c = ( cDeemphasisON | + cDeemphasis75 | + cTopDefault), + .e = ( cTunerGainLow | + cAudioIF_5_5 | + cRadioIF_38_90 ), +}; + +/* ---------------------------------------------------------------------- */ + +static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + static char *afc[16] = { + "- 12.5 kHz", + "- 37.5 kHz", + "- 62.5 kHz", + "- 87.5 kHz", + "-112.5 kHz", + "-137.5 kHz", + "-162.5 kHz", + "-187.5 kHz [min]", + "+187.5 kHz [max]", + "+162.5 kHz", + "+137.5 kHz", + "+112.5 kHz", + "+ 87.5 kHz", + "+ 62.5 kHz", + "+ 37.5 kHz", + "+ 12.5 kHz", + }; + tuner_info("read: 0x%2x\n", buf[0]); + tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); + tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); + tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); + tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); + tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); +} + +static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + static char *sound[4] = { + "AM/TV", + "FM/radio", + "FM/TV", + "FM/radio" + }; + static char *adjust[32] = { + "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9", + "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", + "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", + "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15" + }; + static char *deemph[4] = { + "no", "no", "75", "50" + }; + static char *carrier[4] = { + "4.5 MHz", + "5.5 MHz", + "6.0 MHz", + "6.5 MHz / AM" + }; + static char *vif[8] = { + "58.75 MHz", + "45.75 MHz", + "38.9 MHz", + "38.0 MHz", + "33.9 MHz", + "33.4 MHz", + "45.75 MHz + pin13", + "38.9 MHz + pin13", + }; + static char *rif[4] = { + "44 MHz", + "52 MHz", + "52 MHz", + "44 MHz", + }; + + tuner_info("write: byte B 0x%02x\n", buf[1]); + tuner_info(" B0 video mode : %s\n", + (buf[1] & 0x01) ? "video trap" : "sound trap"); + tuner_info(" B1 auto mute fm : %s\n", + (buf[1] & 0x02) ? "yes" : "no"); + tuner_info(" B2 carrier mode : %s\n", + (buf[1] & 0x04) ? "QSS" : "Intercarrier"); + tuner_info(" B3-4 tv sound/radio : %s\n", + sound[(buf[1] & 0x18) >> 3]); + tuner_info(" B5 force mute audio: %s\n", + (buf[1] & 0x20) ? "yes" : "no"); + tuner_info(" B6 output port 1 : %s\n", + (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); + tuner_info(" B7 output port 2 : %s\n", + (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); + + tuner_info("write: byte C 0x%02x\n", buf[2]); + tuner_info(" C0-4 top adjustment : %s dB\n", + adjust[buf[2] & 0x1f]); + tuner_info(" C5-6 de-emphasis : %s\n", + deemph[(buf[2] & 0x60) >> 5]); + tuner_info(" C7 audio gain : %s\n", + (buf[2] & 0x80) ? "-6" : "0"); + + tuner_info("write: byte E 0x%02x\n", buf[3]); + tuner_info(" E0-1 sound carrier : %s\n", + carrier[(buf[3] & 0x03)]); + tuner_info(" E6 l pll gating : %s\n", + (buf[3] & 0x40) ? "36" : "13"); + + if (buf[1] & 0x08) { + /* radio */ + tuner_info(" E2-4 video if : %s\n", + rif[(buf[3] & 0x0c) >> 2]); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x10) ? "fm-agc radio" : + "sif-agc radio") + : "fm radio carrier afc"); + } else { + /* video */ + tuner_info(" E2-4 video if : %s\n", + vif[(buf[3] & 0x1c) >> 2]); + tuner_info(" E5 tuner gain : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x20) ? "external" : "normal") + : ((buf[3] & 0x20) ? "minimum" : "normal")); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) ? ((buf[3] & 0x20) + ? "pin3 port, pin22 vif agc out" + : "pin22 port, pin3 vif acg ext in") + : "pin3+pin22 port"); + } + tuner_info("--\n"); +} + +/* ---------------------------------------------------------------------- */ + +static int tda9887_set_tvnorm(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + struct tvnorm *norm = NULL; + char *buf = priv->data; + int i; + + if (priv->mode == V4L2_TUNER_RADIO) { + if (priv->audmode == V4L2_TUNER_MODE_MONO) + norm = &radio_mono; + else + norm = &radio_stereo; + } else { + for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { + if (tvnorms[i].std & priv->std) { + norm = tvnorms+i; + break; + } + } + } + if (NULL == norm) { + tuner_dbg("Unsupported tvnorm entry - audio muted\n"); + return -1; + } + + tuner_dbg("configure for: %s\n", norm->name); + buf[1] = norm->b; + buf[2] = norm->c; + buf[3] = norm->e; + return 0; +} + +static unsigned int port1 = UNSET; +static unsigned int port2 = UNSET; +static unsigned int qss = UNSET; +static unsigned int adjust = UNSET; + +module_param(port1, int, 0644); +module_param(port2, int, 0644); +module_param(qss, int, 0644); +module_param(adjust, int, 0644); + +static int tda9887_set_insmod(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + + if (UNSET != port1) { + if (port1) + buf[1] |= cOutputPort1Inactive; + else + buf[1] &= ~cOutputPort1Inactive; + } + if (UNSET != port2) { + if (port2) + buf[1] |= cOutputPort2Inactive; + else + buf[1] &= ~cOutputPort2Inactive; + } + + if (UNSET != qss) { + if (qss) + buf[1] |= cQSS; + else + buf[1] &= ~cQSS; + } + + if (adjust < 0x20) { + buf[2] &= ~cTopMask; + buf[2] |= adjust; + } + return 0; +} + +static int tda9887_do_config(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + + if (priv->config & TDA9887_PORT1_ACTIVE) + buf[1] &= ~cOutputPort1Inactive; + if (priv->config & TDA9887_PORT1_INACTIVE) + buf[1] |= cOutputPort1Inactive; + if (priv->config & TDA9887_PORT2_ACTIVE) + buf[1] &= ~cOutputPort2Inactive; + if (priv->config & TDA9887_PORT2_INACTIVE) + buf[1] |= cOutputPort2Inactive; + + if (priv->config & TDA9887_QSS) + buf[1] |= cQSS; + if (priv->config & TDA9887_INTERCARRIER) + buf[1] &= ~cQSS; + + if (priv->config & TDA9887_AUTOMUTE) + buf[1] |= cAutoMuteFmActive; + if (priv->config & TDA9887_DEEMPHASIS_MASK) { + buf[2] &= ~0x60; + switch (priv->config & TDA9887_DEEMPHASIS_MASK) { + case TDA9887_DEEMPHASIS_NONE: + buf[2] |= cDeemphasisOFF; + break; + case TDA9887_DEEMPHASIS_50: + buf[2] |= cDeemphasisON | cDeemphasis50; + break; + case TDA9887_DEEMPHASIS_75: + buf[2] |= cDeemphasisON | cDeemphasis75; + break; + } + } + if (priv->config & TDA9887_TOP_SET) { + buf[2] &= ~cTopMask; + buf[2] |= (priv->config >> 8) & cTopMask; + } + if ((priv->config & TDA9887_INTERCARRIER_NTSC) && + (priv->std & V4L2_STD_NTSC)) + buf[1] &= ~cQSS; + if (priv->config & TDA9887_GATING_18) + buf[3] &= ~cGating_36; + + if (priv->mode == V4L2_TUNER_RADIO) { + if (priv->config & TDA9887_RIF_41_3) { + buf[3] &= ~cVideoIFMask; + buf[3] |= cRadioIF_41_30; + } + if (priv->config & TDA9887_GAIN_NORMAL) + buf[3] &= ~cTunerGainLow; + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int tda9887_status(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + unsigned char buf[1]; + int rc; + + memset(buf,0,sizeof(buf)); + if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) + tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); + dump_read_message(fe, buf); + return 0; +} + +static void tda9887_configure(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + int rc; + + memset(priv->data,0,sizeof(priv->data)); + tda9887_set_tvnorm(fe); + + /* A note on the port settings: + These settings tend to depend on the specifics of the board. + By default they are set to inactive (bit value 1) by this driver, + overwriting any changes made by the tvnorm. This means that it + is the responsibility of the module using the tda9887 to set + these values in case of changes in the tvnorm. + In many cases port 2 should be made active (0) when selecting + SECAM-L, and port 2 should remain inactive (1) for SECAM-L'. + + For the other standards the tda9887 application note says that + the ports should be set to active (0), but, again, that may + differ depending on the precise hardware configuration. + */ + priv->data[1] |= cOutputPort1Inactive; + priv->data[1] |= cOutputPort2Inactive; + + tda9887_do_config(fe); + tda9887_set_insmod(fe); + + if (priv->standby) + priv->data[1] |= cForcedMuteAudioON; + + tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); + if (debug > 1) + dump_write_message(fe, priv->data); + + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) + tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); + + if (debug > 2) { + msleep_interruptible(1000); + tda9887_status(fe); + } +} + +/* ---------------------------------------------------------------------- */ + +static void tda9887_tuner_status(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); +} + +static int tda9887_get_afc(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + static int AFC_BITS_2_kHz[] = { + -12500, -37500, -62500, -97500, + -112500, -137500, -162500, -187500, + 187500, 162500, 137500, 112500, + 97500 , 62500, 37500 , 12500 + }; + int afc=0; + __u8 reg = 0; + + if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) + afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; + + return afc; +} + +static void tda9887_standby(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->standby = true; + + tda9887_configure(fe); +} + +static void tda9887_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->standby = false; + priv->mode = params->mode; + priv->audmode = params->audmode; + priv->std = params->std; + tda9887_configure(fe); +} + +static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->config = *(unsigned int *)priv_cfg; + tda9887_configure(fe); + + return 0; +} + +static void tda9887_release(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + mutex_lock(&tda9887_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&tda9887_list_mutex); + + fe->analog_demod_priv = NULL; +} + +static struct analog_demod_ops tda9887_ops = { + .info = { + .name = "tda9887", + }, + .set_params = tda9887_set_params, + .standby = tda9887_standby, + .tuner_status = tda9887_tuner_status, + .get_afc = tda9887_get_afc, + .release = tda9887_release, + .set_config = tda9887_set_config, +}; + +struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr) +{ + struct tda9887_priv *priv = NULL; + int instance; + + mutex_lock(&tda9887_list_mutex); + + instance = hybrid_tuner_request_state(struct tda9887_priv, priv, + hybrid_tuner_instance_list, + i2c_adap, i2c_addr, "tda9887"); + switch (instance) { + case 0: + mutex_unlock(&tda9887_list_mutex); + return NULL; + case 1: + fe->analog_demod_priv = priv; + priv->standby = true; + tuner_info("tda988[5/6/7] found\n"); + break; + default: + fe->analog_demod_priv = priv; + break; + } + + mutex_unlock(&tda9887_list_mutex); + + memcpy(&fe->ops.analog_ops, &tda9887_ops, + sizeof(struct analog_demod_ops)); + + return fe; +} +EXPORT_SYMBOL_GPL(tda9887_attach); + +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda9887.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda9887.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda9887.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tda9887.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,38 @@ +/* + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA9887_H__ +#define __TDA9887_H__ + +#include +#include "dvb_frontend.h" + +/* ------------------------------------------------------------------------ */ +#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr); +#else +static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TDA9887_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5761.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5761.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5761.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5761.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,348 @@ +/* + * For Philips TEA5761 FM Chip + * I2C address is allways 0x20 (0x10 at 7-bit mode). + * + * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNUv2 General Public License + * + */ + +#include +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tea5761.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +struct tea5761_priv { + struct tuner_i2c_props i2c_props; + + u32 frequency; + bool standby; +}; + +/*****************************************************************************/ + +/*************************** + * TEA5761HN I2C registers * + ***************************/ + +/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */ + + /* first byte for reading */ +#define TEA5761_INTREG_IFFLAG 0x10 +#define TEA5761_INTREG_LEVFLAG 0x8 +#define TEA5761_INTREG_FRRFLAG 0x2 +#define TEA5761_INTREG_BLFLAG 0x1 + + /* second byte for reading / byte for writing */ +#define TEA5761_INTREG_IFMSK 0x10 +#define TEA5761_INTREG_LEVMSK 0x8 +#define TEA5761_INTREG_FRMSK 0x2 +#define TEA5761_INTREG_BLMSK 0x1 + +/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */ + + /* First byte */ +#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */ +#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */ + + /* Bits 0-5 for divider MSB */ + + /* Second byte */ + /* Bits 0-7 for divider LSB */ + +/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */ + + /* first byte */ + +#define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */ +#define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */ +#define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */ +#define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */ +#define TEA5761_TNCTRL_AFM 0x04 +#define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */ +#define TEA5761_TNCTRL_SNC 0x01 + + /* second byte */ + +#define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */ +#define TEA5761_TNCTRL_SSL_1 0x40 +#define TEA5761_TNCTRL_SSL_0 0x20 +#define TEA5761_TNCTRL_HLSI 0x10 +#define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */ +#define TEA5761_TNCTRL_SWP 0x04 +#define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */ +#define TEA5761_TNCTRL_AHLSI 0x01 + +/* FRQCHECK - Read: bytes 6 and 7 */ + /* First byte */ + + /* Bits 0-5 for divider MSB */ + + /* Second byte */ + /* Bits 0-7 for divider LSB */ + +/* TUNCHECK - Read: bytes 8 and 9 */ + + /* First byte */ +#define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */ +#define TEA5761_TUNCHECK_TUNTO 0x01 + + /* Second byte */ +#define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */ +#define TEA5761_TUNCHECK_LD 0x08 +#define TEA5761_TUNCHECK_STEREO 0x04 + +/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */ + + /* All zero = no test mode */ + +/* MANID - Read: bytes 12 and 13 */ + + /* First byte - should be 0x10 */ +#define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */ +#define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */ + + /* Second byte - Should be 0x2b */ + +#define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */ +#define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */ + +/* Chip ID - Read: bytes 14 and 15 */ + + /* First byte - should be 0x57 */ + + /* Second byte - should be 0x61 */ + +/*****************************************************************************/ + +#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ +static void tea5761_status_dump(unsigned char *buffer) +{ + unsigned int div, frq; + + div = ((buffer[2] & 0x3f) << 8) | buffer[3]; + + frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */ + + printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n", + frq / 1000, frq % 1000, div); +} + +/* Freq should be specifyed at 62.5 Hz */ +static int __set_radio_freq(struct dvb_frontend *fe, + unsigned int freq, + bool mono) +{ + struct tea5761_priv *priv = fe->tuner_priv; + unsigned int frq = freq; + unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; + unsigned div; + int rc; + + tuner_dbg("radio freq counter %d\n", frq); + + if (priv->standby) { + tuner_dbg("TEA5761 set to standby mode\n"); + buffer[5] |= TEA5761_TNCTRL_MU; + } else { + buffer[4] |= TEA5761_TNCTRL_PUPD_0; + } + + + if (mono) { + tuner_dbg("TEA5761 set to mono\n"); + buffer[5] |= TEA5761_TNCTRL_MST; + } else { + tuner_dbg("TEA5761 set to stereo\n"); + } + + div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15; + buffer[1] = (div >> 8) & 0x3f; + buffer[2] = div & 0xff; + + if (debug) + tea5761_status_dump(buffer); + + if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + priv->frequency = frq * 125 / 2; + + return 0; +} + +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tea5761_priv *priv = fe->analog_demod_priv; + + priv->standby = false; + + return __set_radio_freq(fe, params->frequency, + params->audmode == V4L2_TUNER_MODE_MONO); +} + +static int set_radio_sleep(struct dvb_frontend *fe) +{ + struct tea5761_priv *priv = fe->analog_demod_priv; + + priv->standby = true; + + return __set_radio_freq(fe, priv->frequency, false); +} + +static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) +{ + struct tea5761_priv *priv = fe->tuner_priv; + int rc; + + memset(buffer, 0, 16); + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) { + tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc); + return -EREMOTEIO; + } + + return 0; +} + +static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5761_priv *priv = fe->tuner_priv; + + int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); + + tuner_dbg("Signal strength: %d\n", signal); + + return signal; +} + +static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5761_priv *priv = fe->tuner_priv; + + int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO; + + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); +} + +static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) +{ + unsigned char buffer[16]; + + *status = 0; + + if (0 == tea5761_read_status(fe, buffer)) { + if (tea5761_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5761_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } + + return 0; +} + +static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[16]; + + *strength = 0; + + if (0 == tea5761_read_status(fe, buffer)) + *strength = tea5761_signal(fe, buffer); + + return 0; +} + +int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) +{ + unsigned char buffer[16]; + int rc; + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; + + if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { + printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); + return -EINVAL; + } + + if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) { + printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x." + " It is not a TEA5761\n", + buffer[13], buffer[14], buffer[15]); + return -EINVAL; + } + printk(KERN_WARNING "tea5761: TEA%02x%02x detected. " + "Manufacturer ID= 0x%02x\n", + buffer[14], buffer[15], buffer[13]); + + return 0; +} + +static int tea5761_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tea5761_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tea5761_tuner_ops = { + .info = { + .name = "tea5761", // Philips TEA5761HN FM Radio + }, + .set_analog_params = set_radio_freq, + .sleep = set_radio_sleep, + .release = tea5761_release, + .get_frequency = tea5761_get_frequency, + .get_status = tea5761_get_status, + .get_rf_strength = tea5761_get_rf_strength, +}; + +struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + struct tea5761_priv *priv = NULL; + + if (tea5761_autodetection(i2c_adap, i2c_addr) != 0) + return NULL; + + priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->tuner_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->i2c_props.name = "tea5761"; + + memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); + + return fe; +} + + +EXPORT_SYMBOL_GPL(tea5761_attach); +EXPORT_SYMBOL_GPL(tea5761_autodetection); + +MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5761.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5761.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5761.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5761.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,47 @@ +/* + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TEA5761_H__ +#define __TEA5761_H__ + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) +extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + +extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); +#else +static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TEA5761_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5767.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5767.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5767.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5767.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,475 @@ +/* + * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview + * I2C address is allways 0xC0. + * + * + * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + * + * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa + * from their contributions on DScaler. + */ + +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tea5767.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +/*****************************************************************************/ + +struct tea5767_priv { + struct tuner_i2c_props i2c_props; + u32 frequency; + struct tea5767_ctrl ctrl; +}; + +/*****************************************************************************/ + +/****************************** + * Write mode register values * + ******************************/ + +/* First register */ +#define TEA5767_MUTE 0x80 /* Mutes output */ +#define TEA5767_SEARCH 0x40 /* Activates station search */ +/* Bits 0-5 for divider MSB */ + +/* Second register */ +/* Bits 0-7 for divider LSB */ + +/* Third register */ + +/* Station search from botton to up */ +#define TEA5767_SEARCH_UP 0x80 + +/* Searches with ADC output = 10 */ +#define TEA5767_SRCH_HIGH_LVL 0x60 + +/* Searches with ADC output = 10 */ +#define TEA5767_SRCH_MID_LVL 0x40 + +/* Searches with ADC output = 5 */ +#define TEA5767_SRCH_LOW_LVL 0x20 + +/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */ +#define TEA5767_HIGH_LO_INJECT 0x10 + +/* Disable stereo */ +#define TEA5767_MONO 0x08 + +/* Disable right channel and turns to mono */ +#define TEA5767_MUTE_RIGHT 0x04 + +/* Disable left channel and turns to mono */ +#define TEA5767_MUTE_LEFT 0x02 + +#define TEA5767_PORT1_HIGH 0x01 + +/* Fourth register */ +#define TEA5767_PORT2_HIGH 0x80 +/* Chips stops working. Only I2C bus remains on */ +#define TEA5767_STDBY 0x40 + +/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */ +#define TEA5767_JAPAN_BAND 0x20 + +/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */ +#define TEA5767_XTAL_32768 0x10 + +/* Cuts weak signals */ +#define TEA5767_SOFT_MUTE 0x08 + +/* Activates high cut control */ +#define TEA5767_HIGH_CUT_CTRL 0x04 + +/* Activates stereo noise control */ +#define TEA5767_ST_NOISE_CTL 0x02 + +/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ +#define TEA5767_SRCH_IND 0x01 + +/* Fifth register */ + +/* By activating, it will use Xtal at 13 MHz as reference for divider */ +#define TEA5767_PLLREF_ENABLE 0x80 + +/* By activating, deemphasis=50, or else, deemphasis of 50us */ +#define TEA5767_DEEMPH_75 0X40 + +/***************************** + * Read mode register values * + *****************************/ + +/* First register */ +#define TEA5767_READY_FLAG_MASK 0x80 +#define TEA5767_BAND_LIMIT_MASK 0X40 +/* Bits 0-5 for divider MSB after search or preset */ + +/* Second register */ +/* Bits 0-7 for divider LSB after search or preset */ + +/* Third register */ +#define TEA5767_STEREO_MASK 0x80 +#define TEA5767_IF_CNTR_MASK 0x7f + +/* Fourth register */ +#define TEA5767_ADC_LEVEL_MASK 0xf0 + +/* should be 0 */ +#define TEA5767_CHIP_ID_MASK 0x0f + +/* Fifth register */ +/* Reserved for future extensions */ +#define TEA5767_RESERVED_MASK 0xff + +/*****************************************************************************/ + +static void tea5767_status_dump(struct tea5767_priv *priv, + unsigned char *buffer) +{ + unsigned int div, frq; + + if (TEA5767_READY_FLAG_MASK & buffer[0]) + tuner_info("Ready Flag ON\n"); + else + tuner_info("Ready Flag OFF\n"); + + if (TEA5767_BAND_LIMIT_MASK & buffer[0]) + tuner_info("Tuner at band limit\n"); + else + tuner_info("Tuner not at band limit\n"); + + div = ((buffer[0] & 0x3f) << 8) | buffer[1]; + + switch (priv->ctrl.xtal_freq) { + case TEA5767_HIGH_LO_13MHz: + frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ + break; + case TEA5767_LOW_LO_13MHz: + frq = (div * 50000 + 700000 + 225000) / 4; /* Freq in KHz */ + break; + case TEA5767_LOW_LO_32768: + frq = (div * 32768 + 700000 + 225000) / 4; /* Freq in KHz */ + break; + case TEA5767_HIGH_LO_32768: + default: + frq = (div * 32768 - 700000 - 225000) / 4; /* Freq in KHz */ + break; + } + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; + + tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n", + frq / 1000, frq % 1000, div); + + if (TEA5767_STEREO_MASK & buffer[2]) + tuner_info("Stereo\n"); + else + tuner_info("Mono\n"); + + tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); + + tuner_info("ADC Level = %d\n", + (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); + + tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); + + tuner_info("Reserved = 0x%02x\n", + (buffer[4] & TEA5767_RESERVED_MASK)); +} + +/* Freq should be specifyed at 62.5 Hz */ +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tea5767_priv *priv = fe->tuner_priv; + unsigned int frq = params->frequency; + unsigned char buffer[5]; + unsigned div; + int rc; + + tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); + + buffer[2] = 0; + + if (priv->ctrl.port1) + buffer[2] |= TEA5767_PORT1_HIGH; + + if (params->audmode == V4L2_TUNER_MODE_MONO) { + tuner_dbg("TEA5767 set to mono\n"); + buffer[2] |= TEA5767_MONO; + } else { + tuner_dbg("TEA5767 set to stereo\n"); + } + + + buffer[3] = 0; + + if (priv->ctrl.port2) + buffer[3] |= TEA5767_PORT2_HIGH; + + if (priv->ctrl.high_cut) + buffer[3] |= TEA5767_HIGH_CUT_CTRL; + + if (priv->ctrl.st_noise) + buffer[3] |= TEA5767_ST_NOISE_CTL; + + if (priv->ctrl.soft_mute) + buffer[3] |= TEA5767_SOFT_MUTE; + + if (priv->ctrl.japan_band) + buffer[3] |= TEA5767_JAPAN_BAND; + + buffer[4] = 0; + + if (priv->ctrl.deemph_75) + buffer[4] |= TEA5767_DEEMPH_75; + + if (priv->ctrl.pllref) + buffer[4] |= TEA5767_PLLREF_ENABLE; + + + /* Rounds freq to next decimal value - for 62.5 KHz step */ + /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + + switch (priv->ctrl.xtal_freq) { + case TEA5767_HIGH_LO_13MHz: + tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); + buffer[2] |= TEA5767_HIGH_LO_INJECT; + div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; + break; + case TEA5767_LOW_LO_13MHz: + tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); + + div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; + break; + case TEA5767_LOW_LO_32768: + tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); + buffer[3] |= TEA5767_XTAL_32768; + /* const 700=4000*175 Khz - to adjust freq to right value */ + div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; + break; + case TEA5767_HIGH_LO_32768: + default: + tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); + + buffer[2] |= TEA5767_HIGH_LO_INJECT; + buffer[3] |= TEA5767_XTAL_32768; + div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15; + break; + } + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; + + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + if (debug) { + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + else + tea5767_status_dump(priv, buffer); + } + + priv->frequency = frq * 125 / 2; + + return 0; +} + +static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) +{ + struct tea5767_priv *priv = fe->tuner_priv; + int rc; + + memset(buffer, 0, 5); + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + return -EREMOTEIO; + } + + return 0; +} + +static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); + + tuner_dbg("Signal strength: %d\n", signal); + + return signal; +} + +static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + int stereo = buffer[2] & TEA5767_STEREO_MASK; + + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); +} + +static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) +{ + unsigned char buffer[5]; + + *status = 0; + + if (0 == tea5767_read_status(fe, buffer)) { + if (tea5767_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5767_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } + + return 0; +} + +static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[5]; + + *strength = 0; + + if (0 == tea5767_read_status(fe, buffer)) + *strength = tea5767_signal(fe, buffer); + + return 0; +} + +static int tea5767_standby(struct dvb_frontend *fe) +{ + unsigned char buffer[5]; + struct tea5767_priv *priv = fe->tuner_priv; + unsigned div, rc; + + div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; + buffer[2] = TEA5767_PORT1_HIGH; + buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | + TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; + buffer[4] = 0; + + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + return 0; +} + +int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) +{ + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; + unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + int rc; + + if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { + printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); + return -EINVAL; + } + + /* If all bytes are the same then it's a TV tuner and not a tea5767 */ + if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && + buffer[0] == buffer[3] && buffer[0] == buffer[4]) { + printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); + return -EINVAL; + } + + /* Status bytes: + * Byte 4: bit 3:1 : CI (Chip Identification) == 0 + * bit 0 : internally set to 0 + * Byte 5: bit 7:0 : == 0 + */ + if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { + printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); + return -EINVAL; + } + + + return 0; +} + +static int tea5767_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tea5767_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + + return 0; +} + +static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); + + return 0; +} + +static struct dvb_tuner_ops tea5767_tuner_ops = { + .info = { + .name = "tea5767", // Philips TEA5767HN FM Radio + }, + + .set_analog_params = set_radio_freq, + .set_config = tea5767_set_config, + .sleep = tea5767_standby, + .release = tea5767_release, + .get_frequency = tea5767_get_frequency, + .get_status = tea5767_get_status, + .get_rf_strength = tea5767_get_rf_strength, +}; + +struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + struct tea5767_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->tuner_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->i2c_props.name = "tea5767"; + + priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; + priv->ctrl.port1 = 1; + priv->ctrl.port2 = 1; + priv->ctrl.high_cut = 1; + priv->ctrl.st_noise = 1; + priv->ctrl.japan_band = 1; + + memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); + + return fe; +} + +EXPORT_SYMBOL_GPL(tea5767_attach); +EXPORT_SYMBOL_GPL(tea5767_autodetection); + +MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5767.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5767.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5767.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tea5767.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,66 @@ +/* + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TEA5767_H__ +#define __TEA5767_H__ + +#include +#include "dvb_frontend.h" + +enum tea5767_xtal { + TEA5767_LOW_LO_32768 = 0, + TEA5767_HIGH_LO_32768 = 1, + TEA5767_LOW_LO_13MHz = 2, + TEA5767_HIGH_LO_13MHz = 3, +}; + +struct tea5767_ctrl { + unsigned int port1:1; + unsigned int port2:1; + unsigned int high_cut:1; + unsigned int st_noise:1; + unsigned int soft_mute:1; + unsigned int japan_band:1; + unsigned int deemph_75:1; + unsigned int pllref:1; + enum tea5767_xtal xtal_freq; +}; + +#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE)) +extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + +extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); +#else +static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TEA5767_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-i2c.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-i2c.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,182 @@ +/* + tuner-i2c.h - i2c interface for different tuners + + Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TUNER_I2C_H__ +#define __TUNER_I2C_H__ + +#include +#include + +struct tuner_i2c_props { + u8 addr; + struct i2c_adapter *adap; + + /* used for tuner instance management */ + int count; + char *name; +}; + +static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = 0, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, + char *obuf, int olen, + char *ibuf, int ilen) +{ + struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, + .buf = obuf, .len = olen }, + { .addr = props->addr, .flags = I2C_M_RD, + .buf = ibuf, .len = ilen } }; + int ret = i2c_transfer(props->adap, msg, 2); + + return (ret == 2) ? ilen : ret; +} + +/* Callers must declare as a global for the module: + * + * static LIST_HEAD(hybrid_tuner_instance_list); + * + * hybrid_tuner_instance_list should be the third argument + * passed into hybrid_tuner_request_state(). + * + * state structure must contain the following: + * + * struct list_head hybrid_tuner_instance_list; + * struct tuner_i2c_props i2c_props; + * + * hybrid_tuner_instance_list (both within state structure and globally) + * is only required if the driver is using hybrid_tuner_request_state + * and hybrid_tuner_release_state to manage state sharing between + * multiple instances of hybrid tuners. + */ + +#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \ + printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \ + i2cprops.adap ? \ + i2c_adapter_id(i2cprops.adap) : -1, \ + i2cprops.addr, ##arg); \ + } while (0) + +/* TO DO: convert all callers of these macros to pass in + * struct tuner_i2c_props, then remove the macro wrappers */ + +#define __tuner_warn(i2cprops, fmt, arg...) do { \ + tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \ + } while (0) + +#define __tuner_info(i2cprops, fmt, arg...) do { \ + tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \ + } while (0) + +#define __tuner_err(i2cprops, fmt, arg...) do { \ + tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \ + } while (0) + +#define __tuner_dbg(i2cprops, fmt, arg...) do { \ + if ((debug)) \ + tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \ + } while (0) + +#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg) +#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg) +#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg) +#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg) + +/****************************************************************************/ + +/* The return value of hybrid_tuner_request_state indicates the number of + * instances using this tuner object. + * + * 0 - no instances, indicates an error - kzalloc must have failed + * + * 1 - one instance, indicates that the tuner object was created successfully + * + * 2 (or more) instances, indicates that an existing tuner object was found + */ + +#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\ +({ \ + int __ret = 0; \ + list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \ + if (((i2cadap) && (state->i2c_props.adap)) && \ + ((i2c_adapter_id(state->i2c_props.adap) == \ + i2c_adapter_id(i2cadap)) && \ + (i2caddr == state->i2c_props.addr))) { \ + __tuner_info(state->i2c_props, \ + "attaching existing instance\n"); \ + state->i2c_props.count++; \ + __ret = state->i2c_props.count; \ + break; \ + } \ + } \ + if (0 == __ret) { \ + state = kzalloc(sizeof(type), GFP_KERNEL); \ + if (NULL == state) \ + goto __fail; \ + state->i2c_props.addr = i2caddr; \ + state->i2c_props.adap = i2cadap; \ + state->i2c_props.name = devname; \ + __tuner_info(state->i2c_props, \ + "creating new instance\n"); \ + list_add_tail(&state->hybrid_tuner_instance_list, &list);\ + state->i2c_props.count++; \ + __ret = state->i2c_props.count; \ + } \ +__fail: \ + __ret; \ +}) + +#define hybrid_tuner_release_state(state) \ +({ \ + int __ret; \ + state->i2c_props.count--; \ + __ret = state->i2c_props.count; \ + if (!state->i2c_props.count) { \ + __tuner_info(state->i2c_props, "destroying instance\n");\ + list_del(&state->hybrid_tuner_instance_list); \ + kfree(state); \ + } \ + __ret; \ +}) + +#define hybrid_tuner_report_instance_count(state) \ +({ \ + int __ret = 0; \ + if (state) \ + __ret = state->i2c_props.count; \ + __ret; \ +}) + +#endif /* __TUNER_I2C_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-simple.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-simple.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-simple.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-simple.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1131 @@ +/* + * i2c tv tuner chip device driver + * controls all those simple 4-control-bytes style tuners. + * + * This "tuner-simple" module was split apart from the original "tuner" module. + */ +#include +#include +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tuner-simple.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define TUNER_SIMPLE_MAX 64 +static unsigned int simple_devcount; + +static int offset; +module_param(offset, int, 0664); +MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner"); + +static unsigned int atv_input[TUNER_SIMPLE_MAX] = \ + { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; +static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \ + { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; +module_param_array(atv_input, int, NULL, 0644); +module_param_array(dtv_input, int, NULL, 0644); +MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect"); +MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect"); + +/* ---------------------------------------------------------------------- */ + +/* tv standard selection for Temic 4046 FM5 + this value takes the low bits of control byte 2 + from datasheet Rev.01, Feb.00 + standard BG I L L2 D + picture IF 38.9 38.9 38.9 33.95 38.9 + sound 1 33.4 32.9 32.4 40.45 32.4 + sound 2 33.16 + NICAM 33.05 32.348 33.05 33.05 + */ +#define TEMIC_SET_PAL_I 0x05 +#define TEMIC_SET_PAL_DK 0x09 +#define TEMIC_SET_PAL_L 0x0a /* SECAM ? */ +#define TEMIC_SET_PAL_L2 0x0b /* change IF ! */ +#define TEMIC_SET_PAL_BG 0x0c + +/* tv tuner system standard selection for Philips FQ1216ME + this value takes the low bits of control byte 2 + from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") + standard BG DK I L L` + picture carrier 38.90 38.90 38.90 38.90 33.95 + colour 34.47 34.47 34.47 34.47 38.38 + sound 1 33.40 32.40 32.90 32.40 40.45 + sound 2 33.16 - - - - + NICAM 33.05 33.05 32.35 33.05 39.80 + */ +#define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ +#define PHILIPS_SET_PAL_BGDK 0x09 +#define PHILIPS_SET_PAL_L2 0x0a +#define PHILIPS_SET_PAL_L 0x0b + +/* system switching for Philips FI1216MF MK2 + from datasheet "1996 Jul 09", + standard BG L L' + picture carrier 38.90 38.90 33.95 + colour 34.47 34.37 38.38 + sound 1 33.40 32.40 40.45 + sound 2 33.16 - - + NICAM 33.05 33.05 39.80 + */ +#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ +#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */ +#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */ + +/* Control byte */ + +#define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ +#define TUNER_RATIO_SELECT_50 0x00 +#define TUNER_RATIO_SELECT_32 0x02 +#define TUNER_RATIO_SELECT_166 0x04 +#define TUNER_RATIO_SELECT_62 0x06 + +#define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ + +/* Status byte */ + +#define TUNER_POR 0x80 +#define TUNER_FL 0x40 +#define TUNER_MODE 0x38 +#define TUNER_AFC 0x07 +#define TUNER_SIGNAL 0x07 +#define TUNER_STEREO 0x10 + +#define TUNER_PLL_LOCKED 0x40 +#define TUNER_STEREO_MK3 0x04 + +static DEFINE_MUTEX(tuner_simple_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +struct tuner_simple_priv { + unsigned int nr; + u16 last_div; + + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + + unsigned int type; + struct tunertype *tun; + + u32 frequency; + u32 bandwidth; +}; + +/* ---------------------------------------------------------------------- */ + +static int tuner_read_status(struct dvb_frontend *fe) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + unsigned char byte; + + if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1)) + return 0; + + return byte; +} + +static inline int tuner_signal(const int status) +{ + return (status & TUNER_SIGNAL) << 13; +} + +static inline int tuner_stereo(const int type, const int status) +{ + switch (type) { + case TUNER_PHILIPS_FM1216ME_MK3: + case TUNER_PHILIPS_FM1236_MK3: + case TUNER_PHILIPS_FM1256_IH3: + case TUNER_LG_NTSC_TAPE: + case TUNER_TCL_MF02GIP_5N: + return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); + case TUNER_PHILIPS_FM1216MK5: + return status | TUNER_STEREO; + default: + return status & TUNER_STEREO; + } +} + +static inline int tuner_islocked(const int status) +{ + return (status & TUNER_FL); +} + +static inline int tuner_afcstatus(const int status) +{ + return (status & TUNER_AFC) - 2; +} + + +static int simple_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int tuner_status; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + tuner_status = tuner_read_status(fe); + + *status = 0; + + if (tuner_islocked(tuner_status)) + *status = TUNER_STATUS_LOCKED; + if (tuner_stereo(priv->type, tuner_status)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); + + return 0; +} + +static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int signal; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + signal = tuner_signal(tuner_read_status(fe)); + + *strength = signal; + + tuner_dbg("Signal strength: %d\n", signal); + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static inline char *tuner_param_name(enum param_type type) +{ + char *name; + + switch (type) { + case TUNER_PARAM_TYPE_RADIO: + name = "radio"; + break; + case TUNER_PARAM_TYPE_PAL: + name = "pal"; + break; + case TUNER_PARAM_TYPE_SECAM: + name = "secam"; + break; + case TUNER_PARAM_TYPE_NTSC: + name = "ntsc"; + break; + case TUNER_PARAM_TYPE_DIGITAL: + name = "digital"; + break; + default: + name = "unknown"; + break; + } + return name; +} + +static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe, + enum param_type desired_type) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + struct tunertype *tun = priv->tun; + int i; + + for (i = 0; i < tun->count; i++) + if (desired_type == tun->params[i].type) + break; + + /* use default tuner params if desired_type not available */ + if (i == tun->count) { + tuner_dbg("desired params (%s) undefined for tuner %d\n", + tuner_param_name(desired_type), priv->type); + i = 0; + } + + tuner_dbg("using tuner params #%d (%s)\n", i, + tuner_param_name(tun->params[i].type)); + + return &tun->params[i]; +} + +static int simple_config_lookup(struct dvb_frontend *fe, + struct tuner_params *t_params, + unsigned *frequency, u8 *config, u8 *cb) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int i; + + for (i = 0; i < t_params->count; i++) { + if (*frequency > t_params->ranges[i].limit) + continue; + break; + } + if (i == t_params->count) { + tuner_dbg("frequency out of range (%d > %d)\n", + *frequency, t_params->ranges[i - 1].limit); + *frequency = t_params->ranges[--i].limit; + } + *config = t_params->ranges[i].config; + *cb = t_params->ranges[i].cb; + + tuner_dbg("freq = %d.%02d (%d), range = %d, " + "config = 0x%02x, cb = 0x%02x\n", + *frequency / 16, *frequency % 16 * 100 / 16, *frequency, + i, *config, *cb); + + return i; +} + +/* ---------------------------------------------------------------------- */ + +static void simple_set_rf_input(struct dvb_frontend *fe, + u8 *config, u8 *cb, unsigned int rf) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + switch (priv->type) { + case TUNER_PHILIPS_TUV1236D: + switch (rf) { + case 1: + *cb |= 0x08; + break; + default: + *cb &= ~0x08; + break; + } + break; + case TUNER_PHILIPS_FCV1236D: + switch (rf) { + case 1: + *cb |= 0x01; + break; + default: + *cb &= ~0x01; + break; + } + break; + default: + break; + } +} + +static int simple_std_setup(struct dvb_frontend *fe, + struct analog_parameters *params, + u8 *config, u8 *cb) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int rc; + + /* tv norm specific stuff for multi-norm tuners */ + switch (priv->type) { + case TUNER_PHILIPS_SECAM: /* FI1216MF */ + /* 0x01 -> ??? no change ??? */ + /* 0x02 -> PAL BDGHI / SECAM L */ + /* 0x04 -> ??? PAL others / SECAM others ??? */ + *cb &= ~0x03; + if (params->std & V4L2_STD_SECAM_L) + /* also valid for V4L2_STD_SECAM */ + *cb |= PHILIPS_MF_SET_STD_L; + else if (params->std & V4L2_STD_SECAM_LC) + *cb |= PHILIPS_MF_SET_STD_LC; + else /* V4L2_STD_B|V4L2_STD_GH */ + *cb |= PHILIPS_MF_SET_STD_BG; + break; + + case TUNER_TEMIC_4046FM5: + *cb &= ~0x0f; + + if (params->std & V4L2_STD_PAL_BG) { + *cb |= TEMIC_SET_PAL_BG; + + } else if (params->std & V4L2_STD_PAL_I) { + *cb |= TEMIC_SET_PAL_I; + + } else if (params->std & V4L2_STD_PAL_DK) { + *cb |= TEMIC_SET_PAL_DK; + + } else if (params->std & V4L2_STD_SECAM_L) { + *cb |= TEMIC_SET_PAL_L; + + } + break; + + case TUNER_PHILIPS_FQ1216ME: + *cb &= ~0x0f; + + if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { + *cb |= PHILIPS_SET_PAL_BGDK; + + } else if (params->std & V4L2_STD_PAL_I) { + *cb |= PHILIPS_SET_PAL_I; + + } else if (params->std & V4L2_STD_SECAM_L) { + *cb |= PHILIPS_SET_PAL_L; + + } + break; + + case TUNER_PHILIPS_FCV1236D: + /* 0x00 -> ATSC antenna input 1 */ + /* 0x01 -> ATSC antenna input 2 */ + /* 0x02 -> NTSC antenna input 1 */ + /* 0x03 -> NTSC antenna input 2 */ + *cb &= ~0x03; + if (!(params->std & V4L2_STD_ATSC)) + *cb |= 2; + break; + + case TUNER_MICROTUNE_4042FI5: + /* Set the charge pump for fast tuning */ + *config |= TUNER_CHARGE_PUMP; + break; + + case TUNER_PHILIPS_TUV1236D: + { + struct tuner_i2c_props i2c = priv->i2c_props; + /* 0x40 -> ATSC antenna input 1 */ + /* 0x48 -> ATSC antenna input 2 */ + /* 0x00 -> NTSC antenna input 1 */ + /* 0x08 -> NTSC antenna input 2 */ + u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00}; + *cb &= ~0x40; + if (params->std & V4L2_STD_ATSC) { + *cb |= 0x40; + buffer[1] = 0x04; + } + /* set to the correct mode (analog or digital) */ + i2c.addr = 0x0a; + rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2); + if (2 != rc) + tuner_warn("i2c i/o error: rc == %d " + "(should be 2)\n", rc); + rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2); + if (2 != rc) + tuner_warn("i2c i/o error: rc == %d " + "(should be 2)\n", rc); + break; + } + } + if (atv_input[priv->nr]) + simple_set_rf_input(fe, config, cb, atv_input[priv->nr]); + + return 0; +} + +static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int rc; + u8 buffer[2]; + + buffer[0] = (config & ~0x38) | 0x18; + buffer[1] = aux; + + tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]); + + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2); + if (2 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc); + + return rc == 2 ? 0 : rc; +} + +static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, + u16 div, u8 config, u8 cb) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int rc; + + switch (priv->type) { + case TUNER_LG_TDVS_H06XF: + simple_set_aux_byte(fe, config, 0x20); + break; + case TUNER_PHILIPS_FQ1216LME_MK3: + simple_set_aux_byte(fe, config, 0x60); /* External AGC */ + break; + case TUNER_MICROTUNE_4042FI5: + { + /* FIXME - this may also work for other tuners */ + unsigned long timeout = jiffies + msecs_to_jiffies(1); + u8 status_byte = 0; + + /* Wait until the PLL locks */ + for (;;) { + if (time_after(jiffies, timeout)) + return 0; + rc = tuner_i2c_xfer_recv(&priv->i2c_props, + &status_byte, 1); + if (1 != rc) { + tuner_warn("i2c i/o read error: rc == %d " + "(should be 1)\n", rc); + break; + } + if (status_byte & TUNER_PLL_LOCKED) + break; + udelay(10); + } + + /* Set the charge pump for optimized phase noise figure */ + config &= ~TUNER_CHARGE_PUMP; + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = config; + buffer[3] = cb; + tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0], buffer[1], buffer[2], buffer[3]); + + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); + if (4 != rc) + tuner_warn("i2c i/o error: rc == %d " + "(should be 4)\n", rc); + break; + } + } + + return 0; +} + +static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + switch (priv->type) { + case TUNER_TENA_9533_DI: + case TUNER_YMEC_TVF_5533MF: + tuner_dbg("This tuner doesn't have FM. " + "Most cards have a TEA5767 for FM\n"); + return 0; + case TUNER_PHILIPS_FM1216ME_MK3: + case TUNER_PHILIPS_FM1236_MK3: + case TUNER_PHILIPS_FMD1216ME_MK3: + case TUNER_PHILIPS_FMD1216MEX_MK3: + case TUNER_LG_NTSC_TAPE: + case TUNER_PHILIPS_FM1256_IH3: + case TUNER_TCL_MF02GIP_5N: + buffer[3] = 0x19; + break; + case TUNER_PHILIPS_FM1216MK5: + buffer[2] = 0x88; + buffer[3] = 0x09; + break; + case TUNER_TNF_5335MF: + buffer[3] = 0x11; + break; + case TUNER_LG_PAL_FM: + buffer[3] = 0xa5; + break; + case TUNER_THOMSON_DTT761X: + buffer[3] = 0x39; + break; + case TUNER_PHILIPS_FQ1216LME_MK3: + case TUNER_PHILIPS_FQ1236_MK5: + tuner_err("This tuner doesn't have FM\n"); + /* Set the low band for sanity, since it covers 88-108 MHz */ + buffer[3] = 0x01; + break; + case TUNER_MICROTUNE_4049FM5: + default: + buffer[3] = 0xa4; + break; + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int simple_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + u8 config, cb; + u16 div; + u8 buffer[4]; + int rc, IFPCoff, i; + enum param_type desired_type; + struct tuner_params *t_params; + + /* IFPCoff = Video Intermediate Frequency - Vif: + 940 =16*58.75 NTSC/J (Japan) + 732 =16*45.75 M/N STD + 704 =16*44 ATSC (at DVB code) + 632 =16*39.50 I U.K. + 622.4=16*38.90 B/G D/K I, L STD + 592 =16*37.00 D China + 590 =16.36.875 B Australia + 543.2=16*33.95 L' STD + 171.2=16*10.70 FM Radio (at set_radio_freq) + */ + + if (params->std == V4L2_STD_NTSC_M_JP) { + IFPCoff = 940; + desired_type = TUNER_PARAM_TYPE_NTSC; + } else if ((params->std & V4L2_STD_MN) && + !(params->std & ~V4L2_STD_MN)) { + IFPCoff = 732; + desired_type = TUNER_PARAM_TYPE_NTSC; + } else if (params->std == V4L2_STD_SECAM_LC) { + IFPCoff = 543; + desired_type = TUNER_PARAM_TYPE_SECAM; + } else { + IFPCoff = 623; + desired_type = TUNER_PARAM_TYPE_PAL; + } + + t_params = simple_tuner_params(fe, desired_type); + + i = simple_config_lookup(fe, t_params, ¶ms->frequency, + &config, &cb); + + div = params->frequency + IFPCoff + offset; + + tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, " + "Offset=%d.%02d MHz, div=%0d\n", + params->frequency / 16, params->frequency % 16 * 100 / 16, + IFPCoff / 16, IFPCoff % 16 * 100 / 16, + offset / 16, offset % 16 * 100 / 16, div); + + /* tv norm specific stuff for multi-norm tuners */ + simple_std_setup(fe, params, &config, &cb); + + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { + buffer[0] = config; + buffer[1] = cb; + buffer[2] = (div>>8) & 0x7f; + buffer[3] = div & 0xff; + } else { + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = config; + buffer[3] = cb; + } + priv->last_div = div; + if (t_params->has_tda9887) { + struct v4l2_priv_tun_config tda9887_cfg; + int tda_config = 0; + int is_secam_l = (params->std & (V4L2_STD_SECAM_L | + V4L2_STD_SECAM_LC)) && + !(params->std & ~(V4L2_STD_SECAM_L | + V4L2_STD_SECAM_LC)); + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &tda_config; + + if (params->std == V4L2_STD_SECAM_LC) { + if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) + tda_config |= TDA9887_PORT1_ACTIVE; + if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) + tda_config |= TDA9887_PORT2_ACTIVE; + } else { + if (t_params->port1_active) + tda_config |= TDA9887_PORT1_ACTIVE; + if (t_params->port2_active) + tda_config |= TDA9887_PORT2_ACTIVE; + } + if (t_params->intercarrier_mode) + tda_config |= TDA9887_INTERCARRIER; + if (is_secam_l) { + if (i == 0 && t_params->default_top_secam_low) + tda_config |= TDA9887_TOP(t_params->default_top_secam_low); + else if (i == 1 && t_params->default_top_secam_mid) + tda_config |= TDA9887_TOP(t_params->default_top_secam_mid); + else if (t_params->default_top_secam_high) + tda_config |= TDA9887_TOP(t_params->default_top_secam_high); + } else { + if (i == 0 && t_params->default_top_low) + tda_config |= TDA9887_TOP(t_params->default_top_low); + else if (i == 1 && t_params->default_top_mid) + tda_config |= TDA9887_TOP(t_params->default_top_mid); + else if (t_params->default_top_high) + tda_config |= TDA9887_TOP(t_params->default_top_high); + } + if (t_params->default_pll_gating_18) + tda_config |= TDA9887_GATING_18; + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); + } + tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0], buffer[1], buffer[2], buffer[3]); + + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); + if (4 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); + + simple_post_tune(fe, &buffer[0], div, config, cb); + + return 0; +} + +static int simple_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tunertype *tun; + struct tuner_simple_priv *priv = fe->tuner_priv; + u8 buffer[4]; + u16 div; + int rc, j; + struct tuner_params *t_params; + unsigned int freq = params->frequency; + + tun = priv->tun; + + for (j = tun->count-1; j > 0; j--) + if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) + break; + /* default t_params (j=0) will be used if desired type wasn't found */ + t_params = &tun->params[j]; + + /* Select Radio 1st IF used */ + switch (t_params->radio_if) { + case 0: /* 10.7 MHz */ + freq += (unsigned int)(10.7*16000); + break; + case 1: /* 33.3 MHz */ + freq += (unsigned int)(33.3*16000); + break; + case 2: /* 41.3 MHz */ + freq += (unsigned int)(41.3*16000); + break; + default: + tuner_warn("Unsupported radio_if value %d\n", + t_params->radio_if); + return 0; + } + + buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | + TUNER_RATIO_SELECT_50; /* 50 kHz step */ + + /* Bandswitch byte */ + simple_radio_bandswitch(fe, &buffer[0]); + + /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps + freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = + freq * (1/800) */ + div = (freq + 400) / 800; + + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { + buffer[0] = buffer[2]; + buffer[1] = buffer[3]; + buffer[2] = (div>>8) & 0x7f; + buffer[3] = div & 0xff; + } else { + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + } + + tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0], buffer[1], buffer[2], buffer[3]); + priv->last_div = div; + + if (t_params->has_tda9887) { + int config = 0; + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &config; + + if (t_params->port1_active && + !t_params->port1_fm_high_sensitivity) + config |= TDA9887_PORT1_ACTIVE; + if (t_params->port2_active && + !t_params->port2_fm_high_sensitivity) + config |= TDA9887_PORT2_ACTIVE; + if (t_params->intercarrier_mode) + config |= TDA9887_INTERCARRIER; +/* if (t_params->port1_set_for_fm_mono) + config &= ~TDA9887_PORT1_ACTIVE;*/ + if (t_params->fm_gain_normal) + config |= TDA9887_GAIN_NORMAL; + if (t_params->radio_if == 2) + config |= TDA9887_RIF_41_3; + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); + } + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); + if (4 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); + + return 0; +} + +static int simple_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = simple_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = simple_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + priv->bandwidth = 0; + + return ret; +} + +static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + switch (priv->type) { + case TUNER_PHILIPS_FMD1216ME_MK3: + case TUNER_PHILIPS_FMD1216MEX_MK3: + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && + params->frequency >= 158870000) + buf[3] |= 0x08; + break; + case TUNER_PHILIPS_TD1316: + /* determine band */ + buf[3] |= (params->frequency < 161000000) ? 1 : + (params->frequency < 444000000) ? 2 : 4; + + /* setup PLL filter */ + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + buf[3] |= 1 << 3; + break; + case TUNER_PHILIPS_TUV1236D: + case TUNER_PHILIPS_FCV1236D: + { + unsigned int new_rf; + + if (dtv_input[priv->nr]) + new_rf = dtv_input[priv->nr]; + else + switch (params->u.vsb.modulation) { + case QAM_64: + case QAM_256: + new_rf = 1; + break; + case VSB_8: + default: + new_rf = 0; + break; + } + simple_set_rf_input(fe, &buf[2], &buf[3], new_rf); + break; + } + default: + break; + } +} + +static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + /* This function returns the tuned frequency on success, 0 on error */ + struct tuner_simple_priv *priv = fe->tuner_priv; + struct tunertype *tun = priv->tun; + static struct tuner_params *t_params; + u8 config, cb; + u32 div; + int ret; + unsigned frequency = params->frequency / 62500; + + if (!tun->stepsize) { + /* tuner-core was loaded before the digital tuner was + * configured and somehow picked the wrong tuner type */ + tuner_err("attempt to treat tuner %d (%s) as digital tuner " + "without stepsize defined.\n", + priv->type, priv->tun->name); + return 0; /* failure */ + } + + t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); + ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); + if (ret < 0) + return 0; /* failure */ + + div = ((frequency + t_params->iffreq) * 62500 + offset + + tun->stepsize/2) / tun->stepsize; + + buf[0] = div >> 8; + buf[1] = div & 0xff; + buf[2] = config; + buf[3] = cb; + + simple_set_dvb(fe, buf, params); + + tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", + tun->name, div, buf[0], buf[1], buf[2], buf[3]); + + /* calculate the frequency we set it to */ + return (div * tun->stepsize) - t_params->iffreq; +} + +static int simple_dvb_calc_regs(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + u8 *buf, int buf_len) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + u32 frequency; + + if (buf_len < 5) + return -EINVAL; + + frequency = simple_dvb_configure(fe, buf+1, params); + if (frequency == 0) + return -EINVAL; + + buf[0] = priv->i2c_props.addr; + + priv->frequency = frequency; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? + params->u.ofdm.bandwidth : 0; + + return 5; +} + +static int simple_dvb_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + u32 prev_freq, prev_bw; + int ret; + u8 buf[5]; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + prev_freq = priv->frequency; + prev_bw = priv->bandwidth; + + ret = simple_dvb_calc_regs(fe, params, buf, 5); + if (ret != 5) + goto fail; + + /* put analog demod in standby when tuning digital */ + if (fe->ops.analog_ops.standby) + fe->ops.analog_ops.standby(fe); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* buf[0] contains the i2c address, but * + * we already have it in i2c_props.addr */ + ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4); + if (ret != 4) + goto fail; + + return 0; +fail: + /* calc_regs sets frequency and bandwidth. if we failed, unset them */ + priv->frequency = prev_freq; + priv->bandwidth = prev_bw; + + return ret; +} + +static int simple_init(struct dvb_frontend *fe) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + if (priv->tun->initdata) { + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = tuner_i2c_xfer_send(&priv->i2c_props, + priv->tun->initdata + 1, + priv->tun->initdata[0]); + if (ret != priv->tun->initdata[0]) + return ret; + } + + return 0; +} + +static int simple_sleep(struct dvb_frontend *fe) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + if (priv->tun->sleepdata) { + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = tuner_i2c_xfer_send(&priv->i2c_props, + priv->tun->sleepdata + 1, + priv->tun->sleepdata[0]); + if (ret != priv->tun->sleepdata[0]) + return ret; + } + + return 0; +} + +static int simple_release(struct dvb_frontend *fe) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + + mutex_lock(&tuner_simple_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&tuner_simple_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static struct dvb_tuner_ops simple_tuner_ops = { + .init = simple_init, + .sleep = simple_sleep, + .set_analog_params = simple_set_params, + .set_params = simple_dvb_set_params, + .calc_regs = simple_dvb_calc_regs, + .release = simple_release, + .get_frequency = simple_get_frequency, + .get_bandwidth = simple_get_bandwidth, + .get_status = simple_get_status, + .get_rf_strength = simple_get_rf_strength, +}; + +struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + unsigned int type) +{ + struct tuner_simple_priv *priv = NULL; + int instance; + + if (type >= tuner_count) { + printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n", + __func__, type, tuner_count-1); + return NULL; + } + + /* If i2c_adap is set, check that the tuner is at the correct address. + * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly + * by the digital demod via calc_regs. + */ + if (i2c_adap != NULL) { + u8 b[1]; + struct i2c_msg msg = { + .addr = i2c_addr, .flags = I2C_M_RD, + .buf = b, .len = 1, + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (1 != i2c_transfer(i2c_adap, &msg, 1)) + printk(KERN_WARNING "tuner-simple %d-%04x: " + "unable to probe %s, proceeding anyway.", + i2c_adapter_id(i2c_adap), i2c_addr, + tuners[type].name); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + mutex_lock(&tuner_simple_list_mutex); + + instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv, + hybrid_tuner_instance_list, + i2c_adap, i2c_addr, + "tuner-simple"); + switch (instance) { + case 0: + mutex_unlock(&tuner_simple_list_mutex); + return NULL; + case 1: + fe->tuner_priv = priv; + + priv->type = type; + priv->tun = &tuners[type]; + priv->nr = simple_devcount++; + break; + default: + fe->tuner_priv = priv; + break; + } + + mutex_unlock(&tuner_simple_list_mutex); + + memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (type != priv->type) + tuner_warn("couldn't set type to %d. Using %d (%s) instead\n", + type, priv->type, priv->tun->name); + else + tuner_info("type set to %d (%s)\n", + priv->type, priv->tun->name); + + if ((debug) || ((atv_input[priv->nr] > 0) || + (dtv_input[priv->nr] > 0))) { + if (0 == atv_input[priv->nr]) + tuner_info("tuner %d atv rf input will be " + "autoselected\n", priv->nr); + else + tuner_info("tuner %d atv rf input will be " + "set to input %d (insmod option)\n", + priv->nr, atv_input[priv->nr]); + if (0 == dtv_input[priv->nr]) + tuner_info("tuner %d dtv rf input will be " + "autoselected\n", priv->nr); + else + tuner_info("tuner %d dtv rf input will be " + "set to input %d (insmod option)\n", + priv->nr, dtv_input[priv->nr]); + } + + strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name, + sizeof(fe->ops.tuner_ops.info.name)); + + return fe; +} +EXPORT_SYMBOL_GPL(simple_tuner_attach); + +MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-simple.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-simple.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-simple.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-simple.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TUNER_SIMPLE_H__ +#define __TUNER_SIMPLE_H__ + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE)) +extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + unsigned int type); +#else +static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + unsigned int type) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __TUNER_SIMPLE_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-types.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-types.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-types.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-types.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1878 @@ +/* + * + * i2c tv tuner chip device type database. + * + */ + +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +/* + * The floats in the tuner struct are computed at compile time + * by gcc and cast back to integers. Thus we don't violate the + * "no float in kernel" rule. + * + * A tuner_range may be referenced by multiple tuner_params structs. + * There are many duplicates in here. Reusing tuner_range structs, + * rather than defining new ones for each tuner, will cut down on + * memory usage, and is preferred when possible. + * + * Each tuner_params array may contain one or more elements, one + * for each video standard. + * + * FIXME: tuner_params struct contains an element, tda988x. We must + * set this for all tuners that contain a tda988x chip, and then we + * can remove this setting from the various card structs. + * + * FIXME: Right now, all tuners are using the first tuner_params[] + * array element for analog mode. In the future, we will be merging + * similar tuner definitions together, such that each tuner definition + * will have a tuner_params struct for each available video standard. + * At that point, the tuner_params[] array element will be chosen + * based on the video standard in use. + */ + +/* The following was taken from dvb-pll.c: */ + +/* Set AGC TOP value to 103 dBuV: + * 0x80 = Control Byte + * 0x40 = 250 uA charge pump (irrelevant) + * 0x18 = Aux Byte to follow + * 0x06 = 64.5 kHz divider (irrelevant) + * 0x01 = Disable Vt (aka sleep) + * + * 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA) + * 0x50 = AGC Take over point = 103 dBuV + */ +static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; + +/* 0x04 = 166.67 kHz divider + * + * 0x80 = AGC Time constant 50ms Iagc = 9 uA + * 0x20 = AGC Take over point = 112 dBuV + */ +static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 }; + +/* 0-9 */ +/* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */ + +static struct tuner_range tuner_temic_pal_ranges[] = { + { 16 * 140.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, + { 16 * 999.99 , 0x8e, 0x01, }, +}; + +static struct tuner_params tuner_temic_pal_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_pal_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */ + +static struct tuner_range tuner_philips_pal_i_ranges[] = { + { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_pal_i_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_pal_i_ranges, + .count = ARRAY_SIZE(tuner_philips_pal_i_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */ + +static struct tuner_range tuner_philips_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 451.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_ntsc_ranges, + .count = ARRAY_SIZE(tuner_philips_ntsc_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */ + +static struct tuner_range tuner_philips_secam_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, }, + { 16 * 447.25 /*MHz*/, 0x8e, 0x97, }, + { 16 * 999.99 , 0x8e, 0x37, }, +}; + +static struct tuner_params tuner_philips_secam_params[] = { + { + .type = TUNER_PARAM_TYPE_SECAM, + .ranges = tuner_philips_secam_ranges, + .count = ARRAY_SIZE(tuner_philips_secam_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_pal_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 447.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_pal_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_pal_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */ + +static struct tuner_range tuner_temic_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, + { 16 * 999.99 , 0x8e, 0x01, }, +}; + +static struct tuner_params tuner_temic_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_temic_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_ntsc_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */ + +static struct tuner_range tuner_temic_pal_i_ranges[] = { + { 16 * 170.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x04, }, + { 16 * 999.99 , 0x8e, 0x01, }, +}; + +static struct tuner_params tuner_temic_pal_i_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_pal_i_ranges, + .count = ARRAY_SIZE(tuner_temic_pal_i_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */ + +static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_temic_4036fy5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */ + +static struct tuner_range tuner_alps_tsb_1_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 385.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_alps_tsb_1_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), + }, +}; + +/* 10-19 */ +/* ------------ TUNER_ALPS_TSBE1_PAL - TEMIC PAL ------------ */ + +static struct tuner_params tuner_alps_tsb_1_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_alps_tsb_1_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */ + +static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = { + { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 351.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_alps_tsbb5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_alps_tsb_5_pal_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSBE5_PAL - Alps PAL ------------ */ + +static struct tuner_params tuner_alps_tsbe5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_alps_tsb_5_pal_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSBC5_PAL - Alps PAL ------------ */ + +static struct tuner_params tuner_alps_tsbc5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_alps_tsb_5_pal_ranges, + .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */ + +static struct tuner_range tuner_lg_pal_ranges[] = { + { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4006fh5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */ + +static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x14, }, + { 16 * 385.25 /*MHz*/, 0x8e, 0x12, }, + { 16 * 999.99 , 0x8e, 0x11, }, +}; + +static struct tuner_params tuner_alps_tshc6_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_alps_tshc6_ntsc_ranges, + .count = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */ + +static struct tuner_range tuner_temic_pal_dk_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 456.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_pal_dk_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_pal_dk_ranges, + .count = ARRAY_SIZE(tuner_temic_pal_dk_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */ + +static struct tuner_range tuner_philips_ntsc_m_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_ntsc_m_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_ntsc_m_ranges, + .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */ + +static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = { + { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_40x6f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4006FN5_MULTI_PAL - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4006fn5_multi_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_40x6f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), + }, +}; + +/* 20-29 */ +/* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */ + +static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = { + { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 464.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4009f_5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_4009f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */ + +static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = { + { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_temic_4039fr5_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4046fm5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_40x6f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */ + +static struct tuner_params tuner_philips_pal_dk_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1216ME - Philips PAL ------------ */ + +static struct tuner_params tuner_philips_fq1216me_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + }, +}; + +/* ------------ TUNER_LG_PAL_I_FM - LGINNOTEK PAL_I ------------ */ + +static struct tuner_params tuner_lg_pal_i_fm_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_LG_PAL_I - LGINNOTEK PAL_I ------------ */ + +static struct tuner_params tuner_lg_pal_i_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */ + +static struct tuner_range tuner_lg_ntsc_fm_ranges[] = { + { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 497.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_lg_ntsc_fm_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_lg_ntsc_fm_ranges, + .count = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges), + }, +}; + +/* ------------ TUNER_LG_PAL_FM - LGINNOTEK PAL ------------ */ + +static struct tuner_params tuner_lg_pal_fm_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* ------------ TUNER_LG_PAL - LGINNOTEK PAL ------------ */ + +static struct tuner_params tuner_lg_pal_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), + }, +}; + +/* 30-39 */ +/* ------------ TUNER_TEMIC_4009FN5_MULTI_PAL_FM - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_4009f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */ + +static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 317.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_sharp_2u5jf5540_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_sharp_2u5jf5540_ntsc_ranges, + .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges), + }, +}; + +/* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */ + +static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = { + { 16 * 169 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 464 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_samsung_pal_tcpm9091pd27_ranges, + .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4106FH5 - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4106fh5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_4009f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */ + +static struct tuner_params tuner_temic_4012fy5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_pal_ranges), + }, +}; + +/* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */ + +static struct tuner_params tuner_temic_4136_fy5_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), + }, +}; + +/* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */ + +static struct tuner_range tuner_lg_new_tapc_ranges[] = { + { 16 * 170.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_lg_pal_new_tapc_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_new_tapc_ranges, + .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */ + +static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = { + { 16 * 158.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_fm1216me_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), + .cb_first_if_lower_freq = 1, + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + .port1_fm_high_sensitivity = 1, + .default_top_mid = -2, + .default_top_secam_mid = -2, + .default_top_secam_high = -2, + }, +}; + +/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */ + +static struct tuner_range tuner_fm1216mk5_pal_ranges[] = { + { 16 * 158.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 441.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 864.00 , 0xce, 0x04, }, +}; + +static struct tuner_params tuner_fm1216mk5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1216mk5_pal_ranges, + .count = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges), + .cb_first_if_lower_freq = 1, + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + .port1_fm_high_sensitivity = 1, + .default_top_mid = -2, + .default_top_secam_mid = -2, + .default_top_secam_high = -2, + }, +}; + +/* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */ + +static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_lg_new_tapc_ranges, + .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), + }, +}; + +/* 40-49 */ +/* ------------ TUNER_HITACHI_NTSC - HITACHI NTSC ------------ */ + +static struct tuner_params tuner_hitachi_ntsc_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_lg_new_tapc_ranges, + .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = { + { 16 * 140.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, }, + { 16 * 999.99 , 0x8e, 0xcf, }, +}; + +static struct tuner_params tuner_philips_pal_mk_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_pal_mk_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges), + }, +}; + +/* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */ + +static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0xa2, }, + { 16 * 451.25 /*MHz*/, 0x8e, 0x92, }, + { 16 * 999.99 , 0x8e, 0x32, }, +}; + +static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = { + { 16 * 159.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_philips_fcv1236d_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_fcv1236d_ntsc_ranges, + .count = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_philips_fcv1236d_atsc_ranges, + .count = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges), + .iffreq = 16 * 44.00, + }, +}; + +/* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */ + +static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_fm1236_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .cb_first_if_lower_freq = 1, + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port1_fm_high_sensitivity = 1, + }, +}; + +/* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */ + +static struct tuner_params tuner_philips_4in1_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + }, +}; + +/* ------------ TUNER_MICROTUNE_4049FM5 - Microtune PAL ------------ */ + +static struct tuner_params tuner_microtune_4049_fm5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_temic_4009f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), + .has_tda9887 = 1, + .port1_invert_for_secam_lc = 1, + .default_pll_gating_18 = 1, + .fm_gain_normal=1, + .radio_if = 1, /* 33.3 MHz */ + }, +}; + +/* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */ + +static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x08, }, +}; + +static struct tuner_params tuner_panasonic_vp27_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_panasonic_vp27_ntsc_ranges, + .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), + .has_tda9887 = 1, + .intercarrier_mode = 1, + .default_top_low = -3, + .default_top_mid = -3, + .default_top_high = -3, + }, +}; + +/* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */ + +static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = { + { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, +}; + +static struct tuner_params tuner_tnf_8831bgff_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tnf_8831bgff_pal_ranges, + .count = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges), + }, +}; + +/* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */ + +static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = { + { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, }, + { 16 * 457.00 /*MHz*/, 0x8e, 0x94, }, + { 16 * 999.99 , 0x8e, 0x31, }, +}; + +static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = { + { 16 * 162.00 /*MHz*/, 0x8e, 0xa1, }, + { 16 * 457.00 /*MHz*/, 0x8e, 0x91, }, + { 16 * 999.99 , 0x8e, 0x31, }, +}; + +static struct tuner_params tuner_microtune_4042fi5_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_microtune_4042fi5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_microtune_4042fi5_atsc_ranges, + .count = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges), + .iffreq = 16 * 44.00 /*MHz*/, + }, +}; + +/* 50-59 */ +/* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */ + +static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = { + { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_tcl_2002n_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tcl_2002n_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */ + +static struct tuner_params tuner_philips_fm1256_ih3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .radio_if = 1, /* 33.3 MHz */ + }, +}; + +/* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */ + +/* single range used for both ntsc and atsc */ +static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0x8e, 0x39, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, }, + { 16 * 999.99 , 0x8e, 0x3c, }, +}; + +static struct tuner_params tuner_thomson_dtt7610_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_thomson_dtt7610_ntsc_ranges, + .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_thomson_dtt7610_ntsc_ranges, + .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), + .iffreq = 16 * 44.00 /*MHz*/, + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */ + +static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x8e, 0x41, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x42, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_philips_fq1286_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_fq1286_ntsc_ranges, + .count = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges), + }, +}; + +/* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */ + +static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = { + { 16 * 170.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 450.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x08, }, +}; + +static struct tuner_params tuner_tcl_2002mb_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tcl_2002mb_pal_ranges, + .count = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 442.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x04, }, +}; + +static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_fq12_6a___mk4_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_invert_for_secam_lc = 1, + .default_top_mid = -2, + .default_top_secam_low = -2, + .default_top_secam_mid = -2, + .default_top_secam_high = -2, + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1236A_MK4 - Philips NTSC ------------ */ + +static struct tuner_params tuner_philips_fq1236a_mk4_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + }, +}; + +/* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */ + +static struct tuner_params tuner_ymec_tvf_8531mf_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_philips_ntsc_m_ranges, + .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), + }, +}; + +/* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */ + +static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_ymec_tvf_5533mf_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_ymec_tvf_5533mf_ntsc_ranges, + .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges), + }, +}; + +/* 60-69 */ +/* ------------ TUNER_THOMSON_DTT761X - THOMSON ATSC ------------ */ +/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ + +static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = { + { 16 * 145.25 /*MHz*/, 0x8e, 0x39, }, + { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, }, + { 16 * 999.99 , 0x8e, 0x3c, }, +}; + +static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = { + { 16 * 147.00 /*MHz*/, 0x8e, 0x39, }, + { 16 * 417.00 /*MHz*/, 0x8e, 0x3a, }, + { 16 * 999.99 , 0x8e, 0x3c, }, +}; + +static struct tuner_params tuner_thomson_dtt761x_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_thomson_dtt761x_ntsc_ranges, + .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), + .has_tda9887 = 1, + .fm_gain_normal = 1, + .radio_if = 2, /* 41.3 MHz */ + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_thomson_dtt761x_atsc_ranges, + .count = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges), + .iffreq = 16 * 44.00, /*MHz*/ + }, +}; + +/* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */ + +static struct tuner_range tuner_tena_9533_di_pal_ranges[] = { + { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_tena_9533_di_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tena_9533_di_pal_ranges, + .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges), + }, +}; + +/* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */ + +static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = { + { 16 * 166.25 /*MHz*/, 0x86, 0x01, }, + { 16 * 466.25 /*MHz*/, 0x86, 0x02, }, + { 16 * 999.99 , 0x86, 0x08, }, +}; + +static struct tuner_params tuner_tena_tnf_5337_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tena_tnf_5337_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = { + { 16 * 160.00 /*MHz*/, 0x86, 0x51, }, + { 16 * 442.00 /*MHz*/, 0x86, 0x52, }, + { 16 * 999.99 , 0x86, 0x54, }, +}; + +static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = { + { 16 * 143.87 /*MHz*/, 0xbc, 0x41 }, + { 16 * 158.87 /*MHz*/, 0xf4, 0x41 }, + { 16 * 329.87 /*MHz*/, 0xbc, 0x42 }, + { 16 * 441.87 /*MHz*/, 0xf4, 0x42 }, + { 16 * 625.87 /*MHz*/, 0xbc, 0x44 }, + { 16 * 803.87 /*MHz*/, 0xf4, 0x44 }, + { 16 * 999.99 , 0xfc, 0x44 }, +}; + +static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_fm_high_sensitivity = 1, + .port2_invert_for_secam_lc = 1, + .port1_set_for_fm_mono = 1, + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), + .iffreq = 16 * 36.125, /*MHz*/ + }, +}; + +static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_fm_high_sensitivity = 1, + .port2_invert_for_secam_lc = 1, + .port1_set_for_fm_mono = 1, + .radio_if = 1, + .fm_gain_normal = 1, + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), + .iffreq = 16 * 36.125, /*MHz*/ + }, +}; + +/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */ + +static struct tuner_range tuner_tua6034_ntsc_ranges[] = { + { 16 * 165.00 /*MHz*/, 0x8e, 0x01 }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x02 }, + { 16 * 999.99 , 0x8e, 0x04 }, +}; + +static struct tuner_range tuner_tua6034_atsc_ranges[] = { + { 16 * 165.00 /*MHz*/, 0xce, 0x01 }, + { 16 * 450.00 /*MHz*/, 0xce, 0x02 }, + { 16 * 999.99 , 0xce, 0x04 }, +}; + +static struct tuner_params tuner_lg_tdvs_h06xf_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tua6034_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_tua6034_atsc_ranges, + .count = ARRAY_SIZE(tuner_tua6034_atsc_ranges), + .iffreq = 16 * 44.00, + }, +}; + +/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */ + +static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = { + { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges, + .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges), + }, +}; + +/* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */ + +static struct tuner_range tuner_lg_taln_ntsc_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 373.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = { + { 16 * 150.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 425.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_lg_taln_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_lg_taln_ntsc_ranges, + .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges), + },{ + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_taln_pal_secam_ranges, + .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */ + +static struct tuner_range tuner_philips_td1316_pal_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, }, + { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, }, + { 16 * 999.99 , 0xc8, 0xa4, }, +}; + +static struct tuner_range tuner_philips_td1316_dvb_ranges[] = { + { 16 * 93.834 /*MHz*/, 0xca, 0x60, }, + { 16 * 123.834 /*MHz*/, 0xca, 0xa0, }, + { 16 * 163.834 /*MHz*/, 0xca, 0xc0, }, + { 16 * 253.834 /*MHz*/, 0xca, 0x60, }, + { 16 * 383.834 /*MHz*/, 0xca, 0xa0, }, + { 16 * 443.834 /*MHz*/, 0xca, 0xc0, }, + { 16 * 583.834 /*MHz*/, 0xca, 0x60, }, + { 16 * 793.834 /*MHz*/, 0xca, 0xa0, }, + { 16 * 999.999 , 0xca, 0xe0, }, +}; + +static struct tuner_params tuner_philips_td1316_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_td1316_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_philips_td1316_dvb_ranges, + .count = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges), + .iffreq = 16 * 36.166667 /*MHz*/, + }, +}; + +/* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */ + +static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0xce, 0x01, }, + { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x04, }, +}; + +static struct tuner_range tuner_tuv1236d_atsc_ranges[] = { + { 16 * 157.25 /*MHz*/, 0xc6, 0x41, }, + { 16 * 454.00 /*MHz*/, 0xc6, 0x42, }, + { 16 * 999.99 , 0xc6, 0x44, }, +}; + +static struct tuner_params tuner_tuv1236d_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tuv1236d_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_tuv1236d_atsc_ranges, + .count = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges), + .iffreq = 16 * 44.00, + }, +}; + +/* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */ +/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF + * but it is expected to work also with other Tenna/Ymec + * models based on TI SN 761677 chip on both PAL and NTSC + */ + +static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 471.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = { + { 16 * 169.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 469.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_params tuner_tnf_5335mf_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tnf_5335mf_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges), + }, + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tnf_5335_d_if_pal_ranges, + .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges), + }, +}; + +/* 70-79 */ +/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */ + +/* '+ 4' turns on the Low Noise Amplifier */ +static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = { + { 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, }, + { 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, }, + { 16 * 999.99 , 0xce, 0x08 + 4, }, +}; + +static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, + .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), + }, +}; + +/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */ + +static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xfe, 0x11, }, + { 16 * 442.00 /*MHz*/, 0xf6, 0x12, }, + { 16 * 999.99 , 0xf6, 0x18, }, +}; + +static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = { + { 16 * 250.00 /*MHz*/, 0xb4, 0x12, }, + { 16 * 455.00 /*MHz*/, 0xfe, 0x11, }, + { 16 * 775.50 /*MHz*/, 0xbc, 0x18, }, + { 16 * 999.99 , 0xf4, 0x18, }, +}; + +static struct tuner_params tuner_thomson_fe6600_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_thomson_fe6600_pal_ranges, + .count = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges), + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_thomson_fe6600_dvb_ranges, + .count = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges), + .iffreq = 16 * 36.125 /*MHz*/, + }, +}; + +/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */ + +/* '+ 4' turns on the Low Noise Amplifier */ +static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = { + { 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, }, + { 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, }, + { 16 * 999.99 , 0xce, 0x08 + 4, }, +}; + +static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges, + .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + }, +}; + +/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */ + +static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = { + { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_tcl_mf02gip_5n_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + +/* 80-89 */ +/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */ + +static struct tuner_params tuner_fq1216lme_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), + .cb_first_if_lower_freq = 1, /* not specified, but safe to do */ + .has_tda9887 = 1, /* TDA9886 */ + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + .default_top_low = 4, + .default_top_mid = 4, + .default_top_high = 4, + .default_top_secam_low = 4, + .default_top_secam_mid = 4, + .default_top_secam_high = 4, + }, +}; + +/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */ + +static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = { + /* The datasheet specified channel ranges and the bandswitch byte */ + /* The control byte value of 0x8e is just a guess */ + { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels 2 - B */ + { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels C - W+11 */ + { 16 * 999.99 , 0x8e, 0x08, }, /* Channels W+12 - 69 */ +}; + +static struct tuner_params tuner_partsnic_pti_5nf05_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_partsnic_pti_5nf05_ranges, + .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges), + .cb_first_if_lower_freq = 1, /* not specified but safe to do */ + }, +}; + +/* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */ + +static struct tuner_range tuner_cu1216l_ranges[] = { + { 16 * 160.25 /*MHz*/, 0xce, 0x01 }, + { 16 * 444.25 /*MHz*/, 0xce, 0x02 }, + { 16 * 999.99 , 0xce, 0x04 }, +}; + +static struct tuner_params tuner_philips_cu1216l_params[] = { + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_cu1216l_ranges, + .count = ARRAY_SIZE(tuner_cu1216l_ranges), + .iffreq = 16 * 36.125, /*MHz*/ + }, +}; + +/* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */ + +static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_sony_btf_pxn01z_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_sony_btf_pxn01z_ranges, + .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges), + }, +}; + +/* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */ + +static struct tuner_params tuner_philips_fq1236_mk5_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .has_tda9887 = 1, /* TDA9885, no FM radio */ + }, +}; + +/* --------------------------------------------------------------------- */ + +struct tunertype tuners[] = { + /* 0-9 */ + [TUNER_TEMIC_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL (4002 FH5)", + .params = tuner_temic_pal_params, + .count = ARRAY_SIZE(tuner_temic_pal_params), + }, + [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */ + .name = "Philips PAL_I (FI1246 and compatibles)", + .params = tuner_philips_pal_i_params, + .count = ARRAY_SIZE(tuner_philips_pal_i_params), + }, + [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */ + .name = "Philips NTSC (FI1236,FM1236 and compatibles)", + .params = tuner_philips_ntsc_params, + .count = ARRAY_SIZE(tuner_philips_ntsc_params), + }, + [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */ + .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", + .params = tuner_philips_secam_params, + .count = ARRAY_SIZE(tuner_philips_secam_params), + }, + [TUNER_ABSENT] = { /* Tuner Absent */ + .name = "NoTuner", + }, + [TUNER_PHILIPS_PAL] = { /* Philips PAL */ + .name = "Philips PAL_BG (FI1216 and compatibles)", + .params = tuner_philips_pal_params, + .count = ARRAY_SIZE(tuner_philips_pal_params), + }, + [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4032 FY5)", + .params = tuner_temic_ntsc_params, + .count = ARRAY_SIZE(tuner_temic_ntsc_params), + }, + [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */ + .name = "Temic PAL_I (4062 FY5)", + .params = tuner_temic_pal_i_params, + .count = ARRAY_SIZE(tuner_temic_pal_i_params), + }, + [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4036 FY5)", + .params = tuner_temic_4036fy5_ntsc_params, + .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params), + }, + [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */ + .name = "Alps HSBH1", + .params = tuner_alps_tsbh1_ntsc_params, + .count = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params), + }, + + /* 10-19 */ + [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */ + .name = "Alps TSBE1", + .params = tuner_alps_tsb_1_params, + .count = ARRAY_SIZE(tuner_alps_tsb_1_params), + }, + [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */ + .name = "Alps TSBB5", + .params = tuner_alps_tsbb5_params, + .count = ARRAY_SIZE(tuner_alps_tsbb5_params), + }, + [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */ + .name = "Alps TSBE5", + .params = tuner_alps_tsbe5_params, + .count = ARRAY_SIZE(tuner_alps_tsbe5_params), + }, + [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */ + .name = "Alps TSBC5", + .params = tuner_alps_tsbc5_params, + .count = ARRAY_SIZE(tuner_alps_tsbc5_params), + }, + [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL_BG (4006FH5)", + .params = tuner_temic_4006fh5_params, + .count = ARRAY_SIZE(tuner_temic_4006fh5_params), + }, + [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */ + .name = "Alps TSCH6", + .params = tuner_alps_tshc6_params, + .count = ARRAY_SIZE(tuner_alps_tshc6_params), + }, + [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */ + .name = "Temic PAL_DK (4016 FY5)", + .params = tuner_temic_pal_dk_params, + .count = ARRAY_SIZE(tuner_temic_pal_dk_params), + }, + [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */ + .name = "Philips NTSC_M (MK2)", + .params = tuner_philips_ntsc_m_params, + .count = ARRAY_SIZE(tuner_philips_ntsc_m_params), + }, + [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */ + .name = "Temic PAL_I (4066 FY5)", + .params = tuner_temic_4066fy5_pal_i_params, + .count = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params), + }, + [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL* auto (4006 FN5)", + .params = tuner_temic_4006fn5_multi_params, + .count = ARRAY_SIZE(tuner_temic_4006fn5_multi_params), + }, + + /* 20-29 */ + [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", + .params = tuner_temic_4009f_5_params, + .count = ARRAY_SIZE(tuner_temic_4009f_5_params), + }, + [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4039 FR5)", + .params = tuner_temic_4039fr5_params, + .count = ARRAY_SIZE(tuner_temic_4039fr5_params), + }, + [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */ + .name = "Temic PAL/SECAM multi (4046 FM5)", + .params = tuner_temic_4046fm5_params, + .count = ARRAY_SIZE(tuner_temic_4046fm5_params), + }, + [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */ + .name = "Philips PAL_DK (FI1256 and compatibles)", + .params = tuner_philips_pal_dk_params, + .count = ARRAY_SIZE(tuner_philips_pal_dk_params), + }, + [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FQ1216ME)", + .params = tuner_philips_fq1216me_params, + .count = ARRAY_SIZE(tuner_philips_fq1216me_params), + }, + [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */ + .name = "LG PAL_I+FM (TAPC-I001D)", + .params = tuner_lg_pal_i_fm_params, + .count = ARRAY_SIZE(tuner_lg_pal_i_fm_params), + }, + [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */ + .name = "LG PAL_I (TAPC-I701D)", + .params = tuner_lg_pal_i_params, + .count = ARRAY_SIZE(tuner_lg_pal_i_params), + }, + [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC+FM (TPI8NSR01F)", + .params = tuner_lg_ntsc_fm_params, + .count = ARRAY_SIZE(tuner_lg_ntsc_fm_params), + }, + [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */ + .name = "LG PAL_BG+FM (TPI8PSB01D)", + .params = tuner_lg_pal_fm_params, + .count = ARRAY_SIZE(tuner_lg_pal_fm_params), + }, + [TUNER_LG_PAL] = { /* LGINNOTEK PAL */ + .name = "LG PAL_BG (TPI8PSB11D)", + .params = tuner_lg_pal_params, + .count = ARRAY_SIZE(tuner_lg_pal_params), + }, + + /* 30-39 */ + [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */ + .name = "Temic PAL* auto + FM (4009 FN5)", + .params = tuner_temic_4009_fn5_multi_pal_fm_params, + .count = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params), + }, + [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */ + .name = "SHARP NTSC_JP (2U5JF5540)", + .params = tuner_sharp_2u5jf5540_params, + .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_params), + }, + [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */ + .name = "Samsung PAL TCPM9091PD27", + .params = tuner_samsung_pal_tcpm9091pd27_params, + .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params), + }, + [TUNER_MT2032] = { /* Microtune PAL|NTSC */ + .name = "MT20xx universal", + /* see mt20xx.c for details */ }, + [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */ + .name = "Temic PAL_BG (4106 FH5)", + .params = tuner_temic_4106fh5_params, + .count = ARRAY_SIZE(tuner_temic_4106fh5_params), + }, + [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */ + .name = "Temic PAL_DK/SECAM_L (4012 FY5)", + .params = tuner_temic_4012fy5_params, + .count = ARRAY_SIZE(tuner_temic_4012fy5_params), + }, + [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4136 FY5)", + .params = tuner_temic_4136_fy5_params, + .count = ARRAY_SIZE(tuner_temic_4136_fy5_params), + }, + [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */ + .name = "LG PAL (newer TAPC series)", + .params = tuner_lg_pal_new_tapc_params, + .count = ARRAY_SIZE(tuner_lg_pal_new_tapc_params), + }, + [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FM1216ME MK3)", + .params = tuner_fm1216me_mk3_params, + .count = ARRAY_SIZE(tuner_fm1216me_mk3_params), + }, + [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC (newer TAPC series)", + .params = tuner_lg_ntsc_new_tapc_params, + .count = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params), + }, + + /* 40-49 */ + [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */ + .name = "HITACHI V7-J180AT", + .params = tuner_hitachi_ntsc_params, + .count = ARRAY_SIZE(tuner_hitachi_ntsc_params), + }, + [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */ + .name = "Philips PAL_MK (FI1216 MK)", + .params = tuner_philips_pal_mk_params, + .count = ARRAY_SIZE(tuner_philips_pal_mk_params), + }, + [TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */ + .name = "Philips FCV1236D ATSC/NTSC dual in", + .params = tuner_philips_fcv1236d_params, + .count = ARRAY_SIZE(tuner_philips_fcv1236d_params), + .min = 16 * 53.00, + .max = 16 * 803.00, + .stepsize = 62500, + }, + [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ + .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", + .params = tuner_fm1236_mk3_params, + .count = ARRAY_SIZE(tuner_fm1236_mk3_params), + }, + [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */ + .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", + .params = tuner_philips_4in1_params, + .count = ARRAY_SIZE(tuner_philips_4in1_params), + }, + [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */ + .name = "Microtune 4049 FM5", + .params = tuner_microtune_4049_fm5_params, + .count = ARRAY_SIZE(tuner_microtune_4049_fm5_params), + }, + [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */ + .name = "Panasonic VP27s/ENGE4324D", + .params = tuner_panasonic_vp27_params, + .count = ARRAY_SIZE(tuner_panasonic_vp27_params), + }, + [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC (TAPE series)", + .params = tuner_fm1236_mk3_params, + .count = ARRAY_SIZE(tuner_fm1236_mk3_params), + }, + [TUNER_TNF_8831BGFF] = { /* Philips PAL */ + .name = "Tenna TNF 8831 BGFF)", + .params = tuner_tnf_8831bgff_params, + .count = ARRAY_SIZE(tuner_tnf_8831bgff_params), + }, + [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */ + .name = "Microtune 4042 FI5 ATSC/NTSC dual in", + .params = tuner_microtune_4042fi5_params, + .count = ARRAY_SIZE(tuner_microtune_4042fi5_params), + .min = 16 * 57.00, + .max = 16 * 858.00, + .stepsize = 62500, + }, + + /* 50-59 */ + [TUNER_TCL_2002N] = { /* TCL NTSC */ + .name = "TCL 2002N", + .params = tuner_tcl_2002n_params, + .count = ARRAY_SIZE(tuner_tcl_2002n_params), + }, + [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */ + .name = "Philips PAL/SECAM_D (FM 1256 I-H3)", + .params = tuner_philips_fm1256_ih3_params, + .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_params), + }, + [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ + .name = "Thomson DTT 7610 (ATSC/NTSC)", + .params = tuner_thomson_dtt7610_params, + .count = ARRAY_SIZE(tuner_thomson_dtt7610_params), + .min = 16 * 44.00, + .max = 16 * 958.00, + .stepsize = 62500, + }, + [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */ + .name = "Philips FQ1286", + .params = tuner_philips_fq1286_params, + .count = ARRAY_SIZE(tuner_philips_fq1286_params), + }, + [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ + .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", + /* see tda8290.c for details */ }, + [TUNER_TCL_2002MB] = { /* TCL PAL */ + .name = "TCL 2002MB", + .params = tuner_tcl_2002mb_params, + .count = ARRAY_SIZE(tuner_tcl_2002mb_params), + }, + [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FQ1216AME MK4)", + .params = tuner_philips_fq1216ame_mk4_params, + .count = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params), + }, + [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */ + .name = "Philips FQ1236A MK4", + .params = tuner_philips_fq1236a_mk4_params, + .count = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params), + }, + [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */ + .name = "Ymec TVision TVF-8531MF/8831MF/8731MF", + .params = tuner_ymec_tvf_8531mf_params, + .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params), + }, + [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */ + .name = "Ymec TVision TVF-5533MF", + .params = tuner_ymec_tvf_5533mf_params, + .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params), + }, + + /* 60-69 */ + [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */ + /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ + .name = "Thomson DTT 761X (ATSC/NTSC)", + .params = tuner_thomson_dtt761x_params, + .count = ARRAY_SIZE(tuner_thomson_dtt761x_params), + .min = 16 * 57.00, + .max = 16 * 863.00, + .stepsize = 62500, + .initdata = tua603x_agc103, + }, + [TUNER_TENA_9533_DI] = { /* Philips PAL */ + .name = "Tena TNF9533-D/IF/TNF9533-B/DF", + .params = tuner_tena_9533_di_params, + .count = ARRAY_SIZE(tuner_tena_9533_di_params), + }, + [TUNER_TEA5767] = { /* Philips RADIO */ + .name = "Philips TEA5767HN FM Radio", + /* see tea5767.c for details */ + }, + [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */ + .name = "Philips FMD1216ME MK3 Hybrid Tuner", + .params = tuner_philips_fmd1216me_mk3_params, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params), + .min = 16 * 50.87, + .max = 16 * 858.00, + .stepsize = 166667, + .initdata = tua603x_agc112, + .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, + }, + [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */ + .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */ + .params = tuner_lg_tdvs_h06xf_params, + .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params), + .min = 16 * 54.00, + .max = 16 * 863.00, + .stepsize = 62500, + .initdata = tua603x_agc103, + }, + [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */ + .name = "Ymec TVF66T5-B/DFF", + .params = tuner_ymec_tvf66t5_b_dff_params, + .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params), + }, + [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */ + .name = "LG TALN series", + .params = tuner_lg_taln_params, + .count = ARRAY_SIZE(tuner_lg_taln_params), + }, + [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ + .name = "Philips TD1316 Hybrid Tuner", + .params = tuner_philips_td1316_params, + .count = ARRAY_SIZE(tuner_philips_td1316_params), + .min = 16 * 87.00, + .max = 16 * 895.00, + .stepsize = 166667, + }, + [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */ + .name = "Philips TUV1236D ATSC/NTSC dual in", + .params = tuner_tuv1236d_params, + .count = ARRAY_SIZE(tuner_tuv1236d_params), + .min = 16 * 54.00, + .max = 16 * 864.00, + .stepsize = 62500, + }, + [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */ + .name = "Tena TNF 5335 and similar models", + .params = tuner_tnf_5335mf_params, + .count = ARRAY_SIZE(tuner_tnf_5335mf_params), + }, + + /* 70-79 */ + [TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */ + .name = "Samsung TCPN 2121P30A", + .params = tuner_samsung_tcpn_2121p30a_params, + .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), + }, + [TUNER_XC2028] = { /* Xceive 2028 */ + .name = "Xceive xc2028/xc3028 tuner", + /* see tuner-xc2028.c for details */ + }, + [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ + .name = "Thomson FE6600", + .params = tuner_thomson_fe6600_params, + .count = ARRAY_SIZE(tuner_thomson_fe6600_params), + .min = 16 * 44.25, + .max = 16 * 858.00, + .stepsize = 166667, + }, + [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */ + .name = "Samsung TCPG 6121P30A", + .params = tuner_samsung_tcpg_6121p30a_params, + .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params), + }, + [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator. + This chip is part of some modern tuners */ + .name = "Philips TDA988[5,6,7] IF PLL Demodulator", + /* see tda9887.c for details */ + }, + [TUNER_TEA5761] = { /* Philips RADIO */ + .name = "Philips TEA5761 FM Radio", + /* see tea5767.c for details */ + }, + [TUNER_XC5000] = { /* Xceive 5000 */ + .name = "Xceive 5000 tuner", + /* see xc5000.c for details */ + }, + [TUNER_XC4000] = { /* Xceive 4000 */ + .name = "Xceive 4000 tuner", + /* see xc4000.c for details */ + }, + [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */ + .name = "TCL tuner MF02GIP-5N-E", + .params = tuner_tcl_mf02gip_5n_params, + .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params), + }, + [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */ + .name = "Philips FMD1216MEX MK3 Hybrid Tuner", + .params = tuner_philips_fmd1216mex_mk3_params, + .count = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params), + .min = 16 * 50.87, + .max = 16 * 858.00, + .stepsize = 166667, + .initdata = tua603x_agc112, + .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, + }, + [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FM1216 MK5)", + .params = tuner_fm1216mk5_params, + .count = ARRAY_SIZE(tuner_fm1216mk5_params), + }, + + /* 80-89 */ + [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */ + .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough", + .params = tuner_fq1216lme_mk3_params, + .count = ARRAY_SIZE(tuner_fq1216lme_mk3_params), + }, + + [TUNER_PARTSNIC_PTI_5NF05] = { + .name = "Partsnic (Daewoo) PTI-5NF05", + .params = tuner_partsnic_pti_5nf05_params, + .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params), + }, + [TUNER_PHILIPS_CU1216L] = { + .name = "Philips CU1216L", + .params = tuner_philips_cu1216l_params, + .count = ARRAY_SIZE(tuner_philips_cu1216l_params), + .stepsize = 62500, + }, + [TUNER_NXP_TDA18271] = { + .name = "NXP TDA18271", + /* see tda18271-fe.c for details */ + }, + [TUNER_SONY_BTF_PXN01Z] = { + .name = "Sony BTF-Pxn01Z", + .params = tuner_sony_btf_pxn01z_params, + .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params), + }, + [TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */ + .name = "Philips FQ1236 MK5", + .params = tuner_philips_fq1236_mk5_params, + .count = ARRAY_SIZE(tuner_philips_fq1236_mk5_params), + }, + [TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */ + .name = "Tena TNF5337 MFD", + .params = tuner_tena_tnf_5337_params, + .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), + }, +}; +EXPORT_SYMBOL(tuners); + +unsigned const int tuner_count = ARRAY_SIZE(tuners); +EXPORT_SYMBOL(tuner_count); + +MODULE_DESCRIPTION("Simple tuner device type database"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1356 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) + * + * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) + * - frontend interface + * + * This code is placed under the terms of the GNU General Public License v2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tuner-i2c.h" +#include "tuner-xc2028.h" +#include "tuner-xc2028-types.h" + +#include +#include "dvb_frontend.h" + + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static int no_poweroff; +module_param(no_poweroff, int, 0644); +MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" + "1 keep device energized and with tuner ready all the times.\n" + " Faster, but consumes more power and keeps the device hotter\n"); + +static char audio_std[8]; +module_param_string(audio_std, audio_std, sizeof(audio_std), 0); +MODULE_PARM_DESC(audio_std, + "Audio standard. XC3028 audio decoder explicitly " + "needs to know what audio\n" + "standard is needed for some video standards with audio A2 or NICAM.\n" + "The valid values are:\n" + "A2\n" + "A2/A\n" + "A2/B\n" + "NICAM\n" + "NICAM/A\n" + "NICAM/B\n"); + +static char firmware_name[30]; +module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); +MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " + "default firmware name\n"); + +static LIST_HEAD(hybrid_tuner_instance_list); +static DEFINE_MUTEX(xc2028_list_mutex); + +/* struct for storing firmware table */ +struct firmware_description { + unsigned int type; + v4l2_std_id id; + __u16 int_freq; + unsigned char *ptr; + unsigned int size; +}; + +struct firmware_properties { + unsigned int type; + v4l2_std_id id; + v4l2_std_id std_req; + __u16 int_freq; + unsigned int scode_table; + int scode_nr; +}; + +struct xc2028_data { + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + __u32 frequency; + + struct firmware_description *firm; + int firm_size; + __u16 firm_version; + + __u16 hwmodel; + __u16 hwvers; + + struct xc2028_ctrl ctrl; + + struct firmware_properties cur_fw; + + struct mutex lock; +}; + +#define i2c_send(priv, buf, size) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ + if (size != _rc) \ + tuner_info("i2c output error: rc = %d (should be %d)\n",\ + _rc, (int)size); \ + if (priv->ctrl.msleep) \ + msleep(priv->ctrl.msleep); \ + _rc; \ +}) + +#define i2c_rcv(priv, buf, size) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ + if (size != _rc) \ + tuner_err("i2c input error: rc = %d (should be %d)\n", \ + _rc, (int)size); \ + _rc; \ +}) + +#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ + ibuf, isize); \ + if (isize != _rc) \ + tuner_err("i2c input error: rc = %d (should be %d)\n", \ + _rc, (int)isize); \ + if (priv->ctrl.msleep) \ + msleep(priv->ctrl.msleep); \ + _rc; \ +}) + +#define send_seq(priv, data...) ({ \ + static u8 _val[] = data; \ + int _rc; \ + if (sizeof(_val) != \ + (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ + _val, sizeof(_val)))) { \ + tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ + } else if (priv->ctrl.msleep) \ + msleep(priv->ctrl.msleep); \ + _rc; \ +}) + +static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) +{ + unsigned char buf[2]; + unsigned char ibuf[2]; + + tuner_dbg("%s %04x called\n", __func__, reg); + + buf[0] = reg >> 8; + buf[1] = (unsigned char) reg; + + if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) + return -EIO; + + *val = (ibuf[1]) | (ibuf[0] << 8); + return 0; +} + +#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) +static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) +{ + if (type & BASE) + printk("BASE "); + if (type & INIT1) + printk("INIT1 "); + if (type & F8MHZ) + printk("F8MHZ "); + if (type & MTS) + printk("MTS "); + if (type & D2620) + printk("D2620 "); + if (type & D2633) + printk("D2633 "); + if (type & DTV6) + printk("DTV6 "); + if (type & QAM) + printk("QAM "); + if (type & DTV7) + printk("DTV7 "); + if (type & DTV78) + printk("DTV78 "); + if (type & DTV8) + printk("DTV8 "); + if (type & FM) + printk("FM "); + if (type & INPUT1) + printk("INPUT1 "); + if (type & LCD) + printk("LCD "); + if (type & NOGD) + printk("NOGD "); + if (type & MONO) + printk("MONO "); + if (type & ATSC) + printk("ATSC "); + if (type & IF) + printk("IF "); + if (type & LG60) + printk("LG60 "); + if (type & ATI638) + printk("ATI638 "); + if (type & OREN538) + printk("OREN538 "); + if (type & OREN36) + printk("OREN36 "); + if (type & TOYOTA388) + printk("TOYOTA388 "); + if (type & TOYOTA794) + printk("TOYOTA794 "); + if (type & DIBCOM52) + printk("DIBCOM52 "); + if (type & ZARLINK456) + printk("ZARLINK456 "); + if (type & CHINA) + printk("CHINA "); + if (type & F6MHZ) + printk("F6MHZ "); + if (type & INPUT2) + printk("INPUT2 "); + if (type & SCODE) + printk("SCODE "); + if (type & HAS_IF) + printk("HAS_IF_%d ", int_freq); +} + +static v4l2_std_id parse_audio_std_option(void) +{ + if (strcasecmp(audio_std, "A2") == 0) + return V4L2_STD_A2; + if (strcasecmp(audio_std, "A2/A") == 0) + return V4L2_STD_A2_A; + if (strcasecmp(audio_std, "A2/B") == 0) + return V4L2_STD_A2_B; + if (strcasecmp(audio_std, "NICAM") == 0) + return V4L2_STD_NICAM; + if (strcasecmp(audio_std, "NICAM/A") == 0) + return V4L2_STD_NICAM_A; + if (strcasecmp(audio_std, "NICAM/B") == 0) + return V4L2_STD_NICAM_B; + + return 0; +} + +static void free_firmware(struct xc2028_data *priv) +{ + int i; + tuner_dbg("%s called\n", __func__); + + if (!priv->firm) + return; + + for (i = 0; i < priv->firm_size; i++) + kfree(priv->firm[i].ptr); + + kfree(priv->firm); + + priv->firm = NULL; + priv->firm_size = 0; + + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); +} + +static int load_all_firmwares(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + const struct firmware *fw = NULL; + const unsigned char *p, *endp; + int rc = 0; + int n, n_array; + char name[33]; + char *fname; + + tuner_dbg("%s called\n", __func__); + + if (!firmware_name[0]) + fname = priv->ctrl.fname; + else + fname = firmware_name; + + tuner_dbg("Reading firmware %s\n", fname); + rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); + if (rc < 0) { + if (rc == -ENOENT) + tuner_err("Error: firmware %s not found.\n", + fname); + else + tuner_err("Error %d while requesting firmware %s \n", + rc, fname); + + return rc; + } + p = fw->data; + endp = p + fw->size; + + if (fw->size < sizeof(name) - 1 + 2 + 2) { + tuner_err("Error: firmware file %s has invalid size!\n", + fname); + goto corrupt; + } + + memcpy(name, p, sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + p += sizeof(name) - 1; + + priv->firm_version = get_unaligned_le16(p); + p += 2; + + n_array = get_unaligned_le16(p); + p += 2; + + tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", + n_array, fname, name, + priv->firm_version >> 8, priv->firm_version & 0xff); + + priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); + if (priv->firm == NULL) { + tuner_err("Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto err; + } + priv->firm_size = n_array; + + n = -1; + while (p < endp) { + __u32 type, size; + v4l2_std_id id; + __u16 int_freq = 0; + + n++; + if (n >= n_array) { + tuner_err("More firmware images in file than " + "were expected!\n"); + goto corrupt; + } + + /* Checks if there's enough bytes to read */ + if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) + goto header; + + type = get_unaligned_le32(p); + p += sizeof(type); + + id = get_unaligned_le64(p); + p += sizeof(id); + + if (type & HAS_IF) { + int_freq = get_unaligned_le16(p); + p += sizeof(int_freq); + if (endp - p < sizeof(size)) + goto header; + } + + size = get_unaligned_le32(p); + p += sizeof(size); + + if (!size || size > endp - p) { + tuner_err("Firmware type "); + dump_firm_type(type); + printk("(%x), id %llx is corrupted " + "(size=%d, expected %d)\n", + type, (unsigned long long)id, + (unsigned)(endp - p), size); + goto corrupt; + } + + priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); + if (priv->firm[n].ptr == NULL) { + tuner_err("Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto err; + } + tuner_dbg("Reading firmware type "); + if (debug) { + dump_firm_type_and_int_freq(type, int_freq); + printk("(%x), id %llx, size=%d.\n", + type, (unsigned long long)id, size); + } + + memcpy(priv->firm[n].ptr, p, size); + priv->firm[n].type = type; + priv->firm[n].id = id; + priv->firm[n].size = size; + priv->firm[n].int_freq = int_freq; + + p += size; + } + + if (n + 1 != priv->firm_size) { + tuner_err("Firmware file is incomplete!\n"); + goto corrupt; + } + + goto done; + +header: + tuner_err("Firmware header is incomplete!\n"); +corrupt: + rc = -EINVAL; + tuner_err("Error: firmware file is corrupted!\n"); + +err: + tuner_info("Releasing partially loaded firmware file.\n"); + free_firmware(priv); + +done: + release_firmware(fw); + if (rc == 0) + tuner_dbg("Firmware files loaded.\n"); + + return rc; +} + +static int seek_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int i, best_i = -1, best_nr_matches = 0; + unsigned int type_mask = 0; + + tuner_dbg("%s called, want type=", __func__); + if (debug) { + dump_firm_type(type); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + } + + if (!priv->firm) { + tuner_err("Error! firmware not loaded\n"); + return -EINVAL; + } + + if (((type & ~SCODE) == 0) && (*id == 0)) + *id = V4L2_STD_PAL; + + if (type & BASE) + type_mask = BASE_TYPES; + else if (type & SCODE) { + type &= SCODE_TYPES; + type_mask = SCODE_TYPES & ~HAS_IF; + } else if (type & DTV_TYPES) + type_mask = DTV_TYPES; + else if (type & STD_SPECIFIC_TYPES) + type_mask = STD_SPECIFIC_TYPES; + + type &= type_mask; + + if (!(type & SCODE)) + type_mask = ~0; + + /* Seek for exact match */ + for (i = 0; i < priv->firm_size; i++) { + if ((type == (priv->firm[i].type & type_mask)) && + (*id == priv->firm[i].id)) + goto found; + } + + /* Seek for generic video standard match */ + for (i = 0; i < priv->firm_size; i++) { + v4l2_std_id match_mask; + int nr_matches; + + if (type != (priv->firm[i].type & type_mask)) + continue; + + match_mask = *id & priv->firm[i].id; + if (!match_mask) + continue; + + if ((*id & match_mask) == *id) + goto found; /* Supports all the requested standards */ + + nr_matches = hweight64(match_mask); + if (nr_matches > best_nr_matches) { + best_nr_matches = nr_matches; + best_i = i; + } + } + + if (best_nr_matches > 0) { + tuner_dbg("Selecting best matching firmware (%d bits) for " + "type=", best_nr_matches); + dump_firm_type(type); + printk("(%x), id %016llx:\n", type, (unsigned long long)*id); + i = best_i; + goto found; + } + + /*FIXME: Would make sense to seek for type "hint" match ? */ + + i = -ENOENT; + goto ret; + +found: + *id = priv->firm[i].id; + +ret: + tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); + if (debug) { + dump_firm_type(type); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + } + return i; +} + +static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg) +{ + struct xc2028_data *priv = fe->tuner_priv; + + /* analog side (tuner-core) uses i2c_adap->algo_data. + * digital side is not guaranteed to have algo_data defined. + * + * digital side will always have fe->dvb defined. + * analog side (tuner-core) doesn't (yet) define fe->dvb. + */ + + return (!fe->callback) ? -EINVAL : + fe->callback(((fe->dvb) && (fe->dvb->priv)) ? + fe->dvb->priv : priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, cmd, arg); +} + +static int load_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p, *endp, buf[priv->ctrl.max_len]; + + tuner_dbg("%s called\n", __func__); + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + tuner_info("Loading firmware for type="); + dump_firm_type(priv->firm[pos].type); + printk("(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + + p = priv->firm[pos].ptr; + endp = p + priv->firm[pos].size; + + while (p < endp) { + __u16 size; + + /* Checks if there's enough bytes to read */ + if (p + sizeof(size) > endp) { + tuner_err("Firmware chunk size is wrong\n"); + return -EINVAL; + } + + size = le16_to_cpu(*(__u16 *) p); + p += sizeof(size); + + if (size == 0xffff) + return 0; + + if (!size) { + /* Special callback command received */ + rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); + if (rc < 0) { + tuner_err("Error at RESET code %d\n", + (*p) & 0x7f); + return -EINVAL; + } + continue; + } + if (size >= 0xff00) { + switch (size) { + case 0xff00: + rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0); + if (rc < 0) { + tuner_err("Error at RESET code %d\n", + (*p) & 0x7f); + return -EINVAL; + } + break; + default: + tuner_info("Invalid RESET code %d\n", + size & 0x7f); + return -EINVAL; + + } + continue; + } + + /* Checks for a sleep command */ + if (size & 0x8000) { + msleep(size & 0x7fff); + continue; + } + + if ((size + p > endp)) { + tuner_err("missing bytes: need %d, have %d\n", + size, (int)(endp - p)); + return -EINVAL; + } + + buf[0] = *p; + p++; + size--; + + /* Sends message chunks */ + while (size > 0) { + int len = (size < priv->ctrl.max_len - 1) ? + size : priv->ctrl.max_len - 1; + + memcpy(buf + 1, p, len); + + rc = i2c_send(priv, buf, len + 1); + if (rc < 0) { + tuner_err("%d returned from send\n", rc); + return -EINVAL; + } + + p += len; + size -= len; + } + } + return 0; +} + +static int load_scode(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id, __u16 int_freq, int scode) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + + tuner_dbg("%s called\n", __func__); + + if (!int_freq) { + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + } else { + for (pos = 0; pos < priv->firm_size; pos++) { + if ((priv->firm[pos].int_freq == int_freq) && + (priv->firm[pos].type & HAS_IF)) + break; + } + if (pos == priv->firm_size) + return -ENOENT; + } + + p = priv->firm[pos].ptr; + + if (priv->firm[pos].type & HAS_IF) { + if (priv->firm[pos].size != 12 * 16 || scode >= 16) + return -EINVAL; + p += 12 * scode; + } else { + /* 16 SCODE entries per file; each SCODE entry is 12 bytes and + * has a 2-byte size header in the firmware format. */ + if (priv->firm[pos].size != 14 * 16 || scode >= 16 || + le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) + return -EINVAL; + p += 14 * scode + 2; + } + + tuner_info("Loading SCODE for type="); + dump_firm_type_and_int_freq(priv->firm[pos].type, + priv->firm[pos].int_freq); + printk("(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); + else + rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); + if (rc < 0) + return -EIO; + + rc = i2c_send(priv, p, 12); + if (rc < 0) + return -EIO; + + rc = send_seq(priv, {0x00, 0x8c}); + if (rc < 0) + return -EIO; + + return 0; +} + +static int check_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id std, __u16 int_freq) +{ + struct xc2028_data *priv = fe->tuner_priv; + struct firmware_properties new_fw; + int rc = 0, retry_count = 0; + u16 version, hwmodel; + v4l2_std_id std0; + + tuner_dbg("%s called\n", __func__); + + if (!priv->firm) { + if (!priv->ctrl.fname) { + tuner_info("xc2028/3028 firmware name not set!\n"); + return -EINVAL; + } + + rc = load_all_firmwares(fe); + if (rc < 0) + return rc; + } + + if (priv->ctrl.mts && !(type & FM)) + type |= MTS; + +retry: + new_fw.type = type; + new_fw.id = std; + new_fw.std_req = std; + new_fw.scode_table = SCODE | priv->ctrl.scode_table; + new_fw.scode_nr = 0; + new_fw.int_freq = int_freq; + + tuner_dbg("checking firmware, user requested type="); + if (debug) { + dump_firm_type(new_fw.type); + printk("(%x), id %016llx, ", new_fw.type, + (unsigned long long)new_fw.std_req); + if (!int_freq) { + printk("scode_tbl "); + dump_firm_type(priv->ctrl.scode_table); + printk("(%x), ", priv->ctrl.scode_table); + } else + printk("int_freq %d, ", new_fw.int_freq); + printk("scode_nr %d\n", new_fw.scode_nr); + } + + /* No need to reload base firmware if it matches */ + if (((BASE | new_fw.type) & BASE_TYPES) == + (priv->cur_fw.type & BASE_TYPES)) { + tuner_dbg("BASE firmware not changed.\n"); + goto skip_base; + } + + /* Updating BASE - forget about all currently loaded firmware */ + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + + /* Reset is needed before loading firmware */ + rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); + if (rc < 0) + goto fail; + + /* BASE firmwares are all std0 */ + std0 = 0; + rc = load_firmware(fe, BASE | new_fw.type, &std0); + if (rc < 0) { + tuner_err("Error %d while loading base firmware\n", + rc); + goto fail; + } + + /* Load INIT1, if needed */ + tuner_dbg("Load init1 firmware, if exists\n"); + + rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); + if (rc == -ENOENT) + rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, + &std0); + if (rc < 0 && rc != -ENOENT) { + tuner_err("Error %d while loading init1 firmware\n", + rc); + goto fail; + } + +skip_base: + /* + * No need to reload standard specific firmware if base firmware + * was not reloaded and requested video standards have not changed. + */ + if (priv->cur_fw.type == (BASE | new_fw.type) && + priv->cur_fw.std_req == std) { + tuner_dbg("Std-specific firmware already loaded.\n"); + goto skip_std_specific; + } + + /* Reloading std-specific firmware forces a SCODE update */ + priv->cur_fw.scode_table = 0; + + rc = load_firmware(fe, new_fw.type, &new_fw.id); + if (rc == -ENOENT) + rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); + + if (rc < 0) + goto fail; + +skip_std_specific: + if (priv->cur_fw.scode_table == new_fw.scode_table && + priv->cur_fw.scode_nr == new_fw.scode_nr) { + tuner_dbg("SCODE firmware already loaded.\n"); + goto check_device; + } + + if (new_fw.type & FM) + goto check_device; + + /* Load SCODE firmware, if exists */ + tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); + + rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, + new_fw.int_freq, new_fw.scode_nr); + +check_device: + if (xc2028_get_reg(priv, 0x0004, &version) < 0 || + xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { + tuner_err("Unable to read tuner registers.\n"); + goto fail; + } + + tuner_dbg("Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, + (version & 0xf0) >> 4, version & 0xf); + + + if (priv->ctrl.read_not_reliable) + goto read_not_reliable; + + /* Check firmware version against what we downloaded. */ + if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { + if (!priv->ctrl.read_not_reliable) { + tuner_err("Incorrect readback of firmware version.\n"); + goto fail; + } else { + tuner_err("Returned an incorrect version. However, " + "read is not reliable enough. Ignoring it.\n"); + hwmodel = 3028; + } + } + + /* Check that the tuner hardware model remains consistent over time. */ + if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { + priv->hwmodel = hwmodel; + priv->hwvers = version & 0xff00; + } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || + priv->hwvers != (version & 0xff00)) { + tuner_err("Read invalid device hardware information - tuner " + "hung?\n"); + goto fail; + } + +read_not_reliable: + memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); + + /* + * By setting BASE in cur_fw.type only after successfully loading all + * firmwares, we can: + * 1. Identify that BASE firmware with type=0 has been loaded; + * 2. Tell whether BASE firmware was just changed the next time through. + */ + priv->cur_fw.type |= BASE; + + return 0; + +fail: + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + if (retry_count < 8) { + msleep(50); + retry_count++; + tuner_dbg("Retrying firmware load\n"); + goto retry; + } + + if (rc == -ENOENT) + rc = -EINVAL; + return rc; +} + +static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) +{ + struct xc2028_data *priv = fe->tuner_priv; + u16 frq_lock, signal = 0; + int rc; + + tuner_dbg("%s called\n", __func__); + + mutex_lock(&priv->lock); + + /* Sync Lock Indicator */ + rc = xc2028_get_reg(priv, 0x0002, &frq_lock); + if (rc < 0) + goto ret; + + /* Frequency is locked */ + if (frq_lock == 1) + signal = 32768; + + /* Get SNR of the video signal */ + rc = xc2028_get_reg(priv, 0x0040, &signal); + if (rc < 0) + goto ret; + + /* Use both frq_lock and signal to generate the result */ + signal = signal || ((signal & 0x07) << 12); + +ret: + mutex_unlock(&priv->lock); + + *strength = signal; + + tuner_dbg("signal strength is %d\n", signal); + + return rc; +} + +#define DIV 15625 + +static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, + enum v4l2_tuner_type new_type, + unsigned int type, + v4l2_std_id std, + u16 int_freq) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc = -EINVAL; + unsigned char buf[4]; + u32 div, offset = 0; + + tuner_dbg("%s called\n", __func__); + + mutex_lock(&priv->lock); + + tuner_dbg("should set frequency %d kHz\n", freq / 1000); + + if (check_firmware(fe, type, std, int_freq) < 0) + goto ret; + + /* On some cases xc2028 can disable video output, if + * very weak signals are received. By sending a soft + * reset, this is re-enabled. So, it is better to always + * send a soft reset before changing channels, to be sure + * that xc2028 will be in a safe state. + * Maybe this might also be needed for DTV. + */ + if (new_type == V4L2_TUNER_ANALOG_TV) { + rc = send_seq(priv, {0x00, 0x00}); + + /* Analog modes require offset = 0 */ + } else { + /* + * Digital modes require an offset to adjust to the + * proper frequency. The offset depends on what + * firmware version is used. + */ + + /* + * Adjust to the center frequency. This is calculated by the + * formula: offset = 1.25MHz - BW/2 + * For DTV 7/8, the firmware uses BW = 8000, so it needs a + * further adjustment to get the frequency center on VHF + */ + if (priv->cur_fw.type & DTV6) + offset = 1750000; + else if (priv->cur_fw.type & DTV7) + offset = 2250000; + else /* DTV8 or DTV78 */ + offset = 2750000; + if ((priv->cur_fw.type & DTV78) && freq < 470000000) + offset -= 500000; + + /* + * xc3028 additional "magic" + * Depending on the firmware version, it needs some adjustments + * to properly centralize the frequency. This seems to be + * needed to compensate the SCODE table adjustments made by + * newer firmwares + */ + +#if 1 + /* + * The proper adjustment would be to do it at s-code table. + * However, this didn't work, as reported by + * Robert Lowery + */ + + if (priv->cur_fw.type & DTV7) + offset += 500000; + +#else + /* + * Still need tests for XC3028L (firmware 3.2 or upper) + * So, for now, let's just comment the per-firmware + * version of this change. Reports with xc3028l working + * with and without the lines bellow are welcome + */ + + if (priv->firm_version < 0x0302) { + if (priv->cur_fw.type & DTV7) + offset += 500000; + } else { + if (priv->cur_fw.type & DTV7) + offset -= 300000; + else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */ + offset += 200000; + } +#endif + } + + div = (freq - offset + DIV / 2) / DIV; + + /* CMD= Set frequency */ + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00}); + else + rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00}); + if (rc < 0) + goto ret; + + /* Return code shouldn't be checked. + The reset CLK is needed only with tm6000. + Driver should work fine even if this fails. + */ + if (priv->ctrl.msleep) + msleep(priv->ctrl.msleep); + do_tuner_callback(fe, XC2028_RESET_CLK, 1); + + msleep(10); + + buf[0] = 0xff & (div >> 24); + buf[1] = 0xff & (div >> 16); + buf[2] = 0xff & (div >> 8); + buf[3] = 0xff & (div); + + rc = i2c_send(priv, buf, sizeof(buf)); + if (rc < 0) + goto ret; + msleep(100); + + priv->frequency = freq; + + tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n", + buf[0], buf[1], buf[2], buf[3], + freq / 1000000, (freq % 1000000) / 1000); + + rc = 0; + +ret: + mutex_unlock(&priv->lock); + + return rc; +} + +static int xc2028_set_analog_freq(struct dvb_frontend *fe, + struct analog_parameters *p) +{ + struct xc2028_data *priv = fe->tuner_priv; + unsigned int type=0; + + tuner_dbg("%s called\n", __func__); + + if (p->mode == V4L2_TUNER_RADIO) { + type |= FM; + if (priv->ctrl.input1) + type |= INPUT1; + return generic_set_freq(fe, (625l * p->frequency) / 10, + V4L2_TUNER_RADIO, type, 0, 0); + } + + /* if std is not defined, choose one */ + if (!p->std) + p->std = V4L2_STD_MN; + + /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ + if (!(p->std & V4L2_STD_MN)) + type |= F8MHZ; + + /* Add audio hack to std mask */ + p->std |= parse_audio_std_option(); + + return generic_set_freq(fe, 62500l * p->frequency, + V4L2_TUNER_ANALOG_TV, type, p->std, 0); +} + +static int xc2028_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct xc2028_data *priv = fe->tuner_priv; + unsigned int type=0; + fe_bandwidth_t bw = BANDWIDTH_8_MHZ; + u16 demod = 0; + + tuner_dbg("%s called\n", __func__); + + switch(fe->ops.info.type) { + case FE_OFDM: + bw = p->u.ofdm.bandwidth; + /* + * The only countries with 6MHz seem to be Taiwan/Uruguay. + * Both seem to require QAM firmware for OFDM decoding + * Tested in Taiwan by Terry Wu + */ + if (bw == BANDWIDTH_6_MHZ) + type |= QAM; + break; + case FE_ATSC: + bw = BANDWIDTH_6_MHZ; + /* The only ATSC firmware (at least on v2.7) is D2633 */ + type |= ATSC | D2633; + break; + /* DVB-S and pure QAM (FE_QAM) are not supported */ + default: + return -EINVAL; + } + + switch (bw) { + case BANDWIDTH_8_MHZ: + if (p->frequency < 470000000) + priv->ctrl.vhfbw7 = 0; + else + priv->ctrl.uhfbw8 = 1; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; + type |= F8MHZ; + break; + case BANDWIDTH_7_MHZ: + if (p->frequency < 470000000) + priv->ctrl.vhfbw7 = 1; + else + priv->ctrl.uhfbw8 = 0; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; + type |= F8MHZ; + break; + case BANDWIDTH_6_MHZ: + type |= DTV6; + priv->ctrl.vhfbw7 = 0; + priv->ctrl.uhfbw8 = 0; + break; + default: + tuner_err("error: bandwidth not supported.\n"); + }; + + /* + Selects between D2633 or D2620 firmware. + It doesn't make sense for ATSC, since it should be D2633 on all cases + */ + if (fe->ops.info.type != FE_ATSC) { + switch (priv->ctrl.type) { + case XC2028_D2633: + type |= D2633; + break; + case XC2028_D2620: + type |= D2620; + break; + case XC2028_AUTO: + default: + /* Zarlink seems to need D2633 */ + if (priv->ctrl.demod == XC3028_FE_ZARLINK456) + type |= D2633; + else + type |= D2620; + } + } + + /* All S-code tables need a 200kHz shift */ + if (priv->ctrl.demod) { + demod = priv->ctrl.demod; + + /* + * Newer firmwares require a 200 kHz offset only for ATSC + */ + if (type == ATSC || priv->firm_version < 0x0302) + demod += 200; + /* + * The DTV7 S-code table needs a 700 kHz shift. + * + * DTV7 is only used in Australia. Germany or Italy may also + * use this firmware after initialization, but a tune to a UHF + * channel should then cause DTV78 to be used. + * + * Unfortunately, on real-field tests, the s-code offset + * didn't work as expected, as reported by + * Robert Lowery + */ + } + + return generic_set_freq(fe, p->frequency, + V4L2_TUNER_DIGITAL_TV, type, 0, demod); +} + +static int xc2028_sleep(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc = 0; + + /* Avoid firmware reload on slow devices or if PM disabled */ + if (no_poweroff || priv->ctrl.disable_power_mgmt) + return 0; + + tuner_dbg("Putting xc2028/3028 into poweroff mode.\n"); + if (debug > 1) { + tuner_dbg("Printing sleep stack trace:\n"); + dump_stack(); + } + + mutex_lock(&priv->lock); + + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00}); + else + rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00}); + + priv->cur_fw.type = 0; /* need firmware reload */ + + mutex_unlock(&priv->lock); + + return rc; +} + +static int xc2028_dvb_release(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + + tuner_dbg("%s called\n", __func__); + + mutex_lock(&xc2028_list_mutex); + + /* only perform final cleanup if this is the last instance */ + if (hybrid_tuner_report_instance_count(priv) == 1) { + kfree(priv->ctrl.fname); + free_firmware(priv); + } + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&xc2028_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct xc2028_data *priv = fe->tuner_priv; + + tuner_dbg("%s called\n", __func__); + + *frequency = priv->frequency; + + return 0; +} + +static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct xc2028_data *priv = fe->tuner_priv; + struct xc2028_ctrl *p = priv_cfg; + int rc = 0; + + tuner_dbg("%s called\n", __func__); + + mutex_lock(&priv->lock); + + memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); + if (priv->ctrl.max_len < 9) + priv->ctrl.max_len = 13; + + if (p->fname) { + if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) { + kfree(priv->ctrl.fname); + free_firmware(priv); + } + + priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); + if (priv->ctrl.fname == NULL) + rc = -ENOMEM; + } + + mutex_unlock(&priv->lock); + + return rc; +} + +static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { + .info = { + .name = "Xceive XC3028", + .frequency_min = 42000000, + .frequency_max = 864000000, + .frequency_step = 50000, + }, + + .set_config = xc2028_set_config, + .set_analog_params = xc2028_set_analog_freq, + .release = xc2028_dvb_release, + .get_frequency = xc2028_get_frequency, + .get_rf_strength = xc2028_signal, + .set_params = xc2028_set_params, + .sleep = xc2028_sleep, +}; + +struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) +{ + struct xc2028_data *priv; + int instance; + + if (debug) + printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n"); + + if (NULL == cfg) + return NULL; + + if (!fe) { + printk(KERN_ERR "xc2028: No frontend!\n"); + return NULL; + } + + mutex_lock(&xc2028_list_mutex); + + instance = hybrid_tuner_request_state(struct xc2028_data, priv, + hybrid_tuner_instance_list, + cfg->i2c_adap, cfg->i2c_addr, + "xc2028"); + switch (instance) { + case 0: + /* memory allocation failure */ + goto fail; + break; + case 1: + /* new tuner instance */ + priv->ctrl.max_len = 13; + + mutex_init(&priv->lock); + + fe->tuner_priv = priv; + break; + case 2: + /* existing tuner instance */ + fe->tuner_priv = priv; + break; + } + + memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, + sizeof(xc2028_dvb_tuner_ops)); + + tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); + + if (cfg->ctrl) + xc2028_set_config(fe, cfg->ctrl); + + mutex_unlock(&xc2028_list_mutex); + + return fe; +fail: + mutex_unlock(&xc2028_list_mutex); + + xc2028_dvb_release(fe); + return NULL; +} + +EXPORT_SYMBOL(xc2028_attach); + +MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); +MODULE_AUTHOR("Michel Ludwig "); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,71 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +#ifndef __TUNER_XC2028_H__ +#define __TUNER_XC2028_H__ + +#include "dvb_frontend.h" + +#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" +#define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw" + +/* Dmoduler IF (kHz) */ +#define XC3028_FE_DEFAULT 0 /* Don't load SCODE */ +#define XC3028_FE_LG60 6000 +#define XC3028_FE_ATI638 6380 +#define XC3028_FE_OREN538 5380 +#define XC3028_FE_OREN36 3600 +#define XC3028_FE_TOYOTA388 3880 +#define XC3028_FE_TOYOTA794 7940 +#define XC3028_FE_DIBCOM52 5200 +#define XC3028_FE_ZARLINK456 4560 +#define XC3028_FE_CHINA 5200 + +enum firmware_type { + XC2028_AUTO = 0, /* By default, auto-detects */ + XC2028_D2633, + XC2028_D2620, +}; + +struct xc2028_ctrl { + char *fname; + int max_len; + int msleep; + unsigned int scode_table; + unsigned int mts :1; + unsigned int input1:1; + unsigned int vhfbw7:1; + unsigned int uhfbw8:1; + unsigned int disable_power_mgmt:1; + unsigned int read_not_reliable:1; + unsigned int demod; + enum firmware_type type:2; +}; + +struct xc2028_config { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + struct xc2028_ctrl *ctrl; +}; + +/* xc2028 commands for callback */ +#define XC2028_TUNER_RESET 0 +#define XC2028_RESET_CLK 1 + +#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) +extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg); +#else +static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return NULL; +} +#endif + +#endif /* __TUNER_XC2028_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028-types.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028-types.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028-types.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/tuner-xc2028-types.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,141 @@ +/* tuner-xc2028_types + * + * This file includes internal tipes to be used inside tuner-xc2028. + * Shouldn't be included outside tuner-xc2028 + * + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +/* xc3028 firmware types */ + +/* BASE firmware should be loaded before any other firmware */ +#define BASE (1<<0) +#define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) + +/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ +#define F8MHZ (1<<1) + +/* Multichannel Television Sound (MTS) + Those firmwares are capable of using xc2038 DSP to decode audio and + produce a baseband audio output on some pins of the chip. + There are MTS firmwares for the most used video standards. It should be + required to use MTS firmwares, depending on the way audio is routed into + the bridge chip + */ +#define MTS (1<<2) + +/* FIXME: I have no idea what's the difference between + D2620 and D2633 firmwares + */ +#define D2620 (1<<3) +#define D2633 (1<<4) + +/* DTV firmwares for 6, 7 and 8 MHz + DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS + DTV8 - 8MHz - DVB-C/DVB-T + */ +#define DTV6 (1 << 5) +#define QAM (1 << 6) +#define DTV7 (1<<7) +#define DTV78 (1<<8) +#define DTV8 (1<<9) + +#define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) + +/* There's a FM | BASE firmware + FM specific firmware (std=0) */ +#define FM (1<<10) + +#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD) + +/* Applies only for FM firmware + Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) + */ +#define INPUT1 (1<<11) + + +/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + There are variants both with and without NOGD + Those firmwares produce better result with LCD displays + */ +#define LCD (1<<12) + +/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + The NOGD firmwares don't have group delay compensation filter + */ +#define NOGD (1<<13) + +/* Old firmwares were broken into init0 and init1 */ +#define INIT1 (1<<14) + +/* SCODE firmware selects particular behaviours */ +#define MONO (1 << 15) +#define ATSC (1 << 16) +#define IF (1 << 17) +#define LG60 (1 << 18) +#define ATI638 (1 << 19) +#define OREN538 (1 << 20) +#define OREN36 (1 << 21) +#define TOYOTA388 (1 << 22) +#define TOYOTA794 (1 << 23) +#define DIBCOM52 (1 << 24) +#define ZARLINK456 (1 << 25) +#define CHINA (1 << 26) +#define F6MHZ (1 << 27) +#define INPUT2 (1 << 28) +#define SCODE (1 << 29) + +/* This flag identifies that the scode table has a new format */ +#define HAS_IF (1 << 30) + +/* There are different scode tables for MTS and non-MTS. + The MTS firmwares support mono only + */ +#define SCODE_TYPES (SCODE | MTS) + + +/* Newer types not defined on videodev2.h. + The original idea were to move all those types to videodev2.h, but + it seemed overkill, since, with the exception of SECAM/K3, the other + types seem to be autodetected. + It is not clear where secam/k3 is used, nor we have a feedback of this + working or being autodetected by the standard secam firmware. + */ + +#define V4L2_STD_SECAM_K3 (0x04000000) + +/* Audio types */ + +#define V4L2_STD_A2_A (1LL<<32) +#define V4L2_STD_A2_B (1LL<<33) +#define V4L2_STD_NICAM_A (1LL<<34) +#define V4L2_STD_NICAM_B (1LL<<35) +#define V4L2_STD_AM (1LL<<36) +#define V4L2_STD_BTSC (1LL<<37) +#define V4L2_STD_EIAJ (1LL<<38) + +#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) +#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) + +/* To preserve backward compatibilty, + (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported + */ + +#define V4L2_STD_AUDIO (V4L2_STD_A2 | \ + V4L2_STD_NICAM | \ + V4L2_STD_AM | \ + V4L2_STD_BTSC | \ + V4L2_STD_EIAJ) + +/* Used standards with audio restrictions */ + +#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) +#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) +#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) +#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) +#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) +#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc4000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc4000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc4000.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc4000.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1691 @@ +/* + * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Xceive Corporation + * Copyright (c) 2007 Steven Toth + * Copyright (c) 2009 Devin Heitmueller + * Copyright (c) 2009 Davide Ferri + * Copyright (c) 2010 Istvan Varga + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "xc4000.h" +#include "tuner-i2c.h" +#include "tuner-xc2028-types.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off))."); + +static int no_poweroff; +module_param(no_poweroff, int, 0644); +MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, " + "0 (default): use device-specific default mode)."); + +static int audio_std; +module_param(audio_std, int, 0644); +MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly " + "needs to know what audio standard is needed for some video standards " + "with audio A2 or NICAM. The valid settings are a sum of:\n" + " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n" + " 2: use A2 instead of NICAM or BTSC\n" + " 4: use SECAM/K3 instead of K1\n" + " 8: use PAL-D/K audio for SECAM-D/K\n" + "16: use FM radio input 1 instead of input 2\n" + "32: use mono audio (the lower three bits are ignored)"); + +static char firmware_name[30]; +module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); +MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " + "default firmware name."); + +static DEFINE_MUTEX(xc4000_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) + +/* struct for storing firmware table */ +struct firmware_description { + unsigned int type; + v4l2_std_id id; + __u16 int_freq; + unsigned char *ptr; + unsigned int size; +}; + +struct firmware_properties { + unsigned int type; + v4l2_std_id id; + v4l2_std_id std_req; + __u16 int_freq; + unsigned int scode_table; + int scode_nr; +}; + +struct xc4000_priv { + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + struct firmware_description *firm; + int firm_size; + u32 if_khz; + u32 freq_hz; + u32 bandwidth; + u8 video_standard; + u8 rf_mode; + u8 default_pm; + u8 dvb_amplitude; + u8 set_smoothedcvbs; + u8 ignore_i2c_write_errors; + __u16 firm_version; + struct firmware_properties cur_fw; + __u16 hwmodel; + __u16 hwvers; + struct mutex lock; +}; + +#define XC4000_AUDIO_STD_B 1 +#define XC4000_AUDIO_STD_A2 2 +#define XC4000_AUDIO_STD_K3 4 +#define XC4000_AUDIO_STD_L 8 +#define XC4000_AUDIO_STD_INPUT1 16 +#define XC4000_AUDIO_STD_MONO 32 + +#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw" + +/* Misc Defines */ +#define MAX_TV_STANDARD 24 +#define XC_MAX_I2C_WRITE_LENGTH 64 +#define XC_POWERED_DOWN 0x80000000U + +/* Signal Types */ +#define XC_RF_MODE_AIR 0 +#define XC_RF_MODE_CABLE 1 + +/* Product id */ +#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 +#define XC_PRODUCT_ID_XC4000 0x0FA0 +#define XC_PRODUCT_ID_XC4100 0x1004 + +/* Registers (Write-only) */ +#define XREG_INIT 0x00 +#define XREG_VIDEO_MODE 0x01 +#define XREG_AUDIO_MODE 0x02 +#define XREG_RF_FREQ 0x03 +#define XREG_D_CODE 0x04 +#define XREG_DIRECTSITTING_MODE 0x05 +#define XREG_SEEK_MODE 0x06 +#define XREG_POWER_DOWN 0x08 +#define XREG_SIGNALSOURCE 0x0A +#define XREG_SMOOTHEDCVBS 0x0E +#define XREG_AMPLITUDE 0x10 + +/* Registers (Read-only) */ +#define XREG_ADC_ENV 0x00 +#define XREG_QUALITY 0x01 +#define XREG_FRAME_LINES 0x02 +#define XREG_HSYNC_FREQ 0x03 +#define XREG_LOCK 0x04 +#define XREG_FREQ_ERROR 0x05 +#define XREG_SNR 0x06 +#define XREG_VERSION 0x07 +#define XREG_PRODUCT_ID 0x08 + +/* + Basic firmware description. This will remain with + the driver for documentation purposes. + + This represents an I2C firmware file encoded as a + string of unsigned char. Format is as follows: + + char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB + char[1 ]=len0_LSB -> length of first write transaction + char[2 ]=data0 -> first byte to be sent + char[3 ]=data1 + char[4 ]=data2 + char[ ]=... + char[M ]=dataN -> last byte to be sent + char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB + char[M+2]=len1_LSB -> length of second write transaction + char[M+3]=data0 + char[M+4]=data1 + ... + etc. + + The [len] value should be interpreted as follows: + + len= len_MSB _ len_LSB + len=1111_1111_1111_1111 : End of I2C_SEQUENCE + len=0000_0000_0000_0000 : Reset command: Do hardware reset + len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) + len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms + + For the RESET and WAIT commands, the two following bytes will contain + immediately the length of the following transaction. +*/ + +struct XC_TV_STANDARD { + const char *Name; + u16 audio_mode; + u16 video_mode; + u16 int_freq; +}; + +/* Tuner standards */ +#define XC4000_MN_NTSC_PAL_BTSC 0 +#define XC4000_MN_NTSC_PAL_A2 1 +#define XC4000_MN_NTSC_PAL_EIAJ 2 +#define XC4000_MN_NTSC_PAL_Mono 3 +#define XC4000_BG_PAL_A2 4 +#define XC4000_BG_PAL_NICAM 5 +#define XC4000_BG_PAL_MONO 6 +#define XC4000_I_PAL_NICAM 7 +#define XC4000_I_PAL_NICAM_MONO 8 +#define XC4000_DK_PAL_A2 9 +#define XC4000_DK_PAL_NICAM 10 +#define XC4000_DK_PAL_MONO 11 +#define XC4000_DK_SECAM_A2DK1 12 +#define XC4000_DK_SECAM_A2LDK3 13 +#define XC4000_DK_SECAM_A2MONO 14 +#define XC4000_DK_SECAM_NICAM 15 +#define XC4000_L_SECAM_NICAM 16 +#define XC4000_LC_SECAM_NICAM 17 +#define XC4000_DTV6 18 +#define XC4000_DTV8 19 +#define XC4000_DTV7_8 20 +#define XC4000_DTV7 21 +#define XC4000_FM_Radio_INPUT2 22 +#define XC4000_FM_Radio_INPUT1 23 + +static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = { + {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500}, + {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600}, + {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500}, + {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500}, + {"B/G-PAL-A2", 0x0000, 0x8159, 5640}, + {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740}, + {"B/G-PAL-MONO", 0x0078, 0x8159, 5500}, + {"I-PAL-NICAM", 0x0080, 0x8049, 6240}, + {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000}, + {"D/K-PAL-A2", 0x0000, 0x8049, 6380}, + {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200}, + {"D/K-PAL-MONO", 0x0078, 0x8049, 6500}, + {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340}, + {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000}, + {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500}, + {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200}, + {"L-SECAM-NICAM", 0x8080, 0x0009, 6200}, + {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200}, + {"DTV6", 0x00C0, 0x8002, 0}, + {"DTV8", 0x00C0, 0x800B, 0}, + {"DTV7/8", 0x00C0, 0x801B, 0}, + {"DTV7", 0x00C0, 0x8007, 0}, + {"FM Radio-INPUT2", 0x0008, 0x9800, 10700}, + {"FM Radio-INPUT1", 0x0008, 0x9000, 10700} +}; + +static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val); +static int xc4000_tuner_reset(struct dvb_frontend *fe); +static void xc_debug_dump(struct xc4000_priv *priv); + +static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len) +{ + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = 0, .buf = buf, .len = len }; + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + if (priv->ignore_i2c_write_errors == 0) { + printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n", + len); + if (len == 4) { + printk(KERN_ERR "bytes %02x %02x %02x %02x\n", buf[0], + buf[1], buf[2], buf[3]); + } + return -EREMOTEIO; + } + } + return 0; +} + +static int xc4000_tuner_reset(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __func__); + + if (fe->callback) { + ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? + fe->dvb->priv : + priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + XC4000_TUNER_RESET, 0); + if (ret) { + printk(KERN_ERR "xc4000: reset failed\n"); + return -EREMOTEIO; + } + } else { + printk(KERN_ERR "xc4000: no tuner reset callback function, " + "fatal\n"); + return -EINVAL; + } + return 0; +} + +static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData) +{ + u8 buf[4]; + int result; + + buf[0] = (regAddr >> 8) & 0xFF; + buf[1] = regAddr & 0xFF; + buf[2] = (i2cData >> 8) & 0xFF; + buf[3] = i2cData & 0xFF; + result = xc_send_i2c_data(priv, buf, 4); + + return result; +} + +static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) +{ + struct xc4000_priv *priv = fe->tuner_priv; + + int i, nbytes_to_send, result; + unsigned int len, pos, index; + u8 buf[XC_MAX_I2C_WRITE_LENGTH]; + + index = 0; + while ((i2c_sequence[index] != 0xFF) || + (i2c_sequence[index + 1] != 0xFF)) { + len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; + if (len == 0x0000) { + /* RESET command */ + /* NOTE: this is ignored, as the reset callback was */ + /* already called by check_firmware() */ + index += 2; + } else if (len & 0x8000) { + /* WAIT command */ + msleep(len & 0x7FFF); + index += 2; + } else { + /* Send i2c data whilst ensuring individual transactions + * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. + */ + index += 2; + buf[0] = i2c_sequence[index]; + buf[1] = i2c_sequence[index + 1]; + pos = 2; + while (pos < len) { + if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) + nbytes_to_send = + XC_MAX_I2C_WRITE_LENGTH; + else + nbytes_to_send = (len - pos + 2); + for (i = 2; i < nbytes_to_send; i++) { + buf[i] = i2c_sequence[index + pos + + i - 2]; + } + result = xc_send_i2c_data(priv, buf, + nbytes_to_send); + + if (result != 0) + return result; + + pos += nbytes_to_send - 2; + } + index += len; + } + } + return 0; +} + +static int xc_set_tv_standard(struct xc4000_priv *priv, + u16 video_mode, u16 audio_mode) +{ + int ret; + dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); + dprintk(1, "%s() Standard = %s\n", + __func__, + xc4000_standard[priv->video_standard].Name); + + /* Don't complain when the request fails because of i2c stretching */ + priv->ignore_i2c_write_errors = 1; + + ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); + if (ret == 0) + ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); + + priv->ignore_i2c_write_errors = 0; + + return ret; +} + +static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode) +{ + dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, + rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); + + if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { + rf_mode = XC_RF_MODE_CABLE; + printk(KERN_ERR + "%s(), Invalid mode, defaulting to CABLE", + __func__); + } + return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); +} + +static const struct dvb_tuner_ops xc4000_tuner_ops; + +static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz) +{ + u16 freq_code; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + if ((freq_hz > xc4000_tuner_ops.info.frequency_max) || + (freq_hz < xc4000_tuner_ops.info.frequency_min)) + return -EINVAL; + + freq_code = (u16)(freq_hz / 15625); + + /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the + FINERFREQ for all normal tuning (the doc indicates reg 0x03 should + only be used for fast scanning for channel lock) */ + /* WAS: XREG_FINERFREQ */ + return xc_write_reg(priv, XREG_RF_FREQ, freq_code); +} + +static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope) +{ + return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope); +} + +static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz) +{ + int result; + u16 regData; + u32 tmp; + + result = xc4000_readreg(priv, XREG_FREQ_ERROR, ®Data); + if (result != 0) + return result; + + tmp = (u32)regData & 0xFFFFU; + tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp); + (*freq_error_hz) = tmp * 15625; + return result; +} + +static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status) +{ + return xc4000_readreg(priv, XREG_LOCK, lock_status); +} + +static int xc_get_version(struct xc4000_priv *priv, + u8 *hw_majorversion, u8 *hw_minorversion, + u8 *fw_majorversion, u8 *fw_minorversion) +{ + u16 data; + int result; + + result = xc4000_readreg(priv, XREG_VERSION, &data); + if (result != 0) + return result; + + (*hw_majorversion) = (data >> 12) & 0x0F; + (*hw_minorversion) = (data >> 8) & 0x0F; + (*fw_majorversion) = (data >> 4) & 0x0F; + (*fw_minorversion) = data & 0x0F; + + return 0; +} + +static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz) +{ + u16 regData; + int result; + + result = xc4000_readreg(priv, XREG_HSYNC_FREQ, ®Data); + if (result != 0) + return result; + + (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; + return result; +} + +static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines) +{ + return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines); +} + +static int xc_get_quality(struct xc4000_priv *priv, u16 *quality) +{ + return xc4000_readreg(priv, XREG_QUALITY, quality); +} + +static u16 xc_wait_for_lock(struct xc4000_priv *priv) +{ + u16 lock_state = 0; + int watchdog_count = 40; + + while ((lock_state == 0) && (watchdog_count > 0)) { + xc_get_lock_status(priv, &lock_state); + if (lock_state != 1) { + msleep(5); + watchdog_count--; + } + } + return lock_state; +} + +static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz) +{ + int found = 1; + int result; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + /* Don't complain when the request fails because of i2c stretching */ + priv->ignore_i2c_write_errors = 1; + result = xc_set_rf_frequency(priv, freq_hz); + priv->ignore_i2c_write_errors = 0; + + if (result != 0) + return 0; + + /* wait for lock only in analog TV mode */ + if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) { + if (xc_wait_for_lock(priv) != 1) + found = 0; + } + + /* Wait for stats to stabilize. + * Frame Lines needs two frame times after initial lock + * before it is valid. + */ + msleep(debug ? 100 : 10); + + if (debug) + xc_debug_dump(priv); + + return found; +} + +static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) +{ + u8 buf[2] = { reg >> 8, reg & 0xff }; + u8 bval[2] = { 0, 0 }; + struct i2c_msg msg[2] = { + { .addr = priv->i2c_props.addr, + .flags = 0, .buf = &buf[0], .len = 2 }, + { .addr = priv->i2c_props.addr, + .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, + }; + + if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { + printk(KERN_ERR "xc4000: I2C read failed\n"); + return -EREMOTEIO; + } + + *val = (bval[0] << 8) | bval[1]; + return 0; +} + +#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) +static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) +{ + if (type & BASE) + printk(KERN_CONT "BASE "); + if (type & INIT1) + printk(KERN_CONT "INIT1 "); + if (type & F8MHZ) + printk(KERN_CONT "F8MHZ "); + if (type & MTS) + printk(KERN_CONT "MTS "); + if (type & D2620) + printk(KERN_CONT "D2620 "); + if (type & D2633) + printk(KERN_CONT "D2633 "); + if (type & DTV6) + printk(KERN_CONT "DTV6 "); + if (type & QAM) + printk(KERN_CONT "QAM "); + if (type & DTV7) + printk(KERN_CONT "DTV7 "); + if (type & DTV78) + printk(KERN_CONT "DTV78 "); + if (type & DTV8) + printk(KERN_CONT "DTV8 "); + if (type & FM) + printk(KERN_CONT "FM "); + if (type & INPUT1) + printk(KERN_CONT "INPUT1 "); + if (type & LCD) + printk(KERN_CONT "LCD "); + if (type & NOGD) + printk(KERN_CONT "NOGD "); + if (type & MONO) + printk(KERN_CONT "MONO "); + if (type & ATSC) + printk(KERN_CONT "ATSC "); + if (type & IF) + printk(KERN_CONT "IF "); + if (type & LG60) + printk(KERN_CONT "LG60 "); + if (type & ATI638) + printk(KERN_CONT "ATI638 "); + if (type & OREN538) + printk(KERN_CONT "OREN538 "); + if (type & OREN36) + printk(KERN_CONT "OREN36 "); + if (type & TOYOTA388) + printk(KERN_CONT "TOYOTA388 "); + if (type & TOYOTA794) + printk(KERN_CONT "TOYOTA794 "); + if (type & DIBCOM52) + printk(KERN_CONT "DIBCOM52 "); + if (type & ZARLINK456) + printk(KERN_CONT "ZARLINK456 "); + if (type & CHINA) + printk(KERN_CONT "CHINA "); + if (type & F6MHZ) + printk(KERN_CONT "F6MHZ "); + if (type & INPUT2) + printk(KERN_CONT "INPUT2 "); + if (type & SCODE) + printk(KERN_CONT "SCODE "); + if (type & HAS_IF) + printk(KERN_CONT "HAS_IF_%d ", int_freq); +} + +static int seek_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int i, best_i = -1; + unsigned int best_nr_diffs = 255U; + + if (!priv->firm) { + printk(KERN_ERR "Error! firmware not loaded\n"); + return -EINVAL; + } + + if (((type & ~SCODE) == 0) && (*id == 0)) + *id = V4L2_STD_PAL; + + /* Seek for generic video standard match */ + for (i = 0; i < priv->firm_size; i++) { + v4l2_std_id id_diff_mask = + (priv->firm[i].id ^ (*id)) & (*id); + unsigned int type_diff_mask = + (priv->firm[i].type ^ type) + & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE); + unsigned int nr_diffs; + + if (type_diff_mask + & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE)) + continue; + + nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask); + if (!nr_diffs) /* Supports all the requested standards */ + goto found; + + if (nr_diffs < best_nr_diffs) { + best_nr_diffs = nr_diffs; + best_i = i; + } + } + + /* FIXME: Would make sense to seek for type "hint" match ? */ + if (best_i < 0) { + i = -ENOENT; + goto ret; + } + + if (best_nr_diffs > 0U) { + printk(KERN_WARNING + "Selecting best matching firmware (%u bits differ) for " + "type=(%x), id %016llx:\n", + best_nr_diffs, type, (unsigned long long)*id); + i = best_i; + } + +found: + *id = priv->firm[i].id; + +ret: + if (debug) { + printk(KERN_DEBUG "%s firmware for type=", + (i < 0) ? "Can't find" : "Found"); + dump_firm_type(type); + printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id); + } + return i; +} + +static int load_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + p = priv->firm[pos].ptr; + + /* Don't complain when the request fails because of i2c stretching */ + priv->ignore_i2c_write_errors = 1; + + rc = xc_load_i2c_sequence(fe, p); + + priv->ignore_i2c_write_errors = 0; + + return rc; +} + +static int xc4000_fwupload(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + const struct firmware *fw = NULL; + const unsigned char *p, *endp; + int rc = 0; + int n, n_array; + char name[33]; + const char *fname; + + if (firmware_name[0] != '\0') + fname = firmware_name; + else + fname = XC4000_DEFAULT_FIRMWARE; + + dprintk(1, "Reading firmware %s\n", fname); + rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); + if (rc < 0) { + if (rc == -ENOENT) + printk(KERN_ERR "Error: firmware %s not found.\n", fname); + else + printk(KERN_ERR "Error %d while requesting firmware %s\n", + rc, fname); + + return rc; + } + p = fw->data; + endp = p + fw->size; + + if (fw->size < sizeof(name) - 1 + 2 + 2) { + printk(KERN_ERR "Error: firmware file %s has invalid size!\n", + fname); + goto corrupt; + } + + memcpy(name, p, sizeof(name) - 1); + name[sizeof(name) - 1] = '\0'; + p += sizeof(name) - 1; + + priv->firm_version = get_unaligned_le16(p); + p += 2; + + n_array = get_unaligned_le16(p); + p += 2; + + dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n", + n_array, fname, name, + priv->firm_version >> 8, priv->firm_version & 0xff); + + priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); + if (priv->firm == NULL) { + printk(KERN_ERR "Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto done; + } + priv->firm_size = n_array; + + n = -1; + while (p < endp) { + __u32 type, size; + v4l2_std_id id; + __u16 int_freq = 0; + + n++; + if (n >= n_array) { + printk(KERN_ERR "More firmware images in file than " + "were expected!\n"); + goto corrupt; + } + + /* Checks if there's enough bytes to read */ + if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) + goto header; + + type = get_unaligned_le32(p); + p += sizeof(type); + + id = get_unaligned_le64(p); + p += sizeof(id); + + if (type & HAS_IF) { + int_freq = get_unaligned_le16(p); + p += sizeof(int_freq); + if (endp - p < sizeof(size)) + goto header; + } + + size = get_unaligned_le32(p); + p += sizeof(size); + + if (!size || size > endp - p) { + printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n", + type, (unsigned long long)id, + (unsigned)(endp - p), size); + goto corrupt; + } + + priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); + if (priv->firm[n].ptr == NULL) { + printk(KERN_ERR "Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto done; + } + + if (debug) { + printk(KERN_DEBUG "Reading firmware type "); + dump_firm_type_and_int_freq(type, int_freq); + printk(KERN_DEBUG "(%x), id %llx, size=%d.\n", + type, (unsigned long long)id, size); + } + + memcpy(priv->firm[n].ptr, p, size); + priv->firm[n].type = type; + priv->firm[n].id = id; + priv->firm[n].size = size; + priv->firm[n].int_freq = int_freq; + + p += size; + } + + if (n + 1 != priv->firm_size) { + printk(KERN_ERR "Firmware file is incomplete!\n"); + goto corrupt; + } + + goto done; + +header: + printk(KERN_ERR "Firmware header is incomplete!\n"); +corrupt: + rc = -EINVAL; + printk(KERN_ERR "Error: firmware file is corrupted!\n"); + +done: + release_firmware(fw); + if (rc == 0) + dprintk(1, "Firmware files loaded.\n"); + + return rc; +} + +static int load_scode(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id, __u16 int_freq, int scode) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + u8 scode_buf[13]; + u8 indirect_mode[5]; + + dprintk(1, "%s called int_freq=%d\n", __func__, int_freq); + + if (!int_freq) { + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + } else { + for (pos = 0; pos < priv->firm_size; pos++) { + if ((priv->firm[pos].int_freq == int_freq) && + (priv->firm[pos].type & HAS_IF)) + break; + } + if (pos == priv->firm_size) + return -ENOENT; + } + + p = priv->firm[pos].ptr; + + if (priv->firm[pos].size != 12 * 16 || scode >= 16) + return -EINVAL; + p += 12 * scode; + + if (debug) { + tuner_info("Loading SCODE for type="); + dump_firm_type_and_int_freq(priv->firm[pos].type, + priv->firm[pos].int_freq); + printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + } + + scode_buf[0] = 0x00; + memcpy(&scode_buf[1], p, 12); + + /* Enter direct-mode */ + rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0); + if (rc < 0) { + printk(KERN_ERR "failed to put device into direct mode!\n"); + return -EIO; + } + + rc = xc_send_i2c_data(priv, scode_buf, 13); + if (rc != 0) { + /* Even if the send failed, make sure we set back to indirect + mode */ + printk(KERN_ERR "Failed to set scode %d\n", rc); + } + + /* Switch back to indirect-mode */ + memset(indirect_mode, 0, sizeof(indirect_mode)); + indirect_mode[4] = 0x88; + xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode)); + msleep(10); + + return 0; +} + +static int check_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id std, __u16 int_freq) +{ + struct xc4000_priv *priv = fe->tuner_priv; + struct firmware_properties new_fw; + int rc = 0, is_retry = 0; + u16 hwmodel; + v4l2_std_id std0; + u8 hw_major, hw_minor, fw_major, fw_minor; + + dprintk(1, "%s called\n", __func__); + + if (!priv->firm) { + rc = xc4000_fwupload(fe); + if (rc < 0) + return rc; + } + +retry: + new_fw.type = type; + new_fw.id = std; + new_fw.std_req = std; + new_fw.scode_table = SCODE; + new_fw.scode_nr = 0; + new_fw.int_freq = int_freq; + + dprintk(1, "checking firmware, user requested type="); + if (debug) { + dump_firm_type(new_fw.type); + printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, + (unsigned long long)new_fw.std_req); + if (!int_freq) + printk(KERN_CONT "scode_tbl "); + else + printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); + printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); + } + + /* No need to reload base firmware if it matches */ + if (priv->cur_fw.type & BASE) { + dprintk(1, "BASE firmware not changed.\n"); + goto skip_base; + } + + /* Updating BASE - forget about all currently loaded firmware */ + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + + /* Reset is needed before loading firmware */ + rc = xc4000_tuner_reset(fe); + if (rc < 0) + goto fail; + + /* BASE firmwares are all std0 */ + std0 = 0; + rc = load_firmware(fe, BASE, &std0); + if (rc < 0) { + printk(KERN_ERR "Error %d while loading base firmware\n", rc); + goto fail; + } + + /* Load INIT1, if needed */ + dprintk(1, "Load init1 firmware, if exists\n"); + + rc = load_firmware(fe, BASE | INIT1, &std0); + if (rc == -ENOENT) + rc = load_firmware(fe, BASE | INIT1, &std0); + if (rc < 0 && rc != -ENOENT) { + tuner_err("Error %d while loading init1 firmware\n", + rc); + goto fail; + } + +skip_base: + /* + * No need to reload standard specific firmware if base firmware + * was not reloaded and requested video standards have not changed. + */ + if (priv->cur_fw.type == (BASE | new_fw.type) && + priv->cur_fw.std_req == std) { + dprintk(1, "Std-specific firmware already loaded.\n"); + goto skip_std_specific; + } + + /* Reloading std-specific firmware forces a SCODE update */ + priv->cur_fw.scode_table = 0; + + /* Load the standard firmware */ + rc = load_firmware(fe, new_fw.type, &new_fw.id); + + if (rc < 0) + goto fail; + +skip_std_specific: + if (priv->cur_fw.scode_table == new_fw.scode_table && + priv->cur_fw.scode_nr == new_fw.scode_nr) { + dprintk(1, "SCODE firmware already loaded.\n"); + goto check_device; + } + + /* Load SCODE firmware, if exists */ + rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, + new_fw.int_freq, new_fw.scode_nr); + if (rc != 0) + dprintk(1, "load scode failed %d\n", rc); + +check_device: + rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel); + + if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major, + &fw_minor) != 0) { + printk(KERN_ERR "Unable to read tuner registers.\n"); + goto fail; + } + + dprintk(1, "Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, hw_major, hw_minor, fw_major, fw_minor); + + /* Check firmware version against what we downloaded. */ + if (priv->firm_version != ((fw_major << 8) | fw_minor)) { + printk(KERN_WARNING + "Incorrect readback of firmware version %d.%d.\n", + fw_major, fw_minor); + goto fail; + } + + /* Check that the tuner hardware model remains consistent over time. */ + if (priv->hwmodel == 0 && + (hwmodel == XC_PRODUCT_ID_XC4000 || + hwmodel == XC_PRODUCT_ID_XC4100)) { + priv->hwmodel = hwmodel; + priv->hwvers = (hw_major << 8) | hw_minor; + } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || + priv->hwvers != ((hw_major << 8) | hw_minor)) { + printk(KERN_WARNING + "Read invalid device hardware information - tuner " + "hung?\n"); + goto fail; + } + + memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); + + /* + * By setting BASE in cur_fw.type only after successfully loading all + * firmwares, we can: + * 1. Identify that BASE firmware with type=0 has been loaded; + * 2. Tell whether BASE firmware was just changed the next time through. + */ + priv->cur_fw.type |= BASE; + + return 0; + +fail: + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + if (!is_retry) { + msleep(50); + is_retry = 1; + dprintk(1, "Retrying firmware load\n"); + goto retry; + } + + if (rc == -ENOENT) + rc = -EINVAL; + return rc; +} + +static void xc_debug_dump(struct xc4000_priv *priv) +{ + u16 adc_envelope; + u32 freq_error_hz = 0; + u16 lock_status; + u32 hsync_freq_hz = 0; + u16 frame_lines; + u16 quality; + u8 hw_majorversion = 0, hw_minorversion = 0; + u8 fw_majorversion = 0, fw_minorversion = 0; + + xc_get_adc_envelope(priv, &adc_envelope); + dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); + + xc_get_frequency_error(priv, &freq_error_hz); + dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); + + xc_get_lock_status(priv, &lock_status); + dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", + lock_status); + + xc_get_version(priv, &hw_majorversion, &hw_minorversion, + &fw_majorversion, &fw_minorversion); + dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", + hw_majorversion, hw_minorversion, + fw_majorversion, fw_minorversion); + + if (priv->video_standard < XC4000_DTV6) { + xc_get_hsync_freq(priv, &hsync_freq_hz); + dprintk(1, "*** Horizontal sync frequency = %d Hz\n", + hsync_freq_hz); + + xc_get_frame_lines(priv, &frame_lines); + dprintk(1, "*** Frame lines = %d\n", frame_lines); + } + + xc_get_quality(priv, &quality); + dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); +} + +static int xc4000_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct xc4000_priv *priv = fe->tuner_priv; + unsigned int type; + int ret = -EREMOTEIO; + + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); + + mutex_lock(&priv->lock); + + if (fe->ops.info.type == FE_ATSC) { + dprintk(1, "%s() ATSC\n", __func__); + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + case QAM_64: + case QAM_256: + case QAM_AUTO: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + default: + ret = -EINVAL; + goto fail; + } + } else if (fe->ops.info.type == FE_OFDM) { + dprintk(1, "%s() OFDM\n", __func__); + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = XC4000_DTV6; + priv->freq_hz = params->frequency - 1750000; + type = DTV6; + break; + case BANDWIDTH_7_MHZ: + priv->bandwidth = BANDWIDTH_7_MHZ; + priv->video_standard = XC4000_DTV7; + priv->freq_hz = params->frequency - 2250000; + type = DTV7; + break; + case BANDWIDTH_8_MHZ: + priv->bandwidth = BANDWIDTH_8_MHZ; + priv->video_standard = XC4000_DTV8; + priv->freq_hz = params->frequency - 2750000; + type = DTV8; + break; + case BANDWIDTH_AUTO: + if (params->frequency < 400000000) { + priv->bandwidth = BANDWIDTH_7_MHZ; + priv->freq_hz = params->frequency - 2250000; + } else { + priv->bandwidth = BANDWIDTH_8_MHZ; + priv->freq_hz = params->frequency - 2750000; + } + priv->video_standard = XC4000_DTV7_8; + type = DTV78; + break; + default: + printk(KERN_ERR "xc4000 bandwidth not set!\n"); + ret = -EINVAL; + goto fail; + } + priv->rf_mode = XC_RF_MODE_AIR; + } else { + printk(KERN_ERR "xc4000 modulation type not supported!\n"); + ret = -EINVAL; + goto fail; + } + + dprintk(1, "%s() frequency=%d (compensated)\n", + __func__, priv->freq_hz); + + /* Make sure the correct firmware type is loaded */ + if (check_firmware(fe, type, 0, priv->if_khz) != 0) + goto fail; + + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { + printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", + priv->rf_mode); + goto fail; + } else { + u16 video_mode, audio_mode; + video_mode = xc4000_standard[priv->video_standard].video_mode; + audio_mode = xc4000_standard[priv->video_standard].audio_mode; + if (type == DTV6 && priv->firm_version != 0x0102) + video_mode |= 0x0001; + ret = xc_set_tv_standard(priv, video_mode, audio_mode); + if (ret != 0) { + printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); + /* DJH - do not return when it fails... */ + /* goto fail; */ + } + } + + if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) + ret = 0; + if (priv->dvb_amplitude != 0) { + if (xc_write_reg(priv, XREG_AMPLITUDE, + (priv->firm_version != 0x0102 || + priv->dvb_amplitude != 134 ? + priv->dvb_amplitude : 132)) != 0) + ret = -EREMOTEIO; + } + if (priv->set_smoothedcvbs != 0) { + if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) + ret = -EREMOTEIO; + } + if (ret != 0) { + printk(KERN_ERR "xc4000: setting registers failed\n"); + /* goto fail; */ + } + + xc_tune_channel(priv, priv->freq_hz); + + ret = 0; + +fail: + mutex_unlock(&priv->lock); + + return ret; +} + +static int xc4000_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc4000_priv *priv = fe->tuner_priv; + unsigned int type = 0; + int ret = -EREMOTEIO; + + if (params->mode == V4L2_TUNER_RADIO) { + dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n", + __func__, params->frequency); + + mutex_lock(&priv->lock); + + params->std = 0; + priv->freq_hz = params->frequency * 125L / 2; + + if (audio_std & XC4000_AUDIO_STD_INPUT1) { + priv->video_standard = XC4000_FM_Radio_INPUT1; + type = FM | INPUT1; + } else { + priv->video_standard = XC4000_FM_Radio_INPUT2; + type = FM | INPUT2; + } + + goto tune_channel; + } + + dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", + __func__, params->frequency); + + mutex_lock(&priv->lock); + + /* params->frequency is in units of 62.5khz */ + priv->freq_hz = params->frequency * 62500; + + params->std &= V4L2_STD_ALL; + /* if std is not defined, choose one */ + if (!params->std) + params->std = V4L2_STD_PAL_BG; + + if (audio_std & XC4000_AUDIO_STD_MONO) + type = MONO; + + if (params->std & V4L2_STD_MN) { + params->std = V4L2_STD_MN; + if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_MN_NTSC_PAL_Mono; + } else if (audio_std & XC4000_AUDIO_STD_A2) { + params->std |= V4L2_STD_A2; + priv->video_standard = XC4000_MN_NTSC_PAL_A2; + } else { + params->std |= V4L2_STD_BTSC; + priv->video_standard = XC4000_MN_NTSC_PAL_BTSC; + } + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_BG) { + params->std = V4L2_STD_PAL_BG; + if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_BG_PAL_MONO; + } else if (!(audio_std & XC4000_AUDIO_STD_A2)) { + if (!(audio_std & XC4000_AUDIO_STD_B)) { + params->std |= V4L2_STD_NICAM_A; + priv->video_standard = XC4000_BG_PAL_NICAM; + } else { + params->std |= V4L2_STD_NICAM_B; + priv->video_standard = XC4000_BG_PAL_NICAM; + } + } else { + if (!(audio_std & XC4000_AUDIO_STD_B)) { + params->std |= V4L2_STD_A2_A; + priv->video_standard = XC4000_BG_PAL_A2; + } else { + params->std |= V4L2_STD_A2_B; + priv->video_standard = XC4000_BG_PAL_A2; + } + } + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_I) { + /* default to NICAM audio standard */ + params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM; + if (audio_std & XC4000_AUDIO_STD_MONO) + priv->video_standard = XC4000_I_PAL_NICAM_MONO; + else + priv->video_standard = XC4000_I_PAL_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_DK) { + params->std = V4L2_STD_PAL_DK; + if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_DK_PAL_MONO; + } else if (audio_std & XC4000_AUDIO_STD_A2) { + params->std |= V4L2_STD_A2; + priv->video_standard = XC4000_DK_PAL_A2; + } else { + params->std |= V4L2_STD_NICAM; + priv->video_standard = XC4000_DK_PAL_NICAM; + } + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_DK) { + /* default to A2 audio standard */ + params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2; + if (audio_std & XC4000_AUDIO_STD_L) { + type = 0; + priv->video_standard = XC4000_DK_SECAM_NICAM; + } else if (audio_std & XC4000_AUDIO_STD_MONO) { + priv->video_standard = XC4000_DK_SECAM_A2MONO; + } else if (audio_std & XC4000_AUDIO_STD_K3) { + params->std |= V4L2_STD_SECAM_K3; + priv->video_standard = XC4000_DK_SECAM_A2LDK3; + } else { + priv->video_standard = XC4000_DK_SECAM_A2DK1; + } + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_L) { + /* default to NICAM audio standard */ + type = 0; + params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM; + priv->video_standard = XC4000_L_SECAM_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_LC) { + /* default to NICAM audio standard */ + type = 0; + params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM; + priv->video_standard = XC4000_LC_SECAM_NICAM; + goto tune_channel; + } + +tune_channel: + /* FIXME: it could be air. */ + priv->rf_mode = XC_RF_MODE_CABLE; + + if (check_firmware(fe, type, params->std, + xc4000_standard[priv->video_standard].int_freq) != 0) + goto fail; + + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { + printk(KERN_ERR + "xc4000: xc_set_signal_source(%d) failed\n", + priv->rf_mode); + goto fail; + } else { + u16 video_mode, audio_mode; + video_mode = xc4000_standard[priv->video_standard].video_mode; + audio_mode = xc4000_standard[priv->video_standard].audio_mode; + if (priv->video_standard < XC4000_BG_PAL_A2) { + if (type & NOGD) + video_mode &= 0xFF7F; + } else if (priv->video_standard < XC4000_I_PAL_NICAM) { + if (priv->firm_version == 0x0102) + video_mode &= 0xFEFF; + if (audio_std & XC4000_AUDIO_STD_B) + video_mode |= 0x0080; + } + ret = xc_set_tv_standard(priv, video_mode, audio_mode); + if (ret != 0) { + printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); + goto fail; + } + } + + if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) + ret = 0; + if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0) + ret = -EREMOTEIO; + if (priv->set_smoothedcvbs != 0) { + if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) + ret = -EREMOTEIO; + } + if (ret != 0) { + printk(KERN_ERR "xc4000: setting registers failed\n"); + goto fail; + } + + xc_tune_channel(priv, priv->freq_hz); + + ret = 0; + +fail: + mutex_unlock(&priv->lock); + + return ret; +} + +static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc4000_priv *priv = fe->tuner_priv; + + *freq = priv->freq_hz; + + if (debug) { + mutex_lock(&priv->lock); + if ((priv->cur_fw.type + & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) { + u16 snr = 0; + if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) { + mutex_unlock(&priv->lock); + dprintk(1, "%s() freq = %u, SNR = %d\n", + __func__, *freq, snr); + return 0; + } + } + mutex_unlock(&priv->lock); + } + + dprintk(1, "%s()\n", __func__); + + return 0; +} + +static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct xc4000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + *bw = priv->bandwidth; + return 0; +} + +static int xc4000_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct xc4000_priv *priv = fe->tuner_priv; + u16 lock_status = 0; + + mutex_lock(&priv->lock); + + if (priv->cur_fw.type & BASE) + xc_get_lock_status(priv, &lock_status); + + *status = (lock_status == 1 ? + TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0); + if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8)) + *status &= (~TUNER_STATUS_STEREO); + + mutex_unlock(&priv->lock); + + dprintk(2, "%s() lock_status = %d\n", __func__, lock_status); + + return 0; +} + +static int xc4000_sleep(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + int ret = 0; + + dprintk(1, "%s()\n", __func__); + + mutex_lock(&priv->lock); + + /* Avoid firmware reload on slow devices */ + if ((no_poweroff == 2 || + (no_poweroff == 0 && priv->default_pm != 0)) && + (priv->cur_fw.type & BASE) != 0) { + /* force reset and firmware reload */ + priv->cur_fw.type = XC_POWERED_DOWN; + + if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) { + printk(KERN_ERR + "xc4000: %s() unable to shutdown tuner\n", + __func__); + ret = -EREMOTEIO; + } + msleep(20); + } + + mutex_unlock(&priv->lock); + + return ret; +} + +static int xc4000_init(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __func__); + + return 0; +} + +static int xc4000_release(struct dvb_frontend *fe) +{ + struct xc4000_priv *priv = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + + mutex_lock(&xc4000_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&xc4000_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static const struct dvb_tuner_ops xc4000_tuner_ops = { + .info = { + .name = "Xceive XC4000", + .frequency_min = 1000000, + .frequency_max = 1023000000, + .frequency_step = 50000, + }, + + .release = xc4000_release, + .init = xc4000_init, + .sleep = xc4000_sleep, + + .set_params = xc4000_set_params, + .set_analog_params = xc4000_set_analog_params, + .get_frequency = xc4000_get_frequency, + .get_bandwidth = xc4000_get_bandwidth, + .get_status = xc4000_get_status +}; + +struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc4000_config *cfg) +{ + struct xc4000_priv *priv = NULL; + int instance; + u16 id = 0; + + dprintk(1, "%s(%d-%04x)\n", __func__, + i2c ? i2c_adapter_id(i2c) : -1, + cfg ? cfg->i2c_address : -1); + + mutex_lock(&xc4000_list_mutex); + + instance = hybrid_tuner_request_state(struct xc4000_priv, priv, + hybrid_tuner_instance_list, + i2c, cfg->i2c_address, "xc4000"); + switch (instance) { + case 0: + goto fail; + break; + case 1: + /* new tuner instance */ + priv->bandwidth = BANDWIDTH_6_MHZ; + /* set default configuration */ + priv->if_khz = 4560; + priv->default_pm = 0; + priv->dvb_amplitude = 134; + priv->set_smoothedcvbs = 1; + mutex_init(&priv->lock); + fe->tuner_priv = priv; + break; + default: + /* existing tuner instance */ + fe->tuner_priv = priv; + break; + } + + if (cfg->if_khz != 0) { + /* copy configuration if provided by the caller */ + priv->if_khz = cfg->if_khz; + priv->default_pm = cfg->default_pm; + priv->dvb_amplitude = cfg->dvb_amplitude; + priv->set_smoothedcvbs = cfg->set_smoothedcvbs; + } + + /* Check if firmware has been loaded. It is possible that another + instance of the driver has loaded the firmware. + */ + + if (instance == 1) { + if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) + goto fail; + } else { + id = ((priv->cur_fw.type & BASE) != 0 ? + priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED); + } + + switch (id) { + case XC_PRODUCT_ID_XC4000: + case XC_PRODUCT_ID_XC4100: + printk(KERN_INFO + "xc4000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc4000: Firmware has been loaded previously\n"); + break; + case XC_PRODUCT_ID_FW_NOT_LOADED: + printk(KERN_INFO + "xc4000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc4000: Firmware has not been loaded previously\n"); + break; + default: + printk(KERN_ERR + "xc4000: Device not found at addr 0x%02x (0x%x)\n", + cfg->i2c_address, id); + goto fail; + } + + mutex_unlock(&xc4000_list_mutex); + + memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (instance == 1) { + int ret; + mutex_lock(&priv->lock); + ret = xc4000_fwupload(fe); + mutex_unlock(&priv->lock); + if (ret != 0) + goto fail2; + } + + return fe; +fail: + mutex_unlock(&xc4000_list_mutex); +fail2: + xc4000_release(fe); + return NULL; +} +EXPORT_SYMBOL(xc4000_attach); + +MODULE_AUTHOR("Steven Toth, Davide Ferri"); +MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc4000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc4000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc4000.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc4000.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,67 @@ +/* + * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __XC4000_H__ +#define __XC4000_H__ + +#include + +struct dvb_frontend; +struct i2c_adapter; + +struct xc4000_config { + u8 i2c_address; + /* if non-zero, power management is enabled by default */ + u8 default_pm; + /* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */ + u8 dvb_amplitude; + /* if non-zero, register 0x0E is set to filter analog TV video output */ + u8 set_smoothedcvbs; + /* IF for DVB-T */ + u32 if_khz; +}; + +/* xc4000 callback command */ +#define XC4000_TUNER_RESET 0 + +/* For each bridge framework, when it attaches either analog or digital, + * it has to store a reference back to its _core equivalent structure, + * so that it can service the hardware by steering gpio's etc. + * Each bridge implementation is different so cast devptr accordingly. + * The xc4000 driver cares not for this value, other than ensuring + * it's passed back to a bridge during tuner_callback(). + */ + +#if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc4000_config *cfg); +#else +static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc4000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc5000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc5000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc5000.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc5000.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1201 @@ +/* + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Xceive Corporation + * Copyright (c) 2007 Steven Toth + * Copyright (c) 2009 Devin Heitmueller + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "xc5000.h" +#include "tuner-i2c.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +static int no_poweroff; +module_param(no_poweroff, int, 0644); +MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" + "\t\t1 keep device energized and with tuner ready all the times.\n" + "\t\tFaster, but consumes more power and keeps the device hotter"); + +static DEFINE_MUTEX(xc5000_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) + +#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" +#define XC5000_DEFAULT_FIRMWARE_SIZE 12401 + +struct xc5000_priv { + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + + u32 if_khz; + u32 freq_hz; + u32 bandwidth; + u8 video_standard; + u8 rf_mode; + u8 radio_input; +}; + +/* Misc Defines */ +#define MAX_TV_STANDARD 24 +#define XC_MAX_I2C_WRITE_LENGTH 64 + +/* Signal Types */ +#define XC_RF_MODE_AIR 0 +#define XC_RF_MODE_CABLE 1 + +/* Result codes */ +#define XC_RESULT_SUCCESS 0 +#define XC_RESULT_RESET_FAILURE 1 +#define XC_RESULT_I2C_WRITE_FAILURE 2 +#define XC_RESULT_I2C_READ_FAILURE 3 +#define XC_RESULT_OUT_OF_RANGE 5 + +/* Product id */ +#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 +#define XC_PRODUCT_ID_FW_LOADED 0x1388 + +/* Registers */ +#define XREG_INIT 0x00 +#define XREG_VIDEO_MODE 0x01 +#define XREG_AUDIO_MODE 0x02 +#define XREG_RF_FREQ 0x03 +#define XREG_D_CODE 0x04 +#define XREG_IF_OUT 0x05 +#define XREG_SEEK_MODE 0x07 +#define XREG_POWER_DOWN 0x0A /* Obsolete */ +/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */ +#define XREG_OUTPUT_AMP 0x0B +#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ +#define XREG_SMOOTHEDCVBS 0x0E +#define XREG_XTALFREQ 0x0F +#define XREG_FINERFREQ 0x10 +#define XREG_DDIMODE 0x11 + +#define XREG_ADC_ENV 0x00 +#define XREG_QUALITY 0x01 +#define XREG_FRAME_LINES 0x02 +#define XREG_HSYNC_FREQ 0x03 +#define XREG_LOCK 0x04 +#define XREG_FREQ_ERROR 0x05 +#define XREG_SNR 0x06 +#define XREG_VERSION 0x07 +#define XREG_PRODUCT_ID 0x08 +#define XREG_BUSY 0x09 +#define XREG_BUILD 0x0D + +/* + Basic firmware description. This will remain with + the driver for documentation purposes. + + This represents an I2C firmware file encoded as a + string of unsigned char. Format is as follows: + + char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB + char[1 ]=len0_LSB -> length of first write transaction + char[2 ]=data0 -> first byte to be sent + char[3 ]=data1 + char[4 ]=data2 + char[ ]=... + char[M ]=dataN -> last byte to be sent + char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB + char[M+2]=len1_LSB -> length of second write transaction + char[M+3]=data0 + char[M+4]=data1 + ... + etc. + + The [len] value should be interpreted as follows: + + len= len_MSB _ len_LSB + len=1111_1111_1111_1111 : End of I2C_SEQUENCE + len=0000_0000_0000_0000 : Reset command: Do hardware reset + len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) + len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms + + For the RESET and WAIT commands, the two following bytes will contain + immediately the length of the following transaction. + +*/ +struct XC_TV_STANDARD { + char *Name; + u16 AudioMode; + u16 VideoMode; +}; + +/* Tuner standards */ +#define MN_NTSC_PAL_BTSC 0 +#define MN_NTSC_PAL_A2 1 +#define MN_NTSC_PAL_EIAJ 2 +#define MN_NTSC_PAL_Mono 3 +#define BG_PAL_A2 4 +#define BG_PAL_NICAM 5 +#define BG_PAL_MONO 6 +#define I_PAL_NICAM 7 +#define I_PAL_NICAM_MONO 8 +#define DK_PAL_A2 9 +#define DK_PAL_NICAM 10 +#define DK_PAL_MONO 11 +#define DK_SECAM_A2DK1 12 +#define DK_SECAM_A2LDK3 13 +#define DK_SECAM_A2MONO 14 +#define L_SECAM_NICAM 15 +#define LC_SECAM_NICAM 16 +#define DTV6 17 +#define DTV8 18 +#define DTV7_8 19 +#define DTV7 20 +#define FM_Radio_INPUT2 21 +#define FM_Radio_INPUT1 22 +#define FM_Radio_INPUT1_MONO 23 + +static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { + {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, + {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, + {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, + {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, + {"B/G-PAL-A2", 0x0A00, 0x8049}, + {"B/G-PAL-NICAM", 0x0C04, 0x8049}, + {"B/G-PAL-MONO", 0x0878, 0x8059}, + {"I-PAL-NICAM", 0x1080, 0x8009}, + {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, + {"D/K-PAL-A2", 0x1600, 0x8009}, + {"D/K-PAL-NICAM", 0x0E80, 0x8009}, + {"D/K-PAL-MONO", 0x1478, 0x8009}, + {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, + {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009}, + {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, + {"L-SECAM-NICAM", 0x8E82, 0x0009}, + {"L'-SECAM-NICAM", 0x8E82, 0x4009}, + {"DTV6", 0x00C0, 0x8002}, + {"DTV8", 0x00C0, 0x800B}, + {"DTV7/8", 0x00C0, 0x801B}, + {"DTV7", 0x00C0, 0x8007}, + {"FM Radio-INPUT2", 0x9802, 0x9002}, + {"FM Radio-INPUT1", 0x0208, 0x9002}, + {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} +}; + +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); +static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); +static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); +static int xc5000_TunerReset(struct dvb_frontend *fe); + +static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) +{ + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); + return XC_RESULT_I2C_WRITE_FAILURE; + } + return XC_RESULT_SUCCESS; +} + +#if 0 +/* This routine is never used because the only time we read data from the + i2c bus is when we read registers, and we want that to be an atomic i2c + transaction in case we are on a multi-master bus */ +static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) +{ + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = I2C_M_RD, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); + return -EREMOTEIO; + } + return 0; +} +#endif + +static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) +{ + u8 buf[2] = { reg >> 8, reg & 0xff }; + u8 bval[2] = { 0, 0 }; + struct i2c_msg msg[2] = { + { .addr = priv->i2c_props.addr, + .flags = 0, .buf = &buf[0], .len = 2 }, + { .addr = priv->i2c_props.addr, + .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, + }; + + if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { + printk(KERN_WARNING "xc5000: I2C read failed\n"); + return -EREMOTEIO; + } + + *val = (bval[0] << 8) | bval[1]; + return XC_RESULT_SUCCESS; +} + +static void xc_wait(int wait_ms) +{ + msleep(wait_ms); +} + +static int xc5000_TunerReset(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __func__); + + if (fe->callback) { + ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? + fe->dvb->priv : + priv->i2c_props.adap->algo_data, + DVB_FRONTEND_COMPONENT_TUNER, + XC5000_TUNER_RESET, 0); + if (ret) { + printk(KERN_ERR "xc5000: reset failed\n"); + return XC_RESULT_RESET_FAILURE; + } + } else { + printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); + return XC_RESULT_RESET_FAILURE; + } + return XC_RESULT_SUCCESS; +} + +static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) +{ + u8 buf[4]; + int WatchDogTimer = 100; + int result; + + buf[0] = (regAddr >> 8) & 0xFF; + buf[1] = regAddr & 0xFF; + buf[2] = (i2cData >> 8) & 0xFF; + buf[3] = i2cData & 0xFF; + result = xc_send_i2c_data(priv, buf, 4); + if (result == XC_RESULT_SUCCESS) { + /* wait for busy flag to clear */ + while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { + result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf); + if (result == XC_RESULT_SUCCESS) { + if ((buf[0] == 0) && (buf[1] == 0)) { + /* busy flag cleared */ + break; + } else { + xc_wait(5); /* wait 5 ms */ + WatchDogTimer--; + } + } + } + } + if (WatchDogTimer < 0) + result = XC_RESULT_I2C_WRITE_FAILURE; + + return result; +} + +static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + int i, nbytes_to_send, result; + unsigned int len, pos, index; + u8 buf[XC_MAX_I2C_WRITE_LENGTH]; + + index = 0; + while ((i2c_sequence[index] != 0xFF) || + (i2c_sequence[index + 1] != 0xFF)) { + len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; + if (len == 0x0000) { + /* RESET command */ + result = xc5000_TunerReset(fe); + index += 2; + if (result != XC_RESULT_SUCCESS) + return result; + } else if (len & 0x8000) { + /* WAIT command */ + xc_wait(len & 0x7FFF); + index += 2; + } else { + /* Send i2c data whilst ensuring individual transactions + * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. + */ + index += 2; + buf[0] = i2c_sequence[index]; + buf[1] = i2c_sequence[index + 1]; + pos = 2; + while (pos < len) { + if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) + nbytes_to_send = + XC_MAX_I2C_WRITE_LENGTH; + else + nbytes_to_send = (len - pos + 2); + for (i = 2; i < nbytes_to_send; i++) { + buf[i] = i2c_sequence[index + pos + + i - 2]; + } + result = xc_send_i2c_data(priv, buf, + nbytes_to_send); + + if (result != XC_RESULT_SUCCESS) + return result; + + pos += nbytes_to_send - 2; + } + index += len; + } + } + return XC_RESULT_SUCCESS; +} + +static int xc_initialize(struct xc5000_priv *priv) +{ + dprintk(1, "%s()\n", __func__); + return xc_write_reg(priv, XREG_INIT, 0); +} + +static int xc_SetTVStandard(struct xc5000_priv *priv, + u16 VideoMode, u16 AudioMode) +{ + int ret; + dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode); + dprintk(1, "%s() Standard = %s\n", + __func__, + XC5000_Standard[priv->video_standard].Name); + + ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); + if (ret == XC_RESULT_SUCCESS) + ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); + + return ret; +} + +static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) +{ + dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, + rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); + + if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { + rf_mode = XC_RF_MODE_CABLE; + printk(KERN_ERR + "%s(), Invalid mode, defaulting to CABLE", + __func__); + } + return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); +} + +static const struct dvb_tuner_ops xc5000_tuner_ops; + +static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) +{ + u16 freq_code; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || + (freq_hz < xc5000_tuner_ops.info.frequency_min)) + return XC_RESULT_OUT_OF_RANGE; + + freq_code = (u16)(freq_hz / 15625); + + /* Starting in firmware version 1.1.44, Xceive recommends using the + FINERFREQ for all normal tuning (the doc indicates reg 0x03 should + only be used for fast scanning for channel lock) */ + return xc_write_reg(priv, XREG_FINERFREQ, freq_code); +} + + +static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) +{ + u32 freq_code = (freq_khz * 1024)/1000; + dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", + __func__, freq_khz, freq_code); + + return xc_write_reg(priv, XREG_IF_OUT, freq_code); +} + + +static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) +{ + return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); +} + +static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) +{ + int result; + u16 regData; + u32 tmp; + + result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data); + if (result != XC_RESULT_SUCCESS) + return result; + + tmp = (u32)regData; + (*freq_error_hz) = (tmp * 15625) / 1000; + return result; +} + +static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) +{ + return xc5000_readreg(priv, XREG_LOCK, lock_status); +} + +static int xc_get_version(struct xc5000_priv *priv, + u8 *hw_majorversion, u8 *hw_minorversion, + u8 *fw_majorversion, u8 *fw_minorversion) +{ + u16 data; + int result; + + result = xc5000_readreg(priv, XREG_VERSION, &data); + if (result != XC_RESULT_SUCCESS) + return result; + + (*hw_majorversion) = (data >> 12) & 0x0F; + (*hw_minorversion) = (data >> 8) & 0x0F; + (*fw_majorversion) = (data >> 4) & 0x0F; + (*fw_minorversion) = data & 0x0F; + + return 0; +} + +static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) +{ + return xc5000_readreg(priv, XREG_BUILD, buildrev); +} + +static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) +{ + u16 regData; + int result; + + result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data); + if (result != XC_RESULT_SUCCESS) + return result; + + (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; + return result; +} + +static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) +{ + return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); +} + +static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) +{ + return xc5000_readreg(priv, XREG_QUALITY, quality); +} + +static u16 WaitForLock(struct xc5000_priv *priv) +{ + u16 lockState = 0; + int watchDogCount = 40; + + while ((lockState == 0) && (watchDogCount > 0)) { + xc_get_lock_status(priv, &lockState); + if (lockState != 1) { + xc_wait(5); + watchDogCount--; + } + } + return lockState; +} + +#define XC_TUNE_ANALOG 0 +#define XC_TUNE_DIGITAL 1 +static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) +{ + int found = 0; + + dprintk(1, "%s(%u)\n", __func__, freq_hz); + + if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) + return 0; + + if (mode == XC_TUNE_ANALOG) { + if (WaitForLock(priv) == 1) + found = 1; + } + + return found; +} + + +static int xc5000_fwupload(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + const struct firmware *fw; + int ret; + + /* request the firmware, this will block and timeout */ + printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", + XC5000_DEFAULT_FIRMWARE); + + ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, + priv->i2c_props.adap->dev.parent); + if (ret) { + printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); + ret = XC_RESULT_RESET_FAILURE; + goto out; + } else { + printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n", + fw->size); + ret = XC_RESULT_SUCCESS; + } + + if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { + printk(KERN_ERR "xc5000: firmware incorrect size\n"); + ret = XC_RESULT_RESET_FAILURE; + } else { + printk(KERN_INFO "xc5000: firmware uploading...\n"); + ret = xc_load_i2c_sequence(fe, fw->data); + printk(KERN_INFO "xc5000: firmware upload complete...\n"); + } + +out: + release_firmware(fw); + return ret; +} + +static void xc_debug_dump(struct xc5000_priv *priv) +{ + u16 adc_envelope; + u32 freq_error_hz = 0; + u16 lock_status; + u32 hsync_freq_hz = 0; + u16 frame_lines; + u16 quality; + u8 hw_majorversion = 0, hw_minorversion = 0; + u8 fw_majorversion = 0, fw_minorversion = 0; + u16 fw_buildversion = 0; + + /* Wait for stats to stabilize. + * Frame Lines needs two frame times after initial lock + * before it is valid. + */ + xc_wait(100); + + xc_get_ADC_Envelope(priv, &adc_envelope); + dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); + + xc_get_frequency_error(priv, &freq_error_hz); + dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); + + xc_get_lock_status(priv, &lock_status); + dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", + lock_status); + + xc_get_version(priv, &hw_majorversion, &hw_minorversion, + &fw_majorversion, &fw_minorversion); + xc_get_buildversion(priv, &fw_buildversion); + dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n", + hw_majorversion, hw_minorversion, + fw_majorversion, fw_minorversion, fw_buildversion); + + xc_get_hsync_freq(priv, &hsync_freq_hz); + dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); + + xc_get_frame_lines(priv, &frame_lines); + dprintk(1, "*** Frame lines = %d\n", frame_lines); + + xc_get_quality(priv, &quality); + dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); +} + +/* + * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. + * So, the amount of the needed bandwith is given by: + * Bw = Symbol_rate * (1 + 0.15) + * As such, the maximum symbol rate supported by 6 MHz is given by: + * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds + */ +#define MAX_SYMBOL_RATE_6MHz 5217391 + +static int xc5000_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { + if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { + dprintk(1, "Unable to load firmware and init tuner\n"); + return -EINVAL; + } + } + + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); + + if (fe->ops.info.type == FE_ATSC) { + dprintk(1, "%s() ATSC\n", __func__); + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + break; + case QAM_64: + case QAM_256: + case QAM_AUTO: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + break; + default: + return -EINVAL; + } + } else if (fe->ops.info.type == FE_OFDM) { + dprintk(1, "%s() OFDM\n", __func__); + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + priv->freq_hz = params->frequency - 1750000; + break; + case BANDWIDTH_7_MHZ: + printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n"); + return -EINVAL; + case BANDWIDTH_8_MHZ: + priv->bandwidth = BANDWIDTH_8_MHZ; + priv->video_standard = DTV8; + priv->freq_hz = params->frequency - 2750000; + break; + default: + printk(KERN_ERR "xc5000 bandwidth not set!\n"); + return -EINVAL; + } + priv->rf_mode = XC_RF_MODE_AIR; + } else if (fe->ops.info.type == FE_QAM) { + switch (params->u.qam.modulation) { + case QAM_256: + case QAM_AUTO: + case QAM_16: + case QAM_32: + case QAM_64: + case QAM_128: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + /* + * Using a 8MHz bandwidth sometimes fail + * with 6MHz-spaced channels, due to inter-carrier + * interference. So, use DTV6 firmware + */ + if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) { + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + priv->freq_hz = params->frequency - 1750000; + } else { + priv->bandwidth = BANDWIDTH_8_MHZ; + priv->video_standard = DTV7_8; + priv->freq_hz = params->frequency - 2750000; + } + break; + default: + dprintk(1, "%s() Unsupported QAM type\n", __func__); + return -EINVAL; + } + } else { + printk(KERN_ERR "xc5000 modulation type not supported!\n"); + return -EINVAL; + } + + dprintk(1, "%s() frequency=%d (compensated)\n", + __func__, priv->freq_hz); + + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_SetTVStandard(priv, + XC5000_Standard[priv->video_standard].VideoMode, + XC5000_Standard[priv->video_standard].AudioMode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + ret = xc_set_IF_frequency(priv, priv->if_khz); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", + priv->if_khz); + return -EIO; + } + + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); + + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); + + if (debug) + xc_debug_dump(priv); + + return 0; +} + +static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + u16 id; + + ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id); + if (ret == XC_RESULT_SUCCESS) { + if (id == XC_PRODUCT_ID_FW_NOT_LOADED) + ret = XC_RESULT_RESET_FAILURE; + else + ret = XC_RESULT_SUCCESS; + } + + dprintk(1, "%s() returns %s id = 0x%x\n", __func__, + ret == XC_RESULT_SUCCESS ? "True" : "False", id); + return ret; +} + +static int xc5000_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", + __func__, params->frequency); + + /* Fix me: it could be air. */ + priv->rf_mode = params->mode; + if (params->mode > XC_RF_MODE_CABLE) + priv->rf_mode = XC_RF_MODE_CABLE; + + /* params->frequency is in units of 62.5khz */ + priv->freq_hz = params->frequency * 62500; + + /* FIX ME: Some video standards may have several possible audio + standards. We simply default to one of them here. + */ + if (params->std & V4L2_STD_MN) { + /* default to BTSC audio standard */ + priv->video_standard = MN_NTSC_PAL_BTSC; + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_BG) { + /* default to NICAM audio standard */ + priv->video_standard = BG_PAL_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_I) { + /* default to NICAM audio standard */ + priv->video_standard = I_PAL_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_PAL_DK) { + /* default to NICAM audio standard */ + priv->video_standard = DK_PAL_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_DK) { + /* default to A2 DK1 audio standard */ + priv->video_standard = DK_SECAM_A2DK1; + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_L) { + priv->video_standard = L_SECAM_NICAM; + goto tune_channel; + } + + if (params->std & V4L2_STD_SECAM_LC) { + priv->video_standard = LC_SECAM_NICAM; + goto tune_channel; + } + +tune_channel: + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_SetTVStandard(priv, + XC5000_Standard[priv->video_standard].VideoMode, + XC5000_Standard[priv->video_standard].AudioMode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); + + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); + + if (debug) + xc_debug_dump(priv); + + return 0; +} + +static int xc5000_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + u8 radio_input; + + dprintk(1, "%s() frequency=%d (in units of khz)\n", + __func__, params->frequency); + + if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) { + dprintk(1, "%s() radio input not configured\n", __func__); + return -EINVAL; + } + + if (priv->radio_input == XC5000_RADIO_FM1) + radio_input = FM_Radio_INPUT1; + else if (priv->radio_input == XC5000_RADIO_FM2) + radio_input = FM_Radio_INPUT2; + else if (priv->radio_input == XC5000_RADIO_FM1_MONO) + radio_input = FM_Radio_INPUT1_MONO; + else { + dprintk(1, "%s() unknown radio input %d\n", __func__, + priv->radio_input); + return -EINVAL; + } + + priv->freq_hz = params->frequency * 125 / 2; + + priv->rf_mode = XC_RF_MODE_AIR; + + ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode, + XC5000_Standard[radio_input].AudioMode); + + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + if ((priv->radio_input == XC5000_RADIO_FM1) || + (priv->radio_input == XC5000_RADIO_FM2)) + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); + else if (priv->radio_input == XC5000_RADIO_FM1_MONO) + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06); + + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); + + return 0; +} + +static int xc5000_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + + if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { + if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { + dprintk(1, "Unable to load firmware and init tuner\n"); + return -EINVAL; + } + } + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = xc5000_set_radio_freq(fe, params); + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = xc5000_set_tv_freq(fe, params); + break; + } + + return ret; +} + + +static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + *freq = priv->freq_hz; + return 0; +} + +static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + *bw = priv->bandwidth; + return 0; +} + +static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct xc5000_priv *priv = fe->tuner_priv; + u16 lock_status = 0; + + xc_get_lock_status(priv, &lock_status); + + dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status); + + *status = lock_status; + + return 0; +} + +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret = 0; + + if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { + ret = xc5000_fwupload(fe); + if (ret != XC_RESULT_SUCCESS) + return ret; + } + + /* Start the tuner self-calibration process */ + ret |= xc_initialize(priv); + + /* Wait for calibration to complete. + * We could continue but XC5000 will clock stretch subsequent + * I2C transactions until calibration is complete. This way we + * don't have to rely on clock stretching working. + */ + xc_wait(100); + + /* Default to "CABLE" mode */ + ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); + + return ret; +} + +static int xc5000_sleep(struct dvb_frontend *fe) +{ + int ret; + + dprintk(1, "%s()\n", __func__); + + /* Avoid firmware reload on slow devices */ + if (no_poweroff) + return 0; + + /* According to Xceive technical support, the "powerdown" register + was removed in newer versions of the firmware. The "supported" + way to sleep the tuner is to pull the reset pin low for 10ms */ + ret = xc5000_TunerReset(fe); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: %s() unable to shutdown tuner\n", + __func__); + return -EREMOTEIO; + } else + return XC_RESULT_SUCCESS; +} + +static int xc5000_init(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + + if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); + return -EREMOTEIO; + } + + if (debug) + xc_debug_dump(priv); + + return 0; +} + +static int xc5000_release(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + + mutex_lock(&xc5000_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&xc5000_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct xc5000_priv *priv = fe->tuner_priv; + struct xc5000_config *p = priv_cfg; + + dprintk(1, "%s()\n", __func__); + + if (p->if_khz) + priv->if_khz = p->if_khz; + + if (p->radio_input) + priv->radio_input = p->radio_input; + + return 0; +} + + +static const struct dvb_tuner_ops xc5000_tuner_ops = { + .info = { + .name = "Xceive XC5000", + .frequency_min = 1000000, + .frequency_max = 1023000000, + .frequency_step = 50000, + }, + + .release = xc5000_release, + .init = xc5000_init, + .sleep = xc5000_sleep, + + .set_config = xc5000_set_config, + .set_params = xc5000_set_params, + .set_analog_params = xc5000_set_analog_params, + .get_frequency = xc5000_get_frequency, + .get_bandwidth = xc5000_get_bandwidth, + .get_status = xc5000_get_status +}; + +struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct xc5000_config *cfg) +{ + struct xc5000_priv *priv = NULL; + int instance; + u16 id = 0; + + dprintk(1, "%s(%d-%04x)\n", __func__, + i2c ? i2c_adapter_id(i2c) : -1, + cfg ? cfg->i2c_address : -1); + + mutex_lock(&xc5000_list_mutex); + + instance = hybrid_tuner_request_state(struct xc5000_priv, priv, + hybrid_tuner_instance_list, + i2c, cfg->i2c_address, "xc5000"); + switch (instance) { + case 0: + goto fail; + break; + case 1: + /* new tuner instance */ + priv->bandwidth = BANDWIDTH_6_MHZ; + fe->tuner_priv = priv; + break; + default: + /* existing tuner instance */ + fe->tuner_priv = priv; + break; + } + + if (priv->if_khz == 0) { + /* If the IF hasn't been set yet, use the value provided by + the caller (occurs in hybrid devices where the analog + call to xc5000_attach occurs before the digital side) */ + priv->if_khz = cfg->if_khz; + } + + if (priv->radio_input == 0) + priv->radio_input = cfg->radio_input; + + /* Check if firmware has been loaded. It is possible that another + instance of the driver has loaded the firmware. + */ + if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) + goto fail; + + switch (id) { + case XC_PRODUCT_ID_FW_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has been loaded previously\n"); + break; + case XC_PRODUCT_ID_FW_NOT_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has not been loaded previously\n"); + break; + default: + printk(KERN_ERR + "xc5000: Device not found at addr 0x%02x (0x%x)\n", + cfg->i2c_address, id); + goto fail; + } + + mutex_unlock(&xc5000_list_mutex); + + memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +fail: + mutex_unlock(&xc5000_list_mutex); + + xc5000_release(fe); + return NULL; +} +EXPORT_SYMBOL(xc5000_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc5000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc5000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc5000.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/common/tuners/xc5000.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __XC5000_H__ +#define __XC5000_H__ + +#include + +struct dvb_frontend; +struct i2c_adapter; + +struct xc5000_config { + u8 i2c_address; + u32 if_khz; + u8 radio_input; +}; + +/* xc5000 callback command */ +#define XC5000_TUNER_RESET 0 + +/* Possible Radio inputs */ +#define XC5000_RADIO_NOT_CONFIGURED 0 +#define XC5000_RADIO_FM1 1 +#define XC5000_RADIO_FM2 2 +#define XC5000_RADIO_FM1_MONO 3 + +/* For each bridge framework, when it attaches either analog or digital, + * it has to store a reference back to its _core equivalent structure, + * so that it can service the hardware by steering gpio's etc. + * Each bridge implementation is different so cast devptr accordingly. + * The xc5000 driver cares not for this value, other than ensuring + * it's passed back to a bridge during tuner_callback(). + */ + +#if defined(CONFIG_MEDIA_TUNER_XC5000) || \ + (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct xc5000_config *cfg); +#else +static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct xc5000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,311 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop.c - main module part + * Copyright (C) 2004-9 Patrick Boettcher + * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc + * + * Acknowledgements: + * John Jurrius from BBTI, Inc. for extensive support + * with code examples and data books + * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting) + * + * Contributions to the skystar2-driver have been done by + * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes) + * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code) + * Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu) + * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac + * filtering) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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 "flexcop.h" + +#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip" +#define DRIVER_AUTHOR "Patrick Boettcher demux->priv; + return flexcop_pid_feed_control(fc, dvbdmxfeed, 1); +} + +static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct flexcop_device *fc = dvbdmxfeed->demux->priv; + return flexcop_pid_feed_control(fc, dvbdmxfeed, 0); +} + +static int flexcop_dvb_init(struct flexcop_device *fc) +{ + int ret = dvb_register_adapter(&fc->dvb_adapter, + "FlexCop Digital TV device", fc->owner, + fc->dev, adapter_nr); + if (ret < 0) { + err("error registering DVB adapter"); + return ret; + } + fc->dvb_adapter.priv = fc; + + fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING + | DMX_MEMORY_BASED_FILTERING); + fc->demux.priv = fc; + fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED; + fc->demux.start_feed = flexcop_dvb_start_feed; + fc->demux.stop_feed = flexcop_dvb_stop_feed; + fc->demux.write_to_decoder = NULL; + + if ((ret = dvb_dmx_init(&fc->demux)) < 0) { + err("dvb_dmx failed: error %d", ret); + goto err_dmx; + } + + fc->hw_frontend.source = DMX_FRONTEND_0; + + fc->dmxdev.filternum = fc->demux.feednum; + fc->dmxdev.demux = &fc->demux.dmx; + fc->dmxdev.capabilities = 0; + if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) { + err("dvb_dmxdev_init failed: error %d", ret); + goto err_dmx_dev; + } + + if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { + err("adding hw_frontend to dmx failed: error %d", ret); + goto err_dmx_add_hw_frontend; + } + + fc->mem_frontend.source = DMX_MEMORY_FE; + if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) { + err("adding mem_frontend to dmx failed: error %d", ret); + goto err_dmx_add_mem_frontend; + } + + if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { + err("connect frontend failed: error %d", ret); + goto err_connect_frontend; + } + + dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); + + fc->init_state |= FC_STATE_DVB_INIT; + return 0; + +err_connect_frontend: + fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend); +err_dmx_add_mem_frontend: + fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend); +err_dmx_add_hw_frontend: + dvb_dmxdev_release(&fc->dmxdev); +err_dmx_dev: + dvb_dmx_release(&fc->demux); +err_dmx: + dvb_unregister_adapter(&fc->dvb_adapter); + return ret; +} + +static void flexcop_dvb_exit(struct flexcop_device *fc) +{ + if (fc->init_state & FC_STATE_DVB_INIT) { + dvb_net_release(&fc->dvbnet); + + fc->demux.dmx.close(&fc->demux.dmx); + fc->demux.dmx.remove_frontend(&fc->demux.dmx, + &fc->mem_frontend); + fc->demux.dmx.remove_frontend(&fc->demux.dmx, + &fc->hw_frontend); + dvb_dmxdev_release(&fc->dmxdev); + dvb_dmx_release(&fc->demux); + dvb_unregister_adapter(&fc->dvb_adapter); + deb_info("deinitialized dvb stuff\n"); + } + fc->init_state &= ~FC_STATE_DVB_INIT; +} + +/* these methods are necessary to achieve the long-term-goal of hiding the + * struct flexcop_device from the bus-parts */ +void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len) +{ + dvb_dmx_swfilter(&fc->demux, buf, len); +} +EXPORT_SYMBOL(flexcop_pass_dmx_data); + +void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no) +{ + dvb_dmx_swfilter_packets(&fc->demux, buf, no); +} +EXPORT_SYMBOL(flexcop_pass_dmx_packets); + +static void flexcop_reset(struct flexcop_device *fc) +{ + flexcop_ibi_value v210, v204; + + /* reset the flexcop itself */ + fc->write_ibi_reg(fc,ctrl_208,ibi_zero); + + v210.raw = 0; + v210.sw_reset_210.reset_block_000 = 1; + v210.sw_reset_210.reset_block_100 = 1; + v210.sw_reset_210.reset_block_200 = 1; + v210.sw_reset_210.reset_block_300 = 1; + v210.sw_reset_210.reset_block_400 = 1; + v210.sw_reset_210.reset_block_500 = 1; + v210.sw_reset_210.reset_block_600 = 1; + v210.sw_reset_210.reset_block_700 = 1; + v210.sw_reset_210.Block_reset_enable = 0xb2; + v210.sw_reset_210.Special_controls = 0xc259; + fc->write_ibi_reg(fc,sw_reset_210,v210); + msleep(1); + + /* reset the periphical devices */ + + v204 = fc->read_ibi_reg(fc,misc_204); + v204.misc_204.Per_reset_sig = 0; + fc->write_ibi_reg(fc,misc_204,v204); + msleep(1); + v204.misc_204.Per_reset_sig = 1; + fc->write_ibi_reg(fc,misc_204,v204); +} + +void flexcop_reset_block_300(struct flexcop_device *fc) +{ + flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208), + v210 = fc->read_ibi_reg(fc, sw_reset_210); + + deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw); + fc->write_ibi_reg(fc,ctrl_208,ibi_zero); + + v210.sw_reset_210.reset_block_300 = 1; + v210.sw_reset_210.Block_reset_enable = 0xb2; + + fc->write_ibi_reg(fc,sw_reset_210,v210); + fc->write_ibi_reg(fc,ctrl_208,v208_save); +} + +struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) +{ + void *bus; + struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device), + GFP_KERNEL); + if (!fc) { + err("no memory"); + return NULL; + } + + bus = kzalloc(bus_specific_len, GFP_KERNEL); + if (!bus) { + err("no memory"); + kfree(fc); + return NULL; + } + + fc->bus_specific = bus; + + return fc; +} +EXPORT_SYMBOL(flexcop_device_kmalloc); + +void flexcop_device_kfree(struct flexcop_device *fc) +{ + kfree(fc->bus_specific); + kfree(fc); +} +EXPORT_SYMBOL(flexcop_device_kfree); + +int flexcop_device_initialize(struct flexcop_device *fc) +{ + int ret; + ibi_zero.raw = 0; + + flexcop_reset(fc); + flexcop_determine_revision(fc); + flexcop_sram_init(fc); + flexcop_hw_filter_init(fc); + flexcop_smc_ctrl(fc, 0); + + if ((ret = flexcop_dvb_init(fc))) + goto error; + + /* i2c has to be done before doing EEProm stuff - + * because the EEProm is accessed via i2c */ + ret = flexcop_i2c_init(fc); + if (ret) + goto error; + + /* do the MAC address reading after initializing the dvb_adapter */ + if (fc->get_mac_addr(fc, 0) == 0) { + u8 *b = fc->dvb_adapter.proposed_mac; + info("MAC address = %pM", b); + flexcop_set_mac_filter(fc,b); + flexcop_mac_filter_ctrl(fc,1); + } else + warn("reading of MAC address failed.\n"); + + if ((ret = flexcop_frontend_init(fc))) + goto error; + + flexcop_device_name(fc,"initialization of","complete"); + return 0; + +error: + flexcop_device_exit(fc); + return ret; +} +EXPORT_SYMBOL(flexcop_device_initialize); + +void flexcop_device_exit(struct flexcop_device *fc) +{ + flexcop_frontend_exit(fc); + flexcop_i2c_exit(fc); + flexcop_dvb_exit(fc); +} +EXPORT_SYMBOL(flexcop_device_exit); + +static int flexcop_module_init(void) +{ + info(DRIVER_NAME " loaded successfully"); + return 0; +} + +static void flexcop_module_cleanup(void) +{ + info(DRIVER_NAME " unloaded successfully"); +} + +module_init(flexcop_module_init); +module_exit(flexcop_module_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-common.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-common.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,184 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-common.h - common header file for device-specific source files + * see flexcop.c for copyright information + */ +#ifndef __FLEXCOP_COMMON_H__ +#define __FLEXCOP_COMMON_H__ + +#include +#include + +#include "flexcop-reg.h" + +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_filter.h" +#include "dvb_net.h" +#include "dvb_frontend.h" + +#define FC_MAX_FEED 256 + +#ifndef FC_LOG_PREFIX +#warning please define a log prefix for your file, using a default one +#define FC_LOG_PREFIX "b2c2-undef" +#endif + +/* Steal from usb.h */ +#undef err +#define err(format, arg...) \ + printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) \ + printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) \ + printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg) + +struct flexcop_dma { + struct pci_dev *pdev; + + u8 *cpu_addr0; + dma_addr_t dma_addr0; + u8 *cpu_addr1; + dma_addr_t dma_addr1; + u32 size; /* size of each address in bytes */ +}; + +struct flexcop_i2c_adapter { + struct flexcop_device *fc; + struct i2c_adapter i2c_adap; + + u8 no_base_addr; + flexcop_i2c_port_t port; +}; + +/* Control structure for data definitions that are common to + * the B2C2-based PCI and USB devices. + */ +struct flexcop_device { + /* general */ + struct device *dev; /* for firmware_class */ + +#define FC_STATE_DVB_INIT 0x01 +#define FC_STATE_I2C_INIT 0x02 +#define FC_STATE_FE_INIT 0x04 + int init_state; + + /* device information */ + int has_32_hw_pid_filter; + flexcop_revision_t rev; + flexcop_device_type_t dev_type; + flexcop_bus_t bus_type; + + /* dvb stuff */ + struct dvb_adapter dvb_adapter; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + int (*fe_sleep) (struct dvb_frontend *); + + struct flexcop_i2c_adapter fc_i2c_adap[3]; + struct mutex i2c_mutex; + struct module *owner; + + /* options and status */ + int extra_feedcount; + int feedcount; + int pid_filtering; + int fullts_streaming_state; + + /* bus specific callbacks */ + flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *, + flexcop_ibi_register); + int (*write_ibi_reg) (struct flexcop_device *, + flexcop_ibi_register, flexcop_ibi_value); + int (*i2c_request) (struct flexcop_i2c_adapter *, + flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); + int (*stream_control) (struct flexcop_device *, int); + int (*get_mac_addr) (struct flexcop_device *fc, int extended); + void *bus_specific; +}; + +/* exported prototypes */ + +/* from flexcop.c */ +void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len); +void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no); + +struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len); +void flexcop_device_kfree(struct flexcop_device *); + +int flexcop_device_initialize(struct flexcop_device *); +void flexcop_device_exit(struct flexcop_device *fc); +void flexcop_reset_block_300(struct flexcop_device *fc); + +/* from flexcop-dma.c */ +int flexcop_dma_allocate(struct pci_dev *pdev, + struct flexcop_dma *dma, u32 size); +void flexcop_dma_free(struct flexcop_dma *dma); + +int flexcop_dma_control_timer_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, int onoff); +int flexcop_dma_control_size_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, int onoff); +int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, + flexcop_dma_index_t dma_idx); +int flexcop_dma_xfer_control(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, + int onoff); +int flexcop_dma_config_timer(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, u8 cycles); + +/* from flexcop-eeprom.c */ +/* the PCI part uses this call to get the MAC address, the USB part has its own */ +int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended); + +/* from flexcop-i2c.c */ +/* the PCI part uses this a i2c_request callback, whereas the usb part has its own + * one. We have it in flexcop-i2c.c, because it is going via the actual + * I2C-channel of the flexcop. + */ +int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t, + u8 chipaddr, u8 addr, u8 *buf, u16 len); + +/* from flexcop-sram.c */ +int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, + flexcop_sram_dest_target_t target); +void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s); +void flexcop_sram_ctrl(struct flexcop_device *fc, + int usb_wan, int sramdma, int maximumfill); + +/* global prototypes for the flexcop-chip */ +/* from flexcop-fe-tuner.c */ +int flexcop_frontend_init(struct flexcop_device *fc); +void flexcop_frontend_exit(struct flexcop_device *fc); + +/* from flexcop-i2c.c */ +int flexcop_i2c_init(struct flexcop_device *fc); +void flexcop_i2c_exit(struct flexcop_device *fc); + +/* from flexcop-sram.c */ +int flexcop_sram_init(struct flexcop_device *fc); + +/* from flexcop-misc.c */ +void flexcop_determine_revision(struct flexcop_device *fc); +void flexcop_device_name(struct flexcop_device *fc, + const char *prefix, const char *suffix); +void flexcop_dump_reg(struct flexcop_device *fc, + flexcop_ibi_register reg, int num); + +/* from flexcop-hw-filter.c */ +int flexcop_pid_feed_control(struct flexcop_device *fc, + struct dvb_demux_feed *dvbdmxfeed, int onoff); +void flexcop_hw_filter_init(struct flexcop_device *fc); + +void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff); + +void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]); +void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-dma.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-dma.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-dma.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-dma.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,172 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-dma.c - configuring and controlling the DMA of the FlexCop + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +int flexcop_dma_allocate(struct pci_dev *pdev, + struct flexcop_dma *dma, u32 size) +{ + u8 *tcpu; + dma_addr_t tdma = 0; + + if (size % 2) { + err("dma buffersize has to be even."); + return -EINVAL; + } + + if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) { + dma->pdev = pdev; + dma->cpu_addr0 = tcpu; + dma->dma_addr0 = tdma; + dma->cpu_addr1 = tcpu + size/2; + dma->dma_addr1 = tdma + size/2; + dma->size = size/2; + return 0; + } + return -ENOMEM; +} +EXPORT_SYMBOL(flexcop_dma_allocate); + +void flexcop_dma_free(struct flexcop_dma *dma) +{ + pci_free_consistent(dma->pdev, dma->size*2, + dma->cpu_addr0, dma->dma_addr0); + memset(dma,0,sizeof(struct flexcop_dma)); +} +EXPORT_SYMBOL(flexcop_dma_free); + +int flexcop_dma_config(struct flexcop_device *fc, + struct flexcop_dma *dma, + flexcop_dma_index_t dma_idx) +{ + flexcop_ibi_value v0x0,v0x4,v0xc; + v0x0.raw = v0x4.raw = v0xc.raw = 0; + + v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; + v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; + v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; + + if ((dma_idx & FC_DMA_1) == dma_idx) { + fc->write_ibi_reg(fc,dma1_000,v0x0); + fc->write_ibi_reg(fc,dma1_004,v0x4); + fc->write_ibi_reg(fc,dma1_00c,v0xc); + } else if ((dma_idx & FC_DMA_2) == dma_idx) { + fc->write_ibi_reg(fc,dma2_010,v0x0); + fc->write_ibi_reg(fc,dma2_014,v0x4); + fc->write_ibi_reg(fc,dma2_01c,v0xc); + } else { + err("either DMA1 or DMA2 can be configured within one " + "flexcop_dma_config call."); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config); + +/* start the DMA transfers, but not the DMA IRQs */ +int flexcop_dma_xfer_control(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + flexcop_dma_addr_index_t index, + int onoff) +{ + flexcop_ibi_value v0x0,v0xc; + flexcop_ibi_register r0x0,r0xc; + + if ((dma_idx & FC_DMA_1) == dma_idx) { + r0x0 = dma1_000; + r0xc = dma1_00c; + } else if ((dma_idx & FC_DMA_2) == dma_idx) { + r0x0 = dma2_010; + r0xc = dma2_01c; + } else { + err("either transfer DMA1 or DMA2 can be started within one " + "flexcop_dma_xfer_control call."); + return -EINVAL; + } + + v0x0 = fc->read_ibi_reg(fc,r0x0); + v0xc = fc->read_ibi_reg(fc,r0xc); + + deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); + deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); + + if (index & FC_DMA_SUBADDR_0) + v0x0.dma_0x0.dma_0start = onoff; + + if (index & FC_DMA_SUBADDR_1) + v0xc.dma_0xc.dma_1start = onoff; + + fc->write_ibi_reg(fc,r0x0,v0x0); + fc->write_ibi_reg(fc,r0xc,v0xc); + + deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); + deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_xfer_control); + +static int flexcop_dma_remap(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + int onoff) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + deb_info("%s\n",__func__); + v.dma_0xc.remap_enable = onoff; + fc->write_ibi_reg(fc,r,v); + return 0; +} + +int flexcop_dma_control_size_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_IRQ_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_IRQ_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_size_irq); + +int flexcop_dma_control_timer_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_Timer_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_Timer_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_timer_irq); + +/* 1 cycles = 1.97 msec */ +int flexcop_dma_config_timer(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, u8 cycles) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + + flexcop_dma_remap(fc,dma_idx,0); + + deb_info("%s\n",__func__); + v.dma_0x4_write.dmatimer = cycles; + fc->write_ibi_reg(fc,r,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config_timer); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-eeprom.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-eeprom.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-eeprom.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-eeprom.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,147 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading) + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +#if 0 +/*EEPROM (Skystar2 has one "24LC08B" chip on board) */ +static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len) +{ + return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len); +} + +static int eeprom_lrc_write(struct adapter *adapter, u32 addr, + u32 len, u8 *wbuf, u8 *rbuf, int retries) +{ +int i; + +for (i = 0; i < retries; i++) { + if (eeprom_write(adapter, addr, wbuf, len) == len) { + if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1) + return 1; + } + } + return 0; +} + +/* These functions could be used to unlock SkyStar2 cards. */ + +static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len) +{ + u8 rbuf[20]; + u8 wbuf[20]; + + if (len != 16) + return 0; + + memcpy(wbuf, key, len); + wbuf[16] = 0; + wbuf[17] = 0; + wbuf[18] = 0; + wbuf[19] = calc_lrc(wbuf, 19); + return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4); +} + +static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len) +{ + u8 buf[20]; + + if (len != 16) + return 0; + + if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0) + return 0; + + memcpy(key, buf, len); + return 1; +} + +static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac) +{ + u8 tmp[8]; + + if (type != 0) { + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[5]; + tmp[4] = mac[6]; + tmp[5] = mac[7]; + } else { + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[3]; + tmp[4] = mac[4]; + tmp[5] = mac[5]; + } + + tmp[6] = 0; + tmp[7] = calc_lrc(tmp, 7); + + if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8) + return 1; + return 0; +} + +static int flexcop_eeprom_read(struct flexcop_device *fc, + u16 addr, u8 *buf, u16 len) +{ + return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len); +} + +#endif + +static u8 calc_lrc(u8 *buf, int len) +{ + int i; + u8 sum = 0; + for (i = 0; i < len; i++) + sum = sum ^ buf[i]; + return sum; +} + +static int flexcop_eeprom_request(struct flexcop_device *fc, + flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries) +{ + int i,ret = 0; + u8 chipaddr = 0x50 | ((addr >> 8) & 3); + for (i = 0; i < retries; i++) { + ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr, + addr & 0xff, buf, len); + if (ret == 0) + break; + } + return ret; +} + +static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, + u8 *buf, u16 len, int retries) +{ + int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries); + if (ret == 0) + if (calc_lrc(buf, len - 1) != buf[len - 1]) + ret = -EINVAL; + return ret; +} + +/* JJ's comment about extended == 1: it is not presently used anywhere but was + * added to the low-level functions for possible support of EUI64 */ +int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended) +{ + u8 buf[8]; + int ret = 0; + + if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) { + if (extended != 0) { + err("TODO: extended (EUI64) MAC addresses aren't " + "completely supported yet"); + ret = -EINVAL; + } else + memcpy(fc->dvb_adapter.proposed_mac,buf,6); + } + return ret; +} +EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,678 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling + * see flexcop.c for copyright information + */ +#include +#include "flexcop.h" +#include "mt312.h" +#include "stv0299.h" +#include "s5h1420.h" +#include "itd1000.h" +#include "cx24113.h" +#include "cx24123.h" +#include "isl6421.h" +#include "mt352.h" +#include "bcm3510.h" +#include "nxt200x.h" +#include "dvb-pll.h" +#include "lgdt330x.h" +#include "tuner-simple.h" +#include "stv0297.h" + + +/* Can we use the specified front-end? Remember that if we are compiled + * into the kernel we can't call code that's in modules. */ +#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \ + (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE))) + +/* lnb control */ +#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299) +static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct flexcop_device *fc = fe->dvb->priv; + flexcop_ibi_value v; + deb_tuner("polarity/voltage = %u\n", voltage); + + v = fc->read_ibi_reg(fc, misc_204); + switch (voltage) { + case SEC_VOLTAGE_OFF: + v.misc_204.ACPI1_sig = 1; + break; + case SEC_VOLTAGE_13: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 0; + break; + case SEC_VOLTAGE_18: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 1; + break; + default: + err("unknown SEC_VOLTAGE value"); + return -EINVAL; + } + return fc->write_ibi_reg(fc, misc_204, v); +} +#endif + +#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312) +static int flexcop_sleep(struct dvb_frontend* fe) +{ + struct flexcop_device *fc = fe->dvb->priv; + if (fc->fe_sleep) + return fc->fe_sleep(fe); + return 0; +} +#endif + +/* SkyStar2 DVB-S rev 2.3 */ +#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL) +static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ +/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ + struct flexcop_device *fc = fe->dvb->priv; + flexcop_ibi_value v; + u16 ax; + v.raw = 0; + deb_tuner("tone = %u\n",tone); + + switch (tone) { + case SEC_TONE_ON: + ax = 0x01ff; + break; + case SEC_TONE_OFF: + ax = 0; + break; + default: + err("unknown SEC_TONE value"); + return -EINVAL; + } + + v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ + v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax; + v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax; + return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); +} + +static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) +{ + flexcop_set_tone(fe, SEC_TONE_ON); + udelay(data ? 500 : 1000); + flexcop_set_tone(fe, SEC_TONE_OFF); + udelay(data ? 1000 : 500); +} + +static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) +{ + int i, par = 1, d; + for (i = 7; i >= 0; i--) { + d = (data >> i) & 1; + par ^= d; + flexcop_diseqc_send_bit(fe, d); + } + flexcop_diseqc_send_bit(fe, par); +} + +static int flexcop_send_diseqc_msg(struct dvb_frontend *fe, + int len, u8 *msg, unsigned long burst) +{ + int i; + + flexcop_set_tone(fe, SEC_TONE_OFF); + mdelay(16); + + for (i = 0; i < len; i++) + flexcop_diseqc_send_byte(fe,msg[i]); + mdelay(16); + + if (burst != -1) { + if (burst) + flexcop_diseqc_send_byte(fe, 0xff); + else { + flexcop_set_tone(fe, SEC_TONE_ON); + mdelay(12); + udelay(500); + flexcop_set_tone(fe, SEC_TONE_OFF); + } + msleep(20); + } + return 0; +} + +static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); +} + +static int flexcop_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t minicmd) +{ + return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); +} + +static struct mt312_config skystar23_samsung_tbdu18132_config = { + .demod_address = 0x0e, +}; + +static int skystar2_rev23_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + struct dvb_frontend_ops *ops; + + fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c); + if (!fc->fe) + return 0; + + if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, + DVB_PLL_SAMSUNG_TBDU18132)) + return 0; + + ops = &fc->fe->ops; + ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; + ops->diseqc_send_burst = flexcop_diseqc_send_burst; + ops->set_tone = flexcop_set_tone; + ops->set_voltage = flexcop_set_voltage; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; + return 1; +} +#else +#define skystar2_rev23_attach NULL +#endif + +/* SkyStar2 DVB-S rev 2.6 */ +#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL) +static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; bclk = 0x51; + } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, ratio & 0xf0); + return 0; +} + +static u8 samsung_tbmu24112_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0x93, + 0xff, 0xff, +}; + +static struct stv0299_config samsung_tbmu24112_config = { + .demod_address = 0x68, + .inittab = samsung_tbmu24112_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_LK, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, +}; + +static int skystar2_rev26_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); + if (!fc->fe) + return 0; + + if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, + DVB_PLL_SAMSUNG_TBMU24112)) + return 0; + + fc->fe->ops.set_voltage = flexcop_set_voltage; + fc->fe_sleep = fc->fe->ops.sleep; + fc->fe->ops.sleep = flexcop_sleep; + return 1; + +} +#else +#define skystar2_rev26_attach NULL +#endif + +/* SkyStar2 DVB-S rev 2.7 */ +#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000) +static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { + .demod_address = 0x53, + .invert = 1, + .repeated_start_workaround = 1, + .serial_mpeg = 1, +}; + +static struct itd1000_config skystar2_rev2_7_itd1000_config = { + .i2c_address = 0x61, +}; + +static int skystar2_rev27_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + flexcop_ibi_value r108; + struct i2c_adapter *i2c_tuner; + + /* enable no_base_addr - no repeated start when reading */ + fc->fc_i2c_adap[0].no_base_addr = 1; + fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, + i2c); + if (!fc->fe) + goto fail; + + i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe); + if (!i2c_tuner) + goto fail; + + fc->fe_sleep = fc->fe->ops.sleep; + fc->fe->ops.sleep = flexcop_sleep; + + /* enable no_base_addr - no repeated start when reading */ + fc->fc_i2c_adap[2].no_base_addr = 1; + if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, + 0x08, 1, 1)) { + err("ISL6421 could NOT be attached"); + goto fail_isl; + } + info("ISL6421 successfully attached"); + + /* the ITD1000 requires a lower i2c clock - is it a problem ? */ + r108.raw = 0x00000506; + fc->write_ibi_reg(fc, tw_sm_c_108, r108); + if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner, + &skystar2_rev2_7_itd1000_config)) { + err("ITD1000 could NOT be attached"); + /* Should i2c clock be restored? */ + goto fail_isl; + } + info("ITD1000 successfully attached"); + + return 1; + +fail_isl: + fc->fc_i2c_adap[2].no_base_addr = 0; +fail: + /* for the next devices we need it again */ + fc->fc_i2c_adap[0].no_base_addr = 0; + return 0; +} +#else +#define skystar2_rev27_attach NULL +#endif + +/* SkyStar2 rev 2.8 */ +#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113) +static struct cx24123_config skystar2_rev2_8_cx24123_config = { + .demod_address = 0x55, + .dont_use_pll = 1, + .agc_callback = cx24113_agc_callback, +}; + +static const struct cx24113_config skystar2_rev2_8_cx24113_config = { + .i2c_addr = 0x54, + .xtal_khz = 10111, +}; + +static int skystar2_rev28_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + struct i2c_adapter *i2c_tuner; + + fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config, + i2c); + if (!fc->fe) + return 0; + + i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe); + if (!i2c_tuner) + return 0; + + if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config, + i2c_tuner)) { + err("CX24113 could NOT be attached"); + return 0; + } + info("CX24113 successfully attached"); + + fc->fc_i2c_adap[2].no_base_addr = 1; + if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, + 0x08, 0, 0)) { + err("ISL6421 could NOT be attached"); + fc->fc_i2c_adap[2].no_base_addr = 0; + return 0; + } + info("ISL6421 successfully attached"); + /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an + * IR-receiver (PIC16F818) - but the card has no input for that ??? */ + return 1; +} +#else +#define skystar2_rev28_attach NULL +#endif + +/* AirStar DVB-T */ +#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL) +static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe) +{ + static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d }; + static u8 mt352_reset[] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + return 0; +} + +static struct mt352_config samsung_tdtc9251dh0_config = { + .demod_address = 0x0f, + .demod_init = samsung_tdtc9251dh0_demod_init, +}; + +static int airstar_dvbt_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); + if (!fc->fe) + return 0; + + return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, + DVB_PLL_SAMSUNG_TDTC9251DH0); +} +#else +#define airstar_dvbt_attach NULL +#endif + +/* AirStar ATSC 1st generation */ +#if FE_SUPPORTED(BCM3510) +static int flexcop_fe_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char* name) +{ + struct flexcop_device *fc = fe->dvb->priv; + return request_firmware(fw, name, fc->dev); +} + +static struct bcm3510_config air2pc_atsc_first_gen_config = { + .demod_address = 0x0f, + .request_firmware = flexcop_fe_request_firmware, +}; + +static int airstar_atsc1_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); + return fc->fe != NULL; +} +#else +#define airstar_atsc1_attach NULL +#endif + +/* AirStar ATSC 2nd generation */ +#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL) +static struct nxt200x_config samsung_tbmv_config = { + .demod_address = 0x0a, +}; + +static int airstar_atsc2_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); + if (!fc->fe) + return 0; + + return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, + DVB_PLL_SAMSUNG_TBMV); +} +#else +#define airstar_atsc2_attach NULL +#endif + +/* AirStar ATSC 3rd generation */ +#if FE_SUPPORTED(LGDT330X) +static struct lgdt330x_config air2pc_atsc_hd5000_config = { + .demod_address = 0x59, + .demod_chip = LGDT3303, + .serial_mpeg = 0x04, + .clock_polarity_flip = 1, +}; + +static int airstar_atsc3_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); + if (!fc->fe) + return 0; + + return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, + TUNER_LG_TDVS_H06XF); +} +#else +#define airstar_atsc3_attach NULL +#endif + +/* CableStar2 DVB-C */ +#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL) +static u8 alps_tdee4_stv0297_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x48, + 0x01, 0x58, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x30, 0xff, + 0x31, 0x9d, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x29, + 0x35, 0x55, + 0x36, 0x80, + 0x37, 0x6e, + 0x38, 0x9c, + 0x40, 0x1a, + 0x41, 0xfe, + 0x42, 0x33, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x51, + 0x4b, 0xf8, + 0x52, 0x30, + 0x53, 0x06, + 0x59, 0x06, + 0x5a, 0x5e, + 0x5b, 0x04, + 0x61, 0x49, + 0x62, 0x0a, + 0x70, 0xff, + 0x71, 0x04, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x20, + 0x81, 0x00, + 0x82, 0x30, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x22, + 0x86, 0x08, + 0x87, 0x1b, + 0x88, 0x00, + 0x89, 0x00, + 0x90, 0x00, + 0x91, 0x04, + 0xa0, 0x86, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x5b, + 0xc1, 0x10, + 0xc2, 0x12, + 0xd0, 0x02, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x02, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x01, + 0xff, 0xff, +}; + +static struct stv0297_config alps_tdee4_stv0297_config = { + .demod_address = 0x1c, + .inittab = alps_tdee4_stv0297_inittab, +}; + +static int cablestar2_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fc_i2c_adap[0].no_base_addr = 1; + fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); + if (!fc->fe) + goto fail; + + /* This tuner doesn't use the stv0297's I2C gate, but instead the + * tuner is connected to a different flexcop I2C adapter. */ + if (fc->fe->ops.i2c_gate_ctrl) + fc->fe->ops.i2c_gate_ctrl(fc->fe, 0); + fc->fe->ops.i2c_gate_ctrl = NULL; + + if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, + &fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4)) + goto fail; + + return 1; + +fail: + /* Reset for next frontend to try */ + fc->fc_i2c_adap[0].no_base_addr = 0; + return 0; +} +#else +#define cablestar2_attach NULL +#endif + +static struct { + flexcop_device_type_t type; + int (*attach)(struct flexcop_device *, struct i2c_adapter *); +} flexcop_frontends[] = { + { FC_SKY_REV27, skystar2_rev27_attach }, + { FC_SKY_REV28, skystar2_rev28_attach }, + { FC_SKY_REV26, skystar2_rev26_attach }, + { FC_AIR_DVBT, airstar_dvbt_attach }, + { FC_AIR_ATSC2, airstar_atsc2_attach }, + { FC_AIR_ATSC3, airstar_atsc3_attach }, + { FC_AIR_ATSC1, airstar_atsc1_attach }, + { FC_CABLE, cablestar2_attach }, + { FC_SKY_REV23, skystar2_rev23_attach }, +}; + +/* try to figure out the frontend */ +int flexcop_frontend_init(struct flexcop_device *fc) +{ + int i; + for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) { + if (!flexcop_frontends[i].attach) + continue; + /* type needs to be set before, because of some workarounds + * done based on the probed card type */ + fc->dev_type = flexcop_frontends[i].type; + if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap)) + goto fe_found; + /* Clean up partially attached frontend */ + if (fc->fe) { + dvb_frontend_detach(fc->fe); + fc->fe = NULL; + } + } + fc->dev_type = FC_UNK; + err("no frontend driver found for this B2C2/FlexCop adapter"); + return -ENODEV; + +fe_found: + info("found '%s' .", fc->fe->ops.info.name); + if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { + err("frontend registration failed!"); + dvb_frontend_detach(fc->fe); + fc->fe = NULL; + return -EINVAL; + } + fc->init_state |= FC_STATE_FE_INIT; + return 0; +} + +void flexcop_frontend_exit(struct flexcop_device *fc) +{ + if (fc->init_state & FC_STATE_FE_INIT) { + dvb_unregister_frontend(fc->fe); + dvb_frontend_detach(fc->fe); + } + fc->init_state &= ~FC_STATE_FE_INIT; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop.h - private header file for all flexcop-chip-source files + * see flexcop.c for copyright information + */ +#ifndef __FLEXCOP_H__ +#define __FLEXCOP_H___ + +#define FC_LOG_PREFIX "b2c2-flexcop" +#include "flexcop-common.h" + +extern int b2c2_flexcop_debug; + +/* debug */ +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0) +#else +#define dprintk(level,args...) +#endif + +#define deb_info(args...) dprintk(0x01, args) +#define deb_tuner(args...) dprintk(0x02, args) +#define deb_i2c(args...) dprintk(0x04, args) +#define deb_ts(args...) dprintk(0x08, args) +#define deb_sram(args...) dprintk(0x10, args) +#define deb_rdump(args...) dprintk(0x20, args) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-hw-filter.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,232 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-hw-filter.c - pid and mac address filtering and control functions + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff); + deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off"); +} + +void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff); +} + +static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff); +} + +void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]) +{ + flexcop_ibi_value v418, v41c; + v41c = fc->read_ibi_reg(fc, mac_address_41c); + + v418.mac_address_418.MAC1 = mac[0]; + v418.mac_address_418.MAC2 = mac[1]; + v418.mac_address_418.MAC3 = mac[2]; + v418.mac_address_418.MAC6 = mac[3]; + v41c.mac_address_41c.MAC7 = mac[4]; + v41c.mac_address_41c.MAC8 = mac[5]; + + fc->write_ibi_reg(fc, mac_address_418, v418); + fc->write_ibi_reg(fc, mac_address_41c, v41c); +} + +void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff); +} + +static void flexcop_pid_group_filter(struct flexcop_device *fc, + u16 pid, u16 mask) +{ + /* index_reg_310.extra_index_reg need to 0 or 7 to work */ + flexcop_ibi_value v30c; + v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid; + v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask; + fc->write_ibi_reg(fc, pid_filter_30c, v30c); +} + +static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff); +} + +/* this fancy define reduces the code size of the quite similar PID controlling of + * the first 6 PIDs + */ + +#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \ + flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \ +v208 = fc->read_ibi_reg(fc, ctrl_208); \ +vpid.vregname.field = onoff ? pid : 0x1fff; \ +vpid.vregname.trans_field = transval; \ +v208.ctrl_208.enablefield = onoff; \ +fc->write_ibi_reg(fc, vregname, vpid); \ +fc->write_ibi_reg(fc, ctrl_208, v208); + +static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig, + Stream1_trans, 0); +} + +static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig, + Stream2_trans, 0); +} + +static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0); +} + +static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0); +} + +static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0); +} + +static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, + u16 pid, int onoff) +{ + pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0); +} + +static void flexcop_pid_control(struct flexcop_device *fc, + int index, u16 pid, int onoff) +{ + if (pid == 0x2000) + return; + + deb_ts("setting pid: %5d %04x at index %d '%s'\n", + pid, pid, index, onoff ? "on" : "off"); + + /* We could use bit magic here to reduce source code size. + * I decided against it, but to use the real register names */ + switch (index) { + case 0: + flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff); + break; + case 1: + flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff); + break; + case 2: + flexcop_pid_PCR_PID_ctrl(fc, pid, onoff); + break; + case 3: + flexcop_pid_PMT_PID_ctrl(fc, pid, onoff); + break; + case 4: + flexcop_pid_EMM_PID_ctrl(fc, pid, onoff); + break; + case 5: + flexcop_pid_ECM_PID_ctrl(fc, pid, onoff); + break; + default: + if (fc->has_32_hw_pid_filter && index < 38) { + flexcop_ibi_value vpid, vid; + + /* set the index */ + vid = fc->read_ibi_reg(fc, index_reg_310); + vid.index_reg_310.index_reg = index - 6; + fc->write_ibi_reg(fc, index_reg_310, vid); + + vpid = fc->read_ibi_reg(fc, pid_n_reg_314); + vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff; + vpid.pid_n_reg_314.PID_enable_bit = onoff; + fc->write_ibi_reg(fc, pid_n_reg_314, vpid); + } + break; + } +} + +static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff) +{ + if (fc->fullts_streaming_state != onoff) { + deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling"); + flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff)); + flexcop_pid_group_filter_ctrl(fc, onoff); + fc->fullts_streaming_state = onoff; + } + return 0; +} + +int flexcop_pid_feed_control(struct flexcop_device *fc, + struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; + + fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */ + if (dvbdmxfeed->index >= max_pid_filter) + fc->extra_feedcount += onoff ? 1 : -1; + + /* toggle complete-TS-streaming when: + * - pid_filtering is not enabled and it is the first or last feed requested + * - pid_filtering is enabled, + * - but the number of requested feeds is exceeded + * - or the requested pid is 0x2000 */ + + if (!fc->pid_filtering && fc->feedcount == onoff) + flexcop_toggle_fullts_streaming(fc, onoff); + + if (fc->pid_filtering) { + flexcop_pid_control \ + (fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); + + if (fc->extra_feedcount > 0) + flexcop_toggle_fullts_streaming(fc, 1); + else if (dvbdmxfeed->pid == 0x2000) + flexcop_toggle_fullts_streaming(fc, onoff); + else + flexcop_toggle_fullts_streaming(fc, 0); + } + + /* if it was the first or last feed request change the stream-status */ + if (fc->feedcount == onoff) { + flexcop_rcv_data_ctrl(fc, onoff); + if (fc->stream_control) /* device specific stream control */ + fc->stream_control(fc, onoff); + + /* feeding stopped -> reset the flexcop filter*/ + if (onoff == 0) { + flexcop_reset_block_300(fc); + flexcop_hw_filter_init(fc); + } + } + return 0; +} +EXPORT_SYMBOL(flexcop_pid_feed_control); + +void flexcop_hw_filter_init(struct flexcop_device *fc) +{ + int i; + flexcop_ibi_value v; + for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++) + flexcop_pid_control(fc, i, 0x1fff, 0); + + flexcop_pid_group_filter(fc, 0, 0x1fe0); + flexcop_pid_group_filter_ctrl(fc, 0); + + v = fc->read_ibi_reg(fc, pid_filter_308); + v.pid_filter_308.EMM_filter_4 = 1; + v.pid_filter_308.EMM_filter_6 = 0; + fc->write_ibi_reg(fc, pid_filter_308, v); + + flexcop_null_filter_ctrl(fc, 1); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,288 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +#define FC_MAX_I2C_RETRIES 100000 + +static int flexcop_i2c_operation(struct flexcop_device *fc, + flexcop_ibi_value *r100) +{ + int i; + flexcop_ibi_value r; + + r100->tw_sm_c_100.working_start = 1; + deb_i2c("r100 before: %08x\n",r100->raw); + + fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); + fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */ + + for (i = 0; i < FC_MAX_I2C_RETRIES; i++) { + r = fc->read_ibi_reg(fc, tw_sm_c_100); + + if (!r.tw_sm_c_100.no_base_addr_ack_error) { + if (r.tw_sm_c_100.st_done) { + *r100 = r; + deb_i2c("i2c success\n"); + return 0; + } + } else { + deb_i2c("suffering from an i2c ack_error\n"); + return -EREMOTEIO; + } + } + deb_i2c("tried %d times i2c operation, " + "never finished or too many ack errors.\n", i); + return -EREMOTEIO; +} + +static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c, + flexcop_ibi_value r100, u8 *buf) +{ + flexcop_ibi_value r104; + int len = r100.tw_sm_c_100.total_bytes, + /* remember total_bytes is buflen-1 */ + ret; + + /* work-around to have CableStar2 and SkyStar2 rev 2.7 work + * correctly: + * + * the ITD1000 is behind an i2c-gate which closes automatically + * after an i2c-transaction the STV0297 needs 2 consecutive reads + * one with no_base_addr = 0 and one with 1 + * + * those two work-arounds are conflictin: we check for the card + * type, it is set when probing the ITD1000 */ + if (i2c->fc->dev_type == FC_SKY_REV27) + r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; + + ret = flexcop_i2c_operation(i2c->fc, &r100); + if (ret != 0) { + deb_i2c("Retrying operation\n"); + r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr; + ret = flexcop_i2c_operation(i2c->fc, &r100); + } + if (ret != 0) { + deb_i2c("read failed. %d\n", ret); + return ret; + } + + buf[0] = r100.tw_sm_c_100.data1_reg; + + if (len > 0) { + r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104); + deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw); + + /* there is at least one more byte, otherwise we wouldn't be here */ + buf[1] = r104.tw_sm_c_104.data2_reg; + if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; + if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; + } + return 0; +} + +static int flexcop_i2c_write4(struct flexcop_device *fc, + flexcop_ibi_value r100, u8 *buf) +{ + flexcop_ibi_value r104; + int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */ + r104.raw = 0; + + /* there is at least one byte, otherwise we wouldn't be here */ + r100.tw_sm_c_100.data1_reg = buf[0]; + r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0; + r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; + r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; + + deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw); + + /* write the additional i2c data before doing the actual i2c operation */ + fc->write_ibi_reg(fc, tw_sm_c_104, r104); + return flexcop_i2c_operation(fc, &r100); +} + +int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, + flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) +{ + int ret; + +#ifdef DUMP_I2C_MESSAGES + int i; +#endif + + u16 bytes_to_transfer; + flexcop_ibi_value r100; + + deb_i2c("op = %d\n",op); + r100.raw = 0; + r100.tw_sm_c_100.chipaddr = chipaddr; + r100.tw_sm_c_100.twoWS_rw = op; + r100.tw_sm_c_100.twoWS_port_reg = i2c->port; + +#ifdef DUMP_I2C_MESSAGES + printk(KERN_DEBUG "%d ", i2c->port); + if (op == FC_READ) + printk("rd("); + else + printk("wr("); + printk("%02x): %02x ", chipaddr, addr); +#endif + + /* in that case addr is the only value -> + * we write it twice as baseaddr and val0 + * BBTI is doing it like that for ISL6421 at least */ + if (i2c->no_base_addr && len == 0 && op == FC_WRITE) { + buf = &addr; + len = 1; + } + + while (len != 0) { + bytes_to_transfer = len > 4 ? 4 : len; + + r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; + r100.tw_sm_c_100.baseaddr = addr; + + if (op == FC_READ) + ret = flexcop_i2c_read4(i2c, r100, buf); + else + ret = flexcop_i2c_write4(i2c->fc, r100, buf); + +#ifdef DUMP_I2C_MESSAGES + for (i = 0; i < bytes_to_transfer; i++) + printk("%02x ", buf[i]); +#endif + + if (ret < 0) + return ret; + + buf += bytes_to_transfer; + addr += bytes_to_transfer; + len -= bytes_to_transfer; + } + +#ifdef DUMP_I2C_MESSAGES + printk("\n"); +#endif + + return 0; +} +/* exported for PCI i2c */ +EXPORT_SYMBOL(flexcop_i2c_request); + +/* master xfer callback for demodulator */ +static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap); + int i, ret = 0; + + /* Some drivers use 1 byte or 0 byte reads as probes, which this + * driver doesn't support. These probes will always fail, so this + * hack makes them always succeed. If one knew how, it would of + * course be better to actually do the read. */ + if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1) + return 1; + + if (mutex_lock_interruptible(&i2c->fc->i2c_mutex)) + return -ERESTARTSYS; + + for (i = 0; i < num; i++) { + /* reading */ + if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) { + ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr, + msgs[i].buf[0], msgs[i+1].buf, + msgs[i+1].len); + i++; /* skip the following message */ + } else /* writing */ + ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr, + msgs[i].buf[0], &msgs[i].buf[1], + msgs[i].len - 1); + if (ret < 0) { + deb_i2c("i2c master_xfer failed"); + break; + } + } + + mutex_unlock(&i2c->fc->i2c_mutex); + + if (ret == 0) + ret = num; + return ret; +} + +static u32 flexcop_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm flexcop_algo = { + .master_xfer = flexcop_master_xfer, + .functionality = flexcop_i2c_func, +}; + +int flexcop_i2c_init(struct flexcop_device *fc) +{ + int ret; + mutex_init(&fc->i2c_mutex); + + fc->fc_i2c_adap[0].fc = fc; + fc->fc_i2c_adap[1].fc = fc; + fc->fc_i2c_adap[2].fc = fc; + fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD; + fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM; + fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER; + + strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod", + sizeof(fc->fc_i2c_adap[0].i2c_adap.name)); + strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom", + sizeof(fc->fc_i2c_adap[1].i2c_adap.name)); + strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner", + sizeof(fc->fc_i2c_adap[2].i2c_adap.name)); + + i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]); + i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]); + i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]); + + fc->fc_i2c_adap[0].i2c_adap.algo = + fc->fc_i2c_adap[1].i2c_adap.algo = + fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo; + fc->fc_i2c_adap[0].i2c_adap.algo_data = + fc->fc_i2c_adap[1].i2c_adap.algo_data = + fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL; + fc->fc_i2c_adap[0].i2c_adap.dev.parent = + fc->fc_i2c_adap[1].i2c_adap.dev.parent = + fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev; + + ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap); + if (ret < 0) + return ret; + + ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap); + if (ret < 0) + goto adap_1_failed; + + ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap); + if (ret < 0) + goto adap_2_failed; + + fc->init_state |= FC_STATE_I2C_INIT; + return 0; + +adap_2_failed: + i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); +adap_1_failed: + i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); + return ret; +} + +void flexcop_i2c_exit(struct flexcop_device *fc) +{ + if (fc->init_state & FC_STATE_I2C_INIT) { + i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap); + i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap); + i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap); + } + fc->init_state &= ~FC_STATE_I2C_INIT; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,455 @@ +/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * register descriptions + * see flexcop.c for copyright information + */ +/* This file is automatically generated, do not edit things here. */ +#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ +#define __FLEXCOP_IBI_VALUE_INCLUDED__ + +typedef union { + u32 raw; + + struct { + u32 dma_address0 :30; + u32 dma_0No_update : 1; + u32 dma_0start : 1; + } dma_0x0; + + struct { + u32 dma_addr_size :24; + u32 DMA_maxpackets : 8; + } dma_0x4_remap; + + struct { + u32 dma_addr_size :24; + u32 unused : 1; + u32 dma1timer : 7; + } dma_0x4_read; + + struct { + u32 dma_addr_size :24; + u32 dmatimer : 7; + u32 unused : 1; + } dma_0x4_write; + + struct { + u32 dma_cur_addr :30; + u32 unused : 2; + } dma_0x8; + + struct { + u32 dma_address1 :30; + u32 remap_enable : 1; + u32 dma_1start : 1; + } dma_0xc; + + struct { + u32 st_done : 1; + u32 no_base_addr_ack_error : 1; + u32 twoWS_port_reg : 2; + u32 total_bytes : 2; + u32 twoWS_rw : 1; + u32 working_start : 1; + u32 data1_reg : 8; + u32 baseaddr : 8; + u32 reserved1 : 1; + u32 chipaddr : 7; + } tw_sm_c_100; + + struct { + u32 unused : 6; + u32 force_stop : 1; + u32 exlicit_stops : 1; + u32 data4_reg : 8; + u32 data3_reg : 8; + u32 data2_reg : 8; + } tw_sm_c_104; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_108; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_10c; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_110; + + struct { + u32 LNB_CTLPrescaler_sig : 2; + u32 LNB_CTLLowCount_sig :15; + u32 LNB_CTLHighCount_sig :15; + } lnb_switch_freq_200; + + struct { + u32 Rev_N_sig_reserved2 : 1; + u32 Rev_N_sig_caps : 1; + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_revision_hi : 4; + u32 reserved :20; + u32 Per_reset_sig : 1; + u32 LNB_L_H_sig : 1; + u32 ACPI3_sig : 1; + u32 ACPI1_sig : 1; + } misc_204; + + struct { + u32 unused : 9; + u32 Mailbox_from_V8_Enable_sig : 1; + u32 DMA2_Size_IRQ_Enable_sig : 1; + u32 DMA1_Size_IRQ_Enable_sig : 1; + u32 DMA2_Timer_Enable_sig : 1; + u32 DMA2_IRQ_Enable_sig : 1; + u32 DMA1_Timer_Enable_sig : 1; + u32 DMA1_IRQ_Enable_sig : 1; + u32 Rcv_Data_sig : 1; + u32 MAC_filter_Mode_sig : 1; + u32 Multi2_Enable_sig : 1; + u32 Per_CA_Enable_sig : 1; + u32 SMC_Enable_sig : 1; + u32 CA_Enable_sig : 1; + u32 WAN_CA_Enable_sig : 1; + u32 WAN_Enable_sig : 1; + u32 Mask_filter_sig : 1; + u32 Null_filter_sig : 1; + u32 ECM_filter_sig : 1; + u32 EMM_filter_sig : 1; + u32 PMT_filter_sig : 1; + u32 PCR_filter_sig : 1; + u32 Stream2_filter_sig : 1; + u32 Stream1_filter_sig : 1; + } ctrl_208; + + struct { + u32 reserved :21; + u32 Transport_Error : 1; + u32 LLC_SNAP_FLAG_set : 1; + u32 Continuity_error_flag : 1; + u32 Data_receiver_error : 1; + u32 Mailbox_from_V8_Status_sig : 1; + u32 DMA2_Size_IRQ_Status : 1; + u32 DMA1_Size_IRQ_Status : 1; + u32 DMA2_Timer_Status : 1; + u32 DMA2_IRQ_Status : 1; + u32 DMA1_Timer_Status : 1; + u32 DMA1_IRQ_Status : 1; + } irq_20c; + + struct { + u32 Special_controls :16; + u32 Block_reset_enable : 8; + u32 reset_block_700 : 1; + u32 reset_block_600 : 1; + u32 reset_block_500 : 1; + u32 reset_block_400 : 1; + u32 reset_block_300 : 1; + u32 reset_block_200 : 1; + u32 reset_block_100 : 1; + u32 reset_block_000 : 1; + } sw_reset_210; + + struct { + u32 unused2 :20; + u32 polarity_PS_ERR_sig : 1; + u32 polarity_PS_SYNC_sig : 1; + u32 polarity_PS_VALID_sig : 1; + u32 polarity_PS_CLK_sig : 1; + u32 unused1 : 3; + u32 s2p_sel_sig : 1; + u32 section_pkg_enable_sig : 1; + u32 halt_V8_sig : 1; + u32 v2WS_oe_sig : 1; + u32 vuart_oe_sig : 1; + } misc_214; + + struct { + u32 Mailbox_from_V8 :32; + } mbox_v8_to_host_218; + + struct { + u32 sysramaccess_busmuster : 1; + u32 sysramaccess_write : 1; + u32 unused : 7; + u32 sysramaccess_addr :15; + u32 sysramaccess_data : 8; + } mbox_host_to_v8_21c; + + struct { + u32 debug_fifo_problem : 1; + u32 debug_flag_write_status00 : 1; + u32 Stream2_trans : 1; + u32 Stream2_PID :13; + u32 debug_flag_pid_saved : 1; + u32 MAC_Multicast_filter : 1; + u32 Stream1_trans : 1; + u32 Stream1_PID :13; + } pid_filter_300; + + struct { + u32 reserved : 2; + u32 PMT_trans : 1; + u32 PMT_PID :13; + u32 debug_overrun2 : 1; + u32 debug_overrun3 : 1; + u32 PCR_trans : 1; + u32 PCR_PID :13; + } pid_filter_304; + + struct { + u32 reserved : 2; + u32 ECM_trans : 1; + u32 ECM_PID :13; + u32 EMM_filter_6 : 1; + u32 EMM_filter_4 : 1; + u32 EMM_trans : 1; + u32 EMM_PID :13; + } pid_filter_308; + + struct { + u32 unused2 : 3; + u32 Group_mask :13; + u32 unused1 : 2; + u32 Group_trans : 1; + u32 Group_PID :13; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 unused :15; + u32 net_master_read :17; + } pid_filter_30c_ext_ind_1; + + struct { + u32 unused :15; + u32 net_master_write :17; + } pid_filter_30c_ext_ind_2; + + struct { + u32 unused :15; + u32 next_net_master_write :17; + } pid_filter_30c_ext_ind_3; + + struct { + u32 reserved2 : 5; + u32 stack_read :10; + u32 reserved1 : 6; + u32 state_write :10; + u32 unused1 : 1; + } pid_filter_30c_ext_ind_4; + + struct { + u32 unused :22; + u32 stack_cnt :10; + } pid_filter_30c_ext_ind_5; + + struct { + u32 unused : 4; + u32 data_size_reg :12; + u32 write_status4 : 2; + u32 write_status1 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg0 : 2; + } pid_filter_30c_ext_ind_6; + + struct { + u32 unused :22; + u32 pass_alltables : 1; + u32 AB_select : 1; + u32 extra_index_reg : 3; + u32 index_reg : 5; + } index_reg_310; + + struct { + u32 reserved :17; + u32 PID_enable_bit : 1; + u32 PID_trans : 1; + u32 PID :13; + } pid_n_reg_314; + + struct { + u32 reserved : 6; + u32 HighAB_bit : 1; + u32 Enable_bit : 1; + u32 A6_byte : 8; + u32 A5_byte : 8; + u32 A4_byte : 8; + } mac_low_reg_318; + + struct { + u32 reserved : 8; + u32 A3_byte : 8; + u32 A2_byte : 8; + u32 A1_byte : 8; + } mac_high_reg_31c; + + struct { + u32 data_Tag_ID :16; + u32 reserved :16; + } data_tag_400; + + struct { + u32 Card_IDbyte3 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte6 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte1 : 8; + u32 Card_IDbyte2 : 8; + } card_id_40c; + + struct { + u32 MAC6 : 8; + u32 MAC3 : 8; + u32 MAC2 : 8; + u32 MAC1 : 8; + } mac_address_418; + + struct { + u32 reserved :16; + u32 MAC8 : 8; + u32 MAC7 : 8; + } mac_address_41c; + + struct { + u32 reserved :21; + u32 txbuffempty : 1; + u32 ReceiveByteFrameError : 1; + u32 ReceiveDataReady : 1; + u32 transmitter_data_byte : 8; + } ci_600; + + struct { + u32 pi_component_reg : 3; + u32 pi_rw : 1; + u32 pi_ha :20; + u32 pi_d : 8; + } pi_604; + + struct { + u32 pi_busy_n : 1; + u32 pi_wait_n : 1; + u32 pi_timeout_status : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 config_cclk : 1; + u32 config_cs_n : 1; + u32 config_wr_n : 1; + u32 config_Prog_n : 1; + u32 config_Init_stat : 1; + u32 config_Done_stat : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 pcmcia_a_mod_pwr_n : 1; + u32 reserved : 3; + u32 Timer_addr : 5; + u32 unused : 1; + u32 timer_data : 7; + u32 Timer_Load_req : 1; + u32 Timer_Read_req : 1; + u32 oncecycle_read : 1; + u32 serialReset : 1; + } pi_608; + + struct { + u32 reserved : 6; + u32 rw_flag : 1; + u32 dvb_en : 1; + u32 key_array_row : 5; + u32 key_array_col : 3; + u32 key_code : 2; + u32 key_enable : 1; + u32 PID :13; + } dvb_reg_60c; + + struct { + u32 start_sram_ibi : 1; + u32 reserved2 : 1; + u32 ce_pin_reg : 1; + u32 oe_pin_reg : 1; + u32 reserved1 : 3; + u32 sc_xfer_bit : 1; + u32 sram_data : 8; + u32 sram_rw : 1; + u32 sram_addr :15; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_write :16; + u32 net_addr_read :16; + } net_buf_reg_704; + + struct { + u32 cai_cnt : 4; + u32 reserved2 : 6; + u32 cai_write :11; + u32 reserved1 : 5; + u32 cai_read :11; + } cai_buf_reg_708; + + struct { + u32 cao_cnt : 4; + u32 reserved2 : 6; + u32 cap_write :11; + u32 reserved1 : 5; + u32 cao_read :11; + } cao_buf_reg_70c; + + struct { + u32 media_cnt : 4; + u32 reserved2 : 6; + u32 media_write :11; + u32 reserved1 : 5; + u32 media_read :11; + } media_buf_reg_710; + + struct { + u32 reserved :17; + u32 ctrl_maximumfill : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_usb_wan : 1; + u32 cao_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 net_ovflow_error : 1; + u32 MEDIA_Dest : 2; + u32 CAO_Dest : 2; + u32 CAI_Dest : 2; + u32 NET_Dest : 2; + } sram_dest_reg_714; + + struct { + u32 reserved3 :11; + u32 net_addr_write : 1; + u32 reserved2 : 3; + u32 net_addr_read : 1; + u32 reserved1 : 4; + u32 net_cnt :12; + } net_buf_reg_718; + + struct { + u32 reserved3 : 4; + u32 wan_pkt_frame : 4; + u32 reserved2 : 4; + u32 sram_memmap : 2; + u32 sram_chip : 2; + u32 wan_wait_state : 8; + u32 reserved1 : 6; + u32 wan_speed_sig : 2; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,455 @@ +/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * register descriptions + * see flexcop.c for copyright information + */ +/* This file is automatically generated, do not edit things here. */ +#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ +#define __FLEXCOP_IBI_VALUE_INCLUDED__ + +typedef union { + u32 raw; + + struct { + u32 dma_0start : 1; + u32 dma_0No_update : 1; + u32 dma_address0 :30; + } dma_0x0; + + struct { + u32 DMA_maxpackets : 8; + u32 dma_addr_size :24; + } dma_0x4_remap; + + struct { + u32 dma1timer : 7; + u32 unused : 1; + u32 dma_addr_size :24; + } dma_0x4_read; + + struct { + u32 unused : 1; + u32 dmatimer : 7; + u32 dma_addr_size :24; + } dma_0x4_write; + + struct { + u32 unused : 2; + u32 dma_cur_addr :30; + } dma_0x8; + + struct { + u32 dma_1start : 1; + u32 remap_enable : 1; + u32 dma_address1 :30; + } dma_0xc; + + struct { + u32 chipaddr : 7; + u32 reserved1 : 1; + u32 baseaddr : 8; + u32 data1_reg : 8; + u32 working_start : 1; + u32 twoWS_rw : 1; + u32 total_bytes : 2; + u32 twoWS_port_reg : 2; + u32 no_base_addr_ack_error : 1; + u32 st_done : 1; + } tw_sm_c_100; + + struct { + u32 data2_reg : 8; + u32 data3_reg : 8; + u32 data4_reg : 8; + u32 exlicit_stops : 1; + u32 force_stop : 1; + u32 unused : 6; + } tw_sm_c_104; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_108; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_10c; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_110; + + struct { + u32 LNB_CTLHighCount_sig :15; + u32 LNB_CTLLowCount_sig :15; + u32 LNB_CTLPrescaler_sig : 2; + } lnb_switch_freq_200; + + struct { + u32 ACPI1_sig : 1; + u32 ACPI3_sig : 1; + u32 LNB_L_H_sig : 1; + u32 Per_reset_sig : 1; + u32 reserved :20; + u32 Rev_N_sig_revision_hi : 4; + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_caps : 1; + u32 Rev_N_sig_reserved2 : 1; + } misc_204; + + struct { + u32 Stream1_filter_sig : 1; + u32 Stream2_filter_sig : 1; + u32 PCR_filter_sig : 1; + u32 PMT_filter_sig : 1; + u32 EMM_filter_sig : 1; + u32 ECM_filter_sig : 1; + u32 Null_filter_sig : 1; + u32 Mask_filter_sig : 1; + u32 WAN_Enable_sig : 1; + u32 WAN_CA_Enable_sig : 1; + u32 CA_Enable_sig : 1; + u32 SMC_Enable_sig : 1; + u32 Per_CA_Enable_sig : 1; + u32 Multi2_Enable_sig : 1; + u32 MAC_filter_Mode_sig : 1; + u32 Rcv_Data_sig : 1; + u32 DMA1_IRQ_Enable_sig : 1; + u32 DMA1_Timer_Enable_sig : 1; + u32 DMA2_IRQ_Enable_sig : 1; + u32 DMA2_Timer_Enable_sig : 1; + u32 DMA1_Size_IRQ_Enable_sig : 1; + u32 DMA2_Size_IRQ_Enable_sig : 1; + u32 Mailbox_from_V8_Enable_sig : 1; + u32 unused : 9; + } ctrl_208; + + struct { + u32 DMA1_IRQ_Status : 1; + u32 DMA1_Timer_Status : 1; + u32 DMA2_IRQ_Status : 1; + u32 DMA2_Timer_Status : 1; + u32 DMA1_Size_IRQ_Status : 1; + u32 DMA2_Size_IRQ_Status : 1; + u32 Mailbox_from_V8_Status_sig : 1; + u32 Data_receiver_error : 1; + u32 Continuity_error_flag : 1; + u32 LLC_SNAP_FLAG_set : 1; + u32 Transport_Error : 1; + u32 reserved :21; + } irq_20c; + + struct { + u32 reset_block_000 : 1; + u32 reset_block_100 : 1; + u32 reset_block_200 : 1; + u32 reset_block_300 : 1; + u32 reset_block_400 : 1; + u32 reset_block_500 : 1; + u32 reset_block_600 : 1; + u32 reset_block_700 : 1; + u32 Block_reset_enable : 8; + u32 Special_controls :16; + } sw_reset_210; + + struct { + u32 vuart_oe_sig : 1; + u32 v2WS_oe_sig : 1; + u32 halt_V8_sig : 1; + u32 section_pkg_enable_sig : 1; + u32 s2p_sel_sig : 1; + u32 unused1 : 3; + u32 polarity_PS_CLK_sig : 1; + u32 polarity_PS_VALID_sig : 1; + u32 polarity_PS_SYNC_sig : 1; + u32 polarity_PS_ERR_sig : 1; + u32 unused2 :20; + } misc_214; + + struct { + u32 Mailbox_from_V8 :32; + } mbox_v8_to_host_218; + + struct { + u32 sysramaccess_data : 8; + u32 sysramaccess_addr :15; + u32 unused : 7; + u32 sysramaccess_write : 1; + u32 sysramaccess_busmuster : 1; + } mbox_host_to_v8_21c; + + struct { + u32 Stream1_PID :13; + u32 Stream1_trans : 1; + u32 MAC_Multicast_filter : 1; + u32 debug_flag_pid_saved : 1; + u32 Stream2_PID :13; + u32 Stream2_trans : 1; + u32 debug_flag_write_status00 : 1; + u32 debug_fifo_problem : 1; + } pid_filter_300; + + struct { + u32 PCR_PID :13; + u32 PCR_trans : 1; + u32 debug_overrun3 : 1; + u32 debug_overrun2 : 1; + u32 PMT_PID :13; + u32 PMT_trans : 1; + u32 reserved : 2; + } pid_filter_304; + + struct { + u32 EMM_PID :13; + u32 EMM_trans : 1; + u32 EMM_filter_4 : 1; + u32 EMM_filter_6 : 1; + u32 ECM_PID :13; + u32 ECM_trans : 1; + u32 reserved : 2; + } pid_filter_308; + + struct { + u32 Group_PID :13; + u32 Group_trans : 1; + u32 unused1 : 2; + u32 Group_mask :13; + u32 unused2 : 3; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 net_master_read :17; + u32 unused :15; + } pid_filter_30c_ext_ind_1; + + struct { + u32 net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_2; + + struct { + u32 next_net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_3; + + struct { + u32 unused1 : 1; + u32 state_write :10; + u32 reserved1 : 6; + u32 stack_read :10; + u32 reserved2 : 5; + } pid_filter_30c_ext_ind_4; + + struct { + u32 stack_cnt :10; + u32 unused :22; + } pid_filter_30c_ext_ind_5; + + struct { + u32 pid_fsm_save_reg0 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 write_status1 : 2; + u32 write_status4 : 2; + u32 data_size_reg :12; + u32 unused : 4; + } pid_filter_30c_ext_ind_6; + + struct { + u32 index_reg : 5; + u32 extra_index_reg : 3; + u32 AB_select : 1; + u32 pass_alltables : 1; + u32 unused :22; + } index_reg_310; + + struct { + u32 PID :13; + u32 PID_trans : 1; + u32 PID_enable_bit : 1; + u32 reserved :17; + } pid_n_reg_314; + + struct { + u32 A4_byte : 8; + u32 A5_byte : 8; + u32 A6_byte : 8; + u32 Enable_bit : 1; + u32 HighAB_bit : 1; + u32 reserved : 6; + } mac_low_reg_318; + + struct { + u32 A1_byte : 8; + u32 A2_byte : 8; + u32 A3_byte : 8; + u32 reserved : 8; + } mac_high_reg_31c; + + struct { + u32 reserved :16; + u32 data_Tag_ID :16; + } data_tag_400; + + struct { + u32 Card_IDbyte6 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte3 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte2 : 8; + u32 Card_IDbyte1 : 8; + } card_id_40c; + + struct { + u32 MAC1 : 8; + u32 MAC2 : 8; + u32 MAC3 : 8; + u32 MAC6 : 8; + } mac_address_418; + + struct { + u32 MAC7 : 8; + u32 MAC8 : 8; + u32 reserved :16; + } mac_address_41c; + + struct { + u32 transmitter_data_byte : 8; + u32 ReceiveDataReady : 1; + u32 ReceiveByteFrameError : 1; + u32 txbuffempty : 1; + u32 reserved :21; + } ci_600; + + struct { + u32 pi_d : 8; + u32 pi_ha :20; + u32 pi_rw : 1; + u32 pi_component_reg : 3; + } pi_604; + + struct { + u32 serialReset : 1; + u32 oncecycle_read : 1; + u32 Timer_Read_req : 1; + u32 Timer_Load_req : 1; + u32 timer_data : 7; + u32 unused : 1; + u32 Timer_addr : 5; + u32 reserved : 3; + u32 pcmcia_a_mod_pwr_n : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 config_Done_stat : 1; + u32 config_Init_stat : 1; + u32 config_Prog_n : 1; + u32 config_wr_n : 1; + u32 config_cs_n : 1; + u32 config_cclk : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 pi_timeout_status : 1; + u32 pi_wait_n : 1; + u32 pi_busy_n : 1; + } pi_608; + + struct { + u32 PID :13; + u32 key_enable : 1; + u32 key_code : 2; + u32 key_array_col : 3; + u32 key_array_row : 5; + u32 dvb_en : 1; + u32 rw_flag : 1; + u32 reserved : 6; + } dvb_reg_60c; + + struct { + u32 sram_addr :15; + u32 sram_rw : 1; + u32 sram_data : 8; + u32 sc_xfer_bit : 1; + u32 reserved1 : 3; + u32 oe_pin_reg : 1; + u32 ce_pin_reg : 1; + u32 reserved2 : 1; + u32 start_sram_ibi : 1; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_read :16; + u32 net_addr_write :16; + } net_buf_reg_704; + + struct { + u32 cai_read :11; + u32 reserved1 : 5; + u32 cai_write :11; + u32 reserved2 : 6; + u32 cai_cnt : 4; + } cai_buf_reg_708; + + struct { + u32 cao_read :11; + u32 reserved1 : 5; + u32 cap_write :11; + u32 reserved2 : 6; + u32 cao_cnt : 4; + } cao_buf_reg_70c; + + struct { + u32 media_read :11; + u32 reserved1 : 5; + u32 media_write :11; + u32 reserved2 : 6; + u32 media_cnt : 4; + } media_buf_reg_710; + + struct { + u32 NET_Dest : 2; + u32 CAI_Dest : 2; + u32 CAO_Dest : 2; + u32 MEDIA_Dest : 2; + u32 net_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 cao_ovflow_error : 1; + u32 ctrl_usb_wan : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_maximumfill : 1; + u32 reserved :17; + } sram_dest_reg_714; + + struct { + u32 net_cnt :12; + u32 reserved1 : 4; + u32 net_addr_read : 1; + u32 reserved2 : 3; + u32 net_addr_write : 1; + u32 reserved3 :11; + } net_buf_reg_718; + + struct { + u32 wan_speed_sig : 2; + u32 reserved1 : 6; + u32 wan_wait_state : 8; + u32 sram_chip : 2; + u32 sram_memmap : 2; + u32 reserved2 : 4; + u32 wan_pkt_frame : 4; + u32 reserved3 : 4; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-misc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-misc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-misc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-misc.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-misc.c - miscellaneous functions + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +void flexcop_determine_revision(struct flexcop_device *fc) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); + + switch (v.misc_204.Rev_N_sig_revision_hi) { + case 0x2: + deb_info("found a FlexCopII.\n"); + fc->rev = FLEXCOP_II; + break; + case 0x3: + deb_info("found a FlexCopIIb.\n"); + fc->rev = FLEXCOP_IIB; + break; + case 0x0: + deb_info("found a FlexCopIII.\n"); + fc->rev = FLEXCOP_III; + break; + default: + err("unknown FlexCop Revision: %x. Please report this to " + "linux-dvb@linuxtv.org.", + v.misc_204.Rev_N_sig_revision_hi); + break; + } + + if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps)) + deb_info("this FlexCop has " + "the additional 32 hardware pid filter.\n"); + else + deb_info("this FlexCop has " + "the 6 basic main hardware pid filter.\n"); + /* bus parts have to decide if hw pid filtering is used or not. */ +} + +static const char *flexcop_revision_names[] = { + "Unknown chip", + "FlexCopII", + "FlexCopIIb", + "FlexCopIII", +}; + +static const char *flexcop_device_names[] = { + [FC_UNK] = "Unknown device", + [FC_CABLE] = "Cable2PC/CableStar 2 DVB-C", + [FC_AIR_DVBT] = "Air2PC/AirStar 2 DVB-T", + [FC_AIR_ATSC1] = "Air2PC/AirStar 2 ATSC 1st generation", + [FC_AIR_ATSC2] = "Air2PC/AirStar 2 ATSC 2nd generation", + [FC_AIR_ATSC3] = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)", + [FC_SKY_REV23] = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)", + [FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6", + [FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u", + [FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8", +}; + +static const char *flexcop_bus_names[] = { + "USB", + "PCI", +}; + +void flexcop_device_name(struct flexcop_device *fc, + const char *prefix, const char *suffix) +{ + info("%s '%s' at the '%s' bus controlled by a '%s' %s", + prefix, flexcop_device_names[fc->dev_type], + flexcop_bus_names[fc->bus_type], + flexcop_revision_names[fc->rev], suffix); +} + +void flexcop_dump_reg(struct flexcop_device *fc, + flexcop_ibi_register reg, int num) +{ + flexcop_ibi_value v; + int i; + for (i = 0; i < num; i++) { + v = fc->read_ibi_reg(fc, reg+4*i); + deb_rdump("0x%03x: %08x, ", reg+4*i, v.raw); + } + deb_rdump("\n"); +} +EXPORT_SYMBOL(flexcop_dump_reg); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-pci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-pci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-pci.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-pci.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,450 @@ +/* + * Linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-pci.c - covers the PCI part including DMA transfers + * see flexcop.c for copyright information + */ + +#define FC_LOG_PREFIX "flexcop-pci" +#include "flexcop-common.h" + +static int enable_pid_filtering = 1; +module_param(enable_pid_filtering, int, 0444); +MODULE_PARM_DESC(enable_pid_filtering, + "enable hardware pid filtering: supported values: 0 (fullts), 1"); + +static int irq_chk_intv = 100; +module_param(irq_chk_intv, int, 0644); +MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog."); + +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((debug & level)) printk(args); } while (0) +#define DEBSTATUS "" +#else +#define dprintk(level,args...) +#define DEBSTATUS " (debugging is not enabled)" +#endif + +#define deb_info(args...) dprintk(0x01, args) +#define deb_reg(args...) dprintk(0x02, args) +#define deb_ts(args...) dprintk(0x04, args) +#define deb_irq(args...) dprintk(0x08, args) +#define deb_chk(args...) dprintk(0x10, args) + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))." + DEBSTATUS); + +#define DRIVER_VERSION "0.1" +#define DRIVER_NAME "flexcop-pci" +#define DRIVER_AUTHOR "Patrick Boettcher " + +struct flexcop_pci { + struct pci_dev *pdev; + +#define FC_PCI_INIT 0x01 +#define FC_PCI_DMA_INIT 0x02 + int init_state; + + void __iomem *io_mem; + u32 irq; + /* buffersize (at least for DMA1, need to be % 188 == 0, + * this logic is required */ +#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188) +#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188) + struct flexcop_dma dma[2]; + + int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ + u32 last_dma1_cur_pos; + /* position of the pointer last time the timer/packet irq occurred */ + int count; + int count_prev; + int stream_problem; + + spinlock_t irq_lock; + unsigned long last_irq; + + struct delayed_work irq_check_work; + struct flexcop_device *fc_dev; +}; + +static int lastwreg, lastwval, lastrreg, lastrval; + +static flexcop_ibi_value flexcop_pci_read_ibi_reg(struct flexcop_device *fc, + flexcop_ibi_register r) +{ + struct flexcop_pci *fc_pci = fc->bus_specific; + flexcop_ibi_value v; + v.raw = readl(fc_pci->io_mem + r); + + if (lastrreg != r || lastrval != v.raw) { + lastrreg = r; lastrval = v.raw; + deb_reg("new rd: %3x: %08x\n", r, v.raw); + } + + return v; +} + +static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, + flexcop_ibi_register r, flexcop_ibi_value v) +{ + struct flexcop_pci *fc_pci = fc->bus_specific; + + if (lastwreg != r || lastwval != v.raw) { + lastwreg = r; lastwval = v.raw; + deb_reg("new wr: %3x: %08x\n", r, v.raw); + } + + writel(v.raw, fc_pci->io_mem + r); + return 0; +} + +static void flexcop_pci_irq_check_work(struct work_struct *work) +{ + struct flexcop_pci *fc_pci = + container_of(work, struct flexcop_pci, irq_check_work.work); + struct flexcop_device *fc = fc_pci->fc_dev; + + if (fc->feedcount) { + + if (fc_pci->count == fc_pci->count_prev) { + deb_chk("no IRQ since the last check\n"); + if (fc_pci->stream_problem++ == 3) { + struct dvb_demux_feed *feed; + deb_info("flexcop-pci: stream problem, resetting pid filter\n"); + + spin_lock_irq(&fc->demux.lock); + list_for_each_entry(feed, &fc->demux.feed_list, + list_head) { + flexcop_pid_feed_control(fc, feed, 0); + } + + list_for_each_entry(feed, &fc->demux.feed_list, + list_head) { + flexcop_pid_feed_control(fc, feed, 1); + } + spin_unlock_irq(&fc->demux.lock); + + fc_pci->stream_problem = 0; + } + } else { + fc_pci->stream_problem = 0; + fc_pci->count_prev = fc_pci->count; + } + } + + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); +} + +/* When PID filtering is turned on, we use the timer IRQ, because small amounts + * of data need to be passed to the user space instantly as well. When PID + * filtering is turned off, we use the page-change-IRQ */ +static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) +{ + struct flexcop_pci *fc_pci = dev_id; + struct flexcop_device *fc = fc_pci->fc_dev; + unsigned long flags; + flexcop_ibi_value v; + irqreturn_t ret = IRQ_HANDLED; + + spin_lock_irqsave(&fc_pci->irq_lock, flags); + v = fc->read_ibi_reg(fc, irq_20c); + + /* errors */ + if (v.irq_20c.Data_receiver_error) + deb_chk("data receiver error\n"); + if (v.irq_20c.Continuity_error_flag) + deb_chk("Contunuity error flag is set\n"); + if (v.irq_20c.LLC_SNAP_FLAG_set) + deb_chk("LLC_SNAP_FLAG_set is set\n"); + if (v.irq_20c.Transport_Error) + deb_chk("Transport error\n"); + + if ((fc_pci->count % 1000) == 0) + deb_chk("%d valid irq took place so far\n", fc_pci->count); + + if (v.irq_20c.DMA1_IRQ_Status == 1) { + if (fc_pci->active_dma1_addr == 0) + flexcop_pass_dmx_packets(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr0, + fc_pci->dma[0].size / 188); + else + flexcop_pass_dmx_packets(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr1, + fc_pci->dma[0].size / 188); + + deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr); + fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr; + /* for the timer IRQ we only can use buffer dmx feeding, because we don't have + * complete TS packets when reading from the DMA memory */ + } else if (v.irq_20c.DMA1_Timer_Status == 1) { + dma_addr_t cur_addr = + fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; + u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; + + deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, " + "last_cur_pos: %08x ", + jiffies_to_usecs(jiffies - fc_pci->last_irq), + v.raw, (unsigned long long)cur_addr, cur_pos, + fc_pci->last_dma1_cur_pos); + fc_pci->last_irq = jiffies; + + /* buffer end was reached, restarted from the beginning + * pass the data from last_cur_pos to the buffer end to the demux + */ + if (cur_pos < fc_pci->last_dma1_cur_pos) { + deb_irq(" end was reached: passing %d bytes ", + (fc_pci->dma[0].size*2 - 1) - + fc_pci->last_dma1_cur_pos); + flexcop_pass_dmx_data(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr0 + + fc_pci->last_dma1_cur_pos, + (fc_pci->dma[0].size*2) - + fc_pci->last_dma1_cur_pos); + fc_pci->last_dma1_cur_pos = 0; + } + + if (cur_pos > fc_pci->last_dma1_cur_pos) { + deb_irq(" passing %d bytes ", + cur_pos - fc_pci->last_dma1_cur_pos); + flexcop_pass_dmx_data(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr0 + + fc_pci->last_dma1_cur_pos, + cur_pos - fc_pci->last_dma1_cur_pos); + } + deb_irq("\n"); + + fc_pci->last_dma1_cur_pos = cur_pos; + fc_pci->count++; + } else { + deb_irq("isr for flexcop called, " + "apparently without reason (%08x)\n", v.raw); + ret = IRQ_NONE; + } + + spin_unlock_irqrestore(&fc_pci->irq_lock, flags); + return ret; +} + +static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) +{ + struct flexcop_pci *fc_pci = fc->bus_specific; + if (onoff) { + flexcop_dma_config(fc, &fc_pci->dma[0], FC_DMA_1); + flexcop_dma_config(fc, &fc_pci->dma[1], FC_DMA_2); + flexcop_dma_config_timer(fc, FC_DMA_1, 0); + flexcop_dma_xfer_control(fc, FC_DMA_1, + FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 1); + deb_irq("DMA xfer enabled\n"); + + fc_pci->last_dma1_cur_pos = 0; + flexcop_dma_control_timer_irq(fc, FC_DMA_1, 1); + deb_irq("IRQ enabled\n"); + fc_pci->count_prev = fc_pci->count; + } else { + flexcop_dma_control_timer_irq(fc, FC_DMA_1, 0); + deb_irq("IRQ disabled\n"); + + flexcop_dma_xfer_control(fc, FC_DMA_1, + FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1, 0); + deb_irq("DMA xfer disabled\n"); + } + return 0; +} + +static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci) +{ + int ret; + ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[0], + FC_DEFAULT_DMA1_BUFSIZE); + if (ret != 0) + return ret; + + ret = flexcop_dma_allocate(fc_pci->pdev, &fc_pci->dma[1], + FC_DEFAULT_DMA2_BUFSIZE); + if (ret != 0) { + flexcop_dma_free(&fc_pci->dma[0]); + return ret; + } + + flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_MEDIA | + FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1); + flexcop_sram_set_dest(fc_pci->fc_dev, FC_SRAM_DEST_CAO | + FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); + fc_pci->init_state |= FC_PCI_DMA_INIT; + return ret; +} + +static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci) +{ + if (fc_pci->init_state & FC_PCI_DMA_INIT) { + flexcop_dma_free(&fc_pci->dma[0]); + flexcop_dma_free(&fc_pci->dma[1]); + } + fc_pci->init_state &= ~FC_PCI_DMA_INIT; +} + +static int flexcop_pci_init(struct flexcop_pci *fc_pci) +{ + int ret; + + info("card revision %x", fc_pci->pdev->revision); + + if ((ret = pci_enable_device(fc_pci->pdev)) != 0) + return ret; + pci_set_master(fc_pci->pdev); + + if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0) + goto err_pci_disable_device; + + fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800); + + if (!fc_pci->io_mem) { + err("cannot map io memory\n"); + ret = -EIO; + goto err_pci_release_regions; + } + + pci_set_drvdata(fc_pci->pdev, fc_pci); + spin_lock_init(&fc_pci->irq_lock); + if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, + IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) + goto err_pci_iounmap; + + fc_pci->init_state |= FC_PCI_INIT; + return ret; + +err_pci_iounmap: + pci_iounmap(fc_pci->pdev, fc_pci->io_mem); + pci_set_drvdata(fc_pci->pdev, NULL); +err_pci_release_regions: + pci_release_regions(fc_pci->pdev); +err_pci_disable_device: + pci_disable_device(fc_pci->pdev); + return ret; +} + +static void flexcop_pci_exit(struct flexcop_pci *fc_pci) +{ + if (fc_pci->init_state & FC_PCI_INIT) { + free_irq(fc_pci->pdev->irq, fc_pci); + pci_iounmap(fc_pci->pdev, fc_pci->io_mem); + pci_set_drvdata(fc_pci->pdev, NULL); + pci_release_regions(fc_pci->pdev); + pci_disable_device(fc_pci->pdev); + } + fc_pci->init_state &= ~FC_PCI_INIT; +} + +static int flexcop_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct flexcop_device *fc; + struct flexcop_pci *fc_pci; + int ret = -ENOMEM; + + if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) { + err("out of memory\n"); + return -ENOMEM; + } + + /* general flexcop init */ + fc_pci = fc->bus_specific; + fc_pci->fc_dev = fc; + + fc->read_ibi_reg = flexcop_pci_read_ibi_reg; + fc->write_ibi_reg = flexcop_pci_write_ibi_reg; + fc->i2c_request = flexcop_i2c_request; + fc->get_mac_addr = flexcop_eeprom_check_mac_addr; + fc->stream_control = flexcop_pci_stream_control; + + if (enable_pid_filtering) + info("will use the HW PID filter."); + else + info("will pass the complete TS to the demuxer."); + + fc->pid_filtering = enable_pid_filtering; + fc->bus_type = FC_PCI; + fc->dev = &pdev->dev; + fc->owner = THIS_MODULE; + + /* bus specific part */ + fc_pci->pdev = pdev; + if ((ret = flexcop_pci_init(fc_pci)) != 0) + goto err_kfree; + + /* init flexcop */ + if ((ret = flexcop_device_initialize(fc)) != 0) + goto err_pci_exit; + + /* init dma */ + if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) + goto err_fc_exit; + + INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work); + + if (irq_chk_intv > 0) + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? + 100 : + irq_chk_intv)); + return ret; + +err_fc_exit: + flexcop_device_exit(fc); +err_pci_exit: + flexcop_pci_exit(fc_pci); +err_kfree: + flexcop_device_kfree(fc); + return ret; +} + +/* in theory every _exit function should be called exactly two times, + * here and in the bail-out-part of the _init-function + */ +static void flexcop_pci_remove(struct pci_dev *pdev) +{ + struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); + + if (irq_chk_intv > 0) + cancel_delayed_work(&fc_pci->irq_check_work); + + flexcop_pci_dma_exit(fc_pci); + flexcop_device_exit(fc_pci->fc_dev); + flexcop_pci_exit(fc_pci); + flexcop_device_kfree(fc_pci->fc_dev); +} + +static struct pci_device_id flexcop_pci_tbl[] = { + { PCI_DEVICE(0x13d0, 0x2103) }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); + +static struct pci_driver flexcop_pci_driver = { + .name = "b2c2_flexcop_pci", + .id_table = flexcop_pci_tbl, + .probe = flexcop_pci_probe, + .remove = flexcop_pci_remove, +}; + +static int __init flexcop_pci_module_init(void) +{ + return pci_register_driver(&flexcop_pci_driver); +} + +static void __exit flexcop_pci_module_exit(void) +{ + pci_unregister_driver(&flexcop_pci_driver); +} + +module_init(flexcop_pci_module_init); +module_exit(flexcop_pci_module_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,166 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII + * see flexcop.c for copyright information + */ +#ifndef __FLEXCOP_REG_H__ +#define __FLEXCOP_REG_H__ + +typedef enum { + FLEXCOP_UNK = 0, + FLEXCOP_II, + FLEXCOP_IIB, + FLEXCOP_III, +} flexcop_revision_t; + +typedef enum { + FC_UNK = 0, + FC_CABLE, + FC_AIR_DVBT, + FC_AIR_ATSC1, + FC_AIR_ATSC2, + FC_AIR_ATSC3, + FC_SKY_REV23, + FC_SKY_REV26, + FC_SKY_REV27, + FC_SKY_REV28, +} flexcop_device_type_t; + +typedef enum { + FC_USB = 0, + FC_PCI, +} flexcop_bus_t; + +/* FlexCop IBI Registers */ +#if defined(__LITTLE_ENDIAN) +#include "flexcop_ibi_value_le.h" +#else +#if defined(__BIG_ENDIAN) +#include "flexcop_ibi_value_be.h" +#else +#error no endian defined +#endif +#endif + +#define fc_data_Tag_ID_DVB 0x3e +#define fc_data_Tag_ID_ATSC 0x3f +#define fc_data_Tag_ID_IDSB 0x8b + +#define fc_key_code_default 0x1 +#define fc_key_code_even 0x2 +#define fc_key_code_odd 0x3 + +extern flexcop_ibi_value ibi_zero; + +typedef enum { + FC_I2C_PORT_DEMOD = 1, + FC_I2C_PORT_EEPROM = 2, + FC_I2C_PORT_TUNER = 3, +} flexcop_i2c_port_t; + +typedef enum { + FC_WRITE = 0, + FC_READ = 1, +} flexcop_access_op_t; + +typedef enum { + FC_SRAM_DEST_NET = 1, + FC_SRAM_DEST_CAI = 2, + FC_SRAM_DEST_CAO = 4, + FC_SRAM_DEST_MEDIA = 8 +} flexcop_sram_dest_t; + +typedef enum { + FC_SRAM_DEST_TARGET_WAN_USB = 0, + FC_SRAM_DEST_TARGET_DMA1 = 1, + FC_SRAM_DEST_TARGET_DMA2 = 2, + FC_SRAM_DEST_TARGET_FC3_CA = 3 +} flexcop_sram_dest_target_t; + +typedef enum { + FC_SRAM_2_32KB = 0, /* 64KB */ + FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */ + FC_SRAM_1_128KB = 2, /* 128KB */ + FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */ +} flexcop_sram_type_t; + +typedef enum { + FC_WAN_SPEED_4MBITS = 0, + FC_WAN_SPEED_8MBITS = 1, + FC_WAN_SPEED_12MBITS = 2, + FC_WAN_SPEED_16MBITS = 3, +} flexcop_wan_speed_t; + +typedef enum { + FC_DMA_1 = 1, + FC_DMA_2 = 2, +} flexcop_dma_index_t; + +typedef enum { + FC_DMA_SUBADDR_0 = 1, + FC_DMA_SUBADDR_1 = 2, +} flexcop_dma_addr_index_t; + +/* names of the particular registers */ +typedef enum { + dma1_000 = 0x000, + dma1_004 = 0x004, + dma1_008 = 0x008, + dma1_00c = 0x00c, + dma2_010 = 0x010, + dma2_014 = 0x014, + dma2_018 = 0x018, + dma2_01c = 0x01c, + + tw_sm_c_100 = 0x100, + tw_sm_c_104 = 0x104, + tw_sm_c_108 = 0x108, + tw_sm_c_10c = 0x10c, + tw_sm_c_110 = 0x110, + + lnb_switch_freq_200 = 0x200, + misc_204 = 0x204, + ctrl_208 = 0x208, + irq_20c = 0x20c, + sw_reset_210 = 0x210, + misc_214 = 0x214, + mbox_v8_to_host_218 = 0x218, + mbox_host_to_v8_21c = 0x21c, + + pid_filter_300 = 0x300, + pid_filter_304 = 0x304, + pid_filter_308 = 0x308, + pid_filter_30c = 0x30c, + index_reg_310 = 0x310, + pid_n_reg_314 = 0x314, + mac_low_reg_318 = 0x318, + mac_high_reg_31c = 0x31c, + + data_tag_400 = 0x400, + card_id_408 = 0x408, + card_id_40c = 0x40c, + mac_address_418 = 0x418, + mac_address_41c = 0x41c, + + ci_600 = 0x600, + pi_604 = 0x604, + pi_608 = 0x608, + dvb_reg_60c = 0x60c, + + sram_ctrl_reg_700 = 0x700, + net_buf_reg_704 = 0x704, + cai_buf_reg_708 = 0x708, + cao_buf_reg_70c = 0x70c, + media_buf_reg_710 = 0x710, + sram_dest_reg_714 = 0x714, + net_buf_reg_718 = 0x718, + wan_ctrl_reg_71c = 0x71c, +} flexcop_ibi_register; + +#define flexcop_set_ibi_value(reg,attr,val) { \ + flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \ + v.reg.attr = val; \ + fc->write_ibi_reg(fc,reg,v); \ +} + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-sram.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-sram.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-sram.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-sram.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,363 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-sram.c - functions for controlling the SRAM + * see flexcop.c for copyright information + */ +#include "flexcop.h" + +static void flexcop_sram_set_chip(struct flexcop_device *fc, + flexcop_sram_type_t type) +{ + flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type); +} + +int flexcop_sram_init(struct flexcop_device *fc) +{ + switch (fc->rev) { + case FLEXCOP_II: + case FLEXCOP_IIB: + flexcop_sram_set_chip(fc, FC_SRAM_1_32KB); + break; + case FLEXCOP_III: + flexcop_sram_set_chip(fc, FC_SRAM_1_48KB); + break; + default: + return -EINVAL; + } + return 0; +} + +int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, + flexcop_sram_dest_target_t target) +{ + flexcop_ibi_value v; + v = fc->read_ibi_reg(fc, sram_dest_reg_714); + + if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) { + err("SRAM destination target to available on FlexCopII(b)\n"); + return -EINVAL; + } + deb_sram("sram dest: %x target: %x\n", dest, target); + + if (dest & FC_SRAM_DEST_NET) + v.sram_dest_reg_714.NET_Dest = target; + if (dest & FC_SRAM_DEST_CAI) + v.sram_dest_reg_714.CAI_Dest = target; + if (dest & FC_SRAM_DEST_CAO) + v.sram_dest_reg_714.CAO_Dest = target; + if (dest & FC_SRAM_DEST_MEDIA) + v.sram_dest_reg_714.MEDIA_Dest = target; + + fc->write_ibi_reg(fc,sram_dest_reg_714,v); + udelay(1000); /* TODO delay really necessary */ + + return 0; +} +EXPORT_SYMBOL(flexcop_sram_set_dest); + +void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s) +{ + flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s); +} +EXPORT_SYMBOL(flexcop_wan_set_speed); + +void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); + v.sram_dest_reg_714.ctrl_usb_wan = usb_wan; + v.sram_dest_reg_714.ctrl_sramdma = sramdma; + v.sram_dest_reg_714.ctrl_maximumfill = maximumfill; + fc->write_ibi_reg(fc,sram_dest_reg_714,v); +} +EXPORT_SYMBOL(flexcop_sram_ctrl); + +#if 0 +static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) +{ + int i, retries; + u32 command; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04000000 | (*buf << 0x10); + + retries = 2; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __func__); + + write_reg_dw(adapter, 0x700, command); + + buf++; + addr++; + } +} + +static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) +{ + int i, retries; + u32 command, value; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04008000; + + retries = 10000; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __func__); + + write_reg_dw(adapter, 0x700, command); + + retries = 10000; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __func__); + + value = read_reg_dw(adapter, 0x700) >> 0x10; + + *buf = (value & 0xff); + + addr++; + buf++; + } +} + +static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) +{ + u32 bank; + + bank = 0; + + if (adapter->dw_sram_type == 0x20000) { + bank = (addr & 0x18000) << 0x0d; + } + + if (adapter->dw_sram_type == 0x00000) { + if ((addr >> 0x0f) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + flex_sram_write(adapter, bank, addr & 0x7fff, buf, len); +} + +static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) +{ + u32 bank; + bank = 0; + + if (adapter->dw_sram_type == 0x20000) { + bank = (addr & 0x18000) << 0x0d; + } + + if (adapter->dw_sram_type == 0x00000) { + if ((addr >> 0x0f) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + flex_sram_read(adapter, bank, addr & 0x7fff, buf, len); +} + +static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len) +{ + u32 length; + while (len != 0) { + length = len; + /* check if the address range belongs to the same + * 32K memory chip. If not, the data is read + * from one chip at a time */ + if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { + length = (((addr >> 0x0f) + 1) << 0x0f) - addr; + } + + sram_read_chunk(adapter, addr, buf, length); + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len) +{ + u32 length; + while (len != 0) { + length = len; + + /* check if the address range belongs to the same + * 32K memory chip. If not, the data is + * written to one chip at a time */ + if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { + length = (((addr >> 0x0f) + 1) << 0x0f) - addr; + } + + sram_write_chunk(adapter, addr, buf, length); + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void sram_set_size(struct adapter *adapter, u32 mask) +{ + write_reg_dw(adapter, 0x71c, + (mask | (~0x30000 & read_reg_dw(adapter, 0x71c)))); +} + +static void sram_init(struct adapter *adapter) +{ + u32 tmp; + tmp = read_reg_dw(adapter, 0x71c); + write_reg_dw(adapter, 0x71c, 1); + + if (read_reg_dw(adapter, 0x71c) != 0) { + write_reg_dw(adapter, 0x71c, tmp); + adapter->dw_sram_type = tmp & 0x30000; + ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type); + } else { + adapter->dw_sram_type = 0x10000; + ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type); + } +} + +static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr) +{ + u8 tmp1, tmp2; + dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr); + + sram_set_size(adapter, mask); + sram_init(adapter); + + tmp2 = 0xa5; + tmp1 = 0x4f; + + sram_write(adapter, addr, &tmp2, 1); + sram_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + mdelay(20); + + sram_read(adapter, addr, &tmp2, 1); + sram_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0xa5, read 0x%2x\n", __func__, tmp2); + + if (tmp2 != 0xa5) + return 0; + + tmp2 = 0x5a; + tmp1 = 0xf4; + + sram_write(adapter, addr, &tmp2, 1); + sram_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + mdelay(20); + + sram_read(adapter, addr, &tmp2, 1); + sram_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0x5a, read 0x%2x\n", __func__, tmp2); + + if (tmp2 != 0x5a) + return 0; + return 1; +} + +static u32 sram_length(struct adapter *adapter) +{ + if (adapter->dw_sram_type == 0x10000) + return 32768; /* 32K */ + if (adapter->dw_sram_type == 0x00000) + return 65536; /* 64K */ + if (adapter->dw_sram_type == 0x20000) + return 131072; /* 128K */ + return 32768; /* 32K */ +} + +/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. + - for 128K there are 4x32K chips at bank 0,1,2,3. + - for 64K there are 2x32K chips at bank 1,2. + - for 32K there is one 32K chip at bank 0. + + FlexCop works only with one bank at a time. The bank is selected + by bits 28-29 of the 0x700 register. + + bank 0 covers addresses 0x00000-0x07fff + bank 1 covers addresses 0x08000-0x0ffff + bank 2 covers addresses 0x10000-0x17fff + bank 3 covers addresses 0x18000-0x1ffff */ + +static int flexcop_sram_detect(struct flexcop_device *fc) +{ + flexcop_ibi_value r208, r71c_0, vr71c_1; + r208 = fc->read_ibi_reg(fc, ctrl_208); + fc->write_ibi_reg(fc, ctrl_208, ibi_zero); + + r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c); + write_reg_dw(adapter, 0x71c, 1); + tmp3 = read_reg_dw(adapter, 0x71c); + dprintk("%s: tmp3 = %x\n", __func__, tmp3); + write_reg_dw(adapter, 0x71c, tmp2); + + // check for internal SRAM ??? + tmp3--; + if (tmp3 != 0) { + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: sram size = 32K\n", __func__); + return 32; + } + + if (sram_test_location(adapter, 0x20000, 0x18000) != 0) { + sram_set_size(adapter, 0x20000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: sram size = 128K\n", __func__); + return 128; + } + + if (sram_test_location(adapter, 0x00000, 0x10000) != 0) { + sram_set_size(adapter, 0x00000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: sram size = 64K\n", __func__); + return 64; + } + + if (sram_test_location(adapter, 0x10000, 0x00000) != 0) { + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: sram size = 32K\n", __func__); + return 32; + } + + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + dprintk("%s: SRAM detection failed. Set to 32K \n", __func__); + return 0; +} + +static void sll_detect_sram_size(struct adapter *adapter) +{ + sram_detect_for_flex2(adapter); +} + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-usb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-usb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-usb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-usb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,608 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-usb.c - covers the USB part + * see flexcop.c for copyright information + */ +#define FC_LOG_PREFIX "flexcop_usb" +#include "flexcop-usb.h" +#include "flexcop-common.h" + +/* Version information */ +#define DRIVER_VERSION "0.1" +#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver" +#define DRIVER_AUTHOR "Patrick Boettcher " + +/* debug */ +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((debug & level)) printk(args); } while (0) + +#define debug_dump(b, l, method) do {\ + int i; \ + for (i = 0; i < l; i++) \ + method("%02x ", b[i]); \ + method("\n"); \ +} while (0) + +#define DEBSTATUS "" +#else +#define dprintk(level, args...) +#define debug_dump(b, l, method) +#define DEBSTATUS " (debugging is not enabled)" +#endif + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2," + "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS); +#undef DEBSTATUS + +#define deb_info(args...) dprintk(0x01, args) +#define deb_ts(args...) dprintk(0x02, args) +#define deb_ctrl(args...) dprintk(0x04, args) +#define deb_i2c(args...) dprintk(0x08, args) +#define deb_v8(args...) dprintk(0x10, args) + +/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits + * in the IBI address, to make the V8 code simpler. + * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used) + * in general: 0000 0HHH 000L LL00 + * IBI ADDRESS FORMAT: RHHH BLLL + * + * where R is the read(1)/write(0) bit, B is the busy bit + * and HHH and LLL are the two sets of three bits from the PCI address. + */ +#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \ + (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70)) +#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \ + (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4)) + +/* + * DKT 020228 + * - forget about this VENDOR_BUFFER_SIZE, read and write register + * deal with DWORD or 4 bytes, that should be should from now on + * - from now on, we don't support anything older than firm 1.00 + * I eliminated the write register as a 2 trip of writing hi word and lo word + * and force this to write only 4 bytes at a time. + * NOTE: this should work with all the firmware from 1.00 and newer + */ +static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read) +{ + struct flexcop_usb *fc_usb = fc->bus_specific; + u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG; + u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR; + u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | + (read ? 0x80 : 0); + + int len = usb_control_msg(fc_usb->udev, + read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT, + request, + request_type, /* 0xc0 read or 0x40 write */ + wAddress, + 0, + val, + sizeof(u32), + B2C2_WAIT_FOR_OPERATION_RDW * HZ); + + if (len != sizeof(u32)) { + err("error while %s dword from %d (%d).", read ? "reading" : + "writing", wAddress, wRegOffsPCI); + return -EIO; + } + return 0; +} +/* + * DKT 010817 - add support for V8 memory read/write and flash update + */ +static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb, + flexcop_usb_request_t req, u8 page, u16 wAddress, + u8 *pbBuffer, u32 buflen) +{ + u8 request_type = USB_TYPE_VENDOR; + u16 wIndex; + int nWaitTime, pipe, len; + wIndex = page << 8; + + switch (req) { + case B2C2_USB_READ_V8_MEM: + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ; + request_type |= USB_DIR_IN; + pipe = B2C2_USB_CTRL_PIPE_IN; + break; + case B2C2_USB_WRITE_V8_MEM: + wIndex |= pbBuffer[0]; + request_type |= USB_DIR_OUT; + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE; + pipe = B2C2_USB_CTRL_PIPE_OUT; + break; + case B2C2_USB_FLASH_BLOCK: + request_type |= USB_DIR_OUT; + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH; + pipe = B2C2_USB_CTRL_PIPE_OUT; + break; + default: + deb_info("unsupported request for v8_mem_req %x.\n", req); + return -EINVAL; + } + deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req, + wAddress, wIndex, buflen); + + len = usb_control_msg(fc_usb->udev, pipe, + req, + request_type, + wAddress, + wIndex, + pbBuffer, + buflen, + nWaitTime * HZ); + + debug_dump(pbBuffer, len, deb_v8); + return len == buflen ? 0 : -EIO; +} + +#define bytes_left_to_read_on_page(paddr,buflen) \ + ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \ + ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK))) + +static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, + flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start, + u32 addr, int extended, u8 *buf, u32 len) +{ + int i,ret = 0; + u16 wMax; + u32 pagechunk = 0; + + switch(req) { + case B2C2_USB_READ_V8_MEM: + wMax = USB_MEM_READ_MAX; + break; + case B2C2_USB_WRITE_V8_MEM: + wMax = USB_MEM_WRITE_MAX; + break; + case B2C2_USB_FLASH_BLOCK: + wMax = USB_FLASH_MAX; + break; + default: + return -EINVAL; + break; + } + for (i = 0; i < len;) { + pagechunk = + wMax < bytes_left_to_read_on_page(addr, len) ? + wMax : + bytes_left_to_read_on_page(addr, len); + deb_info("%x\n", + (addr & V8_MEMORY_PAGE_MASK) | + (V8_MEMORY_EXTENDED*extended)); + + ret = flexcop_usb_v8_memory_req(fc_usb, req, + page_start + (addr / V8_MEMORY_PAGE_SIZE), + (addr & V8_MEMORY_PAGE_MASK) | + (V8_MEMORY_EXTENDED*extended), + &buf[i], pagechunk); + + if (ret < 0) + return ret; + addr += pagechunk; + len -= pagechunk; + } + return 0; +} + +static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended) +{ + return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM, + V8_MEMORY_PAGE_FLASH, 0x1f010, 1, + fc->dvb_adapter.proposed_mac, 6); +} + +#if 0 +static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set, + flexcop_usb_utility_function_t func, u8 extra, u16 wIndex, + u16 buflen, u8 *pvBuffer) +{ + u16 wValue; + u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR; + int nWaitTime = 2, + pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len; + wValue = (func << 8) | extra; + + len = usb_control_msg(fc_usb->udev,pipe, + B2C2_USB_UTILITY, + request_type, + wValue, + wIndex, + pvBuffer, + buflen, + nWaitTime * HZ); + return len == buflen ? 0 : -EIO; +} +#endif + +/* usb i2c stuff */ +static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c, + flexcop_usb_request_t req, flexcop_usb_i2c_function_t func, + u8 chipaddr, u8 addr, u8 *buf, u8 buflen) +{ + struct flexcop_usb *fc_usb = i2c->fc->bus_specific; + u16 wValue, wIndex; + int nWaitTime,pipe,len; + u8 request_type = USB_TYPE_VENDOR; + + switch (func) { + case USB_FUNC_I2C_WRITE: + case USB_FUNC_I2C_MULTIWRITE: + case USB_FUNC_I2C_REPEATWRITE: + /* DKT 020208 - add this to support special case of DiSEqC */ + case USB_FUNC_I2C_CHECKWRITE: + pipe = B2C2_USB_CTRL_PIPE_OUT; + nWaitTime = 2; + request_type |= USB_DIR_OUT; + break; + case USB_FUNC_I2C_READ: + case USB_FUNC_I2C_REPEATREAD: + pipe = B2C2_USB_CTRL_PIPE_IN; + nWaitTime = 2; + request_type |= USB_DIR_IN; + break; + default: + deb_info("unsupported function for i2c_req %x\n", func); + return -EINVAL; + } + wValue = (func << 8) | (i2c->port << 4); + wIndex = (chipaddr << 8 ) | addr; + + deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n", + func, request_type, req, + wValue & 0xff, wValue >> 8, + wIndex & 0xff, wIndex >> 8); + + len = usb_control_msg(fc_usb->udev,pipe, + req, + request_type, + wValue, + wIndex, + buf, + buflen, + nWaitTime * HZ); + return len == buflen ? 0 : -EREMOTEIO; +} + +/* actual bus specific access functions, + make sure prototype are/will be equal to pci */ +static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, + flexcop_ibi_register reg) +{ + flexcop_ibi_value val; + val.raw = 0; + flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1); + return val; +} + +static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, + flexcop_ibi_register reg, flexcop_ibi_value val) +{ + return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0); +} + +static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c, + flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len) +{ + if (op == FC_READ) + return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, + USB_FUNC_I2C_READ, chipaddr, addr, buf, len); + else + return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST, + USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len); +} + +static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, + u8 *buffer, int buffer_length) +{ + u8 *b; + int l; + + deb_ts("tmp_buffer_length=%d, buffer_length=%d\n", + fc_usb->tmp_buffer_length, buffer_length); + + if (fc_usb->tmp_buffer_length > 0) { + memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer, + buffer_length); + fc_usb->tmp_buffer_length += buffer_length; + b = fc_usb->tmp_buffer; + l = fc_usb->tmp_buffer_length; + } else { + b=buffer; + l=buffer_length; + } + + while (l >= 190) { + if (*b == 0xff) { + switch (*(b+1) & 0x03) { + case 0x01: /* media packet */ + if (*(b+2) == 0x47) + flexcop_pass_dmx_packets( + fc_usb->fc_dev, b+2, 1); + else + deb_ts( + "not ts packet %02x %02x %02x %02x \n", + *(b+2), *(b+3), + *(b+4), *(b+5)); + b += 190; + l -= 190; + break; + default: + deb_ts("wrong packet type\n"); + l = 0; + break; + } + } else { + deb_ts("wrong header\n"); + l = 0; + } + } + + if (l>0) + memcpy(fc_usb->tmp_buffer, b, l); + fc_usb->tmp_buffer_length = l; +} + +static void flexcop_usb_urb_complete(struct urb *urb) +{ + struct flexcop_usb *fc_usb = urb->context; + int i; + + if (urb->actual_length > 0) + deb_ts("urb completed, bufsize: %d actlen; %d\n", + urb->transfer_buffer_length, urb->actual_length); + + for (i = 0; i < urb->number_of_packets; i++) { + if (urb->iso_frame_desc[i].status < 0) { + err("iso frame descriptor %d has an error: %d\n", i, + urb->iso_frame_desc[i].status); + } else + if (urb->iso_frame_desc[i].actual_length > 0) { + deb_ts("passed %d bytes to the demux\n", + urb->iso_frame_desc[i].actual_length); + + flexcop_usb_process_frame(fc_usb, + urb->transfer_buffer + + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + usb_submit_urb(urb,GFP_ATOMIC); +} + +static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff) +{ + /* submit/kill iso packets */ + return 0; +} + +static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) +{ + int i; + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) + if (fc_usb->iso_urb[i] != NULL) { + deb_ts("unlinking/killing urb no. %d\n",i); + usb_kill_urb(fc_usb->iso_urb[i]); + usb_free_urb(fc_usb->iso_urb[i]); + } + + if (fc_usb->iso_buffer != NULL) + pci_free_consistent(NULL, + fc_usb->buffer_size, fc_usb->iso_buffer, + fc_usb->dma_addr); +} + +static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) +{ + u16 frame_size = le16_to_cpu( + fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize); + int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * + frame_size, i, j, ret; + int buffer_offset = 0; + + deb_ts("creating %d iso-urbs with %d frames " + "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB, + B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize); + + fc_usb->iso_buffer = pci_alloc_consistent(NULL, + bufsize, &fc_usb->dma_addr); + if (fc_usb->iso_buffer == NULL) + return -ENOMEM; + + memset(fc_usb->iso_buffer, 0, bufsize); + fc_usb->buffer_size = bufsize; + + /* creating iso urbs */ + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { + fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO, + GFP_ATOMIC); + if (fc_usb->iso_urb[i] == NULL) { + ret = -ENOMEM; + goto urb_error; + } + } + + /* initialising and submitting iso urbs */ + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { + int frame_offset = 0; + struct urb *urb = fc_usb->iso_urb[i]; + deb_ts("initializing and submitting urb no. %d " + "(buf_offset: %d).\n", i, buffer_offset); + + urb->dev = fc_usb->udev; + urb->context = fc_usb; + urb->complete = flexcop_usb_urb_complete; + urb->pipe = B2C2_USB_DATA_PIPE; + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO; + urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO; + urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset; + + buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO; + for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) { + deb_ts("urb no: %d, frame: %d, frame_offset: %d\n", + i, j, frame_offset); + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = frame_size; + frame_offset += frame_size; + } + + if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) { + err("submitting urb %d failed with %d.", i, ret); + goto urb_error; + } + deb_ts("submitted urb no. %d.\n",i); + } + + /* SRAM */ + flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA | + FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, + FC_SRAM_DEST_TARGET_WAN_USB); + flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS); + flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1); + return 0; + +urb_error: + flexcop_usb_transfer_exit(fc_usb); + return ret; +} + +static int flexcop_usb_init(struct flexcop_usb *fc_usb) +{ + /* use the alternate setting with the larges buffer */ + usb_set_interface(fc_usb->udev,0,1); + switch (fc_usb->udev->speed) { + case USB_SPEED_LOW: + err("cannot handle USB speed because it is too slow."); + return -ENODEV; + break; + case USB_SPEED_FULL: + info("running at FULL speed."); + break; + case USB_SPEED_HIGH: + info("running at HIGH speed."); + break; + case USB_SPEED_UNKNOWN: /* fall through */ + default: + err("cannot handle USB speed because it is unknown."); + return -ENODEV; + } + usb_set_intfdata(fc_usb->uintf, fc_usb); + return 0; +} + +static void flexcop_usb_exit(struct flexcop_usb *fc_usb) +{ + usb_set_intfdata(fc_usb->uintf, NULL); +} + +static int flexcop_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct flexcop_usb *fc_usb = NULL; + struct flexcop_device *fc = NULL; + int ret; + + if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { + err("out of memory\n"); + return -ENOMEM; + } + + /* general flexcop init */ + fc_usb = fc->bus_specific; + fc_usb->fc_dev = fc; + + fc->read_ibi_reg = flexcop_usb_read_ibi_reg; + fc->write_ibi_reg = flexcop_usb_write_ibi_reg; + fc->i2c_request = flexcop_usb_i2c_request; + fc->get_mac_addr = flexcop_usb_get_mac_addr; + + fc->stream_control = flexcop_usb_stream_control; + + fc->pid_filtering = 1; + fc->bus_type = FC_USB; + + fc->dev = &udev->dev; + fc->owner = THIS_MODULE; + + /* bus specific part */ + fc_usb->udev = udev; + fc_usb->uintf = intf; + if ((ret = flexcop_usb_init(fc_usb)) != 0) + goto err_kfree; + + /* init flexcop */ + if ((ret = flexcop_device_initialize(fc)) != 0) + goto err_usb_exit; + + /* xfer init */ + if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0) + goto err_fc_exit; + + info("%s successfully initialized and connected.", DRIVER_NAME); + return 0; + +err_fc_exit: + flexcop_device_exit(fc); +err_usb_exit: + flexcop_usb_exit(fc_usb); +err_kfree: + flexcop_device_kfree(fc); + return ret; +} + +static void flexcop_usb_disconnect(struct usb_interface *intf) +{ + struct flexcop_usb *fc_usb = usb_get_intfdata(intf); + flexcop_usb_transfer_exit(fc_usb); + flexcop_device_exit(fc_usb->fc_dev); + flexcop_usb_exit(fc_usb); + flexcop_device_kfree(fc_usb->fc_dev); + info("%s successfully deinitialized and disconnected.", DRIVER_NAME); +} + +static struct usb_device_id flexcop_usb_table [] = { + { USB_DEVICE(0x0af7, 0x0101) }, + { } +}; +MODULE_DEVICE_TABLE (usb, flexcop_usb_table); + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver flexcop_usb_driver = { + .name = "b2c2_flexcop_usb", + .probe = flexcop_usb_probe, + .disconnect = flexcop_usb_disconnect, + .id_table = flexcop_usb_table, +}; + +/* module stuff */ +static int __init flexcop_usb_module_init(void) +{ + int result; + if ((result = usb_register(&flexcop_usb_driver))) { + err("usb_register failed. (%d)", result); + return result; + } + return 0; +} + +static void __exit flexcop_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&flexcop_usb_driver); +} + +module_init(flexcop_usb_module_init); +module_exit(flexcop_usb_module_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-usb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-usb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-usb.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/flexcop-usb.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-usb.h - header file for the USB part + * see flexcop.c for copyright information + */ +#ifndef __FLEXCOP_USB_H_INCLUDED__ +#define __FLEXCOP_USB_H_INCLUDED__ + +#include + +/* transfer parameters */ +#define B2C2_USB_FRAMES_PER_ISO 4 +#define B2C2_USB_NUM_ISO_URB 4 + +#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev, 0) +#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev, 0) +#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 0x81) + +struct flexcop_usb { + struct usb_device *udev; + struct usb_interface *uintf; + + u8 *iso_buffer; + int buffer_size; + dma_addr_t dma_addr; + + struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; + struct flexcop_device *fc_dev; + + u8 tmp_buffer[1023+190]; + int tmp_buffer_length; +}; + +#if 0 +/* request types TODO What is its use?*/ +typedef enum { + +} flexcop_usb_request_type_t; +#endif + +/* request */ +typedef enum { + B2C2_USB_WRITE_V8_MEM = 0x04, + B2C2_USB_READ_V8_MEM = 0x05, + B2C2_USB_READ_REG = 0x08, + B2C2_USB_WRITE_REG = 0x0A, + B2C2_USB_WRITEREGHI = 0x0B, + B2C2_USB_FLASH_BLOCK = 0x10, + B2C2_USB_I2C_REQUEST = 0x11, + B2C2_USB_UTILITY = 0x12, +} flexcop_usb_request_t; + +/* function definition for I2C_REQUEST */ +typedef enum { + USB_FUNC_I2C_WRITE = 0x01, + USB_FUNC_I2C_MULTIWRITE = 0x02, + USB_FUNC_I2C_READ = 0x03, + USB_FUNC_I2C_REPEATWRITE = 0x04, + USB_FUNC_GET_DESCRIPTOR = 0x05, + USB_FUNC_I2C_REPEATREAD = 0x06, + /* DKT 020208 - add this to support special case of DiSEqC */ + USB_FUNC_I2C_CHECKWRITE = 0x07, + USB_FUNC_I2C_CHECKRESULT = 0x08, +} flexcop_usb_i2c_function_t; + +/* function definition for UTILITY request 0x12 + * DKT 020304 - new utility function */ +typedef enum { + UTILITY_SET_FILTER = 0x01, + UTILITY_DATA_ENABLE = 0x02, + UTILITY_FLEX_MULTIWRITE = 0x03, + UTILITY_SET_BUFFER_SIZE = 0x04, + UTILITY_FLEX_OPERATOR = 0x05, + UTILITY_FLEX_RESET300_START = 0x06, + UTILITY_FLEX_RESET300_STOP = 0x07, + UTILITY_FLEX_RESET300 = 0x08, + UTILITY_SET_ISO_SIZE = 0x09, + UTILITY_DATA_RESET = 0x0A, + UTILITY_GET_DATA_STATUS = 0x10, + UTILITY_GET_V8_REG = 0x11, + /* DKT 020326 - add function for v1.14 */ + UTILITY_SRAM_WRITE = 0x12, + UTILITY_SRAM_READ = 0x13, + UTILITY_SRAM_TESTFILL = 0x14, + UTILITY_SRAM_TESTSET = 0x15, + UTILITY_SRAM_TESTVERIFY = 0x16, +} flexcop_usb_utility_function_t; + +#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ) +#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ) +#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ) + +#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ) +#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ) +#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ) + +typedef enum { + V8_MEMORY_PAGE_DVB_CI = 0x20, + V8_MEMORY_PAGE_DVB_DS = 0x40, + V8_MEMORY_PAGE_MULTI2 = 0x60, + V8_MEMORY_PAGE_FLASH = 0x80 +} flexcop_usb_mem_page_t; + +#define V8_MEMORY_EXTENDED (1 << 15) +#define USB_MEM_READ_MAX 32 +#define USB_MEM_WRITE_MAX 1 +#define USB_FLASH_MAX 8 +#define V8_MEMORY_PAGE_SIZE 0x8000 /* 32K */ +#define V8_MEMORY_PAGE_MASK 0x7FFF + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,45 @@ +config DVB_B2C2_FLEXCOP + tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters" + depends on DVB_CORE && I2C + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_MT312 if !DVB_FE_CUSTOMISE + select DVB_NXT200X if !DVB_FE_CUSTOMISE + select DVB_STV0297 if !DVB_FE_CUSTOMISE + select DVB_BCM3510 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_S5H1420 if !DVB_FE_CUSTOMISE + select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE + select DVB_ISL6421 if !DVB_FE_CUSTOMISE + select DVB_CX24123 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE + help + Support for the digital TV receiver chip made by B2C2 Inc. included in + Technisats PCI cards and USB boxes. + + Say Y if you own such a device and want to use it. + +config DVB_B2C2_FLEXCOP_PCI + tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI" + depends on DVB_B2C2_FLEXCOP && PCI && I2C + help + Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2. + + Say Y if you own such a device and want to use it. + +config DVB_B2C2_FLEXCOP_USB + tristate "Technisat/B2C2 Air/Sky/Cable2PC USB" + depends on DVB_B2C2_FLEXCOP && USB && I2C + help + Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2, + + Say Y if you own such a device and want to use it. + +config DVB_B2C2_FLEXCOP_DEBUG + bool "Enable debug for the B2C2 FlexCop drivers" + depends on DVB_B2C2_FLEXCOP + help + Say Y if you want to enable the module option to control debug messages + of all B2C2 FlexCop drivers. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/b2c2/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,16 @@ +b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \ + flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o +obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o + +ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),) +b2c2-flexcop-objs += flexcop-dma.o +endif + +b2c2-flexcop-pci-objs = flexcop-pci.o +obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o + +b2c2-flexcop-usb-objs = flexcop-usb.o +obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/bt878.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/bt878.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/bt878.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/bt878.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,609 @@ +/* + * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card + * + * Copyright (C) 2002 Peter Hettkamp + * + * large parts based on the bttv driver + * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de) + * & Marcus Metzler (mocm@metzlerbros.de) + * (c) 1999,2000 Gerd Knorr + * + * 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, or (at your option) any later version. + * + + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "bt878.h" +#include "dst_priv.h" + + +/**************************************/ +/* Miscellaneous utility definitions */ +/**************************************/ + +static unsigned int bt878_verbose = 1; +static unsigned int bt878_debug; + +module_param_named(verbose, bt878_verbose, int, 0444); +MODULE_PARM_DESC(verbose, + "verbose startup messages, default is 1 (yes)"); +module_param_named(debug, bt878_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off)."); + +int bt878_num; +struct bt878 bt878[BT878_MAX]; + +EXPORT_SYMBOL(bt878_num); +EXPORT_SYMBOL(bt878); + +#define btwrite(dat,adr) bmtwrite((dat), (bt->bt878_mem+(adr))) +#define btread(adr) bmtread(bt->bt878_mem+(adr)) + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#if defined(dprintk) +#undef dprintk +#endif +#define dprintk(fmt, arg...) \ + do { \ + if (bt878_debug) \ + printk(KERN_DEBUG fmt, ##arg); \ + } while (0) + +static void bt878_mem_free(struct bt878 *bt) +{ + if (bt->buf_cpu) { + pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu, + bt->buf_dma); + bt->buf_cpu = NULL; + } + + if (bt->risc_cpu) { + pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu, + bt->risc_dma); + bt->risc_cpu = NULL; + } +} + +static int bt878_mem_alloc(struct bt878 *bt) +{ + if (!bt->buf_cpu) { + bt->buf_size = 128 * 1024; + + bt->buf_cpu = + pci_alloc_consistent(bt->dev, bt->buf_size, + &bt->buf_dma); + + if (!bt->buf_cpu) + return -ENOMEM; + + memset(bt->buf_cpu, 0, bt->buf_size); + } + + if (!bt->risc_cpu) { + bt->risc_size = PAGE_SIZE; + bt->risc_cpu = + pci_alloc_consistent(bt->dev, bt->risc_size, + &bt->risc_dma); + + if (!bt->risc_cpu) { + bt878_mem_free(bt); + return -ENOMEM; + } + + memset(bt->risc_cpu, 0, bt->risc_size); + } + + return 0; +} + +/* RISC instructions */ +#define RISC_WRITE (0x01 << 28) +#define RISC_JUMP (0x07 << 28) +#define RISC_SYNC (0x08 << 28) + +/* RISC bits */ +#define RISC_WR_SOL (1 << 27) +#define RISC_WR_EOL (1 << 26) +#define RISC_IRQ (1 << 24) +#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16)) +#define RISC_SYNC_RESYNC (1 << 15) +#define RISC_SYNC_FM1 0x06 +#define RISC_SYNC_VRO 0x0C + +#define RISC_FLUSH() bt->risc_pos = 0 +#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr) + +static int bt878_make_risc(struct bt878 *bt) +{ + bt->block_bytes = bt->buf_size >> 4; + bt->block_count = 1 << 4; + bt->line_bytes = bt->block_bytes; + bt->line_count = bt->block_count; + + while (bt->line_bytes > 4095) { + bt->line_bytes >>= 1; + bt->line_count <<= 1; + } + + if (bt->line_count > 255) { + printk(KERN_ERR "bt878: buffer size error!\n"); + return -EINVAL; + } + return 0; +} + + +static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin) +{ + u32 buf_pos = 0; + u32 line; + + RISC_FLUSH(); + RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin); + RISC_INSTR(0); + + dprintk("bt878: risc len lines %u, bytes per line %u\n", + bt->line_count, bt->line_bytes); + for (line = 0; line < bt->line_count; line++) { + // At the beginning of every block we issue an IRQ with previous (finished) block number set + if (!(buf_pos % bt->block_bytes)) + RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | + RISC_IRQ | + RISC_STATUS(((buf_pos / + bt->block_bytes) + + (bt->block_count - + 1)) % + bt->block_count) | bt-> + line_bytes); + else + RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | + bt->line_bytes); + RISC_INSTR(bt->buf_dma + buf_pos); + buf_pos += bt->line_bytes; + } + + RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO); + RISC_INSTR(0); + + RISC_INSTR(RISC_JUMP); + RISC_INSTR(bt->risc_dma); + + btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN); +} + +/*****************************/ +/* Start/Stop grabbing funcs */ +/*****************************/ + +void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, + u32 irq_err_ignore) +{ + u32 int_mask; + + dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg); + /* complete the writing of the risc dma program now we have + * the card specifics + */ + bt878_risc_program(bt, op_sync_orin); + controlreg &= ~0x1f; + controlreg |= 0x1b; + + btwrite(bt->risc_dma, BT878_ARISC_START); + + /* original int mask had : + * 6 2 8 4 0 + * 1111 1111 1000 0000 0000 + * SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI + * Hacked for DST to: + * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI + */ + int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT | + BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT | + BT878_AFBUS | BT878_ARISCI; + + + /* ignore pesky bits */ + int_mask &= ~irq_err_ignore; + + btwrite(int_mask, BT878_AINT_MASK); + btwrite(controlreg, BT878_AGPIO_DMA_CTL); +} + +void bt878_stop(struct bt878 *bt) +{ + u32 stat; + int i = 0; + + dprintk("bt878 debug: bt878_stop\n"); + + btwrite(0, BT878_AINT_MASK); + btand(~0x13, BT878_AGPIO_DMA_CTL); + + do { + stat = btread(BT878_AINT_STAT); + if (!(stat & BT878_ARISC_EN)) + break; + i++; + } while (i < 500); + + dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n", + bt->nr, i, stat); +} + +EXPORT_SYMBOL(bt878_start); +EXPORT_SYMBOL(bt878_stop); + +/*****************************/ +/* Interrupt service routine */ +/*****************************/ + +static irqreturn_t bt878_irq(int irq, void *dev_id) +{ + u32 stat, astat, mask; + int count; + struct bt878 *bt; + + bt = (struct bt878 *) dev_id; + + count = 0; + while (1) { + stat = btread(BT878_AINT_STAT); + mask = btread(BT878_AINT_MASK); + if (!(astat = (stat & mask))) + return IRQ_NONE; /* this interrupt is not for me */ +/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */ + btwrite(astat, BT878_AINT_STAT); /* try to clear interrupt condition */ + + + if (astat & (BT878_ASCERR | BT878_AOCERR)) { + if (bt878_verbose) { + printk(KERN_INFO + "bt878(%d): irq%s%s risc_pc=%08x\n", + bt->nr, + (astat & BT878_ASCERR) ? " SCERR" : + "", + (astat & BT878_AOCERR) ? " OCERR" : + "", btread(BT878_ARISC_PC)); + } + } + if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) { + if (bt878_verbose) { + printk(KERN_INFO + "bt878(%d): irq%s%s%s risc_pc=%08x\n", + bt->nr, + (astat & BT878_APABORT) ? " PABORT" : + "", + (astat & BT878_ARIPERR) ? " RIPERR" : + "", + (astat & BT878_APPERR) ? " PPERR" : + "", btread(BT878_ARISC_PC)); + } + } + if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) { + if (bt878_verbose) { + printk(KERN_INFO + "bt878(%d): irq%s%s%s risc_pc=%08x\n", + bt->nr, + (astat & BT878_AFDSR) ? " FDSR" : "", + (astat & BT878_AFTRGT) ? " FTRGT" : + "", + (astat & BT878_AFBUS) ? " FBUS" : "", + btread(BT878_ARISC_PC)); + } + } + if (astat & BT878_ARISCI) { + bt->finished_block = (stat & BT878_ARISCS) >> 28; + tasklet_schedule(&bt->tasklet); + break; + } + count++; + if (count > 20) { + btwrite(0, BT878_AINT_MASK); + printk(KERN_ERR + "bt878(%d): IRQ lockup, cleared int mask\n", + bt->nr); + break; + } + } + return IRQ_HANDLED; +} + +int +bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp) +{ + int retval; + + retval = 0; + if (mutex_lock_interruptible(&bt->gpio_lock)) + return -ERESTARTSYS; + /* special gpio signal */ + switch (cmd) { + case DST_IG_ENABLE: + // dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable); + retval = bttv_gpio_enable(bt->bttv_nr, + mp->enb.mask, + mp->enb.enable); + break; + case DST_IG_WRITE: + // dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals); + retval = bttv_write_gpio(bt->bttv_nr, + mp->outp.mask, + mp->outp.highvals); + + break; + case DST_IG_READ: + /* read */ + retval = bttv_read_gpio(bt->bttv_nr, &mp->rd.value); + // dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value); + break; + case DST_IG_TS: + /* Set packet size */ + bt->TS_Size = mp->psize; + break; + + default: + retval = -EINVAL; + break; + } + mutex_unlock(&bt->gpio_lock); + return retval; +} + +EXPORT_SYMBOL(bt878_device_control); + +#define BROOKTREE_878_DEVICE(vend, dev, name) \ + { \ + .vendor = PCI_VENDOR_ID_BROOKTREE, \ + .device = PCI_DEVICE_ID_BROOKTREE_878, \ + .subvendor = (vend), .subdevice = (dev), \ + .driver_data = (unsigned long) name \ + } + +static struct pci_device_id bt878_pci_tbl[] __devinitdata = { + BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), + BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), + BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), + BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"), + BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"), + BROOKTREE_878_DEVICE(0x270f, 0xfc00, + "ChainTech digitop DST-1000 DVB-S"), + BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"), + BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"), + BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"), + BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"), + BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"), + BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"), + { } +}; + +MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); + +static const char * __devinit card_name(const struct pci_device_id *id) +{ + return id->driver_data ? (const char *)id->driver_data : "Unknown"; +} + +/***********************/ +/* PCI device handling */ +/***********************/ + +static int __devinit bt878_probe(struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + int result = 0; + unsigned char lat; + struct bt878 *bt; +#if defined(__powerpc__) + unsigned int cmd; +#endif + unsigned int cardid; + + printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", + bt878_num); + if (bt878_num >= BT878_MAX) { + printk(KERN_ERR "bt878: Too many devices inserted\n"); + result = -ENOMEM; + goto fail0; + } + if (pci_enable_device(dev)) + return -EIO; + + cardid = dev->subsystem_device << 16; + cardid |= dev->subsystem_vendor; + + printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n", + __func__, cardid, card_name(pci_id)); + + bt = &bt878[bt878_num]; + bt->dev = dev; + bt->nr = bt878_num; + bt->shutdown = 0; + + bt->id = dev->device; + bt->irq = dev->irq; + bt->bt878_adr = pci_resource_start(dev, 0); + if (!request_mem_region(pci_resource_start(dev, 0), + pci_resource_len(dev, 0), "bt878")) { + result = -EBUSY; + goto fail0; + } + + bt->revision = dev->revision; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + + + printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ", + bt878_num, bt->id, bt->revision, dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + printk("irq: %d, latency: %d, memory: 0x%lx\n", + bt->irq, lat, bt->bt878_adr); + + +#if defined(__powerpc__) + /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ + /* response on cards with no firmware is not enabled by OF */ + pci_read_config_dword(dev, PCI_COMMAND, &cmd); + cmd = (cmd | PCI_COMMAND_MEMORY); + pci_write_config_dword(dev, PCI_COMMAND, cmd); +#endif + +#ifdef __sparc__ + bt->bt878_mem = (unsigned char *) bt->bt878_adr; +#else + bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000); +#endif + + /* clear interrupt mask */ + btwrite(0, BT848_INT_MASK); + + result = request_irq(bt->irq, bt878_irq, + IRQF_SHARED | IRQF_DISABLED, "bt878", + (void *) bt); + if (result == -EINVAL) { + printk(KERN_ERR "bt878(%d): Bad irq number or handler\n", + bt878_num); + goto fail1; + } + if (result == -EBUSY) { + printk(KERN_ERR + "bt878(%d): IRQ %d busy, change your PnP config in BIOS\n", + bt878_num, bt->irq); + goto fail1; + } + if (result < 0) + goto fail1; + + pci_set_master(dev); + pci_set_drvdata(dev, bt); + + if ((result = bt878_mem_alloc(bt))) { + printk(KERN_ERR "bt878: failed to allocate memory!\n"); + goto fail2; + } + + bt878_make_risc(bt); + btwrite(0, BT878_AINT_MASK); + bt878_num++; + + return 0; + + fail2: + free_irq(bt->irq, bt); + fail1: + release_mem_region(pci_resource_start(bt->dev, 0), + pci_resource_len(bt->dev, 0)); + fail0: + pci_disable_device(dev); + return result; +} + +static void __devexit bt878_remove(struct pci_dev *pci_dev) +{ + u8 command; + struct bt878 *bt = pci_get_drvdata(pci_dev); + + if (bt878_verbose) + printk(KERN_INFO "bt878(%d): unloading\n", bt->nr); + + /* turn off all capturing, DMA and IRQs */ + btand(~0x13, BT878_AGPIO_DMA_CTL); + + /* first disable interrupts before unmapping the memory! */ + btwrite(0, BT878_AINT_MASK); + btwrite(~0U, BT878_AINT_STAT); + + /* disable PCI bus-mastering */ + pci_read_config_byte(bt->dev, PCI_COMMAND, &command); + /* Should this be &=~ ?? */ + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte(bt->dev, PCI_COMMAND, command); + + free_irq(bt->irq, bt); + printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem); + if (bt->bt878_mem) + iounmap(bt->bt878_mem); + + release_mem_region(pci_resource_start(bt->dev, 0), + pci_resource_len(bt->dev, 0)); + /* wake up any waiting processes + because shutdown flag is set, no new processes (in this queue) + are expected + */ + bt->shutdown = 1; + bt878_mem_free(bt); + + pci_set_drvdata(pci_dev, NULL); + pci_disable_device(pci_dev); + return; +} + +static struct pci_driver bt878_pci_driver = { + .name = "bt878", + .id_table = bt878_pci_tbl, + .probe = bt878_probe, + .remove = __devexit_p(bt878_remove), +}; + +/*******************************/ +/* Module management functions */ +/*******************************/ + +static int __init bt878_init_module(void) +{ + bt878_num = 0; + + printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n", + (BT878_VERSION_CODE >> 16) & 0xff, + (BT878_VERSION_CODE >> 8) & 0xff, + BT878_VERSION_CODE & 0xff); + + return pci_register_driver(&bt878_pci_driver); +} + +static void __exit bt878_cleanup_module(void) +{ + pci_unregister_driver(&bt878_pci_driver); +} + +module_init(bt878_init_module); +module_exit(bt878_cleanup_module); + +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/bt878.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/bt878.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/bt878.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/bt878.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,159 @@ +/* + bt878.h - Bt878 audio module (register offsets) + + Copyright (C) 2002 Peter Hettkamp + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BT878_H_ +#define _BT878_H_ + +#include +#include +#include +#include +#include + +#include "bt848.h" +#include "bttv.h" + +#define BT878_VERSION_CODE 0x000000 + +#define BT878_AINT_STAT 0x100 +#define BT878_ARISCS (0xf<<28) +#define BT878_ARISC_EN (1<<27) +#define BT878_ASCERR (1<<19) +#define BT878_AOCERR (1<<18) +#define BT878_APABORT (1<<17) +#define BT878_ARIPERR (1<<16) +#define BT878_APPERR (1<<15) +#define BT878_AFDSR (1<<14) +#define BT878_AFTRGT (1<<13) +#define BT878_AFBUS (1<<12) +#define BT878_ARISCI (1<<11) +#define BT878_AOFLOW (1<<3) + +#define BT878_AINT_MASK 0x104 + +#define BT878_AGPIO_DMA_CTL 0x10c +#define BT878_A_GAIN (0xf<<28) +#define BT878_A_G2X (1<<27) +#define BT878_A_PWRDN (1<<26) +#define BT878_A_SEL (3<<24) +#define BT878_DA_SCE (1<<23) +#define BT878_DA_LRI (1<<22) +#define BT878_DA_MLB (1<<21) +#define BT878_DA_LRD (0x1f<<16) +#define BT878_DA_DPM (1<<15) +#define BT878_DA_SBR (1<<14) +#define BT878_DA_ES2 (1<<13) +#define BT878_DA_LMT (1<<12) +#define BT878_DA_SDR (0xf<<8) +#define BT878_DA_IOM (3<<6) +#define BT878_DA_APP (1<<5) +#define BT878_ACAP_EN (1<<4) +#define BT878_PKTP (3<<2) +#define BT878_RISC_EN (1<<1) +#define BT878_FIFO_EN 1 + +#define BT878_APACK_LEN 0x110 +#define BT878_AFP_LEN (0xff<<16) +#define BT878_ALP_LEN 0xfff + +#define BT878_ARISC_START 0x114 + +#define BT878_ARISC_PC 0x120 + +/* BT878 FUNCTION 0 REGISTERS */ +#define BT878_GPIO_DMA_CTL 0x10c + +/* Interrupt register */ +#define BT878_INT_STAT 0x100 +#define BT878_INT_MASK 0x104 +#define BT878_I2CRACK (1<<25) +#define BT878_I2CDONE (1<<8) + +#define BT878_MAX 4 + +#define BT878_RISC_SYNC_MASK (1 << 15) + + +#define BTTV_BOARD_UNKNOWN 0x00 +#define BTTV_BOARD_PINNACLESAT 0x5e +#define BTTV_BOARD_NEBULA_DIGITV 0x68 +#define BTTV_BOARD_PC_HDTV 0x70 +#define BTTV_BOARD_TWINHAN_DST 0x71 +#define BTTV_BOARD_AVDVBT_771 0x7b +#define BTTV_BOARD_AVDVBT_761 0x7c +#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 +#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 + +extern int bt878_num; + +struct bt878 { + struct mutex gpio_lock; + unsigned int nr; + unsigned int bttv_nr; + struct i2c_adapter *adapter; + struct pci_dev *dev; + unsigned int id; + unsigned int TS_Size; + unsigned char revision; + unsigned int irq; + unsigned long bt878_adr; + volatile void __iomem *bt878_mem; /* function 1 */ + + volatile u32 finished_block; + volatile u32 last_block; + u32 block_count; + u32 block_bytes; + u32 line_bytes; + u32 line_count; + + u32 buf_size; + u8 *buf_cpu; + dma_addr_t buf_dma; + + u32 risc_size; + __le32 *risc_cpu; + dma_addr_t risc_dma; + u32 risc_pos; + + struct tasklet_struct tasklet; + int shutdown; +}; + +extern struct bt878 bt878[BT878_MAX]; + +void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, + u32 irq_err_ignore); +void bt878_stop(struct bt878 *bt); + +#if defined(__powerpc__) /* big-endian */ +static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) +{ + st_le32(addr, val); + eieio(); +} + +#define bmtwrite(dat,adr) io_st_le32((adr),(dat)) +#define bmtread(adr) ld_le32((adr)) +#else +#define bmtwrite(dat,adr) writel((dat), (adr)) +#define bmtread(adr) readl(adr) +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,1873 @@ +/* + Frontend/Card driver for TwinHan DST Frontend + Copyright (C) 2003 Jamie Honan + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "dst_priv.h" +#include "dst_common.h" + +static unsigned int verbose = 1; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +static unsigned int dst_addons; +module_param(dst_addons, int, 0644); +MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); + +static unsigned int dst_algo; +module_param(dst_algo, int, 0644); +MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); + +#define HAS_LOCK 1 +#define ATTEMPT_TUNE 2 +#define HAS_POWER 4 + +#define DST_ERROR 0 +#define DST_NOTICE 1 +#define DST_INFO 2 +#define DST_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > DST_ERROR) && (x > y)) \ + printk(KERN_ERR "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + else if ((x > DST_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + else if ((x > DST_INFO) && (x > y)) \ + printk(KERN_INFO "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + else if ((x > DST_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ +} while(0) + +static int dst_command(struct dst_state *state, u8 *data, u8 len); + +static void dst_packsize(struct dst_state *state, int psize) +{ + union dst_gpio_packet bits; + + bits.psize = psize; + bt878_device_control(state->bt, DST_IG_TS, &bits); +} + +static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, + u32 outhigh, int delay) +{ + union dst_gpio_packet enb; + union dst_gpio_packet bits; + int err; + + enb.enb.mask = mask; + enb.enb.enable = enbb; + + dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh); + if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { + dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb); + return -EREMOTEIO; + } + udelay(1000); + /* because complete disabling means no output, no need to do output packet */ + if (enbb == 0) + return 0; + if (delay) + msleep(10); + bits.outp.mask = enbb; + bits.outp.highvals = outhigh; + if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { + dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh); + return -EREMOTEIO; + } + + return 0; +} + +static int dst_gpio_inb(struct dst_state *state, u8 *result) +{ + union dst_gpio_packet rd_packet; + int err; + + *result = 0; + if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err); + return -EREMOTEIO; + } + *result = (u8) rd_packet.rd.value; + + return 0; +} + +int rdc_reset_state(struct dst_state *state) +{ + dprintk(verbose, DST_INFO, 1, "Resetting state machine"); + if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + msleep(10); + if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + msleep(10); + return -1; + } + + return 0; +} +EXPORT_SYMBOL(rdc_reset_state); + +static int rdc_8820_reset(struct dst_state *state) +{ + dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); + if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + udelay(1000); + if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + + return 0; +} + +static int dst_pio_enable(struct dst_state *state) +{ + if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + udelay(1000); + + return 0; +} + +int dst_pio_disable(struct dst_state *state) +{ + if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + return -1; + } + if (state->type_flags & DST_TYPE_HAS_FW_1) + udelay(1000); + + return 0; +} +EXPORT_SYMBOL(dst_pio_disable); + +int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) +{ + u8 reply; + int i; + + for (i = 0; i < 200; i++) { + if (dst_gpio_inb(state, &reply) < 0) { + dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !"); + return -1; + } + if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { + dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i); + return 1; + } + msleep(10); + } + dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i); + + return 0; +} +EXPORT_SYMBOL(dst_wait_dst_ready); + +int dst_error_recovery(struct dst_state *state) +{ + dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors."); + dst_pio_disable(state); + msleep(10); + dst_pio_enable(state); + msleep(10); + + return 0; +} +EXPORT_SYMBOL(dst_error_recovery); + +int dst_error_bailout(struct dst_state *state) +{ + dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error."); + rdc_8820_reset(state); + dst_pio_disable(state); + msleep(10); + + return 0; +} +EXPORT_SYMBOL(dst_error_bailout); + +int dst_comm_init(struct dst_state *state) +{ + dprintk(verbose, DST_INFO, 1, "Initializing DST."); + if ((dst_pio_enable(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed"); + return -1; + } + if ((rdc_reset_state(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed."); + return -1; + } + if (state->type_flags & DST_TYPE_HAS_FW_1) + msleep(100); + else + msleep(5); + + return 0; +} +EXPORT_SYMBOL(dst_comm_init); + +int write_dst(struct dst_state *state, u8 *data, u8 len) +{ + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = data, + .len = len + }; + + int err; + u8 cnt, i; + + dprintk(verbose, DST_NOTICE, 0, "writing [ "); + for (i = 0; i < len; i++) + dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]); + dprintk(verbose, DST_NOTICE, 0, "]\n"); + + for (cnt = 0; cnt < 2; cnt++) { + if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { + dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]); + dst_error_recovery(state); + continue; + } else + break; + } + if (cnt >= 2) { + dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); + dst_error_bailout(state); + + return -1; + } + + return 0; +} +EXPORT_SYMBOL(write_dst); + +int read_dst(struct dst_state *state, u8 *ret, u8 len) +{ + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = ret, + .len = len + }; + + int err; + int cnt; + + for (cnt = 0; cnt < 2; cnt++) { + if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { + dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]); + dst_error_recovery(state); + continue; + } else + break; + } + if (cnt >= 2) { + dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); + dst_error_bailout(state); + + return -1; + } + dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]); + for (err = 1; err < len; err++) + dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]); + if (err > 1) + dprintk(verbose, DST_DEBUG, 0, "\n"); + + return 0; +} +EXPORT_SYMBOL(read_dst); + +static int dst_set_polarization(struct dst_state *state) +{ + switch (state->voltage) { + case SEC_VOLTAGE_13: /* Vertical */ + dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]"); + state->tx_tuna[8] &= ~0x40; + break; + case SEC_VOLTAGE_18: /* Horizontal */ + dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]"); + state->tx_tuna[8] |= 0x40; + break; + case SEC_VOLTAGE_OFF: + break; + } + + return 0; +} + +static int dst_set_freq(struct dst_state *state, u32 freq) +{ + state->frequency = freq; + dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq); + + if (state->dst_type == DST_TYPE_IS_SAT) { + freq = freq / 1000; + if (freq < 950 || freq > 2150) + return -EINVAL; + state->tx_tuna[2] = (freq >> 8); + state->tx_tuna[3] = (u8) freq; + state->tx_tuna[4] = 0x01; + state->tx_tuna[8] &= ~0x04; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { + if (freq < 1531) + state->tx_tuna[8] |= 0x04; + } + } else if (state->dst_type == DST_TYPE_IS_TERR) { + freq = freq / 1000; + if (freq < 137000 || freq > 858000) + return -EINVAL; + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + freq = freq / 1000; + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; + } else if (state->dst_type == DST_TYPE_IS_ATSC) { + freq = freq / 1000; + if (freq < 51000 || freq > 858000) + return -EINVAL; + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; + state->tx_tuna[5] = 0x00; /* ATSC */ + state->tx_tuna[6] = 0x00; + if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG) + state->tx_tuna[7] = 0x00; /* Digital */ + } else + return -EINVAL; + + return 0; +} + +static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) +{ + state->bandwidth = bandwidth; + + if (state->dst_type != DST_TYPE_IS_TERR) + return -EOPNOTSUPP; + + switch (bandwidth) { + case BANDWIDTH_6_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x06; + else { + state->tx_tuna[6] = 0x06; + state->tx_tuna[7] = 0x00; + } + break; + case BANDWIDTH_7_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x07; + else { + state->tx_tuna[6] = 0x07; + state->tx_tuna[7] = 0x00; + } + break; + case BANDWIDTH_8_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x08; + else { + state->tx_tuna[6] = 0x08; + state->tx_tuna[7] = 0x00; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) +{ + state->inversion = inversion; + switch (inversion) { + case INVERSION_OFF: /* Inversion = Normal */ + state->tx_tuna[8] &= ~0x80; + break; + case INVERSION_ON: + state->tx_tuna[8] |= 0x80; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) +{ + state->fec = fec; + return 0; +} + +static fe_code_rate_t dst_get_fec(struct dst_state *state) +{ + return state->fec; +} + +static int dst_set_symbolrate(struct dst_state *state, u32 srate) +{ + u32 symcalc; + u64 sval; + + state->symbol_rate = srate; + if (state->dst_type == DST_TYPE_IS_TERR) { + return -EOPNOTSUPP; + } + dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); + srate /= 1000; + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_SYMDIV) { + sval = srate; + sval <<= 20; + do_div(sval, 88000); + symcalc = (u32) sval; + dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); + state->tx_tuna[5] = (u8) (symcalc >> 12); + state->tx_tuna[6] = (u8) (symcalc >> 4); + state->tx_tuna[7] = (u8) (symcalc << 4); + } else { + state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; + state->tx_tuna[6] = (u8) (srate >> 8); + state->tx_tuna[7] = (u8) srate; + } + state->tx_tuna[8] &= ~0x20; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { + if (srate > 8000) + state->tx_tuna[8] |= 0x20; + } + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name); + if (!strncmp(state->fw_name, "DCTNEW", 6)) { + state->tx_tuna[5] = (u8) (srate >> 8); + state->tx_tuna[6] = (u8) srate; + state->tx_tuna[7] = 0x00; + } else if (!strncmp(state->fw_name, "DCT-CI", 6)) { + state->tx_tuna[5] = 0x00; + state->tx_tuna[6] = (u8) (srate >> 8); + state->tx_tuna[7] = (u8) srate; + } + } + return 0; +} + +static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) +{ + if (state->dst_type != DST_TYPE_IS_CABLE) + return -EOPNOTSUPP; + + state->modulation = modulation; + switch (modulation) { + case QAM_16: + state->tx_tuna[8] = 0x10; + break; + case QAM_32: + state->tx_tuna[8] = 0x20; + break; + case QAM_64: + state->tx_tuna[8] = 0x40; + break; + case QAM_128: + state->tx_tuna[8] = 0x80; + break; + case QAM_256: + if (!strncmp(state->fw_name, "DCTNEW", 6)) + state->tx_tuna[8] = 0xff; + else if (!strncmp(state->fw_name, "DCT-CI", 6)) + state->tx_tuna[8] = 0x00; + break; + case QPSK: + case QAM_AUTO: + case VSB_8: + case VSB_16: + default: + return -EINVAL; + + } + + return 0; +} + +static fe_modulation_t dst_get_modulation(struct dst_state *state) +{ + return state->modulation; +} + + +u8 dst_check_sum(u8 *buf, u32 len) +{ + u32 i; + u8 val = 0; + if (!len) + return 0; + for (i = 0; i < len; i++) { + val += buf[i]; + } + return ((~val) + 1); +} +EXPORT_SYMBOL(dst_check_sum); + +static void dst_type_flags_print(struct dst_state *state) +{ + u32 type_flags = state->type_flags; + + dprintk(verbose, DST_ERROR, 0, "DST type flags :"); + if (type_flags & DST_TYPE_HAS_TS188) + dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188); + if (type_flags & DST_TYPE_HAS_NEWTUNE_2) + dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2); + if (type_flags & DST_TYPE_HAS_TS204) + dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); + if (type_flags & DST_TYPE_HAS_VLF) + dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF); + if (type_flags & DST_TYPE_HAS_SYMDIV) + dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); + if (type_flags & DST_TYPE_HAS_FW_1) + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); + if (type_flags & DST_TYPE_HAS_FW_2) + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); + if (type_flags & DST_TYPE_HAS_FW_3) + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); + dprintk(verbose, DST_ERROR, 0, "\n"); +} + + +static int dst_type_print(struct dst_state *state, u8 type) +{ + char *otype; + switch (type) { + case DST_TYPE_IS_SAT: + otype = "satellite"; + break; + + case DST_TYPE_IS_TERR: + otype = "terrestrial"; + break; + + case DST_TYPE_IS_CABLE: + otype = "cable"; + break; + + case DST_TYPE_IS_ATSC: + otype = "atsc"; + break; + + default: + dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); + return -EINVAL; + } + dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); + + return 0; +} + +static struct tuner_types tuner_list[] = { + { + .tuner_type = TUNER_TYPE_L64724, + .tuner_name = "L 64724", + .board_name = "UNKNOWN", + .fw_name = "UNKNOWN" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1020", + .fw_name = "DST-MOT" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1020", + .fw_name = "DST-03T" + }, + + { + .tuner_type = TUNER_TYPE_MB86A15, + .tuner_name = "MB 86A15", + .board_name = "VP1022", + .fw_name = "DST-03T" + }, + + { + .tuner_type = TUNER_TYPE_MB86A15, + .tuner_name = "MB 86A15", + .board_name = "VP1025", + .fw_name = "DST-03T" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1030", + .fw_name = "DST-CI" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1030", + .fw_name = "DSTMCI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2021", + .fw_name = "DCTNEW" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2030", + .fw_name = "DCT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2031", + .fw_name = "DCT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2040", + .fw_name = "DCT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP3020", + .fw_name = "DTTFTA" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP3021", + .fw_name = "DTTFTA" + }, + + { + .tuner_type = TUNER_TYPE_TDA10046, + .tuner_name = "TDA10046", + .board_name = "VP3040", + .fw_name = "DTT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP3051", + .fw_name = "DTTNXT" + }, + + { + .tuner_type = TUNER_TYPE_NXT200x, + .tuner_name = "NXT200x", + .board_name = "VP3220", + .fw_name = "ATSCDI" + }, + + { + .tuner_type = TUNER_TYPE_NXT200x, + .tuner_name = "NXT200x", + .board_name = "VP3250", + .fw_name = "ATSCAD" + }, +}; + +/* + Known cards list + Satellite + ------------------- + 200103A + VP-1020 DST-MOT LG(old), TS=188 + + VP-1020 DST-03T LG(new), TS=204 + VP-1022 DST-03T LG(new), TS=204 + VP-1025 DST-03T LG(new), TS=204 + + VP-1030 DSTMCI, LG(new), TS=188 + VP-1032 DSTMCI, LG(new), TS=188 + + Cable + ------------------- + VP-2030 DCT-CI, Samsung, TS=204 + VP-2021 DCT-CI, Unknown, TS=204 + VP-2031 DCT-CI, Philips, TS=188 + VP-2040 DCT-CI, Philips, TS=188, with CA daughter board + VP-2040 DCT-CI, Philips, TS=204, without CA daughter board + + Terrestrial + ------------------- + VP-3050 DTTNXT TS=188 + VP-3040 DTT-CI, Philips, TS=188 + VP-3040 DTT-CI, Philips, TS=204 + + ATSC + ------------------- + VP-3220 ATSCDI, TS=188 + VP-3250 ATSCAD, TS=188 + +*/ + +static struct dst_types dst_tlist[] = { + { + .device_id = "200103A", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, + .dst_feature = 0, + .tuner_type = 0 + }, /* obsolete */ + + { + .device_id = "DST-020", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 + }, /* obsolete */ + + { + .device_id = "DST-030", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 + }, /* obsolete */ + + { + .device_id = "DST-03T", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, + .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 + | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO, + .tuner_type = TUNER_TYPE_MULTI + }, + + { + .device_id = "DST-MOT", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 + }, /* obsolete */ + + { + .device_id = "DST-CI", + .offset = 1, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1, + .dst_feature = DST_TYPE_HAS_CA, + .tuner_type = 0 + }, /* An OEM board */ + + { + .device_id = "DSTMCI", + .offset = 1, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF, + .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 + | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC, + .tuner_type = TUNER_TYPE_MULTI + }, + + { + .device_id = "DSTFCI", + .offset = 1, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 + }, /* unknown to vendor */ + + { + .device_id = "DCT-CI", + .offset = 1, + .dst_type = DST_TYPE_IS_CABLE, + .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF, + .dst_feature = DST_TYPE_HAS_CA, + .tuner_type = 0 + }, + + { + .device_id = "DCTNEW", + .offset = 1, + .dst_type = DST_TYPE_IS_CABLE, + .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE, + .dst_feature = 0, + .tuner_type = 0 + }, + + { + .device_id = "DTT-CI", + .offset = 1, + .dst_type = DST_TYPE_IS_TERR, + .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF, + .dst_feature = DST_TYPE_HAS_CA, + .tuner_type = 0 + }, + + { + .device_id = "DTTDIG", + .offset = 1, + .dst_type = DST_TYPE_IS_TERR, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = 0, + .tuner_type = 0 + }, + + { + .device_id = "DTTNXT", + .offset = 1, + .dst_type = DST_TYPE_IS_TERR, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = DST_TYPE_HAS_ANALOG, + .tuner_type = 0 + }, + + { + .device_id = "ATSCDI", + .offset = 1, + .dst_type = DST_TYPE_IS_ATSC, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = 0, + .tuner_type = 0 + }, + + { + .device_id = "ATSCAD", + .offset = 1, + .dst_type = DST_TYPE_IS_ATSC, + .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, + .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG, + .tuner_type = 0 + }, + + { } + +}; + +static int dst_get_mac(struct dst_state *state) +{ + u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_mac[7] = dst_check_sum(get_mac, 7); + if (dst_command(state, get_mac, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->mac_address, '\0', 8); + memcpy(&state->mac_address, &state->rxbuffer, 6); + dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address); + + return 0; +} + +static int dst_fw_ver(struct dst_state *state) +{ + u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_ver[7] = dst_check_sum(get_ver, 7); + if (dst_command(state, get_ver, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memcpy(&state->fw_version, &state->rxbuffer, 8); + dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", + state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, + state->fw_version[1], + state->fw_version[5], state->fw_version[6], + state->fw_version[4], state->fw_version[3], state->fw_version[2]); + + return 0; +} + +static int dst_card_type(struct dst_state *state) +{ + int j; + struct tuner_types *p_tuner_list = NULL; + + u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_type[7] = dst_check_sum(get_type, 7); + if (dst_command(state, get_type, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->card_info, '\0', 8); + memcpy(&state->card_info, &state->rxbuffer, 7); + dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); + + for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { + if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) { + state->tuner_type = p_tuner_list->tuner_type; + dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]", + p_tuner_list->tuner_name, p_tuner_list->tuner_type); + } + } + + return 0; +} + +static int dst_get_vendor(struct dst_state *state) +{ + u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_vendor[7] = dst_check_sum(get_vendor, 7); + if (dst_command(state, get_vendor, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->vendor, '\0', 8); + memcpy(&state->vendor, &state->rxbuffer, 7); + dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); + + return 0; +} + +static void debug_dst_buffer(struct dst_state *state) +{ + int i; + + if (verbose > 2) { + printk("%s: [", __func__); + for (i = 0; i < 8; i++) + printk(" %02x", state->rxbuffer[i]); + printk("]\n"); + } +} + +static int dst_check_stv0299(struct dst_state *state) +{ + u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + check_stv0299[7] = dst_check_sum(check_stv0299, 7); + if (dst_command(state, check_stv0299, 8) < 0) { + dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed"); + return -1; + } + debug_dst_buffer(state); + + if (memcmp(&check_stv0299, &state->rxbuffer, 8)) { + dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM"); + state->tuner_type = TUNER_TYPE_STV0299; + return 0; + } + + return -1; +} + +static int dst_check_mb86a15(struct dst_state *state) +{ + u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + check_mb86a15[7] = dst_check_sum(check_mb86a15, 7); + if (dst_command(state, check_mb86a15, 8) < 0) { + dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed"); + return -1; + } + debug_dst_buffer(state); + + if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) { + dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM"); + state->tuner_type = TUNER_TYPE_MB86A15; + return 0; + } + + return -1; +} + +static int dst_get_tuner_info(struct dst_state *state) +{ + u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); + get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); + dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE"); + if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { + if (dst_command(state, get_tuner_1, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported"); + goto force; + } + } else { + if (dst_command(state, get_tuner_2, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported"); + goto force; + } + } + memcpy(&state->board_info, &state->rxbuffer, 8); + if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { + dprintk(verbose, DST_ERROR, 1, "DST type has TS=188"); + } + if (state->board_info[0] == 0xbc) { + if (state->dst_type != DST_TYPE_IS_ATSC) + state->type_flags |= DST_TYPE_HAS_TS188; + else + state->type_flags |= DST_TYPE_HAS_NEWTUNE_2; + + if (state->board_info[1] == 0x01) { + state->dst_hw_cap |= DST_TYPE_HAS_DBOARD; + dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard"); + } + } + + return 0; +force: + if (!strncmp(state->fw_name, "DCT-CI", 6)) { + state->type_flags |= DST_TYPE_HAS_TS204; + dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name); + } + + return -1; +} + +static int dst_get_device_id(struct dst_state *state) +{ + u8 reply; + + int i, j; + struct dst_types *p_dst_type = NULL; + struct tuner_types *p_tuner_list = NULL; + + u8 use_dst_type = 0; + u32 use_type_flags = 0; + + static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; + + state->tuner_type = 0; + device_type[7] = dst_check_sum(device_type, 7); + + if (write_dst(state, device_type, FIXED_COMM)) + return -1; /* Write failed */ + if ((dst_pio_disable(state)) < 0) + return -1; + if (read_dst(state, &reply, GET_ACK)) + return -1; /* Read failure */ + if (reply != ACK) { + dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); + return -1; /* Unack'd write */ + } + if (!dst_wait_dst_ready(state, DEVICE_INIT)) + return -1; /* DST not ready yet */ + if (read_dst(state, state->rxbuffer, FIXED_COMM)) + return -1; + + dst_pio_disable(state); + if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { + dprintk(verbose, DST_INFO, 1, "Checksum failure!"); + return -1; /* Checksum failure */ + } + state->rxbuffer[7] = '\0'; + + for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { + if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { + use_type_flags = p_dst_type->type_flags; + use_dst_type = p_dst_type->dst_type; + + /* Card capabilities */ + state->dst_hw_cap = p_dst_type->dst_feature; + dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id); + strncpy(&state->fw_name[0], p_dst_type->device_id, 6); + /* Multiple tuners */ + if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { + switch (use_dst_type) { + case DST_TYPE_IS_SAT: + /* STV0299 check */ + if (dst_check_stv0299(state) < 0) { + dprintk(verbose, DST_ERROR, 1, "Unsupported"); + state->tuner_type = TUNER_TYPE_MB86A15; + } + break; + default: + break; + } + if (dst_check_mb86a15(state) < 0) + dprintk(verbose, DST_ERROR, 1, "Unsupported"); + /* Single tuner */ + } else { + state->tuner_type = p_dst_type->tuner_type; + } + for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { + if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) && + p_tuner_list->tuner_type == state->tuner_type) { + dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]", + p_dst_type->device_id, p_tuner_list->tuner_name); + } + } + break; + } + } + + if (i >= ARRAY_SIZE(dst_tlist)) { + dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); + dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); + use_dst_type = DST_TYPE_IS_SAT; + use_type_flags = DST_TYPE_HAS_SYMDIV; + } + dst_type_print(state, use_dst_type); + state->type_flags = use_type_flags; + state->dst_type = use_dst_type; + dst_type_flags_print(state); + + return 0; +} + +static int dst_probe(struct dst_state *state) +{ + mutex_init(&state->dst_mutex); + if (dst_addons & DST_TYPE_HAS_CA) { + if ((rdc_8820_reset(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); + return -1; + } + msleep(4000); + } else { + msleep(100); + } + if ((dst_comm_init(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); + return -1; + } + msleep(100); + if (dst_get_device_id(state) < 0) { + dprintk(verbose, DST_ERROR, 1, "unknown device."); + return -1; + } + if (dst_get_mac(state) < 0) { + dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); + } + if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { + if (dst_get_tuner_info(state) < 0) + dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command"); + } + if (state->type_flags & DST_TYPE_HAS_TS204) { + dst_packsize(state, 204); + } + if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { + if (dst_fw_ver(state) < 0) { + dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); + return 0; + } + if (dst_card_type(state) < 0) { + dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); + return 0; + } + if (dst_get_vendor(state) < 0) { + dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); + return 0; + } + } + + return 0; +} + +static int dst_command(struct dst_state *state, u8 *data, u8 len) +{ + u8 reply; + + mutex_lock(&state->dst_mutex); + if ((dst_comm_init(state)) < 0) { + dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); + goto error; + } + if (write_dst(state, data, len)) { + dprintk(verbose, DST_INFO, 1, "Trying to recover.. "); + if ((dst_error_recovery(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); + goto error; + } + goto error; + } + if ((dst_pio_disable(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); + goto error; + } + if (state->type_flags & DST_TYPE_HAS_FW_1) + mdelay(3); + if (read_dst(state, &reply, GET_ACK)) { + dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); + if ((dst_error_recovery(state)) < 0) { + dprintk(verbose, DST_INFO, 1, "Recovery Failed."); + goto error; + } + goto error; + } + if (reply != ACK) { + dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); + goto error; + } + if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) + goto error; + if (state->type_flags & DST_TYPE_HAS_FW_1) + mdelay(3); + else + udelay(2000); + if (!dst_wait_dst_ready(state, NO_DELAY)) + goto error; + if (read_dst(state, state->rxbuffer, FIXED_COMM)) { + dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); + if ((dst_error_recovery(state)) < 0) { + dprintk(verbose, DST_INFO, 1, "Recovery failed."); + goto error; + } + goto error; + } + if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { + dprintk(verbose, DST_INFO, 1, "checksum failure"); + goto error; + } + mutex_unlock(&state->dst_mutex); + return 0; + +error: + mutex_unlock(&state->dst_mutex); + return -EIO; + +} + +static int dst_get_signal(struct dst_state *state) +{ + int retval; + u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; + //dprintk("%s: Getting Signal strength and other parameters\n", __func__); + if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { + state->decode_lock = state->decode_strength = state->decode_snr = 0; + return 0; + } + if (0 == (state->diseq_flags & HAS_LOCK)) { + state->decode_lock = state->decode_strength = state->decode_snr = 0; + return 0; + } + if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { + retval = dst_command(state, get_signal, 8); + if (retval < 0) + return retval; + if (state->dst_type == DST_TYPE_IS_SAT) { + state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; + state->decode_strength = state->rxbuffer[5] << 8; + state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; + } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { + state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; + state->decode_strength = state->rxbuffer[4] << 8; + state->decode_snr = state->rxbuffer[3] << 8; + } else if (state->dst_type == DST_TYPE_IS_ATSC) { + state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0; + state->decode_strength = state->rxbuffer[4] << 8; + state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; + } + state->cur_jiff = jiffies; + } + return 0; +} + +static int dst_tone_power_cmd(struct dst_state *state) +{ + u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; + + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + paket[4] = state->tx_tuna[4]; + paket[2] = state->tx_tuna[2]; + paket[3] = state->tx_tuna[3]; + paket[7] = dst_check_sum (paket, 7); + return dst_command(state, paket, 8); +} + +static int dst_get_tuna(struct dst_state *state) +{ + int retval; + + if ((state->diseq_flags & ATTEMPT_TUNE) == 0) + return 0; + state->diseq_flags &= ~(HAS_LOCK); + if (!dst_wait_dst_ready(state, NO_DELAY)) + return -EIO; + if ((state->type_flags & DST_TYPE_HAS_VLF) && + !(state->dst_type == DST_TYPE_IS_ATSC)) + + retval = read_dst(state, state->rx_tuna, 10); + else + retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); + if (retval < 0) { + dprintk(verbose, DST_DEBUG, 1, "read not successful"); + return retval; + } + if ((state->type_flags & DST_TYPE_HAS_VLF) && + !(state->dst_type == DST_TYPE_IS_ATSC)) { + + if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { + dprintk(verbose, DST_INFO, 1, "checksum failure ? "); + return -EIO; + } + } else { + if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { + dprintk(verbose, DST_INFO, 1, "checksum failure? "); + return -EIO; + } + } + if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) + return 0; + if (state->dst_type == DST_TYPE_IS_SAT) { + state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; + } else { + state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4]; + } + state->decode_freq = state->decode_freq * 1000; + state->decode_lock = 1; + state->diseq_flags |= HAS_LOCK; + + return 1; +} + +static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + +static int dst_write_tuna(struct dvb_frontend *fe) +{ + struct dst_state *state = fe->demodulator_priv; + int retval; + u8 reply; + + dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); + state->decode_freq = 0; + state->decode_lock = state->decode_strength = state->decode_snr = 0; + if (state->dst_type == DST_TYPE_IS_SAT) { + if (!(state->diseq_flags & HAS_POWER)) + dst_set_voltage(fe, SEC_VOLTAGE_13); + } + state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); + mutex_lock(&state->dst_mutex); + if ((dst_comm_init(state)) < 0) { + dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); + goto error; + } +// if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + if ((state->type_flags & DST_TYPE_HAS_VLF) && + (!(state->dst_type == DST_TYPE_IS_ATSC))) { + + state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); + retval = write_dst(state, &state->tx_tuna[0], 10); + } else { + state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); + retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); + } + if (retval < 0) { + dst_pio_disable(state); + dprintk(verbose, DST_DEBUG, 1, "write not successful"); + goto werr; + } + if ((dst_pio_disable(state)) < 0) { + dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); + goto error; + } + if ((read_dst(state, &reply, GET_ACK) < 0)) { + dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); + goto error; + } + if (reply != ACK) { + dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); + goto error; + } + state->diseq_flags |= ATTEMPT_TUNE; + retval = dst_get_tuna(state); +werr: + mutex_unlock(&state->dst_mutex); + return retval; + +error: + mutex_unlock(&state->dst_mutex); + return -EIO; +} + +/* + * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 + * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 + * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 + * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 + * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 + * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 + * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 + * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec + * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 + * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 + * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 + */ + +static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct dst_state *state = fe->demodulator_priv; + u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; + + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + if (cmd->msg_len > 0 && cmd->msg_len < 5) + memcpy(&paket[3], cmd->msg, cmd->msg_len); + else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5) + memcpy(&paket[2], cmd->msg, cmd->msg_len); + else + return -EINVAL; + paket[7] = dst_check_sum(&paket[0], 7); + return dst_command(state, paket, 8); +} + +static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + int need_cmd, retval = 0; + struct dst_state *state = fe->demodulator_priv; + + state->voltage = voltage; + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + + need_cmd = 0; + + switch (voltage) { + case SEC_VOLTAGE_13: + case SEC_VOLTAGE_18: + if ((state->diseq_flags & HAS_POWER) == 0) + need_cmd = 1; + state->diseq_flags |= HAS_POWER; + state->tx_tuna[4] = 0x01; + break; + case SEC_VOLTAGE_OFF: + need_cmd = 1; + state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); + state->tx_tuna[4] = 0x00; + break; + default: + return -EINVAL; + } + + if (need_cmd) + retval = dst_tone_power_cmd(state); + + return retval; +} + +static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct dst_state *state = fe->demodulator_priv; + + state->tone = tone; + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + + switch (tone) { + case SEC_TONE_OFF: + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + state->tx_tuna[2] = 0x00; + else + state->tx_tuna[2] = 0xff; + break; + + case SEC_TONE_ON: + state->tx_tuna[2] = 0x02; + break; + default: + return -EINVAL; + } + return dst_tone_power_cmd(state); +} + +static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) +{ + struct dst_state *state = fe->demodulator_priv; + + if (state->dst_type != DST_TYPE_IS_SAT) + return -EOPNOTSUPP; + state->minicmd = minicmd; + switch (minicmd) { + case SEC_MINI_A: + state->tx_tuna[3] = 0x02; + break; + case SEC_MINI_B: + state->tx_tuna[3] = 0xff; + break; + } + return dst_tone_power_cmd(state); +} + + +static int dst_init(struct dvb_frontend *fe) +{ + struct dst_state *state = fe->demodulator_priv; + + static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; + static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; + static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + + state->inversion = INVERSION_OFF; + state->voltage = SEC_VOLTAGE_13; + state->tone = SEC_TONE_OFF; + state->diseq_flags = 0; + state->k22 = 0x02; + state->bandwidth = BANDWIDTH_7_MHZ; + state->cur_jiff = jiffies; + if (state->dst_type == DST_TYPE_IS_SAT) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_TERR) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_CABLE) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_ATSC) + memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner)); + + return 0; +} + +static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct dst_state *state = fe->demodulator_priv; + + *status = 0; + if (state->diseq_flags & HAS_LOCK) { +// dst_get_signal(state); // don't require(?) to ask MCU + if (state->decode_lock) + *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; + } + + return 0; +} + +static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct dst_state *state = fe->demodulator_priv; + + int retval = dst_get_signal(state); + *strength = state->decode_strength; + + return retval; +} + +static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct dst_state *state = fe->demodulator_priv; + + int retval = dst_get_signal(state); + *snr = state->decode_snr; + + return retval; +} + +static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + int retval = -EINVAL; + struct dst_state *state = fe->demodulator_priv; + + if (p != NULL) { + retval = dst_set_freq(state, p->frequency); + if(retval != 0) + return retval; + dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); + + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + dst_set_inversion(state, p->inversion); + dst_set_fec(state, p->u.qpsk.fec_inner); + dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_polarization(state); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); + + } else if (state->dst_type == DST_TYPE_IS_TERR) + dst_set_bandwidth(state, p->u.ofdm.bandwidth); + else if (state->dst_type == DST_TYPE_IS_CABLE) { + dst_set_fec(state, p->u.qam.fec_inner); + dst_set_symbolrate(state, p->u.qam.symbol_rate); + dst_set_modulation(state, p->u.qam.modulation); + } + retval = dst_write_tuna(fe); + } + + return retval; +} + +static int dst_tune_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters* p, + unsigned int mode_flags, + unsigned int *delay, + fe_status_t *status) +{ + struct dst_state *state = fe->demodulator_priv; + + if (p != NULL) { + dst_set_freq(state, p->frequency); + dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); + + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + dst_set_inversion(state, p->inversion); + dst_set_fec(state, p->u.qpsk.fec_inner); + dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_polarization(state); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); + + } else if (state->dst_type == DST_TYPE_IS_TERR) + dst_set_bandwidth(state, p->u.ofdm.bandwidth); + else if (state->dst_type == DST_TYPE_IS_CABLE) { + dst_set_fec(state, p->u.qam.fec_inner); + dst_set_symbolrate(state, p->u.qam.symbol_rate); + dst_set_modulation(state, p->u.qam.modulation); + } + dst_write_tuna(fe); + } + + if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) + dst_read_status(fe, status); + + *delay = HZ/10; + return 0; +} + +static int dst_get_tuning_algo(struct dvb_frontend *fe) +{ + return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; +} + +static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct dst_state *state = fe->demodulator_priv; + + p->frequency = state->decode_freq; + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + p->inversion = state->inversion; + p->u.qpsk.symbol_rate = state->symbol_rate; + p->u.qpsk.fec_inner = dst_get_fec(state); + } else if (state->dst_type == DST_TYPE_IS_TERR) { + p->u.ofdm.bandwidth = state->bandwidth; + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + p->u.qam.symbol_rate = state->symbol_rate; + p->u.qam.fec_inner = dst_get_fec(state); + p->u.qam.modulation = dst_get_modulation(state); + } + + return 0; +} + +static void dst_release(struct dvb_frontend *fe) +{ + struct dst_state *state = fe->demodulator_priv; + if (state->dst_ca) { + dvb_unregister_device(state->dst_ca); +#ifdef CONFIG_MEDIA_ATTACH + symbol_put(dst_ca_attach); +#endif + } + kfree(state); +} + +static struct dvb_frontend_ops dst_dvbt_ops; +static struct dvb_frontend_ops dst_dvbs_ops; +static struct dvb_frontend_ops dst_dvbc_ops; +static struct dvb_frontend_ops dst_atsc_ops; + +struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) +{ + /* check if the ASIC is there */ + if (dst_probe(state) < 0) { + kfree(state); + return NULL; + } + /* determine settings based on type */ + /* create dvb_frontend */ + switch (state->dst_type) { + case DST_TYPE_IS_TERR: + memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_CABLE: + memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_SAT: + memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_ATSC: + memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops)); + break; + default: + dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); + kfree(state); + return NULL; + } + state->frontend.demodulator_priv = state; + + return state; /* Manu (DST is a card not a frontend) */ +} + +EXPORT_SYMBOL(dst_attach); + +static struct dvb_frontend_ops dst_dvbt_ops = { + + .info = { + .name = "DST DVB-T", + .type = FE_OFDM, + .frequency_min = 137000000, + .frequency_max = 858000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = dst_release, + .init = dst_init, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +static struct dvb_frontend_ops dst_dvbs_ops = { + + .info = { + .name = "DST DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* . symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK + }, + + .release = dst_release, + .init = dst_init, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, + .diseqc_send_burst = dst_send_burst, + .diseqc_send_master_cmd = dst_set_diseqc, + .set_voltage = dst_set_voltage, + .set_tone = dst_set_tone, +}; + +static struct dvb_frontend_ops dst_dvbc_ops = { + + .info = { + .name = "DST DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 51000000, + .frequency_max = 858000000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 + }, + + .release = dst_release, + .init = dst_init, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +static struct dvb_frontend_ops dst_atsc_ops = { + .info = { + .name = "DST ATSC", + .type = FE_ATSC, + .frequency_stepsize = 62500, + .frequency_min = 510000000, + .frequency_max = 858000000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .release = dst_release, + .init = dst_init, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver"); +MODULE_AUTHOR("Jamie Honan, Manu Abraham"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_ca.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_ca.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_ca.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_ca.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,727 @@ +/* + CA-driver for TwinHan DST Frontend/Card + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "dvbdev.h" +#include "dvb_frontend.h" +#include "dst_ca.h" +#include "dst_common.h" + +#define DST_CA_ERROR 0 +#define DST_CA_NOTICE 1 +#define DST_CA_INFO 2 +#define DST_CA_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > DST_CA_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((x > DST_CA_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((x > DST_CA_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((x > DST_CA_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ## arg); \ + } \ +} while(0) + + +static DEFINE_MUTEX(dst_ca_mutex); +static unsigned int verbose = 5; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +/* Need some more work */ +static int ca_set_slot_descr(void) +{ + /* We could make this more graceful ? */ + return -EOPNOTSUPP; +} + +/* Need some more work */ +static int ca_set_pid(void) +{ + /* We could make this more graceful ? */ + return -EOPNOTSUPP; +} + +static void put_command_and_length(u8 *data, int command, int length) +{ + data[0] = (command >> 16) & 0xff; + data[1] = (command >> 8) & 0xff; + data[2] = command & 0xff; + data[3] = length; +} + +static void put_checksum(u8 *check_string, int length) +{ + dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum."); + dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length); + check_string[length] = dst_check_sum (check_string, length); + dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]); +} + +static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read) +{ + u8 reply; + + mutex_lock(&state->dst_mutex); + dst_comm_init(state); + msleep(65); + + if (write_dst(state, data, len)) { + dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover"); + dst_error_recovery(state); + goto error; + } + if ((dst_pio_disable(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed."); + goto error; + } + if (read_dst(state, &reply, GET_ACK) < 0) { + dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); + dst_error_recovery(state); + goto error; + } + if (read) { + if (! dst_wait_dst_ready(state, LONG_DELAY)) { + dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready"); + goto error; + } + if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */ + dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); + dst_error_recovery(state); + goto error; + } + } + mutex_unlock(&state->dst_mutex); + return 0; + +error: + mutex_unlock(&state->dst_mutex); + return -EIO; +} + + +static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read) +{ + u8 dst_ca_comm_err = 0; + + while (dst_ca_comm_err < RETRIES) { + dprintk(verbose, DST_CA_NOTICE, 1, " Put Command"); + if (dst_ci_command(state, data, ca_string, len, read)) { // If error + dst_error_recovery(state); + dst_ca_comm_err++; // work required here. + } else { + break; + } + } + + if(dst_ca_comm_err == RETRIES) + return -1; + + return 0; +} + + + +static int ca_get_app_info(struct dst_state *state) +{ + int length, str_length; + static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff}; + + put_checksum(&command[0], command[0]); + if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================"); + dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]", + state->messages[7], (state->messages[8] << 8) | state->messages[9], + (state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12])); + dprintk(verbose, DST_CA_INFO, 1, " =================================================================================================="); + + // Transform dst message to correct application_info message + length = state->messages[5]; + str_length = length - 6; + if (str_length < 0) { + str_length = 0; + dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering."); + } + + // First, the command and length fields + put_command_and_length(&state->messages[0], CA_APP_INFO, length); + + // Copy application_type, application_manufacturer and manufacturer_code + memcpy(&state->messages[4], &state->messages[7], 5); + + // Set string length and copy string + state->messages[9] = str_length; + memcpy(&state->messages[10], &state->messages[12], str_length); + + return 0; +} + +static int ca_get_ca_info(struct dst_state *state) +{ + int srcPtr, dstPtr, i, num_ids; + static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff}; + const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7; + + put_checksum(&slot_command[0], slot_command[0]); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + + // Print raw data + dprintk(verbose, DST_CA_INFO, 0, " DST data = ["); + for (i = 0; i < state->messages[0] + 1; i++) { + dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]); + } + dprintk(verbose, DST_CA_INFO, 0, "]\n"); + + // Set the command and length of the output + num_ids = state->messages[in_num_ids_pos]; + if (num_ids >= 100) { + num_ids = 100; + dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering."); + } + put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2); + + dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = ["); + srcPtr = in_system_id_pos; + dstPtr = out_system_id_pos; + for(i = 0; i < num_ids; i++) { + dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]); + // Append to output + state->messages[dstPtr + 0] = state->messages[srcPtr + 0]; + state->messages[dstPtr + 1] = state->messages[srcPtr + 1]; + srcPtr += 2; + dstPtr += 2; + } + dprintk(verbose, DST_CA_INFO, 0, "]\n"); + + return 0; +} + +static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg) +{ + int i; + u8 slot_cap[256]; + static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff}; + + put_checksum(&slot_command[0], slot_command[0]); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !"); + + /* Will implement the rest soon */ + + dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]); + dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); + for (i = 0; i < slot_cap[0] + 1; i++) + dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]); + dprintk(verbose, DST_CA_INFO, 0, "\n"); + + p_ca_caps->slot_num = 1; + p_ca_caps->slot_type = 1; + p_ca_caps->descr_num = slot_cap[7]; + p_ca_caps->descr_type = 1; + + if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps))) + return -EFAULT; + + return 0; +} + +/* Need some more work */ +static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) +{ + return -EOPNOTSUPP; +} + + +static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg) +{ + int i; + static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; + + u8 *slot_info = state->messages; + + put_checksum(&slot_command[0], 7); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + + /* Will implement the rest soon */ + + dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]); + dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); + for (i = 0; i < 8; i++) + dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]); + dprintk(verbose, DST_CA_INFO, 0, "\n"); + + if (slot_info[4] & 0x80) { + p_ca_slot_info->flags = CA_CI_MODULE_PRESENT; + p_ca_slot_info->num = 1; + p_ca_slot_info->type = CA_CI; + } else if (slot_info[4] & 0x40) { + p_ca_slot_info->flags = CA_CI_MODULE_READY; + p_ca_slot_info->num = 1; + p_ca_slot_info->type = CA_CI; + } else + p_ca_slot_info->flags = 0; + + if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info))) + return -EFAULT; + + return 0; +} + + +static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) +{ + u8 i = 0; + u32 command = 0; + + if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) + return -EFAULT; + + if (p_ca_message->msg) { + dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%02x %02x %02x]", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]); + + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); + + switch (command) { + case CA_APP_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; + case CA_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; + } + } + + return 0; +} + +static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length) +{ + if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { + hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ + hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ + } else { + if (length > 247) { + dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !"); + return -1; + } + hw_buffer->msg[0] = (length & 0xff) + 7; + hw_buffer->msg[1] = 0x40; + hw_buffer->msg[2] = 0x03; + hw_buffer->msg[3] = 0x00; + hw_buffer->msg[4] = 0x03; + hw_buffer->msg[5] = length & 0xff; + hw_buffer->msg[6] = 0x00; + + /* + * Need to compute length for EN50221 section 8.3.2, for the time being + * assuming 8.3.2 is not applicable + */ + memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length); + } + + return 0; +} + +static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) +{ + if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed."); + dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST."); + rdc_reset_state(state); + return -1; + } + dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success."); + + return 0; +} + +static u32 asn_1_decode(u8 *asn_1_array) +{ + u8 length_field = 0, word_count = 0, count = 0; + u32 length = 0; + + length_field = asn_1_array[0]; + dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field); + if (length_field < 0x80) { + length = length_field & 0x7f; + dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length); + } else { + word_count = length_field & 0x7f; + for (count = 0; count < word_count; count++) { + length = length << 8; + length += asn_1_array[count + 1]; + dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length); + } + } + return length; +} + +static int debug_string(u8 *msg, u32 length, u32 offset) +{ + u32 i; + + dprintk(verbose, DST_CA_DEBUG, 0, " String=[ "); + for (i = offset; i < length; i++) + dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]); + dprintk(verbose, DST_CA_DEBUG, 0, "]\n"); + + return 0; +} + + +static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) +{ + u32 length = 0; + u8 tag_length = 8; + + length = asn_1_decode(&p_ca_message->msg[3]); + dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length); + debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */ + + memset(hw_buffer->msg, '\0', length); + handle_dst_tag(state, p_ca_message, hw_buffer, length); + put_checksum(hw_buffer->msg, hw_buffer->msg[0]); + + debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */ + write_to_8820(state, hw_buffer, (length + tag_length), reply); + + return 0; +} + + +/* Board supports CA PMT reply ? */ +static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) +{ + int ca_pmt_reply_test = 0; + + /* Do test board */ + /* Not there yet but soon */ + + /* CA PMT Reply capable */ + if (ca_pmt_reply_test) { + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); + return -1; + } + + /* Process CA PMT Reply */ + /* will implement soon */ + dprintk(verbose, DST_CA_ERROR, 1, " Not there yet"); + } + /* CA PMT Reply not capable */ + if (!ca_pmt_reply_test) { + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); + return -1; + } + dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !"); + /* put a dummy message */ + + } + return 0; +} + +static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) +{ + int i = 0; + unsigned int ca_message_header_len; + + u32 command = 0; + struct ca_msg *hw_buffer; + int result = 0; + + if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); + return -ENOMEM; + } + dprintk(verbose, DST_CA_DEBUG, 1, " "); + + if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) { + result = -EFAULT; + goto free_mem_and_exit; + } + + + if (p_ca_message->msg) { + ca_message_header_len = p_ca_message->length; /* Restore it back when you are done */ + /* EN50221 tag */ + command = 0; + + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); + + switch (command) { + case CA_PMT: + dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); + break; + case CA_PMT_REPLY: + dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); + /* Have to handle the 2 basic types of cards here */ + if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); + break; + case CA_APP_INFO_ENQUIRY: // only for debugging + dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); + + if ((ca_get_app_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); + break; + case CA_INFO_ENQUIRY: + dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); + + if ((ca_get_ca_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); + break; + } + } +free_mem_and_exit: + kfree (hw_buffer); + + return result; +} + +static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg) +{ + struct dvb_device *dvbdev; + struct dst_state *state; + struct ca_slot_info *p_ca_slot_info; + struct ca_caps *p_ca_caps; + struct ca_msg *p_ca_message; + void __user *arg = (void __user *)ioctl_arg; + int result = 0; + + mutex_lock(&dst_ca_mutex); + dvbdev = file->private_data; + state = (struct dst_state *)dvbdev->priv; + p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL); + p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL); + p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL); + if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) { + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); + result = -ENOMEM; + goto free_mem_and_exit; + } + + /* We have now only the standard ioctl's, the driver is upposed to handle internals. */ + switch (cmd) { + case CA_SEND_MSG: + dprintk(verbose, DST_CA_INFO, 1, " Sending message"); + if ((ca_send_message(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); + result = -1; + goto free_mem_and_exit; + } + break; + case CA_GET_MSG: + dprintk(verbose, DST_CA_INFO, 1, " Getting message"); + if ((ca_get_message(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); + break; + case CA_RESET: + dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST"); + dst_error_bailout(state); + msleep(4000); + break; + case CA_GET_SLOT_INFO: + dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); + if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !"); + break; + case CA_GET_CAP: + dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); + if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); + break; + case CA_GET_DESCR_INFO: + dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); + if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); + break; + case CA_SET_DESCR: + dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); + if ((ca_set_slot_descr()) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); + break; + case CA_SET_PID: + dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); + if ((ca_set_pid()) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); + default: + result = -EOPNOTSUPP; + }; + free_mem_and_exit: + kfree (p_ca_message); + kfree (p_ca_slot_info); + kfree (p_ca_caps); + + mutex_unlock(&dst_ca_mutex); + return result; +} + +static int dst_ca_open(struct inode *inode, struct file *file) +{ + dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); + try_module_get(THIS_MODULE); + + return 0; +} + +static int dst_ca_release(struct inode *inode, struct file *file) +{ + dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); + module_put(THIS_MODULE); + + return 0; +} + +static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) +{ + ssize_t bytes_read = 0; + + dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); + + return bytes_read; +} + +static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) +{ + dprintk(verbose, DST_CA_DEBUG, 1, " Device write."); + + return 0; +} + +static const struct file_operations dst_ca_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dst_ca_ioctl, + .open = dst_ca_open, + .release = dst_ca_release, + .read = dst_ca_read, + .write = dst_ca_write, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_ca = { + .priv = NULL, + .users = 1, + .readers = 1, + .writers = 1, + .fops = &dst_ca_fops +}; + +struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter) +{ + struct dvb_device *dvbdev; + + dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device"); + if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) { + dst->dst_ca = dvbdev; + return dst->dst_ca; + } + + return NULL; +} + +EXPORT_SYMBOL(dst_ca_attach); + +MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_ca.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_ca.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_ca.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_ca.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + CA-driver for TwinHan DST Frontend/Card + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _DST_CA_H_ +#define _DST_CA_H_ + +#define RETRIES 5 + + +#define CA_APP_INFO_ENQUIRY 0x9f8020 +#define CA_APP_INFO 0x9f8021 +#define CA_ENTER_MENU 0x9f8022 +#define CA_INFO_ENQUIRY 0x9f8030 +#define CA_INFO 0x9f8031 +#define CA_PMT 0x9f8032 +#define CA_PMT_REPLY 0x9f8033 + +#define CA_CLOSE_MMI 0x9f8800 +#define CA_DISPLAY_CONTROL 0x9f8801 +#define CA_DISPLAY_REPLY 0x9f8802 +#define CA_TEXT_LAST 0x9f8803 +#define CA_TEXT_MORE 0x9f8804 +#define CA_KEYPAD_CONTROL 0x9f8805 +#define CA_KEYPRESS 0x9f8806 + +#define CA_ENQUIRY 0x9f8807 +#define CA_ANSWER 0x9f8808 +#define CA_MENU_LAST 0x9f8809 +#define CA_MENU_MORE 0x9f880a +#define CA_MENU_ANSWER 0x9f880b +#define CA_LIST_LAST 0x9f880c +#define CA_LIST_MORE 0x9f880d + + +struct dst_ca_private { + struct dst_state *dst; + struct dvb_device *dvbdev; +}; + + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_common.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_common.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,182 @@ +/* + Frontend-driver for TwinHan DST Frontend + + Copyright (C) 2003 Jamie Honan + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef DST_COMMON_H +#define DST_COMMON_H + +#include +#include +#include +#include "bt878.h" + +#include "dst_ca.h" + + +#define NO_DELAY 0 +#define LONG_DELAY 1 +#define DEVICE_INIT 2 + +#define DELAY 1 + +#define DST_TYPE_IS_SAT 0 +#define DST_TYPE_IS_TERR 1 +#define DST_TYPE_IS_CABLE 2 +#define DST_TYPE_IS_ATSC 3 + +#define DST_TYPE_HAS_TS188 1 +#define DST_TYPE_HAS_TS204 2 +#define DST_TYPE_HAS_SYMDIV 4 +#define DST_TYPE_HAS_FW_1 8 +#define DST_TYPE_HAS_FW_2 16 +#define DST_TYPE_HAS_FW_3 32 +#define DST_TYPE_HAS_FW_BUILD 64 +#define DST_TYPE_HAS_OBS_REGS 128 +#define DST_TYPE_HAS_INC_COUNT 256 +#define DST_TYPE_HAS_MULTI_FE 512 +#define DST_TYPE_HAS_NEWTUNE_2 1024 +#define DST_TYPE_HAS_DBOARD 2048 +#define DST_TYPE_HAS_VLF 4096 + +/* Card capability list */ + +#define DST_TYPE_HAS_MAC 1 +#define DST_TYPE_HAS_DISEQC3 2 +#define DST_TYPE_HAS_DISEQC4 4 +#define DST_TYPE_HAS_DISEQC5 8 +#define DST_TYPE_HAS_MOTO 16 +#define DST_TYPE_HAS_CA 32 +#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ +#define DST_TYPE_HAS_SESSION 128 + +#define TUNER_TYPE_MULTI 1 +#define TUNER_TYPE_UNKNOWN 2 +/* DVB-S */ +#define TUNER_TYPE_L64724 4 +#define TUNER_TYPE_STV0299 8 +#define TUNER_TYPE_MB86A15 16 + +/* DVB-T */ +#define TUNER_TYPE_TDA10046 32 + +/* ATSC */ +#define TUNER_TYPE_NXT200x 64 + + +#define RDC_8820_PIO_0_DISABLE 0 +#define RDC_8820_PIO_0_ENABLE 1 +#define RDC_8820_INT 2 +#define RDC_8820_RESET 4 + +/* DST Communication */ +#define GET_REPLY 1 +#define NO_REPLY 0 + +#define GET_ACK 1 +#define FIXED_COMM 8 + +#define ACK 0xff + +struct dst_state { + + struct i2c_adapter* i2c; + + struct bt878* bt; + + /* configuration settings */ + const struct dst_config* config; + + struct dvb_frontend frontend; + + /* private ASIC data */ + u8 tx_tuna[10]; + u8 rx_tuna[10]; + u8 rxbuffer[10]; + u8 diseq_flags; + u8 dst_type; + u32 type_flags; + u32 frequency; /* intermediate frequency in kHz for QPSK */ + fe_spectral_inversion_t inversion; + u32 symbol_rate; /* symbol rate in Symbols per second */ + fe_code_rate_t fec; + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; + u32 decode_freq; + u8 decode_lock; + u16 decode_strength; + u16 decode_snr; + unsigned long cur_jiff; + u8 k22; + fe_bandwidth_t bandwidth; + u32 dst_hw_cap; + u8 dst_fw_version; + fe_sec_mini_cmd_t minicmd; + fe_modulation_t modulation; + u8 messages[256]; + u8 mac_address[8]; + u8 fw_version[8]; + u8 card_info[8]; + u8 vendor[8]; + u8 board_info[8]; + u32 tuner_type; + char *tuner_name; + struct mutex dst_mutex; + u8 fw_name[8]; + struct dvb_device *dst_ca; +}; + +struct tuner_types { + u32 tuner_type; + char *tuner_name; + char *board_name; + char *fw_name; +}; + +struct dst_types { + char *device_id; + int offset; + u8 dst_type; + u32 type_flags; + u32 dst_feature; + u32 tuner_type; +}; + +struct dst_config +{ + /* the ASIC i2c address */ + u8 demod_address; +}; + +int rdc_reset_state(struct dst_state *state); + +int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); +int dst_pio_disable(struct dst_state *state); +int dst_error_recovery(struct dst_state* state); +int dst_error_bailout(struct dst_state *state); +int dst_comm_init(struct dst_state* state); + +int write_dst(struct dst_state *state, u8 * data, u8 len); +int read_dst(struct dst_state *state, u8 * ret, u8 len); +u8 dst_check_sum(u8 * buf, u32 len); +struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); +struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); + + +#endif // DST_COMMON_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dst_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend + * + * Copyright (C) 2003 Jamie Honan + */ + +struct dst_gpio_enable { + u32 mask; + u32 enable; +}; + +struct dst_gpio_output { + u32 mask; + u32 highvals; +}; + +struct dst_gpio_read { + unsigned long value; +}; + +union dst_gpio_packet { + struct dst_gpio_enable enb; + struct dst_gpio_output outp; + struct dst_gpio_read rd; + int psize; +}; + +#define DST_IG_ENABLE 0 +#define DST_IG_WRITE 1 +#define DST_IG_READ 2 +#define DST_IG_TS 3 + +struct bt878; + +int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,970 @@ +/* + * Bt8xx based DVB adapter driver + * + * Copyright (C) 2002,2003 Florian Schirmer + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb-bt8xx.h" +#include "bt878.h" + +static int debug; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk( args... ) \ + do { \ + if (debug) printk(KERN_DEBUG args); \ + } while (0) + +#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + +static void dvb_bt8xx_task(unsigned long data) +{ + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data; + + //printk("%d ", card->bt->finished_block); + + while (card->bt->last_block != card->bt->finished_block) { + (card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) + (&card->demux, + &card->bt->buf_cpu[card->bt->last_block * + card->bt->block_bytes], + card->bt->block_bytes); + card->bt->last_block = (card->bt->last_block + 1) % + card->bt->block_count; + } +} + +static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux*dvbdmx = dvbdmxfeed->demux; + struct dvb_bt8xx_card *card = dvbdmx->priv; + int rc; + + dprintk("dvb_bt8xx: start_feed\n"); + + if (!dvbdmx->dmx.frontend) + return -EINVAL; + + mutex_lock(&card->lock); + card->nfeeds++; + rc = card->nfeeds; + if (card->nfeeds == 1) + bt878_start(card->bt, card->gpio_mode, + card->op_sync_orin, card->irq_err_ignore); + mutex_unlock(&card->lock); + return rc; +} + +static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct dvb_bt8xx_card *card = dvbdmx->priv; + + dprintk("dvb_bt8xx: stop_feed\n"); + + if (!dvbdmx->dmx.frontend) + return -EINVAL; + + mutex_lock(&card->lock); + card->nfeeds--; + if (card->nfeeds == 0) + bt878_stop(card->bt); + mutex_unlock(&card->lock); + + return 0; +} + +static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev) +{ + if ((adev->subsystem_vendor == bdev->subsystem_vendor) && + (adev->subsystem_device == bdev->subsystem_device) && + (adev->bus->number == bdev->bus->number) && + (PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn))) + return 1; + return 0; +} + +static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev) +{ + unsigned int card_nr; + + /* Hmm, n squared. Hope n is small */ + for (card_nr = 0; card_nr < bt878_num; card_nr++) + if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev)) + return &bt878[card_nr]; + return NULL; +} + +static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 }; + static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) +{ + u32 div; + unsigned char bs = 0; + unsigned char cp = 0; + + if (buf_len < 5) + return -EINVAL; + + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency < 542000000) + cp = 0xb4; + else if (params->frequency < 771000000) + cp = 0xbc; + else + cp = 0xf4; + + if (params->frequency == 0) + bs = 0x03; + else if (params->frequency < 443250000) + bs = 0x02; + else + bs = 0x08; + + pllbuf[0] = 0x60; + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = cp; + pllbuf[4] = bs; + + return 5; +} + +static struct mt352_config thomson_dtt7579_config = { + .demod_address = 0x0f, + .demod_init = thomson_dtt7579_demod_init, +}; + +static struct zl10353_config thomson_dtt7579_zl10353_config = { + .demod_address = 0x0f, +}; + +static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u32 freq = params->frequency; + + int i, a, n, pump; + u32 band, pll; + + u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, + 1576000,1718000,1856000,2036000,2150000}; + u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, + 0x00102000,0x00104000,0x00108000,0x00110000, + 0x00120000,0x00140000}; + + #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ + printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq); + + /* This is really the bit driving the tuner chip cx24108 */ + + if (freq<950000) + freq = 950000; /* kHz */ + else if (freq>2150000) + freq = 2150000; /* satellite IF is 950..2150MHz */ + + /* decide which VCO to use for the input frequency */ + for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++); + printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq); + band=bandsel[i]; + /* the gain values must be set by SetSymbolrate */ + /* compute the pll divider needed, from Conexant data sheet, + resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4, + depending on the divider bit. It is set to /4 on the 2 lowest + bands */ + n=((i<=2?2:1)*freq*10L)/(XTAL/100); + a=n%32; n/=32; if(a==0) n--; + pump=(freq<(osci[i-1]+osci[i])/2); + pll=0xf8000000| + ((pump?1:2)<<(14+11))| + ((n&0x1ff)<<(5+11))| + ((a&0x1f)<<11); + /* everything is shifted left 11 bits to left-align the bits in the + 32bit word. Output to the tuner goes MSB-aligned, after all */ + printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a); + cx24110_pll_write(fe,band); + /* set vga and vca to their widest-band settings, as a precaution. + SetSymbolrate might not be called to set this up */ + cx24110_pll_write(fe,0x500c0000); + cx24110_pll_write(fe,0x83f1f800); + cx24110_pll_write(fe,pll); + //writereg(client,0x56,0x7f); + + return 0; +} + +static int pinnsat_tuner_init(struct dvb_frontend* fe) +{ + struct dvb_bt8xx_card *card = fe->dvb->priv; + + bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */ + bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */ + + return 0; +} + +static int pinnsat_tuner_sleep(struct dvb_frontend* fe) +{ + struct dvb_bt8xx_card *card = fe->dvb->priv; + + bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */ + + return 0; +} + +static struct cx24110_config pctvsat_config = { + .demod_address = 0x55, +}; + +static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; + u8 cfg, cpump, band_select; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (36000000 + params->frequency + 83333) / 166666; + cfg = 0x88; + + if (params->frequency < 175000000) + cpump = 2; + else if (params->frequency < 390000000) + cpump = 1; + else if (params->frequency < 470000000) + cpump = 2; + else if (params->frequency < 750000000) + cpump = 2; + else + cpump = 3; + + if (params->frequency < 175000000) + band_select = 0x0e; + else if (params->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = (cpump << 6) | band_select; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(card->i2c_adapter, &msg, 1); + return (div * 166666 - 36000000); +} + +static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; + + return request_firmware(fw, name, &bt->bt->dev->dev); +} + +static struct sp887x_config microtune_mt7202dtf_config = { + .demod_address = 0x70, + .request_firmware = microtune_mt7202dtf_request_firmware, +}; + +static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x40, 0x40 }; + static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); + udelay(2000); + mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) +{ + u32 div; + unsigned char bs = 0; + unsigned char cp = 0; + + if (buf_len < 5) return -EINVAL; + + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency < 150000000) + cp = 0xB4; + else if (params->frequency < 173000000) + cp = 0xBC; + else if (params->frequency < 250000000) + cp = 0xB4; + else if (params->frequency < 400000000) + cp = 0xBC; + else if (params->frequency < 420000000) + cp = 0xF4; + else if (params->frequency < 470000000) + cp = 0xFC; + else if (params->frequency < 600000000) + cp = 0xBC; + else if (params->frequency < 730000000) + cp = 0xF4; + else + cp = 0xFC; + + if (params->frequency < 150000000) + bs = 0x01; + else if (params->frequency < 173000000) + bs = 0x01; + else if (params->frequency < 250000000) + bs = 0x02; + else if (params->frequency < 400000000) + bs = 0x02; + else if (params->frequency < 420000000) + bs = 0x02; + else if (params->frequency < 470000000) + bs = 0x02; + else if (params->frequency < 600000000) + bs = 0x08; + else if (params->frequency < 730000000) + bs = 0x08; + else + bs = 0x08; + + pllbuf[0] = 0x61; + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = cp; + pllbuf[4] = bs; + + return 5; +} + +static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { + .demod_address = 0x0f, + .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, +}; + +static struct dst_config dst_config = { + .demod_address = 0x55, +}; + +static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; + + return request_firmware(fw, name, &bt->bt->dev->dev); +} + +static void or51211_setmode(struct dvb_frontend * fe, int mode) +{ + struct dvb_bt8xx_card *bt = fe->dvb->priv; + bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */ + msleep(20); +} + +static void or51211_reset(struct dvb_frontend * fe) +{ + struct dvb_bt8xx_card *bt = fe->dvb->priv; + + /* RESET DEVICE + * reset is controlled by GPIO-0 + * when set to 0 causes reset and when to 1 for normal op + * must remain reset for 128 clock cycles on a 50Mhz clock + * also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4 + * We assume that the reset has be held low long enough or we + * have been reset by a power on. When the driver is unloaded + * reset set to 0 so if reloaded we have been reset. + */ + /* reset & PRM1,2&4 are outputs */ + int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); + if (ret != 0) + printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret); + bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ + msleep(20); + /* Now set for normal operation */ + bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001); + /* wait for operation to begin */ + msleep(500); +} + +static void or51211_sleep(struct dvb_frontend * fe) +{ + struct dvb_bt8xx_card *bt = fe->dvb->priv; + bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000); +} + +static struct or51211_config or51211_config = { + .demod_address = 0x15, + .request_firmware = or51211_request_firmware, + .setmode = or51211_setmode, + .reset = or51211_reset, + .sleep = or51211_sleep, +}; + +static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; + + div = (params->frequency + 36166667) / 166667; + + buf[0] = (div >> 8) & 0x7F; + buf[1] = div & 0xFF; + buf[2] = 0x85; + if ((params->frequency >= 47000000) && (params->frequency < 153000000)) + buf[3] = 0x01; + else if ((params->frequency >= 153000000) && (params->frequency < 430000000)) + buf[3] = 0x02; + else if ((params->frequency >= 430000000) && (params->frequency < 824000000)) + buf[3] = 0x0C; + else if ((params->frequency >= 824000000) && (params->frequency < 863000000)) + buf[3] = 0x8C; + else + return -EINVAL; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(card->i2c_adapter, &msg, 1); + return 0; +} + +static struct nxt6000_config vp3021_alps_tded4_config = { + .demod_address = 0x0a, + .clock_inversion = 1, +}; + +static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) +{ + u32 div; + struct dvb_ofdm_parameters *op = ¶ms->u.ofdm; + + if (buf_len < 5) + return -EINVAL; + + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + pllbuf[0] = 0x61; + pllbuf[1] = (div >> 8) & 0x7F; + pllbuf[2] = div & 0xFF; + pllbuf[3] = 0x85; + + dprintk("frequency %u, div %u\n", params->frequency, div); + + if (params->frequency < 470000000) + pllbuf[4] = 0x02; + else if (params->frequency > 823000000) + pllbuf[4] = 0x88; + else + pllbuf[4] = 0x08; + + if (op->bandwidth == 8) + pllbuf[4] |= 0x04; + + return 5; +} + +static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) +{ + /* + * Reset the frontend, must be called before trying + * to initialise the MT352 or mt352_attach + * will fail. Same goes for the nxt6000 frontend. + * + */ + + int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08); + if (ret != 0) + printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret); + + /* Pulse the reset line */ + bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ + bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */ + msleep(100); + + bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ +} + +static struct mt352_config digitv_alps_tded4_config = { + .demod_address = 0x0a, + .demod_init = digitv_alps_tded4_demod_init, +}; + +static struct lgdt330x_config tdvs_tua6034_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ +}; + +static void lgdt330x_reset(struct dvb_bt8xx_card *bt) +{ + /* Set pin 27 of the lgdt3303 chip high to reset the frontend */ + + /* Pulse the reset line */ + bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ + bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */ + msleep(100); + + bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ + msleep(100); +} + +static void frontend_init(struct dvb_bt8xx_card *card, u32 type) +{ + struct dst_state* state = NULL; + + switch(type) { + case BTTV_BOARD_DVICO_DVBT_LITE: + card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter); + + if (card->fe == NULL) + card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config, + card->i2c_adapter); + + if (card->fe != NULL) { + card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs; + card->fe->ops.info.frequency_min = 174000000; + card->fe->ops.info.frequency_max = 862000000; + } + break; + + case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: + lgdt330x_reset(card); + card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); + if (card->fe != NULL) { + dvb_attach(simple_tuner_attach, card->fe, + card->i2c_adapter, 0x61, + TUNER_LG_TDVS_H06XF); + dprintk ("dvb_bt8xx: lgdt330x detected\n"); + } + break; + + case BTTV_BOARD_NEBULA_DIGITV: + /* + * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); + * this would be a cleaner solution than trying each frontend in turn. + */ + + /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ + digitv_alps_tded4_reset(card); + card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter); + if (card->fe != NULL) { + card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params; + dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); + break; + } + + /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */ + digitv_alps_tded4_reset(card); + card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter); + + if (card->fe != NULL) { + card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs; + dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); + } + break; + + case BTTV_BOARD_AVDVBT_761: + card->fe = dvb_attach(sp887x_attach, µtune_mt7202dtf_config, card->i2c_adapter); + if (card->fe) { + card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params; + } + break; + + case BTTV_BOARD_AVDVBT_771: + card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); + if (card->fe != NULL) { + card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs; + card->fe->ops.info.frequency_min = 174000000; + card->fe->ops.info.frequency_max = 862000000; + } + break; + + case BTTV_BOARD_TWINHAN_DST: + /* DST is not a frontend driver !!! */ + state = kmalloc(sizeof (struct dst_state), GFP_KERNEL); + if (!state) { + printk("dvb_bt8xx: No memory\n"); + break; + } + /* Setup the Card */ + state->config = &dst_config; + state->i2c = card->i2c_adapter; + state->bt = card->bt; + state->dst_ca = NULL; + /* DST is not a frontend, attaching the ASIC */ + if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) { + printk("%s: Could not find a Twinhan DST.\n", __func__); + break; + } + /* Attach other DST peripherals if any */ + /* Conditional Access device */ + card->fe = &state->frontend; + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + dvb_attach(dst_ca_attach, state, &card->dvb_adapter); + break; + + case BTTV_BOARD_PINNACLESAT: + card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter); + if (card->fe) { + card->fe->ops.tuner_ops.init = pinnsat_tuner_init; + card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep; + card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params; + } + break; + + case BTTV_BOARD_PC_HDTV: + card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter); + if (card->fe != NULL) + dvb_attach(simple_tuner_attach, card->fe, + card->i2c_adapter, 0x61, + TUNER_PHILIPS_FCV1236D); + break; + } + + if (card->fe == NULL) + printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + card->bt->dev->vendor, + card->bt->dev->device, + card->bt->dev->subsystem_vendor, + card->bt->dev->subsystem_device); + else + if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { + printk("dvb-bt8xx: Frontend registration failed!\n"); + dvb_frontend_detach(card->fe); + card->fe = NULL; + } +} + +static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) +{ + int result; + + result = dvb_register_adapter(&card->dvb_adapter, card->card_name, + THIS_MODULE, &card->bt->dev->dev, + adapter_nr); + if (result < 0) { + printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result); + return result; + } + card->dvb_adapter.priv = card; + + card->bt->adapter = card->i2c_adapter; + + memset(&card->demux, 0, sizeof(struct dvb_demux)); + + card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; + + card->demux.priv = card; + card->demux.filternum = 256; + card->demux.feednum = 256; + card->demux.start_feed = dvb_bt8xx_start_feed; + card->demux.stop_feed = dvb_bt8xx_stop_feed; + card->demux.write_to_decoder = NULL; + + if ((result = dvb_dmx_init(&card->demux)) < 0) { + printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); + + dvb_unregister_adapter(&card->dvb_adapter); + return result; + } + + card->dmxdev.filternum = 256; + card->dmxdev.demux = &card->demux.dmx; + card->dmxdev.capabilities = 0; + + if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) { + printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result); + + dvb_dmx_release(&card->demux); + dvb_unregister_adapter(&card->dvb_adapter); + return result; + } + + card->fe_hw.source = DMX_FRONTEND_0; + + if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { + printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); + + dvb_dmxdev_release(&card->dmxdev); + dvb_dmx_release(&card->demux); + dvb_unregister_adapter(&card->dvb_adapter); + return result; + } + + card->fe_mem.source = DMX_MEMORY_FE; + + if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) { + printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); + + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); + dvb_dmxdev_release(&card->dmxdev); + dvb_dmx_release(&card->demux); + dvb_unregister_adapter(&card->dvb_adapter); + return result; + } + + if ((result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { + printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); + + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); + dvb_dmxdev_release(&card->dmxdev); + dvb_dmx_release(&card->demux); + dvb_unregister_adapter(&card->dvb_adapter); + return result; + } + + dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); + + tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); + + frontend_init(card, type); + + return 0; +} + +static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) +{ + struct dvb_bt8xx_card *card; + struct pci_dev* bttv_pci_dev; + int ret; + + if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL))) + return -ENOMEM; + + mutex_init(&card->lock); + card->bttv_nr = sub->core->nr; + strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name)); + card->i2c_adapter = &sub->core->i2c_adap; + + switch(sub->core->type) { + case BTTV_BOARD_PINNACLESAT: + card->gpio_mode = 0x0400c060; + /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, + BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + break; + + case BTTV_BOARD_DVICO_DVBT_LITE: + card->gpio_mode = 0x0400C060; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + /* 26, 15, 14, 6, 5 + * A_PWRDN DA_DPM DA_SBR DA_IOM_DA + * DA_APP(parallel) */ + break; + + case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: + card->gpio_mode = 0x0400c060; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + break; + + case BTTV_BOARD_NEBULA_DIGITV: + case BTTV_BOARD_AVDVBT_761: + card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + /* A_PWRDN DA_SBR DA_APP (high speed serial) */ + break; + + case BTTV_BOARD_AVDVBT_771: //case 0x07711461: + card->gpio_mode = 0x0400402B; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + /* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/ + break; + + case BTTV_BOARD_TWINHAN_DST: + card->gpio_mode = 0x2204f2c; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR | + BT878_APPERR | BT878_AFBUS; + /* 25,21,14,11,10,9,8,3,2 then + * 0x33 = 5,4,1,0 + * A_SEL=SML, DA_MLB, DA_SBR, + * DA_SDR=f, fifo trigger = 32 DWORDS + * IOM = 0 == audio A/D + * DPM = 0 == digital audio mode + * == async data parallel port + * then 0x33 (13 is set by start_capture) + * DA_APP = async data parallel port, + * ACAP_EN = 1, + * RISC+FIFO ENABLE */ + break; + + case BTTV_BOARD_PC_HDTV: + card->gpio_mode = 0x0100EC7B; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + break; + + default: + printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n", + sub->core->type); + kfree(card); + return -ENODEV; + } + + dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name); + + if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) { + printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr); + kfree(card); + return -EFAULT; + } + + if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) { + printk("dvb_bt8xx: unable to determine DMA core of card %d,\n", + card->bttv_nr); + printk("dvb_bt8xx: if you have the ALSA bt87x audio driver " + "installed, try removing it.\n"); + + kfree(card); + return -EFAULT; + } + + mutex_init(&card->bt->gpio_lock); + card->bt->bttv_nr = sub->core->nr; + + if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) { + kfree(card); + return ret; + } + + dev_set_drvdata(&sub->dev, card); + return 0; +} + +static void dvb_bt8xx_remove(struct bttv_sub_device *sub) +{ + struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev); + + dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); + + bt878_stop(card->bt); + tasklet_kill(&card->bt->tasklet); + dvb_net_release(&card->dvbnet); + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); + dvb_dmxdev_release(&card->dmxdev); + dvb_dmx_release(&card->demux); + if (card->fe) { + dvb_unregister_frontend(card->fe); + dvb_frontend_detach(card->fe); + } + dvb_unregister_adapter(&card->dvb_adapter); + + kfree(card); +} + +static struct bttv_sub_driver driver = { + .drv = { + .name = "dvb-bt8xx", + }, + .probe = dvb_bt8xx_probe, + .remove = dvb_bt8xx_remove, + /* FIXME: + * .shutdown = dvb_bt8xx_shutdown, + * .suspend = dvb_bt8xx_suspend, + * .resume = dvb_bt8xx_resume, + */ +}; + +static int __init dvb_bt8xx_init(void) +{ + return bttv_sub_register(&driver, "dvb"); +} + +static void __exit dvb_bt8xx_exit(void) +{ + bttv_sub_unregister(&driver); +} + +module_init(dvb_bt8xx_init); +module_exit(dvb_bt8xx_exit); + +MODULE_DESCRIPTION("Bt8xx based DVB adapter driver"); +MODULE_AUTHOR("Florian Schirmer "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Bt8xx based DVB adapter driver + * + * Copyright (C) 2002,2003 Florian Schirmer + * Copyright (C) 2002 Peter Hettkamp + * Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH + * Copyright (C) 1998,1999 Christian Theiss + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef DVB_BT8XX_H +#define DVB_BT8XX_H + +#include +#include +#include "dvbdev.h" +#include "dvb_net.h" +#include "bttv.h" +#include "mt352.h" +#include "sp887x.h" +#include "dst_common.h" +#include "nxt6000.h" +#include "cx24110.h" +#include "or51211.h" +#include "lgdt330x.h" +#include "zl10353.h" +#include "tuner-simple.h" + +struct dvb_bt8xx_card { + struct mutex lock; + int nfeeds; + char card_name[32]; + struct dvb_adapter dvb_adapter; + struct bt878 *bt; + unsigned int bttv_nr; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + u32 gpio_mode; + u32 op_sync_orin; + u32 irq_err_ignore; + struct i2c_adapter *i2c_adapter; + struct dvb_net dvbnet; + + struct dvb_frontend* fe; +}; + +#endif /* DVB_BT8XX_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,22 @@ +config DVB_BT8XX + tristate "BT8xx based PCI cards" + depends on DVB_CORE && PCI && I2C && VIDEO_BT848 + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_SP887X if !DVB_FE_CUSTOMISE + select DVB_NXT6000 if !DVB_FE_CUSTOMISE + select DVB_CX24110 if !DVB_FE_CUSTOMISE + select DVB_OR51211 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + help + Support for PCI cards based on the Bt8xx PCI bridge. Examples are + the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, + the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and + some AVerMedia cards. + + Since these cards have no MPEG decoder onboard, they transmit + only compressed MPEG data over the PCI bus, so you need + an external software decoder to watch TV on your computer. + + Say Y if you own such a device and want to use it. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/bt8xx/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,6 @@ +obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/video/bt8xx +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/dm1105.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/dm1105.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/dm1105.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/dm1105.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,1244 @@ +/* + * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip + * + * Copyright (C) 2008 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" +#include "dvb-pll.h" + +#include "stv0299.h" +#include "stv0288.h" +#include "stb6000.h" +#include "si21xx.h" +#include "cx24116.h" +#include "z0194a.h" +#include "ds3000.h" + +#define MODULE_NAME "dm1105" + +#define UNSET (-1U) + +#define DM1105_BOARD_NOAUTO UNSET +#define DM1105_BOARD_UNKNOWN 0 +#define DM1105_BOARD_DVBWORLD_2002 1 +#define DM1105_BOARD_DVBWORLD_2004 2 +#define DM1105_BOARD_AXESS_DM05 3 +#define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO 4 + +/* ----------------------------------------------- */ +/* + * PCI ID's + */ +#ifndef PCI_VENDOR_ID_TRIGEM +#define PCI_VENDOR_ID_TRIGEM 0x109f +#endif +#ifndef PCI_VENDOR_ID_AXESS +#define PCI_VENDOR_ID_AXESS 0x195d +#endif +#ifndef PCI_DEVICE_ID_DM1105 +#define PCI_DEVICE_ID_DM1105 0x036f +#endif +#ifndef PCI_DEVICE_ID_DW2002 +#define PCI_DEVICE_ID_DW2002 0x2002 +#endif +#ifndef PCI_DEVICE_ID_DW2004 +#define PCI_DEVICE_ID_DW2004 0x2004 +#endif +#ifndef PCI_DEVICE_ID_DM05 +#define PCI_DEVICE_ID_DM05 0x1105 +#endif +/* ----------------------------------------------- */ +/* sdmc dm1105 registers */ + +/* TS Control */ +#define DM1105_TSCTR 0x00 +#define DM1105_DTALENTH 0x04 + +/* GPIO Interface */ +#define DM1105_GPIOVAL 0x08 +#define DM1105_GPIOCTR 0x0c + +/* PID serial number */ +#define DM1105_PIDN 0x10 + +/* Odd-even secret key select */ +#define DM1105_CWSEL 0x14 + +/* Host Command Interface */ +#define DM1105_HOST_CTR 0x18 +#define DM1105_HOST_AD 0x1c + +/* PCI Interface */ +#define DM1105_CR 0x30 +#define DM1105_RST 0x34 +#define DM1105_STADR 0x38 +#define DM1105_RLEN 0x3c +#define DM1105_WRP 0x40 +#define DM1105_INTCNT 0x44 +#define DM1105_INTMAK 0x48 +#define DM1105_INTSTS 0x4c + +/* CW Value */ +#define DM1105_ODD 0x50 +#define DM1105_EVEN 0x58 + +/* PID Value */ +#define DM1105_PID 0x60 + +/* IR Control */ +#define DM1105_IRCTR 0x64 +#define DM1105_IRMODE 0x68 +#define DM1105_SYSTEMCODE 0x6c +#define DM1105_IRCODE 0x70 + +/* Unknown Values */ +#define DM1105_ENCRYPT 0x74 +#define DM1105_VER 0x7c + +/* I2C Interface */ +#define DM1105_I2CCTR 0x80 +#define DM1105_I2CSTS 0x81 +#define DM1105_I2CDAT 0x82 +#define DM1105_I2C_RA 0x83 +/* ----------------------------------------------- */ +/* Interrupt Mask Bits */ + +#define INTMAK_TSIRQM 0x01 +#define INTMAK_HIRQM 0x04 +#define INTMAK_IRM 0x08 +#define INTMAK_ALLMASK (INTMAK_TSIRQM | \ + INTMAK_HIRQM | \ + INTMAK_IRM) +#define INTMAK_NONEMASK 0x00 + +/* Interrupt Status Bits */ +#define INTSTS_TSIRQ 0x01 +#define INTSTS_HIRQ 0x04 +#define INTSTS_IR 0x08 + +/* IR Control Bits */ +#define DM1105_IR_EN 0x01 +#define DM1105_SYS_CHK 0x02 +#define DM1105_REP_FLG 0x08 + +/* EEPROM addr */ +#define IIC_24C01_addr 0xa0 +/* Max board count */ +#define DM1105_MAX 0x04 + +#define DRIVER_NAME "dm1105" +#define DM1105_I2C_GPIO_NAME "dm1105-gpio" + +#define DM1105_DMA_PACKETS 47 +#define DM1105_DMA_PACKET_LENGTH (128*4) +#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS) + +/* */ +#define GPIO08 (1 << 8) +#define GPIO13 (1 << 13) +#define GPIO14 (1 << 14) +#define GPIO15 (1 << 15) +#define GPIO16 (1 << 16) +#define GPIO17 (1 << 17) +#define GPIO_ALL 0x03ffff + +/* GPIO's for LNB power control */ +#define DM1105_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13)) +#define DM1105_LNB_OFF GPIO17 +#define DM1105_LNB_13V (GPIO16 | GPIO08) +#define DM1105_LNB_18V GPIO08 + +/* GPIO's for LNB power control for Axess DM05 */ +#define DM05_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13)) +#define DM05_LNB_OFF GPIO17/* actually 13v */ +#define DM05_LNB_13V GPIO17 +#define DM05_LNB_18V (GPIO17 | GPIO16) + +/* GPIO's for LNB power control for unbranded with I2C on GPIO */ +#define UNBR_LNB_MASK (GPIO17 | GPIO16) +#define UNBR_LNB_OFF 0 +#define UNBR_LNB_13V GPIO17 +#define UNBR_LNB_18V (GPIO17 | GPIO16) + +static unsigned int card[] = {[0 ... 3] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); + +static int ir_debug; +module_param(ir_debug, int, 0644); +MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); + +static unsigned int dm1105_devcount; + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct dm1105_board { + char *name; + struct { + u32 mask, off, v13, v18; + } lnb; + u32 gpio_scl, gpio_sda; +}; + +struct dm1105_subid { + u16 subvendor; + u16 subdevice; + u32 card; +}; + +static const struct dm1105_board dm1105_boards[] = { + [DM1105_BOARD_UNKNOWN] = { + .name = "UNKNOWN/GENERIC", + .lnb = { + .mask = DM1105_LNB_MASK, + .off = DM1105_LNB_OFF, + .v13 = DM1105_LNB_13V, + .v18 = DM1105_LNB_18V, + }, + }, + [DM1105_BOARD_DVBWORLD_2002] = { + .name = "DVBWorld PCI 2002", + .lnb = { + .mask = DM1105_LNB_MASK, + .off = DM1105_LNB_OFF, + .v13 = DM1105_LNB_13V, + .v18 = DM1105_LNB_18V, + }, + }, + [DM1105_BOARD_DVBWORLD_2004] = { + .name = "DVBWorld PCI 2004", + .lnb = { + .mask = DM1105_LNB_MASK, + .off = DM1105_LNB_OFF, + .v13 = DM1105_LNB_13V, + .v18 = DM1105_LNB_18V, + }, + }, + [DM1105_BOARD_AXESS_DM05] = { + .name = "Axess/EasyTv DM05", + .lnb = { + .mask = DM05_LNB_MASK, + .off = DM05_LNB_OFF, + .v13 = DM05_LNB_13V, + .v18 = DM05_LNB_18V, + }, + }, + [DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = { + .name = "Unbranded DM1105 with i2c on GPIOs", + .lnb = { + .mask = UNBR_LNB_MASK, + .off = UNBR_LNB_OFF, + .v13 = UNBR_LNB_13V, + .v18 = UNBR_LNB_18V, + }, + .gpio_scl = GPIO14, + .gpio_sda = GPIO13, + }, +}; + +static const struct dm1105_subid dm1105_subids[] = { + { + .subvendor = 0x0000, + .subdevice = 0x2002, + .card = DM1105_BOARD_DVBWORLD_2002, + }, { + .subvendor = 0x0001, + .subdevice = 0x2002, + .card = DM1105_BOARD_DVBWORLD_2002, + }, { + .subvendor = 0x0000, + .subdevice = 0x2004, + .card = DM1105_BOARD_DVBWORLD_2004, + }, { + .subvendor = 0x0001, + .subdevice = 0x2004, + .card = DM1105_BOARD_DVBWORLD_2004, + }, { + .subvendor = 0x195d, + .subdevice = 0x1105, + .card = DM1105_BOARD_AXESS_DM05, + }, +}; + +static void dm1105_card_list(struct pci_dev *pci) +{ + int i; + + if (0 == pci->subsystem_vendor && + 0 == pci->subsystem_device) { + printk(KERN_ERR + "dm1105: Your board has no valid PCI Subsystem ID\n" + "dm1105: and thus can't be autodetected\n" + "dm1105: Please pass card= insmod option to\n" + "dm1105: workaround that. Redirect complaints to\n" + "dm1105: the vendor of the TV card. Best regards,\n" + "dm1105: -- tux\n"); + } else { + printk(KERN_ERR + "dm1105: Your board isn't known (yet) to the driver.\n" + "dm1105: You can try to pick one of the existing\n" + "dm1105: card configs via card= insmod option.\n" + "dm1105: Updating to the latest version might help\n" + "dm1105: as well.\n"); + } + printk(KERN_ERR "Here is a list of valid choices for the card= " + "insmod option:\n"); + for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++) + printk(KERN_ERR "dm1105: card=%d -> %s\n", + i, dm1105_boards[i].name); +} + +/* infrared remote control */ +struct infrared { + struct rc_dev *dev; + char input_phys[32]; + struct work_struct work; + u32 ir_command; +}; + +struct dm1105_dev { + /* pci */ + struct pci_dev *pdev; + u8 __iomem *io_mem; + + /* ir */ + struct infrared ir; + + /* dvb */ + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + unsigned int full_ts_users; + unsigned int boardnr; + int nr; + + /* i2c */ + struct i2c_adapter i2c_adap; + struct i2c_adapter i2c_bb_adap; + struct i2c_algo_bit_data i2c_bit; + + /* irq */ + struct work_struct work; + struct workqueue_struct *wq; + char wqn[16]; + + /* dma */ + dma_addr_t dma_addr; + unsigned char *ts_buf; + u32 wrp; + u32 nextwrp; + u32 buffer_size; + unsigned int PacketErrorCount; + unsigned int dmarst; + spinlock_t lock; +}; + +#define dm_io_mem(reg) ((unsigned long)(&dev->io_mem[reg])) + +#define dm_readb(reg) inb(dm_io_mem(reg)) +#define dm_writeb(reg, value) outb((value), (dm_io_mem(reg))) + +#define dm_readw(reg) inw(dm_io_mem(reg)) +#define dm_writew(reg, value) outw((value), (dm_io_mem(reg))) + +#define dm_readl(reg) inl(dm_io_mem(reg)) +#define dm_writel(reg, value) outl((value), (dm_io_mem(reg))) + +#define dm_andorl(reg, mask, value) \ + outl((inl(dm_io_mem(reg)) & ~(mask)) |\ + ((value) & (mask)), (dm_io_mem(reg))) + +#define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit)) +#define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0) + +/* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines, + so we can use only 3 GPIO's from GPIO15 to GPIO17. + Here I don't check whether HOST is enebled as it is not implemented yet. + */ +static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if (mask & 0x0003ffff) + dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff); + +} + +static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if (mask & 0x0003ffff) + dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff); + +} + +static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if (mask & 0x0003ffff) + dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val); + +} + +static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if (mask & 0x0003ffff) + return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff; + + return 0; +} + +static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput) +{ + if (mask & 0xfffc0000) + printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); + + if ((mask & 0x0003ffff) && asoutput) + dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff); + else if ((mask & 0x0003ffff) && !asoutput) + dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff); + +} + +static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state) +{ + if (state) + dm1105_gpio_enable(dev, line, 0); + else { + dm1105_gpio_enable(dev, line, 1); + dm1105_gpio_clear(dev, line); + } +} + +static void dm1105_setsda(void *data, int state) +{ + struct dm1105_dev *dev = data; + + dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state); +} + +static void dm1105_setscl(void *data, int state) +{ + struct dm1105_dev *dev = data; + + dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state); +} + +static int dm1105_getsda(void *data) +{ + struct dm1105_dev *dev = data; + + return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda) + ? 1 : 0; +} + +static int dm1105_getscl(void *data) +{ + struct dm1105_dev *dev = data; + + return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl) + ? 1 : 0; +} + +static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + struct dm1105_dev *dev ; + + int addr, rc, i, j, k, len, byte, data; + u8 status; + + dev = i2c_adap->algo_data; + for (i = 0; i < num; i++) { + dm_writeb(DM1105_I2CCTR, 0x00); + if (msgs[i].flags & I2C_M_RD) { + /* read bytes */ + addr = msgs[i].addr << 1; + addr |= 1; + dm_writeb(DM1105_I2CDAT, addr); + for (byte = 0; byte < msgs[i].len; byte++) + dm_writeb(DM1105_I2CDAT + byte + 1, 0); + + dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len); + for (j = 0; j < 55; j++) { + mdelay(10); + status = dm_readb(DM1105_I2CSTS); + if ((status & 0xc0) == 0x40) + break; + } + if (j >= 55) + return -1; + + for (byte = 0; byte < msgs[i].len; byte++) { + rc = dm_readb(DM1105_I2CDAT + byte + 1); + if (rc < 0) + goto err; + msgs[i].buf[byte] = rc; + } + } else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) { + /* prepaired for cx24116 firmware */ + /* Write in small blocks */ + len = msgs[i].len - 1; + k = 1; + do { + dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1); + dm_writeb(DM1105_I2CDAT + 1, 0xf7); + for (byte = 0; byte < (len > 48 ? 48 : len); byte++) { + data = msgs[i].buf[k + byte]; + dm_writeb(DM1105_I2CDAT + byte + 2, data); + } + dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len)); + for (j = 0; j < 25; j++) { + mdelay(10); + status = dm_readb(DM1105_I2CSTS); + if ((status & 0xc0) == 0x40) + break; + } + + if (j >= 25) + return -1; + + k += 48; + len -= 48; + } while (len > 0); + } else { + /* write bytes */ + dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1); + for (byte = 0; byte < msgs[i].len; byte++) { + data = msgs[i].buf[byte]; + dm_writeb(DM1105_I2CDAT + byte + 1, data); + } + dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len); + for (j = 0; j < 25; j++) { + mdelay(10); + status = dm_readb(DM1105_I2CSTS); + if ((status & 0xc0) == 0x40) + break; + } + + if (j >= 25) + return -1; + } + } + return num; + err: + return rc; +} + +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dm1105_algo = { + .master_xfer = dm1105_i2c_xfer, + .functionality = functionality, +}; + +static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed) +{ + return container_of(feed->demux, struct dm1105_dev, demux); +} + +static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe) +{ + return container_of(fe->dvb, struct dm1105_dev, dvb_adapter); +} + +static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct dm1105_dev *dev = frontend_to_dm1105_dev(fe); + + dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1); + if (voltage == SEC_VOLTAGE_18) + dm1105_gpio_andor(dev, + dm1105_boards[dev->boardnr].lnb.mask, + dm1105_boards[dev->boardnr].lnb.v18); + else if (voltage == SEC_VOLTAGE_13) + dm1105_gpio_andor(dev, + dm1105_boards[dev->boardnr].lnb.mask, + dm1105_boards[dev->boardnr].lnb.v13); + else + dm1105_gpio_andor(dev, + dm1105_boards[dev->boardnr].lnb.mask, + dm1105_boards[dev->boardnr].lnb.off); + + return 0; +} + +static void dm1105_set_dma_addr(struct dm1105_dev *dev) +{ + dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr)); +} + +static int __devinit dm1105_dma_map(struct dm1105_dev *dev) +{ + dev->ts_buf = pci_alloc_consistent(dev->pdev, + 6 * DM1105_DMA_BYTES, + &dev->dma_addr); + + return !dev->ts_buf; +} + +static void dm1105_dma_unmap(struct dm1105_dev *dev) +{ + pci_free_consistent(dev->pdev, + 6 * DM1105_DMA_BYTES, + dev->ts_buf, + dev->dma_addr); +} + +static void dm1105_enable_irqs(struct dm1105_dev *dev) +{ + dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK); + dm_writeb(DM1105_CR, 1); +} + +static void dm1105_disable_irqs(struct dm1105_dev *dev) +{ + dm_writeb(DM1105_INTMAK, INTMAK_IRM); + dm_writeb(DM1105_CR, 0); +} + +static int dm1105_start_feed(struct dvb_demux_feed *f) +{ + struct dm1105_dev *dev = feed_to_dm1105_dev(f); + + if (dev->full_ts_users++ == 0) + dm1105_enable_irqs(dev); + + return 0; +} + +static int dm1105_stop_feed(struct dvb_demux_feed *f) +{ + struct dm1105_dev *dev = feed_to_dm1105_dev(f); + + if (--dev->full_ts_users == 0) + dm1105_disable_irqs(dev); + + return 0; +} + +/* ir work handler */ +static void dm1105_emit_key(struct work_struct *work) +{ + struct infrared *ir = container_of(work, struct infrared, work); + u32 ircom = ir->ir_command; + u8 data; + + if (ir_debug) + printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom); + + data = (ircom >> 8) & 0x7f; + + rc_keydown(ir->dev, data, 0); +} + +/* work handler */ +static void dm1105_dmx_buffer(struct work_struct *work) +{ + struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work); + unsigned int nbpackets; + u32 oldwrp = dev->wrp; + u32 nextwrp = dev->nextwrp; + + if (!((dev->ts_buf[oldwrp] == 0x47) && + (dev->ts_buf[oldwrp + 188] == 0x47) && + (dev->ts_buf[oldwrp + 188 * 2] == 0x47))) { + dev->PacketErrorCount++; + /* bad packet found */ + if ((dev->PacketErrorCount >= 2) && + (dev->dmarst == 0)) { + dm_writeb(DM1105_RST, 1); + dev->wrp = 0; + dev->PacketErrorCount = 0; + dev->dmarst = 0; + return; + } + } + + if (nextwrp < oldwrp) { + memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp); + nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188; + } else + nbpackets = (nextwrp - oldwrp) / 188; + + dev->wrp = nextwrp; + dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets); +} + +static irqreturn_t dm1105_irq(int irq, void *dev_id) +{ + struct dm1105_dev *dev = dev_id; + + /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */ + unsigned int intsts = dm_readb(DM1105_INTSTS); + dm_writeb(DM1105_INTSTS, intsts); + + switch (intsts) { + case INTSTS_TSIRQ: + case (INTSTS_TSIRQ | INTSTS_IR): + dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR); + queue_work(dev->wq, &dev->work); + break; + case INTSTS_IR: + dev->ir.ir_command = dm_readl(DM1105_IRCODE); + schedule_work(&dev->ir.work); + break; + } + + return IRQ_HANDLED; +} + +int __devinit dm1105_ir_init(struct dm1105_dev *dm1105) +{ + struct rc_dev *dev; + int err = -ENOMEM; + + dev = rc_allocate_device(); + if (!dev) + return -ENOMEM; + + snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), + "pci-%s/ir0", pci_name(dm1105->pdev)); + + dev->driver_name = MODULE_NAME; + dev->map_name = RC_MAP_DM1105_NEC; + dev->driver_type = RC_DRIVER_SCANCODE; + dev->input_name = "DVB on-card IR receiver"; + dev->input_phys = dm1105->ir.input_phys; + dev->input_id.bustype = BUS_PCI; + dev->input_id.version = 1; + if (dm1105->pdev->subsystem_vendor) { + dev->input_id.vendor = dm1105->pdev->subsystem_vendor; + dev->input_id.product = dm1105->pdev->subsystem_device; + } else { + dev->input_id.vendor = dm1105->pdev->vendor; + dev->input_id.product = dm1105->pdev->device; + } + dev->dev.parent = &dm1105->pdev->dev; + + INIT_WORK(&dm1105->ir.work, dm1105_emit_key); + + err = rc_register_device(dev); + if (err < 0) { + rc_free_device(dev); + return err; + } + + dm1105->ir.dev = dev; + return 0; +} + +void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105) +{ + rc_unregister_device(dm1105->ir.dev); +} + +static int __devinit dm1105_hw_init(struct dm1105_dev *dev) +{ + dm1105_disable_irqs(dev); + + dm_writeb(DM1105_HOST_CTR, 0); + + /*DATALEN 188,*/ + dm_writeb(DM1105_DTALENTH, 188); + /*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/ + dm_writew(DM1105_TSCTR, 0xc10a); + + /* map DMA and set address */ + dm1105_dma_map(dev); + dm1105_set_dma_addr(dev); + /* big buffer */ + dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES); + dm_writeb(DM1105_INTCNT, 47); + + /* IR NEC mode enable */ + dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK)); + dm_writeb(DM1105_IRMODE, 0); + dm_writew(DM1105_SYSTEMCODE, 0); + + return 0; +} + +static void dm1105_hw_exit(struct dm1105_dev *dev) +{ + dm1105_disable_irqs(dev); + + /* IR disable */ + dm_writeb(DM1105_IRCTR, 0); + dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK); + + dm1105_dma_unmap(dev); +} + +static struct stv0299_config sharp_z0194a_config = { + .demod_address = 0x68, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + +static struct stv0288_config earda_config = { + .demod_address = 0x68, + .min_delay_ms = 100, +}; + +static struct si21xx_config serit_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + +}; + +static struct cx24116_config serit_sp2633_config = { + .demod_address = 0x55, +}; + +static struct ds3000_config dvbworld_ds3000_config = { + .demod_address = 0x68, +}; + +static int __devinit frontend_init(struct dm1105_dev *dev) +{ + int ret; + + switch (dev->boardnr) { + case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO: + dm1105_gpio_enable(dev, GPIO15, 1); + dm1105_gpio_clear(dev, GPIO15); + msleep(100); + dm1105_gpio_set(dev, GPIO15); + msleep(200); + dev->fe = dvb_attach( + stv0299_attach, &sharp_z0194a_config, + &dev->i2c_bb_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + dvb_attach(dvb_pll_attach, dev->fe, 0x60, + &dev->i2c_bb_adap, DVB_PLL_OPERA1); + break; + } + + dev->fe = dvb_attach( + stv0288_attach, &earda_config, + &dev->i2c_bb_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + dvb_attach(stb6000_attach, dev->fe, 0x61, + &dev->i2c_bb_adap); + break; + } + + dev->fe = dvb_attach( + si21xx_attach, &serit_config, + &dev->i2c_bb_adap); + if (dev->fe) + dev->fe->ops.set_voltage = dm1105_set_voltage; + break; + case DM1105_BOARD_DVBWORLD_2004: + dev->fe = dvb_attach( + cx24116_attach, &serit_sp2633_config, + &dev->i2c_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + break; + } + + dev->fe = dvb_attach( + ds3000_attach, &dvbworld_ds3000_config, + &dev->i2c_adap); + if (dev->fe) + dev->fe->ops.set_voltage = dm1105_set_voltage; + + break; + case DM1105_BOARD_DVBWORLD_2002: + case DM1105_BOARD_AXESS_DM05: + default: + dev->fe = dvb_attach( + stv0299_attach, &sharp_z0194a_config, + &dev->i2c_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + dvb_attach(dvb_pll_attach, dev->fe, 0x60, + &dev->i2c_adap, DVB_PLL_OPERA1); + break; + } + + dev->fe = dvb_attach( + stv0288_attach, &earda_config, + &dev->i2c_adap); + if (dev->fe) { + dev->fe->ops.set_voltage = dm1105_set_voltage; + dvb_attach(stb6000_attach, dev->fe, 0x61, + &dev->i2c_adap); + break; + } + + dev->fe = dvb_attach( + si21xx_attach, &serit_config, + &dev->i2c_adap); + if (dev->fe) + dev->fe->ops.set_voltage = dm1105_set_voltage; + + } + + if (!dev->fe) { + dev_err(&dev->pdev->dev, "could not attach frontend\n"); + return -ENODEV; + } + + ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe); + if (ret < 0) { + if (dev->fe->ops.release) + dev->fe->ops.release(dev->fe); + dev->fe = NULL; + return ret; + } + + return 0; +} + +static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac) +{ + static u8 command[1] = { 0x28 }; + + struct i2c_msg msg[] = { + { + .addr = IIC_24C01_addr >> 1, + .flags = 0, + .buf = command, + .len = 1 + }, { + .addr = IIC_24C01_addr >> 1, + .flags = I2C_M_RD, + .buf = mac, + .len = 6 + }, + }; + + dm1105_i2c_xfer(&dev->i2c_adap, msg , 2); + dev_info(&dev->pdev->dev, "MAC %pM\n", mac); +} + +static int __devinit dm1105_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct dm1105_dev *dev; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret = -ENOMEM; + int i; + + dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + /* board config */ + dev->nr = dm1105_devcount; + dev->boardnr = UNSET; + if (card[dev->nr] < ARRAY_SIZE(dm1105_boards)) + dev->boardnr = card[dev->nr]; + for (i = 0; UNSET == dev->boardnr && + i < ARRAY_SIZE(dm1105_subids); i++) + if (pdev->subsystem_vendor == + dm1105_subids[i].subvendor && + pdev->subsystem_device == + dm1105_subids[i].subdevice) + dev->boardnr = dm1105_subids[i].card; + + if (UNSET == dev->boardnr) { + dev->boardnr = DM1105_BOARD_UNKNOWN; + dm1105_card_list(pdev); + } + + dm1105_devcount++; + dev->pdev = pdev; + dev->buffer_size = 5 * DM1105_DMA_BYTES; + dev->PacketErrorCount = 0; + dev->dmarst = 0; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_kfree; + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret < 0) + goto err_pci_disable_device; + + pci_set_master(pdev); + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret < 0) + goto err_pci_disable_device; + + dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); + if (!dev->io_mem) { + ret = -EIO; + goto err_pci_release_regions; + } + + spin_lock_init(&dev->lock); + pci_set_drvdata(pdev, dev); + + ret = dm1105_hw_init(dev); + if (ret < 0) + goto err_pci_iounmap; + + /* i2c */ + i2c_set_adapdata(&dev->i2c_adap, dev); + strcpy(dev->i2c_adap.name, DRIVER_NAME); + dev->i2c_adap.owner = THIS_MODULE; + dev->i2c_adap.dev.parent = &pdev->dev; + dev->i2c_adap.algo = &dm1105_algo; + dev->i2c_adap.algo_data = dev; + ret = i2c_add_adapter(&dev->i2c_adap); + + if (ret < 0) + goto err_dm1105_hw_exit; + + i2c_set_adapdata(&dev->i2c_bb_adap, dev); + strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME); + dev->i2c_bb_adap.owner = THIS_MODULE; + dev->i2c_bb_adap.dev.parent = &pdev->dev; + dev->i2c_bb_adap.algo_data = &dev->i2c_bit; + dev->i2c_bit.data = dev; + dev->i2c_bit.setsda = dm1105_setsda; + dev->i2c_bit.setscl = dm1105_setscl; + dev->i2c_bit.getsda = dm1105_getsda; + dev->i2c_bit.getscl = dm1105_getscl; + dev->i2c_bit.udelay = 10; + dev->i2c_bit.timeout = 10; + + /* Raise SCL and SDA */ + dm1105_setsda(dev, 1); + dm1105_setscl(dev, 1); + + ret = i2c_bit_add_bus(&dev->i2c_bb_adap); + if (ret < 0) + goto err_i2c_del_adapter; + + /* dvb */ + ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME, + THIS_MODULE, &pdev->dev, adapter_nr); + if (ret < 0) + goto err_i2c_del_adapters; + + dvb_adapter = &dev->dvb_adapter; + + dm1105_read_mac(dev, dvb_adapter->proposed_mac); + + dvbdemux = &dev->demux; + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = dm1105_start_feed; + dvbdemux->stop_feed = dm1105_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + dev->dmxdev.filternum = 256; + dev->dmxdev.demux = dmx; + dev->dmxdev.capabilities = 0; + + ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + dev->hw_frontend.source = DMX_FRONTEND_0; + + ret = dmx->add_frontend(dmx, &dev->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + dev->mem_frontend.source = DMX_MEMORY_FE; + + ret = dmx->add_frontend(dmx, &dev->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &dev->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = frontend_init(dev); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &dev->dvbnet, dmx); + dm1105_ir_init(dev); + + INIT_WORK(&dev->work, dm1105_dmx_buffer); + sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num); + dev->wq = create_singlethread_workqueue(dev->wqn); + if (!dev->wq) + goto err_dvb_net; + + ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED, + DRIVER_NAME, dev); + if (ret < 0) + goto err_workqueue; + + return 0; + +err_workqueue: + destroy_workqueue(dev->wq); +err_dvb_net: + dvb_net_release(&dev->dvbnet); +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &dev->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &dev->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&dev->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_i2c_del_adapters: + i2c_del_adapter(&dev->i2c_bb_adap); +err_i2c_del_adapter: + i2c_del_adapter(&dev->i2c_adap); +err_dm1105_hw_exit: + dm1105_hw_exit(dev); +err_pci_iounmap: + pci_iounmap(pdev, dev->io_mem); +err_pci_release_regions: + pci_release_regions(pdev); +err_pci_disable_device: + pci_disable_device(pdev); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(dev); + return ret; +} + +static void __devexit dm1105_remove(struct pci_dev *pdev) +{ + struct dm1105_dev *dev = pci_get_drvdata(pdev); + struct dvb_adapter *dvb_adapter = &dev->dvb_adapter; + struct dvb_demux *dvbdemux = &dev->demux; + struct dmx_demux *dmx = &dvbdemux->dmx; + + dm1105_ir_exit(dev); + dmx->close(dmx); + dvb_net_release(&dev->dvbnet); + if (dev->fe) + dvb_unregister_frontend(dev->fe); + + dmx->disconnect_frontend(dmx); + dmx->remove_frontend(dmx, &dev->mem_frontend); + dmx->remove_frontend(dmx, &dev->hw_frontend); + dvb_dmxdev_release(&dev->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_adapter(dvb_adapter); + if (&dev->i2c_adap) + i2c_del_adapter(&dev->i2c_adap); + + dm1105_hw_exit(dev); + synchronize_irq(pdev->irq); + free_irq(pdev->irq, dev); + pci_iounmap(pdev, dev->io_mem); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + dm1105_devcount--; + kfree(dev); +} + +static struct pci_device_id dm1105_id_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_TRIGEM, + .device = PCI_DEVICE_ID_DM1105, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + .vendor = PCI_VENDOR_ID_AXESS, + .device = PCI_DEVICE_ID_DM05, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + /* empty */ + }, +}; + +MODULE_DEVICE_TABLE(pci, dm1105_id_table); + +static struct pci_driver dm1105_driver = { + .name = DRIVER_NAME, + .id_table = dm1105_id_table, + .probe = dm1105_probe, + .remove = __devexit_p(dm1105_remove), +}; + +static int __init dm1105_init(void) +{ + return pci_register_driver(&dm1105_driver); +} + +static void __exit dm1105_exit(void) +{ + pci_unregister_driver(&dm1105_driver); +} + +module_init(dm1105_init); +module_exit(dm1105_exit); + +MODULE_AUTHOR("Igor M. Liplianin "); +MODULE_DESCRIPTION("SDMC DM1105 DVB driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,20 @@ +config DVB_DM1105 + tristate "SDMC DM1105 based PCI cards" + depends on DVB_CORE && PCI && I2C + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_SI21XX if !DVB_FE_CUSTOMISE + select DVB_DS3000 if !DVB_FE_CUSTOMISE + depends on RC_CORE + help + Support for cards based on the SDMC DM1105 PCI chip like + DvbWorld 2002 + + Since these cards have no MPEG decoder onboard, they transmit + only compressed MPEG data over the PCI bus, so you need + an external software decoder to watch TV on your computer. + + Say Y or M if you own such a device and want to use it. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dm1105/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_DM1105) += dm1105.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/demux.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/demux.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/demux.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/demux.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,280 @@ +/* + * demux.h + * + * Copyright (c) 2002 Convergence GmbH + * + * based on code: + * Copyright (c) 2000 Nokia Research Center + * Tampere, FINLAND + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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. + * + */ + +#ifndef __DEMUX_H +#define __DEMUX_H + +#include +#include +#include +#include +#include + +/*--------------------------------------------------------------------------*/ +/* Common definitions */ +/*--------------------------------------------------------------------------*/ + +/* + * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter. + */ + +#ifndef DMX_MAX_FILTER_SIZE +#define DMX_MAX_FILTER_SIZE 18 +#endif + +/* + * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter. + */ + +#ifndef DMX_MAX_SECTION_SIZE +#define DMX_MAX_SECTION_SIZE 4096 +#endif +#ifndef DMX_MAX_SECFEED_SIZE +#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188) +#endif + + +/* + * enum dmx_success: Success codes for the Demux Callback API. + */ + +enum dmx_success { + DMX_OK = 0, /* Received Ok */ + DMX_LENGTH_ERROR, /* Incorrect length */ + DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */ + DMX_CRC_ERROR, /* Incorrect CRC */ + DMX_FRAME_ERROR, /* Frame alignment error */ + DMX_FIFO_ERROR, /* Receiver FIFO overrun */ + DMX_MISSED_ERROR /* Receiver missed packet */ +} ; + +/*--------------------------------------------------------------------------*/ +/* TS packet reception */ +/*--------------------------------------------------------------------------*/ + +/* TS filter type for set() */ + +#define TS_PACKET 1 /* send TS packets (188 bytes) to callback (default) */ +#define TS_PAYLOAD_ONLY 2 /* in case TS_PACKET is set, only send the TS + payload (<=184 bytes per packet) to callback */ +#define TS_DECODER 4 /* send stream to built-in decoder (if present) */ +#define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to + the demux device, not to the dvr device */ + +/* PES type for filters which write to built-in decoder */ +/* these should be kept identical to the types in dmx.h */ + +enum dmx_ts_pes +{ /* also send packets to decoder (if it exists) */ + DMX_TS_PES_AUDIO0, + DMX_TS_PES_VIDEO0, + DMX_TS_PES_TELETEXT0, + DMX_TS_PES_SUBTITLE0, + DMX_TS_PES_PCR0, + + DMX_TS_PES_AUDIO1, + DMX_TS_PES_VIDEO1, + DMX_TS_PES_TELETEXT1, + DMX_TS_PES_SUBTITLE1, + DMX_TS_PES_PCR1, + + DMX_TS_PES_AUDIO2, + DMX_TS_PES_VIDEO2, + DMX_TS_PES_TELETEXT2, + DMX_TS_PES_SUBTITLE2, + DMX_TS_PES_PCR2, + + DMX_TS_PES_AUDIO3, + DMX_TS_PES_VIDEO3, + DMX_TS_PES_TELETEXT3, + DMX_TS_PES_SUBTITLE3, + DMX_TS_PES_PCR3, + + DMX_TS_PES_OTHER +}; + +#define DMX_TS_PES_AUDIO DMX_TS_PES_AUDIO0 +#define DMX_TS_PES_VIDEO DMX_TS_PES_VIDEO0 +#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0 +#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0 +#define DMX_TS_PES_PCR DMX_TS_PES_PCR0 + + +struct dmx_ts_feed { + int is_filtering; /* Set to non-zero when filtering in progress */ + struct dmx_demux *parent; /* Back-pointer */ + void *priv; /* Pointer to private data of the API client */ + int (*set) (struct dmx_ts_feed *feed, + u16 pid, + int type, + enum dmx_ts_pes pes_type, + size_t circular_buffer_size, + struct timespec timeout); + int (*start_filtering) (struct dmx_ts_feed* feed); + int (*stop_filtering) (struct dmx_ts_feed* feed); +}; + +/*--------------------------------------------------------------------------*/ +/* Section reception */ +/*--------------------------------------------------------------------------*/ + +struct dmx_section_filter { + u8 filter_value [DMX_MAX_FILTER_SIZE]; + u8 filter_mask [DMX_MAX_FILTER_SIZE]; + u8 filter_mode [DMX_MAX_FILTER_SIZE]; + struct dmx_section_feed* parent; /* Back-pointer */ + void* priv; /* Pointer to private data of the API client */ +}; + +struct dmx_section_feed { + int is_filtering; /* Set to non-zero when filtering in progress */ + struct dmx_demux* parent; /* Back-pointer */ + void* priv; /* Pointer to private data of the API client */ + + int check_crc; + u32 crc_val; + + u8 *secbuf; + u8 secbuf_base[DMX_MAX_SECFEED_SIZE]; + u16 secbufp, seclen, tsfeedp; + + int (*set) (struct dmx_section_feed* feed, + u16 pid, + size_t circular_buffer_size, + int check_crc); + int (*allocate_filter) (struct dmx_section_feed* feed, + struct dmx_section_filter** filter); + int (*release_filter) (struct dmx_section_feed* feed, + struct dmx_section_filter* filter); + int (*start_filtering) (struct dmx_section_feed* feed); + int (*stop_filtering) (struct dmx_section_feed* feed); +}; + +/*--------------------------------------------------------------------------*/ +/* Callback functions */ +/*--------------------------------------------------------------------------*/ + +typedef int (*dmx_ts_cb) ( const u8 * buffer1, + size_t buffer1_length, + const u8 * buffer2, + size_t buffer2_length, + struct dmx_ts_feed* source, + enum dmx_success success); + +typedef int (*dmx_section_cb) ( const u8 * buffer1, + size_t buffer1_len, + const u8 * buffer2, + size_t buffer2_len, + struct dmx_section_filter * source, + enum dmx_success success); + +/*--------------------------------------------------------------------------*/ +/* DVB Front-End */ +/*--------------------------------------------------------------------------*/ + +enum dmx_frontend_source { + DMX_MEMORY_FE, + DMX_FRONTEND_0, + DMX_FRONTEND_1, + DMX_FRONTEND_2, + DMX_FRONTEND_3, + DMX_STREAM_0, /* external stream input, e.g. LVDS */ + DMX_STREAM_1, + DMX_STREAM_2, + DMX_STREAM_3 +}; + +struct dmx_frontend { + struct list_head connectivity_list; /* List of front-ends that can + be connected to a particular + demux */ + enum dmx_frontend_source source; +}; + +/*--------------------------------------------------------------------------*/ +/* MPEG-2 TS Demux */ +/*--------------------------------------------------------------------------*/ + +/* + * Flags OR'ed in the capabilities field of struct dmx_demux. + */ + +#define DMX_TS_FILTERING 1 +#define DMX_PES_FILTERING 2 +#define DMX_SECTION_FILTERING 4 +#define DMX_MEMORY_BASED_FILTERING 8 /* write() available */ +#define DMX_CRC_CHECKING 16 +#define DMX_TS_DESCRAMBLING 32 + +/* + * Demux resource type identifier. +*/ + +/* + * DMX_FE_ENTRY(): Casts elements in the list of registered + * front-ends from the generic type struct list_head + * to the type * struct dmx_frontend + *. +*/ + +#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list) + +struct dmx_demux { + u32 capabilities; /* Bitfield of capability flags */ + struct dmx_frontend* frontend; /* Front-end connected to the demux */ + void* priv; /* Pointer to private data of the API client */ + int (*open) (struct dmx_demux* demux); + int (*close) (struct dmx_demux* demux); + int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count); + int (*allocate_ts_feed) (struct dmx_demux* demux, + struct dmx_ts_feed** feed, + dmx_ts_cb callback); + int (*release_ts_feed) (struct dmx_demux* demux, + struct dmx_ts_feed* feed); + int (*allocate_section_feed) (struct dmx_demux* demux, + struct dmx_section_feed** feed, + dmx_section_cb callback); + int (*release_section_feed) (struct dmx_demux* demux, + struct dmx_section_feed* feed); + int (*add_frontend) (struct dmx_demux* demux, + struct dmx_frontend* frontend); + int (*remove_frontend) (struct dmx_demux* demux, + struct dmx_frontend* frontend); + struct list_head* (*get_frontends) (struct dmx_demux* demux); + int (*connect_frontend) (struct dmx_demux* demux, + struct dmx_frontend* frontend); + int (*disconnect_frontend) (struct dmx_demux* demux); + + int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids); + + int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps); + + int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src); + + int (*get_stc) (struct dmx_demux* demux, unsigned int num, + u64 *stc, unsigned int *base); +}; + +#endif /* #ifndef __DEMUX_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dmxdev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dmxdev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dmxdev.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dmxdev.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1278 @@ +/* + * dmxdev.c - DVB demultiplexer device + * + * Copyright (C) 2000 Ralph Metzler & Marcus Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dmxdev.h" + +static int debug; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk if (debug) printk + +static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, + const u8 *src, size_t len) +{ + ssize_t free; + + if (!len) + return 0; + if (!buf->data) + return 0; + + free = dvb_ringbuffer_free(buf); + if (len > free) { + dprintk("dmxdev: buffer overflow\n"); + return -EOVERFLOW; + } + + return dvb_ringbuffer_write(buf, src, len); +} + +static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, + int non_blocking, char __user *buf, + size_t count, loff_t *ppos) +{ + size_t todo; + ssize_t avail; + ssize_t ret = 0; + + if (!src->data) + return 0; + + if (src->error) { + ret = src->error; + dvb_ringbuffer_flush(src); + return ret; + } + + for (todo = count; todo > 0; todo -= ret) { + if (non_blocking && dvb_ringbuffer_empty(src)) { + ret = -EWOULDBLOCK; + break; + } + + ret = wait_event_interruptible(src->queue, + !dvb_ringbuffer_empty(src) || + (src->error != 0)); + if (ret < 0) + break; + + if (src->error) { + ret = src->error; + dvb_ringbuffer_flush(src); + break; + } + + avail = dvb_ringbuffer_avail(src); + if (avail > todo) + avail = todo; + + ret = dvb_ringbuffer_read_user(src, buf, avail); + if (ret < 0) + break; + + buf += ret; + } + + return (count - todo) ? (count - todo) : ret; +} + +static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type) +{ + struct list_head *head, *pos; + + head = demux->get_frontends(demux); + if (!head) + return NULL; + list_for_each(pos, head) + if (DMX_FE_ENTRY(pos)->source == type) + return DMX_FE_ENTRY(pos); + + return NULL; +} + +static int dvb_dvr_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + struct dmx_frontend *front; + + dprintk("function : %s\n", __func__); + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if (dmxdev->exit) { + mutex_unlock(&dmxdev->mutex); + return -ENODEV; + } + + if ((file->f_flags & O_ACCMODE) == O_RDWR) { + if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { + mutex_unlock(&dmxdev->mutex); + return -EOPNOTSUPP; + } + } + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + void *mem; + if (!dvbdev->readers) { + mutex_unlock(&dmxdev->mutex); + return -EBUSY; + } + mem = vmalloc(DVR_BUFFER_SIZE); + if (!mem) { + mutex_unlock(&dmxdev->mutex); + return -ENOMEM; + } + dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); + dvbdev->readers--; + } + + if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + dmxdev->dvr_orig_fe = dmxdev->demux->frontend; + + if (!dmxdev->demux->write) { + mutex_unlock(&dmxdev->mutex); + return -EOPNOTSUPP; + } + + front = get_fe(dmxdev->demux, DMX_MEMORY_FE); + + if (!front) { + mutex_unlock(&dmxdev->mutex); + return -EINVAL; + } + dmxdev->demux->disconnect_frontend(dmxdev->demux); + dmxdev->demux->connect_frontend(dmxdev->demux, front); + } + dvbdev->users++; + mutex_unlock(&dmxdev->mutex); + return 0; +} + +static int dvb_dvr_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + + mutex_lock(&dmxdev->mutex); + + if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + dmxdev->demux->disconnect_frontend(dmxdev->demux); + dmxdev->demux->connect_frontend(dmxdev->demux, + dmxdev->dvr_orig_fe); + } + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + dvbdev->readers++; + if (dmxdev->dvr_buffer.data) { + void *mem = dmxdev->dvr_buffer.data; + mb(); + spin_lock_irq(&dmxdev->lock); + dmxdev->dvr_buffer.data = NULL; + spin_unlock_irq(&dmxdev->lock); + vfree(mem); + } + } + /* TODO */ + dvbdev->users--; + if (dvbdev->users == 1 && dmxdev->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; + mutex_unlock(&dmxdev->mutex); + wake_up(&dvbdev->wait_queue); + } else + mutex_unlock(&dmxdev->mutex); + + return 0; +} + +static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + int ret; + + if (!dmxdev->demux->write) + return -EOPNOTSUPP; + if ((file->f_flags & O_ACCMODE) != O_WRONLY) + return -EINVAL; + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if (dmxdev->exit) { + mutex_unlock(&dmxdev->mutex); + return -ENODEV; + } + ret = dmxdev->demux->write(dmxdev->demux, buf, count); + mutex_unlock(&dmxdev->mutex); + return ret; +} + +static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + + if (dmxdev->exit) + return -ENODEV; + + return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); +} + +static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, + unsigned long size) +{ + struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer; + void *newmem; + void *oldmem; + + dprintk("function : %s\n", __func__); + + if (buf->size == size) + return 0; + if (!size) + return -EINVAL; + + newmem = vmalloc(size); + if (!newmem) + return -ENOMEM; + + oldmem = buf->data; + + spin_lock_irq(&dmxdev->lock); + buf->data = newmem; + buf->size = size; + + /* reset and not flush in case the buffer shrinks */ + dvb_ringbuffer_reset(buf); + spin_unlock_irq(&dmxdev->lock); + + vfree(oldmem); + + return 0; +} + +static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter + *dmxdevfilter, int state) +{ + spin_lock_irq(&dmxdevfilter->dev->lock); + dmxdevfilter->state = state; + spin_unlock_irq(&dmxdevfilter->dev->lock); +} + +static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, + unsigned long size) +{ + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; + void *newmem; + void *oldmem; + + if (buf->size == size) + return 0; + if (!size) + return -EINVAL; + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + newmem = vmalloc(size); + if (!newmem) + return -ENOMEM; + + oldmem = buf->data; + + spin_lock_irq(&dmxdevfilter->dev->lock); + buf->data = newmem; + buf->size = size; + + /* reset and not flush in case the buffer shrinks */ + dvb_ringbuffer_reset(buf); + spin_unlock_irq(&dmxdevfilter->dev->lock); + + vfree(oldmem); + + return 0; +} + +static void dvb_dmxdev_filter_timeout(unsigned long data) +{ + struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; + + dmxdevfilter->buffer.error = -ETIMEDOUT; + spin_lock_irq(&dmxdevfilter->dev->lock); + dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; + spin_unlock_irq(&dmxdevfilter->dev->lock); + wake_up(&dmxdevfilter->buffer.queue); +} + +static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) +{ + struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec; + + del_timer(&dmxdevfilter->timer); + if (para->timeout) { + dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout; + dmxdevfilter->timer.data = (unsigned long)dmxdevfilter; + dmxdevfilter->timer.expires = + jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; + add_timer(&dmxdevfilter->timer); + } +} + +static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, + struct dmx_section_filter *filter, + enum dmx_success success) +{ + struct dmxdev_filter *dmxdevfilter = filter->priv; + int ret; + + if (dmxdevfilter->buffer.error) { + wake_up(&dmxdevfilter->buffer.queue); + return 0; + } + spin_lock(&dmxdevfilter->dev->lock); + if (dmxdevfilter->state != DMXDEV_STATE_GO) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + del_timer(&dmxdevfilter->timer); + dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n", + buffer1[0], buffer1[1], + buffer1[2], buffer1[3], buffer1[4], buffer1[5]); + ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, + buffer1_len); + if (ret == buffer1_len) { + ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, + buffer2_len); + } + if (ret < 0) { + dvb_ringbuffer_flush(&dmxdevfilter->buffer); + dmxdevfilter->buffer.error = ret; + } + if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) + dmxdevfilter->state = DMXDEV_STATE_DONE; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up(&dmxdevfilter->buffer.queue); + return 0; +} + +static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, + struct dmx_ts_feed *feed, + enum dmx_success success) +{ + struct dmxdev_filter *dmxdevfilter = feed->priv; + struct dvb_ringbuffer *buffer; + int ret; + + spin_lock(&dmxdevfilter->dev->lock); + if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + if (dmxdevfilter->params.pes.output == DMX_OUT_TAP + || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) + buffer = &dmxdevfilter->buffer; + else + buffer = &dmxdevfilter->dev->dvr_buffer; + if (buffer->error) { + spin_unlock(&dmxdevfilter->dev->lock); + wake_up(&buffer->queue); + return 0; + } + ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); + if (ret == buffer1_len) + ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); + if (ret < 0) { + dvb_ringbuffer_flush(buffer); + buffer->error = ret; + } + spin_unlock(&dmxdevfilter->dev->lock); + wake_up(&buffer->queue); + return 0; +} + +/* stop feed but only mark the specified filter as stopped (state set) */ +static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) +{ + struct dmxdev_feed *feed; + + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); + + switch (dmxdevfilter->type) { + case DMXDEV_TYPE_SEC: + del_timer(&dmxdevfilter->timer); + dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); + break; + case DMXDEV_TYPE_PES: + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) + feed->ts->stop_filtering(feed->ts); + break; + default: + return -EINVAL; + } + return 0; +} + +/* start feed associated with the specified filter */ +static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) +{ + struct dmxdev_feed *feed; + int ret; + + dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); + + switch (filter->type) { + case DMXDEV_TYPE_SEC: + return filter->feed.sec->start_filtering(filter->feed.sec); + case DMXDEV_TYPE_PES: + list_for_each_entry(feed, &filter->feed.ts, next) { + ret = feed->ts->start_filtering(feed->ts); + if (ret < 0) { + dvb_dmxdev_feed_stop(filter); + return ret; + } + } + break; + default: + return -EINVAL; + } + + return 0; +} + +/* restart section feed if it has filters left associated with it, + otherwise release the feed */ +static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) +{ + int i; + struct dmxdev *dmxdev = filter->dev; + u16 pid = filter->params.sec.pid; + + for (i = 0; i < dmxdev->filternum; i++) + if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && + dmxdev->filter[i].type == DMXDEV_TYPE_SEC && + dmxdev->filter[i].params.sec.pid == pid) { + dvb_dmxdev_feed_start(&dmxdev->filter[i]); + return 0; + } + + filter->dev->demux->release_section_feed(dmxdev->demux, + filter->feed.sec); + + return 0; +} + +static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) +{ + struct dmxdev_feed *feed; + struct dmx_demux *demux; + + if (dmxdevfilter->state < DMXDEV_STATE_GO) + return 0; + + switch (dmxdevfilter->type) { + case DMXDEV_TYPE_SEC: + if (!dmxdevfilter->feed.sec) + break; + dvb_dmxdev_feed_stop(dmxdevfilter); + if (dmxdevfilter->filter.sec) + dmxdevfilter->feed.sec-> + release_filter(dmxdevfilter->feed.sec, + dmxdevfilter->filter.sec); + dvb_dmxdev_feed_restart(dmxdevfilter); + dmxdevfilter->feed.sec = NULL; + break; + case DMXDEV_TYPE_PES: + dvb_dmxdev_feed_stop(dmxdevfilter); + demux = dmxdevfilter->dev->demux; + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { + demux->release_ts_feed(demux, feed->ts); + feed->ts = NULL; + } + break; + default: + if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) + return 0; + return -EINVAL; + } + + dvb_ringbuffer_flush(&dmxdevfilter->buffer); + return 0; +} + +static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter) +{ + struct dmxdev_feed *feed, *tmp; + + /* delete all PIDs */ + list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) { + list_del(&feed->next); + kfree(feed); + } + + BUG_ON(!list_empty(&dmxdevfilter->feed.ts)); +} + +static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) +{ + if (dmxdevfilter->state < DMXDEV_STATE_SET) + return 0; + + if (dmxdevfilter->type == DMXDEV_TYPE_PES) + dvb_dmxdev_delete_pids(dmxdevfilter); + + dmxdevfilter->type = DMXDEV_TYPE_NONE; + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); + return 0; +} + +static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, + struct dmxdev_feed *feed) +{ + struct timespec timeout = { 0 }; + struct dmx_pes_filter_params *para = &filter->params.pes; + dmx_output_t otype; + int ret; + int ts_type; + dmx_pes_type_t ts_pes; + struct dmx_ts_feed *tsfeed; + + feed->ts = NULL; + otype = para->output; + + ts_pes = para->pes_type; + + if (ts_pes < DMX_PES_OTHER) + ts_type = TS_DECODER; + else + ts_type = 0; + + if (otype == DMX_OUT_TS_TAP) + ts_type |= TS_PACKET; + else if (otype == DMX_OUT_TSDEMUX_TAP) + ts_type |= TS_PACKET | TS_DEMUX; + else if (otype == DMX_OUT_TAP) + ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY; + + ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts, + dvb_dmxdev_ts_callback); + if (ret < 0) + return ret; + + tsfeed = feed->ts; + tsfeed->priv = filter; + + ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout); + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); + return ret; + } + + ret = tsfeed->start_filtering(tsfeed); + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); + return ret; + } + + return 0; +} + +static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) +{ + struct dmxdev *dmxdev = filter->dev; + struct dmxdev_feed *feed; + void *mem; + int ret, i; + + if (filter->state < DMXDEV_STATE_SET) + return -EINVAL; + + if (filter->state >= DMXDEV_STATE_GO) + dvb_dmxdev_filter_stop(filter); + + if (!filter->buffer.data) { + mem = vmalloc(filter->buffer.size); + if (!mem) + return -ENOMEM; + spin_lock_irq(&filter->dev->lock); + filter->buffer.data = mem; + spin_unlock_irq(&filter->dev->lock); + } + + dvb_ringbuffer_flush(&filter->buffer); + + switch (filter->type) { + case DMXDEV_TYPE_SEC: + { + struct dmx_sct_filter_params *para = &filter->params.sec; + struct dmx_section_filter **secfilter = &filter->filter.sec; + struct dmx_section_feed **secfeed = &filter->feed.sec; + + *secfilter = NULL; + *secfeed = NULL; + + + /* find active filter/feed with same PID */ + for (i = 0; i < dmxdev->filternum; i++) { + if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && + dmxdev->filter[i].type == DMXDEV_TYPE_SEC && + dmxdev->filter[i].params.sec.pid == para->pid) { + *secfeed = dmxdev->filter[i].feed.sec; + break; + } + } + + /* if no feed found, try to allocate new one */ + if (!*secfeed) { + ret = dmxdev->demux->allocate_section_feed(dmxdev->demux, + secfeed, + dvb_dmxdev_section_callback); + if (ret < 0) { + printk("DVB (%s): could not alloc feed\n", + __func__); + return ret; + } + + ret = (*secfeed)->set(*secfeed, para->pid, 32768, + (para->flags & DMX_CHECK_CRC) ? 1 : 0); + if (ret < 0) { + printk("DVB (%s): could not set feed\n", + __func__); + dvb_dmxdev_feed_restart(filter); + return ret; + } + } else { + dvb_dmxdev_feed_stop(filter); + } + + ret = (*secfeed)->allocate_filter(*secfeed, secfilter); + if (ret < 0) { + dvb_dmxdev_feed_restart(filter); + filter->feed.sec->start_filtering(*secfeed); + dprintk("could not get filter\n"); + return ret; + } + + (*secfilter)->priv = filter; + + memcpy(&((*secfilter)->filter_value[3]), + &(para->filter.filter[1]), DMX_FILTER_SIZE - 1); + memcpy(&(*secfilter)->filter_mask[3], + ¶->filter.mask[1], DMX_FILTER_SIZE - 1); + memcpy(&(*secfilter)->filter_mode[3], + ¶->filter.mode[1], DMX_FILTER_SIZE - 1); + + (*secfilter)->filter_value[0] = para->filter.filter[0]; + (*secfilter)->filter_mask[0] = para->filter.mask[0]; + (*secfilter)->filter_mode[0] = para->filter.mode[0]; + (*secfilter)->filter_mask[1] = 0; + (*secfilter)->filter_mask[2] = 0; + + filter->todo = 0; + + ret = filter->feed.sec->start_filtering(filter->feed.sec); + if (ret < 0) + return ret; + + dvb_dmxdev_filter_timer(filter); + break; + } + case DMXDEV_TYPE_PES: + list_for_each_entry(feed, &filter->feed.ts, next) { + ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); + if (ret < 0) { + dvb_dmxdev_filter_stop(filter); + return ret; + } + } + break; + default: + return -EINVAL; + } + + dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); + return 0; +} + +static int dvb_demux_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + int i; + struct dmxdev_filter *dmxdevfilter; + + if (!dmxdev->filter) + return -EINVAL; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + for (i = 0; i < dmxdev->filternum; i++) + if (dmxdev->filter[i].state == DMXDEV_STATE_FREE) + break; + + if (i == dmxdev->filternum) { + mutex_unlock(&dmxdev->mutex); + return -EMFILE; + } + + dmxdevfilter = &dmxdev->filter[i]; + mutex_init(&dmxdevfilter->mutex); + file->private_data = dmxdevfilter; + + dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); + dmxdevfilter->type = DMXDEV_TYPE_NONE; + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); + init_timer(&dmxdevfilter->timer); + + dvbdev->users++; + + mutex_unlock(&dmxdev->mutex); + return 0; +} + +static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, + struct dmxdev_filter *dmxdevfilter) +{ + mutex_lock(&dmxdev->mutex); + mutex_lock(&dmxdevfilter->mutex); + + dvb_dmxdev_filter_stop(dmxdevfilter); + dvb_dmxdev_filter_reset(dmxdevfilter); + + if (dmxdevfilter->buffer.data) { + void *mem = dmxdevfilter->buffer.data; + + spin_lock_irq(&dmxdev->lock); + dmxdevfilter->buffer.data = NULL; + spin_unlock_irq(&dmxdev->lock); + vfree(mem); + } + + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); + wake_up(&dmxdevfilter->buffer.queue); + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + return 0; +} + +static inline void invert_mode(dmx_filter_t *filter) +{ + int i; + + for (i = 0; i < DMX_FILTER_SIZE; i++) + filter->mode[i] ^= 0xff; +} + +static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, u16 pid) +{ + struct dmxdev_feed *feed; + + if ((filter->type != DMXDEV_TYPE_PES) || + (filter->state < DMXDEV_STATE_SET)) + return -EINVAL; + + /* only TS packet filters may have multiple PIDs */ + if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) && + (!list_empty(&filter->feed.ts))) + return -EINVAL; + + feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL); + if (feed == NULL) + return -ENOMEM; + + feed->pid = pid; + list_add(&feed->next, &filter->feed.ts); + + if (filter->state >= DMXDEV_STATE_GO) + return dvb_dmxdev_start_feed(dmxdev, filter, feed); + + return 0; +} + +static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, u16 pid) +{ + struct dmxdev_feed *feed, *tmp; + + if ((filter->type != DMXDEV_TYPE_PES) || + (filter->state < DMXDEV_STATE_SET)) + return -EINVAL; + + list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) { + if ((feed->pid == pid) && (feed->ts != NULL)) { + feed->ts->stop_filtering(feed->ts); + filter->dev->demux->release_ts_feed(filter->dev->demux, + feed->ts); + list_del(&feed->next); + kfree(feed); + } + } + + return 0; +} + +static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, + struct dmxdev_filter *dmxdevfilter, + struct dmx_sct_filter_params *params) +{ + dprintk("function : %s\n", __func__); + + dvb_dmxdev_filter_stop(dmxdevfilter); + + dmxdevfilter->type = DMXDEV_TYPE_SEC; + memcpy(&dmxdevfilter->params.sec, + params, sizeof(struct dmx_sct_filter_params)); + invert_mode(&dmxdevfilter->params.sec.filter); + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); + + if (params->flags & DMX_IMMEDIATE_START) + return dvb_dmxdev_filter_start(dmxdevfilter); + + return 0; +} + +static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, + struct dmxdev_filter *dmxdevfilter, + struct dmx_pes_filter_params *params) +{ + int ret; + + dvb_dmxdev_filter_stop(dmxdevfilter); + dvb_dmxdev_filter_reset(dmxdevfilter); + + if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0) + return -EINVAL; + + dmxdevfilter->type = DMXDEV_TYPE_PES; + memcpy(&dmxdevfilter->params, params, + sizeof(struct dmx_pes_filter_params)); + INIT_LIST_HEAD(&dmxdevfilter->feed.ts); + + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); + + ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, + dmxdevfilter->params.pes.pid); + if (ret < 0) + return ret; + + if (params->flags & DMX_IMMEDIATE_START) + return dvb_dmxdev_filter_start(dmxdevfilter); + + return 0; +} + +static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, + struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int result, hcount; + int done = 0; + + if (dfil->todo <= 0) { + hcount = 3 + dfil->todo; + if (hcount > count) + hcount = count; + result = dvb_dmxdev_buffer_read(&dfil->buffer, + file->f_flags & O_NONBLOCK, + buf, hcount, ppos); + if (result < 0) { + dfil->todo = 0; + return result; + } + if (copy_from_user(dfil->secheader - dfil->todo, buf, result)) + return -EFAULT; + buf += result; + done = result; + count -= result; + dfil->todo -= result; + if (dfil->todo > -3) + return done; + dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff; + if (!count) + return done; + } + if (count > dfil->todo) + count = dfil->todo; + result = dvb_dmxdev_buffer_read(&dfil->buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); + if (result < 0) + return result; + dfil->todo -= result; + return (result + done); +} + +static ssize_t +dvb_demux_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + struct dmxdev_filter *dmxdevfilter = file->private_data; + int ret; + + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) + return -ERESTARTSYS; + + if (dmxdevfilter->type == DMXDEV_TYPE_SEC) + ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); + else + ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); + + mutex_unlock(&dmxdevfilter->mutex); + return ret; +} + +static int dvb_demux_do_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dmxdev_filter *dmxdevfilter = file->private_data; + struct dmxdev *dmxdev = dmxdevfilter->dev; + unsigned long arg = (unsigned long)parg; + int ret = 0; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + switch (cmd) { + case DMX_START: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + if (dmxdevfilter->state < DMXDEV_STATE_SET) + ret = -EINVAL; + else + ret = dvb_dmxdev_filter_start(dmxdevfilter); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_STOP: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_filter_stop(dmxdevfilter); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_FILTER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_PES_FILTER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_BUFFER_SIZE: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_GET_PES_PIDS: + if (!dmxdev->demux->get_pes_pids) { + ret = -EINVAL; + break; + } + dmxdev->demux->get_pes_pids(dmxdev->demux, parg); + break; + + case DMX_GET_CAPS: + if (!dmxdev->demux->get_caps) { + ret = -EINVAL; + break; + } + ret = dmxdev->demux->get_caps(dmxdev->demux, parg); + break; + + case DMX_SET_SOURCE: + if (!dmxdev->demux->set_source) { + ret = -EINVAL; + break; + } + ret = dmxdev->demux->set_source(dmxdev->demux, parg); + break; + + case DMX_GET_STC: + if (!dmxdev->demux->get_stc) { + ret = -EINVAL; + break; + } + ret = dmxdev->demux->get_stc(dmxdev->demux, + ((struct dmx_stc *)parg)->num, + &((struct dmx_stc *)parg)->stc, + &((struct dmx_stc *)parg)->base); + break; + + case DMX_ADD_PID: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_REMOVE_PID: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + default: + ret = -EINVAL; + break; + } + mutex_unlock(&dmxdev->mutex); + return ret; +} + +static long dvb_demux_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); +} + +static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) +{ + struct dmxdev_filter *dmxdevfilter = file->private_data; + unsigned int mask = 0; + + if (!dmxdevfilter) + return -EINVAL; + + poll_wait(file, &dmxdevfilter->buffer.queue, wait); + + if (dmxdevfilter->state != DMXDEV_STATE_GO && + dmxdevfilter->state != DMXDEV_STATE_DONE && + dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) + return 0; + + if (dmxdevfilter->buffer.error) + mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); + + if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) + mask |= (POLLIN | POLLRDNORM | POLLPRI); + + return mask; +} + +static int dvb_demux_release(struct inode *inode, struct file *file) +{ + struct dmxdev_filter *dmxdevfilter = file->private_data; + struct dmxdev *dmxdev = dmxdevfilter->dev; + + int ret; + + ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); + + mutex_lock(&dmxdev->mutex); + dmxdev->dvbdev->users--; + if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) { + fops_put(file->f_op); + file->f_op = NULL; + mutex_unlock(&dmxdev->mutex); + wake_up(&dmxdev->dvbdev->wait_queue); + } else + mutex_unlock(&dmxdev->mutex); + + return ret; +} + +static const struct file_operations dvb_demux_fops = { + .owner = THIS_MODULE, + .read = dvb_demux_read, + .unlocked_ioctl = dvb_demux_ioctl, + .open = dvb_demux_open, + .release = dvb_demux_release, + .poll = dvb_demux_poll, + .llseek = default_llseek, +}; + +static struct dvb_device dvbdev_demux = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_demux_fops +}; + +static int dvb_dvr_do_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + unsigned long arg = (unsigned long)parg; + int ret; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + switch (cmd) { + case DMX_SET_BUFFER_SIZE: + ret = dvb_dvr_set_buffer_size(dmxdev, arg); + break; + + default: + ret = -EINVAL; + break; + } + mutex_unlock(&dmxdev->mutex); + return ret; +} + +static long dvb_dvr_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); +} + +static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + unsigned int mask = 0; + + dprintk("function : %s\n", __func__); + + poll_wait(file, &dmxdev->dvr_buffer.queue, wait); + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (dmxdev->dvr_buffer.error) + mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); + + if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) + mask |= (POLLIN | POLLRDNORM | POLLPRI); + } else + mask |= (POLLOUT | POLLWRNORM | POLLPRI); + + return mask; +} + +static const struct file_operations dvb_dvr_fops = { + .owner = THIS_MODULE, + .read = dvb_dvr_read, + .write = dvb_dvr_write, + .unlocked_ioctl = dvb_dvr_ioctl, + .open = dvb_dvr_open, + .release = dvb_dvr_release, + .poll = dvb_dvr_poll, + .llseek = default_llseek, +}; + +static struct dvb_device dvbdev_dvr = { + .priv = NULL, + .readers = 1, + .users = 1, + .fops = &dvb_dvr_fops +}; + +int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) +{ + int i; + + if (dmxdev->demux->open(dmxdev->demux) < 0) + return -EUSERS; + + dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter)); + if (!dmxdev->filter) + return -ENOMEM; + + mutex_init(&dmxdev->mutex); + spin_lock_init(&dmxdev->lock); + for (i = 0; i < dmxdev->filternum; i++) { + dmxdev->filter[i].dev = dmxdev; + dmxdev->filter[i].buffer.data = NULL; + dvb_dmxdev_filter_state_set(&dmxdev->filter[i], + DMXDEV_STATE_FREE); + } + + dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, + DVB_DEVICE_DEMUX); + dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, + dmxdev, DVB_DEVICE_DVR); + + dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); + + return 0; +} + +EXPORT_SYMBOL(dvb_dmxdev_init); + +void dvb_dmxdev_release(struct dmxdev *dmxdev) +{ + dmxdev->exit=1; + if (dmxdev->dvbdev->users > 1) { + wait_event(dmxdev->dvbdev->wait_queue, + dmxdev->dvbdev->users==1); + } + if (dmxdev->dvr_dvbdev->users > 1) { + wait_event(dmxdev->dvr_dvbdev->wait_queue, + dmxdev->dvr_dvbdev->users==1); + } + + dvb_unregister_device(dmxdev->dvbdev); + dvb_unregister_device(dmxdev->dvr_dvbdev); + + vfree(dmxdev->filter); + dmxdev->filter = NULL; + dmxdev->demux->close(dmxdev->demux); +} + +EXPORT_SYMBOL(dvb_dmxdev_release); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dmxdev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dmxdev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dmxdev.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dmxdev.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,118 @@ +/* + * dmxdev.h + * + * Copyright (C) 2000 Ralph Metzler & Marcus Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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. + * + */ + +#ifndef _DMXDEV_H_ +#define _DMXDEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dvbdev.h" +#include "demux.h" +#include "dvb_ringbuffer.h" + +enum dmxdev_type { + DMXDEV_TYPE_NONE, + DMXDEV_TYPE_SEC, + DMXDEV_TYPE_PES, +}; + +enum dmxdev_state { + DMXDEV_STATE_FREE, + DMXDEV_STATE_ALLOCATED, + DMXDEV_STATE_SET, + DMXDEV_STATE_GO, + DMXDEV_STATE_DONE, + DMXDEV_STATE_TIMEDOUT +}; + +struct dmxdev_feed { + u16 pid; + struct dmx_ts_feed *ts; + struct list_head next; +}; + +struct dmxdev_filter { + union { + struct dmx_section_filter *sec; + } filter; + + union { + /* list of TS and PES feeds (struct dmxdev_feed) */ + struct list_head ts; + struct dmx_section_feed *sec; + } feed; + + union { + struct dmx_sct_filter_params sec; + struct dmx_pes_filter_params pes; + } params; + + enum dmxdev_type type; + enum dmxdev_state state; + struct dmxdev *dev; + struct dvb_ringbuffer buffer; + + struct mutex mutex; + + /* only for sections */ + struct timer_list timer; + int todo; + u8 secheader[3]; +}; + + +struct dmxdev { + struct dvb_device *dvbdev; + struct dvb_device *dvr_dvbdev; + + struct dmxdev_filter *filter; + struct dmx_demux *demux; + + int filternum; + int capabilities; + + unsigned int exit:1; +#define DMXDEV_CAP_DUPLEX 1 + struct dmx_frontend *dvr_orig_fe; + + struct dvb_ringbuffer dvr_buffer; +#define DVR_BUFFER_SIZE (10*188*1024) + + struct mutex mutex; + spinlock_t lock; +}; + + +int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *); +void dvb_dmxdev_release(struct dmxdev *dmxdev); + +#endif /* _DMXDEV_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1749 @@ +/* + * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces + * + * Copyright (C) 2004 Andrew de Quincey + * + * Parts of this file were based on sources as follows: + * + * Copyright (C) 2003 Ralph Metzler + * + * based on code: + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * 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, or (at your option) any later version. + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_ca_en50221.h" +#include "dvb_ringbuffer.h" + +static int dvb_ca_en50221_debug; + +module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644); +MODULE_PARM_DESC(cam_debug, "enable verbose debug messages"); + +#define dprintk if (dvb_ca_en50221_debug) printk + +#define INIT_TIMEOUT_SECS 10 + +#define HOST_LINK_BUF_SIZE 0x200 + +#define RX_BUFFER_SIZE 65535 + +#define MAX_RX_PACKETS_PER_ITERATION 10 + +#define CTRLIF_DATA 0 +#define CTRLIF_COMMAND 1 +#define CTRLIF_STATUS 1 +#define CTRLIF_SIZE_LOW 2 +#define CTRLIF_SIZE_HIGH 3 + +#define CMDREG_HC 1 /* Host control */ +#define CMDREG_SW 2 /* Size write */ +#define CMDREG_SR 4 /* Size read */ +#define CMDREG_RS 8 /* Reset interface */ +#define CMDREG_FRIE 0x40 /* Enable FR interrupt */ +#define CMDREG_DAIE 0x80 /* Enable DA interrupt */ +#define IRQEN (CMDREG_DAIE) + +#define STATUSREG_RE 1 /* read error */ +#define STATUSREG_WE 2 /* write error */ +#define STATUSREG_FR 0x40 /* module free */ +#define STATUSREG_DA 0x80 /* data available */ +#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE) /* general transfer error */ + + +#define DVB_CA_SLOTSTATE_NONE 0 +#define DVB_CA_SLOTSTATE_UNINITIALISED 1 +#define DVB_CA_SLOTSTATE_RUNNING 2 +#define DVB_CA_SLOTSTATE_INVALID 3 +#define DVB_CA_SLOTSTATE_WAITREADY 4 +#define DVB_CA_SLOTSTATE_VALIDATE 5 +#define DVB_CA_SLOTSTATE_WAITFR 6 +#define DVB_CA_SLOTSTATE_LINKINIT 7 + + +/* Information on a CA slot */ +struct dvb_ca_slot { + + /* current state of the CAM */ + int slot_state; + + /* mutex used for serializing access to one CI slot */ + struct mutex slot_lock; + + /* Number of CAMCHANGES that have occurred since last processing */ + atomic_t camchange_count; + + /* Type of last CAMCHANGE */ + int camchange_type; + + /* base address of CAM config */ + u32 config_base; + + /* value to write into Config Control register */ + u8 config_option; + + /* if 1, the CAM supports DA IRQs */ + u8 da_irq_supported:1; + + /* size of the buffer to use when talking to the CAM */ + int link_buf_size; + + /* buffer for incoming packets */ + struct dvb_ringbuffer rx_buffer; + + /* timer used during various states of the slot */ + unsigned long timeout; +}; + +/* Private CA-interface information */ +struct dvb_ca_private { + + /* pointer back to the public data structure */ + struct dvb_ca_en50221 *pub; + + /* the DVB device */ + struct dvb_device *dvbdev; + + /* Flags describing the interface (DVB_CA_FLAG_*) */ + u32 flags; + + /* number of slots supported by this CA interface */ + unsigned int slot_count; + + /* information on each slot */ + struct dvb_ca_slot *slot_info; + + /* wait queues for read() and write() operations */ + wait_queue_head_t wait_queue; + + /* PID of the monitoring thread */ + struct task_struct *thread; + + /* Flag indicating if the CA device is open */ + unsigned int open:1; + + /* Flag indicating the thread should wake up now */ + unsigned int wakeup:1; + + /* Delay the main thread should use */ + unsigned long delay; + + /* Slot to start looking for data to read from in the next user-space read operation */ + int next_read_slot; +}; + +static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); +static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); +static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); + + +/** + * Safely find needle in haystack. + * + * @param haystack Buffer to look in. + * @param hlen Number of bytes in haystack. + * @param needle Buffer to find. + * @param nlen Number of bytes in needle. + * @return Pointer into haystack needle was found at, or NULL if not found. + */ +static char *findstr(char * haystack, int hlen, char * needle, int nlen) +{ + int i; + + if (hlen < nlen) + return NULL; + + for (i = 0; i <= hlen - nlen; i++) { + if (!strncmp(haystack + i, needle, nlen)) + return haystack + i; + } + + return NULL; +} + + + +/* ******************************************************************************** */ +/* EN50221 physical interface functions */ + + +/** + * Check CAM status. + */ +static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) +{ + int slot_status; + int cam_present_now; + int cam_changed; + + /* IRQ mode */ + if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) { + return (atomic_read(&ca->slot_info[slot].camchange_count) != 0); + } + + /* poll mode */ + slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open); + + cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0; + cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0; + if (!cam_changed) { + int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE); + cam_changed = (cam_present_now != cam_present_old); + } + + if (cam_changed) { + if (!cam_present_now) { + ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; + } else { + ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED; + } + atomic_set(&ca->slot_info[slot].camchange_count, 1); + } else { + if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) && + (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) { + // move to validate state if reset is completed + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; + } + } + + return cam_changed; +} + + +/** + * Wait for flags to become set on the STATUS register on a CAM interface, + * checking for errors and timeout. + * + * @param ca CA instance. + * @param slot Slot on interface. + * @param waitfor Flags to wait for. + * @param timeout_ms Timeout in milliseconds. + * + * @return 0 on success, nonzero on error. + */ +static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, + u8 waitfor, int timeout_hz) +{ + unsigned long timeout; + unsigned long start; + + dprintk("%s\n", __func__); + + /* loop until timeout elapsed */ + start = jiffies; + timeout = jiffies + timeout_hz; + while (1) { + /* read the status and check for error */ + int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); + if (res < 0) + return -EIO; + + /* if we got the flags, it was successful! */ + if (res & waitfor) { + dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start); + return 0; + } + + /* check for timeout */ + if (time_after(jiffies, timeout)) { + break; + } + + /* wait for a bit */ + msleep(1); + } + + dprintk("%s failed timeout:%lu\n", __func__, jiffies - start); + + /* if we get here, we've timed out */ + return -ETIMEDOUT; +} + + +/** + * Initialise the link layer connection to a CAM. + * + * @param ca CA instance. + * @param slot Slot id. + * + * @return 0 on success, nonzero on failure. + */ +static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) +{ + int ret; + int buf_size; + u8 buf[2]; + + dprintk("%s\n", __func__); + + /* we'll be determining these during this function */ + ca->slot_info[slot].da_irq_supported = 0; + + /* set the host link buffer size temporarily. it will be overwritten with the + * real negotiated size later. */ + ca->slot_info[slot].link_buf_size = 2; + + /* read the buffer size from the CAM */ + if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0) + return ret; + if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0) + return ret; + if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) + return -EIO; + if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) + return ret; + + /* store it, and choose the minimum of our buffer and the CAM's buffer size */ + buf_size = (buf[0] << 8) | buf[1]; + if (buf_size > HOST_LINK_BUF_SIZE) + buf_size = HOST_LINK_BUF_SIZE; + ca->slot_info[slot].link_buf_size = buf_size; + buf[0] = buf_size >> 8; + buf[1] = buf_size & 0xff; + dprintk("Chosen link buffer size of %i\n", buf_size); + + /* write the buffer size to the CAM */ + if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0) + return ret; + if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0) + return ret; + if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) + return -EIO; + if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) + return ret; + + /* success */ + return 0; +} + +/** + * Read a tuple from attribute memory. + * + * @param ca CA instance. + * @param slot Slot id. + * @param address Address to read from. Updated. + * @param tupleType Tuple id byte. Updated. + * @param tupleLength Tuple length. Updated. + * @param tuple Dest buffer for tuple (must be 256 bytes). Updated. + * + * @return 0 on success, nonzero on error. + */ +static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, + int *address, int *tupleType, int *tupleLength, u8 * tuple) +{ + int i; + int _tupleType; + int _tupleLength; + int _address = *address; + + /* grab the next tuple length and type */ + if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) + return _tupleType; + if (_tupleType == 0xff) { + dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType); + *address += 2; + *tupleType = _tupleType; + *tupleLength = 0; + return 0; + } + if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0) + return _tupleLength; + _address += 4; + + dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength); + + /* read in the whole tuple */ + for (i = 0; i < _tupleLength; i++) { + tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2)); + dprintk(" 0x%02x: 0x%02x %c\n", + i, tuple[i] & 0xff, + ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.'); + } + _address += (_tupleLength * 2); + + // success + *tupleType = _tupleType; + *tupleLength = _tupleLength; + *address = _address; + return 0; +} + + +/** + * Parse attribute memory of a CAM module, extracting Config register, and checking + * it is a DVB CAM module. + * + * @param ca CA instance. + * @param slot Slot id. + * + * @return 0 on success, <0 on failure. + */ +static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) +{ + int address = 0; + int tupleLength; + int tupleType; + u8 tuple[257]; + char *dvb_str; + int rasz; + int status; + int got_cftableentry = 0; + int end_chain = 0; + int i; + u16 manfid = 0; + u16 devid = 0; + + + // CISTPL_DEVICE_0A + if ((status = + dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x1D) + return -EINVAL; + + + + // CISTPL_DEVICE_0C + if ((status = + dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x1C) + return -EINVAL; + + + + // CISTPL_VERS_1 + if ((status = + dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x15) + return -EINVAL; + + + + // CISTPL_MANFID + if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, + &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x20) + return -EINVAL; + if (tupleLength != 4) + return -EINVAL; + manfid = (tuple[1] << 8) | tuple[0]; + devid = (tuple[3] << 8) | tuple[2]; + + + + // CISTPL_CONFIG + if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, + &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x1A) + return -EINVAL; + if (tupleLength < 3) + return -EINVAL; + + /* extract the configbase */ + rasz = tuple[0] & 3; + if (tupleLength < (3 + rasz + 14)) + return -EINVAL; + ca->slot_info[slot].config_base = 0; + for (i = 0; i < rasz + 1; i++) { + ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i)); + } + + /* check it contains the correct DVB string */ + dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8); + if (dvb_str == NULL) + return -EINVAL; + if (tupleLength < ((dvb_str - (char *) tuple) + 12)) + return -EINVAL; + + /* is it a version we support? */ + if (strncmp(dvb_str + 8, "1.00", 4)) { + printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n", + ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]); + return -EINVAL; + } + + /* process the CFTABLE_ENTRY tuples, and any after those */ + while ((!end_chain) && (address < 0x1000)) { + if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, + &tupleLength, tuple)) < 0) + return status; + switch (tupleType) { + case 0x1B: // CISTPL_CFTABLE_ENTRY + if (tupleLength < (2 + 11 + 17)) + break; + + /* if we've already parsed one, just use it */ + if (got_cftableentry) + break; + + /* get the config option */ + ca->slot_info[slot].config_option = tuple[0] & 0x3f; + + /* OK, check it contains the correct strings */ + if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) || + (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) + break; + + got_cftableentry = 1; + break; + + case 0x14: // CISTPL_NO_LINK + break; + + case 0xFF: // CISTPL_END + end_chain = 1; + break; + + default: /* Unknown tuple type - just skip this tuple and move to the next one */ + dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType, + tupleLength); + break; + } + } + + if ((address > 0x1000) || (!got_cftableentry)) + return -EINVAL; + + dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n", + manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option); + + // success! + return 0; +} + + +/** + * Set CAM's configoption correctly. + * + * @param ca CA instance. + * @param slot Slot containing the CAM. + */ +static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot) +{ + int configoption; + + dprintk("%s\n", __func__); + + /* set the config option */ + ca->pub->write_attribute_mem(ca->pub, slot, + ca->slot_info[slot].config_base, + ca->slot_info[slot].config_option); + + /* check it */ + configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base); + dprintk("Set configoption 0x%x, read configoption 0x%x\n", + ca->slot_info[slot].config_option, configoption & 0x3f); + + /* fine! */ + return 0; + +} + + +/** + * This function talks to an EN50221 CAM control interface. It reads a buffer of + * data from the CAM. The data can either be stored in a supplied buffer, or + * automatically be added to the slot's rx_buffer. + * + * @param ca CA instance. + * @param slot Slot to read from. + * @param ebuf If non-NULL, the data will be written to this buffer. If NULL, + * the data will be added into the buffering system as a normal fragment. + * @param ecount Size of ebuf. Ignored if ebuf is NULL. + * + * @return Number of bytes read, or < 0 on error + */ +static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount) +{ + int bytes_read; + int status; + u8 buf[HOST_LINK_BUF_SIZE]; + int i; + + dprintk("%s\n", __func__); + + /* check if we have space for a link buf in the rx_buffer */ + if (ebuf == NULL) { + int buf_free; + + if (ca->slot_info[slot].rx_buffer.data == NULL) { + status = -EIO; + goto exit; + } + buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); + + if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) { + status = -EAGAIN; + goto exit; + } + } + + /* check if there is data available */ + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exit; + if (!(status & STATUSREG_DA)) { + /* no data */ + status = 0; + goto exit; + } + + /* read the amount of data */ + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0) + goto exit; + bytes_read = status << 8; + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0) + goto exit; + bytes_read |= status; + + /* check it will fit */ + if (ebuf == NULL) { + if (bytes_read > ca->slot_info[slot].link_buf_size) { + printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n", + ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; + status = -EIO; + goto exit; + } + if (bytes_read < 2) { + printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", + ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; + status = -EIO; + goto exit; + } + } else { + if (bytes_read > ecount) { + printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", + ca->dvbdev->adapter->num); + status = -EIO; + goto exit; + } + } + + /* fill the buffer */ + for (i = 0; i < bytes_read; i++) { + /* read byte and check */ + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0) + goto exit; + + /* OK, store it in the buffer */ + buf[i] = status; + } + + /* check for read error (RE should now be 0) */ + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exit; + if (status & STATUSREG_RE) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; + status = -EIO; + goto exit; + } + + /* OK, add it to the receive buffer, or copy into external buffer if supplied */ + if (ebuf == NULL) { + if (ca->slot_info[slot].rx_buffer.data == NULL) { + status = -EIO; + goto exit; + } + dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); + } else { + memcpy(ebuf, buf, bytes_read); + } + + dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot, + buf[0], (buf[1] & 0x80) == 0, bytes_read); + + /* wake up readers when a last_fragment is received */ + if ((buf[1] & 0x80) == 0x00) { + wake_up_interruptible(&ca->wait_queue); + } + status = bytes_read; + +exit: + return status; +} + + +/** + * This function talks to an EN50221 CAM control interface. It writes a buffer of data + * to a CAM. + * + * @param ca CA instance. + * @param slot Slot to write to. + * @param ebuf The data in this buffer is treated as a complete link-level packet to + * be written. + * @param count Size of ebuf. + * + * @return Number of bytes written, or < 0 on error. + */ +static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write) +{ + int status; + int i; + + dprintk("%s\n", __func__); + + + /* sanity check */ + if (bytes_write > ca->slot_info[slot].link_buf_size) + return -EINVAL; + + /* it is possible we are dealing with a single buffer implementation, + thus if there is data available for read or if there is even a read + already in progress, we do nothing but awake the kernel thread to + process the data if necessary. */ + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exitnowrite; + if (status & (STATUSREG_DA | STATUSREG_RE)) { + if (status & STATUSREG_DA) + dvb_ca_en50221_thread_wakeup(ca); + + status = -EAGAIN; + goto exitnowrite; + } + + /* OK, set HC bit */ + if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, + IRQEN | CMDREG_HC)) != 0) + goto exit; + + /* check if interface is still free */ + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exit; + if (!(status & STATUSREG_FR)) { + /* it wasn't free => try again later */ + status = -EAGAIN; + goto exit; + } + + /* send the amount of data */ + if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) + goto exit; + if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, + bytes_write & 0xff)) != 0) + goto exit; + + /* send the buffer */ + for (i = 0; i < bytes_write; i++) { + if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) + goto exit; + } + + /* check for write error (WE should now be 0) */ + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exit; + if (status & STATUSREG_WE) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; + status = -EIO; + goto exit; + } + status = bytes_write; + + dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot, + buf[0], (buf[1] & 0x80) == 0, bytes_write); + +exit: + ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); + +exitnowrite: + return status; +} +EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); + + + +/* ******************************************************************************** */ +/* EN50221 higher level functions */ + + +/** + * A CAM has been removed => shut it down. + * + * @param ca CA instance. + * @param slot Slot to shut down. + */ +static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) +{ + dprintk("%s\n", __func__); + + ca->pub->slot_shutdown(ca->pub, slot); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; + + /* need to wake up all processes to check if they're now + trying to write to a defunct CAM */ + wake_up_interruptible(&ca->wait_queue); + + dprintk("Slot %i shutdown\n", slot); + + /* success */ + return 0; +} +EXPORT_SYMBOL(dvb_ca_en50221_camready_irq); + + +/** + * A CAMCHANGE IRQ has occurred. + * + * @param ca CA instance. + * @param slot Slot concerned. + * @param change_type One of the DVB_CA_CAMCHANGE_* values. + */ +void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type) +{ + struct dvb_ca_private *ca = pubca->private; + + dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type); + + switch (change_type) { + case DVB_CA_EN50221_CAMCHANGE_REMOVED: + case DVB_CA_EN50221_CAMCHANGE_INSERTED: + break; + + default: + return; + } + + ca->slot_info[slot].camchange_type = change_type; + atomic_inc(&ca->slot_info[slot].camchange_count); + dvb_ca_en50221_thread_wakeup(ca); +} +EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); + + +/** + * A CAMREADY IRQ has occurred. + * + * @param ca CA instance. + * @param slot Slot concerned. + */ +void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) +{ + struct dvb_ca_private *ca = pubca->private; + + dprintk("CAMREADY IRQ slot:%i\n", slot); + + if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; + dvb_ca_en50221_thread_wakeup(ca); + } +} + + +/** + * An FR or DA IRQ has occurred. + * + * @param ca CA instance. + * @param slot Slot concerned. + */ +void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) +{ + struct dvb_ca_private *ca = pubca->private; + int flags; + + dprintk("FR/DA IRQ slot:%i\n", slot); + + switch (ca->slot_info[slot].slot_state) { + case DVB_CA_SLOTSTATE_LINKINIT: + flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS); + if (flags & STATUSREG_DA) { + dprintk("CAM supports DA IRQ\n"); + ca->slot_info[slot].da_irq_supported = 1; + } + break; + + case DVB_CA_SLOTSTATE_RUNNING: + if (ca->open) + dvb_ca_en50221_thread_wakeup(ca); + break; + } +} + + + +/* ******************************************************************************** */ +/* EN50221 thread functions */ + +/** + * Wake up the DVB CA thread + * + * @param ca CA instance. + */ +static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) +{ + + dprintk("%s\n", __func__); + + ca->wakeup = 1; + mb(); + wake_up_process(ca->thread); +} + +/** + * Update the delay used by the thread. + * + * @param ca CA instance. + */ +static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) +{ + int delay; + int curdelay = 100000000; + int slot; + + /* Beware of too high polling frequency, because one polling + * call might take several hundred milliseconds until timeout! + */ + for (slot = 0; slot < ca->slot_count; slot++) { + switch (ca->slot_info[slot].slot_state) { + default: + case DVB_CA_SLOTSTATE_NONE: + delay = HZ * 60; /* 60s */ + if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) + delay = HZ * 5; /* 5s */ + break; + case DVB_CA_SLOTSTATE_INVALID: + delay = HZ * 60; /* 60s */ + if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) + delay = HZ / 10; /* 100ms */ + break; + + case DVB_CA_SLOTSTATE_UNINITIALISED: + case DVB_CA_SLOTSTATE_WAITREADY: + case DVB_CA_SLOTSTATE_VALIDATE: + case DVB_CA_SLOTSTATE_WAITFR: + case DVB_CA_SLOTSTATE_LINKINIT: + delay = HZ / 10; /* 100ms */ + break; + + case DVB_CA_SLOTSTATE_RUNNING: + delay = HZ * 60; /* 60s */ + if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) + delay = HZ / 10; /* 100ms */ + if (ca->open) { + if ((!ca->slot_info[slot].da_irq_supported) || + (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) + delay = HZ / 10; /* 100ms */ + } + break; + } + + if (delay < curdelay) + curdelay = delay; + } + + ca->delay = curdelay; +} + + + +/** + * Kernel thread which monitors CA slots for CAM changes, and performs data transfers. + */ +static int dvb_ca_en50221_thread(void *data) +{ + struct dvb_ca_private *ca = data; + int slot; + int flags; + int status; + int pktcount; + void *rxbuf; + + dprintk("%s\n", __func__); + + /* choose the correct initial delay */ + dvb_ca_en50221_thread_update_delay(ca); + + /* main loop */ + while (!kthread_should_stop()) { + /* sleep for a bit */ + if (!ca->wakeup) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(ca->delay); + if (kthread_should_stop()) + return 0; + } + ca->wakeup = 0; + + /* go through all the slots processing them */ + for (slot = 0; slot < ca->slot_count; slot++) { + + mutex_lock(&ca->slot_info[slot].slot_lock); + + // check the cam status + deal with CAMCHANGEs + while (dvb_ca_en50221_check_camstatus(ca, slot)) { + /* clear down an old CI slot if necessary */ + if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) + dvb_ca_en50221_slot_shutdown(ca, slot); + + /* if a CAM is NOW present, initialise it */ + if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED; + } + + /* we've handled one CAMCHANGE */ + dvb_ca_en50221_thread_update_delay(ca); + atomic_dec(&ca->slot_info[slot].camchange_count); + } + + // CAM state machine + switch (ca->slot_info[slot].slot_state) { + case DVB_CA_SLOTSTATE_NONE: + case DVB_CA_SLOTSTATE_INVALID: + // no action needed + break; + + case DVB_CA_SLOTSTATE_UNINITIALISED: + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY; + ca->pub->slot_reset(ca->pub, slot); + ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); + break; + + case DVB_CA_SLOTSTATE_WAITREADY: + if (time_after(jiffies, ca->slot_info[slot].timeout)) { + printk("dvb_ca adaptor %d: PC card did not respond :(\n", + ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + // no other action needed; will automatically change state when ready + break; + + case DVB_CA_SLOTSTATE_VALIDATE: + if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) { + /* we need this extra check for annoying interfaces like the budget-av */ + if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && + (ca->pub->poll_slot_status)) { + status = ca->pub->poll_slot_status(ca->pub, slot, 0); + if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + } + + printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", + ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + if (dvb_ca_en50221_set_configoption(ca, slot) != 0) { + printk("dvb_ca adapter %d: Unable to initialise CAM :(\n", + ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + if (ca->pub->write_cam_control(ca->pub, slot, + CTRLIF_COMMAND, CMDREG_RS) != 0) { + printk("dvb_ca adapter %d: Unable to reset CAM IF\n", + ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + dprintk("DVB CAM validated successfully\n"); + + ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR; + ca->wakeup = 1; + break; + + case DVB_CA_SLOTSTATE_WAITFR: + if (time_after(jiffies, ca->slot_info[slot].timeout)) { + printk("dvb_ca adapter %d: DVB CAM did not respond :(\n", + ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + + flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); + if (flags & STATUSREG_FR) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; + ca->wakeup = 1; + } + break; + + case DVB_CA_SLOTSTATE_LINKINIT: + if (dvb_ca_en50221_link_init(ca, slot) != 0) { + /* we need this extra check for annoying interfaces like the budget-av */ + if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && + (ca->pub->poll_slot_status)) { + status = ca->pub->poll_slot_status(ca->pub, slot, 0); + if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + } + + printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + + if (ca->slot_info[slot].rx_buffer.data == NULL) { + rxbuf = vmalloc(RX_BUFFER_SIZE); + if (rxbuf == NULL) { + printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); + } + + ca->pub->slot_ts_enable(ca->pub, slot); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; + dvb_ca_en50221_thread_update_delay(ca); + printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num); + break; + + case DVB_CA_SLOTSTATE_RUNNING: + if (!ca->open) + break; + + // poll slots for data + pktcount = 0; + while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { + if (!ca->open) + break; + + /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */ + if (dvb_ca_en50221_check_camstatus(ca, slot)) { + // we dont want to sleep on the next iteration so we can handle the cam change + ca->wakeup = 1; + break; + } + + /* check if we've hit our limit this time */ + if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) { + // dont sleep; there is likely to be more data to read + ca->wakeup = 1; + break; + } + } + break; + } + + mutex_unlock(&ca->slot_info[slot].slot_lock); + } + } + + return 0; +} + + + +/* ******************************************************************************** */ +/* EN50221 IO interface functions */ + +/** + * Real ioctl implementation. + * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. + * + * @param inode Inode concerned. + * @param file File concerned. + * @param cmd IOCTL command. + * @param arg Associated argument. + * + * @return 0 on success, <0 on error. + */ +static int dvb_ca_en50221_io_do_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; + int err = 0; + int slot; + + dprintk("%s\n", __func__); + + switch (cmd) { + case CA_RESET: + for (slot = 0; slot < ca->slot_count; slot++) { + mutex_lock(&ca->slot_info[slot].slot_lock); + if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { + dvb_ca_en50221_slot_shutdown(ca, slot); + if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) + dvb_ca_en50221_camchange_irq(ca->pub, + slot, + DVB_CA_EN50221_CAMCHANGE_INSERTED); + } + mutex_unlock(&ca->slot_info[slot].slot_lock); + } + ca->next_read_slot = 0; + dvb_ca_en50221_thread_wakeup(ca); + break; + + case CA_GET_CAP: { + struct ca_caps *caps = parg; + + caps->slot_num = ca->slot_count; + caps->slot_type = CA_CI_LINK; + caps->descr_num = 0; + caps->descr_type = 0; + break; + } + + case CA_GET_SLOT_INFO: { + struct ca_slot_info *info = parg; + + if ((info->num > ca->slot_count) || (info->num < 0)) + return -EINVAL; + + info->type = CA_CI_LINK; + info->flags = 0; + if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) + && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) { + info->flags = CA_CI_MODULE_PRESENT; + } + if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) { + info->flags |= CA_CI_MODULE_READY; + } + break; + } + + default: + err = -EINVAL; + break; + } + + return err; +} + + +/** + * Wrapper for ioctl implementation. + * + * @param inode Inode concerned. + * @param file File concerned. + * @param cmd IOCTL command. + * @param arg Associated argument. + * + * @return 0 on success, <0 on error. + */ +static long dvb_ca_en50221_io_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl); +} + + +/** + * Implementation of write() syscall. + * + * @param file File structure. + * @param buf Source buffer. + * @param count Size of source buffer. + * @param ppos Position in file (ignored). + * + * @return Number of bytes read, or <0 on error. + */ +static ssize_t dvb_ca_en50221_io_write(struct file *file, + const char __user * buf, size_t count, loff_t * ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; + u8 slot, connection_id; + int status; + u8 fragbuf[HOST_LINK_BUF_SIZE]; + int fragpos = 0; + int fraglen; + unsigned long timeout; + int written; + + dprintk("%s\n", __func__); + + /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ + if (count < 2) + return -EINVAL; + + /* extract slot & connection id */ + if (copy_from_user(&slot, buf, 1)) + return -EFAULT; + if (copy_from_user(&connection_id, buf + 1, 1)) + return -EFAULT; + buf += 2; + count -= 2; + + /* check if the slot is actually running */ + if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) + return -EINVAL; + + /* fragment the packets & store in the buffer */ + while (fragpos < count) { + fraglen = ca->slot_info[slot].link_buf_size - 2; + if ((count - fragpos) < fraglen) + fraglen = count - fragpos; + + fragbuf[0] = connection_id; + fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00; + status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen); + if (status) { + status = -EFAULT; + goto exit; + } + + timeout = jiffies + HZ / 2; + written = 0; + while (!time_after(jiffies, timeout)) { + /* check the CAM hasn't been removed/reset in the meantime */ + if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) { + status = -EIO; + goto exit; + } + + mutex_lock(&ca->slot_info[slot].slot_lock); + status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); + mutex_unlock(&ca->slot_info[slot].slot_lock); + if (status == (fraglen + 2)) { + written = 1; + break; + } + if (status != -EAGAIN) + goto exit; + + msleep(1); + } + if (!written) { + status = -EIO; + goto exit; + } + + fragpos += fraglen; + } + status = count + 2; + +exit: + return status; +} + + +/** + * Condition for waking up in dvb_ca_en50221_io_read_condition + */ +static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, + int *result, int *_slot) +{ + int slot; + int slot_count = 0; + int idx; + size_t fraglen; + int connection_id = -1; + int found = 0; + u8 hdr[2]; + + slot = ca->next_read_slot; + while ((slot_count < ca->slot_count) && (!found)) { + if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) + goto nextslot; + + if (ca->slot_info[slot].rx_buffer.data == NULL) { + return 0; + } + + idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); + while (idx != -1) { + dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); + if (connection_id == -1) + connection_id = hdr[0]; + if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) { + *_slot = slot; + found = 1; + break; + } + + idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); + } + +nextslot: + slot = (slot + 1) % ca->slot_count; + slot_count++; + } + + ca->next_read_slot = slot; + return found; +} + + +/** + * Implementation of read() syscall. + * + * @param file File structure. + * @param buf Destination buffer. + * @param count Size of destination buffer. + * @param ppos Position in file (ignored). + * + * @return Number of bytes read, or <0 on error. + */ +static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, + size_t count, loff_t * ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; + int status; + int result = 0; + u8 hdr[2]; + int slot; + int connection_id = -1; + size_t idx, idx2; + int last_fragment = 0; + size_t fraglen; + int pktlen; + int dispose = 0; + + dprintk("%s\n", __func__); + + /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ + if (count < 2) + return -EINVAL; + + /* wait for some data */ + if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) { + + /* if we're in nonblocking mode, exit immediately */ + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + /* wait for some data */ + status = wait_event_interruptible(ca->wait_queue, + dvb_ca_en50221_io_read_condition + (ca, &result, &slot)); + } + if ((status < 0) || (result < 0)) { + if (result) + return result; + return status; + } + + idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); + pktlen = 2; + do { + if (idx == -1) { + printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num); + status = -EIO; + goto exit; + } + + dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); + if (connection_id == -1) + connection_id = hdr[0]; + if (hdr[0] == connection_id) { + if (pktlen < count) { + if ((pktlen + fraglen - 2) > count) { + fraglen = count - pktlen; + } else { + fraglen -= 2; + } + + if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2, + buf + pktlen, fraglen)) < 0) { + goto exit; + } + pktlen += fraglen; + } + + if ((hdr[1] & 0x80) == 0) + last_fragment = 1; + dispose = 1; + } + + idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); + if (dispose) + dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx); + idx = idx2; + dispose = 0; + } while (!last_fragment); + + hdr[0] = slot; + hdr[1] = connection_id; + status = copy_to_user(buf, hdr, 2); + if (status) { + status = -EFAULT; + goto exit; + } + status = pktlen; + +exit: + return status; +} + + +/** + * Implementation of file open syscall. + * + * @param inode Inode concerned. + * @param file File concerned. + * + * @return 0 on success, <0 on failure. + */ +static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; + int err; + int i; + + dprintk("%s\n", __func__); + + if (!try_module_get(ca->pub->owner)) + return -EIO; + + err = dvb_generic_open(inode, file); + if (err < 0) { + module_put(ca->pub->owner); + return err; + } + + for (i = 0; i < ca->slot_count; i++) { + + if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { + if (ca->slot_info[i].rx_buffer.data != NULL) { + /* it is safe to call this here without locks because + * ca->open == 0. Data is not read in this case */ + dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); + } + } + } + + ca->open = 1; + dvb_ca_en50221_thread_update_delay(ca); + dvb_ca_en50221_thread_wakeup(ca); + + return 0; +} + + +/** + * Implementation of file close syscall. + * + * @param inode Inode concerned. + * @param file File concerned. + * + * @return 0 on success, <0 on failure. + */ +static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; + int err; + + dprintk("%s\n", __func__); + + /* mark the CA device as closed */ + ca->open = 0; + dvb_ca_en50221_thread_update_delay(ca); + + err = dvb_generic_release(inode, file); + + module_put(ca->pub->owner); + + return err; +} + + +/** + * Implementation of poll() syscall. + * + * @param file File concerned. + * @param wait poll wait table. + * + * @return Standard poll mask. + */ +static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; + unsigned int mask = 0; + int slot; + int result = 0; + + dprintk("%s\n", __func__); + + if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { + mask |= POLLIN; + } + + /* if there is something, return now */ + if (mask) + return mask; + + /* wait for something to happen */ + poll_wait(file, &ca->wait_queue, wait); + + if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { + mask |= POLLIN; + } + + return mask; +} +EXPORT_SYMBOL(dvb_ca_en50221_init); + + +static const struct file_operations dvb_ca_fops = { + .owner = THIS_MODULE, + .read = dvb_ca_en50221_io_read, + .write = dvb_ca_en50221_io_write, + .unlocked_ioctl = dvb_ca_en50221_io_ioctl, + .open = dvb_ca_en50221_io_open, + .release = dvb_ca_en50221_io_release, + .poll = dvb_ca_en50221_io_poll, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_ca = { + .priv = NULL, + .users = 1, + .readers = 1, + .writers = 1, + .fops = &dvb_ca_fops, +}; + + +/* ******************************************************************************** */ +/* Initialisation/shutdown functions */ + + +/** + * Initialise a new DVB CA EN50221 interface device. + * + * @param dvb_adapter DVB adapter to attach the new CA device to. + * @param ca The dvb_ca instance. + * @param flags Flags describing the CA device (DVB_CA_FLAG_*). + * @param slot_count Number of slots supported. + * + * @return 0 on success, nonzero on failure + */ +int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, + struct dvb_ca_en50221 *pubca, int flags, int slot_count) +{ + int ret; + struct dvb_ca_private *ca = NULL; + int i; + + dprintk("%s\n", __func__); + + if (slot_count < 1) + return -EINVAL; + + /* initialise the system data */ + if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { + ret = -ENOMEM; + goto error; + } + ca->pub = pubca; + ca->flags = flags; + ca->slot_count = slot_count; + if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) { + ret = -ENOMEM; + goto error; + } + init_waitqueue_head(&ca->wait_queue); + ca->open = 0; + ca->wakeup = 0; + ca->next_read_slot = 0; + pubca->private = ca; + + /* register the DVB device */ + ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); + if (ret) + goto error; + + /* now initialise each slot */ + for (i = 0; i < slot_count; i++) { + memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot)); + ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; + atomic_set(&ca->slot_info[i].camchange_count, 0); + ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; + mutex_init(&ca->slot_info[i].slot_lock); + } + + if (signal_pending(current)) { + ret = -EINTR; + goto error; + } + mb(); + + /* create a kthread for monitoring this CA device */ + ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i", + ca->dvbdev->adapter->num, ca->dvbdev->id); + if (IS_ERR(ca->thread)) { + ret = PTR_ERR(ca->thread); + printk("dvb_ca_init: failed to start kernel_thread (%d)\n", + ret); + goto error; + } + return 0; + +error: + if (ca != NULL) { + if (ca->dvbdev != NULL) + dvb_unregister_device(ca->dvbdev); + kfree(ca->slot_info); + kfree(ca); + } + pubca->private = NULL; + return ret; +} +EXPORT_SYMBOL(dvb_ca_en50221_release); + + + +/** + * Release a DVB CA EN50221 interface device. + * + * @param ca_dev The dvb_device_t instance for the CA device. + * @param ca The associated dvb_ca instance. + */ +void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) +{ + struct dvb_ca_private *ca = pubca->private; + int i; + + dprintk("%s\n", __func__); + + /* shutdown the thread if there was one */ + kthread_stop(ca->thread); + + for (i = 0; i < ca->slot_count; i++) { + dvb_ca_en50221_slot_shutdown(ca, i); + vfree(ca->slot_info[i].rx_buffer.data); + } + kfree(ca->slot_info); + dvb_unregister_device(ca->dvbdev); + kfree(ca); + pubca->private = NULL; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,136 @@ +/* + * dvb_ca.h: generic DVB functions for EN50221 CA interfaces + * + * Copyright (C) 2004 Andrew de Quincey + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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. + */ + +#ifndef _DVB_CA_EN50221_H_ +#define _DVB_CA_EN50221_H_ + +#include +#include + +#include "dvbdev.h" + +#define DVB_CA_EN50221_POLL_CAM_PRESENT 1 +#define DVB_CA_EN50221_POLL_CAM_CHANGED 2 +#define DVB_CA_EN50221_POLL_CAM_READY 4 + +#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE 1 +#define DVB_CA_EN50221_FLAG_IRQ_FR 2 +#define DVB_CA_EN50221_FLAG_IRQ_DA 4 + +#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0 +#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1 + + + +/* Structure describing a CA interface */ +struct dvb_ca_en50221 { + + /* the module owning this structure */ + struct module* owner; + + /* NOTE: the read_*, write_* and poll_slot_status functions will be + * called for different slots concurrently and need to use locks where + * and if appropriate. There will be no concurrent access to one slot. + */ + + /* functions for accessing attribute memory on the CAM */ + int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address); + int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value); + + /* functions for accessing the control interface on the CAM */ + int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address); + int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value); + + /* Functions for controlling slots */ + int (*slot_reset)(struct dvb_ca_en50221* ca, int slot); + int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot); + int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot); + + /* + * Poll slot status. + * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set + */ + int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open); + + /* private data, used by caller */ + void* data; + + /* Opaque data used by the dvb_ca core. Do not modify! */ + void* private; +}; + + + + +/* ******************************************************************************** */ +/* Functions for reporting IRQ events */ + +/** + * A CAMCHANGE IRQ has occurred. + * + * @param ca CA instance. + * @param slot Slot concerned. + * @param change_type One of the DVB_CA_CAMCHANGE_* values + */ +void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type); + +/** + * A CAMREADY IRQ has occurred. + * + * @param ca CA instance. + * @param slot Slot concerned. + */ +void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot); + +/** + * An FR or a DA IRQ has occurred. + * + * @param ca CA instance. + * @param slot Slot concerned. + */ +void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot); + + + +/* ******************************************************************************** */ +/* Initialisation/shutdown functions */ + +/** + * Initialise a new DVB CA device. + * + * @param dvb_adapter DVB adapter to attach the new CA device to. + * @param ca The dvb_ca instance. + * @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*). + * @param slot_count Number of slots supported. + * + * @return 0 on success, nonzero on failure + */ +extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count); + +/** + * Release a DVB CA device. + * + * @param ca The associated dvb_ca instance. + */ +extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca); + + + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_demux.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_demux.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_demux.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_demux.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1299 @@ +/* + * dvb_demux.c - DVB kernel demux API + * + * Copyright (C) 2000-2001 Ralph Metzler + * & Marcus Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_demux.h" + +#define NOBUFS +/* +** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog +*/ +// #define DVB_DEMUX_SECTION_LOSS_LOG + +static int dvb_demux_tscheck; +module_param(dvb_demux_tscheck, int, 0644); +MODULE_PARM_DESC(dvb_demux_tscheck, + "enable transport stream continuity and TEI check"); + +static int dvb_demux_speedcheck; +module_param(dvb_demux_speedcheck, int, 0644); +MODULE_PARM_DESC(dvb_demux_speedcheck, + "enable transport stream speed check"); + +#define dprintk_tscheck(x...) do { \ + if (dvb_demux_tscheck && printk_ratelimit()) \ + printk(x); \ + } while (0) + +/****************************************************************************** + * static inlined helper functions + ******************************************************************************/ + +static inline u16 section_length(const u8 *buf) +{ + return 3 + ((buf[1] & 0x0f) << 8) + buf[2]; +} + +static inline u16 ts_pid(const u8 *buf) +{ + return ((buf[1] & 0x1f) << 8) + buf[2]; +} + +static inline u8 payload(const u8 *tsp) +{ + if (!(tsp[3] & 0x10)) // no payload? + return 0; + + if (tsp[3] & 0x20) { // adaptation field? + if (tsp[4] > 183) // corrupted data? + return 0; + else + return 184 - 1 - tsp[4]; + } + + return 184; +} + +static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len) +{ + return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len)); +} + +static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s, + size_t len) +{ + memcpy(d, s, len); +} + +/****************************************************************************** + * Software filter functions + ******************************************************************************/ + +static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, + const u8 *buf) +{ + int count = payload(buf); + int p; + //int ccok; + //u8 cc; + + if (count == 0) + return -1; + + p = 188 - count; + + /* + cc = buf[3] & 0x0f; + ccok = ((feed->cc + 1) & 0x0f) == cc; + feed->cc = cc; + if (!ccok) + printk("missed packet!\n"); + */ + + if (buf[1] & 0x40) // PUSI ? + feed->peslen = 0xfffa; + + feed->peslen += count; + + return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); +} + +static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, + struct dvb_demux_filter *f) +{ + u8 neq = 0; + int i; + + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { + u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i]; + + if (f->maskandmode[i] & xor) + return 0; + + neq |= f->maskandnotmode[i] & xor; + } + + if (f->doneq && !neq) + return 0; + + return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, + NULL, 0, &f->filter, DMX_OK); +} + +static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct dvb_demux_filter *f = feed->filter; + struct dmx_section_feed *sec = &feed->feed.sec; + int section_syntax_indicator; + + if (!sec->is_filtering) + return 0; + + if (!f) + return 0; + + if (sec->check_crc) { + section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); + if (section_syntax_indicator && + demux->check_crc32(feed, sec->secbuf, sec->seclen)) + return -1; + } + + do { + if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0) + return -1; + } while ((f = f->next) && sec->is_filtering); + + sec->seclen = 0; + + return 0; +} + +static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) +{ + struct dmx_section_feed *sec = &feed->feed.sec; + +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + if (sec->secbufp < sec->tsfeedp) { + int i, n = sec->tsfeedp - sec->secbufp; + + /* + * Section padding is done with 0xff bytes entirely. + * Due to speed reasons, we won't check all of them + * but just first and last. + */ + if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { + printk("dvb_demux.c section ts padding loss: %d/%d\n", + n, sec->tsfeedp); + printk("dvb_demux.c pad data:"); + for (i = 0; i < n; i++) + printk(" %02x", sec->secbuf[i]); + printk("\n"); + } + } +#endif + + sec->tsfeedp = sec->secbufp = sec->seclen = 0; + sec->secbuf = sec->secbuf_base; +} + +/* + * Losless Section Demux 1.4.1 by Emard + * Valsecchi Patrick: + * - middle of section A (no PUSI) + * - end of section A and start of section B + * (with PUSI pointing to the start of the second section) + * + * In this case, without feed->pusi_seen you'll receive a garbage section + * consisting of the end of section A. Basically because tsfeedp + * is incemented and the use=0 condition is not raised + * when the second packet arrives. + * + * Fix: + * when demux is started, let feed->pusi_seen = 0 to + * prevent initial feeding of garbage from the end of + * previous section. When you for the first time see PUSI=1 + * then set feed->pusi_seen = 1 + */ +static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, + const u8 *buf, u8 len) +{ + struct dvb_demux *demux = feed->demux; + struct dmx_section_feed *sec = &feed->feed.sec; + u16 limit, seclen, n; + + if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) + return 0; + + if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + printk("dvb_demux.c section buffer full loss: %d/%d\n", + sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, + DMX_MAX_SECFEED_SIZE); +#endif + len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; + } + + if (len <= 0) + return 0; + + demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len); + sec->tsfeedp += len; + + /* + * Dump all the sections we can find in the data (Emard) + */ + limit = sec->tsfeedp; + if (limit > DMX_MAX_SECFEED_SIZE) + return -1; /* internal error should never happen */ + + /* to be sure always set secbuf */ + sec->secbuf = sec->secbuf_base + sec->secbufp; + + for (n = 0; sec->secbufp + 2 < limit; n++) { + seclen = section_length(sec->secbuf); + if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE + || seclen + sec->secbufp > limit) + return 0; + sec->seclen = seclen; + sec->crc_val = ~0; + /* dump [secbuf .. secbuf+seclen) */ + if (feed->pusi_seen) + dvb_dmx_swfilter_section_feed(feed); +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + else + printk("dvb_demux.c pusi not seen, discarding section data\n"); +#endif + sec->secbufp += seclen; /* secbufp and secbuf moving together is */ + sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ + } + + return 0; +} + +static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, + const u8 *buf) +{ + u8 p, count; + int ccok, dc_i = 0; + u8 cc; + + count = payload(buf); + + if (count == 0) /* count == 0 if no payload or out of range */ + return -1; + + p = 188 - count; /* payload start */ + + cc = buf[3] & 0x0f; + ccok = ((feed->cc + 1) & 0x0f) == cc; + feed->cc = cc; + + if (buf[3] & 0x20) { + /* adaption field present, check for discontinuity_indicator */ + if ((buf[4] > 0) && (buf[5] & 0x80)) + dc_i = 1; + } + + if (!ccok || dc_i) { +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + printk("dvb_demux.c discontinuity detected %d bytes lost\n", + count); + /* + * those bytes under sume circumstances will again be reported + * in the following dvb_dmx_swfilter_section_new + */ +#endif + /* + * Discontinuity detected. Reset pusi_seen = 0 to + * stop feeding of suspicious data until next PUSI=1 arrives + */ + feed->pusi_seen = 0; + dvb_dmx_swfilter_section_new(feed); + } + + if (buf[1] & 0x40) { + /* PUSI=1 (is set), section boundary is here */ + if (count > 1 && buf[p] < count) { + const u8 *before = &buf[p + 1]; + u8 before_len = buf[p]; + const u8 *after = &before[before_len]; + u8 after_len = count - 1 - before_len; + + dvb_dmx_swfilter_section_copy_dump(feed, before, + before_len); + /* before start of new section, set pusi_seen = 1 */ + feed->pusi_seen = 1; + dvb_dmx_swfilter_section_new(feed); + dvb_dmx_swfilter_section_copy_dump(feed, after, + after_len); + } +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + else if (count > 0) + printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); +#endif + } else { + /* PUSI=0 (is not set), no section boundary */ + dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); + } + + return 0; +} + +static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, + const u8 *buf) +{ + switch (feed->type) { + case DMX_TYPE_TS: + if (!feed->feed.ts.is_filtering) + break; + if (feed->ts_type & TS_PACKET) { + if (feed->ts_type & TS_PAYLOAD_ONLY) + dvb_dmx_swfilter_payload(feed, buf); + else + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, + DMX_OK); + } + if (feed->ts_type & TS_DECODER) + if (feed->demux->write_to_decoder) + feed->demux->write_to_decoder(feed, buf, 188); + break; + + case DMX_TYPE_SEC: + if (!feed->feed.sec.is_filtering) + break; + if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) + feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; + break; + + default: + break; + } +} + +#define DVR_FEED(f) \ + (((f)->type == DMX_TYPE_TS) && \ + ((f)->feed.ts.is_filtering) && \ + (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET)) + +static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) +{ + struct dvb_demux_feed *feed; + u16 pid = ts_pid(buf); + int dvr_done = 0; + + if (dvb_demux_speedcheck) { + struct timespec cur_time, delta_time; + u64 speed_bytes, speed_timedelta; + + demux->speed_pkts_cnt++; + + /* show speed every SPEED_PKTS_INTERVAL packets */ + if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { + cur_time = current_kernel_time(); + + if (demux->speed_last_time.tv_sec != 0 && + demux->speed_last_time.tv_nsec != 0) { + delta_time = timespec_sub(cur_time, + demux->speed_last_time); + speed_bytes = (u64)demux->speed_pkts_cnt + * 188 * 8; + /* convert to 1024 basis */ + speed_bytes = 1000 * div64_u64(speed_bytes, + 1024); + speed_timedelta = + (u64)timespec_to_ns(&delta_time); + speed_timedelta = div64_u64(speed_timedelta, + 1000000); /* nsec -> usec */ + printk(KERN_INFO "TS speed %llu Kbits/sec \n", + div64_u64(speed_bytes, + speed_timedelta)); + }; + + demux->speed_last_time = cur_time; + demux->speed_pkts_cnt = 0; + }; + }; + + if (demux->cnt_storage && dvb_demux_tscheck) { + /* check pkt counter */ + if (pid < MAX_PID) { + if (buf[1] & 0x80) + dprintk_tscheck("TEI detected. " + "PID=0x%x data1=0x%x\n", + pid, buf[1]); + + if ((buf[3] & 0xf) != demux->cnt_storage[pid]) + dprintk_tscheck("TS packet counter mismatch. " + "PID=0x%x expected 0x%x " + "got 0x%x\n", + pid, demux->cnt_storage[pid], + buf[3] & 0xf); + + demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf; + }; + /* end check */ + }; + + list_for_each_entry(feed, &demux->feed_list, list_head) { + if ((feed->pid != pid) && (feed->pid != 0x2000)) + continue; + + /* copy each packet only once to the dvr device, even + * if a PID is in multiple filters (e.g. video + PCR) */ + if ((DVR_FEED(feed)) && (dvr_done++)) + continue; + + if (feed->pid == pid) + dvb_dmx_swfilter_packet_type(feed, buf); + else if (feed->pid == 0x2000) + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); + } +} + +void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, + size_t count) +{ + spin_lock(&demux->lock); + + while (count--) { + if (buf[0] == 0x47) + dvb_dmx_swfilter_packet(demux, buf); + buf += 188; + } + + spin_unlock(&demux->lock); +} + +EXPORT_SYMBOL(dvb_dmx_swfilter_packets); + +static inline int find_next_packet(const u8 *buf, int pos, size_t count, + const int pktsize) +{ + int start = pos, lost; + + while (pos < count) { + if (buf[pos] == 0x47 || + (pktsize == 204 && buf[pos] == 0xB8)) + break; + pos++; + } + + lost = pos - start; + if (lost) { + /* This garbage is part of a valid packet? */ + int backtrack = pos - pktsize; + if (backtrack >= 0 && (buf[backtrack] == 0x47 || + (pktsize == 204 && buf[backtrack] == 0xB8))) + return backtrack; + } + + return pos; +} + +/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */ +static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, + size_t count, const int pktsize) +{ + int p = 0, i, j; + const u8 *q; + + spin_lock(&demux->lock); + + if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */ + i = demux->tsbufp; + j = pktsize - i; + if (count < j) { + memcpy(&demux->tsbuf[i], buf, count); + demux->tsbufp += count; + goto bailout; + } + memcpy(&demux->tsbuf[i], buf, j); + if (demux->tsbuf[0] == 0x47) /* double check */ + dvb_dmx_swfilter_packet(demux, demux->tsbuf); + demux->tsbufp = 0; + p += j; + } + + while (1) { + p = find_next_packet(buf, p, count, pktsize); + if (p >= count) + break; + if (count - p < pktsize) + break; + + q = &buf[p]; + + if (pktsize == 204 && (*q == 0xB8)) { + memcpy(demux->tsbuf, q, 188); + demux->tsbuf[0] = 0x47; + q = demux->tsbuf; + } + dvb_dmx_swfilter_packet(demux, q); + p += pktsize; + } + + i = count - p; + if (i) { + memcpy(demux->tsbuf, &buf[p], i); + demux->tsbufp = i; + if (pktsize == 204 && demux->tsbuf[0] == 0xB8) + demux->tsbuf[0] = 0x47; + } + +bailout: + spin_unlock(&demux->lock); +} + +void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + _dvb_dmx_swfilter(demux, buf, count, 188); +} +EXPORT_SYMBOL(dvb_dmx_swfilter); + +void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + _dvb_dmx_swfilter(demux, buf, count, 204); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_204); + +static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) +{ + int i; + + for (i = 0; i < demux->filternum; i++) + if (demux->filter[i].state == DMX_STATE_FREE) + break; + + if (i == demux->filternum) + return NULL; + + demux->filter[i].state = DMX_STATE_ALLOCATED; + + return &demux->filter[i]; +} + +static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) +{ + int i; + + for (i = 0; i < demux->feednum; i++) + if (demux->feed[i].state == DMX_STATE_FREE) + break; + + if (i == demux->feednum) + return NULL; + + demux->feed[i].state = DMX_STATE_ALLOCATED; + + return &demux->feed[i]; +} + +static int dvb_demux_feed_find(struct dvb_demux_feed *feed) +{ + struct dvb_demux_feed *entry; + + list_for_each_entry(entry, &feed->demux->feed_list, list_head) + if (entry == feed) + return 1; + + return 0; +} + +static void dvb_demux_feed_add(struct dvb_demux_feed *feed) +{ + spin_lock_irq(&feed->demux->lock); + if (dvb_demux_feed_find(feed)) { + printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n", + __func__, feed->type, feed->state, feed->pid); + goto out; + } + + list_add(&feed->list_head, &feed->demux->feed_list); +out: + spin_unlock_irq(&feed->demux->lock); +} + +static void dvb_demux_feed_del(struct dvb_demux_feed *feed) +{ + spin_lock_irq(&feed->demux->lock); + if (!(dvb_demux_feed_find(feed))) { + printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n", + __func__, feed->type, feed->state, feed->pid); + goto out; + } + + list_del(&feed->list_head); +out: + spin_unlock_irq(&feed->demux->lock); +} + +static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, + enum dmx_ts_pes pes_type, + size_t circular_buffer_size, struct timespec timeout) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + + if (pid > DMX_MAX_PID) + return -EINVAL; + + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; + + if (ts_type & TS_DECODER) { + if (pes_type >= DMX_TS_PES_OTHER) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + if (demux->pesfilter[pes_type] && + demux->pesfilter[pes_type] != feed) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + demux->pesfilter[pes_type] = feed; + demux->pids[pes_type] = pid; + } + + dvb_demux_feed_add(feed); + + feed->pid = pid; + feed->buffer_size = circular_buffer_size; + feed->timeout = timeout; + feed->ts_type = ts_type; + feed->pes_type = pes_type; + + if (feed->buffer_size) { +#ifdef NOBUFS + feed->buffer = NULL; +#else + feed->buffer = vmalloc(feed->buffer_size); + if (!feed->buffer) { + mutex_unlock(&demux->mutex); + return -ENOMEM; + } +#endif + } + + feed->state = DMX_STATE_READY; + mutex_unlock(&demux->mutex); + + return 0; +} + +static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; + + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; + + if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + if (!demux->start_feed) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } + + if ((ret = demux->start_feed(feed)) < 0) { + mutex_unlock(&demux->mutex); + return ret; + } + + spin_lock_irq(&demux->lock); + ts_feed->is_filtering = 1; + feed->state = DMX_STATE_GO; + spin_unlock_irq(&demux->lock); + mutex_unlock(&demux->mutex); + + return 0; +} + +static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; + + mutex_lock(&demux->mutex); + + if (feed->state < DMX_STATE_GO) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + if (!demux->stop_feed) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } + + ret = demux->stop_feed(feed); + + spin_lock_irq(&demux->lock); + ts_feed->is_filtering = 0; + feed->state = DMX_STATE_ALLOCATED; + spin_unlock_irq(&demux->lock); + mutex_unlock(&demux->mutex); + + return ret; +} + +static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, + struct dmx_ts_feed **ts_feed, + dmx_ts_cb callback) +{ + struct dvb_demux *demux = (struct dvb_demux *)dmx; + struct dvb_demux_feed *feed; + + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; + + if (!(feed = dvb_dmx_feed_alloc(demux))) { + mutex_unlock(&demux->mutex); + return -EBUSY; + } + + feed->type = DMX_TYPE_TS; + feed->cb.ts = callback; + feed->demux = demux; + feed->pid = 0xffff; + feed->peslen = 0xfffa; + feed->buffer = NULL; + + (*ts_feed) = &feed->feed.ts; + (*ts_feed)->parent = dmx; + (*ts_feed)->priv = NULL; + (*ts_feed)->is_filtering = 0; + (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering; + (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; + (*ts_feed)->set = dmx_ts_feed_set; + + if (!(feed->filter = dvb_dmx_filter_alloc(demux))) { + feed->state = DMX_STATE_FREE; + mutex_unlock(&demux->mutex); + return -EBUSY; + } + + feed->filter->type = DMX_TYPE_TS; + feed->filter->feed = feed; + feed->filter->state = DMX_STATE_READY; + + mutex_unlock(&demux->mutex); + + return 0; +} + +static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, + struct dmx_ts_feed *ts_feed) +{ + struct dvb_demux *demux = (struct dvb_demux *)dmx; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + + mutex_lock(&demux->mutex); + + if (feed->state == DMX_STATE_FREE) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } +#ifndef NOBUFS + vfree(feed->buffer); + feed->buffer = NULL; +#endif + + feed->state = DMX_STATE_FREE; + feed->filter->state = DMX_STATE_FREE; + + dvb_demux_feed_del(feed); + + feed->pid = 0xffff; + + if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) + demux->pesfilter[feed->pes_type] = NULL; + + mutex_unlock(&demux->mutex); + return 0; +} + +/****************************************************************************** + * dmx_section_feed API calls + ******************************************************************************/ + +static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed, + struct dmx_section_filter **filter) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdemux = dvbdmxfeed->demux; + struct dvb_demux_filter *dvbdmxfilter; + + if (mutex_lock_interruptible(&dvbdemux->mutex)) + return -ERESTARTSYS; + + dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux); + if (!dvbdmxfilter) { + mutex_unlock(&dvbdemux->mutex); + return -EBUSY; + } + + spin_lock_irq(&dvbdemux->lock); + *filter = &dvbdmxfilter->filter; + (*filter)->parent = feed; + (*filter)->priv = NULL; + dvbdmxfilter->feed = dvbdmxfeed; + dvbdmxfilter->type = DMX_TYPE_SEC; + dvbdmxfilter->state = DMX_STATE_READY; + dvbdmxfilter->next = dvbdmxfeed->filter; + dvbdmxfeed->filter = dvbdmxfilter; + spin_unlock_irq(&dvbdemux->lock); + + mutex_unlock(&dvbdemux->mutex); + return 0; +} + +static int dmx_section_feed_set(struct dmx_section_feed *feed, + u16 pid, size_t circular_buffer_size, + int check_crc) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + if (pid > 0x1fff) + return -EINVAL; + + if (mutex_lock_interruptible(&dvbdmx->mutex)) + return -ERESTARTSYS; + + dvb_demux_feed_add(dvbdmxfeed); + + dvbdmxfeed->pid = pid; + dvbdmxfeed->buffer_size = circular_buffer_size; + dvbdmxfeed->feed.sec.check_crc = check_crc; + +#ifdef NOBUFS + dvbdmxfeed->buffer = NULL; +#else + dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size); + if (!dvbdmxfeed->buffer) { + mutex_unlock(&dvbdmx->mutex); + return -ENOMEM; + } +#endif + + dvbdmxfeed->state = DMX_STATE_READY; + mutex_unlock(&dvbdmx->mutex); + return 0; +} + +static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) +{ + int i; + struct dvb_demux_filter *f; + struct dmx_section_filter *sf; + u8 mask, mode, doneq; + + if (!(f = dvbdmxfeed->filter)) + return; + do { + sf = &f->filter; + doneq = 0; + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { + mode = sf->filter_mode[i]; + mask = sf->filter_mask[i]; + f->maskandmode[i] = mask & mode; + doneq |= f->maskandnotmode[i] = mask & ~mode; + } + f->doneq = doneq ? 1 : 0; + } while ((f = f->next)); +} + +static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + int ret; + + if (mutex_lock_interruptible(&dvbdmx->mutex)) + return -ERESTARTSYS; + + if (feed->is_filtering) { + mutex_unlock(&dvbdmx->mutex); + return -EBUSY; + } + + if (!dvbdmxfeed->filter) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + dvbdmxfeed->feed.sec.tsfeedp = 0; + dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; + dvbdmxfeed->feed.sec.secbufp = 0; + dvbdmxfeed->feed.sec.seclen = 0; + + if (!dvbdmx->start_feed) { + mutex_unlock(&dvbdmx->mutex); + return -ENODEV; + } + + prepare_secfilters(dvbdmxfeed); + + if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) { + mutex_unlock(&dvbdmx->mutex); + return ret; + } + + spin_lock_irq(&dvbdmx->lock); + feed->is_filtering = 1; + dvbdmxfeed->state = DMX_STATE_GO; + spin_unlock_irq(&dvbdmx->lock); + + mutex_unlock(&dvbdmx->mutex); + return 0; +} + +static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + int ret; + + mutex_lock(&dvbdmx->mutex); + + if (!dvbdmx->stop_feed) { + mutex_unlock(&dvbdmx->mutex); + return -ENODEV; + } + + ret = dvbdmx->stop_feed(dvbdmxfeed); + + spin_lock_irq(&dvbdmx->lock); + dvbdmxfeed->state = DMX_STATE_READY; + feed->is_filtering = 0; + spin_unlock_irq(&dvbdmx->lock); + + mutex_unlock(&dvbdmx->mutex); + return ret; +} + +static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, + struct dmx_section_filter *filter) +{ + struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + mutex_lock(&dvbdmx->mutex); + + if (dvbdmxfilter->feed != dvbdmxfeed) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + if (feed->is_filtering) + feed->stop_filtering(feed); + + spin_lock_irq(&dvbdmx->lock); + f = dvbdmxfeed->filter; + + if (f == dvbdmxfilter) { + dvbdmxfeed->filter = dvbdmxfilter->next; + } else { + while (f->next != dvbdmxfilter) + f = f->next; + f->next = f->next->next; + } + + dvbdmxfilter->state = DMX_STATE_FREE; + spin_unlock_irq(&dvbdmx->lock); + mutex_unlock(&dvbdmx->mutex); + return 0; +} + +static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, + struct dmx_section_feed **feed, + dmx_section_cb callback) +{ + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; + struct dvb_demux_feed *dvbdmxfeed; + + if (mutex_lock_interruptible(&dvbdmx->mutex)) + return -ERESTARTSYS; + + if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) { + mutex_unlock(&dvbdmx->mutex); + return -EBUSY; + } + + dvbdmxfeed->type = DMX_TYPE_SEC; + dvbdmxfeed->cb.sec = callback; + dvbdmxfeed->demux = dvbdmx; + dvbdmxfeed->pid = 0xffff; + dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; + dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; + dvbdmxfeed->feed.sec.tsfeedp = 0; + dvbdmxfeed->filter = NULL; + dvbdmxfeed->buffer = NULL; + + (*feed) = &dvbdmxfeed->feed.sec; + (*feed)->is_filtering = 0; + (*feed)->parent = demux; + (*feed)->priv = NULL; + + (*feed)->set = dmx_section_feed_set; + (*feed)->allocate_filter = dmx_section_feed_allocate_filter; + (*feed)->start_filtering = dmx_section_feed_start_filtering; + (*feed)->stop_filtering = dmx_section_feed_stop_filtering; + (*feed)->release_filter = dmx_section_feed_release_filter; + + mutex_unlock(&dvbdmx->mutex); + return 0; +} + +static int dvbdmx_release_section_feed(struct dmx_demux *demux, + struct dmx_section_feed *feed) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; + + mutex_lock(&dvbdmx->mutex); + + if (dvbdmxfeed->state == DMX_STATE_FREE) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } +#ifndef NOBUFS + vfree(dvbdmxfeed->buffer); + dvbdmxfeed->buffer = NULL; +#endif + dvbdmxfeed->state = DMX_STATE_FREE; + + dvb_demux_feed_del(dvbdmxfeed); + + dvbdmxfeed->pid = 0xffff; + + mutex_unlock(&dvbdmx->mutex); + return 0; +} + +/****************************************************************************** + * dvb_demux kernel data API calls + ******************************************************************************/ + +static int dvbdmx_open(struct dmx_demux *demux) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + if (dvbdemux->users >= MAX_DVB_DEMUX_USERS) + return -EUSERS; + + dvbdemux->users++; + return 0; +} + +static int dvbdmx_close(struct dmx_demux *demux) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + if (dvbdemux->users == 0) + return -ENODEV; + + dvbdemux->users--; + //FIXME: release any unneeded resources if users==0 + return 0; +} + +static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + void *p; + + if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) + return -EINVAL; + + p = memdup_user(buf, count); + if (IS_ERR(p)) + return PTR_ERR(p); + if (mutex_lock_interruptible(&dvbdemux->mutex)) { + kfree(p); + return -ERESTARTSYS; + } + dvb_dmx_swfilter(dvbdemux, p, count); + kfree(p); + mutex_unlock(&dvbdemux->mutex); + + if (signal_pending(current)) + return -EINTR; + return count; +} + +static int dvbdmx_add_frontend(struct dmx_demux *demux, + struct dmx_frontend *frontend) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + struct list_head *head = &dvbdemux->frontend_list; + + list_add(&(frontend->connectivity_list), head); + + return 0; +} + +static int dvbdmx_remove_frontend(struct dmx_demux *demux, + struct dmx_frontend *frontend) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + struct list_head *pos, *n, *head = &dvbdemux->frontend_list; + + list_for_each_safe(pos, n, head) { + if (DMX_FE_ENTRY(pos) == frontend) { + list_del(pos); + return 0; + } + } + + return -ENODEV; +} + +static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + if (list_empty(&dvbdemux->frontend_list)) + return NULL; + + return &dvbdemux->frontend_list; +} + +static int dvbdmx_connect_frontend(struct dmx_demux *demux, + struct dmx_frontend *frontend) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + if (demux->frontend) + return -EINVAL; + + mutex_lock(&dvbdemux->mutex); + + demux->frontend = frontend; + mutex_unlock(&dvbdemux->mutex); + return 0; +} + +static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + mutex_lock(&dvbdemux->mutex); + + demux->frontend = NULL; + mutex_unlock(&dvbdemux->mutex); + return 0; +} + +static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + memcpy(pids, dvbdemux->pids, 5 * sizeof(u16)); + return 0; +} + +int dvb_dmx_init(struct dvb_demux *dvbdemux) +{ + int i; + struct dmx_demux *dmx = &dvbdemux->dmx; + + dvbdemux->cnt_storage = NULL; + dvbdemux->users = 0; + dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); + + if (!dvbdemux->filter) + return -ENOMEM; + + dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed)); + if (!dvbdemux->feed) { + vfree(dvbdemux->filter); + dvbdemux->filter = NULL; + return -ENOMEM; + } + for (i = 0; i < dvbdemux->filternum; i++) { + dvbdemux->filter[i].state = DMX_STATE_FREE; + dvbdemux->filter[i].index = i; + } + for (i = 0; i < dvbdemux->feednum; i++) { + dvbdemux->feed[i].state = DMX_STATE_FREE; + dvbdemux->feed[i].index = i; + } + + dvbdemux->cnt_storage = vmalloc(MAX_PID + 1); + if (!dvbdemux->cnt_storage) + printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n"); + + INIT_LIST_HEAD(&dvbdemux->frontend_list); + + for (i = 0; i < DMX_TS_PES_OTHER; i++) { + dvbdemux->pesfilter[i] = NULL; + dvbdemux->pids[i] = 0xffff; + } + + INIT_LIST_HEAD(&dvbdemux->feed_list); + + dvbdemux->playing = 0; + dvbdemux->recording = 0; + dvbdemux->tsbufp = 0; + + if (!dvbdemux->check_crc32) + dvbdemux->check_crc32 = dvb_dmx_crc32; + + if (!dvbdemux->memcopy) + dvbdemux->memcopy = dvb_dmx_memcopy; + + dmx->frontend = NULL; + dmx->priv = dvbdemux; + dmx->open = dvbdmx_open; + dmx->close = dvbdmx_close; + dmx->write = dvbdmx_write; + dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed; + dmx->release_ts_feed = dvbdmx_release_ts_feed; + dmx->allocate_section_feed = dvbdmx_allocate_section_feed; + dmx->release_section_feed = dvbdmx_release_section_feed; + + dmx->add_frontend = dvbdmx_add_frontend; + dmx->remove_frontend = dvbdmx_remove_frontend; + dmx->get_frontends = dvbdmx_get_frontends; + dmx->connect_frontend = dvbdmx_connect_frontend; + dmx->disconnect_frontend = dvbdmx_disconnect_frontend; + dmx->get_pes_pids = dvbdmx_get_pes_pids; + + mutex_init(&dvbdemux->mutex); + spin_lock_init(&dvbdemux->lock); + + return 0; +} + +EXPORT_SYMBOL(dvb_dmx_init); + +void dvb_dmx_release(struct dvb_demux *dvbdemux) +{ + vfree(dvbdemux->cnt_storage); + vfree(dvbdemux->filter); + vfree(dvbdemux->feed); +} + +EXPORT_SYMBOL(dvb_dmx_release); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_demux.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_demux.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_demux.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_demux.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,149 @@ +/* + * dvb_demux.h: DVB kernel demux API + * + * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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. + * + */ + +#ifndef _DVB_DEMUX_H_ +#define _DVB_DEMUX_H_ + +#include +#include +#include +#include + +#include "demux.h" + +#define DMX_TYPE_TS 0 +#define DMX_TYPE_SEC 1 +#define DMX_TYPE_PES 2 + +#define DMX_STATE_FREE 0 +#define DMX_STATE_ALLOCATED 1 +#define DMX_STATE_SET 2 +#define DMX_STATE_READY 3 +#define DMX_STATE_GO 4 + +#define DVB_DEMUX_MASK_MAX 18 + +#define MAX_PID 0x1fff + +#define SPEED_PKTS_INTERVAL 50000 + +struct dvb_demux_filter { + struct dmx_section_filter filter; + u8 maskandmode[DMX_MAX_FILTER_SIZE]; + u8 maskandnotmode[DMX_MAX_FILTER_SIZE]; + int doneq; + + struct dvb_demux_filter *next; + struct dvb_demux_feed *feed; + int index; + int state; + int type; + + u16 hw_handle; + struct timer_list timer; +}; + +#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) + +struct dvb_demux_feed { + union { + struct dmx_ts_feed ts; + struct dmx_section_feed sec; + } feed; + + union { + dmx_ts_cb ts; + dmx_section_cb sec; + } cb; + + struct dvb_demux *demux; + void *priv; + int type; + int state; + u16 pid; + u8 *buffer; + int buffer_size; + + struct timespec timeout; + struct dvb_demux_filter *filter; + + int ts_type; + enum dmx_ts_pes pes_type; + + int cc; + int pusi_seen; /* prevents feeding of garbage from previous section */ + + u16 peslen; + + struct list_head list_head; + unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ +}; + +struct dvb_demux { + struct dmx_demux dmx; + void *priv; + int filternum; + int feednum; + int (*start_feed)(struct dvb_demux_feed *feed); + int (*stop_feed)(struct dvb_demux_feed *feed); + int (*write_to_decoder)(struct dvb_demux_feed *feed, + const u8 *buf, size_t len); + u32 (*check_crc32)(struct dvb_demux_feed *feed, + const u8 *buf, size_t len); + void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst, + const u8 *src, size_t len); + + int users; +#define MAX_DVB_DEMUX_USERS 10 + struct dvb_demux_filter *filter; + struct dvb_demux_feed *feed; + + struct list_head frontend_list; + + struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; + u16 pids[DMX_TS_PES_OTHER]; + int playing; + int recording; + +#define DMX_MAX_PID 0x2000 + struct list_head feed_list; + u8 tsbuf[204]; + int tsbufp; + + struct mutex mutex; + spinlock_t lock; + + uint8_t *cnt_storage; /* for TS continuity check */ + + struct timespec speed_last_time; /* for TS speed check */ + uint32_t speed_pkts_cnt; /* for TS speed check */ +}; + +int dvb_dmx_init(struct dvb_demux *dvbdemux); +void dvb_dmx_release(struct dvb_demux *dvbdemux); +void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, + size_t count); +void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); +void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, + size_t count); + +#endif /* _DVB_DEMUX_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvbdev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvbdev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvbdev.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvbdev.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,506 @@ +/* + * dvbdev.c + * + * Copyright (C) 2000 Ralph Metzler + * & Marcus Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dvbdev.h" + +static DEFINE_MUTEX(dvbdev_mutex); +static int dvbdev_debug; + +module_param(dvbdev_debug, int, 0644); +MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off)."); + +#define dprintk if (dvbdev_debug) printk + +static LIST_HEAD(dvb_adapter_list); +static DEFINE_MUTEX(dvbdev_register_lock); + +static const char * const dnames[] = { + "video", "audio", "sec", "frontend", "demux", "dvr", "ca", + "net", "osd" +}; + +#ifdef CONFIG_DVB_DYNAMIC_MINORS +#define MAX_DVB_MINORS 256 +#define DVB_MAX_IDS MAX_DVB_MINORS +#else +#define DVB_MAX_IDS 4 +#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) +#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) +#endif + +static struct class *dvb_class; + +static struct dvb_device *dvb_minors[MAX_DVB_MINORS]; +static DECLARE_RWSEM(minor_rwsem); + +static int dvb_device_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev; + + mutex_lock(&dvbdev_mutex); + down_read(&minor_rwsem); + dvbdev = dvb_minors[iminor(inode)]; + + if (dvbdev && dvbdev->fops) { + int err = 0; + const struct file_operations *old_fops; + + file->private_data = dvbdev; + old_fops = file->f_op; + file->f_op = fops_get(dvbdev->fops); + if (file->f_op == NULL) { + file->f_op = old_fops; + goto fail; + } + if(file->f_op->open) + err = file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + up_read(&minor_rwsem); + mutex_unlock(&dvbdev_mutex); + return err; + } +fail: + up_read(&minor_rwsem); + mutex_unlock(&dvbdev_mutex); + return -ENODEV; +} + + +static const struct file_operations dvb_device_fops = +{ + .owner = THIS_MODULE, + .open = dvb_device_open, + .llseek = noop_llseek, +}; + +static struct cdev dvb_device_cdev; + +int dvb_generic_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + + if (!dvbdev) + return -ENODEV; + + if (!dvbdev->users) + return -EBUSY; + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (!dvbdev->readers) + return -EBUSY; + dvbdev->readers--; + } else { + if (!dvbdev->writers) + return -EBUSY; + dvbdev->writers--; + } + + dvbdev->users--; + return 0; +} +EXPORT_SYMBOL(dvb_generic_open); + + +int dvb_generic_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + + if (!dvbdev) + return -ENODEV; + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + dvbdev->readers++; + } else { + dvbdev->writers++; + } + + dvbdev->users++; + return 0; +} +EXPORT_SYMBOL(dvb_generic_release); + + +long dvb_generic_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct dvb_device *dvbdev = file->private_data; + + if (!dvbdev) + return -ENODEV; + + if (!dvbdev->kernel_ioctl) + return -EINVAL; + + return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl); +} +EXPORT_SYMBOL(dvb_generic_ioctl); + + +static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) +{ + u32 id = 0; + + while (id < DVB_MAX_IDS) { + struct dvb_device *dev; + list_for_each_entry(dev, &adap->device_list, list_head) + if (dev->type == type && dev->id == id) + goto skip; + return id; +skip: + id++; + } + return -ENFILE; +} + + +int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, + const struct dvb_device *template, void *priv, int type) +{ + struct dvb_device *dvbdev; + struct file_operations *dvbdevfops; + struct device *clsdev; + int minor; + int id; + + mutex_lock(&dvbdev_register_lock); + + if ((id = dvbdev_get_free_id (adap, type)) < 0){ + mutex_unlock(&dvbdev_register_lock); + *pdvbdev = NULL; + printk(KERN_ERR "%s: couldn't find free device id\n", __func__); + return -ENFILE; + } + + *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); + + if (!dvbdev){ + mutex_unlock(&dvbdev_register_lock); + return -ENOMEM; + } + + dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); + + if (!dvbdevfops){ + kfree (dvbdev); + mutex_unlock(&dvbdev_register_lock); + return -ENOMEM; + } + + memcpy(dvbdev, template, sizeof(struct dvb_device)); + dvbdev->type = type; + dvbdev->id = id; + dvbdev->adapter = adap; + dvbdev->priv = priv; + dvbdev->fops = dvbdevfops; + init_waitqueue_head (&dvbdev->wait_queue); + + memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); + dvbdevfops->owner = adap->module; + + list_add_tail (&dvbdev->list_head, &adap->device_list); + + down_write(&minor_rwsem); +#ifdef CONFIG_DVB_DYNAMIC_MINORS + for (minor = 0; minor < MAX_DVB_MINORS; minor++) + if (dvb_minors[minor] == NULL) + break; + + if (minor == MAX_DVB_MINORS) { + kfree(dvbdevfops); + kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); + return -EINVAL; + } +#else + minor = nums2minor(adap->num, type, id); +#endif + + dvbdev->minor = minor; + dvb_minors[minor] = dvbdev; + up_write(&minor_rwsem); + + mutex_unlock(&dvbdev_register_lock); + + clsdev = device_create(dvb_class, adap->device, + MKDEV(DVB_MAJOR, minor), + dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); + if (IS_ERR(clsdev)) { + printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", + __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); + return PTR_ERR(clsdev); + } + + dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", + adap->num, dnames[type], id, minor, minor); + + return 0; +} +EXPORT_SYMBOL(dvb_register_device); + + +void dvb_unregister_device(struct dvb_device *dvbdev) +{ + if (!dvbdev) + return; + + down_write(&minor_rwsem); + dvb_minors[dvbdev->minor] = NULL; + up_write(&minor_rwsem); + + device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); + + list_del (&dvbdev->list_head); + kfree (dvbdev->fops); + kfree (dvbdev); +} +EXPORT_SYMBOL(dvb_unregister_device); + +static int dvbdev_check_free_adapter_num(int num) +{ + struct list_head *entry; + list_for_each(entry, &dvb_adapter_list) { + struct dvb_adapter *adap; + adap = list_entry(entry, struct dvb_adapter, list_head); + if (adap->num == num) + return 0; + } + return 1; +} + +static int dvbdev_get_free_adapter_num (void) +{ + int num = 0; + + while (num < DVB_MAX_ADAPTERS) { + if (dvbdev_check_free_adapter_num(num)) + return num; + num++; + } + + return -ENFILE; +} + + +int dvb_register_adapter(struct dvb_adapter *adap, const char *name, + struct module *module, struct device *device, + short *adapter_nums) +{ + int i, num; + + mutex_lock(&dvbdev_register_lock); + + for (i = 0; i < DVB_MAX_ADAPTERS; ++i) { + num = adapter_nums[i]; + if (num >= 0 && num < DVB_MAX_ADAPTERS) { + /* use the one the driver asked for */ + if (dvbdev_check_free_adapter_num(num)) + break; + } else { + num = dvbdev_get_free_adapter_num(); + break; + } + num = -1; + } + + if (num < 0) { + mutex_unlock(&dvbdev_register_lock); + return -ENFILE; + } + + memset (adap, 0, sizeof(struct dvb_adapter)); + INIT_LIST_HEAD (&adap->device_list); + + printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); + + adap->num = num; + adap->name = name; + adap->module = module; + adap->device = device; + adap->mfe_shared = 0; + adap->mfe_dvbdev = NULL; + mutex_init (&adap->mfe_lock); + + list_add_tail (&adap->list_head, &dvb_adapter_list); + + mutex_unlock(&dvbdev_register_lock); + + return num; +} +EXPORT_SYMBOL(dvb_register_adapter); + + +int dvb_unregister_adapter(struct dvb_adapter *adap) +{ + mutex_lock(&dvbdev_register_lock); + list_del (&adap->list_head); + mutex_unlock(&dvbdev_register_lock); + return 0; +} +EXPORT_SYMBOL(dvb_unregister_adapter); + +/* if the miracle happens and "generic_usercopy()" is included into + the kernel, then this can vanish. please don't make the mistake and + define this as video_usercopy(). this will introduce a dependecy + to the v4l "videodev.o" module, which is unnecessary for some + cards (ie. the budget dvb-cards don't need the v4l module...) */ +int dvb_usercopy(struct file *file, + unsigned int cmd, unsigned long arg, + int (*func)(struct file *file, + unsigned int cmd, void *arg)) +{ + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + + /* Copy arguments into temp kernel buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: + /* + * For this command, the pointer is actually an integer + * argument. + */ + parg = (void *) arg; + break; + case _IOC_READ: /* some v4l ioctls are marked wrong ... */ + case _IOC_WRITE: + case (_IOC_WRITE | _IOC_READ): + if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + parg = sbuf; + } else { + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; + } + + err = -EFAULT; + if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) + goto out; + break; + } + + /* call driver */ + mutex_lock(&dvbdev_mutex); + if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) + err = -EINVAL; + mutex_unlock(&dvbdev_mutex); + + if (err < 0) + goto out; + + /* Copy results into user buffer */ + switch (_IOC_DIR(cmd)) + { + case _IOC_READ: + case (_IOC_WRITE | _IOC_READ): + if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } + +out: + kfree(mbuf); + return err; +} + +static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct dvb_device *dvbdev = dev_get_drvdata(dev); + + add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num); + add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]); + add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id); + return 0; +} + +static char *dvb_devnode(struct device *dev, mode_t *mode) +{ + struct dvb_device *dvbdev = dev_get_drvdata(dev); + + return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d", + dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id); +} + + +static int __init init_dvbdev(void) +{ + int retval; + dev_t dev = MKDEV(DVB_MAJOR, 0); + + if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { + printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); + return retval; + } + + cdev_init(&dvb_device_cdev, &dvb_device_fops); + if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { + printk(KERN_ERR "dvb-core: unable register character device\n"); + goto error; + } + + dvb_class = class_create(THIS_MODULE, "dvb"); + if (IS_ERR(dvb_class)) { + retval = PTR_ERR(dvb_class); + goto error; + } + dvb_class->dev_uevent = dvb_uevent; + dvb_class->devnode = dvb_devnode; + return 0; + +error: + cdev_del(&dvb_device_cdev); + unregister_chrdev_region(dev, MAX_DVB_MINORS); + return retval; +} + + +static void __exit exit_dvbdev(void) +{ + class_destroy(dvb_class); + cdev_del(&dvb_device_cdev); + unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); +} + +subsys_initcall(init_dvbdev); +module_exit(exit_dvbdev); + +MODULE_DESCRIPTION("DVB Core Driver"); +MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvbdev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvbdev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvbdev.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvbdev.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,172 @@ +/* + * dvbdev.h + * + * Copyright (C) 2000 Ralph Metzler & Marcus Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Lesser Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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. + * + */ + +#ifndef _DVBDEV_H_ +#define _DVBDEV_H_ + +#include +#include +#include +#include + +#define DVB_MAJOR 212 + +#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0 + #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS +#else + #define DVB_MAX_ADAPTERS 8 +#endif + +#define DVB_UNSET (-1) + +#define DVB_DEVICE_VIDEO 0 +#define DVB_DEVICE_AUDIO 1 +#define DVB_DEVICE_SEC 2 +#define DVB_DEVICE_FRONTEND 3 +#define DVB_DEVICE_DEMUX 4 +#define DVB_DEVICE_DVR 5 +#define DVB_DEVICE_CA 6 +#define DVB_DEVICE_NET 7 +#define DVB_DEVICE_OSD 8 + +#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \ + static short adapter_nr[] = \ + {[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \ + module_param_array(adapter_nr, short, NULL, 0444); \ + MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers") + +struct dvb_frontend; + +struct dvb_adapter { + int num; + struct list_head list_head; + struct list_head device_list; + const char *name; + u8 proposed_mac [6]; + void* priv; + + struct device *device; + + struct module *module; + + int mfe_shared; /* indicates mutually exclusive frontends */ + struct dvb_device *mfe_dvbdev; /* frontend device in use */ + struct mutex mfe_lock; /* access lock for thread creation */ + + /* Allow the adapter/bridge driver to perform an action before and/or + * after the core handles an ioctl: + * + * DVB_FE_IOCTL_PRE indicates that the ioctl has not yet been handled. + * DVB_FE_IOCTL_POST indicates that the ioctl has been handled. + * + * When DVB_FE_IOCTL_PRE is passed to the callback as the stage arg: + * + * return 0 to allow dvb-core to handle the ioctl. + * return a positive int to prevent dvb-core from handling the ioctl, + * and exit without error. + * return a negative int to prevent dvb-core from handling the ioctl, + * and return that value as an error. + * + * When DVB_FE_IOCTL_POST is passed to the callback as the stage arg: + * + * return 0 to allow the dvb_frontend ioctl handler to exit normally. + * return a negative int to cause the dvb_frontend ioctl handler to + * return that value as an error. + */ +#define DVB_FE_IOCTL_PRE 0 +#define DVB_FE_IOCTL_POST 1 + int (*fe_ioctl_override)(struct dvb_frontend *fe, + unsigned int cmd, void *parg, + unsigned int stage); +}; + + +struct dvb_device { + struct list_head list_head; + const struct file_operations *fops; + struct dvb_adapter *adapter; + int type; + int minor; + u32 id; + + /* in theory, 'users' can vanish now, + but I don't want to change too much now... */ + int readers; + int writers; + int users; + + wait_queue_head_t wait_queue; + /* don't really need those !? -- FIXME: use video_usercopy */ + int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg); + + void *priv; +}; + + +extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name, + struct module *module, struct device *device, + short *adapter_nums); +extern int dvb_unregister_adapter (struct dvb_adapter *adap); + +extern int dvb_register_device (struct dvb_adapter *adap, + struct dvb_device **pdvbdev, + const struct dvb_device *template, + void *priv, + int type); + +extern void dvb_unregister_device (struct dvb_device *dvbdev); + +extern int dvb_generic_open (struct inode *inode, struct file *file); +extern int dvb_generic_release (struct inode *inode, struct file *file); +extern long dvb_generic_ioctl (struct file *file, + unsigned int cmd, unsigned long arg); + +/* we don't mess with video_usercopy() any more, +we simply define out own dvb_usercopy(), which will hopefully become +generic_usercopy() someday... */ + +extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, + int (*func)(struct file *file, unsigned int cmd, void *arg)); + +/** generic DVB attach function. */ +#ifdef CONFIG_MEDIA_ATTACH +#define dvb_attach(FUNCTION, ARGS...) ({ \ + void *__r = NULL; \ + typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ + if (__a) { \ + __r = (void *) __a(ARGS); \ + if (__r == NULL) \ + symbol_put(FUNCTION); \ + } else { \ + printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \ + } \ + __r; \ +}) + +#else +#define dvb_attach(FUNCTION, ARGS...) ({ \ + FUNCTION(ARGS); \ +}) + +#endif + +#endif /* #ifndef _DVBDEV_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_filter.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_filter.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_filter.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_filter.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,603 @@ +#include +#include +#include +#include "dvb_filter.h" + +#if 0 +static unsigned int bitrates[3][16] = +{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, + {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, + {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; +#endif + +static u32 freq[4] = {480, 441, 320, 0}; + +static unsigned int ac3_bitrates[32] = + {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, + 0,0,0,0,0,0,0,0,0,0,0,0,0}; + +static u32 ac3_frames[3][32] = + {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, + 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, + 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, + 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + + + +#if 0 +static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, + void (*pes_write)(u8 *buf, int count, void *data), + void *priv) +{ + dvb_filter_ipack_init(pa, IPACKS, pes_write); + dvb_filter_ipack_init(pv, IPACKS, pes_write); + pa->pid = pida; + pv->pid = pidv; + pa->data = priv; + pv->data = priv; +} +#endif + +#if 0 +static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) +{ + u8 off = 0; + + if (!buf || !p ){ + printk("NULL POINTER IDIOT\n"); + return; + } + if (buf[1]&PAY_START) { + if (p->plength == MMAX_PLENGTH-6 && p->found>6){ + p->plength = p->found-6; + p->found = 0; + send_ipack(p); + dvb_filter_ipack_reset(p); + } + } + if (buf[3] & ADAPT_FIELD) { // adaptation field? + off = buf[4] + 1; + if (off+4 > 187) return; + } + dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p); +} +#endif + +#if 0 +/* needs 5 byte input, returns picture coding type*/ +static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr) +{ + u8 pct; + + if (pr) printk( "Pic header: "); + pic->temporal_reference[field] = (( headr[0] << 2 ) | + (headr[1] & 0x03) )& 0x03ff; + if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]); + + pct = ( headr[1] >> 2 ) & 0x07; + pic->picture_coding_type[field] = pct; + if (pr) { + switch(pct){ + case I_FRAME: + printk( " I-FRAME"); + break; + case B_FRAME: + printk( " B-FRAME"); + break; + case P_FRAME: + printk( " P-FRAME"); + break; + } + } + + + pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) | + ( (headr[3] & 0x1F) << 11) ) & 0xffff; + + if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay); + + pic->picture_header_parameter = ( headr[3] & 0xe0 ) | + ((headr[4] & 0x80) >> 3); + + if ( pct == B_FRAME ){ + pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f; + } + if (pr) printk( " pic head param: 0x%x", + pic->picture_header_parameter); + + return pct; +} +#endif + +#if 0 +/* needs 4 byte input */ +static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr) +{ + if (pr) printk("GOP header: "); + + pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) | + ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff; + + if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F, + ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F), + ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F)); + + if ( ( headr[3] & 0x40 ) != 0 ){ + pic->closed_gop = 1; + } else { + pic->closed_gop = 0; + } + if (pr) printk("closed: %d", pic->closed_gop); + + if ( ( headr[3] & 0x20 ) != 0 ){ + pic->broken_link = 1; + } else { + pic->broken_link = 0; + } + if (pr) printk(" broken: %d\n", pic->broken_link); + + return 0; +} +#endif + +#if 0 +/* needs 8 byte input */ +static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr) +{ + int sw; + int form = -1; + + if (pr) printk("Reading sequence header\n"); + + vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); + vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); + + sw = (int)((headr[3]&0xF0) >> 4) ; + + switch( sw ){ + case 1: + if (pr) + printk("Videostream: ASPECT: 1:1"); + vi->aspect_ratio = 100; + break; + case 2: + if (pr) + printk("Videostream: ASPECT: 4:3"); + vi->aspect_ratio = 133; + break; + case 3: + if (pr) + printk("Videostream: ASPECT: 16:9"); + vi->aspect_ratio = 177; + break; + case 4: + if (pr) + printk("Videostream: ASPECT: 2.21:1"); + vi->aspect_ratio = 221; + break; + + case 5 ... 15: + if (pr) + printk("Videostream: ASPECT: reserved"); + vi->aspect_ratio = 0; + break; + + default: + vi->aspect_ratio = 0; + return -1; + } + + if (pr) + printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); + + sw = (int)(headr[3]&0x0F); + + switch ( sw ) { + case 1: + if (pr) + printk(" FRate: 23.976 fps"); + vi->framerate = 23976; + form = -1; + break; + case 2: + if (pr) + printk(" FRate: 24 fps"); + vi->framerate = 24000; + form = -1; + break; + case 3: + if (pr) + printk(" FRate: 25 fps"); + vi->framerate = 25000; + form = VIDEO_MODE_PAL; + break; + case 4: + if (pr) + printk(" FRate: 29.97 fps"); + vi->framerate = 29970; + form = VIDEO_MODE_NTSC; + break; + case 5: + if (pr) + printk(" FRate: 30 fps"); + vi->framerate = 30000; + form = VIDEO_MODE_NTSC; + break; + case 6: + if (pr) + printk(" FRate: 50 fps"); + vi->framerate = 50000; + form = VIDEO_MODE_PAL; + break; + case 7: + if (pr) + printk(" FRate: 60 fps"); + vi->framerate = 60000; + form = VIDEO_MODE_NTSC; + break; + } + + vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03); + + vi->vbv_buffer_size + = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5); + + if (pr){ + printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000); + printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size)); + printk("\n"); + } + + vi->video_format = form; + + return 0; +} +#endif + + +#if 0 +static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr) +{ + u8 *headr; + int found = 0; + int c = 0; + + while (found < 4 && c+4 < count){ + u8 *b; + + b = mbuf+c; + if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 + && b[3] == 0xb3) found = 4; + else { + c++; + } + } + + if (! found) return -1; + c += 4; + if (c+12 >= count) return -1; + headr = mbuf+c; + if (read_sequence_header(headr, vi, pr) < 0) return -1; + vi->off = c-4; + return 0; +} +#endif + + +#if 0 +static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) +{ + u8 *headr; + int found = 0; + int c = 0; + int fr = 0; + + while (found < 2 && c < count){ + u8 b[2]; + memcpy( b, mbuf+c, 2); + + if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) + found = 2; + else { + c++; + } + } + + if (!found) return -1; + + if (c+3 >= count) return -1; + headr = mbuf+c; + + ai->layer = (headr[1] & 0x06) >> 1; + + if (pr) + printk("Audiostream: Layer: %d", 4-ai->layer); + + + ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; + + if (pr){ + if (ai->bit_rate == 0) + printk(" Bit rate: free"); + else if (ai->bit_rate == 0xf) + printk(" BRate: reserved"); + else + printk(" BRate: %d kb/s", ai->bit_rate/1000); + } + + fr = (headr[2] & 0x0c ) >> 2; + ai->frequency = freq[fr]*100; + if (pr){ + if (ai->frequency == 3) + printk(" Freq: reserved\n"); + else + printk(" Freq: %d kHz\n",ai->frequency); + + } + ai->off = c; + return 0; +} +#endif + + +int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) +{ + u8 *headr; + int found = 0; + int c = 0; + u8 frame = 0; + int fr = 0; + + while ( !found && c < count){ + u8 *b = mbuf+c; + + if ( b[0] == 0x0b && b[1] == 0x77 ) + found = 1; + else { + c++; + } + } + + if (!found) return -1; + if (pr) + printk("Audiostream: AC3"); + + ai->off = c; + if (c+5 >= count) return -1; + + ai->layer = 0; // 0 for AC3 + headr = mbuf+c+2; + + frame = (headr[2]&0x3f); + ai->bit_rate = ac3_bitrates[frame >> 1]*1000; + + if (pr) + printk(" BRate: %d kb/s", (int) ai->bit_rate/1000); + + ai->frequency = (headr[2] & 0xc0 ) >> 6; + fr = (headr[2] & 0xc0 ) >> 6; + ai->frequency = freq[fr]*100; + if (pr) printk (" Freq: %d Hz\n", (int) ai->frequency); + + + ai->framesize = ac3_frames[fr][frame >> 1]; + if ((frame & 1) && (fr == 1)) ai->framesize++; + ai->framesize = ai->framesize << 1; + if (pr) printk (" Framesize %d\n",(int) ai->framesize); + + + return 0; +} +EXPORT_SYMBOL(dvb_filter_get_ac3info); + + +#if 0 +static u8 *skip_pes_header(u8 **bufp) +{ + u8 *inbuf = *bufp; + u8 *buf = inbuf; + u8 *pts = NULL; + int skip = 0; + + static const int mpeg1_skip_table[16] = { + 1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff + }; + + + if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ + if (buf[7] & PTS_ONLY) + pts = buf+9; + else pts = NULL; + buf = inbuf + 9 + inbuf[8]; + } else { /* mpeg1 */ + for (buf = inbuf + 6; *buf == 0xff; buf++) + if (buf == inbuf + 6 + 16) { + break; + } + if ((*buf & 0xc0) == 0x40) + buf += 2; + skip = mpeg1_skip_table [*buf >> 4]; + if (skip == 5 || skip == 10) pts = buf; + else pts = NULL; + + buf += mpeg1_skip_table [*buf >> 4]; + } + + *bufp = buf; + return pts; +} +#endif + +#if 0 +static void initialize_quant_matrix( u32 *matrix ) +{ + int i; + + matrix[0] = 0x08101013; + matrix[1] = 0x10131616; + matrix[2] = 0x16161616; + matrix[3] = 0x1a181a1b; + matrix[4] = 0x1b1b1a1a; + matrix[5] = 0x1a1a1b1b; + matrix[6] = 0x1b1d1d1d; + matrix[7] = 0x2222221d; + matrix[8] = 0x1d1d1b1b; + matrix[9] = 0x1d1d2020; + matrix[10] = 0x22222526; + matrix[11] = 0x25232322; + matrix[12] = 0x23262628; + matrix[13] = 0x28283030; + matrix[14] = 0x2e2e3838; + matrix[15] = 0x3a454553; + + for ( i = 16 ; i < 32 ; i++ ) + matrix[i] = 0x10101010; +} +#endif + +#if 0 +static void initialize_mpg_picture(struct mpg_picture *pic) +{ + int i; + + /* set MPEG1 */ + pic->mpeg1_flag = 1; + pic->profile_and_level = 0x4A ; /* MP@LL */ + pic->progressive_sequence = 1; + pic->low_delay = 0; + + pic->sequence_display_extension_flag = 0; + for ( i = 0 ; i < 4 ; i++ ){ + pic->frame_centre_horizontal_offset[i] = 0; + pic->frame_centre_vertical_offset[i] = 0; + } + pic->last_frame_centre_horizontal_offset = 0; + pic->last_frame_centre_vertical_offset = 0; + + pic->picture_display_extension_flag[0] = 0; + pic->picture_display_extension_flag[1] = 0; + pic->sequence_header_flag = 0; + pic->gop_flag = 0; + pic->sequence_end_flag = 0; +} +#endif + +#if 0 +static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic ) +{ + int16_t last_h_offset; + int16_t last_v_offset; + + int16_t *p_h_offset; + int16_t *p_v_offset; + + if ( pic->mpeg1_flag ){ + pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE; + pic->top_field_first = 0; + pic->repeat_first_field = 0; + pic->progressive_frame = 1; + pic->picture_coding_parameter = 0x000010; + } + + /* Reset flag */ + pic->picture_display_extension_flag[field_type] = 0; + + last_h_offset = pic->last_frame_centre_horizontal_offset; + last_v_offset = pic->last_frame_centre_vertical_offset; + if ( field_type == FIRST_FIELD ){ + p_h_offset = pic->frame_centre_horizontal_offset; + p_v_offset = pic->frame_centre_vertical_offset; + *p_h_offset = last_h_offset; + *(p_h_offset + 1) = last_h_offset; + *(p_h_offset + 2) = last_h_offset; + *p_v_offset = last_v_offset; + *(p_v_offset + 1) = last_v_offset; + *(p_v_offset + 2) = last_v_offset; + } else { + pic->frame_centre_horizontal_offset[3] = last_h_offset; + pic->frame_centre_vertical_offset[3] = last_v_offset; + } +} +#endif + +#if 0 +static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type) +{ + pic->picture_header = 0; + pic->sequence_header_data + = ( INIT_HORIZONTAL_SIZE << 20 ) + | ( INIT_VERTICAL_SIZE << 8 ) + | ( INIT_ASPECT_RATIO << 4 ) + | ( INIT_FRAME_RATE ); + pic->mpeg1_flag = 0; + pic->vinfo.horizontal_size + = INIT_DISP_HORIZONTAL_SIZE; + pic->vinfo.vertical_size + = INIT_DISP_VERTICAL_SIZE; + pic->picture_display_extension_flag[field_type] + = 0; + pic->pts_flag[field_type] = 0; + + pic->sequence_gop_header = 0; + pic->picture_header = 0; + pic->sequence_header_flag = 0; + pic->gop_flag = 0; + pic->sequence_end_flag = 0; + pic->sequence_display_extension_flag = 0; + pic->last_frame_centre_horizontal_offset = 0; + pic->last_frame_centre_vertical_offset = 0; + pic->channel = chan; +} +#endif + +void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, + dvb_filter_pes2ts_cb_t *cb, void *priv) +{ + unsigned char *buf=p2ts->buf; + + buf[0]=0x47; + buf[1]=(pid>>8); + buf[2]=pid&0xff; + p2ts->cc=0; + p2ts->cb=cb; + p2ts->priv=priv; +} +EXPORT_SYMBOL(dvb_filter_pes2ts_init); + +int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, + int len, int payload_start) +{ + unsigned char *buf=p2ts->buf; + int ret=0, rest; + + //len=6+((pes[4]<<8)|pes[5]); + + if (payload_start) + buf[1]|=0x40; + else + buf[1]&=~0x40; + while (len>=184) { + buf[3]=0x10|((p2ts->cc++)&0x0f); + memcpy(buf+4, pes, 184); + if ((ret=p2ts->cb(p2ts->priv, buf))) + return ret; + len-=184; pes+=184; + buf[1]&=~0x40; + } + if (!len) + return 0; + buf[3]=0x30|((p2ts->cc++)&0x0f); + rest=183-len; + if (rest) { + buf[5]=0x00; + if (rest-1) + memset(buf+6, 0xff, rest-1); + } + buf[4]=rest; + memcpy(buf+5+rest, pes, len); + return p2ts->cb(p2ts->priv, buf); +} +EXPORT_SYMBOL(dvb_filter_pes2ts); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_filter.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_filter.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_filter.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_filter.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,246 @@ +/* + * dvb_filter.h + * + * Copyright (C) 2003 Convergence GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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. + */ + +#ifndef _DVB_FILTER_H_ +#define _DVB_FILTER_H_ + +#include + +#include "demux.h" + +typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); + +struct dvb_filter_pes2ts { + unsigned char buf[188]; + unsigned char cc; + dvb_filter_pes2ts_cb_t *cb; + void *priv; +}; + +void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, + dvb_filter_pes2ts_cb_t *cb, void *priv); + +int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, + int len, int payload_start); + + +#define PROG_STREAM_MAP 0xBC +#define PRIVATE_STREAM1 0xBD +#define PADDING_STREAM 0xBE +#define PRIVATE_STREAM2 0xBF +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define DVB_PICTURE_START 0x00 +#define DVB_USER_START 0xb2 +#define DVB_SEQUENCE_HEADER 0xb3 +#define DVB_SEQUENCE_ERROR 0xb4 +#define DVB_EXTENSION_START 0xb5 +#define DVB_SEQUENCE_END 0xb7 +#define DVB_GOP_START 0xb8 +#define DVB_EXCEPT_SLICE 0xb0 + +#define SEQUENCE_EXTENSION 0x01 +#define SEQUENCE_DISPLAY_EXTENSION 0x02 +#define PICTURE_CODING_EXTENSION 0x08 +#define QUANT_MATRIX_EXTENSION 0x03 +#define PICTURE_DISPLAY_EXTENSION 0x07 + +#define I_FRAME 0x01 +#define B_FRAME 0x02 +#define P_FRAME 0x03 + +/* Initialize sequence_data */ +#define INIT_HORIZONTAL_SIZE 720 +#define INIT_VERTICAL_SIZE 576 +#define INIT_ASPECT_RATIO 0x02 +#define INIT_FRAME_RATE 0x03 +#define INIT_DISP_HORIZONTAL_SIZE 540 +#define INIT_DISP_VERTICAL_SIZE 576 + + +//flags2 +#define PTS_DTS_FLAGS 0xC0 +#define ESCR_FLAG 0x20 +#define ES_RATE_FLAG 0x10 +#define DSM_TRICK_FLAG 0x08 +#define ADD_CPY_FLAG 0x04 +#define PES_CRC_FLAG 0x02 +#define PES_EXT_FLAG 0x01 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 + +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + +#define MAX_PLENGTH 0xFFFF +#define MMAX_PLENGTH (256*MAX_PLENGTH) + +#ifndef IPACKS +#define IPACKS 2048 +#endif + +struct ipack { + int size; + int found; + u8 *buf; + u8 cid; + u32 plength; + u8 plen[2]; + u8 flag1; + u8 flag2; + u8 hlength; + u8 pts[5]; + u16 *pid; + int mpeg; + u8 check; + int which; + int done; + void *data; + void (*func)(u8 *buf, int size, void *priv); + int count; + int repack_subids; +}; + +struct dvb_video_info { + u32 horizontal_size; + u32 vertical_size; + u32 aspect_ratio; + u32 framerate; + u32 video_format; + u32 bit_rate; + u32 comp_bit_rate; + u32 vbv_buffer_size; + s16 vbv_delay; + u32 CSPF; + u32 off; +}; + +#define OFF_SIZE 4 +#define FIRST_FIELD 0 +#define SECOND_FIELD 1 +#define VIDEO_FRAME_PICTURE 0x03 + +struct mpg_picture { + int channel; + struct dvb_video_info vinfo; + u32 *sequence_gop_header; + u32 *picture_header; + s32 time_code; + int low_delay; + int closed_gop; + int broken_link; + int sequence_header_flag; + int gop_flag; + int sequence_end_flag; + + u8 profile_and_level; + s32 picture_coding_parameter; + u32 matrix[32]; + s8 matrix_change_flag; + + u8 picture_header_parameter; + /* bit 0 - 2: bwd f code + bit 3 : fpb vector + bit 4 - 6: fwd f code + bit 7 : fpf vector */ + + int mpeg1_flag; + int progressive_sequence; + int sequence_display_extension_flag; + u32 sequence_header_data; + s16 last_frame_centre_horizontal_offset; + s16 last_frame_centre_vertical_offset; + + u32 pts[2]; /* [0] 1st field, [1] 2nd field */ + int top_field_first; + int repeat_first_field; + int progressive_frame; + int bank; + int forward_bank; + int backward_bank; + int compress; + s16 frame_centre_horizontal_offset[OFF_SIZE]; + /* [0-2] 1st field, [3] 2nd field */ + s16 frame_centre_vertical_offset[OFF_SIZE]; + /* [0-2] 1st field, [3] 2nd field */ + s16 temporal_reference[2]; + /* [0] 1st field, [1] 2nd field */ + + s8 picture_coding_type[2]; + /* [0] 1st field, [1] 2nd field */ + s8 picture_structure[2]; + /* [0] 1st field, [1] 2nd field */ + s8 picture_display_extension_flag[2]; + /* [0] 1st field, [1] 2nd field */ + /* picture_display_extenion() 0:no 1:exit*/ + s8 pts_flag[2]; + /* [0] 1st field, [1] 2nd field */ +}; + +struct dvb_audio_info { + int layer; + u32 bit_rate; + u32 frequency; + u32 mode; + u32 mode_extension ; + u32 emphasis; + u32 framesize; + u32 off; +}; + +int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr); + + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_frontend.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_frontend.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_frontend.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_frontend.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2165 @@ +/* + * dvb_frontend.c: DVB frontend tuning interface/thread + * + * + * Copyright (C) 1999-2001 Ralph Metzler + * Marcus Metzler + * Holger Waechtler + * for convergence integrated media GmbH + * + * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup) + * + * 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, or (at your option) any later version. + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvbdev.h" +#include + +static int dvb_frontend_debug; +static int dvb_shutdown_timeout; +static int dvb_force_auto_inversion; +static int dvb_override_tune_delay; +static int dvb_powerdown_on_sleep = 1; +static int dvb_mfe_wait_time = 5; + +module_param_named(frontend_debug, dvb_frontend_debug, int, 0644); +MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off)."); +module_param(dvb_shutdown_timeout, int, 0644); +MODULE_PARM_DESC(dvb_shutdown_timeout, "wait seconds after close() before suspending hardware"); +module_param(dvb_force_auto_inversion, int, 0644); +MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always"); +module_param(dvb_override_tune_delay, int, 0644); +MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt"); +module_param(dvb_powerdown_on_sleep, int, 0644); +MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)"); +module_param(dvb_mfe_wait_time, int, 0644); +MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to seconds on open() for multi-frontend to become available (default:5 seconds)"); + +#define dprintk if (dvb_frontend_debug) printk + +#define FESTATE_IDLE 1 +#define FESTATE_RETUNE 2 +#define FESTATE_TUNING_FAST 4 +#define FESTATE_TUNING_SLOW 8 +#define FESTATE_TUNED 16 +#define FESTATE_ZIGZAG_FAST 32 +#define FESTATE_ZIGZAG_SLOW 64 +#define FESTATE_DISEQC 128 +#define FESTATE_ERROR 256 +#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC) +#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST) +#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW) +#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW) + +#define FE_ALGO_HW 1 +/* + * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling. + * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune. + * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress. + * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower. + * FESTATE_TUNED. The frontend has successfully locked on. + * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it. + * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower. + * FESTATE_DISEQC. A DISEQC command has just been issued. + * FESTATE_WAITFORLOCK. When we're waiting for a lock. + * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan. + * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan. + * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again. + */ + +#define DVB_FE_NO_EXIT 0 +#define DVB_FE_NORMAL_EXIT 1 +#define DVB_FE_DEVICE_REMOVED 2 + +static DEFINE_MUTEX(frontend_mutex); + +struct dvb_frontend_private { + + /* thread/frontend values */ + struct dvb_device *dvbdev; + struct dvb_frontend_parameters parameters_in; + struct dvb_frontend_parameters parameters_out; + struct dvb_fe_events events; + struct semaphore sem; + struct list_head list_head; + wait_queue_head_t wait_queue; + struct task_struct *thread; + unsigned long release_jiffies; + unsigned int exit; + unsigned int wakeup; + fe_status_t status; + unsigned long tune_mode_flags; + unsigned int delay; + unsigned int reinitialise; + int tone; + int voltage; + + /* swzigzag values */ + unsigned int state; + unsigned int bending; + int lnb_drift; + unsigned int inversion; + unsigned int auto_step; + unsigned int auto_sub_step; + unsigned int started_auto_step; + unsigned int min_delay; + unsigned int max_drift; + unsigned int step_size; + int quality; + unsigned int check_wrapped; + enum dvbfe_search algo_status; +}; + +static void dvb_frontend_wakeup(struct dvb_frontend *fe); + +static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_fe_events *events = &fepriv->events; + struct dvb_frontend_event *e; + int wp; + + dprintk ("%s\n", __func__); + + if (mutex_lock_interruptible (&events->mtx)) + return; + + wp = (events->eventw + 1) % MAX_EVENT; + + if (wp == events->eventr) { + events->overflow = 1; + events->eventr = (events->eventr + 1) % MAX_EVENT; + } + + e = &events->events[events->eventw]; + + if (status & FE_HAS_LOCK) + if (fe->ops.get_frontend) + fe->ops.get_frontend(fe, &fepriv->parameters_out); + + e->parameters = fepriv->parameters_out; + + events->eventw = wp; + + mutex_unlock(&events->mtx); + + e->status = status; + + wake_up_interruptible (&events->wait_queue); +} + +static int dvb_frontend_get_event(struct dvb_frontend *fe, + struct dvb_frontend_event *event, int flags) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_fe_events *events = &fepriv->events; + + dprintk ("%s\n", __func__); + + if (events->overflow) { + events->overflow = 0; + return -EOVERFLOW; + } + + if (events->eventw == events->eventr) { + int ret; + + if (flags & O_NONBLOCK) + return -EWOULDBLOCK; + + up(&fepriv->sem); + + ret = wait_event_interruptible (events->wait_queue, + events->eventw != events->eventr); + + if (down_interruptible (&fepriv->sem)) + return -ERESTARTSYS; + + if (ret < 0) + return ret; + } + + if (mutex_lock_interruptible (&events->mtx)) + return -ERESTARTSYS; + + memcpy (event, &events->events[events->eventr], + sizeof(struct dvb_frontend_event)); + + events->eventr = (events->eventr + 1) % MAX_EVENT; + + mutex_unlock(&events->mtx); + + return 0; +} + +static void dvb_frontend_init(struct dvb_frontend *fe) +{ + dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n", + fe->dvb->num, + fe->id, + fe->ops.info.name); + + if (fe->ops.init) + fe->ops.init(fe); + if (fe->ops.tuner_ops.init) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.init(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } +} + +void dvb_frontend_reinitialise(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + fepriv->reinitialise = 1; + dvb_frontend_wakeup(fe); +} +EXPORT_SYMBOL(dvb_frontend_reinitialise); + +static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked) +{ + int q2; + + dprintk ("%s\n", __func__); + + if (locked) + (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256; + else + (fepriv->quality) = (fepriv->quality * 220 + 0) / 256; + + q2 = fepriv->quality - 128; + q2 *= q2; + + fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128); +} + +/** + * Performs automatic twiddling of frontend parameters. + * + * @param fe The frontend concerned. + * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT + * @returns Number of complete iterations that have been performed. + */ +static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped) +{ + int autoinversion; + int ready = 0; + int fe_set_err = 0; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + int original_inversion = fepriv->parameters_in.inversion; + u32 original_frequency = fepriv->parameters_in.frequency; + + /* are we using autoinversion? */ + autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && + (fepriv->parameters_in.inversion == INVERSION_AUTO)); + + /* setup parameters correctly */ + while(!ready) { + /* calculate the lnb_drift */ + fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size; + + /* wrap the auto_step if we've exceeded the maximum drift */ + if (fepriv->lnb_drift > fepriv->max_drift) { + fepriv->auto_step = 0; + fepriv->auto_sub_step = 0; + fepriv->lnb_drift = 0; + } + + /* perform inversion and +/- zigzag */ + switch(fepriv->auto_sub_step) { + case 0: + /* try with the current inversion and current drift setting */ + ready = 1; + break; + + case 1: + if (!autoinversion) break; + + fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; + ready = 1; + break; + + case 2: + if (fepriv->lnb_drift == 0) break; + + fepriv->lnb_drift = -fepriv->lnb_drift; + ready = 1; + break; + + case 3: + if (fepriv->lnb_drift == 0) break; + if (!autoinversion) break; + + fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; + fepriv->lnb_drift = -fepriv->lnb_drift; + ready = 1; + break; + + default: + fepriv->auto_step++; + fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */ + break; + } + + if (!ready) fepriv->auto_sub_step++; + } + + /* if this attempt would hit where we started, indicate a complete + * iteration has occurred */ + if ((fepriv->auto_step == fepriv->started_auto_step) && + (fepriv->auto_sub_step == 0) && check_wrapped) { + return 1; + } + + dprintk("%s: drift:%i inversion:%i auto_step:%i " + "auto_sub_step:%i started_auto_step:%i\n", + __func__, fepriv->lnb_drift, fepriv->inversion, + fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step); + + /* set the frontend itself */ + fepriv->parameters_in.frequency += fepriv->lnb_drift; + if (autoinversion) + fepriv->parameters_in.inversion = fepriv->inversion; + if (fe->ops.set_frontend) + fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in); + fepriv->parameters_out = fepriv->parameters_in; + if (fe_set_err < 0) { + fepriv->state = FESTATE_ERROR; + return fe_set_err; + } + + fepriv->parameters_in.frequency = original_frequency; + fepriv->parameters_in.inversion = original_inversion; + + fepriv->auto_sub_step++; + return 0; +} + +static void dvb_frontend_swzigzag(struct dvb_frontend *fe) +{ + fe_status_t s = 0; + int retval = 0; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + /* if we've got no parameters, just keep idling */ + if (fepriv->state & FESTATE_IDLE) { + fepriv->delay = 3*HZ; + fepriv->quality = 0; + return; + } + + /* in SCAN mode, we just set the frontend when asked and leave it alone */ + if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { + if (fepriv->state & FESTATE_RETUNE) { + if (fe->ops.set_frontend) + retval = fe->ops.set_frontend(fe, + &fepriv->parameters_in); + fepriv->parameters_out = fepriv->parameters_in; + if (retval < 0) + fepriv->state = FESTATE_ERROR; + else + fepriv->state = FESTATE_TUNED; + } + fepriv->delay = 3*HZ; + fepriv->quality = 0; + return; + } + + /* get the frontend status */ + if (fepriv->state & FESTATE_RETUNE) { + s = 0; + } else { + if (fe->ops.read_status) + fe->ops.read_status(fe, &s); + if (s != fepriv->status) { + dvb_frontend_add_event(fe, s); + fepriv->status = s; + } + } + + /* if we're not tuned, and we have a lock, move to the TUNED state */ + if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + fepriv->state = FESTATE_TUNED; + + /* if we're tuned, then we have determined the correct inversion */ + if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && + (fepriv->parameters_in.inversion == INVERSION_AUTO)) { + fepriv->parameters_in.inversion = fepriv->inversion; + } + return; + } + + /* if we are tuned already, check we're still locked */ + if (fepriv->state & FESTATE_TUNED) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + + /* we're tuned, and the lock is still good... */ + if (s & FE_HAS_LOCK) { + return; + } else { /* if we _WERE_ tuned, but now don't have a lock */ + fepriv->state = FESTATE_ZIGZAG_FAST; + fepriv->started_auto_step = fepriv->auto_step; + fepriv->check_wrapped = 0; + } + } + + /* don't actually do anything if we're in the LOSTLOCK state, + * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ + if ((fepriv->state & FESTATE_LOSTLOCK) && + (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + return; + } + + /* don't do anything if we're in the DISEQC state, since this + * might be someone with a motorized dish controlled by DISEQC. + * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ + if (fepriv->state & FESTATE_DISEQC) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + return; + } + + /* if we're in the RETUNE state, set everything up for a brand + * new scan, keeping the current inversion setting, as the next + * tune is _very_ likely to require the same */ + if (fepriv->state & FESTATE_RETUNE) { + fepriv->lnb_drift = 0; + fepriv->auto_step = 0; + fepriv->auto_sub_step = 0; + fepriv->started_auto_step = 0; + fepriv->check_wrapped = 0; + } + + /* fast zigzag. */ + if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { + fepriv->delay = fepriv->min_delay; + + /* perform a tune */ + retval = dvb_frontend_swzigzag_autotune(fe, + fepriv->check_wrapped); + if (retval < 0) { + return; + } else if (retval) { + /* OK, if we've run out of trials at the fast speed. + * Drop back to slow for the _next_ attempt */ + fepriv->state = FESTATE_SEARCHING_SLOW; + fepriv->started_auto_step = fepriv->auto_step; + return; + } + fepriv->check_wrapped = 1; + + /* if we've just retuned, enter the ZIGZAG_FAST state. + * This ensures we cannot return from an + * FE_SET_FRONTEND ioctl before the first frontend tune + * occurs */ + if (fepriv->state & FESTATE_RETUNE) { + fepriv->state = FESTATE_TUNING_FAST; + } + } + + /* slow zigzag */ + if (fepriv->state & FESTATE_SEARCHING_SLOW) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + + /* Note: don't bother checking for wrapping; we stay in this + * state until we get a lock */ + dvb_frontend_swzigzag_autotune(fe, 0); + } +} + +static int dvb_frontend_is_exiting(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + if (fepriv->exit != DVB_FE_NO_EXIT) + return 1; + + if (fepriv->dvbdev->writers == 1) + if (time_after(jiffies, fepriv->release_jiffies + + dvb_shutdown_timeout * HZ)) + return 1; + + return 0; +} + +static int dvb_frontend_should_wakeup(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + if (fepriv->wakeup) { + fepriv->wakeup = 0; + return 1; + } + return dvb_frontend_is_exiting(fe); +} + +static void dvb_frontend_wakeup(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + fepriv->wakeup = 1; + wake_up_interruptible(&fepriv->wait_queue); +} + +static int dvb_frontend_thread(void *data) +{ + struct dvb_frontend *fe = data; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + unsigned long timeout; + fe_status_t s; + enum dvbfe_algo algo; + + struct dvb_frontend_parameters *params; + + dprintk("%s\n", __func__); + + fepriv->check_wrapped = 0; + fepriv->quality = 0; + fepriv->delay = 3*HZ; + fepriv->status = 0; + fepriv->wakeup = 0; + fepriv->reinitialise = 0; + + dvb_frontend_init(fe); + + set_freezable(); + while (1) { + up(&fepriv->sem); /* is locked when we enter the thread... */ +restart: + timeout = wait_event_interruptible_timeout(fepriv->wait_queue, + dvb_frontend_should_wakeup(fe) || kthread_should_stop() + || freezing(current), + fepriv->delay); + + if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { + /* got signal or quitting */ + fepriv->exit = DVB_FE_NORMAL_EXIT; + break; + } + + if (try_to_freeze()) + goto restart; + + if (down_interruptible(&fepriv->sem)) + break; + + if (fepriv->reinitialise) { + dvb_frontend_init(fe); + if (fepriv->tone != -1) { + fe->ops.set_tone(fe, fepriv->tone); + } + if (fepriv->voltage != -1) { + fe->ops.set_voltage(fe, fepriv->voltage); + } + fepriv->reinitialise = 0; + } + + /* do an iteration of the tuning loop */ + if (fe->ops.get_frontend_algo) { + algo = fe->ops.get_frontend_algo(fe); + switch (algo) { + case DVBFE_ALGO_HW: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__); + params = NULL; /* have we been asked to RETUNE ? */ + + if (fepriv->state & FESTATE_RETUNE) { + dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); + params = &fepriv->parameters_in; + fepriv->state = FESTATE_TUNED; + } + + if (fe->ops.tune) + fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); + if (params) + fepriv->parameters_out = *params; + + if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) { + dprintk("%s: state changed, adding current state\n", __func__); + dvb_frontend_add_event(fe, s); + fepriv->status = s; + } + break; + case DVBFE_ALGO_SW: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__); + dvb_frontend_swzigzag(fe); + break; + case DVBFE_ALGO_CUSTOM: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state); + if (fepriv->state & FESTATE_RETUNE) { + dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__); + fepriv->state = FESTATE_TUNED; + } + /* Case where we are going to search for a carrier + * User asked us to retune again for some reason, possibly + * requesting a search with a new set of parameters + */ + if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) { + if (fe->ops.search) { + fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in); + /* We did do a search as was requested, the flags are + * now unset as well and has the flags wrt to search. + */ + } else { + fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN; + } + } + /* Track the carrier if the search was successful */ + if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { + if (fe->ops.track) + fe->ops.track(fe, &fepriv->parameters_in); + } else { + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + fepriv->delay = HZ / 2; + } + fepriv->parameters_out = fepriv->parameters_in; + fe->ops.read_status(fe, &s); + if (s != fepriv->status) { + dvb_frontend_add_event(fe, s); /* update event list */ + fepriv->status = s; + if (!(s & FE_HAS_LOCK)) { + fepriv->delay = HZ / 10; + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + } else { + fepriv->delay = 60 * HZ; + } + } + break; + default: + dprintk("%s: UNDEFINED ALGO !\n", __func__); + break; + } + } else { + dvb_frontend_swzigzag(fe); + } + } + + if (dvb_powerdown_on_sleep) { + if (fe->ops.set_voltage) + fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); + if (fe->ops.tuner_ops.sleep) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.sleep(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + if (fe->ops.sleep) + fe->ops.sleep(fe); + } + + fepriv->thread = NULL; + if (kthread_should_stop()) + fepriv->exit = DVB_FE_DEVICE_REMOVED; + else + fepriv->exit = DVB_FE_NO_EXIT; + mb(); + + dvb_frontend_wakeup(fe); + return 0; +} + +static void dvb_frontend_stop(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + dprintk ("%s\n", __func__); + + fepriv->exit = DVB_FE_NORMAL_EXIT; + mb(); + + if (!fepriv->thread) + return; + + kthread_stop(fepriv->thread); + + sema_init(&fepriv->sem, 1); + fepriv->state = FESTATE_IDLE; + + /* paranoia check in case a signal arrived */ + if (fepriv->thread) + printk("dvb_frontend_stop: warning: thread %p won't exit\n", + fepriv->thread); +} + +s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime) +{ + return ((curtime.tv_usec < lasttime.tv_usec) ? + 1000000 - lasttime.tv_usec + curtime.tv_usec : + curtime.tv_usec - lasttime.tv_usec); +} +EXPORT_SYMBOL(timeval_usec_diff); + +static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec) +{ + curtime->tv_usec += add_usec; + if (curtime->tv_usec >= 1000000) { + curtime->tv_usec -= 1000000; + curtime->tv_sec++; + } +} + +/* + * Sleep until gettimeofday() > waketime + add_usec + * This needs to be as precise as possible, but as the delay is + * usually between 2ms and 32ms, it is done using a scheduled msleep + * followed by usleep (normally a busy-wait loop) for the remainder + */ +void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec) +{ + struct timeval lasttime; + s32 delta, newdelta; + + timeval_usec_add(waketime, add_usec); + + do_gettimeofday(&lasttime); + delta = timeval_usec_diff(lasttime, *waketime); + if (delta > 2500) { + msleep((delta - 1500) / 1000); + do_gettimeofday(&lasttime); + newdelta = timeval_usec_diff(lasttime, *waketime); + delta = (newdelta > delta) ? 0 : newdelta; + } + if (delta > 0) + udelay(delta); +} +EXPORT_SYMBOL(dvb_frontend_sleep_until); + +static int dvb_frontend_start(struct dvb_frontend *fe) +{ + int ret; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct task_struct *fe_thread; + + dprintk ("%s\n", __func__); + + if (fepriv->thread) { + if (fepriv->exit == DVB_FE_NO_EXIT) + return 0; + else + dvb_frontend_stop (fe); + } + + if (signal_pending(current)) + return -EINTR; + if (down_interruptible (&fepriv->sem)) + return -EINTR; + + fepriv->state = FESTATE_IDLE; + fepriv->exit = DVB_FE_NO_EXIT; + fepriv->thread = NULL; + mb(); + + fe_thread = kthread_run(dvb_frontend_thread, fe, + "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id); + if (IS_ERR(fe_thread)) { + ret = PTR_ERR(fe_thread); + printk("dvb_frontend_start: failed to start kthread (%d)\n", ret); + up(&fepriv->sem); + return ret; + } + fepriv->thread = fe_thread; + return 0; +} + +static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, + u32 *freq_min, u32 *freq_max) +{ + *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); + + if (fe->ops.info.frequency_max == 0) + *freq_max = fe->ops.tuner_ops.info.frequency_max; + else if (fe->ops.tuner_ops.info.frequency_max == 0) + *freq_max = fe->ops.info.frequency_max; + else + *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); + + if (*freq_min == 0 || *freq_max == 0) + printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", + fe->dvb->num,fe->id); +} + +static int dvb_frontend_check_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *parms) +{ + u32 freq_min; + u32 freq_max; + + /* range check: frequency */ + dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max); + if ((freq_min && parms->frequency < freq_min) || + (freq_max && parms->frequency > freq_max)) { + printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n", + fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max); + return -EINVAL; + } + + /* range check: symbol rate */ + if (fe->ops.info.type == FE_QPSK) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + + } else if (fe->ops.info.type == FE_QAM) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, fe->id, parms->u.qam.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + } + + /* check for supported modulation */ + if (fe->ops.info.type == FE_QAM && + (parms->u.qam.modulation > QAM_AUTO || + !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) { + printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n", + fe->dvb->num, fe->id, parms->u.qam.modulation); + return -EINVAL; + } + + return 0; +} + +static int dvb_frontend_clear_cache(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int i; + + memset(c, 0, sizeof(struct dtv_frontend_properties)); + + c->state = DTV_CLEAR; + c->delivery_system = SYS_UNDEFINED; + c->inversion = INVERSION_AUTO; + c->fec_inner = FEC_AUTO; + c->transmission_mode = TRANSMISSION_MODE_AUTO; + c->bandwidth_hz = BANDWIDTH_AUTO; + c->guard_interval = GUARD_INTERVAL_AUTO; + c->hierarchy = HIERARCHY_AUTO; + c->symbol_rate = QAM_AUTO; + c->code_rate_HP = FEC_AUTO; + c->code_rate_LP = FEC_AUTO; + + c->isdbt_partial_reception = -1; + c->isdbt_sb_mode = -1; + c->isdbt_sb_subchannel = -1; + c->isdbt_sb_segment_idx = -1; + c->isdbt_sb_segment_count = -1; + c->isdbt_layer_enabled = 0x7; + for (i = 0; i < 3; i++) { + c->layer[i].fec = FEC_AUTO; + c->layer[i].modulation = QAM_AUTO; + c->layer[i].interleaving = -1; + c->layer[i].segment_count = -1; + } + + return 0; +} + +#define _DTV_CMD(n, s, b) \ +[n] = { \ + .name = #n, \ + .cmd = n, \ + .set = s,\ + .buffer = b \ +} + +static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { + _DTV_CMD(DTV_TUNE, 1, 0), + _DTV_CMD(DTV_CLEAR, 1, 0), + + /* Set */ + _DTV_CMD(DTV_FREQUENCY, 1, 0), + _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0), + _DTV_CMD(DTV_MODULATION, 1, 0), + _DTV_CMD(DTV_INVERSION, 1, 0), + _DTV_CMD(DTV_DISEQC_MASTER, 1, 1), + _DTV_CMD(DTV_SYMBOL_RATE, 1, 0), + _DTV_CMD(DTV_INNER_FEC, 1, 0), + _DTV_CMD(DTV_VOLTAGE, 1, 0), + _DTV_CMD(DTV_TONE, 1, 0), + _DTV_CMD(DTV_PILOT, 1, 0), + _DTV_CMD(DTV_ROLLOFF, 1, 0), + _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0), + _DTV_CMD(DTV_HIERARCHY, 1, 0), + _DTV_CMD(DTV_CODE_RATE_HP, 1, 0), + _DTV_CMD(DTV_CODE_RATE_LP, 1, 0), + _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0), + _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0), + + _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0), + _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0), + _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0), + _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0), + _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0), + _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0), + + _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 0, 0), + _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 0, 0), + _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 0, 0), + _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 0, 0), + _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0), + _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0), + + _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0), + _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0), + + /* Get */ + _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1), + _DTV_CMD(DTV_API_VERSION, 0, 0), + _DTV_CMD(DTV_CODE_RATE_HP, 0, 0), + _DTV_CMD(DTV_CODE_RATE_LP, 0, 0), + _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0), + _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0), + _DTV_CMD(DTV_HIERARCHY, 0, 0), +}; + +static void dtv_property_dump(struct dtv_property *tvp) +{ + int i; + + if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { + printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n", + __func__, tvp->cmd); + return; + } + + dprintk("%s() tvp.cmd = 0x%08x (%s)\n" + ,__func__ + ,tvp->cmd + ,dtv_cmds[ tvp->cmd ].name); + + if(dtv_cmds[ tvp->cmd ].buffer) { + + dprintk("%s() tvp.u.buffer.len = 0x%02x\n" + ,__func__ + ,tvp->u.buffer.len); + + for(i = 0; i < tvp->u.buffer.len; i++) + dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n" + ,__func__ + ,i + ,tvp->u.buffer.data[i]); + + } else + dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data); +} + +static int is_legacy_delivery_system(fe_delivery_system_t s) +{ + if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || + (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) || + (s == SYS_ATSC)) + return 1; + + return 0; +} + +/* Synchronise the legacy tuning parameters into the cache, so that demodulator + * drivers can use a single set_frontend tuning function, regardless of whether + * it's being used for the legacy or new API, reducing code and complexity. + */ +static void dtv_property_cache_sync(struct dvb_frontend *fe, + struct dtv_frontend_properties *c, + const struct dvb_frontend_parameters *p) +{ + c->frequency = p->frequency; + c->inversion = p->inversion; + + switch (fe->ops.info.type) { + case FE_QPSK: + c->modulation = QPSK; /* implied for DVB-S in legacy API */ + c->rolloff = ROLLOFF_35;/* implied for DVB-S */ + c->symbol_rate = p->u.qpsk.symbol_rate; + c->fec_inner = p->u.qpsk.fec_inner; + c->delivery_system = SYS_DVBS; + break; + case FE_QAM: + c->symbol_rate = p->u.qam.symbol_rate; + c->fec_inner = p->u.qam.fec_inner; + c->modulation = p->u.qam.modulation; + c->delivery_system = SYS_DVBC_ANNEX_AC; + break; + case FE_OFDM: + if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + c->bandwidth_hz = 6000000; + else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + c->bandwidth_hz = 7000000; + else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + c->bandwidth_hz = 8000000; + else + /* Including BANDWIDTH_AUTO */ + c->bandwidth_hz = 0; + c->code_rate_HP = p->u.ofdm.code_rate_HP; + c->code_rate_LP = p->u.ofdm.code_rate_LP; + c->modulation = p->u.ofdm.constellation; + c->transmission_mode = p->u.ofdm.transmission_mode; + c->guard_interval = p->u.ofdm.guard_interval; + c->hierarchy = p->u.ofdm.hierarchy_information; + c->delivery_system = SYS_DVBT; + break; + case FE_ATSC: + c->modulation = p->u.vsb.modulation; + if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) + c->delivery_system = SYS_ATSC; + else + c->delivery_system = SYS_DVBC_ANNEX_B; + break; + } +} + +/* Ensure the cached values are set correctly in the frontend + * legacy tuning structures, for the advanced tuning API. + */ +static void dtv_property_legacy_params_sync(struct dvb_frontend *fe) +{ + const struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_frontend_parameters *p = &fepriv->parameters_in; + + p->frequency = c->frequency; + p->inversion = c->inversion; + + switch (fe->ops.info.type) { + case FE_QPSK: + dprintk("%s() Preparing QPSK req\n", __func__); + p->u.qpsk.symbol_rate = c->symbol_rate; + p->u.qpsk.fec_inner = c->fec_inner; + break; + case FE_QAM: + dprintk("%s() Preparing QAM req\n", __func__); + p->u.qam.symbol_rate = c->symbol_rate; + p->u.qam.fec_inner = c->fec_inner; + p->u.qam.modulation = c->modulation; + break; + case FE_OFDM: + dprintk("%s() Preparing OFDM req\n", __func__); + if (c->bandwidth_hz == 6000000) + p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + else if (c->bandwidth_hz == 7000000) + p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + else if (c->bandwidth_hz == 8000000) + p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + else + p->u.ofdm.bandwidth = BANDWIDTH_AUTO; + p->u.ofdm.code_rate_HP = c->code_rate_HP; + p->u.ofdm.code_rate_LP = c->code_rate_LP; + p->u.ofdm.constellation = c->modulation; + p->u.ofdm.transmission_mode = c->transmission_mode; + p->u.ofdm.guard_interval = c->guard_interval; + p->u.ofdm.hierarchy_information = c->hierarchy; + break; + case FE_ATSC: + dprintk("%s() Preparing VSB req\n", __func__); + p->u.vsb.modulation = c->modulation; + break; + } +} + +/* Ensure the cached values are set correctly in the frontend + * legacy tuning structures, for the legacy tuning API. + */ +static void dtv_property_adv_params_sync(struct dvb_frontend *fe) +{ + const struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_frontend_parameters *p = &fepriv->parameters_in; + + p->frequency = c->frequency; + p->inversion = c->inversion; + + switch(c->modulation) { + case PSK_8: + case APSK_16: + case APSK_32: + case QPSK: + p->u.qpsk.symbol_rate = c->symbol_rate; + p->u.qpsk.fec_inner = c->fec_inner; + break; + default: + break; + } + + /* Fake out a generic DVB-T request so we pass validation in the ioctl */ + if ((c->delivery_system == SYS_ISDBT) || + (c->delivery_system == SYS_DVBT2)) { + p->u.ofdm.constellation = QAM_AUTO; + p->u.ofdm.code_rate_HP = FEC_AUTO; + p->u.ofdm.code_rate_LP = FEC_AUTO; + p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; + if (c->bandwidth_hz == 8000000) + p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + else if (c->bandwidth_hz == 7000000) + p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + else if (c->bandwidth_hz == 6000000) + p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + else + p->u.ofdm.bandwidth = BANDWIDTH_AUTO; + } +} + +static void dtv_property_cache_submit(struct dvb_frontend *fe) +{ + const struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + /* For legacy delivery systems we don't need the delivery_system to + * be specified, but we populate the older structures from the cache + * so we can call set_frontend on older drivers. + */ + if(is_legacy_delivery_system(c->delivery_system)) { + + dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation); + dtv_property_legacy_params_sync(fe); + + } else { + dprintk("%s() adv, modulation = %d\n", __func__, c->modulation); + + /* For advanced delivery systems / modulation types ... + * we seed the lecacy dvb_frontend_parameters structure + * so that the sanity checking code later in the IOCTL processing + * can validate our basic frequency ranges, symbolrates, modulation + * etc. + */ + dtv_property_adv_params_sync(fe); + } +} + +static int dvb_frontend_ioctl_legacy(struct file *file, + unsigned int cmd, void *parg); +static int dvb_frontend_ioctl_properties(struct file *file, + unsigned int cmd, void *parg); + +static int dtv_property_process_get(struct dvb_frontend *fe, + struct dtv_property *tvp, + struct file *file) +{ + const struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_frontend_properties cdetected; + int r; + + /* + * If the driver implements a get_frontend function, then convert + * detected parameters to S2API properties. + */ + if (fe->ops.get_frontend) { + cdetected = *c; + dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out); + c = &cdetected; + } + + switch(tvp->cmd) { + case DTV_FREQUENCY: + tvp->u.data = c->frequency; + break; + case DTV_MODULATION: + tvp->u.data = c->modulation; + break; + case DTV_BANDWIDTH_HZ: + tvp->u.data = c->bandwidth_hz; + break; + case DTV_INVERSION: + tvp->u.data = c->inversion; + break; + case DTV_SYMBOL_RATE: + tvp->u.data = c->symbol_rate; + break; + case DTV_INNER_FEC: + tvp->u.data = c->fec_inner; + break; + case DTV_PILOT: + tvp->u.data = c->pilot; + break; + case DTV_ROLLOFF: + tvp->u.data = c->rolloff; + break; + case DTV_DELIVERY_SYSTEM: + tvp->u.data = c->delivery_system; + break; + case DTV_VOLTAGE: + tvp->u.data = c->voltage; + break; + case DTV_TONE: + tvp->u.data = c->sectone; + break; + case DTV_API_VERSION: + tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR; + break; + case DTV_CODE_RATE_HP: + tvp->u.data = c->code_rate_HP; + break; + case DTV_CODE_RATE_LP: + tvp->u.data = c->code_rate_LP; + break; + case DTV_GUARD_INTERVAL: + tvp->u.data = c->guard_interval; + break; + case DTV_TRANSMISSION_MODE: + tvp->u.data = c->transmission_mode; + break; + case DTV_HIERARCHY: + tvp->u.data = c->hierarchy; + break; + + /* ISDB-T Support here */ + case DTV_ISDBT_PARTIAL_RECEPTION: + tvp->u.data = c->isdbt_partial_reception; + break; + case DTV_ISDBT_SOUND_BROADCASTING: + tvp->u.data = c->isdbt_sb_mode; + break; + case DTV_ISDBT_SB_SUBCHANNEL_ID: + tvp->u.data = c->isdbt_sb_subchannel; + break; + case DTV_ISDBT_SB_SEGMENT_IDX: + tvp->u.data = c->isdbt_sb_segment_idx; + break; + case DTV_ISDBT_SB_SEGMENT_COUNT: + tvp->u.data = c->isdbt_sb_segment_count; + break; + case DTV_ISDBT_LAYER_ENABLED: + tvp->u.data = c->isdbt_layer_enabled; + break; + case DTV_ISDBT_LAYERA_FEC: + tvp->u.data = c->layer[0].fec; + break; + case DTV_ISDBT_LAYERA_MODULATION: + tvp->u.data = c->layer[0].modulation; + break; + case DTV_ISDBT_LAYERA_SEGMENT_COUNT: + tvp->u.data = c->layer[0].segment_count; + break; + case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: + tvp->u.data = c->layer[0].interleaving; + break; + case DTV_ISDBT_LAYERB_FEC: + tvp->u.data = c->layer[1].fec; + break; + case DTV_ISDBT_LAYERB_MODULATION: + tvp->u.data = c->layer[1].modulation; + break; + case DTV_ISDBT_LAYERB_SEGMENT_COUNT: + tvp->u.data = c->layer[1].segment_count; + break; + case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: + tvp->u.data = c->layer[1].interleaving; + break; + case DTV_ISDBT_LAYERC_FEC: + tvp->u.data = c->layer[2].fec; + break; + case DTV_ISDBT_LAYERC_MODULATION: + tvp->u.data = c->layer[2].modulation; + break; + case DTV_ISDBT_LAYERC_SEGMENT_COUNT: + tvp->u.data = c->layer[2].segment_count; + break; + case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: + tvp->u.data = c->layer[2].interleaving; + break; + case DTV_ISDBS_TS_ID: + tvp->u.data = c->isdbs_ts_id; + break; + case DTV_DVBT2_PLP_ID: + tvp->u.data = c->dvbt2_plp_id; + break; + default: + return -EINVAL; + } + + /* Allow the frontend to override outgoing properties */ + if (fe->ops.get_property) { + r = fe->ops.get_property(fe, tvp); + if (r < 0) + return r; + } + + dtv_property_dump(tvp); + + return 0; +} + +static int dtv_property_process_set(struct dvb_frontend *fe, + struct dtv_property *tvp, + struct file *file) +{ + int r = 0; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + dtv_property_dump(tvp); + + /* Allow the frontend to validate incoming properties */ + if (fe->ops.set_property) { + r = fe->ops.set_property(fe, tvp); + if (r < 0) + return r; + } + + switch(tvp->cmd) { + case DTV_CLEAR: + /* Reset a cache of data specific to the frontend here. This does + * not effect hardware. + */ + dvb_frontend_clear_cache(fe); + dprintk("%s() Flushing property cache\n", __func__); + break; + case DTV_TUNE: + /* interpret the cache of data, build either a traditional frontend + * tunerequest so we can pass validation in the FE_SET_FRONTEND + * ioctl. + */ + c->state = tvp->cmd; + dprintk("%s() Finalised property cache\n", __func__); + dtv_property_cache_submit(fe); + + r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND, + &fepriv->parameters_in); + break; + case DTV_FREQUENCY: + c->frequency = tvp->u.data; + break; + case DTV_MODULATION: + c->modulation = tvp->u.data; + break; + case DTV_BANDWIDTH_HZ: + c->bandwidth_hz = tvp->u.data; + break; + case DTV_INVERSION: + c->inversion = tvp->u.data; + break; + case DTV_SYMBOL_RATE: + c->symbol_rate = tvp->u.data; + break; + case DTV_INNER_FEC: + c->fec_inner = tvp->u.data; + break; + case DTV_PILOT: + c->pilot = tvp->u.data; + break; + case DTV_ROLLOFF: + c->rolloff = tvp->u.data; + break; + case DTV_DELIVERY_SYSTEM: + c->delivery_system = tvp->u.data; + break; + case DTV_VOLTAGE: + c->voltage = tvp->u.data; + r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE, + (void *)c->voltage); + break; + case DTV_TONE: + c->sectone = tvp->u.data; + r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE, + (void *)c->sectone); + break; + case DTV_CODE_RATE_HP: + c->code_rate_HP = tvp->u.data; + break; + case DTV_CODE_RATE_LP: + c->code_rate_LP = tvp->u.data; + break; + case DTV_GUARD_INTERVAL: + c->guard_interval = tvp->u.data; + break; + case DTV_TRANSMISSION_MODE: + c->transmission_mode = tvp->u.data; + break; + case DTV_HIERARCHY: + c->hierarchy = tvp->u.data; + break; + + /* ISDB-T Support here */ + case DTV_ISDBT_PARTIAL_RECEPTION: + c->isdbt_partial_reception = tvp->u.data; + break; + case DTV_ISDBT_SOUND_BROADCASTING: + c->isdbt_sb_mode = tvp->u.data; + break; + case DTV_ISDBT_SB_SUBCHANNEL_ID: + c->isdbt_sb_subchannel = tvp->u.data; + break; + case DTV_ISDBT_SB_SEGMENT_IDX: + c->isdbt_sb_segment_idx = tvp->u.data; + break; + case DTV_ISDBT_SB_SEGMENT_COUNT: + c->isdbt_sb_segment_count = tvp->u.data; + break; + case DTV_ISDBT_LAYER_ENABLED: + c->isdbt_layer_enabled = tvp->u.data; + break; + case DTV_ISDBT_LAYERA_FEC: + c->layer[0].fec = tvp->u.data; + break; + case DTV_ISDBT_LAYERA_MODULATION: + c->layer[0].modulation = tvp->u.data; + break; + case DTV_ISDBT_LAYERA_SEGMENT_COUNT: + c->layer[0].segment_count = tvp->u.data; + break; + case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: + c->layer[0].interleaving = tvp->u.data; + break; + case DTV_ISDBT_LAYERB_FEC: + c->layer[1].fec = tvp->u.data; + break; + case DTV_ISDBT_LAYERB_MODULATION: + c->layer[1].modulation = tvp->u.data; + break; + case DTV_ISDBT_LAYERB_SEGMENT_COUNT: + c->layer[1].segment_count = tvp->u.data; + break; + case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: + c->layer[1].interleaving = tvp->u.data; + break; + case DTV_ISDBT_LAYERC_FEC: + c->layer[2].fec = tvp->u.data; + break; + case DTV_ISDBT_LAYERC_MODULATION: + c->layer[2].modulation = tvp->u.data; + break; + case DTV_ISDBT_LAYERC_SEGMENT_COUNT: + c->layer[2].segment_count = tvp->u.data; + break; + case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: + c->layer[2].interleaving = tvp->u.data; + break; + case DTV_ISDBS_TS_ID: + c->isdbs_ts_id = tvp->u.data; + break; + case DTV_DVBT2_PLP_ID: + c->dvbt2_plp_id = tvp->u.data; + break; + default: + return -EINVAL; + } + + return r; +} + +static int dvb_frontend_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + int err = -EOPNOTSUPP; + + dprintk("%s (%d)\n", __func__, _IOC_NR(cmd)); + + if (fepriv->exit != DVB_FE_NO_EXIT) + return -ENODEV; + + if ((file->f_flags & O_ACCMODE) == O_RDONLY && + (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT || + cmd == FE_DISEQC_RECV_SLAVE_REPLY)) + return -EPERM; + + if (down_interruptible (&fepriv->sem)) + return -ERESTARTSYS; + + if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) + err = dvb_frontend_ioctl_properties(file, cmd, parg); + else { + c->state = DTV_UNDEFINED; + err = dvb_frontend_ioctl_legacy(file, cmd, parg); + } + + up(&fepriv->sem); + return err; +} + +static int dvb_frontend_ioctl_properties(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int err = 0; + + struct dtv_properties *tvps = NULL; + struct dtv_property *tvp = NULL; + int i; + + dprintk("%s\n", __func__); + + if(cmd == FE_SET_PROPERTY) { + tvps = (struct dtv_properties __user *)parg; + + dprintk("%s() properties.num = %d\n", __func__, tvps->num); + dprintk("%s() properties.props = %p\n", __func__, tvps->props); + + /* Put an arbitrary limit on the number of messages that can + * be sent at once */ + if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) + return -EINVAL; + + tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); + if (!tvp) { + err = -ENOMEM; + goto out; + } + + if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_set(fe, tvp + i, file); + if (err < 0) + goto out; + (tvp + i)->result = err; + } + + if (c->state == DTV_TUNE) + dprintk("%s() Property cache is full, tuning\n", __func__); + + } else + if(cmd == FE_GET_PROPERTY) { + + tvps = (struct dtv_properties __user *)parg; + + dprintk("%s() properties.num = %d\n", __func__, tvps->num); + dprintk("%s() properties.props = %p\n", __func__, tvps->props); + + /* Put an arbitrary limit on the number of messages that can + * be sent at once */ + if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) + return -EINVAL; + + tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); + if (!tvp) { + err = -ENOMEM; + goto out; + } + + if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_get(fe, tvp + i, file); + if (err < 0) + goto out; + (tvp + i)->result = err; + } + + if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + } else + err = -EOPNOTSUPP; + +out: + kfree(tvp); + return err; +} + +static int dvb_frontend_ioctl_legacy(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + int cb_err, err = -EOPNOTSUPP; + + if (fe->dvb->fe_ioctl_override) { + cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg, + DVB_FE_IOCTL_PRE); + if (cb_err < 0) + return cb_err; + if (cb_err > 0) + return 0; + /* fe_ioctl_override returning 0 allows + * dvb-core to continue handling the ioctl */ + } + + switch (cmd) { + case FE_GET_INFO: { + struct dvb_frontend_info* info = parg; + memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); + dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); + + /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't + * do it, it is done for it. */ + info->caps |= FE_CAN_INVERSION_AUTO; + err = 0; + break; + } + + case FE_READ_STATUS: { + fe_status_t* status = parg; + + /* if retune was requested but hasn't occurred yet, prevent + * that user get signal state from previous tuning */ + if (fepriv->state == FESTATE_RETUNE || + fepriv->state == FESTATE_ERROR) { + err=0; + *status = 0; + break; + } + + if (fe->ops.read_status) + err = fe->ops.read_status(fe, status); + break; + } + case FE_READ_BER: + if (fe->ops.read_ber) + err = fe->ops.read_ber(fe, (__u32*) parg); + break; + + case FE_READ_SIGNAL_STRENGTH: + if (fe->ops.read_signal_strength) + err = fe->ops.read_signal_strength(fe, (__u16*) parg); + break; + + case FE_READ_SNR: + if (fe->ops.read_snr) + err = fe->ops.read_snr(fe, (__u16*) parg); + break; + + case FE_READ_UNCORRECTED_BLOCKS: + if (fe->ops.read_ucblocks) + err = fe->ops.read_ucblocks(fe, (__u32*) parg); + break; + + + case FE_DISEQC_RESET_OVERLOAD: + if (fe->ops.diseqc_reset_overload) { + err = fe->ops.diseqc_reset_overload(fe); + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; + } + break; + + case FE_DISEQC_SEND_MASTER_CMD: + if (fe->ops.diseqc_send_master_cmd) { + err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg); + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; + } + break; + + case FE_DISEQC_SEND_BURST: + if (fe->ops.diseqc_send_burst) { + err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg); + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; + } + break; + + case FE_SET_TONE: + if (fe->ops.set_tone) { + err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg); + fepriv->tone = (fe_sec_tone_mode_t) parg; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; + } + break; + + case FE_SET_VOLTAGE: + if (fe->ops.set_voltage) { + err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg); + fepriv->voltage = (fe_sec_voltage_t) parg; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; + } + break; + + case FE_DISHNETWORK_SEND_LEGACY_CMD: + if (fe->ops.dishnetwork_send_legacy_command) { + err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg); + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; + } else if (fe->ops.set_voltage) { + /* + * NOTE: This is a fallback condition. Some frontends + * (stv0299 for instance) take longer than 8msec to + * respond to a set_voltage command. Those switches + * need custom routines to switch properly. For all + * other frontends, the following should work ok. + * Dish network legacy switches (as used by Dish500) + * are controlled by sending 9-bit command words + * spaced 8msec apart. + * the actual command word is switch/port dependent + * so it is up to the userspace application to send + * the right command. + * The command must always start with a '0' after + * initialization, so parg is 8 bits and does not + * include the initialization or start bit + */ + unsigned long swcmd = ((unsigned long) parg) << 1; + struct timeval nexttime; + struct timeval tv[10]; + int i; + u8 last = 1; + if (dvb_frontend_debug) + printk("%s switch command: 0x%04lx\n", __func__, swcmd); + do_gettimeofday(&nexttime); + if (dvb_frontend_debug) + memcpy(&tv[0], &nexttime, sizeof(struct timeval)); + /* before sending a command, initialize by sending + * a 32ms 18V to the switch + */ + fe->ops.set_voltage(fe, SEC_VOLTAGE_18); + dvb_frontend_sleep_until(&nexttime, 32000); + + for (i = 0; i < 9; i++) { + if (dvb_frontend_debug) + do_gettimeofday(&tv[i + 1]); + if ((swcmd & 0x01) != last) { + /* set voltage to (last ? 13V : 18V) */ + fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); + last = (last) ? 0 : 1; + } + swcmd = swcmd >> 1; + if (i != 8) + dvb_frontend_sleep_until(&nexttime, 8000); + } + if (dvb_frontend_debug) { + printk("%s(%d): switch delay (should be 32k followed by all 8k\n", + __func__, fe->dvb->num); + for (i = 1; i < 10; i++) + printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); + } + err = 0; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; + } + break; + + case FE_DISEQC_RECV_SLAVE_REPLY: + if (fe->ops.diseqc_recv_slave_reply) + err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); + break; + + case FE_ENABLE_HIGH_LNB_VOLTAGE: + if (fe->ops.enable_high_lnb_voltage) + err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); + break; + + case FE_SET_FRONTEND: { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_tune_settings fetunesettings; + + if (c->state == DTV_TUNE) { + if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) { + err = -EINVAL; + break; + } + } else { + if (dvb_frontend_check_parameters(fe, parg) < 0) { + err = -EINVAL; + break; + } + + memcpy (&fepriv->parameters_in, parg, + sizeof (struct dvb_frontend_parameters)); + dtv_property_cache_sync(fe, c, &fepriv->parameters_in); + } + + memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); + memcpy(&fetunesettings.parameters, parg, + sizeof (struct dvb_frontend_parameters)); + + /* force auto frequency inversion if requested */ + if (dvb_force_auto_inversion) { + fepriv->parameters_in.inversion = INVERSION_AUTO; + fetunesettings.parameters.inversion = INVERSION_AUTO; + } + if (fe->ops.info.type == FE_OFDM) { + /* without hierarchical coding code_rate_LP is irrelevant, + * so we tolerate the otherwise invalid FEC_NONE setting */ + if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE && + fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE) + fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO; + } + + /* get frontend-specific tuning settings */ + if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { + fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; + fepriv->max_drift = fetunesettings.max_drift; + fepriv->step_size = fetunesettings.step_size; + } else { + /* default values */ + switch(fe->ops.info.type) { + case FE_QPSK: + fepriv->min_delay = HZ/20; + fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000; + fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000; + break; + + case FE_QAM: + fepriv->min_delay = HZ/20; + fepriv->step_size = 0; /* no zigzag */ + fepriv->max_drift = 0; + break; + + case FE_OFDM: + fepriv->min_delay = HZ/20; + fepriv->step_size = fe->ops.info.frequency_stepsize * 2; + fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; + break; + case FE_ATSC: + fepriv->min_delay = HZ/20; + fepriv->step_size = 0; + fepriv->max_drift = 0; + break; + } + } + if (dvb_override_tune_delay > 0) + fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; + + fepriv->state = FESTATE_RETUNE; + + /* Request the search algorithm to search */ + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + + dvb_frontend_wakeup(fe); + dvb_frontend_add_event(fe, 0); + fepriv->status = 0; + err = 0; + break; + } + + case FE_GET_EVENT: + err = dvb_frontend_get_event (fe, parg, file->f_flags); + break; + + case FE_GET_FRONTEND: + if (fe->ops.get_frontend) { + err = fe->ops.get_frontend(fe, &fepriv->parameters_out); + memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters)); + } + break; + + case FE_SET_FRONTEND_TUNE_MODE: + fepriv->tune_mode_flags = (unsigned long) parg; + err = 0; + break; + }; + + if (fe->dvb->fe_ioctl_override) { + cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg, + DVB_FE_IOCTL_POST); + if (cb_err < 0) + return cb_err; + } + + return err; +} + + +static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + dprintk ("%s\n", __func__); + + poll_wait (file, &fepriv->events.wait_queue, wait); + + if (fepriv->events.eventw != fepriv->events.eventr) + return (POLLIN | POLLRDNORM | POLLPRI); + + return 0; +} + +static int dvb_frontend_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_adapter *adapter = fe->dvb; + int ret; + + dprintk ("%s\n", __func__); + if (fepriv->exit == DVB_FE_DEVICE_REMOVED) + return -ENODEV; + + if (adapter->mfe_shared) { + mutex_lock (&adapter->mfe_lock); + + if (adapter->mfe_dvbdev == NULL) + adapter->mfe_dvbdev = dvbdev; + + else if (adapter->mfe_dvbdev != dvbdev) { + struct dvb_device + *mfedev = adapter->mfe_dvbdev; + struct dvb_frontend + *mfe = mfedev->priv; + struct dvb_frontend_private + *mfepriv = mfe->frontend_priv; + int mferetry = (dvb_mfe_wait_time << 1); + + mutex_unlock (&adapter->mfe_lock); + while (mferetry-- && (mfedev->users != -1 || + mfepriv->thread != NULL)) { + if(msleep_interruptible(500)) { + if(signal_pending(current)) + return -EINTR; + } + } + + mutex_lock (&adapter->mfe_lock); + if(adapter->mfe_dvbdev != dvbdev) { + mfedev = adapter->mfe_dvbdev; + mfe = mfedev->priv; + mfepriv = mfe->frontend_priv; + if (mfedev->users != -1 || + mfepriv->thread != NULL) { + mutex_unlock (&adapter->mfe_lock); + return -EBUSY; + } + adapter->mfe_dvbdev = dvbdev; + } + } + } + + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { + if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) + goto err0; + } + + if ((ret = dvb_generic_open (inode, file)) < 0) + goto err1; + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + /* normal tune mode when opened R/W */ + fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; + fepriv->tone = -1; + fepriv->voltage = -1; + + ret = dvb_frontend_start (fe); + if (ret) + goto err2; + + /* empty event queue */ + fepriv->events.eventr = fepriv->events.eventw = 0; + } + + if (adapter->mfe_shared) + mutex_unlock (&adapter->mfe_lock); + return ret; + +err2: + dvb_generic_release(inode, file); +err1: + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); +err0: + if (adapter->mfe_shared) + mutex_unlock (&adapter->mfe_lock); + return ret; +} + +static int dvb_frontend_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + int ret; + + dprintk ("%s\n", __func__); + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) + fepriv->release_jiffies = jiffies; + + ret = dvb_generic_release (inode, file); + + if (dvbdev->users == -1) { + if (fepriv->exit != DVB_FE_NO_EXIT) { + fops_put(file->f_op); + file->f_op = NULL; + wake_up(&dvbdev->wait_queue); + } + if (fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); + } + + return ret; +} + +static const struct file_operations dvb_frontend_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dvb_generic_ioctl, + .poll = dvb_frontend_poll, + .open = dvb_frontend_open, + .release = dvb_frontend_release, + .llseek = noop_llseek, +}; + +int dvb_register_frontend(struct dvb_adapter* dvb, + struct dvb_frontend* fe) +{ + struct dvb_frontend_private *fepriv; + static const struct dvb_device dvbdev_template = { + .users = ~0, + .writers = 1, + .readers = (~0)-1, + .fops = &dvb_frontend_fops, + .kernel_ioctl = dvb_frontend_ioctl + }; + + dprintk ("%s\n", __func__); + + if (mutex_lock_interruptible(&frontend_mutex)) + return -ERESTARTSYS; + + fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); + if (fe->frontend_priv == NULL) { + mutex_unlock(&frontend_mutex); + return -ENOMEM; + } + fepriv = fe->frontend_priv; + + sema_init(&fepriv->sem, 1); + init_waitqueue_head (&fepriv->wait_queue); + init_waitqueue_head (&fepriv->events.wait_queue); + mutex_init(&fepriv->events.mtx); + fe->dvb = dvb; + fepriv->inversion = INVERSION_OFF; + + printk ("DVB: registering adapter %i frontend %i (%s)...\n", + fe->dvb->num, + fe->id, + fe->ops.info.name); + + dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, + fe, DVB_DEVICE_FRONTEND); + + mutex_unlock(&frontend_mutex); + return 0; +} +EXPORT_SYMBOL(dvb_register_frontend); + +int dvb_unregister_frontend(struct dvb_frontend* fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + dprintk ("%s\n", __func__); + + mutex_lock(&frontend_mutex); + dvb_frontend_stop (fe); + mutex_unlock(&frontend_mutex); + + if (fepriv->dvbdev->users < -1) + wait_event(fepriv->dvbdev->wait_queue, + fepriv->dvbdev->users==-1); + + mutex_lock(&frontend_mutex); + dvb_unregister_device (fepriv->dvbdev); + + /* fe is invalid now */ + kfree(fepriv); + mutex_unlock(&frontend_mutex); + return 0; +} +EXPORT_SYMBOL(dvb_unregister_frontend); + +#ifdef CONFIG_MEDIA_ATTACH +void dvb_frontend_detach(struct dvb_frontend* fe) +{ + void *ptr; + + if (fe->ops.release_sec) { + fe->ops.release_sec(fe); + symbol_put_addr(fe->ops.release_sec); + } + if (fe->ops.tuner_ops.release) { + fe->ops.tuner_ops.release(fe); + symbol_put_addr(fe->ops.tuner_ops.release); + } + if (fe->ops.analog_ops.release) { + fe->ops.analog_ops.release(fe); + symbol_put_addr(fe->ops.analog_ops.release); + } + ptr = (void*)fe->ops.release; + if (ptr) { + fe->ops.release(fe); + symbol_put_addr(ptr); + } +} +#else +void dvb_frontend_detach(struct dvb_frontend* fe) +{ + if (fe->ops.release_sec) + fe->ops.release_sec(fe); + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); + if (fe->ops.analog_ops.release) + fe->ops.analog_ops.release(fe); + if (fe->ops.release) + fe->ops.release(fe); +} +#endif +EXPORT_SYMBOL(dvb_frontend_detach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_frontend.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_frontend.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_frontend.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_frontend.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,392 @@ +/* + * dvb_frontend.h + * + * Copyright (C) 2001 convergence integrated media GmbH + * Copyright (C) 2004 convergence GmbH + * + * Written by Ralph Metzler + * Overhauled by Holger Waechtler + * Kernel I2C stuff by Michael Hunold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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. + * + */ + +#ifndef _DVB_FRONTEND_H_ +#define _DVB_FRONTEND_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dvbdev.h" + +struct dvb_frontend_tune_settings { + int min_delay_ms; + int step_size; + int max_drift; + struct dvb_frontend_parameters parameters; +}; + +struct dvb_frontend; + +struct dvb_tuner_info { + char name[128]; + + u32 frequency_min; + u32 frequency_max; + u32 frequency_step; + + u32 bandwidth_min; + u32 bandwidth_max; + u32 bandwidth_step; +}; + +struct analog_parameters { + unsigned int frequency; + unsigned int mode; + unsigned int audmode; + u64 std; +}; + +enum dvbfe_modcod { + DVBFE_MODCOD_DUMMY_PLFRAME = 0, + DVBFE_MODCOD_QPSK_1_4, + DVBFE_MODCOD_QPSK_1_3, + DVBFE_MODCOD_QPSK_2_5, + DVBFE_MODCOD_QPSK_1_2, + DVBFE_MODCOD_QPSK_3_5, + DVBFE_MODCOD_QPSK_2_3, + DVBFE_MODCOD_QPSK_3_4, + DVBFE_MODCOD_QPSK_4_5, + DVBFE_MODCOD_QPSK_5_6, + DVBFE_MODCOD_QPSK_8_9, + DVBFE_MODCOD_QPSK_9_10, + DVBFE_MODCOD_8PSK_3_5, + DVBFE_MODCOD_8PSK_2_3, + DVBFE_MODCOD_8PSK_3_4, + DVBFE_MODCOD_8PSK_5_6, + DVBFE_MODCOD_8PSK_8_9, + DVBFE_MODCOD_8PSK_9_10, + DVBFE_MODCOD_16APSK_2_3, + DVBFE_MODCOD_16APSK_3_4, + DVBFE_MODCOD_16APSK_4_5, + DVBFE_MODCOD_16APSK_5_6, + DVBFE_MODCOD_16APSK_8_9, + DVBFE_MODCOD_16APSK_9_10, + DVBFE_MODCOD_32APSK_3_4, + DVBFE_MODCOD_32APSK_4_5, + DVBFE_MODCOD_32APSK_5_6, + DVBFE_MODCOD_32APSK_8_9, + DVBFE_MODCOD_32APSK_9_10, + DVBFE_MODCOD_RESERVED_1, + DVBFE_MODCOD_BPSK_1_3, + DVBFE_MODCOD_BPSK_1_4, + DVBFE_MODCOD_RESERVED_2 +}; + +enum tuner_param { + DVBFE_TUNER_FREQUENCY = (1 << 0), + DVBFE_TUNER_TUNERSTEP = (1 << 1), + DVBFE_TUNER_IFFREQ = (1 << 2), + DVBFE_TUNER_BANDWIDTH = (1 << 3), + DVBFE_TUNER_REFCLOCK = (1 << 4), + DVBFE_TUNER_IQSENSE = (1 << 5), + DVBFE_TUNER_DUMMY = (1 << 31) +}; + +/* + * ALGO_HW: (Hardware Algorithm) + * ---------------------------------------------------------------- + * Devices that support this algorithm do everything in hardware + * and no software support is needed to handle them. + * Requesting these devices to LOCK is the only thing required, + * device is supposed to do everything in the hardware. + * + * ALGO_SW: (Software Algorithm) + * ---------------------------------------------------------------- + * These are dumb devices, that require software to do everything + * + * ALGO_CUSTOM: (Customizable Agorithm) + * ---------------------------------------------------------------- + * Devices having this algorithm can be customized to have specific + * algorithms in the frontend driver, rather than simply doing a + * software zig-zag. In this case the zigzag maybe hardware assisted + * or it maybe completely done in hardware. In all cases, usage of + * this algorithm, in conjunction with the search and track + * callbacks, utilizes the driver specific algorithm. + * + * ALGO_RECOVERY: (Recovery Algorithm) + * ---------------------------------------------------------------- + * These devices have AUTO recovery capabilities from LOCK failure + */ +enum dvbfe_algo { + DVBFE_ALGO_HW = (1 << 0), + DVBFE_ALGO_SW = (1 << 1), + DVBFE_ALGO_CUSTOM = (1 << 2), + DVBFE_ALGO_RECOVERY = (1 << 31) +}; + +struct tuner_state { + u32 frequency; + u32 tunerstep; + u32 ifreq; + u32 bandwidth; + u32 iqsense; + u32 refclock; +}; + +/* + * search callback possible return status + * + * DVBFE_ALGO_SEARCH_SUCCESS + * The frontend search algorithm completed and returned successfully + * + * DVBFE_ALGO_SEARCH_ASLEEP + * The frontend search algorithm is sleeping + * + * DVBFE_ALGO_SEARCH_FAILED + * The frontend search for a signal failed + * + * DVBFE_ALGO_SEARCH_INVALID + * The frontend search algorith was probably supplied with invalid + * parameters and the search is an invalid one + * + * DVBFE_ALGO_SEARCH_ERROR + * The frontend search algorithm failed due to some error + * + * DVBFE_ALGO_SEARCH_AGAIN + * The frontend search algorithm was requested to search again + */ +enum dvbfe_search { + DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0), + DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1), + DVBFE_ALGO_SEARCH_FAILED = (1 << 2), + DVBFE_ALGO_SEARCH_INVALID = (1 << 3), + DVBFE_ALGO_SEARCH_AGAIN = (1 << 4), + DVBFE_ALGO_SEARCH_ERROR = (1 << 31), +}; + + +struct dvb_tuner_ops { + + struct dvb_tuner_info info; + + int (*release)(struct dvb_frontend *fe); + int (*init)(struct dvb_frontend *fe); + int (*sleep)(struct dvb_frontend *fe); + + /** This is for simple PLLs - set all parameters in one go. */ + int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); + + /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ + int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); + + /** This is to allow setting tuner-specific configs */ + int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); + + int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); + int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); + +#define TUNER_STATUS_LOCKED 1 +#define TUNER_STATUS_STEREO 2 + int (*get_status)(struct dvb_frontend *fe, u32 *status); + int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); + + /** These are provided separately from set_params in order to facilitate silicon + * tuners which require sophisticated tuning loops, controlling each parameter separately. */ + int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); + int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); + + /* + * These are provided separately from set_params in order to facilitate silicon + * tuners which require sophisticated tuning loops, controlling each parameter separately. + */ + int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); + int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); +}; + +struct analog_demod_info { + char *name; +}; + +struct analog_demod_ops { + + struct analog_demod_info info; + + void (*set_params)(struct dvb_frontend *fe, + struct analog_parameters *params); + int (*has_signal)(struct dvb_frontend *fe); + int (*get_afc)(struct dvb_frontend *fe); + void (*tuner_status)(struct dvb_frontend *fe); + void (*standby)(struct dvb_frontend *fe); + void (*release)(struct dvb_frontend *fe); + int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); + + /** This is to allow setting tuner-specific configuration */ + int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); +}; + +struct dvb_frontend_ops { + + struct dvb_frontend_info info; + + void (*release)(struct dvb_frontend* fe); + void (*release_sec)(struct dvb_frontend* fe); + + int (*init)(struct dvb_frontend* fe); + int (*sleep)(struct dvb_frontend* fe); + + int (*write)(struct dvb_frontend* fe, const u8 buf[], int len); + + /* if this is set, it overrides the default swzigzag */ + int (*tune)(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params, + unsigned int mode_flags, + unsigned int *delay, + fe_status_t *status); + /* get frontend tuning algorithm from the module */ + enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); + + /* these two are only used for the swzigzag code */ + int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); + + int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + + int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); + int (*read_ber)(struct dvb_frontend* fe, u32* ber); + int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); + int (*read_snr)(struct dvb_frontend* fe, u16* snr); + int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks); + + int (*diseqc_reset_overload)(struct dvb_frontend* fe); + int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); + int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply); + int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); + int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); + int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); + int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg); + int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); + int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); + int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); + + /* These callbacks are for devices that implement their own + * tuning algorithms, rather than a simple swzigzag + */ + enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + + struct dvb_tuner_ops tuner_ops; + struct analog_demod_ops analog_ops; + + int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); + int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); +}; + +#define MAX_EVENT 8 + +struct dvb_fe_events { + struct dvb_frontend_event events[MAX_EVENT]; + int eventw; + int eventr; + int overflow; + wait_queue_head_t wait_queue; + struct mutex mtx; +}; + +struct dtv_frontend_properties { + + /* Cache State */ + u32 state; + + u32 frequency; + fe_modulation_t modulation; + + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t sectone; + fe_spectral_inversion_t inversion; + fe_code_rate_t fec_inner; + fe_transmit_mode_t transmission_mode; + u32 bandwidth_hz; /* 0 = AUTO */ + fe_guard_interval_t guard_interval; + fe_hierarchy_t hierarchy; + u32 symbol_rate; + fe_code_rate_t code_rate_HP; + fe_code_rate_t code_rate_LP; + + fe_pilot_t pilot; + fe_rolloff_t rolloff; + + fe_delivery_system_t delivery_system; + + /* ISDB-T specifics */ + u8 isdbt_partial_reception; + u8 isdbt_sb_mode; + u8 isdbt_sb_subchannel; + u32 isdbt_sb_segment_idx; + u32 isdbt_sb_segment_count; + u8 isdbt_layer_enabled; + struct { + u8 segment_count; + fe_code_rate_t fec; + fe_modulation_t modulation; + u8 interleaving; + } layer[3]; + + /* ISDB-T specifics */ + u32 isdbs_ts_id; + + /* DVB-T2 specifics */ + u32 dvbt2_plp_id; +}; + +struct dvb_frontend { + struct dvb_frontend_ops ops; + struct dvb_adapter *dvb; + void *demodulator_priv; + void *tuner_priv; + void *frontend_priv; + void *sec_priv; + void *analog_demod_priv; + struct dtv_frontend_properties dtv_property_cache; +#define DVB_FRONTEND_COMPONENT_TUNER 0 + int (*callback)(void *adapter_priv, int component, int cmd, int arg); + int id; +}; + +extern int dvb_register_frontend(struct dvb_adapter *dvb, + struct dvb_frontend *fe); + +extern int dvb_unregister_frontend(struct dvb_frontend *fe); + +extern void dvb_frontend_detach(struct dvb_frontend *fe); + +extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); + +extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec); +extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_math.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_math.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_math.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_math.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,145 @@ +/* + * dvb-math provides some complex fixed-point math + * operations shared between the dvb related stuff + * + * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include "dvb_math.h" + +static const unsigned short logtable[256] = { + 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, + 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508, + 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6, + 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37, + 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f, + 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41, + 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1, + 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142, + 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68, + 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355, + 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c, + 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490, + 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3, + 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507, + 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe, + 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca, + 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c, + 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7, + 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c, + 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c, + 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a, + 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065, + 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730, + 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc, + 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469, + 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9, + 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c, + 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765, + 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, + 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, + 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, + 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 +}; + +unsigned int intlog2(u32 value) +{ + /** + * returns: log2(value) * 2^24 + * wrong result if value = 0 (log2(0) is undefined) + */ + unsigned int msb; + unsigned int logentry; + unsigned int significand; + unsigned int interpolation; + + if (unlikely(value == 0)) { + WARN_ON(1); + return 0; + } + + /* first detect the msb (count begins at 0) */ + msb = fls(value) - 1; + + /** + * now we use a logtable after the following method: + * + * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24 + * where x = msb and therefore 1 <= y < 2 + * first y is determined by shifting the value left + * so that msb is bit 31 + * 0x00231f56 -> 0x8C7D5800 + * the result is y * 2^31 -> "significand" + * then the highest 9 bits are used for a table lookup + * the highest bit is discarded because it's always set + * the highest nine bits in our example are 100011000 + * so we would use the entry 0x18 + */ + significand = value << (31 - msb); + logentry = (significand >> 23) & 0xff; + + /** + * last step we do is interpolation because of the + * limitations of the log table the error is that part of + * the significand which isn't used for lookup then we + * compute the ratio between the error and the next table entry + * and interpolate it between the log table entry used and the + * next one the biggest error possible is 0x7fffff + * (in our example it's 0x7D5800) + * needed value for next table entry is 0x800000 + * so the interpolation is + * (error / 0x800000) * (logtable_next - logtable_current) + * in the implementation the division is moved to the end for + * better accuracy there is also an overflow correction if + * logtable_next is 256 + */ + interpolation = ((significand & 0x7fffff) * + ((logtable[(logentry + 1) & 0xff] - + logtable[logentry]) & 0xffff)) >> 15; + + /* now we return the result */ + return ((msb << 24) + (logtable[logentry] << 8) + interpolation); +} +EXPORT_SYMBOL(intlog2); + +unsigned int intlog10(u32 value) +{ + /** + * returns: log10(value) * 2^24 + * wrong result if value = 0 (log10(0) is undefined) + */ + u64 log; + + if (unlikely(value == 0)) { + WARN_ON(1); + return 0; + } + + log = intlog2(value); + + /** + * we use the following method: + * log10(x) = log2(x) * log10(2) + */ + + return (log * 646456993) >> 31; +} +EXPORT_SYMBOL(intlog10); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_math.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_math.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_math.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_math.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * dvb-math provides some complex fixed-point math + * operations shared between the dvb related stuff + * + * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __DVB_MATH_H +#define __DVB_MATH_H + +#include + +/** + * computes log2 of a value; the result is shifted left by 24 bits + * + * to use rational values you can use the following method: + * intlog2(value) = intlog2(value * 2^x) - x * 2^24 + * + * example: intlog2(8) will give 3 << 24 = 3 * 2^24 + * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24 + * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24 + * + * @param value The value (must be != 0) + * @return log2(value) * 2^24 + */ +extern unsigned int intlog2(u32 value); + +/** + * computes log10 of a value; the result is shifted left by 24 bits + * + * to use rational values you can use the following method: + * intlog10(value) = intlog10(value * 10^x) - x * 2^24 + * + * example: intlog10(1000) will give 3 << 24 = 3 * 2^24 + * due to the implementation intlog10(1000) might be not exactly 3 * 2^24 + * + * look at intlog2 for similar examples + * + * @param value The value (must be != 0) + * @return log10(value) * 2^24 + */ +extern unsigned int intlog10(u32 value); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_net.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_net.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_net.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_net.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1518 @@ +/* + * dvb_net.c + * + * Copyright (C) 2001 Convergence integrated media GmbH + * Ralph Metzler + * Copyright (C) 2002 Ralph Metzler + * + * ULE Decapsulation code: + * Copyright (C) 2003, 2004 gcs - Global Communication & Services GmbH. + * and Department of Scientific Computing + * Paris Lodron University of Salzburg. + * Hilmar Linder + * and Wolfram Stering + * + * ULE Decaps according to RFC 4326. + * + * 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, or (at your option) any later version. + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +/* + * ULE ChangeLog: + * Feb 2004: hl/ws v1: Implementing draft-fair-ipdvb-ule-01.txt + * + * Dec 2004: hl/ws v2: Implementing draft-ietf-ipdvb-ule-03.txt: + * ULE Extension header handling. + * Bugreports by Moritz Vieth and Hanno Tersteegen, + * Fraunhofer Institute for Open Communication Systems + * Competence Center for Advanced Satellite Communications. + * Bugfixes and robustness improvements. + * Filtering on dest MAC addresses, if present (D-Bit = 0) + * ULE_DEBUG compile-time option. + * Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by + * Christian Praehauser , + * Paris Lodron University of Salzburg. + */ + +/* + * FIXME / TODO (dvb_net.c): + * + * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_demux.h" +#include "dvb_net.h" + +static int dvb_net_debug; +module_param(dvb_net_debug, int, 0444); +MODULE_PARM_DESC(dvb_net_debug, "enable debug messages"); + +#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0) + + +static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) +{ + unsigned int j; + for (j = 0; j < cnt; j++) + c = crc32_be( c, iov[j].iov_base, iov[j].iov_len ); + return c; +} + + +#define DVB_NET_MULTICAST_MAX 10 + +#undef ULE_DEBUG + +#ifdef ULE_DEBUG + +#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" +#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5] + +#define isprint(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) + +static void hexdump( const unsigned char *buf, unsigned short len ) +{ + char str[80], octet[10]; + int ofs, i, l; + + for (ofs = 0; ofs < len; ofs += 16) { + sprintf( str, "%03d: ", ofs ); + + for (i = 0; i < 16; i++) { + if ((i + ofs) < len) + sprintf( octet, "%02x ", buf[ofs + i] ); + else + strcpy( octet, " " ); + + strcat( str, octet ); + } + strcat( str, " " ); + l = strlen( str ); + + for (i = 0; (i < 16) && ((i + ofs) < len); i++) + str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.'; + + str[l] = '\0'; + printk( KERN_WARNING "%s\n", str ); + } +} + +#endif + +struct dvb_net_priv { + int in_use; + u16 pid; + struct net_device *net; + struct dvb_net *host; + struct dmx_demux *demux; + struct dmx_section_feed *secfeed; + struct dmx_section_filter *secfilter; + struct dmx_ts_feed *tsfeed; + int multi_num; + struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX]; + unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6]; + int rx_mode; +#define RX_MODE_UNI 0 +#define RX_MODE_MULTI 1 +#define RX_MODE_ALL_MULTI 2 +#define RX_MODE_PROMISC 3 + struct work_struct set_multicast_list_wq; + struct work_struct restart_net_feed_wq; + unsigned char feedtype; /* Either FEED_TYPE_ or FEED_TYPE_ULE */ + int need_pusi; /* Set to 1, if synchronization on PUSI required. */ + unsigned char tscc; /* TS continuity counter after sync on PUSI. */ + struct sk_buff *ule_skb; /* ULE SNDU decodes into this buffer. */ + unsigned char *ule_next_hdr; /* Pointer into skb to next ULE extension header. */ + unsigned short ule_sndu_len; /* ULE SNDU length in bytes, w/o D-Bit. */ + unsigned short ule_sndu_type; /* ULE SNDU type field, complete. */ + unsigned char ule_sndu_type_1; /* ULE SNDU type field, if split across 2 TS cells. */ + unsigned char ule_dbit; /* Whether the DestMAC address present + * or not (bit is set). */ + unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */ + int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */ + unsigned long ts_count; /* Current ts cell counter. */ + struct mutex mutex; +}; + + +/** + * Determine the packet's protocol ID. The rule here is that we + * assume 802.3 if the type field is short enough to be a length. + * This is normal practice and works for any 'now in use' protocol. + * + * stolen from eth.c out of the linux kernel, hacked for dvb-device + * by Michael Holzt + */ +static __be16 dvb_net_eth_type_trans(struct sk_buff *skb, + struct net_device *dev) +{ + struct ethhdr *eth; + unsigned char *rawp; + + skb_reset_mac_header(skb); + skb_pull(skb,dev->hard_header_len); + eth = eth_hdr(skb); + + if (*eth->h_dest & 1) { + if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) + skb->pkt_type=PACKET_BROADCAST; + else + skb->pkt_type=PACKET_MULTICAST; + } + + if (ntohs(eth->h_proto) >= 1536) + return eth->h_proto; + + rawp = skb->data; + + /** + * This is a magic hack to spot IPX packets. Older Novell breaks + * the protocol design and runs IPX over 802.3 without an 802.2 LLC + * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This + * won't work for fault tolerant netware but does for the rest. + */ + if (*(unsigned short *)rawp == 0xFFFF) + return htons(ETH_P_802_3); + + /** + * Real 802.2 LLC + */ + return htons(ETH_P_802_2); +} + +#define TS_SZ 188 +#define TS_SYNC 0x47 +#define TS_TEI 0x80 +#define TS_SC 0xC0 +#define TS_PUSI 0x40 +#define TS_AF_A 0x20 +#define TS_AF_D 0x10 + +/* ULE Extension Header handlers. */ + +#define ULE_TEST 0 +#define ULE_BRIDGED 1 + +#define ULE_OPTEXTHDR_PADDING 0 + +static int ule_test_sndu( struct dvb_net_priv *p ) +{ + return -1; +} + +static int ule_bridged_sndu( struct dvb_net_priv *p ) +{ + struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr; + if(ntohs(hdr->h_proto) < 1536) { + int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data); + /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */ + if(framelen != ntohs(hdr->h_proto)) { + return -1; + } + } + /* Note: + * From RFC4326: + * "A bridged SNDU is a Mandatory Extension Header of Type 1. + * It must be the final (or only) extension header specified in the header chain of a SNDU." + * The 'ule_bridged' flag will cause the extension header processing loop to terminate. + */ + p->ule_bridged = 1; + return 0; +} + +static int ule_exthdr_padding(struct dvb_net_priv *p) +{ + return 0; +} + +/** Handle ULE extension headers. + * Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding. + * Returns: >= 0: nr. of bytes consumed by next extension header + * -1: Mandatory extension header that is not recognized or TEST SNDU; discard. + */ +static int handle_one_ule_extension( struct dvb_net_priv *p ) +{ + /* Table of mandatory extension header handlers. The header type is the index. */ + static int (*ule_mandatory_ext_handlers[255])( struct dvb_net_priv *p ) = + { [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL, }; + + /* Table of optional extension header handlers. The header type is the index. */ + static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = + { [0] = ule_exthdr_padding, [1] = NULL, }; + + int ext_len = 0; + unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8; + unsigned char htype = p->ule_sndu_type & 0x00FF; + + /* Discriminate mandatory and optional extension headers. */ + if (hlen == 0) { + /* Mandatory extension header */ + if (ule_mandatory_ext_handlers[htype]) { + ext_len = ule_mandatory_ext_handlers[htype]( p ); + if(ext_len >= 0) { + p->ule_next_hdr += ext_len; + if (!p->ule_bridged) { + p->ule_sndu_type = ntohs(*(__be16 *)p->ule_next_hdr); + p->ule_next_hdr += 2; + } else { + p->ule_sndu_type = ntohs(*(__be16 *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN))); + /* This assures the extension handling loop will terminate. */ + } + } + // else: extension handler failed or SNDU should be discarded + } else + ext_len = -1; /* SNDU has to be discarded. */ + } else { + /* Optional extension header. Calculate the length. */ + ext_len = hlen << 1; + /* Process the optional extension header according to its type. */ + if (ule_optional_ext_handlers[htype]) + (void)ule_optional_ext_handlers[htype]( p ); + p->ule_next_hdr += ext_len; + p->ule_sndu_type = ntohs( *(__be16 *)(p->ule_next_hdr-2) ); + /* + * note: the length of the next header type is included in the + * length of THIS optional extension header + */ + } + + return ext_len; +} + +static int handle_ule_extensions( struct dvb_net_priv *p ) +{ + int total_ext_len = 0, l; + + p->ule_next_hdr = p->ule_skb->data; + do { + l = handle_one_ule_extension( p ); + if (l < 0) + return l; /* Stop extension header processing and discard SNDU. */ + total_ext_len += l; +#ifdef ULE_DEBUG + dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, " + "l=%i, total_ext_len=%i\n", p->ule_next_hdr, + (int) p->ule_sndu_type, l, total_ext_len); +#endif + + } while (p->ule_sndu_type < 1536); + + return total_ext_len; +} + + +/** Prepare for a new ULE SNDU: reset the decoder state. */ +static inline void reset_ule( struct dvb_net_priv *p ) +{ + p->ule_skb = NULL; + p->ule_next_hdr = NULL; + p->ule_sndu_len = 0; + p->ule_sndu_type = 0; + p->ule_sndu_type_1 = 0; + p->ule_sndu_remain = 0; + p->ule_dbit = 0xFF; + p->ule_bridged = 0; +} + +/** + * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of + * TS cells of a single PID. + */ +static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) +{ + struct dvb_net_priv *priv = netdev_priv(dev); + unsigned long skipped = 0L; + const u8 *ts, *ts_end, *from_where = NULL; + u8 ts_remain = 0, how_much = 0, new_ts = 1; + struct ethhdr *ethh = NULL; + bool error = false; + +#ifdef ULE_DEBUG + /* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */ + static unsigned char ule_hist[100*TS_SZ]; + static unsigned char *ule_where = ule_hist, ule_dump; +#endif + + /* For all TS cells in current buffer. + * Appearently, we are called for every single TS cell. + */ + for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) { + + if (new_ts) { + /* We are about to process a new TS cell. */ + +#ifdef ULE_DEBUG + if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist; + memcpy( ule_where, ts, TS_SZ ); + if (ule_dump) { + hexdump( ule_where, TS_SZ ); + ule_dump = 0; + } + ule_where += TS_SZ; +#endif + + /* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */ + if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) { + printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n", + priv->ts_count, ts[0], ts[1] & TS_TEI >> 7, ts[3] & 0xC0 >> 6); + + /* Drop partly decoded SNDU, reset state, resync on PUSI. */ + if (priv->ule_skb) { + dev_kfree_skb( priv->ule_skb ); + /* Prepare for next SNDU. */ + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; + } + reset_ule(priv); + priv->need_pusi = 1; + + /* Continue with next TS cell. */ + ts += TS_SZ; + priv->ts_count++; + continue; + } + + ts_remain = 184; + from_where = ts + 4; + } + /* Synchronize on PUSI, if required. */ + if (priv->need_pusi) { + if (ts[1] & TS_PUSI) { + /* Find beginning of first ULE SNDU in current TS cell. */ + /* Synchronize continuity counter. */ + priv->tscc = ts[3] & 0x0F; + /* There is a pointer field here. */ + if (ts[4] > ts_remain) { + printk(KERN_ERR "%lu: Invalid ULE packet " + "(pointer field %d)\n", priv->ts_count, ts[4]); + ts += TS_SZ; + priv->ts_count++; + continue; + } + /* Skip to destination of pointer field. */ + from_where = &ts[5] + ts[4]; + ts_remain -= 1 + ts[4]; + skipped = 0; + } else { + skipped++; + ts += TS_SZ; + priv->ts_count++; + continue; + } + } + + if (new_ts) { + /* Check continuity counter. */ + if ((ts[3] & 0x0F) == priv->tscc) + priv->tscc = (priv->tscc + 1) & 0x0F; + else { + /* TS discontinuity handling: */ + printk(KERN_WARNING "%lu: TS discontinuity: got %#x, " + "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc); + /* Drop partly decoded SNDU, reset state, resync on PUSI. */ + if (priv->ule_skb) { + dev_kfree_skb( priv->ule_skb ); + /* Prepare for next SNDU. */ + // reset_ule(priv); moved to below. + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; + } + reset_ule(priv); + /* skip to next PUSI. */ + priv->need_pusi = 1; + continue; + } + /* If we still have an incomplete payload, but PUSI is + * set; some TS cells are missing. + * This is only possible here, if we missed exactly 16 TS + * cells (continuity counter wrap). */ + if (ts[1] & TS_PUSI) { + if (! priv->need_pusi) { + if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) { + /* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */ + printk(KERN_WARNING "%lu: Invalid pointer " + "field: %u.\n", priv->ts_count, *from_where); + + /* Drop partly decoded SNDU, reset state, resync on PUSI. */ + if (priv->ule_skb) { + error = true; + dev_kfree_skb(priv->ule_skb); + } + + if (error || priv->ule_sndu_remain) { + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; + error = false; + } + + reset_ule(priv); + priv->need_pusi = 1; + continue; + } + /* Skip pointer field (we're processing a + * packed payload). */ + from_where += 1; + ts_remain -= 1; + } else + priv->need_pusi = 0; + + if (priv->ule_sndu_remain > 183) { + /* Current SNDU lacks more data than there could be available in the + * current TS cell. */ + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but " + "got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", + priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain); + dev_kfree_skb(priv->ule_skb); + /* Prepare for next SNDU. */ + reset_ule(priv); + /* Resync: go to where pointer field points to: start of next ULE SNDU. */ + from_where += ts[4]; + ts_remain -= ts[4]; + } + } + } + + /* Check if new payload needs to be started. */ + if (priv->ule_skb == NULL) { + /* Start a new payload with skb. + * Find ULE header. It is only guaranteed that the + * length field (2 bytes) is contained in the current + * TS. + * Check ts_remain has to be >= 2 here. */ + if (ts_remain < 2) { + printk(KERN_WARNING "Invalid payload packing: only %d " + "bytes left in TS. Resyncing.\n", ts_remain); + priv->ule_sndu_len = 0; + priv->need_pusi = 1; + ts += TS_SZ; + continue; + } + + if (! priv->ule_sndu_len) { + /* Got at least two bytes, thus extrace the SNDU length. */ + priv->ule_sndu_len = from_where[0] << 8 | from_where[1]; + if (priv->ule_sndu_len & 0x8000) { + /* D-Bit is set: no dest mac present. */ + priv->ule_sndu_len &= 0x7FFF; + priv->ule_dbit = 1; + } else + priv->ule_dbit = 0; + + if (priv->ule_sndu_len < 5) { + printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " + "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + priv->ule_sndu_len = 0; + priv->need_pusi = 1; + new_ts = 1; + ts += TS_SZ; + priv->ts_count++; + continue; + } + ts_remain -= 2; /* consume the 2 bytes SNDU length. */ + from_where += 2; + } + + priv->ule_sndu_remain = priv->ule_sndu_len + 2; + /* + * State of current TS: + * ts_remain (remaining bytes in the current TS cell) + * 0 ule_type is not available now, we need the next TS cell + * 1 the first byte of the ule_type is present + * >=2 full ULE header present, maybe some payload data as well. + */ + switch (ts_remain) { + case 1: + priv->ule_sndu_remain--; + priv->ule_sndu_type = from_where[0] << 8; + priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */ + ts_remain -= 1; from_where += 1; + /* Continue w/ next TS. */ + case 0: + new_ts = 1; + ts += TS_SZ; + priv->ts_count++; + continue; + + default: /* complete ULE header is present in current TS. */ + /* Extract ULE type field. */ + if (priv->ule_sndu_type_1) { + priv->ule_sndu_type_1 = 0; + priv->ule_sndu_type |= from_where[0]; + from_where += 1; /* points to payload start. */ + ts_remain -= 1; + } else { + /* Complete type is present in new TS. */ + priv->ule_sndu_type = from_where[0] << 8 | from_where[1]; + from_where += 2; /* points to payload start. */ + ts_remain -= 2; + } + break; + } + + /* Allocate the skb (decoder target buffer) with the correct size, as follows: + * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */ + priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN ); + if (priv->ule_skb == NULL) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", + dev->name); + dev->stats.rx_dropped++; + return; + } + + /* This includes the CRC32 _and_ dest mac, if !dbit. */ + priv->ule_sndu_remain = priv->ule_sndu_len; + priv->ule_skb->dev = dev; + /* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */ + skb_reserve( priv->ule_skb, ETH_HLEN + ETH_ALEN ); + } + + /* Copy data into our current skb. */ + how_much = min(priv->ule_sndu_remain, (int)ts_remain); + memcpy(skb_put(priv->ule_skb, how_much), from_where, how_much); + priv->ule_sndu_remain -= how_much; + ts_remain -= how_much; + from_where += how_much; + + /* Check for complete payload. */ + if (priv->ule_sndu_remain <= 0) { + /* Check CRC32, we've got it in our skb already. */ + __be16 ulen = htons(priv->ule_sndu_len); + __be16 utype = htons(priv->ule_sndu_type); + const u8 *tail; + struct kvec iov[3] = { + { &ulen, sizeof ulen }, + { &utype, sizeof utype }, + { priv->ule_skb->data, priv->ule_skb->len - 4 } + }; + u32 ule_crc = ~0L, expected_crc; + if (priv->ule_dbit) { + /* Set D-bit for CRC32 verification, + * if it was set originally. */ + ulen |= htons(0x8000); + } + + ule_crc = iov_crc32(ule_crc, iov, 3); + tail = skb_tail_pointer(priv->ule_skb); + expected_crc = *(tail - 4) << 24 | + *(tail - 3) << 16 | + *(tail - 2) << 8 | + *(tail - 1); + if (ule_crc != expected_crc) { + printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", + priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0); + +#ifdef ULE_DEBUG + hexdump( iov[0].iov_base, iov[0].iov_len ); + hexdump( iov[1].iov_base, iov[1].iov_len ); + hexdump( iov[2].iov_base, iov[2].iov_len ); + + if (ule_where == ule_hist) { + hexdump( &ule_hist[98*TS_SZ], TS_SZ ); + hexdump( &ule_hist[99*TS_SZ], TS_SZ ); + } else if (ule_where == &ule_hist[TS_SZ]) { + hexdump( &ule_hist[99*TS_SZ], TS_SZ ); + hexdump( ule_hist, TS_SZ ); + } else { + hexdump( ule_where - TS_SZ - TS_SZ, TS_SZ ); + hexdump( ule_where - TS_SZ, TS_SZ ); + } + ule_dump = 1; +#endif + + dev->stats.rx_errors++; + dev->stats.rx_crc_errors++; + dev_kfree_skb(priv->ule_skb); + } else { + /* CRC32 verified OK. */ + u8 dest_addr[ETH_ALEN]; + static const u8 bc_addr[ETH_ALEN] = + { [ 0 ... ETH_ALEN-1] = 0xff }; + + /* CRC32 was OK. Remove it from skb. */ + priv->ule_skb->tail -= 4; + priv->ule_skb->len -= 4; + + if (!priv->ule_dbit) { + /* + * The destination MAC address is the + * next data in the skb. It comes + * before any extension headers. + * + * Check if the payload of this SNDU + * should be passed up the stack. + */ + register int drop = 0; + if (priv->rx_mode != RX_MODE_PROMISC) { + if (priv->ule_skb->data[0] & 0x01) { + /* multicast or broadcast */ + if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) { + /* multicast */ + if (priv->rx_mode == RX_MODE_MULTI) { + int i; + for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++) + ; + if (i == priv->multi_num) + drop = 1; + } else if (priv->rx_mode != RX_MODE_ALL_MULTI) + drop = 1; /* no broadcast; */ + /* else: all multicast mode: accept all multicast packets */ + } + /* else: broadcast */ + } + else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN)) + drop = 1; + /* else: destination address matches the MAC address of our receiver device */ + } + /* else: promiscuous mode; pass everything up the stack */ + + if (drop) { +#ifdef ULE_DEBUG + dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n", + MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr)); +#endif + dev_kfree_skb(priv->ule_skb); + goto sndu_done; + } + else + { + skb_copy_from_linear_data(priv->ule_skb, + dest_addr, + ETH_ALEN); + skb_pull(priv->ule_skb, ETH_ALEN); + } + } + + /* Handle ULE Extension Headers. */ + if (priv->ule_sndu_type < 1536) { + /* There is an extension header. Handle it accordingly. */ + int l = handle_ule_extensions(priv); + if (l < 0) { + /* Mandatory extension header unknown or TEST SNDU. Drop it. */ + // printk( KERN_WARNING "Dropping SNDU, extension headers.\n" ); + dev_kfree_skb(priv->ule_skb); + goto sndu_done; + } + skb_pull(priv->ule_skb, l); + } + + /* + * Construct/assure correct ethernet header. + * Note: in bridged mode (priv->ule_bridged != + * 0) we already have the (original) ethernet + * header at the start of the payload (after + * optional dest. address and any extension + * headers). + */ + + if (!priv->ule_bridged) { + skb_push(priv->ule_skb, ETH_HLEN); + ethh = (struct ethhdr *)priv->ule_skb->data; + if (!priv->ule_dbit) { + /* dest_addr buffer is only valid if priv->ule_dbit == 0 */ + memcpy(ethh->h_dest, dest_addr, ETH_ALEN); + memset(ethh->h_source, 0, ETH_ALEN); + } + else /* zeroize source and dest */ + memset( ethh, 0, ETH_ALEN*2 ); + + ethh->h_proto = htons(priv->ule_sndu_type); + } + /* else: skb is in correct state; nothing to do. */ + priv->ule_bridged = 0; + + /* Stuff into kernel's protocol stack. */ + priv->ule_skb->protocol = dvb_net_eth_type_trans(priv->ule_skb, dev); + /* If D-bit is set (i.e. destination MAC address not present), + * receive the packet anyhow. */ + /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) + priv->ule_skb->pkt_type = PACKET_HOST; */ + dev->stats.rx_packets++; + dev->stats.rx_bytes += priv->ule_skb->len; + netif_rx(priv->ule_skb); + } + sndu_done: + /* Prepare for next SNDU. */ + reset_ule(priv); + } + + /* More data in current TS (look at the bytes following the CRC32)? */ + if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) { + /* Next ULE SNDU starts right there. */ + new_ts = 0; + priv->ule_skb = NULL; + priv->ule_sndu_type_1 = 0; + priv->ule_sndu_len = 0; + // printk(KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n", + // *(from_where + 0), *(from_where + 1), + // *(from_where + 2), *(from_where + 3)); + // printk(KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0); + // hexdump(ts, 188); + } else { + new_ts = 1; + ts += TS_SZ; + priv->ts_count++; + if (priv->ule_skb == NULL) { + priv->need_pusi = 1; + priv->ule_sndu_type_1 = 0; + priv->ule_sndu_len = 0; + } + } + } /* for all available TS cells */ +} + +static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, + struct dmx_ts_feed *feed, enum dmx_success success) +{ + struct net_device *dev = feed->priv; + + if (buffer2) + printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2); + if (buffer1_len > 32768) + printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len); + /* printk("TS callback: %u bytes, %u TS cells @ %p.\n", + buffer1_len, buffer1_len / TS_SZ, buffer1); */ + dvb_net_ule(dev, buffer1, buffer1_len); + return 0; +} + + +static void dvb_net_sec(struct net_device *dev, + const u8 *pkt, int pkt_len) +{ + u8 *eth; + struct sk_buff *skb; + struct net_device_stats *stats = &dev->stats; + int snap = 0; + + /* note: pkt_len includes a 32bit checksum */ + if (pkt_len < 16) { + printk("%s: IP/MPE packet length = %d too small.\n", + dev->name, pkt_len); + stats->rx_errors++; + stats->rx_length_errors++; + return; + } +/* it seems some ISPs manage to screw up here, so we have to + * relax the error checks... */ +#if 0 + if ((pkt[5] & 0xfd) != 0xc1) { + /* drop scrambled or broken packets */ +#else + if ((pkt[5] & 0x3c) != 0x00) { + /* drop scrambled */ +#endif + stats->rx_errors++; + stats->rx_crc_errors++; + return; + } + if (pkt[5] & 0x02) { + /* handle LLC/SNAP, see rfc-1042 */ + if (pkt_len < 24 || memcmp(&pkt[12], "\xaa\xaa\x03\0\0\0", 6)) { + stats->rx_dropped++; + return; + } + snap = 8; + } + if (pkt[7]) { + /* FIXME: assemble datagram from multiple sections */ + stats->rx_errors++; + stats->rx_frame_errors++; + return; + } + + /* we have 14 byte ethernet header (ip header follows); + * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP + */ + if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) { + //printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + stats->rx_dropped++; + return; + } + skb_reserve(skb, 2); /* longword align L3 header */ + skb->dev = dev; + + /* copy L3 payload */ + eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap); + memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap); + + /* create ethernet header: */ + eth[0]=pkt[0x0b]; + eth[1]=pkt[0x0a]; + eth[2]=pkt[0x09]; + eth[3]=pkt[0x08]; + eth[4]=pkt[0x04]; + eth[5]=pkt[0x03]; + + eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0; + + if (snap) { + eth[12] = pkt[18]; + eth[13] = pkt[19]; + } else { + /* protocol numbers are from rfc-1700 or + * http://www.iana.org/assignments/ethernet-numbers + */ + if (pkt[12] >> 4 == 6) { /* version field from IP header */ + eth[12] = 0x86; /* IPv6 */ + eth[13] = 0xdd; + } else { + eth[12] = 0x08; /* IPv4 */ + eth[13] = 0x00; + } + } + + skb->protocol = dvb_net_eth_type_trans(skb, dev); + + stats->rx_packets++; + stats->rx_bytes+=skb->len; + netif_rx(skb); +} + +static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, + struct dmx_section_filter *filter, + enum dmx_success success) +{ + struct net_device *dev = filter->priv; + + /** + * we rely on the DVB API definition where exactly one complete + * section is delivered in buffer1 + */ + dvb_net_sec (dev, buffer1, buffer1_len); + return 0; +} + +static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) +{ + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static u8 mask_allmulti[6]={0xff, 0xff, 0xff, 0x00, 0x00, 0x00}; +static u8 mac_allmulti[6]={0x01, 0x00, 0x5e, 0x00, 0x00, 0x00}; +static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static int dvb_net_filter_sec_set(struct net_device *dev, + struct dmx_section_filter **secfilter, + u8 *mac, u8 *mac_mask) +{ + struct dvb_net_priv *priv = netdev_priv(dev); + int ret; + + *secfilter=NULL; + ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter); + if (ret<0) { + printk("%s: could not get filter\n", dev->name); + return ret; + } + + (*secfilter)->priv=(void *) dev; + + memset((*secfilter)->filter_value, 0x00, DMX_MAX_FILTER_SIZE); + memset((*secfilter)->filter_mask, 0x00, DMX_MAX_FILTER_SIZE); + memset((*secfilter)->filter_mode, 0xff, DMX_MAX_FILTER_SIZE); + + (*secfilter)->filter_value[0]=0x3e; + (*secfilter)->filter_value[3]=mac[5]; + (*secfilter)->filter_value[4]=mac[4]; + (*secfilter)->filter_value[8]=mac[3]; + (*secfilter)->filter_value[9]=mac[2]; + (*secfilter)->filter_value[10]=mac[1]; + (*secfilter)->filter_value[11]=mac[0]; + + (*secfilter)->filter_mask[0] = 0xff; + (*secfilter)->filter_mask[3] = mac_mask[5]; + (*secfilter)->filter_mask[4] = mac_mask[4]; + (*secfilter)->filter_mask[8] = mac_mask[3]; + (*secfilter)->filter_mask[9] = mac_mask[2]; + (*secfilter)->filter_mask[10] = mac_mask[1]; + (*secfilter)->filter_mask[11]=mac_mask[0]; + + dprintk("%s: filter mac=%pM\n", dev->name, mac); + dprintk("%s: filter mask=%pM\n", dev->name, mac_mask); + + return 0; +} + +static int dvb_net_feed_start(struct net_device *dev) +{ + int ret = 0, i; + struct dvb_net_priv *priv = netdev_priv(dev); + struct dmx_demux *demux = priv->demux; + unsigned char *mac = (unsigned char *) dev->dev_addr; + + dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode); + mutex_lock(&priv->mutex); + if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) + printk("%s: BUG %d\n", __func__, __LINE__); + + priv->secfeed=NULL; + priv->secfilter=NULL; + priv->tsfeed = NULL; + + if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { + dprintk("%s: alloc secfeed\n", __func__); + ret=demux->allocate_section_feed(demux, &priv->secfeed, + dvb_net_sec_callback); + if (ret<0) { + printk("%s: could not allocate section feed\n", dev->name); + goto error; + } + + ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); + + if (ret<0) { + printk("%s: could not set section feed\n", dev->name); + priv->demux->release_section_feed(priv->demux, priv->secfeed); + priv->secfeed=NULL; + goto error; + } + + if (priv->rx_mode != RX_MODE_PROMISC) { + dprintk("%s: set secfilter\n", __func__); + dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal); + } + + switch (priv->rx_mode) { + case RX_MODE_MULTI: + for (i = 0; i < priv->multi_num; i++) { + dprintk("%s: set multi_secfilter[%d]\n", __func__, i); + dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i], + priv->multi_macs[i], mask_normal); + } + break; + case RX_MODE_ALL_MULTI: + priv->multi_num=1; + dprintk("%s: set multi_secfilter[0]\n", __func__); + dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0], + mac_allmulti, mask_allmulti); + break; + case RX_MODE_PROMISC: + priv->multi_num=0; + dprintk("%s: set secfilter\n", __func__); + dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc); + break; + } + + dprintk("%s: start filtering\n", __func__); + priv->secfeed->start_filtering(priv->secfeed); + } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { + struct timespec timeout = { 0, 10000000 }; // 10 msec + + /* we have payloads encapsulated in TS */ + dprintk("%s: alloc tsfeed\n", __func__); + ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); + if (ret < 0) { + printk("%s: could not allocate ts feed\n", dev->name); + goto error; + } + + /* Set netdevice pointer for ts decaps callback. */ + priv->tsfeed->priv = (void *)dev; + ret = priv->tsfeed->set(priv->tsfeed, + priv->pid, /* pid */ + TS_PACKET, /* type */ + DMX_TS_PES_OTHER, /* pes type */ + 32768, /* circular buffer size */ + timeout /* timeout */ + ); + + if (ret < 0) { + printk("%s: could not set ts feed\n", dev->name); + priv->demux->release_ts_feed(priv->demux, priv->tsfeed); + priv->tsfeed = NULL; + goto error; + } + + dprintk("%s: start filtering\n", __func__); + priv->tsfeed->start_filtering(priv->tsfeed); + } else + ret = -EINVAL; + +error: + mutex_unlock(&priv->mutex); + return ret; +} + +static int dvb_net_feed_stop(struct net_device *dev) +{ + struct dvb_net_priv *priv = netdev_priv(dev); + int i, ret = 0; + + dprintk("%s\n", __func__); + mutex_lock(&priv->mutex); + if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { + if (priv->secfeed) { + if (priv->secfeed->is_filtering) { + dprintk("%s: stop secfeed\n", __func__); + priv->secfeed->stop_filtering(priv->secfeed); + } + + if (priv->secfilter) { + dprintk("%s: release secfilter\n", __func__); + priv->secfeed->release_filter(priv->secfeed, + priv->secfilter); + priv->secfilter=NULL; + } + + for (i=0; imulti_num; i++) { + if (priv->multi_secfilter[i]) { + dprintk("%s: release multi_filter[%d]\n", + __func__, i); + priv->secfeed->release_filter(priv->secfeed, + priv->multi_secfilter[i]); + priv->multi_secfilter[i] = NULL; + } + } + + priv->demux->release_section_feed(priv->demux, priv->secfeed); + priv->secfeed = NULL; + } else + printk("%s: no feed to stop\n", dev->name); + } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { + if (priv->tsfeed) { + if (priv->tsfeed->is_filtering) { + dprintk("%s: stop tsfeed\n", __func__); + priv->tsfeed->stop_filtering(priv->tsfeed); + } + priv->demux->release_ts_feed(priv->demux, priv->tsfeed); + priv->tsfeed = NULL; + } + else + printk("%s: no ts feed to stop\n", dev->name); + } else + ret = -EINVAL; + mutex_unlock(&priv->mutex); + return ret; +} + + +static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr) +{ + struct dvb_net_priv *priv = netdev_priv(dev); + + if (priv->multi_num == DVB_NET_MULTICAST_MAX) + return -ENOMEM; + + memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN); + + priv->multi_num++; + return 0; +} + + +static void wq_set_multicast_list (struct work_struct *work) +{ + struct dvb_net_priv *priv = + container_of(work, struct dvb_net_priv, set_multicast_list_wq); + struct net_device *dev = priv->net; + + dvb_net_feed_stop(dev); + priv->rx_mode = RX_MODE_UNI; + netif_addr_lock_bh(dev); + + if (dev->flags & IFF_PROMISC) { + dprintk("%s: promiscuous mode\n", dev->name); + priv->rx_mode = RX_MODE_PROMISC; + } else if ((dev->flags & IFF_ALLMULTI)) { + dprintk("%s: allmulti mode\n", dev->name); + priv->rx_mode = RX_MODE_ALL_MULTI; + } else if (!netdev_mc_empty(dev)) { + struct netdev_hw_addr *ha; + + dprintk("%s: set_mc_list, %d entries\n", + dev->name, netdev_mc_count(dev)); + + priv->rx_mode = RX_MODE_MULTI; + priv->multi_num = 0; + + netdev_for_each_mc_addr(ha, dev) + dvb_set_mc_filter(dev, ha->addr); + } + + netif_addr_unlock_bh(dev); + dvb_net_feed_start(dev); +} + + +static void dvb_net_set_multicast_list (struct net_device *dev) +{ + struct dvb_net_priv *priv = netdev_priv(dev); + schedule_work(&priv->set_multicast_list_wq); +} + + +static void wq_restart_net_feed (struct work_struct *work) +{ + struct dvb_net_priv *priv = + container_of(work, struct dvb_net_priv, restart_net_feed_wq); + struct net_device *dev = priv->net; + + if (netif_running(dev)) { + dvb_net_feed_stop(dev); + dvb_net_feed_start(dev); + } +} + + +static int dvb_net_set_mac (struct net_device *dev, void *p) +{ + struct dvb_net_priv *priv = netdev_priv(dev); + struct sockaddr *addr=p; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + if (netif_running(dev)) + schedule_work(&priv->restart_net_feed_wq); + + return 0; +} + + +static int dvb_net_open(struct net_device *dev) +{ + struct dvb_net_priv *priv = netdev_priv(dev); + + priv->in_use++; + dvb_net_feed_start(dev); + return 0; +} + + +static int dvb_net_stop(struct net_device *dev) +{ + struct dvb_net_priv *priv = netdev_priv(dev); + + priv->in_use--; + return dvb_net_feed_stop(dev); +} + +static const struct header_ops dvb_header_ops = { + .create = eth_header, + .parse = eth_header_parse, + .rebuild = eth_rebuild_header, +}; + + +static const struct net_device_ops dvb_netdev_ops = { + .ndo_open = dvb_net_open, + .ndo_stop = dvb_net_stop, + .ndo_start_xmit = dvb_net_tx, + .ndo_set_multicast_list = dvb_net_set_multicast_list, + .ndo_set_mac_address = dvb_net_set_mac, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + +static void dvb_net_setup(struct net_device *dev) +{ + ether_setup(dev); + + dev->header_ops = &dvb_header_ops; + dev->netdev_ops = &dvb_netdev_ops; + dev->mtu = 4096; + + dev->flags |= IFF_NOARP; +} + +static int get_if(struct dvb_net *dvbnet) +{ + int i; + + for (i=0; istate[i]) + break; + + if (i == DVB_NET_DEVICES_MAX) + return -1; + + dvbnet->state[i]=1; + return i; +} + +static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) +{ + struct net_device *net; + struct dvb_net_priv *priv; + int result; + int if_num; + + if (feedtype != DVB_NET_FEEDTYPE_MPE && feedtype != DVB_NET_FEEDTYPE_ULE) + return -EINVAL; + if ((if_num = get_if(dvbnet)) < 0) + return -EINVAL; + + net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup); + if (!net) + return -ENOMEM; + + if (dvbnet->dvbdev->id) + snprintf(net->name, IFNAMSIZ, "dvb%d%u%d", + dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num); + else + /* compatibility fix to keep dvb0_0 format */ + snprintf(net->name, IFNAMSIZ, "dvb%d_%d", + dvbnet->dvbdev->adapter->num, if_num); + + net->addr_len = 6; + memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6); + + dvbnet->device[if_num] = net; + + priv = netdev_priv(net); + priv->net = net; + priv->demux = dvbnet->demux; + priv->pid = pid; + priv->rx_mode = RX_MODE_UNI; + priv->need_pusi = 1; + priv->tscc = 0; + priv->feedtype = feedtype; + reset_ule(priv); + + INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list); + INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed); + mutex_init(&priv->mutex); + + net->base_addr = pid; + + if ((result = register_netdev(net)) < 0) { + dvbnet->device[if_num] = NULL; + free_netdev(net); + return result; + } + printk("dvb_net: created network interface %s\n", net->name); + + return if_num; +} + +static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num) +{ + struct net_device *net = dvbnet->device[num]; + struct dvb_net_priv *priv; + + if (!dvbnet->state[num]) + return -EINVAL; + priv = netdev_priv(net); + if (priv->in_use) + return -EBUSY; + + dvb_net_stop(net); + flush_work_sync(&priv->set_multicast_list_wq); + flush_work_sync(&priv->restart_net_feed_wq); + printk("dvb_net: removed network interface %s\n", net->name); + unregister_netdev(net); + dvbnet->state[num]=0; + dvbnet->device[num] = NULL; + free_netdev(net); + + return 0; +} + +static int dvb_net_do_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_net *dvbnet = dvbdev->priv; + + if (((file->f_flags&O_ACCMODE)==O_RDONLY)) + return -EPERM; + + switch (cmd) { + case NET_ADD_IF: + { + struct dvb_net_if *dvbnetif = parg; + int result; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!try_module_get(dvbdev->adapter->module)) + return -EPERM; + + result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype); + if (result<0) { + module_put(dvbdev->adapter->module); + return result; + } + dvbnetif->if_num=result; + break; + } + case NET_GET_IF: + { + struct net_device *netdev; + struct dvb_net_priv *priv_data; + struct dvb_net_if *dvbnetif = parg; + + if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || + !dvbnet->state[dvbnetif->if_num]) + return -EINVAL; + + netdev = dvbnet->device[dvbnetif->if_num]; + + priv_data = netdev_priv(netdev); + dvbnetif->pid=priv_data->pid; + dvbnetif->feedtype=priv_data->feedtype; + break; + } + case NET_REMOVE_IF: + { + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if ((unsigned long) parg >= DVB_NET_DEVICES_MAX) + return -EINVAL; + ret = dvb_net_remove_if(dvbnet, (unsigned long) parg); + if (!ret) + module_put(dvbdev->adapter->module); + return ret; + } + + /* binary compatibility cruft */ + case __NET_ADD_IF_OLD: + { + struct __dvb_net_if_old *dvbnetif = parg; + int result; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!try_module_get(dvbdev->adapter->module)) + return -EPERM; + + result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE); + if (result<0) { + module_put(dvbdev->adapter->module); + return result; + } + dvbnetif->if_num=result; + break; + } + case __NET_GET_IF_OLD: + { + struct net_device *netdev; + struct dvb_net_priv *priv_data; + struct __dvb_net_if_old *dvbnetif = parg; + + if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || + !dvbnet->state[dvbnetif->if_num]) + return -EINVAL; + + netdev = dvbnet->device[dvbnetif->if_num]; + + priv_data = netdev_priv(netdev); + dvbnetif->pid=priv_data->pid; + break; + } + default: + return -ENOTTY; + } + return 0; +} + +static long dvb_net_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl); +} + +static int dvb_net_close(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_net *dvbnet = dvbdev->priv; + + dvb_generic_release(inode, file); + + if(dvbdev->users == 1 && dvbnet->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; + wake_up(&dvbdev->wait_queue); + } + return 0; +} + + +static const struct file_operations dvb_net_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dvb_net_ioctl, + .open = dvb_generic_open, + .release = dvb_net_close, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_net = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_net_fops, +}; + + +void dvb_net_release (struct dvb_net *dvbnet) +{ + int i; + + dvbnet->exit = 1; + if (dvbnet->dvbdev->users < 1) + wait_event(dvbnet->dvbdev->wait_queue, + dvbnet->dvbdev->users==1); + + dvb_unregister_device(dvbnet->dvbdev); + + for (i=0; istate[i]) + continue; + dvb_net_remove_if(dvbnet, i); + } +} +EXPORT_SYMBOL(dvb_net_release); + + +int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, + struct dmx_demux *dmx) +{ + int i; + + dvbnet->demux = dmx; + + for (i=0; istate[i] = 0; + + dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net, + dvbnet, DVB_DEVICE_NET); + + return 0; +} +EXPORT_SYMBOL(dvb_net_init); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_net.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_net.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_net.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_net.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * dvb_net.h + * + * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser 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. + * + */ + +#ifndef _DVB_NET_H_ +#define _DVB_NET_H_ + +#include +#include +#include +#include +#include + +#include "dvbdev.h" + +#define DVB_NET_DEVICES_MAX 10 + +#ifdef CONFIG_DVB_NET + +struct dvb_net { + struct dvb_device *dvbdev; + struct net_device *device[DVB_NET_DEVICES_MAX]; + int state[DVB_NET_DEVICES_MAX]; + unsigned int exit:1; + struct dmx_demux *demux; +}; + +void dvb_net_release(struct dvb_net *); +int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *); + +#else + +struct dvb_net { + struct dvb_device *dvbdev; +}; + +static inline void dvb_net_release(struct dvb_net *dvbnet) +{ +} + +static inline int dvb_net_init(struct dvb_adapter *adap, + struct dvb_net *dvbnet, struct dmx_demux *dmx) +{ + return 0; +} + +#endif /* ifdef CONFIG_DVB_NET */ + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,299 @@ +/* + * + * dvb_ringbuffer.c: ring buffer implementation for the dvb driver + * + * Copyright (C) 2003 Oliver Endriss + * Copyright (C) 2004 Andrew de Quincey + * + * based on code originally found in av7110.c & dvb_ci.c: + * Copyright (C) 1999-2003 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 +#include +#include +#include +#include +#include + +#include "dvb_ringbuffer.h" + +#define PKT_READY 0 +#define PKT_DISPOSED 1 + + +void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) +{ + rbuf->pread=rbuf->pwrite=0; + rbuf->data=data; + rbuf->size=len; + rbuf->error=0; + + init_waitqueue_head(&rbuf->queue); + + spin_lock_init(&(rbuf->lock)); +} + + + +int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) +{ + return (rbuf->pread==rbuf->pwrite); +} + + + +ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf) +{ + ssize_t free; + + free = rbuf->pread - rbuf->pwrite; + if (free <= 0) + free += rbuf->size; + return free-1; +} + + + +ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) +{ + ssize_t avail; + + avail = rbuf->pwrite - rbuf->pread; + if (avail < 0) + avail += rbuf->size; + return avail; +} + + + +void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) +{ + rbuf->pread = rbuf->pwrite; + rbuf->error = 0; +} +EXPORT_SYMBOL(dvb_ringbuffer_flush); + +void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf) +{ + rbuf->pread = rbuf->pwrite = 0; + rbuf->error = 0; +} + +void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf) +{ + unsigned long flags; + + spin_lock_irqsave(&rbuf->lock, flags); + dvb_ringbuffer_flush(rbuf); + spin_unlock_irqrestore(&rbuf->lock, flags); + + wake_up(&rbuf->queue); +} + +ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len) +{ + size_t todo = len; + size_t split; + + split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; + if (split > 0) { + if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) + return -EFAULT; + buf += split; + todo -= split; + rbuf->pread = 0; + } + if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) + return -EFAULT; + + rbuf->pread = (rbuf->pread + todo) % rbuf->size; + + return len; +} + +void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len) +{ + size_t todo = len; + size_t split; + + split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; + if (split > 0) { + memcpy(buf, rbuf->data+rbuf->pread, split); + buf += split; + todo -= split; + rbuf->pread = 0; + } + memcpy(buf, rbuf->data+rbuf->pread, todo); + + rbuf->pread = (rbuf->pread + todo) % rbuf->size; +} + + +ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len) +{ + size_t todo = len; + size_t split; + + split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; + + if (split > 0) { + memcpy(rbuf->data+rbuf->pwrite, buf, split); + buf += split; + todo -= split; + rbuf->pwrite = 0; + } + memcpy(rbuf->data+rbuf->pwrite, buf, todo); + rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; + + return len; +} + +ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len) +{ + int status; + ssize_t oldpwrite = rbuf->pwrite; + + DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8); + DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff); + DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY); + status = dvb_ringbuffer_write(rbuf, buf, len); + + if (status < 0) rbuf->pwrite = oldpwrite; + return status; +} + +ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, + int offset, u8 __user *buf, size_t len) +{ + size_t todo; + size_t split; + size_t pktlen; + + pktlen = rbuf->data[idx] << 8; + pktlen |= rbuf->data[(idx + 1) % rbuf->size]; + if (offset > pktlen) return -EINVAL; + if ((offset + len) > pktlen) len = pktlen - offset; + + idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; + todo = len; + split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; + if (split > 0) { + if (copy_to_user(buf, rbuf->data+idx, split)) + return -EFAULT; + buf += split; + todo -= split; + idx = 0; + } + if (copy_to_user(buf, rbuf->data+idx, todo)) + return -EFAULT; + + return len; +} + +ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, + int offset, u8* buf, size_t len) +{ + size_t todo; + size_t split; + size_t pktlen; + + pktlen = rbuf->data[idx] << 8; + pktlen |= rbuf->data[(idx + 1) % rbuf->size]; + if (offset > pktlen) return -EINVAL; + if ((offset + len) > pktlen) len = pktlen - offset; + + idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; + todo = len; + split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; + if (split > 0) { + memcpy(buf, rbuf->data+idx, split); + buf += split; + todo -= split; + idx = 0; + } + memcpy(buf, rbuf->data+idx, todo); + return len; +} + +void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) +{ + size_t pktlen; + + rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED; + + // clean up disposed packets + while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) { + if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) { + pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8; + pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1); + DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE); + } else { + // first packet is not disposed, so we stop cleaning now + break; + } + } +} + +ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen) +{ + int consumed; + int curpktlen; + int curpktstatus; + + if (idx == -1) { + idx = rbuf->pread; + } else { + curpktlen = rbuf->data[idx] << 8; + curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; + idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; + } + + consumed = (idx - rbuf->pread) % rbuf->size; + + while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) { + + curpktlen = rbuf->data[idx] << 8; + curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; + curpktstatus = rbuf->data[(idx + 2) % rbuf->size]; + + if (curpktstatus == PKT_READY) { + *pktlen = curpktlen; + return idx; + } + + consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE; + idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; + } + + // no packets available + return -1; +} + + + +EXPORT_SYMBOL(dvb_ringbuffer_init); +EXPORT_SYMBOL(dvb_ringbuffer_empty); +EXPORT_SYMBOL(dvb_ringbuffer_free); +EXPORT_SYMBOL(dvb_ringbuffer_avail); +EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); +EXPORT_SYMBOL(dvb_ringbuffer_read_user); +EXPORT_SYMBOL(dvb_ringbuffer_read); +EXPORT_SYMBOL(dvb_ringbuffer_write); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/dvb_ringbuffer.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,186 @@ +/* + * + * dvb_ringbuffer.h: ring buffer implementation for the dvb driver + * + * Copyright (C) 2003 Oliver Endriss + * Copyright (C) 2004 Andrew de Quincey + * + * based on code originally found in av7110.c & dvb_ci.c: + * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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. + */ + +#ifndef _DVB_RINGBUFFER_H_ +#define _DVB_RINGBUFFER_H_ + +#include +#include + +struct dvb_ringbuffer { + u8 *data; + ssize_t size; + ssize_t pread; + ssize_t pwrite; + int error; + + wait_queue_head_t queue; + spinlock_t lock; +}; + +#define DVB_RINGBUFFER_PKTHDRSIZE 3 + + +/* +** Notes: +** ------ +** (1) For performance reasons read and write routines don't check buffer sizes +** and/or number of bytes free/available. This has to be done before these +** routines are called. For example: +** +** *** write bytes *** +** free = dvb_ringbuffer_free(rbuf); +** if (free >= buflen) +** count = dvb_ringbuffer_write(rbuf, buffer, buflen); +** else +** ... +** +** *** read min. 1000, max. bytes *** +** avail = dvb_ringbuffer_avail(rbuf); +** if (avail >= 1000) +** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize)); +** else +** ... +** +** (2) If there is exactly one reader and one writer, there is no need +** to lock read or write operations. +** Two or more readers must be locked against each other. +** Flushing the buffer counts as a read operation. +** Resetting the buffer counts as a read and write operation. +** Two or more writers must be locked against each other. +*/ + +/* initialize ring buffer, lock and queue */ +extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len); + +/* test whether buffer is empty */ +extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf); + +/* return the number of free bytes in the buffer */ +extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf); + +/* return the number of bytes waiting in the buffer */ +extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf); + + +/* +** Reset the read and write pointers to zero and flush the buffer +** This counts as a read and write operation +*/ +extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf); + + +/* read routines & macros */ +/* ---------------------- */ +/* flush buffer */ +extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf); + +/* flush buffer protected by spinlock and wake-up waiting task(s) */ +extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); + +/* peek at byte in the buffer */ +#define DVB_RINGBUFFER_PEEK(rbuf,offs) \ + (rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size] + +/* advance read ptr by bytes */ +#define DVB_RINGBUFFER_SKIP(rbuf,num) \ + (rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size + +/* +** read bytes from ring buffer into +** specifies whether resides in user space +** returns number of bytes transferred or -EFAULT +*/ +extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, + u8 __user *buf, size_t len); +extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, + u8 *buf, size_t len); + + +/* write routines & macros */ +/* ----------------------- */ +/* write single byte to ring buffer */ +#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte) \ + { (rbuf)->data[(rbuf)->pwrite]=(byte); \ + (rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; } +/* +** write bytes to ring buffer +** specifies whether resides in user space +** returns number of bytes transferred or -EFAULT +*/ +extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, + size_t len); + + +/** + * Write a packet into the ringbuffer. + * + * Ringbuffer to write to. + * Buffer to write. + * Length of buffer (currently limited to 65535 bytes max). + * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. + */ +extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, + size_t len); + +/** + * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this + * does NOT update the read pointer in the ringbuffer. You must use + * dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required. + * + * Ringbuffer concerned. + * Packet index as returned by dvb_ringbuffer_pkt_next(). + * Offset into packet to read from. + * Destination buffer for data. + * Size of destination buffer. + * Set to 1 if is in userspace. + * returns Number of bytes read, or -EFAULT. + */ +extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, + int offset, u8 __user *buf, size_t len); +extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, + int offset, u8 *buf, size_t len); + +/** + * Dispose of a packet in the ring buffer. + * + * Ring buffer concerned. + * Packet index as returned by dvb_ringbuffer_pkt_next(). + */ +extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx); + +/** + * Get the index of the next packet in a ringbuffer. + * + * Ringbuffer concerned. + * Previous packet index, or -1 to return the first packet index. + * On success, will be updated to contain the length of the packet in bytes. + * returns Packet index (if >=0), or -1 if no packets available. + */ +extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen); + + +#endif /* _DVB_RINGBUFFER_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-core/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,11 @@ +# +# Makefile for the kernel DVB device drivers. +# + +dvb-net-$(CONFIG_DVB_NET) := dvb_net.o + +dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ + dvb_ca_en50221.o dvb_frontend.o \ + $(dvb-net-y) dvb_ringbuffer.o dvb_math.o + +obj-$(CONFIG_DVB_CORE) += dvb-core.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/a800.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/a800.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/a800.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/a800.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,207 @@ +/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T + * USB2.0 (A800) DVB-T receiver. + * + * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to + * - AVerMedia who kindly provided information and + * - Glen Harris who suffered from my mistakes during development. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_rc(args...) dprintk(debug,0x01,args) + +static int a800_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + /* do nothing for the AVerMedia */ + return 0; +} + +/* assure to put cold to 0 for iManufacturer == 1 */ +static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + *cold = udev->descriptor.iManufacturer != 1; + return 0; +} + +static struct rc_map_table rc_map_a800_table[] = { + { 0x0201, KEY_MODE }, /* SOURCE */ + { 0x0200, KEY_POWER2 }, /* POWER */ + { 0x0205, KEY_1 }, /* 1 */ + { 0x0206, KEY_2 }, /* 2 */ + { 0x0207, KEY_3 }, /* 3 */ + { 0x0209, KEY_4 }, /* 4 */ + { 0x020a, KEY_5 }, /* 5 */ + { 0x020b, KEY_6 }, /* 6 */ + { 0x020d, KEY_7 }, /* 7 */ + { 0x020e, KEY_8 }, /* 8 */ + { 0x020f, KEY_9 }, /* 9 */ + { 0x0212, KEY_LEFT }, /* L / DISPLAY */ + { 0x0211, KEY_0 }, /* 0 */ + { 0x0213, KEY_RIGHT }, /* R / CH RTN */ + { 0x0217, KEY_CAMERA }, /* SNAP SHOT */ + { 0x0210, KEY_LAST }, /* 16-CH PREV */ + { 0x021e, KEY_VOLUMEDOWN }, /* VOL DOWN */ + { 0x020c, KEY_ZOOM }, /* FULL SCREEN */ + { 0x021f, KEY_VOLUMEUP }, /* VOL UP */ + { 0x0214, KEY_MUTE }, /* MUTE */ + { 0x0208, KEY_AUDIO }, /* AUDIO */ + { 0x0219, KEY_RECORD }, /* RECORD */ + { 0x0218, KEY_PLAY }, /* PLAY */ + { 0x021b, KEY_STOP }, /* STOP */ + { 0x021a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */ + { 0x021d, KEY_BACK }, /* << / RED */ + { 0x021c, KEY_FORWARD }, /* >> / YELLOW */ + { 0x0203, KEY_TEXT }, /* TELETEXT */ + { 0x0204, KEY_EPG }, /* EPG */ + { 0x0215, KEY_MENU }, /* MENU */ + + { 0x0303, KEY_CHANNELUP }, /* CH UP */ + { 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */ + { 0x0301, KEY_FIRST }, /* |<< / GREEN */ + { 0x0300, KEY_LAST }, /* >>| / BLUE */ + +}; + +static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + int ret; + u8 *key = kmalloc(5, GFP_KERNEL); + if (!key) + return -ENOMEM; + + if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0), + 0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5, + 2000) != 5) { + ret = -ENODEV; + goto out; + } + + /* call the universal NEC remote processor, to find out the key's state and event */ + dvb_usb_nec_rc_key_to_event(d,key,event,state); + if (key[0] != 0) + deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + ret = 0; +out: + kfree(key); + return ret; +} + +/* USB Driver stuff */ +static struct dvb_usb_device_properties a800_properties; + +static int a800_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &a800_properties, + THIS_MODULE, NULL, adapter_nr); +} + +/* do not change the order of the ID table */ +static struct usb_device_id a800_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_WARM) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, a800_table); + +static struct dvb_usb_device_properties a800_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-avertv-a800-02.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + + .frontend_attach = dibusb_dib3000mc_frontend_attach, + .tuner_attach = dibusb_dib3000mc_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + + .size_of_priv = sizeof(struct dibusb_state), + }, + }, + + .power_ctrl = a800_power_ctrl, + .identify_state = a800_identify_state, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_a800_table, + .rc_map_size = ARRAY_SIZE(rc_map_a800_table), + .rc_query = a800_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + .num_device_descs = 1, + .devices = { + { "AVerMedia AverTV DVB-T USB 2.0 (A800)", + { &a800_table[0], NULL }, + { &a800_table[1], NULL }, + }, + } +}; + +static struct usb_driver a800_driver = { + .name = "dvb_usb_a800", + .probe = a800_probe, + .disconnect = dvb_usb_device_exit, + .id_table = a800_table, +}; + +/* module stuff */ +static int __init a800_module_init(void) +{ + int result; + if ((result = usb_register(&a800_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit a800_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&a800_driver); +} + +module_init (a800_module_init); +module_exit (a800_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1104 @@ +/* DVB USB compliant Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * see Documentation/dvb/REDME.dvb-usb for more information + */ +#include "af9005.h" + +/* debug */ +int dvb_usb_af9005_debug; +module_param_named(debug, dvb_usb_af9005_debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." + DVB_USB_DEBUG_STATUS); +/* enable obnoxious led */ +int dvb_usb_af9005_led = 1; +module_param_named(led, dvb_usb_af9005_led, bool, 0644); +MODULE_PARM_DESC(led, "enable led (default: 1)."); + +/* eeprom dump */ +static int dvb_usb_af9005_dump_eeprom; +module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); +MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* remote control decoder */ +static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len, + u32 *event, int *state); +static void *rc_keys; +static int *rc_keys_size; + +u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + +struct af9005_device_state { + u8 sequence; + int led_state; +}; + +static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, + int readwrite, int type, u8 * values, int len) +{ + struct af9005_device_state *st = d->priv; + u8 obuf[16] = { 0 }; + u8 ibuf[17] = { 0 }; + u8 command; + int i; + int ret; + + if (len < 1) { + err("generic read/write, less than 1 byte. Makes no sense."); + return -EINVAL; + } + if (len > 8) { + err("generic read/write, more than 8 bytes. Not supported."); + return -EINVAL; + } + + obuf[0] = 14; /* rest of buffer length low */ + obuf[1] = 0; /* rest of buffer length high */ + + obuf[2] = AF9005_REGISTER_RW; /* register operation */ + obuf[3] = 12; /* rest of buffer length */ + + obuf[4] = st->sequence++; /* sequence number */ + + obuf[5] = (u8) (reg >> 8); /* register address */ + obuf[6] = (u8) (reg & 0xff); + + if (type == AF9005_OFDM_REG) { + command = AF9005_CMD_OFDM_REG; + } else { + command = AF9005_CMD_TUNER; + } + + if (len > 1) + command |= + AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3; + command |= readwrite; + if (readwrite == AF9005_CMD_WRITE) + for (i = 0; i < len; i++) + obuf[8 + i] = values[i]; + else if (type == AF9005_TUNER_REG) + /* read command for tuner, the first byte contains the i2c address */ + obuf[8] = values[0]; + obuf[7] = command; + + ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0); + if (ret) + return ret; + + /* sanity check */ + if (ibuf[2] != AF9005_REGISTER_RW_ACK) { + err("generic read/write, wrong reply code."); + return -EIO; + } + if (ibuf[3] != 0x0d) { + err("generic read/write, wrong length in reply."); + return -EIO; + } + if (ibuf[4] != obuf[4]) { + err("generic read/write, wrong sequence in reply."); + return -EIO; + } + /* + Windows driver doesn't check these fields, in fact sometimes + the register in the reply is different that what has been sent + + if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) { + err("generic read/write, wrong register in reply."); + return -EIO; + } + if (ibuf[7] != command) { + err("generic read/write wrong command in reply."); + return -EIO; + } + */ + if (ibuf[16] != 0x01) { + err("generic read/write wrong status code in reply."); + return -EIO; + } + if (readwrite == AF9005_CMD_READ) + for (i = 0; i < len; i++) + values[i] = ibuf[8 + i]; + + return 0; + +} + +int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value) +{ + int ret; + deb_reg("read register %x ", reg); + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_READ, AF9005_OFDM_REG, + value, 1); + if (ret) + deb_reg("failed\n"); + else + deb_reg("value %x\n", *value); + return ret; +} + +int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len) +{ + int ret; + deb_reg("read %d registers %x ", len, reg); + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_READ, AF9005_OFDM_REG, + values, len); + if (ret) + deb_reg("failed\n"); + else + debug_dump(values, len, deb_reg); + return ret; +} + +int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value) +{ + int ret; + u8 temp = value; + deb_reg("write register %x value %x ", reg, value); + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_WRITE, AF9005_OFDM_REG, + &temp, 1); + if (ret) + deb_reg("failed\n"); + else + deb_reg("ok\n"); + return ret; +} + +int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len) +{ + int ret; + deb_reg("write %d registers %x values ", len, reg); + debug_dump(values, len, deb_reg); + + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_WRITE, AF9005_OFDM_REG, + values, len); + if (ret) + deb_reg("failed\n"); + else + deb_reg("ok\n"); + return ret; +} + +int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, + u8 len, u8 * value) +{ + u8 temp; + int ret; + deb_reg("read bits %x %x %x", reg, pos, len); + ret = af9005_read_ofdm_register(d, reg, &temp); + if (ret) { + deb_reg(" failed\n"); + return ret; + } + *value = (temp >> pos) & regmask[len - 1]; + deb_reg(" value %x\n", *value); + return 0; + +} + +int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, + u8 len, u8 value) +{ + u8 temp, mask; + int ret; + deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value); + if (pos == 0 && len == 8) + return af9005_write_ofdm_register(d, reg, value); + ret = af9005_read_ofdm_register(d, reg, &temp); + if (ret) + return ret; + mask = regmask[len - 1] << pos; + temp = (temp & ~mask) | ((value << pos) & mask); + return af9005_write_ofdm_register(d, reg, temp); + +} + +static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d, + u16 reg, u8 * values, int len) +{ + return af9005_generic_read_write(d, reg, + AF9005_CMD_READ, AF9005_TUNER_REG, + values, len); +} + +static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d, + u16 reg, u8 * values, int len) +{ + return af9005_generic_read_write(d, reg, + AF9005_CMD_WRITE, + AF9005_TUNER_REG, values, len); +} + +int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len) +{ + /* don't let the name of this function mislead you: it's just used + as an interface from the firmware to the i2c bus. The actual + i2c addresses are contained in the data */ + int ret, i, done = 0, fail = 0; + u8 temp; + ret = af9005_usb_write_tuner_registers(d, reg, values, len); + if (ret) + return ret; + if (reg != 0xffff) { + /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */ + for (i = 0; i < 200; i++) { + ret = + af9005_read_ofdm_register(d, + xd_I2C_i2c_m_status_wdat_done, + &temp); + if (ret) + return ret; + done = temp & (regmask[i2c_m_status_wdat_done_len - 1] + << i2c_m_status_wdat_done_pos); + if (done) + break; + fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1] + << i2c_m_status_wdat_fail_pos); + if (fail) + break; + msleep(50); + } + if (i == 200) + return -ETIMEDOUT; + if (fail) { + /* clear write fail bit */ + af9005_write_register_bits(d, + xd_I2C_i2c_m_status_wdat_fail, + i2c_m_status_wdat_fail_pos, + i2c_m_status_wdat_fail_len, + 1); + return -EIO; + } + /* clear write done bit */ + ret = + af9005_write_register_bits(d, + xd_I2C_i2c_m_status_wdat_fail, + i2c_m_status_wdat_done_pos, + i2c_m_status_wdat_done_len, 1); + if (ret) + return ret; + } + return 0; +} + +int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr, + u8 * values, int len) +{ + /* don't let the name of this function mislead you: it's just used + as an interface from the firmware to the i2c bus. The actual + i2c addresses are contained in the data */ + int ret, i; + u8 temp, buf[2]; + + buf[0] = addr; /* tuner i2c address */ + buf[1] = values[0]; /* tuner register */ + + values[0] = addr + 0x01; /* i2c read address */ + + if (reg == APO_REG_I2C_RW_SILICON_TUNER) { + /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */ + ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2); + if (ret) + return ret; + } + + /* send read command to ofsm */ + ret = af9005_usb_read_tuner_registers(d, reg, values, 1); + if (ret) + return ret; + + /* check if read done */ + for (i = 0; i < 200; i++) { + ret = af9005_read_ofdm_register(d, 0xa408, &temp); + if (ret) + return ret; + if (temp & 0x01) + break; + msleep(50); + } + if (i == 200) + return -ETIMEDOUT; + + /* clear read done bit (by writing 1) */ + ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1); + if (ret) + return ret; + + /* get read data (available from 0xa400) */ + for (i = 0; i < len; i++) { + ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp); + if (ret) + return ret; + values[i] = temp; + } + return 0; +} + +static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg, + u8 * data, int len) +{ + int ret, i; + u8 buf[3]; + deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr, + reg, len); + debug_dump(data, len, deb_i2c); + + for (i = 0; i < len; i++) { + buf[0] = i2caddr; + buf[1] = reg + (u8) i; + buf[2] = data[i]; + ret = + af9005_write_tuner_registers(d, + APO_REG_I2C_RW_SILICON_TUNER, + buf, 3); + if (ret) { + deb_i2c("i2c_write failed\n"); + return ret; + } + } + deb_i2c("i2c_write ok\n"); + return 0; +} + +static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg, + u8 * data, int len) +{ + int ret, i; + u8 temp; + deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len); + for (i = 0; i < len; i++) { + temp = reg + i; + ret = + af9005_read_tuner_registers(d, + APO_REG_I2C_RW_SILICON_TUNER, + i2caddr, &temp, 1); + if (ret) { + deb_i2c("i2c_read failed\n"); + return ret; + } + data[i] = temp; + } + deb_i2c("i2c data read: "); + debug_dump(data, len, deb_i2c); + return 0; +} + +static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + /* only implements what the mt2060 module does, don't know how + to make it really generic */ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret; + u8 reg, addr; + u8 *value; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + if (num == 2) { + /* reads a single register */ + reg = *msg[0].buf; + addr = msg[0].addr; + value = msg[1].buf; + ret = af9005_i2c_read(d, addr, reg, value, 1); + if (ret == 0) + ret = 2; + } else { + /* write one or more registers */ + reg = msg[0].buf[0]; + addr = msg[0].addr; + value = &msg[0].buf[1]; + ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1); + if (ret == 0) + ret = 1; + } + + mutex_unlock(&d->i2c_mutex); + return ret; +} + +static u32 af9005_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9005_i2c_algo = { + .master_xfer = af9005_i2c_xfer, + .functionality = af9005_i2c_func, +}; + +int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf, + int wlen, u8 * rbuf, int rlen) +{ + struct af9005_device_state *st = d->priv; + + int ret, i, packet_len; + u8 buf[64]; + u8 ibuf[64]; + + if (wlen < 0) { + err("send command, wlen less than 0 bytes. Makes no sense."); + return -EINVAL; + } + if (wlen > 54) { + err("send command, wlen more than 54 bytes. Not supported."); + return -EINVAL; + } + if (rlen > 54) { + err("send command, rlen more than 54 bytes. Not supported."); + return -EINVAL; + } + packet_len = wlen + 5; + buf[0] = (u8) (packet_len & 0xff); + buf[1] = (u8) ((packet_len & 0xff00) >> 8); + + buf[2] = 0x26; /* packet type */ + buf[3] = wlen + 3; + buf[4] = st->sequence++; + buf[5] = command; + buf[6] = wlen; + for (i = 0; i < wlen; i++) + buf[7 + i] = wbuf[i]; + ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0); + if (ret) + return ret; + if (ibuf[2] != 0x27) { + err("send command, wrong reply code."); + return -EIO; + } + if (ibuf[4] != buf[4]) { + err("send command, wrong sequence in reply."); + return -EIO; + } + if (ibuf[5] != 0x01) { + err("send command, wrong status code in reply."); + return -EIO; + } + if (ibuf[6] != rlen) { + err("send command, invalid data length in reply."); + return -EIO; + } + for (i = 0; i < rlen; i++) + rbuf[i] = ibuf[i + 7]; + return 0; +} + +int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values, + int len) +{ + struct af9005_device_state *st = d->priv; + u8 obuf[16], ibuf[14]; + int ret, i; + + memset(obuf, 0, sizeof(obuf)); + memset(ibuf, 0, sizeof(ibuf)); + + obuf[0] = 14; /* length of rest of packet low */ + obuf[1] = 0; /* length of rest of packer high */ + + obuf[2] = 0x2a; /* read/write eeprom */ + + obuf[3] = 12; /* size */ + + obuf[4] = st->sequence++; + + obuf[5] = 0; /* read */ + + obuf[6] = len; + obuf[7] = address; + ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0); + if (ret) + return ret; + if (ibuf[2] != 0x2b) { + err("Read eeprom, invalid reply code"); + return -EIO; + } + if (ibuf[3] != 10) { + err("Read eeprom, invalid reply length"); + return -EIO; + } + if (ibuf[4] != obuf[4]) { + err("Read eeprom, wrong sequence in reply "); + return -EIO; + } + if (ibuf[5] != 1) { + err("Read eeprom, wrong status in reply "); + return -EIO; + } + for (i = 0; i < len; i++) { + values[i] = ibuf[6 + i]; + } + return 0; +} + +static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply) +{ + u8 buf[FW_BULKOUT_SIZE + 2]; + u16 checksum; + int act_len, i, ret; + memset(buf, 0, sizeof(buf)); + buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); + buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); + switch (type) { + case FW_CONFIG: + buf[2] = 0x11; + buf[3] = 0x04; + buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ + buf[5] = 0x03; + checksum = buf[4] + buf[5]; + buf[6] = (u8) ((checksum >> 8) & 0xff); + buf[7] = (u8) (checksum & 0xff); + break; + case FW_CONFIRM: + buf[2] = 0x11; + buf[3] = 0x04; + buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ + buf[5] = 0x01; + checksum = buf[4] + buf[5]; + buf[6] = (u8) ((checksum >> 8) & 0xff); + buf[7] = (u8) (checksum & 0xff); + break; + case FW_BOOT: + buf[2] = 0x10; + buf[3] = 0x08; + buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ + buf[5] = 0x97; + buf[6] = 0xaa; + buf[7] = 0x55; + buf[8] = 0xa5; + buf[9] = 0x5a; + checksum = 0; + for (i = 4; i <= 9; i++) + checksum += buf[i]; + buf[10] = (u8) ((checksum >> 8) & 0xff); + buf[11] = (u8) (checksum & 0xff); + break; + default: + err("boot packet invalid boot packet type"); + return -EINVAL; + } + deb_fw(">>> "); + debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); + + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x02), + buf, FW_BULKOUT_SIZE + 2, &act_len, 2000); + if (ret) + err("boot packet bulk message failed: %d (%d/%d)", ret, + FW_BULKOUT_SIZE + 2, act_len); + else + ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0; + if (ret) + return ret; + memset(buf, 0, 9); + ret = usb_bulk_msg(udev, + usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000); + if (ret) { + err("boot packet recv bulk message failed: %d", ret); + return ret; + } + deb_fw("<<< "); + debug_dump(buf, act_len, deb_fw); + checksum = 0; + switch (type) { + case FW_CONFIG: + if (buf[2] != 0x11) { + err("boot bad config header."); + return -EIO; + } + if (buf[3] != 0x05) { + err("boot bad config size."); + return -EIO; + } + if (buf[4] != 0x00) { + err("boot bad config sequence."); + return -EIO; + } + if (buf[5] != 0x04) { + err("boot bad config subtype."); + return -EIO; + } + for (i = 4; i <= 6; i++) + checksum += buf[i]; + if (buf[7] * 256 + buf[8] != checksum) { + err("boot bad config checksum."); + return -EIO; + } + *reply = buf[6]; + break; + case FW_CONFIRM: + if (buf[2] != 0x11) { + err("boot bad confirm header."); + return -EIO; + } + if (buf[3] != 0x05) { + err("boot bad confirm size."); + return -EIO; + } + if (buf[4] != 0x00) { + err("boot bad confirm sequence."); + return -EIO; + } + if (buf[5] != 0x02) { + err("boot bad confirm subtype."); + return -EIO; + } + for (i = 4; i <= 6; i++) + checksum += buf[i]; + if (buf[7] * 256 + buf[8] != checksum) { + err("boot bad confirm checksum."); + return -EIO; + } + *reply = buf[6]; + break; + case FW_BOOT: + if (buf[2] != 0x10) { + err("boot bad boot header."); + return -EIO; + } + if (buf[3] != 0x05) { + err("boot bad boot size."); + return -EIO; + } + if (buf[4] != 0x00) { + err("boot bad boot sequence."); + return -EIO; + } + if (buf[5] != 0x01) { + err("boot bad boot pattern 01."); + return -EIO; + } + if (buf[6] != 0x10) { + err("boot bad boot pattern 10."); + return -EIO; + } + for (i = 4; i <= 6; i++) + checksum += buf[i]; + if (buf[7] * 256 + buf[8] != checksum) { + err("boot bad boot checksum."); + return -EIO; + } + break; + + } + + return 0; +} + +static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) +{ + int i, packets, ret, act_len; + + u8 buf[FW_BULKOUT_SIZE + 2]; + u8 reply; + + ret = af9005_boot_packet(udev, FW_CONFIG, &reply); + if (ret) + return ret; + if (reply != 0x01) { + err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply); + return -EIO; + } + packets = fw->size / FW_BULKOUT_SIZE; + buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); + buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); + for (i = 0; i < packets; i++) { + memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE, + FW_BULKOUT_SIZE); + deb_fw(">>> "); + debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x02), + buf, FW_BULKOUT_SIZE + 2, &act_len, 1000); + if (ret) { + err("firmware download failed at packet %d with code %d", i, ret); + return ret; + } + } + ret = af9005_boot_packet(udev, FW_CONFIRM, &reply); + if (ret) + return ret; + if (reply != (u8) (packets & 0xff)) { + err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply); + return -EIO; + } + ret = af9005_boot_packet(udev, FW_BOOT, &reply); + if (ret) + return ret; + ret = af9005_boot_packet(udev, FW_CONFIG, &reply); + if (ret) + return ret; + if (reply != 0x02) { + err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply); + return -EIO; + } + + return 0; + +} + +int af9005_led_control(struct dvb_usb_device *d, int onoff) +{ + struct af9005_device_state *st = d->priv; + int temp, ret; + + if (onoff && dvb_usb_af9005_led) + temp = 1; + else + temp = 0; + if (st->led_state != temp) { + ret = + af9005_write_register_bits(d, xd_p_reg_top_locken1, + reg_top_locken1_pos, + reg_top_locken1_len, temp); + if (ret) + return ret; + ret = + af9005_write_register_bits(d, xd_p_reg_top_lock1, + reg_top_lock1_pos, + reg_top_lock1_len, temp); + if (ret) + return ret; + st->led_state = temp; + } + return 0; +} + +static int af9005_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 buf[8]; + int i; + + /* without these calls the first commands after downloading + the firmware fail. I put these calls here to simulate + what it is done in dvb-usb-init.c. + */ + struct usb_device *udev = adap->dev->udev; + usb_clear_halt(udev, usb_sndbulkpipe(udev, 2)); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1)); + if (dvb_usb_af9005_dump_eeprom) { + printk("EEPROM DUMP\n"); + for (i = 0; i < 255; i += 8) { + af9005_read_eeprom(adap->dev, i, buf, 8); + printk("ADDR %x ", i); + debug_dump(buf, 8, printk); + } + } + adap->fe = af9005_fe_attach(adap->dev); + return 0; +} + +static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state) +{ + struct af9005_device_state *st = d->priv; + int ret, len; + + u8 obuf[5]; + u8 ibuf[256]; + + *state = REMOTE_NO_KEY_PRESSED; + if (rc_decode == NULL) { + /* it shouldn't never come here */ + return 0; + } + /* deb_info("rc_query\n"); */ + obuf[0] = 3; /* rest of packet length low */ + obuf[1] = 0; /* rest of packet lentgh high */ + obuf[2] = 0x40; /* read remote */ + obuf[3] = 1; /* rest of packet length */ + obuf[4] = st->sequence++; /* sequence number */ + ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0); + if (ret) { + err("rc query failed"); + return ret; + } + if (ibuf[2] != 0x41) { + err("rc query bad header."); + return -EIO; + } + if (ibuf[4] != obuf[4]) { + err("rc query bad sequence."); + return -EIO; + } + len = ibuf[5]; + if (len > 246) { + err("rc query invalid length"); + return -EIO; + } + if (len > 0) { + deb_rc("rc data (%d) ", len); + debug_dump((ibuf + 6), len, deb_rc); + ret = rc_decode(d, &ibuf[6], len, event, state); + if (ret) { + err("rc_decode failed"); + return ret; + } else { + deb_rc("rc_decode state %x event %x\n", *state, *event); + if (*state == REMOTE_KEY_REPEAT) + *event = d->last_event; + } + } + return 0; +} + +static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + + return 0; +} + +static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + deb_info("pid filter control onoff %d\n", onoff); + if (onoff) { + ret = + af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); + if (ret) + return ret; + ret = + af9005_write_register_bits(adap->dev, + XD_MP2IF_DMX_CTRL, 1, 1, 1); + if (ret) + return ret; + ret = + af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); + } else + ret = + af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0); + if (ret) + return ret; + deb_info("pid filter control ok\n"); + return 0; +} + +static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index, + u16 pid, int onoff) +{ + u8 cmd = index & 0x1f; + int ret; + deb_info("set pid filter, index %d, pid %x, onoff %d\n", index, + pid, onoff); + if (onoff) { + /* cannot use it as pid_filter_ctrl since it has to be done + before setting the first pid */ + if (adap->feedcount == 1) { + deb_info("first pid set, enable pid table\n"); + ret = af9005_pid_filter_control(adap, onoff); + if (ret) + return ret; + } + ret = + af9005_write_ofdm_register(adap->dev, + XD_MP2IF_PID_DATA_L, + (u8) (pid & 0xff)); + if (ret) + return ret; + ret = + af9005_write_ofdm_register(adap->dev, + XD_MP2IF_PID_DATA_H, + (u8) (pid >> 8)); + if (ret) + return ret; + cmd |= 0x20 | 0x40; + } else { + if (adap->feedcount == 0) { + deb_info("last pid unset, disable pid table\n"); + ret = af9005_pid_filter_control(adap, onoff); + if (ret) + return ret; + } + } + ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd); + if (ret) + return ret; + deb_info("set pid ok\n"); + return 0; +} + +static int af9005_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int ret; + u8 reply; + ret = af9005_boot_packet(udev, FW_CONFIG, &reply); + if (ret) + return ret; + deb_info("result of FW_CONFIG in identify state %d\n", reply); + if (reply == 0x01) + *cold = 1; + else if (reply == 0x02) + *cold = 0; + else + return -EIO; + deb_info("Identify state cold = %d\n", *cold); + return 0; +} + +static struct dvb_usb_device_properties af9005_properties; + +static int af9005_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &af9005_properties, + THIS_MODULE, NULL, adapter_nr); +} + +static struct usb_device_id af9005_usb_table[] = { + {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)}, + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)}, + {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)}, + {0}, +}; + +MODULE_DEVICE_TABLE(usb, af9005_usb_table); + +static struct dvb_usb_device_properties af9005_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "af9005.fw", + .download_firmware = af9005_download_firmware, + .no_reconnect = 1, + + .size_of_priv = sizeof(struct af9005_device_state), + + .num_adapters = 1, + .adapter = { + { + .caps = + DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = af9005_pid_filter, + /* .pid_filter_ctrl = af9005_pid_filter_control, */ + .frontend_attach = af9005_frontend_attach, + /* .tuner_attach = af9005_tuner_attach, */ + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 4096, /* actual size seen is 3948 */ + } + } + }, + } + }, + .power_ctrl = af9005_power_ctrl, + .identify_state = af9005_identify_state, + + .i2c_algo = &af9005_i2c_algo, + + .rc.legacy = { + .rc_interval = 200, + .rc_map_table = NULL, + .rc_map_size = 0, + .rc_query = af9005_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 2, + .generic_bulk_ctrl_endpoint_response = 1, + + .num_device_descs = 3, + .devices = { + {.name = "Afatech DVB-T USB1.1 stick", + .cold_ids = {&af9005_usb_table[0], NULL}, + .warm_ids = {NULL}, + }, + {.name = "TerraTec Cinergy T USB XE", + .cold_ids = {&af9005_usb_table[1], NULL}, + .warm_ids = {NULL}, + }, + {.name = "Ansonic DVB-T USB1.1 stick", + .cold_ids = {&af9005_usb_table[2], NULL}, + .warm_ids = {NULL}, + }, + {NULL}, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver af9005_usb_driver = { + .name = "dvb_usb_af9005", + .probe = af9005_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = af9005_usb_table, +}; + +/* module stuff */ +static int __init af9005_usb_module_init(void) +{ + int result; + if ((result = usb_register(&af9005_usb_driver))) { + err("usb_register failed. (%d)", result); + return result; + } + rc_decode = symbol_request(af9005_rc_decode); + rc_keys = symbol_request(rc_map_af9005_table); + rc_keys_size = symbol_request(rc_map_af9005_table_size); + if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) { + err("af9005_rc_decode function not found, disabling remote"); + af9005_properties.rc.legacy.rc_query = NULL; + } else { + af9005_properties.rc.legacy.rc_map_table = rc_keys; + af9005_properties.rc.legacy.rc_map_size = *rc_keys_size; + } + + return 0; +} + +static void __exit af9005_usb_module_exit(void) +{ + /* release rc decode symbols */ + if (rc_decode != NULL) + symbol_put(af9005_rc_decode); + if (rc_keys != NULL) + symbol_put(rc_map_af9005_table); + if (rc_keys_size != NULL) + symbol_put(rc_map_af9005_table_size); + /* deregister this driver from the USB subsystem */ + usb_deregister(&af9005_usb_driver); +} + +module_init(af9005_usb_module_init); +module_exit(af9005_usb_module_exit); + +MODULE_AUTHOR("Luca Olivetti "); +MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-fe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1488 @@ +/* Frontend part of the Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "af9005.h" +#include "af9005-script.h" +#include "mt2060.h" +#include "qt1010.h" +#include + +struct af9005_fe_state { + struct dvb_usb_device *d; + fe_status_t stat; + + /* retraining parameters */ + u32 original_fcw; + u16 original_rf_top; + u16 original_if_top; + u16 original_if_min; + u16 original_aci0_if_top; + u16 original_aci1_if_top; + u16 original_aci0_if_min; + u8 original_if_unplug_th; + u8 original_rf_unplug_th; + u8 original_dtop_if_unplug_th; + u8 original_dtop_rf_unplug_th; + + /* statistics */ + u32 pre_vit_error_count; + u32 pre_vit_bit_count; + u32 ber; + u32 post_vit_error_count; + u32 post_vit_bit_count; + u32 unc; + u16 abort_count; + + int opened; + int strong; + unsigned long next_status_check; + struct dvb_frontend frontend; +}; + +static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi, + u16 reglo, u8 pos, u8 len, u16 value) +{ + int ret; + u8 temp; + + if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff)))) + return ret; + temp = (u8) ((value & 0x0300) >> 8); + return af9005_write_register_bits(d, reghi, pos, len, + (u8) ((value & 0x300) >> 8)); +} + +static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi, + u16 reglo, u8 pos, u8 len, u16 * value) +{ + int ret; + u8 temp0, temp1; + + if ((ret = af9005_read_ofdm_register(d, reglo, &temp0))) + return ret; + if ((ret = af9005_read_ofdm_register(d, reghi, &temp1))) + return ret; + switch (pos) { + case 0: + *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0; + break; + case 2: + *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0; + break; + case 4: + *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0; + break; + case 6: + *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0; + break; + default: + err("invalid pos in read word agc"); + return -EINVAL; + } + return 0; + +} + +static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 temp; + + *available = false; + + ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, + fec_vtb_rsd_mon_en_pos, + fec_vtb_rsd_mon_en_len, &temp); + if (ret) + return ret; + if (temp & 1) { + ret = + af9005_read_register_bits(state->d, + xd_p_reg_ofsm_read_rbc_en, + reg_ofsm_read_rbc_en_pos, + reg_ofsm_read_rbc_en_len, &temp); + if (ret) + return ret; + if ((temp & 1) == 0) + *available = true; + + } + return 0; +} + +static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe, + u32 * post_err_count, + u32 * post_cw_count, + u16 * abort_count) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u32 err_count; + u32 cw_count; + u8 temp, temp0, temp1, temp2; + u16 loc_abort_count; + + *post_err_count = 0; + *post_cw_count = 0; + + /* check if error bit count is ready */ + ret = + af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy, + fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len, + &temp); + if (ret) + return ret; + if (!temp) { + deb_info("rsd counter not ready\n"); + return 100; + } + /* get abort count */ + ret = + af9005_read_ofdm_register(state->d, + xd_r_fec_rsd_abort_packet_cnt_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, + xd_r_fec_rsd_abort_packet_cnt_15_8, + &temp1); + if (ret) + return ret; + loc_abort_count = ((u16) temp1 << 8) + temp0; + + /* get error count */ + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8, + &temp1); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16, + &temp2); + if (ret) + return ret; + err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; + *post_err_count = err_count - (u32) loc_abort_count *8 * 8; + + /* get RSD packet number */ + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, + &temp1); + if (ret) + return ret; + cw_count = ((u32) temp1 << 8) + temp0; + if (cw_count == 0) { + err("wrong RSD packet count"); + return -EIO; + } + deb_info("POST abort count %d err count %d rsd packets %d\n", + loc_abort_count, err_count, cw_count); + *post_cw_count = cw_count - (u32) loc_abort_count; + *abort_count = loc_abort_count; + return 0; + +} + +static int af9005_get_post_vit_ber(struct dvb_frontend *fe, + u32 * post_err_count, u32 * post_cw_count, + u16 * abort_count) +{ + u32 loc_cw_count = 0, loc_err_count; + u16 loc_abort_count = 0; + int ret; + + ret = + af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count, + &loc_abort_count); + if (ret) + return ret; + *post_err_count = loc_err_count; + *post_cw_count = loc_cw_count * 204 * 8; + *abort_count = loc_abort_count; + + return 0; +} + +static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, + u32 * pre_err_count, + u32 * pre_bit_count) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + u8 temp, temp0, temp1, temp2; + u32 super_frame_count, x, bits; + int ret; + + ret = + af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy, + fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len, + &temp); + if (ret) + return ret; + if (!temp) { + deb_info("viterbi counter not ready\n"); + return 101; /* ERR_APO_VTB_COUNTER_NOT_READY; */ + } + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8, + &temp1); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16, + &temp2); + if (ret) + return ret; + *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; + + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, + &temp1); + if (ret) + return ret; + super_frame_count = ((u32) temp1 << 8) + temp0; + if (super_frame_count == 0) { + deb_info("super frame count 0\n"); + return 102; + } + + /* read fft mode */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, + reg_tpsd_txmod_pos, reg_tpsd_txmod_len, + &temp); + if (ret) + return ret; + if (temp == 0) { + /* 2K */ + x = 1512; + } else if (temp == 1) { + /* 8k */ + x = 6048; + } else { + err("Invalid fft mode"); + return -EINVAL; + } + + /* read constellation mode */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, + reg_tpsd_const_pos, reg_tpsd_const_len, + &temp); + if (ret) + return ret; + switch (temp) { + case 0: /* QPSK */ + bits = 2; + break; + case 1: /* QAM_16 */ + bits = 4; + break; + case 2: /* QAM_64 */ + bits = 6; + break; + default: + err("invalid constellation mode"); + return -EINVAL; + } + *pre_bit_count = super_frame_count * 68 * 4 * x * bits; + deb_info("PRE err count %d frame count %d bit count %d\n", + *pre_err_count, super_frame_count, *pre_bit_count); + return 0; +} + +static int af9005_reset_pre_viterbi(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + + /* set super frame count to 1 */ + ret = + af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, + 1 & 0xff); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, + 1 >> 8); + if (ret) + return ret; + /* reset pre viterbi error count */ + ret = + af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst, + fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len, + 1); + + return ret; +} + +static int af9005_reset_post_viterbi(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + + /* set packet unit */ + ret = + af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, + 10000 & 0xff); + if (ret) + return ret; + ret = + af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, + 10000 >> 8); + if (ret) + return ret; + /* reset post viterbi error count */ + ret = + af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst, + fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len, + 1); + + return ret; +} + +static int af9005_get_statistic(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret, fecavailable; + u64 numerator, denominator; + + deb_info("GET STATISTIC\n"); + ret = af9005_is_fecmon_available(fe, &fecavailable); + if (ret) + return ret; + if (!fecavailable) { + deb_info("fecmon not available\n"); + return 0; + } + + ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count, + &state->pre_vit_bit_count); + if (ret == 0) { + af9005_reset_pre_viterbi(fe); + if (state->pre_vit_bit_count > 0) { + /* according to v 0.0.4 of the dvb api ber should be a multiple + of 10E-9 so we have to multiply the error count by + 10E9=1000000000 */ + numerator = + (u64) state->pre_vit_error_count * (u64) 1000000000; + denominator = (u64) state->pre_vit_bit_count; + state->ber = do_div(numerator, denominator); + } else { + state->ber = 0xffffffff; + } + } + + ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count, + &state->post_vit_bit_count, + &state->abort_count); + if (ret == 0) { + ret = af9005_reset_post_viterbi(fe); + state->unc += state->abort_count; + if (ret) + return ret; + } + return 0; +} + +static int af9005_fe_refresh_state(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + if (time_after(jiffies, state->next_status_check)) { + deb_info("REFRESH STATE\n"); + + /* statistics */ + if (af9005_get_statistic(fe)) + err("get_statistic_failed"); + state->next_status_check = jiffies + 250 * HZ / 1000; + } + return 0; +} + +static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + u8 temp; + int ret; + + if (fe->ops.tuner_ops.release == NULL) + return -ENODEV; + + *stat = 0; + ret = af9005_read_register_bits(state->d, xd_p_agc_lock, + agc_lock_pos, agc_lock_len, &temp); + if (ret) + return ret; + if (temp) + *stat |= FE_HAS_SIGNAL; + + ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock, + fd_tpsd_lock_pos, fd_tpsd_lock_len, + &temp); + if (ret) + return ret; + if (temp) + *stat |= FE_HAS_CARRIER; + + ret = af9005_read_register_bits(state->d, + xd_r_mp2if_sync_byte_locked, + mp2if_sync_byte_locked_pos, + mp2if_sync_byte_locked_pos, &temp); + if (ret) + return ret; + if (temp) + *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK; + if (state->opened) + af9005_led_control(state->d, *stat & FE_HAS_LOCK); + + ret = + af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected, + reg_strong_sginal_detected_pos, + reg_strong_sginal_detected_len, &temp); + if (ret) + return ret; + if (temp != state->strong) { + deb_info("adjust for strong signal %d\n", temp); + state->strong = temp; + } + return 0; +} + +static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + if (fe->ops.tuner_ops.release == NULL) + return -ENODEV; + af9005_fe_refresh_state(fe); + *ber = state->ber; + return 0; +} + +static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + if (fe->ops.tuner_ops.release == NULL) + return -ENODEV; + af9005_fe_refresh_state(fe); + *unc = state->unc; + return 0; +} + +static int af9005_fe_read_signal_strength(struct dvb_frontend *fe, + u16 * strength) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 if_gain, rf_gain; + + if (fe->ops.tuner_ops.release == NULL) + return -ENODEV; + ret = + af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain, + &rf_gain); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain, + &if_gain); + if (ret) + return ret; + /* this value has no real meaning, but i don't have the tables that relate + the rf and if gain with the dbm, so I just scale the value */ + *strength = (512 - rf_gain - if_gain) << 7; + return 0; +} + +static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + /* the snr can be derived from the ber and the constellation + but I don't think this kind of complex calculations belong + in the driver. I may be wrong.... */ + return -ENOSYS; +} + +static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) +{ + u8 temp0, temp1, temp2, temp3, buf[4]; + int ret; + u32 NS_coeff1_2048Nu; + u32 NS_coeff1_8191Nu; + u32 NS_coeff1_8192Nu; + u32 NS_coeff1_8193Nu; + u32 NS_coeff2_2k; + u32 NS_coeff2_8k; + + switch (bw) { + case BANDWIDTH_6_MHZ: + NS_coeff1_2048Nu = 0x2ADB6DC; + NS_coeff1_8191Nu = 0xAB7313; + NS_coeff1_8192Nu = 0xAB6DB7; + NS_coeff1_8193Nu = 0xAB685C; + NS_coeff2_2k = 0x156DB6E; + NS_coeff2_8k = 0x55B6DC; + break; + + case BANDWIDTH_7_MHZ: + NS_coeff1_2048Nu = 0x3200001; + NS_coeff1_8191Nu = 0xC80640; + NS_coeff1_8192Nu = 0xC80000; + NS_coeff1_8193Nu = 0xC7F9C0; + NS_coeff2_2k = 0x1900000; + NS_coeff2_8k = 0x640000; + break; + + case BANDWIDTH_8_MHZ: + NS_coeff1_2048Nu = 0x3924926; + NS_coeff1_8191Nu = 0xE4996E; + NS_coeff1_8192Nu = 0xE49249; + NS_coeff1_8193Nu = 0xE48B25; + NS_coeff2_2k = 0x1C92493; + NS_coeff2_8k = 0x724925; + break; + default: + err("Invalid bandwidth %d.", bw); + return -EINVAL; + } + + /* + * write NS_coeff1_2048Nu + */ + + temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF); + temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16); + temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + /* cfoe_NS_2k_coeff1_25_24 */ + ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]); + if (ret) + return ret; + + /* cfoe_NS_2k_coeff1_23_16 */ + ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]); + if (ret) + return ret; + + /* cfoe_NS_2k_coeff1_15_8 */ + ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]); + if (ret) + return ret; + + /* cfoe_NS_2k_coeff1_7_0 */ + ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff2_2k + */ + + temp0 = (u8) ((NS_coeff2_2k & 0x0000003F)); + temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6); + temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14); + temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff1_8191Nu + */ + + temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF)); + temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16); + temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff1_8192Nu + */ + + temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF); + temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16); + temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff1_8193Nu + */ + + temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF)); + temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16); + temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff2_8k + */ + + temp0 = (u8) ((NS_coeff2_8k & 0x0000003F)); + temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6); + temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14); + temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]); + return ret; + +} + +static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw) +{ + u8 temp; + switch (bw) { + case BANDWIDTH_6_MHZ: + temp = 0; + break; + case BANDWIDTH_7_MHZ: + temp = 1; + break; + case BANDWIDTH_8_MHZ: + temp = 2; + break; + default: + err("Invalid bandwidth %d.", bw); + return -EINVAL; + } + return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos, + reg_bw_len, temp); +} + +static int af9005_fe_power(struct dvb_frontend *fe, int on) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + u8 temp = on; + int ret; + deb_info("power %s tuner\n", on ? "on" : "off"); + ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); + return ret; +} + +static struct mt2060_config af9005_mt2060_config = { + 0xC0 +}; + +static struct qt1010_config af9005_qt1010_config = { + 0xC4 +}; + +static int af9005_fe_init(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + struct dvb_usb_adapter *adap = fe->dvb->priv; + int ret, i, scriptlen; + u8 temp, temp0 = 0, temp1 = 0, temp2 = 0; + u8 buf[2]; + u16 if1; + + deb_info("in af9005_fe_init\n"); + + /* reset */ + deb_info("reset\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en, + 4, 1, 0x01))) + return ret; + if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0))) + return ret; + /* clear ofdm reset */ + deb_info("clear ofdm reset\n"); + for (i = 0; i < 150; i++) { + if ((ret = + af9005_read_ofdm_register(state->d, + xd_I2C_reg_ofdm_rst, &temp))) + return ret; + if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos)) + break; + msleep(10); + } + if (i == 150) + return -ETIMEDOUT; + + /*FIXME in the dump + write B200 A9 + write xd_g_reg_ofsm_clk 7 + read eepr c6 (2) + read eepr c7 (2) + misc ctrl 3 -> 1 + read eepr ca (6) + write xd_g_reg_ofsm_clk 0 + write B200 a1 + */ + ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07); + if (ret) + return ret; + temp = 0x01; + ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1); + if (ret) + return ret; + + temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos; + if ((ret = + af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, + reg_ofdm_rst_pos, reg_ofdm_rst_len, 1))) + return ret; + ret = af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, + reg_ofdm_rst_pos, reg_ofdm_rst_len, 0); + + if (ret) + return ret; + /* don't know what register aefc is, but this is what the windows driver does */ + ret = af9005_write_ofdm_register(state->d, 0xaefc, 0); + if (ret) + return ret; + + /* set stand alone chip */ + deb_info("set stand alone chip\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone, + reg_dca_stand_alone_pos, + reg_dca_stand_alone_len, 1))) + return ret; + + /* set dca upper & lower chip */ + deb_info("set dca upper & lower chip\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip, + reg_dca_upper_chip_pos, + reg_dca_upper_chip_len, 0))) + return ret; + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip, + reg_dca_lower_chip_pos, + reg_dca_lower_chip_len, 0))) + return ret; + + /* set 2wire master clock to 0x14 (for 60KHz) */ + deb_info("set 2wire master clock to 0x14 (for 60KHz)\n"); + if ((ret = + af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14))) + return ret; + + /* clear dca enable chip */ + deb_info("clear dca enable chip\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_en, + reg_dca_en_pos, reg_dca_en_len, 0))) + return ret; + /* FIXME these are register bits, but I don't know which ones */ + ret = af9005_write_ofdm_register(state->d, 0xa16c, 1); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0); + if (ret) + return ret; + + /* init other parameters: program cfoe and select bandwidth */ + deb_info("program cfoe\n"); + if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ))) + return ret; + /* set read-update bit for constellation */ + deb_info("set read-update bit for constellation\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_feq_read_update, + reg_feq_read_update_pos, + reg_feq_read_update_len, 1))) + return ret; + + /* sample code has a set MPEG TS code here + but sniffing reveals that it doesn't do it */ + + /* set read-update bit to 1 for DCA constellation */ + deb_info("set read-update bit 1 for DCA constellation\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_read_update, + reg_dca_read_update_pos, + reg_dca_read_update_len, 1))) + return ret; + + /* enable fec monitor */ + deb_info("enable fec monitor\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, + fec_vtb_rsd_mon_en_pos, + fec_vtb_rsd_mon_en_len, 1))) + return ret; + + /* FIXME should be register bits, I don't know which ones */ + ret = af9005_write_ofdm_register(state->d, 0xa601, 0); + + /* set api_retrain_never_freeze */ + deb_info("set api_retrain_never_freeze\n"); + if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01))) + return ret; + + /* load init script */ + deb_info("load init script\n"); + scriptlen = sizeof(script) / sizeof(RegDesc); + for (i = 0; i < scriptlen; i++) { + if ((ret = + af9005_write_register_bits(state->d, script[i].reg, + script[i].pos, + script[i].len, script[i].val))) + return ret; + /* save 3 bytes of original fcw */ + if (script[i].reg == 0xae18) + temp2 = script[i].val; + if (script[i].reg == 0xae19) + temp1 = script[i].val; + if (script[i].reg == 0xae1a) + temp0 = script[i].val; + + /* save original unplug threshold */ + if (script[i].reg == xd_p_reg_unplug_th) + state->original_if_unplug_th = script[i].val; + if (script[i].reg == xd_p_reg_unplug_rf_gain_th) + state->original_rf_unplug_th = script[i].val; + if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th) + state->original_dtop_if_unplug_th = script[i].val; + if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th) + state->original_dtop_rf_unplug_th = script[i].val; + + } + state->original_fcw = + ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0; + + + /* save original TOPs */ + deb_info("save original TOPs\n"); + + /* RF TOP */ + ret = + af9005_read_word_agc(state->d, + xd_p_reg_aagc_rf_top_numerator_9_8, + xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, + &state->original_rf_top); + if (ret) + return ret; + + /* IF TOP */ + ret = + af9005_read_word_agc(state->d, + xd_p_reg_aagc_if_top_numerator_9_8, + xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, + &state->original_if_top); + if (ret) + return ret; + + /* ACI 0 IF TOP */ + ret = + af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, + &state->original_aci0_if_top); + if (ret) + return ret; + + /* ACI 1 IF TOP */ + ret = + af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, + &state->original_aci1_if_top); + if (ret) + return ret; + + /* attach tuner and init */ + if (fe->ops.tuner_ops.release == NULL) { + /* read tuner and board id from eeprom */ + ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2); + if (ret) { + err("Impossible to read EEPROM\n"); + return ret; + } + deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]); + switch (buf[0]) { + case 2: /* MT2060 */ + /* read if1 from eeprom */ + ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2); + if (ret) { + err("Impossible to read EEPROM\n"); + return ret; + } + if1 = (u16) (buf[0] << 8) + buf[1]; + if (dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap, + &af9005_mt2060_config, if1) == NULL) { + deb_info("MT2060 attach failed\n"); + return -ENODEV; + } + break; + case 3: /* QT1010 */ + case 9: /* QT1010B */ + if (dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap, + &af9005_qt1010_config) ==NULL) { + deb_info("QT1010 attach failed\n"); + return -ENODEV; + } + break; + default: + err("Unsupported tuner type %d", buf[0]); + return -ENODEV; + } + ret = fe->ops.tuner_ops.init(fe); + if (ret) + return ret; + } + + deb_info("profit!\n"); + return 0; +} + +static int af9005_fe_sleep(struct dvb_frontend *fe) +{ + return af9005_fe_power(fe, 0); +} + +static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + + if (acquire) { + state->opened++; + } else { + + state->opened--; + if (!state->opened) + af9005_led_control(state->d, 0); + } + return 0; +} + +static int af9005_fe_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 temp, temp0, temp1, temp2; + + deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency, + fep->u.ofdm.bandwidth); + if (fe->ops.tuner_ops.release == NULL) { + err("Tuner not attached"); + return -ENODEV; + } + + deb_info("turn off led\n"); + /* not in the log */ + ret = af9005_led_control(state->d, 0); + if (ret) + return ret; + /* not sure about the bits */ + ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0); + if (ret) + return ret; + + /* set FCW to default value */ + deb_info("set FCW to default value\n"); + temp0 = (u8) (state->original_fcw & 0x000000ff); + temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8); + temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16); + ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xae19, temp1); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xae18, temp2); + if (ret) + return ret; + + /* restore original TOPs */ + deb_info("restore original TOPs\n"); + ret = + af9005_write_word_agc(state->d, + xd_p_reg_aagc_rf_top_numerator_9_8, + xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, + state->original_rf_top); + if (ret) + return ret; + ret = + af9005_write_word_agc(state->d, + xd_p_reg_aagc_if_top_numerator_9_8, + xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, + state->original_if_top); + if (ret) + return ret; + ret = + af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, + state->original_aci0_if_top); + if (ret) + return ret; + ret = + af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, + state->original_aci1_if_top); + if (ret) + return ret; + + /* select bandwidth */ + deb_info("select bandwidth"); + ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth); + if (ret) + return ret; + ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth); + if (ret) + return ret; + + /* clear easy mode flag */ + deb_info("clear easy mode flag\n"); + ret = af9005_write_ofdm_register(state->d, 0xaefd, 0); + if (ret) + return ret; + + /* set unplug threshold to original value */ + deb_info("set unplug threshold to original value\n"); + ret = + af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th, + state->original_if_unplug_th); + if (ret) + return ret; + /* set tuner */ + deb_info("set tuner\n"); + ret = fe->ops.tuner_ops.set_params(fe, fep); + if (ret) + return ret; + + /* trigger ofsm */ + deb_info("trigger ofsm\n"); + temp = 0; + ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1); + if (ret) + return ret; + + /* clear retrain and freeze flag */ + deb_info("clear retrain and freeze flag\n"); + ret = + af9005_write_register_bits(state->d, + xd_p_reg_api_retrain_request, + reg_api_retrain_request_pos, 2, 0); + if (ret) + return ret; + + /* reset pre viterbi and post viterbi registers and statistics */ + af9005_reset_pre_viterbi(fe); + af9005_reset_post_viterbi(fe); + state->pre_vit_error_count = 0; + state->pre_vit_bit_count = 0; + state->ber = 0; + state->post_vit_error_count = 0; + /* state->unc = 0; commented out since it should be ever increasing */ + state->abort_count = 0; + + state->next_status_check = jiffies; + state->strong = -1; + + return 0; +} + +static int af9005_fe_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 temp; + + /* mode */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, + reg_tpsd_const_pos, reg_tpsd_const_len, + &temp); + if (ret) + return ret; + deb_info("===== fe_get_frontend ==============\n"); + deb_info("CONSTELLATION "); + switch (temp) { + case 0: + fep->u.ofdm.constellation = QPSK; + deb_info("QPSK\n"); + break; + case 1: + fep->u.ofdm.constellation = QAM_16; + deb_info("QAM_16\n"); + break; + case 2: + fep->u.ofdm.constellation = QAM_64; + deb_info("QAM_64\n"); + break; + } + + /* tps hierarchy and alpha value */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier, + reg_tpsd_hier_pos, reg_tpsd_hier_len, + &temp); + if (ret) + return ret; + deb_info("HIERARCHY "); + switch (temp) { + case 0: + fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + deb_info("NONE\n"); + break; + case 1: + fep->u.ofdm.hierarchy_information = HIERARCHY_1; + deb_info("1\n"); + break; + case 2: + fep->u.ofdm.hierarchy_information = HIERARCHY_2; + deb_info("2\n"); + break; + case 3: + fep->u.ofdm.hierarchy_information = HIERARCHY_4; + deb_info("4\n"); + break; + } + + /* high/low priority */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_dec_pri, + reg_dec_pri_pos, reg_dec_pri_len, &temp); + if (ret) + return ret; + /* if temp is set = high priority */ + deb_info("PRIORITY %s\n", temp ? "high" : "low"); + + /* high coderate */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr, + reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len, + &temp); + if (ret) + return ret; + deb_info("CODERATE HP "); + switch (temp) { + case 0: + fep->u.ofdm.code_rate_HP = FEC_1_2; + deb_info("FEC_1_2\n"); + break; + case 1: + fep->u.ofdm.code_rate_HP = FEC_2_3; + deb_info("FEC_2_3\n"); + break; + case 2: + fep->u.ofdm.code_rate_HP = FEC_3_4; + deb_info("FEC_3_4\n"); + break; + case 3: + fep->u.ofdm.code_rate_HP = FEC_5_6; + deb_info("FEC_5_6\n"); + break; + case 4: + fep->u.ofdm.code_rate_HP = FEC_7_8; + deb_info("FEC_7_8\n"); + break; + } + + /* low coderate */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr, + reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len, + &temp); + if (ret) + return ret; + deb_info("CODERATE LP "); + switch (temp) { + case 0: + fep->u.ofdm.code_rate_LP = FEC_1_2; + deb_info("FEC_1_2\n"); + break; + case 1: + fep->u.ofdm.code_rate_LP = FEC_2_3; + deb_info("FEC_2_3\n"); + break; + case 2: + fep->u.ofdm.code_rate_LP = FEC_3_4; + deb_info("FEC_3_4\n"); + break; + case 3: + fep->u.ofdm.code_rate_LP = FEC_5_6; + deb_info("FEC_5_6\n"); + break; + case 4: + fep->u.ofdm.code_rate_LP = FEC_7_8; + deb_info("FEC_7_8\n"); + break; + } + + /* guard interval */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi, + reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp); + if (ret) + return ret; + deb_info("GUARD INTERVAL "); + switch (temp) { + case 0: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + deb_info("1_32\n"); + break; + case 1: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + deb_info("1_16\n"); + break; + case 2: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + deb_info("1_8\n"); + break; + case 3: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + deb_info("1_4\n"); + break; + } + + /* fft */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, + reg_tpsd_txmod_pos, reg_tpsd_txmod_len, + &temp); + if (ret) + return ret; + deb_info("TRANSMISSION MODE "); + switch (temp) { + case 0: + fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + deb_info("2K\n"); + break; + case 1: + fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + deb_info("8K\n"); + break; + } + + /* bandwidth */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos, + reg_bw_len, &temp); + deb_info("BANDWIDTH "); + switch (temp) { + case 0: + fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + deb_info("6\n"); + break; + case 1: + fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + deb_info("7\n"); + break; + case 2: + fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + deb_info("8\n"); + break; + } + return 0; +} + +static void af9005_fe_release(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = + (struct af9005_fe_state *)fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops af9005_fe_ops; + +struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d) +{ + struct af9005_fe_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL); + if (state == NULL) + goto error; + + deb_info("attaching frontend af9005\n"); + + state->d = d; + state->opened = 0; + + memcpy(&state->frontend.ops, &af9005_fe_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; + error: + return NULL; +} + +static struct dvb_frontend_ops af9005_fe_ops = { + .info = { + .name = "AF9005 USB DVB-T", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = af9005_fe_release, + + .init = af9005_fe_init, + .sleep = af9005_fe_sleep, + .ts_bus_ctrl = af9005_ts_bus_ctrl, + + .set_frontend = af9005_fe_set_frontend, + .get_frontend = af9005_fe_get_frontend, + + .read_status = af9005_fe_read_status, + .read_ber = af9005_fe_read_ber, + .read_signal_strength = af9005_fe_read_signal_strength, + .read_snr = af9005_fe_read_snr, + .read_ucblocks = af9005_fe_read_unc_blocks, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3496 @@ +/* Common header-file of the Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_AF9005_H_ +#define _DVB_USB_AF9005_H_ + +#define DVB_USB_LOG_PREFIX "af9005" +#include "dvb-usb.h" + +extern int dvb_usb_af9005_debug; +#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_af9005_debug,0x04,args) +#define deb_reg(args...) dprintk(dvb_usb_af9005_debug,0x08,args) +#define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args) +#define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args) + +extern int dvb_usb_af9005_led; + +/* firmware */ +#define FW_BULKOUT_SIZE 250 +enum { + FW_CONFIG, + FW_CONFIRM, + FW_BOOT +}; + +/* af9005 commands */ +#define AF9005_OFDM_REG 0 +#define AF9005_TUNER_REG 1 + +#define AF9005_REGISTER_RW 0x20 +#define AF9005_REGISTER_RW_ACK 0x21 + +#define AF9005_CMD_OFDM_REG 0x00 +#define AF9005_CMD_TUNER 0x80 +#define AF9005_CMD_BURST 0x02 +#define AF9005_CMD_AUTOINC 0x04 +#define AF9005_CMD_READ 0x00 +#define AF9005_CMD_WRITE 0x01 + +/* af9005 registers */ +#define APO_REG_RESET 0xAEFF + +#define APO_REG_I2C_RW_CAN_TUNER 0xF000 +#define APO_REG_I2C_RW_SILICON_TUNER 0xF001 +#define APO_REG_GPIO_RW_SILICON_TUNER 0xFFFE /* also for OFSM */ +#define APO_REG_TRIGGER_OFSM 0xFFFF /* also for OFSM */ + +/*********************************************************************** + * Apollo Registers from VLSI * + ***********************************************************************/ +#define xd_p_reg_aagc_inverted_agc 0xA000 +#define reg_aagc_inverted_agc_pos 0 +#define reg_aagc_inverted_agc_len 1 +#define reg_aagc_inverted_agc_lsb 0 +#define xd_p_reg_aagc_sign_only 0xA000 +#define reg_aagc_sign_only_pos 1 +#define reg_aagc_sign_only_len 1 +#define reg_aagc_sign_only_lsb 0 +#define xd_p_reg_aagc_slow_adc_en 0xA000 +#define reg_aagc_slow_adc_en_pos 2 +#define reg_aagc_slow_adc_en_len 1 +#define reg_aagc_slow_adc_en_lsb 0 +#define xd_p_reg_aagc_slow_adc_scale 0xA000 +#define reg_aagc_slow_adc_scale_pos 3 +#define reg_aagc_slow_adc_scale_len 5 +#define reg_aagc_slow_adc_scale_lsb 0 +#define xd_p_reg_aagc_check_slow_adc_lock 0xA001 +#define reg_aagc_check_slow_adc_lock_pos 0 +#define reg_aagc_check_slow_adc_lock_len 1 +#define reg_aagc_check_slow_adc_lock_lsb 0 +#define xd_p_reg_aagc_init_control 0xA001 +#define reg_aagc_init_control_pos 1 +#define reg_aagc_init_control_len 1 +#define reg_aagc_init_control_lsb 0 +#define xd_p_reg_aagc_total_gain_sel 0xA001 +#define reg_aagc_total_gain_sel_pos 2 +#define reg_aagc_total_gain_sel_len 2 +#define reg_aagc_total_gain_sel_lsb 0 +#define xd_p_reg_aagc_out_inv 0xA001 +#define reg_aagc_out_inv_pos 5 +#define reg_aagc_out_inv_len 1 +#define reg_aagc_out_inv_lsb 0 +#define xd_p_reg_aagc_int_en 0xA001 +#define reg_aagc_int_en_pos 6 +#define reg_aagc_int_en_len 1 +#define reg_aagc_int_en_lsb 0 +#define xd_p_reg_aagc_lock_change_flag 0xA001 +#define reg_aagc_lock_change_flag_pos 7 +#define reg_aagc_lock_change_flag_len 1 +#define reg_aagc_lock_change_flag_lsb 0 +#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002 +#define reg_aagc_rf_loop_bw_scale_acquire_pos 0 +#define reg_aagc_rf_loop_bw_scale_acquire_len 5 +#define reg_aagc_rf_loop_bw_scale_acquire_lsb 0 +#define xd_p_reg_aagc_rf_loop_bw_scale_track 0xA003 +#define reg_aagc_rf_loop_bw_scale_track_pos 0 +#define reg_aagc_rf_loop_bw_scale_track_len 5 +#define reg_aagc_rf_loop_bw_scale_track_lsb 0 +#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004 +#define reg_aagc_if_loop_bw_scale_acquire_pos 0 +#define reg_aagc_if_loop_bw_scale_acquire_len 5 +#define reg_aagc_if_loop_bw_scale_acquire_lsb 0 +#define xd_p_reg_aagc_if_loop_bw_scale_track 0xA005 +#define reg_aagc_if_loop_bw_scale_track_pos 0 +#define reg_aagc_if_loop_bw_scale_track_len 5 +#define reg_aagc_if_loop_bw_scale_track_lsb 0 +#define xd_p_reg_aagc_max_rf_agc_7_0 0xA006 +#define reg_aagc_max_rf_agc_7_0_pos 0 +#define reg_aagc_max_rf_agc_7_0_len 8 +#define reg_aagc_max_rf_agc_7_0_lsb 0 +#define xd_p_reg_aagc_max_rf_agc_9_8 0xA007 +#define reg_aagc_max_rf_agc_9_8_pos 0 +#define reg_aagc_max_rf_agc_9_8_len 2 +#define reg_aagc_max_rf_agc_9_8_lsb 8 +#define xd_p_reg_aagc_min_rf_agc_7_0 0xA008 +#define reg_aagc_min_rf_agc_7_0_pos 0 +#define reg_aagc_min_rf_agc_7_0_len 8 +#define reg_aagc_min_rf_agc_7_0_lsb 0 +#define xd_p_reg_aagc_min_rf_agc_9_8 0xA009 +#define reg_aagc_min_rf_agc_9_8_pos 0 +#define reg_aagc_min_rf_agc_9_8_len 2 +#define reg_aagc_min_rf_agc_9_8_lsb 8 +#define xd_p_reg_aagc_max_if_agc_7_0 0xA00A +#define reg_aagc_max_if_agc_7_0_pos 0 +#define reg_aagc_max_if_agc_7_0_len 8 +#define reg_aagc_max_if_agc_7_0_lsb 0 +#define xd_p_reg_aagc_max_if_agc_9_8 0xA00B +#define reg_aagc_max_if_agc_9_8_pos 0 +#define reg_aagc_max_if_agc_9_8_len 2 +#define reg_aagc_max_if_agc_9_8_lsb 8 +#define xd_p_reg_aagc_min_if_agc_7_0 0xA00C +#define reg_aagc_min_if_agc_7_0_pos 0 +#define reg_aagc_min_if_agc_7_0_len 8 +#define reg_aagc_min_if_agc_7_0_lsb 0 +#define xd_p_reg_aagc_min_if_agc_9_8 0xA00D +#define reg_aagc_min_if_agc_9_8_pos 0 +#define reg_aagc_min_if_agc_9_8_len 2 +#define reg_aagc_min_if_agc_9_8_lsb 8 +#define xd_p_reg_aagc_lock_sample_scale 0xA00E +#define reg_aagc_lock_sample_scale_pos 0 +#define reg_aagc_lock_sample_scale_len 5 +#define reg_aagc_lock_sample_scale_lsb 0 +#define xd_p_reg_aagc_rf_agc_lock_scale_acquire 0xA00F +#define reg_aagc_rf_agc_lock_scale_acquire_pos 0 +#define reg_aagc_rf_agc_lock_scale_acquire_len 3 +#define reg_aagc_rf_agc_lock_scale_acquire_lsb 0 +#define xd_p_reg_aagc_rf_agc_lock_scale_track 0xA00F +#define reg_aagc_rf_agc_lock_scale_track_pos 3 +#define reg_aagc_rf_agc_lock_scale_track_len 3 +#define reg_aagc_rf_agc_lock_scale_track_lsb 0 +#define xd_p_reg_aagc_if_agc_lock_scale_acquire 0xA010 +#define reg_aagc_if_agc_lock_scale_acquire_pos 0 +#define reg_aagc_if_agc_lock_scale_acquire_len 3 +#define reg_aagc_if_agc_lock_scale_acquire_lsb 0 +#define xd_p_reg_aagc_if_agc_lock_scale_track 0xA010 +#define reg_aagc_if_agc_lock_scale_track_pos 3 +#define reg_aagc_if_agc_lock_scale_track_len 3 +#define reg_aagc_if_agc_lock_scale_track_lsb 0 +#define xd_p_reg_aagc_rf_top_numerator_7_0 0xA011 +#define reg_aagc_rf_top_numerator_7_0_pos 0 +#define reg_aagc_rf_top_numerator_7_0_len 8 +#define reg_aagc_rf_top_numerator_7_0_lsb 0 +#define xd_p_reg_aagc_rf_top_numerator_9_8 0xA012 +#define reg_aagc_rf_top_numerator_9_8_pos 0 +#define reg_aagc_rf_top_numerator_9_8_len 2 +#define reg_aagc_rf_top_numerator_9_8_lsb 8 +#define xd_p_reg_aagc_if_top_numerator_7_0 0xA013 +#define reg_aagc_if_top_numerator_7_0_pos 0 +#define reg_aagc_if_top_numerator_7_0_len 8 +#define reg_aagc_if_top_numerator_7_0_lsb 0 +#define xd_p_reg_aagc_if_top_numerator_9_8 0xA014 +#define reg_aagc_if_top_numerator_9_8_pos 0 +#define reg_aagc_if_top_numerator_9_8_len 2 +#define reg_aagc_if_top_numerator_9_8_lsb 8 +#define xd_p_reg_aagc_adc_out_desired_7_0 0xA015 +#define reg_aagc_adc_out_desired_7_0_pos 0 +#define reg_aagc_adc_out_desired_7_0_len 8 +#define reg_aagc_adc_out_desired_7_0_lsb 0 +#define xd_p_reg_aagc_adc_out_desired_8 0xA016 +#define reg_aagc_adc_out_desired_8_pos 0 +#define reg_aagc_adc_out_desired_8_len 1 +#define reg_aagc_adc_out_desired_8_lsb 0 +#define xd_p_reg_aagc_fixed_gain 0xA016 +#define reg_aagc_fixed_gain_pos 3 +#define reg_aagc_fixed_gain_len 1 +#define reg_aagc_fixed_gain_lsb 0 +#define xd_p_reg_aagc_lock_count_th 0xA016 +#define reg_aagc_lock_count_th_pos 4 +#define reg_aagc_lock_count_th_len 4 +#define reg_aagc_lock_count_th_lsb 0 +#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017 +#define reg_aagc_fixed_rf_agc_control_7_0_pos 0 +#define reg_aagc_fixed_rf_agc_control_7_0_len 8 +#define reg_aagc_fixed_rf_agc_control_7_0_lsb 0 +#define xd_p_reg_aagc_fixed_rf_agc_control_15_8 0xA018 +#define reg_aagc_fixed_rf_agc_control_15_8_pos 0 +#define reg_aagc_fixed_rf_agc_control_15_8_len 8 +#define reg_aagc_fixed_rf_agc_control_15_8_lsb 8 +#define xd_p_reg_aagc_fixed_rf_agc_control_23_16 0xA019 +#define reg_aagc_fixed_rf_agc_control_23_16_pos 0 +#define reg_aagc_fixed_rf_agc_control_23_16_len 8 +#define reg_aagc_fixed_rf_agc_control_23_16_lsb 16 +#define xd_p_reg_aagc_fixed_rf_agc_control_30_24 0xA01A +#define reg_aagc_fixed_rf_agc_control_30_24_pos 0 +#define reg_aagc_fixed_rf_agc_control_30_24_len 7 +#define reg_aagc_fixed_rf_agc_control_30_24_lsb 24 +#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B +#define reg_aagc_fixed_if_agc_control_7_0_pos 0 +#define reg_aagc_fixed_if_agc_control_7_0_len 8 +#define reg_aagc_fixed_if_agc_control_7_0_lsb 0 +#define xd_p_reg_aagc_fixed_if_agc_control_15_8 0xA01C +#define reg_aagc_fixed_if_agc_control_15_8_pos 0 +#define reg_aagc_fixed_if_agc_control_15_8_len 8 +#define reg_aagc_fixed_if_agc_control_15_8_lsb 8 +#define xd_p_reg_aagc_fixed_if_agc_control_23_16 0xA01D +#define reg_aagc_fixed_if_agc_control_23_16_pos 0 +#define reg_aagc_fixed_if_agc_control_23_16_len 8 +#define reg_aagc_fixed_if_agc_control_23_16_lsb 16 +#define xd_p_reg_aagc_fixed_if_agc_control_30_24 0xA01E +#define reg_aagc_fixed_if_agc_control_30_24_pos 0 +#define reg_aagc_fixed_if_agc_control_30_24_len 7 +#define reg_aagc_fixed_if_agc_control_30_24_lsb 24 +#define xd_p_reg_aagc_rf_agc_unlock_numerator 0xA01F +#define reg_aagc_rf_agc_unlock_numerator_pos 0 +#define reg_aagc_rf_agc_unlock_numerator_len 6 +#define reg_aagc_rf_agc_unlock_numerator_lsb 0 +#define xd_p_reg_aagc_if_agc_unlock_numerator 0xA020 +#define reg_aagc_if_agc_unlock_numerator_pos 0 +#define reg_aagc_if_agc_unlock_numerator_len 6 +#define reg_aagc_if_agc_unlock_numerator_lsb 0 +#define xd_p_reg_unplug_th 0xA021 +#define reg_unplug_th_pos 0 +#define reg_unplug_th_len 8 +#define reg_aagc_rf_x0_lsb 0 +#define xd_p_reg_weak_signal_rfagc_thr 0xA022 +#define reg_weak_signal_rfagc_thr_pos 0 +#define reg_weak_signal_rfagc_thr_len 8 +#define reg_weak_signal_rfagc_thr_lsb 0 +#define xd_p_reg_unplug_rf_gain_th 0xA023 +#define reg_unplug_rf_gain_th_pos 0 +#define reg_unplug_rf_gain_th_len 8 +#define reg_unplug_rf_gain_th_lsb 0 +#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024 +#define reg_unplug_dtop_rf_gain_th_pos 0 +#define reg_unplug_dtop_rf_gain_th_len 8 +#define reg_unplug_dtop_rf_gain_th_lsb 0 +#define xd_p_reg_unplug_dtop_if_gain_th 0xA025 +#define reg_unplug_dtop_if_gain_th_pos 0 +#define reg_unplug_dtop_if_gain_th_len 8 +#define reg_unplug_dtop_if_gain_th_lsb 0 +#define xd_p_reg_top_recover_at_unplug_en 0xA026 +#define reg_top_recover_at_unplug_en_pos 0 +#define reg_top_recover_at_unplug_en_len 1 +#define reg_top_recover_at_unplug_en_lsb 0 +#define xd_p_reg_aagc_rf_x6 0xA027 +#define reg_aagc_rf_x6_pos 0 +#define reg_aagc_rf_x6_len 8 +#define reg_aagc_rf_x6_lsb 0 +#define xd_p_reg_aagc_rf_x7 0xA028 +#define reg_aagc_rf_x7_pos 0 +#define reg_aagc_rf_x7_len 8 +#define reg_aagc_rf_x7_lsb 0 +#define xd_p_reg_aagc_rf_x8 0xA029 +#define reg_aagc_rf_x8_pos 0 +#define reg_aagc_rf_x8_len 8 +#define reg_aagc_rf_x8_lsb 0 +#define xd_p_reg_aagc_rf_x9 0xA02A +#define reg_aagc_rf_x9_pos 0 +#define reg_aagc_rf_x9_len 8 +#define reg_aagc_rf_x9_lsb 0 +#define xd_p_reg_aagc_rf_x10 0xA02B +#define reg_aagc_rf_x10_pos 0 +#define reg_aagc_rf_x10_len 8 +#define reg_aagc_rf_x10_lsb 0 +#define xd_p_reg_aagc_rf_x11 0xA02C +#define reg_aagc_rf_x11_pos 0 +#define reg_aagc_rf_x11_len 8 +#define reg_aagc_rf_x11_lsb 0 +#define xd_p_reg_aagc_rf_x12 0xA02D +#define reg_aagc_rf_x12_pos 0 +#define reg_aagc_rf_x12_len 8 +#define reg_aagc_rf_x12_lsb 0 +#define xd_p_reg_aagc_rf_x13 0xA02E +#define reg_aagc_rf_x13_pos 0 +#define reg_aagc_rf_x13_len 8 +#define reg_aagc_rf_x13_lsb 0 +#define xd_p_reg_aagc_if_x0 0xA02F +#define reg_aagc_if_x0_pos 0 +#define reg_aagc_if_x0_len 8 +#define reg_aagc_if_x0_lsb 0 +#define xd_p_reg_aagc_if_x1 0xA030 +#define reg_aagc_if_x1_pos 0 +#define reg_aagc_if_x1_len 8 +#define reg_aagc_if_x1_lsb 0 +#define xd_p_reg_aagc_if_x2 0xA031 +#define reg_aagc_if_x2_pos 0 +#define reg_aagc_if_x2_len 8 +#define reg_aagc_if_x2_lsb 0 +#define xd_p_reg_aagc_if_x3 0xA032 +#define reg_aagc_if_x3_pos 0 +#define reg_aagc_if_x3_len 8 +#define reg_aagc_if_x3_lsb 0 +#define xd_p_reg_aagc_if_x4 0xA033 +#define reg_aagc_if_x4_pos 0 +#define reg_aagc_if_x4_len 8 +#define reg_aagc_if_x4_lsb 0 +#define xd_p_reg_aagc_if_x5 0xA034 +#define reg_aagc_if_x5_pos 0 +#define reg_aagc_if_x5_len 8 +#define reg_aagc_if_x5_lsb 0 +#define xd_p_reg_aagc_if_x6 0xA035 +#define reg_aagc_if_x6_pos 0 +#define reg_aagc_if_x6_len 8 +#define reg_aagc_if_x6_lsb 0 +#define xd_p_reg_aagc_if_x7 0xA036 +#define reg_aagc_if_x7_pos 0 +#define reg_aagc_if_x7_len 8 +#define reg_aagc_if_x7_lsb 0 +#define xd_p_reg_aagc_if_x8 0xA037 +#define reg_aagc_if_x8_pos 0 +#define reg_aagc_if_x8_len 8 +#define reg_aagc_if_x8_lsb 0 +#define xd_p_reg_aagc_if_x9 0xA038 +#define reg_aagc_if_x9_pos 0 +#define reg_aagc_if_x9_len 8 +#define reg_aagc_if_x9_lsb 0 +#define xd_p_reg_aagc_if_x10 0xA039 +#define reg_aagc_if_x10_pos 0 +#define reg_aagc_if_x10_len 8 +#define reg_aagc_if_x10_lsb 0 +#define xd_p_reg_aagc_if_x11 0xA03A +#define reg_aagc_if_x11_pos 0 +#define reg_aagc_if_x11_len 8 +#define reg_aagc_if_x11_lsb 0 +#define xd_p_reg_aagc_if_x12 0xA03B +#define reg_aagc_if_x12_pos 0 +#define reg_aagc_if_x12_len 8 +#define reg_aagc_if_x12_lsb 0 +#define xd_p_reg_aagc_if_x13 0xA03C +#define reg_aagc_if_x13_pos 0 +#define reg_aagc_if_x13_len 8 +#define reg_aagc_if_x13_lsb 0 +#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca 0xA03D +#define reg_aagc_min_rf_ctl_8bit_for_dca_pos 0 +#define reg_aagc_min_rf_ctl_8bit_for_dca_len 8 +#define reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0 +#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca 0xA03E +#define reg_aagc_min_if_ctl_8bit_for_dca_pos 0 +#define reg_aagc_min_if_ctl_8bit_for_dca_len 8 +#define reg_aagc_min_if_ctl_8bit_for_dca_lsb 0 +#define xd_r_reg_aagc_total_gain_7_0 0xA070 +#define reg_aagc_total_gain_7_0_pos 0 +#define reg_aagc_total_gain_7_0_len 8 +#define reg_aagc_total_gain_7_0_lsb 0 +#define xd_r_reg_aagc_total_gain_15_8 0xA071 +#define reg_aagc_total_gain_15_8_pos 0 +#define reg_aagc_total_gain_15_8_len 8 +#define reg_aagc_total_gain_15_8_lsb 8 +#define xd_p_reg_aagc_in_sat_cnt_7_0 0xA074 +#define reg_aagc_in_sat_cnt_7_0_pos 0 +#define reg_aagc_in_sat_cnt_7_0_len 8 +#define reg_aagc_in_sat_cnt_7_0_lsb 0 +#define xd_p_reg_aagc_in_sat_cnt_15_8 0xA075 +#define reg_aagc_in_sat_cnt_15_8_pos 0 +#define reg_aagc_in_sat_cnt_15_8_len 8 +#define reg_aagc_in_sat_cnt_15_8_lsb 8 +#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076 +#define reg_aagc_in_sat_cnt_23_16_pos 0 +#define reg_aagc_in_sat_cnt_23_16_len 8 +#define reg_aagc_in_sat_cnt_23_16_lsb 16 +#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077 +#define reg_aagc_in_sat_cnt_31_24_pos 0 +#define reg_aagc_in_sat_cnt_31_24_len 8 +#define reg_aagc_in_sat_cnt_31_24_lsb 24 +#define xd_r_reg_aagc_digital_rf_volt_7_0 0xA078 +#define reg_aagc_digital_rf_volt_7_0_pos 0 +#define reg_aagc_digital_rf_volt_7_0_len 8 +#define reg_aagc_digital_rf_volt_7_0_lsb 0 +#define xd_r_reg_aagc_digital_rf_volt_9_8 0xA079 +#define reg_aagc_digital_rf_volt_9_8_pos 0 +#define reg_aagc_digital_rf_volt_9_8_len 2 +#define reg_aagc_digital_rf_volt_9_8_lsb 8 +#define xd_r_reg_aagc_digital_if_volt_7_0 0xA07A +#define reg_aagc_digital_if_volt_7_0_pos 0 +#define reg_aagc_digital_if_volt_7_0_len 8 +#define reg_aagc_digital_if_volt_7_0_lsb 0 +#define xd_r_reg_aagc_digital_if_volt_9_8 0xA07B +#define reg_aagc_digital_if_volt_9_8_pos 0 +#define reg_aagc_digital_if_volt_9_8_len 2 +#define reg_aagc_digital_if_volt_9_8_lsb 8 +#define xd_r_reg_aagc_rf_gain 0xA07C +#define reg_aagc_rf_gain_pos 0 +#define reg_aagc_rf_gain_len 8 +#define reg_aagc_rf_gain_lsb 0 +#define xd_r_reg_aagc_if_gain 0xA07D +#define reg_aagc_if_gain_pos 0 +#define reg_aagc_if_gain_len 8 +#define reg_aagc_if_gain_lsb 0 +#define xd_p_tinr_imp_indicator 0xA080 +#define tinr_imp_indicator_pos 0 +#define tinr_imp_indicator_len 2 +#define tinr_imp_indicator_lsb 0 +#define xd_p_reg_tinr_fifo_size 0xA080 +#define reg_tinr_fifo_size_pos 2 +#define reg_tinr_fifo_size_len 5 +#define reg_tinr_fifo_size_lsb 0 +#define xd_p_reg_tinr_saturation_cnt_th 0xA081 +#define reg_tinr_saturation_cnt_th_pos 0 +#define reg_tinr_saturation_cnt_th_len 4 +#define reg_tinr_saturation_cnt_th_lsb 0 +#define xd_p_reg_tinr_saturation_th_3_0 0xA081 +#define reg_tinr_saturation_th_3_0_pos 4 +#define reg_tinr_saturation_th_3_0_len 4 +#define reg_tinr_saturation_th_3_0_lsb 0 +#define xd_p_reg_tinr_saturation_th_8_4 0xA082 +#define reg_tinr_saturation_th_8_4_pos 0 +#define reg_tinr_saturation_th_8_4_len 5 +#define reg_tinr_saturation_th_8_4_lsb 4 +#define xd_p_reg_tinr_imp_duration_th_2k_7_0 0xA083 +#define reg_tinr_imp_duration_th_2k_7_0_pos 0 +#define reg_tinr_imp_duration_th_2k_7_0_len 8 +#define reg_tinr_imp_duration_th_2k_7_0_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_2k_8 0xA084 +#define reg_tinr_imp_duration_th_2k_8_pos 0 +#define reg_tinr_imp_duration_th_2k_8_len 1 +#define reg_tinr_imp_duration_th_2k_8_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_8k_7_0 0xA085 +#define reg_tinr_imp_duration_th_8k_7_0_pos 0 +#define reg_tinr_imp_duration_th_8k_7_0_len 8 +#define reg_tinr_imp_duration_th_8k_7_0_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_8k_10_8 0xA086 +#define reg_tinr_imp_duration_th_8k_10_8_pos 0 +#define reg_tinr_imp_duration_th_8k_10_8_len 3 +#define reg_tinr_imp_duration_th_8k_10_8_lsb 8 +#define xd_p_reg_tinr_freq_ratio_6m_7_0 0xA087 +#define reg_tinr_freq_ratio_6m_7_0_pos 0 +#define reg_tinr_freq_ratio_6m_7_0_len 8 +#define reg_tinr_freq_ratio_6m_7_0_lsb 0 +#define xd_p_reg_tinr_freq_ratio_6m_12_8 0xA088 +#define reg_tinr_freq_ratio_6m_12_8_pos 0 +#define reg_tinr_freq_ratio_6m_12_8_len 5 +#define reg_tinr_freq_ratio_6m_12_8_lsb 8 +#define xd_p_reg_tinr_freq_ratio_7m_7_0 0xA089 +#define reg_tinr_freq_ratio_7m_7_0_pos 0 +#define reg_tinr_freq_ratio_7m_7_0_len 8 +#define reg_tinr_freq_ratio_7m_7_0_lsb 0 +#define xd_p_reg_tinr_freq_ratio_7m_12_8 0xA08A +#define reg_tinr_freq_ratio_7m_12_8_pos 0 +#define reg_tinr_freq_ratio_7m_12_8_len 5 +#define reg_tinr_freq_ratio_7m_12_8_lsb 8 +#define xd_p_reg_tinr_freq_ratio_8m_7_0 0xA08B +#define reg_tinr_freq_ratio_8m_7_0_pos 0 +#define reg_tinr_freq_ratio_8m_7_0_len 8 +#define reg_tinr_freq_ratio_8m_7_0_lsb 0 +#define xd_p_reg_tinr_freq_ratio_8m_12_8 0xA08C +#define reg_tinr_freq_ratio_8m_12_8_pos 0 +#define reg_tinr_freq_ratio_8m_12_8_len 5 +#define reg_tinr_freq_ratio_8m_12_8_lsb 8 +#define xd_p_reg_tinr_imp_duration_th_low_2k 0xA08D +#define reg_tinr_imp_duration_th_low_2k_pos 0 +#define reg_tinr_imp_duration_th_low_2k_len 8 +#define reg_tinr_imp_duration_th_low_2k_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_low_8k 0xA08E +#define reg_tinr_imp_duration_th_low_8k_pos 0 +#define reg_tinr_imp_duration_th_low_8k_len 8 +#define reg_tinr_imp_duration_th_low_8k_lsb 0 +#define xd_r_reg_tinr_counter_7_0 0xA090 +#define reg_tinr_counter_7_0_pos 0 +#define reg_tinr_counter_7_0_len 8 +#define reg_tinr_counter_7_0_lsb 0 +#define xd_r_reg_tinr_counter_15_8 0xA091 +#define reg_tinr_counter_15_8_pos 0 +#define reg_tinr_counter_15_8_len 8 +#define reg_tinr_counter_15_8_lsb 8 +#define xd_p_reg_tinr_adative_tinr_en 0xA093 +#define reg_tinr_adative_tinr_en_pos 0 +#define reg_tinr_adative_tinr_en_len 1 +#define reg_tinr_adative_tinr_en_lsb 0 +#define xd_p_reg_tinr_peak_fifo_size 0xA093 +#define reg_tinr_peak_fifo_size_pos 1 +#define reg_tinr_peak_fifo_size_len 5 +#define reg_tinr_peak_fifo_size_lsb 0 +#define xd_p_reg_tinr_counter_rst 0xA093 +#define reg_tinr_counter_rst_pos 6 +#define reg_tinr_counter_rst_len 1 +#define reg_tinr_counter_rst_lsb 0 +#define xd_p_reg_tinr_search_period_7_0 0xA094 +#define reg_tinr_search_period_7_0_pos 0 +#define reg_tinr_search_period_7_0_len 8 +#define reg_tinr_search_period_7_0_lsb 0 +#define xd_p_reg_tinr_search_period_15_8 0xA095 +#define reg_tinr_search_period_15_8_pos 0 +#define reg_tinr_search_period_15_8_len 8 +#define reg_tinr_search_period_15_8_lsb 8 +#define xd_p_reg_ccifs_fcw_7_0 0xA0A0 +#define reg_ccifs_fcw_7_0_pos 0 +#define reg_ccifs_fcw_7_0_len 8 +#define reg_ccifs_fcw_7_0_lsb 0 +#define xd_p_reg_ccifs_fcw_12_8 0xA0A1 +#define reg_ccifs_fcw_12_8_pos 0 +#define reg_ccifs_fcw_12_8_len 5 +#define reg_ccifs_fcw_12_8_lsb 8 +#define xd_p_reg_ccifs_spec_inv 0xA0A1 +#define reg_ccifs_spec_inv_pos 5 +#define reg_ccifs_spec_inv_len 1 +#define reg_ccifs_spec_inv_lsb 0 +#define xd_p_reg_gp_trigger 0xA0A2 +#define reg_gp_trigger_pos 0 +#define reg_gp_trigger_len 1 +#define reg_gp_trigger_lsb 0 +#define xd_p_reg_trigger_sel 0xA0A2 +#define reg_trigger_sel_pos 1 +#define reg_trigger_sel_len 2 +#define reg_trigger_sel_lsb 0 +#define xd_p_reg_debug_ofdm 0xA0A2 +#define reg_debug_ofdm_pos 3 +#define reg_debug_ofdm_len 2 +#define reg_debug_ofdm_lsb 0 +#define xd_p_reg_trigger_module_sel 0xA0A3 +#define reg_trigger_module_sel_pos 0 +#define reg_trigger_module_sel_len 6 +#define reg_trigger_module_sel_lsb 0 +#define xd_p_reg_trigger_set_sel 0xA0A4 +#define reg_trigger_set_sel_pos 0 +#define reg_trigger_set_sel_len 6 +#define reg_trigger_set_sel_lsb 0 +#define xd_p_reg_fw_int_mask_n 0xA0A4 +#define reg_fw_int_mask_n_pos 6 +#define reg_fw_int_mask_n_len 1 +#define reg_fw_int_mask_n_lsb 0 +#define xd_p_reg_debug_group 0xA0A5 +#define reg_debug_group_pos 0 +#define reg_debug_group_len 4 +#define reg_debug_group_lsb 0 +#define xd_p_reg_odbg_clk_sel 0xA0A5 +#define reg_odbg_clk_sel_pos 4 +#define reg_odbg_clk_sel_len 2 +#define reg_odbg_clk_sel_lsb 0 +#define xd_p_reg_ccif_sc 0xA0C0 +#define reg_ccif_sc_pos 0 +#define reg_ccif_sc_len 4 +#define reg_ccif_sc_lsb 0 +#define xd_r_reg_ccif_saturate 0xA0C1 +#define reg_ccif_saturate_pos 0 +#define reg_ccif_saturate_len 2 +#define reg_ccif_saturate_lsb 0 +#define xd_r_reg_antif_saturate 0xA0C1 +#define reg_antif_saturate_pos 2 +#define reg_antif_saturate_len 4 +#define reg_antif_saturate_lsb 0 +#define xd_r_reg_acif_saturate 0xA0C2 +#define reg_acif_saturate_pos 0 +#define reg_acif_saturate_len 8 +#define reg_acif_saturate_lsb 0 +#define xd_p_reg_tmr_timer0_threshold_7_0 0xA0C8 +#define reg_tmr_timer0_threshold_7_0_pos 0 +#define reg_tmr_timer0_threshold_7_0_len 8 +#define reg_tmr_timer0_threshold_7_0_lsb 0 +#define xd_p_reg_tmr_timer0_threshold_15_8 0xA0C9 +#define reg_tmr_timer0_threshold_15_8_pos 0 +#define reg_tmr_timer0_threshold_15_8_len 8 +#define reg_tmr_timer0_threshold_15_8_lsb 8 +#define xd_p_reg_tmr_timer0_enable 0xA0CA +#define reg_tmr_timer0_enable_pos 0 +#define reg_tmr_timer0_enable_len 1 +#define reg_tmr_timer0_enable_lsb 0 +#define xd_p_reg_tmr_timer0_clk_sel 0xA0CA +#define reg_tmr_timer0_clk_sel_pos 1 +#define reg_tmr_timer0_clk_sel_len 1 +#define reg_tmr_timer0_clk_sel_lsb 0 +#define xd_p_reg_tmr_timer0_int 0xA0CA +#define reg_tmr_timer0_int_pos 2 +#define reg_tmr_timer0_int_len 1 +#define reg_tmr_timer0_int_lsb 0 +#define xd_p_reg_tmr_timer0_rst 0xA0CA +#define reg_tmr_timer0_rst_pos 3 +#define reg_tmr_timer0_rst_len 1 +#define reg_tmr_timer0_rst_lsb 0 +#define xd_r_reg_tmr_timer0_count_7_0 0xA0CB +#define reg_tmr_timer0_count_7_0_pos 0 +#define reg_tmr_timer0_count_7_0_len 8 +#define reg_tmr_timer0_count_7_0_lsb 0 +#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC +#define reg_tmr_timer0_count_15_8_pos 0 +#define reg_tmr_timer0_count_15_8_len 8 +#define reg_tmr_timer0_count_15_8_lsb 8 +#define xd_p_reg_suspend 0xA0CD +#define reg_suspend_pos 0 +#define reg_suspend_len 1 +#define reg_suspend_lsb 0 +#define xd_p_reg_suspend_rdy 0xA0CD +#define reg_suspend_rdy_pos 1 +#define reg_suspend_rdy_len 1 +#define reg_suspend_rdy_lsb 0 +#define xd_p_reg_resume 0xA0CD +#define reg_resume_pos 2 +#define reg_resume_len 1 +#define reg_resume_lsb 0 +#define xd_p_reg_resume_rdy 0xA0CD +#define reg_resume_rdy_pos 3 +#define reg_resume_rdy_len 1 +#define reg_resume_rdy_lsb 0 +#define xd_p_reg_fmf 0xA0CE +#define reg_fmf_pos 0 +#define reg_fmf_len 8 +#define reg_fmf_lsb 0 +#define xd_p_ccid_accumulate_num_2k_7_0 0xA100 +#define ccid_accumulate_num_2k_7_0_pos 0 +#define ccid_accumulate_num_2k_7_0_len 8 +#define ccid_accumulate_num_2k_7_0_lsb 0 +#define xd_p_ccid_accumulate_num_2k_12_8 0xA101 +#define ccid_accumulate_num_2k_12_8_pos 0 +#define ccid_accumulate_num_2k_12_8_len 5 +#define ccid_accumulate_num_2k_12_8_lsb 8 +#define xd_p_ccid_accumulate_num_8k_7_0 0xA102 +#define ccid_accumulate_num_8k_7_0_pos 0 +#define ccid_accumulate_num_8k_7_0_len 8 +#define ccid_accumulate_num_8k_7_0_lsb 0 +#define xd_p_ccid_accumulate_num_8k_14_8 0xA103 +#define ccid_accumulate_num_8k_14_8_pos 0 +#define ccid_accumulate_num_8k_14_8_len 7 +#define ccid_accumulate_num_8k_14_8_lsb 8 +#define xd_p_ccid_desired_level_0 0xA103 +#define ccid_desired_level_0_pos 7 +#define ccid_desired_level_0_len 1 +#define ccid_desired_level_0_lsb 0 +#define xd_p_ccid_desired_level_8_1 0xA104 +#define ccid_desired_level_8_1_pos 0 +#define ccid_desired_level_8_1_len 8 +#define ccid_desired_level_8_1_lsb 1 +#define xd_p_ccid_apply_delay 0xA105 +#define ccid_apply_delay_pos 0 +#define ccid_apply_delay_len 7 +#define ccid_apply_delay_lsb 0 +#define xd_p_ccid_CCID_Threshold1 0xA106 +#define ccid_CCID_Threshold1_pos 0 +#define ccid_CCID_Threshold1_len 8 +#define ccid_CCID_Threshold1_lsb 0 +#define xd_p_ccid_CCID_Threshold2 0xA107 +#define ccid_CCID_Threshold2_pos 0 +#define ccid_CCID_Threshold2_len 8 +#define ccid_CCID_Threshold2_lsb 0 +#define xd_p_reg_ccid_gain_scale 0xA108 +#define reg_ccid_gain_scale_pos 0 +#define reg_ccid_gain_scale_len 4 +#define reg_ccid_gain_scale_lsb 0 +#define xd_p_reg_ccid2_passband_gain_set 0xA108 +#define reg_ccid2_passband_gain_set_pos 4 +#define reg_ccid2_passband_gain_set_len 4 +#define reg_ccid2_passband_gain_set_lsb 0 +#define xd_r_ccid_multiplier_7_0 0xA109 +#define ccid_multiplier_7_0_pos 0 +#define ccid_multiplier_7_0_len 8 +#define ccid_multiplier_7_0_lsb 0 +#define xd_r_ccid_multiplier_15_8 0xA10A +#define ccid_multiplier_15_8_pos 0 +#define ccid_multiplier_15_8_len 8 +#define ccid_multiplier_15_8_lsb 8 +#define xd_r_ccid_right_shift_bits 0xA10B +#define ccid_right_shift_bits_pos 0 +#define ccid_right_shift_bits_len 4 +#define ccid_right_shift_bits_lsb 0 +#define xd_r_reg_ccid_sx_7_0 0xA10C +#define reg_ccid_sx_7_0_pos 0 +#define reg_ccid_sx_7_0_len 8 +#define reg_ccid_sx_7_0_lsb 0 +#define xd_r_reg_ccid_sx_15_8 0xA10D +#define reg_ccid_sx_15_8_pos 0 +#define reg_ccid_sx_15_8_len 8 +#define reg_ccid_sx_15_8_lsb 8 +#define xd_r_reg_ccid_sx_21_16 0xA10E +#define reg_ccid_sx_21_16_pos 0 +#define reg_ccid_sx_21_16_len 6 +#define reg_ccid_sx_21_16_lsb 16 +#define xd_r_reg_ccid_sy_7_0 0xA110 +#define reg_ccid_sy_7_0_pos 0 +#define reg_ccid_sy_7_0_len 8 +#define reg_ccid_sy_7_0_lsb 0 +#define xd_r_reg_ccid_sy_15_8 0xA111 +#define reg_ccid_sy_15_8_pos 0 +#define reg_ccid_sy_15_8_len 8 +#define reg_ccid_sy_15_8_lsb 8 +#define xd_r_reg_ccid_sy_23_16 0xA112 +#define reg_ccid_sy_23_16_pos 0 +#define reg_ccid_sy_23_16_len 8 +#define reg_ccid_sy_23_16_lsb 16 +#define xd_r_reg_ccid2_sz_7_0 0xA114 +#define reg_ccid2_sz_7_0_pos 0 +#define reg_ccid2_sz_7_0_len 8 +#define reg_ccid2_sz_7_0_lsb 0 +#define xd_r_reg_ccid2_sz_15_8 0xA115 +#define reg_ccid2_sz_15_8_pos 0 +#define reg_ccid2_sz_15_8_len 8 +#define reg_ccid2_sz_15_8_lsb 8 +#define xd_r_reg_ccid2_sz_23_16 0xA116 +#define reg_ccid2_sz_23_16_pos 0 +#define reg_ccid2_sz_23_16_len 8 +#define reg_ccid2_sz_23_16_lsb 16 +#define xd_r_reg_ccid2_sz_25_24 0xA117 +#define reg_ccid2_sz_25_24_pos 0 +#define reg_ccid2_sz_25_24_len 2 +#define reg_ccid2_sz_25_24_lsb 24 +#define xd_r_reg_ccid2_sy_7_0 0xA118 +#define reg_ccid2_sy_7_0_pos 0 +#define reg_ccid2_sy_7_0_len 8 +#define reg_ccid2_sy_7_0_lsb 0 +#define xd_r_reg_ccid2_sy_15_8 0xA119 +#define reg_ccid2_sy_15_8_pos 0 +#define reg_ccid2_sy_15_8_len 8 +#define reg_ccid2_sy_15_8_lsb 8 +#define xd_r_reg_ccid2_sy_23_16 0xA11A +#define reg_ccid2_sy_23_16_pos 0 +#define reg_ccid2_sy_23_16_len 8 +#define reg_ccid2_sy_23_16_lsb 16 +#define xd_r_reg_ccid2_sy_25_24 0xA11B +#define reg_ccid2_sy_25_24_pos 0 +#define reg_ccid2_sy_25_24_len 2 +#define reg_ccid2_sy_25_24_lsb 24 +#define xd_p_dagc1_accumulate_num_2k_7_0 0xA120 +#define dagc1_accumulate_num_2k_7_0_pos 0 +#define dagc1_accumulate_num_2k_7_0_len 8 +#define dagc1_accumulate_num_2k_7_0_lsb 0 +#define xd_p_dagc1_accumulate_num_2k_12_8 0xA121 +#define dagc1_accumulate_num_2k_12_8_pos 0 +#define dagc1_accumulate_num_2k_12_8_len 5 +#define dagc1_accumulate_num_2k_12_8_lsb 8 +#define xd_p_dagc1_accumulate_num_8k_7_0 0xA122 +#define dagc1_accumulate_num_8k_7_0_pos 0 +#define dagc1_accumulate_num_8k_7_0_len 8 +#define dagc1_accumulate_num_8k_7_0_lsb 0 +#define xd_p_dagc1_accumulate_num_8k_14_8 0xA123 +#define dagc1_accumulate_num_8k_14_8_pos 0 +#define dagc1_accumulate_num_8k_14_8_len 7 +#define dagc1_accumulate_num_8k_14_8_lsb 8 +#define xd_p_dagc1_desired_level_0 0xA123 +#define dagc1_desired_level_0_pos 7 +#define dagc1_desired_level_0_len 1 +#define dagc1_desired_level_0_lsb 0 +#define xd_p_dagc1_desired_level_8_1 0xA124 +#define dagc1_desired_level_8_1_pos 0 +#define dagc1_desired_level_8_1_len 8 +#define dagc1_desired_level_8_1_lsb 1 +#define xd_p_dagc1_apply_delay 0xA125 +#define dagc1_apply_delay_pos 0 +#define dagc1_apply_delay_len 7 +#define dagc1_apply_delay_lsb 0 +#define xd_p_dagc1_bypass_scale_ctl 0xA126 +#define dagc1_bypass_scale_ctl_pos 0 +#define dagc1_bypass_scale_ctl_len 2 +#define dagc1_bypass_scale_ctl_lsb 0 +#define xd_p_reg_dagc1_in_sat_cnt_7_0 0xA127 +#define reg_dagc1_in_sat_cnt_7_0_pos 0 +#define reg_dagc1_in_sat_cnt_7_0_len 8 +#define reg_dagc1_in_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128 +#define reg_dagc1_in_sat_cnt_15_8_pos 0 +#define reg_dagc1_in_sat_cnt_15_8_len 8 +#define reg_dagc1_in_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc1_in_sat_cnt_23_16 0xA129 +#define reg_dagc1_in_sat_cnt_23_16_pos 0 +#define reg_dagc1_in_sat_cnt_23_16_len 8 +#define reg_dagc1_in_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc1_in_sat_cnt_31_24 0xA12A +#define reg_dagc1_in_sat_cnt_31_24_pos 0 +#define reg_dagc1_in_sat_cnt_31_24_len 8 +#define reg_dagc1_in_sat_cnt_31_24_lsb 24 +#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B +#define reg_dagc1_out_sat_cnt_7_0_pos 0 +#define reg_dagc1_out_sat_cnt_7_0_len 8 +#define reg_dagc1_out_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc1_out_sat_cnt_15_8 0xA12C +#define reg_dagc1_out_sat_cnt_15_8_pos 0 +#define reg_dagc1_out_sat_cnt_15_8_len 8 +#define reg_dagc1_out_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc1_out_sat_cnt_23_16 0xA12D +#define reg_dagc1_out_sat_cnt_23_16_pos 0 +#define reg_dagc1_out_sat_cnt_23_16_len 8 +#define reg_dagc1_out_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc1_out_sat_cnt_31_24 0xA12E +#define reg_dagc1_out_sat_cnt_31_24_pos 0 +#define reg_dagc1_out_sat_cnt_31_24_len 8 +#define reg_dagc1_out_sat_cnt_31_24_lsb 24 +#define xd_r_dagc1_multiplier_7_0 0xA136 +#define dagc1_multiplier_7_0_pos 0 +#define dagc1_multiplier_7_0_len 8 +#define dagc1_multiplier_7_0_lsb 0 +#define xd_r_dagc1_multiplier_15_8 0xA137 +#define dagc1_multiplier_15_8_pos 0 +#define dagc1_multiplier_15_8_len 8 +#define dagc1_multiplier_15_8_lsb 8 +#define xd_r_dagc1_right_shift_bits 0xA138 +#define dagc1_right_shift_bits_pos 0 +#define dagc1_right_shift_bits_len 4 +#define dagc1_right_shift_bits_lsb 0 +#define xd_p_reg_bfs_fcw_7_0 0xA140 +#define reg_bfs_fcw_7_0_pos 0 +#define reg_bfs_fcw_7_0_len 8 +#define reg_bfs_fcw_7_0_lsb 0 +#define xd_p_reg_bfs_fcw_15_8 0xA141 +#define reg_bfs_fcw_15_8_pos 0 +#define reg_bfs_fcw_15_8_len 8 +#define reg_bfs_fcw_15_8_lsb 8 +#define xd_p_reg_bfs_fcw_22_16 0xA142 +#define reg_bfs_fcw_22_16_pos 0 +#define reg_bfs_fcw_22_16_len 7 +#define reg_bfs_fcw_22_16_lsb 16 +#define xd_p_reg_antif_sf_7_0 0xA144 +#define reg_antif_sf_7_0_pos 0 +#define reg_antif_sf_7_0_len 8 +#define reg_antif_sf_7_0_lsb 0 +#define xd_p_reg_antif_sf_11_8 0xA145 +#define reg_antif_sf_11_8_pos 0 +#define reg_antif_sf_11_8_len 4 +#define reg_antif_sf_11_8_lsb 8 +#define xd_r_bfs_fcw_q_7_0 0xA150 +#define bfs_fcw_q_7_0_pos 0 +#define bfs_fcw_q_7_0_len 8 +#define bfs_fcw_q_7_0_lsb 0 +#define xd_r_bfs_fcw_q_15_8 0xA151 +#define bfs_fcw_q_15_8_pos 0 +#define bfs_fcw_q_15_8_len 8 +#define bfs_fcw_q_15_8_lsb 8 +#define xd_r_bfs_fcw_q_22_16 0xA152 +#define bfs_fcw_q_22_16_pos 0 +#define bfs_fcw_q_22_16_len 7 +#define bfs_fcw_q_22_16_lsb 16 +#define xd_p_reg_dca_enu 0xA160 +#define reg_dca_enu_pos 0 +#define reg_dca_enu_len 1 +#define reg_dca_enu_lsb 0 +#define xd_p_reg_dca_enl 0xA160 +#define reg_dca_enl_pos 1 +#define reg_dca_enl_len 1 +#define reg_dca_enl_lsb 0 +#define xd_p_reg_dca_lower_chip 0xA160 +#define reg_dca_lower_chip_pos 2 +#define reg_dca_lower_chip_len 1 +#define reg_dca_lower_chip_lsb 0 +#define xd_p_reg_dca_upper_chip 0xA160 +#define reg_dca_upper_chip_pos 3 +#define reg_dca_upper_chip_len 1 +#define reg_dca_upper_chip_lsb 0 +#define xd_p_reg_dca_platch 0xA160 +#define reg_dca_platch_pos 4 +#define reg_dca_platch_len 1 +#define reg_dca_platch_lsb 0 +#define xd_p_reg_dca_th 0xA161 +#define reg_dca_th_pos 0 +#define reg_dca_th_len 5 +#define reg_dca_th_lsb 0 +#define xd_p_reg_dca_scale 0xA162 +#define reg_dca_scale_pos 0 +#define reg_dca_scale_len 4 +#define reg_dca_scale_lsb 0 +#define xd_p_reg_dca_tone_7_0 0xA163 +#define reg_dca_tone_7_0_pos 0 +#define reg_dca_tone_7_0_len 8 +#define reg_dca_tone_7_0_lsb 0 +#define xd_p_reg_dca_tone_12_8 0xA164 +#define reg_dca_tone_12_8_pos 0 +#define reg_dca_tone_12_8_len 5 +#define reg_dca_tone_12_8_lsb 8 +#define xd_p_reg_dca_time_7_0 0xA165 +#define reg_dca_time_7_0_pos 0 +#define reg_dca_time_7_0_len 8 +#define reg_dca_time_7_0_lsb 0 +#define xd_p_reg_dca_time_15_8 0xA166 +#define reg_dca_time_15_8_pos 0 +#define reg_dca_time_15_8_len 8 +#define reg_dca_time_15_8_lsb 8 +#define xd_r_dcasm 0xA167 +#define dcasm_pos 0 +#define dcasm_len 3 +#define dcasm_lsb 0 +#define xd_p_reg_qnt_valuew_7_0 0xA168 +#define reg_qnt_valuew_7_0_pos 0 +#define reg_qnt_valuew_7_0_len 8 +#define reg_qnt_valuew_7_0_lsb 0 +#define xd_p_reg_qnt_valuew_10_8 0xA169 +#define reg_qnt_valuew_10_8_pos 0 +#define reg_qnt_valuew_10_8_len 3 +#define reg_qnt_valuew_10_8_lsb 8 +#define xd_p_dca_sbx_gain_diff_7_0 0xA16A +#define dca_sbx_gain_diff_7_0_pos 0 +#define dca_sbx_gain_diff_7_0_len 8 +#define dca_sbx_gain_diff_7_0_lsb 0 +#define xd_p_dca_sbx_gain_diff_9_8 0xA16B +#define dca_sbx_gain_diff_9_8_pos 0 +#define dca_sbx_gain_diff_9_8_len 2 +#define dca_sbx_gain_diff_9_8_lsb 8 +#define xd_p_reg_dca_stand_alone 0xA16C +#define reg_dca_stand_alone_pos 0 +#define reg_dca_stand_alone_len 1 +#define reg_dca_stand_alone_lsb 0 +#define xd_p_reg_dca_upper_out_en 0xA16C +#define reg_dca_upper_out_en_pos 1 +#define reg_dca_upper_out_en_len 1 +#define reg_dca_upper_out_en_lsb 0 +#define xd_p_reg_dca_rc_en 0xA16C +#define reg_dca_rc_en_pos 2 +#define reg_dca_rc_en_len 1 +#define reg_dca_rc_en_lsb 0 +#define xd_p_reg_dca_retrain_send 0xA16C +#define reg_dca_retrain_send_pos 3 +#define reg_dca_retrain_send_len 1 +#define reg_dca_retrain_send_lsb 0 +#define xd_p_reg_dca_retrain_rec 0xA16C +#define reg_dca_retrain_rec_pos 4 +#define reg_dca_retrain_rec_len 1 +#define reg_dca_retrain_rec_lsb 0 +#define xd_p_reg_dca_api_tpsrdy 0xA16C +#define reg_dca_api_tpsrdy_pos 5 +#define reg_dca_api_tpsrdy_len 1 +#define reg_dca_api_tpsrdy_lsb 0 +#define xd_p_reg_dca_symbol_gap 0xA16D +#define reg_dca_symbol_gap_pos 0 +#define reg_dca_symbol_gap_len 4 +#define reg_dca_symbol_gap_lsb 0 +#define xd_p_reg_qnt_nfvaluew_7_0 0xA16E +#define reg_qnt_nfvaluew_7_0_pos 0 +#define reg_qnt_nfvaluew_7_0_len 8 +#define reg_qnt_nfvaluew_7_0_lsb 0 +#define xd_p_reg_qnt_nfvaluew_10_8 0xA16F +#define reg_qnt_nfvaluew_10_8_pos 0 +#define reg_qnt_nfvaluew_10_8_len 3 +#define reg_qnt_nfvaluew_10_8_lsb 8 +#define xd_p_reg_qnt_flatness_thr_7_0 0xA170 +#define reg_qnt_flatness_thr_7_0_pos 0 +#define reg_qnt_flatness_thr_7_0_len 8 +#define reg_qnt_flatness_thr_7_0_lsb 0 +#define xd_p_reg_qnt_flatness_thr_9_8 0xA171 +#define reg_qnt_flatness_thr_9_8_pos 0 +#define reg_qnt_flatness_thr_9_8_len 2 +#define reg_qnt_flatness_thr_9_8_lsb 8 +#define xd_p_reg_dca_tone_idx_5_0 0xA171 +#define reg_dca_tone_idx_5_0_pos 2 +#define reg_dca_tone_idx_5_0_len 6 +#define reg_dca_tone_idx_5_0_lsb 0 +#define xd_p_reg_dca_tone_idx_12_6 0xA172 +#define reg_dca_tone_idx_12_6_pos 0 +#define reg_dca_tone_idx_12_6_len 7 +#define reg_dca_tone_idx_12_6_lsb 6 +#define xd_p_reg_dca_data_vld 0xA173 +#define reg_dca_data_vld_pos 0 +#define reg_dca_data_vld_len 1 +#define reg_dca_data_vld_lsb 0 +#define xd_p_reg_dca_read_update 0xA173 +#define reg_dca_read_update_pos 1 +#define reg_dca_read_update_len 1 +#define reg_dca_read_update_lsb 0 +#define xd_r_reg_dca_data_re_5_0 0xA173 +#define reg_dca_data_re_5_0_pos 2 +#define reg_dca_data_re_5_0_len 6 +#define reg_dca_data_re_5_0_lsb 0 +#define xd_r_reg_dca_data_re_10_6 0xA174 +#define reg_dca_data_re_10_6_pos 0 +#define reg_dca_data_re_10_6_len 5 +#define reg_dca_data_re_10_6_lsb 6 +#define xd_r_reg_dca_data_im_7_0 0xA175 +#define reg_dca_data_im_7_0_pos 0 +#define reg_dca_data_im_7_0_len 8 +#define reg_dca_data_im_7_0_lsb 0 +#define xd_r_reg_dca_data_im_10_8 0xA176 +#define reg_dca_data_im_10_8_pos 0 +#define reg_dca_data_im_10_8_len 3 +#define reg_dca_data_im_10_8_lsb 8 +#define xd_r_reg_dca_data_h2_7_0 0xA178 +#define reg_dca_data_h2_7_0_pos 0 +#define reg_dca_data_h2_7_0_len 8 +#define reg_dca_data_h2_7_0_lsb 0 +#define xd_r_reg_dca_data_h2_9_8 0xA179 +#define reg_dca_data_h2_9_8_pos 0 +#define reg_dca_data_h2_9_8_len 2 +#define reg_dca_data_h2_9_8_lsb 8 +#define xd_p_reg_f_adc_7_0 0xA180 +#define reg_f_adc_7_0_pos 0 +#define reg_f_adc_7_0_len 8 +#define reg_f_adc_7_0_lsb 0 +#define xd_p_reg_f_adc_15_8 0xA181 +#define reg_f_adc_15_8_pos 0 +#define reg_f_adc_15_8_len 8 +#define reg_f_adc_15_8_lsb 8 +#define xd_p_reg_f_adc_23_16 0xA182 +#define reg_f_adc_23_16_pos 0 +#define reg_f_adc_23_16_len 8 +#define reg_f_adc_23_16_lsb 16 +#define xd_r_intp_mu_7_0 0xA190 +#define intp_mu_7_0_pos 0 +#define intp_mu_7_0_len 8 +#define intp_mu_7_0_lsb 0 +#define xd_r_intp_mu_15_8 0xA191 +#define intp_mu_15_8_pos 0 +#define intp_mu_15_8_len 8 +#define intp_mu_15_8_lsb 8 +#define xd_r_intp_mu_19_16 0xA192 +#define intp_mu_19_16_pos 0 +#define intp_mu_19_16_len 4 +#define intp_mu_19_16_lsb 16 +#define xd_p_reg_agc_rst 0xA1A0 +#define reg_agc_rst_pos 0 +#define reg_agc_rst_len 1 +#define reg_agc_rst_lsb 0 +#define xd_p_rf_agc_en 0xA1A0 +#define rf_agc_en_pos 1 +#define rf_agc_en_len 1 +#define rf_agc_en_lsb 0 +#define xd_p_rf_agc_dis 0xA1A0 +#define rf_agc_dis_pos 2 +#define rf_agc_dis_len 1 +#define rf_agc_dis_lsb 0 +#define xd_p_if_agc_rst 0xA1A0 +#define if_agc_rst_pos 3 +#define if_agc_rst_len 1 +#define if_agc_rst_lsb 0 +#define xd_p_if_agc_en 0xA1A0 +#define if_agc_en_pos 4 +#define if_agc_en_len 1 +#define if_agc_en_lsb 0 +#define xd_p_if_agc_dis 0xA1A0 +#define if_agc_dis_pos 5 +#define if_agc_dis_len 1 +#define if_agc_dis_lsb 0 +#define xd_p_agc_lock 0xA1A0 +#define agc_lock_pos 6 +#define agc_lock_len 1 +#define agc_lock_lsb 0 +#define xd_p_reg_tinr_rst 0xA1A1 +#define reg_tinr_rst_pos 0 +#define reg_tinr_rst_len 1 +#define reg_tinr_rst_lsb 0 +#define xd_p_reg_tinr_en 0xA1A1 +#define reg_tinr_en_pos 1 +#define reg_tinr_en_len 1 +#define reg_tinr_en_lsb 0 +#define xd_p_reg_ccifs_en 0xA1A2 +#define reg_ccifs_en_pos 0 +#define reg_ccifs_en_len 1 +#define reg_ccifs_en_lsb 0 +#define xd_p_reg_ccifs_dis 0xA1A2 +#define reg_ccifs_dis_pos 1 +#define reg_ccifs_dis_len 1 +#define reg_ccifs_dis_lsb 0 +#define xd_p_reg_ccifs_rst 0xA1A2 +#define reg_ccifs_rst_pos 2 +#define reg_ccifs_rst_len 1 +#define reg_ccifs_rst_lsb 0 +#define xd_p_reg_ccifs_byp 0xA1A2 +#define reg_ccifs_byp_pos 3 +#define reg_ccifs_byp_len 1 +#define reg_ccifs_byp_lsb 0 +#define xd_p_reg_ccif_en 0xA1A3 +#define reg_ccif_en_pos 0 +#define reg_ccif_en_len 1 +#define reg_ccif_en_lsb 0 +#define xd_p_reg_ccif_dis 0xA1A3 +#define reg_ccif_dis_pos 1 +#define reg_ccif_dis_len 1 +#define reg_ccif_dis_lsb 0 +#define xd_p_reg_ccif_rst 0xA1A3 +#define reg_ccif_rst_pos 2 +#define reg_ccif_rst_len 1 +#define reg_ccif_rst_lsb 0 +#define xd_p_reg_ccif_byp 0xA1A3 +#define reg_ccif_byp_pos 3 +#define reg_ccif_byp_len 1 +#define reg_ccif_byp_lsb 0 +#define xd_p_dagc1_rst 0xA1A4 +#define dagc1_rst_pos 0 +#define dagc1_rst_len 1 +#define dagc1_rst_lsb 0 +#define xd_p_dagc1_en 0xA1A4 +#define dagc1_en_pos 1 +#define dagc1_en_len 1 +#define dagc1_en_lsb 0 +#define xd_p_dagc1_mode 0xA1A4 +#define dagc1_mode_pos 2 +#define dagc1_mode_len 2 +#define dagc1_mode_lsb 0 +#define xd_p_dagc1_done 0xA1A4 +#define dagc1_done_pos 4 +#define dagc1_done_len 1 +#define dagc1_done_lsb 0 +#define xd_p_ccid_rst 0xA1A5 +#define ccid_rst_pos 0 +#define ccid_rst_len 1 +#define ccid_rst_lsb 0 +#define xd_p_ccid_en 0xA1A5 +#define ccid_en_pos 1 +#define ccid_en_len 1 +#define ccid_en_lsb 0 +#define xd_p_ccid_mode 0xA1A5 +#define ccid_mode_pos 2 +#define ccid_mode_len 2 +#define ccid_mode_lsb 0 +#define xd_p_ccid_done 0xA1A5 +#define ccid_done_pos 4 +#define ccid_done_len 1 +#define ccid_done_lsb 0 +#define xd_r_ccid_deted 0xA1A5 +#define ccid_deted_pos 5 +#define ccid_deted_len 1 +#define ccid_deted_lsb 0 +#define xd_p_ccid2_en 0xA1A5 +#define ccid2_en_pos 6 +#define ccid2_en_len 1 +#define ccid2_en_lsb 0 +#define xd_p_ccid2_done 0xA1A5 +#define ccid2_done_pos 7 +#define ccid2_done_len 1 +#define ccid2_done_lsb 0 +#define xd_p_reg_bfs_en 0xA1A6 +#define reg_bfs_en_pos 0 +#define reg_bfs_en_len 1 +#define reg_bfs_en_lsb 0 +#define xd_p_reg_bfs_dis 0xA1A6 +#define reg_bfs_dis_pos 1 +#define reg_bfs_dis_len 1 +#define reg_bfs_dis_lsb 0 +#define xd_p_reg_bfs_rst 0xA1A6 +#define reg_bfs_rst_pos 2 +#define reg_bfs_rst_len 1 +#define reg_bfs_rst_lsb 0 +#define xd_p_reg_bfs_byp 0xA1A6 +#define reg_bfs_byp_pos 3 +#define reg_bfs_byp_len 1 +#define reg_bfs_byp_lsb 0 +#define xd_p_reg_antif_en 0xA1A7 +#define reg_antif_en_pos 0 +#define reg_antif_en_len 1 +#define reg_antif_en_lsb 0 +#define xd_p_reg_antif_dis 0xA1A7 +#define reg_antif_dis_pos 1 +#define reg_antif_dis_len 1 +#define reg_antif_dis_lsb 0 +#define xd_p_reg_antif_rst 0xA1A7 +#define reg_antif_rst_pos 2 +#define reg_antif_rst_len 1 +#define reg_antif_rst_lsb 0 +#define xd_p_reg_antif_byp 0xA1A7 +#define reg_antif_byp_pos 3 +#define reg_antif_byp_len 1 +#define reg_antif_byp_lsb 0 +#define xd_p_intp_en 0xA1A8 +#define intp_en_pos 0 +#define intp_en_len 1 +#define intp_en_lsb 0 +#define xd_p_intp_dis 0xA1A8 +#define intp_dis_pos 1 +#define intp_dis_len 1 +#define intp_dis_lsb 0 +#define xd_p_intp_rst 0xA1A8 +#define intp_rst_pos 2 +#define intp_rst_len 1 +#define intp_rst_lsb 0 +#define xd_p_intp_byp 0xA1A8 +#define intp_byp_pos 3 +#define intp_byp_len 1 +#define intp_byp_lsb 0 +#define xd_p_reg_acif_en 0xA1A9 +#define reg_acif_en_pos 0 +#define reg_acif_en_len 1 +#define reg_acif_en_lsb 0 +#define xd_p_reg_acif_dis 0xA1A9 +#define reg_acif_dis_pos 1 +#define reg_acif_dis_len 1 +#define reg_acif_dis_lsb 0 +#define xd_p_reg_acif_rst 0xA1A9 +#define reg_acif_rst_pos 2 +#define reg_acif_rst_len 1 +#define reg_acif_rst_lsb 0 +#define xd_p_reg_acif_byp 0xA1A9 +#define reg_acif_byp_pos 3 +#define reg_acif_byp_len 1 +#define reg_acif_byp_lsb 0 +#define xd_p_reg_acif_sync_mode 0xA1A9 +#define reg_acif_sync_mode_pos 4 +#define reg_acif_sync_mode_len 1 +#define reg_acif_sync_mode_lsb 0 +#define xd_p_dagc2_rst 0xA1AA +#define dagc2_rst_pos 0 +#define dagc2_rst_len 1 +#define dagc2_rst_lsb 0 +#define xd_p_dagc2_en 0xA1AA +#define dagc2_en_pos 1 +#define dagc2_en_len 1 +#define dagc2_en_lsb 0 +#define xd_p_dagc2_mode 0xA1AA +#define dagc2_mode_pos 2 +#define dagc2_mode_len 2 +#define dagc2_mode_lsb 0 +#define xd_p_dagc2_done 0xA1AA +#define dagc2_done_pos 4 +#define dagc2_done_len 1 +#define dagc2_done_lsb 0 +#define xd_p_reg_dca_en 0xA1AB +#define reg_dca_en_pos 0 +#define reg_dca_en_len 1 +#define reg_dca_en_lsb 0 +#define xd_p_dagc2_accumulate_num_2k_7_0 0xA1C0 +#define dagc2_accumulate_num_2k_7_0_pos 0 +#define dagc2_accumulate_num_2k_7_0_len 8 +#define dagc2_accumulate_num_2k_7_0_lsb 0 +#define xd_p_dagc2_accumulate_num_2k_12_8 0xA1C1 +#define dagc2_accumulate_num_2k_12_8_pos 0 +#define dagc2_accumulate_num_2k_12_8_len 5 +#define dagc2_accumulate_num_2k_12_8_lsb 8 +#define xd_p_dagc2_accumulate_num_8k_7_0 0xA1C2 +#define dagc2_accumulate_num_8k_7_0_pos 0 +#define dagc2_accumulate_num_8k_7_0_len 8 +#define dagc2_accumulate_num_8k_7_0_lsb 0 +#define xd_p_dagc2_accumulate_num_8k_12_8 0xA1C3 +#define dagc2_accumulate_num_8k_12_8_pos 0 +#define dagc2_accumulate_num_8k_12_8_len 5 +#define dagc2_accumulate_num_8k_12_8_lsb 8 +#define xd_p_dagc2_desired_level_2_0 0xA1C3 +#define dagc2_desired_level_2_0_pos 5 +#define dagc2_desired_level_2_0_len 3 +#define dagc2_desired_level_2_0_lsb 0 +#define xd_p_dagc2_desired_level_8_3 0xA1C4 +#define dagc2_desired_level_8_3_pos 0 +#define dagc2_desired_level_8_3_len 6 +#define dagc2_desired_level_8_3_lsb 3 +#define xd_p_dagc2_apply_delay 0xA1C5 +#define dagc2_apply_delay_pos 0 +#define dagc2_apply_delay_len 7 +#define dagc2_apply_delay_lsb 0 +#define xd_p_dagc2_bypass_scale_ctl 0xA1C6 +#define dagc2_bypass_scale_ctl_pos 0 +#define dagc2_bypass_scale_ctl_len 3 +#define dagc2_bypass_scale_ctl_lsb 0 +#define xd_p_dagc2_programmable_shift1 0xA1C7 +#define dagc2_programmable_shift1_pos 0 +#define dagc2_programmable_shift1_len 8 +#define dagc2_programmable_shift1_lsb 0 +#define xd_p_dagc2_programmable_shift2 0xA1C8 +#define dagc2_programmable_shift2_pos 0 +#define dagc2_programmable_shift2_len 8 +#define dagc2_programmable_shift2_lsb 0 +#define xd_p_reg_dagc2_in_sat_cnt_7_0 0xA1C9 +#define reg_dagc2_in_sat_cnt_7_0_pos 0 +#define reg_dagc2_in_sat_cnt_7_0_len 8 +#define reg_dagc2_in_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA +#define reg_dagc2_in_sat_cnt_15_8_pos 0 +#define reg_dagc2_in_sat_cnt_15_8_len 8 +#define reg_dagc2_in_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc2_in_sat_cnt_23_16 0xA1CB +#define reg_dagc2_in_sat_cnt_23_16_pos 0 +#define reg_dagc2_in_sat_cnt_23_16_len 8 +#define reg_dagc2_in_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc2_in_sat_cnt_31_24 0xA1CC +#define reg_dagc2_in_sat_cnt_31_24_pos 0 +#define reg_dagc2_in_sat_cnt_31_24_len 8 +#define reg_dagc2_in_sat_cnt_31_24_lsb 24 +#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD +#define reg_dagc2_out_sat_cnt_7_0_pos 0 +#define reg_dagc2_out_sat_cnt_7_0_len 8 +#define reg_dagc2_out_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc2_out_sat_cnt_15_8 0xA1CE +#define reg_dagc2_out_sat_cnt_15_8_pos 0 +#define reg_dagc2_out_sat_cnt_15_8_len 8 +#define reg_dagc2_out_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc2_out_sat_cnt_23_16 0xA1CF +#define reg_dagc2_out_sat_cnt_23_16_pos 0 +#define reg_dagc2_out_sat_cnt_23_16_len 8 +#define reg_dagc2_out_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc2_out_sat_cnt_31_24 0xA1D0 +#define reg_dagc2_out_sat_cnt_31_24_pos 0 +#define reg_dagc2_out_sat_cnt_31_24_len 8 +#define reg_dagc2_out_sat_cnt_31_24_lsb 24 +#define xd_r_dagc2_multiplier_7_0 0xA1D6 +#define dagc2_multiplier_7_0_pos 0 +#define dagc2_multiplier_7_0_len 8 +#define dagc2_multiplier_7_0_lsb 0 +#define xd_r_dagc2_multiplier_15_8 0xA1D7 +#define dagc2_multiplier_15_8_pos 0 +#define dagc2_multiplier_15_8_len 8 +#define dagc2_multiplier_15_8_lsb 8 +#define xd_r_dagc2_right_shift_bits 0xA1D8 +#define dagc2_right_shift_bits_pos 0 +#define dagc2_right_shift_bits_len 4 +#define dagc2_right_shift_bits_lsb 0 +#define xd_p_cfoe_NS_coeff1_7_0 0xA200 +#define cfoe_NS_coeff1_7_0_pos 0 +#define cfoe_NS_coeff1_7_0_len 8 +#define cfoe_NS_coeff1_7_0_lsb 0 +#define xd_p_cfoe_NS_coeff1_15_8 0xA201 +#define cfoe_NS_coeff1_15_8_pos 0 +#define cfoe_NS_coeff1_15_8_len 8 +#define cfoe_NS_coeff1_15_8_lsb 8 +#define xd_p_cfoe_NS_coeff1_23_16 0xA202 +#define cfoe_NS_coeff1_23_16_pos 0 +#define cfoe_NS_coeff1_23_16_len 8 +#define cfoe_NS_coeff1_23_16_lsb 16 +#define xd_p_cfoe_NS_coeff1_25_24 0xA203 +#define cfoe_NS_coeff1_25_24_pos 0 +#define cfoe_NS_coeff1_25_24_len 2 +#define cfoe_NS_coeff1_25_24_lsb 24 +#define xd_p_cfoe_NS_coeff2_5_0 0xA203 +#define cfoe_NS_coeff2_5_0_pos 2 +#define cfoe_NS_coeff2_5_0_len 6 +#define cfoe_NS_coeff2_5_0_lsb 0 +#define xd_p_cfoe_NS_coeff2_13_6 0xA204 +#define cfoe_NS_coeff2_13_6_pos 0 +#define cfoe_NS_coeff2_13_6_len 8 +#define cfoe_NS_coeff2_13_6_lsb 6 +#define xd_p_cfoe_NS_coeff2_21_14 0xA205 +#define cfoe_NS_coeff2_21_14_pos 0 +#define cfoe_NS_coeff2_21_14_len 8 +#define cfoe_NS_coeff2_21_14_lsb 14 +#define xd_p_cfoe_NS_coeff2_24_22 0xA206 +#define cfoe_NS_coeff2_24_22_pos 0 +#define cfoe_NS_coeff2_24_22_len 3 +#define cfoe_NS_coeff2_24_22_lsb 22 +#define xd_p_cfoe_lf_c1_4_0 0xA206 +#define cfoe_lf_c1_4_0_pos 3 +#define cfoe_lf_c1_4_0_len 5 +#define cfoe_lf_c1_4_0_lsb 0 +#define xd_p_cfoe_lf_c1_12_5 0xA207 +#define cfoe_lf_c1_12_5_pos 0 +#define cfoe_lf_c1_12_5_len 8 +#define cfoe_lf_c1_12_5_lsb 5 +#define xd_p_cfoe_lf_c1_20_13 0xA208 +#define cfoe_lf_c1_20_13_pos 0 +#define cfoe_lf_c1_20_13_len 8 +#define cfoe_lf_c1_20_13_lsb 13 +#define xd_p_cfoe_lf_c1_25_21 0xA209 +#define cfoe_lf_c1_25_21_pos 0 +#define cfoe_lf_c1_25_21_len 5 +#define cfoe_lf_c1_25_21_lsb 21 +#define xd_p_cfoe_lf_c2_2_0 0xA209 +#define cfoe_lf_c2_2_0_pos 5 +#define cfoe_lf_c2_2_0_len 3 +#define cfoe_lf_c2_2_0_lsb 0 +#define xd_p_cfoe_lf_c2_10_3 0xA20A +#define cfoe_lf_c2_10_3_pos 0 +#define cfoe_lf_c2_10_3_len 8 +#define cfoe_lf_c2_10_3_lsb 3 +#define xd_p_cfoe_lf_c2_18_11 0xA20B +#define cfoe_lf_c2_18_11_pos 0 +#define cfoe_lf_c2_18_11_len 8 +#define cfoe_lf_c2_18_11_lsb 11 +#define xd_p_cfoe_lf_c2_25_19 0xA20C +#define cfoe_lf_c2_25_19_pos 0 +#define cfoe_lf_c2_25_19_len 7 +#define cfoe_lf_c2_25_19_lsb 19 +#define xd_p_cfoe_ifod_7_0 0xA20D +#define cfoe_ifod_7_0_pos 0 +#define cfoe_ifod_7_0_len 8 +#define cfoe_ifod_7_0_lsb 0 +#define xd_p_cfoe_ifod_10_8 0xA20E +#define cfoe_ifod_10_8_pos 0 +#define cfoe_ifod_10_8_len 3 +#define cfoe_ifod_10_8_lsb 8 +#define xd_p_cfoe_Divg_ctr_th 0xA20E +#define cfoe_Divg_ctr_th_pos 4 +#define cfoe_Divg_ctr_th_len 4 +#define cfoe_Divg_ctr_th_lsb 0 +#define xd_p_cfoe_FOT_divg_th 0xA20F +#define cfoe_FOT_divg_th_pos 0 +#define cfoe_FOT_divg_th_len 8 +#define cfoe_FOT_divg_th_lsb 0 +#define xd_p_cfoe_FOT_cnvg_th 0xA210 +#define cfoe_FOT_cnvg_th_pos 0 +#define cfoe_FOT_cnvg_th_len 8 +#define cfoe_FOT_cnvg_th_lsb 0 +#define xd_p_reg_cfoe_offset_7_0 0xA211 +#define reg_cfoe_offset_7_0_pos 0 +#define reg_cfoe_offset_7_0_len 8 +#define reg_cfoe_offset_7_0_lsb 0 +#define xd_p_reg_cfoe_offset_9_8 0xA212 +#define reg_cfoe_offset_9_8_pos 0 +#define reg_cfoe_offset_9_8_len 2 +#define reg_cfoe_offset_9_8_lsb 8 +#define xd_p_reg_cfoe_ifoe_sign_corr 0xA212 +#define reg_cfoe_ifoe_sign_corr_pos 2 +#define reg_cfoe_ifoe_sign_corr_len 1 +#define reg_cfoe_ifoe_sign_corr_lsb 0 +#define xd_r_cfoe_fot_LF_output_7_0 0xA218 +#define cfoe_fot_LF_output_7_0_pos 0 +#define cfoe_fot_LF_output_7_0_len 8 +#define cfoe_fot_LF_output_7_0_lsb 0 +#define xd_r_cfoe_fot_LF_output_15_8 0xA219 +#define cfoe_fot_LF_output_15_8_pos 0 +#define cfoe_fot_LF_output_15_8_len 8 +#define cfoe_fot_LF_output_15_8_lsb 8 +#define xd_r_cfoe_ifo_metric_7_0 0xA21A +#define cfoe_ifo_metric_7_0_pos 0 +#define cfoe_ifo_metric_7_0_len 8 +#define cfoe_ifo_metric_7_0_lsb 0 +#define xd_r_cfoe_ifo_metric_15_8 0xA21B +#define cfoe_ifo_metric_15_8_pos 0 +#define cfoe_ifo_metric_15_8_len 8 +#define cfoe_ifo_metric_15_8_lsb 8 +#define xd_r_cfoe_ifo_metric_23_16 0xA21C +#define cfoe_ifo_metric_23_16_pos 0 +#define cfoe_ifo_metric_23_16_len 8 +#define cfoe_ifo_metric_23_16_lsb 16 +#define xd_p_ste_Nu 0xA220 +#define ste_Nu_pos 0 +#define ste_Nu_len 2 +#define ste_Nu_lsb 0 +#define xd_p_ste_GI 0xA220 +#define ste_GI_pos 2 +#define ste_GI_len 3 +#define ste_GI_lsb 0 +#define xd_p_ste_symbol_num 0xA221 +#define ste_symbol_num_pos 0 +#define ste_symbol_num_len 2 +#define ste_symbol_num_lsb 0 +#define xd_p_ste_sample_num 0xA221 +#define ste_sample_num_pos 2 +#define ste_sample_num_len 2 +#define ste_sample_num_lsb 0 +#define xd_p_reg_ste_buf_en 0xA221 +#define reg_ste_buf_en_pos 7 +#define reg_ste_buf_en_len 1 +#define reg_ste_buf_en_lsb 0 +#define xd_p_ste_FFT_offset_7_0 0xA222 +#define ste_FFT_offset_7_0_pos 0 +#define ste_FFT_offset_7_0_len 8 +#define ste_FFT_offset_7_0_lsb 0 +#define xd_p_ste_FFT_offset_11_8 0xA223 +#define ste_FFT_offset_11_8_pos 0 +#define ste_FFT_offset_11_8_len 4 +#define ste_FFT_offset_11_8_lsb 8 +#define xd_p_reg_ste_tstmod 0xA223 +#define reg_ste_tstmod_pos 5 +#define reg_ste_tstmod_len 1 +#define reg_ste_tstmod_lsb 0 +#define xd_p_ste_adv_start_7_0 0xA224 +#define ste_adv_start_7_0_pos 0 +#define ste_adv_start_7_0_len 8 +#define ste_adv_start_7_0_lsb 0 +#define xd_p_ste_adv_start_10_8 0xA225 +#define ste_adv_start_10_8_pos 0 +#define ste_adv_start_10_8_len 3 +#define ste_adv_start_10_8_lsb 8 +#define xd_p_ste_adv_stop 0xA226 +#define ste_adv_stop_pos 0 +#define ste_adv_stop_len 8 +#define ste_adv_stop_lsb 0 +#define xd_r_ste_P_value_7_0 0xA228 +#define ste_P_value_7_0_pos 0 +#define ste_P_value_7_0_len 8 +#define ste_P_value_7_0_lsb 0 +#define xd_r_ste_P_value_10_8 0xA229 +#define ste_P_value_10_8_pos 0 +#define ste_P_value_10_8_len 3 +#define ste_P_value_10_8_lsb 8 +#define xd_r_ste_M_value_7_0 0xA22A +#define ste_M_value_7_0_pos 0 +#define ste_M_value_7_0_len 8 +#define ste_M_value_7_0_lsb 0 +#define xd_r_ste_M_value_10_8 0xA22B +#define ste_M_value_10_8_pos 0 +#define ste_M_value_10_8_len 3 +#define ste_M_value_10_8_lsb 8 +#define xd_r_ste_H1 0xA22C +#define ste_H1_pos 0 +#define ste_H1_len 7 +#define ste_H1_lsb 0 +#define xd_r_ste_H2 0xA22D +#define ste_H2_pos 0 +#define ste_H2_len 7 +#define ste_H2_lsb 0 +#define xd_r_ste_H3 0xA22E +#define ste_H3_pos 0 +#define ste_H3_len 7 +#define ste_H3_lsb 0 +#define xd_r_ste_H4 0xA22F +#define ste_H4_pos 0 +#define ste_H4_len 7 +#define ste_H4_lsb 0 +#define xd_r_ste_Corr_value_I_7_0 0xA230 +#define ste_Corr_value_I_7_0_pos 0 +#define ste_Corr_value_I_7_0_len 8 +#define ste_Corr_value_I_7_0_lsb 0 +#define xd_r_ste_Corr_value_I_15_8 0xA231 +#define ste_Corr_value_I_15_8_pos 0 +#define ste_Corr_value_I_15_8_len 8 +#define ste_Corr_value_I_15_8_lsb 8 +#define xd_r_ste_Corr_value_I_23_16 0xA232 +#define ste_Corr_value_I_23_16_pos 0 +#define ste_Corr_value_I_23_16_len 8 +#define ste_Corr_value_I_23_16_lsb 16 +#define xd_r_ste_Corr_value_I_27_24 0xA233 +#define ste_Corr_value_I_27_24_pos 0 +#define ste_Corr_value_I_27_24_len 4 +#define ste_Corr_value_I_27_24_lsb 24 +#define xd_r_ste_Corr_value_Q_7_0 0xA234 +#define ste_Corr_value_Q_7_0_pos 0 +#define ste_Corr_value_Q_7_0_len 8 +#define ste_Corr_value_Q_7_0_lsb 0 +#define xd_r_ste_Corr_value_Q_15_8 0xA235 +#define ste_Corr_value_Q_15_8_pos 0 +#define ste_Corr_value_Q_15_8_len 8 +#define ste_Corr_value_Q_15_8_lsb 8 +#define xd_r_ste_Corr_value_Q_23_16 0xA236 +#define ste_Corr_value_Q_23_16_pos 0 +#define ste_Corr_value_Q_23_16_len 8 +#define ste_Corr_value_Q_23_16_lsb 16 +#define xd_r_ste_Corr_value_Q_27_24 0xA237 +#define ste_Corr_value_Q_27_24_pos 0 +#define ste_Corr_value_Q_27_24_len 4 +#define ste_Corr_value_Q_27_24_lsb 24 +#define xd_r_ste_J_num_7_0 0xA238 +#define ste_J_num_7_0_pos 0 +#define ste_J_num_7_0_len 8 +#define ste_J_num_7_0_lsb 0 +#define xd_r_ste_J_num_15_8 0xA239 +#define ste_J_num_15_8_pos 0 +#define ste_J_num_15_8_len 8 +#define ste_J_num_15_8_lsb 8 +#define xd_r_ste_J_num_23_16 0xA23A +#define ste_J_num_23_16_pos 0 +#define ste_J_num_23_16_len 8 +#define ste_J_num_23_16_lsb 16 +#define xd_r_ste_J_num_31_24 0xA23B +#define ste_J_num_31_24_pos 0 +#define ste_J_num_31_24_len 8 +#define ste_J_num_31_24_lsb 24 +#define xd_r_ste_J_den_7_0 0xA23C +#define ste_J_den_7_0_pos 0 +#define ste_J_den_7_0_len 8 +#define ste_J_den_7_0_lsb 0 +#define xd_r_ste_J_den_15_8 0xA23D +#define ste_J_den_15_8_pos 0 +#define ste_J_den_15_8_len 8 +#define ste_J_den_15_8_lsb 8 +#define xd_r_ste_J_den_18_16 0xA23E +#define ste_J_den_18_16_pos 0 +#define ste_J_den_18_16_len 3 +#define ste_J_den_18_16_lsb 16 +#define xd_r_ste_Beacon_Indicator 0xA23E +#define ste_Beacon_Indicator_pos 4 +#define ste_Beacon_Indicator_len 1 +#define ste_Beacon_Indicator_lsb 0 +#define xd_r_tpsd_Frame_Num 0xA250 +#define tpsd_Frame_Num_pos 0 +#define tpsd_Frame_Num_len 2 +#define tpsd_Frame_Num_lsb 0 +#define xd_r_tpsd_Constel 0xA250 +#define tpsd_Constel_pos 2 +#define tpsd_Constel_len 2 +#define tpsd_Constel_lsb 0 +#define xd_r_tpsd_GI 0xA250 +#define tpsd_GI_pos 4 +#define tpsd_GI_len 2 +#define tpsd_GI_lsb 0 +#define xd_r_tpsd_Mode 0xA250 +#define tpsd_Mode_pos 6 +#define tpsd_Mode_len 2 +#define tpsd_Mode_lsb 0 +#define xd_r_tpsd_CR_HP 0xA251 +#define tpsd_CR_HP_pos 0 +#define tpsd_CR_HP_len 3 +#define tpsd_CR_HP_lsb 0 +#define xd_r_tpsd_CR_LP 0xA251 +#define tpsd_CR_LP_pos 3 +#define tpsd_CR_LP_len 3 +#define tpsd_CR_LP_lsb 0 +#define xd_r_tpsd_Hie 0xA252 +#define tpsd_Hie_pos 0 +#define tpsd_Hie_len 3 +#define tpsd_Hie_lsb 0 +#define xd_r_tpsd_Res_Bits 0xA252 +#define tpsd_Res_Bits_pos 3 +#define tpsd_Res_Bits_len 5 +#define tpsd_Res_Bits_lsb 0 +#define xd_r_tpsd_Res_Bits_0 0xA253 +#define tpsd_Res_Bits_0_pos 0 +#define tpsd_Res_Bits_0_len 1 +#define tpsd_Res_Bits_0_lsb 0 +#define xd_r_tpsd_LengthInd 0xA253 +#define tpsd_LengthInd_pos 1 +#define tpsd_LengthInd_len 6 +#define tpsd_LengthInd_lsb 0 +#define xd_r_tpsd_Cell_Id_7_0 0xA254 +#define tpsd_Cell_Id_7_0_pos 0 +#define tpsd_Cell_Id_7_0_len 8 +#define tpsd_Cell_Id_7_0_lsb 0 +#define xd_r_tpsd_Cell_Id_15_8 0xA255 +#define tpsd_Cell_Id_15_8_pos 0 +#define tpsd_Cell_Id_15_8_len 8 +#define tpsd_Cell_Id_15_8_lsb 0 +#define xd_p_reg_fft_mask_tone0_7_0 0xA260 +#define reg_fft_mask_tone0_7_0_pos 0 +#define reg_fft_mask_tone0_7_0_len 8 +#define reg_fft_mask_tone0_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone0_12_8 0xA261 +#define reg_fft_mask_tone0_12_8_pos 0 +#define reg_fft_mask_tone0_12_8_len 5 +#define reg_fft_mask_tone0_12_8_lsb 8 +#define xd_p_reg_fft_mask_tone1_7_0 0xA262 +#define reg_fft_mask_tone1_7_0_pos 0 +#define reg_fft_mask_tone1_7_0_len 8 +#define reg_fft_mask_tone1_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone1_12_8 0xA263 +#define reg_fft_mask_tone1_12_8_pos 0 +#define reg_fft_mask_tone1_12_8_len 5 +#define reg_fft_mask_tone1_12_8_lsb 8 +#define xd_p_reg_fft_mask_tone2_7_0 0xA264 +#define reg_fft_mask_tone2_7_0_pos 0 +#define reg_fft_mask_tone2_7_0_len 8 +#define reg_fft_mask_tone2_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone2_12_8 0xA265 +#define reg_fft_mask_tone2_12_8_pos 0 +#define reg_fft_mask_tone2_12_8_len 5 +#define reg_fft_mask_tone2_12_8_lsb 8 +#define xd_p_reg_fft_mask_tone3_7_0 0xA266 +#define reg_fft_mask_tone3_7_0_pos 0 +#define reg_fft_mask_tone3_7_0_len 8 +#define reg_fft_mask_tone3_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone3_12_8 0xA267 +#define reg_fft_mask_tone3_12_8_pos 0 +#define reg_fft_mask_tone3_12_8_len 5 +#define reg_fft_mask_tone3_12_8_lsb 8 +#define xd_p_reg_fft_mask_from0_7_0 0xA268 +#define reg_fft_mask_from0_7_0_pos 0 +#define reg_fft_mask_from0_7_0_len 8 +#define reg_fft_mask_from0_7_0_lsb 0 +#define xd_p_reg_fft_mask_from0_12_8 0xA269 +#define reg_fft_mask_from0_12_8_pos 0 +#define reg_fft_mask_from0_12_8_len 5 +#define reg_fft_mask_from0_12_8_lsb 8 +#define xd_p_reg_fft_mask_to0_7_0 0xA26A +#define reg_fft_mask_to0_7_0_pos 0 +#define reg_fft_mask_to0_7_0_len 8 +#define reg_fft_mask_to0_7_0_lsb 0 +#define xd_p_reg_fft_mask_to0_12_8 0xA26B +#define reg_fft_mask_to0_12_8_pos 0 +#define reg_fft_mask_to0_12_8_len 5 +#define reg_fft_mask_to0_12_8_lsb 8 +#define xd_p_reg_fft_mask_from1_7_0 0xA26C +#define reg_fft_mask_from1_7_0_pos 0 +#define reg_fft_mask_from1_7_0_len 8 +#define reg_fft_mask_from1_7_0_lsb 0 +#define xd_p_reg_fft_mask_from1_12_8 0xA26D +#define reg_fft_mask_from1_12_8_pos 0 +#define reg_fft_mask_from1_12_8_len 5 +#define reg_fft_mask_from1_12_8_lsb 8 +#define xd_p_reg_fft_mask_to1_7_0 0xA26E +#define reg_fft_mask_to1_7_0_pos 0 +#define reg_fft_mask_to1_7_0_len 8 +#define reg_fft_mask_to1_7_0_lsb 0 +#define xd_p_reg_fft_mask_to1_12_8 0xA26F +#define reg_fft_mask_to1_12_8_pos 0 +#define reg_fft_mask_to1_12_8_len 5 +#define reg_fft_mask_to1_12_8_lsb 8 +#define xd_p_reg_cge_idx0_7_0 0xA280 +#define reg_cge_idx0_7_0_pos 0 +#define reg_cge_idx0_7_0_len 8 +#define reg_cge_idx0_7_0_lsb 0 +#define xd_p_reg_cge_idx0_12_8 0xA281 +#define reg_cge_idx0_12_8_pos 0 +#define reg_cge_idx0_12_8_len 5 +#define reg_cge_idx0_12_8_lsb 8 +#define xd_p_reg_cge_idx1_7_0 0xA282 +#define reg_cge_idx1_7_0_pos 0 +#define reg_cge_idx1_7_0_len 8 +#define reg_cge_idx1_7_0_lsb 0 +#define xd_p_reg_cge_idx1_12_8 0xA283 +#define reg_cge_idx1_12_8_pos 0 +#define reg_cge_idx1_12_8_len 5 +#define reg_cge_idx1_12_8_lsb 8 +#define xd_p_reg_cge_idx2_7_0 0xA284 +#define reg_cge_idx2_7_0_pos 0 +#define reg_cge_idx2_7_0_len 8 +#define reg_cge_idx2_7_0_lsb 0 +#define xd_p_reg_cge_idx2_12_8 0xA285 +#define reg_cge_idx2_12_8_pos 0 +#define reg_cge_idx2_12_8_len 5 +#define reg_cge_idx2_12_8_lsb 8 +#define xd_p_reg_cge_idx3_7_0 0xA286 +#define reg_cge_idx3_7_0_pos 0 +#define reg_cge_idx3_7_0_len 8 +#define reg_cge_idx3_7_0_lsb 0 +#define xd_p_reg_cge_idx3_12_8 0xA287 +#define reg_cge_idx3_12_8_pos 0 +#define reg_cge_idx3_12_8_len 5 +#define reg_cge_idx3_12_8_lsb 8 +#define xd_p_reg_cge_idx4_7_0 0xA288 +#define reg_cge_idx4_7_0_pos 0 +#define reg_cge_idx4_7_0_len 8 +#define reg_cge_idx4_7_0_lsb 0 +#define xd_p_reg_cge_idx4_12_8 0xA289 +#define reg_cge_idx4_12_8_pos 0 +#define reg_cge_idx4_12_8_len 5 +#define reg_cge_idx4_12_8_lsb 8 +#define xd_p_reg_cge_idx5_7_0 0xA28A +#define reg_cge_idx5_7_0_pos 0 +#define reg_cge_idx5_7_0_len 8 +#define reg_cge_idx5_7_0_lsb 0 +#define xd_p_reg_cge_idx5_12_8 0xA28B +#define reg_cge_idx5_12_8_pos 0 +#define reg_cge_idx5_12_8_len 5 +#define reg_cge_idx5_12_8_lsb 8 +#define xd_p_reg_cge_idx6_7_0 0xA28C +#define reg_cge_idx6_7_0_pos 0 +#define reg_cge_idx6_7_0_len 8 +#define reg_cge_idx6_7_0_lsb 0 +#define xd_p_reg_cge_idx6_12_8 0xA28D +#define reg_cge_idx6_12_8_pos 0 +#define reg_cge_idx6_12_8_len 5 +#define reg_cge_idx6_12_8_lsb 8 +#define xd_p_reg_cge_idx7_7_0 0xA28E +#define reg_cge_idx7_7_0_pos 0 +#define reg_cge_idx7_7_0_len 8 +#define reg_cge_idx7_7_0_lsb 0 +#define xd_p_reg_cge_idx7_12_8 0xA28F +#define reg_cge_idx7_12_8_pos 0 +#define reg_cge_idx7_12_8_len 5 +#define reg_cge_idx7_12_8_lsb 8 +#define xd_p_reg_cge_idx8_7_0 0xA290 +#define reg_cge_idx8_7_0_pos 0 +#define reg_cge_idx8_7_0_len 8 +#define reg_cge_idx8_7_0_lsb 0 +#define xd_p_reg_cge_idx8_12_8 0xA291 +#define reg_cge_idx8_12_8_pos 0 +#define reg_cge_idx8_12_8_len 5 +#define reg_cge_idx8_12_8_lsb 8 +#define xd_p_reg_cge_idx9_7_0 0xA292 +#define reg_cge_idx9_7_0_pos 0 +#define reg_cge_idx9_7_0_len 8 +#define reg_cge_idx9_7_0_lsb 0 +#define xd_p_reg_cge_idx9_12_8 0xA293 +#define reg_cge_idx9_12_8_pos 0 +#define reg_cge_idx9_12_8_len 5 +#define reg_cge_idx9_12_8_lsb 8 +#define xd_p_reg_cge_idx10_7_0 0xA294 +#define reg_cge_idx10_7_0_pos 0 +#define reg_cge_idx10_7_0_len 8 +#define reg_cge_idx10_7_0_lsb 0 +#define xd_p_reg_cge_idx10_12_8 0xA295 +#define reg_cge_idx10_12_8_pos 0 +#define reg_cge_idx10_12_8_len 5 +#define reg_cge_idx10_12_8_lsb 8 +#define xd_p_reg_cge_idx11_7_0 0xA296 +#define reg_cge_idx11_7_0_pos 0 +#define reg_cge_idx11_7_0_len 8 +#define reg_cge_idx11_7_0_lsb 0 +#define xd_p_reg_cge_idx11_12_8 0xA297 +#define reg_cge_idx11_12_8_pos 0 +#define reg_cge_idx11_12_8_len 5 +#define reg_cge_idx11_12_8_lsb 8 +#define xd_p_reg_cge_idx12_7_0 0xA298 +#define reg_cge_idx12_7_0_pos 0 +#define reg_cge_idx12_7_0_len 8 +#define reg_cge_idx12_7_0_lsb 0 +#define xd_p_reg_cge_idx12_12_8 0xA299 +#define reg_cge_idx12_12_8_pos 0 +#define reg_cge_idx12_12_8_len 5 +#define reg_cge_idx12_12_8_lsb 8 +#define xd_p_reg_cge_idx13_7_0 0xA29A +#define reg_cge_idx13_7_0_pos 0 +#define reg_cge_idx13_7_0_len 8 +#define reg_cge_idx13_7_0_lsb 0 +#define xd_p_reg_cge_idx13_12_8 0xA29B +#define reg_cge_idx13_12_8_pos 0 +#define reg_cge_idx13_12_8_len 5 +#define reg_cge_idx13_12_8_lsb 8 +#define xd_p_reg_cge_idx14_7_0 0xA29C +#define reg_cge_idx14_7_0_pos 0 +#define reg_cge_idx14_7_0_len 8 +#define reg_cge_idx14_7_0_lsb 0 +#define xd_p_reg_cge_idx14_12_8 0xA29D +#define reg_cge_idx14_12_8_pos 0 +#define reg_cge_idx14_12_8_len 5 +#define reg_cge_idx14_12_8_lsb 8 +#define xd_p_reg_cge_idx15_7_0 0xA29E +#define reg_cge_idx15_7_0_pos 0 +#define reg_cge_idx15_7_0_len 8 +#define reg_cge_idx15_7_0_lsb 0 +#define xd_p_reg_cge_idx15_12_8 0xA29F +#define reg_cge_idx15_12_8_pos 0 +#define reg_cge_idx15_12_8_len 5 +#define reg_cge_idx15_12_8_lsb 8 +#define xd_r_reg_fft_crc 0xA2A8 +#define reg_fft_crc_pos 0 +#define reg_fft_crc_len 8 +#define reg_fft_crc_lsb 0 +#define xd_p_fd_fft_shift_max 0xA2A9 +#define fd_fft_shift_max_pos 0 +#define fd_fft_shift_max_len 4 +#define fd_fft_shift_max_lsb 0 +#define xd_r_fd_fft_shift 0xA2A9 +#define fd_fft_shift_pos 4 +#define fd_fft_shift_len 4 +#define fd_fft_shift_lsb 0 +#define xd_r_fd_fft_frame_num 0xA2AA +#define fd_fft_frame_num_pos 0 +#define fd_fft_frame_num_len 2 +#define fd_fft_frame_num_lsb 0 +#define xd_r_fd_fft_symbol_count 0xA2AB +#define fd_fft_symbol_count_pos 0 +#define fd_fft_symbol_count_len 7 +#define fd_fft_symbol_count_lsb 0 +#define xd_r_reg_fft_idx_max_7_0 0xA2AC +#define reg_fft_idx_max_7_0_pos 0 +#define reg_fft_idx_max_7_0_len 8 +#define reg_fft_idx_max_7_0_lsb 0 +#define xd_r_reg_fft_idx_max_12_8 0xA2AD +#define reg_fft_idx_max_12_8_pos 0 +#define reg_fft_idx_max_12_8_len 5 +#define reg_fft_idx_max_12_8_lsb 8 +#define xd_p_reg_cge_program 0xA2AE +#define reg_cge_program_pos 0 +#define reg_cge_program_len 1 +#define reg_cge_program_lsb 0 +#define xd_p_reg_cge_fixed 0xA2AE +#define reg_cge_fixed_pos 1 +#define reg_cge_fixed_len 1 +#define reg_cge_fixed_lsb 0 +#define xd_p_reg_fft_rotate_en 0xA2AE +#define reg_fft_rotate_en_pos 2 +#define reg_fft_rotate_en_len 1 +#define reg_fft_rotate_en_lsb 0 +#define xd_p_reg_fft_rotate_base_4_0 0xA2AE +#define reg_fft_rotate_base_4_0_pos 3 +#define reg_fft_rotate_base_4_0_len 5 +#define reg_fft_rotate_base_4_0_lsb 0 +#define xd_p_reg_fft_rotate_base_12_5 0xA2AF +#define reg_fft_rotate_base_12_5_pos 0 +#define reg_fft_rotate_base_12_5_len 8 +#define reg_fft_rotate_base_12_5_lsb 5 +#define xd_p_reg_gp_trigger_fd 0xA2B8 +#define reg_gp_trigger_fd_pos 0 +#define reg_gp_trigger_fd_len 1 +#define reg_gp_trigger_fd_lsb 0 +#define xd_p_reg_trigger_sel_fd 0xA2B8 +#define reg_trigger_sel_fd_pos 1 +#define reg_trigger_sel_fd_len 2 +#define reg_trigger_sel_fd_lsb 0 +#define xd_p_reg_trigger_module_sel_fd 0xA2B9 +#define reg_trigger_module_sel_fd_pos 0 +#define reg_trigger_module_sel_fd_len 6 +#define reg_trigger_module_sel_fd_lsb 0 +#define xd_p_reg_trigger_set_sel_fd 0xA2BA +#define reg_trigger_set_sel_fd_pos 0 +#define reg_trigger_set_sel_fd_len 6 +#define reg_trigger_set_sel_fd_lsb 0 +#define xd_p_reg_fd_noname_7_0 0xA2BC +#define reg_fd_noname_7_0_pos 0 +#define reg_fd_noname_7_0_len 8 +#define reg_fd_noname_7_0_lsb 0 +#define xd_p_reg_fd_noname_15_8 0xA2BD +#define reg_fd_noname_15_8_pos 0 +#define reg_fd_noname_15_8_len 8 +#define reg_fd_noname_15_8_lsb 8 +#define xd_p_reg_fd_noname_23_16 0xA2BE +#define reg_fd_noname_23_16_pos 0 +#define reg_fd_noname_23_16_len 8 +#define reg_fd_noname_23_16_lsb 16 +#define xd_p_reg_fd_noname_31_24 0xA2BF +#define reg_fd_noname_31_24_pos 0 +#define reg_fd_noname_31_24_len 8 +#define reg_fd_noname_31_24_lsb 24 +#define xd_r_fd_fpcc_cp_corr_signn 0xA2C0 +#define fd_fpcc_cp_corr_signn_pos 0 +#define fd_fpcc_cp_corr_signn_len 8 +#define fd_fpcc_cp_corr_signn_lsb 0 +#define xd_p_reg_feq_s1 0xA2C1 +#define reg_feq_s1_pos 0 +#define reg_feq_s1_len 5 +#define reg_feq_s1_lsb 0 +#define xd_p_fd_fpcc_cp_corr_tone_th 0xA2C2 +#define fd_fpcc_cp_corr_tone_th_pos 0 +#define fd_fpcc_cp_corr_tone_th_len 6 +#define fd_fpcc_cp_corr_tone_th_lsb 0 +#define xd_p_fd_fpcc_cp_corr_symbol_log_th 0xA2C3 +#define fd_fpcc_cp_corr_symbol_log_th_pos 0 +#define fd_fpcc_cp_corr_symbol_log_th_len 4 +#define fd_fpcc_cp_corr_symbol_log_th_lsb 0 +#define xd_p_fd_fpcc_cp_corr_int 0xA2C4 +#define fd_fpcc_cp_corr_int_pos 0 +#define fd_fpcc_cp_corr_int_len 1 +#define fd_fpcc_cp_corr_int_lsb 0 +#define xd_p_reg_sfoe_ns_7_0 0xA320 +#define reg_sfoe_ns_7_0_pos 0 +#define reg_sfoe_ns_7_0_len 8 +#define reg_sfoe_ns_7_0_lsb 0 +#define xd_p_reg_sfoe_ns_14_8 0xA321 +#define reg_sfoe_ns_14_8_pos 0 +#define reg_sfoe_ns_14_8_len 7 +#define reg_sfoe_ns_14_8_lsb 8 +#define xd_p_reg_sfoe_c1_7_0 0xA322 +#define reg_sfoe_c1_7_0_pos 0 +#define reg_sfoe_c1_7_0_len 8 +#define reg_sfoe_c1_7_0_lsb 0 +#define xd_p_reg_sfoe_c1_15_8 0xA323 +#define reg_sfoe_c1_15_8_pos 0 +#define reg_sfoe_c1_15_8_len 8 +#define reg_sfoe_c1_15_8_lsb 8 +#define xd_p_reg_sfoe_c1_17_16 0xA324 +#define reg_sfoe_c1_17_16_pos 0 +#define reg_sfoe_c1_17_16_len 2 +#define reg_sfoe_c1_17_16_lsb 16 +#define xd_p_reg_sfoe_c2_7_0 0xA325 +#define reg_sfoe_c2_7_0_pos 0 +#define reg_sfoe_c2_7_0_len 8 +#define reg_sfoe_c2_7_0_lsb 0 +#define xd_p_reg_sfoe_c2_15_8 0xA326 +#define reg_sfoe_c2_15_8_pos 0 +#define reg_sfoe_c2_15_8_len 8 +#define reg_sfoe_c2_15_8_lsb 8 +#define xd_p_reg_sfoe_c2_17_16 0xA327 +#define reg_sfoe_c2_17_16_pos 0 +#define reg_sfoe_c2_17_16_len 2 +#define reg_sfoe_c2_17_16_lsb 16 +#define xd_r_reg_sfoe_out_9_2 0xA328 +#define reg_sfoe_out_9_2_pos 0 +#define reg_sfoe_out_9_2_len 8 +#define reg_sfoe_out_9_2_lsb 0 +#define xd_r_reg_sfoe_out_1_0 0xA329 +#define reg_sfoe_out_1_0_pos 0 +#define reg_sfoe_out_1_0_len 2 +#define reg_sfoe_out_1_0_lsb 0 +#define xd_p_reg_sfoe_lm_counter_th 0xA32A +#define reg_sfoe_lm_counter_th_pos 0 +#define reg_sfoe_lm_counter_th_len 4 +#define reg_sfoe_lm_counter_th_lsb 0 +#define xd_p_reg_sfoe_convg_th 0xA32B +#define reg_sfoe_convg_th_pos 0 +#define reg_sfoe_convg_th_len 8 +#define reg_sfoe_convg_th_lsb 0 +#define xd_p_reg_sfoe_divg_th 0xA32C +#define reg_sfoe_divg_th_pos 0 +#define reg_sfoe_divg_th_len 8 +#define reg_sfoe_divg_th_lsb 0 +#define xd_p_fd_tpsd_en 0xA330 +#define fd_tpsd_en_pos 0 +#define fd_tpsd_en_len 1 +#define fd_tpsd_en_lsb 0 +#define xd_p_fd_tpsd_dis 0xA330 +#define fd_tpsd_dis_pos 1 +#define fd_tpsd_dis_len 1 +#define fd_tpsd_dis_lsb 0 +#define xd_p_fd_tpsd_rst 0xA330 +#define fd_tpsd_rst_pos 2 +#define fd_tpsd_rst_len 1 +#define fd_tpsd_rst_lsb 0 +#define xd_p_fd_tpsd_lock 0xA330 +#define fd_tpsd_lock_pos 3 +#define fd_tpsd_lock_len 1 +#define fd_tpsd_lock_lsb 0 +#define xd_r_fd_tpsd_s19 0xA330 +#define fd_tpsd_s19_pos 4 +#define fd_tpsd_s19_len 1 +#define fd_tpsd_s19_lsb 0 +#define xd_r_fd_tpsd_s17 0xA330 +#define fd_tpsd_s17_pos 5 +#define fd_tpsd_s17_len 1 +#define fd_tpsd_s17_lsb 0 +#define xd_p_fd_sfr_ste_en 0xA331 +#define fd_sfr_ste_en_pos 0 +#define fd_sfr_ste_en_len 1 +#define fd_sfr_ste_en_lsb 0 +#define xd_p_fd_sfr_ste_dis 0xA331 +#define fd_sfr_ste_dis_pos 1 +#define fd_sfr_ste_dis_len 1 +#define fd_sfr_ste_dis_lsb 0 +#define xd_p_fd_sfr_ste_rst 0xA331 +#define fd_sfr_ste_rst_pos 2 +#define fd_sfr_ste_rst_len 1 +#define fd_sfr_ste_rst_lsb 0 +#define xd_p_fd_sfr_ste_mode 0xA331 +#define fd_sfr_ste_mode_pos 3 +#define fd_sfr_ste_mode_len 1 +#define fd_sfr_ste_mode_lsb 0 +#define xd_p_fd_sfr_ste_done 0xA331 +#define fd_sfr_ste_done_pos 4 +#define fd_sfr_ste_done_len 1 +#define fd_sfr_ste_done_lsb 0 +#define xd_p_reg_cfoe_ffoe_en 0xA332 +#define reg_cfoe_ffoe_en_pos 0 +#define reg_cfoe_ffoe_en_len 1 +#define reg_cfoe_ffoe_en_lsb 0 +#define xd_p_reg_cfoe_ffoe_dis 0xA332 +#define reg_cfoe_ffoe_dis_pos 1 +#define reg_cfoe_ffoe_dis_len 1 +#define reg_cfoe_ffoe_dis_lsb 0 +#define xd_p_reg_cfoe_ffoe_rst 0xA332 +#define reg_cfoe_ffoe_rst_pos 2 +#define reg_cfoe_ffoe_rst_len 1 +#define reg_cfoe_ffoe_rst_lsb 0 +#define xd_p_reg_cfoe_ifoe_en 0xA332 +#define reg_cfoe_ifoe_en_pos 3 +#define reg_cfoe_ifoe_en_len 1 +#define reg_cfoe_ifoe_en_lsb 0 +#define xd_p_reg_cfoe_ifoe_dis 0xA332 +#define reg_cfoe_ifoe_dis_pos 4 +#define reg_cfoe_ifoe_dis_len 1 +#define reg_cfoe_ifoe_dis_lsb 0 +#define xd_p_reg_cfoe_ifoe_rst 0xA332 +#define reg_cfoe_ifoe_rst_pos 5 +#define reg_cfoe_ifoe_rst_len 1 +#define reg_cfoe_ifoe_rst_lsb 0 +#define xd_p_reg_cfoe_fot_en 0xA332 +#define reg_cfoe_fot_en_pos 6 +#define reg_cfoe_fot_en_len 1 +#define reg_cfoe_fot_en_lsb 0 +#define xd_p_reg_cfoe_fot_lm_en 0xA332 +#define reg_cfoe_fot_lm_en_pos 7 +#define reg_cfoe_fot_lm_en_len 1 +#define reg_cfoe_fot_lm_en_lsb 0 +#define xd_p_reg_cfoe_fot_rst 0xA333 +#define reg_cfoe_fot_rst_pos 0 +#define reg_cfoe_fot_rst_len 1 +#define reg_cfoe_fot_rst_lsb 0 +#define xd_r_fd_cfoe_ffoe_done 0xA333 +#define fd_cfoe_ffoe_done_pos 1 +#define fd_cfoe_ffoe_done_len 1 +#define fd_cfoe_ffoe_done_lsb 0 +#define xd_p_fd_cfoe_metric_vld 0xA333 +#define fd_cfoe_metric_vld_pos 2 +#define fd_cfoe_metric_vld_len 1 +#define fd_cfoe_metric_vld_lsb 0 +#define xd_p_reg_cfoe_ifod_vld 0xA333 +#define reg_cfoe_ifod_vld_pos 3 +#define reg_cfoe_ifod_vld_len 1 +#define reg_cfoe_ifod_vld_lsb 0 +#define xd_r_fd_cfoe_ifoe_done 0xA333 +#define fd_cfoe_ifoe_done_pos 4 +#define fd_cfoe_ifoe_done_len 1 +#define fd_cfoe_ifoe_done_lsb 0 +#define xd_r_fd_cfoe_fot_valid 0xA333 +#define fd_cfoe_fot_valid_pos 5 +#define fd_cfoe_fot_valid_len 1 +#define fd_cfoe_fot_valid_lsb 0 +#define xd_p_reg_cfoe_divg_int 0xA333 +#define reg_cfoe_divg_int_pos 6 +#define reg_cfoe_divg_int_len 1 +#define reg_cfoe_divg_int_lsb 0 +#define xd_r_reg_cfoe_divg_flag 0xA333 +#define reg_cfoe_divg_flag_pos 7 +#define reg_cfoe_divg_flag_len 1 +#define reg_cfoe_divg_flag_lsb 0 +#define xd_p_reg_sfoe_en 0xA334 +#define reg_sfoe_en_pos 0 +#define reg_sfoe_en_len 1 +#define reg_sfoe_en_lsb 0 +#define xd_p_reg_sfoe_dis 0xA334 +#define reg_sfoe_dis_pos 1 +#define reg_sfoe_dis_len 1 +#define reg_sfoe_dis_lsb 0 +#define xd_p_reg_sfoe_rst 0xA334 +#define reg_sfoe_rst_pos 2 +#define reg_sfoe_rst_len 1 +#define reg_sfoe_rst_lsb 0 +#define xd_p_reg_sfoe_vld_int 0xA334 +#define reg_sfoe_vld_int_pos 3 +#define reg_sfoe_vld_int_len 1 +#define reg_sfoe_vld_int_lsb 0 +#define xd_p_reg_sfoe_lm_en 0xA334 +#define reg_sfoe_lm_en_pos 4 +#define reg_sfoe_lm_en_len 1 +#define reg_sfoe_lm_en_lsb 0 +#define xd_p_reg_sfoe_divg_int 0xA334 +#define reg_sfoe_divg_int_pos 5 +#define reg_sfoe_divg_int_len 1 +#define reg_sfoe_divg_int_lsb 0 +#define xd_r_reg_sfoe_divg_flag 0xA334 +#define reg_sfoe_divg_flag_pos 6 +#define reg_sfoe_divg_flag_len 1 +#define reg_sfoe_divg_flag_lsb 0 +#define xd_p_reg_fft_rst 0xA335 +#define reg_fft_rst_pos 0 +#define reg_fft_rst_len 1 +#define reg_fft_rst_lsb 0 +#define xd_p_reg_fft_fast_beacon 0xA335 +#define reg_fft_fast_beacon_pos 1 +#define reg_fft_fast_beacon_len 1 +#define reg_fft_fast_beacon_lsb 0 +#define xd_p_reg_fft_fast_valid 0xA335 +#define reg_fft_fast_valid_pos 2 +#define reg_fft_fast_valid_len 1 +#define reg_fft_fast_valid_lsb 0 +#define xd_p_reg_fft_mask_en 0xA335 +#define reg_fft_mask_en_pos 3 +#define reg_fft_mask_en_len 1 +#define reg_fft_mask_en_lsb 0 +#define xd_p_reg_fft_crc_en 0xA335 +#define reg_fft_crc_en_pos 4 +#define reg_fft_crc_en_len 1 +#define reg_fft_crc_en_lsb 0 +#define xd_p_reg_finr_en 0xA336 +#define reg_finr_en_pos 0 +#define reg_finr_en_len 1 +#define reg_finr_en_lsb 0 +#define xd_p_fd_fste_en 0xA337 +#define fd_fste_en_pos 1 +#define fd_fste_en_len 1 +#define fd_fste_en_lsb 0 +#define xd_p_fd_sqi_tps_level_shift 0xA338 +#define fd_sqi_tps_level_shift_pos 0 +#define fd_sqi_tps_level_shift_len 8 +#define fd_sqi_tps_level_shift_lsb 0 +#define xd_p_fd_pilot_ma_len 0xA339 +#define fd_pilot_ma_len_pos 0 +#define fd_pilot_ma_len_len 6 +#define fd_pilot_ma_len_lsb 0 +#define xd_p_fd_tps_ma_len 0xA33A +#define fd_tps_ma_len_pos 0 +#define fd_tps_ma_len_len 6 +#define fd_tps_ma_len_lsb 0 +#define xd_p_fd_sqi_s3 0xA33B +#define fd_sqi_s3_pos 0 +#define fd_sqi_s3_len 8 +#define fd_sqi_s3_lsb 0 +#define xd_p_fd_sqi_dummy_reg_0 0xA33C +#define fd_sqi_dummy_reg_0_pos 0 +#define fd_sqi_dummy_reg_0_len 1 +#define fd_sqi_dummy_reg_0_lsb 0 +#define xd_p_fd_sqi_debug_sel 0xA33C +#define fd_sqi_debug_sel_pos 1 +#define fd_sqi_debug_sel_len 2 +#define fd_sqi_debug_sel_lsb 0 +#define xd_p_fd_sqi_s2 0xA33C +#define fd_sqi_s2_pos 3 +#define fd_sqi_s2_len 5 +#define fd_sqi_s2_lsb 0 +#define xd_p_fd_sqi_dummy_reg_1 0xA33D +#define fd_sqi_dummy_reg_1_pos 0 +#define fd_sqi_dummy_reg_1_len 1 +#define fd_sqi_dummy_reg_1_lsb 0 +#define xd_p_fd_inr_ignore 0xA33D +#define fd_inr_ignore_pos 1 +#define fd_inr_ignore_len 1 +#define fd_inr_ignore_lsb 0 +#define xd_p_fd_pilot_ignore 0xA33D +#define fd_pilot_ignore_pos 2 +#define fd_pilot_ignore_len 1 +#define fd_pilot_ignore_lsb 0 +#define xd_p_fd_etps_ignore 0xA33D +#define fd_etps_ignore_pos 3 +#define fd_etps_ignore_len 1 +#define fd_etps_ignore_lsb 0 +#define xd_p_fd_sqi_s1 0xA33D +#define fd_sqi_s1_pos 4 +#define fd_sqi_s1_len 4 +#define fd_sqi_s1_lsb 0 +#define xd_p_reg_fste_ehw_7_0 0xA33E +#define reg_fste_ehw_7_0_pos 0 +#define reg_fste_ehw_7_0_len 8 +#define reg_fste_ehw_7_0_lsb 0 +#define xd_p_reg_fste_ehw_9_8 0xA33F +#define reg_fste_ehw_9_8_pos 0 +#define reg_fste_ehw_9_8_len 2 +#define reg_fste_ehw_9_8_lsb 8 +#define xd_p_reg_fste_i_adj_vld 0xA33F +#define reg_fste_i_adj_vld_pos 2 +#define reg_fste_i_adj_vld_len 1 +#define reg_fste_i_adj_vld_lsb 0 +#define xd_p_reg_fste_phase_ini_7_0 0xA340 +#define reg_fste_phase_ini_7_0_pos 0 +#define reg_fste_phase_ini_7_0_len 8 +#define reg_fste_phase_ini_7_0_lsb 0 +#define xd_p_reg_fste_phase_ini_11_8 0xA341 +#define reg_fste_phase_ini_11_8_pos 0 +#define reg_fste_phase_ini_11_8_len 4 +#define reg_fste_phase_ini_11_8_lsb 8 +#define xd_p_reg_fste_phase_inc_3_0 0xA341 +#define reg_fste_phase_inc_3_0_pos 4 +#define reg_fste_phase_inc_3_0_len 4 +#define reg_fste_phase_inc_3_0_lsb 0 +#define xd_p_reg_fste_phase_inc_11_4 0xA342 +#define reg_fste_phase_inc_11_4_pos 0 +#define reg_fste_phase_inc_11_4_len 8 +#define reg_fste_phase_inc_11_4_lsb 4 +#define xd_p_reg_fste_acum_cost_cnt_max 0xA343 +#define reg_fste_acum_cost_cnt_max_pos 0 +#define reg_fste_acum_cost_cnt_max_len 4 +#define reg_fste_acum_cost_cnt_max_lsb 0 +#define xd_p_reg_fste_step_size_std 0xA343 +#define reg_fste_step_size_std_pos 4 +#define reg_fste_step_size_std_len 4 +#define reg_fste_step_size_std_lsb 0 +#define xd_p_reg_fste_step_size_max 0xA344 +#define reg_fste_step_size_max_pos 0 +#define reg_fste_step_size_max_len 4 +#define reg_fste_step_size_max_lsb 0 +#define xd_p_reg_fste_step_size_min 0xA344 +#define reg_fste_step_size_min_pos 4 +#define reg_fste_step_size_min_len 4 +#define reg_fste_step_size_min_lsb 0 +#define xd_p_reg_fste_frac_step_size_7_0 0xA345 +#define reg_fste_frac_step_size_7_0_pos 0 +#define reg_fste_frac_step_size_7_0_len 8 +#define reg_fste_frac_step_size_7_0_lsb 0 +#define xd_p_reg_fste_frac_step_size_15_8 0xA346 +#define reg_fste_frac_step_size_15_8_pos 0 +#define reg_fste_frac_step_size_15_8_len 8 +#define reg_fste_frac_step_size_15_8_lsb 8 +#define xd_p_reg_fste_frac_step_size_19_16 0xA347 +#define reg_fste_frac_step_size_19_16_pos 0 +#define reg_fste_frac_step_size_19_16_len 4 +#define reg_fste_frac_step_size_19_16_lsb 16 +#define xd_p_reg_fste_rpd_dir_cnt_max 0xA347 +#define reg_fste_rpd_dir_cnt_max_pos 4 +#define reg_fste_rpd_dir_cnt_max_len 4 +#define reg_fste_rpd_dir_cnt_max_lsb 0 +#define xd_p_reg_fste_ehs 0xA348 +#define reg_fste_ehs_pos 0 +#define reg_fste_ehs_len 4 +#define reg_fste_ehs_lsb 0 +#define xd_p_reg_fste_frac_cost_cnt_max_3_0 0xA348 +#define reg_fste_frac_cost_cnt_max_3_0_pos 4 +#define reg_fste_frac_cost_cnt_max_3_0_len 4 +#define reg_fste_frac_cost_cnt_max_3_0_lsb 0 +#define xd_p_reg_fste_frac_cost_cnt_max_9_4 0xA349 +#define reg_fste_frac_cost_cnt_max_9_4_pos 0 +#define reg_fste_frac_cost_cnt_max_9_4_len 6 +#define reg_fste_frac_cost_cnt_max_9_4_lsb 4 +#define xd_p_reg_fste_w0_7_0 0xA34A +#define reg_fste_w0_7_0_pos 0 +#define reg_fste_w0_7_0_len 8 +#define reg_fste_w0_7_0_lsb 0 +#define xd_p_reg_fste_w0_11_8 0xA34B +#define reg_fste_w0_11_8_pos 0 +#define reg_fste_w0_11_8_len 4 +#define reg_fste_w0_11_8_lsb 8 +#define xd_p_reg_fste_w1_3_0 0xA34B +#define reg_fste_w1_3_0_pos 4 +#define reg_fste_w1_3_0_len 4 +#define reg_fste_w1_3_0_lsb 0 +#define xd_p_reg_fste_w1_11_4 0xA34C +#define reg_fste_w1_11_4_pos 0 +#define reg_fste_w1_11_4_len 8 +#define reg_fste_w1_11_4_lsb 4 +#define xd_p_reg_fste_w2_7_0 0xA34D +#define reg_fste_w2_7_0_pos 0 +#define reg_fste_w2_7_0_len 8 +#define reg_fste_w2_7_0_lsb 0 +#define xd_p_reg_fste_w2_11_8 0xA34E +#define reg_fste_w2_11_8_pos 0 +#define reg_fste_w2_11_8_len 4 +#define reg_fste_w2_11_8_lsb 8 +#define xd_p_reg_fste_w3_3_0 0xA34E +#define reg_fste_w3_3_0_pos 4 +#define reg_fste_w3_3_0_len 4 +#define reg_fste_w3_3_0_lsb 0 +#define xd_p_reg_fste_w3_11_4 0xA34F +#define reg_fste_w3_11_4_pos 0 +#define reg_fste_w3_11_4_len 8 +#define reg_fste_w3_11_4_lsb 4 +#define xd_p_reg_fste_w4_7_0 0xA350 +#define reg_fste_w4_7_0_pos 0 +#define reg_fste_w4_7_0_len 8 +#define reg_fste_w4_7_0_lsb 0 +#define xd_p_reg_fste_w4_11_8 0xA351 +#define reg_fste_w4_11_8_pos 0 +#define reg_fste_w4_11_8_len 4 +#define reg_fste_w4_11_8_lsb 8 +#define xd_p_reg_fste_w5_3_0 0xA351 +#define reg_fste_w5_3_0_pos 4 +#define reg_fste_w5_3_0_len 4 +#define reg_fste_w5_3_0_lsb 0 +#define xd_p_reg_fste_w5_11_4 0xA352 +#define reg_fste_w5_11_4_pos 0 +#define reg_fste_w5_11_4_len 8 +#define reg_fste_w5_11_4_lsb 4 +#define xd_p_reg_fste_w6_7_0 0xA353 +#define reg_fste_w6_7_0_pos 0 +#define reg_fste_w6_7_0_len 8 +#define reg_fste_w6_7_0_lsb 0 +#define xd_p_reg_fste_w6_11_8 0xA354 +#define reg_fste_w6_11_8_pos 0 +#define reg_fste_w6_11_8_len 4 +#define reg_fste_w6_11_8_lsb 8 +#define xd_p_reg_fste_w7_3_0 0xA354 +#define reg_fste_w7_3_0_pos 4 +#define reg_fste_w7_3_0_len 4 +#define reg_fste_w7_3_0_lsb 0 +#define xd_p_reg_fste_w7_11_4 0xA355 +#define reg_fste_w7_11_4_pos 0 +#define reg_fste_w7_11_4_len 8 +#define reg_fste_w7_11_4_lsb 4 +#define xd_p_reg_fste_w8_7_0 0xA356 +#define reg_fste_w8_7_0_pos 0 +#define reg_fste_w8_7_0_len 8 +#define reg_fste_w8_7_0_lsb 0 +#define xd_p_reg_fste_w8_11_8 0xA357 +#define reg_fste_w8_11_8_pos 0 +#define reg_fste_w8_11_8_len 4 +#define reg_fste_w8_11_8_lsb 8 +#define xd_p_reg_fste_w9_3_0 0xA357 +#define reg_fste_w9_3_0_pos 4 +#define reg_fste_w9_3_0_len 4 +#define reg_fste_w9_3_0_lsb 0 +#define xd_p_reg_fste_w9_11_4 0xA358 +#define reg_fste_w9_11_4_pos 0 +#define reg_fste_w9_11_4_len 8 +#define reg_fste_w9_11_4_lsb 4 +#define xd_p_reg_fste_wa_7_0 0xA359 +#define reg_fste_wa_7_0_pos 0 +#define reg_fste_wa_7_0_len 8 +#define reg_fste_wa_7_0_lsb 0 +#define xd_p_reg_fste_wa_11_8 0xA35A +#define reg_fste_wa_11_8_pos 0 +#define reg_fste_wa_11_8_len 4 +#define reg_fste_wa_11_8_lsb 8 +#define xd_p_reg_fste_wb_3_0 0xA35A +#define reg_fste_wb_3_0_pos 4 +#define reg_fste_wb_3_0_len 4 +#define reg_fste_wb_3_0_lsb 0 +#define xd_p_reg_fste_wb_11_4 0xA35B +#define reg_fste_wb_11_4_pos 0 +#define reg_fste_wb_11_4_len 8 +#define reg_fste_wb_11_4_lsb 4 +#define xd_r_fd_fste_i_adj 0xA35C +#define fd_fste_i_adj_pos 0 +#define fd_fste_i_adj_len 5 +#define fd_fste_i_adj_lsb 0 +#define xd_r_fd_fste_f_adj_7_0 0xA35D +#define fd_fste_f_adj_7_0_pos 0 +#define fd_fste_f_adj_7_0_len 8 +#define fd_fste_f_adj_7_0_lsb 0 +#define xd_r_fd_fste_f_adj_15_8 0xA35E +#define fd_fste_f_adj_15_8_pos 0 +#define fd_fste_f_adj_15_8_len 8 +#define fd_fste_f_adj_15_8_lsb 8 +#define xd_r_fd_fste_f_adj_19_16 0xA35F +#define fd_fste_f_adj_19_16_pos 0 +#define fd_fste_f_adj_19_16_len 4 +#define fd_fste_f_adj_19_16_lsb 16 +#define xd_p_reg_feq_Leak_Bypass 0xA366 +#define reg_feq_Leak_Bypass_pos 0 +#define reg_feq_Leak_Bypass_len 1 +#define reg_feq_Leak_Bypass_lsb 0 +#define xd_p_reg_feq_Leak_Mneg1 0xA366 +#define reg_feq_Leak_Mneg1_pos 1 +#define reg_feq_Leak_Mneg1_len 3 +#define reg_feq_Leak_Mneg1_lsb 0 +#define xd_p_reg_feq_Leak_B_ShiftQ 0xA366 +#define reg_feq_Leak_B_ShiftQ_pos 4 +#define reg_feq_Leak_B_ShiftQ_len 4 +#define reg_feq_Leak_B_ShiftQ_lsb 0 +#define xd_p_reg_feq_Leak_B_Float0 0xA367 +#define reg_feq_Leak_B_Float0_pos 0 +#define reg_feq_Leak_B_Float0_len 8 +#define reg_feq_Leak_B_Float0_lsb 0 +#define xd_p_reg_feq_Leak_B_Float1 0xA368 +#define reg_feq_Leak_B_Float1_pos 0 +#define reg_feq_Leak_B_Float1_len 8 +#define reg_feq_Leak_B_Float1_lsb 0 +#define xd_p_reg_feq_Leak_B_Float2 0xA369 +#define reg_feq_Leak_B_Float2_pos 0 +#define reg_feq_Leak_B_Float2_len 8 +#define reg_feq_Leak_B_Float2_lsb 0 +#define xd_p_reg_feq_Leak_B_Float3 0xA36A +#define reg_feq_Leak_B_Float3_pos 0 +#define reg_feq_Leak_B_Float3_len 8 +#define reg_feq_Leak_B_Float3_lsb 0 +#define xd_p_reg_feq_Leak_B_Float4 0xA36B +#define reg_feq_Leak_B_Float4_pos 0 +#define reg_feq_Leak_B_Float4_len 8 +#define reg_feq_Leak_B_Float4_lsb 0 +#define xd_p_reg_feq_Leak_B_Float5 0xA36C +#define reg_feq_Leak_B_Float5_pos 0 +#define reg_feq_Leak_B_Float5_len 8 +#define reg_feq_Leak_B_Float5_lsb 0 +#define xd_p_reg_feq_Leak_B_Float6 0xA36D +#define reg_feq_Leak_B_Float6_pos 0 +#define reg_feq_Leak_B_Float6_len 8 +#define reg_feq_Leak_B_Float6_lsb 0 +#define xd_p_reg_feq_Leak_B_Float7 0xA36E +#define reg_feq_Leak_B_Float7_pos 0 +#define reg_feq_Leak_B_Float7_len 8 +#define reg_feq_Leak_B_Float7_lsb 0 +#define xd_r_reg_feq_data_h2_7_0 0xA36F +#define reg_feq_data_h2_7_0_pos 0 +#define reg_feq_data_h2_7_0_len 8 +#define reg_feq_data_h2_7_0_lsb 0 +#define xd_r_reg_feq_data_h2_9_8 0xA370 +#define reg_feq_data_h2_9_8_pos 0 +#define reg_feq_data_h2_9_8_len 2 +#define reg_feq_data_h2_9_8_lsb 8 +#define xd_p_reg_feq_leak_use_slice_tps 0xA371 +#define reg_feq_leak_use_slice_tps_pos 0 +#define reg_feq_leak_use_slice_tps_len 1 +#define reg_feq_leak_use_slice_tps_lsb 0 +#define xd_p_reg_feq_read_update 0xA371 +#define reg_feq_read_update_pos 1 +#define reg_feq_read_update_len 1 +#define reg_feq_read_update_lsb 0 +#define xd_p_reg_feq_data_vld 0xA371 +#define reg_feq_data_vld_pos 2 +#define reg_feq_data_vld_len 1 +#define reg_feq_data_vld_lsb 0 +#define xd_p_reg_feq_tone_idx_4_0 0xA371 +#define reg_feq_tone_idx_4_0_pos 3 +#define reg_feq_tone_idx_4_0_len 5 +#define reg_feq_tone_idx_4_0_lsb 0 +#define xd_p_reg_feq_tone_idx_12_5 0xA372 +#define reg_feq_tone_idx_12_5_pos 0 +#define reg_feq_tone_idx_12_5_len 8 +#define reg_feq_tone_idx_12_5_lsb 5 +#define xd_r_reg_feq_data_re_7_0 0xA373 +#define reg_feq_data_re_7_0_pos 0 +#define reg_feq_data_re_7_0_len 8 +#define reg_feq_data_re_7_0_lsb 0 +#define xd_r_reg_feq_data_re_10_8 0xA374 +#define reg_feq_data_re_10_8_pos 0 +#define reg_feq_data_re_10_8_len 3 +#define reg_feq_data_re_10_8_lsb 8 +#define xd_r_reg_feq_data_im_7_0 0xA375 +#define reg_feq_data_im_7_0_pos 0 +#define reg_feq_data_im_7_0_len 8 +#define reg_feq_data_im_7_0_lsb 0 +#define xd_r_reg_feq_data_im_10_8 0xA376 +#define reg_feq_data_im_10_8_pos 0 +#define reg_feq_data_im_10_8_len 3 +#define reg_feq_data_im_10_8_lsb 8 +#define xd_r_reg_feq_y_re 0xA377 +#define reg_feq_y_re_pos 0 +#define reg_feq_y_re_len 8 +#define reg_feq_y_re_lsb 0 +#define xd_r_reg_feq_y_im 0xA378 +#define reg_feq_y_im_pos 0 +#define reg_feq_y_im_len 8 +#define reg_feq_y_im_lsb 0 +#define xd_r_reg_feq_h_re_7_0 0xA379 +#define reg_feq_h_re_7_0_pos 0 +#define reg_feq_h_re_7_0_len 8 +#define reg_feq_h_re_7_0_lsb 0 +#define xd_r_reg_feq_h_re_8 0xA37A +#define reg_feq_h_re_8_pos 0 +#define reg_feq_h_re_8_len 1 +#define reg_feq_h_re_8_lsb 0 +#define xd_r_reg_feq_h_im_7_0 0xA37B +#define reg_feq_h_im_7_0_pos 0 +#define reg_feq_h_im_7_0_len 8 +#define reg_feq_h_im_7_0_lsb 0 +#define xd_r_reg_feq_h_im_8 0xA37C +#define reg_feq_h_im_8_pos 0 +#define reg_feq_h_im_8_len 1 +#define reg_feq_h_im_8_lsb 0 +#define xd_p_fec_super_frm_unit_7_0 0xA380 +#define fec_super_frm_unit_7_0_pos 0 +#define fec_super_frm_unit_7_0_len 8 +#define fec_super_frm_unit_7_0_lsb 0 +#define xd_p_fec_super_frm_unit_15_8 0xA381 +#define fec_super_frm_unit_15_8_pos 0 +#define fec_super_frm_unit_15_8_len 8 +#define fec_super_frm_unit_15_8_lsb 8 +#define xd_r_fec_vtb_err_bit_cnt_7_0 0xA382 +#define fec_vtb_err_bit_cnt_7_0_pos 0 +#define fec_vtb_err_bit_cnt_7_0_len 8 +#define fec_vtb_err_bit_cnt_7_0_lsb 0 +#define xd_r_fec_vtb_err_bit_cnt_15_8 0xA383 +#define fec_vtb_err_bit_cnt_15_8_pos 0 +#define fec_vtb_err_bit_cnt_15_8_len 8 +#define fec_vtb_err_bit_cnt_15_8_lsb 8 +#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384 +#define fec_vtb_err_bit_cnt_23_16_pos 0 +#define fec_vtb_err_bit_cnt_23_16_len 8 +#define fec_vtb_err_bit_cnt_23_16_lsb 16 +#define xd_p_fec_rsd_packet_unit_7_0 0xA385 +#define fec_rsd_packet_unit_7_0_pos 0 +#define fec_rsd_packet_unit_7_0_len 8 +#define fec_rsd_packet_unit_7_0_lsb 0 +#define xd_p_fec_rsd_packet_unit_15_8 0xA386 +#define fec_rsd_packet_unit_15_8_pos 0 +#define fec_rsd_packet_unit_15_8_len 8 +#define fec_rsd_packet_unit_15_8_lsb 8 +#define xd_r_fec_rsd_bit_err_cnt_7_0 0xA387 +#define fec_rsd_bit_err_cnt_7_0_pos 0 +#define fec_rsd_bit_err_cnt_7_0_len 8 +#define fec_rsd_bit_err_cnt_7_0_lsb 0 +#define xd_r_fec_rsd_bit_err_cnt_15_8 0xA388 +#define fec_rsd_bit_err_cnt_15_8_pos 0 +#define fec_rsd_bit_err_cnt_15_8_len 8 +#define fec_rsd_bit_err_cnt_15_8_lsb 8 +#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389 +#define fec_rsd_bit_err_cnt_23_16_pos 0 +#define fec_rsd_bit_err_cnt_23_16_len 8 +#define fec_rsd_bit_err_cnt_23_16_lsb 16 +#define xd_r_fec_rsd_abort_packet_cnt_7_0 0xA38A +#define fec_rsd_abort_packet_cnt_7_0_pos 0 +#define fec_rsd_abort_packet_cnt_7_0_len 8 +#define fec_rsd_abort_packet_cnt_7_0_lsb 0 +#define xd_r_fec_rsd_abort_packet_cnt_15_8 0xA38B +#define fec_rsd_abort_packet_cnt_15_8_pos 0 +#define fec_rsd_abort_packet_cnt_15_8_len 8 +#define fec_rsd_abort_packet_cnt_15_8_lsb 8 +#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0 0xA38C +#define fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0 +#define fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8 +#define fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0 +#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8 0xA38D +#define fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0 +#define fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8 +#define fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8 +#define xd_p_fec_RS_TH_1_7_0 0xA38E +#define fec_RS_TH_1_7_0_pos 0 +#define fec_RS_TH_1_7_0_len 8 +#define fec_RS_TH_1_7_0_lsb 0 +#define xd_p_fec_RS_TH_1_15_8 0xA38F +#define fec_RS_TH_1_15_8_pos 0 +#define fec_RS_TH_1_15_8_len 8 +#define fec_RS_TH_1_15_8_lsb 8 +#define xd_p_fec_RS_TH_2 0xA390 +#define fec_RS_TH_2_pos 0 +#define fec_RS_TH_2_len 8 +#define fec_RS_TH_2_lsb 0 +#define xd_p_fec_mon_en 0xA391 +#define fec_mon_en_pos 0 +#define fec_mon_en_len 1 +#define fec_mon_en_lsb 0 +#define xd_p_reg_b8to47 0xA391 +#define reg_b8to47_pos 1 +#define reg_b8to47_len 1 +#define reg_b8to47_lsb 0 +#define xd_p_reg_rsd_sync_rep 0xA391 +#define reg_rsd_sync_rep_pos 2 +#define reg_rsd_sync_rep_len 1 +#define reg_rsd_sync_rep_lsb 0 +#define xd_p_fec_rsd_retrain_rst 0xA391 +#define fec_rsd_retrain_rst_pos 3 +#define fec_rsd_retrain_rst_len 1 +#define fec_rsd_retrain_rst_lsb 0 +#define xd_r_fec_rsd_ber_rdy 0xA391 +#define fec_rsd_ber_rdy_pos 4 +#define fec_rsd_ber_rdy_len 1 +#define fec_rsd_ber_rdy_lsb 0 +#define xd_p_fec_rsd_ber_rst 0xA391 +#define fec_rsd_ber_rst_pos 5 +#define fec_rsd_ber_rst_len 1 +#define fec_rsd_ber_rst_lsb 0 +#define xd_r_fec_vtb_ber_rdy 0xA391 +#define fec_vtb_ber_rdy_pos 6 +#define fec_vtb_ber_rdy_len 1 +#define fec_vtb_ber_rdy_lsb 0 +#define xd_p_fec_vtb_ber_rst 0xA391 +#define fec_vtb_ber_rst_pos 7 +#define fec_vtb_ber_rst_len 1 +#define fec_vtb_ber_rst_lsb 0 +#define xd_p_reg_vtb_clk40en 0xA392 +#define reg_vtb_clk40en_pos 0 +#define reg_vtb_clk40en_len 1 +#define reg_vtb_clk40en_lsb 0 +#define xd_p_fec_vtb_rsd_mon_en 0xA392 +#define fec_vtb_rsd_mon_en_pos 1 +#define fec_vtb_rsd_mon_en_len 1 +#define fec_vtb_rsd_mon_en_lsb 0 +#define xd_p_reg_fec_data_en 0xA392 +#define reg_fec_data_en_pos 2 +#define reg_fec_data_en_len 1 +#define reg_fec_data_en_lsb 0 +#define xd_p_fec_dummy_reg_2 0xA392 +#define fec_dummy_reg_2_pos 3 +#define fec_dummy_reg_2_len 3 +#define fec_dummy_reg_2_lsb 0 +#define xd_p_reg_sync_chk 0xA392 +#define reg_sync_chk_pos 6 +#define reg_sync_chk_len 1 +#define reg_sync_chk_lsb 0 +#define xd_p_fec_rsd_bypass 0xA392 +#define fec_rsd_bypass_pos 7 +#define fec_rsd_bypass_len 1 +#define fec_rsd_bypass_lsb 0 +#define xd_p_fec_sw_rst 0xA393 +#define fec_sw_rst_pos 0 +#define fec_sw_rst_len 1 +#define fec_sw_rst_lsb 0 +#define xd_r_fec_vtb_pm_crc 0xA394 +#define fec_vtb_pm_crc_pos 0 +#define fec_vtb_pm_crc_len 8 +#define fec_vtb_pm_crc_lsb 0 +#define xd_r_fec_vtb_tb_7_crc 0xA395 +#define fec_vtb_tb_7_crc_pos 0 +#define fec_vtb_tb_7_crc_len 8 +#define fec_vtb_tb_7_crc_lsb 0 +#define xd_r_fec_vtb_tb_6_crc 0xA396 +#define fec_vtb_tb_6_crc_pos 0 +#define fec_vtb_tb_6_crc_len 8 +#define fec_vtb_tb_6_crc_lsb 0 +#define xd_r_fec_vtb_tb_5_crc 0xA397 +#define fec_vtb_tb_5_crc_pos 0 +#define fec_vtb_tb_5_crc_len 8 +#define fec_vtb_tb_5_crc_lsb 0 +#define xd_r_fec_vtb_tb_4_crc 0xA398 +#define fec_vtb_tb_4_crc_pos 0 +#define fec_vtb_tb_4_crc_len 8 +#define fec_vtb_tb_4_crc_lsb 0 +#define xd_r_fec_vtb_tb_3_crc 0xA399 +#define fec_vtb_tb_3_crc_pos 0 +#define fec_vtb_tb_3_crc_len 8 +#define fec_vtb_tb_3_crc_lsb 0 +#define xd_r_fec_vtb_tb_2_crc 0xA39A +#define fec_vtb_tb_2_crc_pos 0 +#define fec_vtb_tb_2_crc_len 8 +#define fec_vtb_tb_2_crc_lsb 0 +#define xd_r_fec_vtb_tb_1_crc 0xA39B +#define fec_vtb_tb_1_crc_pos 0 +#define fec_vtb_tb_1_crc_len 8 +#define fec_vtb_tb_1_crc_lsb 0 +#define xd_r_fec_vtb_tb_0_crc 0xA39C +#define fec_vtb_tb_0_crc_pos 0 +#define fec_vtb_tb_0_crc_len 8 +#define fec_vtb_tb_0_crc_lsb 0 +#define xd_r_fec_rsd_bank0_crc 0xA39D +#define fec_rsd_bank0_crc_pos 0 +#define fec_rsd_bank0_crc_len 8 +#define fec_rsd_bank0_crc_lsb 0 +#define xd_r_fec_rsd_bank1_crc 0xA39E +#define fec_rsd_bank1_crc_pos 0 +#define fec_rsd_bank1_crc_len 8 +#define fec_rsd_bank1_crc_lsb 0 +#define xd_r_fec_idi_vtb_crc 0xA39F +#define fec_idi_vtb_crc_pos 0 +#define fec_idi_vtb_crc_len 8 +#define fec_idi_vtb_crc_lsb 0 +#define xd_g_reg_tpsd_txmod 0xA3C0 +#define reg_tpsd_txmod_pos 0 +#define reg_tpsd_txmod_len 2 +#define reg_tpsd_txmod_lsb 0 +#define xd_g_reg_tpsd_gi 0xA3C0 +#define reg_tpsd_gi_pos 2 +#define reg_tpsd_gi_len 2 +#define reg_tpsd_gi_lsb 0 +#define xd_g_reg_tpsd_hier 0xA3C0 +#define reg_tpsd_hier_pos 4 +#define reg_tpsd_hier_len 3 +#define reg_tpsd_hier_lsb 0 +#define xd_g_reg_bw 0xA3C1 +#define reg_bw_pos 2 +#define reg_bw_len 2 +#define reg_bw_lsb 0 +#define xd_g_reg_dec_pri 0xA3C1 +#define reg_dec_pri_pos 4 +#define reg_dec_pri_len 1 +#define reg_dec_pri_lsb 0 +#define xd_g_reg_tpsd_const 0xA3C1 +#define reg_tpsd_const_pos 6 +#define reg_tpsd_const_len 2 +#define reg_tpsd_const_lsb 0 +#define xd_g_reg_tpsd_hpcr 0xA3C2 +#define reg_tpsd_hpcr_pos 0 +#define reg_tpsd_hpcr_len 3 +#define reg_tpsd_hpcr_lsb 0 +#define xd_g_reg_tpsd_lpcr 0xA3C2 +#define reg_tpsd_lpcr_pos 3 +#define reg_tpsd_lpcr_len 3 +#define reg_tpsd_lpcr_lsb 0 +#define xd_g_reg_ofsm_clk 0xA3D0 +#define reg_ofsm_clk_pos 0 +#define reg_ofsm_clk_len 3 +#define reg_ofsm_clk_lsb 0 +#define xd_g_reg_fclk_cfg 0xA3D1 +#define reg_fclk_cfg_pos 0 +#define reg_fclk_cfg_len 1 +#define reg_fclk_cfg_lsb 0 +#define xd_g_reg_fclk_idi 0xA3D1 +#define reg_fclk_idi_pos 1 +#define reg_fclk_idi_len 1 +#define reg_fclk_idi_lsb 0 +#define xd_g_reg_fclk_odi 0xA3D1 +#define reg_fclk_odi_pos 2 +#define reg_fclk_odi_len 1 +#define reg_fclk_odi_lsb 0 +#define xd_g_reg_fclk_rsd 0xA3D1 +#define reg_fclk_rsd_pos 3 +#define reg_fclk_rsd_len 1 +#define reg_fclk_rsd_lsb 0 +#define xd_g_reg_fclk_vtb 0xA3D1 +#define reg_fclk_vtb_pos 4 +#define reg_fclk_vtb_len 1 +#define reg_fclk_vtb_lsb 0 +#define xd_g_reg_fclk_cste 0xA3D1 +#define reg_fclk_cste_pos 5 +#define reg_fclk_cste_len 1 +#define reg_fclk_cste_lsb 0 +#define xd_g_reg_fclk_mp2if 0xA3D1 +#define reg_fclk_mp2if_pos 6 +#define reg_fclk_mp2if_len 1 +#define reg_fclk_mp2if_lsb 0 +#define xd_I2C_i2c_m_slave_addr 0xA400 +#define i2c_m_slave_addr_pos 0 +#define i2c_m_slave_addr_len 8 +#define i2c_m_slave_addr_lsb 0 +#define xd_I2C_i2c_m_data1 0xA401 +#define i2c_m_data1_pos 0 +#define i2c_m_data1_len 8 +#define i2c_m_data1_lsb 0 +#define xd_I2C_i2c_m_data2 0xA402 +#define i2c_m_data2_pos 0 +#define i2c_m_data2_len 8 +#define i2c_m_data2_lsb 0 +#define xd_I2C_i2c_m_data3 0xA403 +#define i2c_m_data3_pos 0 +#define i2c_m_data3_len 8 +#define i2c_m_data3_lsb 0 +#define xd_I2C_i2c_m_data4 0xA404 +#define i2c_m_data4_pos 0 +#define i2c_m_data4_len 8 +#define i2c_m_data4_lsb 0 +#define xd_I2C_i2c_m_data5 0xA405 +#define i2c_m_data5_pos 0 +#define i2c_m_data5_len 8 +#define i2c_m_data5_lsb 0 +#define xd_I2C_i2c_m_data6 0xA406 +#define i2c_m_data6_pos 0 +#define i2c_m_data6_len 8 +#define i2c_m_data6_lsb 0 +#define xd_I2C_i2c_m_data7 0xA407 +#define i2c_m_data7_pos 0 +#define i2c_m_data7_len 8 +#define i2c_m_data7_lsb 0 +#define xd_I2C_i2c_m_data8 0xA408 +#define i2c_m_data8_pos 0 +#define i2c_m_data8_len 8 +#define i2c_m_data8_lsb 0 +#define xd_I2C_i2c_m_data9 0xA409 +#define i2c_m_data9_pos 0 +#define i2c_m_data9_len 8 +#define i2c_m_data9_lsb 0 +#define xd_I2C_i2c_m_data10 0xA40A +#define i2c_m_data10_pos 0 +#define i2c_m_data10_len 8 +#define i2c_m_data10_lsb 0 +#define xd_I2C_i2c_m_data11 0xA40B +#define i2c_m_data11_pos 0 +#define i2c_m_data11_len 8 +#define i2c_m_data11_lsb 0 +#define xd_I2C_i2c_m_cmd_rw 0xA40C +#define i2c_m_cmd_rw_pos 0 +#define i2c_m_cmd_rw_len 1 +#define i2c_m_cmd_rw_lsb 0 +#define xd_I2C_i2c_m_cmd_rwlen 0xA40C +#define i2c_m_cmd_rwlen_pos 3 +#define i2c_m_cmd_rwlen_len 4 +#define i2c_m_cmd_rwlen_lsb 0 +#define xd_I2C_i2c_m_status_cmd_exe 0xA40D +#define i2c_m_status_cmd_exe_pos 0 +#define i2c_m_status_cmd_exe_len 1 +#define i2c_m_status_cmd_exe_lsb 0 +#define xd_I2C_i2c_m_status_wdat_done 0xA40D +#define i2c_m_status_wdat_done_pos 1 +#define i2c_m_status_wdat_done_len 1 +#define i2c_m_status_wdat_done_lsb 0 +#define xd_I2C_i2c_m_status_wdat_fail 0xA40D +#define i2c_m_status_wdat_fail_pos 2 +#define i2c_m_status_wdat_fail_len 1 +#define i2c_m_status_wdat_fail_lsb 0 +#define xd_I2C_i2c_m_period 0xA40E +#define i2c_m_period_pos 0 +#define i2c_m_period_len 8 +#define i2c_m_period_lsb 0 +#define xd_I2C_i2c_m_reg_msb_lsb 0xA40F +#define i2c_m_reg_msb_lsb_pos 0 +#define i2c_m_reg_msb_lsb_len 1 +#define i2c_m_reg_msb_lsb_lsb 0 +#define xd_I2C_reg_ofdm_rst 0xA40F +#define reg_ofdm_rst_pos 1 +#define reg_ofdm_rst_len 1 +#define reg_ofdm_rst_lsb 0 +#define xd_I2C_reg_sample_period_on_tuner 0xA40F +#define reg_sample_period_on_tuner_pos 2 +#define reg_sample_period_on_tuner_len 1 +#define reg_sample_period_on_tuner_lsb 0 +#define xd_I2C_reg_rst_i2c 0xA40F +#define reg_rst_i2c_pos 3 +#define reg_rst_i2c_len 1 +#define reg_rst_i2c_lsb 0 +#define xd_I2C_reg_ofdm_rst_en 0xA40F +#define reg_ofdm_rst_en_pos 4 +#define reg_ofdm_rst_en_len 1 +#define reg_ofdm_rst_en_lsb 0 +#define xd_I2C_reg_tuner_sda_sync_on 0xA40F +#define reg_tuner_sda_sync_on_pos 5 +#define reg_tuner_sda_sync_on_len 1 +#define reg_tuner_sda_sync_on_lsb 0 +#define xd_p_mp2if_data_access_disable_ofsm 0xA500 +#define mp2if_data_access_disable_ofsm_pos 0 +#define mp2if_data_access_disable_ofsm_len 1 +#define mp2if_data_access_disable_ofsm_lsb 0 +#define xd_p_reg_mp2_sw_rst_ofsm 0xA500 +#define reg_mp2_sw_rst_ofsm_pos 1 +#define reg_mp2_sw_rst_ofsm_len 1 +#define reg_mp2_sw_rst_ofsm_lsb 0 +#define xd_p_reg_mp2if_clk_en_ofsm 0xA500 +#define reg_mp2if_clk_en_ofsm_pos 2 +#define reg_mp2if_clk_en_ofsm_len 1 +#define reg_mp2if_clk_en_ofsm_lsb 0 +#define xd_r_mp2if_sync_byte_locked 0xA500 +#define mp2if_sync_byte_locked_pos 3 +#define mp2if_sync_byte_locked_len 1 +#define mp2if_sync_byte_locked_lsb 0 +#define xd_r_mp2if_ts_not_188 0xA500 +#define mp2if_ts_not_188_pos 4 +#define mp2if_ts_not_188_len 1 +#define mp2if_ts_not_188_lsb 0 +#define xd_r_mp2if_psb_empty 0xA500 +#define mp2if_psb_empty_pos 5 +#define mp2if_psb_empty_len 1 +#define mp2if_psb_empty_lsb 0 +#define xd_r_mp2if_psb_overflow 0xA500 +#define mp2if_psb_overflow_pos 6 +#define mp2if_psb_overflow_len 1 +#define mp2if_psb_overflow_lsb 0 +#define xd_p_mp2if_keep_sf_sync_byte_ofsm 0xA500 +#define mp2if_keep_sf_sync_byte_ofsm_pos 7 +#define mp2if_keep_sf_sync_byte_ofsm_len 1 +#define mp2if_keep_sf_sync_byte_ofsm_lsb 0 +#define xd_r_mp2if_psb_mp2if_num_pkt 0xA501 +#define mp2if_psb_mp2if_num_pkt_pos 0 +#define mp2if_psb_mp2if_num_pkt_len 6 +#define mp2if_psb_mp2if_num_pkt_lsb 0 +#define xd_p_reg_mpeg_full_speed_ofsm 0xA501 +#define reg_mpeg_full_speed_ofsm_pos 6 +#define reg_mpeg_full_speed_ofsm_len 1 +#define reg_mpeg_full_speed_ofsm_lsb 0 +#define xd_p_mp2if_mpeg_ser_mode_ofsm 0xA501 +#define mp2if_mpeg_ser_mode_ofsm_pos 7 +#define mp2if_mpeg_ser_mode_ofsm_len 1 +#define mp2if_mpeg_ser_mode_ofsm_lsb 0 +#define xd_p_reg_sw_mon51 0xA600 +#define reg_sw_mon51_pos 0 +#define reg_sw_mon51_len 8 +#define reg_sw_mon51_lsb 0 +#define xd_p_reg_top_pcsel 0xA601 +#define reg_top_pcsel_pos 0 +#define reg_top_pcsel_len 1 +#define reg_top_pcsel_lsb 0 +#define xd_p_reg_top_rs232 0xA601 +#define reg_top_rs232_pos 1 +#define reg_top_rs232_len 1 +#define reg_top_rs232_lsb 0 +#define xd_p_reg_top_pcout 0xA601 +#define reg_top_pcout_pos 2 +#define reg_top_pcout_len 1 +#define reg_top_pcout_lsb 0 +#define xd_p_reg_top_debug 0xA601 +#define reg_top_debug_pos 3 +#define reg_top_debug_len 1 +#define reg_top_debug_lsb 0 +#define xd_p_reg_top_adcdly 0xA601 +#define reg_top_adcdly_pos 4 +#define reg_top_adcdly_len 2 +#define reg_top_adcdly_lsb 0 +#define xd_p_reg_top_pwrdw 0xA601 +#define reg_top_pwrdw_pos 6 +#define reg_top_pwrdw_len 1 +#define reg_top_pwrdw_lsb 0 +#define xd_p_reg_top_pwrdw_inv 0xA601 +#define reg_top_pwrdw_inv_pos 7 +#define reg_top_pwrdw_inv_len 1 +#define reg_top_pwrdw_inv_lsb 0 +#define xd_p_reg_top_int_inv 0xA602 +#define reg_top_int_inv_pos 0 +#define reg_top_int_inv_len 1 +#define reg_top_int_inv_lsb 0 +#define xd_p_reg_top_dio_sel 0xA602 +#define reg_top_dio_sel_pos 1 +#define reg_top_dio_sel_len 1 +#define reg_top_dio_sel_lsb 0 +#define xd_p_reg_top_gpioon0 0xA603 +#define reg_top_gpioon0_pos 0 +#define reg_top_gpioon0_len 1 +#define reg_top_gpioon0_lsb 0 +#define xd_p_reg_top_gpioon1 0xA603 +#define reg_top_gpioon1_pos 1 +#define reg_top_gpioon1_len 1 +#define reg_top_gpioon1_lsb 0 +#define xd_p_reg_top_gpioon2 0xA603 +#define reg_top_gpioon2_pos 2 +#define reg_top_gpioon2_len 1 +#define reg_top_gpioon2_lsb 0 +#define xd_p_reg_top_gpioon3 0xA603 +#define reg_top_gpioon3_pos 3 +#define reg_top_gpioon3_len 1 +#define reg_top_gpioon3_lsb 0 +#define xd_p_reg_top_lockon1 0xA603 +#define reg_top_lockon1_pos 4 +#define reg_top_lockon1_len 1 +#define reg_top_lockon1_lsb 0 +#define xd_p_reg_top_lockon2 0xA603 +#define reg_top_lockon2_pos 5 +#define reg_top_lockon2_len 1 +#define reg_top_lockon2_lsb 0 +#define xd_p_reg_top_gpioo0 0xA604 +#define reg_top_gpioo0_pos 0 +#define reg_top_gpioo0_len 1 +#define reg_top_gpioo0_lsb 0 +#define xd_p_reg_top_gpioo1 0xA604 +#define reg_top_gpioo1_pos 1 +#define reg_top_gpioo1_len 1 +#define reg_top_gpioo1_lsb 0 +#define xd_p_reg_top_gpioo2 0xA604 +#define reg_top_gpioo2_pos 2 +#define reg_top_gpioo2_len 1 +#define reg_top_gpioo2_lsb 0 +#define xd_p_reg_top_gpioo3 0xA604 +#define reg_top_gpioo3_pos 3 +#define reg_top_gpioo3_len 1 +#define reg_top_gpioo3_lsb 0 +#define xd_p_reg_top_lock1 0xA604 +#define reg_top_lock1_pos 4 +#define reg_top_lock1_len 1 +#define reg_top_lock1_lsb 0 +#define xd_p_reg_top_lock2 0xA604 +#define reg_top_lock2_pos 5 +#define reg_top_lock2_len 1 +#define reg_top_lock2_lsb 0 +#define xd_p_reg_top_gpioen0 0xA605 +#define reg_top_gpioen0_pos 0 +#define reg_top_gpioen0_len 1 +#define reg_top_gpioen0_lsb 0 +#define xd_p_reg_top_gpioen1 0xA605 +#define reg_top_gpioen1_pos 1 +#define reg_top_gpioen1_len 1 +#define reg_top_gpioen1_lsb 0 +#define xd_p_reg_top_gpioen2 0xA605 +#define reg_top_gpioen2_pos 2 +#define reg_top_gpioen2_len 1 +#define reg_top_gpioen2_lsb 0 +#define xd_p_reg_top_gpioen3 0xA605 +#define reg_top_gpioen3_pos 3 +#define reg_top_gpioen3_len 1 +#define reg_top_gpioen3_lsb 0 +#define xd_p_reg_top_locken1 0xA605 +#define reg_top_locken1_pos 4 +#define reg_top_locken1_len 1 +#define reg_top_locken1_lsb 0 +#define xd_p_reg_top_locken2 0xA605 +#define reg_top_locken2_pos 5 +#define reg_top_locken2_len 1 +#define reg_top_locken2_lsb 0 +#define xd_r_reg_top_gpioi0 0xA606 +#define reg_top_gpioi0_pos 0 +#define reg_top_gpioi0_len 1 +#define reg_top_gpioi0_lsb 0 +#define xd_r_reg_top_gpioi1 0xA606 +#define reg_top_gpioi1_pos 1 +#define reg_top_gpioi1_len 1 +#define reg_top_gpioi1_lsb 0 +#define xd_r_reg_top_gpioi2 0xA606 +#define reg_top_gpioi2_pos 2 +#define reg_top_gpioi2_len 1 +#define reg_top_gpioi2_lsb 0 +#define xd_r_reg_top_gpioi3 0xA606 +#define reg_top_gpioi3_pos 3 +#define reg_top_gpioi3_len 1 +#define reg_top_gpioi3_lsb 0 +#define xd_r_reg_top_locki1 0xA606 +#define reg_top_locki1_pos 4 +#define reg_top_locki1_len 1 +#define reg_top_locki1_lsb 0 +#define xd_r_reg_top_locki2 0xA606 +#define reg_top_locki2_pos 5 +#define reg_top_locki2_len 1 +#define reg_top_locki2_lsb 0 +#define xd_p_reg_dummy_7_0 0xA608 +#define reg_dummy_7_0_pos 0 +#define reg_dummy_7_0_len 8 +#define reg_dummy_7_0_lsb 0 +#define xd_p_reg_dummy_15_8 0xA609 +#define reg_dummy_15_8_pos 0 +#define reg_dummy_15_8_len 8 +#define reg_dummy_15_8_lsb 8 +#define xd_p_reg_dummy_23_16 0xA60A +#define reg_dummy_23_16_pos 0 +#define reg_dummy_23_16_len 8 +#define reg_dummy_23_16_lsb 16 +#define xd_p_reg_dummy_31_24 0xA60B +#define reg_dummy_31_24_pos 0 +#define reg_dummy_31_24_len 8 +#define reg_dummy_31_24_lsb 24 +#define xd_p_reg_dummy_39_32 0xA60C +#define reg_dummy_39_32_pos 0 +#define reg_dummy_39_32_len 8 +#define reg_dummy_39_32_lsb 32 +#define xd_p_reg_dummy_47_40 0xA60D +#define reg_dummy_47_40_pos 0 +#define reg_dummy_47_40_len 8 +#define reg_dummy_47_40_lsb 40 +#define xd_p_reg_dummy_55_48 0xA60E +#define reg_dummy_55_48_pos 0 +#define reg_dummy_55_48_len 8 +#define reg_dummy_55_48_lsb 48 +#define xd_p_reg_dummy_63_56 0xA60F +#define reg_dummy_63_56_pos 0 +#define reg_dummy_63_56_len 8 +#define reg_dummy_63_56_lsb 56 +#define xd_p_reg_dummy_71_64 0xA610 +#define reg_dummy_71_64_pos 0 +#define reg_dummy_71_64_len 8 +#define reg_dummy_71_64_lsb 64 +#define xd_p_reg_dummy_79_72 0xA611 +#define reg_dummy_79_72_pos 0 +#define reg_dummy_79_72_len 8 +#define reg_dummy_79_72_lsb 72 +#define xd_p_reg_dummy_87_80 0xA612 +#define reg_dummy_87_80_pos 0 +#define reg_dummy_87_80_len 8 +#define reg_dummy_87_80_lsb 80 +#define xd_p_reg_dummy_95_88 0xA613 +#define reg_dummy_95_88_pos 0 +#define reg_dummy_95_88_len 8 +#define reg_dummy_95_88_lsb 88 +#define xd_p_reg_dummy_103_96 0xA614 +#define reg_dummy_103_96_pos 0 +#define reg_dummy_103_96_len 8 +#define reg_dummy_103_96_lsb 96 + +#define xd_p_reg_unplug_flag 0xA615 +#define reg_unplug_flag_pos 0 +#define reg_unplug_flag_len 1 +#define reg_unplug_flag_lsb 104 + +#define xd_p_reg_api_dca_stes_request 0xA615 +#define reg_api_dca_stes_request_pos 1 +#define reg_api_dca_stes_request_len 1 +#define reg_api_dca_stes_request_lsb 0 + +#define xd_p_reg_back_to_dca_flag 0xA615 +#define reg_back_to_dca_flag_pos 2 +#define reg_back_to_dca_flag_len 1 +#define reg_back_to_dca_flag_lsb 106 + +#define xd_p_reg_api_retrain_request 0xA615 +#define reg_api_retrain_request_pos 3 +#define reg_api_retrain_request_len 1 +#define reg_api_retrain_request_lsb 0 + +#define xd_p_reg_Dyn_Top_Try_flag 0xA615 +#define reg_Dyn_Top_Try_flag_pos 3 +#define reg_Dyn_Top_Try_flag_len 1 +#define reg_Dyn_Top_Try_flag_lsb 107 + +#define xd_p_reg_API_retrain_freeze_flag 0xA615 +#define reg_API_retrain_freeze_flag_pos 4 +#define reg_API_retrain_freeze_flag_len 1 +#define reg_API_retrain_freeze_flag_lsb 108 + +#define xd_p_reg_dummy_111_104 0xA615 +#define reg_dummy_111_104_pos 0 +#define reg_dummy_111_104_len 8 +#define reg_dummy_111_104_lsb 104 +#define xd_p_reg_dummy_119_112 0xA616 +#define reg_dummy_119_112_pos 0 +#define reg_dummy_119_112_len 8 +#define reg_dummy_119_112_lsb 112 +#define xd_p_reg_dummy_127_120 0xA617 +#define reg_dummy_127_120_pos 0 +#define reg_dummy_127_120_len 8 +#define reg_dummy_127_120_lsb 120 +#define xd_p_reg_dummy_135_128 0xA618 +#define reg_dummy_135_128_pos 0 +#define reg_dummy_135_128_len 8 +#define reg_dummy_135_128_lsb 128 + +#define xd_p_reg_dummy_143_136 0xA619 +#define reg_dummy_143_136_pos 0 +#define reg_dummy_143_136_len 8 +#define reg_dummy_143_136_lsb 136 + +#define xd_p_reg_CCIR_dis 0xA619 +#define reg_CCIR_dis_pos 0 +#define reg_CCIR_dis_len 1 +#define reg_CCIR_dis_lsb 0 + +#define xd_p_reg_dummy_151_144 0xA61A +#define reg_dummy_151_144_pos 0 +#define reg_dummy_151_144_len 8 +#define reg_dummy_151_144_lsb 144 + +#define xd_p_reg_dummy_159_152 0xA61B +#define reg_dummy_159_152_pos 0 +#define reg_dummy_159_152_len 8 +#define reg_dummy_159_152_lsb 152 + +#define xd_p_reg_dummy_167_160 0xA61C +#define reg_dummy_167_160_pos 0 +#define reg_dummy_167_160_len 8 +#define reg_dummy_167_160_lsb 160 + +#define xd_p_reg_dummy_175_168 0xA61D +#define reg_dummy_175_168_pos 0 +#define reg_dummy_175_168_len 8 +#define reg_dummy_175_168_lsb 168 + +#define xd_p_reg_dummy_183_176 0xA61E +#define reg_dummy_183_176_pos 0 +#define reg_dummy_183_176_len 8 +#define reg_dummy_183_176_lsb 176 + +#define xd_p_reg_ofsm_read_rbc_en 0xA61E +#define reg_ofsm_read_rbc_en_pos 2 +#define reg_ofsm_read_rbc_en_len 1 +#define reg_ofsm_read_rbc_en_lsb 0 + +#define xd_p_reg_ce_filter_selection_dis 0xA61E +#define reg_ce_filter_selection_dis_pos 1 +#define reg_ce_filter_selection_dis_len 1 +#define reg_ce_filter_selection_dis_lsb 0 + +#define xd_p_reg_OFSM_version_control_7_0 0xA611 +#define reg_OFSM_version_control_7_0_pos 0 +#define reg_OFSM_version_control_7_0_len 8 +#define reg_OFSM_version_control_7_0_lsb 0 + +#define xd_p_reg_OFSM_version_control_15_8 0xA61F +#define reg_OFSM_version_control_15_8_pos 0 +#define reg_OFSM_version_control_15_8_len 8 +#define reg_OFSM_version_control_15_8_lsb 0 + +#define xd_p_reg_OFSM_version_control_23_16 0xA620 +#define reg_OFSM_version_control_23_16_pos 0 +#define reg_OFSM_version_control_23_16_len 8 +#define reg_OFSM_version_control_23_16_lsb 0 + +#define xd_p_reg_dummy_191_184 0xA61F +#define reg_dummy_191_184_pos 0 +#define reg_dummy_191_184_len 8 +#define reg_dummy_191_184_lsb 184 + +#define xd_p_reg_dummy_199_192 0xA620 +#define reg_dummy_199_192_pos 0 +#define reg_dummy_199_192_len 8 +#define reg_dummy_199_192_lsb 192 + +#define xd_p_reg_ce_en 0xABC0 +#define reg_ce_en_pos 0 +#define reg_ce_en_len 1 +#define reg_ce_en_lsb 0 +#define xd_p_reg_ce_fctrl_en 0xABC0 +#define reg_ce_fctrl_en_pos 1 +#define reg_ce_fctrl_en_len 1 +#define reg_ce_fctrl_en_lsb 0 +#define xd_p_reg_ce_fste_tdi 0xABC0 +#define reg_ce_fste_tdi_pos 2 +#define reg_ce_fste_tdi_len 1 +#define reg_ce_fste_tdi_lsb 0 +#define xd_p_reg_ce_dynamic 0xABC0 +#define reg_ce_dynamic_pos 3 +#define reg_ce_dynamic_len 1 +#define reg_ce_dynamic_lsb 0 +#define xd_p_reg_ce_conf 0xABC0 +#define reg_ce_conf_pos 4 +#define reg_ce_conf_len 2 +#define reg_ce_conf_lsb 0 +#define xd_p_reg_ce_dyn12 0xABC0 +#define reg_ce_dyn12_pos 6 +#define reg_ce_dyn12_len 1 +#define reg_ce_dyn12_lsb 0 +#define xd_p_reg_ce_derot_en 0xABC0 +#define reg_ce_derot_en_pos 7 +#define reg_ce_derot_en_len 1 +#define reg_ce_derot_en_lsb 0 +#define xd_p_reg_ce_dynamic_th_7_0 0xABC1 +#define reg_ce_dynamic_th_7_0_pos 0 +#define reg_ce_dynamic_th_7_0_len 8 +#define reg_ce_dynamic_th_7_0_lsb 0 +#define xd_p_reg_ce_dynamic_th_15_8 0xABC2 +#define reg_ce_dynamic_th_15_8_pos 0 +#define reg_ce_dynamic_th_15_8_len 8 +#define reg_ce_dynamic_th_15_8_lsb 8 +#define xd_p_reg_ce_s1 0xABC3 +#define reg_ce_s1_pos 0 +#define reg_ce_s1_len 5 +#define reg_ce_s1_lsb 0 +#define xd_p_reg_ce_var_forced_value 0xABC3 +#define reg_ce_var_forced_value_pos 5 +#define reg_ce_var_forced_value_len 3 +#define reg_ce_var_forced_value_lsb 0 +#define xd_p_reg_ce_data_im_7_0 0xABC4 +#define reg_ce_data_im_7_0_pos 0 +#define reg_ce_data_im_7_0_len 8 +#define reg_ce_data_im_7_0_lsb 0 +#define xd_p_reg_ce_data_im_8 0xABC5 +#define reg_ce_data_im_8_pos 0 +#define reg_ce_data_im_8_len 1 +#define reg_ce_data_im_8_lsb 0 +#define xd_p_reg_ce_data_re_6_0 0xABC5 +#define reg_ce_data_re_6_0_pos 1 +#define reg_ce_data_re_6_0_len 7 +#define reg_ce_data_re_6_0_lsb 0 +#define xd_p_reg_ce_data_re_8_7 0xABC6 +#define reg_ce_data_re_8_7_pos 0 +#define reg_ce_data_re_8_7_len 2 +#define reg_ce_data_re_8_7_lsb 7 +#define xd_p_reg_ce_tone_5_0 0xABC6 +#define reg_ce_tone_5_0_pos 2 +#define reg_ce_tone_5_0_len 6 +#define reg_ce_tone_5_0_lsb 0 +#define xd_p_reg_ce_tone_12_6 0xABC7 +#define reg_ce_tone_12_6_pos 0 +#define reg_ce_tone_12_6_len 7 +#define reg_ce_tone_12_6_lsb 6 +#define xd_p_reg_ce_centroid_drift_th 0xABC8 +#define reg_ce_centroid_drift_th_pos 0 +#define reg_ce_centroid_drift_th_len 8 +#define reg_ce_centroid_drift_th_lsb 0 +#define xd_p_reg_ce_centroid_count_max 0xABC9 +#define reg_ce_centroid_count_max_pos 0 +#define reg_ce_centroid_count_max_len 4 +#define reg_ce_centroid_count_max_lsb 0 +#define xd_p_reg_ce_centroid_bias_inc_7_0 0xABCA +#define reg_ce_centroid_bias_inc_7_0_pos 0 +#define reg_ce_centroid_bias_inc_7_0_len 8 +#define reg_ce_centroid_bias_inc_7_0_lsb 0 +#define xd_p_reg_ce_centroid_bias_inc_8 0xABCB +#define reg_ce_centroid_bias_inc_8_pos 0 +#define reg_ce_centroid_bias_inc_8_len 1 +#define reg_ce_centroid_bias_inc_8_lsb 0 +#define xd_p_reg_ce_var_th0_7_0 0xABCC +#define reg_ce_var_th0_7_0_pos 0 +#define reg_ce_var_th0_7_0_len 8 +#define reg_ce_var_th0_7_0_lsb 0 +#define xd_p_reg_ce_var_th0_15_8 0xABCD +#define reg_ce_var_th0_15_8_pos 0 +#define reg_ce_var_th0_15_8_len 8 +#define reg_ce_var_th0_15_8_lsb 8 +#define xd_p_reg_ce_var_th1_7_0 0xABCE +#define reg_ce_var_th1_7_0_pos 0 +#define reg_ce_var_th1_7_0_len 8 +#define reg_ce_var_th1_7_0_lsb 0 +#define xd_p_reg_ce_var_th1_15_8 0xABCF +#define reg_ce_var_th1_15_8_pos 0 +#define reg_ce_var_th1_15_8_len 8 +#define reg_ce_var_th1_15_8_lsb 8 +#define xd_p_reg_ce_var_th2_7_0 0xABD0 +#define reg_ce_var_th2_7_0_pos 0 +#define reg_ce_var_th2_7_0_len 8 +#define reg_ce_var_th2_7_0_lsb 0 +#define xd_p_reg_ce_var_th2_15_8 0xABD1 +#define reg_ce_var_th2_15_8_pos 0 +#define reg_ce_var_th2_15_8_len 8 +#define reg_ce_var_th2_15_8_lsb 8 +#define xd_p_reg_ce_var_th3_7_0 0xABD2 +#define reg_ce_var_th3_7_0_pos 0 +#define reg_ce_var_th3_7_0_len 8 +#define reg_ce_var_th3_7_0_lsb 0 +#define xd_p_reg_ce_var_th3_15_8 0xABD3 +#define reg_ce_var_th3_15_8_pos 0 +#define reg_ce_var_th3_15_8_len 8 +#define reg_ce_var_th3_15_8_lsb 8 +#define xd_p_reg_ce_var_th4_7_0 0xABD4 +#define reg_ce_var_th4_7_0_pos 0 +#define reg_ce_var_th4_7_0_len 8 +#define reg_ce_var_th4_7_0_lsb 0 +#define xd_p_reg_ce_var_th4_15_8 0xABD5 +#define reg_ce_var_th4_15_8_pos 0 +#define reg_ce_var_th4_15_8_len 8 +#define reg_ce_var_th4_15_8_lsb 8 +#define xd_p_reg_ce_var_th5_7_0 0xABD6 +#define reg_ce_var_th5_7_0_pos 0 +#define reg_ce_var_th5_7_0_len 8 +#define reg_ce_var_th5_7_0_lsb 0 +#define xd_p_reg_ce_var_th5_15_8 0xABD7 +#define reg_ce_var_th5_15_8_pos 0 +#define reg_ce_var_th5_15_8_len 8 +#define reg_ce_var_th5_15_8_lsb 8 +#define xd_p_reg_ce_var_th6_7_0 0xABD8 +#define reg_ce_var_th6_7_0_pos 0 +#define reg_ce_var_th6_7_0_len 8 +#define reg_ce_var_th6_7_0_lsb 0 +#define xd_p_reg_ce_var_th6_15_8 0xABD9 +#define reg_ce_var_th6_15_8_pos 0 +#define reg_ce_var_th6_15_8_len 8 +#define reg_ce_var_th6_15_8_lsb 8 +#define xd_p_reg_ce_fctrl_reset 0xABDA +#define reg_ce_fctrl_reset_pos 0 +#define reg_ce_fctrl_reset_len 1 +#define reg_ce_fctrl_reset_lsb 0 +#define xd_p_reg_ce_cent_auto_clr_en 0xABDA +#define reg_ce_cent_auto_clr_en_pos 1 +#define reg_ce_cent_auto_clr_en_len 1 +#define reg_ce_cent_auto_clr_en_lsb 0 +#define xd_p_reg_ce_fctrl_auto_reset_en 0xABDA +#define reg_ce_fctrl_auto_reset_en_pos 2 +#define reg_ce_fctrl_auto_reset_en_len 1 +#define reg_ce_fctrl_auto_reset_en_lsb 0 +#define xd_p_reg_ce_var_forced_en 0xABDA +#define reg_ce_var_forced_en_pos 3 +#define reg_ce_var_forced_en_len 1 +#define reg_ce_var_forced_en_lsb 0 +#define xd_p_reg_ce_cent_forced_en 0xABDA +#define reg_ce_cent_forced_en_pos 4 +#define reg_ce_cent_forced_en_len 1 +#define reg_ce_cent_forced_en_lsb 0 +#define xd_p_reg_ce_var_max 0xABDA +#define reg_ce_var_max_pos 5 +#define reg_ce_var_max_len 3 +#define reg_ce_var_max_lsb 0 +#define xd_p_reg_ce_cent_forced_value_7_0 0xABDB +#define reg_ce_cent_forced_value_7_0_pos 0 +#define reg_ce_cent_forced_value_7_0_len 8 +#define reg_ce_cent_forced_value_7_0_lsb 0 +#define xd_p_reg_ce_cent_forced_value_11_8 0xABDC +#define reg_ce_cent_forced_value_11_8_pos 0 +#define reg_ce_cent_forced_value_11_8_len 4 +#define reg_ce_cent_forced_value_11_8_lsb 8 +#define xd_p_reg_ce_fctrl_rd 0xABDD +#define reg_ce_fctrl_rd_pos 0 +#define reg_ce_fctrl_rd_len 1 +#define reg_ce_fctrl_rd_lsb 0 +#define xd_p_reg_ce_centroid_max_6_0 0xABDD +#define reg_ce_centroid_max_6_0_pos 1 +#define reg_ce_centroid_max_6_0_len 7 +#define reg_ce_centroid_max_6_0_lsb 0 +#define xd_p_reg_ce_centroid_max_11_7 0xABDE +#define reg_ce_centroid_max_11_7_pos 0 +#define reg_ce_centroid_max_11_7_len 5 +#define reg_ce_centroid_max_11_7_lsb 7 +#define xd_p_reg_ce_var 0xABDF +#define reg_ce_var_pos 0 +#define reg_ce_var_len 3 +#define reg_ce_var_lsb 0 +#define xd_p_reg_ce_fctrl_rdy 0xABDF +#define reg_ce_fctrl_rdy_pos 3 +#define reg_ce_fctrl_rdy_len 1 +#define reg_ce_fctrl_rdy_lsb 0 +#define xd_p_reg_ce_centroid_out_3_0 0xABDF +#define reg_ce_centroid_out_3_0_pos 4 +#define reg_ce_centroid_out_3_0_len 4 +#define reg_ce_centroid_out_3_0_lsb 0 +#define xd_p_reg_ce_centroid_out_11_4 0xABE0 +#define reg_ce_centroid_out_11_4_pos 0 +#define reg_ce_centroid_out_11_4_len 8 +#define reg_ce_centroid_out_11_4_lsb 4 +#define xd_p_reg_ce_bias_7_0 0xABE1 +#define reg_ce_bias_7_0_pos 0 +#define reg_ce_bias_7_0_len 8 +#define reg_ce_bias_7_0_lsb 0 +#define xd_p_reg_ce_bias_11_8 0xABE2 +#define reg_ce_bias_11_8_pos 0 +#define reg_ce_bias_11_8_len 4 +#define reg_ce_bias_11_8_lsb 8 +#define xd_p_reg_ce_m1_3_0 0xABE2 +#define reg_ce_m1_3_0_pos 4 +#define reg_ce_m1_3_0_len 4 +#define reg_ce_m1_3_0_lsb 0 +#define xd_p_reg_ce_m1_11_4 0xABE3 +#define reg_ce_m1_11_4_pos 0 +#define reg_ce_m1_11_4_len 8 +#define reg_ce_m1_11_4_lsb 4 +#define xd_p_reg_ce_rh0_7_0 0xABE4 +#define reg_ce_rh0_7_0_pos 0 +#define reg_ce_rh0_7_0_len 8 +#define reg_ce_rh0_7_0_lsb 0 +#define xd_p_reg_ce_rh0_15_8 0xABE5 +#define reg_ce_rh0_15_8_pos 0 +#define reg_ce_rh0_15_8_len 8 +#define reg_ce_rh0_15_8_lsb 8 +#define xd_p_reg_ce_rh0_23_16 0xABE6 +#define reg_ce_rh0_23_16_pos 0 +#define reg_ce_rh0_23_16_len 8 +#define reg_ce_rh0_23_16_lsb 16 +#define xd_p_reg_ce_rh0_31_24 0xABE7 +#define reg_ce_rh0_31_24_pos 0 +#define reg_ce_rh0_31_24_len 8 +#define reg_ce_rh0_31_24_lsb 24 +#define xd_p_reg_ce_rh3_real_7_0 0xABE8 +#define reg_ce_rh3_real_7_0_pos 0 +#define reg_ce_rh3_real_7_0_len 8 +#define reg_ce_rh3_real_7_0_lsb 0 +#define xd_p_reg_ce_rh3_real_15_8 0xABE9 +#define reg_ce_rh3_real_15_8_pos 0 +#define reg_ce_rh3_real_15_8_len 8 +#define reg_ce_rh3_real_15_8_lsb 8 +#define xd_p_reg_ce_rh3_real_23_16 0xABEA +#define reg_ce_rh3_real_23_16_pos 0 +#define reg_ce_rh3_real_23_16_len 8 +#define reg_ce_rh3_real_23_16_lsb 16 +#define xd_p_reg_ce_rh3_real_31_24 0xABEB +#define reg_ce_rh3_real_31_24_pos 0 +#define reg_ce_rh3_real_31_24_len 8 +#define reg_ce_rh3_real_31_24_lsb 24 +#define xd_p_reg_ce_rh3_imag_7_0 0xABEC +#define reg_ce_rh3_imag_7_0_pos 0 +#define reg_ce_rh3_imag_7_0_len 8 +#define reg_ce_rh3_imag_7_0_lsb 0 +#define xd_p_reg_ce_rh3_imag_15_8 0xABED +#define reg_ce_rh3_imag_15_8_pos 0 +#define reg_ce_rh3_imag_15_8_len 8 +#define reg_ce_rh3_imag_15_8_lsb 8 +#define xd_p_reg_ce_rh3_imag_23_16 0xABEE +#define reg_ce_rh3_imag_23_16_pos 0 +#define reg_ce_rh3_imag_23_16_len 8 +#define reg_ce_rh3_imag_23_16_lsb 16 +#define xd_p_reg_ce_rh3_imag_31_24 0xABEF +#define reg_ce_rh3_imag_31_24_pos 0 +#define reg_ce_rh3_imag_31_24_len 8 +#define reg_ce_rh3_imag_31_24_lsb 24 +#define xd_p_reg_feq_fix_eh2_7_0 0xABF0 +#define reg_feq_fix_eh2_7_0_pos 0 +#define reg_feq_fix_eh2_7_0_len 8 +#define reg_feq_fix_eh2_7_0_lsb 0 +#define xd_p_reg_feq_fix_eh2_15_8 0xABF1 +#define reg_feq_fix_eh2_15_8_pos 0 +#define reg_feq_fix_eh2_15_8_len 8 +#define reg_feq_fix_eh2_15_8_lsb 8 +#define xd_p_reg_feq_fix_eh2_23_16 0xABF2 +#define reg_feq_fix_eh2_23_16_pos 0 +#define reg_feq_fix_eh2_23_16_len 8 +#define reg_feq_fix_eh2_23_16_lsb 16 +#define xd_p_reg_feq_fix_eh2_31_24 0xABF3 +#define reg_feq_fix_eh2_31_24_pos 0 +#define reg_feq_fix_eh2_31_24_len 8 +#define reg_feq_fix_eh2_31_24_lsb 24 +#define xd_p_reg_ce_m2_central_7_0 0xABF4 +#define reg_ce_m2_central_7_0_pos 0 +#define reg_ce_m2_central_7_0_len 8 +#define reg_ce_m2_central_7_0_lsb 0 +#define xd_p_reg_ce_m2_central_15_8 0xABF5 +#define reg_ce_m2_central_15_8_pos 0 +#define reg_ce_m2_central_15_8_len 8 +#define reg_ce_m2_central_15_8_lsb 8 +#define xd_p_reg_ce_fftshift 0xABF6 +#define reg_ce_fftshift_pos 0 +#define reg_ce_fftshift_len 4 +#define reg_ce_fftshift_lsb 0 +#define xd_p_reg_ce_fftshift1 0xABF6 +#define reg_ce_fftshift1_pos 4 +#define reg_ce_fftshift1_len 4 +#define reg_ce_fftshift1_lsb 0 +#define xd_p_reg_ce_fftshift2 0xABF7 +#define reg_ce_fftshift2_pos 0 +#define reg_ce_fftshift2_len 4 +#define reg_ce_fftshift2_lsb 0 +#define xd_p_reg_ce_top_mobile 0xABF7 +#define reg_ce_top_mobile_pos 4 +#define reg_ce_top_mobile_len 1 +#define reg_ce_top_mobile_lsb 0 +#define xd_p_reg_strong_sginal_detected 0xA2BC +#define reg_strong_sginal_detected_pos 2 +#define reg_strong_sginal_detected_len 1 +#define reg_strong_sginal_detected_lsb 0 + +#define XD_MP2IF_BASE 0xB000 +#define XD_MP2IF_CSR (0x00 + XD_MP2IF_BASE) +#define XD_MP2IF_DMX_CTRL (0x03 + XD_MP2IF_BASE) +#define XD_MP2IF_PID_IDX (0x04 + XD_MP2IF_BASE) +#define XD_MP2IF_PID_DATA_L (0x05 + XD_MP2IF_BASE) +#define XD_MP2IF_PID_DATA_H (0x06 + XD_MP2IF_BASE) +#define XD_MP2IF_MISC (0x07 + XD_MP2IF_BASE) + +extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d); +extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, + u8 * value); +extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len); +extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, + u8 value); +extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len); +extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, + u8 addr, u8 * values, int len); +extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len); +extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, + u8 pos, u8 len, u8 * value); +extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, + u8 pos, u8 len, u8 value); +extern int af9005_send_command(struct dvb_usb_device *d, u8 command, + u8 * wbuf, int wlen, u8 * rbuf, int rlen); +extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, + u8 * values, int len); +extern int af9005_tuner_attach(struct dvb_usb_adapter *adap); +extern int af9005_led_control(struct dvb_usb_device *d, int onoff); + +extern u8 regmask[8]; + +/* remote control decoder */ +extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, + u32 * event, int *state); +extern struct rc_map_table rc_map_af9005_table[]; +extern int rc_map_af9005_table_size; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-remote.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-remote.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-remote.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-remote.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,156 @@ +/* DVB USB compliant Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Standard remote decode function + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * see Documentation/dvb/REDME.dvb-usb for more information + */ +#include "af9005.h" +/* debug */ +static int dvb_usb_af9005_remote_debug; +module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); +MODULE_PARM_DESC(debug, + "enable (1) or disable (0) debug messages." + DVB_USB_DEBUG_STATUS); + +#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args) + +struct rc_map_table rc_map_af9005_table[] = { + + {0x01b7, KEY_POWER}, + {0x01a7, KEY_VOLUMEUP}, + {0x0187, KEY_CHANNELUP}, + {0x017f, KEY_MUTE}, + {0x01bf, KEY_VOLUMEDOWN}, + {0x013f, KEY_CHANNELDOWN}, + {0x01df, KEY_1}, + {0x015f, KEY_2}, + {0x019f, KEY_3}, + {0x011f, KEY_4}, + {0x01ef, KEY_5}, + {0x016f, KEY_6}, + {0x01af, KEY_7}, + {0x0127, KEY_8}, + {0x0107, KEY_9}, + {0x01cf, KEY_ZOOM}, + {0x014f, KEY_0}, + {0x018f, KEY_GOTO}, /* marked jump on the remote */ + + {0x00bd, KEY_POWER}, + {0x007d, KEY_VOLUMEUP}, + {0x00fd, KEY_CHANNELUP}, + {0x009d, KEY_MUTE}, + {0x005d, KEY_VOLUMEDOWN}, + {0x00dd, KEY_CHANNELDOWN}, + {0x00ad, KEY_1}, + {0x006d, KEY_2}, + {0x00ed, KEY_3}, + {0x008d, KEY_4}, + {0x004d, KEY_5}, + {0x00cd, KEY_6}, + {0x00b5, KEY_7}, + {0x0075, KEY_8}, + {0x00f5, KEY_9}, + {0x0095, KEY_ZOOM}, + {0x0055, KEY_0}, + {0x00d5, KEY_GOTO}, /* marked jump on the remote */ +}; + +int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table); + +static int repeatable_keys[] = { + KEY_VOLUMEUP, + KEY_VOLUMEDOWN, + KEY_CHANNELUP, + KEY_CHANNELDOWN +}; + +int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event, + int *state) +{ + u16 mark, space; + u32 result; + u8 cust, dat, invdat; + int i; + + if (len >= 6) { + mark = (u16) (data[0] << 8) + data[1]; + space = (u16) (data[2] << 8) + data[3]; + if (space * 3 < mark) { + for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { + if (d->last_event == repeatable_keys[i]) { + *state = REMOTE_KEY_REPEAT; + *event = d->last_event; + deb_decode("repeat key, event %x\n", + *event); + return 0; + } + } + deb_decode("repeated key ignored (non repeatable)\n"); + return 0; + } else if (len >= 33 * 4) { /*32 bits + start code */ + result = 0; + for (i = 4; i < 4 + 32 * 4; i += 4) { + result <<= 1; + mark = (u16) (data[i] << 8) + data[i + 1]; + mark >>= 1; + space = (u16) (data[i + 2] << 8) + data[i + 3]; + space >>= 1; + if (mark * 2 > space) + result += 1; + } + deb_decode("key pressed, raw value %x\n", result); + if ((result & 0xff000000) != 0xfe000000) { + deb_decode + ("doesn't start with 0xfe, ignored\n"); + return 0; + } + cust = (result >> 16) & 0xff; + dat = (result >> 8) & 0xff; + invdat = (~result) & 0xff; + if (dat != invdat) { + deb_decode("code != inverted code\n"); + return 0; + } + for (i = 0; i < rc_map_af9005_table_size; i++) { + if (rc5_custom(&rc_map_af9005_table[i]) == cust + && rc5_data(&rc_map_af9005_table[i]) == dat) { + *event = rc_map_af9005_table[i].keycode; + *state = REMOTE_KEY_PRESSED; + deb_decode + ("key pressed, event %x\n", *event); + return 0; + } + } + deb_decode("not found in table\n"); + } + } + return 0; +} + +EXPORT_SYMBOL(rc_map_af9005_table); +EXPORT_SYMBOL(rc_map_af9005_table_size); +EXPORT_SYMBOL(af9005_rc_decode); + +MODULE_AUTHOR("Luca Olivetti "); +MODULE_DESCRIPTION + ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-script.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-script.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-script.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9005-script.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,203 @@ +/* +File automatically generated by createinit.py using data +extracted from AF05BDA.sys (windows driver): + +dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110 +python createinit.py > af9005-script.h + +*/ + +typedef struct { + u16 reg; + u8 pos; + u8 len; + u8 val; +} RegDesc; + +static RegDesc script[] = { + {0xa180, 0x0, 0x8, 0xa}, + {0xa181, 0x0, 0x8, 0xd7}, + {0xa182, 0x0, 0x8, 0xa3}, + {0xa0a0, 0x0, 0x8, 0x0}, + {0xa0a1, 0x0, 0x5, 0x0}, + {0xa0a1, 0x5, 0x1, 0x1}, + {0xa0c0, 0x0, 0x4, 0x1}, + {0xa20e, 0x4, 0x4, 0xa}, + {0xa20f, 0x0, 0x8, 0x40}, + {0xa210, 0x0, 0x8, 0x8}, + {0xa32a, 0x0, 0x4, 0xa}, + {0xa32c, 0x0, 0x8, 0x20}, + {0xa32b, 0x0, 0x8, 0x15}, + {0xa1a0, 0x1, 0x1, 0x1}, + {0xa000, 0x0, 0x1, 0x1}, + {0xa000, 0x1, 0x1, 0x0}, + {0xa001, 0x1, 0x1, 0x1}, + {0xa001, 0x0, 0x1, 0x0}, + {0xa001, 0x5, 0x1, 0x0}, + {0xa00e, 0x0, 0x5, 0x10}, + {0xa00f, 0x0, 0x3, 0x4}, + {0xa00f, 0x3, 0x3, 0x5}, + {0xa010, 0x0, 0x3, 0x4}, + {0xa010, 0x3, 0x3, 0x5}, + {0xa016, 0x4, 0x4, 0x3}, + {0xa01f, 0x0, 0x6, 0xa}, + {0xa020, 0x0, 0x6, 0xa}, + {0xa2bc, 0x0, 0x1, 0x1}, + {0xa2bc, 0x5, 0x1, 0x1}, + {0xa015, 0x0, 0x8, 0x50}, + {0xa016, 0x0, 0x1, 0x0}, + {0xa02a, 0x0, 0x8, 0x50}, + {0xa029, 0x0, 0x8, 0x4b}, + {0xa614, 0x0, 0x8, 0x46}, + {0xa002, 0x0, 0x5, 0x19}, + {0xa003, 0x0, 0x5, 0x1a}, + {0xa004, 0x0, 0x5, 0x19}, + {0xa005, 0x0, 0x5, 0x1a}, + {0xa008, 0x0, 0x8, 0x69}, + {0xa009, 0x0, 0x2, 0x2}, + {0xae1b, 0x0, 0x8, 0x69}, + {0xae1c, 0x0, 0x8, 0x2}, + {0xae1d, 0x0, 0x8, 0x2a}, + {0xa022, 0x0, 0x8, 0xaa}, + {0xa006, 0x0, 0x8, 0xc8}, + {0xa007, 0x0, 0x2, 0x0}, + {0xa00c, 0x0, 0x8, 0xba}, + {0xa00d, 0x0, 0x2, 0x2}, + {0xa608, 0x0, 0x8, 0xba}, + {0xa60e, 0x0, 0x2, 0x2}, + {0xa609, 0x0, 0x8, 0x80}, + {0xa60e, 0x2, 0x2, 0x3}, + {0xa00a, 0x0, 0x8, 0xb6}, + {0xa00b, 0x0, 0x2, 0x0}, + {0xa011, 0x0, 0x8, 0xb9}, + {0xa012, 0x0, 0x2, 0x0}, + {0xa013, 0x0, 0x8, 0xbd}, + {0xa014, 0x0, 0x2, 0x2}, + {0xa366, 0x0, 0x1, 0x1}, + {0xa2bc, 0x3, 0x1, 0x0}, + {0xa2bd, 0x0, 0x8, 0xa}, + {0xa2be, 0x0, 0x8, 0x14}, + {0xa2bf, 0x0, 0x8, 0x8}, + {0xa60a, 0x0, 0x8, 0xbd}, + {0xa60e, 0x4, 0x2, 0x2}, + {0xa60b, 0x0, 0x8, 0x86}, + {0xa60e, 0x6, 0x2, 0x3}, + {0xa001, 0x2, 0x2, 0x1}, + {0xa1c7, 0x0, 0x8, 0xf5}, + {0xa03d, 0x0, 0x8, 0xb1}, + {0xa616, 0x0, 0x8, 0xff}, + {0xa617, 0x0, 0x8, 0xad}, + {0xa618, 0x0, 0x8, 0xad}, + {0xa61e, 0x3, 0x1, 0x1}, + {0xae1a, 0x0, 0x8, 0x0}, + {0xae19, 0x0, 0x8, 0xc8}, + {0xae18, 0x0, 0x8, 0x61}, + {0xa140, 0x0, 0x8, 0x0}, + {0xa141, 0x0, 0x8, 0xc8}, + {0xa142, 0x0, 0x7, 0x61}, + {0xa023, 0x0, 0x8, 0xff}, + {0xa021, 0x0, 0x8, 0xad}, + {0xa026, 0x0, 0x1, 0x0}, + {0xa024, 0x0, 0x8, 0xff}, + {0xa025, 0x0, 0x8, 0xff}, + {0xa1c8, 0x0, 0x8, 0xf}, + {0xa2bc, 0x1, 0x1, 0x0}, + {0xa60c, 0x0, 0x4, 0x5}, + {0xa60c, 0x4, 0x4, 0x6}, + {0xa60d, 0x0, 0x8, 0xa}, + {0xa371, 0x0, 0x1, 0x1}, + {0xa366, 0x1, 0x3, 0x7}, + {0xa338, 0x0, 0x8, 0x10}, + {0xa339, 0x0, 0x6, 0x7}, + {0xa33a, 0x0, 0x6, 0x1f}, + {0xa33b, 0x0, 0x8, 0xf6}, + {0xa33c, 0x3, 0x5, 0x4}, + {0xa33d, 0x4, 0x4, 0x0}, + {0xa33d, 0x1, 0x1, 0x1}, + {0xa33d, 0x2, 0x1, 0x1}, + {0xa33d, 0x3, 0x1, 0x1}, + {0xa16d, 0x0, 0x4, 0xf}, + {0xa161, 0x0, 0x5, 0x5}, + {0xa162, 0x0, 0x4, 0x5}, + {0xa165, 0x0, 0x8, 0xff}, + {0xa166, 0x0, 0x8, 0x9c}, + {0xa2c3, 0x0, 0x4, 0x5}, + {0xa61a, 0x0, 0x6, 0xf}, + {0xb200, 0x0, 0x8, 0xa1}, + {0xb201, 0x0, 0x8, 0x7}, + {0xa093, 0x0, 0x1, 0x0}, + {0xa093, 0x1, 0x5, 0xf}, + {0xa094, 0x0, 0x8, 0xff}, + {0xa095, 0x0, 0x8, 0xf}, + {0xa080, 0x2, 0x5, 0x3}, + {0xa081, 0x0, 0x4, 0x0}, + {0xa081, 0x4, 0x4, 0x9}, + {0xa082, 0x0, 0x5, 0x1f}, + {0xa08d, 0x0, 0x8, 0x1}, + {0xa083, 0x0, 0x8, 0x32}, + {0xa084, 0x0, 0x1, 0x0}, + {0xa08e, 0x0, 0x8, 0x3}, + {0xa085, 0x0, 0x8, 0x32}, + {0xa086, 0x0, 0x3, 0x0}, + {0xa087, 0x0, 0x8, 0x6e}, + {0xa088, 0x0, 0x5, 0x15}, + {0xa089, 0x0, 0x8, 0x0}, + {0xa08a, 0x0, 0x5, 0x19}, + {0xa08b, 0x0, 0x8, 0x92}, + {0xa08c, 0x0, 0x5, 0x1c}, + {0xa120, 0x0, 0x8, 0x0}, + {0xa121, 0x0, 0x5, 0x10}, + {0xa122, 0x0, 0x8, 0x0}, + {0xa123, 0x0, 0x7, 0x40}, + {0xa123, 0x7, 0x1, 0x0}, + {0xa124, 0x0, 0x8, 0x13}, + {0xa125, 0x0, 0x7, 0x10}, + {0xa1c0, 0x0, 0x8, 0x0}, + {0xa1c1, 0x0, 0x5, 0x4}, + {0xa1c2, 0x0, 0x8, 0x0}, + {0xa1c3, 0x0, 0x5, 0x10}, + {0xa1c3, 0x5, 0x3, 0x0}, + {0xa1c4, 0x0, 0x6, 0x0}, + {0xa1c5, 0x0, 0x7, 0x10}, + {0xa100, 0x0, 0x8, 0x0}, + {0xa101, 0x0, 0x5, 0x10}, + {0xa102, 0x0, 0x8, 0x0}, + {0xa103, 0x0, 0x7, 0x40}, + {0xa103, 0x7, 0x1, 0x0}, + {0xa104, 0x0, 0x8, 0x18}, + {0xa105, 0x0, 0x7, 0xa}, + {0xa106, 0x0, 0x8, 0x20}, + {0xa107, 0x0, 0x8, 0x40}, + {0xa108, 0x0, 0x4, 0x0}, + {0xa38c, 0x0, 0x8, 0xfc}, + {0xa38d, 0x0, 0x8, 0x0}, + {0xa38e, 0x0, 0x8, 0x7e}, + {0xa38f, 0x0, 0x8, 0x0}, + {0xa390, 0x0, 0x8, 0x2f}, + {0xa60f, 0x5, 0x1, 0x1}, + {0xa170, 0x0, 0x8, 0xdc}, + {0xa171, 0x0, 0x2, 0x0}, + {0xa2ae, 0x0, 0x1, 0x1}, + {0xa2ae, 0x1, 0x1, 0x1}, + {0xa392, 0x0, 0x1, 0x1}, + {0xa391, 0x2, 0x1, 0x0}, + {0xabc1, 0x0, 0x8, 0xff}, + {0xabc2, 0x0, 0x8, 0x0}, + {0xabc8, 0x0, 0x8, 0x8}, + {0xabca, 0x0, 0x8, 0x10}, + {0xabcb, 0x0, 0x1, 0x0}, + {0xabc3, 0x5, 0x3, 0x7}, + {0xabc0, 0x6, 0x1, 0x0}, + {0xabc0, 0x4, 0x2, 0x0}, + {0xa344, 0x4, 0x4, 0x1}, + {0xabc0, 0x7, 0x1, 0x1}, + {0xabc0, 0x2, 0x1, 0x1}, + {0xa345, 0x0, 0x8, 0x66}, + {0xa346, 0x0, 0x8, 0x66}, + {0xa347, 0x0, 0x4, 0x0}, + {0xa343, 0x0, 0x4, 0xa}, + {0xa347, 0x4, 0x4, 0x2}, + {0xa348, 0x0, 0x4, 0xc}, + {0xa348, 0x4, 0x4, 0x7}, + {0xa349, 0x0, 0x6, 0x2}, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9015.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9015.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9015.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9015.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1759 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + +#include "af9015.h" +#include "af9013.h" +#include "mt2060.h" +#include "qt1010.h" +#include "tda18271.h" +#include "mxl5005s.h" +#include "mc44s803.h" +#include "tda18218.h" +#include "mxl5007t.h" + +static int dvb_usb_af9015_debug; +module_param_named(debug, dvb_usb_af9015_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +static int dvb_usb_af9015_remote; +module_param_named(remote, dvb_usb_af9015_remote, int, 0644); +MODULE_PARM_DESC(remote, "select remote"); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static DEFINE_MUTEX(af9015_usb_mutex); + +static struct af9015_config af9015_config; +static struct dvb_usb_device_properties af9015_properties[3]; +static int af9015_properties_count = ARRAY_SIZE(af9015_properties); + +static struct af9013_config af9015_af9013_config[] = { + { + .demod_address = AF9015_I2C_DEMOD, + .output_mode = AF9013_OUTPUT_MODE_USB, + .api_version = { 0, 1, 9, 0 }, + .gpio[0] = AF9013_GPIO_HI, + .gpio[3] = AF9013_GPIO_TUNER_ON, + + }, { + .output_mode = AF9013_OUTPUT_MODE_SERIAL, + .api_version = { 0, 1, 9, 0 }, + .gpio[0] = AF9013_GPIO_TUNER_ON, + .gpio[1] = AF9013_GPIO_LO, + } +}; + +static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) +{ +#define BUF_LEN 63 +#define REQ_HDR_LEN 8 /* send header size */ +#define ACK_HDR_LEN 2 /* rece header size */ + int act_len, ret; + u8 buf[BUF_LEN]; + u8 write = 1; + u8 msg_len = REQ_HDR_LEN; + static u8 seq; /* packet sequence number */ + + if (mutex_lock_interruptible(&af9015_usb_mutex) < 0) + return -EAGAIN; + + buf[0] = req->cmd; + buf[1] = seq++; + buf[2] = req->i2c_addr; + buf[3] = req->addr >> 8; + buf[4] = req->addr & 0xff; + buf[5] = req->mbox; + buf[6] = req->addr_len; + buf[7] = req->data_len; + + switch (req->cmd) { + case GET_CONFIG: + case READ_MEMORY: + case RECONNECT_USB: + case GET_IR_CODE: + write = 0; + break; + case READ_I2C: + write = 0; + buf[2] |= 0x01; /* set I2C direction */ + case WRITE_I2C: + buf[0] = READ_WRITE_I2C; + break; + case WRITE_MEMORY: + if (((req->addr & 0xff00) == 0xff00) || + ((req->addr & 0xff00) == 0xae00)) + buf[0] = WRITE_VIRTUAL_MEMORY; + case WRITE_VIRTUAL_MEMORY: + case COPY_FIRMWARE: + case DOWNLOAD_FIRMWARE: + case BOOT: + break; + default: + err("unknown command:%d", req->cmd); + ret = -1; + goto error_unlock; + } + + /* buffer overflow check */ + if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || + (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { + err("too much data; cmd:%d len:%d", req->cmd, req->data_len); + ret = -EINVAL; + goto error_unlock; + } + + /* write requested */ + if (write) { + memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); + msg_len += req->data_len; + } + + deb_xfer(">>> "); + debug_dump(buf, msg_len, deb_xfer); + + /* send req */ + ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, + &act_len, AF9015_USB_TIMEOUT); + if (ret) + err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len); + else + if (act_len != msg_len) + ret = -1; /* all data is not send */ + if (ret) + goto error_unlock; + + /* no ack for those packets */ + if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) + goto exit_unlock; + + /* write receives seq + status = 2 bytes + read receives seq + status + data = 2 + N bytes */ + msg_len = ACK_HDR_LEN; + if (!write) + msg_len += req->data_len; + + ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, + &act_len, AF9015_USB_TIMEOUT); + if (ret) { + err("recv bulk message failed:%d", ret); + ret = -1; + goto error_unlock; + } + + deb_xfer("<<< "); + debug_dump(buf, act_len, deb_xfer); + + /* remote controller query status is 1 if remote code is not received */ + if (req->cmd == GET_IR_CODE && buf[1] == 1) { + buf[1] = 0; /* clear command "error" status */ + memset(&buf[2], 0, req->data_len); + buf[3] = 1; /* no remote code received mark */ + } + + /* check status */ + if (buf[1]) { + err("command failed:%d", buf[1]); + ret = -1; + goto error_unlock; + } + + /* read request, copy returned data to return buf */ + if (!write) + memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len); + +error_unlock: +exit_unlock: + mutex_unlock(&af9015_usb_mutex); + + return ret; +} + +static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) +{ + return af9015_rw_udev(d->udev, req); +} + +static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, + u8 len) +{ + struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, + val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) +{ + return af9015_write_regs(d, addr, &val, 1); +} + +static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) +{ + struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, + val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) +{ + return af9015_read_regs(d, addr, val, 1); +} + +static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 val) +{ + struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; + + if (addr == af9015_af9013_config[0].demod_address || + addr == af9015_af9013_config[1].demod_address) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 *val) +{ + struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; + + if (addr == af9015_af9013_config[0].demod_address || + addr == af9015_af9013_config[1].demod_address) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, i = 0; + u16 addr; + u8 uninitialized_var(mbox), addr_len; + struct req_t req; + +/* TODO: implement bus lock + +The bus lock is needed because there is two tuners both using same I2C-address. +Due to that the only way to select correct tuner is use demodulator I2C-gate. + +................................................ +. AF9015 includes integrated AF9013 demodulator. +. ____________ ____________ . ____________ +.| uC | | demod | . | tuner | +.|------------| |------------| . |------------| +.| AF9015 | | AF9013/5 | . | MXL5003 | +.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | +.| | | | addr 0x38 | . | addr 0xc6 | +.|____________| | |____________| . |____________| +.................|.............................. + | ____________ ____________ + | | demod | | tuner | + | |------------| |------------| + | | AF9013 | | MXL5003 | + +----I2C-------|-----/ -----|-------I2C-------| | + | addr 0x3a | | addr 0xc6 | + |____________| |____________| +*/ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (msg[i].addr == af9015_af9013_config[0].demod_address || + msg[i].addr == af9015_af9013_config[1].demod_address) { + addr = msg[i].buf[0] << 8; + addr += msg[i].buf[1]; + mbox = msg[i].buf[2]; + addr_len = 3; + } else { + addr = msg[i].buf[0]; + addr_len = 1; + /* mbox is don't care in that case */ + } + + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].addr == + af9015_af9013_config[0].demod_address) + req.cmd = READ_MEMORY; + else + req.cmd = READ_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i+1].len; + req.data = &msg[i+1].buf[0]; + ret = af9015_ctrl_msg(d, &req); + i += 2; + } else if (msg[i].flags & I2C_M_RD) { + ret = -EINVAL; + if (msg[i].addr == + af9015_af9013_config[0].demod_address) + goto error; + else + req.cmd = READ_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i].len; + req.data = &msg[i].buf[0]; + ret = af9015_ctrl_msg(d, &req); + i += 1; + } else { + if (msg[i].addr == + af9015_af9013_config[0].demod_address) + req.cmd = WRITE_MEMORY; + else + req.cmd = WRITE_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i].len-addr_len; + req.data = &msg[i].buf[addr_len]; + ret = af9015_ctrl_msg(d, &req); + i += 1; + } + if (ret) + goto error; + + } + ret = i; + +error: + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 af9015_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9015_i2c_algo = { + .master_xfer = af9015_i2c_xfer, + .functionality = af9015_i2c_func, +}; + +static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) +{ + int ret; + u8 val, mask = 0x01; + + ret = af9015_read_reg(d, addr, &val); + if (ret) + return ret; + + mask <<= bit; + if (op) { + /* set bit */ + val |= mask; + } else { + /* clear bit */ + mask ^= 0xff; + val &= mask; + } + + return af9015_write_reg(d, addr, val); +} + +static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 1); +} + +static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 0); +} + +static int af9015_init_endpoint(struct dvb_usb_device *d) +{ + int ret; + u16 frame_size; + u8 packet_size; + deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); + + /* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. + We use smaller - about 1/4 from the original, 5 and 87. */ +#define TS_PACKET_SIZE 188 + +#define TS_USB20_PACKET_COUNT 87 +#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) + +#define TS_USB11_PACKET_COUNT 5 +#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) + +#define TS_USB20_MAX_PACKET_SIZE 512 +#define TS_USB11_MAX_PACKET_SIZE 64 + + if (d->udev->speed == USB_SPEED_FULL) { + frame_size = TS_USB11_FRAME_SIZE/4; + packet_size = TS_USB11_MAX_PACKET_SIZE/4; + } else { + frame_size = TS_USB20_FRAME_SIZE/4; + packet_size = TS_USB20_MAX_PACKET_SIZE/4; + } + + ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ + if (ret) + goto error; + if (af9015_config.dual_mode) { + ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ + if (ret) + goto error; + } + ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ + if (ret) + goto error; + if (af9015_config.dual_mode) { + ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ + if (ret) + goto error; + } + /* EP4 xfer length */ + ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); + if (ret) + goto error; + /* EP5 xfer length */ + ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ + if (ret) + goto error; + if (af9015_config.dual_mode) { + ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ + if (ret) + goto error; + } + + /* enable / disable mp2if2 */ + if (af9015_config.dual_mode) + ret = af9015_set_reg_bit(d, 0xd50b, 0); + else + ret = af9015_clear_reg_bit(d, 0xd50b, 0); + +error: + if (ret) + err("endpoint init failed:%d", ret); + return ret; +} + +static int af9015_copy_firmware(struct dvb_usb_device *d) +{ + int ret; + u8 fw_params[4]; + u8 val, i; + struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), + fw_params }; + deb_info("%s:\n", __func__); + + fw_params[0] = af9015_config.firmware_size >> 8; + fw_params[1] = af9015_config.firmware_size & 0xff; + fw_params[2] = af9015_config.firmware_checksum >> 8; + fw_params[3] = af9015_config.firmware_checksum & 0xff; + + /* wait 2nd demodulator ready */ + msleep(100); + + ret = af9015_read_reg_i2c(d, + af9015_af9013_config[1].demod_address, 0x98be, &val); + if (ret) + goto error; + else + deb_info("%s: firmware status:%02x\n", __func__, val); + + if (val == 0x0c) /* fw is running, no need for download */ + goto exit; + + /* set I2C master clock to fast (to speed up firmware copy) */ + ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ + if (ret) + goto error; + + msleep(50); + + /* copy firmware */ + ret = af9015_ctrl_msg(d, &req); + if (ret) + err("firmware copy cmd failed:%d", ret); + deb_info("%s: firmware copy done\n", __func__); + + /* set I2C master clock back to normal */ + ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ + if (ret) + goto error; + + /* request boot firmware */ + ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address, + 0xe205, 1); + deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); + if (ret) + goto error; + + for (i = 0; i < 15; i++) { + msleep(100); + + /* check firmware status */ + ret = af9015_read_reg_i2c(d, + af9015_af9013_config[1].demod_address, 0x98be, &val); + deb_info("%s: firmware status cmd status:%d fw status:%02x\n", + __func__, ret, val); + if (ret) + goto error; + + if (val == 0x0c || val == 0x04) /* success or fail */ + break; + } + + if (val == 0x04) { + err("firmware did not run"); + ret = -1; + } else if (val != 0x0c) { + err("firmware boot timeout"); + ret = -1; + } + +error: +exit: + return ret; +} + +/* hash (and dump) eeprom */ +static int af9015_eeprom_hash(struct usb_device *udev) +{ + static const unsigned int eeprom_size = 256; + unsigned int reg; + int ret; + u8 val, *eeprom; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + + eeprom = kmalloc(eeprom_size, GFP_KERNEL); + if (eeprom == NULL) + return -ENOMEM; + + for (reg = 0; reg < eeprom_size; reg++) { + req.addr = reg; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto free; + eeprom[reg] = val; + } + + if (dvb_usb_af9015_debug & 0x01) + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom, + eeprom_size); + + BUG_ON(eeprom_size % 4); + + af9015_config.eeprom_sum = 0; + for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) { + af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32; + af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]); + } + + deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum); + + ret = 0; +free: + kfree(eeprom); + return ret; +} + +static int af9015_init(struct dvb_usb_device *d) +{ + int ret; + deb_info("%s:\n", __func__); + + /* init RC canary */ + ret = af9015_write_reg(d, 0x98e9, 0xff); + if (ret) + goto error; + + ret = af9015_init_endpoint(d); + if (ret) + goto error; + +error: + return ret; +} + +static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + deb_info("%s: onoff:%d\n", __func__, onoff); + + if (onoff) + ret = af9015_set_reg_bit(adap->dev, 0xd503, 0); + else + ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0); + + return ret; +} + +static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + int ret; + u8 idx; + + deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", + __func__, index, pid, onoff); + + ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff)); + if (ret) + goto error; + + ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8)); + if (ret) + goto error; + + idx = ((index & 0x1f) | (1 << 5)); + ret = af9015_write_reg(adap->dev, 0xd504, idx); + +error: + return ret; +} + +static int af9015_download_firmware(struct usb_device *udev, + const struct firmware *fw) +{ + int i, len, remaining, ret; + struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; + u16 checksum = 0; + + deb_info("%s:\n", __func__); + + /* calc checksum */ + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + + af9015_config.firmware_size = fw->size; + af9015_config.firmware_checksum = checksum; + + #define FW_ADDR 0x5100 /* firmware start address */ + #define LEN_MAX 55 /* max packet size */ + for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { + len = remaining; + if (len > LEN_MAX) + len = LEN_MAX; + + req.data_len = len; + req.data = (u8 *) &fw->data[fw->size - remaining]; + req.addr = FW_ADDR + fw->size - remaining; + + ret = af9015_rw_udev(udev, &req); + if (ret) { + err("firmware download failed:%d", ret); + goto error; + } + } + + /* firmware loaded, request boot */ + req.cmd = BOOT; + ret = af9015_rw_udev(udev, &req); + if (ret) { + err("firmware boot failed:%d", ret); + goto error; + } + +error: + return ret; +} + +struct af9015_rc_setup { + unsigned int id; + char *rc_codes; +}; + +static char *af9015_rc_setup_match(unsigned int id, + const struct af9015_rc_setup *table) +{ + for (; table->rc_codes; table++) + if (table->id == id) + return table->rc_codes; + return NULL; +} + +static const struct af9015_rc_setup af9015_rc_setup_modparam[] = { + { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, + { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, + { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, + { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, + { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, + { } +}; + +static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { + { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, + { 0xa3703d00, RC_MAP_ALINK_DTU_M }, + { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ + { } +}; + +static const struct af9015_rc_setup af9015_rc_setup_usbids[] = { + { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_RC, + RC_MAP_TERRATEC_SLIM_2 }, + { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, + RC_MAP_TERRATEC_SLIM }, + { (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700, + RC_MAP_AZUREWAVE_AD_TU700 }, + { (USB_VID_VISIONPLUS << 16) + USB_PID_TINYTWIN, + RC_MAP_AZUREWAVE_AD_TU700 }, + { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III, + RC_MAP_MSI_DIGIVOX_III }, + { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD, + RC_MAP_LEADTEK_Y04G0051 }, + { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X, + RC_MAP_AVERMEDIA_M135A }, + { (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT, + RC_MAP_TREKSTOR }, + { (USB_VID_KWORLD_2 << 16) + USB_PID_TINYTWIN_2, + RC_MAP_DIGITALNOW_TINYTWIN }, + { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3, + RC_MAP_DIGITALNOW_TINYTWIN }, + { } +}; + +static void af9015_set_remote_config(struct usb_device *udev, + struct dvb_usb_device_properties *props) +{ + u16 vid = le16_to_cpu(udev->descriptor.idVendor); + u16 pid = le16_to_cpu(udev->descriptor.idProduct); + + /* try to load remote based module param */ + props->rc.core.rc_codes = af9015_rc_setup_match( + dvb_usb_af9015_remote, af9015_rc_setup_modparam); + + /* try to load remote based eeprom hash */ + if (!props->rc.core.rc_codes) + props->rc.core.rc_codes = af9015_rc_setup_match( + af9015_config.eeprom_sum, af9015_rc_setup_hashes); + + /* try to load remote based USB ID */ + if (!props->rc.core.rc_codes) + props->rc.core.rc_codes = af9015_rc_setup_match( + (vid << 16) + pid, af9015_rc_setup_usbids); + + /* try to load remote based USB iManufacturer string */ + if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) { + /* Check USB manufacturer and product strings and try + to determine correct remote in case of chip vendor + reference IDs are used. + DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ + char manufacturer[10]; + memset(manufacturer, 0, sizeof(manufacturer)); + usb_string(udev, udev->descriptor.iManufacturer, + manufacturer, sizeof(manufacturer)); + if (!strcmp("MSI", manufacturer)) { + /* iManufacturer 1 MSI + iProduct 2 MSI K-VOX */ + props->rc.core.rc_codes = af9015_rc_setup_match( + AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + af9015_rc_setup_modparam); + } + } + + /* finally load "empty" just for leaving IR receiver enabled */ + if (!props->rc.core.rc_codes) + props->rc.core.rc_codes = RC_MAP_EMPTY; + + return; +} + +static int af9015_read_config(struct usb_device *udev) +{ + int ret; + u8 val, i, offset = 0; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + + /* IR remote controller */ + req.addr = AF9015_EEPROM_IR_MODE; + /* first message will timeout often due to possible hw bug */ + for (i = 0; i < 4; i++) { + ret = af9015_rw_udev(udev, &req); + if (!ret) + break; + } + if (ret) + goto error; + + ret = af9015_eeprom_hash(udev); + if (ret) + goto error; + + deb_info("%s: IR mode:%d\n", __func__, val); + for (i = 0; i < af9015_properties_count; i++) { + if (val == AF9015_IR_MODE_DISABLED) + af9015_properties[i].rc.core.rc_codes = NULL; + else + af9015_set_remote_config(udev, &af9015_properties[i]); + } + + /* TS mode - one or two receivers */ + req.addr = AF9015_EEPROM_TS_MODE; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_config.dual_mode = val; + deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode); + + /* Set adapter0 buffer size according to USB port speed, adapter1 buffer + size can be static because it is enabled only USB2.0 */ + for (i = 0; i < af9015_properties_count; i++) { + /* USB1.1 set smaller buffersize and disable 2nd adapter */ + if (udev->speed == USB_SPEED_FULL) { + af9015_properties[i].adapter[0].stream.u.bulk.buffersize + = TS_USB11_FRAME_SIZE; + /* disable 2nd adapter because we don't have + PID-filters */ + af9015_config.dual_mode = 0; + } else { + af9015_properties[i].adapter[0].stream.u.bulk.buffersize + = TS_USB20_FRAME_SIZE; + } + } + + if (af9015_config.dual_mode) { + /* read 2nd demodulator I2C address */ + req.addr = AF9015_EEPROM_DEMOD2_I2C; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_af9013_config[1].demod_address = val; + + /* enable 2nd adapter */ + for (i = 0; i < af9015_properties_count; i++) + af9015_properties[i].num_adapters = 2; + + } else { + /* disable 2nd adapter */ + for (i = 0; i < af9015_properties_count; i++) + af9015_properties[i].num_adapters = 1; + } + + for (i = 0; i < af9015_properties[0].num_adapters; i++) { + if (i == 1) + offset = AF9015_EEPROM_OFFSET; + /* xtal */ + req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + switch (val) { + case 0: + af9015_af9013_config[i].adc_clock = 28800; + break; + case 1: + af9015_af9013_config[i].adc_clock = 20480; + break; + case 2: + af9015_af9013_config[i].adc_clock = 28000; + break; + case 3: + af9015_af9013_config[i].adc_clock = 25000; + break; + }; + deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i, + val, af9015_af9013_config[i].adc_clock); + + /* tuner IF */ + req.addr = AF9015_EEPROM_IF1H + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_af9013_config[i].tuner_if = val << 8; + req.addr = AF9015_EEPROM_IF1L + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_af9013_config[i].tuner_if += val; + deb_info("%s: [%d] IF1:%d\n", __func__, i, + af9015_af9013_config[0].tuner_if); + + /* MT2060 IF1 */ + req.addr = AF9015_EEPROM_MT2060_IF1H + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_config.mt2060_if1[i] = val << 8; + req.addr = AF9015_EEPROM_MT2060_IF1L + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_config.mt2060_if1[i] += val; + deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i, + af9015_config.mt2060_if1[i]); + + /* tuner */ + req.addr = AF9015_EEPROM_TUNER_ID1 + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + switch (val) { + case AF9013_TUNER_ENV77H11D5: + case AF9013_TUNER_MT2060: + case AF9013_TUNER_QT1010: + case AF9013_TUNER_UNKNOWN: + case AF9013_TUNER_MT2060_2: + case AF9013_TUNER_TDA18271: + case AF9013_TUNER_QT1010A: + case AF9013_TUNER_TDA18218: + af9015_af9013_config[i].rf_spec_inv = 1; + break; + case AF9013_TUNER_MXL5003D: + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + case AF9013_TUNER_MXL5007T: + af9015_af9013_config[i].rf_spec_inv = 0; + break; + case AF9013_TUNER_MC44S803: + af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO; + af9015_af9013_config[i].rf_spec_inv = 1; + break; + default: + warn("tuner id:%d not supported, please report!", val); + return -ENODEV; + }; + + af9015_af9013_config[i].tuner = val; + deb_info("%s: [%d] tuner id:%d\n", __func__, i, val); + } + +error: + if (ret) + err("eeprom read failed:%d", ret); + + /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM + content :-( Override some wrong values here. Ditto for the + AVerTV Red HD+ (A850T) device. */ + if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA && + ((le16_to_cpu(udev->descriptor.idProduct) == + USB_PID_AVERMEDIA_A850) || + (le16_to_cpu(udev->descriptor.idProduct) == + USB_PID_AVERMEDIA_A850T))) { + deb_info("%s: AverMedia A850: overriding config\n", __func__); + /* disable dual mode */ + af9015_config.dual_mode = 0; + /* disable 2nd adapter */ + for (i = 0; i < af9015_properties_count; i++) + af9015_properties[i].num_adapters = 1; + + /* set correct IF */ + af9015_af9013_config[0].tuner_if = 4570; + } + + return ret; +} + +static int af9015_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int ret; + u8 reply; + struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; + + ret = af9015_rw_udev(udev, &req); + if (ret) + return ret; + + deb_info("%s: reply:%02x\n", __func__, reply); + if (reply == 0x02) + *cold = 0; + else + *cold = 1; + + return ret; +} + +static int af9015_rc_query(struct dvb_usb_device *d) +{ + struct af9015_state *priv = d->priv; + int ret; + u8 buf[17]; + + /* read registers needed to detect remote controller code */ + ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); + if (ret) + goto error; + + /* If any of these are non-zero, assume invalid data */ + if (buf[1] || buf[2] || buf[3]) + return ret; + + /* Check for repeat of previous code */ + if ((priv->rc_repeat != buf[6] || buf[0]) && + !memcmp(&buf[12], priv->rc_last, 4)) { + deb_rc("%s: key repeated\n", __func__); + rc_keydown(d->rc_dev, priv->rc_keycode, 0); + priv->rc_repeat = buf[6]; + return ret; + } + + /* Only process key if canary killed */ + if (buf[16] != 0xff && buf[0] != 0x01) { + deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__, + buf[12], buf[13], buf[14], buf[15]); + + /* Reset the canary */ + ret = af9015_write_reg(d, 0x98e9, 0xff); + if (ret) + goto error; + + /* Remember this key */ + memcpy(priv->rc_last, &buf[12], 4); + if (buf[14] == (u8) ~buf[15]) { + if (buf[12] == (u8) ~buf[13]) { + /* NEC */ + priv->rc_keycode = buf[12] << 8 | buf[14]; + } else { + /* NEC extended*/ + priv->rc_keycode = buf[12] << 16 | + buf[13] << 8 | buf[14]; + } + } else { + /* 32 bit NEC */ + priv->rc_keycode = buf[12] << 24 | buf[13] << 16 | + buf[14] << 8 | buf[15]; + } + rc_keydown(d->rc_dev, priv->rc_keycode, 0); + } else { + deb_rc("%s: no key press\n", __func__); + /* Invalidate last keypress */ + /* Not really needed, but helps with debug */ + priv->rc_last[2] = priv->rc_last[3]; + } + + priv->rc_repeat = buf[6]; + +error: + if (ret) + err("%s: failed:%d", __func__, ret); + + return ret; +} + +/* init 2nd I2C adapter */ +static int af9015_i2c_init(struct dvb_usb_device *d) +{ + int ret; + struct af9015_state *state = d->priv; + deb_info("%s:\n", __func__); + + strncpy(state->i2c_adap.name, d->desc->name, + sizeof(state->i2c_adap.name)); + state->i2c_adap.algo = d->props.i2c_algo; + state->i2c_adap.algo_data = NULL; + state->i2c_adap.dev.parent = &d->udev->dev; + + i2c_set_adapdata(&state->i2c_adap, d); + + ret = i2c_add_adapter(&state->i2c_adap); + if (ret < 0) + err("could not add i2c adapter"); + + return ret; +} + +static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct af9015_state *state = adap->dev->priv; + struct i2c_adapter *i2c_adap; + + if (adap->id == 0) { + /* select I2C adapter */ + i2c_adap = &adap->dev->i2c_adap; + + deb_info("%s: init I2C\n", __func__); + ret = af9015_i2c_init(adap->dev); + } else { + /* select I2C adapter */ + i2c_adap = &state->i2c_adap; + + /* copy firmware to 2nd demodulator */ + if (af9015_config.dual_mode) { + ret = af9015_copy_firmware(adap->dev); + if (ret) { + err("firmware copy to 2nd frontend " \ + "failed, will disable it"); + af9015_config.dual_mode = 0; + return -ENODEV; + } + } else { + return -ENODEV; + } + } + + /* attach demodulator */ + adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], + i2c_adap); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static struct mt2060_config af9015_mt2060_config = { + .i2c_address = 0xc0, + .clock_out = 0, +}; + +static struct qt1010_config af9015_qt1010_config = { + .i2c_address = 0xc4, +}; + +static struct tda18271_config af9015_tda18271_config = { + .gate = TDA18271_GATE_DIGITAL, + .small_i2c = TDA18271_16_BYTE_CHUNK_INIT, +}; + +static struct mxl5005s_config af9015_mxl5003_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_DEFAULT, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static struct mxl5005s_config af9015_mxl5005_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_OFF, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static struct mc44s803_config af9015_mc44s803_config = { + .i2c_address = 0xc0, + .dig_out = 1, +}; + +static struct tda18218_config af9015_tda18218_config = { + .i2c_address = 0xc0, + .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ +}; + +static struct mxl5007t_config af9015_mxl5007t_config = { + .xtal_freq_hz = MxL_XTAL_24_MHZ, + .if_freq_hz = MxL_IF_4_57_MHZ, +}; + +static int af9015_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct af9015_state *state = adap->dev->priv; + struct i2c_adapter *i2c_adap; + int ret; + deb_info("%s:\n", __func__); + + /* select I2C adapter */ + if (adap->id == 0) + i2c_adap = &adap->dev->i2c_adap; + else + i2c_adap = &state->i2c_adap; + + switch (af9015_af9013_config[adap->id].tuner) { + case AF9013_TUNER_MT2060: + case AF9013_TUNER_MT2060_2: + ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap, + &af9015_mt2060_config, + af9015_config.mt2060_if1[adap->id]) + == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_QT1010: + case AF9013_TUNER_QT1010A: + ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap, + &af9015_qt1010_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_TDA18271: + ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap, + &af9015_tda18271_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_TDA18218: + ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap, + &af9015_tda18218_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5003D: + ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, + &af9015_mxl5003_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, + &af9015_mxl5005_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_ENV77H11D5: + ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap, + DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MC44S803: + ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap, + &af9015_mc44s803_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5007T: + ret = dvb_attach(mxl5007t_attach, adap->fe, i2c_adap, + 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_UNKNOWN: + default: + ret = -ENODEV; + err("Unknown tuner id:%d", + af9015_af9013_config[adap->id].tuner); + } + return ret; +} + +static struct usb_device_id af9015_usb_table[] = { +/* 0 */{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, + {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, + {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, + {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, +/* 5 */{USB_DEVICE(USB_VID_VISIONPLUS, + USB_PID_TINYTWIN)}, + {USB_DEVICE(USB_VID_VISIONPLUS, + USB_PID_AZUREWAVE_AD_TU700)}, + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, +/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, + {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, + {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, +/* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, + {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, +/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, + {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, +/* 25 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)}, + {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, +/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)}, + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)}, + {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)}, +/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, + {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, + {0}, +}; +MODULE_DEVICE_TABLE(usb, af9015_usb_table); + +#define AF9015_RC_INTERVAL 500 +static struct dvb_usb_device_properties af9015_properties[] = { + { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = af9015_download_firmware, + .firmware = "dvb-usb-af9015.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct af9015_state), + + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + }, + }, + { + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = + TS_USB20_FRAME_SIZE, + } + } + }, + } + }, + + .identify_state = af9015_identify_state, + + .rc.core = { + .protocol = RC_TYPE_NEC, + .module_name = "af9015", + .rc_query = af9015_rc_query, + .rc_interval = AF9015_RC_INTERVAL, + .allowed_protos = RC_TYPE_NEC, + }, + + .i2c_algo = &af9015_i2c_algo, + + .num_device_descs = 12, /* check max from dvb-usb.h */ + .devices = { + { + .name = "Afatech AF9015 DVB-T USB2.0 stick", + .cold_ids = {&af9015_usb_table[0], + &af9015_usb_table[1], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Leadtek WinFast DTV Dongle Gold", + .cold_ids = {&af9015_usb_table[2], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Pinnacle PCTV 71e", + .cold_ids = {&af9015_usb_table[3], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "KWorld PlusTV Dual DVB-T Stick " \ + "(DVB-T 399U)", + .cold_ids = {&af9015_usb_table[4], + &af9015_usb_table[25], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "DigitalNow TinyTwin DVB-T Receiver", + .cold_ids = {&af9015_usb_table[5], + &af9015_usb_table[28], + &af9015_usb_table[36], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "TwinHan AzureWave AD-TU700(704J)", + .cold_ids = {&af9015_usb_table[6], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "TerraTec Cinergy T USB XE", + .cold_ids = {&af9015_usb_table[7], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "KWorld PlusTV Dual DVB-T PCI " \ + "(DVB-T PC160-2T)", + .cold_ids = {&af9015_usb_table[8], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "AVerMedia AVerTV DVB-T Volar X", + .cold_ids = {&af9015_usb_table[9], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "TerraTec Cinergy T Stick RC", + .cold_ids = {&af9015_usb_table[33], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "TerraTec Cinergy T Stick Dual RC", + .cold_ids = {&af9015_usb_table[34], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "AverMedia AVerTV Red HD+ (A850T)", + .cold_ids = {&af9015_usb_table[35], NULL}, + .warm_ids = {NULL}, + }, + } + }, { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = af9015_download_firmware, + .firmware = "dvb-usb-af9015.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct af9015_state), + + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + }, + }, + { + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = + TS_USB20_FRAME_SIZE, + } + } + }, + } + }, + + .identify_state = af9015_identify_state, + + .rc.core = { + .protocol = RC_TYPE_NEC, + .module_name = "af9015", + .rc_query = af9015_rc_query, + .rc_interval = AF9015_RC_INTERVAL, + .allowed_protos = RC_TYPE_NEC, + }, + + .i2c_algo = &af9015_i2c_algo, + + .num_device_descs = 9, /* check max from dvb-usb.h */ + .devices = { + { + .name = "Xtensions XD-380", + .cold_ids = {&af9015_usb_table[10], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "MSI DIGIVOX Duo", + .cold_ids = {&af9015_usb_table[11], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Fujitsu-Siemens Slim Mobile USB DVB-T", + .cold_ids = {&af9015_usb_table[12], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Telestar Starstick 2", + .cold_ids = {&af9015_usb_table[13], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "AVerMedia A309", + .cold_ids = {&af9015_usb_table[14], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "MSI Digi VOX mini III", + .cold_ids = {&af9015_usb_table[15], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "KWorld USB DVB-T TV Stick II " \ + "(VS-DVB-T 395U)", + .cold_ids = {&af9015_usb_table[16], + &af9015_usb_table[17], + &af9015_usb_table[18], + &af9015_usb_table[31], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "TrekStor DVB-T USB Stick", + .cold_ids = {&af9015_usb_table[19], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "AverMedia AVerTV Volar Black HD " \ + "(A850)", + .cold_ids = {&af9015_usb_table[20], NULL}, + .warm_ids = {NULL}, + }, + } + }, { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = af9015_download_firmware, + .firmware = "dvb-usb-af9015.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct af9015_state), + + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + }, + }, + { + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = + TS_USB20_FRAME_SIZE, + } + } + }, + } + }, + + .identify_state = af9015_identify_state, + + .rc.core = { + .protocol = RC_TYPE_NEC, + .module_name = "af9015", + .rc_query = af9015_rc_query, + .rc_interval = AF9015_RC_INTERVAL, + .allowed_protos = RC_TYPE_NEC, + }, + + .i2c_algo = &af9015_i2c_algo, + + .num_device_descs = 9, /* check max from dvb-usb.h */ + .devices = { + { + .name = "AverMedia AVerTV Volar GPS 805 (A805)", + .cold_ids = {&af9015_usb_table[21], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \ + "V3.0", + .cold_ids = {&af9015_usb_table[22], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "KWorld Digial MC-810", + .cold_ids = {&af9015_usb_table[23], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Genius TVGo DVB-T03", + .cold_ids = {&af9015_usb_table[24], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "KWorld PlusTV DVB-T PCI Pro Card " \ + "(DVB-T PC160-T)", + .cold_ids = {&af9015_usb_table[26], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Sveon STV20 Tuner USB DVB-T HDTV", + .cold_ids = {&af9015_usb_table[27], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Leadtek WinFast DTV2000DS", + .cold_ids = {&af9015_usb_table[29], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "KWorld USB DVB-T Stick Mobile " \ + "(UB383-T)", + .cold_ids = {&af9015_usb_table[30], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "AverMedia AVerTV Volar M (A815Mac)", + .cold_ids = {&af9015_usb_table[32], NULL}, + .warm_ids = {NULL}, + }, + } + }, +}; + +static int af9015_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret = 0; + struct dvb_usb_device *d = NULL; + struct usb_device *udev = interface_to_usbdev(intf); + u8 i; + + deb_info("%s: interface:%d\n", __func__, + intf->cur_altsetting->desc.bInterfaceNumber); + + /* interface 0 is used by DVB-T receiver and + interface 1 is for remote controller (HID) */ + if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { + ret = af9015_read_config(udev); + if (ret) + return ret; + + for (i = 0; i < af9015_properties_count; i++) { + ret = dvb_usb_device_init(intf, &af9015_properties[i], + THIS_MODULE, &d, adapter_nr); + if (!ret) + break; + if (ret != -ENODEV) + return ret; + } + if (ret) + return ret; + + if (d) + ret = af9015_init(d); + } + + return ret; +} + +static void af9015_i2c_exit(struct dvb_usb_device *d) +{ + struct af9015_state *state = d->priv; + deb_info("%s:\n", __func__); + + /* remove 2nd I2C adapter */ + if (d->state & DVB_USB_STATE_I2C) + i2c_del_adapter(&state->i2c_adap); +} + +static void af9015_usb_device_exit(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + deb_info("%s:\n", __func__); + + /* remove 2nd I2C adapter */ + if (d != NULL && d->desc != NULL) + af9015_i2c_exit(d); + + dvb_usb_device_exit(intf); +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver af9015_usb_driver = { + .name = "dvb_usb_af9015", + .probe = af9015_usb_probe, + .disconnect = af9015_usb_device_exit, + .id_table = af9015_usb_table, +}; + +/* module stuff */ +static int __init af9015_usb_module_init(void) +{ + int ret; + ret = usb_register(&af9015_usb_driver); + if (ret) + err("module init failed:%d", ret); + + return ret; +} + +static void __exit af9015_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&af9015_usb_driver); +} + +module_init(af9015_usb_module_init); +module_exit(af9015_usb_module_exit); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9015.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9015.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9015.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/af9015.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,125 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _DVB_USB_AF9015_H_ +#define _DVB_USB_AF9015_H_ + +#define DVB_USB_LOG_PREFIX "af9015" +#include "dvb-usb.h" + +#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) +#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) +#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args) +#define deb_reg(args...) dprintk(dvb_usb_af9015_debug, 0x08, args) +#define deb_i2c(args...) dprintk(dvb_usb_af9015_debug, 0x10, args) +#define deb_fw(args...) dprintk(dvb_usb_af9015_debug, 0x20, args) + +#define AF9015_I2C_EEPROM 0xa0 +#define AF9015_I2C_DEMOD 0x38 +#define AF9015_USB_TIMEOUT 2000 + +/* EEPROM locations */ +#define AF9015_EEPROM_IR_MODE 0x18 +#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34 +#define AF9015_EEPROM_TS_MODE 0x31 +#define AF9015_EEPROM_DEMOD2_I2C 0x32 + +#define AF9015_EEPROM_SAW_BW1 0x35 +#define AF9015_EEPROM_XTAL_TYPE1 0x36 +#define AF9015_EEPROM_SPEC_INV1 0x37 +#define AF9015_EEPROM_IF1L 0x38 +#define AF9015_EEPROM_IF1H 0x39 +#define AF9015_EEPROM_MT2060_IF1L 0x3a +#define AF9015_EEPROM_MT2060_IF1H 0x3b +#define AF9015_EEPROM_TUNER_ID1 0x3c + +#define AF9015_EEPROM_SAW_BW2 0x45 +#define AF9015_EEPROM_XTAL_TYPE2 0x46 +#define AF9015_EEPROM_SPEC_INV2 0x47 +#define AF9015_EEPROM_IF2L 0x48 +#define AF9015_EEPROM_IF2H 0x49 +#define AF9015_EEPROM_MT2060_IF2L 0x4a +#define AF9015_EEPROM_MT2060_IF2H 0x4b +#define AF9015_EEPROM_TUNER_ID2 0x4c + +#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1) + +struct req_t { + u8 cmd; /* [0] */ + /* seq */ /* [1] */ + u8 i2c_addr; /* [2] */ + u16 addr; /* [3|4] */ + u8 mbox; /* [5] */ + u8 addr_len; /* [6] */ + u8 data_len; /* [7] */ + u8 *data; +}; + +enum af9015_cmd { + GET_CONFIG = 0x10, + DOWNLOAD_FIRMWARE = 0x11, + BOOT = 0x13, + READ_MEMORY = 0x20, + WRITE_MEMORY = 0x21, + READ_WRITE_I2C = 0x22, + COPY_FIRMWARE = 0x23, + RECONNECT_USB = 0x5a, + WRITE_VIRTUAL_MEMORY = 0x26, + GET_IR_CODE = 0x27, + READ_I2C, + WRITE_I2C, +}; + +enum af9015_ir_mode { + AF9015_IR_MODE_DISABLED = 0, + AF9015_IR_MODE_HID, + AF9015_IR_MODE_RLC, + AF9015_IR_MODE_RC6, + AF9015_IR_MODE_POLLING, /* just guess */ +}; + +struct af9015_state { + struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */ + u8 rc_repeat; + u32 rc_keycode; + u8 rc_last[4]; +}; + +struct af9015_config { + u8 dual_mode:1; + u16 mt2060_if1[2]; + u16 firmware_size; + u16 firmware_checksum; + u32 eeprom_sum; +}; + +enum af9015_remote { + AF9015_REMOTE_NONE = 0, +/* 1 */ AF9015_REMOTE_A_LINK_DTU_M, + AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + AF9015_REMOTE_MYGICTV_U718, + AF9015_REMOTE_DIGITTRADE_DVB_T, +/* 5 */ AF9015_REMOTE_AVERMEDIA_KS, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/anysee.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/anysee.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/anysee.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/anysee.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,990 @@ +/* + * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * TODO: + * - add smart card reader support for Conditional Access (CA) + * + * Card reader in Anysee is nothing more than ISO 7816 card reader. + * There is no hardware CAM in any Anysee device sold. + * In my understanding it should be implemented by making own module + * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This + * module registers serial interface that can be used to communicate + * with any ISO 7816 smart card. + * + * Any help according to implement serial smart card reader support + * is highly welcome! + */ + +#include "anysee.h" +#include "tda1002x.h" +#include "mt352.h" +#include "mt352_priv.h" +#include "zl10353.h" +#include "tda18212.h" +#include "cx24116.h" +#include "stv0900.h" +#include "stv6110.h" +#include "isl6423.h" + +/* debug */ +static int dvb_usb_anysee_debug; +module_param_named(debug, dvb_usb_anysee_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +static int dvb_usb_anysee_delsys; +module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644); +MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)"); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static DEFINE_MUTEX(anysee_usb_mutex); + +static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, + u8 *rbuf, u8 rlen) +{ + struct anysee_state *state = d->priv; + int act_len, ret; + u8 buf[64]; + + memcpy(&buf[0], sbuf, slen); + buf[60] = state->seq++; + + if (mutex_lock_interruptible(&anysee_usb_mutex) < 0) + return -EAGAIN; + + /* We need receive one message more after dvb_usb_generic_rw due + to weird transaction flow, which is 1 x send + 2 x receive. */ + ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); + + if (!ret) { + /* receive 2nd answer */ + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf), + &act_len, 2000); + if (ret) + err("%s: recv bulk message failed: %d", __func__, ret); + else { + deb_xfer("<<< "); + debug_dump(buf, act_len, deb_xfer); + } + } + + /* read request, copy returned data to return buf */ + if (!ret && rbuf && rlen) + memcpy(rbuf, buf, rlen); + + mutex_unlock(&anysee_usb_mutex); + + return ret; +} + +static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val) +{ + u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01}; + int ret; + ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1); + deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val); + return ret; +} + +static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val) +{ + u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val}; + deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +/* write single register with mask */ +static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, + u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = anysee_read_reg(d, reg, &tmp); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return anysee_write_reg(d, reg, val); +} + +static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) +{ + u8 buf[] = {CMD_GET_HW_INFO}; + return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3); +} + +static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00}; + deb_info("%s: onoff:%02x\n", __func__, onoff); + return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0); +} + +static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval) +{ + u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval}; + deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) +{ + u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff}; + deb_info("%s: onoff:%02x\n", __func__, onoff); + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); +} + +static int anysee_init(struct dvb_usb_device *d) +{ + int ret; + /* LED light */ + ret = anysee_led_ctrl(d, 0x01, 0x03); + if (ret) + return ret; + + /* enable IR */ + ret = anysee_ir_ctrl(d, 1); + if (ret) + return ret; + + return 0; +} + +/* I2C */ +static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, inc, i = 0; + u8 buf[52]; /* 4 + 48 (I2C WR USB command header + I2C WR max) */ + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].len > 2 || msg[i+1].len > 60) { + ret = -EOPNOTSUPP; + break; + } + buf[0] = CMD_I2C_READ; + buf[1] = (msg[i].addr << 1) | 0x01; + buf[2] = msg[i].buf[0]; + buf[3] = msg[i].buf[1]; + buf[4] = msg[i].len-1; + buf[5] = msg[i+1].len; + ret = anysee_ctrl_msg(d, buf, 6, msg[i+1].buf, + msg[i+1].len); + inc = 2; + } else { + if (msg[i].len > 48) { + ret = -EOPNOTSUPP; + break; + } + buf[0] = CMD_I2C_WRITE; + buf[1] = (msg[i].addr << 1); + buf[2] = msg[i].len; + buf[3] = 0x01; + memcpy(&buf[4], msg[i].buf, msg[i].len); + ret = anysee_ctrl_msg(d, buf, 4 + msg[i].len, NULL, 0); + inc = 1; + } + if (ret) + break; + + i += inc; + } + + mutex_unlock(&d->i2c_mutex); + + return ret ? ret : i; +} + +static u32 anysee_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm anysee_i2c_algo = { + .master_xfer = anysee_master_xfer, + .functionality = anysee_i2c_func, +}; + +static int anysee_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 }; + static u8 reset[] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; + static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +/* Callbacks for DVB USB */ +static struct tda10023_config anysee_tda10023_config = { + .demod_address = (0x1a >> 1), + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, + .deltaf = 0xfeeb, +}; + +static struct mt352_config anysee_mt352_config = { + .demod_address = (0x1e >> 1), + .demod_init = anysee_mt352_demod_init, +}; + +static struct zl10353_config anysee_zl10353_config = { + .demod_address = (0x1e >> 1), + .parallel_ts = 1, +}; + +static struct zl10353_config anysee_zl10353_tda18212_config2 = { + .demod_address = (0x1e >> 1), + .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, + .no_tuner = 1, + .if2 = 41500, +}; + +static struct zl10353_config anysee_zl10353_tda18212_config = { + .demod_address = (0x18 >> 1), + .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, + .no_tuner = 1, + .if2 = 41500, +}; + +static struct tda10023_config anysee_tda10023_tda18212_config = { + .demod_address = (0x1a >> 1), + .xtal = 16000000, + .pll_m = 12, + .pll_p = 3, + .pll_n = 1, + .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, + .deltaf = 0xba02, +}; + +static struct tda18212_config anysee_tda18212_config = { + .i2c_address = (0xc0 >> 1), + .if_dvbt_6 = 4150, + .if_dvbt_7 = 4150, + .if_dvbt_8 = 4150, + .if_dvbc = 5000, +}; + +static struct cx24116_config anysee_cx24116_config = { + .demod_address = (0xaa >> 1), + .mpg_clk_pos_pol = 0x00, + .i2c_wr_max = 48, +}; + +static struct stv0900_config anysee_stv0900_config = { + .demod_address = (0xd0 >> 1), + .demod_mode = 0, + .xtal = 8000000, + .clkmode = 3, + .diseqc_mode = 2, + .tun1_maddress = 0, + .tun1_adc = 1, /* 1 Vpp */ + .path1_mode = 3, +}; + +static struct stv6110_config anysee_stv6110_config = { + .i2c_address = (0xc0 >> 1), + .mclk = 16000000, + .clk_div = 1, +}; + +static struct isl6423_config anysee_isl6423_config = { + .current_max = SEC_CURRENT_800m, + .curlim = SEC_CURRENT_LIM_OFF, + .mod_extern = 1, + .addr = (0x10 >> 1), +}; + +/* + * New USB device strings: Mfr=1, Product=2, SerialNumber=0 + * Manufacturer: AMT.CO.KR + * + * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=???????? + * PCB: ? + * parts: DNOS404ZH102A(MT352, DTT7579(?)) + * + * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)" + * PCB: PCB 507T (rev1.61) + * parts: DNOS404ZH103A(ZL10353, DTT7579(?)) + * OEA=0a OEB=00 OEC=00 OED=ff OEE=00 + * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00 + * + * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee" + * PCB: 507CD (rev1.1) + * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01 + * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe + * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01 + * IOD[0] ZL10353 1=enabled + * IOA[7] TS 0=enabled + * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not) + * + * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)" + * PCB: 507DC (rev0.2) + * parts: TDA10023, DTOS403IH102B TM, CST56I01 + * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe + * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01 + * IOD[0] TDA10023 1=enabled + * + * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)" + * PCB: 507SI (rev2.1) + * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe + * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01 + * IOD[0] CX24116 1=enabled + * + * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" + * PCB: 507FA (rev0.4) + * parts: TDA10023, DTOS403IH102B TM, TDA8024 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff + * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 + * IOD[5] TDA10023 1=enabled + * IOE[0] tuner 1=enabled + * + * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)" + * PCB: 507FA (rev1.1) + * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024 + * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff + * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0 + * DVB-C: + * IOD[5] TDA10023 1=enabled + * IOE[0] tuner 1=enabled + * DVB-T: + * IOD[0] ZL10353 1=enabled + * IOE[0] tuner 0=enabled + * tuner is behind ZL10353 I2C-gate + * + * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" + * PCB: 508TC (rev0.6) + * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[4] TDA18212 1=enabled + * DVB-C: + * IOD[6] ZL10353 0=disabled + * IOD[5] TDA10023 1=enabled + * IOE[0] IF 1=enabled + * DVB-T: + * IOD[5] TDA10023 0=disabled + * IOD[6] ZL10353 1=enabled + * IOE[0] IF 0=enabled + * + * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)" + * PCB: 508S2 (rev0.7) + * parts: DNBU10512IST(STV0903, STV6110), ISL6423 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] STV0903 1=enabled + * + * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)" + * PCB: 508PTC (rev0.5) + * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[4] TDA18212 1=enabled + * DVB-C: + * IOD[6] ZL10353 0=disabled + * IOD[5] TDA10023 1=enabled + * IOE[0] IF 1=enabled + * DVB-T: + * IOD[5] TDA10023 0=disabled + * IOD[6] ZL10353 1=enabled + * IOE[0] IF 0=enabled + * + * E7 S2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" + * PCB: 508PS2 (rev0.4) + * parts: DNBU10512IST(STV0903, STV6110), ISL6423 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] STV0903 1=enabled + */ + +static int anysee_frontend_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct anysee_state *state = adap->dev->priv; + u8 hw_info[3]; + u8 tmp; + struct i2c_msg msg[2] = { + { + .addr = anysee_tda18212_config.i2c_address, + .flags = 0, + .len = 1, + .buf = "\x00", + }, { + .addr = anysee_tda18212_config.i2c_address, + .flags = I2C_M_RD, + .len = 1, + .buf = &tmp, + } + }; + + /* Check which hardware we have. + * We must do this call two times to get reliable values (hw bug). + */ + ret = anysee_get_hw_info(adap->dev, hw_info); + if (ret) + goto error; + + ret = anysee_get_hw_info(adap->dev, hw_info); + if (ret) + goto error; + + /* Meaning of these info bytes are guessed. */ + info("firmware version:%d.%d hardware id:%d", + hw_info[1], hw_info[2], hw_info[0]); + + state->hw = hw_info[0]; + + switch (state->hw) { + case ANYSEE_HW_507T: /* 2 */ + /* E30 */ + + /* attach demod */ + adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config, + &adap->dev->i2c_adap); + if (adap->fe) + break; + + /* attach demod */ + adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &adap->dev->i2c_adap); + + break; + case ANYSEE_HW_507CD: /* 6 */ + /* E30 Plus */ + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* enable transport stream on IOA[7] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (0 << 7), 0x80); + if (ret) + goto error; + + /* attach demod */ + adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &adap->dev->i2c_adap); + + break; + case ANYSEE_HW_507DC: /* 10 */ + /* E30 C Plus */ + + /* enable DVB-C demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* attach demod */ + adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config, + &adap->dev->i2c_adap, 0x48); + + break; + case ANYSEE_HW_507SI: /* 11 */ + /* E30 S2 Plus */ + + /* enable DVB-S/S2 demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* attach demod */ + adap->fe = dvb_attach(cx24116_attach, &anysee_cx24116_config, + &adap->dev->i2c_adap); + + break; + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + /* enable tuner on IOE[4] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); + if (ret) + goto error; + + /* probe TDA18212 */ + tmp = 0; + ret = i2c_transfer(&adap->dev->i2c_adap, msg, 2); + if (ret == 2 && tmp == 0xc7) + deb_info("%s: TDA18212 found\n", __func__); + else + tmp = 0; + + /* disable tuner on IOE[4] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10); + if (ret) + goto error; + + if (dvb_usb_anysee_delsys) { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), + 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), + 0x01); + if (ret) + goto error; + + /* attach demod */ + if (tmp == 0xc7) { + /* TDA18212 config */ + adap->fe = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config2, + &adap->dev->i2c_adap); + } else { + /* PLL config */ + adap->fe = dvb_attach(zl10353_attach, + &anysee_zl10353_config, + &adap->dev->i2c_adap); + } + } else { + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), + 0x01); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); + if (ret) + goto error; + + /* attach demod */ + if (tmp == 0xc7) { + /* TDA18212 config */ + adap->fe = dvb_attach(tda10023_attach, + &anysee_tda10023_tda18212_config, + &adap->dev->i2c_adap, 0x48); + } else { + /* PLL config */ + adap->fe = dvb_attach(tda10023_attach, + &anysee_tda10023_config, + &adap->dev->i2c_adap, 0x48); + } + } + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + /* enable transport stream on IOA[7] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); + if (ret) + goto error; + + if (dvb_usb_anysee_delsys) { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), + 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), + 0x40); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), + 0x01); + if (ret) + goto error; + + /* attach demod */ + adap->fe = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config, + &adap->dev->i2c_adap); + } else { + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), + 0x40); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), + 0x01); + if (ret) + goto error; + + /* attach demod */ + adap->fe = dvb_attach(tda10023_attach, + &anysee_tda10023_tda18212_config, + &adap->dev->i2c_adap, 0x48); + } + + break; + case ANYSEE_HW_508S2: /* 19 */ + case ANYSEE_HW_508PS2: /* 22 */ + /* E7 S2 */ + /* E7 PS2 */ + + /* enable transport stream on IOA[7] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); + if (ret) + goto error; + + /* enable DVB-S/S2 demod on IOE[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); + if (ret) + goto error; + + /* attach demod */ + adap->fe = dvb_attach(stv0900_attach, &anysee_stv0900_config, + &adap->dev->i2c_adap, 0); + + break; + } + + if (!adap->fe) { + /* we have no frontend :-( */ + ret = -ENODEV; + err("Unsupported Anysee version. " \ + "Please report the ."); + } +error: + return ret; +} + +static int anysee_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct anysee_state *state = adap->dev->priv; + struct dvb_frontend *fe; + int ret; + deb_info("%s:\n", __func__); + + switch (state->hw) { + case ANYSEE_HW_507T: /* 2 */ + /* E30 */ + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1), + NULL, DVB_PLL_THOMSON_DTT7579); + + break; + case ANYSEE_HW_507CD: /* 6 */ + /* E30 Plus */ + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1), + &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579); + + break; + case ANYSEE_HW_507DC: /* 10 */ + /* E30 C Plus */ + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1), + &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + + break; + case ANYSEE_HW_507SI: /* 11 */ + /* E30 S2 Plus */ + + /* attach LNB controller */ + fe = dvb_attach(isl6423_attach, adap->fe, &adap->dev->i2c_adap, + &anysee_isl6423_config); + + break; + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + if (dvb_usb_anysee_delsys) { + /* enable DVB-T tuner on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), + 0x01); + if (ret) + goto error; + } else { + /* enable DVB-C tuner on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), + 0x01); + if (ret) + goto error; + } + + /* Try first attach TDA18212 silicon tuner on IOE[4], if that + * fails attach old simple PLL. */ + + /* enable tuner on IOE[4] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); + if (ret) + goto error; + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap, + &anysee_tda18212_config); + if (fe) + break; + + /* disable tuner on IOE[4] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10); + if (ret) + goto error; + + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1), + &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + /* enable tuner on IOE[4] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); + if (ret) + goto error; + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap, + &anysee_tda18212_config); + + break; + case ANYSEE_HW_508S2: /* 19 */ + case ANYSEE_HW_508PS2: /* 22 */ + /* E7 S2 */ + /* E7 PS2 */ + + /* attach tuner */ + fe = dvb_attach(stv6110_attach, adap->fe, + &anysee_stv6110_config, &adap->dev->i2c_adap); + + if (fe) { + /* attach LNB controller */ + fe = dvb_attach(isl6423_attach, adap->fe, + &adap->dev->i2c_adap, &anysee_isl6423_config); + } + + break; + default: + fe = NULL; + } + + if (fe) + ret = 0; + else + ret = -ENODEV; + +error: + return ret; +} + +static int anysee_rc_query(struct dvb_usb_device *d) +{ + u8 buf[] = {CMD_GET_IR_CODE}; + u8 ircode[2]; + int ret; + + /* Remote controller is basic NEC using address byte 0x08. + Anysee device RC query returns only two bytes, status and code, + address byte is dropped. Also it does not return any value for + NEC RCs having address byte other than 0x08. Due to that, we + cannot use that device as standard NEC receiver. + It could be possible make hack which reads whole code directly + from device memory... */ + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode)); + if (ret) + return ret; + + if (ircode[0]) { + deb_rc("%s: key pressed %02x\n", __func__, ircode[1]); + rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0); + } + + return 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties anysee_properties; + +static int anysee_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + struct usb_host_interface *alt; + int ret; + + /* There is one interface with two alternate settings. + Alternate setting 0 is for bulk transfer. + Alternate setting 1 is for isochronous transfer. + We use bulk transfer (alternate setting 0). */ + if (intf->num_altsetting < 1) + return -ENODEV; + + /* + * Anysee is always warm (its USB-bridge, Cypress FX2, uploads + * firmware from eeprom). If dvb_usb_device_init() succeeds that + * means d is a valid pointer. + */ + ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d, + adapter_nr); + if (ret) + return ret; + + alt = usb_altnum_to_altsetting(intf, 0); + if (alt == NULL) { + deb_info("%s: no alt found!\n", __func__); + return -ENODEV; + } + + ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + if (ret) + return ret; + + return anysee_init(d); +} + +static struct usb_device_id anysee_table[] = { + { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, + { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, anysee_table); + +static struct dvb_usb_device_properties anysee_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = sizeof(struct anysee_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = anysee_streaming_ctrl, + .frontend_attach = anysee_frontend_attach, + .tuner_attach = anysee_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = (16*512), + } + } + }, + } + }, + + .rc.core = { + .rc_codes = RC_MAP_ANYSEE, + .protocol = RC_TYPE_OTHER, + .module_name = "anysee", + .rc_query = anysee_rc_query, + .rc_interval = 250, /* windows driver uses 500ms */ + }, + + .i2c_algo = &anysee_i2c_algo, + + .generic_bulk_ctrl_endpoint = 1, + + .num_device_descs = 1, + .devices = { + { + .name = "Anysee DVB USB2.0", + .cold_ids = {NULL}, + .warm_ids = {&anysee_table[0], + &anysee_table[1], NULL}, + }, + } +}; + +static struct usb_driver anysee_driver = { + .name = "dvb_usb_anysee", + .probe = anysee_probe, + .disconnect = dvb_usb_device_exit, + .id_table = anysee_table, +}; + +/* module stuff */ +static int __init anysee_module_init(void) +{ + int ret; + + ret = usb_register(&anysee_driver); + if (ret) + err("%s: usb_register failed. Error number %d", __func__, ret); + + return ret; +} + +static void __exit anysee_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&anysee_driver); +} + +module_init(anysee_module_init); +module_exit(anysee_module_exit); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/anysee.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/anysee.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/anysee.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/anysee.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,325 @@ +/* + * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * TODO: + * - add smart card reader support for Conditional Access (CA) + * + * Card reader in Anysee is nothing more than ISO 7816 card reader. + * There is no hardware CAM in any Anysee device sold. + * In my understanding it should be implemented by making own module + * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This + * module registers serial interface that can be used to communicate + * with any ISO 7816 smart card. + * + * Any help according to implement serial smart card reader support + * is highly welcome! + */ + +#ifndef _DVB_USB_ANYSEE_H_ +#define _DVB_USB_ANYSEE_H_ + +#define DVB_USB_LOG_PREFIX "anysee" +#include "dvb-usb.h" + +#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) +#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args) +#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args) +#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args) +#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args) + +enum cmd { + CMD_I2C_READ = 0x33, + CMD_I2C_WRITE = 0x31, + CMD_REG_READ = 0xb0, + CMD_REG_WRITE = 0xb1, + CMD_STREAMING_CTRL = 0x12, + CMD_LED_AND_IR_CTRL = 0x16, + CMD_GET_IR_CODE = 0x41, + CMD_GET_HW_INFO = 0x19, + CMD_SMARTCARD = 0x34, +}; + +struct anysee_state { + u8 hw; /* PCB ID */ + u8 seq; +}; + +#define ANYSEE_HW_507T 2 /* E30 */ +#define ANYSEE_HW_507CD 6 /* E30 Plus */ +#define ANYSEE_HW_507DC 10 /* E30 C Plus */ +#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */ +#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ +#define ANYSEE_HW_508TC 18 /* E7 TC */ +#define ANYSEE_HW_508S2 19 /* E7 S2 */ +#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */ +#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */ + +#define REG_IOA 0x80 /* Port A (bit addressable) */ +#define REG_IOB 0x90 /* Port B (bit addressable) */ +#define REG_IOC 0xa0 /* Port C (bit addressable) */ +#define REG_IOD 0xb0 /* Port D (bit addressable) */ +#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */ +#define REG_OEA 0xb2 /* Port A Output Enable */ +#define REG_OEB 0xb3 /* Port B Output Enable */ +#define REG_OEC 0xb4 /* Port C Output Enable */ +#define REG_OED 0xb5 /* Port D Output Enable */ +#define REG_OEE 0xb6 /* Port E Output Enable */ + +#endif + +/*************************************************************************** + * USB API description (reverse engineered) + *************************************************************************** + +Transaction flow: +================= +BULK[00001] >>> REQUEST PACKET 64 bytes +BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY) +BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY) + +General reply packet(s) are always used if not own reply defined. + +============================================================================ +| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY) +============================================================================ +| 00 | reply data (if any) from previous transaction +| | Just same reply packet as returned during previous transaction. +| | Needed only if reply is missed in previous transaction. +| | Just skip normally. +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY) +============================================================================ +| 00 | reply data (if any) +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | I2C WRITE REQUEST PACKET +============================================================================ +| 00 | 0x31 I2C write command +---------------------------------------------------------------------------- +| 01 | i2c address +---------------------------------------------------------------------------- +| 02 | data length +| | 0x02 (for typical I2C reg / val pair) +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04- | data +---------------------------------------------------------------------------- +| -59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | I2C READ REQUEST PACKET +============================================================================ +| 00 | 0x33 I2C read command +---------------------------------------------------------------------------- +| 01 | i2c address + 1 +---------------------------------------------------------------------------- +| 02 | register +---------------------------------------------------------------------------- +| 03 | 0x00 +---------------------------------------------------------------------------- +| 04 | 0x00 +---------------------------------------------------------------------------- +| 05 | data length +---------------------------------------------------------------------------- +| 06-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET +============================================================================ +| 00 | 0xb1 register write command +---------------------------------------------------------------------------- +| 01-02 | register +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04 | value +---------------------------------------------------------------------------- +| 05-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET +============================================================================ +| 00 | 0xb0 register read command +---------------------------------------------------------------------------- +| 01-02 | register +---------------------------------------------------------------------------- +| 03 | 0x01 +---------------------------------------------------------------------------- +| 04-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | LED CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x16 LED and IR control command +---------------------------------------------------------------------------- +| 01 | 0x01 (LED) +---------------------------------------------------------------------------- +| 03 | 0x00 blink +| | 0x01 lights continuously +---------------------------------------------------------------------------- +| 04 | blink interval +| | 0x00 fastest (looks like LED lights continuously) +| | 0xff slowest +---------------------------------------------------------------------------- +| 05-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | IR CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x16 LED and IR control command +---------------------------------------------------------------------------- +| 01 | 0x02 (IR) +---------------------------------------------------------------------------- +| 03 | 0x00 IR disabled +| | 0x01 IR enabled +---------------------------------------------------------------------------- +| 04-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | STREAMING CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x12 streaming control command +---------------------------------------------------------------------------- +| 01 | 0x00 streaming disabled +| | 0x01 streaming enabled +---------------------------------------------------------------------------- +| 02 | 0x00 +---------------------------------------------------------------------------- +| 03-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | REMOTE CONTROL REQUEST PACKET +============================================================================ +| 00 | 0x41 remote control command +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | REMOTE CONTROL REPLY PACKET +============================================================================ +| 00 | 0x00 code not received +| | 0x01 code received +---------------------------------------------------------------------------- +| 01 | remote control code +---------------------------------------------------------------------------- +| 02-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GET HARDWARE INFO REQUEST PACKET +============================================================================ +| 00 | 0x19 get hardware info command +---------------------------------------------------------------------------- +| 01-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | GET HARDWARE INFO REPLY PACKET +============================================================================ +| 00 | hardware id +---------------------------------------------------------------------------- +| 01-02 | firmware version +---------------------------------------------------------------------------- +| 03-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +============================================================================ +| 00-63 | SMART CARD READER PACKET +============================================================================ +| 00 | 0x34 smart card reader command +---------------------------------------------------------------------------- +| xx | +---------------------------------------------------------------------------- +| xx-59 | don't care +---------------------------------------------------------------------------- +| 60 | packet sequence number +---------------------------------------------------------------------------- +| 61-63 | don't care +---------------------------------------------------------------------------- + +*/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/au6610.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/au6610.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/au6610.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/au6610.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,267 @@ +/* + * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. + * + * Copyright (C) 2006 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "au6610.h" +#include "zl10353.h" +#include "qt1010.h" + +/* debug */ +static int dvb_usb_au6610_debug; +module_param_named(debug, dvb_usb_au6610_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + int ret; + u16 index; + u8 *usb_buf; + + /* + * allocate enough for all known requests, + * read returns 5 and write 6 bytes + */ + usb_buf = kmalloc(6, GFP_KERNEL); + if (!usb_buf) + return -ENOMEM; + + switch (wlen) { + case 1: + index = wbuf[0] << 8; + break; + case 2: + index = wbuf[0] << 8; + index += wbuf[1]; + break; + default: + warn("wlen = %x, aborting.", wlen); + ret = -EINVAL; + goto error; + } + + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation, + USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, + usb_buf, 6, AU6610_USB_TIMEOUT); + if (ret < 0) + goto error; + + switch (operation) { + case AU6610_REQ_I2C_READ: + case AU6610_REQ_USB_READ: + /* requested value is always 5th byte in buffer */ + rbuf[0] = usb_buf[4]; + } +error: + kfree(usb_buf); + return ret; +} + +static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 request; + u8 wo = (rbuf == NULL || rlen == 0); /* write-only */ + + if (wo) { + request = AU6610_REQ_I2C_WRITE; + } else { /* rw */ + request = AU6610_REQ_I2C_READ; + } + + return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen); +} + + +/* I2C */ +static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, msg[i+1].buf, + msg[i+1].len) < 0) + break; + i++; + } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, NULL, 0) < 0) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + + +static u32 au6610_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm au6610_i2c_algo = { + .master_xfer = au6610_i2c_xfer, + .functionality = au6610_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config au6610_zl10353_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe == NULL) + return -ENODEV; + + return 0; +} + +static struct qt1010_config au6610_qt1010_config = { + .i2c_address = 0x62 +}; + +static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(qt1010_attach, + adap->fe, &adap->dev->i2c_adap, + &au6610_qt1010_config) == NULL ? -ENODEV : 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties au6610_properties; + +static int au6610_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + struct usb_host_interface *alt; + int ret; + + if (intf->num_altsetting < AU6610_ALTSETTING_COUNT) + return -ENODEV; + + ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d, + adapter_nr); + if (ret == 0) { + alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING); + + if (alt == NULL) { + deb_info("%s: no alt found!\n", __func__); + return -ENODEV; + } + ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + } + + return ret; +} + +static struct usb_device_id au6610_table [] = { + { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, au6610_table); + +static struct dvb_usb_device_properties au6610_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = 0, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = au6610_zl10353_frontend_attach, + .tuner_attach = au6610_qt1010_tuner_attach, + + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x82, + .u = { + .isoc = { + .framesperurb = 40, + .framesize = 942, + .interval = 1, + } + } + }, + } + }, + + .i2c_algo = &au6610_i2c_algo, + + .num_device_descs = 1, + .devices = { + { + .name = "Sigmatek DVB-110 DVB-T USB2.0", + .cold_ids = {NULL}, + .warm_ids = {&au6610_table[0], NULL}, + }, + } +}; + +static struct usb_driver au6610_driver = { + .name = "dvb_usb_au6610", + .probe = au6610_probe, + .disconnect = dvb_usb_device_exit, + .id_table = au6610_table, +}; + +/* module stuff */ +static int __init au6610_module_init(void) +{ + int ret; + + ret = usb_register(&au6610_driver); + if (ret) + err("usb_register failed. Error number %d", ret); + + return ret; +} + +static void __exit au6610_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&au6610_driver); +} + +module_init(au6610_module_init); +module_exit(au6610_module_exit); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/au6610.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/au6610.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/au6610.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/au6610.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0. + * + * Copyright (C) 2006 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _DVB_USB_AU6610_H_ +#define _DVB_USB_AU6610_H_ + +#define DVB_USB_LOG_PREFIX "au6610" +#include "dvb-usb.h" + +#define deb_info(args...) dprintk(dvb_usb_au6610_debug, 0x01, args) + +#define AU6610_REQ_I2C_WRITE 0x14 +#define AU6610_REQ_I2C_READ 0x13 +#define AU6610_REQ_USB_WRITE 0x16 +#define AU6610_REQ_USB_READ 0x15 + +#define AU6610_USB_TIMEOUT 1000 + +#define AU6610_ALTSETTING_COUNT 6 +#define AU6610_ALTSETTING 5 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/az6027.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/az6027.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/az6027.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/az6027.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1202 @@ +/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027) + * receiver. + * + * Copyright (C) 2009 Adams.Xu + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "az6027.h" + +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" + +#include "stb6100.h" +#include "stb6100_cfg.h" +#include "dvb_ca_en50221.h" + +int dvb_usb_az6027_debug; +module_param_named(debug, dvb_usb_az6027_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct az6027_device_state { + struct dvb_ca_en50221 ca; + struct mutex ca_mutex; + u8 power_state; +}; + +static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = { + + /* 0x0000000b, SYSREG */ + { STB0899_DEV_ID , 0x30 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISFIFO , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x99 }, + { STB0899_DISF22RX , 0xa8 }, + /* SYSREG ? */ + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0xfe }, + { STB0899_IRQSTATUS_2 , 0x03 }, + { STB0899_IRQSTATUS_1 , 0x7c }, + { STB0899_IRQSTATUS_0 , 0xf4 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x58 }, + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x33 }, + { STB0899_IOPVALUE3 , 0x6d }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x60 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x01 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x01 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x23 }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xf7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xf1 }, + { STB0899_LDT2 , 0xe3 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfd }, + { STB0899_QDCCOMP , 0xff }, + { STB0899_POWERI , 0x0c }, + { STB0899_POWERQ , 0x0f }, + { STB0899_RCOMP , 0x6c }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x06 }, + { STB0899_AGC2I2 , 0x00 }, + { STB0899_TLIR , 0x30 }, + { STB0899_RTF , 0x7f }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xbc }, + { STB0899_CFRM , 0xea }, + { STB0899_CFRL , 0x31 }, + { STB0899_NIRM , 0x2b }, + { STB0899_NIRL , 0x80 }, + { STB0899_ISYMB , 0x1d }, + { STB0899_QSYMB , 0xa6 }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0x02 }, + { STB0899_EQUAQ1 , 0xff }, + { STB0899_EQUAI2 , 0x04 }, + { STB0899_EQUAQ2 , 0x05 }, + { STB0899_EQUAI3 , 0x02 }, + { STB0899_EQUAQ3 , 0xfd }, + { STB0899_EQUAI4 , 0x03 }, + { STB0899_EQUAQ4 , 0x07 }, + { STB0899_EQUAI5 , 0x08 }, + { STB0899_EQUAQ5 , 0xf5 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0x86 }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x0a }, + { STB0899_ECNT3L , 0xad }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xb0 }, + { STB0899_VTH23 , 0x7a }, + { STB0899_VTH34 , 0x58 }, + { STB0899_VTH56 , 0x38 }, + { STB0899_VTH67 , 0x34 }, + { STB0899_VTH78 , 0x24 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x41 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x00 }, + { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x1b }, + { STB0899_TSLLSTKL , 0xb3 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0x00 }, + { STB0899_PCKLENUL , 0xbc }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xbd }, + { STB0899_TSSTATUS , 0x90 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x95 }, + { STB0899_ERRCTRL3 , 0x8d }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x19 }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0xf0 }, + { STB0899_MATSTRL , 0x02 }, + { STB0899_UPLSTRM , 0x45 }, + { STB0899_UPLSTRL , 0x60 }, + { STB0899_DFLSTRM , 0xe3 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x47 }, + { STB0899_SYNCDSTRM , 0x05 }, + { STB0899_SYNCDSTRL , 0x18 }, + { STB0899_CFGPDELSTATUS1 , 0x19 }, + { STB0899_CFGPDELSTATUS2 , 0x2b }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x01 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + + + +struct stb0899_config az6027_stb0899_config = { + .init_dev = az6027_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = az6027_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .demod_address = 0xd0, /* 0x68, 0xd0 >> 1 */ + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_ON, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL, +}; + +struct stb6100_config az6027_stb6100_config = { + .tuner_address = 0xc0, + .refclock = 27000000, +}; + + +/* check for mutex FIXME */ +int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +{ + int ret = -1; + if (mutex_lock_interruptible(&d->usb_mutex)) + return -EAGAIN; + + ret = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev, 0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value, + index, + b, + blen, + 2000); + + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EIO; + } else + ret = 0; + + deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index); + debug_dump(b, blen, deb_xfer); + + mutex_unlock(&d->usb_mutex); + return ret; +} + +static int az6027_usb_out_op(struct dvb_usb_device *d, + u8 req, + u16 value, + u16 index, + u8 *b, + int blen) +{ + int ret; + + deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index); + debug_dump(b, blen, deb_xfer); + + if (mutex_lock_interruptible(&d->usb_mutex)) + return -EAGAIN; + + ret = usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev, 0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value, + index, + b, + blen, + 2000); + + if (ret != blen) { + warn("usb out operation failed. (%d)", ret); + mutex_unlock(&d->usb_mutex); + return -EIO; + } else{ + mutex_unlock(&d->usb_mutex); + return 0; + } +} + +static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + deb_info("%s %d", __func__, onoff); + + req = 0xBC; + value = onoff; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + warn("usb out operation failed. (%d)", ret); + + return ret; +} + +/* keys for the enclosed remote control */ +static struct rc_map_table rc_map_az6027_table[] = { + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, +}; + +/* remote control stuff (does not work with my box) */ +static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + return 0; +} + +/* +int az6027_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 v = onoff; + return az6027_usb_out_op(d,0xBC,v,3,NULL,1); +} +*/ + +static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, + int address) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + if (slot != 0) + return -EINVAL; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + + mutex_lock(&state->ca_mutex); + + req = 0xC1; + value = address; + index = 0; + blen = 1; + + ret = az6027_usb_in_op(d, req, value, index, b, blen); + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EINVAL; + } else { + ret = b[0]; + } + + mutex_unlock(&state->ca_mutex); + kfree(b); + return ret; +} + +static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, + int address, + u8 value) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value1; + u16 index; + int blen; + + deb_info("%s %d", __func__, slot); + if (slot != 0) + return -EINVAL; + + mutex_lock(&state->ca_mutex); + req = 0xC2; + value1 = address; + index = value; + blen = 0; + + ret = az6027_usb_out_op(d, req, value1, index, NULL, blen); + if (ret != 0) + warn("usb out operation failed. (%d)", ret); + + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + if (slot != 0) + return -EINVAL; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + + mutex_lock(&state->ca_mutex); + + req = 0xC3; + value = address; + index = 0; + blen = 2; + + ret = az6027_usb_in_op(d, req, value, index, b, blen); + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EINVAL; + } else { + if (b[0] == 0) + warn("Read CI IO error"); + + ret = b[1]; + deb_info("read cam data = %x from 0x%x", b[1], value); + } + + mutex_unlock(&state->ca_mutex); + kfree(b); + return ret; +} + +static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address, + u8 value) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value1; + u16 index; + int blen; + + if (slot != 0) + return -EINVAL; + + mutex_lock(&state->ca_mutex); + req = 0xC4; + value1 = address; + index = value; + blen = 0; + + ret = az6027_usb_out_op(d, req, value1, index, NULL, blen); + if (ret != 0) { + warn("usb out operation failed. (%d)", ret); + goto failed; + } + +failed: + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + + req = 0xC8; + value = 0; + index = 0; + blen = 1; + + ret = az6027_usb_in_op(d, req, value, index, b, blen); + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EIO; + } else{ + ret = b[0]; + } + kfree(b); + return ret; +} + +static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret, i; + u8 req; + u16 value; + u16 index; + int blen; + + mutex_lock(&state->ca_mutex); + + req = 0xC6; + value = 1; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(d, req, value, index, NULL, blen); + if (ret != 0) { + warn("usb out operation failed. (%d)", ret); + goto failed; + } + + msleep(500); + req = 0xC6; + value = 0; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(d, req, value, index, NULL, blen); + if (ret != 0) { + warn("usb out operation failed. (%d)", ret); + goto failed; + } + + for (i = 0; i < 15; i++) { + msleep(100); + + if (CI_CamReady(ca, slot)) { + deb_info("CAM Ready"); + break; + } + } + msleep(5000); + +failed: + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + return 0; +} + +static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + deb_info("%s", __func__); + mutex_lock(&state->ca_mutex); + req = 0xC7; + value = 1; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(d, req, value, index, NULL, blen); + if (ret != 0) { + warn("usb out operation failed. (%d)", ret); + goto failed; + } + +failed: + mutex_unlock(&state->ca_mutex); + return ret; +} + +static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + int ret; + u8 req; + u16 value; + u16 index; + int blen; + u8 *b; + + b = kmalloc(12, GFP_KERNEL); + if (!b) + return -ENOMEM; + mutex_lock(&state->ca_mutex); + + req = 0xC5; + value = 0; + index = 0; + blen = 1; + + ret = az6027_usb_in_op(d, req, value, index, b, blen); + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EIO; + } else + ret = 0; + + if (!ret && b[0] == 1) { + ret = DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + } + + mutex_unlock(&state->ca_mutex); + kfree(b); + return ret; +} + + +static void az6027_ci_uninit(struct dvb_usb_device *d) +{ + struct az6027_device_state *state; + + deb_info("%s", __func__); + + if (NULL == d) + return; + + state = (struct az6027_device_state *)d->priv; + if (NULL == state) + return; + + if (NULL == state->ca.data) + return; + + dvb_ca_en50221_release(&state->ca); + + memset(&state->ca, 0, sizeof(state->ca)); +} + + +static int az6027_ci_init(struct dvb_usb_adapter *a) +{ + struct dvb_usb_device *d = a->dev; + struct az6027_device_state *state = (struct az6027_device_state *)d->priv; + int ret; + + deb_info("%s", __func__); + + mutex_init(&state->ca_mutex); + + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = az6027_ci_read_attribute_mem; + state->ca.write_attribute_mem = az6027_ci_write_attribute_mem; + state->ca.read_cam_control = az6027_ci_read_cam_control; + state->ca.write_cam_control = az6027_ci_write_cam_control; + state->ca.slot_reset = az6027_ci_slot_reset; + state->ca.slot_shutdown = az6027_ci_slot_shutdown; + state->ca.slot_ts_enable = az6027_ci_slot_ts_enable; + state->ca.poll_slot_status = az6027_ci_poll_slot_status; + state->ca.data = d; + + ret = dvb_ca_en50221_init(&a->dvb_adap, + &state->ca, + 0, /* flags */ + 1);/* n_slots */ + if (ret != 0) { + err("Cannot initialize CI: Error %d.", ret); + memset(&state->ca, 0, sizeof(state->ca)); + return ret; + } + + deb_info("CI initialized."); + + return 0; +} + +/* +static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) +{ + az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6); + return 0; +} +*/ + +static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + + u8 buf; + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + + struct i2c_msg i2c_msg = { + .addr = 0x99, + .flags = 0, + .buf = &buf, + .len = 1 + }; + + /* + * 2 --18v + * 1 --13v + * 0 --off + */ + switch (voltage) { + case SEC_VOLTAGE_13: + buf = 1; + ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); + break; + + case SEC_VOLTAGE_18: + buf = 2; + ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); + break; + + case SEC_VOLTAGE_OFF: + buf = 0; + ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); + break; + + default: + return -EINVAL; + } + return 0; +} + + +static int az6027_frontend_poweron(struct dvb_usb_adapter *adap) +{ + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + req = 0xBC; + value = 1; /* power on */ + index = 3; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + return 0; +} +static int az6027_frontend_reset(struct dvb_usb_adapter *adap) +{ + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + /* reset demodulator */ + req = 0xC0; + value = 1; /* high */ + index = 3; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + req = 0xC0; + value = 0; /* low */ + index = 3; + blen = 0; + msleep_interruptible(200); + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + msleep_interruptible(200); + + req = 0xC0; + value = 1; /*high */ + index = 3; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + msleep_interruptible(200); + return 0; +} + +static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + u8 req; + u16 value; + u16 index; + int blen; + + /* TS passthrough */ + req = 0xC7; + value = onoff; + index = 0; + blen = 0; + + ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen); + if (ret != 0) + return -EIO; + + return 0; +} + +static int az6027_frontend_attach(struct dvb_usb_adapter *adap) +{ + + az6027_frontend_poweron(adap); + az6027_frontend_reset(adap); + + deb_info("adap = %p, dev = %p\n", adap, adap->dev); + adap->fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); + + if (adap->fe) { + deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address); + if (stb6100_attach(adap->fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) { + deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address); + adap->fe->ops.set_voltage = az6027_set_voltage; + az6027_ci_init(adap); + } else { + adap->fe = NULL; + } + } else + warn("no front-end attached\n"); + + az6027_frontend_tsbypass(adap, 0); + + return 0; +} + +static struct dvb_usb_device_properties az6027_properties; + +static void az6027_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + az6027_ci_uninit(d); + dvb_usb_device_exit(intf); +} + + +static int az6027_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, + &az6027_properties, + THIS_MODULE, + NULL, + adapter_nr); +} + +/* I2C */ +static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i = 0, j = 0, len = 0; + int ret; + u16 index; + u16 value; + int length; + u8 req; + u8 *data; + + data = kmalloc(256, GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) { + kfree(data); + return -EAGAIN; + } + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + + if (msg[i].addr == 0x99) { + req = 0xBE; + index = 0; + value = msg[i].buf[0] & 0x00ff; + length = 1; + az6027_usb_out_op(d, req, value, index, data, length); + } + + if (msg[i].addr == 0xd0) { + /* write/read request */ + if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { + req = 0xB9; + index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); + value = msg[i].addr + (msg[i].len << 8); + length = msg[i + 1].len + 6; + ret = az6027_usb_in_op(d, req, value, index, data, length); + len = msg[i + 1].len; + for (j = 0; j < len; j++) + msg[i + 1].buf[j] = data[j + 5]; + + i++; + } else { + + /* demod 16bit addr */ + req = 0xBD; + index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); + value = msg[i].addr + (2 << 8); + length = msg[i].len - 2; + len = msg[i].len - 2; + for (j = 0; j < len; j++) + data[j] = msg[i].buf[j + 2]; + az6027_usb_out_op(d, req, value, index, data, length); + } + } + + if (msg[i].addr == 0xc0) { + if (msg[i].flags & I2C_M_RD) { + + req = 0xB9; + index = 0x0; + value = msg[i].addr; + length = msg[i].len + 6; + ret = az6027_usb_in_op(d, req, value, index, data, length); + len = msg[i].len; + for (j = 0; j < len; j++) + msg[i].buf[j] = data[j + 5]; + + } else { + + req = 0xBD; + index = msg[i].buf[0] & 0x00FF; + value = msg[i].addr + (1 << 8); + length = msg[i].len - 1; + len = msg[i].len - 1; + + for (j = 0; j < len; j++) + data[j] = msg[i].buf[j + 1]; + + az6027_usb_out_op(d, req, value, index, data, length); + } + } + } + mutex_unlock(&d->i2c_mutex); + kfree(data); + + return i; +} + + +static u32 az6027_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm az6027_i2c_algo = { + .master_xfer = az6027_i2c_xfer, + .functionality = az6027_i2c_func, +}; + +int az6027_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + u8 *b; + s16 ret; + + b = kmalloc(16, GFP_KERNEL); + if (!b) + return -ENOMEM; + + ret = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + 0xb7, + USB_TYPE_VENDOR | USB_DIR_IN, + 6, + 0, + b, + 6, + USB_CTRL_GET_TIMEOUT); + + *cold = ret <= 0; + kfree(b); + deb_info("cold: %d\n", *cold); + return 0; +} + + +static struct usb_device_id az6027_usb_table[] = { + { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V1) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V2) }, + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) }, + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, + { }, +}; + +MODULE_DEVICE_TABLE(usb, az6027_usb_table); + +static struct dvb_usb_device_properties az6027_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-az6027-03.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct az6027_device_state), + .identify_state = az6027_identify_state, + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = az6027_streaming_ctrl, + .frontend_attach = az6027_frontend_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, +/* + .power_ctrl = az6027_power_ctrl, + .read_mac_address = az6027_read_mac_addr, + */ + .rc.legacy = { + .rc_map_table = rc_map_az6027_table, + .rc_map_size = ARRAY_SIZE(rc_map_az6027_table), + .rc_interval = 400, + .rc_query = az6027_rc_query, + }, + + .i2c_algo = &az6027_i2c_algo, + + .num_device_descs = 6, + .devices = { + { + .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", + .cold_ids = { &az6027_usb_table[0], NULL }, + .warm_ids = { NULL }, + }, { + .name = "TERRATEC S7", + .cold_ids = { &az6027_usb_table[1], NULL }, + .warm_ids = { NULL }, + }, { + .name = "TERRATEC S7 MKII", + .cold_ids = { &az6027_usb_table[2], NULL }, + .warm_ids = { NULL }, + }, { + .name = "Technisat SkyStar USB 2 HD CI", + .cold_ids = { &az6027_usb_table[3], NULL }, + .warm_ids = { NULL }, + }, { + .name = "Technisat SkyStar USB 2 HD CI", + .cold_ids = { &az6027_usb_table[4], NULL }, + .warm_ids = { NULL }, + }, { + .name = "Elgato EyeTV Sat", + .cold_ids = { &az6027_usb_table[5], NULL }, + .warm_ids = { NULL }, + }, + { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver az6027_usb_driver = { + .name = "dvb_usb_az6027", + .probe = az6027_usb_probe, + .disconnect = az6027_usb_disconnect, + .id_table = az6027_usb_table, +}; + +/* module stuff */ +static int __init az6027_usb_module_init(void) +{ + int result; + + result = usb_register(&az6027_usb_driver); + if (result) { + err("usb_register failed. (%d)", result); + return result; + } + + return 0; +} + +static void __exit az6027_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&az6027_usb_driver); +} + +module_init(az6027_usb_module_init); +module_exit(az6027_usb_module_exit); + +MODULE_AUTHOR("Adams Xu "); +MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/az6027.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/az6027.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/az6027.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/az6027.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,14 @@ +#ifndef _DVB_USB_VP6027_H_ +#define _DVB_USB_VP6027_H_ + +#define DVB_USB_LOG_PREFIX "az6027" +#include "dvb-usb.h" + + +extern int dvb_usb_az6027_debug; +#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args) +#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_az6027_debug, 0x04, args) +#define deb_fe(args...) dprintk(dvb_usb_az6027_debug, 0x08, args) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ce6230.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ce6230.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ce6230.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ce6230.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,341 @@ +/* + * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "ce6230.h" +#include "zl10353.h" +#include "mxl5005s.h" + +/* debug */ +static int dvb_usb_ce6230_debug; +module_param_named(debug, dvb_usb_ce6230_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static struct zl10353_config ce6230_zl10353_config; + +static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req) +{ + int ret; + unsigned int pipe; + u8 request; + u8 requesttype; + u16 value; + u16 index; + u8 *buf; + + request = req->cmd; + value = req->value; + index = req->index; + + switch (req->cmd) { + case I2C_READ: + case DEMOD_READ: + case REG_READ: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + break; + case I2C_WRITE: + case DEMOD_WRITE: + case REG_WRITE: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + break; + default: + err("unknown command:%02x", req->cmd); + ret = -EPERM; + goto error; + } + + buf = kmalloc(req->data_len, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto error; + } + + if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { + /* write */ + memcpy(buf, req->data, req->data_len); + pipe = usb_sndctrlpipe(udev, 0); + } else { + /* read */ + pipe = usb_rcvctrlpipe(udev, 0); + } + + msleep(1); /* avoid I2C errors */ + + ret = usb_control_msg(udev, pipe, request, requesttype, value, index, + buf, req->data_len, CE6230_USB_TIMEOUT); + + ce6230_debug_dump(request, requesttype, value, index, buf, + req->data_len, deb_xfer); + + if (ret < 0) + deb_info("%s: usb_control_msg failed:%d\n", __func__, ret); + else + ret = 0; + + /* read request, copy returned data to return buf */ + if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) + memcpy(req->data, buf, req->data_len); + + kfree(buf); +error: + return ret; +} + +static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) +{ + return ce6230_rw_udev(d->udev, req); +} + +/* I2C */ +static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i = 0; + struct req_t req; + int ret = 0; + memset(&req, 0, sizeof(req)); + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].addr == + ce6230_zl10353_config.demod_address) { + req.cmd = DEMOD_READ; + req.value = msg[i].addr >> 1; + req.index = msg[i].buf[0]; + req.data_len = msg[i+1].len; + req.data = &msg[i+1].buf[0]; + ret = ce6230_ctrl_msg(d, &req); + } else { + err("i2c read not implemented"); + ret = -EPERM; + } + i += 2; + } else { + if (msg[i].addr == + ce6230_zl10353_config.demod_address) { + req.cmd = DEMOD_WRITE; + req.value = msg[i].addr >> 1; + req.index = msg[i].buf[0]; + req.data_len = msg[i].len-1; + req.data = &msg[i].buf[1]; + ret = ce6230_ctrl_msg(d, &req); + } else { + req.cmd = I2C_WRITE; + req.value = 0x2000 + (msg[i].addr >> 1); + req.index = 0x0000; + req.data_len = msg[i].len; + req.data = &msg[i].buf[0]; + ret = ce6230_ctrl_msg(d, &req); + } + i += 1; + } + if (ret) + break; + } + + mutex_unlock(&d->i2c_mutex); + return ret ? ret : i; +} + +static u32 ce6230_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm ce6230_i2c_algo = { + .master_xfer = ce6230_i2c_xfer, + .functionality = ce6230_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config ce6230_zl10353_config = { + .demod_address = 0x1e, + .adc_clock = 450000, + .if2 = 45700, + .no_tuner = 1, + .parallel_ts = 1, + .clock_ctl_1 = 0x34, + .pll_0 = 0x0e, +}; + +static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) +{ + deb_info("%s:\n", __func__); + adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe == NULL) + return -ENODEV; + return 0; +} + +static struct mxl5005s_config ce6230_mxl5003s_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_DEFAULT, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s:\n", __func__); + ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap, + &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; + return ret; +} + +static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + deb_info("%s: onoff:%d\n", __func__, onoff); + + /* InterfaceNumber 1 / AlternateSetting 0 idle + InterfaceNumber 1 / AlternateSetting 1 streaming */ + ret = usb_set_interface(d->udev, 1, onoff); + if (ret) + err("usb_set_interface failed with error:%d", ret); + + return ret; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties ce6230_properties; + +static int ce6230_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret = 0; + struct dvb_usb_device *d = NULL; + + deb_info("%s: interface:%d\n", __func__, + intf->cur_altsetting->desc.bInterfaceNumber); + + if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { + ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE, + &d, adapter_nr); + if (ret) + err("init failed with error:%d\n", ret); + } + + return ret; +} + +static struct usb_device_id ce6230_table[] = { + { USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) }, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, ce6230_table); + +static struct dvb_usb_device_properties ce6230_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .no_reconnect = 1, + + .size_of_priv = 0, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = ce6230_zl10353_frontend_attach, + .tuner_attach = ce6230_mxl5003s_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = (16*512), + } + } + }, + } + }, + + .power_ctrl = ce6230_power_ctrl, + + .i2c_algo = &ce6230_i2c_algo, + + .num_device_descs = 2, + .devices = { + { + .name = "Intel CE9500 reference design", + .cold_ids = {NULL}, + .warm_ids = {&ce6230_table[0], NULL}, + }, + { + .name = "AVerMedia A310 USB 2.0 DVB-T tuner", + .cold_ids = {NULL}, + .warm_ids = {&ce6230_table[1], NULL}, + }, + } +}; + +static struct usb_driver ce6230_driver = { + .name = "dvb_usb_ce6230", + .probe = ce6230_probe, + .disconnect = dvb_usb_device_exit, + .id_table = ce6230_table, +}; + +/* module stuff */ +static int __init ce6230_module_init(void) +{ + int ret; + deb_info("%s:\n", __func__); + ret = usb_register(&ce6230_driver); + if (ret) + err("usb_register failed with error:%d", ret); + + return ret; +} + +static void __exit ce6230_module_exit(void) +{ + deb_info("%s:\n", __func__); + /* deregister this driver from the USB subsystem */ + usb_deregister(&ce6230_driver); +} + +module_init(ce6230_module_init); +module_exit(ce6230_module_exit); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ce6230.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ce6230.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ce6230.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ce6230.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _DVB_USB_CE6230_H_ +#define _DVB_USB_CE6230_H_ + +#define DVB_USB_LOG_PREFIX "ce6230" +#include "dvb-usb.h" + +#define deb_info(args...) dprintk(dvb_usb_ce6230_debug, 0x01, args) +#define deb_rc(args...) dprintk(dvb_usb_ce6230_debug, 0x02, args) +#define deb_xfer(args...) dprintk(dvb_usb_ce6230_debug, 0x04, args) +#define deb_reg(args...) dprintk(dvb_usb_ce6230_debug, 0x08, args) +#define deb_i2c(args...) dprintk(dvb_usb_ce6230_debug, 0x10, args) +#define deb_fw(args...) dprintk(dvb_usb_ce6230_debug, 0x20, args) + +#define ce6230_debug_dump(r, t, v, i, b, l, func) { \ + int loop_; \ + func("%02x %02x %02x %02x %02x %02x %02x %02x", \ + t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \ + if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ + func(" >>> "); \ + else \ + func(" <<< "); \ + for (loop_ = 0; loop_ < l; loop_++) \ + func("%02x ", b[loop_]); \ + func("\n");\ +} + +#define CE6230_USB_TIMEOUT 1000 + +struct req_t { + u8 cmd; /* [1] */ + u16 value; /* [2|3] */ + u16 index; /* [4|5] */ + u16 data_len; /* [6|7] */ + u8 *data; +}; + +enum ce6230_cmd { + CONFIG_READ = 0xd0, /* rd 0 (unclear) */ + UNKNOWN_WRITE = 0xc7, /* wr 7 (unclear) */ + I2C_READ = 0xd9, /* rd 9 (unclear) */ + I2C_WRITE = 0xca, /* wr a */ + DEMOD_READ = 0xdb, /* rd b */ + DEMOD_WRITE = 0xcc, /* wr c */ + REG_READ = 0xde, /* rd e */ + REG_WRITE = 0xcf, /* wr f */ +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,269 @@ +/* + * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack and + * Holger Waechtler + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "cinergyT2.h" + + +/* debug */ +int dvb_usb_cinergyt2_debug; + +module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " + "(or-able))."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct cinergyt2_state { + u8 rc_counter; +}; + +/* We are missing a release hook with usb_device data */ +static struct dvb_usb_device *cinergyt2_usb_device; + +static struct dvb_usb_device_properties cinergyt2_properties; + +static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable) +{ + char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; + char result[64]; + return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result, + sizeof(result), 0); +} + +static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable) +{ + char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 }; + char state[3]; + return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0); +} + +static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) +{ + char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION }; + char state[3]; + int ret; + + adap->fe = cinergyt2_fe_attach(adap->dev); + + ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, + sizeof(state), 0); + if (ret < 0) { + deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep " + "state info\n"); + } + + /* Copy this pointer as we are gonna need it in the release phase */ + cinergyt2_usb_device = adap->dev; + + return 0; +} + +static struct rc_map_table rc_map_cinergyt2_table[] = { + { 0x0401, KEY_POWER }, + { 0x0402, KEY_1 }, + { 0x0403, KEY_2 }, + { 0x0404, KEY_3 }, + { 0x0405, KEY_4 }, + { 0x0406, KEY_5 }, + { 0x0407, KEY_6 }, + { 0x0408, KEY_7 }, + { 0x0409, KEY_8 }, + { 0x040a, KEY_9 }, + { 0x040c, KEY_0 }, + { 0x040b, KEY_VIDEO }, + { 0x040d, KEY_REFRESH }, + { 0x040e, KEY_SELECT }, + { 0x040f, KEY_EPG }, + { 0x0410, KEY_UP }, + { 0x0414, KEY_DOWN }, + { 0x0411, KEY_LEFT }, + { 0x0413, KEY_RIGHT }, + { 0x0412, KEY_OK }, + { 0x0415, KEY_TEXT }, + { 0x0416, KEY_INFO }, + { 0x0417, KEY_RED }, + { 0x0418, KEY_GREEN }, + { 0x0419, KEY_YELLOW }, + { 0x041a, KEY_BLUE }, + { 0x041c, KEY_VOLUMEUP }, + { 0x041e, KEY_VOLUMEDOWN }, + { 0x041d, KEY_MUTE }, + { 0x041b, KEY_CHANNELUP }, + { 0x041f, KEY_CHANNELDOWN }, + { 0x0440, KEY_PAUSE }, + { 0x044c, KEY_PLAY }, + { 0x0458, KEY_RECORD }, + { 0x0454, KEY_PREVIOUS }, + { 0x0448, KEY_STOP }, + { 0x045c, KEY_NEXT } +}; + +/* Number of keypresses to ignore before detect repeating */ +#define RC_REPEAT_DELAY 3 + +static int repeatable_keys[] = { + KEY_UP, + KEY_DOWN, + KEY_LEFT, + KEY_RIGHT, + KEY_VOLUMEUP, + KEY_VOLUMEDOWN, + KEY_CHANNELUP, + KEY_CHANNELDOWN +}; + +static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct cinergyt2_state *st = d->priv; + u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS; + int i; + + *state = REMOTE_NO_KEY_PRESSED; + + dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0); + if (key[4] == 0xff) { + /* key repeat */ + st->rc_counter++; + if (st->rc_counter > RC_REPEAT_DELAY) { + for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { + if (d->last_event == repeatable_keys[i]) { + *state = REMOTE_KEY_REPEAT; + *event = d->last_event; + deb_rc("repeat key, event %x\n", + *event); + return 0; + } + } + deb_rc("repeated key (non repeatable)\n"); + } + return 0; + } + + /* hack to pass checksum on the custom field */ + key[2] = ~key[1]; + dvb_usb_nec_rc_key_to_event(d, key, event, state); + if (key[0] != 0) { + if (*event != d->last_event) + st->rc_counter = 0; + + deb_rc("key: %x %x %x %x %x\n", + key[0], key[1], key[2], key[3], key[4]); + } + return 0; +} + +static int cinergyt2_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &cinergyt2_properties, + THIS_MODULE, NULL, adapter_nr); +} + + +static struct usb_device_id cinergyt2_usb_table[] = { + { USB_DEVICE(USB_VID_TERRATEC, 0x0038) }, + { 0 } +}; + +MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table); + +static struct dvb_usb_device_properties cinergyt2_properties = { + .size_of_priv = sizeof(struct cinergyt2_state), + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cinergyt2_streaming_ctrl, + .frontend_attach = cinergyt2_frontend_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + } + }, + + .power_ctrl = cinergyt2_power_ctrl, + + .rc.legacy = { + .rc_interval = 50, + .rc_map_table = rc_map_cinergyt2_table, + .rc_map_size = ARRAY_SIZE(rc_map_cinergyt2_table), + .rc_query = cinergyt2_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 1, + + .num_device_descs = 1, + .devices = { + { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver", + .cold_ids = {NULL}, + .warm_ids = { &cinergyt2_usb_table[0], NULL }, + }, + { NULL }, + } +}; + + +static struct usb_driver cinergyt2_driver = { + .name = "cinergyT2", + .probe = cinergyt2_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = cinergyt2_usb_table +}; + +static int __init cinergyt2_usb_init(void) +{ + int err; + + err = usb_register(&cinergyt2_driver); + if (err) { + err("usb_register() failed! (err %i)\n", err); + return err; + } + return 0; +} + +static void __exit cinergyt2_usb_exit(void) +{ + usb_deregister(&cinergyt2_driver); +} + +module_init(cinergyt2_usb_init); +module_exit(cinergyt2_usb_exit); + +MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tomi Orava"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,352 @@ +/* + * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack and + * Holger Waechtler + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "cinergyT2.h" + + +/** + * convert linux-dvb frontend parameter set into TPS. + * See ETSI ETS-300744, section 4.6.2, table 9 for details. + * + * This function is probably reusable and may better get placed in a support + * library. + * + * We replace errornous fields by default TPS fields (the ones with value 0). + */ + +static uint16_t compute_tps(struct dvb_frontend_parameters *p) +{ + struct dvb_ofdm_parameters *op = &p->u.ofdm; + uint16_t tps = 0; + + switch (op->code_rate_HP) { + case FEC_2_3: + tps |= (1 << 7); + break; + case FEC_3_4: + tps |= (2 << 7); + break; + case FEC_5_6: + tps |= (3 << 7); + break; + case FEC_7_8: + tps |= (4 << 7); + break; + case FEC_1_2: + case FEC_AUTO: + default: + /* tps |= (0 << 7) */; + } + + switch (op->code_rate_LP) { + case FEC_2_3: + tps |= (1 << 4); + break; + case FEC_3_4: + tps |= (2 << 4); + break; + case FEC_5_6: + tps |= (3 << 4); + break; + case FEC_7_8: + tps |= (4 << 4); + break; + case FEC_1_2: + case FEC_AUTO: + default: + /* tps |= (0 << 4) */; + } + + switch (op->constellation) { + case QAM_16: + tps |= (1 << 13); + break; + case QAM_64: + tps |= (2 << 13); + break; + case QPSK: + default: + /* tps |= (0 << 13) */; + } + + switch (op->transmission_mode) { + case TRANSMISSION_MODE_8K: + tps |= (1 << 0); + break; + case TRANSMISSION_MODE_2K: + default: + /* tps |= (0 << 0) */; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_16: + tps |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + tps |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + tps |= (3 << 2); + break; + case GUARD_INTERVAL_1_32: + default: + /* tps |= (0 << 2) */; + } + + switch (op->hierarchy_information) { + case HIERARCHY_1: + tps |= (1 << 10); + break; + case HIERARCHY_2: + tps |= (2 << 10); + break; + case HIERARCHY_4: + tps |= (3 << 10); + break; + case HIERARCHY_NONE: + default: + /* tps |= (0 << 10) */; + } + + return tps; +} + +struct cinergyt2_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; +}; + +static int cinergyt2_fe_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg result; + u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result, + sizeof(result), 0); + if (ret < 0) + return ret; + + *status = 0; + + if (0xffff - le16_to_cpu(result.gain) > 30) + *status |= FE_HAS_SIGNAL; + if (result.lock_bits & (1 << 6)) + *status |= FE_HAS_LOCK; + if (result.lock_bits & (1 << 5)) + *status |= FE_HAS_SYNC; + if (result.lock_bits & (1 << 4)) + *status |= FE_HAS_CARRIER; + if (result.lock_bits & (1 << 1)) + *status |= FE_HAS_VITERBI; + + if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != + (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) + *status &= ~FE_HAS_LOCK; + + return 0; +} + +static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, + sizeof(status), 0); + if (ret < 0) + return ret; + + *ber = le32_to_cpu(status.viterbi_error_rate); + return 0; +} + +static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status, + sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n", + ret); + return ret; + } + *unc = le32_to_cpu(status.uncorrected_block_count); + return 0; +} + +static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, + sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_signal_strength() Failed!" + " (Error=%d)\n", ret); + return ret; + } + *strength = (0xffff - le16_to_cpu(status.gain)); + return 0; +} + +static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, + sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret); + return ret; + } + *snr = (status.snr << 8) | status.snr; + return 0; +} + +static int cinergyt2_fe_init(struct dvb_frontend *fe) +{ + return 0; +} + +static int cinergyt2_fe_sleep(struct dvb_frontend *fe) +{ + deb_info("cinergyt2_fe_sleep() Called\n"); + return 0; +} + +static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_set_parameters_msg param; + char result[2]; + int err; + + param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; + param.tps = cpu_to_le16(compute_tps(fep)); + param.freq = cpu_to_le32(fep->frequency / 1000); + param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; + param.flags = 0; + + err = dvb_usb_generic_rw(state->d, + (char *)¶m, sizeof(param), + result, sizeof(result), 0); + if (err < 0) + err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); + + return (err < 0) ? err : 0; +} + +static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + return 0; +} + +static void cinergyt2_fe_release(struct dvb_frontend *fe) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + if (state != NULL) + kfree(state); +} + +static struct dvb_frontend_ops cinergyt2_fe_ops; + +struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) +{ + struct cinergyt2_fe_state *s = kzalloc(sizeof( + struct cinergyt2_fe_state), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->d = d; + memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + return &s->fe; +} + + +static struct dvb_frontend_ops cinergyt2_fe_ops = { + .info = { + .name = DRIVER_NAME, + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 + | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 + | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 + | FE_CAN_FEC_AUTO | FE_CAN_QPSK + | FE_CAN_QAM_16 | FE_CAN_QAM_64 + | FE_CAN_QAM_AUTO + | FE_CAN_TRANSMISSION_MODE_AUTO + | FE_CAN_GUARD_INTERVAL_AUTO + | FE_CAN_HIERARCHY_AUTO + | FE_CAN_RECOVER + | FE_CAN_MUTE_TS + }, + + .release = cinergyt2_fe_release, + + .init = cinergyt2_fe_init, + .sleep = cinergyt2_fe_sleep, + + .set_frontend = cinergyt2_fe_set_frontend, + .get_frontend = cinergyt2_fe_get_frontend, + .get_tune_settings = cinergyt2_fe_get_tune_settings, + + .read_status = cinergyt2_fe_read_status, + .read_ber = cinergyt2_fe_read_ber, + .read_signal_strength = cinergyt2_fe_read_signal_strength, + .read_snr = cinergyt2_fe_read_snr, + .read_ucblocks = cinergyt2_fe_read_unc_blocks, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cinergyT2.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack and + * Holger Waechtler + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _DVB_USB_CINERGYT2_H_ +#define _DVB_USB_CINERGYT2_H_ + +#include + +#define DVB_USB_LOG_PREFIX "cinergyT2" +#include "dvb-usb.h" + +#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" + +extern int dvb_usb_cinergyt2_debug; + +#define deb_info(args...) dprintk(dvb_usb_cinergyt2_debug, 0x001, args) +#define deb_xfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x002, args) +#define deb_pll(args...) dprintk(dvb_usb_cinergyt2_debug, 0x004, args) +#define deb_ts(args...) dprintk(dvb_usb_cinergyt2_debug, 0x008, args) +#define deb_err(args...) dprintk(dvb_usb_cinergyt2_debug, 0x010, args) +#define deb_rc(args...) dprintk(dvb_usb_cinergyt2_debug, 0x020, args) +#define deb_fw(args...) dprintk(dvb_usb_cinergyt2_debug, 0x040, args) +#define deb_mem(args...) dprintk(dvb_usb_cinergyt2_debug, 0x080, args) +#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x100, args) + + + +enum cinergyt2_ep1_cmd { + CINERGYT2_EP1_PID_TABLE_RESET = 0x01, + CINERGYT2_EP1_PID_SETUP = 0x02, + CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03, + CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04, + CINERGYT2_EP1_GET_TUNER_STATUS = 0x05, + CINERGYT2_EP1_START_SCAN = 0x06, + CINERGYT2_EP1_CONTINUE_SCAN = 0x07, + CINERGYT2_EP1_GET_RC_EVENTS = 0x08, + CINERGYT2_EP1_SLEEP_MODE = 0x09, + CINERGYT2_EP1_GET_FIRMWARE_VERSION = 0x0A +}; + + +struct dvbt_get_status_msg { + uint32_t freq; + uint8_t bandwidth; + uint16_t tps; + uint8_t flags; + __le16 gain; + uint8_t snr; + __le32 viterbi_error_rate; + uint32_t rs_error_rate; + __le32 uncorrected_block_count; + uint8_t lock_bits; + uint8_t prev_lock_bits; +} __attribute__((packed)); + + +struct dvbt_set_parameters_msg { + uint8_t cmd; + __le32 freq; + uint8_t bandwidth; + __le16 tps; + uint8_t flags; +} __attribute__((packed)); + + +extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d); + +#endif /* _DVB_USB_CINERGYT2_H_ */ + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cxusb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cxusb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cxusb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cxusb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2016 @@ +/* DVB USB compliant linux driver for Conexant USB reference design. + * + * The Conexant reference design I saw on their website was only for analogue + * capturing (using the cx25842). The box I took to write this driver (reverse + * engineered) is the one labeled Medion MD95700. In addition to the cx25842 + * for analogue capturing it also has a cx22702 DVB-T demodulator on the main + * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard. + * + * Maybe it is a little bit premature to call this driver cxusb, but I assume + * the USB protocol is identical or at least inherited from the reference + * design, so it can be reused for the "analogue-only" device (if it will + * appear at all). + * + * TODO: Use the cx25840-driver for the analogue part + * + * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) + * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include +#include +#include + +#include "cxusb.h" + +#include "cx22702.h" +#include "lgdt330x.h" +#include "mt352.h" +#include "mt352_priv.h" +#include "zl10353.h" +#include "tuner-xc2028.h" +#include "tuner-simple.h" +#include "mxl5005s.h" +#include "max2165.h" +#include "dib7000p.h" +#include "dib0070.h" +#include "lgs8gxx.h" +#include "atbm8830.h" + +/* debug */ +static int dvb_usb_cxusb_debug; +module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args) +#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args) + +static int cxusb_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + u8 sndbuf[1+wlen]; + memset(sndbuf, 0, 1+wlen); + + sndbuf[0] = cmd; + memcpy(&sndbuf[1], wbuf, wlen); + if (wo) + return dvb_usb_generic_write(d, sndbuf, 1+wlen); + else + return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); +} + +/* GPIO */ +static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) +{ + struct cxusb_state *st = d->priv; + u8 o[2], i; + + if (st->gpio_write_state[GPIO_TUNER] == onoff) + return; + + o[0] = GPIO_TUNER; + o[1] = onoff; + cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + + if (i != 0x01) + deb_info("gpio_write failed.\n"); + + st->gpio_write_state[GPIO_TUNER] = onoff; +} + +static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, + u8 newval) +{ + u8 o[2], gpio_state; + int rc; + + o[0] = 0xff & ~changemask; /* mask of bits to keep */ + o[1] = newval & changemask; /* new values for bits */ + + rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1); + if (rc < 0 || (gpio_state & changemask) != (newval & changemask)) + deb_info("bluebird_gpio_write failed.\n"); + + return rc < 0 ? rc : gpio_state; +} + +static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low) +{ + cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin); + msleep(5); + cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0); +} + +static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) +{ + cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); +} + +static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, + u8 addr, int onoff) +{ + u8 o[2] = {addr, onoff}; + u8 i; + int rc; + + rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + + if (rc < 0) + return rc; + if (i == 0x01) + return 0; + else { + deb_info("gpio_write failed.\n"); + return -EIO; + } +} + +/* I2C */ +static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + + if (d->udev->descriptor.idVendor == USB_VID_MEDION) + switch (msg[i].addr) { + case 0x63: + cxusb_gpio_tuner(d, 0); + break; + default: + cxusb_gpio_tuner(d, 1); + break; + } + + if (msg[i].flags & I2C_M_RD) { + /* read only */ + u8 obuf[3], ibuf[1+msg[i].len]; + obuf[0] = 0; + obuf[1] = msg[i].len; + obuf[2] = msg[i].addr; + if (cxusb_ctrl_msg(d, CMD_I2C_READ, + obuf, 3, + ibuf, 1+msg[i].len) < 0) { + warn("i2c read failed"); + break; + } + memcpy(msg[i].buf, &ibuf[1], msg[i].len); + } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && + msg[i].addr == msg[i+1].addr) { + /* write to then read from same address */ + u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; + obuf[0] = msg[i].len; + obuf[1] = msg[i+1].len; + obuf[2] = msg[i].addr; + memcpy(&obuf[3], msg[i].buf, msg[i].len); + + if (cxusb_ctrl_msg(d, CMD_I2C_READ, + obuf, 3+msg[i].len, + ibuf, 1+msg[i+1].len) < 0) + break; + + if (ibuf[0] != 0x08) + deb_i2c("i2c read may have failed\n"); + + memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); + + i++; + } else { + /* write only */ + u8 obuf[2+msg[i].len], ibuf; + obuf[0] = msg[i].addr; + obuf[1] = msg[i].len; + memcpy(&obuf[2], msg[i].buf, msg[i].len); + + if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf, + 2+msg[i].len, &ibuf,1) < 0) + break; + if (ibuf != 0x08) + deb_i2c("i2c write may have failed\n"); + } + } + + mutex_unlock(&d->i2c_mutex); + return i == num ? num : -EREMOTEIO; +} + +static u32 cxusb_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm cxusb_i2c_algo = { + .master_xfer = cxusb_i2c_xfer, + .functionality = cxusb_i2c_func, +}; + +static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = 0; + if (onoff) + return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); + else + return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); +} + +static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + if (!onoff) + return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0); + if (d->state == DVB_USB_STATE_INIT && + usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); + if (!ret) { + /* FIXME: We don't know why, but we need to configure the + * lgdt3303 with the register settings below on resume */ + int i; + u8 buf, bufs[] = { + 0x0e, 0x2, 0x00, 0x7f, + 0x0e, 0x2, 0x02, 0xfe, + 0x0e, 0x2, 0x02, 0x01, + 0x0e, 0x2, 0x00, 0x03, + 0x0e, 0x2, 0x0d, 0x40, + 0x0e, 0x2, 0x0e, 0x87, + 0x0e, 0x2, 0x0f, 0x8e, + 0x0e, 0x2, 0x10, 0x01, + 0x0e, 0x2, 0x14, 0xd7, + 0x0e, 0x2, 0x47, 0x88, + }; + msleep(20); + for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) { + ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE, + bufs+i, 4, &buf, 1); + if (ret) + break; + if (buf != 0x8) + return -EREMOTEIO; + } + } + return ret; +} + +static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = 0; + if (onoff) + return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); + else + return 0; +} + +static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int rc = 0; + + rc = cxusb_power_ctrl(d, onoff); + if (!onoff) + cxusb_nano2_led(d, 0); + + return rc; +} + +static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + u8 b; + ret = cxusb_power_ctrl(d, onoff); + if (!onoff) + return ret; + + msleep(128); + cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1); + msleep(100); + return ret; +} + +static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + u8 buf[2] = { 0x03, 0x00 }; + if (onoff) + cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0); + else + cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + + return 0; +} + +static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + if (onoff) + cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0); + else + cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF, + NULL, 0, NULL, 0); + return 0; +} + +static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) +{ + int ep = d->props.generic_bulk_ctrl_endpoint; + const int timeout = 100; + const int junk_len = 32; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, ep), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) +{ + struct usb_data_stream_properties *p = &d->props.adapter[0].stream; + const int timeout = 100; + const int junk_len = p->u.bulk.buffersize; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, p->endpoint), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static int cxusb_d680_dmb_streaming_ctrl( + struct dvb_usb_adapter *adap, int onoff) +{ + if (onoff) { + u8 buf[2] = { 0x03, 0x00 }; + cxusb_d680_dmb_drain_video(adap->dev); + return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, + buf, sizeof(buf), NULL, 0); + } else { + int ret = cxusb_ctrl_msg(adap->dev, + CMD_STREAMING_OFF, NULL, 0, NULL, 0); + return ret; + } +} + +static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + u8 ircode[4]; + int i; + + cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + if (rc5_custom(&keymap[i]) == ircode[2] && + rc5_data(&keymap[i]) == ircode[3]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + +static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + u8 ircode[4]; + int i; + struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, + .buf = ircode, .len = 4 }; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) + return 0; + + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + if (rc5_custom(&keymap[i]) == ircode[1] && + rc5_data(&keymap[i]) == ircode[2]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + +static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + u8 ircode[2]; + int i; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0) + return 0; + + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + if (rc5_custom(&keymap[i]) == ircode[0] && + rc5_data(&keymap[i]) == ircode[1]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + +static struct rc_map_table rc_map_dvico_mce_table[] = { + { 0xfe02, KEY_TV }, + { 0xfe0e, KEY_MP3 }, + { 0xfe1a, KEY_DVD }, + { 0xfe1e, KEY_FAVORITES }, + { 0xfe16, KEY_SETUP }, + { 0xfe46, KEY_POWER2 }, + { 0xfe0a, KEY_EPG }, + { 0xfe49, KEY_BACK }, + { 0xfe4d, KEY_MENU }, + { 0xfe51, KEY_UP }, + { 0xfe5b, KEY_LEFT }, + { 0xfe5f, KEY_RIGHT }, + { 0xfe53, KEY_DOWN }, + { 0xfe5e, KEY_OK }, + { 0xfe59, KEY_INFO }, + { 0xfe55, KEY_TAB }, + { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */ + { 0xfe12, KEY_NEXTSONG }, /* Skip */ + { 0xfe42, KEY_ENTER }, /* Windows/Start */ + { 0xfe15, KEY_VOLUMEUP }, + { 0xfe05, KEY_VOLUMEDOWN }, + { 0xfe11, KEY_CHANNELUP }, + { 0xfe09, KEY_CHANNELDOWN }, + { 0xfe52, KEY_CAMERA }, + { 0xfe5a, KEY_TUNER }, /* Live */ + { 0xfe19, KEY_OPEN }, + { 0xfe0b, KEY_1 }, + { 0xfe17, KEY_2 }, + { 0xfe1b, KEY_3 }, + { 0xfe07, KEY_4 }, + { 0xfe50, KEY_5 }, + { 0xfe54, KEY_6 }, + { 0xfe48, KEY_7 }, + { 0xfe4c, KEY_8 }, + { 0xfe58, KEY_9 }, + { 0xfe13, KEY_ANGLE }, /* Aspect */ + { 0xfe03, KEY_0 }, + { 0xfe1f, KEY_ZOOM }, + { 0xfe43, KEY_REWIND }, + { 0xfe47, KEY_PLAYPAUSE }, + { 0xfe4f, KEY_FASTFORWARD }, + { 0xfe57, KEY_MUTE }, + { 0xfe0d, KEY_STOP }, + { 0xfe01, KEY_RECORD }, + { 0xfe4e, KEY_POWER }, +}; + +static struct rc_map_table rc_map_dvico_portable_table[] = { + { 0xfc02, KEY_SETUP }, /* Profile */ + { 0xfc43, KEY_POWER2 }, + { 0xfc06, KEY_EPG }, + { 0xfc5a, KEY_BACK }, + { 0xfc05, KEY_MENU }, + { 0xfc47, KEY_INFO }, + { 0xfc01, KEY_TAB }, + { 0xfc42, KEY_PREVIOUSSONG },/* Replay */ + { 0xfc49, KEY_VOLUMEUP }, + { 0xfc09, KEY_VOLUMEDOWN }, + { 0xfc54, KEY_CHANNELUP }, + { 0xfc0b, KEY_CHANNELDOWN }, + { 0xfc16, KEY_CAMERA }, + { 0xfc40, KEY_TUNER }, /* ATV/DTV */ + { 0xfc45, KEY_OPEN }, + { 0xfc19, KEY_1 }, + { 0xfc18, KEY_2 }, + { 0xfc1b, KEY_3 }, + { 0xfc1a, KEY_4 }, + { 0xfc58, KEY_5 }, + { 0xfc59, KEY_6 }, + { 0xfc15, KEY_7 }, + { 0xfc14, KEY_8 }, + { 0xfc17, KEY_9 }, + { 0xfc44, KEY_ANGLE }, /* Aspect */ + { 0xfc55, KEY_0 }, + { 0xfc07, KEY_ZOOM }, + { 0xfc0a, KEY_REWIND }, + { 0xfc08, KEY_PLAYPAUSE }, + { 0xfc4b, KEY_FASTFORWARD }, + { 0xfc5b, KEY_MUTE }, + { 0xfc04, KEY_STOP }, + { 0xfc56, KEY_RECORD }, + { 0xfc57, KEY_POWER }, + { 0xfc41, KEY_UNKNOWN }, /* INPUT */ + { 0xfc00, KEY_UNKNOWN }, /* HD */ +}; + +static struct rc_map_table rc_map_d680_dmb_table[] = { + { 0x0038, KEY_UNKNOWN }, /* TV/AV */ + { 0x080c, KEY_ZOOM }, + { 0x0800, KEY_0 }, + { 0x0001, KEY_1 }, + { 0x0802, KEY_2 }, + { 0x0003, KEY_3 }, + { 0x0804, KEY_4 }, + { 0x0005, KEY_5 }, + { 0x0806, KEY_6 }, + { 0x0007, KEY_7 }, + { 0x0808, KEY_8 }, + { 0x0009, KEY_9 }, + { 0x000a, KEY_MUTE }, + { 0x0829, KEY_BACK }, + { 0x0012, KEY_CHANNELUP }, + { 0x0813, KEY_CHANNELDOWN }, + { 0x002b, KEY_VOLUMEUP }, + { 0x082c, KEY_VOLUMEDOWN }, + { 0x0020, KEY_UP }, + { 0x0821, KEY_DOWN }, + { 0x0011, KEY_LEFT }, + { 0x0810, KEY_RIGHT }, + { 0x000d, KEY_OK }, + { 0x081f, KEY_RECORD }, + { 0x0017, KEY_PLAYPAUSE }, + { 0x0816, KEY_PLAYPAUSE }, + { 0x000b, KEY_STOP }, + { 0x0827, KEY_FASTFORWARD }, + { 0x0026, KEY_REWIND }, + { 0x081e, KEY_UNKNOWN }, /* Time Shift */ + { 0x000e, KEY_UNKNOWN }, /* Snapshot */ + { 0x082d, KEY_UNKNOWN }, /* Mouse Cursor */ + { 0x000f, KEY_UNKNOWN }, /* Minimize/Maximize */ + { 0x0814, KEY_UNKNOWN }, /* Shuffle */ + { 0x0025, KEY_POWER }, +}; + +static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) +{ + static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; + static u8 reset [] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; + static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +static int cxusb_mt352_demod_init(struct dvb_frontend* fe) +{ /* used in both lgz201 and th7579 */ + static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x29 }; + static u8 reset [] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; + static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + return 0; +} + +static struct cx22702_config cxusb_cx22702_config = { + .demod_address = 0x63, + .output_mode = CX22702_PARALLEL_OUTPUT, +}; + +static struct lgdt330x_config cxusb_lgdt3303_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, +}; + +static struct lgdt330x_config cxusb_aver_lgdt3303_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .clock_polarity_flip = 2, +}; + +static struct mt352_config cxusb_dee1601_config = { + .demod_address = 0x0f, + .demod_init = cxusb_dee1601_demod_init, +}; + +static struct zl10353_config cxusb_zl10353_dee1601_config = { + .demod_address = 0x0f, + .parallel_ts = 1, +}; + +static struct mt352_config cxusb_mt352_config = { + /* used in both lgz201 and th7579 */ + .demod_address = 0x0f, + .demod_init = cxusb_mt352_demod_init, +}; + +static struct zl10353_config cxusb_zl10353_xc3028_config = { + .demod_address = 0x0f, + .if2 = 45600, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static struct zl10353_config cxusb_zl10353_xc3028_config_no_i2c_gate = { + .demod_address = 0x0f, + .if2 = 45600, + .no_tuner = 1, + .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, +}; + +static struct mt352_config cxusb_mt352_xc3028_config = { + .demod_address = 0x0f, + .if2 = 4560, + .no_tuner = 1, + .demod_init = cxusb_mt352_demod_init, +}; + +/* FIXME: needs tweaking */ +static struct mxl5005s_config aver_a868r_tuner = { + .i2c_address = 0x63, + .if_freq = 6000000UL, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +/* FIXME: needs tweaking */ +static struct mxl5005s_config d680_dmb_tuner = { + .i2c_address = 0x63, + .if_freq = 36125000UL, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static struct max2165_config mygica_d689_max2165_cfg = { + .i2c_address = 0x60, + .osc_clk = 20 +}; + +/* Callbacks for DVB USB */ +static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(simple_tuner_attach, adap->fe, + &adap->dev->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3); + return 0; +} + +static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe, 0x61, + NULL, DVB_PLL_THOMSON_DTT7579); + return 0; +} + +static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201); + return 0; +} + +static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe, 0x60, + NULL, DVB_PLL_THOMSON_DTT7579); + return 0; +} + +static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(simple_tuner_attach, adap->fe, + &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); + return 0; +} + +static int dvico_bluebird_xc2028_callback(void *ptr, int component, + int command, int arg) +{ + struct dvb_usb_adapter *adap = ptr; + struct dvb_usb_device *d = adap->dev; + + switch (command) { + case XC2028_TUNER_RESET: + deb_info("%s: XC2028_TUNER_RESET %d\n", __func__, arg); + cxusb_bluebird_gpio_pulse(d, 0x01, 1); + break; + case XC2028_RESET_CLK: + deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg); + break; + default: + deb_info("%s: unknown command %d, arg %d\n", __func__, + command, arg); + return -EINVAL; + } + + return 0; +} + +static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &adap->dev->i2c_adap, + .i2c_addr = 0x61, + }; + static struct xc2028_ctrl ctl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_ZARLINK456, + }; + + /* FIXME: generalize & move to common area */ + adap->fe->callback = dvico_bluebird_xc2028_callback; + + fe = dvb_attach(xc2028_attach, adap->fe, &cfg); + if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) + return -EIO; + + fe->ops.tuner_ops.set_config(fe, &ctl); + + return 0; +} + +static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(mxl5005s_attach, adap->fe, + &adap->dev->i2c_adap, &aver_a868r_tuner); + return 0; +} + +static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + fe = dvb_attach(mxl5005s_attach, adap->fe, + &adap->dev->i2c_adap, &d680_dmb_tuner); + return (fe == NULL) ? -EIO : 0; +} + +static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + fe = dvb_attach(max2165_attach, adap->fe, + &adap->dev->i2c_adap, &mygica_d689_max2165_cfg); + return (fe == NULL) ? -EIO : 0; +} + +static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 b; + if (usb_set_interface(adap->dev->udev, 0, 6) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); + + if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, + &adap->dev->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 7) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, + &adap->dev->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, + &adap->dev->i2c_adap); + if (adap->fe != NULL) + return 0; + + return -EIO; +} + +static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) +{ + /* used in both lgz201 and th7579 */ + if (usb_set_interface(adap->dev->udev, 0, 0) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, + &adap->dev->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 0) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, + &adap->dev->i2c_adap)) != NULL) || + ((adap->fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_dee1601_config, + &adap->dev->i2c_adap)) != NULL)) + return 0; + + return -EIO; +} + +static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 ircode[4]; + int i; + struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, + .buf = ircode, .len = 4 }; + + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + /* reset the tuner and demodulator */ + cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); + cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + if ((adap->fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config_no_i2c_gate, + &adap->dev->i2c_adap)) == NULL) + return -EIO; + + /* try to determine if there is no IR decoder on the I2C bus */ + for (i = 0; adap->dev->props.rc.legacy.rc_map_table != NULL && i < 5; i++) { + msleep(20); + if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1) + goto no_IR; + if (ircode[0] == 0 && ircode[1] == 0) + continue; + if (ircode[2] + ircode[3] != 0xff) { +no_IR: + adap->dev->props.rc.legacy.rc_map_table = NULL; + info("No IR receiver detected on this device."); + break; + } + } + + return 0; +} + +static struct dibx000_agc_config dib7070_agc_config = { + .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + + /* + * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 + */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | + (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + .inv_gain = 600, + .time_stabiliz = 10, + .alpha_level = 0, + .thlock = 118, + .wbd_inv = 0, + .wbd_ref = 3530, + .wbd_sel = 1, + .wbd_alpha = 5, + .agc1_max = 65535, + .agc1_min = 0, + .agc2_max = 65535, + .agc2_min = 0, + .agc1_pt1 = 0, + .agc1_pt2 = 40, + .agc1_pt3 = 183, + .agc1_slope1 = 206, + .agc1_slope2 = 255, + .agc2_pt1 = 72, + .agc2_pt2 = 152, + .agc2_slope1 = 88, + .agc2_slope2 = 90, + .alpha_mant = 17, + .alpha_exp = 27, + .beta_mant = 23, + .beta_exp = 51, + .perform_agc_softsplit = 0, +}; + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + .internal = 60000, + .sampling = 15000, + .pll_prediv = 1, + .pll_ratio = 20, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + /* refsel, sel, freq_15k */ + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = (0 << 25) | 0, + .timf = 20452225, + .xtal_hz = 12000000, +}; + +static struct dib7000p_config cxusb_dualdig4_rev2_config = { + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = 0xfcef, + .gpio_val = 0x0110, + + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &cxusb_dualdig4_rev2_config) < 0) { + printk(KERN_WARNING "Unable to enumerate dib7000p\n"); + return -ENODEV; + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &cxusb_dualdig4_rev2_config); + if (adap->fe == NULL) + return -EIO; + + return 0; +} + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return 0; +} + +static struct dib0070_config dib7070p_dib0070_config = { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, +}; + +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *, + struct dvb_frontend_parameters *); +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + default: + case BAND_UHF: offset = 550; break; + } + + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + + return state->set_param_save(fe, fep); +} + +static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = + dib7000p_get_i2c_master(adap->fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + &dib7070p_dib0070_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + +static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + /* reset the tuner and demodulator */ + cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); + cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + if ((adap->fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config, + &adap->dev->i2c_adap)) != NULL) + return 0; + + if ((adap->fe = dvb_attach(mt352_attach, + &cxusb_mt352_xc3028_config, + &adap->dev->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +static struct lgs8gxx_config d680_lgs8gl5_cfg = { + .prod = LGS8GXX_PROD_LGS8GL5, + .demod_address = 0x19, + .serial_ts = 0, + .ts_clk_pol = 0, + .ts_clk_gated = 1, + .if_clk_freq = 30400, /* 30.4 MHz */ + .if_freq = 5725, /* 5.725 MHz */ + .if_neg_center = 0, + .ext_adc = 0, + .adc_signed = 0, + .if_neg_edge = 0, +}; + +static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + int n; + + /* Select required USB configuration */ + if (usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + + /* Unblock all USB pipes */ + usb_clear_halt(d->udev, + usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); + + /* Drain USB pipes to avoid hang after reboot */ + for (n = 0; n < 5; n++) { + cxusb_d680_dmb_drain_message(d); + cxusb_d680_dmb_drain_video(d); + msleep(200); + } + + /* Reset the tuner */ + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { + err("clear tuner gpio failed"); + return -EIO; + } + msleep(100); + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { + err("set tuner gpio failed"); + return -EIO; + } + msleep(100); + + /* Attach frontend */ + adap->fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); + if (adap->fe == NULL) + return -EIO; + + return 0; +} + +static struct atbm8830_config mygica_d689_atbm8830_cfg = { + .prod = ATBM8830_PROD_8830, + .demod_address = 0x40, + .serial_ts = 0, + .ts_sampling_edge = 1, + .ts_clk_gated = 0, + .osc_clk_freq = 30400, /* in kHz */ + .if_freq = 0, /* zero IF */ + .zif_swap_iq = 1, + .agc_min = 0x2E, + .agc_max = 0x90, + .agc_hold_loop = 0, +}; + +static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + + /* Select required USB configuration */ + if (usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + + /* Unblock all USB pipes */ + usb_clear_halt(d->udev, + usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); + + + /* Reset the tuner */ + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { + err("clear tuner gpio failed"); + return -EIO; + } + msleep(100); + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { + err("set tuner gpio failed"); + return -EIO; + } + msleep(100); + + /* Attach frontend */ + adap->fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, + &d->i2c_adap); + if (adap->fe == NULL) + return -EIO; + + return 0; +} + +/* + * DViCO has shipped two devices with the same USB ID, but only one of them + * needs a firmware download. Check the device class details to see if they + * have non-default values to decide whether the device is actually cold or + * not, and forget a match if it turns out we selected the wrong device. + */ +static int bluebird_fx2_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int wascold = *cold; + + *cold = udev->descriptor.bDeviceClass == 0xff && + udev->descriptor.bDeviceSubClass == 0xff && + udev->descriptor.bDeviceProtocol == 0xff; + + if (*cold && !wascold) + *desc = NULL; + + return 0; +} + +/* + * DViCO bluebird firmware needs the "warm" product ID to be patched into the + * firmware file before download. + */ + +static const int dvico_firmware_id_offsets[] = { 6638, 3204 }; +static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, + const struct firmware *fw) +{ + int pos; + + for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) { + int idoff = dvico_firmware_id_offsets[pos]; + + if (fw->size < idoff + 4) + continue; + + if (fw->data[idoff] == (USB_VID_DVICO & 0xff) && + fw->data[idoff + 1] == USB_VID_DVICO >> 8) { + struct firmware new_fw; + u8 *new_fw_data = vmalloc(fw->size); + int ret; + + if (!new_fw_data) + return -ENOMEM; + + memcpy(new_fw_data, fw->data, fw->size); + new_fw.size = fw->size; + new_fw.data = new_fw_data; + + new_fw_data[idoff + 2] = + le16_to_cpu(udev->descriptor.idProduct) + 1; + new_fw_data[idoff + 3] = + le16_to_cpu(udev->descriptor.idProduct) >> 8; + + ret = usb_cypress_load_firmware(udev, &new_fw, + CYPRESS_FX2); + vfree(new_fw_data); + return ret; + } + } + + return -EINVAL; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties cxusb_medion_properties; +static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; +static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; +static struct dvb_usb_device_properties cxusb_aver_a868r_properties; +static struct dvb_usb_device_properties cxusb_d680_dmb_properties; +static struct dvb_usb_device_properties cxusb_mygica_d689_properties; + +static int cxusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &cxusb_bluebird_nano2_needsfirmware_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &cxusb_bluebird_dualdig4_rev2_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, + THIS_MODULE, NULL, adapter_nr) || + 0) + return 0; + + return -EINVAL; +} + +static struct usb_device_id cxusb_table [] = { + { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, + { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, + { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) }, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, cxusb_table); + +static struct dvb_usb_device_properties cxusb_medion_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_cx22702_frontend_attach, + .tuner_attach = cxusb_fmd1216me_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + }, + }, + .power_ctrl = cxusb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Medion MD95700 (MDUSBTV-HYBRID)", + { NULL }, + { &cxusb_table[0], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_lgdt3303_frontend_attach, + .tuner_attach = cxusb_lgh064f_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV5 USB Gold", + { &cxusb_table[1], NULL }, + { &cxusb_table[2], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dee1601_frontend_attach, + .tuner_attach = cxusb_dee1601_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .rc.legacy = { + .rc_interval = 150, + .rc_map_table = rc_map_dvico_mce_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), + .rc_query = cxusb_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 3, + .devices = { + { "DViCO FusionHDTV DVB-T Dual USB", + { &cxusb_table[3], NULL }, + { &cxusb_table[4], NULL }, + }, + { "DigitalNow DVB-T Dual USB", + { &cxusb_table[9], NULL }, + { &cxusb_table[10], NULL }, + }, + { "DViCO FusionHDTV DVB-T Dual Digital 2", + { &cxusb_table[11], NULL }, + { &cxusb_table[12], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 2, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_lgz201_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T USB (LGZ201)", + { &cxusb_table[5], NULL }, + { &cxusb_table[6], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_dtt7579_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T USB (TH7579)", + { &cxusb_table[7], NULL }, + { &cxusb_table[8], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_mce_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), + .rc_query = cxusb_bluebird2_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T Dual Digital 4", + { NULL }, + { &cxusb_table[13], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .identify_state = bluebird_fx2_identify_state, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_nano2_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_nano2_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_bluebird2_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T NANO2", + { NULL }, + { &cxusb_table[14], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-02.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + .identify_state = bluebird_fx2_identify_state, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_nano2_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_nano2_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_portable_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_query = cxusb_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", + { &cxusb_table[14], NULL }, + { &cxusb_table[15], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_aver_streaming_ctrl, + .frontend_attach = cxusb_aver_lgdt3303_frontend_attach, + .tuner_attach = cxusb_mxl5003s_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + }, + }, + .power_ctrl = cxusb_aver_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "AVerMedia AVerTVHD Volar (A868R)", + { NULL }, + { &cxusb_table[16], NULL }, + }, + } +}; + +static +struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, + .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, + .size_of_priv = sizeof(struct dib0700_adapter_state), + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }, + }, + + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_dvico_mce_table, + .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table), + .rc_query = cxusb_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)", + { NULL }, + { &cxusb_table[17], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, + .frontend_attach = cxusb_d680_dmb_frontend_attach, + .tuner_attach = cxusb_d680_dmb_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_d680_dmb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_d680_dmb_table, + .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table), + .rc_query = cxusb_d680_dmb_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { + "Conexant DMB-TH Stick", + { NULL }, + { &cxusb_table[18], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, + .frontend_attach = cxusb_mygica_d689_frontend_attach, + .tuner_attach = cxusb_mygica_d689_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_d680_dmb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_d680_dmb_table, + .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table), + .rc_query = cxusb_d680_dmb_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { + "Mygica D689 DMB-TH", + { NULL }, + { &cxusb_table[19], NULL }, + }, + } +}; + +static struct usb_driver cxusb_driver = { + .name = "dvb_usb_cxusb", + .probe = cxusb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = cxusb_table, +}; + +/* module stuff */ +static int __init cxusb_module_init(void) +{ + int result; + if ((result = usb_register(&cxusb_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit cxusb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&cxusb_driver); +} + +module_init (cxusb_module_init); +module_exit (cxusb_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_AUTHOR("Michael Krufky "); +MODULE_AUTHOR("Chris Pascoe "); +MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cxusb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cxusb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cxusb.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/cxusb.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,35 @@ +#ifndef _DVB_USB_CXUSB_H_ +#define _DVB_USB_CXUSB_H_ + +#define DVB_USB_LOG_PREFIX "cxusb" +#include "dvb-usb.h" + +/* usb commands - some of it are guesses, don't have a reference yet */ +#define CMD_BLUEBIRD_GPIO_RW 0x05 + +#define CMD_I2C_WRITE 0x08 +#define CMD_I2C_READ 0x09 + +#define CMD_GPIO_READ 0x0d +#define CMD_GPIO_WRITE 0x0e +#define GPIO_TUNER 0x02 + +#define CMD_POWER_OFF 0xdc +#define CMD_POWER_ON 0xde + +#define CMD_STREAMING_ON 0x36 +#define CMD_STREAMING_OFF 0x37 + +#define CMD_AVER_STREAM_ON 0x18 +#define CMD_AVER_STREAM_OFF 0x19 + +#define CMD_GET_IR_CODE 0x47 + +#define CMD_ANALOG 0x50 +#define CMD_DIGITAL 0x51 + +struct cxusb_state { + u8 gpio_write_state[3]; +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700_core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700_core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,796 @@ +/* Linux driver for devices based on the DiBcom DiB0700 USB bridge + * + * 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, version 2. + * + * Copyright (C) 2005-6 DiBcom, SA + */ +#include "dib0700.h" + +/* debug */ +int dvb_usb_dib0700_debug; +module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); + +static int nb_packet_buffer_size = 21; +module_param(nb_packet_buffer_size, int, 0644); +MODULE_PARM_DESC(nb_packet_buffer_size, + "Set the dib0700 driver data buffer size. This parameter " + "corresponds to the number of TS packets. The actual size of " + "the data buffer corresponds to this parameter " + "multiplied by 188 (default: 21)"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + + +int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, + u32 *romversion, u32 *ramversion, u32 *fwtype) +{ + struct dib0700_state *st = d->priv; + int ret; + + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + st->buf, 16, USB_CTRL_GET_TIMEOUT); + if (hwversion != NULL) + *hwversion = (st->buf[0] << 24) | (st->buf[1] << 16) | + (st->buf[2] << 8) | st->buf[3]; + if (romversion != NULL) + *romversion = (st->buf[4] << 24) | (st->buf[5] << 16) | + (st->buf[6] << 8) | st->buf[7]; + if (ramversion != NULL) + *ramversion = (st->buf[8] << 24) | (st->buf[9] << 16) | + (st->buf[10] << 8) | st->buf[11]; + if (fwtype != NULL) + *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) | + (st->buf[14] << 8) | st->buf[15]; + return ret; +} + +/* expecting rx buffer: request data[0] data[1] ... data[2] */ +static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) +{ + int status; + + deb_data(">>> "); + debug_dump(tx, txlen, deb_data); + + status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), + tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen, + USB_CTRL_GET_TIMEOUT); + + if (status != txlen) + deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen); + + return status < 0 ? status : 0; +} + +/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ +int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +{ + u16 index, value; + int status; + + if (txlen < 2) { + err("tx buffer length is smaller than 2. Makes no sense."); + return -EINVAL; + } + if (txlen > 4) { + err("tx buffer length is larger than 4. Not supported."); + return -EINVAL; + } + + deb_data(">>> "); + debug_dump(tx,txlen,deb_data); + + value = ((txlen - 2) << 8) | tx[1]; + index = 0; + if (txlen > 2) + index |= (tx[2] << 8); + if (txlen > 3) + index |= tx[3]; + + status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], + USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, + USB_CTRL_GET_TIMEOUT); + + if (status < 0) + deb_info("ep 0 read error (status = %d)\n",status); + + deb_data("<<< "); + debug_dump(rx, rxlen, deb_data); + + return status; /* length in case of success */ +} + +int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) +{ + struct dib0700_state *st = d->priv; + s16 ret; + + st->buf[0] = REQUEST_SET_GPIO; + st->buf[1] = gpio; + st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6); + + ret = dib0700_ctrl_wr(d, st->buf, 3); + + return ret; +} + +static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) +{ + struct dib0700_state *st = d->priv; + int ret; + + if (st->fw_version >= 0x10201) { + st->buf[0] = REQUEST_SET_USB_XFER_LEN; + st->buf[1] = (nb_ts_packets >> 8) & 0xff; + st->buf[2] = nb_ts_packets & 0xff; + + deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); + + ret = dib0700_ctrl_wr(d, st->buf, 3); + } else { + deb_info("this firmware does not allow to change the USB xfer len\n"); + ret = -EIO; + } + + return ret; +} + +/* + * I2C master xfer function (supported in 1.20 firmware) + */ +static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + /* The new i2c firmware messages are more reliable and in particular + properly support i2c read calls not preceded by a write */ + + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dib0700_state *st = d->priv; + uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */ + uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */ + uint8_t en_start = 0; + uint8_t en_stop = 0; + int result, i; + + /* Ensure nobody else hits the i2c bus while we're sending our + sequence of messages, (such as the remote control thread) */ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if (i == 0) { + /* First message in the transaction */ + en_start = 1; + } else if (!(msg[i].flags & I2C_M_NOSTART)) { + /* Device supports repeated-start */ + en_start = 1; + } else { + /* Not the first packet and device doesn't support + repeated start */ + en_start = 0; + } + if (i == (num - 1)) { + /* Last message in the transaction */ + en_stop = 1; + } + + if (msg[i].flags & I2C_M_RD) { + /* Read request */ + u16 index, value; + uint8_t i2c_dest; + + i2c_dest = (msg[i].addr << 1); + value = ((en_start << 7) | (en_stop << 6) | + (msg[i].len & 0x3F)) << 8 | i2c_dest; + /* I2C ctrl + FE bus; */ + index = ((gen_mode << 6) & 0xC0) | + ((bus_mode << 4) & 0x30); + + result = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev, 0), + REQUEST_NEW_I2C_READ, + USB_TYPE_VENDOR | USB_DIR_IN, + value, index, msg[i].buf, + msg[i].len, + USB_CTRL_GET_TIMEOUT); + if (result < 0) { + deb_info("i2c read error (status = %d)\n", result); + break; + } + + deb_data("<<< "); + debug_dump(msg[i].buf, msg[i].len, deb_data); + + } else { + /* Write request */ + st->buf[0] = REQUEST_NEW_I2C_WRITE; + st->buf[1] = msg[i].addr << 1; + st->buf[2] = (en_start << 7) | (en_stop << 6) | + (msg[i].len & 0x3F); + /* I2C ctrl + FE bus; */ + st->buf[3] = ((gen_mode << 6) & 0xC0) | + ((bus_mode << 4) & 0x30); + /* The Actual i2c payload */ + memcpy(&st->buf[4], msg[i].buf, msg[i].len); + + deb_data(">>> "); + debug_dump(st->buf, msg[i].len + 4, deb_data); + + result = usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev, 0), + REQUEST_NEW_I2C_WRITE, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, st->buf, msg[i].len + 4, + USB_CTRL_GET_TIMEOUT); + if (result < 0) { + deb_info("i2c write error (status = %d)\n", result); + break; + } + } + } + mutex_unlock(&d->i2c_mutex); + return i; +} + +/* + * I2C master xfer function (pre-1.20 firmware) + */ +static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, + struct i2c_msg *msg, int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dib0700_state *st = d->priv; + int i,len; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* fill in the address */ + st->buf[1] = msg[i].addr << 1; + /* fill the buffer */ + memcpy(&st->buf[2], msg[i].buf, msg[i].len); + + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + st->buf[0] = REQUEST_I2C_READ; + st->buf[1] |= 1; + + /* special thing in the current firmware: when length is zero the read-failed */ + len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2, + msg[i+1].buf, msg[i+1].len); + if (len <= 0) { + deb_info("I2C read failed on address 0x%02x\n", + msg[i].addr); + break; + } + + msg[i+1].len = len; + + i++; + } else { + st->buf[0] = REQUEST_I2C_WRITE; + if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0) + break; + } + } + mutex_unlock(&d->i2c_mutex); + + return i; +} + +static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dib0700_state *st = d->priv; + + if (st->fw_use_new_i2c_api == 1) { + /* User running at least fw 1.20 */ + return dib0700_i2c_xfer_new(adap, msg, num); + } else { + /* Use legacy calls */ + return dib0700_i2c_xfer_legacy(adap, msg, num); + } +} + +static u32 dib0700_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +struct i2c_algorithm dib0700_i2c_algo = { + .master_xfer = dib0700_i2c_xfer, + .functionality = dib0700_i2c_func, +}; + +int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + s16 ret; + u8 *b; + + b = kmalloc(16, GFP_KERNEL); + if (!b) + return -ENOMEM; + + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT); + + deb_info("FW GET_VERSION length: %d\n",ret); + + *cold = ret <= 0; + deb_info("cold: %d\n", *cold); + + kfree(b); + return 0; +} + +static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, + u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv, + u16 pll_loopdiv, u16 free_div, u16 dsuScaler) +{ + struct dib0700_state *st = d->priv; + s16 ret; + + st->buf[0] = REQUEST_SET_CLOCK; + st->buf[1] = (en_pll << 7) | (pll_src << 6) | + (pll_range << 5) | (clock_gpio3 << 4); + st->buf[2] = (pll_prediv >> 8) & 0xff; /* MSB */ + st->buf[3] = pll_prediv & 0xff; /* LSB */ + st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */ + st->buf[5] = pll_loopdiv & 0xff; /* LSB */ + st->buf[6] = (free_div >> 8) & 0xff; /* MSB */ + st->buf[7] = free_div & 0xff; /* LSB */ + st->buf[8] = (dsuScaler >> 8) & 0xff; /* MSB */ + st->buf[9] = dsuScaler & 0xff; /* LSB */ + + ret = dib0700_ctrl_wr(d, st->buf, 10); + + return ret; +} + +int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) +{ + struct dib0700_state *st = d->priv; + u16 divider; + + if (scl_kHz == 0) + return -EINVAL; + + st->buf[0] = REQUEST_SET_I2C_PARAM; + divider = (u16) (30000 / scl_kHz); + st->buf[1] = 0; + st->buf[2] = (u8) (divider >> 8); + st->buf[3] = (u8) (divider & 0xff); + divider = (u16) (72000 / scl_kHz); + st->buf[4] = (u8) (divider >> 8); + st->buf[5] = (u8) (divider & 0xff); + divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */ + st->buf[6] = (u8) (divider >> 8); + st->buf[7] = (u8) (divider & 0xff); + + deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", + (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) | + st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz); + return dib0700_ctrl_wr(d, st->buf, 8); +} + + +int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3) +{ + switch (clk_MHz) { + case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break; + default: return -EINVAL; + } + return 0; +} + +static int dib0700_jumpram(struct usb_device *udev, u32 address) +{ + int ret = 0, actlen; + u8 *buf; + + buf = kmalloc(8, GFP_KERNEL); + if (!buf) + return -ENOMEM; + buf[0] = REQUEST_JUMPRAM; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + buf[4] = (address >> 24) & 0xff; + buf[5] = (address >> 16) & 0xff; + buf[6] = (address >> 8) & 0xff; + buf[7] = address & 0xff; + + if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) { + deb_fw("jumpram to 0x%x failed\n",address); + goto out; + } + if (actlen != 8) { + deb_fw("jumpram to 0x%x failed\n",address); + ret = -EIO; + goto out; + } +out: + kfree(buf); + return ret; +} + +int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) +{ + struct hexline hx; + int pos = 0, ret, act_len, i, adap_num; + u8 *buf; + u32 fw_version; + + buf = kmalloc(260, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) { + deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n", + hx.addr, hx.len, hx.chk); + + buf[0] = hx.len; + buf[1] = (hx.addr >> 8) & 0xff; + buf[2] = hx.addr & 0xff; + buf[3] = hx.type; + memcpy(&buf[4],hx.data,hx.len); + buf[4+hx.len] = hx.chk; + + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x01), + buf, + hx.len + 5, + &act_len, + 1000); + + if (ret < 0) { + err("firmware download failed at %d with %d",pos,ret); + goto out; + } + } + + if (ret == 0) { + /* start the firmware */ + if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) { + info("firmware started successfully."); + msleep(500); + } + } else + ret = -EIO; + + /* the number of ts packet has to be at least 1 */ + if (nb_packet_buffer_size < 1) + nb_packet_buffer_size = 1; + + /* get the fimware version */ + usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + buf, 16, USB_CTRL_GET_TIMEOUT); + fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11]; + + /* set the buffer size - DVB-USB is allocating URB buffers + * only after the firwmare download was successful */ + for (i = 0; i < dib0700_device_count; i++) { + for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters; + adap_num++) { + if (fw_version >= 0x10201) { + dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size; + } else { + /* for fw version older than 1.20.1, + * the buffersize has to be n times 512 */ + dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512; + if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512) + dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512; + } + } + } +out: + kfree(buf); + return ret; +} + +int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dib0700_state *st = adap->dev->priv; + int ret; + + if ((onoff != 0) && (st->fw_version >= 0x10201)) { + /* for firmware later than 1.20.1, + * the USB xfer length can be set */ + ret = dib0700_set_usb_xfer_len(adap->dev, + st->nb_packet_buffer_size); + if (ret < 0) { + deb_info("can not set the USB xfer len\n"); + return ret; + } + } + + st->buf[0] = REQUEST_ENABLE_VIDEO; + /* this bit gives a kind of command, + * rather than enabling something or not */ + st->buf[1] = (onoff << 4) | 0x00; + + if (st->disable_streaming_master_mode == 1) + st->buf[2] = 0x00; + else + st->buf[2] = 0x01 << 4; /* Master mode */ + + st->buf[3] = 0x00; + + deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); + + st->channel_state &= ~0x3; + if ((adap->stream.props.endpoint != 2) + && (adap->stream.props.endpoint != 3)) { + deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->stream.props.endpoint); + if (onoff) + st->channel_state |= 1 << (adap->id); + else + st->channel_state |= 1 << ~(adap->id); + } else { + if (onoff) + st->channel_state |= 1 << (adap->stream.props.endpoint-2); + else + st->channel_state |= 1 << (3-adap->stream.props.endpoint); + } + + st->buf[2] |= st->channel_state; + + deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]); + + return dib0700_ctrl_wr(adap->dev, st->buf, 4); +} + +int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) +{ + struct dvb_usb_device *d = rc->priv; + struct dib0700_state *st = d->priv; + int new_proto, ret; + + st->buf[0] = REQUEST_SET_RC; + st->buf[1] = 0; + st->buf[2] = 0; + + /* Set the IR mode */ + if (rc_type == RC_TYPE_RC5) + new_proto = 1; + else if (rc_type == RC_TYPE_NEC) + new_proto = 0; + else if (rc_type == RC_TYPE_RC6) { + if (st->fw_version < 0x10200) + return -EINVAL; + + new_proto = 2; + } else + return -EINVAL; + + st->buf[1] = new_proto; + + ret = dib0700_ctrl_wr(d, st->buf, 3); + if (ret < 0) { + err("ir protocol setup failed"); + return ret; + } + + d->props.rc.core.protocol = rc_type; + + return ret; +} + +/* Number of keypresses to ignore before start repeating */ +#define RC_REPEAT_DELAY_V1_20 10 + +/* This is the structure of the RC response packet starting in firmware 1.20 */ +struct dib0700_rc_response { + u8 report_id; + u8 data_state; + union { + u16 system16; + struct { + u8 not_system; + u8 system; + }; + }; + u8 data; + u8 not_data; +}; +#define RC_MSG_SIZE_V1_20 6 + +static void dib0700_rc_urb_completion(struct urb *purb) +{ + struct dvb_usb_device *d = purb->context; + struct dib0700_rc_response *poll_reply; + u32 uninitialized_var(keycode); + u8 toggle; + + deb_info("%s()\n", __func__); + if (d == NULL) + return; + + if (d->rc_dev == NULL) { + /* This will occur if disable_rc_polling=1 */ + usb_free_urb(purb); + return; + } + + poll_reply = purb->transfer_buffer; + + if (purb->status < 0) { + deb_info("discontinuing polling\n"); + usb_free_urb(purb); + return; + } + + if (purb->actual_length != RC_MSG_SIZE_V1_20) { + deb_info("malformed rc msg size=%d\n", purb->actual_length); + goto resubmit; + } + + deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n", + poll_reply->report_id, poll_reply->data_state, + poll_reply->system, poll_reply->not_system, + poll_reply->data, poll_reply->not_data, + purb->actual_length); + + switch (d->props.rc.core.protocol) { + case RC_TYPE_NEC: + toggle = 0; + + /* NEC protocol sends repeat code as 0 0 0 FF */ + if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00) + && (poll_reply->not_data == 0xff)) { + poll_reply->data_state = 2; + break; + } + + if ((poll_reply->system ^ poll_reply->not_system) != 0xff) { + deb_data("NEC extended protocol\n"); + /* NEC extended code - 24 bits */ + keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data; + } else { + deb_data("NEC normal protocol\n"); + /* normal NEC code - 16 bits */ + keycode = poll_reply->system << 8 | poll_reply->data; + } + + break; + default: + deb_data("RC5 protocol\n"); + /* RC5 Protocol */ + toggle = poll_reply->report_id; + keycode = poll_reply->system << 8 | poll_reply->data; + + break; + } + + if ((poll_reply->data + poll_reply->not_data) != 0xff) { + /* Key failed integrity check */ + err("key failed integrity check: %04x %02x %02x", + poll_reply->system, + poll_reply->data, poll_reply->not_data); + goto resubmit; + } + + rc_keydown(d->rc_dev, keycode, toggle); + +resubmit: + /* Clean the buffer before we requeue */ + memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20); + + /* Requeue URB */ + usb_submit_urb(purb, GFP_ATOMIC); +} + +int dib0700_rc_setup(struct dvb_usb_device *d) +{ + struct dib0700_state *st = d->priv; + struct urb *purb; + int ret; + + /* Poll-based. Don't initialize bulk mode */ + if (st->fw_version < 0x10200) + return 0; + + /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ + purb = usb_alloc_urb(0, GFP_KERNEL); + if (purb == NULL) { + err("rc usb alloc urb failed\n"); + return -ENOMEM; + } + + purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL); + if (purb->transfer_buffer == NULL) { + err("rc kzalloc failed\n"); + usb_free_urb(purb); + return -ENOMEM; + } + + purb->status = -EINPROGRESS; + usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1), + purb->transfer_buffer, RC_MSG_SIZE_V1_20, + dib0700_rc_urb_completion, d); + + ret = usb_submit_urb(purb, GFP_ATOMIC); + if (ret) + err("rc submit urb failed\n"); + + return ret; +} + +static int dib0700_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int i; + struct dvb_usb_device *dev; + + for (i = 0; i < dib0700_device_count; i++) + if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, + &dev, adapter_nr) == 0) { + struct dib0700_state *st = dev->priv; + u32 hwversion, romversion, fw_version, fwtype; + + dib0700_get_version(dev, &hwversion, &romversion, + &fw_version, &fwtype); + + deb_info("Firmware version: %x, %d, 0x%x, %d\n", + hwversion, romversion, fw_version, fwtype); + + st->fw_version = fw_version; + st->nb_packet_buffer_size = (u32)nb_packet_buffer_size; + + /* Disable polling mode on newer firmwares */ + if (st->fw_version >= 0x10200) + dev->props.rc.core.bulk_mode = true; + else + dev->props.rc.core.bulk_mode = false; + + dib0700_rc_setup(dev); + + return 0; + } + + return -ENODEV; +} + +static struct usb_driver dib0700_driver = { + .name = "dvb_usb_dib0700", + .probe = dib0700_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dib0700_usb_id_table, +}; + +/* module stuff */ +static int __init dib0700_module_init(void) +{ + int result; + info("loaded with support for %d different device-types", dib0700_device_count); + if ((result = usb_register(&dib0700_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit dib0700_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&dib0700_driver); +} + +module_init (dib0700_module_init); +module_exit (dib0700_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,3966 @@ +/* Linux driver for devices based on the DiBcom DiB0700 USB bridge + * + * 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, version 2. + * + * Copyright (C) 2005-9 DiBcom, SA et al + */ +#include "dib0700.h" + +#include "dib3000mc.h" +#include "dib7000m.h" +#include "dib7000p.h" +#include "dib8000.h" +#include "dib9000.h" +#include "mt2060.h" +#include "mt2266.h" +#include "tuner-xc2028.h" +#include "xc5000.h" +#include "xc4000.h" +#include "s5h1411.h" +#include "dib0070.h" +#include "dib0090.h" +#include "lgdt3305.h" +#include "mxl5007t.h" + +static int force_lna_activation; +module_param(force_lna_activation, int, 0644); +MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " + "if applicable for the device (default: 0=automatic/off)."); + +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *); + const struct firmware *frontend_firmware; +}; + +/* Hauppauge Nova-T 500 (aka Bristol) + * has a LNA on GPIO0 which is enabled by setting 1 */ +static struct mt2060_config bristol_mt2060_config[2] = { + { + .i2c_address = 0x60, + .clock_out = 3, + }, { + .i2c_address = 0x61, + } +}; + + +static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 42598, + .agc1_min = 17694, + .agc2_max = 45875, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 59, + + .agc1_slope1 = 0, + .agc1_slope2 = 69, + + .agc2_pt1 = 0, + .agc2_pt2 = 59, + + .agc2_slope1 = 111, + .agc2_slope2 = 28, +}; + +static struct dib3000mc_config bristol_dib3000mc_config[2] = { + { .agc = &bristol_dib3000p_mt2060_agc_config, + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + .output_mpeg2_in_188_bytes = 1, + }, + { .agc = &bristol_dib3000p_mt2060_agc_config, + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + .output_mpeg2_in_188_bytes = 1, + } +}; + +static int bristol_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); + + if (force_lna_activation) + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + else + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); + + if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); + return -ENODEV; + } + } + st->mt2060_if1[adap->id] = 1220; + return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, + (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; +} + +static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) +{ + struct i2c_msg msg[2] = { + { .addr = 0x50, .flags = 0, .buf = &adrs, .len = 1 }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = pval, .len = 1 }, + }; + if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO; + return 0; +} + +static int bristol_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; + struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); + s8 a; + int if1=1220; + if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && + adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) { + if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; + } + return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id], + if1) == NULL ? -ENODEV : 0; +} + +/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ + +/* MT226x */ +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { + { + BAND_UHF, + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 1130, + 21, + + 0, + 118, + + 0, + 3530, + 1, + 0, + + 65535, + 33770, + 65535, + 23592, + + 0, + 62, + 255, + 64, + 64, + 132, + 192, + 80, + 80, + + 17, + 27, + 23, + 51, + + 1, + }, { + BAND_VHF | BAND_LBAND, + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 2372, + 21, + + 0, + 118, + + 0, + 3530, + 1, + 0, + + 65535, + 0, + 65535, + 23592, + + 0, + 128, + 128, + 128, + 0, + 128, + 253, + 81, + 0, + + 17, + 27, + 23, + 51, + + 1, + } +}; + +static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { + 60000, 30000, + 1, 8, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + 0, + 20452225, +}; + +static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + }, + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + } +}; + +static struct mt2266_config stk7700d_mt2266_config[2] = { + { .i2c_address = 0x60 + }, + { .i2c_address = 0x60 + } +}; + +static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + stk7700d_dib7000p_mt2266_config) + != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, + stk7700d_dib7000p_mt2266_config) + != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + return dvb_attach(mt2266_attach, adap->fe, tun_i2c, + &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0; +} + +/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */ +static struct dibx000_agc_config xc3028_agc_config = { + BAND_VHF | BAND_UHF, /* band_caps */ + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | + (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */ + + 712, /* inv_gain */ + 21, /* time_stabiliz */ + + 0, /* alpha_level */ + 118, /* thlock */ + + 0, /* wbd_inv */ + 2867, /* wbd_ref */ + 0, /* wbd_sel */ + 2, /* wbd_alpha */ + + 0, /* agc1_max */ + 0, /* agc1_min */ + 39718, /* agc2_max */ + 9930, /* agc2_min */ + 0, /* agc1_pt1 */ + 0, /* agc1_pt2 */ + 0, /* agc1_pt3 */ + 0, /* agc1_slope1 */ + 0, /* agc1_slope2 */ + 0, /* agc2_pt1 */ + 128, /* agc2_pt2 */ + 29, /* agc2_slope1 */ + 29, /* agc2_slope2 */ + + 17, /* alpha_mant */ + 27, /* alpha_exp */ + 23, /* beta_mant */ + 51, /* beta_exp */ + + 1, /* perform_agc_softsplit */ +}; + +/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */ +static struct dibx000_bandwidth_config xc3028_bw_config = { + 60000, 30000, /* internal, sampling */ + 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ + 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, + modulo */ + (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ + (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ + 20452225, /* timf */ + 30000000, /* xtal_hz */ +}; + +static struct dib7000p_config stk7700ph_dib7700_xc3028_config = { + .output_mpeg2_in_188_bytes = 1, + .tuner_is_baseband = 1, + + .agc_config_count = 1, + .agc = &xc3028_agc_config, + .bw = &xc3028_bw_config, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, +}; + +static int stk7700ph_xc3028_callback(void *ptr, int component, + int command, int arg) +{ + struct dvb_usb_adapter *adap = ptr; + + switch (command) { + case XC2028_TUNER_RESET: + /* Send the tuner in then out of reset */ + dib7000p_set_gpio(adap->fe, 8, 0, 0); msleep(10); + dib7000p_set_gpio(adap->fe, 8, 0, 1); + break; + case XC2028_RESET_CLK: + break; + default: + err("%s: unknown command %d, arg %d\n", __func__, + command, arg); + return -EINVAL; + } + return 0; +} + +static struct xc2028_ctrl stk7700ph_xc3028_ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_DIBCOM52, +}; + +static struct xc2028_config stk7700ph_xc3028_config = { + .i2c_addr = 0x61, + .ctrl = &stk7700ph_xc3028_ctrl, +}; + +static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct usb_device_descriptor *desc = &adap->dev->udev->descriptor; + + if (desc->idVendor == cpu_to_le16(USB_VID_PINNACLE) && + desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX)) + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + else + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + msleep(10); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &stk7700ph_dib7700_xc3028_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &stk7700ph_dib7700_xc3028_config); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + + tun_i2c = dib7000p_get_i2c_master(adap->fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + + stk7700ph_xc3028_config.i2c_adap = tun_i2c; + + /* FIXME: generalize & move to common area */ + adap->fe->callback = stk7700ph_xc3028_callback; + + return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config) + == NULL ? -ENODEV : 0; +} + +#define DEFAULT_RC_INTERVAL 50 + +static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; + +/* Number of keypresses to ignore before start repeating */ +#define RC_REPEAT_DELAY 6 + +/* + * This function is used only when firmware is < 1.20 version. Newer + * firmwares use bulk mode, with functions implemented at dib0700_core, + * at dib0700_rc_urb_completion() + */ +static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) +{ + u8 key[4]; + u32 keycode; + u8 toggle; + int i; + struct dib0700_state *st = d->priv; + + if (st->fw_version >= 0x10200) { + /* For 1.20 firmware , We need to keep the RC polling + callback so we can reuse the input device setup in + dvb-usb-remote.c. However, the actual work is being done + in the bulk URB completion handler. */ + return 0; + } + + i = dib0700_ctrl_rd(d, rc_request, 2, key, 4); + if (i <= 0) { + err("RC Query Failed"); + return -1; + } + + /* losing half of KEY_0 events from Philipps rc5 remotes.. */ + if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0) + return 0; + + /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */ + + dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */ + + d->last_event = 0; + switch (d->props.rc.core.protocol) { + case RC_TYPE_NEC: + /* NEC protocol sends repeat code as 0 0 0 FF */ + if ((key[3-2] == 0x00) && (key[3-3] == 0x00) && + (key[3] == 0xff)) + keycode = d->last_event; + else { + keycode = key[3-2] << 8 | key[3-3]; + d->last_event = keycode; + } + + rc_keydown(d->rc_dev, keycode, 0); + break; + default: + /* RC-5 protocol changes toggle bit on new keypress */ + keycode = key[3-2] << 8 | key[3-3]; + toggle = key[3-1]; + rc_keydown(d->rc_dev, keycode, toggle); + + break; + } + return 0; +} + +/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ +static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { + BAND_UHF | BAND_VHF, + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 712, + 41, + + 0, + 118, + + 0, + 4095, + 0, + 0, + + 42598, + 17694, + 45875, + 2621, + 0, + 76, + 139, + 52, + 59, + 107, + 172, + 57, + 70, + + 21, + 25, + 28, + 48, + + 1, + { 0, + 107, + 51800, + 24700 + }, +}; + +static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = { + BAND_UHF | BAND_VHF, + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 712, + 41, + + 0, + 118, + + 0, + 4095, + 0, + 0, + + 42598, + 16384, + 42598, + 0, + + 0, + 137, + 255, + + 0, + 255, + + 0, + 0, + + 0, + 41, + + 15, + 25, + + 28, + 48, + + 0, +}; + +static struct dibx000_bandwidth_config stk7700p_pll_config = { + 60000, 30000, + 1, 8, 3, 1, 0, + 0, 0, 1, 1, 0, + (3 << 14) | (1 << 12) | (524 << 0), + 60258167, + 20452225, + 30000000, +}; + +static struct dib7000m_config stk7700p_dib7000m_config = { + .dvbt_mode = 1, + .output_mpeg2_in_188_bytes = 1, + .quartz_direct = 1, + + .agc_config_count = 1, + .agc = &stk7700p_7000m_mt2060_agc_config, + .bw = &stk7700p_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, +}; + +static struct dib7000p_config stk7700p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &stk7700p_7000p_mt2060_agc_config, + .bw = &stk7700p_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, +}; + +static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + /* unless there is no real power management in DVB - we leave the device on GPIO6 */ + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(50); + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); + dib0700_ctrl_clock(adap->dev, 72, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100); + + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + st->mt2060_if1[0] = 1220; + + if (dib7000pc_detection(&adap->dev->i2c_adap)) { + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); + st->is_dib7000pc = 1; + } else + adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static struct mt2060_config stk7700p_mt2060_config = { + 0x60 +}; + +static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; + struct dib0700_state *st = adap->dev->priv; + struct i2c_adapter *tun_i2c; + s8 a; + int if1=1220; + if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && + adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) { + if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; + } + if (st->is_dib7000pc) + tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + else + tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config, + if1) == NULL ? -ENODEV : 0; +} + +/* DIB7070 generic */ +static struct dibx000_agc_config dib7070_agc_config = { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 600, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 65535, + 0, + + 65535, + 0, + + 0, + 40, + 183, + 206, + 255, + 72, + 152, + 88, + 90, + + 17, + 27, + 23, + 51, + + 0, +}; + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + deb_info("reset: %d", onoff); + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + deb_info("sleep: %d", onoff); + return dib7000p_set_gpio(fe, 9, 0, onoff); +} + +static struct dib0070_config dib7070p_dib0070_config[2] = { + { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 4, + .charge_pump = 2, + }, { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .charge_pump = 2, + } +}; + +static struct dib0070_config dib7770p_dib0070_config = { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 0, + .flip_chip = 1, + .charge_pump = 2, +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; + } + deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + return state->set_param_save(fe, fep); +} + +static int dib7770_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: + dib7000p_set_gpio(fe, 0, 0, 1); + offset = 850; + break; + case BAND_UHF: + default: + dib7000p_set_gpio(fe, 0, 0, 0); + offset = 250; + break; + } + deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + return state->set_param_save(fe, fep); +} + +static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + &dib7770p_dib0070_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7770_set_param_override; + return 0; +} + +static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (adap->id == 0) { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) + return -ENODEV; + } else { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) + return -ENODEV; + } + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + +static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index, + u16 pid, int onoff) +{ + struct dib0700_state *st = adapter->dev->priv; + if (st->is_dib7000pc) + return dib7000p_pid_filter(adapter->fe, index, pid, onoff); + return dib7000m_pid_filter(adapter->fe, index, pid, onoff); +} + +static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +{ + struct dib0700_state *st = adapter->dev->priv; + if (st->is_dib7000pc) + return dib7000p_pid_filter_ctrl(adapter->fe, onoff); + return dib7000m_pid_filter_ctrl(adapter->fe, onoff); +} + +static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) +{ + return dib7000p_pid_filter(adapter->fe, index, pid, onoff); +} + +static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +{ + return dib7000p_pid_filter_ctrl(adapter->fe, onoff); +} + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + 60000, 15000, + 1, 20, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20452225, + 12000000, +}; + +static struct dib7000p_config dib7070p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +/* STK7070P */ +static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct usb_device_descriptor *p = &adap->dev->udev->descriptor; + if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && + p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + else + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &dib7070p_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &dib7070p_dib7000p_config); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* STK7770P */ +static struct dib7000p_config dib7770p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .enable_current_mirror = 1, + .disable_sample_and_hold = 0, +}; + +static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct usb_device_descriptor *p = &adap->dev->udev->descriptor; + if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && + p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + else + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &dib7770p_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &dib7770p_dib7000p_config); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* DIB807x generic */ +static struct dibx000_agc_config dib807x_agc_config[2] = { + { + BAND_VHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + * P_agc_inv_pwm2=0,P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + * P_agc_write=0 */ + (0 << 15) | (0 << 14) | (7 << 11) | (0 << 10) | (0 << 9) | + (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | + (0 << 0), /* setup*/ + + 600, /* inv_gain*/ + 10, /* time_stabiliz*/ + + 0, /* alpha_level*/ + 118, /* thlock*/ + + 0, /* wbd_inv*/ + 3530, /* wbd_ref*/ + 1, /* wbd_sel*/ + 5, /* wbd_alpha*/ + + 65535, /* agc1_max*/ + 0, /* agc1_min*/ + + 65535, /* agc2_max*/ + 0, /* agc2_min*/ + + 0, /* agc1_pt1*/ + 40, /* agc1_pt2*/ + 183, /* agc1_pt3*/ + 206, /* agc1_slope1*/ + 255, /* agc1_slope2*/ + 72, /* agc2_pt1*/ + 152, /* agc2_pt2*/ + 88, /* agc2_slope1*/ + 90, /* agc2_slope2*/ + + 17, /* alpha_mant*/ + 27, /* alpha_exp*/ + 23, /* beta_mant*/ + 51, /* beta_exp*/ + + 0, /* perform_agc_softsplit*/ + }, { + BAND_UHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + * P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + * P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + * P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (0 << 10) | (0 << 9) | + (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | + (0 << 0), /* setup */ + + 600, /* inv_gain*/ + 10, /* time_stabiliz*/ + + 0, /* alpha_level*/ + 118, /* thlock*/ + + 0, /* wbd_inv*/ + 3530, /* wbd_ref*/ + 1, /* wbd_sel*/ + 5, /* wbd_alpha*/ + + 65535, /* agc1_max*/ + 0, /* agc1_min*/ + + 65535, /* agc2_max*/ + 0, /* agc2_min*/ + + 0, /* agc1_pt1*/ + 40, /* agc1_pt2*/ + 183, /* agc1_pt3*/ + 206, /* agc1_slope1*/ + 255, /* agc1_slope2*/ + 72, /* agc2_pt1*/ + 152, /* agc2_pt2*/ + 88, /* agc2_slope1*/ + 90, /* agc2_slope2*/ + + 17, /* alpha_mant*/ + 27, /* alpha_exp*/ + 23, /* beta_mant*/ + 51, /* beta_exp*/ + + 0, /* perform_agc_softsplit*/ + } +}; + +static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = { + 60000, 15000, /* internal, sampling*/ + 1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/ + 0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core, + ADClkSrc, modulo */ + (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/ + (0 << 25) | 0, /* ifreq = 0.000000 MHz*/ + 18179755, /* timf*/ + 12000000, /* xtal_hz*/ +}; + +static struct dib8000_config dib807x_dib8000_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib807x_agc_config, + .pll = &dib807x_bw_config_12_mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 1, + .agc_control = &dib0070_ctrl_agc_filter, + .output_mode = OUTMODE_MPEG2_FIFO, + .drives = 0x2d98, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib807x_agc_config, + .pll = &dib807x_bw_config_12_mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .agc_control = &dib0070_ctrl_agc_filter, + .output_mode = OUTMODE_MPEG2_FIFO, + .drives = 0x2d98, + } +}; + +static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib8000_set_gpio(fe, 5, 0, !onoff); +} + +static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return dib8000_set_gpio(fe, 0, 0, onoff); +} + +static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = { + { 240, 7}, + { 0xffff, 6}, +}; + +static struct dib0070_config dib807x_dib0070_config[2] = { + { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 4, + .vga_filter = 1, + .force_crystal_mode = 1, + .enable_third_order_filter = 1, + .charge_pump = 0, + .wbd_gain = dib8070_wbd_gain_cfg, + .osc_buffer_state = 0, + .freq_offset_khz_uhf = -100, + .freq_offset_khz_vhf = -100, + }, { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 2, + .vga_filter = 1, + .force_crystal_mode = 1, + .enable_third_order_filter = 1, + .charge_pump = 0, + .wbd_gain = dib8070_wbd_gain_cfg, + .osc_buffer_state = 0, + .freq_offset_khz_uhf = -25, + .freq_offset_khz_vhf = -25, + } +}; + +static int dib807x_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset = dib0070_wbd_offset(fe); + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: + offset += 750; + break; + case BAND_UHF: /* fall-thru wanted */ + default: + offset += 250; break; + } + deb_info("WBD for DiB8000: %d\n", offset); + dib8000_set_wbd_ref(fe, offset); + + return state->set_param_save(fe, fep); +} + +static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + + if (adap->id == 0) { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + &dib807x_dib0070_config[0]) == NULL) + return -ENODEV; + } else { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + &dib807x_dib0070_config[1]) == NULL) + return -ENODEV; + } + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib807x_set_param_override; + return 0; +} + +static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, + u16 pid, int onoff) +{ + return dib8000_pid_filter(adapter->fe, index, pid, onoff); +} + +static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, + int onoff) +{ + return dib8000_pid_filter_ctrl(adapter->fe, onoff); +} + +/* STK807x */ +static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + 0x80); + + adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + &dib807x_dib8000_config[0]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +/* STK807xPVR */ +static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(500); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + /* initialize IC 0 */ + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); + + adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + &dib807x_dib8000_config[0]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) +{ + /* initialize IC 1 */ + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); + + adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, + &dib807x_dib8000_config[1]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +/* STK8096GP */ +struct dibx000_agc_config dib8090_agc_config[2] = { + { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 787, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 65535, + 0, + + 65535, + 0, + + 0, + 32, + 114, + 143, + 144, + 114, + 227, + 116, + 117, + + 28, + 26, + 31, + 51, + + 0, + }, + { + BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 787, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 0, + 0, + + 65535, + 0, + + 0, + 32, + 114, + 143, + 144, + 114, + 227, + 116, + 117, + + 28, + 26, + 31, + 51, + + 0, + } +}; + +static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = { + 54000, 13500, + 1, 18, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (599 << 0), + (0 << 25) | 0, + 20199727, + 12000000, +}; + +static int dib8090_get_adc_power(struct dvb_frontend *fe) +{ + return dib8000_get_adc_power(fe, 1); +} + +static struct dib8000_config dib809x_dib8000_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib8090_agc_config, + .agc_control = dib0090_dcc_freq, + .pll = &dib8090_pll_config_12mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 0x31, + .output_mode = OUTMODE_MPEG2_FIFO, + .drives = 0x2d98, + .diversity_delay = 48, + .refclksel = 3, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib8090_agc_config, + .agc_control = dib0090_dcc_freq, + .pll = &dib8090_pll_config_12mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 0x31, + .output_mode = OUTMODE_DIVERSITY, + .drives = 0x2d08, + .diversity_delay = 1, + .refclksel = 3, + } +}; + +static struct dib0090_wbd_slope dib8090_wbd_table[] = { + /* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */ + { 120, 0, 500, 0, 500, 4 }, /* CBAND */ + { 170, 0, 450, 0, 450, 4 }, /* CBAND */ + { 380, 48, 373, 28, 259, 6 }, /* VHF */ + { 860, 34, 700, 36, 616, 6 }, /* high UHF */ + { 0xFFFF, 34, 700, 36, 616, 6 }, /* default */ +}; + +static struct dib0090_config dib809x_dib0090_config = { + .io.pll_bypass = 1, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 20, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 12000, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, + .clkouttobamse = 1, + .analog_output = 1, + .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS, + .use_pwm_agc = 1, + .clkoutdrive = 1, + .get_adc_power = dib8090_get_adc_power, + .freq_offset_khz_uhf = -63, + .freq_offset_khz_vhf = -143, + .wbd = dib8090_wbd_table, + .fref_clock_ratio = 6, +}; + +static int dib8096_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u16 target; + int ret = 0; + enum frontend_tune_state tune_state = CT_SHUTDOWN; + u16 ltgain, rf_gain_limit; + + ret = state->set_param_save(fe, fep); + if (ret < 0) + return ret; + + target = (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2; + dib8000_set_wbd_ref(fe, target); + + + if (band == BAND_CBAND) { + deb_info("tuning in CBAND - soft-AGC startup\n"); + dib0090_set_tune_state(fe, CT_AGC_START); + do { + ret = dib0090_gain_control(fe); + msleep(ret); + tune_state = dib0090_get_tune_state(fe); + if (tune_state == CT_AGC_STEP_0) + dib8000_set_gpio(fe, 6, 0, 1); + else if (tune_state == CT_AGC_STEP_1) { + dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); + if (rf_gain_limit == 0) + dib8000_set_gpio(fe, 6, 0, 0); + } + } while (tune_state < CT_AGC_STOP); + dib0090_pwm_gain_reset(fe); + dib8000_pwm_agc_reset(fe); + dib8000_set_tune_state(fe, CT_DEMOD_START); + } else { + deb_info("not tuning in CBAND - standard AGC startup\n"); + dib0090_pwm_gain_reset(fe); + } + + return 0; +} + +static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + return 0; +} + +static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); + + adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c; + struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe, 1); + + if (fe_slave) { + tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); + if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + fe_slave->dvb = adap->fe->dvb; + fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override; + } + tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + + return 0; +} + +static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe_slave; + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(1000); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80); + + adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + if (adap->fe == NULL) + return -ENODEV; + + fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); + dib8000_set_slave_frontend(adap->fe, fe_slave); + + return fe_slave == NULL ? -ENODEV : 0; +} + +/* STK9090M */ +static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) +{ + return dib9000_fw_pid_filter(adapter->fe, index, pid, onoff); +} + +static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +{ + return dib9000_fw_pid_filter_ctrl(adapter->fe, onoff); +} + +static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib9000_set_gpio(fe, 5, 0, !onoff); +} + +static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return dib9000_set_gpio(fe, 0, 0, onoff); +} + +static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len) +{ + u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 }; + u8 rb[2]; + struct i2c_msg msg[2] = { + {.addr = 0x1e >> 1, .flags = 0, .buf = wb, .len = 2}, + {.addr = 0x1e >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2}, + }; + u8 index_data; + + dibx000_i2c_set_speed(i2c, 250); + + if (i2c_transfer(i2c, msg, 2) != 2) + return -EIO; + + switch (rb[0] << 8 | rb[1]) { + case 0: + deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n"); + return -EIO; + case 1: + deb_info("Found DiB0170 rev2"); + break; + case 2: + deb_info("Found DiB0190 rev2"); + break; + default: + deb_info("DiB01x0 not found"); + return -EIO; + } + + for (index_data = 0; index_data < len; index_data += 2) { + wb[2] = (data[index_data + 1] >> 8) & 0xff; + wb[3] = (data[index_data + 1]) & 0xff; + + if (data[index_data] == 0) { + wb[0] = (data[index_data] >> 8) & 0xff; + wb[1] = (data[index_data]) & 0xff; + msg[0].len = 2; + if (i2c_transfer(i2c, msg, 2) != 2) + return -EIO; + wb[2] |= rb[0]; + wb[3] |= rb[1] & ~(3 << 4); + } + + wb[0] = (data[index_data] >> 8)&0xff; + wb[1] = (data[index_data])&0xff; + msg[0].len = 4; + if (i2c_transfer(i2c, &msg[0], 1) != 1) + return -EIO; + } + return 0; +} + +static struct dib9000_config stk9090m_config = { + .output_mpeg2_in_188_bytes = 1, + .output_mode = OUTMODE_MPEG2_FIFO, + .vcxo_timer = 279620, + .timing_frequency = 20452225, + .demod_clock_khz = 60000, + .xtal_clock_khz = 30000, + .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), + .subband = { + 2, + { + { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */ + { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */ + { 0 }, + }, + }, + .gpio_function = { + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, + }, +}; + +static struct dib9000_config nim9090md_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + .output_mode = OUTMODE_MPEG2_FIFO, + .vcxo_timer = 279620, + .timing_frequency = 20452225, + .demod_clock_khz = 60000, + .xtal_clock_khz = 30000, + .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), + }, { + .output_mpeg2_in_188_bytes = 1, + .output_mode = OUTMODE_DIVERSITY, + .vcxo_timer = 279620, + .timing_frequency = 20452225, + .demod_clock_khz = 60000, + .xtal_clock_khz = 30000, + .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), + .subband = { + 2, + { + { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */ + { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */ + { 0 }, + }, + }, + .gpio_function = { + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, + }, + } +}; + +static struct dib0090_config dib9090_dib0090_config = { + .io.pll_bypass = 0, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 8, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 30000, + .reset = dib90x0_tuner_reset, + .sleep = dib90x0_tuner_sleep, + .clkouttobamse = 0, + .analog_output = 0, + .use_pwm_agc = 0, + .clkoutdrive = 0, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, +}; + +static struct dib0090_config nim9090md_dib0090_config[2] = { + { + .io.pll_bypass = 0, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 8, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 30000, + .reset = dib90x0_tuner_reset, + .sleep = dib90x0_tuner_sleep, + .clkouttobamse = 1, + .analog_output = 0, + .use_pwm_agc = 0, + .clkoutdrive = 0, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + }, { + .io.pll_bypass = 0, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 8, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 30000, + .reset = dib90x0_tuner_reset, + .sleep = dib90x0_tuner_sleep, + .clkouttobamse = 0, + .analog_output = 0, + .use_pwm_agc = 0, + .clkoutdrive = 0, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + } +}; + + +static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct dib0700_state *st = adap->dev->priv; + u32 fw_version; + + /* Make use of the new i2c functions from FW 1.20 */ + dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); + if (fw_version >= 0x10200) + st->fw_use_new_i2c_api = 1; + dib0700_set_i2c_speed(adap->dev, 340); + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80); + + if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { + deb_info("%s: Upload failed. (file not found?)\n", __func__); + return -ENODEV; + } else { + deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); + } + stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size; + stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data; + + adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe); + u16 data_dib190[10] = { + 1, 0x1374, + 2, 0x01a2, + 7, 0x0020, + 0, 0x00ef, + 8, 0x0486, + }; + + if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &dib9090_dib0090_config) == NULL) + return -ENODEV; + i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) + return -ENODEV; + dib0700_set_i2c_speed(adap->dev, 2000); + if (dib9000_firmware_post_pll_init(adap->fe) < 0) + return -ENODEV; + release_firmware(state->frontend_firmware); + return 0; +} + +static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct dib0700_state *st = adap->dev->priv; + struct i2c_adapter *i2c; + struct dvb_frontend *fe_slave; + u32 fw_version; + + /* Make use of the new i2c functions from FW 1.20 */ + dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); + if (fw_version >= 0x10200) + st->fw_use_new_i2c_api = 1; + dib0700_set_i2c_speed(adap->dev, 340); + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { + deb_info("%s: Upload failed. (file not found?)\n", __func__); + return -EIO; + } else { + deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); + } + nim9090md_config[0].microcode_B_fe_size = state->frontend_firmware->size; + nim9090md_config[0].microcode_B_fe_buffer = state->frontend_firmware->data; + nim9090md_config[1].microcode_B_fe_size = state->frontend_firmware->size; + nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data; + + dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80); + adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); + + if (adap->fe == NULL) + return -ENODEV; + + i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0); + dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82); + + fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]); + dib9000_set_slave_frontend(adap->fe, fe_slave); + + return fe_slave == NULL ? -ENODEV : 0; +} + +static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct i2c_adapter *i2c; + struct dvb_frontend *fe_slave; + u16 data_dib190[10] = { + 1, 0x5374, + 2, 0x01ae, + 7, 0x0020, + 0, 0x00ef, + 8, 0x0406, + }; + i2c = dib9000_get_tuner_interface(adap->fe); + if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &nim9090md_dib0090_config[0]) == NULL) + return -ENODEV; + i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) + return -ENODEV; + dib0700_set_i2c_speed(adap->dev, 2000); + if (dib9000_firmware_post_pll_init(adap->fe) < 0) + return -ENODEV; + + fe_slave = dib9000_get_slave_frontend(adap->fe, 1); + if (fe_slave != NULL) { + i2c = dib9000_get_component_bus_interface(adap->fe); + dib9000_set_i2c_adapter(fe_slave, i2c); + + i2c = dib9000_get_tuner_interface(fe_slave); + if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) + return -ENODEV; + fe_slave->dvb = adap->fe->dvb; + dib9000_fw_set_component_bus_speed(adap->fe, 2000); + if (dib9000_firmware_post_pll_init(fe_slave) < 0) + return -ENODEV; + } + release_firmware(state->frontend_firmware); + + return 0; +} + +/* NIM7090 */ +struct dib7090p_best_adc { + u32 timf; + u32 pll_loopdiv; + u32 pll_prediv; +}; + +static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc) +{ + u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1; + + u16 xtal = 12000; + u32 fcp_min = 1900; /* PLL Minimum Frequency comparator KHz */ + u32 fcp_max = 20000; /* PLL Maximum Frequency comparator KHz */ + u32 fdem_max = 76000; + u32 fdem_min = 69500; + u32 fcp = 0, fs = 0, fdem = 0; + u32 harmonic_id = 0; + + adc->pll_loopdiv = loopdiv; + adc->pll_prediv = prediv; + adc->timf = 0; + + deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min); + + /* Find Min and Max prediv */ + while ((xtal/max_prediv) >= fcp_min) + max_prediv++; + + max_prediv--; + min_prediv = max_prediv; + while ((xtal/min_prediv) <= fcp_max) { + min_prediv--; + if (min_prediv == 1) + break; + } + deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv); + + min_prediv = 2; + + for (prediv = min_prediv ; prediv < max_prediv; prediv++) { + fcp = xtal / prediv; + if (fcp > fcp_min && fcp < fcp_max) { + for (loopdiv = 1 ; loopdiv < 64 ; loopdiv++) { + fdem = ((xtal/prediv) * loopdiv); + fs = fdem / 4; + /* test min/max system restrictions */ + + if ((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) { + spur = 0; + /* test fs harmonics positions */ + for (harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ; harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) { + if (((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) && ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) { + spur = 1; + break; + } + } + + if (!spur) { + adc->pll_loopdiv = loopdiv; + adc->pll_prediv = prediv; + adc->timf = 2396745143UL/fdem*(1 << 9); + adc->timf += ((2396745143UL%fdem) << 9)/fdem; + deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf); + break; + } + } + } + } + if (!spur) + break; + } + + + if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0) + return -EINVAL; + else + return 0; +} + +static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + struct dibx000_bandwidth_config pll; + u16 target; + struct dib7090p_best_adc adc; + int ret; + + ret = state->set_param_save(fe, fep); + if (ret < 0) + return ret; + + memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); + dib0090_pwm_gain_reset(fe); + target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2; + dib7000p_set_wbd_ref(fe, target); + + if (dib7090p_get_best_sampling(fe, &adc) == 0) { + pll.pll_ratio = adc.pll_loopdiv; + pll.pll_prediv = adc.pll_prediv; + + dib7000p_update_pll(fe, &pll); + dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); + } + return 0; +} + +static struct dib0090_wbd_slope dib7090_wbd_table[] = { + { 380, 81, 850, 64, 540, 4}, + { 860, 51, 866, 21, 375, 4}, + {1700, 0, 250, 0, 100, 6}, + {2600, 0, 250, 0, 100, 6}, + { 0xFFFF, 0, 0, 0, 0, 0}, +}; + +struct dibx000_agc_config dib7090_agc_config[2] = { + { + .band_caps = BAND_UHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 687, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 65535, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 32, + .agc1_pt3 = 114, + .agc1_slope1 = 143, + .agc1_slope2 = 144, + .agc2_pt1 = 114, + .agc2_pt2 = 227, + .agc2_slope1 = 116, + .agc2_slope2 = 117, + + .alpha_mant = 18, + .alpha_exp = 0, + .beta_mant = 20, + .beta_exp = 59, + + .perform_agc_softsplit = 0, + } , { + .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 732, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 65535, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 98, + .agc1_slope1 = 0, + .agc1_slope2 = 167, + .agc2_pt1 = 98, + .agc2_pt2 = 255, + .agc2_slope1 = 104, + .agc2_slope2 = 0, + + .alpha_mant = 18, + .alpha_exp = 0, + .beta_mant = 20, + .beta_exp = 59, + + .perform_agc_softsplit = 0, + } +}; + +static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = { + 60000, 15000, + 1, 5, 0, 0, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20452225, + 15000000, +}; + +static struct dib7000p_config nim7090_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_FIFO, + .enMpegOutput = 1, +}; + +static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .default_i2c_addr = 0x90, + .enMpegOutput = 1, + }, { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .default_i2c_addr = 0x92, + .enMpegOutput = 0, + } +}; + +static const struct dib0090_config nim7090_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, +}; + +static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { + { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 50, + .freq_offset_khz_vhf = 70, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + }, { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = -50, + .freq_offset_khz_vhf = -70, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + } +}; + +static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &nim7090_dib0090_config) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe, 8, 0, 1); + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* The TFE7090 requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + /* initialize IC 0 */ + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + + dib0700_set_i2c_speed(adap->dev, 340); + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); + if (adap->fe == NULL) + return -ENODEV; + + dib7090_slave_reset(adap->fe); + + return 0; +} + +static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *i2c; + + if (adap->dev->adapter[0].fe == NULL) { + err("the master dib7090 has to be initialized first"); + return -ENODEV; /* the master device has not been initialized */ + } + + i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); + if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + + adap->fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); + dib0700_set_i2c_speed(adap->dev, 200); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe, 8, 0, 1); + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe, 8, 0, 1); + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +/* STK7070PD */ +static struct dib7000p_config stk7070pd_dib7000p_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + } +}; + +static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, + stk7070pd_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) +{ + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* S5H1411 */ +static struct s5h1411_config pinnacle_801e_config = { + .output_mode = S5H1411_PARALLEL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, + .qam_if = S5H1411_IF_44000, + .vsb_if = S5H1411_IF_44000, + .inversion = S5H1411_INVERSION_OFF, + .status_mode = S5H1411_DEMODLOCKING +}; + +/* Pinnacle PCTV HD Pro 801e GPIOs map: + GPIO0 - currently unknown + GPIO1 - xc5000 tuner reset + GPIO2 - CX25843 sleep + GPIO3 - currently unknown + GPIO4 - currently unknown + GPIO6 - currently unknown + GPIO7 - currently unknown + GPIO9 - currently unknown + GPIO10 - CX25843 reset + */ +static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* Make use of the new i2c functions from FW 1.20 */ + st->fw_use_new_i2c_api = 1; + + /* The s5h1411 requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + + /* All msleep values taken from Windows USB trace */ + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(400); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(60); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0); + msleep(30); + + /* Put the CX25843 to sleep for now since we're in digital mode */ + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); + + /* GPIOs are initialized, do the attach */ + adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, + &adap->dev->i2c_adap); + return adap->fe == NULL ? -ENODEV : 0; +} + +static int dib0700_xc5000_tuner_callback(void *priv, int component, + int command, int arg) +{ + struct dvb_usb_adapter *adap = priv; + + if (command == XC5000_TUNER_RESET) { + /* Reset the tuner */ + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); + msleep(10); + } else { + err("xc5000: unknown tuner callback command: %d\n", command); + return -EINVAL; + } + + return 0; +} + +static struct xc5000_config s5h1411_xc5000_tunerconfig = { + .i2c_address = 0x64, + .if_khz = 5380, +}; + +static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) +{ + /* FIXME: generalize & move to common area */ + adap->fe->callback = dib0700_xc5000_tuner_callback; + + return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, + &s5h1411_xc5000_tunerconfig) + == NULL ? -ENODEV : 0; +} + +static int dib0700_xc4000_tuner_callback(void *priv, int component, + int command, int arg) +{ + struct dvb_usb_adapter *adap = priv; + + if (command == XC4000_TUNER_RESET) { + /* Reset the tuner */ + dib7000p_set_gpio(adap->fe, 8, 0, 0); + msleep(10); + dib7000p_set_gpio(adap->fe, 8, 0, 1); + } else { + err("xc4000: unknown tuner callback command: %d\n", command); + return -EINVAL; + } + + return 0; +} + +static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = { + .band_caps = BAND_UHF | BAND_VHF, + .setup = 0x64, + .inv_gain = 0x02c8, + .time_stabiliz = 0x15, + .alpha_level = 0x00, + .thlock = 0x76, + .wbd_inv = 0x01, + .wbd_ref = 0x0b33, + .wbd_sel = 0x00, + .wbd_alpha = 0x02, + .agc1_max = 0x00, + .agc1_min = 0x00, + .agc2_max = 0x9b26, + .agc2_min = 0x26ca, + .agc1_pt1 = 0x00, + .agc1_pt2 = 0x00, + .agc1_pt3 = 0x00, + .agc1_slope1 = 0x00, + .agc1_slope2 = 0x00, + .agc2_pt1 = 0x00, + .agc2_pt2 = 0x80, + .agc2_slope1 = 0x1d, + .agc2_slope2 = 0x1d, + .alpha_mant = 0x11, + .alpha_exp = 0x1b, + .beta_mant = 0x17, + .beta_exp = 0x33, + .perform_agc_softsplit = 0x00, +}; + +static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = { + 60000, 30000, /* internal, sampling */ + 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ + 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, */ + /* ADClkSrc, modulo */ + (3 << 14) | (1 << 12) | 524, /* sad_cfg: refsel, sel, freq_15k */ + 39370534, /* ifreq */ + 20452225, /* timf */ + 30000000 /* xtal */ +}; + +/* FIXME: none of these inputs are validated yet */ +static struct dib7000p_config pctv_340e_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &stk7700p_7000p_xc4000_agc_config, + .bw = &stk7700p_xc4000_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, +}; + +/* PCTV 340e GPIOs map: + dib0700: + GPIO2 - CX25843 sleep + GPIO3 - CS5340 reset + GPIO5 - IRD + GPIO6 - Power Supply + GPIO8 - LNA (1=off 0=on) + GPIO10 - CX25843 reset + dib7000: + GPIO8 - xc4000 reset + */ +static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* Power Supply on */ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(50); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(100); /* Allow power supply to settle before probing */ + + /* cx25843 reset */ + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(1); /* cx25843 datasheet say 350us required */ + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + + /* LNA off for now */ + dib0700_set_gpio(adap->dev, GPIO8, GPIO_OUT, 1); + + /* Put the CX25843 to sleep for now since we're in digital mode */ + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); + + /* FIXME: not verified yet */ + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(500); + + if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) { + /* Demodulator not found for some reason? */ + return -ENODEV; + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, + &pctv_340e_config); + st->is_dib7000pc = 1; + + return adap->fe == NULL ? -ENODEV : 0; +} + +static struct xc4000_config dib7000p_xc4000_tunerconfig = { + .i2c_address = 0x61, + .default_pm = 1, + .dvb_amplitude = 0, + .set_smoothedcvbs = 0, + .if_khz = 5400 +}; + +static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + + /* The xc4000 is not on the main i2c bus */ + tun_i2c = dib7000p_get_i2c_master(adap->fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + if (tun_i2c == NULL) { + printk(KERN_ERR "Could not reach tuner i2c bus\n"); + return 0; + } + + /* Setup the reset callback */ + adap->fe->callback = dib0700_xc4000_tuner_callback; + + return dvb_attach(xc4000_attach, adap->fe, tun_i2c, + &dib7000p_xc4000_tunerconfig) + == NULL ? -ENODEV : 0; +} + +static struct lgdt3305_config hcw_lgdt3305_config = { + .i2c_addr = 0x0e, + .mpeg_mode = LGDT3305_MPEG_PARALLEL, + .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_LOW, + .deny_i2c_rptr = 0, + .spectral_inversion = 1, + .qam_if_khz = 6000, + .vsb_if_khz = 6000, + .usref_8vsb = 0x0500, +}; + +static struct mxl5007t_config hcw_mxl5007t_config = { + .xtal_freq_hz = MxL_XTAL_25_MHZ, + .if_freq_hz = MxL_IF_6_MHZ, + .invert_if = 1, +}; + +/* TIGER-ATSC map: + GPIO0 - LNA_CTR (H: LNA power enabled, L: LNA power disabled) + GPIO1 - ANT_SEL (H: VPA, L: MCX) + GPIO4 - SCL2 + GPIO6 - EN_TUNER + GPIO7 - SDA2 + GPIO10 - DEM_RST + + MXL is behind LG's i2c repeater. LG is on SCL2/SDA2 gpios on the DIB + */ +static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* Make use of the new i2c functions from FW 1.20 */ + st->fw_use_new_i2c_api = 1; + + st->disable_streaming_master_mode = 1; + + /* fe power enable */ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(30); + + /* demod reset */ + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(30); + + adap->fe = dvb_attach(lgdt3305_attach, + &hcw_lgdt3305_config, + &adap->dev->i2c_adap); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(mxl5007t_attach, adap->fe, + &adap->dev->i2c_adap, 0x60, + &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; +} + + +/* DVB-USB and USB stuff follows */ +struct usb_device_id dib0700_usb_id_table[] = { +/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, +/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, + { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, + { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, +/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, + { USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, +/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, + { USB_DEVICE(USB_VID_PINNACLE, + USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, +/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, +/* 25 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_USB_XE) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_EXPRESSCARD_320CX) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV72E) }, +/* 30 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73E) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_EC372S) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) }, + { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, +/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, +/* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_EXPRESS) }, + { USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) }, + { USB_DEVICE(USB_VID_SONY, USB_PID_SONY_PLAYTV) }, +/* 45 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_PD378S) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) }, +/* 50 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_Dlx) }, + { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, +/* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV73ESE) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV282E) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, +/* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, + { USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x000, 0x3f00) }, + { USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) }, +/* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096GP) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DIVERSITY) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090M) }, +/* 70 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM8096MD) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090MD) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM7090) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) }, + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) }, +/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) }, + { 0 } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); + +#define DIB0700_DEFAULT_DEVICE_PROPERTIES \ + .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ + .usb_ctrl = DEVICE_SPECIFIC, \ + .firmware = "dvb-usb-dib0700-1.20.fw", \ + .download_firmware = dib0700_download_firmware, \ + .no_reconnect = 1, \ + .size_of_priv = sizeof(struct dib0700_state), \ + .i2c_algo = &dib0700_i2c_algo, \ + .identify_state = dib0700_identify_state + +#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \ + .streaming_ctrl = dib0700_streaming_ctrl, \ + .stream = { \ + .type = USB_BULK, \ + .count = 4, \ + .endpoint = ep, \ + .u = { \ + .bulk = { \ + .buffersize = 39480, \ + } \ + } \ + } + +struct dvb_usb_device_properties dib0700_devices[] = { + { + DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk7700p_pid_filter, + .pid_filter_ctrl = stk7700p_pid_filter_ctrl, + .frontend_attach = stk7700p_frontend_attach, + .tuner_attach = stk7700p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, + }, + + .num_device_descs = 8, + .devices = { + { "DiBcom STK7700P reference design", + { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, + { NULL }, + }, + { "Hauppauge Nova-T Stick", + { &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL }, + { NULL }, + }, + { "AVerMedia AVerTV DVB-T Volar", + { &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] }, + { NULL }, + }, + { "Compro Videomate U500", + { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] }, + { NULL }, + }, + { "Uniwill STK7700P based (Hama and others)", + { &dib0700_usb_id_table[7], NULL }, + { NULL }, + }, + { "Leadtek Winfast DTV Dongle (STK7700P based)", + { &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] }, + { NULL }, + }, + { "AVerMedia AVerTV DVB-T Express", + { &dib0700_usb_id_table[20] }, + { NULL }, + }, + { "Gigabyte U7000", + { &dib0700_usb_id_table[21], NULL }, + { NULL }, + } + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = bristol_frontend_attach, + .tuner_attach = bristol_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, { + .frontend_attach = bristol_frontend_attach, + .tuner_attach = bristol_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } + }, + + .num_device_descs = 1, + .devices = { + { "Hauppauge Nova-T 500 Dual DVB-T", + { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } + }, + + .num_device_descs = 5, + .devices = { + { "Pinnacle PCTV 2000e", + { &dib0700_usb_id_table[11], NULL }, + { NULL }, + }, + { "Terratec Cinergy DT XS Diversity", + { &dib0700_usb_id_table[12], NULL }, + { NULL }, + }, + { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity", + { &dib0700_usb_id_table[13], NULL }, + { NULL }, + }, + { "DiBcom STK7700D reference design", + { &dib0700_usb_id_table[14], NULL }, + { NULL }, + }, + { "YUAN High-Tech DiBcom STK7700D", + { &dib0700_usb_id_table[55], NULL }, + { NULL }, + }, + + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7700P2_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, + }, + + .num_device_descs = 3, + .devices = { + { "ASUS My Cinema U3000 Mini DVBT Tuner", + { &dib0700_usb_id_table[23], NULL }, + { NULL }, + }, + { "Yuan EC372S", + { &dib0700_usb_id_table[31], NULL }, + { NULL }, + }, + { "Terratec Cinergy T Express", + { &dib0700_usb_id_table[42], NULL }, + { NULL }, + } + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070p_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 11, + .devices = { + { "DiBcom STK7070P reference design", + { &dib0700_usb_id_table[15], NULL }, + { NULL }, + }, + { "Pinnacle PCTV DVB-T Flash Stick", + { &dib0700_usb_id_table[16], NULL }, + { NULL }, + }, + { "Artec T14BR DVB-T", + { &dib0700_usb_id_table[22], NULL }, + { NULL }, + }, + { "ASUS My Cinema U3100 Mini DVBT Tuner", + { &dib0700_usb_id_table[24], NULL }, + { NULL }, + }, + { "Hauppauge Nova-T Stick", + { &dib0700_usb_id_table[25], NULL }, + { NULL }, + }, + { "Hauppauge Nova-T MyTV.t", + { &dib0700_usb_id_table[26], NULL }, + { NULL }, + }, + { "Pinnacle PCTV 72e", + { &dib0700_usb_id_table[29], NULL }, + { NULL }, + }, + { "Pinnacle PCTV 73e", + { &dib0700_usb_id_table[30], NULL }, + { NULL }, + }, + { "Elgato EyeTV DTT", + { &dib0700_usb_id_table[49], NULL }, + { NULL }, + }, + { "Yuan PD378S", + { &dib0700_usb_id_table[45], NULL }, + { NULL }, + }, + { "Elgato EyeTV Dtt Dlx PD378S", + { &dib0700_usb_id_table[50], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070p_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 3, + .devices = { + { "Pinnacle PCTV 73A", + { &dib0700_usb_id_table[56], NULL }, + { NULL }, + }, + { "Pinnacle PCTV 73e SE", + { &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL }, + { NULL }, + }, + { "Pinnacle PCTV 282e", + { &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070pd_frontend_attach0, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070pd_frontend_attach1, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 6, + .devices = { + { "DiBcom STK7070PD reference design", + { &dib0700_usb_id_table[17], NULL }, + { NULL }, + }, + { "Pinnacle PCTV Dual DVB-T Diversity Stick", + { &dib0700_usb_id_table[18], NULL }, + { NULL }, + }, + { "Hauppauge Nova-TD Stick (52009)", + { &dib0700_usb_id_table[35], NULL }, + { NULL }, + }, + { "Hauppauge Nova-TD-500 (84xxx)", + { &dib0700_usb_id_table[36], NULL }, + { NULL }, + }, + { "Terratec Cinergy DT USB XS Diversity/ T5", + { &dib0700_usb_id_table[43], + &dib0700_usb_id_table[53], NULL}, + { NULL }, + }, + { "Sony PlayTV", + { &dib0700_usb_id_table[44], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070pd_frontend_attach0, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7070pd_frontend_attach1, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 1, + .devices = { + { "Elgato EyeTV Diversity", + { &dib0700_usb_id_table[68], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_NEC_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7700ph_frontend_attach, + .tuner_attach = stk7700ph_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 9, + .devices = { + { "Terratec Cinergy HT USB XE", + { &dib0700_usb_id_table[27], NULL }, + { NULL }, + }, + { "Pinnacle Expresscard 320cx", + { &dib0700_usb_id_table[28], NULL }, + { NULL }, + }, + { "Terratec Cinergy HT Express", + { &dib0700_usb_id_table[32], NULL }, + { NULL }, + }, + { "Gigabyte U8000-RH", + { &dib0700_usb_id_table[37], NULL }, + { NULL }, + }, + { "YUAN High-Tech STK7700PH", + { &dib0700_usb_id_table[38], NULL }, + { NULL }, + }, + { "Asus My Cinema-U3000Hybrid", + { &dib0700_usb_id_table[39], NULL }, + { NULL }, + }, + { "YUAN High-Tech MC770", + { &dib0700_usb_id_table[48], NULL }, + { NULL }, + }, + { "Leadtek WinFast DTV Dongle H", + { &dib0700_usb_id_table[51], NULL }, + { NULL }, + }, + { "YUAN High-Tech STK7700D", + { &dib0700_usb_id_table[54], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .frontend_attach = s5h1411_frontend_attach, + .tuner_attach = xc5000_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "Pinnacle PCTV HD Pro USB Stick", + { &dib0700_usb_id_table[40], NULL }, + { NULL }, + }, + { "Pinnacle PCTV HD USB Stick", + { &dib0700_usb_id_table[41], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .frontend_attach = lgdt3305_frontend_attach, + .tuner_attach = mxl5007t_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "Hauppauge ATSC MiniCard (B200)", + { &dib0700_usb_id_table[46], NULL }, + { NULL }, + }, + { "Hauppauge ATSC MiniCard (B210)", + { &dib0700_usb_id_table[47], NULL }, + { NULL }, + }, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = stk7770p_frontend_attach, + .tuner_attach = dib7770p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 4, + .devices = { + { "DiBcom STK7770P reference design", + { &dib0700_usb_id_table[59], NULL }, + { NULL }, + }, + { "Terratec Cinergy T USB XXS (HD)/ T3", + { &dib0700_usb_id_table[33], + &dib0700_usb_id_table[52], + &dib0700_usb_id_table[60], NULL}, + { NULL }, + }, + { "TechniSat AirStar TeleStick 2", + { &dib0700_usb_id_table[74], NULL }, + { NULL }, + }, + { "Medion CTX1921 DVB-T USB", + { &dib0700_usb_id_table[75], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk807x_frontend_attach, + .tuner_attach = dib807x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 3, + .devices = { + { "DiBcom STK807xP reference design", + { &dib0700_usb_id_table[62], NULL }, + { NULL }, + }, + { "Prolink Pixelview SBTVD", + { &dib0700_usb_id_table[63], NULL }, + { NULL }, + }, + { "EvolutePC TVWay+", + { &dib0700_usb_id_table[64], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_NEC_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk807xpvr_frontend_attach0, + .tuner_attach = dib807x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk807xpvr_frontend_attach1, + .tuner_attach = dib807x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom STK807xPVR reference design", + { &dib0700_usb_id_table[61], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk809x_frontend_attach, + .tuner_attach = dib809x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom STK8096GP reference design", + { &dib0700_usb_id_table[67], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = dib90x0_pid_filter, + .pid_filter_ctrl = dib90x0_pid_filter_ctrl, + .frontend_attach = stk9090m_frontend_attach, + .tuner_attach = dib9090_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom STK9090M reference design", + { &dib0700_usb_id_table[69], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = nim8096md_frontend_attach, + .tuner_attach = nim8096md_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom NIM8096MD reference design", + { &dib0700_usb_id_table[70], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = dib90x0_pid_filter, + .pid_filter_ctrl = dib90x0_pid_filter_ctrl, + .frontend_attach = nim9090md_frontend_attach, + .tuner_attach = nim9090md_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom NIM9090MD reference design", + { &dib0700_usb_id_table[71], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = nim7090_frontend_attach, + .tuner_attach = nim7090_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom NIM7090 reference design", + { &dib0700_usb_id_table[72], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7090pvr_frontend0_attach, + .tuner_attach = tfe7090pvr_tuner0_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7090pvr_frontend1_attach, + .tuner_attach = tfe7090pvr_tuner1_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE7090PVR reference design", + { &dib0700_usb_id_table[73], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .frontend_attach = pctv340e_frontend_attach, + .tuner_attach = xc4000_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "Pinnacle PCTV 340e HD Pro USB Stick", + { &dib0700_usb_id_table[76], NULL }, + { NULL }, + }, + { "Pinnacle PCTV Hybrid Stick Solo", + { &dib0700_usb_id_table[77], NULL }, + { NULL }, + }, + }, + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, +}; + +int dib0700_device_count = ARRAY_SIZE(dib0700_devices); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib0700.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,73 @@ +/* Linux driver for devices based on the DiBcom DiB0700 USB bridge + * + * 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, version 2. + * + * Copyright (C) 2005-6 DiBcom, SA + */ +#ifndef _DIB0700_H_ +#define _DIB0700_H_ + +#define DVB_USB_LOG_PREFIX "dib0700" +#include "dvb-usb.h" + +#include "dib07x0.h" + +extern int dvb_usb_dib0700_debug; +#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args) +#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args) +#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) +#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) + +#define REQUEST_SET_USB_XFER_LEN 0x0 /* valid only for firmware version */ + /* higher than 1.21 */ +#define REQUEST_I2C_READ 0x2 +#define REQUEST_I2C_WRITE 0x3 +#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ +#define REQUEST_JUMPRAM 0x8 +#define REQUEST_SET_CLOCK 0xB +#define REQUEST_SET_GPIO 0xC +#define REQUEST_ENABLE_VIDEO 0xF + // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) + // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) + // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) +#define REQUEST_SET_I2C_PARAM 0x10 +#define REQUEST_SET_RC 0x11 +#define REQUEST_NEW_I2C_READ 0x12 +#define REQUEST_NEW_I2C_WRITE 0x13 +#define REQUEST_GET_VERSION 0x15 + +struct dib0700_state { + u8 channel_state; + u16 mt2060_if1[2]; + u8 rc_toggle; + u8 rc_counter; + u8 is_dib7000pc; + u8 fw_use_new_i2c_api; + u8 disable_streaming_master_mode; + u32 fw_version; + u32 nb_packet_buffer_size; + u8 buf[255]; +}; + +extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, + u32 *romversion, u32 *ramversion, u32 *fwtype); +extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); +extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); +extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); +extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); +extern int dib0700_rc_setup(struct dvb_usb_device *d); +extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); +extern struct i2c_algorithm dib0700_i2c_algo; +extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold); +extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type); +extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz); + +extern int dib0700_device_count; +extern int dvb_usb_dib0700_ir_proto; +extern struct dvb_usb_device_properties dib0700_devices[]; +extern struct usb_device_id dib0700_usb_id_table[]; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib07x0.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib07x0.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib07x0.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dib07x0.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,21 @@ +#ifndef _DIB07X0_H_ +#define _DIB07X0_H_ + +enum dib07x0_gpios { + GPIO0 = 0, + GPIO1 = 2, + GPIO2 = 3, + GPIO3 = 4, + GPIO4 = 5, + GPIO5 = 6, + GPIO6 = 8, + GPIO7 = 10, + GPIO8 = 11, + GPIO9 = 14, + GPIO10 = 15, +}; + +#define GPIO_IN 0 +#define GPIO_OUT 1 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-common.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-common.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,470 @@ +/* Common methods for dibusb-based-receivers. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS); +MODULE_LICENSE("GPL"); + +#define deb_info(args...) dprintk(debug,0x01,args) + +/* common stuff used by the different dibusb modules */ +int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + if (st->ops.fifo_ctrl != NULL) + if (st->ops.fifo_ctrl(adap->fe,onoff)) { + err("error while controlling the fifo of the demod."); + return -ENODEV; + } + } + return 0; +} +EXPORT_SYMBOL(dibusb_streaming_ctrl); + +int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) +{ + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + if (st->ops.pid_ctrl != NULL) + st->ops.pid_ctrl(adap->fe,index,pid,onoff); + } + return 0; +} +EXPORT_SYMBOL(dibusb_pid_filter); + +int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + if (st->ops.pid_parse != NULL) + if (st->ops.pid_parse(adap->fe,onoff) < 0) + err("could not handle pid_parser"); + } + return 0; +} +EXPORT_SYMBOL(dibusb_pid_filter_ctrl); + +int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b[3]; + int ret; + b[0] = DIBUSB_REQ_SET_IOCTL; + b[1] = DIBUSB_IOCTL_CMD_POWER_MODE; + b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP; + ret = dvb_usb_generic_write(d,b,3); + msleep(10); + return ret; +} +EXPORT_SYMBOL(dibusb_power_ctrl); + +int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + u8 b[3] = { 0 }; + int ret; + + if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0) + return ret; + + if (onoff) { + b[0] = DIBUSB_REQ_SET_STREAMING_MODE; + b[1] = 0x00; + if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0) + return ret; + } + + b[0] = DIBUSB_REQ_SET_IOCTL; + b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; + return dvb_usb_generic_write(adap->dev,b,3); +} +EXPORT_SYMBOL(dibusb2_0_streaming_ctrl); + +int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + if (onoff) { + u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP }; + return dvb_usb_generic_write(d,b,3); + } else + return 0; +} +EXPORT_SYMBOL(dibusb2_0_power_ctrl); + +static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ + /* write only ? */ + int wo = (rbuf == NULL || rlen == 0), + len = 2 + wlen + (wo ? 0 : 2); + + sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; + sndbuf[1] = (addr << 1) | (wo ? 0 : 1); + + memcpy(&sndbuf[2],wbuf,wlen); + + if (!wo) { + sndbuf[wlen+2] = (rlen >> 8) & 0xff; + sndbuf[wlen+3] = rlen & 0xff; + } + + return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0); +} + +/* + * I2C master xfer function + */ +static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0 + && (msg[i+1].flags & I2C_M_RD)) { + if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len, + msg[i+1].buf,msg[i+1].len) < 0) + break; + i++; + } else if ((msg[i].flags & I2C_M_RD) == 0) { + if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) + break; + } else if (msg[i].addr != 0x50) { + /* 0x50 is the address of the eeprom - we need to protect it + * from dibusb's bad i2c implementation: reads without + * writing the offset before are forbidden */ + if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0) + break; + } + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 dibusb_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +struct i2c_algorithm dibusb_i2c_algo = { + .master_xfer = dibusb_i2c_xfer, + .functionality = dibusb_i2c_func, +}; +EXPORT_SYMBOL(dibusb_i2c_algo); + +int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) +{ + u8 wbuf[1] = { offs }; + return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1); +} +EXPORT_SYMBOL(dibusb_read_eeprom_byte); + +/* 3000MC/P stuff */ +// Config Adjacent channels Perf -cal22 +static struct dibx000_agc_config dib3000p_mt2060_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 48497, + .agc1_min = 23593, + .agc2_max = 46531, + .agc2_min = 24904, + + .agc1_pt1 = 0x65, + .agc1_pt2 = 0x69, + + .agc1_slope1 = 0x51, + .agc1_slope2 = 0x27, + + .agc2_pt1 = 0, + .agc2_pt2 = 0x33, + + .agc2_slope1 = 0x35, + .agc2_slope2 = 0x37, +}; + +static struct dib3000mc_config stk3000p_dib3000p_config = { + &dib3000p_mt2060_agc_config, + + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + + .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, +}; + +static struct dibx000_agc_config dib3000p_panasonic_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 56361, + .agc1_min = 22282, + .agc2_max = 47841, + .agc2_min = 36045, + + .agc1_pt1 = 0x3b, + .agc1_pt2 = 0x6b, + + .agc1_slope1 = 0x55, + .agc1_slope2 = 0x1d, + + .agc2_pt1 = 0, + .agc2_pt2 = 0x0a, + + .agc2_slope1 = 0x95, + .agc2_slope2 = 0x1e, +}; + +#if defined(CONFIG_DVB_DIB3000MC) || \ + (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE)) + +static struct dib3000mc_config mod3000p_dib3000p_config = { + &dib3000p_panasonic_agc_config, + + .max_time = 0x51, + .ln_adc_level = 0x1cc7, + + .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, +}; + +int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && + adap->dev->udev->descriptor.idProduct == + USB_PID_LITEON_DVB_T_WARM) { + msleep(1000); + } + + if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || + (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + st->ops.pid_parse = dib3000mc_pid_parse; + st->ops.pid_ctrl = dib3000mc_pid_control; + } + return 0; + } + return -ENODEV; +} +EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); + +static struct mt2060_config stk3000p_mt2060_config = { + 0x60 +}; + +int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dibusb_state *st = adap->priv; + u8 a,b; + u16 if1 = 1220; + struct i2c_adapter *tun_i2c; + + // First IF calibration for Liteon Sticks + if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && + adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) { + + dibusb_read_eeprom_byte(adap->dev,0x7E,&a); + dibusb_read_eeprom_byte(adap->dev,0x7F,&b); + + if (a == 0x00) + if1 += b; + else if (a == 0x80) + if1 -= b; + else + warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); + + } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM && + adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) { + u8 desc; + dibusb_read_eeprom_byte(adap->dev, 7, &desc); + if (desc == 2) { + a = 127; + do { + dibusb_read_eeprom_byte(adap->dev, a, &desc); + a--; + } while (a > 7 && (desc == 0xff || desc == 0x00)); + if (desc & 0x80) + if1 -= (0xff - desc); + else + if1 += desc; + } + } + + tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); + if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { + /* not found - use panasonic pll parameters */ + if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) + return -ENOMEM; + } else { + st->mt2060_present = 1; + /* set the correct parameters for the dib3000p */ + dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config); + } + return 0; +} +EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); +#endif + +/* + * common remote control stuff + */ +struct rc_map_table rc_map_dibusb_table[] = { + /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */ + { 0x0016, KEY_POWER }, + { 0x0010, KEY_MUTE }, + { 0x0003, KEY_1 }, + { 0x0001, KEY_2 }, + { 0x0006, KEY_3 }, + { 0x0009, KEY_4 }, + { 0x001d, KEY_5 }, + { 0x001f, KEY_6 }, + { 0x000d, KEY_7 }, + { 0x0019, KEY_8 }, + { 0x001b, KEY_9 }, + { 0x0015, KEY_0 }, + { 0x0005, KEY_CHANNELUP }, + { 0x0002, KEY_CHANNELDOWN }, + { 0x001e, KEY_VOLUMEUP }, + { 0x000a, KEY_VOLUMEDOWN }, + { 0x0011, KEY_RECORD }, + { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */ + { 0x0014, KEY_PLAY }, + { 0x001a, KEY_STOP }, + { 0x0040, KEY_REWIND }, + { 0x0012, KEY_FASTFORWARD }, + { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */ + { 0x004c, KEY_PAUSE }, + { 0x004d, KEY_SCREEN }, /* Full screen mode. */ + { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ + /* additional keys TwinHan VisionPlus, the Artec seemingly not have */ + { 0x000c, KEY_CANCEL }, /* Cancel */ + { 0x001c, KEY_EPG }, /* EPG */ + { 0x0000, KEY_TAB }, /* Tab */ + { 0x0048, KEY_INFO }, /* Preview */ + { 0x0004, KEY_LIST }, /* RecordList */ + { 0x000f, KEY_TEXT }, /* Teletext */ + /* Key codes for the KWorld/ADSTech/JetWay remote. */ + { 0x8612, KEY_POWER }, + { 0x860f, KEY_SELECT }, /* source */ + { 0x860c, KEY_UNKNOWN }, /* scan */ + { 0x860b, KEY_EPG }, + { 0x8610, KEY_MUTE }, + { 0x8601, KEY_1 }, + { 0x8602, KEY_2 }, + { 0x8603, KEY_3 }, + { 0x8604, KEY_4 }, + { 0x8605, KEY_5 }, + { 0x8606, KEY_6 }, + { 0x8607, KEY_7 }, + { 0x8608, KEY_8 }, + { 0x8609, KEY_9 }, + { 0x860a, KEY_0 }, + { 0x8618, KEY_ZOOM }, + { 0x861c, KEY_UNKNOWN }, /* preview */ + { 0x8613, KEY_UNKNOWN }, /* snap */ + { 0x8600, KEY_UNDO }, + { 0x861d, KEY_RECORD }, + { 0x860d, KEY_STOP }, + { 0x860e, KEY_PAUSE }, + { 0x8616, KEY_PLAY }, + { 0x8611, KEY_BACK }, + { 0x8619, KEY_FORWARD }, + { 0x8614, KEY_UNKNOWN }, /* pip */ + { 0x8615, KEY_ESC }, + { 0x861a, KEY_UP }, + { 0x861e, KEY_DOWN }, + { 0x861f, KEY_LEFT }, + { 0x861b, KEY_RIGHT }, + + /* Key codes for the DiBcom MOD3000 remote. */ + { 0x8000, KEY_MUTE }, + { 0x8001, KEY_TEXT }, + { 0x8002, KEY_HOME }, + { 0x8003, KEY_POWER }, + + { 0x8004, KEY_RED }, + { 0x8005, KEY_GREEN }, + { 0x8006, KEY_YELLOW }, + { 0x8007, KEY_BLUE }, + + { 0x8008, KEY_DVD }, + { 0x8009, KEY_AUDIO }, + { 0x800a, KEY_IMAGES }, /* Pictures */ + { 0x800b, KEY_VIDEO }, + + { 0x800c, KEY_BACK }, + { 0x800d, KEY_UP }, + { 0x800e, KEY_RADIO }, + { 0x800f, KEY_EPG }, + + { 0x8010, KEY_LEFT }, + { 0x8011, KEY_OK }, + { 0x8012, KEY_RIGHT }, + { 0x8013, KEY_UNKNOWN }, /* SAP */ + + { 0x8014, KEY_TV }, + { 0x8015, KEY_DOWN }, + { 0x8016, KEY_MENU }, /* DVD Menu */ + { 0x8017, KEY_LAST }, + + { 0x8018, KEY_RECORD }, + { 0x8019, KEY_STOP }, + { 0x801a, KEY_PAUSE }, + { 0x801b, KEY_PLAY }, + + { 0x801c, KEY_PREVIOUS }, + { 0x801d, KEY_REWIND }, + { 0x801e, KEY_FASTFORWARD }, + { 0x801f, KEY_NEXT}, + + { 0x8040, KEY_1 }, + { 0x8041, KEY_2 }, + { 0x8042, KEY_3 }, + { 0x8043, KEY_CHANNELUP }, + + { 0x8044, KEY_4 }, + { 0x8045, KEY_5 }, + { 0x8046, KEY_6 }, + { 0x8047, KEY_CHANNELDOWN }, + + { 0x8048, KEY_7 }, + { 0x8049, KEY_8 }, + { 0x804a, KEY_9 }, + { 0x804b, KEY_VOLUMEUP }, + + { 0x804c, KEY_CLEAR }, + { 0x804d, KEY_0 }, + { 0x804e, KEY_ENTER }, + { 0x804f, KEY_VOLUMEDOWN }, +}; +EXPORT_SYMBOL(rc_map_dibusb_table); + +int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE; + dvb_usb_generic_rw(d,&cmd,1,key,5,0); + dvb_usb_nec_rc_key_to_event(d,key,event,state); + if (key[0] != 0) + deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + return 0; +} +EXPORT_SYMBOL(dibusb_rc_query); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,131 @@ +/* Header file for all dibusb-based-receivers. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_DIBUSB_H_ +#define _DVB_USB_DIBUSB_H_ + +#ifndef DVB_USB_LOG_PREFIX + #define DVB_USB_LOG_PREFIX "dibusb" +#endif +#include "dvb-usb.h" + +#include "dib3000.h" +#include "dib3000mc.h" +#include "mt2060.h" + +/* + * protocol of all dibusb related devices + */ + +/* + * bulk msg to/from endpoint 0x01 + * + * general structure: + * request_byte parameter_bytes + */ + +#define DIBUSB_REQ_START_READ 0x00 +#define DIBUSB_REQ_START_DEMOD 0x01 + +/* + * i2c read + * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word + * bulk read: byte_buffer (length_word bytes) + */ +#define DIBUSB_REQ_I2C_READ 0x02 + +/* + * i2c write + * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes + */ +#define DIBUSB_REQ_I2C_WRITE 0x03 + +/* + * polling the value of the remote control + * bulk write: 0x04 + * bulk read: byte_buffer (5 bytes) + */ +#define DIBUSB_REQ_POLL_REMOTE 0x04 + +/* additional status values for Hauppauge Remote Control Protocol */ +#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01 +#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03 + +/* streaming mode: + * bulk write: 0x05 mode_byte + * + * mode_byte is mostly 0x00 + */ +#define DIBUSB_REQ_SET_STREAMING_MODE 0x05 + +/* interrupt the internal read loop, when blocking */ +#define DIBUSB_REQ_INTR_READ 0x06 + +/* io control + * 0x07 cmd_byte param_bytes + * + * param_bytes can be up to 32 bytes + * + * cmd_byte function parameter name + * 0x00 power mode + * 0x00 sleep + * 0x01 wakeup + * + * 0x01 enable streaming + * 0x02 disable streaming + * + * + */ +#define DIBUSB_REQ_SET_IOCTL 0x07 + +/* IOCTL commands */ + +/* change the power mode in firmware */ +#define DIBUSB_IOCTL_CMD_POWER_MODE 0x00 +#define DIBUSB_IOCTL_POWER_SLEEP 0x00 +#define DIBUSB_IOCTL_POWER_WAKEUP 0x01 + +/* modify streaming of the FX2 */ +#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01 +#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02 + +struct dibusb_state { + struct dib_fe_xfer_ops ops; + int mt2060_present; + u8 tuner_addr; +}; + +struct dibusb_device_state { + /* for RC5 remote control */ + int old_toggle; + int last_repeat_count; +}; + +extern struct i2c_algorithm dibusb_i2c_algo; + +extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *); +extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *); + +extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int); +extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int); +extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int); +extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int); + +extern int dibusb_power_ctrl(struct dvb_usb_device *, int); +extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int); + +#define DEFAULT_RC_INTERVAL 150 +//#define DEFAULT_RC_INTERVAL 100000 + +extern struct rc_map_table rc_map_dibusb_table[]; +extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *); +extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-mb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-mb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-mb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-mb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,476 @@ +/* DVB USB compliant linux driver for mobile DVB-T USB devices based on + * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * based on GPL code from DiBcom, which has + * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dibusb_state *st = adap->priv; + + return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr); +} + +static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib3000_config demod_cfg; + struct dibusb_state *st = adap->priv; + + demod_cfg.demod_address = 0x8; + + if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg, + &adap->dev->i2c_adap, &st->ops)) == NULL) + return -ENODEV; + + adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; + + return 0; +} + +static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dibusb_state *st = adap->priv; + + st->tuner_addr = 0x61; + + dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap, + DVB_PLL_TUA6010XS); + return 0; +} + +static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dibusb_state *st = adap->priv; + + st->tuner_addr = 0x60; + + dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap, + DVB_PLL_TDA665X); + return 0; +} + +/* Some of the Artec 1.1 device aren't equipped with the default tuner + * (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures + * this out. */ +static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) +{ + u8 b[2] = { 0,0 }, b2[1]; + int ret = 0; + struct i2c_msg msg[2] = { + { .flags = 0, .buf = b, .len = 2 }, + { .flags = I2C_M_RD, .buf = b2, .len = 1 }, + }; + struct dibusb_state *st = adap->priv; + + /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ + msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; + + if (adap->fe->ops.i2c_gate_ctrl) + adap->fe->ops.i2c_gate_ctrl(adap->fe,1); + + if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { + err("tuner i2c write failed."); + ret = -EREMOTEIO; + } + + if (adap->fe->ops.i2c_gate_ctrl) + adap->fe->ops.i2c_gate_ctrl(adap->fe,0); + + if (b2[0] == 0xfe) { + info("This device has the Thomson Cable onboard. Which is default."); + ret = dibusb_thomson_tuner_attach(adap); + } else { + info("This device has the Panasonic ENV77H11D5 onboard."); + ret = dibusb_panasonic_tuner_attach(adap); + } + + return ret; +} + +/* USB Driver stuff */ +static struct dvb_usb_device_properties dibusb1_1_properties; +static struct dvb_usb_device_properties dibusb1_1_an2235_properties; +static struct dvb_usb_device_properties dibusb2_0b_properties; +static struct dvb_usb_device_properties artec_t1_usb2_properties; + +static int dibusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dibusb2_0b_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + + return -EINVAL; +} + +/* do not change the order of the ID table */ +static struct usb_device_id dibusb_dib3000mb_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM) }, +/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, +/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, +/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) }, +/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) }, +/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) }, +/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, +/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, +/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) }, +/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) }, +/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) }, +/* 12 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) }, +/* 13 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) }, +/* 14 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) }, +/* 15 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_COLD) }, +/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) }, +/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) }, +/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) }, +/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, +/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, +/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, +/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, +/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) }, + +/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ +/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, +/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, +/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, + +/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) }, + +/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, +/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, + +/* + * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices + * we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that + * have been left on the device. If you don't have such a device but an Artec + * device that's supposed to work with this driver but is not detected by it, + * free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config. + */ + +#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY +/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +#endif + + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); + +static struct dvb_usb_device_properties dibusb1_1_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_AN2135, + + .firmware = "dvb-usb-dibusb-5.0.0.11.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + + .power_ctrl = dibusb_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 9, + .devices = { + { "AVerMedia AverTV DVBT USB1.1", + { &dibusb_dib3000mb_table[0], NULL }, + { &dibusb_dib3000mb_table[1], NULL }, + }, + { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)", + { &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL}, + { &dibusb_dib3000mb_table[3], NULL }, + }, + { "DiBcom USB1.1 DVB-T reference design (MOD3000)", + { &dibusb_dib3000mb_table[5], NULL }, + { &dibusb_dib3000mb_table[6], NULL }, + }, + { "KWorld V-Stream XPERT DTV - DVB-T USB1.1", + { &dibusb_dib3000mb_table[7], NULL }, + { &dibusb_dib3000mb_table[8], NULL }, + }, + { "Grandtec USB1.1 DVB-T", + { &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL }, + { &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL }, + }, + { "Unknown USB1.1 DVB-T device ???? please report the name to the author", + { &dibusb_dib3000mb_table[13], NULL }, + { &dibusb_dib3000mb_table[14], NULL }, + }, + { "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device", + { &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL}, + { &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL}, + }, + { "Artec T1 USB1.1 TVBOX with AN2135", + { &dibusb_dib3000mb_table[19], NULL }, + { &dibusb_dib3000mb_table[20], NULL }, + }, + { "VideoWalker DVB-T USB", + { &dibusb_dib3000mb_table[25], NULL }, + { &dibusb_dib3000mb_table[26], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties dibusb1_1_an2235_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = CYPRESS_AN2235, + + .firmware = "dvb-usb-dibusb-an2235-01.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + }, + }, + .power_ctrl = dibusb_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + +#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY + .num_device_descs = 2, +#else + .num_device_descs = 1, +#endif + .devices = { + { "Artec T1 USB1.1 TVBOX with AN2235", + { &dibusb_dib3000mb_table[21], NULL }, + { &dibusb_dib3000mb_table[22], NULL }, + }, +#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY + { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", + { &dibusb_dib3000mb_table[30], NULL }, + { NULL }, + }, + { NULL }, +#endif + } +}; + +static struct dvb_usb_device_properties dibusb2_0b_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .firmware = "dvb-usb-adstech-usb2-02.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_thomson_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .power_ctrl = dibusb2_0_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 2, + .devices = { + { "KWorld/ADSTech Instant DVB-T USB2.0", + { &dibusb_dib3000mb_table[23], NULL }, + { &dibusb_dib3000mb_table[24], NULL }, + }, + { "KWorld Xpert DVB-T USB2.0", + { &dibusb_dib3000mb_table[27], NULL }, + { NULL } + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties artec_t1_usb2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .firmware = "dvb-usb-dibusb-6.0.0.8.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .power_ctrl = dibusb2_0_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Artec T1 USB2.0", + { &dibusb_dib3000mb_table[28], NULL }, + { &dibusb_dib3000mb_table[29], NULL }, + }, + { NULL }, + } +}; + +static struct usb_driver dibusb_driver = { + .name = "dvb_usb_dibusb_mb", + .probe = dibusb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dibusb_dib3000mb_table, +}; + +/* module stuff */ +static int __init dibusb_module_init(void) +{ + int result; + if ((result = usb_register(&dibusb_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit dibusb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&dibusb_driver); +} + +module_init (dibusb_module_init); +module_exit (dibusb_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,164 @@ +/* DVB USB compliant linux driver for mobile DVB-T USB devices based on + * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * based on GPL code from DiBcom, which has + * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* USB Driver stuff */ +static struct dvb_usb_device_properties dibusb_mc_properties; + +static int dibusb_mc_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &dibusb_mc_properties, THIS_MODULE, + NULL, adapter_nr); +} + +/* do not change the order of the ID table */ +static struct usb_device_id dibusb_dib3000mc_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) }, +/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, +/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? ) +/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) }, +/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) }, +/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) }, +/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) }, +/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) }, +/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) }, +/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) }, +/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) }, +/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) }, +/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) }, +/* 14 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD) }, +/* 15 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table); + +static struct dvb_usb_device_properties dibusb_mc_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-dibusb-6.0.0.8.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mc_frontend_attach, + .tuner_attach = dibusb_dib3000mc_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .power_ctrl = dibusb2_0_power_ctrl, + + .rc.legacy = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_map_table = rc_map_dibusb_table, + .rc_map_size = 111, /* FIXME */ + .rc_query = dibusb_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 8, + .devices = { + { "DiBcom USB2.0 DVB-T reference design (MOD3000P)", + { &dibusb_dib3000mc_table[0], NULL }, + { &dibusb_dib3000mc_table[1], NULL }, + }, + { "Artec T1 USB2.0 TVBOX (please check the warm ID)", + { &dibusb_dib3000mc_table[2], NULL }, + { &dibusb_dib3000mc_table[3], NULL }, + }, + { "LITE-ON USB2.0 DVB-T Tuner", + /* Also rebranded as Intuix S800, Toshiba */ + { &dibusb_dib3000mc_table[4], NULL }, + { &dibusb_dib3000mc_table[5], NULL }, + }, + { "MSI Digivox Mini SL", + { &dibusb_dib3000mc_table[6], NULL }, + { &dibusb_dib3000mc_table[7], NULL }, + }, + { "GRAND - USB2.0 DVB-T adapter", + { &dibusb_dib3000mc_table[8], NULL }, + { &dibusb_dib3000mc_table[9], NULL }, + }, + { "Artec T14 - USB2.0 DVB-T", + { &dibusb_dib3000mc_table[10], NULL }, + { &dibusb_dib3000mc_table[11], NULL }, + }, + { "Leadtek - USB2.0 Winfast DTV dongle", + { &dibusb_dib3000mc_table[12], NULL }, + { &dibusb_dib3000mc_table[13], NULL }, + }, + { "Humax/Coex DVB-T USB Stick 2.0 High Speed", + { &dibusb_dib3000mc_table[14], NULL }, + { &dibusb_dib3000mc_table[15], NULL }, + }, + { NULL }, + } +}; + +static struct usb_driver dibusb_mc_driver = { + .name = "dvb_usb_dibusb_mc", + .probe = dibusb_mc_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dibusb_dib3000mc_table, +}; + +/* module stuff */ +static int __init dibusb_mc_module_init(void) +{ + int result; + if ((result = usb_register(&dibusb_mc_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit dibusb_mc_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&dibusb_mc_driver); +} + +module_init (dibusb_mc_module_init); +module_exit (dibusb_mc_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/digitv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/digitv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/digitv.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/digitv.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,364 @@ +/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0 + * receiver + * + * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) + * + * partly based on the SDK published by Nebula Electronics + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "digitv.h" + +#include "mt352.h" +#include "nxt6000.h" + +/* debug */ +static int dvb_usb_digitv_debug; +module_param_named(debug,dvb_usb_digitv_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) + +static int digitv_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + u8 sndbuf[7],rcvbuf[7]; + memset(sndbuf,0,7); memset(rcvbuf,0,7); + + sndbuf[0] = cmd; + sndbuf[1] = vv; + sndbuf[2] = wo ? wlen : rlen; + + if (wo) { + memcpy(&sndbuf[3],wbuf,wlen); + dvb_usb_generic_write(d,sndbuf,7); + } else { + dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10); + memcpy(rbuf,&rcvbuf[3],rlen); + } + return 0; +} + +/* I2C */ +static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0, + msg[i+1].buf,msg[i+1].len) < 0) + break; + i++; + } else + if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0], + &msg[i].buf[1],msg[i].len-1,NULL,0) < 0) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 digitv_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm digitv_i2c_algo = { + .master_xfer = digitv_i2c_xfer, + .functionality = digitv_i2c_func, +}; + +/* Callbacks for DVB USB */ +static int digitv_identify_state (struct usb_device *udev, struct + dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, + int *cold) +{ + *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; + return 0; +} + +static int digitv_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 }; + static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50, + 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00, + 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f, + 0x75, 0x32 }; + int i; + + for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2) + mt352_write(fe, &reset_buf[i], 2); + + msleep(1); + + for (i = 0; i < ARRAY_SIZE(init_buf); i += 2) + mt352_write(fe, &init_buf[i], 2); + + return 0; +} + +static struct mt352_config digitv_mt352_config = { + .demod_init = digitv_mt352_demod_init, +}; + +static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + u8 b[5]; + + fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b)); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); +} + +static struct nxt6000_config digitv_nxt6000_config = { + .clock_inversion = 1, +}; + +static int digitv_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct digitv_state *st = adap->dev->priv; + + if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { + st->is_nxt6000 = 0; + return 0; + } + if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { + st->is_nxt6000 = 1; + return 0; + } + return -EIO; +} + +static int digitv_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct digitv_state *st = adap->dev->priv; + + if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4)) + return -ENODEV; + + if (st->is_nxt6000) + adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; + + return 0; +} + +static struct rc_map_table rc_map_digitv_table[] = { + { 0x5f55, KEY_0 }, + { 0x6f55, KEY_1 }, + { 0x9f55, KEY_2 }, + { 0xaf55, KEY_3 }, + { 0x5f56, KEY_4 }, + { 0x6f56, KEY_5 }, + { 0x9f56, KEY_6 }, + { 0xaf56, KEY_7 }, + { 0x5f59, KEY_8 }, + { 0x6f59, KEY_9 }, + { 0x9f59, KEY_TV }, + { 0xaf59, KEY_AUX }, + { 0x5f5a, KEY_DVD }, + { 0x6f5a, KEY_POWER }, + { 0x9f5a, KEY_CAMERA }, /* labelled 'Picture' */ + { 0xaf5a, KEY_AUDIO }, + { 0x5f65, KEY_INFO }, + { 0x6f65, KEY_F13 }, /* 16:9 */ + { 0x9f65, KEY_F14 }, /* 14:9 */ + { 0xaf65, KEY_EPG }, + { 0x5f66, KEY_EXIT }, + { 0x6f66, KEY_MENU }, + { 0x9f66, KEY_UP }, + { 0xaf66, KEY_DOWN }, + { 0x5f69, KEY_LEFT }, + { 0x6f69, KEY_RIGHT }, + { 0x9f69, KEY_ENTER }, + { 0xaf69, KEY_CHANNELUP }, + { 0x5f6a, KEY_CHANNELDOWN }, + { 0x6f6a, KEY_VOLUMEUP }, + { 0x9f6a, KEY_VOLUMEDOWN }, + { 0xaf6a, KEY_RED }, + { 0x5f95, KEY_GREEN }, + { 0x6f95, KEY_YELLOW }, + { 0x9f95, KEY_BLUE }, + { 0xaf95, KEY_SUBTITLE }, + { 0x5f96, KEY_F15 }, /* AD */ + { 0x6f96, KEY_TEXT }, + { 0x9f96, KEY_MUTE }, + { 0xaf96, KEY_REWIND }, + { 0x5f99, KEY_STOP }, + { 0x6f99, KEY_PLAY }, + { 0x9f99, KEY_FASTFORWARD }, + { 0xaf99, KEY_F16 }, /* chapter */ + { 0x5f9a, KEY_PAUSE }, + { 0x6f9a, KEY_PLAY }, + { 0x9f9a, KEY_RECORD }, + { 0xaf9a, KEY_F17 }, /* picture in picture */ + { 0x5fa5, KEY_KPPLUS }, /* zoom in */ + { 0x6fa5, KEY_KPMINUS }, /* zoom out */ + { 0x9fa5, KEY_F18 }, /* capture */ + { 0xafa5, KEY_F19 }, /* web */ + { 0x5fa6, KEY_EMAIL }, + { 0x6fa6, KEY_PHONE }, + { 0x9fa6, KEY_PC }, +}; + +static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + int i; + u8 key[5]; + u8 b[4] = { 0 }; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4); + + /* Tell the device we've read the remote. Not sure how necessary + this is, but the Nebula SDK does it. */ + digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); + + /* if something is inside the buffer, simulate key press */ + if (key[1] != 0) + { + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] && + rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) { + *event = d->props.rc.legacy.rc_map_table[i].keycode; + *state = REMOTE_KEY_PRESSED; + return 0; + } + } + } + + if (key[0] != 0) + deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + return 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties digitv_properties; + +static int digitv_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d, + adapter_nr); + if (ret == 0) { + u8 b[4] = { 0 }; + + if (d != NULL) { /* do that only when the firmware is loaded */ + b[0] = 1; + digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0); + + b[0] = 0; + digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); + } + } + return ret; +} + +static struct usb_device_id digitv_table [] = { + { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, digitv_table); + +static struct dvb_usb_device_properties digitv_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-digitv-02.fw", + + .size_of_priv = sizeof(struct digitv_state), + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = digitv_frontend_attach, + .tuner_attach = digitv_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .identify_state = digitv_identify_state, + + .rc.legacy = { + .rc_interval = 1000, + .rc_map_table = rc_map_digitv_table, + .rc_map_size = ARRAY_SIZE(rc_map_digitv_table), + .rc_query = digitv_rc_query, + }, + + .i2c_algo = &digitv_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Nebula Electronics uDigiTV DVB-T USB2.0)", + { &digitv_table[0], NULL }, + { NULL }, + }, + { NULL }, + } +}; + +static struct usb_driver digitv_driver = { + .name = "dvb_usb_digitv", + .probe = digitv_probe, + .disconnect = dvb_usb_device_exit, + .id_table = digitv_table, +}; + +/* module stuff */ +static int __init digitv_module_init(void) +{ + int result; + if ((result = usb_register(&digitv_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit digitv_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&digitv_driver); +} + +module_init (digitv_module_init); +module_exit (digitv_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/digitv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/digitv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/digitv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/digitv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,66 @@ +#ifndef _DVB_USB_DIGITV_H_ +#define _DVB_USB_DIGITV_H_ + +#define DVB_USB_LOG_PREFIX "digitv" +#include "dvb-usb.h" + +struct digitv_state { + int is_nxt6000; +}; + +/* protocol (from usblogging and the SDK: + * + * Always 7 bytes bulk message(s) for controlling + * + * First byte describes the command. Reads are 2 consecutive transfer (as always). + * + * General structure: + * + * write or first message of a read: + * VV B0 B1 B2 B3 + * + * second message of a read + * VV R0 R1 R2 R3 + * + * whereas 0 < len <= 4 + * + * I2C address is stored somewhere inside the device. + * + * 0x01 read from EEPROM + * VV = offset; B* = 0; R* = value(s) + * + * 0x02 read register of the COFDM + * VV = register; B* = 0; R* = value(s) + * + * 0x05 write register of the COFDM + * VV = register; B* = value(s); + * + * 0x06 write to the tuner (only for NXT6000) + * VV = 0; B* = PLL data; len = 4; + * + * 0x03 read remote control + * VV = 0; B* = 0; len = 4; R* = key + * + * 0x07 write to the remote (don't know why one should this, resetting ?) + * VV = 0; B* = key; len = 4; + * + * 0x08 write remote type + * VV = 0; B[0] = 0x01, len = 4 + * + * 0x09 write device init + * TODO + */ +#define USB_READ_EEPROM 1 + +#define USB_READ_COFDM 2 +#define USB_WRITE_COFDM 5 + +#define USB_WRITE_TUNER 6 + +#define USB_READ_REMOTE 3 +#define USB_WRITE_REMOTE 7 +#define USB_WRITE_REMOTE_TYPE 8 + +#define USB_DEV_INIT 9 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,374 @@ +/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to Steve Chang from WideView for providing support for the WT-220U. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dtt200u.h" + +/* debug */ +int dvb_usb_dtt200u_debug; +module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = SET_INIT; + + if (onoff) + dvb_usb_generic_write(d,&b,2); + + return 0; +} + +static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + u8 b_streaming[2] = { SET_STREAMING, onoff }; + u8 b_rst_pid = RESET_PID_FILTER; + + dvb_usb_generic_write(adap->dev, b_streaming, 2); + + if (onoff == 0) + dvb_usb_generic_write(adap->dev, &b_rst_pid, 1); + return 0; +} + +static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) +{ + u8 b_pid[4]; + pid = onoff ? pid : 0; + + b_pid[0] = SET_PID_FILTER; + b_pid[1] = index; + b_pid[2] = pid & 0xff; + b_pid[3] = (pid >> 8) & 0x1f; + + return dvb_usb_generic_write(adap->dev, b_pid, 4); +} + +/* remote control */ +/* key list for the tiny remote control (Yakumo, don't know about the others) */ +static struct rc_map_table rc_map_dtt200u_table[] = { + { 0x8001, KEY_MUTE }, + { 0x8002, KEY_CHANNELDOWN }, + { 0x8003, KEY_VOLUMEDOWN }, + { 0x8004, KEY_1 }, + { 0x8005, KEY_2 }, + { 0x8006, KEY_3 }, + { 0x8007, KEY_4 }, + { 0x8008, KEY_5 }, + { 0x8009, KEY_6 }, + { 0x800a, KEY_7 }, + { 0x800c, KEY_ZOOM }, + { 0x800d, KEY_0 }, + { 0x800e, KEY_SELECT }, + { 0x8012, KEY_POWER }, + { 0x801a, KEY_CHANNELUP }, + { 0x801b, KEY_8 }, + { 0x801e, KEY_VOLUMEUP }, + { 0x801f, KEY_9 }, +}; + +static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[5],cmd = GET_RC_CODE; + dvb_usb_generic_rw(d,&cmd,1,key,5,0); + dvb_usb_nec_rc_key_to_event(d,key,event,state); + if (key[0] != 0) + deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + return 0; +} + +static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe = dtt200u_fe_attach(adap->dev); + return 0; +} + +static struct dvb_usb_device_properties dtt200u_properties; +static struct dvb_usb_device_properties wt220u_fc_properties; +static struct dvb_usb_device_properties wt220u_properties; +static struct dvb_usb_device_properties wt220u_zl0353_properties; +static struct dvb_usb_device_properties wt220u_miglia_properties; + +static int dtt200u_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &dtt200u_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &wt220u_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &wt220u_fc_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &wt220u_miglia_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + + return -ENODEV; +} + +static struct usb_device_id dtt200u_usb_table [] = { + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, + { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); + +static struct dvb_usb_device_properties dtt200u_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-dtt200u-01.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc.legacy = { + .rc_interval = 300, + .rc_map_table = rc_map_dtt200u_table, + .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_query = dtt200u_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)", + .cold_ids = { &dtt200u_usb_table[0], NULL }, + .warm_ids = { &dtt200u_usb_table[1], NULL }, + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties wt220u_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-02.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc.legacy = { + .rc_interval = 300, + .rc_map_table = rc_map_dtt200u_table, + .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_query = dtt200u_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", + .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL }, + .warm_ids = { &dtt200u_usb_table[3], NULL }, + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties wt220u_fc_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-fc03.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc.legacy = { + .rc_interval = 300, + .rc_map_table = rc_map_dtt200u_table, + .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_query = dtt200u_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", + .cold_ids = { &dtt200u_usb_table[6], NULL }, + .warm_ids = { &dtt200u_usb_table[7], NULL }, + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties wt220u_zl0353_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-zl0353-01.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc.legacy = { + .rc_interval = 300, + .rc_map_table = rc_map_dtt200u_table, + .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_query = dtt200u_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (based on ZL353)", + .cold_ids = { &dtt200u_usb_table[4], NULL }, + .warm_ids = { &dtt200u_usb_table[5], NULL }, + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties wt220u_miglia_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-miglia-01.fw", + + .num_adapters = 1, + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Miglia)", + .cold_ids = { &dtt200u_usb_table[9], NULL }, + /* This device turns into WT220U_ZL0353_WARM when fw + has been uploaded */ + .warm_ids = { NULL }, + }, + { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver dtt200u_usb_driver = { + .name = "dvb_usb_dtt200u", + .probe = dtt200u_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dtt200u_usb_table, +}; + +/* module stuff */ +static int __init dtt200u_usb_module_init(void) +{ + int result; + if ((result = usb_register(&dtt200u_usb_driver))) { + err("usb_register failed. (%d)",result); + return result; + } + + return 0; +} + +static void __exit dtt200u_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&dtt200u_usb_driver); +} + +module_init(dtt200u_usb_module_init); +module_exit(dtt200u_usb_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u-fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u-fe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,205 @@ +/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. + * + * Copyright (C) 2005 Patrick Boettcher + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dtt200u.h" + +struct dtt200u_fe_state { + struct dvb_usb_device *d; + + fe_status_t stat; + + struct dvb_frontend_parameters fep; + struct dvb_frontend frontend; +}; + +static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 st = GET_TUNE_STATUS, b[3]; + + dvb_usb_generic_rw(state->d,&st,1,b,3,0); + + switch (b[0]) { + case 0x01: + *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + break; + case 0x00: /* pending */ + *stat = FE_TIMEDOUT; /* during set_frontend */ + break; + default: + case 0x02: /* failed */ + *stat = 0; + break; + } + return 0; +} + +static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 bw = GET_VIT_ERR_CNT,b[3]; + dvb_usb_generic_rw(state->d,&bw,1,b,3,0); + *ber = (b[0] << 16) | (b[1] << 8) | b[2]; + return 0; +} + +static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 bw = GET_RS_UNCOR_BLK_CNT,b[2]; + + dvb_usb_generic_rw(state->d,&bw,1,b,2,0); + *unc = (b[0] << 8) | b[1]; + return 0; +} + +static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 bw = GET_AGC, b; + dvb_usb_generic_rw(state->d,&bw,1,&b,1,0); + *strength = (b << 8) | b; + return 0; +} + +static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 bw = GET_SNR,br; + dvb_usb_generic_rw(state->d,&bw,1,&br,1,0); + *snr = ~((br << 8) | br); + return 0; +} + +static int dtt200u_fe_init(struct dvb_frontend* fe) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + u8 b = SET_INIT; + return dvb_usb_generic_write(state->d,&b,1); +} + +static int dtt200u_fe_sleep(struct dvb_frontend* fe) +{ + return dtt200u_fe_init(fe); +} + +static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1500; + tune->step_size = 0; + tune->max_drift = 0; + return 0; +} + +static int dtt200u_fe_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + int i; + fe_status_t st; + u16 freq = fep->frequency / 250000; + u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 }; + + switch (fep->u.ofdm.bandwidth) { + case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break; + case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break; + case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break; + case BANDWIDTH_AUTO: return -EOPNOTSUPP; + default: + return -EINVAL; + } + + dvb_usb_generic_write(state->d,bwbuf,2); + + freqbuf[1] = freq & 0xff; + freqbuf[2] = (freq >> 8) & 0xff; + dvb_usb_generic_write(state->d,freqbuf,3); + + for (i = 0; i < 30; i++) { + msleep(20); + dtt200u_fe_read_status(fe, &st); + if (st & FE_TIMEDOUT) + continue; + } + + return 0; +} + +static int dtt200u_fe_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct dtt200u_fe_state *state = fe->demodulator_priv; + memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters)); + return 0; +} + +static void dtt200u_fe_release(struct dvb_frontend* fe) +{ + struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops dtt200u_fe_ops; + +struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d) +{ + struct dtt200u_fe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL); + if (state == NULL) + goto error; + + deb_info("attaching frontend dtt200u\n"); + + state->d = d; + + memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; +error: + return NULL; +} + +static struct dvb_frontend_ops dtt200u_fe_ops = { + .info = { + .name = "WideView USB DVB-T", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = dtt200u_fe_release, + + .init = dtt200u_fe_init, + .sleep = dtt200u_fe_sleep, + + .set_frontend = dtt200u_fe_set_frontend, + .get_frontend = dtt200u_fe_get_frontend, + .get_tune_settings = dtt200u_fe_get_tune_settings, + + .read_status = dtt200u_fe_read_status, + .read_ber = dtt200u_fe_read_ber, + .read_signal_strength = dtt200u_fe_read_signal_strength, + .read_snr = dtt200u_fe_read_snr, + .read_ucblocks = dtt200u_fe_read_unc_blocks, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtt200u.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,57 @@ +/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_DTT200U_H_ +#define _DVB_USB_DTT200U_H_ + +#define DVB_USB_LOG_PREFIX "dtt200u" + +#include "dvb-usb.h" + +extern int dvb_usb_dtt200u_debug; +#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args) + +/* guessed protocol description (reverse engineered): + * read + * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1 + * 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal) + */ + +#define GET_SPEED 0x00 +#define GET_TUNE_STATUS 0x81 +#define GET_RC_CODE 0x84 +#define GET_CONFIGURATION 0x88 +#define GET_AGC 0x89 +#define GET_SNR 0x8a +#define GET_VIT_ERR_CNT 0x8c +#define GET_RS_ERR_CNT 0x8d +#define GET_RS_UNCOR_BLK_CNT 0x8e + +/* write + * 01 - init + * 02 - frequency (divided by 250000) + * 03 - bandwidth + * 04 - pid table (index pid(7:0) pid(12:8)) + * 05 - reset the pid table + * 08 - transfer switch + */ + +#define SET_INIT 0x01 +#define SET_RF_FREQ 0x02 +#define SET_BANDWIDTH 0x03 +#define SET_PID_FILTER 0x04 +#define RESET_PID_FILTER 0x05 +#define SET_STREAMING 0x08 + +extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtv5100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtv5100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtv5100.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtv5100.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,240 @@ +/* + * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T + * + * Copyright (C) 2008 Antoine Jacquet + * http://royale.zerezo.com/dtv5100/ + * + * Inspired by gl861.c and au6610.c drivers + * + * 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, or + * (at your option) any later version. + * + * 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 "dtv5100.h" +#include "zl10353.h" +#include "qt1010.h" + +/* debug */ +static int dvb_usb_dtv5100_debug; +module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 request; + u8 type; + u16 value; + u16 index; + + switch (wlen) { + case 1: + /* write { reg }, read { value } */ + request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ : + DTV5100_TUNER_READ); + type = USB_TYPE_VENDOR | USB_DIR_IN; + value = 0; + break; + case 2: + /* write { reg, value } */ + request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE : + DTV5100_TUNER_WRITE); + type = USB_TYPE_VENDOR | USB_DIR_OUT; + value = wbuf[1]; + break; + default: + warn("wlen = %x, aborting.", wlen); + return -EINVAL; + } + index = (addr << 8) + wbuf[0]; + + msleep(1); /* avoid I2C errors */ + return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request, + type, value, index, rbuf, rlen, + DTV5100_USB_TIMEOUT); +} + +/* I2C */ +static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, msg[i+1].buf, + msg[i+1].len) < 0) + break; + i++; + } else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, NULL, 0) < 0) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 dtv5100_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dtv5100_i2c_algo = { + .master_xfer = dtv5100_i2c_xfer, + .functionality = dtv5100_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config dtv5100_zl10353_config = { + .demod_address = DTV5100_DEMOD_ADDR, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe == NULL) + return -EIO; + + /* disable i2c gate, or it won't work... is this safe? */ + adap->fe->ops.i2c_gate_ctrl = NULL; + + return 0; +} + +static struct qt1010_config dtv5100_qt1010_config = { + .i2c_address = DTV5100_TUNER_ADDR +}; + +static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(qt1010_attach, + adap->fe, &adap->dev->i2c_adap, + &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties dtv5100_properties; + +static int dtv5100_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int i, ret; + struct usb_device *udev = interface_to_usbdev(intf); + + /* initialize non qt1010/zl10353 part? */ + for (i = 0; dtv5100_init[i].request; i++) { + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + dtv5100_init[i].request, + USB_TYPE_VENDOR | USB_DIR_OUT, + dtv5100_init[i].value, + dtv5100_init[i].index, NULL, 0, + DTV5100_USB_TIMEOUT); + if (ret) + return ret; + } + + ret = dvb_usb_device_init(intf, &dtv5100_properties, + THIS_MODULE, NULL, adapter_nr); + if (ret) + return ret; + + return 0; +} + +static struct usb_device_id dtv5100_table[] = { + { USB_DEVICE(0x06be, 0xa232) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, dtv5100_table); + +static struct dvb_usb_device_properties dtv5100_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = 0, + + .num_adapters = 1, + .adapter = {{ + .frontend_attach = dtv5100_frontend_attach, + .tuner_attach = dtv5100_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } }, + + .i2c_algo = &dtv5100_i2c_algo, + + .num_device_descs = 1, + .devices = { + { + .name = "AME DTV-5100 USB2.0 DVB-T", + .cold_ids = { NULL }, + .warm_ids = { &dtv5100_table[0], NULL }, + }, + } +}; + +static struct usb_driver dtv5100_driver = { + .name = "dvb_usb_dtv5100", + .probe = dtv5100_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dtv5100_table, +}; + +/* module stuff */ +static int __init dtv5100_module_init(void) +{ + int ret; + + ret = usb_register(&dtv5100_driver); + if (ret) + err("usb_register failed. Error number %d", ret); + + return ret; +} + +static void __exit dtv5100_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&dtv5100_driver); +} + +module_init(dtv5100_module_init); +module_exit(dtv5100_module_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtv5100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtv5100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtv5100.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dtv5100.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T + * + * Copyright (C) 2008 Antoine Jacquet + * http://royale.zerezo.com/dtv5100/ + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#ifndef _DVB_USB_DTV5100_H_ +#define _DVB_USB_DTV5100_H_ + +#define DVB_USB_LOG_PREFIX "dtv5100" +#include "dvb-usb.h" + +#define DTV5100_USB_TIMEOUT 500 + +#define DTV5100_DEMOD_ADDR 0x00 +#define DTV5100_DEMOD_WRITE 0xc0 +#define DTV5100_DEMOD_READ 0xc1 + +#define DTV5100_TUNER_ADDR 0xc4 +#define DTV5100_TUNER_WRITE 0xc7 +#define DTV5100_TUNER_READ 0xc8 + +#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" +#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T" + +static struct { + u8 request; + u8 value; + u16 index; +} dtv5100_init[] = { + { 0x000000c5, 0x00000000, 0x00000001 }, + { 0x000000c5, 0x00000001, 0x00000001 }, + { } /* Terminating entry */ +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-common.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-common.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* dvb-usb-common.h is part of the DVB USB library. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * a header file containing prototypes and types for internal use of the dvb-usb-lib + */ +#ifndef _DVB_USB_COMMON_H_ +#define _DVB_USB_COMMON_H_ + +#define DVB_USB_LOG_PREFIX "dvb-usb" +#include "dvb-usb.h" + +extern int dvb_usb_debug; +extern int dvb_usb_disable_rc_polling; + +#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args) +#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args) +#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args) +#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args) +#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args) +#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args) +#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args) +#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args) +#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args) + +/* commonly used methods */ +extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *); + +extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); + +extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props); +extern int usb_urb_exit(struct usb_data_stream *stream); +extern int usb_urb_submit(struct usb_data_stream *stream); +extern int usb_urb_kill(struct usb_data_stream *stream); + +extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap); + +extern int dvb_usb_i2c_init(struct dvb_usb_device *); +extern int dvb_usb_i2c_exit(struct dvb_usb_device *); + +extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, + short *adapter_nums); +extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap); + +extern int dvb_usb_remote_init(struct dvb_usb_device *); +extern int dvb_usb_remote_exit(struct dvb_usb_device *); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,216 @@ +/* dvb-usb-dvb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for initializing and handling the + * linux-dvb API. + */ +#include "dvb-usb-common.h" + +/* does the complete input transfer handling */ +static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + int newfeedcount, ret; + + if (adap == NULL) + return -ENODEV; + + newfeedcount = adap->feedcount + (onoff ? 1 : -1); + + /* stop feed before setting a new pid if there will be no pid anymore */ + if (newfeedcount == 0) { + deb_ts("stop feeding\n"); + usb_urb_kill(&adap->stream); + + if (adap->props.streaming_ctrl != NULL) { + ret = adap->props.streaming_ctrl(adap, 0); + if (ret < 0) { + err("error while stopping stream."); + return ret; + } + } + } + + adap->feedcount = newfeedcount; + + /* activate the pid on the device specific pid_filter */ + deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->pid_filtering ? + "yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? + "on" : "off"); + if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->pid_filtering && + adap->props.pid_filter != NULL) + adap->props.pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid,onoff); + + /* start the feed if this was the first feed and there is still a feed + * for reception. + */ + if (adap->feedcount == onoff && adap->feedcount > 0) { + deb_ts("submitting all URBs\n"); + usb_urb_submit(&adap->stream); + + deb_ts("controlling pid parser\n"); + if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props.caps & + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props.pid_filter_ctrl != NULL) { + ret = adap->props.pid_filter_ctrl(adap, + adap->pid_filtering); + if (ret < 0) { + err("could not handle pid_parser"); + return ret; + } + } + deb_ts("start feeding\n"); + if (adap->props.streaming_ctrl != NULL) { + ret = adap->props.streaming_ctrl(adap, 1); + if (ret < 0) { + err("error while enabling fifo."); + return ret; + } + } + + } + return 0; +} + +static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); + return dvb_usb_ctrl_feed(dvbdmxfeed,1); +} + +static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); + return dvb_usb_ctrl_feed(dvbdmxfeed,0); +} + +int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) +{ + int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, + adap->dev->owner, &adap->dev->udev->dev, + adapter_nums); + + if (ret < 0) { + deb_info("dvb_register_adapter failed: error %d", ret); + goto err; + } + adap->dvb_adap.priv = adap; + adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override; + + if (adap->dev->props.read_mac_address) { + if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) + info("MAC address: %pM",adap->dvb_adap.proposed_mac); + else + err("MAC address reading failed."); + } + + + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + + adap->demux.feednum = adap->demux.filternum = adap->max_feed_count; + adap->demux.start_feed = dvb_usb_start_feed; + adap->demux.stop_feed = dvb_usb_stop_feed; + adap->demux.write_to_decoder = NULL; + if ((ret = dvb_dmx_init(&adap->demux)) < 0) { + err("dvb_dmx_init failed: error %d",ret); + goto err_dmx; + } + + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) { + err("dvb_dmxdev_init failed: error %d",ret); + goto err_dmx_dev; + } + + dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + + adap->state |= DVB_USB_ADAP_STATE_DVB; + return 0; + +err_dmx_dev: + dvb_dmx_release(&adap->demux); +err_dmx: + dvb_unregister_adapter(&adap->dvb_adap); +err: + return ret; +} + +int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) +{ + if (adap->state & DVB_USB_ADAP_STATE_DVB) { + deb_info("unregistering DVB part\n"); + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + adap->state &= ~DVB_USB_ADAP_STATE_DVB; + } + return 0; +} + +static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + dvb_usb_device_power_ctrl(adap->dev, 1); + + if (adap->fe_init) + adap->fe_init(fe); + + return 0; +} + +static int dvb_usb_fe_sleep(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + if (adap->fe_sleep) + adap->fe_sleep(fe); + + return dvb_usb_device_power_ctrl(adap->dev, 0); +} + +int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) +{ + if (adap->props.frontend_attach == NULL) { + err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id); + return 0; + } + + /* re-assign sleep and wakeup functions */ + if (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) { + adap->fe_init = adap->fe->ops.init; adap->fe->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep; + + if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { + err("Frontend registration failed."); + dvb_frontend_detach(adap->fe); + adap->fe = NULL; + return -ENODEV; + } + + /* only attach the tuner if the demod is there */ + if (adap->props.tuner_attach != NULL) + adap->props.tuner_attach(adap); + } else + err("no frontend was attached by '%s'",adap->dev->desc->name); + + return 0; +} + +int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) +{ + if (adap->fe != NULL) { + dvb_unregister_frontend(adap->fe); + dvb_frontend_detach(adap->fe); + } + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,146 @@ +/* dvb-usb-firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices. + * + * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem. + */ +#include "dvb-usb-common.h" + +#include + +struct usb_cypress_controller { + int id; + const char *name; /* name of the usb controller */ + u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */ +}; + +static struct usb_cypress_controller cypress[] = { + { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 }, + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, +}; + +/* + * load a firmware packet to the device + */ +static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev,0), + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); +} + +int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) +{ + struct hexline hx; + u8 reset; + int ret,pos=0; + + /* stop the CPU */ + reset = 1; + if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) + err("could not stop the USB controller CPU."); + + while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) { + deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); + ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); + + if (ret != hx.len) { + err("error while transferring firmware " + "(transferred size: %d, block size: %d)", + ret,hx.len); + ret = -EINVAL; + break; + } + } + if (ret < 0) { + err("firmware download failed at %d with %d",pos,ret); + return ret; + } + + if (ret == 0) { + /* restart the CPU */ + reset = 0; + if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + } else + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL(usb_cypress_load_firmware); + +int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props) +{ + int ret; + const struct firmware *fw = NULL; + + if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + props->firmware,ret); + return ret; + } + + info("downloading firmware from file '%s'",props->firmware); + + switch (props->usb_ctrl) { + case CYPRESS_AN2135: + case CYPRESS_AN2235: + case CYPRESS_FX2: + ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl); + break; + case DEVICE_SPECIFIC: + if (props->download_firmware) + ret = props->download_firmware(udev,fw); + else { + err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one."); + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + break; + } + + release_firmware(fw); + return ret; +} + +int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, + int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + if (*pos >= fw->size) + return 0; + + memset(hx,0,sizeof(struct hexline)); + + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = b[1] | (b[2] << 8); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); +/* hx->len -= 2; + data_offs += 2; */ + } + memcpy(hx->data,&b[data_offs],hx->len); + hx->chk = b[hx->len + data_offs]; + + *pos += hx->len + 5; + + return *pos; +} +EXPORT_SYMBOL(dvb_usb_get_hexline); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,463 @@ +/* dvb-usb.h is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * the headerfile, all dvb-usb-drivers have to include. + * + * TODO: clean-up the structures for unused fields and update the comments + */ +#ifndef __DVB_USB_H__ +#define __DVB_USB_H__ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb_demux.h" +#include "dvb_net.h" +#include "dmxdev.h" + +#include "dvb-pll.h" + +#include "dvb-usb-ids.h" + +/* debug */ +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var,level,args...) \ + do { if ((var & level)) { printk(args); } } while (0) + +#define debug_dump(b,l,func) {\ + int loop_; \ + for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \ + func("\n");\ +} +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define debug_dump(b,l,func) + +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" + +#endif + +/* generic log methods - taken from usb.h */ +#ifndef DVB_USB_LOG_PREFIX + #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)" +#endif + +#undef err +#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) + +/** + * struct dvb_usb_device_description - name and its according USB IDs + * @name: real name of the box, regardless which DVB USB device class is in use + * @cold_ids: array of struct usb_device_id which describe the device in + * pre-firmware state + * @warm_ids: array of struct usb_device_id which describe the device in + * post-firmware state + * + * Each DVB USB device class can have one or more actual devices, this struct + * assigns a name to it. + */ +struct dvb_usb_device_description { + const char *name; + +#define DVB_USB_ID_MAX_NUM 15 + struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM]; + struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM]; +}; + +static inline u8 rc5_custom(struct rc_map_table *key) +{ + return (key->scancode >> 8) & 0xff; +} + +static inline u8 rc5_data(struct rc_map_table *key) +{ + return key->scancode & 0xff; +} + +static inline u16 rc5_scan(struct rc_map_table *key) +{ + return key->scancode & 0xffff; +} + +struct dvb_usb_device; +struct dvb_usb_adapter; +struct usb_data_stream; + +/** + * Properties of USB streaming - TODO this structure should be somewhere else + * describes the kind of USB transfer used for data-streaming. + * (BULK or ISOC) + */ +struct usb_data_stream_properties { +#define USB_BULK 1 +#define USB_ISOC 2 + int type; + int count; + int endpoint; + + union { + struct { + int buffersize; /* per URB */ + } bulk; + struct { + int framesperurb; + int framesize; + int interval; + } isoc; + } u; +}; + +/** + * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. + * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device. + * @caps: capabilities of the DVB USB device. + * @pid_filter_count: number of PID filter position in the optional hardware + * PID-filter. + * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the + * device (not URB submitting/killing). + * @pid_filter_ctrl: called to en/disable the PID filter, if any. + * @pid_filter: called to set/unset a PID for filtering. + * @frontend_attach: called to attach the possible frontends (fill fe-field + * of struct dvb_usb_device). + * @tuner_attach: called to attach the correct tuner and to fill pll_addr, + * pll_desc and pll_init_buf of struct dvb_usb_device). + * @stream: configuration of the USB streaming + */ +struct dvb_usb_adapter_properties { +#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 +#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 +#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 +#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 + int caps; + int pid_filter_count; + + int (*streaming_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); + + int (*frontend_attach) (struct dvb_usb_adapter *); + int (*tuner_attach) (struct dvb_usb_adapter *); + + struct usb_data_stream_properties stream; + + int size_of_priv; + + int (*fe_ioctl_override) (struct dvb_frontend *, + unsigned int, void *, unsigned int); +}; + +/** + * struct dvb_rc_legacy - old properties of remote controller + * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable + * remote control handling). + * @rc_map_size: number of items in @rc_map_table. + * @rc_query: called to query an event event. + * @rc_interval: time in ms between two queries. + */ +struct dvb_rc_legacy { +/* remote control properties */ +#define REMOTE_NO_KEY_PRESSED 0x00 +#define REMOTE_KEY_PRESSED 0x01 +#define REMOTE_KEY_REPEAT 0x02 + struct rc_map_table *rc_map_table; + int rc_map_size; + int (*rc_query) (struct dvb_usb_device *, u32 *, int *); + int rc_interval; +}; + +/** + * struct dvb_rc properties of remote controller, using rc-core + * @rc_codes: name of rc codes table + * @protocol: type of protocol(s) currently used by the driver + * @allowed_protos: protocol(s) supported by the driver + * @driver_type: Used to point if a device supports raw mode + * @change_protocol: callback to change protocol + * @rc_query: called to query an event event. + * @rc_interval: time in ms between two queries. + * @bulk_mode: device supports bulk mode for RC (disable polling mode) + */ +struct dvb_rc { + char *rc_codes; + u64 protocol; + u64 allowed_protos; + enum rc_driver_type driver_type; + int (*change_protocol)(struct rc_dev *dev, u64 rc_type); + char *module_name; + int (*rc_query) (struct dvb_usb_device *d); + int rc_interval; + bool bulk_mode; /* uses bulk mode */ +}; + +/** + * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one + * based on rc-core + * This is initialized/used only inside dvb-usb-remote.c. + * It shouldn't be set by the drivers. + */ +enum dvb_usb_mode { + DVB_RC_LEGACY, + DVB_RC_CORE, +}; + +/** + * struct dvb_usb_device_properties - properties of a dvb-usb-device + * @usb_ctrl: which USB device-side controller is in use. Needed for firmware + * download. + * @firmware: name of the firmware file. + * @download_firmware: called to download the firmware when the usb_ctrl is + * DEVICE_SPECIFIC. + * @no_reconnect: device doesn't do a reconnect after downloading the firmware, + * so do the warm initialization right after it + * + * @size_of_priv: how many bytes shall be allocated for the private field + * of struct dvb_usb_device. + * + * @power_ctrl: called to enable/disable power of the device. + * @read_mac_address: called to read the MAC address of the device. + * @identify_state: called to determine the state (cold or warm), when it + * is not distinguishable by the USB IDs. + * + * @rc: remote controller properties + * + * @i2c_algo: i2c_algorithm if the device has I2CoverUSB. + * + * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic + * endpoint which received control messages with bulk transfers. When this + * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write- + * helper functions. + * + * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate + * endpoint for responses to control messages sent with bulk transfers via + * the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used + * instead of the generic_bulk_ctrl_endpoint when reading usb responses in + * the dvb_usb_generic_rw helper function. + * + * @num_device_descs: number of struct dvb_usb_device_description in @devices + * @devices: array of struct dvb_usb_device_description compatibles with these + * properties. + */ +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 +struct dvb_usb_device_properties { + +#define DVB_USB_IS_AN_I2C_ADAPTER 0x01 + int caps; + +#define DEVICE_SPECIFIC 0 +#define CYPRESS_AN2135 1 +#define CYPRESS_AN2235 2 +#define CYPRESS_FX2 3 + int usb_ctrl; + int (*download_firmware) (struct usb_device *, const struct firmware *); + const char *firmware; + int no_reconnect; + + int size_of_priv; + + int num_adapters; + struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + + int (*power_ctrl) (struct dvb_usb_device *, int); + int (*read_mac_address) (struct dvb_usb_device *, u8 []); + int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *, + struct dvb_usb_device_description **, int *); + + struct { + enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */ + struct dvb_rc_legacy legacy; + struct dvb_rc core; + } rc; + + struct i2c_algorithm *i2c_algo; + + int generic_bulk_ctrl_endpoint; + int generic_bulk_ctrl_endpoint_response; + + int num_device_descs; + struct dvb_usb_device_description devices[12]; +}; + +/** + * struct usb_data_stream - generic object of an USB stream + * @buf_num: number of buffer allocated. + * @buf_size: size of each buffer in buf_list. + * @buf_list: array containing all allocate buffers for streaming. + * @dma_addr: list of dma_addr_t for each buffer in buf_list. + * + * @urbs_initialized: number of URBs initialized. + * @urbs_submitted: number of URBs submitted. + */ +#define MAX_NO_URBS_FOR_DATA_STREAM 10 +struct usb_data_stream { + struct usb_device *udev; + struct usb_data_stream_properties props; + +#define USB_STATE_INIT 0x00 +#define USB_STATE_URB_BUF 0x01 + int state; + + void (*complete) (struct usb_data_stream *, u8 *, size_t); + + struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; + int buf_num; + unsigned long buf_size; + u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; + dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; + + int urbs_initialized; + int urbs_submitted; + + void *user_priv; +}; + +/** + * struct dvb_usb_adapter - a DVB adapter on a USB device + * @id: index of this adapter (starting with 0). + * + * @feedcount: number of reqested feeds (used for streaming-activation) + * @pid_filtering: is hardware pid_filtering used or not. + * + * @pll_addr: I2C address of the tuner for programming + * @pll_init: array containing the initialization buffer + * @pll_desc: pointer to the appropriate struct dvb_pll_desc + * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board + * + * @dvb_adap: device's dvb_adapter. + * @dmxdev: device's dmxdev. + * @demux: device's software demuxer. + * @dvb_net: device's dvb_net interfaces. + * @dvb_frontend: device's frontend. + * @max_feed_count: how many feeds can be handled simultaneously by this + * device + * + * @fe_init: rerouted frontend-init (wakeup) function. + * @fe_sleep: rerouted frontend-sleep function. + * + * @stream: the usb data stream. + */ +struct dvb_usb_adapter { + struct dvb_usb_device *dev; + struct dvb_usb_adapter_properties props; + +#define DVB_USB_ADAP_STATE_INIT 0x000 +#define DVB_USB_ADAP_STATE_DVB 0x001 + int state; + + u8 id; + + int feedcount; + int pid_filtering; + + /* dvb */ + struct dvb_adapter dvb_adap; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvb_net; + struct dvb_frontend *fe; + int max_feed_count; + + int (*fe_init) (struct dvb_frontend *); + int (*fe_sleep) (struct dvb_frontend *); + + struct usb_data_stream stream; + + void *priv; +}; + +/** + * struct dvb_usb_device - object of a DVB USB device + * @props: copy of the struct dvb_usb_properties this device belongs to. + * @desc: pointer to the device's struct dvb_usb_device_description. + * @state: initialization and runtime state of the device. + * + * @powered: indicated whether the device is power or not. + * Powered is in/decremented for each call to modify the state. + * @udev: pointer to the device's struct usb_device. + * + * @usb_mutex: semaphore of USB control messages (reading needs two messages) + * @i2c_mutex: semaphore for i2c-transfers + * + * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB + * + * @rc_dev: rc device for the remote control (rc-core mode) + * @input_dev: input device for the remote control (legacy mode) + * @rc_query_work: struct work_struct frequent rc queries + * @last_event: last triggered event + * @last_state: last state (no, pressed, repeat) + * @owner: owner of the dvb_adapter + * @priv: private data of the actual driver (allocate by dvb-usb, size defined + * in size_of_priv of dvb_usb_properties). + */ +struct dvb_usb_device { + struct dvb_usb_device_properties props; + struct dvb_usb_device_description *desc; + + struct usb_device *udev; + +#define DVB_USB_STATE_INIT 0x000 +#define DVB_USB_STATE_I2C 0x001 +#define DVB_USB_STATE_DVB 0x002 +#define DVB_USB_STATE_REMOTE 0x004 + int state; + + int powered; + + /* locking */ + struct mutex usb_mutex; + + /* i2c */ + struct mutex i2c_mutex; + struct i2c_adapter i2c_adap; + + int num_adapters_initialized; + struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + + /* remote control */ + struct rc_dev *rc_dev; + struct input_dev *input_dev; + char rc_phys[64]; + struct delayed_work rc_query_work; + u32 last_event; + int last_state; + + struct module *owner; + + void *priv; +}; + +extern int dvb_usb_device_init(struct usb_interface *, + struct dvb_usb_device_properties *, + struct module *, struct dvb_usb_device **, + short *adapter_nums); +extern void dvb_usb_device_exit(struct usb_interface *); + +/* the generic read/write method for device control */ +extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int); +extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); + +/* commonly used remote control parsing */ +extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); + +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; +extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type); +extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos); + + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,43 @@ +/* dvb-usb-i2c.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for (de-)initializing an I2C adapter. + */ +#include "dvb-usb-common.h" + +int dvb_usb_i2c_init(struct dvb_usb_device *d) +{ + int ret = 0; + + if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER)) + return 0; + + if (d->props.i2c_algo == NULL) { + err("no i2c algorithm specified"); + return -EINVAL; + } + + strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); + d->i2c_adap.algo = d->props.i2c_algo; + d->i2c_adap.algo_data = NULL; + d->i2c_adap.dev.parent = &d->udev->dev; + + i2c_set_adapdata(&d->i2c_adap, d); + + if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0) + err("could not add i2c adapter"); + + d->state |= DVB_USB_STATE_I2C; + + return ret; +} + +int dvb_usb_i2c_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_I2C) + i2c_del_adapter(&d->i2c_adap); + d->state &= ~DVB_USB_STATE_I2C; + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,325 @@ +/* dvb-usb-ids.h is part of the DVB USB library. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see + * dvb-usb-init.c for copyright information. + * + * a header file containing define's for the USB device supported by the + * various drivers. + */ +#ifndef _DVB_USB_IDS_H_ +#define _DVB_USB_IDS_H_ + +/* Vendor IDs */ +#define USB_VID_ADSTECH 0x06e1 +#define USB_VID_AFATECH 0x15a4 +#define USB_VID_ALCOR_MICRO 0x058f +#define USB_VID_ALINK 0x05e3 +#define USB_VID_AMT 0x1c73 +#define USB_VID_ANCHOR 0x0547 +#define USB_VID_ANSONIC 0x10b9 +#define USB_VID_ANUBIS_ELECTRONIC 0x10fd +#define USB_VID_ASUS 0x0b05 +#define USB_VID_AVERMEDIA 0x07ca +#define USB_VID_COMPRO 0x185b +#define USB_VID_COMPRO_UNK 0x145f +#define USB_VID_CONEXANT 0x0572 +#define USB_VID_CYPRESS 0x04b4 +#define USB_VID_DIBCOM 0x10b8 +#define USB_VID_DPOSH 0x1498 +#define USB_VID_DVICO 0x0fe9 +#define USB_VID_E3C 0x18b4 +#define USB_VID_ELGATO 0x0fd9 +#define USB_VID_EMPIA 0xeb1a +#define USB_VID_GENPIX 0x09c0 +#define USB_VID_GRANDTEC 0x5032 +#define USB_VID_GTEK 0x1f4d +#define USB_VID_HANFTEK 0x15f4 +#define USB_VID_HAUPPAUGE 0x2040 +#define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_INTEL 0x8086 +#define USB_VID_KWORLD 0xeb2a +#define USB_VID_KWORLD_2 0x1b80 +#define USB_VID_KYE 0x0458 +#define USB_VID_LEADTEK 0x0413 +#define USB_VID_LITEON 0x04ca +#define USB_VID_MEDION 0x1660 +#define USB_VID_MIGLIA 0x18f3 +#define USB_VID_MSI 0x0db0 +#define USB_VID_MSI_2 0x1462 +#define USB_VID_OPERA1 0x695c +#define USB_VID_PINNACLE 0x2304 +#define USB_VID_PCTV 0x2013 +#define USB_VID_PIXELVIEW 0x1554 +#define USB_VID_TECHNOTREND 0x0b48 +#define USB_VID_TERRATEC 0x0ccd +#define USB_VID_TELESTAR 0x10b9 +#define USB_VID_VISIONPLUS 0x13d3 +#define USB_VID_SONY 0x1415 +#define USB_VID_TWINHAN 0x1822 +#define USB_VID_ULTIMA_ELECTRONIC 0x05d8 +#define USB_VID_UNIWILL 0x1584 +#define USB_VID_WIDEVIEW 0x14aa +#define USB_VID_GIGABYTE 0x1044 +#define USB_VID_YUAN 0x1164 +#define USB_VID_XTENSIONS 0x1ae7 +#define USB_VID_HUMAX_COEX 0x10b9 +#define USB_VID_774 0x7a69 +#define USB_VID_EVOLUTEPC 0x1e59 +#define USB_VID_AZUREWAVE 0x13d3 +#define USB_VID_TECHNISAT 0x14f7 + +/* Product IDs */ +#define USB_PID_ADSTECH_USB2_COLD 0xa333 +#define USB_PID_ADSTECH_USB2_WARM 0xa334 +#define USB_PID_AFATECH_AF9005 0x9020 +#define USB_PID_AFATECH_AF9015_9015 0x9015 +#define USB_PID_AFATECH_AF9015_9016 0x9016 +#define USB_PID_TREKSTOR_DVBT 0x901b +#define USB_VID_ALINK_DTU 0xf170 +#define USB_PID_ANSONIC_DVBT_USB 0x6000 +#define USB_PID_ANYSEE 0x861f +#define USB_PID_AZUREWAVE_AD_TU700 0x3237 +#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 +#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 +#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 +#define USB_PID_AVERMEDIA_DVBT_USB2_WARM 0xa801 +#define USB_PID_COMPRO_DVBU2000_COLD 0xd000 +#define USB_PID_COMPRO_DVBU2000_WARM 0xd001 +#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c +#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d +#define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 +#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 +#define USB_PID_CONCEPTRONIC_CTVDIGRCU 0xe397 +#define USB_PID_CONEXANT_D680_DMB 0x86d6 +#define USB_PID_CREATIX_CTX1921 0x1921 +#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 +#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 +#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 +#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9 +#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6 +#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 +#define USB_PID_DIBCOM_STK7700P 0x1e14 +#define USB_PID_DIBCOM_STK7700P_PC 0x1e78 +#define USB_PID_DIBCOM_STK7700D 0x1ef0 +#define USB_PID_DIBCOM_STK7700_U7000 0x7001 +#define USB_PID_DIBCOM_STK7070P 0x1ebc +#define USB_PID_DIBCOM_STK7070PD 0x1ebe +#define USB_PID_DIBCOM_STK807XP 0x1f90 +#define USB_PID_DIBCOM_STK807XPVR 0x1f98 +#define USB_PID_DIBCOM_STK8096GP 0x1fa0 +#define USB_PID_DIBCOM_NIM8096MD 0x1fa8 +#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 +#define USB_PID_DIBCOM_STK7770P 0x1e80 +#define USB_PID_DIBCOM_NIM7090 0x1bb2 +#define USB_PID_DIBCOM_TFE7090PVR 0x1bb4 +#define USB_PID_DIBCOM_NIM9090M 0x2383 +#define USB_PID_DIBCOM_NIM9090MD 0x2384 +#define USB_PID_DPOSH_M9206_COLD 0x9206 +#define USB_PID_DPOSH_M9206_WARM 0xa090 +#define USB_PID_E3C_EC168 0x1689 +#define USB_PID_E3C_EC168_2 0xfffa +#define USB_PID_E3C_EC168_3 0xfffb +#define USB_PID_E3C_EC168_4 0x1001 +#define USB_PID_E3C_EC168_5 0x1002 +#define USB_PID_UNIWILL_STK7700P 0x6003 +#define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 +#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 +#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 +#define USB_PID_INTEL_CE9500 0x9500 +#define USB_PID_KWORLD_399U 0xe399 +#define USB_PID_KWORLD_399U_2 0xe400 +#define USB_PID_KWORLD_395U 0xe396 +#define USB_PID_KWORLD_395U_2 0xe39b +#define USB_PID_KWORLD_395U_3 0xe395 +#define USB_PID_KWORLD_395U_4 0xe39a +#define USB_PID_KWORLD_MC810 0xc810 +#define USB_PID_KWORLD_PC160_2T 0xc160 +#define USB_PID_KWORLD_PC160_T 0xc161 +#define USB_PID_KWORLD_UB383_T 0xe383 +#define USB_PID_KWORLD_VSTREAM_COLD 0x17de +#define USB_PID_KWORLD_VSTREAM_WARM 0x17df +#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 +#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 +#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097 +#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099 +#define USB_PID_TWINHAN_VP7041_COLD 0x3201 +#define USB_PID_TWINHAN_VP7041_WARM 0x3202 +#define USB_PID_TWINHAN_VP7020_COLD 0x3203 +#define USB_PID_TWINHAN_VP7020_WARM 0x3204 +#define USB_PID_TWINHAN_VP7045_COLD 0x3205 +#define USB_PID_TWINHAN_VP7045_WARM 0x3206 +#define USB_PID_TWINHAN_VP7021_COLD 0x3207 +#define USB_PID_TWINHAN_VP7021_WARM 0x3208 +#define USB_PID_TINYTWIN 0x3226 +#define USB_PID_TINYTWIN_2 0xe402 +#define USB_PID_TINYTWIN_3 0x9016 +#define USB_PID_DNTV_TINYUSB2_COLD 0x3223 +#define USB_PID_DNTV_TINYUSB2_WARM 0x3224 +#define USB_PID_ULTIMA_TVBOX_COLD 0x8105 +#define USB_PID_ULTIMA_TVBOX_WARM 0x8106 +#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107 +#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108 +#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235 +#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109 +#define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a +#define USB_PID_ARTEC_T14_COLD 0x810b +#define USB_PID_ARTEC_T14_WARM 0x810c +#define USB_PID_ARTEC_T14BR 0x810f +#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 +#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 +#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e +#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f +#define USB_PID_HANFTEK_UMT_010_COLD 0x0001 +#define USB_PID_HANFTEK_UMT_010_WARM 0x0015 +#define USB_PID_DTT200U_COLD 0x0201 +#define USB_PID_DTT200U_WARM 0x0301 +#define USB_PID_WT220U_ZAP250_COLD 0x0220 +#define USB_PID_WT220U_COLD 0x0222 +#define USB_PID_WT220U_WARM 0x0221 +#define USB_PID_WT220U_FC_COLD 0x0225 +#define USB_PID_WT220U_FC_WARM 0x0226 +#define USB_PID_WT220U_ZL0353_COLD 0x022a +#define USB_PID_WT220U_ZL0353_WARM 0x022b +#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 +#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 +#define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941 +#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 +#define USB_PID_HAUPPAUGE_NOVA_T_500_3 0x8400 +#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 +#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 +#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 +#define USB_PID_HAUPPAUGE_MYTV_T 0x7080 +#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 +#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200 +#define USB_PID_HAUPPAUGE_TIGER_ATSC 0xb200 +#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210 0xb210 +#define USB_PID_AVERMEDIA_EXPRESS 0xb568 +#define USB_PID_AVERMEDIA_VOLAR 0xa807 +#define USB_PID_AVERMEDIA_VOLAR_2 0xb808 +#define USB_PID_AVERMEDIA_VOLAR_A868R 0xa868 +#define USB_PID_AVERMEDIA_MCE_USB_M038 0x1228 +#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039 +#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039 +#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039 +#define USB_PID_AVERMEDIA_VOLAR_X 0xa815 +#define USB_PID_AVERMEDIA_VOLAR_X_2 0x8150 +#define USB_PID_AVERMEDIA_A309 0xa309 +#define USB_PID_AVERMEDIA_A310 0xa310 +#define USB_PID_AVERMEDIA_A850 0x850a +#define USB_PID_AVERMEDIA_A850T 0x850b +#define USB_PID_AVERMEDIA_A805 0xa805 +#define USB_PID_AVERMEDIA_A815M 0x815a +#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 +#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d +#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a +#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 +#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 +#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060 +#define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 +#define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 +#define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab +#define USB_PID_TERRATEC_T3 0x10a0 +#define USB_PID_TERRATEC_T5 0x10a1 +#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e +#define USB_PID_PINNACLE_PCTV2000E 0x022c +#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 +#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 +#define USB_PID_PINNACLE_PCTV71E 0x022b +#define USB_PID_PINNACLE_PCTV72E 0x0236 +#define USB_PID_PINNACLE_PCTV73E 0x0237 +#define USB_PID_PINNACLE_PCTV310E 0x3211 +#define USB_PID_PINNACLE_PCTV801E 0x023a +#define USB_PID_PINNACLE_PCTV801E_SE 0x023b +#define USB_PID_PINNACLE_PCTV340E 0x023d +#define USB_PID_PINNACLE_PCTV340E_SE 0x023e +#define USB_PID_PINNACLE_PCTV73A 0x0243 +#define USB_PID_PINNACLE_PCTV73ESE 0x0245 +#define USB_PID_PINNACLE_PCTV74E 0x0246 +#define USB_PID_PINNACLE_PCTV282E 0x0248 +#define USB_PID_PIXELVIEW_SBTVD 0x5010 +#define USB_PID_PCTV_200E 0x020e +#define USB_PID_PCTV_400E 0x020f +#define USB_PID_PCTV_450E 0x0222 +#define USB_PID_NEBULA_DIGITV 0x0201 +#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 +#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 +#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM 0xd501 +#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD 0xdb00 +#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM 0xdb01 +#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD 0xdb10 +#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM 0xdb11 +#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD 0xdb50 +#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51 +#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 +#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 +#define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 +#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2 0xdb98 +#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 +#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 +#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 +#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 +#define USB_PID_MEDION_MD95700 0x0932 +#define USB_PID_MSI_MEGASKY580 0x5580 +#define USB_PID_MSI_MEGASKY580_55801 0x5581 +#define USB_PID_KYE_DVB_T_COLD 0x701e +#define USB_PID_KYE_DVB_T_WARM 0x701f +#define USB_PID_LITEON_DVB_T_COLD 0xf000 +#define USB_PID_LITEON_DVB_T_WARM 0xf001 +#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 +#define USB_PID_DIGIVOX_MINI_SL_WARM 0xe361 +#define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6 +#define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7 +#define USB_PID_WINFAST_DTV2000DS 0x6a04 +#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 +#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 +#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 +#define USB_PID_WINFAST_DTV_DONGLE_H 0x60f6 +#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01 +#define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029 +#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 +#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 +#define USB_PID_GENPIX_8PSK_REV_2 0x0202 +#define USB_PID_GENPIX_SKYWALKER_1 0x0203 +#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204 +#define USB_PID_GENPIX_SKYWALKER_2 0x0206 +#define USB_PID_SIGMATEK_DVB_110 0x6610 +#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 +#define USB_PID_MSI_DIGIVOX_DUO 0x8801 +#define USB_PID_OPERA1_COLD 0x2830 +#define USB_PID_OPERA1_WARM 0x3829 +#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 +#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 +#define USB_PID_GIGABYTE_U7000 0x7001 +#define USB_PID_GIGABYTE_U8000 0x7002 +#define USB_PID_ASUS_U3000 0x171f +#define USB_PID_ASUS_U3000H 0x1736 +#define USB_PID_ASUS_U3100 0x173f +#define USB_PID_YUAN_EC372S 0x1edc +#define USB_PID_YUAN_STK7700PH 0x1f08 +#define USB_PID_YUAN_PD378S 0x2edc +#define USB_PID_YUAN_MC770 0x0871 +#define USB_PID_YUAN_STK7700D 0x1efc +#define USB_PID_YUAN_STK7700D_2 0x1e8c +#define USB_PID_DW2102 0x2102 +#define USB_PID_XTENSIONS_XD_380 0x0381 +#define USB_PID_TELESTAR_STARSTICK_2 0x8000 +#define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807 +#define USB_PID_SONY_PLAYTV 0x0003 +#define USB_PID_MYGICA_D689 0xd811 +#define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 +#define USB_PID_ELGATO_EYETV_DTT 0x0021 +#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 +#define USB_PID_ELGATO_EYETV_SAT 0x002a +#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000 +#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001 +#define USB_PID_FRIIO_WHITE 0x0001 +#define USB_PID_TVWAY_PLUS 0x0002 +#define USB_PID_SVEON_STV20 0xe39d +#define USB_PID_AZUREWAVE_AZ6027 0x3275 +#define USB_PID_TERRATEC_DVBS2CI_V1 0x10a4 +#define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac +#define USB_PID_TECHNISAT_USB2_HDCI_V1 0x0001 +#define USB_PID_TECHNISAT_USB2_HDCI_V2 0x0002 +#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2 0x0004 +#define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500 +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-init.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,288 @@ +/* + * DVB USB library - provides a generic interface for a DVB USB device driver. + * + * dvb-usb-init.c + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dvb-usb-common.h" + +/* debug */ +int dvb_usb_debug; +module_param_named(debug, dvb_usb_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS); + +int dvb_usb_disable_rc_polling; +module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); +MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); + +static int dvb_usb_force_pid_filter_usage; +module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); +MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); + +static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) +{ + struct dvb_usb_adapter *adap; + int ret, n; + + for (n = 0; n < d->props.num_adapters; n++) { + adap = &d->adapter[n]; + adap->dev = d; + adap->id = n; + + memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties)); + + /* speed - when running at FULL speed we need a HW PID filter */ + if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); + return -ENODEV; + } + + if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + info("will use the device's hardware PID filter (table count: %d).", adap->props.pid_filter_count); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props.pid_filter_count; + } else { + info("will pass the complete MPEG2 transport stream to the software demuxer."); + adap->pid_filtering = 0; + adap->max_feed_count = 255; + } + + if (!adap->pid_filtering && + dvb_usb_force_pid_filter_usage && + adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) { + info("pid filter enabled by module option."); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props.pid_filter_count; + } + + if (adap->props.size_of_priv > 0) { + adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL); + if (adap->priv == NULL) { + err("no memory for priv for adapter %d.", n); + return -ENOMEM; + } + } + + if ((ret = dvb_usb_adapter_stream_init(adap)) || + (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || + (ret = dvb_usb_adapter_frontend_init(adap))) { + return ret; + } + + d->num_adapters_initialized++; + d->state |= DVB_USB_STATE_DVB; + } + + /* + * when reloading the driver w/o replugging the device + * sometimes a timeout occures, this helps + */ + if (d->props.generic_bulk_ctrl_endpoint != 0) { + usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + } + + return 0; +} + +static int dvb_usb_adapter_exit(struct dvb_usb_device *d) +{ + int n; + + for (n = 0; n < d->num_adapters_initialized; n++) { + dvb_usb_adapter_frontend_exit(&d->adapter[n]); + dvb_usb_adapter_dvb_exit(&d->adapter[n]); + dvb_usb_adapter_stream_exit(&d->adapter[n]); + kfree(d->adapter[n].priv); + } + d->num_adapters_initialized = 0; + d->state &= ~DVB_USB_STATE_DVB; + return 0; +} + + +/* general initialization functions */ +static int dvb_usb_exit(struct dvb_usb_device *d) +{ + deb_info("state before exiting everything: %x\n", d->state); + dvb_usb_remote_exit(d); + dvb_usb_adapter_exit(d); + dvb_usb_i2c_exit(d); + deb_info("state should be zero now: %x\n", d->state); + d->state = DVB_USB_STATE_INIT; + kfree(d->priv); + kfree(d); + return 0; +} + +static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) +{ + int ret = 0; + + mutex_init(&d->usb_mutex); + mutex_init(&d->i2c_mutex); + + d->state = DVB_USB_STATE_INIT; + + if (d->props.size_of_priv > 0) { + d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); + if (d->priv == NULL) { + err("no memory for priv in 'struct dvb_usb_device'"); + return -ENOMEM; + } + } + + /* check the capabilities and set appropriate variables */ + dvb_usb_device_power_ctrl(d, 1); + + if ((ret = dvb_usb_i2c_init(d)) || + (ret = dvb_usb_adapter_init(d, adapter_nums))) { + dvb_usb_exit(d); + return ret; + } + + if ((ret = dvb_usb_remote_init(d))) + err("could not initialize remote control."); + + dvb_usb_device_power_ctrl(d, 0); + + return 0; +} + +/* determine the name and the state of the just found USB device */ +static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold) +{ + int i, j; + struct dvb_usb_device_description *desc = NULL; + + *cold = -1; + + for (i = 0; i < props->num_device_descs; i++) { + + for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) { + deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct); + if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && + props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { + *cold = 1; + desc = &props->devices[i]; + break; + } + } + + if (desc != NULL) + break; + + for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) { + deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct); + if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && + props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { + *cold = 0; + desc = &props->devices[i]; + break; + } + } + } + + if (desc != NULL && props->identify_state != NULL) + props->identify_state(udev, props, &desc, cold); + + return desc; +} + +int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + if (onoff) + d->powered++; + else + d->powered--; + + if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ + deb_info("power control: %d\n", onoff); + if (d->props.power_ctrl) + return d->props.power_ctrl(d, onoff); + } + return 0; +} + +/* + * USB + */ +int dvb_usb_device_init(struct usb_interface *intf, + struct dvb_usb_device_properties *props, + struct module *owner, struct dvb_usb_device **du, + short *adapter_nums) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct dvb_usb_device *d = NULL; + struct dvb_usb_device_description *desc = NULL; + + int ret = -ENOMEM, cold = 0; + + if (du != NULL) + *du = NULL; + + if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { + deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); + return -ENODEV; + } + + if (cold) { + info("found a '%s' in cold state, will try to load a firmware", desc->name); + ret = dvb_usb_download_firmware(udev, props); + if (!props->no_reconnect || ret != 0) + return ret; + } + + info("found a '%s' in warm state.", desc->name); + d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); + if (d == NULL) { + err("no memory for 'struct dvb_usb_device'"); + return -ENOMEM; + } + + d->udev = udev; + memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); + d->desc = desc; + d->owner = owner; + + usb_set_intfdata(intf, d); + + if (du != NULL) + *du = d; + + ret = dvb_usb_init(d, adapter_nums); + + if (ret == 0) + info("%s successfully initialized and connected.", desc->name); + else + info("%s error while loading driver (%d)", desc->name, ret); + return ret; +} +EXPORT_SYMBOL(dvb_usb_device_init); + +void dvb_usb_device_exit(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + const char *name = "generic DVB-USB module"; + + usb_set_intfdata(intf, NULL); + if (d != NULL && d->desc != NULL) { + name = d->desc->name; + dvb_usb_exit(d); + } + info("%s successfully deinitialized and disconnected.", name); + +} +EXPORT_SYMBOL(dvb_usb_device_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,391 @@ +/* dvb-usb-remote.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for initializing the input-device and for handling remote-control-queries. + */ +#include "dvb-usb-common.h" +#include + +static unsigned int +legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke, + struct rc_map_table *keymap, + unsigned int keymap_size) +{ + unsigned int index; + unsigned int scancode; + + if (ke->flags & INPUT_KEYMAP_BY_INDEX) { + index = ke->index; + } else { + if (input_scancode_to_scalar(ke, &scancode)) + return keymap_size; + + /* See if we can match the raw key code. */ + for (index = 0; index < keymap_size; index++) + if (keymap[index].scancode == scancode) + break; + + /* See if there is an unused hole in the map */ + if (index >= keymap_size) { + for (index = 0; index < keymap_size; index++) { + if (keymap[index].keycode == KEY_RESERVED || + keymap[index].keycode == KEY_UNKNOWN) { + break; + } + } + } + } + + return index; +} + +static int legacy_dvb_usb_getkeycode(struct input_dev *dev, + struct input_keymap_entry *ke) +{ + struct dvb_usb_device *d = input_get_drvdata(dev); + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + unsigned int keymap_size = d->props.rc.legacy.rc_map_size; + unsigned int index; + + index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); + if (index >= keymap_size) + return -EINVAL; + + ke->keycode = keymap[index].keycode; + if (ke->keycode == KEY_UNKNOWN) + ke->keycode = KEY_RESERVED; + ke->len = sizeof(keymap[index].scancode); + memcpy(&ke->scancode, &keymap[index].scancode, ke->len); + ke->index = index; + + return 0; +} + +static int legacy_dvb_usb_setkeycode(struct input_dev *dev, + const struct input_keymap_entry *ke, + unsigned int *old_keycode) +{ + struct dvb_usb_device *d = input_get_drvdata(dev); + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + unsigned int keymap_size = d->props.rc.legacy.rc_map_size; + unsigned int index; + + index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); + /* + * FIXME: Currently, it is not possible to increase the size of + * scancode table. For it to happen, one possibility + * would be to allocate a table with key_map_size + 1, + * copying data, appending the new key on it, and freeing + * the old one - or maybe just allocating some spare space + */ + if (index >= keymap_size) + return -EINVAL; + + *old_keycode = keymap[index].keycode; + keymap->keycode = ke->keycode; + __set_bit(ke->keycode, dev->keybit); + + if (*old_keycode != KEY_RESERVED) { + __clear_bit(*old_keycode, dev->keybit); + for (index = 0; index < keymap_size; index++) { + if (keymap[index].keycode == *old_keycode) { + __set_bit(*old_keycode, dev->keybit); + break; + } + } + } + + return 0; +} + +/* Remote-control poll function - called every dib->rc_query_interval ms to see + * whether the remote control has received anything. + * + * TODO: Fix the repeat rate of the input device. + */ +static void legacy_dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); + u32 event; + int state; + + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the driver was running */ + if (dvb_usb_disable_rc_polling) + return; + + if (d->props.rc.legacy.rc_query(d,&event,&state)) { + err("error while querying for an remote control event."); + goto schedule; + } + + + switch (state) { + case REMOTE_NO_KEY_PRESSED: + break; + case REMOTE_KEY_PRESSED: + deb_rc("key pressed\n"); + d->last_event = event; + case REMOTE_KEY_REPEAT: + deb_rc("key repeated\n"); + input_event(d->input_dev, EV_KEY, event, 1); + input_sync(d->input_dev); + input_event(d->input_dev, EV_KEY, d->last_event, 0); + input_sync(d->input_dev); + break; + default: + break; + } + +/* improved repeat handling ??? + switch (state) { + case REMOTE_NO_KEY_PRESSED: + deb_rc("NO KEY PRESSED\n"); + if (d->last_state != REMOTE_NO_KEY_PRESSED) { + deb_rc("releasing event %d\n",d->last_event); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); + input_sync(d->rc_input_dev); + } + d->last_state = REMOTE_NO_KEY_PRESSED; + d->last_event = 0; + break; + case REMOTE_KEY_PRESSED: + deb_rc("KEY PRESSED\n"); + deb_rc("pressing event %d\n",event); + + input_event(d->rc_input_dev, EV_KEY, event, 1); + input_sync(d->rc_input_dev); + + d->last_event = event; + d->last_state = REMOTE_KEY_PRESSED; + break; + case REMOTE_KEY_REPEAT: + deb_rc("KEY_REPEAT\n"); + if (d->last_state != REMOTE_NO_KEY_PRESSED) { + deb_rc("repeating event %d\n",d->last_event); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); + input_sync(d->rc_input_dev); + d->last_state = REMOTE_KEY_REPEAT; + } + default: + break; + } +*/ + +schedule: + schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval)); +} + +static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) +{ + int i, err, rc_interval; + struct input_dev *input_dev; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + input_dev->name = "IR-receiver inside an USB DVB receiver"; + input_dev->phys = d->rc_phys; + usb_to_input_id(d->udev, &input_dev->id); + input_dev->dev.parent = &d->udev->dev; + d->input_dev = input_dev; + d->rc_dev = NULL; + + input_dev->getkeycode = legacy_dvb_usb_getkeycode; + input_dev->setkeycode = legacy_dvb_usb_setkeycode; + + /* set the bits for the keys */ + deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size); + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + deb_rc("setting bit for event %d item %d\n", + d->props.rc.legacy.rc_map_table[i].keycode, i); + set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit); + } + + /* setting these two values to non-zero, we have to manage key repeats */ + input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval; + input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150; + + input_set_drvdata(input_dev, d); + + err = input_register_device(input_dev); + if (err) + input_free_device(input_dev); + + rc_interval = d->props.rc.legacy.rc_interval; + + INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control); + + info("schedule remote query interval to %d msecs.", rc_interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(rc_interval)); + + d->state |= DVB_USB_STATE_REMOTE; + + return err; +} + +/* Remote-control poll function - called every dib->rc_query_interval ms to see + * whether the remote control has received anything. + * + * TODO: Fix the repeat rate of the input device. + */ +static void dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); + int err; + + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the + * driver was running, or when bulk mode is enabled after IR init + */ + if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode) + return; + + err = d->props.rc.core.rc_query(d); + if (err) + err("error %d while querying for an remote control event.", err); + + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->props.rc.core.rc_interval)); +} + +static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) +{ + int err, rc_interval; + struct rc_dev *dev; + + dev = rc_allocate_device(); + if (!dev) + return -ENOMEM; + + dev->driver_name = d->props.rc.core.module_name; + dev->map_name = d->props.rc.core.rc_codes; + dev->change_protocol = d->props.rc.core.change_protocol; + dev->allowed_protos = d->props.rc.core.allowed_protos; + dev->driver_type = d->props.rc.core.driver_type; + usb_to_input_id(d->udev, &dev->input_id); + dev->input_name = "IR-receiver inside an USB DVB receiver"; + dev->input_phys = d->rc_phys; + dev->dev.parent = &d->udev->dev; + dev->priv = d; + + err = rc_register_device(dev); + if (err < 0) { + rc_free_device(dev); + return err; + } + + d->input_dev = NULL; + d->rc_dev = dev; + + if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode) + return 0; + + /* Polling mode - initialize a work queue for handling it */ + INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); + + rc_interval = d->props.rc.core.rc_interval; + + info("schedule remote query interval to %d msecs.", rc_interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(rc_interval)); + + return 0; +} + +int dvb_usb_remote_init(struct dvb_usb_device *d) +{ + int err; + + if (dvb_usb_disable_rc_polling) + return 0; + + if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query) + d->props.rc.mode = DVB_RC_LEGACY; + else if (d->props.rc.core.rc_codes) + d->props.rc.mode = DVB_RC_CORE; + else + return 0; + + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + + /* Start the remote-control polling. */ + if (d->props.rc.legacy.rc_interval < 40) + d->props.rc.legacy.rc_interval = 100; /* default */ + + if (d->props.rc.mode == DVB_RC_LEGACY) + err = legacy_dvb_usb_remote_init(d); + else + err = rc_core_dvb_usb_remote_init(d); + if (err) + return err; + + d->state |= DVB_USB_STATE_REMOTE; + + return 0; +} + +int dvb_usb_remote_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_REMOTE) { + cancel_delayed_work_sync(&d->rc_query_work); + if (d->props.rc.mode == DVB_RC_LEGACY) + input_unregister_device(d->input_dev); + else + rc_unregister_device(d->rc_dev); + } + d->state &= ~DVB_USB_STATE_REMOTE; + return 0; +} + +#define DVB_USB_RC_NEC_EMPTY 0x00 +#define DVB_USB_RC_NEC_KEY_PRESSED 0x01 +#define DVB_USB_RC_NEC_KEY_REPEATED 0x02 +int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, + u8 keybuf[5], u32 *event, int *state) +{ + int i; + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + switch (keybuf[0]) { + case DVB_USB_RC_NEC_EMPTY: + break; + case DVB_USB_RC_NEC_KEY_PRESSED: + if ((u8) ~keybuf[1] != keybuf[2] || + (u8) ~keybuf[3] != keybuf[4]) { + deb_err("remote control checksum failed.\n"); + break; + } + /* See if we can match the raw key code. */ + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) + if (rc5_custom(&keymap[i]) == keybuf[1] && + rc5_data(&keymap[i]) == keybuf[3]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + return 0; + } + deb_err("key mapping failed - no appropriate key found in keymapping\n"); + break; + case DVB_USB_RC_NEC_KEY_REPEATED: + *state = REMOTE_KEY_REPEAT; + break; + default: + deb_err("unknown type of remote status: %d\n",keybuf[0]); + break; + } + return 0; +} +EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,97 @@ +/* dvb-usb-urb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file keeps functions for initializing and handling the + * USB and URB stuff. + */ +#include "dvb-usb-common.h" + +int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, + u16 rlen, int delay_ms) +{ + int actlen,ret = -ENOMEM; + + if (!d || wbuf == NULL || wlen == 0) + return -EINVAL; + + if (d->props.generic_bulk_ctrl_endpoint == 0) { + err("endpoint for generic control not specified."); + return -EINVAL; + } + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + deb_xfer(">>> "); + debug_dump(wbuf,wlen,deb_xfer); + + ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, + 2000); + + if (ret) + err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); + else + ret = actlen != wlen ? -1 : 0; + + /* an answer is expected, and no error before */ + if (!ret && rbuf && rlen) { + if (delay_ms) + msleep(delay_ms); + + ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint_response ? + d->props.generic_bulk_ctrl_endpoint_response : + d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, + 2000); + + if (ret) + err("recv bulk message failed: %d",ret); + else { + deb_xfer("<<< "); + debug_dump(rbuf,actlen,deb_xfer); + } + } + + mutex_unlock(&d->usb_mutex); + return ret; +} +EXPORT_SYMBOL(dvb_usb_generic_rw); + +int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) +{ + return dvb_usb_generic_rw(d,buf,len,NULL,0,0); +} +EXPORT_SYMBOL(dvb_usb_generic_write); + +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter(&adap->demux, buffer, length); +} + +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter_204(&adap->demux, buffer, length); +} + +int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) +{ + adap->stream.udev = adap->dev->udev; + if (adap->props.caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) + adap->stream.complete = dvb_usb_data_complete_204; + else + adap->stream.complete = dvb_usb_data_complete; + adap->stream.user_priv = adap; + return usb_urb_init(&adap->stream, &adap->props.stream); +} + +int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) +{ + return usb_urb_exit(&adap->stream); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dw2102.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dw2102.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dw2102.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dw2102.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1939 @@ +/* DVB USB framework compliant Linux driver for the + * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, + * TeVii S600, S630, S650, S660, S480, + * Prof 1100, 7500, + * Geniatech SU3000 Cards + * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dw2102.h" +#include "si21xx.h" +#include "stv0299.h" +#include "z0194a.h" +#include "stv0288.h" +#include "stb6000.h" +#include "eds1547.h" +#include "cx24116.h" +#include "tda1002x.h" +#include "mt312.h" +#include "zl10039.h" +#include "ds3000.h" +#include "stv0900.h" +#include "stv6110.h" +#include "stb6100.h" +#include "stb6100_proc.h" + +#ifndef USB_PID_DW2102 +#define USB_PID_DW2102 0x2102 +#endif + +#ifndef USB_PID_DW2104 +#define USB_PID_DW2104 0x2104 +#endif + +#ifndef USB_PID_DW3101 +#define USB_PID_DW3101 0x3101 +#endif + +#ifndef USB_PID_CINERGY_S +#define USB_PID_CINERGY_S 0x0064 +#endif + +#ifndef USB_PID_TEVII_S630 +#define USB_PID_TEVII_S630 0xd630 +#endif + +#ifndef USB_PID_TEVII_S650 +#define USB_PID_TEVII_S650 0xd650 +#endif + +#ifndef USB_PID_TEVII_S660 +#define USB_PID_TEVII_S660 0xd660 +#endif + +#ifndef USB_PID_TEVII_S480_1 +#define USB_PID_TEVII_S480_1 0xd481 +#endif + +#ifndef USB_PID_TEVII_S480_2 +#define USB_PID_TEVII_S480_2 0xd482 +#endif + +#ifndef USB_PID_PROF_1100 +#define USB_PID_PROF_1100 0xb012 +#endif + +#define DW210X_READ_MSG 0 +#define DW210X_WRITE_MSG 1 + +#define REG_1F_SYMBOLRATE_BYTE0 0x1f +#define REG_20_SYMBOLRATE_BYTE1 0x20 +#define REG_21_SYMBOLRATE_BYTE2 0x21 +/* on my own*/ +#define DW2102_VOLTAGE_CTRL (0x1800) +#define SU3000_STREAM_CTRL (0x1900) +#define DW2102_RC_QUERY (0x1a00) +#define DW2102_LED_CTRL (0x1b00) + +#define err_str "did not find the firmware file. (%s) " \ + "Please see linux/Documentation/dvb/ for more details " \ + "on firmware-problems." + +struct rc_map_dvb_usb_table_table { + struct rc_map_table *rc_keys; + int rc_keys_size; +}; + +struct su3000_state { + u8 initialized; +}; + +struct s6x0_state { + int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v); +}; + +/* debug */ +static int dvb_usb_dw2102_debug; +module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." + DVB_USB_DEBUG_STATUS); + +/* keymaps */ +static int ir_keymap; +module_param_named(keymap, ir_keymap, int, 0644); +MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..." + " 256=none"); + +/* demod probe */ +static int demod_probe = 1; +module_param_named(demod, demod_probe, int, 0644); +MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 " + "4=stv0903+stb6100(or-able))."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, + u16 index, u8 * data, u16 len, int flags) +{ + int ret; + u8 *u8buf; + unsigned int pipe = (flags == DW210X_READ_MSG) ? + usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); + u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; + + u8buf = kmalloc(len, GFP_KERNEL); + if (!u8buf) + return -ENOMEM; + + + if (flags == DW210X_WRITE_MSG) + memcpy(u8buf, data, len); + ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, + value, index , u8buf, len, 2000); + + if (flags == DW210X_READ_MSG) + memcpy(data, u8buf, len); + + kfree(u8buf); + return ret; +} + +/* I2C */ +static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i = 0, ret = 0; + u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; + u16 value; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: + /* read stv0299 register */ + value = msg[0].buf[0];/* register */ + for (i = 0; i < msg[1].len; i++) { + ret = dw210x_op_rw(d->udev, 0xb5, value + i, 0, + buf6, 2, DW210X_READ_MSG); + msg[1].buf[i] = buf6[0]; + } + break; + case 1: + switch (msg[0].addr) { + case 0x68: + /* write to stv0299 register */ + buf6[0] = 0x2a; + buf6[1] = msg[0].buf[0]; + buf6[2] = msg[0].buf[1]; + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 3, DW210X_WRITE_MSG); + break; + case 0x60: + if (msg[0].flags == 0) { + /* write to tuner pll */ + buf6[0] = 0x2c; + buf6[1] = 5; + buf6[2] = 0xc0; + buf6[3] = msg[0].buf[0]; + buf6[4] = msg[0].buf[1]; + buf6[5] = msg[0].buf[2]; + buf6[6] = msg[0].buf[3]; + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 7, DW210X_WRITE_MSG); + } else { + /* read from tuner */ + ret = dw210x_op_rw(d->udev, 0xb5, 0, 0, + buf6, 1, DW210X_READ_MSG); + msg[0].buf[0] = buf6[0]; + } + break; + case (DW2102_RC_QUERY): + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + buf6, 2, DW210X_READ_MSG); + msg[0].buf[0] = buf6[0]; + msg[0].buf[1] = buf6[1]; + break; + case (DW2102_VOLTAGE_CTRL): + buf6[0] = 0x30; + buf6[1] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 2, DW210X_WRITE_MSG); + break; + } + + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0; + u8 buf6[] = {0, 0, 0, 0, 0, 0, 0}; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: + /* read si2109 register by number */ + buf6[0] = msg[0].addr << 1; + buf6[1] = msg[0].len; + buf6[2] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + buf6, msg[0].len + 2, DW210X_WRITE_MSG); + /* read si2109 register */ + ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, + buf6, msg[1].len + 2, DW210X_READ_MSG); + memcpy(msg[1].buf, buf6 + 2, msg[1].len); + + break; + case 1: + switch (msg[0].addr) { + case 0x68: + /* write to si2109 register */ + buf6[0] = msg[0].addr << 1; + buf6[1] = msg[0].len; + memcpy(buf6 + 2, msg[0].buf, msg[0].len); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, + msg[0].len + 2, DW210X_WRITE_MSG); + break; + case(DW2102_RC_QUERY): + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + buf6, 2, DW210X_READ_MSG); + msg[0].buf[0] = buf6[0]; + msg[0].buf[1] = buf6[1]; + break; + case(DW2102_VOLTAGE_CTRL): + buf6[0] = 0x30; + buf6[1] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 2, DW210X_WRITE_MSG); + break; + } + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: { + /* read */ + /* first write first register number */ + u8 ibuf[msg[1].len + 2], obuf[3]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + obuf[2] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + /* second read registers */ + ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0, + ibuf, msg[1].len + 2, DW210X_READ_MSG); + memcpy(msg[1].buf, ibuf + 2, msg[1].len); + + break; + } + case 1: + switch (msg[0].addr) { + case 0x68: { + /* write to register */ + u8 obuf[msg[0].len + 2]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + memcpy(obuf + 2, msg[0].buf, msg[0].len); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + break; + } + case 0x61: { + /* write to tuner */ + u8 obuf[msg[0].len + 2]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + memcpy(obuf + 2, msg[0].buf, msg[0].len); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + break; + } + case(DW2102_RC_QUERY): { + u8 ibuf[2]; + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[0].buf, ibuf , 2); + break; + } + case(DW2102_VOLTAGE_CTRL): { + u8 obuf[2]; + obuf[0] = 0x30; + obuf[1] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } + } + + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0; + int len, i, j; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (j = 0; j < num; j++) { + switch (msg[j].addr) { + case(DW2102_RC_QUERY): { + u8 ibuf[2]; + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf , 2); + break; + } + case(DW2102_VOLTAGE_CTRL): { + u8 obuf[2]; + obuf[0] = 0x30; + obuf[1] = msg[j].buf[0]; + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } + /*case 0x55: cx24116 + case 0x6a: stv0903 + case 0x68: ds3000, stv0903 + case 0x60: ts2020, stv6110, stb6100 */ + default: { + if (msg[j].flags == I2C_M_RD) { + /* read registers */ + u8 ibuf[msg[j].len + 2]; + ret = dw210x_op_rw(d->udev, 0xc3, + (msg[j].addr << 1) + 1, 0, + ibuf, msg[j].len + 2, + DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf + 2, msg[j].len); + mdelay(10); + } else if (((msg[j].buf[0] == 0xb0) && + (msg[j].addr == 0x68)) || + ((msg[j].buf[0] == 0xf7) && + (msg[j].addr == 0x55))) { + /* write firmware */ + u8 obuf[19]; + obuf[0] = msg[j].addr << 1; + obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len); + obuf[2] = msg[j].buf[0]; + len = msg[j].len - 1; + i = 1; + do { + memcpy(obuf + 3, msg[j].buf + i, + (len > 16 ? 16 : len)); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); + i += 16; + len -= 16; + } while (len > 0); + } else { + /* write registers */ + u8 obuf[msg[j].len + 2]; + obuf[0] = msg[j].addr << 1; + obuf[1] = msg[j].len; + memcpy(obuf + 2, msg[j].buf, msg[j].len); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + } + break; + } + } + + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, i; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: { + /* read */ + /* first write first register number */ + u8 ibuf[msg[1].len + 2], obuf[3]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + obuf[2] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + /* second read registers */ + ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, + ibuf, msg[1].len + 2, DW210X_READ_MSG); + memcpy(msg[1].buf, ibuf + 2, msg[1].len); + + break; + } + case 1: + switch (msg[0].addr) { + case 0x60: + case 0x0c: { + /* write to register */ + u8 obuf[msg[0].len + 2]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + memcpy(obuf + 2, msg[0].buf, msg[0].len); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + break; + } + case(DW2102_RC_QUERY): { + u8 ibuf[2]; + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[0].buf, ibuf , 2); + break; + } + } + + break; + } + + for (i = 0; i < num; i++) { + deb_xfer("%02x:%02x: %s ", i, msg[i].addr, + msg[i].flags == 0 ? ">>>" : "<<<"); + debug_dump(msg[i].buf, msg[i].len, deb_xfer); + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct usb_device *udev; + int ret = 0; + int len, i, j; + + if (!d) + return -ENODEV; + udev = d->udev; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (j = 0; j < num; j++) { + switch (msg[j].addr) { + case (DW2102_RC_QUERY): { + u8 ibuf[5]; + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 5, DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf + 3, 2); + break; + } + case (DW2102_VOLTAGE_CTRL): { + u8 obuf[2]; + + obuf[0] = 1; + obuf[1] = msg[j].buf[1];/* off-on */ + ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + obuf[0] = 3; + obuf[1] = msg[j].buf[0];/* 13v-18v */ + ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } + case (DW2102_LED_CTRL): { + u8 obuf[2]; + + obuf[0] = 5; + obuf[1] = msg[j].buf[0]; + ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } + /*case 0x55: cx24116 + case 0x6a: stv0903 + case 0x68: ds3000, stv0903 + case 0x60: ts2020, stv6110, stb6100 + case 0xa0: eeprom */ + default: { + if (msg[j].flags == I2C_M_RD) { + /* read registers */ + u8 ibuf[msg[j].len]; + ret = dw210x_op_rw(d->udev, 0x91, 0, 0, + ibuf, msg[j].len, + DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf, msg[j].len); + break; + } else if ((msg[j].buf[0] == 0xb0) && + (msg[j].addr == 0x68)) { + /* write firmware */ + u8 obuf[19]; + obuf[0] = (msg[j].len > 16 ? + 18 : msg[j].len + 1); + obuf[1] = msg[j].addr << 1; + obuf[2] = msg[j].buf[0]; + len = msg[j].len - 1; + i = 1; + do { + memcpy(obuf + 3, msg[j].buf + i, + (len > 16 ? 16 : len)); + ret = dw210x_op_rw(d->udev, 0x80, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); + i += 16; + len -= 16; + } while (len > 0); + } else if (j < (num - 1)) { + /* write register addr before read */ + u8 obuf[msg[j].len + 2]; + obuf[0] = msg[j + 1].len; + obuf[1] = (msg[j].addr << 1); + memcpy(obuf + 2, msg[j].buf, msg[j].len); + ret = dw210x_op_rw(d->udev, + udev->descriptor.idProduct == + 0x7500 ? 0x92 : 0x90, 0, 0, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + break; + } else { + /* write registers */ + u8 obuf[msg[j].len + 2]; + obuf[0] = msg[j].len + 1; + obuf[1] = (msg[j].addr << 1); + memcpy(obuf + 2, msg[j].buf, msg[j].len); + ret = dw210x_op_rw(d->udev, 0x80, 0, 0, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + break; + } + break; + } + } + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + u8 obuf[0x40], ibuf[0x40]; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 1: + switch (msg[0].addr) { + case SU3000_STREAM_CTRL: + obuf[0] = msg[0].buf[0] + 0x36; + obuf[1] = 3; + obuf[2] = 0; + if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0) + err("i2c transfer failed."); + break; + case DW2102_RC_QUERY: + obuf[0] = 0x10; + if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0) + err("i2c transfer failed."); + msg[0].buf[1] = ibuf[0]; + msg[0].buf[0] = ibuf[1]; + break; + default: + /* always i2c write*/ + obuf[0] = 0x08; + obuf[1] = msg[0].addr; + obuf[2] = msg[0].len; + + memcpy(&obuf[3], msg[0].buf, msg[0].len); + + if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3, + ibuf, 1, 0) < 0) + err("i2c transfer failed."); + + } + break; + case 2: + /* always i2c read */ + obuf[0] = 0x09; + obuf[1] = msg[0].len; + obuf[2] = msg[1].len; + obuf[3] = msg[0].addr; + memcpy(&obuf[4], msg[0].buf, msg[0].len); + + if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4, + ibuf, msg[1].len + 1, 0) < 0) + err("i2c transfer failed."); + + memcpy(msg[1].buf, &ibuf[1], msg[1].len); + break; + default: + warn("more than 2 i2c messages at a time is not handled yet."); + break; + } + mutex_unlock(&d->i2c_mutex); + return num; +} + +static u32 dw210x_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dw2102_i2c_algo = { + .master_xfer = dw2102_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm dw2102_serit_i2c_algo = { + .master_xfer = dw2102_serit_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm dw2102_earda_i2c_algo = { + .master_xfer = dw2102_earda_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm dw2104_i2c_algo = { + .master_xfer = dw2104_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm dw3101_i2c_algo = { + .master_xfer = dw3101_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm s6x0_i2c_algo = { + .master_xfer = s6x0_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm su3000_i2c_algo = { + .master_xfer = su3000_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + +static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + int i; + u8 ibuf[] = {0, 0}; + u8 eeprom[256], eepromline[16]; + + for (i = 0; i < 256; i++) { + if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) { + err("read eeprom failed."); + return -1; + } else { + eepromline[i%16] = ibuf[0]; + eeprom[i] = ibuf[0]; + } + if ((i % 16) == 15) { + deb_xfer("%02x: ", i - 15); + debug_dump(eepromline, 16, deb_xfer); + } + } + + memcpy(mac, eeprom + 8, 6); + return 0; +}; + +static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + int i, ret; + u8 ibuf[] = { 0 }, obuf[] = { 0 }; + u8 eeprom[256], eepromline[16]; + struct i2c_msg msg[] = { + { + .addr = 0xa0 >> 1, + .flags = 0, + .buf = obuf, + .len = 1, + }, { + .addr = 0xa0 >> 1, + .flags = I2C_M_RD, + .buf = ibuf, + .len = 1, + } + }; + + for (i = 0; i < 256; i++) { + obuf[0] = i; + ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2); + if (ret != 2) { + err("read eeprom failed."); + return -1; + } else { + eepromline[i % 16] = ibuf[0]; + eeprom[i] = ibuf[0]; + } + + if ((i % 16) == 15) { + deb_xfer("%02x: ", i - 15); + debug_dump(eepromline, 16, deb_xfer); + } + } + + memcpy(mac, eeprom + 16, 6); + return 0; +}; + +static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + static u8 command_start[] = {0x00}; + static u8 command_stop[] = {0x01}; + struct i2c_msg msg = { + .addr = SU3000_STREAM_CTRL, + .flags = 0, + .buf = onoff ? command_start : command_stop, + .len = 1 + }; + + i2c_transfer(&adap->dev->i2c_adap, &msg, 1); + + return 0; +} + +static int su3000_power_ctrl(struct dvb_usb_device *d, int i) +{ + struct su3000_state *state = (struct su3000_state *)d->priv; + u8 obuf[] = {0xde, 0}; + + info("%s: %d, initialized %d\n", __func__, i, state->initialized); + + if (i && !state->initialized) { + state->initialized = 1; + /* reset board */ + dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0); + } + + return 0; +} + +static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + int i; + u8 obuf[] = { 0x1f, 0xf0 }; + u8 ibuf[] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = 0x51, + .flags = 0, + .buf = obuf, + .len = 2, + }, { + .addr = 0x51, + .flags = I2C_M_RD, + .buf = ibuf, + .len = 1, + + } + }; + + for (i = 0; i < 6; i++) { + obuf[1] = 0xf0 + i; + if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) + break; + else + mac[i] = ibuf[0]; + + debug_dump(mac, 6, printk); + } + + return 0; +} + +static int su3000_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + info("%s\n", __func__); + + *cold = 0; + return 0; +} + +static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + static u8 command_13v[] = {0x00, 0x01}; + static u8 command_18v[] = {0x01, 0x01}; + static u8 command_off[] = {0x00, 0x00}; + struct i2c_msg msg = { + .addr = DW2102_VOLTAGE_CTRL, + .flags = 0, + .buf = command_off, + .len = 2, + }; + + struct dvb_usb_adapter *udev_adap = + (struct dvb_usb_adapter *)(fe->dvb->priv); + if (voltage == SEC_VOLTAGE_18) + msg.buf = command_18v; + else if (voltage == SEC_VOLTAGE_13) + msg.buf = command_13v; + + i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); + + return 0; +} + +static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct dvb_usb_adapter *d = + (struct dvb_usb_adapter *)(fe->dvb->priv); + struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; + + dw210x_set_voltage(fe, voltage); + if (st->old_set_voltage) + st->old_set_voltage(fe, voltage); + + return 0; +} + +static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) +{ + static u8 led_off[] = { 0 }; + static u8 led_on[] = { 1 }; + struct i2c_msg msg = { + .addr = DW2102_LED_CTRL, + .flags = 0, + .buf = led_off, + .len = 1 + }; + struct dvb_usb_adapter *udev_adap = + (struct dvb_usb_adapter *)(fe->dvb->priv); + + if (offon) + msg.buf = led_on; + i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); +} + +static struct stv0299_config sharp_z0194a_config = { + .demod_address = 0x68, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + +static struct cx24116_config dw2104_config = { + .demod_address = 0x55, + .mpg_clk_pos_pol = 0x01, +}; + +static struct si21xx_config serit_sp1511lhb_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + +}; + +static struct tda10023_config dw3101_tda10023_config = { + .demod_address = 0x0c, + .invert = 1, +}; + +static struct mt312_config zl313_config = { + .demod_address = 0x0e, +}; + +static struct ds3000_config dw2104_ds3000_config = { + .demod_address = 0x68, +}; + +static struct stv0900_config dw2104a_stv0900_config = { + .demod_address = 0x6a, + .demod_mode = 0, + .xtal = 27000000, + .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ + .diseqc_mode = 2,/* 2/3 PWM */ + .tun1_maddress = 0,/* 0x60 */ + .tun1_adc = 0,/* 2 Vpp */ + .path1_mode = 3, +}; + +static struct stb6100_config dw2104a_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static struct stv0900_config dw2104_stv0900_config = { + .demod_address = 0x68, + .demod_mode = 0, + .xtal = 8000000, + .clkmode = 3, + .diseqc_mode = 2, + .tun1_maddress = 0, + .tun1_adc = 1,/* 1 Vpp */ + .path1_mode = 3, +}; + +static struct stv6110_config dw2104_stv6110_config = { + .i2c_address = 0x60, + .mclk = 16000000, + .clk_div = 1, +}; + +static struct stv0900_config prof_7500_stv0900_config = { + .demod_address = 0x6a, + .demod_mode = 0, + .xtal = 27000000, + .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ + .diseqc_mode = 2,/* 2/3 PWM */ + .tun1_maddress = 0,/* 0x60 */ + .tun1_adc = 0,/* 2 Vpp */ + .path1_mode = 3, + .tun1_type = 3, + .set_lock_led = dw210x_led_ctrl, +}; + +static struct ds3000_config su3000_ds3000_config = { + .demod_address = 0x68, + .ci_mode = 1, +}; + +static int dw2104_frontend_attach(struct dvb_usb_adapter *d) +{ + struct dvb_tuner_ops *tuner_ops = NULL; + + if (demod_probe & 4) { + d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe != NULL) { + if (dvb_attach(stb6100_attach, d->fe, + &dw2104a_stb6100_config, + &d->dev->i2c_adap)) { + tuner_ops = &d->fe->ops.tuner_ops; + tuner_ops->set_frequency = stb6100_set_freq; + tuner_ops->get_frequency = stb6100_get_freq; + tuner_ops->set_bandwidth = stb6100_set_bandw; + tuner_ops->get_bandwidth = stb6100_get_bandw; + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached STV0900+STB6100!\n"); + return 0; + } + } + } + + if (demod_probe & 2) { + d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe != NULL) { + if (dvb_attach(stv6110_attach, d->fe, + &dw2104_stv6110_config, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached STV0900+STV6110A!\n"); + return 0; + } + } + } + + if (demod_probe & 1) { + d->fe = dvb_attach(cx24116_attach, &dw2104_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached cx24116!\n"); + return 0; + } + } + + d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached DS3000!\n"); + return 0; + } + + return -EIO; +} + +static struct dvb_usb_device_properties dw2102_properties; +static struct dvb_usb_device_properties dw2104_properties; +static struct dvb_usb_device_properties s6x0_properties; + +static int dw2102_frontend_attach(struct dvb_usb_adapter *d) +{ + if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { + /*dw2102_properties.adapter->tuner_attach = NULL;*/ + d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached si21xx!\n"); + return 0; + } + } + + if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { + d->fe = dvb_attach(stv0288_attach, &earda_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + if (dvb_attach(stb6000_attach, d->fe, 0x61, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0288!\n"); + return 0; + } + } + } + + if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { + /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ + d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0299!\n"); + return 0; + } + } + return -EIO; +} + +static int dw3101_frontend_attach(struct dvb_usb_adapter *d) +{ + d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, + &d->dev->i2c_adap, 0x48); + if (d->fe != NULL) { + info("Attached tda10023!\n"); + return 0; + } + return -EIO; +} + +static int zl100313_frontend_attach(struct dvb_usb_adapter *d) +{ + d->fe = dvb_attach(mt312_attach, &zl313_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + if (dvb_attach(zl10039_attach, d->fe, 0x60, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached zl100313+zl10039!\n"); + return 0; + } + } + + return -EIO; +} + +static int stv0288_frontend_attach(struct dvb_usb_adapter *d) +{ + u8 obuf[] = {7, 1}; + + d->fe = dvb_attach(stv0288_attach, &earda_config, + &d->dev->i2c_adap); + + if (d->fe == NULL) + return -EIO; + + if (NULL == dvb_attach(stb6000_attach, d->fe, 0x61, &d->dev->i2c_adap)) + return -EIO; + + d->fe->ops.set_voltage = dw210x_set_voltage; + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + + info("Attached stv0288+stb6000!\n"); + + return 0; + +} + +static int ds3000_frontend_attach(struct dvb_usb_adapter *d) +{ + struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; + u8 obuf[] = {7, 1}; + + d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + &d->dev->i2c_adap); + + if (d->fe == NULL) + return -EIO; + + st->old_set_voltage = d->fe->ops.set_voltage; + d->fe->ops.set_voltage = s660_set_voltage; + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + + info("Attached ds3000+ds2020!\n"); + + return 0; +} + +static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) +{ + u8 obuf[] = {7, 1}; + + d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe == NULL) + return -EIO; + + d->fe->ops.set_voltage = dw210x_set_voltage; + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + + info("Attached STV0900+STB6100A!\n"); + + return 0; +} + +static int su3000_frontend_attach(struct dvb_usb_adapter *d) +{ + u8 obuf[3] = { 0xe, 0x80, 0 }; + u8 ibuf[] = { 0 }; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0xe; + obuf[1] = 0x83; + obuf[2] = 0; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0xe; + obuf[1] = 0x83; + obuf[2] = 1; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0x51; + + if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) + err("command 0x51 transfer failed."); + + d->fe = dvb_attach(ds3000_attach, &su3000_ds3000_config, + &d->dev->i2c_adap); + if (d->fe == NULL) + return -EIO; + + info("Attached DS3000!\n"); + + return 0; +} + +static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe, 0x60, + &adap->dev->i2c_adap, DVB_PLL_OPERA1); + return 0; +} + +static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe, 0x60, + &adap->dev->i2c_adap, DVB_PLL_TUA6034); + + return 0; +} + +static struct rc_map_table rc_map_dw210x_table[] = { + { 0xf80a, KEY_POWER2 }, /*power*/ + { 0xf80c, KEY_MUTE }, /*mute*/ + { 0xf811, KEY_1 }, + { 0xf812, KEY_2 }, + { 0xf813, KEY_3 }, + { 0xf814, KEY_4 }, + { 0xf815, KEY_5 }, + { 0xf816, KEY_6 }, + { 0xf817, KEY_7 }, + { 0xf818, KEY_8 }, + { 0xf819, KEY_9 }, + { 0xf810, KEY_0 }, + { 0xf81c, KEY_CHANNELUP }, /*ch+*/ + { 0xf80f, KEY_CHANNELDOWN }, /*ch-*/ + { 0xf81a, KEY_VOLUMEUP }, /*vol+*/ + { 0xf80e, KEY_VOLUMEDOWN }, /*vol-*/ + { 0xf804, KEY_RECORD }, /*rec*/ + { 0xf809, KEY_FAVORITES }, /*fav*/ + { 0xf808, KEY_REWIND }, /*rewind*/ + { 0xf807, KEY_FASTFORWARD }, /*fast*/ + { 0xf80b, KEY_PAUSE }, /*pause*/ + { 0xf802, KEY_ESC }, /*cancel*/ + { 0xf803, KEY_TAB }, /*tab*/ + { 0xf800, KEY_UP }, /*up*/ + { 0xf81f, KEY_OK }, /*ok*/ + { 0xf801, KEY_DOWN }, /*down*/ + { 0xf805, KEY_CAMERA }, /*cap*/ + { 0xf806, KEY_STOP }, /*stop*/ + { 0xf840, KEY_ZOOM }, /*full*/ + { 0xf81e, KEY_TV }, /*tvmode*/ + { 0xf81b, KEY_LAST }, /*recall*/ +}; + +static struct rc_map_table rc_map_tevii_table[] = { + { 0xf80a, KEY_POWER }, + { 0xf80c, KEY_MUTE }, + { 0xf811, KEY_1 }, + { 0xf812, KEY_2 }, + { 0xf813, KEY_3 }, + { 0xf814, KEY_4 }, + { 0xf815, KEY_5 }, + { 0xf816, KEY_6 }, + { 0xf817, KEY_7 }, + { 0xf818, KEY_8 }, + { 0xf819, KEY_9 }, + { 0xf810, KEY_0 }, + { 0xf81c, KEY_MENU }, + { 0xf80f, KEY_VOLUMEDOWN }, + { 0xf81a, KEY_LAST }, + { 0xf80e, KEY_OPEN }, + { 0xf804, KEY_RECORD }, + { 0xf809, KEY_VOLUMEUP }, + { 0xf808, KEY_CHANNELUP }, + { 0xf807, KEY_PVR }, + { 0xf80b, KEY_TIME }, + { 0xf802, KEY_RIGHT }, + { 0xf803, KEY_LEFT }, + { 0xf800, KEY_UP }, + { 0xf81f, KEY_OK }, + { 0xf801, KEY_DOWN }, + { 0xf805, KEY_TUNER }, + { 0xf806, KEY_CHANNELDOWN }, + { 0xf840, KEY_PLAYPAUSE }, + { 0xf81e, KEY_REWIND }, + { 0xf81b, KEY_FAVORITES }, + { 0xf81d, KEY_BACK }, + { 0xf84d, KEY_FASTFORWARD }, + { 0xf844, KEY_EPG }, + { 0xf84c, KEY_INFO }, + { 0xf841, KEY_AB }, + { 0xf843, KEY_AUDIO }, + { 0xf845, KEY_SUBTITLE }, + { 0xf84a, KEY_LIST }, + { 0xf846, KEY_F1 }, + { 0xf847, KEY_F2 }, + { 0xf85e, KEY_F3 }, + { 0xf85c, KEY_F4 }, + { 0xf852, KEY_F5 }, + { 0xf85a, KEY_F6 }, + { 0xf856, KEY_MODE }, + { 0xf858, KEY_SWITCHVIDEOMODE }, +}; + +static struct rc_map_table rc_map_tbs_table[] = { + { 0xf884, KEY_POWER }, + { 0xf894, KEY_MUTE }, + { 0xf887, KEY_1 }, + { 0xf886, KEY_2 }, + { 0xf885, KEY_3 }, + { 0xf88b, KEY_4 }, + { 0xf88a, KEY_5 }, + { 0xf889, KEY_6 }, + { 0xf88f, KEY_7 }, + { 0xf88e, KEY_8 }, + { 0xf88d, KEY_9 }, + { 0xf892, KEY_0 }, + { 0xf896, KEY_CHANNELUP }, + { 0xf891, KEY_CHANNELDOWN }, + { 0xf893, KEY_VOLUMEUP }, + { 0xf88c, KEY_VOLUMEDOWN }, + { 0xf883, KEY_RECORD }, + { 0xf898, KEY_PAUSE }, + { 0xf899, KEY_OK }, + { 0xf89a, KEY_SHUFFLE }, + { 0xf881, KEY_UP }, + { 0xf890, KEY_LEFT }, + { 0xf882, KEY_RIGHT }, + { 0xf888, KEY_DOWN }, + { 0xf895, KEY_FAVORITES }, + { 0xf897, KEY_SUBTITLE }, + { 0xf89d, KEY_ZOOM }, + { 0xf89f, KEY_EXIT }, + { 0xf89e, KEY_MENU }, + { 0xf89c, KEY_EPG }, + { 0xf880, KEY_PREVIOUS }, + { 0xf89b, KEY_MODE } +}; + +static struct rc_map_table rc_map_su3000_table[] = { + { 0x25, KEY_POWER }, /* right-bottom Red */ + { 0x0a, KEY_MUTE }, /* -/-- */ + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + { 0x00, KEY_0 }, + { 0x20, KEY_UP }, /* CH+ */ + { 0x21, KEY_DOWN }, /* CH+ */ + { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ + { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */ + { 0x1f, KEY_RECORD }, + { 0x17, KEY_PLAY }, + { 0x16, KEY_PAUSE }, + { 0x0b, KEY_STOP }, + { 0x27, KEY_FASTFORWARD },/* >> */ + { 0x26, KEY_REWIND }, /* << */ + { 0x0d, KEY_OK }, /* Mute */ + { 0x11, KEY_LEFT }, /* VOL- */ + { 0x10, KEY_RIGHT }, /* VOL+ */ + { 0x29, KEY_BACK }, /* button under 9 */ + { 0x2c, KEY_MENU }, /* TTX */ + { 0x2b, KEY_EPG }, /* EPG */ + { 0x1e, KEY_RED }, /* OSD */ + { 0x0e, KEY_GREEN }, /* Window */ + { 0x2d, KEY_YELLOW }, /* button under << */ + { 0x0f, KEY_BLUE }, /* bottom yellow button */ + { 0x14, KEY_AUDIO }, /* Snapshot */ + { 0x38, KEY_TV }, /* TV/Radio */ + { 0x0c, KEY_ESC } /* upper Red button */ +}; + +static struct rc_map_dvb_usb_table_table keys_tables[] = { + { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) }, + { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) }, + { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) }, + { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) }, +}; + +static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + int keymap_size = d->props.rc.legacy.rc_map_size; + u8 key[2]; + struct i2c_msg msg = { + .addr = DW2102_RC_QUERY, + .flags = I2C_M_RD, + .buf = key, + .len = 2 + }; + int i; + /* override keymap */ + if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) { + keymap = keys_tables[ir_keymap - 1].rc_keys ; + keymap_size = keys_tables[ir_keymap - 1].rc_keys_size; + } else if (ir_keymap > ARRAY_SIZE(keys_tables)) + return 0; /* none */ + + *state = REMOTE_NO_KEY_PRESSED; + if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { + for (i = 0; i < keymap_size ; i++) { + if (rc5_data(&keymap[i]) == msg.buf[0]) { + *state = REMOTE_KEY_PRESSED; + *event = keymap[i].keycode; + break; + } + + } + + if ((*state) == REMOTE_KEY_PRESSED) + deb_rc("%s: found rc key: %x, %x, event: %x\n", + __func__, key[0], key[1], (*event)); + else if (key[0] != 0xff) + deb_rc("%s: unknown rc key: %x, %x\n", + __func__, key[0], key[1]); + + } + + return 0; +} + +static struct usb_device_id dw2102_table[] = { + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, + {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, + {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, + {USB_DEVICE(0x3034, 0x7500)}, + {USB_DEVICE(0x1f4d, 0x3000)}, + {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, + {USB_DEVICE(0x1f4d, 0x3100)}, + { } +}; + +MODULE_DEVICE_TABLE(usb, dw2102_table); + +static int dw2102_load_firmware(struct usb_device *dev, + const struct firmware *frmwr) +{ + u8 *b, *p; + int ret = 0, i; + u8 reset; + u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; + const struct firmware *fw; + const char *fw_2101 = "dvb-usb-dw2101.fw"; + + switch (dev->descriptor.idProduct) { + case 0x2101: + ret = request_firmware(&fw, fw_2101, &dev->dev); + if (ret != 0) { + err(err_str, fw_2101); + return ret; + } + break; + default: + fw = frmwr; + break; + } + info("start downloading DW210X firmware"); + p = kmalloc(fw->size, GFP_KERNEL); + reset = 1; + /*stop the CPU*/ + dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG); + + if (p != NULL) { + memcpy(p, fw->data, fw->size); + for (i = 0; i < fw->size; i += 0x40) { + b = (u8 *) p + i; + if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40, + DW210X_WRITE_MSG) != 0x40) { + err("error while transferring firmware"); + ret = -EINVAL; + break; + } + } + /* restart the CPU */ + reset = 0; + if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, + DW210X_WRITE_MSG) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, + DW210X_WRITE_MSG) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + /* init registers */ + switch (dev->descriptor.idProduct) { + case USB_PID_TEVII_S650: + dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table; + dw2104_properties.rc.legacy.rc_map_size = + ARRAY_SIZE(rc_map_tevii_table); + case USB_PID_DW2104: + reset = 1; + dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, + DW210X_WRITE_MSG); + /* break omitted intentionally */ + case USB_PID_DW3101: + reset = 0; + dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, + DW210X_WRITE_MSG); + break; + case USB_PID_CINERGY_S: + case USB_PID_DW2102: + dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, + DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, + DW210X_READ_MSG); + /* check STV0299 frontend */ + dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, + DW210X_READ_MSG); + if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) { + dw2102_properties.i2c_algo = &dw2102_i2c_algo; + dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach; + break; + } else { + /* check STV0288 frontend */ + reset16[0] = 0xd0; + reset16[1] = 1; + reset16[2] = 0; + dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3, + DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3, + DW210X_READ_MSG); + if (reset16[2] == 0x11) { + dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; + break; + } + } + case 0x2101: + dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, + DW210X_READ_MSG); + dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, + DW210X_READ_MSG); + dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, + DW210X_READ_MSG); + dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, + DW210X_READ_MSG); + break; + } + + msleep(100); + kfree(p); + } + return ret; +} + +static struct dvb_usb_device_properties dw2102_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dw2102.fw", + .no_reconnect = 1, + + .i2c_algo = &dw2102_serit_i2c_algo, + + .rc.legacy = { + .rc_map_table = rc_map_dw210x_table, + .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x81, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = dw210x_read_mac_address, + .adapter = { + { + .frontend_attach = dw2102_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .num_device_descs = 3, + .devices = { + {"DVBWorld DVB-S 2102 USB2.0", + {&dw2102_table[0], NULL}, + {NULL}, + }, + {"DVBWorld DVB-S 2101 USB2.0", + {&dw2102_table[1], NULL}, + {NULL}, + }, + {"TerraTec Cinergy S USB", + {&dw2102_table[4], NULL}, + {NULL}, + }, + } +}; + +static struct dvb_usb_device_properties dw2104_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dw2104.fw", + .no_reconnect = 1, + + .i2c_algo = &dw2104_i2c_algo, + .rc.legacy = { + .rc_map_table = rc_map_dw210x_table, + .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x81, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = dw210x_read_mac_address, + .adapter = { + { + .frontend_attach = dw2104_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .num_device_descs = 2, + .devices = { + { "DVBWorld DW2104 USB2.0", + {&dw2102_table[2], NULL}, + {NULL}, + }, + { "TeVii S650 USB2.0", + {&dw2102_table[3], NULL}, + {NULL}, + }, + } +}; + +static struct dvb_usb_device_properties dw3101_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dw3101.fw", + .no_reconnect = 1, + + .i2c_algo = &dw3101_i2c_algo, + .rc.legacy = { + .rc_map_table = rc_map_dw210x_table, + .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x81, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = dw210x_read_mac_address, + .adapter = { + { + .frontend_attach = dw3101_frontend_attach, + .tuner_attach = dw3101_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .num_device_descs = 1, + .devices = { + { "DVBWorld DVB-C 3101 USB2.0", + {&dw2102_table[5], NULL}, + {NULL}, + }, + } +}; + +static struct dvb_usb_device_properties s6x0_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct s6x0_state), + .firmware = "dvb-usb-s630.fw", + .no_reconnect = 1, + + .i2c_algo = &s6x0_i2c_algo, + .rc.legacy = { + .rc_map_table = rc_map_tevii_table, + .rc_map_size = ARRAY_SIZE(rc_map_tevii_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x81, + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = s6x0_read_mac_address, + .adapter = { + { + .frontend_attach = zl100313_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .num_device_descs = 1, + .devices = { + {"TeVii S630 USB", + {&dw2102_table[6], NULL}, + {NULL}, + }, + } +}; + +struct dvb_usb_device_properties *p1100; +static struct dvb_usb_device_description d1100 = { + "Prof 1100 USB ", + {&dw2102_table[7], NULL}, + {NULL}, +}; + +struct dvb_usb_device_properties *s660; +static struct dvb_usb_device_description d660 = { + "TeVii S660 USB", + {&dw2102_table[8], NULL}, + {NULL}, +}; + +static struct dvb_usb_device_description d480_1 = { + "TeVii S480.1 USB", + {&dw2102_table[12], NULL}, + {NULL}, +}; + +static struct dvb_usb_device_description d480_2 = { + "TeVii S480.2 USB", + {&dw2102_table[13], NULL}, + {NULL}, +}; + +struct dvb_usb_device_properties *p7500; +static struct dvb_usb_device_description d7500 = { + "Prof 7500 USB DVB-S2", + {&dw2102_table[9], NULL}, + {NULL}, +}; + +static struct dvb_usb_device_properties su3000_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct su3000_state), + .power_ctrl = su3000_power_ctrl, + .num_adapters = 1, + .identify_state = su3000_identify_state, + .i2c_algo = &su3000_i2c_algo, + + .rc.legacy = { + .rc_map_table = rc_map_su3000_table, + .rc_map_size = ARRAY_SIZE(rc_map_su3000_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .read_mac_address = su3000_read_mac_address, + + .generic_bulk_ctrl_endpoint = 0x01, + + .adapter = { + { + .streaming_ctrl = su3000_streaming_ctrl, + .frontend_attach = su3000_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + } + } + }, + .num_device_descs = 3, + .devices = { + { "SU3000HD DVB-S USB2.0", + { &dw2102_table[10], NULL }, + { NULL }, + }, + { "Terratec Cinergy S2 USB HD", + { &dw2102_table[11], NULL }, + { NULL }, + }, + { "X3M TV SPC1400HD PCI", + { &dw2102_table[14], NULL }, + { NULL }, + }, + } +}; + +static int dw2102_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + p1100 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + if (!p1100) + return -ENOMEM; + /* copy default structure */ + memcpy(p1100, &s6x0_properties, + sizeof(struct dvb_usb_device_properties)); + /* fill only different fields */ + p1100->firmware = "dvb-usb-p1100.fw"; + p1100->devices[0] = d1100; + p1100->rc.legacy.rc_map_table = rc_map_tbs_table; + p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); + p1100->adapter->frontend_attach = stv0288_frontend_attach; + + s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + if (!s660) { + kfree(p1100); + return -ENOMEM; + } + memcpy(s660, &s6x0_properties, + sizeof(struct dvb_usb_device_properties)); + s660->firmware = "dvb-usb-s660.fw"; + s660->num_device_descs = 3; + s660->devices[0] = d660; + s660->devices[1] = d480_1; + s660->devices[2] = d480_2; + s660->adapter->frontend_attach = ds3000_frontend_attach; + + p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + if (!p7500) { + kfree(p1100); + kfree(s660); + return -ENOMEM; + } + memcpy(p7500, &s6x0_properties, + sizeof(struct dvb_usb_device_properties)); + p7500->firmware = "dvb-usb-p7500.fw"; + p7500->devices[0] = d7500; + p7500->rc.legacy.rc_map_table = rc_map_tbs_table; + p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); + p7500->adapter->frontend_attach = prof_7500_frontend_attach; + + if (0 == dvb_usb_device_init(intf, &dw2102_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dw2104_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dw3101_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &s6x0_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, p1100, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, s660, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, p7500, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &su3000_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + + return -ENODEV; +} + +static struct usb_driver dw2102_driver = { + .name = "dw2102", + .probe = dw2102_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dw2102_table, +}; + +static int __init dw2102_module_init(void) +{ + int ret = usb_register(&dw2102_driver); + if (ret) + err("usb_register failed. Error number %d", ret); + + return ret; +} + +static void __exit dw2102_module_exit(void) +{ + usb_deregister(&dw2102_driver); +} + +module_init(dw2102_module_init); +module_exit(dw2102_module_exit); + +MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); +MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," + " DVB-C 3101 USB2.0," + " TeVii S600, S630, S650, S660, S480," + " Prof 1100, 7500 USB2.0," + " Geniatech SU3000 devices"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dw2102.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dw2102.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dw2102.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/dw2102.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,9 @@ +#ifndef _DW2102_H_ +#define _DW2102_H_ + +#define DVB_USB_LOG_PREFIX "dw2102" +#include "dvb-usb.h" + +#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_dw2102_debug, 0x04, args) +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ec168.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ec168.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ec168.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ec168.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,452 @@ +/* + * E3C EC168 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "ec168.h" +#include "ec100.h" +#include "mxl5005s.h" + +/* debug */ +static int dvb_usb_ec168_debug; +module_param_named(debug, dvb_usb_ec168_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static struct ec100_config ec168_ec100_config; + +static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req) +{ + int ret; + unsigned int pipe; + u8 request, requesttype; + u8 *buf; + + + + switch (req->cmd) { + case DOWNLOAD_FIRMWARE: + case GPIO: + case WRITE_I2C: + case STREAMING_CTRL: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + request = req->cmd; + break; + case READ_I2C: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + request = req->cmd; + break; + case GET_CONFIG: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + request = CONFIG; + break; + case SET_CONFIG: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + request = CONFIG; + break; + case WRITE_DEMOD: + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + request = DEMOD_RW; + break; + case READ_DEMOD: + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + request = DEMOD_RW; + break; + default: + err("unknown command:%02x", req->cmd); + ret = -EPERM; + goto error; + } + + buf = kmalloc(req->size, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto error; + } + + if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { + /* write */ + memcpy(buf, req->data, req->size); + pipe = usb_sndctrlpipe(udev, 0); + } else { + /* read */ + pipe = usb_rcvctrlpipe(udev, 0); + } + + msleep(1); /* avoid I2C errors */ + + ret = usb_control_msg(udev, pipe, request, requesttype, req->value, + req->index, buf, req->size, EC168_USB_TIMEOUT); + + ec168_debug_dump(request, requesttype, req->value, req->index, buf, + req->size, deb_xfer); + + if (ret < 0) + goto err_dealloc; + else + ret = 0; + + /* read request, copy returned data to return buf */ + if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) + memcpy(req->data, buf, req->size); + + kfree(buf); + return ret; + +err_dealloc: + kfree(buf); +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + +static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) +{ + return ec168_rw_udev(d->udev, req); +} + +/* I2C */ +static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct ec168_req req; + int i = 0; + int ret; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].addr == ec168_ec100_config.demod_address) { + req.cmd = READ_DEMOD; + req.value = 0; + req.index = 0xff00 + msg[i].buf[0]; /* reg */ + req.size = msg[i+1].len; /* bytes to read */ + req.data = &msg[i+1].buf[0]; + ret = ec168_ctrl_msg(d, &req); + i += 2; + } else { + err("I2C read not implemented"); + ret = -ENOSYS; + i += 2; + } + } else { + if (msg[i].addr == ec168_ec100_config.demod_address) { + req.cmd = WRITE_DEMOD; + req.value = msg[i].buf[1]; /* val */ + req.index = 0xff00 + msg[i].buf[0]; /* reg */ + req.size = 0; + req.data = NULL; + ret = ec168_ctrl_msg(d, &req); + i += 1; + } else { + req.cmd = WRITE_I2C; + req.value = msg[i].buf[0]; /* val */ + req.index = 0x0100 + msg[i].addr; /* I2C addr */ + req.size = msg[i].len-1; + req.data = &msg[i].buf[1]; + ret = ec168_ctrl_msg(d, &req); + i += 1; + } + } + if (ret) + goto error; + + } + ret = i; + +error: + mutex_unlock(&d->i2c_mutex); + return i; +} + + +static u32 ec168_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm ec168_i2c_algo = { + .master_xfer = ec168_i2c_xfer, + .functionality = ec168_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct ec100_config ec168_ec100_config = { + .demod_address = 0xff, /* not real address, demod is integrated */ +}; + +static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) +{ + deb_info("%s:\n", __func__); + adap->fe = dvb_attach(ec100_attach, &ec168_ec100_config, + &adap->dev->i2c_adap); + if (adap->fe == NULL) + return -ENODEV; + + return 0; +} + +static struct mxl5005s_config ec168_mxl5003s_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_OFF, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) +{ + deb_info("%s:\n", __func__); + return dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap, + &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; +} + +static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL}; + deb_info("%s: onoff:%d\n", __func__, onoff); + if (onoff) + req.index = 0x0102; + return ec168_ctrl_msg(adap->dev, &req); +} + +static int ec168_download_firmware(struct usb_device *udev, + const struct firmware *fw) +{ + int i, len, packets, remainder, ret; + u16 addr = 0x0000; /* firmware start address */ + struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; + deb_info("%s:\n", __func__); + + #define FW_PACKET_MAX_DATA 2048 + packets = fw->size / FW_PACKET_MAX_DATA; + remainder = fw->size % FW_PACKET_MAX_DATA; + len = FW_PACKET_MAX_DATA; + for (i = 0; i <= packets; i++) { + if (i == packets) /* set size of the last packet */ + len = remainder; + + req.size = len; + req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); + req.index = addr; + addr += FW_PACKET_MAX_DATA; + + ret = ec168_rw_udev(udev, &req); + if (ret) { + err("firmware download failed:%d packet:%d", ret, i); + goto error; + } + } + req.size = 0; + + /* set "warm"? */ + req.cmd = SET_CONFIG; + req.value = 0; + req.index = 0x0001; + ret = ec168_rw_udev(udev, &req); + if (ret) + goto error; + + /* really needed - no idea what does */ + req.cmd = GPIO; + req.value = 0; + req.index = 0x0206; + ret = ec168_rw_udev(udev, &req); + if (ret) + goto error; + + /* activate tuner I2C? */ + req.cmd = WRITE_I2C; + req.value = 0; + req.index = 0x00c6; + ret = ec168_rw_udev(udev, &req); + if (ret) + goto error; + + return ret; +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + +static int ec168_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + int ret; + u8 reply; + struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; + deb_info("%s:\n", __func__); + + ret = ec168_rw_udev(udev, &req); + if (ret) + goto error; + + deb_info("%s: reply:%02x\n", __func__, reply); + + if (reply == 0x01) + *cold = 0; + else + *cold = 1; + + return ret; +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties ec168_properties; + +static int ec168_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + deb_info("%s: interface:%d\n", __func__, + intf->cur_altsetting->desc.bInterfaceNumber); + + ret = dvb_usb_device_init(intf, &ec168_properties, THIS_MODULE, NULL, + adapter_nr); + if (ret) + goto error; + + return ret; +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + +#define E3C_EC168_1689 0 +#define E3C_EC168_FFFA 1 +#define E3C_EC168_FFFB 2 +#define E3C_EC168_1001 3 +#define E3C_EC168_1002 4 + +static struct usb_device_id ec168_id[] = { + [E3C_EC168_1689] = + {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168)}, + [E3C_EC168_FFFA] = + {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2)}, + [E3C_EC168_FFFB] = + {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3)}, + [E3C_EC168_1001] = + {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4)}, + [E3C_EC168_1002] = + {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5)}, + {} /* terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, ec168_id); + +static struct dvb_usb_device_properties ec168_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = ec168_download_firmware, + .firmware = "dvb-usb-ec168.fw", + .no_reconnect = 1, + + .size_of_priv = 0, + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = ec168_streaming_ctrl, + .frontend_attach = ec168_ec100_frontend_attach, + .tuner_attach = ec168_mxl5003s_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = (32*512), + } + } + }, + } + }, + + .identify_state = ec168_identify_state, + + .i2c_algo = &ec168_i2c_algo, + + .num_device_descs = 1, + .devices = { + { + .name = "E3C EC168 DVB-T USB2.0 reference design", + .cold_ids = { + &ec168_id[E3C_EC168_1689], + &ec168_id[E3C_EC168_FFFA], + &ec168_id[E3C_EC168_FFFB], + &ec168_id[E3C_EC168_1001], + &ec168_id[E3C_EC168_1002], + NULL}, + .warm_ids = {NULL}, + }, + } +}; + +static struct usb_driver ec168_driver = { + .name = "dvb_usb_ec168", + .probe = ec168_probe, + .disconnect = dvb_usb_device_exit, + .id_table = ec168_id, +}; + +/* module stuff */ +static int __init ec168_module_init(void) +{ + int ret; + deb_info("%s:\n", __func__); + ret = usb_register(&ec168_driver); + if (ret) + err("module init failed:%d", ret); + + return ret; +} + +static void __exit ec168_module_exit(void) +{ + deb_info("%s:\n", __func__); + /* deregister this driver from the USB subsystem */ + usb_deregister(&ec168_driver); +} + +module_init(ec168_module_init); +module_exit(ec168_module_exit); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("E3C EC168 DVB-T USB2.0 driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ec168.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ec168.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ec168.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ec168.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * E3C EC168 DVB USB driver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef EC168_H +#define EC168_H + +#define DVB_USB_LOG_PREFIX "ec168" +#include "dvb-usb.h" + +#define deb_info(args...) dprintk(dvb_usb_ec168_debug, 0x01, args) +#define deb_rc(args...) dprintk(dvb_usb_ec168_debug, 0x02, args) +#define deb_xfer(args...) dprintk(dvb_usb_ec168_debug, 0x04, args) +#define deb_reg(args...) dprintk(dvb_usb_ec168_debug, 0x08, args) +#define deb_i2c(args...) dprintk(dvb_usb_ec168_debug, 0x10, args) +#define deb_fw(args...) dprintk(dvb_usb_ec168_debug, 0x20, args) + +#define ec168_debug_dump(r, t, v, i, b, l, func) { \ + int loop_; \ + func("%02x %02x %02x %02x %02x %02x %02x %02x", \ + t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \ + if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ + func(" >>> "); \ + else \ + func(" <<< "); \ + for (loop_ = 0; loop_ < l; loop_++) \ + func("%02x ", b[loop_]); \ + func("\n");\ +} + +#define EC168_USB_TIMEOUT 1000 + +struct ec168_req { + u8 cmd; /* [1] */ + u16 value; /* [2|3] */ + u16 index; /* [4|5] */ + u16 size; /* [6|7] */ + u8 *data; +}; + +enum ec168_cmd { + DOWNLOAD_FIRMWARE = 0x00, + CONFIG = 0x01, + DEMOD_RW = 0x03, + GPIO = 0x04, + STREAMING_CTRL = 0x10, + READ_I2C = 0x20, + WRITE_I2C = 0x21, + HID_DOWNLOAD = 0x30, + GET_CONFIG, + SET_CONFIG, + READ_DEMOD, + WRITE_DEMOD, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,539 @@ +/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. + * + * Copyright (C) 2009 Akihiro Tsukada + * + * This module is based off the the gl861 and vp702x modules. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "friio.h" + +/* debug */ +int dvb_usb_friio_debug; +module_param_named(debug, dvb_usb_friio_debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))." + DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/** + * Indirect I2C access to the PLL via FE. + * whole I2C protocol data to the PLL is sent via the FE's I2C register. + * This is done by a control msg to the FE with the I2C data accompanied, and + * a specific USB request number is assigned for that purpose. + * + * this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE). + * TODO: refoctored, smarter i2c functions. + */ +static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u16 index = wbuf[0]; /* must be JDVBT90502_2ND_I2C_REG(=0xFE) */ + u16 value = addr << (8 + 1); + int wo = (rbuf == NULL || rlen == 0); /* write only */ + u8 req, type; + + deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n", + wbuf[1], wbuf[0], wlen - 1); + + if (wo && wlen >= 2) { + req = GL861_REQ_I2C_DATA_CTRL_WRITE; + type = GL861_WRITE; + udelay(20); + return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + req, type, value, index, + &wbuf[1], wlen - 1, 2000); + } + + deb_xfer("not supported ctrl-msg, aborting."); + return -EINVAL; +} + +/* normal I2C access (without extra data arguments). + * write to the register wbuf[0] at I2C address addr with the value wbuf[1], + * or read from the register wbuf[0]. + * register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3 + */ +static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u16 index; + u16 value = addr << (8 + 1); + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + u8 req, type; + unsigned int pipe; + + /* special case for the indirect I2C access to the PLL via FE, */ + if (addr == friio_fe_config.demod_address && + wbuf[0] == JDVBT90502_2ND_I2C_REG) + return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen); + + if (wo) { + req = GL861_REQ_I2C_WRITE; + type = GL861_WRITE; + pipe = usb_sndctrlpipe(d->udev, 0); + } else { /* rw */ + req = GL861_REQ_I2C_READ; + type = GL861_READ; + pipe = usb_rcvctrlpipe(d->udev, 0); + } + + switch (wlen) { + case 1: + index = wbuf[0]; + break; + case 2: + index = wbuf[0]; + value = value + wbuf[1]; + break; + case 3: + /* special case for 16bit register-address */ + index = (wbuf[2] << 8) | wbuf[0]; + value = value + wbuf[1]; + break; + default: + deb_xfer("wlen = %x, aborting.", wlen); + return -EINVAL; + } + msleep(1); + return usb_control_msg(d->udev, pipe, req, type, + value, index, rbuf, rlen, 2000); +} + +/* I2C */ +static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { + if (gl861_i2c_msg(d, msg[i].addr, + msg[i].buf, msg[i].len, + msg[i + 1].buf, msg[i + 1].len) < 0) + break; + i++; + } else + if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, NULL, 0) < 0) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 gl861_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static int friio_ext_ctl(struct dvb_usb_adapter *adap, + u32 sat_color, int lnb_on) +{ + int i; + int ret; + struct i2c_msg msg; + u8 *buf; + u32 mask; + u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + msg.addr = 0x00; + msg.flags = 0; + msg.len = 2; + msg.buf = buf; + + buf[0] = 0x00; + + /* send 2bit header (&B10) */ + buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE; + ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); + buf[1] |= FRIIO_CTL_CLK; + ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); + + buf[1] = lnb | FRIIO_CTL_STROBE; + ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); + buf[1] |= FRIIO_CTL_CLK; + ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); + + /* send 32bit(satur, R, G, B) data in serial */ + mask = 1 << 31; + for (i = 0; i < 32; i++) { + buf[1] = lnb | FRIIO_CTL_STROBE; + if (sat_color & mask) + buf[1] |= FRIIO_CTL_LED; + ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); + buf[1] |= FRIIO_CTL_CLK; + ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); + mask >>= 1; + } + + /* set the strobe off */ + buf[1] = lnb; + ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); + buf[1] |= FRIIO_CTL_CLK; + ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1); + + kfree(buf); + return (ret == 70); +} + + +static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); + +/* TODO: move these init cmds to the FE's init routine? */ +static u8 streaming_init_cmds[][2] = { + {0x33, 0x08}, + {0x37, 0x40}, + {0x3A, 0x1F}, + {0x3B, 0xFF}, + {0x3C, 0x1F}, + {0x3D, 0xFF}, + {0x38, 0x00}, + {0x35, 0x00}, + {0x39, 0x00}, + {0x36, 0x00}, +}; +static int cmdlen = sizeof(streaming_init_cmds) / 2; + +/* + * Command sequence in this init function is a replay + * of the captured USB commands from the Windows proprietary driver. + */ +static int friio_initialize(struct dvb_usb_device *d) +{ + int ret; + int i; + int retry = 0; + u8 *rbuf, *wbuf; + + deb_info("%s called.\n", __func__); + + wbuf = kmalloc(3, GFP_KERNEL); + if (!wbuf) + return -ENOMEM; + + rbuf = kmalloc(2, GFP_KERNEL); + if (!rbuf) { + kfree(wbuf); + return -ENOMEM; + } + + /* use gl861_i2c_msg instead of gl861_i2c_xfer(), */ + /* because the i2c device is not set up yet. */ + wbuf[0] = 0x11; + wbuf[1] = 0x02; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + goto error; + msleep(2); + + wbuf[0] = 0x11; + wbuf[1] = 0x00; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + goto error; + msleep(1); + + /* following msgs should be in the FE's init code? */ + /* cmd sequence to identify the device type? (friio black/white) */ + wbuf[0] = 0x03; + wbuf[1] = 0x80; + /* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */ + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE, + 0x1200, 0x0100, wbuf, 2, 2000); + if (ret < 0) + goto error; + + msleep(2); + wbuf[0] = 0x00; + wbuf[2] = 0x01; /* reg.0x0100 */ + wbuf[1] = 0x00; + ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2); + /* my Friio White returns 0xffff. */ + if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff) + goto error; + + msleep(2); + wbuf[0] = 0x03; + wbuf[1] = 0x80; + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE, + 0x9000, 0x0100, wbuf, 2, 2000); + if (ret < 0) + goto error; + + msleep(2); + wbuf[0] = 0x00; + wbuf[2] = 0x01; /* reg.0x0100 */ + wbuf[1] = 0x00; + ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2); + /* my Friio White returns 0xffff again. */ + if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff) + goto error; + + msleep(1); + +restart: + /* ============ start DEMOD init cmds ================== */ + /* read PLL status to clear the POR bit */ + wbuf[0] = JDVBT90502_2ND_I2C_REG; + wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1; /* +1 for reading */ + ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0); + if (ret < 0) + goto error; + + msleep(5); + /* note: DEMODULATOR has 16bit register-address. */ + wbuf[0] = 0x00; + wbuf[2] = 0x01; /* reg addr: 0x0100 */ + wbuf[1] = 0x00; /* val: not used */ + ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1); + if (ret < 0) + goto error; +/* + msleep(1); + wbuf[0] = 0x80; + wbuf[1] = 0x00; + ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1); + if (ret < 0) + goto error; + */ + if (rbuf[0] & 0x80) { /* still in PowerOnReset state? */ + if (++retry > 3) { + deb_info("failed to get the correct" + " FE demod status:0x%02x\n", rbuf[0]); + goto error; + } + msleep(100); + goto restart; + } + + /* TODO: check return value in rbuf */ + /* =========== end DEMOD init cmds ===================== */ + msleep(1); + + wbuf[0] = 0x30; + wbuf[1] = 0x04; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + goto error; + + msleep(2); + /* following 2 cmds unnecessary? */ + wbuf[0] = 0x00; + wbuf[1] = 0x01; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + goto error; + + wbuf[0] = 0x06; + wbuf[1] = 0x0F; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + goto error; + + /* some streaming ctl cmds (maybe) */ + msleep(10); + for (i = 0; i < cmdlen; i++) { + ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2, + NULL, 0); + if (ret < 0) + goto error; + msleep(1); + } + msleep(20); + + /* change the LED color etc. */ + ret = friio_streaming_ctrl(&d->adapter[0], 0); + if (ret < 0) + goto error; + + return 0; + +error: + kfree(wbuf); + kfree(rbuf); + deb_info("%s:ret == %d\n", __func__, ret); + return -EIO; +} + +/* Callbacks for DVB USB */ + +static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + + deb_info("%s called.(%d)\n", __func__, onoff); + + /* set the LED color and saturation (and LNB on) */ + if (onoff) + ret = friio_ext_ctl(adap, 0x6400ff64, 1); + else + ret = friio_ext_ctl(adap, 0x96ff00ff, 1); + + if (ret != 1) { + deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret); + return -EREMOTEIO; + } + return 0; +} + +static int friio_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (friio_initialize(adap->dev) < 0) + return -EIO; + + adap->fe = jdvbt90502_attach(adap->dev); + if (adap->fe == NULL) + return -EIO; + + return 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties friio_properties; + +static int friio_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + struct usb_host_interface *alt; + int ret; + + if (intf->num_altsetting < GL861_ALTSETTING_COUNT) + return -ENODEV; + + alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING); + if (alt == NULL) { + deb_rc("not alt found!\n"); + return -ENODEV; + } + ret = usb_set_interface(interface_to_usbdev(intf), + alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + if (ret != 0) { + deb_rc("failed to set alt-setting!\n"); + return ret; + } + + ret = dvb_usb_device_init(intf, &friio_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) + friio_streaming_ctrl(&d->adapter[0], 1); + + return ret; +} + + +struct jdvbt90502_config friio_fe_config = { + .demod_address = FRIIO_DEMOD_ADDR, + .pll_address = FRIIO_PLL_ADDR, +}; + +static struct i2c_algorithm gl861_i2c_algo = { + .master_xfer = gl861_i2c_xfer, + .functionality = gl861_i2c_func, +}; + +static struct usb_device_id friio_table[] = { + { USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, friio_table); + + +static struct dvb_usb_device_properties friio_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = 0, + + .num_adapters = 1, + .adapter = { + /* caps:0 => no pid filter, 188B TS packet */ + /* GL861 has a HW pid filter, but no info available. */ + { + .caps = 0, + + .frontend_attach = friio_frontend_attach, + .streaming_ctrl = friio_streaming_ctrl, + + .stream = { + .type = USB_BULK, + /* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */ + .count = 8, + .endpoint = 0x01, + .u = { + /* GL861 has 6KB buf inside */ + .bulk = { + .buffersize = 16384, + } + } + }, + } + }, + .i2c_algo = &gl861_i2c_algo, + + .num_device_descs = 1, + .devices = { + { + .name = "774 Friio ISDB-T USB2.0", + .cold_ids = { NULL }, + .warm_ids = { &friio_table[0], NULL }, + }, + } +}; + +static struct usb_driver friio_driver = { + .name = "dvb_usb_friio", + .probe = friio_probe, + .disconnect = dvb_usb_device_exit, + .id_table = friio_table, +}; + + +/* module stuff */ +static int __init friio_module_init(void) +{ + int ret; + + ret = usb_register(&friio_driver); + if (ret) + err("usb_register failed. Error number %d", ret); + + return ret; +} + + +static void __exit friio_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&friio_driver); +} + +module_init(friio_module_init); +module_exit(friio_module_exit); + +MODULE_AUTHOR("Akihiro Tsukada "); +MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio-fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio-fe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,474 @@ +/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. + * + * Copyright (C) 2009 Akihiro Tsukada + * + * This module is based off the the gl861 and vp702x modules. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include +#include +#include + +#include "friio.h" + +struct jdvbt90502_state { + struct i2c_adapter *i2c; + struct dvb_frontend frontend; + struct jdvbt90502_config config; +}; + +/* NOTE: TC90502 has 16bit register-address? */ +/* register 0x0100 is used for reading PLL status, so reg is u16 here */ +static int jdvbt90502_reg_read(struct jdvbt90502_state *state, + const u16 reg, u8 *buf, const size_t count) +{ + int ret; + u8 wbuf[3]; + struct i2c_msg msg[2]; + + wbuf[0] = reg & 0xFF; + wbuf[1] = 0; + wbuf[2] = reg >> 8; + + msg[0].addr = state->config.demod_address; + msg[0].flags = 0; + msg[0].buf = wbuf; + msg[0].len = sizeof(wbuf); + + msg[1].addr = msg[0].addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + deb_fe(" reg read failed.\n"); + return -EREMOTEIO; + } + return 0; +} + +/* currently 16bit register-address is not used, so reg is u8 here */ +static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state, + const u8 reg, const u8 val) +{ + struct i2c_msg msg; + u8 wbuf[2]; + + wbuf[0] = reg; + wbuf[1] = val; + + msg.addr = state->config.demod_address; + msg.flags = 0; + msg.buf = wbuf; + msg.len = sizeof(wbuf); + + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + deb_fe(" reg write failed."); + return -EREMOTEIO; + } + return 0; +} + +static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len) +{ + struct jdvbt90502_state *state = fe->demodulator_priv; + int err, i; + for (i = 0; i < len - 1; i++) { + err = jdvbt90502_single_reg_write(state, + buf[0] + i, buf[i + 1]); + if (err) + return err; + } + + return 0; +} + +/* read pll status byte via the demodulator's I2C register */ +/* note: Win box reads it by 8B block at the I2C addr 0x30 from reg:0x80 */ +static int jdvbt90502_pll_read(struct jdvbt90502_state *state, u8 *result) +{ + int ret; + + /* +1 for reading */ + u8 pll_addr_byte = (state->config.pll_address << 1) + 1; + + *result = 0; + + ret = jdvbt90502_single_reg_write(state, JDVBT90502_2ND_I2C_REG, + pll_addr_byte); + if (ret) + goto error; + + ret = jdvbt90502_reg_read(state, 0x0100, result, 1); + if (ret) + goto error; + + deb_fe("PLL read val:%02x\n", *result); + return 0; + +error: + deb_fe("%s:ret == %d\n", __func__, ret); + return -EREMOTEIO; +} + + +/* set pll frequency via the demodulator's I2C register */ +static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq) +{ + int ret; + int retry; + u8 res1; + u8 res2[9]; + + u8 pll_freq_cmd[PLL_CMD_LEN]; + u8 pll_agc_cmd[PLL_CMD_LEN]; + struct i2c_msg msg[2]; + u32 f; + + deb_fe("%s: freq=%d, step=%d\n", __func__, freq, + state->frontend.ops.info.frequency_stepsize); + /* freq -> oscilator frequency conversion. */ + /* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */ + f = freq / state->frontend.ops.info.frequency_stepsize; + /* add 399[1/7 MHZ] = 57MHz for the IF */ + f += 399; + /* add center frequency shift if necessary */ + if (f % 7 == 0) + f++; + pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */ + pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1; + pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F; + pll_freq_cmd[DIVIDER_BYTE2] = f & 0xFF; + pll_freq_cmd[CONTROL_BYTE] = 0xB2; /* ref.divider:28, 4MHz/28=1/7MHz */ + pll_freq_cmd[BANDSWITCH_BYTE] = 0x08; /* UHF band */ + + msg[0].addr = state->config.demod_address; + msg[0].flags = 0; + msg[0].buf = pll_freq_cmd; + msg[0].len = sizeof(pll_freq_cmd); + + ret = i2c_transfer(state->i2c, &msg[0], 1); + if (ret != 1) + goto error; + + udelay(50); + + pll_agc_cmd[DEMOD_REDIRECT_REG] = pll_freq_cmd[DEMOD_REDIRECT_REG]; + pll_agc_cmd[ADDRESS_BYTE] = pll_freq_cmd[ADDRESS_BYTE]; + pll_agc_cmd[DIVIDER_BYTE1] = pll_freq_cmd[DIVIDER_BYTE1]; + pll_agc_cmd[DIVIDER_BYTE2] = pll_freq_cmd[DIVIDER_BYTE2]; + pll_agc_cmd[CONTROL_BYTE] = 0x9A; /* AGC_CTRL instead of BANDSWITCH */ + pll_agc_cmd[AGC_CTRL_BYTE] = 0x50; + /* AGC Time Constant 2s, AGC take-over point:103dBuV(lowest) */ + + msg[1].addr = msg[0].addr; + msg[1].flags = 0; + msg[1].buf = pll_agc_cmd; + msg[1].len = sizeof(pll_agc_cmd); + + ret = i2c_transfer(state->i2c, &msg[1], 1); + if (ret != 1) + goto error; + + /* I don't know what these cmds are for, */ + /* but the USB log on a windows box contains them */ + ret = jdvbt90502_single_reg_write(state, 0x01, 0x40); + ret |= jdvbt90502_single_reg_write(state, 0x01, 0x00); + if (ret) + goto error; + udelay(100); + + /* wait for the demod to be ready? */ +#define RETRY_COUNT 5 + for (retry = 0; retry < RETRY_COUNT; retry++) { + ret = jdvbt90502_reg_read(state, 0x0096, &res1, 1); + if (ret) + goto error; + /* if (res1 != 0x00) goto error; */ + ret = jdvbt90502_reg_read(state, 0x00B0, res2, sizeof(res2)); + if (ret) + goto error; + if (res2[0] >= 0xA7) + break; + msleep(100); + } + if (retry >= RETRY_COUNT) { + deb_fe("%s: FE does not get ready after freq setting.\n", + __func__); + return -EREMOTEIO; + } + + return 0; +error: + deb_fe("%s:ret == %d\n", __func__, ret); + return -EREMOTEIO; +} + +static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state) +{ + u8 result; + int ret; + + *state = FE_HAS_SIGNAL; + + ret = jdvbt90502_pll_read(fe->demodulator_priv, &result); + if (ret) { + deb_fe("%s:ret == %d\n", __func__, ret); + return -EREMOTEIO; + } + + *state = FE_HAS_SIGNAL + | FE_HAS_CARRIER + | FE_HAS_VITERBI + | FE_HAS_SYNC; + + if (result & PLL_STATUS_LOCKED) + *state |= FE_HAS_LOCK; + + return 0; +} + +static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + int ret; + u8 rbuf[37]; + + *strength = 0; + + /* status register (incl. signal strength) : 0x89 */ + /* TODO: read just the necessary registers [0x8B..0x8D]? */ + ret = jdvbt90502_reg_read(fe->demodulator_priv, 0x0089, + rbuf, sizeof(rbuf)); + + if (ret) { + deb_fe("%s:ret == %d\n", __func__, ret); + return -EREMOTEIO; + } + + /* signal_strength: rbuf[2-4] (24bit BE), use lower 16bit for now. */ + *strength = (rbuf[3] << 8) + rbuf[4]; + if (rbuf[2]) + *strength = 0xffff; + + return 0; +} + + +/* filter out un-supported properties to notify users */ +static int jdvbt90502_set_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + int r = 0; + + switch (tvp->cmd) { + case DTV_DELIVERY_SYSTEM: + if (tvp->u.data != SYS_ISDBT) + r = -EINVAL; + break; + case DTV_CLEAR: + case DTV_TUNE: + case DTV_FREQUENCY: + break; + default: + r = -EINVAL; + } + return r; +} + +static int jdvbt90502_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + p->inversion = INVERSION_AUTO; + p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + p->u.ofdm.code_rate_HP = FEC_AUTO; + p->u.ofdm.code_rate_LP = FEC_AUTO; + p->u.ofdm.constellation = QAM_64; + p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; + return 0; +} + +static int jdvbt90502_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + /** + * NOTE: ignore all the parameters except frequency. + * others should be fixed to the proper value for ISDB-T, + * but don't check here. + */ + + struct jdvbt90502_state *state = fe->demodulator_priv; + int ret; + + deb_fe("%s: Freq:%d\n", __func__, p->frequency); + + /* for recovery from DTV_CLEAN */ + fe->dtv_property_cache.delivery_system = SYS_ISDBT; + + ret = jdvbt90502_pll_set_freq(state, p->frequency); + if (ret) { + deb_fe("%s:ret == %d\n", __func__, ret); + return -EREMOTEIO; + } + + return 0; +} + + +/** + * (reg, val) commad list to initialize this module. + * captured on a Windows box. + */ +static u8 init_code[][2] = { + {0x01, 0x40}, + {0x04, 0x38}, + {0x05, 0x40}, + {0x07, 0x40}, + {0x0F, 0x4F}, + {0x11, 0x21}, + {0x12, 0x0B}, + {0x13, 0x2F}, + {0x14, 0x31}, + {0x16, 0x02}, + {0x21, 0xC4}, + {0x22, 0x20}, + {0x2C, 0x79}, + {0x2D, 0x34}, + {0x2F, 0x00}, + {0x30, 0x28}, + {0x31, 0x31}, + {0x32, 0xDF}, + {0x38, 0x01}, + {0x39, 0x78}, + {0x3B, 0x33}, + {0x3C, 0x33}, + {0x48, 0x90}, + {0x51, 0x68}, + {0x5E, 0x38}, + {0x71, 0x00}, + {0x72, 0x08}, + {0x77, 0x00}, + {0xC0, 0x21}, + {0xC1, 0x10}, + {0xE4, 0x1A}, + {0xEA, 0x1F}, + {0x77, 0x00}, + {0x71, 0x00}, + {0x71, 0x00}, + {0x76, 0x0C}, +}; + +static const int init_code_len = sizeof(init_code) / sizeof(u8[2]); + +static int jdvbt90502_init(struct dvb_frontend *fe) +{ + int i = -1; + int ret; + struct i2c_msg msg; + + struct jdvbt90502_state *state = fe->demodulator_priv; + + deb_fe("%s called.\n", __func__); + + msg.addr = state->config.demod_address; + msg.flags = 0; + msg.len = 2; + for (i = 0; i < init_code_len; i++) { + msg.buf = init_code[i]; + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) + goto error; + } + fe->dtv_property_cache.delivery_system = SYS_ISDBT; + msleep(100); + + return 0; + +error: + deb_fe("%s: init_code[%d] failed. ret==%d\n", __func__, i, ret); + return -EREMOTEIO; +} + + +static void jdvbt90502_release(struct dvb_frontend *fe) +{ + struct jdvbt90502_state *state = fe->demodulator_priv; + kfree(state); +} + + +static struct dvb_frontend_ops jdvbt90502_ops; + +struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d) +{ + struct jdvbt90502_state *state = NULL; + + deb_info("%s called.\n", __func__); + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct jdvbt90502_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->i2c = &d->i2c_adap; + memcpy(&state->config, &friio_fe_config, sizeof(friio_fe_config)); + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &jdvbt90502_ops, + sizeof(jdvbt90502_ops)); + state->frontend.demodulator_priv = state; + + if (jdvbt90502_init(&state->frontend) < 0) + goto error; + + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops jdvbt90502_ops = { + + .info = { + .name = "Comtech JDVBT90502 ISDB-T", + .type = FE_OFDM, + .frequency_min = 473000000, /* UHF 13ch, center */ + .frequency_max = 767142857, /* UHF 62ch, center */ + .frequency_stepsize = JDVBT90502_PLL_CLK / + JDVBT90502_PLL_DIVIDER, + .frequency_tolerance = 0, + + /* NOTE: this driver ignores all parameters but frequency. */ + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = jdvbt90502_release, + + .init = jdvbt90502_init, + .write = _jdvbt90502_write, + + .set_property = jdvbt90502_set_property, + + .set_frontend = jdvbt90502_set_frontend, + .get_frontend = jdvbt90502_get_frontend, + + .read_status = jdvbt90502_read_status, + .read_signal_strength = jdvbt90502_read_signal_strength, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/friio.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,99 @@ +/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver. + * + * Copyright (C) 2009 Akihiro Tsukada + * + * This module is based off the the gl861 and vp702x modules. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_FRIIO_H_ +#define _DVB_USB_FRIIO_H_ + +/** + * Friio Components + * USB hub: AU4254 + * USB controller(+ TS dmx & streaming): GL861 + * Frontend: comtech JDVBT-90502 + * (tuner PLL: tua6034, I2C addr:(0xC0 >> 1)) + * (OFDM demodulator: TC90502, I2C addr:(0x30 >> 1)) + * LED x3 (+LNB) control: PIC 16F676 + * EEPROM: 24C08 + * + * (USB smart card reader: AU9522) + * + */ + +#define DVB_USB_LOG_PREFIX "friio" +#include "dvb-usb.h" + +extern int dvb_usb_friio_debug; +#define deb_info(args...) dprintk(dvb_usb_friio_debug, 0x01, args) +#define deb_xfer(args...) dprintk(dvb_usb_friio_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_friio_debug, 0x04, args) +#define deb_fe(args...) dprintk(dvb_usb_friio_debug, 0x08, args) + +/* Vendor requests */ +#define GL861_WRITE 0x40 +#define GL861_READ 0xc0 + +/* command bytes */ +#define GL861_REQ_I2C_WRITE 0x01 +#define GL861_REQ_I2C_READ 0x02 +/* For control msg with data argument */ +/* Used for accessing the PLL on the secondary I2C bus of FE via GL861 */ +#define GL861_REQ_I2C_DATA_CTRL_WRITE 0x03 + +#define GL861_ALTSETTING_COUNT 2 +#define FRIIO_BULK_ALTSETTING 0 +#define FRIIO_ISOC_ALTSETTING 1 + +/* LED & LNB control via PIC. */ +/* basically, it's serial control with clock and strobe. */ +/* write the below 4bit control data to the reg 0x00 at the I2C addr 0x00 */ +/* when controlling the LEDs, 32bit(saturation, R, G, B) is sent on the bit3*/ +#define FRIIO_CTL_LNB (1 << 0) +#define FRIIO_CTL_STROBE (1 << 1) +#define FRIIO_CTL_CLK (1 << 2) +#define FRIIO_CTL_LED (1 << 3) + +/* Front End related */ + +#define FRIIO_DEMOD_ADDR (0x30 >> 1) +#define FRIIO_PLL_ADDR (0xC0 >> 1) + +#define JDVBT90502_PLL_CLK 4000000 +#define JDVBT90502_PLL_DIVIDER 28 + +#define JDVBT90502_2ND_I2C_REG 0xFE + +/* byte index for pll i2c command data structure*/ +/* see datasheet for tua6034 */ +#define DEMOD_REDIRECT_REG 0 +#define ADDRESS_BYTE 1 +#define DIVIDER_BYTE1 2 +#define DIVIDER_BYTE2 3 +#define CONTROL_BYTE 4 +#define BANDSWITCH_BYTE 5 +#define AGC_CTRL_BYTE 5 +#define PLL_CMD_LEN 6 + +/* bit masks for PLL STATUS response */ +#define PLL_STATUS_POR_MODE 0x80 /* 1: Power on Reset (test) Mode */ +#define PLL_STATUS_LOCKED 0x40 /* 1: locked */ +#define PLL_STATUS_AGC_ACTIVE 0x08 /* 1:active */ +#define PLL_STATUS_TESTMODE 0x07 /* digital output level (5 level) */ + /* 0.15Vcc step 0x00: < 0.15Vcc, ..., 0x04: >= 0.6Vcc (<= 1Vcc) */ + + +struct jdvbt90502_config { + u8 demod_address; /* i2c addr for demodulator IC */ + u8 pll_address; /* PLL addr on the secondary i2c*/ +}; +extern struct jdvbt90502_config friio_fe_config; + +extern struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d); +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gl861.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gl861.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gl861.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gl861.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,232 @@ +/* DVB USB compliant linux driver for GL861 USB2.0 devices. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "gl861.h" + +#include "zl10353.h" +#include "qt1010.h" + +/* debug */ +static int dvb_usb_gl861_debug; +module_param_named(debug, dvb_usb_gl861_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." + DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u16 index; + u16 value = addr << (8 + 1); + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + u8 req, type; + + if (wo) { + req = GL861_REQ_I2C_WRITE; + type = GL861_WRITE; + } else { /* rw */ + req = GL861_REQ_I2C_READ; + type = GL861_READ; + } + + switch (wlen) { + case 1: + index = wbuf[0]; + break; + case 2: + index = wbuf[0]; + value = value + wbuf[1]; + break; + default: + warn("wlen = %x, aborting.", wlen); + return -EINVAL; + } + + msleep(1); /* avoid I2C errors */ + + return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type, + value, index, rbuf, rlen, 2000); +} + +/* I2C */ +static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, msg[i+1].buf, msg[i+1].len) < 0) + break; + i++; + } else + if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, NULL, 0) < 0) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 gl861_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm gl861_i2c_algo = { + .master_xfer = gl861_i2c_xfer, + .functionality = gl861_i2c_func, +}; + +/* Callbacks for DVB USB */ +static struct zl10353_config gl861_zl10353_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static int gl861_frontend_attach(struct dvb_usb_adapter *adap) +{ + + adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe == NULL) + return -EIO; + + return 0; +} + +static struct qt1010_config gl861_qt1010_config = { + .i2c_address = 0x62 +}; + +static int gl861_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(qt1010_attach, + adap->fe, &adap->dev->i2c_adap, + &gl861_qt1010_config) == NULL ? -ENODEV : 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties gl861_properties; + +static int gl861_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + struct usb_host_interface *alt; + int ret; + + if (intf->num_altsetting < 2) + return -ENODEV; + + ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d, + adapter_nr); + if (ret == 0) { + alt = usb_altnum_to_altsetting(intf, 0); + + if (alt == NULL) { + deb_rc("not alt found!\n"); + return -ENODEV; + } + + ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + } + + return ret; +} + +static struct usb_device_id gl861_table [] = { + { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) }, + { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, gl861_table); + +static struct dvb_usb_device_properties gl861_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = 0, + + .num_adapters = 1, + .adapter = {{ + + .frontend_attach = gl861_frontend_attach, + .tuner_attach = gl861_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + } }, + .i2c_algo = &gl861_i2c_algo, + + .num_device_descs = 2, + .devices = { + { + .name = "MSI Mega Sky 55801 DVB-T USB2.0", + .cold_ids = { NULL }, + .warm_ids = { &gl861_table[0], NULL }, + }, + { + .name = "A-LINK DTU DVB-T USB2.0", + .cold_ids = { NULL }, + .warm_ids = { &gl861_table[1], NULL }, + }, + } +}; + +static struct usb_driver gl861_driver = { + .name = "dvb_usb_gl861", + .probe = gl861_probe, + .disconnect = dvb_usb_device_exit, + .id_table = gl861_table, +}; + +/* module stuff */ +static int __init gl861_module_init(void) +{ + int ret; + + ret = usb_register(&gl861_driver); + if (ret) + err("usb_register failed. Error number %d", ret); + + return ret; +} + +static void __exit gl861_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&gl861_driver); +} + +module_init(gl861_module_init); +module_exit(gl861_module_exit); + +MODULE_AUTHOR("Carl Lundqvist "); +MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gl861.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gl861.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gl861.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gl861.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,15 @@ +#ifndef _DVB_USB_GL861_H_ +#define _DVB_USB_GL861_H_ + +#define DVB_USB_LOG_PREFIX "gl861" +#include "dvb-usb.h" + +#define deb_rc(args...) dprintk(dvb_usb_gl861_debug, 0x01, args) + +#define GL861_WRITE 0x40 +#define GL861_READ 0xc0 + +#define GL861_REQ_I2C_WRITE 0x01 +#define GL861_REQ_I2C_READ 0x02 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,343 @@ +/* DVB USB compliant Linux driver for the + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module + * + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) + * + * Thanks to GENPIX for the sample code used to implement this module. + * + * This module is based off the vp7045 and vp702x modules + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "gp8psk.h" + +/* debug */ +static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; +int dvb_usb_gp8psk_debug; +module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers) +{ + return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6)); +} + +static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers) +{ + return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1)); +} + +static void gp8psk_info(struct dvb_usb_device *d) +{ + u8 fpga_vers, fw_vers[6]; + + if (!gp8psk_get_fw_version(d, fw_vers)) + info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i", + fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers), + 2000 + fw_vers[5], fw_vers[4], fw_vers[3]); + else + info("failed to get FW version"); + + if (!gp8psk_get_fpga_version(d, &fpga_vers)) + info("FPGA Version = %i", fpga_vers); + else + info("failed to get FPGA version"); +} + +int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +{ + int ret = 0,try = 0; + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + while (ret >= 0 && ret != blen && try < 3) { + ret = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value,index,b,blen, + 2000); + deb_info("reading number %d (ret: %d)\n",try,ret); + try++; + } + + if (ret < 0 || ret != blen) { + warn("usb in %d operation failed.", req); + ret = -EIO; + } else + ret = 0; + + deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + mutex_unlock(&d->usb_mutex); + + return ret; +} + +int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + + deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + if (usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value,index,b,blen, + 2000) != blen) { + warn("usb out operation failed."); + ret = -EIO; + } else + ret = 0; + mutex_unlock(&d->usb_mutex); + + return ret; +} + +static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) +{ + int ret; + const struct firmware *fw = NULL; + const u8 *ptr; + u8 *buf; + if ((ret = request_firmware(&fw, bcm4500_firmware, + &d->udev->dev)) != 0) { + err("did not find the bcm4500 firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + bcm4500_firmware,ret); + return ret; + } + + ret = -EINVAL; + + if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) + goto out_rel_fw; + + info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); + + ptr = fw->data; + buf = kmalloc(64, GFP_KERNEL | GFP_DMA); + if (!buf) { + ret = -ENOMEM; + goto out_rel_fw; + } + + while (ptr[0] != 0xff) { + u16 buflen = ptr[0] + 4; + if (ptr + buflen >= fw->data + fw->size) { + err("failed to load bcm4500 firmware."); + goto out_free; + } + memcpy(buf, ptr, buflen); + if (dvb_usb_generic_write(d, buf, buflen)) { + err("failed to load bcm4500 firmware."); + goto out_free; + } + ptr += buflen; + } + + ret = 0; + +out_free: + kfree(buf); +out_rel_fw: + release_firmware(fw); + + return ret; +} + +static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 status, buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + + if (onoff) { + gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); + if (! (status & bm8pskStarted)) { /* started */ + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0); + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + gp8psk_info(d); + } + + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */ + if(gp8psk_load_bcm4500fw(d)) + return -EINVAL; + + if (! (status & bmIntersilOn)) /* LNB Power */ + if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, + &buf, 1)) + return -EINVAL; + + /* Set DVB mode to 1 */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) + return -EINVAL; + /* Abort possible TS (if previous tune crashed) */ + if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0)) + return -EINVAL; + } else { + /* Turn off LNB power */ + if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) + return -EINVAL; + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0); + } + return 0; +} + +int gp8psk_bcm4500_reload(struct dvb_usb_device *d) +{ + u8 buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + /* Turn On 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + /* load BCM4500 firmware */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_load_bcm4500fw(d)) + return -EINVAL; + return 0; +} + +static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0); +} + +static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe = gp8psk_fe_attach(adap->dev); + return 0; +} + +static struct dvb_usb_device_properties gp8psk_properties; + +static int gp8psk_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + struct usb_device *udev = interface_to_usbdev(intf); + ret = dvb_usb_device_init(intf, &gp8psk_properties, + THIS_MODULE, NULL, adapter_nr); + if (ret == 0) { + info("found Genpix USB device pID = %x (hex)", + le16_to_cpu(udev->descriptor.idProduct)); + } + return ret; +} + +static struct usb_device_id gp8psk_usb_table [] = { + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) }, +/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */ + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); + +static struct dvb_usb_device_properties gp8psk_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-gp8psk-01.fw", + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = gp8psk_streaming_ctrl, + .frontend_attach = gp8psk_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + } + }, + .power_ctrl = gp8psk_power_ctrl, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 4, + .devices = { + { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", + .cold_ids = { &gp8psk_usb_table[0], NULL }, + .warm_ids = { &gp8psk_usb_table[1], NULL }, + }, + { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[2], NULL }, + }, + { .name = "Genpix SkyWalker-1 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[3], NULL }, + }, + { .name = "Genpix SkyWalker-2 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[4], NULL }, + }, + { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver gp8psk_usb_driver = { + .name = "dvb_usb_gp8psk", + .probe = gp8psk_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = gp8psk_usb_table, +}; + +/* module stuff */ +static int __init gp8psk_usb_module_init(void) +{ + int result; + if ((result = usb_register(&gp8psk_usb_driver))) { + err("usb_register failed. (%d)",result); + return result; + } + + return 0; +} + +static void __exit gp8psk_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&gp8psk_usb_driver); +} + +module_init(gp8psk_usb_module_init); +module_exit(gp8psk_usb_module_exit); + +MODULE_AUTHOR("Alan Nisota "); +MODULE_DESCRIPTION("Driver for Genpix DVB-S"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk-fe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,378 @@ +/* DVB USB compliant Linux driver for the + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module + * + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) + * + * Thanks to GENPIX for the sample code used to implement this module. + * + * This module is based off the vp7045 and vp702x modules + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "gp8psk.h" + +struct gp8psk_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; + u8 lock; + u16 snr; + unsigned long next_status_check; + unsigned long status_check_interval; +}; + +static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + u8 status; + gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1); + return status & bmDCtuned; +} + +static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode) +{ + struct gp8psk_fe_state *state = fe->demodulator_priv; + return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0); +} + +static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) +{ + u8 buf[6]; + if (time_after(jiffies,st->next_status_check)) { + gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); + gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); + st->snr = (buf[1]) << 8 | buf[0]; + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + +static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + + if (st->lock) + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; + else + *status = 0; + + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 100; + return 0; +} + +/* not supported by this Frontend */ +static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + (void) fe; + *ber = 0; + return 0; +} + +/* not supported by this Frontend */ +static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + (void) fe; + *unc = 0; + return 0; +} + +static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + *snr = st->snr; + return 0; +} + +static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + /* snr / 38.4 ~= 100% strength */ + /* snr * 17 returns 100% strength as 65535 */ + if (st->snr > 0xf00) + *strength = 0xffff; + else + *strength = (st->snr << 4) + st->snr; /* snr*17 */ + return 0; +} + +static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int gp8psk_fe_set_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + deb_fe("%s(..)\n", __func__); + return 0; +} + +static int gp8psk_fe_get_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + deb_fe("%s(..)\n", __func__); + return 0; +} + + +static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct gp8psk_fe_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 cmd[10]; + u32 freq = fep->frequency * 1000; + int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct); + + deb_fe("%s()\n", __func__); + + cmd[4] = freq & 0xff; + cmd[5] = (freq >> 8) & 0xff; + cmd[6] = (freq >> 16) & 0xff; + cmd[7] = (freq >> 24) & 0xff; + + switch (c->delivery_system) { + case SYS_DVBS: + /* Allow QPSK and 8PSK (even for DVB-S) */ + if (c->modulation != QPSK && c->modulation != PSK_8) { + deb_fe("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + c->fec_inner = FEC_AUTO; + break; + case SYS_DVBS2: + deb_fe("%s: DVB-S2 delivery system selected\n", __func__); + break; + + default: + deb_fe("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; + } + + cmd[0] = c->symbol_rate & 0xff; + cmd[1] = (c->symbol_rate >> 8) & 0xff; + cmd[2] = (c->symbol_rate >> 16) & 0xff; + cmd[3] = (c->symbol_rate >> 24) & 0xff; + switch (c->modulation) { + case QPSK: + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_tuned_to_DCII(fe)) + gp8psk_bcm4500_reload(state->d); + switch (c->fec_inner) { + case FEC_1_2: + cmd[9] = 0; break; + case FEC_2_3: + cmd[9] = 1; break; + case FEC_3_4: + cmd[9] = 2; break; + case FEC_5_6: + cmd[9] = 3; break; + case FEC_7_8: + cmd[9] = 4; break; + case FEC_AUTO: + cmd[9] = 5; break; + default: + cmd[9] = 5; break; + } + cmd[8] = ADV_MOD_DVB_QPSK; + break; + case PSK_8: /* PSK_8 is for compatibility with DN */ + cmd[8] = ADV_MOD_TURBO_8PSK; + switch (c->fec_inner) { + case FEC_2_3: + cmd[9] = 0; break; + case FEC_3_4: + cmd[9] = 1; break; + case FEC_3_5: + cmd[9] = 2; break; + case FEC_5_6: + cmd[9] = 3; break; + case FEC_8_9: + cmd[9] = 4; break; + default: + cmd[9] = 0; break; + } + break; + case QAM_16: /* QAM_16 is for compatibility with DN */ + cmd[8] = ADV_MOD_TURBO_16QAM; + cmd[9] = 0; + break; + default: /* Unknown modulation */ + deb_fe("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + gp8psk_set_tuner_mode(fe, 0); + gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10); + + state->lock = 0; + state->next_status_check = jiffies; + state->status_check_interval = 200; + + return 0; +} + +static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + + deb_fe("%s\n",__func__); + + if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0, + m->msg, m->msg_len)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe, + fe_sec_mini_cmd_t burst) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + u8 cmd; + + deb_fe("%s\n",__func__); + + /* These commands are certainly wrong */ + cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01; + + if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0, + &cmd, 0)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + + if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE, + (tone == SEC_TONE_ON), 0, NULL, 0)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + + if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, + voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); +} + +static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + u8 cmd = sw_cmd & 0x7f; + + if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0, + NULL, 0)) { + return -EINVAL; + } + if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), + 0, NULL, 0)) { + return -EINVAL; + } + + return 0; +} + +static void gp8psk_fe_release(struct dvb_frontend* fe) +{ + struct gp8psk_fe_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops gp8psk_fe_ops; + +struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d) +{ + struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL); + if (s == NULL) + goto error; + + s->d = d; + memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + + goto success; +error: + return NULL; +success: + return &s->fe; +} + + +static struct dvb_frontend_ops gp8psk_fe_ops = { + .info = { + .name = "Genpix DVB-S", + .type = FE_QPSK, + .frequency_min = 800000, + .frequency_max = 2250000, + .frequency_stepsize = 100, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + /* + * FE_CAN_QAM_16 is for compatibility + * (Myth incorrectly detects Turbo-QPSK as plain QAM-16) + */ + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC + }, + + .release = gp8psk_fe_release, + + .init = NULL, + .sleep = NULL, + + .set_property = gp8psk_fe_set_property, + .get_property = gp8psk_fe_get_property, + .set_frontend = gp8psk_fe_set_frontend, + + .get_tune_settings = gp8psk_fe_get_tune_settings, + + .read_status = gp8psk_fe_read_status, + .read_ber = gp8psk_fe_read_ber, + .read_signal_strength = gp8psk_fe_read_signal_strength, + .read_snr = gp8psk_fe_read_snr, + .read_ucblocks = gp8psk_fe_read_unc_blocks, + + .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg, + .diseqc_send_burst = gp8psk_fe_send_diseqc_burst, + .set_tone = gp8psk_fe_set_tone, + .set_voltage = gp8psk_fe_set_voltage, + .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, + .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/gp8psk.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,100 @@ +/* DVB USB compliant Linux driver for the + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module + * + * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * + * Thanks to GENPIX for the sample code used to implement this module. + * + * This module is based off the vp7045 and vp702x modules + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_GP8PSK_H_ +#define _DVB_USB_GP8PSK_H_ + +#define DVB_USB_LOG_PREFIX "gp8psk" +#include "dvb-usb.h" + +extern int dvb_usb_gp8psk_debug; +#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args) +#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args) + +/* Twinhan Vendor requests */ +#define TH_COMMAND_IN 0xC0 +#define TH_COMMAND_OUT 0xC1 + +/* gp8psk commands */ + +#define GET_8PSK_CONFIG 0x80 /* in */ +#define SET_8PSK_CONFIG 0x81 +#define I2C_WRITE 0x83 +#define I2C_READ 0x84 +#define ARM_TRANSFER 0x85 +#define TUNE_8PSK 0x86 +#define GET_SIGNAL_STRENGTH 0x87 /* in */ +#define LOAD_BCM4500 0x88 +#define BOOT_8PSK 0x89 /* in */ +#define START_INTERSIL 0x8A /* in */ +#define SET_LNB_VOLTAGE 0x8B +#define SET_22KHZ_TONE 0x8C +#define SEND_DISEQC_COMMAND 0x8D +#define SET_DVB_MODE 0x8E +#define SET_DN_SWITCH 0x8F +#define GET_SIGNAL_LOCK 0x90 /* in */ +#define GET_FW_VERS 0x92 +#define GET_SERIAL_NUMBER 0x93 /* in */ +#define USE_EXTRA_VOLT 0x94 +#define GET_FPGA_VERS 0x95 +#define CW3K_INIT 0x9d + +/* PSK_configuration bits */ +#define bm8pskStarted 0x01 +#define bm8pskFW_Loaded 0x02 +#define bmIntersilOn 0x04 +#define bmDVBmode 0x08 +#define bm22kHz 0x10 +#define bmSEL18V 0x20 +#define bmDCtuned 0x40 +#define bmArmed 0x80 + +/* Satellite modulation modes */ +#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ +#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */ +#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */ +#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */ + +#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */ +#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */ +#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */ +#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */ +#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */ +#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */ + +#define GET_USB_SPEED 0x07 + +#define RESET_FX2 0x13 + +#define FW_VERSION_READ 0x0B +#define VENDOR_STRING_READ 0x0C +#define PRODUCT_STRING_READ 0x0D +#define FW_BCD_VERSION_READ 0x14 + +/* firmware revision id's */ +#define GP8PSK_FW_REV1 0x020604 +#define GP8PSK_FW_REV2 0x020704 +#define GP8PSK_FW_VERS(_fw_vers) ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0]) + +extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); +extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen); +extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,376 @@ +config DVB_USB + tristate "Support for various USB DVB devices" + depends on DVB_CORE && USB && I2C && RC_CORE + help + By enabling this you will be able to choose the various supported + USB1.1 and USB2.0 DVB devices. + + Almost every USB device needs a firmware, please look into + . + + For a complete list of supported USB devices see the LinuxTV DVB Wiki: + + + Say Y if you own a USB DVB device. + +config DVB_USB_DEBUG + bool "Enable extended debug support for all DVB-USB devices" + depends on DVB_USB + help + Say Y if you want to enable debugging. See modinfo dvb-usb (and the + appropriate drivers) for debug levels. + +config DVB_USB_A800 + tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" + depends on DVB_USB + select DVB_DIB3000MC + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. + +config DVB_USB_DIBUSB_MB + tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_DIB3000MB + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + help + Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by + DiBcom () equipped with a DiB3000M-B demodulator. + + For an up-to-date list of devices supported by this driver, have a look + on the Linux-DVB Wiki at www.linuxtv.org. + + Say Y if you own such a device and want to use it. You should build it as + a module. + +config DVB_USB_DIBUSB_MB_FAULTY + bool "Support faulty USB IDs" + depends on DVB_USB_DIBUSB_MB + help + Support for faulty USB IDs due to an invalid EEPROM on some Artec devices. + +config DVB_USB_DIBUSB_MC + tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" + depends on DVB_USB + select DVB_DIB3000MC + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + help + Support for USB2.0 DVB-T receivers based on reference designs made by + DiBcom () equipped with a DiB3000M-C/P demodulator. + + For an up-to-date list of devices supported by this driver, have a look + on the Linux-DVB Wiki at www.linuxtv.org. + + Say Y if you own such a device and want to use it. You should build it as + a module. + +config DVB_USB_DIB0700 + tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)" + depends on DVB_USB + select DVB_DIB7000P if !DVB_FE_CUSTOMISE + select DVB_DIB7000M if !DVB_FE_CUSTOMISE + select DVB_DIB8000 if !DVB_FE_CUSTOMISE + select DVB_DIB3000MC if !DVB_FE_CUSTOMISE + select DVB_S5H1411 if !DVB_FE_CUSTOMISE + select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + help + Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The + USB bridge is also present in devices having the DiB7700 DVB-T-USB + silicon. This chip can be found in devices offered by Hauppauge, + Avermedia and other big and small companies. + + For an up-to-date list of devices supported by this driver, have a look + on the LinuxTV Wiki at www.linuxtv.org. + + Say Y if you own such a device and want to use it. You should build it as + a module. + +config DVB_USB_UMT_010 + tristate "HanfTek UMT-010 DVB-T USB2.0 support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_DIB3000MC + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + help + Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. + +config DVB_USB_CXUSB + tristate "Conexant USB2.0 hybrid reference design support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_CX22702 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_DIB7000P if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE + select DVB_ATBM8830 if !DVB_FE_CUSTOMISE + select DVB_LGS8GXX if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Conexant USB2.0 hybrid reference design. + Currently, only DVB and ATSC modes are supported, analog mode + shall be added in the future. Devices that require this module: + + Medion MD95700 hybrid USB2.0 device. + DViCO FusionHDTV (Bluebird) USB2.0 devices + +config DVB_USB_M920X + tristate "Uli m920x DVB-T USB2.0 support" + depends on DVB_USB + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. + Currently, only devices with a product id of + "DTV USB MINI" (in cold state) are supported. + Firmware required. + +config DVB_USB_GL861 + tristate "Genesys Logic GL861 USB2.0 support" + depends on DVB_USB + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 + receiver with USB ID 0db0:5581. + +config DVB_USB_AU6610 + tristate "Alcor Micro AU6610 USB2.0 support" + depends on DVB_USB + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. + +config DVB_USB_DIGITV + tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_NXT6000 if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + help + Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. + +config DVB_USB_VP7045 + tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support" + depends on DVB_USB + help + Say Y here to support the + + TwinhanDTV Alpha (stick) (VP-7045), + TwinhanDTV MagicBox II (VP-7046), + DigitalNow TinyUSB 2 DVB-t, + DigitalRise USB 2.0 Ter (Beetle) and + TYPHOON DVB-T USB DRIVE + + DVB-T USB2.0 receivers. + +config DVB_USB_VP702X + tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support" + depends on DVB_USB + help + Say Y here to support the + + TwinhanDTV StarBox, + DigitalRise USB Starbox and + TYPHOON DVB-S USB 2.0 BOX + + DVB-S USB2.0 receivers. + +config DVB_USB_GP8PSK + tristate "GENPIX 8PSK->USB module support" + depends on DVB_USB + help + Say Y here to support the + GENPIX 8psk module + + DVB-S USB2.0 receivers. + +config DVB_USB_NOVA_T_USB2 + tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" + depends on DVB_USB + select DVB_DIB3000MC + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. + +config DVB_USB_TTUSB2 + tristate "Pinnacle 400e DVB-S USB2.0 support" + depends on DVB_USB + select DVB_TDA10086 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_TDA826X if !DVB_FE_CUSTOMISE + help + Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The + firmware protocol used by this module is similar to the one used by the + old ttusb-driver - that's why the module is called dvb-usb-ttusb2. + +config DVB_USB_DTT200U + tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" + depends on DVB_USB + help + Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. + + The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). + + The WT-220U and its clones are pen-sized. + +config DVB_USB_OPERA1 + tristate "Opera1 DVB-S USB2.0 receiver" + depends on DVB_USB + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE + help + Say Y here to support the Opera DVB-S USB2.0 receiver. + +config DVB_USB_AF9005 + tristate "Afatech AF9005 DVB-T USB1.1 support" + depends on DVB_USB && EXPERIMENTAL + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver + and the TerraTec Cinergy T USB XE (Rev.1) + +config DVB_USB_AF9005_REMOTE + tristate "Afatech AF9005 default remote control support" + depends on DVB_USB_AF9005 + help + Say Y here to support the default remote control decoding for the + Afatech AF9005 based receiver. + +config DVB_USB_DW2102 + tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_SI21XX if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_MT312 if !DVB_FE_CUSTOMISE + select DVB_ZL10039 if !DVB_FE_CUSTOMISE + select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE + help + Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0 + receivers. + +config DVB_USB_CINERGY_T2 + tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" + depends on DVB_USB + help + Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers + + Say Y if you own such a device and want to use it. + +config DVB_USB_ANYSEE + tristate "Anysee DVB-T/C USB2.0 support" + depends on DVB_USB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_ISL6423 if !DVB_FE_CUSTOMISE + help + Say Y here to support the Anysee E30, Anysee E30 Plus or + Anysee E30 C Plus DVB USB2.0 receiver. + +config DVB_USB_DTV5100 + tristate "AME DTV-5100 USB2.0 DVB-T support" + depends on DVB_USB + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. + +config DVB_USB_AF9015 + tristate "Afatech AF9015 DVB-T USB2.0 support" + depends on DVB_USB + select DVB_AF9013 + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver + +config DVB_USB_CE6230 + tristate "Intel CE6230 DVB-T USB2.0 support" + depends on DVB_USB && EXPERIMENTAL + select DVB_ZL10353 + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver + +config DVB_USB_FRIIO + tristate "Friio ISDB-T USB2.0 Receiver support" + depends on DVB_USB + help + Say Y here to support the Japanese DTV receiver Friio. + +config DVB_USB_EC168 + tristate "E3C EC168 DVB-T USB2.0 support" + depends on DVB_USB && EXPERIMENTAL + select DVB_EC100 + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. + +config DVB_USB_AZ6027 + tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" + depends on DVB_USB + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + help + Say Y here to support the AZ6027 device + +config DVB_USB_LME2510 + tristate "LME DM04/QQBOX DVB-S USB2.0 support" + depends on DVB_USB + select DVB_TDA10086 if !DVB_FE_CUSTOMISE + select DVB_TDA826X if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_IX2505V if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE + help + Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . + +config DVB_USB_TECHNISAT_USB2 + tristate "Technisat DVB-S/S2 USB2.0 support" + depends on DVB_USB + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE + help + Say Y here to support the Technisat USB2 DVB-S/S2 device diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/lmedm04.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/lmedm04.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/lmedm04.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/lmedm04.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1309 @@ +/* DVB USB compliant linux driver for + * + * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 + * LME2510C + LG TDQY-P001F + * LME2510C + BS2F7HZ0194 + * LME2510 + LG TDQY-P001F + * LME2510 + BS2F7HZ0194 + * + * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) + * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) + * + * MV001F (LME2510+LGTDQY-P001F) + * LG TDQY - P001F =(TDA8263 + TDA10086H) + * + * MVB0001F (LME2510C+LGTDQT-P001F) + * + * MV0194 (LME2510+SHARP:BS2F7HZ0194) + * SHARP:BS2F7HZ0194 = (STV0299+IX2410) + * + * MVB0194 (LME2510C+SHARP0194) + * + * For firmware see Documentation/dvb/lmedm04.txt + * + * I2C addresses: + * 0xd0 - STV0288 - Demodulator + * 0xc0 - Sharp IX2505V - Tuner + * -- + * 0x1c - TDA10086 - Demodulator + * 0xc0 - TDA8263 - Tuner + * -- + * 0xd0 - STV0299 - Demodulator + * 0xc0 - IX2410 - Tuner + * + * + * VID = 3344 PID LME2510=1122 LME2510C=1120 + * + * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com) + * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * see Documentation/dvb/README.dvb-usb for more information + * + * Known Issues : + * LME2510: Non Intel USB chipsets fail to maintain High Speed on + * Boot or Hot Plug. + * + * QQbox suffers from noise on LNB voltage. + * + * LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system + * with other tuners. After a cold reset streaming will not start. + * + */ +#define DVB_USB_LOG_PREFIX "LME2510(C)" +#include +#include +#include + +#include "dvb-usb.h" +#include "lmedm04.h" +#include "tda826x.h" +#include "tda10086.h" +#include "stv0288.h" +#include "ix2505v.h" +#include "stv0299.h" +#include "dvb-pll.h" +#include "z0194a.h" + + + +/* debug */ +static int dvb_usb_lme2510_debug; +#define l_dprintk(var, level, args...) do { \ + if ((var >= level)) \ + printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \ +} while (0) + +#define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args) +#define debug_data_snipet(level, name, p) \ + deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ + *p, *(p+1), *(p+2), *(p+3), *(p+4), \ + *(p+5), *(p+6), *(p+7)); + + +module_param_named(debug, dvb_usb_lme2510_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." + DVB_USB_DEBUG_STATUS); + +static int dvb_usb_lme2510_firmware; +module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644); +MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG"); + +static int pid_filter; +module_param_named(pid, pid_filter, int, 0644); +MODULE_PARM_DESC(pid, "set default 0=on 1=off"); + + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define TUNER_DEFAULT 0x0 +#define TUNER_LG 0x1 +#define TUNER_S7395 0x2 +#define TUNER_S0194 0x3 + +struct lme2510_state { + u8 id; + u8 tuner_config; + u8 signal_lock; + u8 signal_level; + u8 signal_sn; + u8 time_key; + u8 i2c_talk_onoff; + u8 i2c_gate; + u8 i2c_tuner_gate_w; + u8 i2c_tuner_gate_r; + u8 i2c_tuner_addr; + u8 stream_on; + u8 pid_size; + void *buffer; + struct urb *lme_urb; + void *usb_buffer; + +}; + +static int lme2510_bulk_write(struct usb_device *dev, + u8 *snd, int len, u8 pipe) +{ + int ret, actual_l; + + ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), + snd, len , &actual_l, 100); + return ret; +} + +static int lme2510_bulk_read(struct usb_device *dev, + u8 *rev, int len, u8 pipe) +{ + int ret, actual_l; + + ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), + rev, len , &actual_l, 200); + return ret; +} + +static int lme2510_usb_talk(struct dvb_usb_device *d, + u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + struct lme2510_state *st = d->priv; + u8 *buff; + int ret = 0; + + if (st->usb_buffer == NULL) { + st->usb_buffer = kmalloc(512, GFP_KERNEL); + if (st->usb_buffer == NULL) { + info("MEM Error no memory"); + return -ENOMEM; + } + } + buff = st->usb_buffer; + + ret = mutex_lock_interruptible(&d->usb_mutex); + + if (ret < 0) + return -EAGAIN; + + /* the read/write capped at 512 */ + memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen); + + ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01)); + + ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); + + msleep(10); + + ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01)); + + ret |= lme2510_bulk_read(d->udev, buff, (rlen > 512) ? + 512 : rlen , 0x01); + + if (rlen > 0) + memcpy(rbuf, buff, rlen); + + mutex_unlock(&d->usb_mutex); + + return (ret < 0) ? -ENODEV : 0; +} + +static int lme2510_stream_restart(struct dvb_usb_device *d) +{ + static u8 stream_on[] = LME_ST_ON_W; + int ret; + u8 rbuff[10]; + /*Restart Stream Command*/ + ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), + rbuff, sizeof(rbuff)); + return ret; +} + +static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out) +{ + struct lme2510_state *st = d->priv; + static u8 pid_buff[] = LME_ZERO_PID; + static u8 rbuf[1]; + u8 pid_no = index * 2; + u8 pid_len = pid_no + 2; + int ret = 0; + deb_info(1, "PID Setting Pid %04x", pid_out); + + if (st->pid_size == 0) + ret |= lme2510_stream_restart(d); + + pid_buff[2] = pid_no; + pid_buff[3] = (u8)pid_out & 0xff; + pid_buff[4] = pid_no + 1; + pid_buff[5] = (u8)(pid_out >> 8); + + if (pid_len > st->pid_size) + st->pid_size = pid_len; + pid_buff[7] = 0x80 + st->pid_size; + + ret |= lme2510_usb_talk(d, pid_buff , + sizeof(pid_buff) , rbuf, sizeof(rbuf)); + + if (st->stream_on) + ret |= lme2510_stream_restart(d); + + return ret; +} + +static void lme2510_int_response(struct urb *lme_urb) +{ + struct dvb_usb_adapter *adap = lme_urb->context; + struct lme2510_state *st = adap->dev->priv; + static u8 *ibuf, *rbuf; + int i = 0, offset; + u32 key; + + switch (lme_urb->status) { + case 0: + case -ETIMEDOUT: + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + default: + info("Error %x", lme_urb->status); + break; + } + + rbuf = (u8 *) lme_urb->transfer_buffer; + + offset = ((lme_urb->actual_length/8) > 4) + ? 4 : (lme_urb->actual_length/8) ; + + for (i = 0; i < offset; ++i) { + ibuf = (u8 *)&rbuf[i*8]; + deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x", + offset, i, ibuf[0], ibuf[1]); + + switch (ibuf[0]) { + case 0xaa: + debug_data_snipet(1, "INT Remote data snipet", ibuf); + if ((ibuf[4] + ibuf[5]) == 0xff) { + key = ibuf[5]; + key += (ibuf[3] > 0) + ? (ibuf[3] ^ 0xff) << 8 : 0; + key += (ibuf[2] ^ 0xff) << 16; + deb_info(1, "INT Key =%08x", key); + if (adap->dev->rc_dev != NULL) + rc_keydown(adap->dev->rc_dev, key, 0); + } + break; + case 0xbb: + switch (st->tuner_config) { + case TUNER_LG: + if (ibuf[2] > 0) + st->signal_lock = ibuf[2]; + st->signal_level = ibuf[4]; + st->signal_sn = ibuf[3]; + st->time_key = ibuf[7]; + break; + case TUNER_S7395: + case TUNER_S0194: + /* Tweak for earlier firmware*/ + if (ibuf[1] == 0x03) { + if (ibuf[2] > 1) + st->signal_lock = ibuf[2]; + st->signal_level = ibuf[3]; + st->signal_sn = ibuf[4]; + } else { + st->signal_level = ibuf[4]; + st->signal_sn = ibuf[5]; + st->signal_lock = + (st->signal_lock & 0xf7) + + ((ibuf[2] & 0x01) << 0x03); + } + break; + default: + break; + } + debug_data_snipet(5, "INT Remote data snipet in", ibuf); + break; + case 0xcc: + debug_data_snipet(1, "INT Control data snipet", ibuf); + break; + default: + debug_data_snipet(1, "INT Unknown data snipet", ibuf); + break; + } + } + usb_submit_urb(lme_urb, GFP_ATOMIC); +} + +static int lme2510_int_read(struct dvb_usb_adapter *adap) +{ + struct lme2510_state *lme_int = adap->dev->priv; + + lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC); + + if (lme_int->lme_urb == NULL) + return -ENOMEM; + + lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 5000, GFP_ATOMIC, + &lme_int->lme_urb->transfer_dma); + + if (lme_int->buffer == NULL) + return -ENOMEM; + + usb_fill_int_urb(lme_int->lme_urb, + adap->dev->udev, + usb_rcvintpipe(adap->dev->udev, 0xa), + lme_int->buffer, + 4096, + lme2510_int_response, + adap, + 11); + + lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC); + info("INT Interrupt Service Started"); + + return 0; +} + +static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct lme2510_state *st = adap->dev->priv; + static u8 clear_pid_reg[] = LME_CLEAR_PID; + static u8 rbuf[1]; + int ret; + + deb_info(1, "PID Clearing Filter"); + + ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); + if (ret < 0) + return -EAGAIN; + + if (!onoff) + ret |= lme2510_usb_talk(adap->dev, clear_pid_reg, + sizeof(clear_pid_reg), rbuf, sizeof(rbuf)); + + st->pid_size = 0; + + mutex_unlock(&adap->dev->i2c_mutex); + + return 0; +} + +static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + int ret = 0; + + deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__, + pid, index, onoff); + + if (onoff) + if (!pid_filter) { + ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); + if (ret < 0) + return -EAGAIN; + ret |= lme2510_enable_pid(adap->dev, index, pid); + mutex_unlock(&adap->dev->i2c_mutex); + } + + + return ret; +} + + +static int lme2510_return_status(struct usb_device *dev) +{ + int ret = 0; + u8 *data; + + data = kzalloc(10, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200); + info("Firmware Status: %x (%x)", ret , data[2]); + + ret = (ret < 0) ? -ENODEV : data[2]; + kfree(data); + return ret; +} + +static int lme2510_msg(struct dvb_usb_device *d, + u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int ret = 0; + struct lme2510_state *st = d->priv; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (st->i2c_talk_onoff == 1) { + + ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + + switch (st->tuner_config) { + case TUNER_LG: + if (wbuf[2] == 0x1c) { + if (wbuf[3] == 0x0e) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x10)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + msleep(80); + } + } + break; + case TUNER_S7395: + if (wbuf[2] == 0xd0) { + if (wbuf[3] == 0x24) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x8)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + } + if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5)) + msleep(5); + } + break; + case TUNER_S0194: + if (wbuf[2] == 0xd0) { + if (wbuf[3] == 0x1b) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x8)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + } + } + break; + default: + break; + } + } else { + switch (st->tuner_config) { + case TUNER_LG: + switch (wbuf[3]) { + case 0x0e: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x43: + rbuf[0] = 0x55; + rbuf[1] = st->signal_level; + break; + case 0x1c: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x15: + case 0x16: + case 0x17: + case 0x18: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; + case TUNER_S7395: + switch (wbuf[3]) { + case 0x10: + rbuf[0] = 0x55; + rbuf[1] = (st->signal_level & 0x80) + ? 0 : (st->signal_level * 2); + break; + case 0x2d: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x24: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x2e: + case 0x26: + case 0x27: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; + case TUNER_S0194: + switch (wbuf[3]) { + case 0x18: + rbuf[0] = 0x55; + rbuf[1] = (st->signal_level & 0x80) + ? 0 : (st->signal_level * 2); + break; + case 0x24: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x1b: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x19: + case 0x25: + case 0x1e: + case 0x1d: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; + default: + break; + } + + deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)", + wbuf[3], rbuf[1]); + + } + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + + +static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct lme2510_state *st = d->priv; + static u8 obuf[64], ibuf[512]; + int i, read, read_o; + u16 len; + u8 gate = st->i2c_gate; + + if (gate == 0) + gate = 5; + + if (num > 2) + warn("more than 2 i2c messages" + "at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + read_o = 1 & (msg[i].flags & I2C_M_RD); + read = i+1 < num && (msg[i+1].flags & I2C_M_RD); + read |= read_o; + gate = (msg[i].addr == st->i2c_tuner_addr) + ? (read) ? st->i2c_tuner_gate_r + : st->i2c_tuner_gate_w + : st->i2c_gate; + obuf[0] = gate | (read << 7); + + if (gate == 5) + obuf[1] = (read) ? 2 : msg[i].len + 1; + else + obuf[1] = msg[i].len + read + 1; + + obuf[2] = msg[i].addr; + if (read) { + if (read_o) + len = 3; + else { + memcpy(&obuf[3], msg[i].buf, msg[i].len); + obuf[msg[i].len+3] = msg[i+1].len; + len = msg[i].len+4; + } + } else { + memcpy(&obuf[3], msg[i].buf, msg[i].len); + len = msg[i].len+3; + } + + if (lme2510_msg(d, obuf, len, ibuf, 512) < 0) { + deb_info(1, "i2c transfer failed."); + return -EAGAIN; + } + + if (read) { + if (read_o) + memcpy(msg[i].buf, &ibuf[1], msg[i].len); + else { + memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); + i++; + } + } + } + return i; +} + +static u32 lme2510_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm lme2510_i2c_algo = { + .master_xfer = lme2510_i2c_xfer, + .functionality = lme2510_i2c_func, +}; + +/* Callbacks for DVB USB */ +static int lme2510_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + *cold = 0; + return 0; +} + +static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct lme2510_state *st = adap->dev->priv; + static u8 clear_reg_3[] = LME_CLEAR_PID; + static u8 rbuf[1]; + int ret = 0, rlen = sizeof(rbuf); + + deb_info(1, "STM (%02x)", onoff); + + /* Streaming is started by FE_HAS_LOCK */ + if (onoff == 1) + st->stream_on = 1; + else { + deb_info(1, "STM Steam Off"); + /* mutex is here only to avoid collision with I2C */ + if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) + return -EAGAIN; + + ret = lme2510_usb_talk(adap->dev, clear_reg_3, + sizeof(clear_reg_3), rbuf, rlen); + st->stream_on = 0; + st->i2c_talk_onoff = 1; + + mutex_unlock(&adap->dev->i2c_mutex); + } + + return (ret < 0) ? -ENODEV : 0; +} + +static u8 check_sum(u8 *p, u8 len) +{ + u8 sum = 0; + while (len--) + sum += *p++; + return sum; +} + +static int lme2510_download_firmware(struct usb_device *dev, + const struct firmware *fw) +{ + int ret = 0; + u8 *data; + u16 j, wlen, len_in, start, end; + u8 packet_size, dlen, i; + u8 *fw_data; + + packet_size = 0x31; + len_in = 1; + + data = kzalloc(512, GFP_KERNEL); + if (!data) { + info("FRM Could not start Firmware Download (Buffer allocation failed)"); + return -ENOMEM; + } + + info("FRM Starting Firmware Download"); + + for (i = 1; i < 3; i++) { + start = (i == 1) ? 0 : 512; + end = (i == 1) ? 512 : fw->size; + for (j = start; j < end; j += (packet_size+1)) { + fw_data = (u8 *)(fw->data + j); + if ((end - j) > packet_size) { + data[0] = i; + dlen = packet_size; + } else { + data[0] = i | 0x80; + dlen = (u8)(end - j)-1; + } + data[1] = dlen; + memcpy(&data[2], fw_data, dlen+1); + wlen = (u8) dlen + 4; + data[wlen-1] = check_sum(fw_data, dlen+1); + deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3], + data[dlen+2], data[dlen+3]); + ret |= lme2510_bulk_write(dev, data, wlen, 1); + ret |= lme2510_bulk_read(dev, data, len_in , 1); + ret |= (data[0] == 0x88) ? 0 : -1; + } + } + + usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000); + + + data[0] = 0x8a; + len_in = 1; + msleep(2000); + ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Resetting*/ + ret |= lme2510_bulk_read(dev, data, len_in, 1); + msleep(400); + + if (ret < 0) + info("FRM Firmware Download Failed (%04x)" , ret); + else + info("FRM Firmware Download Completed - Resetting Device"); + + kfree(data); + return (ret < 0) ? -ENODEV : 0; +} + +static void lme_coldreset(struct usb_device *dev) +{ + int ret = 0, len_in; + u8 data[512] = {0}; + + data[0] = 0x0a; + len_in = 1; + info("FRM Firmware Cold Reset"); + ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/ + ret |= lme2510_bulk_read(dev, data, len_in, 1); + + return; +} + +static int lme_firmware_switch(struct usb_device *udev, int cold) +{ + const struct firmware *fw = NULL; + const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw"; + const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw"; + const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw"; + const char fw_lg[] = "dvb-usb-lme2510-lg.fw"; + const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw"; + const char *fw_lme; + int ret, cold_fw; + + cold = (cold > 0) ? (cold & 1) : 0; + + cold_fw = !cold; + + if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) { + switch (dvb_usb_lme2510_firmware) { + default: + dvb_usb_lme2510_firmware = TUNER_S0194; + case TUNER_S0194: + fw_lme = fw_s0194; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) { + cold = 0; + break; + } + dvb_usb_lme2510_firmware = TUNER_LG; + case TUNER_LG: + fw_lme = fw_lg; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + info("FRM No Firmware Found - please install"); + dvb_usb_lme2510_firmware = TUNER_DEFAULT; + cold = 0; + cold_fw = 0; + break; + } + } else { + switch (dvb_usb_lme2510_firmware) { + default: + dvb_usb_lme2510_firmware = TUNER_S7395; + case TUNER_S7395: + fw_lme = fw_c_s7395; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) { + cold = 0; + break; + } + dvb_usb_lme2510_firmware = TUNER_LG; + case TUNER_LG: + fw_lme = fw_c_lg; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + dvb_usb_lme2510_firmware = TUNER_S0194; + case TUNER_S0194: + fw_lme = fw_c_s0194; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + info("FRM No Firmware Found - please install"); + dvb_usb_lme2510_firmware = TUNER_DEFAULT; + cold = 0; + cold_fw = 0; + break; + } + } + + if (cold_fw) { + info("FRM Loading %s file", fw_lme); + ret = lme2510_download_firmware(udev, fw); + } + + release_firmware(fw); + + if (cold) { + info("FRM Changing to %s firmware", fw_lme); + lme_coldreset(udev); + return -ENODEV; + } + + return ret; +} + +static int lme2510_kill_urb(struct usb_data_stream *stream) +{ + int i; + + for (i = 0; i < stream->urbs_submitted; i++) { + deb_info(3, "killing URB no. %d.", i); + /* stop the URB */ + usb_kill_urb(stream->urb_list[i]); + } + stream->urbs_submitted = 0; + + return 0; +} + +static struct tda10086_config tda10086_config = { + .demod_address = 0x1c, + .invert = 0, + .diseqc_tone = 1, + .xtal_freq = TDA10086_XTAL_16M, +}; + +static struct stv0288_config lme_config = { + .demod_address = 0xd0, + .min_delay_ms = 15, + .inittab = s7395_inittab, +}; + +static struct ix2505v_config lme_tuner = { + .tuner_address = 0xc0, + .min_delay_ms = 100, + .tuner_gain = 0x0, + .tuner_chargepump = 0x3, +}; + +static struct stv0299_config sharp_z0194_config = { + .demod_address = 0xd0, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + +static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + static u8 voltage_low[] = LME_VOLTAGE_L; + static u8 voltage_high[] = LME_VOLTAGE_H; + static u8 rbuf[1]; + int ret = 0, len = 3, rlen = 1; + + if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) + return -EAGAIN; + + switch (voltage) { + case SEC_VOLTAGE_18: + ret |= lme2510_usb_talk(adap->dev, + voltage_high, len, rbuf, rlen); + break; + + case SEC_VOLTAGE_OFF: + case SEC_VOLTAGE_13: + default: + ret |= lme2510_usb_talk(adap->dev, + voltage_low, len, rbuf, rlen); + break; + } + + mutex_unlock(&adap->dev->i2c_mutex); + + return (ret < 0) ? -ENODEV : 0; +} + +static int lme_name(struct dvb_usb_adapter *adap) +{ + struct lme2510_state *st = adap->dev->priv; + const char *desc = adap->dev->desc->name; + char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", + " SHARP:BS2F7HZ0194"}; + char *name = adap->fe->ops.info.name; + + strlcpy(name, desc, 128); + strlcat(name, fe_name[st->tuner_config], 128); + + return 0; +} + +static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct lme2510_state *st = adap->dev->priv; + + int ret = 0; + + st->i2c_talk_onoff = 1; + + st->i2c_gate = 4; + adap->fe = dvb_attach(tda10086_attach, &tda10086_config, + &adap->dev->i2c_adap); + + if (adap->fe) { + info("TUN Found Frontend TDA10086"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 4; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_LG; + if (dvb_usb_lme2510_firmware != TUNER_LG) { + dvb_usb_lme2510_firmware = TUNER_LG; + ret = lme_firmware_switch(adap->dev->udev, 1); + } + goto end; + } + + st->i2c_gate = 4; + adap->fe = dvb_attach(stv0299_attach, &sharp_z0194_config, + &adap->dev->i2c_adap); + if (adap->fe) { + info("FE Found Stv0299"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_S0194; + if (dvb_usb_lme2510_firmware != TUNER_S0194) { + dvb_usb_lme2510_firmware = TUNER_S0194; + ret = lme_firmware_switch(adap->dev->udev, 1); + } + goto end; + } + + st->i2c_gate = 5; + adap->fe = dvb_attach(stv0288_attach, &lme_config, + &adap->dev->i2c_adap); + if (adap->fe) { + info("FE Found Stv0288"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_S7395; + if (dvb_usb_lme2510_firmware != TUNER_S7395) { + dvb_usb_lme2510_firmware = TUNER_S7395; + ret = lme_firmware_switch(adap->dev->udev, 1); + } + } else { + info("DM04 Not Supported"); + return -ENODEV; + } + + +end: if (ret) { + if (adap->fe) { + dvb_frontend_detach(adap->fe); + adap->fe = NULL; + } + adap->dev->props.rc.core.rc_codes = NULL; + return -ENODEV; + } + + adap->fe->ops.set_voltage = dm04_lme2510_set_voltage; + ret = lme_name(adap); + return ret; +} + +static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) +{ + struct lme2510_state *st = adap->dev->priv; + char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"}; + int ret = 0; + + switch (st->tuner_config) { + case TUNER_LG: + if (dvb_attach(tda826x_attach, adap->fe, 0xc0, + &adap->dev->i2c_adap, 1)) + ret = st->tuner_config; + break; + case TUNER_S7395: + if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner, + &adap->dev->i2c_adap)) + ret = st->tuner_config; + break; + case TUNER_S0194: + if (dvb_attach(dvb_pll_attach , adap->fe, 0xc0, + &adap->dev->i2c_adap, DVB_PLL_OPERA1)) + ret = st->tuner_config; + break; + default: + break; + } + + if (ret) + info("TUN Found %s tuner", tun_msg[ret]); + else { + info("TUN No tuner found --- reseting device"); + lme_coldreset(adap->dev->udev); + return -ENODEV; + } + + /* Start the Interrupt*/ + ret = lme2510_int_read(adap); + if (ret < 0) { + info("INT Unable to start Interrupt Service"); + return -ENODEV; + } + + return ret; +} + +static int lme2510_powerup(struct dvb_usb_device *d, int onoff) +{ + struct lme2510_state *st = d->priv; + static u8 lnb_on[] = LNB_ON; + static u8 lnb_off[] = LNB_OFF; + static u8 rbuf[1]; + int ret, len = 3, rlen = 1; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (onoff) + ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); + else + ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen); + + st->i2c_talk_onoff = 1; + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties lme2510_properties; +static struct dvb_usb_device_properties lme2510c_properties; + +static int lme2510_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + int ret = 0; + + usb_reset_configuration(udev); + + usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1); + + if (udev->speed != USB_SPEED_HIGH) { + ret = usb_reset_device(udev); + info("DEV Failed to connect in HIGH SPEED mode"); + return -ENODEV; + } + + if (lme2510_return_status(udev) == 0x44) { + lme_firmware_switch(udev, 0); + return -ENODEV; + } + + if (0 == dvb_usb_device_init(intf, &lme2510_properties, + THIS_MODULE, NULL, adapter_nr)) { + info("DEV registering device driver"); + return 0; + } + if (0 == dvb_usb_device_init(intf, &lme2510c_properties, + THIS_MODULE, NULL, adapter_nr)) { + info("DEV registering device driver"); + return 0; + } + + info("DEV lme2510 Error"); + return -ENODEV; + +} + +static struct usb_device_id lme2510_table[] = { + { USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */ + { USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */ + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, lme2510_table); + +static struct dvb_usb_device_properties lme2510_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .size_of_priv = sizeof(struct lme2510_state), + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER| + DVB_USB_ADAP_NEED_PID_FILTERING| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .streaming_ctrl = lme2510_streaming_ctrl, + .pid_filter_count = 15, + .pid_filter = lme2510_pid_filter, + .pid_filter_ctrl = lme2510_pid_filter_ctrl, + .frontend_attach = dm04_lme2510_frontend_attach, + .tuner_attach = dm04_lme2510_tuner, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + + } + } + } + } + }, + .rc.core = { + .protocol = RC_TYPE_NEC, + .module_name = "LME2510 Remote Control", + .allowed_protos = RC_TYPE_NEC, + .rc_codes = RC_MAP_LME2510, + }, + .power_ctrl = lme2510_powerup, + .identify_state = lme2510_identify_state, + .i2c_algo = &lme2510_i2c_algo, + .generic_bulk_ctrl_endpoint = 0, + .num_device_descs = 1, + .devices = { + { "DM04_LME2510_DVB-S", + { &lme2510_table[0], NULL }, + }, + + } +}; + +static struct dvb_usb_device_properties lme2510c_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .size_of_priv = sizeof(struct lme2510_state), + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER| + DVB_USB_ADAP_NEED_PID_FILTERING| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .streaming_ctrl = lme2510_streaming_ctrl, + .pid_filter_count = 15, + .pid_filter = lme2510_pid_filter, + .pid_filter_ctrl = lme2510_pid_filter_ctrl, + .frontend_attach = dm04_lme2510_frontend_attach, + .tuner_attach = dm04_lme2510_tuner, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x8, + .u = { + .bulk = { + .buffersize = 4096, + + } + } + } + } + }, + .rc.core = { + .protocol = RC_TYPE_NEC, + .module_name = "LME2510 Remote Control", + .allowed_protos = RC_TYPE_NEC, + .rc_codes = RC_MAP_LME2510, + }, + .power_ctrl = lme2510_powerup, + .identify_state = lme2510_identify_state, + .i2c_algo = &lme2510_i2c_algo, + .generic_bulk_ctrl_endpoint = 0, + .num_device_descs = 1, + .devices = { + { "DM04_LME2510C_DVB-S", + { &lme2510_table[1], NULL }, + }, + } +}; + +static void *lme2510_exit_int(struct dvb_usb_device *d) +{ + struct lme2510_state *st = d->priv; + struct dvb_usb_adapter *adap = &d->adapter[0]; + void *buffer = NULL; + + if (adap != NULL) { + lme2510_kill_urb(&adap->stream); + adap->feedcount = 0; + } + + if (st->usb_buffer != NULL) { + st->i2c_talk_onoff = 1; + st->signal_lock = 0; + st->signal_level = 0; + st->signal_sn = 0; + buffer = st->usb_buffer; + } + + if (st->lme_urb != NULL) { + usb_kill_urb(st->lme_urb); + usb_free_coherent(d->udev, 5000, st->buffer, + st->lme_urb->transfer_dma); + info("Interrupt Service Stopped"); + } + + return buffer; +} + +static void lme2510_exit(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + void *usb_buffer; + + if (d != NULL) { + usb_buffer = lme2510_exit_int(d); + dvb_usb_device_exit(intf); + if (usb_buffer != NULL) + kfree(usb_buffer); + } +} + +static struct usb_driver lme2510_driver = { + .name = "LME2510C_DVB-S", + .probe = lme2510_probe, + .disconnect = lme2510_exit, + .id_table = lme2510_table, +}; + +/* module stuff */ +static int __init lme2510_module_init(void) +{ + int result = usb_register(&lme2510_driver); + if (result) { + err("usb_register failed. Error number %d", result); + return result; + } + + return 0; +} + +static void __exit lme2510_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&lme2510_driver); +} + +module_init(lme2510_module_init); +module_exit(lme2510_module_exit); + +MODULE_AUTHOR("Malcolm Priestley "); +MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/lmedm04.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/lmedm04.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/lmedm04.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/lmedm04.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,174 @@ +/* DVB USB compliant linux driver for + * + * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 + * LME2510C + LG TDQY-P001F + * LME2510 + LG TDQY-P001F + * + * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) + * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) + * + * MVB001F (LME2510+LGTDQT-P001F) + * LG TDQY - P001F =(TDA8263 + TDA10086H) + * + * MVB0001F (LME2510C+LGTDQT-P001F) + * + * 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, version 2. + * * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_LME2510_H_ +#define _DVB_USB_LME2510_H_ + +/* Streamer & PID + * + * Note: These commands do not actually stop the streaming + * but form some kind of packet filtering/stream count + * or tuning related functions. + * 06 XX + * offset 1 = 00 Enable Streaming + * + * + * PID + * 03 XX XX ----> reg number ---> setting....20 XX + * offset 1 = length + * offset 2 = start of data + * end byte -1 = 20 + * end byte = clear pid always a0, other wise 9c, 9a ?? + * +*/ +#define LME_ST_ON_W {0x06, 0x00} +#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} +#define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c} + +/* LNB Voltage + * 07 XX XX + * offset 1 = 01 + * offset 2 = 00=Voltage low 01=Voltage high + * + * LNB Power + * 03 01 XX + * offset 2 = 00=ON 01=OFF + */ + +#define LME_VOLTAGE_L {0x07, 0x01, 0x00} +#define LME_VOLTAGE_H {0x07, 0x01, 0x01} +#define LNB_ON {0x3a, 0x01, 0x00} +#define LNB_OFF {0x3a, 0x01, 0x01} + +/* Initial stv0288 settings for 7395 Frontend */ +static u8 s7395_inittab[] = { + 0x01, 0x15, + 0x02, 0x20, + 0x03, 0xa0, + 0x04, 0xa0, + 0x05, 0x12, + 0x06, 0x00, + 0x09, 0x00, + 0x0a, 0x04, + 0x0b, 0x00, + 0x0c, 0x00, + 0x0d, 0x00, + 0x0e, 0xc1, + 0x0f, 0x54, + 0x11, 0x7a, + 0x12, 0x03, + 0x13, 0x48, + 0x14, 0x84, + 0x15, 0xc5, + 0x16, 0xb8, + 0x17, 0x9c, + 0x18, 0x00, + 0x19, 0xa6, + 0x1a, 0x88, + 0x1b, 0x8f, + 0x1c, 0xf0, + 0x20, 0x0b, + 0x21, 0x54, + 0x22, 0xff, + 0x23, 0x01, + 0x28, 0x46, + 0x29, 0x66, + 0x2a, 0x90, + 0x2b, 0xfa, + 0x2c, 0xd9, + 0x30, 0x0, + 0x31, 0x1e, + 0x32, 0x14, + 0x33, 0x0f, + 0x34, 0x09, + 0x35, 0x0c, + 0x36, 0x05, + 0x37, 0x2f, + 0x38, 0x16, + 0x39, 0xbd, + 0x3a, 0x0, + 0x3b, 0x13, + 0x3c, 0x11, + 0x3d, 0x30, + 0x40, 0x63, + 0x41, 0x04, + 0x42, 0x20, + 0x43, 0x00, + 0x44, 0x00, + 0x45, 0x00, + 0x46, 0x00, + 0x47, 0x00, + 0x4a, 0x00, + 0x50, 0x10, + 0x51, 0x36, + 0x52, 0x21, + 0x53, 0x94, + 0x54, 0xb2, + 0x55, 0x29, + 0x56, 0x64, + 0x57, 0x2b, + 0x58, 0x54, + 0x59, 0x86, + 0x5a, 0x00, + 0x5b, 0x9b, + 0x5c, 0x08, + 0x5d, 0x7f, + 0x5e, 0xff, + 0x5f, 0x8d, + 0x70, 0x0, + 0x71, 0x0, + 0x72, 0x0, + 0x74, 0x0, + 0x75, 0x0, + 0x76, 0x0, + 0x81, 0x0, + 0x82, 0x3f, + 0x83, 0x3f, + 0x84, 0x0, + 0x85, 0x0, + 0x88, 0x0, + 0x89, 0x0, + 0x8a, 0x0, + 0x8b, 0x0, + 0x8c, 0x0, + 0x90, 0x0, + 0x91, 0x0, + 0x92, 0x0, + 0x93, 0x0, + 0x94, 0x1c, + 0x97, 0x0, + 0xa0, 0x48, + 0xa1, 0x0, + 0xb0, 0xb8, + 0xb1, 0x3a, + 0xb2, 0x10, + 0xb3, 0x82, + 0xb4, 0x80, + 0xb5, 0x82, + 0xb6, 0x82, + 0xb7, 0x82, + 0xb8, 0x20, + 0xb9, 0x0, + 0xf0, 0x0, + 0xf1, 0x0, + 0xf2, 0xc0, + 0xff, 0xff, +}; +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/m920x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/m920x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/m920x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/m920x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1092 @@ +/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver + * + * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ + +#include "m920x.h" + +#include "mt352.h" +#include "mt352_priv.h" +#include "qt1010.h" +#include "tda1004x.h" +#include "tda827x.h" + +#include +#include "tuner-simple.h" +#include + +/* debug */ +static int dvb_usb_m920x_debug; +module_param_named(debug,dvb_usb_m920x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid); + +static inline int m920x_read(struct usb_device *udev, u8 request, u16 value, + u16 index, void *data, int size) +{ + int ret; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + request, USB_TYPE_VENDOR | USB_DIR_IN, + value, index, data, size, 2000); + if (ret < 0) { + printk(KERN_INFO "m920x_read = error: %d\n", ret); + return ret; + } + + if (ret != size) { + deb("m920x_read = no data\n"); + return -EIO; + } + + return 0; +} + +static inline int m920x_write(struct usb_device *udev, u8 request, + u16 value, u16 index) +{ + int ret; + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + request, USB_TYPE_VENDOR | USB_DIR_OUT, + value, index, NULL, 0, 2000); + + return ret; +} + +static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) +{ + int ret = 0, i, epi, flags = 0; + int adap_enabled[M9206_MAX_ADAPTERS] = { 0 }; + + /* Remote controller init. */ + if (d->props.rc.legacy.rc_query) { + deb("Initialising remote control\n"); + while (rc_seq->address) { + if ((ret = m920x_write(d->udev, M9206_CORE, + rc_seq->data, + rc_seq->address)) != 0) { + deb("Initialising remote control failed\n"); + return ret; + } + + rc_seq++; + } + + deb("Initialising remote control success\n"); + } + + for (i = 0; i < d->props.num_adapters; i++) + flags |= d->adapter[i].props.caps; + + /* Some devices(Dposh) might crash if we attempt touch at all. */ + if (flags & DVB_USB_ADAP_HAS_PID_FILTER) { + for (i = 0; i < d->props.num_adapters; i++) { + epi = d->adapter[i].props.stream.endpoint - 0x81; + + if (epi < 0 || epi >= M9206_MAX_ADAPTERS) { + printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n"); + return -EINVAL; + } + + adap_enabled[epi] = 1; + } + + for (i = 0; i < M9206_MAX_ADAPTERS; i++) { + if (adap_enabled[i]) + continue; + + if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0) + return ret; + + if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0) + return ret; + } + } + + return ret; +} + +static int m920x_init_ep(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_host_interface *alt; + + if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) { + deb("No alt found!\n"); + return -ENODEV; + } + + return usb_set_interface(udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); +} + +static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct m920x_state *m = d->priv; + int i, ret = 0; + u8 *rc_state; + + rc_state = kmalloc(2, GFP_KERNEL); + if (!rc_state) + return -ENOMEM; + + if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0) + goto out; + + if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0) + goto out; + + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) + if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) { + *event = d->props.rc.legacy.rc_map_table[i].keycode; + + switch(rc_state[0]) { + case 0x80: + *state = REMOTE_NO_KEY_PRESSED; + goto out; + + case 0x88: /* framing error or "invalid code" */ + case 0x99: + case 0xc0: + case 0xd8: + *state = REMOTE_NO_KEY_PRESSED; + m->rep_count = 0; + goto out; + + case 0x93: + case 0x92: + case 0x83: /* pinnacle PCTV310e */ + case 0x82: + m->rep_count = 0; + *state = REMOTE_KEY_PRESSED; + goto out; + + case 0x91: + case 0x81: /* pinnacle PCTV310e */ + /* prevent immediate auto-repeat */ + if (++m->rep_count > 2) + *state = REMOTE_KEY_REPEAT; + else + *state = REMOTE_NO_KEY_PRESSED; + goto out; + + default: + deb("Unexpected rc state %02x\n", rc_state[0]); + *state = REMOTE_NO_KEY_PRESSED; + goto out; + } + } + + if (rc_state[1] != 0) + deb("Unknown rc key %02x\n", rc_state[1]); + + *state = REMOTE_NO_KEY_PRESSED; + + out: + kfree(rc_state); + return ret; +} + +/* I2C */ +static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i, j; + int ret = 0; + + if (!num) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if (msg[i].flags & (I2C_M_NO_RD_ACK | I2C_M_IGNORE_NAK | I2C_M_TEN) || msg[i].len == 0) { + /* For a 0 byte message, I think sending the address + * to index 0x80|0x40 would be the correct thing to + * do. However, zero byte messages are only used for + * probing, and since we don't know how to get the + * slave's ack, we can't probe. */ + ret = -ENOTSUPP; + goto unlock; + } + /* Send START & address/RW bit */ + if (!(msg[i].flags & I2C_M_NOSTART)) { + if ((ret = m920x_write(d->udev, M9206_I2C, + (msg[i].addr << 1) | + (msg[i].flags & I2C_M_RD ? 0x01 : 0), 0x80)) != 0) + goto unlock; + /* Should check for ack here, if we knew how. */ + } + if (msg[i].flags & I2C_M_RD) { + for (j = 0; j < msg[i].len; j++) { + /* Last byte of transaction? + * Send STOP, otherwise send ACK. */ + int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x01; + + if ((ret = m920x_read(d->udev, M9206_I2C, 0x0, + 0x20 | stop, + &msg[i].buf[j], 1)) != 0) + goto unlock; + } + } else { + for (j = 0; j < msg[i].len; j++) { + /* Last byte of transaction? Then send STOP. */ + int stop = (i+1 == num && j+1 == msg[i].len) ? 0x40 : 0x00; + + if ((ret = m920x_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0) + goto unlock; + /* Should check for ack here too. */ + } + } + } + ret = num; + + unlock: + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 m920x_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm m920x_i2c_algo = { + .master_xfer = m920x_i2c_xfer, + .functionality = m920x_i2c_func, +}; + +/* pid filter */ +static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid) +{ + int ret = 0; + + if (pid >= 0x8000) + return -EINVAL; + + pid |= 0x8000; + + if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0) + return ret; + + if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0) + return ret; + + return ret; +} + +static int m920x_update_filters(struct dvb_usb_adapter *adap) +{ + struct m920x_state *m = adap->dev->priv; + int enabled = m->filtering_enabled[adap->id]; + int i, ret = 0, filter = 0; + int ep = adap->props.stream.endpoint; + + for (i = 0; i < M9206_MAX_FILTERS; i++) + if (m->filters[adap->id][i] == 8192) + enabled = 0; + + /* Disable all filters */ + if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0) + return ret; + + for (i = 0; i < M9206_MAX_FILTERS; i++) + if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0) + return ret; + + /* Set */ + if (enabled) { + for (i = 0; i < M9206_MAX_FILTERS; i++) { + if (m->filters[adap->id][i] == 0) + continue; + + if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0) + return ret; + + filter++; + } + } + + return ret; +} + +static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct m920x_state *m = adap->dev->priv; + + m->filtering_enabled[adap->id] = onoff ? 1 : 0; + + return m920x_update_filters(adap); +} + +static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) +{ + struct m920x_state *m = adap->dev->priv; + + m->filters[adap->id][index] = onoff ? pid : 0; + + return m920x_update_filters(adap); +} + +static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw) +{ + u16 value, index, size; + u8 *read, *buff; + int i, pass, ret = 0; + + buff = kmalloc(65536, GFP_KERNEL); + if (buff == NULL) + return -ENOMEM; + + read = kmalloc(4, GFP_KERNEL); + if (!read) { + kfree(buff); + return -ENOMEM; + } + + if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) + goto done; + deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]); + + if ((ret = m920x_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0) + goto done; + deb("%x\n", read[0]); + + for (pass = 0; pass < 2; pass++) { + for (i = 0; i + (sizeof(u16) * 3) < fw->size;) { + value = get_unaligned_le16(fw->data + i); + i += sizeof(u16); + + index = get_unaligned_le16(fw->data + i); + i += sizeof(u16); + + size = get_unaligned_le16(fw->data + i); + i += sizeof(u16); + + if (pass == 1) { + /* Will stall if using fw->data ... */ + memcpy(buff, fw->data + i, size); + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), + M9206_FW, + USB_TYPE_VENDOR | USB_DIR_OUT, + value, index, buff, size, 20); + if (ret != size) { + deb("error while uploading fw!\n"); + ret = -EIO; + goto done; + } + msleep(3); + } + i += size; + } + if (i != fw->size) { + deb("bad firmware file!\n"); + ret = -EINVAL; + goto done; + } + } + + msleep(36); + + /* m920x will disconnect itself from the bus after this. */ + (void) m920x_write(udev, M9206_CORE, 0x01, M9206_FW_GO); + deb("firmware uploaded!\n"); + + done: + kfree(read); + kfree(buff); + + return ret; +} + +/* Callbacks for DVB USB */ +static int m920x_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + struct usb_host_interface *alt; + + alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1); + *cold = (alt == NULL) ? 1 : 0; + + return 0; +} + +/* demod configurations */ +static int m920x_mt352_demod_init(struct dvb_frontend *fe) +{ + int ret; + u8 config[] = { CONFIG, 0x3d }; + u8 clock[] = { CLOCK_CTL, 0x30 }; + u8 reset[] = { RESET, 0x80 }; + u8 adc_ctl[] = { ADC_CTL_1, 0x40 }; + u8 agc[] = { AGC_TARGET, 0x1c, 0x20 }; + u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 }; + u8 unk1[] = { 0x93, 0x1a }; + u8 unk2[] = { 0xb5, 0x7a }; + + deb("Demod init!\n"); + + if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0) + return ret; + if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0) + return ret; + if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0) + return ret; + if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0) + return ret; + if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0) + return ret; + if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0) + return ret; + if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0) + return ret; + if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0) + return ret; + + return 0; +} + +static struct mt352_config m920x_mt352_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .demod_init = m920x_mt352_demod_init, +}; + +static struct tda1004x_config m920x_tda10046_08_config = { + .demod_address = 0x08, + .invert = 0, + .invert_oclk = 0, + .ts_mode = TDA10046_TS_SERIAL, + .xtal_freq = TDA10046_XTAL_16M, + .if_freq = TDA10046_FREQ_045, + .agc_config = TDA10046_AGC_TDA827X, + .gpio_config = TDA10046_GPTRI, + .request_firmware = NULL, +}; + +static struct tda1004x_config m920x_tda10046_0b_config = { + .demod_address = 0x0b, + .invert = 0, + .invert_oclk = 0, + .ts_mode = TDA10046_TS_SERIAL, + .xtal_freq = TDA10046_XTAL_16M, + .if_freq = TDA10046_FREQ_045, + .agc_config = TDA10046_AGC_TDA827X, + .gpio_config = TDA10046_GPTRI, + .request_firmware = NULL, /* uses firmware EEPROM */ +}; + +/* tuner configurations */ +static struct qt1010_config m920x_qt1010_config = { + .i2c_address = 0x62 +}; + +/* Callbacks for DVB USB */ +static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + if ((adap->fe = dvb_attach(mt352_attach, + &m920x_mt352_config, + &adap->dev->i2c_adap)) == NULL) + return -EIO; + + return 0; +} + +static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + if ((adap->fe = dvb_attach(tda10046_attach, + &m920x_tda10046_08_config, + &adap->dev->i2c_adap)) == NULL) + return -EIO; + + return 0; +} + +static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + if ((adap->fe = dvb_attach(tda10046_attach, + &m920x_tda10046_0b_config, + &adap->dev->i2c_adap)) == NULL) + return -EIO; + + return 0; +} + +static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) + return -ENODEV; + + return 0; +} + +static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL) + return -ENODEV; + + return 0; +} + +static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) +{ + deb("%s\n",__func__); + + if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) + return -ENODEV; + + return 0; +} + +static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(simple_tuner_attach, adap->fe, + &adap->dev->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3); + return 0; +} + +/* device-specific initialization */ +static struct m920x_inits megasky_rc_init [] = { + { M9206_RC_INIT2, 0xa8 }, + { M9206_RC_INIT1, 0x51 }, + { } /* terminating entry */ +}; + +static struct m920x_inits tvwalkertwin_rc_init [] = { + { M9206_RC_INIT2, 0x00 }, + { M9206_RC_INIT1, 0xef }, + { 0xff28, 0x00 }, + { 0xff23, 0x00 }, + { 0xff21, 0x30 }, + { } /* terminating entry */ +}; + +static struct m920x_inits pinnacle310e_init[] = { + /* without these the tuner don't work */ + { 0xff20, 0x9b }, + { 0xff22, 0x70 }, + + /* rc settings */ + { 0xff50, 0x80 }, + { M9206_RC_INIT1, 0x00 }, + { M9206_RC_INIT2, 0xff }, + { } /* terminating entry */ +}; + +/* ir keymaps */ +static struct rc_map_table rc_map_megasky_table[] = { + { 0x0012, KEY_POWER }, + { 0x001e, KEY_CYCLEWINDOWS }, /* min/max */ + { 0x0002, KEY_CHANNELUP }, + { 0x0005, KEY_CHANNELDOWN }, + { 0x0003, KEY_VOLUMEUP }, + { 0x0006, KEY_VOLUMEDOWN }, + { 0x0004, KEY_MUTE }, + { 0x0007, KEY_OK }, /* TS */ + { 0x0008, KEY_STOP }, + { 0x0009, KEY_MENU }, /* swap */ + { 0x000a, KEY_REWIND }, + { 0x001b, KEY_PAUSE }, + { 0x001f, KEY_FASTFORWARD }, + { 0x000c, KEY_RECORD }, + { 0x000d, KEY_CAMERA }, /* screenshot */ + { 0x000e, KEY_COFFEE }, /* "MTS" */ +}; + +static struct rc_map_table rc_map_tvwalkertwin_table[] = { + { 0x0001, KEY_ZOOM }, /* Full Screen */ + { 0x0002, KEY_CAMERA }, /* snapshot */ + { 0x0003, KEY_MUTE }, + { 0x0004, KEY_REWIND }, + { 0x0005, KEY_PLAYPAUSE }, /* Play/Pause */ + { 0x0006, KEY_FASTFORWARD }, + { 0x0007, KEY_RECORD }, + { 0x0008, KEY_STOP }, + { 0x0009, KEY_TIME }, /* Timeshift */ + { 0x000c, KEY_COFFEE }, /* Recall */ + { 0x000e, KEY_CHANNELUP }, + { 0x0012, KEY_POWER }, + { 0x0015, KEY_MENU }, /* source */ + { 0x0018, KEY_CYCLEWINDOWS }, /* TWIN PIP */ + { 0x001a, KEY_CHANNELDOWN }, + { 0x001b, KEY_VOLUMEDOWN }, + { 0x001e, KEY_VOLUMEUP }, +}; + +static struct rc_map_table rc_map_pinnacle310e_table[] = { + { 0x16, KEY_POWER }, + { 0x17, KEY_FAVORITES }, + { 0x0f, KEY_TEXT }, + { 0x48, KEY_PROGRAM }, /* preview */ + { 0x1c, KEY_EPG }, + { 0x04, KEY_LIST }, /* record list */ + { 0x03, KEY_1 }, + { 0x01, KEY_2 }, + { 0x06, KEY_3 }, + { 0x09, KEY_4 }, + { 0x1d, KEY_5 }, + { 0x1f, KEY_6 }, + { 0x0d, KEY_7 }, + { 0x19, KEY_8 }, + { 0x1b, KEY_9 }, + { 0x15, KEY_0 }, + { 0x0c, KEY_CANCEL }, + { 0x4a, KEY_CLEAR }, + { 0x13, KEY_BACK }, + { 0x00, KEY_TAB }, + { 0x4b, KEY_UP }, + { 0x4e, KEY_LEFT }, + { 0x52, KEY_RIGHT }, + { 0x51, KEY_DOWN }, + { 0x4f, KEY_ENTER }, /* could also be KEY_OK */ + { 0x1e, KEY_VOLUMEUP }, + { 0x0a, KEY_VOLUMEDOWN }, + { 0x05, KEY_CHANNELUP }, + { 0x02, KEY_CHANNELDOWN }, + { 0x11, KEY_RECORD }, + { 0x14, KEY_PLAY }, + { 0x4c, KEY_PAUSE }, + { 0x1a, KEY_STOP }, + { 0x40, KEY_REWIND }, + { 0x12, KEY_FASTFORWARD }, + { 0x41, KEY_PREVIOUSSONG }, /* Replay */ + { 0x42, KEY_NEXTSONG }, /* Skip */ + { 0x54, KEY_CAMERA }, /* Capture */ +/* { 0x50, KEY_SAP }, */ /* Sap */ + { 0x47, KEY_CYCLEWINDOWS }, /* Pip */ + { 0x4d, KEY_SCREEN }, /* FullScreen */ + { 0x08, KEY_SUBTITLE }, + { 0x0e, KEY_MUTE }, +/* { 0x49, KEY_LR }, */ /* L/R */ + { 0x07, KEY_SLEEP }, /* Hibernate */ + { 0x08, KEY_VIDEO }, /* A/V */ + { 0x0e, KEY_MENU }, /* Recall */ + { 0x45, KEY_ZOOMIN }, + { 0x46, KEY_ZOOMOUT }, + { 0x18, KEY_RED }, /* Red */ + { 0x53, KEY_GREEN }, /* Green */ + { 0x5e, KEY_YELLOW }, /* Yellow */ + { 0x5f, KEY_BLUE }, /* Blue */ +}; + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties megasky_properties; +static struct dvb_usb_device_properties digivox_mini_ii_properties; +static struct dvb_usb_device_properties tvwalkertwin_properties; +static struct dvb_usb_device_properties dposh_properties; +static struct dvb_usb_device_properties pinnacle_pctv310e_properties; + +static int m920x_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d = NULL; + int ret; + struct m920x_inits *rc_init_seq = NULL; + int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber; + + deb("Probing for m920x device at interface %d\n", bInterfaceNumber); + + if (bInterfaceNumber == 0) { + /* Single-tuner device, or first interface on + * multi-tuner device + */ + + ret = dvb_usb_device_init(intf, &megasky_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + rc_init_seq = megasky_rc_init; + goto found; + } + + ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + /* No remote control, so no rc_init_seq */ + goto found; + } + + /* This configures both tuners on the TV Walker Twin */ + ret = dvb_usb_device_init(intf, &tvwalkertwin_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + rc_init_seq = tvwalkertwin_rc_init; + goto found; + } + + ret = dvb_usb_device_init(intf, &dposh_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + /* Remote controller not supported yet. */ + goto found; + } + + ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties, + THIS_MODULE, &d, adapter_nr); + if (ret == 0) { + rc_init_seq = pinnacle310e_init; + goto found; + } + + return ret; + } else { + /* Another interface on a multi-tuner device */ + + /* The LifeView TV Walker Twin gets here, but struct + * tvwalkertwin_properties already configured both + * tuners, so there is nothing for us to do here + */ + } + + found: + if ((ret = m920x_init_ep(intf)) < 0) + return ret; + + if (d && (ret = m920x_init(d, rc_init_seq)) != 0) + return ret; + + return ret; +} + +static struct usb_device_id m920x_table [] = { + { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, + { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, + USB_PID_MSI_DIGI_VOX_MINI_II) }, + { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, + USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD) }, + { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, + USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) }, + { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) }, + { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, m920x_table); + +static struct dvb_usb_device_properties megasky_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-megasky-02.fw", + .download_firmware = m920x_firmware_download, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_megasky_table, + .rc_map_size = ARRAY_SIZE(rc_map_megasky_table), + .rc_query = m920x_rc_query, + }, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 1, + .adapter = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_mt352_frontend_attach, + .tuner_attach = m920x_qt1010_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + }}, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { "MSI Mega Sky 580 DVB-T USB2.0", + { &m920x_table[0], NULL }, + { NULL }, + } + } +}; + +static struct dvb_usb_device_properties digivox_mini_ii_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-digivox-02.fw", + .download_firmware = m920x_firmware_download, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 1, + .adapter = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_tda10046_08_frontend_attach, + .tuner_attach = m920x_tda8275_60_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 0x4000, + } + } + }, + }}, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { "MSI DIGI VOX mini II DVB-T USB2.0", + { &m920x_table[1], NULL }, + { NULL }, + }, + } +}; + +/* LifeView TV Walker Twin support by Nick Andrew + * + * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A + * TDA10046 #0 is located at i2c address 0x08 + * TDA10046 #1 is located at i2c address 0x0b + * TDA8275A #0 is located at i2c address 0x60 + * TDA8275A #1 is located at i2c address 0x61 + */ +static struct dvb_usb_device_properties tvwalkertwin_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-tvwalkert.fw", + .download_firmware = m920x_firmware_download, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_tvwalkertwin_table, + .rc_map_size = ARRAY_SIZE(rc_map_tvwalkertwin_table), + .rc_query = m920x_rc_query, + }, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 2, + .adapter = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_tda10046_08_frontend_attach, + .tuner_attach = m920x_tda8275_60_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 512, + } + } + }},{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_tda10046_0b_frontend_attach, + .tuner_attach = m920x_tda8275_61_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + }}, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { .name = "LifeView TV Walker Twin DVB-T USB2.0", + .cold_ids = { &m920x_table[2], NULL }, + .warm_ids = { &m920x_table[3], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties dposh_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dposh-01.fw", + .download_firmware = m920x_firmware_download, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 1, + .adapter = {{ + /* Hardware pid filters don't work with this device/firmware */ + + .frontend_attach = m920x_mt352_frontend_attach, + .tuner_attach = m920x_qt1010_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + }}, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { .name = "Dposh DVB-T USB2.0", + .cold_ids = { &m920x_table[4], NULL }, + .warm_ids = { &m920x_table[5], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties pinnacle_pctv310e_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = NULL, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_pinnacle310e_table, + .rc_map_size = ARRAY_SIZE(rc_map_pinnacle310e_table), + .rc_query = m920x_rc_query, + }, + + .size_of_priv = sizeof(struct m920x_state), + + .identify_state = m920x_identify_state, + .num_adapters = 1, + .adapter = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m920x_pid_filter, + .pid_filter_ctrl = m920x_pid_filter_ctrl, + + .frontend_attach = m920x_mt352_frontend_attach, + .tuner_attach = m920x_fmd1216me_tuner_attach, + + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x84, + .u = { + .isoc = { + .framesperurb = 128, + .framesize = 564, + .interval = 1, + } + } + }, + } }, + .i2c_algo = &m920x_i2c_algo, + + .num_device_descs = 1, + .devices = { + { "Pinnacle PCTV 310e", + { &m920x_table[6], NULL }, + { NULL }, + } + } +}; + +static struct usb_driver m920x_driver = { + .name = "dvb_usb_m920x", + .probe = m920x_probe, + .disconnect = dvb_usb_device_exit, + .id_table = m920x_table, +}; + +/* module stuff */ +static int __init m920x_module_init(void) +{ + int ret; + + if ((ret = usb_register(&m920x_driver))) { + err("usb_register failed. Error number %d", ret); + return ret; + } + + return 0; +} + +static void __exit m920x_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&m920x_driver); +} + +module_init (m920x_module_init); +module_exit (m920x_module_exit); + +MODULE_AUTHOR("Aapo Tahkola "); +MODULE_DESCRIPTION("DVB Driver for ULI M920x"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/m920x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/m920x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/m920x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/m920x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,77 @@ +#ifndef _DVB_USB_M920X_H_ +#define _DVB_USB_M920X_H_ + +#define DVB_USB_LOG_PREFIX "m920x" +#include "dvb-usb.h" + +#define deb(args...) dprintk(dvb_usb_m920x_debug,0x01,args) + +#define M9206_CORE 0x22 +#define M9206_RC_STATE 0xff51 +#define M9206_RC_KEY 0xff52 +#define M9206_RC_INIT1 0xff54 +#define M9206_RC_INIT2 0xff55 +#define M9206_FW_GO 0xff69 + +#define M9206_I2C 0x23 +#define M9206_FILTER 0x25 +#define M9206_FW 0x30 + +#define M9206_MAX_FILTERS 8 +#define M9206_MAX_ADAPTERS 4 + +/* +sequences found in logs: +[index value] +0x80 write addr +(0x00 out byte)* +0x40 out byte + +0x80 write addr +(0x00 out byte)* +0x80 read addr +(0x21 in byte)* +0x60 in byte + +this sequence works: +0x80 read addr +(0x21 in byte)* +0x60 in byte + +Guess at API of the I2C function: +I2C operation is done one byte at a time with USB control messages. The +index the messages is sent to is made up of a set of flags that control +the I2C bus state: +0x80: Send START condition. After a START condition, one would normally + always send the 7-bit slave I2C address as the 7 MSB, followed by + the read/write bit as the LSB. +0x40: Send STOP condition. This should be set on the last byte of an + I2C transaction. +0x20: Read a byte from the slave. As opposed to writing a byte to the + slave. The slave will normally not produce any data unless you + set the R/W bit to 1 when sending the slave's address after the + START condition. +0x01: Respond with ACK, as opposed to a NACK. For a multi-byte read, + the master should send an ACK, that is pull SDA low during the 9th + clock cycle, after every byte but the last. This flags only makes + sense when bit 0x20 is set, indicating a read. + +What any other bits might mean, or how to get the slave's ACK/NACK +response to a write, is unknown. +*/ + +struct m920x_state { + u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS]; + int filtering_enabled[M9206_MAX_ADAPTERS]; + int rep_count; +}; + +/* Initialisation data for the m920x + */ + +struct m920x_inits { + u16 address; + u8 data; +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,100 @@ +dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o +obj-$(CONFIG_DVB_USB) += dvb-usb.o + +dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o +obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o + +dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o +obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o + +dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o +obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o + +dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o +obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o + +dvb-usb-dibusb-common-objs = dibusb-common.o + +dvb-usb-a800-objs = a800.o +obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o + +dvb-usb-dibusb-mb-objs = dibusb-mb.o +obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o + +dvb-usb-dibusb-mc-objs = dibusb-mc.o +obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o + +dvb-usb-nova-t-usb2-objs = nova-t-usb2.o +obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o + +dvb-usb-umt-010-objs = umt-010.o +obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o + +dvb-usb-m920x-objs = m920x.o +obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o + +dvb-usb-gl861-objs = gl861.o +obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o + +dvb-usb-au6610-objs = au6610.o +obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o + +dvb-usb-digitv-objs = digitv.o +obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o + +dvb-usb-cxusb-objs = cxusb.o +obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o + +dvb-usb-ttusb2-objs = ttusb2.o +obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o + +dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o +obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o + +dvb-usb-opera-objs = opera1.o +obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o + + +dvb-usb-af9005-objs = af9005.o af9005-fe.o +obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o + +dvb-usb-af9005-remote-objs = af9005-remote.o +obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o + +dvb-usb-anysee-objs = anysee.o +obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o + +dvb-usb-dw2102-objs = dw2102.o +obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o + +dvb-usb-dtv5100-objs = dtv5100.o +obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o + +dvb-usb-af9015-objs = af9015.o +obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o + +dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o +obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o + +dvb-usb-ce6230-objs = ce6230.o +obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o + +dvb-usb-friio-objs = friio.o friio-fe.o +obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o + +dvb-usb-ec168-objs = ec168.o +obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o + +dvb-usb-az6027-objs = az6027.o +obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o + +dvb-usb-lmedm04-objs = lmedm04.o +obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o + +dvb-usb-technisat-usb2-objs = technisat-usb2.o +obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +# due to tuner-xc3028 +EXTRA_CFLAGS += -Idrivers/media/common/tuners + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/nova-t-usb2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/nova-t-usb2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/nova-t-usb2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/nova-t-usb2.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,249 @@ +/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2 + * DVB-T receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_rc(args...) dprintk(debug,0x01,args) +#define deb_ee(args...) dprintk(debug,0x02,args) + +/* Hauppauge NOVA-T USB2 keys */ +static struct rc_map_table rc_map_haupp_table[] = { + { 0x1e00, KEY_0 }, + { 0x1e01, KEY_1 }, + { 0x1e02, KEY_2 }, + { 0x1e03, KEY_3 }, + { 0x1e04, KEY_4 }, + { 0x1e05, KEY_5 }, + { 0x1e06, KEY_6 }, + { 0x1e07, KEY_7 }, + { 0x1e08, KEY_8 }, + { 0x1e09, KEY_9 }, + { 0x1e0a, KEY_KPASTERISK }, + { 0x1e0b, KEY_RED }, + { 0x1e0c, KEY_RADIO }, + { 0x1e0d, KEY_MENU }, + { 0x1e0e, KEY_GRAVE }, /* # */ + { 0x1e0f, KEY_MUTE }, + { 0x1e10, KEY_VOLUMEUP }, + { 0x1e11, KEY_VOLUMEDOWN }, + { 0x1e12, KEY_CHANNEL }, + { 0x1e14, KEY_UP }, + { 0x1e15, KEY_DOWN }, + { 0x1e16, KEY_LEFT }, + { 0x1e17, KEY_RIGHT }, + { 0x1e18, KEY_VIDEO }, + { 0x1e19, KEY_AUDIO }, + { 0x1e1a, KEY_IMAGES }, + { 0x1e1b, KEY_EPG }, + { 0x1e1c, KEY_TV }, + { 0x1e1e, KEY_NEXT }, + { 0x1e1f, KEY_BACK }, + { 0x1e20, KEY_CHANNELUP }, + { 0x1e21, KEY_CHANNELDOWN }, + { 0x1e24, KEY_LAST }, /* Skip backwards */ + { 0x1e25, KEY_OK }, + { 0x1e29, KEY_BLUE}, + { 0x1e2e, KEY_GREEN }, + { 0x1e30, KEY_PAUSE }, + { 0x1e32, KEY_REWIND }, + { 0x1e34, KEY_FASTFORWARD }, + { 0x1e35, KEY_PLAY }, + { 0x1e36, KEY_STOP }, + { 0x1e37, KEY_RECORD }, + { 0x1e38, KEY_YELLOW }, + { 0x1e3b, KEY_GOTO }, + { 0x1e3d, KEY_POWER }, +}; + +/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key + * is delivered. No workaround yet, maybe a new firmware. + */ +static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom; + u16 raw; + int i; + struct dibusb_device_state *st = d->priv; + + dvb_usb_generic_rw(d,cmd,2,key,5,0); + + *state = REMOTE_NO_KEY_PRESSED; + switch (key[0]) { + case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED: + raw = ((key[1] << 8) | key[2]) >> 3; + toggle = !!(raw & 0x800); + data = raw & 0x3f; + custom = (raw >> 6) & 0x1f; + + deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle); + + for (i = 0; i < ARRAY_SIZE(rc_map_haupp_table); i++) { + if (rc5_data(&rc_map_haupp_table[i]) == data && + rc5_custom(&rc_map_haupp_table[i]) == custom) { + + deb_rc("c: %x, d: %x\n", rc5_data(&rc_map_haupp_table[i]), + rc5_custom(&rc_map_haupp_table[i])); + + *event = rc_map_haupp_table[i].keycode; + *state = REMOTE_KEY_PRESSED; + if (st->old_toggle == toggle) { + if (st->last_repeat_count++ < 2) + *state = REMOTE_NO_KEY_PRESSED; + } else { + st->last_repeat_count = 0; + st->old_toggle = toggle; + } + break; + } + } + + break; + case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY: + default: + break; + } + + return 0; +} + +static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) +{ + int i; + u8 b; + + mac[0] = 0x00; + mac[1] = 0x0d; + mac[2] = 0xfe; + + /* this is a complete guess, but works for my box */ + for (i = 136; i < 139; i++) { + dibusb_read_eeprom_byte(d,i, &b); + + mac[5 - (i - 136)] = b; + } + + return 0; +} + +/* USB Driver stuff */ +static struct dvb_usb_device_properties nova_t_properties; + +static int nova_t_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &nova_t_properties, + THIS_MODULE, NULL, adapter_nr); +} + +/* do not change the order of the ID table */ +static struct usb_device_id nova_t_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, nova_t_table); + +static struct dvb_usb_device_properties nova_t_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-nova-t-usb2-02.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mc_frontend_attach, + .tuner_attach = dibusb_dib3000mc_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .size_of_priv = sizeof(struct dibusb_device_state), + + .power_ctrl = dibusb2_0_power_ctrl, + .read_mac_address = nova_t_read_mac_address, + + .rc.legacy = { + .rc_interval = 100, + .rc_map_table = rc_map_haupp_table, + .rc_map_size = ARRAY_SIZE(rc_map_haupp_table), + .rc_query = nova_t_rc_query, + }, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Hauppauge WinTV-NOVA-T usb2", + { &nova_t_table[0], NULL }, + { &nova_t_table[1], NULL }, + }, + { NULL }, + } +}; + +static struct usb_driver nova_t_driver = { + .name = "dvb_usb_nova_t_usb2", + .probe = nova_t_probe, + .disconnect = dvb_usb_device_exit, + .id_table = nova_t_table, +}; + +/* module stuff */ +static int __init nova_t_module_init(void) +{ + int result; + if ((result = usb_register(&nova_t_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit nova_t_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&nova_t_driver); +} + +module_init (nova_t_module_init); +module_exit (nova_t_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/opera1.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/opera1.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/opera1.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/opera1.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,594 @@ +/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card +* +* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org) +* Copyright (C) 2006 Marco Gittler (g.marco@freenet.de) +* +* 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, version 2. +* +* see Documentation/dvb/README.dvb-usb for more information +*/ + +#define DVB_USB_LOG_PREFIX "opera" + +#include "dvb-usb.h" +#include "stv0299.h" + +#define OPERA_READ_MSG 0 +#define OPERA_WRITE_MSG 1 +#define OPERA_I2C_TUNER 0xd1 + +#define READ_FX2_REG_REQ 0xba +#define READ_MAC_ADDR 0x08 +#define OPERA_WRITE_FX2 0xbb +#define OPERA_TUNER_REQ 0xb1 +#define REG_1F_SYMBOLRATE_BYTE0 0x1f +#define REG_20_SYMBOLRATE_BYTE1 0x20 +#define REG_21_SYMBOLRATE_BYTE2 0x21 + +#define ADDR_B600_VOLTAGE_13V (0x02) +#define ADDR_B601_VOLTAGE_18V (0x03) +#define ADDR_B1A6_STREAM_CTRL (0x04) +#define ADDR_B880_READ_REMOTE (0x05) + +struct opera1_state { + u32 last_key_pressed; +}; +struct rc_map_opera_table { + u32 keycode; + u32 event; +}; + +static int dvb_usb_opera1_debug; +module_param_named(debug, dvb_usb_opera1_debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." + DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + + +static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value, + u8 * data, u16 len, int flags) +{ + int ret; + u8 tmp; + u8 *buf; + unsigned int pipe = (flags == OPERA_READ_MSG) ? + usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0); + u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; + + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (flags == OPERA_WRITE_MSG) + memcpy(buf, data, len); + ret = usb_control_msg(dev, pipe, request, + request_type | USB_TYPE_VENDOR, value, 0x0, + buf, len, 2000); + + if (request == OPERA_TUNER_REQ) { + tmp = buf[0]; + if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR, + 0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) { + ret = 0; + goto out; + } + buf[0] = tmp; + } + if (flags == OPERA_READ_MSG) + memcpy(data, buf, len); +out: + kfree(buf); + return ret; +} + +/* I2C */ + +static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr, + u8 * buf, u16 len) +{ + int ret = 0; + u8 request; + u16 value; + + if (!dev) { + info("no usb_device"); + return -EINVAL; + } + if (mutex_lock_interruptible(&dev->usb_mutex) < 0) + return -EAGAIN; + + switch (addr>>1){ + case ADDR_B600_VOLTAGE_13V: + request=0xb6; + value=0x00; + break; + case ADDR_B601_VOLTAGE_18V: + request=0xb6; + value=0x01; + break; + case ADDR_B1A6_STREAM_CTRL: + request=0xb1; + value=0xa6; + break; + case ADDR_B880_READ_REMOTE: + request=0xb8; + value=0x80; + break; + default: + request=0xb1; + value=addr; + } + ret = opera1_xilinx_rw(dev->udev, request, + value, buf, len, + addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG); + + mutex_unlock(&dev->usb_mutex); + return ret; +} + +static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i = 0, tmp = 0; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if ((tmp = opera1_usb_i2c_msgxfer(d, + (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), + msg[i].buf, + msg[i].len + )) != msg[i].len) { + break; + } + if (dvb_usb_opera1_debug & 0x10) + info("sending i2c mesage %d %d", tmp, msg[i].len); + } + mutex_unlock(&d->i2c_mutex); + return num; +} + +static u32 opera1_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm opera1_i2c_algo = { + .master_xfer = opera1_i2c_xfer, + .functionality = opera1_i2c_func, +}; + +static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + static u8 command_13v[1]={0x00}; + static u8 command_18v[1]={0x01}; + struct i2c_msg msg[] = { + {.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1}, + }; + struct dvb_usb_adapter *udev_adap = + (struct dvb_usb_adapter *)(fe->dvb->priv); + if (voltage == SEC_VOLTAGE_18) { + msg[0].addr = ADDR_B601_VOLTAGE_18V; + msg[0].buf = command_18v; + } + i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1); + return 0; +} + +static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, + u32 ratio) +{ + stv0299_writereg(fe, 0x13, 0x98); + stv0299_writereg(fe, 0x14, 0x95); + stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff); + stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff); + stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0); + return 0; + +} +static u8 opera1_inittab[] = { + 0x00, 0xa1, + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, + 0x05, 0x05, + 0x06, 0x02, + 0x07, 0x00, + 0x0b, 0x00, + 0x0c, 0x01, + 0x0d, 0x81, + 0x0e, 0x44, + 0x0f, 0x19, + 0x10, 0x3f, + 0x11, 0x84, + 0x12, 0xda, + 0x13, 0x98, + 0x14, 0x95, + 0x15, 0xc9, + 0x16, 0xeb, + 0x17, 0x00, + 0x18, 0x19, + 0x19, 0x8b, + 0x1a, 0x00, + 0x1b, 0x82, + 0x1c, 0x7f, + 0x1d, 0x00, + 0x1e, 0x00, + REG_1F_SYMBOLRATE_BYTE0, 0x06, + REG_20_SYMBOLRATE_BYTE1, 0x50, + REG_21_SYMBOLRATE_BYTE2, 0x10, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x37, + 0x25, 0xbc, + 0x26, 0x00, + 0x27, 0x00, + 0x28, 0x00, + 0x29, 0x1e, + 0x2a, 0x14, + 0x2b, 0x1f, + 0x2c, 0x09, + 0x2d, 0x0a, + 0x2e, 0x00, + 0x2f, 0x00, + 0x30, 0x00, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x13, + 0xff, 0xff, +}; + +static struct stv0299_config opera1_stv0299_config = { + .demod_address = 0xd0>>1, + .min_delay_ms = 100, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_0, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .inittab = opera1_inittab, + .set_symbol_rate = opera1_stv0299_set_symbol_rate, +}; + +static int opera1_frontend_attach(struct dvb_usb_adapter *d) +{ + if ((d->fe = + dvb_attach(stv0299_attach, &opera1_stv0299_config, + &d->dev->i2c_adap)) != NULL) { + d->fe->ops.set_voltage = opera1_set_voltage; + return 0; + } + info("not attached stv0299"); + return -EIO; +} + +static int opera1_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach( + dvb_pll_attach, adap->fe, 0xc0>>1, + &adap->dev->i2c_adap, DVB_PLL_OPERA1 + ); + return 0; +} + +static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 val = onoff ? 0x01 : 0x00; + + if (dvb_usb_opera1_debug) + info("power %s", onoff ? "on" : "off"); + return opera1_xilinx_rw(d->udev, 0xb7, val, + &val, 1, OPERA_WRITE_MSG); +} + +static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + static u8 buf_start[2] = { 0xff, 0x03 }; + static u8 buf_stop[2] = { 0xff, 0x00 }; + struct i2c_msg start_tuner[] = { + {.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2}, + }; + if (dvb_usb_opera1_debug) + info("streaming %s", onoff ? "on" : "off"); + i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1); + return 0; +} + +static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + u8 b_pid[3]; + struct i2c_msg msg[] = { + {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, + }; + if (dvb_usb_opera1_debug) + info("pidfilter index: %d pid: %d %s", index, pid, + onoff ? "on" : "off"); + b_pid[0] = (2 * index) + 4; + b_pid[1] = onoff ? (pid & 0xff) : (0x00); + b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00); + i2c_transfer(&adap->dev->i2c_adap, msg, 1); + return 0; +} + +static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) +{ + int u = 0x04; + u8 b_pid[3]; + struct i2c_msg msg[] = { + {.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3}, + }; + if (dvb_usb_opera1_debug) + info("%s hw-pidfilter", onoff ? "enable" : "disable"); + for (; u < 0x7e; u += 2) { + b_pid[0] = u; + b_pid[1] = 0; + b_pid[2] = 0x80; + i2c_transfer(&adap->dev->i2c_adap, msg, 1); + } + return 0; +} + +static struct rc_map_table rc_map_opera1_table[] = { + {0x5fa0, KEY_1}, + {0x51af, KEY_2}, + {0x5da2, KEY_3}, + {0x41be, KEY_4}, + {0x0bf5, KEY_5}, + {0x43bd, KEY_6}, + {0x47b8, KEY_7}, + {0x49b6, KEY_8}, + {0x05fa, KEY_9}, + {0x45ba, KEY_0}, + {0x09f6, KEY_CHANNELUP}, /*chanup */ + {0x1be5, KEY_CHANNELDOWN}, /*chandown */ + {0x5da3, KEY_VOLUMEDOWN}, /*voldown */ + {0x5fa1, KEY_VOLUMEUP}, /*volup */ + {0x07f8, KEY_SPACE}, /*tab */ + {0x1fe1, KEY_OK}, /*play ok */ + {0x1be4, KEY_ZOOM}, /*zoom */ + {0x59a6, KEY_MUTE}, /*mute */ + {0x5ba5, KEY_RADIO}, /*tv/f */ + {0x19e7, KEY_RECORD}, /*rec */ + {0x01fe, KEY_STOP}, /*Stop */ + {0x03fd, KEY_PAUSE}, /*pause */ + {0x03fc, KEY_SCREEN}, /*<- -> */ + {0x07f9, KEY_CAMERA}, /*capture */ + {0x47b9, KEY_ESC}, /*exit */ + {0x43bc, KEY_POWER2}, /*power */ +}; + +static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state) +{ + struct opera1_state *opst = dev->priv; + u8 rcbuffer[32]; + const u16 startmarker1 = 0x10ed; + const u16 startmarker2 = 0x11ec; + struct i2c_msg read_remote[] = { + {.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32}, + }; + int i = 0; + u32 send_key = 0; + + if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) { + for (i = 0; i < 32; i++) { + if (rcbuffer[i]) + send_key |= 1; + if (i < 31) + send_key = send_key << 1; + } + if (send_key & 0x8000) + send_key = (send_key << 1) | (send_key >> 15 & 0x01); + + if (send_key == 0xffff && opst->last_key_pressed != 0) { + *state = REMOTE_KEY_REPEAT; + *event = opst->last_key_pressed; + return 0; + } + for (; send_key != 0;) { + if (send_key >> 16 == startmarker2) { + break; + } else if (send_key >> 16 == startmarker1) { + send_key = + (send_key & 0xfffeffff) | (startmarker1 << 16); + break; + } else + send_key >>= 1; + } + + if (send_key == 0) + return 0; + + send_key = (send_key & 0xffff) | 0x0100; + + for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) { + if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) { + *state = REMOTE_KEY_PRESSED; + *event = rc_map_opera1_table[i].keycode; + opst->last_key_pressed = + rc_map_opera1_table[i].keycode; + break; + } + opst->last_key_pressed = 0; + } + } else + *state = REMOTE_NO_KEY_PRESSED; + return 0; +} + +static struct usb_device_id opera1_table[] = { + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)}, + {USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, opera1_table); + +static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + u8 command[] = { READ_MAC_ADDR }; + opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG); + opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG); + return 0; +} +static int opera1_xilinx_load_firmware(struct usb_device *dev, + const char *filename) +{ + const struct firmware *fw = NULL; + u8 *b, *p; + int ret = 0, i,fpgasize=40; + u8 testval; + info("start downloading fpga firmware %s",filename); + + if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems.", + filename); + return ret; + } else { + p = kmalloc(fw->size, GFP_KERNEL); + opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG); + if (p != NULL && testval != 0x67) { + + u8 reset = 0, fpga_command = 0; + memcpy(p, fw->data, fw->size); + /* clear fpga ? */ + opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1, + OPERA_WRITE_MSG); + for (i = 0; i < fw->size;) { + if ( (fw->size - i) size-i; + } + b = (u8 *) p + i; + if (opera1_xilinx_rw + (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize, + OPERA_WRITE_MSG) != fpgasize + ) { + err("error while transferring firmware"); + ret = -EINVAL; + break; + } + i = i + fpgasize; + } + /* restart the CPU */ + if (ret || opera1_xilinx_rw + (dev, 0xa0, 0xe600, &reset, 1, + OPERA_WRITE_MSG) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + } + } + kfree(p); + release_firmware(fw); + return ret; +} + +static struct dvb_usb_device_properties opera1_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-opera-01.fw", + .size_of_priv = sizeof(struct opera1_state), + + .power_ctrl = opera1_power_ctrl, + .i2c_algo = &opera1_i2c_algo, + + .rc.legacy = { + .rc_map_table = rc_map_opera1_table, + .rc_map_size = ARRAY_SIZE(rc_map_opera1_table), + .rc_interval = 200, + .rc_query = opera1_rc_query, + }, + .read_mac_address = opera1_read_mac_address, + .generic_bulk_ctrl_endpoint = 0x00, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .adapter = { + { + .frontend_attach = opera1_frontend_attach, + .streaming_ctrl = opera1_streaming_ctrl, + .tuner_attach = opera1_tuner_attach, + .caps = + DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter = opera1_pid_filter, + .pid_filter_ctrl = opera1_pid_filter_control, + .pid_filter_count = 252, + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .num_device_descs = 1, + .devices = { + {"Opera1 DVB-S USB2.0", + {&opera1_table[0], NULL}, + {&opera1_table[1], NULL}, + }, + } +}; + +static int opera1_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + + if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM && + udev->descriptor.idVendor == USB_VID_OPERA1 && + opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0 + ) { + return -EINVAL; + } + + if (0 != dvb_usb_device_init(intf, &opera1_properties, + THIS_MODULE, NULL, adapter_nr)) + return -EINVAL; + return 0; +} + +static struct usb_driver opera1_driver = { + .name = "opera1", + .probe = opera1_probe, + .disconnect = dvb_usb_device_exit, + .id_table = opera1_table, +}; + +static int __init opera1_module_init(void) +{ + int result = 0; + if ((result = usb_register(&opera1_driver))) { + err("usb_register failed. Error number %d", result); + } + return result; +} + +static void __exit opera1_module_exit(void) +{ + usb_deregister(&opera1_driver); +} + +module_init(opera1_module_init); +module_exit(opera1_module_exit); + +MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org"); +MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de"); +MODULE_DESCRIPTION("Driver for Opera1 DVB-S device"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/technisat-usb2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/technisat-usb2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/technisat-usb2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/technisat-usb2.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,804 @@ +/* + * Linux driver for Technisat DVB-S/S2 USB 2.0 device + * + * Copyright (C) 2010 Patrick Boettcher, + * Kernel Labs Inc. PO Box 745, St James, NY 11780 + * + * Development was sponsored by Technisat Digital UK Limited, whose + * registered office is Witan Gate House 500 - 600 Witan Gate West, + * Milton Keynes, MK9 1SH + * + * 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, or (at your option) any later version. + * + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND + * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. NEITHER THE COPYRIGHT HOLDER + * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the + * GNU General Public License for more details. + */ + +#define DVB_USB_LOG_PREFIX "technisat-usb2" +#include "dvb-usb.h" + +#include "stv6110x.h" +#include "stv090x.h" + +/* module parameters */ +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \ + DVB_USB_DEBUG_STATUS); + +/* disables all LED control command and + * also does not start the signal polling thread */ +static int disable_led_control; +module_param(disable_led_control, int, 0444); +MODULE_PARM_DESC(disable_led_control, + "disable LED control of the device " + "(default: 0 - LED control is active)."); + +/* device private data */ +struct technisat_usb2_state { + struct dvb_usb_device *dev; + struct delayed_work green_led_work; + u8 power_state; + + u16 last_scan_code; +}; + +/* debug print helpers */ +#define deb_info(args...) dprintk(debug, 0x01, args) +#define deb_eeprom(args...) dprintk(debug, 0x02, args) +#define deb_i2c(args...) dprintk(debug, 0x04, args) +#define deb_rc(args...) dprintk(debug, 0x08, args) + +/* vendor requests */ +#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3 +#define SET_FRONT_END_RESET_VENDOR_REQUEST 0xB4 +#define GET_VERSION_INFO_VENDOR_REQUEST 0xB5 +#define SET_GREEN_LED_VENDOR_REQUEST 0xB6 +#define SET_RED_LED_VENDOR_REQUEST 0xB7 +#define GET_IR_DATA_VENDOR_REQUEST 0xB8 +#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST 0xB9 +#define SET_USB_REENUMERATION 0xBA + +/* i2c-access methods */ +#define I2C_SPEED_100KHZ_BIT 0x40 + +#define I2C_STATUS_NAK 7 +#define I2C_STATUS_OK 8 + +static int technisat_usb2_i2c_access(struct usb_device *udev, + u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +{ + u8 b[64]; + int ret, actual_length; + + deb_i2c("i2c-access: %02x, tx: ", device_addr); + debug_dump(tx, txlen, deb_i2c); + deb_i2c(" "); + + if (txlen > 62) { + err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)", + device_addr); + txlen = 62; + } + if (rxlen > 62) { + err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)", + device_addr); + txlen = 62; + } + + b[0] = I2C_SPEED_100KHZ_BIT; + b[1] = device_addr << 1; + + if (rx != NULL) { + b[0] |= rxlen; + b[1] |= 1; + } + + memcpy(&b[2], tx, txlen); + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x01), + b, 2 + txlen, + NULL, 1000); + + if (ret < 0) { + err("i2c-error: out failed %02x = %d", device_addr, ret); + return -ENODEV; + } + + ret = usb_bulk_msg(udev, + usb_rcvbulkpipe(udev, 0x01), + b, 64, &actual_length, 1000); + if (ret < 0) { + err("i2c-error: in failed %02x = %d", device_addr, ret); + return -ENODEV; + } + + if (b[0] != I2C_STATUS_OK) { + err("i2c-error: %02x = %d", device_addr, b[0]); + /* handle tuner-i2c-nak */ + if (!(b[0] == I2C_STATUS_NAK && + device_addr == 0x60 + /* && device_is_technisat_usb2 */)) + return -ENODEV; + } + + deb_i2c("status: %d, ", b[0]); + + if (rx != NULL) { + memcpy(rx, &b[2], rxlen); + + deb_i2c("rx (%d): ", rxlen); + debug_dump(rx, rxlen, deb_i2c); + } + + deb_i2c("\n"); + + return 0; +} + +static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + int ret = 0, i; + struct dvb_usb_device *d = i2c_get_adapdata(adap); + + /* Ensure nobody else hits the i2c bus while we're sending our + sequence of messages, (such as the remote control thread) */ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if (i+1 < num && msg[i+1].flags & I2C_M_RD) { + ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr, + msg[i].buf, msg[i].len, + msg[i+1].buf, msg[i+1].len); + if (ret != 0) + break; + i++; + } else { + ret = technisat_usb2_i2c_access(d->udev, msg[i].addr, + msg[i].buf, msg[i].len, + NULL, 0); + if (ret != 0) + break; + } + } + + if (ret == 0) + ret = i; + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm technisat_usb2_i2c_algo = { + .master_xfer = technisat_usb2_i2c_xfer, + .functionality = technisat_usb2_i2c_func, +}; + +#if 0 +static void technisat_usb2_frontend_reset(struct usb_device *udev) +{ + usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SET_FRONT_END_RESET_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 10, 0, + NULL, 0, 500); +} +#endif + +/* LED control */ +enum technisat_usb2_led_state { + LED_OFF, + LED_BLINK, + LED_ON, + LED_UNDEFINED +}; + +static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state) +{ + int ret; + + u8 led[8] = { + red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, + 0 + }; + + if (disable_led_control && state != LED_OFF) + return 0; + + switch (state) { + case LED_ON: + led[1] = 0x82; + break; + case LED_BLINK: + led[1] = 0x82; + if (red) { + led[2] = 0x02; + led[3] = 10; + led[4] = 10; + } else { + led[2] = 0xff; + led[3] = 50; + led[4] = 50; + } + led[5] = 1; + break; + + default: + case LED_OFF: + led[1] = 0x80; + break; + } + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, + led, sizeof(led), 500); + + mutex_unlock(&d->i2c_mutex); + return ret; +} + +static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green) +{ + int ret; + u8 b = 0; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + SET_LED_TIMER_DIVIDER_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + (red << 8) | green, 0, + &b, 1, 500); + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static void technisat_usb2_green_led_control(struct work_struct *work) +{ + struct technisat_usb2_state *state = + container_of(work, struct technisat_usb2_state, green_led_work.work); + struct dvb_frontend *fe = state->dev->adapter[0].fe; + + if (state->power_state == 0) + goto schedule; + + if (fe != NULL) { + enum fe_status status; + + if (fe->ops.read_status(fe, &status) != 0) + goto schedule; + + if (status & FE_HAS_LOCK) { + u32 ber; + + if (fe->ops.read_ber(fe, &ber) != 0) + goto schedule; + + if (ber > 1000) + technisat_usb2_set_led(state->dev, 0, LED_BLINK); + else + technisat_usb2_set_led(state->dev, 0, LED_ON); + } else + technisat_usb2_set_led(state->dev, 0, LED_OFF); + } + +schedule: + schedule_delayed_work(&state->green_led_work, + msecs_to_jiffies(500)); +} + +/* method to find out whether the firmware has to be downloaded or not */ +static int technisat_usb2_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + int ret; + u8 version[3]; + + /* first select the interface */ + if (usb_set_interface(udev, 0, 1) != 0) + err("could not set alternate setting to 0"); + else + info("set alternate setting"); + + *cold = 0; /* by default do not download a firmware - just in case something is wrong */ + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + GET_VERSION_INFO_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_IN, + 0, 0, + version, sizeof(version), 500); + + if (ret < 0) + *cold = 1; + else { + info("firmware version: %d.%d", version[1], version[2]); + *cold = 0; + } + + return 0; +} + +/* power control */ +static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level) +{ + struct technisat_usb2_state *state = d->priv; + + state->power_state = level; + + if (disable_led_control) + return 0; + + /* green led is turned off in any case - will be turned on when tuning */ + technisat_usb2_set_led(d, 0, LED_OFF); + /* red led is turned on all the time */ + technisat_usb2_set_led(d, 1, LED_ON); + return 0; +} + +/* mac address reading - from the eeprom */ +#if 0 +static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d) +{ + u8 reg; + u8 b[16]; + int i, j; + + /* full EEPROM dump */ + for (j = 0; j < 256 * 4; j += 16) { + reg = j; + if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, ®, 1, b, 16) != 0) + break; + + deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg); + for (i = 0; i < 16; i++) + deb_eeprom("%02x ", b[i]); + deb_eeprom("\n"); + } +} +#endif + +static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length) +{ + u8 lrc = 0; + while (--length) + lrc ^= *b++; + return lrc; +} + +static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d, + u16 offset, u8 *b, u16 length, u8 tries) +{ + u8 bo = offset & 0xff; + struct i2c_msg msg[] = { + { + .addr = 0x50 | ((offset >> 8) & 0x3), + .buf = &bo, + .len = 1 + }, { + .addr = 0x50 | ((offset >> 8) & 0x3), + .flags = I2C_M_RD, + .buf = b, + .len = length + } + }; + + while (tries--) { + int status; + + if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) + break; + + status = + technisat_usb2_calc_lrc(b, length - 1) == b[length - 1]; + + if (status) + return 0; + } + + return -EREMOTEIO; +} + +#define EEPROM_MAC_START 0x3f8 +#define EEPROM_MAC_TOTAL 8 +static int technisat_usb2_read_mac_address(struct dvb_usb_device *d, + u8 mac[]) +{ + u8 buf[EEPROM_MAC_TOTAL]; + + if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START, + buf, EEPROM_MAC_TOTAL, 4) != 0) + return -ENODEV; + + memcpy(mac, buf, 6); + return 0; +} + +/* frontend attach */ +static int technisat_usb2_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + int i; + u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */ + + gpio[2] = 1; /* high - voltage ? */ + + switch (voltage) { + case SEC_VOLTAGE_13: + gpio[0] = 1; + break; + case SEC_VOLTAGE_18: + gpio[0] = 1; + gpio[1] = 1; + break; + default: + case SEC_VOLTAGE_OFF: + break; + } + + for (i = 0; i < 3; i++) + if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0) + return -EREMOTEIO; + return 0; +} + +static struct stv090x_config technisat_usb2_stv090x_config = { + .device = STV0903, + .demod_mode = STV090x_SINGLE, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 8000000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_DVBCI, + .ts1_clk = 13400000, + .ts1_tei = 1, + + .repeater_level = STV090x_RPTLEVEL_64, + + .tuner_bbgain = 6, +}; + +static struct stv6110x_config technisat_usb2_stv6110x_config = { + .addr = 0x60, + .refclk = 16000000, + .clk_div = 2, +}; + +static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) +{ + struct usb_device *udev = a->dev->udev; + int ret; + + a->fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, + &a->dev->i2c_adap, STV090x_DEMODULATOR_0); + + if (a->fe) { + struct stv6110x_devctl *ctl; + + ctl = dvb_attach(stv6110x_attach, + a->fe, + &technisat_usb2_stv6110x_config, + &a->dev->i2c_adap); + + if (ctl) { + technisat_usb2_stv090x_config.tuner_init = ctl->tuner_init; + technisat_usb2_stv090x_config.tuner_sleep = ctl->tuner_sleep; + technisat_usb2_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; + technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; + technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; + technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; + technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; + technisat_usb2_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; + technisat_usb2_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; + technisat_usb2_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; + technisat_usb2_stv090x_config.tuner_get_status = ctl->tuner_get_status; + + /* call the init function once to initialize + tuner's clock output divider and demod's + master clock */ + if (a->fe->ops.init) + a->fe->ops.init(a->fe); + + if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0) + return -EAGAIN; + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, + NULL, 0, 500); + mutex_unlock(&a->dev->i2c_mutex); + + if (ret != 0) + err("could not set IF_CLK to external"); + + a->fe->ops.set_voltage = technisat_usb2_set_voltage; + + /* if everything was successful assign a nice name to the frontend */ + strlcpy(a->fe->ops.info.name, a->dev->desc->name, + sizeof(a->fe->ops.info.name)); + } else { + dvb_frontend_detach(a->fe); + a->fe = NULL; + } + } + + technisat_usb2_set_led_timer(a->dev, 1, 1); + + return a->fe == NULL ? -ENODEV : 0; +} + +/* Remote control */ + +/* the device is giving providing raw IR-signals to the host mapping + * it only to one remote control is just the default implementation + */ +#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889 +#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US) + +#define FIRMWARE_CLOCK_TICK 83333 +#define FIRMWARE_CLOCK_DIVISOR 256 + +#define IR_PERCENT_TOLERANCE 15 + +#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) +#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR) + +#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) +#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR) + +#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) +#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) + +#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) +#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) + +static int technisat_usb2_get_ir(struct dvb_usb_device *d) +{ + u8 buf[62], *b; + int ret; + struct ir_raw_event ev; + + buf[0] = GET_IR_DATA_VENDOR_REQUEST; + buf[1] = 0x08; + buf[2] = 0x8f; + buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT; + buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + GET_IR_DATA_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, + buf, 5, 500); + if (ret < 0) + goto unlock; + + buf[1] = 0; + buf[2] = 0; + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + GET_IR_DATA_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_IN, + 0x8080, 0, + buf, sizeof(buf), 500); + +unlock: + mutex_unlock(&d->i2c_mutex); + + if (ret < 0) + return ret; + + if (ret == 1) + return 0; /* no key pressed */ + + /* decoding */ + b = buf+1; + +#if 0 + deb_rc("RC: %d ", ret); + debug_dump(b, ret, deb_rc); +#endif + + ev.pulse = 0; + while (1) { + ev.pulse = !ev.pulse; + ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000; + ir_raw_event_store(d->rc_dev, &ev); + + b++; + if (*b == 0xff) { + ev.pulse = 0; + ev.duration = 888888*2; + ir_raw_event_store(d->rc_dev, &ev); + break; + } + } + + ir_raw_event_handle(d->rc_dev); + + return 1; +} + +static int technisat_usb2_rc_query(struct dvb_usb_device *d) +{ + int ret = technisat_usb2_get_ir(d); + + if (ret < 0) + return ret; + + if (ret == 0) + return 0; + + if (!disable_led_control) + technisat_usb2_set_led(d, 1, LED_BLINK); + + return 0; +} + +/* DVB-USB and USB stuff follows */ +static struct usb_device_id technisat_usb2_id_table[] = { + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) }, + { 0 } /* Terminating entry */ +}; + +/* device description */ +static struct dvb_usb_device_properties technisat_usb2_devices = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .identify_state = technisat_usb2_identify_state, + .firmware = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw", + + .size_of_priv = sizeof(struct technisat_usb2_state), + + .i2c_algo = &technisat_usb2_i2c_algo, + + .power_ctrl = technisat_usb2_power_ctrl, + .read_mac_address = technisat_usb2_read_mac_address, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = technisat_usb2_frontend_attach, + + .stream = { + .type = USB_ISOC, + .count = 8, + .endpoint = 0x2, + .u = { + .isoc = { + .framesperurb = 32, + .framesize = 2048, + .interval = 3, + } + } + }, + + .size_of_priv = 0, + }, + }, + + .num_device_descs = 1, + .devices = { + { "Technisat SkyStar USB HD (DVB-S/S2)", + { &technisat_usb2_id_table[0], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = 100, + .rc_codes = RC_MAP_TECHNISAT_USB2, + .module_name = "technisat-usb2", + .rc_query = technisat_usb2_rc_query, + .allowed_protos = RC_TYPE_ALL, + .driver_type = RC_DRIVER_IR_RAW, + } +}; + +static int technisat_usb2_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *dev; + + if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE, + &dev, adapter_nr) != 0) + return -ENODEV; + + if (dev) { + struct technisat_usb2_state *state = dev->priv; + state->dev = dev; + + if (!disable_led_control) { + INIT_DELAYED_WORK(&state->green_led_work, + technisat_usb2_green_led_control); + schedule_delayed_work(&state->green_led_work, + msecs_to_jiffies(500)); + } + } + + return 0; +} + +static void technisat_usb2_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *dev = usb_get_intfdata(intf); + + /* work and stuff was only created when the device is is hot-state */ + if (dev != NULL) { + struct technisat_usb2_state *state = dev->priv; + if (state != NULL) + cancel_delayed_work_sync(&state->green_led_work); + } + + dvb_usb_device_exit(intf); +} + +static struct usb_driver technisat_usb2_driver = { + .name = "dvb_usb_technisat_usb2", + .probe = technisat_usb2_probe, + .disconnect = technisat_usb2_disconnect, + .id_table = technisat_usb2_id_table, +}; + +/* module stuff */ +static int __init technisat_usb2_module_init(void) +{ + int result = usb_register(&technisat_usb2_driver); + if (result) { + err("usb_register failed. Code %d", result); + return result; + } + + return 0; +} + +static void __exit technisat_usb2_module_exit(void) +{ + usb_deregister(&technisat_usb2_driver); +} + +module_init(technisat_usb2_module_init); +module_exit(technisat_usb2_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ttusb2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ttusb2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ttusb2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ttusb2.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,452 @@ +/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones + * (e.g. Pinnacle 400e DVB-S USB2.0). + * + * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes. + * + * TDA8263 + TDA10086 + * + * I2C addresses: + * 0x08 - LNBP21PD - LNB power supply + * 0x0e - TDA10086 - Demodulator + * 0x50 - FX2 eeprom + * 0x60 - TDA8263 - Tuner + * 0x78 ??? + * + * Copyright (c) 2002 Holger Waechtler + * Copyright (c) 2003 Felix Domke + * Copyright (C) 2005-6 Patrick Boettcher + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#define DVB_USB_LOG_PREFIX "ttusb2" +#include "dvb-usb.h" + +#include "ttusb2.h" + +#include "tda826x.h" +#include "tda10086.h" +#include "tda1002x.h" +#include "tda827x.h" +#include "lnbp21.h" + +/* debug */ +static int dvb_usb_ttusb2_debug; +#define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) +module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct ttusb2_state { + u8 id; + u16 last_rc_key; +}; + +static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, + u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + struct ttusb2_state *st = d->priv; + u8 s[wlen+4],r[64] = { 0 }; + int ret = 0; + + memset(s,0,wlen+4); + + s[0] = 0xaa; + s[1] = ++st->id; + s[2] = cmd; + s[3] = wlen; + memcpy(&s[4],wbuf,wlen); + + ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0); + + if (ret != 0 || + r[0] != 0x55 || + r[1] != s[1] || + r[2] != cmd || + (rlen > 0 && r[3] != rlen)) { + warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); + return -EIO; + } + + if (rlen > 0) + memcpy(rbuf, &r[4], rlen); + + return 0; +} + +static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + static u8 obuf[60], ibuf[60]; + int i,read; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + read = i+1 < num && (msg[i+1].flags & I2C_M_RD); + + obuf[0] = (msg[i].addr << 1) | read; + obuf[1] = msg[i].len; + + /* read request */ + if (read) + obuf[2] = msg[i+1].len; + else + obuf[2] = 0; + + memcpy(&obuf[3],msg[i].buf,msg[i].len); + + if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) { + err("i2c transfer failed."); + break; + } + + if (read) { + memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len); + i++; + } + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm ttusb2_i2c_algo = { + .master_xfer = ttusb2_i2c_xfer, + .functionality = ttusb2_i2c_func, +}; + +/* command to poll IR receiver (copied from pctv452e.c) */ +#define CMD_GET_IR_CODE 0x1b + +/* IR */ +static int tt3650_rc_query(struct dvb_usb_device *d) +{ + int ret; + u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */ + struct ttusb2_state *st = d->priv; + ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx)); + if (ret != 0) + return ret; + + if (rx[8] & 0x01) { + /* got a "press" event */ + st->last_rc_key = (rx[3] << 8) | rx[2]; + deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]); + rc_keydown(d->rc_dev, st->last_rc_key, 0); + } else if (st->last_rc_key) { + rc_keyup(d->rc_dev); + st->last_rc_key = 0; + } + + return 0; +} + + +/* Callbacks for DVB USB */ +static int ttusb2_identify_state (struct usb_device *udev, struct + dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, + int *cold) +{ + *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; + return 0; +} + +static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = onoff; + ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0); + return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0); +} + + +static struct tda10086_config tda10086_config = { + .demod_address = 0x0e, + .invert = 0, + .diseqc_tone = 1, + .xtal_freq = TDA10086_XTAL_16M, +}; + +static struct tda10023_config tda10023_config = { + .demod_address = 0x0c, + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .deltaf = 0xa511, +}; + +static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev,0,3) < 0) + err("set interface to alts=3 failed"); + + if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { + deb_info("TDA10086 attach failed\n"); + return -ENODEV; + } + + return 0; +} + +static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 3) < 0) + err("set interface to alts=3 failed"); + if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { + deb_info("TDA10023 attach failed\n"); + return -ENODEV; + } + return 0; +} + +static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) +{ + if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) { + printk(KERN_ERR "%s: No tda827x found!\n", __func__); + return -ENODEV; + } + return 0; +} + +static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) +{ + if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { + deb_info("TDA8263 attach failed\n"); + return -ENODEV; + } + + if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) { + deb_info("LNBP21 attach failed\n"); + return -ENODEV; + } + return 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties ttusb2_properties; +static struct dvb_usb_device_properties ttusb2_properties_s2400; +static struct dvb_usb_device_properties ttusb2_properties_ct3650; + +static int ttusb2_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &ttusb2_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650, + THIS_MODULE, NULL, adapter_nr)) + return 0; + return -ENODEV; +} + +static struct usb_device_id ttusb2_table [] = { + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, + { USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_S2400) }, + { USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_CT3650) }, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, ttusb2_table); + +static struct dvb_usb_device_properties ttusb2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-pctv-400e-01.fw", + + .size_of_priv = sizeof(struct ttusb2_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, + + .frontend_attach = ttusb2_frontend_tda10086_attach, + .tuner_attach = ttusb2_tuner_tda826x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + } + }, + + .power_ctrl = ttusb2_power_ctrl, + .identify_state = ttusb2_identify_state, + + .i2c_algo = &ttusb2_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 2, + .devices = { + { "Pinnacle 400e DVB-S USB2.0", + { &ttusb2_table[0], NULL }, + { NULL }, + }, + { "Pinnacle 450e DVB-S USB2.0", + { &ttusb2_table[1], NULL }, + { NULL }, + }, + } +}; + +static struct dvb_usb_device_properties ttusb2_properties_s2400 = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-tt-s2400-01.fw", + + .size_of_priv = sizeof(struct ttusb2_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = NULL, + + .frontend_attach = ttusb2_frontend_tda10086_attach, + .tuner_attach = ttusb2_tuner_tda826x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + } + }, + + .power_ctrl = ttusb2_power_ctrl, + .identify_state = ttusb2_identify_state, + + .i2c_algo = &ttusb2_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Technotrend TT-connect S-2400", + { &ttusb2_table[2], NULL }, + { NULL }, + }, + } +}; + +static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct ttusb2_state), + + .rc.core = { + .rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */ + .rc_codes = RC_MAP_TT_1500, + .rc_query = tt3650_rc_query, + .allowed_protos = RC_TYPE_UNKNOWN, + }, + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = NULL, + + .frontend_attach = ttusb2_frontend_tda10023_attach, + .tuner_attach = ttusb2_tuner_tda827x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + }, + }, + + .power_ctrl = ttusb2_power_ctrl, + .identify_state = ttusb2_identify_state, + + .i2c_algo = &ttusb2_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Technotrend TT-connect CT-3650", + .warm_ids = { &ttusb2_table[3], NULL }, + }, + } +}; + +static struct usb_driver ttusb2_driver = { + .name = "dvb_usb_ttusb2", + .probe = ttusb2_probe, + .disconnect = dvb_usb_device_exit, + .id_table = ttusb2_table, +}; + +/* module stuff */ +static int __init ttusb2_module_init(void) +{ + int result; + if ((result = usb_register(&ttusb2_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit ttusb2_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&ttusb2_driver); +} + +module_init (ttusb2_module_init); +module_exit (ttusb2_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ttusb2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ttusb2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ttusb2.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/ttusb2.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,70 @@ +/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones + * (e.g. Pinnacle 400e DVB-S USB2.0). + * + * Copyright (c) 2002 Holger Waechtler + * Copyright (c) 2003 Felix Domke + * Copyright (C) 2005-6 Patrick Boettcher + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_TTUSB2_H_ +#define _DVB_USB_TTUSB2_H_ + +/* TTUSB protocol + * + * always to messages (out/in) + * out message: + * 0xaa + * + * in message (complete block is always 0x40 bytes long) + * 0x55 + * + * id is incremented for each transaction + */ + +#define CMD_DSP_DOWNLOAD 0x13 +/* out data: [28] + * last block must be empty */ + +#define CMD_DSP_BOOT 0x14 +/* out data: nothing */ + +#define CMD_POWER 0x15 +/* out data: */ + +#define CMD_LNB 0x16 +/* out data: <18V=0,13V=1> */ + +#define CMD_GET_VERSION 0x17 +/* in data: [5] */ + +#define CMD_DISEQC 0x18 +/* out data: [cmdlen] */ + +#define CMD_PID_ENABLE 0x22 +/* out data: */ + +#define CMD_PID_DISABLE 0x23 +/* out data: */ + +#define CMD_FILTER_ENABLE 0x24 +/* out data: [12] [12] */ + +#define CMD_FILTER_DISABLE 0x25 +/* out data: */ + +#define CMD_GET_DSP_VERSION 0x26 +/* in data: [28] */ + +#define CMD_I2C_XFER 0x31 +/* out data: [sndlen] + * in data: [rcvlen] */ + +#define CMD_I2C_BITRATE 0x32 +/* out data: */ + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/umt-010.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/umt-010.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/umt-010.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/umt-010.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,167 @@ +/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0 + * DVB-T receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +#include "mt352.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int umt_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d }; + static u8 mt352_reset[] = { 0x50, 0x80 }; + static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 }; + static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 }; + + static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff }; + static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff }; + static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 }; + static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 }; + static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f }; + + static u8 mt352_acq_ctl[] = { 0x53, 0x50 }; + static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio)); + + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + + mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1)); + mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2)); + mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3)); + mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4)); + mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5)); + + mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl)); + mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1)); + + return 0; +} + +static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct mt352_config umt_config; + + memset(&umt_config,0,sizeof(struct mt352_config)); + umt_config.demod_init = umt_mt352_demod_init; + umt_config.demod_address = 0xf; + + adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); + + return 0; +} + +static int umt_tuner_attach (struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034); + return 0; +} + +/* USB Driver stuff */ +static struct dvb_usb_device_properties umt_properties; + +static int umt_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &umt_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + return -EINVAL; +} + +/* do not change the order of the ID table */ +static struct usb_device_id umt_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, umt_table); + +static struct dvb_usb_device_properties umt_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-umt-010-02.fw", + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .frontend_attach = umt_mt352_frontend_attach, + .tuner_attach = umt_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = MAX_NO_URBS_FOR_DATA_STREAM, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .power_ctrl = dibusb_power_ctrl, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Hanftek UMT-010 DVB-T USB2.0", + { &umt_table[0], NULL }, + { &umt_table[1], NULL }, + }, + } +}; + +static struct usb_driver umt_driver = { + .name = "dvb_usb_umt_010", + .probe = umt_probe, + .disconnect = dvb_usb_device_exit, + .id_table = umt_table, +}; + +/* module stuff */ +static int __init umt_module_init(void) +{ + int result; + if ((result = usb_register(&umt_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit umt_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&umt_driver); +} + +module_init (umt_module_init); +module_exit (umt_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/usb-urb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/usb-urb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/usb-urb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/usb-urb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,254 @@ +/* usb-urb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file keeps functions for initializing and handling the + * BULK and ISOC USB data transfers in a generic way. + * Can be used for DVB-only and also, that's the plan, for + * Hybrid USB devices (analog and DVB). + */ +#include "dvb-usb-common.h" + +/* URB stuff for streaming */ +static void usb_urb_complete(struct urb *urb) +{ + struct usb_data_stream *stream = urb->context; + int ptype = usb_pipetype(urb->pipe); + int i; + u8 *b; + + deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n", + ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", + urb->status,urb->actual_length,urb->transfer_buffer_length, + urb->number_of_packets,urb->error_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + deb_ts("urb completition error %d.\n", urb->status); + break; + } + + b = (u8 *) urb->transfer_buffer; + switch (ptype) { + case PIPE_ISOCHRONOUS: + for (i = 0; i < urb->number_of_packets; i++) { + + if (urb->iso_frame_desc[i].status != 0) + deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); + else if (urb->iso_frame_desc[i].actual_length > 0) + stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); + + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + debug_dump(b,20,deb_uxfer); + break; + case PIPE_BULK: + if (urb->actual_length > 0) + stream->complete(stream, b, urb->actual_length); + break; + default: + err("unknown endpoint type in completition handler."); + return; + } + usb_submit_urb(urb,GFP_ATOMIC); +} + +int usb_urb_kill(struct usb_data_stream *stream) +{ + int i; + for (i = 0; i < stream->urbs_submitted; i++) { + deb_ts("killing URB no. %d.\n",i); + + /* stop the URB */ + usb_kill_urb(stream->urb_list[i]); + } + stream->urbs_submitted = 0; + return 0; +} + +int usb_urb_submit(struct usb_data_stream *stream) +{ + int i,ret; + for (i = 0; i < stream->urbs_initialized; i++) { + deb_ts("submitting URB no. %d\n",i); + if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) { + err("could not submit URB no. %d - get them all back",i); + usb_urb_kill(stream); + return ret; + } + stream->urbs_submitted++; + } + return 0; +} + +static int usb_free_stream_buffers(struct usb_data_stream *stream) +{ + if (stream->state & USB_STATE_URB_BUF) { + while (stream->buf_num) { + stream->buf_num--; + deb_mem("freeing buffer %d\n",stream->buf_num); + usb_free_coherent(stream->udev, stream->buf_size, + stream->buf_list[stream->buf_num], + stream->dma_addr[stream->buf_num]); + } + } + + stream->state &= ~USB_STATE_URB_BUF; + + return 0; +} + +static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size) +{ + stream->buf_num = 0; + stream->buf_size = size; + + deb_mem("all in all I will use %lu bytes for streaming\n",num*size); + + for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { + deb_mem("allocating buffer %d\n",stream->buf_num); + if (( stream->buf_list[stream->buf_num] = + usb_alloc_coherent(stream->udev, size, GFP_ATOMIC, + &stream->dma_addr[stream->buf_num]) ) == NULL) { + deb_mem("not enough memory for urb-buffer allocation.\n"); + usb_free_stream_buffers(stream); + return -ENOMEM; + } + deb_mem("buffer %d: %p (dma: %Lu)\n", + stream->buf_num, +stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); + memset(stream->buf_list[stream->buf_num],0,size); + stream->state |= USB_STATE_URB_BUF; + } + deb_mem("allocation successful\n"); + + return 0; +} + +static int usb_bulk_urb_init(struct usb_data_stream *stream) +{ + int i, j; + + if ((i = usb_allocate_stream_buffers(stream,stream->props.count, + stream->props.u.bulk.buffersize)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!.\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[i]); + return -ENOMEM; + } + usb_fill_bulk_urb( stream->urb_list[i], stream->udev, + usb_rcvbulkpipe(stream->udev,stream->props.endpoint), + stream->buf_list[i], + stream->props.u.bulk.buffersize, + usb_urb_complete, stream); + + stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; + stream->urbs_initialized++; + } + return 0; +} + +static int usb_isoc_urb_init(struct usb_data_stream *stream) +{ + int i,j; + + if ((i = usb_allocate_stream_buffers(stream,stream->props.count, + stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + struct urb *urb; + int frame_offset = 0; + + stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[i]); + return -ENOMEM; + } + + urb = stream->urb_list[i]; + + urb->dev = stream->udev; + urb->context = stream; + urb->complete = usb_urb_complete; + urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = stream->props.u.isoc.interval; + urb->number_of_packets = stream->props.u.isoc.framesperurb; + urb->transfer_buffer_length = stream->buf_size; + urb->transfer_buffer = stream->buf_list[i]; + urb->transfer_dma = stream->dma_addr[i]; + + for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize; + frame_offset += stream->props.u.isoc.framesize; + } + + stream->urbs_initialized++; + } + return 0; +} + +int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) +{ + if (stream == NULL || props == NULL) + return -EINVAL; + + memcpy(&stream->props, props, sizeof(*props)); + + usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint)); + + if (stream->complete == NULL) { + err("there is no data callback - this doesn't make sense."); + return -EINVAL; + } + + switch (stream->props.type) { + case USB_BULK: + return usb_bulk_urb_init(stream); + case USB_ISOC: + return usb_isoc_urb_init(stream); + default: + err("unknown URB-type for data transfer."); + return -EINVAL; + } +} + +int usb_urb_exit(struct usb_data_stream *stream) +{ + int i; + + usb_urb_kill(stream); + + for (i = 0; i < stream->urbs_initialized; i++) { + if (stream->urb_list[i] != NULL) { + deb_mem("freeing URB no. %d.\n",i); + /* free the URBs */ + usb_free_urb(stream->urb_list[i]); + } + } + stream->urbs_initialized = 0; + + usb_free_stream_buffers(stream); + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,459 @@ +/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S + * receiver. + * + * Copyright (C) 2005 Ralph Metzler + * Metzler Brothers Systementwicklung GbR + * + * Copyright (C) 2005 Patrick Boettcher + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "vp702x.h" +#include + +/* debug */ +int dvb_usb_vp702x_debug; +module_param_named(debug,dvb_usb_vp702x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct vp702x_adapter_state { + int pid_filter_count; + int pid_filter_can_bypass; + u8 pid_filter_state; +}; + +static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req, + u16 value, u16 index, u8 *b, int blen) +{ + int ret; + + ret = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev, 0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value, index, b, blen, + 2000); + + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); + ret = -EIO; + } else + ret = 0; + + + deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + return ret; +} + +int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + + mutex_lock(&d->usb_mutex); + ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen); + mutex_unlock(&d->usb_mutex); + + return ret; +} + +int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + if ((ret = usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value,index,b,blen, + 2000)) != blen) { + warn("usb out operation failed. (%d)",ret); + return -EIO; + } else + return 0; +} + +int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + + mutex_lock(&d->usb_mutex); + ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen); + mutex_unlock(&d->usb_mutex); + + return ret; +} + +int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec) +{ + int ret; + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen); + msleep(msec); + ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen); + + mutex_unlock(&d->usb_mutex); + return ret; +} + +static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, + int olen, u8 *i, int ilen, int msec) +{ + struct vp702x_device_state *st = d->priv; + int ret = 0; + u8 *buf; + int buflen = max(olen + 2, ilen + 1); + + ret = mutex_lock_interruptible(&st->buf_mutex); + if (ret < 0) + return ret; + + if (buflen > st->buf_len) { + buf = kmalloc(buflen, GFP_KERNEL); + if (!buf) { + mutex_unlock(&st->buf_mutex); + return -ENOMEM; + } + info("successfully reallocated a bigger buffer"); + kfree(st->buf); + st->buf = buf; + st->buf_len = buflen; + } else { + buf = st->buf; + } + + buf[0] = 0x00; + buf[1] = cmd; + memcpy(&buf[2], o, olen); + + ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec); + + if (ret == 0) + memcpy(i, &buf[1], ilen); + mutex_unlock(&st->buf_mutex); + + return ret; +} + +static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass) +{ + int ret; + struct vp702x_device_state *st = adap->dev->priv; + u8 *buf; + + mutex_lock(&st->buf_mutex); + + buf = st->buf; + memset(buf, 0, 16); + + ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, + 0, buf, 16); + mutex_unlock(&st->buf_mutex); + return ret; +} + +static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state) +{ + int ret; + struct vp702x_device_state *st = adap->dev->priv; + u8 *buf; + + mutex_lock(&st->buf_mutex); + + buf = st->buf; + memset(buf, 0, 16); + ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, + 0, buf, 16); + + mutex_unlock(&st->buf_mutex); + + return ret; +} + +static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff) +{ + struct vp702x_adapter_state *st = adap->priv; + struct vp702x_device_state *dst = adap->dev->priv; + u8 *buf; + + if (onoff) + st->pid_filter_state |= (1 << id); + else { + st->pid_filter_state &= ~(1 << id); + pid = 0xffff; + } + + id = 0x10 + id*2; + + vp702x_set_pld_state(adap, st->pid_filter_state); + + mutex_lock(&dst->buf_mutex); + + buf = dst->buf; + memset(buf, 0, 16); + vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16); + vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16); + + mutex_unlock(&dst->buf_mutex); + + return 0; +} + + +static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap) +{ + struct vp702x_adapter_state *st = adap->priv; + struct vp702x_device_state *dst = adap->dev->priv; + int i; + u8 *b; + + st->pid_filter_count = 8; + st->pid_filter_can_bypass = 1; + st->pid_filter_state = 0x00; + + vp702x_set_pld_mode(adap, 1); /* bypass */ + + for (i = 0; i < st->pid_filter_count; i++) + vp702x_set_pid(adap, 0xffff, i, 1); + + mutex_lock(&dst->buf_mutex); + b = dst->buf; + memset(b, 0, 10); + vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10); + vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10); + vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10); + mutex_unlock(&dst->buf_mutex); + /*vp702x_set_pld_mode(d, 0); // filter */ + + return 0; +} + +static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + return 0; +} + +/* keys for the enclosed remote control */ +static struct rc_map_table rc_map_vp702x_table[] = { + { 0x0001, KEY_1 }, + { 0x0002, KEY_2 }, +}; + +/* remote control stuff (does not work with my box) */ +static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 *key; + int i; + +/* remove the following return to enabled remote querying */ + return 0; + + key = kmalloc(10, GFP_KERNEL); + if (!key) + return -ENOMEM; + + vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10); + + deb_rc("remote query key: %x %d\n",key[1],key[1]); + + if (key[1] == 0x44) { + *state = REMOTE_NO_KEY_PRESSED; + kfree(key); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++) + if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) { + *state = REMOTE_KEY_PRESSED; + *event = rc_map_vp702x_table[i].keycode; + break; + } + kfree(key); + return 0; +} + + +static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) +{ + u8 i, *buf; + struct vp702x_device_state *st = d->priv; + + mutex_lock(&st->buf_mutex); + buf = st->buf; + for (i = 6; i < 12; i++) + vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1); + + memcpy(mac, buf, 6); + mutex_unlock(&st->buf_mutex); + return 0; +} + +static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 buf[10] = { 0 }; + + vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); + + if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, + buf, 10, 10)) + return -EIO; + + buf[9] = '\0'; + info("system string: %s",&buf[1]); + + vp702x_init_pid_filter(adap); + + adap->fe = vp702x_fe_attach(adap->dev); + vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); + + return 0; +} + +static struct dvb_usb_device_properties vp702x_properties; + +static int vp702x_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + struct vp702x_device_state *st; + int ret; + + ret = dvb_usb_device_init(intf, &vp702x_properties, + THIS_MODULE, &d, adapter_nr); + if (ret) + goto out; + + st = d->priv; + st->buf_len = 16; + st->buf = kmalloc(st->buf_len, GFP_KERNEL); + if (!st->buf) { + ret = -ENOMEM; + dvb_usb_device_exit(intf); + goto out; + } + mutex_init(&st->buf_mutex); + +out: + return ret; + +} + +static void vp702x_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + struct vp702x_device_state *st = d->priv; + mutex_lock(&st->buf_mutex); + kfree(st->buf); + mutex_unlock(&st->buf_mutex); + dvb_usb_device_exit(intf); +} + +static struct usb_device_id vp702x_usb_table [] = { + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) }, +// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) }, +// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, vp702x_usb_table); + +static struct dvb_usb_device_properties vp702x_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-vp702x-02.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct vp702x_device_state), + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS, + + .streaming_ctrl = vp702x_streaming_ctrl, + .frontend_attach = vp702x_frontend_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct vp702x_adapter_state), + } + }, + .read_mac_address = vp702x_read_mac_addr, + + .rc.legacy = { + .rc_map_table = rc_map_vp702x_table, + .rc_map_size = ARRAY_SIZE(rc_map_vp702x_table), + .rc_interval = 400, + .rc_query = vp702x_rc_query, + }, + + .num_device_descs = 1, + .devices = { + { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)", + .cold_ids = { &vp702x_usb_table[0], NULL }, + .warm_ids = { NULL }, + }, +/* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)", + .cold_ids = { &vp702x_usb_table[2], NULL }, + .warm_ids = { &vp702x_usb_table[3], NULL }, + }, +*/ { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver vp702x_usb_driver = { + .name = "dvb_usb_vp702x", + .probe = vp702x_usb_probe, + .disconnect = vp702x_usb_disconnect, + .id_table = vp702x_usb_table, +}; + +/* module stuff */ +static int __init vp702x_usb_module_init(void) +{ + int result; + if ((result = usb_register(&vp702x_usb_driver))) { + err("usb_register failed. (%d)",result); + return result; + } + + return 0; +} + +static void __exit vp702x_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&vp702x_usb_driver); +} + +module_init(vp702x_usb_module_init); +module_exit(vp702x_usb_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x-fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x-fe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,387 @@ +/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0 + * DVB-S receiver. + * + * Copyright (C) 2005 Ralph Metzler + * Metzler Brothers Systementwicklung GbR + * + * Copyright (C) 2005 Patrick Boettcher + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * This file can be removed soon, after the DST-driver is rewritten to provice + * the frontend-controlling separately. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + * + */ +#include "vp702x.h" + +struct vp702x_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; + + struct dvb_frontend_ops ops; + + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone_mode; + + u8 lnb_buf[8]; + + u8 lock; + u8 sig; + u8 snr; + + unsigned long next_status_check; + unsigned long status_check_interval; +}; + +static int vp702x_fe_refresh_state(struct vp702x_fe_state *st) +{ + struct vp702x_device_state *dst = st->d->priv; + u8 *buf; + + if (time_after(jiffies, st->next_status_check)) { + mutex_lock(&dst->buf_mutex); + buf = dst->buf; + + vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10); + st->lock = buf[4]; + + vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1); + st->snr = buf[0]; + + vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1); + st->sig = buf[0]; + + mutex_unlock(&dst->buf_mutex); + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + +static u8 vp702x_chksum(u8 *buf,int f, int count) +{ + u8 s = 0; + int i; + for (i = f; i < f+count; i++) + s += buf[i]; + return ~s+1; +} + +static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + deb_fe("%s\n",__func__); + + if (st->lock == 0) + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; + else + *status = 0; + + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 250; + return 0; +} + +/* not supported by this Frontend */ +static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + *ber = 0; + return 0; +} + +/* not supported by this Frontend */ +static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + *unc = 0; + return 0; +} + +static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + + *strength = (st->sig << 8) | st->sig; + return 0; +} + +static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + u8 _snr; + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + + _snr = (st->snr & 0x1f) * 0xff / 0x1f; + *snr = (_snr << 8) | _snr; + return 0; +} + +static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + deb_fe("%s\n",__func__); + tune->min_delay_ms = 2000; + return 0; +} + +static int vp702x_fe_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + struct vp702x_device_state *dst = st->d->priv; + u32 freq = fep->frequency/1000; + /*CalFrequency*/ +/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */ + u64 sr; + u8 *cmd; + + mutex_lock(&dst->buf_mutex); + + cmd = dst->buf; + memset(cmd, 0, 10); + + cmd[0] = (freq >> 8) & 0x7f; + cmd[1] = freq & 0xff; + cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ + + sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20; + do_div(sr,88000); + cmd[3] = (sr >> 12) & 0xff; + cmd[4] = (sr >> 4) & 0xff; + cmd[5] = (sr << 4) & 0xf0; + + deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", + fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, + (unsigned long) sr, (unsigned long) sr); + +/* if (fep->inversion == INVERSION_ON) + cmd[6] |= 0x80; */ + + if (st->voltage == SEC_VOLTAGE_18) + cmd[6] |= 0x40; + +/* if (fep->u.qpsk.symbol_rate > 8000000) + cmd[6] |= 0x20; + + if (fep->frequency < 1531000) + cmd[6] |= 0x04; + + if (st->tone_mode == SEC_TONE_ON) + cmd[6] |= 0x01;*/ + + cmd[7] = vp702x_chksum(cmd,0,7); + + st->status_check_interval = 250; + st->next_status_check = jiffies; + + vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100); + + if (cmd[2] == 0 && cmd[3] == 0) + deb_fe("tuning failed.\n"); + else + deb_fe("tuning succeeded.\n"); + + mutex_unlock(&dst->buf_mutex); + + return 0; +} + +static int vp702x_fe_init(struct dvb_frontend *fe) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + deb_fe("%s\n",__func__); + vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); + return 0; +} + +static int vp702x_fe_sleep(struct dvb_frontend *fe) +{ + deb_fe("%s\n",__func__); + return 0; +} + +static int vp702x_fe_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + deb_fe("%s\n",__func__); + return 0; +} + +static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + u8 *cmd; + struct vp702x_fe_state *st = fe->demodulator_priv; + struct vp702x_device_state *dst = st->d->priv; + + deb_fe("%s\n",__func__); + + if (m->msg_len > 4) + return -EINVAL; + + mutex_lock(&dst->buf_mutex); + + cmd = dst->buf; + cmd[1] = SET_DISEQC_CMD; + cmd[2] = m->msg_len; + memcpy(&cmd[3], m->msg, m->msg_len); + cmd[7] = vp702x_chksum(cmd, 0, 7); + + vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100); + + if (cmd[2] == 0 && cmd[3] == 0) + deb_fe("diseqc cmd failed.\n"); + else + deb_fe("diseqc cmd succeeded.\n"); + + mutex_unlock(&dst->buf_mutex); + + return 0; +} + +static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + deb_fe("%s\n",__func__); + return 0; +} + +static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + struct vp702x_device_state *dst = st->d->priv; + u8 *buf; + + deb_fe("%s\n",__func__); + + st->tone_mode = tone; + + if (tone == SEC_TONE_ON) + st->lnb_buf[2] = 0x02; + else + st->lnb_buf[2] = 0x00; + + st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7); + + mutex_lock(&dst->buf_mutex); + + buf = dst->buf; + memcpy(buf, st->lnb_buf, 8); + + vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100); + if (buf[2] == 0 && buf[3] == 0) + deb_fe("set_tone cmd failed.\n"); + else + deb_fe("set_tone cmd succeeded.\n"); + + mutex_unlock(&dst->buf_mutex); + + return 0; +} + +static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t + voltage) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + struct vp702x_device_state *dst = st->d->priv; + u8 *buf; + deb_fe("%s\n",__func__); + + st->voltage = voltage; + + if (voltage != SEC_VOLTAGE_OFF) + st->lnb_buf[4] = 0x01; + else + st->lnb_buf[4] = 0x00; + + st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7); + + mutex_lock(&dst->buf_mutex); + + buf = dst->buf; + memcpy(buf, st->lnb_buf, 8); + + vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100); + if (buf[2] == 0 && buf[3] == 0) + deb_fe("set_voltage cmd failed.\n"); + else + deb_fe("set_voltage cmd succeeded.\n"); + + mutex_unlock(&dst->buf_mutex); + return 0; +} + +static void vp702x_fe_release(struct dvb_frontend* fe) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + kfree(st); +} + +static struct dvb_frontend_ops vp702x_fe_ops; + +struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) +{ + struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL); + if (s == NULL) + goto error; + + s->d = d; + + memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + + s->lnb_buf[1] = SET_LNB_POWER; + s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */ + + return &s->fe; +error: + return NULL; +} + + +static struct dvb_frontend_ops vp702x_fe_ops = { + .info = { + .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + .release = vp702x_fe_release, + + .init = vp702x_fe_init, + .sleep = vp702x_fe_sleep, + + .set_frontend = vp702x_fe_set_frontend, + .get_frontend = vp702x_fe_get_frontend, + .get_tune_settings = vp702x_fe_get_tune_settings, + + .read_status = vp702x_fe_read_status, + .read_ber = vp702x_fe_read_ber, + .read_signal_strength = vp702x_fe_read_signal_strength, + .read_snr = vp702x_fe_read_snr, + .read_ucblocks = vp702x_fe_read_unc_blocks, + + .diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg, + .diseqc_send_burst = vp702x_fe_send_diseqc_burst, + .set_tone = vp702x_fe_set_tone, + .set_voltage = vp702x_fe_set_voltage, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp702x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,113 @@ +#ifndef _DVB_USB_VP7021_H_ +#define _DVB_USB_VP7021_H_ + +#define DVB_USB_LOG_PREFIX "vp702x" +#include "dvb-usb.h" + +extern int dvb_usb_vp702x_debug; +#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp702x_debug,0x04,args) +#define deb_fe(args...) dprintk(dvb_usb_vp702x_debug,0x08,args) + +/* commands are read and written with USB control messages */ + +/* consecutive read/write operation */ +#define REQUEST_OUT 0xB2 +#define REQUEST_IN 0xB3 + +/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0 + * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer + * the returning buffer looks as follows + * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */ + +#define GET_TUNER_STATUS 0x05 +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */ + +#define GET_SYSTEM_STRING 0x06 +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */ + +#define SET_DISEQC_CMD 0x08 +/* additional out buffer: + * 0 1 2 3 4 + * len X1 X2 X3 X4 + * additional in buffer: + * 0 1 2 + * N/A 0 0 b[1] == b[2] == 0 -> success, failure otherwise */ + +#define SET_LNB_POWER 0x09 +/* additional out buffer: + * 0 1 2 + * 0x00 0xff 1 = on, 0 = off + * additional in buffer: + * 0 1 2 + * N/A 0 0 b[1] == b[2] == 0 -> success failure otherwise */ + +#define GET_MAC_ADDRESS 0x0A +/* #define GET_MAC_ADDRESS 0x0B */ +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */ + +#define SET_PID_FILTER 0x11 +/* additional in buffer: + * 0 1 ... 14 15 16 + * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */ + +/* request: 0xB2; i: 0; v: 0; + * b[0] != 0 -> tune and lock a channel + * 0 1 2 3 4 5 6 7 + * freq0 freq1 divstep srate0 srate1 srate2 flag chksum + */ + +/* one direction requests */ +#define READ_REMOTE_REQ 0xB4 +/* IN i: 0; v: 0; b[0] == request, b[1] == key */ + +#define READ_PID_NUMBER_REQ 0xB5 +/* IN i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */ + +#define WRITE_EEPROM_REQ 0xB6 +/* OUT i: offset; v: value to write; no extra buffer */ + +#define READ_EEPROM_REQ 0xB7 +/* IN i: bufferlen; v: offset; buffer with bufferlen bytes */ + +#define READ_STATUS 0xB8 +/* IN i: 0; v: 0; bufferlen 10 */ + +#define READ_TUNER_REG_REQ 0xB9 +/* IN i: 0; v: register; b[0] = value */ + +#define READ_FX2_REG_REQ 0xBA +/* IN i: offset; v: 0; b[0] = value */ + +#define WRITE_FX2_REG_REQ 0xBB +/* OUT i: offset; v: value to write; 1 byte extra buffer */ + +#define SET_TUNER_POWER_REQ 0xBC +/* IN i: 0 = power off, 1 = power on */ + +#define WRITE_TUNER_REG_REQ 0xBD +/* IN i: register, v: value to write, no extra buffer */ + +#define RESET_TUNER 0xBE +/* IN i: 0, v: 0, no extra buffer */ + +struct vp702x_device_state { + struct mutex buf_mutex; + int buf_len; + u8 *buf; +}; + + +extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); + +extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); +extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,335 @@ +/* DVB USB compliant Linux driver for the + * - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver + * - DigitalNow TinyUSB2 DVB-t receiver + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "vp7045.h" + +/* debug */ +static int dvb_usb_vp7045_debug; +module_param_named(debug,dvb_usb_vp7045_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) + +int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec) +{ + int ret = 0; + u8 *buf = d->priv; + + buf[0] = cmd; + + if (outlen > 19) + outlen = 19; + + if (inlen > 11) + inlen = 11; + + ret = mutex_lock_interruptible(&d->usb_mutex); + if (ret) + return ret; + + if (out != NULL && outlen > 0) + memcpy(&buf[1], out, outlen); + + deb_xfer("out buffer: "); + debug_dump(buf, outlen+1, deb_xfer); + + + if (usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev,0), + TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, + buf, 20, 2000) != 20) { + err("USB control message 'out' went wrong."); + ret = -EIO; + goto unlock; + } + + msleep(msec); + + if (usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev,0), + TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + buf, 12, 2000) != 12) { + err("USB control message 'in' went wrong."); + ret = -EIO; + goto unlock; + } + + deb_xfer("in buffer: "); + debug_dump(buf, 12, deb_xfer); + + if (in != NULL && inlen > 0) + memcpy(in, &buf[1], inlen); + +unlock: + mutex_unlock(&d->usb_mutex); + + return ret; +} + +u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg) +{ + u8 obuf[2] = { 0 },v; + obuf[1] = reg; + + vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30); + + return v; +} + +static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 v = onoff; + return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150); +} + +/* remote control stuff */ + +/* The keymapping struct. Somehow this should be loaded to the driver, but + * currently it is hardcoded. */ +static struct rc_map_table rc_map_vp7045_table[] = { + { 0x0016, KEY_POWER }, + { 0x0010, KEY_MUTE }, + { 0x0003, KEY_1 }, + { 0x0001, KEY_2 }, + { 0x0006, KEY_3 }, + { 0x0009, KEY_4 }, + { 0x001d, KEY_5 }, + { 0x001f, KEY_6 }, + { 0x000d, KEY_7 }, + { 0x0019, KEY_8 }, + { 0x001b, KEY_9 }, + { 0x0015, KEY_0 }, + { 0x0005, KEY_CHANNELUP }, + { 0x0002, KEY_CHANNELDOWN }, + { 0x001e, KEY_VOLUMEUP }, + { 0x000a, KEY_VOLUMEDOWN }, + { 0x0011, KEY_RECORD }, + { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */ + { 0x0014, KEY_PLAY }, + { 0x001a, KEY_STOP }, + { 0x0040, KEY_REWIND }, + { 0x0012, KEY_FASTFORWARD }, + { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */ + { 0x004c, KEY_PAUSE }, + { 0x004d, KEY_SCREEN }, /* Full screen mode. */ + { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ + { 0x000c, KEY_CANCEL }, /* Cancel */ + { 0x001c, KEY_EPG }, /* EPG */ + { 0x0000, KEY_TAB }, /* Tab */ + { 0x0048, KEY_INFO }, /* Preview */ + { 0x0004, KEY_LIST }, /* RecordList */ + { 0x000f, KEY_TEXT }, /* Teletext */ + { 0x0041, KEY_PREVIOUSSONG }, + { 0x0042, KEY_NEXTSONG }, + { 0x004b, KEY_UP }, + { 0x0051, KEY_DOWN }, + { 0x004e, KEY_LEFT }, + { 0x0052, KEY_RIGHT }, + { 0x004f, KEY_ENTER }, + { 0x0013, KEY_CANCEL }, + { 0x004a, KEY_CLEAR }, + { 0x0054, KEY_PRINT }, /* Capture */ + { 0x0043, KEY_SUBTITLE }, /* Subtitle/CC */ + { 0x0008, KEY_VIDEO }, /* A/V */ + { 0x0007, KEY_SLEEP }, /* Hibernate */ + { 0x0045, KEY_ZOOM }, /* Zoom+ */ + { 0x0018, KEY_RED}, + { 0x0053, KEY_GREEN}, + { 0x005e, KEY_YELLOW}, + { 0x005f, KEY_BLUE} +}; + +static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key; + int i; + vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20); + + deb_rc("remote query key: %x %d\n",key,key); + + if (key == 0x44) { + *state = REMOTE_NO_KEY_PRESSED; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(rc_map_vp7045_table); i++) + if (rc5_data(&rc_map_vp7045_table[i]) == key) { + *state = REMOTE_KEY_PRESSED; + *event = rc_map_vp7045_table[i].keycode; + break; + } + return 0; +} + +static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset) +{ + int i = 0; + u8 v,br[2]; + for (i=0; i < len; i++) { + v = offset + i; + vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5); + buf[i] = br[1]; + } + deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i); + debug_dump(buf,i,deb_info); + return 0; +} + +static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) +{ + return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR); +} + +static int vp7045_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 buf[255] = { 0 }; + + vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0); + buf[10] = '\0'; + deb_info("firmware says: %s ",buf); + + vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0); + buf[10] = '\0'; + deb_info("%s ",buf); + + vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0); + buf[10] = '\0'; + deb_info("v%s\n",buf); + +/* Dump the EEPROM */ +/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */ + + adap->fe = vp7045_fe_attach(adap->dev); + + return 0; +} + +static struct dvb_usb_device_properties vp7045_properties; + +static int vp7045_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + int ret = dvb_usb_device_init(intf, &vp7045_properties, + THIS_MODULE, &d, adapter_nr); + if (ret) + return ret; + + d->priv = kmalloc(20, GFP_KERNEL); + if (!d->priv) { + dvb_usb_device_exit(intf); + return -ENOMEM; + } + + return ret; +} + +static void vp7045_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + kfree(d->priv); + dvb_usb_device_exit(intf); +} + +static struct usb_device_id vp7045_usb_table [] = { + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, vp7045_usb_table); + +static struct dvb_usb_device_properties vp7045_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-vp7045-01.fw", + .size_of_priv = sizeof(u8 *), + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = vp7045_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .power_ctrl = vp7045_power_ctrl, + .read_mac_address = vp7045_read_mac_addr, + + .rc.legacy = { + .rc_interval = 400, + .rc_map_table = rc_map_vp7045_table, + .rc_map_size = ARRAY_SIZE(rc_map_vp7045_table), + .rc_query = vp7045_rc_query, + }, + + .num_device_descs = 2, + .devices = { + { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)", + .cold_ids = { &vp7045_usb_table[0], NULL }, + .warm_ids = { &vp7045_usb_table[1], NULL }, + }, + { .name = "DigitalNow TinyUSB 2 DVB-t Receiver", + .cold_ids = { &vp7045_usb_table[2], NULL }, + .warm_ids = { &vp7045_usb_table[3], NULL }, + }, + { NULL }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver vp7045_usb_driver = { + .name = "dvb_usb_vp7045", + .probe = vp7045_usb_probe, + .disconnect = vp7045_usb_disconnect, + .id_table = vp7045_usb_table, +}; + +/* module stuff */ +static int __init vp7045_usb_module_init(void) +{ + int result; + if ((result = usb_register(&vp7045_usb_driver))) { + err("usb_register failed. (%d)",result); + return result; + } + + return 0; +} + +static void __exit vp7045_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&vp7045_usb_driver); +} + +module_init(vp7045_usb_module_init); +module_exit(vp7045_usb_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045-fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045-fe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,192 @@ +/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0 + * DVB-T receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + * + */ +#include "vp7045.h" + +/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT + * + * Programming is hidden inside the firmware, so set_frontend is very easy. + * Even though there is a Firmware command that one can use to access the demod + * via its registers. This is used for status information. + */ + +struct vp7045_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; +}; + +static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + u8 s0 = vp7045_read_reg(state->d,0x00), + s1 = vp7045_read_reg(state->d,0x01), + s3 = vp7045_read_reg(state->d,0x03); + + *status = 0; + if (s0 & (1 << 4)) + *status |= FE_HAS_CARRIER; + if (s0 & (1 << 1)) + *status |= FE_HAS_VITERBI; + if (s0 & (1 << 5)) + *status |= FE_HAS_LOCK; + if (s1 & (1 << 1)) + *status |= FE_HAS_SYNC; + if (s3 & (1 << 6)) + *status |= FE_HAS_SIGNAL; + + if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != + (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) + *status &= ~FE_HAS_LOCK; + + return 0; +} + +static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + *ber = (vp7045_read_reg(state->d, 0x0D) << 16) | + (vp7045_read_reg(state->d, 0x0E) << 8) | + vp7045_read_reg(state->d, 0x0F); + return 0; +} + +static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + *unc = (vp7045_read_reg(state->d, 0x10) << 8) | + vp7045_read_reg(state->d, 0x11); + return 0; +} + +static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) | + vp7045_read_reg(state->d, 0x15); + + *strength = ~signal; + return 0; +} + +static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + u8 _snr = vp7045_read_reg(state->d, 0x09); + *snr = (_snr << 8) | _snr; + return 0; +} + +static int vp7045_fe_init(struct dvb_frontend* fe) +{ + return 0; +} + +static int vp7045_fe_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int vp7045_fe_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + u8 buf[5]; + u32 freq = fep->frequency / 1000; + + buf[0] = (freq >> 16) & 0xff; + buf[1] = (freq >> 8) & 0xff; + buf[2] = freq & 0xff; + buf[3] = 0; + + switch (fep->u.ofdm.bandwidth) { + case BANDWIDTH_8_MHZ: buf[4] = 8; break; + case BANDWIDTH_7_MHZ: buf[4] = 7; break; + case BANDWIDTH_6_MHZ: buf[4] = 6; break; + case BANDWIDTH_AUTO: return -EOPNOTSUPP; + default: + return -EINVAL; + } + + vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200); + return 0; +} + +static int vp7045_fe_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + return 0; +} + +static void vp7045_fe_release(struct dvb_frontend* fe) +{ + struct vp7045_fe_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops vp7045_fe_ops; + +struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d) +{ + struct vp7045_fe_state *s = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL); + if (s == NULL) + goto error; + + s->d = d; + memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + + return &s->fe; +error: + return NULL; +} + + +static struct dvb_frontend_ops vp7045_fe_ops = { + .info = { + .name = "Twinhan VP7045/46 USB DVB-T", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 1000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = vp7045_fe_release, + + .init = vp7045_fe_init, + .sleep = vp7045_fe_sleep, + + .set_frontend = vp7045_fe_set_frontend, + .get_frontend = vp7045_fe_get_frontend, + .get_tune_settings = vp7045_fe_get_tune_settings, + + .read_status = vp7045_fe_read_status, + .read_ber = vp7045_fe_read_ber, + .read_signal_strength = vp7045_fe_read_signal_strength, + .read_snr = vp7045_fe_read_snr, + .read_ucblocks = vp7045_fe_read_unc_blocks, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/dvb-usb/vp7045.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,70 @@ +/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII + * USB2.0 DVB-T receiver. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_VP7045_H_ +#define _DVB_USB_VP7045_H_ + +#define DVB_USB_LOG_PREFIX "vp7045" +#include "dvb-usb.h" + +/* vp7045 commands */ + +/* Twinhan Vendor requests */ +#define TH_COMMAND_IN 0xC0 +#define TH_COMMAND_OUT 0xC1 + +/* command bytes */ +#define TUNER_REG_READ 0x03 +#define TUNER_REG_WRITE 0x04 + +#define RC_VAL_READ 0x05 + #define RC_NO_KEY 0x44 + +#define SET_TUNER_POWER 0x06 +#define CHECK_TUNER_POWER 0x12 + #define Tuner_Power_ON 1 + #define Tuner_Power_OFF 0 + +#define GET_USB_SPEED 0x07 + +#define LOCK_TUNER_COMMAND 0x09 + +#define TUNER_SIGNAL_READ 0x0A + +/* FX2 eeprom */ +#define SET_EE_VALUE 0x10 +#define GET_EE_VALUE 0x11 + #define FX2_ID_ADDR 0x00 + #define VID_MSB_ADDR 0x02 + #define VID_LSB_ADDR 0x01 + #define PID_MSB_ADDR 0x04 + #define PID_LSB_ADDR 0x03 + #define MAC_0_ADDR 0x07 + #define MAC_1_ADDR 0x08 + #define MAC_2_ADDR 0x09 + #define MAC_3_ADDR 0x0a + #define MAC_4_ADDR 0x0b + #define MAC_5_ADDR 0x0c + +#define RESET_FX2 0x13 + +#define FW_VERSION_READ 0x0B +#define VENDOR_STRING_READ 0x0C +#define PRODUCT_STRING_READ 0x0D +#define FW_BCD_VERSION_READ 0x14 + +extern struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d); +extern int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen,int msec); +extern u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-avc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-avc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-avc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-avc.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1457 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Ben Backx + * Copyright (C) 2008 Henrik Kurelid + * + * 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, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "firedtv.h" + +#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL + +#define AVC_CTYPE_CONTROL 0x0 +#define AVC_CTYPE_STATUS 0x1 +#define AVC_CTYPE_NOTIFY 0x3 + +#define AVC_RESPONSE_ACCEPTED 0x9 +#define AVC_RESPONSE_STABLE 0xc +#define AVC_RESPONSE_CHANGED 0xd +#define AVC_RESPONSE_INTERIM 0xf + +#define AVC_SUBUNIT_TYPE_TUNER (0x05 << 3) +#define AVC_SUBUNIT_TYPE_UNIT (0x1f << 3) + +#define AVC_OPCODE_VENDOR 0x00 +#define AVC_OPCODE_READ_DESCRIPTOR 0x09 +#define AVC_OPCODE_DSIT 0xc8 +#define AVC_OPCODE_DSD 0xcb + +#define DESCRIPTOR_TUNER_STATUS 0x80 +#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00 + +#define SFE_VENDOR_DE_COMPANYID_0 0x00 /* OUI of Digital Everywhere */ +#define SFE_VENDOR_DE_COMPANYID_1 0x12 +#define SFE_VENDOR_DE_COMPANYID_2 0x87 + +#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0a +#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52 +#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 /* for DVB-S */ + +#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00 +#define SFE_VENDOR_OPCODE_HOST2CA 0x56 +#define SFE_VENDOR_OPCODE_CA2HOST 0x57 +#define SFE_VENDOR_OPCODE_CISTATUS 0x59 +#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 /* for DVB-S2 */ + +#define SFE_VENDOR_TAG_CA_RESET 0x00 +#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01 +#define SFE_VENDOR_TAG_CA_PMT 0x02 +#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04 +#define SFE_VENDOR_TAG_CA_MMI 0x05 +#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07 + +#define EN50221_LIST_MANAGEMENT_ONLY 0x03 +#define EN50221_TAG_APP_INFO 0x9f8021 +#define EN50221_TAG_CA_INFO 0x9f8031 + +struct avc_command_frame { + u8 ctype; + u8 subunit; + u8 opcode; + u8 operand[509]; +}; + +struct avc_response_frame { + u8 response; + u8 subunit; + u8 opcode; + u8 operand[509]; +}; + +#define LAST_OPERAND (509 - 1) + +static inline void clear_operands(struct avc_command_frame *c, int from, int to) +{ + memset(&c->operand[from], 0, to - from + 1); +} + +static void pad_operands(struct avc_command_frame *c, int from) +{ + int to = ALIGN(from, 4); + + if (from <= to && to <= LAST_OPERAND) + clear_operands(c, from, to); +} + +#define AVC_DEBUG_READ_DESCRIPTOR 0x0001 +#define AVC_DEBUG_DSIT 0x0002 +#define AVC_DEBUG_DSD 0x0004 +#define AVC_DEBUG_REGISTER_REMOTE_CONTROL 0x0008 +#define AVC_DEBUG_LNB_CONTROL 0x0010 +#define AVC_DEBUG_TUNE_QPSK 0x0020 +#define AVC_DEBUG_TUNE_QPSK2 0x0040 +#define AVC_DEBUG_HOST2CA 0x0080 +#define AVC_DEBUG_CA2HOST 0x0100 +#define AVC_DEBUG_APPLICATION_PMT 0x4000 +#define AVC_DEBUG_FCP_PAYLOADS 0x8000 + +static int avc_debug; +module_param_named(debug, avc_debug, int, 0644); +MODULE_PARM_DESC(debug, "Verbose logging (none = 0" + ", FCP subactions" + ": READ DESCRIPTOR = " __stringify(AVC_DEBUG_READ_DESCRIPTOR) + ", DSIT = " __stringify(AVC_DEBUG_DSIT) + ", REGISTER_REMOTE_CONTROL = " __stringify(AVC_DEBUG_REGISTER_REMOTE_CONTROL) + ", LNB CONTROL = " __stringify(AVC_DEBUG_LNB_CONTROL) + ", TUNE QPSK = " __stringify(AVC_DEBUG_TUNE_QPSK) + ", TUNE QPSK2 = " __stringify(AVC_DEBUG_TUNE_QPSK2) + ", HOST2CA = " __stringify(AVC_DEBUG_HOST2CA) + ", CA2HOST = " __stringify(AVC_DEBUG_CA2HOST) + "; Application sent PMT = " __stringify(AVC_DEBUG_APPLICATION_PMT) + ", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS) + ", or a combination, or all = -1)"); + +/* + * This is a workaround since there is no vendor specific command to retrieve + * ca_info using AVC. If this parameter is not used, ca_system_id will be + * filled with application_manufacturer from ca_app_info. + * Digital Everywhere have said that adding ca_info is on their TODO list. + */ +static unsigned int num_fake_ca_system_ids; +static int fake_ca_system_ids[4] = { -1, -1, -1, -1 }; +module_param_array(fake_ca_system_ids, int, &num_fake_ca_system_ids, 0644); +MODULE_PARM_DESC(fake_ca_system_ids, "If your CAM application manufacturer " + "does not have the same ca_system_id as your CAS, you can " + "override what ca_system_ids are presented to the " + "application by setting this field to an array of ids."); + +static const char *debug_fcp_ctype(unsigned int ctype) +{ + static const char *ctypes[] = { + [0x0] = "CONTROL", [0x1] = "STATUS", + [0x2] = "SPECIFIC INQUIRY", [0x3] = "NOTIFY", + [0x4] = "GENERAL INQUIRY", [0x8] = "NOT IMPLEMENTED", + [0x9] = "ACCEPTED", [0xa] = "REJECTED", + [0xb] = "IN TRANSITION", [0xc] = "IMPLEMENTED/STABLE", + [0xd] = "CHANGED", [0xf] = "INTERIM", + }; + const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL; + + return ret ? ret : "?"; +} + +static const char *debug_fcp_opcode(unsigned int opcode, + const u8 *data, int length) +{ + switch (opcode) { + case AVC_OPCODE_VENDOR: + break; + case AVC_OPCODE_READ_DESCRIPTOR: + return avc_debug & AVC_DEBUG_READ_DESCRIPTOR ? + "ReadDescriptor" : NULL; + case AVC_OPCODE_DSIT: + return avc_debug & AVC_DEBUG_DSIT ? + "DirectSelectInfo.Type" : NULL; + case AVC_OPCODE_DSD: + return avc_debug & AVC_DEBUG_DSD ? "DirectSelectData" : NULL; + default: + return "Unknown"; + } + + if (length < 7 || + data[3] != SFE_VENDOR_DE_COMPANYID_0 || + data[4] != SFE_VENDOR_DE_COMPANYID_1 || + data[5] != SFE_VENDOR_DE_COMPANYID_2) + return "Vendor/Unknown"; + + switch (data[6]) { + case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL: + return avc_debug & AVC_DEBUG_REGISTER_REMOTE_CONTROL ? + "RegisterRC" : NULL; + case SFE_VENDOR_OPCODE_LNB_CONTROL: + return avc_debug & AVC_DEBUG_LNB_CONTROL ? "LNBControl" : NULL; + case SFE_VENDOR_OPCODE_TUNE_QPSK: + return avc_debug & AVC_DEBUG_TUNE_QPSK ? "TuneQPSK" : NULL; + case SFE_VENDOR_OPCODE_TUNE_QPSK2: + return avc_debug & AVC_DEBUG_TUNE_QPSK2 ? "TuneQPSK2" : NULL; + case SFE_VENDOR_OPCODE_HOST2CA: + return avc_debug & AVC_DEBUG_HOST2CA ? "Host2CA" : NULL; + case SFE_VENDOR_OPCODE_CA2HOST: + return avc_debug & AVC_DEBUG_CA2HOST ? "CA2Host" : NULL; + } + return "Vendor/Unknown"; +} + +static void debug_fcp(const u8 *data, int length) +{ + unsigned int subunit_type, subunit_id, opcode; + const char *op, *prefix; + + prefix = data[0] > 7 ? "FCP <- " : "FCP -> "; + subunit_type = data[1] >> 3; + subunit_id = data[1] & 7; + opcode = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2]; + op = debug_fcp_opcode(opcode, data, length); + + if (op) { + printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n", + prefix, subunit_type, subunit_id, length, + debug_fcp_ctype(data[0]), op); + if (avc_debug & AVC_DEBUG_FCP_PAYLOADS) + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE, + 16, 1, data, length, false); + } +} + +static void debug_pmt(char *msg, int length) +{ + printk(KERN_INFO "APP PMT -> l=%d\n", length); + print_hex_dump(KERN_INFO, "APP PMT -> ", DUMP_PREFIX_NONE, + 16, 1, msg, length, false); +} + +static int avc_write(struct firedtv *fdtv) +{ + int err, retry; + + fdtv->avc_reply_received = false; + + for (retry = 0; retry < 6; retry++) { + if (unlikely(avc_debug)) + debug_fcp(fdtv->avc_data, fdtv->avc_data_length); + + err = fdtv_write(fdtv, FCP_COMMAND_REGISTER, + fdtv->avc_data, fdtv->avc_data_length); + if (err) { + dev_err(fdtv->device, "FCP command write failed\n"); + + return err; + } + + /* + * AV/C specs say that answers should be sent within 150 ms. + * Time out after 200 ms. + */ + if (wait_event_timeout(fdtv->avc_wait, + fdtv->avc_reply_received, + msecs_to_jiffies(200)) != 0) + return 0; + } + dev_err(fdtv->device, "FCP response timed out\n"); + + return -ETIMEDOUT; +} + +static bool is_register_rc(struct avc_response_frame *r) +{ + return r->opcode == AVC_OPCODE_VENDOR && + r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && + r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && + r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && + r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; +} + +int avc_recv(struct firedtv *fdtv, void *data, size_t length) +{ + struct avc_response_frame *r = data; + + if (unlikely(avc_debug)) + debug_fcp(data, length); + + if (length >= 8 && is_register_rc(r)) { + switch (r->response) { + case AVC_RESPONSE_CHANGED: + fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]); + schedule_work(&fdtv->remote_ctrl_work); + break; + case AVC_RESPONSE_INTERIM: + if (is_register_rc((void *)fdtv->avc_data)) + goto wake; + break; + default: + dev_info(fdtv->device, + "remote control result = %d\n", r->response); + } + return 0; + } + + if (fdtv->avc_reply_received) { + dev_err(fdtv->device, "out-of-order AVC response, ignored\n"); + return -EIO; + } + + memcpy(fdtv->avc_data, data, length); + fdtv->avc_data_length = length; +wake: + fdtv->avc_reply_received = true; + wake_up(&fdtv->avc_wait); + + return 0; +} + +static int add_pid_filter(struct firedtv *fdtv, u8 *operand) +{ + int i, n, pos = 1; + + for (i = 0, n = 0; i < 16; i++) { + if (test_bit(i, &fdtv->channel_active)) { + operand[pos++] = 0x13; /* flowfunction relay */ + operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */ + operand[pos++] = (fdtv->channel_pid[i] >> 8) & 0x1f; + operand[pos++] = fdtv->channel_pid[i] & 0xff; + operand[pos++] = 0x00; /* tableID */ + operand[pos++] = 0x00; /* filter_length */ + n++; + } + } + operand[0] = n; + + return pos; +} + +/* + * tuning command for setting the relative LNB frequency + * (not supported by the AVC standard) + */ +static int avc_tuner_tuneqpsk(struct firedtv *fdtv, + struct dvb_frontend_parameters *params) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + if (fdtv->type == FIREDTV_DVB_S2) + c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK2; + else + c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; + + c->operand[4] = (params->frequency >> 24) & 0xff; + c->operand[5] = (params->frequency >> 16) & 0xff; + c->operand[6] = (params->frequency >> 8) & 0xff; + c->operand[7] = params->frequency & 0xff; + + c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; + c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; + + switch (params->u.qpsk.fec_inner) { + case FEC_1_2: c->operand[10] = 0x1; break; + case FEC_2_3: c->operand[10] = 0x2; break; + case FEC_3_4: c->operand[10] = 0x3; break; + case FEC_5_6: c->operand[10] = 0x4; break; + case FEC_7_8: c->operand[10] = 0x5; break; + case FEC_4_5: + case FEC_8_9: + case FEC_AUTO: + default: c->operand[10] = 0x0; + } + + if (fdtv->voltage == 0xff) + c->operand[11] = 0xff; + else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */ + c->operand[11] = 0; + else + c->operand[11] = 1; + + if (fdtv->tone == 0xff) + c->operand[12] = 0xff; + else if (fdtv->tone == SEC_TONE_ON) /* band */ + c->operand[12] = 1; + else + c->operand[12] = 0; + + if (fdtv->type == FIREDTV_DVB_S2) { + if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) { + switch (fdtv->fe.dtv_property_cache.modulation) { + case QAM_16: c->operand[13] = 0x1; break; + case QPSK: c->operand[13] = 0x2; break; + case PSK_8: c->operand[13] = 0x3; break; + default: c->operand[13] = 0x2; break; + } + switch (fdtv->fe.dtv_property_cache.rolloff) { + case ROLLOFF_AUTO: c->operand[14] = 0x2; break; + case ROLLOFF_35: c->operand[14] = 0x2; break; + case ROLLOFF_20: c->operand[14] = 0x0; break; + case ROLLOFF_25: c->operand[14] = 0x1; break; + /* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */ + } + switch (fdtv->fe.dtv_property_cache.pilot) { + case PILOT_AUTO: c->operand[15] = 0x0; break; + case PILOT_OFF: c->operand[15] = 0x0; break; + case PILOT_ON: c->operand[15] = 0x1; break; + } + } else { + c->operand[13] = 0x1; /* auto modulation */ + c->operand[14] = 0xff; /* disable rolloff */ + c->operand[15] = 0xff; /* disable pilot */ + } + return 16; + } else { + return 13; + } +} + +static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, + struct dvb_frontend_parameters *params) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + + c->opcode = AVC_OPCODE_DSD; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0x20; /* system id = DVB */ + c->operand[3] = 0x00; /* antenna number */ + c->operand[4] = 0x11; /* system_specific_multiplex selection_length */ + + /* multiplex_valid_flags, high byte */ + c->operand[5] = 0 << 7 /* reserved */ + | 0 << 6 /* Polarisation */ + | 0 << 5 /* Orbital_Pos */ + | 1 << 4 /* Frequency */ + | 1 << 3 /* Symbol_Rate */ + | 0 << 2 /* FEC_outer */ + | (params->u.qam.fec_inner != FEC_AUTO ? 1 << 1 : 0) + | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0); + + /* multiplex_valid_flags, low byte */ + c->operand[6] = 0 << 7 /* NetworkID */ + | 0 << 0 /* reserved */ ; + + c->operand[7] = 0x00; + c->operand[8] = 0x00; + c->operand[9] = 0x00; + c->operand[10] = 0x00; + + c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); + c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff; + c->operand[13] = (params->frequency / 4000) & 0xff; + c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; + c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; + c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; + c->operand[17] = 0x00; + + switch (params->u.qpsk.fec_inner) { + case FEC_1_2: c->operand[18] = 0x1; break; + case FEC_2_3: c->operand[18] = 0x2; break; + case FEC_3_4: c->operand[18] = 0x3; break; + case FEC_5_6: c->operand[18] = 0x4; break; + case FEC_7_8: c->operand[18] = 0x5; break; + case FEC_8_9: c->operand[18] = 0x6; break; + case FEC_4_5: c->operand[18] = 0x8; break; + case FEC_AUTO: + default: c->operand[18] = 0x0; + } + + switch (params->u.qam.modulation) { + case QAM_16: c->operand[19] = 0x08; break; + case QAM_32: c->operand[19] = 0x10; break; + case QAM_64: c->operand[19] = 0x18; break; + case QAM_128: c->operand[19] = 0x20; break; + case QAM_256: c->operand[19] = 0x28; break; + case QAM_AUTO: + default: c->operand[19] = 0x00; + } + + c->operand[20] = 0x00; + c->operand[21] = 0x00; + + return 22 + add_pid_filter(fdtv, &c->operand[22]); +} + +static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, + struct dvb_frontend_parameters *params) +{ + struct dvb_ofdm_parameters *ofdm = ¶ms->u.ofdm; + struct avc_command_frame *c = (void *)fdtv->avc_data; + + c->opcode = AVC_OPCODE_DSD; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0x20; /* system id = DVB */ + c->operand[3] = 0x00; /* antenna number */ + c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */ + + /* multiplex_valid_flags, high byte */ + c->operand[5] = + 0 << 7 /* reserved */ + | 1 << 6 /* CenterFrequency */ + | (ofdm->bandwidth != BANDWIDTH_AUTO ? 1 << 5 : 0) + | (ofdm->constellation != QAM_AUTO ? 1 << 4 : 0) + | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0) + | (ofdm->code_rate_HP != FEC_AUTO ? 1 << 2 : 0) + | (ofdm->code_rate_LP != FEC_AUTO ? 1 << 1 : 0) + | (ofdm->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0); + + /* multiplex_valid_flags, low byte */ + c->operand[6] = + 0 << 7 /* NetworkID */ + | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0) + | 0 << 5 /* OtherFrequencyFlag */ + | 0 << 0 /* reserved */ ; + + c->operand[7] = 0x0; + c->operand[8] = (params->frequency / 10) >> 24; + c->operand[9] = ((params->frequency / 10) >> 16) & 0xff; + c->operand[10] = ((params->frequency / 10) >> 8) & 0xff; + c->operand[11] = (params->frequency / 10) & 0xff; + + switch (ofdm->bandwidth) { + case BANDWIDTH_7_MHZ: c->operand[12] = 0x20; break; + case BANDWIDTH_8_MHZ: + case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ + case BANDWIDTH_AUTO: + default: c->operand[12] = 0x00; + } + + switch (ofdm->constellation) { + case QAM_16: c->operand[13] = 1 << 6; break; + case QAM_64: c->operand[13] = 2 << 6; break; + case QPSK: + default: c->operand[13] = 0x00; + } + + switch (ofdm->hierarchy_information) { + case HIERARCHY_1: c->operand[13] |= 1 << 3; break; + case HIERARCHY_2: c->operand[13] |= 2 << 3; break; + case HIERARCHY_4: c->operand[13] |= 3 << 3; break; + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + default: break; + } + + switch (ofdm->code_rate_HP) { + case FEC_2_3: c->operand[13] |= 1; break; + case FEC_3_4: c->operand[13] |= 2; break; + case FEC_5_6: c->operand[13] |= 3; break; + case FEC_7_8: c->operand[13] |= 4; break; + case FEC_1_2: + default: break; + } + + switch (ofdm->code_rate_LP) { + case FEC_2_3: c->operand[14] = 1 << 5; break; + case FEC_3_4: c->operand[14] = 2 << 5; break; + case FEC_5_6: c->operand[14] = 3 << 5; break; + case FEC_7_8: c->operand[14] = 4 << 5; break; + case FEC_1_2: + default: c->operand[14] = 0x00; break; + } + + switch (ofdm->guard_interval) { + case GUARD_INTERVAL_1_16: c->operand[14] |= 1 << 3; break; + case GUARD_INTERVAL_1_8: c->operand[14] |= 2 << 3; break; + case GUARD_INTERVAL_1_4: c->operand[14] |= 3 << 3; break; + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + default: break; + } + + switch (ofdm->transmission_mode) { + case TRANSMISSION_MODE_8K: c->operand[14] |= 1 << 1; break; + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + default: break; + } + + c->operand[15] = 0x00; /* network_ID[0] */ + c->operand[16] = 0x00; /* network_ID[1] */ + + return 17 + add_pid_filter(fdtv, &c->operand[17]); +} + +int avc_tuner_dsd(struct firedtv *fdtv, + struct dvb_frontend_parameters *params) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + int pos, ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + + switch (fdtv->type) { + case FIREDTV_DVB_S: + case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break; + case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break; + case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break; + default: + BUG(); + } + pad_operands(c, pos); + + fdtv->avc_data_length = ALIGN(3 + pos, 4); + ret = avc_write(fdtv); +#if 0 + /* + * FIXME: + * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller. + * Check for AVC_RESPONSE_ACCEPTED here instead? + */ + if (status) + *status = r->operand[2]; +#endif + mutex_unlock(&fdtv->avc_mutex); + + if (ret == 0) + msleep(500); + + return ret; +} + +int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + int ret, pos, k; + + if (pidc > 16 && pidc != 0xff) + return -EINVAL; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_DSD; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0x20; /* system id = DVB */ + c->operand[3] = 0x00; /* antenna number */ + c->operand[4] = 0x00; /* system_specific_multiplex selection_length */ + c->operand[5] = pidc; /* Nr_of_dsd_sel_specs */ + + pos = 6; + if (pidc != 0xff) + for (k = 0; k < pidc; k++) { + c->operand[pos++] = 0x13; /* flowfunction relay */ + c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */ + c->operand[pos++] = (pid[k] >> 8) & 0x1f; + c->operand[pos++] = pid[k] & 0xff; + c->operand[pos++] = 0x00; /* tableID */ + c->operand[pos++] = 0x00; /* filter_length */ + } + pad_operands(c, pos); + + fdtv->avc_data_length = ALIGN(3 + pos, 4); + ret = avc_write(fdtv); + + /* FIXME: check response code? */ + + mutex_unlock(&fdtv->avc_mutex); + + if (ret == 0) + msleep(50); + + return ret; +} + +int avc_tuner_get_ts(struct firedtv *fdtv) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + int ret, sl; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_DSIT; + + sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0xff; /* status */ + c->operand[3] = 0x20; /* system id = DVB */ + c->operand[4] = 0x00; /* antenna number */ + c->operand[5] = 0x0; /* system_specific_search_flags */ + c->operand[6] = sl; /* system_specific_multiplex selection_length */ + /* + * operand[7]: valid_flags[0] + * operand[8]: valid_flags[1] + * operand[7 + sl]: nr_of_dsit_sel_specs (always 0) + */ + clear_operands(c, 7, 24); + + fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28; + ret = avc_write(fdtv); + + /* FIXME: check response code? */ + + mutex_unlock(&fdtv->avc_mutex); + + if (ret == 0) + msleep(250); + + return ret; +} + +int avc_identify_subunit(struct firedtv *fdtv) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + struct avc_response_frame *r = (void *)fdtv->avc_data; + int ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_READ_DESCRIPTOR; + + c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER; + c->operand[1] = 0xff; + c->operand[2] = 0x00; + c->operand[3] = 0x00; /* length highbyte */ + c->operand[4] = 0x08; /* length lowbyte */ + c->operand[5] = 0x00; /* offset highbyte */ + c->operand[6] = 0x0d; /* offset lowbyte */ + clear_operands(c, 7, 8); /* padding */ + + fdtv->avc_data_length = 12; + ret = avc_write(fdtv); + if (ret < 0) + goto out; + + if ((r->response != AVC_RESPONSE_STABLE && + r->response != AVC_RESPONSE_ACCEPTED) || + (r->operand[3] << 8) + r->operand[4] != 8) { + dev_err(fdtv->device, "cannot read subunit identifier\n"); + ret = -EINVAL; + } +out: + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +#define SIZEOF_ANTENNA_INPUT_INFO 22 + +int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + struct avc_response_frame *r = (void *)fdtv->avc_data; + int length, ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_READ_DESCRIPTOR; + + c->operand[0] = DESCRIPTOR_TUNER_STATUS; + c->operand[1] = 0xff; /* read_result_status */ + /* + * operand[2]: reserved + * operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8 + * operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff + */ + clear_operands(c, 2, 31); + + fdtv->avc_data_length = 12; + ret = avc_write(fdtv); + if (ret < 0) + goto out; + + if (r->response != AVC_RESPONSE_STABLE && + r->response != AVC_RESPONSE_ACCEPTED) { + dev_err(fdtv->device, "cannot read tuner status\n"); + ret = -EINVAL; + goto out; + } + + length = r->operand[9]; + if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) { + dev_err(fdtv->device, "got invalid tuner status\n"); + ret = -EINVAL; + goto out; + } + + stat->active_system = r->operand[10]; + stat->searching = r->operand[11] >> 7 & 1; + stat->moving = r->operand[11] >> 6 & 1; + stat->no_rf = r->operand[11] >> 5 & 1; + stat->input = r->operand[12] >> 7 & 1; + stat->selected_antenna = r->operand[12] & 0x7f; + stat->ber = r->operand[13] << 24 | + r->operand[14] << 16 | + r->operand[15] << 8 | + r->operand[16]; + stat->signal_strength = r->operand[17]; + stat->raster_frequency = r->operand[18] >> 6 & 2; + stat->rf_frequency = (r->operand[18] & 0x3f) << 16 | + r->operand[19] << 8 | + r->operand[20]; + stat->man_dep_info_length = r->operand[21]; + stat->front_end_error = r->operand[22] >> 4 & 1; + stat->antenna_error = r->operand[22] >> 3 & 1; + stat->front_end_power_status = r->operand[22] >> 1 & 1; + stat->power_supply = r->operand[22] & 1; + stat->carrier_noise_ratio = r->operand[23] << 8 | + r->operand[24]; + stat->power_supply_voltage = r->operand[27]; + stat->antenna_voltage = r->operand[28]; + stat->firewire_bus_voltage = r->operand[29]; + stat->ca_mmi = r->operand[30] & 1; + stat->ca_pmt_reply = r->operand[31] >> 7 & 1; + stat->ca_date_time_request = r->operand[31] >> 6 & 1; + stat->ca_application_info = r->operand[31] >> 5 & 1; + stat->ca_module_present_status = r->operand[31] >> 4 & 1; + stat->ca_dvb_flag = r->operand[31] >> 3 & 1; + stat->ca_error_flag = r->operand[31] >> 2 & 1; + stat->ca_initialization_status = r->operand[31] >> 1 & 1; +out: + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + struct avc_response_frame *r = (void *)fdtv->avc_data; + int pos, j, k, ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL; + c->operand[4] = voltage; + c->operand[5] = nrdiseq; + + pos = 6; + for (j = 0; j < nrdiseq; j++) { + c->operand[pos++] = diseqcmd[j].msg_len; + + for (k = 0; k < diseqcmd[j].msg_len; k++) + c->operand[pos++] = diseqcmd[j].msg[k]; + } + c->operand[pos++] = burst; + c->operand[pos++] = conttone; + pad_operands(c, pos); + + fdtv->avc_data_length = ALIGN(3 + pos, 4); + ret = avc_write(fdtv); + if (ret < 0) + goto out; + + if (r->response != AVC_RESPONSE_ACCEPTED) { + dev_err(fdtv->device, "LNB control failed\n"); + ret = -EINVAL; + } +out: + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +int avc_register_remote_control(struct firedtv *fdtv) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + int ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_NOTIFY; + c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; + c->operand[4] = 0; /* padding */ + + fdtv->avc_data_length = 8; + ret = avc_write(fdtv); + + /* FIXME: check response code? */ + + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +void avc_remote_ctrl_work(struct work_struct *work) +{ + struct firedtv *fdtv = + container_of(work, struct firedtv, remote_ctrl_work); + + /* Should it be rescheduled in failure cases? */ + avc_register_remote_control(fdtv); +} + +#if 0 /* FIXME: unused */ +int avc_tuner_host2ca(struct firedtv *fdtv) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + int ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ + clear_operands(c, 6, 8); + + fdtv->avc_data_length = 12; + ret = avc_write(fdtv); + + /* FIXME: check response code? */ + + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} +#endif + +static int get_ca_object_pos(struct avc_response_frame *r) +{ + int length = 1; + + /* Check length of length field */ + if (r->operand[7] & 0x80) + length = (r->operand[7] & 0x7f) + 1; + return length + 7; +} + +static int get_ca_object_length(struct avc_response_frame *r) +{ +#if 0 /* FIXME: unused */ + int size = 0; + int i; + + if (r->operand[7] & 0x80) + for (i = 0; i < (r->operand[7] & 0x7f); i++) { + size <<= 8; + size += r->operand[8 + i]; + } +#endif + return r->operand[7]; +} + +int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + struct avc_response_frame *r = (void *)fdtv->avc_data; + int pos, ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ + clear_operands(c, 6, LAST_OPERAND); + + fdtv->avc_data_length = 12; + ret = avc_write(fdtv); + if (ret < 0) + goto out; + + /* FIXME: check response code and validate response data */ + + pos = get_ca_object_pos(r); + app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff; + app_info[1] = (EN50221_TAG_APP_INFO >> 8) & 0xff; + app_info[2] = (EN50221_TAG_APP_INFO >> 0) & 0xff; + app_info[3] = 6 + r->operand[pos + 4]; + app_info[4] = 0x01; + memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]); + *len = app_info[3] + 4; +out: + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + struct avc_response_frame *r = (void *)fdtv->avc_data; + int i, pos, ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ + clear_operands(c, 6, LAST_OPERAND); + + fdtv->avc_data_length = 12; + ret = avc_write(fdtv); + if (ret < 0) + goto out; + + /* FIXME: check response code and validate response data */ + + pos = get_ca_object_pos(r); + app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff; + app_info[1] = (EN50221_TAG_CA_INFO >> 8) & 0xff; + app_info[2] = (EN50221_TAG_CA_INFO >> 0) & 0xff; + if (num_fake_ca_system_ids == 0) { + app_info[3] = 2; + app_info[4] = r->operand[pos + 0]; + app_info[5] = r->operand[pos + 1]; + } else { + app_info[3] = num_fake_ca_system_ids * 2; + for (i = 0; i < num_fake_ca_system_ids; i++) { + app_info[4 + i * 2] = + (fake_ca_system_ids[i] >> 8) & 0xff; + app_info[5 + i * 2] = fake_ca_system_ids[i] & 0xff; + } + } + *len = app_info[3] + 4; +out: + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +int avc_ca_reset(struct firedtv *fdtv) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + int ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */ + c->operand[6] = 0; /* more/last */ + c->operand[7] = 1; /* length */ + c->operand[8] = 0; /* force hardware reset */ + + fdtv->avc_data_length = 12; + ret = avc_write(fdtv); + + /* FIXME: check response code? */ + + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + struct avc_response_frame *r = (void *)fdtv->avc_data; + int list_management; + int program_info_length; + int pmt_cmd_id; + int read_pos; + int write_pos; + int es_info_length; + int crc32_csum; + int ret; + + if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT)) + debug_pmt(msg, length); + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) { + dev_info(fdtv->device, "forcing list_management to ONLY\n"); + msg[0] = EN50221_LIST_MANAGEMENT_ONLY; + } + /* We take the cmd_id from the programme level only! */ + list_management = msg[0]; + program_info_length = ((msg[4] & 0x0f) << 8) + msg[5]; + if (program_info_length > 0) + program_info_length--; /* Remove pmt_cmd_id */ + pmt_cmd_id = msg[6]; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */ + c->operand[6] = 0; /* more/last */ + /* Use three bytes for length field in case length > 127 */ + c->operand[10] = list_management; + c->operand[11] = 0x01; /* pmt_cmd=OK_descramble */ + + /* TS program map table */ + + c->operand[12] = 0x02; /* Table id=2 */ + c->operand[13] = 0x80; /* Section syntax + length */ + + c->operand[15] = msg[1]; /* Program number */ + c->operand[16] = msg[2]; + c->operand[17] = msg[3]; /* Version number and current/next */ + c->operand[18] = 0x00; /* Section number=0 */ + c->operand[19] = 0x00; /* Last section number=0 */ + c->operand[20] = 0x1f; /* PCR_PID=1FFF */ + c->operand[21] = 0xff; + c->operand[22] = (program_info_length >> 8); /* Program info length */ + c->operand[23] = (program_info_length & 0xff); + + /* CA descriptors at programme level */ + read_pos = 6; + write_pos = 24; + if (program_info_length > 0) { + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(fdtv->device, + "invalid pmt_cmd_id %d\n", pmt_cmd_id); + + memcpy(&c->operand[write_pos], &msg[read_pos], + program_info_length); + read_pos += program_info_length; + write_pos += program_info_length; + } + while (read_pos < length) { + c->operand[write_pos++] = msg[read_pos++]; + c->operand[write_pos++] = msg[read_pos++]; + c->operand[write_pos++] = msg[read_pos++]; + es_info_length = + ((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1]; + read_pos += 2; + if (es_info_length > 0) + es_info_length--; /* Remove pmt_cmd_id */ + c->operand[write_pos++] = es_info_length >> 8; + c->operand[write_pos++] = es_info_length & 0xff; + if (es_info_length > 0) { + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(fdtv->device, "invalid pmt_cmd_id %d " + "at stream level\n", pmt_cmd_id); + + memcpy(&c->operand[write_pos], &msg[read_pos], + es_info_length); + read_pos += es_info_length; + write_pos += es_info_length; + } + } + write_pos += 4; /* CRC */ + + c->operand[7] = 0x82; + c->operand[8] = (write_pos - 10) >> 8; + c->operand[9] = (write_pos - 10) & 0xff; + c->operand[14] = write_pos - 15; + + crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1); + c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff; + c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff; + c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff; + c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff; + pad_operands(c, write_pos); + + fdtv->avc_data_length = ALIGN(3 + write_pos, 4); + ret = avc_write(fdtv); + if (ret < 0) + goto out; + + if (r->response != AVC_RESPONSE_ACCEPTED) { + dev_err(fdtv->device, + "CA PMT failed with response 0x%x\n", r->response); + ret = -EFAULT; + } +out: + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +int avc_ca_get_time_date(struct firedtv *fdtv, int *interval) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + struct avc_response_frame *r = (void *)fdtv->avc_data; + int ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */ + clear_operands(c, 6, LAST_OPERAND); + + fdtv->avc_data_length = 12; + ret = avc_write(fdtv); + if (ret < 0) + goto out; + + /* FIXME: check response code and validate response data */ + + *interval = r->operand[get_ca_object_pos(r)]; +out: + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +int avc_ca_enter_menu(struct firedtv *fdtv) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + int ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; + clear_operands(c, 6, 8); + + fdtv->avc_data_length = 12; + ret = avc_write(fdtv); + + /* FIXME: check response code? */ + + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len) +{ + struct avc_command_frame *c = (void *)fdtv->avc_data; + struct avc_response_frame *r = (void *)fdtv->avc_data; + int ret; + + mutex_lock(&fdtv->avc_mutex); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_MMI; + clear_operands(c, 6, LAST_OPERAND); + + fdtv->avc_data_length = 12; + ret = avc_write(fdtv); + if (ret < 0) + goto out; + + /* FIXME: check response code and validate response data */ + + *len = get_ca_object_length(r); + memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len); +out: + mutex_unlock(&fdtv->avc_mutex); + + return ret; +} + +#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL + +static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data) +{ + int ret; + + ret = fdtv_read(fdtv, addr, data); + if (ret < 0) + dev_err(fdtv->device, "CMP: read I/O error\n"); + + return ret; +} + +static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[]) +{ + int ret; + + ret = fdtv_lock(fdtv, addr, data); + if (ret < 0) + dev_err(fdtv->device, "CMP: lock I/O error\n"); + + return ret; +} + +static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift) +{ + return (be32_to_cpu(opcr) >> shift) & mask; +} + +static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift) +{ + *opcr &= ~cpu_to_be32(mask << shift); + *opcr |= cpu_to_be32((value & mask) << shift); +} + +#define get_opcr_online(v) get_opcr((v), 0x1, 31) +#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24) +#define get_opcr_channel(v) get_opcr((v), 0x3f, 16) + +#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24) +#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16) +#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14) +#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10) + +int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel) +{ + __be32 old_opcr, opcr[2]; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + int ret; + + ret = cmp_read(fdtv, opcr_address, opcr); + if (ret < 0) + return ret; + +repeat: + if (!get_opcr_online(*opcr)) { + dev_err(fdtv->device, "CMP: output offline\n"); + return -EBUSY; + } + + old_opcr = *opcr; + + if (get_opcr_p2p_connections(*opcr)) { + if (get_opcr_channel(*opcr) != channel) { + dev_err(fdtv->device, "CMP: cannot change channel\n"); + return -EBUSY; + } + dev_info(fdtv->device, "CMP: overlaying connection\n"); + + /* We don't allocate isochronous resources. */ + } else { + set_opcr_channel(opcr, channel); + set_opcr_data_rate(opcr, 2); /* S400 */ + + /* FIXME: this is for the worst case - optimize */ + set_opcr_overhead_id(opcr, 0); + + /* FIXME: allocate isochronous channel and bandwidth at IRM */ + } + + set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1); + + opcr[1] = *opcr; + opcr[0] = old_opcr; + + ret = cmp_lock(fdtv, opcr_address, opcr); + if (ret < 0) + return ret; + + if (old_opcr != *opcr) { + /* + * FIXME: if old_opcr.P2P_Connections > 0, + * deallocate isochronous channel and bandwidth at IRM + */ + + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + return -EBUSY; + } + + return 0; +} + +void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel) +{ + __be32 old_opcr, opcr[2]; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + + if (cmp_read(fdtv, opcr_address, opcr) < 0) + return; + +repeat: + if (!get_opcr_online(*opcr) || !get_opcr_p2p_connections(*opcr) || + get_opcr_channel(*opcr) != channel) { + dev_err(fdtv->device, "CMP: no connection to break\n"); + return; + } + + old_opcr = *opcr; + set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) - 1); + + opcr[1] = *opcr; + opcr[0] = old_opcr; + + if (cmp_lock(fdtv, opcr_address, opcr) < 0) + return; + + if (old_opcr != *opcr) { + /* + * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last + * owner, deallocate isochronous channel and bandwidth at IRM + * if (...) + * fdtv->backend->dealloc_resources(fdtv, channel, bw); + */ + + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-ci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-ci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-ci.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-ci.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,260 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid + * + * 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, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include + +#include "firedtv.h" + +#define EN50221_TAG_APP_INFO_ENQUIRY 0x9f8020 +#define EN50221_TAG_CA_INFO_ENQUIRY 0x9f8030 +#define EN50221_TAG_CA_PMT 0x9f8032 +#define EN50221_TAG_ENTER_MENU 0x9f8022 + +static int fdtv_ca_ready(struct firedtv_tuner_status *stat) +{ + return stat->ca_initialization_status == 1 && + stat->ca_error_flag == 0 && + stat->ca_dvb_flag == 1 && + stat->ca_module_present_status == 1; +} + +static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat) +{ + int flags = 0; + + if (stat->ca_module_present_status == 1) + flags |= CA_CI_MODULE_PRESENT; + if (stat->ca_initialization_status == 1 && + stat->ca_error_flag == 0 && + stat->ca_dvb_flag == 1) + flags |= CA_CI_MODULE_READY; + return flags; +} + +static int fdtv_ca_reset(struct firedtv *fdtv) +{ + return avc_ca_reset(fdtv) ? -EFAULT : 0; +} + +static int fdtv_ca_get_caps(void *arg) +{ + struct ca_caps *cap = arg; + + cap->slot_num = 1; + cap->slot_type = CA_CI; + cap->descr_num = 1; + cap->descr_type = CA_ECD; + return 0; +} + +static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg) +{ + struct firedtv_tuner_status stat; + struct ca_slot_info *slot = arg; + + if (avc_tuner_status(fdtv, &stat)) + return -EFAULT; + + if (slot->num != 0) + return -EFAULT; + + slot->type = CA_CI; + slot->flags = fdtv_get_ca_flags(&stat); + return 0; +} + +static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *reply = arg; + + return avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; +} + +static int fdtv_ca_info(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *reply = arg; + + return avc_ca_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; +} + +static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *reply = arg; + + return avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; +} + +static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg) +{ + struct firedtv_tuner_status stat; + int err; + + switch (fdtv->ca_last_command) { + case EN50221_TAG_APP_INFO_ENQUIRY: + err = fdtv_ca_app_info(fdtv, arg); + break; + case EN50221_TAG_CA_INFO_ENQUIRY: + err = fdtv_ca_info(fdtv, arg); + break; + default: + if (avc_tuner_status(fdtv, &stat)) + err = -EFAULT; + else if (stat.ca_mmi == 1) + err = fdtv_ca_get_mmi(fdtv, arg); + else { + dev_info(fdtv->device, "unhandled CA message 0x%08x\n", + fdtv->ca_last_command); + err = -EFAULT; + } + } + fdtv->ca_last_command = 0; + return err; +} + +static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *msg = arg; + int data_pos; + int data_length; + int i; + + data_pos = 4; + if (msg->msg[3] & 0x80) { + data_length = 0; + for (i = 0; i < (msg->msg[3] & 0x7f); i++) + data_length = (data_length << 8) + msg->msg[data_pos++]; + } else { + data_length = msg->msg[3]; + } + + return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? -EFAULT : 0; +} + +static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *msg = arg; + int err; + + /* Do we need a semaphore for this? */ + fdtv->ca_last_command = + (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2]; + switch (fdtv->ca_last_command) { + case EN50221_TAG_CA_PMT: + err = fdtv_ca_pmt(fdtv, arg); + break; + case EN50221_TAG_APP_INFO_ENQUIRY: + /* handled in ca_get_msg */ + err = 0; + break; + case EN50221_TAG_CA_INFO_ENQUIRY: + /* handled in ca_get_msg */ + err = 0; + break; + case EN50221_TAG_ENTER_MENU: + err = avc_ca_enter_menu(fdtv); + break; + default: + dev_err(fdtv->device, "unhandled CA message 0x%08x\n", + fdtv->ca_last_command); + err = -EFAULT; + } + return err; +} + +static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg) +{ + struct dvb_device *dvbdev = file->private_data; + struct firedtv *fdtv = dvbdev->priv; + struct firedtv_tuner_status stat; + int err; + + switch (cmd) { + case CA_RESET: + err = fdtv_ca_reset(fdtv); + break; + case CA_GET_CAP: + err = fdtv_ca_get_caps(arg); + break; + case CA_GET_SLOT_INFO: + err = fdtv_ca_get_slot_info(fdtv, arg); + break; + case CA_GET_MSG: + err = fdtv_ca_get_msg(fdtv, arg); + break; + case CA_SEND_MSG: + err = fdtv_ca_send_msg(fdtv, arg); + break; + default: + dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd); + err = -EOPNOTSUPP; + } + + /* FIXME Is this necessary? */ + avc_tuner_status(fdtv, &stat); + + return err; +} + +static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait) +{ + return POLLIN; +} + +static const struct file_operations fdtv_ca_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_generic_open, + .release = dvb_generic_release, + .poll = fdtv_ca_io_poll, + .llseek = noop_llseek, +}; + +static struct dvb_device fdtv_ca = { + .users = 1, + .readers = 1, + .writers = 1, + .fops = &fdtv_ca_fops, + .kernel_ioctl = fdtv_ca_ioctl, +}; + +int fdtv_ca_register(struct firedtv *fdtv) +{ + struct firedtv_tuner_status stat; + int err; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + if (!fdtv_ca_ready(&stat)) + return -EFAULT; + + err = dvb_register_device(&fdtv->adapter, &fdtv->cadev, + &fdtv_ca, fdtv, DVB_DEVICE_CA); + + if (stat.ca_application_info == 0) + dev_err(fdtv->device, "CaApplicationInfo is not set\n"); + if (stat.ca_date_time_request == 1) + avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval); + + return err; +} + +void fdtv_ca_release(struct firedtv *fdtv) +{ + if (fdtv->cadev) + dvb_unregister_device(fdtv->cadev); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-dvb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,245 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid + * + * 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, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "firedtv.h" + +static int alloc_channel(struct firedtv *fdtv) +{ + int i; + + for (i = 0; i < 16; i++) + if (!__test_and_set_bit(i, &fdtv->channel_active)) + break; + return i; +} + +static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[]) +{ + int i, n; + + for (i = 0, n = 0; i < 16; i++) + if (test_bit(i, &fdtv->channel_active)) + pid[n++] = fdtv->channel_pid[i]; + *pidc = n; +} + +static inline void dealloc_channel(struct firedtv *fdtv, int i) +{ + __clear_bit(i, &fdtv->channel_active); +} + +int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct firedtv *fdtv = dvbdmxfeed->demux->priv; + int pidc, c, ret; + u16 pids[16]; + + switch (dvbdmxfeed->type) { + case DMX_TYPE_TS: + case DMX_TYPE_SEC: + break; + default: + dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n", + dvbdmxfeed->type); + return -EINVAL; + } + + if (mutex_lock_interruptible(&fdtv->demux_mutex)) + return -EINTR; + + if (dvbdmxfeed->type == DMX_TYPE_TS) { + switch (dvbdmxfeed->pes_type) { + case DMX_TS_PES_VIDEO: + case DMX_TS_PES_AUDIO: + case DMX_TS_PES_TELETEXT: + case DMX_TS_PES_PCR: + case DMX_TS_PES_OTHER: + c = alloc_channel(fdtv); + break; + default: + dev_err(fdtv->device, + "can't start dmx feed: invalid pes type %u\n", + dvbdmxfeed->pes_type); + ret = -EINVAL; + goto out; + } + } else { + c = alloc_channel(fdtv); + } + + if (c > 15) { + dev_err(fdtv->device, "can't start dmx feed: busy\n"); + ret = -EBUSY; + goto out; + } + + dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c; + fdtv->channel_pid[c] = dvbdmxfeed->pid; + collect_channels(fdtv, &pidc, pids); + + if (dvbdmxfeed->pid == 8192) { + ret = avc_tuner_get_ts(fdtv); + if (ret) { + dealloc_channel(fdtv, c); + dev_err(fdtv->device, "can't get TS\n"); + goto out; + } + } else { + ret = avc_tuner_set_pids(fdtv, pidc, pids); + if (ret) { + dealloc_channel(fdtv, c); + dev_err(fdtv->device, "can't set PIDs\n"); + goto out; + } + } +out: + mutex_unlock(&fdtv->demux_mutex); + + return ret; +} + +int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *demux = dvbdmxfeed->demux; + struct firedtv *fdtv = demux->priv; + int pidc, c, ret; + u16 pids[16]; + + if (dvbdmxfeed->type == DMX_TYPE_TS && + !((dvbdmxfeed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE))) { + + if (dvbdmxfeed->ts_type & TS_DECODER) { + if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || + !demux->pesfilter[dvbdmxfeed->pes_type]) + return -EINVAL; + + demux->pids[dvbdmxfeed->pes_type] |= 0x8000; + demux->pesfilter[dvbdmxfeed->pes_type] = NULL; + } + + if (!(dvbdmxfeed->ts_type & TS_DECODER && + dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) + return 0; + } + + if (mutex_lock_interruptible(&fdtv->demux_mutex)) + return -EINTR; + + c = (unsigned long)dvbdmxfeed->priv; + dealloc_channel(fdtv, c); + collect_channels(fdtv, &pidc, pids); + + ret = avc_tuner_set_pids(fdtv, pidc, pids); + + mutex_unlock(&fdtv->demux_mutex); + + return ret; +} + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +int fdtv_dvb_register(struct firedtv *fdtv, const char *name) +{ + int err; + + err = dvb_register_adapter(&fdtv->adapter, name, + THIS_MODULE, fdtv->device, adapter_nr); + if (err < 0) + goto fail_log; + + /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/ + fdtv->demux.dmx.capabilities = 0; + + fdtv->demux.priv = fdtv; + fdtv->demux.filternum = 16; + fdtv->demux.feednum = 16; + fdtv->demux.start_feed = fdtv_start_feed; + fdtv->demux.stop_feed = fdtv_stop_feed; + fdtv->demux.write_to_decoder = NULL; + + err = dvb_dmx_init(&fdtv->demux); + if (err) + goto fail_unreg_adapter; + + fdtv->dmxdev.filternum = 16; + fdtv->dmxdev.demux = &fdtv->demux.dmx; + fdtv->dmxdev.capabilities = 0; + + err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter); + if (err) + goto fail_dmx_release; + + fdtv->frontend.source = DMX_FRONTEND_0; + + err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend); + if (err) + goto fail_dmxdev_release; + + err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx, + &fdtv->frontend); + if (err) + goto fail_rem_frontend; + + dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); + + fdtv_frontend_init(fdtv, name); + err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe); + if (err) + goto fail_net_release; + + err = fdtv_ca_register(fdtv); + if (err) + dev_info(fdtv->device, + "Conditional Access Module not enabled\n"); + return 0; + +fail_net_release: + dvb_net_release(&fdtv->dvbnet); + fdtv->demux.dmx.close(&fdtv->demux.dmx); +fail_rem_frontend: + fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); +fail_dmxdev_release: + dvb_dmxdev_release(&fdtv->dmxdev); +fail_dmx_release: + dvb_dmx_release(&fdtv->demux); +fail_unreg_adapter: + dvb_unregister_adapter(&fdtv->adapter); +fail_log: + dev_err(fdtv->device, "DVB initialization failed\n"); + return err; +} + +void fdtv_dvb_unregister(struct firedtv *fdtv) +{ + fdtv_ca_release(fdtv); + dvb_unregister_frontend(&fdtv->fe); + dvb_net_release(&fdtv->dvbnet); + fdtv->demux.dmx.close(&fdtv->demux.dmx); + fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); + dvb_dmxdev_release(&fdtv->dmxdev); + dvb_dmx_release(&fdtv->demux); + dvb_unregister_adapter(&fdtv->adapter); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-fe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,273 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid + * + * 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, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include + +#include "firedtv.h" + +static int fdtv_dvb_init(struct dvb_frontend *fe) +{ + struct firedtv *fdtv = fe->sec_priv; + int err; + + /* FIXME - allocate free channel at IRM */ + fdtv->isochannel = fdtv->adapter.num; + + err = cmp_establish_pp_connection(fdtv, fdtv->subunit, + fdtv->isochannel); + if (err) { + dev_err(fdtv->device, + "could not establish point to point connection\n"); + return err; + } + + return fdtv_start_iso(fdtv); +} + +static int fdtv_sleep(struct dvb_frontend *fe) +{ + struct firedtv *fdtv = fe->sec_priv; + + fdtv_stop_iso(fdtv); + cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel); + fdtv->isochannel = -1; + return 0; +} + +#define LNBCONTROL_DONTCARE 0xff + +static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct firedtv *fdtv = fe->sec_priv; + + return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, + LNBCONTROL_DONTCARE, 1, cmd); +} + +static int fdtv_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t minicmd) +{ + return 0; +} + +static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct firedtv *fdtv = fe->sec_priv; + + fdtv->tone = tone; + return 0; +} + +static int fdtv_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct firedtv *fdtv = fe->sec_priv; + + fdtv->voltage = voltage; + return 0; +} + +static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct firedtv *fdtv = fe->sec_priv; + struct firedtv_tuner_status stat; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + if (stat.no_rf) + *status = 0; + else + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; +} + +static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct firedtv *fdtv = fe->sec_priv; + struct firedtv_tuner_status stat; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + *ber = stat.ber; + return 0; +} + +static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct firedtv *fdtv = fe->sec_priv; + struct firedtv_tuner_status stat; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + *strength = stat.signal_strength << 8; + return 0; +} + +static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct firedtv *fdtv = fe->sec_priv; + struct firedtv_tuner_status stat; + + if (avc_tuner_status(fdtv, &stat)) + return -EINVAL; + + /* C/N[dB] = -10 * log10(snr / 65535) */ + *snr = stat.carrier_noise_ratio * 257; + return 0; +} + +static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + return -EOPNOTSUPP; +} + +static int fdtv_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct firedtv *fdtv = fe->sec_priv; + + return avc_tuner_dsd(fdtv, params); +} + +static int fdtv_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + return -EOPNOTSUPP; +} + +static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp) +{ + return 0; +} + +static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp) +{ + return 0; +} + +void fdtv_frontend_init(struct firedtv *fdtv, const char *name) +{ + struct dvb_frontend_ops *ops = &fdtv->fe.ops; + struct dvb_frontend_info *fi = &ops->info; + + ops->init = fdtv_dvb_init; + ops->sleep = fdtv_sleep; + + ops->set_frontend = fdtv_set_frontend; + ops->get_frontend = fdtv_get_frontend; + + ops->get_property = fdtv_get_property; + ops->set_property = fdtv_set_property; + + ops->read_status = fdtv_read_status; + ops->read_ber = fdtv_read_ber; + ops->read_signal_strength = fdtv_read_signal_strength; + ops->read_snr = fdtv_read_snr; + ops->read_ucblocks = fdtv_read_uncorrected_blocks; + + ops->diseqc_send_master_cmd = fdtv_diseqc_send_master_cmd; + ops->diseqc_send_burst = fdtv_diseqc_send_burst; + ops->set_tone = fdtv_set_tone; + ops->set_voltage = fdtv_set_voltage; + + switch (fdtv->type) { + case FIREDTV_DVB_S: + fi->type = FE_QPSK; + + fi->frequency_min = 950000; + fi->frequency_max = 2150000; + fi->frequency_stepsize = 125; + fi->symbol_rate_min = 1000000; + fi->symbol_rate_max = 40000000; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK; + break; + + case FIREDTV_DVB_S2: + fi->type = FE_QPSK; + + fi->frequency_min = 950000; + fi->frequency_max = 2150000; + fi->frequency_stepsize = 125; + fi->symbol_rate_min = 1000000; + fi->symbol_rate_max = 40000000; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_2G_MODULATION; + break; + + case FIREDTV_DVB_C: + fi->type = FE_QAM; + + fi->frequency_min = 47000000; + fi->frequency_max = 866000000; + fi->frequency_stepsize = 62500; + fi->symbol_rate_min = 870000; + fi->symbol_rate_max = 6900000; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO; + break; + + case FIREDTV_DVB_T: + fi->type = FE_OFDM; + + fi->frequency_min = 49000000; + fi->frequency_max = 861000000; + fi->frequency_stepsize = 62500; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_2_3 | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO; + break; + + default: + dev_err(fdtv->device, "no frontend for model type %d\n", + fdtv->type); + } + strcpy(fi->name, name); + + fdtv->fe.dvb = &fdtv->adapter; + fdtv->fe.sec_priv = fdtv; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-fw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-fw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-fw.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-fw.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,430 @@ +/* + * FireDTV driver -- firewire I/O backend + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "firedtv.h" + +static LIST_HEAD(node_list); +static DEFINE_SPINLOCK(node_list_lock); + +static inline struct fw_device *device_of(struct firedtv *fdtv) +{ + return fw_device(fdtv->device->parent); +} + +static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len, + int tcode) +{ + struct fw_device *device = device_of(fdtv); + int rcode, generation = device->generation; + + smp_rmb(); /* node_id vs. generation */ + + rcode = fw_run_transaction(device->card, tcode, device->node_id, + generation, device->max_speed, addr, data, len); + + return rcode != RCODE_COMPLETE ? -EIO : 0; +} + +int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data) +{ + return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP); +} + +int fdtv_read(struct firedtv *fdtv, u64 addr, void *data) +{ + return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST); +} + +int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) +{ + return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST); +} + +#define ISO_HEADER_SIZE 4 +#define CIP_HEADER_SIZE 8 +#define MPEG2_TS_HEADER_SIZE 4 +#define MPEG2_TS_SOURCE_PACKET_SIZE (4 + 188) + +#define MAX_PACKET_SIZE 1024 /* 776, rounded up to 2^n */ +#define PACKETS_PER_PAGE (PAGE_SIZE / MAX_PACKET_SIZE) +#define N_PACKETS 64 /* buffer size */ +#define N_PAGES DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE) +#define IRQ_INTERVAL 16 + +struct fdtv_ir_context { + struct fw_iso_context *context; + struct fw_iso_buffer buffer; + int interrupt_packet; + int current_packet; + char *pages[N_PAGES]; +}; + +static int queue_iso(struct fdtv_ir_context *ctx, int index) +{ + struct fw_iso_packet p; + + p.payload_length = MAX_PACKET_SIZE; + p.interrupt = !(++ctx->interrupt_packet & (IRQ_INTERVAL - 1)); + p.skip = 0; + p.header_length = ISO_HEADER_SIZE; + + return fw_iso_context_queue(ctx->context, &p, &ctx->buffer, + index * MAX_PACKET_SIZE); +} + +static void handle_iso(struct fw_iso_context *context, u32 cycle, + size_t header_length, void *header, void *data) +{ + struct firedtv *fdtv = data; + struct fdtv_ir_context *ctx = fdtv->ir_context; + __be32 *h, *h_end; + int length, err, i = ctx->current_packet; + char *p, *p_end; + + for (h = header, h_end = h + header_length / 4; h < h_end; h++) { + length = be32_to_cpup(h) >> 16; + if (unlikely(length > MAX_PACKET_SIZE)) { + dev_err(fdtv->device, "length = %d\n", length); + length = MAX_PACKET_SIZE; + } + + p = ctx->pages[i / PACKETS_PER_PAGE] + + (i % PACKETS_PER_PAGE) * MAX_PACKET_SIZE; + p_end = p + length; + + for (p += CIP_HEADER_SIZE + MPEG2_TS_HEADER_SIZE; p < p_end; + p += MPEG2_TS_SOURCE_PACKET_SIZE) + dvb_dmx_swfilter_packets(&fdtv->demux, p, 1); + + err = queue_iso(ctx, i); + if (unlikely(err)) + dev_err(fdtv->device, "requeue failed\n"); + + i = (i + 1) & (N_PACKETS - 1); + } + fw_iso_context_queue_flush(ctx->context); + ctx->current_packet = i; +} + +int fdtv_start_iso(struct firedtv *fdtv) +{ + struct fdtv_ir_context *ctx; + struct fw_device *device = device_of(fdtv); + int i, err; + + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->context = fw_iso_context_create(device->card, + FW_ISO_CONTEXT_RECEIVE, fdtv->isochannel, + device->max_speed, ISO_HEADER_SIZE, handle_iso, fdtv); + if (IS_ERR(ctx->context)) { + err = PTR_ERR(ctx->context); + goto fail_free; + } + + err = fw_iso_buffer_init(&ctx->buffer, device->card, + N_PAGES, DMA_FROM_DEVICE); + if (err) + goto fail_context_destroy; + + ctx->interrupt_packet = 0; + ctx->current_packet = 0; + + for (i = 0; i < N_PAGES; i++) + ctx->pages[i] = page_address(ctx->buffer.pages[i]); + + for (i = 0; i < N_PACKETS; i++) { + err = queue_iso(ctx, i); + if (err) + goto fail; + } + + err = fw_iso_context_start(ctx->context, -1, 0, + FW_ISO_CONTEXT_MATCH_ALL_TAGS); + if (err) + goto fail; + + fdtv->ir_context = ctx; + + return 0; +fail: + fw_iso_buffer_destroy(&ctx->buffer, device->card); +fail_context_destroy: + fw_iso_context_destroy(ctx->context); +fail_free: + kfree(ctx); + + return err; +} + +void fdtv_stop_iso(struct firedtv *fdtv) +{ + struct fdtv_ir_context *ctx = fdtv->ir_context; + + fw_iso_context_stop(ctx->context); + fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card); + fw_iso_context_destroy(ctx->context); + kfree(ctx); +} + +static void handle_fcp(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, int generation, + unsigned long long offset, void *payload, size_t length, + void *callback_data) +{ + struct firedtv *f, *fdtv = NULL; + struct fw_device *device; + unsigned long flags; + int su; + + if (length < 2 || (((u8 *)payload)[0] & 0xf0) != 0) + return; + + su = ((u8 *)payload)[1] & 0x7; + + spin_lock_irqsave(&node_list_lock, flags); + list_for_each_entry(f, &node_list, list) { + device = device_of(f); + if (device->generation != generation) + continue; + + smp_rmb(); /* node_id vs. generation */ + + if (device->card == card && + device->node_id == source && + (f->subunit == su || (f->subunit == 0 && su == 0x7))) { + fdtv = f; + break; + } + } + spin_unlock_irqrestore(&node_list_lock, flags); + + if (fdtv) + avc_recv(fdtv, payload, length); +} + +static struct fw_address_handler fcp_handler = { + .length = CSR_FCP_END - CSR_FCP_RESPONSE, + .address_callback = handle_fcp, +}; + +static const struct fw_address_region fcp_region = { + .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE, + .end = CSR_REGISTER_BASE + CSR_FCP_END, +}; + +static const char * const model_names[] = { + [FIREDTV_UNKNOWN] = "unknown type", + [FIREDTV_DVB_S] = "FireDTV S/CI", + [FIREDTV_DVB_C] = "FireDTV C/CI", + [FIREDTV_DVB_T] = "FireDTV T/CI", + [FIREDTV_DVB_S2] = "FireDTV S2 ", +}; + +/* Adjust the template string if models with longer names appear. */ +#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????") + +static int node_probe(struct device *dev) +{ + struct firedtv *fdtv; + char name[MAX_MODEL_NAME_LEN]; + int name_len, i, err; + + fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); + if (!fdtv) + return -ENOMEM; + + dev_set_drvdata(dev, fdtv); + fdtv->device = dev; + fdtv->isochannel = -1; + fdtv->voltage = 0xff; + fdtv->tone = 0xff; + + mutex_init(&fdtv->avc_mutex); + init_waitqueue_head(&fdtv->avc_wait); + mutex_init(&fdtv->demux_mutex); + INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); + + name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL, + name, sizeof(name)); + for (i = ARRAY_SIZE(model_names); --i; ) + if (strlen(model_names[i]) <= name_len && + strncmp(name, model_names[i], name_len) == 0) + break; + fdtv->type = i; + + err = fdtv_register_rc(fdtv, dev); + if (err) + goto fail_free; + + spin_lock_irq(&node_list_lock); + list_add_tail(&fdtv->list, &node_list); + spin_unlock_irq(&node_list_lock); + + err = avc_identify_subunit(fdtv); + if (err) + goto fail; + + err = fdtv_dvb_register(fdtv, model_names[fdtv->type]); + if (err) + goto fail; + + avc_register_remote_control(fdtv); + + return 0; +fail: + spin_lock_irq(&node_list_lock); + list_del(&fdtv->list); + spin_unlock_irq(&node_list_lock); + fdtv_unregister_rc(fdtv); +fail_free: + kfree(fdtv); + + return err; +} + +static int node_remove(struct device *dev) +{ + struct firedtv *fdtv = dev_get_drvdata(dev); + + fdtv_dvb_unregister(fdtv); + + spin_lock_irq(&node_list_lock); + list_del(&fdtv->list); + spin_unlock_irq(&node_list_lock); + + fdtv_unregister_rc(fdtv); + + kfree(fdtv); + return 0; +} + +static void node_update(struct fw_unit *unit) +{ + struct firedtv *fdtv = dev_get_drvdata(&unit->device); + + if (fdtv->isochannel >= 0) + cmp_establish_pp_connection(fdtv, fdtv->subunit, + fdtv->isochannel); +} + +#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION) + +#define DIGITAL_EVERYWHERE_OUI 0x001287 +#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d +#define AVC_SW_VERSION_ENTRY 0x010001 + +static const struct ieee1394_device_id fdtv_id_table[] = { + { + /* FloppyDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000024, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FloppyDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000025, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FloppyDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000026, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000034, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000035, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000036, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, {} +}; +MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); + +static struct fw_driver fdtv_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "firedtv", + .bus = &fw_bus_type, + .probe = node_probe, + .remove = node_remove, + }, + .update = node_update, + .id_table = fdtv_id_table, +}; + +static int __init fdtv_init(void) +{ + int ret; + + ret = fw_core_add_address_handler(&fcp_handler, &fcp_region); + if (ret < 0) + return ret; + + ret = driver_register(&fdtv_driver.driver); + if (ret < 0) + fw_core_remove_address_handler(&fcp_handler); + + return ret; +} + +static void __exit fdtv_exit(void) +{ + driver_unregister(&fdtv_driver.driver); + fw_core_remove_address_handler(&fcp_handler); +} + +module_init(fdtv_init); +module_exit(fdtv_exit); + +MODULE_AUTHOR("Andreas Monitzer "); +MODULE_AUTHOR("Ben Backx "); +MODULE_DESCRIPTION("FireDTV DVB Driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,168 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid + * + * 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, or (at your option) any later version. + */ + +#ifndef _FIREDTV_H +#define _FIREDTV_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct firedtv_tuner_status { + unsigned active_system:8; + unsigned searching:1; + unsigned moving:1; + unsigned no_rf:1; + unsigned input:1; + unsigned selected_antenna:7; + unsigned ber:32; + unsigned signal_strength:8; + unsigned raster_frequency:2; + unsigned rf_frequency:22; + unsigned man_dep_info_length:8; + unsigned front_end_error:1; + unsigned antenna_error:1; + unsigned front_end_power_status:1; + unsigned power_supply:1; + unsigned carrier_noise_ratio:16; + unsigned power_supply_voltage:8; + unsigned antenna_voltage:8; + unsigned firewire_bus_voltage:8; + unsigned ca_mmi:1; + unsigned ca_pmt_reply:1; + unsigned ca_date_time_request:1; + unsigned ca_application_info:1; + unsigned ca_module_present_status:1; + unsigned ca_dvb_flag:1; + unsigned ca_error_flag:1; + unsigned ca_initialization_status:1; +}; + +enum model_type { + FIREDTV_UNKNOWN = 0, + FIREDTV_DVB_S = 1, + FIREDTV_DVB_C = 2, + FIREDTV_DVB_T = 3, + FIREDTV_DVB_S2 = 4, +}; + +struct device; +struct input_dev; +struct fdtv_ir_context; + +struct firedtv { + struct device *device; + struct list_head list; + + struct dvb_adapter adapter; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dmx_frontend frontend; + struct dvb_net dvbnet; + struct dvb_frontend fe; + + struct dvb_device *cadev; + int ca_last_command; + int ca_time_interval; + + struct mutex avc_mutex; + wait_queue_head_t avc_wait; + bool avc_reply_received; + struct work_struct remote_ctrl_work; + struct input_dev *remote_ctrl_dev; + + enum model_type type; + char subunit; + char isochannel; + struct fdtv_ir_context *ir_context; + + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; + + struct mutex demux_mutex; + unsigned long channel_active; + u16 channel_pid[16]; + + int avc_data_length; + u8 avc_data[512]; +}; + +/* firedtv-avc.c */ +int avc_recv(struct firedtv *fdtv, void *data, size_t length); +int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat); +struct dvb_frontend_parameters; +int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params); +int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]); +int avc_tuner_get_ts(struct firedtv *fdtv); +int avc_identify_subunit(struct firedtv *fdtv); +struct dvb_diseqc_master_cmd; +int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd); +void avc_remote_ctrl_work(struct work_struct *work); +int avc_register_remote_control(struct firedtv *fdtv); +int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len); +int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len); +int avc_ca_reset(struct firedtv *fdtv); +int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length); +int avc_ca_get_time_date(struct firedtv *fdtv, int *interval); +int avc_ca_enter_menu(struct firedtv *fdtv); +int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len); +int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel); +void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel); + +/* firedtv-ci.c */ +int fdtv_ca_register(struct firedtv *fdtv); +void fdtv_ca_release(struct firedtv *fdtv); + +/* firedtv-dvb.c */ +int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed); +int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed); +int fdtv_dvb_register(struct firedtv *fdtv, const char *name); +void fdtv_dvb_unregister(struct firedtv *fdtv); + +/* firedtv-fe.c */ +void fdtv_frontend_init(struct firedtv *fdtv, const char *name); + +/* firedtv-fw.c */ +int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data); +int fdtv_read(struct firedtv *fdtv, u64 addr, void *data); +int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len); +int fdtv_start_iso(struct firedtv *fdtv); +void fdtv_stop_iso(struct firedtv *fdtv); + +/* firedtv-rc.c */ +#ifdef CONFIG_DVB_FIREDTV_INPUT +int fdtv_register_rc(struct firedtv *fdtv, struct device *dev); +void fdtv_unregister_rc(struct firedtv *fdtv); +void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code); +#else +static inline int fdtv_register_rc(struct firedtv *fdtv, + struct device *dev) { return 0; } +static inline void fdtv_unregister_rc(struct firedtv *fdtv) {} +static inline void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) {} +#endif + +#endif /* _FIREDTV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-rc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-rc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-rc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/firedtv-rc.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,196 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * + * 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, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "firedtv.h" + +/* fixed table with older keycodes, geared towards MythTV */ +static const u16 oldtable[] = { + + /* code from device: 0x4501...0x451f */ + + KEY_ESC, + KEY_F9, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_I, + KEY_0, + KEY_ENTER, + KEY_RED, + KEY_UP, + KEY_GREEN, + KEY_F10, + KEY_SPACE, + KEY_F11, + KEY_YELLOW, + KEY_DOWN, + KEY_BLUE, + KEY_Z, + KEY_P, + KEY_PAGEDOWN, + KEY_LEFT, + KEY_W, + KEY_RIGHT, + KEY_P, + KEY_M, + + /* code from device: 0x4540...0x4542 */ + + KEY_R, + KEY_V, + KEY_C, +}; + +/* user-modifiable table for a remote as sold in 2008 */ +static const u16 keytable[] = { + + /* code from device: 0x0300...0x031f */ + + [0x00] = KEY_POWER, + [0x01] = KEY_SLEEP, + [0x02] = KEY_STOP, + [0x03] = KEY_OK, + [0x04] = KEY_RIGHT, + [0x05] = KEY_1, + [0x06] = KEY_2, + [0x07] = KEY_3, + [0x08] = KEY_LEFT, + [0x09] = KEY_4, + [0x0a] = KEY_5, + [0x0b] = KEY_6, + [0x0c] = KEY_UP, + [0x0d] = KEY_7, + [0x0e] = KEY_8, + [0x0f] = KEY_9, + [0x10] = KEY_DOWN, + [0x11] = KEY_TITLE, /* "OSD" - fixme */ + [0x12] = KEY_0, + [0x13] = KEY_F20, /* "16:9" - fixme */ + [0x14] = KEY_SCREEN, /* "FULL" - fixme */ + [0x15] = KEY_MUTE, + [0x16] = KEY_SUBTITLE, + [0x17] = KEY_RECORD, + [0x18] = KEY_TEXT, + [0x19] = KEY_AUDIO, + [0x1a] = KEY_RED, + [0x1b] = KEY_PREVIOUS, + [0x1c] = KEY_REWIND, + [0x1d] = KEY_PLAYPAUSE, + [0x1e] = KEY_NEXT, + [0x1f] = KEY_VOLUMEUP, + + /* code from device: 0x0340...0x0354 */ + + [0x20] = KEY_CHANNELUP, + [0x21] = KEY_F21, /* "4:3" - fixme */ + [0x22] = KEY_TV, + [0x23] = KEY_DVD, + [0x24] = KEY_VCR, + [0x25] = KEY_AUX, + [0x26] = KEY_GREEN, + [0x27] = KEY_YELLOW, + [0x28] = KEY_BLUE, + [0x29] = KEY_CHANNEL, /* "CH.LIST" */ + [0x2a] = KEY_VENDOR, /* "CI" - fixme */ + [0x2b] = KEY_VOLUMEDOWN, + [0x2c] = KEY_CHANNELDOWN, + [0x2d] = KEY_LAST, + [0x2e] = KEY_INFO, + [0x2f] = KEY_FORWARD, + [0x30] = KEY_LIST, + [0x31] = KEY_FAVORITES, + [0x32] = KEY_MENU, + [0x33] = KEY_EPG, + [0x34] = KEY_EXIT, +}; + +int fdtv_register_rc(struct firedtv *fdtv, struct device *dev) +{ + struct input_dev *idev; + int i, err; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; + + fdtv->remote_ctrl_dev = idev; + idev->name = "FireDTV remote control"; + idev->dev.parent = dev; + idev->evbit[0] = BIT_MASK(EV_KEY); + idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL); + if (!idev->keycode) { + err = -ENOMEM; + goto fail; + } + idev->keycodesize = sizeof(keytable[0]); + idev->keycodemax = ARRAY_SIZE(keytable); + + for (i = 0; i < ARRAY_SIZE(keytable); i++) + set_bit(keytable[i], idev->keybit); + + err = input_register_device(idev); + if (err) + goto fail_free_keymap; + + return 0; + +fail_free_keymap: + kfree(idev->keycode); +fail: + input_free_device(idev); + return err; +} + +void fdtv_unregister_rc(struct firedtv *fdtv) +{ + cancel_work_sync(&fdtv->remote_ctrl_work); + kfree(fdtv->remote_ctrl_dev->keycode); + input_unregister_device(fdtv->remote_ctrl_dev); +} + +void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) +{ + struct input_dev *idev = fdtv->remote_ctrl_dev; + u16 *keycode = idev->keycode; + + if (code >= 0x0300 && code <= 0x031f) + code = keycode[code - 0x0300]; + else if (code >= 0x0340 && code <= 0x0354) + code = keycode[code - 0x0320]; + else if (code >= 0x4501 && code <= 0x451f) + code = oldtable[code - 0x4501]; + else if (code >= 0x4540 && code <= 0x4542) + code = oldtable[code - 0x4521]; + else { + printk(KERN_DEBUG "firedtv: invalid key code 0x%04x " + "from remote control\n", code); + return; + } + + input_report_key(idev, code, 1); + input_sync(idev); + input_report_key(idev, code, 0); + input_sync(idev); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,19 @@ +config DVB_FIREDTV + tristate "FireDTV and FloppyDTV" + depends on DVB_CORE && FIREWIRE + help + Support for DVB receivers from Digital Everywhere + which are connected via IEEE 1394 (FireWire). + + These devices don't have an MPEG decoder built in, + so you need an external software decoder to watch TV. + + To compile this driver as a module, say M here: + the module will be called firedtv. + +if DVB_FIREDTV + +config DVB_FIREDTV_INPUT + def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m) + +endif # DVB_FIREDTV diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/firewire/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,6 @@ +obj-$(CONFIG_DVB_FIREDTV) += firedtv.o + +firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o +firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o + +ccflags-y += -Idrivers/media/dvb/dvb-core diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,1572 @@ +/* + * Afatech AF9013 demodulator driver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "af9013_priv.h" +#include "af9013.h" + +int af9013_debug; + +struct af9013_state { + struct i2c_adapter *i2c; + struct dvb_frontend frontend; + + struct af9013_config config; + + /* tuner/demod RF and IF AGC limits used for signal strength calc */ + u8 signal_strength_en, rf_50, rf_80, if_50, if_80; + u16 signal_strength; + u32 ber; + u32 ucblocks; + u16 snr; + u32 frequency; + unsigned long next_statistics_check; +}; + +static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + +static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg, + u8 *val, u8 len) +{ + u8 buf[3+len]; + struct i2c_msg msg = { + .addr = state->config.demod_address, + .flags = 0, + .len = sizeof(buf), + .buf = buf }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + buf[2] = mbox; + memcpy(&buf[3], val, len); + + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + warn("I2C write failed reg:%04x len:%d", reg, len); + return -EREMOTEIO; + } + return 0; +} + +static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val, + u8 len) +{ + u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7); + return af9013_write_regs(state, mbox, reg, val, len); +} + +static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val, + u8 len) +{ + u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7); + return af9013_write_regs(state, mbox, reg, val, len); +} + +/* write single register */ +static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val) +{ + return af9013_write_ofdm_regs(state, reg, &val, 1); +} + +/* read single register */ +static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val) +{ + u8 obuf[3] = { reg >> 8, reg & 0xff, 0 }; + u8 ibuf[1]; + struct i2c_msg msg[2] = { + { + .addr = state->config.demod_address, + .flags = 0, + .len = sizeof(obuf), + .buf = obuf + }, { + .addr = state->config.demod_address, + .flags = I2C_M_RD, + .len = sizeof(ibuf), + .buf = ibuf + } + }; + + if (i2c_transfer(state->i2c, msg, 2) != 2) { + warn("I2C read failed reg:%04x", reg); + return -EREMOTEIO; + } + *val = ibuf[0]; + return 0; +} + +static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos, + u8 len, u8 val) +{ + int ret; + u8 tmp, mask; + + ret = af9013_read_reg(state, reg, &tmp); + if (ret) + return ret; + + mask = regmask[len - 1] << pos; + tmp = (tmp & ~mask) | ((val << pos) & mask); + + return af9013_write_reg(state, reg, tmp); +} + +static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos, + u8 len, u8 *val) +{ + int ret; + u8 tmp; + + ret = af9013_read_reg(state, reg, &tmp); + if (ret) + return ret; + *val = (tmp >> pos) & regmask[len - 1]; + return 0; +} + +static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) +{ + int ret; + u8 pos; + u16 addr; + deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval); + +/* GPIO0 & GPIO1 0xd735 + GPIO2 & GPIO3 0xd736 */ + + switch (gpio) { + case 0: + case 1: + addr = 0xd735; + break; + case 2: + case 3: + addr = 0xd736; + break; + + default: + err("invalid gpio:%d\n", gpio); + ret = -EINVAL; + goto error; + }; + + switch (gpio) { + case 0: + case 2: + pos = 0; + break; + case 1: + case 3: + default: + pos = 4; + break; + }; + + ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval); + +error: + return ret; +} + +static u32 af913_div(u32 a, u32 b, u32 x) +{ + u32 r = 0, c = 0, i; + deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x); + + if (a > b) { + c = a / b; + a = a - c * b; + } + + for (i = 0; i < x; i++) { + if (a >= b) { + r += 1; + a -= b; + } + a <<= 1; + r <<= 1; + } + r = (c << (u32)x) + r; + + deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r); + return r; +} + +static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw) +{ + int ret, i, j, found; + deb_info("%s: adc_clock:%d bw:%d\n", __func__, + state->config.adc_clock, bw); + + /* lookup coeff from table */ + for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) { + if (coeff_table[i].adc_clock == state->config.adc_clock && + coeff_table[i].bw == bw) { + found = 1; + break; + } + } + + if (!found) { + err("invalid bw or clock"); + ret = -EINVAL; + goto error; + } + + deb_info("%s: coeff: ", __func__); + debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info); + + /* program */ + for (j = 0; j < sizeof(coeff_table[i].val); j++) { + ret = af9013_write_reg(state, 0xae00 + j, + coeff_table[i].val[j]); + if (ret) + break; + } + +error: + return ret; +} + +static int af9013_set_adc_ctrl(struct af9013_state *state) +{ + int ret; + u8 buf[3], tmp, i; + u32 adc_cw; + + deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock); + + /* adc frequency type */ + switch (state->config.adc_clock) { + case 28800: /* 28.800 MHz */ + tmp = 0; + break; + case 20480: /* 20.480 MHz */ + tmp = 1; + break; + case 28000: /* 28.000 MHz */ + tmp = 2; + break; + case 25000: /* 25.000 MHz */ + tmp = 3; + break; + default: + err("invalid xtal"); + return -EINVAL; + } + + adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul); + + buf[0] = (u8) ((adc_cw & 0x000000ff)); + buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8); + buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16); + + deb_info("%s: adc_cw:", __func__); + debug_dump(buf, sizeof(buf), deb_info); + + /* program */ + for (i = 0; i < sizeof(buf); i++) { + ret = af9013_write_reg(state, 0xd180 + i, buf[i]); + if (ret) + goto error; + } + ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp); +error: + return ret; +} + +static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw) +{ + int ret; + u16 addr; + u8 buf[3], i, j; + u32 adc_freq, freq_cw; + s8 bfs_spec_inv; + int if_sample_freq; + + for (j = 0; j < 3; j++) { + if (j == 0) { + addr = 0xd140; /* fcw normal */ + bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; + } else if (j == 1) { + addr = 0x9be7; /* fcw dummy ram */ + bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; + } else { + addr = 0x9bea; /* fcw inverted */ + bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1; + } + + adc_freq = state->config.adc_clock * 1000; + if_sample_freq = state->config.tuner_if * 1000; + + /* TDA18271 uses different sampling freq for every bw */ + if (state->config.tuner == AF9013_TUNER_TDA18271) { + switch (bw) { + case BANDWIDTH_6_MHZ: + if_sample_freq = 3300000; /* 3.3 MHz */ + break; + case BANDWIDTH_7_MHZ: + if_sample_freq = 3500000; /* 3.5 MHz */ + break; + case BANDWIDTH_8_MHZ: + default: + if_sample_freq = 4000000; /* 4.0 MHz */ + break; + } + } else if (state->config.tuner == AF9013_TUNER_TDA18218) { + switch (bw) { + case BANDWIDTH_6_MHZ: + if_sample_freq = 3000000; /* 3 MHz */ + break; + case BANDWIDTH_7_MHZ: + if_sample_freq = 3500000; /* 3.5 MHz */ + break; + case BANDWIDTH_8_MHZ: + default: + if_sample_freq = 4000000; /* 4 MHz */ + break; + } + } + + while (if_sample_freq > (adc_freq / 2)) + if_sample_freq = if_sample_freq - adc_freq; + + if (if_sample_freq >= 0) + bfs_spec_inv = bfs_spec_inv * (-1); + else + if_sample_freq = if_sample_freq * (-1); + + freq_cw = af913_div(if_sample_freq, adc_freq, 23ul); + + if (bfs_spec_inv == -1) + freq_cw = 0x00800000 - freq_cw; + + buf[0] = (u8) ((freq_cw & 0x000000ff)); + buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8); + buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16); + + + deb_info("%s: freq_cw:", __func__); + debug_dump(buf, sizeof(buf), deb_info); + + /* program */ + for (i = 0; i < sizeof(buf); i++) { + ret = af9013_write_reg(state, addr++, buf[i]); + if (ret) + goto error; + } + } +error: + return ret; +} + +static int af9013_set_ofdm_params(struct af9013_state *state, + struct dvb_ofdm_parameters *params, u8 *auto_mode) +{ + int ret; + u8 i, buf[3] = {0, 0, 0}; + *auto_mode = 0; /* set if parameters are requested to auto set */ + + /* Try auto-detect transmission parameters in case of AUTO requested or + garbage parameters given by application for compatibility. + MPlayer seems to provide garbage parameters currently. */ + + switch (params->transmission_mode) { + case TRANSMISSION_MODE_AUTO: + *auto_mode = 1; + case TRANSMISSION_MODE_2K: + break; + case TRANSMISSION_MODE_8K: + buf[0] |= (1 << 0); + break; + default: + deb_info("%s: invalid transmission_mode\n", __func__); + *auto_mode = 1; + } + + switch (params->guard_interval) { + case GUARD_INTERVAL_AUTO: + *auto_mode = 1; + case GUARD_INTERVAL_1_32: + break; + case GUARD_INTERVAL_1_16: + buf[0] |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + buf[0] |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + buf[0] |= (3 << 2); + break; + default: + deb_info("%s: invalid guard_interval\n", __func__); + *auto_mode = 1; + } + + switch (params->hierarchy_information) { + case HIERARCHY_AUTO: + *auto_mode = 1; + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + buf[0] |= (1 << 4); + break; + case HIERARCHY_2: + buf[0] |= (2 << 4); + break; + case HIERARCHY_4: + buf[0] |= (3 << 4); + break; + default: + deb_info("%s: invalid hierarchy_information\n", __func__); + *auto_mode = 1; + }; + + switch (params->constellation) { + case QAM_AUTO: + *auto_mode = 1; + case QPSK: + break; + case QAM_16: + buf[1] |= (1 << 6); + break; + case QAM_64: + buf[1] |= (2 << 6); + break; + default: + deb_info("%s: invalid constellation\n", __func__); + *auto_mode = 1; + } + + /* Use HP. How and which case we can switch to LP? */ + buf[1] |= (1 << 4); + + switch (params->code_rate_HP) { + case FEC_AUTO: + *auto_mode = 1; + case FEC_1_2: + break; + case FEC_2_3: + buf[2] |= (1 << 0); + break; + case FEC_3_4: + buf[2] |= (2 << 0); + break; + case FEC_5_6: + buf[2] |= (3 << 0); + break; + case FEC_7_8: + buf[2] |= (4 << 0); + break; + default: + deb_info("%s: invalid code_rate_HP\n", __func__); + *auto_mode = 1; + } + + switch (params->code_rate_LP) { + case FEC_AUTO: + /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO + by dvb_frontend.c for compatibility */ + if (params->hierarchy_information != HIERARCHY_NONE) + *auto_mode = 1; + case FEC_1_2: + break; + case FEC_2_3: + buf[2] |= (1 << 3); + break; + case FEC_3_4: + buf[2] |= (2 << 3); + break; + case FEC_5_6: + buf[2] |= (3 << 3); + break; + case FEC_7_8: + buf[2] |= (4 << 3); + break; + case FEC_NONE: + if (params->hierarchy_information == HIERARCHY_AUTO) + break; + default: + deb_info("%s: invalid code_rate_LP\n", __func__); + *auto_mode = 1; + } + + switch (params->bandwidth) { + case BANDWIDTH_6_MHZ: + break; + case BANDWIDTH_7_MHZ: + buf[1] |= (1 << 2); + break; + case BANDWIDTH_8_MHZ: + buf[1] |= (2 << 2); + break; + default: + deb_info("%s: invalid bandwidth\n", __func__); + buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */ + } + + /* program */ + for (i = 0; i < sizeof(buf); i++) { + ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]); + if (ret) + break; + } + + return ret; +} + +static int af9013_reset(struct af9013_state *state, u8 sleep) +{ + int ret; + u8 tmp, i; + deb_info("%s\n", __func__); + + /* enable OFDM reset */ + ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1); + if (ret) + goto error; + + /* start reset mechanism */ + ret = af9013_write_reg(state, 0xaeff, 1); + if (ret) + goto error; + + /* reset is done when bit 1 is set */ + for (i = 0; i < 150; i++) { + ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp); + if (ret) + goto error; + if (tmp) + break; /* reset done */ + msleep(10); + } + if (!tmp) + return -ETIMEDOUT; + + /* don't clear reset when going to sleep */ + if (!sleep) { + /* clear OFDM reset */ + ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); + if (ret) + goto error; + + /* disable OFDM reset */ + ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); + } +error: + return ret; +} + +static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) +{ + int ret; + deb_info("%s: onoff:%d\n", __func__, onoff); + + if (onoff) { + /* power on */ + ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0); + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); + } else { + /* power off */ + ret = af9013_reset(state, 1); + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1); + } +error: + return ret; +} + +static int af9013_lock_led(struct af9013_state *state, u8 onoff) +{ + deb_info("%s: onoff:%d\n", __func__, onoff); + + return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff); +} + +static int af9013_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + u8 auto_mode; /* auto set TPS */ + + deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, + params->u.ofdm.bandwidth); + + state->frequency = params->frequency; + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, params); + + /* program CFOE coefficients */ + ret = af9013_set_coeff(state, params->u.ofdm.bandwidth); + if (ret) + goto error; + + /* program frequency control */ + ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth); + if (ret) + goto error; + + /* clear TPS lock flag (inverted flag) */ + ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1); + if (ret) + goto error; + + /* clear MPEG2 lock flag */ + ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0); + if (ret) + goto error; + + /* empty channel function */ + ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0); + if (ret) + goto error; + + /* empty DVB-T channel function */ + ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0); + if (ret) + goto error; + + /* program TPS and bandwidth, check if auto mode needed */ + ret = af9013_set_ofdm_params(state, ¶ms->u.ofdm, &auto_mode); + if (ret) + goto error; + + if (auto_mode) { + /* clear easy mode flag */ + ret = af9013_write_reg(state, 0xaefd, 0); + deb_info("%s: auto TPS\n", __func__); + } else { + /* set easy mode flag */ + ret = af9013_write_reg(state, 0xaefd, 1); + if (ret) + goto error; + ret = af9013_write_reg(state, 0xaefe, 0); + deb_info("%s: manual TPS\n", __func__); + } + if (ret) + goto error; + + /* everything is set, lets try to receive channel - OFSM GO! */ + ret = af9013_write_reg(state, 0xffff, 0); + if (ret) + goto error; + +error: + return ret; +} + +static int af9013_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + u8 i, buf[3]; + deb_info("%s\n", __func__); + + /* read TPS registers */ + for (i = 0; i < 3; i++) { + ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]); + if (ret) + goto error; + } + + switch ((buf[1] >> 6) & 3) { + case 0: + p->u.ofdm.constellation = QPSK; + break; + case 1: + p->u.ofdm.constellation = QAM_16; + break; + case 2: + p->u.ofdm.constellation = QAM_64; + break; + } + + switch ((buf[0] >> 0) & 3) { + case 0: + p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + } + + switch ((buf[0] >> 2) & 3) { + case 0: + p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + break; + } + + switch ((buf[0] >> 4) & 7) { + case 0: + p->u.ofdm.hierarchy_information = HIERARCHY_NONE; + break; + case 1: + p->u.ofdm.hierarchy_information = HIERARCHY_1; + break; + case 2: + p->u.ofdm.hierarchy_information = HIERARCHY_2; + break; + case 3: + p->u.ofdm.hierarchy_information = HIERARCHY_4; + break; + } + + switch ((buf[2] >> 0) & 7) { + case 0: + p->u.ofdm.code_rate_HP = FEC_1_2; + break; + case 1: + p->u.ofdm.code_rate_HP = FEC_2_3; + break; + case 2: + p->u.ofdm.code_rate_HP = FEC_3_4; + break; + case 3: + p->u.ofdm.code_rate_HP = FEC_5_6; + break; + case 4: + p->u.ofdm.code_rate_HP = FEC_7_8; + break; + } + + switch ((buf[2] >> 3) & 7) { + case 0: + p->u.ofdm.code_rate_LP = FEC_1_2; + break; + case 1: + p->u.ofdm.code_rate_LP = FEC_2_3; + break; + case 2: + p->u.ofdm.code_rate_LP = FEC_3_4; + break; + case 3: + p->u.ofdm.code_rate_LP = FEC_5_6; + break; + case 4: + p->u.ofdm.code_rate_LP = FEC_7_8; + break; + } + + switch ((buf[1] >> 2) & 3) { + case 0: + p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + break; + case 1: + p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + break; + case 2: + p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + break; + } + + p->inversion = INVERSION_AUTO; + p->frequency = state->frequency; + +error: + return ret; +} + +static int af9013_update_ber_unc(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + u8 buf[3], i; + u32 error_bit_count = 0; + u32 total_bit_count = 0; + u32 abort_packet_count = 0; + + state->ber = 0; + + /* check if error bit count is ready */ + ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]); + if (ret) + goto error; + if (!buf[0]) + goto exit; + + /* get RSD packet abort count */ + for (i = 0; i < 2; i++) { + ret = af9013_read_reg(state, 0xd38a + i, &buf[i]); + if (ret) + goto error; + } + abort_packet_count = (buf[1] << 8) + buf[0]; + + /* get error bit count */ + for (i = 0; i < 3; i++) { + ret = af9013_read_reg(state, 0xd387 + i, &buf[i]); + if (ret) + goto error; + } + error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0]; + error_bit_count = error_bit_count - abort_packet_count * 8 * 8; + + /* get used RSD counting period (10000 RSD packets used) */ + for (i = 0; i < 2; i++) { + ret = af9013_read_reg(state, 0xd385 + i, &buf[i]); + if (ret) + goto error; + } + total_bit_count = (buf[1] << 8) + buf[0]; + total_bit_count = total_bit_count - abort_packet_count; + total_bit_count = total_bit_count * 204 * 8; + + if (total_bit_count) + state->ber = error_bit_count * 1000000000 / total_bit_count; + + state->ucblocks += abort_packet_count; + + deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__, + error_bit_count, total_bit_count, abort_packet_count); + + /* set BER counting range */ + ret = af9013_write_reg(state, 0xd385, 10000 & 0xff); + if (ret) + goto error; + ret = af9013_write_reg(state, 0xd386, 10000 >> 8); + if (ret) + goto error; + /* reset and start BER counter */ + ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1); + if (ret) + goto error; + +exit: +error: + return ret; +} + +static int af9013_update_snr(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + u8 buf[3], i, len; + u32 quant = 0; + struct snr_table *uninitialized_var(snr_table); + + /* check if quantizer ready (for snr) */ + ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]); + if (ret) + goto error; + if (buf[0]) { + /* quantizer ready - read it */ + for (i = 0; i < 3; i++) { + ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]); + if (ret) + goto error; + } + quant = (buf[2] << 16) + (buf[1] << 8) + buf[0]; + + /* read current constellation */ + ret = af9013_read_reg(state, 0xd3c1, &buf[0]); + if (ret) + goto error; + + switch ((buf[0] >> 6) & 3) { + case 0: + len = ARRAY_SIZE(qpsk_snr_table); + snr_table = qpsk_snr_table; + break; + case 1: + len = ARRAY_SIZE(qam16_snr_table); + snr_table = qam16_snr_table; + break; + case 2: + len = ARRAY_SIZE(qam64_snr_table); + snr_table = qam64_snr_table; + break; + default: + len = 0; + break; + } + + if (len) { + for (i = 0; i < len; i++) { + if (quant < snr_table[i].val) { + state->snr = snr_table[i].snr * 10; + break; + } + } + } + + /* set quantizer super frame count */ + ret = af9013_write_reg(state, 0xd2e2, 1); + if (ret) + goto error; + + /* check quantizer availability */ + for (i = 0; i < 10; i++) { + msleep(10); + ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1, + &buf[0]); + if (ret) + goto error; + if (!buf[0]) + break; + } + + /* reset quantizer */ + ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1); + if (ret) + goto error; + } + +error: + return ret; +} + +static int af9013_update_signal_strength(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret = 0; + u8 rf_gain, if_gain; + int signal_strength; + + deb_info("%s\n", __func__); + + if (state->signal_strength_en) { + ret = af9013_read_reg(state, 0xd07c, &rf_gain); + if (ret) + goto error; + ret = af9013_read_reg(state, 0xd07d, &if_gain); + if (ret) + goto error; + signal_strength = (0xffff / \ + (9 * (state->rf_50 + state->if_50) - \ + 11 * (state->rf_80 + state->if_80))) * \ + (10 * (rf_gain + if_gain) - \ + 11 * (state->rf_80 + state->if_80)); + if (signal_strength < 0) + signal_strength = 0; + else if (signal_strength > 0xffff) + signal_strength = 0xffff; + + state->signal_strength = signal_strength; + } else { + state->signal_strength = 0; + } + +error: + return ret; +} + +static int af9013_update_statistics(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + + if (time_before(jiffies, state->next_statistics_check)) + return 0; + + /* set minimum statistic update interval */ + state->next_statistics_check = jiffies + msecs_to_jiffies(1200); + + ret = af9013_update_signal_strength(fe); + if (ret) + goto error; + ret = af9013_update_snr(fe); + if (ret) + goto error; + ret = af9013_update_ber_unc(fe); + if (ret) + goto error; + +error: + return ret; +} + +static int af9013_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 800; + fesettings->step_size = 0; + fesettings->max_drift = 0; + + return 0; +} + +static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret = 0; + u8 tmp; + *status = 0; + + /* MPEG2 lock */ + ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_LOCK; + + if (!*status) { + /* TPS lock */ + ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI; + } + + if (!*status) { + /* CFO lock */ + ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + } + + if (!*status) { + /* SFOE lock */ + ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + } + + if (!*status) { + /* AGC lock */ + ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_SIGNAL; + } + + ret = af9013_update_statistics(fe); + +error: + return ret; +} + + +static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + ret = af9013_update_statistics(fe); + *ber = state->ber; + return ret; +} + +static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + ret = af9013_update_statistics(fe); + *strength = state->signal_strength; + return ret; +} + +static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + ret = af9013_update_statistics(fe); + *snr = state->snr; + return ret; +} + +static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + ret = af9013_update_statistics(fe); + *ucblocks = state->ucblocks; + return ret; +} + +static int af9013_sleep(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + deb_info("%s\n", __func__); + + ret = af9013_lock_led(state, 0); + if (ret) + goto error; + + ret = af9013_power_ctrl(state, 0); +error: + return ret; +} + +static int af9013_init(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret, i, len; + u8 tmp0, tmp1; + struct regdesc *init; + deb_info("%s\n", __func__); + + /* reset OFDM */ + ret = af9013_reset(state, 0); + if (ret) + goto error; + + /* power on */ + ret = af9013_power_ctrl(state, 1); + if (ret) + goto error; + + /* enable ADC */ + ret = af9013_write_reg(state, 0xd73a, 0xa4); + if (ret) + goto error; + + /* write API version to firmware */ + for (i = 0; i < sizeof(state->config.api_version); i++) { + ret = af9013_write_reg(state, 0x9bf2 + i, + state->config.api_version[i]); + if (ret) + goto error; + } + + /* program ADC control */ + ret = af9013_set_adc_ctrl(state); + if (ret) + goto error; + + /* set I2C master clock */ + ret = af9013_write_reg(state, 0xd416, 0x14); + if (ret) + goto error; + + /* set 16 embx */ + ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1); + if (ret) + goto error; + + /* set no trigger */ + ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0); + if (ret) + goto error; + + /* set read-update bit for constellation */ + ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1); + if (ret) + goto error; + + /* enable FEC monitor */ + ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1); + if (ret) + goto error; + + /* load OFSM settings */ + deb_info("%s: load ofsm settings\n", __func__); + len = ARRAY_SIZE(ofsm_init); + init = ofsm_init; + for (i = 0; i < len; i++) { + ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, + init[i].len, init[i].val); + if (ret) + goto error; + } + + /* load tuner specific settings */ + deb_info("%s: load tuner specific settings\n", __func__); + switch (state->config.tuner) { + case AF9013_TUNER_MXL5003D: + len = ARRAY_SIZE(tuner_init_mxl5003d); + init = tuner_init_mxl5003d; + break; + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + case AF9013_TUNER_MXL5007T: + len = ARRAY_SIZE(tuner_init_mxl5005); + init = tuner_init_mxl5005; + break; + case AF9013_TUNER_ENV77H11D5: + len = ARRAY_SIZE(tuner_init_env77h11d5); + init = tuner_init_env77h11d5; + break; + case AF9013_TUNER_MT2060: + len = ARRAY_SIZE(tuner_init_mt2060); + init = tuner_init_mt2060; + break; + case AF9013_TUNER_MC44S803: + len = ARRAY_SIZE(tuner_init_mc44s803); + init = tuner_init_mc44s803; + break; + case AF9013_TUNER_QT1010: + case AF9013_TUNER_QT1010A: + len = ARRAY_SIZE(tuner_init_qt1010); + init = tuner_init_qt1010; + break; + case AF9013_TUNER_MT2060_2: + len = ARRAY_SIZE(tuner_init_mt2060_2); + init = tuner_init_mt2060_2; + break; + case AF9013_TUNER_TDA18271: + case AF9013_TUNER_TDA18218: + len = ARRAY_SIZE(tuner_init_tda18271); + init = tuner_init_tda18271; + break; + case AF9013_TUNER_UNKNOWN: + default: + len = ARRAY_SIZE(tuner_init_unknown); + init = tuner_init_unknown; + break; + } + + for (i = 0; i < len; i++) { + ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, + init[i].len, init[i].val); + if (ret) + goto error; + } + + /* set TS mode */ + deb_info("%s: setting ts mode\n", __func__); + tmp0 = 0; /* parallel mode */ + tmp1 = 0; /* serial mode */ + switch (state->config.output_mode) { + case AF9013_OUTPUT_MODE_PARALLEL: + tmp0 = 1; + break; + case AF9013_OUTPUT_MODE_SERIAL: + tmp1 = 1; + break; + case AF9013_OUTPUT_MODE_USB: + /* usb mode for AF9015 */ + default: + break; + } + ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */ + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */ + if (ret) + goto error; + + /* enable lock led */ + ret = af9013_lock_led(state, 1); + if (ret) + goto error; + + /* read values needed for signal strength calculation */ + ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, + &state->signal_strength_en); + if (ret) + goto error; + + if (state->signal_strength_en) { + ret = af9013_read_reg(state, 0x9bbd, &state->rf_50); + if (ret) + goto error; + ret = af9013_read_reg(state, 0x9bd0, &state->rf_80); + if (ret) + goto error; + ret = af9013_read_reg(state, 0x9be2, &state->if_50); + if (ret) + goto error; + ret = af9013_read_reg(state, 0x9be4, &state->if_80); + if (ret) + goto error; + } + +error: + return ret; +} + +static struct dvb_frontend_ops af9013_ops; + +static int af9013_download_firmware(struct af9013_state *state) +{ + int i, len, remaining, ret; + const struct firmware *fw; + u16 checksum = 0; + u8 val; + u8 fw_params[4]; + u8 *fw_file = AF9013_DEFAULT_FIRMWARE; + + msleep(100); + /* check whether firmware is already running */ + ret = af9013_read_reg(state, 0x98be, &val); + if (ret) + goto error; + else + deb_info("%s: firmware status:%02x\n", __func__, val); + + if (val == 0x0c) /* fw is running, no need for download */ + goto exit; + + info("found a '%s' in cold state, will try to load a firmware", + af9013_ops.info.name); + + /* request the firmware, this will block and timeout */ + ret = request_firmware(&fw, fw_file, state->i2c->dev.parent); + if (ret) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details" \ + " on firmware-problems. (%d)", + fw_file, ret); + goto error; + } + + info("downloading firmware from file '%s'", fw_file); + + /* calc checksum */ + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + + fw_params[0] = checksum >> 8; + fw_params[1] = checksum & 0xff; + fw_params[2] = fw->size >> 8; + fw_params[3] = fw->size & 0xff; + + /* write fw checksum & size */ + ret = af9013_write_ofsm_regs(state, 0x50fc, + fw_params, sizeof(fw_params)); + if (ret) + goto error_release; + + #define FW_ADDR 0x5100 /* firmware start address */ + #define LEN_MAX 16 /* max packet size */ + for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { + len = remaining; + if (len > LEN_MAX) + len = LEN_MAX; + + ret = af9013_write_ofsm_regs(state, + FW_ADDR + fw->size - remaining, + (u8 *) &fw->data[fw->size - remaining], len); + if (ret) { + err("firmware download failed:%d", ret); + goto error_release; + } + } + + /* request boot firmware */ + ret = af9013_write_reg(state, 0xe205, 1); + if (ret) + goto error_release; + + for (i = 0; i < 15; i++) { + msleep(100); + + /* check firmware status */ + ret = af9013_read_reg(state, 0x98be, &val); + if (ret) + goto error_release; + + deb_info("%s: firmware status:%02x\n", __func__, val); + + if (val == 0x0c || val == 0x04) /* success or fail */ + break; + } + + if (val == 0x04) { + err("firmware did not run"); + ret = -1; + } else if (val != 0x0c) { + err("firmware boot timeout"); + ret = -1; + } + +error_release: + release_firmware(fw); +error: +exit: + if (!ret) + info("found a '%s' in warm state.", af9013_ops.info.name); + return ret; +} + +static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int ret; + struct af9013_state *state = fe->demodulator_priv; + deb_info("%s: enable:%d\n", __func__, enable); + + if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) + ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable); + else + ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable); + + return ret; +} + +static void af9013_release(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops af9013_ops; + +struct dvb_frontend *af9013_attach(const struct af9013_config *config, + struct i2c_adapter *i2c) +{ + int ret; + struct af9013_state *state = NULL; + u8 buf[4], i; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->i2c = i2c; + memcpy(&state->config, config, sizeof(struct af9013_config)); + + /* download firmware */ + if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) { + ret = af9013_download_firmware(state); + if (ret) + goto error; + } + + /* firmware version */ + for (i = 0; i < 4; i++) { + ret = af9013_read_reg(state, 0x5103 + i, &buf[i]); + if (ret) + goto error; + } + info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]); + + /* chip version */ + ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]); + if (ret) + goto error; + + /* ROM version */ + for (i = 0; i < 2; i++) { + ret = af9013_read_reg(state, 0x116b + i, &buf[i]); + if (ret) + goto error; + } + deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__, + buf[2], buf[0], buf[1]); + + /* settings for mp2if */ + if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) { + /* AF9015 split PSB to 1.5k + 0.5k */ + ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1); + } else { + /* AF9013 change the output bit to data7 */ + ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1); + if (ret) + goto error; + /* AF9013 set mpeg to full speed */ + ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1); + } + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1); + if (ret) + goto error; + + /* set GPIOs */ + for (i = 0; i < sizeof(state->config.gpio); i++) { + ret = af9013_set_gpio(state, i, state->config.gpio[i]); + if (ret) + goto error; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &af9013_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(af9013_attach); + +static struct dvb_frontend_ops af9013_ops = { + .info = { + .name = "Afatech AF9013 DVB-T", + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 250000, + .frequency_tolerance = 0, + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | + FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + + .release = af9013_release, + .init = af9013_init, + .sleep = af9013_sleep, + .i2c_gate_ctrl = af9013_i2c_gate_ctrl, + + .set_frontend = af9013_set_frontend, + .get_frontend = af9013_get_frontend, + + .get_tune_settings = af9013_get_tune_settings, + + .read_status = af9013_read_status, + .read_ber = af9013_read_ber, + .read_signal_strength = af9013_read_signal_strength, + .read_snr = af9013_read_snr, + .read_ucblocks = af9013_read_ucblocks, +}; + +module_param_named(debug, af9013_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,109 @@ +/* + * Afatech AF9013 demodulator driver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _AF9013_H_ +#define _AF9013_H_ + +#include + +enum af9013_ts_mode { + AF9013_OUTPUT_MODE_PARALLEL, + AF9013_OUTPUT_MODE_SERIAL, + AF9013_OUTPUT_MODE_USB, /* only for AF9015 */ +}; + +enum af9013_tuner { + AF9013_TUNER_MXL5003D = 3, /* MaxLinear */ + AF9013_TUNER_MXL5005D = 13, /* MaxLinear */ + AF9013_TUNER_MXL5005R = 30, /* MaxLinear */ + AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */ + AF9013_TUNER_MT2060 = 130, /* Microtune */ + AF9013_TUNER_MC44S803 = 133, /* Freescale */ + AF9013_TUNER_QT1010 = 134, /* Quantek */ + AF9013_TUNER_UNKNOWN = 140, /* for can tuners ? */ + AF9013_TUNER_MT2060_2 = 147, /* Microtune */ + AF9013_TUNER_TDA18271 = 156, /* NXP */ + AF9013_TUNER_QT1010A = 162, /* Quantek */ + AF9013_TUNER_MXL5007T = 177, /* MaxLinear */ + AF9013_TUNER_TDA18218 = 179, /* NXP */ +}; + +/* AF9013/5 GPIOs (mostly guessed) + demod#1-gpio#0 - set demod#2 i2c-addr for dual devices + demod#1-gpio#1 - xtal setting (?) + demod#1-gpio#3 - tuner#1 + demod#2-gpio#0 - tuner#2 + demod#2-gpio#1 - xtal setting (?) +*/ +#define AF9013_GPIO_ON (1 << 0) +#define AF9013_GPIO_EN (1 << 1) +#define AF9013_GPIO_O (1 << 2) +#define AF9013_GPIO_I (1 << 3) + +#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN) +#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) + +#define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN) +#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) + +struct af9013_config { + /* demodulator's I2C address */ + u8 demod_address; + + /* frequencies in kHz */ + u32 adc_clock; + + /* tuner ID */ + u8 tuner; + + /* tuner IF */ + u16 tuner_if; + + /* TS data output mode */ + u8 output_mode:2; + + /* RF spectrum inversion */ + u8 rf_spec_inv:1; + + /* API version */ + u8 api_version[4]; + + /* GPIOs */ + u8 gpio[4]; +}; + + +#if defined(CONFIG_DVB_AF9013) || \ + (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE)) +extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *af9013_attach( +const struct af9013_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_AF9013 */ + +#endif /* _AF9013_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/af9013_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,923 @@ +/* + * Afatech AF9013 demodulator driver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _AF9013_PRIV_ +#define _AF9013_PRIV_ + +#define LOG_PREFIX "af9013" +extern int af9013_debug; + +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) + +#define debug_dump(b, l, func) {\ + int loop_; \ + for (loop_ = 0; loop_ < l; loop_++) \ + func("%02x ", b[loop_]); \ + func("\n");\ +} + +#define deb_info(args...) dprintk(af9013_debug, 0x01, args) + +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +#define AF9013_DEFAULT_FIRMWARE "dvb-fe-af9013.fw" + +struct regdesc { + u16 addr; + u8 pos:4; + u8 len:4; + u8 val; +}; + +struct snr_table { + u32 val; + u8 snr; +}; + +struct coeff { + u32 adc_clock; + fe_bandwidth_t bw; + u8 val[24]; +}; + +/* pre-calculated coeff lookup table */ +static struct coeff coeff_table[] = { + /* 28.800 MHz */ + { 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14, + 0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a, + 0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } }, + { 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71, + 0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38, + 0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } }, + { 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf, + 0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7, + 0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } }, + /* 20.480 MHz */ + { 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24, + 0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92, + 0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } }, + { 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40, + 0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00, + 0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } }, + { 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b, + 0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d, + 0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } }, + /* 28.000 MHz */ + { 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39, + 0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f, + 0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } }, + { 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92, + 0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49, + 0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } }, + { 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb, + 0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63, + 0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } }, + /* 25.000 MHz */ + { 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9, + 0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e, + 0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } }, + { 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e, + 0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7, + 0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } }, + { 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63, + 0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f, + 0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } }, +}; + +/* QPSK SNR lookup table */ +static struct snr_table qpsk_snr_table[] = { + { 0x0b4771, 0 }, + { 0x0c1aed, 1 }, + { 0x0d0d27, 2 }, + { 0x0e4d19, 3 }, + { 0x0e5da8, 4 }, + { 0x107097, 5 }, + { 0x116975, 6 }, + { 0x1252d9, 7 }, + { 0x131fa4, 8 }, + { 0x13d5e1, 9 }, + { 0x148e53, 10 }, + { 0x15358b, 11 }, + { 0x15dd29, 12 }, + { 0x168112, 13 }, + { 0x170b61, 14 }, + { 0xffffff, 15 }, +}; + +/* QAM16 SNR lookup table */ +static struct snr_table qam16_snr_table[] = { + { 0x05eb62, 5 }, + { 0x05fecf, 6 }, + { 0x060b80, 7 }, + { 0x062501, 8 }, + { 0x064865, 9 }, + { 0x069604, 10 }, + { 0x06f356, 11 }, + { 0x07706a, 12 }, + { 0x0804d3, 13 }, + { 0x089d1a, 14 }, + { 0x093e3d, 15 }, + { 0x09e35d, 16 }, + { 0x0a7c3c, 17 }, + { 0x0afaf8, 18 }, + { 0x0b719d, 19 }, + { 0xffffff, 20 }, +}; + +/* QAM64 SNR lookup table */ +static struct snr_table qam64_snr_table[] = { + { 0x03109b, 12 }, + { 0x0310d4, 13 }, + { 0x031920, 14 }, + { 0x0322d0, 15 }, + { 0x0339fc, 16 }, + { 0x0364a1, 17 }, + { 0x038bcc, 18 }, + { 0x03c7d3, 19 }, + { 0x0408cc, 20 }, + { 0x043bed, 21 }, + { 0x048061, 22 }, + { 0x04be95, 23 }, + { 0x04fa7d, 24 }, + { 0x052405, 25 }, + { 0x05570d, 26 }, + { 0xffffff, 27 }, +}; + +static struct regdesc ofsm_init[] = { + { 0xd73a, 0, 8, 0xa1 }, + { 0xd73b, 0, 8, 0x1f }, + { 0xd73c, 4, 4, 0x0a }, + { 0xd732, 3, 1, 0x00 }, + { 0xd731, 4, 2, 0x03 }, + { 0xd73d, 7, 1, 0x01 }, + { 0xd740, 0, 1, 0x00 }, + { 0xd740, 1, 1, 0x00 }, + { 0xd740, 2, 1, 0x00 }, + { 0xd740, 3, 1, 0x01 }, + { 0xd3c1, 4, 1, 0x01 }, + { 0x9124, 0, 8, 0x58 }, + { 0x9125, 0, 2, 0x02 }, + { 0xd3a2, 0, 8, 0x00 }, + { 0xd3a3, 0, 8, 0x04 }, + { 0xd305, 0, 8, 0x32 }, + { 0xd306, 0, 8, 0x10 }, + { 0xd304, 0, 8, 0x04 }, + { 0x9112, 0, 1, 0x01 }, + { 0x911d, 0, 1, 0x01 }, + { 0x911a, 0, 1, 0x01 }, + { 0x911b, 0, 1, 0x01 }, + { 0x9bce, 0, 4, 0x02 }, + { 0x9116, 0, 1, 0x01 }, + { 0x9122, 0, 8, 0xd0 }, + { 0xd2e0, 0, 8, 0xd0 }, + { 0xd2e9, 0, 4, 0x0d }, + { 0xd38c, 0, 8, 0xfc }, + { 0xd38d, 0, 8, 0x00 }, + { 0xd38e, 0, 8, 0x7e }, + { 0xd38f, 0, 8, 0x00 }, + { 0xd390, 0, 8, 0x2f }, + { 0xd145, 4, 1, 0x01 }, + { 0xd1a9, 4, 1, 0x01 }, + { 0xd158, 5, 3, 0x01 }, + { 0xd159, 0, 6, 0x06 }, + { 0xd167, 0, 8, 0x00 }, + { 0xd168, 0, 4, 0x07 }, + { 0xd1c3, 5, 3, 0x00 }, + { 0xd1c4, 0, 6, 0x00 }, + { 0xd1c5, 0, 7, 0x10 }, + { 0xd1c6, 0, 3, 0x02 }, + { 0xd080, 2, 5, 0x03 }, + { 0xd081, 4, 4, 0x09 }, + { 0xd098, 4, 4, 0x0f }, + { 0xd098, 0, 4, 0x03 }, + { 0xdbc0, 4, 1, 0x01 }, + { 0xdbc7, 0, 8, 0x08 }, + { 0xdbc8, 4, 4, 0x00 }, + { 0xdbc9, 0, 5, 0x01 }, + { 0xd280, 0, 8, 0xe0 }, + { 0xd281, 0, 8, 0xff }, + { 0xd282, 0, 8, 0xff }, + { 0xd283, 0, 8, 0xc3 }, + { 0xd284, 0, 8, 0xff }, + { 0xd285, 0, 4, 0x01 }, + { 0xd0f0, 0, 7, 0x1a }, + { 0xd0f1, 4, 1, 0x01 }, + { 0xd0f2, 0, 8, 0x0c }, + { 0xd101, 5, 3, 0x06 }, + { 0xd103, 0, 4, 0x08 }, + { 0xd0f8, 0, 7, 0x20 }, + { 0xd111, 5, 1, 0x00 }, + { 0xd111, 6, 1, 0x00 }, + { 0x910b, 0, 8, 0x0a }, + { 0x9115, 0, 8, 0x02 }, + { 0x910c, 0, 8, 0x02 }, + { 0x910d, 0, 8, 0x08 }, + { 0x910e, 0, 8, 0x0a }, + { 0x9bf6, 0, 8, 0x06 }, + { 0x9bf8, 0, 8, 0x02 }, + { 0x9bf7, 0, 8, 0x05 }, + { 0x9bf9, 0, 8, 0x0f }, + { 0x9bfc, 0, 8, 0x13 }, + { 0x9bd3, 0, 8, 0xff }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, +}; + +/* Panasonic ENV77H11D5 tuner init + AF9013_TUNER_ENV77H11D5 = 129 */ +static struct regdesc tuner_init_env77h11d5[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x03 }, + { 0x9bbe, 0, 8, 0x01 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x00 }, + { 0x9be3, 0, 8, 0x00 }, + { 0xd015, 0, 8, 0x50 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0xdf }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x44 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0xeb }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0xf4 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bba, 0, 8, 0xf9 }, + { 0x9bc3, 0, 8, 0xdf }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0xeb }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bc9, 0, 8, 0x52 }, + { 0xd011, 0, 8, 0x3c }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0xf7 }, + { 0xd014, 0, 2, 0x02 }, + { 0xd040, 0, 8, 0x0b }, + { 0xd041, 0, 2, 0x02 }, + { 0xd042, 0, 8, 0x4d }, + { 0xd043, 0, 2, 0x00 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, +}; + +/* Microtune MT2060 tuner init + AF9013_TUNER_MT2060 = 130 */ +static struct regdesc tuner_init_mt2060[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x07 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x00 }, + { 0x9be3, 0, 8, 0x00 }, + { 0x9bbe, 0, 1, 0x00 }, + { 0x9bcc, 0, 1, 0x00 }, + { 0x9bb9, 0, 8, 0x75 }, + { 0x9bcd, 0, 8, 0x24 }, + { 0x9bff, 0, 8, 0x30 }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x32 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x36 }, + { 0xd00d, 0, 2, 0x03 }, + { 0xd00a, 0, 8, 0x35 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x07 }, + { 0x9bc8, 0, 8, 0x90 }, + { 0x9bc3, 0, 8, 0x0f }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x36 }, + { 0x9bc6, 0, 8, 0x03 }, + { 0x9bba, 0, 8, 0xc9 }, + { 0x9bc9, 0, 8, 0x79 }, + { 0xd011, 0, 8, 0x10 }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0x45 }, + { 0xd014, 0, 2, 0x03 }, + { 0xd040, 0, 8, 0x98 }, + { 0xd041, 0, 2, 0x00 }, + { 0xd042, 0, 8, 0xcf }, + { 0xd043, 0, 2, 0x03 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0xcc }, + { 0x9be4, 0, 8, 0xa0 }, + { 0x9bbd, 0, 8, 0x8e }, + { 0x9be2, 0, 8, 0x4d }, + { 0x9bee, 0, 1, 0x01 }, +}; + +/* Microtune MT2060 tuner init + AF9013_TUNER_MT2060_2 = 147 */ +static struct regdesc tuner_init_mt2060_2[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x06 }, + { 0x9bbe, 0, 8, 0x01 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x32 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x36 }, + { 0xd00d, 0, 2, 0x03 }, + { 0xd00a, 0, 8, 0x35 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x07 }, + { 0x9bc8, 0, 8, 0x90 }, + { 0x9bc3, 0, 8, 0x0f }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x36 }, + { 0x9bc6, 0, 8, 0x03 }, + { 0x9bba, 0, 8, 0xc9 }, + { 0x9bc9, 0, 8, 0x79 }, + { 0xd011, 0, 8, 0x10 }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0x45 }, + { 0xd014, 0, 2, 0x03 }, + { 0xd040, 0, 8, 0x98 }, + { 0xd041, 0, 2, 0x00 }, + { 0xd042, 0, 8, 0xcf }, + { 0xd043, 0, 2, 0x03 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 8, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x96 }, + { 0xd054, 0, 8, 0x46 }, + { 0xd045, 7, 1, 0x00 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, +}; + +/* MaxLinear MXL5003 tuner init + AF9013_TUNER_MXL5003D = 3 */ +static struct regdesc tuner_init_mxl5003d[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x09 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x00 }, + { 0x9be3, 0, 8, 0x00 }, + { 0x9bfc, 0, 8, 0x0f }, + { 0x9bf6, 0, 8, 0x01 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0xd015, 0, 8, 0x33 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x40 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x6c }, + { 0xd007, 0, 2, 0x00 }, + { 0xd00c, 0, 8, 0x3d }, + { 0xd00d, 0, 2, 0x00 }, + { 0xd00a, 0, 8, 0x45 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x07 }, + { 0x9bc8, 0, 8, 0x52 }, + { 0x9bc3, 0, 8, 0x0f }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x3d }, + { 0x9bc6, 0, 8, 0x00 }, + { 0x9bba, 0, 8, 0xa2 }, + { 0x9bc9, 0, 8, 0xa0 }, + { 0xd011, 0, 8, 0x56 }, + { 0xd012, 0, 2, 0x00 }, + { 0xd013, 0, 8, 0x50 }, + { 0xd014, 0, 2, 0x00 }, + { 0xd040, 0, 8, 0x56 }, + { 0xd041, 0, 2, 0x00 }, + { 0xd042, 0, 8, 0x50 }, + { 0xd043, 0, 2, 0x00 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 8, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, +}; + +/* MaxLinear MXL5005S & MXL5007T tuner init + AF9013_TUNER_MXL5005D = 13 + AF9013_TUNER_MXL5005R = 30 + AF9013_TUNER_MXL5007T = 177 */ +static struct regdesc tuner_init_mxl5005[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x07 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x01 }, + { 0x9be3, 0, 8, 0x01 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x28 }, + { 0x9bff, 0, 8, 0x24 }, + { 0xd015, 0, 8, 0x40 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x40 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x73 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0xfa }, + { 0xd00d, 0, 2, 0x01 }, + { 0xd00a, 0, 8, 0xff }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x23 }, + { 0x9bc8, 0, 8, 0x55 }, + { 0x9bc3, 0, 8, 0x01 }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0xfa }, + { 0x9bc6, 0, 8, 0x01 }, + { 0x9bba, 0, 8, 0xff }, + { 0x9bc9, 0, 8, 0xff }, + { 0x9bd3, 0, 8, 0x95 }, + { 0xd011, 0, 8, 0x70 }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0xfb }, + { 0xd014, 0, 2, 0x01 }, + { 0xd040, 0, 8, 0x70 }, + { 0xd041, 0, 2, 0x01 }, + { 0xd042, 0, 8, 0xfb }, + { 0xd043, 0, 2, 0x01 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0x93 }, + { 0x9be4, 0, 8, 0xfe }, + { 0x9bbd, 0, 8, 0x63 }, + { 0x9be2, 0, 8, 0xfe }, + { 0x9bee, 0, 1, 0x01 }, +}; + +/* Quantek QT1010 tuner init + AF9013_TUNER_QT1010 = 134 + AF9013_TUNER_QT1010A = 162 */ +static struct regdesc tuner_init_qt1010[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x09 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x01 }, + { 0x9be3, 0, 8, 0x01 }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x28 }, + { 0x9bff, 0, 8, 0x20 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x99 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x0f }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0x50 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x00 }, + { 0x9bc8, 0, 8, 0x00 }, + { 0x9bc3, 0, 8, 0x0f }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x0f }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bba, 0, 8, 0xc5 }, + { 0x9bc9, 0, 8, 0xff }, + { 0xd011, 0, 8, 0x58 }, + { 0xd012, 0, 2, 0x02 }, + { 0xd013, 0, 8, 0x89 }, + { 0xd014, 0, 2, 0x01 }, + { 0xd040, 0, 8, 0x58 }, + { 0xd041, 0, 2, 0x02 }, + { 0xd042, 0, 8, 0x89 }, + { 0xd043, 0, 2, 0x01 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0xcd }, + { 0x9be4, 0, 8, 0xbb }, + { 0x9bbd, 0, 8, 0x93 }, + { 0x9be2, 0, 8, 0x80 }, + { 0x9bee, 0, 1, 0x01 }, +}; + +/* Freescale MC44S803 tuner init + AF9013_TUNER_MC44S803 = 133 */ +static struct regdesc tuner_init_mc44s803[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x06 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x00 }, + { 0x9be3, 0, 8, 0x00 }, + { 0x9bf6, 0, 8, 0x01 }, + { 0x9bf8, 0, 8, 0x02 }, + { 0x9bf9, 0, 8, 0x02 }, + { 0x9bfc, 0, 8, 0x1f }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x24 }, + { 0x9bff, 0, 8, 0x24 }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x01 }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x7b }, + { 0xd007, 0, 2, 0x00 }, + { 0xd00c, 0, 8, 0x7c }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0xfe }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x08 }, + { 0x9bc8, 0, 8, 0x9a }, + { 0x9bc3, 0, 8, 0x01 }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x7c }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bba, 0, 8, 0xfc }, + { 0x9bc9, 0, 8, 0xaa }, + { 0xd011, 0, 8, 0x6b }, + { 0xd012, 0, 2, 0x00 }, + { 0xd013, 0, 8, 0x88 }, + { 0xd014, 0, 2, 0x02 }, + { 0xd040, 0, 8, 0x6b }, + { 0xd041, 0, 2, 0x00 }, + { 0xd042, 0, 8, 0x7c }, + { 0xd043, 0, 2, 0x02 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0x9e }, + { 0x9be4, 0, 8, 0xff }, + { 0x9bbd, 0, 8, 0x9e }, + { 0x9be2, 0, 8, 0x25 }, + { 0x9bee, 0, 1, 0x01 }, + { 0xd73b, 3, 1, 0x00 }, +}; + +/* unknown, probably for tin can tuner, tuner init + AF9013_TUNER_UNKNOWN = 140 */ +static struct regdesc tuner_init_unknown[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x02 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x01 }, + { 0x9be3, 0, 8, 0x01 }, + { 0xd1a0, 1, 1, 0x00 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x18 }, + { 0x9bff, 0, 8, 0x2c }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0xdf }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x44 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x00 }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0xf6 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bba, 0, 8, 0xf9 }, + { 0x9bc8, 0, 8, 0xaa }, + { 0x9bc3, 0, 8, 0xdf }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x00 }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bc9, 0, 8, 0xf0 }, + { 0xd011, 0, 8, 0x3c }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0xf7 }, + { 0xd014, 0, 2, 0x02 }, + { 0xd040, 0, 8, 0x0b }, + { 0xd041, 0, 2, 0x02 }, + { 0xd042, 0, 8, 0x4d }, + { 0xd043, 0, 2, 0x00 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, +}; + +/* NXP TDA18271 & TDA18218 tuner init + AF9013_TUNER_TDA18271 = 156 + AF9013_TUNER_TDA18218 = 179 */ +static struct regdesc tuner_init_tda18271[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x04 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x01 }, + { 0x9be3, 0, 8, 0x01 }, + { 0xd1a0, 1, 1, 0x00 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x18 }, + { 0x9bff, 0, 8, 0x2c }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0xdf }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x44 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x00 }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0xf6 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bba, 0, 8, 0xf9 }, + { 0x9bc8, 0, 8, 0xaa }, + { 0x9bc3, 0, 8, 0xdf }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x00 }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bc9, 0, 8, 0xf0 }, + { 0xd011, 0, 8, 0x3c }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0xf7 }, + { 0xd014, 0, 2, 0x02 }, + { 0xd040, 0, 8, 0x0b }, + { 0xd041, 0, 2, 0x02 }, + { 0xd042, 0, 8, 0x4d }, + { 0xd043, 0, 2, 0x00 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0xa8 }, + { 0x9be4, 0, 8, 0x7f }, + { 0x9bbd, 0, 8, 0xa8 }, + { 0x9be2, 0, 8, 0x20 }, + { 0x9bee, 0, 1, 0x01 }, +}; + +#endif /* _AF9013_PRIV_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,509 @@ +/* + * Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator + * ATBM8830, ATBM8831 + * + * Copyright (C) 2009 David T.L. Wong + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "dvb_frontend.h" + +#include "atbm8830.h" +#include "atbm8830_priv.h" + +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "atbm8830: " args); \ + } while (0) + +static int debug; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data) +{ + int ret = 0; + u8 dev_addr; + u8 buf1[] = { reg >> 8, reg & 0xFF }; + u8 buf2[] = { data }; + struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 }; + struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 }; + + dev_addr = priv->config->demod_address; + msg1.addr = dev_addr; + msg2.addr = dev_addr; + + if (debug >= 2) + dprintk("%s: reg=0x%04X, data=0x%02X\n", __func__, reg, data); + + ret = i2c_transfer(priv->i2c, &msg1, 1); + if (ret != 1) + return -EIO; + + ret = i2c_transfer(priv->i2c, &msg2, 1); + return (ret != 1) ? -EIO : 0; +} + +static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data) +{ + int ret; + u8 dev_addr; + + u8 buf1[] = { reg >> 8, reg & 0xFF }; + u8 buf2[] = { 0 }; + struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 }; + struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 }; + + dev_addr = priv->config->demod_address; + msg1.addr = dev_addr; + msg2.addr = dev_addr; + + ret = i2c_transfer(priv->i2c, &msg1, 1); + if (ret != 1) { + dprintk("%s: error reg=0x%04x, ret=%i\n", __func__, reg, ret); + return -EIO; + } + + ret = i2c_transfer(priv->i2c, &msg2, 1); + if (ret != 1) + return -EIO; + + *p_data = buf2[0]; + if (debug >= 2) + dprintk("%s: reg=0x%04X, data=0x%02X\n", + __func__, reg, buf2[0]); + + return 0; +} + +/* Lock register latch so that multi-register read is atomic */ +static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock) +{ + return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0); +} + +static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/) +{ + u32 val; + u64 t; + + /* 0x100000 * freq / 30.4MHz */ + t = (u64)0x100000 * freq; + do_div(t, 30400); + val = t; + + atbm8830_write_reg(priv, REG_OSC_CLK, val); + atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8); + atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16); + + return 0; +} + +static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/) +{ + + u32 fs = priv->config->osc_clk_freq; + u64 t; + u32 val; + u8 dat; + + if (freq != 0) { + /* 2 * PI * (freq - fs) / fs * (2 ^ 22) */ + t = (u64) 2 * 31416 * (freq - fs); + t <<= 22; + do_div(t, fs); + do_div(t, 1000); + val = t; + + atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1); + atbm8830_write_reg(priv, REG_IF_FREQ, val); + atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8); + atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16); + + atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat); + dat &= 0xFC; + atbm8830_write_reg(priv, REG_ADC_CONFIG, dat); + } else { + /* Zero IF */ + atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0); + + atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat); + dat &= 0xFC; + dat |= 0x02; + atbm8830_write_reg(priv, REG_ADC_CONFIG, dat); + + if (priv->config->zif_swap_iq) + atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03); + else + atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01); + } + + return 0; +} + +static int is_locked(struct atbm_state *priv, u8 *locked) +{ + u8 status; + + atbm8830_read_reg(priv, REG_LOCK_STATUS, &status); + + if (locked != NULL) + *locked = (status == 1); + return 0; +} + +static int set_agc_config(struct atbm_state *priv, + u8 min, u8 max, u8 hold_loop) +{ + /* no effect if both min and max are zero */ + if (!min && !max) + return 0; + + atbm8830_write_reg(priv, REG_AGC_MIN, min); + atbm8830_write_reg(priv, REG_AGC_MAX, max); + atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop); + + return 0; +} + +static int set_static_channel_mode(struct atbm_state *priv) +{ + int i; + + for (i = 0; i < 5; i++) + atbm8830_write_reg(priv, 0x099B + i, 0x08); + + atbm8830_write_reg(priv, 0x095B, 0x7F); + atbm8830_write_reg(priv, 0x09CB, 0x01); + atbm8830_write_reg(priv, 0x09CC, 0x7F); + atbm8830_write_reg(priv, 0x09CD, 0x7F); + atbm8830_write_reg(priv, 0x0E01, 0x20); + + /* For single carrier */ + atbm8830_write_reg(priv, 0x0B03, 0x0A); + atbm8830_write_reg(priv, 0x0935, 0x10); + atbm8830_write_reg(priv, 0x0936, 0x08); + atbm8830_write_reg(priv, 0x093E, 0x08); + atbm8830_write_reg(priv, 0x096E, 0x06); + + /* frame_count_max0 */ + atbm8830_write_reg(priv, 0x0B09, 0x00); + /* frame_count_max1 */ + atbm8830_write_reg(priv, 0x0B0A, 0x08); + + return 0; +} + +static int set_ts_config(struct atbm_state *priv) +{ + const struct atbm8830_config *cfg = priv->config; + + /*Set parallel/serial ts mode*/ + atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0); + atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0); + /*Set ts sampling edge*/ + atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE, + cfg->ts_sampling_edge ? 1 : 0); + /*Set ts clock freerun*/ + atbm8830_write_reg(priv, REG_TS_CLK_FREERUN, + cfg->ts_clk_gated ? 0 : 1); + + return 0; +} + +static int atbm8830_init(struct dvb_frontend *fe) +{ + struct atbm_state *priv = fe->demodulator_priv; + const struct atbm8830_config *cfg = priv->config; + + /*Set oscillator frequency*/ + set_osc_freq(priv, cfg->osc_clk_freq); + + /*Set IF frequency*/ + set_if_freq(priv, cfg->if_freq); + + /*Set AGC Config*/ + set_agc_config(priv, cfg->agc_min, cfg->agc_max, + cfg->agc_hold_loop); + + /*Set static channel mode*/ + set_static_channel_mode(priv); + + set_ts_config(priv); + /*Turn off DSP reset*/ + atbm8830_write_reg(priv, 0x000A, 0); + + /*SW version test*/ + atbm8830_write_reg(priv, 0x020C, 11); + + /* Run */ + atbm8830_write_reg(priv, REG_DEMOD_RUN, 1); + + return 0; +} + + +static void atbm8830_release(struct dvb_frontend *fe) +{ + struct atbm_state *state = fe->demodulator_priv; + dprintk("%s\n", __func__); + + kfree(state); +} + +static int atbm8830_set_fe(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fe_params) +{ + struct atbm_state *priv = fe->demodulator_priv; + int i; + u8 locked = 0; + dprintk("%s\n", __func__); + + /* set frequency */ + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, fe_params); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* start auto lock */ + for (i = 0; i < 10; i++) { + mdelay(100); + dprintk("Try %d\n", i); + is_locked(priv, &locked); + if (locked != 0) { + dprintk("ATBM8830 locked!\n"); + break; + } + } + + return 0; +} + +static int atbm8830_get_fe(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fe_params) +{ + dprintk("%s\n", __func__); + + /* TODO: get real readings from device */ + /* inversion status */ + fe_params->inversion = INVERSION_OFF; + + /* bandwidth */ + fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + + fe_params->u.ofdm.code_rate_HP = FEC_AUTO; + fe_params->u.ofdm.code_rate_LP = FEC_AUTO; + + fe_params->u.ofdm.constellation = QAM_AUTO; + + /* transmission mode */ + fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + + /* guard interval */ + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + + /* hierarchy */ + fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + + return 0; +} + +static int atbm8830_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 0; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status) +{ + struct atbm_state *priv = fe->demodulator_priv; + u8 locked = 0; + u8 agc_locked = 0; + + dprintk("%s\n", __func__); + *fe_status = 0; + + is_locked(priv, &locked); + if (locked) { + *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } + dprintk("%s: fe_status=0x%x\n", __func__, *fe_status); + + atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked); + dprintk("AGC Lock: %d\n", agc_locked); + + return 0; +} + +static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct atbm_state *priv = fe->demodulator_priv; + u32 frame_err; + u8 t; + + dprintk("%s\n", __func__); + + atbm8830_reglatch_lock(priv, 1); + + atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t); + frame_err = t & 0x7F; + frame_err <<= 8; + atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t); + frame_err |= t; + + atbm8830_reglatch_lock(priv, 0); + + *ber = frame_err * 100 / 32767; + + dprintk("%s: ber=0x%x\n", __func__, *ber); + return 0; +} + +static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal) +{ + struct atbm_state *priv = fe->demodulator_priv; + u32 pwm; + u8 t; + + dprintk("%s\n", __func__); + atbm8830_reglatch_lock(priv, 1); + + atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t); + pwm = t & 0x03; + pwm <<= 8; + atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t); + pwm |= t; + + atbm8830_reglatch_lock(priv, 0); + + dprintk("AGC PWM = 0x%02X\n", pwm); + pwm = 0x400 - pwm; + + *signal = pwm * 0x10000 / 0x400; + + return 0; +} + +static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + dprintk("%s\n", __func__); + *snr = 0; + return 0; +} + +static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + dprintk("%s\n", __func__); + *ucblocks = 0; + return 0; +} + +static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct atbm_state *priv = fe->demodulator_priv; + + return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0); +} + +static struct dvb_frontend_ops atbm8830_ops = { + .info = { + .name = "AltoBeam ATBM8830/8831 DMB-TH", + .type = FE_OFDM, + .frequency_min = 474000000, + .frequency_max = 858000000, + .frequency_stepsize = 10000, + .caps = + FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = atbm8830_release, + + .init = atbm8830_init, + .sleep = NULL, + .write = NULL, + .i2c_gate_ctrl = atbm8830_i2c_gate_ctrl, + + .set_frontend = atbm8830_set_fe, + .get_frontend = atbm8830_get_fe, + .get_tune_settings = atbm8830_get_tune_settings, + + .read_status = atbm8830_read_status, + .read_ber = atbm8830_read_ber, + .read_signal_strength = atbm8830_read_signal_strength, + .read_snr = atbm8830_read_snr, + .read_ucblocks = atbm8830_read_ucblocks, +}; + +struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, + struct i2c_adapter *i2c) +{ + struct atbm_state *priv = NULL; + u8 data = 0; + + dprintk("%s()\n", __func__); + + if (config == NULL || i2c == NULL) + return NULL; + + priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL); + if (priv == NULL) + goto error_out; + + priv->config = config; + priv->i2c = i2c; + + /* check if the demod is there */ + if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) { + dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n", + __func__, priv->config->demod_address); + goto error_out; + } + dprintk("atbm8830 chip id: 0x%02X\n", data); + + memcpy(&priv->frontend.ops, &atbm8830_ops, + sizeof(struct dvb_frontend_ops)); + priv->frontend.demodulator_priv = priv; + + atbm8830_init(&priv->frontend); + + atbm8830_i2c_gate_ctrl(&priv->frontend, 1); + + return &priv->frontend; + +error_out: + dprintk("%s() error_out\n", __func__); + kfree(priv); + return NULL; + +} +EXPORT_SYMBOL(atbm8830_attach); + +MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver"); +MODULE_AUTHOR("David T. L. Wong "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,76 @@ +/* + * Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator + * ATBM8830, ATBM8831 + * + * Copyright (C) 2009 David T.L. Wong + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __ATBM8830_H__ +#define __ATBM8830_H__ + +#include +#include + +#define ATBM8830_PROD_8830 0 +#define ATBM8830_PROD_8831 1 + +struct atbm8830_config { + + /* product type */ + u8 prod; + + /* the demodulator's i2c address */ + u8 demod_address; + + /* parallel or serial transport stream */ + u8 serial_ts; + + /* transport stream clock output only when receiving valid stream */ + u8 ts_clk_gated; + + /* Decoder sample TS data at rising edge of clock */ + u8 ts_sampling_edge; + + /* Oscillator clock frequency */ + u32 osc_clk_freq; /* in kHz */ + + /* IF frequency */ + u32 if_freq; /* in kHz */ + + /* Swap I/Q for zero IF */ + u8 zif_swap_iq; + + /* Tuner AGC settings */ + u8 agc_min; + u8 agc_max; + u8 agc_hold_loop; +}; + +#if defined(CONFIG_DVB_ATBM8830) || \ + (defined(CONFIG_DVB_ATBM8830_MODULE) && defined(MODULE)) +extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, + struct i2c_adapter *i2c); +#else +static inline +struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, + struct i2c_adapter *i2c) { + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_ATBM8830 */ + +#endif /* __ATBM8830_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/atbm8830_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator + * ATBM8830, ATBM8831 + * + * Copyright (C) 2009 David T.L. Wong + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __ATBM8830_PRIV_H +#define __ATBM8830_PRIV_H + +struct atbm_state { + struct i2c_adapter *i2c; + /* configuration settings */ + const struct atbm8830_config *config; + struct dvb_frontend frontend; +}; + +#define REG_CHIP_ID 0x0000 +#define REG_TUNER_BASEBAND 0x0001 +#define REG_DEMOD_RUN 0x0004 +#define REG_DSP_RESET 0x0005 +#define REG_RAM_RESET 0x0006 +#define REG_ADC_RESET 0x0007 +#define REG_TSPORT_RESET 0x0008 +#define REG_BLKERR_POL 0x000C +#define REG_I2C_GATE 0x0103 +#define REG_TS_SAMPLE_EDGE 0x0301 +#define REG_TS_PKT_LEN_204 0x0302 +#define REG_TS_PKT_LEN_AUTO 0x0303 +#define REG_TS_SERIAL 0x0305 +#define REG_TS_CLK_FREERUN 0x0306 +#define REG_TS_VALID_MODE 0x0307 +#define REG_TS_CLK_MODE 0x030B /* 1 for serial, 0 for parallel */ + +#define REG_TS_ERRBIT_USE 0x030C +#define REG_LOCK_STATUS 0x030D +#define REG_ADC_CONFIG 0x0602 +#define REG_CARRIER_OFFSET 0x0827 /* 0x0827-0x0829 little endian */ +#define REG_DETECTED_PN_MODE 0x082D +#define REG_READ_LATCH 0x084D +#define REG_IF_FREQ 0x0A00 /* 0x0A00-0x0A02 little endian */ +#define REG_OSC_CLK 0x0A03 /* 0x0A03-0x0A05 little endian */ +#define REG_BYPASS_CCI 0x0A06 +#define REG_ANALOG_LUMA_DETECTED 0x0A25 +#define REG_ANALOG_AUDIO_DETECTED 0x0A26 +#define REG_ANALOG_CHROMA_DETECTED 0x0A39 +#define REG_FRAME_ERR_CNT 0x0B04 +#define REG_USE_EXT_ADC 0x0C00 +#define REG_SWAP_I_Q 0x0C01 +#define REG_TPS_MANUAL 0x0D01 +#define REG_TPS_CONFIG 0x0D02 +#define REG_BYPASS_DEINTERLEAVER 0x0E00 +#define REG_AGC_TARGET 0x1003 /* 0x1003-0x1005 little endian */ +#define REG_AGC_MIN 0x1020 +#define REG_AGC_MAX 0x1023 +#define REG_AGC_LOCK 0x1027 +#define REG_AGC_PWM_VAL 0x1028 /* 0x1028-0x1029 little endian */ +#define REG_AGC_HOLD_LOOP 0x1031 + +#endif + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_decoder.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_decoder.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,853 @@ +/* + * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder + * + * Copyright (C) 2009 Devin Heitmueller + * Copyright (C) 2005-2008 Auvitek International, Ltd. + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* Developer notes: + * + * VBI support is not yet working + * Enough is implemented here for CVBS and S-Video inputs, but the actual + * analog demodulator code isn't implemented (not needed for xc5000 since it + * has its own demodulator and outputs CVBS) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "au8522.h" +#include "au8522_priv.h" + +MODULE_AUTHOR("Devin Heitmueller"); +MODULE_LICENSE("GPL"); + +static int au8522_analog_debug; + + +module_param_named(analog_debug, au8522_analog_debug, int, 0644); + +MODULE_PARM_DESC(analog_debug, + "Analog debugging messages [0=Off (default) 1=On]"); + +struct au8522_register_config { + u16 reg_name; + u8 reg_val[8]; +}; + + +/* Video Decoder Filter Coefficients + The values are as follows from left to right + 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13" +*/ +static const struct au8522_register_config filter_coef[] = { + {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} }, + {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} }, + {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} }, + {AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} }, + {AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} }, + {AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} }, + {AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} }, + {AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} }, + {AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} }, + {AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} }, + {AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} }, + {AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} }, + {AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} }, + {AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} }, + {AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} }, + {AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} }, + {AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} }, + {AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} }, + {AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} }, + {AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} }, + {AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} }, + {AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} }, + {AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} }, + {AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} }, + {AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} }, + {AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} }, + {AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} }, + {AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} }, + {AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} }, + {AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} }, + +}; +#define NUM_FILTER_COEF (sizeof(filter_coef)\ + / sizeof(struct au8522_register_config)) + + +/* Registers 0x060b through 0x0652 are the LP Filter coefficients + The values are as follows from left to right + 0="SIF" 1="ATVRF/ATVRF13" + Note: the "ATVRF/ATVRF13" mode has never been tested +*/ +static const struct au8522_register_config lpfilter_coef[] = { + {0x060b, {0x21, 0x0b} }, + {0x060c, {0xad, 0xad} }, + {0x060d, {0x70, 0xf0} }, + {0x060e, {0xea, 0xe9} }, + {0x060f, {0xdd, 0xdd} }, + {0x0610, {0x08, 0x64} }, + {0x0611, {0x60, 0x60} }, + {0x0612, {0xf8, 0xb2} }, + {0x0613, {0x01, 0x02} }, + {0x0614, {0xe4, 0xb4} }, + {0x0615, {0x19, 0x02} }, + {0x0616, {0xae, 0x2e} }, + {0x0617, {0xee, 0xc5} }, + {0x0618, {0x56, 0x56} }, + {0x0619, {0x30, 0x58} }, + {0x061a, {0xf9, 0xf8} }, + {0x061b, {0x24, 0x64} }, + {0x061c, {0x07, 0x07} }, + {0x061d, {0x30, 0x30} }, + {0x061e, {0xa9, 0xed} }, + {0x061f, {0x09, 0x0b} }, + {0x0620, {0x42, 0xc2} }, + {0x0621, {0x1d, 0x2a} }, + {0x0622, {0xd6, 0x56} }, + {0x0623, {0x95, 0x8b} }, + {0x0624, {0x2b, 0x2b} }, + {0x0625, {0x30, 0x24} }, + {0x0626, {0x3e, 0x3e} }, + {0x0627, {0x62, 0xe2} }, + {0x0628, {0xe9, 0xf5} }, + {0x0629, {0x99, 0x19} }, + {0x062a, {0xd4, 0x11} }, + {0x062b, {0x03, 0x04} }, + {0x062c, {0xb5, 0x85} }, + {0x062d, {0x1e, 0x20} }, + {0x062e, {0x2a, 0xea} }, + {0x062f, {0xd7, 0xd2} }, + {0x0630, {0x15, 0x15} }, + {0x0631, {0xa3, 0xa9} }, + {0x0632, {0x1f, 0x1f} }, + {0x0633, {0xf9, 0xd1} }, + {0x0634, {0xc0, 0xc3} }, + {0x0635, {0x4d, 0x8d} }, + {0x0636, {0x21, 0x31} }, + {0x0637, {0x83, 0x83} }, + {0x0638, {0x08, 0x8c} }, + {0x0639, {0x19, 0x19} }, + {0x063a, {0x45, 0xa5} }, + {0x063b, {0xef, 0xec} }, + {0x063c, {0x8a, 0x8a} }, + {0x063d, {0xf4, 0xf6} }, + {0x063e, {0x8f, 0x8f} }, + {0x063f, {0x44, 0x0c} }, + {0x0640, {0xef, 0xf0} }, + {0x0641, {0x66, 0x66} }, + {0x0642, {0xcc, 0xd2} }, + {0x0643, {0x41, 0x41} }, + {0x0644, {0x63, 0x93} }, + {0x0645, {0x8e, 0x8e} }, + {0x0646, {0xa2, 0x42} }, + {0x0647, {0x7b, 0x7b} }, + {0x0648, {0x04, 0x04} }, + {0x0649, {0x00, 0x00} }, + {0x064a, {0x40, 0x40} }, + {0x064b, {0x8c, 0x98} }, + {0x064c, {0x00, 0x00} }, + {0x064d, {0x63, 0xc3} }, + {0x064e, {0x04, 0x04} }, + {0x064f, {0x20, 0x20} }, + {0x0650, {0x00, 0x00} }, + {0x0651, {0x40, 0x40} }, + {0x0652, {0x01, 0x01} }, +}; +#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\ + / sizeof(struct au8522_register_config)) + +static inline struct au8522_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct au8522_state, sd); +} + +static void setup_vbi(struct au8522_state *state, int aud_input) +{ + int i; + + /* These are set to zero regardless of what mode we're in */ + au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_L_REG018H, 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H, 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH, 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH, 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_THRESH1_REG01CH, 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH, 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH, 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H, 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H, + 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H, + 0x00); + au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H, + 0x00); + + /* Setup the VBI registers */ + for (i = 0x30; i < 0x60; i++) + au8522_writereg(state, i, 0x40); + + /* For some reason, every register is 0x40 except register 0x44 + (confirmed via the HVR-950q USB capture) */ + au8522_writereg(state, 0x44, 0x60); + + /* Enable VBI (we always do this regardless of whether the user is + viewing closed caption info) */ + au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, + AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON); + +} + +static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode) +{ + int i; + int filter_coef_type; + + /* Provide reasonable defaults for picture tuning values */ + au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07); + au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed); + state->brightness = 0xed - 128; + au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79); + state->contrast = 0x79; + au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80); + au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80); + state->saturation = 0x80; + au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00); + au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00); + state->hue = 0x00; + + /* Other decoder registers */ + au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00); + + if (input_mode == 0x23) { + /* S-Video input mapping */ + au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04); + } else { + /* All other modes (CVBS/ATVRF etc.) */ + au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00); + } + + au8522_writereg(state, AU8522_TVDEC_PGA_REG012H, + AU8522_TVDEC_PGA_REG012H_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H, + AU8522_TVDEC_COMB_MODE_REG015H_CVBS); + au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H, + AU8522_TVDED_DBG_MODE_REG060H_CVBS); + au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H, + AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13); + au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H, + AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13); + au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H, + AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS); + au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H, + AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H, + AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H, + AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H, + AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H, + AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H, + AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH, + AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH, + AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS); + if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 || + input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) { + au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH, + AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO); + au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH, + AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO); + } else { + au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH, + AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH, + AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS); + } + au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH, + AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS); + au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH, + AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H, + AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS); + au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS); + au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS); + au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H, + AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS); + au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS); + au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS); + au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H, + AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS); + au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H, + AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS); + au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H, + AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS); + au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH, + AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS); + au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH, + AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS); + au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H, + AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS); + au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H, + AU8522_TOREGAAGC_REG0E5H_CVBS); + au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS); + + setup_vbi(state, 0); + + if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 || + input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) { + /* Despite what the table says, for the HVR-950q we still need + to be in CVBS mode for the S-Video input (reason unknown). */ + /* filter_coef_type = 3; */ + filter_coef_type = 5; + } else { + filter_coef_type = 5; + } + + /* Load the Video Decoder Filter Coefficients */ + for (i = 0; i < NUM_FILTER_COEF; i++) { + au8522_writereg(state, filter_coef[i].reg_name, + filter_coef[i].reg_val[filter_coef_type]); + } + + /* It's not clear what these registers are for, but they are always + set to the same value regardless of what mode we're in */ + au8522_writereg(state, AU8522_REG42EH, 0x87); + au8522_writereg(state, AU8522_REG42FH, 0xa2); + au8522_writereg(state, AU8522_REG430H, 0xbf); + au8522_writereg(state, AU8522_REG431H, 0xcb); + au8522_writereg(state, AU8522_REG432H, 0xa1); + au8522_writereg(state, AU8522_REG433H, 0x41); + au8522_writereg(state, AU8522_REG434H, 0x88); + au8522_writereg(state, AU8522_REG435H, 0xc2); + au8522_writereg(state, AU8522_REG436H, 0x3c); +} + +static void au8522_setup_cvbs_mode(struct au8522_state *state) +{ + /* here we're going to try the pre-programmed route */ + au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H, + AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS); + + /* PGA in automatic mode */ + au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00); + + /* Enable clamping control */ + au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00); + + au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, + AU8522_INPUT_CONTROL_REG081H_CVBS_CH1); + + setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1); + + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, + AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); +} + +static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state) +{ + /* here we're going to try the pre-programmed route */ + au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H, + AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS); + + /* It's not clear why we have to have the PGA in automatic mode while + enabling clamp control, but it's what Windows does */ + au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00); + + /* Enable clamping control */ + au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e); + + /* Disable automatic PGA (since the CVBS is coming from the tuner) */ + au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10); + + /* Set input mode to CVBS on channel 4 with SIF audio input enabled */ + au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, + AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF); + + setup_decoder_defaults(state, + AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF); + + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, + AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); +} + +static void au8522_setup_svideo_mode(struct au8522_state *state) +{ + au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H, + AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO); + + /* Set input to Y on Channe1, C on Channel 3 */ + au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, + AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13); + + /* PGA in automatic mode */ + au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00); + + /* Enable clamping control */ + au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00); + + setup_decoder_defaults(state, + AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13); + + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, + AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); +} + +/* ----------------------------------------------------------------------- */ + +static void disable_audio_input(struct au8522_state *state) +{ + au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00); + au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00); + au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00); + + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04); + au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02); + + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, + AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO); +} + +/* 0=disable, 1=SIF */ +static void set_audio_input(struct au8522_state *state, int aud_input) +{ + int i; + + /* Note that this function needs to be used in conjunction with setting + the input routing via register 0x81 */ + + if (aud_input == AU8522_AUDIO_NONE) { + disable_audio_input(state); + return; + } + + if (aud_input != AU8522_AUDIO_SIF) { + /* The caller asked for a mode we don't currently support */ + printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n", + aud_input); + return; + } + + /* Load the Audio Decoder Filter Coefficients */ + for (i = 0; i < NUM_LPFILTER_COEF; i++) { + au8522_writereg(state, lpfilter_coef[i].reg_name, + lpfilter_coef[i].reg_val[0]); + } + + /* Setup audio */ + au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00); + au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00); + au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00); + au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80); + au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84); + msleep(150); + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00); + msleep(1); + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d); + msleep(50); + au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F); + au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F); + au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff); + msleep(80); + au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F); + au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F); + au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO); + au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82); + msleep(70); + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09); + au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03); + au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2); +} + +/* ----------------------------------------------------------------------- */ + +static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct au8522_state *state = to_state(sd); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + state->brightness = ctrl->value; + au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, + ctrl->value - 128); + break; + case V4L2_CID_CONTRAST: + state->contrast = ctrl->value; + au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, + ctrl->value); + break; + case V4L2_CID_SATURATION: + state->saturation = ctrl->value; + au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, + ctrl->value); + au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, + ctrl->value); + break; + case V4L2_CID_HUE: + state->hue = ctrl->value; + au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, + ctrl->value >> 8); + au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, + ctrl->value & 0xFF); + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_MUTE: + /* Not yet implemented */ + default: + return -EINVAL; + } + + return 0; +} + +static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct au8522_state *state = to_state(sd); + + /* Note that we are using values cached in the state structure instead + of reading the registers due to issues with i2c reads not working + properly/consistently yet on the HVR-950q */ + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = state->brightness; + break; + case V4L2_CID_CONTRAST: + ctrl->value = state->contrast; + break; + case V4L2_CID_SATURATION: + ctrl->value = state->saturation; + break; + case V4L2_CID_HUE: + ctrl->value = state->hue; + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_MUTE: + /* Not yet supported */ + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int au8522_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct au8522_state *state = to_state(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + reg->val = au8522_readreg(state, reg->reg & 0xffff); + return 0; +} + +static int au8522_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct au8522_state *state = to_state(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + au8522_writereg(state, reg->reg, reg->val & 0xff); + return 0; +} +#endif + +static int au8522_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct au8522_state *state = to_state(sd); + + if (enable) { + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, + 0x01); + msleep(1); + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, + AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); + } else { + /* This does not completely power down the device + (it only reduces it from around 140ma to 80ma) */ + au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, + 1 << 5); + } + return 0; +} + +static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_CONTRAST: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, + AU8522_TVDEC_CONTRAST_REG00BH_CVBS); + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109); + case V4L2_CID_SATURATION: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); + case V4L2_CID_HUE: + return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0); + default: + break; + } + + qc->type = 0; + return -EINVAL; +} + +static int au8522_reset(struct v4l2_subdev *sd, u32 val) +{ + struct au8522_state *state = to_state(sd); + + state->operational_mode = AU8522_ANALOG_MODE; + + /* Clear out any state associated with the digital side of the + chip, so that when it gets powered back up it won't think + that it is already tuned */ + state->current_frequency = 0; + + au8522_writereg(state, 0xa4, 1 << 5); + + return 0; +} + +static int au8522_s_video_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct au8522_state *state = to_state(sd); + + au8522_reset(sd, 0); + + /* Jam open the i2c gate to the tuner. We do this here to handle the + case where the user went into digital mode (causing the gate to be + closed), and then came back to analog mode */ + au8522_writereg(state, 0x106, 1); + + if (input == AU8522_COMPOSITE_CH1) { + au8522_setup_cvbs_mode(state); + } else if (input == AU8522_SVIDEO_CH13) { + au8522_setup_svideo_mode(state); + } else if (input == AU8522_COMPOSITE_CH4_SIF) { + au8522_setup_cvbs_tuner_mode(state); + } else { + printk(KERN_ERR "au8522 mode not currently supported\n"); + return -EINVAL; + } + return 0; +} + +static int au8522_s_audio_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct au8522_state *state = to_state(sd); + set_audio_input(state, input); + return 0; +} + +static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + int val = 0; + struct au8522_state *state = to_state(sd); + u8 lock_status; + + /* Interrogate the decoder to see if we are getting a real signal */ + lock_status = au8522_readreg(state, 0x00); + if (lock_status == 0xa2) + vt->signal = 0x01; + else + vt->signal = 0x00; + + vt->capability |= + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + + val = V4L2_TUNER_SUB_MONO; + vt->rxsubchans = val; + vt->audmode = V4L2_TUNER_MODE_STEREO; + return 0; +} + +static int au8522_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct au8522_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev); +} + +static int au8522_log_status(struct v4l2_subdev *sd) +{ + /* FIXME: Add some status info here */ + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops au8522_core_ops = { + .log_status = au8522_log_status, + .g_chip_ident = au8522_g_chip_ident, + .g_ctrl = au8522_g_ctrl, + .s_ctrl = au8522_s_ctrl, + .queryctrl = au8522_queryctrl, + .reset = au8522_reset, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = au8522_g_register, + .s_register = au8522_s_register, +#endif +}; + +static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = { + .g_tuner = au8522_g_tuner, +}; + +static const struct v4l2_subdev_audio_ops au8522_audio_ops = { + .s_routing = au8522_s_audio_routing, +}; + +static const struct v4l2_subdev_video_ops au8522_video_ops = { + .s_routing = au8522_s_video_routing, + .s_stream = au8522_s_stream, +}; + +static const struct v4l2_subdev_ops au8522_ops = { + .core = &au8522_core_ops, + .tuner = &au8522_tuner_ops, + .audio = &au8522_audio_ops, + .video = &au8522_video_ops, +}; + +/* ----------------------------------------------------------------------- */ + +static int au8522_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct au8522_state *state; + struct v4l2_subdev *sd; + int instance; + struct au8522_config *demod_config; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + return -EIO; + } + + /* allocate memory for the internal state */ + instance = au8522_get_state(&state, client->adapter, client->addr); + switch (instance) { + case 0: + printk(KERN_ERR "au8522_decoder allocation failed\n"); + return -EIO; + case 1: + /* new demod instance */ + printk(KERN_INFO "au8522_decoder creating new instance...\n"); + break; + default: + /* existing demod instance */ + printk(KERN_INFO "au8522_decoder attach existing instance.\n"); + break; + } + + demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL); + if (demod_config == NULL) { + if (instance == 1) + kfree(state); + return -ENOMEM; + } + demod_config->demod_address = 0x8e >> 1; + + state->config = demod_config; + state->i2c = client->adapter; + + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &au8522_ops); + + state->c = client; + state->vid_input = AU8522_COMPOSITE_CH1; + state->aud_input = AU8522_AUDIO_NONE; + state->id = 8522; + state->rev = 0; + + /* Jam open the i2c gate to the tuner */ + au8522_writereg(state, 0x106, 1); + + return 0; +} + +static int au8522_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + v4l2_device_unregister_subdev(sd); + au8522_release_state(to_state(sd)); + return 0; +} + +static const struct i2c_device_id au8522_id[] = { + {"au8522", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, au8522_id); + +static struct i2c_driver au8522_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "au8522", + }, + .probe = au8522_probe, + .remove = au8522_remove, + .id_table = au8522_id, +}; + +static __init int init_au8522(void) +{ + return i2c_add_driver(&au8522_driver); +} + +static __exit void exit_au8522(void) +{ + i2c_del_driver(&au8522_driver); +} + +module_init(init_au8522); +module_exit(exit_au8522); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_dig.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_dig.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_dig.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_dig.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1013 @@ +/* + Auvitek AU8522 QAM/8VSB demodulator driver + + Copyright (C) 2008 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "au8522.h" +#include "au8522_priv.h" + +static int debug; + +/* Despite the name "hybrid_tuner", the framework works just as well for + hybrid demodulators as well... */ +static LIST_HEAD(hybrid_tuner_instance_list); +static DEFINE_MUTEX(au8522_list_mutex); + +#define dprintk(arg...)\ + do { if (debug)\ + printk(arg);\ + } while (0) + +/* 16 bit registers, 8 bit values */ +int au8522_writereg(struct au8522_state *state, u16 reg, u8 data) +{ + int ret; + u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data }; + + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 3 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +u8 au8522_readreg(struct au8522_state *state, u16 reg) +{ + int ret; + u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff }; + u8 b1[] = { 0 }; + + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk(KERN_ERR "%s: readreg error (ret == %i)\n", + __func__, ret); + return b1[0]; +} + +static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct au8522_state *state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __func__, enable); + + if (state->operational_mode == AU8522_ANALOG_MODE) { + /* We're being asked to manage the gate even though we're + not in digital mode. This can occur if we get switched + over to analog mode before the dvb_frontend kernel thread + has completely shutdown */ + return 0; + } + + if (enable) + return au8522_writereg(state, 0x106, 1); + else + return au8522_writereg(state, 0x106, 0); +} + +struct mse2snr_tab { + u16 val; + u16 data; +}; + +/* VSB SNR lookup table */ +static struct mse2snr_tab vsb_mse2snr_tab[] = { + { 0, 270 }, + { 2, 250 }, + { 3, 240 }, + { 5, 230 }, + { 7, 220 }, + { 9, 210 }, + { 12, 200 }, + { 13, 195 }, + { 15, 190 }, + { 17, 185 }, + { 19, 180 }, + { 21, 175 }, + { 24, 170 }, + { 27, 165 }, + { 31, 160 }, + { 32, 158 }, + { 33, 156 }, + { 36, 152 }, + { 37, 150 }, + { 39, 148 }, + { 40, 146 }, + { 41, 144 }, + { 43, 142 }, + { 44, 140 }, + { 48, 135 }, + { 50, 130 }, + { 43, 142 }, + { 53, 125 }, + { 56, 120 }, + { 256, 115 }, +}; + +/* QAM64 SNR lookup table */ +static struct mse2snr_tab qam64_mse2snr_tab[] = { + { 15, 0 }, + { 16, 290 }, + { 17, 288 }, + { 18, 286 }, + { 19, 284 }, + { 20, 282 }, + { 21, 281 }, + { 22, 279 }, + { 23, 277 }, + { 24, 275 }, + { 25, 273 }, + { 26, 271 }, + { 27, 269 }, + { 28, 268 }, + { 29, 266 }, + { 30, 264 }, + { 31, 262 }, + { 32, 260 }, + { 33, 259 }, + { 34, 258 }, + { 35, 256 }, + { 36, 255 }, + { 37, 254 }, + { 38, 252 }, + { 39, 251 }, + { 40, 250 }, + { 41, 249 }, + { 42, 248 }, + { 43, 246 }, + { 44, 245 }, + { 45, 244 }, + { 46, 242 }, + { 47, 241 }, + { 48, 240 }, + { 50, 239 }, + { 51, 238 }, + { 53, 237 }, + { 54, 236 }, + { 56, 235 }, + { 57, 234 }, + { 59, 233 }, + { 60, 232 }, + { 62, 231 }, + { 63, 230 }, + { 65, 229 }, + { 67, 228 }, + { 68, 227 }, + { 70, 226 }, + { 71, 225 }, + { 73, 224 }, + { 74, 223 }, + { 76, 222 }, + { 78, 221 }, + { 80, 220 }, + { 82, 219 }, + { 85, 218 }, + { 88, 217 }, + { 90, 216 }, + { 92, 215 }, + { 93, 214 }, + { 94, 212 }, + { 95, 211 }, + { 97, 210 }, + { 99, 209 }, + { 101, 208 }, + { 102, 207 }, + { 104, 206 }, + { 107, 205 }, + { 111, 204 }, + { 114, 203 }, + { 118, 202 }, + { 122, 201 }, + { 125, 200 }, + { 128, 199 }, + { 130, 198 }, + { 132, 197 }, + { 256, 190 }, +}; + +/* QAM256 SNR lookup table */ +static struct mse2snr_tab qam256_mse2snr_tab[] = { + { 16, 0 }, + { 17, 400 }, + { 18, 398 }, + { 19, 396 }, + { 20, 394 }, + { 21, 392 }, + { 22, 390 }, + { 23, 388 }, + { 24, 386 }, + { 25, 384 }, + { 26, 382 }, + { 27, 380 }, + { 28, 379 }, + { 29, 378 }, + { 30, 377 }, + { 31, 376 }, + { 32, 375 }, + { 33, 374 }, + { 34, 373 }, + { 35, 372 }, + { 36, 371 }, + { 37, 370 }, + { 38, 362 }, + { 39, 354 }, + { 40, 346 }, + { 41, 338 }, + { 42, 330 }, + { 43, 328 }, + { 44, 326 }, + { 45, 324 }, + { 46, 322 }, + { 47, 320 }, + { 48, 319 }, + { 49, 318 }, + { 50, 317 }, + { 51, 316 }, + { 52, 315 }, + { 53, 314 }, + { 54, 313 }, + { 55, 312 }, + { 56, 311 }, + { 57, 310 }, + { 58, 308 }, + { 59, 306 }, + { 60, 304 }, + { 61, 302 }, + { 62, 300 }, + { 63, 298 }, + { 65, 295 }, + { 68, 294 }, + { 70, 293 }, + { 73, 292 }, + { 76, 291 }, + { 78, 290 }, + { 79, 289 }, + { 81, 288 }, + { 82, 287 }, + { 83, 286 }, + { 84, 285 }, + { 85, 284 }, + { 86, 283 }, + { 88, 282 }, + { 89, 281 }, + { 256, 280 }, +}; + +static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse, + u16 *snr) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __func__); + + for (i = 0; i < sz; i++) { + if (mse < tab[i].val) { + *snr = tab[i].data; + ret = 0; + break; + } + } + dprintk("%s() snr=%d\n", __func__, *snr); + return ret; +} + +static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq) +{ + struct au8522_state *state = fe->demodulator_priv; + u8 r0b5, r0b6, r0b7; + char *ifmhz; + + switch (if_freq) { + case AU8522_IF_3_25MHZ: + ifmhz = "3.25"; + r0b5 = 0x00; + r0b6 = 0x3d; + r0b7 = 0xa0; + break; + case AU8522_IF_4MHZ: + ifmhz = "4.00"; + r0b5 = 0x00; + r0b6 = 0x4b; + r0b7 = 0xd9; + break; + case AU8522_IF_6MHZ: + ifmhz = "6.00"; + r0b5 = 0xfb; + r0b6 = 0x8e; + r0b7 = 0x39; + break; + default: + dprintk("%s() IF Frequency not supported\n", __func__); + return -EINVAL; + } + dprintk("%s() %s MHz\n", __func__, ifmhz); + au8522_writereg(state, 0x80b5, r0b5); + au8522_writereg(state, 0x80b6, r0b6); + au8522_writereg(state, 0x80b7, r0b7); + + return 0; +} + +/* VSB Modulation table */ +static struct { + u16 reg; + u16 data; +} VSB_mod_tab[] = { + { 0x8090, 0x84 }, + { 0x4092, 0x11 }, + { 0x2005, 0x00 }, + { 0x8091, 0x80 }, + { 0x80a3, 0x0c }, + { 0x80a4, 0xe8 }, + { 0x8081, 0xc4 }, + { 0x80a5, 0x40 }, + { 0x80a7, 0x40 }, + { 0x80a6, 0x67 }, + { 0x8262, 0x20 }, + { 0x821c, 0x30 }, + { 0x80d8, 0x1a }, + { 0x8227, 0xa0 }, + { 0x8121, 0xff }, + { 0x80a8, 0xf0 }, + { 0x80a9, 0x05 }, + { 0x80aa, 0x77 }, + { 0x80ab, 0xf0 }, + { 0x80ac, 0x05 }, + { 0x80ad, 0x77 }, + { 0x80ae, 0x41 }, + { 0x80af, 0x66 }, + { 0x821b, 0xcc }, + { 0x821d, 0x80 }, + { 0x80a4, 0xe8 }, + { 0x8231, 0x13 }, +}; + +/* QAM64 Modulation table */ +static struct { + u16 reg; + u16 data; +} QAM64_mod_tab[] = { + { 0x00a3, 0x09 }, + { 0x00a4, 0x00 }, + { 0x0081, 0xc4 }, + { 0x00a5, 0x40 }, + { 0x00aa, 0x77 }, + { 0x00ad, 0x77 }, + { 0x00a6, 0x67 }, + { 0x0262, 0x20 }, + { 0x021c, 0x30 }, + { 0x00b8, 0x3e }, + { 0x00b9, 0xf0 }, + { 0x00ba, 0x01 }, + { 0x00bb, 0x18 }, + { 0x00bc, 0x50 }, + { 0x00bd, 0x00 }, + { 0x00be, 0xea }, + { 0x00bf, 0xef }, + { 0x00c0, 0xfc }, + { 0x00c1, 0xbd }, + { 0x00c2, 0x1f }, + { 0x00c3, 0xfc }, + { 0x00c4, 0xdd }, + { 0x00c5, 0xaf }, + { 0x00c6, 0x00 }, + { 0x00c7, 0x38 }, + { 0x00c8, 0x30 }, + { 0x00c9, 0x05 }, + { 0x00ca, 0x4a }, + { 0x00cb, 0xd0 }, + { 0x00cc, 0x01 }, + { 0x00cd, 0xd9 }, + { 0x00ce, 0x6f }, + { 0x00cf, 0xf9 }, + { 0x00d0, 0x70 }, + { 0x00d1, 0xdf }, + { 0x00d2, 0xf7 }, + { 0x00d3, 0xc2 }, + { 0x00d4, 0xdf }, + { 0x00d5, 0x02 }, + { 0x00d6, 0x9a }, + { 0x00d7, 0xd0 }, + { 0x0250, 0x0d }, + { 0x0251, 0xcd }, + { 0x0252, 0xe0 }, + { 0x0253, 0x05 }, + { 0x0254, 0xa7 }, + { 0x0255, 0xff }, + { 0x0256, 0xed }, + { 0x0257, 0x5b }, + { 0x0258, 0xae }, + { 0x0259, 0xe6 }, + { 0x025a, 0x3d }, + { 0x025b, 0x0f }, + { 0x025c, 0x0d }, + { 0x025d, 0xea }, + { 0x025e, 0xf2 }, + { 0x025f, 0x51 }, + { 0x0260, 0xf5 }, + { 0x0261, 0x06 }, + { 0x021a, 0x00 }, + { 0x0546, 0x40 }, + { 0x0210, 0xc7 }, + { 0x0211, 0xaa }, + { 0x0212, 0xab }, + { 0x0213, 0x02 }, + { 0x0502, 0x00 }, + { 0x0121, 0x04 }, + { 0x0122, 0x04 }, + { 0x052e, 0x10 }, + { 0x00a4, 0xca }, + { 0x00a7, 0x40 }, + { 0x0526, 0x01 }, +}; + +/* QAM256 Modulation table */ +static struct { + u16 reg; + u16 data; +} QAM256_mod_tab[] = { + { 0x80a3, 0x09 }, + { 0x80a4, 0x00 }, + { 0x8081, 0xc4 }, + { 0x80a5, 0x40 }, + { 0x80aa, 0x77 }, + { 0x80ad, 0x77 }, + { 0x80a6, 0x67 }, + { 0x8262, 0x20 }, + { 0x821c, 0x30 }, + { 0x80b8, 0x3e }, + { 0x80b9, 0xf0 }, + { 0x80ba, 0x01 }, + { 0x80bb, 0x18 }, + { 0x80bc, 0x50 }, + { 0x80bd, 0x00 }, + { 0x80be, 0xea }, + { 0x80bf, 0xef }, + { 0x80c0, 0xfc }, + { 0x80c1, 0xbd }, + { 0x80c2, 0x1f }, + { 0x80c3, 0xfc }, + { 0x80c4, 0xdd }, + { 0x80c5, 0xaf }, + { 0x80c6, 0x00 }, + { 0x80c7, 0x38 }, + { 0x80c8, 0x30 }, + { 0x80c9, 0x05 }, + { 0x80ca, 0x4a }, + { 0x80cb, 0xd0 }, + { 0x80cc, 0x01 }, + { 0x80cd, 0xd9 }, + { 0x80ce, 0x6f }, + { 0x80cf, 0xf9 }, + { 0x80d0, 0x70 }, + { 0x80d1, 0xdf }, + { 0x80d2, 0xf7 }, + { 0x80d3, 0xc2 }, + { 0x80d4, 0xdf }, + { 0x80d5, 0x02 }, + { 0x80d6, 0x9a }, + { 0x80d7, 0xd0 }, + { 0x8250, 0x0d }, + { 0x8251, 0xcd }, + { 0x8252, 0xe0 }, + { 0x8253, 0x05 }, + { 0x8254, 0xa7 }, + { 0x8255, 0xff }, + { 0x8256, 0xed }, + { 0x8257, 0x5b }, + { 0x8258, 0xae }, + { 0x8259, 0xe6 }, + { 0x825a, 0x3d }, + { 0x825b, 0x0f }, + { 0x825c, 0x0d }, + { 0x825d, 0xea }, + { 0x825e, 0xf2 }, + { 0x825f, 0x51 }, + { 0x8260, 0xf5 }, + { 0x8261, 0x06 }, + { 0x821a, 0x00 }, + { 0x8546, 0x40 }, + { 0x8210, 0x26 }, + { 0x8211, 0xf6 }, + { 0x8212, 0x84 }, + { 0x8213, 0x02 }, + { 0x8502, 0x01 }, + { 0x8121, 0x04 }, + { 0x8122, 0x04 }, + { 0x852e, 0x10 }, + { 0x80a4, 0xca }, + { 0x80a7, 0x40 }, + { 0x8526, 0x01 }, +}; + +static int au8522_enable_modulation(struct dvb_frontend *fe, + fe_modulation_t m) +{ + struct au8522_state *state = fe->demodulator_priv; + int i; + + dprintk("%s(0x%08x)\n", __func__, m); + + switch (m) { + case VSB_8: + dprintk("%s() VSB_8\n", __func__); + for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++) + au8522_writereg(state, + VSB_mod_tab[i].reg, + VSB_mod_tab[i].data); + au8522_set_if(fe, state->config->vsb_if); + break; + case QAM_64: + dprintk("%s() QAM 64\n", __func__); + for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++) + au8522_writereg(state, + QAM64_mod_tab[i].reg, + QAM64_mod_tab[i].data); + au8522_set_if(fe, state->config->qam_if); + break; + case QAM_256: + dprintk("%s() QAM 256\n", __func__); + for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++) + au8522_writereg(state, + QAM256_mod_tab[i].reg, + QAM256_mod_tab[i].data); + au8522_set_if(fe, state->config->qam_if); + break; + default: + dprintk("%s() Invalid modulation\n", __func__); + return -EINVAL; + } + + state->current_modulation = m; + + return 0; +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +static int au8522_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct au8522_state *state = fe->demodulator_priv; + int ret = -EINVAL; + + dprintk("%s(frequency=%d)\n", __func__, p->frequency); + + if ((state->current_frequency == p->frequency) && + (state->current_modulation == p->u.vsb.modulation)) + return 0; + + au8522_enable_modulation(fe, p->u.vsb.modulation); + + /* Allow the demod to settle */ + msleep(100); + + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + if (ret < 0) + return ret; + + state->current_frequency = p->frequency; + + return 0; +} + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +int au8522_init(struct dvb_frontend *fe) +{ + struct au8522_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + + state->operational_mode = AU8522_DIGITAL_MODE; + + /* Clear out any state associated with the digital side of the + chip, so that when it gets powered back up it won't think + that it is already tuned */ + state->current_frequency = 0; + + au8522_writereg(state, 0xa4, 1 << 5); + + au8522_i2c_gate_ctrl(fe, 1); + + return 0; +} + +static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + u8 val; + + /* bail out if we can't control an LED */ + if (!led_config || !led_config->gpio_output || + !led_config->gpio_output_enable || !led_config->gpio_output_disable) + return 0; + + val = au8522_readreg(state, 0x4000 | + (led_config->gpio_output & ~0xc000)); + if (onoff) { + /* enable GPIO output */ + val &= ~((led_config->gpio_output_enable >> 8) & 0xff); + val |= (led_config->gpio_output_enable & 0xff); + } else { + /* disable GPIO output */ + val &= ~((led_config->gpio_output_disable >> 8) & 0xff); + val |= (led_config->gpio_output_disable & 0xff); + } + return au8522_writereg(state, 0x8000 | + (led_config->gpio_output & ~0xc000), val); +} + +/* led = 0 | off + * led = 1 | signal ok + * led = 2 | signal strong + * led < 0 | only light led if leds are currently off + */ +static int au8522_led_ctrl(struct au8522_state *state, int led) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + int i, ret = 0; + + /* bail out if we can't control an LED */ + if (!led_config || !led_config->gpio_leds || + !led_config->num_led_states || !led_config->led_states) + return 0; + + if (led < 0) { + /* if LED is already lit, then leave it as-is */ + if (state->led_state) + return 0; + else + led *= -1; + } + + /* toggle LED if changing state */ + if (state->led_state != led) { + u8 val; + + dprintk("%s: %d\n", __func__, led); + + au8522_led_gpio_enable(state, 1); + + val = au8522_readreg(state, 0x4000 | + (led_config->gpio_leds & ~0xc000)); + + /* start with all leds off */ + for (i = 0; i < led_config->num_led_states; i++) + val &= ~led_config->led_states[i]; + + /* set selected LED state */ + if (led < led_config->num_led_states) + val |= led_config->led_states[led]; + else if (led_config->num_led_states) + val |= + led_config->led_states[led_config->num_led_states - 1]; + + ret = au8522_writereg(state, 0x8000 | + (led_config->gpio_leds & ~0xc000), val); + if (ret < 0) + return ret; + + state->led_state = led; + + if (led == 0) + au8522_led_gpio_enable(state, 0); + } + + return 0; +} + +int au8522_sleep(struct dvb_frontend *fe) +{ + struct au8522_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + + /* Only power down if the digital side is currently using the chip */ + if (state->operational_mode == AU8522_ANALOG_MODE) { + /* We're not in one of the expected power modes, which means + that the DVB thread is probably telling us to go to sleep + even though the analog frontend has already started using + the chip. So ignore the request */ + return 0; + } + + /* turn off led */ + au8522_led_ctrl(state, 0); + + /* Power down the chip */ + au8522_writereg(state, 0xa4, 1 << 5); + + state->current_frequency = 0; + + return 0; +} + +static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct au8522_state *state = fe->demodulator_priv; + u8 reg; + u32 tuner_status = 0; + + *status = 0; + + if (state->current_modulation == VSB_8) { + dprintk("%s() Checking VSB_8\n", __func__); + reg = au8522_readreg(state, 0x4088); + if ((reg & 0x03) == 0x03) + *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; + } else { + dprintk("%s() Checking QAM\n", __func__); + reg = au8522_readreg(state, 0x4541); + if (reg & 0x80) + *status |= FE_HAS_VITERBI; + if (reg & 0x20) + *status |= FE_HAS_LOCK | FE_HAS_SYNC; + } + + switch (state->config->status_mode) { + case AU8522_DEMODLOCKING: + dprintk("%s() DEMODLOCKING\n", __func__); + if (*status & FE_HAS_VITERBI) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + case AU8522_TUNERLOCKING: + /* Get the tuner status */ + dprintk("%s() TUNERLOCKING\n", __func__); + if (fe->ops.tuner_ops.get_status) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + fe->ops.tuner_ops.get_status(fe, &tuner_status); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + if (tuner_status) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + } + state->fe_status = *status; + + if (*status & FE_HAS_LOCK) + /* turn on LED, if it isn't on already */ + au8522_led_ctrl(state, -1); + else + /* turn off LED */ + au8522_led_ctrl(state, 0); + + dprintk("%s() status 0x%08x\n", __func__, *status); + + return 0; +} + +static int au8522_led_status(struct au8522_state *state, const u16 *snr) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + int led; + u16 strong; + + /* bail out if we can't control an LED */ + if (!led_config) + return 0; + + if (0 == (state->fe_status & FE_HAS_LOCK)) + return au8522_led_ctrl(state, 0); + else if (state->current_modulation == QAM_256) + strong = led_config->qam256_strong; + else if (state->current_modulation == QAM_64) + strong = led_config->qam64_strong; + else /* (state->current_modulation == VSB_8) */ + strong = led_config->vsb8_strong; + + if (*snr >= strong) + led = 2; + else + led = 1; + + if ((state->led_state) && + (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10)) + /* snr didn't change enough to bother + * changing the color of the led */ + return 0; + + return au8522_led_ctrl(state, led); +} + +static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct au8522_state *state = fe->demodulator_priv; + int ret = -EINVAL; + + dprintk("%s()\n", __func__); + + if (state->current_modulation == QAM_256) + ret = au8522_mse2snr_lookup(qam256_mse2snr_tab, + ARRAY_SIZE(qam256_mse2snr_tab), + au8522_readreg(state, 0x4522), + snr); + else if (state->current_modulation == QAM_64) + ret = au8522_mse2snr_lookup(qam64_mse2snr_tab, + ARRAY_SIZE(qam64_mse2snr_tab), + au8522_readreg(state, 0x4522), + snr); + else /* VSB_8 */ + ret = au8522_mse2snr_lookup(vsb_mse2snr_tab, + ARRAY_SIZE(vsb_mse2snr_tab), + au8522_readreg(state, 0x4311), + snr); + + if (state->config->led_cfg) + au8522_led_status(state, snr); + + return ret; +} + +static int au8522_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + return au8522_read_snr(fe, signal_strength); +} + +static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct au8522_state *state = fe->demodulator_priv; + + if (state->current_modulation == VSB_8) + *ucblocks = au8522_readreg(state, 0x4087); + else + *ucblocks = au8522_readreg(state, 0x4543); + + return 0; +} + +static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + return au8522_read_ucblocks(fe, ber); +} + +static int au8522_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct au8522_state *state = fe->demodulator_priv; + + p->frequency = state->current_frequency; + p->u.vsb.modulation = state->current_modulation; + + return 0; +} + +static int au8522_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static struct dvb_frontend_ops au8522_ops; + +int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, + u8 client_address) +{ + int ret; + + mutex_lock(&au8522_list_mutex); + ret = hybrid_tuner_request_state(struct au8522_state, (*state), + hybrid_tuner_instance_list, + i2c, client_address, "au8522"); + mutex_unlock(&au8522_list_mutex); + + return ret; +} + +void au8522_release_state(struct au8522_state *state) +{ + mutex_lock(&au8522_list_mutex); + if (state != NULL) + hybrid_tuner_release_state(state); + mutex_unlock(&au8522_list_mutex); +} + + +static void au8522_release(struct dvb_frontend *fe) +{ + struct au8522_state *state = fe->demodulator_priv; + au8522_release_state(state); +} + +struct dvb_frontend *au8522_attach(const struct au8522_config *config, + struct i2c_adapter *i2c) +{ + struct au8522_state *state = NULL; + int instance; + + /* allocate memory for the internal state */ + instance = au8522_get_state(&state, i2c, config->demod_address); + switch (instance) { + case 0: + dprintk("%s state allocation failed\n", __func__); + break; + case 1: + /* new demod instance */ + dprintk("%s using new instance\n", __func__); + break; + default: + /* existing demod instance */ + dprintk("%s using existing instance\n", __func__); + break; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->operational_mode = AU8522_DIGITAL_MODE; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &au8522_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + if (au8522_init(&state->frontend) != 0) { + printk(KERN_ERR "%s: Failed to initialize correctly\n", + __func__); + goto error; + } + + /* Note: Leaving the I2C gate open here. */ + au8522_i2c_gate_ctrl(&state->frontend, 1); + + return &state->frontend; + +error: + au8522_release_state(state); + return NULL; +} +EXPORT_SYMBOL(au8522_attach); + +static struct dvb_frontend_ops au8522_ops = { + + .info = { + .name = "Auvitek AU8522 QAM/8VSB Frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .init = au8522_init, + .sleep = au8522_sleep, + .i2c_gate_ctrl = au8522_i2c_gate_ctrl, + .set_frontend = au8522_set_frontend, + .get_frontend = au8522_get_frontend, + .get_tune_settings = au8522_get_tune_settings, + .read_status = au8522_read_status, + .read_ber = au8522_read_ber, + .read_signal_strength = au8522_read_signal_strength, + .read_snr = au8522_read_snr, + .read_ucblocks = au8522_read_ucblocks, + .release = au8522_release, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* + Auvitek AU8522 QAM/8VSB demodulator driver + + Copyright (C) 2008 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __AU8522_H__ +#define __AU8522_H__ + +#include + +enum au8522_if_freq { + AU8522_IF_6MHZ = 0, + AU8522_IF_4MHZ, + AU8522_IF_3_25MHZ, +}; + +struct au8522_led_config { + u16 vsb8_strong; + u16 qam64_strong; + u16 qam256_strong; + + u16 gpio_output; + /* unset hi bits, set low bits */ + u16 gpio_output_enable; + u16 gpio_output_disable; + + u16 gpio_leds; + u8 *led_states; + unsigned int num_led_states; +}; + +struct au8522_config { + /* the demodulator's i2c address */ + u8 demod_address; + + /* Return lock status based on tuner lock, or demod lock */ +#define AU8522_TUNERLOCKING 0 +#define AU8522_DEMODLOCKING 1 + u8 status_mode; + + struct au8522_led_config *led_cfg; + + enum au8522_if_freq vsb_if; + enum au8522_if_freq qam_if; +}; + +#if defined(CONFIG_DVB_AU8522) || \ + (defined(CONFIG_DVB_AU8522_MODULE) && defined(MODULE)) +extern struct dvb_frontend *au8522_attach(const struct au8522_config *config, + struct i2c_adapter *i2c); +#else +static inline +struct dvb_frontend *au8522_attach(const struct au8522_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_AU8522 */ + +/* Other modes may need to be added later */ +enum au8522_video_input { + AU8522_COMPOSITE_CH1 = 1, + AU8522_COMPOSITE_CH2, + AU8522_COMPOSITE_CH3, + AU8522_COMPOSITE_CH4, + AU8522_COMPOSITE_CH4_SIF, + AU8522_SVIDEO_CH13, + AU8522_SVIDEO_CH24, +}; + +enum au8522_audio_input { + AU8522_AUDIO_NONE, + AU8522_AUDIO_SIF, +}; + +#endif /* __AU8522_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/au8522_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,421 @@ +/* + Auvitek AU8522 QAM/8VSB demodulator driver + + Copyright (C) 2008 Steven Toth + Copyright (C) 2008 Devin Heitmueller + Copyright (C) 2005-2008 Auvitek International, Ltd. + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "au8522.h" +#include "tuner-i2c.h" + +#define AU8522_ANALOG_MODE 0 +#define AU8522_DIGITAL_MODE 1 + +struct au8522_state { + struct i2c_client *c; + struct i2c_adapter *i2c; + + u8 operational_mode; + + /* Used for sharing of the state between analog and digital mode */ + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; + + /* configuration settings */ + const struct au8522_config *config; + + struct dvb_frontend frontend; + + u32 current_frequency; + fe_modulation_t current_modulation; + + u32 fe_status; + unsigned int led_state; + + /* Analog settings */ + struct v4l2_subdev sd; + v4l2_std_id std; + int vid_input; + int aud_input; + u32 id; + u32 rev; + u8 brightness; + u8 contrast; + u8 saturation; + s16 hue; +}; + +/* These are routines shared by both the VSB/QAM demodulator and the analog + decoder */ +int au8522_writereg(struct au8522_state *state, u16 reg, u8 data); +u8 au8522_readreg(struct au8522_state *state, u16 reg); +int au8522_init(struct dvb_frontend *fe); +int au8522_sleep(struct dvb_frontend *fe); + +int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, + u8 client_address); +void au8522_release_state(struct au8522_state *state); + +/* REGISTERS */ +#define AU8522_INPUT_CONTROL_REG081H 0x081 +#define AU8522_PGA_CONTROL_REG082H 0x082 +#define AU8522_CLAMPING_CONTROL_REG083H 0x083 + +#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H 0x0A3 +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H 0x0A4 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H 0x0A5 +#define AU8522_AGC_CONTROL_RANGE_REG0A6H 0x0A6 +#define AU8522_SYSTEM_GAIN_CONTROL_REG0A7H 0x0A7 +#define AU8522_TUNER_AGC_RF_STOP_REG0A8H 0x0A8 +#define AU8522_TUNER_AGC_RF_START_REG0A9H 0x0A9 +#define AU8522_TUNER_RF_AGC_DEFAULT_REG0AAH 0x0AA +#define AU8522_TUNER_AGC_IF_STOP_REG0ABH 0x0AB +#define AU8522_TUNER_AGC_IF_START_REG0ACH 0x0AC +#define AU8522_TUNER_AGC_IF_DEFAULT_REG0ADH 0x0AD +#define AU8522_TUNER_AGC_STEP_REG0AEH 0x0AE +#define AU8522_TUNER_GAIN_STEP_REG0AFH 0x0AF + +/* Receiver registers */ +#define AU8522_FRMREGTHRD1_REG0B0H 0x0B0 +#define AU8522_FRMREGAGC1H_REG0B1H 0x0B1 +#define AU8522_FRMREGSHIFT1_REG0B2H 0x0B2 +#define AU8522_TOREGAGC1_REG0B3H 0x0B3 +#define AU8522_TOREGASHIFT1_REG0B4H 0x0B4 +#define AU8522_FRMREGBBH_REG0B5H 0x0B5 +#define AU8522_FRMREGBBM_REG0B6H 0x0B6 +#define AU8522_FRMREGBBL_REG0B7H 0x0B7 +/* 0xB8 TO 0xD7 are the filter coefficients */ +#define AU8522_FRMREGTHRD2_REG0D8H 0x0D8 +#define AU8522_FRMREGAGC2H_REG0D9H 0x0D9 +#define AU8522_TOREGAGC2_REG0DAH 0x0DA +#define AU8522_TOREGSHIFT2_REG0DBH 0x0DB +#define AU8522_FRMREGPILOTH_REG0DCH 0x0DC +#define AU8522_FRMREGPILOTM_REG0DDH 0x0DD +#define AU8522_FRMREGPILOTL_REG0DEH 0x0DE +#define AU8522_TOREGFREQ_REG0DFH 0x0DF + +#define AU8522_RX_PGA_RFOUT_REG0EBH 0x0EB +#define AU8522_RX_PGA_IFOUT_REG0ECH 0x0EC +#define AU8522_RX_PGA_PGAOUT_REG0EDH 0x0ED + +#define AU8522_CHIP_MODE_REG0FEH 0x0FE + +/* I2C bus control registers */ +#define AU8522_I2C_CONTROL_REG0_REG090H 0x090 +#define AU8522_I2C_CONTROL_REG1_REG091H 0x091 +#define AU8522_I2C_STATUS_REG092H 0x092 +#define AU8522_I2C_WR_DATA0_REG093H 0x093 +#define AU8522_I2C_WR_DATA1_REG094H 0x094 +#define AU8522_I2C_WR_DATA2_REG095H 0x095 +#define AU8522_I2C_WR_DATA3_REG096H 0x096 +#define AU8522_I2C_WR_DATA4_REG097H 0x097 +#define AU8522_I2C_WR_DATA5_REG098H 0x098 +#define AU8522_I2C_WR_DATA6_REG099H 0x099 +#define AU8522_I2C_WR_DATA7_REG09AH 0x09A +#define AU8522_I2C_RD_DATA0_REG09BH 0x09B +#define AU8522_I2C_RD_DATA1_REG09CH 0x09C +#define AU8522_I2C_RD_DATA2_REG09DH 0x09D +#define AU8522_I2C_RD_DATA3_REG09EH 0x09E +#define AU8522_I2C_RD_DATA4_REG09FH 0x09F +#define AU8522_I2C_RD_DATA5_REG0A0H 0x0A0 +#define AU8522_I2C_RD_DATA6_REG0A1H 0x0A1 +#define AU8522_I2C_RD_DATA7_REG0A2H 0x0A2 + +#define AU8522_ENA_USB_REG101H 0x101 + +#define AU8522_I2S_CTRL_0_REG110H 0x110 +#define AU8522_I2S_CTRL_1_REG111H 0x111 +#define AU8522_I2S_CTRL_2_REG112H 0x112 + +#define AU8522_FRMREGFFECONTROL_REG121H 0x121 +#define AU8522_FRMREGDFECONTROL_REG122H 0x122 + +#define AU8522_CARRFREQOFFSET0_REG201H 0x201 +#define AU8522_CARRFREQOFFSET1_REG202H 0x202 + +#define AU8522_DECIMATION_GAIN_REG21AH 0x21A +#define AU8522_FRMREGIFSLP_REG21BH 0x21B +#define AU8522_FRMREGTHRDL2_REG21CH 0x21C +#define AU8522_FRMREGSTEP3DB_REG21DH 0x21D +#define AU8522_DAGC_GAIN_ADJUSTMENT_REG21EH 0x21E +#define AU8522_FRMREGPLLMODE_REG21FH 0x21F +#define AU8522_FRMREGCSTHRD_REG220H 0x220 +#define AU8522_FRMREGCRLOCKDMAX_REG221H 0x221 +#define AU8522_FRMREGCRPERIODMASK_REG222H 0x222 +#define AU8522_FRMREGCRLOCK0THH_REG223H 0x223 +#define AU8522_FRMREGCRLOCK1THH_REG224H 0x224 +#define AU8522_FRMREGCRLOCK0THL_REG225H 0x225 +#define AU8522_FRMREGCRLOCK1THL_REG226H 0x226 +#define AU_FRMREGPLLACQPHASESCL_REG227H 0x227 +#define AU8522_FRMREGFREQFBCTRL_REG228H 0x228 + +/* Analog TV Decoder */ +#define AU8522_TVDEC_STATUS_REG000H 0x000 +#define AU8522_TVDEC_INT_STATUS_REG001H 0x001 +#define AU8522_TVDEC_MACROVISION_STATUS_REG002H 0x002 +#define AU8522_TVDEC_SHARPNESSREG009H 0x009 +#define AU8522_TVDEC_BRIGHTNESS_REG00AH 0x00A +#define AU8522_TVDEC_CONTRAST_REG00BH 0x00B +#define AU8522_TVDEC_SATURATION_CB_REG00CH 0x00C +#define AU8522_TVDEC_SATURATION_CR_REG00DH 0x00D +#define AU8522_TVDEC_HUE_H_REG00EH 0x00E +#define AU8522_TVDEC_HUE_L_REG00FH 0x00F +#define AU8522_TVDEC_INT_MASK_REG010H 0x010 +#define AU8522_VIDEO_MODE_REG011H 0x011 +#define AU8522_TVDEC_PGA_REG012H 0x012 +#define AU8522_TVDEC_COMB_MODE_REG015H 0x015 +#define AU8522_REG016H 0x016 +#define AU8522_TVDED_DBG_MODE_REG060H 0x060 +#define AU8522_TVDEC_FORMAT_CTRL1_REG061H 0x061 +#define AU8522_TVDEC_FORMAT_CTRL2_REG062H 0x062 +#define AU8522_TVDEC_VCR_DET_LLIM_REG063H 0x063 +#define AU8522_TVDEC_VCR_DET_HLIM_REG064H 0x064 +#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H 0x065 +#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H 0x066 +#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H 0x067 +#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H 0x068 +#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H 0x069 +#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH 0x06A +#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH 0x06B +#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH 0x06C +#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH 0x06D +#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH 0x06E +#define AU8522_TVDEC_UV_SEP_THR_REG06FH 0x06F +#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H 0x070 +#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H 0x073 +#define AU8522_TVDEC_DCAGC_CTRL_REG077H 0x077 +#define AU8522_TVDEC_PIC_START_ADJ_REG078H 0x078 +#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H 0x079 +#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH 0x07A +#define AU8522_TVDEC_INTRP_CTRL_REG07BH 0x07B +#define AU8522_TVDEC_PLL_STATUS_REG07EH 0x07E +#define AU8522_TVDEC_FSC_FREQ_REG07FH 0x07F + +#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H 0x0E4 +#define AU8522_TOREGAAGC_REG0E5H 0x0E5 + +#define AU8522_TVDEC_CHROMA_AGC_REG401H 0x401 +#define AU8522_TVDEC_CHROMA_SFT_REG402H 0x402 +#define AU8522_FILTER_COEF_R410 0x410 +#define AU8522_FILTER_COEF_R411 0x411 +#define AU8522_FILTER_COEF_R412 0x412 +#define AU8522_FILTER_COEF_R413 0x413 +#define AU8522_FILTER_COEF_R414 0x414 +#define AU8522_FILTER_COEF_R415 0x415 +#define AU8522_FILTER_COEF_R416 0x416 +#define AU8522_FILTER_COEF_R417 0x417 +#define AU8522_FILTER_COEF_R418 0x418 +#define AU8522_FILTER_COEF_R419 0x419 +#define AU8522_FILTER_COEF_R41A 0x41A +#define AU8522_FILTER_COEF_R41B 0x41B +#define AU8522_FILTER_COEF_R41C 0x41C +#define AU8522_FILTER_COEF_R41D 0x41D +#define AU8522_FILTER_COEF_R41E 0x41E +#define AU8522_FILTER_COEF_R41F 0x41F +#define AU8522_FILTER_COEF_R420 0x420 +#define AU8522_FILTER_COEF_R421 0x421 +#define AU8522_FILTER_COEF_R422 0x422 +#define AU8522_FILTER_COEF_R423 0x423 +#define AU8522_FILTER_COEF_R424 0x424 +#define AU8522_FILTER_COEF_R425 0x425 +#define AU8522_FILTER_COEF_R426 0x426 +#define AU8522_FILTER_COEF_R427 0x427 +#define AU8522_FILTER_COEF_R428 0x428 +#define AU8522_FILTER_COEF_R429 0x429 +#define AU8522_FILTER_COEF_R42A 0x42A +#define AU8522_FILTER_COEF_R42B 0x42B +#define AU8522_FILTER_COEF_R42C 0x42C +#define AU8522_FILTER_COEF_R42D 0x42D + +/* VBI Control Registers */ +#define AU8522_TVDEC_VBI_RX_FIFO_CONTAIN_REG004H 0x004 +#define AU8522_TVDEC_VBI_TX_FIFO_CONTAIN_REG005H 0x005 +#define AU8522_TVDEC_VBI_RX_FIFO_READ_REG006H 0x006 +#define AU8522_TVDEC_VBI_FIFO_STATUS_REG007H 0x007 +#define AU8522_TVDEC_VBI_CTRL_H_REG017H 0x017 +#define AU8522_TVDEC_VBI_CTRL_L_REG018H 0x018 +#define AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H 0x019 +#define AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH 0x01A +#define AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH 0x01B +#define AU8522_TVDEC_VBI_USER_THRESH1_REG01CH 0x01C +#define AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH 0x01E +#define AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH 0x01F +#define AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H 0x020 +#define AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H 0x021 +#define AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H 0x022 +#define AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H 0x023 + +#define AU8522_REG071H 0x071 +#define AU8522_REG072H 0x072 +#define AU8522_REG074H 0x074 +#define AU8522_REG075H 0x075 + +/* Digital Demodulator Registers */ +#define AU8522_FRAME_COUNT0_REG084H 0x084 +#define AU8522_RS_STATUS_G0_REG085H 0x085 +#define AU8522_RS_STATUS_B0_REG086H 0x086 +#define AU8522_RS_STATUS_E_REG087H 0x087 +#define AU8522_DEMODULATION_STATUS_REG088H 0x088 +#define AU8522_TOREGTRESTATUS_REG0E6H 0x0E6 +#define AU8522_TSPORT_CONTROL_REG10BH 0x10B +#define AU8522_TSTHES_REG10CH 0x10C +#define AU8522_FRMREGDFEKEEP_REG301H 0x301 +#define AU8522_DFE_AVERAGE_REG302H 0x302 +#define AU8522_FRMREGEQLERRWIN_REG303H 0x303 +#define AU8522_FRMREGFFEKEEP_REG304H 0x304 +#define AU8522_FRMREGDFECONTROL1_REG305H 0x305 +#define AU8522_FRMREGEQLERRLOW_REG306H 0x306 + +#define AU8522_REG42EH 0x42E +#define AU8522_REG42FH 0x42F +#define AU8522_REG430H 0x430 +#define AU8522_REG431H 0x431 +#define AU8522_REG432H 0x432 +#define AU8522_REG433H 0x433 +#define AU8522_REG434H 0x434 +#define AU8522_REG435H 0x435 +#define AU8522_REG436H 0x436 + +/* GPIO Registers */ +#define AU8522_GPIO_CONTROL_REG0E0H 0x0E0 +#define AU8522_GPIO_STATUS_REG0E1H 0x0E1 +#define AU8522_GPIO_DATA_REG0E2H 0x0E2 + +/* Audio Control Registers */ +#define AU8522_AUDIOAGC_REG0EEH 0x0EE +#define AU8522_AUDIO_STATUS_REG0F0H 0x0F0 +#define AU8522_AUDIO_MODE_REG0F1H 0x0F1 +#define AU8522_AUDIO_VOLUME_L_REG0F2H 0x0F2 +#define AU8522_AUDIO_VOLUME_R_REG0F3H 0x0F3 +#define AU8522_AUDIO_VOLUME_REG0F4H 0x0F4 +#define AU8522_FRMREGAUPHASE_REG0F7H 0x0F7 +#define AU8522_REG0F9H 0x0F9 + +#define AU8522_AUDIOAGC2_REG605H 0x605 +#define AU8522_AUDIOFREQ_REG606H 0x606 + + +/**************************************************************/ + +#define AU8522_INPUT_CONTROL_REG081H_ATSC 0xC4 +#define AU8522_INPUT_CONTROL_REG081H_ATVRF 0xC4 +#define AU8522_INPUT_CONTROL_REG081H_ATVRF13 0xC4 +#define AU8522_INPUT_CONTROL_REG081H_J83B64 0xC4 +#define AU8522_INPUT_CONTROL_REG081H_J83B256 0xC4 +#define AU8522_INPUT_CONTROL_REG081H_CVBS 0x20 +#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH1 0xA2 +#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH2 0xA0 +#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH3 0x69 +#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4 0x68 +#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF 0x28 +/* CH1 AS Y,CH3 AS C */ +#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 0x23 +/* CH2 AS Y,CH4 AS C */ +#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24 0x20 +#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATSC 0x0C +#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B64 0x09 +#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B256 0x09 +#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS 0x12 +#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF 0x1A +#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF13 0x1A +#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO 0x02 + +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CLEAR 0x00 +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO 0x9C +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS 0x9D +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATSC 0xE8 +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B256 0xCA +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B64 0xCA +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF 0xDD +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF13 0xDD +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_PAL 0xDD +#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_FM 0xDD + +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATSC 0x80 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B256 0x80 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B64 0x80 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_ATSC 0x40 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B256 0x40 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B64 0x40 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_CLEAR 0x00 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF 0x01 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF13 0x01 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_SVIDEO 0x04 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_CVBS 0x01 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PWM 0x03 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_IIS 0x09 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PAL 0x01 +#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_FM 0x01 + +/* STILL NEED TO BE REFACTORED @@@@@@@@@@@@@@ */ +#define AU8522_TVDEC_CONTRAST_REG00BH_CVBS 0x79 +#define AU8522_TVDEC_SATURATION_CB_REG00CH_CVBS 0x80 +#define AU8522_TVDEC_SATURATION_CR_REG00DH_CVBS 0x80 +#define AU8522_TVDEC_HUE_H_REG00EH_CVBS 0x00 +#define AU8522_TVDEC_HUE_L_REG00FH_CVBS 0x00 +#define AU8522_TVDEC_PGA_REG012H_CVBS 0x0F +#define AU8522_TVDEC_COMB_MODE_REG015H_CVBS 0x00 +#define AU8522_REG016H_CVBS 0x00 +#define AU8522_TVDED_DBG_MODE_REG060H_CVBS 0x00 +#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS 0x0B +#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13 0x03 +#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13 0x00 +#define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS 0x19 +#define AU8522_REG0F9H_AUDIO 0x20 +#define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS 0xA7 +#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS 0x0A +#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS 0x32 +#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS 0x19 +#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS 0x23 +#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS 0x41 +#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS 0x0A +#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS 0x32 +#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS 0x34 +#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO 0x2a +#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS 0x05 +#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO 0x15 +#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS 0x6E +#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS 0x0F +#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS 0x80 +#define AU8522_REG071H_CVBS 0x18 +#define AU8522_REG072H_CVBS 0x30 +#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS 0xF0 +#define AU8522_REG074H_CVBS 0x80 +#define AU8522_REG075H_CVBS 0xF0 +#define AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS 0xFB +#define AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS 0x04 +#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS 0x00 +#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS 0x00 +#define AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS 0xEE +#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS 0xFE +#define AU8522_TOREGAAGC_REG0E5H_CVBS 0x00 +#define AU8522_TVDEC_VBI6A_REG035H_CVBS 0x40 + +/* Enables Closed captioning */ +#define AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON 0x21 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,854 @@ +/* + * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) + * + * Copyright (C) 2001-5, B2C2 inc. + * + * GPL/Linux driver written by Patrick Boettcher + * + * This driver is "hard-coded" to be used with the 1st generation of + * Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming + * (Panasonic CT10S) is located here, which is actually wrong. Unless there is + * another device with a BCM3510, this is no problem. + * + * The driver works also with QAM64 DVB-C, but had an unreasonable high + * UNC. (Tested with the Air2PC ATSC 1st generation) + * + * You'll need a firmware for this driver in order to get it running. It is + * called "dvb-fe-bcm3510-01.fw". + * + * 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, or (at your option) + * any later version. + * + * 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., 675 Mass + * Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "bcm3510.h" +#include "bcm3510_priv.h" + +struct bcm3510_state { + + struct i2c_adapter* i2c; + const struct bcm3510_config* config; + struct dvb_frontend frontend; + + /* demodulator private data */ + struct mutex hab_mutex; + u8 firmware_loaded:1; + + unsigned long next_status_check; + unsigned long status_check_interval; + struct bcm3510_hab_cmd_status1 status1; + struct bcm3510_hab_cmd_status2 status2; +}; + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able))."); + +#define dprintk(level,x...) if (level & debug) printk(x) +#define dbufout(b,l,m) {\ + int i; \ + for (i = 0; i < l; i++) \ + m("%02x ",b[i]); \ +} +#define deb_info(args...) dprintk(0x01,args) +#define deb_i2c(args...) dprintk(0x02,args) +#define deb_hab(args...) dprintk(0x04,args) + +/* transfer functions */ +static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len) +{ + u8 b[256]; + int err; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 }; + + b[0] = reg; + memcpy(&b[1],buf,len); + + deb_i2c("i2c wr %02x: ",reg); + dbufout(buf,len,deb_i2c); + deb_i2c("\n"); + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + + deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n", + __func__, state->config->demod_address, reg, err); + return -EREMOTEIO; + } + + return 0; +} + +static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len) +{ + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } + }; + int err; + + memset(buf,0,len); + + if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { + deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n", + __func__, state->config->demod_address, reg, err); + return -EREMOTEIO; + } + deb_i2c("i2c rd %02x: ",reg); + dbufout(buf,len,deb_i2c); + deb_i2c("\n"); + + return 0; +} + +static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v) +{ + return bcm3510_writebytes(state,reg,&v.raw,1); +} + +static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v) +{ + return bcm3510_readbytes(state,reg,&v->raw,1); +} + +/* Host Access Buffer transfers */ +static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len) +{ + bcm3510_register_value v; + int ret,i; + + v.HABADR_a6.HABADR = 0; + if ((ret = bcm3510_writeB(st,0xa6,v)) < 0) + return ret; + + for (i = 0; i < len; i++) { + if ((ret = bcm3510_readB(st,0xa7,&v)) < 0) + return ret; + buf[i] = v.HABDATA_a7; + } + return 0; +} + +static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len) +{ + bcm3510_register_value v,hab; + int ret,i; + unsigned long t; + +/* Check if any previous HAB request still needs to be serviced by the + * Acquisition Processor before sending new request */ + if ((ret = bcm3510_readB(st,0xa8,&v)) < 0) + return ret; + if (v.HABSTAT_a8.HABR) { + deb_info("HAB is running already - clearing it.\n"); + v.HABSTAT_a8.HABR = 0; + bcm3510_writeB(st,0xa8,v); +// return -EBUSY; + } + +/* Send the start HAB Address (automatically incremented after write of + * HABDATA) and write the HAB Data */ + hab.HABADR_a6.HABADR = 0; + if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0) + return ret; + + for (i = 0; i < len; i++) { + hab.HABDATA_a7 = buf[i]; + if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0) + return ret; + } + +/* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to + * be written) */ + v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1; + if ((ret = bcm3510_writeB(st,0xa8,v)) < 0) + return ret; + +/* Polling method: Wait until the AP finishes processing the HAB request */ + t = jiffies + 1*HZ; + while (time_before(jiffies, t)) { + deb_info("waiting for HAB to complete\n"); + msleep(10); + if ((ret = bcm3510_readB(st,0xa8,&v)) < 0) + return ret; + + if (!v.HABSTAT_a8.HABR) + return 0; + } + + deb_info("send_request execution timed out.\n"); + return -ETIMEDOUT; +} + +static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen) +{ + u8 ob[olen+2],ib[ilen+2]; + int ret = 0; + + ob[0] = cmd; + ob[1] = msgid; + memcpy(&ob[2],obuf,olen); + + deb_hab("hab snd: "); + dbufout(ob,olen+2,deb_hab); + deb_hab("\n"); + + if (mutex_lock_interruptible(&st->hab_mutex) < 0) + return -EAGAIN; + + if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 || + (ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0) + goto error; + + deb_hab("hab get: "); + dbufout(ib,ilen+2,deb_hab); + deb_hab("\n"); + + memcpy(ibuf,&ib[2],ilen); +error: + mutex_unlock(&st->hab_mutex); + return ret; +} + +#if 0 +/* not needed, we use a semaphore to prevent HAB races */ +static int bcm3510_is_ap_ready(struct bcm3510_state *st) +{ + bcm3510_register_value ap,hab; + int ret; + + if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 || + (ret = bcm3510_readB(st,0xa2,&ap) < 0)) + return ret; + + if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) { + deb_info("AP is busy\n"); + return -EBUSY; + } + + return 0; +} +#endif + +static int bcm3510_bert_reset(struct bcm3510_state *st) +{ + bcm3510_register_value b; + int ret; + + if ((ret = bcm3510_readB(st,0xfa,&b)) < 0) + return ret; + + b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); + b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b); + b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); + b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b); + + /* clear residual bit counter TODO */ + return 0; +} + +static int bcm3510_refresh_state(struct bcm3510_state *st) +{ + if (time_after(jiffies,st->next_status_check)) { + bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1)); + bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2)); + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + +static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_refresh_state(st); + + *status = 0; + if (st->status1.STATUS1.RECEIVER_LOCK) + *status |= FE_HAS_LOCK | FE_HAS_SYNC; + + if (st->status1.STATUS1.FEC_LOCK) + *status |= FE_HAS_VITERBI; + + if (st->status1.STATUS1.OUT_PLL_LOCK) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1500; + else /* more frequently checks if no lock has been achieved yet */ + st->status_check_interval = 500; + + deb_info("real_status: %02x\n",*status); + return 0; +} + +static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_refresh_state(st); + + *ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2; + return 0; +} + +static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_refresh_state(st); + *unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1; + return 0; +} + +static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct bcm3510_state* st = fe->demodulator_priv; + s32 t; + + bcm3510_refresh_state(st); + t = st->status2.SIGNAL; + + if (t > 190) + t = 190; + if (t < 90) + t = 90; + + t -= 90; + t = t * 0xff / 100; + /* normalize if necessary */ + *strength = (t << 8) | t; + return 0; +} + +static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_refresh_state(st); + + *snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8); + return 0; +} + +/* tuner frontend programming */ +static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a) +{ + struct bcm3510_hab_cmd_tune c; + memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune)); + +/* I2C Mode disabled, set 16 control / Data pairs */ + c.length = 0x10; + c.clock_width = 0; +/* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to + * logic high (as Configuration) */ + c.misc = 0x10; +/* Set duration of the initial state of TUNCTL = 3.34 micro Sec */ + c.TUNCTL_state = 0x40; + +/* PRESCALER DIVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */ + c.ctl_dat[0].ctrl.size = BITS_8; + c.ctl_dat[0].data = 0x80 | bc; + +/* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */ + c.ctl_dat[1].ctrl.size = BITS_8; + c.ctl_dat[1].data = 4; + +/* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */ + c.ctl_dat[2].ctrl.size = BITS_3; + c.ctl_dat[2].data = 0x20; + +/* control CS0 pin, pulse byte ? */ + c.ctl_dat[3].ctrl.size = BITS_3; + c.ctl_dat[3].ctrl.clk_off = 1; + c.ctl_dat[3].ctrl.cs0 = 1; + c.ctl_dat[3].data = 0x40; + +/* PGM_S18 to PGM_S11 */ + c.ctl_dat[4].ctrl.size = BITS_8; + c.ctl_dat[4].data = n >> 3; + +/* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */ + c.ctl_dat[5].ctrl.size = BITS_8; + c.ctl_dat[5].data = ((n & 0x7) << 5) | (a >> 2); + +/* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */ + c.ctl_dat[6].ctrl.size = BITS_3; + c.ctl_dat[6].data = (a << 6) & 0xdf; + +/* control CS0 pin, pulse byte ? */ + c.ctl_dat[7].ctrl.size = BITS_3; + c.ctl_dat[7].ctrl.clk_off = 1; + c.ctl_dat[7].ctrl.cs0 = 1; + c.ctl_dat[7].data = 0x40; + +/* PRESCALER DIVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */ + c.ctl_dat[8].ctrl.size = BITS_8; + c.ctl_dat[8].data = 0x80; + +/* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */ + c.ctl_dat[9].ctrl.size = BITS_8; + c.ctl_dat[9].data = 0x10; + +/* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */ + c.ctl_dat[10].ctrl.size = BITS_3; + c.ctl_dat[10].data = 0x20; + +/* pulse byte */ + c.ctl_dat[11].ctrl.size = BITS_3; + c.ctl_dat[11].ctrl.clk_off = 1; + c.ctl_dat[11].ctrl.cs1 = 1; + c.ctl_dat[11].data = 0x40; + +/* PGM_S18 to PGM_S11 */ + c.ctl_dat[12].ctrl.size = BITS_8; + c.ctl_dat[12].data = 0x2a; + +/* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */ + c.ctl_dat[13].ctrl.size = BITS_8; + c.ctl_dat[13].data = 0x8e; + +/* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */ + c.ctl_dat[14].ctrl.size = BITS_3; + c.ctl_dat[14].data = 0; + +/* Pulse Byte */ + c.ctl_dat[15].ctrl.size = BITS_3; + c.ctl_dat[15].ctrl.clk_off = 1; + c.ctl_dat[15].ctrl.cs1 = 1; + c.ctl_dat[15].data = 0x40; + + return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0); +} + +static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq) +{ + u8 bc,a; + u16 n; + s32 YIntercept,Tfvco1; + + freq /= 1000; + + deb_info("%dkHz:",freq); + /* set Band Switch */ + if (freq <= 168000) + bc = 0x1c; + else if (freq <= 378000) + bc = 0x2c; + else + bc = 0x30; + + if (freq >= 470000) { + freq -= 470001; + YIntercept = 18805; + } else if (freq >= 90000) { + freq -= 90001; + YIntercept = 15005; + } else if (freq >= 76000){ + freq -= 76001; + YIntercept = 14865; + } else { + freq -= 54001; + YIntercept = 14645; + } + + Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10; + + n = Tfvco1 >> 6; + a = Tfvco1 & 0x3f; + + deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a); + if (n >= 16 && n <= 2047) + return bcm3510_tuner_cmd(st,bc,n,a); + + return -EINVAL; +} + +static int bcm3510_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct bcm3510_state* st = fe->demodulator_priv; + struct bcm3510_hab_cmd_ext_acquire cmd; + struct bcm3510_hab_cmd_bert_control bert; + int ret; + + memset(&cmd,0,sizeof(cmd)); + switch (p->u.vsb.modulation) { + case QAM_256: + cmd.ACQUIRE0.MODE = 0x1; + cmd.ACQUIRE1.SYM_RATE = 0x1; + cmd.ACQUIRE1.IF_FREQ = 0x1; + break; + case QAM_64: + cmd.ACQUIRE0.MODE = 0x2; + cmd.ACQUIRE1.SYM_RATE = 0x2; + cmd.ACQUIRE1.IF_FREQ = 0x1; + break; +/* case QAM_256: + cmd.ACQUIRE0.MODE = 0x3; + break; + case QAM_128: + cmd.ACQUIRE0.MODE = 0x4; + break; + case QAM_64: + cmd.ACQUIRE0.MODE = 0x5; + break; + case QAM_32: + cmd.ACQUIRE0.MODE = 0x6; + break; + case QAM_16: + cmd.ACQUIRE0.MODE = 0x7; + break;*/ + case VSB_8: + cmd.ACQUIRE0.MODE = 0x8; + cmd.ACQUIRE1.SYM_RATE = 0x0; + cmd.ACQUIRE1.IF_FREQ = 0x0; + break; + case VSB_16: + cmd.ACQUIRE0.MODE = 0x9; + cmd.ACQUIRE1.SYM_RATE = 0x0; + cmd.ACQUIRE1.IF_FREQ = 0x0; + default: + return -EINVAL; + }; + cmd.ACQUIRE0.OFFSET = 0; + cmd.ACQUIRE0.NTSCSWEEP = 1; + cmd.ACQUIRE0.FA = 1; + cmd.ACQUIRE0.BW = 0; + +/* if (enableOffset) { + cmd.IF_OFFSET0 = xx; + cmd.IF_OFFSET1 = xx; + + cmd.SYM_OFFSET0 = xx; + cmd.SYM_OFFSET1 = xx; + if (enableNtscSweep) { + cmd.NTSC_OFFSET0; + cmd.NTSC_OFFSET1; + } + } */ + bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0); + +/* doing it with different MSGIDs, data book and source differs */ + bert.BE = 0; + bert.unused = 0; + bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0); + bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0); + + bcm3510_bert_reset(st); + + if ((ret = bcm3510_set_freq(st,p->frequency)) < 0) + return ret; + + memset(&st->status1,0,sizeof(st->status1)); + memset(&st->status2,0,sizeof(st->status2)); + st->status_check_interval = 500; + +/* Give the AP some time */ + msleep(200); + + return 0; +} + +static int bcm3510_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s) +{ + s->min_delay_ms = 1000; + s->step_size = 0; + s->max_drift = 0; + return 0; +} + +static void bcm3510_release(struct dvb_frontend* fe) +{ + struct bcm3510_state* state = fe->demodulator_priv; + kfree(state); +} + +/* firmware download: + * firmware file is build up like this: + * 16bit addr, 16bit length, 8byte of length + */ +#define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw" + +static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, const u8 *b, + u16 len) +{ + int ret = 0,i; + bcm3510_register_value vH, vL,vD; + + vH.MADRH_a9 = addr >> 8; + vL.MADRL_aa = addr; + if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret; + if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret; + + for (i = 0; i < len; i++) { + vD.MDATA_ab = b[i]; + if ((ret = bcm3510_writeB(st,0xab,vD)) < 0) + return ret; + } + + return 0; +} + +static int bcm3510_download_firmware(struct dvb_frontend* fe) +{ + struct bcm3510_state* st = fe->demodulator_priv; + const struct firmware *fw; + u16 addr,len; + const u8 *b; + int ret,i; + + deb_info("requesting firmware\n"); + if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) { + err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); + return ret; + } + deb_info("got firmware: %zd\n",fw->size); + + b = fw->data; + for (i = 0; i < fw->size;) { + addr = le16_to_cpu( *( (u16 *)&b[i] ) ); + len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); + deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size); + if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { + err("firmware download failed: %d\n",ret); + return ret; + } + i += 4 + len; + } + release_firmware(fw); + deb_info("firmware download successfully completed\n"); + return 0; +} + +static int bcm3510_check_firmware_version(struct bcm3510_state *st) +{ + struct bcm3510_hab_cmd_get_version_info ver; + bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver)); + + deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n", + ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version); + + if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION && + ver.config_version == BCM3510_DEF_CONFIG_VERSION && + ver.demod_version == BCM3510_DEF_DEMOD_VERSION) + return 0; + + deb_info("version check failed\n"); + return -ENODEV; +} + +/* (un)resetting the AP */ +static int bcm3510_reset(struct bcm3510_state *st) +{ + int ret; + unsigned long t; + bcm3510_register_value v; + + bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1; + if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) + return ret; + + t = jiffies + 3*HZ; + while (time_before(jiffies, t)) { + msleep(10); + if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) + return ret; + + if (v.APSTAT1_a2.RESET) + return 0; + } + deb_info("reset timed out\n"); + return -ETIMEDOUT; +} + +static int bcm3510_clear_reset(struct bcm3510_state *st) +{ + bcm3510_register_value v; + int ret; + unsigned long t; + + v.raw = 0; + if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) + return ret; + + t = jiffies + 3*HZ; + while (time_before(jiffies, t)) { + msleep(10); + if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) + return ret; + + /* verify that reset is cleared */ + if (!v.APSTAT1_a2.RESET) + return 0; + } + deb_info("reset clear timed out\n"); + return -ETIMEDOUT; +} + +static int bcm3510_init_cold(struct bcm3510_state *st) +{ + int ret; + bcm3510_register_value v; + + /* read Acquisation Processor status register and check it is not in RUN mode */ + if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) + return ret; + if (v.APSTAT1_a2.RUN) { + deb_info("AP is already running - firmware already loaded.\n"); + return 0; + } + + deb_info("reset?\n"); + if ((ret = bcm3510_reset(st)) < 0) + return ret; + + deb_info("tristate?\n"); + /* tri-state */ + v.TSTCTL_2e.CTL = 0; + if ((ret = bcm3510_writeB(st,0x2e,v)) < 0) + return ret; + + deb_info("firmware?\n"); + if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 || + (ret = bcm3510_clear_reset(st)) < 0) + return ret; + + /* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */ + + return 0; +} + +static int bcm3510_init(struct dvb_frontend* fe) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_register_value j; + struct bcm3510_hab_cmd_set_agc c; + int ret; + + if ((ret = bcm3510_readB(st,0xca,&j)) < 0) + return ret; + + deb_info("JDEC: %02x\n",j.raw); + + switch (j.JDEC_ca.JDEC) { + case JDEC_WAIT_AT_RAM: + deb_info("attempting to download firmware\n"); + if ((ret = bcm3510_init_cold(st)) < 0) + return ret; + case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */ + deb_info("firmware is loaded\n"); + bcm3510_check_firmware_version(st); + break; + default: + return -ENODEV; + } + + memset(&c,0,1); + c.SEL = 1; + bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0); + + return 0; +} + + +static struct dvb_frontend_ops bcm3510_ops; + +struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config, + struct i2c_adapter *i2c) +{ + struct bcm3510_state* state = NULL; + int ret; + bcm3510_register_value v; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct bcm3510_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + + state->config = config; + state->i2c = i2c; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + mutex_init(&state->hab_mutex); + + if ((ret = bcm3510_readB(state,0xe0,&v)) < 0) + goto error; + + deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER); + + if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */ + (v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0)) /* warm */ + goto error; + + info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER); + + bcm3510_reset(state); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(bcm3510_attach); + +static struct dvb_frontend_ops bcm3510_ops = { + + .info = { + .name = "Broadcom BCM3510 VSB/QAM frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 803000000, + /* stepsize is just a guess */ + .frequency_stepsize = 0, + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_8VSB | FE_CAN_16VSB | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 + }, + + .release = bcm3510_release, + + .init = bcm3510_init, + .sleep = bcm3510_sleep, + + .set_frontend = bcm3510_set_frontend, + .get_tune_settings = bcm3510_get_tune_settings, + + .read_status = bcm3510_read_status, + .read_ber = bcm3510_read_ber, + .read_signal_strength = bcm3510_read_signal_strength, + .read_snr = bcm3510_read_snr, + .read_ucblocks = bcm3510_read_unc, +}; + +MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver"); +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) + * + * Copyright (C) 2001-5, B2C2 inc. + * + * GPL/Linux driver written by Patrick Boettcher + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef BCM3510_H +#define BCM3510_H + +#include +#include + +struct bcm3510_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +#if defined(CONFIG_DVB_BCM3510) || (defined(CONFIG_DVB_BCM3510_MODULE) && defined(MODULE)) +extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_BCM3510 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bcm3510_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,460 @@ +/* + * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) + * + * Copyright (C) 2001-5, B2C2 inc. + * + * GPL/Linux driver written by Patrick Boettcher + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __BCM3510_PRIV_H__ +#define __BCM3510_PRIV_H__ + +#define PACKED __attribute__((packed)) + +#undef err +#define err(format, arg...) printk(KERN_ERR "bcm3510: " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO "bcm3510: " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING "bcm3510: " format "\n" , ## arg) + + +#define PANASONIC_FIRST_IF_BASE_IN_KHz 1407500 +#define BCM3510_SYMBOL_RATE 5381000 + +typedef union { + u8 raw; + + struct { + u8 CTL :8; + } TSTCTL_2e; + + u8 LDCERC_4e; + u8 LDUERC_4f; + u8 LD_BER0_65; + u8 LD_BER1_66; + u8 LD_BER2_67; + u8 LD_BER3_68; + + struct { + u8 RESET :1; + u8 IDLE :1; + u8 STOP :1; + u8 HIRQ0 :1; + u8 HIRQ1 :1; + u8 na0 :1; + u8 HABAV :1; + u8 na1 :1; + } HCTL1_a0; + + struct { + u8 na0 :1; + u8 IDLMSK :1; + u8 STMSK :1; + u8 I0MSK :1; + u8 I1MSK :1; + u8 na1 :1; + u8 HABMSK :1; + u8 na2 :1; + } HCTLMSK_a1; + + struct { + u8 RESET :1; + u8 IDLE :1; + u8 STOP :1; + u8 RUN :1; + u8 HABAV :1; + u8 MEMAV :1; + u8 ALDONE :1; + u8 REIRQ :1; + } APSTAT1_a2; + + struct { + u8 RSTMSK :1; + u8 IMSK :1; + u8 SMSK :1; + u8 RMSK :1; + u8 HABMSK :1; + u8 MAVMSK :1; + u8 ALDMSK :1; + u8 REMSK :1; + } APMSK1_a3; + + u8 APSTAT2_a4; + u8 APMSK2_a5; + + struct { + u8 HABADR :7; + u8 na :1; + } HABADR_a6; + + u8 HABDATA_a7; + + struct { + u8 HABR :1; + u8 LDHABR :1; + u8 APMSK :1; + u8 HMSK :1; + u8 LDMSK :1; + u8 na :3; + } HABSTAT_a8; + + u8 MADRH_a9; + u8 MADRL_aa; + u8 MDATA_ab; + + struct { +#define JDEC_WAIT_AT_RAM 0x7 +#define JDEC_EEPROM_LOAD_WAIT 0x4 + u8 JDEC :3; + u8 na :5; + } JDEC_ca; + + struct { + u8 REV :4; + u8 LAYER :4; + } REVID_e0; + + struct { + u8 unk0 :1; + u8 CNTCTL :1; + u8 BITCNT :1; + u8 unk1 :1; + u8 RESYNC :1; + u8 unk2 :3; + } BERCTL_fa; + + struct { + u8 CSEL0 :1; + u8 CLKED0 :1; + u8 CSEL1 :1; + u8 CLKED1 :1; + u8 CLKLEV :1; + u8 SPIVAR :1; + u8 na :2; + } TUNSET_fc; + + struct { + u8 CLK :1; + u8 DATA :1; + u8 CS0 :1; + u8 CS1 :1; + u8 AGCSEL :1; + u8 na0 :1; + u8 TUNSEL :1; + u8 na1 :1; + } TUNCTL_fd; + + u8 TUNSEL0_fe; + u8 TUNSEL1_ff; + +} bcm3510_register_value; + +/* HAB commands */ + +/* version */ +#define CMD_GET_VERSION_INFO 0x3D +#define MSGID_GET_VERSION_INFO 0x15 +struct bcm3510_hab_cmd_get_version_info { + u8 microcode_version; + u8 script_version; + u8 config_version; + u8 demod_version; +} PACKED; + +#define BCM3510_DEF_MICROCODE_VERSION 0x0E +#define BCM3510_DEF_SCRIPT_VERSION 0x06 +#define BCM3510_DEF_CONFIG_VERSION 0x01 +#define BCM3510_DEF_DEMOD_VERSION 0xB1 + +/* acquire */ +#define CMD_ACQUIRE 0x38 + +#define MSGID_EXT_TUNER_ACQUIRE 0x0A +struct bcm3510_hab_cmd_ext_acquire { + struct { + u8 MODE :4; + u8 BW :1; + u8 FA :1; + u8 NTSCSWEEP :1; + u8 OFFSET :1; + } PACKED ACQUIRE0; /* control_byte */ + + struct { + u8 IF_FREQ :3; + u8 zero0 :1; + u8 SYM_RATE :3; + u8 zero1 :1; + } PACKED ACQUIRE1; /* sym_if */ + + u8 IF_OFFSET0; /* IF_Offset_10hz */ + u8 IF_OFFSET1; + u8 SYM_OFFSET0; /* SymbolRateOffset */ + u8 SYM_OFFSET1; + u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */ + u8 NTSC_OFFSET1; +} PACKED; + +#define MSGID_INT_TUNER_ACQUIRE 0x0B +struct bcm3510_hab_cmd_int_acquire { + struct { + u8 MODE :4; + u8 BW :1; + u8 FA :1; + u8 NTSCSWEEP :1; + u8 OFFSET :1; + } PACKED ACQUIRE0; /* control_byte */ + + struct { + u8 IF_FREQ :3; + u8 zero0 :1; + u8 SYM_RATE :3; + u8 zero1 :1; + } PACKED ACQUIRE1; /* sym_if */ + + u8 TUNER_FREQ0; + u8 TUNER_FREQ1; + u8 TUNER_FREQ2; + u8 TUNER_FREQ3; + u8 IF_OFFSET0; /* IF_Offset_10hz */ + u8 IF_OFFSET1; + u8 SYM_OFFSET0; /* SymbolRateOffset */ + u8 SYM_OFFSET1; + u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */ + u8 NTSC_OFFSET1; +} PACKED; + +/* modes */ +#define BCM3510_QAM16 = 0x01 +#define BCM3510_QAM32 = 0x02 +#define BCM3510_QAM64 = 0x03 +#define BCM3510_QAM128 = 0x04 +#define BCM3510_QAM256 = 0x05 +#define BCM3510_8VSB = 0x0B +#define BCM3510_16VSB = 0x0D + +/* IF_FREQS */ +#define BCM3510_IF_TERRESTRIAL 0x0 +#define BCM3510_IF_CABLE 0x1 +#define BCM3510_IF_USE_CMD 0x7 + +/* SYM_RATE */ +#define BCM3510_SR_8VSB 0x0 /* 5381119 s/sec */ +#define BCM3510_SR_256QAM 0x1 /* 5360537 s/sec */ +#define BCM3510_SR_16QAM 0x2 /* 5056971 s/sec */ +#define BCM3510_SR_MISC 0x3 /* 5000000 s/sec */ +#define BCM3510_SR_USE_CMD 0x7 + +/* special symbol rate */ +#define CMD_SET_VALUE_NOT_LISTED 0x2d +#define MSGID_SET_SYMBOL_RATE_NOT_LISTED 0x0c +struct bcm3510_hab_cmd_set_sr_not_listed { + u8 HOST_SYM_RATE0; + u8 HOST_SYM_RATE1; + u8 HOST_SYM_RATE2; + u8 HOST_SYM_RATE3; +} PACKED; + +/* special IF */ +#define MSGID_SET_IF_FREQ_NOT_LISTED 0x0d +struct bcm3510_hab_cmd_set_if_freq_not_listed { + u8 HOST_IF_FREQ0; + u8 HOST_IF_FREQ1; + u8 HOST_IF_FREQ2; + u8 HOST_IF_FREQ3; +} PACKED; + +/* auto reacquire */ +#define CMD_AUTO_PARAM 0x2a +#define MSGID_AUTO_REACQUIRE 0x0e +struct bcm3510_hab_cmd_auto_reacquire { + u8 ACQ :1; /* on/off*/ + u8 unused :7; +} PACKED; + +#define MSGID_SET_RF_AGC_SEL 0x12 +struct bcm3510_hab_cmd_set_agc { + u8 LVL :1; + u8 unused :6; + u8 SEL :1; +} PACKED; + +#define MSGID_SET_AUTO_INVERSION 0x14 +struct bcm3510_hab_cmd_auto_inversion { + u8 AI :1; + u8 unused :7; +} PACKED; + + +/* bert control */ +#define CMD_STATE_CONTROL 0x12 +#define MSGID_BERT_CONTROL 0x0e +#define MSGID_BERT_SET 0xfa +struct bcm3510_hab_cmd_bert_control { + u8 BE :1; + u8 unused :7; +} PACKED; + +#define MSGID_TRI_STATE 0x2e +struct bcm3510_hab_cmd_tri_state { + u8 RE :1; /* a/d ram port pins */ + u8 PE :1; /* baud clock pin */ + u8 AC :1; /* a/d clock pin */ + u8 BE :1; /* baud clock pin */ + u8 unused :4; +} PACKED; + + +/* tune */ +#define CMD_TUNE 0x38 +#define MSGID_TUNE 0x16 +struct bcm3510_hab_cmd_tune_ctrl_data_pair { + struct { +#define BITS_8 0x07 +#define BITS_7 0x06 +#define BITS_6 0x05 +#define BITS_5 0x04 +#define BITS_4 0x03 +#define BITS_3 0x02 +#define BITS_2 0x01 +#define BITS_1 0x00 + u8 size :3; + u8 unk :2; + u8 clk_off :1; + u8 cs0 :1; + u8 cs1 :1; + + } PACKED ctrl; + + u8 data; +} PACKED; + +struct bcm3510_hab_cmd_tune { + u8 length; + u8 clock_width; + u8 misc; + u8 TUNCTL_state; + + struct bcm3510_hab_cmd_tune_ctrl_data_pair ctl_dat[16]; +} PACKED; + +#define CMD_STATUS 0x38 +#define MSGID_STATUS1 0x08 +struct bcm3510_hab_cmd_status1 { + struct { + u8 EQ_MODE :4; + u8 reserved :2; + u8 QRE :1; /* if QSE and the spectrum is inversed */ + u8 QSE :1; /* automatic spectral inversion */ + } PACKED STATUS0; + + struct { + u8 RECEIVER_LOCK :1; + u8 FEC_LOCK :1; + u8 OUT_PLL_LOCK :1; + u8 reserved :5; + } PACKED STATUS1; + + struct { + u8 reserved :2; + u8 BW :1; + u8 NTE :1; /* NTSC filter sweep enabled */ + u8 AQI :1; /* currently acquiring */ + u8 FA :1; /* fast acquisition */ + u8 ARI :1; /* auto reacquire */ + u8 TI :1; /* programming the tuner */ + } PACKED STATUS2; + u8 STATUS3; + u8 SNR_EST0; + u8 SNR_EST1; + u8 TUNER_FREQ0; + u8 TUNER_FREQ1; + u8 TUNER_FREQ2; + u8 TUNER_FREQ3; + u8 SYM_RATE0; + u8 SYM_RATE1; + u8 SYM_RATE2; + u8 SYM_RATE3; + u8 SYM_OFFSET0; + u8 SYM_OFFSET1; + u8 SYM_ERROR0; + u8 SYM_ERROR1; + u8 IF_FREQ0; + u8 IF_FREQ1; + u8 IF_FREQ2; + u8 IF_FREQ3; + u8 IF_OFFSET0; + u8 IF_OFFSET1; + u8 IF_ERROR0; + u8 IF_ERROR1; + u8 NTSC_FILTER0; + u8 NTSC_FILTER1; + u8 NTSC_FILTER2; + u8 NTSC_FILTER3; + u8 NTSC_OFFSET0; + u8 NTSC_OFFSET1; + u8 NTSC_ERROR0; + u8 NTSC_ERROR1; + u8 INT_AGC_LEVEL0; + u8 INT_AGC_LEVEL1; + u8 EXT_AGC_LEVEL0; + u8 EXT_AGC_LEVEL1; +} PACKED; + +#define MSGID_STATUS2 0x14 +struct bcm3510_hab_cmd_status2 { + struct { + u8 EQ_MODE :4; + u8 reserved :2; + u8 QRE :1; + u8 QSR :1; + } PACKED STATUS0; + struct { + u8 RL :1; + u8 FL :1; + u8 OL :1; + u8 reserved :5; + } PACKED STATUS1; + u8 SYMBOL_RATE0; + u8 SYMBOL_RATE1; + u8 SYMBOL_RATE2; + u8 SYMBOL_RATE3; + u8 LDCERC0; + u8 LDCERC1; + u8 LDCERC2; + u8 LDCERC3; + u8 LDUERC0; + u8 LDUERC1; + u8 LDUERC2; + u8 LDUERC3; + u8 LDBER0; + u8 LDBER1; + u8 LDBER2; + u8 LDBER3; + struct { + u8 MODE_TYPE :4; /* acquire mode 0 */ + u8 reservd :4; + } MODE_TYPE; + u8 SNR_EST0; + u8 SNR_EST1; + u8 SIGNAL; +} PACKED; + +#define CMD_SET_RF_BW_NOT_LISTED 0x3f +#define MSGID_SET_RF_BW_NOT_LISTED 0x11 +/* TODO */ + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsbe1-d01a.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsbe1-d01a.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsbe1-d01a.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsbe1-d01a.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * bsbe1-d01a.h - ALPS BSBE1-D01A tuner support + * + * Copyright (C) 2011 Oliver Endriss + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ + +#ifndef BSBE1_D01A_H +#define BSBE1_D01A_H + +#include "stb6000.h" +#include "stv0288.h" + +static u8 stv0288_bsbe1_d01a_inittab[] = { + 0x01, 0x15, + 0x02, 0x20, + 0x09, 0x0, + 0x0a, 0x4, + 0x0b, 0x0, + 0x0c, 0x0, + 0x0d, 0x0, + 0x0e, 0xd4, + 0x0f, 0x30, + 0x11, 0x80, + 0x12, 0x03, + 0x13, 0x48, + 0x14, 0x84, + 0x15, 0x45, + 0x16, 0xb7, + 0x17, 0x9c, + 0x18, 0x0, + 0x19, 0xa6, + 0x1a, 0x88, + 0x1b, 0x8f, + 0x1c, 0xf0, + 0x20, 0x0b, + 0x21, 0x54, + 0x22, 0x0, + 0x23, 0x0, + 0x2b, 0xff, + 0x2c, 0xf7, + 0x30, 0x0, + 0x31, 0x1e, + 0x32, 0x14, + 0x33, 0x0f, + 0x34, 0x09, + 0x35, 0x0c, + 0x36, 0x05, + 0x37, 0x2f, + 0x38, 0x16, + 0x39, 0xbd, + 0x3a, 0x03, + 0x3b, 0x13, + 0x3c, 0x11, + 0x3d, 0x30, + 0x40, 0x63, + 0x41, 0x04, + 0x42, 0x60, + 0x43, 0x00, + 0x44, 0x00, + 0x45, 0x00, + 0x46, 0x00, + 0x47, 0x00, + 0x4a, 0x00, + 0x50, 0x10, + 0x51, 0x36, + 0x52, 0x09, + 0x53, 0x94, + 0x54, 0x62, + 0x55, 0x29, + 0x56, 0x64, + 0x57, 0x2b, + 0x58, 0x54, + 0x59, 0x86, + 0x5a, 0x0, + 0x5b, 0x9b, + 0x5c, 0x08, + 0x5d, 0x7f, + 0x5e, 0x0, + 0x5f, 0xff, + 0x70, 0x0, + 0x71, 0x0, + 0x72, 0x0, + 0x74, 0x0, + 0x75, 0x0, + 0x76, 0x0, + 0x81, 0x0, + 0x82, 0x3f, + 0x83, 0x3f, + 0x84, 0x0, + 0x85, 0x0, + 0x88, 0x0, + 0x89, 0x0, + 0x8a, 0x0, + 0x8b, 0x0, + 0x8c, 0x0, + 0x90, 0x0, + 0x91, 0x0, + 0x92, 0x0, + 0x93, 0x0, + 0x94, 0x1c, + 0x97, 0x0, + 0xa0, 0x48, + 0xa1, 0x0, + 0xb0, 0xb8, + 0xb1, 0x3a, + 0xb2, 0x10, + 0xb3, 0x82, + 0xb4, 0x80, + 0xb5, 0x82, + 0xb6, 0x82, + 0xb7, 0x82, + 0xb8, 0x20, + 0xb9, 0x0, + 0xf0, 0x0, + 0xf1, 0x0, + 0xf2, 0xc0, + 0xff, 0xff, +}; + +static struct stv0288_config stv0288_bsbe1_d01a_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + .inittab = stv0288_bsbe1_d01a_inittab, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsbe1.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsbe1.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsbe1.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsbe1.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,105 @@ +/* + * bsbe1.h - ALPS BSBE1 tuner support + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ + +#ifndef BSBE1_H +#define BSBE1_H + +static u8 alps_bsbe1_inittab[] = { + 0x01, 0x15, /* XTAL = 4MHz, VCO = 352 MHz */ + 0x02, 0x30, /* MCLK = 88 MHz */ + 0x03, 0x00, /* ACR output 0 */ + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x05, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x00, /* DAC output 0 */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1/OP0 normal, val = 1 (LNB power on) */ + 0x0d, 0x82, /* DC offset compensation = on, beta_agc1 = 2 */ + 0x0f, 0x92, /* AGC1R */ + 0x10, 0x34, /* AGC2O */ + 0x11, 0x84, /* TLSR */ + 0x12, 0xb9, /* CFD */ + 0x15, 0xc9, /* lock detector threshold */ + 0x28, 0x00, /* out imp: normal, type: parallel, FEC mode: QPSK */ + 0x33, 0xfc, /* RS control */ + 0x34, 0x93, /* count viterbi bit errors per 2E18 bytes */ + 0xff, 0xff +}; + + +static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio ) & 0xf0); + + return 0; +} + +static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +{ + int ret; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + struct i2c_adapter *i2c = fe->tuner_priv; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = params->frequency / 1000; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1; + data[3] = 0xe0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = i2c_transfer(i2c, &msg, 1); + return (ret != 1) ? -EIO : 0; +} + +static struct stv0299_config alps_bsbe1_config = { + .demod_address = 0x68, + .inittab = alps_bsbe1_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsbe1_set_symbol_rate, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsru6.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsru6.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsru6.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/bsru6.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,142 @@ +/* + * bsru6.h - ALPS BSRU6 tuner support (moved from budget-ci.c) + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ + +#ifndef BSRU6_H +#define BSRU6_H + +static u8 alps_bsru6_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x52, + 0xff, 0xff +}; + +static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; + bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; + bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; + bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; + bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; + bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; + bclk = 0x51; + } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, ratio & 0xf0); + + return 0; +} + +static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct i2c_adapter *i2c = fe->tuner_priv; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + buf[3] = 0xC4; + + if (params->frequency > 1530000) + buf[3] = 0xc0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct stv0299_config alps_bsru6_config = { + .demod_address = 0x68, + .inittab = alps_bsru6_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsru6_set_symbol_rate, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22700.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22700.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22700.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22700.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,440 @@ +/* + Conexant cx22700 DVB OFDM demodulator driver + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + Holger Waechtler + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "cx22700.h" + + +struct cx22700_state { + + struct i2c_adapter* i2c; + + const struct cx22700_config* config; + + struct dvb_frontend frontend; +}; + + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "cx22700: " args); \ + } while (0) + +static u8 init_tab [] = { + 0x04, 0x10, + 0x05, 0x09, + 0x06, 0x00, + 0x08, 0x04, + 0x09, 0x00, + 0x0a, 0x01, + 0x15, 0x40, + 0x16, 0x10, + 0x17, 0x87, + 0x18, 0x17, + 0x1a, 0x10, + 0x25, 0x04, + 0x2e, 0x00, + 0x39, 0x00, + 0x3a, 0x04, + 0x45, 0x08, + 0x46, 0x02, + 0x47, 0x05, +}; + + +static int cx22700_writereg (struct cx22700_state* state, u8 reg, u8 data) +{ + int ret; + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + + dprintk ("%s\n", __func__); + + ret = i2c_transfer (state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + __func__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static int cx22700_readreg (struct cx22700_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + dprintk ("%s\n", __func__); + + ret = i2c_transfer (state->i2c, msg, 2); + + if (ret != 2) return -EIO; + + return b1[0]; +} + +static int cx22700_set_inversion (struct cx22700_state* state, int inversion) +{ + u8 val; + + dprintk ("%s\n", __func__); + + switch (inversion) { + case INVERSION_AUTO: + return -EOPNOTSUPP; + case INVERSION_ON: + val = cx22700_readreg (state, 0x09); + return cx22700_writereg (state, 0x09, val | 0x01); + case INVERSION_OFF: + val = cx22700_readreg (state, 0x09); + return cx22700_writereg (state, 0x09, val & 0xfe); + default: + return -EINVAL; + } +} + +static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p) +{ + static const u8 qam_tab [4] = { 0, 1, 0, 2 }; + static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 }; + u8 val; + + dprintk ("%s\n", __func__); + + if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8) + return -EINVAL; + + if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8) + return -EINVAL; + + if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5) + return -EINVAL; + + if (p->guard_interval < GUARD_INTERVAL_1_32 || + p->guard_interval > GUARD_INTERVAL_1_4) + return -EINVAL; + + if (p->transmission_mode != TRANSMISSION_MODE_2K && + p->transmission_mode != TRANSMISSION_MODE_8K) + return -EINVAL; + + if (p->constellation != QPSK && + p->constellation != QAM_16 && + p->constellation != QAM_64) + return -EINVAL; + + if (p->hierarchy_information < HIERARCHY_NONE || + p->hierarchy_information > HIERARCHY_4) + return -EINVAL; + + if (p->bandwidth < BANDWIDTH_8_MHZ || p->bandwidth > BANDWIDTH_6_MHZ) + return -EINVAL; + + if (p->bandwidth == BANDWIDTH_7_MHZ) + cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10)); + else + cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10)); + + val = qam_tab[p->constellation - QPSK]; + val |= p->hierarchy_information - HIERARCHY_NONE; + + cx22700_writereg (state, 0x04, val); + + val = fec_tab[p->code_rate_HP - FEC_1_2] << 3; + val |= fec_tab[p->code_rate_LP - FEC_1_2]; + + cx22700_writereg (state, 0x05, val); + + val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2; + val |= p->transmission_mode - TRANSMISSION_MODE_2K; + + cx22700_writereg (state, 0x06, val); + + cx22700_writereg (state, 0x08, 0x04 | 0x02); /* use user tps parameters */ + cx22700_writereg (state, 0x08, 0x04); /* restart acquisition */ + + return 0; +} + +static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p) +{ + static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 }; + static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4, + FEC_5_6, FEC_7_8 }; + u8 val; + + dprintk ("%s\n", __func__); + + if (!(cx22700_readreg(state, 0x07) & 0x20)) /* tps valid? */ + return -EAGAIN; + + val = cx22700_readreg (state, 0x01); + + if ((val & 0x7) > 4) + p->hierarchy_information = HIERARCHY_AUTO; + else + p->hierarchy_information = HIERARCHY_NONE + (val & 0x7); + + if (((val >> 3) & 0x3) > 2) + p->constellation = QAM_AUTO; + else + p->constellation = qam_tab[(val >> 3) & 0x3]; + + val = cx22700_readreg (state, 0x02); + + if (((val >> 3) & 0x07) > 4) + p->code_rate_HP = FEC_AUTO; + else + p->code_rate_HP = fec_tab[(val >> 3) & 0x07]; + + if ((val & 0x07) > 4) + p->code_rate_LP = FEC_AUTO; + else + p->code_rate_LP = fec_tab[val & 0x07]; + + val = cx22700_readreg (state, 0x03); + + p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3); + p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1); + + return 0; +} + +static int cx22700_init (struct dvb_frontend* fe) + +{ struct cx22700_state* state = fe->demodulator_priv; + int i; + + dprintk("cx22700_init: init chip\n"); + + cx22700_writereg (state, 0x00, 0x02); /* soft reset */ + cx22700_writereg (state, 0x00, 0x00); + + msleep(10); + + for (i=0; idemodulator_priv; + + u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) + | (cx22700_readreg (state, 0x0e) << 1); + u8 sync = cx22700_readreg (state, 0x07); + + *status = 0; + + if (rs_ber < 0xff00) + *status |= FE_HAS_SIGNAL; + + if (sync & 0x20) + *status |= FE_HAS_CARRIER; + + if (sync & 0x10) + *status |= FE_HAS_VITERBI; + + if (sync & 0x10) + *status |= FE_HAS_SYNC; + + if (*status == 0x0f) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct cx22700_state* state = fe->demodulator_priv; + + *ber = cx22700_readreg (state, 0x0c) & 0x7f; + cx22700_writereg (state, 0x0c, 0x00); + + return 0; +} + +static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct cx22700_state* state = fe->demodulator_priv; + + u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) + | (cx22700_readreg (state, 0x0e) << 1); + *signal_strength = ~rs_ber; + + return 0; +} + +static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct cx22700_state* state = fe->demodulator_priv; + + u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) + | (cx22700_readreg (state, 0x0e) << 1); + *snr = ~rs_ber; + + return 0; +} + +static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct cx22700_state* state = fe->demodulator_priv; + + *ucblocks = cx22700_readreg (state, 0x0f); + cx22700_writereg (state, 0x0f, 0x00); + + return 0; +} + +static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx22700_state* state = fe->demodulator_priv; + + cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/ + cx22700_writereg (state, 0x00, 0x00); + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + cx22700_set_inversion (state, p->inversion); + cx22700_set_tps (state, &p->u.ofdm); + cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */ + cx22700_writereg (state, 0x00, 0x01); /* restart acquire */ + + return 0; +} + +static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx22700_state* state = fe->demodulator_priv; + u8 reg09 = cx22700_readreg (state, 0x09); + + p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22700_get_tps (state, &p->u.ofdm); +} + +static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct cx22700_state* state = fe->demodulator_priv; + + if (enable) { + return cx22700_writereg(state, 0x0a, 0x00); + } else { + return cx22700_writereg(state, 0x0a, 0x01); + } +} + +static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 150; + fesettings->step_size = 166667; + fesettings->max_drift = 166667*2; + return 0; +} + +static void cx22700_release(struct dvb_frontend* fe) +{ + struct cx22700_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops cx22700_ops; + +struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, + struct i2c_adapter* i2c) +{ + struct cx22700_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct cx22700_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* check if the demod is there */ + if (cx22700_readreg(state, 0x07) < 0) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops cx22700_ops = { + + .info = { + .name = "Conexant CX22700 DVB-T", + .type = FE_OFDM, + .frequency_min = 470000000, + .frequency_max = 860000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_RECOVER + }, + + .release = cx22700_release, + + .init = cx22700_init, + .i2c_gate_ctrl = cx22700_i2c_gate_ctrl, + + .set_frontend = cx22700_set_frontend, + .get_frontend = cx22700_get_frontend, + .get_tune_settings = cx22700_get_tune_settings, + + .read_status = cx22700_read_status, + .read_ber = cx22700_read_ber, + .read_signal_strength = cx22700_read_signal_strength, + .read_snr = cx22700_read_snr, + .read_ucblocks = cx22700_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver"); +MODULE_AUTHOR("Holger Waechtler"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(cx22700_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22700.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22700.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22700.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22700.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + Conexant CX22700 DVB OFDM demodulator driver + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + Holger Waechtler + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef CX22700_H +#define CX22700_H + +#include + +struct cx22700_config +{ + /* the demodulator's i2c address */ + u8 demod_address; +}; + +#if defined(CONFIG_DVB_CX22700) || (defined(CONFIG_DVB_CX22700_MODULE) && defined(MODULE)) +extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_CX22700 + +#endif // CX22700_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22702.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22702.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22702.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22702.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,638 @@ +/* + Conexant 22702 DVB OFDM demodulator driver + + based on: + Alps TDMB7 DVB OFDM demodulator driver + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + Holger Waechtler + + Copyright (C) 2004 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "cx22702.h" + +struct cx22702_state { + + struct i2c_adapter *i2c; + + /* configuration settings */ + const struct cx22702_config *config; + + struct dvb_frontend frontend; + + /* previous uncorrected block counter */ + u8 prevUCBlocks; +}; + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +#define dprintk if (debug) printk + +/* Register values to initialise the demod */ +static const u8 init_tab[] = { + 0x00, 0x00, /* Stop acquisition */ + 0x0B, 0x06, + 0x09, 0x01, + 0x0D, 0x41, + 0x16, 0x32, + 0x20, 0x0A, + 0x21, 0x17, + 0x24, 0x3e, + 0x26, 0xff, + 0x27, 0x10, + 0x28, 0x00, + 0x29, 0x00, + 0x2a, 0x10, + 0x2b, 0x00, + 0x2c, 0x10, + 0x2d, 0x00, + 0x48, 0xd4, + 0x49, 0x56, + 0x6b, 0x1e, + 0xc8, 0x02, + 0xf9, 0x00, + 0xfa, 0x00, + 0xfb, 0x00, + 0xfc, 0x00, + 0xfd, 0x00, +}; + +static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = state->config->demod_address, .flags = 0, + .buf = buf, .len = 2 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (unlikely(ret != 1)) { + printk(KERN_ERR + "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + __func__, reg, data, ret); + return -1; + } + + return 0; +} + +static u8 cx22702_readreg(struct cx22702_state *state, u8 reg) +{ + int ret; + u8 data; + + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = &data, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (unlikely(ret != 2)) { + printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n", + __func__, reg, ret); + return 0; + } + + return data; +} + +static int cx22702_set_inversion(struct cx22702_state *state, int inversion) +{ + u8 val; + + val = cx22702_readreg(state, 0x0C); + switch (inversion) { + case INVERSION_AUTO: + return -EOPNOTSUPP; + case INVERSION_ON: + val |= 0x01; + break; + case INVERSION_OFF: + val &= 0xfe; + break; + default: + return -EINVAL; + } + return cx22702_writereg(state, 0x0C, val); +} + +/* Retrieve the demod settings */ +static int cx22702_get_tps(struct cx22702_state *state, + struct dvb_ofdm_parameters *p) +{ + u8 val; + + /* Make sure the TPS regs are valid */ + if (!(cx22702_readreg(state, 0x0A) & 0x20)) + return -EAGAIN; + + val = cx22702_readreg(state, 0x01); + switch ((val & 0x18) >> 3) { + case 0: + p->constellation = QPSK; + break; + case 1: + p->constellation = QAM_16; + break; + case 2: + p->constellation = QAM_64; + break; + } + switch (val & 0x07) { + case 0: + p->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + p->hierarchy_information = HIERARCHY_1; + break; + case 2: + p->hierarchy_information = HIERARCHY_2; + break; + case 3: + p->hierarchy_information = HIERARCHY_4; + break; + } + + + val = cx22702_readreg(state, 0x02); + switch ((val & 0x38) >> 3) { + case 0: + p->code_rate_HP = FEC_1_2; + break; + case 1: + p->code_rate_HP = FEC_2_3; + break; + case 2: + p->code_rate_HP = FEC_3_4; + break; + case 3: + p->code_rate_HP = FEC_5_6; + break; + case 4: + p->code_rate_HP = FEC_7_8; + break; + } + switch (val & 0x07) { + case 0: + p->code_rate_LP = FEC_1_2; + break; + case 1: + p->code_rate_LP = FEC_2_3; + break; + case 2: + p->code_rate_LP = FEC_3_4; + break; + case 3: + p->code_rate_LP = FEC_5_6; + break; + case 4: + p->code_rate_LP = FEC_7_8; + break; + } + + val = cx22702_readreg(state, 0x03); + switch ((val & 0x0c) >> 2) { + case 0: + p->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + p->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + p->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + p->guard_interval = GUARD_INTERVAL_1_4; + break; + } + switch (val & 0x03) { + case 0: + p->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + p->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + return 0; +} + +static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct cx22702_state *state = fe->demodulator_priv; + u8 val; + + dprintk("%s(%d)\n", __func__, enable); + val = cx22702_readreg(state, 0x0D); + if (enable) + val &= 0xfe; + else + val |= 0x01; + return cx22702_writereg(state, 0x0D, val); +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +static int cx22702_set_tps(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + u8 val; + struct cx22702_state *state = fe->demodulator_priv; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* set inversion */ + cx22702_set_inversion(state, p->inversion); + + /* set bandwidth */ + val = cx22702_readreg(state, 0x0C) & 0xcf; + switch (p->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + val |= 0x20; + break; + case BANDWIDTH_7_MHZ: + val |= 0x10; + break; + case BANDWIDTH_8_MHZ: + break; + default: + dprintk("%s: invalid bandwidth\n", __func__); + return -EINVAL; + } + cx22702_writereg(state, 0x0C, val); + + p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */ + + /* use auto configuration? */ + if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) || + (p->u.ofdm.constellation == QAM_AUTO) || + (p->u.ofdm.code_rate_HP == FEC_AUTO) || + (p->u.ofdm.code_rate_LP == FEC_AUTO) || + (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) || + (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) { + + /* TPS Source - use hardware driven values */ + cx22702_writereg(state, 0x06, 0x10); + cx22702_writereg(state, 0x07, 0x9); + cx22702_writereg(state, 0x08, 0xC1); + cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) + & 0xfc); + cx22702_writereg(state, 0x0C, + (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); + cx22702_writereg(state, 0x00, 0x01); /* Begin acquisition */ + dprintk("%s: Autodetecting\n", __func__); + return 0; + } + + /* manually programmed values */ + switch (p->u.ofdm.constellation) { /* mask 0x18 */ + case QPSK: + val = 0x00; + break; + case QAM_16: + val = 0x08; + break; + case QAM_64: + val = 0x10; + break; + default: + dprintk("%s: invalid constellation\n", __func__); + return -EINVAL; + } + switch (p->u.ofdm.hierarchy_information) { /* mask 0x07 */ + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + val |= 0x01; + break; + case HIERARCHY_2: + val |= 0x02; + break; + case HIERARCHY_4: + val |= 0x03; + break; + default: + dprintk("%s: invalid hierarchy\n", __func__); + return -EINVAL; + } + cx22702_writereg(state, 0x06, val); + + switch (p->u.ofdm.code_rate_HP) { /* mask 0x38 */ + case FEC_NONE: + case FEC_1_2: + val = 0x00; + break; + case FEC_2_3: + val = 0x08; + break; + case FEC_3_4: + val = 0x10; + break; + case FEC_5_6: + val = 0x18; + break; + case FEC_7_8: + val = 0x20; + break; + default: + dprintk("%s: invalid code_rate_HP\n", __func__); + return -EINVAL; + } + switch (p->u.ofdm.code_rate_LP) { /* mask 0x07 */ + case FEC_NONE: + case FEC_1_2: + break; + case FEC_2_3: + val |= 0x01; + break; + case FEC_3_4: + val |= 0x02; + break; + case FEC_5_6: + val |= 0x03; + break; + case FEC_7_8: + val |= 0x04; + break; + default: + dprintk("%s: invalid code_rate_LP\n", __func__); + return -EINVAL; + } + cx22702_writereg(state, 0x07, val); + + switch (p->u.ofdm.guard_interval) { /* mask 0x0c */ + case GUARD_INTERVAL_1_32: + val = 0x00; + break; + case GUARD_INTERVAL_1_16: + val = 0x04; + break; + case GUARD_INTERVAL_1_8: + val = 0x08; + break; + case GUARD_INTERVAL_1_4: + val = 0x0c; + break; + default: + dprintk("%s: invalid guard_interval\n", __func__); + return -EINVAL; + } + switch (p->u.ofdm.transmission_mode) { /* mask 0x03 */ + case TRANSMISSION_MODE_2K: + break; + case TRANSMISSION_MODE_8K: + val |= 0x1; + break; + default: + dprintk("%s: invalid transmission_mode\n", __func__); + return -EINVAL; + } + cx22702_writereg(state, 0x08, val); + cx22702_writereg(state, 0x0B, + (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02); + cx22702_writereg(state, 0x0C, + (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); + + /* Begin channel acquisition */ + cx22702_writereg(state, 0x00, 0x01); + + return 0; +} + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +static int cx22702_init(struct dvb_frontend *fe) +{ + int i; + struct cx22702_state *state = fe->demodulator_priv; + + cx22702_writereg(state, 0x00, 0x02); + + msleep(10); + + for (i = 0; i < ARRAY_SIZE(init_tab); i += 2) + cx22702_writereg(state, init_tab[i], init_tab[i + 1]); + + cx22702_writereg(state, 0xf8, (state->config->output_mode << 1) + & 0x02); + + cx22702_i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct cx22702_state *state = fe->demodulator_priv; + u8 reg0A; + u8 reg23; + + *status = 0; + + reg0A = cx22702_readreg(state, 0x0A); + reg23 = cx22702_readreg(state, 0x23); + + dprintk("%s: status demod=0x%02x agc=0x%02x\n" + , __func__, reg0A, reg23); + + if (reg0A & 0x10) { + *status |= FE_HAS_LOCK; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + } + + if (reg0A & 0x20) + *status |= FE_HAS_CARRIER; + + if (reg23 < 0xf0) + *status |= FE_HAS_SIGNAL; + + return 0; +} + +static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct cx22702_state *state = fe->demodulator_priv; + + if (cx22702_readreg(state, 0xE4) & 0x02) { + /* Realtime statistics */ + *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 + | (cx22702_readreg(state, 0xDF) & 0x7F); + } else { + /* Averagtine statistics */ + *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 + | cx22702_readreg(state, 0xDF); + } + + return 0; +} + +static int cx22702_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct cx22702_state *state = fe->demodulator_priv; + + u16 rs_ber; + rs_ber = cx22702_readreg(state, 0x23); + *signal_strength = (rs_ber << 8) | rs_ber; + + return 0; +} + +static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct cx22702_state *state = fe->demodulator_priv; + + u16 rs_ber; + if (cx22702_readreg(state, 0xE4) & 0x02) { + /* Realtime statistics */ + rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 + | (cx22702_readreg(state, 0xDF) & 0x7F); + } else { + /* Averagine statistics */ + rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8 + | cx22702_readreg(state, 0xDF); + } + *snr = ~rs_ber; + + return 0; +} + +static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct cx22702_state *state = fe->demodulator_priv; + + u8 _ucblocks; + + /* RS Uncorrectable Packet Count then reset */ + _ucblocks = cx22702_readreg(state, 0xE3); + if (state->prevUCBlocks < _ucblocks) + *ucblocks = (_ucblocks - state->prevUCBlocks); + else + *ucblocks = state->prevUCBlocks - _ucblocks; + state->prevUCBlocks = _ucblocks; + + return 0; +} + +static int cx22702_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cx22702_state *state = fe->demodulator_priv; + + u8 reg0C = cx22702_readreg(state, 0x0C); + + p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22702_get_tps(state, &p->u.ofdm); +} + +static int cx22702_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void cx22702_release(struct dvb_frontend *fe) +{ + struct cx22702_state *state = fe->demodulator_priv; + kfree(state); +} + +static const struct dvb_frontend_ops cx22702_ops; + +struct dvb_frontend *cx22702_attach(const struct cx22702_config *config, + struct i2c_adapter *i2c) +{ + struct cx22702_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* check if the demod is there */ + if (cx22702_readreg(state, 0x1f) != 0x3) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &cx22702_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(cx22702_attach); + +static const struct dvb_frontend_ops cx22702_ops = { + + .info = { + .name = "Conexant CX22702 DVB-T", + .type = FE_OFDM, + .frequency_min = 177000000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER + }, + + .release = cx22702_release, + + .init = cx22702_init, + .i2c_gate_ctrl = cx22702_i2c_gate_ctrl, + + .set_frontend = cx22702_set_tps, + .get_frontend = cx22702_get_frontend, + .get_tune_settings = cx22702_get_tune_settings, + + .read_status = cx22702_read_status, + .read_ber = cx22702_read_ber, + .read_signal_strength = cx22702_read_signal_strength, + .read_snr = cx22702_read_snr, + .read_ucblocks = cx22702_read_ucblocks, +}; + +MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22702.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22702.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22702.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx22702.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + Conexant 22702 DVB OFDM demodulator driver + + based on: + Alps TDMB7 DVB OFDM demodulator driver + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + Holger Waechtler + + Copyright (C) 2004 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef CX22702_H +#define CX22702_H + +#include + +struct cx22702_config { + /* the demodulator's i2c address */ + u8 demod_address; + + /* serial/parallel output */ +#define CX22702_PARALLEL_OUTPUT 0 +#define CX22702_SERIAL_OUTPUT 1 + u8 output_mode; +}; + +#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *cx22702_attach( + const struct cx22702_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *cx22702_attach( + const struct cx22702_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24110.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24110.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24110.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24110.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,667 @@ +/* + cx24110 - Single Chip Satellite Channel Receiver driver module + + Copyright (C) 2002 Peter Hettkamp based on + work + Copyright (C) 1999 Convergence Integrated Media GmbH + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "cx24110.h" + + +struct cx24110_state { + + struct i2c_adapter* i2c; + + const struct cx24110_config* config; + + struct dvb_frontend frontend; + + u32 lastber; + u32 lastbler; + u32 lastesn0; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "cx24110: " args); \ + } while (0) + +static struct {u8 reg; u8 data;} cx24110_regdata[]= + /* Comments beginning with @ denote this value should + be the default */ + {{0x09,0x01}, /* SoftResetAll */ + {0x09,0x00}, /* release reset */ + {0x01,0xe8}, /* MSB of code rate 27.5MS/s */ + {0x02,0x17}, /* middle byte " */ + {0x03,0x29}, /* LSB " */ + {0x05,0x03}, /* @ DVB mode, standard code rate 3/4 */ + {0x06,0xa5}, /* @ PLL 60MHz */ + {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */ + {0x0a,0x00}, /* @ partial chip disables, do not set */ + {0x0b,0x01}, /* set output clock in gapped mode, start signal low + active for first byte */ + {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */ + {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */ + {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1 + to avoid starting the BER counter. Reset the + CRC test bit. Finite counting selected */ + {0x15,0xff}, /* @ size of the limited time window for RS BER + estimation. It is *256 RS blocks, this + gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */ + {0x16,0x00}, /* @ enable all RS output ports */ + {0x17,0x04}, /* @ time window allowed for the RS to sync */ + {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned + for automatically */ + /* leave the current code rate and normalization + registers as they are after reset... */ + {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting + only once */ + {0x23,0x18}, /* @ size of the limited time window for Viterbi BER + estimation. It is *65536 channel bits, i.e. + approx. 38ms at 27.5MS/s, rate 3/4 */ + {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */ + /* leave front-end AGC parameters at default values */ + /* leave decimation AGC parameters at default values */ + {0x35,0x40}, /* disable all interrupts. They are not connected anyway */ + {0x36,0xff}, /* clear all interrupt pending flags */ + {0x37,0x00}, /* @ fully enable AutoAcqq state machine */ + {0x38,0x07}, /* @ enable fade recovery, but not autostart AutoAcq */ + /* leave the equalizer parameters on their default values */ + /* leave the final AGC parameters on their default values */ + {0x41,0x00}, /* @ MSB of front-end derotator frequency */ + {0x42,0x00}, /* @ middle bytes " */ + {0x43,0x00}, /* @ LSB " */ + /* leave the carrier tracking loop parameters on default */ + /* leave the bit timing loop parameters at default */ + {0x56,0x4d}, /* set the filtune voltage to 2.7V, as recommended by */ + /* the cx24108 data sheet for symbol rates above 15MS/s */ + {0x57,0x00}, /* @ Filter sigma delta enabled, positive */ + {0x61,0x95}, /* GPIO pins 1-4 have special function */ + {0x62,0x05}, /* GPIO pin 5 has special function, pin 6 is GPIO */ + {0x63,0x00}, /* All GPIO pins use CMOS output characteristics */ + {0x64,0x20}, /* GPIO 6 is input, all others are outputs */ + {0x6d,0x30}, /* tuner auto mode clock freq 62kHz */ + {0x70,0x15}, /* use auto mode, tuner word is 21 bits long */ + {0x73,0x00}, /* @ disable several demod bypasses */ + {0x74,0x00}, /* @ " */ + {0x75,0x00} /* @ " */ + /* the remaining registers are for SEC */ + }; + + +static int cx24110_writereg (struct cx24110_state* state, int reg, int data) +{ + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + dprintk ("%s: writereg error (err == %i, reg == 0x%02x," + " data == 0x%02x)\n", __func__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static int cx24110_readreg (struct cx24110_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) return ret; + + return b1[0]; +} + +static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inversion_t inversion) +{ +/* fixme (low): error handling */ + + switch (inversion) { + case INVERSION_OFF: + cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1); + /* AcqSpectrInvDis on. No idea why someone should want this */ + cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7); + /* Initial value 0 at start of acq */ + cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef); + /* current value 0 */ + /* The cx24110 manual tells us this reg is read-only. + But what the heck... set it ayways */ + break; + case INVERSION_ON: + cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1); + /* AcqSpectrInvDis on. No idea why someone should want this */ + cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08); + /* Initial value 1 at start of acq */ + cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10); + /* current value 1 */ + break; + case INVERSION_AUTO: + cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe); + /* AcqSpectrInvDis off. Leave initial & current states as is */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec) +{ +/* fixme (low): error handling */ + + static const int rate[]={-1,1,2,3,5,7,-1}; + static const int g1[]={-1,0x01,0x02,0x05,0x15,0x45,-1}; + static const int g2[]={-1,0x01,0x03,0x06,0x1a,0x7a,-1}; + + /* Well, the AutoAcq engine of the cx24106 and 24110 automatically + searches all enabled viterbi rates, and can handle non-standard + rates as well. */ + + if (fec>FEC_AUTO) + fec=FEC_AUTO; + + if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */ + cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf); + /* clear AcqVitDis bit */ + cx24110_writereg(state,0x18,0xae); + /* allow all DVB standard code rates */ + cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3); + /* set nominal Viterbi rate 3/4 */ + cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3); + /* set current Viterbi rate 3/4 */ + cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06); + /* set the puncture registers for code rate 3/4 */ + return 0; + } else { + cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20); + /* set AcqVitDis bit */ + if(rate[fec]>0) { + cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]); + /* set nominal Viterbi rate */ + cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]); + /* set current Viterbi rate */ + cx24110_writereg(state,0x1a,g1[fec]); + cx24110_writereg(state,0x1b,g2[fec]); + /* not sure if this is the right way: I always used AutoAcq mode */ + } else + return -EOPNOTSUPP; +/* fixme (low): which is the correct return code? */ + }; + return 0; +} + +static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state) +{ + int i; + + i=cx24110_readreg(state,0x22)&0x0f; + if(!(i&0x08)) { + return FEC_1_2 + i - 1; + } else { +/* fixme (low): a special code rate has been selected. In theory, we need to + return a denominator value, a numerator value, and a pair of puncture + maps to correctly describe this mode. But this should never happen in + practice, because it cannot be set by cx24110_get_fec. */ + return FEC_NONE; + } +} + +static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate) +{ +/* fixme (low): add error handling */ + u32 ratio; + u32 tmp, fclk, BDRI; + + static const u32 bands[]={5000000UL,15000000UL,90999000UL/2}; + int i; + + dprintk("cx24110 debug: entering %s(%d)\n",__func__,srate); + if (srate>90999000UL/2) + srate=90999000UL/2; + if (srate<500000) + srate=500000; + + for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++) + ; + /* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz, + and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult, + R06[3:0] PLLphaseDetGain */ + tmp=cx24110_readreg(state,0x07)&0xfc; + if(srate<90999000UL/4) { /* sample rate 45MHz*/ + cx24110_writereg(state,0x07,tmp); + cx24110_writereg(state,0x06,0x78); + fclk=90999000UL/2; + } else if(srate<60666000UL/2) { /* sample rate 60MHz */ + cx24110_writereg(state,0x07,tmp|0x1); + cx24110_writereg(state,0x06,0xa5); + fclk=60666000UL; + } else if(srate<80888000UL/2) { /* sample rate 80MHz */ + cx24110_writereg(state,0x07,tmp|0x2); + cx24110_writereg(state,0x06,0x87); + fclk=80888000UL; + } else { /* sample rate 90MHz */ + cx24110_writereg(state,0x07,tmp|0x3); + cx24110_writereg(state,0x06,0x78); + fclk=90999000UL; + }; + dprintk("cx24110 debug: fclk %d Hz\n",fclk); + /* we need to divide two integers with approx. 27 bits in 32 bit + arithmetic giving a 25 bit result */ + /* the maximum dividend is 90999000/2, 0x02b6446c, this number is + also the most complex divisor. Hence, the dividend has, + assuming 32bit unsigned arithmetic, 6 clear bits on top, the + divisor 2 unused bits at the bottom. Also, the quotient is + always less than 1/2. Borrowed from VES1893.c, of course */ + + tmp=srate<<6; + BDRI=fclk>>2; + ratio=(tmp/BDRI); + + tmp=(tmp%BDRI)<<8; + ratio=(ratio<<8)+(tmp/BDRI); + + tmp=(tmp%BDRI)<<8; + ratio=(ratio<<8)+(tmp/BDRI); + + tmp=(tmp%BDRI)<<1; + ratio=(ratio<<1)+(tmp/BDRI); + + dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]); + dprintk("fclk = %d\n", fclk); + dprintk("ratio= %08x\n", ratio); + + cx24110_writereg(state, 0x1, (ratio>>16)&0xff); + cx24110_writereg(state, 0x2, (ratio>>8)&0xff); + cx24110_writereg(state, 0x3, (ratio)&0xff); + + return 0; + +} + +static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len) +{ + struct cx24110_state *state = fe->demodulator_priv; + + if (len != 3) + return -EINVAL; + +/* tuner data is 21 bits long, must be left-aligned in data */ +/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */ +/* FIXME (low): add error handling, avoid infinite loops if HW fails... */ + + cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */ + cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */ + + /* if the auto tuner writer is still busy, clear it out */ + while (cx24110_readreg(state,0x6d)&0x80) + cx24110_writereg(state,0x72,0); + + /* write the topmost 8 bits */ + cx24110_writereg(state,0x72,buf[0]); + + /* wait for the send to be completed */ + while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) + ; + + /* send another 8 bytes */ + cx24110_writereg(state,0x72,buf[1]); + while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) + ; + + /* and the topmost 5 bits of this byte */ + cx24110_writereg(state,0x72,buf[2]); + while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) + ; + + /* now strobe the enable line once */ + cx24110_writereg(state,0x6d,0x32); + cx24110_writereg(state,0x6d,0x30); + + return 0; +} + +static int cx24110_initfe(struct dvb_frontend* fe) +{ + struct cx24110_state *state = fe->demodulator_priv; +/* fixme (low): error handling */ + int i; + + dprintk("%s: init chip\n", __func__); + + for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) { + cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data); + }; + + return 0; +} + +static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct cx24110_state *state = fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0); + case SEC_VOLTAGE_18: + return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40); + default: + return -EINVAL; + }; +} + +static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + int rv, bit; + struct cx24110_state *state = fe->demodulator_priv; + unsigned long timeout; + + if (burst == SEC_MINI_A) + bit = 0x00; + else if (burst == SEC_MINI_B) + bit = 0x08; + else + return -EINVAL; + + rv = cx24110_readreg(state, 0x77); + if (!(rv & 0x04)) + cx24110_writereg(state, 0x77, rv | 0x04); + + rv = cx24110_readreg(state, 0x76); + cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit)); + timeout = jiffies + msecs_to_jiffies(100); + while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40)) + ; /* wait for LNB ready */ + + return 0; +} + +static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *cmd) +{ + int i, rv; + struct cx24110_state *state = fe->demodulator_priv; + unsigned long timeout; + + if (cmd->msg_len < 3 || cmd->msg_len > 6) + return -EINVAL; /* not implemented */ + + for (i = 0; i < cmd->msg_len; i++) + cx24110_writereg(state, 0x79 + i, cmd->msg[i]); + + rv = cx24110_readreg(state, 0x77); + if (rv & 0x04) { + cx24110_writereg(state, 0x77, rv & ~0x04); + msleep(30); /* reportedly fixes switching problems */ + } + + rv = cx24110_readreg(state, 0x76); + + cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); + timeout = jiffies + msecs_to_jiffies(100); + while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40)) + ; /* wait for LNB ready */ + + return 0; +} + +static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct cx24110_state *state = fe->demodulator_priv; + + int sync = cx24110_readreg (state, 0x55); + + *status = 0; + + if (sync & 0x10) + *status |= FE_HAS_SIGNAL; + + if (sync & 0x08) + *status |= FE_HAS_CARRIER; + + sync = cx24110_readreg (state, 0x08); + + if (sync & 0x40) + *status |= FE_HAS_VITERBI; + + if (sync & 0x20) + *status |= FE_HAS_SYNC; + + if ((sync & 0x60) == 0x60) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct cx24110_state *state = fe->demodulator_priv; + + /* fixme (maybe): value range is 16 bit. Scale? */ + if(cx24110_readreg(state,0x24)&0x10) { + /* the Viterbi error counter has finished one counting window */ + cx24110_writereg(state,0x24,0x04); /* select the ber reg */ + state->lastber=cx24110_readreg(state,0x25)| + (cx24110_readreg(state,0x26)<<8); + cx24110_writereg(state,0x24,0x04); /* start new count window */ + cx24110_writereg(state,0x24,0x14); + } + *ber = state->lastber; + + return 0; +} + +static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct cx24110_state *state = fe->demodulator_priv; + +/* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */ + u8 signal = cx24110_readreg (state, 0x27)+128; + *signal_strength = (signal << 8) | signal; + + return 0; +} + +static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct cx24110_state *state = fe->demodulator_priv; + + /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */ + if(cx24110_readreg(state,0x6a)&0x80) { + /* the Es/N0 error counter has finished one counting window */ + state->lastesn0=cx24110_readreg(state,0x69)| + (cx24110_readreg(state,0x68)<<8); + cx24110_writereg(state,0x6a,0x84); /* start new count window */ + } + *snr = state->lastesn0; + + return 0; +} + +static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct cx24110_state *state = fe->demodulator_priv; + u32 lastbyer; + + if(cx24110_readreg(state,0x10)&0x40) { + /* the RS error counter has finished one counting window */ + cx24110_writereg(state,0x10,0x60); /* select the byer reg */ + lastbyer=cx24110_readreg(state,0x12)| + (cx24110_readreg(state,0x13)<<8)| + (cx24110_readreg(state,0x14)<<16); + cx24110_writereg(state,0x10,0x70); /* select the bler reg */ + state->lastbler=cx24110_readreg(state,0x12)| + (cx24110_readreg(state,0x13)<<8)| + (cx24110_readreg(state,0x14)<<16); + cx24110_writereg(state,0x10,0x20); /* start new count window */ + } + *ucblocks = state->lastbler; + + return 0; +} + +static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24110_state *state = fe->demodulator_priv; + + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + cx24110_set_inversion (state, p->inversion); + cx24110_set_fec (state, p->u.qpsk.fec_inner); + cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate); + cx24110_writereg(state,0x04,0x05); /* start acquisition */ + + return 0; +} + +static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24110_state *state = fe->demodulator_priv; + s32 afc; unsigned sclk; + +/* cannot read back tuner settings (freq). Need to have some private storage */ + + sclk = cx24110_readreg (state, 0x07) & 0x03; +/* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz. + * Need 64 bit arithmetic. Is thiss possible in the kernel? */ + if (sclk==0) sclk=90999000L/2L; + else if (sclk==1) sclk=60666000L; + else if (sclk==2) sclk=80888000L; + else sclk=90999000L; + sclk>>=8; + afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+ + ((sclk*cx24110_readreg (state, 0x45))>>8)+ + ((sclk*cx24110_readreg (state, 0x46))>>16); + + p->frequency += afc; + p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ? + INVERSION_ON : INVERSION_OFF; + p->u.qpsk.fec_inner = cx24110_get_fec (state); + + return 0; +} + +static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct cx24110_state *state = fe->demodulator_priv; + + return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0)); +} + +static void cx24110_release(struct dvb_frontend* fe) +{ + struct cx24110_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops cx24110_ops; + +struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, + struct i2c_adapter* i2c) +{ + struct cx24110_state* state = NULL; + int ret; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct cx24110_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->lastber = 0; + state->lastbler = 0; + state->lastesn0 = 0; + + /* check if the demod is there */ + ret = cx24110_readreg(state, 0x00); + if ((ret != 0x5a) && (ret != 0x69)) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops cx24110_ops = { + + .info = { + .name = "Conexant CX24110 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1011, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_RECOVER + }, + + .release = cx24110_release, + + .init = cx24110_initfe, + .write = _cx24110_pll_write, + .set_frontend = cx24110_set_frontend, + .get_frontend = cx24110_get_frontend, + .read_status = cx24110_read_status, + .read_ber = cx24110_read_ber, + .read_signal_strength = cx24110_read_signal_strength, + .read_snr = cx24110_read_snr, + .read_ucblocks = cx24110_read_ucblocks, + + .diseqc_send_master_cmd = cx24110_send_diseqc_msg, + .set_tone = cx24110_set_tone, + .set_voltage = cx24110_set_voltage, + .diseqc_send_burst = cx24110_diseqc_send_burst, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver"); +MODULE_AUTHOR("Peter Hettkamp"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(cx24110_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24110.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24110.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24110.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24110.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* + cx24110 - Single Chip Satellite Channel Receiver driver module + + Copyright (C) 2002 Peter Hettkamp based on + work + Copyright (C) 1999 Convergence Integrated Media GmbH + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef CX24110_H +#define CX24110_H + +#include + +struct cx24110_config +{ + /* the demodulator's i2c address */ + u8 demod_address; +}; + +static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) +{ + u8 buf[] = { + (u8)((val >> 24) & 0xff), + (u8)((val >> 16) & 0xff), + (u8)((val >> 8) & 0xff) + }; + + if (fe->ops.write) + return fe->ops.write(fe, buf, 3); + return 0; +} + +#if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) +extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_CX24110 + +#endif // CX24110_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24113.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24113.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24113.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24113.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,620 @@ +/* + * Driver for Conexant CX24113/CX24128 Tuner (Satellite) + * + * Copyright (C) 2007-8 Patrick Boettcher + * + * Developed for BBTI / Technisat + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "cx24113.h" + +static int debug; + +#define cx_info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0) +#define cx_err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0) + +#define dprintk(args...) \ + do { \ + if (debug) { \ + printk(KERN_DEBUG "CX24113: %s: ", __func__); \ + printk(args); \ + } \ + } while (0) + +struct cx24113_state { + struct i2c_adapter *i2c; + const struct cx24113_config *config; + +#define REV_CX24113 0x23 + u8 rev; + u8 ver; + + u8 icp_mode:1; + +#define ICP_LEVEL1 0 +#define ICP_LEVEL2 1 +#define ICP_LEVEL3 2 +#define ICP_LEVEL4 3 + u8 icp_man:2; + u8 icp_auto_low:2; + u8 icp_auto_mlow:2; + u8 icp_auto_mhi:2; + u8 icp_auto_hi:2; + u8 icp_dig; + +#define LNA_MIN_GAIN 0 +#define LNA_MID_GAIN 1 +#define LNA_MAX_GAIN 2 + u8 lna_gain:2; + + u8 acp_on:1; + + u8 vco_mode:2; + u8 vco_shift:1; +#define VCOBANDSEL_6 0x80 +#define VCOBANDSEL_5 0x01 +#define VCOBANDSEL_4 0x02 +#define VCOBANDSEL_3 0x04 +#define VCOBANDSEL_2 0x08 +#define VCOBANDSEL_1 0x10 + u8 vco_band; + +#define VCODIV4 4 +#define VCODIV2 2 + u8 vcodiv; + + u8 bs_delay:4; + u16 bs_freqcnt:13; + u16 bs_rdiv; + u8 prescaler_mode:1; + + u8 rfvga_bias_ctrl; + + s16 tuner_gain_thres; + u8 gain_level; + + u32 frequency; + + u8 refdiv; + + u8 Fwindow_enabled; +}; + +static int cx24113_writereg(struct cx24113_state *state, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->i2c_addr, + .flags = 0, .buf = buf, .len = 2 }; + int err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x," + " data == 0x%02x)\n", __func__, err, reg, data); + return err; + } + + return 0; +} + +static int cx24113_readreg(struct cx24113_state *state, u8 reg) +{ + int ret; + u8 b; + struct i2c_msg msg[] = { + { .addr = state->config->i2c_addr, + .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->config->i2c_addr, + .flags = I2C_M_RD, .buf = &b, .len = 1 } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n", + __func__, reg, ret); + return ret; + } + + return b; +} + +static void cx24113_set_parameters(struct cx24113_state *state) +{ + u8 r; + + r = cx24113_readreg(state, 0x10) & 0x82; + r |= state->icp_mode; + r |= state->icp_man << 4; + r |= state->icp_dig << 2; + r |= state->prescaler_mode << 5; + cx24113_writereg(state, 0x10, r); + + r = (state->icp_auto_low << 0) | (state->icp_auto_mlow << 2) + | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6); + cx24113_writereg(state, 0x11, r); + + if (state->rev == REV_CX24113) { + r = cx24113_readreg(state, 0x20) & 0xec; + r |= state->lna_gain; + r |= state->rfvga_bias_ctrl << 4; + cx24113_writereg(state, 0x20, r); + } + + r = cx24113_readreg(state, 0x12) & 0x03; + r |= state->acp_on << 2; + r |= state->bs_delay << 4; + cx24113_writereg(state, 0x12, r); + + r = cx24113_readreg(state, 0x18) & 0x40; + r |= state->vco_shift; + if (state->vco_band == VCOBANDSEL_6) + r |= (1 << 7); + else + r |= (state->vco_band << 1); + cx24113_writereg(state, 0x18, r); + + r = cx24113_readreg(state, 0x14) & 0x20; + r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f); + cx24113_writereg(state, 0x14, r); + cx24113_writereg(state, 0x15, (state->bs_freqcnt & 0xff)); + + cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff); + r = (cx24113_readreg(state, 0x17) & 0x0f) | + ((state->bs_rdiv & 0x0f) << 4); + cx24113_writereg(state, 0x17, r); +} + +#define VGA_0 0x00 +#define VGA_1 0x04 +#define VGA_2 0x02 +#define VGA_3 0x06 +#define VGA_4 0x01 +#define VGA_5 0x05 +#define VGA_6 0x03 +#define VGA_7 0x07 + +#define RFVGA_0 0x00 +#define RFVGA_1 0x01 +#define RFVGA_2 0x02 +#define RFVGA_3 0x03 + +static int cx24113_set_gain_settings(struct cx24113_state *state, + s16 power_estimation) +{ + u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0, + vga = cx24113_readreg(state, 0x1f) & 0x3f, + rfvga = cx24113_readreg(state, 0x20) & 0xf3; + u8 gain_level = power_estimation >= state->tuner_gain_thres; + + dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n", + power_estimation, state->tuner_gain_thres, + state->gain_level, gain_level); + + if (gain_level == state->gain_level) + return 0; /* nothing to be done */ + + ampout |= 0xf; + + if (gain_level) { + rfvga |= RFVGA_0 << 2; + vga |= (VGA_7 << 3) | VGA_7; + } else { + rfvga |= RFVGA_2 << 2; + vga |= (VGA_6 << 3) | VGA_2; + } + state->gain_level = gain_level; + + cx24113_writereg(state, 0x1d, ampout); + cx24113_writereg(state, 0x1f, vga); + cx24113_writereg(state, 0x20, rfvga); + + return 1; /* did something */ +} + +static int cx24113_set_Fref(struct cx24113_state *state, u8 high) +{ + u8 xtal = cx24113_readreg(state, 0x02); + if (state->rev == 0x43 && state->vcodiv == VCODIV4) + high = 1; + + xtal &= ~0x2; + if (high) + xtal |= high << 1; + return cx24113_writereg(state, 0x02, xtal); +} + +static int cx24113_enable(struct cx24113_state *state, u8 enable) +{ + u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable; + if (state->rev == REV_CX24113) + r21 |= (1 << 1); + return cx24113_writereg(state, 0x21, r21); +} + +static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz) +{ + u8 r; + + if (bandwidth_khz <= 19000) + r = 0x03 << 6; + else if (bandwidth_khz <= 25000) + r = 0x02 << 6; + else + r = 0x01 << 6; + + dprintk("bandwidth to be set: %d\n", bandwidth_khz); + bandwidth_khz *= 10; + bandwidth_khz -= 10000; + bandwidth_khz /= 1000; + bandwidth_khz += 5; + bandwidth_khz /= 10; + + dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz); + + r |= bandwidth_khz & 0x3f; + + return cx24113_writereg(state, 0x1e, r); +} + +static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on) +{ + u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7); + return cx24113_writereg(state, 0x10, r); +} + +static int cx24113_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct cx24113_state *state = fe->tuner_priv; + u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1; + if (r) + *status |= TUNER_STATUS_LOCKED; + dprintk("PLL locked: %d\n", r); + return 0; +} + +static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv) +{ + if (state->rev == 0x43 && state->vcodiv == VCODIV4) + refdiv = 2; + return state->refdiv = refdiv; +} + +static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f) +{ + s32 N; + s64 F; + u64 dividend; + u8 R, r; + u8 vcodiv; + u8 factor; + s32 freq_hz = state->frequency * 1000; + + if (state->config->xtal_khz < 20000) + factor = 1; + else + factor = 2; + + if (state->rev == REV_CX24113) { + if (state->frequency >= 1100000) + vcodiv = VCODIV2; + else + vcodiv = VCODIV4; + } else { + if (state->frequency >= 1165000) + vcodiv = VCODIV2; + else + vcodiv = VCODIV4; + } + state->vcodiv = vcodiv; + + dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv); + R = 0; + do { + R = cx24113_set_ref_div(state, R + 1); + + /* calculate tuner PLL settings: */ + N = (freq_hz / 100 * vcodiv) * R; + N /= (state->config->xtal_khz) * factor * 2; + N += 5; /* For round up. */ + N /= 10; + N -= 32; + } while (N < 6 && R < 3); + + if (N < 6) { + cx_err("strange frequency: N < 6\n"); + return; + } + F = freq_hz; + F *= (u64) (R * vcodiv * 262144); + dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R); + /* do_div needs an u64 as first argument */ + dividend = F; + do_div(dividend, state->config->xtal_khz * 1000 * factor * 2); + F = dividend; + dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R); + F -= (N + 32) * 262144; + + dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R); + + if (state->Fwindow_enabled) { + if (F > (262144 / 2 - 1638)) + F = 262144 / 2 - 1638; + if (F < (-262144 / 2 + 1638)) + F = -262144 / 2 + 1638; + if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) { + F = 0; + r = cx24113_readreg(state, 0x10); + cx24113_writereg(state, 0x10, r | (1 << 6)); + } + } + dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R); + + *n = (u16) N; + *f = (s32) F; +} + + +static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r) +{ + u8 reg; + cx24113_writereg(state, 0x19, (n >> 1) & 0xff); + + reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f); + cx24113_writereg(state, 0x1a, reg); + + cx24113_writereg(state, 0x1b, (f >> 3) & 0xff); + + reg = cx24113_readreg(state, 0x1c) & 0x1f; + cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5)); + + cx24113_set_Fref(state, r - 1); +} + +static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency) +{ + u8 r = 1; /* or 2 */ + u16 n = 6; + s32 f = 0; + + r = cx24113_readreg(state, 0x14); + cx24113_writereg(state, 0x14, r & 0x3f); + + r = cx24113_readreg(state, 0x10); + cx24113_writereg(state, 0x10, r & 0xbf); + + state->frequency = frequency; + + dprintk("tuning to frequency: %d\n", frequency); + + cx24113_calc_pll_nf(state, &n, &f); + cx24113_set_nfr(state, n, f, state->refdiv); + + r = cx24113_readreg(state, 0x18) & 0xbf; + if (state->vcodiv != VCODIV2) + r |= 1 << 6; + cx24113_writereg(state, 0x18, r); + + /* The need for this sleep is not clear. But helps in some cases */ + msleep(5); + + r = cx24113_readreg(state, 0x1c) & 0xef; + cx24113_writereg(state, 0x1c, r | (1 << 4)); + return 0; +} + +static int cx24113_init(struct dvb_frontend *fe) +{ + struct cx24113_state *state = fe->tuner_priv; + int ret; + + state->tuner_gain_thres = -50; + state->gain_level = 255; /* to force a gain-setting initialization */ + state->icp_mode = 0; + + if (state->config->xtal_khz < 11000) { + state->icp_auto_hi = ICP_LEVEL4; + state->icp_auto_mhi = ICP_LEVEL4; + state->icp_auto_mlow = ICP_LEVEL3; + state->icp_auto_low = ICP_LEVEL3; + } else { + state->icp_auto_hi = ICP_LEVEL4; + state->icp_auto_mhi = ICP_LEVEL4; + state->icp_auto_mlow = ICP_LEVEL3; + state->icp_auto_low = ICP_LEVEL2; + } + + state->icp_dig = ICP_LEVEL3; + state->icp_man = ICP_LEVEL1; + state->acp_on = 1; + state->vco_mode = 0; + state->vco_shift = 0; + state->vco_band = VCOBANDSEL_1; + state->bs_delay = 8; + state->bs_freqcnt = 0x0fff; + state->bs_rdiv = 0x0fff; + state->prescaler_mode = 0; + state->lna_gain = LNA_MAX_GAIN; + state->rfvga_bias_ctrl = 1; + state->Fwindow_enabled = 1; + + cx24113_set_Fref(state, 0); + cx24113_enable(state, 0x3d); + cx24113_set_parameters(state); + + cx24113_set_gain_settings(state, -30); + + cx24113_set_bandwidth(state, 18025); + cx24113_set_clk_inversion(state, 1); + + if (state->config->xtal_khz >= 40000) + ret = cx24113_writereg(state, 0x02, + (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2)); + else + ret = cx24113_writereg(state, 0x02, + (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2)); + + return ret; +} + +static int cx24113_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cx24113_state *state = fe->tuner_priv; + /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */ + u32 roll_off = 675; + u32 bw; + + bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000; + bw += (10000000/100) + 5; + bw /= 10; + bw += 1000; + cx24113_set_bandwidth(state, bw); + + cx24113_set_frequency(state, p->frequency); + msleep(5); + return cx24113_get_status(fe, &bw); +} + +static s8 cx24113_agc_table[2][10] = { + {-54, -41, -35, -30, -25, -21, -16, -10, -6, -2}, + {-39, -35, -30, -25, -19, -15, -11, -5, 1, 9}, +}; + +void cx24113_agc_callback(struct dvb_frontend *fe) +{ + struct cx24113_state *state = fe->tuner_priv; + s16 s, i; + if (!fe->ops.read_signal_strength) + return; + + do { + /* this only works with the current CX24123 implementation */ + fe->ops.read_signal_strength(fe, (u16 *) &s); + s >>= 8; + dprintk("signal strength: %d\n", s); + for (i = 0; i < sizeof(cx24113_agc_table[0]); i++) + if (cx24113_agc_table[state->gain_level][i] > s) + break; + s = -25 - i*5; + } while (cx24113_set_gain_settings(state, s)); +} +EXPORT_SYMBOL(cx24113_agc_callback); + +static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct cx24113_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int cx24113_release(struct dvb_frontend *fe) +{ + struct cx24113_state *state = fe->tuner_priv; + dprintk("\n"); + fe->tuner_priv = NULL; + kfree(state); + return 0; +} + +static const struct dvb_tuner_ops cx24113_tuner_ops = { + .info = { + .name = "Conexant CX24113", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 125, + }, + + .release = cx24113_release, + + .init = cx24113_init, + .sleep = NULL, + + .set_params = cx24113_set_params, + .get_frequency = cx24113_get_frequency, + .get_bandwidth = NULL, + .get_status = cx24113_get_status, +}; + +struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, + const struct cx24113_config *config, struct i2c_adapter *i2c) +{ + /* allocate memory for the internal state */ + struct cx24113_state *state = + kzalloc(sizeof(struct cx24113_state), GFP_KERNEL); + int rc; + if (state == NULL) { + cx_err("Unable to kzalloc\n"); + goto error; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + cx_info("trying to detect myself\n"); + + /* making a dummy read, because of some expected troubles + * after power on */ + cx24113_readreg(state, 0x00); + + rc = cx24113_readreg(state, 0x00); + if (rc < 0) { + cx_info("CX24113 not found.\n"); + goto error; + } + state->rev = rc; + + switch (rc) { + case 0x43: + cx_info("detected CX24113 variant\n"); + break; + case REV_CX24113: + cx_info("successfully detected\n"); + break; + default: + cx_err("unsupported device id: %x\n", state->rev); + goto error; + } + state->ver = cx24113_readreg(state, 0x01); + cx_info("version: %x\n", state->ver); + + /* create dvb_frontend */ + memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops, + sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = state; + return fe; + +error: + kfree(state); + + return NULL; +} +EXPORT_SYMBOL(cx24113_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware"); +MODULE_LICENSE("GPL"); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24113.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24113.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24113.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24113.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Driver for Conexant CX24113/CX24128 Tuner (Satellite) + * + * Copyright (C) 2007-8 Patrick Boettcher + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CX24113_H +#define CX24113_H + +struct dvb_frontend; + +struct cx24113_config { + u8 i2c_addr; /* 0x14 or 0x54 */ + + u32 xtal_khz; +}; + +#if defined(CONFIG_DVB_TUNER_CX24113) || \ + (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) +extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *, + const struct cx24113_config *config, struct i2c_adapter *i2c); + +extern void cx24113_agc_callback(struct dvb_frontend *fe); +#else +static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, + const struct cx24113_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline void cx24113_agc_callback(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} +#endif + +#endif /* CX24113_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24116.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24116.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24116.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24116.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,1518 @@ +/* + Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver + + Copyright (C) 2006-2008 Steven Toth + Copyright (C) 2006-2007 Georg Acher + Copyright (C) 2007-2008 Darron Broad + March 2007 + Fixed some bugs. + Added diseqc support. + Added corrected signal strength support. + August 2007 + Sync with legacy version. + Some clean ups. + Copyright (C) 2008 Igor Liplianin + September, 9th 2008 + Fixed locking on high symbol rates (>30000). + Implement MPEG initialization parameter. + January, 17th 2009 + Fill set_voltage with actually control voltage code. + Correct set tone to not affect voltage. + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "cx24116.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_INFO "cx24116: " args); \ + } while (0) + +#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw" +#define CX24116_SEARCH_RANGE_KHZ 5000 + +/* known registers */ +#define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */ +#define CX24116_REG_EXECUTE (0x1f) /* execute command */ +#define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */ +#define CX24116_REG_RESET (0x20) /* reset status > 0 */ +#define CX24116_REG_SIGNAL (0x9e) /* signal low */ +#define CX24116_REG_SSTATUS (0x9d) /* signal high / status */ +#define CX24116_REG_QUALITY8 (0xa3) +#define CX24116_REG_QSTATUS (0xbc) +#define CX24116_REG_QUALITY0 (0xd5) +#define CX24116_REG_BER0 (0xc9) +#define CX24116_REG_BER8 (0xc8) +#define CX24116_REG_BER16 (0xc7) +#define CX24116_REG_BER24 (0xc6) +#define CX24116_REG_UCB0 (0xcb) +#define CX24116_REG_UCB8 (0xca) +#define CX24116_REG_CLKDIV (0xf3) +#define CX24116_REG_RATEDIV (0xf9) + +/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */ +#define CX24116_REG_FECSTATUS (0x9c) + +/* FECSTATUS bits */ +/* mask to determine configured fec (not tuned) or actual fec (tuned) */ +#define CX24116_FEC_FECMASK (0x1f) + +/* Select DVB-S demodulator, else DVB-S2 */ +#define CX24116_FEC_DVBS (0x20) +#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */ + +/* Pilot mode requested when tuning else always reset when tuned */ +#define CX24116_FEC_PILOT (0x80) + +/* arg buffer size */ +#define CX24116_ARGLEN (0x1e) + +/* rolloff */ +#define CX24116_ROLLOFF_020 (0x00) +#define CX24116_ROLLOFF_025 (0x01) +#define CX24116_ROLLOFF_035 (0x02) + +/* pilot bit */ +#define CX24116_PILOT_OFF (0x00) +#define CX24116_PILOT_ON (0x40) + +/* signal status */ +#define CX24116_HAS_SIGNAL (0x01) +#define CX24116_HAS_CARRIER (0x02) +#define CX24116_HAS_VITERBI (0x04) +#define CX24116_HAS_SYNCLOCK (0x08) +#define CX24116_HAS_UNKNOWN1 (0x10) +#define CX24116_HAS_UNKNOWN2 (0x20) +#define CX24116_STATUS_MASK (0x0f) +#define CX24116_SIGNAL_MASK (0xc0) + +#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */ +#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */ +#define CX24116_DISEQC_MESGCACHE (2) /* message cached */ + +/* arg offset for DiSEqC */ +#define CX24116_DISEQC_BURST (1) +#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */ +#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */ +#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */ +#define CX24116_DISEQC_MSGLEN (5) +#define CX24116_DISEQC_MSGOFS (6) + +/* DiSEqC burst */ +#define CX24116_DISEQC_MINI_A (0) +#define CX24116_DISEQC_MINI_B (1) + +/* DiSEqC tone burst */ +static int toneburst = 1; +module_param(toneburst, int, 0644); +MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\ + "2=MESSAGE CACHE (default:1)"); + +/* SNR measurements */ +static int esno_snr; +module_param(esno_snr, int, 0644); +MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\ + "1=ESNO(db * 10) (default:0)"); + +enum cmds { + CMD_SET_VCO = 0x10, + CMD_TUNEREQUEST = 0x11, + CMD_MPEGCONFIG = 0x13, + CMD_TUNERINIT = 0x14, + CMD_BANDWIDTH = 0x15, + CMD_GETAGC = 0x19, + CMD_LNBCONFIG = 0x20, + CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */ + CMD_LNBDCLEVEL = 0x22, + CMD_SET_TONE = 0x23, + CMD_UPDFWVERS = 0x35, + CMD_TUNERSLEEP = 0x36, + CMD_AGCCONTROL = 0x3b, /* Unknown */ +}; + +/* The Demod/Tuner can't easily provide these, we cache them */ +struct cx24116_tuning { + u32 frequency; + u32 symbol_rate; + fe_spectral_inversion_t inversion; + fe_code_rate_t fec; + + fe_delivery_system_t delsys; + fe_modulation_t modulation; + fe_pilot_t pilot; + fe_rolloff_t rolloff; + + /* Demod values */ + u8 fec_val; + u8 fec_mask; + u8 inversion_val; + u8 pilot_val; + u8 rolloff_val; +}; + +/* Basic commands that are sent to the firmware */ +struct cx24116_cmd { + u8 len; + u8 args[CX24116_ARGLEN]; +}; + +struct cx24116_state { + struct i2c_adapter *i2c; + const struct cx24116_config *config; + + struct dvb_frontend frontend; + + struct cx24116_tuning dcur; + struct cx24116_tuning dnxt; + + u8 skip_fw_load; + u8 burst; + struct cx24116_cmd dsec_cmd; +}; + +static int cx24116_writereg(struct cx24116_state *state, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 2 }; + int err; + + if (debug > 1) + printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n", + __func__, reg, data); + + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," + " value == 0x%02x)\n", __func__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +/* Bulk byte writes to a single I2C address, for 32k firmware load */ +static int cx24116_writeregN(struct cx24116_state *state, int reg, + const u8 *data, u16 len) +{ + int ret = -EREMOTEIO; + struct i2c_msg msg; + u8 *buf; + + buf = kmalloc(len + 1, GFP_KERNEL); + if (buf == NULL) { + printk("Unable to kmalloc\n"); + ret = -ENOMEM; + goto error; + } + + *(buf) = reg; + memcpy(buf + 1, data, len); + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.buf = buf; + msg.len = len + 1; + + if (debug > 1) + printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n", + __func__, reg, len); + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) { + printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n", + __func__, ret, reg); + ret = -EREMOTEIO; + } + +error: + kfree(buf); + + return ret; +} + +static int cx24116_readreg(struct cx24116_state *state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 1 } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk(KERN_ERR "%s: reg=0x%x (error=%d)\n", + __func__, reg, ret); + return ret; + } + + if (debug > 1) + printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n", + reg, b1[0]); + + return b1[0]; +} + +static int cx24116_set_inversion(struct cx24116_state *state, + fe_spectral_inversion_t inversion) +{ + dprintk("%s(%d)\n", __func__, inversion); + + switch (inversion) { + case INVERSION_OFF: + state->dnxt.inversion_val = 0x00; + break; + case INVERSION_ON: + state->dnxt.inversion_val = 0x04; + break; + case INVERSION_AUTO: + state->dnxt.inversion_val = 0x0C; + break; + default: + return -EINVAL; + } + + state->dnxt.inversion = inversion; + + return 0; +} + +/* + * modfec (modulation and FEC) + * =========================== + * + * MOD FEC mask/val standard + * ---- -------- ----------- -------- + * QPSK FEC_1_2 0x02 0x02+X DVB-S + * QPSK FEC_2_3 0x04 0x02+X DVB-S + * QPSK FEC_3_4 0x08 0x02+X DVB-S + * QPSK FEC_4_5 0x10 0x02+X DVB-S (?) + * QPSK FEC_5_6 0x20 0x02+X DVB-S + * QPSK FEC_6_7 0x40 0x02+X DVB-S + * QPSK FEC_7_8 0x80 0x02+X DVB-S + * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?) + * QPSK AUTO 0xff 0x02+X DVB-S + * + * For DVB-S high byte probably represents FEC + * and low byte selects the modulator. The high + * byte is search range mask. Bit 5 may turn + * on DVB-S and remaining bits represent some + * kind of calibration (how/what i do not know). + * + * Eg.(2/3) szap "Zone Horror" + * + * mask/val = 0x04, 0x20 + * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK + * + * mask/val = 0x04, 0x30 + * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK + * + * After tuning FECSTATUS contains actual FEC + * in use numbered 1 through to 8 for 1/2 .. 2/3 etc + * + * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only) + * + * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2 + * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2 + * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2 + * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2 + * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2 + * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2 + * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2 + * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2 + * + * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2 + * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2 + * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2 + * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2 + * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2 + * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2 + * + * For DVB-S2 low bytes selects both modulator + * and FEC. High byte is meaningless here. To + * set pilot, bit 6 (0x40) is set. When inspecting + * FECSTATUS bit 7 (0x80) represents the pilot + * selection whilst not tuned. When tuned, actual FEC + * in use is found in FECSTATUS as per above. Pilot + * value is reset. + */ + +/* A table of modulation, fec and configuration bytes for the demod. + * Not all S2 mmodulation schemes are support and not all rates with + * a scheme are support. Especially, no auto detect when in S2 mode. + */ +static struct cx24116_modfec { + fe_delivery_system_t delivery_system; + fe_modulation_t modulation; + fe_code_rate_t fec; + u8 mask; /* In DVBS mode this is used to autodetect */ + u8 val; /* Passed to the firmware to indicate mode selection */ +} CX24116_MODFEC_MODES[] = { + /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ + + /*mod fec mask val */ + { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 }, + { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ + { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ + { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ + { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ + { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ + { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ + { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ + { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ + { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 }, + /* NBC-QPSK */ + { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 }, + { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 }, + { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 }, + { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 }, + { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 }, + { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 }, + { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a }, + { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b }, + /* 8PSK */ + { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c }, + { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d }, + { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e }, + { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f }, + { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 }, + { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 }, + /* + * `val' can be found in the FECSTATUS register when tuning. + * FECSTATUS will give the actual FEC in use if tuning was successful. + */ +}; + +static int cx24116_lookup_fecmod(struct cx24116_state *state, + fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f) +{ + int i, ret = -EOPNOTSUPP; + + dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f); + + for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) { + if ((d == CX24116_MODFEC_MODES[i].delivery_system) && + (m == CX24116_MODFEC_MODES[i].modulation) && + (f == CX24116_MODFEC_MODES[i].fec)) { + ret = i; + break; + } + } + + return ret; +} + +static int cx24116_set_fec(struct cx24116_state *state, + fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec) +{ + int ret = 0; + + dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec); + + ret = cx24116_lookup_fecmod(state, delsys, mod, fec); + + if (ret < 0) + return ret; + + state->dnxt.fec = fec; + state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val; + state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask; + dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__, + state->dnxt.fec_mask, state->dnxt.fec_val); + + return 0; +} + +static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate) +{ + dprintk("%s(%d)\n", __func__, rate); + + /* check if symbol rate is within limits */ + if ((rate > state->frontend.ops.info.symbol_rate_max) || + (rate < state->frontend.ops.info.symbol_rate_min)) { + dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate); + return -EOPNOTSUPP; + } + + state->dnxt.symbol_rate = rate; + dprintk("%s() symbol_rate = %d\n", __func__, rate); + + return 0; +} + +static int cx24116_load_firmware(struct dvb_frontend *fe, + const struct firmware *fw); + +static int cx24116_firmware_ondemand(struct dvb_frontend *fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + const struct firmware *fw; + int ret = 0; + + dprintk("%s()\n", __func__); + + if (cx24116_readreg(state, 0x20) > 0) { + + if (state->skip_fw_load) + return 0; + + /* Load firmware */ + /* request the firmware, this will block until loaded */ + printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", + __func__, CX24116_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, + state->i2c->dev.parent); + printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", + __func__); + if (ret) { + printk(KERN_ERR "%s: No firmware uploaded " + "(timeout or file not found?)\n", __func__); + return ret; + } + + /* Make sure we don't recurse back through here + * during loading */ + state->skip_fw_load = 1; + + ret = cx24116_load_firmware(fe, fw); + if (ret) + printk(KERN_ERR "%s: Writing firmware to device failed\n", + __func__); + + release_firmware(fw); + + printk(KERN_INFO "%s: Firmware upload %s\n", __func__, + ret == 0 ? "complete" : "failed"); + + /* Ensure firmware is always loaded if required */ + state->skip_fw_load = 0; + } + + return ret; +} + +/* Take a basic firmware command structure, format it + * and forward it for processing + */ +static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd) +{ + struct cx24116_state *state = fe->demodulator_priv; + int i, ret; + + dprintk("%s()\n", __func__); + + /* Load the firmware if required */ + ret = cx24116_firmware_ondemand(fe); + if (ret != 0) { + printk(KERN_ERR "%s(): Unable initialise the firmware\n", + __func__); + return ret; + } + + /* Write the command */ + for (i = 0; i < cmd->len ; i++) { + dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]); + cx24116_writereg(state, i, cmd->args[i]); + } + + /* Start execution and wait for cmd to terminate */ + cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01); + while (cx24116_readreg(state, CX24116_REG_EXECUTE)) { + msleep(10); + if (i++ > 64) { + /* Avoid looping forever if the firmware does + not respond */ + printk(KERN_WARNING "%s() Firmware not responding\n", + __func__); + return -EREMOTEIO; + } + } + return 0; +} + +static int cx24116_load_firmware(struct dvb_frontend *fe, + const struct firmware *fw) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int i, ret, len, max, remaining; + unsigned char vers[4]; + + dprintk("%s\n", __func__); + dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n", + fw->size, + fw->data[0], + fw->data[1], + fw->data[fw->size-2], + fw->data[fw->size-1]); + + /* Toggle 88x SRST pin to reset demod */ + if (state->config->reset_device) + state->config->reset_device(fe); + + /* Begin the firmware load process */ + /* Prepare the demod, load the firmware, cleanup after load */ + + /* Init PLL */ + cx24116_writereg(state, 0xE5, 0x00); + cx24116_writereg(state, 0xF1, 0x08); + cx24116_writereg(state, 0xF2, 0x13); + + /* Start PLL */ + cx24116_writereg(state, 0xe0, 0x03); + cx24116_writereg(state, 0xe0, 0x00); + + /* Unknown */ + cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); + cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); + + /* Unknown */ + cx24116_writereg(state, 0xF0, 0x03); + cx24116_writereg(state, 0xF4, 0x81); + cx24116_writereg(state, 0xF5, 0x00); + cx24116_writereg(state, 0xF6, 0x00); + + /* Split firmware to the max I2C write len and write. + * Writes whole firmware as one write when i2c_wr_max is set to 0. */ + if (state->config->i2c_wr_max) + max = state->config->i2c_wr_max; + else + max = INT_MAX; /* enough for 32k firmware */ + + for (remaining = fw->size; remaining > 0; remaining -= max - 1) { + len = remaining; + if (len > max - 1) + len = max - 1; + + cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining], + len); + } + + cx24116_writereg(state, 0xF4, 0x10); + cx24116_writereg(state, 0xF0, 0x00); + cx24116_writereg(state, 0xF8, 0x06); + + /* Firmware CMD 10: VCO config */ + cmd.args[0x00] = CMD_SET_VCO; + cmd.args[0x01] = 0x05; + cmd.args[0x02] = 0xdc; + cmd.args[0x03] = 0xda; + cmd.args[0x04] = 0xae; + cmd.args[0x05] = 0xaa; + cmd.args[0x06] = 0x04; + cmd.args[0x07] = 0x9d; + cmd.args[0x08] = 0xfc; + cmd.args[0x09] = 0x06; + cmd.len = 0x0a; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00); + + /* Firmware CMD 14: Tuner config */ + cmd.args[0x00] = CMD_TUNERINIT; + cmd.args[0x01] = 0x00; + cmd.args[0x02] = 0x00; + cmd.len = 0x03; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + cx24116_writereg(state, 0xe5, 0x00); + + /* Firmware CMD 13: MPEG config */ + cmd.args[0x00] = CMD_MPEGCONFIG; + cmd.args[0x01] = 0x01; + cmd.args[0x02] = 0x75; + cmd.args[0x03] = 0x00; + if (state->config->mpg_clk_pos_pol) + cmd.args[0x04] = state->config->mpg_clk_pos_pol; + else + cmd.args[0x04] = 0x02; + cmd.args[0x05] = 0x00; + cmd.len = 0x06; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + /* Firmware CMD 35: Get firmware version */ + cmd.args[0x00] = CMD_UPDFWVERS; + cmd.len = 0x02; + for (i = 0; i < 4; i++) { + cmd.args[0x01] = i; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX); + } + printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__, + vers[0], vers[1], vers[2], vers[3]); + + return 0; +} + +static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct cx24116_state *state = fe->demodulator_priv; + + int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) & + CX24116_STATUS_MASK; + + dprintk("%s: status = 0x%02x\n", __func__, lock); + + *status = 0; + + if (lock & CX24116_HAS_SIGNAL) + *status |= FE_HAS_SIGNAL; + if (lock & CX24116_HAS_CARRIER) + *status |= FE_HAS_CARRIER; + if (lock & CX24116_HAS_VITERBI) + *status |= FE_HAS_VITERBI; + if (lock & CX24116_HAS_SYNCLOCK) + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + + return 0; +} + +static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct cx24116_state *state = fe->demodulator_priv; + + dprintk("%s()\n", __func__); + + *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) | + (cx24116_readreg(state, CX24116_REG_BER16) << 16) | + (cx24116_readreg(state, CX24116_REG_BER8) << 8) | + cx24116_readreg(state, CX24116_REG_BER0); + + return 0; +} + +/* TODO Determine function and scale appropriately */ +static int cx24116_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int ret; + u16 sig_reading; + + dprintk("%s()\n", __func__); + + /* Firmware CMD 19: Get AGC */ + cmd.args[0x00] = CMD_GETAGC; + cmd.len = 0x01; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + sig_reading = + (cx24116_readreg(state, + CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) | + (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6); + *signal_strength = 0 - sig_reading; + + dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", + __func__, sig_reading, *signal_strength); + + return 0; +} + +/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ +static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr) +{ + struct cx24116_state *state = fe->demodulator_priv; + u8 snr_reading; + static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ + 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667, + 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667, + 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667, + 0x18000 }; + + dprintk("%s()\n", __func__); + + snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); + + if (snr_reading >= 0xa0 /* 100% */) + *snr = 0xffff; + else + *snr = snr_tab[(snr_reading & 0xf0) >> 4] + + (snr_tab[(snr_reading & 0x0f)] >> 4); + + dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, + snr_reading, *snr); + + return 0; +} + +/* The reelbox patches show the value in the registers represents + * ESNO, from 0->30db (values 0->300). We provide this value by + * default. + */ +static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr) +{ + struct cx24116_state *state = fe->demodulator_priv; + + dprintk("%s()\n", __func__); + + *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 | + cx24116_readreg(state, CX24116_REG_QUALITY0); + + dprintk("%s: raw 0x%04x\n", __func__, *snr); + + return 0; +} + +static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + if (esno_snr == 1) + return cx24116_read_snr_esno(fe, snr); + else + return cx24116_read_snr_pct(fe, snr); +} + +static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct cx24116_state *state = fe->demodulator_priv; + + dprintk("%s()\n", __func__); + + *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) | + cx24116_readreg(state, CX24116_REG_UCB0); + + return 0; +} + +/* Overwrite the current tuning params, we are about to tune */ +static void cx24116_clone_params(struct dvb_frontend *fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur)); +} + +/* Wait for LNB */ +static int cx24116_wait_for_lnb(struct dvb_frontend *fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + int i; + + dprintk("%s() qstatus = 0x%02x\n", __func__, + cx24116_readreg(state, CX24116_REG_QSTATUS)); + + /* Wait for up to 300 ms */ + for (i = 0; i < 30 ; i++) { + if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20) + return 0; + msleep(10); + } + + dprintk("%s(): LNB not ready\n", __func__); + + return -ETIMEDOUT; /* -EBUSY ? */ +} + +static int cx24116_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx24116_cmd cmd; + int ret; + + dprintk("%s: %s\n", __func__, + voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : + voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); + + /* Wait for LNB ready */ + ret = cx24116_wait_for_lnb(fe); + if (ret != 0) + return ret; + + /* Wait for voltage/min repeat delay */ + msleep(100); + + cmd.args[0x00] = CMD_LNBDCLEVEL; + cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00); + cmd.len = 0x02; + + /* Min delay time before DiSEqC send */ + msleep(15); + + return cx24116_cmd_execute(fe, &cmd); +} + +static int cx24116_set_tone(struct dvb_frontend *fe, + fe_sec_tone_mode_t tone) +{ + struct cx24116_cmd cmd; + int ret; + + dprintk("%s(%d)\n", __func__, tone); + if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { + printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone); + return -EINVAL; + } + + /* Wait for LNB ready */ + ret = cx24116_wait_for_lnb(fe); + if (ret != 0) + return ret; + + /* Min delay time after DiSEqC send */ + msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ + + /* Now we set the tone */ + cmd.args[0x00] = CMD_SET_TONE; + cmd.args[0x01] = 0x00; + cmd.args[0x02] = 0x00; + + switch (tone) { + case SEC_TONE_ON: + dprintk("%s: setting tone on\n", __func__); + cmd.args[0x03] = 0x01; + break; + case SEC_TONE_OFF: + dprintk("%s: setting tone off\n", __func__); + cmd.args[0x03] = 0x00; + break; + } + cmd.len = 0x04; + + /* Min delay time before DiSEqC send */ + msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ + + return cx24116_cmd_execute(fe, &cmd); +} + +/* Initialise DiSEqC */ +static int cx24116_diseqc_init(struct dvb_frontend *fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int ret; + + /* Firmware CMD 20: LNB/DiSEqC config */ + cmd.args[0x00] = CMD_LNBCONFIG; + cmd.args[0x01] = 0x00; + cmd.args[0x02] = 0x10; + cmd.args[0x03] = 0x00; + cmd.args[0x04] = 0x8f; + cmd.args[0x05] = 0x28; + cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01; + cmd.args[0x07] = 0x01; + cmd.len = 0x08; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + /* Prepare a DiSEqC command */ + state->dsec_cmd.args[0x00] = CMD_LNBSEND; + + /* DiSEqC burst */ + state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; + + /* Unknown */ + state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; + state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; + /* Continuation flag? */ + state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; + + /* DiSEqC message length */ + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; + + /* Command length */ + state->dsec_cmd.len = CX24116_DISEQC_MSGOFS; + + return 0; +} + +/* Send DiSEqC message with derived burst (hack) || previous burst */ +static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *d) +{ + struct cx24116_state *state = fe->demodulator_priv; + int i, ret; + + /* Dump DiSEqC message */ + if (debug) { + printk(KERN_INFO "cx24116: %s(", __func__); + for (i = 0 ; i < d->msg_len ;) { + printk(KERN_INFO "0x%02x", d->msg[i]); + if (++i < d->msg_len) + printk(KERN_INFO ", "); + } + printk(") toneburst=%d\n", toneburst); + } + + /* Validate length */ + if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) + return -EINVAL; + + /* DiSEqC message */ + for (i = 0; i < d->msg_len; i++) + state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; + + /* DiSEqC message length */ + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; + + /* Command length */ + state->dsec_cmd.len = CX24116_DISEQC_MSGOFS + + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN]; + + /* DiSEqC toneburst */ + if (toneburst == CX24116_DISEQC_MESGCACHE) + /* Message is cached */ + return 0; + + else if (toneburst == CX24116_DISEQC_TONEOFF) + /* Message is sent without burst */ + state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0; + + else if (toneburst == CX24116_DISEQC_TONECACHE) { + /* + * Message is sent with derived else cached burst + * + * WRITE PORT GROUP COMMAND 38 + * + * 0/A/A: E0 10 38 F0..F3 + * 1/B/B: E0 10 38 F4..F7 + * 2/C/A: E0 10 38 F8..FB + * 3/D/B: E0 10 38 FC..FF + * + * databyte[3]= 8421:8421 + * ABCD:WXYZ + * CLR :SET + * + * WX= PORT SELECT 0..3 (X=TONEBURST) + * Y = VOLTAGE (0=13V, 1=18V) + * Z = BAND (0=LOW, 1=HIGH(22K)) + */ + if (d->msg_len >= 4 && d->msg[2] == 0x38) + state->dsec_cmd.args[CX24116_DISEQC_BURST] = + ((d->msg[3] & 4) >> 2); + if (debug) + dprintk("%s burst=%d\n", __func__, + state->dsec_cmd.args[CX24116_DISEQC_BURST]); + } + + /* Wait for LNB ready */ + ret = cx24116_wait_for_lnb(fe); + if (ret != 0) + return ret; + + /* Wait for voltage/min repeat delay */ + msleep(100); + + /* Command */ + ret = cx24116_cmd_execute(fe, &state->dsec_cmd); + if (ret != 0) + return ret; + /* + * Wait for send + * + * Eutelsat spec: + * >15ms delay + (XXX determine if FW does this, see set_tone) + * 13.5ms per byte + + * >15ms delay + + * 12.5ms burst + + * >15ms delay (XXX determine if FW does this, see set_tone) + */ + msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60)); + + return 0; +} + +/* Send DiSEqC burst */ +static int cx24116_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t burst) +{ + struct cx24116_state *state = fe->demodulator_priv; + int ret; + + dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst); + + /* DiSEqC burst */ + if (burst == SEC_MINI_A) + state->dsec_cmd.args[CX24116_DISEQC_BURST] = + CX24116_DISEQC_MINI_A; + else if (burst == SEC_MINI_B) + state->dsec_cmd.args[CX24116_DISEQC_BURST] = + CX24116_DISEQC_MINI_B; + else + return -EINVAL; + + /* DiSEqC toneburst */ + if (toneburst != CX24116_DISEQC_MESGCACHE) + /* Burst is cached */ + return 0; + + /* Burst is to be sent with cached message */ + + /* Wait for LNB ready */ + ret = cx24116_wait_for_lnb(fe); + if (ret != 0) + return ret; + + /* Wait for voltage/min repeat delay */ + msleep(100); + + /* Command */ + ret = cx24116_cmd_execute(fe, &state->dsec_cmd); + if (ret != 0) + return ret; + + /* + * Wait for send + * + * Eutelsat spec: + * >15ms delay + (XXX determine if FW does this, see set_tone) + * 13.5ms per byte + + * >15ms delay + + * 12.5ms burst + + * >15ms delay (XXX determine if FW does this, see set_tone) + */ + msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60); + + return 0; +} + +static void cx24116_release(struct dvb_frontend *fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + dprintk("%s\n", __func__); + kfree(state); +} + +static struct dvb_frontend_ops cx24116_ops; + +struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, + struct i2c_adapter *i2c) +{ + struct cx24116_state *state = NULL; + int ret; + + dprintk("%s\n", __func__); + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL); + if (state == NULL) + goto error1; + + state->config = config; + state->i2c = i2c; + + /* check if the demod is present */ + ret = (cx24116_readreg(state, 0xFF) << 8) | + cx24116_readreg(state, 0xFE); + if (ret != 0x0501) { + printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n"); + goto error2; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &cx24116_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error2: kfree(state); +error1: return NULL; +} +EXPORT_SYMBOL(cx24116_attach); + +/* + * Initialise or wake up device + * + * Power config will reset and load initial firmware if required + */ +static int cx24116_initfe(struct dvb_frontend *fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int ret; + + dprintk("%s()\n", __func__); + + /* Power on */ + cx24116_writereg(state, 0xe0, 0); + cx24116_writereg(state, 0xe1, 0); + cx24116_writereg(state, 0xea, 0); + + /* Firmware CMD 36: Power config */ + cmd.args[0x00] = CMD_TUNERSLEEP; + cmd.args[0x01] = 0; + cmd.len = 0x02; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + ret = cx24116_diseqc_init(fe); + if (ret != 0) + return ret; + + /* HVR-4000 needs this */ + return cx24116_set_voltage(fe, SEC_VOLTAGE_13); +} + +/* + * Put device to sleep + */ +static int cx24116_sleep(struct dvb_frontend *fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int ret; + + dprintk("%s()\n", __func__); + + /* Firmware CMD 36: Power config */ + cmd.args[0x00] = CMD_TUNERSLEEP; + cmd.args[0x01] = 1; + cmd.len = 0x02; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + /* Power off (Shutdown clocks) */ + cx24116_writereg(state, 0xea, 0xff); + cx24116_writereg(state, 0xe1, 1); + cx24116_writereg(state, 0xe0, 1); + + return 0; +} + +static int cx24116_set_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int cx24116_get_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +/* dvb-core told us to tune, the tv property cache will be complete, + * it's safe for is to pull values and use them for tuning purposes. + */ +static int cx24116_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct cx24116_cmd cmd; + fe_status_t tunerstat; + int i, status, ret, retune = 1; + + dprintk("%s()\n", __func__); + + switch (c->delivery_system) { + case SYS_DVBS: + dprintk("%s: DVB-S delivery system selected\n", __func__); + + /* Only QPSK is supported for DVB-S */ + if (c->modulation != QPSK) { + dprintk("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + + /* Pilot doesn't exist in DVB-S, turn bit off */ + state->dnxt.pilot_val = CX24116_PILOT_OFF; + + /* DVB-S only supports 0.35 */ + if (c->rolloff != ROLLOFF_35) { + dprintk("%s: unsupported rolloff selected (%d)\n", + __func__, c->rolloff); + return -EOPNOTSUPP; + } + state->dnxt.rolloff_val = CX24116_ROLLOFF_035; + break; + + case SYS_DVBS2: + dprintk("%s: DVB-S2 delivery system selected\n", __func__); + + /* + * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, + * but not hardware auto detection + */ + if (c->modulation != PSK_8 && c->modulation != QPSK) { + dprintk("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + + switch (c->pilot) { + case PILOT_AUTO: /* Not supported but emulated */ + state->dnxt.pilot_val = (c->modulation == QPSK) + ? CX24116_PILOT_OFF : CX24116_PILOT_ON; + retune++; + break; + case PILOT_OFF: + state->dnxt.pilot_val = CX24116_PILOT_OFF; + break; + case PILOT_ON: + state->dnxt.pilot_val = CX24116_PILOT_ON; + break; + default: + dprintk("%s: unsupported pilot mode selected (%d)\n", + __func__, c->pilot); + return -EOPNOTSUPP; + } + + switch (c->rolloff) { + case ROLLOFF_20: + state->dnxt.rolloff_val = CX24116_ROLLOFF_020; + break; + case ROLLOFF_25: + state->dnxt.rolloff_val = CX24116_ROLLOFF_025; + break; + case ROLLOFF_35: + state->dnxt.rolloff_val = CX24116_ROLLOFF_035; + break; + case ROLLOFF_AUTO: /* Rolloff must be explicit */ + default: + dprintk("%s: unsupported rolloff selected (%d)\n", + __func__, c->rolloff); + return -EOPNOTSUPP; + } + break; + + default: + dprintk("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; + } + state->dnxt.delsys = c->delivery_system; + state->dnxt.modulation = c->modulation; + state->dnxt.frequency = c->frequency; + state->dnxt.pilot = c->pilot; + state->dnxt.rolloff = c->rolloff; + + ret = cx24116_set_inversion(state, c->inversion); + if (ret != 0) + return ret; + + /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ + ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner); + if (ret != 0) + return ret; + + ret = cx24116_set_symbolrate(state, c->symbol_rate); + if (ret != 0) + return ret; + + /* discard the 'current' tuning parameters and prepare to tune */ + cx24116_clone_params(fe); + + dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys); + dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation); + dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); + dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__, + state->dcur.pilot, state->dcur.pilot_val); + dprintk("%s: retune = %d\n", __func__, retune); + dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__, + state->dcur.rolloff, state->dcur.rolloff_val); + dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); + dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, + state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); + dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__, + state->dcur.inversion, state->dcur.inversion_val); + + /* This is also done in advise/acquire on HVR4000 but not on LITE */ + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + /* Set/Reset B/W */ + cmd.args[0x00] = CMD_BANDWIDTH; + cmd.args[0x01] = 0x01; + cmd.len = 0x02; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + /* Prepare a tune request */ + cmd.args[0x00] = CMD_TUNEREQUEST; + + /* Frequency */ + cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16; + cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8; + cmd.args[0x03] = (state->dcur.frequency & 0x0000ff); + + /* Symbol Rate */ + cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8; + cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff); + + /* Automatic Inversion */ + cmd.args[0x06] = state->dcur.inversion_val; + + /* Modulation / FEC / Pilot */ + cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val; + + cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; + cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; + cmd.args[0x0a] = 0x00; + cmd.args[0x0b] = 0x00; + cmd.args[0x0c] = state->dcur.rolloff_val; + cmd.args[0x0d] = state->dcur.fec_mask; + + if (state->dcur.symbol_rate > 30000000) { + cmd.args[0x0e] = 0x04; + cmd.args[0x0f] = 0x00; + cmd.args[0x10] = 0x01; + cmd.args[0x11] = 0x77; + cmd.args[0x12] = 0x36; + cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44); + cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01); + } else { + cmd.args[0x0e] = 0x06; + cmd.args[0x0f] = 0x00; + cmd.args[0x10] = 0x00; + cmd.args[0x11] = 0xFA; + cmd.args[0x12] = 0x24; + cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); + cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); + } + + cmd.len = 0x13; + + /* We need to support pilot and non-pilot tuning in the + * driver automatically. This is a workaround for because + * the demod does not support autodetect. + */ + do { + /* Reset status register */ + status = cx24116_readreg(state, CX24116_REG_SSTATUS) + & CX24116_SIGNAL_MASK; + cx24116_writereg(state, CX24116_REG_SSTATUS, status); + + /* Tune */ + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + break; + + /* + * Wait for up to 500 ms before retrying + * + * If we are able to tune then generally it occurs within 100ms. + * If it takes longer, try a different toneburst setting. + */ + for (i = 0; i < 50 ; i++) { + cx24116_read_status(fe, &tunerstat); + status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC); + if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) { + dprintk("%s: Tuned\n", __func__); + goto tuned; + } + msleep(10); + } + + dprintk("%s: Not tuned\n", __func__); + + /* Toggle pilot bit when in auto-pilot */ + if (state->dcur.pilot == PILOT_AUTO) + cmd.args[0x07] ^= CX24116_PILOT_ON; + } while (--retune); + +tuned: /* Set/Reset B/W */ + cmd.args[0x00] = CMD_BANDWIDTH; + cmd.args[0x01] = 0x00; + cmd.len = 0x02; + return cx24116_cmd_execute(fe, &cmd); +} + +static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, + unsigned int mode_flags, unsigned int *delay, fe_status_t *status) +{ + *delay = HZ / 5; + if (params) { + int ret = cx24116_set_frontend(fe, params); + if (ret) + return ret; + } + return cx24116_read_status(fe, status); +} + +static int cx24116_get_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +static struct dvb_frontend_ops cx24116_ops = { + + .info = { + .name = "Conexant CX24116/CX24118", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1011, /* kHz for QPSK frontends */ + .frequency_tolerance = 5000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_2G_MODULATION | + FE_CAN_QPSK | FE_CAN_RECOVER + }, + + .release = cx24116_release, + + .init = cx24116_initfe, + .sleep = cx24116_sleep, + .read_status = cx24116_read_status, + .read_ber = cx24116_read_ber, + .read_signal_strength = cx24116_read_signal_strength, + .read_snr = cx24116_read_snr, + .read_ucblocks = cx24116_read_ucblocks, + .set_tone = cx24116_set_tone, + .set_voltage = cx24116_set_voltage, + .diseqc_send_master_cmd = cx24116_send_diseqc_msg, + .diseqc_send_burst = cx24116_diseqc_send_burst, + .get_frontend_algo = cx24116_get_algo, + .tune = cx24116_tune, + + .set_property = cx24116_set_property, + .get_property = cx24116_get_property, + .set_frontend = cx24116_set_frontend, +}; + +MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24116.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24116.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24116.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24116.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver + + Copyright (C) 2006 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef CX24116_H +#define CX24116_H + +#include + +struct cx24116_config { + /* the demodulator's i2c address */ + u8 demod_address; + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); + + /* Need to reset device during firmware loading */ + int (*reset_device)(struct dvb_frontend *fe); + + /* Need to set MPEG parameters */ + u8 mpg_clk_pos_pol:0x02; + + /* max bytes I2C provider can write at once */ + u16 i2c_wr_max; +}; + +#if defined(CONFIG_DVB_CX24116) || \ + (defined(CONFIG_DVB_CX24116_MODULE) && defined(MODULE)) +extern struct dvb_frontend *cx24116_attach( + const struct cx24116_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *cx24116_attach( + const struct cx24116_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* CX24116_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24123.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24123.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24123.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24123.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1167 @@ +/* + * Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver + * + * Copyright (C) 2005 Steven Toth + * + * Support for KWorld DVB-S 100 by Vadim Catana + * + * Support for CX24123/CX24113-NIM by Patrick Boettcher + * + * 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, or (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "cx24123.h" + +#define XTAL 10111000 + +static int force_band; +module_param(force_band, int, 0644); +MODULE_PARM_DESC(force_band, "Force a specific band select "\ + "(1-9, default:off)."); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + +#define info(args...) do { printk(KERN_INFO "CX24123: " args); } while (0) +#define err(args...) do { printk(KERN_ERR "CX24123: " args); } while (0) + +#define dprintk(args...) \ + do { \ + if (debug) { \ + printk(KERN_DEBUG "CX24123: %s: ", __func__); \ + printk(args); \ + } \ + } while (0) + +struct cx24123_state { + struct i2c_adapter *i2c; + const struct cx24123_config *config; + + struct dvb_frontend frontend; + + /* Some PLL specifics for tuning */ + u32 VCAarg; + u32 VGAarg; + u32 bandselectarg; + u32 pllarg; + u32 FILTune; + + struct i2c_adapter tuner_i2c_adapter; + + u8 demod_rev; + + /* The Demod/Tuner can't easily provide these, we cache them */ + u32 currentfreq; + u32 currentsymbolrate; +}; + +/* Various tuner defaults need to be established for a given symbol rate Sps */ +static struct cx24123_AGC_val { + u32 symbolrate_low; + u32 symbolrate_high; + u32 VCAprogdata; + u32 VGAprogdata; + u32 FILTune; +} cx24123_AGC_vals[] = +{ + { + .symbolrate_low = 1000000, + .symbolrate_high = 4999999, + /* the specs recommend other values for VGA offsets, + but tests show they are wrong */ + .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0, + .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x07, + .FILTune = 0x27f /* 0.41 V */ + }, + { + .symbolrate_low = 5000000, + .symbolrate_high = 14999999, + .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0, + .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x1f, + .FILTune = 0x317 /* 0.90 V */ + }, + { + .symbolrate_low = 15000000, + .symbolrate_high = 45000000, + .VGAprogdata = (1 << 19) | (0x100 << 9) | 0x180, + .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x3f, + .FILTune = 0x145 /* 2.70 V */ + }, +}; + +/* + * Various tuner defaults need to be established for a given frequency kHz. + * fixme: The bounds on the bands do not match the doc in real life. + * fixme: Some of them have been moved, other might need adjustment. + */ +static struct cx24123_bandselect_val { + u32 freq_low; + u32 freq_high; + u32 VCOdivider; + u32 progdata; +} cx24123_bandselect_vals[] = +{ + /* band 1 */ + { + .freq_low = 950000, + .freq_high = 1074999, + .VCOdivider = 4, + .progdata = (0 << 19) | (0 << 9) | 0x40, + }, + + /* band 2 */ + { + .freq_low = 1075000, + .freq_high = 1177999, + .VCOdivider = 4, + .progdata = (0 << 19) | (0 << 9) | 0x80, + }, + + /* band 3 */ + { + .freq_low = 1178000, + .freq_high = 1295999, + .VCOdivider = 2, + .progdata = (0 << 19) | (1 << 9) | 0x01, + }, + + /* band 4 */ + { + .freq_low = 1296000, + .freq_high = 1431999, + .VCOdivider = 2, + .progdata = (0 << 19) | (1 << 9) | 0x02, + }, + + /* band 5 */ + { + .freq_low = 1432000, + .freq_high = 1575999, + .VCOdivider = 2, + .progdata = (0 << 19) | (1 << 9) | 0x04, + }, + + /* band 6 */ + { + .freq_low = 1576000, + .freq_high = 1717999, + .VCOdivider = 2, + .progdata = (0 << 19) | (1 << 9) | 0x08, + }, + + /* band 7 */ + { + .freq_low = 1718000, + .freq_high = 1855999, + .VCOdivider = 2, + .progdata = (0 << 19) | (1 << 9) | 0x10, + }, + + /* band 8 */ + { + .freq_low = 1856000, + .freq_high = 2035999, + .VCOdivider = 2, + .progdata = (0 << 19) | (1 << 9) | 0x20, + }, + + /* band 9 */ + { + .freq_low = 2036000, + .freq_high = 2150000, + .VCOdivider = 2, + .progdata = (0 << 19) | (1 << 9) | 0x40, + }, +}; + +static struct { + u8 reg; + u8 data; +} cx24123_regdata[] = +{ + {0x00, 0x03}, /* Reset system */ + {0x00, 0x00}, /* Clear reset */ + {0x03, 0x07}, /* QPSK, DVB, Auto Acquisition (default) */ + {0x04, 0x10}, /* MPEG */ + {0x05, 0x04}, /* MPEG */ + {0x06, 0x31}, /* MPEG (default) */ + {0x0b, 0x00}, /* Freq search start point (default) */ + {0x0c, 0x00}, /* Demodulator sample gain (default) */ + {0x0d, 0x7f}, /* Force driver to shift until the maximum (+-10 MHz) */ + {0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */ + {0x0f, 0xfe}, /* FEC search mask (all supported codes) */ + {0x10, 0x01}, /* Default search inversion, no repeat (default) */ + {0x16, 0x00}, /* Enable reading of frequency */ + {0x17, 0x01}, /* Enable EsNO Ready Counter */ + {0x1c, 0x80}, /* Enable error counter */ + {0x20, 0x00}, /* Tuner burst clock rate = 500KHz */ + {0x21, 0x15}, /* Tuner burst mode, word length = 0x15 */ + {0x28, 0x00}, /* Enable FILTERV with positive pol., DiSEqC 2.x off */ + {0x29, 0x00}, /* DiSEqC LNB_DC off */ + {0x2a, 0xb0}, /* DiSEqC Parameters (default) */ + {0x2b, 0x73}, /* DiSEqC Tone Frequency (default) */ + {0x2c, 0x00}, /* DiSEqC Message (0x2c - 0x31) */ + {0x2d, 0x00}, + {0x2e, 0x00}, + {0x2f, 0x00}, + {0x30, 0x00}, + {0x31, 0x00}, + {0x32, 0x8c}, /* DiSEqC Parameters (default) */ + {0x33, 0x00}, /* Interrupts off (0x33 - 0x34) */ + {0x34, 0x00}, + {0x35, 0x03}, /* DiSEqC Tone Amplitude (default) */ + {0x36, 0x02}, /* DiSEqC Parameters (default) */ + {0x37, 0x3a}, /* DiSEqC Parameters (default) */ + {0x3a, 0x00}, /* Enable AGC accumulator (for signal strength) */ + {0x44, 0x00}, /* Constellation (default) */ + {0x45, 0x00}, /* Symbol count (default) */ + {0x46, 0x0d}, /* Symbol rate estimator on (default) */ + {0x56, 0xc1}, /* Error Counter = Viterbi BER */ + {0x57, 0xff}, /* Error Counter Window (default) */ + {0x5c, 0x20}, /* Acquisition AFC Expiration window (default is 0x10) */ + {0x67, 0x83}, /* Non-DCII symbol clock */ +}; + +static int cx24123_i2c_writereg(struct cx24123_state *state, + u8 i2c_addr, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2 + }; + int err; + + /* printk(KERN_DEBUG "wr(%02x): %02x %02x\n", i2c_addr, reg, data); */ + + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk("%s: writereg error(err == %i, reg == 0x%02x," + " data == 0x%02x)\n", __func__, err, reg, data); + return err; + } + + return 0; +} + +static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg) +{ + int ret; + u8 b = 0; + struct i2c_msg msg[] = { + { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 }, + { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &b, .len = 1 } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + err("%s: reg=0x%x (error=%d)\n", __func__, reg, ret); + return ret; + } + + /* printk(KERN_DEBUG "rd(%02x): %02x %02x\n", i2c_addr, reg, b); */ + + return b; +} + +#define cx24123_readreg(state, reg) \ + cx24123_i2c_readreg(state, state->config->demod_address, reg) +#define cx24123_writereg(state, reg, val) \ + cx24123_i2c_writereg(state, state->config->demod_address, reg, val) + +static int cx24123_set_inversion(struct cx24123_state *state, + fe_spectral_inversion_t inversion) +{ + u8 nom_reg = cx24123_readreg(state, 0x0e); + u8 auto_reg = cx24123_readreg(state, 0x10); + + switch (inversion) { + case INVERSION_OFF: + dprintk("inversion off\n"); + cx24123_writereg(state, 0x0e, nom_reg & ~0x80); + cx24123_writereg(state, 0x10, auto_reg | 0x80); + break; + case INVERSION_ON: + dprintk("inversion on\n"); + cx24123_writereg(state, 0x0e, nom_reg | 0x80); + cx24123_writereg(state, 0x10, auto_reg | 0x80); + break; + case INVERSION_AUTO: + dprintk("inversion auto\n"); + cx24123_writereg(state, 0x10, auto_reg & ~0x80); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cx24123_get_inversion(struct cx24123_state *state, + fe_spectral_inversion_t *inversion) +{ + u8 val; + + val = cx24123_readreg(state, 0x1b) >> 7; + + if (val == 0) { + dprintk("read inversion off\n"); + *inversion = INVERSION_OFF; + } else { + dprintk("read inversion on\n"); + *inversion = INVERSION_ON; + } + + return 0; +} + +static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec) +{ + u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07; + + if ((fec < FEC_NONE) || (fec > FEC_AUTO)) + fec = FEC_AUTO; + + /* Set the soft decision threshold */ + if (fec == FEC_1_2) + cx24123_writereg(state, 0x43, + cx24123_readreg(state, 0x43) | 0x01); + else + cx24123_writereg(state, 0x43, + cx24123_readreg(state, 0x43) & ~0x01); + + switch (fec) { + case FEC_1_2: + dprintk("set FEC to 1/2\n"); + cx24123_writereg(state, 0x0e, nom_reg | 0x01); + cx24123_writereg(state, 0x0f, 0x02); + break; + case FEC_2_3: + dprintk("set FEC to 2/3\n"); + cx24123_writereg(state, 0x0e, nom_reg | 0x02); + cx24123_writereg(state, 0x0f, 0x04); + break; + case FEC_3_4: + dprintk("set FEC to 3/4\n"); + cx24123_writereg(state, 0x0e, nom_reg | 0x03); + cx24123_writereg(state, 0x0f, 0x08); + break; + case FEC_4_5: + dprintk("set FEC to 4/5\n"); + cx24123_writereg(state, 0x0e, nom_reg | 0x04); + cx24123_writereg(state, 0x0f, 0x10); + break; + case FEC_5_6: + dprintk("set FEC to 5/6\n"); + cx24123_writereg(state, 0x0e, nom_reg | 0x05); + cx24123_writereg(state, 0x0f, 0x20); + break; + case FEC_6_7: + dprintk("set FEC to 6/7\n"); + cx24123_writereg(state, 0x0e, nom_reg | 0x06); + cx24123_writereg(state, 0x0f, 0x40); + break; + case FEC_7_8: + dprintk("set FEC to 7/8\n"); + cx24123_writereg(state, 0x0e, nom_reg | 0x07); + cx24123_writereg(state, 0x0f, 0x80); + break; + case FEC_AUTO: + dprintk("set FEC to auto\n"); + cx24123_writereg(state, 0x0f, 0xfe); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int cx24123_get_fec(struct cx24123_state *state, fe_code_rate_t *fec) +{ + int ret; + + ret = cx24123_readreg(state, 0x1b); + if (ret < 0) + return ret; + ret = ret & 0x07; + + switch (ret) { + case 1: + *fec = FEC_1_2; + break; + case 2: + *fec = FEC_2_3; + break; + case 3: + *fec = FEC_3_4; + break; + case 4: + *fec = FEC_4_5; + break; + case 5: + *fec = FEC_5_6; + break; + case 6: + *fec = FEC_6_7; + break; + case 7: + *fec = FEC_7_8; + break; + default: + /* this can happen when there's no lock */ + *fec = FEC_NONE; + } + + return 0; +} + +/* Approximation of closest integer of log2(a/b). It actually gives the + lowest integer i such that 2^i >= round(a/b) */ +static u32 cx24123_int_log2(u32 a, u32 b) +{ + u32 exp, nearest = 0; + u32 div = a / b; + if (a % b >= b / 2) + ++div; + if (div < (1 << 31)) { + for (exp = 1; div > exp; nearest++) + exp += exp; + } + return nearest; +} + +static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate) +{ + u32 tmp, sample_rate, ratio, sample_gain; + u8 pll_mult; + + /* check if symbol rate is within limits */ + if ((srate > state->frontend.ops.info.symbol_rate_max) || + (srate < state->frontend.ops.info.symbol_rate_min)) + return -EOPNOTSUPP; + + /* choose the sampling rate high enough for the required operation, + while optimizing the power consumed by the demodulator */ + if (srate < (XTAL*2)/2) + pll_mult = 2; + else if (srate < (XTAL*3)/2) + pll_mult = 3; + else if (srate < (XTAL*4)/2) + pll_mult = 4; + else if (srate < (XTAL*5)/2) + pll_mult = 5; + else if (srate < (XTAL*6)/2) + pll_mult = 6; + else if (srate < (XTAL*7)/2) + pll_mult = 7; + else if (srate < (XTAL*8)/2) + pll_mult = 8; + else + pll_mult = 9; + + + sample_rate = pll_mult * XTAL; + + /* + SYSSymbolRate[21:0] = (srate << 23) / sample_rate + + We have to use 32 bit unsigned arithmetic without precision loss. + The maximum srate is 45000000 or 0x02AEA540. This number has + only 6 clear bits on top, hence we can shift it left only 6 bits + at a time. Borrowed from cx24110.c + */ + + tmp = srate << 6; + ratio = tmp / sample_rate; + + tmp = (tmp % sample_rate) << 6; + ratio = (ratio << 6) + (tmp / sample_rate); + + tmp = (tmp % sample_rate) << 6; + ratio = (ratio << 6) + (tmp / sample_rate); + + tmp = (tmp % sample_rate) << 5; + ratio = (ratio << 5) + (tmp / sample_rate); + + + cx24123_writereg(state, 0x01, pll_mult * 6); + + cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f); + cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff); + cx24123_writereg(state, 0x0a, ratio & 0xff); + + /* also set the demodulator sample gain */ + sample_gain = cx24123_int_log2(sample_rate, srate); + tmp = cx24123_readreg(state, 0x0c) & ~0xe0; + cx24123_writereg(state, 0x0c, tmp | sample_gain << 5); + + dprintk("srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n", + srate, ratio, sample_rate, sample_gain); + + return 0; +} + +/* + * Based on the required frequency and symbolrate, the tuner AGC has + * to be configured and the correct band selected. + * Calculate those values. + */ +static int cx24123_pll_calculate(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + u32 ndiv = 0, adiv = 0, vco_div = 0; + int i = 0; + int pump = 2; + int band = 0; + int num_bands = ARRAY_SIZE(cx24123_bandselect_vals); + struct cx24123_bandselect_val *bsv = NULL; + struct cx24123_AGC_val *agcv = NULL; + + /* Defaults for low freq, low rate */ + state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; + state->VGAarg = cx24123_AGC_vals[0].VGAprogdata; + state->bandselectarg = cx24123_bandselect_vals[0].progdata; + vco_div = cx24123_bandselect_vals[0].VCOdivider; + + /* For the given symbol rate, determine the VCA, VGA and + * FILTUNE programming bits */ + for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) { + agcv = &cx24123_AGC_vals[i]; + if ((agcv->symbolrate_low <= p->u.qpsk.symbol_rate) && + (agcv->symbolrate_high >= p->u.qpsk.symbol_rate)) { + state->VCAarg = agcv->VCAprogdata; + state->VGAarg = agcv->VGAprogdata; + state->FILTune = agcv->FILTune; + } + } + + /* determine the band to use */ + if (force_band < 1 || force_band > num_bands) { + for (i = 0; i < num_bands; i++) { + bsv = &cx24123_bandselect_vals[i]; + if ((bsv->freq_low <= p->frequency) && + (bsv->freq_high >= p->frequency)) + band = i; + } + } else + band = force_band - 1; + + state->bandselectarg = cx24123_bandselect_vals[band].progdata; + vco_div = cx24123_bandselect_vals[band].VCOdivider; + + /* determine the charge pump current */ + if (p->frequency < (cx24123_bandselect_vals[band].freq_low + + cx24123_bandselect_vals[band].freq_high) / 2) + pump = 0x01; + else + pump = 0x02; + + /* Determine the N/A dividers for the requested lband freq (in kHz). */ + /* Note: the reference divider R=10, frequency is in KHz, + * XTAL is in Hz */ + ndiv = (((p->frequency * vco_div * 10) / + (2 * XTAL / 1000)) / 32) & 0x1ff; + adiv = (((p->frequency * vco_div * 10) / + (2 * XTAL / 1000)) % 32) & 0x1f; + + if (adiv == 0 && ndiv > 0) + ndiv--; + + /* control bits 11, refdiv 11, charge pump polarity 1, + * charge pump current, ndiv, adiv */ + state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | + (pump << 14) | (ndiv << 5) | adiv; + + return 0; +} + +/* + * Tuner data is 21 bits long, must be left-aligned in data. + * Tuner cx24109 is written through a dedicated 3wire interface + * on the demod chip. + */ +static int cx24123_pll_writereg(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p, u32 data) +{ + struct cx24123_state *state = fe->demodulator_priv; + unsigned long timeout; + + dprintk("pll writereg called, data=0x%08x\n", data); + + /* align the 21 bytes into to bit23 boundary */ + data = data << 3; + + /* Reset the demod pll word length to 0x15 bits */ + cx24123_writereg(state, 0x21, 0x15); + + /* write the msb 8 bits, wait for the send to be completed */ + timeout = jiffies + msecs_to_jiffies(40); + cx24123_writereg(state, 0x22, (data >> 16) & 0xff); + while ((cx24123_readreg(state, 0x20) & 0x40) == 0) { + if (time_after(jiffies, timeout)) { + err("%s: demodulator is not responding, "\ + "possibly hung, aborting.\n", __func__); + return -EREMOTEIO; + } + msleep(10); + } + + /* send another 8 bytes, wait for the send to be completed */ + timeout = jiffies + msecs_to_jiffies(40); + cx24123_writereg(state, 0x22, (data >> 8) & 0xff); + while ((cx24123_readreg(state, 0x20) & 0x40) == 0) { + if (time_after(jiffies, timeout)) { + err("%s: demodulator is not responding, "\ + "possibly hung, aborting.\n", __func__); + return -EREMOTEIO; + } + msleep(10); + } + + /* send the lower 5 bits of this byte, padded with 3 LBB, + * wait for the send to be completed */ + timeout = jiffies + msecs_to_jiffies(40); + cx24123_writereg(state, 0x22, (data) & 0xff); + while ((cx24123_readreg(state, 0x20) & 0x80)) { + if (time_after(jiffies, timeout)) { + err("%s: demodulator is not responding," \ + "possibly hung, aborting.\n", __func__); + return -EREMOTEIO; + } + msleep(10); + } + + /* Trigger the demod to configure the tuner */ + cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2); + cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd); + + return 0; +} + +static int cx24123_pll_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + u8 val; + + dprintk("frequency=%i\n", p->frequency); + + if (cx24123_pll_calculate(fe, p) != 0) { + err("%s: cx24123_pll_calcutate failed\n", __func__); + return -EINVAL; + } + + /* Write the new VCO/VGA */ + cx24123_pll_writereg(fe, p, state->VCAarg); + cx24123_pll_writereg(fe, p, state->VGAarg); + + /* Write the new bandselect and pll args */ + cx24123_pll_writereg(fe, p, state->bandselectarg); + cx24123_pll_writereg(fe, p, state->pllarg); + + /* set the FILTUNE voltage */ + val = cx24123_readreg(state, 0x28) & ~0x3; + cx24123_writereg(state, 0x27, state->FILTune >> 2); + cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3)); + + dprintk("pll tune VCA=%d, band=%d, pll=%d\n", state->VCAarg, + state->bandselectarg, state->pllarg); + + return 0; +} + + +/* + * 0x23: + * [7:7] = BTI enabled + * [6:6] = I2C repeater enabled + * [5:5] = I2C repeater start + * [0:0] = BTI start + */ + +/* mode == 1 -> i2c-repeater, 0 -> bti */ +static int cx24123_repeater_mode(struct cx24123_state *state, u8 mode, u8 start) +{ + u8 r = cx24123_readreg(state, 0x23) & 0x1e; + if (mode) + r |= (1 << 6) | (start << 5); + else + r |= (1 << 7) | (start); + return cx24123_writereg(state, 0x23, r); +} + +static int cx24123_initfe(struct dvb_frontend *fe) +{ + struct cx24123_state *state = fe->demodulator_priv; + int i; + + dprintk("init frontend\n"); + + /* Configure the demod to a good set of defaults */ + for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++) + cx24123_writereg(state, cx24123_regdata[i].reg, + cx24123_regdata[i].data); + + /* Set the LNB polarity */ + if (state->config->lnb_polarity) + cx24123_writereg(state, 0x32, + cx24123_readreg(state, 0x32) | 0x02); + + if (state->config->dont_use_pll) + cx24123_repeater_mode(state, 1, 0); + + return 0; +} + +static int cx24123_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx24123_state *state = fe->demodulator_priv; + u8 val; + + val = cx24123_readreg(state, 0x29) & ~0x40; + + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk("setting voltage 13V\n"); + return cx24123_writereg(state, 0x29, val & 0x7f); + case SEC_VOLTAGE_18: + dprintk("setting voltage 18V\n"); + return cx24123_writereg(state, 0x29, val | 0x80); + case SEC_VOLTAGE_OFF: + /* already handled in cx88-dvb */ + return 0; + default: + return -EINVAL; + }; + + return 0; +} + +/* wait for diseqc queue to become ready (or timeout) */ +static void cx24123_wait_for_diseqc(struct cx24123_state *state) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(200); + while (!(cx24123_readreg(state, 0x29) & 0x40)) { + if (time_after(jiffies, timeout)) { + err("%s: diseqc queue not ready, " \ + "command may be lost.\n", __func__); + break; + } + msleep(10); + } +} + +static int cx24123_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct cx24123_state *state = fe->demodulator_priv; + int i, val, tone; + + dprintk("\n"); + + /* stop continuous tone if enabled */ + tone = cx24123_readreg(state, 0x29); + if (tone & 0x10) + cx24123_writereg(state, 0x29, tone & ~0x50); + + /* wait for diseqc queue ready */ + cx24123_wait_for_diseqc(state); + + /* select tone mode */ + cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb); + + for (i = 0; i < cmd->msg_len; i++) + cx24123_writereg(state, 0x2C + i, cmd->msg[i]); + + val = cx24123_readreg(state, 0x29); + cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) | + ((cmd->msg_len-3) & 3)); + + /* wait for diseqc message to finish sending */ + cx24123_wait_for_diseqc(state); + + /* restart continuous tone if enabled */ + if (tone & 0x10) + cx24123_writereg(state, 0x29, tone & ~0x40); + + return 0; +} + +static int cx24123_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t burst) +{ + struct cx24123_state *state = fe->demodulator_priv; + int val, tone; + + dprintk("\n"); + + /* stop continuous tone if enabled */ + tone = cx24123_readreg(state, 0x29); + if (tone & 0x10) + cx24123_writereg(state, 0x29, tone & ~0x50); + + /* wait for diseqc queue ready */ + cx24123_wait_for_diseqc(state); + + /* select tone mode */ + cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4); + msleep(30); + val = cx24123_readreg(state, 0x29); + if (burst == SEC_MINI_A) + cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00)); + else if (burst == SEC_MINI_B) + cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x08)); + else + return -EINVAL; + + cx24123_wait_for_diseqc(state); + cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb); + + /* restart continuous tone if enabled */ + if (tone & 0x10) + cx24123_writereg(state, 0x29, tone & ~0x40); + + return 0; +} + +static int cx24123_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct cx24123_state *state = fe->demodulator_priv; + int sync = cx24123_readreg(state, 0x14); + + *status = 0; + if (state->config->dont_use_pll) { + u32 tun_status = 0; + if (fe->ops.tuner_ops.get_status) + fe->ops.tuner_ops.get_status(fe, &tun_status); + if (tun_status & TUNER_STATUS_LOCKED) + *status |= FE_HAS_SIGNAL; + } else { + int lock = cx24123_readreg(state, 0x20); + if (lock & 0x01) + *status |= FE_HAS_SIGNAL; + } + + if (sync & 0x02) + *status |= FE_HAS_CARRIER; /* Phase locked */ + if (sync & 0x04) + *status |= FE_HAS_VITERBI; + + /* Reed-Solomon Status */ + if (sync & 0x08) + *status |= FE_HAS_SYNC; + if (sync & 0x80) + *status |= FE_HAS_LOCK; /*Full Sync */ + + return 0; +} + +/* + * Configured to return the measurement of errors in blocks, + * because no UCBLOCKS value is available, so this value doubles up + * to satisfy both measurements. + */ +static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct cx24123_state *state = fe->demodulator_priv; + + /* The true bit error rate is this value divided by + the window size (set as 256 * 255) */ + *ber = ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) | + (cx24123_readreg(state, 0x1d) << 8 | + cx24123_readreg(state, 0x1e)); + + dprintk("BER = %d\n", *ber); + + return 0; +} + +static int cx24123_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct cx24123_state *state = fe->demodulator_priv; + + /* larger = better */ + *signal_strength = cx24123_readreg(state, 0x3b) << 8; + + dprintk("Signal strength = %d\n", *signal_strength); + + return 0; +} + +static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct cx24123_state *state = fe->demodulator_priv; + + /* Inverted raw Es/N0 count, totally bogus but better than the + BER threshold. */ + *snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) | + (u16)cx24123_readreg(state, 0x19)); + + dprintk("read S/N index = %d\n", *snr); + + return 0; +} + +static int cx24123_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + dprintk("\n"); + + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + state->currentfreq = p->frequency; + state->currentsymbolrate = p->u.qpsk.symbol_rate; + + cx24123_set_inversion(state, p->inversion); + cx24123_set_fec(state, p->u.qpsk.fec_inner); + cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate); + + if (!state->config->dont_use_pll) + cx24123_pll_tune(fe, p); + else if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, p); + else + err("it seems I don't have a tuner..."); + + /* Enable automatic acquisition and reset cycle */ + cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07)); + cx24123_writereg(state, 0x00, 0x10); + cx24123_writereg(state, 0x00, 0); + + if (state->config->agc_callback) + state->config->agc_callback(fe); + + return 0; +} + +static int cx24123_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + dprintk("\n"); + + if (cx24123_get_inversion(state, &p->inversion) != 0) { + err("%s: Failed to get inversion status\n", __func__); + return -EREMOTEIO; + } + if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) { + err("%s: Failed to get fec status\n", __func__); + return -EREMOTEIO; + } + p->frequency = state->currentfreq; + p->u.qpsk.symbol_rate = state->currentsymbolrate; + + return 0; +} + +static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct cx24123_state *state = fe->demodulator_priv; + u8 val; + + /* wait for diseqc queue ready */ + cx24123_wait_for_diseqc(state); + + val = cx24123_readreg(state, 0x29) & ~0x40; + + switch (tone) { + case SEC_TONE_ON: + dprintk("setting tone on\n"); + return cx24123_writereg(state, 0x29, val | 0x10); + case SEC_TONE_OFF: + dprintk("setting tone off\n"); + return cx24123_writereg(state, 0x29, val & 0xef); + default: + err("CASE reached default with tone=%d\n", tone); + return -EINVAL; + } + + return 0; +} + +static int cx24123_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + unsigned int mode_flags, + unsigned int *delay, + fe_status_t *status) +{ + int retval = 0; + + if (params != NULL) + retval = cx24123_set_frontend(fe, params); + + if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) + cx24123_read_status(fe, status); + *delay = HZ/10; + + return retval; +} + +static int cx24123_get_algo(struct dvb_frontend *fe) +{ + return 1; /* FE_ALGO_HW */ +} + +static void cx24123_release(struct dvb_frontend *fe) +{ + struct cx24123_state *state = fe->demodulator_priv; + dprintk("\n"); + i2c_del_adapter(&state->tuner_i2c_adapter); + kfree(state); +} + +static int cx24123_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct cx24123_state *state = i2c_get_adapdata(i2c_adap); + /* this repeater closes after the first stop */ + cx24123_repeater_mode(state, 1, 1); + return i2c_transfer(state->i2c, msg, num); +} + +static u32 cx24123_tuner_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm cx24123_tuner_i2c_algo = { + .master_xfer = cx24123_tuner_i2c_tuner_xfer, + .functionality = cx24123_tuner_i2c_func, +}; + +struct i2c_adapter * + cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe) +{ + struct cx24123_state *state = fe->demodulator_priv; + return &state->tuner_i2c_adapter; +} +EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter); + +static struct dvb_frontend_ops cx24123_ops; + +struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, + struct i2c_adapter *i2c) +{ + /* allocate memory for the internal state */ + struct cx24123_state *state = + kzalloc(sizeof(struct cx24123_state), GFP_KERNEL); + + dprintk("\n"); + if (state == NULL) { + err("Unable to kzalloc\n"); + goto error; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* check if the demod is there */ + state->demod_rev = cx24123_readreg(state, 0x00); + switch (state->demod_rev) { + case 0xe1: + info("detected CX24123C\n"); + break; + case 0xd1: + info("detected CX24123\n"); + break; + default: + err("wrong demod revision: %x\n", state->demod_rev); + goto error; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &cx24123_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* create tuner i2c adapter */ + if (config->dont_use_pll) + cx24123_repeater_mode(state, 1, 0); + + strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus", + sizeof(state->tuner_i2c_adapter.name)); + state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo; + state->tuner_i2c_adapter.algo_data = NULL; + i2c_set_adapdata(&state->tuner_i2c_adapter, state); + if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) { + err("tuner i2c bus could not be initialized\n"); + goto error; + } + + return &state->frontend; + +error: + kfree(state); + + return NULL; +} +EXPORT_SYMBOL(cx24123_attach); + +static struct dvb_frontend_ops cx24123_ops = { + + .info = { + .name = "Conexant CX24123/CX24109", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1011, /* kHz for QPSK frontends */ + .frequency_tolerance = 5000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_RECOVER + }, + + .release = cx24123_release, + + .init = cx24123_initfe, + .set_frontend = cx24123_set_frontend, + .get_frontend = cx24123_get_frontend, + .read_status = cx24123_read_status, + .read_ber = cx24123_read_ber, + .read_signal_strength = cx24123_read_signal_strength, + .read_snr = cx24123_read_snr, + .diseqc_send_master_cmd = cx24123_send_diseqc_msg, + .diseqc_send_burst = cx24123_diseqc_send_burst, + .set_tone = cx24123_set_tone, + .set_voltage = cx24123_set_voltage, + .tune = cx24123_tune, + .get_frontend_algo = cx24123_get_algo, +}; + +MODULE_DESCRIPTION("DVB Frontend module for Conexant " \ + "CX24123/CX24109/CX24113 hardware"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24123.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24123.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24123.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cx24123.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* + Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver + + Copyright (C) 2005 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef CX24123_H +#define CX24123_H + +#include + +struct cx24123_config { + /* the demodulator's i2c address */ + u8 demod_address; + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); + + /* 0 = LNB voltage normal, 1 = LNB voltage inverted */ + int lnb_polarity; + + /* this device has another tuner */ + u8 dont_use_pll; + void (*agc_callback) (struct dvb_frontend *); +}; + +#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, + struct i2c_adapter *i2c); +extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *); +#else +static inline struct dvb_frontend *cx24123_attach( + const struct cx24123_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static struct i2c_adapter * + cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* CX24123_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,338 @@ +/* + * Sony CXD2820R demodulator driver + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include "cxd2820r_priv.h" + +int cxd2820r_set_frontend_c(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; + u8 buf[2]; + u16 if_ctl; + u64 num; + struct reg_val_mask tab[] = { + { 0x00080, 0x01, 0xff }, + { 0x00081, 0x05, 0xff }, + { 0x00085, 0x07, 0xff }, + { 0x00088, 0x01, 0xff }, + + { 0x00082, 0x20, 0x60 }, + { 0x1016a, 0x48, 0xff }, + { 0x100a5, 0x00, 0x01 }, + { 0x10020, 0x06, 0x07 }, + { 0x10059, 0x50, 0xff }, + { 0x10087, 0x0c, 0x3c }, + { 0x1008b, 0x07, 0xff }, + { 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 }, + { 0x10070, priv->cfg.ts_mode, 0xff }, + }; + + dbg("%s: RF=%d SR=%d", __func__, c->frequency, c->symbol_rate); + + /* update GPIOs */ + ret = cxd2820r_gpio(fe); + if (ret) + goto error; + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, params); + + if (priv->delivery_system != SYS_DVBC_ANNEX_AC) { + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, + tab[i].val, tab[i].mask); + if (ret) + goto error; + } + } + + priv->delivery_system = SYS_DVBC_ANNEX_AC; + priv->ber_running = 0; /* tune stops BER counter */ + + num = priv->cfg.if_dvbc; + num *= 0x4000; + if_ctl = cxd2820r_div_u64_round_closest(num, 41000); + buf[0] = (if_ctl >> 8) & 0x3f; + buf[1] = (if_ctl >> 0) & 0xff; + + ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2); + if (ret) + goto error; + + ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08); + if (ret) + goto error; + + ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_get_frontend_c(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + u8 buf[2]; + + ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2); + if (ret) + goto error; + + c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]); + + ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]); + if (ret) + goto error; + + switch ((buf[0] >> 0) & 0x03) { + case 0: + c->modulation = QAM_16; + break; + case 1: + c->modulation = QAM_32; + break; + case 2: + c->modulation = QAM_64; + break; + case 3: + c->modulation = QAM_128; + break; + case 4: + c->modulation = QAM_256; + break; + } + + switch ((buf[0] >> 7) & 0x01) { + case 0: + c->inversion = INVERSION_OFF; + break; + case 1: + c->inversion = INVERSION_ON; + break; + } + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[3], start_ber = 0; + *ber = 0; + + if (priv->ber_running) { + ret = cxd2820r_rd_regs(priv, 0x10076, buf, sizeof(buf)); + if (ret) + goto error; + + if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) { + *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0]; + start_ber = 1; + } + } else { + priv->ber_running = 1; + start_ber = 1; + } + + if (start_ber) { + /* (re)start BER */ + ret = cxd2820r_wr_reg(priv, 0x10079, 0x01); + if (ret) + goto error; + } + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, + u16 *strength) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + u16 tmp; + + ret = cxd2820r_rd_regs(priv, 0x10049, buf, sizeof(buf)); + if (ret) + goto error; + + tmp = (buf[0] & 0x03) << 8 | buf[1]; + tmp = (~tmp & 0x03ff); + + if (tmp == 512) + /* ~no signal */ + tmp = 0; + else if (tmp > 350) + tmp = 350; + + /* scale value to 0x0000-0xffff */ + *strength = tmp * 0xffff / (350-0); + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 tmp; + unsigned int A, B; + /* report SNR in dB * 10 */ + + ret = cxd2820r_rd_reg(priv, 0x10019, &tmp); + if (ret) + goto error; + + if (((tmp >> 0) & 0x03) % 2) { + A = 875; + B = 650; + } else { + A = 950; + B = 760; + } + + ret = cxd2820r_rd_reg(priv, 0x1004d, &tmp); + if (ret) + goto error; + + #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */ + if (tmp) + *snr = A * (intlog2(B / tmp) >> 5) / (CXD2820R_LOG2_E_24 >> 5) + / 10; + else + *snr = 0; + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + /* no way to read ? */ + return 0; +} + +int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + *status = 0; + + ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf)); + if (ret) + goto error; + + if (((buf[0] >> 0) & 0x01) == 1) { + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC; + + if (((buf[1] >> 3) & 0x01) == 1) { + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } + } + + dbg("%s: lock=%02x %02x", __func__, buf[0], buf[1]); + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_init_c(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + + ret = cxd2820r_wr_reg(priv, 0x00085, 0x07); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_sleep_c(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret, i; + struct reg_val_mask tab[] = { + { 0x000ff, 0x1f, 0xff }, + { 0x00085, 0x00, 0xff }, + { 0x00088, 0x01, 0xff }, + { 0x00081, 0x00, 0xff }, + { 0x00080, 0x00, 0xff }, + }; + + dbg("%s", __func__); + + priv->delivery_system = SYS_UNDEFINED; + + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val, + tab[i].mask); + if (ret) + goto error; + } + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *s) +{ + s->min_delay_ms = 500; + s->step_size = 0; /* no zigzag */ + s->max_drift = 0; + + return 0; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_core.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,929 @@ +/* + * Sony CXD2820R demodulator driver + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include "cxd2820r_priv.h" + +int cxd2820r_debug; +module_param_named(debug, cxd2820r_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +/* write multiple registers */ +static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg, + u8 *val, int len) +{ + int ret; + u8 buf[len+1]; + struct i2c_msg msg[1] = { + { + .addr = i2c, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = reg; + memcpy(&buf[1], val, len); + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); + ret = -EREMOTEIO; + } + return ret; +} + +/* read multiple registers */ +static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg, + u8 *val, int len) +{ + int ret; + u8 buf[len]; + struct i2c_msg msg[2] = { + { + .addr = i2c, + .flags = 0, + .len = 1, + .buf = ®, + }, { + .addr = i2c, + .flags = I2C_M_RD, + .len = sizeof(buf), + .buf = buf, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + memcpy(val, buf, len); + ret = 0; + } else { + warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* write multiple registers */ +int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, + int len) +{ + int ret; + u8 i2c_addr; + u8 reg = (reginfo >> 0) & 0xff; + u8 bank = (reginfo >> 8) & 0xff; + u8 i2c = (reginfo >> 16) & 0x01; + + /* select I2C */ + if (i2c) + i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */ + else + i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */ + + /* switch bank if needed */ + if (bank != priv->bank[i2c]) { + ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1); + if (ret) + return ret; + priv->bank[i2c] = bank; + } + return cxd2820r_wr_regs_i2c(priv, i2c_addr, reg, val, len); +} + +/* read multiple registers */ +int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, + int len) +{ + int ret; + u8 i2c_addr; + u8 reg = (reginfo >> 0) & 0xff; + u8 bank = (reginfo >> 8) & 0xff; + u8 i2c = (reginfo >> 16) & 0x01; + + /* select I2C */ + if (i2c) + i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */ + else + i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */ + + /* switch bank if needed */ + if (bank != priv->bank[i2c]) { + ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1); + if (ret) + return ret; + priv->bank[i2c] = bank; + } + return cxd2820r_rd_regs_i2c(priv, i2c_addr, reg, val, len); +} + +/* write single register */ +int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val) +{ + return cxd2820r_wr_regs(priv, reg, &val, 1); +} + +/* read single register */ +int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val) +{ + return cxd2820r_rd_regs(priv, reg, val, 1); +} + +/* write single register with mask */ +int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val, + u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = cxd2820r_rd_reg(priv, reg, &tmp); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return cxd2820r_wr_reg(priv, reg, val); +} + +int cxd2820r_gpio(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret, i; + u8 *gpio, tmp0, tmp1; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + gpio = priv->cfg.gpio_dvbt; + break; + case SYS_DVBT2: + gpio = priv->cfg.gpio_dvbt2; + break; + case SYS_DVBC_ANNEX_AC: + gpio = priv->cfg.gpio_dvbc; + break; + default: + ret = -EINVAL; + goto error; + } + + /* update GPIOs only when needed */ + if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio))) + return 0; + + tmp0 = 0x00; + tmp1 = 0x00; + for (i = 0; i < sizeof(priv->gpio); i++) { + /* enable / disable */ + if (gpio[i] & CXD2820R_GPIO_E) + tmp0 |= (2 << 6) >> (2 * i); + else + tmp0 |= (1 << 6) >> (2 * i); + + /* input / output */ + if (gpio[i] & CXD2820R_GPIO_I) + tmp1 |= (1 << (3 + i)); + else + tmp1 |= (0 << (3 + i)); + + /* high / low */ + if (gpio[i] & CXD2820R_GPIO_H) + tmp1 |= (1 << (0 + i)); + else + tmp1 |= (0 << (0 + i)); + + dbg("%s: GPIO i=%d %02x %02x", __func__, i, tmp0, tmp1); + } + + dbg("%s: wr gpio=%02x %02x", __func__, tmp0, tmp1); + + /* write bits [7:2] */ + ret = cxd2820r_wr_reg_mask(priv, 0x00089, tmp0, 0xfc); + if (ret) + goto error; + + /* write bits [5:0] */ + ret = cxd2820r_wr_reg_mask(priv, 0x0008e, tmp1, 0x3f); + if (ret) + goto error; + + memcpy(priv->gpio, gpio, sizeof(priv->gpio)); + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +/* lock FE */ +static int cxd2820r_lock(struct cxd2820r_priv *priv, int active_fe) +{ + int ret = 0; + dbg("%s: active_fe=%d", __func__, active_fe); + + mutex_lock(&priv->fe_lock); + + /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */ + if (priv->active_fe == active_fe) + ; + else if (priv->active_fe == -1) + priv->active_fe = active_fe; + else + ret = -EBUSY; + + mutex_unlock(&priv->fe_lock); + + return ret; +} + +/* unlock FE */ +static void cxd2820r_unlock(struct cxd2820r_priv *priv, int active_fe) +{ + dbg("%s: active_fe=%d", __func__, active_fe); + + mutex_lock(&priv->fe_lock); + + /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */ + if (priv->active_fe == active_fe) + priv->active_fe = -1; + + mutex_unlock(&priv->fe_lock); + + return; +} + +/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */ +u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor) +{ + return div_u64(dividend + (divisor / 2), divisor); +} + +static int cxd2820r_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + switch (priv->delivery_system) { + case SYS_UNDEFINED: + if (c->delivery_system == SYS_DVBT) { + /* SLEEP => DVB-T */ + ret = cxd2820r_set_frontend_t(fe, p); + } else { + /* SLEEP => DVB-T2 */ + ret = cxd2820r_set_frontend_t2(fe, p); + } + break; + case SYS_DVBT: + if (c->delivery_system == SYS_DVBT) { + /* DVB-T => DVB-T */ + ret = cxd2820r_set_frontend_t(fe, p); + } else if (c->delivery_system == SYS_DVBT2) { + /* DVB-T => DVB-T2 */ + ret = cxd2820r_sleep_t(fe); + if (ret) + break; + ret = cxd2820r_set_frontend_t2(fe, p); + } + break; + case SYS_DVBT2: + if (c->delivery_system == SYS_DVBT2) { + /* DVB-T2 => DVB-T2 */ + ret = cxd2820r_set_frontend_t2(fe, p); + } else if (c->delivery_system == SYS_DVBT) { + /* DVB-T2 => DVB-T */ + ret = cxd2820r_sleep_t2(fe); + if (ret) + break; + ret = cxd2820r_set_frontend_t(fe, p); + } + break; + default: + dbg("%s: error state=%d", __func__, + priv->delivery_system); + ret = -EINVAL; + } + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_set_frontend_c(fe, p); + } + + return ret; +} + +static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_status_t(fe, status); + break; + case SYS_DVBT2: + ret = cxd2820r_read_status_t2(fe, status); + break; + default: + ret = -EINVAL; + } + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_read_status_c(fe, status); + } + + return ret; +} + +static int cxd2820r_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_get_frontend_t(fe, p); + break; + case SYS_DVBT2: + ret = cxd2820r_get_frontend_t2(fe, p); + break; + default: + ret = -EINVAL; + } + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_get_frontend_c(fe, p); + } + + return ret; +} + +static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_ber_t(fe, ber); + break; + case SYS_DVBT2: + ret = cxd2820r_read_ber_t2(fe, ber); + break; + default: + ret = -EINVAL; + } + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_read_ber_c(fe, ber); + } + + return ret; +} + +static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_signal_strength_t(fe, strength); + break; + case SYS_DVBT2: + ret = cxd2820r_read_signal_strength_t2(fe, strength); + break; + default: + ret = -EINVAL; + } + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_read_signal_strength_c(fe, strength); + } + + return ret; +} + +static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_snr_t(fe, snr); + break; + case SYS_DVBT2: + ret = cxd2820r_read_snr_t2(fe, snr); + break; + default: + ret = -EINVAL; + } + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_read_snr_c(fe, snr); + } + + return ret; +} + +static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_ucblocks_t(fe, ucblocks); + break; + case SYS_DVBT2: + ret = cxd2820r_read_ucblocks_t2(fe, ucblocks); + break; + default: + ret = -EINVAL; + } + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_read_ucblocks_c(fe, ucblocks); + } + + return ret; +} + +static int cxd2820r_init(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + priv->delivery_system = SYS_UNDEFINED; + /* delivery system is unknown at that (init) phase */ + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + ret = cxd2820r_init_t(fe); + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_init_c(fe); + } + + return ret; +} + +static int cxd2820r_sleep(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_sleep_t(fe); + break; + case SYS_DVBT2: + ret = cxd2820r_sleep_t2(fe); + break; + default: + ret = -EINVAL; + } + + cxd2820r_unlock(priv, 0); + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_sleep_c(fe); + + cxd2820r_unlock(priv, 1); + } + + return ret; +} + +static int cxd2820r_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *s) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + if (fe->ops.info.type == FE_OFDM) { + /* DVB-T/T2 */ + ret = cxd2820r_lock(priv, 0); + if (ret) + return ret; + + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_get_tune_settings_t(fe, s); + break; + case SYS_DVBT2: + ret = cxd2820r_get_tune_settings_t2(fe, s); + break; + default: + ret = -EINVAL; + } + } else { + /* DVB-C */ + ret = cxd2820r_lock(priv, 1); + if (ret) + return ret; + + ret = cxd2820r_get_tune_settings_c(fe, s); + } + + return ret; +} + +static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; + fe_status_t status = 0; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + + /* switch between DVB-T and DVB-T2 when tune fails */ + if (priv->last_tune_failed) { + if (priv->delivery_system == SYS_DVBT) + c->delivery_system = SYS_DVBT2; + else + c->delivery_system = SYS_DVBT; + } + + /* set frontend */ + ret = cxd2820r_set_frontend(fe, p); + if (ret) + goto error; + + + /* frontend lock wait loop count */ + switch (priv->delivery_system) { + case SYS_DVBT: + i = 20; + break; + case SYS_DVBT2: + i = 40; + break; + case SYS_UNDEFINED: + default: + i = 0; + break; + } + + /* wait frontend lock */ + for (; i > 0; i--) { + dbg("%s: LOOP=%d", __func__, i); + msleep(50); + ret = cxd2820r_read_status(fe, &status); + if (ret) + goto error; + + if (status & FE_HAS_SIGNAL) + break; + } + + /* check if we have a valid signal */ + if (status) { + priv->last_tune_failed = 0; + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + priv->last_tune_failed = 1; + return DVBFE_ALGO_SEARCH_AGAIN; + } + +error: + dbg("%s: failed:%d", __func__, ret); + return DVBFE_ALGO_SEARCH_ERROR; +} + +static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static void cxd2820r_release(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + dbg("%s", __func__); + + if (fe->ops.info.type == FE_OFDM) { + i2c_del_adapter(&priv->tuner_i2c_adapter); + kfree(priv); + } + + return; +} + +static u32 cxd2820r_tuner_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap); + int ret; + u8 *obuf = kmalloc(msg[0].len + 2, GFP_KERNEL); + struct i2c_msg msg2[2] = { + { + .addr = priv->cfg.i2c_address, + .flags = 0, + .len = msg[0].len + 2, + .buf = obuf, + }, { + .addr = priv->cfg.i2c_address, + .flags = I2C_M_RD, + .len = msg[1].len, + .buf = msg[1].buf, + } + }; + + if (!obuf) + return -ENOMEM; + + obuf[0] = 0x09; + obuf[1] = (msg[0].addr << 1); + if (num == 2) { /* I2C read */ + obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */ + msg2[0].len = msg[0].len + 2 - 1; /* '-1' maybe HW bug ? */ + } + memcpy(&obuf[2], msg[0].buf, msg[0].len); + + ret = i2c_transfer(priv->i2c, msg2, num); + if (ret < 0) + warn("tuner i2c failed ret:%d", ret); + + kfree(obuf); + + return ret; +} + +static struct i2c_algorithm cxd2820r_tuner_i2c_algo = { + .master_xfer = cxd2820r_tuner_i2c_xfer, + .functionality = cxd2820r_tuner_i2c_func, +}; + +struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + return &priv->tuner_i2c_adapter; +} +EXPORT_SYMBOL(cxd2820r_get_tuner_i2c_adapter); + +static struct dvb_frontend_ops cxd2820r_ops[2]; + +struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, + struct i2c_adapter *i2c, struct dvb_frontend *fe) +{ + int ret; + struct cxd2820r_priv *priv = NULL; + u8 tmp; + + if (fe == NULL) { + /* FE0 */ + /* allocate memory for the internal priv */ + priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL); + if (priv == NULL) + goto error; + + /* setup the priv */ + priv->i2c = i2c; + memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config)); + mutex_init(&priv->fe_lock); + + priv->active_fe = -1; /* NONE */ + + /* check if the demod is there */ + priv->bank[0] = priv->bank[1] = 0xff; + ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp); + dbg("%s: chip id=%02x", __func__, tmp); + if (ret || tmp != 0xe1) + goto error; + + /* create frontends */ + memcpy(&priv->fe[0].ops, &cxd2820r_ops[0], + sizeof(struct dvb_frontend_ops)); + memcpy(&priv->fe[1].ops, &cxd2820r_ops[1], + sizeof(struct dvb_frontend_ops)); + + priv->fe[0].demodulator_priv = priv; + priv->fe[1].demodulator_priv = priv; + + /* create tuner i2c adapter */ + strlcpy(priv->tuner_i2c_adapter.name, + "CXD2820R tuner I2C adapter", + sizeof(priv->tuner_i2c_adapter.name)); + priv->tuner_i2c_adapter.algo = &cxd2820r_tuner_i2c_algo; + priv->tuner_i2c_adapter.algo_data = NULL; + i2c_set_adapdata(&priv->tuner_i2c_adapter, priv); + if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) { + err("tuner I2C bus could not be initialized"); + goto error; + } + + return &priv->fe[0]; + + } else { + /* FE1: FE0 given as pointer, just return FE1 we have + * already created */ + priv = fe->demodulator_priv; + return &priv->fe[1]; + } + +error: + kfree(priv); + return NULL; +} +EXPORT_SYMBOL(cxd2820r_attach); + +static struct dvb_frontend_ops cxd2820r_ops[2] = { + { + /* DVB-T/T2 */ + .info = { + .name = "Sony CXD2820R (DVB-T/T2)", + .type = FE_OFDM, + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | + FE_CAN_QAM_64 | FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_MUTE_TS | + FE_CAN_2G_MODULATION + }, + + .release = cxd2820r_release, + .init = cxd2820r_init, + .sleep = cxd2820r_sleep, + + .get_tune_settings = cxd2820r_get_tune_settings, + + .get_frontend = cxd2820r_get_frontend, + + .get_frontend_algo = cxd2820r_get_frontend_algo, + .search = cxd2820r_search, + + .read_status = cxd2820r_read_status, + .read_snr = cxd2820r_read_snr, + .read_ber = cxd2820r_read_ber, + .read_ucblocks = cxd2820r_read_ucblocks, + .read_signal_strength = cxd2820r_read_signal_strength, + }, + { + /* DVB-C */ + .info = { + .name = "Sony CXD2820R (DVB-C)", + .type = FE_QAM, + .caps = + FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO + }, + + .release = cxd2820r_release, + .init = cxd2820r_init, + .sleep = cxd2820r_sleep, + + .get_tune_settings = cxd2820r_get_tune_settings, + + .set_frontend = cxd2820r_set_frontend, + .get_frontend = cxd2820r_get_frontend, + + .read_status = cxd2820r_read_status, + .read_snr = cxd2820r_read_snr, + .read_ber = cxd2820r_read_ber, + .read_ucblocks = cxd2820r_read_ucblocks, + .read_signal_strength = cxd2820r_read_signal_strength, + }, +}; + + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Sony CXD2820R demodulator driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,118 @@ +/* + * Sony CXD2820R demodulator driver + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#ifndef CXD2820R_H +#define CXD2820R_H + +#include + +#define CXD2820R_GPIO_D (0 << 0) /* disable */ +#define CXD2820R_GPIO_E (1 << 0) /* enable */ +#define CXD2820R_GPIO_O (0 << 1) /* output */ +#define CXD2820R_GPIO_I (1 << 1) /* input */ +#define CXD2820R_GPIO_L (0 << 2) /* output low */ +#define CXD2820R_GPIO_H (1 << 2) /* output high */ + +#define CXD2820R_TS_SERIAL 0x08 +#define CXD2820R_TS_SERIAL_MSB 0x28 +#define CXD2820R_TS_PARALLEL 0x30 +#define CXD2820R_TS_PARALLEL_MSB 0x70 + +struct cxd2820r_config { + /* Demodulator I2C address. + * Driver determines DVB-C slave I2C address automatically from master + * address. + * Default: none, must set + * Values: 0x6c, 0x6d + */ + u8 i2c_address; + + /* TS output mode. + * Default: none, must set. + * Values: + */ + u8 ts_mode; + + /* IF AGC polarity. + * Default: 0 + * Values: 0, 1 + */ + bool if_agc_polarity; + + /* Spectrum inversion. + * Default: 0 + * Values: 0, 1 + */ + bool spec_inv; + + /* IFs for all used modes. + * Default: none, must set + * Values: + */ + u16 if_dvbt_6; + u16 if_dvbt_7; + u16 if_dvbt_8; + u16 if_dvbt2_5; + u16 if_dvbt2_6; + u16 if_dvbt2_7; + u16 if_dvbt2_8; + u16 if_dvbc; + + /* GPIOs for all used modes. + * Default: none, disabled + * Values: + */ + u8 gpio_dvbt[3]; + u8 gpio_dvbt2[3]; + u8 gpio_dvbc[3]; +}; + + +#if defined(CONFIG_DVB_CXD2820R) || \ + (defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE)) +extern struct dvb_frontend *cxd2820r_attach( + const struct cxd2820r_config *config, + struct i2c_adapter *i2c, + struct dvb_frontend *fe +); +extern struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter( + struct dvb_frontend *fe +); +#else +static inline struct dvb_frontend *cxd2820r_attach( + const struct cxd2820r_config *config, + struct i2c_adapter *i2c, + struct dvb_frontend *fe +) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter( + struct dvb_frontend *fe +) +{ + return NULL; +} + +#endif + +#endif /* CXD2820R_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,166 @@ +/* + * Sony CXD2820R demodulator driver + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#ifndef CXD2820R_PRIV_H +#define CXD2820R_PRIV_H + +#include +#include "dvb_frontend.h" +#include "dvb_math.h" +#include "cxd2820r.h" + +#define LOG_PREFIX "cxd2820r" + +#undef dbg +#define dbg(f, arg...) \ + if (cxd2820r_debug) \ + printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +struct reg_val_mask { + u32 reg; + u8 val; + u8 mask; +}; + +struct cxd2820r_priv { + struct i2c_adapter *i2c; + struct dvb_frontend fe[2]; + struct cxd2820r_config cfg; + struct i2c_adapter tuner_i2c_adapter; + + struct mutex fe_lock; /* FE lock */ + int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */ + + bool ber_running; + + u8 bank[2]; + u8 gpio[3]; + + fe_delivery_system_t delivery_system; + bool last_tune_failed; /* for switch between T and T2 tune */ +}; + +/* cxd2820r_core.c */ + +extern int cxd2820r_debug; + +int cxd2820r_gpio(struct dvb_frontend *fe); + +int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val, + u8 mask); + +int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, + int len); + +u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor); + +int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, + int len); + +int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, + int len); + +int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val); + +int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val); + +/* cxd2820r_c.c */ + +int cxd2820r_get_frontend_c(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p); + +int cxd2820r_set_frontend_c(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params); + +int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status); + +int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber); + +int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, u16 *strength); + +int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr); + +int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks); + +int cxd2820r_init_c(struct dvb_frontend *fe); + +int cxd2820r_sleep_c(struct dvb_frontend *fe); + +int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *s); + +/* cxd2820r_t.c */ + +int cxd2820r_get_frontend_t(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p); + +int cxd2820r_set_frontend_t(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params); + +int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status); + +int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber); + +int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe, u16 *strength); + +int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr); + +int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks); + +int cxd2820r_init_t(struct dvb_frontend *fe); + +int cxd2820r_sleep_t(struct dvb_frontend *fe); + +int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *s); + +/* cxd2820r_t2.c */ + +int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p); + +int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params); + +int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status); + +int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber); + +int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe, u16 *strength); + +int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr); + +int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks); + +int cxd2820r_init_t2(struct dvb_frontend *fe); + +int cxd2820r_sleep_t2(struct dvb_frontend *fe); + +int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *s); + +#endif /* CXD2820R_PRIV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_t2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_t2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_t2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_t2.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,423 @@ +/* + * Sony CXD2820R demodulator driver + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include "cxd2820r_priv.h" + +int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; + u32 if_khz, if_ctl; + u64 num; + u8 buf[3], bw_param; + u8 bw_params1[][5] = { + { 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */ + { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */ + { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */ + { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */ + }; + struct reg_val_mask tab[] = { + { 0x00080, 0x02, 0xff }, + { 0x00081, 0x20, 0xff }, + { 0x00085, 0x07, 0xff }, + { 0x00088, 0x01, 0xff }, + { 0x02069, 0x01, 0xff }, + + { 0x0207f, 0x2a, 0xff }, + { 0x02082, 0x0a, 0xff }, + { 0x02083, 0x0a, 0xff }, + { 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 }, + { 0x02070, priv->cfg.ts_mode, 0xff }, + { 0x020b5, priv->cfg.spec_inv << 4, 0x10 }, + { 0x02567, 0x07, 0x0f }, + { 0x02569, 0x03, 0x03 }, + { 0x02595, 0x1a, 0xff }, + { 0x02596, 0x50, 0xff }, + { 0x02a8c, 0x00, 0xff }, + { 0x02a8d, 0x34, 0xff }, + { 0x02a45, 0x06, 0x07 }, + { 0x03f10, 0x0d, 0xff }, + { 0x03f11, 0x02, 0xff }, + { 0x03f12, 0x01, 0xff }, + { 0x03f23, 0x2c, 0xff }, + { 0x03f51, 0x13, 0xff }, + { 0x03f52, 0x01, 0xff }, + { 0x03f53, 0x00, 0xff }, + { 0x027e6, 0x14, 0xff }, + { 0x02786, 0x02, 0x07 }, + { 0x02787, 0x40, 0xe0 }, + { 0x027ef, 0x10, 0x18 }, + }; + + dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz); + + /* update GPIOs */ + ret = cxd2820r_gpio(fe); + if (ret) + goto error; + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, params); + + if (priv->delivery_system != SYS_DVBT2) { + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, + tab[i].val, tab[i].mask); + if (ret) + goto error; + } + } + + priv->delivery_system = SYS_DVBT2; + + switch (c->bandwidth_hz) { + case 5000000: + if_khz = priv->cfg.if_dvbt2_5; + i = 0; + bw_param = 3; + break; + case 6000000: + if_khz = priv->cfg.if_dvbt2_6; + i = 1; + bw_param = 2; + break; + case 7000000: + if_khz = priv->cfg.if_dvbt2_7; + i = 2; + bw_param = 1; + break; + case 8000000: + if_khz = priv->cfg.if_dvbt2_8; + i = 3; + bw_param = 0; + break; + default: + return -EINVAL; + } + + num = if_khz; + num *= 0x1000000; + if_ctl = cxd2820r_div_u64_round_closest(num, 41000); + buf[0] = ((if_ctl >> 16) & 0xff); + buf[1] = ((if_ctl >> 8) & 0xff); + buf[2] = ((if_ctl >> 0) & 0xff); + + ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3); + if (ret) + goto error; + + ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5); + if (ret) + goto error; + + ret = cxd2820r_wr_reg_mask(priv, 0x020d7, bw_param << 6, 0xc0); + if (ret) + goto error; + + ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08); + if (ret) + goto error; + + ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; + +} + +int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + u8 buf[2]; + + ret = cxd2820r_rd_regs(priv, 0x0205c, buf, 2); + if (ret) + goto error; + + switch ((buf[0] >> 0) & 0x07) { + case 0: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + case 2: + c->transmission_mode = TRANSMISSION_MODE_4K; + break; + case 3: + c->transmission_mode = TRANSMISSION_MODE_1K; + break; + case 4: + c->transmission_mode = TRANSMISSION_MODE_16K; + break; + case 5: + c->transmission_mode = TRANSMISSION_MODE_32K; + break; + } + + switch ((buf[1] >> 4) & 0x07) { + case 0: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + case 4: + c->guard_interval = GUARD_INTERVAL_1_128; + break; + case 5: + c->guard_interval = GUARD_INTERVAL_19_128; + break; + case 6: + c->guard_interval = GUARD_INTERVAL_19_256; + break; + } + + ret = cxd2820r_rd_regs(priv, 0x0225b, buf, 2); + if (ret) + goto error; + + switch ((buf[0] >> 0) & 0x07) { + case 0: + c->fec_inner = FEC_1_2; + break; + case 1: + c->fec_inner = FEC_3_5; + break; + case 2: + c->fec_inner = FEC_2_3; + break; + case 3: + c->fec_inner = FEC_3_4; + break; + case 4: + c->fec_inner = FEC_4_5; + break; + case 5: + c->fec_inner = FEC_5_6; + break; + } + + switch ((buf[1] >> 0) & 0x07) { + case 0: + c->modulation = QPSK; + break; + case 1: + c->modulation = QAM_16; + break; + case 2: + c->modulation = QAM_64; + break; + case 3: + c->modulation = QAM_256; + break; + } + + ret = cxd2820r_rd_reg(priv, 0x020b5, &buf[0]); + if (ret) + goto error; + + switch ((buf[0] >> 4) & 0x01) { + case 0: + c->inversion = INVERSION_OFF; + break; + case 1: + c->inversion = INVERSION_ON; + break; + } + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[1]; + *status = 0; + + ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]); + if (ret) + goto error; + + if ((buf[0] & 0x07) == 6) { + if (((buf[0] >> 5) & 0x01) == 1) { + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } else { + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC; + } + } + + dbg("%s: lock=%02x", __func__, buf[0]); + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[4]; + unsigned int errbits; + *ber = 0; + /* FIXME: correct calculation */ + + ret = cxd2820r_rd_regs(priv, 0x02039, buf, sizeof(buf)); + if (ret) + goto error; + + if ((buf[0] >> 4) & 0x01) { + errbits = (buf[0] & 0x0f) << 24 | buf[1] << 16 | + buf[2] << 8 | buf[3]; + + if (errbits) + *ber = errbits * 64 / 16588800; + } + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe, + u16 *strength) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + u16 tmp; + + ret = cxd2820r_rd_regs(priv, 0x02026, buf, sizeof(buf)); + if (ret) + goto error; + + tmp = (buf[0] & 0x0f) << 8 | buf[1]; + tmp = ~tmp & 0x0fff; + + /* scale value to 0x0000-0xffff from 0x0000-0x0fff */ + *strength = tmp * 0xffff / 0x0fff; + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + u16 tmp; + /* report SNR in dB * 10 */ + + ret = cxd2820r_rd_regs(priv, 0x02028, buf, sizeof(buf)); + if (ret) + goto error; + + tmp = (buf[0] & 0x0f) << 8 | buf[1]; + #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */ + if (tmp) + *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24) + / 100); + else + *snr = 0; + + dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp); + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + /* no way to read ? */ + return 0; +} + +int cxd2820r_sleep_t2(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret, i; + struct reg_val_mask tab[] = { + { 0x000ff, 0x1f, 0xff }, + { 0x00085, 0x00, 0xff }, + { 0x00088, 0x01, 0xff }, + { 0x02069, 0x00, 0xff }, + { 0x00081, 0x00, 0xff }, + { 0x00080, 0x00, 0xff }, + }; + + dbg("%s", __func__); + + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val, + tab[i].mask); + if (ret) + goto error; + } + + priv->delivery_system = SYS_UNDEFINED; + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *s) +{ + s->min_delay_ms = 1500; + s->step_size = fe->ops.info.frequency_stepsize * 2; + s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; + + return 0; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_t.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_t.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_t.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/cxd2820r_t.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,449 @@ +/* + * Sony CXD2820R demodulator driver + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include "cxd2820r_priv.h" + +int cxd2820r_set_frontend_t(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; + u32 if_khz, if_ctl; + u64 num; + u8 buf[3], bw_param; + u8 bw_params1[][5] = { + { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */ + { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */ + { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */ + }; + u8 bw_params2[][2] = { + { 0x1f, 0xdc }, /* 6 MHz */ + { 0x12, 0xf8 }, /* 7 MHz */ + { 0x01, 0xe0 }, /* 8 MHz */ + }; + struct reg_val_mask tab[] = { + { 0x00080, 0x00, 0xff }, + { 0x00081, 0x03, 0xff }, + { 0x00085, 0x07, 0xff }, + { 0x00088, 0x01, 0xff }, + + { 0x00070, priv->cfg.ts_mode, 0xff }, + { 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 }, + { 0x000a5, 0x00, 0x01 }, + { 0x00082, 0x20, 0x60 }, + { 0x000c2, 0xc3, 0xff }, + { 0x0016a, 0x50, 0xff }, + { 0x00427, 0x41, 0xff }, + }; + + dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz); + + /* update GPIOs */ + ret = cxd2820r_gpio(fe); + if (ret) + goto error; + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, p); + + if (priv->delivery_system != SYS_DVBT) { + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, + tab[i].val, tab[i].mask); + if (ret) + goto error; + } + } + + priv->delivery_system = SYS_DVBT; + priv->ber_running = 0; /* tune stops BER counter */ + + switch (c->bandwidth_hz) { + case 6000000: + if_khz = priv->cfg.if_dvbt_6; + i = 0; + bw_param = 2; + break; + case 7000000: + if_khz = priv->cfg.if_dvbt_7; + i = 1; + bw_param = 1; + break; + case 8000000: + if_khz = priv->cfg.if_dvbt_8; + i = 2; + bw_param = 0; + break; + default: + return -EINVAL; + } + + num = if_khz; + num *= 0x1000000; + if_ctl = cxd2820r_div_u64_round_closest(num, 41000); + buf[0] = ((if_ctl >> 16) & 0xff); + buf[1] = ((if_ctl >> 8) & 0xff); + buf[2] = ((if_ctl >> 0) & 0xff); + + ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3); + if (ret) + goto error; + + ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[i], 5); + if (ret) + goto error; + + ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0); + if (ret) + goto error; + + ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[i], 2); + if (ret) + goto error; + + ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08); + if (ret) + goto error; + + ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_get_frontend_t(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + u8 buf[2]; + + ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf)); + if (ret) + goto error; + + switch ((buf[0] >> 6) & 0x03) { + case 0: + c->modulation = QPSK; + break; + case 1: + c->modulation = QAM_16; + break; + case 2: + c->modulation = QAM_64; + break; + } + + switch ((buf[1] >> 1) & 0x03) { + case 0: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + switch ((buf[1] >> 3) & 0x03) { + case 0: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + switch ((buf[0] >> 3) & 0x07) { + case 0: + c->hierarchy = HIERARCHY_NONE; + break; + case 1: + c->hierarchy = HIERARCHY_1; + break; + case 2: + c->hierarchy = HIERARCHY_2; + break; + case 3: + c->hierarchy = HIERARCHY_4; + break; + } + + switch ((buf[0] >> 0) & 0x07) { + case 0: + c->code_rate_HP = FEC_1_2; + break; + case 1: + c->code_rate_HP = FEC_2_3; + break; + case 2: + c->code_rate_HP = FEC_3_4; + break; + case 3: + c->code_rate_HP = FEC_5_6; + break; + case 4: + c->code_rate_HP = FEC_7_8; + break; + } + + switch ((buf[1] >> 5) & 0x07) { + case 0: + c->code_rate_LP = FEC_1_2; + break; + case 1: + c->code_rate_LP = FEC_2_3; + break; + case 2: + c->code_rate_LP = FEC_3_4; + break; + case 3: + c->code_rate_LP = FEC_5_6; + break; + case 4: + c->code_rate_LP = FEC_7_8; + break; + } + + ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]); + if (ret) + goto error; + + switch ((buf[0] >> 0) & 0x01) { + case 0: + c->inversion = INVERSION_OFF; + break; + case 1: + c->inversion = INVERSION_ON; + break; + } + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[3], start_ber = 0; + *ber = 0; + + if (priv->ber_running) { + ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf)); + if (ret) + goto error; + + if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) { + *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0]; + start_ber = 1; + } + } else { + priv->ber_running = 1; + start_ber = 1; + } + + if (start_ber) { + /* (re)start BER */ + ret = cxd2820r_wr_reg(priv, 0x00079, 0x01); + if (ret) + goto error; + } + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe, + u16 *strength) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + u16 tmp; + + ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf)); + if (ret) + goto error; + + tmp = (buf[0] & 0x0f) << 8 | buf[1]; + tmp = ~tmp & 0x0fff; + + /* scale value to 0x0000-0xffff from 0x0000-0x0fff */ + *strength = tmp * 0xffff / 0x0fff; + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + u16 tmp; + /* report SNR in dB * 10 */ + + ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf)); + if (ret) + goto error; + + tmp = (buf[0] & 0x1f) << 8 | buf[1]; + #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */ + if (tmp) + *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24) + / 100); + else + *snr = 0; + + dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp); + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + /* no way to read ? */ + return 0; +} + +int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[4]; + *status = 0; + + ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]); + if (ret) + goto error; + + if ((buf[0] & 0x07) == 6) { + ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]); + if (ret) + goto error; + + if (((buf[1] >> 3) & 0x01) == 1) { + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } else { + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC; + } + } else { + ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]); + if (ret) + goto error; + + if ((buf[2] & 0x0f) >= 4) { + ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]); + if (ret) + goto error; + + if (((buf[3] >> 4) & 0x01) == 1) + *status |= FE_HAS_SIGNAL; + } + } + + dbg("%s: lock=%02x %02x %02x %02x", __func__, + buf[0], buf[1], buf[2], buf[3]); + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_init_t(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret; + + ret = cxd2820r_wr_reg(priv, 0x00085, 0x07); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_sleep_t(struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = fe->demodulator_priv; + int ret, i; + struct reg_val_mask tab[] = { + { 0x000ff, 0x1f, 0xff }, + { 0x00085, 0x00, 0xff }, + { 0x00088, 0x01, 0xff }, + { 0x00081, 0x00, 0xff }, + { 0x00080, 0x00, 0xff }, + }; + + dbg("%s", __func__); + + priv->delivery_system = SYS_UNDEFINED; + + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val, + tab[i].mask); + if (ret) + goto error; + } + + return ret; +error: + dbg("%s: failed:%d", __func__, ret); + return ret; +} + +int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *s) +{ + s->min_delay_ms = 500; + s->step_size = fe->ops.info.frequency_stepsize * 2; + s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; + + return 0; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0070.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0070.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0070.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0070.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,757 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) + * + * 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, or (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * This code is more or less generated from another driver, please + * excuse some codingstyle oddities. + * + */ + +#include +#include +#include + +#include "dvb_frontend.h" + +#include "dib0070.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { \ + if (debug) { \ + printk(KERN_DEBUG "DiB0070: "); \ + printk(args); \ + printk("\n"); \ + } \ +} while (0) + +#define DIB0070_P1D 0x00 +#define DIB0070_P1F 0x01 +#define DIB0070_P1G 0x03 +#define DIB0070S_P1A 0x02 + +struct dib0070_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + const struct dib0070_config *cfg; + u16 wbd_ff_offset; + u8 revision; + + enum frontend_tune_state tune_state; + u32 current_rf; + + /* for the captrim binary search */ + s8 step; + u16 adc_diff; + + s8 captrim; + s8 fcaptrim; + u16 lo4; + + const struct dib0070_tuning *current_tune_table_index; + const struct dib0070_lna_match *lna_match; + + u8 wbd_gain_current; + u16 wbd_offset_3_3[2]; + + /* for the I2C transfer */ + struct i2c_msg msg[2]; + u8 i2c_write_buffer[3]; + u8 i2c_read_buffer[2]; +}; + +static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) +{ + state->i2c_write_buffer[0] = reg; + + memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); + state->msg[0].addr = state->cfg->i2c_address; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 1; + state->msg[1].addr = state->cfg->i2c_address; + state->msg[1].flags = I2C_M_RD; + state->msg[1].buf = state->i2c_read_buffer; + state->msg[1].len = 2; + + if (i2c_transfer(state->i2c, state->msg, 2) != 2) { + printk(KERN_WARNING "DiB0070 I2C read failed\n"); + return 0; + } + return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; +} + +static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) +{ + state->i2c_write_buffer[0] = reg; + state->i2c_write_buffer[1] = val >> 8; + state->i2c_write_buffer[2] = val & 0xff; + + memset(state->msg, 0, sizeof(struct i2c_msg)); + state->msg[0].addr = state->cfg->i2c_address; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 3; + + if (i2c_transfer(state->i2c, state->msg, 1) != 1) { + printk(KERN_WARNING "DiB0070 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +#define HARD_RESET(state) do { \ + state->cfg->sleep(state->fe, 0); \ + if (state->cfg->reset) { \ + state->cfg->reset(state->fe,1); msleep(10); \ + state->cfg->reset(state->fe,0); msleep(10); \ + } \ +} while (0) + +static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; + + if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000) + tmp |= (0 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000) + tmp |= (1 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000) + tmp |= (2 << 14); + else + tmp |= (3 << 14); + + dib0070_write_reg(state, 0x02, tmp); + + /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { + u16 value = dib0070_read_reg(state, 0x17); + + dib0070_write_reg(state, 0x17, value & 0xfffc); + tmp = dib0070_read_reg(state, 0x01) & 0x01ff; + dib0070_write_reg(state, 0x01, tmp | (60 << 9)); + + dib0070_write_reg(state, 0x17, value); + } + return 0; +} + +static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state) +{ + int8_t step_sign; + u16 adc; + int ret = 0; + + if (*tune_state == CT_TUNER_STEP_0) { + + dib0070_write_reg(state, 0x0f, 0xed10); + dib0070_write_reg(state, 0x17, 0x0034); + + dib0070_write_reg(state, 0x18, 0x0032); + state->step = state->captrim = state->fcaptrim = 64; + state->adc_diff = 3000; + ret = 20; + + *tune_state = CT_TUNER_STEP_1; + } else if (*tune_state == CT_TUNER_STEP_1) { + state->step /= 2; + dib0070_write_reg(state, 0x14, state->lo4 | state->captrim); + ret = 15; + + *tune_state = CT_TUNER_STEP_2; + } else if (*tune_state == CT_TUNER_STEP_2) { + + adc = dib0070_read_reg(state, 0x19); + + dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024); + + if (adc >= 400) { + adc -= 400; + step_sign = -1; + } else { + adc = 400 - adc; + step_sign = 1; + } + + if (adc < state->adc_diff) { + dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff); + state->adc_diff = adc; + state->fcaptrim = state->captrim; + + + + } + state->captrim += (step_sign * state->step); + + if (state->step >= 1) + *tune_state = CT_TUNER_STEP_1; + else + *tune_state = CT_TUNER_STEP_3; + + } else if (*tune_state == CT_TUNER_STEP_3) { + dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim); + dib0070_write_reg(state, 0x18, 0x07ff); + *tune_state = CT_TUNER_STEP_4; + } + + return ret; +} + +static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); + dprintk("CTRL_LO5: 0x%x", lo5); + return dib0070_write_reg(state, 0x15, lo5); +} + +void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) +{ + struct dib0070_state *state = fe->tuner_priv; + + if (open) { + dib0070_write_reg(state, 0x1b, 0xff00); + dib0070_write_reg(state, 0x1a, 0x0000); + } else { + dib0070_write_reg(state, 0x1b, 0x4112); + if (state->cfg->vga_filter != 0) { + dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); + dprintk("vga filter register is set to %x", state->cfg->vga_filter); + } else + dib0070_write_reg(state, 0x1a, 0x0009); + } +} + +EXPORT_SYMBOL(dib0070_ctrl_agc_filter); +struct dib0070_tuning { + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 switch_trim; + u8 vco_band; + u8 hfdiv; + u8 vco_multi; + u8 presc; + u8 wbdmux; + u16 tuner_enable; +}; + +struct dib0070_lna_match { + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 lna_band; +}; + +static const struct dib0070_tuning dib0070s_tuning_table[] = { + { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */ + { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 }, + { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 }, + { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */ + { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, + { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, + { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */ +}; + +static const struct dib0070_tuning dib0070_tuning_table[] = { + { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */ + { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */ + { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 }, + { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 }, + { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */ + { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 }, + { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 }, + { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */ +}; + +static const struct dib0070_lna_match dib0070_lna_flip_chip[] = { + { 180000, 0 }, /* VHF */ + { 188000, 1 }, + { 196400, 2 }, + { 250000, 3 }, + { 550000, 0 }, /* UHF */ + { 590000, 1 }, + { 666000, 3 }, + { 864000, 5 }, + { 1500000, 0 }, /* LBAND or everything higher than UHF */ + { 1600000, 1 }, + { 2000000, 3 }, + { 0xffffffff, 7 }, +}; + +static const struct dib0070_lna_match dib0070_lna[] = { + { 180000, 0 }, /* VHF */ + { 188000, 1 }, + { 196400, 2 }, + { 250000, 3 }, + { 550000, 2 }, /* UHF */ + { 650000, 3 }, + { 750000, 5 }, + { 850000, 6 }, + { 864000, 7 }, + { 1500000, 0 }, /* LBAND or everything higher than UHF */ + { 1600000, 1 }, + { 2000000, 3 }, + { 0xffffffff, 7 }, +}; + +#define LPF 100 +static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *state = fe->tuner_priv; + + const struct dib0070_tuning *tune; + const struct dib0070_lna_match *lna_match; + + enum frontend_tune_state *tune_state = &state->tune_state; + int ret = 10; /* 1ms is the default delay most of the time */ + + u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000); + u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); + +#ifdef CONFIG_SYS_ISDBT + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) + if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) + && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) + || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) + && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2))) + || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) + && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) + freq += 850; +#endif + if (state->current_rf != freq) { + + switch (state->revision) { + case DIB0070S_P1A: + tune = dib0070s_tuning_table; + lna_match = dib0070_lna; + break; + default: + tune = dib0070_tuning_table; + if (state->cfg->flip_chip) + lna_match = dib0070_lna_flip_chip; + else + lna_match = dib0070_lna; + break; + } + while (freq > tune->max_freq) /* find the right one */ + tune++; + while (freq > lna_match->max_freq) /* find the right one */ + lna_match++; + + state->current_tune_table_index = tune; + state->lna_match = lna_match; + } + + if (*tune_state == CT_TUNER_START) { + dprintk("Tuning for Band: %hd (%d kHz)", band, freq); + if (state->current_rf != freq) { + u8 REFDIV; + u32 FBDiv, Rest, FREF, VCOF_kHz; + u8 Den; + + state->current_rf = freq; + state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); + + + dib0070_write_reg(state, 0x17, 0x30); + + + VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; + + switch (band) { + case BAND_VHF: + REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); + break; + case BAND_FM: + REFDIV = (u8) ((state->cfg->clock_khz) / 1000); + break; + default: + REFDIV = (u8) (state->cfg->clock_khz / 10000); + break; + } + FREF = state->cfg->clock_khz / REFDIV; + + + + switch (state->revision) { + case DIB0070S_P1A: + FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); + Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; + break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + FBDiv = (freq / (FREF / 2)); + Rest = 2 * freq - FBDiv * FREF; + break; + } + + if (Rest < LPF) + Rest = 0; + else if (Rest < 2 * LPF) + Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { + Rest = 0; + FBDiv += 1; + } else if (Rest > (FREF - 2 * LPF)) + Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + + Den = 1; + if (Rest > 0) { + state->lo4 |= (1 << 14) | (1 << 12); + Den = 255; + } + + + dib0070_write_reg(state, 0x11, (u16)FBDiv); + dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); + dib0070_write_reg(state, 0x13, (u16) Rest); + + if (state->revision == DIB0070S_P1A) { + + if (band == BAND_SBAND) { + dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); + dib0070_write_reg(state, 0x1d, 0xFFFF); + } else + dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); + } + + dib0070_write_reg(state, 0x20, + 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); + + dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); + dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); + dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); + dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); + dprintk("VCO = %hd", state->current_tune_table_index->vco_band); + dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); + + *tune_state = CT_TUNER_STEP_0; + } else { /* we are already tuned to this frequency - the configuration is correct */ + ret = 50; /* wakeup time */ + *tune_state = CT_TUNER_STEP_5; + } + } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { + + ret = dib0070_captrim(state, tune_state); + + } else if (*tune_state == CT_TUNER_STEP_4) { + const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; + if (tmp != NULL) { + while (freq/1000 > tmp->freq) /* find the right one */ + tmp++; + dib0070_write_reg(state, 0x0f, + (0 << 15) | (1 << 14) | (3 << 12) + | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) + | (state->current_tune_table_index->wbdmux << 0)); + state->wbd_gain_current = tmp->wbd_gain_val; + } else { + dib0070_write_reg(state, 0x0f, + (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index-> + wbdmux << 0)); + state->wbd_gain_current = 6; + } + + dib0070_write_reg(state, 0x06, 0x3fff); + dib0070_write_reg(state, 0x07, + (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0)); + dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); + dib0070_write_reg(state, 0x0d, 0x0d80); + + + dib0070_write_reg(state, 0x18, 0x07ff); + dib0070_write_reg(state, 0x17, 0x0033); + + + *tune_state = CT_TUNER_STEP_5; + } else if (*tune_state == CT_TUNER_STEP_5) { + dib0070_set_bandwidth(fe, ch); + *tune_state = CT_TUNER_STOP; + } else { + ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ + } + return ret; +} + + +static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct dib0070_state *state = fe->tuner_priv; + uint32_t ret; + + state->tune_state = CT_TUNER_START; + + do { + ret = dib0070_tune_digital(fe, p); + if (ret != FE_CALLBACK_TIME_NEVER) + msleep(ret/10); + else + break; + } while (state->tune_state != CT_TUNER_STOP); + + return 0; +} + +static int dib0070_wakeup(struct dvb_frontend *fe) +{ + struct dib0070_state *state = fe->tuner_priv; + if (state->cfg->sleep) + state->cfg->sleep(fe, 0); + return 0; +} + +static int dib0070_sleep(struct dvb_frontend *fe) +{ + struct dib0070_state *state = fe->tuner_priv; + if (state->cfg->sleep) + state->cfg->sleep(fe, 1); + return 0; +} + +u8 dib0070_get_rf_output(struct dvb_frontend *fe) +{ + struct dib0070_state *state = fe->tuner_priv; + return (dib0070_read_reg(state, 0x07) >> 11) & 0x3; +} +EXPORT_SYMBOL(dib0070_get_rf_output); + +int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff; + if (no > 3) + no = 3; + if (no < 1) + no = 1; + return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11)); +} +EXPORT_SYMBOL(dib0070_set_rf_output); + +static const u16 dib0070_p1f_defaults[] = + +{ + 7, 0x02, + 0x0008, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0002, + 0x0100, + + 3, 0x0d, + 0x0d80, + 0x0001, + 0x0000, + + 4, 0x11, + 0x0000, + 0x0103, + 0x0000, + 0x0000, + + 3, 0x16, + 0x0004 | 0x0040, + 0x0030, + 0x07ff, + + 6, 0x1b, + 0x4112, + 0xff00, + 0xc07f, + 0x0000, + 0x0180, + 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, + + 0, +}; + +static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain) +{ + u16 tuner_en = dib0070_read_reg(state, 0x20); + u16 offset; + + dib0070_write_reg(state, 0x18, 0x07ff); + dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); + dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); + msleep(9); + offset = dib0070_read_reg(state, 0x19); + dib0070_write_reg(state, 0x20, tuner_en); + return offset; +} + +static void dib0070_wbd_offset_calibration(struct dib0070_state *state) +{ + u8 gain; + for (gain = 6; gain < 8; gain++) { + state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); + dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]); + } +} + +u16 dib0070_wbd_offset(struct dvb_frontend *fe) +{ + struct dib0070_state *state = fe->tuner_priv; + const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; + u32 freq = fe->dtv_property_cache.frequency/1000; + + if (tmp != NULL) { + while (freq/1000 > tmp->freq) /* find the right one */ + tmp++; + state->wbd_gain_current = tmp->wbd_gain_val; + } else + state->wbd_gain_current = 6; + + return state->wbd_offset_3_3[state->wbd_gain_current - 6]; +} +EXPORT_SYMBOL(dib0070_wbd_offset); + +#define pgm_read_word(w) (*w) +static int dib0070_reset(struct dvb_frontend *fe) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 l, r, *n; + + HARD_RESET(state); + + +#ifndef FORCE_SBAND_TUNER + if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) + state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; + else +#else +#warning forcing SBAND +#endif + state->revision = DIB0070S_P1A; + + /* P1F or not */ + dprintk("Revision: %x", state->revision); + + if (state->revision == DIB0070_P1D) { + dprintk("Error: this driver is not to be used meant for P1D or earlier"); + return -EINVAL; + } + + n = (u16 *) dib0070_p1f_defaults; + l = pgm_read_word(n++); + while (l) { + r = pgm_read_word(n++); + do { + dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); + r++; + } while (--l); + l = pgm_read_word(n++); + } + + if (state->cfg->force_crystal_mode != 0) + r = state->cfg->force_crystal_mode; + else if (state->cfg->clock_khz >= 24000) + r = 1; + else + r = 2; + + + r |= state->cfg->osc_buffer_state << 3; + + dib0070_write_reg(state, 0x10, r); + dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5)); + + if (state->cfg->invert_iq) { + r = dib0070_read_reg(state, 0x02) & 0xffdf; + dib0070_write_reg(state, 0x02, r | (1 << 5)); + } + + if (state->revision == DIB0070S_P1A) + dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); + else + dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter); + + dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); + + dib0070_wbd_offset_calibration(state); + + return 0; +} + +static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dib0070_state *state = fe->tuner_priv; + + *frequency = 1000 * state->current_rf; + return 0; +} + +static int dib0070_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops dib0070_ops = { + .info = { + .name = "DiBcom DiB0070", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0070_release, + + .init = dib0070_wakeup, + .sleep = dib0070_sleep, + .set_params = dib0070_tune, + + .get_frequency = dib0070_get_frequency, +// .get_bandwidth = dib0070_get_bandwidth +}; + +struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) +{ + struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->cfg = cfg; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + + if (dib0070_reset(fe) != 0) + goto free_mem; + + printk(KERN_INFO "DiB0070: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; + +free_mem: + kfree(state); + fe->tuner_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(dib0070_attach); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0070.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0070.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0070.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0070.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,76 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#ifndef DIB0070_H +#define DIB0070_H + +struct dvb_frontend; +struct i2c_adapter; + +#define DEFAULT_DIB0070_I2C_ADDRESS 0x60 + +struct dib0070_wbd_gain_cfg { + u16 freq; + u16 wbd_gain_val; +}; + +struct dib0070_config { + u8 i2c_address; + + /* tuner pins controlled externally */ + int (*reset) (struct dvb_frontend *, int); + int (*sleep) (struct dvb_frontend *, int); + + /* offset in kHz */ + int freq_offset_khz_uhf; + int freq_offset_khz_vhf; + + u8 osc_buffer_state; /* 0= normal, 1= tri-state */ + u32 clock_khz; + u8 clock_pad_drive; /* (Drive + 1) * 2mA */ + + u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */ + + u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */ + + u8 flip_chip; + u8 enable_third_order_filter; + u8 charge_pump; + + const struct dib0070_wbd_gain_cfg *wbd_gain; + + u8 vga_filter; +}; + +#if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE)) +extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); +extern u16 dib0070_wbd_offset(struct dvb_frontend *); +extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open); +extern u8 dib0070_get_rf_output(struct dvb_frontend *fe); +extern int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no); +#else +static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0090.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0090.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0090.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0090.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2493 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. + * + * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) + * + * 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, or (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * This code is more or less generated from another driver, please + * excuse some codingstyle oddities. + * + */ + +#include +#include +#include + +#include "dvb_frontend.h" + +#include "dib0090.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { \ + if (debug) { \ + printk(KERN_DEBUG "DiB0090: "); \ + printk(args); \ + printk("\n"); \ + } \ +} while (0) + +#define CONFIG_SYS_DVBT +#define CONFIG_SYS_ISDBT +#define CONFIG_BAND_CBAND +#define CONFIG_BAND_VHF +#define CONFIG_BAND_UHF +#define CONFIG_DIB0090_USE_PWM_AGC + +#define EN_LNA0 0x8000 +#define EN_LNA1 0x4000 +#define EN_LNA2 0x2000 +#define EN_LNA3 0x1000 +#define EN_MIX0 0x0800 +#define EN_MIX1 0x0400 +#define EN_MIX2 0x0200 +#define EN_MIX3 0x0100 +#define EN_IQADC 0x0040 +#define EN_PLL 0x0020 +#define EN_TX 0x0010 +#define EN_BB 0x0008 +#define EN_LO 0x0004 +#define EN_BIAS 0x0001 + +#define EN_IQANA 0x0002 +#define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */ +#define EN_CRYSTAL 0x0002 + +#define EN_UHF 0x22E9 +#define EN_VHF 0x44E9 +#define EN_LBD 0x11E9 +#define EN_SBD 0x44E9 +#define EN_CAB 0x88E9 + +/* Calibration defines */ +#define DC_CAL 0x1 +#define WBD_CAL 0x2 +#define TEMP_CAL 0x4 +#define CAPTRIM_CAL 0x8 + +#define KROSUS_PLL_LOCKED 0x800 +#define KROSUS 0x2 + +/* Use those defines to identify SOC version */ +#define SOC 0x02 +#define SOC_7090_P1G_11R1 0x82 +#define SOC_7090_P1G_21R1 0x8a +#define SOC_8090_P1G_11R1 0x86 +#define SOC_8090_P1G_21R1 0x8e + +/* else use thos ones to check */ +#define P1A_B 0x0 +#define P1C 0x1 +#define P1D_E_F 0x3 +#define P1G 0x7 +#define P1G_21R2 0xf + +#define MP001 0x1 /* Single 9090/8096 */ +#define MP005 0x4 /* Single Sband */ +#define MP008 0x6 /* Dual diversity VHF-UHF-LBAND */ +#define MP009 0x7 /* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */ + +#define pgm_read_word(w) (*w) + +struct dc_calibration; + +struct dib0090_tuning { + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 switch_trim; + u8 lna_tune; + u16 lna_bias; + u16 v2i; + u16 mix; + u16 load; + u16 tuner_enable; +}; + +struct dib0090_pll { + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 vco_band; + u8 hfdiv_code; + u8 hfdiv; + u8 topresc; +}; + +struct dib0090_identity { + u8 version; + u8 product; + u8 p1g; + u8 in_soc; +}; + +struct dib0090_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + const struct dib0090_config *config; + + u8 current_band; + enum frontend_tune_state tune_state; + u32 current_rf; + + u16 wbd_offset; + s16 wbd_target; /* in dB */ + + s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */ + s16 current_gain; /* keeps the currently programmed gain */ + u8 agc_step; /* new binary search */ + + u16 gain[2]; /* for channel monitoring */ + + const u16 *rf_ramp; + const u16 *bb_ramp; + + /* for the software AGC ramps */ + u16 bb_1_def; + u16 rf_lt_def; + u16 gain_reg[4]; + + /* for the captrim/dc-offset search */ + s8 step; + s16 adc_diff; + s16 min_adc_diff; + + s8 captrim; + s8 fcaptrim; + + const struct dc_calibration *dc; + u16 bb6, bb7; + + const struct dib0090_tuning *current_tune_table_index; + const struct dib0090_pll *current_pll_table_index; + + u8 tuner_is_tuned; + u8 agc_freeze; + + struct dib0090_identity identity; + + u32 rf_request; + u8 current_standard; + + u8 calibrate; + u32 rest; + u16 bias; + s16 temperature; + + u8 wbd_calibration_gain; + const struct dib0090_wbd_slope *current_wbd_table; + u16 wbdmux; + + /* for the I2C transfer */ + struct i2c_msg msg[2]; + u8 i2c_write_buffer[3]; + u8 i2c_read_buffer[2]; +}; + +struct dib0090_fw_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + struct dib0090_identity identity; + const struct dib0090_config *config; + + /* for the I2C transfer */ + struct i2c_msg msg; + u8 i2c_write_buffer[2]; + u8 i2c_read_buffer[2]; +}; + +static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) +{ + state->i2c_write_buffer[0] = reg; + + memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); + state->msg[0].addr = state->config->i2c_address; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 1; + state->msg[1].addr = state->config->i2c_address; + state->msg[1].flags = I2C_M_RD; + state->msg[1].buf = state->i2c_read_buffer; + state->msg[1].len = 2; + + if (i2c_transfer(state->i2c, state->msg, 2) != 2) { + printk(KERN_WARNING "DiB0090 I2C read failed\n"); + return 0; + } + + return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; +} + +static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) +{ + state->i2c_write_buffer[0] = reg & 0xff; + state->i2c_write_buffer[1] = val >> 8; + state->i2c_write_buffer[2] = val & 0xff; + + memset(state->msg, 0, sizeof(struct i2c_msg)); + state->msg[0].addr = state->config->i2c_address; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 3; + + if (i2c_transfer(state->i2c, state->msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) +{ + state->i2c_write_buffer[0] = reg; + + memset(&state->msg, 0, sizeof(struct i2c_msg)); + state->msg.addr = reg; + state->msg.flags = I2C_M_RD; + state->msg.buf = state->i2c_read_buffer; + state->msg.len = 2; + if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C read failed\n"); + return 0; + } + return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; +} + +static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) +{ + state->i2c_write_buffer[0] = val >> 8; + state->i2c_write_buffer[1] = val & 0xff; + + memset(&state->msg, 0, sizeof(struct i2c_msg)); + state->msg.addr = reg; + state->msg.flags = 0; + state->msg.buf = state->i2c_write_buffer; + state->msg.len = 2; + if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +#define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0) +#define ADC_TARGET -220 +#define GAIN_ALPHA 5 +#define WBD_ALPHA 6 +#define LPF 100 +static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c) +{ + do { + dib0090_write_reg(state, r++, *b++); + } while (--c); +} + +static int dib0090_identify(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + u16 v; + struct dib0090_identity *identity = &state->identity; + + v = dib0090_read_reg(state, 0x1a); + + identity->p1g = 0; + identity->in_soc = 0; + + dprintk("Tuner identification (Version = 0x%04x)", v); + + /* without PLL lock info */ + v &= ~KROSUS_PLL_LOCKED; + + identity->version = v & 0xff; + identity->product = (v >> 8) & 0xf; + + if (identity->product != KROSUS) + goto identification_error; + + if ((identity->version & 0x3) == SOC) { + identity->in_soc = 1; + switch (identity->version) { + case SOC_8090_P1G_11R1: + dprintk("SOC 8090 P1-G11R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_8090_P1G_21R1: + dprintk("SOC 8090 P1-G21R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_7090_P1G_11R1: + dprintk("SOC 7090 P1-G11R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_7090_P1G_21R1: + dprintk("SOC 7090 P1-G21R1 Has been detected"); + identity->p1g = 1; + break; + default: + goto identification_error; + } + } else { + switch ((identity->version >> 5) & 0x7) { + case MP001: + dprintk("MP001 : 9090/8096"); + break; + case MP005: + dprintk("MP005 : Single Sband"); + break; + case MP008: + dprintk("MP008 : diversity VHF-UHF-LBAND"); + break; + case MP009: + dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND"); + break; + default: + goto identification_error; + } + + switch (identity->version & 0x1f) { + case P1G_21R2: + dprintk("P1G_21R2 detected"); + identity->p1g = 1; + break; + case P1G: + dprintk("P1G detected"); + identity->p1g = 1; + break; + case P1D_E_F: + dprintk("P1D/E/F detected"); + break; + case P1C: + dprintk("P1C detected"); + break; + case P1A_B: + dprintk("P1-A/B detected: driver is deactivated - not available"); + goto identification_error; + break; + default: + goto identification_error; + } + } + + return 0; + +identification_error: + return -EIO; +} + +static int dib0090_fw_identify(struct dvb_frontend *fe) +{ + struct dib0090_fw_state *state = fe->tuner_priv; + struct dib0090_identity *identity = &state->identity; + + u16 v = dib0090_fw_read_reg(state, 0x1a); + identity->p1g = 0; + identity->in_soc = 0; + + dprintk("FE: Tuner identification (Version = 0x%04x)", v); + + /* without PLL lock info */ + v &= ~KROSUS_PLL_LOCKED; + + identity->version = v & 0xff; + identity->product = (v >> 8) & 0xf; + + if (identity->product != KROSUS) + goto identification_error; + + if ((identity->version & 0x3) == SOC) { + identity->in_soc = 1; + switch (identity->version) { + case SOC_8090_P1G_11R1: + dprintk("SOC 8090 P1-G11R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_8090_P1G_21R1: + dprintk("SOC 8090 P1-G21R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_7090_P1G_11R1: + dprintk("SOC 7090 P1-G11R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_7090_P1G_21R1: + dprintk("SOC 7090 P1-G21R1 Has been detected"); + identity->p1g = 1; + break; + default: + goto identification_error; + } + } else { + switch ((identity->version >> 5) & 0x7) { + case MP001: + dprintk("MP001 : 9090/8096"); + break; + case MP005: + dprintk("MP005 : Single Sband"); + break; + case MP008: + dprintk("MP008 : diversity VHF-UHF-LBAND"); + break; + case MP009: + dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND"); + break; + default: + goto identification_error; + } + + switch (identity->version & 0x1f) { + case P1G_21R2: + dprintk("P1G_21R2 detected"); + identity->p1g = 1; + break; + case P1G: + dprintk("P1G detected"); + identity->p1g = 1; + break; + case P1D_E_F: + dprintk("P1D/E/F detected"); + break; + case P1C: + dprintk("P1C detected"); + break; + case P1A_B: + dprintk("P1-A/B detected: driver is deactivated - not available"); + goto identification_error; + break; + default: + goto identification_error; + } + } + + return 0; + +identification_error: + return -EIO;; +} + +static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) +{ + struct dib0090_state *state = fe->tuner_priv; + u16 PllCfg, i, v; + + HARD_RESET(state); + + dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL); + dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ + + if (!cfg->in_soc) { + /* adcClkOutRatio=8->7, release reset */ + dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); + if (cfg->clkoutdrive != 0) + dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) + | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); + else + dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) + | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); + } + + /* Read Pll current config * */ + PllCfg = dib0090_read_reg(state, 0x21); + + /** Reconfigure PLL if current setting is different from default setting **/ + if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc) + && !cfg->io.pll_bypass) { + + /* Set Bypass mode */ + PllCfg |= (1 << 15); + dib0090_write_reg(state, 0x21, PllCfg); + + /* Set Reset Pll */ + PllCfg &= ~(1 << 13); + dib0090_write_reg(state, 0x21, PllCfg); + + /*** Set new Pll configuration in bypass and reset state ***/ + PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv); + dib0090_write_reg(state, 0x21, PllCfg); + + /* Remove Reset Pll */ + PllCfg |= (1 << 13); + dib0090_write_reg(state, 0x21, PllCfg); + + /*** Wait for PLL lock ***/ + i = 100; + do { + v = !!(dib0090_read_reg(state, 0x1a) & 0x800); + if (v) + break; + } while (--i); + + if (i == 0) { + dprintk("Pll: Unable to lock Pll"); + return; + } + + /* Finally Remove Bypass mode */ + PllCfg &= ~(1 << 15); + dib0090_write_reg(state, 0x21, PllCfg); + } + + if (cfg->io.pll_bypass) { + PllCfg |= (cfg->io.pll_bypass << 15); + dib0090_write_reg(state, 0x21, PllCfg); + } +} + +static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) +{ + struct dib0090_fw_state *state = fe->tuner_priv; + u16 PllCfg; + u16 v; + int i; + + dprintk("fw reset digital"); + HARD_RESET(state); + + dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL); + dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ + + dib0090_fw_write_reg(state, 0x20, + ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv); + + v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0); + if (cfg->clkoutdrive != 0) + v |= cfg->clkoutdrive << 5; + else + v |= 7 << 5; + + v |= 2 << 10; + dib0090_fw_write_reg(state, 0x23, v); + + /* Read Pll current config * */ + PllCfg = dib0090_fw_read_reg(state, 0x21); + + /** Reconfigure PLL if current setting is different from default setting **/ + if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) { + + /* Set Bypass mode */ + PllCfg |= (1 << 15); + dib0090_fw_write_reg(state, 0x21, PllCfg); + + /* Set Reset Pll */ + PllCfg &= ~(1 << 13); + dib0090_fw_write_reg(state, 0x21, PllCfg); + + /*** Set new Pll configuration in bypass and reset state ***/ + PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv); + dib0090_fw_write_reg(state, 0x21, PllCfg); + + /* Remove Reset Pll */ + PllCfg |= (1 << 13); + dib0090_fw_write_reg(state, 0x21, PllCfg); + + /*** Wait for PLL lock ***/ + i = 100; + do { + v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800); + if (v) + break; + } while (--i); + + if (i == 0) { + dprintk("Pll: Unable to lock Pll"); + return -EIO; + } + + /* Finally Remove Bypass mode */ + PllCfg &= ~(1 << 15); + dib0090_fw_write_reg(state, 0x21, PllCfg); + } + + if (cfg->io.pll_bypass) { + PllCfg |= (cfg->io.pll_bypass << 15); + dib0090_fw_write_reg(state, 0x21, PllCfg); + } + + return dib0090_fw_identify(fe); +} + +static int dib0090_wakeup(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + if (state->config->sleep) + state->config->sleep(fe, 0); + + /* enable dataTX in case we have been restarted in the wrong moment */ + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); + return 0; +} + +static int dib0090_sleep(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + if (state->config->sleep) + state->config->sleep(fe, 1); + return 0; +} + +void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) +{ + struct dib0090_state *state = fe->tuner_priv; + if (fast) + dib0090_write_reg(state, 0x04, 0); + else + dib0090_write_reg(state, 0x04, 1); +} + +EXPORT_SYMBOL(dib0090_dcc_freq); + +static const u16 bb_ramp_pwm_normal_socs[] = { + 550, /* max BB gain in 10th of dB */ + (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */ + 440, + (4 << 9) | 0, /* BB_RAMP3 = 26dB */ + (0 << 9) | 208, /* BB_RAMP4 */ + (4 << 9) | 208, /* BB_RAMP5 = 29dB */ + (0 << 9) | 440, /* BB_RAMP6 */ +}; + +static const u16 rf_ramp_pwm_cband_7090[] = { + 280, /* max RF gain in 10th of dB */ + 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 504, /* ramp_max = maximum X used on the ramp */ + (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */ + (0 << 10) | 504, /* RF_RAMP6, LNA 1 */ + (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */ + (0 << 10) | 364, /* RF_RAMP8, LNA 2 */ + (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */ + (0 << 10) | 228, /* GAIN_4_2, LNA 3 */ + (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ + (0 << 10) | 109, /* RF_RAMP4, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_cband_8090[] = { + 345, /* max RF gain in 10th of dB */ + 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 1000, /* ramp_max = maximum X used on the ramp */ + (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */ + (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */ + (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */ + (0 << 10) | 772, /* RF_RAMP6, LNA 2 */ + (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */ + (0 << 10) | 496, /* RF_RAMP8, LNA 3 */ + (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */ + (0 << 10) | 200, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_uhf_7090[] = { + 407, /* max RF gain in 10th of dB */ + 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 529, /* ramp_max = maximum X used on the ramp */ + (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ + (0 << 10) | 176, /* RF_RAMP4, LNA 1 */ + (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */ + (0 << 10) | 529, /* RF_RAMP6, LNA 2 */ + (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */ + (0 << 10) | 400, /* RF_RAMP8, LNA 3 */ + (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */ + (0 << 10) | 316, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_uhf_8090[] = { + 388, /* max RF gain in 10th of dB */ + 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 1008, /* ramp_max = maximum X used on the ramp */ + (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ + (0 << 10) | 369, /* RF_RAMP4, LNA 1 */ + (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */ + (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */ + (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */ + (0 << 10) | 809, /* RF_RAMP8, LNA 3 */ + (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */ + (0 << 10) | 659, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_cband[] = { + 0, /* max RF gain in 10th of dB */ + 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ + 0, /* ramp_max = maximum X used on the ramp */ + (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */ + (0 << 10) | 0, /* 0x2d, LNA 1 */ + (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */ + (0 << 10) | 0, /* 0x2f, LNA 2 */ + (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */ + (0 << 10) | 0, /* 0x31, LNA 3 */ + (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ + (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_vhf[] = { + 412, /* max RF gain in 10th of dB */ + 132, 307, 127, /* LNA1, 13.2dB */ + 105, 412, 255, /* LNA2, 10.5dB */ + 50, 50, 127, /* LNA3, 5dB */ + 125, 175, 127, /* LNA4, 12.5dB */ + 0, 0, 127, /* CBAND, 0dB */ +}; + +static const u16 rf_ramp_uhf[] = { + 412, /* max RF gain in 10th of dB */ + 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */ + 105, 412, 255, /* LNA2 : 10.5 dB */ + 50, 50, 127, /* LNA3 : 5.0 dB */ + 125, 175, 127, /* LNA4 : 12.5 dB */ + 0, 0, 127, /* CBAND : 0.0 dB */ +}; + +static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */ +{ + 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */ + 84, 314, 127, /* LNA1 */ + 80, 230, 255, /* LNA2 */ + 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */ + 70, 70, 127, /* LNA4 */ + 0, 0, 127, /* CBAND */ +}; + +static const u16 rf_ramp_cband[] = { + 332, /* max RF gain in 10th of dB */ + 132, 252, 127, /* LNA1, dB */ + 80, 332, 255, /* LNA2, dB */ + 0, 0, 127, /* LNA3, dB */ + 0, 0, 127, /* LNA4, dB */ + 120, 120, 127, /* LT1 CBAND */ +}; + +static const u16 rf_ramp_pwm_vhf[] = { + 404, /* max RF gain in 10th of dB */ + 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ + 1011, /* ramp_max = maximum X used on the ramp */ + (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ + (0 << 10) | 756, /* 0x2d, LNA 1 */ + (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ + (0 << 10) | 1011, /* 0x2f, LNA 2 */ + (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */ + (0 << 10) | 417, /* 0x31, LNA 3 */ + (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */ + (0 << 10) | 290, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_uhf[] = { + 404, /* max RF gain in 10th of dB */ + 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ + 1011, /* ramp_max = maximum X used on the ramp */ + (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ + (0 << 10) | 756, /* 0x2d, LNA 1 */ + (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ + (0 << 10) | 1011, /* 0x2f, LNA 2 */ + (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */ + (0 << 10) | 127, /* 0x31, LNA 3 */ + (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */ + (0 << 10) | 417, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 bb_ramp_boost[] = { + 550, /* max BB gain in 10th of dB */ + 260, 260, 26, /* BB1, 26dB */ + 290, 550, 29, /* BB2, 29dB */ +}; + +static const u16 bb_ramp_pwm_normal[] = { + 500, /* max RF gain in 10th of dB */ + 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */ + 400, + (2 << 9) | 0, /* 0x35 = 21dB */ + (0 << 9) | 168, /* 0x36 */ + (2 << 9) | 168, /* 0x37 = 29dB */ + (0 << 9) | 400, /* 0x38 */ +}; + +struct slope { + s16 range; + s16 slope; +}; +static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val) +{ + u8 i; + u16 rest; + u16 ret = 0; + for (i = 0; i < num; i++) { + if (val > slopes[i].range) + rest = slopes[i].range; + else + rest = val; + ret += (rest * slopes[i].slope) / slopes[i].range; + val -= rest; + } + return ret; +} + +static const struct slope dib0090_wbd_slopes[3] = { + {66, 120}, /* -64,-52: offset - 65 */ + {600, 170}, /* -52,-35: 65 - 665 */ + {170, 250}, /* -45,-10: 665 - 835 */ +}; + +static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd) +{ + wbd &= 0x3ff; + if (wbd < state->wbd_offset) + wbd = 0; + else + wbd -= state->wbd_offset; + /* -64dB is the floor */ + return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd); +} + +static void dib0090_wbd_target(struct dib0090_state *state, u32 rf) +{ + u16 offset = 250; + + /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */ + + if (state->current_band == BAND_VHF) + offset = 650; +#ifndef FIRMWARE_FIREFLY + if (state->current_band == BAND_VHF) + offset = state->config->wbd_vhf_offset; + if (state->current_band == BAND_CBAND) + offset = state->config->wbd_cband_offset; +#endif + + state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset); + dprintk("wbd-target: %d dB", (u32) state->wbd_target); +} + +static const int gain_reg_addr[4] = { + 0x08, 0x0a, 0x0f, 0x01 +}; + +static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force) +{ + u16 rf, bb, ref; + u16 i, v, gain_reg[4] = { 0 }, gain; + const u16 *g; + + if (top_delta < -511) + top_delta = -511; + if (top_delta > 511) + top_delta = 511; + + if (force) { + top_delta *= (1 << WBD_ALPHA); + gain_delta *= (1 << GAIN_ALPHA); + } + + if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */ + state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; + else + state->rf_gain_limit += top_delta; + + if (state->rf_gain_limit < 0) /*underflow */ + state->rf_gain_limit = 0; + + /* use gain as a temporary variable and correct current_gain */ + gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA; + if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */ + state->current_gain = gain; + else + state->current_gain += gain_delta; + /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */ + if (state->current_gain < 0) + state->current_gain = 0; + + /* now split total gain to rf and bb gain */ + gain = state->current_gain >> GAIN_ALPHA; + + /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */ + if (gain > (state->rf_gain_limit >> WBD_ALPHA)) { + rf = state->rf_gain_limit >> WBD_ALPHA; + bb = gain - rf; + if (bb > state->bb_ramp[0]) + bb = state->bb_ramp[0]; + } else { /* high signal level -> all gains put on RF */ + rf = gain; + bb = 0; + } + + state->gain[0] = rf; + state->gain[1] = bb; + + /* software ramp */ + /* Start with RF gains */ + g = state->rf_ramp + 1; /* point on RF LNA1 max gain */ + ref = rf; + for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */ + if (g[0] == 0 || ref < (g[1] - g[0])) /* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */ + v = 0; /* force the gain to write for the current amp to be null */ + else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */ + v = g[2]; /* force this amp to be full gain */ + else /* compute the value to set to this amp because we are somewhere in his range */ + v = ((ref - (g[1] - g[0])) * g[2]) / g[0]; + + if (i == 0) /* LNA 1 reg mapping */ + gain_reg[0] = v; + else if (i == 1) /* LNA 2 reg mapping */ + gain_reg[0] |= v << 7; + else if (i == 2) /* LNA 3 reg mapping */ + gain_reg[1] = v; + else if (i == 3) /* LNA 4 reg mapping */ + gain_reg[1] |= v << 7; + else if (i == 4) /* CBAND LNA reg mapping */ + gain_reg[2] = v | state->rf_lt_def; + else if (i == 5) /* BB gain 1 reg mapping */ + gain_reg[3] = v << 3; + else if (i == 6) /* BB gain 2 reg mapping */ + gain_reg[3] |= v << 8; + + g += 3; /* go to next gain bloc */ + + /* When RF is finished, start with BB */ + if (i == 4) { + g = state->bb_ramp + 1; /* point on BB gain 1 max gain */ + ref = bb; + } + } + gain_reg[3] |= state->bb_1_def; + gain_reg[3] |= ((bb % 10) * 100) / 125; + +#ifdef DEBUG_AGC + dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb, + gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]); +#endif + + /* Write the amplifier regs */ + for (i = 0; i < 4; i++) { + v = gain_reg[i]; + if (force || state->gain_reg[i] != v) { + state->gain_reg[i] = v; + dib0090_write_reg(state, gain_reg_addr[i], v); + } + } +} + +static void dib0090_set_boost(struct dib0090_state *state, int onoff) +{ + state->bb_1_def &= 0xdfff; + state->bb_1_def |= onoff << 13; +} + +static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg) +{ + state->rf_ramp = cfg; +} + +static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg) +{ + state->rf_ramp = cfg; + + dib0090_write_reg(state, 0x2a, 0xffff); + + dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a)); + + dib0090_write_regs(state, 0x2c, cfg + 3, 6); + dib0090_write_regs(state, 0x3e, cfg + 9, 2); +} + +static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg) +{ + state->bb_ramp = cfg; + dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ +} + +static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg) +{ + state->bb_ramp = cfg; + + dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ + + dib0090_write_reg(state, 0x33, 0xffff); + dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33)); + dib0090_write_regs(state, 0x35, cfg + 3, 4); +} + +void dib0090_pwm_gain_reset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + /* reset the AGC */ + + if (state->config->use_pwm_agc) { +#ifdef CONFIG_BAND_SBAND + if (state->current_band == BAND_SBAND) { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost); + } else +#endif +#ifdef CONFIG_BAND_CBAND + if (state->current_band == BAND_CBAND) { + if (state->identity.in_soc) { + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); + if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090); + else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090); + } else { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } + } else +#endif +#ifdef CONFIG_BAND_VHF + if (state->current_band == BAND_VHF) { + if (state->identity.in_soc) { + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); + } else { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } + } else +#endif + { + if (state->identity.in_soc) { + if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090); + else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); + } else { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } + } + + if (state->rf_ramp[0] != 0) + dib0090_write_reg(state, 0x32, (3 << 11)); + else + dib0090_write_reg(state, 0x32, (0 << 11)); + + dib0090_write_reg(state, 0x04, 0x01); + dib0090_write_reg(state, 0x39, (1 << 10)); + } +} + +EXPORT_SYMBOL(dib0090_pwm_gain_reset); + +static u32 dib0090_get_slow_adc_val(struct dib0090_state *state) +{ + u16 adc_val = dib0090_read_reg(state, 0x1d); + if (state->identity.in_soc) + adc_val >>= 2; + return adc_val; +} + +int dib0090_gain_control(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + enum frontend_tune_state *tune_state = &state->tune_state; + int ret = 10; + + u16 wbd_val = 0; + u8 apply_gain_immediatly = 1; + s16 wbd_error = 0, adc_error = 0; + + if (*tune_state == CT_AGC_START) { + state->agc_freeze = 0; + dib0090_write_reg(state, 0x04, 0x0); + +#ifdef CONFIG_BAND_SBAND + if (state->current_band == BAND_SBAND) { + dib0090_set_rframp(state, rf_ramp_sband); + dib0090_set_bbramp(state, bb_ramp_boost); + } else +#endif +#ifdef CONFIG_BAND_VHF + if (state->current_band == BAND_VHF && !state->identity.p1g) { + dib0090_set_rframp(state, rf_ramp_vhf); + dib0090_set_bbramp(state, bb_ramp_boost); + } else +#endif +#ifdef CONFIG_BAND_CBAND + if (state->current_band == BAND_CBAND && !state->identity.p1g) { + dib0090_set_rframp(state, rf_ramp_cband); + dib0090_set_bbramp(state, bb_ramp_boost); + } else +#endif + if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) { + dib0090_set_rframp(state, rf_ramp_cband_broadmatching); + dib0090_set_bbramp(state, bb_ramp_boost); + } else { + dib0090_set_rframp(state, rf_ramp_uhf); + dib0090_set_bbramp(state, bb_ramp_boost); + } + + dib0090_write_reg(state, 0x32, 0); + dib0090_write_reg(state, 0x39, 0); + + dib0090_wbd_target(state, state->current_rf); + + state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; + state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA; + + *tune_state = CT_AGC_STEP_0; + } else if (!state->agc_freeze) { + s16 wbd = 0, i, cnt; + + int adc; + wbd_val = dib0090_get_slow_adc_val(state); + + if (*tune_state == CT_AGC_STEP_0) + cnt = 5; + else + cnt = 1; + + for (i = 0; i < cnt; i++) { + wbd_val = dib0090_get_slow_adc_val(state); + wbd += dib0090_wbd_to_db(state, wbd_val); + } + wbd /= cnt; + wbd_error = state->wbd_target - wbd; + + if (*tune_state == CT_AGC_STEP_0) { + if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) { +#ifdef CONFIG_BAND_CBAND + /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */ + u8 ltg2 = (state->rf_lt_def >> 10) & 0x7; + if (state->current_band == BAND_CBAND && ltg2) { + ltg2 >>= 1; + state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */ + } +#endif + } else { + state->agc_step = 0; + *tune_state = CT_AGC_STEP_1; + } + } else { + /* calc the adc power */ + adc = state->config->get_adc_power(fe); + adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */ + + adc_error = (s16) (((s32) ADC_TARGET) - adc); +#ifdef CONFIG_STANDARD_DAB + if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) + adc_error -= 10; +#endif +#ifdef CONFIG_STANDARD_DVBT + if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT && + (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16)) + adc_error += 60; +#endif +#ifdef CONFIG_SYS_ISDBT + if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[0].modulation == + QAM_64) + || (state->fe->dtv_property_cache. + layer[0].modulation == QAM_16))) + || + ((state->fe->dtv_property_cache.layer[1].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[1].modulation == + QAM_64) + || (state->fe->dtv_property_cache. + layer[1].modulation == QAM_16))) + || + ((state->fe->dtv_property_cache.layer[2].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[2].modulation == + QAM_64) + || (state->fe->dtv_property_cache. + layer[2].modulation == QAM_16))) + ) + ) + adc_error += 60; +#endif + + if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */ + if (ABS(adc_error) < 50 || state->agc_step++ > 5) { + +#ifdef CONFIG_STANDARD_DAB + if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) { + dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */ + dib0090_write_reg(state, 0x04, 0x0); + } else +#endif + { + dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32)); + dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */ + } + + *tune_state = CT_AGC_STOP; + } + } else { + /* everything higher than or equal to CT_AGC_STOP means tracking */ + ret = 100; /* 10ms interval */ + apply_gain_immediatly = 0; + } + } +#ifdef DEBUG_AGC + dprintk + ("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm", + (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, + (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA)); +#endif + } + + /* apply gain */ + if (!state->agc_freeze) + dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly); + return ret; +} + +EXPORT_SYMBOL(dib0090_gain_control); + +void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) +{ + struct dib0090_state *state = fe->tuner_priv; + if (rf) + *rf = state->gain[0]; + if (bb) + *bb = state->gain[1]; + if (rf_gain_limit) + *rf_gain_limit = state->rf_gain_limit; + if (rflt) + *rflt = (state->rf_lt_def >> 10) & 0x7; +} + +EXPORT_SYMBOL(dib0090_get_current_gain); + +u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000; + s32 current_temp = state->temperature; + s32 wbd_thot, wbd_tcold; + const struct dib0090_wbd_slope *wbd = state->current_wbd_table; + + while (f_MHz > wbd->max_freq) + wbd++; + + dprintk("using wbd-table-entry with max freq %d", wbd->max_freq); + + if (current_temp < 0) + current_temp = 0; + if (current_temp > 128) + current_temp = 128; + + state->wbdmux &= ~(7 << 13); + if (wbd->wbd_gain != 0) + state->wbdmux |= (wbd->wbd_gain << 13); + else + state->wbdmux |= (4 << 13); + + dib0090_write_reg(state, 0x10, state->wbdmux); + + wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6); + wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6); + + wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7; + + state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold); + dprintk("wbd-target: %d dB", (u32) state->wbd_target); + dprintk("wbd offset applied is %d", wbd_tcold); + + return state->wbd_offset + wbd_tcold; +} + +EXPORT_SYMBOL(dib0090_get_wbd_offset); + +static const u16 dib0090_defaults[] = { + + 25, 0x01, + 0x0000, + 0x99a0, + 0x6008, + 0x0000, + 0x8bcb, + 0x0000, + 0x0405, + 0x0000, + 0x0000, + 0x0000, + 0xb802, + 0x0300, + 0x2d12, + 0xbac0, + 0x7c00, + 0xdbb9, + 0x0954, + 0x0743, + 0x8000, + 0x0001, + 0x0040, + 0x0100, + 0x0000, + 0xe910, + 0x149e, + + 1, 0x1c, + 0xff2d, + + 1, 0x39, + 0x0000, + + 2, 0x1e, + 0x07FF, + 0x0007, + + 1, 0x24, + EN_UHF | EN_CRYSTAL, + + 2, 0x3c, + 0x3ff, + 0x111, + 0 +}; + +static const u16 dib0090_p1g_additionnal_defaults[] = { + 1, 0x05, + 0xabcd, + + 1, 0x11, + 0x00b4, + + 1, 0x1c, + 0xfffd, + + 1, 0x40, + 0x108, + 0 +}; + +static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n) +{ + u16 l, r; + + l = pgm_read_word(n++); + while (l) { + r = pgm_read_word(n++); + do { + dib0090_write_reg(state, r, pgm_read_word(n++)); + r++; + } while (--l); + l = pgm_read_word(n++); + } +} + +#define CAP_VALUE_MIN (u8) 9 +#define CAP_VALUE_MAX (u8) 40 +#define HR_MIN (u8) 25 +#define HR_MAX (u8) 40 +#define POLY_MIN (u8) 0 +#define POLY_MAX (u8) 8 + +void dib0090_set_EFUSE(struct dib0090_state *state) +{ + u8 c, h, n; + u16 e2, e4; + u16 cal; + + e2 = dib0090_read_reg(state, 0x26); + e4 = dib0090_read_reg(state, 0x28); + + if ((state->identity.version == P1D_E_F) || + (state->identity.version == P1G) || (e2 == 0xffff)) { + + dib0090_write_reg(state, 0x22, 0x10); + cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff; + + if ((cal < 670) || (cal == 1023)) + cal = 850; + n = 165 - ((cal * 10)>>6) ; + e2 = e4 = (3<<12) | (34<<6) | (n); + } + + if (e2 != e4) + e2 &= e4; /* Remove the redundancy */ + + if (e2 != 0xffff) { + c = e2 & 0x3f; + n = (e2 >> 12) & 0xf; + h = (e2 >> 6) & 0x3f; + + if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN)) + c = 32; + if ((h >= HR_MAX) || (h <= HR_MIN)) + h = 34; + if ((n >= POLY_MAX) || (n <= POLY_MIN)) + n = 3; + + dib0090_write_reg(state, 0x13, (h << 10)) ; + e2 = (n<<11) | ((h>>2)<<6) | (c); + dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */ + } +} + +static int dib0090_reset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + + dib0090_reset_digital(fe, state->config); + if (dib0090_identify(fe) < 0) + return -EIO; + +#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT + if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */ + return 0; +#endif + + if (!state->identity.in_soc) { + if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2) + dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL)); + else + dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL)); + } + + dib0090_set_default_config(state, dib0090_defaults); + + if (state->identity.in_soc) + dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */ + + if (state->identity.p1g) + dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults); + + /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/ + if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc)) + dib0090_set_EFUSE(state); + + /* Congigure in function of the crystal */ + if (state->config->io.clock_khz >= 24000) + dib0090_write_reg(state, 0x14, 1); + else + dib0090_write_reg(state, 0x14, 2); + dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1); + + state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL; /* enable iq-offset-calibration and wbd-calibration when tuning next time */ + + return 0; +} + +#define steps(u) (((u) > 15) ? ((u)-16) : (u)) +#define INTERN_WAIT 10 +static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = INTERN_WAIT * 10; + + switch (*tune_state) { + case CT_TUNER_STEP_2: + /* Turns to positive */ + dib0090_write_reg(state, 0x1f, 0x7); + *tune_state = CT_TUNER_STEP_3; + break; + + case CT_TUNER_STEP_3: + state->adc_diff = dib0090_read_reg(state, 0x1d); + + /* Turns to negative */ + dib0090_write_reg(state, 0x1f, 0x4); + *tune_state = CT_TUNER_STEP_4; + break; + + case CT_TUNER_STEP_4: + state->adc_diff -= dib0090_read_reg(state, 0x1d); + *tune_state = CT_TUNER_STEP_5; + ret = 0; + break; + + default: + break; + } + + return ret; +} + +struct dc_calibration { + u8 addr; + u8 offset; + u8 pga:1; + u16 bb1; + u8 i:1; +}; + +static const struct dc_calibration dc_table[] = { + /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ + {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1}, + {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0}, + /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ + {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1}, + {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0}, + {0}, +}; + +static const struct dc_calibration dc_p1g_table[] = { + /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ + /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */ + {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1}, + {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0}, + /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ + {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1}, + {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0}, + {0}, +}; + +static void dib0090_set_trim(struct dib0090_state *state) +{ + u16 *val; + + if (state->dc->addr == 0x07) + val = &state->bb7; + else + val = &state->bb6; + + *val &= ~(0x1f << state->dc->offset); + *val |= state->step << state->dc->offset; + + dib0090_write_reg(state, state->dc->addr, *val); +} + +static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = 0; + u16 reg; + + switch (*tune_state) { + case CT_TUNER_START: + dprintk("Start DC offset calibration"); + + /* force vcm2 = 0.8V */ + state->bb6 = 0; + state->bb7 = 0x040d; + + /* the LNA AND LO are off */ + reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */ + dib0090_write_reg(state, 0x24, reg); + + state->wbdmux = dib0090_read_reg(state, 0x10); + dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3); + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); + + state->dc = dc_table; + + if (state->identity.p1g) + state->dc = dc_p1g_table; + *tune_state = CT_TUNER_STEP_0; + + /* fall through */ + + case CT_TUNER_STEP_0: + dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q"); + dib0090_write_reg(state, 0x01, state->dc->bb1); + dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7)); + + state->step = 0; + state->min_adc_diff = 1023; + *tune_state = CT_TUNER_STEP_1; + ret = 50; + break; + + case CT_TUNER_STEP_1: + dib0090_set_trim(state); + *tune_state = CT_TUNER_STEP_2; + break; + + case CT_TUNER_STEP_2: + case CT_TUNER_STEP_3: + case CT_TUNER_STEP_4: + ret = dib0090_get_offset(state, tune_state); + break; + + case CT_TUNER_STEP_5: /* found an offset */ + dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step); + if (state->step == 0 && state->adc_diff < 0) { + state->min_adc_diff = -1023; + dprintk("Change of sign of the minimum adc diff"); + } + + dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step); + + /* first turn for this frequency */ + if (state->step == 0) { + if (state->dc->pga && state->adc_diff < 0) + state->step = 0x10; + if (state->dc->pga == 0 && state->adc_diff > 0) + state->step = 0x10; + } + + /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */ + if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) { + /* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */ + state->step++; + state->min_adc_diff = state->adc_diff; + *tune_state = CT_TUNER_STEP_1; + } else { + /* the minimum was what we have seen in the step before */ + if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) { + dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff); + state->step--; + } + + dib0090_set_trim(state); + dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step); + + state->dc++; + if (state->dc->addr == 0) /* done */ + *tune_state = CT_TUNER_STEP_6; + else + *tune_state = CT_TUNER_STEP_0; + + } + break; + + case CT_TUNER_STEP_6: + dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); + dib0090_write_reg(state, 0x1f, 0x7); + *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ + state->calibrate &= ~DC_CAL; + default: + break; + } + return ret; +} + +static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + u8 wbd_gain; + const struct dib0090_wbd_slope *wbd = state->current_wbd_table; + + switch (*tune_state) { + case CT_TUNER_START: + while (state->current_rf / 1000 > wbd->max_freq) + wbd++; + if (wbd->wbd_gain != 0) + wbd_gain = wbd->wbd_gain; + else { + wbd_gain = 4; +#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND) + if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) + wbd_gain = 2; +#endif + } + + if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */ + *tune_state = CT_TUNER_START; + state->calibrate &= ~WBD_CAL; + return 0; + } + + dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3)); + + dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1))); + *tune_state = CT_TUNER_STEP_0; + state->wbd_calibration_gain = wbd_gain; + return 90; /* wait for the WBDMUX to switch and for the ADC to sample */ + + case CT_TUNER_STEP_0: + state->wbd_offset = dib0090_get_slow_adc_val(state); + dprintk("WBD calibration offset = %d", state->wbd_offset); + *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ + state->calibrate &= ~WBD_CAL; + break; + + default: + break; + } + return 0; +} + +static void dib0090_set_bandwidth(struct dib0090_state *state) +{ + u16 tmp; + + if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000) + tmp = (3 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000) + tmp = (2 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000) + tmp = (1 << 14); + else + tmp = (0 << 14); + + state->bb_1_def &= 0x3fff; + state->bb_1_def |= tmp; + + dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */ + + dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */ + dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */ + if (state->identity.in_soc) { + dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */ + } else { + dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */ + dib0090_write_reg(state, 0x05, 0xabcd); /* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */ + } +} + +static const struct dib0090_pll dib0090_pll_table[] = { +#ifdef CONFIG_BAND_CBAND + {56000, 0, 9, 48, 6}, + {70000, 1, 9, 48, 6}, + {87000, 0, 8, 32, 4}, + {105000, 1, 8, 32, 4}, + {115000, 0, 7, 24, 6}, + {140000, 1, 7, 24, 6}, + {170000, 0, 6, 16, 4}, +#endif +#ifdef CONFIG_BAND_VHF + {200000, 1, 6, 16, 4}, + {230000, 0, 5, 12, 6}, + {280000, 1, 5, 12, 6}, + {340000, 0, 4, 8, 4}, + {380000, 1, 4, 8, 4}, + {450000, 0, 3, 6, 6}, +#endif +#ifdef CONFIG_BAND_UHF + {580000, 1, 3, 6, 6}, + {700000, 0, 2, 4, 4}, + {860000, 1, 2, 4, 4}, +#endif +#ifdef CONFIG_BAND_LBAND + {1800000, 1, 0, 2, 4}, +#endif +#ifdef CONFIG_BAND_SBAND + {2900000, 0, 14, 1, 4}, +#endif +}; + +static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = { + +#ifdef CONFIG_BAND_CBAND + {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, + {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, + {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, +#endif +#ifdef CONFIG_BAND_UHF + {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, +#endif +}; + +static const struct dib0090_tuning dib0090_tuning_table[] = { + +#ifdef CONFIG_BAND_CBAND + {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, +#endif +#ifdef CONFIG_BAND_VHF + {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, +#endif +#ifdef CONFIG_BAND_UHF + {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, +#endif +}; + +static const struct dib0090_tuning dib0090_p1g_tuning_table[] = { +#ifdef CONFIG_BAND_CBAND + {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB}, +#endif +#ifdef CONFIG_BAND_VHF + {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, +#endif +#ifdef CONFIG_BAND_UHF + {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, +#endif +}; + +static const struct dib0090_pll dib0090_p1g_pll_table[] = { +#ifdef CONFIG_BAND_CBAND + {57000, 0, 11, 48, 6}, + {70000, 1, 11, 48, 6}, + {86000, 0, 10, 32, 4}, + {105000, 1, 10, 32, 4}, + {115000, 0, 9, 24, 6}, + {140000, 1, 9, 24, 6}, + {170000, 0, 8, 16, 4}, +#endif +#ifdef CONFIG_BAND_VHF + {200000, 1, 8, 16, 4}, + {230000, 0, 7, 12, 6}, + {280000, 1, 7, 12, 6}, + {340000, 0, 6, 8, 4}, + {380000, 1, 6, 8, 4}, + {455000, 0, 5, 6, 6}, +#endif +#ifdef CONFIG_BAND_UHF + {580000, 1, 5, 6, 6}, + {680000, 0, 4, 4, 4}, + {860000, 1, 4, 4, 4}, +#endif +#ifdef CONFIG_BAND_LBAND + {1800000, 1, 2, 2, 4}, +#endif +#ifdef CONFIG_BAND_SBAND + {2900000, 0, 1, 1, 6}, +#endif +}; + +static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = { +#ifdef CONFIG_BAND_CBAND + {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, + {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, + {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, +#endif +#ifdef CONFIG_BAND_UHF + {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, +#endif +}; + +static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = { +#ifdef CONFIG_BAND_CBAND + {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, + {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, + {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, + {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, +#endif +}; + +static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = 0; + u16 lo4 = 0xe900; + + s16 adc_target; + u16 adc; + s8 step_sign; + u8 force_soft_search = 0; + + if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) + force_soft_search = 1; + + if (*tune_state == CT_TUNER_START) { + dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO"); + dib0090_write_reg(state, 0x10, 0x2B1); + dib0090_write_reg(state, 0x1e, 0x0032); + + if (!state->tuner_is_tuned) { + /* prepare a complete captrim */ + if (!state->identity.p1g || force_soft_search) + state->step = state->captrim = state->fcaptrim = 64; + + state->current_rf = state->rf_request; + } else { /* we are already tuned to this frequency - the configuration is correct */ + if (!state->identity.p1g || force_soft_search) { + /* do a minimal captrim even if the frequency has not changed */ + state->step = 4; + state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f; + } + } + state->adc_diff = 3000; + *tune_state = CT_TUNER_STEP_0; + + } else if (*tune_state == CT_TUNER_STEP_0) { + if (state->identity.p1g && !force_soft_search) { + u8 ratio = 31; + + dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1); + dib0090_read_reg(state, 0x40); + ret = 50; + } else { + state->step /= 2; + dib0090_write_reg(state, 0x18, lo4 | state->captrim); + + if (state->identity.in_soc) + ret = 25; + } + *tune_state = CT_TUNER_STEP_1; + + } else if (*tune_state == CT_TUNER_STEP_1) { + if (state->identity.p1g && !force_soft_search) { + dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0); + dib0090_read_reg(state, 0x40); + + state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F; + dprintk("***Final Captrim= 0x%x", state->fcaptrim); + *tune_state = CT_TUNER_STEP_3; + + } else { + /* MERGE for all krosus before P1G */ + adc = dib0090_get_slow_adc_val(state); + dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024); + + if (state->rest == 0 || state->identity.in_soc) { /* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */ + adc_target = 200; + } else + adc_target = 400; + + if (adc >= adc_target) { + adc -= adc_target; + step_sign = -1; + } else { + adc = adc_target - adc; + step_sign = 1; + } + + if (adc < state->adc_diff) { + dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff); + state->adc_diff = adc; + state->fcaptrim = state->captrim; + } + + state->captrim += step_sign * state->step; + if (state->step >= 1) + *tune_state = CT_TUNER_STEP_0; + else + *tune_state = CT_TUNER_STEP_2; + + ret = 25; + } + } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */ + /*write the final cptrim config */ + dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim); + + *tune_state = CT_TUNER_STEP_3; + + } else if (*tune_state == CT_TUNER_STEP_3) { + state->calibrate &= ~CAPTRIM_CAL; + *tune_state = CT_TUNER_STEP_0; + } + + return ret; +} + +static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = 15; + s16 val; + + switch (*tune_state) { + case CT_TUNER_START: + state->wbdmux = dib0090_read_reg(state, 0x10); + dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3)); + + state->bias = dib0090_read_reg(state, 0x13); + dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8)); + + *tune_state = CT_TUNER_STEP_0; + /* wait for the WBDMUX to switch and for the ADC to sample */ + break; + + case CT_TUNER_STEP_0: + state->adc_diff = dib0090_get_slow_adc_val(state); + dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8)); + *tune_state = CT_TUNER_STEP_1; + break; + + case CT_TUNER_STEP_1: + val = dib0090_get_slow_adc_val(state); + state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55; + + dprintk("temperature: %d C", state->temperature - 30); + + *tune_state = CT_TUNER_STEP_2; + break; + + case CT_TUNER_STEP_2: + dib0090_write_reg(state, 0x13, state->bias); + dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */ + + *tune_state = CT_TUNER_START; + state->calibrate &= ~TEMP_CAL; + if (state->config->analog_output == 0) + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); + + break; + + default: + ret = 0; + break; + } + return ret; +} + +#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ +static int dib0090_tune(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + const struct dib0090_tuning *tune = state->current_tune_table_index; + const struct dib0090_pll *pll = state->current_pll_table_index; + enum frontend_tune_state *tune_state = &state->tune_state; + + u16 lo5, lo6, Den, tmp; + u32 FBDiv, Rest, FREF, VCOF_kHz = 0; + int ret = 10; /* 1ms is the default delay most of the time */ + u8 c, i; + + /************************* VCO ***************************/ + /* Default values for FG */ + /* from these are needed : */ + /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */ + + /* in any case we first need to do a calibration if needed */ + if (*tune_state == CT_TUNER_START) { + /* deactivate DataTX before some calibrations */ + if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL)) + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); + else + /* Activate DataTX in case a calibration has been done before */ + if (state->config->analog_output == 0) + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); + } + + if (state->calibrate & DC_CAL) + return dib0090_dc_offset_calibration(state, tune_state); + else if (state->calibrate & WBD_CAL) { + if (state->current_rf == 0) + state->current_rf = state->fe->dtv_property_cache.frequency / 1000; + return dib0090_wbd_calibration(state, tune_state); + } else if (state->calibrate & TEMP_CAL) + return dib0090_get_temperature(state, tune_state); + else if (state->calibrate & CAPTRIM_CAL) + return dib0090_captrim_search(state, tune_state); + + if (*tune_state == CT_TUNER_START) { + /* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */ + if (state->config->use_pwm_agc && state->identity.in_soc) { + tmp = dib0090_read_reg(state, 0x39); + if ((tmp >> 10) & 0x1) + dib0090_write_reg(state, 0x39, tmp & ~(1 << 10)); + } + + state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000); + state->rf_request = + state->fe->dtv_property_cache.frequency / 1000 + (state->current_band == + BAND_UHF ? state->config->freq_offset_khz_uhf : state->config-> + freq_offset_khz_vhf); + + /* in ISDB-T 1seg we shift tuning frequency */ + if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1 + && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) { + const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if; + u8 found_offset = 0; + u32 margin_khz = 100; + + if (LUT_offset != NULL) { + while (LUT_offset->RF_freq != 0xffff) { + if (((state->rf_request > (LUT_offset->RF_freq - margin_khz)) + && (state->rf_request < (LUT_offset->RF_freq + margin_khz))) + && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) { + state->rf_request += LUT_offset->offset_khz; + found_offset = 1; + break; + } + LUT_offset++; + } + } + + if (found_offset == 0) + state->rf_request += 400; + } + if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) { + state->tuner_is_tuned = 0; + state->current_rf = 0; + state->current_standard = 0; + + tune = dib0090_tuning_table; + if (state->identity.p1g) + tune = dib0090_p1g_tuning_table; + + tmp = (state->identity.version >> 5) & 0x7; + + if (state->identity.in_soc) { + if (state->config->force_cband_input) { /* Use the CBAND input for all band */ + if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF + || state->current_band & BAND_UHF) { + state->current_band = BAND_CBAND; + tune = dib0090_tuning_table_cband_7090; + } + } else { /* Use the CBAND input for all band under UHF */ + if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) { + state->current_band = BAND_CBAND; + tune = dib0090_tuning_table_cband_7090; + } + } + } else + if (tmp == 0x4 || tmp == 0x7) { + /* CBAND tuner version for VHF */ + if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) { + state->current_band = BAND_CBAND; /* Force CBAND */ + + tune = dib0090_tuning_table_fm_vhf_on_cband; + if (state->identity.p1g) + tune = dib0090_p1g_tuning_table_fm_vhf_on_cband; + } + } + + pll = dib0090_pll_table; + if (state->identity.p1g) + pll = dib0090_p1g_pll_table; + + /* Look for the interval */ + while (state->rf_request > tune->max_freq) + tune++; + while (state->rf_request > pll->max_freq) + pll++; + + state->current_tune_table_index = tune; + state->current_pll_table_index = pll; + + dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim)); + + VCOF_kHz = (pll->hfdiv * state->rf_request) * 2; + + FREF = state->config->io.clock_khz; + if (state->config->fref_clock_ratio != 0) + FREF /= state->config->fref_clock_ratio; + + FBDiv = (VCOF_kHz / pll->topresc / FREF); + Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; + + if (Rest < LPF) + Rest = 0; + else if (Rest < 2 * LPF) + Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { + Rest = 0; + FBDiv += 1; + } else if (Rest > (FREF - 2 * LPF)) + Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + state->rest = Rest; + + /* external loop filter, otherwise: + * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4; + * lo6 = 0x0e34 */ + + if (Rest == 0) { + if (pll->vco_band) + lo5 = 0x049f; + else + lo5 = 0x041f; + } else { + if (pll->vco_band) + lo5 = 0x049e; + else if (state->config->analog_output) + lo5 = 0x041d; + else + lo5 = 0x041c; + } + + if (state->identity.p1g) { /* Bias is done automatically in P1G */ + if (state->identity.in_soc) { + if (state->identity.version == SOC_8090_P1G_11R1) + lo5 = 0x46f; + else + lo5 = 0x42f; + } else + lo5 = 0x42c; + } + + lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */ + + if (!state->config->io.pll_int_loop_filt) { + if (state->identity.in_soc) + lo6 = 0xff98; + else if (state->identity.p1g || (Rest == 0)) + lo6 = 0xfff8; + else + lo6 = 0xff28; + } else + lo6 = (state->config->io.pll_int_loop_filt << 3); + + Den = 1; + + if (Rest > 0) { + if (state->config->analog_output) + lo6 |= (1 << 2) | 2; + else { + if (state->identity.in_soc) + lo6 |= (1 << 2) | 2; + else + lo6 |= (1 << 2) | 2; + } + Den = 255; + } + dib0090_write_reg(state, 0x15, (u16) FBDiv); + if (state->config->fref_clock_ratio != 0) + dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio); + else + dib0090_write_reg(state, 0x16, (Den << 8) | 1); + dib0090_write_reg(state, 0x17, (u16) Rest); + dib0090_write_reg(state, 0x19, lo5); + dib0090_write_reg(state, 0x1c, lo6); + + lo6 = tune->tuner_enable; + if (state->config->analog_output) + lo6 = (lo6 & 0xff9f) | 0x2; + + dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL); + + } + + state->current_rf = state->rf_request; + state->current_standard = state->fe->dtv_property_cache.delivery_system; + + ret = 20; + state->calibrate = CAPTRIM_CAL; /* captrim serach now */ + } + + else if (*tune_state == CT_TUNER_STEP_0) { /* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */ + const struct dib0090_wbd_slope *wbd = state->current_wbd_table; + + while (state->current_rf / 1000 > wbd->max_freq) + wbd++; + + dib0090_write_reg(state, 0x1e, 0x07ff); + dprintk("Final Captrim: %d", (u32) state->fcaptrim); + dprintk("HFDIV code: %d", (u32) pll->hfdiv_code); + dprintk("VCO = %d", (u32) pll->vco_band); + dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request); + dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz); + dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); + dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8), + (u32) dib0090_read_reg(state, 0x1c) & 0x3); + +#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ + c = 4; + i = 3; + + if (wbd->wbd_gain != 0) + c = wbd->wbd_gain; + + state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1)); + dib0090_write_reg(state, 0x10, state->wbdmux); + + if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) { + dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune); + dib0090_write_reg(state, 0x09, tune->lna_bias); + dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim)); + } else + dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias); + + dib0090_write_reg(state, 0x0c, tune->v2i); + dib0090_write_reg(state, 0x0d, tune->mix); + dib0090_write_reg(state, 0x0e, tune->load); + *tune_state = CT_TUNER_STEP_1; + + } else if (*tune_state == CT_TUNER_STEP_1) { + /* initialize the lt gain register */ + state->rf_lt_def = 0x7c00; + + dib0090_set_bandwidth(state); + state->tuner_is_tuned = 1; + + state->calibrate |= WBD_CAL; + state->calibrate |= TEMP_CAL; + *tune_state = CT_TUNER_STOP; + } else + ret = FE_CALLBACK_TIME_NEVER; + return ret; +} + +static int dib0090_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + + return state->tune_state; +} + +EXPORT_SYMBOL(dib0090_get_tune_state); + +int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + struct dib0090_state *state = fe->tuner_priv; + + state->tune_state = tune_state; + return 0; +} + +EXPORT_SYMBOL(dib0090_set_tune_state); + +static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) +{ + struct dib0090_state *state = fe->tuner_priv; + + *frequency = 1000 * state->current_rf; + return 0; +} + +static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct dib0090_state *state = fe->tuner_priv; + u32 ret; + + state->tune_state = CT_TUNER_START; + + do { + ret = dib0090_tune(fe); + if (ret != FE_CALLBACK_TIME_NEVER) + msleep(ret / 10); + else + break; + } while (state->tune_state != CT_TUNER_STOP); + + return 0; +} + +static const struct dvb_tuner_ops dib0090_ops = { + .info = { + .name = "DiBcom DiB0090", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0090_release, + + .init = dib0090_wakeup, + .sleep = dib0090_sleep, + .set_params = dib0090_set_params, + .get_frequency = dib0090_get_frequency, +}; + +static const struct dvb_tuner_ops dib0090_fw_ops = { + .info = { + .name = "DiBcom DiB0090", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0090_release, + + .init = NULL, + .sleep = NULL, + .set_params = NULL, + .get_frequency = NULL, +}; + +static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = { + {470, 0, 250, 0, 100, 4}, + {860, 51, 866, 21, 375, 4}, + {1700, 0, 800, 0, 850, 4}, + {2900, 0, 250, 0, 100, 6}, + {0xFFFF, 0, 0, 0, 0, 0}, +}; + +struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) +{ + struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL); + if (st == NULL) + return NULL; + + st->config = config; + st->i2c = i2c; + st->fe = fe; + fe->tuner_priv = st; + + if (config->wbd == NULL) + st->current_wbd_table = dib0090_wbd_table_default; + else + st->current_wbd_table = config->wbd; + + if (dib0090_reset(fe) != 0) + goto free_mem; + + printk(KERN_INFO "DiB0090: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops)); + + return fe; + free_mem: + kfree(st); + fe->tuner_priv = NULL; + return NULL; +} + +EXPORT_SYMBOL(dib0090_register); + +struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) +{ + struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL); + if (st == NULL) + return NULL; + + st->config = config; + st->i2c = i2c; + st->fe = fe; + fe->tuner_priv = st; + + if (dib0090_fw_reset_digital(fe, st->config) != 0) + goto free_mem; + + dprintk("DiB0090 FW: successfully identified"); + memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops)); + + return fe; +free_mem: + kfree(st); + fe->tuner_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(dib0090_fw_register); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_AUTHOR("Olivier Grenie "); +MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0090.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0090.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0090.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib0090.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,139 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#ifndef DIB0090_H +#define DIB0090_H + +struct dvb_frontend; +struct i2c_adapter; + +#define DEFAULT_DIB0090_I2C_ADDRESS 0x60 + +struct dib0090_io_config { + u32 clock_khz; + + u8 pll_bypass:1; + u8 pll_range:1; + u8 pll_prediv:6; + u8 pll_loopdiv:6; + + u8 adc_clock_ratio; /* valid is 8, 7 ,6 */ + u16 pll_int_loop_filt; +}; + +struct dib0090_wbd_slope { + u16 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u16 slope_cold; + u16 offset_cold; + u16 slope_hot; + u16 offset_hot; + u8 wbd_gain; +}; + +struct dib0090_low_if_offset_table { + int std; + u32 RF_freq; + s32 offset_khz; +}; + +struct dib0090_config { + struct dib0090_io_config io; + int (*reset) (struct dvb_frontend *, int); + int (*sleep) (struct dvb_frontend *, int); + + /* offset in kHz */ + int freq_offset_khz_uhf; + int freq_offset_khz_vhf; + + int (*get_adc_power) (struct dvb_frontend *); + + u8 clkouttobamse:1; /* activate or deactivate clock output */ + u8 analog_output; + + u8 i2c_address; + /* add drives and other things if necessary */ + u16 wbd_vhf_offset; + u16 wbd_cband_offset; + u8 use_pwm_agc; + u8 clkoutdrive; + + u8 ls_cfg_pad_drv; + u8 data_tx_drv; + + u8 in_soc; + const struct dib0090_low_if_offset_table *low_if; + u8 fref_clock_ratio; + u16 force_cband_input; + struct dib0090_wbd_slope *wbd; +}; + +#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE)) +extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); +extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); +extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); +extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe); +extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner); +extern int dib0090_gain_control(struct dvb_frontend *fe); +extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe); +extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); +extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt); +#else +static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline int dib0090_gain_control(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return CT_DONE; +} + +static inline int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * public header file of the frontend drivers for mobile DVB-T demodulators + * DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * based on GPL code from DibCom, which has + * + * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) + * + * 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, version 2. + * + * Acknowledgements + * + * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver + * sources, on which this driver (and the dvb-dibusb) are based. + * + * see Documentation/dvb/README.dibusb for more information + * + */ + +#ifndef DIB3000_H +#define DIB3000_H + +#include + +struct dib3000_config +{ + /* the demodulator's i2c address */ + u8 demod_address; +}; + +struct dib_fe_xfer_ops +{ + /* pid and transfer handling is done in the demodulator */ + int (*pid_parse)(struct dvb_frontend *fe, int onoff); + int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff); + int (*pid_ctrl)(struct dvb_frontend *fe, int index, int pid, int onoff); + int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl); +}; + +#if defined(CONFIG_DVB_DIB3000MB) || (defined(CONFIG_DVB_DIB3000MB_MODULE) && defined(MODULE)) +extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, + struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops); +#else +static inline struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, + struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_DIB3000MB + +#endif // DIB3000_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mb.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,834 @@ +/* + * Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B + * DiBcom (http://www.dibcom.fr/) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * based on GPL code from DibCom, which has + * + * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) + * + * 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, version 2. + * + * Acknowledgements + * + * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver + * sources, on which this driver (and the dvb-dibusb) are based. + * + * see Documentation/dvb/README.dibusb for more information + * + */ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "dib3000.h" +#include "dib3000mb_priv.h" + +/* Version information */ +#define DRIVER_VERSION "0.1" +#define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator" +#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able))."); + +#define deb_info(args...) dprintk(0x01,args) +#define deb_i2c(args...) dprintk(0x02,args) +#define deb_srch(args...) dprintk(0x04,args) +#define deb_info(args...) dprintk(0x01,args) +#define deb_xfer(args...) dprintk(0x02,args) +#define deb_setf(args...) dprintk(0x04,args) +#define deb_getf(args...) dprintk(0x08,args) + +static int dib3000_read_reg(struct dib3000_state *state, u16 reg) +{ + u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff }; + u8 rb[2]; + struct i2c_msg msg[] = { + { .addr = state->config.demod_address, .flags = 0, .buf = wb, .len = 2 }, + { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 }, + }; + + if (i2c_transfer(state->i2c, msg, 2) != 2) + deb_i2c("i2c read error\n"); + + deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg, + (rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]); + + return (rb[0] << 8) | rb[1]; +} + +static int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val) +{ + u8 b[] = { + (reg >> 8) & 0xff, reg & 0xff, + (val >> 8) & 0xff, val & 0xff, + }; + struct i2c_msg msg[] = { + { .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 } + }; + deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val); + + return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0; +} + +static int dib3000_search_status(u16 irq,u16 lock) +{ + if (irq & 0x02) { + if (lock & 0x01) { + deb_srch("auto search succeeded\n"); + return 1; // auto search succeeded + } else { + deb_srch("auto search not successful\n"); + return 0; // auto search failed + } + } else if (irq & 0x01) { + deb_srch("auto search failed\n"); + return 0; // auto search failed + } + return -1; // try again +} + +/* for auto search */ +static u16 dib3000_seq[2][2][2] = /* fft,gua, inv */ + { /* fft */ + { /* gua */ + { 0, 1 }, /* 0 0 { 0,1 } */ + { 3, 9 }, /* 0 1 { 0,1 } */ + }, + { + { 2, 5 }, /* 1 0 { 0,1 } */ + { 6, 11 }, /* 1 1 { 0,1 } */ + } + }; + +static int dib3000mb_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep); + +static int dib3000mb_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep, int tuner) +{ + struct dib3000_state* state = fe->demodulator_priv; + struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; + fe_code_rate_t fe_cr = FEC_NONE; + int search_state, seq; + + if (tuner && fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, fep); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + + deb_setf("bandwidth: "); + switch (ofdm->bandwidth) { + case BANDWIDTH_8_MHZ: + deb_setf("8 MHz\n"); + wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]); + wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz); + break; + case BANDWIDTH_7_MHZ: + deb_setf("7 MHz\n"); + wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]); + wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz); + break; + case BANDWIDTH_6_MHZ: + deb_setf("6 MHz\n"); + wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]); + wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz); + break; + case BANDWIDTH_AUTO: + return -EOPNOTSUPP; + default: + err("unknown bandwidth value."); + return -EINVAL; + } + } + wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4); + + deb_setf("transmission mode: "); + switch (ofdm->transmission_mode) { + case TRANSMISSION_MODE_2K: + deb_setf("2k\n"); + wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K); + break; + case TRANSMISSION_MODE_8K: + deb_setf("8k\n"); + wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_8K); + break; + case TRANSMISSION_MODE_AUTO: + deb_setf("auto\n"); + break; + default: + return -EINVAL; + } + + deb_setf("guard: "); + switch (ofdm->guard_interval) { + case GUARD_INTERVAL_1_32: + deb_setf("1_32\n"); + wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32); + break; + case GUARD_INTERVAL_1_16: + deb_setf("1_16\n"); + wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_16); + break; + case GUARD_INTERVAL_1_8: + deb_setf("1_8\n"); + wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_8); + break; + case GUARD_INTERVAL_1_4: + deb_setf("1_4\n"); + wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_4); + break; + case GUARD_INTERVAL_AUTO: + deb_setf("auto\n"); + break; + default: + return -EINVAL; + } + + deb_setf("inversion: "); + switch (fep->inversion) { + case INVERSION_OFF: + deb_setf("off\n"); + wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF); + break; + case INVERSION_AUTO: + deb_setf("auto "); + break; + case INVERSION_ON: + deb_setf("on\n"); + wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_ON); + break; + default: + return -EINVAL; + } + + deb_setf("constellation: "); + switch (ofdm->constellation) { + case QPSK: + deb_setf("qpsk\n"); + wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK); + break; + case QAM_16: + deb_setf("qam16\n"); + wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_16QAM); + break; + case QAM_64: + deb_setf("qam64\n"); + wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_64QAM); + break; + case QAM_AUTO: + break; + default: + return -EINVAL; + } + deb_setf("hierarchy: "); + switch (ofdm->hierarchy_information) { + case HIERARCHY_NONE: + deb_setf("none "); + /* fall through */ + case HIERARCHY_1: + deb_setf("alpha=1\n"); + wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1); + break; + case HIERARCHY_2: + deb_setf("alpha=2\n"); + wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_2); + break; + case HIERARCHY_4: + deb_setf("alpha=4\n"); + wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_4); + break; + case HIERARCHY_AUTO: + deb_setf("alpha=auto\n"); + break; + default: + return -EINVAL; + } + + deb_setf("hierarchy: "); + if (ofdm->hierarchy_information == HIERARCHY_NONE) { + deb_setf("none\n"); + wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF); + wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP); + fe_cr = ofdm->code_rate_HP; + } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { + deb_setf("on\n"); + wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON); + wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP); + fe_cr = ofdm->code_rate_LP; + } + deb_setf("fec: "); + switch (fe_cr) { + case FEC_1_2: + deb_setf("1_2\n"); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_1_2); + break; + case FEC_2_3: + deb_setf("2_3\n"); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_2_3); + break; + case FEC_3_4: + deb_setf("3_4\n"); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_3_4); + break; + case FEC_5_6: + deb_setf("5_6\n"); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_5_6); + break; + case FEC_7_8: + deb_setf("7_8\n"); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_7_8); + break; + case FEC_NONE: + deb_setf("none "); + break; + case FEC_AUTO: + deb_setf("auto\n"); + break; + default: + return -EINVAL; + } + + seq = dib3000_seq + [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO] + [ofdm->guard_interval == GUARD_INTERVAL_AUTO] + [fep->inversion == INVERSION_AUTO]; + + deb_setf("seq? %d\n", seq); + + wr(DIB3000MB_REG_SEQ, seq); + + wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE); + + if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) { + if (ofdm->guard_interval == GUARD_INTERVAL_1_8) { + wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8); + } else { + wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT); + } + + wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_2K); + } else { + wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_DEFAULT); + } + + wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_OFF); + wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF); + wr(DIB3000MB_REG_MOBILE_MODE, DIB3000MB_MOBILE_MODE_OFF); + + wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_high); + + wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_ACTIVATE); + + wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC + DIB3000MB_RESTART_CTRL); + wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF); + + /* wait for AGC lock */ + msleep(70); + + wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low); + + /* something has to be auto searched */ + if (ofdm->constellation == QAM_AUTO || + ofdm->hierarchy_information == HIERARCHY_AUTO || + fe_cr == FEC_AUTO || + fep->inversion == INVERSION_AUTO) { + int as_count=0; + + deb_setf("autosearch enabled.\n"); + + wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT); + + wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AUTO_SEARCH); + wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF); + + while ((search_state = + dib3000_search_status( + rd(DIB3000MB_REG_AS_IRQ_PENDING), + rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100) + msleep(1); + + deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count); + + if (search_state == 1) { + struct dvb_frontend_parameters feps; + if (dib3000mb_get_frontend(fe, &feps) == 0) { + deb_setf("reading tuning data from frontend succeeded.\n"); + return dib3000mb_set_frontend(fe, &feps, 0); + } + } + + } else { + wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_CTRL); + wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF); + } + + return 0; +} + +static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) +{ + struct dib3000_state* state = fe->demodulator_priv; + + deb_info("dib3000mb is getting up.\n"); + wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_UP); + + wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC); + + wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE); + wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE_RST); + + wr(DIB3000MB_REG_CLOCK, DIB3000MB_CLOCK_DEFAULT); + + wr(DIB3000MB_REG_ELECT_OUT_MODE, DIB3000MB_ELECT_OUT_MODE_ON); + + wr(DIB3000MB_REG_DDS_FREQ_MSB, DIB3000MB_DDS_FREQ_MSB); + wr(DIB3000MB_REG_DDS_FREQ_LSB, DIB3000MB_DDS_FREQ_LSB); + + wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]); + + wr_foreach(dib3000mb_reg_impulse_noise, + dib3000mb_impulse_noise_values[DIB3000MB_IMPNOISE_OFF]); + + wr_foreach(dib3000mb_reg_agc_gain, dib3000mb_default_agc_gain); + + wr(DIB3000MB_REG_PHASE_NOISE, DIB3000MB_PHASE_NOISE_DEFAULT); + + wr_foreach(dib3000mb_reg_phase_noise, dib3000mb_default_noise_phase); + + wr_foreach(dib3000mb_reg_lock_duration, dib3000mb_default_lock_duration); + + wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low); + + wr(DIB3000MB_REG_LOCK0_MASK, DIB3000MB_LOCK0_DEFAULT); + wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4); + wr(DIB3000MB_REG_LOCK2_MASK, DIB3000MB_LOCK2_DEFAULT); + wr(DIB3000MB_REG_SEQ, dib3000_seq[1][1][1]); + + wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz); + + wr(DIB3000MB_REG_UNK_68, DIB3000MB_UNK_68); + wr(DIB3000MB_REG_UNK_69, DIB3000MB_UNK_69); + wr(DIB3000MB_REG_UNK_71, DIB3000MB_UNK_71); + wr(DIB3000MB_REG_UNK_77, DIB3000MB_UNK_77); + wr(DIB3000MB_REG_UNK_78, DIB3000MB_UNK_78); + wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT); + wr(DIB3000MB_REG_UNK_92, DIB3000MB_UNK_92); + wr(DIB3000MB_REG_UNK_96, DIB3000MB_UNK_96); + wr(DIB3000MB_REG_UNK_97, DIB3000MB_UNK_97); + wr(DIB3000MB_REG_UNK_106, DIB3000MB_UNK_106); + wr(DIB3000MB_REG_UNK_107, DIB3000MB_UNK_107); + wr(DIB3000MB_REG_UNK_108, DIB3000MB_UNK_108); + wr(DIB3000MB_REG_UNK_122, DIB3000MB_UNK_122); + wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF); + wr(DIB3000MB_REG_BERLEN, DIB3000MB_BERLEN_DEFAULT); + + wr_foreach(dib3000mb_reg_filter_coeffs, dib3000mb_filter_coeffs); + + wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_ON); + wr(DIB3000MB_REG_MULTI_DEMOD_MSB, DIB3000MB_MULTI_DEMOD_MSB); + wr(DIB3000MB_REG_MULTI_DEMOD_LSB, DIB3000MB_MULTI_DEMOD_LSB); + + wr(DIB3000MB_REG_OUTPUT_MODE, DIB3000MB_OUTPUT_MODE_SLAVE); + + wr(DIB3000MB_REG_FIFO_142, DIB3000MB_FIFO_142); + wr(DIB3000MB_REG_MPEG2_OUT_MODE, DIB3000MB_MPEG2_OUT_MODE_188); + wr(DIB3000MB_REG_PID_PARSE, DIB3000MB_PID_PARSE_ACTIVATE); + wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT); + wr(DIB3000MB_REG_FIFO_146, DIB3000MB_FIFO_146); + wr(DIB3000MB_REG_FIFO_147, DIB3000MB_FIFO_147); + + wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF); + + return 0; +} + +static int dib3000mb_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct dib3000_state* state = fe->demodulator_priv; + struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; + fe_code_rate_t *cr; + u16 tps_val; + int inv_test1,inv_test2; + u32 dds_val, threshold = 0x800000; + + if (!rd(DIB3000MB_REG_TPS_LOCK)) + return 0; + + dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB); + deb_getf("DDS_VAL: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_VALUE_MSB), rd(DIB3000MB_REG_DDS_VALUE_LSB)); + if (dds_val < threshold) + inv_test1 = 0; + else if (dds_val == threshold) + inv_test1 = 1; + else + inv_test1 = 2; + + dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB); + deb_getf("DDS_FREQ: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_FREQ_MSB), rd(DIB3000MB_REG_DDS_FREQ_LSB)); + if (dds_val < threshold) + inv_test2 = 0; + else if (dds_val == threshold) + inv_test2 = 1; + else + inv_test2 = 2; + + fep->inversion = + ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) || + ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ? + INVERSION_ON : INVERSION_OFF; + + deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); + + switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) { + case DIB3000_CONSTELLATION_QPSK: + deb_getf("QPSK "); + ofdm->constellation = QPSK; + break; + case DIB3000_CONSTELLATION_16QAM: + deb_getf("QAM16 "); + ofdm->constellation = QAM_16; + break; + case DIB3000_CONSTELLATION_64QAM: + deb_getf("QAM64 "); + ofdm->constellation = QAM_64; + break; + default: + err("Unexpected constellation returned by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n", tps_val); + + if (rd(DIB3000MB_REG_TPS_HRCH)) { + deb_getf("HRCH ON\n"); + cr = &ofdm->code_rate_LP; + ofdm->code_rate_HP = FEC_NONE; + switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) { + case DIB3000_ALPHA_0: + deb_getf("HIERARCHY_NONE "); + ofdm->hierarchy_information = HIERARCHY_NONE; + break; + case DIB3000_ALPHA_1: + deb_getf("HIERARCHY_1 "); + ofdm->hierarchy_information = HIERARCHY_1; + break; + case DIB3000_ALPHA_2: + deb_getf("HIERARCHY_2 "); + ofdm->hierarchy_information = HIERARCHY_2; + break; + case DIB3000_ALPHA_4: + deb_getf("HIERARCHY_4 "); + ofdm->hierarchy_information = HIERARCHY_4; + break; + default: + err("Unexpected ALPHA value returned by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n", tps_val); + + tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP); + } else { + deb_getf("HRCH OFF\n"); + cr = &ofdm->code_rate_HP; + ofdm->code_rate_LP = FEC_NONE; + ofdm->hierarchy_information = HIERARCHY_NONE; + + tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP); + } + + switch (tps_val) { + case DIB3000_FEC_1_2: + deb_getf("FEC_1_2 "); + *cr = FEC_1_2; + break; + case DIB3000_FEC_2_3: + deb_getf("FEC_2_3 "); + *cr = FEC_2_3; + break; + case DIB3000_FEC_3_4: + deb_getf("FEC_3_4 "); + *cr = FEC_3_4; + break; + case DIB3000_FEC_5_6: + deb_getf("FEC_5_6 "); + *cr = FEC_4_5; + break; + case DIB3000_FEC_7_8: + deb_getf("FEC_7_8 "); + *cr = FEC_7_8; + break; + default: + err("Unexpected FEC returned by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n",tps_val); + + switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) { + case DIB3000_GUARD_TIME_1_32: + deb_getf("GUARD_INTERVAL_1_32 "); + ofdm->guard_interval = GUARD_INTERVAL_1_32; + break; + case DIB3000_GUARD_TIME_1_16: + deb_getf("GUARD_INTERVAL_1_16 "); + ofdm->guard_interval = GUARD_INTERVAL_1_16; + break; + case DIB3000_GUARD_TIME_1_8: + deb_getf("GUARD_INTERVAL_1_8 "); + ofdm->guard_interval = GUARD_INTERVAL_1_8; + break; + case DIB3000_GUARD_TIME_1_4: + deb_getf("GUARD_INTERVAL_1_4 "); + ofdm->guard_interval = GUARD_INTERVAL_1_4; + break; + default: + err("Unexpected Guard Time returned by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n", tps_val); + + switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) { + case DIB3000_TRANSMISSION_MODE_2K: + deb_getf("TRANSMISSION_MODE_2K "); + ofdm->transmission_mode = TRANSMISSION_MODE_2K; + break; + case DIB3000_TRANSMISSION_MODE_8K: + deb_getf("TRANSMISSION_MODE_8K "); + ofdm->transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + err("unexpected transmission mode return by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n", tps_val); + + return 0; +} + +static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat) +{ + struct dib3000_state* state = fe->demodulator_priv; + + *stat = 0; + + if (rd(DIB3000MB_REG_AGC_LOCK)) + *stat |= FE_HAS_SIGNAL; + if (rd(DIB3000MB_REG_CARRIER_LOCK)) + *stat |= FE_HAS_CARRIER; + if (rd(DIB3000MB_REG_VIT_LCK)) + *stat |= FE_HAS_VITERBI; + if (rd(DIB3000MB_REG_TS_SYNC_LOCK)) + *stat |= (FE_HAS_SYNC | FE_HAS_LOCK); + + deb_getf("actual status is %2x\n",*stat); + + deb_getf("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n", + rd(DIB3000MB_REG_TPS_LOCK), + rd(DIB3000MB_REG_TPS_QAM), + rd(DIB3000MB_REG_TPS_HRCH), + rd(DIB3000MB_REG_TPS_VIT_ALPHA), + rd(DIB3000MB_REG_TPS_CODE_RATE_HP), + rd(DIB3000MB_REG_TPS_CODE_RATE_LP), + rd(DIB3000MB_REG_TPS_GUARD_TIME), + rd(DIB3000MB_REG_TPS_FFT), + rd(DIB3000MB_REG_TPS_CELL_ID)); + + //*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + return 0; +} + +static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct dib3000_state* state = fe->demodulator_priv; + + *ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB)); + return 0; +} + +/* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */ +static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct dib3000_state* state = fe->demodulator_priv; + + *strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170; + return 0; +} + +static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + struct dib3000_state* state = fe->demodulator_priv; + short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER); + int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) | + rd(DIB3000MB_REG_NOISE_POWER_LSB); + *snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1); + return 0; +} + +static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct dib3000_state* state = fe->demodulator_priv; + + *unc = rd(DIB3000MB_REG_PACKET_ERROR_RATE); + return 0; +} + +static int dib3000mb_sleep(struct dvb_frontend* fe) +{ + struct dib3000_state* state = fe->demodulator_priv; + deb_info("dib3000mb is going to bed.\n"); + wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_DOWN); + return 0; +} + +static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe) +{ + return dib3000mb_fe_init(fe, 0); +} + +static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) +{ + return dib3000mb_set_frontend(fe, fep, 1); +} + +static void dib3000mb_release(struct dvb_frontend* fe) +{ + struct dib3000_state *state = fe->demodulator_priv; + kfree(state); +} + +/* pid filter and transfer stuff */ +static int dib3000mb_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff) +{ + struct dib3000_state *state = fe->demodulator_priv; + pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0); + wr(index+DIB3000MB_REG_FIRST_PID,pid); + return 0; +} + +static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff) +{ + struct dib3000_state *state = fe->demodulator_priv; + + deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling"); + if (onoff) { + wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_ACTIVATE); + } else { + wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT); + } + return 0; +} + +static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff) +{ + struct dib3000_state *state = fe->demodulator_priv; + deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling"); + wr(DIB3000MB_REG_PID_PARSE,onoff); + return 0; +} + +static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr) +{ + struct dib3000_state *state = fe->demodulator_priv; + if (onoff) { + wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); + } else { + wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr)); + } + return 0; +} + +static struct dvb_frontend_ops dib3000mb_ops; + +struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, + struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) +{ + struct dib3000_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->i2c = i2c; + memcpy(&state->config,config,sizeof(struct dib3000_config)); + + /* check for the correct demod */ + if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) + goto error; + + if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* set the xfer operations */ + xfer_ops->pid_parse = dib3000mb_pid_parse; + xfer_ops->fifo_ctrl = dib3000mb_fifo_control; + xfer_ops->pid_ctrl = dib3000mb_pid_control; + xfer_ops->tuner_pass_ctrl = dib3000mb_tuner_pass_ctrl; + + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops dib3000mb_ops = { + + .info = { + .name = "DiBcom 3000M-B DVB-T", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = dib3000mb_release, + + .init = dib3000mb_fe_init_nonmobile, + .sleep = dib3000mb_sleep, + + .set_frontend = dib3000mb_set_frontend_and_tuner, + .get_frontend = dib3000mb_get_frontend, + .get_tune_settings = dib3000mb_fe_get_tune_settings, + + .read_status = dib3000mb_read_status, + .read_ber = dib3000mb_read_ber, + .read_signal_strength = dib3000mb_read_signal_strength, + .read_snr = dib3000mb_read_snr, + .read_ucblocks = dib3000mb_read_unc_blocks, +}; + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(dib3000mb_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mb_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mb_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mb_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mb_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,556 @@ +/* + * dib3000mb_priv.h + * + * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) + * + * 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, version 2. + * + * for more information see dib3000mb.c . + */ + +#ifndef __DIB3000MB_PRIV_H_INCLUDED__ +#define __DIB3000MB_PRIV_H_INCLUDED__ + +/* info and err, taken from usb.h, if there is anything available like by default. */ +#define err(format, arg...) printk(KERN_ERR "dib3000: " format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO "dib3000: " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg) + +/* handy shortcuts */ +#define rd(reg) dib3000_read_reg(state,reg) + +#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \ + { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; } + +#define wr_foreach(a,v) { int i; \ + if (sizeof(a) != sizeof(v)) \ + err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\ + for (i=0; i < sizeof(a)/sizeof(u16); i++) \ + wr(a[i],v[i]); \ + } + +#define set_or(reg,val) wr(reg,rd(reg) | val) + +#define set_and(reg,val) wr(reg,rd(reg) & val) + +/* debug */ + +#define dprintk(level,args...) \ + do { if ((debug & level)) { printk(args); } } while (0) + +/* mask for enabling a specific pid for the pid_filter */ +#define DIB3000_ACTIVATE_PID_FILTERING (0x2000) + +/* common values for tuning */ +#define DIB3000_ALPHA_0 ( 0) +#define DIB3000_ALPHA_1 ( 1) +#define DIB3000_ALPHA_2 ( 2) +#define DIB3000_ALPHA_4 ( 4) + +#define DIB3000_CONSTELLATION_QPSK ( 0) +#define DIB3000_CONSTELLATION_16QAM ( 1) +#define DIB3000_CONSTELLATION_64QAM ( 2) + +#define DIB3000_GUARD_TIME_1_32 ( 0) +#define DIB3000_GUARD_TIME_1_16 ( 1) +#define DIB3000_GUARD_TIME_1_8 ( 2) +#define DIB3000_GUARD_TIME_1_4 ( 3) + +#define DIB3000_TRANSMISSION_MODE_2K ( 0) +#define DIB3000_TRANSMISSION_MODE_8K ( 1) + +#define DIB3000_SELECT_LP ( 0) +#define DIB3000_SELECT_HP ( 1) + +#define DIB3000_FEC_1_2 ( 1) +#define DIB3000_FEC_2_3 ( 2) +#define DIB3000_FEC_3_4 ( 3) +#define DIB3000_FEC_5_6 ( 5) +#define DIB3000_FEC_7_8 ( 7) + +#define DIB3000_HRCH_OFF ( 0) +#define DIB3000_HRCH_ON ( 1) + +#define DIB3000_DDS_INVERSION_OFF ( 0) +#define DIB3000_DDS_INVERSION_ON ( 1) + +#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a << 8)) +#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 8) | (1 << 7))) + +#define DIB3000_REG_MANUFACTOR_ID ( 1025) +#define DIB3000_I2C_ID_DIBCOM (0x01b3) + +#define DIB3000_REG_DEVICE_ID ( 1026) +#define DIB3000MB_DEVICE_ID (0x3000) +#define DIB3000MC_DEVICE_ID (0x3001) +#define DIB3000P_DEVICE_ID (0x3002) + +/* frontend state */ +struct dib3000_state { + struct i2c_adapter* i2c; + +/* configuration settings */ + struct dib3000_config config; + + struct dvb_frontend frontend; + int timing_offset; + int timing_offset_comp_done; + + fe_bandwidth_t last_tuned_bw; + u32 last_tuned_freq; +}; + +/* register addresses and some of their default values */ + +/* restart subsystems */ +#define DIB3000MB_REG_RESTART ( 0) + +#define DIB3000MB_RESTART_OFF ( 0) +#define DIB3000MB_RESTART_AUTO_SEARCH (1 << 1) +#define DIB3000MB_RESTART_CTRL (1 << 2) +#define DIB3000MB_RESTART_AGC (1 << 3) + +/* FFT size */ +#define DIB3000MB_REG_FFT ( 1) + +/* Guard time */ +#define DIB3000MB_REG_GUARD_TIME ( 2) + +/* QAM */ +#define DIB3000MB_REG_QAM ( 3) + +/* Alpha coefficient high priority Viterbi algorithm */ +#define DIB3000MB_REG_VIT_ALPHA ( 4) + +/* spectrum inversion */ +#define DIB3000MB_REG_DDS_INV ( 5) + +/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */ +#define DIB3000MB_REG_DDS_FREQ_MSB ( 6) +#define DIB3000MB_REG_DDS_FREQ_LSB ( 7) +#define DIB3000MB_DDS_FREQ_MSB ( 178) +#define DIB3000MB_DDS_FREQ_LSB ( 8990) + +/* timing frequency (carrier spacing) */ +static u16 dib3000mb_reg_timing_freq[] = { 8,9 }; +static u16 dib3000mb_timing_freq[][2] = { + { 126 , 48873 }, /* 6 MHz */ + { 147 , 57019 }, /* 7 MHz */ + { 168 , 65164 }, /* 8 MHz */ +}; + +/* impulse noise parameter */ +/* 36 ??? */ + +static u16 dib3000mb_reg_impulse_noise[] = { 10,11,12,15,36 }; + +enum dib3000mb_impulse_noise_type { + DIB3000MB_IMPNOISE_OFF, + DIB3000MB_IMPNOISE_MOBILE, + DIB3000MB_IMPNOISE_FIXED, + DIB3000MB_IMPNOISE_DEFAULT +}; + +static u16 dib3000mb_impulse_noise_values[][5] = { + { 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */ + { 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */ + { 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */ + { 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */ +}; + +/* + * Dual Automatic-Gain-Control + * - gains RF in tuner (AGC1) + * - gains IF after filtering (AGC2) + */ + +/* also from 16 to 18 */ +static u16 dib3000mb_reg_agc_gain[] = { + 19,20,21,22,23,24,25,26,27,28,29,30,31,32 +}; + +static u16 dib3000mb_default_agc_gain[] = + { 0x0001, 52429, 623, 128, 166, 195, 61, /* RF ??? */ + 0x0001, 53766, 38011, 0, 90, 33, 23 }; /* IF ??? */ + +/* phase noise */ +/* 36 is set when setting the impulse noise */ +static u16 dib3000mb_reg_phase_noise[] = { 33,34,35,37,38 }; + +static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 }; + +/* lock duration */ +static u16 dib3000mb_reg_lock_duration[] = { 39,40 }; +static u16 dib3000mb_default_lock_duration[] = { 135, 135 }; + +/* AGC loop bandwidth */ +static u16 dib3000mb_reg_agc_bandwidth[] = { 43,44,45,46,47,48,49,50 }; + +static u16 dib3000mb_agc_bandwidth_low[] = + { 2088, 10, 2088, 10, 3448, 5, 3448, 5 }; +static u16 dib3000mb_agc_bandwidth_high[] = + { 2349, 5, 2349, 5, 2586, 2, 2586, 2 }; + +/* + * lock0 definition (coff_lock) + */ +#define DIB3000MB_REG_LOCK0_MASK ( 51) +#define DIB3000MB_LOCK0_DEFAULT ( 4) + +/* + * lock1 definition (cpil_lock) + * for auto search + * which values hide behind the lock masks + */ +#define DIB3000MB_REG_LOCK1_MASK ( 52) +#define DIB3000MB_LOCK1_SEARCH_4 (0x0004) +#define DIB3000MB_LOCK1_SEARCH_2048 (0x0800) +#define DIB3000MB_LOCK1_DEFAULT (0x0001) + +/* + * lock2 definition (fec_lock) */ +#define DIB3000MB_REG_LOCK2_MASK ( 53) +#define DIB3000MB_LOCK2_DEFAULT (0x0080) + +/* + * SEQ ? what was that again ... :) + * changes when, inversion, guard time and fft is + * either automatically detected or not + */ +#define DIB3000MB_REG_SEQ ( 54) + +/* bandwidth */ +static u16 dib3000mb_reg_bandwidth[] = { 55,56,57,58,59,60,61,62,63,64,65,66,67 }; +static u16 dib3000mb_bandwidth_6mhz[] = + { 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 }; + +static u16 dib3000mb_bandwidth_7mhz[] = + { 0, 28, 64421, 96, 39973, 483, 3255, 0, 1000, 0, 1010, 1, 45264 }; + +static u16 dib3000mb_bandwidth_8mhz[] = + { 0, 25, 23600, 84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 }; + +#define DIB3000MB_REG_UNK_68 ( 68) +#define DIB3000MB_UNK_68 ( 0) + +#define DIB3000MB_REG_UNK_69 ( 69) +#define DIB3000MB_UNK_69 ( 0) + +#define DIB3000MB_REG_UNK_71 ( 71) +#define DIB3000MB_UNK_71 ( 0) + +#define DIB3000MB_REG_UNK_77 ( 77) +#define DIB3000MB_UNK_77 ( 6) + +#define DIB3000MB_REG_UNK_78 ( 78) +#define DIB3000MB_UNK_78 (0x0080) + +/* isi */ +#define DIB3000MB_REG_ISI ( 79) +#define DIB3000MB_ISI_ACTIVATE ( 0) +#define DIB3000MB_ISI_INHIBIT ( 1) + +/* sync impovement */ +#define DIB3000MB_REG_SYNC_IMPROVEMENT ( 84) +#define DIB3000MB_SYNC_IMPROVE_2K_1_8 ( 3) +#define DIB3000MB_SYNC_IMPROVE_DEFAULT ( 0) + +/* phase noise compensation inhibition */ +#define DIB3000MB_REG_PHASE_NOISE ( 87) +#define DIB3000MB_PHASE_NOISE_DEFAULT ( 0) + +#define DIB3000MB_REG_UNK_92 ( 92) +#define DIB3000MB_UNK_92 (0x0080) + +#define DIB3000MB_REG_UNK_96 ( 96) +#define DIB3000MB_UNK_96 (0x0010) + +#define DIB3000MB_REG_UNK_97 ( 97) +#define DIB3000MB_UNK_97 (0x0009) + +/* mobile mode ??? */ +#define DIB3000MB_REG_MOBILE_MODE ( 101) +#define DIB3000MB_MOBILE_MODE_ON ( 1) +#define DIB3000MB_MOBILE_MODE_OFF ( 0) + +#define DIB3000MB_REG_UNK_106 ( 106) +#define DIB3000MB_UNK_106 (0x0080) + +#define DIB3000MB_REG_UNK_107 ( 107) +#define DIB3000MB_UNK_107 (0x0080) + +#define DIB3000MB_REG_UNK_108 ( 108) +#define DIB3000MB_UNK_108 (0x0080) + +/* fft */ +#define DIB3000MB_REG_UNK_121 ( 121) +#define DIB3000MB_UNK_121_2K ( 7) +#define DIB3000MB_UNK_121_DEFAULT ( 5) + +#define DIB3000MB_REG_UNK_122 ( 122) +#define DIB3000MB_UNK_122 ( 2867) + +/* QAM for mobile mode */ +#define DIB3000MB_REG_MOBILE_MODE_QAM ( 126) +#define DIB3000MB_MOBILE_MODE_QAM_64 ( 3) +#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16 ( 1) +#define DIB3000MB_MOBILE_MODE_QAM_OFF ( 0) + +/* + * data diversity when having more than one chip on-board + * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY + */ +#define DIB3000MB_REG_DATA_IN_DIVERSITY ( 127) +#define DIB3000MB_DATA_DIVERSITY_IN_OFF ( 0) +#define DIB3000MB_DATA_DIVERSITY_IN_ON ( 2) + +/* vit hrch */ +#define DIB3000MB_REG_VIT_HRCH ( 128) + +/* vit code rate */ +#define DIB3000MB_REG_VIT_CODE_RATE ( 129) + +/* vit select hp */ +#define DIB3000MB_REG_VIT_HP ( 130) + +/* time frame for Bit-Error-Rate calculation */ +#define DIB3000MB_REG_BERLEN ( 135) +#define DIB3000MB_BERLEN_LONG ( 0) +#define DIB3000MB_BERLEN_DEFAULT ( 1) +#define DIB3000MB_BERLEN_MEDIUM ( 2) +#define DIB3000MB_BERLEN_SHORT ( 3) + +/* 142 - 152 FIFO parameters + * which is what ? + */ + +#define DIB3000MB_REG_FIFO_142 ( 142) +#define DIB3000MB_FIFO_142 ( 0) + +/* MPEG2 TS output mode */ +#define DIB3000MB_REG_MPEG2_OUT_MODE ( 143) +#define DIB3000MB_MPEG2_OUT_MODE_204 ( 0) +#define DIB3000MB_MPEG2_OUT_MODE_188 ( 1) + +#define DIB3000MB_REG_PID_PARSE ( 144) +#define DIB3000MB_PID_PARSE_INHIBIT ( 0) +#define DIB3000MB_PID_PARSE_ACTIVATE ( 1) + +#define DIB3000MB_REG_FIFO ( 145) +#define DIB3000MB_FIFO_INHIBIT ( 1) +#define DIB3000MB_FIFO_ACTIVATE ( 0) + +#define DIB3000MB_REG_FIFO_146 ( 146) +#define DIB3000MB_FIFO_146 ( 3) + +#define DIB3000MB_REG_FIFO_147 ( 147) +#define DIB3000MB_FIFO_147 (0x0100) + +/* + * pidfilter + * it is not a hardware pidfilter but a filter which drops all pids + * except the ones set. Necessary because of the limited USB1.1 bandwidth. + * regs 153-168 + */ + +#define DIB3000MB_REG_FIRST_PID ( 153) +#define DIB3000MB_NUM_PIDS ( 16) + +/* + * output mode + * USB devices have to use 'slave'-mode + * see also DIB3000MB_REG_ELECT_OUT_MODE + */ +#define DIB3000MB_REG_OUTPUT_MODE ( 169) +#define DIB3000MB_OUTPUT_MODE_GATED_CLK ( 0) +#define DIB3000MB_OUTPUT_MODE_CONT_CLK ( 1) +#define DIB3000MB_OUTPUT_MODE_SERIAL ( 2) +#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY ( 5) +#define DIB3000MB_OUTPUT_MODE_SLAVE ( 6) + +/* irq event mask */ +#define DIB3000MB_REG_IRQ_EVENT_MASK ( 170) +#define DIB3000MB_IRQ_EVENT_MASK ( 0) + +/* filter coefficients */ +static u16 dib3000mb_reg_filter_coeffs[] = { + 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, + 188, 189, 190, 191, 192, 194 +}; + +static u16 dib3000mb_filter_coeffs[] = { + 226, 160, 29, + 979, 998, 19, + 22, 1019, 1006, + 1022, 12, 6, + 1017, 1017, 3, + 6, 1019, + 1021, 2, 3, + 1, 0, +}; + +/* + * mobile algorithm (when you are moving with your device) + * but not faster than 90 km/h + */ +#define DIB3000MB_REG_MOBILE_ALGO ( 195) +#define DIB3000MB_MOBILE_ALGO_ON ( 0) +#define DIB3000MB_MOBILE_ALGO_OFF ( 1) + +/* multiple demodulators algorithm */ +#define DIB3000MB_REG_MULTI_DEMOD_MSB ( 206) +#define DIB3000MB_REG_MULTI_DEMOD_LSB ( 207) + +/* terminator, no more demods */ +#define DIB3000MB_MULTI_DEMOD_MSB ( 32767) +#define DIB3000MB_MULTI_DEMOD_LSB ( 4095) + +/* bring the device into a known */ +#define DIB3000MB_REG_RESET_DEVICE ( 1024) +#define DIB3000MB_RESET_DEVICE (0x812c) +#define DIB3000MB_RESET_DEVICE_RST ( 0) + +/* hardware clock configuration */ +#define DIB3000MB_REG_CLOCK ( 1027) +#define DIB3000MB_CLOCK_DEFAULT (0x9000) +#define DIB3000MB_CLOCK_DIVERSITY (0x92b0) + +/* power down config */ +#define DIB3000MB_REG_POWER_CONTROL ( 1028) +#define DIB3000MB_POWER_DOWN ( 1) +#define DIB3000MB_POWER_UP ( 0) + +/* electrical output mode */ +#define DIB3000MB_REG_ELECT_OUT_MODE ( 1029) +#define DIB3000MB_ELECT_OUT_MODE_OFF ( 0) +#define DIB3000MB_ELECT_OUT_MODE_ON ( 1) + +/* set the tuner i2c address */ +#define DIB3000MB_REG_TUNER ( 1089) + +/* monitoring registers (read only) */ + +/* agc loop locked (size: 1) */ +#define DIB3000MB_REG_AGC_LOCK ( 324) + +/* agc power (size: 16) */ +#define DIB3000MB_REG_AGC_POWER ( 325) + +/* agc1 value (16) */ +#define DIB3000MB_REG_AGC1_VALUE ( 326) + +/* agc2 value (16) */ +#define DIB3000MB_REG_AGC2_VALUE ( 327) + +/* total RF power (16), can be used for signal strength */ +#define DIB3000MB_REG_RF_POWER ( 328) + +/* dds_frequency with offset (24) */ +#define DIB3000MB_REG_DDS_VALUE_MSB ( 339) +#define DIB3000MB_REG_DDS_VALUE_LSB ( 340) + +/* timing offset signed (24) */ +#define DIB3000MB_REG_TIMING_OFFSET_MSB ( 341) +#define DIB3000MB_REG_TIMING_OFFSET_LSB ( 342) + +/* fft start position (13) */ +#define DIB3000MB_REG_FFT_WINDOW_POS ( 353) + +/* carriers locked (1) */ +#define DIB3000MB_REG_CARRIER_LOCK ( 355) + +/* noise power (24) */ +#define DIB3000MB_REG_NOISE_POWER_MSB ( 372) +#define DIB3000MB_REG_NOISE_POWER_LSB ( 373) + +#define DIB3000MB_REG_MOBILE_NOISE_MSB ( 374) +#define DIB3000MB_REG_MOBILE_NOISE_LSB ( 375) + +/* + * signal power (16), this and the above can be + * used to calculate the signal/noise - ratio + */ +#define DIB3000MB_REG_SIGNAL_POWER ( 380) + +/* mer (24) */ +#define DIB3000MB_REG_MER_MSB ( 381) +#define DIB3000MB_REG_MER_LSB ( 382) + +/* + * Transmission Parameter Signalling (TPS) + * the following registers can be used to get TPS-information. + * The values are according to the DVB-T standard. + */ + +/* TPS locked (1) */ +#define DIB3000MB_REG_TPS_LOCK ( 394) + +/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */ +#define DIB3000MB_REG_TPS_QAM ( 398) + +/* hierarchy from TPS (1) */ +#define DIB3000MB_REG_TPS_HRCH ( 399) + +/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */ +#define DIB3000MB_REG_TPS_VIT_ALPHA ( 400) + +/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */ +#define DIB3000MB_REG_TPS_CODE_RATE_HP ( 401) + +/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */ +#define DIB3000MB_REG_TPS_CODE_RATE_LP ( 402) + +/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */ +#define DIB3000MB_REG_TPS_GUARD_TIME ( 403) + +/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */ +#define DIB3000MB_REG_TPS_FFT ( 404) + +/* cell id from TPS (16) */ +#define DIB3000MB_REG_TPS_CELL_ID ( 406) + +/* TPS (68) */ +#define DIB3000MB_REG_TPS_1 ( 408) +#define DIB3000MB_REG_TPS_2 ( 409) +#define DIB3000MB_REG_TPS_3 ( 410) +#define DIB3000MB_REG_TPS_4 ( 411) +#define DIB3000MB_REG_TPS_5 ( 412) + +/* bit error rate (before RS correction) (21) */ +#define DIB3000MB_REG_BER_MSB ( 414) +#define DIB3000MB_REG_BER_LSB ( 415) + +/* packet error rate (uncorrected TS packets) (16) */ +#define DIB3000MB_REG_PACKET_ERROR_RATE ( 417) + +/* uncorrected packet count (16) */ +#define DIB3000MB_REG_UNC ( 420) + +/* viterbi locked (1) */ +#define DIB3000MB_REG_VIT_LCK ( 421) + +/* viterbi inidcator (16) */ +#define DIB3000MB_REG_VIT_INDICATOR ( 422) + +/* transport stream sync lock (1) */ +#define DIB3000MB_REG_TS_SYNC_LOCK ( 423) + +/* transport stream RS lock (1) */ +#define DIB3000MB_REG_TS_RS_LOCK ( 424) + +/* lock mask 0 value (1) */ +#define DIB3000MB_REG_LOCK0_VALUE ( 425) + +/* lock mask 1 value (1) */ +#define DIB3000MB_REG_LOCK1_VALUE ( 426) + +/* lock mask 2 value (1) */ +#define DIB3000MB_REG_LOCK2_VALUE ( 427) + +/* interrupt pending for auto search */ +#define DIB3000MB_REG_AS_IRQ_PENDING ( 434) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mc.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,934 @@ +/* + * Driver for DiBcom DiB3000MC/P-demodulator. + * + * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * This code is partially based on the previous dib3000mc.c . + * + * 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, version 2. + */ + +#include +#include +#include + +#include "dvb_frontend.h" + +#include "dib3000mc.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) + +struct dib3000mc_state { + struct dvb_frontend demod; + struct dib3000mc_config *cfg; + + u8 i2c_addr; + struct i2c_adapter *i2c_adap; + + struct dibx000_i2c_master i2c_master; + + u32 timf; + + fe_bandwidth_t current_bandwidth; + + u16 dev_id; + + u8 sfn_workaround_active :1; +}; + +static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg) +{ + u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff }; + u8 rb[2]; + struct i2c_msg msg[2] = { + { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 }, + { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 }, + }; + + if (i2c_transfer(state->i2c_adap, msg, 2) != 2) + dprintk("i2c read error on %d\n",reg); + + return (rb[0] << 8) | rb[1]; +} + +static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val) +{ + u8 b[4] = { + (reg >> 8) & 0xff, reg & 0xff, + (val >> 8) & 0xff, val & 0xff, + }; + struct i2c_msg msg = { + .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 + }; + return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; +} + +static int dib3000mc_identify(struct dib3000mc_state *state) +{ + u16 value; + if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) { + dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value); + return -EREMOTEIO; + } + + value = dib3000mc_read_word(state, 1026); + if (value != 0x3001 && value != 0x3002) { + dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value); + return -EREMOTEIO; + } + state->dev_id = value; + + dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id); + + return 0; +} + +static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset) +{ + u32 timf; + + if (state->timf == 0) { + timf = 1384402; // default value for 8MHz + if (update_offset) + msleep(200); // first time we do an update + } else + timf = state->timf; + + timf *= (bw / 1000); + + if (update_offset) { + s16 tim_offs = dib3000mc_read_word(state, 416); + + if (tim_offs & 0x2000) + tim_offs -= 0x4000; + + if (nfft == TRANSMISSION_MODE_2K) + tim_offs *= 4; + + timf += tim_offs; + state->timf = timf / (bw / 1000); + } + + dprintk("timf: %d\n", timf); + + dib3000mc_write_word(state, 23, (u16) (timf >> 16)); + dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff); + + return 0; +} + +static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state) +{ + u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb; + if (state->cfg->pwm3_inversion) { + reg_51 = (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0); + reg_52 |= (1 << 2); + } else { + reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0); + reg_52 |= (1 << 8); + } + dib3000mc_write_word(state, 51, reg_51); + dib3000mc_write_word(state, 52, reg_52); + + if (state->cfg->use_pwm3) + dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0)); + else + dib3000mc_write_word(state, 245, 0); + + dib3000mc_write_word(state, 1040, 0x3); + return 0; +} + +static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode) +{ + int ret = 0; + u16 fifo_threshold = 1792; + u16 outreg = 0; + u16 outmode = 0; + u16 elecout = 1; + u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */ + + dprintk("-I- Setting output mode for demod %p to %d\n", + &state->demod, mode); + + switch (mode) { + case OUTMODE_HIGH_Z: // disable + elecout = 0; + break; + case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock + outmode = 0; + break; + case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock + outmode = 1; + break; + case OUTMODE_MPEG2_SERIAL: // STBs with serial input + outmode = 2; + break; + case OUTMODE_MPEG2_FIFO: // e.g. USB feeding + elecout = 3; + /*ADDR @ 206 : + P_smo_error_discard [1;6:6] = 0 + P_smo_rs_discard [1;5:5] = 0 + P_smo_pid_parse [1;4:4] = 0 + P_smo_fifo_flush [1;3:3] = 0 + P_smo_mode [2;2:1] = 11 + P_smo_ovf_prot [1;0:0] = 0 + */ + smo_reg |= 3 << 1; + fifo_threshold = 512; + outmode = 5; + break; + case OUTMODE_DIVERSITY: + outmode = 4; + elecout = 1; + break; + default: + dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + outmode = 0; + break; + } + + if ((state->cfg->output_mpeg2_in_188_bytes)) + smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1 + + outreg = dib3000mc_read_word(state, 244) & 0x07FF; + outreg |= (outmode << 11); + ret |= dib3000mc_write_word(state, 244, outreg); + ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/ + ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */ + ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */ + return ret; +} + +static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw) +{ + u16 bw_cfg[6] = { 0 }; + u16 imp_bw_cfg[3] = { 0 }; + u16 reg; + +/* settings here are for 27.7MHz */ + switch (bw) { + case 8000: + bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20; + imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7; + break; + + case 7000: + bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7; + imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0; + break; + + case 6000: + bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5; + imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089; + break; + + case 5000: + bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500; + imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072; + break; + + default: return -EINVAL; + } + + for (reg = 6; reg < 12; reg++) + dib3000mc_write_word(state, reg, bw_cfg[reg - 6]); + dib3000mc_write_word(state, 12, 0x0000); + dib3000mc_write_word(state, 13, 0x03e8); + dib3000mc_write_word(state, 14, 0x0000); + dib3000mc_write_word(state, 15, 0x03f2); + dib3000mc_write_word(state, 16, 0x0001); + dib3000mc_write_word(state, 17, 0xb0d0); + // P_sec_len + dib3000mc_write_word(state, 18, 0x0393); + dib3000mc_write_word(state, 19, 0x8700); + + for (reg = 55; reg < 58; reg++) + dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]); + + // Timing configuration + dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0); + + return 0; +} + +static u16 impulse_noise_val[29] = + +{ + 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3, + 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2, + 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd +}; + +static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft) +{ + u16 i; + for (i = 58; i < 87; i++) + dib3000mc_write_word(state, i, impulse_noise_val[i-58]); + + if (nfft == TRANSMISSION_MODE_8K) { + dib3000mc_write_word(state, 58, 0x3b); + dib3000mc_write_word(state, 84, 0x00); + dib3000mc_write_word(state, 85, 0x8200); + } + + dib3000mc_write_word(state, 34, 0x1294); + dib3000mc_write_word(state, 35, 0x1ff8); + if (mode == 1) + dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10)); +} + +static int dib3000mc_init(struct dvb_frontend *demod) +{ + struct dib3000mc_state *state = demod->demodulator_priv; + struct dibx000_agc_config *agc = state->cfg->agc; + + // Restart Configuration + dib3000mc_write_word(state, 1027, 0x8000); + dib3000mc_write_word(state, 1027, 0x0000); + + // power up the demod + mobility configuration + dib3000mc_write_word(state, 140, 0x0000); + dib3000mc_write_word(state, 1031, 0); + + if (state->cfg->mobile_mode) { + dib3000mc_write_word(state, 139, 0x0000); + dib3000mc_write_word(state, 141, 0x0000); + dib3000mc_write_word(state, 175, 0x0002); + dib3000mc_write_word(state, 1032, 0x0000); + } else { + dib3000mc_write_word(state, 139, 0x0001); + dib3000mc_write_word(state, 141, 0x0000); + dib3000mc_write_word(state, 175, 0x0000); + dib3000mc_write_word(state, 1032, 0x012C); + } + dib3000mc_write_word(state, 1033, 0x0000); + + // P_clk_cfg + dib3000mc_write_word(state, 1037, 0x3130); + + // other configurations + + // P_ctrl_sfreq + dib3000mc_write_word(state, 33, (5 << 0)); + dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0)); + + // Phase noise control + // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange + dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0)); + + if (state->cfg->phase_noise_mode == 0) + dib3000mc_write_word(state, 111, 0x00); + else + dib3000mc_write_word(state, 111, 0x02); + + // P_agc_global + dib3000mc_write_word(state, 50, 0x8000); + + // agc setup misc + dib3000mc_setup_pwm_state(state); + + // P_agc_counter_lock + dib3000mc_write_word(state, 53, 0x87); + // P_agc_counter_unlock + dib3000mc_write_word(state, 54, 0x87); + + /* agc */ + dib3000mc_write_word(state, 36, state->cfg->max_time); + dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0)); + dib3000mc_write_word(state, 38, state->cfg->pwm3_value); + dib3000mc_write_word(state, 39, state->cfg->ln_adc_level); + + // set_agc_loop_Bw + dib3000mc_write_word(state, 40, 0x0179); + dib3000mc_write_word(state, 41, 0x03f0); + + dib3000mc_write_word(state, 42, agc->agc1_max); + dib3000mc_write_word(state, 43, agc->agc1_min); + dib3000mc_write_word(state, 44, agc->agc2_max); + dib3000mc_write_word(state, 45, agc->agc2_min); + dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2); + dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2); + dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2); + +// Begin: TimeOut registers + // P_pha3_thres + dib3000mc_write_word(state, 110, 3277); + // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80 + dib3000mc_write_word(state, 26, 0x6680); + // lock_mask0 + dib3000mc_write_word(state, 1, 4); + // lock_mask1 + dib3000mc_write_word(state, 2, 4); + // lock_mask2 + dib3000mc_write_word(state, 3, 0x1000); + // P_search_maxtrial=1 + dib3000mc_write_word(state, 5, 1); + + dib3000mc_set_bandwidth(state, 8000); + + // div_lock_mask + dib3000mc_write_word(state, 4, 0x814); + + dib3000mc_write_word(state, 21, (1 << 9) | 0x164); + dib3000mc_write_word(state, 22, 0x463d); + + // Spurious rm cfg + // P_cspu_regul, P_cspu_win_cut + dib3000mc_write_word(state, 120, 0x200f); + // P_adp_selec_monit + dib3000mc_write_word(state, 134, 0); + + // Fec cfg + dib3000mc_write_word(state, 195, 0x10); + + // diversity register: P_dvsy_sync_wait.. + dib3000mc_write_word(state, 180, 0x2FF0); + + // Impulse noise configuration + dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K); + + // output mode set-up + dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); + + /* close the i2c-gate */ + dib3000mc_write_word(state, 769, (1 << 7) ); + + return 0; +} + +static int dib3000mc_sleep(struct dvb_frontend *demod) +{ + struct dib3000mc_state *state = demod->demodulator_priv; + + dib3000mc_write_word(state, 1031, 0xFFFF); + dib3000mc_write_word(state, 1032, 0xFFFF); + dib3000mc_write_word(state, 1033, 0xFFF0); + + return 0; +} + +static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) +{ + u16 cfg[4] = { 0 },reg; + switch (qam) { + case QPSK: + cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0; + break; + case QAM_16: + cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0; + break; + case QAM_64: + cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8; + break; + } + for (reg = 129; reg < 133; reg++) + dib3000mc_write_word(state, reg, cfg[reg - 129]); +} + +static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) +{ + u16 value; + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); + +// if (boost) +// dib3000mc_write_word(state, 100, (11 << 6) + 6); +// else + dib3000mc_write_word(state, 100, (16 << 6) + 9); + + dib3000mc_write_word(state, 1027, 0x0800); + dib3000mc_write_word(state, 1027, 0x0000); + + //Default cfg isi offset adp + dib3000mc_write_word(state, 26, 0x6680); + dib3000mc_write_word(state, 29, 0x1273); + dib3000mc_write_word(state, 33, 5); + dib3000mc_set_adp_cfg(state, QAM_16); + dib3000mc_write_word(state, 133, 15564); + + dib3000mc_write_word(state, 12 , 0x0); + dib3000mc_write_word(state, 13 , 0x3e8); + dib3000mc_write_word(state, 14 , 0x0); + dib3000mc_write_word(state, 15 , 0x3f2); + + dib3000mc_write_word(state, 93,0); + dib3000mc_write_word(state, 94,0); + dib3000mc_write_word(state, 95,0); + dib3000mc_write_word(state, 96,0); + dib3000mc_write_word(state, 97,0); + dib3000mc_write_word(state, 98,0); + + dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); + + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib3000mc_write_word(state, 0, value); + dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); + + value = 0; + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib3000mc_write_word(state, 181, value); + + // diversity synchro delay add 50% SFN margin + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + value <<= 4; + value |= dib3000mc_read_word(state, 180) & 0x000f; + dib3000mc_write_word(state, 180, value); + + // restart demod + value = dib3000mc_read_word(state, 0); + dib3000mc_write_word(state, 0, value | (1 << 9)); + dib3000mc_write_word(state, 0, value); + + msleep(30); + + dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); +} + +static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) +{ + struct dib3000mc_state *state = demod->demodulator_priv; + u16 reg; +// u32 val; + struct dvb_frontend_parameters schan; + + schan = *chan; + + /* TODO what is that ? */ + + /* a channel for autosearch */ + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_2_3; + schan.u.ofdm.hierarchy_information = 0; + + dib3000mc_set_channel_cfg(state, &schan, 11); + + reg = dib3000mc_read_word(state, 0); + dib3000mc_write_word(state, 0, reg | (1 << 8)); + dib3000mc_read_word(state, 511); + dib3000mc_write_word(state, 0, reg); + + return 0; +} + +static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) +{ + struct dib3000mc_state *state = demod->demodulator_priv; + u16 irq_pending = dib3000mc_read_word(state, 511); + + if (irq_pending & 0x1) // failed + return 1; + + if (irq_pending & 0x2) // succeeded + return 2; + + return 0; // still pending +} + +static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib3000mc_state *state = demod->demodulator_priv; + + // ** configure demod ** + dib3000mc_set_channel_cfg(state, ch, 0); + + // activates isi + if (state->sfn_workaround_active) { + dprintk("SFN workaround is active\n"); + dib3000mc_write_word(state, 29, 0x1273); + dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift + } else { + dib3000mc_write_word(state, 29, 0x1073); + dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift + } + + dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); + if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { + dib3000mc_write_word(state, 26, 38528); + dib3000mc_write_word(state, 33, 8); + } else { + dib3000mc_write_word(state, 26, 30336); + dib3000mc_write_word(state, 33, 6); + } + + if (dib3000mc_read_word(state, 509) & 0x80) + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); + + return 0; +} + +struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating) +{ + struct dib3000mc_state *st = demod->demodulator_priv; + return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating); +} + +EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master); + +static int dib3000mc_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + u16 tps = dib3000mc_read_word(state,458); + + fep->inversion = INVERSION_AUTO; + + fep->u.ofdm.bandwidth = state->current_bandwidth; + + switch ((tps >> 8) & 0x1) { + case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; + case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; + } + + switch (tps & 0x3) { + case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; + case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; + case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; + case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; + } + + switch ((tps >> 13) & 0x3) { + case 0: fep->u.ofdm.constellation = QPSK; break; + case 1: fep->u.ofdm.constellation = QAM_16; break; + case 2: + default: fep->u.ofdm.constellation = QAM_64; break; + } + + /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ + /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */ + + fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + switch ((tps >> 5) & 0x7) { + case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; + case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; + case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; + case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; + case 7: + default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; + + } + + switch ((tps >> 2) & 0x7) { + case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; + case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; + case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; + case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; + case 7: + default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; + } + + return 0; +} + +static int dib3000mc_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + int ret; + + dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); + + state->current_bandwidth = fep->u.ofdm.bandwidth; + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, fep); + msleep(100); + } + + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || + fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || + fep->u.ofdm.constellation == QAM_AUTO || + fep->u.ofdm.code_rate_HP == FEC_AUTO) { + int i = 1000, found; + + dib3000mc_autosearch_start(fe, fep); + do { + msleep(1); + found = dib3000mc_autosearch_is_irq(fe); + } while (found == 0 && i--); + + dprintk("autosearch returns: %d\n",found); + if (found == 0 || found == 1) + return 0; // no channel found + + dib3000mc_get_frontend(fe, fep); + } + + ret = dib3000mc_tune(fe, fep); + + /* make this a config parameter */ + dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); + return ret; +} + +static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + u16 lock = dib3000mc_read_word(state, 509); + + *stat = 0; + + if (lock & 0x8000) + *stat |= FE_HAS_SIGNAL; + if (lock & 0x3000) + *stat |= FE_HAS_CARRIER; + if (lock & 0x0100) + *stat |= FE_HAS_VITERBI; + if (lock & 0x0010) + *stat |= FE_HAS_SYNC; + if (lock & 0x0008) + *stat |= FE_HAS_LOCK; + + return 0; +} + +static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501); + return 0; +} + +static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + *unc = dib3000mc_read_word(state, 508); + return 0; +} + +static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + u16 val = dib3000mc_read_word(state, 392); + *strength = 65535 - val; + return 0; +} + +static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + *snr = 0x0000; + return 0; +} + +static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void dib3000mc_release(struct dvb_frontend *fe) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + dibx000_exit_i2c_master(&state->i2c_master); + kfree(state); +} + +int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0); + return 0; +} +EXPORT_SYMBOL(dib3000mc_pid_control); + +int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4); + tmp |= (onoff << 4); + return dib3000mc_write_word(state, 206, tmp); +} +EXPORT_SYMBOL(dib3000mc_pid_parse); + +void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg) +{ + struct dib3000mc_state *state = fe->demodulator_priv; + state->cfg = cfg; +} +EXPORT_SYMBOL(dib3000mc_set_config); + +int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]) +{ + struct dib3000mc_state *dmcst; + int k; + u8 new_addr; + + static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26}; + + dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL); + if (dmcst == NULL) + return -ENOMEM; + + dmcst->i2c_adap = i2c; + + for (k = no_of_demods-1; k >= 0; k--) { + dmcst->cfg = &cfg[k]; + + /* designated i2c address */ + new_addr = DIB3000MC_I2C_ADDRESS[k]; + dmcst->i2c_addr = new_addr; + if (dib3000mc_identify(dmcst) != 0) { + dmcst->i2c_addr = default_addr; + if (dib3000mc_identify(dmcst) != 0) { + dprintk("-E- DiB3000P/MC #%d: not identified\n", k); + kfree(dmcst); + return -ENODEV; + } + } + + dib3000mc_set_output_mode(dmcst, OUTMODE_MPEG2_PAR_CONT_CLK); + + // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0) + dib3000mc_write_word(dmcst, 1024, (new_addr << 3) | 0x1); + dmcst->i2c_addr = new_addr; + } + + for (k = 0; k < no_of_demods; k++) { + dmcst->cfg = &cfg[k]; + dmcst->i2c_addr = DIB3000MC_I2C_ADDRESS[k]; + + dib3000mc_write_word(dmcst, 1024, dmcst->i2c_addr << 3); + + /* turn off data output */ + dib3000mc_set_output_mode(dmcst, OUTMODE_HIGH_Z); + } + + kfree(dmcst); + return 0; +} +EXPORT_SYMBOL(dib3000mc_i2c_enumeration); + +static struct dvb_frontend_ops dib3000mc_ops; + +struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg) +{ + struct dvb_frontend *demod; + struct dib3000mc_state *st; + st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL); + if (st == NULL) + return NULL; + + st->cfg = cfg; + st->i2c_adap = i2c_adap; + st->i2c_addr = i2c_addr; + + demod = &st->demod; + demod->demodulator_priv = st; + memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); + + if (dib3000mc_identify(st) != 0) + goto error; + + dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr); + + dib3000mc_write_word(st, 1037, 0x3130); + + return demod; + +error: + kfree(st); + return NULL; +} +EXPORT_SYMBOL(dib3000mc_attach); + +static struct dvb_frontend_ops dib3000mc_ops = { + .info = { + .name = "DiBcom 3000MC/P", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = dib3000mc_release, + + .init = dib3000mc_init, + .sleep = dib3000mc_sleep, + + .set_frontend = dib3000mc_set_frontend, + .get_tune_settings = dib3000mc_fe_get_tune_settings, + .get_frontend = dib3000mc_get_frontend, + + .read_status = dib3000mc_read_status, + .read_ber = dib3000mc_read_ber, + .read_signal_strength = dib3000mc_read_signal_strength, + .read_snr = dib3000mc_read_snr, + .read_ucblocks = dib3000mc_read_unc_blocks, +}; + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mc.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib3000mc.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Driver for DiBcom DiB3000MC/P-demodulator. + * + * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher\@desy.de) + * + * This code is partially based on the previous dib3000mc.c . + * + * 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, version 2. + */ +#ifndef DIB3000MC_H +#define DIB3000MC_H + +#include "dibx000_common.h" + +struct dib3000mc_config { + struct dibx000_agc_config *agc; + + u8 phase_noise_mode; + u8 impulse_noise_mode; + + u8 pwm3_inversion; + u8 use_pwm3; + u16 pwm3_value; + + u16 max_time; + u16 ln_adc_level; + + u8 agc_command1 :1; + u8 agc_command2 :1; + + u8 mobile_mode; + + u8 output_mpeg2_in_188_bytes; +}; + +#define DEFAULT_DIB3000MC_I2C_ADDRESS 16 +#define DEFAULT_DIB3000P_I2C_ADDRESS 24 + +#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && \ + defined(MODULE)) +extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct dib3000mc_config *cfg); +extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, + int no_of_demods, u8 default_addr, + struct dib3000mc_config cfg[]); +extern +struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, + int gating); +#else +static inline +struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, + struct dib3000mc_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline +int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, + int no_of_demods, u8 default_addr, + struct dib3000mc_config cfg[]) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline +struct i2c_adapter *dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, + int gating) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_DIB3000MC + +extern int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff); +extern int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff); + +extern void dib3000mc_set_config(struct dvb_frontend *, struct dib3000mc_config *); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000m.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000m.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000m.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000m.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1444 @@ +/* + * Linux-DVB Driver for DiBcom's DiB7000M and + * first generation DiB7000P-demodulator-family. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#include +#include +#include + +#include "dvb_frontend.h" + +#include "dib7000m.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0) + +struct dib7000m_state { + struct dvb_frontend demod; + struct dib7000m_config cfg; + + u8 i2c_addr; + struct i2c_adapter *i2c_adap; + + struct dibx000_i2c_master i2c_master; + +/* offset is 1 in case of the 7000MC */ + u8 reg_offs; + + u16 wbd_ref; + + u8 current_band; + fe_bandwidth_t current_bandwidth; + struct dibx000_agc_config *current_agc; + u32 timf; + u32 timf_default; + u32 internal_clk; + + u8 div_force_off : 1; + u8 div_state : 1; + u16 div_sync_wait; + + u16 revision; + + u8 agc_state; + + /* for the I2C transfer */ + struct i2c_msg msg[2]; + u8 i2c_write_buffer[4]; + u8 i2c_read_buffer[2]; +}; + +enum dib7000m_power_mode { + DIB7000M_POWER_ALL = 0, + + DIB7000M_POWER_NO, + DIB7000M_POWER_INTERF_ANALOG_AGC, + DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD, + DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD, + DIB7000M_POWER_INTERFACE_ONLY, +}; + +static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) +{ + state->i2c_write_buffer[0] = (reg >> 8) | 0x80; + state->i2c_write_buffer[1] = reg & 0xff; + + memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); + state->msg[0].addr = state->i2c_addr >> 1; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 2; + state->msg[1].addr = state->i2c_addr >> 1; + state->msg[1].flags = I2C_M_RD; + state->msg[1].buf = state->i2c_read_buffer; + state->msg[1].len = 2; + + if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) + dprintk("i2c read error on %d",reg); + + return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; +} + +static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) +{ + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; + state->i2c_write_buffer[1] = reg & 0xff; + state->i2c_write_buffer[2] = (val >> 8) & 0xff; + state->i2c_write_buffer[3] = val & 0xff; + + memset(&state->msg[0], 0, sizeof(struct i2c_msg)); + state->msg[0].addr = state->i2c_addr >> 1; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 4; + + return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; +} +static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC + r++; + + do { + dib7000m_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + +static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) +{ + int ret = 0; + u16 outreg, fifo_threshold, smo_mode, + sram = 0x0005; /* by default SRAM output is disabled */ + + outreg = 0; + fifo_threshold = 1792; + smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1); + + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); + + switch (mode) { + case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock + outreg = (1 << 10); /* 0x0400 */ + break; + case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock + outreg = (1 << 10) | (1 << 6); /* 0x0440 */ + break; + case OUTMODE_MPEG2_SERIAL: // STBs with serial input + outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ + break; + case OUTMODE_DIVERSITY: + if (state->cfg.hostbus_diversity) + outreg = (1 << 10) | (4 << 6); /* 0x0500 */ + else + sram |= 0x0c00; + break; + case OUTMODE_MPEG2_FIFO: // e.g. USB feeding + smo_mode |= (3 << 1); + fifo_threshold = 512; + outreg = (1 << 10) | (5 << 6); + break; + case OUTMODE_HIGH_Z: // disable + outreg = 0; + break; + default: + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); + break; + } + + if (state->cfg.output_mpeg2_in_188_bytes) + smo_mode |= (1 << 5) ; + + ret |= dib7000m_write_word(state, 294 + state->reg_offs, smo_mode); + ret |= dib7000m_write_word(state, 295 + state->reg_offs, fifo_threshold); /* synchronous fread */ + ret |= dib7000m_write_word(state, 1795, outreg); + ret |= dib7000m_write_word(state, 1805, sram); + + if (state->revision == 0x4003) { + u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd; + if (mode == OUTMODE_DIVERSITY) + clk_cfg1 |= (1 << 1); // P_O_CLK_en + dib7000m_write_word(state, 909, clk_cfg1); + } + return ret; +} + +static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) +{ + /* by default everything is going to be powered off */ + u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff; + u8 offset = 0; + + /* now, depending on the requested mode, we power on */ + switch (mode) { + /* power up everything in the demod */ + case DIB7000M_POWER_ALL: + reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000; + break; + + /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */ + case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */ + reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)); + break; + + case DIB7000M_POWER_INTERF_ANALOG_AGC: + reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10)); + reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2)); + reg_906 &= ~((1 << 0)); + break; + + case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD: + reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000; + break; + + case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD: + reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000; + break; + case DIB7000M_POWER_NO: + break; + } + + /* always power down unused parts */ + if (!state->cfg.mobile_mode) + reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); + + /* P_sdio_select_clk = 0 on MC and after*/ + if (state->revision != 0x4000) + reg_906 <<= 1; + + if (state->revision == 0x4003) + offset = 1; + + dib7000m_write_word(state, 903 + offset, reg_903); + dib7000m_write_word(state, 904 + offset, reg_904); + dib7000m_write_word(state, 905 + offset, reg_905); + dib7000m_write_word(state, 906 + offset, reg_906); +} + +static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no) +{ + int ret = 0; + u16 reg_913 = dib7000m_read_word(state, 913), + reg_914 = dib7000m_read_word(state, 914); + + switch (no) { + case DIBX000_SLOW_ADC_ON: + reg_914 |= (1 << 1) | (1 << 0); + ret |= dib7000m_write_word(state, 914, reg_914); + reg_914 &= ~(1 << 1); + break; + + case DIBX000_SLOW_ADC_OFF: + reg_914 |= (1 << 1) | (1 << 0); + break; + + case DIBX000_ADC_ON: + if (state->revision == 0x4000) { // workaround for PA/MA + // power-up ADC + dib7000m_write_word(state, 913, 0); + dib7000m_write_word(state, 914, reg_914 & 0x3); + // power-down bandgag + dib7000m_write_word(state, 913, (1 << 15)); + dib7000m_write_word(state, 914, reg_914 & 0x3); + } + + reg_913 &= 0x0fff; + reg_914 &= 0x0003; + break; + + case DIBX000_ADC_OFF: // leave the VBG voltage on + reg_913 |= (1 << 14) | (1 << 13) | (1 << 12); + reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); + break; + + case DIBX000_VBG_ENABLE: + reg_913 &= ~(1 << 15); + break; + + case DIBX000_VBG_DISABLE: + reg_913 |= (1 << 15); + break; + + default: + break; + } + +// dprintk( "913: %x, 914: %x", reg_913, reg_914); + ret |= dib7000m_write_word(state, 913, reg_913); + ret |= dib7000m_write_word(state, 914, reg_914); + + return ret; +} + +static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) +{ + u32 timf; + + // store the current bandwidth for later use + state->current_bandwidth = bw; + + if (state->timf == 0) { + dprintk( "using default timf"); + timf = state->timf_default; + } else { + dprintk( "using updated timf"); + timf = state->timf; + } + + timf = timf * (bw / 50) / 160; + + dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff)); + + return 0; +} + +static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000m_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (u8)onoff; + + if (onoff) { + dib7000m_write_word(state, 263 + state->reg_offs, 6); + dib7000m_write_word(state, 264 + state->reg_offs, 6); + dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000m_write_word(state, 263 + state->reg_offs, 1); + dib7000m_write_word(state, 264 + state->reg_offs, 0); + dib7000m_write_word(state, 266 + state->reg_offs, 0); + } + + return 0; +} + +static int dib7000m_sad_calib(struct dib7000m_state *state) +{ + +/* internal */ +// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth + dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); + dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 + + /* do the calibration */ + dib7000m_write_word(state, 929, (1 << 0)); + dib7000m_write_word(state, 929, (0 << 0)); + + msleep(1); + + return 0; +} + +static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw) +{ + dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff)); + dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff)); + + dib7000m_write_word(state, 928, bw->sad_cfg); +} + +static void dib7000m_reset_pll(struct dib7000m_state *state) +{ + const struct dibx000_bandwidth_config *bw = state->cfg.bw; + u16 reg_907,reg_910; + + /* default */ + reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) | + (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | + (bw->enable_refdiv << 1) | (0 << 0); + reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset; + + // for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value) + // this is only working only for 30 MHz crystals + if (!state->cfg.quartz_direct) { + reg_910 |= (1 << 5); // forcing the predivider to 1 + + // if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2) + if(state->cfg.input_clk_is_div_2) + reg_907 |= (16 << 9); + else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary + reg_907 |= (8 << 9); + } else { + reg_907 |= (bw->pll_ratio & 0x3f) << 9; + reg_910 |= (bw->pll_prediv << 5); + } + + dib7000m_write_word(state, 910, reg_910); // pll cfg + dib7000m_write_word(state, 907, reg_907); // clk cfg0 + dib7000m_write_word(state, 908, 0x0006); // clk_cfg1 + + dib7000m_reset_pll_common(state, bw); +} + +static void dib7000mc_reset_pll(struct dib7000m_state *state) +{ + const struct dibx000_bandwidth_config *bw = state->cfg.bw; + u16 clk_cfg1; + + // clk_cfg0 + dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0)); + + // clk_cfg1 + //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) | + clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) | + (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) | + (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0); + dib7000m_write_word(state, 908, clk_cfg1); + clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3); + dib7000m_write_word(state, 908, clk_cfg1); + + // smpl_cfg + dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7)); + + dib7000m_reset_pll_common(state, bw); +} + +static int dib7000m_reset_gpio(struct dib7000m_state *st) +{ + /* reset the GPIOs */ + dib7000m_write_word(st, 773, st->cfg.gpio_dir); + dib7000m_write_word(st, 774, st->cfg.gpio_val); + + /* TODO 782 is P_gpio_od */ + + dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos); + + dib7000m_write_word(st, 780, st->cfg.pwm_freq_div); + return 0; +} + +static u16 dib7000m_defaults_common[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_corm_thres Lock algorithms configuration + + 1, 170, + 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on + + 8, 173, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 182, + 8192, // P_fft_nb_to_cut + + 2, 195, + 0x0ccd, // P_pha3_thres + 0, // P_cti_use_cpe, P_cti_use_prog + + 1, 205, + 0x200f, // P_cspu_regul, P_cspu_win_cut + + 5, 214, + 0x023d, // P_adp_regul_cnt + 0x00a4, // P_adp_noise_cnt + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 226, + 0, // P_2d_byp_ti_num + + 1, 255, + 0x800, // P_equal_thres_wgn + + 1, 263, + 0x0001, + + 1, 281, + 0x0010, // P_fec_* + + 1, 294, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 0 +}; + +static u16 dib7000m_defaults[] = + +{ + /* set ADC level to -16 */ + 11, 76, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + // Tuner IO bank: max drive (14mA) + 1, 912, + 0x2c8a, + + 1, 1817, + 1, + + 0, +}; + +static int dib7000m_demod_reset(struct dib7000m_state *state) +{ + dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); + + /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ + dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE); + + /* restart all parts */ + dib7000m_write_word(state, 898, 0xffff); + dib7000m_write_word(state, 899, 0xffff); + dib7000m_write_word(state, 900, 0xff0f); + dib7000m_write_word(state, 901, 0xfffc); + + dib7000m_write_word(state, 898, 0); + dib7000m_write_word(state, 899, 0); + dib7000m_write_word(state, 900, 0); + dib7000m_write_word(state, 901, 0); + + if (state->revision == 0x4000) + dib7000m_reset_pll(state); + else + dib7000mc_reset_pll(state); + + if (dib7000m_reset_gpio(state) != 0) + dprintk( "GPIO reset was not successful."); + + if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0) + dprintk( "OUTPUT_MODE could not be reset."); + + /* unforce divstr regardless whether i2c enumeration was done or not */ + dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) ); + + dib7000m_set_bandwidth(state, 8000); + + dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON); + dib7000m_sad_calib(state); + dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + + if (state->cfg.dvbt_mode) + dib7000m_write_word(state, 1796, 0x0); // select DVB-T output + + if (state->cfg.mobile_mode) + dib7000m_write_word(state, 261 + state->reg_offs, 2); + else + dib7000m_write_word(state, 224 + state->reg_offs, 1); + + // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000m_write_word(state, 36, 0x0755); + else + dib7000m_write_word(state, 36, 0x1f55); + + // P_divclksel=3 P_divbitsel=1 + if (state->revision == 0x4000) + dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); + else + dib7000m_write_word(state, 909, (3 << 4) | 1); + + dib7000m_write_tab(state, dib7000m_defaults_common); + dib7000m_write_tab(state, dib7000m_defaults); + + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY); + + state->internal_clk = state->cfg.bw->internal; + + return 0; +} + +static void dib7000m_restart_agc(struct dib7000m_state *state) +{ + // P_restart_iqc & P_restart_agc + dib7000m_write_word(state, 898, 0x0c00); + dib7000m_write_word(state, 898, 0x0000); +} + +static int dib7000m_agc_soft_split(struct dib7000m_state *state) +{ + u16 agc,split_offset; + + if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) + return 0; + + // n_agc_global + agc = dib7000m_read_word(state, 390); + + if (agc > state->current_agc->split.min_thres) + split_offset = state->current_agc->split.min; + else if (agc < state->current_agc->split.max_thres) + split_offset = state->current_agc->split.max; + else + split_offset = state->current_agc->split.max * + (agc - state->current_agc->split.min_thres) / + (state->current_agc->split.max_thres - state->current_agc->split.min_thres); + + dprintk( "AGC split_offset: %d",split_offset); + + // P_agc_force_split and P_agc_split_offset + return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset); +} + +static int dib7000m_update_lna(struct dib7000m_state *state) +{ + u16 dyn_gain; + + if (state->cfg.update_lna) { + // read dyn_gain here (because it is demod-dependent and not fe) + dyn_gain = dib7000m_read_word(state, 390); + + if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed + dib7000m_restart_agc(state); + return 1; + } + } + return 0; +} + +static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) +{ + struct dibx000_agc_config *agc = NULL; + int i; + if (state->current_band == band && state->current_agc != NULL) + return 0; + state->current_band = band; + + for (i = 0; i < state->cfg.agc_config_count; i++) + if (state->cfg.agc[i].band_caps & band) { + agc = &state->cfg.agc[i]; + break; + } + + if (agc == NULL) { + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; + } + + state->current_agc = agc; + + /* AGC */ + dib7000m_write_word(state, 72 , agc->setup); + dib7000m_write_word(state, 73 , agc->inv_gain); + dib7000m_write_word(state, 74 , agc->time_stabiliz); + dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock); + + // Demod AGC loop configuration + dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp); + dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp); + + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", + state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); + + /* AGC continued */ + if (state->wbd_ref != 0) + dib7000m_write_word(state, 102, state->wbd_ref); + else // use default + dib7000m_write_word(state, 102, agc->wbd_ref); + + dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) ); + dib7000m_write_word(state, 104, agc->agc1_max); + dib7000m_write_word(state, 105, agc->agc1_min); + dib7000m_write_word(state, 106, agc->agc2_max); + dib7000m_write_word(state, 107, agc->agc2_min); + dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 ); + dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2); + dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2); + + if (state->revision > 0x4000) { // settings for the MC + dib7000m_write_word(state, 71, agc->agc1_pt3); +// dprintk( "929: %x %d %d", +// (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel); + dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); + } else { + // wrong default values + u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 }; + for (i = 0; i < 9; i++) + dib7000m_write_word(state, 88 + i, b[i]); + } + return 0; +} + +static void dib7000m_update_timf(struct dib7000m_state *state) +{ + u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437); + state->timf = timf * 160 / (state->current_bandwidth / 50); + dib7000m_write_word(state, 23, (u16) (timf >> 16)); + dib7000m_write_word(state, 24, (u16) (timf & 0xffff)); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); +} + +static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000m_state *state = demod->demodulator_priv; + u16 cfg_72 = dib7000m_read_word(state, 72); + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); + dib7000m_set_adc_state(state, DIBX000_ADC_ON); + + if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; /* ADC power up */ + (*agc_state)++; + break; + + case 1: + /* AGC initialization */ + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000m_write_word(state, 75, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */ + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000m_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */ + dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */ + dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ + + dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ + dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000m_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + /* wait AGC accurate lock time */ + ret = 7; + + if (dib7000m_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else + (*agc_state)++; + break; + + case 5: + dib7000m_agc_soft_split(state); + + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + + (*agc_state)++; + break; + + default: + break; + } + return ret; +} + +static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq) +{ + u16 value, est[4]; + + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + + /* nfft, guard, qam, alpha */ + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case TRANSMISSION_MODE_4K: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000m_write_word(state, 0, value); + dib7000m_write_word(state, 5, (seq << 4)); + + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib7000m_write_word(state, 267 + state->reg_offs, value); + + /* offset loop parameters */ + + /* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */ + dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80); + + /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ + dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3)); + + /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */ + dib7000m_write_word(state, 32, (0 << 4) | 0x3); + + /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */ + dib7000m_write_word(state, 33, (0 << 4) | 0x5); + + /* P_dvsy_sync_wait */ + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case TRANSMISSION_MODE_4K: value = 128; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO + + /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */ + /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ + if (1 == 1 || state->revision > 0x4000) + state->div_force_off = 0; + else + state->div_force_off = 1; + dib7000m_set_diversity_in(&state->demod, state->div_state); + + /* channel estimation fine configuration */ + switch (ch->u.ofdm.constellation) { + case QAM_64: + est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ + est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ + est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ + est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ + break; + case QAM_16: + est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ + est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ + est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ + est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ + break; + default: + est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ + est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ + est[2] = 0x0333; /* P_adp_regul_ext 0.1 */ + est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ + break; + } + for (value = 0; value < 4; value++) + dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]); + + // set power-up level: autosearch + dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); +} + +static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000m_state *state = demod->demodulator_priv; + struct dvb_frontend_parameters schan; + int ret = 0; + u32 value, factor; + + schan = *ch; + + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000m_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; + + // always use the setting for 8MHz here lock_time for 7,6 MHz are longer + value = 30 * state->internal_clk * factor; + ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time + ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time + value = 100 * state->internal_clk * factor; + ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time + ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time + value = 500 * state->internal_clk * factor; + ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time + ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time + + // start search + value = dib7000m_read_word(state, 0); + ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9))); + + /* clear n_irq_pending */ + if (state->revision == 0x4000) + dib7000m_write_word(state, 1793, 0); + else + dib7000m_read_word(state, 537); + + ret |= dib7000m_write_word(state, 0, (u16) value); + + return ret; +} + +static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg) +{ + u16 irq_pending = dib7000m_read_word(state, reg); + + if (irq_pending & 0x1) { // failed + dprintk( "autosearch failed"); + return 1; + } + + if (irq_pending & 0x2) { // succeeded + dprintk( "autosearch succeeded"); + return 2; + } + return 0; // still pending +} + +static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) +{ + struct dib7000m_state *state = demod->demodulator_priv; + if (state->revision == 0x4000) + return dib7000m_autosearch_irq(state, 1793); + else + return dib7000m_autosearch_irq(state, 537); +} + +static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000m_state *state = demod->demodulator_priv; + int ret = 0; + u16 value; + + // we are already tuned - just resuming from suspend + if (ch != NULL) + dib7000m_set_channel(state, ch, 0); + else + return -EINVAL; + + // restart demod + ret |= dib7000m_write_word(state, 898, 0x4000); + ret |= dib7000m_write_word(state, 898, 0x0000); + msleep(45); + + dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); + /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ + ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); + + // never achieved a lock before - wait for timfreq to update + if (state->timf == 0) + msleep(200); + + //dump_reg(state); + /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ + value = (6 << 8) | 0x80; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (7 << 12); break; + case TRANSMISSION_MODE_4K: value |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: value |= (9 << 12); break; + } + ret |= dib7000m_write_word(state, 26, value); + + /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ + value = (0 << 4); + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case TRANSMISSION_MODE_4K: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; + } + ret |= dib7000m_write_word(state, 32, value); + + /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ + value = (0 << 4); + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case TRANSMISSION_MODE_4K: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; + } + ret |= dib7000m_write_word(state, 33, value); + + // we achieved a lock - it's time to update the timf freq + if ((dib7000m_read_word(state, 535) >> 6) & 0x1) + dib7000m_update_timf(state); + + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + return ret; +} + +static int dib7000m_wakeup(struct dvb_frontend *demod) +{ + struct dib7000m_state *state = demod->demodulator_priv; + + dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); + + if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) + dprintk( "could not start Slow ADC"); + + return 0; +} + +static int dib7000m_sleep(struct dvb_frontend *demod) +{ + struct dib7000m_state *st = demod->demodulator_priv; + dib7000m_set_output_mode(st, OUTMODE_HIGH_Z); + dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY); + return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | + dib7000m_set_adc_state(st, DIBX000_ADC_OFF); +} + +static int dib7000m_identify(struct dib7000m_state *state) +{ + u16 value; + + if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { + dprintk( "wrong Vendor ID (0x%x)",value); + return -EREMOTEIO; + } + + state->revision = dib7000m_read_word(state, 897); + if (state->revision != 0x4000 && + state->revision != 0x4001 && + state->revision != 0x4002 && + state->revision != 0x4003) { + dprintk( "wrong Device ID (0x%x)",value); + return -EREMOTEIO; + } + + /* protect this driver to be used with 7000PC */ + if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { + dprintk( "this driver does not work with DiB7000PC"); + return -EREMOTEIO; + } + + switch (state->revision) { + case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break; + case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break; + case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break; + case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break; + } + + return 0; +} + + +static int dib7000m_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct dib7000m_state *state = fe->demodulator_priv; + u16 tps = dib7000m_read_word(state,480); + + fep->inversion = INVERSION_AUTO; + + fep->u.ofdm.bandwidth = state->current_bandwidth; + + switch ((tps >> 8) & 0x3) { + case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; + case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; + /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ + } + + switch (tps & 0x3) { + case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; + case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; + case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; + case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; + } + + switch ((tps >> 14) & 0x3) { + case 0: fep->u.ofdm.constellation = QPSK; break; + case 1: fep->u.ofdm.constellation = QAM_16; break; + case 2: + default: fep->u.ofdm.constellation = QAM_64; break; + } + + /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ + /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ + + fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + switch ((tps >> 5) & 0x7) { + case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; + case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; + case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; + case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; + case 7: + default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; + + } + + switch ((tps >> 2) & 0x7) { + case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; + case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; + case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; + case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; + case 7: + default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; + } + + /* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */ + + return 0; +} + +static int dib7000m_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct dib7000m_state *state = fe->demodulator_priv; + int time, ret; + + dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); + + state->current_bandwidth = fep->u.ofdm.bandwidth; + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, fep); + + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000m_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || + fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || + fep->u.ofdm.constellation == QAM_AUTO || + fep->u.ofdm.code_rate_HP == FEC_AUTO) { + int i = 800, found; + + dib7000m_autosearch_start(fe, fep); + do { + msleep(1); + found = dib7000m_autosearch_is_irq(fe); + } while (found == 0 && i--); + + dprintk("autosearch returns: %d",found); + if (found == 0 || found == 1) + return 0; // no channel found + + dib7000m_get_frontend(fe, fep); + } + + ret = dib7000m_tune(fe, fep); + + /* make this a config parameter */ + dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); + return ret; +} + +static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) +{ + struct dib7000m_state *state = fe->demodulator_priv; + u16 lock = dib7000m_read_word(state, 535); + + *stat = 0; + + if (lock & 0x8000) + *stat |= FE_HAS_SIGNAL; + if (lock & 0x3000) + *stat |= FE_HAS_CARRIER; + if (lock & 0x0100) + *stat |= FE_HAS_VITERBI; + if (lock & 0x0010) + *stat |= FE_HAS_SYNC; + if (lock & 0x0008) + *stat |= FE_HAS_LOCK; + + return 0; +} + +static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct dib7000m_state *state = fe->demodulator_priv; + *ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527); + return 0; +} + +static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) +{ + struct dib7000m_state *state = fe->demodulator_priv; + *unc = dib7000m_read_word(state, 534); + return 0; +} + +static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct dib7000m_state *state = fe->demodulator_priv; + u16 val = dib7000m_read_word(state, 390); + *strength = 65535 - val; + return 0; +} + +static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + *snr = 0x0000; + return 0; +} + +static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void dib7000m_release(struct dvb_frontend *demod) +{ + struct dib7000m_state *st = demod->demodulator_priv; + dibx000_exit_i2c_master(&st->i2c_master); + kfree(st); +} + +struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating) +{ + struct dib7000m_state *st = demod->demodulator_priv; + return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); +} +EXPORT_SYMBOL(dib7000m_get_i2c_master); + +int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + struct dib7000m_state *state = fe->demodulator_priv; + u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef; + val |= (onoff & 0x1) << 4; + dprintk("PID filter enabled %d", onoff); + return dib7000m_write_word(state, 294 + state->reg_offs, val); +} +EXPORT_SYMBOL(dib7000m_pid_filter_ctrl); + +int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + struct dib7000m_state *state = fe->demodulator_priv; + dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); + return dib7000m_write_word(state, 300 + state->reg_offs + id, + onoff ? (1 << 13) | pid : 0); +} +EXPORT_SYMBOL(dib7000m_pid_filter); + +#if 0 +/* used with some prototype boards */ +int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, + u8 default_addr, struct dib7000m_config cfg[]) +{ + struct dib7000m_state st = { .i2c_adap = i2c }; + int k = 0; + u8 new_addr = 0; + + for (k = no_of_demods-1; k >= 0; k--) { + st.cfg = cfg[k]; + + /* designated i2c address */ + new_addr = (0x40 + k) << 1; + st.i2c_addr = new_addr; + if (dib7000m_identify(&st) != 0) { + st.i2c_addr = default_addr; + if (dib7000m_identify(&st) != 0) { + dprintk("DiB7000M #%d: not identified", k); + return -EIO; + } + } + + /* start diversity to pull_down div_str - just for i2c-enumeration */ + dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY); + + dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output + + /* set new i2c address and force divstart */ + dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); + + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); + } + + for (k = 0; k < no_of_demods; k++) { + st.cfg = cfg[k]; + st.i2c_addr = (0x40 + k) << 1; + + // unforce divstr + dib7000m_write_word(&st,1794, st.i2c_addr << 2); + + /* deactivate div - it was just for i2c-enumeration */ + dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z); + } + + return 0; +} +EXPORT_SYMBOL(dib7000m_i2c_enumeration); +#endif + +static struct dvb_frontend_ops dib7000m_ops; +struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg) +{ + struct dvb_frontend *demod; + struct dib7000m_state *st; + st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL); + if (st == NULL) + return NULL; + + memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config)); + st->i2c_adap = i2c_adap; + st->i2c_addr = i2c_addr; + + demod = &st->demod; + demod->demodulator_priv = st; + memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); + + st->timf_default = cfg->bw->timf; + + if (dib7000m_identify(st) != 0) + goto error; + + if (st->revision == 0x4000) + dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr); + else + dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr); + + dib7000m_demod_reset(st); + + return demod; + +error: + kfree(st); + return NULL; +} +EXPORT_SYMBOL(dib7000m_attach); + +static struct dvb_frontend_ops dib7000m_ops = { + .info = { + .name = "DiBcom 7000MA/MB/PA/PB/MC", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = dib7000m_release, + + .init = dib7000m_wakeup, + .sleep = dib7000m_sleep, + + .set_frontend = dib7000m_set_frontend, + .get_tune_settings = dib7000m_fe_get_tune_settings, + .get_frontend = dib7000m_get_frontend, + + .read_status = dib7000m_read_status, + .read_ber = dib7000m_read_ber, + .read_signal_strength = dib7000m_read_signal_strength, + .read_snr = dib7000m_read_snr, + .read_ucblocks = dib7000m_read_unc_blocks, +}; + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000m.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000m.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000m.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000m.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,90 @@ +#ifndef DIB7000M_H +#define DIB7000M_H + +#include "dibx000_common.h" + +struct dib7000m_config { + u8 dvbt_mode; + u8 output_mpeg2_in_188_bytes; + u8 hostbus_diversity; + u8 tuner_is_baseband; + u8 mobile_mode; + int (*update_lna) (struct dvb_frontend *, u16 agc_global); + + u8 agc_config_count; + struct dibx000_agc_config *agc; + + struct dibx000_bandwidth_config *bw; + +#define DIB7000M_GPIO_DEFAULT_DIRECTIONS 0xffff + u16 gpio_dir; +#define DIB7000M_GPIO_DEFAULT_VALUES 0x0000 + u16 gpio_val; +#define DIB7000M_GPIO_PWM_POS0(v) ((v & 0xf) << 12) +#define DIB7000M_GPIO_PWM_POS1(v) ((v & 0xf) << 8 ) +#define DIB7000M_GPIO_PWM_POS2(v) ((v & 0xf) << 4 ) +#define DIB7000M_GPIO_PWM_POS3(v) (v & 0xf) +#define DIB7000M_GPIO_DEFAULT_PWM_POS 0xffff + u16 gpio_pwm_pos; + + u16 pwm_freq_div; + + u8 quartz_direct; + + u8 input_clk_is_div_2; + + int (*agc_control) (struct dvb_frontend *, u8 before); +}; + +#define DEFAULT_DIB7000M_I2C_ADDRESS 18 + +#if defined(CONFIG_DVB_DIB7000M) || (defined(CONFIG_DVB_DIB7000M_MODULE) && \ + defined(MODULE)) +extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct dib7000m_config *cfg); +extern struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *, + enum dibx000_i2c_interface, + int); +extern int dib7000m_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); +extern int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); +#else +static inline +struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap, + u8 i2c_addr, struct dib7000m_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline +struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *demod, + enum dibx000_i2c_interface intf, + int gating) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, + u16 pid, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, + uint8_t onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +#endif + +/* TODO +extern INT dib7000m_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); +extern INT dib7000m_enable_vbg_voltage(struct dibDemod *demod); +extern void dib7000m_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff); +extern USHORT dib7000m_get_current_agc_global(struct dibDemod *demod); +*/ + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000p.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000p.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000p.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000p.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2402 @@ +/* + * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#include +#include +#include + +#include "dvb_math.h" +#include "dvb_frontend.h" + +#include "dib7000p.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) + +struct i2c_device { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; +}; + +struct dib7000p_state { + struct dvb_frontend demod; + struct dib7000p_config cfg; + + u8 i2c_addr; + struct i2c_adapter *i2c_adap; + + struct dibx000_i2c_master i2c_master; + + u16 wbd_ref; + + u8 current_band; + u32 current_bandwidth; + struct dibx000_agc_config *current_agc; + u32 timf; + + u8 div_force_off:1; + u8 div_state:1; + u16 div_sync_wait; + + u8 agc_state; + + u16 gpio_dir; + u16 gpio_val; + + u8 sfn_workaround_active:1; + +#define SOC7090 0x7090 + u16 version; + + u16 tuner_enable; + struct i2c_adapter dib7090_tuner_adap; + + /* for the I2C transfer */ + struct i2c_msg msg[2]; + u8 i2c_write_buffer[4]; + u8 i2c_read_buffer[2]; +}; + +enum dib7000p_power_mode { + DIB7000P_POWER_ALL = 0, + DIB7000P_POWER_ANALOG_ADC, + DIB7000P_POWER_INTERFACE_ONLY, +}; + +static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode); +static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); + +static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) +{ + state->i2c_write_buffer[0] = reg >> 8; + state->i2c_write_buffer[1] = reg & 0xff; + + memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); + state->msg[0].addr = state->i2c_addr >> 1; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 2; + state->msg[1].addr = state->i2c_addr >> 1; + state->msg[1].flags = I2C_M_RD; + state->msg[1].buf = state->i2c_read_buffer; + state->msg[1].len = 2; + + if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) + dprintk("i2c read error on %d", reg); + + return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; +} + +static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) +{ + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; + state->i2c_write_buffer[1] = reg & 0xff; + state->i2c_write_buffer[2] = (val >> 8) & 0xff; + state->i2c_write_buffer[3] = val & 0xff; + + memset(&state->msg[0], 0, sizeof(struct i2c_msg)); + state->msg[0].addr = state->i2c_addr >> 1; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 4; + + return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; +} + +static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + do { + dib7000p_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + +static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) +{ + int ret = 0; + u16 outreg, fifo_threshold, smo_mode; + + outreg = 0; + fifo_threshold = 1792; + smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); + + dprintk("setting output mode for demod %p to %d", &state->demod, mode); + + switch (mode) { + case OUTMODE_MPEG2_PAR_GATED_CLK: + outreg = (1 << 10); /* 0x0400 */ + break; + case OUTMODE_MPEG2_PAR_CONT_CLK: + outreg = (1 << 10) | (1 << 6); /* 0x0440 */ + break; + case OUTMODE_MPEG2_SERIAL: + outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */ + break; + case OUTMODE_DIVERSITY: + if (state->cfg.hostbus_diversity) + outreg = (1 << 10) | (4 << 6); /* 0x0500 */ + else + outreg = (1 << 11); + break; + case OUTMODE_MPEG2_FIFO: + smo_mode |= (3 << 1); + fifo_threshold = 512; + outreg = (1 << 10) | (5 << 6); + break; + case OUTMODE_ANALOG_ADC: + outreg = (1 << 10) | (3 << 6); + break; + case OUTMODE_HIGH_Z: + outreg = 0; + break; + default: + dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod); + break; + } + + if (state->cfg.output_mpeg2_in_188_bytes) + smo_mode |= (1 << 5); + + ret |= dib7000p_write_word(state, 235, smo_mode); + ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ + if (state->version != SOC7090) + ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */ + + return ret; +} + +static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000p_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk("diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + dib7000p_write_word(state, 207, 0); + } else + dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + + state->div_state = (u8) onoff; + + if (onoff) { + dib7000p_write_word(state, 204, 6); + dib7000p_write_word(state, 205, 16); + /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ + } else { + dib7000p_write_word(state, 204, 1); + dib7000p_write_word(state, 205, 0); + } + + return 0; +} + +static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode) +{ + /* by default everything is powered off */ + u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff); + + /* now, depending on the requested mode, we power on */ + switch (mode) { + /* power up everything in the demod */ + case DIB7000P_POWER_ALL: + reg_774 = 0x0000; + reg_775 = 0x0000; + reg_776 = 0x0; + reg_899 = 0x0; + if (state->version == SOC7090) + reg_1280 &= 0x001f; + else + reg_1280 &= 0x01ff; + break; + + case DIB7000P_POWER_ANALOG_ADC: + /* dem, cfg, iqc, sad, agc */ + reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); + /* nud */ + reg_776 &= ~((1 << 0)); + /* Dout */ + if (state->version != SOC7090) + reg_1280 &= ~((1 << 11)); + reg_1280 &= ~(1 << 6); + /* fall through wanted to enable the interfaces */ + + /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ + case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ + if (state->version == SOC7090) + reg_1280 &= ~((1 << 7) | (1 << 5)); + else + reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); + break; + +/* TODO following stuff is just converted from the dib7000-driver - check when is used what */ + } + + dib7000p_write_word(state, 774, reg_774); + dib7000p_write_word(state, 775, reg_775); + dib7000p_write_word(state, 776, reg_776); + dib7000p_write_word(state, 899, reg_899); + dib7000p_write_word(state, 1280, reg_1280); + + return 0; +} + +static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no) +{ + u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909); + u16 reg; + + switch (no) { + case DIBX000_SLOW_ADC_ON: + if (state->version == SOC7090) { + reg = dib7000p_read_word(state, 1925); + + dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */ + + reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */ + msleep(200); + dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */ + + reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12)); + dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */ + } else { + reg_909 |= (1 << 1) | (1 << 0); + dib7000p_write_word(state, 909, reg_909); + reg_909 &= ~(1 << 1); + } + break; + + case DIBX000_SLOW_ADC_OFF: + if (state->version == SOC7090) { + reg = dib7000p_read_word(state, 1925); + dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */ + } else + reg_909 |= (1 << 1) | (1 << 0); + break; + + case DIBX000_ADC_ON: + reg_908 &= 0x0fff; + reg_909 &= 0x0003; + break; + + case DIBX000_ADC_OFF: + reg_908 |= (1 << 14) | (1 << 13) | (1 << 12); + reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); + break; + + case DIBX000_VBG_ENABLE: + reg_908 &= ~(1 << 15); + break; + + case DIBX000_VBG_DISABLE: + reg_908 |= (1 << 15); + break; + + default: + break; + } + +// dprintk( "908: %x, 909: %x\n", reg_908, reg_909); + + reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4; + reg_908 |= (state->cfg.enable_current_mirror & 1) << 7; + + dib7000p_write_word(state, 908, reg_908); + dib7000p_write_word(state, 909, reg_909); +} + +static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) +{ + u32 timf; + + // store the current bandwidth for later use + state->current_bandwidth = bw; + + if (state->timf == 0) { + dprintk("using default timf"); + timf = state->cfg.bw->timf; + } else { + dprintk("using updated timf"); + timf = state->timf; + } + + timf = timf * (bw / 50) / 160; + + dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff)); + + return 0; +} + +static int dib7000p_sad_calib(struct dib7000p_state *state) +{ +/* internal */ + dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); + + if (state->version == SOC7090) + dib7000p_write_word(state, 74, 2048); + else + dib7000p_write_word(state, 74, 776); + + /* do the calibration */ + dib7000p_write_word(state, 73, (1 << 0)); + dib7000p_write_word(state, 73, (0 << 0)); + + msleep(1); + + return 0; +} + +int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) +{ + struct dib7000p_state *state = demod->demodulator_priv; + if (value > 4095) + value = 4095; + state->wbd_ref = value; + return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value); +} +EXPORT_SYMBOL(dib7000p_set_wbd_ref); + +static void dib7000p_reset_pll(struct dib7000p_state *state) +{ + struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; + u16 clk_cfg0; + + if (state->version == SOC7090) { + dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv)); + + while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) + ; + + dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15)); + } else { + /* force PLL bypass */ + clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | + (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); + + dib7000p_write_word(state, 900, clk_cfg0); + + /* P_pll_cfg */ + dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); + clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); + dib7000p_write_word(state, 900, clk_cfg0); + } + + dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); + dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff)); + dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff)); + dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff)); + + dib7000p_write_word(state, 72, bw->sad_cfg); +} + +static u32 dib7000p_get_internal_freq(struct dib7000p_state *state) +{ + u32 internal = (u32) dib7000p_read_word(state, 18) << 16; + internal |= (u32) dib7000p_read_word(state, 19); + internal /= 1000; + + return internal; +} + +int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856); + u8 loopdiv, prediv; + u32 internal, xtal; + + /* get back old values */ + prediv = reg_1856 & 0x3f; + loopdiv = (reg_1856 >> 6) & 0x3f; + + if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) { + dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio); + reg_1856 &= 0xf000; + reg_1857 = dib7000p_read_word(state, 1857); + dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15)); + + dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f)); + + /* write new system clk into P_sec_len */ + internal = dib7000p_get_internal_freq(state); + xtal = (internal / loopdiv) * prediv; + internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */ + dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff)); + dib7000p_write_word(state, 19, (u16) (internal & 0xffff)); + + dib7000p_write_word(state, 1857, reg_1857 | (1 << 15)); + + while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) + dprintk("Waiting for PLL to lock"); + + return 0; + } + return -EIO; +} +EXPORT_SYMBOL(dib7000p_update_pll); + +static int dib7000p_reset_gpio(struct dib7000p_state *st) +{ + /* reset the GPIOs */ + dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos); + + dib7000p_write_word(st, 1029, st->gpio_dir); + dib7000p_write_word(st, 1030, st->gpio_val); + + /* TODO 1031 is P_gpio_od */ + + dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos); + + dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div); + return 0; +} + +static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val) +{ + st->gpio_dir = dib7000p_read_word(st, 1029); + st->gpio_dir &= ~(1 << num); /* reset the direction bit */ + st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ + dib7000p_write_word(st, 1029, st->gpio_dir); + + st->gpio_val = dib7000p_read_word(st, 1030); + st->gpio_val &= ~(1 << num); /* reset the direction bit */ + st->gpio_val |= (val & 0x01) << num; /* set the new value */ + dib7000p_write_word(st, 1030, st->gpio_val); + + return 0; +} + +int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val) +{ + struct dib7000p_state *state = demod->demodulator_priv; + return dib7000p_cfg_gpio(state, num, dir, val); +} +EXPORT_SYMBOL(dib7000p_set_gpio); + +static u16 dib7000p_defaults[] = { + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, /* Equal Lock */ + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, + + /* set ADC level to -16 */ + 11, 79, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + 1, 142, + 0x0410, + + /* disable power smoothing */ + 8, 145, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 154, + 1 << 13, + + 1, 168, + 0x0ccd, + + 1, 183, + 0x200f, + + 1, 212, + 0x169, + + 5, 187, + 0x023d, + 0x00a4, + 0x00a4, + 0x7ff0, + 0x3ccc, + + 1, 198, + 0x800, + + 1, 222, + 0x0010, + + 1, 235, + 0x0062, + + 2, 901, + 0x0006, + (3 << 10) | (1 << 6), + + 1, 905, + 0x2c8e, + + 0, +}; + +static int dib7000p_demod_reset(struct dib7000p_state *state) +{ + dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + + if (state->version == SOC7090) + dibx000_reset_i2c_master(&state->i2c_master); + + dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE); + + /* restart all parts */ + dib7000p_write_word(state, 770, 0xffff); + dib7000p_write_word(state, 771, 0xffff); + dib7000p_write_word(state, 772, 0x001f); + dib7000p_write_word(state, 898, 0x0003); + dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3))); + + dib7000p_write_word(state, 770, 0); + dib7000p_write_word(state, 771, 0); + dib7000p_write_word(state, 772, 0); + dib7000p_write_word(state, 898, 0); + dib7000p_write_word(state, 1280, 0); + + /* default */ + dib7000p_reset_pll(state); + + if (dib7000p_reset_gpio(state) != 0) + dprintk("GPIO reset was not successful."); + + if (state->version == SOC7090) { + dib7000p_write_word(state, 899, 0); + + /* impulse noise */ + dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */ + dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */ + dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */ + dib7000p_write_word(state, 273, (1<<6) | 30); + } + if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) + dprintk("OUTPUT_MODE could not be reset."); + + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); + dib7000p_sad_calib(state); + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + + /* unforce divstr regardless whether i2c enumeration was done or not */ + dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1)); + + dib7000p_set_bandwidth(state, 8000); + + if (state->version == SOC7090) { + dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */ + } else { + if (state->cfg.tuner_is_baseband) + dib7000p_write_word(state, 36, 0x0755); + else + dib7000p_write_word(state, 36, 0x1f55); + } + + dib7000p_write_tab(state, dib7000p_defaults); + + dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); + + return 0; +} + +static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) +{ + u16 tmp = 0; + tmp = dib7000p_read_word(state, 903); + dib7000p_write_word(state, 903, (tmp | 0x1)); + tmp = dib7000p_read_word(state, 900); + dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); +} + +static void dib7000p_restart_agc(struct dib7000p_state *state) +{ + // P_restart_iqc & P_restart_agc + dib7000p_write_word(state, 770, (1 << 11) | (1 << 9)); + dib7000p_write_word(state, 770, 0x0000); +} + +static int dib7000p_update_lna(struct dib7000p_state *state) +{ + u16 dyn_gain; + + if (state->cfg.update_lna) { + dyn_gain = dib7000p_read_word(state, 394); + if (state->cfg.update_lna(&state->demod, dyn_gain)) { + dib7000p_restart_agc(state); + return 1; + } + } + + return 0; +} + +static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) +{ + struct dibx000_agc_config *agc = NULL; + int i; + if (state->current_band == band && state->current_agc != NULL) + return 0; + state->current_band = band; + + for (i = 0; i < state->cfg.agc_config_count; i++) + if (state->cfg.agc[i].band_caps & band) { + agc = &state->cfg.agc[i]; + break; + } + + if (agc == NULL) { + dprintk("no valid AGC configuration found for band 0x%02x", band); + return -EINVAL; + } + + state->current_agc = agc; + + /* AGC */ + dib7000p_write_word(state, 75, agc->setup); + dib7000p_write_word(state, 76, agc->inv_gain); + dib7000p_write_word(state, 77, agc->time_stabiliz); + dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); + + // Demod AGC loop configuration + dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); + dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); + + /* AGC continued */ + dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", + state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); + + if (state->wbd_ref != 0) + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); + else + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); + + dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); + + dib7000p_write_word(state, 107, agc->agc1_max); + dib7000p_write_word(state, 108, agc->agc1_min); + dib7000p_write_word(state, 109, agc->agc2_max); + dib7000p_write_word(state, 110, agc->agc2_min); + dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); + dib7000p_write_word(state, 112, agc->agc1_pt3); + dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); + dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); + return 0; +} + +static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz) +{ + u32 internal = dib7000p_get_internal_freq(state); + s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */ + u32 abs_offset_khz = ABS(offset_khz); + u32 dds = state->cfg.bw->ifreq & 0x1ffffff; + u8 invert = !!(state->cfg.bw->ifreq & (1 << 25)); + + dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert); + + if (offset_khz < 0) + unit_khz_dds_val *= -1; + + /* IF tuner */ + if (invert) + dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */ + else + dds += (abs_offset_khz * unit_khz_dds_val); + + if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */ + dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9))); + dib7000p_write_word(state, 22, (u16) (dds & 0xffff)); + } +} + +static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000p_state *state = demod->demodulator_priv; + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + u16 reg; + u32 upd_demod_gain_period = 0x1000; + + switch (state->agc_state) { + case 0: + dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + if (state->version == SOC7090) { + reg = dib7000p_read_word(state, 0x79b) & 0xff00; + dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */ + dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF)); + + /* enable adc i & q */ + reg = dib7000p_read_word(state, 0x780); + dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7))); + } else { + dib7000p_set_adc_state(state, DIBX000_ADC_ON); + dib7000p_pll_clk_cfg(state); + } + + if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0) + return -1; + + dib7000p_set_dds(state, 0); + ret = 7; + (*agc_state)++; + break; + + case 1: + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000p_write_word(state, 78, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + /* force 0 split on WBD and restart AGC */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000p_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */ + dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ + + dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000p_restart_agc(state); + + dprintk("SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + ret = 7; + + if (dib7000p_update_lna(state)) + ret = 5; + else + (*agc_state)++; + break; + + case 5: + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + (*agc_state)++; + break; + default: + break; + } + return ret; +} + +static void dib7000p_update_timf(struct dib7000p_state *state) +{ + u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); + state->timf = timf * 160 / (state->current_bandwidth / 50); + dib7000p_write_word(state, 23, (u16) (timf >> 16)); + dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); + dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf); + +} + +u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) +{ + struct dib7000p_state *state = fe->demodulator_priv; + switch (op) { + case DEMOD_TIMF_SET: + state->timf = timf; + break; + case DEMOD_TIMF_UPDATE: + dib7000p_update_timf(state); + break; + case DEMOD_TIMF_GET: + break; + } + dib7000p_set_bandwidth(state, state->current_bandwidth); + return state->timf; +} +EXPORT_SYMBOL(dib7000p_ctrl_timf); + +static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) +{ + u16 value, est[4]; + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + + /* nfft, guard, qam, alpha */ + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: + value |= (0 << 7); + break; + case TRANSMISSION_MODE_4K: + value |= (2 << 7); + break; + default: + case TRANSMISSION_MODE_8K: + value |= (1 << 7); + break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: + value |= (0 << 5); + break; + case GUARD_INTERVAL_1_16: + value |= (1 << 5); + break; + case GUARD_INTERVAL_1_4: + value |= (3 << 5); + break; + default: + case GUARD_INTERVAL_1_8: + value |= (2 << 5); + break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: + value |= (0 << 3); + break; + case QAM_16: + value |= (1 << 3); + break; + default: + case QAM_64: + value |= (2 << 3); + break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: + value |= 2; + break; + case HIERARCHY_4: + value |= 4; + break; + default: + case HIERARCHY_1: + value |= 1; + break; + } + dib7000p_write_word(state, 0, value); + dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ + + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: + value |= (2 << 1); + break; + case FEC_3_4: + value |= (3 << 1); + break; + case FEC_5_6: + value |= (5 << 1); + break; + case FEC_7_8: + value |= (7 << 1); + break; + default: + case FEC_1_2: + value |= (1 << 1); + break; + } + dib7000p_write_word(state, 208, value); + + /* offset loop parameters */ + dib7000p_write_word(state, 26, 0x6680); + dib7000p_write_word(state, 32, 0x0003); + dib7000p_write_word(state, 29, 0x1273); + dib7000p_write_word(state, 33, 0x0005); + + /* P_dvsy_sync_wait */ + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: + value = 256; + break; + case TRANSMISSION_MODE_4K: + value = 128; + break; + case TRANSMISSION_MODE_2K: + default: + value = 64; + break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: + value *= 2; + break; + case GUARD_INTERVAL_1_8: + value *= 4; + break; + case GUARD_INTERVAL_1_4: + value *= 8; + break; + default: + case GUARD_INTERVAL_1_32: + value *= 1; + break; + } + if (state->cfg.diversity_delay == 0) + state->div_sync_wait = (value * 3) / 2 + 48; + else + state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; + + /* deactive the possibility of diversity reception if extended interleaver */ + state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; + dib7000p_set_diversity_in(&state->demod, state->div_state); + + /* channel estimation fine configuration */ + switch (ch->u.ofdm.constellation) { + case QAM_64: + est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ + est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ + est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ + est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ + break; + case QAM_16: + est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ + est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ + est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ + est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ + break; + default: + est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ + est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ + est[2] = 0x0333; /* P_adp_regul_ext 0.1 */ + est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ + break; + } + for (value = 0; value < 4; value++) + dib7000p_write_word(state, 187 + value, est[value]); +} + +static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000p_state *state = demod->demodulator_priv; + struct dvb_frontend_parameters schan; + u32 value, factor; + u32 internal = dib7000p_get_internal_freq(state); + + schan = *ch; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000p_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; + + value = 30 * internal * factor; + dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); + dib7000p_write_word(state, 7, (u16) (value & 0xffff)); + value = 100 * internal * factor; + dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); + dib7000p_write_word(state, 9, (u16) (value & 0xffff)); + value = 500 * internal * factor; + dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); + dib7000p_write_word(state, 11, (u16) (value & 0xffff)); + + value = dib7000p_read_word(state, 0); + dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); + dib7000p_read_word(state, 1284); + dib7000p_write_word(state, 0, (u16) value); + + return 0; +} + +static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) +{ + struct dib7000p_state *state = demod->demodulator_priv; + u16 irq_pending = dib7000p_read_word(state, 1284); + + if (irq_pending & 0x1) + return 1; + + if (irq_pending & 0x2) + return 2; + + return 0; +} + +static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) +{ + static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 }; + static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, + 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, + 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, + 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, + 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, + 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, + 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, + 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, + 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, + 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, + 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, + 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, + 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255 + }; + + u32 xtal = state->cfg.bw->xtal_hz / 1000; + int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz; + int k; + int coef_re[8], coef_im[8]; + int bw_khz = bw; + u32 pha; + + dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); + + if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2) + return; + + bw_khz /= 100; + + dib7000p_write_word(state, 142, 0x0610); + + for (k = 0; k < 8; k++) { + pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff; + + if (pha == 0) { + coef_re[k] = 256; + coef_im[k] = 0; + } else if (pha < 256) { + coef_re[k] = sine[256 - (pha & 0xff)]; + coef_im[k] = sine[pha & 0xff]; + } else if (pha == 256) { + coef_re[k] = 0; + coef_im[k] = 256; + } else if (pha < 512) { + coef_re[k] = -sine[pha & 0xff]; + coef_im[k] = sine[256 - (pha & 0xff)]; + } else if (pha == 512) { + coef_re[k] = -256; + coef_im[k] = 0; + } else if (pha < 768) { + coef_re[k] = -sine[256 - (pha & 0xff)]; + coef_im[k] = -sine[pha & 0xff]; + } else if (pha == 768) { + coef_re[k] = 0; + coef_im[k] = -256; + } else { + coef_re[k] = sine[pha & 0xff]; + coef_im[k] = -sine[256 - (pha & 0xff)]; + } + + coef_re[k] *= notch[k]; + coef_re[k] += (1 << 14); + if (coef_re[k] >= (1 << 24)) + coef_re[k] = (1 << 24) - 1; + coef_re[k] /= (1 << 15); + + coef_im[k] *= notch[k]; + coef_im[k] += (1 << 14); + if (coef_im[k] >= (1 << 24)) + coef_im[k] = (1 << 24) - 1; + coef_im[k] /= (1 << 15); + + dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); + + dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); + dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + } + dib7000p_write_word(state, 143, 0); +} + +static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000p_state *state = demod->demodulator_priv; + u16 tmp = 0; + + if (ch != NULL) + dib7000p_set_channel(state, ch, 0); + else + return -EINVAL; + + // restart demod + dib7000p_write_word(state, 770, 0x4000); + dib7000p_write_word(state, 770, 0x0000); + msleep(45); + + /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ + tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3); + if (state->sfn_workaround_active) { + dprintk("SFN workaround is active"); + tmp |= (1 << 9); + dib7000p_write_word(state, 166, 0x4000); + } else { + dib7000p_write_word(state, 166, 0x0000); + } + dib7000p_write_word(state, 29, tmp); + + // never achieved a lock with that bandwidth so far - wait for osc-freq to update + if (state->timf == 0) + msleep(200); + + /* offset loop parameters */ + + /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ + tmp = (6 << 8) | 0x80; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: + tmp |= (2 << 12); + break; + case TRANSMISSION_MODE_4K: + tmp |= (3 << 12); + break; + default: + case TRANSMISSION_MODE_8K: + tmp |= (4 << 12); + break; + } + dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ + + /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ + tmp = (0 << 4); + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: + tmp |= 0x6; + break; + case TRANSMISSION_MODE_4K: + tmp |= 0x7; + break; + default: + case TRANSMISSION_MODE_8K: + tmp |= 0x8; + break; + } + dib7000p_write_word(state, 32, tmp); + + /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ + tmp = (0 << 4); + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: + tmp |= 0x6; + break; + case TRANSMISSION_MODE_4K: + tmp |= 0x7; + break; + default: + case TRANSMISSION_MODE_8K: + tmp |= 0x8; + break; + } + dib7000p_write_word(state, 33, tmp); + + tmp = dib7000p_read_word(state, 509); + if (!((tmp >> 6) & 0x1)) { + /* restart the fec */ + tmp = dib7000p_read_word(state, 771); + dib7000p_write_word(state, 771, tmp | (1 << 1)); + dib7000p_write_word(state, 771, tmp); + msleep(40); + tmp = dib7000p_read_word(state, 509); + } + // we achieved a lock - it's time to update the osc freq + if ((tmp >> 6) & 0x1) { + dib7000p_update_timf(state); + /* P_timf_alpha += 2 */ + tmp = dib7000p_read_word(state, 26); + dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12)); + } + + if (state->cfg.spur_protect) + dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + return 0; +} + +static int dib7000p_wakeup(struct dvb_frontend *demod) +{ + struct dib7000p_state *state = demod->demodulator_priv; + dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); + if (state->version == SOC7090) + dib7000p_sad_calib(state); + return 0; +} + +static int dib7000p_sleep(struct dvb_frontend *demod) +{ + struct dib7000p_state *state = demod->demodulator_priv; + if (state->version == SOC7090) + return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); + return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); +} + +static int dib7000p_identify(struct dib7000p_state *st) +{ + u16 value; + dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); + + if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { + dprintk("wrong Vendor ID (read=0x%x)", value); + return -EREMOTEIO; + } + + if ((value = dib7000p_read_word(st, 769)) != 0x4000) { + dprintk("wrong Device ID (%x)", value); + return -EREMOTEIO; + } + + return 0; +} + +static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 tps = dib7000p_read_word(state, 463); + + fep->inversion = INVERSION_AUTO; + + fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth); + + switch ((tps >> 8) & 0x3) { + case 0: + fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + break; + /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ + } + + switch (tps & 0x3) { + case 0: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + break; + } + + switch ((tps >> 14) & 0x3) { + case 0: + fep->u.ofdm.constellation = QPSK; + break; + case 1: + fep->u.ofdm.constellation = QAM_16; + break; + case 2: + default: + fep->u.ofdm.constellation = QAM_64; + break; + } + + /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ + /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ + + fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + switch ((tps >> 5) & 0x7) { + case 1: + fep->u.ofdm.code_rate_HP = FEC_1_2; + break; + case 2: + fep->u.ofdm.code_rate_HP = FEC_2_3; + break; + case 3: + fep->u.ofdm.code_rate_HP = FEC_3_4; + break; + case 5: + fep->u.ofdm.code_rate_HP = FEC_5_6; + break; + case 7: + default: + fep->u.ofdm.code_rate_HP = FEC_7_8; + break; + + } + + switch ((tps >> 2) & 0x7) { + case 1: + fep->u.ofdm.code_rate_LP = FEC_1_2; + break; + case 2: + fep->u.ofdm.code_rate_LP = FEC_2_3; + break; + case 3: + fep->u.ofdm.code_rate_LP = FEC_3_4; + break; + case 5: + fep->u.ofdm.code_rate_LP = FEC_5_6; + break; + case 7: + default: + fep->u.ofdm.code_rate_LP = FEC_7_8; + break; + } + + /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */ + + return 0; +} + +static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dib7000p_state *state = fe->demodulator_priv; + int time, ret; + + if (state->version == SOC7090) { + dib7090_set_diversity_in(fe, 0); + dib7090_set_output_mode(fe, OUTMODE_HIGH_Z); + } else + dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); + + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; + + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, fep); + + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000p_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || + fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { + int i = 800, found; + + dib7000p_autosearch_start(fe, fep); + do { + msleep(1); + found = dib7000p_autosearch_is_irq(fe); + } while (found == 0 && i--); + + dprintk("autosearch returns: %d", found); + if (found == 0 || found == 1) + return 0; + + dib7000p_get_frontend(fe, fep); + } + + ret = dib7000p_tune(fe, fep); + + /* make this a config parameter */ + if (state->version == SOC7090) + dib7090_set_output_mode(fe, state->cfg.output_mode); + else + dib7000p_set_output_mode(state, state->cfg.output_mode); + + return ret; +} + +static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 lock = dib7000p_read_word(state, 509); + + *stat = 0; + + if (lock & 0x8000) + *stat |= FE_HAS_SIGNAL; + if (lock & 0x3000) + *stat |= FE_HAS_CARRIER; + if (lock & 0x0100) + *stat |= FE_HAS_VITERBI; + if (lock & 0x0010) + *stat |= FE_HAS_SYNC; + if ((lock & 0x0038) == 0x38) + *stat |= FE_HAS_LOCK; + + return 0; +} + +static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber) +{ + struct dib7000p_state *state = fe->demodulator_priv; + *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501); + return 0; +} + +static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) +{ + struct dib7000p_state *state = fe->demodulator_priv; + *unc = dib7000p_read_word(state, 506); + return 0; +} + +static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 val = dib7000p_read_word(state, 394); + *strength = 65535 - val; + return 0; +} + +static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 val; + s32 signal_mant, signal_exp, noise_mant, noise_exp; + u32 result = 0; + + val = dib7000p_read_word(state, 479); + noise_mant = (val >> 4) & 0xff; + noise_exp = ((val & 0xf) << 2); + val = dib7000p_read_word(state, 480); + noise_exp += ((val >> 14) & 0x3); + if ((noise_exp & 0x20) != 0) + noise_exp -= 0x40; + + signal_mant = (val >> 6) & 0xFF; + signal_exp = (val & 0x3F); + if ((signal_exp & 0x20) != 0) + signal_exp -= 0x40; + + if (signal_mant != 0) + result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant); + else + result = intlog10(2) * 10 * signal_exp - 100; + + if (noise_mant != 0) + result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant); + else + result -= intlog10(2) * 10 * noise_exp - 100; + + *snr = result / ((1 << 24) / 10); + return 0; +} + +static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void dib7000p_release(struct dvb_frontend *demod) +{ + struct dib7000p_state *st = demod->demodulator_priv; + dibx000_exit_i2c_master(&st->i2c_master); + i2c_del_adapter(&st->dib7090_tuner_adap); + kfree(st); +} + +int dib7000pc_detection(struct i2c_adapter *i2c_adap) +{ + u8 *tx, *rx; + struct i2c_msg msg[2] = { + {.addr = 18 >> 1, .flags = 0, .len = 2}, + {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2}, + }; + int ret = 0; + + tx = kzalloc(2*sizeof(u8), GFP_KERNEL); + if (!tx) + return -ENOMEM; + rx = kzalloc(2*sizeof(u8), GFP_KERNEL); + if (!rx) { + goto rx_memory_error; + ret = -ENOMEM; + } + + msg[0].buf = tx; + msg[1].buf = rx; + + tx[0] = 0x03; + tx[1] = 0x00; + + if (i2c_transfer(i2c_adap, msg, 2) == 2) + if (rx[0] == 0x01 && rx[1] == 0xb3) { + dprintk("-D- DiB7000PC detected"); + return 1; + } + + msg[0].addr = msg[1].addr = 0x40; + + if (i2c_transfer(i2c_adap, msg, 2) == 2) + if (rx[0] == 0x01 && rx[1] == 0xb3) { + dprintk("-D- DiB7000PC detected"); + return 1; + } + + dprintk("-D- DiB7000PC not detected"); + + kfree(rx); +rx_memory_error: + kfree(tx); + return ret; +} +EXPORT_SYMBOL(dib7000pc_detection); + +struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating) +{ + struct dib7000p_state *st = demod->demodulator_priv; + return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); +} +EXPORT_SYMBOL(dib7000p_get_i2c_master); + +int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 val = dib7000p_read_word(state, 235) & 0xffef; + val |= (onoff & 0x1) << 4; + dprintk("PID filter enabled %d", onoff); + return dib7000p_write_word(state, 235, val); +} +EXPORT_SYMBOL(dib7000p_pid_filter_ctrl); + +int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + struct dib7000p_state *state = fe->demodulator_priv; + dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); + return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0); +} +EXPORT_SYMBOL(dib7000p_pid_filter); + +int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]) +{ + struct dib7000p_state *dpst; + int k = 0; + u8 new_addr = 0; + + dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL); + if (!dpst) + return -ENOMEM; + + dpst->i2c_adap = i2c; + + for (k = no_of_demods - 1; k >= 0; k--) { + dpst->cfg = cfg[k]; + + /* designated i2c address */ + if (cfg[k].default_i2c_addr != 0) + new_addr = cfg[k].default_i2c_addr + (k << 1); + else + new_addr = (0x40 + k) << 1; + dpst->i2c_addr = new_addr; + dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ + if (dib7000p_identify(dpst) != 0) { + dpst->i2c_addr = default_addr; + dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ + if (dib7000p_identify(dpst) != 0) { + dprintk("DiB7000P #%d: not identified\n", k); + kfree(dpst); + return -EIO; + } + } + + /* start diversity to pull_down div_str - just for i2c-enumeration */ + dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY); + + /* set new i2c address and force divstart */ + dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2); + + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); + } + + for (k = 0; k < no_of_demods; k++) { + dpst->cfg = cfg[k]; + if (cfg[k].default_i2c_addr != 0) + dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1; + else + dpst->i2c_addr = (0x40 + k) << 1; + + // unforce divstr + dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2); + + /* deactivate div - it was just for i2c-enumeration */ + dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z); + } + + kfree(dpst); + return 0; +} +EXPORT_SYMBOL(dib7000p_i2c_enumeration); + +static const s32 lut_1000ln_mant[] = { + 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600 +}; + +static s32 dib7000p_get_adc_power(struct dvb_frontend *fe) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u32 tmp_val = 0, exp = 0, mant = 0; + s32 pow_i; + u16 buf[2]; + u8 ix = 0; + + buf[0] = dib7000p_read_word(state, 0x184); + buf[1] = dib7000p_read_word(state, 0x185); + pow_i = (buf[0] << 16) | buf[1]; + dprintk("raw pow_i = %d", pow_i); + + tmp_val = pow_i; + while (tmp_val >>= 1) + exp++; + + mant = (pow_i * 1000 / (1 << exp)); + dprintk(" mant = %d exp = %d", mant / 1000, exp); + + ix = (u8) ((mant - 1000) / 100); /* index of the LUT */ + dprintk(" ix = %d", ix); + + pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908); + pow_i = (pow_i << 8) / 1000; + dprintk(" pow_i = %d", pow_i); + + return pow_i; +} + +static int map_addr_to_serpar_number(struct i2c_msg *msg) +{ + if ((msg->buf[0] <= 15)) + msg->buf[0] -= 1; + else if (msg->buf[0] == 17) + msg->buf[0] = 15; + else if (msg->buf[0] == 16) + msg->buf[0] = 17; + else if (msg->buf[0] == 19) + msg->buf[0] = 16; + else if (msg->buf[0] >= 21 && msg->buf[0] <= 25) + msg->buf[0] -= 3; + else if (msg->buf[0] == 28) + msg->buf[0] = 23; + else + return -EINVAL; + return 0; +} + +static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); + u8 n_overflow = 1; + u16 i = 1000; + u16 serpar_num = msg[0].buf[0]; + + while (n_overflow == 1 && i) { + n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; + i--; + if (i == 0) + dprintk("Tuner ITF: write busy (overflow)"); + } + dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); + dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); + + return num; +} + +static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); + u8 n_overflow = 1, n_empty = 1; + u16 i = 1000; + u16 serpar_num = msg[0].buf[0]; + u16 read_word; + + while (n_overflow == 1 && i) { + n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; + i--; + if (i == 0) + dprintk("TunerITF: read busy (overflow)"); + } + dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f)); + + i = 1000; + while (n_empty == 1 && i) { + n_empty = dib7000p_read_word(state, 1984) & 0x1; + i--; + if (i == 0) + dprintk("TunerITF: read busy (empty)"); + } + read_word = dib7000p_read_word(state, 1987); + msg[1].buf[0] = (read_word >> 8) & 0xff; + msg[1].buf[1] = (read_word) & 0xff; + + return num; +} + +static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + if (map_addr_to_serpar_number(&msg[0]) == 0) { /* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */ + if (num == 1) { /* write */ + return w7090p_tuner_write_serpar(i2c_adap, msg, 1); + } else { /* read */ + return w7090p_tuner_read_serpar(i2c_adap, msg, 2); + } + } + return num; +} + +int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address) +{ + struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); + u16 word; + + if (num == 1) { /* write */ + dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); + } else { + word = dib7000p_read_word(state, apb_address); + msg[1].buf[0] = (word >> 8) & 0xff; + msg[1].buf[1] = (word) & 0xff; + } + + return num; +} + +static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); + + u16 apb_address = 0, word; + int i = 0; + switch (msg[0].buf[0]) { + case 0x12: + apb_address = 1920; + break; + case 0x14: + apb_address = 1921; + break; + case 0x24: + apb_address = 1922; + break; + case 0x1a: + apb_address = 1923; + break; + case 0x22: + apb_address = 1924; + break; + case 0x33: + apb_address = 1926; + break; + case 0x34: + apb_address = 1927; + break; + case 0x35: + apb_address = 1928; + break; + case 0x36: + apb_address = 1929; + break; + case 0x37: + apb_address = 1930; + break; + case 0x38: + apb_address = 1931; + break; + case 0x39: + apb_address = 1932; + break; + case 0x2a: + apb_address = 1935; + break; + case 0x2b: + apb_address = 1936; + break; + case 0x2c: + apb_address = 1937; + break; + case 0x2d: + apb_address = 1938; + break; + case 0x2e: + apb_address = 1939; + break; + case 0x2f: + apb_address = 1940; + break; + case 0x30: + apb_address = 1941; + break; + case 0x31: + apb_address = 1942; + break; + case 0x32: + apb_address = 1943; + break; + case 0x3e: + apb_address = 1944; + break; + case 0x3f: + apb_address = 1945; + break; + case 0x40: + apb_address = 1948; + break; + case 0x25: + apb_address = 914; + break; + case 0x26: + apb_address = 915; + break; + case 0x27: + apb_address = 916; + break; + case 0x28: + apb_address = 917; + break; + case 0x1d: + i = ((dib7000p_read_word(state, 72) >> 12) & 0x3); + word = dib7000p_read_word(state, 384 + i); + msg[1].buf[0] = (word >> 8) & 0xff; + msg[1].buf[1] = (word) & 0xff; + return num; + case 0x1f: + if (num == 1) { /* write */ + word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]); + word &= 0x3; + word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12); + dib7000p_write_word(state, 72, word); /* Set the proper input */ + return num; + } + } + + if (apb_address != 0) /* R/W acces via APB */ + return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address); + else /* R/W access via SERPAR */ + return w7090p_tuner_rw_serpar(i2c_adap, msg, num); + + return 0; +} + +static u32 dib7000p_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dib7090_tuner_xfer_algo = { + .master_xfer = dib7090_tuner_xfer, + .functionality = dib7000p_i2c_func, +}; + +struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe) +{ + struct dib7000p_state *st = fe->demodulator_priv; + return &st->dib7090_tuner_adap; +} +EXPORT_SYMBOL(dib7090_get_i2c_tuner); + +static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive) +{ + u16 reg; + + /* drive host bus 2, 3, 4 */ + reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); + reg |= (drive << 12) | (drive << 6) | drive; + dib7000p_write_word(state, 1798, reg); + + /* drive host bus 5,6 */ + reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8)); + reg |= (drive << 8) | (drive << 2); + dib7000p_write_word(state, 1799, reg); + + /* drive host bus 7, 8, 9 */ + reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); + reg |= (drive << 12) | (drive << 6) | drive; + dib7000p_write_word(state, 1800, reg); + + /* drive host bus 10, 11 */ + reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8)); + reg |= (drive << 8) | (drive << 2); + dib7000p_write_word(state, 1801, reg); + + /* drive host bus 12, 13, 14 */ + reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); + reg |= (drive << 12) | (drive << 6) | drive; + dib7000p_write_word(state, 1802, reg); + + return 0; +} + +static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize) +{ + u32 quantif = 3; + u32 nom = (insertExtSynchro * P_Kin + syncSize); + u32 denom = P_Kout; + u32 syncFreq = ((nom << quantif) / denom); + + if ((syncFreq & ((1 << quantif) - 1)) != 0) + syncFreq = (syncFreq >> quantif) + 1; + else + syncFreq = (syncFreq >> quantif); + + if (syncFreq != 0) + syncFreq = syncFreq - 1; + + return syncFreq; +} + +static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize) +{ + u8 index_buf; + u16 rx_copy_buf[22]; + + dprintk("Configure DibStream Tx"); + for (index_buf = 0; index_buf < 22; index_buf++) + rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf); + + dib7000p_write_word(state, 1615, 1); + dib7000p_write_word(state, 1603, P_Kin); + dib7000p_write_word(state, 1605, P_Kout); + dib7000p_write_word(state, 1606, insertExtSynchro); + dib7000p_write_word(state, 1608, synchroMode); + dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff); + dib7000p_write_word(state, 1610, syncWord & 0xffff); + dib7000p_write_word(state, 1612, syncSize); + dib7000p_write_word(state, 1615, 0); + + for (index_buf = 0; index_buf < 22; index_buf++) + dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]); + + return 0; +} + +static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize, + u32 dataOutRate) +{ + u32 syncFreq; + + dprintk("Configure DibStream Rx"); + if ((P_Kin != 0) && (P_Kout != 0)) { + syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize); + dib7000p_write_word(state, 1542, syncFreq); + } + dib7000p_write_word(state, 1554, 1); + dib7000p_write_word(state, 1536, P_Kin); + dib7000p_write_word(state, 1537, P_Kout); + dib7000p_write_word(state, 1539, synchroMode); + dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff); + dib7000p_write_word(state, 1541, syncWord & 0xffff); + dib7000p_write_word(state, 1543, syncSize); + dib7000p_write_word(state, 1544, dataOutRate); + dib7000p_write_word(state, 1554, 0); + + return 0; +} + +static int dib7090_enDivOnHostBus(struct dib7000p_state *state) +{ + u16 reg; + + dprintk("Enable Diversity on host bus"); + reg = (1 << 8) | (1 << 5); + dib7000p_write_word(state, 1288, reg); + + return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); +} + +static int dib7090_enAdcOnHostBus(struct dib7000p_state *state) +{ + u16 reg; + + dprintk("Enable ADC on host bus"); + reg = (1 << 7) | (1 << 5); + dib7000p_write_word(state, 1288, reg); + + return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); +} + +static int dib7090_enMpegOnHostBus(struct dib7000p_state *state) +{ + u16 reg; + + dprintk("Enable Mpeg on host bus"); + reg = (1 << 9) | (1 << 5); + dib7000p_write_word(state, 1288, reg); + + return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); +} + +static int dib7090_enMpegInput(struct dib7000p_state *state) +{ + dprintk("Enable Mpeg input"); + return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ +} + +static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) +{ + u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1); + + dprintk("Enable Mpeg mux"); + dib7000p_write_word(state, 1287, reg); + + reg &= ~(1 << 7); + dib7000p_write_word(state, 1287, reg); + + reg = (1 << 4); + dib7000p_write_word(state, 1288, reg); + + return 0; +} + +static int dib7090_disableMpegMux(struct dib7000p_state *state) +{ + u16 reg; + + dprintk("Disable Mpeg mux"); + dib7000p_write_word(state, 1288, 0); + + reg = dib7000p_read_word(state, 1287); + reg &= ~(1 << 7); + dib7000p_write_word(state, 1287, reg); + + return 0; +} + +static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode) +{ + struct dib7000p_state *state = fe->demodulator_priv; + + switch (mode) { + case INPUT_MODE_DIVERSITY: + dprintk("Enable diversity INPUT"); + dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); + break; + case INPUT_MODE_MPEG: + dprintk("Enable Mpeg INPUT"); + dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ + break; + case INPUT_MODE_OFF: + default: + dprintk("Disable INPUT"); + dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0); + break; + } + return 0; +} + +static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) +{ + switch (onoff) { + case 0: /* only use the internal way - not the diversity input */ + dib7090_set_input_mode(fe, INPUT_MODE_MPEG); + break; + case 1: /* both ways */ + case 2: /* only the diversity input */ + dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY); + break; + } + + return 0; +} + +static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) +{ + struct dib7000p_state *state = fe->demodulator_priv; + + u16 outreg, smo_mode, fifo_threshold; + u8 prefer_mpeg_mux_use = 1; + int ret = 0; + + dib7090_host_bus_drive(state, 1); + + fifo_threshold = 1792; + smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); + outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1)); + + switch (mode) { + case OUTMODE_HIGH_Z: + outreg = 0; + break; + + case OUTMODE_MPEG2_SERIAL: + if (prefer_mpeg_mux_use) { + dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux"); + dib7090_enMpegOnHostBus(state); + dib7090_enMpegInput(state); + if (state->cfg.enMpegOutput == 1) + dib7090_enMpegMux(state, 3, 1, 1); + + } else { /* Use Smooth block */ + dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc"); + dib7090_disableMpegMux(state); + dib7000p_write_word(state, 1288, (1 << 6)); + outreg |= (2 << 6) | (0 << 1); + } + break; + + case OUTMODE_MPEG2_PAR_GATED_CLK: + if (prefer_mpeg_mux_use) { + dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); + dib7090_enMpegOnHostBus(state); + dib7090_enMpegInput(state); + if (state->cfg.enMpegOutput == 1) + dib7090_enMpegMux(state, 2, 0, 0); + } else { /* Use Smooth block */ + dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block"); + dib7090_disableMpegMux(state); + dib7000p_write_word(state, 1288, (1 << 6)); + outreg |= (0 << 6); + } + break; + + case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ + dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block"); + dib7090_disableMpegMux(state); + dib7000p_write_word(state, 1288, (1 << 6)); + outreg |= (1 << 6); + break; + + case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */ + dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block"); + dib7090_disableMpegMux(state); + dib7000p_write_word(state, 1288, (1 << 6)); + outreg |= (5 << 6); + smo_mode |= (3 << 1); + fifo_threshold = 512; + break; + + case OUTMODE_DIVERSITY: + dprintk("Sip 7090P setting output mode MODE_DIVERSITY"); + dib7090_disableMpegMux(state); + dib7090_enDivOnHostBus(state); + break; + + case OUTMODE_ANALOG_ADC: + dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC"); + dib7090_enAdcOnHostBus(state); + break; + } + + if (state->cfg.output_mpeg2_in_188_bytes) + smo_mode |= (1 << 5); + + ret |= dib7000p_write_word(state, 235, smo_mode); + ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ + ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */ + + return ret; +} + +int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 en_cur_state; + + dprintk("sleep dib7090: %d", onoff); + + en_cur_state = dib7000p_read_word(state, 1922); + + if (en_cur_state > 0xff) + state->tuner_enable = en_cur_state; + + if (onoff) + en_cur_state &= 0x00ff; + else { + if (state->tuner_enable != 0) + en_cur_state = state->tuner_enable; + } + + dib7000p_write_word(state, 1922, en_cur_state); + + return 0; +} +EXPORT_SYMBOL(dib7090_tuner_sleep); + +int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) +{ + dprintk("AGC restart callback: %d", restart); + return 0; +} +EXPORT_SYMBOL(dib7090_agc_restart); + +int dib7090_get_adc_power(struct dvb_frontend *fe) +{ + return dib7000p_get_adc_power(fe); +} +EXPORT_SYMBOL(dib7090_get_adc_power); + +int dib7090_slave_reset(struct dvb_frontend *fe) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 reg; + + reg = dib7000p_read_word(state, 1794); + dib7000p_write_word(state, 1794, reg | (4 << 12)); + + dib7000p_write_word(state, 1032, 0xffff); + return 0; +} +EXPORT_SYMBOL(dib7090_slave_reset); + +static struct dvb_frontend_ops dib7000p_ops; +struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) +{ + struct dvb_frontend *demod; + struct dib7000p_state *st; + st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL); + if (st == NULL) + return NULL; + + memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config)); + st->i2c_adap = i2c_adap; + st->i2c_addr = i2c_addr; + st->gpio_val = cfg->gpio_val; + st->gpio_dir = cfg->gpio_dir; + + /* Ensure the output mode remains at the previous default if it's + * not specifically set by the caller. + */ + if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) + st->cfg.output_mode = OUTMODE_MPEG2_FIFO; + + demod = &st->demod; + demod->demodulator_priv = st; + memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops)); + + dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */ + + if (dib7000p_identify(st) != 0) + goto error; + + st->version = dib7000p_read_word(st, 897); + + /* FIXME: make sure the dev.parent field is initialized, or else + request_firmware() will hit an OOPS (this should be moved somewhere + more common) */ + + /* FIXME: make sure the dev.parent field is initialized, or else + request_firmware() will hit an OOPS (this should be moved somewhere + more common) */ + st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; + + dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); + + /* init 7090 tuner adapter */ + strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name)); + st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo; + st->dib7090_tuner_adap.algo_data = NULL; + st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent; + i2c_set_adapdata(&st->dib7090_tuner_adap, st); + i2c_add_adapter(&st->dib7090_tuner_adap); + + dib7000p_demod_reset(st); + + if (st->version == SOC7090) { + dib7090_set_output_mode(demod, st->cfg.output_mode); + dib7090_set_diversity_in(demod, 0); + } + + return demod; + +error: + kfree(st); + return NULL; +} +EXPORT_SYMBOL(dib7000p_attach); + +static struct dvb_frontend_ops dib7000p_ops = { + .info = { + .name = "DiBcom 7000PC", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, + }, + + .release = dib7000p_release, + + .init = dib7000p_wakeup, + .sleep = dib7000p_sleep, + + .set_frontend = dib7000p_set_frontend, + .get_tune_settings = dib7000p_fe_get_tune_settings, + .get_frontend = dib7000p_get_frontend, + + .read_status = dib7000p_read_status, + .read_ber = dib7000p_read_ber, + .read_signal_strength = dib7000p_read_signal_strength, + .read_snr = dib7000p_read_snr, + .read_ucblocks = dib7000p_read_unc_blocks, +}; + +MODULE_AUTHOR("Olivier Grenie "); +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000p.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000p.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000p.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib7000p.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,156 @@ +#ifndef DIB7000P_H +#define DIB7000P_H + +#include "dibx000_common.h" + +struct dib7000p_config { + u8 output_mpeg2_in_188_bytes; + u8 hostbus_diversity; + u8 tuner_is_baseband; + int (*update_lna) (struct dvb_frontend *, u16 agc_global); + + u8 agc_config_count; + struct dibx000_agc_config *agc; + struct dibx000_bandwidth_config *bw; + +#define DIB7000P_GPIO_DEFAULT_DIRECTIONS 0xffff + u16 gpio_dir; +#define DIB7000P_GPIO_DEFAULT_VALUES 0x0000 + u16 gpio_val; +#define DIB7000P_GPIO_PWM_POS0(v) ((v & 0xf) << 12) +#define DIB7000P_GPIO_PWM_POS1(v) ((v & 0xf) << 8 ) +#define DIB7000P_GPIO_PWM_POS2(v) ((v & 0xf) << 4 ) +#define DIB7000P_GPIO_PWM_POS3(v) (v & 0xf) +#define DIB7000P_GPIO_DEFAULT_PWM_POS 0xffff + u16 gpio_pwm_pos; + + u16 pwm_freq_div; + + u8 quartz_direct; + + u8 spur_protect; + + int (*agc_control) (struct dvb_frontend *, u8 before); + + u8 output_mode; + u8 disable_sample_and_hold:1; + + u8 enable_current_mirror:1; + u16 diversity_delay; + + u8 default_i2c_addr; + u8 enMpegOutput:1; +}; + +#define DEFAULT_DIB7000P_I2C_ADDRESS 18 + +#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \ + defined(MODULE)) +extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); +extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); +extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); +extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); +extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); +extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); +extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw); +extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf); +extern int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart); +extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff); +extern int dib7090_get_adc_power(struct dvb_frontend *fe); +extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe); +extern int dib7090_slave_reset(struct dvb_frontend *fe); +#else +static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7090_get_adc_power(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib7090_slave_reset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib8000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib8000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib8000.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib8000.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2619 @@ +/* + * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T). + * + * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#include +#include +#include +#include "dvb_math.h" + +#include "dvb_frontend.h" + +#include "dib8000.h" + +#define LAYER_ALL -1 +#define LAYER_A 1 +#define LAYER_B 2 +#define LAYER_C 3 + +#define FE_CALLBACK_TIME_NEVER 0xffffffff +#define MAX_NUMBER_OF_FRONTENDS 6 + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) + +#define FE_STATUS_TUNE_FAILED 0 + +struct i2c_device { + struct i2c_adapter *adap; + u8 addr; + u8 *i2c_write_buffer; + u8 *i2c_read_buffer; +}; + +struct dib8000_state { + struct dib8000_config cfg; + + struct i2c_device i2c; + + struct dibx000_i2c_master i2c_master; + + u16 wbd_ref; + + u8 current_band; + u32 current_bandwidth; + struct dibx000_agc_config *current_agc; + u32 timf; + u32 timf_default; + + u8 div_force_off:1; + u8 div_state:1; + u16 div_sync_wait; + + u8 agc_state; + u8 differential_constellation; + u8 diversity_onoff; + + s16 ber_monitored_layer; + u16 gpio_dir; + u16 gpio_val; + + u16 revision; + u8 isdbt_cfg_loaded; + enum frontend_tune_state tune_state; + u32 status; + + struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; + + /* for the I2C transfer */ + struct i2c_msg msg[2]; + u8 i2c_write_buffer[4]; + u8 i2c_read_buffer[2]; +}; + +enum dib8000_power_mode { + DIB8000M_POWER_ALL = 0, + DIB8000M_POWER_INTERFACE_ONLY, +}; + +static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) +{ + struct i2c_msg msg[2] = { + {.addr = i2c->addr >> 1, .flags = 0, + .buf = i2c->i2c_write_buffer, .len = 2}, + {.addr = i2c->addr >> 1, .flags = I2C_M_RD, + .buf = i2c->i2c_read_buffer, .len = 2}, + }; + + msg[0].buf[0] = reg >> 8; + msg[0].buf[1] = reg & 0xff; + + if (i2c_transfer(i2c->adap, msg, 2) != 2) + dprintk("i2c read error on %d", reg); + + return (msg[1].buf[0] << 8) | msg[1].buf[1]; +} + +static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) +{ + state->i2c_write_buffer[0] = reg >> 8; + state->i2c_write_buffer[1] = reg & 0xff; + + memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); + state->msg[0].addr = state->i2c.addr >> 1; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 2; + state->msg[1].addr = state->i2c.addr >> 1; + state->msg[1].flags = I2C_M_RD; + state->msg[1].buf = state->i2c_read_buffer; + state->msg[1].len = 2; + + if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2) + dprintk("i2c read error on %d", reg); + + return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; +} + +static u32 dib8000_read32(struct dib8000_state *state, u16 reg) +{ + u16 rw[2]; + + rw[0] = dib8000_read_word(state, reg + 0); + rw[1] = dib8000_read_word(state, reg + 1); + + return ((rw[0] << 16) | (rw[1])); +} + +static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) +{ + struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, + .buf = i2c->i2c_write_buffer, .len = 4}; + int ret = 0; + + msg.buf[0] = (reg >> 8) & 0xff; + msg.buf[1] = reg & 0xff; + msg.buf[2] = (val >> 8) & 0xff; + msg.buf[3] = val & 0xff; + + ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; + + return ret; +} + +static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) +{ + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; + state->i2c_write_buffer[1] = reg & 0xff; + state->i2c_write_buffer[2] = (val >> 8) & 0xff; + state->i2c_write_buffer[3] = val & 0xff; + + memset(&state->msg[0], 0, sizeof(struct i2c_msg)); + state->msg[0].addr = state->i2c.addr >> 1; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 4; + + return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; +} + +static const s16 coeff_2k_sb_1seg_dqpsk[8] = { + (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, + (920 << 5) | 0x09 +}; + +static const s16 coeff_2k_sb_1seg[8] = { + (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f +}; + +static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { + (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, + (-931 << 5) | 0x0f +}; + +static const s16 coeff_2k_sb_3seg_0dqpsk[8] = { + (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, + (982 << 5) | 0x0c +}; + +static const s16 coeff_2k_sb_3seg_1dqpsk[8] = { + (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, + (-720 << 5) | 0x0d +}; + +static const s16 coeff_2k_sb_3seg[8] = { + (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, + (-610 << 5) | 0x0a +}; + +static const s16 coeff_4k_sb_1seg_dqpsk[8] = { + (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, + (-922 << 5) | 0x0d +}; + +static const s16 coeff_4k_sb_1seg[8] = { + (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, + (-655 << 5) | 0x0a +}; + +static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { + (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, + (-958 << 5) | 0x13 +}; + +static const s16 coeff_4k_sb_3seg_0dqpsk[8] = { + (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, + (-568 << 5) | 0x0f +}; + +static const s16 coeff_4k_sb_3seg_1dqpsk[8] = { + (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, + (-848 << 5) | 0x13 +}; + +static const s16 coeff_4k_sb_3seg[8] = { + (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, + (-869 << 5) | 0x13 +}; + +static const s16 coeff_8k_sb_1seg_dqpsk[8] = { + (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, + (-598 << 5) | 0x10 +}; + +static const s16 coeff_8k_sb_1seg[8] = { + (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, + (585 << 5) | 0x0f +}; + +static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { + (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, + (0 << 5) | 0x14 +}; + +static const s16 coeff_8k_sb_3seg_0dqpsk[8] = { + (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, + (-877 << 5) | 0x15 +}; + +static const s16 coeff_8k_sb_3seg_1dqpsk[8] = { + (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, + (-921 << 5) | 0x14 +}; + +static const s16 coeff_8k_sb_3seg[8] = { + (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, + (690 << 5) | 0x14 +}; + +static const s16 ana_fe_coeff_3seg[24] = { + 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017 +}; + +static const s16 ana_fe_coeff_1seg[24] = { + 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003 +}; + +static const s16 ana_fe_coeff_13seg[24] = { + 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1 +}; + +static u16 fft_to_mode(struct dib8000_state *state) +{ + u16 mode; + switch (state->fe[0]->dtv_property_cache.transmission_mode) { + case TRANSMISSION_MODE_2K: + mode = 1; + break; + case TRANSMISSION_MODE_4K: + mode = 2; + break; + default: + case TRANSMISSION_MODE_AUTO: + case TRANSMISSION_MODE_8K: + mode = 3; + break; + } + return mode; +} + +static void dib8000_set_acquisition_mode(struct dib8000_state *state) +{ + u16 nud = dib8000_read_word(state, 298); + nud |= (1 << 3) | (1 << 0); + dprintk("acquisition mode activated"); + dib8000_write_word(state, 298, nud); +} +static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) +{ + struct dib8000_state *state = fe->demodulator_priv; + + u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */ + + outreg = 0; + fifo_threshold = 1792; + smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); + + dprintk("-I- Setting output mode for demod %p to %d", + &state->fe[0], mode); + + switch (mode) { + case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock + outreg = (1 << 10); /* 0x0400 */ + break; + case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock + outreg = (1 << 10) | (1 << 6); /* 0x0440 */ + break; + case OUTMODE_MPEG2_SERIAL: // STBs with serial input + outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ + break; + case OUTMODE_DIVERSITY: + if (state->cfg.hostbus_diversity) { + outreg = (1 << 10) | (4 << 6); /* 0x0500 */ + sram &= 0xfdff; + } else + sram |= 0x0c00; + break; + case OUTMODE_MPEG2_FIFO: // e.g. USB feeding + smo_mode |= (3 << 1); + fifo_threshold = 512; + outreg = (1 << 10) | (5 << 6); + break; + case OUTMODE_HIGH_Z: // disable + outreg = 0; + break; + + case OUTMODE_ANALOG_ADC: + outreg = (1 << 10) | (3 << 6); + dib8000_set_acquisition_mode(state); + break; + + default: + dprintk("Unhandled output_mode passed to be set for demod %p", + &state->fe[0]); + return -EINVAL; + } + + if (state->cfg.output_mpeg2_in_188_bytes) + smo_mode |= (1 << 5); + + dib8000_write_word(state, 299, smo_mode); + dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */ + dib8000_write_word(state, 1286, outreg); + dib8000_write_word(state, 1291, sram); + + return 0; +} + +static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0; + + if (!state->differential_constellation) { + dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1 + dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2 + } else { + dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0 + dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0 + } + state->diversity_onoff = onoff; + + switch (onoff) { + case 0: /* only use the internal way - not the diversity input */ + dib8000_write_word(state, 270, 1); + dib8000_write_word(state, 271, 0); + break; + case 1: /* both ways */ + dib8000_write_word(state, 270, 6); + dib8000_write_word(state, 271, 6); + break; + case 2: /* only the diversity input */ + dib8000_write_word(state, 270, 0); + dib8000_write_word(state, 271, 1); + break; + } + return 0; +} + +static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode) +{ + /* by default everything is going to be powered off */ + u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, + reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, + reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; + + /* now, depending on the requested mode, we power on */ + switch (mode) { + /* power up everything in the demod */ + case DIB8000M_POWER_ALL: + reg_774 = 0x0000; + reg_775 = 0x0000; + reg_776 = 0x0000; + reg_900 &= 0xfffc; + reg_1280 &= 0x00ff; + break; + case DIB8000M_POWER_INTERFACE_ONLY: + reg_1280 &= 0x00ff; + break; + } + + dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280); + dib8000_write_word(state, 774, reg_774); + dib8000_write_word(state, 775, reg_775); + dib8000_write_word(state, 776, reg_776); + dib8000_write_word(state, 900, reg_900); + dib8000_write_word(state, 1280, reg_1280); +} + +static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no) +{ + int ret = 0; + u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908); + + switch (no) { + case DIBX000_SLOW_ADC_ON: + reg_908 |= (1 << 1) | (1 << 0); + ret |= dib8000_write_word(state, 908, reg_908); + reg_908 &= ~(1 << 1); + break; + + case DIBX000_SLOW_ADC_OFF: + reg_908 |= (1 << 1) | (1 << 0); + break; + + case DIBX000_ADC_ON: + reg_907 &= 0x0fff; + reg_908 &= 0x0003; + break; + + case DIBX000_ADC_OFF: // leave the VBG voltage on + reg_907 |= (1 << 14) | (1 << 13) | (1 << 12); + reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); + break; + + case DIBX000_VBG_ENABLE: + reg_907 &= ~(1 << 15); + break; + + case DIBX000_VBG_DISABLE: + reg_907 |= (1 << 15); + break; + + default: + break; + } + + ret |= dib8000_write_word(state, 907, reg_907); + ret |= dib8000_write_word(state, 908, reg_908); + + return ret; +} + +static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) +{ + struct dib8000_state *state = fe->demodulator_priv; + u32 timf; + + if (bw == 0) + bw = 6000; + + if (state->timf == 0) { + dprintk("using default timf"); + timf = state->timf_default; + } else { + dprintk("using updated timf"); + timf = state->timf; + } + + dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff)); + dib8000_write_word(state, 30, (u16) ((timf) & 0xffff)); + + return 0; +} + +static int dib8000_sad_calib(struct dib8000_state *state) +{ +/* internal */ + dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); + dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096 + + /* do the calibration */ + dib8000_write_word(state, 923, (1 << 0)); + dib8000_write_word(state, 923, (0 << 0)); + + msleep(1); + return 0; +} + +int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) +{ + struct dib8000_state *state = fe->demodulator_priv; + if (value > 4095) + value = 4095; + state->wbd_ref = value; + return dib8000_write_word(state, 106, value); +} + +EXPORT_SYMBOL(dib8000_set_wbd_ref); +static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) +{ + dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25); + dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */ + dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff)); + dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff)); + dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff)); + dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003)); + + dib8000_write_word(state, 922, bw->sad_cfg); +} + +static void dib8000_reset_pll(struct dib8000_state *state) +{ + const struct dibx000_bandwidth_config *pll = state->cfg.pll; + u16 clk_cfg1; + + // clk_cfg0 + dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); + + // clk_cfg1 + clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | + (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | + (pll->pll_range << 1) | (pll->pll_reset << 0); + + dib8000_write_word(state, 902, clk_cfg1); + clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); + dib8000_write_word(state, 902, clk_cfg1); + + dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */ + + /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ + if (state->cfg.pll->ADClkSrc == 0) + dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | + (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); + else if (state->cfg.refclksel != 0) + dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | + ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | + (pll->ADClkSrc << 7) | (0 << 1)); + else + dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); + + dib8000_reset_pll_common(state, pll); +} + +static int dib8000_reset_gpio(struct dib8000_state *st) +{ + /* reset the GPIOs */ + dib8000_write_word(st, 1029, st->cfg.gpio_dir); + dib8000_write_word(st, 1030, st->cfg.gpio_val); + + /* TODO 782 is P_gpio_od */ + + dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos); + + dib8000_write_word(st, 1037, st->cfg.pwm_freq_div); + return 0; +} + +static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val) +{ + st->cfg.gpio_dir = dib8000_read_word(st, 1029); + st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */ + st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */ + dib8000_write_word(st, 1029, st->cfg.gpio_dir); + + st->cfg.gpio_val = dib8000_read_word(st, 1030); + st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */ + st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */ + dib8000_write_word(st, 1030, st->cfg.gpio_val); + + dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val); + + return 0; +} + +int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + struct dib8000_state *state = fe->demodulator_priv; + return dib8000_cfg_gpio(state, num, dir, val); +} + +EXPORT_SYMBOL(dib8000_set_gpio); +static const u16 dib8000_defaults[] = { + /* auto search configuration - lock0 by default waiting + * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */ + 3, 7, + 0x0004, + 0x0400, + 0x0814, + + 12, 11, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + /*1, 32, + 0x6680 // P_corm_thres Lock algorithms configuration */ + + 11, 80, /* set ADC level to -16 */ + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + 4, 108, + 0, + 0, + 0, + 0, + + 1, 175, + 0x0410, + 1, 179, + 8192, // P_fft_nb_to_cut + + 6, 181, + 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800 + 0x2800, + 0x2800, + 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800 + 0x2800, + 0x2800, + + 2, 193, + 0x0666, // P_pha3_thres + 0x0000, // P_cti_use_cpe, P_cti_use_prog + + 2, 205, + 0x200f, // P_cspu_regul, P_cspu_win_cut + 0x000f, // P_des_shift_work + + 5, 215, + 0x023d, // P_adp_regul_cnt + 0x00a4, // P_adp_noise_cnt + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 230, + 0x0000, // P_2d_byp_ti_num + + 1, 263, + 0x800, //P_equal_thres_wgn + + 1, 268, + (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode + + 1, 270, + 0x0001, // P_div_lock0_wait + 1, 285, + 0x0020, //p_fec_ + 1, 299, + 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */ + + 1, 338, + (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1 + (1 << 10) | + (0 << 9) | /* P_ctrl_pre_freq_inh=0 */ + (3 << 5) | /* P_ctrl_pre_freq_step=3 */ + (1 << 0), /* P_pre_freq_win_len=1 */ + + 1, 903, + (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW) + + 0, +}; + +static u16 dib8000_identify(struct i2c_device *client) +{ + u16 value; + + //because of glitches sometimes + value = dib8000_i2c_read16(client, 896); + + if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) { + dprintk("wrong Vendor ID (read=0x%x)", value); + return 0; + } + + value = dib8000_i2c_read16(client, 897); + if (value != 0x8000 && value != 0x8001 && value != 0x8002) { + dprintk("wrong Device ID (%x)", value); + return 0; + } + + switch (value) { + case 0x8000: + dprintk("found DiB8000A"); + break; + case 0x8001: + dprintk("found DiB8000B"); + break; + case 0x8002: + dprintk("found DiB8000C"); + break; + } + return value; +} + +static int dib8000_reset(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + + dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */ + + if ((state->revision = dib8000_identify(&state->i2c)) == 0) + return -EINVAL; + + if (state->revision == 0x8000) + dprintk("error : dib8000 MA not supported"); + + dibx000_reset_i2c_master(&state->i2c_master); + + dib8000_set_power_mode(state, DIB8000M_POWER_ALL); + + /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ + dib8000_set_adc_state(state, DIBX000_VBG_ENABLE); + + /* restart all parts */ + dib8000_write_word(state, 770, 0xffff); + dib8000_write_word(state, 771, 0xffff); + dib8000_write_word(state, 772, 0xfffc); + dib8000_write_word(state, 898, 0x000c); // sad + dib8000_write_word(state, 1280, 0x004d); + dib8000_write_word(state, 1281, 0x000c); + + dib8000_write_word(state, 770, 0x0000); + dib8000_write_word(state, 771, 0x0000); + dib8000_write_word(state, 772, 0x0000); + dib8000_write_word(state, 898, 0x0004); // sad + dib8000_write_word(state, 1280, 0x0000); + dib8000_write_word(state, 1281, 0x0000); + + /* drives */ + if (state->cfg.drives) + dib8000_write_word(state, 906, state->cfg.drives); + else { + dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); + dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust + } + + dib8000_reset_pll(state); + + if (dib8000_reset_gpio(state) != 0) + dprintk("GPIO reset was not successful."); + + if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0) + dprintk("OUTPUT_MODE could not be resetted."); + + state->current_agc = NULL; + + // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... + /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */ + if (state->cfg.pll->ifreq == 0) + dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */ + else + dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */ + + { + u16 l = 0, r; + const u16 *n; + n = dib8000_defaults; + l = *n++; + while (l) { + r = *n++; + do { + dib8000_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } + } + state->isdbt_cfg_loaded = 0; + + //div_cfg override for special configs + if (state->cfg.div_cfg != 0) + dib8000_write_word(state, 903, state->cfg.div_cfg); + + /* unforce divstr regardless whether i2c enumeration was done or not */ + dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1)); + + dib8000_set_bandwidth(fe, 6000); + + dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); + dib8000_sad_calib(state); + dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + + dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); + + return 0; +} + +static void dib8000_restart_agc(struct dib8000_state *state) +{ + // P_restart_iqc & P_restart_agc + dib8000_write_word(state, 770, 0x0a00); + dib8000_write_word(state, 770, 0x0000); +} + +static int dib8000_update_lna(struct dib8000_state *state) +{ + u16 dyn_gain; + + if (state->cfg.update_lna) { + // read dyn_gain here (because it is demod-dependent and not tuner) + dyn_gain = dib8000_read_word(state, 390); + + if (state->cfg.update_lna(state->fe[0], dyn_gain)) { + dib8000_restart_agc(state); + return 1; + } + } + return 0; +} + +static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) +{ + struct dibx000_agc_config *agc = NULL; + int i; + if (state->current_band == band && state->current_agc != NULL) + return 0; + state->current_band = band; + + for (i = 0; i < state->cfg.agc_config_count; i++) + if (state->cfg.agc[i].band_caps & band) { + agc = &state->cfg.agc[i]; + break; + } + + if (agc == NULL) { + dprintk("no valid AGC configuration found for band 0x%02x", band); + return -EINVAL; + } + + state->current_agc = agc; + + /* AGC */ + dib8000_write_word(state, 76, agc->setup); + dib8000_write_word(state, 77, agc->inv_gain); + dib8000_write_word(state, 78, agc->time_stabiliz); + dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock); + + // Demod AGC loop configuration + dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp); + dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp); + + dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", + state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); + + /* AGC continued */ + if (state->wbd_ref != 0) + dib8000_write_word(state, 106, state->wbd_ref); + else // use default + dib8000_write_word(state, 106, agc->wbd_ref); + dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); + dib8000_write_word(state, 108, agc->agc1_max); + dib8000_write_word(state, 109, agc->agc1_min); + dib8000_write_word(state, 110, agc->agc2_max); + dib8000_write_word(state, 111, agc->agc2_min); + dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2); + dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); + dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); + + dib8000_write_word(state, 75, agc->agc1_pt3); + dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */ + + return 0; +} + +void dib8000_pwm_agc_reset(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + dib8000_set_adc_state(state, DIBX000_ADC_ON); + dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))); +} +EXPORT_SYMBOL(dib8000_pwm_agc_reset); + +static int dib8000_agc_soft_split(struct dib8000_state *state) +{ + u16 agc, split_offset; + + if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0) + return FE_CALLBACK_TIME_NEVER; + + // n_agc_global + agc = dib8000_read_word(state, 390); + + if (agc > state->current_agc->split.min_thres) + split_offset = state->current_agc->split.min; + else if (agc < state->current_agc->split.max_thres) + split_offset = state->current_agc->split.max; + else + split_offset = state->current_agc->split.max * + (agc - state->current_agc->split.min_thres) / + (state->current_agc->split.max_thres - state->current_agc->split.min_thres); + + dprintk("AGC split_offset: %d", split_offset); + + // P_agc_force_split and P_agc_split_offset + dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset); + return 5000; +} + +static int dib8000_agc_startup(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + enum frontend_tune_state *tune_state = &state->tune_state; + + int ret = 0; + + switch (*tune_state) { + case CT_AGC_START: + // set power-up level: interf+analog+AGC + + dib8000_set_adc_state(state, DIBX000_ADC_ON); + + if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) { + *tune_state = CT_AGC_STOP; + state->status = FE_STATUS_TUNE_FAILED; + break; + } + + ret = 70; + *tune_state = CT_AGC_STEP_0; + break; + + case CT_AGC_STEP_0: + //AGC initialization + if (state->cfg.agc_control) + state->cfg.agc_control(fe, 1); + + dib8000_restart_agc(state); + + // wait AGC rough lock time + ret = 50; + *tune_state = CT_AGC_STEP_1; + break; + + case CT_AGC_STEP_1: + // wait AGC accurate lock time + ret = 70; + + if (dib8000_update_lna(state)) + // wait only AGC rough lock time + ret = 50; + else + *tune_state = CT_AGC_STEP_2; + break; + + case CT_AGC_STEP_2: + dib8000_agc_soft_split(state); + + if (state->cfg.agc_control) + state->cfg.agc_control(fe, 0); + + *tune_state = CT_AGC_STOP; + break; + default: + ret = dib8000_agc_soft_split(state); + break; + } + return ret; + +} + +static const s32 lut_1000ln_mant[] = +{ + 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 +}; + +s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) +{ + struct dib8000_state *state = fe->demodulator_priv; + u32 ix = 0, tmp_val = 0, exp = 0, mant = 0; + s32 val; + + val = dib8000_read32(state, 384); + if (mode) { + tmp_val = val; + while (tmp_val >>= 1) + exp++; + mant = (val * 1000 / (1<timf = dib8000_read32(state, 435); + + dib8000_write_word(state, 29, (u16) (timf >> 16)); + dib8000_write_word(state, 30, (u16) (timf & 0xffff)); + dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); +} + +static const u16 adc_target_16dB[11] = { + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117 +}; +static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; + +static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching) +{ + u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0; + u8 guard, crate, constellation, timeI; + u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled + const s16 *ncoeff = NULL, *ana_fe; + u16 tmcc_pow = 0; + u16 coff_pow = 0x2800; + u16 init_prbs = 0xfff; + u16 ana_gain = 0; + + if (state->ber_monitored_layer != LAYER_ALL) + dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer); + else + dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); + + i = dib8000_read_word(state, 26) & 1; // P_dds_invspec + dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i); + + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + //compute new dds_freq for the seg and adjust prbs + int seg_offset = + state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx - + (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) - + (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2); + int clk = state->cfg.pll->internal; + u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26) + int dds_offset = seg_offset * segtodds; + int new_dds, sub_channel; + if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) + dds_offset -= (int)(segtodds / 2); + + if (state->cfg.pll->ifreq == 0) { + if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) { + dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); + new_dds = dds_offset; + } else + new_dds = dds_offset; + + // We shift tuning frequency if the wanted segment is : + // - the segment of center frequency with an odd total number of segments + // - the segment to the left of center frequency with an even total number of segments + // - the segment to the right of center frequency with an even total number of segments + if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT) + && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) + && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) + && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == + ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) + || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) + && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2))) + || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) + && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == + ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) + )) { + new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26) + } + } else { + if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) + new_dds = state->cfg.pll->ifreq - dds_offset; + else + new_dds = state->cfg.pll->ifreq + dds_offset; + } + dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff)); + dib8000_write_word(state, 28, (u16) (new_dds & 0xffff)); + if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) + sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3; + else + sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3; + sub_channel -= 6; + + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K + || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) { + dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1 + dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1 + } else { + dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0 + dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0 + } + + switch (state->fe[0]->dtv_property_cache.transmission_mode) { + case TRANSMISSION_MODE_2K: + switch (sub_channel) { + case -6: + init_prbs = 0x0; + break; // 41, 0, 1 + case -5: + init_prbs = 0x423; + break; // 02~04 + case -4: + init_prbs = 0x9; + break; // 05~07 + case -3: + init_prbs = 0x5C7; + break; // 08~10 + case -2: + init_prbs = 0x7A6; + break; // 11~13 + case -1: + init_prbs = 0x3D8; + break; // 14~16 + case 0: + init_prbs = 0x527; + break; // 17~19 + case 1: + init_prbs = 0x7FF; + break; // 20~22 + case 2: + init_prbs = 0x79B; + break; // 23~25 + case 3: + init_prbs = 0x3D6; + break; // 26~28 + case 4: + init_prbs = 0x3A2; + break; // 29~31 + case 5: + init_prbs = 0x53B; + break; // 32~34 + case 6: + init_prbs = 0x2F4; + break; // 35~37 + default: + case 7: + init_prbs = 0x213; + break; // 38~40 + } + break; + + case TRANSMISSION_MODE_4K: + switch (sub_channel) { + case -6: + init_prbs = 0x0; + break; // 41, 0, 1 + case -5: + init_prbs = 0x208; + break; // 02~04 + case -4: + init_prbs = 0xC3; + break; // 05~07 + case -3: + init_prbs = 0x7B9; + break; // 08~10 + case -2: + init_prbs = 0x423; + break; // 11~13 + case -1: + init_prbs = 0x5C7; + break; // 14~16 + case 0: + init_prbs = 0x3D8; + break; // 17~19 + case 1: + init_prbs = 0x7FF; + break; // 20~22 + case 2: + init_prbs = 0x3D6; + break; // 23~25 + case 3: + init_prbs = 0x53B; + break; // 26~28 + case 4: + init_prbs = 0x213; + break; // 29~31 + case 5: + init_prbs = 0x29; + break; // 32~34 + case 6: + init_prbs = 0xD0; + break; // 35~37 + default: + case 7: + init_prbs = 0x48E; + break; // 38~40 + } + break; + + default: + case TRANSMISSION_MODE_8K: + switch (sub_channel) { + case -6: + init_prbs = 0x0; + break; // 41, 0, 1 + case -5: + init_prbs = 0x740; + break; // 02~04 + case -4: + init_prbs = 0x069; + break; // 05~07 + case -3: + init_prbs = 0x7DD; + break; // 08~10 + case -2: + init_prbs = 0x208; + break; // 11~13 + case -1: + init_prbs = 0x7B9; + break; // 14~16 + case 0: + init_prbs = 0x5C7; + break; // 17~19 + case 1: + init_prbs = 0x7FF; + break; // 20~22 + case 2: + init_prbs = 0x53B; + break; // 23~25 + case 3: + init_prbs = 0x29; + break; // 26~28 + case 4: + init_prbs = 0x48E; + break; // 29~31 + case 5: + init_prbs = 0x4C4; + break; // 32~34 + case 6: + init_prbs = 0x367; + break; // 33~37 + default: + case 7: + init_prbs = 0x684; + break; // 38~40 + } + break; + } + } else { + dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff)); + dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff)); + dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003)); + } + /*P_mode == ?? */ + dib8000_write_word(state, 10, (seq << 4)); + // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000); + + switch (state->fe[0]->dtv_property_cache.guard_interval) { + case GUARD_INTERVAL_1_32: + guard = 0; + break; + case GUARD_INTERVAL_1_16: + guard = 1; + break; + case GUARD_INTERVAL_1_8: + guard = 2; + break; + case GUARD_INTERVAL_1_4: + default: + guard = 3; + break; + } + + dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1 + + max_constellation = DQPSK; + for (i = 0; i < 3; i++) { + switch (state->fe[0]->dtv_property_cache.layer[i].modulation) { + case DQPSK: + constellation = 0; + break; + case QPSK: + constellation = 1; + break; + case QAM_16: + constellation = 2; + break; + case QAM_64: + default: + constellation = 3; + break; + } + + switch (state->fe[0]->dtv_property_cache.layer[i].fec) { + case FEC_1_2: + crate = 1; + break; + case FEC_2_3: + crate = 2; + break; + case FEC_3_4: + crate = 3; + break; + case FEC_5_6: + crate = 5; + break; + case FEC_7_8: + default: + crate = 7; + break; + } + + if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) && + ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) || + (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)) + ) + timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving; + else + timeI = 0; + dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) | + (crate << 3) | timeI); + if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) { + switch (max_constellation) { + case DQPSK: + case QPSK: + if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 || + state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64) + max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation; + break; + case QAM_16: + if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64) + max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation; + break; + } + } + } + + mode = fft_to_mode(state); + + //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/ + + dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | + ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache. + isdbt_sb_mode & 1) << 4)); + + dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval); + + /* signal optimization parameter */ + + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) { + seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0]; + for (i = 1; i < 3; i++) + nbseg_diff += + (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; + for (i = 0; i < nbseg_diff; i++) + seg_diff_mask |= 1 << permu_seg[i + 1]; + } else { + for (i = 0; i < 3; i++) + nbseg_diff += + (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; + for (i = 0; i < nbseg_diff; i++) + seg_diff_mask |= 1 << permu_seg[i]; + } + dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask); + + state->differential_constellation = (seg_diff_mask != 0); + dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); + + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) + seg_mask13 = 0x00E0; + else // 1-segment + seg_mask13 = 0x0040; + } else + seg_mask13 = 0x1fff; + + // WRITE: Mode & Diff mask + dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask); + + if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode)) + dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); + else + dib8000_write_word(state, 268, (2 << 9) | 39); //init value + + // ---- SMALL ---- + // P_small_seg_diff + dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352 + + dib8000_write_word(state, 353, seg_mask13); // ADDR 353 + +/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */ + + // ---- SMALL ---- + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + switch (state->fe[0]->dtv_property_cache.transmission_mode) { + case TRANSMISSION_MODE_2K: + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) + ncoeff = coeff_2k_sb_1seg_dqpsk; + else // QPSK or QAM + ncoeff = coeff_2k_sb_1seg; + } else { // 3-segments + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) + ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; + else // QPSK or QAM on external segments + ncoeff = coeff_2k_sb_3seg_0dqpsk; + } else { // QPSK or QAM on central segment + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) + ncoeff = coeff_2k_sb_3seg_1dqpsk; + else // QPSK or QAM on external segments + ncoeff = coeff_2k_sb_3seg; + } + } + break; + + case TRANSMISSION_MODE_4K: + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) + ncoeff = coeff_4k_sb_1seg_dqpsk; + else // QPSK or QAM + ncoeff = coeff_4k_sb_1seg; + } else { // 3-segments + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { + ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; + } else { // QPSK or QAM on external segments + ncoeff = coeff_4k_sb_3seg_0dqpsk; + } + } else { // QPSK or QAM on central segment + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { + ncoeff = coeff_4k_sb_3seg_1dqpsk; + } else // QPSK or QAM on external segments + ncoeff = coeff_4k_sb_3seg; + } + } + break; + + case TRANSMISSION_MODE_AUTO: + case TRANSMISSION_MODE_8K: + default: + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) + ncoeff = coeff_8k_sb_1seg_dqpsk; + else // QPSK or QAM + ncoeff = coeff_8k_sb_1seg; + } else { // 3-segments + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { + ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; + } else { // QPSK or QAM on external segments + ncoeff = coeff_8k_sb_3seg_0dqpsk; + } + } else { // QPSK or QAM on central segment + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { + ncoeff = coeff_8k_sb_3seg_1dqpsk; + } else // QPSK or QAM on external segments + ncoeff = coeff_8k_sb_3seg; + } + } + break; + } + for (i = 0; i < 8; i++) + dib8000_write_word(state, 343 + i, ncoeff[i]); + } + + // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 + dib8000_write_word(state, 351, + (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5); + + // ---- COFF ---- + // Carloff, the most robust + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + + // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64 + // P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 + dib8000_write_word(state, 187, + (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2) + | 0x3); + +/* // P_small_coef_ext_enable = 1 */ +/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */ + + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + + // P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1) + if (mode == 3) + dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14)); + else + dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14)); + // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, + // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 + dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4); + // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 + dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); + // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 + dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); + + // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k + dib8000_write_word(state, 181, 300); + dib8000_write_word(state, 182, 150); + dib8000_write_word(state, 183, 80); + dib8000_write_word(state, 184, 300); + dib8000_write_word(state, 185, 150); + dib8000_write_word(state, 186, 80); + } else { // Sound Broadcasting mode 3 seg + // P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15 + /* if (mode == 3) */ + /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */ + /* else */ + /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */ + dib8000_write_word(state, 180, 0x1fcf | (1 << 14)); + + // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, + // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 + dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4); + // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 + dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); + //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 + dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); + + // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k + dib8000_write_word(state, 181, 350); + dib8000_write_word(state, 182, 300); + dib8000_write_word(state, 183, 250); + dib8000_write_word(state, 184, 350); + dib8000_write_word(state, 185, 300); + dib8000_write_word(state, 186, 250); + } + + } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments + dib8000_write_word(state, 180, (16 << 6) | 9); + dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2); + coff_pow = 0x2800; + for (i = 0; i < 6; i++) + dib8000_write_word(state, 181 + i, coff_pow); + + // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1, + // P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 + dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1); + + // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 + dib8000_write_word(state, 340, (8 << 6) | (6 << 0)); + // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 + dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); + } + // ---- FFT ---- + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) + dib8000_write_word(state, 178, 64); // P_fft_powrange=64 + else + dib8000_write_word(state, 178, 32); // P_fft_powrange=32 + + /* make the cpil_coff_lock more robust but slower p_coff_winlen + * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) + */ + /* if ( ( nbseg_diff>0)&&(nbseg_diff<13)) + dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */ + + dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */ + dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */ + dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */ + if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0)) + dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */ + else + dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */ + dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */ + //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */ + if (!autosearching) + dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */ + else + dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. + dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000); + + dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */ + + /* offset loop parameters */ + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) + /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ + dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40); + + else // Sound Broadcasting mode 3 seg + /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ + dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60); + } else + // TODO in 13 seg, timf_alpha can always be the same or not ? + /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */ + dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80); + + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) + /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */ + dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode)); + + else // Sound Broadcasting mode 3 seg + /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */ + dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode)); + } else + /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */ + dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode)); + + /* P_dvsy_sync_wait - reuse mode */ + switch (state->fe[0]->dtv_property_cache.transmission_mode) { + case TRANSMISSION_MODE_8K: + mode = 256; + break; + case TRANSMISSION_MODE_4K: + mode = 128; + break; + default: + case TRANSMISSION_MODE_2K: + mode = 64; + break; + } + if (state->cfg.diversity_delay == 0) + mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo + else + mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo + mode <<= 4; + dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode); + + /* channel estimation fine configuration */ + switch (max_constellation) { + case QAM_64: + ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB + coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ + coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ + coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ + coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ + //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1 + break; + case QAM_16: + ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB + coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ + coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ + coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ + coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ + //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16))) + break; + default: + ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level + coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ + coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ + coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */ + coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ + break; + } + for (mode = 0; mode < 4; mode++) + dib8000_write_word(state, 215 + mode, coeff[mode]); + + // update ana_gain depending on max constellation + dib8000_write_word(state, 116, ana_gain); + // update ADC target depending on ana_gain + if (ana_gain) { // set -16dB ADC target for ana_gain=-1 + for (i = 0; i < 10; i++) + dib8000_write_word(state, 80 + i, adc_target_16dB[i]); + } else { // set -22dB ADC target for ana_gain=0 + for (i = 0; i < 10; i++) + dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355); + } + + // ---- ANA_FE ---- + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) + ana_fe = ana_fe_coeff_3seg; + else // 1-segment + ana_fe = ana_fe_coeff_1seg; + } else + ana_fe = ana_fe_coeff_13seg; + + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0) + for (mode = 0; mode < 24; mode++) + dib8000_write_word(state, 117 + mode, ana_fe[mode]); + + // ---- CHAN_BLK ---- + for (i = 0; i < 13; i++) { + if ((((~seg_diff_mask) >> i) & 1) == 1) { + P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0)); + P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0)); + } + } + dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge + dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge + // "P_cspu_left_edge" not used => do not care + // "P_cspu_right_edge" not used => do not care + + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1 + dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0 + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 + && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) { + //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0 + dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15 + } + } else if (state->isdbt_cfg_loaded == 0) { + dib8000_write_word(state, 228, 0); // default value + dib8000_write_word(state, 265, 31); // default value + dib8000_write_word(state, 205, 0x200f); // init value + } + // ---- TMCC ---- + for (i = 0; i < 3; i++) + tmcc_pow += + (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count); + // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); + // Threshold is set at 1/4 of max power. + tmcc_pow *= (1 << (9 - 2)); + + dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k + dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k + dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k + //dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); + // ---- PHA3 ---- + + if (state->isdbt_cfg_loaded == 0) + dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */ + + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) + state->isdbt_cfg_loaded = 0; + else + state->isdbt_cfg_loaded = 1; + +} + +static int dib8000_autosearch_start(struct dvb_frontend *fe) +{ + u8 factor; + u32 value; + struct dib8000_state *state = fe->demodulator_priv; + + int slist = 0; + + state->fe[0]->dtv_property_cache.inversion = 0; + if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode) + state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; + state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64; + state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3; + state->fe[0]->dtv_property_cache.layer[0].interleaving = 0; + + //choose the right list, in sb, always do everything + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + slist = 7; + dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); + } else { + if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { + slist = 7; + dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 to have autosearch start ok with mode2 + } else + slist = 3; + } else { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { + slist = 2; + dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 + } else + slist = 0; + } + + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + + dprintk("using list for autosearch : %d", slist); + dib8000_set_channel(state, (unsigned char)slist, 1); + //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 + + factor = 1; + + //set lock_mask values + dib8000_write_word(state, 6, 0x4); + dib8000_write_word(state, 7, 0x8); + dib8000_write_word(state, 8, 0x1000); + + //set lock_mask wait time values + value = 50 * state->cfg.pll->internal * factor; + dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time + dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time + value = 100 * state->cfg.pll->internal * factor; + dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time + dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time + value = 1000 * state->cfg.pll->internal * factor; + dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time + dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time + + value = dib8000_read_word(state, 0); + dib8000_write_word(state, 0, (u16) ((1 << 15) | value)); + dib8000_read_word(state, 1284); // reset the INT. n_irq_pending + dib8000_write_word(state, 0, (u16) value); + + } + + return 0; +} + +static int dib8000_autosearch_irq(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 irq_pending = dib8000_read_word(state, 1284); + + if (irq_pending & 0x1) { // failed + dprintk("dib8000_autosearch_irq failed"); + return 1; + } + + if (irq_pending & 0x2) { // succeeded + dprintk("dib8000_autosearch_irq succeeded"); + return 2; + } + + return 0; // still pending +} + +static int dib8000_tune(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + int ret = 0; + u16 value, mode = fft_to_mode(state); + + // we are already tuned - just resuming from suspend + if (state == NULL) + return -EINVAL; + + dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000); + dib8000_set_channel(state, 0, 0); + + // restart demod + ret |= dib8000_write_word(state, 770, 0x4000); + ret |= dib8000_write_word(state, 770, 0x0000); + msleep(45); + + /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */ + /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */ + + // never achieved a lock before - wait for timfreq to update + if (state->timf == 0) { + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) + msleep(300); + else // Sound Broadcasting mode 3 seg + msleep(500); + } else // 13 seg + msleep(200); + } + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + + /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */ + dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40); + //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80); + + /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */ + ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5)); + + } else { // Sound Broadcasting mode 3 seg + + /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */ + dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60); + + ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5)); + } + + } else { // 13 seg + /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */ + dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80); + + ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5)); + + } + + // we achieved a coff_cpil_lock - it's time to update the timf + if ((dib8000_read_word(state, 568) >> 11) & 0x1) + dib8000_update_timf(state); + + //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start + dib8000_write_word(state, 6, 0x200); + + if (state->revision == 0x8002) { + value = dib8000_read_word(state, 903); + dib8000_write_word(state, 903, value & ~(1 << 3)); + msleep(1); + dib8000_write_word(state, 903, value | (1 << 3)); + } + + return ret; +} + +static int dib8000_wakeup(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend; + int ret; + + dib8000_set_power_mode(state, DIB8000M_POWER_ALL); + dib8000_set_adc_state(state, DIBX000_ADC_ON); + if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) + dprintk("could not start Slow ADC"); + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]); + if (ret < 0) + return ret; + } + + return 0; +} + +static int dib8000_sleep(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend; + int ret; + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); + if (ret < 0) + return ret; + } + + dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); + dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); + return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); +} + +enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + return state->tune_state; +} +EXPORT_SYMBOL(dib8000_get_tune_state); + +int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + struct dib8000_state *state = fe->demodulator_priv; + state->tune_state = tune_state; + return 0; +} +EXPORT_SYMBOL(dib8000_set_tune_state); + +static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 i, val = 0; + fe_status_t stat; + u8 index_frontend, sub_index_frontend; + + fe->dtv_property_cache.bandwidth_hz = 6000000; + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); + if (stat&FE_HAS_SYNC) { + dprintk("TMCC lock on the slave%i", index_frontend); + /* synchronize the cache with the other frontends */ + state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); + for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { + if (sub_index_frontend != index_frontend) { + state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; + state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; + state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; + state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; + state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; + for (i = 0; i < 3; i++) { + state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count; + state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; + state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; + state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; + } + } + } + return 0; + } + } + + fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1; + + val = dib8000_read_word(state, 570); + fe->dtv_property_cache.inversion = (val & 0x40) >> 6; + switch ((val & 0x30) >> 4) { + case 1: + fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; + break; + case 3: + default: + fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + switch (val & 0x3) { + case 0: + fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; + dprintk("dib8000_get_frontend GI = 1/32 "); + break; + case 1: + fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; + dprintk("dib8000_get_frontend GI = 1/16 "); + break; + case 2: + dprintk("dib8000_get_frontend GI = 1/8 "); + fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + dprintk("dib8000_get_frontend GI = 1/4 "); + fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; + break; + } + + val = dib8000_read_word(state, 505); + fe->dtv_property_cache.isdbt_partial_reception = val & 1; + dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception); + + for (i = 0; i < 3; i++) { + val = dib8000_read_word(state, 493 + i); + fe->dtv_property_cache.layer[i].segment_count = val & 0x0F; + dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count); + + val = dib8000_read_word(state, 499 + i); + fe->dtv_property_cache.layer[i].interleaving = val & 0x3; + dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving); + + val = dib8000_read_word(state, 481 + i); + switch (val & 0x7) { + case 1: + fe->dtv_property_cache.layer[i].fec = FEC_1_2; + dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i); + break; + case 2: + fe->dtv_property_cache.layer[i].fec = FEC_2_3; + dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i); + break; + case 3: + fe->dtv_property_cache.layer[i].fec = FEC_3_4; + dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i); + break; + case 5: + fe->dtv_property_cache.layer[i].fec = FEC_5_6; + dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i); + break; + default: + fe->dtv_property_cache.layer[i].fec = FEC_7_8; + dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i); + break; + } + + val = dib8000_read_word(state, 487 + i); + switch (val & 0x3) { + case 0: + dprintk("dib8000_get_frontend : Layer %d DQPSK ", i); + fe->dtv_property_cache.layer[i].modulation = DQPSK; + break; + case 1: + fe->dtv_property_cache.layer[i].modulation = QPSK; + dprintk("dib8000_get_frontend : Layer %d QPSK ", i); + break; + case 2: + fe->dtv_property_cache.layer[i].modulation = QAM_16; + dprintk("dib8000_get_frontend : Layer %d QAM16 ", i); + break; + case 3: + default: + dprintk("dib8000_get_frontend : Layer %d QAM64 ", i); + fe->dtv_property_cache.layer[i].modulation = QAM_64; + break; + } + } + + /* synchronize the cache with the other frontends */ + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode; + state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; + state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; + state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval; + state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception; + for (i = 0; i < 3; i++) { + state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count; + state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving; + state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec; + state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation; + } + } + return 0; +} + +static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 nbr_pending, exit_condition, index_frontend; + s8 index_frontend_success = -1; + int time, ret; + int time_slave = FE_CALLBACK_TIME_NEVER; + + if (state->fe[0]->dtv_property_cache.frequency == 0) { + dprintk("dib8000: must at least specify frequency "); + return 0; + } + + if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { + dprintk("dib8000: no bandwidth specified, set to default "); + state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000; + } + + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + /* synchronization of the cache */ + state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; + memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); + + dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); + if (state->fe[index_frontend]->ops.tuner_ops.set_params) + state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep); + + dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START); + } + + /* start up the AGC */ + do { + time = dib8000_agc_startup(state->fe[0]); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + time_slave = dib8000_agc_startup(state->fe[index_frontend]); + if (time == FE_CALLBACK_TIME_NEVER) + time = time_slave; + else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time)) + time = time_slave; + } + if (time != FE_CALLBACK_TIME_NEVER) + msleep(time / 10); + else + break; + exit_condition = 1; + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) { + exit_condition = 0; + break; + } + } + } while (exit_condition == 0); + + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); + + if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) || + (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) || + (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) || + (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) || + (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) && + (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) && + (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) && + ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) || + (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) || + (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) && + (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) && + (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) && + ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) || + (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) || + (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) && + (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) && + (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) && + ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) || + (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) || + (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) || + ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) && + ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) || + ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && + ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) { + int i = 80000; + u8 found = 0; + u8 tune_failed = 0; + + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000); + dib8000_autosearch_start(state->fe[index_frontend]); + } + + do { + msleep(20); + nbr_pending = 0; + exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (((tune_failed >> index_frontend) & 0x1) == 0) { + found = dib8000_autosearch_irq(state->fe[index_frontend]); + switch (found) { + case 0: /* tune pending */ + nbr_pending++; + break; + case 2: + dprintk("autosearch succeed on the frontend%i", index_frontend); + exit_condition = 2; + index_frontend_success = index_frontend; + break; + default: + dprintk("unhandled autosearch result"); + case 1: + dprintk("autosearch failed for the frontend%i", index_frontend); + break; + } + } + } + + /* if all tune are done and no success, exit: tune failed */ + if ((nbr_pending == 0) && (exit_condition == 0)) + exit_condition = 1; + } while ((exit_condition == 0) && i--); + + if (exit_condition == 1) { /* tune failed */ + dprintk("tune failed"); + return 0; + } + + dprintk("tune success on frontend%i", index_frontend_success); + + dib8000_get_frontend(fe, fep); + } + + for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + ret = dib8000_tune(state->fe[index_frontend]); + + /* set output mode and diversity input */ + dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); + dib8000_set_diversity_in(state->fe[index_frontend-1], 1); + } + + /* turn off the diversity of the last chip */ + dib8000_set_diversity_in(state->fe[index_frontend-1], 0); + + return ret; +} + +static u16 dib8000_read_lock(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + + return dib8000_read_word(state, 568); +} + +static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 lock_slave = 0, lock = dib8000_read_word(state, 568); + u8 index_frontend; + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + lock_slave |= dib8000_read_lock(state->fe[index_frontend]); + + *stat = 0; + + if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1)) + *stat |= FE_HAS_SIGNAL; + + if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */ + *stat |= FE_HAS_CARRIER; + + if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */ + *stat |= FE_HAS_SYNC; + + if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */ + *stat |= FE_HAS_LOCK; + + if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) { + lock = dib8000_read_word(state, 554); /* Viterbi Layer A */ + if (lock & 0x01) + *stat |= FE_HAS_VITERBI; + + lock = dib8000_read_word(state, 555); /* Viterbi Layer B */ + if (lock & 0x01) + *stat |= FE_HAS_VITERBI; + + lock = dib8000_read_word(state, 556); /* Viterbi Layer C */ + if (lock & 0x01) + *stat |= FE_HAS_VITERBI; + } + + return 0; +} + +static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber) +{ + struct dib8000_state *state = fe->demodulator_priv; + *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments + return 0; +} + +static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) +{ + struct dib8000_state *state = fe->demodulator_priv; + *unc = dib8000_read_word(state, 565); // packet error on 13 seg + return 0; +} + +static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend; + u16 val; + + *strength = 0; + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); + if (val > 65535 - *strength) + *strength = 65535; + else + *strength += val; + } + + val = 65535 - dib8000_read_word(state, 390); + if (val > 65535 - *strength) + *strength = 65535; + else + *strength += val; + return 0; +} + +static u32 dib8000_get_snr(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + u32 n, s, exp; + u16 val; + + val = dib8000_read_word(state, 542); + n = (val >> 6) & 0xff; + exp = (val & 0x3f); + if ((exp & 0x20) != 0) + exp -= 0x40; + n <<= exp+16; + + val = dib8000_read_word(state, 543); + s = (val >> 6) & 0xff; + exp = (val & 0x3f); + if ((exp & 0x20) != 0) + exp -= 0x40; + s <<= exp+16; + + if (n > 0) { + u32 t = (s/n) << 16; + return t + ((s << 16) - n*t) / n; + } + return 0xffffffff; +} + +static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend; + u32 snr_master; + + snr_master = dib8000_get_snr(fe); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + snr_master += dib8000_get_snr(state->fe[index_frontend]); + + if (snr_master != 0) { + snr_master = 10*intlog10(snr_master>>16); + *snr = snr_master / ((1 << 24) / 10); + } + else + *snr = 0; + + return 0; +} + +int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend = 1; + + while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) + index_frontend++; + if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { + dprintk("set slave fe %p to index %i", fe_slave, index_frontend); + state->fe[index_frontend] = fe_slave; + return 0; + } + + dprintk("too many slave frontend"); + return -ENOMEM; +} +EXPORT_SYMBOL(dib8000_set_slave_frontend); + +int dib8000_remove_slave_frontend(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend = 1; + + while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) + index_frontend++; + if (index_frontend != 1) { + dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1); + state->fe[index_frontend] = NULL; + return 0; + } + + dprintk("no frontend to be removed"); + return -ENODEV; +} +EXPORT_SYMBOL(dib8000_remove_slave_frontend); + +struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +{ + struct dib8000_state *state = fe->demodulator_priv; + + if (slave_index >= MAX_NUMBER_OF_FRONTENDS) + return NULL; + return state->fe[slave_index]; +} +EXPORT_SYMBOL(dib8000_get_slave_frontend); + + +int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +{ + int k = 0, ret = 0; + u8 new_addr = 0; + struct i2c_device client = {.adap = host }; + + client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); + if (!client.i2c_write_buffer) { + dprintk("%s: not enough memory", __func__); + return -ENOMEM; + } + client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); + if (!client.i2c_read_buffer) { + dprintk("%s: not enough memory", __func__); + ret = -ENOMEM; + goto error_memory; + } + + for (k = no_of_demods - 1; k >= 0; k--) { + /* designated i2c address */ + new_addr = first_addr + (k << 1); + + client.addr = new_addr; + dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ + if (dib8000_identify(&client) == 0) { + dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ + client.addr = default_addr; + if (dib8000_identify(&client) == 0) { + dprintk("#%d: not identified", k); + ret = -EINVAL; + goto error; + } + } + + /* start diversity to pull_down div_str - just for i2c-enumeration */ + dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6)); + + /* set new i2c address and force divstart */ + dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2); + client.addr = new_addr; + dib8000_identify(&client); + + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); + } + + for (k = 0; k < no_of_demods; k++) { + new_addr = first_addr | (k << 1); + client.addr = new_addr; + + // unforce divstr + dib8000_i2c_write16(&client, 1285, new_addr << 2); + + /* deactivate div - it was just for i2c-enumeration */ + dib8000_i2c_write16(&client, 1286, 0); + } + +error: + kfree(client.i2c_read_buffer); +error_memory: + kfree(client.i2c_write_buffer); + + return ret; +} + +EXPORT_SYMBOL(dib8000_i2c_enumeration); +static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + tune->step_size = 0; + tune->max_drift = 0; + return 0; +} + +static void dib8000_release(struct dvb_frontend *fe) +{ + struct dib8000_state *st = fe->demodulator_priv; + u8 index_frontend; + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) + dvb_frontend_detach(st->fe[index_frontend]); + + dibx000_exit_i2c_master(&st->i2c_master); + kfree(st->fe[0]); + kfree(st); +} + +struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) +{ + struct dib8000_state *st = fe->demodulator_priv; + return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); +} + +EXPORT_SYMBOL(dib8000_get_i2c_master); + +int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + struct dib8000_state *st = fe->demodulator_priv; + u16 val = dib8000_read_word(st, 299) & 0xffef; + val |= (onoff & 0x1) << 4; + + dprintk("pid filter enabled %d", onoff); + return dib8000_write_word(st, 299, val); +} +EXPORT_SYMBOL(dib8000_pid_filter_ctrl); + +int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + struct dib8000_state *st = fe->demodulator_priv; + dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); + return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); +} +EXPORT_SYMBOL(dib8000_pid_filter); + +static const struct dvb_frontend_ops dib8000_ops = { + .info = { + .name = "DiBcom 8000 ISDB-T", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, + }, + + .release = dib8000_release, + + .init = dib8000_wakeup, + .sleep = dib8000_sleep, + + .set_frontend = dib8000_set_frontend, + .get_tune_settings = dib8000_fe_get_tune_settings, + .get_frontend = dib8000_get_frontend, + + .read_status = dib8000_read_status, + .read_ber = dib8000_read_ber, + .read_signal_strength = dib8000_read_signal_strength, + .read_snr = dib8000_read_snr, + .read_ucblocks = dib8000_read_unc_blocks, +}; + +struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) +{ + struct dvb_frontend *fe; + struct dib8000_state *state; + + dprintk("dib8000_attach"); + + state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL); + if (state == NULL) + return NULL; + fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); + if (fe == NULL) + goto error; + + memcpy(&state->cfg, cfg, sizeof(struct dib8000_config)); + state->i2c.adap = i2c_adap; + state->i2c.addr = i2c_addr; + state->i2c.i2c_write_buffer = state->i2c_write_buffer; + state->i2c.i2c_read_buffer = state->i2c_read_buffer; + state->gpio_val = cfg->gpio_val; + state->gpio_dir = cfg->gpio_dir; + + /* Ensure the output mode remains at the previous default if it's + * not specifically set by the caller. + */ + if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) + state->cfg.output_mode = OUTMODE_MPEG2_FIFO; + + state->fe[0] = fe; + fe->demodulator_priv = state; + memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops)); + + state->timf_default = cfg->pll->timf; + + if (dib8000_identify(&state->i2c) == 0) + goto error; + + dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); + + dib8000_reset(fe); + + dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */ + + return fe; + + error: + kfree(state); + return NULL; +} + +EXPORT_SYMBOL(dib8000_attach); + +MODULE_AUTHOR("Olivier Grenie "); +MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib8000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib8000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib8000.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib8000.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,136 @@ +#ifndef DIB8000_H +#define DIB8000_H + +#include "dibx000_common.h" + +struct dib8000_config { + u8 output_mpeg2_in_188_bytes; + u8 hostbus_diversity; + u8 tuner_is_baseband; + int (*update_lna) (struct dvb_frontend *, u16 agc_global); + + u8 agc_config_count; + struct dibx000_agc_config *agc; + struct dibx000_bandwidth_config *pll; + +#define DIB8000_GPIO_DEFAULT_DIRECTIONS 0xffff + u16 gpio_dir; +#define DIB8000_GPIO_DEFAULT_VALUES 0x0000 + u16 gpio_val; +#define DIB8000_GPIO_PWM_POS0(v) ((v & 0xf) << 12) +#define DIB8000_GPIO_PWM_POS1(v) ((v & 0xf) << 8 ) +#define DIB8000_GPIO_PWM_POS2(v) ((v & 0xf) << 4 ) +#define DIB8000_GPIO_PWM_POS3(v) (v & 0xf) +#define DIB8000_GPIO_DEFAULT_PWM_POS 0xffff + u16 gpio_pwm_pos; + u16 pwm_freq_div; + + void (*agc_control) (struct dvb_frontend *, u8 before); + + u16 drives; + u16 diversity_delay; + u8 div_cfg; + u8 output_mode; + u8 refclksel; +}; + +#define DEFAULT_DIB8000_I2C_ADDRESS 18 + +#if defined(CONFIG_DVB_DIB8000) || (defined(CONFIG_DVB_DIB8000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg); +extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); + +extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); + +extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); +extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); +extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff); +extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); +extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); +extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe); +extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe); +extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode); +extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); +extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe); +extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); +#else +static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return CT_SHUTDOWN; +} +static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} +static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} +static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +int dib8000_remove_slave_frontend(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib9000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib9000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib9000.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib9000.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,2403 @@ +/* + * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family. + * + * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#include +#include +#include + +#include "dvb_math.h" +#include "dvb_frontend.h" + +#include "dib9000.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB9000: "); printk(args); printk("\n"); } } while (0) +#define MAX_NUMBER_OF_FRONTENDS 6 + +struct i2c_device { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + u8 *i2c_read_buffer; + u8 *i2c_write_buffer; +}; + +/* lock */ +#define DIB_LOCK struct mutex +#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0) +#define DibReleaseLock(lock) mutex_unlock(lock) +#define DibInitLock(lock) mutex_init(lock) +#define DibFreeLock(lock) + +struct dib9000_state { + struct i2c_device i2c; + + struct dibx000_i2c_master i2c_master; + struct i2c_adapter tuner_adap; + struct i2c_adapter component_bus; + + u16 revision; + u8 reg_offs; + + enum frontend_tune_state tune_state; + u32 status; + struct dvb_frontend_parametersContext channel_status; + + u8 fe_id; + +#define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff + u16 gpio_dir; +#define DIB9000_GPIO_DEFAULT_VALUES 0x0000 + u16 gpio_val; +#define DIB9000_GPIO_DEFAULT_PWM_POS 0xffff + u16 gpio_pwm_pos; + + union { /* common for all chips */ + struct { + u8 mobile_mode:1; + } host; + + struct { + struct dib9000_fe_memory_map { + u16 addr; + u16 size; + } fe_mm[18]; + u8 memcmd; + + DIB_LOCK mbx_if_lock; /* to protect read/write operations */ + DIB_LOCK mbx_lock; /* to protect the whole mailbox handling */ + + DIB_LOCK mem_lock; /* to protect the memory accesses */ + DIB_LOCK mem_mbx_lock; /* to protect the memory-based mailbox */ + +#define MBX_MAX_WORDS (256 - 200 - 2) +#define DIB9000_MSG_CACHE_SIZE 2 + u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS]; + u8 fw_is_running; + } risc; + } platform; + + union { /* common for all platforms */ + struct { + struct dib9000_config cfg; + } d9; + } chip; + + struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; + u16 component_bus_speed; + + /* for the I2C transfer */ + struct i2c_msg msg[2]; + u8 i2c_write_buffer[255]; + u8 i2c_read_buffer[255]; +}; + +static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +enum dib9000_power_mode { + DIB9000_POWER_ALL = 0, + + DIB9000_POWER_NO, + DIB9000_POWER_INTERF_ANALOG_AGC, + DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD, + DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD, + DIB9000_POWER_INTERFACE_ONLY, +}; + +enum dib9000_out_messages { + OUT_MSG_HBM_ACK, + OUT_MSG_HOST_BUF_FAIL, + OUT_MSG_REQ_VERSION, + OUT_MSG_BRIDGE_I2C_W, + OUT_MSG_BRIDGE_I2C_R, + OUT_MSG_BRIDGE_APB_W, + OUT_MSG_BRIDGE_APB_R, + OUT_MSG_SCAN_CHANNEL, + OUT_MSG_MONIT_DEMOD, + OUT_MSG_CONF_GPIO, + OUT_MSG_DEBUG_HELP, + OUT_MSG_SUBBAND_SEL, + OUT_MSG_ENABLE_TIME_SLICE, + OUT_MSG_FE_FW_DL, + OUT_MSG_FE_CHANNEL_SEARCH, + OUT_MSG_FE_CHANNEL_TUNE, + OUT_MSG_FE_SLEEP, + OUT_MSG_FE_SYNC, + OUT_MSG_CTL_MONIT, + + OUT_MSG_CONF_SVC, + OUT_MSG_SET_HBM, + OUT_MSG_INIT_DEMOD, + OUT_MSG_ENABLE_DIVERSITY, + OUT_MSG_SET_OUTPUT_MODE, + OUT_MSG_SET_PRIORITARY_CHANNEL, + OUT_MSG_ACK_FRG, + OUT_MSG_INIT_PMU, +}; + +enum dib9000_in_messages { + IN_MSG_DATA, + IN_MSG_FRAME_INFO, + IN_MSG_CTL_MONIT, + IN_MSG_ACK_FREE_ITEM, + IN_MSG_DEBUG_BUF, + IN_MSG_MPE_MONITOR, + IN_MSG_RAWTS_MONITOR, + IN_MSG_END_BRIDGE_I2C_RW, + IN_MSG_END_BRIDGE_APB_RW, + IN_MSG_VERSION, + IN_MSG_END_OF_SCAN, + IN_MSG_MONIT_DEMOD, + IN_MSG_ERROR, + IN_MSG_FE_FW_DL_DONE, + IN_MSG_EVENT, + IN_MSG_ACK_CHANGE_SVC, + IN_MSG_HBM_PROF, +}; + +/* memory_access requests */ +#define FE_MM_W_CHANNEL 0 +#define FE_MM_W_FE_INFO 1 +#define FE_MM_RW_SYNC 2 + +#define FE_SYNC_CHANNEL 1 +#define FE_SYNC_W_GENERIC_MONIT 2 +#define FE_SYNC_COMPONENT_ACCESS 3 + +#define FE_MM_R_CHANNEL_SEARCH_STATE 3 +#define FE_MM_R_CHANNEL_UNION_CONTEXT 4 +#define FE_MM_R_FE_INFO 5 +#define FE_MM_R_FE_MONITOR 6 + +#define FE_MM_W_CHANNEL_HEAD 7 +#define FE_MM_W_CHANNEL_UNION 8 +#define FE_MM_W_CHANNEL_CONTEXT 9 +#define FE_MM_R_CHANNEL_UNION 10 +#define FE_MM_R_CHANNEL_CONTEXT 11 +#define FE_MM_R_CHANNEL_TUNE_STATE 12 + +#define FE_MM_R_GENERIC_MONITORING_SIZE 13 +#define FE_MM_W_GENERIC_MONITORING 14 +#define FE_MM_R_GENERIC_MONITORING 15 + +#define FE_MM_W_COMPONENT_ACCESS 16 +#define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17 +static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len); +static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len); + +static u16 to_fw_output_mode(u16 mode) +{ + switch (mode) { + case OUTMODE_HIGH_Z: + return 0; + case OUTMODE_MPEG2_PAR_GATED_CLK: + return 4; + case OUTMODE_MPEG2_PAR_CONT_CLK: + return 8; + case OUTMODE_MPEG2_SERIAL: + return 16; + case OUTMODE_DIVERSITY: + return 128; + case OUTMODE_MPEG2_FIFO: + return 2; + case OUTMODE_ANALOG_ADC: + return 1; + default: + return 0; + } +} + +static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32 len, u16 attribute) +{ + u32 chunk_size = 126; + u32 l; + int ret; + + if (state->platform.risc.fw_is_running && (reg < 1024)) + return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len); + + memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); + state->msg[0].addr = state->i2c.i2c_addr >> 1; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = 2; + state->msg[1].addr = state->i2c.i2c_addr >> 1; + state->msg[1].flags = I2C_M_RD; + state->msg[1].buf = b; + state->msg[1].len = len; + + state->i2c_write_buffer[0] = reg >> 8; + state->i2c_write_buffer[1] = reg & 0xff; + + if (attribute & DATA_BUS_ACCESS_MODE_8BIT) + state->i2c_write_buffer[0] |= (1 << 5); + if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) + state->i2c_write_buffer[0] |= (1 << 4); + + do { + l = len < chunk_size ? len : chunk_size; + state->msg[1].len = l; + state->msg[1].buf = b; + ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0; + if (ret != 0) { + dprintk("i2c read error on %d", reg); + return -EREMOTEIO; + } + + b += l; + len -= l; + + if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) + reg += l / 2; + } while ((ret == 0) && len); + + return 0; +} + +static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg) +{ + struct i2c_msg msg[2] = { + {.addr = i2c->i2c_addr >> 1, .flags = 0, + .buf = i2c->i2c_write_buffer, .len = 2}, + {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, + .buf = i2c->i2c_read_buffer, .len = 2}, + }; + + i2c->i2c_write_buffer[0] = reg >> 8; + i2c->i2c_write_buffer[1] = reg & 0xff; + + if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) { + dprintk("read register %x error", reg); + return 0; + } + + return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1]; +} + +static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg) +{ + if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0) + return 0; + return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; +} + +static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute) +{ + if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, + attribute) != 0) + return 0; + return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; +} + +#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) + +static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute) +{ + u32 chunk_size = 126; + u32 l; + int ret; + + if (state->platform.risc.fw_is_running && (reg < 1024)) { + if (dib9000_risc_apb_access_write + (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0) + return -EINVAL; + return 0; + } + + memset(&state->msg[0], 0, sizeof(struct i2c_msg)); + state->msg[0].addr = state->i2c.i2c_addr >> 1; + state->msg[0].flags = 0; + state->msg[0].buf = state->i2c_write_buffer; + state->msg[0].len = len + 2; + + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; + state->i2c_write_buffer[1] = (reg) & 0xff; + + if (attribute & DATA_BUS_ACCESS_MODE_8BIT) + state->i2c_write_buffer[0] |= (1 << 5); + if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) + state->i2c_write_buffer[0] |= (1 << 4); + + do { + l = len < chunk_size ? len : chunk_size; + state->msg[0].len = l + 2; + memcpy(&state->i2c_write_buffer[2], buf, l); + + ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + + buf += l; + len -= l; + + if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) + reg += l / 2; + } while ((ret == 0) && len); + + return ret; +} + +static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) +{ + struct i2c_msg msg = { + .addr = i2c->i2c_addr >> 1, .flags = 0, + .buf = i2c->i2c_write_buffer, .len = 4 + }; + + i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff; + i2c->i2c_write_buffer[1] = reg & 0xff; + i2c->i2c_write_buffer[2] = (val >> 8) & 0xff; + i2c->i2c_write_buffer[3] = val & 0xff; + + return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; +} + +static inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val) +{ + u8 b[2] = { val >> 8, val & 0xff }; + return dib9000_write16_attr(state, reg, b, 2, 0); +} + +static inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute) +{ + u8 b[2] = { val >> 8, val & 0xff }; + return dib9000_write16_attr(state, reg, b, 2, attribute); +} + +#define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0) +#define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) +#define dib9000_write16_noinc_attr(state, reg, buf, len, attribute) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | (attribute)) + +#define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0) +#define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0) + +#define MAC_IRQ (1 << 1) +#define IRQ_POL_MSK (1 << 4) + +#define dib9000_risc_mem_read_chunks(state, b, len) dib9000_read16_attr(state, 1063, b, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) +#define dib9000_risc_mem_write_chunks(state, buf, len) dib9000_write16_attr(state, 1063, buf, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) + +static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading) +{ + u8 b[14] = { 0 }; + +/* dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */ +/* b[0] = 0 << 7; */ + b[1] = 1; + +/* b[2] = 0; */ +/* b[3] = 0; */ + b[4] = (u8) (addr >> 8); + b[5] = (u8) (addr & 0xff); + +/* b[10] = 0; */ +/* b[11] = 0; */ + b[12] = (u8) (addr >> 8); + b[13] = (u8) (addr & 0xff); + + addr += len; +/* b[6] = 0; */ +/* b[7] = 0; */ + b[8] = (u8) (addr >> 8); + b[9] = (u8) (addr & 0xff); + + dib9000_write(state, 1056, b, 14); + if (reading) + dib9000_write_word(state, 1056, (1 << 15) | 1); + state->platform.risc.memcmd = -1; /* if it was called directly reset it - to force a future setup-call to set it */ +} + +static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd) +{ + struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f]; + /* decide whether we need to "refresh" the memory controller */ + if (state->platform.risc.memcmd == cmd && /* same command */ + !(cmd & 0x80 && m->size < 67)) /* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */ + return; + dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80); + state->platform.risc.memcmd = cmd; +} + +static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len) +{ + if (!state->platform.risc.fw_is_running) + return -EIO; + + DibAcquireLock(&state->platform.risc.mem_lock); + dib9000_risc_mem_setup(state, cmd | 0x80); + dib9000_risc_mem_read_chunks(state, b, len); + DibReleaseLock(&state->platform.risc.mem_lock); + return 0; +} + +static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b) +{ + struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd]; + if (!state->platform.risc.fw_is_running) + return -EIO; + + DibAcquireLock(&state->platform.risc.mem_lock); + dib9000_risc_mem_setup(state, cmd); + dib9000_risc_mem_write_chunks(state, b, m->size); + DibReleaseLock(&state->platform.risc.mem_lock); + return 0; +} + +static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len) +{ + u16 offs; + + if (risc_id == 1) + offs = 16; + else + offs = 0; + + /* config crtl reg */ + dib9000_write_word(state, 1024 + offs, 0x000f); + dib9000_write_word(state, 1025 + offs, 0); + dib9000_write_word(state, 1031 + offs, key); + + dprintk("going to download %dB of microcode", len); + if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) { + dprintk("error while downloading microcode for RISC %c", 'A' + risc_id); + return -EIO; + } + + dprintk("Microcode for RISC %c loaded", 'A' + risc_id); + + return 0; +} + +static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id) +{ + u16 mbox_offs; + u16 reset_reg; + u16 tries = 1000; + + if (risc_id == 1) + mbox_offs = 16; + else + mbox_offs = 0; + + /* Reset mailbox */ + dib9000_write_word(state, 1027 + mbox_offs, 0x8000); + + /* Read reset status */ + do { + reset_reg = dib9000_read_word(state, 1027 + mbox_offs); + msleep(100); + } while ((reset_reg & 0x8000) && --tries); + + if (reset_reg & 0x8000) { + dprintk("MBX: init ERROR, no response from RISC %c", 'A' + risc_id); + return -EIO; + } + dprintk("MBX: initialized"); + return 0; +} + +#define MAX_MAILBOX_TRY 100 +static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr) +{ + u8 *d, b[2]; + u16 tmp; + u16 size; + u32 i; + int ret = 0; + + if (!state->platform.risc.fw_is_running) + return -EINVAL; + + DibAcquireLock(&state->platform.risc.mbx_if_lock); + tmp = MAX_MAILBOX_TRY; + do { + size = dib9000_read_word_attr(state, 1043, attr) & 0xff; + if ((size + len + 1) > MBX_MAX_WORDS && --tmp) { + dprintk("MBX: RISC mbx full, retrying"); + msleep(100); + } else + break; + } while (1); + + /*dprintk( "MBX: size: %d", size); */ + + if (tmp == 0) { + ret = -EINVAL; + goto out; + } +#ifdef DUMP_MSG + dprintk("--> %02x %d ", id, len + 1); + for (i = 0; i < len; i++) + dprintk("%04x ", data[i]); + dprintk("\n"); +#endif + + /* byte-order conversion - works on big (where it is not necessary) or little endian */ + d = (u8 *) data; + for (i = 0; i < len; i++) { + tmp = data[i]; + *d++ = tmp >> 8; + *d++ = tmp & 0xff; + } + + /* write msg */ + b[0] = id; + b[1] = len + 1; + if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) { + ret = -EIO; + goto out; + } + + /* update register nb_mes_in_RX */ + ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr); + +out: + DibReleaseLock(&state->platform.risc.mbx_if_lock); + + return ret; +} + +static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr) +{ +#ifdef DUMP_MSG + u16 *d = data; +#endif + + u16 tmp, i; + u8 size; + u8 mc_base; + + if (!state->platform.risc.fw_is_running) + return 0; + + DibAcquireLock(&state->platform.risc.mbx_if_lock); + if (risc_id == 1) + mc_base = 16; + else + mc_base = 0; + + /* Length and type in the first word */ + *data = dib9000_read_word_attr(state, 1029 + mc_base, attr); + + size = *data & 0xff; + if (size <= MBX_MAX_WORDS) { + data++; + size--; /* Initial word already read */ + + dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr); + + /* to word conversion */ + for (i = 0; i < size; i++) { + tmp = *data; + *data = (tmp >> 8) | (tmp << 8); + data++; + } + +#ifdef DUMP_MSG + dprintk("<-- "); + for (i = 0; i < size + 1; i++) + dprintk("%04x ", d[i]); + dprintk("\n"); +#endif + } else { + dprintk("MBX: message is too big for message cache (%d), flushing message", size); + size--; /* Initial word already read */ + while (size--) + dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr); + } + /* Update register nb_mes_in_TX */ + dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr); + + DibReleaseLock(&state->platform.risc.mbx_if_lock); + + return size + 1; +} + +static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size) +{ + u32 ts = data[1] << 16 | data[0]; + char *b = (char *)&data[2]; + + b[2 * (size - 2) - 1] = '\0'; /* Bullet proof the buffer */ + if (*b == '~') { + b++; + dprintk(b); + } else + dprintk("RISC%d: %d.%04d %s", state->fe_id, ts / 10000, ts % 10000, *b ? b : ""); + return 1; +} + +static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr) +{ + int i; + u8 size; + u16 *block; + /* find a free slot */ + for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { + block = state->platform.risc.message_cache[i]; + if (*block == 0) { + size = dib9000_mbx_read(state, block, 1, attr); + +/* dprintk( "MBX: fetched %04x message to cache", *block); */ + + switch (*block >> 8) { + case IN_MSG_DEBUG_BUF: + dib9000_risc_debug_buf(state, block + 1, size); /* debug-messages are going to be printed right away */ + *block = 0; /* free the block */ + break; +#if 0 + case IN_MSG_DATA: /* FE-TRACE */ + dib9000_risc_data_process(state, block + 1, size); + *block = 0; + break; +#endif + default: + break; + } + + return 1; + } + } + dprintk("MBX: no free cache-slot found for new message..."); + return -1; +} + +static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr) +{ + if (risc_id == 0) + return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f; /* 5 bit field */ + else + return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f; /* 7 bit field */ +} + +static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) +{ + int ret = 0; + u16 tmp; + + if (!state->platform.risc.fw_is_running) + return -1; + + DibAcquireLock(&state->platform.risc.mbx_lock); + + if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ + ret = dib9000_mbx_fetch_to_cache(state, attr); + + tmp = dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ +/* if (tmp) */ +/* dprintk( "cleared IRQ: %x", tmp); */ + DibReleaseLock(&state->platform.risc.mbx_lock); + + return ret; +} + +static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr) +{ + u8 i; + u16 *block; + u16 timeout = 30; + + *msg = 0; + do { + /* dib9000_mbx_get_from_cache(); */ + for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { + block = state->platform.risc.message_cache[i]; + if ((*block >> 8) == id) { + *size = (*block & 0xff) - 1; + memcpy(msg, block + 1, (*size) * 2); + *block = 0; /* free the block */ + i = 0; /* signal that we found a message */ + break; + } + } + + if (i == 0) + break; + + if (dib9000_mbx_process(state, attr) == -1) /* try to fetch one message - if any */ + return -1; + + } while (--timeout); + + if (timeout == 0) { + dprintk("waiting for message %d timed out", id); + return -1; + } + + return i == 0; +} + +static int dib9000_risc_check_version(struct dib9000_state *state) +{ + u8 r[4]; + u8 size; + u16 fw_version = 0; + + if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0) + return -EIO; + + if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0) + return -EIO; + + fw_version = (r[0] << 8) | r[1]; + dprintk("RISC: ver: %d.%02d (IC: %d)", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]); + + if ((fw_version >> 10) != 7) + return -EINVAL; + + switch (fw_version & 0x3ff) { + case 11: + case 12: + case 14: + case 15: + case 16: + case 17: + break; + default: + dprintk("RISC: invalid firmware version"); + return -EINVAL; + } + + dprintk("RISC: valid firmware version"); + return 0; +} + +static int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB) +{ + /* Reconfig pool mac ram */ + dib9000_write_word(state, 1225, 0x02); /* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */ + dib9000_write_word(state, 1226, 0x05); + + /* Toggles IP crypto to Host APB interface. */ + dib9000_write_word(state, 1542, 1); + + /* Set jump and no jump in the dma box */ + dib9000_write_word(state, 1074, 0); + dib9000_write_word(state, 1075, 0); + + /* Set MAC as APB Master. */ + dib9000_write_word(state, 1237, 0); + + /* Reset the RISCs */ + if (codeA != NULL) + dib9000_write_word(state, 1024, 2); + else + dib9000_write_word(state, 1024, 15); + if (codeB != NULL) + dib9000_write_word(state, 1040, 2); + + if (codeA != NULL) + dib9000_firmware_download(state, 0, 0x1234, codeA, lenA); + if (codeB != NULL) + dib9000_firmware_download(state, 1, 0x1234, codeB, lenB); + + /* Run the RISCs */ + if (codeA != NULL) + dib9000_write_word(state, 1024, 0); + if (codeB != NULL) + dib9000_write_word(state, 1040, 0); + + if (codeA != NULL) + if (dib9000_mbx_host_init(state, 0) != 0) + return -EIO; + if (codeB != NULL) + if (dib9000_mbx_host_init(state, 1) != 0) + return -EIO; + + msleep(100); + state->platform.risc.fw_is_running = 1; + + if (dib9000_risc_check_version(state) != 0) + return -EINVAL; + + state->platform.risc.memcmd = 0xff; + return 0; +} + +static u16 dib9000_identify(struct i2c_device *client) +{ + u16 value; + + value = dib9000_i2c_read16(client, 896); + if (value != 0x01b3) { + dprintk("wrong Vendor ID (0x%x)", value); + return 0; + } + + value = dib9000_i2c_read16(client, 897); + if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) { + dprintk("wrong Device ID (0x%x)", value); + return 0; + } + + /* protect this driver to be used with 7000PC */ + if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) { + dprintk("this driver does not work with DiB7000PC"); + return 0; + } + + switch (value) { + case 0x4000: + dprintk("found DiB7000MA/PA/MB/PB"); + break; + case 0x4001: + dprintk("found DiB7000HC"); + break; + case 0x4002: + dprintk("found DiB7000MC"); + break; + case 0x4003: + dprintk("found DiB9000A"); + break; + case 0x4004: + dprintk("found DiB9000H"); + break; + case 0x4005: + dprintk("found DiB9000M"); + break; + } + + return value; +} + +static void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode) +{ + /* by default everything is going to be powered off */ + u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906; + u8 offset; + + if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005) + offset = 1; + else + offset = 0; + + reg_906 = dib9000_read_word(state, 906 + offset) | 0x3; /* keep settings for RISC */ + + /* now, depending on the requested mode, we power on */ + switch (mode) { + /* power up everything in the demod */ + case DIB9000_POWER_ALL: + reg_903 = 0x0000; + reg_904 = 0x0000; + reg_905 = 0x0000; + reg_906 = 0x0000; + break; + + /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */ + case DIB9000_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */ + reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)); + break; + + case DIB9000_POWER_INTERF_ANALOG_AGC: + reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10)); + reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2)); + reg_906 &= ~((1 << 0)); + break; + + case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD: + reg_903 = 0x0000; + reg_904 = 0x801f; + reg_905 = 0x0000; + reg_906 &= ~((1 << 0)); + break; + + case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD: + reg_903 = 0x0000; + reg_904 = 0x8000; + reg_905 = 0x010b; + reg_906 &= ~((1 << 0)); + break; + default: + case DIB9000_POWER_NO: + break; + } + + /* always power down unused parts */ + if (!state->platform.host.mobile_mode) + reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); + + /* P_sdio_select_clk = 0 on MC and after */ + if (state->revision != 0x4000) + reg_906 <<= 1; + + dib9000_write_word(state, 903 + offset, reg_903); + dib9000_write_word(state, 904 + offset, reg_904); + dib9000_write_word(state, 905 + offset, reg_905); + dib9000_write_word(state, 906 + offset, reg_906); +} + +static int dib9000_fw_reset(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + + dib9000_write_word(state, 1817, 0x0003); + + dib9000_write_word(state, 1227, 1); + dib9000_write_word(state, 1227, 0); + + switch ((state->revision = dib9000_identify(&state->i2c))) { + case 0x4003: + case 0x4004: + case 0x4005: + state->reg_offs = 1; + break; + default: + return -EINVAL; + } + + /* reset the i2c-master to use the host interface */ + dibx000_reset_i2c_master(&state->i2c_master); + + dib9000_set_power_mode(state, DIB9000_POWER_ALL); + + /* unforce divstr regardless whether i2c enumeration was done or not */ + dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1)); + dib9000_write_word(state, 1796, 0); + dib9000_write_word(state, 1805, 0x805); + + /* restart all parts */ + dib9000_write_word(state, 898, 0xffff); + dib9000_write_word(state, 899, 0xffff); + dib9000_write_word(state, 900, 0x0001); + dib9000_write_word(state, 901, 0xff19); + dib9000_write_word(state, 902, 0x003c); + + dib9000_write_word(state, 898, 0); + dib9000_write_word(state, 899, 0); + dib9000_write_word(state, 900, 0); + dib9000_write_word(state, 901, 0); + dib9000_write_word(state, 902, 0); + + dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives); + + dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY); + + return 0; +} + +static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len) +{ + u16 mb[10]; + u8 i, s; + + if (address >= 1024 || !state->platform.risc.fw_is_running) + return -EINVAL; + + /* dprintk( "APB access thru rd fw %d %x", address, attribute); */ + + mb[0] = (u16) address; + mb[1] = len / 2; + dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute); + switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) { + case 1: + s--; + for (i = 0; i < s; i++) { + b[i * 2] = (mb[i + 1] >> 8) & 0xff; + b[i * 2 + 1] = (mb[i + 1]) & 0xff; + } + return 0; + default: + return -EIO; + } + return -EIO; +} + +static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len) +{ + u16 mb[10]; + u8 s, i; + + if (address >= 1024 || !state->platform.risc.fw_is_running) + return -EINVAL; + + /* dprintk( "APB access thru wr fw %d %x", address, attribute); */ + + mb[0] = (unsigned short)address; + for (i = 0; i < len && i < 20; i += 2) + mb[1 + (i / 2)] = (b[i] << 8 | b[i + 1]); + + dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, 1 + len / 2, attribute); + return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL; +} + +static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i) +{ + u8 index_loop = 10; + + if (!state->platform.risc.fw_is_running) + return 0; + dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i); + do { + dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1); + } while (state->i2c_read_buffer[0] && index_loop--); + + if (index_loop > 0) + return 0; + return -EIO; +} + +static int dib9000_fw_init(struct dib9000_state *state) +{ + struct dibGPIOFunction *f; + u16 b[40] = { 0 }; + u8 i; + u8 size; + + if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0) + return -EIO; + + /* initialize the firmware */ + for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) { + f = &state->chip.d9.cfg.gpio_function[i]; + if (f->mask) { + switch (f->function) { + case BOARD_GPIO_FUNCTION_COMPONENT_ON: + b[0] = (u16) f->mask; + b[1] = (u16) f->direction; + b[2] = (u16) f->value; + break; + case BOARD_GPIO_FUNCTION_COMPONENT_OFF: + b[3] = (u16) f->mask; + b[4] = (u16) f->direction; + b[5] = (u16) f->value; + break; + } + } + } + if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0) + return -EIO; + + /* subband */ + b[0] = state->chip.d9.cfg.subband.size; /* type == 0 -> GPIO - PWM not yet supported */ + for (i = 0; i < state->chip.d9.cfg.subband.size; i++) { + b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz; + b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask; + b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction; + b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value; + } + b[1 + i * 4] = 0; /* fe_id */ + if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0) + return -EIO; + + /* 0 - id, 1 - no_of_frontends */ + b[0] = (0 << 8) | 1; + /* 0 = i2c-address demod, 0 = tuner */ + b[1] = (0 << 8) | (0); + b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff); + b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff); + b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff); + b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff); + b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff); + b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff); + b[29] = state->chip.d9.cfg.if_drives; + if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0) + return -EIO; + + if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0) + return -EIO; + + if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0) + return -EIO; + + if (size > ARRAY_SIZE(b)) { + dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size, + (int)ARRAY_SIZE(b)); + return -EINVAL; + } + + for (i = 0; i < size; i += 2) { + state->platform.risc.fe_mm[i / 2].addr = b[i + 0]; + state->platform.risc.fe_mm[i / 2].size = b[i + 1]; + } + + return 0; +} + +static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_frontend_parameters *ch) +{ + u8 b[9]; + u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000; + if (state->fe_id % 2) + freq += 101; + + b[0] = (u8) ((freq >> 0) & 0xff); + b[1] = (u8) ((freq >> 8) & 0xff); + b[2] = (u8) ((freq >> 16) & 0xff); + b[3] = (u8) ((freq >> 24) & 0xff); + b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff); + b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff); + b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff); + b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff); + b[8] = 0x80; /* do not wait for CELL ID when doing autosearch */ + if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT) + b[8] |= 1; + dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b); +} + +static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) +{ + struct dib9000_state *state = fe->demodulator_priv; + struct dibDVBTChannel { + s8 spectrum_inversion; + + s8 nfft; + s8 guard; + s8 constellation; + + s8 hrch; + s8 alpha; + s8 code_rate_hp; + s8 code_rate_lp; + s8 select_hp; + + s8 intlv_native; + }; + struct dibDVBTChannel *ch; + int ret = 0; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + goto error; + ret = -EIO; + } + + dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, + state->i2c_read_buffer, sizeof(struct dibDVBTChannel)); + ch = (struct dibDVBTChannel *)state->i2c_read_buffer; + + + switch (ch->spectrum_inversion & 0x7) { + case 1: + state->fe[0]->dtv_property_cache.inversion = INVERSION_ON; + break; + case 0: + state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO; + break; + } + switch (ch->nfft) { + case 0: + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; + break; + case 2: + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K; + break; + case 1: + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; + break; + } + switch (ch->guard) { + case 0: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; + break; + } + switch (ch->constellation) { + case 2: + state->fe[0]->dtv_property_cache.modulation = QAM_64; + break; + case 1: + state->fe[0]->dtv_property_cache.modulation = QAM_16; + break; + case 0: + state->fe[0]->dtv_property_cache.modulation = QPSK; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.modulation = QAM_AUTO; + break; + } + switch (ch->hrch) { + case 0: + state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE; + break; + case 1: + state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO; + break; + } + switch (ch->code_rate_hp) { + case 1: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2; + break; + case 2: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3; + break; + case 3: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4; + break; + case 5: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6; + break; + case 7: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO; + break; + } + switch (ch->code_rate_lp) { + case 1: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2; + break; + case 2: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3; + break; + case 3: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4; + break; + case 5: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6; + break; + case 7: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO; + break; + } + +error: + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + return ret; +} + +static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) +{ + struct dib9000_state *state = fe->demodulator_priv; + struct dibDVBTChannel { + s8 spectrum_inversion; + + s8 nfft; + s8 guard; + s8 constellation; + + s8 hrch; + s8 alpha; + s8 code_rate_hp; + s8 code_rate_lp; + s8 select_hp; + + s8 intlv_native; + }; + struct dibDVBTChannel ch; + + switch (state->fe[0]->dtv_property_cache.inversion) { + case INVERSION_ON: + ch.spectrum_inversion = 1; + break; + case INVERSION_OFF: + ch.spectrum_inversion = 0; + break; + default: + case INVERSION_AUTO: + ch.spectrum_inversion = -1; + break; + } + switch (state->fe[0]->dtv_property_cache.transmission_mode) { + case TRANSMISSION_MODE_2K: + ch.nfft = 0; + break; + case TRANSMISSION_MODE_4K: + ch.nfft = 2; + break; + case TRANSMISSION_MODE_8K: + ch.nfft = 1; + break; + default: + case TRANSMISSION_MODE_AUTO: + ch.nfft = 1; + break; + } + switch (state->fe[0]->dtv_property_cache.guard_interval) { + case GUARD_INTERVAL_1_32: + ch.guard = 0; + break; + case GUARD_INTERVAL_1_16: + ch.guard = 1; + break; + case GUARD_INTERVAL_1_8: + ch.guard = 2; + break; + case GUARD_INTERVAL_1_4: + ch.guard = 3; + break; + default: + case GUARD_INTERVAL_AUTO: + ch.guard = -1; + break; + } + switch (state->fe[0]->dtv_property_cache.modulation) { + case QAM_64: + ch.constellation = 2; + break; + case QAM_16: + ch.constellation = 1; + break; + case QPSK: + ch.constellation = 0; + break; + default: + case QAM_AUTO: + ch.constellation = -1; + break; + } + switch (state->fe[0]->dtv_property_cache.hierarchy) { + case HIERARCHY_NONE: + ch.hrch = 0; + break; + case HIERARCHY_1: + case HIERARCHY_2: + case HIERARCHY_4: + ch.hrch = 1; + break; + default: + case HIERARCHY_AUTO: + ch.hrch = -1; + break; + } + ch.alpha = 1; + switch (state->fe[0]->dtv_property_cache.code_rate_HP) { + case FEC_1_2: + ch.code_rate_hp = 1; + break; + case FEC_2_3: + ch.code_rate_hp = 2; + break; + case FEC_3_4: + ch.code_rate_hp = 3; + break; + case FEC_5_6: + ch.code_rate_hp = 5; + break; + case FEC_7_8: + ch.code_rate_hp = 7; + break; + default: + case FEC_AUTO: + ch.code_rate_hp = -1; + break; + } + switch (state->fe[0]->dtv_property_cache.code_rate_LP) { + case FEC_1_2: + ch.code_rate_lp = 1; + break; + case FEC_2_3: + ch.code_rate_lp = 2; + break; + case FEC_3_4: + ch.code_rate_lp = 3; + break; + case FEC_5_6: + ch.code_rate_lp = 5; + break; + case FEC_7_8: + ch.code_rate_lp = 7; + break; + default: + case FEC_AUTO: + ch.code_rate_lp = -1; + break; + } + ch.select_hp = 1; + ch.intlv_native = 1; + + dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch); + + return 0; +} + +static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib9000_state *state = fe->demodulator_priv; + int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN; + s8 i; + + switch (state->tune_state) { + case CT_DEMOD_START: + dib9000_fw_set_channel_head(state, ch); + + /* write the channel context - a channel is initialized to 0, so it is OK */ + dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info); + dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info); + + if (search) + dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0); + else { + dib9000_fw_set_channel_union(fe, ch); + dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0); + } + state->tune_state = CT_DEMOD_STEP_1; + break; + case CT_DEMOD_STEP_1: + if (search) + dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1); + else + dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1); + i = (s8)state->i2c_read_buffer[0]; + switch (i) { /* something happened */ + case 0: + break; + case -2: /* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */ + if (search) + state->status = FE_STATUS_DEMOD_SUCCESS; + else { + state->tune_state = CT_DEMOD_STOP; + state->status = FE_STATUS_LOCKED; + } + break; + default: + state->status = FE_STATUS_TUNE_FAILED; + state->tune_state = CT_DEMOD_STOP; + break; + } + break; + default: + ret = FE_CALLBACK_TIME_NEVER; + break; + } + + return ret; +} + +static int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 mode = (u16) onoff; + return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1); +} + +static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 outreg, smo_mode; + + dprintk("setting output mode for demod %p to %d", fe, mode); + + switch (mode) { + case OUTMODE_MPEG2_PAR_GATED_CLK: + outreg = (1 << 10); /* 0x0400 */ + break; + case OUTMODE_MPEG2_PAR_CONT_CLK: + outreg = (1 << 10) | (1 << 6); /* 0x0440 */ + break; + case OUTMODE_MPEG2_SERIAL: + outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ + break; + case OUTMODE_DIVERSITY: + outreg = (1 << 10) | (4 << 6); /* 0x0500 */ + break; + case OUTMODE_MPEG2_FIFO: + outreg = (1 << 10) | (5 << 6); + break; + case OUTMODE_HIGH_Z: + outreg = 0; + break; + default: + dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]); + return -EINVAL; + } + + dib9000_write_word(state, 1795, outreg); + + switch (mode) { + case OUTMODE_MPEG2_PAR_GATED_CLK: + case OUTMODE_MPEG2_PAR_CONT_CLK: + case OUTMODE_MPEG2_SERIAL: + case OUTMODE_MPEG2_FIFO: + smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1); + if (state->chip.d9.cfg.output_mpeg2_in_188_bytes) + smo_mode |= (1 << 5); + dib9000_write_word(state, 295, smo_mode); + break; + } + + outreg = to_fw_output_mode(mode); + return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1); +} + +static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib9000_state *state = i2c_get_adapdata(i2c_adap); + u16 i, len, t, index_msg; + + for (index_msg = 0; index_msg < num; index_msg++) { + if (msg[index_msg].flags & I2C_M_RD) { /* read */ + len = msg[index_msg].len; + if (len > 16) + len = 16; + + if (dib9000_read_word(state, 790) != 0) + dprintk("TunerITF: read busy"); + + dib9000_write_word(state, 784, (u16) (msg[index_msg].addr)); + dib9000_write_word(state, 787, (len / 2) - 1); + dib9000_write_word(state, 786, 1); /* start read */ + + i = 1000; + while (dib9000_read_word(state, 790) != (len / 2) && i) + i--; + + if (i == 0) + dprintk("TunerITF: read failed"); + + for (i = 0; i < len; i += 2) { + t = dib9000_read_word(state, 785); + msg[index_msg].buf[i] = (t >> 8) & 0xff; + msg[index_msg].buf[i + 1] = (t) & 0xff; + } + if (dib9000_read_word(state, 790) != 0) + dprintk("TunerITF: read more data than expected"); + } else { + i = 1000; + while (dib9000_read_word(state, 789) && i) + i--; + if (i == 0) + dprintk("TunerITF: write busy"); + + len = msg[index_msg].len; + if (len > 16) + len = 16; + + for (i = 0; i < len; i += 2) + dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]); + dib9000_write_word(state, 784, (u16) msg[index_msg].addr); + dib9000_write_word(state, 787, (len / 2) - 1); + dib9000_write_word(state, 786, 0); /* start write */ + + i = 1000; + while (dib9000_read_word(state, 791) > 0 && i) + i--; + if (i == 0) + dprintk("TunerITF: write failed"); + } + } + return num; +} + +int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed) +{ + struct dib9000_state *state = fe->demodulator_priv; + + state->component_bus_speed = speed; + return 0; +} +EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed); + +static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib9000_state *state = i2c_get_adapdata(i2c_adap); + u8 type = 0; /* I2C */ + u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4; + u16 scl = state->component_bus_speed; /* SCL frequency */ + struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER]; + u8 p[13] = { 0 }; + + p[0] = type; + p[1] = port; + p[2] = msg[0].addr << 1; + + p[3] = (u8) scl & 0xff; /* scl */ + p[4] = (u8) (scl >> 8); + + p[7] = 0; + p[8] = 0; + + p[9] = (u8) (msg[0].len); + p[10] = (u8) (msg[0].len >> 8); + if ((num > 1) && (msg[1].flags & I2C_M_RD)) { + p[11] = (u8) (msg[1].len); + p[12] = (u8) (msg[1].len >> 8); + } else { + p[11] = 0; + p[12] = 0; + } + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + + dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p); + + { /* write-part */ + dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0); + dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len); + } + + /* do the transaction */ + if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) { + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + return 0; + } + + /* read back any possible result */ + if ((num > 1) && (msg[1].flags & I2C_M_RD)) + dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len); + + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + return num; +} + +static u32 dib9000_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dib9000_tuner_algo = { + .master_xfer = dib9000_tuner_xfer, + .functionality = dib9000_i2c_func, +}; + +static struct i2c_algorithm dib9000_component_bus_algo = { + .master_xfer = dib9000_fw_component_bus_xfer, + .functionality = dib9000_i2c_func, +}; + +struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe) +{ + struct dib9000_state *st = fe->demodulator_priv; + return &st->tuner_adap; +} +EXPORT_SYMBOL(dib9000_get_tuner_interface); + +struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) +{ + struct dib9000_state *st = fe->demodulator_priv; + return &st->component_bus; +} +EXPORT_SYMBOL(dib9000_get_component_bus_interface); + +struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) +{ + struct dib9000_state *st = fe->demodulator_priv; + return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); +} +EXPORT_SYMBOL(dib9000_get_i2c_master); + +int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) +{ + struct dib9000_state *st = fe->demodulator_priv; + + st->i2c.i2c_adap = i2c; + return 0; +} +EXPORT_SYMBOL(dib9000_set_i2c_adapter); + +static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val) +{ + st->gpio_dir = dib9000_read_word(st, 773); + st->gpio_dir &= ~(1 << num); /* reset the direction bit */ + st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ + dib9000_write_word(st, 773, st->gpio_dir); + + st->gpio_val = dib9000_read_word(st, 774); + st->gpio_val &= ~(1 << num); /* reset the direction bit */ + st->gpio_val |= (val & 0x01) << num; /* set the new value */ + dib9000_write_word(st, 774, st->gpio_val); + + dprintk("gpio dir: %04x: gpio val: %04x", st->gpio_dir, st->gpio_val); + + return 0; +} + +int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + struct dib9000_state *state = fe->demodulator_priv; + return dib9000_cfg_gpio(state, num, dir, val); +} +EXPORT_SYMBOL(dib9000_set_gpio); + +int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 val = dib9000_read_word(state, 294 + 1) & 0xffef; + val |= (onoff & 0x1) << 4; + + dprintk("PID filter enabled %d", onoff); + return dib9000_write_word(state, 294 + 1, val); +} +EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl); + +int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + struct dib9000_state *state = fe->demodulator_priv; + dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); + return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); +} +EXPORT_SYMBOL(dib9000_fw_pid_filter); + +int dib9000_firmware_post_pll_init(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + return dib9000_fw_init(state); +} +EXPORT_SYMBOL(dib9000_firmware_post_pll_init); + +static void dib9000_release(struct dvb_frontend *demod) +{ + struct dib9000_state *st = demod->demodulator_priv; + u8 index_frontend; + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) + dvb_frontend_detach(st->fe[index_frontend]); + + DibFreeLock(&state->platform.risc.mbx_if_lock); + DibFreeLock(&state->platform.risc.mbx_lock); + DibFreeLock(&state->platform.risc.mem_lock); + DibFreeLock(&state->platform.risc.mem_mbx_lock); + dibx000_exit_i2c_master(&st->i2c_master); + + i2c_del_adapter(&st->tuner_adap); + i2c_del_adapter(&st->component_bus); + kfree(st->fe[0]); + kfree(st); +} + +static int dib9000_wakeup(struct dvb_frontend *fe) +{ + return 0; +} + +static int dib9000_sleep(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend; + int ret; + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); + if (ret < 0) + return ret; + } + return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); +} + +static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend, sub_index_frontend; + fe_status_t stat; + int ret; + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); + if (stat & FE_HAS_SYNC) { + dprintk("TPS lock on the slave%i", index_frontend); + + /* synchronize the cache with the other frontends */ + state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); + for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); + sub_index_frontend++) { + if (sub_index_frontend != index_frontend) { + state->fe[sub_index_frontend]->dtv_property_cache.modulation = + state->fe[index_frontend]->dtv_property_cache.modulation; + state->fe[sub_index_frontend]->dtv_property_cache.inversion = + state->fe[index_frontend]->dtv_property_cache.inversion; + state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = + state->fe[index_frontend]->dtv_property_cache.transmission_mode; + state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = + state->fe[index_frontend]->dtv_property_cache.guard_interval; + state->fe[sub_index_frontend]->dtv_property_cache.hierarchy = + state->fe[index_frontend]->dtv_property_cache.hierarchy; + state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP = + state->fe[index_frontend]->dtv_property_cache.code_rate_HP; + state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP = + state->fe[index_frontend]->dtv_property_cache.code_rate_LP; + state->fe[sub_index_frontend]->dtv_property_cache.rolloff = + state->fe[index_frontend]->dtv_property_cache.rolloff; + } + } + return 0; + } + } + + /* get the channel from master chip */ + ret = dib9000_fw_get_channel(fe, fep); + if (ret != 0) + return ret; + + /* synchronize the cache with the other frontends */ + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; + state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; + state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval; + state->fe[index_frontend]->dtv_property_cache.modulation = fe->dtv_property_cache.modulation; + state->fe[index_frontend]->dtv_property_cache.hierarchy = fe->dtv_property_cache.hierarchy; + state->fe[index_frontend]->dtv_property_cache.code_rate_HP = fe->dtv_property_cache.code_rate_HP; + state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP; + state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff; + } + + return 0; +} + +static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + struct dib9000_state *state = fe->demodulator_priv; + state->tune_state = tune_state; + if (tune_state == CT_DEMOD_START) + state->status = FE_STATUS_TUNE_PENDING; + + return 0; +} + +static u32 dib9000_get_status(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + return state->status; +} + +static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status) +{ + struct dib9000_state *state = fe->demodulator_priv; + + memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext)); + return 0; +} + +static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dib9000_state *state = fe->demodulator_priv; + int sleep_time, sleep_time_slave; + u32 frontend_status; + u8 nbr_pending, exit_condition, index_frontend, index_frontend_success; + struct dvb_frontend_parametersContext channel_status; + + /* check that the correct parameters are set */ + if (state->fe[0]->dtv_property_cache.frequency == 0) { + dprintk("dib9000: must specify frequency "); + return 0; + } + + if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { + dprintk("dib9000: must specify bandwidth "); + return 0; + } + fe->dtv_property_cache.delivery_system = SYS_DVBT; + + /* set the master status */ + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || + fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { + /* no channel specified, autosearch the channel */ + state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN; + } else + state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; + + /* set mode and status for the different frontends */ + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + dib9000_fw_set_diversity_in(state->fe[index_frontend], 1); + + /* synchronization of the cache */ + memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); + + state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT; + dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); + + dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status); + dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); + } + + /* actual tune */ + exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ + index_frontend_success = 0; + do { + sleep_time = dib9000_fw_tune(state->fe[0], NULL); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); + if (sleep_time == FE_CALLBACK_TIME_NEVER) + sleep_time = sleep_time_slave; + else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) + sleep_time = sleep_time_slave; + } + if (sleep_time != FE_CALLBACK_TIME_NEVER) + msleep(sleep_time / 10); + else + break; + + nbr_pending = 0; + exit_condition = 0; + index_frontend_success = 0; + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + frontend_status = -dib9000_get_status(state->fe[index_frontend]); + if (frontend_status > -FE_STATUS_TUNE_PENDING) { + exit_condition = 2; /* tune success */ + index_frontend_success = index_frontend; + break; + } + if (frontend_status == -FE_STATUS_TUNE_PENDING) + nbr_pending++; /* some frontends are still tuning */ + } + if ((exit_condition != 2) && (nbr_pending == 0)) + exit_condition = 1; /* if all tune are done and no success, exit: tune failed */ + + } while (exit_condition == 0); + + /* check the tune result */ + if (exit_condition == 1) { /* tune failed */ + dprintk("tune failed"); + return 0; + } + + dprintk("tune success on frontend%i", index_frontend_success); + + /* synchronize all the channel cache */ + dib9000_get_frontend(state->fe[0], fep); + + /* retune the other frontends with the found channel */ + channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + /* only retune the frontends which was not tuned success */ + if (index_frontend != index_frontend_success) { + dib9000_set_channel_status(state->fe[index_frontend], &channel_status); + dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); + } + } + do { + sleep_time = FE_CALLBACK_TIME_NEVER; + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (index_frontend != index_frontend_success) { + sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); + if (sleep_time == FE_CALLBACK_TIME_NEVER) + sleep_time = sleep_time_slave; + else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) + sleep_time = sleep_time_slave; + } + } + if (sleep_time != FE_CALLBACK_TIME_NEVER) + msleep(sleep_time / 10); + else + break; + + nbr_pending = 0; + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (index_frontend != index_frontend_success) { + frontend_status = -dib9000_get_status(state->fe[index_frontend]); + if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING)) + nbr_pending++; /* some frontends are still tuning */ + } + } + } while (nbr_pending != 0); + + /* set the output mode */ + dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); + + /* turn off the diversity for the last frontend */ + dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); + + return 0; +} + +static u16 dib9000_read_lock(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + + return dib9000_read_word(state, 535); +} + +static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend; + u16 lock = 0, lock_slave = 0; + + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + lock_slave |= dib9000_read_lock(state->fe[index_frontend]); + + lock = dib9000_read_word(state, 535); + + *stat = 0; + + if ((lock & 0x8000) || (lock_slave & 0x8000)) + *stat |= FE_HAS_SIGNAL; + if ((lock & 0x3000) || (lock_slave & 0x3000)) + *stat |= FE_HAS_CARRIER; + if ((lock & 0x0100) || (lock_slave & 0x0100)) + *stat |= FE_HAS_VITERBI; + if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38)) + *stat |= FE_HAS_SYNC; + if ((lock & 0x0008) || (lock_slave & 0x0008)) + *stat |= FE_HAS_LOCK; + + return 0; +} + +static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 *c; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; + dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, + state->i2c_read_buffer, 16 * 2); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + c = (u16 *)state->i2c_read_buffer; + + *ber = c[10] << 16 | c[11]; + return 0; +} + +static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend; + u16 *c = (u16 *)state->i2c_read_buffer; + u16 val; + + *strength = 0; + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); + if (val > 65535 - *strength) + *strength = 65535; + else + *strength += val; + } + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; + dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + val = 65535 - c[4]; + if (val > 65535 - *strength) + *strength = 65535; + else + *strength += val; + return 0; +} + +static u32 dib9000_get_snr(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 *c = (u16 *)state->i2c_read_buffer; + u32 n, s, exp; + u16 val; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; + dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + val = c[7]; + n = (val >> 4) & 0xff; + exp = ((val & 0xf) << 2); + val = c[8]; + exp += ((val >> 14) & 0x3); + if ((exp & 0x20) != 0) + exp -= 0x40; + n <<= exp + 16; + + s = (val >> 6) & 0xFF; + exp = (val & 0x3F); + if ((exp & 0x20) != 0) + exp -= 0x40; + s <<= exp + 16; + + if (n > 0) { + u32 t = (s / n) << 16; + return t + ((s << 16) - n * t) / n; + } + return 0xffffffff; +} + +static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend; + u32 snr_master; + + snr_master = dib9000_get_snr(fe); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + snr_master += dib9000_get_snr(state->fe[index_frontend]); + + if ((snr_master >> 16) != 0) { + snr_master = 10 * intlog10(snr_master >> 16); + *snr = snr_master / ((1 << 24) / 10); + } else + *snr = 0; + + return 0; +} + +static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 *c = (u16 *)state->i2c_read_buffer; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; + dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + *unc = c[12]; + return 0; +} + +int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr) +{ + int k = 0, ret = 0; + u8 new_addr = 0; + struct i2c_device client = {.i2c_adap = i2c }; + + client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); + if (!client.i2c_write_buffer) { + dprintk("%s: not enough memory", __func__); + return -ENOMEM; + } + client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); + if (!client.i2c_read_buffer) { + dprintk("%s: not enough memory", __func__); + ret = -ENOMEM; + goto error_memory; + } + + client.i2c_addr = default_addr + 16; + dib9000_i2c_write16(&client, 1796, 0x0); + + for (k = no_of_demods - 1; k >= 0; k--) { + /* designated i2c address */ + new_addr = first_addr + (k << 1); + client.i2c_addr = default_addr; + + dib9000_i2c_write16(&client, 1817, 3); + dib9000_i2c_write16(&client, 1796, 0); + dib9000_i2c_write16(&client, 1227, 1); + dib9000_i2c_write16(&client, 1227, 0); + + client.i2c_addr = new_addr; + dib9000_i2c_write16(&client, 1817, 3); + dib9000_i2c_write16(&client, 1796, 0); + dib9000_i2c_write16(&client, 1227, 1); + dib9000_i2c_write16(&client, 1227, 0); + + if (dib9000_identify(&client) == 0) { + client.i2c_addr = default_addr; + if (dib9000_identify(&client) == 0) { + dprintk("DiB9000 #%d: not identified", k); + ret = -EIO; + goto error; + } + } + + dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6)); + dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2); + + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); + } + + for (k = 0; k < no_of_demods; k++) { + new_addr = first_addr | (k << 1); + client.i2c_addr = new_addr; + + dib9000_i2c_write16(&client, 1794, (new_addr << 2)); + dib9000_i2c_write16(&client, 1795, 0); + } + +error: + kfree(client.i2c_read_buffer); +error_memory: + kfree(client.i2c_write_buffer); + + return ret; +} +EXPORT_SYMBOL(dib9000_i2c_enumeration); + +int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend = 1; + + while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) + index_frontend++; + if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { + dprintk("set slave fe %p to index %i", fe_slave, index_frontend); + state->fe[index_frontend] = fe_slave; + return 0; + } + + dprintk("too many slave frontend"); + return -ENOMEM; +} +EXPORT_SYMBOL(dib9000_set_slave_frontend); + +int dib9000_remove_slave_frontend(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend = 1; + + while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) + index_frontend++; + if (index_frontend != 1) { + dprintk("remove slave fe %p (index %i)", state->fe[index_frontend - 1], index_frontend - 1); + state->fe[index_frontend] = NULL; + return 0; + } + + dprintk("no frontend to be removed"); + return -ENODEV; +} +EXPORT_SYMBOL(dib9000_remove_slave_frontend); + +struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +{ + struct dib9000_state *state = fe->demodulator_priv; + + if (slave_index >= MAX_NUMBER_OF_FRONTENDS) + return NULL; + return state->fe[slave_index]; +} +EXPORT_SYMBOL(dib9000_get_slave_frontend); + +static struct dvb_frontend_ops dib9000_ops; +struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg) +{ + struct dvb_frontend *fe; + struct dib9000_state *st; + st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL); + if (st == NULL) + return NULL; + fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); + if (fe == NULL) { + kfree(st); + return NULL; + } + + memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config)); + st->i2c.i2c_adap = i2c_adap; + st->i2c.i2c_addr = i2c_addr; + st->i2c.i2c_write_buffer = st->i2c_write_buffer; + st->i2c.i2c_read_buffer = st->i2c_read_buffer; + + st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS; + st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES; + st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS; + + DibInitLock(&st->platform.risc.mbx_if_lock); + DibInitLock(&st->platform.risc.mbx_lock); + DibInitLock(&st->platform.risc.mem_lock); + DibInitLock(&st->platform.risc.mem_mbx_lock); + + st->fe[0] = fe; + fe->demodulator_priv = st; + memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops)); + + /* Ensure the output mode remains at the previous default if it's + * not specifically set by the caller. + */ + if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) + st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO; + + if (dib9000_identify(&st->i2c) == 0) + goto error; + + dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr); + + st->tuner_adap.dev.parent = i2c_adap->dev.parent; + strncpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", sizeof(st->tuner_adap.name)); + st->tuner_adap.algo = &dib9000_tuner_algo; + st->tuner_adap.algo_data = NULL; + i2c_set_adapdata(&st->tuner_adap, st); + if (i2c_add_adapter(&st->tuner_adap) < 0) + goto error; + + st->component_bus.dev.parent = i2c_adap->dev.parent; + strncpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", sizeof(st->component_bus.name)); + st->component_bus.algo = &dib9000_component_bus_algo; + st->component_bus.algo_data = NULL; + st->component_bus_speed = 340; + i2c_set_adapdata(&st->component_bus, st); + if (i2c_add_adapter(&st->component_bus) < 0) + goto component_bus_add_error; + + dib9000_fw_reset(fe); + + return fe; + +component_bus_add_error: + i2c_del_adapter(&st->tuner_adap); +error: + kfree(st); + return NULL; +} +EXPORT_SYMBOL(dib9000_attach); + +static struct dvb_frontend_ops dib9000_ops = { + .info = { + .name = "DiBcom 9000", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, + }, + + .release = dib9000_release, + + .init = dib9000_wakeup, + .sleep = dib9000_sleep, + + .set_frontend = dib9000_set_frontend, + .get_tune_settings = dib9000_fe_get_tune_settings, + .get_frontend = dib9000_get_frontend, + + .read_status = dib9000_read_status, + .read_ber = dib9000_read_ber, + .read_signal_strength = dib9000_read_signal_strength, + .read_snr = dib9000_read_snr, + .read_ucblocks = dib9000_read_unc_blocks, +}; + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_AUTHOR("Olivier Grenie "); +MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib9000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib9000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib9000.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dib9000.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,131 @@ +#ifndef DIB9000_H +#define DIB9000_H + +#include "dibx000_common.h" + +struct dib9000_config { + u8 dvbt_mode; + u8 output_mpeg2_in_188_bytes; + u8 hostbus_diversity; + struct dibx000_bandwidth_config *bw; + + u16 if_drives; + + u32 timing_frequency; + u32 xtal_clock_khz; + u32 vcxo_timer; + u32 demod_clock_khz; + + const u8 *microcode_B_fe_buffer; + u32 microcode_B_fe_size; + + struct dibGPIOFunction gpio_function[2]; + struct dibSubbandSelection subband; + + u8 output_mode; +}; + +#define DEFAULT_DIB9000_I2C_ADDRESS 18 + +#if defined(CONFIG_DVB_DIB9000) || (defined(CONFIG_DVB_DIB9000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg); +extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); +extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe); +extern struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating); +extern int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val); +extern int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); +extern int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff); +extern int dib9000_firmware_post_pll_init(struct dvb_frontend *fe); +extern int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); +extern int dib9000_remove_slave_frontend(struct dvb_frontend *fe); +extern struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); +extern struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe); +extern int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c); +extern int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed); +#else +static inline struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib9000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_firmware_post_pll_init(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +int dib9000_remove_slave_frontend(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dibx000_common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dibx000_common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dibx000_common.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dibx000_common.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,462 @@ +#include + +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0) + +static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) +{ + mst->i2c_write_buffer[0] = (reg >> 8) & 0xff; + mst->i2c_write_buffer[1] = reg & 0xff; + mst->i2c_write_buffer[2] = (val >> 8) & 0xff; + mst->i2c_write_buffer[3] = val & 0xff; + + memset(mst->msg, 0, sizeof(struct i2c_msg)); + mst->msg[0].addr = mst->i2c_addr; + mst->msg[0].flags = 0; + mst->msg[0].buf = mst->i2c_write_buffer; + mst->msg[0].len = 4; + + return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; +} + +static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) +{ + mst->i2c_write_buffer[0] = reg >> 8; + mst->i2c_write_buffer[1] = reg & 0xff; + + memset(mst->msg, 0, 2 * sizeof(struct i2c_msg)); + mst->msg[0].addr = mst->i2c_addr; + mst->msg[0].flags = 0; + mst->msg[0].buf = mst->i2c_write_buffer; + mst->msg[0].len = 2; + mst->msg[1].addr = mst->i2c_addr; + mst->msg[1].flags = I2C_M_RD; + mst->msg[1].buf = mst->i2c_read_buffer; + mst->msg[1].len = 2; + + if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2) + dprintk("i2c read error on %d", reg); + + return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; +} + +static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) +{ + int i = 100; + u16 status; + + while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0) + ; + + /* i2c timed out */ + if (i == 0) + return -EREMOTEIO; + + /* no acknowledge */ + if ((status & 0x0080) == 0) + return -EREMOTEIO; + + return 0; +} + +static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop) +{ + u16 data; + u16 da; + u16 i; + u16 txlen = msg->len, len; + const u8 *b = msg->buf; + + while (txlen) { + dibx000_read_word(mst, mst->base_reg + 2); + + len = txlen > 8 ? 8 : txlen; + for (i = 0; i < len; i += 2) { + data = *b++ << 8; + if (i+1 < len) + data |= *b++; + dibx000_write_word(mst, mst->base_reg, data); + } + da = (((u8) (msg->addr)) << 9) | + (1 << 8) | + (1 << 7) | + (0 << 6) | + (0 << 5) | + ((len & 0x7) << 2) | + (0 << 1) | + (0 << 0); + + if (txlen == msg->len) + da |= 1 << 5; /* start */ + + if (txlen-len == 0 && stop) + da |= 1 << 6; /* stop */ + + dibx000_write_word(mst, mst->base_reg+1, da); + + if (dibx000_is_i2c_done(mst) != 0) + return -EREMOTEIO; + txlen -= len; + } + + return 0; +} + +static int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg) +{ + u16 da; + u8 *b = msg->buf; + u16 rxlen = msg->len, len; + + while (rxlen) { + len = rxlen > 8 ? 8 : rxlen; + da = (((u8) (msg->addr)) << 9) | + (1 << 8) | + (1 << 7) | + (0 << 6) | + (0 << 5) | + ((len & 0x7) << 2) | + (1 << 1) | + (0 << 0); + + if (rxlen == msg->len) + da |= 1 << 5; /* start */ + + if (rxlen-len == 0) + da |= 1 << 6; /* stop */ + dibx000_write_word(mst, mst->base_reg+1, da); + + if (dibx000_is_i2c_done(mst) != 0) + return -EREMOTEIO; + + rxlen -= len; + + while (len) { + da = dibx000_read_word(mst, mst->base_reg); + *b++ = (da >> 8) & 0xff; + len--; + if (len >= 1) { + *b++ = da & 0xff; + len--; + } + } + } + + return 0; +} + +int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed) +{ + struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + + if (mst->device_rev < DIB7000MC && speed < 235) + speed = 235; + return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed)); + +} +EXPORT_SYMBOL(dibx000_i2c_set_speed); + +static u32 dibx000_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, + enum dibx000_i2c_interface intf) +{ + if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { + dprintk("selecting interface: %d", intf); + mst->selected_interface = intf; + return dibx000_write_word(mst, mst->base_reg + 4, intf); + } + return 0; +} + +static int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + int msg_index; + int ret = 0; + + dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2); + for (msg_index = 0; msg_index < num; msg_index++) { + if (msg[msg_index].flags & I2C_M_RD) { + ret = dibx000_master_i2c_read(mst, &msg[msg_index]); + if (ret != 0) + return 0; + } else { + ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1); + if (ret != 0) + return 0; + } + } + + return num; +} + +static int dibx000_i2c_master_xfer_gpio34(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + int msg_index; + int ret = 0; + + dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_3_4); + for (msg_index = 0; msg_index < num; msg_index++) { + if (msg[msg_index].flags & I2C_M_RD) { + ret = dibx000_master_i2c_read(mst, &msg[msg_index]); + if (ret != 0) + return 0; + } else { + ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1); + if (ret != 0) + return 0; + } + } + + return num; +} + +static struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = { + .master_xfer = dibx000_i2c_master_xfer_gpio12, + .functionality = dibx000_i2c_func, +}; + +static struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = { + .master_xfer = dibx000_i2c_master_xfer_gpio34, + .functionality = dibx000_i2c_func, +}; + +static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], + u8 addr, int onoff) +{ + u16 val; + + + if (onoff) + val = addr << 8; // bit 7 = use master or not, if 0, the gate is open + else + val = 1 << 7; + + if (mst->device_rev > DIB7000) + val <<= 1; + + tx[0] = (((mst->base_reg + 1) >> 8) & 0xff); + tx[1] = ((mst->base_reg + 1) & 0xff); + tx[2] = val >> 8; + tx[3] = val & 0xff; + + return 0; +} + +static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + + if (num > 32) { + dprintk("%s: too much I2C message to be transmitted (%i).\ + Maximum is 32", __func__, num); + return -ENOMEM; + } + + memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + + dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); + + /* open the gate */ + dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); + mst->msg[0].addr = mst->i2c_addr; + mst->msg[0].buf = &mst->i2c_write_buffer[0]; + mst->msg[0].len = 4; + + memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num); + + /* close the gate */ + dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0); + mst->msg[num + 1].addr = mst->i2c_addr; + mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; + mst->msg[num + 1].len = 4; + + return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; +} + +static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = { + .master_xfer = dibx000_i2c_gated_gpio67_xfer, + .functionality = dibx000_i2c_func, +}; + +static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + + if (num > 32) { + dprintk("%s: too much I2C message to be transmitted (%i).\ + Maximum is 32", __func__, num); + return -ENOMEM; + } + + memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + + dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); + + /* open the gate */ + dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); + mst->msg[0].addr = mst->i2c_addr; + mst->msg[0].buf = &mst->i2c_write_buffer[0]; + mst->msg[0].len = 4; + + memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num); + + /* close the gate */ + dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0); + mst->msg[num + 1].addr = mst->i2c_addr; + mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; + mst->msg[num + 1].len = 4; + + return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; +} + +static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { + .master_xfer = dibx000_i2c_gated_tuner_xfer, + .functionality = dibx000_i2c_func, +}; + +struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, + enum dibx000_i2c_interface intf, + int gating) +{ + struct i2c_adapter *i2c = NULL; + + switch (intf) { + case DIBX000_I2C_INTERFACE_TUNER: + if (gating) + i2c = &mst->gated_tuner_i2c_adap; + break; + case DIBX000_I2C_INTERFACE_GPIO_1_2: + if (!gating) + i2c = &mst->master_i2c_adap_gpio12; + break; + case DIBX000_I2C_INTERFACE_GPIO_3_4: + if (!gating) + i2c = &mst->master_i2c_adap_gpio34; + break; + case DIBX000_I2C_INTERFACE_GPIO_6_7: + if (gating) + i2c = &mst->master_i2c_adap_gpio67; + break; + default: + printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n"); + break; + } + + return i2c; +} + +EXPORT_SYMBOL(dibx000_get_i2c_adapter); + +void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst) +{ + /* initialize the i2c-master by closing the gate */ + u8 tx[4]; + struct i2c_msg m = {.addr = mst->i2c_addr,.buf = tx,.len = 4 }; + + dibx000_i2c_gate_ctrl(mst, tx, 0, 0); + i2c_transfer(mst->i2c_adap, &m, 1); + mst->selected_interface = 0xff; // the first time force a select of the I2C + dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); +} + +EXPORT_SYMBOL(dibx000_reset_i2c_master); + +static int i2c_adapter_init(struct i2c_adapter *i2c_adap, + struct i2c_algorithm *algo, const char *name, + struct dibx000_i2c_master *mst) +{ + strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); + i2c_adap->algo = algo; + i2c_adap->algo_data = NULL; + i2c_set_adapdata(i2c_adap, mst); + if (i2c_add_adapter(i2c_adap) < 0) + return -ENODEV; + return 0; +} + +int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, + struct i2c_adapter *i2c_adap, u8 i2c_addr) +{ + u8 tx[4]; + struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 }; + + mst->device_rev = device_rev; + mst->i2c_adap = i2c_adap; + mst->i2c_addr = i2c_addr >> 1; + + if (device_rev == DIB7000P || device_rev == DIB8000) + mst->base_reg = 1024; + else + mst->base_reg = 768; + + mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent; + if (i2c_adapter_init + (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, + "DiBX000 tuner I2C bus", mst) != 0) + printk(KERN_ERR + "DiBX000: could not initialize the tuner i2c_adapter\n"); + + mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent; + if (i2c_adapter_init + (&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo, + "DiBX000 master GPIO12 I2C bus", mst) != 0) + printk(KERN_ERR + "DiBX000: could not initialize the master i2c_adapter\n"); + + mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent; + if (i2c_adapter_init + (&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo, + "DiBX000 master GPIO34 I2C bus", mst) != 0) + printk(KERN_ERR + "DiBX000: could not initialize the master i2c_adapter\n"); + + mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent; + if (i2c_adapter_init + (&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo, + "DiBX000 master GPIO67 I2C bus", mst) != 0) + printk(KERN_ERR + "DiBX000: could not initialize the master i2c_adapter\n"); + + /* initialize the i2c-master by closing the gate */ + dibx000_i2c_gate_ctrl(mst, tx, 0, 0); + + return i2c_transfer(i2c_adap, &m, 1) == 1; +} + +EXPORT_SYMBOL(dibx000_init_i2c_master); + +void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) +{ + i2c_del_adapter(&mst->gated_tuner_i2c_adap); + i2c_del_adapter(&mst->master_i2c_adap_gpio12); + i2c_del_adapter(&mst->master_i2c_adap_gpio34); + i2c_del_adapter(&mst->master_i2c_adap_gpio67); +} +EXPORT_SYMBOL(dibx000_exit_i2c_master); + + +u32 systime(void) +{ + struct timespec t; + + t = current_kernel_time(); + return (t.tv_sec * 10000) + (t.tv_nsec / 100000); +} +EXPORT_SYMBOL(systime); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Common function the DiBcom demodulator family"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dibx000_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dibx000_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dibx000_common.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dibx000_common.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,278 @@ +#ifndef DIBX000_COMMON_H +#define DIBX000_COMMON_H + +enum dibx000_i2c_interface { + DIBX000_I2C_INTERFACE_TUNER = 0, + DIBX000_I2C_INTERFACE_GPIO_1_2 = 1, + DIBX000_I2C_INTERFACE_GPIO_3_4 = 2, + DIBX000_I2C_INTERFACE_GPIO_6_7 = 3 +}; + +struct dibx000_i2c_master { +#define DIB3000MC 1 +#define DIB7000 2 +#define DIB7000P 11 +#define DIB7000MC 12 +#define DIB8000 13 + u16 device_rev; + + enum dibx000_i2c_interface selected_interface; + +/* struct i2c_adapter tuner_i2c_adap; */ + struct i2c_adapter gated_tuner_i2c_adap; + struct i2c_adapter master_i2c_adap_gpio12; + struct i2c_adapter master_i2c_adap_gpio34; + struct i2c_adapter master_i2c_adap_gpio67; + + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + + u16 base_reg; + + /* for the I2C transfer */ + struct i2c_msg msg[34]; + u8 i2c_write_buffer[8]; + u8 i2c_read_buffer[2]; +}; + +extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, + u16 device_rev, struct i2c_adapter *i2c_adap, + u8 i2c_addr); +extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master + *mst, + enum dibx000_i2c_interface + intf, int gating); +extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); +extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst); +extern int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed); + +extern u32 systime(void); + +#define BAND_LBAND 0x01 +#define BAND_UHF 0x02 +#define BAND_VHF 0x04 +#define BAND_SBAND 0x08 +#define BAND_FM 0x10 +#define BAND_CBAND 0x20 + +#define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \ + (freq_kHz) <= 115000 ? BAND_FM : \ + (freq_kHz) <= 250000 ? BAND_VHF : \ + (freq_kHz) <= 863000 ? BAND_UHF : \ + (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND ) + +struct dibx000_agc_config { + /* defines the capabilities of this AGC-setting - using the BAND_-defines */ + u8 band_caps; + + u16 setup; + + u16 inv_gain; + u16 time_stabiliz; + + u8 alpha_level; + u16 thlock; + + u8 wbd_inv; + u16 wbd_ref; + u8 wbd_sel; + u8 wbd_alpha; + + u16 agc1_max; + u16 agc1_min; + u16 agc2_max; + u16 agc2_min; + + u8 agc1_pt1; + u8 agc1_pt2; + u8 agc1_pt3; + + u8 agc1_slope1; + u8 agc1_slope2; + + u8 agc2_pt1; + u8 agc2_pt2; + + u8 agc2_slope1; + u8 agc2_slope2; + + u8 alpha_mant; + u8 alpha_exp; + + u8 beta_mant; + u8 beta_exp; + + u8 perform_agc_softsplit; + + struct { + u16 min; + u16 max; + u16 min_thres; + u16 max_thres; + } split; +}; + +struct dibx000_bandwidth_config { + u32 internal; + u32 sampling; + + u8 pll_prediv; + u8 pll_ratio; + u8 pll_range; + u8 pll_reset; + u8 pll_bypass; + + u8 enable_refdiv; + u8 bypclk_div; + u8 IO_CLK_en_core; + u8 ADClkSrc; + u8 modulo; + + u16 sad_cfg; + + u32 ifreq; + u32 timf; + + u32 xtal_hz; +}; + +enum dibx000_adc_states { + DIBX000_SLOW_ADC_ON = 0, + DIBX000_SLOW_ADC_OFF, + DIBX000_ADC_ON, + DIBX000_ADC_OFF, + DIBX000_VBG_ENABLE, + DIBX000_VBG_DISABLE, +}; + +#define BANDWIDTH_TO_KHZ(v) ((v) == BANDWIDTH_8_MHZ ? 8000 : \ + (v) == BANDWIDTH_7_MHZ ? 7000 : \ + (v) == BANDWIDTH_6_MHZ ? 6000 : 8000) + +#define BANDWIDTH_TO_INDEX(v) ( \ + (v) == 8000 ? BANDWIDTH_8_MHZ : \ + (v) == 7000 ? BANDWIDTH_7_MHZ : \ + (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ ) + +/* Chip output mode. */ +#define OUTMODE_HIGH_Z 0 +#define OUTMODE_MPEG2_PAR_GATED_CLK 1 +#define OUTMODE_MPEG2_PAR_CONT_CLK 2 +#define OUTMODE_MPEG2_SERIAL 7 +#define OUTMODE_DIVERSITY 4 +#define OUTMODE_MPEG2_FIFO 5 +#define OUTMODE_ANALOG_ADC 6 + +#define INPUT_MODE_OFF 0x11 +#define INPUT_MODE_DIVERSITY 0x12 +#define INPUT_MODE_MPEG 0x13 + +enum frontend_tune_state { + CT_TUNER_START = 10, + CT_TUNER_STEP_0, + CT_TUNER_STEP_1, + CT_TUNER_STEP_2, + CT_TUNER_STEP_3, + CT_TUNER_STEP_4, + CT_TUNER_STEP_5, + CT_TUNER_STEP_6, + CT_TUNER_STEP_7, + CT_TUNER_STOP, + + CT_AGC_START = 20, + CT_AGC_STEP_0, + CT_AGC_STEP_1, + CT_AGC_STEP_2, + CT_AGC_STEP_3, + CT_AGC_STEP_4, + CT_AGC_STOP, + + CT_DEMOD_START = 30, + CT_DEMOD_STEP_1, + CT_DEMOD_STEP_2, + CT_DEMOD_STEP_3, + CT_DEMOD_STEP_4, + CT_DEMOD_STEP_5, + CT_DEMOD_STEP_6, + CT_DEMOD_STEP_7, + CT_DEMOD_STEP_8, + CT_DEMOD_STEP_9, + CT_DEMOD_STEP_10, + CT_DEMOD_SEARCH_NEXT = 41, + CT_DEMOD_STEP_LOCKED, + CT_DEMOD_STOP, + + CT_DONE = 100, + CT_SHUTDOWN, + +}; + +struct dvb_frontend_parametersContext { +#define CHANNEL_STATUS_PARAMETERS_UNKNOWN 0x01 +#define CHANNEL_STATUS_PARAMETERS_SET 0x02 + u8 status; + u32 tune_time_estimation[2]; + s32 tps_available; + u16 tps[9]; +}; + +#define FE_STATUS_TUNE_FAILED 0 +#define FE_STATUS_TUNE_TIMED_OUT -1 +#define FE_STATUS_TUNE_TIME_TOO_SHORT -2 +#define FE_STATUS_TUNE_PENDING -3 +#define FE_STATUS_STD_SUCCESS -4 +#define FE_STATUS_FFT_SUCCESS -5 +#define FE_STATUS_DEMOD_SUCCESS -6 +#define FE_STATUS_LOCKED -7 +#define FE_STATUS_DATA_LOCKED -8 + +#define FE_CALLBACK_TIME_NEVER 0xffffffff + +#define ABS(x) ((x < 0) ? (-x) : (x)) + +#define DATA_BUS_ACCESS_MODE_8BIT 0x01 +#define DATA_BUS_ACCESS_MODE_16BIT 0x02 +#define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10 + +struct dibGPIOFunction { +#define BOARD_GPIO_COMPONENT_BUS_ADAPTER 1 +#define BOARD_GPIO_COMPONENT_DEMOD 2 + u8 component; + +#define BOARD_GPIO_FUNCTION_BOARD_ON 1 +#define BOARD_GPIO_FUNCTION_BOARD_OFF 2 +#define BOARD_GPIO_FUNCTION_COMPONENT_ON 3 +#define BOARD_GPIO_FUNCTION_COMPONENT_OFF 4 +#define BOARD_GPIO_FUNCTION_SUBBAND_PWM 5 +#define BOARD_GPIO_FUNCTION_SUBBAND_GPIO 6 + u8 function; + +/* mask, direction and value are used specify which GPIO to change GPIO0 + * is LSB and possible GPIO31 is MSB. The same bit-position as in the + * mask is used for the direction and the value. Direction == 1 is OUT, + * 0 == IN. For direction "OUT" value is either 1 or 0, for direction IN + * value has no meaning. + * + * In case of BOARD_GPIO_FUNCTION_PWM mask is giving the GPIO to be + * used to do the PWM. Direction gives the PWModulator to be used. + * Value gives the PWM value in device-dependent scale. + */ + u32 mask; + u32 direction; + u32 value; +}; + +#define MAX_NB_SUBBANDS 8 +struct dibSubbandSelection { + u8 size; /* Actual number of subbands. */ + struct { + u16 f_mhz; + struct dibGPIOFunction gpio; + } subband[MAX_NB_SUBBANDS]; +}; + +#define DEMOD_TIMF_SET 0x00 +#define DEMOD_TIMF_GET 0x01 +#define DEMOD_TIMF_UPDATE 0x02 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_firm.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_firm.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_firm.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_firm.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,929 @@ +/* + * drxd_firm.c : DRXD firmware tables + * + * Copyright (C) 2006-2007 Micronas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +/* TODO: generate this file with a script from a settings file */ + +/* Contains A2 firmware version: 1.4.2 + * Contains B1 firmware version: 3.3.33 + * Contains settings from driver 1.4.23 +*/ + +#include "drxd_firm.h" + +#define ADDRESS(x) ((x) & 0xFF), (((x)>>8) & 0xFF), (((x)>>16) & 0xFF), (((x)>>24) & 0xFF) +#define LENGTH(x) ((x) & 0xFF), (((x)>>8) & 0xFF) + +/* Is written via block write, must be little endian */ +#define DATA16(x) ((x) & 0xFF), (((x)>>8) & 0xFF) + +#define WRBLOCK(a, l) ADDRESS(a), LENGTH(l) +#define WR16(a, d) ADDRESS(a), LENGTH(1), DATA16(d) + +#define END_OF_TABLE 0xFF, 0xFF, 0xFF, 0xFF + +/* HI firmware patches */ + +#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A +#define HI_TR_FUNC_SIZE 9 /* size of this function in instruction words */ + +u8 DRXD_InitAtomicRead[] = { + WRBLOCK(HI_TR_FUNC_ADDR, HI_TR_FUNC_SIZE), + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0x60, 0x04, /* r0rami.dt -> ring.xba; */ + 0x61, 0x04, /* r0rami.dt -> ring.xad; */ + 0xE3, 0x07, /* HI_RA_RAM_USR_BEGIN -> ring.iad; */ + 0x40, 0x00, /* (long immediate) */ + 0x64, 0x04, /* r0rami.dt -> ring.len; */ + 0x65, 0x04, /* r0rami.dt -> ring.ctl; */ + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0x38, 0x00, /* 0 -> jumps.ad; */ + END_OF_TABLE +}; + +/* Pins D0 and D1 of the parallel MPEG output can be used + to set the I2C address of a device. */ + +#define HI_RST_FUNC_ADDR (HI_IF_RAM_USR_BEGIN__A + HI_TR_FUNC_SIZE) +#define HI_RST_FUNC_SIZE 54 /* size of this function in instruction words */ + +/* D0 Version */ +u8 DRXD_HiI2cPatch_1[] = { + WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE), + 0xC8, 0x07, 0x01, 0x00, /* MASK -> reg0.dt; */ + 0xE0, 0x07, 0x15, 0x02, /* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */ + 0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad; */ + 0xA2, 0x00, /* M_BNK_ID_DAT -> ring.iba; */ + 0x23, 0x00, /* &data -> ring.iad; */ + 0x24, 0x00, /* 0 -> ring.len; */ + 0xA5, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl; */ + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0x42, 0x00, /* &data+1 -> w0ram.ad; */ + 0xC0, 0x07, 0xFF, 0x0F, /* -1 -> w0ram.dt; */ + 0x63, 0x00, /* &data+1 -> ring.iad; */ + 0x65, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl; */ + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0xE1, 0x07, 0x38, 0x00, /* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad; */ + 0xA5, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl; */ + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad; */ + 0x23, 0x00, /* &data -> ring.iad; */ + 0x65, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl; */ + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0x42, 0x00, /* &data+1 -> w0ram.ad; */ + 0x0F, 0x04, /* r0ram.dt -> and.op; */ + 0x1C, 0x06, /* reg0.dt -> and.tr; */ + 0xCF, 0x04, /* and.rs -> add.op; */ + 0xD0, 0x07, 0x70, 0x00, /* DEF_DEV_ID -> add.tr; */ + 0xD0, 0x04, /* add.rs -> add.tr; */ + 0xC8, 0x04, /* add.rs -> reg0.dt; */ + 0x60, 0x00, /* reg0.dt -> w0ram.dt; */ + 0xC2, 0x07, 0x10, 0x00, /* SLV0_BASE -> w0rami.ad; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x01, 0x06, /* reg0.dt -> w0rami.dt; */ + 0xC2, 0x07, 0x20, 0x00, /* SLV1_BASE -> w0rami.ad; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x01, 0x06, /* reg0.dt -> w0rami.dt; */ + 0xC2, 0x07, 0x30, 0x00, /* CMD_BASE -> w0rami.ad; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x68, 0x00, /* M_IC_SEL_PT1 -> i2c.sel; */ + 0x29, 0x00, /* M_IC_CMD_RESET -> i2c.cmd; */ + 0x28, 0x00, /* M_IC_SEL_PT0 -> i2c.sel; */ + 0x29, 0x00, /* M_IC_CMD_RESET -> i2c.cmd; */ + 0xF8, 0x07, 0x2F, 0x00, /* 0x2F -> jumps.ad; */ + + WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)), + (u16) (HI_RST_FUNC_ADDR & 0x3FF)), + WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)), + (u16) (HI_RST_FUNC_ADDR & 0x3FF)), + WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)), + (u16) (HI_RST_FUNC_ADDR & 0x3FF)), + WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)), + (u16) (HI_RST_FUNC_ADDR & 0x3FF)), + + /* Force quick and dirty reset */ + WR16(B_HI_CT_REG_COMM_STATE__A, 0), + END_OF_TABLE +}; + +/* D0,D1 Version */ +u8 DRXD_HiI2cPatch_3[] = { + WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE), + 0xC8, 0x07, 0x03, 0x00, /* MASK -> reg0.dt; */ + 0xE0, 0x07, 0x15, 0x02, /* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */ + 0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad; */ + 0xA2, 0x00, /* M_BNK_ID_DAT -> ring.iba; */ + 0x23, 0x00, /* &data -> ring.iad; */ + 0x24, 0x00, /* 0 -> ring.len; */ + 0xA5, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl; */ + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0x42, 0x00, /* &data+1 -> w0ram.ad; */ + 0xC0, 0x07, 0xFF, 0x0F, /* -1 -> w0ram.dt; */ + 0x63, 0x00, /* &data+1 -> ring.iad; */ + 0x65, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl; */ + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0xE1, 0x07, 0x38, 0x00, /* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad; */ + 0xA5, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl; */ + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad; */ + 0x23, 0x00, /* &data -> ring.iad; */ + 0x65, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl; */ + 0x26, 0x00, /* 0 -> ring.rdy; */ + 0x42, 0x00, /* &data+1 -> w0ram.ad; */ + 0x0F, 0x04, /* r0ram.dt -> and.op; */ + 0x1C, 0x06, /* reg0.dt -> and.tr; */ + 0xCF, 0x04, /* and.rs -> add.op; */ + 0xD0, 0x07, 0x70, 0x00, /* DEF_DEV_ID -> add.tr; */ + 0xD0, 0x04, /* add.rs -> add.tr; */ + 0xC8, 0x04, /* add.rs -> reg0.dt; */ + 0x60, 0x00, /* reg0.dt -> w0ram.dt; */ + 0xC2, 0x07, 0x10, 0x00, /* SLV0_BASE -> w0rami.ad; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x01, 0x06, /* reg0.dt -> w0rami.dt; */ + 0xC2, 0x07, 0x20, 0x00, /* SLV1_BASE -> w0rami.ad; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x01, 0x06, /* reg0.dt -> w0rami.dt; */ + 0xC2, 0x07, 0x30, 0x00, /* CMD_BASE -> w0rami.ad; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x01, 0x00, /* 0 -> w0rami.dt; */ + 0x68, 0x00, /* M_IC_SEL_PT1 -> i2c.sel; */ + 0x29, 0x00, /* M_IC_CMD_RESET -> i2c.cmd; */ + 0x28, 0x00, /* M_IC_SEL_PT0 -> i2c.sel; */ + 0x29, 0x00, /* M_IC_CMD_RESET -> i2c.cmd; */ + 0xF8, 0x07, 0x2F, 0x00, /* 0x2F -> jumps.ad; */ + + WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)), + (u16) (HI_RST_FUNC_ADDR & 0x3FF)), + WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)), + (u16) (HI_RST_FUNC_ADDR & 0x3FF)), + WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)), + (u16) (HI_RST_FUNC_ADDR & 0x3FF)), + WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)), + (u16) (HI_RST_FUNC_ADDR & 0x3FF)), + + /* Force quick and dirty reset */ + WR16(B_HI_CT_REG_COMM_STATE__A, 0), + END_OF_TABLE +}; + +u8 DRXD_ResetCEFR[] = { + WRBLOCK(CE_REG_FR_TREAL00__A, 57), + 0x52, 0x00, /* CE_REG_FR_TREAL00__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG00__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL01__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG01__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL02__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG02__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL03__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG03__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL04__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG04__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL05__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG05__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL06__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG06__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL07__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG07__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL08__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG08__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL09__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG09__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL10__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG10__A */ + 0x52, 0x00, /* CE_REG_FR_TREAL11__A */ + 0x00, 0x00, /* CE_REG_FR_TIMAG11__A */ + + 0x52, 0x00, /* CE_REG_FR_MID_TAP__A */ + + 0x0B, 0x00, /* CE_REG_FR_SQS_G00__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G01__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G02__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G03__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G04__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G05__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G06__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G07__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G08__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G09__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G10__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G11__A */ + 0x0B, 0x00, /* CE_REG_FR_SQS_G12__A */ + + 0xFF, 0x01, /* CE_REG_FR_RIO_G00__A */ + 0x90, 0x01, /* CE_REG_FR_RIO_G01__A */ + 0x0B, 0x01, /* CE_REG_FR_RIO_G02__A */ + 0xC8, 0x00, /* CE_REG_FR_RIO_G03__A */ + 0xA0, 0x00, /* CE_REG_FR_RIO_G04__A */ + 0x85, 0x00, /* CE_REG_FR_RIO_G05__A */ + 0x72, 0x00, /* CE_REG_FR_RIO_G06__A */ + 0x64, 0x00, /* CE_REG_FR_RIO_G07__A */ + 0x59, 0x00, /* CE_REG_FR_RIO_G08__A */ + 0x50, 0x00, /* CE_REG_FR_RIO_G09__A */ + 0x49, 0x00, /* CE_REG_FR_RIO_G10__A */ + + 0x10, 0x00, /* CE_REG_FR_MODE__A */ + 0x78, 0x00, /* CE_REG_FR_SQS_TRH__A */ + 0x00, 0x00, /* CE_REG_FR_RIO_GAIN__A */ + 0x00, 0x02, /* CE_REG_FR_BYPASS__A */ + 0x0D, 0x00, /* CE_REG_FR_PM_SET__A */ + 0x07, 0x00, /* CE_REG_FR_ERR_SH__A */ + 0x04, 0x00, /* CE_REG_FR_MAN_SH__A */ + 0x06, 0x00, /* CE_REG_FR_TAP_SH__A */ + + END_OF_TABLE +}; + +u8 DRXD_InitFEA2_1[] = { + WRBLOCK(FE_AD_REG_PD__A, 3), + 0x00, 0x00, /* FE_AD_REG_PD__A */ + 0x01, 0x00, /* FE_AD_REG_INVEXT__A */ + 0x00, 0x00, /* FE_AD_REG_CLKNEG__A */ + + WRBLOCK(FE_AG_REG_DCE_AUR_CNT__A, 2), + 0x10, 0x00, /* FE_AG_REG_DCE_AUR_CNT__A */ + 0x10, 0x00, /* FE_AG_REG_DCE_RUR_CNT__A */ + + WRBLOCK(FE_AG_REG_ACE_AUR_CNT__A, 2), + 0x0E, 0x00, /* FE_AG_REG_ACE_AUR_CNT__A */ + 0x00, 0x00, /* FE_AG_REG_ACE_RUR_CNT__A */ + + WRBLOCK(FE_AG_REG_EGC_FLA_RGN__A, 5), + 0x04, 0x00, /* FE_AG_REG_EGC_FLA_RGN__A */ + 0x1F, 0x00, /* FE_AG_REG_EGC_SLO_RGN__A */ + 0x00, 0x00, /* FE_AG_REG_EGC_JMP_PSN__A */ + 0x00, 0x00, /* FE_AG_REG_EGC_FLA_INC__A */ + 0x00, 0x00, /* FE_AG_REG_EGC_FLA_DEC__A */ + + WRBLOCK(FE_AG_REG_GC1_AGC_MAX__A, 2), + 0xFF, 0x01, /* FE_AG_REG_GC1_AGC_MAX__A */ + 0x00, 0xFE, /* FE_AG_REG_GC1_AGC_MIN__A */ + + WRBLOCK(FE_AG_REG_IND_WIN__A, 29), + 0x00, 0x00, /* FE_AG_REG_IND_WIN__A */ + 0x05, 0x00, /* FE_AG_REG_IND_THD_LOL__A */ + 0x0F, 0x00, /* FE_AG_REG_IND_THD_HIL__A */ + 0x00, 0x00, /* FE_AG_REG_IND_DEL__A don't care */ + 0x1E, 0x00, /* FE_AG_REG_IND_PD1_WRI__A */ + 0x0C, 0x00, /* FE_AG_REG_PDA_AUR_CNT__A */ + 0x00, 0x00, /* FE_AG_REG_PDA_RUR_CNT__A */ + 0x00, 0x00, /* FE_AG_REG_PDA_AVE_DAT__A don't care */ + 0x00, 0x00, /* FE_AG_REG_PDC_RUR_CNT__A */ + 0x01, 0x00, /* FE_AG_REG_PDC_SET_LVL__A */ + 0x02, 0x00, /* FE_AG_REG_PDC_FLA_RGN__A */ + 0x00, 0x00, /* FE_AG_REG_PDC_JMP_PSN__A don't care */ + 0xFF, 0xFF, /* FE_AG_REG_PDC_FLA_STP__A */ + 0xFF, 0xFF, /* FE_AG_REG_PDC_SLO_STP__A */ + 0x00, 0x1F, /* FE_AG_REG_PDC_PD2_WRI__A don't care */ + 0x00, 0x00, /* FE_AG_REG_PDC_MAP_DAT__A don't care */ + 0x02, 0x00, /* FE_AG_REG_PDC_MAX__A */ + 0x0C, 0x00, /* FE_AG_REG_TGA_AUR_CNT__A */ + 0x00, 0x00, /* FE_AG_REG_TGA_RUR_CNT__A */ + 0x00, 0x00, /* FE_AG_REG_TGA_AVE_DAT__A don't care */ + 0x00, 0x00, /* FE_AG_REG_TGC_RUR_CNT__A */ + 0x22, 0x00, /* FE_AG_REG_TGC_SET_LVL__A */ + 0x15, 0x00, /* FE_AG_REG_TGC_FLA_RGN__A */ + 0x00, 0x00, /* FE_AG_REG_TGC_JMP_PSN__A don't care */ + 0x01, 0x00, /* FE_AG_REG_TGC_FLA_STP__A */ + 0x0A, 0x00, /* FE_AG_REG_TGC_SLO_STP__A */ + 0x00, 0x00, /* FE_AG_REG_TGC_MAP_DAT__A don't care */ + 0x10, 0x00, /* FE_AG_REG_FGA_AUR_CNT__A */ + 0x10, 0x00, /* FE_AG_REG_FGA_RUR_CNT__A */ + + WRBLOCK(FE_AG_REG_BGC_FGC_WRI__A, 2), + 0x00, 0x00, /* FE_AG_REG_BGC_FGC_WRI__A */ + 0x00, 0x00, /* FE_AG_REG_BGC_CGC_WRI__A */ + + WRBLOCK(FE_FD_REG_SCL__A, 3), + 0x05, 0x00, /* FE_FD_REG_SCL__A */ + 0x03, 0x00, /* FE_FD_REG_MAX_LEV__A */ + 0x05, 0x00, /* FE_FD_REG_NR__A */ + + WRBLOCK(FE_CF_REG_SCL__A, 5), + 0x16, 0x00, /* FE_CF_REG_SCL__A */ + 0x04, 0x00, /* FE_CF_REG_MAX_LEV__A */ + 0x06, 0x00, /* FE_CF_REG_NR__A */ + 0x00, 0x00, /* FE_CF_REG_IMP_VAL__A */ + 0x01, 0x00, /* FE_CF_REG_MEAS_VAL__A */ + + WRBLOCK(FE_CU_REG_FRM_CNT_RST__A, 2), + 0x00, 0x08, /* FE_CU_REG_FRM_CNT_RST__A */ + 0x00, 0x00, /* FE_CU_REG_FRM_CNT_STR__A */ + + END_OF_TABLE +}; + + /* with PGA */ +/* WR16COND( DRXD_WITH_PGA, FE_AG_REG_AG_PGA_MODE__A , 0x0004), */ + /* without PGA */ +/* WR16COND( DRXD_WITHOUT_PGA, FE_AG_REG_AG_PGA_MODE__A , 0x0001), */ +/* WR16(FE_AG_REG_AG_AGC_SIO__A, (extAttr -> FeAgRegAgAgcSio), 0x0000 );*/ +/* WR16(FE_AG_REG_AG_PWD__A ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/ + +u8 DRXD_InitFEA2_2[] = { + WR16(FE_AG_REG_CDR_RUR_CNT__A, 0x0010), + WR16(FE_AG_REG_FGM_WRI__A, 48), + /* Activate measurement, activate scale */ + WR16(FE_FD_REG_MEAS_VAL__A, 0x0001), + + WR16(FE_CU_REG_COMM_EXEC__A, 0x0001), + WR16(FE_CF_REG_COMM_EXEC__A, 0x0001), + WR16(FE_IF_REG_COMM_EXEC__A, 0x0001), + WR16(FE_FD_REG_COMM_EXEC__A, 0x0001), + WR16(FE_FS_REG_COMM_EXEC__A, 0x0001), + WR16(FE_AD_REG_COMM_EXEC__A, 0x0001), + WR16(FE_AG_REG_COMM_EXEC__A, 0x0001), + WR16(FE_AG_REG_AG_MODE_LOP__A, 0x895E), + + END_OF_TABLE +}; + +u8 DRXD_InitFEB1_1[] = { + WR16(B_FE_AD_REG_PD__A, 0x0000), + WR16(B_FE_AD_REG_CLKNEG__A, 0x0000), + WR16(B_FE_AG_REG_BGC_FGC_WRI__A, 0x0000), + WR16(B_FE_AG_REG_BGC_CGC_WRI__A, 0x0000), + WR16(B_FE_AG_REG_AG_MODE_LOP__A, 0x000a), + WR16(B_FE_AG_REG_IND_PD1_WRI__A, 35), + WR16(B_FE_AG_REG_IND_WIN__A, 0), + WR16(B_FE_AG_REG_IND_THD_LOL__A, 8), + WR16(B_FE_AG_REG_IND_THD_HIL__A, 8), + WR16(B_FE_CF_REG_IMP_VAL__A, 1), + WR16(B_FE_AG_REG_EGC_FLA_RGN__A, 7), + END_OF_TABLE +}; + + /* with PGA */ +/* WR16(B_FE_AG_REG_AG_PGA_MODE__A , 0x0000, 0x0000); */ + /* without PGA */ +/* WR16(B_FE_AG_REG_AG_PGA_MODE__A , + B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);*/ + /* WR16(B_FE_AG_REG_AG_AGC_SIO__A,(extAttr -> FeAgRegAgAgcSio), 0x0000 );*//*added HS 23-05-2005 */ +/* WR16(B_FE_AG_REG_AG_PWD__A ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/ + +u8 DRXD_InitFEB1_2[] = { + WR16(B_FE_COMM_EXEC__A, 0x0001), + + /* RF-AGC setup */ + WR16(B_FE_AG_REG_PDA_AUR_CNT__A, 0x0C), + WR16(B_FE_AG_REG_PDC_SET_LVL__A, 0x01), + WR16(B_FE_AG_REG_PDC_FLA_RGN__A, 0x02), + WR16(B_FE_AG_REG_PDC_FLA_STP__A, 0xFFFF), + WR16(B_FE_AG_REG_PDC_SLO_STP__A, 0xFFFF), + WR16(B_FE_AG_REG_PDC_MAX__A, 0x02), + WR16(B_FE_AG_REG_TGA_AUR_CNT__A, 0x0C), + WR16(B_FE_AG_REG_TGC_SET_LVL__A, 0x22), + WR16(B_FE_AG_REG_TGC_FLA_RGN__A, 0x15), + WR16(B_FE_AG_REG_TGC_FLA_STP__A, 0x01), + WR16(B_FE_AG_REG_TGC_SLO_STP__A, 0x0A), + + WR16(B_FE_CU_REG_DIV_NFC_CLP__A, 0), + WR16(B_FE_CU_REG_CTR_NFC_OCR__A, 25000), + WR16(B_FE_CU_REG_CTR_NFC_ICR__A, 1), + END_OF_TABLE +}; + +u8 DRXD_InitCPA2[] = { + WRBLOCK(CP_REG_BR_SPL_OFFSET__A, 2), + 0x07, 0x00, /* CP_REG_BR_SPL_OFFSET__A */ + 0x0A, 0x00, /* CP_REG_BR_STR_DEL__A */ + + WRBLOCK(CP_REG_RT_ANG_INC0__A, 4), + 0x00, 0x00, /* CP_REG_RT_ANG_INC0__A */ + 0x00, 0x00, /* CP_REG_RT_ANG_INC1__A */ + 0x03, 0x00, /* CP_REG_RT_DETECT_ENA__A */ + 0x03, 0x00, /* CP_REG_RT_DETECT_TRH__A */ + + WRBLOCK(CP_REG_AC_NEXP_OFFS__A, 5), + 0x32, 0x00, /* CP_REG_AC_NEXP_OFFS__A */ + 0x62, 0x00, /* CP_REG_AC_AVER_POW__A */ + 0x82, 0x00, /* CP_REG_AC_MAX_POW__A */ + 0x26, 0x00, /* CP_REG_AC_WEIGHT_MAN__A */ + 0x0F, 0x00, /* CP_REG_AC_WEIGHT_EXP__A */ + + WRBLOCK(CP_REG_AC_AMP_MODE__A, 2), + 0x02, 0x00, /* CP_REG_AC_AMP_MODE__A */ + 0x01, 0x00, /* CP_REG_AC_AMP_FIX__A */ + + WR16(CP_REG_INTERVAL__A, 0x0005), + WR16(CP_REG_RT_EXP_MARG__A, 0x0004), + WR16(CP_REG_AC_ANG_MODE__A, 0x0003), + + WR16(CP_REG_COMM_EXEC__A, 0x0001), + END_OF_TABLE +}; + +u8 DRXD_InitCPB1[] = { + WR16(B_CP_REG_BR_SPL_OFFSET__A, 0x0008), + WR16(B_CP_COMM_EXEC__A, 0x0001), + END_OF_TABLE +}; + +u8 DRXD_InitCEA2[] = { + WRBLOCK(CE_REG_AVG_POW__A, 4), + 0x62, 0x00, /* CE_REG_AVG_POW__A */ + 0x78, 0x00, /* CE_REG_MAX_POW__A */ + 0x62, 0x00, /* CE_REG_ATT__A */ + 0x17, 0x00, /* CE_REG_NRED__A */ + + WRBLOCK(CE_REG_NE_ERR_SELECT__A, 2), + 0x07, 0x00, /* CE_REG_NE_ERR_SELECT__A */ + 0xEB, 0xFF, /* CE_REG_NE_TD_CAL__A */ + + WRBLOCK(CE_REG_NE_MIXAVG__A, 2), + 0x06, 0x00, /* CE_REG_NE_MIXAVG__A */ + 0x00, 0x00, /* CE_REG_NE_NUPD_OFS__A */ + + WRBLOCK(CE_REG_PE_NEXP_OFFS__A, 2), + 0x00, 0x00, /* CE_REG_PE_NEXP_OFFS__A */ + 0x00, 0x00, /* CE_REG_PE_TIMESHIFT__A */ + + WRBLOCK(CE_REG_TP_A0_TAP_NEW__A, 3), + 0x00, 0x01, /* CE_REG_TP_A0_TAP_NEW__A */ + 0x01, 0x00, /* CE_REG_TP_A0_TAP_NEW_VALID__A */ + 0x0E, 0x00, /* CE_REG_TP_A0_MU_LMS_STEP__A */ + + WRBLOCK(CE_REG_TP_A1_TAP_NEW__A, 3), + 0x00, 0x00, /* CE_REG_TP_A1_TAP_NEW__A */ + 0x01, 0x00, /* CE_REG_TP_A1_TAP_NEW_VALID__A */ + 0x0A, 0x00, /* CE_REG_TP_A1_MU_LMS_STEP__A */ + + WRBLOCK(CE_REG_FI_SHT_INCR__A, 2), + 0x12, 0x00, /* CE_REG_FI_SHT_INCR__A */ + 0x0C, 0x00, /* CE_REG_FI_EXP_NORM__A */ + + WRBLOCK(CE_REG_IR_INPUTSEL__A, 3), + 0x00, 0x00, /* CE_REG_IR_INPUTSEL__A */ + 0x00, 0x00, /* CE_REG_IR_STARTPOS__A */ + 0xFF, 0x00, /* CE_REG_IR_NEXP_THRES__A */ + + WR16(CE_REG_TI_NEXP_OFFS__A, 0x0000), + + END_OF_TABLE +}; + +u8 DRXD_InitCEB1[] = { + WR16(B_CE_REG_TI_PHN_ENABLE__A, 0x0001), + WR16(B_CE_REG_FR_PM_SET__A, 0x000D), + + END_OF_TABLE +}; + +u8 DRXD_InitEQA2[] = { + WRBLOCK(EQ_REG_OT_QNT_THRES0__A, 4), + 0x1E, 0x00, /* EQ_REG_OT_QNT_THRES0__A */ + 0x1F, 0x00, /* EQ_REG_OT_QNT_THRES1__A */ + 0x06, 0x00, /* EQ_REG_OT_CSI_STEP__A */ + 0x02, 0x00, /* EQ_REG_OT_CSI_OFFSET__A */ + + WR16(EQ_REG_TD_REQ_SMB_CNT__A, 0x0200), + WR16(EQ_REG_IS_CLIP_EXP__A, 0x001F), + WR16(EQ_REG_SN_OFFSET__A, (u16) (-7)), + WR16(EQ_REG_RC_SEL_CAR__A, 0x0002), + WR16(EQ_REG_COMM_EXEC__A, 0x0001), + END_OF_TABLE +}; + +u8 DRXD_InitEQB1[] = { + WR16(B_EQ_REG_COMM_EXEC__A, 0x0001), + END_OF_TABLE +}; + +u8 DRXD_ResetECRAM[] = { + /* Reset packet sync bytes in EC_VD ram */ + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000), + + /* Reset packet sync bytes in EC_RS ram */ + WR16(EC_RS_EC_RAM__A, 0x0000), + WR16(EC_RS_EC_RAM__A + 204, 0x0000), + END_OF_TABLE +}; + +u8 DRXD_InitECA2[] = { + WRBLOCK(EC_SB_REG_CSI_HI__A, 6), + 0x1F, 0x00, /* EC_SB_REG_CSI_HI__A */ + 0x1E, 0x00, /* EC_SB_REG_CSI_LO__A */ + 0x01, 0x00, /* EC_SB_REG_SMB_TGL__A */ + 0x7F, 0x00, /* EC_SB_REG_SNR_HI__A */ + 0x7F, 0x00, /* EC_SB_REG_SNR_MID__A */ + 0x7F, 0x00, /* EC_SB_REG_SNR_LO__A */ + + WRBLOCK(EC_RS_REG_REQ_PCK_CNT__A, 2), + 0x00, 0x10, /* EC_RS_REG_REQ_PCK_CNT__A */ + DATA16(EC_RS_REG_VAL_PCK), /* EC_RS_REG_VAL__A */ + + WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5), + 0x03, 0x00, /* EC_OC_REG_TMD_TOP_MODE__A */ + 0xF4, 0x01, /* EC_OC_REG_TMD_TOP_CNT__A */ + 0xC0, 0x03, /* EC_OC_REG_TMD_HIL_MAR__A */ + 0x40, 0x00, /* EC_OC_REG_TMD_LOL_MAR__A */ + 0x03, 0x00, /* EC_OC_REG_TMD_CUR_CNT__A */ + + WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2), + 0x06, 0x00, /* EC_OC_REG_AVR_ASH_CNT__A */ + 0x02, 0x00, /* EC_OC_REG_AVR_BSH_CNT__A */ + + WRBLOCK(EC_OC_REG_RCN_MODE__A, 7), + 0x07, 0x00, /* EC_OC_REG_RCN_MODE__A */ + 0x00, 0x00, /* EC_OC_REG_RCN_CRA_LOP__A */ + 0xc0, 0x00, /* EC_OC_REG_RCN_CRA_HIP__A */ + 0x00, 0x10, /* EC_OC_REG_RCN_CST_LOP__A */ + 0x00, 0x00, /* EC_OC_REG_RCN_CST_HIP__A */ + 0xFF, 0x01, /* EC_OC_REG_RCN_SET_LVL__A */ + 0x0D, 0x00, /* EC_OC_REG_RCN_GAI_LVL__A */ + + WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2), + 0x00, 0x00, /* EC_OC_REG_RCN_CLP_LOP__A */ + 0xC0, 0x00, /* EC_OC_REG_RCN_CLP_HIP__A */ + + WR16(EC_SB_REG_CSI_OFS__A, 0x0001), + WR16(EC_VD_REG_FORCE__A, 0x0002), + WR16(EC_VD_REG_REQ_SMB_CNT__A, 0x0001), + WR16(EC_VD_REG_RLK_ENA__A, 0x0001), + WR16(EC_OD_REG_SYNC__A, 0x0664), + WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000), + WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C), + /* Output zero on monitorbus pads, power saving */ + WR16(EC_OC_REG_OCR_MON_UOS__A, + (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE | + EC_OC_REG_OCR_MON_UOS_VAL_ENABLE | + EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)), + WR16(EC_OC_REG_OCR_MON_WRI__A, + EC_OC_REG_OCR_MON_WRI_INIT), + +/* CHK_ERROR(ResetECRAM(demod)); */ + /* Reset packet sync bytes in EC_VD ram */ + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000), + + /* Reset packet sync bytes in EC_RS ram */ + WR16(EC_RS_EC_RAM__A, 0x0000), + WR16(EC_RS_EC_RAM__A + 204, 0x0000), + + WR16(EC_SB_REG_COMM_EXEC__A, 0x0001), + WR16(EC_VD_REG_COMM_EXEC__A, 0x0001), + WR16(EC_OD_REG_COMM_EXEC__A, 0x0001), + WR16(EC_RS_REG_COMM_EXEC__A, 0x0001), + END_OF_TABLE +}; + +u8 DRXD_InitECB1[] = { + WR16(B_EC_SB_REG_CSI_OFS0__A, 0x0001), + WR16(B_EC_SB_REG_CSI_OFS1__A, 0x0001), + WR16(B_EC_SB_REG_CSI_OFS2__A, 0x0001), + WR16(B_EC_SB_REG_CSI_LO__A, 0x000c), + WR16(B_EC_SB_REG_CSI_HI__A, 0x0018), + WR16(B_EC_SB_REG_SNR_HI__A, 0x007f), + WR16(B_EC_SB_REG_SNR_MID__A, 0x007f), + WR16(B_EC_SB_REG_SNR_LO__A, 0x007f), + + WR16(B_EC_OC_REG_DTO_CLKMODE__A, 0x0002), + WR16(B_EC_OC_REG_DTO_PER__A, 0x0006), + WR16(B_EC_OC_REG_DTO_BUR__A, 0x0001), + WR16(B_EC_OC_REG_RCR_CLKMODE__A, 0x0000), + WR16(B_EC_OC_REG_RCN_GAI_LVL__A, 0x000D), + WR16(B_EC_OC_REG_OC_MPG_SIO__A, 0x0000), + + /* Needed because shadow registers do not have correct default value */ + WR16(B_EC_OC_REG_RCN_CST_LOP__A, 0x1000), + WR16(B_EC_OC_REG_RCN_CST_HIP__A, 0x0000), + WR16(B_EC_OC_REG_RCN_CRA_LOP__A, 0x0000), + WR16(B_EC_OC_REG_RCN_CRA_HIP__A, 0x00C0), + WR16(B_EC_OC_REG_RCN_CLP_LOP__A, 0x0000), + WR16(B_EC_OC_REG_RCN_CLP_HIP__A, 0x00C0), + WR16(B_EC_OC_REG_DTO_INC_LOP__A, 0x0000), + WR16(B_EC_OC_REG_DTO_INC_HIP__A, 0x00C0), + + WR16(B_EC_OD_REG_SYNC__A, 0x0664), + WR16(B_EC_RS_REG_REQ_PCK_CNT__A, 0x1000), + +/* CHK_ERROR(ResetECRAM(demod)); */ + /* Reset packet sync bytes in EC_VD ram */ + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000), + + /* Reset packet sync bytes in EC_RS ram */ + WR16(EC_RS_EC_RAM__A, 0x0000), + WR16(EC_RS_EC_RAM__A + 204, 0x0000), + + WR16(B_EC_SB_REG_COMM_EXEC__A, 0x0001), + WR16(B_EC_VD_REG_COMM_EXEC__A, 0x0001), + WR16(B_EC_OD_REG_COMM_EXEC__A, 0x0001), + WR16(B_EC_RS_REG_COMM_EXEC__A, 0x0001), + END_OF_TABLE +}; + +u8 DRXD_ResetECA2[] = { + + WR16(EC_OC_REG_COMM_EXEC__A, 0x0000), + WR16(EC_OD_REG_COMM_EXEC__A, 0x0000), + + WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5), + 0x03, 0x00, /* EC_OC_REG_TMD_TOP_MODE__A */ + 0xF4, 0x01, /* EC_OC_REG_TMD_TOP_CNT__A */ + 0xC0, 0x03, /* EC_OC_REG_TMD_HIL_MAR__A */ + 0x40, 0x00, /* EC_OC_REG_TMD_LOL_MAR__A */ + 0x03, 0x00, /* EC_OC_REG_TMD_CUR_CNT__A */ + + WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2), + 0x06, 0x00, /* EC_OC_REG_AVR_ASH_CNT__A */ + 0x02, 0x00, /* EC_OC_REG_AVR_BSH_CNT__A */ + + WRBLOCK(EC_OC_REG_RCN_MODE__A, 7), + 0x07, 0x00, /* EC_OC_REG_RCN_MODE__A */ + 0x00, 0x00, /* EC_OC_REG_RCN_CRA_LOP__A */ + 0xc0, 0x00, /* EC_OC_REG_RCN_CRA_HIP__A */ + 0x00, 0x10, /* EC_OC_REG_RCN_CST_LOP__A */ + 0x00, 0x00, /* EC_OC_REG_RCN_CST_HIP__A */ + 0xFF, 0x01, /* EC_OC_REG_RCN_SET_LVL__A */ + 0x0D, 0x00, /* EC_OC_REG_RCN_GAI_LVL__A */ + + WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2), + 0x00, 0x00, /* EC_OC_REG_RCN_CLP_LOP__A */ + 0xC0, 0x00, /* EC_OC_REG_RCN_CLP_HIP__A */ + + WR16(EC_OD_REG_SYNC__A, 0x0664), + WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000), + WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C), + /* Output zero on monitorbus pads, power saving */ + WR16(EC_OC_REG_OCR_MON_UOS__A, + (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE | + EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE | + EC_OC_REG_OCR_MON_UOS_VAL_ENABLE | + EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)), + WR16(EC_OC_REG_OCR_MON_WRI__A, + EC_OC_REG_OCR_MON_WRI_INIT), + +/* CHK_ERROR(ResetECRAM(demod)); */ + /* Reset packet sync bytes in EC_VD ram */ + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000), + WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000), + + /* Reset packet sync bytes in EC_RS ram */ + WR16(EC_RS_EC_RAM__A, 0x0000), + WR16(EC_RS_EC_RAM__A + 204, 0x0000), + + WR16(EC_OD_REG_COMM_EXEC__A, 0x0001), + END_OF_TABLE +}; + +u8 DRXD_InitSC[] = { + WR16(SC_COMM_EXEC__A, 0), + WR16(SC_COMM_STATE__A, 0), + +#ifdef COMPILE_FOR_QT + WR16(SC_RA_RAM_BE_OPT_DELAY__A, 0x100), +#endif + + /* SC is not started, this is done in SetChannels() */ + END_OF_TABLE +}; + +/* Diversity settings */ + +u8 DRXD_InitDiversityFront[] = { + /* Start demod ********* RF in , diversity out **************************** */ + WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M | + B_SC_RA_RAM_CONFIG_FREQSCAN__M), + + WR16(B_SC_RA_RAM_LC_ABS_2K__A, 0x7), + WR16(B_SC_RA_RAM_LC_ABS_8K__A, 0x7), + WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K), + WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)), + WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)), + WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K), + WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)), + WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)), + + WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K), + WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)), + WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)), + WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K), + WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)), + WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)), + + WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7), + WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4), + WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7), + WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4), + WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500), + + WR16(B_CC_REG_DIVERSITY__A, 0x0001), + WR16(B_EC_OC_REG_OC_MODE_HIP__A, 0x0010), + WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE | + B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE), + + /* 0x2a ), *//* CE to PASS mux */ + + END_OF_TABLE +}; + +u8 DRXD_InitDiversityEnd[] = { + /* End demod *********** combining RF in and diversity in, MPEG TS out **** */ + /* disable near/far; switch on timing slave mode */ + WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M | + B_SC_RA_RAM_CONFIG_FREQSCAN__M | + B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M | + B_SC_RA_RAM_CONFIG_SLAVE__M | + B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M +/* MV from CtrlDiversity */ + ), +#ifdef DRXDDIV_SRMM_SLAVING + WR16(SC_RA_RAM_LC_ABS_2K__A, 0x3c7), + WR16(SC_RA_RAM_LC_ABS_8K__A, 0x3c7), +#else + WR16(SC_RA_RAM_LC_ABS_2K__A, 0x7), + WR16(SC_RA_RAM_LC_ABS_8K__A, 0x7), +#endif + + WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K), + WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)), + WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)), + WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K), + WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)), + WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)), + + WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K), + WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)), + WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)), + WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K), + WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)), + WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)), + + WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7), + WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4), + WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7), + WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4), + WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500), + + WR16(B_CC_REG_DIVERSITY__A, 0x0001), + END_OF_TABLE +}; + +u8 DRXD_DisableDiversity[] = { + WR16(B_SC_RA_RAM_LC_ABS_2K__A, B_SC_RA_RAM_LC_ABS_2K__PRE), + WR16(B_SC_RA_RAM_LC_ABS_8K__A, B_SC_RA_RAM_LC_ABS_8K__PRE), + WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, + B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE), + WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, + B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE), + WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, + B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE), + WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, + B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE), + WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, + B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE), + WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, + B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE), + + WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, + B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE), + WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, + B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE), + WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, + B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE), + WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, + B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE), + WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, + B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE), + WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, + B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE), + + WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, B_LC_RA_RAM_FILTER_CRMM_A__PRE), + WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, B_LC_RA_RAM_FILTER_CRMM_B__PRE), + WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, B_LC_RA_RAM_FILTER_SRMM_A__PRE), + WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, B_LC_RA_RAM_FILTER_SRMM_B__PRE), + WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, B_LC_RA_RAM_FILTER_SYM_SET__PRE), + + WR16(B_CC_REG_DIVERSITY__A, 0x0000), + WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_INIT), /* combining disabled */ + + END_OF_TABLE +}; + +u8 DRXD_StartDiversityFront[] = { + /* Start demod, RF in and diversity out, no combining */ + WR16(B_FE_CF_REG_IMP_VAL__A, 0x0), + WR16(B_FE_AD_REG_FDB_IN__A, 0x0), + WR16(B_FE_AD_REG_INVEXT__A, 0x0), + WR16(B_EQ_REG_COMM_MB__A, 0x12), /* EQ to MB out */ + WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE | /* CE to PASS mux */ + B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE), + + WR16(SC_RA_RAM_ECHO_SHIFT_LIM__A, 2), + + END_OF_TABLE +}; + +u8 DRXD_StartDiversityEnd[] = { + /* End demod, combining RF in and diversity in, MPEG TS out */ + WR16(B_FE_CF_REG_IMP_VAL__A, 0x0), /* disable impulse noise cruncher */ + WR16(B_FE_AD_REG_INVEXT__A, 0x0), /* clock inversion (for sohard board) */ + WR16(B_CP_REG_BR_STR_DEL__A, 10), /* apperently no mb delay matching is best */ + + WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_DIV_ON | /* org = 0x81 combining enabled */ + B_EQ_REG_RC_SEL_CAR_MEAS_A_CC | + B_EQ_REG_RC_SEL_CAR_PASS_A_CC | B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC), + + END_OF_TABLE +}; + +u8 DRXD_DiversityDelay8MHZ[] = { + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1150 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1100 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 1000 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 800 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5420 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5200 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4800 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 4000 - 50), + END_OF_TABLE +}; + +u8 DRXD_DiversityDelay6MHZ[] = /* also used ok for 7 MHz */ +{ + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1100 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1000 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 900 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 600 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5300 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5000 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4500 - 50), + WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 3500 - 50), + END_OF_TABLE +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_firm.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_firm.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_firm.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_firm.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,115 @@ +/* + * drxd_firm.h + * + * Copyright (C) 2006-2007 Micronas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _DRXD_FIRM_H_ +#define _DRXD_FIRM_H_ + +#include +#include "drxd_map_firm.h" + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 4 +#define VERSION_PATCH 23 + +#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A + +#define DRXD_MAX_RETRIES (1000) +#define HI_I2C_DELAY 84 +#define HI_I2C_BRIDGE_DELAY 750 + +#define EQ_TD_TPS_PWR_UNKNOWN 0x00C0 /* Unknown configurations */ +#define EQ_TD_TPS_PWR_QPSK 0x016a +#define EQ_TD_TPS_PWR_QAM16_ALPHAN 0x0195 +#define EQ_TD_TPS_PWR_QAM16_ALPHA1 0x0195 +#define EQ_TD_TPS_PWR_QAM16_ALPHA2 0x011E +#define EQ_TD_TPS_PWR_QAM16_ALPHA4 0x01CE +#define EQ_TD_TPS_PWR_QAM64_ALPHAN 0x019F +#define EQ_TD_TPS_PWR_QAM64_ALPHA1 0x019F +#define EQ_TD_TPS_PWR_QAM64_ALPHA2 0x00F8 +#define EQ_TD_TPS_PWR_QAM64_ALPHA4 0x014D + +#define DRXD_DEF_AG_PWD_CONSUMER 0x000E +#define DRXD_DEF_AG_PWD_PRO 0x0000 +#define DRXD_DEF_AG_AGC_SIO 0x0000 + +#define DRXD_FE_CTRL_MAX 1023 + +#define DRXD_OSCDEV_DO_SCAN (16) + +#define DRXD_OSCDEV_DONT_SCAN (0) + +#define DRXD_OSCDEV_STEP (275) + +#define DRXD_SCAN_TIMEOUT (650) + +#define DRXD_BANDWIDTH_8MHZ_IN_HZ (0x8B8249L) +#define DRXD_BANDWIDTH_7MHZ_IN_HZ (0x7A1200L) +#define DRXD_BANDWIDTH_6MHZ_IN_HZ (0x68A1B6L) + +#define IRLEN_COARSE_8K (10) +#define IRLEN_FINE_8K (10) +#define IRLEN_COARSE_2K (7) +#define IRLEN_FINE_2K (9) +#define DIFF_INVALID (511) +#define DIFF_TARGET (4) +#define DIFF_MARGIN (1) + +extern u8 DRXD_InitAtomicRead[]; +extern u8 DRXD_HiI2cPatch_1[]; +extern u8 DRXD_HiI2cPatch_3[]; + +extern u8 DRXD_InitSC[]; + +extern u8 DRXD_ResetCEFR[]; +extern u8 DRXD_InitFEA2_1[]; +extern u8 DRXD_InitFEA2_2[]; +extern u8 DRXD_InitCPA2[]; +extern u8 DRXD_InitCEA2[]; +extern u8 DRXD_InitEQA2[]; +extern u8 DRXD_InitECA2[]; +extern u8 DRXD_ResetECA2[]; +extern u8 DRXD_ResetECRAM[]; + +extern u8 DRXD_A2_microcode[]; +extern u32 DRXD_A2_microcode_length; + +extern u8 DRXD_InitFEB1_1[]; +extern u8 DRXD_InitFEB1_2[]; +extern u8 DRXD_InitCPB1[]; +extern u8 DRXD_InitCEB1[]; +extern u8 DRXD_InitEQB1[]; +extern u8 DRXD_InitECB1[]; + +extern u8 DRXD_InitDiversityFront[]; +extern u8 DRXD_InitDiversityEnd[]; +extern u8 DRXD_DisableDiversity[]; +extern u8 DRXD_StartDiversityFront[]; +extern u8 DRXD_StartDiversityEnd[]; + +extern u8 DRXD_DiversityDelay8MHZ[]; +extern u8 DRXD_DiversityDelay6MHZ[]; + +extern u8 DRXD_B1_microcode[]; +extern u32 DRXD_B1_microcode_length; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * drxd.h: DRXD DVB-T demodulator driver + * + * Copyright (C) 2005-2007 Micronas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _DRXD_H_ +#define _DRXD_H_ + +#include +#include + +struct drxd_config { + u8 index; + + u8 pll_address; + u8 pll_type; +#define DRXD_PLL_NONE 0 +#define DRXD_PLL_DTT7520X 1 +#define DRXD_PLL_MT3X0823 2 + + u32 clock; + u8 insert_rs_byte; + + u8 demod_address; + u8 demoda_address; + u8 demod_revision; + + /* If the tuner is not behind an i2c gate, be sure to flip this bit + or else the i2c bus could get wedged */ + u8 disable_i2c_gate_ctrl; + + u32 IF; + int (*pll_set) (void *priv, void *priv_params, + u8 pll_addr, u8 demoda_addr, s32 *off); + s16(*osc_deviation) (void *priv, s16 dev, int flag); +}; + +extern +struct dvb_frontend *drxd_attach(const struct drxd_config *config, + void *priv, struct i2c_adapter *i2c, + struct device *dev); +extern int drxd_config_i2c(struct dvb_frontend *, int); +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_hard.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_hard.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_hard.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_hard.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,3001 @@ +/* + * drxd_hard.c: DVB-T Demodulator Micronas DRX3975D-A2,DRX397xD-B1 + * + * Copyright (C) 2003-2007 Micronas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "drxd.h" +#include "drxd_firm.h" + +#define DRX_FW_FILENAME_A2 "drxd-a2-1.1.fw" +#define DRX_FW_FILENAME_B1 "drxd-b1-1.1.fw" + +#define CHUNK_SIZE 48 + +#define DRX_I2C_RMW 0x10 +#define DRX_I2C_BROADCAST 0x20 +#define DRX_I2C_CLEARCRC 0x80 +#define DRX_I2C_SINGLE_MASTER 0xC0 +#define DRX_I2C_MODEFLAGS 0xC0 +#define DRX_I2C_FLAGS 0xF0 + +#ifndef SIZEOF_ARRAY +#define SIZEOF_ARRAY(array) (sizeof((array))/sizeof((array)[0])) +#endif + +#define DEFAULT_LOCK_TIMEOUT 1100 + +#define DRX_CHANNEL_AUTO 0 +#define DRX_CHANNEL_HIGH 1 +#define DRX_CHANNEL_LOW 2 + +#define DRX_LOCK_MPEG 1 +#define DRX_LOCK_FEC 2 +#define DRX_LOCK_DEMOD 4 + +/****************************************************************************/ + +enum CSCDState { + CSCD_INIT = 0, + CSCD_SET, + CSCD_SAVED +}; + +enum CDrxdState { + DRXD_UNINITIALIZED = 0, + DRXD_STOPPED, + DRXD_STARTED +}; + +enum AGC_CTRL_MODE { + AGC_CTRL_AUTO = 0, + AGC_CTRL_USER, + AGC_CTRL_OFF +}; + +enum OperationMode { + OM_Default, + OM_DVBT_Diversity_Front, + OM_DVBT_Diversity_End +}; + +struct SCfgAgc { + enum AGC_CTRL_MODE ctrlMode; + u16 outputLevel; /* range [0, ... , 1023], 1/n of fullscale range */ + u16 settleLevel; /* range [0, ... , 1023], 1/n of fullscale range */ + u16 minOutputLevel; /* range [0, ... , 1023], 1/n of fullscale range */ + u16 maxOutputLevel; /* range [0, ... , 1023], 1/n of fullscale range */ + u16 speed; /* range [0, ... , 1023], 1/n of fullscale range */ + + u16 R1; + u16 R2; + u16 R3; +}; + +struct SNoiseCal { + int cpOpt; + u16 cpNexpOfs; + u16 tdCal2k; + u16 tdCal8k; +}; + +enum app_env { + APPENV_STATIC = 0, + APPENV_PORTABLE = 1, + APPENV_MOBILE = 2 +}; + +enum EIFFilter { + IFFILTER_SAW = 0, + IFFILTER_DISCRETE = 1 +}; + +struct drxd_state { + struct dvb_frontend frontend; + struct dvb_frontend_ops ops; + struct dvb_frontend_parameters param; + + const struct firmware *fw; + struct device *dev; + + struct i2c_adapter *i2c; + void *priv; + struct drxd_config config; + + int i2c_access; + int init_done; + struct mutex mutex; + + u8 chip_adr; + u16 hi_cfg_timing_div; + u16 hi_cfg_bridge_delay; + u16 hi_cfg_wakeup_key; + u16 hi_cfg_ctrl; + + u16 intermediate_freq; + u16 osc_clock_freq; + + enum CSCDState cscd_state; + enum CDrxdState drxd_state; + + u16 sys_clock_freq; + s16 osc_clock_deviation; + u16 expected_sys_clock_freq; + + u16 insert_rs_byte; + u16 enable_parallel; + + int operation_mode; + + struct SCfgAgc if_agc_cfg; + struct SCfgAgc rf_agc_cfg; + + struct SNoiseCal noise_cal; + + u32 fe_fs_add_incr; + u32 org_fe_fs_add_incr; + u16 current_fe_if_incr; + + u16 m_FeAgRegAgPwd; + u16 m_FeAgRegAgAgcSio; + + u16 m_EcOcRegOcModeLop; + u16 m_EcOcRegSncSncLvl; + u8 *m_InitAtomicRead; + u8 *m_HiI2cPatch; + + u8 *m_ResetCEFR; + u8 *m_InitFE_1; + u8 *m_InitFE_2; + u8 *m_InitCP; + u8 *m_InitCE; + u8 *m_InitEQ; + u8 *m_InitSC; + u8 *m_InitEC; + u8 *m_ResetECRAM; + u8 *m_InitDiversityFront; + u8 *m_InitDiversityEnd; + u8 *m_DisableDiversity; + u8 *m_StartDiversityFront; + u8 *m_StartDiversityEnd; + + u8 *m_DiversityDelay8MHZ; + u8 *m_DiversityDelay6MHZ; + + u8 *microcode; + u32 microcode_length; + + int type_A; + int PGA; + int diversity; + int tuner_mirrors; + + enum app_env app_env_default; + enum app_env app_env_diversity; + +}; + +/****************************************************************************/ +/* I2C **********************************************************************/ +/****************************************************************************/ + +static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 * data, int len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len }; + + if (i2c_transfer(adap, &msg, 1) != 1) + return -1; + return 0; +} + +static int i2c_read(struct i2c_adapter *adap, + u8 adr, u8 *msg, int len, u8 *answ, int alen) +{ + struct i2c_msg msgs[2] = { + { + .addr = adr, .flags = 0, + .buf = msg, .len = len + }, { + .addr = adr, .flags = I2C_M_RD, + .buf = answ, .len = alen + } + }; + if (i2c_transfer(adap, msgs, 2) != 2) + return -1; + return 0; +} + +inline u32 MulDiv32(u32 a, u32 b, u32 c) +{ + u64 tmp64; + + tmp64 = (u64)a * (u64)b; + do_div(tmp64, c); + + return (u32) tmp64; +} + +static int Read16(struct drxd_state *state, u32 reg, u16 *data, u8 flags) +{ + u8 adr = state->config.demod_address; + u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff, + flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff + }; + u8 mm2[2]; + if (i2c_read(state->i2c, adr, mm1, 4, mm2, 2) < 0) + return -1; + if (data) + *data = mm2[0] | (mm2[1] << 8); + return mm2[0] | (mm2[1] << 8); +} + +static int Read32(struct drxd_state *state, u32 reg, u32 *data, u8 flags) +{ + u8 adr = state->config.demod_address; + u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff, + flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff + }; + u8 mm2[4]; + + if (i2c_read(state->i2c, adr, mm1, 4, mm2, 4) < 0) + return -1; + if (data) + *data = + mm2[0] | (mm2[1] << 8) | (mm2[2] << 16) | (mm2[3] << 24); + return 0; +} + +static int Write16(struct drxd_state *state, u32 reg, u16 data, u8 flags) +{ + u8 adr = state->config.demod_address; + u8 mm[6] = { reg & 0xff, (reg >> 16) & 0xff, + flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff, + data & 0xff, (data >> 8) & 0xff + }; + + if (i2c_write(state->i2c, adr, mm, 6) < 0) + return -1; + return 0; +} + +static int Write32(struct drxd_state *state, u32 reg, u32 data, u8 flags) +{ + u8 adr = state->config.demod_address; + u8 mm[8] = { reg & 0xff, (reg >> 16) & 0xff, + flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff, + data & 0xff, (data >> 8) & 0xff, + (data >> 16) & 0xff, (data >> 24) & 0xff + }; + + if (i2c_write(state->i2c, adr, mm, 8) < 0) + return -1; + return 0; +} + +static int write_chunk(struct drxd_state *state, + u32 reg, u8 *data, u32 len, u8 flags) +{ + u8 adr = state->config.demod_address; + u8 mm[CHUNK_SIZE + 4] = { reg & 0xff, (reg >> 16) & 0xff, + flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff + }; + int i; + + for (i = 0; i < len; i++) + mm[4 + i] = data[i]; + if (i2c_write(state->i2c, adr, mm, 4 + len) < 0) { + printk(KERN_ERR "error in write_chunk\n"); + return -1; + } + return 0; +} + +static int WriteBlock(struct drxd_state *state, + u32 Address, u16 BlockSize, u8 *pBlock, u8 Flags) +{ + while (BlockSize > 0) { + u16 Chunk = BlockSize > CHUNK_SIZE ? CHUNK_SIZE : BlockSize; + + if (write_chunk(state, Address, pBlock, Chunk, Flags) < 0) + return -1; + pBlock += Chunk; + Address += (Chunk >> 1); + BlockSize -= Chunk; + } + return 0; +} + +static int WriteTable(struct drxd_state *state, u8 * pTable) +{ + int status = 0; + + if (pTable == NULL) + return 0; + + while (!status) { + u16 Length; + u32 Address = pTable[0] | (pTable[1] << 8) | + (pTable[2] << 16) | (pTable[3] << 24); + + if (Address == 0xFFFFFFFF) + break; + pTable += sizeof(u32); + + Length = pTable[0] | (pTable[1] << 8); + pTable += sizeof(u16); + if (!Length) + break; + status = WriteBlock(state, Address, Length * 2, pTable, 0); + pTable += (Length * 2); + } + return status; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static int ResetCEFR(struct drxd_state *state) +{ + return WriteTable(state, state->m_ResetCEFR); +} + +static int InitCP(struct drxd_state *state) +{ + return WriteTable(state, state->m_InitCP); +} + +static int InitCE(struct drxd_state *state) +{ + int status; + enum app_env AppEnv = state->app_env_default; + + do { + status = WriteTable(state, state->m_InitCE); + if (status < 0) + break; + + if (state->operation_mode == OM_DVBT_Diversity_Front || + state->operation_mode == OM_DVBT_Diversity_End) { + AppEnv = state->app_env_diversity; + } + if (AppEnv == APPENV_STATIC) { + status = Write16(state, CE_REG_TAPSET__A, 0x0000, 0); + if (status < 0) + break; + } else if (AppEnv == APPENV_PORTABLE) { + status = Write16(state, CE_REG_TAPSET__A, 0x0001, 0); + if (status < 0) + break; + } else if (AppEnv == APPENV_MOBILE && state->type_A) { + status = Write16(state, CE_REG_TAPSET__A, 0x0002, 0); + if (status < 0) + break; + } else if (AppEnv == APPENV_MOBILE && !state->type_A) { + status = Write16(state, CE_REG_TAPSET__A, 0x0006, 0); + if (status < 0) + break; + } + + /* start ce */ + status = Write16(state, B_CE_REG_COMM_EXEC__A, 0x0001, 0); + if (status < 0) + break; + } while (0); + return status; +} + +static int StopOC(struct drxd_state *state) +{ + int status = 0; + u16 ocSyncLvl = 0; + u16 ocModeLop = state->m_EcOcRegOcModeLop; + u16 dtoIncLop = 0; + u16 dtoIncHip = 0; + + do { + /* Store output configuration */ + status = Read16(state, EC_OC_REG_SNC_ISC_LVL__A, &ocSyncLvl, 0); + if (status < 0) + break; + /* CHK_ERROR(Read16(EC_OC_REG_OC_MODE_LOP__A, &ocModeLop)); */ + state->m_EcOcRegSncSncLvl = ocSyncLvl; + /* m_EcOcRegOcModeLop = ocModeLop; */ + + /* Flush FIFO (byte-boundary) at fixed rate */ + status = Read16(state, EC_OC_REG_RCN_MAP_LOP__A, &dtoIncLop, 0); + if (status < 0) + break; + status = Read16(state, EC_OC_REG_RCN_MAP_HIP__A, &dtoIncHip, 0); + if (status < 0) + break; + status = Write16(state, EC_OC_REG_DTO_INC_LOP__A, dtoIncLop, 0); + if (status < 0) + break; + status = Write16(state, EC_OC_REG_DTO_INC_HIP__A, dtoIncHip, 0); + if (status < 0) + break; + ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M); + ocModeLop |= EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC; + status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0); + if (status < 0) + break; + status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0); + if (status < 0) + break; + + msleep(1); + /* Output pins to '0' */ + status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS__M, 0); + if (status < 0) + break; + + /* Force the OC out of sync */ + ocSyncLvl &= ~(EC_OC_REG_SNC_ISC_LVL_OSC__M); + status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, ocSyncLvl, 0); + if (status < 0) + break; + ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M); + ocModeLop |= EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE; + ocModeLop |= 0x2; /* Magically-out-of-sync */ + status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0); + if (status < 0) + break; + status = Write16(state, EC_OC_REG_COMM_INT_STA__A, 0x0, 0); + if (status < 0) + break; + status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0); + if (status < 0) + break; + } while (0); + + return status; +} + +static int StartOC(struct drxd_state *state) +{ + int status = 0; + + do { + /* Stop OC */ + status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0); + if (status < 0) + break; + + /* Restore output configuration */ + status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, state->m_EcOcRegSncSncLvl, 0); + if (status < 0) + break; + status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, state->m_EcOcRegOcModeLop, 0); + if (status < 0) + break; + + /* Output pins active again */ + status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS_INIT, 0); + if (status < 0) + break; + + /* Start OC */ + status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0); + if (status < 0) + break; + } while (0); + return status; +} + +static int InitEQ(struct drxd_state *state) +{ + return WriteTable(state, state->m_InitEQ); +} + +static int InitEC(struct drxd_state *state) +{ + return WriteTable(state, state->m_InitEC); +} + +static int InitSC(struct drxd_state *state) +{ + return WriteTable(state, state->m_InitSC); +} + +static int InitAtomicRead(struct drxd_state *state) +{ + return WriteTable(state, state->m_InitAtomicRead); +} + +static int CorrectSysClockDeviation(struct drxd_state *state); + +static int DRX_GetLockStatus(struct drxd_state *state, u32 * pLockStatus) +{ + u16 ScRaRamLock = 0; + const u16 mpeg_lock_mask = (SC_RA_RAM_LOCK_MPEG__M | + SC_RA_RAM_LOCK_FEC__M | + SC_RA_RAM_LOCK_DEMOD__M); + const u16 fec_lock_mask = (SC_RA_RAM_LOCK_FEC__M | + SC_RA_RAM_LOCK_DEMOD__M); + const u16 demod_lock_mask = SC_RA_RAM_LOCK_DEMOD__M; + + int status; + + *pLockStatus = 0; + + status = Read16(state, SC_RA_RAM_LOCK__A, &ScRaRamLock, 0x0000); + if (status < 0) { + printk(KERN_ERR "Can't read SC_RA_RAM_LOCK__A status = %08x\n", status); + return status; + } + + if (state->drxd_state != DRXD_STARTED) + return 0; + + if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask) { + *pLockStatus |= DRX_LOCK_MPEG; + CorrectSysClockDeviation(state); + } + + if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask) + *pLockStatus |= DRX_LOCK_FEC; + + if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask) + *pLockStatus |= DRX_LOCK_DEMOD; + return 0; +} + +/****************************************************************************/ + +static int SetCfgIfAgc(struct drxd_state *state, struct SCfgAgc *cfg) +{ + int status; + + if (cfg->outputLevel > DRXD_FE_CTRL_MAX) + return -1; + + if (cfg->ctrlMode == AGC_CTRL_USER) { + do { + u16 FeAgRegPm1AgcWri; + u16 FeAgRegAgModeLop; + + status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0); + if (status < 0) + break; + FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M); + FeAgRegAgModeLop |= FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC; + status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0); + if (status < 0) + break; + + FeAgRegPm1AgcWri = (u16) (cfg->outputLevel & + FE_AG_REG_PM1_AGC_WRI__M); + status = Write16(state, FE_AG_REG_PM1_AGC_WRI__A, FeAgRegPm1AgcWri, 0); + if (status < 0) + break; + } while (0); + } else if (cfg->ctrlMode == AGC_CTRL_AUTO) { + if (((cfg->maxOutputLevel) < (cfg->minOutputLevel)) || + ((cfg->maxOutputLevel) > DRXD_FE_CTRL_MAX) || + ((cfg->speed) > DRXD_FE_CTRL_MAX) || + ((cfg->settleLevel) > DRXD_FE_CTRL_MAX) + ) + return -1; + do { + u16 FeAgRegAgModeLop; + u16 FeAgRegEgcSetLvl; + u16 slope, offset; + + /* == Mode == */ + + status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0); + if (status < 0) + break; + FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M); + FeAgRegAgModeLop |= + FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC; + status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0); + if (status < 0) + break; + + /* == Settle level == */ + + FeAgRegEgcSetLvl = (u16) ((cfg->settleLevel >> 1) & + FE_AG_REG_EGC_SET_LVL__M); + status = Write16(state, FE_AG_REG_EGC_SET_LVL__A, FeAgRegEgcSetLvl, 0); + if (status < 0) + break; + + /* == Min/Max == */ + + slope = (u16) ((cfg->maxOutputLevel - + cfg->minOutputLevel) / 2); + offset = (u16) ((cfg->maxOutputLevel + + cfg->minOutputLevel) / 2 - 511); + + status = Write16(state, FE_AG_REG_GC1_AGC_RIC__A, slope, 0); + if (status < 0) + break; + status = Write16(state, FE_AG_REG_GC1_AGC_OFF__A, offset, 0); + if (status < 0) + break; + + /* == Speed == */ + { + const u16 maxRur = 8; + const u16 slowIncrDecLUT[] = { 3, 4, 4, 5, 6 }; + const u16 fastIncrDecLUT[] = { 14, 15, 15, 16, + 17, 18, 18, 19, + 20, 21, 22, 23, + 24, 26, 27, 28, + 29, 31 + }; + + u16 fineSteps = (DRXD_FE_CTRL_MAX + 1) / + (maxRur + 1); + u16 fineSpeed = (u16) (cfg->speed - + ((cfg->speed / + fineSteps) * + fineSteps)); + u16 invRurCount = (u16) (cfg->speed / + fineSteps); + u16 rurCount; + if (invRurCount > maxRur) { + rurCount = 0; + fineSpeed += fineSteps; + } else { + rurCount = maxRur - invRurCount; + } + + /* + fastInc = default * + (2^(fineSpeed/fineSteps)) + => range[default...2*default> + slowInc = default * + (2^(fineSpeed/fineSteps)) + */ + { + u16 fastIncrDec = + fastIncrDecLUT[fineSpeed / + ((fineSteps / + (14 + 1)) + 1)]; + u16 slowIncrDec = + slowIncrDecLUT[fineSpeed / + (fineSteps / + (3 + 1))]; + + status = Write16(state, FE_AG_REG_EGC_RUR_CNT__A, rurCount, 0); + if (status < 0) + break; + status = Write16(state, FE_AG_REG_EGC_FAS_INC__A, fastIncrDec, 0); + if (status < 0) + break; + status = Write16(state, FE_AG_REG_EGC_FAS_DEC__A, fastIncrDec, 0); + if (status < 0) + break; + status = Write16(state, FE_AG_REG_EGC_SLO_INC__A, slowIncrDec, 0); + if (status < 0) + break; + status = Write16(state, FE_AG_REG_EGC_SLO_DEC__A, slowIncrDec, 0); + if (status < 0) + break; + } + } + } while (0); + + } else { + /* No OFF mode for IF control */ + return -1; + } + return status; +} + +static int SetCfgRfAgc(struct drxd_state *state, struct SCfgAgc *cfg) +{ + int status = 0; + + if (cfg->outputLevel > DRXD_FE_CTRL_MAX) + return -1; + + if (cfg->ctrlMode == AGC_CTRL_USER) { + do { + u16 AgModeLop = 0; + u16 level = (cfg->outputLevel); + + if (level == DRXD_FE_CTRL_MAX) + level++; + + status = Write16(state, FE_AG_REG_PM2_AGC_WRI__A, level, 0x0000); + if (status < 0) + break; + + /*==== Mode ====*/ + + /* Powerdown PD2, WRI source */ + state->m_FeAgRegAgPwd &= ~(FE_AG_REG_AG_PWD_PWD_PD2__M); + state->m_FeAgRegAgPwd |= + FE_AG_REG_AG_PWD_PWD_PD2_DISABLE; + status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000); + if (status < 0) + break; + + status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000); + if (status < 0) + break; + AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M | + FE_AG_REG_AG_MODE_LOP_MODE_E__M)); + AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC | + FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC); + status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000); + if (status < 0) + break; + + /* enable AGC2 pin */ + { + u16 FeAgRegAgAgcSio = 0; + status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000); + if (status < 0) + break; + FeAgRegAgAgcSio &= + ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M); + FeAgRegAgAgcSio |= + FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT; + status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000); + if (status < 0) + break; + } + + } while (0); + } else if (cfg->ctrlMode == AGC_CTRL_AUTO) { + u16 AgModeLop = 0; + + do { + u16 level; + /* Automatic control */ + /* Powerup PD2, AGC2 as output, TGC source */ + (state->m_FeAgRegAgPwd) &= + ~(FE_AG_REG_AG_PWD_PWD_PD2__M); + (state->m_FeAgRegAgPwd) |= + FE_AG_REG_AG_PWD_PWD_PD2_DISABLE; + status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000); + if (status < 0) + break; + + status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000); + if (status < 0) + break; + AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M | + FE_AG_REG_AG_MODE_LOP_MODE_E__M)); + AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC | + FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC); + status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000); + if (status < 0) + break; + /* Settle level */ + level = (((cfg->settleLevel) >> 4) & + FE_AG_REG_TGC_SET_LVL__M); + status = Write16(state, FE_AG_REG_TGC_SET_LVL__A, level, 0x0000); + if (status < 0) + break; + + /* Min/max: don't care */ + + /* Speed: TODO */ + + /* enable AGC2 pin */ + { + u16 FeAgRegAgAgcSio = 0; + status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000); + if (status < 0) + break; + FeAgRegAgAgcSio &= + ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M); + FeAgRegAgAgcSio |= + FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT; + status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000); + if (status < 0) + break; + } + + } while (0); + } else { + u16 AgModeLop = 0; + + do { + /* No RF AGC control */ + /* Powerdown PD2, AGC2 as output, WRI source */ + (state->m_FeAgRegAgPwd) &= + ~(FE_AG_REG_AG_PWD_PWD_PD2__M); + (state->m_FeAgRegAgPwd) |= + FE_AG_REG_AG_PWD_PWD_PD2_ENABLE; + status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000); + if (status < 0) + break; + + status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000); + if (status < 0) + break; + AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M | + FE_AG_REG_AG_MODE_LOP_MODE_E__M)); + AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC | + FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC); + status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000); + if (status < 0) + break; + + /* set FeAgRegAgAgcSio AGC2 (RF) as input */ + { + u16 FeAgRegAgAgcSio = 0; + status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000); + if (status < 0) + break; + FeAgRegAgAgcSio &= + ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M); + FeAgRegAgAgcSio |= + FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT; + status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000); + if (status < 0) + break; + } + } while (0); + } + return status; +} + +static int ReadIFAgc(struct drxd_state *state, u32 * pValue) +{ + int status = 0; + + *pValue = 0; + if (state->if_agc_cfg.ctrlMode != AGC_CTRL_OFF) { + u16 Value; + status = Read16(state, FE_AG_REG_GC1_AGC_DAT__A, &Value, 0); + Value &= FE_AG_REG_GC1_AGC_DAT__M; + if (status >= 0) { + /* 3.3V + | + R1 + | + Vin - R3 - * -- Vout + | + R2 + | + GND + */ + u32 R1 = state->if_agc_cfg.R1; + u32 R2 = state->if_agc_cfg.R2; + u32 R3 = state->if_agc_cfg.R3; + + u32 Vmax = (3300 * R2) / (R1 + R2); + u32 Rpar = (R2 * R3) / (R3 + R2); + u32 Vmin = (3300 * Rpar) / (R1 + Rpar); + u32 Vout = Vmin + ((Vmax - Vmin) * Value) / 1024; + + *pValue = Vout; + } + } + return status; +} + +static int load_firmware(struct drxd_state *state, const char *fw_name) +{ + const struct firmware *fw; + + if (request_firmware(&fw, fw_name, state->dev) < 0) { + printk(KERN_ERR "drxd: firmware load failure [%s]\n", fw_name); + return -EIO; + } + + state->microcode = kzalloc(fw->size, GFP_KERNEL); + if (state->microcode == NULL) { + printk(KERN_ERR "drxd: firmware load failure: nomemory\n"); + return -ENOMEM; + } + + memcpy(state->microcode, fw->data, fw->size); + state->microcode_length = fw->size; + return 0; +} + +static int DownloadMicrocode(struct drxd_state *state, + const u8 *pMCImage, u32 Length) +{ + u8 *pSrc; + u16 Flags; + u32 Address; + u16 nBlocks; + u16 BlockSize; + u16 BlockCRC; + u32 offset = 0; + int i, status = 0; + + pSrc = (u8 *) pMCImage; + Flags = (pSrc[0] << 8) | pSrc[1]; + pSrc += sizeof(u16); + offset += sizeof(u16); + nBlocks = (pSrc[0] << 8) | pSrc[1]; + pSrc += sizeof(u16); + offset += sizeof(u16); + + for (i = 0; i < nBlocks; i++) { + Address = (pSrc[0] << 24) | (pSrc[1] << 16) | + (pSrc[2] << 8) | pSrc[3]; + pSrc += sizeof(u32); + offset += sizeof(u32); + + BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16); + pSrc += sizeof(u16); + offset += sizeof(u16); + + Flags = (pSrc[0] << 8) | pSrc[1]; + pSrc += sizeof(u16); + offset += sizeof(u16); + + BlockCRC = (pSrc[0] << 8) | pSrc[1]; + pSrc += sizeof(u16); + offset += sizeof(u16); + + status = WriteBlock(state, Address, BlockSize, + pSrc, DRX_I2C_CLEARCRC); + if (status < 0) + break; + pSrc += BlockSize; + offset += BlockSize; + } + + return status; +} + +static int HI_Command(struct drxd_state *state, u16 cmd, u16 * pResult) +{ + u32 nrRetries = 0; + u16 waitCmd; + int status; + + status = Write16(state, HI_RA_RAM_SRV_CMD__A, cmd, 0); + if (status < 0) + return status; + + do { + nrRetries += 1; + if (nrRetries > DRXD_MAX_RETRIES) { + status = -1; + break; + }; + status = Read16(state, HI_RA_RAM_SRV_CMD__A, &waitCmd, 0); + } while (waitCmd != 0); + + if (status >= 0) + status = Read16(state, HI_RA_RAM_SRV_RES__A, pResult, 0); + return status; +} + +static int HI_CfgCommand(struct drxd_state *state) +{ + int status = 0; + + mutex_lock(&state->mutex); + Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0); + Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, state->hi_cfg_timing_div, 0); + Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, state->hi_cfg_bridge_delay, 0); + Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, state->hi_cfg_wakeup_key, 0); + Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, state->hi_cfg_ctrl, 0); + + Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0); + + if ((state->hi_cfg_ctrl & HI_RA_RAM_SRV_CFG_ACT_PWD_EXE) == + HI_RA_RAM_SRV_CFG_ACT_PWD_EXE) + status = Write16(state, HI_RA_RAM_SRV_CMD__A, + HI_RA_RAM_SRV_CMD_CONFIG, 0); + else + status = HI_Command(state, HI_RA_RAM_SRV_CMD_CONFIG, 0); + mutex_unlock(&state->mutex); + return status; +} + +static int InitHI(struct drxd_state *state) +{ + state->hi_cfg_wakeup_key = (state->chip_adr); + /* port/bridge/power down ctrl */ + state->hi_cfg_ctrl = HI_RA_RAM_SRV_CFG_ACT_SLV0_ON; + return HI_CfgCommand(state); +} + +static int HI_ResetCommand(struct drxd_state *state) +{ + int status; + + mutex_lock(&state->mutex); + status = Write16(state, HI_RA_RAM_SRV_RST_KEY__A, + HI_RA_RAM_SRV_RST_KEY_ACT, 0); + if (status == 0) + status = HI_Command(state, HI_RA_RAM_SRV_CMD_RESET, 0); + mutex_unlock(&state->mutex); + msleep(1); + return status; +} + +static int DRX_ConfigureI2CBridge(struct drxd_state *state, int bEnableBridge) +{ + state->hi_cfg_ctrl &= (~HI_RA_RAM_SRV_CFG_ACT_BRD__M); + if (bEnableBridge) + state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_ON; + else + state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_OFF; + + return HI_CfgCommand(state); +} + +#define HI_TR_WRITE 0x9 +#define HI_TR_READ 0xA +#define HI_TR_READ_WRITE 0xB +#define HI_TR_BROADCAST 0x4 + +#if 0 +static int AtomicReadBlock(struct drxd_state *state, + u32 Addr, u16 DataSize, u8 *pData, u8 Flags) +{ + int status; + int i = 0; + + /* Parameter check */ + if ((!pData) || ((DataSize & 1) != 0)) + return -1; + + mutex_lock(&state->mutex); + + do { + /* Instruct HI to read n bytes */ + /* TODO use proper names forthese egisters */ + status = Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, (HI_TR_FUNC_ADDR & 0xFFFF), 0); + if (status < 0) + break; + status = Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, (u16) (Addr >> 16), 0); + if (status < 0) + break; + status = Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, (u16) (Addr & 0xFFFF), 0); + if (status < 0) + break; + status = Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, (u16) ((DataSize / 2) - 1), 0); + if (status < 0) + break; + status = Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, HI_TR_READ, 0); + if (status < 0) + break; + + status = HI_Command(state, HI_RA_RAM_SRV_CMD_EXECUTE, 0); + if (status < 0) + break; + + } while (0); + + if (status >= 0) { + for (i = 0; i < (DataSize / 2); i += 1) { + u16 word; + + status = Read16(state, (HI_RA_RAM_USR_BEGIN__A + i), + &word, 0); + if (status < 0) + break; + pData[2 * i] = (u8) (word & 0xFF); + pData[(2 * i) + 1] = (u8) (word >> 8); + } + } + mutex_unlock(&state->mutex); + return status; +} + +static int AtomicReadReg32(struct drxd_state *state, + u32 Addr, u32 *pData, u8 Flags) +{ + u8 buf[sizeof(u32)]; + int status; + + if (!pData) + return -1; + status = AtomicReadBlock(state, Addr, sizeof(u32), buf, Flags); + *pData = (((u32) buf[0]) << 0) + + (((u32) buf[1]) << 8) + + (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24); + return status; +} +#endif + +static int StopAllProcessors(struct drxd_state *state) +{ + return Write16(state, HI_COMM_EXEC__A, + SC_COMM_EXEC_CTL_STOP, DRX_I2C_BROADCAST); +} + +static int EnableAndResetMB(struct drxd_state *state) +{ + if (state->type_A) { + /* disable? monitor bus observe @ EC_OC */ + Write16(state, EC_OC_REG_OC_MON_SIO__A, 0x0000, 0x0000); + } + + /* do inverse broadcast, followed by explicit write to HI */ + Write16(state, HI_COMM_MB__A, 0x0000, DRX_I2C_BROADCAST); + Write16(state, HI_COMM_MB__A, 0x0000, 0x0000); + return 0; +} + +static int InitCC(struct drxd_state *state) +{ + if (state->osc_clock_freq == 0 || + state->osc_clock_freq > 20000 || + (state->osc_clock_freq % 4000) != 0) { + printk(KERN_ERR "invalid osc frequency %d\n", state->osc_clock_freq); + return -1; + } + + Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0); + Write16(state, CC_REG_PLL_MODE__A, CC_REG_PLL_MODE_BYPASS_PLL | + CC_REG_PLL_MODE_PUMP_CUR_12, 0); + Write16(state, CC_REG_REF_DIVIDE__A, state->osc_clock_freq / 4000, 0); + Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL, 0); + Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0); + + return 0; +} + +static int ResetECOD(struct drxd_state *state) +{ + int status = 0; + + if (state->type_A) + status = Write16(state, EC_OD_REG_SYNC__A, 0x0664, 0); + else + status = Write16(state, B_EC_OD_REG_SYNC__A, 0x0664, 0); + + if (!(status < 0)) + status = WriteTable(state, state->m_ResetECRAM); + if (!(status < 0)) + status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0001, 0); + return status; +} + +/* Configure PGA switch */ + +static int SetCfgPga(struct drxd_state *state, int pgaSwitch) +{ + int status; + u16 AgModeLop = 0; + u16 AgModeHip = 0; + do { + if (pgaSwitch) { + /* PGA on */ + /* fine gain */ + status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000); + if (status < 0) + break; + AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M)); + AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC; + status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000); + if (status < 0) + break; + + /* coarse gain */ + status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000); + if (status < 0) + break; + AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M)); + AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC; + status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000); + if (status < 0) + break; + + /* enable fine and coarse gain, enable AAF, + no ext resistor */ + status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN, 0x0000); + if (status < 0) + break; + } else { + /* PGA off, bypass */ + + /* fine gain */ + status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000); + if (status < 0) + break; + AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M)); + AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC; + status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000); + if (status < 0) + break; + + /* coarse gain */ + status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000); + if (status < 0) + break; + AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M)); + AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC; + status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000); + if (status < 0) + break; + + /* disable fine and coarse gain, enable AAF, + no ext resistor */ + status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000); + if (status < 0) + break; + } + } while (0); + return status; +} + +static int InitFE(struct drxd_state *state) +{ + int status; + + do { + status = WriteTable(state, state->m_InitFE_1); + if (status < 0) + break; + + if (state->type_A) { + status = Write16(state, FE_AG_REG_AG_PGA_MODE__A, + FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, + 0); + } else { + if (state->PGA) + status = SetCfgPga(state, 0); + else + status = + Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, + B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, + 0); + } + + if (status < 0) + break; + status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, state->m_FeAgRegAgAgcSio, 0x0000); + if (status < 0) + break; + status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000); + if (status < 0) + break; + + status = WriteTable(state, state->m_InitFE_2); + if (status < 0) + break; + + } while (0); + + return status; +} + +static int InitFT(struct drxd_state *state) +{ + /* + norm OFFSET, MB says =2 voor 8K en =3 voor 2K waarschijnlijk + SC stuff + */ + return Write16(state, FT_REG_COMM_EXEC__A, 0x0001, 0x0000); +} + +static int SC_WaitForReady(struct drxd_state *state) +{ + u16 curCmd; + int i; + + for (i = 0; i < DRXD_MAX_RETRIES; i += 1) { + int status = Read16(state, SC_RA_RAM_CMD__A, &curCmd, 0); + if (status == 0 || curCmd == 0) + return status; + } + return -1; +} + +static int SC_SendCommand(struct drxd_state *state, u16 cmd) +{ + int status = 0; + u16 errCode; + + Write16(state, SC_RA_RAM_CMD__A, cmd, 0); + SC_WaitForReady(state); + + Read16(state, SC_RA_RAM_CMD_ADDR__A, &errCode, 0); + + if (errCode == 0xFFFF) { + printk(KERN_ERR "Command Error\n"); + status = -1; + } + + return status; +} + +static int SC_ProcStartCommand(struct drxd_state *state, + u16 subCmd, u16 param0, u16 param1) +{ + int status = 0; + u16 scExec; + + mutex_lock(&state->mutex); + do { + Read16(state, SC_COMM_EXEC__A, &scExec, 0); + if (scExec != 1) { + status = -1; + break; + } + SC_WaitForReady(state); + Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0); + Write16(state, SC_RA_RAM_PARAM1__A, param1, 0); + Write16(state, SC_RA_RAM_PARAM0__A, param0, 0); + + SC_SendCommand(state, SC_RA_RAM_CMD_PROC_START); + } while (0); + mutex_unlock(&state->mutex); + return status; +} + +static int SC_SetPrefParamCommand(struct drxd_state *state, + u16 subCmd, u16 param0, u16 param1) +{ + int status; + + mutex_lock(&state->mutex); + do { + status = SC_WaitForReady(state); + if (status < 0) + break; + status = Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0); + if (status < 0) + break; + status = Write16(state, SC_RA_RAM_PARAM1__A, param1, 0); + if (status < 0) + break; + status = Write16(state, SC_RA_RAM_PARAM0__A, param0, 0); + if (status < 0) + break; + + status = SC_SendCommand(state, SC_RA_RAM_CMD_SET_PREF_PARAM); + if (status < 0) + break; + } while (0); + mutex_unlock(&state->mutex); + return status; +} + +#if 0 +static int SC_GetOpParamCommand(struct drxd_state *state, u16 * result) +{ + int status = 0; + + mutex_lock(&state->mutex); + do { + status = SC_WaitForReady(state); + if (status < 0) + break; + status = SC_SendCommand(state, SC_RA_RAM_CMD_GET_OP_PARAM); + if (status < 0) + break; + status = Read16(state, SC_RA_RAM_PARAM0__A, result, 0); + if (status < 0) + break; + } while (0); + mutex_unlock(&state->mutex); + return status; +} +#endif + +static int ConfigureMPEGOutput(struct drxd_state *state, int bEnableOutput) +{ + int status; + + do { + u16 EcOcRegIprInvMpg = 0; + u16 EcOcRegOcModeLop = 0; + u16 EcOcRegOcModeHip = 0; + u16 EcOcRegOcMpgSio = 0; + + /*CHK_ERROR(Read16(state, EC_OC_REG_OC_MODE_LOP__A, &EcOcRegOcModeLop, 0)); */ + + if (state->operation_mode == OM_DVBT_Diversity_Front) { + if (bEnableOutput) { + EcOcRegOcModeHip |= + B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR; + } else + EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M; + EcOcRegOcModeLop |= + EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE; + } else { + EcOcRegOcModeLop = state->m_EcOcRegOcModeLop; + + if (bEnableOutput) + EcOcRegOcMpgSio &= (~(EC_OC_REG_OC_MPG_SIO__M)); + else + EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M; + + /* Don't Insert RS Byte */ + if (state->insert_rs_byte) { + EcOcRegOcModeLop &= + (~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M)); + EcOcRegOcModeHip &= + (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M); + EcOcRegOcModeHip |= + EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE; + } else { + EcOcRegOcModeLop |= + EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE; + EcOcRegOcModeHip &= + (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M); + EcOcRegOcModeHip |= + EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE; + } + + /* Mode = Parallel */ + if (state->enable_parallel) + EcOcRegOcModeLop &= + (~(EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M)); + else + EcOcRegOcModeLop |= + EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL; + } + /* Invert Data */ + /* EcOcRegIprInvMpg |= 0x00FF; */ + EcOcRegIprInvMpg &= (~(0x00FF)); + + /* Invert Error ( we don't use the pin ) */ + /* EcOcRegIprInvMpg |= 0x0100; */ + EcOcRegIprInvMpg &= (~(0x0100)); + + /* Invert Start ( we don't use the pin ) */ + /* EcOcRegIprInvMpg |= 0x0200; */ + EcOcRegIprInvMpg &= (~(0x0200)); + + /* Invert Valid ( we don't use the pin ) */ + /* EcOcRegIprInvMpg |= 0x0400; */ + EcOcRegIprInvMpg &= (~(0x0400)); + + /* Invert Clock */ + /* EcOcRegIprInvMpg |= 0x0800; */ + EcOcRegIprInvMpg &= (~(0x0800)); + + /* EcOcRegOcModeLop =0x05; */ + status = Write16(state, EC_OC_REG_IPR_INV_MPG__A, EcOcRegIprInvMpg, 0); + if (status < 0) + break; + status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, EcOcRegOcModeLop, 0); + if (status < 0) + break; + status = Write16(state, EC_OC_REG_OC_MODE_HIP__A, EcOcRegOcModeHip, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_OC_REG_OC_MPG_SIO__A, EcOcRegOcMpgSio, 0); + if (status < 0) + break; + } while (0); + return status; +} + +static int SetDeviceTypeId(struct drxd_state *state) +{ + int status = 0; + u16 deviceId = 0; + + do { + status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0); + if (status < 0) + break; + /* TODO: why twice? */ + status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0); + if (status < 0) + break; + printk(KERN_INFO "drxd: deviceId = %04x\n", deviceId); + + state->type_A = 0; + state->PGA = 0; + state->diversity = 0; + if (deviceId == 0) { /* on A2 only 3975 available */ + state->type_A = 1; + printk(KERN_INFO "DRX3975D-A2\n"); + } else { + deviceId >>= 12; + printk(KERN_INFO "DRX397%dD-B1\n", deviceId); + switch (deviceId) { + case 4: + state->diversity = 1; + case 3: + case 7: + state->PGA = 1; + break; + case 6: + state->diversity = 1; + case 5: + case 8: + break; + default: + status = -1; + break; + } + } + } while (0); + + if (status < 0) + return status; + + /* Init Table selection */ + state->m_InitAtomicRead = DRXD_InitAtomicRead; + state->m_InitSC = DRXD_InitSC; + state->m_ResetECRAM = DRXD_ResetECRAM; + if (state->type_A) { + state->m_ResetCEFR = DRXD_ResetCEFR; + state->m_InitFE_1 = DRXD_InitFEA2_1; + state->m_InitFE_2 = DRXD_InitFEA2_2; + state->m_InitCP = DRXD_InitCPA2; + state->m_InitCE = DRXD_InitCEA2; + state->m_InitEQ = DRXD_InitEQA2; + state->m_InitEC = DRXD_InitECA2; + if (load_firmware(state, DRX_FW_FILENAME_A2)) + return -EIO; + } else { + state->m_ResetCEFR = NULL; + state->m_InitFE_1 = DRXD_InitFEB1_1; + state->m_InitFE_2 = DRXD_InitFEB1_2; + state->m_InitCP = DRXD_InitCPB1; + state->m_InitCE = DRXD_InitCEB1; + state->m_InitEQ = DRXD_InitEQB1; + state->m_InitEC = DRXD_InitECB1; + if (load_firmware(state, DRX_FW_FILENAME_B1)) + return -EIO; + } + if (state->diversity) { + state->m_InitDiversityFront = DRXD_InitDiversityFront; + state->m_InitDiversityEnd = DRXD_InitDiversityEnd; + state->m_DisableDiversity = DRXD_DisableDiversity; + state->m_StartDiversityFront = DRXD_StartDiversityFront; + state->m_StartDiversityEnd = DRXD_StartDiversityEnd; + state->m_DiversityDelay8MHZ = DRXD_DiversityDelay8MHZ; + state->m_DiversityDelay6MHZ = DRXD_DiversityDelay6MHZ; + } else { + state->m_InitDiversityFront = NULL; + state->m_InitDiversityEnd = NULL; + state->m_DisableDiversity = NULL; + state->m_StartDiversityFront = NULL; + state->m_StartDiversityEnd = NULL; + state->m_DiversityDelay8MHZ = NULL; + state->m_DiversityDelay6MHZ = NULL; + } + + return status; +} + +static int CorrectSysClockDeviation(struct drxd_state *state) +{ + int status; + s32 incr = 0; + s32 nomincr = 0; + u32 bandwidth = 0; + u32 sysClockInHz = 0; + u32 sysClockFreq = 0; /* in kHz */ + s16 oscClockDeviation; + s16 Diff; + + do { + /* Retrieve bandwidth and incr, sanity check */ + + /* These accesses should be AtomicReadReg32, but that + causes trouble (at least for diversity */ + status = Read32(state, LC_RA_RAM_IFINCR_NOM_L__A, ((u32 *) &nomincr), 0); + if (status < 0) + break; + status = Read32(state, FE_IF_REG_INCR0__A, (u32 *) &incr, 0); + if (status < 0) + break; + + if (state->type_A) { + if ((nomincr - incr < -500) || (nomincr - incr > 500)) + break; + } else { + if ((nomincr - incr < -2000) || (nomincr - incr > 2000)) + break; + } + + switch (state->param.u.ofdm.bandwidth) { + case BANDWIDTH_8_MHZ: + bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ; + break; + case BANDWIDTH_7_MHZ: + bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ; + break; + case BANDWIDTH_6_MHZ: + bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ; + break; + default: + return -1; + break; + } + + /* Compute new sysclock value + sysClockFreq = (((incr + 2^23)*bandwidth)/2^21)/1000 */ + incr += (1 << 23); + sysClockInHz = MulDiv32(incr, bandwidth, 1 << 21); + sysClockFreq = (u32) (sysClockInHz / 1000); + /* rounding */ + if ((sysClockInHz % 1000) > 500) + sysClockFreq++; + + /* Compute clock deviation in ppm */ + oscClockDeviation = (u16) ((((s32) (sysClockFreq) - + (s32) + (state->expected_sys_clock_freq)) * + 1000000L) / + (s32) + (state->expected_sys_clock_freq)); + + Diff = oscClockDeviation - state->osc_clock_deviation; + /*printk(KERN_INFO "sysclockdiff=%d\n", Diff); */ + if (Diff >= -200 && Diff <= 200) { + state->sys_clock_freq = (u16) sysClockFreq; + if (oscClockDeviation != state->osc_clock_deviation) { + if (state->config.osc_deviation) { + state->config.osc_deviation(state->priv, + oscClockDeviation, + 1); + state->osc_clock_deviation = + oscClockDeviation; + } + } + /* switch OFF SRMM scan in SC */ + status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DONT_SCAN, 0); + if (status < 0) + break; + /* overrule FE_IF internal value for + proper re-locking */ + status = Write16(state, SC_RA_RAM_IF_SAVE__AX, state->current_fe_if_incr, 0); + if (status < 0) + break; + state->cscd_state = CSCD_SAVED; + } + } while (0); + + return status; +} + +static int DRX_Stop(struct drxd_state *state) +{ + int status; + + if (state->drxd_state != DRXD_STARTED) + return 0; + + do { + if (state->cscd_state != CSCD_SAVED) { + u32 lock; + status = DRX_GetLockStatus(state, &lock); + if (status < 0) + break; + } + + status = StopOC(state); + if (status < 0) + break; + + state->drxd_state = DRXD_STOPPED; + + status = ConfigureMPEGOutput(state, 0); + if (status < 0) + break; + + if (state->type_A) { + /* Stop relevant processors off the device */ + status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0x0000); + if (status < 0) + break; + + status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + } else { + /* Stop all processors except HI & CC & FE */ + status = Write16(state, B_SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + status = Write16(state, B_LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + status = Write16(state, B_FT_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + status = Write16(state, B_CP_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + status = Write16(state, B_CE_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + status = Write16(state, B_EQ_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0); + if (status < 0) + break; + } + + } while (0); + return status; +} + +int SetOperationMode(struct drxd_state *state, int oMode) +{ + int status; + + do { + if (state->drxd_state != DRXD_STOPPED) { + status = -1; + break; + } + + if (oMode == state->operation_mode) { + status = 0; + break; + } + + if (oMode != OM_Default && !state->diversity) { + status = -1; + break; + } + + switch (oMode) { + case OM_DVBT_Diversity_Front: + status = WriteTable(state, state->m_InitDiversityFront); + break; + case OM_DVBT_Diversity_End: + status = WriteTable(state, state->m_InitDiversityEnd); + break; + case OM_Default: + /* We need to check how to + get DRXD out of diversity */ + default: + status = WriteTable(state, state->m_DisableDiversity); + break; + } + } while (0); + + if (!status) + state->operation_mode = oMode; + return status; +} + +static int StartDiversity(struct drxd_state *state) +{ + int status = 0; + u16 rcControl; + + do { + if (state->operation_mode == OM_DVBT_Diversity_Front) { + status = WriteTable(state, state->m_StartDiversityFront); + if (status < 0) + break; + } else if (state->operation_mode == OM_DVBT_Diversity_End) { + status = WriteTable(state, state->m_StartDiversityEnd); + if (status < 0) + break; + if (state->param.u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + status = WriteTable(state, state->m_DiversityDelay8MHZ); + if (status < 0) + break; + } else { + status = WriteTable(state, state->m_DiversityDelay6MHZ); + if (status < 0) + break; + } + + status = Read16(state, B_EQ_REG_RC_SEL_CAR__A, &rcControl, 0); + if (status < 0) + break; + rcControl &= ~(B_EQ_REG_RC_SEL_CAR_FFTMODE__M); + rcControl |= B_EQ_REG_RC_SEL_CAR_DIV_ON | + /* combining enabled */ + B_EQ_REG_RC_SEL_CAR_MEAS_A_CC | + B_EQ_REG_RC_SEL_CAR_PASS_A_CC | + B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC; + status = Write16(state, B_EQ_REG_RC_SEL_CAR__A, rcControl, 0); + if (status < 0) + break; + } + } while (0); + return status; +} + +static int SetFrequencyShift(struct drxd_state *state, + u32 offsetFreq, int channelMirrored) +{ + int negativeShift = (state->tuner_mirrors == channelMirrored); + + /* Handle all mirroring + * + * Note: ADC mirroring (aliasing) is implictly handled by limiting + * feFsRegAddInc to 28 bits below + * (if the result before masking is more than 28 bits, this means + * that the ADC is mirroring. + * The masking is in fact the aliasing of the ADC) + * + */ + + /* Compute register value, unsigned computation */ + state->fe_fs_add_incr = MulDiv32(state->intermediate_freq + + offsetFreq, + 1 << 28, state->sys_clock_freq); + /* Remove integer part */ + state->fe_fs_add_incr &= 0x0FFFFFFFL; + if (negativeShift) + state->fe_fs_add_incr = ((1 << 28) - state->fe_fs_add_incr); + + /* Save the frequency shift without tunerOffset compensation + for CtrlGetChannel. */ + state->org_fe_fs_add_incr = MulDiv32(state->intermediate_freq, + 1 << 28, state->sys_clock_freq); + /* Remove integer part */ + state->org_fe_fs_add_incr &= 0x0FFFFFFFL; + if (negativeShift) + state->org_fe_fs_add_incr = ((1L << 28) - + state->org_fe_fs_add_incr); + + return Write32(state, FE_FS_REG_ADD_INC_LOP__A, + state->fe_fs_add_incr, 0); +} + +static int SetCfgNoiseCalibration(struct drxd_state *state, + struct SNoiseCal *noiseCal) +{ + u16 beOptEna; + int status = 0; + + do { + status = Read16(state, SC_RA_RAM_BE_OPT_ENA__A, &beOptEna, 0); + if (status < 0) + break; + if (noiseCal->cpOpt) { + beOptEna |= (1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT); + } else { + beOptEna &= ~(1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT); + status = Write16(state, CP_REG_AC_NEXP_OFFS__A, noiseCal->cpNexpOfs, 0); + if (status < 0) + break; + } + status = Write16(state, SC_RA_RAM_BE_OPT_ENA__A, beOptEna, 0); + if (status < 0) + break; + + if (!state->type_A) { + status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_2K__A, noiseCal->tdCal2k, 0); + if (status < 0) + break; + status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_8K__A, noiseCal->tdCal8k, 0); + if (status < 0) + break; + } + } while (0); + + return status; +} + +static int DRX_Start(struct drxd_state *state, s32 off) +{ + struct dvb_ofdm_parameters *p = &state->param.u.ofdm; + int status; + + u16 transmissionParams = 0; + u16 operationMode = 0; + u16 qpskTdTpsPwr = 0; + u16 qam16TdTpsPwr = 0; + u16 qam64TdTpsPwr = 0; + u32 feIfIncr = 0; + u32 bandwidth = 0; + int mirrorFreqSpect; + + u16 qpskSnCeGain = 0; + u16 qam16SnCeGain = 0; + u16 qam64SnCeGain = 0; + u16 qpskIsGainMan = 0; + u16 qam16IsGainMan = 0; + u16 qam64IsGainMan = 0; + u16 qpskIsGainExp = 0; + u16 qam16IsGainExp = 0; + u16 qam64IsGainExp = 0; + u16 bandwidthParam = 0; + + if (off < 0) + off = (off - 500) / 1000; + else + off = (off + 500) / 1000; + + do { + if (state->drxd_state != DRXD_STOPPED) + return -1; + status = ResetECOD(state); + if (status < 0) + break; + if (state->type_A) { + status = InitSC(state); + if (status < 0) + break; + } else { + status = InitFT(state); + if (status < 0) + break; + status = InitCP(state); + if (status < 0) + break; + status = InitCE(state); + if (status < 0) + break; + status = InitEQ(state); + if (status < 0) + break; + status = InitSC(state); + if (status < 0) + break; + } + + /* Restore current IF & RF AGC settings */ + + status = SetCfgIfAgc(state, &state->if_agc_cfg); + if (status < 0) + break; + status = SetCfgRfAgc(state, &state->rf_agc_cfg); + if (status < 0) + break; + + mirrorFreqSpect = (state->param.inversion == INVERSION_ON); + + switch (p->transmission_mode) { + default: /* Not set, detect it automatically */ + operationMode |= SC_RA_RAM_OP_AUTO_MODE__M; + /* fall through , try first guess DRX_FFTMODE_8K */ + case TRANSMISSION_MODE_8K: + transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_8K; + if (state->type_A) { + status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_8K, 0x0000); + if (status < 0) + break; + qpskSnCeGain = 99; + qam16SnCeGain = 83; + qam64SnCeGain = 67; + } + break; + case TRANSMISSION_MODE_2K: + transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_2K; + if (state->type_A) { + status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_2K, 0x0000); + if (status < 0) + break; + qpskSnCeGain = 97; + qam16SnCeGain = 71; + qam64SnCeGain = 65; + } + break; + } + + switch (p->guard_interval) { + case GUARD_INTERVAL_1_4: + transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4; + break; + case GUARD_INTERVAL_1_8: + transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_8; + break; + case GUARD_INTERVAL_1_16: + transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_16; + break; + case GUARD_INTERVAL_1_32: + transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_32; + break; + default: /* Not set, detect it automatically */ + operationMode |= SC_RA_RAM_OP_AUTO_GUARD__M; + /* try first guess 1/4 */ + transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4; + break; + } + + switch (p->hierarchy_information) { + case HIERARCHY_1: + transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1; + if (state->type_A) { + status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0001, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_ALPHA__A, 0x0001, 0x0000); + if (status < 0) + break; + + qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN; + qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA1; + qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA1; + + qpskIsGainMan = + SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE; + qam16IsGainMan = + SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE; + qam64IsGainMan = + SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE; + + qpskIsGainExp = + SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE; + qam16IsGainExp = + SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE; + qam64IsGainExp = + SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE; + } + break; + + case HIERARCHY_2: + transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A2; + if (state->type_A) { + status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0002, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_ALPHA__A, 0x0002, 0x0000); + if (status < 0) + break; + + qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN; + qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA2; + qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA2; + + qpskIsGainMan = + SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE; + qam16IsGainMan = + SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE; + qam64IsGainMan = + SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE; + + qpskIsGainExp = + SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE; + qam16IsGainExp = + SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE; + qam64IsGainExp = + SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE; + } + break; + case HIERARCHY_4: + transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A4; + if (state->type_A) { + status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0003, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_ALPHA__A, 0x0003, 0x0000); + if (status < 0) + break; + + qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN; + qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA4; + qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA4; + + qpskIsGainMan = + SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE; + qam16IsGainMan = + SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE; + qam64IsGainMan = + SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE; + + qpskIsGainExp = + SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE; + qam16IsGainExp = + SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE; + qam64IsGainExp = + SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE; + } + break; + case HIERARCHY_AUTO: + default: + /* Not set, detect it automatically, start with none */ + operationMode |= SC_RA_RAM_OP_AUTO_HIER__M; + transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_NO; + if (state->type_A) { + status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0000, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_ALPHA__A, 0x0000, 0x0000); + if (status < 0) + break; + + qpskTdTpsPwr = EQ_TD_TPS_PWR_QPSK; + qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHAN; + qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHAN; + + qpskIsGainMan = + SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE; + qam16IsGainMan = + SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE; + qam64IsGainMan = + SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE; + + qpskIsGainExp = + SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE; + qam16IsGainExp = + SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE; + qam64IsGainExp = + SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE; + } + break; + } + status = status; + if (status < 0) + break; + + switch (p->constellation) { + default: + operationMode |= SC_RA_RAM_OP_AUTO_CONST__M; + /* fall through , try first guess + DRX_CONSTELLATION_QAM64 */ + case QAM_64: + transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM64; + if (state->type_A) { + status = Write16(state, EQ_REG_OT_CONST__A, 0x0002, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_64QAM, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0020, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0008, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0002, 0x0000); + if (status < 0) + break; + + status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam64TdTpsPwr, 0x0000); + if (status < 0) + break; + status = Write16(state, EQ_REG_SN_CEGAIN__A, qam64SnCeGain, 0x0000); + if (status < 0) + break; + status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam64IsGainMan, 0x0000); + if (status < 0) + break; + status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam64IsGainExp, 0x0000); + if (status < 0) + break; + } + break; + case QPSK: + transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QPSK; + if (state->type_A) { + status = Write16(state, EQ_REG_OT_CONST__A, 0x0000, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_QPSK, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0000, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000); + if (status < 0) + break; + + status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qpskTdTpsPwr, 0x0000); + if (status < 0) + break; + status = Write16(state, EQ_REG_SN_CEGAIN__A, qpskSnCeGain, 0x0000); + if (status < 0) + break; + status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qpskIsGainMan, 0x0000); + if (status < 0) + break; + status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qpskIsGainExp, 0x0000); + if (status < 0) + break; + } + break; + + case QAM_16: + transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM16; + if (state->type_A) { + status = Write16(state, EQ_REG_OT_CONST__A, 0x0001, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_16QAM, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0004, 0x0000); + if (status < 0) + break; + status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000); + if (status < 0) + break; + + status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam16TdTpsPwr, 0x0000); + if (status < 0) + break; + status = Write16(state, EQ_REG_SN_CEGAIN__A, qam16SnCeGain, 0x0000); + if (status < 0) + break; + status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam16IsGainMan, 0x0000); + if (status < 0) + break; + status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam16IsGainExp, 0x0000); + if (status < 0) + break; + } + break; + + } + status = status; + if (status < 0) + break; + + switch (DRX_CHANNEL_HIGH) { + default: + case DRX_CHANNEL_AUTO: + case DRX_CHANNEL_LOW: + transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_LO; + status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_LO, 0x0000); + if (status < 0) + break; + break; + case DRX_CHANNEL_HIGH: + transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_HI; + status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_HI, 0x0000); + if (status < 0) + break; + break; + + } + + switch (p->code_rate_HP) { + case FEC_1_2: + transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_1_2; + if (state->type_A) { + status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C1_2, 0x0000); + if (status < 0) + break; + } + break; + default: + operationMode |= SC_RA_RAM_OP_AUTO_RATE__M; + case FEC_2_3: + transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_2_3; + if (state->type_A) { + status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C2_3, 0x0000); + if (status < 0) + break; + } + break; + case FEC_3_4: + transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_3_4; + if (state->type_A) { + status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C3_4, 0x0000); + if (status < 0) + break; + } + break; + case FEC_5_6: + transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_5_6; + if (state->type_A) { + status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C5_6, 0x0000); + if (status < 0) + break; + } + break; + case FEC_7_8: + transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_7_8; + if (state->type_A) { + status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C7_8, 0x0000); + if (status < 0) + break; + } + break; + } + status = status; + if (status < 0) + break; + + /* First determine real bandwidth (Hz) */ + /* Also set delay for impulse noise cruncher (only A2) */ + /* Also set parameters for EC_OC fix, note + EC_OC_REG_TMD_HIL_MAR is changed + by SC for fix for some 8K,1/8 guard but is restored by + InitEC and ResetEC + functions */ + switch (p->bandwidth) { + case BANDWIDTH_AUTO: + case BANDWIDTH_8_MHZ: + /* (64/7)*(8/8)*1000000 */ + bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ; + + bandwidthParam = 0; + status = Write16(state, + FE_AG_REG_IND_DEL__A, 50, 0x0000); + break; + case BANDWIDTH_7_MHZ: + /* (64/7)*(7/8)*1000000 */ + bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ; + bandwidthParam = 0x4807; /*binary:0100 1000 0000 0111 */ + status = Write16(state, + FE_AG_REG_IND_DEL__A, 59, 0x0000); + break; + case BANDWIDTH_6_MHZ: + /* (64/7)*(6/8)*1000000 */ + bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ; + bandwidthParam = 0x0F07; /*binary: 0000 1111 0000 0111 */ + status = Write16(state, + FE_AG_REG_IND_DEL__A, 71, 0x0000); + break; + default: + status = -EINVAL; + } + if (status < 0) + break; + + status = Write16(state, SC_RA_RAM_BAND__A, bandwidthParam, 0x0000); + if (status < 0) + break; + + { + u16 sc_config; + status = Read16(state, SC_RA_RAM_CONFIG__A, &sc_config, 0); + if (status < 0) + break; + + /* enable SLAVE mode in 2k 1/32 to + prevent timing change glitches */ + if ((p->transmission_mode == TRANSMISSION_MODE_2K) && + (p->guard_interval == GUARD_INTERVAL_1_32)) { + /* enable slave */ + sc_config |= SC_RA_RAM_CONFIG_SLAVE__M; + } else { + /* disable slave */ + sc_config &= ~SC_RA_RAM_CONFIG_SLAVE__M; + } + status = Write16(state, SC_RA_RAM_CONFIG__A, sc_config, 0); + if (status < 0) + break; + } + + status = SetCfgNoiseCalibration(state, &state->noise_cal); + if (status < 0) + break; + + if (state->cscd_state == CSCD_INIT) { + /* switch on SRMM scan in SC */ + status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DO_SCAN, 0x0000); + if (status < 0) + break; +/* CHK_ERROR(Write16(SC_RA_RAM_SAMPLE_RATE_STEP__A, DRXD_OSCDEV_STEP, 0x0000));*/ + state->cscd_state = CSCD_SET; + } + + /* Now compute FE_IF_REG_INCR */ + /*((( SysFreq/BandWidth)/2)/2) -1) * 2^23) => + ((SysFreq / BandWidth) * (2^21) ) - (2^23) */ + feIfIncr = MulDiv32(state->sys_clock_freq * 1000, + (1ULL << 21), bandwidth) - (1 << 23); + status = Write16(state, FE_IF_REG_INCR0__A, (u16) (feIfIncr & FE_IF_REG_INCR0__M), 0x0000); + if (status < 0) + break; + status = Write16(state, FE_IF_REG_INCR1__A, (u16) ((feIfIncr >> FE_IF_REG_INCR0__W) & FE_IF_REG_INCR1__M), 0x0000); + if (status < 0) + break; + /* Bandwidth setting done */ + + /* Mirror & frequency offset */ + SetFrequencyShift(state, off, mirrorFreqSpect); + + /* Start SC, write channel settings to SC */ + + /* Enable SC after setting all other parameters */ + status = Write16(state, SC_COMM_STATE__A, 0, 0x0000); + if (status < 0) + break; + status = Write16(state, SC_COMM_EXEC__A, 1, 0x0000); + if (status < 0) + break; + + /* Write SC parameter registers, operation mode */ +#if 1 + operationMode = (SC_RA_RAM_OP_AUTO_MODE__M | + SC_RA_RAM_OP_AUTO_GUARD__M | + SC_RA_RAM_OP_AUTO_CONST__M | + SC_RA_RAM_OP_AUTO_HIER__M | + SC_RA_RAM_OP_AUTO_RATE__M); +#endif + status = SC_SetPrefParamCommand(state, 0x0000, transmissionParams, operationMode); + if (status < 0) + break; + + /* Start correct processes to get in lock */ + status = SC_ProcStartCommand(state, SC_RA_RAM_PROC_LOCKTRACK, SC_RA_RAM_SW_EVENT_RUN_NMASK__M, SC_RA_RAM_LOCKTRACK_MIN); + if (status < 0) + break; + + status = StartOC(state); + if (status < 0) + break; + + if (state->operation_mode != OM_Default) { + status = StartDiversity(state); + if (status < 0) + break; + } + + state->drxd_state = DRXD_STARTED; + } while (0); + + return status; +} + +static int CDRXD(struct drxd_state *state, u32 IntermediateFrequency) +{ + u32 ulRfAgcOutputLevel = 0xffffffff; + u32 ulRfAgcSettleLevel = 528; /* Optimum value for MT2060 */ + u32 ulRfAgcMinLevel = 0; /* Currently unused */ + u32 ulRfAgcMaxLevel = DRXD_FE_CTRL_MAX; /* Currently unused */ + u32 ulRfAgcSpeed = 0; /* Currently unused */ + u32 ulRfAgcMode = 0; /*2; Off */ + u32 ulRfAgcR1 = 820; + u32 ulRfAgcR2 = 2200; + u32 ulRfAgcR3 = 150; + u32 ulIfAgcMode = 0; /* Auto */ + u32 ulIfAgcOutputLevel = 0xffffffff; + u32 ulIfAgcSettleLevel = 0xffffffff; + u32 ulIfAgcMinLevel = 0xffffffff; + u32 ulIfAgcMaxLevel = 0xffffffff; + u32 ulIfAgcSpeed = 0xffffffff; + u32 ulIfAgcR1 = 820; + u32 ulIfAgcR2 = 2200; + u32 ulIfAgcR3 = 150; + u32 ulClock = state->config.clock; + u32 ulSerialMode = 0; + u32 ulEcOcRegOcModeLop = 4; /* Dynamic DTO source */ + u32 ulHiI2cDelay = HI_I2C_DELAY; + u32 ulHiI2cBridgeDelay = HI_I2C_BRIDGE_DELAY; + u32 ulHiI2cPatch = 0; + u32 ulEnvironment = APPENV_PORTABLE; + u32 ulEnvironmentDiversity = APPENV_MOBILE; + u32 ulIFFilter = IFFILTER_SAW; + + state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO; + state->if_agc_cfg.outputLevel = 0; + state->if_agc_cfg.settleLevel = 140; + state->if_agc_cfg.minOutputLevel = 0; + state->if_agc_cfg.maxOutputLevel = 1023; + state->if_agc_cfg.speed = 904; + + if (ulIfAgcMode == 1 && ulIfAgcOutputLevel <= DRXD_FE_CTRL_MAX) { + state->if_agc_cfg.ctrlMode = AGC_CTRL_USER; + state->if_agc_cfg.outputLevel = (u16) (ulIfAgcOutputLevel); + } + + if (ulIfAgcMode == 0 && + ulIfAgcSettleLevel <= DRXD_FE_CTRL_MAX && + ulIfAgcMinLevel <= DRXD_FE_CTRL_MAX && + ulIfAgcMaxLevel <= DRXD_FE_CTRL_MAX && + ulIfAgcSpeed <= DRXD_FE_CTRL_MAX) { + state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO; + state->if_agc_cfg.settleLevel = (u16) (ulIfAgcSettleLevel); + state->if_agc_cfg.minOutputLevel = (u16) (ulIfAgcMinLevel); + state->if_agc_cfg.maxOutputLevel = (u16) (ulIfAgcMaxLevel); + state->if_agc_cfg.speed = (u16) (ulIfAgcSpeed); + } + + state->if_agc_cfg.R1 = (u16) (ulIfAgcR1); + state->if_agc_cfg.R2 = (u16) (ulIfAgcR2); + state->if_agc_cfg.R3 = (u16) (ulIfAgcR3); + + state->rf_agc_cfg.R1 = (u16) (ulRfAgcR1); + state->rf_agc_cfg.R2 = (u16) (ulRfAgcR2); + state->rf_agc_cfg.R3 = (u16) (ulRfAgcR3); + + state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO; + /* rest of the RFAgcCfg structure currently unused */ + if (ulRfAgcMode == 1 && ulRfAgcOutputLevel <= DRXD_FE_CTRL_MAX) { + state->rf_agc_cfg.ctrlMode = AGC_CTRL_USER; + state->rf_agc_cfg.outputLevel = (u16) (ulRfAgcOutputLevel); + } + + if (ulRfAgcMode == 0 && + ulRfAgcSettleLevel <= DRXD_FE_CTRL_MAX && + ulRfAgcMinLevel <= DRXD_FE_CTRL_MAX && + ulRfAgcMaxLevel <= DRXD_FE_CTRL_MAX && + ulRfAgcSpeed <= DRXD_FE_CTRL_MAX) { + state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO; + state->rf_agc_cfg.settleLevel = (u16) (ulRfAgcSettleLevel); + state->rf_agc_cfg.minOutputLevel = (u16) (ulRfAgcMinLevel); + state->rf_agc_cfg.maxOutputLevel = (u16) (ulRfAgcMaxLevel); + state->rf_agc_cfg.speed = (u16) (ulRfAgcSpeed); + } + + if (ulRfAgcMode == 2) + state->rf_agc_cfg.ctrlMode = AGC_CTRL_OFF; + + if (ulEnvironment <= 2) + state->app_env_default = (enum app_env) + (ulEnvironment); + if (ulEnvironmentDiversity <= 2) + state->app_env_diversity = (enum app_env) + (ulEnvironmentDiversity); + + if (ulIFFilter == IFFILTER_DISCRETE) { + /* discrete filter */ + state->noise_cal.cpOpt = 0; + state->noise_cal.cpNexpOfs = 40; + state->noise_cal.tdCal2k = -40; + state->noise_cal.tdCal8k = -24; + } else { + /* SAW filter */ + state->noise_cal.cpOpt = 1; + state->noise_cal.cpNexpOfs = 0; + state->noise_cal.tdCal2k = -21; + state->noise_cal.tdCal8k = -24; + } + state->m_EcOcRegOcModeLop = (u16) (ulEcOcRegOcModeLop); + + state->chip_adr = (state->config.demod_address << 1) | 1; + switch (ulHiI2cPatch) { + case 1: + state->m_HiI2cPatch = DRXD_HiI2cPatch_1; + break; + case 3: + state->m_HiI2cPatch = DRXD_HiI2cPatch_3; + break; + default: + state->m_HiI2cPatch = NULL; + } + + /* modify tuner and clock attributes */ + state->intermediate_freq = (u16) (IntermediateFrequency / 1000); + /* expected system clock frequency in kHz */ + state->expected_sys_clock_freq = 48000; + /* real system clock frequency in kHz */ + state->sys_clock_freq = 48000; + state->osc_clock_freq = (u16) ulClock; + state->osc_clock_deviation = 0; + state->cscd_state = CSCD_INIT; + state->drxd_state = DRXD_UNINITIALIZED; + + state->PGA = 0; + state->type_A = 0; + state->tuner_mirrors = 0; + + /* modify MPEG output attributes */ + state->insert_rs_byte = state->config.insert_rs_byte; + state->enable_parallel = (ulSerialMode != 1); + + /* Timing div, 250ns/Psys */ + /* Timing div, = ( delay (nano seconds) * sysclk (kHz) )/ 1000 */ + + state->hi_cfg_timing_div = (u16) ((state->sys_clock_freq / 1000) * + ulHiI2cDelay) / 1000; + /* Bridge delay, uses oscilator clock */ + /* Delay = ( delay (nano seconds) * oscclk (kHz) )/ 1000 */ + state->hi_cfg_bridge_delay = (u16) ((state->osc_clock_freq / 1000) * + ulHiI2cBridgeDelay) / 1000; + + state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER; + /* state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO; */ + state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO; + return 0; +} + +int DRXD_init(struct drxd_state *state, const u8 * fw, u32 fw_size) +{ + int status = 0; + u32 driverVersion; + + if (state->init_done) + return 0; + + CDRXD(state, state->config.IF ? state->config.IF : 36000000); + + do { + state->operation_mode = OM_Default; + + status = SetDeviceTypeId(state); + if (status < 0) + break; + + /* Apply I2c address patch to B1 */ + if (!state->type_A && state->m_HiI2cPatch != NULL) + status = WriteTable(state, state->m_HiI2cPatch); + if (status < 0) + break; + + if (state->type_A) { + /* HI firmware patch for UIO readout, + avoid clearing of result register */ + status = Write16(state, 0x43012D, 0x047f, 0); + if (status < 0) + break; + } + + status = HI_ResetCommand(state); + if (status < 0) + break; + + status = StopAllProcessors(state); + if (status < 0) + break; + status = InitCC(state); + if (status < 0) + break; + + state->osc_clock_deviation = 0; + + if (state->config.osc_deviation) + state->osc_clock_deviation = + state->config.osc_deviation(state->priv, 0, 0); + { + /* Handle clock deviation */ + s32 devB; + s32 devA = (s32) (state->osc_clock_deviation) * + (s32) (state->expected_sys_clock_freq); + /* deviation in kHz */ + s32 deviation = (devA / (1000000L)); + /* rounding, signed */ + if (devA > 0) + devB = (2); + else + devB = (-2); + if ((devB * (devA % 1000000L) > 1000000L)) { + /* add +1 or -1 */ + deviation += (devB / 2); + } + + state->sys_clock_freq = + (u16) ((state->expected_sys_clock_freq) + + deviation); + } + status = InitHI(state); + if (status < 0) + break; + status = InitAtomicRead(state); + if (status < 0) + break; + + status = EnableAndResetMB(state); + if (status < 0) + break; + if (state->type_A) + status = ResetCEFR(state); + if (status < 0) + break; + + if (fw) { + status = DownloadMicrocode(state, fw, fw_size); + if (status < 0) + break; + } else { + status = DownloadMicrocode(state, state->microcode, state->microcode_length); + if (status < 0) + break; + } + + if (state->PGA) { + state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO; + SetCfgPga(state, 0); /* PGA = 0 dB */ + } else { + state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER; + } + + state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO; + + status = InitFE(state); + if (status < 0) + break; + status = InitFT(state); + if (status < 0) + break; + status = InitCP(state); + if (status < 0) + break; + status = InitCE(state); + if (status < 0) + break; + status = InitEQ(state); + if (status < 0) + break; + status = InitEC(state); + if (status < 0) + break; + status = InitSC(state); + if (status < 0) + break; + + status = SetCfgIfAgc(state, &state->if_agc_cfg); + if (status < 0) + break; + status = SetCfgRfAgc(state, &state->rf_agc_cfg); + if (status < 0) + break; + + state->cscd_state = CSCD_INIT; + status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0); + if (status < 0) + break; + + driverVersion = (((VERSION_MAJOR / 10) << 4) + + (VERSION_MAJOR % 10)) << 24; + driverVersion += (((VERSION_MINOR / 10) << 4) + + (VERSION_MINOR % 10)) << 16; + driverVersion += ((VERSION_PATCH / 1000) << 12) + + ((VERSION_PATCH / 100) << 8) + + ((VERSION_PATCH / 10) << 4) + (VERSION_PATCH % 10); + + status = Write32(state, SC_RA_RAM_DRIVER_VERSION__AX, driverVersion, 0); + if (status < 0) + break; + + status = StopOC(state); + if (status < 0) + break; + + state->drxd_state = DRXD_STOPPED; + state->init_done = 1; + status = 0; + } while (0); + return status; +} + +int DRXD_status(struct drxd_state *state, u32 * pLockStatus) +{ + DRX_GetLockStatus(state, pLockStatus); + + /*if (*pLockStatus&DRX_LOCK_MPEG) */ + if (*pLockStatus & DRX_LOCK_FEC) { + ConfigureMPEGOutput(state, 1); + /* Get status again, in case we have MPEG lock now */ + /*DRX_GetLockStatus(state, pLockStatus); */ + } + + return 0; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static int drxd_read_signal_strength(struct dvb_frontend *fe, u16 * strength) +{ + struct drxd_state *state = fe->demodulator_priv; + u32 value; + int res; + + res = ReadIFAgc(state, &value); + if (res < 0) + *strength = 0; + else + *strength = 0xffff - (value << 4); + return 0; +} + +static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status) +{ + struct drxd_state *state = fe->demodulator_priv; + u32 lock; + + DRXD_status(state, &lock); + *status = 0; + /* No MPEG lock in V255 firmware, bug ? */ +#if 1 + if (lock & DRX_LOCK_MPEG) + *status |= FE_HAS_LOCK; +#else + if (lock & DRX_LOCK_FEC) + *status |= FE_HAS_LOCK; +#endif + if (lock & DRX_LOCK_FEC) + *status |= FE_HAS_VITERBI | FE_HAS_SYNC; + if (lock & DRX_LOCK_DEMOD) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + + return 0; +} + +static int drxd_init(struct dvb_frontend *fe) +{ + struct drxd_state *state = fe->demodulator_priv; + int err = 0; + +/* if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */ + return DRXD_init(state, 0, 0); + + err = DRXD_init(state, state->fw->data, state->fw->size); + release_firmware(state->fw); + return err; +} + +int drxd_config_i2c(struct dvb_frontend *fe, int onoff) +{ + struct drxd_state *state = fe->demodulator_priv; + + if (state->config.disable_i2c_gate_ctrl == 1) + return 0; + + return DRX_ConfigureI2CBridge(state, onoff); +} +EXPORT_SYMBOL(drxd_config_i2c); + +static int drxd_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *sets) +{ + sets->min_delay_ms = 10000; + sets->max_drift = 0; + sets->step_size = 0; + return 0; +} + +static int drxd_read_ber(struct dvb_frontend *fe, u32 * ber) +{ + *ber = 0; + return 0; +} + +static int drxd_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + *snr = 0; + return 0; +} + +static int drxd_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) +{ + *ucblocks = 0; + return 0; +} + +static int drxd_sleep(struct dvb_frontend *fe) +{ + struct drxd_state *state = fe->demodulator_priv; + + ConfigureMPEGOutput(state, 0); + return 0; +} + +static int drxd_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + return 0; +} + +static int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + return drxd_config_i2c(fe, enable); +} + +static int drxd_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct drxd_state *state = fe->demodulator_priv; + s32 off = 0; + + state->param = *param; + DRX_Stop(state); + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* FIXME: move PLL drivers */ + if (state->config.pll_set && + state->config.pll_set(state->priv, param, + state->config.pll_address, + state->config.demoda_address, &off) < 0) { + printk(KERN_ERR "Error in pll_set\n"); + return -1; + } + + msleep(200); + + return DRX_Start(state, off); +} + +static void drxd_release(struct dvb_frontend *fe) +{ + struct drxd_state *state = fe->demodulator_priv; + + kfree(state); +} + +static struct dvb_frontend_ops drxd_ops = { + + .info = { + .name = "Micronas DRXD DVB-T", + .type = FE_OFDM, + .frequency_min = 47125000, + .frequency_max = 855250000, + .frequency_stepsize = 166667, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS}, + + .release = drxd_release, + .init = drxd_init, + .sleep = drxd_sleep, + .i2c_gate_ctrl = drxd_i2c_gate_ctrl, + + .set_frontend = drxd_set_frontend, + .get_frontend = drxd_get_frontend, + .get_tune_settings = drxd_get_tune_settings, + + .read_status = drxd_read_status, + .read_ber = drxd_read_ber, + .read_signal_strength = drxd_read_signal_strength, + .read_snr = drxd_read_snr, + .read_ucblocks = drxd_read_ucblocks, +}; + +struct dvb_frontend *drxd_attach(const struct drxd_config *config, + void *priv, struct i2c_adapter *i2c, + struct device *dev) +{ + struct drxd_state *state = NULL; + + state = kmalloc(sizeof(struct drxd_state), GFP_KERNEL); + if (!state) + return NULL; + memset(state, 0, sizeof(*state)); + + memcpy(&state->ops, &drxd_ops, sizeof(struct dvb_frontend_ops)); + state->dev = dev; + state->config = *config; + state->i2c = i2c; + state->priv = priv; + + mutex_init(&state->mutex); + + if (Read16(state, 0, 0, 0) < 0) + goto error; + + memcpy(&state->frontend.ops, &drxd_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + ConfigureMPEGOutput(state, 0); + return &state->frontend; + +error: + printk(KERN_ERR "drxd: not found\n"); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(drxd_attach); + +MODULE_DESCRIPTION("DRXD driver"); +MODULE_AUTHOR("Micronas"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_map_firm.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_map_firm.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_map_firm.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/drxd_map_firm.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1013 @@ +/* + * drx3973d_map_firm.h + * + * Copyright (C) 2006-2007 Micronas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __DRX3973D_MAP__H__ +#define __DRX3973D_MAP__H__ + +/* + * Note: originally, this file contained 12000+ lines of data + * Probably a few lines for every firwmare assembler instruction. However, + * only a few defines were actually used. So, removed all uneeded lines. + * If ever needed, the other lines can be easily obtained via git history. + */ + +#define HI_COMM_EXEC__A 0x400000 +#define HI_COMM_MB__A 0x400002 +#define HI_CT_REG_COMM_STATE__A 0x410001 +#define HI_RA_RAM_SRV_RES__A 0x420031 +#define HI_RA_RAM_SRV_CMD__A 0x420032 +#define HI_RA_RAM_SRV_CMD_RESET 0x2 +#define HI_RA_RAM_SRV_CMD_CONFIG 0x3 +#define HI_RA_RAM_SRV_CMD_EXECUTE 0x6 +#define HI_RA_RAM_SRV_RST_KEY__A 0x420033 +#define HI_RA_RAM_SRV_RST_KEY_ACT 0x3973 +#define HI_RA_RAM_SRV_CFG_KEY__A 0x420033 +#define HI_RA_RAM_SRV_CFG_DIV__A 0x420034 +#define HI_RA_RAM_SRV_CFG_BDL__A 0x420035 +#define HI_RA_RAM_SRV_CFG_WUP__A 0x420036 +#define HI_RA_RAM_SRV_CFG_ACT__A 0x420037 +#define HI_RA_RAM_SRV_CFG_ACT_SLV0_ON 0x1 +#define HI_RA_RAM_SRV_CFG_ACT_BRD__M 0x4 +#define HI_RA_RAM_SRV_CFG_ACT_BRD_OFF 0x0 +#define HI_RA_RAM_SRV_CFG_ACT_BRD_ON 0x4 +#define HI_RA_RAM_SRV_CFG_ACT_PWD_EXE 0x8 +#define HI_RA_RAM_USR_BEGIN__A 0x420040 +#define HI_IF_RAM_TRP_BPT0__AX 0x430000 +#define HI_IF_RAM_USR_BEGIN__A 0x430200 +#define SC_COMM_EXEC__A 0x800000 +#define SC_COMM_EXEC_CTL_STOP 0x0 +#define SC_COMM_STATE__A 0x800001 +#define SC_RA_RAM_PARAM0__A 0x820040 +#define SC_RA_RAM_PARAM1__A 0x820041 +#define SC_RA_RAM_CMD_ADDR__A 0x820042 +#define SC_RA_RAM_CMD__A 0x820043 +#define SC_RA_RAM_CMD_PROC_START 0x1 +#define SC_RA_RAM_CMD_SET_PREF_PARAM 0x3 +#define SC_RA_RAM_CMD_GET_OP_PARAM 0x5 +#define SC_RA_RAM_SW_EVENT_RUN_NMASK__M 0x1 +#define SC_RA_RAM_LOCKTRACK_MIN 0x1 +#define SC_RA_RAM_OP_PARAM_MODE_2K 0x0 +#define SC_RA_RAM_OP_PARAM_MODE_8K 0x1 +#define SC_RA_RAM_OP_PARAM_GUARD_32 0x0 +#define SC_RA_RAM_OP_PARAM_GUARD_16 0x4 +#define SC_RA_RAM_OP_PARAM_GUARD_8 0x8 +#define SC_RA_RAM_OP_PARAM_GUARD_4 0xC +#define SC_RA_RAM_OP_PARAM_CONST_QPSK 0x0 +#define SC_RA_RAM_OP_PARAM_CONST_QAM16 0x10 +#define SC_RA_RAM_OP_PARAM_CONST_QAM64 0x20 +#define SC_RA_RAM_OP_PARAM_HIER_NO 0x0 +#define SC_RA_RAM_OP_PARAM_HIER_A1 0x40 +#define SC_RA_RAM_OP_PARAM_HIER_A2 0x80 +#define SC_RA_RAM_OP_PARAM_HIER_A4 0xC0 +#define SC_RA_RAM_OP_PARAM_RATE_1_2 0x0 +#define SC_RA_RAM_OP_PARAM_RATE_2_3 0x200 +#define SC_RA_RAM_OP_PARAM_RATE_3_4 0x400 +#define SC_RA_RAM_OP_PARAM_RATE_5_6 0x600 +#define SC_RA_RAM_OP_PARAM_RATE_7_8 0x800 +#define SC_RA_RAM_OP_PARAM_PRIO_HI 0x0 +#define SC_RA_RAM_OP_PARAM_PRIO_LO 0x1000 +#define SC_RA_RAM_OP_AUTO_MODE__M 0x1 +#define SC_RA_RAM_OP_AUTO_GUARD__M 0x2 +#define SC_RA_RAM_OP_AUTO_CONST__M 0x4 +#define SC_RA_RAM_OP_AUTO_HIER__M 0x8 +#define SC_RA_RAM_OP_AUTO_RATE__M 0x10 +#define SC_RA_RAM_LOCK__A 0x82004B +#define SC_RA_RAM_LOCK_DEMOD__M 0x1 +#define SC_RA_RAM_LOCK_FEC__M 0x2 +#define SC_RA_RAM_LOCK_MPEG__M 0x4 +#define SC_RA_RAM_BE_OPT_ENA__A 0x82004C +#define SC_RA_RAM_BE_OPT_ENA_CP_OPT 0x1 +#define SC_RA_RAM_BE_OPT_DELAY__A 0x82004D +#define SC_RA_RAM_CONFIG__A 0x820050 +#define SC_RA_RAM_CONFIG_FR_ENABLE__M 0x4 +#define SC_RA_RAM_CONFIG_FREQSCAN__M 0x10 +#define SC_RA_RAM_CONFIG_SLAVE__M 0x20 +#define SC_RA_RAM_IF_SAVE__AX 0x82008E +#define SC_RA_RAM_IR_COARSE_2K_LENGTH__A 0x8200D1 +#define SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE 0x9 +#define SC_RA_RAM_IR_COARSE_2K_FREQINC__A 0x8200D2 +#define SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE 0x4 +#define SC_RA_RAM_IR_COARSE_2K_KAISINC__A 0x8200D3 +#define SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE 0x100 +#define SC_RA_RAM_IR_COARSE_8K_LENGTH__A 0x8200D4 +#define SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE 0x8 +#define SC_RA_RAM_IR_COARSE_8K_FREQINC__A 0x8200D5 +#define SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE 0x8 +#define SC_RA_RAM_IR_COARSE_8K_KAISINC__A 0x8200D6 +#define SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE 0x200 +#define SC_RA_RAM_IR_FINE_2K_LENGTH__A 0x8200D7 +#define SC_RA_RAM_IR_FINE_2K_LENGTH__PRE 0x9 +#define SC_RA_RAM_IR_FINE_2K_FREQINC__A 0x8200D8 +#define SC_RA_RAM_IR_FINE_2K_FREQINC__PRE 0x4 +#define SC_RA_RAM_IR_FINE_2K_KAISINC__A 0x8200D9 +#define SC_RA_RAM_IR_FINE_2K_KAISINC__PRE 0x100 +#define SC_RA_RAM_IR_FINE_8K_LENGTH__A 0x8200DA +#define SC_RA_RAM_IR_FINE_8K_LENGTH__PRE 0xB +#define SC_RA_RAM_IR_FINE_8K_FREQINC__A 0x8200DB +#define SC_RA_RAM_IR_FINE_8K_FREQINC__PRE 0x1 +#define SC_RA_RAM_IR_FINE_8K_KAISINC__A 0x8200DC +#define SC_RA_RAM_IR_FINE_8K_KAISINC__PRE 0x40 +#define SC_RA_RAM_ECHO_SHIFT_LIM__A 0x8200DD +#define SC_RA_RAM_SAMPLE_RATE_COUNT__A 0x8200E8 +#define SC_RA_RAM_SAMPLE_RATE_STEP__A 0x8200E9 +#define SC_RA_RAM_BAND__A 0x8200EC +#define SC_RA_RAM_LC_ABS_2K__A 0x8200F4 +#define SC_RA_RAM_LC_ABS_2K__PRE 0x1F +#define SC_RA_RAM_LC_ABS_8K__A 0x8200F5 +#define SC_RA_RAM_LC_ABS_8K__PRE 0x1F +#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE 0x1D6 +#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE 0x4 +#define SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE 0x1BB +#define SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE 0x5 +#define SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE 0x1EF +#define SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE 0x5 +#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE 0x15E +#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE 0x5 +#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE 0x11A +#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE 0x6 +#define SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE 0x1FB +#define SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE 0x5 +#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE 0x12F +#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE 0x5 +#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE 0x197 +#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE 0x5 +#define SC_RA_RAM_DRIVER_VERSION__AX 0x8201FE +#define SC_RA_RAM_PROC_LOCKTRACK 0x0 +#define FE_COMM_EXEC__A 0xC00000 +#define FE_AD_REG_COMM_EXEC__A 0xC10000 +#define FE_AD_REG_FDB_IN__A 0xC10012 +#define FE_AD_REG_PD__A 0xC10013 +#define FE_AD_REG_INVEXT__A 0xC10014 +#define FE_AD_REG_CLKNEG__A 0xC10015 +#define FE_AG_REG_COMM_EXEC__A 0xC20000 +#define FE_AG_REG_AG_MODE_LOP__A 0xC20010 +#define FE_AG_REG_AG_MODE_LOP_MODE_4__M 0x10 +#define FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC 0x0 +#define FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC 0x10 +#define FE_AG_REG_AG_MODE_LOP_MODE_5__M 0x20 +#define FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC 0x0 +#define FE_AG_REG_AG_MODE_LOP_MODE_C__M 0x1000 +#define FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC 0x0 +#define FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC 0x1000 +#define FE_AG_REG_AG_MODE_LOP_MODE_E__M 0x4000 +#define FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC 0x0 +#define FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC 0x4000 +#define FE_AG_REG_AG_MODE_HIP__A 0xC20011 +#define FE_AG_REG_AG_PGA_MODE__A 0xC20012 +#define FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN 0x0 +#define FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN 0x1 +#define FE_AG_REG_AG_AGC_SIO__A 0xC20013 +#define FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M 0x2 +#define FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT 0x0 +#define FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT 0x2 +#define FE_AG_REG_AG_PWD__A 0xC20015 +#define FE_AG_REG_AG_PWD_PWD_PD2__M 0x2 +#define FE_AG_REG_AG_PWD_PWD_PD2_DISABLE 0x0 +#define FE_AG_REG_AG_PWD_PWD_PD2_ENABLE 0x2 +#define FE_AG_REG_DCE_AUR_CNT__A 0xC20016 +#define FE_AG_REG_DCE_RUR_CNT__A 0xC20017 +#define FE_AG_REG_ACE_AUR_CNT__A 0xC2001A +#define FE_AG_REG_ACE_RUR_CNT__A 0xC2001B +#define FE_AG_REG_CDR_RUR_CNT__A 0xC20020 +#define FE_AG_REG_EGC_RUR_CNT__A 0xC20024 +#define FE_AG_REG_EGC_SET_LVL__A 0xC20025 +#define FE_AG_REG_EGC_SET_LVL__M 0x1FF +#define FE_AG_REG_EGC_FLA_RGN__A 0xC20026 +#define FE_AG_REG_EGC_SLO_RGN__A 0xC20027 +#define FE_AG_REG_EGC_JMP_PSN__A 0xC20028 +#define FE_AG_REG_EGC_FLA_INC__A 0xC20029 +#define FE_AG_REG_EGC_FLA_DEC__A 0xC2002A +#define FE_AG_REG_EGC_SLO_INC__A 0xC2002B +#define FE_AG_REG_EGC_SLO_DEC__A 0xC2002C +#define FE_AG_REG_EGC_FAS_INC__A 0xC2002D +#define FE_AG_REG_EGC_FAS_DEC__A 0xC2002E +#define FE_AG_REG_PM1_AGC_WRI__A 0xC20030 +#define FE_AG_REG_PM1_AGC_WRI__M 0x7FF +#define FE_AG_REG_GC1_AGC_RIC__A 0xC20031 +#define FE_AG_REG_GC1_AGC_OFF__A 0xC20032 +#define FE_AG_REG_GC1_AGC_MAX__A 0xC20033 +#define FE_AG_REG_GC1_AGC_MIN__A 0xC20034 +#define FE_AG_REG_GC1_AGC_DAT__A 0xC20035 +#define FE_AG_REG_GC1_AGC_DAT__M 0x3FF +#define FE_AG_REG_PM2_AGC_WRI__A 0xC20036 +#define FE_AG_REG_IND_WIN__A 0xC2003C +#define FE_AG_REG_IND_THD_LOL__A 0xC2003D +#define FE_AG_REG_IND_THD_HIL__A 0xC2003E +#define FE_AG_REG_IND_DEL__A 0xC2003F +#define FE_AG_REG_IND_PD1_WRI__A 0xC20040 +#define FE_AG_REG_PDA_AUR_CNT__A 0xC20041 +#define FE_AG_REG_PDA_RUR_CNT__A 0xC20042 +#define FE_AG_REG_PDA_AVE_DAT__A 0xC20043 +#define FE_AG_REG_PDC_RUR_CNT__A 0xC20044 +#define FE_AG_REG_PDC_SET_LVL__A 0xC20045 +#define FE_AG_REG_PDC_FLA_RGN__A 0xC20046 +#define FE_AG_REG_PDC_JMP_PSN__A 0xC20047 +#define FE_AG_REG_PDC_FLA_STP__A 0xC20048 +#define FE_AG_REG_PDC_SLO_STP__A 0xC20049 +#define FE_AG_REG_PDC_PD2_WRI__A 0xC2004A +#define FE_AG_REG_PDC_MAP_DAT__A 0xC2004B +#define FE_AG_REG_PDC_MAX__A 0xC2004C +#define FE_AG_REG_TGA_AUR_CNT__A 0xC2004D +#define FE_AG_REG_TGA_RUR_CNT__A 0xC2004E +#define FE_AG_REG_TGA_AVE_DAT__A 0xC2004F +#define FE_AG_REG_TGC_RUR_CNT__A 0xC20050 +#define FE_AG_REG_TGC_SET_LVL__A 0xC20051 +#define FE_AG_REG_TGC_SET_LVL__M 0x3F +#define FE_AG_REG_TGC_FLA_RGN__A 0xC20052 +#define FE_AG_REG_TGC_JMP_PSN__A 0xC20053 +#define FE_AG_REG_TGC_FLA_STP__A 0xC20054 +#define FE_AG_REG_TGC_SLO_STP__A 0xC20055 +#define FE_AG_REG_TGC_MAP_DAT__A 0xC20056 +#define FE_AG_REG_FGA_AUR_CNT__A 0xC20057 +#define FE_AG_REG_FGA_RUR_CNT__A 0xC20058 +#define FE_AG_REG_FGM_WRI__A 0xC20061 +#define FE_AG_REG_BGC_FGC_WRI__A 0xC20068 +#define FE_AG_REG_BGC_CGC_WRI__A 0xC20069 +#define FE_FS_REG_COMM_EXEC__A 0xC30000 +#define FE_FS_REG_ADD_INC_LOP__A 0xC30010 +#define FE_FD_REG_COMM_EXEC__A 0xC40000 +#define FE_FD_REG_SCL__A 0xC40010 +#define FE_FD_REG_MAX_LEV__A 0xC40011 +#define FE_FD_REG_NR__A 0xC40012 +#define FE_FD_REG_MEAS_VAL__A 0xC40014 +#define FE_IF_REG_COMM_EXEC__A 0xC50000 +#define FE_IF_REG_INCR0__A 0xC50010 +#define FE_IF_REG_INCR0__W 16 +#define FE_IF_REG_INCR0__M 0xFFFF +#define FE_IF_REG_INCR1__A 0xC50011 +#define FE_IF_REG_INCR1__M 0xFF +#define FE_CF_REG_COMM_EXEC__A 0xC60000 +#define FE_CF_REG_SCL__A 0xC60010 +#define FE_CF_REG_MAX_LEV__A 0xC60011 +#define FE_CF_REG_NR__A 0xC60012 +#define FE_CF_REG_IMP_VAL__A 0xC60013 +#define FE_CF_REG_MEAS_VAL__A 0xC60014 +#define FE_CU_REG_COMM_EXEC__A 0xC70000 +#define FE_CU_REG_FRM_CNT_RST__A 0xC70011 +#define FE_CU_REG_FRM_CNT_STR__A 0xC70012 +#define FT_COMM_EXEC__A 0x1000000 +#define FT_REG_COMM_EXEC__A 0x1010000 +#define CP_COMM_EXEC__A 0x1400000 +#define CP_REG_COMM_EXEC__A 0x1410000 +#define CP_REG_INTERVAL__A 0x1410011 +#define CP_REG_BR_SPL_OFFSET__A 0x1410023 +#define CP_REG_BR_STR_DEL__A 0x1410024 +#define CP_REG_RT_ANG_INC0__A 0x1410030 +#define CP_REG_RT_ANG_INC1__A 0x1410031 +#define CP_REG_RT_DETECT_ENA__A 0x1410032 +#define CP_REG_RT_DETECT_TRH__A 0x1410033 +#define CP_REG_RT_EXP_MARG__A 0x141003E +#define CP_REG_AC_NEXP_OFFS__A 0x1410040 +#define CP_REG_AC_AVER_POW__A 0x1410041 +#define CP_REG_AC_MAX_POW__A 0x1410042 +#define CP_REG_AC_WEIGHT_MAN__A 0x1410043 +#define CP_REG_AC_WEIGHT_EXP__A 0x1410044 +#define CP_REG_AC_AMP_MODE__A 0x1410047 +#define CP_REG_AC_AMP_FIX__A 0x1410048 +#define CP_REG_AC_ANG_MODE__A 0x141004A +#define CE_COMM_EXEC__A 0x1800000 +#define CE_REG_COMM_EXEC__A 0x1810000 +#define CE_REG_TAPSET__A 0x1810011 +#define CE_REG_AVG_POW__A 0x1810012 +#define CE_REG_MAX_POW__A 0x1810013 +#define CE_REG_ATT__A 0x1810014 +#define CE_REG_NRED__A 0x1810015 +#define CE_REG_NE_ERR_SELECT__A 0x1810043 +#define CE_REG_NE_TD_CAL__A 0x1810044 +#define CE_REG_NE_MIXAVG__A 0x1810046 +#define CE_REG_NE_NUPD_OFS__A 0x1810047 +#define CE_REG_PE_NEXP_OFFS__A 0x1810050 +#define CE_REG_PE_TIMESHIFT__A 0x1810051 +#define CE_REG_TP_A0_TAP_NEW__A 0x1810064 +#define CE_REG_TP_A0_TAP_NEW_VALID__A 0x1810065 +#define CE_REG_TP_A0_MU_LMS_STEP__A 0x1810066 +#define CE_REG_TP_A1_TAP_NEW__A 0x1810068 +#define CE_REG_TP_A1_TAP_NEW_VALID__A 0x1810069 +#define CE_REG_TP_A1_MU_LMS_STEP__A 0x181006A +#define CE_REG_TI_NEXP_OFFS__A 0x1810070 +#define CE_REG_FI_SHT_INCR__A 0x1810090 +#define CE_REG_FI_EXP_NORM__A 0x1810091 +#define CE_REG_IR_INPUTSEL__A 0x18100A0 +#define CE_REG_IR_STARTPOS__A 0x18100A1 +#define CE_REG_IR_NEXP_THRES__A 0x18100A2 +#define CE_REG_FR_TREAL00__A 0x1820010 +#define CE_REG_FR_TIMAG00__A 0x1820011 +#define CE_REG_FR_TREAL01__A 0x1820012 +#define CE_REG_FR_TIMAG01__A 0x1820013 +#define CE_REG_FR_TREAL02__A 0x1820014 +#define CE_REG_FR_TIMAG02__A 0x1820015 +#define CE_REG_FR_TREAL03__A 0x1820016 +#define CE_REG_FR_TIMAG03__A 0x1820017 +#define CE_REG_FR_TREAL04__A 0x1820018 +#define CE_REG_FR_TIMAG04__A 0x1820019 +#define CE_REG_FR_TREAL05__A 0x182001A +#define CE_REG_FR_TIMAG05__A 0x182001B +#define CE_REG_FR_TREAL06__A 0x182001C +#define CE_REG_FR_TIMAG06__A 0x182001D +#define CE_REG_FR_TREAL07__A 0x182001E +#define CE_REG_FR_TIMAG07__A 0x182001F +#define CE_REG_FR_TREAL08__A 0x1820020 +#define CE_REG_FR_TIMAG08__A 0x1820021 +#define CE_REG_FR_TREAL09__A 0x1820022 +#define CE_REG_FR_TIMAG09__A 0x1820023 +#define CE_REG_FR_TREAL10__A 0x1820024 +#define CE_REG_FR_TIMAG10__A 0x1820025 +#define CE_REG_FR_TREAL11__A 0x1820026 +#define CE_REG_FR_TIMAG11__A 0x1820027 +#define CE_REG_FR_MID_TAP__A 0x1820028 +#define CE_REG_FR_SQS_G00__A 0x1820029 +#define CE_REG_FR_SQS_G01__A 0x182002A +#define CE_REG_FR_SQS_G02__A 0x182002B +#define CE_REG_FR_SQS_G03__A 0x182002C +#define CE_REG_FR_SQS_G04__A 0x182002D +#define CE_REG_FR_SQS_G05__A 0x182002E +#define CE_REG_FR_SQS_G06__A 0x182002F +#define CE_REG_FR_SQS_G07__A 0x1820030 +#define CE_REG_FR_SQS_G08__A 0x1820031 +#define CE_REG_FR_SQS_G09__A 0x1820032 +#define CE_REG_FR_SQS_G10__A 0x1820033 +#define CE_REG_FR_SQS_G11__A 0x1820034 +#define CE_REG_FR_SQS_G12__A 0x1820035 +#define CE_REG_FR_RIO_G00__A 0x1820036 +#define CE_REG_FR_RIO_G01__A 0x1820037 +#define CE_REG_FR_RIO_G02__A 0x1820038 +#define CE_REG_FR_RIO_G03__A 0x1820039 +#define CE_REG_FR_RIO_G04__A 0x182003A +#define CE_REG_FR_RIO_G05__A 0x182003B +#define CE_REG_FR_RIO_G06__A 0x182003C +#define CE_REG_FR_RIO_G07__A 0x182003D +#define CE_REG_FR_RIO_G08__A 0x182003E +#define CE_REG_FR_RIO_G09__A 0x182003F +#define CE_REG_FR_RIO_G10__A 0x1820040 +#define CE_REG_FR_MODE__A 0x1820041 +#define CE_REG_FR_SQS_TRH__A 0x1820042 +#define CE_REG_FR_RIO_GAIN__A 0x1820043 +#define CE_REG_FR_BYPASS__A 0x1820044 +#define CE_REG_FR_PM_SET__A 0x1820045 +#define CE_REG_FR_ERR_SH__A 0x1820046 +#define CE_REG_FR_MAN_SH__A 0x1820047 +#define CE_REG_FR_TAP_SH__A 0x1820048 +#define EQ_COMM_EXEC__A 0x1C00000 +#define EQ_REG_COMM_EXEC__A 0x1C10000 +#define EQ_REG_COMM_MB__A 0x1C10002 +#define EQ_REG_IS_GAIN_MAN__A 0x1C10015 +#define EQ_REG_IS_GAIN_EXP__A 0x1C10016 +#define EQ_REG_IS_CLIP_EXP__A 0x1C10017 +#define EQ_REG_SN_CEGAIN__A 0x1C1002A +#define EQ_REG_SN_OFFSET__A 0x1C1002B +#define EQ_REG_RC_SEL_CAR__A 0x1C10032 +#define EQ_REG_RC_SEL_CAR_INIT 0x0 +#define EQ_REG_RC_SEL_CAR_DIV_ON 0x1 +#define EQ_REG_RC_SEL_CAR_PASS_A_CC 0x0 +#define EQ_REG_RC_SEL_CAR_PASS_B_CE 0x2 +#define EQ_REG_RC_SEL_CAR_LOCAL_A_CC 0x0 +#define EQ_REG_RC_SEL_CAR_LOCAL_B_CE 0x8 +#define EQ_REG_RC_SEL_CAR_MEAS_A_CC 0x0 +#define EQ_REG_RC_SEL_CAR_MEAS_B_CE 0x20 +#define EQ_REG_OT_CONST__A 0x1C10046 +#define EQ_REG_OT_ALPHA__A 0x1C10047 +#define EQ_REG_OT_QNT_THRES0__A 0x1C10048 +#define EQ_REG_OT_QNT_THRES1__A 0x1C10049 +#define EQ_REG_OT_CSI_STEP__A 0x1C1004A +#define EQ_REG_OT_CSI_OFFSET__A 0x1C1004B +#define EQ_REG_TD_REQ_SMB_CNT__A 0x1C10061 +#define EQ_REG_TD_TPS_PWR_OFS__A 0x1C10062 +#define EC_SB_REG_COMM_EXEC__A 0x2010000 +#define EC_SB_REG_TR_MODE__A 0x2010010 +#define EC_SB_REG_TR_MODE_8K 0x0 +#define EC_SB_REG_TR_MODE_2K 0x1 +#define EC_SB_REG_CONST__A 0x2010011 +#define EC_SB_REG_CONST_QPSK 0x0 +#define EC_SB_REG_CONST_16QAM 0x1 +#define EC_SB_REG_CONST_64QAM 0x2 +#define EC_SB_REG_ALPHA__A 0x2010012 +#define EC_SB_REG_PRIOR__A 0x2010013 +#define EC_SB_REG_PRIOR_HI 0x0 +#define EC_SB_REG_PRIOR_LO 0x1 +#define EC_SB_REG_CSI_HI__A 0x2010014 +#define EC_SB_REG_CSI_LO__A 0x2010015 +#define EC_SB_REG_SMB_TGL__A 0x2010016 +#define EC_SB_REG_SNR_HI__A 0x2010017 +#define EC_SB_REG_SNR_MID__A 0x2010018 +#define EC_SB_REG_SNR_LO__A 0x2010019 +#define EC_SB_REG_SCALE_MSB__A 0x201001A +#define EC_SB_REG_SCALE_BIT2__A 0x201001B +#define EC_SB_REG_SCALE_LSB__A 0x201001C +#define EC_SB_REG_CSI_OFS__A 0x201001D +#define EC_VD_REG_COMM_EXEC__A 0x2090000 +#define EC_VD_REG_FORCE__A 0x2090010 +#define EC_VD_REG_SET_CODERATE__A 0x2090011 +#define EC_VD_REG_SET_CODERATE_C1_2 0x0 +#define EC_VD_REG_SET_CODERATE_C2_3 0x1 +#define EC_VD_REG_SET_CODERATE_C3_4 0x2 +#define EC_VD_REG_SET_CODERATE_C5_6 0x3 +#define EC_VD_REG_SET_CODERATE_C7_8 0x4 +#define EC_VD_REG_REQ_SMB_CNT__A 0x2090012 +#define EC_VD_REG_RLK_ENA__A 0x2090014 +#define EC_OD_REG_COMM_EXEC__A 0x2110000 +#define EC_OD_REG_SYNC__A 0x2110010 +#define EC_OD_DEINT_RAM__A 0x2120000 +#define EC_RS_REG_COMM_EXEC__A 0x2130000 +#define EC_RS_REG_REQ_PCK_CNT__A 0x2130010 +#define EC_RS_REG_VAL__A 0x2130011 +#define EC_RS_REG_VAL_PCK 0x1 +#define EC_RS_EC_RAM__A 0x2140000 +#define EC_OC_REG_COMM_EXEC__A 0x2150000 +#define EC_OC_REG_COMM_EXEC_CTL_ACTIVE 0x1 +#define EC_OC_REG_COMM_EXEC_CTL_HOLD 0x2 +#define EC_OC_REG_COMM_INT_STA__A 0x2150007 +#define EC_OC_REG_OC_MODE_LOP__A 0x2150010 +#define EC_OC_REG_OC_MODE_LOP_PAR_ENA__M 0x1 +#define EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE 0x0 +#define EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE 0x1 +#define EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M 0x4 +#define EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC 0x0 +#define EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M 0x80 +#define EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL 0x80 +#define EC_OC_REG_OC_MODE_HIP__A 0x2150011 +#define EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR 0x10 +#define EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M 0x200 +#define EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE 0x0 +#define EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE 0x200 +#define EC_OC_REG_OC_MPG_SIO__A 0x2150012 +#define EC_OC_REG_OC_MPG_SIO__M 0xFFF +#define EC_OC_REG_OC_MON_SIO__A 0x2150013 +#define EC_OC_REG_DTO_INC_LOP__A 0x2150014 +#define EC_OC_REG_DTO_INC_HIP__A 0x2150015 +#define EC_OC_REG_SNC_ISC_LVL__A 0x2150016 +#define EC_OC_REG_SNC_ISC_LVL_OSC__M 0xF0 +#define EC_OC_REG_TMD_TOP_MODE__A 0x215001D +#define EC_OC_REG_TMD_TOP_CNT__A 0x215001E +#define EC_OC_REG_TMD_HIL_MAR__A 0x215001F +#define EC_OC_REG_TMD_LOL_MAR__A 0x2150020 +#define EC_OC_REG_TMD_CUR_CNT__A 0x2150021 +#define EC_OC_REG_AVR_ASH_CNT__A 0x2150023 +#define EC_OC_REG_AVR_BSH_CNT__A 0x2150024 +#define EC_OC_REG_RCN_MODE__A 0x2150027 +#define EC_OC_REG_RCN_CRA_LOP__A 0x2150028 +#define EC_OC_REG_RCN_CRA_HIP__A 0x2150029 +#define EC_OC_REG_RCN_CST_LOP__A 0x215002A +#define EC_OC_REG_RCN_CST_HIP__A 0x215002B +#define EC_OC_REG_RCN_SET_LVL__A 0x215002C +#define EC_OC_REG_RCN_GAI_LVL__A 0x215002D +#define EC_OC_REG_RCN_CLP_LOP__A 0x2150032 +#define EC_OC_REG_RCN_CLP_HIP__A 0x2150033 +#define EC_OC_REG_RCN_MAP_LOP__A 0x2150034 +#define EC_OC_REG_RCN_MAP_HIP__A 0x2150035 +#define EC_OC_REG_OCR_MPG_UOS__A 0x2150036 +#define EC_OC_REG_OCR_MPG_UOS__M 0xFFF +#define EC_OC_REG_OCR_MPG_UOS_INIT 0x0 +#define EC_OC_REG_OCR_MPG_USR_DAT__A 0x2150038 +#define EC_OC_REG_OCR_MON_UOS__A 0x2150039 +#define EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE 0x1 +#define EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE 0x2 +#define EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE 0x4 +#define EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE 0x8 +#define EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE 0x10 +#define EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE 0x20 +#define EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE 0x40 +#define EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE 0x80 +#define EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE 0x100 +#define EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE 0x200 +#define EC_OC_REG_OCR_MON_UOS_VAL_ENABLE 0x400 +#define EC_OC_REG_OCR_MON_UOS_CLK_ENABLE 0x800 +#define EC_OC_REG_OCR_MON_WRI__A 0x215003A +#define EC_OC_REG_OCR_MON_WRI_INIT 0x0 +#define EC_OC_REG_IPR_INV_MPG__A 0x2150045 +#define CC_REG_OSC_MODE__A 0x2410010 +#define CC_REG_OSC_MODE_M20 0x1 +#define CC_REG_PLL_MODE__A 0x2410011 +#define CC_REG_PLL_MODE_BYPASS_PLL 0x1 +#define CC_REG_PLL_MODE_PUMP_CUR_12 0x14 +#define CC_REG_REF_DIVIDE__A 0x2410012 +#define CC_REG_PWD_MODE__A 0x2410015 +#define CC_REG_PWD_MODE_DOWN_PLL 0x2 +#define CC_REG_UPDATE__A 0x2410017 +#define CC_REG_UPDATE_KEY 0x3973 +#define CC_REG_JTAGID_L__A 0x2410019 +#define LC_COMM_EXEC__A 0x2800000 +#define LC_RA_RAM_IFINCR_NOM_L__A 0x282000C +#define LC_RA_RAM_FILTER_SYM_SET__A 0x282001A +#define LC_RA_RAM_FILTER_SYM_SET__PRE 0x3E8 +#define LC_RA_RAM_FILTER_CRMM_A__A 0x2820060 +#define LC_RA_RAM_FILTER_CRMM_A__PRE 0x4 +#define LC_RA_RAM_FILTER_CRMM_B__A 0x2820061 +#define LC_RA_RAM_FILTER_CRMM_B__PRE 0x1 +#define LC_RA_RAM_FILTER_SRMM_A__A 0x2820068 +#define LC_RA_RAM_FILTER_SRMM_A__PRE 0x4 +#define LC_RA_RAM_FILTER_SRMM_B__A 0x2820069 +#define LC_RA_RAM_FILTER_SRMM_B__PRE 0x1 +#define B_HI_COMM_EXEC__A 0x400000 +#define B_HI_COMM_MB__A 0x400002 +#define B_HI_CT_REG_COMM_STATE__A 0x410001 +#define B_HI_RA_RAM_SRV_RES__A 0x420031 +#define B_HI_RA_RAM_SRV_CMD__A 0x420032 +#define B_HI_RA_RAM_SRV_CMD_RESET 0x2 +#define B_HI_RA_RAM_SRV_CMD_CONFIG 0x3 +#define B_HI_RA_RAM_SRV_CMD_EXECUTE 0x6 +#define B_HI_RA_RAM_SRV_RST_KEY__A 0x420033 +#define B_HI_RA_RAM_SRV_RST_KEY_ACT 0x3973 +#define B_HI_RA_RAM_SRV_CFG_KEY__A 0x420033 +#define B_HI_RA_RAM_SRV_CFG_DIV__A 0x420034 +#define B_HI_RA_RAM_SRV_CFG_BDL__A 0x420035 +#define B_HI_RA_RAM_SRV_CFG_WUP__A 0x420036 +#define B_HI_RA_RAM_SRV_CFG_ACT__A 0x420037 +#define B_HI_RA_RAM_SRV_CFG_ACT_SLV0_ON 0x1 +#define B_HI_RA_RAM_SRV_CFG_ACT_BRD__M 0x4 +#define B_HI_RA_RAM_SRV_CFG_ACT_BRD_OFF 0x0 +#define B_HI_RA_RAM_SRV_CFG_ACT_BRD_ON 0x4 +#define B_HI_RA_RAM_SRV_CFG_ACT_PWD_EXE 0x8 +#define B_HI_RA_RAM_USR_BEGIN__A 0x420040 +#define B_HI_IF_RAM_TRP_BPT0__AX 0x430000 +#define B_HI_IF_RAM_USR_BEGIN__A 0x430200 +#define B_SC_COMM_EXEC__A 0x800000 +#define B_SC_COMM_EXEC_CTL_STOP 0x0 +#define B_SC_COMM_STATE__A 0x800001 +#define B_SC_RA_RAM_PARAM0__A 0x820040 +#define B_SC_RA_RAM_PARAM1__A 0x820041 +#define B_SC_RA_RAM_CMD_ADDR__A 0x820042 +#define B_SC_RA_RAM_CMD__A 0x820043 +#define B_SC_RA_RAM_CMD_PROC_START 0x1 +#define B_SC_RA_RAM_CMD_SET_PREF_PARAM 0x3 +#define B_SC_RA_RAM_CMD_GET_OP_PARAM 0x5 +#define B_SC_RA_RAM_SW_EVENT_RUN_NMASK__M 0x1 +#define B_SC_RA_RAM_LOCKTRACK_MIN 0x1 +#define B_SC_RA_RAM_OP_PARAM_MODE_2K 0x0 +#define B_SC_RA_RAM_OP_PARAM_MODE_8K 0x1 +#define B_SC_RA_RAM_OP_PARAM_GUARD_32 0x0 +#define B_SC_RA_RAM_OP_PARAM_GUARD_16 0x4 +#define B_SC_RA_RAM_OP_PARAM_GUARD_8 0x8 +#define B_SC_RA_RAM_OP_PARAM_GUARD_4 0xC +#define B_SC_RA_RAM_OP_PARAM_CONST_QPSK 0x0 +#define B_SC_RA_RAM_OP_PARAM_CONST_QAM16 0x10 +#define B_SC_RA_RAM_OP_PARAM_CONST_QAM64 0x20 +#define B_SC_RA_RAM_OP_PARAM_HIER_NO 0x0 +#define B_SC_RA_RAM_OP_PARAM_HIER_A1 0x40 +#define B_SC_RA_RAM_OP_PARAM_HIER_A2 0x80 +#define B_SC_RA_RAM_OP_PARAM_HIER_A4 0xC0 +#define B_SC_RA_RAM_OP_PARAM_RATE_1_2 0x0 +#define B_SC_RA_RAM_OP_PARAM_RATE_2_3 0x200 +#define B_SC_RA_RAM_OP_PARAM_RATE_3_4 0x400 +#define B_SC_RA_RAM_OP_PARAM_RATE_5_6 0x600 +#define B_SC_RA_RAM_OP_PARAM_RATE_7_8 0x800 +#define B_SC_RA_RAM_OP_PARAM_PRIO_HI 0x0 +#define B_SC_RA_RAM_OP_PARAM_PRIO_LO 0x1000 +#define B_SC_RA_RAM_OP_AUTO_MODE__M 0x1 +#define B_SC_RA_RAM_OP_AUTO_GUARD__M 0x2 +#define B_SC_RA_RAM_OP_AUTO_CONST__M 0x4 +#define B_SC_RA_RAM_OP_AUTO_HIER__M 0x8 +#define B_SC_RA_RAM_OP_AUTO_RATE__M 0x10 +#define B_SC_RA_RAM_LOCK__A 0x82004B +#define B_SC_RA_RAM_LOCK_DEMOD__M 0x1 +#define B_SC_RA_RAM_LOCK_FEC__M 0x2 +#define B_SC_RA_RAM_LOCK_MPEG__M 0x4 +#define B_SC_RA_RAM_BE_OPT_ENA__A 0x82004C +#define B_SC_RA_RAM_BE_OPT_ENA_CP_OPT 0x1 +#define B_SC_RA_RAM_BE_OPT_DELAY__A 0x82004D +#define B_SC_RA_RAM_CONFIG__A 0x820050 +#define B_SC_RA_RAM_CONFIG_FR_ENABLE__M 0x4 +#define B_SC_RA_RAM_CONFIG_FREQSCAN__M 0x10 +#define B_SC_RA_RAM_CONFIG_SLAVE__M 0x20 +#define B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M 0x200 +#define B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M 0x400 +#define B_SC_RA_RAM_CO_TD_CAL_2K__A 0x82005D +#define B_SC_RA_RAM_CO_TD_CAL_8K__A 0x82005E +#define B_SC_RA_RAM_IF_SAVE__AX 0x82008E +#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A 0x820098 +#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A 0x820099 +#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A 0x82009A +#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A 0x82009B +#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A 0x82009C +#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A 0x82009D +#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A 0x82009E +#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A 0x82009F +#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A 0x8200D1 +#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE 0x9 +#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A 0x8200D2 +#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE 0x4 +#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A 0x8200D3 +#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE 0x100 +#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A 0x8200D4 +#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE 0x8 +#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A 0x8200D5 +#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE 0x8 +#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A 0x8200D6 +#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE 0x200 +#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__A 0x8200D7 +#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE 0x9 +#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__A 0x8200D8 +#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE 0x4 +#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__A 0x8200D9 +#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE 0x100 +#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__A 0x8200DA +#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE 0xB +#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__A 0x8200DB +#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE 0x1 +#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__A 0x8200DC +#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE 0x40 +#define B_SC_RA_RAM_ECHO_SHIFT_LIM__A 0x8200DD +#define B_SC_RA_RAM_SAMPLE_RATE_COUNT__A 0x8200E8 +#define B_SC_RA_RAM_SAMPLE_RATE_STEP__A 0x8200E9 +#define B_SC_RA_RAM_BAND__A 0x8200EC +#define B_SC_RA_RAM_LC_ABS_2K__A 0x8200F4 +#define B_SC_RA_RAM_LC_ABS_2K__PRE 0x1F +#define B_SC_RA_RAM_LC_ABS_8K__A 0x8200F5 +#define B_SC_RA_RAM_LC_ABS_8K__PRE 0x1F +#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE 0x100 +#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE 0x4 +#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE 0x1E2 +#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE 0x4 +#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE 0x10D +#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE 0x5 +#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE 0x17D +#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE 0x4 +#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE 0x133 +#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE 0x5 +#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE 0x114 +#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE 0x5 +#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE 0x14A +#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE 0x4 +#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE 0x1BB +#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE 0x4 +#define B_SC_RA_RAM_DRIVER_VERSION__AX 0x8201FE +#define B_SC_RA_RAM_PROC_LOCKTRACK 0x0 +#define B_FE_COMM_EXEC__A 0xC00000 +#define B_FE_AD_REG_COMM_EXEC__A 0xC10000 +#define B_FE_AD_REG_FDB_IN__A 0xC10012 +#define B_FE_AD_REG_PD__A 0xC10013 +#define B_FE_AD_REG_INVEXT__A 0xC10014 +#define B_FE_AD_REG_CLKNEG__A 0xC10015 +#define B_FE_AG_REG_COMM_EXEC__A 0xC20000 +#define B_FE_AG_REG_AG_MODE_LOP__A 0xC20010 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_4__M 0x10 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC 0x0 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC 0x10 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_5__M 0x20 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC 0x0 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_C__M 0x1000 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC 0x0 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC 0x1000 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_E__M 0x4000 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC 0x0 +#define B_FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC 0x4000 +#define B_FE_AG_REG_AG_MODE_HIP__A 0xC20011 +#define B_FE_AG_REG_AG_MODE_HIP_MODE_J__M 0x8 +#define B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC 0x0 +#define B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC 0x8 +#define B_FE_AG_REG_AG_PGA_MODE__A 0xC20012 +#define B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN 0x0 +#define B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN 0x1 +#define B_FE_AG_REG_AG_AGC_SIO__A 0xC20013 +#define B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M 0x2 +#define B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT 0x0 +#define B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT 0x2 +#define B_FE_AG_REG_AG_PWD__A 0xC20015 +#define B_FE_AG_REG_AG_PWD_PWD_PD2__M 0x2 +#define B_FE_AG_REG_AG_PWD_PWD_PD2_DISABLE 0x0 +#define B_FE_AG_REG_AG_PWD_PWD_PD2_ENABLE 0x2 +#define B_FE_AG_REG_DCE_AUR_CNT__A 0xC20016 +#define B_FE_AG_REG_DCE_RUR_CNT__A 0xC20017 +#define B_FE_AG_REG_ACE_AUR_CNT__A 0xC2001A +#define B_FE_AG_REG_ACE_RUR_CNT__A 0xC2001B +#define B_FE_AG_REG_CDR_RUR_CNT__A 0xC20020 +#define B_FE_AG_REG_EGC_RUR_CNT__A 0xC20024 +#define B_FE_AG_REG_EGC_SET_LVL__A 0xC20025 +#define B_FE_AG_REG_EGC_SET_LVL__M 0x1FF +#define B_FE_AG_REG_EGC_FLA_RGN__A 0xC20026 +#define B_FE_AG_REG_EGC_SLO_RGN__A 0xC20027 +#define B_FE_AG_REG_EGC_JMP_PSN__A 0xC20028 +#define B_FE_AG_REG_EGC_FLA_INC__A 0xC20029 +#define B_FE_AG_REG_EGC_FLA_DEC__A 0xC2002A +#define B_FE_AG_REG_EGC_SLO_INC__A 0xC2002B +#define B_FE_AG_REG_EGC_SLO_DEC__A 0xC2002C +#define B_FE_AG_REG_EGC_FAS_INC__A 0xC2002D +#define B_FE_AG_REG_EGC_FAS_DEC__A 0xC2002E +#define B_FE_AG_REG_PM1_AGC_WRI__A 0xC20030 +#define B_FE_AG_REG_PM1_AGC_WRI__M 0x7FF +#define B_FE_AG_REG_GC1_AGC_RIC__A 0xC20031 +#define B_FE_AG_REG_GC1_AGC_OFF__A 0xC20032 +#define B_FE_AG_REG_GC1_AGC_MAX__A 0xC20033 +#define B_FE_AG_REG_GC1_AGC_MIN__A 0xC20034 +#define B_FE_AG_REG_GC1_AGC_DAT__A 0xC20035 +#define B_FE_AG_REG_GC1_AGC_DAT__M 0x3FF +#define B_FE_AG_REG_PM2_AGC_WRI__A 0xC20036 +#define B_FE_AG_REG_IND_WIN__A 0xC2003C +#define B_FE_AG_REG_IND_THD_LOL__A 0xC2003D +#define B_FE_AG_REG_IND_THD_HIL__A 0xC2003E +#define B_FE_AG_REG_IND_DEL__A 0xC2003F +#define B_FE_AG_REG_IND_PD1_WRI__A 0xC20040 +#define B_FE_AG_REG_PDA_AUR_CNT__A 0xC20041 +#define B_FE_AG_REG_PDA_RUR_CNT__A 0xC20042 +#define B_FE_AG_REG_PDA_AVE_DAT__A 0xC20043 +#define B_FE_AG_REG_PDC_RUR_CNT__A 0xC20044 +#define B_FE_AG_REG_PDC_SET_LVL__A 0xC20045 +#define B_FE_AG_REG_PDC_FLA_RGN__A 0xC20046 +#define B_FE_AG_REG_PDC_JMP_PSN__A 0xC20047 +#define B_FE_AG_REG_PDC_FLA_STP__A 0xC20048 +#define B_FE_AG_REG_PDC_SLO_STP__A 0xC20049 +#define B_FE_AG_REG_PDC_PD2_WRI__A 0xC2004A +#define B_FE_AG_REG_PDC_MAP_DAT__A 0xC2004B +#define B_FE_AG_REG_PDC_MAX__A 0xC2004C +#define B_FE_AG_REG_TGA_AUR_CNT__A 0xC2004D +#define B_FE_AG_REG_TGA_RUR_CNT__A 0xC2004E +#define B_FE_AG_REG_TGA_AVE_DAT__A 0xC2004F +#define B_FE_AG_REG_TGC_RUR_CNT__A 0xC20050 +#define B_FE_AG_REG_TGC_SET_LVL__A 0xC20051 +#define B_FE_AG_REG_TGC_SET_LVL__M 0x3F +#define B_FE_AG_REG_TGC_FLA_RGN__A 0xC20052 +#define B_FE_AG_REG_TGC_JMP_PSN__A 0xC20053 +#define B_FE_AG_REG_TGC_FLA_STP__A 0xC20054 +#define B_FE_AG_REG_TGC_SLO_STP__A 0xC20055 +#define B_FE_AG_REG_TGC_MAP_DAT__A 0xC20056 +#define B_FE_AG_REG_FGM_WRI__A 0xC20061 +#define B_FE_AG_REG_BGC_FGC_WRI__A 0xC20068 +#define B_FE_AG_REG_BGC_CGC_WRI__A 0xC20069 +#define B_FE_FS_REG_COMM_EXEC__A 0xC30000 +#define B_FE_FS_REG_ADD_INC_LOP__A 0xC30010 +#define B_FE_FD_REG_COMM_EXEC__A 0xC40000 +#define B_FE_FD_REG_SCL__A 0xC40010 +#define B_FE_FD_REG_MAX_LEV__A 0xC40011 +#define B_FE_FD_REG_NR__A 0xC40012 +#define B_FE_FD_REG_MEAS_VAL__A 0xC40014 +#define B_FE_IF_REG_COMM_EXEC__A 0xC50000 +#define B_FE_IF_REG_INCR0__A 0xC50010 +#define B_FE_IF_REG_INCR0__W 16 +#define B_FE_IF_REG_INCR0__M 0xFFFF +#define B_FE_IF_REG_INCR1__A 0xC50011 +#define B_FE_IF_REG_INCR1__M 0xFF +#define B_FE_CF_REG_COMM_EXEC__A 0xC60000 +#define B_FE_CF_REG_SCL__A 0xC60010 +#define B_FE_CF_REG_MAX_LEV__A 0xC60011 +#define B_FE_CF_REG_NR__A 0xC60012 +#define B_FE_CF_REG_IMP_VAL__A 0xC60013 +#define B_FE_CF_REG_MEAS_VAL__A 0xC60014 +#define B_FE_CU_REG_COMM_EXEC__A 0xC70000 +#define B_FE_CU_REG_FRM_CNT_RST__A 0xC70011 +#define B_FE_CU_REG_FRM_CNT_STR__A 0xC70012 +#define B_FE_CU_REG_CTR_NFC_ICR__A 0xC70020 +#define B_FE_CU_REG_CTR_NFC_OCR__A 0xC70021 +#define B_FE_CU_REG_DIV_NFC_CLP__A 0xC70027 +#define B_FT_COMM_EXEC__A 0x1000000 +#define B_FT_REG_COMM_EXEC__A 0x1010000 +#define B_CP_COMM_EXEC__A 0x1400000 +#define B_CP_REG_COMM_EXEC__A 0x1410000 +#define B_CP_REG_INTERVAL__A 0x1410011 +#define B_CP_REG_BR_SPL_OFFSET__A 0x1410023 +#define B_CP_REG_BR_STR_DEL__A 0x1410024 +#define B_CP_REG_RT_ANG_INC0__A 0x1410030 +#define B_CP_REG_RT_ANG_INC1__A 0x1410031 +#define B_CP_REG_RT_DETECT_TRH__A 0x1410033 +#define B_CP_REG_AC_NEXP_OFFS__A 0x1410040 +#define B_CP_REG_AC_AVER_POW__A 0x1410041 +#define B_CP_REG_AC_MAX_POW__A 0x1410042 +#define B_CP_REG_AC_WEIGHT_MAN__A 0x1410043 +#define B_CP_REG_AC_WEIGHT_EXP__A 0x1410044 +#define B_CP_REG_AC_AMP_MODE__A 0x1410047 +#define B_CP_REG_AC_AMP_FIX__A 0x1410048 +#define B_CP_REG_AC_ANG_MODE__A 0x141004A +#define B_CE_COMM_EXEC__A 0x1800000 +#define B_CE_REG_COMM_EXEC__A 0x1810000 +#define B_CE_REG_TAPSET__A 0x1810011 +#define B_CE_REG_AVG_POW__A 0x1810012 +#define B_CE_REG_MAX_POW__A 0x1810013 +#define B_CE_REG_ATT__A 0x1810014 +#define B_CE_REG_NRED__A 0x1810015 +#define B_CE_REG_NE_ERR_SELECT__A 0x1810043 +#define B_CE_REG_NE_TD_CAL__A 0x1810044 +#define B_CE_REG_NE_MIXAVG__A 0x1810046 +#define B_CE_REG_NE_NUPD_OFS__A 0x1810047 +#define B_CE_REG_PE_NEXP_OFFS__A 0x1810050 +#define B_CE_REG_PE_TIMESHIFT__A 0x1810051 +#define B_CE_REG_TP_A0_TAP_NEW__A 0x1810064 +#define B_CE_REG_TP_A0_TAP_NEW_VALID__A 0x1810065 +#define B_CE_REG_TP_A0_MU_LMS_STEP__A 0x1810066 +#define B_CE_REG_TP_A1_TAP_NEW__A 0x1810068 +#define B_CE_REG_TP_A1_TAP_NEW_VALID__A 0x1810069 +#define B_CE_REG_TP_A1_MU_LMS_STEP__A 0x181006A +#define B_CE_REG_TI_PHN_ENABLE__A 0x1810073 +#define B_CE_REG_FI_SHT_INCR__A 0x1810090 +#define B_CE_REG_FI_EXP_NORM__A 0x1810091 +#define B_CE_REG_IR_INPUTSEL__A 0x18100A0 +#define B_CE_REG_IR_STARTPOS__A 0x18100A1 +#define B_CE_REG_IR_NEXP_THRES__A 0x18100A2 +#define B_CE_REG_FR_TREAL00__A 0x1820010 +#define B_CE_REG_FR_TIMAG00__A 0x1820011 +#define B_CE_REG_FR_TREAL01__A 0x1820012 +#define B_CE_REG_FR_TIMAG01__A 0x1820013 +#define B_CE_REG_FR_TREAL02__A 0x1820014 +#define B_CE_REG_FR_TIMAG02__A 0x1820015 +#define B_CE_REG_FR_TREAL03__A 0x1820016 +#define B_CE_REG_FR_TIMAG03__A 0x1820017 +#define B_CE_REG_FR_TREAL04__A 0x1820018 +#define B_CE_REG_FR_TIMAG04__A 0x1820019 +#define B_CE_REG_FR_TREAL05__A 0x182001A +#define B_CE_REG_FR_TIMAG05__A 0x182001B +#define B_CE_REG_FR_TREAL06__A 0x182001C +#define B_CE_REG_FR_TIMAG06__A 0x182001D +#define B_CE_REG_FR_TREAL07__A 0x182001E +#define B_CE_REG_FR_TIMAG07__A 0x182001F +#define B_CE_REG_FR_TREAL08__A 0x1820020 +#define B_CE_REG_FR_TIMAG08__A 0x1820021 +#define B_CE_REG_FR_TREAL09__A 0x1820022 +#define B_CE_REG_FR_TIMAG09__A 0x1820023 +#define B_CE_REG_FR_TREAL10__A 0x1820024 +#define B_CE_REG_FR_TIMAG10__A 0x1820025 +#define B_CE_REG_FR_TREAL11__A 0x1820026 +#define B_CE_REG_FR_TIMAG11__A 0x1820027 +#define B_CE_REG_FR_MID_TAP__A 0x1820028 +#define B_CE_REG_FR_SQS_G00__A 0x1820029 +#define B_CE_REG_FR_SQS_G01__A 0x182002A +#define B_CE_REG_FR_SQS_G02__A 0x182002B +#define B_CE_REG_FR_SQS_G03__A 0x182002C +#define B_CE_REG_FR_SQS_G04__A 0x182002D +#define B_CE_REG_FR_SQS_G05__A 0x182002E +#define B_CE_REG_FR_SQS_G06__A 0x182002F +#define B_CE_REG_FR_SQS_G07__A 0x1820030 +#define B_CE_REG_FR_SQS_G08__A 0x1820031 +#define B_CE_REG_FR_SQS_G09__A 0x1820032 +#define B_CE_REG_FR_SQS_G10__A 0x1820033 +#define B_CE_REG_FR_SQS_G11__A 0x1820034 +#define B_CE_REG_FR_SQS_G12__A 0x1820035 +#define B_CE_REG_FR_RIO_G00__A 0x1820036 +#define B_CE_REG_FR_RIO_G01__A 0x1820037 +#define B_CE_REG_FR_RIO_G02__A 0x1820038 +#define B_CE_REG_FR_RIO_G03__A 0x1820039 +#define B_CE_REG_FR_RIO_G04__A 0x182003A +#define B_CE_REG_FR_RIO_G05__A 0x182003B +#define B_CE_REG_FR_RIO_G06__A 0x182003C +#define B_CE_REG_FR_RIO_G07__A 0x182003D +#define B_CE_REG_FR_RIO_G08__A 0x182003E +#define B_CE_REG_FR_RIO_G09__A 0x182003F +#define B_CE_REG_FR_RIO_G10__A 0x1820040 +#define B_CE_REG_FR_MODE__A 0x1820041 +#define B_CE_REG_FR_SQS_TRH__A 0x1820042 +#define B_CE_REG_FR_RIO_GAIN__A 0x1820043 +#define B_CE_REG_FR_BYPASS__A 0x1820044 +#define B_CE_REG_FR_PM_SET__A 0x1820045 +#define B_CE_REG_FR_ERR_SH__A 0x1820046 +#define B_CE_REG_FR_MAN_SH__A 0x1820047 +#define B_CE_REG_FR_TAP_SH__A 0x1820048 +#define B_EQ_COMM_EXEC__A 0x1C00000 +#define B_EQ_REG_COMM_EXEC__A 0x1C10000 +#define B_EQ_REG_COMM_MB__A 0x1C10002 +#define B_EQ_REG_IS_GAIN_MAN__A 0x1C10015 +#define B_EQ_REG_IS_GAIN_EXP__A 0x1C10016 +#define B_EQ_REG_IS_CLIP_EXP__A 0x1C10017 +#define B_EQ_REG_SN_CEGAIN__A 0x1C1002A +#define B_EQ_REG_SN_OFFSET__A 0x1C1002B +#define B_EQ_REG_RC_SEL_CAR__A 0x1C10032 +#define B_EQ_REG_RC_SEL_CAR_INIT 0x2 +#define B_EQ_REG_RC_SEL_CAR_DIV_ON 0x1 +#define B_EQ_REG_RC_SEL_CAR_PASS_A_CC 0x0 +#define B_EQ_REG_RC_SEL_CAR_PASS_B_CE 0x2 +#define B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC 0x0 +#define B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE 0x8 +#define B_EQ_REG_RC_SEL_CAR_MEAS_A_CC 0x0 +#define B_EQ_REG_RC_SEL_CAR_MEAS_B_CE 0x20 +#define B_EQ_REG_RC_SEL_CAR_FFTMODE__M 0x80 +#define B_EQ_REG_OT_CONST__A 0x1C10046 +#define B_EQ_REG_OT_ALPHA__A 0x1C10047 +#define B_EQ_REG_OT_QNT_THRES0__A 0x1C10048 +#define B_EQ_REG_OT_QNT_THRES1__A 0x1C10049 +#define B_EQ_REG_OT_CSI_STEP__A 0x1C1004A +#define B_EQ_REG_OT_CSI_OFFSET__A 0x1C1004B +#define B_EQ_REG_TD_REQ_SMB_CNT__A 0x1C10061 +#define B_EQ_REG_TD_TPS_PWR_OFS__A 0x1C10062 +#define B_EC_SB_REG_COMM_EXEC__A 0x2010000 +#define B_EC_SB_REG_TR_MODE__A 0x2010010 +#define B_EC_SB_REG_TR_MODE_8K 0x0 +#define B_EC_SB_REG_TR_MODE_2K 0x1 +#define B_EC_SB_REG_CONST__A 0x2010011 +#define B_EC_SB_REG_CONST_QPSK 0x0 +#define B_EC_SB_REG_CONST_16QAM 0x1 +#define B_EC_SB_REG_CONST_64QAM 0x2 +#define B_EC_SB_REG_ALPHA__A 0x2010012 +#define B_EC_SB_REG_PRIOR__A 0x2010013 +#define B_EC_SB_REG_PRIOR_HI 0x0 +#define B_EC_SB_REG_PRIOR_LO 0x1 +#define B_EC_SB_REG_CSI_HI__A 0x2010014 +#define B_EC_SB_REG_CSI_LO__A 0x2010015 +#define B_EC_SB_REG_SMB_TGL__A 0x2010016 +#define B_EC_SB_REG_SNR_HI__A 0x2010017 +#define B_EC_SB_REG_SNR_MID__A 0x2010018 +#define B_EC_SB_REG_SNR_LO__A 0x2010019 +#define B_EC_SB_REG_SCALE_MSB__A 0x201001A +#define B_EC_SB_REG_SCALE_BIT2__A 0x201001B +#define B_EC_SB_REG_SCALE_LSB__A 0x201001C +#define B_EC_SB_REG_CSI_OFS0__A 0x201001D +#define B_EC_SB_REG_CSI_OFS1__A 0x201001E +#define B_EC_SB_REG_CSI_OFS2__A 0x201001F +#define B_EC_VD_REG_COMM_EXEC__A 0x2090000 +#define B_EC_VD_REG_FORCE__A 0x2090010 +#define B_EC_VD_REG_SET_CODERATE__A 0x2090011 +#define B_EC_VD_REG_SET_CODERATE_C1_2 0x0 +#define B_EC_VD_REG_SET_CODERATE_C2_3 0x1 +#define B_EC_VD_REG_SET_CODERATE_C3_4 0x2 +#define B_EC_VD_REG_SET_CODERATE_C5_6 0x3 +#define B_EC_VD_REG_SET_CODERATE_C7_8 0x4 +#define B_EC_VD_REG_REQ_SMB_CNT__A 0x2090012 +#define B_EC_VD_REG_RLK_ENA__A 0x2090014 +#define B_EC_OD_REG_COMM_EXEC__A 0x2110000 +#define B_EC_OD_REG_SYNC__A 0x2110664 +#define B_EC_OD_DEINT_RAM__A 0x2120000 +#define B_EC_RS_REG_COMM_EXEC__A 0x2130000 +#define B_EC_RS_REG_REQ_PCK_CNT__A 0x2130010 +#define B_EC_RS_REG_VAL__A 0x2130011 +#define B_EC_RS_REG_VAL_PCK 0x1 +#define B_EC_RS_EC_RAM__A 0x2140000 +#define B_EC_OC_REG_COMM_EXEC__A 0x2150000 +#define B_EC_OC_REG_COMM_EXEC_CTL_ACTIVE 0x1 +#define B_EC_OC_REG_COMM_EXEC_CTL_HOLD 0x2 +#define B_EC_OC_REG_COMM_INT_STA__A 0x2150007 +#define B_EC_OC_REG_OC_MODE_LOP__A 0x2150010 +#define B_EC_OC_REG_OC_MODE_LOP_PAR_ENA__M 0x1 +#define B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE 0x0 +#define B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE 0x1 +#define B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M 0x4 +#define B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC 0x0 +#define B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M 0x80 +#define B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL 0x80 +#define B_EC_OC_REG_OC_MODE_HIP__A 0x2150011 +#define B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR 0x10 +#define B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M 0x200 +#define B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE 0x0 +#define B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE 0x200 +#define B_EC_OC_REG_OC_MPG_SIO__A 0x2150012 +#define B_EC_OC_REG_OC_MPG_SIO__M 0xFFF +#define B_EC_OC_REG_DTO_INC_LOP__A 0x2150014 +#define B_EC_OC_REG_DTO_INC_HIP__A 0x2150015 +#define B_EC_OC_REG_SNC_ISC_LVL__A 0x2150016 +#define B_EC_OC_REG_SNC_ISC_LVL_OSC__M 0xF0 +#define B_EC_OC_REG_TMD_TOP_MODE__A 0x215001D +#define B_EC_OC_REG_TMD_TOP_CNT__A 0x215001E +#define B_EC_OC_REG_TMD_HIL_MAR__A 0x215001F +#define B_EC_OC_REG_TMD_LOL_MAR__A 0x2150020 +#define B_EC_OC_REG_TMD_CUR_CNT__A 0x2150021 +#define B_EC_OC_REG_AVR_ASH_CNT__A 0x2150023 +#define B_EC_OC_REG_AVR_BSH_CNT__A 0x2150024 +#define B_EC_OC_REG_RCN_MODE__A 0x2150027 +#define B_EC_OC_REG_RCN_CRA_LOP__A 0x2150028 +#define B_EC_OC_REG_RCN_CRA_HIP__A 0x2150029 +#define B_EC_OC_REG_RCN_CST_LOP__A 0x215002A +#define B_EC_OC_REG_RCN_CST_HIP__A 0x215002B +#define B_EC_OC_REG_RCN_SET_LVL__A 0x215002C +#define B_EC_OC_REG_RCN_GAI_LVL__A 0x215002D +#define B_EC_OC_REG_RCN_CLP_LOP__A 0x2150032 +#define B_EC_OC_REG_RCN_CLP_HIP__A 0x2150033 +#define B_EC_OC_REG_RCN_MAP_LOP__A 0x2150034 +#define B_EC_OC_REG_RCN_MAP_HIP__A 0x2150035 +#define B_EC_OC_REG_OCR_MPG_UOS__A 0x2150036 +#define B_EC_OC_REG_OCR_MPG_UOS__M 0xFFF +#define B_EC_OC_REG_OCR_MPG_UOS_INIT 0x0 +#define B_EC_OC_REG_OCR_MPG_USR_DAT__A 0x2150038 +#define B_EC_OC_REG_IPR_INV_MPG__A 0x2150045 +#define B_EC_OC_REG_DTO_CLKMODE__A 0x2150047 +#define B_EC_OC_REG_DTO_PER__A 0x2150048 +#define B_EC_OC_REG_DTO_BUR__A 0x2150049 +#define B_EC_OC_REG_RCR_CLKMODE__A 0x215004A +#define B_CC_REG_OSC_MODE__A 0x2410010 +#define B_CC_REG_OSC_MODE_M20 0x1 +#define B_CC_REG_PLL_MODE__A 0x2410011 +#define B_CC_REG_PLL_MODE_BYPASS_PLL 0x1 +#define B_CC_REG_PLL_MODE_PUMP_CUR_12 0x14 +#define B_CC_REG_REF_DIVIDE__A 0x2410012 +#define B_CC_REG_PWD_MODE__A 0x2410015 +#define B_CC_REG_PWD_MODE_DOWN_PLL 0x2 +#define B_CC_REG_UPDATE__A 0x2410017 +#define B_CC_REG_UPDATE_KEY 0x3973 +#define B_CC_REG_JTAGID_L__A 0x2410019 +#define B_CC_REG_DIVERSITY__A 0x241001B +#define B_LC_COMM_EXEC__A 0x2800000 +#define B_LC_RA_RAM_IFINCR_NOM_L__A 0x282000C +#define B_LC_RA_RAM_FILTER_SYM_SET__A 0x282001A +#define B_LC_RA_RAM_FILTER_SYM_SET__PRE 0x3E8 +#define B_LC_RA_RAM_FILTER_CRMM_A__A 0x2820060 +#define B_LC_RA_RAM_FILTER_CRMM_A__PRE 0x4 +#define B_LC_RA_RAM_FILTER_CRMM_B__A 0x2820061 +#define B_LC_RA_RAM_FILTER_CRMM_B__PRE 0x1 +#define B_LC_RA_RAM_FILTER_SRMM_A__A 0x2820068 +#define B_LC_RA_RAM_FILTER_SRMM_A__PRE 0x4 +#define B_LC_RA_RAM_FILTER_SRMM_B__A 0x2820069 +#define B_LC_RA_RAM_FILTER_SRMM_B__PRE 0x1 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ds3000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ds3000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ds3000.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ds3000.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1327 @@ +/* + Montage Technology DS3000/TS2020 - DVBS/S2 Demodulator/Tuner driver + Copyright (C) 2009 Konstantin Dimitrov + + Copyright (C) 2009 TurboSight.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "ds3000.h" + +static int debug; + +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(args); \ + } while (0) + +/* as of March 2009 current DS3000 firmware version is 1.78 */ +/* DS3000 FW v1.78 MD5: a32d17910c4f370073f9346e71d34b80 */ +#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw" + +#define DS3000_SAMPLE_RATE 96000 /* in kHz */ +#define DS3000_XTAL_FREQ 27000 /* in kHz */ + +/* Register values to initialise the demod in DVB-S mode */ +static u8 ds3000_dvbs_init_tab[] = { + 0x23, 0x05, + 0x08, 0x03, + 0x0c, 0x00, + 0x21, 0x54, + 0x25, 0x82, + 0x27, 0x31, + 0x30, 0x08, + 0x31, 0x40, + 0x32, 0x32, + 0x33, 0x35, + 0x35, 0xff, + 0x3a, 0x00, + 0x37, 0x10, + 0x38, 0x10, + 0x39, 0x02, + 0x42, 0x60, + 0x4a, 0x40, + 0x4b, 0x04, + 0x4d, 0x91, + 0x5d, 0xc8, + 0x50, 0x77, + 0x51, 0x77, + 0x52, 0x36, + 0x53, 0x36, + 0x56, 0x01, + 0x63, 0x43, + 0x64, 0x30, + 0x65, 0x40, + 0x68, 0x26, + 0x69, 0x4c, + 0x70, 0x20, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0x40, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0x60, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0x80, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0xa0, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0x1f, + 0x76, 0x00, + 0x77, 0xd1, + 0x78, 0x0c, + 0x79, 0x80, + 0x7f, 0x04, + 0x7c, 0x00, + 0x80, 0x86, + 0x81, 0xa6, + 0x85, 0x04, + 0xcd, 0xf4, + 0x90, 0x33, + 0xa0, 0x44, + 0xc0, 0x18, + 0xc3, 0x10, + 0xc4, 0x08, + 0xc5, 0x80, + 0xc6, 0x80, + 0xc7, 0x0a, + 0xc8, 0x1a, + 0xc9, 0x80, + 0xfe, 0x92, + 0xe0, 0xf8, + 0xe6, 0x8b, + 0xd0, 0x40, + 0xf8, 0x20, + 0xfa, 0x0f, + 0xfd, 0x20, + 0xad, 0x20, + 0xae, 0x07, + 0xb8, 0x00, +}; + +/* Register values to initialise the demod in DVB-S2 mode */ +static u8 ds3000_dvbs2_init_tab[] = { + 0x23, 0x0f, + 0x08, 0x07, + 0x0c, 0x00, + 0x21, 0x54, + 0x25, 0x82, + 0x27, 0x31, + 0x30, 0x08, + 0x31, 0x32, + 0x32, 0x32, + 0x33, 0x35, + 0x35, 0xff, + 0x3a, 0x00, + 0x37, 0x10, + 0x38, 0x10, + 0x39, 0x02, + 0x42, 0x60, + 0x4a, 0x80, + 0x4b, 0x04, + 0x4d, 0x81, + 0x5d, 0x88, + 0x50, 0x36, + 0x51, 0x36, + 0x52, 0x36, + 0x53, 0x36, + 0x63, 0x60, + 0x64, 0x10, + 0x65, 0x10, + 0x68, 0x04, + 0x69, 0x29, + 0x70, 0x20, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0x40, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0x60, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0x80, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0xa0, + 0x71, 0x70, + 0x72, 0x04, + 0x73, 0x00, + 0x70, 0x1f, + 0xa0, 0x44, + 0xc0, 0x08, + 0xc1, 0x10, + 0xc2, 0x08, + 0xc3, 0x10, + 0xc4, 0x08, + 0xc5, 0xf0, + 0xc6, 0xf0, + 0xc7, 0x0a, + 0xc8, 0x1a, + 0xc9, 0x80, + 0xca, 0x23, + 0xcb, 0x24, + 0xce, 0x74, + 0x90, 0x03, + 0x76, 0x80, + 0x77, 0x42, + 0x78, 0x0a, + 0x79, 0x80, + 0xad, 0x40, + 0xae, 0x07, + 0x7f, 0xd4, + 0x7c, 0x00, + 0x80, 0xa8, + 0x81, 0xda, + 0x7c, 0x01, + 0x80, 0xda, + 0x81, 0xec, + 0x7c, 0x02, + 0x80, 0xca, + 0x81, 0xeb, + 0x7c, 0x03, + 0x80, 0xba, + 0x81, 0xdb, + 0x85, 0x08, + 0x86, 0x00, + 0x87, 0x02, + 0x89, 0x80, + 0x8b, 0x44, + 0x8c, 0xaa, + 0x8a, 0x10, + 0xba, 0x00, + 0xf5, 0x04, + 0xfe, 0x44, + 0xd2, 0x32, + 0xb8, 0x00, +}; + +struct ds3000_state { + struct i2c_adapter *i2c; + const struct ds3000_config *config; + struct dvb_frontend frontend; + u8 skip_fw_load; + /* previous uncorrected block counter for DVB-S2 */ + u16 prevUCBS2; +}; + +static int ds3000_writereg(struct ds3000_state *state, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 2 }; + int err; + + dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data); + + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," + " value == 0x%02x)\n", __func__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static int ds3000_tuner_writereg(struct ds3000_state *state, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = 0x60, + .flags = 0, .buf = buf, .len = 2 }; + int err; + + dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data); + + ds3000_writereg(state, 0x03, 0x11); + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk("%s: writereg error(err == %i, reg == 0x%02x," + " value == 0x%02x)\n", __func__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +/* I2C write for 8k firmware load */ +static int ds3000_writeFW(struct ds3000_state *state, int reg, + const u8 *data, u16 len) +{ + int i, ret = -EREMOTEIO; + struct i2c_msg msg; + u8 *buf; + + buf = kmalloc(33, GFP_KERNEL); + if (buf == NULL) { + printk(KERN_ERR "Unable to kmalloc\n"); + ret = -ENOMEM; + goto error; + } + + *(buf) = reg; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.buf = buf; + msg.len = 33; + + for (i = 0; i < len; i += 32) { + memcpy(buf + 1, data + i, 32); + + dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len); + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) { + printk(KERN_ERR "%s: write error(err == %i, " + "reg == 0x%02x\n", __func__, ret, reg); + ret = -EREMOTEIO; + } + } + +error: + kfree(buf); + + return ret; +} + +static int ds3000_readreg(struct ds3000_state *state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 1 + }, { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret); + return ret; + } + + dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]); + + return b1[0]; +} + +static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = 0x60, + .flags = 0, + .buf = b0, + .len = 1 + }, { + .addr = 0x60, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + + ds3000_writereg(state, 0x03, 0x12); + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret); + return ret; + } + + dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]); + + return b1[0]; +} + +static int ds3000_load_firmware(struct dvb_frontend *fe, + const struct firmware *fw); + +static int ds3000_firmware_ondemand(struct dvb_frontend *fe) +{ + struct ds3000_state *state = fe->demodulator_priv; + const struct firmware *fw; + int ret = 0; + + dprintk("%s()\n", __func__); + + if (ds3000_readreg(state, 0xb2) <= 0) + return ret; + + if (state->skip_fw_load) + return 0; + /* Load firmware */ + /* request the firmware, this will block until someone uploads it */ + printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, + DS3000_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE, + state->i2c->dev.parent); + printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__); + if (ret) { + printk(KERN_ERR "%s: No firmware uploaded (timeout or file not " + "found?)\n", __func__); + return ret; + } + + /* Make sure we don't recurse back through here during loading */ + state->skip_fw_load = 1; + + ret = ds3000_load_firmware(fe, fw); + if (ret) + printk("%s: Writing firmware to device failed\n", __func__); + + release_firmware(fw); + + dprintk("%s: Firmware upload %s\n", __func__, + ret == 0 ? "complete" : "failed"); + + /* Ensure firmware is always loaded if required */ + state->skip_fw_load = 0; + + return ret; +} + +static int ds3000_load_firmware(struct dvb_frontend *fe, + const struct firmware *fw) +{ + struct ds3000_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n", + fw->size, + fw->data[0], + fw->data[1], + fw->data[fw->size - 2], + fw->data[fw->size - 1]); + + /* Begin the firmware load process */ + ds3000_writereg(state, 0xb2, 0x01); + /* write the entire firmware */ + ds3000_writeFW(state, 0xb0, fw->data, fw->size); + ds3000_writereg(state, 0xb2, 0x00); + + return 0; +} + +static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct ds3000_state *state = fe->demodulator_priv; + u8 data; + + dprintk("%s(%d)\n", __func__, voltage); + + data = ds3000_readreg(state, 0xa2); + data |= 0x03; /* bit0 V/H, bit1 off/on */ + + switch (voltage) { + case SEC_VOLTAGE_18: + data &= ~0x03; + break; + case SEC_VOLTAGE_13: + data &= ~0x03; + data |= 0x01; + break; + case SEC_VOLTAGE_OFF: + break; + } + + ds3000_writereg(state, 0xa2, data); + + return 0; +} + +static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status) +{ + struct ds3000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int lock; + + *status = 0; + + switch (c->delivery_system) { + case SYS_DVBS: + lock = ds3000_readreg(state, 0xd1); + if ((lock & 0x07) == 0x07) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + + break; + case SYS_DVBS2: + lock = ds3000_readreg(state, 0x0d); + if ((lock & 0x8f) == 0x8f) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + + break; + default: + return 1; + } + + dprintk("%s: status = 0x%02x\n", __func__, lock); + + return 0; +} + +/* read DS3000 BER value */ +static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber) +{ + struct ds3000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 data; + u32 ber_reading, lpdc_frames; + + dprintk("%s()\n", __func__); + + switch (c->delivery_system) { + case SYS_DVBS: + /* set the number of bytes checked during + BER estimation */ + ds3000_writereg(state, 0xf9, 0x04); + /* read BER estimation status */ + data = ds3000_readreg(state, 0xf8); + /* check if BER estimation is ready */ + if ((data & 0x10) == 0) { + /* this is the number of error bits, + to calculate the bit error rate + divide to 8388608 */ + *ber = (ds3000_readreg(state, 0xf7) << 8) | + ds3000_readreg(state, 0xf6); + /* start counting error bits */ + /* need to be set twice + otherwise it fails sometimes */ + data |= 0x10; + ds3000_writereg(state, 0xf8, data); + ds3000_writereg(state, 0xf8, data); + } else + /* used to indicate that BER estimation + is not ready, i.e. BER is unknown */ + *ber = 0xffffffff; + break; + case SYS_DVBS2: + /* read the number of LPDC decoded frames */ + lpdc_frames = (ds3000_readreg(state, 0xd7) << 16) | + (ds3000_readreg(state, 0xd6) << 8) | + ds3000_readreg(state, 0xd5); + /* read the number of packets with bad CRC */ + ber_reading = (ds3000_readreg(state, 0xf8) << 8) | + ds3000_readreg(state, 0xf7); + if (lpdc_frames > 750) { + /* clear LPDC frame counters */ + ds3000_writereg(state, 0xd1, 0x01); + /* clear bad packets counter */ + ds3000_writereg(state, 0xf9, 0x01); + /* enable bad packets counter */ + ds3000_writereg(state, 0xf9, 0x00); + /* enable LPDC frame counters */ + ds3000_writereg(state, 0xd1, 0x00); + *ber = ber_reading; + } else + /* used to indicate that BER estimation is not ready, + i.e. BER is unknown */ + *ber = 0xffffffff; + break; + default: + return 1; + } + + return 0; +} + +/* read TS2020 signal strength */ +static int ds3000_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct ds3000_state *state = fe->demodulator_priv; + u16 sig_reading, sig_strength; + u8 rfgain, bbgain; + + dprintk("%s()\n", __func__); + + rfgain = ds3000_tuner_readreg(state, 0x3d) & 0x1f; + bbgain = ds3000_tuner_readreg(state, 0x21) & 0x1f; + + if (rfgain > 15) + rfgain = 15; + if (bbgain > 13) + bbgain = 13; + + sig_reading = rfgain * 2 + bbgain * 3; + + sig_strength = 40 + (64 - sig_reading) * 50 / 64 ; + + /* cook the value to be suitable for szap-s2 human readable output */ + *signal_strength = sig_strength * 1000; + + dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, + sig_reading, *signal_strength); + + return 0; +} + +/* calculate DS3000 snr value in dB */ +static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct ds3000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 snr_reading, snr_value; + u32 dvbs2_signal_reading, dvbs2_noise_reading, tmp; + static const u16 dvbs_snr_tab[] = { /* 20 x Table (rounded up) */ + 0x0000, 0x1b13, 0x2aea, 0x3627, 0x3ede, 0x45fe, 0x4c03, + 0x513a, 0x55d4, 0x59f2, 0x5dab, 0x6111, 0x6431, 0x6717, + 0x69c9, 0x6c4e, 0x6eac, 0x70e8, 0x7304, 0x7505 + }; + static const u16 dvbs2_snr_tab[] = { /* 80 x Table (rounded up) */ + 0x0000, 0x0bc2, 0x12a3, 0x1785, 0x1b4e, 0x1e65, 0x2103, + 0x2347, 0x2546, 0x2710, 0x28ae, 0x2a28, 0x2b83, 0x2cc5, + 0x2df1, 0x2f09, 0x3010, 0x3109, 0x31f4, 0x32d2, 0x33a6, + 0x3470, 0x3531, 0x35ea, 0x369b, 0x3746, 0x37ea, 0x3888, + 0x3920, 0x39b3, 0x3a42, 0x3acc, 0x3b51, 0x3bd3, 0x3c51, + 0x3ccb, 0x3d42, 0x3db6, 0x3e27, 0x3e95, 0x3f00, 0x3f68, + 0x3fcf, 0x4033, 0x4094, 0x40f4, 0x4151, 0x41ac, 0x4206, + 0x425e, 0x42b4, 0x4308, 0x435b, 0x43ac, 0x43fc, 0x444a, + 0x4497, 0x44e2, 0x452d, 0x4576, 0x45bd, 0x4604, 0x4649, + 0x468e, 0x46d1, 0x4713, 0x4755, 0x4795, 0x47d4, 0x4813, + 0x4851, 0x488d, 0x48c9, 0x4904, 0x493f, 0x4978, 0x49b1, + 0x49e9, 0x4a20, 0x4a57 + }; + + dprintk("%s()\n", __func__); + + switch (c->delivery_system) { + case SYS_DVBS: + snr_reading = ds3000_readreg(state, 0xff); + snr_reading /= 8; + if (snr_reading == 0) + *snr = 0x0000; + else { + if (snr_reading > 20) + snr_reading = 20; + snr_value = dvbs_snr_tab[snr_reading - 1] * 10 / 23026; + /* cook the value to be suitable for szap-s2 + human readable output */ + *snr = snr_value * 8 * 655; + } + dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, + snr_reading, *snr); + break; + case SYS_DVBS2: + dvbs2_noise_reading = (ds3000_readreg(state, 0x8c) & 0x3f) + + (ds3000_readreg(state, 0x8d) << 4); + dvbs2_signal_reading = ds3000_readreg(state, 0x8e); + tmp = dvbs2_signal_reading * dvbs2_signal_reading >> 1; + if (tmp == 0) { + *snr = 0x0000; + return 0; + } + if (dvbs2_noise_reading == 0) { + snr_value = 0x0013; + /* cook the value to be suitable for szap-s2 + human readable output */ + *snr = 0xffff; + return 0; + } + if (tmp > dvbs2_noise_reading) { + snr_reading = tmp / dvbs2_noise_reading; + if (snr_reading > 80) + snr_reading = 80; + snr_value = dvbs2_snr_tab[snr_reading - 1] / 1000; + /* cook the value to be suitable for szap-s2 + human readable output */ + *snr = snr_value * 5 * 655; + } else { + snr_reading = dvbs2_noise_reading / tmp; + if (snr_reading > 80) + snr_reading = 80; + *snr = -(dvbs2_snr_tab[snr_reading] / 1000); + } + dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, + snr_reading, *snr); + break; + default: + return 1; + } + + return 0; +} + +/* read DS3000 uncorrected blocks */ +static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct ds3000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 data; + u16 _ucblocks; + + dprintk("%s()\n", __func__); + + switch (c->delivery_system) { + case SYS_DVBS: + *ucblocks = (ds3000_readreg(state, 0xf5) << 8) | + ds3000_readreg(state, 0xf4); + data = ds3000_readreg(state, 0xf8); + /* clear packet counters */ + data &= ~0x20; + ds3000_writereg(state, 0xf8, data); + /* enable packet counters */ + data |= 0x20; + ds3000_writereg(state, 0xf8, data); + break; + case SYS_DVBS2: + _ucblocks = (ds3000_readreg(state, 0xe2) << 8) | + ds3000_readreg(state, 0xe1); + if (_ucblocks > state->prevUCBS2) + *ucblocks = _ucblocks - state->prevUCBS2; + else + *ucblocks = state->prevUCBS2 - _ucblocks; + state->prevUCBS2 = _ucblocks; + break; + default: + return 1; + } + + return 0; +} + +static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct ds3000_state *state = fe->demodulator_priv; + u8 data; + + dprintk("%s(%d)\n", __func__, tone); + if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { + printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone); + return -EINVAL; + } + + data = ds3000_readreg(state, 0xa2); + data &= ~0xc0; + ds3000_writereg(state, 0xa2, data); + + switch (tone) { + case SEC_TONE_ON: + dprintk("%s: setting tone on\n", __func__); + data = ds3000_readreg(state, 0xa1); + data &= ~0x43; + data |= 0x04; + ds3000_writereg(state, 0xa1, data); + break; + case SEC_TONE_OFF: + dprintk("%s: setting tone off\n", __func__); + data = ds3000_readreg(state, 0xa2); + data |= 0x80; + ds3000_writereg(state, 0xa2, data); + break; + } + + return 0; +} + +static int ds3000_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *d) +{ + struct ds3000_state *state = fe->demodulator_priv; + int i; + u8 data; + + /* Dump DiSEqC message */ + dprintk("%s(", __func__); + for (i = 0 ; i < d->msg_len;) { + dprintk("0x%02x", d->msg[i]); + if (++i < d->msg_len) + dprintk(", "); + } + + /* enable DiSEqC message send pin */ + data = ds3000_readreg(state, 0xa2); + data &= ~0xc0; + ds3000_writereg(state, 0xa2, data); + + /* DiSEqC message */ + for (i = 0; i < d->msg_len; i++) + ds3000_writereg(state, 0xa3 + i, d->msg[i]); + + data = ds3000_readreg(state, 0xa1); + /* clear DiSEqC message length and status, + enable DiSEqC message send */ + data &= ~0xf8; + /* set DiSEqC mode, modulation active during 33 pulses, + set DiSEqC message length */ + data |= ((d->msg_len - 1) << 3) | 0x07; + ds3000_writereg(state, 0xa1, data); + + /* wait up to 150ms for DiSEqC transmission to complete */ + for (i = 0; i < 15; i++) { + data = ds3000_readreg(state, 0xa1); + if ((data & 0x40) == 0) + break; + msleep(10); + } + + /* DiSEqC timeout after 150ms */ + if (i == 15) { + data = ds3000_readreg(state, 0xa1); + data &= ~0x80; + data |= 0x40; + ds3000_writereg(state, 0xa1, data); + + data = ds3000_readreg(state, 0xa2); + data &= ~0xc0; + data |= 0x80; + ds3000_writereg(state, 0xa2, data); + + return 1; + } + + data = ds3000_readreg(state, 0xa2); + data &= ~0xc0; + data |= 0x80; + ds3000_writereg(state, 0xa2, data); + + return 0; +} + +/* Send DiSEqC burst */ +static int ds3000_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t burst) +{ + struct ds3000_state *state = fe->demodulator_priv; + int i; + u8 data; + + dprintk("%s()\n", __func__); + + data = ds3000_readreg(state, 0xa2); + data &= ~0xc0; + ds3000_writereg(state, 0xa2, data); + + /* DiSEqC burst */ + if (burst == SEC_MINI_A) + /* Unmodulated tone burst */ + ds3000_writereg(state, 0xa1, 0x02); + else if (burst == SEC_MINI_B) + /* Modulated tone burst */ + ds3000_writereg(state, 0xa1, 0x01); + else + return -EINVAL; + + msleep(13); + for (i = 0; i < 5; i++) { + data = ds3000_readreg(state, 0xa1); + if ((data & 0x40) == 0) + break; + msleep(1); + } + + if (i == 5) { + data = ds3000_readreg(state, 0xa1); + data &= ~0x80; + data |= 0x40; + ds3000_writereg(state, 0xa1, data); + + data = ds3000_readreg(state, 0xa2); + data &= ~0xc0; + data |= 0x80; + ds3000_writereg(state, 0xa2, data); + + return 1; + } + + data = ds3000_readreg(state, 0xa2); + data &= ~0xc0; + data |= 0x80; + ds3000_writereg(state, 0xa2, data); + + return 0; +} + +static void ds3000_release(struct dvb_frontend *fe) +{ + struct ds3000_state *state = fe->demodulator_priv; + dprintk("%s\n", __func__); + kfree(state); +} + +static struct dvb_frontend_ops ds3000_ops; + +struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, + struct i2c_adapter *i2c) +{ + struct ds3000_state *state = NULL; + int ret; + + dprintk("%s\n", __func__); + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL); + if (state == NULL) { + printk(KERN_ERR "Unable to kmalloc\n"); + goto error2; + } + + state->config = config; + state->i2c = i2c; + state->prevUCBS2 = 0; + + /* check if the demod is present */ + ret = ds3000_readreg(state, 0x00) & 0xfe; + if (ret != 0xe0) { + printk(KERN_ERR "Invalid probe, probably not a DS3000\n"); + goto error3; + } + + printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n", + ds3000_readreg(state, 0x02), + ds3000_readreg(state, 0x01)); + + memcpy(&state->frontend.ops, &ds3000_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error3: + kfree(state); +error2: + return NULL; +} +EXPORT_SYMBOL(ds3000_attach); + +static int ds3000_set_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int ds3000_get_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int ds3000_set_carrier_offset(struct dvb_frontend *fe, + s32 carrier_offset_khz) +{ + struct ds3000_state *state = fe->demodulator_priv; + s32 tmp; + + tmp = carrier_offset_khz; + tmp *= 65536; + tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE); + + if (tmp < 0) + tmp += 65536; + + ds3000_writereg(state, 0x5f, tmp >> 8); + ds3000_writereg(state, 0x5e, tmp & 0xff); + + return 0; +} + +static int ds3000_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct ds3000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + int i; + fe_status_t status; + u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4; + s32 offset_khz; + u16 value, ndiv; + u32 f3db; + + dprintk("%s() ", __func__); + + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + /* Tune */ + /* unknown */ + ds3000_tuner_writereg(state, 0x07, 0x02); + ds3000_tuner_writereg(state, 0x10, 0x00); + ds3000_tuner_writereg(state, 0x60, 0x79); + ds3000_tuner_writereg(state, 0x08, 0x01); + ds3000_tuner_writereg(state, 0x00, 0x01); + div4 = 0; + + /* calculate and set freq divider */ + if (p->frequency < 1146000) { + ds3000_tuner_writereg(state, 0x10, 0x11); + div4 = 1; + ndiv = ((p->frequency * (6 + 8) * 4) + + (DS3000_XTAL_FREQ / 2)) / + DS3000_XTAL_FREQ - 1024; + } else { + ds3000_tuner_writereg(state, 0x10, 0x01); + ndiv = ((p->frequency * (6 + 8) * 2) + + (DS3000_XTAL_FREQ / 2)) / + DS3000_XTAL_FREQ - 1024; + } + + ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8); + ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff); + + /* set pll */ + ds3000_tuner_writereg(state, 0x03, 0x06); + ds3000_tuner_writereg(state, 0x51, 0x0f); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x10); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(5); + + /* unknown */ + ds3000_tuner_writereg(state, 0x51, 0x17); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x08); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(5); + + value = ds3000_tuner_readreg(state, 0x3d); + value &= 0x0f; + if ((value > 4) && (value < 15)) { + value -= 3; + if (value < 4) + value = 4; + value = ((value << 3) | 0x01) & 0x79; + } + + ds3000_tuner_writereg(state, 0x60, value); + ds3000_tuner_writereg(state, 0x51, 0x17); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x08); + ds3000_tuner_writereg(state, 0x50, 0x00); + + /* set low-pass filter period */ + ds3000_tuner_writereg(state, 0x04, 0x2e); + ds3000_tuner_writereg(state, 0x51, 0x1b); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x04); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(5); + + f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000; + if ((c->symbol_rate / 1000) < 5000) + f3db += 3000; + if (f3db < 7000) + f3db = 7000; + if (f3db > 40000) + f3db = 40000; + + /* set low-pass filter baseband */ + value = ds3000_tuner_readreg(state, 0x26); + mlpf = 0x2e * 207 / ((value << 1) + 151); + mlpf_max = mlpf * 135 / 100; + mlpf_min = mlpf * 78 / 100; + if (mlpf_max > 63) + mlpf_max = 63; + + /* rounded to the closest integer */ + nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2)) + / (2766 * DS3000_XTAL_FREQ); + if (nlpf > 23) + nlpf = 23; + if (nlpf < 1) + nlpf = 1; + + /* rounded to the closest integer */ + mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) + + (1000 * f3db / 2)) / (1000 * f3db); + + if (mlpf_new < mlpf_min) { + nlpf++; + mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) + + (1000 * f3db / 2)) / (1000 * f3db); + } + + if (mlpf_new > mlpf_max) + mlpf_new = mlpf_max; + + ds3000_tuner_writereg(state, 0x04, mlpf_new); + ds3000_tuner_writereg(state, 0x06, nlpf); + ds3000_tuner_writereg(state, 0x51, 0x1b); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x04); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(5); + + /* unknown */ + ds3000_tuner_writereg(state, 0x51, 0x1e); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x01); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(60); + + offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ + / (6 + 8) / (div4 + 1) / 2 - p->frequency; + + /* ds3000 global reset */ + ds3000_writereg(state, 0x07, 0x80); + ds3000_writereg(state, 0x07, 0x00); + /* ds3000 build-in uC reset */ + ds3000_writereg(state, 0xb2, 0x01); + /* ds3000 software reset */ + ds3000_writereg(state, 0x00, 0x01); + + switch (c->delivery_system) { + case SYS_DVBS: + /* initialise the demod in DVB-S mode */ + for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2) + ds3000_writereg(state, + ds3000_dvbs_init_tab[i], + ds3000_dvbs_init_tab[i + 1]); + value = ds3000_readreg(state, 0xfe); + value &= 0xc0; + value |= 0x1b; + ds3000_writereg(state, 0xfe, value); + break; + case SYS_DVBS2: + /* initialise the demod in DVB-S2 mode */ + for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2) + ds3000_writereg(state, + ds3000_dvbs2_init_tab[i], + ds3000_dvbs2_init_tab[i + 1]); + ds3000_writereg(state, 0xfe, 0x98); + break; + default: + return 1; + } + + /* enable 27MHz clock output */ + ds3000_writereg(state, 0x29, 0x80); + /* enable ac coupling */ + ds3000_writereg(state, 0x25, 0x8a); + + /* enhance symbol rate performance */ + if ((c->symbol_rate / 1000) <= 5000) { + value = 29777 / (c->symbol_rate / 1000) + 1; + if (value % 2 != 0) + value++; + ds3000_writereg(state, 0xc3, 0x0d); + ds3000_writereg(state, 0xc8, value); + ds3000_writereg(state, 0xc4, 0x10); + ds3000_writereg(state, 0xc7, 0x0e); + } else if ((c->symbol_rate / 1000) <= 10000) { + value = 92166 / (c->symbol_rate / 1000) + 1; + if (value % 2 != 0) + value++; + ds3000_writereg(state, 0xc3, 0x07); + ds3000_writereg(state, 0xc8, value); + ds3000_writereg(state, 0xc4, 0x09); + ds3000_writereg(state, 0xc7, 0x12); + } else if ((c->symbol_rate / 1000) <= 20000) { + value = 64516 / (c->symbol_rate / 1000) + 1; + ds3000_writereg(state, 0xc3, value); + ds3000_writereg(state, 0xc8, 0x0e); + ds3000_writereg(state, 0xc4, 0x07); + ds3000_writereg(state, 0xc7, 0x18); + } else { + value = 129032 / (c->symbol_rate / 1000) + 1; + ds3000_writereg(state, 0xc3, value); + ds3000_writereg(state, 0xc8, 0x0a); + ds3000_writereg(state, 0xc4, 0x05); + ds3000_writereg(state, 0xc7, 0x24); + } + + /* normalized symbol rate rounded to the closest integer */ + value = (((c->symbol_rate / 1000) << 16) + + (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE; + ds3000_writereg(state, 0x61, value & 0x00ff); + ds3000_writereg(state, 0x62, (value & 0xff00) >> 8); + + /* co-channel interference cancellation disabled */ + ds3000_writereg(state, 0x56, 0x00); + + /* equalizer disabled */ + ds3000_writereg(state, 0x76, 0x00); + + /*ds3000_writereg(state, 0x08, 0x03); + ds3000_writereg(state, 0xfd, 0x22); + ds3000_writereg(state, 0x08, 0x07); + ds3000_writereg(state, 0xfd, 0x42); + ds3000_writereg(state, 0x08, 0x07);*/ + + if (state->config->ci_mode) { + switch (c->delivery_system) { + case SYS_DVBS: + default: + ds3000_writereg(state, 0xfd, 0x80); + break; + case SYS_DVBS2: + ds3000_writereg(state, 0xfd, 0x01); + break; + } + } + + /* ds3000 out of software reset */ + ds3000_writereg(state, 0x00, 0x00); + /* start ds3000 build-in uC */ + ds3000_writereg(state, 0xb2, 0x00); + + ds3000_set_carrier_offset(fe, offset_khz); + + for (i = 0; i < 30 ; i++) { + ds3000_read_status(fe, &status); + if (status && FE_HAS_LOCK) + break; + + msleep(10); + } + + return 0; +} + +static int ds3000_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p, + unsigned int mode_flags, + unsigned int *delay, + fe_status_t *status) +{ + if (p) { + int ret = ds3000_set_frontend(fe, p); + if (ret) + return ret; + } + + *delay = HZ / 5; + + return ds3000_read_status(fe, status); +} + +static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe) +{ + dprintk("%s()\n", __func__); + return DVBFE_ALGO_HW; +} + +/* + * Initialise or wake up device + * + * Power config will reset and load initial firmware if required + */ +static int ds3000_initfe(struct dvb_frontend *fe) +{ + struct ds3000_state *state = fe->demodulator_priv; + int ret; + + dprintk("%s()\n", __func__); + /* hard reset */ + ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08)); + msleep(1); + + /* TS2020 init */ + ds3000_tuner_writereg(state, 0x42, 0x73); + ds3000_tuner_writereg(state, 0x05, 0x01); + ds3000_tuner_writereg(state, 0x62, 0xf5); + /* Load the firmware if required */ + ret = ds3000_firmware_ondemand(fe); + if (ret != 0) { + printk(KERN_ERR "%s: Unable initialize firmware\n", __func__); + return ret; + } + + return 0; +} + +/* Put device to sleep */ +static int ds3000_sleep(struct dvb_frontend *fe) +{ + dprintk("%s()\n", __func__); + return 0; +} + +static struct dvb_frontend_ops ds3000_ops = { + + .info = { + .name = "Montage Technology DS3000/TS2020", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1011, /* kHz for QPSK frontends */ + .frequency_tolerance = 5000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_2G_MODULATION | + FE_CAN_QPSK | FE_CAN_RECOVER + }, + + .release = ds3000_release, + + .init = ds3000_initfe, + .sleep = ds3000_sleep, + .read_status = ds3000_read_status, + .read_ber = ds3000_read_ber, + .read_signal_strength = ds3000_read_signal_strength, + .read_snr = ds3000_read_snr, + .read_ucblocks = ds3000_read_ucblocks, + .set_voltage = ds3000_set_voltage, + .set_tone = ds3000_set_tone, + .diseqc_send_master_cmd = ds3000_send_diseqc_msg, + .diseqc_send_burst = ds3000_diseqc_send_burst, + .get_frontend_algo = ds3000_get_algo, + + .set_property = ds3000_set_property, + .get_property = ds3000_get_property, + .set_frontend = ds3000_set_frontend, + .tune = ds3000_tune, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + +MODULE_DESCRIPTION("DVB Frontend module for Montage Technology " + "DS3000/TS2020 hardware"); +MODULE_AUTHOR("Konstantin Dimitrov"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ds3000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ds3000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ds3000.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ds3000.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + Montage Technology DS3000/TS2020 - DVBS/S2 Satellite demod/tuner driver + Copyright (C) 2009 Konstantin Dimitrov + + Copyright (C) 2009 TurboSight.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef DS3000_H +#define DS3000_H + +#include + +struct ds3000_config { + /* the demodulator's i2c address */ + u8 demod_address; + u8 ci_mode; + /* Set device param to start dma */ + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); +}; + +#if defined(CONFIG_DVB_DS3000) || \ + (defined(CONFIG_DVB_DS3000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, + struct i2c_adapter *i2c); +#else +static inline +struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_DS3000 */ +#endif /* DS3000_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,276 @@ +/* + * Driver for Dummy Frontend + * + * Written by Emard + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb_dummy_fe.h" + + +struct dvb_dummy_fe_state { + struct dvb_frontend frontend; +}; + + +static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + *status = FE_HAS_SIGNAL + | FE_HAS_CARRIER + | FE_HAS_VITERBI + | FE_HAS_SYNC + | FE_HAS_LOCK; + + return 0; +} + +static int dvb_dummy_fe_read_ber(struct dvb_frontend* fe, u32* ber) +{ + *ber = 0; + return 0; +} + +static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + *strength = 0; + return 0; +} + +static int dvb_dummy_fe_read_snr(struct dvb_frontend* fe, u16* snr) +{ + *snr = 0; + return 0; +} + +static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + *ucblocks = 0; + return 0; +} + +static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + return 0; +} + +static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + return 0; +} + +static int dvb_dummy_fe_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int dvb_dummy_fe_init(struct dvb_frontend* fe) +{ + return 0; +} + +static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + return 0; +} + +static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + return 0; +} + +static void dvb_dummy_fe_release(struct dvb_frontend* fe) +{ + struct dvb_dummy_fe_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops; + +struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) +{ + struct dvb_dummy_fe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; + +struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) +{ + struct dvb_dummy_fe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; + +struct dvb_frontend *dvb_dummy_fe_qam_attach(void) +{ + struct dvb_dummy_fe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { + + .info = { + .name = "Dummy DVB-T", + .type = FE_OFDM, + .frequency_min = 0, + .frequency_max = 863250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = dvb_dummy_fe_release, + + .init = dvb_dummy_fe_init, + .sleep = dvb_dummy_fe_sleep, + + .set_frontend = dvb_dummy_fe_set_frontend, + .get_frontend = dvb_dummy_fe_get_frontend, + + .read_status = dvb_dummy_fe_read_status, + .read_ber = dvb_dummy_fe_read_ber, + .read_signal_strength = dvb_dummy_fe_read_signal_strength, + .read_snr = dvb_dummy_fe_read_snr, + .read_ucblocks = dvb_dummy_fe_read_ucblocks, +}; + +static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { + + .info = { + .name = "Dummy DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 51000000, + .frequency_max = 858000000, + .symbol_rate_min = (57840000/2)/64, /* SACLK/64 == (XIN/2)/64 */ + .symbol_rate_max = (57840000/2)/4, /* SACLK/4 */ + .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO + }, + + .release = dvb_dummy_fe_release, + + .init = dvb_dummy_fe_init, + .sleep = dvb_dummy_fe_sleep, + + .set_frontend = dvb_dummy_fe_set_frontend, + .get_frontend = dvb_dummy_fe_get_frontend, + + .read_status = dvb_dummy_fe_read_status, + .read_ber = dvb_dummy_fe_read_ber, + .read_signal_strength = dvb_dummy_fe_read_signal_strength, + .read_snr = dvb_dummy_fe_read_snr, + .read_ucblocks = dvb_dummy_fe_read_ucblocks, +}; + +static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { + + .info = { + .name = "Dummy DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 250, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = dvb_dummy_fe_release, + + .init = dvb_dummy_fe_init, + .sleep = dvb_dummy_fe_sleep, + + .set_frontend = dvb_dummy_fe_set_frontend, + .get_frontend = dvb_dummy_fe_get_frontend, + + .read_status = dvb_dummy_fe_read_status, + .read_ber = dvb_dummy_fe_read_ber, + .read_signal_strength = dvb_dummy_fe_read_signal_strength, + .read_snr = dvb_dummy_fe_read_snr, + .read_ucblocks = dvb_dummy_fe_read_ucblocks, + + .set_voltage = dvb_dummy_fe_set_voltage, + .set_tone = dvb_dummy_fe_set_tone, +}; + +MODULE_DESCRIPTION("DVB DUMMY Frontend"); +MODULE_AUTHOR("Emard"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach); +EXPORT_SYMBOL(dvb_dummy_fe_qam_attach); +EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Driver for Dummy Frontend + * + * Written by Emard + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef DVB_DUMMY_FE_H +#define DVB_DUMMY_FE_H + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_DVB_DUMMY_FE) || (defined(CONFIG_DVB_DUMMY_FE_MODULE) && \ +defined(MODULE)) +extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void); +extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void); +extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void); +#else +static inline struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline struct dvb_frontend *dvb_dummy_fe_qam_attach(void) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_DUMMY_FE */ + +#endif // DVB_DUMMY_FE_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb-pll.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb-pll.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb-pll.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb-pll.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,795 @@ +/* + * descriptions + helper functions for simple dvb plls. + * + * (c) 2004 Gerd Knorr [SuSE Labs] + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "dvb-pll.h" + +struct dvb_pll_priv { + /* pll number */ + int nr; + + /* i2c details */ + int pll_i2c_address; + struct i2c_adapter *i2c; + + /* the PLL descriptor */ + struct dvb_pll_desc *pll_desc; + + /* cached frequency/bandwidth */ + u32 frequency; + u32 bandwidth; +}; + +#define DVB_PLL_MAX 64 + +static unsigned int dvb_pll_devcount; + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static unsigned int id[DVB_PLL_MAX] = + { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED }; +module_param_array(id, int, NULL, 0644); +MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)"); + +/* ----------------------------------------------------------- */ + +struct dvb_pll_desc { + char *name; + u32 min; + u32 max; + u32 iffreq; + void (*set)(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params); + u8 *initdata; + u8 *initdata2; + u8 *sleepdata; + int count; + struct { + u32 limit; + u32 stepsize; + u8 config; + u8 cb; + } entries[12]; +}; + +/* ----------------------------------------------------------- */ +/* descriptions */ + +static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { + .name = "Thomson dtt7579", + .min = 177000000, + .max = 858000000, + .iffreq= 36166667, + .sleepdata = (u8[]){ 2, 0xb4, 0x03 }, + .count = 4, + .entries = { + { 443250000, 166667, 0xb4, 0x02 }, + { 542000000, 166667, 0xb4, 0x08 }, + { 771000000, 166667, 0xbc, 0x08 }, + { 999999999, 166667, 0xf4, 0x08 }, + }, +}; + +static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth) + buf[3] |= 0x10; +} + +static struct dvb_pll_desc dvb_pll_thomson_dtt759x = { + .name = "Thomson dtt759x", + .min = 177000000, + .max = 896000000, + .set = thomson_dtt759x_bw, + .iffreq= 36166667, + .sleepdata = (u8[]){ 2, 0x84, 0x03 }, + .count = 5, + .entries = { + { 264000000, 166667, 0xb4, 0x02 }, + { 470000000, 166667, 0xbc, 0x02 }, + { 735000000, 166667, 0xbc, 0x08 }, + { 835000000, 166667, 0xf4, 0x08 }, + { 999999999, 166667, 0xfc, 0x08 }, + }, +}; + +static struct dvb_pll_desc dvb_pll_lg_z201 = { + .name = "LG z201", + .min = 174000000, + .max = 862000000, + .iffreq= 36166667, + .sleepdata = (u8[]){ 2, 0xbc, 0x03 }, + .count = 5, + .entries = { + { 157500000, 166667, 0xbc, 0x01 }, + { 443250000, 166667, 0xbc, 0x02 }, + { 542000000, 166667, 0xbc, 0x04 }, + { 830000000, 166667, 0xf4, 0x04 }, + { 999999999, 166667, 0xfc, 0x04 }, + }, +}; + +static struct dvb_pll_desc dvb_pll_unknown_1 = { + .name = "unknown 1", /* used by dntv live dvb-t */ + .min = 174000000, + .max = 862000000, + .iffreq= 36166667, + .count = 9, + .entries = { + { 150000000, 166667, 0xb4, 0x01 }, + { 173000000, 166667, 0xbc, 0x01 }, + { 250000000, 166667, 0xb4, 0x02 }, + { 400000000, 166667, 0xbc, 0x02 }, + { 420000000, 166667, 0xf4, 0x02 }, + { 470000000, 166667, 0xfc, 0x02 }, + { 600000000, 166667, 0xbc, 0x08 }, + { 730000000, 166667, 0xf4, 0x08 }, + { 999999999, 166667, 0xfc, 0x08 }, + }, +}; + +/* Infineon TUA6010XS + * used in Thomson Cable Tuner + */ +static struct dvb_pll_desc dvb_pll_tua6010xs = { + .name = "Infineon TUA6010XS", + .min = 44250000, + .max = 858000000, + .iffreq= 36125000, + .count = 3, + .entries = { + { 115750000, 62500, 0x8e, 0x03 }, + { 403250000, 62500, 0x8e, 0x06 }, + { 999999999, 62500, 0x8e, 0x85 }, + }, +}; + +/* Panasonic env57h1xd5 (some Philips PLL ?) */ +static struct dvb_pll_desc dvb_pll_env57h1xd5 = { + .name = "Panasonic ENV57H1XD5", + .min = 44250000, + .max = 858000000, + .iffreq= 36125000, + .count = 4, + .entries = { + { 153000000, 166667, 0xc2, 0x41 }, + { 470000000, 166667, 0xc2, 0x42 }, + { 526000000, 166667, 0xc2, 0x84 }, + { 999999999, 166667, 0xc2, 0xa4 }, + }, +}; + +/* Philips TDA6650/TDA6651 + * used in Panasonic ENV77H11D5 + */ +static void tda665x_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + buf[3] |= 0x08; +} + +static struct dvb_pll_desc dvb_pll_tda665x = { + .name = "Philips TDA6650/TDA6651", + .min = 44250000, + .max = 858000000, + .set = tda665x_bw, + .iffreq= 36166667, + .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab }, + .count = 12, + .entries = { + { 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ }, + { 123834000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, + { 161000000, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ }, + { 163834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, + { 253834000, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ }, + { 383834000, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ }, + { 443834000, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ }, + { 444000000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, + { 583834000, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ }, + { 793834000, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ }, + { 444834000, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ }, + { 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, + } +}; + +/* Infineon TUA6034 + * used in LG TDTP E102P + */ +static void tua6034_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth) + buf[3] |= 0x08; +} + +static struct dvb_pll_desc dvb_pll_tua6034 = { + .name = "Infineon TUA6034", + .min = 44250000, + .max = 858000000, + .iffreq= 36166667, + .count = 3, + .set = tua6034_bw, + .entries = { + { 174500000, 62500, 0xce, 0x01 }, + { 230000000, 62500, 0xce, 0x02 }, + { 999999999, 62500, 0xce, 0x04 }, + }, +}; + +/* ALPS TDED4 + * used in Nebula-Cards and USB boxes + */ +static void tded4_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + buf[3] |= 0x04; +} + +static struct dvb_pll_desc dvb_pll_tded4 = { + .name = "ALPS TDED4", + .min = 47000000, + .max = 863000000, + .iffreq= 36166667, + .set = tded4_bw, + .count = 4, + .entries = { + { 153000000, 166667, 0x85, 0x01 }, + { 470000000, 166667, 0x85, 0x02 }, + { 823000000, 166667, 0x85, 0x08 }, + { 999999999, 166667, 0x85, 0x88 }, + } +}; + +/* ALPS TDHU2 + * used in AverTVHD MCE A180 + */ +static struct dvb_pll_desc dvb_pll_tdhu2 = { + .name = "ALPS TDHU2", + .min = 54000000, + .max = 864000000, + .iffreq= 44000000, + .count = 4, + .entries = { + { 162000000, 62500, 0x85, 0x01 }, + { 426000000, 62500, 0x85, 0x02 }, + { 782000000, 62500, 0x85, 0x08 }, + { 999999999, 62500, 0x85, 0x88 }, + } +}; + +/* Samsung TBMV30111IN / TBMV30712IN1 + * used in Air2PC ATSC - 2nd generation (nxt2002) + */ +static struct dvb_pll_desc dvb_pll_samsung_tbmv = { + .name = "Samsung TBMV30111IN / TBMV30712IN1", + .min = 54000000, + .max = 860000000, + .iffreq= 44000000, + .count = 6, + .entries = { + { 172000000, 166667, 0xb4, 0x01 }, + { 214000000, 166667, 0xb4, 0x02 }, + { 467000000, 166667, 0xbc, 0x02 }, + { 721000000, 166667, 0xbc, 0x08 }, + { 841000000, 166667, 0xf4, 0x08 }, + { 999999999, 166667, 0xfc, 0x02 }, + } +}; + +/* + * Philips SD1878 Tuner. + */ +static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { + .name = "Philips SD1878", + .min = 950000, + .max = 2150000, + .iffreq= 249, /* zero-IF, offset 249 is to round up */ + .count = 4, + .entries = { + { 1250000, 500, 0xc4, 0x00}, + { 1450000, 500, 0xc4, 0x40}, + { 2050000, 500, 0xc4, 0x80}, + { 2150000, 500, 0xc4, 0xc0}, + }, +}; + +static void opera1_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000; + struct i2c_msg msg = { + .addr = priv->pll_i2c_address, + .flags = 0, + .buf = buf, + .len = 4 + }; + int result; + u8 lpf; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + result = i2c_transfer(priv->i2c, &msg, 1); + if (result != 1) + printk(KERN_ERR "%s: i2c_transfer failed:%d", + __func__, result); + + if (b_w <= 10000) + lpf = 0xc; + else if (b_w <= 12000) + lpf = 0x2; + else if (b_w <= 14000) + lpf = 0xa; + else if (b_w <= 16000) + lpf = 0x6; + else if (b_w <= 18000) + lpf = 0xe; + else if (b_w <= 20000) + lpf = 0x1; + else if (b_w <= 22000) + lpf = 0x9; + else if (b_w <= 24000) + lpf = 0x5; + else if (b_w <= 26000) + lpf = 0xd; + else if (b_w <= 28000) + lpf = 0x3; + else + lpf = 0xb; + buf[2] ^= 0x1c; /* Flip bits 3-5 */ + /* Set lpf */ + buf[2] |= ((lpf >> 2) & 0x3) << 3; + buf[3] |= (lpf & 0x3) << 2; + + return; +} + +static struct dvb_pll_desc dvb_pll_opera1 = { + .name = "Opera Tuner", + .min = 900000, + .max = 2250000, + .initdata = (u8[]){ 4, 0x08, 0xe5, 0xe1, 0x00 }, + .initdata2 = (u8[]){ 4, 0x08, 0xe5, 0xe5, 0x00 }, + .iffreq= 0, + .set = opera1_bw, + .count = 8, + .entries = { + { 1064000, 500, 0xf9, 0xc2 }, + { 1169000, 500, 0xf9, 0xe2 }, + { 1299000, 500, 0xf9, 0x20 }, + { 1444000, 500, 0xf9, 0x40 }, + { 1606000, 500, 0xf9, 0x60 }, + { 1777000, 500, 0xf9, 0x80 }, + { 1941000, 500, 0xf9, 0xa0 }, + { 2250000, 500, 0xf9, 0xc0 }, + } +}; + +static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { + .addr = priv->pll_i2c_address, + .flags = 0, + .buf = buf, + .len = 4 + }; + int result; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + result = i2c_transfer(priv->i2c, &msg, 1); + if (result != 1) + printk(KERN_ERR "%s: i2c_transfer failed:%d", + __func__, result); + + buf[2] = 0x9e; + buf[3] = 0x90; + + return; +} + +/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */ +static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = { + .name = "Samsung DTOS403IH102A", + .min = 44250000, + .max = 858000000, + .iffreq = 36125000, + .count = 8, + .set = samsung_dtos403ih102a_set, + .entries = { + { 135000000, 62500, 0xbe, 0x01 }, + { 177000000, 62500, 0xf6, 0x01 }, + { 370000000, 62500, 0xbe, 0x02 }, + { 450000000, 62500, 0xf6, 0x02 }, + { 466000000, 62500, 0xfe, 0x02 }, + { 538000000, 62500, 0xbe, 0x08 }, + { 826000000, 62500, 0xf6, 0x08 }, + { 999999999, 62500, 0xfe, 0x08 }, + } +}; + +/* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */ +static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = { + .name = "Samsung TDTC9251DH0", + .min = 48000000, + .max = 863000000, + .iffreq = 36166667, + .count = 3, + .entries = { + { 157500000, 166667, 0xcc, 0x09 }, + { 443000000, 166667, 0xcc, 0x0a }, + { 863000000, 166667, 0xcc, 0x08 }, + } +}; + +/* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */ +static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = { + .name = "Samsung TBDU18132", + .min = 950000, + .max = 2150000, /* guesses */ + .iffreq = 0, + .count = 2, + .entries = { + { 1550000, 125, 0x84, 0x82 }, + { 4095937, 125, 0x84, 0x80 }, + } + /* TSA5059 PLL has a 17 bit divisor rather than the 15 bits supported + * by this driver. The two extra bits are 0x60 in the third byte. 15 + * bits is enough for over 4 GHz, which is enough to cover the range + * of this tuner. We could use the additional divisor bits by adding + * more entries, e.g. + { 0x0ffff * 125 + 125/2, 125, 0x84 | 0x20, }, + { 0x17fff * 125 + 125/2, 125, 0x84 | 0x40, }, + { 0x1ffff * 125 + 125/2, 125, 0x84 | 0x60, }, */ +}; + +/* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */ +static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = { + .name = "Samsung TBMU24112", + .min = 950000, + .max = 2150000, /* guesses */ + .iffreq = 0, + .count = 2, + .entries = { + { 1500000, 125, 0x84, 0x18 }, + { 9999999, 125, 0x84, 0x08 }, + } +}; + +/* Alps TDEE4 DVB-C NIM, used on Cablestar 2 */ +/* byte 4 : 1 * * AGD R3 R2 R1 R0 + * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1 + * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 + * Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5 + * 47 - 153 0 * 0 0 0 0 0 1 0x01 + * 153 - 430 0 * 0 0 0 0 1 0 0x02 + * 430 - 822 0 * 0 0 1 0 0 0 0x08 + * 822 - 862 1 * 0 0 1 0 0 0 0x88 */ +static struct dvb_pll_desc dvb_pll_alps_tdee4 = { + .name = "ALPS TDEE4", + .min = 47000000, + .max = 862000000, + .iffreq = 36125000, + .count = 4, + .entries = { + { 153000000, 62500, 0x95, 0x01 }, + { 430000000, 62500, 0x95, 0x02 }, + { 822000000, 62500, 0x95, 0x08 }, + { 999999999, 62500, 0x95, 0x88 }, + } +}; + +/* ----------------------------------------------------------- */ + +static struct dvb_pll_desc *pll_list[] = { + [DVB_PLL_UNDEFINED] = NULL, + [DVB_PLL_THOMSON_DTT7579] = &dvb_pll_thomson_dtt7579, + [DVB_PLL_THOMSON_DTT759X] = &dvb_pll_thomson_dtt759x, + [DVB_PLL_LG_Z201] = &dvb_pll_lg_z201, + [DVB_PLL_UNKNOWN_1] = &dvb_pll_unknown_1, + [DVB_PLL_TUA6010XS] = &dvb_pll_tua6010xs, + [DVB_PLL_ENV57H1XD5] = &dvb_pll_env57h1xd5, + [DVB_PLL_TUA6034] = &dvb_pll_tua6034, + [DVB_PLL_TDA665X] = &dvb_pll_tda665x, + [DVB_PLL_TDED4] = &dvb_pll_tded4, + [DVB_PLL_TDEE4] = &dvb_pll_alps_tdee4, + [DVB_PLL_TDHU2] = &dvb_pll_tdhu2, + [DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv, + [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261, + [DVB_PLL_OPERA1] = &dvb_pll_opera1, + [DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a, + [DVB_PLL_SAMSUNG_TDTC9251DH0] = &dvb_pll_samsung_tdtc9251dh0, + [DVB_PLL_SAMSUNG_TBDU18132] = &dvb_pll_samsung_tbdu18132, + [DVB_PLL_SAMSUNG_TBMU24112] = &dvb_pll_samsung_tbmu24112, +}; + +/* ----------------------------------------------------------- */ +/* code */ + +static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + struct dvb_pll_desc *desc = priv->pll_desc; + u32 div; + int i; + + if (params->frequency != 0 && (params->frequency < desc->min || + params->frequency > desc->max)) + return -EINVAL; + + for (i = 0; i < desc->count; i++) { + if (params->frequency > desc->entries[i].limit) + continue; + break; + } + + if (debug) + printk("pll: %s: freq=%d | i=%d/%d\n", desc->name, + params->frequency, i, desc->count); + if (i == desc->count) + return -EINVAL; + + div = (params->frequency + desc->iffreq + + desc->entries[i].stepsize/2) / desc->entries[i].stepsize; + buf[0] = div >> 8; + buf[1] = div & 0xff; + buf[2] = desc->entries[i].config; + buf[3] = desc->entries[i].cb; + + if (desc->set) + desc->set(fe, buf, params); + + if (debug) + printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", + desc->name, div, buf[0], buf[1], buf[2], buf[3]); + + // calculate the frequency we set it to + return (div * desc->entries[i].stepsize) - desc->iffreq; +} + +static int dvb_pll_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int dvb_pll_sleep(struct dvb_frontend *fe) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + + if (priv->i2c == NULL) + return -EINVAL; + + if (priv->pll_desc->sleepdata) { + struct i2c_msg msg = { .flags = 0, + .addr = priv->pll_i2c_address, + .buf = priv->pll_desc->sleepdata + 1, + .len = priv->pll_desc->sleepdata[0] }; + + int result; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { + return result; + } + return 0; + } + /* Shouldn't be called when initdata is NULL, maybe BUG()? */ + return -EINVAL; +} + +static int dvb_pll_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + u8 buf[4]; + struct i2c_msg msg = + { .addr = priv->pll_i2c_address, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + int result; + u32 frequency = 0; + + if (priv->i2c == NULL) + return -EINVAL; + + if ((result = dvb_pll_configure(fe, buf, params)) < 0) + return result; + else + frequency = result; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { + return result; + } + + priv->frequency = frequency; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + + return 0; +} + +static int dvb_pll_calc_regs(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + u8 *buf, int buf_len) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + int result; + u32 frequency = 0; + + if (buf_len < 5) + return -EINVAL; + + if ((result = dvb_pll_configure(fe, buf+1, params)) < 0) + return result; + else + frequency = result; + + buf[0] = priv->pll_i2c_address; + + priv->frequency = frequency; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + + return 5; +} + +static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int dvb_pll_init(struct dvb_frontend *fe) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + + if (priv->i2c == NULL) + return -EINVAL; + + if (priv->pll_desc->initdata) { + struct i2c_msg msg = { .flags = 0, + .addr = priv->pll_i2c_address, + .buf = priv->pll_desc->initdata + 1, + .len = priv->pll_desc->initdata[0] }; + + int result; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + result = i2c_transfer(priv->i2c, &msg, 1); + if (result != 1) + return result; + if (priv->pll_desc->initdata2) { + msg.buf = priv->pll_desc->initdata2 + 1; + msg.len = priv->pll_desc->initdata2[0]; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + result = i2c_transfer(priv->i2c, &msg, 1); + if (result != 1) + return result; + } + return 0; + } + /* Shouldn't be called when initdata is NULL, maybe BUG()? */ + return -EINVAL; +} + +static struct dvb_tuner_ops dvb_pll_tuner_ops = { + .release = dvb_pll_release, + .sleep = dvb_pll_sleep, + .init = dvb_pll_init, + .set_params = dvb_pll_set_params, + .calc_regs = dvb_pll_calc_regs, + .get_frequency = dvb_pll_get_frequency, + .get_bandwidth = dvb_pll_get_bandwidth, +}; + +struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, + struct i2c_adapter *i2c, + unsigned int pll_desc_id) +{ + u8 b1 [] = { 0 }; + struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, + .buf = b1, .len = 1 }; + struct dvb_pll_priv *priv = NULL; + int ret; + struct dvb_pll_desc *desc; + + if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) && + (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list))) + pll_desc_id = id[dvb_pll_devcount]; + + BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list)); + + desc = pll_list[pll_desc_id]; + + if (i2c != NULL) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer (i2c, &msg, 1); + if (ret != 1) + return NULL; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->pll_i2c_address = pll_addr; + priv->i2c = i2c; + priv->pll_desc = desc; + priv->nr = dvb_pll_devcount++; + + memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + strncpy(fe->ops.tuner_ops.info.name, desc->name, + sizeof(fe->ops.tuner_ops.info.name)); + fe->ops.tuner_ops.info.frequency_min = desc->min; + fe->ops.tuner_ops.info.frequency_max = desc->max; + if (!desc->initdata) + fe->ops.tuner_ops.init = NULL; + if (!desc->sleepdata) + fe->ops.tuner_ops.sleep = NULL; + + fe->tuner_priv = priv; + + if ((debug) || (id[priv->nr] == pll_desc_id)) { + printk("dvb-pll[%d]", priv->nr); + if (i2c != NULL) + printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, + id[priv->nr] == pll_desc_id ? + "insmod option" : "autodetected"); + } + + return fe; +} +EXPORT_SYMBOL(dvb_pll_attach); + +MODULE_DESCRIPTION("dvb pll library"); +MODULE_AUTHOR("Gerd Knorr"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb-pll.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb-pll.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb-pll.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/dvb-pll.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * descriptions + helper functions for simple dvb plls. + */ + +#ifndef __DVB_PLL_H__ +#define __DVB_PLL_H__ + +#include +#include "dvb_frontend.h" + +#define DVB_PLL_UNDEFINED 0 +#define DVB_PLL_THOMSON_DTT7579 1 +#define DVB_PLL_THOMSON_DTT759X 2 +#define DVB_PLL_LG_Z201 3 +#define DVB_PLL_UNKNOWN_1 4 +#define DVB_PLL_TUA6010XS 5 +#define DVB_PLL_ENV57H1XD5 6 +#define DVB_PLL_TUA6034 7 +#define DVB_PLL_TDA665X 8 +#define DVB_PLL_TDED4 9 +#define DVB_PLL_TDHU2 10 +#define DVB_PLL_SAMSUNG_TBMV 11 +#define DVB_PLL_PHILIPS_SD1878_TDA8261 12 +#define DVB_PLL_OPERA1 13 +#define DVB_PLL_SAMSUNG_DTOS403IH102A 14 +#define DVB_PLL_SAMSUNG_TDTC9251DH0 15 +#define DVB_PLL_SAMSUNG_TBDU18132 16 +#define DVB_PLL_SAMSUNG_TBMU24112 17 +#define DVB_PLL_TDEE4 18 + +/** + * Attach a dvb-pll to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param pll_addr i2c address of the PLL (if used). + * @param i2c i2c adapter to use (set to NULL if not used). + * @param pll_desc_id dvb_pll_desc to use. + * @return Frontend pointer on success, NULL on failure + */ +#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE)) +extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, + int pll_addr, + struct i2c_adapter *i2c, + unsigned int pll_desc_id); +#else +static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, + int pll_addr, + struct i2c_adapter *i2c, + unsigned int pll_desc_id) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,335 @@ +/* + * E3C EC100 demodulator driver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "dvb_frontend.h" +#include "ec100_priv.h" +#include "ec100.h" + +int ec100_debug; +module_param_named(debug, ec100_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +struct ec100_state { + struct i2c_adapter *i2c; + struct dvb_frontend frontend; + struct ec100_config config; + + u16 ber; +}; + +/* write single register */ +static int ec100_write_reg(struct ec100_state *state, u8 reg, u8 val) +{ + u8 buf[2] = {reg, val}; + struct i2c_msg msg = { + .addr = state->config.demod_address, + .flags = 0, + .len = 2, + .buf = buf}; + + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + warn("I2C write failed reg:%02x", reg); + return -EREMOTEIO; + } + return 0; +} + +/* read single register */ +static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { + .addr = state->config.demod_address, + .flags = 0, + .len = 1, + .buf = ® + }, { + .addr = state->config.demod_address, + .flags = I2C_M_RD, + .len = 1, + .buf = val + } + }; + + if (i2c_transfer(state->i2c, msg, 2) != 2) { + warn("I2C read failed reg:%02x", reg); + return -EREMOTEIO; + } + return 0; +} + +static int ec100_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct ec100_state *state = fe->demodulator_priv; + int ret; + u8 tmp, tmp2; + + deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, + params->u.ofdm.bandwidth); + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, params); + + ret = ec100_write_reg(state, 0x04, 0x06); + if (ret) + goto error; + ret = ec100_write_reg(state, 0x67, 0x58); + if (ret) + goto error; + ret = ec100_write_reg(state, 0x05, 0x18); + if (ret) + goto error; + + /* reg/bw | 6 | 7 | 8 + -------+------+------+------ + A 0x1b | 0xa1 | 0xe7 | 0x2c + A 0x1c | 0x55 | 0x63 | 0x72 + -------+------+------+------ + B 0x1b | 0xb7 | 0x00 | 0x49 + B 0x1c | 0x55 | 0x64 | 0x72 */ + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + tmp = 0xb7; + tmp2 = 0x55; + break; + case BANDWIDTH_7_MHZ: + tmp = 0x00; + tmp2 = 0x64; + break; + case BANDWIDTH_8_MHZ: + default: + tmp = 0x49; + tmp2 = 0x72; + } + + ret = ec100_write_reg(state, 0x1b, tmp); + if (ret) + goto error; + ret = ec100_write_reg(state, 0x1c, tmp2); + if (ret) + goto error; + + ret = ec100_write_reg(state, 0x0c, 0xbb); /* if freq */ + if (ret) + goto error; + ret = ec100_write_reg(state, 0x0d, 0x31); /* if freq */ + if (ret) + goto error; + + ret = ec100_write_reg(state, 0x08, 0x24); + if (ret) + goto error; + + ret = ec100_write_reg(state, 0x00, 0x00); /* go */ + if (ret) + goto error; + ret = ec100_write_reg(state, 0x00, 0x20); /* go */ + if (ret) + goto error; + + return ret; +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + +static int ec100_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 300; + fesettings->step_size = 0; + fesettings->max_drift = 0; + + return 0; +} + +static int ec100_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct ec100_state *state = fe->demodulator_priv; + int ret; + u8 tmp; + *status = 0; + + ret = ec100_read_reg(state, 0x42, &tmp); + if (ret) + goto error; + + if (tmp & 0x80) { + /* bit7 set - have lock */ + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_LOCK; + } else { + ret = ec100_read_reg(state, 0x01, &tmp); + if (ret) + goto error; + + if (tmp & 0x10) { + /* bit4 set - have signal */ + *status |= FE_HAS_SIGNAL; + if (!(tmp & 0x01)) { + /* bit0 clear - have ~valid signal */ + *status |= FE_HAS_CARRIER | FE_HAS_VITERBI; + } + } + } + + return ret; +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + +static int ec100_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct ec100_state *state = fe->demodulator_priv; + int ret; + u8 tmp, tmp2; + u16 ber2; + + *ber = 0; + + ret = ec100_read_reg(state, 0x65, &tmp); + if (ret) + goto error; + ret = ec100_read_reg(state, 0x66, &tmp2); + if (ret) + goto error; + + ber2 = (tmp2 << 8) | tmp; + + /* if counter overflow or clear */ + if (ber2 < state->ber) + *ber = ber2; + else + *ber = ber2 - state->ber; + + state->ber = ber2; + + return ret; +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + +static int ec100_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct ec100_state *state = fe->demodulator_priv; + int ret; + u8 tmp; + + ret = ec100_read_reg(state, 0x24, &tmp); + if (ret) { + *strength = 0; + goto error; + } + + *strength = ((tmp << 8) | tmp); + + return ret; +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + +static int ec100_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + *snr = 0; + return 0; +} + +static int ec100_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + return 0; +} + +static void ec100_release(struct dvb_frontend *fe) +{ + struct ec100_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops ec100_ops; + +struct dvb_frontend *ec100_attach(const struct ec100_config *config, + struct i2c_adapter *i2c) +{ + int ret; + struct ec100_state *state = NULL; + u8 tmp; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct ec100_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->i2c = i2c; + memcpy(&state->config, config, sizeof(struct ec100_config)); + + /* check if the demod is there */ + ret = ec100_read_reg(state, 0x33, &tmp); + if (ret || tmp != 0x0b) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &ec100_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(ec100_attach); + +static struct dvb_frontend_ops ec100_ops = { + .info = { + .name = "E3C EC100 DVB-T", + .type = FE_OFDM, + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | + FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_MUTE_TS + }, + + .release = ec100_release, + .set_frontend = ec100_set_frontend, + .get_tune_settings = ec100_get_tune_settings, + .read_status = ec100_read_status, + .read_ber = ec100_read_ber, + .read_signal_strength = ec100_read_signal_strength, + .read_snr = ec100_read_snr, + .read_ucblocks = ec100_read_ucblocks, +}; + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("E3C EC100 DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * E3C EC100 demodulator driver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef EC100_H +#define EC100_H + +#include + +struct ec100_config { + /* demodulator's I2C address */ + u8 demod_address; +}; + + +#if defined(CONFIG_DVB_EC100) || \ + (defined(CONFIG_DVB_EC100_MODULE) && defined(MODULE)) +extern struct dvb_frontend *ec100_attach(const struct ec100_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *ec100_attach( + const struct ec100_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* EC100_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ec100_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * E3C EC100 demodulator driver + * + * Copyright (C) 2009 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef EC100_PRIV +#define EC100_PRIV + +#define LOG_PREFIX "ec100" + +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) + +#define deb_info(args...) dprintk(ec100_debug, 0x01, args) + +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +#endif /* EC100_PRIV */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/eds1547.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/eds1547.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/eds1547.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/eds1547.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,133 @@ +/* eds1547.h Earda EDS-1547 tuner support +* +* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) +* +* 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, version 2. +* +* see Documentation/dvb/README.dvb-usb for more information +*/ + +#ifndef EDS1547 +#define EDS1547 + +static u8 stv0288_earda_inittab[] = { + 0x01, 0x57, + 0x02, 0x20, + 0x03, 0x8e, + 0x04, 0x8e, + 0x05, 0x12, + 0x06, 0x00, + 0x07, 0x00, + 0x09, 0x00, + 0x0a, 0x04, + 0x0b, 0x00, + 0x0c, 0x00, + 0x0d, 0x00, + 0x0e, 0xd4, + 0x0f, 0x30, + 0x11, 0x44, + 0x12, 0x03, + 0x13, 0x48, + 0x14, 0x84, + 0x15, 0x45, + 0x16, 0xb7, + 0x17, 0x9c, + 0x18, 0x00, + 0x19, 0xa6, + 0x1a, 0x88, + 0x1b, 0x8f, + 0x1c, 0xf0, + 0x20, 0x0b, + 0x21, 0x54, + 0x22, 0x00, + 0x23, 0x00, + 0x2b, 0xff, + 0x2c, 0xf7, + 0x30, 0x00, + 0x31, 0x1e, + 0x32, 0x14, + 0x33, 0x0f, + 0x34, 0x09, + 0x35, 0x0c, + 0x36, 0x05, + 0x37, 0x2f, + 0x38, 0x16, + 0x39, 0xbd, + 0x3a, 0x00, + 0x3b, 0x13, + 0x3c, 0x11, + 0x3d, 0x30, + 0x40, 0x63, + 0x41, 0x04, + 0x42, 0x20, + 0x43, 0x00, + 0x44, 0x00, + 0x45, 0x00, + 0x46, 0x00, + 0x47, 0x00, + 0x4a, 0x00, + 0x50, 0x10, + 0x51, 0x36, + 0x52, 0x09, + 0x53, 0x94, + 0x54, 0x62, + 0x55, 0x29, + 0x56, 0x64, + 0x57, 0x2b, + 0x58, 0x54, + 0x59, 0x86, + 0x5a, 0x00, + 0x5b, 0x9b, + 0x5c, 0x08, + 0x5d, 0x7f, + 0x5e, 0x00, + 0x5f, 0xff, + 0x70, 0x00, + 0x71, 0x00, + 0x72, 0x00, + 0x74, 0x00, + 0x75, 0x00, + 0x76, 0x00, + 0x81, 0x00, + 0x82, 0x3f, + 0x83, 0x3f, + 0x84, 0x00, + 0x85, 0x00, + 0x88, 0x00, + 0x89, 0x00, + 0x8a, 0x00, + 0x8b, 0x00, + 0x8c, 0x00, + 0x90, 0x00, + 0x91, 0x00, + 0x92, 0x00, + 0x93, 0x00, + 0x94, 0x1c, + 0x97, 0x00, + 0xa0, 0x48, + 0xa1, 0x00, + 0xb0, 0xb8, + 0xb1, 0x3a, + 0xb2, 0x10, + 0xb3, 0x82, + 0xb4, 0x80, + 0xb5, 0x82, + 0xb6, 0x82, + 0xb7, 0x82, + 0xb8, 0x20, + 0xb9, 0x00, + 0xf0, 0x00, + 0xf1, 0x00, + 0xf2, 0xc0, + 0xff,0xff, +}; + +static struct stv0288_config earda_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + .inittab = stv0288_earda_inittab, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6405.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6405.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6405.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6405.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,164 @@ +/* + * isl6405.c - driver for dual lnb supply and control ic ISL6405 + * + * Copyright (C) 2008 Hartmut Hackmann + * Copyright (C) 2006 Oliver Endriss + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "isl6405.h" + +struct isl6405 { + u8 config; + u8 override_or; + u8 override_and; + struct i2c_adapter *i2c; + u8 i2c_addr; +}; + +static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv; + struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0, + .buf = &isl6405->config, + .len = sizeof(isl6405->config) }; + + if (isl6405->override_or & 0x80) { + isl6405->config &= ~(ISL6405_VSEL2 | ISL6405_EN2); + switch (voltage) { + case SEC_VOLTAGE_OFF: + break; + case SEC_VOLTAGE_13: + isl6405->config |= ISL6405_EN2; + break; + case SEC_VOLTAGE_18: + isl6405->config |= (ISL6405_EN2 | ISL6405_VSEL2); + break; + default: + return -EINVAL; + } + } else { + isl6405->config &= ~(ISL6405_VSEL1 | ISL6405_EN1); + switch (voltage) { + case SEC_VOLTAGE_OFF: + break; + case SEC_VOLTAGE_13: + isl6405->config |= ISL6405_EN1; + break; + case SEC_VOLTAGE_18: + isl6405->config |= (ISL6405_EN1 | ISL6405_VSEL1); + break; + default: + return -EINVAL; + }; + } + isl6405->config |= isl6405->override_or; + isl6405->config &= isl6405->override_and; + + return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static int isl6405_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) +{ + struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv; + struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0, + .buf = &isl6405->config, + .len = sizeof(isl6405->config) }; + + if (isl6405->override_or & 0x80) { + if (arg) + isl6405->config |= ISL6405_LLC2; + else + isl6405->config &= ~ISL6405_LLC2; + } else { + if (arg) + isl6405->config |= ISL6405_LLC1; + else + isl6405->config &= ~ISL6405_LLC1; + } + isl6405->config |= isl6405->override_or; + isl6405->config &= isl6405->override_and; + + return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static void isl6405_release(struct dvb_frontend *fe) +{ + /* power off */ + isl6405_set_voltage(fe, SEC_VOLTAGE_OFF); + + /* free */ + kfree(fe->sec_priv); + fe->sec_priv = NULL; +} + +struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, + u8 i2c_addr, u8 override_set, u8 override_clear) +{ + struct isl6405 *isl6405 = kmalloc(sizeof(struct isl6405), GFP_KERNEL); + if (!isl6405) + return NULL; + + /* default configuration */ + if (override_set & 0x80) + isl6405->config = ISL6405_ISEL2; + else + isl6405->config = ISL6405_ISEL1; + isl6405->i2c = i2c; + isl6405->i2c_addr = i2c_addr; + fe->sec_priv = isl6405; + + /* bits which should be forced to '1' */ + isl6405->override_or = override_set; + + /* bits which should be forced to '0' */ + isl6405->override_and = ~override_clear; + + /* detect if it is present or not */ + if (isl6405_set_voltage(fe, SEC_VOLTAGE_OFF)) { + kfree(isl6405); + fe->sec_priv = NULL; + return NULL; + } + + /* install release callback */ + fe->ops.release_sec = isl6405_release; + + /* override frontend ops */ + fe->ops.set_voltage = isl6405_set_voltage; + fe->ops.enable_high_lnb_voltage = isl6405_enable_high_lnb_voltage; + + return fe; +} +EXPORT_SYMBOL(isl6405_attach); + +MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405"); +MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6405.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6405.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6405.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6405.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * isl6405.h - driver for dual lnb supply and control ic ISL6405 + * + * Copyright (C) 2008 Hartmut Hackmann + * Copyright (C) 2006 Oliver Endriss + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ + +#ifndef _ISL6405_H +#define _ISL6405_H + +#include + +/* system register bits */ + +/* this bit selects register (control) 1 or 2 + note that the bit maps are different */ + +#define ISL6405_SR 0x80 + +/* SR = 0 */ +#define ISL6405_OLF1 0x01 +#define ISL6405_EN1 0x02 +#define ISL6405_VSEL1 0x04 +#define ISL6405_LLC1 0x08 +#define ISL6405_ENT1 0x10 +#define ISL6405_ISEL1 0x20 +#define ISL6405_DCL 0x40 + +/* SR = 1 */ +#define ISL6405_OLF2 0x01 +#define ISL6405_OTF 0x02 +#define ISL6405_EN2 0x04 +#define ISL6405_VSEL2 0x08 +#define ISL6405_LLC2 0x10 +#define ISL6405_ENT2 0x20 +#define ISL6405_ISEL2 0x40 + +#if defined(CONFIG_DVB_ISL6405) || (defined(CONFIG_DVB_ISL6405_MODULE) && defined(MODULE)) +/* override_set and override_clear control which system register bits (above) + * to always set & clear + */ +extern struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, + u8 i2c_addr, u8 override_set, u8 override_clear); +#else +static inline struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 i2c_addr, + u8 override_set, u8 override_clear) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_ISL6405 */ + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6421.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6421.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6421.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6421.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,141 @@ +/* + * isl6421.h - driver for lnb supply and control ic ISL6421 + * + * Copyright (C) 2006 Andrew de Quincey + * Copyright (C) 2006 Oliver Endriss + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "isl6421.h" + +struct isl6421 { + u8 config; + u8 override_or; + u8 override_and; + struct i2c_adapter *i2c; + u8 i2c_addr; +}; + +static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; + struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, + .buf = &isl6421->config, + .len = sizeof(isl6421->config) }; + + isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1); + + switch(voltage) { + case SEC_VOLTAGE_OFF: + break; + case SEC_VOLTAGE_13: + isl6421->config |= ISL6421_EN1; + break; + case SEC_VOLTAGE_18: + isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1); + break; + default: + return -EINVAL; + }; + + isl6421->config |= isl6421->override_or; + isl6421->config &= isl6421->override_and; + + return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) +{ + struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; + struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, + .buf = &isl6421->config, + .len = sizeof(isl6421->config) }; + + if (arg) + isl6421->config |= ISL6421_LLC1; + else + isl6421->config &= ~ISL6421_LLC1; + + isl6421->config |= isl6421->override_or; + isl6421->config &= isl6421->override_and; + + return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static void isl6421_release(struct dvb_frontend *fe) +{ + /* power off */ + isl6421_set_voltage(fe, SEC_VOLTAGE_OFF); + + /* free */ + kfree(fe->sec_priv); + fe->sec_priv = NULL; +} + +struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, + u8 override_set, u8 override_clear) +{ + struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL); + if (!isl6421) + return NULL; + + /* default configuration */ + isl6421->config = ISL6421_ISEL1; + isl6421->i2c = i2c; + isl6421->i2c_addr = i2c_addr; + fe->sec_priv = isl6421; + + /* bits which should be forced to '1' */ + isl6421->override_or = override_set; + + /* bits which should be forced to '0' */ + isl6421->override_and = ~override_clear; + + /* detect if it is present or not */ + if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) { + kfree(isl6421); + fe->sec_priv = NULL; + return NULL; + } + + /* install release callback */ + fe->ops.release_sec = isl6421_release; + + /* override frontend ops */ + fe->ops.set_voltage = isl6421_set_voltage; + fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage; + + return fe; +} +EXPORT_SYMBOL(isl6421_attach); + +MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421"); +MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6421.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6421.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6421.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6421.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * isl6421.h - driver for lnb supply and control ic ISL6421 + * + * Copyright (C) 2006 Andrew de Quincey + * Copyright (C) 2006 Oliver Endriss + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ + +#ifndef _ISL6421_H +#define _ISL6421_H + +#include + +/* system register bits */ +#define ISL6421_OLF1 0x01 +#define ISL6421_EN1 0x02 +#define ISL6421_VSEL1 0x04 +#define ISL6421_LLC1 0x08 +#define ISL6421_ENT1 0x10 +#define ISL6421_ISEL1 0x20 +#define ISL6421_DCL 0x40 + +#if defined(CONFIG_DVB_ISL6421) || (defined(CONFIG_DVB_ISL6421_MODULE) && defined(MODULE)) +/* override_set and override_clear control which system register bits (above) to always set & clear */ +extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, + u8 override_set, u8 override_clear); +#else +static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, + u8 override_set, u8 override_clear) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_ISL6421 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6423.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6423.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6423.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6423.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,308 @@ +/* + Intersil ISL6423 SEC and LNB Power supply controller + + Copyright (C) Manu Abraham + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "isl6423.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 +#define FE_DEBUGREG 4 + +#define dprintk(__y, __z, format, arg...) do { \ + if (__z) { \ + if ((verbose > FE_ERROR) && (verbose > __y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_NOTICE) && (verbose > __y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_INFO) && (verbose > __y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_DEBUG) && (verbose > __y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (verbose > __y) \ + printk(format, ##arg); \ + } \ +} while (0) + +struct isl6423_dev { + const struct isl6423_config *config; + struct i2c_adapter *i2c; + + u8 reg_3; + u8 reg_4; + + unsigned int verbose; +}; + +static int isl6423_write(struct isl6423_dev *isl6423, u8 reg) +{ + struct i2c_adapter *i2c = isl6423->i2c; + u8 addr = isl6423->config->addr; + int err = 0; + + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = ®, .len = 1 }; + + dprintk(FE_DEBUG, 1, "write reg %02X", reg); + err = i2c_transfer(i2c, &msg, 1); + if (err < 0) + goto exit; + return 0; + +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + +static int isl6423_set_modulation(struct dvb_frontend *fe) +{ + struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; + const struct isl6423_config *config = isl6423->config; + int err = 0; + u8 reg_2 = 0; + + reg_2 = 0x01 << 5; + + if (config->mod_extern) + reg_2 |= (1 << 3); + else + reg_2 |= (1 << 4); + + err = isl6423_write(isl6423, reg_2); + if (err < 0) + goto exit; + return 0; + +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + +static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg) +{ + struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; + u8 reg_3 = isl6423->reg_3; + u8 reg_4 = isl6423->reg_4; + int err = 0; + + if (arg) { + /* EN = 1, VSPEN = 1, VBOT = 1 */ + reg_4 |= (1 << 4); + reg_4 |= 0x1; + reg_3 |= (1 << 3); + } else { + /* EN = 1, VSPEN = 1, VBOT = 0 */ + reg_4 |= (1 << 4); + reg_4 &= ~0x1; + reg_3 |= (1 << 3); + } + err = isl6423_write(isl6423, reg_3); + if (err < 0) + goto exit; + + err = isl6423_write(isl6423, reg_4); + if (err < 0) + goto exit; + + isl6423->reg_3 = reg_3; + isl6423->reg_4 = reg_4; + + return 0; +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + + +static int isl6423_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) +{ + struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; + u8 reg_3 = isl6423->reg_3; + u8 reg_4 = isl6423->reg_4; + int err = 0; + + switch (voltage) { + case SEC_VOLTAGE_OFF: + /* EN = 0 */ + reg_4 &= ~(1 << 4); + break; + + case SEC_VOLTAGE_13: + /* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */ + reg_4 |= (1 << 4); + reg_4 &= ~0x3; + reg_3 |= (1 << 3); + break; + + case SEC_VOLTAGE_18: + /* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */ + reg_4 |= (1 << 4); + reg_4 |= 0x2; + reg_4 &= ~0x1; + reg_3 |= (1 << 3); + break; + + default: + break; + } + err = isl6423_write(isl6423, reg_3); + if (err < 0) + goto exit; + + err = isl6423_write(isl6423, reg_4); + if (err < 0) + goto exit; + + isl6423->reg_3 = reg_3; + isl6423->reg_4 = reg_4; + + return 0; +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + +static int isl6423_set_current(struct dvb_frontend *fe) +{ + struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; + u8 reg_3 = isl6423->reg_3; + const struct isl6423_config *config = isl6423->config; + int err = 0; + + switch (config->current_max) { + case SEC_CURRENT_275m: + /* 275mA */ + /* ISELH = 0, ISELL = 0 */ + reg_3 &= ~0x3; + break; + + case SEC_CURRENT_515m: + /* 515mA */ + /* ISELH = 0, ISELL = 1 */ + reg_3 &= ~0x2; + reg_3 |= 0x1; + break; + + case SEC_CURRENT_635m: + /* 635mA */ + /* ISELH = 1, ISELL = 0 */ + reg_3 &= ~0x1; + reg_3 |= 0x2; + break; + + case SEC_CURRENT_800m: + /* 800mA */ + /* ISELH = 1, ISELL = 1 */ + reg_3 |= 0x3; + break; + } + + err = isl6423_write(isl6423, reg_3); + if (err < 0) + goto exit; + + switch (config->curlim) { + case SEC_CURRENT_LIM_ON: + /* DCL = 0 */ + reg_3 &= ~0x10; + break; + + case SEC_CURRENT_LIM_OFF: + /* DCL = 1 */ + reg_3 |= 0x10; + break; + } + + err = isl6423_write(isl6423, reg_3); + if (err < 0) + goto exit; + + isl6423->reg_3 = reg_3; + + return 0; +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + +static void isl6423_release(struct dvb_frontend *fe) +{ + isl6423_set_voltage(fe, SEC_VOLTAGE_OFF); + + kfree(fe->sec_priv); + fe->sec_priv = NULL; +} + +struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct isl6423_config *config) +{ + struct isl6423_dev *isl6423; + + isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL); + if (!isl6423) + return NULL; + + isl6423->config = config; + isl6423->i2c = i2c; + fe->sec_priv = isl6423; + + /* SR3H = 0, SR3M = 1, SR3L = 0 */ + isl6423->reg_3 = 0x02 << 5; + /* SR4H = 0, SR4M = 1, SR4L = 1 */ + isl6423->reg_4 = 0x03 << 5; + + if (isl6423_set_current(fe)) + goto exit; + + if (isl6423_set_modulation(fe)) + goto exit; + + fe->ops.release_sec = isl6423_release; + fe->ops.set_voltage = isl6423_set_voltage; + fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost; + isl6423->verbose = verbose; + + return fe; + +exit: + kfree(isl6423); + fe->sec_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(isl6423_attach); + +MODULE_DESCRIPTION("ISL6423 SEC"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6423.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6423.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6423.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/isl6423.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + Intersil ISL6423 SEC and LNB Power supply controller + + Copyright (C) Manu Abraham + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ISL_6423_H +#define __ISL_6423_H + +#include + +enum isl6423_current { + SEC_CURRENT_275m = 0, + SEC_CURRENT_515m, + SEC_CURRENT_635m, + SEC_CURRENT_800m, +}; + +enum isl6423_curlim { + SEC_CURRENT_LIM_ON = 1, + SEC_CURRENT_LIM_OFF +}; + +struct isl6423_config { + enum isl6423_current current_max; + enum isl6423_curlim curlim; + u8 addr; + u8 mod_extern; +}; + +#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE)) + + +extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct isl6423_config *config); + +#else +static inline struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct isl6423_config *config) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_ISL6423 */ + +#endif /* __ISL_6423_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,398 @@ +/* + * Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite" + * + * Copyright (c) 2007-8 Patrick Boettcher + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "itd1000.h" +#include "itd1000_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define itd_dbg(args...) do { \ + if (debug) { \ + printk(KERN_DEBUG "ITD1000: " args);\ + } \ +} while (0) + +#define itd_warn(args...) do { \ + printk(KERN_WARNING "ITD1000: " args); \ +} while (0) + +#define itd_info(args...) do { \ + printk(KERN_INFO "ITD1000: " args); \ +} while (0) + +/* don't write more than one byte with flexcop behind */ +static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 len) +{ + u8 buf[1+len]; + struct i2c_msg msg = { + .addr = state->cfg->i2c_address, .flags = 0, .buf = buf, .len = len+1 + }; + buf[0] = reg; + memcpy(&buf[1], v, len); + + /* itd_dbg("wr %02x: %02x\n", reg, v[0]); */ + + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "itd1000 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int itd1000_read_reg(struct itd1000_state *state, u8 reg) +{ + u8 val; + struct i2c_msg msg[2] = { + { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = &val, .len = 1 }, + }; + + /* ugly flexcop workaround */ + itd1000_write_regs(state, (reg - 1) & 0xff, &state->shadow[(reg - 1) & 0xff], 1); + + if (i2c_transfer(state->i2c, msg, 2) != 2) { + itd_warn("itd1000 I2C read failed\n"); + return -EREMOTEIO; + } + return val; +} + +static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v) +{ + int ret = itd1000_write_regs(state, r, &v, 1); + state->shadow[r] = v; + return ret; +} + + +static struct { + u32 symbol_rate; + u8 pgaext : 4; /* PLLFH */ + u8 bbgvmin : 4; /* BBGVMIN */ +} itd1000_lpf_pga[] = { + { 0, 0x8, 0x3 }, + { 5200000, 0x8, 0x3 }, + { 12200000, 0x4, 0x3 }, + { 15400000, 0x2, 0x3 }, + { 19800000, 0x2, 0x3 }, + { 21500000, 0x2, 0x3 }, + { 24500000, 0x2, 0x3 }, + { 28400000, 0x2, 0x3 }, + { 33400000, 0x2, 0x3 }, + { 34400000, 0x1, 0x4 }, + { 34400000, 0x1, 0x4 }, + { 38400000, 0x1, 0x4 }, + { 38400000, 0x1, 0x4 }, + { 40400000, 0x1, 0x4 }, + { 45400000, 0x1, 0x4 }, +}; + +static void itd1000_set_lpf_bw(struct itd1000_state *state, u32 symbol_rate) +{ + u8 i; + u8 con1 = itd1000_read_reg(state, CON1) & 0xfd; + u8 pllfh = itd1000_read_reg(state, PLLFH) & 0x0f; + u8 bbgvmin = itd1000_read_reg(state, BBGVMIN) & 0xf0; + u8 bw = itd1000_read_reg(state, BW) & 0xf0; + + itd_dbg("symbol_rate = %d\n", symbol_rate); + + /* not sure what is that ? - starting to download the table */ + itd1000_write_reg(state, CON1, con1 | (1 << 1)); + + for (i = 0; i < ARRAY_SIZE(itd1000_lpf_pga); i++) + if (symbol_rate < itd1000_lpf_pga[i].symbol_rate) { + itd_dbg("symrate: index: %d pgaext: %x, bbgvmin: %x\n", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin); + itd1000_write_reg(state, PLLFH, pllfh | (itd1000_lpf_pga[i].pgaext << 4)); + itd1000_write_reg(state, BBGVMIN, bbgvmin | (itd1000_lpf_pga[i].bbgvmin)); + itd1000_write_reg(state, BW, bw | (i & 0x0f)); + break; + } + + itd1000_write_reg(state, CON1, con1 | (0 << 1)); +} + +static struct { + u8 vcorg; + u32 fmax_rg; +} itd1000_vcorg[] = { + { 1, 920000 }, + { 2, 971000 }, + { 3, 1031000 }, + { 4, 1091000 }, + { 5, 1171000 }, + { 6, 1281000 }, + { 7, 1381000 }, + { 8, 500000 }, /* this is intentional. */ + { 9, 1451000 }, + { 10, 1531000 }, + { 11, 1631000 }, + { 12, 1741000 }, + { 13, 1891000 }, + { 14, 2071000 }, + { 15, 2250000 }, +}; + +static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz) +{ + u8 i; + u8 gvbb_i2c = itd1000_read_reg(state, GVBB_I2C) & 0xbf; + u8 vco_chp1_i2c = itd1000_read_reg(state, VCO_CHP1_I2C) & 0x0f; + u8 adcout; + + /* reserved bit again (reset ?) */ + itd1000_write_reg(state, GVBB_I2C, gvbb_i2c | (1 << 6)); + + for (i = 0; i < ARRAY_SIZE(itd1000_vcorg); i++) { + if (freq_khz < itd1000_vcorg[i].fmax_rg) { + itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | (itd1000_vcorg[i].vcorg << 4)); + msleep(1); + + adcout = itd1000_read_reg(state, PLLLOCK) & 0x0f; + + itd_dbg("VCO: %dkHz: %d -> ADCOUT: %d %02x\n", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c); + + if (adcout > 13) { + if (!(itd1000_vcorg[i].vcorg == 7 || itd1000_vcorg[i].vcorg == 15)) + itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg + 1) << 4)); + } else if (adcout < 2) { + if (!(itd1000_vcorg[i].vcorg == 1 || itd1000_vcorg[i].vcorg == 9)) + itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg - 1) << 4)); + } + break; + } + } +} + +static const struct { + u32 freq; + u8 values[10]; /* RFTR, RFST1 - RFST9 */ +} itd1000_fre_values[] = { + { 1075000, { 0x59, 0x1d, 0x1c, 0x17, 0x16, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, + { 1250000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, + { 1450000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, + { 1650000, { 0x69, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, + { 1750000, { 0x69, 0x1e, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } }, + { 1850000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } }, + { 1900000, { 0x69, 0x1d, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } }, + { 1950000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0d, 0x0b, 0x0a } }, + { 2050000, { 0x69, 0x1e, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0b, 0x0a } }, + { 2150000, { 0x69, 0x1d, 0x1c, 0x17, 0x15, 0x14, 0x13, 0x0f, 0x0e, 0x0b } } +}; + + +#define FREF 16 + +static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz) +{ + int i, j; + u32 plln, pllf; + u64 tmp; + + plln = (freq_khz * 1000) / 2 / FREF; + + /* Compute the factional part times 1000 */ + tmp = plln % 1000000; + plln /= 1000000; + + tmp *= 1048576; + do_div(tmp, 1000000); + pllf = (u32) tmp; + + state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF; + itd_dbg("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d\n", freq_khz, state->frequency, pllf, plln); + + itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */; + itd1000_write_reg(state, PLLNL, plln & 0xff); + itd1000_write_reg(state, PLLFH, (itd1000_read_reg(state, PLLFH) & 0xf0) | ((pllf >> 16) & 0x0f)); + itd1000_write_reg(state, PLLFM, (pllf >> 8) & 0xff); + itd1000_write_reg(state, PLLFL, (pllf >> 0) & 0xff); + + for (i = 0; i < ARRAY_SIZE(itd1000_fre_values); i++) { + if (freq_khz <= itd1000_fre_values[i].freq) { + itd_dbg("fre_values: %d\n", i); + itd1000_write_reg(state, RFTR, itd1000_fre_values[i].values[0]); + for (j = 0; j < 9; j++) + itd1000_write_reg(state, RFST1+j, itd1000_fre_values[i].values[j+1]); + break; + } + } + + itd1000_set_vco(state, freq_khz); +} + +static int itd1000_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct itd1000_state *state = fe->tuner_priv; + u8 pllcon1; + + itd1000_set_lo(state, p->frequency); + itd1000_set_lpf_bw(state, p->u.qpsk.symbol_rate); + + pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f; + itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7)); + itd1000_write_reg(state, PLLCON1, pllcon1); + + return 0; +} + +static int itd1000_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct itd1000_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int itd1000_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + return 0; +} + +static u8 itd1000_init_tab[][2] = { + { PLLCON1, 0x65 }, /* Register does not change */ + { PLLNH, 0x80 }, /* Bits [7:6] do not change */ + { RESERVED_0X6D, 0x3b }, + { VCO_CHP2_I2C, 0x12 }, + { 0x72, 0xf9 }, /* No such regsister defined */ + { RESERVED_0X73, 0xff }, + { RESERVED_0X74, 0xb2 }, + { RESERVED_0X75, 0xc7 }, + { EXTGVBBRF, 0xf0 }, + { DIVAGCCK, 0x80 }, + { BBTR, 0xa0 }, + { RESERVED_0X7E, 0x4f }, + { 0x82, 0x88 }, /* No such regsister defined */ + { 0x83, 0x80 }, /* No such regsister defined */ + { 0x84, 0x80 }, /* No such regsister defined */ + { RESERVED_0X85, 0x74 }, + { RESERVED_0X86, 0xff }, + { RESERVED_0X88, 0x02 }, + { RESERVED_0X89, 0x16 }, + { RFST0, 0x1f }, + { RESERVED_0X94, 0x66 }, + { RESERVED_0X95, 0x66 }, + { RESERVED_0X96, 0x77 }, + { RESERVED_0X97, 0x99 }, + { RESERVED_0X98, 0xff }, + { RESERVED_0X99, 0xfc }, + { RESERVED_0X9A, 0xba }, + { RESERVED_0X9B, 0xaa }, +}; + +static u8 itd1000_reinit_tab[][2] = { + { VCO_CHP1_I2C, 0x8a }, + { BW, 0x87 }, + { GVBB_I2C, 0x03 }, + { BBGVMIN, 0x03 }, + { CON1, 0x2e }, +}; + + +static int itd1000_init(struct dvb_frontend *fe) +{ + struct itd1000_state *state = fe->tuner_priv; + int i; + + for (i = 0; i < ARRAY_SIZE(itd1000_init_tab); i++) + itd1000_write_reg(state, itd1000_init_tab[i][0], itd1000_init_tab[i][1]); + + for (i = 0; i < ARRAY_SIZE(itd1000_reinit_tab); i++) + itd1000_write_reg(state, itd1000_reinit_tab[i][0], itd1000_reinit_tab[i][1]); + + return 0; +} + +static int itd1000_sleep(struct dvb_frontend *fe) +{ + return 0; +} + +static int itd1000_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops itd1000_tuner_ops = { + .info = { + .name = "Integrant ITD1000", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 125, /* kHz for QPSK frontends */ + }, + + .release = itd1000_release, + + .init = itd1000_init, + .sleep = itd1000_sleep, + + .set_params = itd1000_set_parameters, + .get_frequency = itd1000_get_frequency, + .get_bandwidth = itd1000_get_bandwidth +}; + + +struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg) +{ + struct itd1000_state *state = NULL; + u8 i = 0; + + state = kzalloc(sizeof(struct itd1000_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->cfg = cfg; + state->i2c = i2c; + + i = itd1000_read_reg(state, 0); + if (i != 0) { + kfree(state); + return NULL; + } + itd_info("successfully identified (ID: %d)\n", i); + + memset(state->shadow, 0xff, sizeof(state->shadow)); + for (i = 0x65; i < 0x9c; i++) + state->shadow[i] = itd1000_read_reg(state, i); + + memcpy(&fe->ops.tuner_ops, &itd1000_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + + return fe; +} +EXPORT_SYMBOL(itd1000_attach); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Integrant ITD1000 driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite" + * + * Copyright (c) 2007 Patrick Boettcher + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef ITD1000_H +#define ITD1000_H + +struct dvb_frontend; +struct i2c_adapter; + +struct itd1000_config { + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_TUNER_ITD1000) || (defined(CONFIG_DVB_TUNER_ITD1000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg); +#else +static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/itd1000_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* + * Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite" + * + * Copyright (c) 2007 Patrick Boettcher + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef ITD1000_PRIV_H +#define ITD1000_PRIV_H + +struct itd1000_state { + struct itd1000_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; /* contains the value resulting from the LO-setting */ + + /* ugly workaround for flexcop's incapable i2c-controller + * FIXME, if possible + */ + u8 shadow[256]; +}; + +enum itd1000_register { + VCO_CHP1 = 0x65, + VCO_CHP2, + PLLCON1, + PLLNH, + PLLNL, + PLLFH, + PLLFM, + PLLFL, + RESERVED_0X6D, + PLLLOCK, + VCO_CHP2_I2C, + VCO_CHP1_I2C, + BW, + RESERVED_0X73 = 0x73, + RESERVED_0X74, + RESERVED_0X75, + GVBB, + GVRF, + GVBB_I2C, + EXTGVBBRF, + DIVAGCCK, + BBTR, + RFTR, + BBGVMIN, + RESERVED_0X7E, + RESERVED_0X85 = 0x85, + RESERVED_0X86, + CON1, + RESERVED_0X88, + RESERVED_0X89, + RFST0, + RFST1, + RFST2, + RFST3, + RFST4, + RFST5, + RFST6, + RFST7, + RFST8, + RFST9, + RESERVED_0X94, + RESERVED_0X95, + RESERVED_0X96, + RESERVED_0X97, + RESERVED_0X98, + RESERVED_0X99, + RESERVED_0X9A, + RESERVED_0X9B, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ix2505v.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ix2505v.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ix2505v.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ix2505v.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,325 @@ +/** + * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner + * + * Copyright (C) 2010 Malcolm Priestley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#include "ix2505v.h" + +static int ix2505v_debug; +#define dprintk(level, args...) do { \ + if (ix2505v_debug & level) \ + printk(KERN_DEBUG "ix2505v: " args); \ +} while (0) + +#define deb_info(args...) dprintk(0x01, args) +#define deb_i2c(args...) dprintk(0x02, args) + +struct ix2505v_state { + struct i2c_adapter *i2c; + const struct ix2505v_config *config; + u32 frequency; +}; + +/** + * Data read format of the Sharp IX2505V B0017 + * + * byte1: 1 | 1 | 0 | 0 | 0 | MA1 | MA0 | 1 + * byte2: POR | FL | RD2 | RD1 | RD0 | X | X | X + * + * byte1 = address + * byte2; + * POR = Power on Reset (VCC H=<2.2v L=>2.2v) + * FL = Phase Lock (H=lock L=unlock) + * RD0-2 = Reserved internal operations + * + * Only POR can be used to check the tuner is present + * + * Caution: after byte2 the I2C reverts to write mode continuing to read + * may corrupt tuning data. + * + */ + +static int ix2505v_read_status_reg(struct ix2505v_state *state) +{ + u8 addr = state->config->tuner_address; + u8 b2[] = {0}; + int ret; + + struct i2c_msg msg[1] = { + { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } + }; + + ret = i2c_transfer(state->i2c, msg, 1); + deb_i2c("Read %s ", __func__); + + return (ret == 1) ? (int) b2[0] : -1; +} + +static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count) +{ + struct i2c_msg msg[1] = { + { .addr = state->config->tuner_address, .flags = 0, + .buf = buf, .len = count }, + }; + + int ret; + + ret = i2c_transfer(state->i2c, msg, 1); + + if (ret != 1) { + deb_i2c("%s: i2c error, ret=%d\n", __func__, ret); + return -EIO; + } + + return 0; +} + +static int ix2505v_release(struct dvb_frontend *fe) +{ + struct ix2505v_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + + return 0; +} + +/** + * Data write format of the Sharp IX2505V B0017 + * + * byte1: 1 | 1 | 0 | 0 | 0 | 0(MA1)| 0(MA0)| 0 + * byte2: 0 | BG1 | BG2 | N8 | N7 | N6 | N5 | N4 + * byte3: N3 | N2 | N1 | A5 | A4 | A3 | A2 | A1 + * byte4: 1 | 1(C1) | 1(C0) | PD5 | PD4 | TM | 0(RTS)| 1(REF) + * byte5: BA2 | BA1 | BA0 | PSC | PD3 |PD2/TS2|DIV/TS1|PD0/TS0 + * + * byte1 = address + * + * Write order + * 1) byte1 -> byte2 -> byte3 -> byte4 -> byte5 + * 2) byte1 -> byte4 -> byte5 -> byte2 -> byte3 + * 3) byte1 -> byte2 -> byte3 -> byte4 + * 4) byte1 -> byte4 -> byte5 -> byte2 + * 5) byte1 -> byte2 -> byte3 + * 6) byte1 -> byte4 -> byte5 + * 7) byte1 -> byte2 + * 8) byte1 -> byte4 + * + * Recommended Setup + * 1 -> 8 -> 6 + */ + +static int ix2505v_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct ix2505v_state *state = fe->tuner_priv; + u32 frequency = params->frequency; + u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000; + u32 div_factor, N , A, x; + int ret = 0, len; + u8 gain, cc, ref, psc, local_osc, lpf; + u8 data[4] = {0}; + + if ((frequency < fe->ops.info.frequency_min) + || (frequency > fe->ops.info.frequency_max)) + return -EINVAL; + + if (state->config->tuner_gain) + gain = (state->config->tuner_gain < 4) + ? state->config->tuner_gain : 0; + else + gain = 0x0; + + if (state->config->tuner_chargepump) + cc = state->config->tuner_chargepump; + else + cc = 0x3; + + ref = 8; /* REF =1 */ + psc = 32; /* PSC = 0 */ + + div_factor = (frequency * ref) / 40; /* local osc = 4Mhz */ + x = div_factor / psc; + N = x/100; + A = ((x - (N * 100)) * psc) / 100; + + data[0] = ((gain & 0x3) << 5) | (N >> 3); + data[1] = (N << 5) | (A & 0x1f); + data[2] = 0x81 | ((cc & 0x3) << 5) ; /*PD5,PD4 & TM = 0|C1,C0|REF=1*/ + + deb_info("Frq=%d x=%d N=%d A=%d\n", frequency, x, N, A); + + if (frequency <= 1065000) + local_osc = (6 << 5) | 2; + else if (frequency <= 1170000) + local_osc = (7 << 5) | 2; + else if (frequency <= 1300000) + local_osc = (1 << 5); + else if (frequency <= 1445000) + local_osc = (2 << 5); + else if (frequency <= 1607000) + local_osc = (3 << 5); + else if (frequency <= 1778000) + local_osc = (4 << 5); + else if (frequency <= 1942000) + local_osc = (5 << 5); + else /*frequency up to 2150000*/ + local_osc = (6 << 5); + + data[3] = local_osc; /* all other bits set 0 */ + + if (b_w <= 10000) + lpf = 0xc; + else if (b_w <= 12000) + lpf = 0x2; + else if (b_w <= 14000) + lpf = 0xa; + else if (b_w <= 16000) + lpf = 0x6; + else if (b_w <= 18000) + lpf = 0xe; + else if (b_w <= 20000) + lpf = 0x1; + else if (b_w <= 22000) + lpf = 0x9; + else if (b_w <= 24000) + lpf = 0x5; + else if (b_w <= 26000) + lpf = 0xd; + else if (b_w <= 28000) + lpf = 0x3; + else + lpf = 0xb; + + deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf); + deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + len = sizeof(data); + ret |= ix2505v_write(state, data, len); + + data[2] |= 0x4; /* set TM = 1 other bits same */ + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + len = 1; + ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */ + + msleep(10); + + data[2] |= ((lpf >> 2) & 0x3) << 3; /* lpf */ + data[3] |= (lpf & 0x3) << 2; + + deb_info("Data 2=[%x%x]\n", data[2], data[3]); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + len = 2; + ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */ + + if (state->config->min_delay_ms) + msleep(state->config->min_delay_ms); + + state->frequency = frequency; + + return ret; +} + +static int ix2505v_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct ix2505v_state *state = fe->tuner_priv; + + *frequency = state->frequency; + + return 0; +} + +static struct dvb_tuner_ops ix2505v_tuner_ops = { + .info = { + .name = "Sharp IX2505V (B0017)", + .frequency_min = 950000, + .frequency_max = 2175000 + }, + .release = ix2505v_release, + .set_params = ix2505v_set_params, + .get_frequency = ix2505v_get_frequency, +}; + +struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, + const struct ix2505v_config *config, + struct i2c_adapter *i2c) +{ + struct ix2505v_state *state = NULL; + int ret; + + if (NULL == config) { + deb_i2c("%s: no config ", __func__); + goto error; + } + + state = kzalloc(sizeof(struct ix2505v_state), GFP_KERNEL); + if (NULL == state) + return NULL; + + state->config = config; + state->i2c = i2c; + + if (state->config->tuner_write_only) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = ix2505v_read_status_reg(state); + + if (ret & 0x80) { + deb_i2c("%s: No IX2505V found\n", __func__); + goto error; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + fe->tuner_priv = state; + + memcpy(&fe->ops.tuner_ops, &ix2505v_tuner_ops, + sizeof(struct dvb_tuner_ops)); + deb_i2c("%s: initialization (%s addr=0x%02x) ok\n", + __func__, fe->ops.tuner_ops.info.name, config->tuner_address); + + return fe; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(ix2505v_attach); + +module_param_named(debug, ix2505v_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +MODULE_DESCRIPTION("DVB IX2505V tuner driver"); +MODULE_AUTHOR("Malcolm Priestley"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ix2505v.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ix2505v.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ix2505v.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ix2505v.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,64 @@ +/** + * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner + * + * Copyright (C) 2010 Malcolm Priestley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DVB_IX2505V_H +#define DVB_IX2505V_H + +#include +#include "dvb_frontend.h" + +/** + * Attach a ix2505v tuner to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param config ix2505v_config structure + * @return FE pointer on success, NULL on failure. + */ + +struct ix2505v_config { + u8 tuner_address; + + /*Baseband AMP gain control 0/1=0dB(default) 2=-2bB 3=-4dB */ + u8 tuner_gain; + + /*Charge pump output +/- 0=120 1=260 2=555 3=1200(default) */ + u8 tuner_chargepump; + + /* delay after tune */ + int min_delay_ms; + + /* disables reads*/ + u8 tuner_write_only; + +}; + +#if defined(CONFIG_DVB_IX2505V) || \ + (defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE)) +extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, + const struct ix2505v_config *config, struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, + const struct ix2505v_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* DVB_IX2505V_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,648 @@ +config DVB_FE_CUSTOMISE + bool "Customise the frontend modules to build" + depends on DVB_CORE + default y if EXPERT + help + This allows the user to select/deselect frontend drivers for their + hardware from the build. + + Use this option with care as deselecting frontends which are in fact + necessary will result in DVB devices which cannot be tuned due to lack + of driver support. + + If unsure say N. + +menu "Customise DVB Frontends" + visible if DVB_FE_CUSTOMISE + +comment "Multistandard (satellite) frontends" + depends on DVB_CORE + +config DVB_STB0899 + tristate "STB0899 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want + to support this demodulator based frontends + +config DVB_STB6100 + tristate "STB6100 based tuners" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A Silicon tuner from ST used in conjunction with the STB0899 + demodulator. Say Y when you want to support this tuner. + +config DVB_STV090x + tristate "STV0900/STV0903(A/B) based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators. + Say Y when you want to support these frontends. + +config DVB_STV6110x + tristate "STV6110/(A) based tuners" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A Silicon tuner that supports DVB-S and DVB-S2 modes + +comment "DVB-S (satellite) frontends" + depends on DVB_CORE + +config DVB_CX24110 + tristate "Conexant CX24110 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_CX24123 + tristate "Conexant CX24123 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_MT312 + tristate "Zarlink VP310/MT312/ZL10313 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_ZL10036 + tristate "Zarlink ZL10036 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_ZL10039 + tristate "Zarlink ZL10039 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_S5H1420 + tristate "Samsung S5H1420 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_STV0288 + tristate "ST STV0288 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_STB6000 + tristate "ST STB6000 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S silicon tuner module. Say Y when you want to support this tuner. + +config DVB_STV0299 + tristate "ST STV0299 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_STV6110 + tristate "ST STV6110 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S silicon tuner module. Say Y when you want to support this tuner. + +config DVB_STV0900 + tristate "ST STV0900 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S/S2 demodulator. Say Y when you want to support this frontend. + +config DVB_TDA8083 + tristate "Philips TDA8083 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_TDA10086 + tristate "Philips TDA10086 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_TDA8261 + tristate "Philips TDA8261 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_VES1X93 + tristate "VLSI VES1893 or VES1993 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_TUNER_ITD1000 + tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_TUNER_CX24113 + tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + + +config DVB_TDA826X + tristate "Philips TDA826X silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S silicon tuner module. Say Y when you want to support this tuner. + +config DVB_TUA6100 + tristate "Infineon TUA6100 PLL" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S PLL chip. + +config DVB_CX24116 + tristate "Conexant CX24116 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S/S2 tuner module. Say Y when you want to support this frontend. + +config DVB_SI21XX + tristate "Silicon Labs SI21XX based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_DS3000 + tristate "Montage Tehnology DS3000 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S/S2 tuner module. Say Y when you want to support this frontend. + +config DVB_MB86A16 + tristate "Fujitsu MB86A16 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S/DSS Direct Conversion reveiver. + Say Y when you want to support this frontend. + +comment "DVB-T (terrestrial) frontends" + depends on DVB_CORE + +config DVB_SP8870 + tristate "Spase sp8870 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + + This driver needs external firmware. Please use the command + "/Documentation/dvb/get_dvb_firmware sp8870" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + +config DVB_SP887X + tristate "Spase sp887x based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + + This driver needs external firmware. Please use the command + "/Documentation/dvb/get_dvb_firmware sp887x" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + +config DVB_CX22700 + tristate "Conexant CX22700 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + +config DVB_CX22702 + tristate "Conexant cx22702 demodulator (OFDM)" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + +config DVB_S5H1432 + tristate "Samsung s5h1432 demodulator (OFDM)" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + +config DVB_DRXD + tristate "Micronas DRXD driver" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + + Note: this driver was based on vendor driver reference code (released + under the GPL) as opposed to the existing drx397xd driver, which + was written via reverse engineering. + +config DVB_L64781 + tristate "LSI L64781" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + +config DVB_TDA1004X + tristate "Philips TDA10045H/TDA10046H based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + + This driver needs external firmware. Please use the commands + "/Documentation/dvb/get_dvb_firmware tda10045", + "/Documentation/dvb/get_dvb_firmware tda10046" to + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + +config DVB_NXT6000 + tristate "NxtWave Communications NXT6000 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + +config DVB_MT352 + tristate "Zarlink MT352 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + +config DVB_ZL10353 + tristate "Zarlink ZL10353 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + +config DVB_DIB3000MB + tristate "DiBcom 3000M-B" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Designed for mobile usage. Say Y when you want + to support this frontend. + +config DVB_DIB3000MC + tristate "DiBcom 3000P/M-C" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Designed for mobile usage. Say Y when you want + to support this frontend. + +config DVB_DIB7000M + tristate "DiBcom 7000MA/MB/PA/PB/MC" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Designed for mobile usage. Say Y when you want + to support this frontend. + +config DVB_DIB7000P + tristate "DiBcom 7000PC" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Designed for mobile usage. Say Y when you want + to support this frontend. + +config DVB_DIB9000 + tristate "DiBcom 9000" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Designed for mobile usage. Say Y when you want + to support this frontend. + +config DVB_TDA10048 + tristate "Philips TDA10048HN based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + +config DVB_AF9013 + tristate "Afatech AF9013 demodulator" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y when you want to support this frontend. + +config DVB_EC100 + tristate "E3C EC100" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y when you want to support this frontend. + +config DVB_STV0367 + tristate "ST STV0367 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T/C tuner module. Say Y when you want to support this frontend. + +config DVB_CXD2820R + tristate "Sony CXD2820R" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y when you want to support this frontend. + +comment "DVB-C (cable) frontends" + depends on DVB_CORE + +config DVB_VES1820 + tristate "VLSI VES1820 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-C tuner module. Say Y when you want to support this frontend. + +config DVB_TDA10021 + tristate "Philips TDA10021 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-C tuner module. Say Y when you want to support this frontend. + +config DVB_TDA10023 + tristate "Philips TDA10023 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-C tuner module. Say Y when you want to support this frontend. + +config DVB_STV0297 + tristate "ST STV0297 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-C tuner module. Say Y when you want to support this frontend. + +comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends" + depends on DVB_CORE + +config DVB_NXT200X + tristate "NxtWave Communications NXT2002/NXT2004 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + + This driver needs external firmware. Please use the commands + "/Documentation/dvb/get_dvb_firmware nxt2002" and + "/Documentation/dvb/get_dvb_firmware nxt2004" to + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + +config DVB_OR51211 + tristate "Oren OR51211 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB tuner module. Say Y when you want to support this frontend. + + This driver needs external firmware. Please use the command + "/Documentation/dvb/get_dvb_firmware or51211" to + download it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + +config DVB_OR51132 + tristate "Oren OR51132 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + + This driver needs external firmware. Please use the commands + "/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or + "/Documentation/dvb/get_dvb_firmware or51132_qam" to + download firmwares for 8VSB and QAM64/256, respectively. Copy them to + /usr/lib/hotplug/firmware or /lib/firmware (depending on + configuration of firmware hotplug). + +config DVB_BCM3510 + tristate "Broadcom BCM3510" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to + support this frontend. + +config DVB_LGDT330X + tristate "LG Electronics LGDT3302/LGDT3303 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + +config DVB_LGDT3305 + tristate "LG Electronics LGDT3304 and LGDT3305 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + +config DVB_S5H1409 + tristate "Samsung S5H1409 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + +config DVB_AU8522 + tristate "Auvitek AU8522 based" + depends on DVB_CORE && I2C && VIDEO_V4L2 + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + +config DVB_S5H1411 + tristate "Samsung S5H1411 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + +comment "ISDB-T (terrestrial) frontends" + depends on DVB_CORE + +config DVB_S921 + tristate "Sharp S921 frontend" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module. + Say Y when you want to support this frontend. + +config DVB_DIB8000 + tristate "DiBcom 8000MB/MC" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator. + Say Y when you want to support this frontend. + +config DVB_MB86A20S + tristate "Fujitsu mb86a20s" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator. + Say Y when you want to support this frontend. + +comment "Digital terrestrial only tuners/PLL" + depends on DVB_CORE + +config DVB_PLL + tristate "Generic I2C PLL based tuners" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + This module drives a number of tuners based on PLL chips with a + common I2C interface. Say Y when you want to support these tuners. + +config DVB_TUNER_DIB0070 + tristate "DiBcom DiB0070 silicon base-band tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner DiB0070 from DiBcom. + This device is only used inside a SiP called together with a + demodulator for now. + +config DVB_TUNER_DIB0090 + tristate "DiBcom DiB0090 silicon base-band tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner DiB0090 from DiBcom. + This device is only used inside a SiP called together with a + demodulator for now. + +comment "SEC control devices for DVB-S" + depends on DVB_CORE + +config DVB_LNBP21 + tristate "LNBP21/LNBH24 SEC controllers" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An SEC control chips. + +config DVB_ISL6405 + tristate "ISL6405 SEC controller" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An SEC control chip. + +config DVB_ISL6421 + tristate "ISL6421 SEC controller" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An SEC control chip. + +config DVB_ISL6423 + tristate "ISL6423 SEC controller" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A SEC controller chip from Intersil + +config DVB_LGS8GL5 + tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DMB-TH tuner module. Say Y when you want to support this frontend. + +config DVB_LGS8GXX + tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator" + depends on DVB_CORE && I2C + select FW_LOADER + default m if DVB_FE_CUSTOMISE + help + A DMB-TH tuner module. Say Y when you want to support this frontend. + +config DVB_ATBM8830 + tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DMB-TH tuner module. Say Y when you want to support this frontend. + +config DVB_TDA665x + tristate "TDA665x tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Support for tuner modules based on Philips TDA6650/TDA6651 chips. + Say Y when you want to support this chip. + + Currently supported tuners: + * Panasonic ENV57H12D5 (ET-50DT) + +config DVB_IX2505V + tristate "Sharp IX2505V silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +comment "Tools to develop new frontends" + +config DVB_DUMMY_FE + tristate "Dummy frontend driver" + default n +endmenu diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/l64781.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/l64781.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/l64781.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/l64781.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,602 @@ +/* + driver for LSI L64781 COFDM demodulator + + Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH + Marko Kohtala + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "l64781.h" + + +struct l64781_state { + struct i2c_adapter* i2c; + const struct l64781_config* config; + struct dvb_frontend frontend; + + /* private demodulator data */ + unsigned int first:1; +}; + +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "l64781: " args); \ + } while (0) + +static int debug; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + + +static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data) +{ + int ret; + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + + if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) + dprintk ("%s: write_reg error (reg == %02x) = %02x!\n", + __func__, reg, ret); + + return (ret != 1) ? -1 : 0; +} + +static int l64781_readreg (struct l64781_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) return ret; + + return b1[0]; +} + +static void apply_tps (struct l64781_state* state) +{ + l64781_writereg (state, 0x2a, 0x00); + l64781_writereg (state, 0x2a, 0x01); + + /* This here is a little bit questionable because it enables + the automatic update of TPS registers. I think we'd need to + handle the IRQ from FE to update some other registers as + well, or at least implement some magic to tuning to correct + to the TPS received from transmission. */ + l64781_writereg (state, 0x2a, 0x02); +} + + +static void reset_afc (struct l64781_state* state) +{ + /* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for + timing offset */ + l64781_writereg (state, 0x07, 0x9e); /* stall AFC */ + l64781_writereg (state, 0x08, 0); /* AFC INIT FREQ */ + l64781_writereg (state, 0x09, 0); + l64781_writereg (state, 0x0a, 0); + l64781_writereg (state, 0x07, 0x8e); + l64781_writereg (state, 0x0e, 0); /* AGC gain to zero in beginning */ + l64781_writereg (state, 0x11, 0x80); /* stall TIM */ + l64781_writereg (state, 0x10, 0); /* TIM_OFFSET_LSB */ + l64781_writereg (state, 0x12, 0); + l64781_writereg (state, 0x13, 0); + l64781_writereg (state, 0x11, 0x00); +} + +static int reset_and_configure (struct l64781_state* state) +{ + u8 buf [] = { 0x06 }; + struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 }; + // NOTE: this is correct in writing to address 0x00 + + return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV; +} + +static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param) +{ + struct l64781_state* state = fe->demodulator_priv; + /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */ + static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 }; + /* QPSK, QAM_16, QAM_64 */ + static const u8 qam_tab [] = { 2, 4, 0, 6 }; + static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */ + static const u8 guard_tab [] = { 1, 2, 4, 8 }; + /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */ + static const u32 ppm = 8000; + struct dvb_ofdm_parameters *p = ¶m->u.ofdm; + u32 ddfs_offset_fixed; +/* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */ +/* bw_tab[p->bandWidth]<<10)/15625; */ + u32 init_freq; + u32 spi_bias; + u8 val0x04; + u8 val0x05; + u8 val0x06; + int bw = p->bandwidth - BANDWIDTH_8_MHZ; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + if (param->inversion != INVERSION_ON && + param->inversion != INVERSION_OFF) + return -EINVAL; + + if (bw < 0 || bw > 2) + return -EINVAL; + + if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 && + p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 && + p->code_rate_HP != FEC_7_8) + return -EINVAL; + + if (p->hierarchy_information != HIERARCHY_NONE && + (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 && + p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 && + p->code_rate_LP != FEC_7_8)) + return -EINVAL; + + if (p->constellation != QPSK && p->constellation != QAM_16 && + p->constellation != QAM_64) + return -EINVAL; + + if (p->transmission_mode != TRANSMISSION_MODE_2K && + p->transmission_mode != TRANSMISSION_MODE_8K) + return -EINVAL; + + if (p->guard_interval < GUARD_INTERVAL_1_32 || + p->guard_interval > GUARD_INTERVAL_1_4) + return -EINVAL; + + if (p->hierarchy_information < HIERARCHY_NONE || + p->hierarchy_information > HIERARCHY_4) + return -EINVAL; + + ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000; + + /* This works up to 20000 ppm, it overflows if too large ppm! */ + init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) / + bw_tab[p->bandwidth] & 0xFFFFFF); + + /* SPI bias calculation is slightly modified to fit in 32bit */ + /* will work for high ppm only... */ + spi_bias = 378 * (1 << 10); + spi_bias *= 16; + spi_bias *= bw_tab[p->bandwidth]; + spi_bias *= qam_tab[p->constellation]; + spi_bias /= p->code_rate_HP + 1; + spi_bias /= (guard_tab[p->guard_interval] + 32); + spi_bias *= 1000; + spi_bias /= 1000 + ppm/1000; + spi_bias *= p->code_rate_HP; + + val0x04 = (p->transmission_mode << 2) | p->guard_interval; + val0x05 = fec_tab[p->code_rate_HP]; + + if (p->hierarchy_information != HIERARCHY_NONE) + val0x05 |= (p->code_rate_LP - FEC_1_2) << 3; + + val0x06 = (p->hierarchy_information << 2) | p->constellation; + + l64781_writereg (state, 0x04, val0x04); + l64781_writereg (state, 0x05, val0x05); + l64781_writereg (state, 0x06, val0x06); + + reset_afc (state); + + /* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */ + l64781_writereg (state, 0x15, + p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3); + l64781_writereg (state, 0x16, init_freq & 0xff); + l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff); + l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff); + + l64781_writereg (state, 0x1b, spi_bias & 0xff); + l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff); + l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) | + (param->inversion == INVERSION_ON ? 0x80 : 0x00)); + + l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff); + l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f); + + l64781_readreg (state, 0x00); /* clear interrupt registers... */ + l64781_readreg (state, 0x01); /* dto. */ + + apply_tps (state); + + return 0; +} + +static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param) +{ + struct l64781_state* state = fe->demodulator_priv; + int tmp; + + + tmp = l64781_readreg(state, 0x04); + switch(tmp & 3) { + case 0: + param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + break; + } + switch((tmp >> 2) & 3) { + case 0: + param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + printk("Unexpected value for transmission_mode\n"); + } + + + + tmp = l64781_readreg(state, 0x05); + switch(tmp & 7) { + case 0: + param->u.ofdm.code_rate_HP = FEC_1_2; + break; + case 1: + param->u.ofdm.code_rate_HP = FEC_2_3; + break; + case 2: + param->u.ofdm.code_rate_HP = FEC_3_4; + break; + case 3: + param->u.ofdm.code_rate_HP = FEC_5_6; + break; + case 4: + param->u.ofdm.code_rate_HP = FEC_7_8; + break; + default: + printk("Unexpected value for code_rate_HP\n"); + } + switch((tmp >> 3) & 7) { + case 0: + param->u.ofdm.code_rate_LP = FEC_1_2; + break; + case 1: + param->u.ofdm.code_rate_LP = FEC_2_3; + break; + case 2: + param->u.ofdm.code_rate_LP = FEC_3_4; + break; + case 3: + param->u.ofdm.code_rate_LP = FEC_5_6; + break; + case 4: + param->u.ofdm.code_rate_LP = FEC_7_8; + break; + default: + printk("Unexpected value for code_rate_LP\n"); + } + + + tmp = l64781_readreg(state, 0x06); + switch(tmp & 3) { + case 0: + param->u.ofdm.constellation = QPSK; + break; + case 1: + param->u.ofdm.constellation = QAM_16; + break; + case 2: + param->u.ofdm.constellation = QAM_64; + break; + default: + printk("Unexpected value for constellation\n"); + } + switch((tmp >> 2) & 7) { + case 0: + param->u.ofdm.hierarchy_information = HIERARCHY_NONE; + break; + case 1: + param->u.ofdm.hierarchy_information = HIERARCHY_1; + break; + case 2: + param->u.ofdm.hierarchy_information = HIERARCHY_2; + break; + case 3: + param->u.ofdm.hierarchy_information = HIERARCHY_4; + break; + default: + printk("Unexpected value for hierarchy\n"); + } + + + tmp = l64781_readreg (state, 0x1d); + param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; + + tmp = (int) (l64781_readreg (state, 0x08) | + (l64781_readreg (state, 0x09) << 8) | + (l64781_readreg (state, 0x0a) << 16)); + param->frequency += tmp; + + return 0; +} + +static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct l64781_state* state = fe->demodulator_priv; + int sync = l64781_readreg (state, 0x32); + int gain = l64781_readreg (state, 0x0e); + + l64781_readreg (state, 0x00); /* clear interrupt registers... */ + l64781_readreg (state, 0x01); /* dto. */ + + *status = 0; + + if (gain > 5) + *status |= FE_HAS_SIGNAL; + + if (sync & 0x02) /* VCXO locked, this criteria should be ok */ + *status |= FE_HAS_CARRIER; + + if (sync & 0x20) + *status |= FE_HAS_VITERBI; + + if (sync & 0x40) + *status |= FE_HAS_SYNC; + + if (sync == 0x7f) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int l64781_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct l64781_state* state = fe->demodulator_priv; + + /* XXX FIXME: set up counting period (reg 0x26...0x28) + */ + *ber = l64781_readreg (state, 0x39) + | (l64781_readreg (state, 0x3a) << 8); + + return 0; +} + +static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct l64781_state* state = fe->demodulator_priv; + + u8 gain = l64781_readreg (state, 0x0e); + *signal_strength = (gain << 8) | gain; + + return 0; +} + +static int l64781_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct l64781_state* state = fe->demodulator_priv; + + u8 avg_quality = 0xff - l64781_readreg (state, 0x33); + *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/ + + return 0; +} + +static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct l64781_state* state = fe->demodulator_priv; + + *ucblocks = l64781_readreg (state, 0x37) + | (l64781_readreg (state, 0x38) << 8); + + return 0; +} + +static int l64781_sleep(struct dvb_frontend* fe) +{ + struct l64781_state* state = fe->demodulator_priv; + + /* Power down */ + return l64781_writereg (state, 0x3e, 0x5a); +} + +static int l64781_init(struct dvb_frontend* fe) +{ + struct l64781_state* state = fe->demodulator_priv; + + reset_and_configure (state); + + /* Power up */ + l64781_writereg (state, 0x3e, 0xa5); + + /* Reset hard */ + l64781_writereg (state, 0x2a, 0x04); + l64781_writereg (state, 0x2a, 0x00); + + /* Set tuner specific things */ + /* AFC_POL, set also in reset_afc */ + l64781_writereg (state, 0x07, 0x8e); + + /* Use internal ADC */ + l64781_writereg (state, 0x0b, 0x81); + + /* AGC loop gain, and polarity is positive */ + l64781_writereg (state, 0x0c, 0x84); + + /* Internal ADC outputs two's complement */ + l64781_writereg (state, 0x0d, 0x8c); + + /* With ppm=8000, it seems the DTR_SENSITIVITY will result in + value of 2 with all possible bandwidths and guard + intervals, which is the initial value anyway. */ + /*l64781_writereg (state, 0x19, 0x92);*/ + + /* Everything is two's complement, soft bit and CSI_OUT too */ + l64781_writereg (state, 0x1e, 0x09); + + /* delay a bit after first init attempt */ + if (state->first) { + state->first = 0; + msleep(200); + } + + return 0; +} + +static int l64781_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 4000; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static void l64781_release(struct dvb_frontend* fe) +{ + struct l64781_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops l64781_ops; + +struct dvb_frontend* l64781_attach(const struct l64781_config* config, + struct i2c_adapter* i2c) +{ + struct l64781_state* state = NULL; + int reg0x3e = -1; + u8 b0 [] = { 0x1a }; + u8 b1 [] = { 0x00 }; + struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct l64781_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->first = 1; + + /** + * the L64781 won't show up before we send the reset_and_configure() + * broadcast. If nothing responds there is no L64781 on the bus... + */ + if (reset_and_configure(state) < 0) { + dprintk("No response to reset and configure broadcast...\n"); + goto error; + } + + /* The chip always responds to reads */ + if (i2c_transfer(state->i2c, msg, 2) != 2) { + dprintk("No response to read on I2C bus\n"); + goto error; + } + + /* Save current register contents for bailout */ + reg0x3e = l64781_readreg(state, 0x3e); + + /* Reading the POWER_DOWN register always returns 0 */ + if (reg0x3e != 0) { + dprintk("Device doesn't look like L64781\n"); + goto error; + } + + /* Turn the chip off */ + l64781_writereg (state, 0x3e, 0x5a); + + /* Responds to all reads with 0 */ + if (l64781_readreg(state, 0x1a) != 0) { + dprintk("Read 1 returned unexpcted value\n"); + goto error; + } + + /* Turn the chip on */ + l64781_writereg (state, 0x3e, 0xa5); + + /* Responds with register default value */ + if (l64781_readreg(state, 0x1a) != 0xa1) { + dprintk("Read 2 returned unexpcted value\n"); + goto error; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (reg0x3e >= 0) + l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */ + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops l64781_ops = { + + .info = { + .name = "LSI L64781 DVB-T", + .type = FE_OFDM, + /* .frequency_min = ???,*/ + /* .frequency_max = ???,*/ + .frequency_stepsize = 166666, + /* .frequency_tolerance = ???,*/ + /* .symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_MUTE_TS + }, + + .release = l64781_release, + + .init = l64781_init, + .sleep = l64781_sleep, + + .set_frontend = apply_frontend_param, + .get_frontend = get_frontend, + .get_tune_settings = l64781_get_tune_settings, + + .read_status = l64781_read_status, + .read_ber = l64781_read_ber, + .read_signal_strength = l64781_read_signal_strength, + .read_snr = l64781_read_snr, + .read_ucblocks = l64781_read_ucblocks, +}; + +MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver"); +MODULE_AUTHOR("Holger Waechtler, Marko Kohtala"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(l64781_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/l64781.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/l64781.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/l64781.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/l64781.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + driver for LSI L64781 COFDM demodulator + + Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH + Marko Kohtala + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef L64781_H +#define L64781_H + +#include + +struct l64781_config +{ + /* the demodulator's i2c address */ + u8 demod_address; +}; + +#if defined(CONFIG_DVB_L64781) || (defined(CONFIG_DVB_L64781_MODULE) && defined(MODULE)) +extern struct dvb_frontend* l64781_attach(const struct l64781_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* l64781_attach(const struct l64781_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_L64781 + +#endif // L64781_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt3305.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt3305.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt3305.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt3305.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,1221 @@ +/* + * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM + * + * Copyright (C) 2008, 2009, 2010 Michael Krufky + * + * LGDT3304 support by Jarod Wilson + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "dvb_math.h" +#include "lgdt3305.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); + +#define DBG_INFO 1 +#define DBG_REG 2 + +#define lg_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt, __func__, ##arg) + +#define lg_info(fmt, arg...) printk(KERN_INFO "lgdt3305: " fmt, ##arg) +#define lg_warn(fmt, arg...) lg_printk(KERN_WARNING, fmt, ##arg) +#define lg_err(fmt, arg...) lg_printk(KERN_ERR, fmt, ##arg) +#define lg_dbg(fmt, arg...) if (debug & DBG_INFO) \ + lg_printk(KERN_DEBUG, fmt, ##arg) +#define lg_reg(fmt, arg...) if (debug & DBG_REG) \ + lg_printk(KERN_DEBUG, fmt, ##arg) + +#define lg_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + lg_err("error %d on line %d\n", ret, __LINE__); \ + __ret; \ +}) + +struct lgdt3305_state { + struct i2c_adapter *i2c_adap; + const struct lgdt3305_config *cfg; + + struct dvb_frontend frontend; + + fe_modulation_t current_modulation; + u32 current_frequency; + u32 snr; +}; + +/* ------------------------------------------------------------------------ */ + +/* FIXME: verify & document the LGDT3304 registers */ + +#define LGDT3305_GEN_CTRL_1 0x0000 +#define LGDT3305_GEN_CTRL_2 0x0001 +#define LGDT3305_GEN_CTRL_3 0x0002 +#define LGDT3305_GEN_STATUS 0x0003 +#define LGDT3305_GEN_CONTROL 0x0007 +#define LGDT3305_GEN_CTRL_4 0x000a +#define LGDT3305_DGTL_AGC_REF_1 0x0012 +#define LGDT3305_DGTL_AGC_REF_2 0x0013 +#define LGDT3305_CR_CTR_FREQ_1 0x0106 +#define LGDT3305_CR_CTR_FREQ_2 0x0107 +#define LGDT3305_CR_CTR_FREQ_3 0x0108 +#define LGDT3305_CR_CTR_FREQ_4 0x0109 +#define LGDT3305_CR_MSE_1 0x011b +#define LGDT3305_CR_MSE_2 0x011c +#define LGDT3305_CR_LOCK_STATUS 0x011d +#define LGDT3305_CR_CTRL_7 0x0126 +#define LGDT3305_AGC_POWER_REF_1 0x0300 +#define LGDT3305_AGC_POWER_REF_2 0x0301 +#define LGDT3305_AGC_DELAY_PT_1 0x0302 +#define LGDT3305_AGC_DELAY_PT_2 0x0303 +#define LGDT3305_RFAGC_LOOP_FLTR_BW_1 0x0306 +#define LGDT3305_RFAGC_LOOP_FLTR_BW_2 0x0307 +#define LGDT3305_IFBW_1 0x0308 +#define LGDT3305_IFBW_2 0x0309 +#define LGDT3305_AGC_CTRL_1 0x030c +#define LGDT3305_AGC_CTRL_4 0x0314 +#define LGDT3305_EQ_MSE_1 0x0413 +#define LGDT3305_EQ_MSE_2 0x0414 +#define LGDT3305_EQ_MSE_3 0x0415 +#define LGDT3305_PT_MSE_1 0x0417 +#define LGDT3305_PT_MSE_2 0x0418 +#define LGDT3305_PT_MSE_3 0x0419 +#define LGDT3305_FEC_BLOCK_CTRL 0x0504 +#define LGDT3305_FEC_LOCK_STATUS 0x050a +#define LGDT3305_FEC_PKT_ERR_1 0x050c +#define LGDT3305_FEC_PKT_ERR_2 0x050d +#define LGDT3305_TP_CTRL_1 0x050e +#define LGDT3305_BERT_PERIOD 0x0801 +#define LGDT3305_BERT_ERROR_COUNT_1 0x080a +#define LGDT3305_BERT_ERROR_COUNT_2 0x080b +#define LGDT3305_BERT_ERROR_COUNT_3 0x080c +#define LGDT3305_BERT_ERROR_COUNT_4 0x080d + +static int lgdt3305_write_reg(struct lgdt3305_state *state, u16 reg, u8 val) +{ + int ret; + u8 buf[] = { reg >> 8, reg & 0xff, val }; + struct i2c_msg msg = { + .addr = state->cfg->i2c_addr, .flags = 0, + .buf = buf, .len = 3, + }; + + lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val); + + ret = i2c_transfer(state->i2c_adap, &msg, 1); + + if (ret != 1) { + lg_err("error (addr %02x %02x <- %02x, err = %i)\n", + msg.buf[0], msg.buf[1], msg.buf[2], ret); + if (ret < 0) + return ret; + else + return -EREMOTEIO; + } + return 0; +} + +static int lgdt3305_read_reg(struct lgdt3305_state *state, u16 reg, u8 *val) +{ + int ret; + u8 reg_buf[] = { reg >> 8, reg & 0xff }; + struct i2c_msg msg[] = { + { .addr = state->cfg->i2c_addr, + .flags = 0, .buf = reg_buf, .len = 2 }, + { .addr = state->cfg->i2c_addr, + .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + lg_reg("reg: 0x%04x\n", reg); + + ret = i2c_transfer(state->i2c_adap, msg, 2); + + if (ret != 2) { + lg_err("error (addr %02x reg %04x error (ret == %i)\n", + state->cfg->i2c_addr, reg, ret); + if (ret < 0) + return ret; + else + return -EREMOTEIO; + } + return 0; +} + +#define read_reg(state, reg) \ +({ \ + u8 __val; \ + int ret = lgdt3305_read_reg(state, reg, &__val); \ + if (lg_fail(ret)) \ + __val = 0; \ + __val; \ +}) + +static int lgdt3305_set_reg_bit(struct lgdt3305_state *state, + u16 reg, int bit, int onoff) +{ + u8 val; + int ret; + + lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff); + + ret = lgdt3305_read_reg(state, reg, &val); + if (lg_fail(ret)) + goto fail; + + val &= ~(1 << bit); + val |= (onoff & 1) << bit; + + ret = lgdt3305_write_reg(state, reg, val); +fail: + return ret; +} + +struct lgdt3305_reg { + u16 reg; + u8 val; +}; + +static int lgdt3305_write_regs(struct lgdt3305_state *state, + struct lgdt3305_reg *regs, int len) +{ + int i, ret; + + lg_reg("writing %d registers...\n", len); + + for (i = 0; i < len - 1; i++) { + ret = lgdt3305_write_reg(state, regs[i].reg, regs[i].val); + if (lg_fail(ret)) + return ret; + } + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3305_soft_reset(struct lgdt3305_state *state) +{ + int ret; + + lg_dbg("\n"); + + ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 0); + if (lg_fail(ret)) + goto fail; + + msleep(20); + ret = lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_3, 0, 1); +fail: + return ret; +} + +static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state, + enum lgdt3305_mpeg_mode mode) +{ + lg_dbg("(%d)\n", mode); + return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode); +} + +static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state, + enum lgdt3305_tp_clock_edge edge, + enum lgdt3305_tp_valid_polarity valid) +{ + u8 val; + int ret; + + lg_dbg("edge = %d, valid = %d\n", edge, valid); + + ret = lgdt3305_read_reg(state, LGDT3305_TP_CTRL_1, &val); + if (lg_fail(ret)) + goto fail; + + val &= ~0x09; + + if (edge) + val |= 0x08; + if (valid) + val |= 0x01; + + ret = lgdt3305_write_reg(state, LGDT3305_TP_CTRL_1, val); + if (lg_fail(ret)) + goto fail; + + ret = lgdt3305_soft_reset(state); +fail: + return ret; +} + +static int lgdt3305_set_modulation(struct lgdt3305_state *state, + struct dvb_frontend_parameters *param) +{ + u8 opermode; + int ret; + + lg_dbg("\n"); + + ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_1, &opermode); + if (lg_fail(ret)) + goto fail; + + opermode &= ~0x03; + + switch (param->u.vsb.modulation) { + case VSB_8: + opermode |= 0x03; + break; + case QAM_64: + opermode |= 0x00; + break; + case QAM_256: + opermode |= 0x01; + break; + default: + return -EINVAL; + } + ret = lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_1, opermode); +fail: + return ret; +} + +static int lgdt3305_set_filter_extension(struct lgdt3305_state *state, + struct dvb_frontend_parameters *param) +{ + int val; + + switch (param->u.vsb.modulation) { + case VSB_8: + val = 0; + break; + case QAM_64: + case QAM_256: + val = 1; + break; + default: + return -EINVAL; + } + lg_dbg("val = %d\n", val); + + return lgdt3305_set_reg_bit(state, 0x043f, 2, val); +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state, + struct dvb_frontend_parameters *param) +{ + u16 agc_ref; + + switch (param->u.vsb.modulation) { + case VSB_8: + agc_ref = 0x32c4; + break; + case QAM_64: + agc_ref = 0x2a00; + break; + case QAM_256: + agc_ref = 0x2a80; + break; + default: + return -EINVAL; + } + + lg_dbg("agc ref: 0x%04x\n", agc_ref); + + lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_1, agc_ref >> 8); + lgdt3305_write_reg(state, LGDT3305_DGTL_AGC_REF_2, agc_ref & 0xff); + + return 0; +} + +static int lgdt3305_rfagc_loop(struct lgdt3305_state *state, + struct dvb_frontend_parameters *param) +{ + u16 ifbw, rfbw, agcdelay; + + switch (param->u.vsb.modulation) { + case VSB_8: + agcdelay = 0x04c0; + rfbw = 0x8000; + ifbw = 0x8000; + break; + case QAM_64: + case QAM_256: + agcdelay = 0x046b; + rfbw = 0x8889; + /* FIXME: investigate optimal ifbw & rfbw values for the + * DT3304 and re-write this switch..case block */ + if (state->cfg->demod_chip == LGDT3304) + ifbw = 0x6666; + else /* (state->cfg->demod_chip == LGDT3305) */ + ifbw = 0x8888; + break; + default: + return -EINVAL; + } + + if (state->cfg->rf_agc_loop) { + lg_dbg("agcdelay: 0x%04x, rfbw: 0x%04x\n", agcdelay, rfbw); + + /* rf agc loop filter bandwidth */ + lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_1, + agcdelay >> 8); + lgdt3305_write_reg(state, LGDT3305_AGC_DELAY_PT_2, + agcdelay & 0xff); + + lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_1, + rfbw >> 8); + lgdt3305_write_reg(state, LGDT3305_RFAGC_LOOP_FLTR_BW_2, + rfbw & 0xff); + } else { + lg_dbg("ifbw: 0x%04x\n", ifbw); + + /* if agc loop filter bandwidth */ + lgdt3305_write_reg(state, LGDT3305_IFBW_1, ifbw >> 8); + lgdt3305_write_reg(state, LGDT3305_IFBW_2, ifbw & 0xff); + } + + return 0; +} + +static int lgdt3305_agc_setup(struct lgdt3305_state *state, + struct dvb_frontend_parameters *param) +{ + int lockdten, acqen; + + switch (param->u.vsb.modulation) { + case VSB_8: + lockdten = 0; + acqen = 0; + break; + case QAM_64: + case QAM_256: + lockdten = 1; + acqen = 1; + break; + default: + return -EINVAL; + } + + lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen); + + /* control agc function */ + switch (state->cfg->demod_chip) { + case LGDT3304: + lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1); + lgdt3305_set_reg_bit(state, 0x030e, 2, acqen); + break; + case LGDT3305: + lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1); + lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen); + break; + default: + return -EINVAL; + } + + return lgdt3305_rfagc_loop(state, param); +} + +static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state, + struct dvb_frontend_parameters *param) +{ + u16 usref = 0; + + switch (param->u.vsb.modulation) { + case VSB_8: + if (state->cfg->usref_8vsb) + usref = state->cfg->usref_8vsb; + break; + case QAM_64: + if (state->cfg->usref_qam64) + usref = state->cfg->usref_qam64; + break; + case QAM_256: + if (state->cfg->usref_qam256) + usref = state->cfg->usref_qam256; + break; + default: + return -EINVAL; + } + + if (usref) { + lg_dbg("set manual mode: 0x%04x\n", usref); + + lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 3, 1); + + lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_1, + 0xff & (usref >> 8)); + lgdt3305_write_reg(state, LGDT3305_AGC_POWER_REF_2, + 0xff & (usref >> 0)); + } + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3305_spectral_inversion(struct lgdt3305_state *state, + struct dvb_frontend_parameters *param, + int inversion) +{ + int ret; + + lg_dbg("(%d)\n", inversion); + + switch (param->u.vsb.modulation) { + case VSB_8: + ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7, + inversion ? 0xf9 : 0x79); + break; + case QAM_64: + case QAM_256: + ret = lgdt3305_write_reg(state, LGDT3305_FEC_BLOCK_CTRL, + inversion ? 0xfd : 0xff); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int lgdt3305_set_if(struct lgdt3305_state *state, + struct dvb_frontend_parameters *param) +{ + u16 if_freq_khz; + u8 nco1, nco2, nco3, nco4; + u64 nco; + + switch (param->u.vsb.modulation) { + case VSB_8: + if_freq_khz = state->cfg->vsb_if_khz; + break; + case QAM_64: + case QAM_256: + if_freq_khz = state->cfg->qam_if_khz; + break; + default: + return -EINVAL; + } + + nco = if_freq_khz / 10; + + switch (param->u.vsb.modulation) { + case VSB_8: + nco <<= 24; + do_div(nco, 625); + break; + case QAM_64: + case QAM_256: + nco <<= 28; + do_div(nco, 625); + break; + default: + return -EINVAL; + } + + nco1 = (nco >> 24) & 0x3f; + nco1 |= 0x40; + nco2 = (nco >> 16) & 0xff; + nco3 = (nco >> 8) & 0xff; + nco4 = nco & 0xff; + + lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, nco1); + lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, nco2); + lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, nco3); + lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, nco4); + + lg_dbg("%d KHz -> [%02x%02x%02x%02x]\n", + if_freq_khz, nco1, nco2, nco3, nco4); + + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + + if (state->cfg->deny_i2c_rptr) + return 0; + + lg_dbg("(%d)\n", enable); + + return lgdt3305_set_reg_bit(state, LGDT3305_GEN_CTRL_2, 5, + enable ? 0 : 1); +} + +static int lgdt3305_sleep(struct dvb_frontend *fe) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + u8 gen_ctrl_3, gen_ctrl_4; + + lg_dbg("\n"); + + gen_ctrl_3 = read_reg(state, LGDT3305_GEN_CTRL_3); + gen_ctrl_4 = read_reg(state, LGDT3305_GEN_CTRL_4); + + /* hold in software reset while sleeping */ + gen_ctrl_3 &= ~0x01; + /* tristate the IF-AGC pin */ + gen_ctrl_3 |= 0x02; + /* tristate the RF-AGC pin */ + gen_ctrl_3 |= 0x04; + + /* disable vsb/qam module */ + gen_ctrl_4 &= ~0x01; + /* disable adc module */ + gen_ctrl_4 &= ~0x02; + + lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_3, gen_ctrl_3); + lgdt3305_write_reg(state, LGDT3305_GEN_CTRL_4, gen_ctrl_4); + + return 0; +} + +static int lgdt3305_init(struct dvb_frontend *fe) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + int ret; + + static struct lgdt3305_reg lgdt3304_init_data[] = { + { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, }, + { .reg = 0x000d, .val = 0x02, }, + { .reg = 0x000e, .val = 0x02, }, + { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, }, + { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, }, + { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, }, + { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, }, + { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, }, + { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, }, + { .reg = LGDT3305_CR_CTRL_7, .val = 0xf9, }, + { .reg = 0x0112, .val = 0x17, }, + { .reg = 0x0113, .val = 0x15, }, + { .reg = 0x0114, .val = 0x18, }, + { .reg = 0x0115, .val = 0xff, }, + { .reg = 0x0116, .val = 0x3c, }, + { .reg = 0x0214, .val = 0x67, }, + { .reg = 0x0424, .val = 0x8d, }, + { .reg = 0x0427, .val = 0x12, }, + { .reg = 0x0428, .val = 0x4f, }, + { .reg = LGDT3305_IFBW_1, .val = 0x80, }, + { .reg = LGDT3305_IFBW_2, .val = 0x00, }, + { .reg = 0x030a, .val = 0x08, }, + { .reg = 0x030b, .val = 0x9b, }, + { .reg = 0x030d, .val = 0x00, }, + { .reg = 0x030e, .val = 0x1c, }, + { .reg = 0x0314, .val = 0xe1, }, + { .reg = 0x000d, .val = 0x82, }, + { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, }, + { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, }, + }; + + static struct lgdt3305_reg lgdt3305_init_data[] = { + { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, }, + { .reg = LGDT3305_GEN_CTRL_2, .val = 0xb0, }, + { .reg = LGDT3305_GEN_CTRL_3, .val = 0x01, }, + { .reg = LGDT3305_GEN_CONTROL, .val = 0x6f, }, + { .reg = LGDT3305_GEN_CTRL_4, .val = 0x03, }, + { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, }, + { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, }, + { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, }, + { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, }, + { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, }, + { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, }, + { .reg = LGDT3305_CR_CTRL_7, .val = 0x79, }, + { .reg = LGDT3305_AGC_POWER_REF_1, .val = 0x32, }, + { .reg = LGDT3305_AGC_POWER_REF_2, .val = 0xc4, }, + { .reg = LGDT3305_AGC_DELAY_PT_1, .val = 0x0d, }, + { .reg = LGDT3305_AGC_DELAY_PT_2, .val = 0x30, }, + { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, }, + { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, }, + { .reg = LGDT3305_IFBW_1, .val = 0x80, }, + { .reg = LGDT3305_IFBW_2, .val = 0x00, }, + { .reg = LGDT3305_AGC_CTRL_1, .val = 0x30, }, + { .reg = LGDT3305_AGC_CTRL_4, .val = 0x61, }, + { .reg = LGDT3305_FEC_BLOCK_CTRL, .val = 0xff, }, + { .reg = LGDT3305_TP_CTRL_1, .val = 0x1b, }, + }; + + lg_dbg("\n"); + + switch (state->cfg->demod_chip) { + case LGDT3304: + ret = lgdt3305_write_regs(state, lgdt3304_init_data, + ARRAY_SIZE(lgdt3304_init_data)); + break; + case LGDT3305: + ret = lgdt3305_write_regs(state, lgdt3305_init_data, + ARRAY_SIZE(lgdt3305_init_data)); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + ret = lgdt3305_soft_reset(state); +fail: + return ret; +} + +static int lgdt3304_set_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + int ret; + + lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); + + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + if (lg_fail(ret)) + goto fail; + state->current_frequency = param->frequency; + } + + ret = lgdt3305_set_modulation(state, param); + if (lg_fail(ret)) + goto fail; + + ret = lgdt3305_passband_digital_agc(state, param); + if (lg_fail(ret)) + goto fail; + + ret = lgdt3305_agc_setup(state, param); + if (lg_fail(ret)) + goto fail; + + /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */ + switch (param->u.vsb.modulation) { + case VSB_8: + lgdt3305_write_reg(state, 0x030d, 0x00); + lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f); + lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c); + lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac); + lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba); + break; + case QAM_64: + case QAM_256: + lgdt3305_write_reg(state, 0x030d, 0x14); + ret = lgdt3305_set_if(state, param); + if (lg_fail(ret)) + goto fail; + break; + default: + return -EINVAL; + } + + + ret = lgdt3305_spectral_inversion(state, param, + state->cfg->spectral_inversion + ? 1 : 0); + if (lg_fail(ret)) + goto fail; + + state->current_modulation = param->u.vsb.modulation; + + ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); + if (lg_fail(ret)) + goto fail; + + /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */ + ret = lgdt3305_mpeg_mode_polarity(state, + state->cfg->tpclk_edge, + state->cfg->tpvalid_polarity); +fail: + return ret; +} + +static int lgdt3305_set_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + int ret; + + lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); + + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + if (lg_fail(ret)) + goto fail; + state->current_frequency = param->frequency; + } + + ret = lgdt3305_set_modulation(state, param); + if (lg_fail(ret)) + goto fail; + + ret = lgdt3305_passband_digital_agc(state, param); + if (lg_fail(ret)) + goto fail; + ret = lgdt3305_set_agc_power_ref(state, param); + if (lg_fail(ret)) + goto fail; + ret = lgdt3305_agc_setup(state, param); + if (lg_fail(ret)) + goto fail; + + /* low if */ + ret = lgdt3305_write_reg(state, LGDT3305_GEN_CONTROL, 0x2f); + if (lg_fail(ret)) + goto fail; + ret = lgdt3305_set_reg_bit(state, LGDT3305_CR_CTR_FREQ_1, 6, 1); + if (lg_fail(ret)) + goto fail; + + ret = lgdt3305_set_if(state, param); + if (lg_fail(ret)) + goto fail; + ret = lgdt3305_spectral_inversion(state, param, + state->cfg->spectral_inversion + ? 1 : 0); + if (lg_fail(ret)) + goto fail; + + ret = lgdt3305_set_filter_extension(state, param); + if (lg_fail(ret)) + goto fail; + + state->current_modulation = param->u.vsb.modulation; + + ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); + if (lg_fail(ret)) + goto fail; + + /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */ + ret = lgdt3305_mpeg_mode_polarity(state, + state->cfg->tpclk_edge, + state->cfg->tpvalid_polarity); +fail: + return ret; +} + +static int lgdt3305_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + + lg_dbg("\n"); + + param->u.vsb.modulation = state->current_modulation; + param->frequency = state->current_frequency; + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3305_read_cr_lock_status(struct lgdt3305_state *state, + int *locked) +{ + u8 val; + int ret; + char *cr_lock_state = ""; + + *locked = 0; + + ret = lgdt3305_read_reg(state, LGDT3305_CR_LOCK_STATUS, &val); + if (lg_fail(ret)) + goto fail; + + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + if (val & (1 << 1)) + *locked = 1; + + switch (val & 0x07) { + case 0: + cr_lock_state = "QAM UNLOCK"; + break; + case 4: + cr_lock_state = "QAM 1stLock"; + break; + case 6: + cr_lock_state = "QAM 2ndLock"; + break; + case 7: + cr_lock_state = "QAM FinalLock"; + break; + default: + cr_lock_state = "CLOCKQAM-INVALID!"; + break; + } + break; + case VSB_8: + if (val & (1 << 7)) { + *locked = 1; + cr_lock_state = "CLOCKVSB"; + } + break; + default: + ret = -EINVAL; + } + lg_dbg("(%d) %s\n", *locked, cr_lock_state); +fail: + return ret; +} + +static int lgdt3305_read_fec_lock_status(struct lgdt3305_state *state, + int *locked) +{ + u8 val; + int ret, mpeg_lock, fec_lock, viterbi_lock; + + *locked = 0; + + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + ret = lgdt3305_read_reg(state, + LGDT3305_FEC_LOCK_STATUS, &val); + if (lg_fail(ret)) + goto fail; + + mpeg_lock = (val & (1 << 0)) ? 1 : 0; + fec_lock = (val & (1 << 2)) ? 1 : 0; + viterbi_lock = (val & (1 << 3)) ? 1 : 0; + + *locked = mpeg_lock && fec_lock && viterbi_lock; + + lg_dbg("(%d) %s%s%s\n", *locked, + mpeg_lock ? "mpeg lock " : "", + fec_lock ? "fec lock " : "", + viterbi_lock ? "viterbi lock" : ""); + break; + case VSB_8: + default: + ret = -EINVAL; + } +fail: + return ret; +} + +static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + u8 val; + int ret, signal, inlock, nofecerr, snrgood, + cr_lock, fec_lock, sync_lock; + + *status = 0; + + ret = lgdt3305_read_reg(state, LGDT3305_GEN_STATUS, &val); + if (lg_fail(ret)) + goto fail; + + signal = (val & (1 << 4)) ? 1 : 0; + inlock = (val & (1 << 3)) ? 0 : 1; + sync_lock = (val & (1 << 2)) ? 1 : 0; + nofecerr = (val & (1 << 1)) ? 1 : 0; + snrgood = (val & (1 << 0)) ? 1 : 0; + + lg_dbg("%s%s%s%s%s\n", + signal ? "SIGNALEXIST " : "", + inlock ? "INLOCK " : "", + sync_lock ? "SYNCLOCK " : "", + nofecerr ? "NOFECERR " : "", + snrgood ? "SNRGOOD " : ""); + + ret = lgdt3305_read_cr_lock_status(state, &cr_lock); + if (lg_fail(ret)) + goto fail; + + if (signal) + *status |= FE_HAS_SIGNAL; + if (cr_lock) + *status |= FE_HAS_CARRIER; + if (nofecerr) + *status |= FE_HAS_VITERBI; + if (sync_lock) + *status |= FE_HAS_SYNC; + + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + /* signal bit is unreliable on the DT3304 in QAM mode */ + if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock)) + *status |= FE_HAS_SIGNAL; + + ret = lgdt3305_read_fec_lock_status(state, &fec_lock); + if (lg_fail(ret)) + goto fail; + + if (fec_lock) + *status |= FE_HAS_LOCK; + break; + case VSB_8: + if (inlock) + *status |= FE_HAS_LOCK; + break; + default: + ret = -EINVAL; + } +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +/* borrowed from lgdt330x.c */ +static u32 calculate_snr(u32 mse, u32 c) +{ + if (mse == 0) /* no signal */ + return 0; + + mse = intlog10(mse); + if (mse > c) { + /* Negative SNR, which is possible, but realisticly the + demod will lose lock before the signal gets this bad. The + API only allows for unsigned values, so just return 0 */ + return 0; + } + return 10*(c - mse); +} + +static int lgdt3305_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + u32 noise; /* noise value */ + u32 c; /* per-modulation SNR calculation constant */ + + switch (state->current_modulation) { + case VSB_8: +#ifdef USE_PTMSE + /* Use Phase Tracker Mean-Square Error Register */ + /* SNR for ranges from -13.11 to +44.08 */ + noise = ((read_reg(state, LGDT3305_PT_MSE_1) & 0x07) << 16) | + (read_reg(state, LGDT3305_PT_MSE_2) << 8) | + (read_reg(state, LGDT3305_PT_MSE_3) & 0xff); + c = 73957994; /* log10(25*32^2)*2^24 */ +#else + /* Use Equalizer Mean-Square Error Register */ + /* SNR for ranges from -16.12 to +44.08 */ + noise = ((read_reg(state, LGDT3305_EQ_MSE_1) & 0x0f) << 16) | + (read_reg(state, LGDT3305_EQ_MSE_2) << 8) | + (read_reg(state, LGDT3305_EQ_MSE_3) & 0xff); + c = 73957994; /* log10(25*32^2)*2^24 */ +#endif + break; + case QAM_64: + case QAM_256: + noise = (read_reg(state, LGDT3305_CR_MSE_1) << 8) | + (read_reg(state, LGDT3305_CR_MSE_2) & 0xff); + + c = (state->current_modulation == QAM_64) ? + 97939837 : 98026066; + /* log10(688128)*2^24 and log10(696320)*2^24 */ + break; + default: + return -EINVAL; + } + state->snr = calculate_snr(noise, c); + /* report SNR in dB * 10 */ + *snr = (state->snr / ((1 << 24) / 10)); + lg_dbg("noise = 0x%08x, snr = %d.%02d dB\n", noise, + state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); + + return 0; +} + +static int lgdt3305_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + /* borrowed from lgdt330x.c + * + * Calculate strength from SNR up to 35dB + * Even though the SNR can go higher than 35dB, + * there is some comfort factor in having a range of + * strong signals that can show at 100% + */ + struct lgdt3305_state *state = fe->demodulator_priv; + u16 snr; + int ret; + + *strength = 0; + + ret = fe->ops.read_snr(fe, &snr); + if (lg_fail(ret)) + goto fail; + /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ + /* scale the range 0 - 35*2^24 into 0 - 65535 */ + if (state->snr >= 8960 * 0x10000) + *strength = 0xffff; + else + *strength = state->snr / 8960; +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3305_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + return 0; +} + +static int lgdt3305_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + + *ucblocks = + (read_reg(state, LGDT3305_FEC_PKT_ERR_1) << 8) | + (read_reg(state, LGDT3305_FEC_PKT_ERR_2) & 0xff); + + return 0; +} + +static int lgdt3305_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings + *fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 500; + lg_dbg("\n"); + return 0; +} + +static void lgdt3305_release(struct dvb_frontend *fe) +{ + struct lgdt3305_state *state = fe->demodulator_priv; + lg_dbg("\n"); + kfree(state); +} + +static struct dvb_frontend_ops lgdt3304_ops; +static struct dvb_frontend_ops lgdt3305_ops; + +struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, + struct i2c_adapter *i2c_adap) +{ + struct lgdt3305_state *state = NULL; + int ret; + u8 val; + + lg_dbg("(%d-%04x)\n", + i2c_adap ? i2c_adapter_id(i2c_adap) : 0, + config ? config->i2c_addr : 0); + + state = kzalloc(sizeof(struct lgdt3305_state), GFP_KERNEL); + if (state == NULL) + goto fail; + + state->cfg = config; + state->i2c_adap = i2c_adap; + + switch (config->demod_chip) { + case LGDT3304: + memcpy(&state->frontend.ops, &lgdt3304_ops, + sizeof(struct dvb_frontend_ops)); + break; + case LGDT3305: + memcpy(&state->frontend.ops, &lgdt3305_ops, + sizeof(struct dvb_frontend_ops)); + break; + default: + goto fail; + } + state->frontend.demodulator_priv = state; + + /* verify that we're talking to a lg dt3304/5 */ + ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val); + if ((lg_fail(ret)) | (val == 0)) + goto fail; + ret = lgdt3305_write_reg(state, 0x0808, 0x80); + if (lg_fail(ret)) + goto fail; + ret = lgdt3305_read_reg(state, 0x0808, &val); + if ((lg_fail(ret)) | (val != 0x80)) + goto fail; + ret = lgdt3305_write_reg(state, 0x0808, 0x00); + if (lg_fail(ret)) + goto fail; + + state->current_frequency = -1; + state->current_modulation = -1; + + return &state->frontend; +fail: + lg_warn("unable to detect %s hardware\n", + config->demod_chip ? "LGDT3304" : "LGDT3305"); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(lgdt3305_attach); + +static struct dvb_frontend_ops lgdt3304_ops = { + .info = { + .name = "LG Electronics LGDT3304 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl, + .init = lgdt3305_init, + .set_frontend = lgdt3304_set_parameters, + .get_frontend = lgdt3305_get_frontend, + .get_tune_settings = lgdt3305_get_tune_settings, + .read_status = lgdt3305_read_status, + .read_ber = lgdt3305_read_ber, + .read_signal_strength = lgdt3305_read_signal_strength, + .read_snr = lgdt3305_read_snr, + .read_ucblocks = lgdt3305_read_ucblocks, + .release = lgdt3305_release, +}; + +static struct dvb_frontend_ops lgdt3305_ops = { + .info = { + .name = "LG Electronics LGDT3305 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl, + .init = lgdt3305_init, + .sleep = lgdt3305_sleep, + .set_frontend = lgdt3305_set_parameters, + .get_frontend = lgdt3305_get_frontend, + .get_tune_settings = lgdt3305_get_tune_settings, + .read_status = lgdt3305_read_status, + .read_ber = lgdt3305_read_ber, + .read_signal_strength = lgdt3305_read_signal_strength, + .read_snr = lgdt3305_read_snr, + .read_ucblocks = lgdt3305_read_ucblocks, + .release = lgdt3305_release, +}; + +MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt3305.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt3305.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt3305.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt3305.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM + * + * Copyright (C) 2008, 2009, 2010 Michael Krufky + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _LGDT3305_H_ +#define _LGDT3305_H_ + +#include +#include "dvb_frontend.h" + + +enum lgdt3305_mpeg_mode { + LGDT3305_MPEG_PARALLEL = 0, + LGDT3305_MPEG_SERIAL = 1, +}; + +enum lgdt3305_tp_clock_edge { + LGDT3305_TPCLK_RISING_EDGE = 0, + LGDT3305_TPCLK_FALLING_EDGE = 1, +}; + +enum lgdt3305_tp_valid_polarity { + LGDT3305_TP_VALID_LOW = 0, + LGDT3305_TP_VALID_HIGH = 1, +}; + +enum lgdt_demod_chip_type { + LGDT3305 = 0, + LGDT3304 = 1, +}; + +struct lgdt3305_config { + u8 i2c_addr; + + /* user defined IF frequency in KHz */ + u16 qam_if_khz; + u16 vsb_if_khz; + + /* AGC Power reference - defaults are used if left unset */ + u16 usref_8vsb; /* default: 0x32c4 */ + u16 usref_qam64; /* default: 0x5400 */ + u16 usref_qam256; /* default: 0x2a80 */ + + /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */ + unsigned int deny_i2c_rptr:1; + + /* spectral inversion - 0:disabled 1:enabled */ + unsigned int spectral_inversion:1; + + /* use RF AGC loop - 0:disabled 1:enabled */ + unsigned int rf_agc_loop:1; + + enum lgdt3305_mpeg_mode mpeg_mode; + enum lgdt3305_tp_clock_edge tpclk_edge; + enum lgdt3305_tp_valid_polarity tpvalid_polarity; + enum lgdt_demod_chip_type demod_chip; +}; + +#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \ + defined(MODULE)) +extern +struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, + struct i2c_adapter *i2c_adap); +#else +static inline +struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, + struct i2c_adapter *i2c_adap) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGDT3305 */ + +#endif /* _LGDT3305_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,820 @@ +/* + * Support for LGDT3302 and LGDT3303 - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * NOTES ABOUT THIS DRIVER + * + * This Linux driver supports: + * DViCO FusionHDTV 3 Gold-Q + * DViCO FusionHDTV 3 Gold-T + * DViCO FusionHDTV 5 Gold + * DViCO FusionHDTV 5 Lite + * DViCO FusionHDTV 5 USB Gold + * Air2PC/AirStar 2 ATSC 3rd generation (HD5000) + * pcHDTV HD5500 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb_math.h" +#include "lgdt330x_priv.h" +#include "lgdt330x.h" + +/* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */ +/* #define USE_EQMSE */ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off)."); +#define dprintk(args...) \ +do { \ +if (debug) printk(KERN_DEBUG "lgdt330x: " args); \ +} while (0) + +struct lgdt330x_state +{ + struct i2c_adapter* i2c; + + /* Configuration settings */ + const struct lgdt330x_config* config; + + struct dvb_frontend frontend; + + /* Demodulator private data */ + fe_modulation_t current_modulation; + u32 snr; /* Result of last SNR calculation */ + + /* Tuner private data */ + u32 current_frequency; +}; + +static int i2c_write_demod_bytes (struct lgdt330x_state* state, + u8 *buf, /* data bytes to send */ + int len /* number of bytes to send */ ) +{ + struct i2c_msg msg = + { .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 }; + int i; + int err; + + for (i=0; ii2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __func__, msg.buf[0], msg.buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + msg.buf += 2; + } + return 0; +} + +/* + * This routine writes the register (reg) to the demod bus + * then reads the data returned for (len) bytes. + */ + +static u8 i2c_read_demod_bytes (struct lgdt330x_state* state, + enum I2C_REG reg, u8* buf, int len) +{ + u8 wr [] = { reg }; + struct i2c_msg msg [] = { + { .addr = state->config->demod_address, + .flags = 0, .buf = wr, .len = 1 }, + { .addr = state->config->demod_address, + .flags = I2C_M_RD, .buf = buf, .len = len }, + }; + int ret; + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret); + } else { + ret = 0; + } + return ret; +} + +/* Software reset */ +static int lgdt3302_SwReset(struct lgdt330x_state* state) +{ + u8 ret; + u8 reset[] = { + IRQ_MASK, + 0x00 /* bit 6 is active low software reset + * bits 5-0 are 1 to mask interrupts */ + }; + + ret = i2c_write_demod_bytes(state, + reset, sizeof(reset)); + if (ret == 0) { + + /* force reset high (inactive) and unmask interrupts */ + reset[1] = 0x7f; + ret = i2c_write_demod_bytes(state, + reset, sizeof(reset)); + } + return ret; +} + +static int lgdt3303_SwReset(struct lgdt330x_state* state) +{ + u8 ret; + u8 reset[] = { + 0x02, + 0x00 /* bit 0 is active low software reset */ + }; + + ret = i2c_write_demod_bytes(state, + reset, sizeof(reset)); + if (ret == 0) { + + /* force reset high (inactive) */ + reset[1] = 0x01; + ret = i2c_write_demod_bytes(state, + reset, sizeof(reset)); + } + return ret; +} + +static int lgdt330x_SwReset(struct lgdt330x_state* state) +{ + switch (state->config->demod_chip) { + case LGDT3302: + return lgdt3302_SwReset(state); + case LGDT3303: + return lgdt3303_SwReset(state); + default: + return -ENODEV; + } +} + +static int lgdt330x_init(struct dvb_frontend* fe) +{ + /* Hardware reset is done using gpio[0] of cx23880x chip. + * I'd like to do it here, but don't know how to find chip address. + * cx88-cards.c arranges for the reset bit to be inactive (high). + * Maybe there needs to be a callable function in cx88-core or + * the caller of this function needs to do it. */ + + /* + * Array of byte pairs + * to initialize each different chip + */ + static u8 lgdt3302_init_data[] = { + /* Use 50MHz parameter values from spec sheet since xtal is 50 */ + /* Change the value of NCOCTFV[25:0] of carrier + recovery center frequency register */ + VSB_CARRIER_FREQ0, 0x00, + VSB_CARRIER_FREQ1, 0x87, + VSB_CARRIER_FREQ2, 0x8e, + VSB_CARRIER_FREQ3, 0x01, + /* Change the TPCLK pin polarity + data is valid on falling clock */ + DEMUX_CONTROL, 0xfb, + /* Change the value of IFBW[11:0] of + AGC IF/RF loop filter bandwidth register */ + AGC_RF_BANDWIDTH0, 0x40, + AGC_RF_BANDWIDTH1, 0x93, + AGC_RF_BANDWIDTH2, 0x00, + /* Change the value of bit 6, 'nINAGCBY' and + 'NSSEL[1:0] of ACG function control register 2 */ + AGC_FUNC_CTRL2, 0xc6, + /* Change the value of bit 6 'RFFIX' + of AGC function control register 3 */ + AGC_FUNC_CTRL3, 0x40, + /* Set the value of 'INLVTHD' register 0x2a/0x2c + to 0x7fe */ + AGC_DELAY0, 0x07, + AGC_DELAY2, 0xfe, + /* Change the value of IAGCBW[15:8] + of inner AGC loop filter bandwidth */ + AGC_LOOP_BANDWIDTH0, 0x08, + AGC_LOOP_BANDWIDTH1, 0x9a + }; + + static u8 lgdt3303_init_data[] = { + 0x4c, 0x14 + }; + + static u8 flip_1_lgdt3303_init_data[] = { + 0x4c, 0x14, + 0x87, 0xf3 + }; + + static u8 flip_2_lgdt3303_init_data[] = { + 0x4c, 0x14, + 0x87, 0xda + }; + + struct lgdt330x_state* state = fe->demodulator_priv; + char *chip_name; + int err; + + switch (state->config->demod_chip) { + case LGDT3302: + chip_name = "LGDT3302"; + err = i2c_write_demod_bytes(state, lgdt3302_init_data, + sizeof(lgdt3302_init_data)); + break; + case LGDT3303: + chip_name = "LGDT3303"; + switch (state->config->clock_polarity_flip) { + case 2: + err = i2c_write_demod_bytes(state, + flip_2_lgdt3303_init_data, + sizeof(flip_2_lgdt3303_init_data)); + break; + case 1: + err = i2c_write_demod_bytes(state, + flip_1_lgdt3303_init_data, + sizeof(flip_1_lgdt3303_init_data)); + break; + case 0: + default: + err = i2c_write_demod_bytes(state, lgdt3303_init_data, + sizeof(lgdt3303_init_data)); + } + break; + default: + chip_name = "undefined"; + printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n"); + err = -ENODEV; + } + dprintk("%s entered as %s\n", __func__, chip_name); + if (err < 0) + return err; + return lgdt330x_SwReset(state); +} + +static int lgdt330x_read_ber(struct dvb_frontend* fe, u32* ber) +{ + *ber = 0; /* Not supplied by the demod chips */ + return 0; +} + +static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct lgdt330x_state* state = fe->demodulator_priv; + int err; + u8 buf[2]; + + switch (state->config->demod_chip) { + case LGDT3302: + err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, + buf, sizeof(buf)); + break; + case LGDT3303: + err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1, + buf, sizeof(buf)); + break; + default: + printk(KERN_WARNING + "Only LGDT3302 and LGDT3303 are supported chips.\n"); + err = -ENODEV; + } + + *ucblocks = (buf[0] << 8) | buf[1]; + return 0; +} + +static int lgdt330x_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + /* + * Array of byte pairs + * to initialize 8VSB for lgdt3303 chip 50 MHz IF + */ + static u8 lgdt3303_8vsb_44_data[] = { + 0x04, 0x00, + 0x0d, 0x40, + 0x0e, 0x87, + 0x0f, 0x8e, + 0x10, 0x01, + 0x47, 0x8b }; + + /* + * Array of byte pairs + * to initialize QAM for lgdt3303 chip + */ + static u8 lgdt3303_qam_data[] = { + 0x04, 0x00, + 0x0d, 0x00, + 0x0e, 0x00, + 0x0f, 0x00, + 0x10, 0x00, + 0x51, 0x63, + 0x47, 0x66, + 0x48, 0x66, + 0x4d, 0x1a, + 0x49, 0x08, + 0x4a, 0x9b }; + + struct lgdt330x_state* state = fe->demodulator_priv; + + static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; + + int err; + /* Change only if we are actually changing the modulation */ + if (state->current_modulation != param->u.vsb.modulation) { + switch(param->u.vsb.modulation) { + case VSB_8: + dprintk("%s: VSB_8 MODE\n", __func__); + + /* Select VSB mode */ + top_ctrl_cfg[1] = 0x03; + + /* Select ANT connector if supported by card */ + if (state->config->pll_rf_set) + state->config->pll_rf_set(fe, 1); + + if (state->config->demod_chip == LGDT3303) { + err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data, + sizeof(lgdt3303_8vsb_44_data)); + } + break; + + case QAM_64: + dprintk("%s: QAM_64 MODE\n", __func__); + + /* Select QAM_64 mode */ + top_ctrl_cfg[1] = 0x00; + + /* Select CABLE connector if supported by card */ + if (state->config->pll_rf_set) + state->config->pll_rf_set(fe, 0); + + if (state->config->demod_chip == LGDT3303) { + err = i2c_write_demod_bytes(state, lgdt3303_qam_data, + sizeof(lgdt3303_qam_data)); + } + break; + + case QAM_256: + dprintk("%s: QAM_256 MODE\n", __func__); + + /* Select QAM_256 mode */ + top_ctrl_cfg[1] = 0x01; + + /* Select CABLE connector if supported by card */ + if (state->config->pll_rf_set) + state->config->pll_rf_set(fe, 0); + + if (state->config->demod_chip == LGDT3303) { + err = i2c_write_demod_bytes(state, lgdt3303_qam_data, + sizeof(lgdt3303_qam_data)); + } + break; + default: + printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, param->u.vsb.modulation); + return -1; + } + /* + * select serial or parallel MPEG harware interface + * Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303 + * Parallel: 0x00 + */ + top_ctrl_cfg[1] |= state->config->serial_mpeg; + + /* Select the requested mode */ + i2c_write_demod_bytes(state, top_ctrl_cfg, + sizeof(top_ctrl_cfg)); + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + state->current_modulation = param->u.vsb.modulation; + } + + /* Tune to the specified frequency */ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* Keep track of the new frequency */ + /* FIXME this is the wrong way to do this... */ + /* The tuner is shared with the video4linux analog API */ + state->current_frequency = param->frequency; + + lgdt330x_SwReset(state); + return 0; +} + +static int lgdt330x_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters* param) +{ + struct lgdt330x_state *state = fe->demodulator_priv; + param->frequency = state->current_frequency; + return 0; +} + +static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct lgdt330x_state* state = fe->demodulator_priv; + u8 buf[3]; + + *status = 0; /* Reset status result */ + + /* AGC status register */ + i2c_read_demod_bytes(state, AGC_STATUS, buf, 1); + dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]); + if ((buf[0] & 0x0c) == 0x8){ + /* Test signal does not exist flag */ + /* as well as the AGC lock flag. */ + *status |= FE_HAS_SIGNAL; + } + + /* + * You must set the Mask bits to 1 in the IRQ_MASK in order + * to see that status bit in the IRQ_STATUS register. + * This is done in SwReset(); + */ + /* signal status */ + i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf)); + dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __func__, buf[0], buf[1], buf[2]); + + + /* sync status */ + if ((buf[2] & 0x03) == 0x01) { + *status |= FE_HAS_SYNC; + } + + /* FEC error status */ + if ((buf[2] & 0x0c) == 0x08) { + *status |= FE_HAS_LOCK; + *status |= FE_HAS_VITERBI; + } + + /* Carrier Recovery Lock Status Register */ + i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); + dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]); + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + /* Need to understand why there are 3 lock levels here */ + if ((buf[0] & 0x07) == 0x07) + *status |= FE_HAS_CARRIER; + break; + case VSB_8: + if ((buf[0] & 0x80) == 0x80) + *status |= FE_HAS_CARRIER; + break; + default: + printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__); + } + + return 0; +} + +static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct lgdt330x_state* state = fe->demodulator_priv; + int err; + u8 buf[3]; + + *status = 0; /* Reset status result */ + + /* lgdt3303 AGC status register */ + err = i2c_read_demod_bytes(state, 0x58, buf, 1); + if (err < 0) + return err; + + dprintk("%s: AGC_STATUS = 0x%02x\n", __func__, buf[0]); + if ((buf[0] & 0x21) == 0x01){ + /* Test input signal does not exist flag */ + /* as well as the AGC lock flag. */ + *status |= FE_HAS_SIGNAL; + } + + /* Carrier Recovery Lock Status Register */ + i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); + dprintk("%s: CARRIER_LOCK = 0x%02x\n", __func__, buf[0]); + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + /* Need to understand why there are 3 lock levels here */ + if ((buf[0] & 0x07) == 0x07) + *status |= FE_HAS_CARRIER; + else + break; + i2c_read_demod_bytes(state, 0x8a, buf, 1); + if ((buf[0] & 0x04) == 0x04) + *status |= FE_HAS_SYNC; + if ((buf[0] & 0x01) == 0x01) + *status |= FE_HAS_LOCK; + if ((buf[0] & 0x08) == 0x08) + *status |= FE_HAS_VITERBI; + break; + case VSB_8: + if ((buf[0] & 0x80) == 0x80) + *status |= FE_HAS_CARRIER; + else + break; + i2c_read_demod_bytes(state, 0x38, buf, 1); + if ((buf[0] & 0x02) == 0x00) + *status |= FE_HAS_SYNC; + if ((buf[0] & 0x01) == 0x01) { + *status |= FE_HAS_LOCK; + *status |= FE_HAS_VITERBI; + } + break; + default: + printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __func__); + } + return 0; +} + +/* Calculate SNR estimation (scaled by 2^24) + + 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM + equations from LGDT3303 datasheet. VSB is the same between the '02 + and '03, so maybe QAM is too? Perhaps someone with a newer datasheet + that has QAM information could verify? + + For 8-VSB: (two ways, take your pick) + LGDT3302: + SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE) + LGDT3303: + SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE) + LGDT3302 & LGDT3303: + SNR_PT = 10 * log10(25 * 32^2 / PT_MSE) (we use this one) + For 64-QAM: + SNR = 10 * log10( 688128 / MSEQAM) + For 256-QAM: + SNR = 10 * log10( 696320 / MSEQAM) + + We re-write the snr equation as: + SNR * 2^24 = 10*(c - intlog10(MSE)) + Where for 256-QAM, c = log10(696320) * 2^24, and so on. */ + +static u32 calculate_snr(u32 mse, u32 c) +{ + if (mse == 0) /* No signal */ + return 0; + + mse = intlog10(mse); + if (mse > c) { + /* Negative SNR, which is possible, but realisticly the + demod will lose lock before the signal gets this bad. The + API only allows for unsigned values, so just return 0 */ + return 0; + } + return 10*(c - mse); +} + +static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + u8 buf[5]; /* read data buffer */ + u32 noise; /* noise value */ + u32 c; /* per-modulation SNR calculation constant */ + + switch(state->current_modulation) { + case VSB_8: + i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5); +#ifdef USE_EQMSE + /* Use Equalizer Mean-Square Error Register */ + /* SNR for ranges from -15.61 to +41.58 */ + noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; + c = 69765745; /* log10(25*24^2)*2^24 */ +#else + /* Use Phase Tracker Mean-Square Error Register */ + /* SNR for ranges from -13.11 to +44.08 */ + noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; + c = 73957994; /* log10(25*32^2)*2^24 */ +#endif + break; + case QAM_64: + case QAM_256: + i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); + noise = ((buf[0] & 3) << 8) | buf[1]; + c = state->current_modulation == QAM_64 ? 97939837 : 98026066; + /* log10(688128)*2^24 and log10(696320)*2^24 */ + break; + default: + printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n", + __func__); + return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ + } + + state->snr = calculate_snr(noise, c); + *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ + + dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, + state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); + + return 0; +} + +static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + u8 buf[5]; /* read data buffer */ + u32 noise; /* noise value */ + u32 c; /* per-modulation SNR calculation constant */ + + switch(state->current_modulation) { + case VSB_8: + i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5); +#ifdef USE_EQMSE + /* Use Equalizer Mean-Square Error Register */ + /* SNR for ranges from -16.12 to +44.08 */ + noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2]; + c = 73957994; /* log10(25*32^2)*2^24 */ +#else + /* Use Phase Tracker Mean-Square Error Register */ + /* SNR for ranges from -13.11 to +44.08 */ + noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; + c = 73957994; /* log10(25*32^2)*2^24 */ +#endif + break; + case QAM_64: + case QAM_256: + i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); + noise = (buf[0] << 8) | buf[1]; + c = state->current_modulation == QAM_64 ? 97939837 : 98026066; + /* log10(688128)*2^24 and log10(696320)*2^24 */ + break; + default: + printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n", + __func__); + return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ + } + + state->snr = calculate_snr(noise, c); + *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ + + dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, + state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); + + return 0; +} + +static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + /* Calculate Strength from SNR up to 35dB */ + /* Even though the SNR can go higher than 35dB, there is some comfort */ + /* factor in having a range of strong signals that can show at 100% */ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + u16 snr; + int ret; + + ret = fe->ops.read_snr(fe, &snr); + if (ret != 0) + return ret; + /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ + /* scale the range 0 - 35*2^24 into 0 - 65535 */ + if (state->snr >= 8960 * 0x10000) + *strength = 0xffff; + else + *strength = state->snr / 8960; + + return 0; +} + +static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) +{ + /* I have no idea about this - it may not be needed */ + fe_tune_settings->min_delay_ms = 500; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + return 0; +} + +static void lgdt330x_release(struct dvb_frontend* fe) +{ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops lgdt3302_ops; +static struct dvb_frontend_ops lgdt3303_ops; + +struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, + struct i2c_adapter* i2c) +{ + struct lgdt330x_state* state = NULL; + u8 buf[1]; + + /* Allocate memory for the internal state */ + state = kzalloc(sizeof(struct lgdt330x_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + + /* Create dvb_frontend */ + switch (config->demod_chip) { + case LGDT3302: + memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); + break; + case LGDT3303: + memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops)); + break; + default: + goto error; + } + state->frontend.demodulator_priv = state; + + /* Verify communication with demod chip */ + if (i2c_read_demod_bytes(state, 2, buf, 1)) + goto error; + + state->current_frequency = -1; + state->current_modulation = -1; + + return &state->frontend; + +error: + kfree(state); + dprintk("%s: ERROR\n",__func__); + return NULL; +} + +static struct dvb_frontend_ops lgdt3302_ops = { + .info = { + .name= "LG Electronics LGDT3302 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min= 54000000, + .frequency_max= 858000000, + .frequency_stepsize= 62500, + .symbol_rate_min = 5056941, /* QAM 64 */ + .symbol_rate_max = 10762000, /* VSB 8 */ + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt330x_init, + .set_frontend = lgdt330x_set_parameters, + .get_frontend = lgdt330x_get_frontend, + .get_tune_settings = lgdt330x_get_tune_settings, + .read_status = lgdt3302_read_status, + .read_ber = lgdt330x_read_ber, + .read_signal_strength = lgdt330x_read_signal_strength, + .read_snr = lgdt3302_read_snr, + .read_ucblocks = lgdt330x_read_ucblocks, + .release = lgdt330x_release, +}; + +static struct dvb_frontend_ops lgdt3303_ops = { + .info = { + .name= "LG Electronics LGDT3303 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min= 54000000, + .frequency_max= 858000000, + .frequency_stepsize= 62500, + .symbol_rate_min = 5056941, /* QAM 64 */ + .symbol_rate_max = 10762000, /* VSB 8 */ + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt330x_init, + .set_frontend = lgdt330x_set_parameters, + .get_frontend = lgdt330x_get_frontend, + .get_tune_settings = lgdt330x_get_tune_settings, + .read_status = lgdt3303_read_status, + .read_ber = lgdt330x_read_ber, + .read_signal_strength = lgdt330x_read_signal_strength, + .read_snr = lgdt3303_read_snr, + .read_ucblocks = lgdt330x_read_ucblocks, + .release = lgdt330x_release, +}; + +MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); +MODULE_AUTHOR("Wilson Michaels"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(lgdt330x_attach); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * Support for LGDT3302 and LGDT3303 - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef LGDT330X_H +#define LGDT330X_H + +#include + +typedef enum lg_chip_t { + UNDEFINED, + LGDT3302, + LGDT3303 +}lg_chip_type; + +struct lgdt330x_config +{ + /* The demodulator's i2c address */ + u8 demod_address; + + /* LG demodulator chip LGDT3302 or LGDT3303 */ + lg_chip_type demod_chip; + + /* MPEG hardware interface - 0:parallel 1:serial */ + int serial_mpeg; + + /* PLL interface */ + int (*pll_rf_set) (struct dvb_frontend* fe, int index); + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); + + /* Flip the polarity of the mpeg data transfer clock using alternate init data + * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled */ + int clock_polarity_flip; +}; + +#if defined(CONFIG_DVB_LGDT330X) || (defined(CONFIG_DVB_LGDT330X_MODULE) && defined(MODULE)) +extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_LGDT330X + +#endif /* LGDT330X_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgdt330x_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,77 @@ +/* + * Support for LGDT3302 and LGDT3303 - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _LGDT330X_PRIV_ +#define _LGDT330X_PRIV_ + +/* i2c control register addresses */ +enum I2C_REG { + TOP_CONTROL= 0x00, + IRQ_MASK= 0x01, + IRQ_STATUS= 0x02, + VSB_CARRIER_FREQ0= 0x16, + VSB_CARRIER_FREQ1= 0x17, + VSB_CARRIER_FREQ2= 0x18, + VSB_CARRIER_FREQ3= 0x19, + CARRIER_MSEQAM1= 0x1a, + CARRIER_MSEQAM2= 0x1b, + CARRIER_LOCK= 0x1c, + TIMING_RECOVERY= 0x1d, + AGC_DELAY0= 0x2a, + AGC_DELAY1= 0x2b, + AGC_DELAY2= 0x2c, + AGC_RF_BANDWIDTH0= 0x2d, + AGC_RF_BANDWIDTH1= 0x2e, + AGC_RF_BANDWIDTH2= 0x2f, + AGC_LOOP_BANDWIDTH0= 0x30, + AGC_LOOP_BANDWIDTH1= 0x31, + AGC_FUNC_CTRL1= 0x32, + AGC_FUNC_CTRL2= 0x33, + AGC_FUNC_CTRL3= 0x34, + AGC_RFIF_ACC0= 0x39, + AGC_RFIF_ACC1= 0x3a, + AGC_RFIF_ACC2= 0x3b, + AGC_STATUS= 0x3f, + SYNC_STATUS_VSB= 0x43, + DEMUX_CONTROL= 0x66, + LGDT3302_EQPH_ERR0= 0x47, + LGDT3302_EQ_ERR1= 0x48, + LGDT3302_EQ_ERR2= 0x49, + LGDT3302_PH_ERR1= 0x4a, + LGDT3302_PH_ERR2= 0x4b, + LGDT3302_PACKET_ERR_COUNTER1= 0x6a, + LGDT3302_PACKET_ERR_COUNTER2= 0x6b, + LGDT3303_EQPH_ERR0= 0x6e, + LGDT3303_EQ_ERR1= 0x6f, + LGDT3303_EQ_ERR2= 0x70, + LGDT3303_PH_ERR1= 0x71, + LGDT3303_PH_ERR2= 0x72, + LGDT3303_PACKET_ERR_COUNTER1= 0x8b, + LGDT3303_PACKET_ERR_COUNTER2= 0x8c, +}; + +#endif /* _LGDT330X_PRIV_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gl5.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gl5.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gl5.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gl5.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,454 @@ +/* + Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver + + Copyright (C) 2008 Sirius International (Hong Kong) Limited + Timothy Lee + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "lgs8gl5.h" + + +#define REG_RESET 0x02 +#define REG_RESET_OFF 0x01 +#define REG_03 0x03 +#define REG_04 0x04 +#define REG_07 0x07 +#define REG_09 0x09 +#define REG_0A 0x0a +#define REG_0B 0x0b +#define REG_0C 0x0c +#define REG_37 0x37 +#define REG_STRENGTH 0x4b +#define REG_STRENGTH_MASK 0x7f +#define REG_STRENGTH_CARRIER 0x80 +#define REG_INVERSION 0x7c +#define REG_INVERSION_ON 0x80 +#define REG_7D 0x7d +#define REG_7E 0x7e +#define REG_A2 0xa2 +#define REG_STATUS 0xa4 +#define REG_STATUS_SYNC 0x04 +#define REG_STATUS_LOCK 0x01 + + +struct lgs8gl5_state { + struct i2c_adapter *i2c; + const struct lgs8gl5_config *config; + struct dvb_frontend frontend; +}; + + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "lgs8gl5: " args); \ + } while (0) + + +/* Writes into demod's register */ +static int +lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = {reg, data}; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n", + __func__, reg, data, ret); + return (ret != 1) ? -1 : 0; +} + + +/* Reads from demod's register */ +static int +lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) +{ + int ret; + u8 b0[] = {reg}; + u8 b1[] = {0}; + struct i2c_msg msg[2] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 1 + }, + { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) + return -EIO; + + return b1[0]; +} + + +static int +lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + lgs8gl5_read_reg(state, reg); + lgs8gl5_write_reg(state, reg, data); + return 0; +} + + +/* Writes into alternate device's register */ +/* TODO: Find out what that device is for! */ +static int +lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + int ret; + u8 b0[] = {reg}; + u8 b1[] = {0}; + u8 b2[] = {reg, data}; + struct i2c_msg msg[3] = { + { + .addr = state->config->demod_address + 2, + .flags = 0, + .buf = b0, + .len = 1 + }, + { + .addr = state->config->demod_address + 2, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + }, + { + .addr = state->config->demod_address + 2, + .flags = 0, + .buf = b2, + .len = 2 + }, + }; + + ret = i2c_transfer(state->i2c, msg, 3); + return (ret != 3) ? -1 : 0; +} + + +static void +lgs8gl5_soft_reset(struct lgs8gl5_state *state) +{ + u8 val; + + dprintk("%s\n", __func__); + + val = lgs8gl5_read_reg(state, REG_RESET); + lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF); + lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF); + msleep(5); +} + + +/* Starts demodulation */ +static void +lgs8gl5_start_demod(struct lgs8gl5_state *state) +{ + u8 val; + int n; + + dprintk("%s\n", __func__); + + lgs8gl5_update_alt_reg(state, 0xc2, 0x28); + lgs8gl5_soft_reset(state); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_write_reg(state, REG_09, 0x0e); + lgs8gl5_write_reg(state, REG_0A, 0xe5); + lgs8gl5_write_reg(state, REG_0B, 0x35); + lgs8gl5_write_reg(state, REG_0C, 0x30); + + lgs8gl5_update_reg(state, REG_03, 0x00); + lgs8gl5_update_reg(state, REG_7E, 0x01); + lgs8gl5_update_alt_reg(state, 0xc5, 0x00); + lgs8gl5_update_reg(state, REG_04, 0x02); + lgs8gl5_update_reg(state, REG_37, 0x01); + lgs8gl5_soft_reset(state); + + /* Wait for carrier */ + for (n = 0; n < 10; n++) { + val = lgs8gl5_read_reg(state, REG_STRENGTH); + dprintk("Wait for carrier[%d] 0x%02X\n", n, val); + if (val & REG_STRENGTH_CARRIER) + break; + msleep(4); + } + if (!(val & REG_STRENGTH_CARRIER)) + return; + + /* Wait for lock */ + for (n = 0; n < 20; n++) { + val = lgs8gl5_read_reg(state, REG_STATUS); + dprintk("Wait for lock[%d] 0x%02X\n", n, val); + if (val & REG_STATUS_LOCK) + break; + msleep(12); + } + if (!(val & REG_STATUS_LOCK)) + return; + + lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2)); + lgs8gl5_soft_reset(state); +} + + +static int +lgs8gl5_init(struct dvb_frontend *fe) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + lgs8gl5_update_alt_reg(state, 0xc2, 0x28); + lgs8gl5_soft_reset(state); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_write_reg(state, REG_09, 0x0e); + lgs8gl5_write_reg(state, REG_0A, 0xe5); + lgs8gl5_write_reg(state, REG_0B, 0x35); + lgs8gl5_write_reg(state, REG_0C, 0x30); + + return 0; +} + + +static int +lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + u8 flags = lgs8gl5_read_reg(state, REG_STATUS); + + *status = 0; + + if ((level & REG_STRENGTH_MASK) > 0) + *status |= FE_HAS_SIGNAL; + if (level & REG_STRENGTH_CARRIER) + *status |= FE_HAS_CARRIER; + if (flags & REG_STATUS_SYNC) + *status |= FE_HAS_SYNC; + if (flags & REG_STATUS_LOCK) + *status |= FE_HAS_LOCK; + + return 0; +} + + +static int +lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + + return 0; +} + + +static int +lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + *signal_strength = (level & REG_STRENGTH_MASK) << 8; + + return 0; +} + + +static int +lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + *snr = (level & REG_STRENGTH_MASK) << 8; + + return 0; +} + + +static int +lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + + return 0; +} + + +static int +lgs8gl5_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ) + return -EINVAL; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* lgs8gl5_set_inversion(state, p->inversion); */ + + lgs8gl5_start_demod(state); + + return 0; +} + + +static int +lgs8gl5_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); + struct dvb_ofdm_parameters *o = &p->u.ofdm; + + p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; + + o->code_rate_HP = FEC_1_2; + o->code_rate_LP = FEC_7_8; + o->guard_interval = GUARD_INTERVAL_1_32; + o->transmission_mode = TRANSMISSION_MODE_2K; + o->constellation = QAM_64; + o->hierarchy_information = HIERARCHY_NONE; + o->bandwidth = BANDWIDTH_8_MHZ; + + return 0; +} + + +static int +lgs8gl5_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 240; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + + +static void +lgs8gl5_release(struct dvb_frontend *fe) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + kfree(state); +} + + +static struct dvb_frontend_ops lgs8gl5_ops; + + +struct dvb_frontend* +lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c) +{ + struct lgs8gl5_state *state = NULL; + + dprintk("%s\n", __func__); + + /* Allocate memory for the internal state */ + state = kzalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + + /* Check if the demod is there */ + if (lgs8gl5_read_reg(state, REG_RESET) < 0) + goto error; + + /* Create dvb_frontend */ + memcpy(&state->frontend.ops, &lgs8gl5_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(lgs8gl5_attach); + + +static struct dvb_frontend_ops lgs8gl5_ops = { + .info = { + .name = "Legend Silicon LGS-8GL5 DMB-TH", + .type = FE_OFDM, + .frequency_min = 474000000, + .frequency_max = 858000000, + .frequency_stepsize = 10000, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | + FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_BANDWIDTH_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER + }, + + .release = lgs8gl5_release, + + .init = lgs8gl5_init, + + .set_frontend = lgs8gl5_set_frontend, + .get_frontend = lgs8gl5_get_frontend, + .get_tune_settings = lgs8gl5_get_tune_settings, + + .read_status = lgs8gl5_read_status, + .read_ber = lgs8gl5_read_ber, + .read_signal_strength = lgs8gl5_read_signal_strength, + .read_snr = lgs8gl5_read_snr, + .read_ucblocks = lgs8gl5_read_ucblocks, +}; + + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver"); +MODULE_AUTHOR("Timothy Lee"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gl5.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gl5.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gl5.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gl5.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,45 @@ +/* + Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver + + Copyright (C) 2008 Sirius International (Hong Kong) Limited + Timothy Lee + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef LGS8GL5_H +#define LGS8GL5_H + +#include + +struct lgs8gl5_config { + /* the demodulator's i2c address */ + u8 demod_address; +}; + +#if defined(CONFIG_DVB_LGS8GL5) || \ + (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE)) +extern struct dvb_frontend *lgs8gl5_attach( + const struct lgs8gl5_config *config, struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *lgs8gl5_attach( + const struct lgs8gl5_config *config, struct i2c_adapter *i2c) { + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGS8GL5 */ + +#endif /* LGS8GL5_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1073 @@ +/* + * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator + * LGS8913, LGS8GL5, LGS8G75 + * experimental support LGS8G42, LGS8G52 + * + * Copyright (C) 2007-2009 David T.L. Wong + * Copyright (C) 2008 Sirius International (Hong Kong) Limited + * Timothy Lee (for initial work on LGS8GL5) + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + +#include "dvb_frontend.h" + +#include "lgs8gxx.h" +#include "lgs8gxx_priv.h" + +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "lgs8gxx: " args); \ + } while (0) + +static int debug; +static int fake_signal_str = 1; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +module_param(fake_signal_str, int, 0644); +MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913." +"Signal strength calculation is slow.(default:on)."); + +/* LGS8GXX internal helper functions */ + +static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; + + msg.addr = priv->config->demod_address; + if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0) + msg.addr += 0x02; + + if (debug >= 2) + dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data); + + ret = i2c_transfer(priv->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", + __func__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data) +{ + int ret; + u8 dev_addr; + + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { .flags = 0, .buf = b0, .len = 1 }, + { .flags = I2C_M_RD, .buf = b1, .len = 1 }, + }; + + dev_addr = priv->config->demod_address; + if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0) + dev_addr += 0x02; + msg[1].addr = msg[0].addr = dev_addr; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret != 2) { + dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret); + return -1; + } + + *p_data = b1[0]; + if (debug >= 2) + dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, b1[0]); + return 0; +} + +static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv) +{ + lgs8gxx_write_reg(priv, 0x02, 0x00); + msleep(1); + lgs8gxx_write_reg(priv, 0x02, 0x01); + msleep(100); + + return 0; +} + +static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask, + u8 val, u8 delay, u8 tries) +{ + u8 t; + int i; + + for (i = 0; i < tries; i++) { + lgs8gxx_read_reg(priv, reg, &t); + + if ((t & mask) == val) + return 0; + msleep(delay); + } + + return 1; +} + +static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv) +{ + const struct lgs8gxx_config *config = priv->config; + u8 if_conf; + + if_conf = 0x10; /* AGC output on, RF_AGC output off; */ + + if_conf |= + ((config->ext_adc) ? 0x80 : 0x00) | + ((config->if_neg_center) ? 0x04 : 0x00) | + ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */ + ((config->adc_signed) ? 0x02 : 0x00) | + ((config->if_neg_edge) ? 0x01 : 0x00); + + if (config->ext_adc && + (config->prod == LGS8GXX_PROD_LGS8G52)) { + lgs8gxx_write_reg(priv, 0xBA, 0x40); + } + + lgs8gxx_write_reg(priv, 0x07, if_conf); + + return 0; +} + +static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/) +{ + u64 val; + u32 v32; + u32 if_clk; + + if_clk = priv->config->if_clk_freq; + + val = freq; + if (freq != 0) { + val <<= 32; + if (if_clk != 0) + do_div(val, if_clk); + v32 = val & 0xFFFFFFFF; + dprintk("Set IF Freq to %dkHz\n", freq); + } else { + v32 = 0; + dprintk("Set IF Freq to baseband\n"); + } + dprintk("AFC_INIT_FREQ = 0x%08X\n", v32); + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32)); + lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8)); + lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16)); + lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24)); + } else { + lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32)); + lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8)); + lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16)); + lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24)); + } + + return 0; +} + +static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv) +{ + u64 val; + u32 v32 = 0; + u8 reg_addr, t; + int i; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + reg_addr = 0x23; + else + reg_addr = 0x48; + + for (i = 0; i < 4; i++) { + lgs8gxx_read_reg(priv, reg_addr, &t); + v32 <<= 8; + v32 |= t; + reg_addr--; + } + + val = v32; + val *= priv->config->if_clk_freq; + val >>= 32; + dprintk("AFC = %u kHz\n", (u32)val); + return 0; +} + +static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv) +{ + u8 t; + u8 prod = priv->config->prod; + + if (prod == LGS8GXX_PROD_LGS8913) + lgs8gxx_write_reg(priv, 0xC6, 0x01); + + if (prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0x0C, &t); + t &= (~0x04); + lgs8gxx_write_reg(priv, 0x0C, t | 0x80); + lgs8gxx_write_reg(priv, 0x39, 0x00); + lgs8gxx_write_reg(priv, 0x3D, 0x04); + } else if (prod == LGS8GXX_PROD_LGS8913 || + prod == LGS8GXX_PROD_LGS8GL5 || + prod == LGS8GXX_PROD_LGS8G42 || + prod == LGS8GXX_PROD_LGS8G52 || + prod == LGS8GXX_PROD_LGS8G54) { + lgs8gxx_read_reg(priv, 0x7E, &t); + lgs8gxx_write_reg(priv, 0x7E, t | 0x01); + + /* clear FEC self reset */ + lgs8gxx_read_reg(priv, 0xC5, &t); + lgs8gxx_write_reg(priv, 0xC5, t & 0xE0); + } + + if (prod == LGS8GXX_PROD_LGS8913) { + /* FEC auto detect */ + lgs8gxx_write_reg(priv, 0xC1, 0x03); + + lgs8gxx_read_reg(priv, 0x7C, &t); + t = (t & 0x8C) | 0x03; + lgs8gxx_write_reg(priv, 0x7C, t); + + /* BER test mode */ + lgs8gxx_read_reg(priv, 0xC3, &t); + t = (t & 0xEF) | 0x10; + lgs8gxx_write_reg(priv, 0xC3, t); + } + + if (priv->config->prod == LGS8GXX_PROD_LGS8G52) + lgs8gxx_write_reg(priv, 0xD9, 0x40); + + return 0; +} + +static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv) +{ + int ret = 0; + u8 t; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + u8 t2; + lgs8gxx_read_reg(priv, 0x0C, &t); + t &= (~0x80); + lgs8gxx_write_reg(priv, 0x0C, t); + + lgs8gxx_read_reg(priv, 0x0C, &t); + lgs8gxx_read_reg(priv, 0x19, &t2); + + if (((t&0x03) == 0x01) && (t2&0x01)) { + lgs8gxx_write_reg(priv, 0x6E, 0x05); + lgs8gxx_write_reg(priv, 0x39, 0x02); + lgs8gxx_write_reg(priv, 0x39, 0x03); + lgs8gxx_write_reg(priv, 0x3D, 0x05); + lgs8gxx_write_reg(priv, 0x3E, 0x28); + lgs8gxx_write_reg(priv, 0x53, 0x80); + } else { + lgs8gxx_write_reg(priv, 0x6E, 0x3F); + lgs8gxx_write_reg(priv, 0x39, 0x00); + lgs8gxx_write_reg(priv, 0x3D, 0x04); + } + + lgs8gxx_soft_reset(priv); + return 0; + } + + /* turn off auto-detect; manual settings */ + lgs8gxx_write_reg(priv, 0x7E, 0); + if (priv->config->prod == LGS8GXX_PROD_LGS8913) + lgs8gxx_write_reg(priv, 0xC1, 0); + + ret = lgs8gxx_read_reg(priv, 0xC5, &t); + t = (t & 0xE0) | 0x06; + lgs8gxx_write_reg(priv, 0xC5, t); + + lgs8gxx_soft_reset(priv); + + return 0; +} + +static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked) +{ + int ret = 0; + u8 t; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + ret = lgs8gxx_read_reg(priv, 0x13, &t); + else + ret = lgs8gxx_read_reg(priv, 0x4B, &t); + if (ret != 0) + return ret; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + *locked = ((t & 0x80) == 0x80) ? 1 : 0; + else + *locked = ((t & 0xC0) == 0xC0) ? 1 : 0; + return 0; +} + +/* Wait for Code Acquisition Lock */ +static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked) +{ + int ret = 0; + u8 reg, mask, val; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + reg = 0x13; + mask = 0x80; + val = 0x80; + } else { + reg = 0x4B; + mask = 0xC0; + val = 0xC0; + } + + ret = wait_reg_mask(priv, reg, mask, val, 50, 40); + *locked = (ret == 0) ? 1 : 0; + + return 0; +} + +static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv, + u8 *finished) +{ + int ret = 0; + u8 reg, mask, val; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + reg = 0x1f; + mask = 0xC0; + val = 0x80; + } else { + reg = 0xA4; + mask = 0x03; + val = 0x01; + } + + ret = wait_reg_mask(priv, reg, mask, val, 10, 20); + *finished = (ret == 0) ? 1 : 0; + + return 0; +} + +static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn, + u8 *locked) +{ + int err = 0; + u8 ad_fini = 0; + u8 t1, t2; + + if (gi == GI_945) + dprintk("try GI 945\n"); + else if (gi == GI_595) + dprintk("try GI 595\n"); + else if (gi == GI_420) + dprintk("try GI 420\n"); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0x0C, &t1); + lgs8gxx_read_reg(priv, 0x18, &t2); + t1 &= ~(GI_MASK); + t1 |= gi; + t2 &= 0xFE; + t2 |= cpn ? 0x01 : 0x00; + lgs8gxx_write_reg(priv, 0x0C, t1); + lgs8gxx_write_reg(priv, 0x18, t2); + } else { + lgs8gxx_write_reg(priv, 0x04, gi); + } + lgs8gxx_soft_reset(priv); + err = lgs8gxx_wait_ca_lock(priv, locked); + if (err || !(*locked)) + return err; + err = lgs8gxx_is_autodetect_finished(priv, &ad_fini); + if (err != 0) + return err; + if (ad_fini) { + dprintk("auto detect finished\n"); + } else + *locked = 0; + + return 0; +} + +static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv, + u8 *detected_param, u8 *gi) +{ + int i, j; + int err = 0; + u8 locked = 0, tmp_gi; + + dprintk("%s\n", __func__); + + lgs8gxx_set_mode_auto(priv); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_write_reg(priv, 0x67, 0xAA); + lgs8gxx_write_reg(priv, 0x6E, 0x3F); + } else { + /* Guard Interval */ + lgs8gxx_write_reg(priv, 0x03, 00); + } + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + tmp_gi = GI_945; + err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked); + if (err) + goto out; + if (locked) + goto locked; + } + for (j = 0; j < 2; j++) { + tmp_gi = GI_420; + err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked); + if (err) + goto out; + if (locked) + goto locked; + } + tmp_gi = GI_595; + err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked); + if (err) + goto out; + if (locked) + goto locked; + } + +locked: + if ((err == 0) && (locked == 1)) { + u8 t; + + if (priv->config->prod != LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0xA2, &t); + *detected_param = t; + } else { + lgs8gxx_read_reg(priv, 0x1F, &t); + *detected_param = t & 0x3F; + } + + if (tmp_gi == GI_945) + dprintk("GI 945 locked\n"); + else if (tmp_gi == GI_595) + dprintk("GI 595 locked\n"); + else if (tmp_gi == GI_420) + dprintk("GI 420 locked\n"); + *gi = tmp_gi; + } + if (!locked) + err = -1; + +out: + return err; +} + +static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv) +{ + s8 err; + u8 gi = 0x2; + u8 detected_param = 0; + + err = lgs8gxx_auto_detect(priv, &detected_param, &gi); + + if (err != 0) { + dprintk("lgs8gxx_auto_detect failed\n"); + } else + dprintk("detected param = 0x%02X\n", detected_param); + + /* Apply detected parameters */ + if (priv->config->prod == LGS8GXX_PROD_LGS8913) { + u8 inter_leave_len = detected_param & TIM_MASK ; + /* Fix 8913 time interleaver detection bug */ + inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40; + detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK; + detected_param |= inter_leave_len; + } + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + u8 t; + lgs8gxx_read_reg(priv, 0x19, &t); + t &= 0x81; + t |= detected_param << 1; + lgs8gxx_write_reg(priv, 0x19, t); + } else { + lgs8gxx_write_reg(priv, 0x7D, detected_param); + if (priv->config->prod == LGS8GXX_PROD_LGS8913) + lgs8gxx_write_reg(priv, 0xC0, detected_param); + } + /* lgs8gxx_soft_reset(priv); */ + + /* Enter manual mode */ + lgs8gxx_set_mode_manual(priv); + + switch (gi) { + case GI_945: + priv->curr_gi = 945; break; + case GI_595: + priv->curr_gi = 595; break; + case GI_420: + priv->curr_gi = 420; break; + default: + priv->curr_gi = 945; break; + } +} + +static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv, + u8 serial, u8 clk_pol, u8 clk_gated) +{ + int ret = 0; + u8 t, reg_addr; + + reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2; + ret = lgs8gxx_read_reg(priv, reg_addr, &t); + if (ret != 0) + return ret; + + t &= 0xF8; + t |= serial ? TS_SERIAL : TS_PARALLEL; + t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL; + t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN; + + ret = lgs8gxx_write_reg(priv, reg_addr, t); + if (ret != 0) + return ret; + + return 0; +} + +/* A/D input peak-to-peak voltage range */ +static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv, + u8 sel) +{ + u8 r26 = 0x73, r27 = 0x90; + + if (priv->config->prod != LGS8GXX_PROD_LGS8G75) + return 0; + + r26 |= (sel & 0x01) << 7; + r27 |= (sel & 0x02) >> 1; + lgs8gxx_write_reg(priv, 0x26, r26); + lgs8gxx_write_reg(priv, 0x27, r27); + + return 0; +} + +/* LGS8913 demod frontend functions */ + +static int lgs8913_init(struct lgs8gxx_state *priv) +{ + u8 t; + + /* LGS8913 specific */ + lgs8gxx_write_reg(priv, 0xc1, 0x3); + + lgs8gxx_read_reg(priv, 0x7c, &t); + lgs8gxx_write_reg(priv, 0x7c, (t&0x8c) | 0x3); + + /* LGS8913 specific */ + lgs8gxx_read_reg(priv, 0xc3, &t); + lgs8gxx_write_reg(priv, 0xc3, t&0x10); + + + return 0; +} + +static int lgs8g75_init_data(struct lgs8gxx_state *priv) +{ + const struct firmware *fw; + int rc; + int i; + + rc = request_firmware(&fw, "lgs8g75.fw", &priv->i2c->dev); + if (rc) + return rc; + + lgs8gxx_write_reg(priv, 0xC6, 0x40); + + lgs8gxx_write_reg(priv, 0x3D, 0x04); + lgs8gxx_write_reg(priv, 0x39, 0x00); + + lgs8gxx_write_reg(priv, 0x3A, 0x00); + lgs8gxx_write_reg(priv, 0x38, 0x00); + lgs8gxx_write_reg(priv, 0x3B, 0x00); + lgs8gxx_write_reg(priv, 0x38, 0x00); + + for (i = 0; i < fw->size; i++) { + lgs8gxx_write_reg(priv, 0x38, 0x00); + lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff)); + lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8)); + lgs8gxx_write_reg(priv, 0x3C, fw->data[i]); + } + + lgs8gxx_write_reg(priv, 0x38, 0x00); + + release_firmware(fw); + return 0; +} + +static int lgs8gxx_init(struct dvb_frontend *fe) +{ + struct lgs8gxx_state *priv = + (struct lgs8gxx_state *)fe->demodulator_priv; + const struct lgs8gxx_config *config = priv->config; + u8 data = 0; + s8 err; + dprintk("%s\n", __func__); + + lgs8gxx_read_reg(priv, 0, &data); + dprintk("reg 0 = 0x%02X\n", data); + + if (config->prod == LGS8GXX_PROD_LGS8G75) + lgs8g75_set_adc_vpp(priv, config->adc_vpp); + + /* Setup MPEG output format */ + err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts, + config->ts_clk_pol, + config->ts_clk_gated); + if (err != 0) + return -EIO; + + if (config->prod == LGS8GXX_PROD_LGS8913) + lgs8913_init(priv); + lgs8gxx_set_if_freq(priv, priv->config->if_freq); + lgs8gxx_set_ad_mode(priv); + + return 0; +} + +static void lgs8gxx_release(struct dvb_frontend *fe) +{ + struct lgs8gxx_state *state = fe->demodulator_priv; + dprintk("%s\n", __func__); + + kfree(state); +} + + +static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len) +{ + struct lgs8gxx_state *priv = fe->demodulator_priv; + + if (len != 2) + return -EINVAL; + + return lgs8gxx_write_reg(priv, buf[0], buf[1]); +} + +static int lgs8gxx_set_fe(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fe_params) +{ + struct lgs8gxx_state *priv = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + /* set frequency */ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, fe_params); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* start auto lock */ + lgs8gxx_auto_lock(priv); + + msleep(10); + + return 0; +} + +static int lgs8gxx_get_fe(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fe_params) +{ + dprintk("%s\n", __func__); + + /* TODO: get real readings from device */ + /* inversion status */ + fe_params->inversion = INVERSION_OFF; + + /* bandwidth */ + fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + + fe_params->u.ofdm.code_rate_HP = FEC_AUTO; + fe_params->u.ofdm.code_rate_LP = FEC_AUTO; + + fe_params->u.ofdm.constellation = QAM_AUTO; + + /* transmission mode */ + fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + + /* guard interval */ + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + + /* hierarchy */ + fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + + return 0; +} + +static +int lgs8gxx_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + /* FIXME: copy from tda1004x.c */ + fesettings->min_delay_ms = 800; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status) +{ + struct lgs8gxx_state *priv = fe->demodulator_priv; + s8 ret; + u8 t, locked = 0; + + dprintk("%s\n", __func__); + *fe_status = 0; + + lgs8gxx_get_afc_phase(priv); + lgs8gxx_is_locked(priv, &locked); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + if (locked) + *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + return 0; + } + + ret = lgs8gxx_read_reg(priv, 0x4B, &t); + if (ret != 0) + return -EIO; + + dprintk("Reg 0x4B: 0x%02X\n", t); + + *fe_status = 0; + if (priv->config->prod == LGS8GXX_PROD_LGS8913) { + if ((t & 0x40) == 0x40) + *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + if ((t & 0x80) == 0x80) + *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + } else { + if ((t & 0x80) == 0x80) + *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } + + /* success */ + dprintk("%s: fe_status=0x%x\n", __func__, *fe_status); + return 0; +} + +static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal) +{ + u16 v; + u8 agc_lvl[2], cat; + + dprintk("%s()\n", __func__); + lgs8gxx_read_reg(priv, 0x3F, &agc_lvl[0]); + lgs8gxx_read_reg(priv, 0x3E, &agc_lvl[1]); + + v = agc_lvl[0]; + v <<= 8; + v |= agc_lvl[1]; + + dprintk("agc_lvl: 0x%04X\n", v); + + if (v < 0x100) + cat = 0; + else if (v < 0x190) + cat = 5; + else if (v < 0x2A8) + cat = 4; + else if (v < 0x381) + cat = 3; + else if (v < 0x400) + cat = 2; + else if (v == 0x400) + cat = 1; + else + cat = 0; + + *signal = cat * 65535 / 5; + + return 0; +} + +static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal) +{ + u8 t; s8 ret; + s16 max_strength = 0; + u8 str; + u16 i, gi = priv->curr_gi; + + dprintk("%s\n", __func__); + + ret = lgs8gxx_read_reg(priv, 0x4B, &t); + if (ret != 0) + return -EIO; + + if (fake_signal_str) { + if ((t & 0xC0) == 0xC0) { + dprintk("Fake signal strength\n"); + *signal = 0x7FFF; + } else + *signal = 0; + return 0; + } + + dprintk("gi = %d\n", gi); + for (i = 0; i < gi; i++) { + + if ((i & 0xFF) == 0) + lgs8gxx_write_reg(priv, 0x84, 0x03 & (i >> 8)); + lgs8gxx_write_reg(priv, 0x83, i & 0xFF); + + lgs8gxx_read_reg(priv, 0x94, &str); + if (max_strength < str) + max_strength = str; + } + + *signal = max_strength; + dprintk("%s: signal=0x%02X\n", __func__, *signal); + + lgs8gxx_read_reg(priv, 0x95, &t); + dprintk("%s: AVG Noise=0x%02X\n", __func__, t); + + return 0; +} + +static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal) +{ + u8 t; + s16 v = 0; + + dprintk("%s\n", __func__); + + lgs8gxx_read_reg(priv, 0xB1, &t); + v |= t; + v <<= 8; + lgs8gxx_read_reg(priv, 0xB0, &t); + v |= t; + + *signal = v; + dprintk("%s: signal=0x%02X\n", __func__, *signal); + + return 0; +} + +static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal) +{ + struct lgs8gxx_state *priv = fe->demodulator_priv; + + if (priv->config->prod == LGS8GXX_PROD_LGS8913) + return lgs8913_read_signal_strength(priv, signal); + else if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + return lgs8g75_read_signal_strength(priv, signal); + else + return lgs8gxx_read_signal_agc(priv, signal); +} + +static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lgs8gxx_state *priv = fe->demodulator_priv; + u8 t; + *snr = 0; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + lgs8gxx_read_reg(priv, 0x34, &t); + else + lgs8gxx_read_reg(priv, 0x95, &t); + dprintk("AVG Noise=0x%02X\n", t); + *snr = 256 - t; + *snr <<= 8; + dprintk("snr=0x%x\n", *snr); + + return 0; +} + +static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks); + return 0; +} + +static void packet_counter_start(struct lgs8gxx_state *priv) +{ + u8 orig, t; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0x30, &orig); + orig &= 0xE7; + t = orig | 0x10; + lgs8gxx_write_reg(priv, 0x30, t); + t = orig | 0x18; + lgs8gxx_write_reg(priv, 0x30, t); + t = orig | 0x10; + lgs8gxx_write_reg(priv, 0x30, t); + } else { + lgs8gxx_write_reg(priv, 0xC6, 0x01); + lgs8gxx_write_reg(priv, 0xC6, 0x41); + lgs8gxx_write_reg(priv, 0xC6, 0x01); + } +} + +static void packet_counter_stop(struct lgs8gxx_state *priv) +{ + u8 t; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0x30, &t); + t &= 0xE7; + lgs8gxx_write_reg(priv, 0x30, t); + } else { + lgs8gxx_write_reg(priv, 0xC6, 0x81); + } +} + +static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct lgs8gxx_state *priv = fe->demodulator_priv; + u8 reg_err, reg_total, t; + u32 total_cnt = 0, err_cnt = 0; + int i; + + dprintk("%s\n", __func__); + + packet_counter_start(priv); + msleep(200); + packet_counter_stop(priv); + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + reg_total = 0x28; reg_err = 0x2C; + } else { + reg_total = 0xD0; reg_err = 0xD4; + } + + for (i = 0; i < 4; i++) { + total_cnt <<= 8; + lgs8gxx_read_reg(priv, reg_total+3-i, &t); + total_cnt |= t; + } + for (i = 0; i < 4; i++) { + err_cnt <<= 8; + lgs8gxx_read_reg(priv, reg_err+3-i, &t); + err_cnt |= t; + } + dprintk("error=%d total=%d\n", err_cnt, total_cnt); + + if (total_cnt == 0) + *ber = 0; + else + *ber = err_cnt * 100 / total_cnt; + + dprintk("%s: ber=0x%x\n", __func__, *ber); + return 0; +} + +static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct lgs8gxx_state *priv = fe->demodulator_priv; + + if (priv->config->tuner_address == 0) + return 0; + if (enable) { + u8 v = 0x80 | priv->config->tuner_address; + return lgs8gxx_write_reg(priv, 0x01, v); + } + return lgs8gxx_write_reg(priv, 0x01, 0); +} + +static struct dvb_frontend_ops lgs8gxx_ops = { + .info = { + .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH", + .type = FE_OFDM, + .frequency_min = 474000000, + .frequency_max = 858000000, + .frequency_stepsize = 10000, + .caps = + FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = lgs8gxx_release, + + .init = lgs8gxx_init, + .write = lgs8gxx_write, + .i2c_gate_ctrl = lgs8gxx_i2c_gate_ctrl, + + .set_frontend = lgs8gxx_set_fe, + .get_frontend = lgs8gxx_get_fe, + .get_tune_settings = lgs8gxx_get_tune_settings, + + .read_status = lgs8gxx_read_status, + .read_ber = lgs8gxx_read_ber, + .read_signal_strength = lgs8gxx_read_signal_strength, + .read_snr = lgs8gxx_read_snr, + .read_ucblocks = lgs8gxx_read_ucblocks, +}; + +struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, + struct i2c_adapter *i2c) +{ + struct lgs8gxx_state *priv = NULL; + u8 data = 0; + + dprintk("%s()\n", __func__); + + if (config == NULL || i2c == NULL) + return NULL; + + priv = kzalloc(sizeof(struct lgs8gxx_state), GFP_KERNEL); + if (priv == NULL) + goto error_out; + + priv->config = config; + priv->i2c = i2c; + + /* check if the demod is there */ + if (lgs8gxx_read_reg(priv, 0, &data) != 0) { + dprintk("%s lgs8gxx not found at i2c addr 0x%02X\n", + __func__, priv->config->demod_address); + goto error_out; + } + + lgs8gxx_read_reg(priv, 1, &data); + + memcpy(&priv->frontend.ops, &lgs8gxx_ops, + sizeof(struct dvb_frontend_ops)); + priv->frontend.demodulator_priv = priv; + + if (config->prod == LGS8GXX_PROD_LGS8G75) + lgs8g75_init_data(priv); + + return &priv->frontend; + +error_out: + dprintk("%s() error_out\n", __func__); + kfree(priv); + return NULL; + +} +EXPORT_SYMBOL(lgs8gxx_attach); + +MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver"); +MODULE_AUTHOR("David T. L. Wong "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator + * LGS8913, LGS8GL5, LGS8G75 + * experimental support LGS8G42, LGS8G52 + * + * Copyright (C) 2007-2009 David T.L. Wong + * Copyright (C) 2008 Sirius International (Hong Kong) Limited + * Timothy Lee (for initial work on LGS8GL5) + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LGS8GXX_H__ +#define __LGS8GXX_H__ + +#include +#include + +#define LGS8GXX_PROD_LGS8913 0 +#define LGS8GXX_PROD_LGS8GL5 1 +#define LGS8GXX_PROD_LGS8G42 3 +#define LGS8GXX_PROD_LGS8G52 4 +#define LGS8GXX_PROD_LGS8G54 5 +#define LGS8GXX_PROD_LGS8G75 6 + +struct lgs8gxx_config { + + /* product type */ + u8 prod; + + /* the demodulator's i2c address */ + u8 demod_address; + + /* parallel or serial transport stream */ + u8 serial_ts; + + /* transport stream polarity*/ + u8 ts_clk_pol; + + /* transport stream clock gated by ts_valid */ + u8 ts_clk_gated; + + /* A/D Clock frequency */ + u32 if_clk_freq; /* in kHz */ + + /* IF frequency */ + u32 if_freq; /* in kHz */ + + /*Use External ADC*/ + u8 ext_adc; + + /*External ADC output two's complement*/ + u8 adc_signed; + + /*Sample IF data at falling edge of IF_CLK*/ + u8 if_neg_edge; + + /*IF use Negative center frequency*/ + u8 if_neg_center; + + /*8G75 internal ADC input range selection*/ + /*0: 0.8Vpp, 1: 1.0Vpp, 2: 1.6Vpp, 3: 2.0Vpp*/ + u8 adc_vpp; + + /* slave address and configuration of the tuner */ + u8 tuner_address; +}; + +#if defined(CONFIG_DVB_LGS8GXX) || \ + (defined(CONFIG_DVB_LGS8GXX_MODULE) && defined(MODULE)) +extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, + struct i2c_adapter *i2c); +#else +static inline +struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, + struct i2c_adapter *i2c) { + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGS8GXX */ + +#endif /* __LGS8GXX_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,70 @@ +/* + * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator + * LGS8913, LGS8GL5, LGS8G75 + * experimental support LGS8G42, LGS8G52 + * + * Copyright (C) 2007-2009 David T.L. Wong + * Copyright (C) 2008 Sirius International (Hong Kong) Limited + * Timothy Lee (for initial work on LGS8GL5) + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef LGS8913_PRIV_H +#define LGS8913_PRIV_H + +struct lgs8gxx_state { + struct i2c_adapter *i2c; + /* configuration settings */ + const struct lgs8gxx_config *config; + struct dvb_frontend frontend; + u16 curr_gi; /* current guard interval */ +}; + +#define SC_MASK 0x1C /* Sub-Carrier Modulation Mask */ +#define SC_QAM64 0x10 /* 64QAM modulation */ +#define SC_QAM32 0x0C /* 32QAM modulation */ +#define SC_QAM16 0x08 /* 16QAM modulation */ +#define SC_QAM4NR 0x04 /* 4QAM-NR modulation */ +#define SC_QAM4 0x00 /* 4QAM modulation */ + +#define LGS_FEC_MASK 0x03 /* FEC Rate Mask */ +#define LGS_FEC_0_4 0x00 /* FEC Rate 0.4 */ +#define LGS_FEC_0_6 0x01 /* FEC Rate 0.6 */ +#define LGS_FEC_0_8 0x02 /* FEC Rate 0.8 */ + +#define TIM_MASK 0x20 /* Time Interleave Length Mask */ +#define TIM_LONG 0x20 /* Time Interleave Length = 720 */ +#define TIM_MIDDLE 0x00 /* Time Interleave Length = 240 */ + +#define CF_MASK 0x80 /* Control Frame Mask */ +#define CF_EN 0x80 /* Control Frame On */ + +#define GI_MASK 0x03 /* Guard Interval Mask */ +#define GI_420 0x00 /* 1/9 Guard Interval */ +#define GI_595 0x01 /* */ +#define GI_945 0x02 /* 1/4 Guard Interval */ + + +#define TS_PARALLEL 0x00 /* Parallel TS Output a.k.a. SPI */ +#define TS_SERIAL 0x01 /* Serial TS Output a.k.a. SSI */ +#define TS_CLK_NORMAL 0x00 /* MPEG Clock Normal */ +#define TS_CLK_INVERTED 0x02 /* MPEG Clock Inverted */ +#define TS_CLK_GATED 0x00 /* MPEG clock gated */ +#define TS_CLK_FREERUN 0x04 /* MPEG clock free running*/ + + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbh24.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbh24.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbh24.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbh24.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * lnbh24.h - driver for lnb supply and control ic lnbh24 + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LNBH24_H +#define _LNBH24_H + +/* system register bits */ +#define LNBH24_OLF 0x01 +#define LNBH24_OTF 0x02 +#define LNBH24_EN 0x04 +#define LNBH24_VSEL 0x08 +#define LNBH24_LLC 0x10 +#define LNBH24_TEN 0x20 +#define LNBH24_TTX 0x40 +#define LNBH24_PCL 0x80 + +#include + +#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \ + && defined(MODULE)) +/* override_set and override_clear control which + system register bits (above) to always set & clear */ +extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 override_set, + u8 override_clear, u8 i2c_addr); +#else +static inline struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 override_set, + u8 override_clear, u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbp21.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbp21.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbp21.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbp21.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,188 @@ +/* + * lnbp21.c - driver for lnb supply and control ic lnbp21 + * + * Copyright (C) 2006, 2009 Oliver Endriss + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "lnbp21.h" +#include "lnbh24.h" + +struct lnbp21 { + u8 config; + u8 override_or; + u8 override_and; + struct i2c_adapter *i2c; + u8 i2c_addr; +}; + +static int lnbp21_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; + struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, + .buf = &lnbp21->config, + .len = sizeof(lnbp21->config) }; + + lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN); + + switch(voltage) { + case SEC_VOLTAGE_OFF: + break; + case SEC_VOLTAGE_13: + lnbp21->config |= LNBP21_EN; + break; + case SEC_VOLTAGE_18: + lnbp21->config |= (LNBP21_EN | LNBP21_VSEL); + break; + default: + return -EINVAL; + }; + + lnbp21->config |= lnbp21->override_or; + lnbp21->config &= lnbp21->override_and; + + return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) +{ + struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; + struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, + .buf = &lnbp21->config, + .len = sizeof(lnbp21->config) }; + + if (arg) + lnbp21->config |= LNBP21_LLC; + else + lnbp21->config &= ~LNBP21_LLC; + + lnbp21->config |= lnbp21->override_or; + lnbp21->config &= lnbp21->override_and; + + return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static int lnbp21_set_tone(struct dvb_frontend *fe, + fe_sec_tone_mode_t tone) +{ + struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; + struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, + .buf = &lnbp21->config, + .len = sizeof(lnbp21->config) }; + + switch (tone) { + case SEC_TONE_OFF: + lnbp21->config &= ~LNBP21_TEN; + break; + case SEC_TONE_ON: + lnbp21->config |= LNBP21_TEN; + break; + default: + return -EINVAL; + }; + + lnbp21->config |= lnbp21->override_or; + lnbp21->config &= lnbp21->override_and; + + return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static void lnbp21_release(struct dvb_frontend *fe) +{ + /* LNBP power off */ + lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF); + + /* free data */ + kfree(fe->sec_priv); + fe->sec_priv = NULL; +} + +static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 override_set, + u8 override_clear, u8 i2c_addr, u8 config) +{ + struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL); + if (!lnbp21) + return NULL; + + /* default configuration */ + lnbp21->config = config; + lnbp21->i2c = i2c; + lnbp21->i2c_addr = i2c_addr; + fe->sec_priv = lnbp21; + + /* bits which should be forced to '1' */ + lnbp21->override_or = override_set; + + /* bits which should be forced to '0' */ + lnbp21->override_and = ~override_clear; + + /* detect if it is present or not */ + if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) { + kfree(lnbp21); + return NULL; + } + + /* install release callback */ + fe->ops.release_sec = lnbp21_release; + + /* override frontend ops */ + fe->ops.set_voltage = lnbp21_set_voltage; + fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; + if (!(override_clear & LNBH24_TEN)) /*22kHz logic controlled by demod*/ + fe->ops.set_tone = lnbp21_set_tone; + printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr); + + return fe; +} + +struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 override_set, + u8 override_clear, u8 i2c_addr) +{ + return lnbx2x_attach(fe, i2c, override_set, override_clear, + i2c_addr, LNBH24_TTX); +} +EXPORT_SYMBOL(lnbh24_attach); + +struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 override_set, + u8 override_clear) +{ + return lnbx2x_attach(fe, i2c, override_set, override_clear, + 0x08, LNBP21_ISEL); +} +EXPORT_SYMBOL(lnbp21_attach); + +MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24"); +MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbp21.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbp21.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbp21.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/lnbp21.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * lnbp21.h - driver for lnb supply and control ic lnbp21 + * + * Copyright (C) 2006 Oliver Endriss + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ + +#ifndef _LNBP21_H +#define _LNBP21_H + +/* system register bits */ +/* [RO] 0=OK; 1=over current limit flag */ +#define LNBP21_OLF 0x01 +/* [RO] 0=OK; 1=over temperature flag (150 C) */ +#define LNBP21_OTF 0x02 +/* [RW] 0=disable LNB power, enable loopthrough + 1=enable LNB power, disable loopthrough */ +#define LNBP21_EN 0x04 +/* [RW] 0=low voltage (13/14V, vert pol) + 1=high voltage (18/19V,horiz pol) */ +#define LNBP21_VSEL 0x08 +/* [RW] increase LNB voltage by 1V: + 0=13/18V; 1=14/19V */ +#define LNBP21_LLC 0x10 +/* [RW] 0=tone controlled by DSQIN pin + 1=tone enable, disable DSQIN */ +#define LNBP21_TEN 0x20 +/* [RW] current limit select: + 0:Iout=500-650mA Isc=300mA + 1:Iout=400-550mA Isc=200mA */ +#define LNBP21_ISEL 0x40 +/* [RW] short-circuit protect: + 0=pulsed (dynamic) curr limiting + 1=static curr limiting */ +#define LNBP21_PCL 0x80 + +#include + +#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \ + && defined(MODULE)) +/* override_set and override_clear control which + system register bits (above) to always set & clear */ +extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 override_set, + u8 override_clear); +#else +static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 override_set, + u8 override_clear) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,91 @@ +# +# Makefile for the kernel DVB frontend device drivers. +# + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ + +stb0899-objs = stb0899_drv.o stb0899_algo.o +stv0900-objs = stv0900_core.o stv0900_sw.o +au8522-objs = au8522_dig.o au8522_decoder.o +drxd-objs = drxd_firm.o drxd_hard.o +cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o + +obj-$(CONFIG_DVB_PLL) += dvb-pll.o +obj-$(CONFIG_DVB_STV0299) += stv0299.o +obj-$(CONFIG_DVB_STB0899) += stb0899.o +obj-$(CONFIG_DVB_STB6100) += stb6100.o +obj-$(CONFIG_DVB_SP8870) += sp8870.o +obj-$(CONFIG_DVB_CX22700) += cx22700.o +obj-$(CONFIG_DVB_S5H1432) += s5h1432.o +obj-$(CONFIG_DVB_CX24110) += cx24110.o +obj-$(CONFIG_DVB_TDA8083) += tda8083.o +obj-$(CONFIG_DVB_L64781) += l64781.o +obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o +obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o +obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o +obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o +obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o +obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o +obj-$(CONFIG_DVB_MT312) += mt312.o +obj-$(CONFIG_DVB_VES1820) += ves1820.o +obj-$(CONFIG_DVB_VES1X93) += ves1x93.o +obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o +obj-$(CONFIG_DVB_SP887X) += sp887x.o +obj-$(CONFIG_DVB_NXT6000) += nxt6000.o +obj-$(CONFIG_DVB_MT352) += mt352.o +obj-$(CONFIG_DVB_ZL10036) += zl10036.o +obj-$(CONFIG_DVB_ZL10039) += zl10039.o +obj-$(CONFIG_DVB_ZL10353) += zl10353.o +obj-$(CONFIG_DVB_CX22702) += cx22702.o +obj-$(CONFIG_DVB_DRXD) += drxd.o +obj-$(CONFIG_DVB_TDA10021) += tda10021.o +obj-$(CONFIG_DVB_TDA10023) += tda10023.o +obj-$(CONFIG_DVB_STV0297) += stv0297.o +obj-$(CONFIG_DVB_NXT200X) += nxt200x.o +obj-$(CONFIG_DVB_OR51211) += or51211.o +obj-$(CONFIG_DVB_OR51132) += or51132.o +obj-$(CONFIG_DVB_BCM3510) += bcm3510.o +obj-$(CONFIG_DVB_S5H1420) += s5h1420.o +obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o +obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o +obj-$(CONFIG_DVB_CX24123) += cx24123.o +obj-$(CONFIG_DVB_LNBP21) += lnbp21.o +obj-$(CONFIG_DVB_ISL6405) += isl6405.o +obj-$(CONFIG_DVB_ISL6421) += isl6421.o +obj-$(CONFIG_DVB_TDA10086) += tda10086.o +obj-$(CONFIG_DVB_TDA826X) += tda826x.o +obj-$(CONFIG_DVB_TDA8261) += tda8261.o +obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o +obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o +obj-$(CONFIG_DVB_TUA6100) += tua6100.o +obj-$(CONFIG_DVB_S5H1409) += s5h1409.o +obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o +obj-$(CONFIG_DVB_AU8522) += au8522.o +obj-$(CONFIG_DVB_TDA10048) += tda10048.o +obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o +obj-$(CONFIG_DVB_S5H1411) += s5h1411.o +obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o +obj-$(CONFIG_DVB_TDA665x) += tda665x.o +obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o +obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o +obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o +obj-$(CONFIG_DVB_AF9013) += af9013.o +obj-$(CONFIG_DVB_CX24116) += cx24116.o +obj-$(CONFIG_DVB_SI21XX) += si21xx.o +obj-$(CONFIG_DVB_STV0288) += stv0288.o +obj-$(CONFIG_DVB_STB6000) += stb6000.o +obj-$(CONFIG_DVB_S921) += s921.o +obj-$(CONFIG_DVB_STV6110) += stv6110.o +obj-$(CONFIG_DVB_STV0900) += stv0900.o +obj-$(CONFIG_DVB_STV090x) += stv090x.o +obj-$(CONFIG_DVB_STV6110x) += stv6110x.o +obj-$(CONFIG_DVB_ISL6423) += isl6423.o +obj-$(CONFIG_DVB_EC100) += ec100.o +obj-$(CONFIG_DVB_DS3000) += ds3000.o +obj-$(CONFIG_DVB_MB86A16) += mb86a16.o +obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o +obj-$(CONFIG_DVB_IX2505V) += ix2505v.o +obj-$(CONFIG_DVB_STV0367) += stv0367.o +obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1878 @@ +/* + Fujitsu MB86A16 DVB-S/DSS DC Receiver driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "mb86a16.h" +#include "mb86a16_priv.h" + +unsigned int verbose = 5; +module_param(verbose, int, 0644); + +#define ABS(x) ((x) < 0 ? (-x) : (x)) + +struct mb86a16_state { + struct i2c_adapter *i2c_adap; + const struct mb86a16_config *config; + struct dvb_frontend frontend; + + /* tuning parameters */ + int frequency; + int srate; + + /* Internal stuff */ + int master_clk; + int deci; + int csel; + int rsel; +}; + +#define MB86A16_ERROR 0 +#define MB86A16_NOTICE 1 +#define MB86A16_INFO 2 +#define MB86A16_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > MB86A16_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__, ##arg); \ + else if ((x > MB86A16_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__, ##arg); \ + else if ((x > MB86A16_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__, ##arg); \ + else if ((x > MB86A16_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__, ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ +} while (0) + +#define TRACE_IN dprintk(verbose, MB86A16_DEBUG, 1, "-->()") +#define TRACE_OUT dprintk(verbose, MB86A16_DEBUG, 1, "()-->") + +static int mb86a16_write(struct mb86a16_state *state, u8 reg, u8 val) +{ + int ret; + u8 buf[] = { reg, val }; + + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + dprintk(verbose, MB86A16_DEBUG, 1, + "writing to [0x%02x],Reg[0x%02x],Data[0x%02x]", + state->config->demod_address, buf[0], buf[1]); + + ret = i2c_transfer(state->i2c_adap, &msg, 1); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 1 + }, { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + ret = i2c_transfer(state->i2c_adap, msg, 2); + if (ret != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)", + reg, ret); + + return -EREMOTEIO; + } + *val = b1[0]; + + return ret; +} + +static int CNTM_set(struct mb86a16_state *state, + unsigned char timint1, + unsigned char timint2, + unsigned char cnext) +{ + unsigned char val; + + val = (timint1 << 4) | (timint2 << 2) | cnext; + if (mb86a16_write(state, MB86A16_CNTMR, val) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int smrt_set(struct mb86a16_state *state, int rate) +{ + int tmp ; + int m ; + unsigned char STOFS0, STOFS1; + + m = 1 << state->deci; + tmp = (8192 * state->master_clk - 2 * m * rate * 8192 + state->master_clk / 2) / state->master_clk; + + STOFS0 = tmp & 0x0ff; + STOFS1 = (tmp & 0xf00) >> 8; + + if (mb86a16_write(state, MB86A16_SRATE1, (state->deci << 2) | + (state->csel << 1) | + state->rsel) < 0) + goto err; + if (mb86a16_write(state, MB86A16_SRATE2, STOFS0) < 0) + goto err; + if (mb86a16_write(state, MB86A16_SRATE3, STOFS1) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -1; +} + +static int srst(struct mb86a16_state *state) +{ + if (mb86a16_write(state, MB86A16_RESET, 0x04) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + +} + +static int afcex_data_set(struct mb86a16_state *state, + unsigned char AFCEX_L, + unsigned char AFCEX_H) +{ + if (mb86a16_write(state, MB86A16_AFCEXL, AFCEX_L) < 0) + goto err; + if (mb86a16_write(state, MB86A16_AFCEXH, AFCEX_H) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + + return -1; +} + +static int afcofs_data_set(struct mb86a16_state *state, + unsigned char AFCEX_L, + unsigned char AFCEX_H) +{ + if (mb86a16_write(state, 0x58, AFCEX_L) < 0) + goto err; + if (mb86a16_write(state, 0x59, AFCEX_H) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int stlp_set(struct mb86a16_state *state, + unsigned char STRAS, + unsigned char STRBS) +{ + if (mb86a16_write(state, MB86A16_STRFILTCOEF1, (STRBS << 3) | (STRAS)) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int Vi_set(struct mb86a16_state *state, unsigned char ETH, unsigned char VIA) +{ + if (mb86a16_write(state, MB86A16_VISET2, 0x04) < 0) + goto err; + if (mb86a16_write(state, MB86A16_VISET3, 0xf5) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int initial_set(struct mb86a16_state *state) +{ + if (stlp_set(state, 5, 7)) + goto err; + + udelay(100); + if (afcex_data_set(state, 0, 0)) + goto err; + + udelay(100); + if (afcofs_data_set(state, 0, 0)) + goto err; + + udelay(100); + if (mb86a16_write(state, MB86A16_CRLFILTCOEF1, 0x16) < 0) + goto err; + if (mb86a16_write(state, 0x2f, 0x21) < 0) + goto err; + if (mb86a16_write(state, MB86A16_VIMAG, 0x38) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS1, 0x00) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS2, 0x1c) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS3, 0x20) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS4, 0x1e) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS5, 0x23) < 0) + goto err; + if (mb86a16_write(state, 0x54, 0xff) < 0) + goto err; + if (mb86a16_write(state, MB86A16_TSOUT, 0x00) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int S01T_set(struct mb86a16_state *state, + unsigned char s1t, + unsigned s0t) +{ + if (mb86a16_write(state, 0x33, (s1t << 3) | s0t) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + + +static int EN_set(struct mb86a16_state *state, + int cren, + int afcen) +{ + unsigned char val; + + val = 0x7a | (cren << 7) | (afcen << 2); + if (mb86a16_write(state, 0x49, val) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int AFCEXEN_set(struct mb86a16_state *state, + int afcexen, + int smrt) +{ + unsigned char AFCA ; + + if (smrt > 18875) + AFCA = 4; + else if (smrt > 9375) + AFCA = 3; + else if (smrt > 2250) + AFCA = 2; + else + AFCA = 1; + + if (mb86a16_write(state, 0x2a, 0x02 | (afcexen << 5) | (AFCA << 2)) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int DAGC_data_set(struct mb86a16_state *state, + unsigned char DAGCA, + unsigned char DAGCW) +{ + if (mb86a16_write(state, 0x2d, (DAGCA << 3) | DAGCW) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static void smrt_info_get(struct mb86a16_state *state, int rate) +{ + if (rate >= 37501) { + state->deci = 0; state->csel = 0; state->rsel = 0; + } else if (rate >= 30001) { + state->deci = 0; state->csel = 0; state->rsel = 1; + } else if (rate >= 26251) { + state->deci = 0; state->csel = 1; state->rsel = 0; + } else if (rate >= 22501) { + state->deci = 0; state->csel = 1; state->rsel = 1; + } else if (rate >= 18751) { + state->deci = 1; state->csel = 0; state->rsel = 0; + } else if (rate >= 15001) { + state->deci = 1; state->csel = 0; state->rsel = 1; + } else if (rate >= 13126) { + state->deci = 1; state->csel = 1; state->rsel = 0; + } else if (rate >= 11251) { + state->deci = 1; state->csel = 1; state->rsel = 1; + } else if (rate >= 9376) { + state->deci = 2; state->csel = 0; state->rsel = 0; + } else if (rate >= 7501) { + state->deci = 2; state->csel = 0; state->rsel = 1; + } else if (rate >= 6563) { + state->deci = 2; state->csel = 1; state->rsel = 0; + } else if (rate >= 5626) { + state->deci = 2; state->csel = 1; state->rsel = 1; + } else if (rate >= 4688) { + state->deci = 3; state->csel = 0; state->rsel = 0; + } else if (rate >= 3751) { + state->deci = 3; state->csel = 0; state->rsel = 1; + } else if (rate >= 3282) { + state->deci = 3; state->csel = 1; state->rsel = 0; + } else if (rate >= 2814) { + state->deci = 3; state->csel = 1; state->rsel = 1; + } else if (rate >= 2344) { + state->deci = 4; state->csel = 0; state->rsel = 0; + } else if (rate >= 1876) { + state->deci = 4; state->csel = 0; state->rsel = 1; + } else if (rate >= 1641) { + state->deci = 4; state->csel = 1; state->rsel = 0; + } else if (rate >= 1407) { + state->deci = 4; state->csel = 1; state->rsel = 1; + } else if (rate >= 1172) { + state->deci = 5; state->csel = 0; state->rsel = 0; + } else if (rate >= 939) { + state->deci = 5; state->csel = 0; state->rsel = 1; + } else if (rate >= 821) { + state->deci = 5; state->csel = 1; state->rsel = 0; + } else { + state->deci = 5; state->csel = 1; state->rsel = 1; + } + + if (state->csel == 0) + state->master_clk = 92000; + else + state->master_clk = 61333; + +} + +static int signal_det(struct mb86a16_state *state, + int smrt, + unsigned char *SIG) +{ + + int ret ; + int smrtd ; + int wait_sym ; + + u32 wait_t; + unsigned char S[3] ; + int i ; + + if (*SIG > 45) { + if (CNTM_set(state, 2, 1, 2) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); + return -1; + } + wait_sym = 40000; + } else { + if (CNTM_set(state, 3, 1, 2) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); + return -1; + } + wait_sym = 80000; + } + for (i = 0; i < 3; i++) { + if (i == 0) + smrtd = smrt * 98 / 100; + else if (i == 1) + smrtd = smrt; + else + smrtd = smrt * 102 / 100; + smrt_info_get(state, smrtd); + smrt_set(state, smrtd); + srst(state); + wait_t = (wait_sym + 99 * smrtd / 100) / smrtd; + if (wait_t == 0) + wait_t = 1; + msleep_interruptible(10); + if (mb86a16_read(state, 0x37, &(S[i])) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + } + if ((S[1] > S[0] * 112 / 100) && + (S[1] > S[2] * 112 / 100)) { + + ret = 1; + } else { + ret = 0; + } + *SIG = S[1]; + + if (CNTM_set(state, 0, 1, 2) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); + return -1; + } + + return ret; +} + +static int rf_val_set(struct mb86a16_state *state, + int f, + int smrt, + unsigned char R) +{ + unsigned char C, F, B; + int M; + unsigned char rf_val[5]; + int ack = -1; + + if (smrt > 37750) + C = 1; + else if (smrt > 18875) + C = 2; + else if (smrt > 5500) + C = 3; + else + C = 4; + + if (smrt > 30500) + F = 3; + else if (smrt > 9375) + F = 1; + else if (smrt > 4625) + F = 0; + else + F = 2; + + if (f < 1060) + B = 0; + else if (f < 1175) + B = 1; + else if (f < 1305) + B = 2; + else if (f < 1435) + B = 3; + else if (f < 1570) + B = 4; + else if (f < 1715) + B = 5; + else if (f < 1845) + B = 6; + else if (f < 1980) + B = 7; + else if (f < 2080) + B = 8; + else + B = 9; + + M = f * (1 << R) / 2; + + rf_val[0] = 0x01 | (C << 3) | (F << 1); + rf_val[1] = (R << 5) | ((M & 0x1f000) >> 12); + rf_val[2] = (M & 0x00ff0) >> 4; + rf_val[3] = ((M & 0x0000f) << 4) | B; + + /* Frequency Set */ + if (mb86a16_write(state, 0x21, rf_val[0]) < 0) + ack = 0; + if (mb86a16_write(state, 0x22, rf_val[1]) < 0) + ack = 0; + if (mb86a16_write(state, 0x23, rf_val[2]) < 0) + ack = 0; + if (mb86a16_write(state, 0x24, rf_val[3]) < 0) + ack = 0; + if (mb86a16_write(state, 0x25, 0x01) < 0) + ack = 0; + if (ack == 0) { + dprintk(verbose, MB86A16_ERROR, 1, "RF Setup - I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int afcerr_chk(struct mb86a16_state *state) +{ + unsigned char AFCM_L, AFCM_H ; + int AFCM ; + int afcm, afcerr ; + + if (mb86a16_read(state, 0x0e, &AFCM_L) != 2) + goto err; + if (mb86a16_read(state, 0x0f, &AFCM_H) != 2) + goto err; + + AFCM = (AFCM_H << 8) + AFCM_L; + + if (AFCM > 2048) + afcm = AFCM - 4096; + else + afcm = AFCM; + afcerr = afcm * state->master_clk / 8192; + + return afcerr; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int dagcm_val_get(struct mb86a16_state *state) +{ + int DAGCM; + unsigned char DAGCM_H, DAGCM_L; + + if (mb86a16_read(state, 0x45, &DAGCM_L) != 2) + goto err; + if (mb86a16_read(state, 0x46, &DAGCM_H) != 2) + goto err; + + DAGCM = (DAGCM_H << 8) + DAGCM_L; + + return DAGCM; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + u8 stat, stat2; + struct mb86a16_state *state = fe->demodulator_priv; + + *status = 0; + + if (mb86a16_read(state, MB86A16_SIG1, &stat) != 2) + goto err; + if (mb86a16_read(state, MB86A16_SIG2, &stat2) != 2) + goto err; + if ((stat > 25) && (stat2 > 25)) + *status |= FE_HAS_SIGNAL; + if ((stat > 45) && (stat2 > 45)) + *status |= FE_HAS_CARRIER; + + if (mb86a16_read(state, MB86A16_STATUS, &stat) != 2) + goto err; + + if (stat & 0x01) + *status |= FE_HAS_SYNC; + if (stat & 0x01) + *status |= FE_HAS_VITERBI; + + if (mb86a16_read(state, MB86A16_FRAMESYNC, &stat) != 2) + goto err; + + if ((stat & 0x0f) && (*status & FE_HAS_VITERBI)) + *status |= FE_HAS_LOCK; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int sync_chk(struct mb86a16_state *state, + unsigned char *VIRM) +{ + unsigned char val; + int sync; + + if (mb86a16_read(state, 0x0d, &val) != 2) + goto err; + + dprintk(verbose, MB86A16_INFO, 1, "Status = %02x,", val); + sync = val & 0x01; + *VIRM = (val & 0x1c) >> 2; + + return sync; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + +} + +static int freqerr_chk(struct mb86a16_state *state, + int fTP, + int smrt, + int unit) +{ + unsigned char CRM, AFCML, AFCMH; + unsigned char temp1, temp2, temp3; + int crm, afcm, AFCM; + int crrerr, afcerr; /* kHz */ + int frqerr; /* MHz */ + int afcen, afcexen = 0; + int R, M, fOSC, fOSC_OFS; + + if (mb86a16_read(state, 0x43, &CRM) != 2) + goto err; + + if (CRM > 127) + crm = CRM - 256; + else + crm = CRM; + + crrerr = smrt * crm / 256; + if (mb86a16_read(state, 0x49, &temp1) != 2) + goto err; + + afcen = (temp1 & 0x04) >> 2; + if (afcen == 0) { + if (mb86a16_read(state, 0x2a, &temp1) != 2) + goto err; + afcexen = (temp1 & 0x20) >> 5; + } + + if (afcen == 1) { + if (mb86a16_read(state, 0x0e, &AFCML) != 2) + goto err; + if (mb86a16_read(state, 0x0f, &AFCMH) != 2) + goto err; + } else if (afcexen == 1) { + if (mb86a16_read(state, 0x2b, &AFCML) != 2) + goto err; + if (mb86a16_read(state, 0x2c, &AFCMH) != 2) + goto err; + } + if ((afcen == 1) || (afcexen == 1)) { + smrt_info_get(state, smrt); + AFCM = ((AFCMH & 0x01) << 8) + AFCML; + if (AFCM > 255) + afcm = AFCM - 512; + else + afcm = AFCM; + + afcerr = afcm * state->master_clk / 8192; + } else + afcerr = 0; + + if (mb86a16_read(state, 0x22, &temp1) != 2) + goto err; + if (mb86a16_read(state, 0x23, &temp2) != 2) + goto err; + if (mb86a16_read(state, 0x24, &temp3) != 2) + goto err; + + R = (temp1 & 0xe0) >> 5; + M = ((temp1 & 0x1f) << 12) + (temp2 << 4) + (temp3 >> 4); + if (R == 0) + fOSC = 2 * M; + else + fOSC = M; + + fOSC_OFS = fOSC - fTP; + + if (unit == 0) { /* MHz */ + if (crrerr + afcerr + fOSC_OFS * 1000 >= 0) + frqerr = (crrerr + afcerr + fOSC_OFS * 1000 + 500) / 1000; + else + frqerr = (crrerr + afcerr + fOSC_OFS * 1000 - 500) / 1000; + } else { /* kHz */ + frqerr = crrerr + afcerr + fOSC_OFS * 1000; + } + + return frqerr; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static unsigned char vco_dev_get(struct mb86a16_state *state, int smrt) +{ + unsigned char R; + + if (smrt > 9375) + R = 0; + else + R = 1; + + return R; +} + +static void swp_info_get(struct mb86a16_state *state, + int fOSC_start, + int smrt, + int v, int R, + int swp_ofs, + int *fOSC, + int *afcex_freq, + unsigned char *AFCEX_L, + unsigned char *AFCEX_H) +{ + int AFCEX ; + int crnt_swp_freq ; + + crnt_swp_freq = fOSC_start * 1000 + v * swp_ofs; + + if (R == 0) + *fOSC = (crnt_swp_freq + 1000) / 2000 * 2; + else + *fOSC = (crnt_swp_freq + 500) / 1000; + + if (*fOSC >= crnt_swp_freq) + *afcex_freq = *fOSC * 1000 - crnt_swp_freq; + else + *afcex_freq = crnt_swp_freq - *fOSC * 1000; + + AFCEX = *afcex_freq * 8192 / state->master_clk; + *AFCEX_L = AFCEX & 0x00ff; + *AFCEX_H = (AFCEX & 0x0f00) >> 8; +} + + +static int swp_freq_calcuation(struct mb86a16_state *state, int i, int v, int *V, int vmax, int vmin, + int SIGMIN, int fOSC, int afcex_freq, int swp_ofs, unsigned char *SIG1) +{ + int swp_freq ; + + if ((i % 2 == 1) && (v <= vmax)) { + /* positive v (case 1) */ + if ((v - 1 == vmin) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v - 1) >= 0) && + (*(V + 30 + v - 1) > *(V + 30 + v)) && + (*(V + 30 + v - 1) > SIGMIN)) { + + swp_freq = fOSC * 1000 + afcex_freq - swp_ofs; + *SIG1 = *(V + 30 + v - 1); + } else if ((v == vmax) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v - 1) >= 0) && + (*(V + 30 + v) > *(V + 30 + v - 1)) && + (*(V + 30 + v) > SIGMIN)) { + /* (case 2) */ + swp_freq = fOSC * 1000 + afcex_freq; + *SIG1 = *(V + 30 + v); + } else if ((*(V + 30 + v) > 0) && + (*(V + 30 + v - 1) > 0) && + (*(V + 30 + v - 2) > 0) && + (*(V + 30 + v - 3) > 0) && + (*(V + 30 + v - 1) > *(V + 30 + v)) && + (*(V + 30 + v - 2) > *(V + 30 + v - 3)) && + ((*(V + 30 + v - 1) > SIGMIN) || + (*(V + 30 + v - 2) > SIGMIN))) { + /* (case 3) */ + if (*(V + 30 + v - 1) >= *(V + 30 + v - 2)) { + swp_freq = fOSC * 1000 + afcex_freq - swp_ofs; + *SIG1 = *(V + 30 + v - 1); + } else { + swp_freq = fOSC * 1000 + afcex_freq - swp_ofs * 2; + *SIG1 = *(V + 30 + v - 2); + } + } else if ((v == vmax) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v - 1) >= 0) && + (*(V + 30 + v - 2) >= 0) && + (*(V + 30 + v) > *(V + 30 + v - 2)) && + (*(V + 30 + v - 1) > *(V + 30 + v - 2)) && + ((*(V + 30 + v) > SIGMIN) || + (*(V + 30 + v - 1) > SIGMIN))) { + /* (case 4) */ + if (*(V + 30 + v) >= *(V + 30 + v - 1)) { + swp_freq = fOSC * 1000 + afcex_freq; + *SIG1 = *(V + 30 + v); + } else { + swp_freq = fOSC * 1000 + afcex_freq - swp_ofs; + *SIG1 = *(V + 30 + v - 1); + } + } else { + swp_freq = -1 ; + } + } else if ((i % 2 == 0) && (v >= vmin)) { + /* Negative v (case 1) */ + if ((*(V + 30 + v) > 0) && + (*(V + 30 + v + 1) > 0) && + (*(V + 30 + v + 2) > 0) && + (*(V + 30 + v + 1) > *(V + 30 + v)) && + (*(V + 30 + v + 1) > *(V + 30 + v + 2)) && + (*(V + 30 + v + 1) > SIGMIN)) { + + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v + 1); + } else if ((v + 1 == vmax) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v + 1) >= 0) && + (*(V + 30 + v + 1) > *(V + 30 + v)) && + (*(V + 30 + v + 1) > SIGMIN)) { + /* (case 2) */ + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v); + } else if ((v == vmin) && + (*(V + 30 + v) > 0) && + (*(V + 30 + v + 1) > 0) && + (*(V + 30 + v + 2) > 0) && + (*(V + 30 + v) > *(V + 30 + v + 1)) && + (*(V + 30 + v) > *(V + 30 + v + 2)) && + (*(V + 30 + v) > SIGMIN)) { + /* (case 3) */ + swp_freq = fOSC * 1000 + afcex_freq; + *SIG1 = *(V + 30 + v); + } else if ((*(V + 30 + v) >= 0) && + (*(V + 30 + v + 1) >= 0) && + (*(V + 30 + v + 2) >= 0) && + (*(V + 30 + v + 3) >= 0) && + (*(V + 30 + v + 1) > *(V + 30 + v)) && + (*(V + 30 + v + 2) > *(V + 30 + v + 3)) && + ((*(V + 30 + v + 1) > SIGMIN) || + (*(V + 30 + v + 2) > SIGMIN))) { + /* (case 4) */ + if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v + 1); + } else { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2; + *SIG1 = *(V + 30 + v + 2); + } + } else if ((*(V + 30 + v) >= 0) && + (*(V + 30 + v + 1) >= 0) && + (*(V + 30 + v + 2) >= 0) && + (*(V + 30 + v + 3) >= 0) && + (*(V + 30 + v) > *(V + 30 + v + 2)) && + (*(V + 30 + v + 1) > *(V + 30 + v + 2)) && + (*(V + 30 + v) > *(V + 30 + v + 3)) && + (*(V + 30 + v + 1) > *(V + 30 + v + 3)) && + ((*(V + 30 + v) > SIGMIN) || + (*(V + 30 + v + 1) > SIGMIN))) { + /* (case 5) */ + if (*(V + 30 + v) >= *(V + 30 + v + 1)) { + swp_freq = fOSC * 1000 + afcex_freq; + *SIG1 = *(V + 30 + v); + } else { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v + 1); + } + } else if ((v + 2 == vmin) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v + 1) >= 0) && + (*(V + 30 + v + 2) >= 0) && + (*(V + 30 + v + 1) > *(V + 30 + v)) && + (*(V + 30 + v + 2) > *(V + 30 + v)) && + ((*(V + 30 + v + 1) > SIGMIN) || + (*(V + 30 + v + 2) > SIGMIN))) { + /* (case 6) */ + if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v + 1); + } else { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2; + *SIG1 = *(V + 30 + v + 2); + } + } else if ((vmax == 0) && (vmin == 0) && (*(V + 30 + v) > SIGMIN)) { + swp_freq = fOSC * 1000; + *SIG1 = *(V + 30 + v); + } else + swp_freq = -1; + } else + swp_freq = -1; + + return swp_freq; +} + +static void swp_info_get2(struct mb86a16_state *state, + int smrt, + int R, + int swp_freq, + int *afcex_freq, + int *fOSC, + unsigned char *AFCEX_L, + unsigned char *AFCEX_H) +{ + int AFCEX ; + + if (R == 0) + *fOSC = (swp_freq + 1000) / 2000 * 2; + else + *fOSC = (swp_freq + 500) / 1000; + + if (*fOSC >= swp_freq) + *afcex_freq = *fOSC * 1000 - swp_freq; + else + *afcex_freq = swp_freq - *fOSC * 1000; + + AFCEX = *afcex_freq * 8192 / state->master_clk; + *AFCEX_L = AFCEX & 0x00ff; + *AFCEX_H = (AFCEX & 0x0f00) >> 8; +} + +static void afcex_info_get(struct mb86a16_state *state, + int afcex_freq, + unsigned char *AFCEX_L, + unsigned char *AFCEX_H) +{ + int AFCEX ; + + AFCEX = afcex_freq * 8192 / state->master_clk; + *AFCEX_L = AFCEX & 0x00ff; + *AFCEX_H = (AFCEX & 0x0f00) >> 8; +} + +static int SEQ_set(struct mb86a16_state *state, unsigned char loop) +{ + /* SLOCK0 = 0 */ + if (mb86a16_write(state, 0x32, 0x02 | (loop << 2)) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int iq_vt_set(struct mb86a16_state *state, unsigned char IQINV) +{ + /* Viterbi Rate, IQ Settings */ + if (mb86a16_write(state, 0x06, 0xdf | (IQINV << 5)) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int FEC_srst(struct mb86a16_state *state) +{ + if (mb86a16_write(state, MB86A16_RESET, 0x02) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int S2T_set(struct mb86a16_state *state, unsigned char S2T) +{ + if (mb86a16_write(state, 0x34, 0x70 | S2T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int S45T_set(struct mb86a16_state *state, unsigned char S4T, unsigned char S5T) +{ + if (mb86a16_write(state, 0x35, 0x00 | (S5T << 4) | S4T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + + +static int mb86a16_set_fe(struct mb86a16_state *state) +{ + u8 agcval, cnmval; + + int i, j; + int fOSC = 0; + int fOSC_start = 0; + int wait_t; + int fcp; + int swp_ofs; + int V[60]; + u8 SIG1MIN; + + unsigned char CREN, AFCEN, AFCEXEN; + unsigned char SIG1; + unsigned char TIMINT1, TIMINT2, TIMEXT; + unsigned char S0T, S1T; + unsigned char S2T; +/* unsigned char S2T, S3T; */ + unsigned char S4T, S5T; + unsigned char AFCEX_L, AFCEX_H; + unsigned char R; + unsigned char VIRM; + unsigned char ETH, VIA; + unsigned char junk; + + int loop; + int ftemp; + int v, vmax, vmin; + int vmax_his, vmin_his; + int swp_freq, prev_swp_freq[20]; + int prev_freq_num; + int signal_dupl; + int afcex_freq; + int signal; + int afcerr; + int temp_freq, delta_freq; + int dagcm[4]; + int smrt_d; +/* int freq_err; */ + int n; + int ret = -1; + int sync; + + dprintk(verbose, MB86A16_INFO, 1, "freq=%d Mhz, symbrt=%d Ksps", state->frequency, state->srate); + + fcp = 3000; + swp_ofs = state->srate / 4; + + for (i = 0; i < 60; i++) + V[i] = -1; + + for (i = 0; i < 20; i++) + prev_swp_freq[i] = 0; + + SIG1MIN = 25; + + for (n = 0; ((n < 3) && (ret == -1)); n++) { + SEQ_set(state, 0); + iq_vt_set(state, 0); + + CREN = 0; + AFCEN = 0; + AFCEXEN = 1; + TIMINT1 = 0; + TIMINT2 = 1; + TIMEXT = 2; + S1T = 0; + S0T = 0; + + if (initial_set(state) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "initial set failed"); + return -1; + } + if (DAGC_data_set(state, 3, 2) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error"); + return -1; + } + if (EN_set(state, CREN, AFCEN) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "EN set error"); + return -1; /* (0, 0) */ + } + if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); + return -1; /* (1, smrt) = (1, symbolrate) */ + } + if (CNTM_set(state, TIMINT1, TIMINT2, TIMEXT) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "CNTM set error"); + return -1; /* (0, 1, 2) */ + } + if (S01T_set(state, S1T, S0T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "S01T set error"); + return -1; /* (0, 0) */ + } + smrt_info_get(state, state->srate); + if (smrt_set(state, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt info get error"); + return -1; + } + + R = vco_dev_get(state, state->srate); + if (R == 1) + fOSC_start = state->frequency; + + else if (R == 0) { + if (state->frequency % 2 == 0) { + fOSC_start = state->frequency; + } else { + fOSC_start = state->frequency + 1; + if (fOSC_start > 2150) + fOSC_start = state->frequency - 1; + } + } + loop = 1; + ftemp = fOSC_start * 1000; + vmax = 0 ; + while (loop == 1) { + ftemp = ftemp + swp_ofs; + vmax++; + + /* Upper bound */ + if (ftemp > 2150000) { + loop = 0; + vmax--; + } else { + if ((ftemp == 2150000) || + (ftemp - state->frequency * 1000 >= fcp + state->srate / 4)) + loop = 0; + } + } + + loop = 1; + ftemp = fOSC_start * 1000; + vmin = 0 ; + while (loop == 1) { + ftemp = ftemp - swp_ofs; + vmin--; + + /* Lower bound */ + if (ftemp < 950000) { + loop = 0; + vmin++; + } else { + if ((ftemp == 950000) || + (state->frequency * 1000 - ftemp >= fcp + state->srate / 4)) + loop = 0; + } + } + + wait_t = (8000 + state->srate / 2) / state->srate; + if (wait_t == 0) + wait_t = 1; + + i = 0; + j = 0; + prev_freq_num = 0; + loop = 1; + signal = 0; + vmax_his = 0; + vmin_his = 0; + v = 0; + + while (loop == 1) { + swp_info_get(state, fOSC_start, state->srate, + v, R, swp_ofs, &fOSC, + &afcex_freq, &AFCEX_L, &AFCEX_H); + + udelay(100); + if (rf_val_set(state, fOSC, state->srate, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + udelay(100); + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); + return -1; + } + if (srst(state) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "srst error"); + return -1; + } + msleep_interruptible(wait_t); + + if (mb86a16_read(state, 0x37, &SIG1) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -1; + } + V[30 + v] = SIG1 ; + swp_freq = swp_freq_calcuation(state, i, v, V, vmax, vmin, + SIG1MIN, fOSC, afcex_freq, + swp_ofs, &SIG1); /* changed */ + + signal_dupl = 0; + for (j = 0; j < prev_freq_num; j++) { + if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) { + signal_dupl = 1; + dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j); + } + } + if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) { + dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate); + prev_swp_freq[prev_freq_num] = swp_freq; + prev_freq_num++; + swp_info_get2(state, state->srate, R, swp_freq, + &afcex_freq, &fOSC, + &AFCEX_L, &AFCEX_H); + + if (rf_val_set(state, fOSC, state->srate, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); + return -1; + } + signal = signal_det(state, state->srate, &SIG1); + if (signal == 1) { + dprintk(verbose, MB86A16_ERROR, 1, "***** Signal Found *****"); + loop = 0; + } else { + dprintk(verbose, MB86A16_ERROR, 1, "!!!!! No signal !!!!!, try again..."); + smrt_info_get(state, state->srate); + if (smrt_set(state, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); + return -1; + } + } + } + if (v > vmax) + vmax_his = 1 ; + if (v < vmin) + vmin_his = 1 ; + i++; + + if ((i % 2 == 1) && (vmax_his == 1)) + i++; + if ((i % 2 == 0) && (vmin_his == 1)) + i++; + + if (i % 2 == 1) + v = (i + 1) / 2; + else + v = -i / 2; + + if ((vmax_his == 1) && (vmin_his == 1)) + loop = 0 ; + } + + if (signal == 1) { + dprintk(verbose, MB86A16_INFO, 1, " Start Freq Error Check"); + S1T = 7 ; + S0T = 1 ; + CREN = 0 ; + AFCEN = 1 ; + AFCEXEN = 0 ; + + if (S01T_set(state, S1T, S0T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "S01T set error"); + return -1; + } + smrt_info_get(state, state->srate); + if (smrt_set(state, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); + return -1; + } + if (EN_set(state, CREN, AFCEN) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "EN set error"); + return -1; + } + if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); + return -1; + } + afcex_info_get(state, afcex_freq, &AFCEX_L, &AFCEX_H); + if (afcofs_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCOFS data set error"); + return -1; + } + if (srst(state) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "srst error"); + return -1; + } + /* delay 4~200 */ + wait_t = 200000 / state->master_clk + 200000 / state->srate; + msleep(wait_t); + afcerr = afcerr_chk(state); + if (afcerr == -1) + return -1; + + swp_freq = fOSC * 1000 + afcerr ; + AFCEXEN = 1 ; + if (state->srate >= 1500) + smrt_d = state->srate / 3; + else + smrt_d = state->srate / 2; + smrt_info_get(state, smrt_d); + if (smrt_set(state, smrt_d) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); + return -1; + } + if (AFCEXEN_set(state, AFCEXEN, smrt_d) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); + return -1; + } + R = vco_dev_get(state, smrt_d); + if (DAGC_data_set(state, 2, 0) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error"); + return -1; + } + for (i = 0; i < 3; i++) { + temp_freq = swp_freq + (i - 1) * state->srate / 8; + swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); + if (rf_val_set(state, fOSC, smrt_d, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); + return -1; + } + wait_t = 200000 / state->master_clk + 40000 / smrt_d; + msleep(wait_t); + dagcm[i] = dagcm_val_get(state); + } + if ((dagcm[0] > dagcm[1]) && + (dagcm[0] > dagcm[2]) && + (dagcm[0] - dagcm[1] > 2 * (dagcm[2] - dagcm[1]))) { + + temp_freq = swp_freq - 2 * state->srate / 8; + swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); + if (rf_val_set(state, fOSC, smrt_d, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set"); + return -1; + } + wait_t = 200000 / state->master_clk + 40000 / smrt_d; + msleep(wait_t); + dagcm[3] = dagcm_val_get(state); + if (dagcm[3] > dagcm[1]) + delta_freq = (dagcm[2] - dagcm[0] + dagcm[1] - dagcm[3]) * state->srate / 300; + else + delta_freq = 0; + } else if ((dagcm[2] > dagcm[1]) && + (dagcm[2] > dagcm[0]) && + (dagcm[2] - dagcm[1] > 2 * (dagcm[0] - dagcm[1]))) { + + temp_freq = swp_freq + 2 * state->srate / 8; + swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); + if (rf_val_set(state, fOSC, smrt_d, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set"); + return -1; + } + wait_t = 200000 / state->master_clk + 40000 / smrt_d; + msleep(wait_t); + dagcm[3] = dagcm_val_get(state); + if (dagcm[3] > dagcm[1]) + delta_freq = (dagcm[2] - dagcm[0] + dagcm[3] - dagcm[1]) * state->srate / 300; + else + delta_freq = 0 ; + + } else { + delta_freq = 0 ; + } + dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq); + swp_freq += delta_freq; + dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq); + if (ABS(state->frequency * 1000 - swp_freq) > 3800) { + dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !"); + } else { + + S1T = 0; + S0T = 3; + CREN = 1; + AFCEN = 0; + AFCEXEN = 1; + + if (S01T_set(state, S1T, S0T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "S01T set error"); + return -1; + } + if (DAGC_data_set(state, 0, 0) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error"); + return -1; + } + R = vco_dev_get(state, state->srate); + smrt_info_get(state, state->srate); + if (smrt_set(state, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); + return -1; + } + if (EN_set(state, CREN, AFCEN) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "EN set error"); + return -1; + } + if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); + return -1; + } + swp_info_get2(state, state->srate, R, swp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); + if (rf_val_set(state, fOSC, state->srate, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); + return -1; + } + if (srst(state) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "srst error"); + return -1; + } + wait_t = 7 + (10000 + state->srate / 2) / state->srate; + if (wait_t == 0) + wait_t = 1; + msleep_interruptible(wait_t); + if (mb86a16_read(state, 0x37, &SIG1) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + if (SIG1 > 110) { + S2T = 4; S4T = 1; S5T = 6; ETH = 4; VIA = 6; + wait_t = 7 + (917504 + state->srate / 2) / state->srate; + } else if (SIG1 > 105) { + S2T = 4; S4T = 2; S5T = 8; ETH = 7; VIA = 2; + wait_t = 7 + (1048576 + state->srate / 2) / state->srate; + } else if (SIG1 > 85) { + S2T = 5; S4T = 2; S5T = 8; ETH = 7; VIA = 2; + wait_t = 7 + (1310720 + state->srate / 2) / state->srate; + } else if (SIG1 > 65) { + S2T = 6; S4T = 2; S5T = 8; ETH = 7; VIA = 2; + wait_t = 7 + (1572864 + state->srate / 2) / state->srate; + } else { + S2T = 7; S4T = 2; S5T = 8; ETH = 7; VIA = 2; + wait_t = 7 + (2097152 + state->srate / 2) / state->srate; + } + wait_t *= 2; /* FOS */ + S2T_set(state, S2T); + S45T_set(state, S4T, S5T); + Vi_set(state, ETH, VIA); + srst(state); + msleep_interruptible(wait_t); + sync = sync_chk(state, &VIRM); + dprintk(verbose, MB86A16_INFO, 1, "-------- Viterbi=[%d] SYNC=[%d] ---------", VIRM, sync); + if (VIRM) { + if (VIRM == 4) { + /* 5/6 */ + if (SIG1 > 110) + wait_t = (786432 + state->srate / 2) / state->srate; + else + wait_t = (1572864 + state->srate / 2) / state->srate; + if (state->srate < 5000) + /* FIXME ! , should be a long wait ! */ + msleep_interruptible(wait_t); + else + msleep_interruptible(wait_t); + + if (sync_chk(state, &junk) == 0) { + iq_vt_set(state, 1); + FEC_srst(state); + } + } + /* 1/2, 2/3, 3/4, 7/8 */ + if (SIG1 > 110) + wait_t = (786432 + state->srate / 2) / state->srate; + else + wait_t = (1572864 + state->srate / 2) / state->srate; + msleep_interruptible(wait_t); + SEQ_set(state, 1); + } else { + dprintk(verbose, MB86A16_INFO, 1, "NO -- SYNC"); + SEQ_set(state, 1); + ret = -1; + } + } + } else { + dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL"); + ret = -1; + } + + sync = sync_chk(state, &junk); + if (sync) { + dprintk(verbose, MB86A16_INFO, 1, "******* SYNC *******"); + freqerr_chk(state, state->frequency, state->srate, 1); + ret = 0; + break; + } + } + + mb86a16_read(state, 0x15, &agcval); + mb86a16_read(state, 0x26, &cnmval); + dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval); + + return ret; +} + +static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct mb86a16_state *state = fe->demodulator_priv; + int i; + u8 regs; + + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0) + goto err; + if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0) + goto err; + + regs = 0x18; + + if (cmd->msg_len > 5 || cmd->msg_len < 4) + return -EINVAL; + + for (i = 0; i < cmd->msg_len; i++) { + if (mb86a16_write(state, regs, cmd->msg[i]) < 0) + goto err; + + regs++; + } + i += 0x90; + + msleep_interruptible(10); + + if (mb86a16_write(state, MB86A16_DCC1, i) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +{ + struct mb86a16_state *state = fe->demodulator_priv; + + switch (burst) { + case SEC_MINI_A: + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA | + MB86A16_DCC1_TBEN | + MB86A16_DCC1_TBO) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) + goto err; + break; + case SEC_MINI_B: + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA | + MB86A16_DCC1_TBEN) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) + goto err; + break; + } + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct mb86a16_state *state = fe->demodulator_priv; + + switch (tone) { + case SEC_TONE_ON: + if (mb86a16_write(state, MB86A16_TONEOUT2, 0x00) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA | + MB86A16_DCC1_CTOE) < 0) + + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) + goto err; + break; + case SEC_TONE_OFF: + if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0) + goto err; + break; + default: + return -EINVAL; + } + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct mb86a16_state *state = fe->demodulator_priv; + + state->frequency = p->frequency / 1000; + state->srate = p->u.qpsk.symbol_rate / 1000; + + if (!mb86a16_set_fe(state)) { + dprintk(verbose, MB86A16_ERROR, 1, "Successfully acquired LOCK"); + return DVBFE_ALGO_SEARCH_SUCCESS; + } + + dprintk(verbose, MB86A16_ERROR, 1, "Lock acquisition failed!"); + return DVBFE_ALGO_SEARCH_FAILED; +} + +static void mb86a16_release(struct dvb_frontend *fe) +{ + struct mb86a16_state *state = fe->demodulator_priv; + kfree(state); +} + +static int mb86a16_init(struct dvb_frontend *fe) +{ + return 0; +} + +static int mb86a16_sleep(struct dvb_frontend *fe) +{ + return 0; +} + +static int mb86a16_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + u8 ber_mon, ber_tab, ber_lsb, ber_mid, ber_msb, ber_tim, ber_rst; + u32 timer; + + struct mb86a16_state *state = fe->demodulator_priv; + + *ber = 0; + if (mb86a16_read(state, MB86A16_BERMON, &ber_mon) != 2) + goto err; + if (mb86a16_read(state, MB86A16_BERTAB, &ber_tab) != 2) + goto err; + if (mb86a16_read(state, MB86A16_BERLSB, &ber_lsb) != 2) + goto err; + if (mb86a16_read(state, MB86A16_BERMID, &ber_mid) != 2) + goto err; + if (mb86a16_read(state, MB86A16_BERMSB, &ber_msb) != 2) + goto err; + /* BER monitor invalid when BER_EN = 0 */ + if (ber_mon & 0x04) { + /* coarse, fast calculation */ + *ber = ber_tab & 0x1f; + dprintk(verbose, MB86A16_DEBUG, 1, "BER coarse=[0x%02x]", *ber); + if (ber_mon & 0x01) { + /* + * BER_SEL = 1, The monitored BER is the estimated + * value with a Reed-Solomon decoder error amount at + * the deinterleaver output. + * monitored BER is expressed as a 20 bit output in total + */ + ber_rst = ber_mon >> 3; + *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb; + if (ber_rst == 0) + timer = 12500000; + if (ber_rst == 1) + timer = 25000000; + if (ber_rst == 2) + timer = 50000000; + if (ber_rst == 3) + timer = 100000000; + + *ber /= timer; + dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber); + } else { + /* + * BER_SEL = 0, The monitored BER is the estimated + * value with a Viterbi decoder error amount at the + * QPSK demodulator output. + * monitored BER is expressed as a 24 bit output in total + */ + ber_tim = ber_mon >> 1; + *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb; + if (ber_tim == 0) + timer = 16; + if (ber_tim == 1) + timer = 24; + + *ber /= 2 ^ timer; + dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber); + } + } + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int mb86a16_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + u8 agcm = 0; + struct mb86a16_state *state = fe->demodulator_priv; + + *strength = 0; + if (mb86a16_read(state, MB86A16_AGCM, &agcm) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + *strength = ((0xff - agcm) * 100) / 256; + dprintk(verbose, MB86A16_DEBUG, 1, "Signal strength=[%d %%]", (u8) *strength); + *strength = (0xffff - 0xff) + agcm; + + return 0; +} + +struct cnr { + u8 cn_reg; + u8 cn_val; +}; + +static const struct cnr cnr_tab[] = { + { 35, 2 }, + { 40, 3 }, + { 50, 4 }, + { 60, 5 }, + { 70, 6 }, + { 80, 7 }, + { 92, 8 }, + { 103, 9 }, + { 115, 10 }, + { 138, 12 }, + { 162, 15 }, + { 180, 18 }, + { 185, 19 }, + { 189, 20 }, + { 195, 22 }, + { 199, 24 }, + { 201, 25 }, + { 202, 26 }, + { 203, 27 }, + { 205, 28 }, + { 208, 30 } +}; + +static int mb86a16_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct mb86a16_state *state = fe->demodulator_priv; + int i = 0; + int low_tide = 2, high_tide = 30, q_level; + u8 cn; + + *snr = 0; + if (mb86a16_read(state, 0x26, &cn) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + for (i = 0; i < ARRAY_SIZE(cnr_tab); i++) { + if (cn < cnr_tab[i].cn_reg) { + *snr = cnr_tab[i].cn_val; + break; + } + } + q_level = (*snr * 100) / (high_tide - low_tide); + dprintk(verbose, MB86A16_ERROR, 1, "SNR (Quality) = [%d dB], Level=%d %%", *snr, q_level); + *snr = (0xffff - 0xff) + *snr; + + return 0; +} + +static int mb86a16_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + u8 dist; + struct mb86a16_state *state = fe->demodulator_priv; + + if (mb86a16_read(state, MB86A16_DISTMON, &dist) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + *ucblocks = dist; + + return 0; +} + +static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static struct dvb_frontend_ops mb86a16_ops = { + .info = { + .name = "Fujitsu MB86A16 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 3000, + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + .release = mb86a16_release, + + .get_frontend_algo = mb86a16_frontend_algo, + .search = mb86a16_search, + .init = mb86a16_init, + .sleep = mb86a16_sleep, + .read_status = mb86a16_read_status, + + .read_ber = mb86a16_read_ber, + .read_signal_strength = mb86a16_read_signal_strength, + .read_snr = mb86a16_read_snr, + .read_ucblocks = mb86a16_read_ucblocks, + + .diseqc_send_master_cmd = mb86a16_send_diseqc_msg, + .diseqc_send_burst = mb86a16_send_diseqc_burst, + .set_tone = mb86a16_set_tone, +}; + +struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, + struct i2c_adapter *i2c_adap) +{ + u8 dev_id = 0; + struct mb86a16_state *state = NULL; + + state = kmalloc(sizeof(struct mb86a16_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->config = config; + state->i2c_adap = i2c_adap; + + mb86a16_read(state, 0x7f, &dev_id); + if (dev_id != 0xfe) + goto error; + + memcpy(&state->frontend.ops, &mb86a16_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + state->frontend.ops.set_voltage = state->config->set_voltage; + + return &state->frontend; +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(mb86a16_attach); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Manu Abraham"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Fujitsu MB86A16 DVB-S/DSS DC Receiver driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MB86A16_H +#define __MB86A16_H + +#include +#include "dvb_frontend.h" + + +struct mb86a16_config { + u8 demod_address; + + int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); +}; + + + +#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, + struct i2c_adapter *i2c_adap); + +#else + +static inline struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, + struct i2c_adapter *i2c_adap) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_MB86A16 */ + +#endif /* __MB86A16_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a16_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,151 @@ +/* + Fujitsu MB86A16 DVB-S/DSS DC Receiver driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MB86A16_PRIV_H +#define __MB86A16_PRIV_H + +#define MB86A16_TSOUT 0x00 +#define MB86A16_TSOUT_HIZSEL (0x01 << 5) +#define MB86A16_TSOUT_HIZCNTI (0x01 << 4) +#define MB86A16_TSOUT_MODE (0x01 << 3) +#define MB86A16_TSOUT_ORDER (0x01 << 2) +#define MB86A16_TSOUT_ERROR (0x01 << 1) +#define Mb86A16_TSOUT_EDGE (0x01 << 0) + +#define MB86A16_FEC 0x01 +#define MB86A16_FEC_FSYNC (0x01 << 5) +#define MB86A16_FEC_PCKB8 (0x01 << 4) +#define MB86A16_FEC_DVDS (0x01 << 3) +#define MB86A16_FEC_EREN (0x01 << 2) +#define Mb86A16_FEC_RSEN (0x01 << 1) +#define MB86A16_FEC_DIEN (0x01 << 0) + +#define MB86A16_AGC 0x02 +#define MB86A16_AGC_AGMD (0x01 << 6) +#define MB86A16_AGC_AGCW (0x0f << 2) +#define MB86A16_AGC_AGCP (0x01 << 1) +#define MB86A16_AGC_AGCR (0x01 << 0) + +#define MB86A16_SRATE1 0x03 +#define MB86A16_SRATE1_DECI (0x07 << 2) +#define MB86A16_SRATE1_CSEL (0x01 << 1) +#define MB86A16_SRATE1_RSEL (0x01 << 0) + +#define MB86A16_SRATE2 0x04 +#define MB86A16_SRATE2_STOFSL (0xff << 0) + +#define MB86A16_SRATE3 0x05 +#define MB86A16_SRATE2_STOFSH (0xff << 0) + +#define MB86A16_VITERBI 0x06 +#define MB86A16_FRAMESYNC 0x07 +#define MB86A16_CRLFILTCOEF1 0x08 +#define MB86A16_CRLFILTCOEF2 0x09 +#define MB86A16_STRFILTCOEF1 0x0a +#define MB86A16_STRFILTCOEF2 0x0b +#define MB86A16_RESET 0x0c +#define MB86A16_STATUS 0x0d +#define MB86A16_AFCML 0x0e +#define MB86A16_AFCMH 0x0f +#define MB86A16_BERMON 0x10 +#define MB86A16_BERTAB 0x11 +#define MB86A16_BERLSB 0x12 +#define MB86A16_BERMID 0x13 +#define MB86A16_BERMSB 0x14 +#define MB86A16_AGCM 0x15 + +#define MB86A16_DCC1 0x16 +#define MB86A16_DCC1_DISTA (0x01 << 7) +#define MB86A16_DCC1_PRTY (0x01 << 6) +#define MB86A16_DCC1_CTOE (0x01 << 5) +#define MB86A16_DCC1_TBEN (0x01 << 4) +#define MB86A16_DCC1_TBO (0x01 << 3) +#define MB86A16_DCC1_NUM (0x07 << 0) + +#define MB86A16_DCC2 0x17 +#define MB86A16_DCC2_DCBST (0x01 << 0) + +#define MB86A16_DCC3 0x18 +#define MB86A16_DCC3_CODE0 (0xff << 0) + +#define MB86A16_DCC4 0x19 +#define MB86A16_DCC4_CODE1 (0xff << 0) + +#define MB86A16_DCC5 0x1a +#define MB86A16_DCC5_CODE2 (0xff << 0) + +#define MB86A16_DCC6 0x1b +#define MB86A16_DCC6_CODE3 (0xff << 0) + +#define MB86A16_DCC7 0x1c +#define MB86A16_DCC7_CODE4 (0xff << 0) + +#define MB86A16_DCC8 0x1d +#define MB86A16_DCC8_CODE5 (0xff << 0) + +#define MB86A16_DCCOUT 0x1e +#define MB86A16_DCCOUT_DISEN (0x01 << 0) + +#define MB86A16_TONEOUT1 0x1f +#define MB86A16_TONE_TDIVL (0xff << 0) + +#define MB86A16_TONEOUT2 0x20 +#define MB86A16_TONE_TMD (0x03 << 2) +#define MB86A16_TONE_TDIVH (0x03 << 0) + +#define MB86A16_FREQ1 0x21 +#define MB86A16_FREQ2 0x22 +#define MB86A16_FREQ3 0x23 +#define MB86A16_FREQ4 0x24 +#define MB86A16_FREQSET 0x25 +#define MB86A16_CNM 0x26 +#define MB86A16_PORT0 0x27 +#define MB86A16_PORT1 0x28 +#define MB86A16_DRCFILT 0x29 +#define MB86A16_AFC 0x2a +#define MB86A16_AFCEXL 0x2b +#define MB86A16_AFCEXH 0x2c +#define MB86A16_DAGC 0x2d +#define MB86A16_SEQMODE 0x32 +#define MB86A16_S0S1T 0x33 +#define MB86A16_S2S3T 0x34 +#define MB86A16_S4S5T 0x35 +#define MB86A16_CNTMR 0x36 +#define MB86A16_SIG1 0x37 +#define MB86A16_SIG2 0x38 +#define MB86A16_VIMAG 0x39 +#define MB86A16_VISET1 0x3a +#define MB86A16_VISET2 0x3b +#define MB86A16_VISET3 0x3c +#define MB86A16_FAGCS1 0x3d +#define MB86A16_FAGCS2 0x3e +#define MB86A16_FAGCS3 0x3f +#define MB86A16_FAGCS4 0x40 +#define MB86A16_FAGCS5 0x41 +#define MB86A16_FAGCS6 0x42 +#define MB86A16_CRM 0x43 +#define MB86A16_STRM 0x44 +#define MB86A16_DAGCML 0x45 +#define MB86A16_DAGCMH 0x46 +#define MB86A16_QPSKTST 0x49 +#define MB86A16_DISTMON 0x52 +#define MB86A16_VERSION 0x7f + +#endif /* __MB86A16_PRIV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a20s.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a20s.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a20s.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a20s.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,639 @@ +/* + * Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver + * + * Copyright (C) 2010 Mauro Carvalho Chehab + * Copyright (C) 2009-2010 Douglas Landgraf + * + * FIXME: Need to port to DVB v5.2 API + * + * 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 version 2. + * + * 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. + */ + +#include +#include + +#include "dvb_frontend.h" +#include "mb86a20s.h" + +static int debug = 1; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + +#define rc(args...) do { \ + printk(KERN_ERR "mb86a20s: " args); \ +} while (0) + +#define dprintk(args...) \ + do { \ + if (debug) { \ + printk(KERN_DEBUG "mb86a20s: %s: ", __func__); \ + printk(args); \ + } \ + } while (0) + +struct mb86a20s_state { + struct i2c_adapter *i2c; + const struct mb86a20s_config *config; + + struct dvb_frontend frontend; + + bool need_init; +}; + +struct regdata { + u8 reg; + u8 data; +}; + +/* + * Initialization sequence: Use whatevere default values that PV SBTVD + * does on its initialisation, obtained via USB snoop + */ +static struct regdata mb86a20s_init[] = { + { 0x70, 0x0f }, + { 0x70, 0xff }, + { 0x08, 0x01 }, + { 0x09, 0x3e }, + { 0x50, 0xd1 }, + { 0x51, 0x22 }, + { 0x39, 0x01 }, + { 0x71, 0x00 }, + { 0x28, 0x2a }, + { 0x29, 0x00 }, + { 0x2a, 0xff }, + { 0x2b, 0x80 }, + { 0x28, 0x20 }, + { 0x29, 0x33 }, + { 0x2a, 0xdf }, + { 0x2b, 0xa9 }, + { 0x3b, 0x21 }, + { 0x3c, 0x3a }, + { 0x01, 0x0d }, + { 0x04, 0x08 }, + { 0x05, 0x05 }, + { 0x04, 0x0e }, + { 0x05, 0x00 }, + { 0x04, 0x0f }, + { 0x05, 0x14 }, + { 0x04, 0x0b }, + { 0x05, 0x8c }, + { 0x04, 0x00 }, + { 0x05, 0x00 }, + { 0x04, 0x01 }, + { 0x05, 0x07 }, + { 0x04, 0x02 }, + { 0x05, 0x0f }, + { 0x04, 0x03 }, + { 0x05, 0xa0 }, + { 0x04, 0x09 }, + { 0x05, 0x00 }, + { 0x04, 0x0a }, + { 0x05, 0xff }, + { 0x04, 0x27 }, + { 0x05, 0x64 }, + { 0x04, 0x28 }, + { 0x05, 0x00 }, + { 0x04, 0x1e }, + { 0x05, 0xff }, + { 0x04, 0x29 }, + { 0x05, 0x0a }, + { 0x04, 0x32 }, + { 0x05, 0x0a }, + { 0x04, 0x14 }, + { 0x05, 0x02 }, + { 0x04, 0x04 }, + { 0x05, 0x00 }, + { 0x04, 0x05 }, + { 0x05, 0x22 }, + { 0x04, 0x06 }, + { 0x05, 0x0e }, + { 0x04, 0x07 }, + { 0x05, 0xd8 }, + { 0x04, 0x12 }, + { 0x05, 0x00 }, + { 0x04, 0x13 }, + { 0x05, 0xff }, + { 0x52, 0x01 }, + { 0x50, 0xa7 }, + { 0x51, 0x00 }, + { 0x50, 0xa8 }, + { 0x51, 0xff }, + { 0x50, 0xa9 }, + { 0x51, 0xff }, + { 0x50, 0xaa }, + { 0x51, 0x00 }, + { 0x50, 0xab }, + { 0x51, 0xff }, + { 0x50, 0xac }, + { 0x51, 0xff }, + { 0x50, 0xad }, + { 0x51, 0x00 }, + { 0x50, 0xae }, + { 0x51, 0xff }, + { 0x50, 0xaf }, + { 0x51, 0xff }, + { 0x5e, 0x07 }, + { 0x50, 0xdc }, + { 0x51, 0x01 }, + { 0x50, 0xdd }, + { 0x51, 0xf4 }, + { 0x50, 0xde }, + { 0x51, 0x01 }, + { 0x50, 0xdf }, + { 0x51, 0xf4 }, + { 0x50, 0xe0 }, + { 0x51, 0x01 }, + { 0x50, 0xe1 }, + { 0x51, 0xf4 }, + { 0x50, 0xb0 }, + { 0x51, 0x07 }, + { 0x50, 0xb2 }, + { 0x51, 0xff }, + { 0x50, 0xb3 }, + { 0x51, 0xff }, + { 0x50, 0xb4 }, + { 0x51, 0xff }, + { 0x50, 0xb5 }, + { 0x51, 0xff }, + { 0x50, 0xb6 }, + { 0x51, 0xff }, + { 0x50, 0xb7 }, + { 0x51, 0xff }, + { 0x50, 0x50 }, + { 0x51, 0x02 }, + { 0x50, 0x51 }, + { 0x51, 0x04 }, + { 0x45, 0x04 }, + { 0x48, 0x04 }, + { 0x50, 0xd5 }, + { 0x51, 0x01 }, /* Serial */ + { 0x50, 0xd6 }, + { 0x51, 0x1f }, + { 0x50, 0xd2 }, + { 0x51, 0x03 }, + { 0x50, 0xd7 }, + { 0x51, 0x3f }, + { 0x1c, 0x01 }, + { 0x28, 0x06 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x03 }, + { 0x28, 0x07 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x0d }, + { 0x28, 0x08 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x02 }, + { 0x28, 0x09 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x01 }, + { 0x28, 0x0a }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x21 }, + { 0x28, 0x0b }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x29 }, + { 0x28, 0x0c }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x16 }, + { 0x28, 0x0d }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x31 }, + { 0x28, 0x0e }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x0e }, + { 0x28, 0x0f }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x4e }, + { 0x28, 0x10 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x46 }, + { 0x28, 0x11 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x0f }, + { 0x28, 0x12 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x56 }, + { 0x28, 0x13 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x35 }, + { 0x28, 0x14 }, + { 0x29, 0x00 }, + { 0x2a, 0x01 }, + { 0x2b, 0xbe }, + { 0x28, 0x15 }, + { 0x29, 0x00 }, + { 0x2a, 0x01 }, + { 0x2b, 0x84 }, + { 0x28, 0x16 }, + { 0x29, 0x00 }, + { 0x2a, 0x03 }, + { 0x2b, 0xee }, + { 0x28, 0x17 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x98 }, + { 0x28, 0x18 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x9f }, + { 0x28, 0x19 }, + { 0x29, 0x00 }, + { 0x2a, 0x07 }, + { 0x2b, 0xb2 }, + { 0x28, 0x1a }, + { 0x29, 0x00 }, + { 0x2a, 0x06 }, + { 0x2b, 0xc2 }, + { 0x28, 0x1b }, + { 0x29, 0x00 }, + { 0x2a, 0x07 }, + { 0x2b, 0x4a }, + { 0x28, 0x1c }, + { 0x29, 0x00 }, + { 0x2a, 0x01 }, + { 0x2b, 0xbc }, + { 0x28, 0x1d }, + { 0x29, 0x00 }, + { 0x2a, 0x04 }, + { 0x2b, 0xba }, + { 0x28, 0x1e }, + { 0x29, 0x00 }, + { 0x2a, 0x06 }, + { 0x2b, 0x14 }, + { 0x50, 0x1e }, + { 0x51, 0x5d }, + { 0x50, 0x22 }, + { 0x51, 0x00 }, + { 0x50, 0x23 }, + { 0x51, 0xc8 }, + { 0x50, 0x24 }, + { 0x51, 0x00 }, + { 0x50, 0x25 }, + { 0x51, 0xf0 }, + { 0x50, 0x26 }, + { 0x51, 0x00 }, + { 0x50, 0x27 }, + { 0x51, 0xc3 }, + { 0x50, 0x39 }, + { 0x51, 0x02 }, + { 0x50, 0xd5 }, + { 0x51, 0x01 }, + { 0xd0, 0x00 }, +}; + +static struct regdata mb86a20s_reset_reception[] = { + { 0x70, 0xf0 }, + { 0x70, 0xff }, + { 0x08, 0x01 }, + { 0x08, 0x00 }, +}; + +static int mb86a20s_i2c_writereg(struct mb86a20s_state *state, + u8 i2c_addr, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2 + }; + int rc; + + rc = i2c_transfer(state->i2c, &msg, 1); + if (rc != 1) { + printk("%s: writereg error (rc == %i, reg == 0x%02x," + " data == 0x%02x)\n", __func__, rc, reg, data); + return rc; + } + + return 0; +} + +static int mb86a20s_i2c_writeregdata(struct mb86a20s_state *state, + u8 i2c_addr, struct regdata *rd, int size) +{ + int i, rc; + + for (i = 0; i < size; i++) { + rc = mb86a20s_i2c_writereg(state, i2c_addr, rd[i].reg, + rd[i].data); + if (rc < 0) + return rc; + } + return 0; +} + +static int mb86a20s_i2c_readreg(struct mb86a20s_state *state, + u8 i2c_addr, u8 reg) +{ + u8 val; + int rc; + struct i2c_msg msg[] = { + { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 }, + { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 } + }; + + rc = i2c_transfer(state->i2c, msg, 2); + + if (rc != 2) { + rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc); + return rc; + } + + return val; +} + +#define mb86a20s_readreg(state, reg) \ + mb86a20s_i2c_readreg(state, state->config->demod_address, reg) +#define mb86a20s_writereg(state, reg, val) \ + mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val) +#define mb86a20s_writeregdata(state, regdata) \ + mb86a20s_i2c_writeregdata(state, state->config->demod_address, \ + regdata, ARRAY_SIZE(regdata)) + +static int mb86a20s_initfe(struct dvb_frontend *fe) +{ + struct mb86a20s_state *state = fe->demodulator_priv; + int rc; + u8 regD5 = 1; + + dprintk("\n"); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + /* Initialize the frontend */ + rc = mb86a20s_writeregdata(state, mb86a20s_init); + if (rc < 0) + goto err; + + if (!state->config->is_serial) { + regD5 &= ~1; + + rc = mb86a20s_writereg(state, 0x50, 0xd5); + if (rc < 0) + goto err; + rc = mb86a20s_writereg(state, 0x51, regD5); + if (rc < 0) + goto err; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + +err: + if (rc < 0) { + state->need_init = true; + printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n"); + } else { + state->need_init = false; + dprintk("Initialization succeeded.\n"); + } + return rc; +} + +static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct mb86a20s_state *state = fe->demodulator_priv; + unsigned rf_max, rf_min, rf; + u8 val; + + dprintk("\n"); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + /* Does a binary search to get RF strength */ + rf_max = 0xfff; + rf_min = 0; + do { + rf = (rf_max + rf_min) / 2; + mb86a20s_writereg(state, 0x04, 0x1f); + mb86a20s_writereg(state, 0x05, rf >> 8); + mb86a20s_writereg(state, 0x04, 0x20); + mb86a20s_writereg(state, 0x04, rf); + + val = mb86a20s_readreg(state, 0x02); + if (val & 0x08) + rf_min = (rf_max + rf_min) / 2; + else + rf_max = (rf_max + rf_min) / 2; + if (rf_max - rf_min < 4) { + *strength = (((rf_max + rf_min) / 2) * 65535) / 4095; + break; + } + } while (1); + + dprintk("signal strength = %d\n", *strength); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + return 0; +} + +static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct mb86a20s_state *state = fe->demodulator_priv; + u8 val; + + dprintk("\n"); + *status = 0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + val = mb86a20s_readreg(state, 0x0a) & 0xf; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (val >= 2) + *status |= FE_HAS_SIGNAL; + + if (val >= 4) + *status |= FE_HAS_CARRIER; + + if (val >= 5) + *status |= FE_HAS_VITERBI; + + if (val >= 7) + *status |= FE_HAS_SYNC; + + if (val >= 8) /* Maybe 9? */ + *status |= FE_HAS_LOCK; + + dprintk("val = %d, status = 0x%02x\n", val, *status); + + return 0; +} + +static int mb86a20s_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct mb86a20s_state *state = fe->demodulator_priv; + int rc; + + dprintk("\n"); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + dprintk("Calling tuner set parameters\n"); + fe->ops.tuner_ops.set_params(fe, p); + + /* + * Make it more reliable: if, for some reason, the initial + * device initialization doesn't happen, initialize it when + * a SBTVD parameters are adjusted. + * + * Unfortunately, due to a hard to track bug at tda829x/tda18271, + * the agc callback logic is not called during DVB attach time, + * causing mb86a20s to not be initialized with Kworld SBTVD. + * So, this hack is needed, in order to make Kworld SBTVD to work. + */ + if (state->need_init) + mb86a20s_initfe(fe); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + return rc; +} + +static int mb86a20s_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + + /* FIXME: For now, it does nothing */ + + fe->dtv_property_cache.bandwidth_hz = 6000000; + fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; + fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; + fe->dtv_property_cache.isdbt_partial_reception = 0; + + return 0; +} + +static int mb86a20s_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + unsigned int mode_flags, + unsigned int *delay, + fe_status_t *status) +{ + int rc = 0; + + dprintk("\n"); + + if (params != NULL) + rc = mb86a20s_set_frontend(fe, params); + + if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) + mb86a20s_read_status(fe, status); + + return rc; +} + +static void mb86a20s_release(struct dvb_frontend *fe) +{ + struct mb86a20s_state *state = fe->demodulator_priv; + + dprintk("\n"); + + kfree(state); +} + +static struct dvb_frontend_ops mb86a20s_ops; + +struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, + struct i2c_adapter *i2c) +{ + u8 rev; + + /* allocate memory for the internal state */ + struct mb86a20s_state *state = + kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL); + + dprintk("\n"); + if (state == NULL) { + rc("Unable to kzalloc\n"); + goto error; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &mb86a20s_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* Check if it is a mb86a20s frontend */ + rev = mb86a20s_readreg(state, 0); + + if (rev == 0x13) { + printk(KERN_INFO "Detected a Fujitsu mb86a20s frontend\n"); + } else { + printk(KERN_ERR "Frontend revision %d is unknown - aborting.\n", + rev); + goto error; + } + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(mb86a20s_attach); + +static struct dvb_frontend_ops mb86a20s_ops = { + /* Use dib8000 values per default */ + .info = { + .name = "Fujitsu mb86A20s", + .type = FE_OFDM, + .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_QAM_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, + /* Actually, those values depend on the used tuner */ + .frequency_min = 45000000, + .frequency_max = 864000000, + .frequency_stepsize = 62500, + }, + + .release = mb86a20s_release, + + .init = mb86a20s_initfe, + .set_frontend = mb86a20s_set_frontend, + .get_frontend = mb86a20s_get_frontend, + .read_status = mb86a20s_read_status, + .read_signal_strength = mb86a20s_read_signal_strength, + .tune = mb86a20s_tune, +}; + +MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a20s.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a20s.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a20s.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mb86a20s.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Fujitsu mb86a20s driver + * + * Copyright (C) 2010 Mauro Carvalho Chehab + * + * 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 version 2. + * + * 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. + */ + +#ifndef MB86A20S_H +#define MB86A20S_H + +#include + +/** + * struct mb86a20s_config - Define the per-device attributes of the frontend + * + * @demod_address: the demodulator's i2c address + */ + +struct mb86a20s_config { + u8 demod_address; + bool is_serial; +}; + +#if defined(CONFIG_DVB_MB86A20S) || (defined(CONFIG_DVB_MB86A20S_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, + struct i2c_adapter *i2c); +extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *); +#else +static inline struct dvb_frontend *mb86a20s_attach( + const struct mb86a20s_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static struct i2c_adapter * + mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* MB86A20S */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,840 @@ +/* + Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder + + Copyright (C) 2003 Andreas Oberritter + Copyright (C) 2008 Matthias Schwarzott + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + References: + http://products.zarlink.com/product_profiles/MT312.htm + http://products.zarlink.com/product_profiles/SL1935.htm +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "mt312_priv.h" +#include "mt312.h" + + +struct mt312_state { + struct i2c_adapter *i2c; + /* configuration settings */ + const struct mt312_config *config; + struct dvb_frontend frontend; + + u8 id; + unsigned long xtal; + u8 freq_mult; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "mt312: " args); \ + } while (0) + +#define MT312_PLL_CLK 10000000UL /* 10 MHz */ +#define MT312_PLL_CLK_10_111 10111000UL /* 10.111 MHz */ + +static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, + u8 *buf, const size_t count) +{ + int ret; + struct i2c_msg msg[2]; + u8 regbuf[1] = { reg }; + + msg[0].addr = state->config->demod_address; + msg[0].flags = 0; + msg[0].buf = regbuf; + msg[0].len = 1; + msg[1].addr = state->config->demod_address; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret); + return -EREMOTEIO; + } + + if (debug) { + int i; + dprintk("R(%d):", reg & 0x7f); + for (i = 0; i < count; i++) + printk(KERN_CONT " %02x", buf[i]); + printk("\n"); + } + + return 0; +} + +static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, + const u8 *src, const size_t count) +{ + int ret; + u8 buf[count + 1]; + struct i2c_msg msg; + + if (debug) { + int i; + dprintk("W(%d):", reg & 0x7f); + for (i = 0; i < count; i++) + printk(KERN_CONT " %02x", src[i]); + printk("\n"); + } + + buf[0] = reg; + memcpy(&buf[1], src, count); + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.buf = buf; + msg.len = count + 1; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) { + dprintk("%s: ret == %d\n", __func__, ret); + return -EREMOTEIO; + } + + return 0; +} + +static inline int mt312_readreg(struct mt312_state *state, + const enum mt312_reg_addr reg, u8 *val) +{ + return mt312_read(state, reg, val, 1); +} + +static inline int mt312_writereg(struct mt312_state *state, + const enum mt312_reg_addr reg, const u8 val) +{ + return mt312_write(state, reg, &val, 1); +} + +static inline u32 mt312_div(u32 a, u32 b) +{ + return (a + (b / 2)) / b; +} + +static int mt312_reset(struct mt312_state *state, const u8 full) +{ + return mt312_writereg(state, RESET, full ? 0x80 : 0x40); +} + +static int mt312_get_inversion(struct mt312_state *state, + fe_spectral_inversion_t *i) +{ + int ret; + u8 vit_mode; + + ret = mt312_readreg(state, VIT_MODE, &vit_mode); + if (ret < 0) + return ret; + + if (vit_mode & 0x80) /* auto inversion was used */ + *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF; + + return 0; +} + +static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) +{ + int ret; + u8 sym_rate_h; + u8 dec_ratio; + u16 sym_rat_op; + u16 monitor; + u8 buf[2]; + + ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h); + if (ret < 0) + return ret; + + if (sym_rate_h & 0x80) { + /* symbol rate search was used */ + ret = mt312_writereg(state, MON_CTRL, 0x03); + if (ret < 0) + return ret; + + ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); + if (ret < 0) + return ret; + + monitor = (buf[0] << 8) | buf[1]; + + dprintk("sr(auto) = %u\n", + mt312_div(monitor * 15625, 4)); + } else { + ret = mt312_writereg(state, MON_CTRL, 0x05); + if (ret < 0) + return ret; + + ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); + if (ret < 0) + return ret; + + dec_ratio = ((buf[0] >> 5) & 0x07) * 32; + + ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf)); + if (ret < 0) + return ret; + + sym_rat_op = (buf[0] << 8) | buf[1]; + + dprintk("sym_rat_op=%d dec_ratio=%d\n", + sym_rat_op, dec_ratio); + dprintk("*sr(manual) = %lu\n", + (((state->xtal * 8192) / (sym_rat_op + 8192)) * + 2) - dec_ratio); + } + + return 0; +} + +static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr) +{ + const fe_code_rate_t fec_tab[8] = + { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8, + FEC_AUTO, FEC_AUTO }; + + int ret; + u8 fec_status; + + ret = mt312_readreg(state, FEC_STATUS, &fec_status); + if (ret < 0) + return ret; + + *cr = fec_tab[(fec_status >> 4) & 0x07]; + + return 0; +} + +static int mt312_initfe(struct dvb_frontend *fe) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + u8 buf[2]; + + /* wake up */ + ret = mt312_writereg(state, CONFIG, + (state->freq_mult == 6 ? 0x88 : 0x8c)); + if (ret < 0) + return ret; + + /* wait at least 150 usec */ + udelay(150); + + /* full reset */ + ret = mt312_reset(state, 1); + if (ret < 0) + return ret; + +/* Per datasheet, write correct values. 09/28/03 ACCJr. + * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */ + { + u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02, + 0x01, 0x00, 0x00, 0x00 }; + + ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def)); + if (ret < 0) + return ret; + } + + switch (state->id) { + case ID_ZL10313: + /* enable ADC */ + ret = mt312_writereg(state, GPP_CTRL, 0x80); + if (ret < 0) + return ret; + + /* configure ZL10313 for optimal ADC performance */ + buf[0] = 0x80; + buf[1] = 0xB0; + ret = mt312_write(state, HW_CTRL, buf, 2); + if (ret < 0) + return ret; + + /* enable MPEG output and ADCs */ + ret = mt312_writereg(state, HW_CTRL, 0x00); + if (ret < 0) + return ret; + + ret = mt312_writereg(state, MPEG_CTRL, 0x00); + if (ret < 0) + return ret; + + break; + } + + /* SYS_CLK */ + buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000); + + /* DISEQC_RATIO */ + buf[1] = mt312_div(state->xtal, 22000 * 4); + + ret = mt312_write(state, SYS_CLK, buf, sizeof(buf)); + if (ret < 0) + return ret; + + ret = mt312_writereg(state, SNR_THS_HIGH, 0x32); + if (ret < 0) + return ret; + + /* different MOCLK polarity */ + switch (state->id) { + case ID_ZL10313: + buf[0] = 0x33; + break; + default: + buf[0] = 0x53; + break; + } + + ret = mt312_writereg(state, OP_CTRL, buf[0]); + if (ret < 0) + return ret; + + /* TS_SW_LIM */ + buf[0] = 0x8c; + buf[1] = 0x98; + + ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf)); + if (ret < 0) + return ret; + + ret = mt312_writereg(state, CS_SW_LIM, 0x69); + if (ret < 0) + return ret; + + return 0; +} + +static int mt312_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *c) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + u8 diseqc_mode; + + if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) + return -EINVAL; + + ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); + if (ret < 0) + return ret; + + ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len); + if (ret < 0) + return ret; + + ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) + | 0x04); + if (ret < 0) + return ret; + + /* is there a better way to wait for message to be transmitted */ + msleep(100); + + /* set DISEQC_MODE[2:0] to zero if a return message is expected */ + if (c->msg[0] & 0x02) { + ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40)); + if (ret < 0) + return ret; + } + + return 0; +} + +static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c) +{ + struct mt312_state *state = fe->demodulator_priv; + const u8 mini_tab[2] = { 0x02, 0x03 }; + + int ret; + u8 diseqc_mode; + + if (c > SEC_MINI_B) + return -EINVAL; + + ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); + if (ret < 0) + return ret; + + ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | mini_tab[c]); + if (ret < 0) + return ret; + + return 0; +} + +static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t) +{ + struct mt312_state *state = fe->demodulator_priv; + const u8 tone_tab[2] = { 0x01, 0x00 }; + + int ret; + u8 diseqc_mode; + + if (t > SEC_TONE_OFF) + return -EINVAL; + + ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); + if (ret < 0) + return ret; + + ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | tone_tab[t]); + if (ret < 0) + return ret; + + return 0; +} + +static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v) +{ + struct mt312_state *state = fe->demodulator_priv; + const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; + u8 val; + + if (v > SEC_VOLTAGE_OFF) + return -EINVAL; + + val = volt_tab[v]; + if (state->config->voltage_inverted) + val ^= 0x40; + + return mt312_writereg(state, DISEQC_MODE, val); +} + +static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + u8 status[3]; + + *s = 0; + + ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status)); + if (ret < 0) + return ret; + + dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x," + " FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); + + if (status[0] & 0xc0) + *s |= FE_HAS_SIGNAL; /* signal noise ratio */ + if (status[0] & 0x04) + *s |= FE_HAS_CARRIER; /* qpsk carrier lock */ + if (status[2] & 0x02) + *s |= FE_HAS_VITERBI; /* viterbi lock */ + if (status[2] & 0x04) + *s |= FE_HAS_SYNC; /* byte align lock */ + if (status[0] & 0x01) + *s |= FE_HAS_LOCK; /* qpsk lock */ + + return 0; +} + +static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + u8 buf[3]; + + ret = mt312_read(state, RS_BERCNT_H, buf, 3); + if (ret < 0) + return ret; + + *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64; + + return 0; +} + +static int mt312_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + u8 buf[3]; + u16 agc; + s16 err_db; + + ret = mt312_read(state, AGC_H, buf, sizeof(buf)); + if (ret < 0) + return ret; + + agc = (buf[0] << 6) | (buf[1] >> 2); + err_db = (s16) (((buf[1] & 0x03) << 14) | buf[2] << 6) >> 6; + + *signal_strength = agc; + + dprintk("agc=%08x err_db=%hd\n", agc, err_db); + + return 0; +} + +static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + u8 buf[2]; + + ret = mt312_read(state, M_SNR_H, buf, sizeof(buf)); + if (ret < 0) + return ret; + + *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1); + + return 0; +} + +static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + u8 buf[2]; + + ret = mt312_read(state, RS_UBC_H, buf, sizeof(buf)); + if (ret < 0) + return ret; + + *ubc = (buf[0] << 8) | buf[1]; + + return 0; +} + +static int mt312_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + u8 buf[5], config_val; + u16 sr; + + const u8 fec_tab[10] = + { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f }; + const u8 inv_tab[3] = { 0x00, 0x40, 0x80 }; + + dprintk("%s: Freq %d\n", __func__, p->frequency); + + if ((p->frequency < fe->ops.info.frequency_min) + || (p->frequency > fe->ops.info.frequency_max)) + return -EINVAL; + + if ((p->inversion < INVERSION_OFF) + || (p->inversion > INVERSION_ON)) + return -EINVAL; + + if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) + || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) + return -EINVAL; + + if ((p->u.qpsk.fec_inner < FEC_NONE) + || (p->u.qpsk.fec_inner > FEC_AUTO)) + return -EINVAL; + + if ((p->u.qpsk.fec_inner == FEC_4_5) + || (p->u.qpsk.fec_inner == FEC_8_9)) + return -EINVAL; + + switch (state->id) { + case ID_VP310: + /* For now we will do this only for the VP310. + * It should be better for the mt312 as well, + * but tuning will be slower. ACCJr 09/29/03 + */ + ret = mt312_readreg(state, CONFIG, &config_val); + if (ret < 0) + return ret; + if (p->u.qpsk.symbol_rate >= 30000000) { + /* Note that 30MS/s should use 90MHz */ + if (state->freq_mult == 6) { + /* We are running 60MHz */ + state->freq_mult = 9; + ret = mt312_initfe(fe); + if (ret < 0) + return ret; + } + } else { + if (state->freq_mult == 9) { + /* We are running 90MHz */ + state->freq_mult = 6; + ret = mt312_initfe(fe); + if (ret < 0) + return ret; + } + } + break; + + case ID_MT312: + case ID_ZL10313: + break; + + default: + return -EINVAL; + } + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* sr = (u16)(sr * 256.0 / 1000000.0) */ + sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625); + + /* SYM_RATE */ + buf[0] = (sr >> 8) & 0x3f; + buf[1] = (sr >> 0) & 0xff; + + /* VIT_MODE */ + buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner]; + + /* QPSK_CTRL */ + buf[3] = 0x40; /* swap I and Q before QPSK demodulation */ + + if (p->u.qpsk.symbol_rate < 10000000) + buf[3] |= 0x04; /* use afc mode */ + + /* GO */ + buf[4] = 0x01; + + ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf)); + if (ret < 0) + return ret; + + mt312_reset(state, 0); + + return 0; +} + +static int mt312_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + + ret = mt312_get_inversion(state, &p->inversion); + if (ret < 0) + return ret; + + ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate); + if (ret < 0) + return ret; + + ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner); + if (ret < 0) + return ret; + + return 0; +} + +static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct mt312_state *state = fe->demodulator_priv; + + u8 val = 0x00; + int ret; + + switch (state->id) { + case ID_ZL10313: + ret = mt312_readreg(state, GPP_CTRL, &val); + if (ret < 0) + goto error; + + /* preserve this bit to not accidentally shutdown ADC */ + val &= 0x80; + break; + } + + if (enable) + val |= 0x40; + else + val &= ~0x40; + + ret = mt312_writereg(state, GPP_CTRL, val); + +error: + return ret; +} + +static int mt312_sleep(struct dvb_frontend *fe) +{ + struct mt312_state *state = fe->demodulator_priv; + int ret; + u8 config; + + /* reset all registers to defaults */ + ret = mt312_reset(state, 1); + if (ret < 0) + return ret; + + if (state->id == ID_ZL10313) { + /* reset ADC */ + ret = mt312_writereg(state, GPP_CTRL, 0x00); + if (ret < 0) + return ret; + + /* full shutdown of ADCs, mpeg bus tristated */ + ret = mt312_writereg(state, HW_CTRL, 0x0d); + if (ret < 0) + return ret; + } + + ret = mt312_readreg(state, CONFIG, &config); + if (ret < 0) + return ret; + + /* enter standby */ + ret = mt312_writereg(state, CONFIG, config & 0x7f); + if (ret < 0) + return ret; + + return 0; +} + +static int mt312_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 50; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static void mt312_release(struct dvb_frontend *fe) +{ + struct mt312_state *state = fe->demodulator_priv; + kfree(state); +} + +#define MT312_SYS_CLK 90000000UL /* 90 MHz */ +static struct dvb_frontend_ops mt312_ops = { + + .info = { + .name = "Zarlink ???? DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + /* FIXME: adjust freq to real used xtal */ + .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, + .symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */ + .symbol_rate_max = MT312_SYS_CLK / 2, + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS | + FE_CAN_RECOVER + }, + + .release = mt312_release, + + .init = mt312_initfe, + .sleep = mt312_sleep, + .i2c_gate_ctrl = mt312_i2c_gate_ctrl, + + .set_frontend = mt312_set_frontend, + .get_frontend = mt312_get_frontend, + .get_tune_settings = mt312_get_tune_settings, + + .read_status = mt312_read_status, + .read_ber = mt312_read_ber, + .read_signal_strength = mt312_read_signal_strength, + .read_snr = mt312_read_snr, + .read_ucblocks = mt312_read_ucblocks, + + .diseqc_send_master_cmd = mt312_send_master_cmd, + .diseqc_send_burst = mt312_send_burst, + .set_tone = mt312_set_tone, + .set_voltage = mt312_set_voltage, +}; + +struct dvb_frontend *mt312_attach(const struct mt312_config *config, + struct i2c_adapter *i2c) +{ + struct mt312_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct mt312_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* check if the demod is there */ + if (mt312_readreg(state, ID, &state->id) < 0) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &mt312_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + switch (state->id) { + case ID_VP310: + strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S"); + state->xtal = MT312_PLL_CLK; + state->freq_mult = 9; + break; + case ID_MT312: + strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S"); + state->xtal = MT312_PLL_CLK; + state->freq_mult = 6; + break; + case ID_ZL10313: + strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S"); + state->xtal = MT312_PLL_CLK_10_111; + state->freq_mult = 9; + break; + default: + printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313" + " are supported chips.\n"); + goto error; + } + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(mt312_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver"); +MODULE_AUTHOR("Andreas Oberritter "); +MODULE_AUTHOR("Matthias Schwarzott "); +MODULE_LICENSE("GPL"); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + Driver for Zarlink MT312 Satellite Channel Decoder + + Copyright (C) 2003 Andreas Oberritter + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + References: + http://products.zarlink.com/product_profiles/MT312.htm + http://products.zarlink.com/product_profiles/SL1935.htm +*/ + +#ifndef MT312_H +#define MT312_H + +#include + +struct mt312_config { + /* the demodulator's i2c address */ + u8 demod_address; + + /* inverted voltage setting */ + unsigned int voltage_inverted:1; +}; + +#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE)) +struct dvb_frontend *mt312_attach(const struct mt312_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *mt312_attach( + const struct mt312_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_MT312 */ + +#endif /* MT312_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt312_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,165 @@ +/* + Driver for Zarlink MT312 QPSK Frontend + + Copyright (C) 2003 Andreas Oberritter + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef _DVB_FRONTENDS_MT312_PRIV +#define _DVB_FRONTENDS_MT312_PRIV + +enum mt312_reg_addr { + QPSK_INT_H = 0, + QPSK_INT_M = 1, + QPSK_INT_L = 2, + FEC_INT = 3, + QPSK_STAT_H = 4, + QPSK_STAT_L = 5, + FEC_STATUS = 6, + LNB_FREQ_H = 7, + LNB_FREQ_L = 8, + M_SNR_H = 9, + M_SNR_L = 10, + VIT_ERRCNT_H = 11, + VIT_ERRCNT_M = 12, + VIT_ERRCNT_L = 13, + RS_BERCNT_H = 14, + RS_BERCNT_M = 15, + RS_BERCNT_L = 16, + RS_UBC_H = 17, + RS_UBC_L = 18, + SIG_LEVEL = 19, + GPP_CTRL = 20, + RESET = 21, + DISEQC_MODE = 22, + SYM_RATE_H = 23, + SYM_RATE_L = 24, + VIT_MODE = 25, + QPSK_CTRL = 26, + GO = 27, + IE_QPSK_H = 28, + IE_QPSK_M = 29, + IE_QPSK_L = 30, + IE_FEC = 31, + QPSK_STAT_EN = 32, + FEC_STAT_EN = 33, + SYS_CLK = 34, + DISEQC_RATIO = 35, + DISEQC_INSTR = 36, + FR_LIM = 37, + FR_OFF = 38, + AGC_CTRL = 39, + AGC_INIT = 40, + AGC_REF = 41, + AGC_MAX = 42, + AGC_MIN = 43, + AGC_LK_TH = 44, + TS_AGC_LK_TH = 45, + AGC_PWR_SET = 46, + QPSK_MISC = 47, + SNR_THS_LOW = 48, + SNR_THS_HIGH = 49, + TS_SW_RATE = 50, + TS_SW_LIM_L = 51, + TS_SW_LIM_H = 52, + CS_SW_RATE_1 = 53, + CS_SW_RATE_2 = 54, + CS_SW_RATE_3 = 55, + CS_SW_RATE_4 = 56, + CS_SW_LIM = 57, + TS_LPK = 58, + TS_LPK_M = 59, + TS_LPK_L = 60, + CS_KPROP_H = 61, + CS_KPROP_L = 62, + CS_KINT_H = 63, + CS_KINT_L = 64, + QPSK_SCALE = 65, + TLD_OUTCLK_TH = 66, + TLD_INCLK_TH = 67, + FLD_TH = 68, + PLD_OUTLK3 = 69, + PLD_OUTLK2 = 70, + PLD_OUTLK1 = 71, + PLD_OUTLK0 = 72, + PLD_INLK3 = 73, + PLD_INLK2 = 74, + PLD_INLK1 = 75, + PLD_INLK0 = 76, + PLD_ACC_TIME = 77, + SWEEP_PAR = 78, + STARTUP_TIME = 79, + LOSSLOCK_TH = 80, + FEC_LOCK_TM = 81, + LOSSLOCK_TM = 82, + VIT_ERRPER_H = 83, + VIT_ERRPER_M = 84, + VIT_ERRPER_L = 85, + HW_CTRL = 84, /* ZL10313 only */ + MPEG_CTRL = 85, /* ZL10313 only */ + VIT_SETUP = 86, + VIT_REF0 = 87, + VIT_REF1 = 88, + VIT_REF2 = 89, + VIT_REF3 = 90, + VIT_REF4 = 91, + VIT_REF5 = 92, + VIT_REF6 = 93, + VIT_MAXERR = 94, + BA_SETUPT = 95, + OP_CTRL = 96, + FEC_SETUP = 97, + PROG_SYNC = 98, + AFC_SEAR_TH = 99, + CSACC_DIF_TH = 100, + QPSK_LK_CT = 101, + QPSK_ST_CT = 102, + MON_CTRL = 103, + QPSK_RESET = 104, + QPSK_TST_CT = 105, + QPSK_TST_ST = 106, + TEST_R = 107, + AGC_H = 108, + AGC_M = 109, + AGC_L = 110, + FREQ_ERR1_H = 111, + FREQ_ERR1_M = 112, + FREQ_ERR1_L = 113, + FREQ_ERR2_H = 114, + FREQ_ERR2_L = 115, + SYM_RAT_OP_H = 116, + SYM_RAT_OP_L = 117, + DESEQC2_INT = 118, + DISEQC2_STAT = 119, + DISEQC2_FIFO = 120, + DISEQC2_CTRL1 = 121, + DISEQC2_CTRL2 = 122, + MONITOR_H = 123, + MONITOR_L = 124, + TEST_MODE = 125, + ID = 126, + CONFIG = 127 +}; + +enum mt312_model_id { + ID_VP310 = 1, + ID_MT312 = 3, + ID_ZL10313 = 5, +}; + +#endif /* DVB_FRONTENDS_MT312_PRIV */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,613 @@ +/* + * Driver for Zarlink DVB-T MT352 demodulator + * + * Written by Holger Waechtler + * and Daniel Mack + * + * AVerMedia AVerTV DVB-T 771 support by + * Wolfram Joost + * + * Support for Samsung TDTC9251DH01C(M) tuner + * Copyright (C) 2004 Antonio Mancuso + * Amauri Celani + * + * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by + * Christopher Pascoe + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "mt352_priv.h" +#include "mt352.h" + +struct mt352_state { + struct i2c_adapter* i2c; + struct dvb_frontend frontend; + + /* configuration settings */ + struct mt352_config config; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "mt352: " args); \ + } while (0) + +static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val) +{ + struct mt352_state* state = fe->demodulator_priv; + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0, + .buf = buf, .len = 2 }; + int err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk("mt352_write() to reg %x failed (err = %d)!\n", reg, err); + return err; + } + return 0; +} + +static int _mt352_write(struct dvb_frontend* fe, const u8 ibuf[], int ilen) +{ + int err,i; + for (i=0; i < ilen-1; i++) + if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1]))) + return err; + + return 0; +} + +static int mt352_read_register(struct mt352_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config.demod_address, + .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config.demod_address, + .flags = I2C_M_RD, + .buf = b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk("%s: readreg error (reg=%d, ret==%i)\n", + __func__, reg, ret); + return ret; + } + + return b1[0]; +} + +static int mt352_sleep(struct dvb_frontend* fe) +{ + static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 }; + + _mt352_write(fe, mt352_softdown, sizeof(mt352_softdown)); + return 0; +} + +static void mt352_calc_nominal_rate(struct mt352_state* state, + enum fe_bandwidth bandwidth, + unsigned char *buf) +{ + u32 adc_clock = 20480; /* 20.340 MHz */ + u32 bw,value; + + switch (bandwidth) { + case BANDWIDTH_6_MHZ: + bw = 6; + break; + case BANDWIDTH_7_MHZ: + bw = 7; + break; + case BANDWIDTH_8_MHZ: + default: + bw = 8; + break; + } + if (state->config.adc_clock) + adc_clock = state->config.adc_clock; + + value = 64 * bw * (1<<16) / (7 * 8); + value = value * 1000 / adc_clock; + dprintk("%s: bw %d, adc_clock %d => 0x%x\n", + __func__, bw, adc_clock, value); + buf[0] = msb(value); + buf[1] = lsb(value); +} + +static void mt352_calc_input_freq(struct mt352_state* state, + unsigned char *buf) +{ + int adc_clock = 20480; /* 20.480000 MHz */ + int if2 = 36167; /* 36.166667 MHz */ + int ife,value; + + if (state->config.adc_clock) + adc_clock = state->config.adc_clock; + if (state->config.if2) + if2 = state->config.if2; + + if (adc_clock >= if2 * 2) + ife = if2; + else { + ife = adc_clock - (if2 % adc_clock); + if (ife > adc_clock / 2) + ife = adc_clock - ife; + } + value = -16374 * ife / adc_clock; + dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", + __func__, if2, ife, adc_clock, value, value & 0x3fff); + buf[0] = msb(value); + buf[1] = lsb(value); +} + +static int mt352_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + struct mt352_state* state = fe->demodulator_priv; + unsigned char buf[13]; + static unsigned char tuner_go[] = { 0x5d, 0x01 }; + static unsigned char fsm_go[] = { 0x5e, 0x01 }; + unsigned int tps = 0; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + + switch (op->code_rate_HP) { + case FEC_2_3: + tps |= (1 << 7); + break; + case FEC_3_4: + tps |= (2 << 7); + break; + case FEC_5_6: + tps |= (3 << 7); + break; + case FEC_7_8: + tps |= (4 << 7); + break; + case FEC_1_2: + case FEC_AUTO: + break; + default: + return -EINVAL; + } + + switch (op->code_rate_LP) { + case FEC_2_3: + tps |= (1 << 4); + break; + case FEC_3_4: + tps |= (2 << 4); + break; + case FEC_5_6: + tps |= (3 << 4); + break; + case FEC_7_8: + tps |= (4 << 4); + break; + case FEC_1_2: + case FEC_AUTO: + break; + case FEC_NONE: + if (op->hierarchy_information == HIERARCHY_AUTO || + op->hierarchy_information == HIERARCHY_NONE) + break; + default: + return -EINVAL; + } + + switch (op->constellation) { + case QPSK: + break; + case QAM_AUTO: + case QAM_16: + tps |= (1 << 13); + break; + case QAM_64: + tps |= (2 << 13); + break; + default: + return -EINVAL; + } + + switch (op->transmission_mode) { + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + break; + case TRANSMISSION_MODE_8K: + tps |= (1 << 0); + break; + default: + return -EINVAL; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + break; + case GUARD_INTERVAL_1_16: + tps |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + tps |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + tps |= (3 << 2); + break; + default: + return -EINVAL; + } + + switch (op->hierarchy_information) { + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + tps |= (1 << 10); + break; + case HIERARCHY_2: + tps |= (2 << 10); + break; + case HIERARCHY_4: + tps |= (3 << 10); + break; + default: + return -EINVAL; + } + + + buf[0] = TPS_GIVEN_1; /* TPS_GIVEN_1 and following registers */ + + buf[1] = msb(tps); /* TPS_GIVEN_(1|0) */ + buf[2] = lsb(tps); + + buf[3] = 0x50; // old +// buf[3] = 0xf4; // pinnacle + + mt352_calc_nominal_rate(state, op->bandwidth, buf+4); + mt352_calc_input_freq(state, buf+6); + + if (state->config.no_tuner) { + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + _mt352_write(fe, buf, 8); + _mt352_write(fe, fsm_go, 2); + } else { + if (fe->ops.tuner_ops.calc_regs) { + fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5); + buf[8] <<= 1; + _mt352_write(fe, buf, sizeof(buf)); + _mt352_write(fe, tuner_go, 2); + } + } + + return 0; +} + +static int mt352_get_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + struct mt352_state* state = fe->demodulator_priv; + u16 tps; + u16 div; + u8 trl; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + static const u8 tps_fec_to_api[8] = + { + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_5_6, + FEC_7_8, + FEC_AUTO, + FEC_AUTO, + FEC_AUTO + }; + + if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 ) + return -EINVAL; + + /* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because + * the mt352 sometimes works with the wrong parameters + */ + tps = (mt352_read_register(state, TPS_RECEIVED_1) << 8) | mt352_read_register(state, TPS_RECEIVED_0); + div = (mt352_read_register(state, CHAN_START_1) << 8) | mt352_read_register(state, CHAN_START_0); + trl = mt352_read_register(state, TRL_NOMINAL_RATE_1); + + op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; + op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; + + switch ( (tps >> 13) & 3) + { + case 0: + op->constellation = QPSK; + break; + case 1: + op->constellation = QAM_16; + break; + case 2: + op->constellation = QAM_64; + break; + default: + op->constellation = QAM_AUTO; + break; + } + + op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K; + + switch ( (tps >> 2) & 3) + { + case 0: + op->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + op->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + op->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + op->guard_interval = GUARD_INTERVAL_1_4; + break; + default: + op->guard_interval = GUARD_INTERVAL_AUTO; + break; + } + + switch ( (tps >> 10) & 7) + { + case 0: + op->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + op->hierarchy_information = HIERARCHY_1; + break; + case 2: + op->hierarchy_information = HIERARCHY_2; + break; + case 3: + op->hierarchy_information = HIERARCHY_4; + break; + default: + op->hierarchy_information = HIERARCHY_AUTO; + break; + } + + param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000; + + if (trl == 0x72) + op->bandwidth = BANDWIDTH_8_MHZ; + else if (trl == 0x64) + op->bandwidth = BANDWIDTH_7_MHZ; + else + op->bandwidth = BANDWIDTH_6_MHZ; + + + if (mt352_read_register(state, STATUS_2) & 0x02) + param->inversion = INVERSION_OFF; + else + param->inversion = INVERSION_ON; + + return 0; +} + +static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct mt352_state* state = fe->demodulator_priv; + int s0, s1, s3; + + /* FIXME: + * + * The MT352 design manual from Zarlink states (page 46-47): + * + * Notes about the TUNER_GO register: + * + * If the Read_Tuner_Byte (bit-1) is activated, then the tuner status + * byte is copied from the tuner to the STATUS_3 register and + * completion of the read operation is indicated by bit-5 of the + * INTERRUPT_3 register. + */ + + if ((s0 = mt352_read_register(state, STATUS_0)) < 0) + return -EREMOTEIO; + if ((s1 = mt352_read_register(state, STATUS_1)) < 0) + return -EREMOTEIO; + if ((s3 = mt352_read_register(state, STATUS_3)) < 0) + return -EREMOTEIO; + + *status = 0; + if (s0 & (1 << 4)) + *status |= FE_HAS_CARRIER; + if (s0 & (1 << 1)) + *status |= FE_HAS_VITERBI; + if (s0 & (1 << 5)) + *status |= FE_HAS_LOCK; + if (s1 & (1 << 1)) + *status |= FE_HAS_SYNC; + if (s3 & (1 << 6)) + *status |= FE_HAS_SIGNAL; + + if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != + (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) + *status &= ~FE_HAS_LOCK; + + return 0; +} + +static int mt352_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct mt352_state* state = fe->demodulator_priv; + + *ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) | + (mt352_read_register (state, RS_ERR_CNT_1) << 8) | + (mt352_read_register (state, RS_ERR_CNT_0)); + + return 0; +} + +static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct mt352_state* state = fe->demodulator_priv; + + /* align the 12 bit AGC gain with the most significant bits */ + u16 signal = ((mt352_read_register(state, AGC_GAIN_1) & 0x0f) << 12) | + (mt352_read_register(state, AGC_GAIN_0) << 4); + + /* inverse of gain is signal strength */ + *strength = ~signal; + return 0; +} + +static int mt352_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct mt352_state* state = fe->demodulator_priv; + + u8 _snr = mt352_read_register (state, SNR); + *snr = (_snr << 8) | _snr; + + return 0; +} + +static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct mt352_state* state = fe->demodulator_priv; + + *ucblocks = (mt352_read_register (state, RS_UBC_1) << 8) | + (mt352_read_register (state, RS_UBC_0)); + + return 0; +} + +static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 800; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + + return 0; +} + +static int mt352_init(struct dvb_frontend* fe) +{ + struct mt352_state* state = fe->demodulator_priv; + + static u8 mt352_reset_attach [] = { RESET, 0xC0 }; + + dprintk("%s: hello\n",__func__); + + if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 || + (mt352_read_register(state, CONFIG) & 0x20) == 0) { + + /* Do a "hard" reset */ + _mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach)); + return state->config.demod_init(fe); + } + + return 0; +} + +static void mt352_release(struct dvb_frontend* fe) +{ + struct mt352_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops mt352_ops; + +struct dvb_frontend* mt352_attach(const struct mt352_config* config, + struct i2c_adapter* i2c) +{ + struct mt352_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct mt352_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->i2c = i2c; + memcpy(&state->config,config,sizeof(struct mt352_config)); + + /* check if the demod is there */ + if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops mt352_ops = { + + .info = { + .name = "Zarlink MT352 DVB-T", + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + + .release = mt352_release, + + .init = mt352_init, + .sleep = mt352_sleep, + .write = _mt352_write, + + .set_frontend = mt352_set_parameters, + .get_frontend = mt352_get_parameters, + .get_tune_settings = mt352_get_tune_settings, + + .read_status = mt352_read_status, + .read_ber = mt352_read_ber, + .read_signal_strength = mt352_read_signal_strength, + .read_snr = mt352_read_snr, + .read_ucblocks = mt352_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Zarlink MT352 DVB-T Demodulator driver"); +MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(mt352_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * Driver for Zarlink DVB-T MT352 demodulator + * + * Written by Holger Waechtler + * and Daniel Mack + * + * AVerMedia AVerTV DVB-T 771 support by + * Wolfram Joost + * + * Support for Samsung TDTC9251DH01C(M) tuner + * Copyright (C) 2004 Antonio Mancuso + * Amauri Celani + * + * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by + * Christopher Pascoe + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef MT352_H +#define MT352_H + +#include + +struct mt352_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* frequencies in kHz */ + int adc_clock; // default: 20480 + int if2; // default: 36166 + + /* set if no pll is connected to the secondary i2c bus */ + int no_tuner; + + /* Initialise the demodulator and PLL. Cannot be NULL */ + int (*demod_init)(struct dvb_frontend* fe); +}; + +#if defined(CONFIG_DVB_MT352) || (defined(CONFIG_DVB_MT352_MODULE) && defined(MODULE)) +extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* mt352_attach(const struct mt352_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_MT352 + +static inline int mt352_write(struct dvb_frontend *fe, const u8 buf[], int len) { + int r = 0; + if (fe->ops.write) + r = fe->ops.write(fe, buf, len); + return r; +} + +#endif // MT352_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/mt352_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,127 @@ +/* + * Driver for Zarlink DVB-T MT352 demodulator + * + * Written by Holger Waechtler + * and Daniel Mack + * + * AVerMedia AVerTV DVB-T 771 support by + * Wolfram Joost + * + * Support for Samsung TDTC9251DH01C(M) tuner + * Copyright (C) 2004 Antonio Mancuso + * Amauri Celani + * + * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by + * Christopher Pascoe + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef _MT352_PRIV_ +#define _MT352_PRIV_ + +#define ID_MT352 0x13 + +#define msb(x) (((x) >> 8) & 0xff) +#define lsb(x) ((x) & 0xff) + +enum mt352_reg_addr { + STATUS_0 = 0x00, + STATUS_1 = 0x01, + STATUS_2 = 0x02, + STATUS_3 = 0x03, + STATUS_4 = 0x04, + INTERRUPT_0 = 0x05, + INTERRUPT_1 = 0x06, + INTERRUPT_2 = 0x07, + INTERRUPT_3 = 0x08, + SNR = 0x09, + VIT_ERR_CNT_2 = 0x0A, + VIT_ERR_CNT_1 = 0x0B, + VIT_ERR_CNT_0 = 0x0C, + RS_ERR_CNT_2 = 0x0D, + RS_ERR_CNT_1 = 0x0E, + RS_ERR_CNT_0 = 0x0F, + RS_UBC_1 = 0x10, + RS_UBC_0 = 0x11, + AGC_GAIN_3 = 0x12, + AGC_GAIN_2 = 0x13, + AGC_GAIN_1 = 0x14, + AGC_GAIN_0 = 0x15, + FREQ_OFFSET_2 = 0x17, + FREQ_OFFSET_1 = 0x18, + FREQ_OFFSET_0 = 0x19, + TIMING_OFFSET_1 = 0x1A, + TIMING_OFFSET_0 = 0x1B, + CHAN_FREQ_1 = 0x1C, + CHAN_FREQ_0 = 0x1D, + TPS_RECEIVED_1 = 0x1E, + TPS_RECEIVED_0 = 0x1F, + TPS_CURRENT_1 = 0x20, + TPS_CURRENT_0 = 0x21, + TPS_CELL_ID_1 = 0x22, + TPS_CELL_ID_0 = 0x23, + TPS_MISC_DATA_2 = 0x24, + TPS_MISC_DATA_1 = 0x25, + TPS_MISC_DATA_0 = 0x26, + RESET = 0x50, + TPS_GIVEN_1 = 0x51, + TPS_GIVEN_0 = 0x52, + ACQ_CTL = 0x53, + TRL_NOMINAL_RATE_1 = 0x54, + TRL_NOMINAL_RATE_0 = 0x55, + INPUT_FREQ_1 = 0x56, + INPUT_FREQ_0 = 0x57, + TUNER_ADDR = 0x58, + CHAN_START_1 = 0x59, + CHAN_START_0 = 0x5A, + CONT_1 = 0x5B, + CONT_0 = 0x5C, + TUNER_GO = 0x5D, + STATUS_EN_0 = 0x5F, + STATUS_EN_1 = 0x60, + INTERRUPT_EN_0 = 0x61, + INTERRUPT_EN_1 = 0x62, + INTERRUPT_EN_2 = 0x63, + INTERRUPT_EN_3 = 0x64, + AGC_TARGET = 0x67, + AGC_CTL = 0x68, + CAPT_RANGE = 0x75, + SNR_SELECT_1 = 0x79, + SNR_SELECT_0 = 0x7A, + RS_ERR_PER_1 = 0x7C, + RS_ERR_PER_0 = 0x7D, + CHIP_ID = 0x7F, + CHAN_STOP_1 = 0x80, + CHAN_STOP_0 = 0x81, + CHAN_STEP_1 = 0x82, + CHAN_STEP_0 = 0x83, + FEC_LOCK_TIME = 0x85, + OFDM_LOCK_TIME = 0x86, + ACQ_DELAY = 0x87, + SCAN_CTL = 0x88, + CLOCK_CTL = 0x89, + CONFIG = 0x8A, + MCLK_RATIO = 0x8B, + GPP_CTL = 0x8C, + ADC_CTL_1 = 0x8E, + ADC_CTL_0 = 0x8F +}; + +/* here we assume 1/6MHz == 166.66kHz stepsize */ +#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + +#endif /* _MT352_PRIV_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt200x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt200x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt200x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt200x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1241 @@ +/* + * Support for NXT2002 and NXT2004 - VSB/QAM + * + * Copyright (C) 2005 Kirk Lapray + * Copyright (C) 2006 Michael Krufky + * based on nxt2002 by Taylor Jacob + * and nxt2004 by Jean-Francois Thibert + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * +*/ + +/* + * NOTES ABOUT THIS DRIVER + * + * This Linux driver supports: + * B2C2/BBTI Technisat Air2PC - ATSC (NXT2002) + * AverTVHD MCE A180 (NXT2004) + * ATI HDTV Wonder (NXT2004) + * + * This driver needs external firmware. Please use the command + * "/Documentation/dvb/get_dvb_firmware nxt2002" or + * "/Documentation/dvb/get_dvb_firmware nxt2004" to + * download/extract the appropriate firmware, and then copy it to + * /usr/lib/hotplug/firmware/ or /lib/firmware/ + * (depending on configuration of firmware hotplug). + */ +#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" +#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw" +#define CRC_CCIT_MASK 0x1021 + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "nxt200x.h" + +struct nxt200x_state { + + struct i2c_adapter* i2c; + const struct nxt200x_config* config; + struct dvb_frontend frontend; + + /* demodulator private data */ + nxt_chip_type demod_chip; + u8 initialised:1; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "nxt200x: " args); \ + } while (0) + +static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len) +{ + int err; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len }; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n", + __func__, addr, err); + return -EREMOTEIO; + } + return 0; +} + +static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len) +{ + int err; + struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n", + __func__, addr, err); + return -EREMOTEIO; + } + return 0; +} + +static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, + const u8 *buf, u8 len) +{ + u8 buf2 [len+1]; + int err; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 }; + + buf2[0] = reg; + memcpy(&buf2[1], buf, len); + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n", + __func__, state->config->demod_address, err); + return -EREMOTEIO; + } + return 0; +} + +static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len) +{ + u8 reg2 [] = { reg }; + + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } }; + + int err; + + if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { + printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n", + __func__, state->config->demod_address, err); + return -EREMOTEIO; + } + return 0; +} + +static u16 nxt200x_crc(u16 crc, u8 c) +{ + u8 i; + u16 input = (u16) c & 0xFF; + + input<<=8; + for(i=0; i<8; i++) { + if((crc^input) & 0x8000) + crc=(crc<<1)^CRC_CCIT_MASK; + else + crc<<=1; + input<<=1; + } + return crc; +} + +static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) +{ + u8 attr, len2, buf; + dprintk("%s\n", __func__); + + /* set mutli register register */ + nxt200x_writebytes(state, 0x35, ®, 1); + + /* send the actual data */ + nxt200x_writebytes(state, 0x36, data, len); + + switch (state->demod_chip) { + case NXT2002: + len2 = len; + buf = 0x02; + break; + case NXT2004: + /* probably not right, but gives correct values */ + attr = 0x02; + if (reg & 0x80) { + attr = attr << 1; + if (reg & 0x04) + attr = attr >> 1; + } + /* set write bit */ + len2 = ((attr << 4) | 0x10) | len; + buf = 0x80; + break; + default: + return -EINVAL; + break; + } + + /* set multi register length */ + nxt200x_writebytes(state, 0x34, &len2, 1); + + /* toggle the multireg write bit */ + nxt200x_writebytes(state, 0x21, &buf, 1); + + nxt200x_readbytes(state, 0x21, &buf, 1); + + switch (state->demod_chip) { + case NXT2002: + if ((buf & 0x02) == 0) + return 0; + break; + case NXT2004: + if (buf == 0) + return 0; + break; + default: + return -EINVAL; + break; + } + + printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg); + + return 0; +} + +static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) +{ + int i; + u8 buf, len2, attr; + dprintk("%s\n", __func__); + + /* set mutli register register */ + nxt200x_writebytes(state, 0x35, ®, 1); + + switch (state->demod_chip) { + case NXT2002: + /* set multi register length */ + len2 = len & 0x80; + nxt200x_writebytes(state, 0x34, &len2, 1); + + /* read the actual data */ + nxt200x_readbytes(state, reg, data, len); + return 0; + break; + case NXT2004: + /* probably not right, but gives correct values */ + attr = 0x02; + if (reg & 0x80) { + attr = attr << 1; + if (reg & 0x04) + attr = attr >> 1; + } + + /* set multi register length */ + len2 = (attr << 4) | len; + nxt200x_writebytes(state, 0x34, &len2, 1); + + /* toggle the multireg bit*/ + buf = 0x80; + nxt200x_writebytes(state, 0x21, &buf, 1); + + /* read the actual data */ + for(i = 0; i < len; i++) { + nxt200x_readbytes(state, 0x36 + i, &data[i], 1); + } + return 0; + break; + default: + return -EINVAL; + break; + } +} + +static void nxt200x_microcontroller_stop (struct nxt200x_state* state) +{ + u8 buf, stopval, counter = 0; + dprintk("%s\n", __func__); + + /* set correct stop value */ + switch (state->demod_chip) { + case NXT2002: + stopval = 0x40; + break; + case NXT2004: + stopval = 0x10; + break; + default: + stopval = 0; + break; + } + + buf = 0x80; + nxt200x_writebytes(state, 0x22, &buf, 1); + + while (counter < 20) { + nxt200x_readbytes(state, 0x31, &buf, 1); + if (buf & stopval) + return; + msleep(10); + counter++; + } + + printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n"); + return; +} + +static void nxt200x_microcontroller_start (struct nxt200x_state* state) +{ + u8 buf; + dprintk("%s\n", __func__); + + buf = 0x00; + nxt200x_writebytes(state, 0x22, &buf, 1); +} + +static void nxt2004_microcontroller_init (struct nxt200x_state* state) +{ + u8 buf[9]; + u8 counter = 0; + dprintk("%s\n", __func__); + + buf[0] = 0x00; + nxt200x_writebytes(state, 0x2b, buf, 1); + buf[0] = 0x70; + nxt200x_writebytes(state, 0x34, buf, 1); + buf[0] = 0x04; + nxt200x_writebytes(state, 0x35, buf, 1); + buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89; + buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0; + nxt200x_writebytes(state, 0x36, buf, 9); + buf[0] = 0x80; + nxt200x_writebytes(state, 0x21, buf, 1); + + while (counter < 20) { + nxt200x_readbytes(state, 0x21, buf, 1); + if (buf[0] == 0) + return; + msleep(10); + counter++; + } + + printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n"); + + return; +} + +static int nxt200x_writetuner (struct nxt200x_state* state, u8* data) +{ + u8 buf, count = 0; + + dprintk("%s\n", __func__); + + dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]); + + /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip. + * direct write is required for Philips TUV1236D and ALPS TDHU2 */ + switch (state->demod_chip) { + case NXT2004: + if (i2c_writebytes(state, data[0], data+1, 4)) + printk(KERN_WARNING "nxt200x: error writing to tuner\n"); + /* wait until we have a lock */ + while (count < 20) { + i2c_readbytes(state, data[0], &buf, 1); + if (buf & 0x40) + return 0; + msleep(100); + count++; + } + printk("nxt2004: timeout waiting for tuner lock\n"); + break; + case NXT2002: + /* set the i2c transfer speed to the tuner */ + buf = 0x03; + nxt200x_writebytes(state, 0x20, &buf, 1); + + /* setup to transfer 4 bytes via i2c */ + buf = 0x04; + nxt200x_writebytes(state, 0x34, &buf, 1); + + /* write actual tuner bytes */ + nxt200x_writebytes(state, 0x36, data+1, 4); + + /* set tuner i2c address */ + buf = data[0] << 1; + nxt200x_writebytes(state, 0x35, &buf, 1); + + /* write UC Opmode to begin transfer */ + buf = 0x80; + nxt200x_writebytes(state, 0x21, &buf, 1); + + while (count < 20) { + nxt200x_readbytes(state, 0x21, &buf, 1); + if ((buf & 0x80)== 0x00) + return 0; + msleep(100); + count++; + } + printk("nxt2002: timeout error writing tuner\n"); + break; + default: + return -EINVAL; + break; + } + return 0; +} + +static void nxt200x_agc_reset(struct nxt200x_state* state) +{ + u8 buf; + dprintk("%s\n", __func__); + + switch (state->demod_chip) { + case NXT2002: + buf = 0x08; + nxt200x_writebytes(state, 0x08, &buf, 1); + buf = 0x00; + nxt200x_writebytes(state, 0x08, &buf, 1); + break; + case NXT2004: + nxt200x_readreg_multibyte(state, 0x08, &buf, 1); + buf = 0x08; + nxt200x_writereg_multibyte(state, 0x08, &buf, 1); + buf = 0x00; + nxt200x_writereg_multibyte(state, 0x08, &buf, 1); + break; + default: + break; + } + return; +} + +static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) +{ + + struct nxt200x_state* state = fe->demodulator_priv; + u8 buf[3], written = 0, chunkpos = 0; + u16 rambase, position, crc = 0; + + dprintk("%s\n", __func__); + dprintk("Firmware is %zu bytes\n", fw->size); + + /* Get the RAM base for this nxt2002 */ + nxt200x_readbytes(state, 0x10, buf, 1); + + if (buf[0] & 0x10) + rambase = 0x1000; + else + rambase = 0x0000; + + dprintk("rambase on this nxt2002 is %04X\n", rambase); + + /* Hold the micro in reset while loading firmware */ + buf[0] = 0x80; + nxt200x_writebytes(state, 0x2B, buf, 1); + + for (position = 0; position < fw->size; position++) { + if (written == 0) { + crc = 0; + chunkpos = 0x28; + buf[0] = ((rambase + position) >> 8); + buf[1] = (rambase + position) & 0xFF; + buf[2] = 0x81; + /* write starting address */ + nxt200x_writebytes(state, 0x29, buf, 3); + } + written++; + chunkpos++; + + if ((written % 4) == 0) + nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4); + + crc = nxt200x_crc(crc, fw->data[position]); + + if ((written == 255) || (position+1 == fw->size)) { + /* write remaining bytes of firmware */ + nxt200x_writebytes(state, chunkpos+4-(written %4), + &fw->data[position-(written %4) + 1], + written %4); + buf[0] = crc << 8; + buf[1] = crc & 0xFF; + + /* write crc */ + nxt200x_writebytes(state, 0x2C, buf, 2); + + /* do a read to stop things */ + nxt200x_readbytes(state, 0x2A, buf, 1); + + /* set transfer mode to complete */ + buf[0] = 0x80; + nxt200x_writebytes(state, 0x2B, buf, 1); + + written = 0; + } + } + + return 0; +}; + +static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) +{ + + struct nxt200x_state* state = fe->demodulator_priv; + u8 buf[3]; + u16 rambase, position, crc=0; + + dprintk("%s\n", __func__); + dprintk("Firmware is %zu bytes\n", fw->size); + + /* set rambase */ + rambase = 0x1000; + + /* hold the micro in reset while loading firmware */ + buf[0] = 0x80; + nxt200x_writebytes(state, 0x2B, buf,1); + + /* calculate firmware CRC */ + for (position = 0; position < fw->size; position++) { + crc = nxt200x_crc(crc, fw->data[position]); + } + + buf[0] = rambase >> 8; + buf[1] = rambase & 0xFF; + buf[2] = 0x81; + /* write starting address */ + nxt200x_writebytes(state,0x29,buf,3); + + for (position = 0; position < fw->size;) { + nxt200x_writebytes(state, 0x2C, &fw->data[position], + fw->size-position > 255 ? 255 : fw->size-position); + position += (fw->size-position > 255 ? 255 : fw->size-position); + } + buf[0] = crc >> 8; + buf[1] = crc & 0xFF; + + dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]); + + /* write crc */ + nxt200x_writebytes(state, 0x2C, buf,2); + + /* do a read to stop things */ + nxt200x_readbytes(state, 0x2C, buf, 1); + + /* set transfer mode to complete */ + buf[0] = 0x80; + nxt200x_writebytes(state, 0x2B, buf,1); + + return 0; +}; + +static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 buf[5]; + + /* stop the micro first */ + nxt200x_microcontroller_stop(state); + + if (state->demod_chip == NXT2004) { + /* make sure demod is set to digital */ + buf[0] = 0x04; + nxt200x_writebytes(state, 0x14, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0x17, buf, 1); + } + + /* set additional params */ + switch (p->u.vsb.modulation) { + case QAM_64: + case QAM_256: + /* Set punctured clock for QAM */ + /* This is just a guess since I am unable to test it */ + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 1); + break; + case VSB_8: + /* Set non-punctured clock for VSB */ + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + break; + default: + return -EINVAL; + break; + } + + if (fe->ops.tuner_ops.calc_regs) { + /* get tuning information */ + fe->ops.tuner_ops.calc_regs(fe, p, buf, 5); + + /* write frequency information */ + nxt200x_writetuner(state, buf); + } + + /* reset the agc now that tuning has been completed */ + nxt200x_agc_reset(state); + + /* set target power level */ + switch (p->u.vsb.modulation) { + case QAM_64: + case QAM_256: + buf[0] = 0x74; + break; + case VSB_8: + buf[0] = 0x70; + break; + default: + return -EINVAL; + break; + } + nxt200x_writebytes(state, 0x42, buf, 1); + + /* configure sdm */ + switch (state->demod_chip) { + case NXT2002: + buf[0] = 0x87; + break; + case NXT2004: + buf[0] = 0x07; + break; + default: + return -EINVAL; + break; + } + nxt200x_writebytes(state, 0x57, buf, 1); + + /* write sdm1 input */ + buf[0] = 0x10; + buf[1] = 0x00; + switch (state->demod_chip) { + case NXT2002: + nxt200x_writereg_multibyte(state, 0x58, buf, 2); + break; + case NXT2004: + nxt200x_writebytes(state, 0x58, buf, 2); + break; + default: + return -EINVAL; + break; + } + + /* write sdmx input */ + switch (p->u.vsb.modulation) { + case QAM_64: + buf[0] = 0x68; + break; + case QAM_256: + buf[0] = 0x64; + break; + case VSB_8: + buf[0] = 0x60; + break; + default: + return -EINVAL; + break; + } + buf[1] = 0x00; + switch (state->demod_chip) { + case NXT2002: + nxt200x_writereg_multibyte(state, 0x5C, buf, 2); + break; + case NXT2004: + nxt200x_writebytes(state, 0x5C, buf, 2); + break; + default: + return -EINVAL; + break; + } + + /* write adc power lpf fc */ + buf[0] = 0x05; + nxt200x_writebytes(state, 0x43, buf, 1); + + if (state->demod_chip == NXT2004) { + /* write ??? */ + buf[0] = 0x00; + buf[1] = 0x00; + nxt200x_writebytes(state, 0x46, buf, 2); + } + + /* write accumulator2 input */ + buf[0] = 0x80; + buf[1] = 0x00; + switch (state->demod_chip) { + case NXT2002: + nxt200x_writereg_multibyte(state, 0x4B, buf, 2); + break; + case NXT2004: + nxt200x_writebytes(state, 0x4B, buf, 2); + break; + default: + return -EINVAL; + break; + } + + /* write kg1 */ + buf[0] = 0x00; + nxt200x_writebytes(state, 0x4D, buf, 1); + + /* write sdm12 lpf fc */ + buf[0] = 0x44; + nxt200x_writebytes(state, 0x55, buf, 1); + + /* write agc control reg */ + buf[0] = 0x04; + nxt200x_writebytes(state, 0x41, buf, 1); + + if (state->demod_chip == NXT2004) { + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x24; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* soft reset? */ + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x10; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x04; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x81, buf, 1); + buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; + nxt200x_writereg_multibyte(state, 0x82, buf, 3); + nxt200x_readreg_multibyte(state, 0x88, buf, 1); + buf[0] = 0x11; + nxt200x_writereg_multibyte(state, 0x88, buf, 1); + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x44; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + } + + /* write agc ucgp0 */ + switch (p->u.vsb.modulation) { + case QAM_64: + buf[0] = 0x02; + break; + case QAM_256: + buf[0] = 0x03; + break; + case VSB_8: + buf[0] = 0x00; + break; + default: + return -EINVAL; + break; + } + nxt200x_writebytes(state, 0x30, buf, 1); + + /* write agc control reg */ + buf[0] = 0x00; + nxt200x_writebytes(state, 0x41, buf, 1); + + /* write accumulator2 input */ + buf[0] = 0x80; + buf[1] = 0x00; + switch (state->demod_chip) { + case NXT2002: + nxt200x_writereg_multibyte(state, 0x49, buf, 2); + nxt200x_writereg_multibyte(state, 0x4B, buf, 2); + break; + case NXT2004: + nxt200x_writebytes(state, 0x49, buf, 2); + nxt200x_writebytes(state, 0x4B, buf, 2); + break; + default: + return -EINVAL; + break; + } + + /* write agc control reg */ + buf[0] = 0x04; + nxt200x_writebytes(state, 0x41, buf, 1); + + nxt200x_microcontroller_start(state); + + if (state->demod_chip == NXT2004) { + nxt2004_microcontroller_init(state); + + /* ???? */ + buf[0] = 0xF0; + buf[1] = 0x00; + nxt200x_writebytes(state, 0x5C, buf, 2); + } + + /* adjacent channel detection should be done here, but I don't + have any stations with this need so I cannot test it */ + + return 0; +} + +static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 lock; + nxt200x_readbytes(state, 0x31, &lock, 1); + + *status = 0; + if (lock & 0x20) { + *status |= FE_HAS_SIGNAL; + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_LOCK; + } + return 0; +} + +static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 b[3]; + + nxt200x_readreg_multibyte(state, 0xE6, b, 3); + + *ber = ((b[0] << 8) + b[1]) * 8; + + return 0; +} + +static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 b[2]; + u16 temp = 0; + + /* setup to read cluster variance */ + b[0] = 0x00; + nxt200x_writebytes(state, 0xA1, b, 1); + + /* get multreg val */ + nxt200x_readreg_multibyte(state, 0xA6, b, 2); + + temp = (b[0] << 8) | b[1]; + *strength = ((0x7FFF - temp) & 0x0FFF) * 16; + + return 0; +} + +static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr) +{ + + struct nxt200x_state* state = fe->demodulator_priv; + u8 b[2]; + u16 temp = 0, temp2; + u32 snrdb = 0; + + /* setup to read cluster variance */ + b[0] = 0x00; + nxt200x_writebytes(state, 0xA1, b, 1); + + /* get multreg val from 0xA6 */ + nxt200x_readreg_multibyte(state, 0xA6, b, 2); + + temp = (b[0] << 8) | b[1]; + temp2 = 0x7FFF - temp; + + /* snr will be in db */ + if (temp2 > 0x7F00) + snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) ); + else if (temp2 > 0x7EC0) + snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) ); + else if (temp2 > 0x7C00) + snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) ); + else + snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) ); + + /* the value reported back from the frontend will be FFFF=32db 0000=0db */ + *snr = snrdb * (0xFFFF/32000); + + return 0; +} + +static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 b[3]; + + nxt200x_readreg_multibyte(state, 0xE6, b, 3); + *ucblocks = b[2]; + + return 0; +} + +static int nxt200x_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int nxt2002_init(struct dvb_frontend* fe) +{ + struct nxt200x_state* state = fe->demodulator_priv; + const struct firmware *fw; + int ret; + u8 buf[2]; + + /* request the firmware, this will block until someone uploads it */ + printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, + state->i2c->dev.parent); + printk("nxt2002: Waiting for firmware upload(2)...\n"); + if (ret) { + printk("nxt2002: No firmware uploaded (timeout or file not found?)\n"); + return ret; + } + + ret = nxt2002_load_firmware(fe, fw); + release_firmware(fw); + if (ret) { + printk("nxt2002: Writing firmware to device failed\n"); + return ret; + } + printk("nxt2002: Firmware upload complete\n"); + + /* Put the micro into reset */ + nxt200x_microcontroller_stop(state); + + /* ensure transfer is complete */ + buf[0]=0x00; + nxt200x_writebytes(state, 0x2B, buf, 1); + + /* Put the micro into reset for real this time */ + nxt200x_microcontroller_stop(state); + + /* soft reset everything (agc,frontend,eq,fec)*/ + buf[0] = 0x0F; + nxt200x_writebytes(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0x08, buf, 1); + + /* write agc sdm configure */ + buf[0] = 0xF1; + nxt200x_writebytes(state, 0x57, buf, 1); + + /* write mod output format */ + buf[0] = 0x20; + nxt200x_writebytes(state, 0x09, buf, 1); + + /* write fec mpeg mode */ + buf[0] = 0x7E; + buf[1] = 0x00; + nxt200x_writebytes(state, 0xE9, buf, 2); + + /* write mux selection */ + buf[0] = 0x00; + nxt200x_writebytes(state, 0xCC, buf, 1); + + return 0; +} + +static int nxt2004_init(struct dvb_frontend* fe) +{ + struct nxt200x_state* state = fe->demodulator_priv; + const struct firmware *fw; + int ret; + u8 buf[3]; + + /* ??? */ + buf[0]=0x00; + nxt200x_writebytes(state, 0x1E, buf, 1); + + /* request the firmware, this will block until someone uploads it */ + printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, + state->i2c->dev.parent); + printk("nxt2004: Waiting for firmware upload(2)...\n"); + if (ret) { + printk("nxt2004: No firmware uploaded (timeout or file not found?)\n"); + return ret; + } + + ret = nxt2004_load_firmware(fe, fw); + release_firmware(fw); + if (ret) { + printk("nxt2004: Writing firmware to device failed\n"); + return ret; + } + printk("nxt2004: Firmware upload complete\n"); + + /* ensure transfer is complete */ + buf[0] = 0x01; + nxt200x_writebytes(state, 0x19, buf, 1); + + nxt2004_microcontroller_init(state); + nxt200x_microcontroller_stop(state); + nxt200x_microcontroller_stop(state); + nxt2004_microcontroller_init(state); + nxt200x_microcontroller_stop(state); + + /* soft reset everything (agc,frontend,eq,fec)*/ + buf[0] = 0xFF; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + + /* write agc sdm configure */ + buf[0] = 0xD7; + nxt200x_writebytes(state, 0x57, buf, 1); + + /* ???*/ + buf[0] = 0x07; + buf[1] = 0xfe; + nxt200x_writebytes(state, 0x35, buf, 2); + buf[0] = 0x12; + nxt200x_writebytes(state, 0x34, buf, 1); + buf[0] = 0x80; + nxt200x_writebytes(state, 0x21, buf, 1); + + /* ???*/ + buf[0] = 0x21; + nxt200x_writebytes(state, 0x0A, buf, 1); + + /* ???*/ + buf[0] = 0x01; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* write fec mpeg mode */ + buf[0] = 0x7E; + buf[1] = 0x00; + nxt200x_writebytes(state, 0xE9, buf, 2); + + /* write mux selection */ + buf[0] = 0x00; + nxt200x_writebytes(state, 0xCC, buf, 1); + + /* ???*/ + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* soft reset? */ + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x10; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + + /* ???*/ + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x01; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x70; + nxt200x_writereg_multibyte(state, 0x81, buf, 1); + buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66; + nxt200x_writereg_multibyte(state, 0x82, buf, 3); + + nxt200x_readreg_multibyte(state, 0x88, buf, 1); + buf[0] = 0x11; + nxt200x_writereg_multibyte(state, 0x88, buf, 1); + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x40; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + nxt200x_readbytes(state, 0x10, buf, 1); + buf[0] = 0x10; + nxt200x_writebytes(state, 0x10, buf, 1); + nxt200x_readbytes(state, 0x0A, buf, 1); + buf[0] = 0x21; + nxt200x_writebytes(state, 0x0A, buf, 1); + + nxt2004_microcontroller_init(state); + + buf[0] = 0x21; + nxt200x_writebytes(state, 0x0A, buf, 1); + buf[0] = 0x7E; + nxt200x_writebytes(state, 0xE9, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0xEA, buf, 1); + + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* soft reset? */ + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x10; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x04; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x81, buf, 1); + buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; + nxt200x_writereg_multibyte(state, 0x82, buf, 3); + + nxt200x_readreg_multibyte(state, 0x88, buf, 1); + buf[0] = 0x11; + nxt200x_writereg_multibyte(state, 0x88, buf, 1); + + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x44; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* initialize tuner */ + nxt200x_readbytes(state, 0x10, buf, 1); + buf[0] = 0x12; + nxt200x_writebytes(state, 0x10, buf, 1); + buf[0] = 0x04; + nxt200x_writebytes(state, 0x13, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0x16, buf, 1); + buf[0] = 0x04; + nxt200x_writebytes(state, 0x14, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0x14, buf, 1); + nxt200x_writebytes(state, 0x17, buf, 1); + nxt200x_writebytes(state, 0x14, buf, 1); + nxt200x_writebytes(state, 0x17, buf, 1); + + return 0; +} + +static int nxt200x_init(struct dvb_frontend* fe) +{ + struct nxt200x_state* state = fe->demodulator_priv; + int ret = 0; + + if (!state->initialised) { + switch (state->demod_chip) { + case NXT2002: + ret = nxt2002_init(fe); + break; + case NXT2004: + ret = nxt2004_init(fe); + break; + default: + return -EINVAL; + break; + } + state->initialised = 1; + } + return ret; +} + +static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 500; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static void nxt200x_release(struct dvb_frontend* fe) +{ + struct nxt200x_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops nxt200x_ops; + +struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, + struct i2c_adapter* i2c) +{ + struct nxt200x_state* state = NULL; + u8 buf [] = {0,0,0,0,0}; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct nxt200x_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->initialised = 0; + + /* read card id */ + nxt200x_readbytes(state, 0x00, buf, 5); + dprintk("NXT info: %02X %02X %02X %02X %02X\n", + buf[0], buf[1], buf[2], buf[3], buf[4]); + + /* set demod chip */ + switch (buf[0]) { + case 0x04: + state->demod_chip = NXT2002; + printk("nxt200x: NXT2002 Detected\n"); + break; + case 0x05: + state->demod_chip = NXT2004; + printk("nxt200x: NXT2004 Detected\n"); + break; + default: + goto error; + } + + /* make sure demod chip is supported */ + switch (state->demod_chip) { + case NXT2002: + if (buf[0] != 0x04) goto error; /* device id */ + if (buf[1] != 0x02) goto error; /* fab id */ + if (buf[2] != 0x11) goto error; /* month */ + if (buf[3] != 0x20) goto error; /* year msb */ + if (buf[4] != 0x00) goto error; /* year lsb */ + break; + case NXT2004: + if (buf[0] != 0x05) goto error; /* device id */ + break; + default: + goto error; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + printk("Unknown/Unsupported NXT chip: %02X %02X %02X %02X %02X\n", + buf[0], buf[1], buf[2], buf[3], buf[4]); + return NULL; +} + +static struct dvb_frontend_ops nxt200x_ops = { + + .info = { + .name = "Nextwave NXT200X VSB/QAM frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 860000000, + .frequency_stepsize = 166666, /* stepsize is just a guess */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256 + }, + + .release = nxt200x_release, + + .init = nxt200x_init, + .sleep = nxt200x_sleep, + + .set_frontend = nxt200x_setup_frontend_parameters, + .get_tune_settings = nxt200x_get_tune_settings, + + .read_status = nxt200x_read_status, + .read_ber = nxt200x_read_ber, + .read_signal_strength = nxt200x_read_signal_strength, + .read_snr = nxt200x_read_snr, + .read_ucblocks = nxt200x_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); +MODULE_AUTHOR("Kirk Lapray, Michael Krufky, Jean-Francois Thibert, and Taylor Jacob"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(nxt200x_attach); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt200x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt200x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt200x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt200x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Support for NXT2002 and NXT2004 - VSB/QAM + * + * Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com) + * based on nxt2002 by Taylor Jacob + * and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * +*/ + +#ifndef NXT200X_H +#define NXT200X_H + +#include +#include + +typedef enum nxt_chip_t { + NXTUNDEFINED, + NXT2002, + NXT2004 +}nxt_chip_type; + +struct nxt200x_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); +}; + +#if defined(CONFIG_DVB_NXT200X) || (defined(CONFIG_DVB_NXT200X_MODULE) && defined(MODULE)) +extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_NXT200X + +#endif /* NXT200X_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,610 @@ +/* + NxtWave Communications - NXT6000 demodulator driver + + Copyright (C) 2002-2003 Florian Schirmer + Copyright (C) 2003 Paul Andreassen + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "nxt6000_priv.h" +#include "nxt6000.h" + + + +struct nxt6000_state { + struct i2c_adapter* i2c; + /* configuration settings */ + const struct nxt6000_config* config; + struct dvb_frontend frontend; +}; + +static int debug; +#define dprintk if (debug) printk + +static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 }; + int ret; + + if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) + dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret); + + return (ret != 1) ? -EFAULT : 0; +} + +static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msgs[] = { + {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, + {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} + }; + + ret = i2c_transfer(state->i2c, msgs, 2); + + if (ret != 2) + dprintk("nxt6000: nxt6000_read error (reg: 0x%02X, ret: %d)\n", reg, ret); + + return b1[0]; +} + +static void nxt6000_reset(struct nxt6000_state* state) +{ + u8 val; + + val = nxt6000_readreg(state, OFDM_COR_CTL); + + nxt6000_writereg(state, OFDM_COR_CTL, val & ~COREACT); + nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT); +} + +static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth) +{ + u16 nominal_rate; + int result; + + switch (bandwidth) { + + case BANDWIDTH_6_MHZ: + nominal_rate = 0x55B7; + break; + + case BANDWIDTH_7_MHZ: + nominal_rate = 0x6400; + break; + + case BANDWIDTH_8_MHZ: + nominal_rate = 0x7249; + break; + + default: + return -EINVAL; + } + + if ((result = nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0) + return result; + + return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF); +} + +static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval) +{ + switch (guard_interval) { + + case GUARD_INTERVAL_1_32: + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); + + case GUARD_INTERVAL_1_16: + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); + + case GUARD_INTERVAL_AUTO: + case GUARD_INTERVAL_1_8: + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); + + case GUARD_INTERVAL_1_4: + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); + + default: + return -EINVAL; + } +} + +static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion) +{ + switch (inversion) { + + case INVERSION_OFF: + return nxt6000_writereg(state, OFDM_ITB_CTL, 0x00); + + case INVERSION_ON: + return nxt6000_writereg(state, OFDM_ITB_CTL, ITBINV); + + default: + return -EINVAL; + + } +} + +static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmit_mode_t transmission_mode) +{ + int result; + + switch (transmission_mode) { + + case TRANSMISSION_MODE_2K: + if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0) + return result; + + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04)); + + case TRANSMISSION_MODE_8K: + case TRANSMISSION_MODE_AUTO: + if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0) + return result; + + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04)); + + default: + return -EINVAL; + + } +} + +static void nxt6000_setup(struct dvb_frontend* fe) +{ + struct nxt6000_state* state = fe->demodulator_priv; + + nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM); + nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01); + nxt6000_writereg(state, VIT_BERTIME_2, 0x00); // BER Timer = 0x000200 * 256 = 131072 bits + nxt6000_writereg(state, VIT_BERTIME_1, 0x02); // + nxt6000_writereg(state, VIT_BERTIME_0, 0x00); // + nxt6000_writereg(state, VIT_COR_INTEN, 0x98); // Enable BER interrupts + nxt6000_writereg(state, VIT_COR_CTL, 0x82); // Enable BER measurement + nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC | 0x02 ); + nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F)); + nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02); + nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW); + nxt6000_writereg(state, OFDM_ITB_FREQ_1, 0x06); + nxt6000_writereg(state, OFDM_ITB_FREQ_2, 0x31); + nxt6000_writereg(state, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04); + nxt6000_writereg(state, CAS_FREQ, 0xBB); /* CHECKME */ + nxt6000_writereg(state, OFDM_SYR_CTL, 1 << 2); + nxt6000_writereg(state, OFDM_PPM_CTL_1, PPM256); + nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, 0x49); + nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, 0x72); + nxt6000_writereg(state, ANALOG_CONTROL_0, 1 << 5); + nxt6000_writereg(state, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2); + nxt6000_writereg(state, DIAG_CONFIG, TB_SET); + + if (state->config->clock_inversion) + nxt6000_writereg(state, SUB_DIAG_MODE_SEL, CLKINVERSION); + else + nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0); + + nxt6000_writereg(state, TS_FORMAT, 0); +} + +static void nxt6000_dump_status(struct nxt6000_state *state) +{ + u8 val; + +/* + printk("RS_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, RS_COR_STAT)); + printk("VIT_SYNC_STATUS: 0x%02X\n", nxt6000_readreg(fe, VIT_SYNC_STATUS)); + printk("OFDM_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_COR_STAT)); + printk("OFDM_SYR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_SYR_STAT)); + printk("OFDM_TPS_RCVD_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_1)); + printk("OFDM_TPS_RCVD_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_2)); + printk("OFDM_TPS_RCVD_3: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_3)); + printk("OFDM_TPS_RCVD_4: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_4)); + printk("OFDM_TPS_RESERVED_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_1)); + printk("OFDM_TPS_RESERVED_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_2)); +*/ + printk("NXT6000 status:"); + + val = nxt6000_readreg(state, RS_COR_STAT); + + printk(" DATA DESCR LOCK: %d,", val & 0x01); + printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01); + + val = nxt6000_readreg(state, VIT_SYNC_STATUS); + + printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01); + + switch ((val >> 4) & 0x07) { + + case 0x00: + printk(" VITERBI CODERATE: 1/2,"); + break; + + case 0x01: + printk(" VITERBI CODERATE: 2/3,"); + break; + + case 0x02: + printk(" VITERBI CODERATE: 3/4,"); + break; + + case 0x03: + printk(" VITERBI CODERATE: 5/6,"); + break; + + case 0x04: + printk(" VITERBI CODERATE: 7/8,"); + break; + + default: + printk(" VITERBI CODERATE: Reserved,"); + + } + + val = nxt6000_readreg(state, OFDM_COR_STAT); + + printk(" CHCTrack: %d,", (val >> 7) & 0x01); + printk(" TPSLock: %d,", (val >> 6) & 0x01); + printk(" SYRLock: %d,", (val >> 5) & 0x01); + printk(" AGCLock: %d,", (val >> 4) & 0x01); + + switch (val & 0x0F) { + + case 0x00: + printk(" CoreState: IDLE,"); + break; + + case 0x02: + printk(" CoreState: WAIT_AGC,"); + break; + + case 0x03: + printk(" CoreState: WAIT_SYR,"); + break; + + case 0x04: + printk(" CoreState: WAIT_PPM,"); + break; + + case 0x01: + printk(" CoreState: WAIT_TRL,"); + break; + + case 0x05: + printk(" CoreState: WAIT_TPS,"); + break; + + case 0x06: + printk(" CoreState: MONITOR_TPS,"); + break; + + default: + printk(" CoreState: Reserved,"); + + } + + val = nxt6000_readreg(state, OFDM_SYR_STAT); + + printk(" SYRLock: %d,", (val >> 4) & 0x01); + printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K"); + + switch ((val >> 4) & 0x03) { + + case 0x00: + printk(" SYRGuard: 1/32,"); + break; + + case 0x01: + printk(" SYRGuard: 1/16,"); + break; + + case 0x02: + printk(" SYRGuard: 1/8,"); + break; + + case 0x03: + printk(" SYRGuard: 1/4,"); + break; + } + + val = nxt6000_readreg(state, OFDM_TPS_RCVD_3); + + switch ((val >> 4) & 0x07) { + + case 0x00: + printk(" TPSLP: 1/2,"); + break; + + case 0x01: + printk(" TPSLP: 2/3,"); + break; + + case 0x02: + printk(" TPSLP: 3/4,"); + break; + + case 0x03: + printk(" TPSLP: 5/6,"); + break; + + case 0x04: + printk(" TPSLP: 7/8,"); + break; + + default: + printk(" TPSLP: Reserved,"); + + } + + switch (val & 0x07) { + + case 0x00: + printk(" TPSHP: 1/2,"); + break; + + case 0x01: + printk(" TPSHP: 2/3,"); + break; + + case 0x02: + printk(" TPSHP: 3/4,"); + break; + + case 0x03: + printk(" TPSHP: 5/6,"); + break; + + case 0x04: + printk(" TPSHP: 7/8,"); + break; + + default: + printk(" TPSHP: Reserved,"); + + } + + val = nxt6000_readreg(state, OFDM_TPS_RCVD_4); + + printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K"); + + switch ((val >> 4) & 0x03) { + + case 0x00: + printk(" TPSGuard: 1/32,"); + break; + + case 0x01: + printk(" TPSGuard: 1/16,"); + break; + + case 0x02: + printk(" TPSGuard: 1/8,"); + break; + + case 0x03: + printk(" TPSGuard: 1/4,"); + break; + + } + + /* Strange magic required to gain access to RF_AGC_STATUS */ + nxt6000_readreg(state, RF_AGC_VAL_1); + val = nxt6000_readreg(state, RF_AGC_STATUS); + val = nxt6000_readreg(state, RF_AGC_STATUS); + + printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01); + printk("\n"); +} + +static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + u8 core_status; + struct nxt6000_state* state = fe->demodulator_priv; + + *status = 0; + + core_status = nxt6000_readreg(state, OFDM_COR_STAT); + + if (core_status & AGCLOCKED) + *status |= FE_HAS_SIGNAL; + + if (nxt6000_readreg(state, OFDM_SYR_STAT) & GI14_SYR_LOCK) + *status |= FE_HAS_CARRIER; + + if (nxt6000_readreg(state, VIT_SYNC_STATUS) & VITINSYNC) + *status |= FE_HAS_VITERBI; + + if (nxt6000_readreg(state, RS_COR_STAT) & RSCORESTATUS) + *status |= FE_HAS_SYNC; + + if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))) + *status |= FE_HAS_LOCK; + + if (debug) + nxt6000_dump_status(state); + + return 0; +} + +static int nxt6000_init(struct dvb_frontend* fe) +{ + struct nxt6000_state* state = fe->demodulator_priv; + + nxt6000_reset(state); + nxt6000_setup(fe); + + return 0; +} + +static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) +{ + struct nxt6000_state* state = fe->demodulator_priv; + int result; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0) + return result; + if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0) + return result; + if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0) + return result; + if ((result = nxt6000_set_inversion(state, param->inversion)) < 0) + return result; + + msleep(500); + return 0; +} + +static void nxt6000_release(struct dvb_frontend* fe) +{ + struct nxt6000_state* state = fe->demodulator_priv; + kfree(state); +} + +static int nxt6000_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct nxt6000_state* state = fe->demodulator_priv; + + *snr = nxt6000_readreg( state, OFDM_CHC_SNR) / 8; + + return 0; +} + +static int nxt6000_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct nxt6000_state* state = fe->demodulator_priv; + + nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18 ); + + *ber = (nxt6000_readreg( state, VIT_BER_1 ) << 8 ) | + nxt6000_readreg( state, VIT_BER_0 ); + + nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18); // Clear BER Done interrupts + + return 0; +} + +static int nxt6000_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct nxt6000_state* state = fe->demodulator_priv; + + *signal_strength = (short) (511 - + (nxt6000_readreg(state, AGC_GAIN_1) + + ((nxt6000_readreg(state, AGC_GAIN_2) & 0x03) << 8))); + + return 0; +} + +static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 500; + return 0; +} + +static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct nxt6000_state* state = fe->demodulator_priv; + + if (enable) { + return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); + } else { + return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); + } +} + +static struct dvb_frontend_ops nxt6000_ops; + +struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, + struct i2c_adapter* i2c) +{ + struct nxt6000_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct nxt6000_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* check if the demod is there */ + if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops nxt6000_ops = { + + .info = { + .name = "NxtWave NXT6000 DVB-T", + .type = FE_OFDM, + .frequency_min = 0, + .frequency_max = 863250000, + .frequency_stepsize = 62500, + /*.frequency_tolerance = *//* FIXME: 12% of SR */ + .symbol_rate_min = 0, /* FIXME */ + .symbol_rate_max = 9360000, /* FIXME */ + .symbol_rate_tolerance = 4000, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = nxt6000_release, + + .init = nxt6000_init, + .i2c_gate_ctrl = nxt6000_i2c_gate_ctrl, + + .get_tune_settings = nxt6000_fe_get_tune_settings, + + .set_frontend = nxt6000_set_frontend, + + .read_status = nxt6000_read_status, + .read_ber = nxt6000_read_ber, + .read_signal_strength = nxt6000_read_signal_strength, + .read_snr = nxt6000_read_snr, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("NxtWave NXT6000 DVB-T demodulator driver"); +MODULE_AUTHOR("Florian Schirmer"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(nxt6000_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + NxtWave Communications - NXT6000 demodulator driver + + Copyright (C) 2002-2003 Florian Schirmer + Copyright (C) 2003 Paul Andreassen + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef NXT6000_H +#define NXT6000_H + +#include + +struct nxt6000_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* should clock inversion be used? */ + u8 clock_inversion:1; +}; + +#if defined(CONFIG_DVB_NXT6000) || (defined(CONFIG_DVB_NXT6000_MODULE) && defined(MODULE)) +extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_NXT6000 + +#endif // NXT6000_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/nxt6000_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,286 @@ +/* + * Public Include File for DRV6000 users + * (ie. NxtWave Communications - NXT6000 demodulator driver) + * + * Copyright (C) 2001 NxtWave Communications, Inc. + * + */ + +/* Nxt6000 Register Addresses and Bit Masks */ + +/* Maximum Register Number */ +#define MAXNXT6000REG (0x9A) + +/* 0x1B A_VIT_BER_0 aka 0x3A */ +#define A_VIT_BER_0 (0x1B) + +/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */ +#define A_VIT_BER_TIMER_0 (0x1D) + +/* 0x21 RS_COR_STAT */ +#define RS_COR_STAT (0x21) +#define RSCORESTATUS (0x03) + +/* 0x22 RS_COR_INTEN */ +#define RS_COR_INTEN (0x22) + +/* 0x23 RS_COR_INSTAT */ +#define RS_COR_INSTAT (0x23) +#define INSTAT_ERROR (0x04) +#define LOCK_LOSS_BITS (0x03) + +/* 0x24 RS_COR_SYNC_PARAM */ +#define RS_COR_SYNC_PARAM (0x24) +#define SYNC_PARAM (0x03) + +/* 0x25 BER_CTRL */ +#define BER_CTRL (0x25) +#define BER_ENABLE (0x02) +#define BER_RESET (0x01) + +/* 0x26 BER_PAY */ +#define BER_PAY (0x26) + +/* 0x27 BER_PKT_L */ +#define BER_PKT_L (0x27) +#define BER_PKTOVERFLOW (0x80) + +/* 0x30 VIT_COR_CTL */ +#define VIT_COR_CTL (0x30) +#define BER_CONTROL (0x02) +#define VIT_COR_MASK (0x82) +#define VIT_COR_RESYNC (0x80) + + +/* 0x32 VIT_SYNC_STATUS */ +#define VIT_SYNC_STATUS (0x32) +#define VITINSYNC (0x80) + +/* 0x33 VIT_COR_INTEN */ +#define VIT_COR_INTEN (0x33) +#define GLOBAL_ENABLE (0x80) + +/* 0x34 VIT_COR_INTSTAT */ +#define VIT_COR_INTSTAT (0x34) +#define BER_DONE (0x08) +#define BER_OVERFLOW (0x10) + +/* 0x38 VIT_BERTIME_2 */ +#define VIT_BERTIME_2 (0x38) + +/* 0x39 VIT_BERTIME_1 */ +#define VIT_BERTIME_1 (0x39) + +/* 0x3A VIT_BERTIME_0 */ +#define VIT_BERTIME_0 (0x3a) + + /* 0x38 OFDM_BERTimer *//* Use the alias registers */ +#define A_VIT_BER_TIMER_0 (0x1D) + + /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */ +#define A_VIT_BER_0 (0x1B) + +/* 0x3B VIT_BER_1 */ +#define VIT_BER_1 (0x3b) + +/* 0x3C VIT_BER_0 */ +#define VIT_BER_0 (0x3c) + +/* 0x40 OFDM_COR_CTL */ +#define OFDM_COR_CTL (0x40) +#define COREACT (0x20) +#define HOLDSM (0x10) +#define WAIT_AGC (0x02) +#define WAIT_SYR (0x03) + +/* 0x41 OFDM_COR_STAT */ +#define OFDM_COR_STAT (0x41) +#define COR_STATUS (0x0F) +#define MONITOR_TPS (0x06) +#define TPSLOCKED (0x40) +#define AGCLOCKED (0x10) + +/* 0x42 OFDM_COR_INTEN */ +#define OFDM_COR_INTEN (0x42) +#define TPSRCVBAD (0x04) +#define TPSRCVCHANGED (0x02) +#define TPSRCVUPDATE (0x01) + +/* 0x43 OFDM_COR_INSTAT */ +#define OFDM_COR_INSTAT (0x43) + +/* 0x44 OFDM_COR_MODEGUARD */ +#define OFDM_COR_MODEGUARD (0x44) +#define FORCEMODE (0x08) +#define FORCEMODE8K (0x04) + +/* 0x45 OFDM_AGC_CTL */ +#define OFDM_AGC_CTL (0x45) +#define INITIAL_AGC_BW (0x08) +#define AGCNEG (0x02) +#define AGCLAST (0x10) + +/* 0x48 OFDM_AGC_TARGET */ +#define OFDM_AGC_TARGET (0x48) +#define OFDM_AGC_TARGET_DEFAULT (0x28) +#define OFDM_AGC_TARGET_IMPULSE (0x38) + +/* 0x49 OFDM_AGC_GAIN_1 */ +#define OFDM_AGC_GAIN_1 (0x49) + +/* 0x4B OFDM_ITB_CTL */ +#define OFDM_ITB_CTL (0x4B) +#define ITBINV (0x01) + +/* 0x49 AGC_GAIN_1 */ +#define AGC_GAIN_1 (0x49) + +/* 0x4A AGC_GAIN_2 */ +#define AGC_GAIN_2 (0x4A) + +/* 0x4C OFDM_ITB_FREQ_1 */ +#define OFDM_ITB_FREQ_1 (0x4C) + +/* 0x4D OFDM_ITB_FREQ_2 */ +#define OFDM_ITB_FREQ_2 (0x4D) + +/* 0x4E OFDM_CAS_CTL */ +#define OFDM_CAS_CTL (0x4E) +#define ACSDIS (0x40) +#define CCSEN (0x80) + +/* 0x4F CAS_FREQ */ +#define CAS_FREQ (0x4F) + +/* 0x51 OFDM_SYR_CTL */ +#define OFDM_SYR_CTL (0x51) +#define SIXTH_ENABLE (0x80) +#define SYR_TRACKING_DISABLE (0x01) + +/* 0x52 OFDM_SYR_STAT */ +#define OFDM_SYR_STAT (0x52) +#define GI14_2K_SYR_LOCK (0x13) +#define GI14_8K_SYR_LOCK (0x17) +#define GI14_SYR_LOCK (0x10) + +/* 0x55 OFDM_SYR_OFFSET_1 */ +#define OFDM_SYR_OFFSET_1 (0x55) + +/* 0x56 OFDM_SYR_OFFSET_2 */ +#define OFDM_SYR_OFFSET_2 (0x56) + +/* 0x58 OFDM_SCR_CTL */ +#define OFDM_SCR_CTL (0x58) +#define SYR_ADJ_DECAY_MASK (0x70) +#define SYR_ADJ_DECAY (0x30) + +/* 0x59 OFDM_PPM_CTL_1 */ +#define OFDM_PPM_CTL_1 (0x59) +#define PPMMAX_MASK (0x30) +#define PPM256 (0x30) + +/* 0x5B OFDM_TRL_NOMINALRATE_1 */ +#define OFDM_TRL_NOMINALRATE_1 (0x5B) + +/* 0x5C OFDM_TRL_NOMINALRATE_2 */ +#define OFDM_TRL_NOMINALRATE_2 (0x5C) + +/* 0x5D OFDM_TRL_TIME_1 */ +#define OFDM_TRL_TIME_1 (0x5D) + +/* 0x60 OFDM_CRL_FREQ_1 */ +#define OFDM_CRL_FREQ_1 (0x60) + +/* 0x63 OFDM_CHC_CTL_1 */ +#define OFDM_CHC_CTL_1 (0x63) +#define MANMEAN1 (0xF0); +#define CHCFIR (0x01) + +/* 0x64 OFDM_CHC_SNR */ +#define OFDM_CHC_SNR (0x64) + +/* 0x65 OFDM_BDI_CTL */ +#define OFDM_BDI_CTL (0x65) +#define LP_SELECT (0x02) + +/* 0x67 OFDM_TPS_RCVD_1 */ +#define OFDM_TPS_RCVD_1 (0x67) +#define TPSFRAME (0x03) + +/* 0x68 OFDM_TPS_RCVD_2 */ +#define OFDM_TPS_RCVD_2 (0x68) + +/* 0x69 OFDM_TPS_RCVD_3 */ +#define OFDM_TPS_RCVD_3 (0x69) + +/* 0x6A OFDM_TPS_RCVD_4 */ +#define OFDM_TPS_RCVD_4 (0x6A) + +/* 0x6B OFDM_TPS_RESERVED_1 */ +#define OFDM_TPS_RESERVED_1 (0x6B) + +/* 0x6C OFDM_TPS_RESERVED_2 */ +#define OFDM_TPS_RESERVED_2 (0x6C) + +/* 0x73 OFDM_MSC_REV */ +#define OFDM_MSC_REV (0x73) + +/* 0x76 OFDM_SNR_CARRIER_2 */ +#define OFDM_SNR_CARRIER_2 (0x76) +#define MEAN_MASK (0x80) +#define MEANBIT (0x80) + +/* 0x80 ANALOG_CONTROL_0 */ +#define ANALOG_CONTROL_0 (0x80) +#define POWER_DOWN_ADC (0x40) + +/* 0x81 ENABLE_TUNER_IIC */ +#define ENABLE_TUNER_IIC (0x81) +#define ENABLE_TUNER_BIT (0x01) + +/* 0x82 EN_DMD_RACQ */ +#define EN_DMD_RACQ (0x82) +#define EN_DMD_RACQ_REG_VAL (0x81) +#define EN_DMD_RACQ_REG_VAL_14 (0x01) + +/* 0x84 SNR_COMMAND */ +#define SNR_COMMAND (0x84) +#define SNRStat (0x80) + +/* 0x85 SNRCARRIERNUMBER_LSB */ +#define SNRCARRIERNUMBER_LSB (0x85) + +/* 0x87 SNRMINTHRESHOLD_LSB */ +#define SNRMINTHRESHOLD_LSB (0x87) + +/* 0x89 SNR_PER_CARRIER_LSB */ +#define SNR_PER_CARRIER_LSB (0x89) + +/* 0x8B SNRBELOWTHRESHOLD_LSB */ +#define SNRBELOWTHRESHOLD_LSB (0x8B) + +/* 0x91 RF_AGC_VAL_1 */ +#define RF_AGC_VAL_1 (0x91) + +/* 0x92 RF_AGC_STATUS */ +#define RF_AGC_STATUS (0x92) + +/* 0x98 DIAG_CONFIG */ +#define DIAG_CONFIG (0x98) +#define DIAG_MASK (0x70) +#define TB_SET (0x10) +#define TRAN_SELECT (0x07) +#define SERIAL_SELECT (0x01) + +/* 0x99 SUB_DIAG_MODE_SEL */ +#define SUB_DIAG_MODE_SEL (0x99) +#define CLKINVERSION (0x01) + +/* 0x9A TS_FORMAT */ +#define TS_FORMAT (0x9A) +#define ERROR_SENSE (0x08) +#define VALID_SENSE (0x04) +#define SYNC_SENSE (0x02) +#define GATED_CLOCK (0x01) + +#define NXT6000ASICDEVICE (0x0b) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51132.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51132.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51132.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51132.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,625 @@ +/* + * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM + * + * + * Copyright (C) 2007 Trent Piepho + * + * Copyright (C) 2005 Kirk Lapray + * + * Based on code from Jack Kelliher (kelliher@xmission.com) + * Copyright (C) 2002 & pcHDTV, inc. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * +*/ + +/* + * This driver needs two external firmware files. Please copy + * "dvb-fe-or51132-vsb.fw" and "dvb-fe-or51132-qam.fw" to + * /usr/lib/hotplug/firmware/ or /lib/firmware/ + * (depending on configuration of firmware hotplug). + */ +#define OR51132_VSB_FIRMWARE "dvb-fe-or51132-vsb.fw" +#define OR51132_QAM_FIRMWARE "dvb-fe-or51132-qam.fw" + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_math.h" +#include "dvb_frontend.h" +#include "or51132.h" + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "or51132: " args); \ + } while (0) + + +struct or51132_state +{ + struct i2c_adapter* i2c; + + /* Configuration settings */ + const struct or51132_config* config; + + struct dvb_frontend frontend; + + /* Demodulator private data */ + fe_modulation_t current_modulation; + u32 snr; /* Result of last SNR calculation */ + + /* Tuner private data */ + u32 current_frequency; +}; + + +/* Write buffer to demod */ +static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len) +{ + int err; + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = (u8*)buf, .len = len }; + + /* msleep(20); */ /* doesn't appear to be necessary */ + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n", + msg.addr, msg.len, err); + return -EREMOTEIO; + } + return 0; +} + +/* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00); + Less code and more efficient that loading a buffer on the stack with + the bytes to send and then calling or51132_writebuf() on that. */ +#define or51132_writebytes(state, data...) \ + ({ static const u8 _data[] = {data}; \ + or51132_writebuf(state, _data, sizeof(_data)); }) + +/* Read data from demod into buffer. Returns 0 on success. */ +static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len) +{ + int err; + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = I2C_M_RD, .buf = buf, .len = len }; + + /* msleep(20); */ /* doesn't appear to be necessary */ + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n", + msg.addr, msg.len, err); + return -EREMOTEIO; + } + return 0; +} + +/* Reads a 16-bit demod register. Returns <0 on error. */ +static int or51132_readreg(struct or51132_state *state, u8 reg) +{ + u8 buf[2] = { 0x04, reg }; + struct i2c_msg msg[2] = { + {.addr = state->config->demod_address, .flags = 0, + .buf = buf, .len = 2 }, + {.addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = buf, .len = 2 }}; + int err; + + if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) { + printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n", + reg, err); + return -EREMOTEIO; + } + return buf[0] | (buf[1] << 8); +} + +static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) +{ + struct or51132_state* state = fe->demodulator_priv; + static const u8 run_buf[] = {0x7F,0x01}; + u8 rec_buf[8]; + u32 firmwareAsize, firmwareBsize; + int i,ret; + + dprintk("Firmware is %Zd bytes\n",fw->size); + + /* Get size of firmware A and B */ + firmwareAsize = le32_to_cpu(*((__le32*)fw->data)); + dprintk("FirmwareA is %i bytes\n",firmwareAsize); + firmwareBsize = le32_to_cpu(*((__le32*)(fw->data+4))); + dprintk("FirmwareB is %i bytes\n",firmwareBsize); + + /* Upload firmware */ + if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) { + printk(KERN_WARNING "or51132: load_firmware error 1\n"); + return ret; + } + if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize], + firmwareBsize))) { + printk(KERN_WARNING "or51132: load_firmware error 2\n"); + return ret; + } + + if ((ret = or51132_writebuf(state, run_buf, 2))) { + printk(KERN_WARNING "or51132: load_firmware error 3\n"); + return ret; + } + if ((ret = or51132_writebuf(state, run_buf, 2))) { + printk(KERN_WARNING "or51132: load_firmware error 4\n"); + return ret; + } + + /* 50ms for operation to begin */ + msleep(50); + + /* Read back ucode version to besure we loaded correctly and are really up and running */ + /* Get uCode version */ + if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) { + printk(KERN_WARNING "or51132: load_firmware error a\n"); + return ret; + } + if ((ret = or51132_writebytes(state, 0x04, 0x17))) { + printk(KERN_WARNING "or51132: load_firmware error b\n"); + return ret; + } + if ((ret = or51132_writebytes(state, 0x00, 0x00))) { + printk(KERN_WARNING "or51132: load_firmware error c\n"); + return ret; + } + for (i=0;i<4;i++) { + /* Once upon a time, this command might have had something + to do with getting the firmware version, but it's + not used anymore: + {0x04,0x00,0x30,0x00,i+1} */ + /* Read 8 bytes, two bytes at a time */ + if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) { + printk(KERN_WARNING + "or51132: load_firmware error d - %d\n",i); + return ret; + } + } + + printk(KERN_WARNING + "or51132: Version: %02X%02X%02X%02X-%02X%02X%02X%02X (%02X%01X-%01X-%02X%01X-%01X)\n", + rec_buf[1],rec_buf[0],rec_buf[3],rec_buf[2], + rec_buf[5],rec_buf[4],rec_buf[7],rec_buf[6], + rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f, + rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f); + + if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) { + printk(KERN_WARNING "or51132: load_firmware error e\n"); + return ret; + } + return 0; +}; + +static int or51132_init(struct dvb_frontend* fe) +{ + return 0; +} + +static int or51132_read_ber(struct dvb_frontend* fe, u32* ber) +{ + *ber = 0; + return 0; +} + +static int or51132_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + *ucblocks = 0; + return 0; +} + +static int or51132_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int or51132_setmode(struct dvb_frontend* fe) +{ + struct or51132_state* state = fe->demodulator_priv; + u8 cmd_buf1[3] = {0x04, 0x01, 0x5f}; + u8 cmd_buf2[3] = {0x1c, 0x00, 0 }; + + dprintk("setmode %d\n",(int)state->current_modulation); + + switch (state->current_modulation) { + case VSB_8: + /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */ + cmd_buf1[2] = 0x50; + /* REC MODE inv IF spectrum, Normal */ + cmd_buf2[1] = 0x03; + /* Channel MODE ATSC/VSB8 */ + cmd_buf2[2] = 0x06; + break; + /* All QAM modes are: + Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high + REC MODE Normal Carrier Lock */ + case QAM_AUTO: + /* Channel MODE Auto QAM64/256 */ + cmd_buf2[2] = 0x4f; + break; + case QAM_256: + /* Channel MODE QAM256 */ + cmd_buf2[2] = 0x45; + break; + case QAM_64: + /* Channel MODE QAM64 */ + cmd_buf2[2] = 0x43; + break; + default: + printk(KERN_WARNING + "or51132: setmode: Modulation set to unsupported value (%d)\n", + state->current_modulation); + return -EINVAL; + } + + /* Set Receiver 1 register */ + if (or51132_writebuf(state, cmd_buf1, 3)) { + printk(KERN_WARNING "or51132: set_mode error 1\n"); + return -EREMOTEIO; + } + dprintk("set #1 to %02x\n", cmd_buf1[2]); + + /* Set operation mode in Receiver 6 register */ + if (or51132_writebuf(state, cmd_buf2, 3)) { + printk(KERN_WARNING "or51132: set_mode error 2\n"); + return -EREMOTEIO; + } + dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]); + + return 0; +} + +/* Some modulations use the same firmware. This classifies modulations + by the firmware they use. */ +#define MOD_FWCLASS_UNKNOWN 0 +#define MOD_FWCLASS_VSB 1 +#define MOD_FWCLASS_QAM 2 +static int modulation_fw_class(fe_modulation_t modulation) +{ + switch(modulation) { + case VSB_8: + return MOD_FWCLASS_VSB; + case QAM_AUTO: + case QAM_64: + case QAM_256: + return MOD_FWCLASS_QAM; + default: + return MOD_FWCLASS_UNKNOWN; + } +} + +static int or51132_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + int ret; + struct or51132_state* state = fe->demodulator_priv; + const struct firmware *fw; + const char *fwname; + int clock_mode; + + /* Upload new firmware only if we need a different one */ + if (modulation_fw_class(state->current_modulation) != + modulation_fw_class(param->u.vsb.modulation)) { + switch(modulation_fw_class(param->u.vsb.modulation)) { + case MOD_FWCLASS_VSB: + dprintk("set_parameters VSB MODE\n"); + fwname = OR51132_VSB_FIRMWARE; + + /* Set non-punctured clock for VSB */ + clock_mode = 0; + break; + case MOD_FWCLASS_QAM: + dprintk("set_parameters QAM MODE\n"); + fwname = OR51132_QAM_FIRMWARE; + + /* Set punctured clock for QAM */ + clock_mode = 1; + break; + default: + printk("or51132: Modulation type(%d) UNSUPPORTED\n", + param->u.vsb.modulation); + return -1; + } + printk("or51132: Waiting for firmware upload(%s)...\n", + fwname); + ret = request_firmware(&fw, fwname, state->i2c->dev.parent); + if (ret) { + printk(KERN_WARNING "or51132: No firmware up" + "loaded(timeout or file not found?)\n"); + return ret; + } + ret = or51132_load_firmware(fe, fw); + release_firmware(fw); + if (ret) { + printk(KERN_WARNING "or51132: Writing firmware to " + "device failed!\n"); + return ret; + } + printk("or51132: Firmware upload complete.\n"); + state->config->set_ts_params(fe, clock_mode); + } + /* Change only if we are actually changing the modulation */ + if (state->current_modulation != param->u.vsb.modulation) { + state->current_modulation = param->u.vsb.modulation; + or51132_setmode(fe); + } + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* Set to current mode */ + or51132_setmode(fe); + + /* Update current frequency */ + state->current_frequency = param->frequency; + return 0; +} + +static int or51132_get_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + struct or51132_state* state = fe->demodulator_priv; + int status; + int retry = 1; + +start: + /* Receiver Status */ + if ((status = or51132_readreg(state, 0x00)) < 0) { + printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n"); + return -EREMOTEIO; + } + switch(status&0xff) { + case 0x06: param->u.vsb.modulation = VSB_8; break; + case 0x43: param->u.vsb.modulation = QAM_64; break; + case 0x45: param->u.vsb.modulation = QAM_256; break; + default: + if (retry--) goto start; + printk(KERN_WARNING "or51132: unknown status 0x%02x\n", + status&0xff); + return -EREMOTEIO; + } + + /* FIXME: Read frequency from frontend, take AFC into account */ + param->frequency = state->current_frequency; + + /* FIXME: How to read inversion setting? Receiver 6 register? */ + param->inversion = INVERSION_AUTO; + + return 0; +} + +static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct or51132_state* state = fe->demodulator_priv; + int reg; + + /* Receiver Status */ + if ((reg = or51132_readreg(state, 0x00)) < 0) { + printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg); + *status = 0; + return -EREMOTEIO; + } + dprintk("%s: read_status %04x\n", __func__, reg); + + if (reg & 0x0100) /* Receiver Lock */ + *status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI| + FE_HAS_SYNC|FE_HAS_LOCK; + else + *status = 0; + return 0; +} + +/* Calculate SNR estimation (scaled by 2^24) + + 8-VSB SNR and QAM equations from Oren datasheets + + For 8-VSB: + SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) - K + + Where K = 0 if NTSC rejection filter is OFF; and + K = 3 if NTSC rejection filter is ON + + For QAM64: + SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) + + For QAM256: + SNR[dB] = 10 * log10(907832426.314266 / MSE^2 ) + + We re-write the snr equation as: + SNR * 2^24 = 10*(c - 2*intlog10(MSE)) + Where for QAM256, c = log10(907832426.314266) * 2^24 + and for 8-VSB and QAM64, c = log10(897152044.8282) * 2^24 */ + +static u32 calculate_snr(u32 mse, u32 c) +{ + if (mse == 0) /* No signal */ + return 0; + + mse = 2*intlog10(mse); + if (mse > c) { + /* Negative SNR, which is possible, but realisticly the + demod will lose lock before the signal gets this bad. The + API only allows for unsigned values, so just return 0 */ + return 0; + } + return 10*(c - mse); +} + +static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct or51132_state* state = fe->demodulator_priv; + int noise, reg; + u32 c, usK = 0; + int retry = 1; + +start: + /* SNR after Equalizer */ + noise = or51132_readreg(state, 0x02); + if (noise < 0) { + printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n"); + return -EREMOTEIO; + } + dprintk("read_snr noise (%d)\n", noise); + + /* Read status, contains modulation type for QAM_AUTO and + NTSC filter for VSB */ + reg = or51132_readreg(state, 0x00); + if (reg < 0) { + printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n"); + return -EREMOTEIO; + } + + switch (reg&0xff) { + case 0x06: + if (reg & 0x1000) usK = 3 << 24; + /* Fall through to QAM64 case */ + case 0x43: + c = 150204167; + break; + case 0x45: + c = 150290396; + break; + default: + printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff); + if (retry--) goto start; + return -EREMOTEIO; + } + dprintk("%s: modulation %02x, NTSC rej O%s\n", __func__, + reg&0xff, reg&0x1000?"n":"ff"); + + /* Calculate SNR using noise, c, and NTSC rejection correction */ + state->snr = calculate_snr(noise, c) - usK; + *snr = (state->snr) >> 16; + + dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, + state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); + + return 0; +} + +static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + /* Calculate Strength from SNR up to 35dB */ + /* Even though the SNR can go higher than 35dB, there is some comfort */ + /* factor in having a range of strong signals that can show at 100% */ + struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + u16 snr; + int ret; + + ret = fe->ops.read_snr(fe, &snr); + if (ret != 0) + return ret; + /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ + /* scale the range 0 - 35*2^24 into 0 - 65535 */ + if (state->snr >= 8960 * 0x10000) + *strength = 0xffff; + else + *strength = state->snr / 8960; + + return 0; +} + +static int or51132_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 500; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + + return 0; +} + +static void or51132_release(struct dvb_frontend* fe) +{ + struct or51132_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops or51132_ops; + +struct dvb_frontend* or51132_attach(const struct or51132_config* config, + struct i2c_adapter* i2c) +{ + struct or51132_state* state = NULL; + + /* Allocate memory for the internal state */ + state = kzalloc(sizeof(struct or51132_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + state->current_frequency = -1; + state->current_modulation = -1; + + /* Create dvb_frontend */ + memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +static struct dvb_frontend_ops or51132_ops = { + + .info = { + .name = "Oren OR51132 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min = 44000000, + .frequency_max = 958000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | + FE_CAN_8VSB + }, + + .release = or51132_release, + + .init = or51132_init, + .sleep = or51132_sleep, + + .set_frontend = or51132_set_parameters, + .get_frontend = or51132_get_parameters, + .get_tune_settings = or51132_get_tune_settings, + + .read_status = or51132_read_status, + .read_ber = or51132_read_ber, + .read_signal_strength = or51132_read_signal_strength, + .read_snr = or51132_read_snr, + .read_ucblocks = or51132_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver"); +MODULE_AUTHOR("Kirk Lapray"); +MODULE_AUTHOR("Trent Piepho"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(or51132_attach); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51132.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51132.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51132.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51132.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM + * + * Copyright (C) 2005 Kirk Lapray + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * +*/ + +#ifndef OR51132_H +#define OR51132_H + +#include +#include + +struct or51132_config +{ + /* The demodulator's i2c address */ + u8 demod_address; + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); +}; + +#if defined(CONFIG_DVB_OR51132) || (defined(CONFIG_DVB_OR51132_MODULE) && defined(MODULE)) +extern struct dvb_frontend* or51132_attach(const struct or51132_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* or51132_attach(const struct or51132_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_OR51132 + +#endif // OR51132_H + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51211.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51211.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51211.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51211.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,582 @@ +/* + * Support for OR51211 (pcHDTV HD-2000) - VSB + * + * Copyright (C) 2005 Kirk Lapray + * + * Based on code from Jack Kelliher (kelliher@xmission.com) + * Copyright (C) 2002 & pcHDTV, inc. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * +*/ + +/* + * This driver needs external firmware. Please use the command + * "/Documentation/dvb/get_dvb_firmware or51211" to + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). + */ +#define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw" + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_math.h" +#include "dvb_frontend.h" +#include "or51211.h" + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "or51211: " args); \ + } while (0) + +static u8 run_buf[] = {0x7f,0x01}; +static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC + +struct or51211_state { + + struct i2c_adapter* i2c; + + /* Configuration settings */ + const struct or51211_config* config; + + struct dvb_frontend frontend; + struct bt878* bt; + + /* Demodulator private data */ + u8 initialized:1; + u32 snr; /* Result of last SNR claculation */ + + /* Tuner private data */ + u32 current_frequency; +}; + +static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf, + int len) +{ + int err; + struct i2c_msg msg; + msg.addr = reg; + msg.flags = 0; + msg.len = len; + msg.buf = (u8 *)buf; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "or51211: i2c_writebytes error " + "(addr %02x, err == %i)\n", reg, err); + return -EREMOTEIO; + } + + return 0; +} + +static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len) +{ + int err; + struct i2c_msg msg; + msg.addr = reg; + msg.flags = I2C_M_RD; + msg.len = len; + msg.buf = buf; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "or51211: i2c_readbytes error " + "(addr %02x, err == %i)\n", reg, err); + return -EREMOTEIO; + } + + return 0; +} + +static int or51211_load_firmware (struct dvb_frontend* fe, + const struct firmware *fw) +{ + struct or51211_state* state = fe->demodulator_priv; + u8 tudata[585]; + int i; + + dprintk("Firmware is %zd bytes\n",fw->size); + + /* Get eprom data */ + tudata[0] = 17; + if (i2c_writebytes(state,0x50,tudata,1)) { + printk(KERN_WARNING "or51211:load_firmware error eprom addr\n"); + return -1; + } + if (i2c_readbytes(state,0x50,&tudata[145],192)) { + printk(KERN_WARNING "or51211: load_firmware error eprom\n"); + return -1; + } + + /* Create firmware buffer */ + for (i = 0; i < 145; i++) + tudata[i] = fw->data[i]; + + for (i = 0; i < 248; i++) + tudata[i+337] = fw->data[145+i]; + + state->config->reset(fe); + + if (i2c_writebytes(state,state->config->demod_address,tudata,585)) { + printk(KERN_WARNING "or51211: load_firmware error 1\n"); + return -1; + } + msleep(1); + + if (i2c_writebytes(state,state->config->demod_address, + &fw->data[393],8125)) { + printk(KERN_WARNING "or51211: load_firmware error 2\n"); + return -1; + } + msleep(1); + + if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { + printk(KERN_WARNING "or51211: load_firmware error 3\n"); + return -1; + } + + /* Wait at least 5 msec */ + msleep(10); + if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { + printk(KERN_WARNING "or51211: load_firmware error 4\n"); + return -1; + } + msleep(10); + + printk("or51211: Done.\n"); + return 0; +}; + +static int or51211_setmode(struct dvb_frontend* fe, int mode) +{ + struct or51211_state* state = fe->demodulator_priv; + u8 rec_buf[14]; + + state->config->setmode(fe, mode); + + if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { + printk(KERN_WARNING "or51211: setmode error 1\n"); + return -1; + } + + /* Wait at least 5 msec */ + msleep(10); + if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { + printk(KERN_WARNING "or51211: setmode error 2\n"); + return -1; + } + + msleep(10); + + /* Set operation mode in Receiver 1 register; + * type 1: + * data 0x50h Automatic sets receiver channel conditions + * Automatic NTSC rejection filter + * Enable MPEG serial data output + * MPEG2tr + * High tuner phase noise + * normal +/-150kHz Carrier acquisition range + */ + if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) { + printk(KERN_WARNING "or51211: setmode error 3\n"); + return -1; + } + + rec_buf[0] = 0x04; + rec_buf[1] = 0x00; + rec_buf[2] = 0x03; + rec_buf[3] = 0x00; + msleep(20); + if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) { + printk(KERN_WARNING "or51211: setmode error 5\n"); + } + msleep(3); + if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) { + printk(KERN_WARNING "or51211: setmode error 6"); + return -1; + } + dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]); + + return 0; +} + +static int or51211_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + struct or51211_state* state = fe->demodulator_priv; + + /* Change only if we are actually changing the channel */ + if (state->current_frequency != param->frequency) { + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* Set to ATSC mode */ + or51211_setmode(fe,0); + + /* Update current frequency */ + state->current_frequency = param->frequency; + } + return 0; +} + +static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct or51211_state* state = fe->demodulator_priv; + unsigned char rec_buf[2]; + unsigned char snd_buf[] = {0x04,0x00,0x03,0x00}; + *status = 0; + + /* Receiver Status */ + if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { + printk(KERN_WARNING "or51132: read_status write error\n"); + return -1; + } + msleep(3); + if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { + printk(KERN_WARNING "or51132: read_status read error\n"); + return -1; + } + dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]); + + if (rec_buf[0] & 0x01) { /* Receiver Lock */ + *status |= FE_HAS_SIGNAL; + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_LOCK; + } + return 0; +} + +/* Calculate SNR estimation (scaled by 2^24) + + 8-VSB SNR equation from Oren datasheets + + For 8-VSB: + SNR[dB] = 10 * log10(219037.9454 / MSE^2 ) + + We re-write the snr equation as: + SNR * 2^24 = 10*(c - 2*intlog10(MSE)) + Where for 8-VSB, c = log10(219037.9454) * 2^24 */ + +static u32 calculate_snr(u32 mse, u32 c) +{ + if (mse == 0) /* No signal */ + return 0; + + mse = 2*intlog10(mse); + if (mse > c) { + /* Negative SNR, which is possible, but realisticly the + demod will lose lock before the signal gets this bad. The + API only allows for unsigned values, so just return 0 */ + return 0; + } + return 10*(c - mse); +} + +static int or51211_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct or51211_state* state = fe->demodulator_priv; + u8 rec_buf[2]; + u8 snd_buf[3]; + + /* SNR after Equalizer */ + snd_buf[0] = 0x04; + snd_buf[1] = 0x00; + snd_buf[2] = 0x04; + + if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { + printk(KERN_WARNING "%s: error writing snr reg\n", + __func__); + return -1; + } + if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { + printk(KERN_WARNING "%s: read_status read error\n", + __func__); + return -1; + } + + state->snr = calculate_snr(rec_buf[0], 89599047); + *snr = (state->snr) >> 16; + + dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __func__, rec_buf[0], + state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); + + return 0; +} + +static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + /* Calculate Strength from SNR up to 35dB */ + /* Even though the SNR can go higher than 35dB, there is some comfort */ + /* factor in having a range of strong signals that can show at 100% */ + struct or51211_state* state = (struct or51211_state*)fe->demodulator_priv; + u16 snr; + int ret; + + ret = fe->ops.read_snr(fe, &snr); + if (ret != 0) + return ret; + /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ + /* scale the range 0 - 35*2^24 into 0 - 65535 */ + if (state->snr >= 8960 * 0x10000) + *strength = 0xffff; + else + *strength = state->snr / 8960; + + return 0; +} + +static int or51211_read_ber(struct dvb_frontend* fe, u32* ber) +{ + *ber = -ENOSYS; + return 0; +} + +static int or51211_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + *ucblocks = -ENOSYS; + return 0; +} + +static int or51211_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int or51211_init(struct dvb_frontend* fe) +{ + struct or51211_state* state = fe->demodulator_priv; + const struct or51211_config* config = state->config; + const struct firmware* fw; + unsigned char get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00}; + unsigned char rec_buf[14]; + int ret,i; + + if (!state->initialized) { + /* Request the firmware, this will block until it uploads */ + printk(KERN_INFO "or51211: Waiting for firmware upload " + "(%s)...\n", OR51211_DEFAULT_FIRMWARE); + ret = config->request_firmware(fe, &fw, + OR51211_DEFAULT_FIRMWARE); + printk(KERN_INFO "or51211:Got Hotplug firmware\n"); + if (ret) { + printk(KERN_WARNING "or51211: No firmware uploaded " + "(timeout or file not found?)\n"); + return ret; + } + + ret = or51211_load_firmware(fe, fw); + release_firmware(fw); + if (ret) { + printk(KERN_WARNING "or51211: Writing firmware to " + "device failed!\n"); + return ret; + } + printk(KERN_INFO "or51211: Firmware upload complete.\n"); + + /* Set operation mode in Receiver 1 register; + * type 1: + * data 0x50h Automatic sets receiver channel conditions + * Automatic NTSC rejection filter + * Enable MPEG serial data output + * MPEG2tr + * High tuner phase noise + * normal +/-150kHz Carrier acquisition range + */ + if (i2c_writebytes(state,state->config->demod_address, + cmd_buf,3)) { + printk(KERN_WARNING "or51211: Load DVR Error 5\n"); + return -1; + } + + /* Read back ucode version to besure we loaded correctly */ + /* and are really up and running */ + rec_buf[0] = 0x04; + rec_buf[1] = 0x00; + rec_buf[2] = 0x03; + rec_buf[3] = 0x00; + msleep(30); + if (i2c_writebytes(state,state->config->demod_address, + rec_buf,3)) { + printk(KERN_WARNING "or51211: Load DVR Error A\n"); + return -1; + } + msleep(3); + if (i2c_readbytes(state,state->config->demod_address, + &rec_buf[10],2)) { + printk(KERN_WARNING "or51211: Load DVR Error B\n"); + return -1; + } + + rec_buf[0] = 0x04; + rec_buf[1] = 0x00; + rec_buf[2] = 0x01; + rec_buf[3] = 0x00; + msleep(20); + if (i2c_writebytes(state,state->config->demod_address, + rec_buf,3)) { + printk(KERN_WARNING "or51211: Load DVR Error C\n"); + return -1; + } + msleep(3); + if (i2c_readbytes(state,state->config->demod_address, + &rec_buf[12],2)) { + printk(KERN_WARNING "or51211: Load DVR Error D\n"); + return -1; + } + + for (i = 0; i < 8; i++) + rec_buf[i]=0xed; + + for (i = 0; i < 5; i++) { + msleep(30); + get_ver_buf[4] = i+1; + if (i2c_writebytes(state,state->config->demod_address, + get_ver_buf,5)) { + printk(KERN_WARNING "or51211:Load DVR Error 6" + " - %d\n",i); + return -1; + } + msleep(3); + + if (i2c_readbytes(state,state->config->demod_address, + &rec_buf[i*2],2)) { + printk(KERN_WARNING "or51211:Load DVR Error 7" + " - %d\n",i); + return -1; + } + /* If we didn't receive the right index, try again */ + if ((int)rec_buf[i*2+1]!=i+1){ + i--; + } + } + dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n", + rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3], + rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7], + rec_buf[8], rec_buf[9]); + + printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x" + " Status %02x\n", + rec_buf[2], rec_buf[4],rec_buf[6], + rec_buf[12],rec_buf[10]); + + rec_buf[0] = 0x04; + rec_buf[1] = 0x00; + rec_buf[2] = 0x03; + rec_buf[3] = 0x00; + msleep(20); + if (i2c_writebytes(state,state->config->demod_address, + rec_buf,3)) { + printk(KERN_WARNING "or51211: Load DVR Error 8\n"); + return -1; + } + msleep(20); + if (i2c_readbytes(state,state->config->demod_address, + &rec_buf[8],2)) { + printk(KERN_WARNING "or51211: Load DVR Error 9\n"); + return -1; + } + state->initialized = 1; + } + + return 0; +} + +static int or51211_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 500; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static void or51211_release(struct dvb_frontend* fe) +{ + struct or51211_state* state = fe->demodulator_priv; + state->config->sleep(fe); + kfree(state); +} + +static struct dvb_frontend_ops or51211_ops; + +struct dvb_frontend* or51211_attach(const struct or51211_config* config, + struct i2c_adapter* i2c) +{ + struct or51211_state* state = NULL; + + /* Allocate memory for the internal state */ + state = kzalloc(sizeof(struct or51211_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + state->initialized = 0; + state->current_frequency = 0; + + /* Create dvb_frontend */ + memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +static struct dvb_frontend_ops or51211_ops = { + + .info = { + .name = "Oren OR51211 VSB Frontend", + .type = FE_ATSC, + .frequency_min = 44000000, + .frequency_max = 958000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_8VSB + }, + + .release = or51211_release, + + .init = or51211_init, + .sleep = or51211_sleep, + + .set_frontend = or51211_set_parameters, + .get_tune_settings = or51211_get_tune_settings, + + .read_status = or51211_read_status, + .read_ber = or51211_read_ber, + .read_signal_strength = or51211_read_signal_strength, + .read_snr = or51211_read_snr, + .read_ucblocks = or51211_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver"); +MODULE_AUTHOR("Kirk Lapray"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(or51211_attach); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51211.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51211.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51211.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/or51211.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Support for OR51211 (pcHDTV HD-2000) - VSB + * + * Copyright (C) 2005 Kirk Lapray + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * +*/ + +#ifndef OR51211_H +#define OR51211_H + +#include +#include + +struct or51211_config +{ + /* The demodulator's i2c address */ + u8 demod_address; + + /* Request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); + void (*setmode)(struct dvb_frontend * fe, int mode); + void (*reset)(struct dvb_frontend * fe); + void (*sleep)(struct dvb_frontend * fe); +}; + +#if defined(CONFIG_DVB_OR51211) || (defined(CONFIG_DVB_OR51211_MODULE) && defined(MODULE)) +extern struct dvb_frontend* or51211_attach(const struct or51211_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* or51211_attach(const struct or51211_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_OR51211 + +#endif // OR51211_H + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1409.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1409.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1409.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1409.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1001 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "s5h1409.h" + +struct s5h1409_state { + + struct i2c_adapter *i2c; + + /* configuration settings */ + const struct s5h1409_config *config; + + struct dvb_frontend frontend; + + /* previous uncorrected block counter */ + fe_modulation_t current_modulation; + + u32 current_frequency; + int if_freq; + + u32 is_qam_locked; + + /* QAM tuning state goes through the following state transitions */ +#define QAM_STATE_UNTUNED 0 +#define QAM_STATE_TUNING_STARTED 1 +#define QAM_STATE_INTERLEAVE_SET 2 +#define QAM_STATE_QAM_OPTIMIZED_L1 3 +#define QAM_STATE_QAM_OPTIMIZED_L2 4 +#define QAM_STATE_QAM_OPTIMIZED_L3 5 + u8 qam_state; +}; + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +#define dprintk if (debug) printk + +/* Register values to initialise the demod, this will set VSB by default */ +static struct init_tab { + u8 reg; + u16 data; +} init_tab[] = { + { 0x00, 0x0071, }, + { 0x01, 0x3213, }, + { 0x09, 0x0025, }, + { 0x1c, 0x001d, }, + { 0x1f, 0x002d, }, + { 0x20, 0x001d, }, + { 0x22, 0x0022, }, + { 0x23, 0x0020, }, + { 0x29, 0x110f, }, + { 0x2a, 0x10b4, }, + { 0x2b, 0x10ae, }, + { 0x2c, 0x0031, }, + { 0x31, 0x010d, }, + { 0x32, 0x0100, }, + { 0x44, 0x0510, }, + { 0x54, 0x0104, }, + { 0x58, 0x2222, }, + { 0x59, 0x1162, }, + { 0x5a, 0x3211, }, + { 0x5d, 0x0370, }, + { 0x5e, 0x0296, }, + { 0x61, 0x0010, }, + { 0x63, 0x4a00, }, + { 0x65, 0x0800, }, + { 0x71, 0x0003, }, + { 0x72, 0x0470, }, + { 0x81, 0x0002, }, + { 0x82, 0x0600, }, + { 0x86, 0x0002, }, + { 0x8a, 0x2c38, }, + { 0x8b, 0x2a37, }, + { 0x92, 0x302f, }, + { 0x93, 0x3332, }, + { 0x96, 0x000c, }, + { 0x99, 0x0101, }, + { 0x9c, 0x2e37, }, + { 0x9d, 0x2c37, }, + { 0x9e, 0x2c37, }, + { 0xab, 0x0100, }, + { 0xac, 0x1003, }, + { 0xad, 0x103f, }, + { 0xe2, 0x0100, }, + { 0xe3, 0x1000, }, + { 0x28, 0x1010, }, + { 0xb1, 0x000e, }, +}; + +/* VSB SNR lookup table */ +static struct vsb_snr_tab { + u16 val; + u16 data; +} vsb_snr_tab[] = { + { 924, 300, }, + { 923, 300, }, + { 918, 295, }, + { 915, 290, }, + { 911, 285, }, + { 906, 280, }, + { 901, 275, }, + { 896, 270, }, + { 891, 265, }, + { 885, 260, }, + { 879, 255, }, + { 873, 250, }, + { 864, 245, }, + { 858, 240, }, + { 850, 235, }, + { 841, 230, }, + { 832, 225, }, + { 823, 220, }, + { 812, 215, }, + { 802, 210, }, + { 788, 205, }, + { 778, 200, }, + { 767, 195, }, + { 753, 190, }, + { 740, 185, }, + { 725, 180, }, + { 707, 175, }, + { 689, 170, }, + { 671, 165, }, + { 656, 160, }, + { 637, 155, }, + { 616, 150, }, + { 542, 145, }, + { 519, 140, }, + { 507, 135, }, + { 497, 130, }, + { 492, 125, }, + { 474, 120, }, + { 300, 111, }, + { 0, 0, }, +}; + +/* QAM64 SNR lookup table */ +static struct qam64_snr_tab { + u16 val; + u16 data; +} qam64_snr_tab[] = { + { 1, 0, }, + { 12, 300, }, + { 15, 290, }, + { 18, 280, }, + { 22, 270, }, + { 23, 268, }, + { 24, 266, }, + { 25, 264, }, + { 27, 262, }, + { 28, 260, }, + { 29, 258, }, + { 30, 256, }, + { 32, 254, }, + { 33, 252, }, + { 34, 250, }, + { 35, 249, }, + { 36, 248, }, + { 37, 247, }, + { 38, 246, }, + { 39, 245, }, + { 40, 244, }, + { 41, 243, }, + { 42, 241, }, + { 43, 240, }, + { 44, 239, }, + { 45, 238, }, + { 46, 237, }, + { 47, 236, }, + { 48, 235, }, + { 49, 234, }, + { 50, 233, }, + { 51, 232, }, + { 52, 231, }, + { 53, 230, }, + { 55, 229, }, + { 56, 228, }, + { 57, 227, }, + { 58, 226, }, + { 59, 225, }, + { 60, 224, }, + { 62, 223, }, + { 63, 222, }, + { 65, 221, }, + { 66, 220, }, + { 68, 219, }, + { 69, 218, }, + { 70, 217, }, + { 72, 216, }, + { 73, 215, }, + { 75, 214, }, + { 76, 213, }, + { 78, 212, }, + { 80, 211, }, + { 81, 210, }, + { 83, 209, }, + { 84, 208, }, + { 85, 207, }, + { 87, 206, }, + { 89, 205, }, + { 91, 204, }, + { 93, 203, }, + { 95, 202, }, + { 96, 201, }, + { 104, 200, }, + { 255, 0, }, +}; + +/* QAM256 SNR lookup table */ +static struct qam256_snr_tab { + u16 val; + u16 data; +} qam256_snr_tab[] = { + { 1, 0, }, + { 12, 400, }, + { 13, 390, }, + { 15, 380, }, + { 17, 360, }, + { 19, 350, }, + { 22, 348, }, + { 23, 346, }, + { 24, 344, }, + { 25, 342, }, + { 26, 340, }, + { 27, 336, }, + { 28, 334, }, + { 29, 332, }, + { 30, 330, }, + { 31, 328, }, + { 32, 326, }, + { 33, 325, }, + { 34, 322, }, + { 35, 320, }, + { 37, 318, }, + { 39, 316, }, + { 40, 314, }, + { 41, 312, }, + { 42, 310, }, + { 43, 308, }, + { 46, 306, }, + { 47, 304, }, + { 49, 302, }, + { 51, 300, }, + { 53, 298, }, + { 54, 297, }, + { 55, 296, }, + { 56, 295, }, + { 57, 294, }, + { 59, 293, }, + { 60, 292, }, + { 61, 291, }, + { 63, 290, }, + { 64, 289, }, + { 65, 288, }, + { 66, 287, }, + { 68, 286, }, + { 69, 285, }, + { 71, 284, }, + { 72, 283, }, + { 74, 282, }, + { 75, 281, }, + { 76, 280, }, + { 77, 279, }, + { 78, 278, }, + { 81, 277, }, + { 83, 276, }, + { 84, 275, }, + { 86, 274, }, + { 87, 273, }, + { 89, 272, }, + { 90, 271, }, + { 92, 270, }, + { 93, 269, }, + { 95, 268, }, + { 96, 267, }, + { 98, 266, }, + { 100, 265, }, + { 102, 264, }, + { 104, 263, }, + { 105, 262, }, + { 106, 261, }, + { 110, 260, }, + { 255, 0, }, +}; + +/* 8 bit registers, 16 bit values */ +static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data) +{ + int ret; + u8 buf[] = { reg, data >> 8, data & 0xff }; + + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 3 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0, 0 }; + + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 2 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk("%s: readreg error (ret == %i)\n", __func__, ret); + return (b1[0] << 8) | b1[1]; +} + +static int s5h1409_softreset(struct dvb_frontend *fe) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + dprintk("%s()\n", __func__); + + s5h1409_writereg(state, 0xf5, 0); + s5h1409_writereg(state, 0xf5, 1); + state->is_qam_locked = 0; + state->qam_state = QAM_STATE_UNTUNED; + return 0; +} + +#define S5H1409_VSB_IF_FREQ 5380 +#define S5H1409_QAM_IF_FREQ (state->config->qam_if) + +static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + dprintk("%s(%d KHz)\n", __func__, KHz); + + switch (KHz) { + case 4000: + s5h1409_writereg(state, 0x87, 0x014b); + s5h1409_writereg(state, 0x88, 0x0cb5); + s5h1409_writereg(state, 0x89, 0x03e2); + break; + case 5380: + case 44000: + default: + s5h1409_writereg(state, 0x87, 0x01be); + s5h1409_writereg(state, 0x88, 0x0436); + s5h1409_writereg(state, 0x89, 0x054d); + break; + } + state->if_freq = KHz; + + return 0; +} + +static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __func__, inverted); + + if (inverted == 1) + return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ + else + return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ +} + +static int s5h1409_enable_modulation(struct dvb_frontend *fe, + fe_modulation_t m) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + dprintk("%s(0x%08x)\n", __func__, m); + + switch (m) { + case VSB_8: + dprintk("%s() VSB_8\n", __func__); + if (state->if_freq != S5H1409_VSB_IF_FREQ) + s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ); + s5h1409_writereg(state, 0xf4, 0); + break; + case QAM_64: + case QAM_256: + case QAM_AUTO: + dprintk("%s() QAM_AUTO (64/256)\n", __func__); + if (state->if_freq != S5H1409_QAM_IF_FREQ) + s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ); + s5h1409_writereg(state, 0xf4, 1); + s5h1409_writereg(state, 0x85, 0x110); + break; + default: + dprintk("%s() Invalid modulation\n", __func__); + return -EINVAL; + } + + state->current_modulation = m; + s5h1409_softreset(fe); + + return 0; +} + +static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __func__, enable); + + if (enable) + return s5h1409_writereg(state, 0xf3, 1); + else + return s5h1409_writereg(state, 0xf3, 0); +} + +static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __func__, enable); + + if (enable) + return s5h1409_writereg(state, 0xe3, + s5h1409_readreg(state, 0xe3) | 0x1100); + else + return s5h1409_writereg(state, 0xe3, + s5h1409_readreg(state, 0xe3) & 0xfeff); +} + +static int s5h1409_sleep(struct dvb_frontend *fe, int enable) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __func__, enable); + + return s5h1409_writereg(state, 0xf2, enable); +} + +static int s5h1409_register_reset(struct dvb_frontend *fe) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + dprintk("%s()\n", __func__); + + return s5h1409_writereg(state, 0xfa, 0); +} + +static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 reg; + + if (state->qam_state < QAM_STATE_INTERLEAVE_SET) { + /* We should not perform amhum optimization until + the interleave mode has been configured */ + return; + } + + if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) { + /* We've already reached the maximum optimization level, so + dont bother banging on the status registers */ + return; + } + + /* QAM EQ lock check */ + reg = s5h1409_readreg(state, 0xf0); + + if ((reg >> 13) & 0x1) { + reg &= 0xff; + + s5h1409_writereg(state, 0x96, 0x000c); + if (reg < 0x68) { + if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L3) { + dprintk("%s() setting QAM state to OPT_L3\n", + __func__); + s5h1409_writereg(state, 0x93, 0x3130); + s5h1409_writereg(state, 0x9e, 0x2836); + state->qam_state = QAM_STATE_QAM_OPTIMIZED_L3; + } + } else { + if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L2) { + dprintk("%s() setting QAM state to OPT_L2\n", + __func__); + s5h1409_writereg(state, 0x93, 0x3332); + s5h1409_writereg(state, 0x9e, 0x2c37); + state->qam_state = QAM_STATE_QAM_OPTIMIZED_L2; + } + } + + } else { + if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L1) { + dprintk("%s() setting QAM state to OPT_L1\n", __func__); + s5h1409_writereg(state, 0x96, 0x0008); + s5h1409_writereg(state, 0x93, 0x3332); + s5h1409_writereg(state, 0x9e, 0x2c37); + state->qam_state = QAM_STATE_QAM_OPTIMIZED_L1; + } + } +} + +static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 reg; + + if (state->is_qam_locked) + return; + + /* QAM EQ lock check */ + reg = s5h1409_readreg(state, 0xf0); + + if ((reg >> 13) & 0x1) { + + state->is_qam_locked = 1; + reg &= 0xff; + + s5h1409_writereg(state, 0x96, 0x00c); + if ((reg < 0x38) || (reg > 0x68)) { + s5h1409_writereg(state, 0x93, 0x3332); + s5h1409_writereg(state, 0x9e, 0x2c37); + } else { + s5h1409_writereg(state, 0x93, 0x3130); + s5h1409_writereg(state, 0x9e, 0x2836); + } + + } else { + s5h1409_writereg(state, 0x96, 0x0008); + s5h1409_writereg(state, 0x93, 0x3332); + s5h1409_writereg(state, 0x9e, 0x2c37); + } +} + +static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 reg, reg1, reg2; + + if (state->qam_state >= QAM_STATE_INTERLEAVE_SET) { + /* We've done the optimization already */ + return; + } + + reg = s5h1409_readreg(state, 0xf1); + + /* Master lock */ + if ((reg >> 15) & 0x1) { + if (state->qam_state == QAM_STATE_UNTUNED || + state->qam_state == QAM_STATE_TUNING_STARTED) { + dprintk("%s() setting QAM state to INTERLEAVE_SET\n", + __func__); + reg1 = s5h1409_readreg(state, 0xb2); + reg2 = s5h1409_readreg(state, 0xad); + + s5h1409_writereg(state, 0x96, 0x0020); + s5h1409_writereg(state, 0xad, + (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff))); + state->qam_state = QAM_STATE_INTERLEAVE_SET; + } + } else { + if (state->qam_state == QAM_STATE_UNTUNED) { + dprintk("%s() setting QAM state to TUNING_STARTED\n", + __func__); + s5h1409_writereg(state, 0x96, 0x08); + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) | 0x1001); + state->qam_state = QAM_STATE_TUNING_STARTED; + } + } +} + +static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 reg, reg1, reg2; + + reg = s5h1409_readreg(state, 0xf1); + + /* Master lock */ + if ((reg >> 15) & 0x1) { + if (state->qam_state != 2) { + state->qam_state = 2; + reg1 = s5h1409_readreg(state, 0xb2); + reg2 = s5h1409_readreg(state, 0xad); + + s5h1409_writereg(state, 0x96, 0x20); + s5h1409_writereg(state, 0xad, + (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff))); + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) & 0xeffe); + } + } else { + if (state->qam_state != 1) { + state->qam_state = 1; + s5h1409_writereg(state, 0x96, 0x08); + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) | 0x1001); + } + } +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +static int s5h1409_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + dprintk("%s(frequency=%d)\n", __func__, p->frequency); + + s5h1409_softreset(fe); + + state->current_frequency = p->frequency; + + s5h1409_enable_modulation(fe, p->u.vsb.modulation); + + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* Issue a reset to the demod so it knows to resync against the + newly tuned frequency */ + s5h1409_softreset(fe); + + /* Optimize the demod for QAM */ + if (state->current_modulation != VSB_8) { + /* This almost certainly applies to all boards, but for now + only do it for the HVR-1600. Once the other boards are + tested, the "legacy" versions can just go away */ + if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) { + s5h1409_set_qam_interleave_mode(fe); + s5h1409_set_qam_amhum_mode(fe); + } else { + s5h1409_set_qam_amhum_mode_legacy(fe); + s5h1409_set_qam_interleave_mode_legacy(fe); + } + } + + return 0; +} + +static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __func__, mode); + + val = s5h1409_readreg(state, 0xac) & 0xcfff; + switch (mode) { + case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: + val |= 0x0000; + break; + case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: + dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); + val |= 0x1000; + break; + case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: + val |= 0x2000; + break; + case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: + val |= 0x3000; + break; + default: + return -EINVAL; + } + + /* Configure MPEG Signal Timing charactistics */ + return s5h1409_writereg(state, 0xac, val); +} + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +static int s5h1409_init(struct dvb_frontend *fe) +{ + int i; + + struct s5h1409_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + + s5h1409_sleep(fe, 0); + s5h1409_register_reset(fe); + + for (i = 0; i < ARRAY_SIZE(init_tab); i++) + s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data); + + /* The datasheet says that after initialisation, VSB is default */ + state->current_modulation = VSB_8; + + /* Optimize for the HVR-1600 if appropriate. Note that some of these + may get folded into the generic case after testing with other + devices */ + if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) { + /* VSB AGC REF */ + s5h1409_writereg(state, 0x09, 0x0050); + + /* Unknown but Windows driver does it... */ + s5h1409_writereg(state, 0x21, 0x0001); + s5h1409_writereg(state, 0x50, 0x030e); + + /* QAM AGC REF */ + s5h1409_writereg(state, 0x82, 0x0800); + } + + if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ + else + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */ + + s5h1409_set_spectralinversion(fe, state->config->inversion); + s5h1409_set_if_freq(fe, state->if_freq); + s5h1409_set_gpio(fe, state->config->gpio); + s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing); + s5h1409_softreset(fe); + + /* Note: Leaving the I2C gate closed. */ + s5h1409_i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 reg; + u32 tuner_status = 0; + + *status = 0; + + /* Optimize the demod for QAM */ + if (state->current_modulation != VSB_8) { + /* This almost certainly applies to all boards, but for now + only do it for the HVR-1600. Once the other boards are + tested, the "legacy" versions can just go away */ + if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) { + s5h1409_set_qam_interleave_mode(fe); + s5h1409_set_qam_amhum_mode(fe); + } + } + + /* Get the demodulator status */ + reg = s5h1409_readreg(state, 0xf1); + if (reg & 0x1000) + *status |= FE_HAS_VITERBI; + if (reg & 0x8000) + *status |= FE_HAS_LOCK | FE_HAS_SYNC; + + switch (state->config->status_mode) { + case S5H1409_DEMODLOCKING: + if (*status & FE_HAS_VITERBI) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + case S5H1409_TUNERLOCKING: + /* Get the tuner status */ + if (fe->ops.tuner_ops.get_status) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + fe->ops.tuner_ops.get_status(fe, &tuner_status); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + if (tuner_status) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + } + + dprintk("%s() status 0x%08x\n", __func__, *status); + + return 0; +} + +static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __func__); + + for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) { + if (v < qam256_snr_tab[i].val) { + *snr = qam256_snr_tab[i].data; + ret = 0; + break; + } + } + return ret; +} + +static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __func__); + + for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) { + if (v < qam64_snr_tab[i].val) { + *snr = qam64_snr_tab[i].data; + ret = 0; + break; + } + } + return ret; +} + +static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __func__); + + for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) { + if (v > vsb_snr_tab[i].val) { + *snr = vsb_snr_tab[i].data; + ret = 0; + break; + } + } + dprintk("%s() snr=%d\n", __func__, *snr); + return ret; +} + +static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 reg; + dprintk("%s()\n", __func__); + + switch (state->current_modulation) { + case QAM_64: + reg = s5h1409_readreg(state, 0xf0) & 0xff; + return s5h1409_qam64_lookup_snr(fe, snr, reg); + case QAM_256: + reg = s5h1409_readreg(state, 0xf0) & 0xff; + return s5h1409_qam256_lookup_snr(fe, snr, reg); + case VSB_8: + reg = s5h1409_readreg(state, 0xf1) & 0x3ff; + return s5h1409_vsb_lookup_snr(fe, snr, reg); + default: + break; + } + + return -EINVAL; +} + +static int s5h1409_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + return s5h1409_read_snr(fe, signal_strength); +} + +static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + *ucblocks = s5h1409_readreg(state, 0xb5); + + return 0; +} + +static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + return s5h1409_read_ucblocks(fe, ber); +} + +static int s5h1409_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct s5h1409_state *state = fe->demodulator_priv; + + p->frequency = state->current_frequency; + p->u.vsb.modulation = state->current_modulation; + + return 0; +} + +static int s5h1409_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void s5h1409_release(struct dvb_frontend *fe) +{ + struct s5h1409_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops s5h1409_ops; + +struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, + struct i2c_adapter *i2c) +{ + struct s5h1409_state *state = NULL; + u16 reg; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct s5h1409_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->current_modulation = 0; + state->if_freq = S5H1409_VSB_IF_FREQ; + + /* check if the demod exists */ + reg = s5h1409_readreg(state, 0x04); + if ((reg != 0x0066) && (reg != 0x007f)) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &s5h1409_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + if (s5h1409_init(&state->frontend) != 0) { + printk(KERN_ERR "%s: Failed to initialize correctly\n", + __func__); + goto error; + } + + /* Note: Leaving the I2C gate open here. */ + s5h1409_i2c_gate_ctrl(&state->frontend, 1); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(s5h1409_attach); + +static struct dvb_frontend_ops s5h1409_ops = { + + .info = { + .name = "Samsung S5H1409 QAM/8VSB Frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .init = s5h1409_init, + .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl, + .set_frontend = s5h1409_set_frontend, + .get_frontend = s5h1409_get_frontend, + .get_tune_settings = s5h1409_get_tune_settings, + .read_status = s5h1409_read_status, + .read_ber = s5h1409_read_ber, + .read_signal_strength = s5h1409_read_signal_strength, + .read_snr = s5h1409_read_snr, + .read_ucblocks = s5h1409_read_ucblocks, + .release = s5h1409_release, +}; + +MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + + +/* + * Local variables: + * c-basic-offset: 8 + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1409.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1409.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1409.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1409.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __S5H1409_H__ +#define __S5H1409_H__ + +#include + +struct s5h1409_config { + /* the demodulator's i2c address */ + u8 demod_address; + + /* serial/parallel output */ +#define S5H1409_PARALLEL_OUTPUT 0 +#define S5H1409_SERIAL_OUTPUT 1 + u8 output_mode; + + /* GPIO Setting */ +#define S5H1409_GPIO_OFF 0 +#define S5H1409_GPIO_ON 1 + u8 gpio; + + /* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */ + u16 qam_if; + + /* Spectral Inversion */ +#define S5H1409_INVERSION_OFF 0 +#define S5H1409_INVERSION_ON 1 + u8 inversion; + + /* Return lock status based on tuner lock, or demod lock */ +#define S5H1409_TUNERLOCKING 0 +#define S5H1409_DEMODLOCKING 1 + u8 status_mode; + + /* MPEG signal timing */ +#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 +#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 +#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 +#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 + u16 mpeg_timing; + + /* HVR-1600 optimizations (to better work with MXL5005s) + Note: some of these are likely to be folded into the generic driver + after being regression tested with other boards */ +#define S5H1409_HVR1600_NOOPTIMIZE 0 +#define S5H1409_HVR1600_OPTIMIZE 1 + u8 hvr1600_opt; +}; + +#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *s5h1409_attach( + const struct s5h1409_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_S5H1409 */ + +#endif /* __S5H1409_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1411.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1411.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1411.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1411.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,923 @@ +/* + Samsung S5H1411 VSB/QAM demodulator driver + + Copyright (C) 2008 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "s5h1411.h" + +struct s5h1411_state { + + struct i2c_adapter *i2c; + + /* configuration settings */ + const struct s5h1411_config *config; + + struct dvb_frontend frontend; + + fe_modulation_t current_modulation; + unsigned int first_tune:1; + + u32 current_frequency; + int if_freq; + + u8 inversion; +}; + +static int debug; + +#define dprintk(arg...) do { \ + if (debug) \ + printk(arg); \ + } while (0) + +/* Register values to initialise the demod, defaults to VSB */ +static struct init_tab { + u8 addr; + u8 reg; + u16 data; +} init_tab[] = { + { S5H1411_I2C_TOP_ADDR, 0x00, 0x0071, }, + { S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, }, + { S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, }, + { S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, }, + { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342c, }, + { S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, }, + { S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, }, + { S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, }, + { S5H1411_I2C_TOP_ADDR, 0x27, 0x0f04, }, + { S5H1411_I2C_TOP_ADDR, 0x28, 0x070f, }, + { S5H1411_I2C_TOP_ADDR, 0x29, 0x2820, }, + { S5H1411_I2C_TOP_ADDR, 0x2a, 0x102e, }, + { S5H1411_I2C_TOP_ADDR, 0x2b, 0x0220, }, + { S5H1411_I2C_TOP_ADDR, 0x2e, 0x0d0e, }, + { S5H1411_I2C_TOP_ADDR, 0x2f, 0x1013, }, + { S5H1411_I2C_TOP_ADDR, 0x31, 0x171b, }, + { S5H1411_I2C_TOP_ADDR, 0x32, 0x0e0f, }, + { S5H1411_I2C_TOP_ADDR, 0x33, 0x0f10, }, + { S5H1411_I2C_TOP_ADDR, 0x34, 0x170e, }, + { S5H1411_I2C_TOP_ADDR, 0x35, 0x4b10, }, + { S5H1411_I2C_TOP_ADDR, 0x36, 0x0f17, }, + { S5H1411_I2C_TOP_ADDR, 0x3c, 0x1577, }, + { S5H1411_I2C_TOP_ADDR, 0x3d, 0x081a, }, + { S5H1411_I2C_TOP_ADDR, 0x3e, 0x77ee, }, + { S5H1411_I2C_TOP_ADDR, 0x40, 0x1e09, }, + { S5H1411_I2C_TOP_ADDR, 0x41, 0x0f0c, }, + { S5H1411_I2C_TOP_ADDR, 0x42, 0x1f10, }, + { S5H1411_I2C_TOP_ADDR, 0x4d, 0x0509, }, + { S5H1411_I2C_TOP_ADDR, 0x4e, 0x0a00, }, + { S5H1411_I2C_TOP_ADDR, 0x50, 0x0000, }, + { S5H1411_I2C_TOP_ADDR, 0x5b, 0x0000, }, + { S5H1411_I2C_TOP_ADDR, 0x5c, 0x0008, }, + { S5H1411_I2C_TOP_ADDR, 0x57, 0x1101, }, + { S5H1411_I2C_TOP_ADDR, 0x65, 0x007c, }, + { S5H1411_I2C_TOP_ADDR, 0x68, 0x0512, }, + { S5H1411_I2C_TOP_ADDR, 0x69, 0x0258, }, + { S5H1411_I2C_TOP_ADDR, 0x70, 0x0004, }, + { S5H1411_I2C_TOP_ADDR, 0x71, 0x0007, }, + { S5H1411_I2C_TOP_ADDR, 0x76, 0x00a9, }, + { S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, }, + { S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, }, + { S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, }, + { S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, }, + { S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, }, + { S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, }, + { S5H1411_I2C_TOP_ADDR, 0xb8, 0x003f, }, + { S5H1411_I2C_TOP_ADDR, 0xb9, 0x2700, }, + { S5H1411_I2C_TOP_ADDR, 0xba, 0xfac8, }, + { S5H1411_I2C_TOP_ADDR, 0xbe, 0x1003, }, + { S5H1411_I2C_TOP_ADDR, 0xbf, 0x103f, }, + { S5H1411_I2C_TOP_ADDR, 0xce, 0x2000, }, + { S5H1411_I2C_TOP_ADDR, 0xcf, 0x0800, }, + { S5H1411_I2C_TOP_ADDR, 0xd0, 0x0800, }, + { S5H1411_I2C_TOP_ADDR, 0xd1, 0x0400, }, + { S5H1411_I2C_TOP_ADDR, 0xd2, 0x0800, }, + { S5H1411_I2C_TOP_ADDR, 0xd3, 0x2000, }, + { S5H1411_I2C_TOP_ADDR, 0xd4, 0x3000, }, + { S5H1411_I2C_TOP_ADDR, 0xdb, 0x4a9b, }, + { S5H1411_I2C_TOP_ADDR, 0xdc, 0x1000, }, + { S5H1411_I2C_TOP_ADDR, 0xde, 0x0001, }, + { S5H1411_I2C_TOP_ADDR, 0xdf, 0x0000, }, + { S5H1411_I2C_TOP_ADDR, 0xe3, 0x0301, }, + { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0000, }, + { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0001, }, + { S5H1411_I2C_QAM_ADDR, 0x08, 0x0600, }, + { S5H1411_I2C_QAM_ADDR, 0x18, 0x4201, }, + { S5H1411_I2C_QAM_ADDR, 0x1e, 0x6476, }, + { S5H1411_I2C_QAM_ADDR, 0x21, 0x0830, }, + { S5H1411_I2C_QAM_ADDR, 0x0c, 0x5679, }, + { S5H1411_I2C_QAM_ADDR, 0x0d, 0x579b, }, + { S5H1411_I2C_QAM_ADDR, 0x24, 0x0102, }, + { S5H1411_I2C_QAM_ADDR, 0x31, 0x7488, }, + { S5H1411_I2C_QAM_ADDR, 0x32, 0x0a08, }, + { S5H1411_I2C_QAM_ADDR, 0x3d, 0x8689, }, + { S5H1411_I2C_QAM_ADDR, 0x49, 0x0048, }, + { S5H1411_I2C_QAM_ADDR, 0x57, 0x2012, }, + { S5H1411_I2C_QAM_ADDR, 0x5d, 0x7676, }, + { S5H1411_I2C_QAM_ADDR, 0x04, 0x0400, }, + { S5H1411_I2C_QAM_ADDR, 0x58, 0x00c0, }, + { S5H1411_I2C_QAM_ADDR, 0x5b, 0x0100, }, +}; + +/* VSB SNR lookup table */ +static struct vsb_snr_tab { + u16 val; + u16 data; +} vsb_snr_tab[] = { + { 0x39f, 300, }, + { 0x39b, 295, }, + { 0x397, 290, }, + { 0x394, 285, }, + { 0x38f, 280, }, + { 0x38b, 275, }, + { 0x387, 270, }, + { 0x382, 265, }, + { 0x37d, 260, }, + { 0x377, 255, }, + { 0x370, 250, }, + { 0x36a, 245, }, + { 0x364, 240, }, + { 0x35b, 235, }, + { 0x353, 230, }, + { 0x349, 225, }, + { 0x340, 320, }, + { 0x337, 215, }, + { 0x327, 210, }, + { 0x31b, 205, }, + { 0x310, 200, }, + { 0x302, 195, }, + { 0x2f3, 190, }, + { 0x2e4, 185, }, + { 0x2d7, 180, }, + { 0x2cd, 175, }, + { 0x2bb, 170, }, + { 0x2a9, 165, }, + { 0x29e, 160, }, + { 0x284, 155, }, + { 0x27a, 150, }, + { 0x260, 145, }, + { 0x23a, 140, }, + { 0x224, 135, }, + { 0x213, 130, }, + { 0x204, 125, }, + { 0x1fe, 120, }, + { 0, 0, }, +}; + +/* QAM64 SNR lookup table */ +static struct qam64_snr_tab { + u16 val; + u16 data; +} qam64_snr_tab[] = { + { 0x0001, 0, }, + { 0x0af0, 300, }, + { 0x0d80, 290, }, + { 0x10a0, 280, }, + { 0x14b5, 270, }, + { 0x1590, 268, }, + { 0x1680, 266, }, + { 0x17b0, 264, }, + { 0x18c0, 262, }, + { 0x19b0, 260, }, + { 0x1ad0, 258, }, + { 0x1d00, 256, }, + { 0x1da0, 254, }, + { 0x1ef0, 252, }, + { 0x2050, 250, }, + { 0x20f0, 249, }, + { 0x21d0, 248, }, + { 0x22b0, 247, }, + { 0x23a0, 246, }, + { 0x2470, 245, }, + { 0x24f0, 244, }, + { 0x25a0, 243, }, + { 0x26c0, 242, }, + { 0x27b0, 241, }, + { 0x28d0, 240, }, + { 0x29b0, 239, }, + { 0x2ad0, 238, }, + { 0x2ba0, 237, }, + { 0x2c80, 236, }, + { 0x2d20, 235, }, + { 0x2e00, 234, }, + { 0x2f10, 233, }, + { 0x3050, 232, }, + { 0x3190, 231, }, + { 0x3300, 230, }, + { 0x3340, 229, }, + { 0x3200, 228, }, + { 0x3550, 227, }, + { 0x3610, 226, }, + { 0x3600, 225, }, + { 0x3700, 224, }, + { 0x3800, 223, }, + { 0x3920, 222, }, + { 0x3a20, 221, }, + { 0x3b30, 220, }, + { 0x3d00, 219, }, + { 0x3e00, 218, }, + { 0x4000, 217, }, + { 0x4100, 216, }, + { 0x4300, 215, }, + { 0x4400, 214, }, + { 0x4600, 213, }, + { 0x4700, 212, }, + { 0x4800, 211, }, + { 0x4a00, 210, }, + { 0x4b00, 209, }, + { 0x4d00, 208, }, + { 0x4f00, 207, }, + { 0x5050, 206, }, + { 0x5200, 205, }, + { 0x53c0, 204, }, + { 0x5450, 203, }, + { 0x5650, 202, }, + { 0x5820, 201, }, + { 0x6000, 200, }, + { 0xffff, 0, }, +}; + +/* QAM256 SNR lookup table */ +static struct qam256_snr_tab { + u16 val; + u16 data; +} qam256_snr_tab[] = { + { 0x0001, 0, }, + { 0x0970, 400, }, + { 0x0a90, 390, }, + { 0x0b90, 380, }, + { 0x0d90, 370, }, + { 0x0ff0, 360, }, + { 0x1240, 350, }, + { 0x1345, 348, }, + { 0x13c0, 346, }, + { 0x14c0, 344, }, + { 0x1500, 342, }, + { 0x1610, 340, }, + { 0x1700, 338, }, + { 0x1800, 336, }, + { 0x18b0, 334, }, + { 0x1900, 332, }, + { 0x1ab0, 330, }, + { 0x1bc0, 328, }, + { 0x1cb0, 326, }, + { 0x1db0, 324, }, + { 0x1eb0, 322, }, + { 0x2030, 320, }, + { 0x2200, 318, }, + { 0x2280, 316, }, + { 0x2410, 314, }, + { 0x25b0, 312, }, + { 0x27a0, 310, }, + { 0x2840, 308, }, + { 0x29d0, 306, }, + { 0x2b10, 304, }, + { 0x2d30, 302, }, + { 0x2f20, 300, }, + { 0x30c0, 298, }, + { 0x3260, 297, }, + { 0x32c0, 296, }, + { 0x3300, 295, }, + { 0x33b0, 294, }, + { 0x34b0, 293, }, + { 0x35a0, 292, }, + { 0x3650, 291, }, + { 0x3800, 290, }, + { 0x3900, 289, }, + { 0x3a50, 288, }, + { 0x3b30, 287, }, + { 0x3cb0, 286, }, + { 0x3e20, 285, }, + { 0x3fa0, 284, }, + { 0x40a0, 283, }, + { 0x41c0, 282, }, + { 0x42f0, 281, }, + { 0x44a0, 280, }, + { 0x4600, 279, }, + { 0x47b0, 278, }, + { 0x4900, 277, }, + { 0x4a00, 276, }, + { 0x4ba0, 275, }, + { 0x4d00, 274, }, + { 0x4f00, 273, }, + { 0x5000, 272, }, + { 0x51f0, 272, }, + { 0x53a0, 270, }, + { 0x5520, 269, }, + { 0x5700, 268, }, + { 0x5800, 267, }, + { 0x5a00, 266, }, + { 0x5c00, 265, }, + { 0x5d00, 264, }, + { 0x5f00, 263, }, + { 0x6000, 262, }, + { 0x6200, 261, }, + { 0x6400, 260, }, + { 0xffff, 0, }, +}; + +/* 8 bit registers, 16 bit values */ +static int s5h1411_writereg(struct s5h1411_state *state, + u8 addr, u8 reg, u16 data) +{ + int ret; + u8 buf[] = { reg, data >> 8, data & 0xff }; + + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, " + "ret == %i)\n", __func__, addr, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0, 0 }; + + struct i2c_msg msg[] = { + { .addr = addr, .flags = 0, .buf = b0, .len = 1 }, + { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk(KERN_ERR "%s: readreg error (ret == %i)\n", + __func__, ret); + return (b1[0] << 8) | b1[1]; +} + +static int s5h1411_softreset(struct dvb_frontend *fe) +{ + struct s5h1411_state *state = fe->demodulator_priv; + + dprintk("%s()\n", __func__); + + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 0); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 1); + return 0; +} + +static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz) +{ + struct s5h1411_state *state = fe->demodulator_priv; + + dprintk("%s(%d KHz)\n", __func__, KHz); + + switch (KHz) { + case 3250: + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d5); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342); + s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9); + break; + case 3500: + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1225); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x1e96); + s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1225); + break; + case 4000: + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x14bc); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0xb53e); + s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x14bd); + break; + default: + dprintk("%s(%d KHz) Invalid, defaulting to 5380\n", + __func__, KHz); + /* no break, need to continue */ + case 5380: + case 44000: + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x3655); + s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1be4); + break; + } + + state->if_freq = KHz; + + return 0; +} + +static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode) +{ + struct s5h1411_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __func__, mode); + + val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff; + switch (mode) { + case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: + val |= 0x0000; + break; + case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: + dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); + val |= 0x1000; + break; + case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: + val |= 0x2000; + break; + case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: + val |= 0x3000; + break; + default: + return -EINVAL; + } + + /* Configure MPEG Signal Timing charactistics */ + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbe, val); +} + +static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion) +{ + struct s5h1411_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __func__, inversion); + val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x24) & ~0x1000; + + if (inversion == 1) + val |= 0x1000; /* Inverted */ + + state->inversion = inversion; + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val); +} + +static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial) +{ + struct s5h1411_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __func__, serial); + val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100; + + if (serial == 1) + val |= 0x100; + + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val); +} + +static int s5h1411_enable_modulation(struct dvb_frontend *fe, + fe_modulation_t m) +{ + struct s5h1411_state *state = fe->demodulator_priv; + + dprintk("%s(0x%08x)\n", __func__, m); + + if ((state->first_tune == 0) && (m == state->current_modulation)) { + dprintk("%s() Already at desired modulation. Skipping...\n", + __func__); + return 0; + } + + switch (m) { + case VSB_8: + dprintk("%s() VSB_8\n", __func__); + s5h1411_set_if_freq(fe, state->config->vsb_if); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x71); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x00); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0xf1); + break; + case QAM_64: + case QAM_256: + case QAM_AUTO: + dprintk("%s() QAM_AUTO (64/256)\n", __func__); + s5h1411_set_if_freq(fe, state->config->qam_if); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x0001); + s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x16, 0x1101); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0x00f0); + break; + default: + dprintk("%s() Invalid modulation\n", __func__); + return -EINVAL; + } + + state->current_modulation = m; + state->first_tune = 0; + s5h1411_softreset(fe); + + return 0; +} + +static int s5h1411_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct s5h1411_state *state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __func__, enable); + + if (enable) + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1); + else + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 0); +} + +static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable) +{ + struct s5h1411_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __func__, enable); + + val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xe0) & ~0x02; + + if (enable) + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, + val | 0x02); + else + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val); +} + +static int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable) +{ + struct s5h1411_state *state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __func__, enable); + + if (enable) + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 1); + else { + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 0); + s5h1411_softreset(fe); + } + + return 0; +} + +static int s5h1411_sleep(struct dvb_frontend *fe) +{ + return s5h1411_set_powerstate(fe, 1); +} + +static int s5h1411_register_reset(struct dvb_frontend *fe) +{ + struct s5h1411_state *state = fe->demodulator_priv; + + dprintk("%s()\n", __func__); + + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf3, 0); +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +static int s5h1411_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct s5h1411_state *state = fe->demodulator_priv; + + dprintk("%s(frequency=%d)\n", __func__, p->frequency); + + s5h1411_softreset(fe); + + state->current_frequency = p->frequency; + + s5h1411_enable_modulation(fe, p->u.vsb.modulation); + + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + fe->ops.tuner_ops.set_params(fe, p); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* Issue a reset to the demod so it knows to resync against the + newly tuned frequency */ + s5h1411_softreset(fe); + + return 0; +} + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +static int s5h1411_init(struct dvb_frontend *fe) +{ + struct s5h1411_state *state = fe->demodulator_priv; + int i; + + dprintk("%s()\n", __func__); + + s5h1411_set_powerstate(fe, 0); + s5h1411_register_reset(fe); + + for (i = 0; i < ARRAY_SIZE(init_tab); i++) + s5h1411_writereg(state, init_tab[i].addr, + init_tab[i].reg, + init_tab[i].data); + + /* The datasheet says that after initialisation, VSB is default */ + state->current_modulation = VSB_8; + + /* Although the datasheet says it's in VSB, empirical evidence + shows problems getting lock on the first tuning request. Make + sure we call enable_modulation the first time around */ + state->first_tune = 1; + + if (state->config->output_mode == S5H1411_SERIAL_OUTPUT) + /* Serial */ + s5h1411_set_serialmode(fe, 1); + else + /* Parallel */ + s5h1411_set_serialmode(fe, 0); + + s5h1411_set_spectralinversion(fe, state->config->inversion); + s5h1411_set_if_freq(fe, state->config->vsb_if); + s5h1411_set_gpio(fe, state->config->gpio); + s5h1411_set_mpeg_timing(fe, state->config->mpeg_timing); + s5h1411_softreset(fe); + + /* Note: Leaving the I2C gate closed. */ + s5h1411_i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct s5h1411_state *state = fe->demodulator_priv; + u16 reg; + u32 tuner_status = 0; + + *status = 0; + + /* Register F2 bit 15 = Master Lock, removed */ + + switch (state->current_modulation) { + case QAM_64: + case QAM_256: + reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0); + if (reg & 0x10) /* QAM FEC Lock */ + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + if (reg & 0x100) /* QAM EQ Lock */ + *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; + + break; + case VSB_8: + reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2); + if (reg & 0x1000) /* FEC Lock */ + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + if (reg & 0x2000) /* EQ Lock */ + *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; + + reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x53); + if (reg & 0x1) /* AFC Lock */ + *status |= FE_HAS_SIGNAL; + + break; + default: + return -EINVAL; + } + + switch (state->config->status_mode) { + case S5H1411_DEMODLOCKING: + if (*status & FE_HAS_VITERBI) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + case S5H1411_TUNERLOCKING: + /* Get the tuner status */ + if (fe->ops.tuner_ops.get_status) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + fe->ops.tuner_ops.get_status(fe, &tuner_status); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + if (tuner_status) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + } + + dprintk("%s() status 0x%08x\n", __func__, *status); + + return 0; +} + +static int s5h1411_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __func__); + + for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) { + if (v < qam256_snr_tab[i].val) { + *snr = qam256_snr_tab[i].data; + ret = 0; + break; + } + } + return ret; +} + +static int s5h1411_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __func__); + + for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) { + if (v < qam64_snr_tab[i].val) { + *snr = qam64_snr_tab[i].data; + ret = 0; + break; + } + } + return ret; +} + +static int s5h1411_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __func__); + + for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) { + if (v > vsb_snr_tab[i].val) { + *snr = vsb_snr_tab[i].data; + ret = 0; + break; + } + } + dprintk("%s() snr=%d\n", __func__, *snr); + return ret; +} + +static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct s5h1411_state *state = fe->demodulator_priv; + u16 reg; + dprintk("%s()\n", __func__); + + switch (state->current_modulation) { + case QAM_64: + reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1); + return s5h1411_qam64_lookup_snr(fe, snr, reg); + case QAM_256: + reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1); + return s5h1411_qam256_lookup_snr(fe, snr, reg); + case VSB_8: + reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, + 0xf2) & 0x3ff; + return s5h1411_vsb_lookup_snr(fe, snr, reg); + default: + break; + } + + return -EINVAL; +} + +static int s5h1411_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + return s5h1411_read_snr(fe, signal_strength); +} + +static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct s5h1411_state *state = fe->demodulator_priv; + + *ucblocks = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xc9); + + return 0; +} + +static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + return s5h1411_read_ucblocks(fe, ber); +} + +static int s5h1411_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct s5h1411_state *state = fe->demodulator_priv; + + p->frequency = state->current_frequency; + p->u.vsb.modulation = state->current_modulation; + + return 0; +} + +static int s5h1411_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void s5h1411_release(struct dvb_frontend *fe) +{ + struct s5h1411_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops s5h1411_ops; + +struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, + struct i2c_adapter *i2c) +{ + struct s5h1411_state *state = NULL; + u16 reg; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct s5h1411_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->current_modulation = VSB_8; + state->inversion = state->config->inversion; + + /* check if the demod exists */ + reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x05); + if (reg != 0x0066) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &s5h1411_ops, + sizeof(struct dvb_frontend_ops)); + + state->frontend.demodulator_priv = state; + + if (s5h1411_init(&state->frontend) != 0) { + printk(KERN_ERR "%s: Failed to initialize correctly\n", + __func__); + goto error; + } + + /* Note: Leaving the I2C gate open here. */ + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1); + + /* Put the device into low-power mode until first use */ + s5h1411_set_powerstate(&state->frontend, 1); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(s5h1411_attach); + +static struct dvb_frontend_ops s5h1411_ops = { + + .info = { + .name = "Samsung S5H1411 QAM/8VSB Frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .init = s5h1411_init, + .sleep = s5h1411_sleep, + .i2c_gate_ctrl = s5h1411_i2c_gate_ctrl, + .set_frontend = s5h1411_set_frontend, + .get_frontend = s5h1411_get_frontend, + .get_tune_settings = s5h1411_get_tune_settings, + .read_status = s5h1411_read_status, + .read_ber = s5h1411_read_ber, + .read_signal_strength = s5h1411_read_signal_strength, + .read_snr = s5h1411_read_snr, + .read_ucblocks = s5h1411_read_ucblocks, + .release = s5h1411_release, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1411.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1411.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1411.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1411.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,90 @@ +/* + Samsung S5H1411 VSB/QAM demodulator driver + + Copyright (C) 2008 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __S5H1411_H__ +#define __S5H1411_H__ + +#include + +#define S5H1411_I2C_TOP_ADDR (0x32 >> 1) +#define S5H1411_I2C_QAM_ADDR (0x34 >> 1) + +struct s5h1411_config { + + /* serial/parallel output */ +#define S5H1411_PARALLEL_OUTPUT 0 +#define S5H1411_SERIAL_OUTPUT 1 + u8 output_mode; + + /* GPIO Setting */ +#define S5H1411_GPIO_OFF 0 +#define S5H1411_GPIO_ON 1 + u8 gpio; + + /* MPEG signal timing */ +#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 +#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 +#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 +#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 + u16 mpeg_timing; + + /* IF Freq for QAM and VSB in KHz */ +#define S5H1411_IF_3250 3250 +#define S5H1411_IF_3500 3500 +#define S5H1411_IF_4000 4000 +#define S5H1411_IF_5380 5380 +#define S5H1411_IF_44000 44000 +#define S5H1411_VSB_IF_DEFAULT S5H1411_IF_44000 +#define S5H1411_QAM_IF_DEFAULT S5H1411_IF_44000 + u16 qam_if; + u16 vsb_if; + + /* Spectral Inversion */ +#define S5H1411_INVERSION_OFF 0 +#define S5H1411_INVERSION_ON 1 + u8 inversion; + + /* Return lock status based on tuner lock, or demod lock */ +#define S5H1411_TUNERLOCKING 0 +#define S5H1411_DEMODLOCKING 1 + u8 status_mode; +}; + +#if defined(CONFIG_DVB_S5H1411) || \ + (defined(CONFIG_DVB_S5H1411_MODULE) && defined(MODULE)) +extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *s5h1411_attach( + const struct s5h1411_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_S5H1411 */ + +#endif /* __S5H1411_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,981 @@ +/* + * Driver for + * Samsung S5H1420 and + * PnpNetwork PN1010 QPSK Demodulator + * + * Copyright (C) 2005 Andrew de Quincey + * Copyright (C) 2005-8 Patrick Boettcher + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#include "dvb_frontend.h" +#include "s5h1420.h" +#include "s5h1420_priv.h" + +#define TONE_FREQ 22000 + +struct s5h1420_state { + struct i2c_adapter* i2c; + const struct s5h1420_config* config; + + struct dvb_frontend frontend; + struct i2c_adapter tuner_i2c_adapter; + + u8 CON_1_val; + + u8 postlocked:1; + u32 fclk; + u32 tunedfreq; + fe_code_rate_t fec_inner; + u32 symbol_rate; + + /* FIXME: ugly workaround for flexcop's incapable i2c-controller + * it does not support repeated-start, workaround: write addr-1 + * and then read + */ + u8 shadow[256]; +}; + +static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings); + + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debugging"); + +#define dprintk(x...) do { \ + if (debug) \ + printk(KERN_DEBUG "S5H1420: " x); \ +} while (0) + +static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg) +{ + int ret; + u8 b[2]; + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 2 }, + { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = 1 }, + }; + + b[0] = (reg - 1) & 0xff; + b[1] = state->shadow[(reg - 1) & 0xff]; + + if (state->config->repeated_start_workaround) { + ret = i2c_transfer(state->i2c, msg, 3); + if (ret != 3) + return ret; + } else { + ret = i2c_transfer(state->i2c, &msg[1], 1); + if (ret != 1) + return ret; + ret = i2c_transfer(state->i2c, &msg[2], 1); + if (ret != 1) + return ret; + } + + /* dprintk("rd(%02x): %02x %02x\n", state->config->demod_address, reg, b[0]); */ + + return b[0]; +} + +static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int err; + + /* dprintk("wr(%02x): %02x %02x\n", state->config->demod_address, reg, data); */ + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data); + return -EREMOTEIO; + } + state->shadow[reg] = data; + + return 0; +} + +static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + dprintk("enter %s\n", __func__); + + switch(voltage) { + case SEC_VOLTAGE_13: + s5h1420_writereg(state, 0x3c, + (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02); + break; + + case SEC_VOLTAGE_18: + s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03); + break; + + case SEC_VOLTAGE_OFF: + s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd); + break; + } + + dprintk("leave %s\n", __func__); + return 0; +} + +static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + dprintk("enter %s\n", __func__); + switch(tone) { + case SEC_TONE_ON: + s5h1420_writereg(state, 0x3b, + (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08); + break; + + case SEC_TONE_OFF: + s5h1420_writereg(state, 0x3b, + (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); + break; + } + dprintk("leave %s\n", __func__); + + return 0; +} + +static int s5h1420_send_master_cmd (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + int i; + unsigned long timeout; + int result = 0; + + dprintk("enter %s\n", __func__); + if (cmd->msg_len > 8) + return -EINVAL; + + /* setup for DISEQC */ + val = s5h1420_readreg(state, 0x3b); + s5h1420_writereg(state, 0x3b, 0x02); + msleep(15); + + /* write the DISEQC command bytes */ + for(i=0; i< cmd->msg_len; i++) { + s5h1420_writereg(state, 0x3d + i, cmd->msg[i]); + } + + /* kick off transmission */ + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | + ((cmd->msg_len-1) << 4) | 0x08); + + /* wait for transmission to complete */ + timeout = jiffies + ((100*HZ) / 1000); + while(time_before(jiffies, timeout)) { + if (!(s5h1420_readreg(state, 0x3b) & 0x08)) + break; + + msleep(5); + } + if (time_after(jiffies, timeout)) + result = -ETIMEDOUT; + + /* restore original settings */ + s5h1420_writereg(state, 0x3b, val); + msleep(15); + dprintk("leave %s\n", __func__); + return result; +} + +static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, + struct dvb_diseqc_slave_reply* reply) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + int i; + int length; + unsigned long timeout; + int result = 0; + + /* setup for DISEQC receive */ + val = s5h1420_readreg(state, 0x3b); + s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */ + msleep(15); + + /* wait for reception to complete */ + timeout = jiffies + ((reply->timeout*HZ) / 1000); + while(time_before(jiffies, timeout)) { + if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */ + break; + + msleep(5); + } + if (time_after(jiffies, timeout)) { + result = -ETIMEDOUT; + goto exit; + } + + /* check error flag - FIXME: not sure what this does - docs do not describe + * beyond "error flag for diseqc receive data :( */ + if (s5h1420_readreg(state, 0x49)) { + result = -EIO; + goto exit; + } + + /* check length */ + length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4; + if (length > sizeof(reply->msg)) { + result = -EOVERFLOW; + goto exit; + } + reply->msg_len = length; + + /* extract data */ + for(i=0; i< length; i++) { + reply->msg[i] = s5h1420_readreg(state, 0x3d + i); + } + +exit: + /* restore original settings */ + s5h1420_writereg(state, 0x3b, val); + msleep(15); + return result; +} + +static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + int result = 0; + unsigned long timeout; + + /* setup for tone burst */ + val = s5h1420_readreg(state, 0x3b); + s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01); + + /* set value for B position if requested */ + if (minicmd == SEC_MINI_B) { + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04); + } + msleep(15); + + /* start transmission */ + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08); + + /* wait for transmission to complete */ + timeout = jiffies + ((100*HZ) / 1000); + while(time_before(jiffies, timeout)) { + if (!(s5h1420_readreg(state, 0x3b) & 0x08)) + break; + + msleep(5); + } + if (time_after(jiffies, timeout)) + result = -ETIMEDOUT; + + /* restore original settings */ + s5h1420_writereg(state, 0x3b, val); + msleep(15); + return result; +} + +static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state) +{ + u8 val; + fe_status_t status = 0; + + val = s5h1420_readreg(state, 0x14); + if (val & 0x02) + status |= FE_HAS_SIGNAL; + if (val & 0x01) + status |= FE_HAS_CARRIER; + val = s5h1420_readreg(state, 0x36); + if (val & 0x01) + status |= FE_HAS_VITERBI; + if (val & 0x20) + status |= FE_HAS_SYNC; + if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC)) + status |= FE_HAS_LOCK; + + return status; +} + +static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + + dprintk("enter %s\n", __func__); + + if (status == NULL) + return -EINVAL; + + /* determine lock state */ + *status = s5h1420_get_status_bits(state); + + /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert + the inversion, wait a bit and check again */ + if (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI)) { + val = s5h1420_readreg(state, Vit10); + if ((val & 0x07) == 0x03) { + if (val & 0x08) + s5h1420_writereg(state, Vit09, 0x13); + else + s5h1420_writereg(state, Vit09, 0x1b); + + /* wait a bit then update lock status */ + mdelay(200); + *status = s5h1420_get_status_bits(state); + } + } + + /* perform post lock setup */ + if ((*status & FE_HAS_LOCK) && !state->postlocked) { + + /* calculate the data rate */ + u32 tmp = s5h1420_getsymbolrate(state); + switch (s5h1420_readreg(state, Vit10) & 0x07) { + case 0: tmp = (tmp * 2 * 1) / 2; break; + case 1: tmp = (tmp * 2 * 2) / 3; break; + case 2: tmp = (tmp * 2 * 3) / 4; break; + case 3: tmp = (tmp * 2 * 5) / 6; break; + case 4: tmp = (tmp * 2 * 6) / 7; break; + case 5: tmp = (tmp * 2 * 7) / 8; break; + } + + if (tmp == 0) { + printk(KERN_ERR "s5h1420: avoided division by 0\n"); + tmp = 1; + } + tmp = state->fclk / tmp; + + + /* set the MPEG_CLK_INTL for the calculated data rate */ + if (tmp < 2) + val = 0x00; + else if (tmp < 5) + val = 0x01; + else if (tmp < 9) + val = 0x02; + else if (tmp < 13) + val = 0x03; + else if (tmp < 17) + val = 0x04; + else if (tmp < 25) + val = 0x05; + else if (tmp < 33) + val = 0x06; + else + val = 0x07; + dprintk("for MPEG_CLK_INTL %d %x\n", tmp, val); + + s5h1420_writereg(state, FEC01, 0x18); + s5h1420_writereg(state, FEC01, 0x10); + s5h1420_writereg(state, FEC01, val); + + /* Enable "MPEG_Out" */ + val = s5h1420_readreg(state, Mpeg02); + s5h1420_writereg(state, Mpeg02, val | (1 << 6)); + + /* kicker disable */ + val = s5h1420_readreg(state, QPSK01) & 0x7f; + s5h1420_writereg(state, QPSK01, val); + + /* DC freeze TODO it was never activated by default or it can stay activated */ + + if (s5h1420_getsymbolrate(state) >= 20000000) { + s5h1420_writereg(state, Loop04, 0x8a); + s5h1420_writereg(state, Loop05, 0x6a); + } else { + s5h1420_writereg(state, Loop04, 0x58); + s5h1420_writereg(state, Loop05, 0x27); + } + + /* post-lock processing has been done! */ + state->postlocked = 1; + } + + dprintk("leave %s\n", __func__); + + return 0; +} + +static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + s5h1420_writereg(state, 0x46, 0x1d); + mdelay(25); + + *ber = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + return 0; +} + +static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + u8 val = s5h1420_readreg(state, 0x15); + + *strength = (u16) ((val << 8) | val); + + return 0; +} + +static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + s5h1420_writereg(state, 0x46, 0x1f); + mdelay(25); + + *ucblocks = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + return 0; +} + +static void s5h1420_reset(struct s5h1420_state* state) +{ + dprintk("%s\n", __func__); + s5h1420_writereg (state, 0x01, 0x08); + s5h1420_writereg (state, 0x01, 0x00); + udelay(10); +} + +static void s5h1420_setsymbolrate(struct s5h1420_state* state, + struct dvb_frontend_parameters *p) +{ + u8 v; + u64 val; + + dprintk("enter %s\n", __func__); + + val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24); + if (p->u.qpsk.symbol_rate < 29000000) + val *= 2; + do_div(val, (state->fclk / 1000)); + + dprintk("symbol rate register: %06llx\n", (unsigned long long)val); + + v = s5h1420_readreg(state, Loop01); + s5h1420_writereg(state, Loop01, v & 0x7f); + s5h1420_writereg(state, Tnco01, val >> 16); + s5h1420_writereg(state, Tnco02, val >> 8); + s5h1420_writereg(state, Tnco03, val & 0xff); + s5h1420_writereg(state, Loop01, v | 0x80); + dprintk("leave %s\n", __func__); +} + +static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) +{ + return state->symbol_rate; +} + +static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset) +{ + int val; + u8 v; + + dprintk("enter %s\n", __func__); + + /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so + * divide fclk by 1000000 to get the correct value. */ + val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000)); + + dprintk("phase rotator/freqoffset: %d %06x\n", freqoffset, val); + + v = s5h1420_readreg(state, Loop01); + s5h1420_writereg(state, Loop01, v & 0xbf); + s5h1420_writereg(state, Pnco01, val >> 16); + s5h1420_writereg(state, Pnco02, val >> 8); + s5h1420_writereg(state, Pnco03, val & 0xff); + s5h1420_writereg(state, Loop01, v | 0x40); + dprintk("leave %s\n", __func__); +} + +static int s5h1420_getfreqoffset(struct s5h1420_state* state) +{ + int val; + + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08); + val = s5h1420_readreg(state, 0x0e) << 16; + val |= s5h1420_readreg(state, 0x0f) << 8; + val |= s5h1420_readreg(state, 0x10); + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); + + if (val & 0x800000) + val |= 0xff000000; + + /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so + * divide fclk by 1000000 to get the correct value. */ + val = (((-val) * (state->fclk/1000000)) / (1<<24)); + + return val; +} + +static void s5h1420_setfec_inversion(struct s5h1420_state* state, + struct dvb_frontend_parameters *p) +{ + u8 inversion = 0; + u8 vit08, vit09; + + dprintk("enter %s\n", __func__); + + if (p->inversion == INVERSION_OFF) + inversion = state->config->invert ? 0x08 : 0; + else if (p->inversion == INVERSION_ON) + inversion = state->config->invert ? 0 : 0x08; + + if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { + vit08 = 0x3f; + vit09 = 0; + } else { + switch(p->u.qpsk.fec_inner) { + case FEC_1_2: + vit08 = 0x01; vit09 = 0x10; + break; + + case FEC_2_3: + vit08 = 0x02; vit09 = 0x11; + break; + + case FEC_3_4: + vit08 = 0x04; vit09 = 0x12; + break; + + case FEC_5_6: + vit08 = 0x08; vit09 = 0x13; + break; + + case FEC_6_7: + vit08 = 0x10; vit09 = 0x14; + break; + + case FEC_7_8: + vit08 = 0x20; vit09 = 0x15; + break; + + default: + return; + } + } + vit09 |= inversion; + dprintk("fec: %02x %02x\n", vit08, vit09); + s5h1420_writereg(state, Vit08, vit08); + s5h1420_writereg(state, Vit09, vit09); + dprintk("leave %s\n", __func__); +} + +static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) +{ + switch(s5h1420_readreg(state, 0x32) & 0x07) { + case 0: + return FEC_1_2; + + case 1: + return FEC_2_3; + + case 2: + return FEC_3_4; + + case 3: + return FEC_5_6; + + case 4: + return FEC_6_7; + + case 5: + return FEC_7_8; + } + + return FEC_NONE; +} + +static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) +{ + if (s5h1420_readreg(state, 0x32) & 0x08) + return INVERSION_ON; + + return INVERSION_OFF; +} + +static int s5h1420_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct s5h1420_state* state = fe->demodulator_priv; + int frequency_delta; + struct dvb_frontend_tune_settings fesettings; + uint8_t clock_setting; + + dprintk("enter %s\n", __func__); + + /* check if we should do a fast-tune */ + memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); + s5h1420_get_tune_settings(fe, &fesettings); + frequency_delta = p->frequency - state->tunedfreq; + if ((frequency_delta > -fesettings.max_drift) && + (frequency_delta < fesettings.max_drift) && + (frequency_delta != 0) && + (state->fec_inner == p->u.qpsk.fec_inner) && + (state->symbol_rate == p->u.qpsk.symbol_rate)) { + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + if (fe->ops.tuner_ops.get_frequency) { + u32 tmp; + fe->ops.tuner_ops.get_frequency(fe, &tmp); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + s5h1420_setfreqoffset(state, p->frequency - tmp); + } else { + s5h1420_setfreqoffset(state, 0); + } + dprintk("simple tune\n"); + return 0; + } + dprintk("tuning demod\n"); + + /* first of all, software reset */ + s5h1420_reset(state); + + /* set s5h1420 fclk PLL according to desired symbol rate */ + if (p->u.qpsk.symbol_rate > 33000000) + state->fclk = 80000000; + else if (p->u.qpsk.symbol_rate > 28500000) + state->fclk = 59000000; + else if (p->u.qpsk.symbol_rate > 25000000) + state->fclk = 86000000; + else if (p->u.qpsk.symbol_rate > 1900000) + state->fclk = 88000000; + else + state->fclk = 44000000; + + /* Clock */ + switch (state->fclk) { + default: + case 88000000: + clock_setting = 80; + break; + case 86000000: + clock_setting = 78; + break; + case 80000000: + clock_setting = 72; + break; + case 59000000: + clock_setting = 51; + break; + case 44000000: + clock_setting = 36; + break; + } + dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); + s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8); + s5h1420_writereg(state, PLL02, 0x40); + s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); + + /* TODO DC offset removal, config parameter ? */ + if (p->u.qpsk.symbol_rate > 29000000) + s5h1420_writereg(state, QPSK01, 0xae | 0x10); + else + s5h1420_writereg(state, QPSK01, 0xac | 0x10); + + /* set misc registers */ + s5h1420_writereg(state, CON_1, 0x00); + s5h1420_writereg(state, QPSK02, 0x00); + s5h1420_writereg(state, Pre01, 0xb0); + + s5h1420_writereg(state, Loop01, 0xF0); + s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */ + s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */ + if (p->u.qpsk.symbol_rate > 20000000) + s5h1420_writereg(state, Loop04, 0x79); + else + s5h1420_writereg(state, Loop04, 0x58); + s5h1420_writereg(state, Loop05, 0x6b); + + if (p->u.qpsk.symbol_rate >= 8000000) + s5h1420_writereg(state, Post01, (0 << 6) | 0x10); + else if (p->u.qpsk.symbol_rate >= 4000000) + s5h1420_writereg(state, Post01, (1 << 6) | 0x10); + else + s5h1420_writereg(state, Post01, (3 << 6) | 0x10); + + s5h1420_writereg(state, Monitor12, 0x00); /* unfreeze DC compensation */ + + s5h1420_writereg(state, Sync01, 0x33); + s5h1420_writereg(state, Mpeg01, state->config->cdclk_polarity); + s5h1420_writereg(state, Mpeg02, 0x3d); /* Parallel output more, disabled -> enabled later */ + s5h1420_writereg(state, Err01, 0x03); /* 0x1d for s5h1420 */ + + s5h1420_writereg(state, Vit06, 0x6e); /* 0x8e for s5h1420 */ + s5h1420_writereg(state, DiS03, 0x00); + s5h1420_writereg(state, Rf01, 0x61); /* Tuner i2c address - for the gate controller */ + + /* set tuner PLL */ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + s5h1420_setfreqoffset(state, 0); + } + + /* set the reset of the parameters */ + s5h1420_setsymbolrate(state, p); + s5h1420_setfec_inversion(state, p); + + /* start QPSK */ + s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1); + + state->fec_inner = p->u.qpsk.fec_inner; + state->symbol_rate = p->u.qpsk.symbol_rate; + state->postlocked = 0; + state->tunedfreq = p->frequency; + + dprintk("leave %s\n", __func__); + return 0; +} + +static int s5h1420_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state); + p->inversion = s5h1420_getinversion(state); + p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state); + p->u.qpsk.fec_inner = s5h1420_getfec(state); + + return 0; +} + +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) +{ + if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { + fesettings->min_delay_ms = 50; + fesettings->step_size = 2000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1500; + fesettings->max_drift = 9000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 500; + fesettings->max_drift = 7000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 14 * fesettings->step_size; + } else { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 18 * fesettings->step_size; + } + + return 0; +} + +static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + if (enable) + return s5h1420_writereg(state, 0x02, state->CON_1_val | 1); + else + return s5h1420_writereg(state, 0x02, state->CON_1_val & 0xfe); +} + +static int s5h1420_init (struct dvb_frontend* fe) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + /* disable power down and do reset */ + state->CON_1_val = state->config->serial_mpeg << 4; + s5h1420_writereg(state, 0x02, state->CON_1_val); + msleep(10); + s5h1420_reset(state); + + return 0; +} + +static int s5h1420_sleep(struct dvb_frontend* fe) +{ + struct s5h1420_state* state = fe->demodulator_priv; + state->CON_1_val = 0x12; + return s5h1420_writereg(state, 0x02, state->CON_1_val); +} + +static void s5h1420_release(struct dvb_frontend* fe) +{ + struct s5h1420_state* state = fe->demodulator_priv; + i2c_del_adapter(&state->tuner_i2c_adapter); + kfree(state); +} + +static u32 s5h1420_tuner_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct s5h1420_state *state = i2c_get_adapdata(i2c_adap); + struct i2c_msg m[1 + num]; + u8 tx_open[2] = { CON_1, state->CON_1_val | 1 }; /* repeater stops once there was a stop condition */ + + memset(m, 0, sizeof(struct i2c_msg) * (1 + num)); + + m[0].addr = state->config->demod_address; + m[0].buf = tx_open; + m[0].len = 2; + + memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); + + return i2c_transfer(state->i2c, m, 1+num) == 1 + num ? num : -EIO; +} + +static struct i2c_algorithm s5h1420_tuner_i2c_algo = { + .master_xfer = s5h1420_tuner_i2c_tuner_xfer, + .functionality = s5h1420_tuner_i2c_func, +}; + +struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe) +{ + struct s5h1420_state *state = fe->demodulator_priv; + return &state->tuner_i2c_adapter; +} +EXPORT_SYMBOL(s5h1420_get_tuner_i2c_adapter); + +static struct dvb_frontend_ops s5h1420_ops; + +struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, + struct i2c_adapter *i2c) +{ + /* allocate memory for the internal state */ + struct s5h1420_state *state = kzalloc(sizeof(struct s5h1420_state), GFP_KERNEL); + u8 i; + + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->postlocked = 0; + state->fclk = 88000000; + state->tunedfreq = 0; + state->fec_inner = FEC_NONE; + state->symbol_rate = 0; + + /* check if the demod is there + identify it */ + i = s5h1420_readreg(state, ID01); + if (i != 0x03) + goto error; + + memset(state->shadow, 0xff, sizeof(state->shadow)); + + for (i = 0; i < 0x50; i++) + state->shadow[i] = s5h1420_readreg(state, i); + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* create tuner i2c adapter */ + strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", + sizeof(state->tuner_i2c_adapter.name)); + state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo; + state->tuner_i2c_adapter.algo_data = NULL; + i2c_set_adapdata(&state->tuner_i2c_adapter, state); + if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) { + printk(KERN_ERR "S5H1420/PN1010: tuner i2c bus could not be initialized\n"); + goto error; + } + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(s5h1420_attach); + +static struct dvb_frontend_ops s5h1420_ops = { + + .info = { + .name = "Samsung S5H1420/PnpNetwork PN1010 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* .symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = s5h1420_release, + + .init = s5h1420_init, + .sleep = s5h1420_sleep, + .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl, + + .set_frontend = s5h1420_set_frontend, + .get_frontend = s5h1420_get_frontend, + .get_tune_settings = s5h1420_get_tune_settings, + + .read_status = s5h1420_read_status, + .read_ber = s5h1420_read_ber, + .read_signal_strength = s5h1420_read_signal_strength, + .read_ucblocks = s5h1420_read_ucblocks, + + .diseqc_send_master_cmd = s5h1420_send_master_cmd, + .diseqc_recv_slave_reply = s5h1420_recv_slave_reply, + .diseqc_send_burst = s5h1420_send_burst, + .set_tone = s5h1420_set_tone, + .set_voltage = s5h1420_set_voltage, +}; + +MODULE_DESCRIPTION("Samsung S5H1420/PnpNetwork PN1010 DVB-S Demodulator driver"); +MODULE_AUTHOR("Andrew de Quincey, Patrick Boettcher"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Driver for + * Samsung S5H1420 and + * PnpNetwork PN1010 QPSK Demodulator + * + * Copyright (C) 2005 Andrew de Quincey + * Copyright (C) 2005-8 Patrick Boettcher + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef S5H1420_H +#define S5H1420_H + +#include + +struct s5h1420_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* does the inversion require inversion? */ + u8 invert:1; + + u8 repeated_start_workaround:1; + u8 cdclk_polarity:1; /* 1 == falling edge, 0 == raising edge */ + + u8 serial_mpeg:1; +}; + +#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE)) +extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, + struct i2c_adapter *i2c); +extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe); +#else +static inline struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe) +{ + return NULL; +} +#endif // CONFIG_DVB_S5H1420 + +#endif // S5H1420_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1420_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,102 @@ +/* + * Driver for + * Samsung S5H1420 and + * PnpNetwork PN1010 QPSK Demodulator + * + * Copyright (C) 2005 Andrew de Quincey + * Copyright (C) 2005 Patrick Boettcher + * + * 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, or (at your option) + * any later version. + * + * 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., 675 Mass + * Ave, Cambridge, MA 02139, USA. + */ +#ifndef S5H1420_PRIV +#define S5H1420_PRIV + +#include + +enum s5h1420_register { + ID01 = 0x00, + CON_0 = 0x01, + CON_1 = 0x02, + PLL01 = 0x03, + PLL02 = 0x04, + QPSK01 = 0x05, + QPSK02 = 0x06, + Pre01 = 0x07, + Post01 = 0x08, + Loop01 = 0x09, + Loop02 = 0x0a, + Loop03 = 0x0b, + Loop04 = 0x0c, + Loop05 = 0x0d, + Pnco01 = 0x0e, + Pnco02 = 0x0f, + Pnco03 = 0x10, + Tnco01 = 0x11, + Tnco02 = 0x12, + Tnco03 = 0x13, + Monitor01 = 0x14, + Monitor02 = 0x15, + Monitor03 = 0x16, + Monitor04 = 0x17, + Monitor05 = 0x18, + Monitor06 = 0x19, + Monitor07 = 0x1a, + Monitor12 = 0x1f, + + FEC01 = 0x22, + Soft01 = 0x23, + Soft02 = 0x24, + Soft03 = 0x25, + Soft04 = 0x26, + Soft05 = 0x27, + Soft06 = 0x28, + Vit01 = 0x29, + Vit02 = 0x2a, + Vit03 = 0x2b, + Vit04 = 0x2c, + Vit05 = 0x2d, + Vit06 = 0x2e, + Vit07 = 0x2f, + Vit08 = 0x30, + Vit09 = 0x31, + Vit10 = 0x32, + Vit11 = 0x33, + Vit12 = 0x34, + Sync01 = 0x35, + Sync02 = 0x36, + Rs01 = 0x37, + Mpeg01 = 0x38, + Mpeg02 = 0x39, + DiS01 = 0x3a, + DiS02 = 0x3b, + DiS03 = 0x3c, + DiS04 = 0x3d, + DiS05 = 0x3e, + DiS06 = 0x3f, + DiS07 = 0x40, + DiS08 = 0x41, + DiS09 = 0x42, + DiS10 = 0x43, + DiS11 = 0x44, + Rf01 = 0x45, + Err01 = 0x46, + Err02 = 0x47, + Err03 = 0x48, + Err04 = 0x49, +}; + + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1432.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1432.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1432.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1432.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,415 @@ +/* + * Samsung s5h1432 DVB-T demodulator driver + * + * Copyright (C) 2009 Bill Liu + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "s5h1432.h" + +struct s5h1432_state { + + struct i2c_adapter *i2c; + + /* configuration settings */ + const struct s5h1432_config *config; + + struct dvb_frontend frontend; + + fe_modulation_t current_modulation; + unsigned int first_tune:1; + + u32 current_frequency; + int if_freq; + + u8 inversion; +}; + +static int debug; + +#define dprintk(arg...) do { \ + if (debug) \ + printk(arg); \ + } while (0) + +static int s5h1432_writereg(struct s5h1432_state *state, + u8 addr, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + + struct i2c_msg msg = {.addr = addr, .flags = 0, .buf = buf, .len = 2 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, " + "ret == %i)\n", __func__, addr, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static u8 s5h1432_readreg(struct s5h1432_state *state, u8 addr, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + + struct i2c_msg msg[] = { + {.addr = addr, .flags = 0, .buf = b0, .len = 1}, + {.addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1} + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk(KERN_ERR "%s: readreg error (ret == %i)\n", + __func__, ret); + return b1[0]; +} + +static int s5h1432_sleep(struct dvb_frontend *fe) +{ + return 0; +} + +static int s5h1432_set_channel_bandwidth(struct dvb_frontend *fe, + u32 bandwidth) +{ + struct s5h1432_state *state = fe->demodulator_priv; + + u8 reg = 0; + + /* Register [0x2E] bit 3:2 : 8MHz = 0; 7MHz = 1; 6MHz = 2 */ + reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x2E); + reg &= ~(0x0C); + switch (bandwidth) { + case 6: + reg |= 0x08; + break; + case 7: + reg |= 0x04; + break; + case 8: + reg |= 0x00; + break; + default: + return 0; + } + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2E, reg); + return 1; +} + +static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz) +{ + struct s5h1432_state *state = fe->demodulator_priv; + + switch (ifFreqHz) { + case TAIWAN_HI_IF_FREQ_44_MHZ: + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x15); + break; + case EUROPE_HI_IF_FREQ_36_MHZ: + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x40); + break; + case IF_FREQ_6_MHZ: + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xe0); + break; + case IF_FREQ_3point3_MHZ: + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE); + break; + case IF_FREQ_3point5_MHZ: + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xED); + break; + case IF_FREQ_4_MHZ: + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0xAA); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0xAA); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEA); + break; + default: + { + u32 value = 0; + value = (u32) (((48000 - (ifFreqHz / 1000)) * 512 * + (u32) 32768) / (48 * 1000)); + printk(KERN_INFO + "Default IFFreq %d :reg value = 0x%x\n", + ifFreqHz, value); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, + (u8) value & 0xFF); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, + (u8) (value >> 8) & 0xFF); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, + (u8) (value >> 16) & 0xFF); + break; + } + + } + + return 1; +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +static int s5h1432_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + u32 dvb_bandwidth = 8; + struct s5h1432_state *state = fe->demodulator_priv; + + if (p->frequency == state->current_frequency) { + /*current_frequency = p->frequency; */ + /*state->current_frequency = p->frequency; */ + } else { + fe->ops.tuner_ops.set_params(fe, p); + msleep(300); + s5h1432_set_channel_bandwidth(fe, dvb_bandwidth); + switch (p->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + dvb_bandwidth = 6; + s5h1432_set_IF(fe, IF_FREQ_4_MHZ); + break; + case BANDWIDTH_7_MHZ: + dvb_bandwidth = 7; + s5h1432_set_IF(fe, IF_FREQ_4_MHZ); + break; + case BANDWIDTH_8_MHZ: + dvb_bandwidth = 8; + s5h1432_set_IF(fe, IF_FREQ_4_MHZ); + break; + default: + return 0; + } + /*fe->ops.tuner_ops.set_params(fe, p); */ +/*Soft Reset chip*/ + msleep(30); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); + msleep(30); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b); + + s5h1432_set_channel_bandwidth(fe, dvb_bandwidth); + switch (p->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + dvb_bandwidth = 6; + s5h1432_set_IF(fe, IF_FREQ_4_MHZ); + break; + case BANDWIDTH_7_MHZ: + dvb_bandwidth = 7; + s5h1432_set_IF(fe, IF_FREQ_4_MHZ); + break; + case BANDWIDTH_8_MHZ: + dvb_bandwidth = 8; + s5h1432_set_IF(fe, IF_FREQ_4_MHZ); + break; + default: + return 0; + } + /*fe->ops.tuner_ops.set_params(fe,p); */ + /*Soft Reset chip*/ + msleep(30); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); + msleep(30); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b); + + } + + state->current_frequency = p->frequency; + + return 0; +} + +static int s5h1432_init(struct dvb_frontend *fe) +{ + struct s5h1432_state *state = fe->demodulator_priv; + + u8 reg = 0; + state->current_frequency = 0; + printk(KERN_INFO " s5h1432_init().\n"); + + /*Set VSB mode as default, this also does a soft reset */ + /*Initialize registers */ + + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x04, 0xa8); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x05, 0x01); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x07, 0x70); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x19, 0x80); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1b, 0x9D); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1c, 0x30); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1d, 0x20); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x1B); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2e, 0x40); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, 0x84); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x50, 0x5a); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x5a, 0xd3); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x68, 0x50); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xb8, 0x3c); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xc4, 0x10); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xcc, 0x9c); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xDA, 0x00); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe1, 0x94); + /* s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf4, 0xa1); */ + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf9, 0x00); + + /*For NXP tuner*/ + + /*Set 3.3MHz as default IF frequency */ + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE); + /* Set reg 0x1E to get the full dynamic range */ + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x31); + + /* Mode setting in demod */ + reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x42); + reg |= 0x80; + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, reg); + /* Serial mode */ + + /* Soft Reset chip */ + + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); + msleep(30); + s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b); + + + return 0; +} + +static int s5h1432_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + return 0; +} + +static int s5h1432_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + return 0; +} + +static int s5h1432_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + return 0; +} + +static int s5h1432_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + + return 0; +} + +static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + return 0; +} + +static int s5h1432_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + return 0; +} + +static int s5h1432_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + return 0; +} + +static void s5h1432_release(struct dvb_frontend *fe) +{ + struct s5h1432_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops s5h1432_ops; + +struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, + struct i2c_adapter *i2c) +{ + struct s5h1432_state *state = NULL; + + printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n"); + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->current_modulation = QAM_16; + state->inversion = state->config->inversion; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &s5h1432_ops, + sizeof(struct dvb_frontend_ops)); + + state->frontend.demodulator_priv = state; + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(s5h1432_attach); + +static struct dvb_frontend_ops s5h1432_ops = { + + .info = { + .name = "Samsung s5h1432 DVB-T Frontend", + .type = FE_OFDM, + .frequency_min = 177000000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER}, + + .init = s5h1432_init, + .sleep = s5h1432_sleep, + .set_frontend = s5h1432_set_frontend, + .get_frontend = s5h1432_get_frontend, + .get_tune_settings = s5h1432_get_tune_settings, + .read_status = s5h1432_read_status, + .read_ber = s5h1432_read_ber, + .read_signal_strength = s5h1432_read_signal_strength, + .read_snr = s5h1432_read_snr, + .read_ucblocks = s5h1432_read_ucblocks, + .release = s5h1432_release, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +MODULE_DESCRIPTION("Samsung s5h1432 DVB-T Demodulator driver"); +MODULE_AUTHOR("Bill Liu"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1432.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1432.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1432.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s5h1432.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * Samsung s5h1432 VSB/QAM demodulator driver + * + * Copyright (C) 2009 Bill Liu + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __S5H1432_H__ +#define __S5H1432_H__ + +#include + +#define S5H1432_I2C_TOP_ADDR (0x02 >> 1) + +#define TAIWAN_HI_IF_FREQ_44_MHZ 44000000 +#define EUROPE_HI_IF_FREQ_36_MHZ 36000000 +#define IF_FREQ_6_MHZ 6000000 +#define IF_FREQ_3point3_MHZ 3300000 +#define IF_FREQ_3point5_MHZ 3500000 +#define IF_FREQ_4_MHZ 4000000 + +struct s5h1432_config { + + /* serial/parallel output */ +#define S5H1432_PARALLEL_OUTPUT 0 +#define S5H1432_SERIAL_OUTPUT 1 + u8 output_mode; + + /* GPIO Setting */ +#define S5H1432_GPIO_OFF 0 +#define S5H1432_GPIO_ON 1 + u8 gpio; + + /* MPEG signal timing */ +#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 +#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 +#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 +#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 + u16 mpeg_timing; + + /* IF Freq for QAM and VSB in KHz */ +#define S5H1432_IF_3250 3250 +#define S5H1432_IF_3500 3500 +#define S5H1432_IF_4000 4000 +#define S5H1432_IF_5380 5380 +#define S5H1432_IF_44000 44000 +#define S5H1432_VSB_IF_DEFAULT s5h1432_IF_44000 +#define S5H1432_QAM_IF_DEFAULT s5h1432_IF_44000 + u16 qam_if; + u16 vsb_if; + + /* Spectral Inversion */ +#define S5H1432_INVERSION_OFF 0 +#define S5H1432_INVERSION_ON 1 + u8 inversion; + + /* Return lock status based on tuner lock, or demod lock */ +#define S5H1432_TUNERLOCKING 0 +#define S5H1432_DEMODLOCKING 1 + u8 status_mode; +}; + +#if defined(CONFIG_DVB_S5H1432) || \ + (defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE)) +extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *s5h1432_attach(const struct s5h1432_config + *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_s5h1432 */ + +#endif /* __s5h1432_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s921.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s921.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s921.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s921.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,548 @@ +/* + * Sharp VA3A5JZ921 One Seg Broadcast Module driver + * This device is labeled as just S. 921 at the top of the frontend can + * + * Copyright (C) 2009-2010 Mauro Carvalho Chehab + * Copyright (C) 2009-2010 Douglas Landgraf + * + * Developed for Leadership SBTVD 1seg device sold in Brazil + * + * Frontend module based on cx24123 driver, getting some info from + * the old s921 driver. + * + * FIXME: Need to port to DVB v5.2 API + * + * 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 version 2. + * + * 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. + */ + +#include +#include + +#include "dvb_frontend.h" +#include "s921.h" + +static int debug = 1; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + +#define rc(args...) do { \ + printk(KERN_ERR "s921: " args); \ +} while (0) + +#define dprintk(args...) \ + do { \ + if (debug) { \ + printk(KERN_DEBUG "s921: %s: ", __func__); \ + printk(args); \ + } \ + } while (0) + +struct s921_state { + struct i2c_adapter *i2c; + const struct s921_config *config; + + struct dvb_frontend frontend; + + /* The Demod can't easily provide these, we cache them */ + u32 currentfreq; +}; + +/* + * Various tuner defaults need to be established for a given frequency kHz. + * fixme: The bounds on the bands do not match the doc in real life. + * fixme: Some of them have been moved, other might need adjustment. + */ +static struct s921_bandselect_val { + u32 freq_low; + u8 band_reg; +} s921_bandselect[] = { + { 0, 0x7b }, + { 485140000, 0x5b }, + { 515140000, 0x3b }, + { 545140000, 0x1b }, + { 599140000, 0xfb }, + { 623140000, 0xdb }, + { 659140000, 0xbb }, + { 713140000, 0x9b }, +}; + +struct regdata { + u8 reg; + u8 data; +}; + +static struct regdata s921_init[] = { + { 0x01, 0x80 }, /* Probably, a reset sequence */ + { 0x01, 0x40 }, + { 0x01, 0x80 }, + { 0x01, 0x40 }, + + { 0x02, 0x00 }, + { 0x03, 0x40 }, + { 0x04, 0x01 }, + { 0x05, 0x00 }, + { 0x06, 0x00 }, + { 0x07, 0x00 }, + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x5a }, + { 0x0c, 0x00 }, + { 0x0d, 0x00 }, + { 0x0f, 0x00 }, + { 0x13, 0x1b }, + { 0x14, 0x80 }, + { 0x15, 0x40 }, + { 0x17, 0x70 }, + { 0x18, 0x01 }, + { 0x19, 0x12 }, + { 0x1a, 0x01 }, + { 0x1b, 0x12 }, + { 0x1c, 0xa0 }, + { 0x1d, 0x00 }, + { 0x1e, 0x0a }, + { 0x1f, 0x08 }, + { 0x20, 0x40 }, + { 0x21, 0xff }, + { 0x22, 0x4c }, + { 0x23, 0x4e }, + { 0x24, 0x4c }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x27, 0xf4 }, + { 0x28, 0x60 }, + { 0x29, 0x88 }, + { 0x2a, 0x40 }, + { 0x2b, 0x40 }, + { 0x2c, 0xff }, + { 0x2d, 0x00 }, + { 0x2e, 0xff }, + { 0x2f, 0x00 }, + { 0x30, 0x20 }, + { 0x31, 0x06 }, + { 0x32, 0x0c }, + { 0x34, 0x0f }, + { 0x37, 0xfe }, + { 0x38, 0x00 }, + { 0x39, 0x63 }, + { 0x3a, 0x10 }, + { 0x3b, 0x10 }, + { 0x47, 0x00 }, + { 0x49, 0xe5 }, + { 0x4b, 0x00 }, + { 0x50, 0xc0 }, + { 0x52, 0x20 }, + { 0x54, 0x5a }, + { 0x55, 0x5b }, + { 0x56, 0x40 }, + { 0x57, 0x70 }, + { 0x5c, 0x50 }, + { 0x5d, 0x00 }, + { 0x62, 0x17 }, + { 0x63, 0x2f }, + { 0x64, 0x6f }, + { 0x68, 0x00 }, + { 0x69, 0x89 }, + { 0x6a, 0x00 }, + { 0x6b, 0x00 }, + { 0x6c, 0x00 }, + { 0x6d, 0x00 }, + { 0x6e, 0x00 }, + { 0x70, 0x10 }, + { 0x71, 0x00 }, + { 0x75, 0x00 }, + { 0x76, 0x30 }, + { 0x77, 0x01 }, + { 0xaf, 0x00 }, + { 0xb0, 0xa0 }, + { 0xb2, 0x3d }, + { 0xb3, 0x25 }, + { 0xb4, 0x8b }, + { 0xb5, 0x4b }, + { 0xb6, 0x3f }, + { 0xb7, 0xff }, + { 0xb8, 0xff }, + { 0xb9, 0xfc }, + { 0xba, 0x00 }, + { 0xbb, 0x00 }, + { 0xbc, 0x00 }, + { 0xd0, 0x30 }, + { 0xe4, 0x84 }, + { 0xf0, 0x48 }, + { 0xf1, 0x19 }, + { 0xf2, 0x5a }, + { 0xf3, 0x8e }, + { 0xf4, 0x2d }, + { 0xf5, 0x07 }, + { 0xf6, 0x5a }, + { 0xf7, 0xba }, + { 0xf8, 0xd7 }, +}; + +static struct regdata s921_prefreq[] = { + { 0x47, 0x60 }, + { 0x68, 0x00 }, + { 0x69, 0x89 }, + { 0xf0, 0x48 }, + { 0xf1, 0x19 }, +}; + +static struct regdata s921_postfreq[] = { + { 0xf5, 0xae }, + { 0xf6, 0xb7 }, + { 0xf7, 0xba }, + { 0xf8, 0xd7 }, + { 0x68, 0x0a }, + { 0x69, 0x09 }, +}; + +static int s921_i2c_writereg(struct s921_state *state, + u8 i2c_addr, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2 + }; + int rc; + + rc = i2c_transfer(state->i2c, &msg, 1); + if (rc != 1) { + printk("%s: writereg rcor(rc == %i, reg == 0x%02x," + " data == 0x%02x)\n", __func__, rc, reg, data); + return rc; + } + + return 0; +} + +static int s921_i2c_writeregdata(struct s921_state *state, u8 i2c_addr, + struct regdata *rd, int size) +{ + int i, rc; + + for (i = 0; i < size; i++) { + rc = s921_i2c_writereg(state, i2c_addr, rd[i].reg, rd[i].data); + if (rc < 0) + return rc; + } + return 0; +} + +static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg) +{ + u8 val; + int rc; + struct i2c_msg msg[] = { + { .addr = i2c_addr, .flags = 0, .buf = ®, .len = 1 }, + { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 } + }; + + rc = i2c_transfer(state->i2c, msg, 2); + + if (rc != 2) { + rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc); + return rc; + } + + return val; +} + +#define s921_readreg(state, reg) \ + s921_i2c_readreg(state, state->config->demod_address, reg) +#define s921_writereg(state, reg, val) \ + s921_i2c_writereg(state, state->config->demod_address, reg, val) +#define s921_writeregdata(state, regdata) \ + s921_i2c_writeregdata(state, state->config->demod_address, \ + regdata, ARRAY_SIZE(regdata)) + +static int s921_pll_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct s921_state *state = fe->demodulator_priv; + int band, rc, i; + unsigned long f_offset; + u8 f_switch; + u64 offset; + + dprintk("frequency=%i\n", p->frequency); + + for (band = 0; band < ARRAY_SIZE(s921_bandselect); band++) + if (p->frequency < s921_bandselect[band].freq_low) + break; + band--; + + if (band < 0) { + rc("%s: frequency out of range\n", __func__); + return -EINVAL; + } + + f_switch = s921_bandselect[band].band_reg; + + offset = ((u64)p->frequency) * 258; + do_div(offset, 6000000); + f_offset = ((unsigned long)offset) + 2321; + + rc = s921_writeregdata(state, s921_prefreq); + if (rc < 0) + return rc; + + rc = s921_writereg(state, 0xf2, (f_offset >> 8) & 0xff); + if (rc < 0) + return rc; + + rc = s921_writereg(state, 0xf3, f_offset & 0xff); + if (rc < 0) + return rc; + + rc = s921_writereg(state, 0xf4, f_switch); + if (rc < 0) + return rc; + + rc = s921_writeregdata(state, s921_postfreq); + if (rc < 0) + return rc; + + for (i = 0 ; i < 6; i++) { + rc = s921_readreg(state, 0x80); + dprintk("status 0x80: %02x\n", rc); + } + rc = s921_writereg(state, 0x01, 0x40); + if (rc < 0) + return rc; + + rc = s921_readreg(state, 0x01); + dprintk("status 0x01: %02x\n", rc); + + rc = s921_readreg(state, 0x80); + dprintk("status 0x80: %02x\n", rc); + + rc = s921_readreg(state, 0x80); + dprintk("status 0x80: %02x\n", rc); + + rc = s921_readreg(state, 0x32); + dprintk("status 0x32: %02x\n", rc); + + dprintk("pll tune band=%d, pll=%d\n", f_switch, (int)f_offset); + + return 0; +} + +static int s921_initfe(struct dvb_frontend *fe) +{ + struct s921_state *state = fe->demodulator_priv; + int rc; + + dprintk("\n"); + + rc = s921_writeregdata(state, s921_init); + if (rc < 0) + return rc; + + return 0; +} + +static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct s921_state *state = fe->demodulator_priv; + int regstatus, rc; + + *status = 0; + + rc = s921_readreg(state, 0x81); + if (rc < 0) + return rc; + + regstatus = rc << 8; + + rc = s921_readreg(state, 0x82); + if (rc < 0) + return rc; + + regstatus |= rc; + + dprintk("status = %04x\n", regstatus); + + /* Full Sync - We don't know what each bit means on regs 0x81/0x82 */ + if ((regstatus & 0xff) == 0x40) { + *status = FE_HAS_SIGNAL | + FE_HAS_CARRIER | + FE_HAS_VITERBI | + FE_HAS_SYNC | + FE_HAS_LOCK; + } else if (regstatus & 0x40) { + /* This is close to Full Sync, but not enough to get useful info */ + *status = FE_HAS_SIGNAL | + FE_HAS_CARRIER | + FE_HAS_VITERBI | + FE_HAS_SYNC; + } + + return 0; +} + +static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + fe_status_t status; + struct s921_state *state = fe->demodulator_priv; + int rc; + + /* FIXME: Use the proper register for it... 0x80? */ + rc = s921_read_status(fe, &status); + if (rc < 0) + return rc; + + *strength = (status & FE_HAS_LOCK) ? 0xffff : 0; + + dprintk("strength = 0x%04x\n", *strength); + + rc = s921_readreg(state, 0x01); + dprintk("status 0x01: %02x\n", rc); + + rc = s921_readreg(state, 0x80); + dprintk("status 0x80: %02x\n", rc); + + rc = s921_readreg(state, 0x32); + dprintk("status 0x32: %02x\n", rc); + + return 0; +} + +static int s921_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct s921_state *state = fe->demodulator_priv; + int rc; + + dprintk("\n"); + + /* FIXME: We don't know how to use non-auto mode */ + + rc = s921_pll_tune(fe, p); + if (rc < 0) + return rc; + + state->currentfreq = p->frequency; + + return 0; +} + +static int s921_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct s921_state *state = fe->demodulator_priv; + + /* FIXME: Probably it is possible to get it from regs f1 and f2 */ + p->frequency = state->currentfreq; + + return 0; +} + +static int s921_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + unsigned int mode_flags, + unsigned int *delay, + fe_status_t *status) +{ + int rc = 0; + + dprintk("\n"); + + if (params != NULL) + rc = s921_set_frontend(fe, params); + + if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) + s921_read_status(fe, status); + + return rc; +} + +static int s921_get_algo(struct dvb_frontend *fe) +{ + return 1; /* FE_ALGO_HW */ +} + +static void s921_release(struct dvb_frontend *fe) +{ + struct s921_state *state = fe->demodulator_priv; + + dprintk("\n"); + kfree(state); +} + +static struct dvb_frontend_ops s921_ops; + +struct dvb_frontend *s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c) +{ + /* allocate memory for the internal state */ + struct s921_state *state = + kzalloc(sizeof(struct s921_state), GFP_KERNEL); + + dprintk("\n"); + if (state == NULL) { + rc("Unable to kzalloc\n"); + goto rcor; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &s921_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; + +rcor: + kfree(state); + + return NULL; +} +EXPORT_SYMBOL(s921_attach); + +static struct dvb_frontend_ops s921_ops = { + /* Use dib8000 values per default */ + .info = { + .name = "Sharp S921", + .type = FE_OFDM, + .frequency_min = 470000000, + /* + * Max should be 770MHz instead, according with Sharp docs, + * but Leadership doc says it works up to 806 MHz. This is + * required to get channel 69, used in Brazil + */ + .frequency_max = 806000000, + .frequency_tolerance = 0, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = s921_release, + + .init = s921_initfe, + .set_frontend = s921_set_frontend, + .get_frontend = s921_get_frontend, + .read_status = s921_read_status, + .read_signal_strength = s921_read_signal_strength, + .tune = s921_tune, + .get_frontend_algo = s921_get_algo, +}; + +MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Douglas Landgraf "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s921.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s921.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s921.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/s921.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Sharp s921 driver + * + * Copyright (C) 2009 Mauro Carvalho Chehab + * Copyright (C) 2009 Douglas Landgraf + * + * 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 version 2. + * + * 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. + */ + +#ifndef S921_H +#define S921_H + +#include + +struct s921_config { + /* the demodulator's i2c address */ + u8 demod_address; +}; + +#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c); +extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *); +#else +static inline struct dvb_frontend *s921_attach( + const struct s921_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static struct i2c_adapter * + s921_get_tuner_i2c_adapter(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* S921_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/si21xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/si21xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/si21xx.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/si21xx.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,967 @@ +/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator +* +* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) +* +* 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, or +* (at your option) any later version. +* +*/ +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "si21xx.h" + +#define REVISION_REG 0x00 +#define SYSTEM_MODE_REG 0x01 +#define TS_CTRL_REG_1 0x02 +#define TS_CTRL_REG_2 0x03 +#define PIN_CTRL_REG_1 0x04 +#define PIN_CTRL_REG_2 0x05 +#define LOCK_STATUS_REG_1 0x0f +#define LOCK_STATUS_REG_2 0x10 +#define ACQ_STATUS_REG 0x11 +#define ACQ_CTRL_REG_1 0x13 +#define ACQ_CTRL_REG_2 0x14 +#define PLL_DIVISOR_REG 0x15 +#define COARSE_TUNE_REG 0x16 +#define FINE_TUNE_REG_L 0x17 +#define FINE_TUNE_REG_H 0x18 + +#define ANALOG_AGC_POWER_LEVEL_REG 0x28 +#define CFO_ESTIMATOR_CTRL_REG_1 0x29 +#define CFO_ESTIMATOR_CTRL_REG_2 0x2a +#define CFO_ESTIMATOR_CTRL_REG_3 0x2b + +#define SYM_RATE_ESTIMATE_REG_L 0x31 +#define SYM_RATE_ESTIMATE_REG_M 0x32 +#define SYM_RATE_ESTIMATE_REG_H 0x33 + +#define CFO_ESTIMATOR_OFFSET_REG_L 0x36 +#define CFO_ESTIMATOR_OFFSET_REG_H 0x37 +#define CFO_ERROR_REG_L 0x38 +#define CFO_ERROR_REG_H 0x39 +#define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a + +#define SYM_RATE_REG_L 0x3f +#define SYM_RATE_REG_M 0x40 +#define SYM_RATE_REG_H 0x41 +#define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42 +#define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43 + +#define C_N_ESTIMATOR_CTRL_REG 0x7c +#define C_N_ESTIMATOR_THRSHLD_REG 0x7d +#define C_N_ESTIMATOR_LEVEL_REG_L 0x7e +#define C_N_ESTIMATOR_LEVEL_REG_H 0x7f + +#define BLIND_SCAN_CTRL_REG 0x80 + +#define LSA_CTRL_REG_1 0x8D +#define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f +#define ONE_DB_BNDWDTH_THRSHLD_REG 0x90 +#define TWO_DB_BNDWDTH_THRSHLD_REG 0x91 +#define THREE_DB_BNDWDTH_THRSHLD_REG 0x92 +#define INBAND_POWER_THRSHLD_REG 0x93 +#define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94 + +#define VIT_SRCH_CTRL_REG_1 0xa0 +#define VIT_SRCH_CTRL_REG_2 0xa1 +#define VIT_SRCH_CTRL_REG_3 0xa2 +#define VIT_SRCH_STATUS_REG 0xa3 +#define VITERBI_BER_COUNT_REG_L 0xab +#define REED_SOLOMON_CTRL_REG 0xb0 +#define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1 +#define PRBS_CTRL_REG 0xb5 + +#define LNB_CTRL_REG_1 0xc0 +#define LNB_CTRL_REG_2 0xc1 +#define LNB_CTRL_REG_3 0xc2 +#define LNB_CTRL_REG_4 0xc3 +#define LNB_CTRL_STATUS_REG 0xc4 +#define LNB_FIFO_REGS_0 0xc5 +#define LNB_FIFO_REGS_1 0xc6 +#define LNB_FIFO_REGS_2 0xc7 +#define LNB_FIFO_REGS_3 0xc8 +#define LNB_FIFO_REGS_4 0xc9 +#define LNB_FIFO_REGS_5 0xca +#define LNB_SUPPLY_CTRL_REG_1 0xcb +#define LNB_SUPPLY_CTRL_REG_2 0xcc +#define LNB_SUPPLY_CTRL_REG_3 0xcd +#define LNB_SUPPLY_CTRL_REG_4 0xce +#define LNB_SUPPLY_STATUS_REG 0xcf + +#define FAIL -1 +#define PASS 0 + +#define ALLOWABLE_FS_COUNT 10 +#define STATUS_BER 0 +#define STATUS_UCBLOCKS 1 + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "si21xx: " args); \ + } while (0) + +enum { + ACTIVE_HIGH, + ACTIVE_LOW +}; +enum { + BYTE_WIDE, + BIT_WIDE +}; +enum { + CLK_GAPPED_MODE, + CLK_CONTINUOUS_MODE +}; +enum { + RISING_EDGE, + FALLING_EDGE +}; +enum { + MSB_FIRST, + LSB_FIRST +}; +enum { + SERIAL, + PARALLEL +}; + +struct si21xx_state { + struct i2c_adapter *i2c; + const struct si21xx_config *config; + struct dvb_frontend frontend; + u8 initialised:1; + int errmode; + int fs; /*Sampling rate of the ADC in MHz*/ +}; + +/* register default initialization */ +static u8 serit_sp1511lhb_inittab[] = { + 0x01, 0x28, /* set i2c_inc_disable */ + 0x20, 0x03, + 0x27, 0x20, + 0xe0, 0x45, + 0xe1, 0x08, + 0xfe, 0x01, + 0x01, 0x28, + 0x89, 0x09, + 0x04, 0x80, + 0x05, 0x01, + 0x06, 0x00, + 0x20, 0x03, + 0x24, 0x88, + 0x29, 0x09, + 0x2a, 0x0f, + 0x2c, 0x10, + 0x2d, 0x19, + 0x2e, 0x08, + 0x2f, 0x10, + 0x30, 0x19, + 0x34, 0x20, + 0x35, 0x03, + 0x45, 0x02, + 0x46, 0x45, + 0x47, 0xd0, + 0x48, 0x00, + 0x49, 0x40, + 0x4a, 0x03, + 0x4c, 0xfd, + 0x4f, 0x2e, + 0x50, 0x2e, + 0x51, 0x10, + 0x52, 0x10, + 0x56, 0x92, + 0x59, 0x00, + 0x5a, 0x2d, + 0x5b, 0x33, + 0x5c, 0x1f, + 0x5f, 0x76, + 0x62, 0xc0, + 0x63, 0xc0, + 0x64, 0xf3, + 0x65, 0xf3, + 0x79, 0x40, + 0x6a, 0x40, + 0x6b, 0x0a, + 0x6c, 0x80, + 0x6d, 0x27, + 0x71, 0x06, + 0x75, 0x60, + 0x78, 0x00, + 0x79, 0xb5, + 0x7c, 0x05, + 0x7d, 0x1a, + 0x87, 0x55, + 0x88, 0x72, + 0x8f, 0x08, + 0x90, 0xe0, + 0x94, 0x40, + 0xa0, 0x3f, + 0xa1, 0xc0, + 0xa4, 0xcc, + 0xa5, 0x66, + 0xa6, 0x66, + 0xa7, 0x7b, + 0xa8, 0x7b, + 0xa9, 0x7b, + 0xaa, 0x9a, + 0xed, 0x04, + 0xad, 0x00, + 0xae, 0x03, + 0xcc, 0xab, + 0x01, 0x08, + 0xff, 0xff +}; + +/* low level read/writes */ +static int si21_writeregs(struct si21xx_state *state, u8 reg1, + u8 *data, int len) +{ + int ret; + u8 buf[60];/* = { reg1, data };*/ + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = len + 1 + }; + + msg.buf[0] = reg1; + memcpy(msg.buf + 1, data, len); + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, " + "ret == %i)\n", __func__, reg1, data[0], ret); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len) +{ + struct si21xx_state *state = fe->demodulator_priv; + + if (len != 2) + return -EINVAL; + + return si21_writereg(state, buf[0], buf[1]); +} + +static u8 si21_readreg(struct si21xx_state *state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 1 + }, { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __func__, reg, ret); + + return b1[0]; +} + +static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len) +{ + int ret; + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = ®1, + .len = 1 + }, { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b, + .len = len + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (ret == %i)\n", __func__, ret); + + return ret == 2 ? 0 : -1; +} + +static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) +{ + unsigned long start = jiffies; + + dprintk("%s\n", __func__); + + while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) { + if (jiffies - start > timeout) { + dprintk("%s: timeout!!\n", __func__); + return -ETIMEDOUT; + } + msleep(10); + }; + + return 0; +} + +static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate) +{ + struct si21xx_state *state = fe->demodulator_priv; + u32 sym_rate, data_rate; + int i; + u8 sym_rate_bytes[3]; + + dprintk("%s : srate = %i\n", __func__ , srate); + + if ((srate < 1000000) || (srate > 45000000)) + return -EINVAL; + + data_rate = srate; + sym_rate = 0; + + for (i = 0; i < 4; ++i) { + sym_rate /= 100; + sym_rate = sym_rate + ((data_rate % 100) * 0x800000) / + state->fs; + data_rate /= 100; + } + for (i = 0; i < 3; ++i) + sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff); + + si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03); + + return 0; +} + +static int si21xx_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *m) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 lnb_status; + u8 LNB_CTRL_1; + int status; + + dprintk("%s\n", __func__); + + status = PASS; + LNB_CTRL_1 = 0; + + status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01); + status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01); + + /*fill the FIFO*/ + status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len); + + LNB_CTRL_1 = (lnb_status & 0x70); + LNB_CTRL_1 |= m->msg_len; + + LNB_CTRL_1 |= 0x80; /* begin LNB signaling */ + + status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01); + + return status; +} + +static int si21xx_send_diseqc_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t burst) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 val; + + dprintk("%s\n", __func__); + + if (si21xx_wait_diseqc_idle(state, 100) < 0) + return -ETIMEDOUT; + + val = (0x80 | si21_readreg(state, 0xc1)); + if (si21_writereg(state, LNB_CTRL_REG_1, + burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10))) + return -EREMOTEIO; + + if (si21xx_wait_diseqc_idle(state, 100) < 0) + return -ETIMEDOUT; + + if (si21_writereg(state, LNB_CTRL_REG_1, val)) + return -EREMOTEIO; + + return 0; +} +/* 30.06.2008 */ +static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 val; + + dprintk("%s\n", __func__); + val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); + + switch (tone) { + case SEC_TONE_ON: + return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20); + + case SEC_TONE_OFF: + return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20)); + + default: + return -EINVAL; + } +} + +static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +{ + struct si21xx_state *state = fe->demodulator_priv; + + u8 val; + dprintk("%s: %s\n", __func__, + volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : + volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); + + + val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); + + switch (volt) { + case SEC_VOLTAGE_18: + return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40); + break; + case SEC_VOLTAGE_13: + return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40)); + break; + default: + return -EINVAL; + }; +} + +static int si21xx_init(struct dvb_frontend *fe) +{ + struct si21xx_state *state = fe->demodulator_priv; + int i; + int status = 0; + u8 reg1; + u8 val; + u8 reg2[2]; + + dprintk("%s\n", __func__); + + for (i = 0; ; i += 2) { + reg1 = serit_sp1511lhb_inittab[i]; + val = serit_sp1511lhb_inittab[i+1]; + if (reg1 == 0xff && val == 0xff) + break; + si21_writeregs(state, reg1, &val, 1); + } + + /*DVB QPSK SYSTEM MODE REG*/ + reg1 = 0x08; + si21_writeregs(state, SYSTEM_MODE_REG, ®1, 0x01); + + /*transport stream config*/ + /* + mode = PARALLEL; + sdata_form = LSB_FIRST; + clk_edge = FALLING_EDGE; + clk_mode = CLK_GAPPED_MODE; + strt_len = BYTE_WIDE; + sync_pol = ACTIVE_HIGH; + val_pol = ACTIVE_HIGH; + err_pol = ACTIVE_HIGH; + sclk_rate = 0x00; + parity = 0x00 ; + data_delay = 0x00; + clk_delay = 0x00; + pclk_smooth = 0x00; + */ + reg2[0] = + PARALLEL + (LSB_FIRST << 1) + + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3) + + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5) + + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7); + + reg2[1] = 0; + /* sclk_rate + (parity << 2) + + (data_delay << 3) + (clk_delay << 4) + + (pclk_smooth << 5); + */ + status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02); + if (status != 0) + dprintk(" %s : TS Set Error\n", __func__); + + return 0; + +} + +static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 regs_read[2]; + u8 reg_read; + u8 i; + u8 lock; + u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG); + + si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02); + reg_read = 0; + + for (i = 0; i < 7; ++i) + reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i); + + lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80)); + + dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock); + *status = 0; + + if (signal > 10) + *status |= FE_HAS_SIGNAL; + + if (lock & 0x2) + *status |= FE_HAS_CARRIER; + + if (lock & 0x20) + *status |= FE_HAS_VITERBI; + + if (lock & 0x40) + *status |= FE_HAS_SYNC; + + if ((lock & 0x7b) == 0x7b) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct si21xx_state *state = fe->demodulator_priv; + + /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG, + (u8*)agclevel, 0x01);*/ + + u16 signal = (3 * si21_readreg(state, 0x27) * + si21_readreg(state, 0x28)); + + dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__, + si21_readreg(state, 0x27), + si21_readreg(state, 0x28), (int) signal); + + signal <<= 4; + *strength = signal; + + return 0; +} + +static int si21_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct si21xx_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (state->errmode != STATUS_BER) + return 0; + + *ber = (si21_readreg(state, 0x1d) << 8) | + si21_readreg(state, 0x1e); + + return 0; +} + +static int si21_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct si21xx_state *state = fe->demodulator_priv; + + s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) | + si21_readreg(state, 0x25)); + xsnr = 3 * (xsnr - 0xa100); + *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; + + dprintk("%s\n", __func__); + + return 0; +} + +static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct si21xx_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (state->errmode != STATUS_UCBLOCKS) + *ucblocks = 0; + else + *ucblocks = (si21_readreg(state, 0x1d) << 8) | + si21_readreg(state, 0x1e); + + return 0; +} + +/* initiates a channel acquisition sequence + using the specified symbol rate and code rate */ +static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, + fe_code_rate_t crate) +{ + + struct si21xx_state *state = fe->demodulator_priv; + u8 coderates[] = { + 0x0, 0x01, 0x02, 0x04, 0x00, + 0x8, 0x10, 0x20, 0x00, 0x3f + }; + + u8 coderate_ptr; + int status; + u8 start_acq = 0x80; + u8 reg, regs[3]; + + dprintk("%s\n", __func__); + + status = PASS; + coderate_ptr = coderates[crate]; + + si21xx_set_symbolrate(fe, symbrate); + + /* write code rates to use in the Viterbi search */ + status |= si21_writeregs(state, + VIT_SRCH_CTRL_REG_1, + &coderate_ptr, 0x01); + + /* clear acq_start bit */ + status |= si21_readregs(state, ACQ_CTRL_REG_2, ®, 0x01); + reg &= ~start_acq; + status |= si21_writeregs(state, ACQ_CTRL_REG_2, ®, 0x01); + + /* use new Carrier Frequency Offset Estimator (QuickLock) */ + regs[0] = 0xCB; + regs[1] = 0x40; + regs[2] = 0xCB; + + status |= si21_writeregs(state, + TWO_DB_BNDWDTH_THRSHLD_REG, + ®s[0], 0x03); + reg = 0x56; + status |= si21_writeregs(state, + LSA_CTRL_REG_1, ®, 1); + reg = 0x05; + status |= si21_writeregs(state, + BLIND_SCAN_CTRL_REG, ®, 1); + /* start automatic acq */ + status |= si21_writeregs(state, + ACQ_CTRL_REG_2, &start_acq, 0x01); + + return status; +} + +static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int si21xx_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *dfp) +{ + struct si21xx_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + /* freq Channel carrier frequency in KHz (i.e. 1550000 KHz) + datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/ + + /* in MHz */ + unsigned char coarse_tune_freq; + int fine_tune_freq; + unsigned char sample_rate = 0; + /* boolean */ + bool inband_interferer_ind; + + /* INTERMEDIATE VALUES */ + int icoarse_tune_freq; /* MHz */ + int ifine_tune_freq; /* MHz */ + unsigned int band_high; + unsigned int band_low; + unsigned int x1; + unsigned int x2; + int i; + bool inband_interferer_div2[ALLOWABLE_FS_COUNT]; + bool inband_interferer_div4[ALLOWABLE_FS_COUNT]; + int status; + + /* allowable sample rates for ADC in MHz */ + int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195, + 196, 204, 205, 206, 207 + }; + /* in MHz */ + int if_limit_high; + int if_limit_low; + int lnb_lo; + int lnb_uncertanity; + + int rf_freq; + int data_rate; + unsigned char regs[4]; + + dprintk("%s : FE_SET_FRONTEND\n", __func__); + + if (c->delivery_system != SYS_DVBS) { + dprintk("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; + } + + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) + inband_interferer_div2[i] = inband_interferer_div4[i] = false; + + if_limit_high = -700000; + if_limit_low = -100000; + /* in MHz */ + lnb_lo = 0; + lnb_uncertanity = 0; + + rf_freq = 10 * c->frequency ; + data_rate = c->symbol_rate / 100; + + status = PASS; + + band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200) + + (data_rate * 135)) / 200; + + band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200) + + (data_rate * 135)) / 200; + + + icoarse_tune_freq = 100000 * + (((rf_freq - lnb_lo) - + (if_limit_low + if_limit_high) / 2) + / 100000); + + ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ; + + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { + x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * + (afs[i] * 2500) + afs[i] * 2500; + + x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * + (afs[i] * 2500); + + if (((band_low < x1) && (x1 < band_high)) || + ((band_low < x2) && (x2 < band_high))) + inband_interferer_div4[i] = true; + + } + + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { + x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * + (afs[i] * 5000) + afs[i] * 5000; + + x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * + (afs[i] * 5000); + + if (((band_low < x1) && (x1 < band_high)) || + ((band_low < x2) && (x2 < band_high))) + inband_interferer_div2[i] = true; + } + + inband_interferer_ind = true; + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { + if (inband_interferer_div2[i] || inband_interferer_div4[i]) { + inband_interferer_ind = false; + break; + } + } + + if (inband_interferer_ind) { + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { + if (!inband_interferer_div2[i]) { + sample_rate = (u8) afs[i]; + break; + } + } + } else { + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { + if ((inband_interferer_div2[i] || + !inband_interferer_div4[i])) { + sample_rate = (u8) afs[i]; + break; + } + } + + } + + if (sample_rate > 207 || sample_rate < 192) + sample_rate = 200; + + fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) / + ((sample_rate) * 1000)); + + coarse_tune_freq = (u8)(icoarse_tune_freq / 100000); + + regs[0] = sample_rate; + regs[1] = coarse_tune_freq; + regs[2] = fine_tune_freq & 0xFF; + regs[3] = fine_tune_freq >> 8 & 0xFF; + + status |= si21_writeregs(state, PLL_DIVISOR_REG, ®s[0], 0x04); + + state->fs = sample_rate;/*ADC MHz*/ + si21xx_setacquire(fe, c->symbol_rate, c->fec_inner); + + return 0; +} + +static int si21xx_sleep(struct dvb_frontend *fe) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 regdata; + + dprintk("%s\n", __func__); + + si21_readregs(state, SYSTEM_MODE_REG, ®data, 0x01); + regdata |= 1 << 6; + si21_writeregs(state, SYSTEM_MODE_REG, ®data, 0x01); + state->initialised = 0; + + return 0; +} + +static void si21xx_release(struct dvb_frontend *fe) +{ + struct si21xx_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + kfree(state); +} + +static struct dvb_frontend_ops si21xx_ops = { + + .info = { + .name = "SL SI21XX DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + + .release = si21xx_release, + .init = si21xx_init, + .sleep = si21xx_sleep, + .write = si21_write, + .read_status = si21_read_status, + .read_ber = si21_read_ber, + .read_signal_strength = si21_read_signal_strength, + .read_snr = si21_read_snr, + .read_ucblocks = si21_read_ucblocks, + .diseqc_send_master_cmd = si21xx_send_diseqc_msg, + .diseqc_send_burst = si21xx_send_diseqc_burst, + .set_tone = si21xx_set_tone, + .set_voltage = si21xx_set_voltage, + + .set_property = si21xx_set_property, + .get_property = si21xx_get_property, + .set_frontend = si21xx_set_frontend, +}; + +struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, + struct i2c_adapter *i2c) +{ + struct si21xx_state *state = NULL; + int id; + + dprintk("%s\n", __func__); + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->initialised = 0; + state->errmode = STATUS_BER; + + /* check if the demod is there */ + id = si21_readreg(state, SYSTEM_MODE_REG); + si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */ + msleep(200); + id = si21_readreg(state, 0x00); + + /* register 0x00 contains: + 0x34 for SI2107 + 0x24 for SI2108 + 0x14 for SI2109 + 0x04 for SI2110 + */ + if (id != 0x04 && id != 0x14) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &si21xx_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(si21xx_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver"); +MODULE_AUTHOR("Igor M. Liplianin"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/si21xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/si21xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/si21xx.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/si21xx.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,37 @@ +#ifndef SI21XX_H +#define SI21XX_H + +#include +#include "dvb_frontend.h" + +struct si21xx_config { + /* the demodulator's i2c address */ + u8 demod_address; + + /* minimum delay before retuning */ + int min_delay_ms; +}; + +#if defined(CONFIG_DVB_SI21XX) || \ + (defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE)) +extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *si21xx_attach( + const struct si21xx_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val) +{ + int r = 0; + u8 buf[] = {reg, val}; + if (fe->ops.write) + r = fe->ops.write(fe, buf, 2); + return r; +} + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp8870.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp8870.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp8870.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp8870.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,619 @@ +/* + Driver for Spase SP8870 demodulator + + Copyright (C) 1999 Juergen Peitz + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ +/* + * This driver needs external firmware. Please use the command + * "/Documentation/dvb/get_dvb_firmware alps_tdlb7" to + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). + */ +#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw" + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "sp8870.h" + + +struct sp8870_state { + + struct i2c_adapter* i2c; + + const struct sp8870_config* config; + + struct dvb_frontend frontend; + + /* demodulator private data */ + u8 initialised:1; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "sp8870: " args); \ + } while (0) + +/* firmware size for sp8870 */ +#define SP8870_FIRMWARE_SIZE 16382 + +/* starting point for firmware in file 'Sc_main.mc' */ +#define SP8870_FIRMWARE_OFFSET 0x0A + +static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data) +{ + u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 }; + int err; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static int sp8870_readreg (struct sp8870_state* state, u16 reg) +{ + int ret; + u8 b0 [] = { reg >> 8 , reg & 0xff }; + u8 b1 [] = { 0, 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + + ret = i2c_transfer (state->i2c, msg, 2); + + if (ret != 2) { + dprintk("%s: readreg error (ret == %i)\n", __func__, ret); + return -1; + } + + return (b1[0] << 8 | b1[1]); +} + +static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw) +{ + struct i2c_msg msg; + const char *fw_buf = fw->data; + int fw_pos; + u8 tx_buf[255]; + int tx_len; + int err = 0; + + dprintk ("%s: ...\n", __func__); + + if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET) + return -EINVAL; + + // system controller stop + sp8870_writereg(state, 0x0F00, 0x0000); + + // instruction RAM register hiword + sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF)); + + // instruction RAM MWR + sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16)); + + // do firmware upload + fw_pos = SP8870_FIRMWARE_OFFSET; + while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){ + tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos; + // write register 0xCF0A + tx_buf[0] = 0xCF; + tx_buf[1] = 0x0A; + memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len); + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.buf = tx_buf; + msg.len = tx_len + 2; + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk("%s: firmware upload failed!\n", __func__); + printk ("%s: i2c error (err == %i)\n", __func__, err); + return err; + } + fw_pos += tx_len; + } + + dprintk ("%s: done!\n", __func__); + return 0; +}; + +static void sp8870_microcontroller_stop (struct sp8870_state* state) +{ + sp8870_writereg(state, 0x0F08, 0x000); + sp8870_writereg(state, 0x0F09, 0x000); + + // microcontroller STOP + sp8870_writereg(state, 0x0F00, 0x000); +} + +static void sp8870_microcontroller_start (struct sp8870_state* state) +{ + sp8870_writereg(state, 0x0F08, 0x000); + sp8870_writereg(state, 0x0F09, 0x000); + + // microcontroller START + sp8870_writereg(state, 0x0F00, 0x001); + // not documented but if we don't read 0x0D01 out here + // we don't get a correct data valid signal + sp8870_readreg(state, 0x0D01); +} + +static int sp8870_read_data_valid_signal(struct sp8870_state* state) +{ + return (sp8870_readreg(state, 0x0D02) > 0); +} + +static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) +{ + int known_parameters = 1; + + *reg0xc05 = 0x000; + + switch (p->u.ofdm.constellation) { + case QPSK: + break; + case QAM_16: + *reg0xc05 |= (1 << 10); + break; + case QAM_64: + *reg0xc05 |= (2 << 10); + break; + case QAM_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + switch (p->u.ofdm.hierarchy_information) { + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + *reg0xc05 |= (1 << 7); + break; + case HIERARCHY_2: + *reg0xc05 |= (2 << 7); + break; + case HIERARCHY_4: + *reg0xc05 |= (3 << 7); + break; + case HIERARCHY_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + switch (p->u.ofdm.code_rate_HP) { + case FEC_1_2: + break; + case FEC_2_3: + *reg0xc05 |= (1 << 3); + break; + case FEC_3_4: + *reg0xc05 |= (2 << 3); + break; + case FEC_5_6: + *reg0xc05 |= (3 << 3); + break; + case FEC_7_8: + *reg0xc05 |= (4 << 3); + break; + case FEC_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + if (known_parameters) + *reg0xc05 |= (2 << 1); /* use specified parameters */ + else + *reg0xc05 |= (1 << 1); /* enable autoprobing */ + + return 0; +} + +static int sp8870_wake_up(struct sp8870_state* state) +{ + // enable TS output and interface pins + return sp8870_writereg(state, 0xC18, 0x00D); +} + +static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct sp8870_state* state = fe->demodulator_priv; + int err; + u16 reg0xc05; + + if ((err = configure_reg0xc05(p, ®0xc05))) + return err; + + // system controller stop + sp8870_microcontroller_stop(state); + + // set tuner parameters + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + // sample rate correction bit [23..17] + sp8870_writereg(state, 0x0319, 0x000A); + + // sample rate correction bit [16..0] + sp8870_writereg(state, 0x031A, 0x0AAB); + + // integer carrier offset + sp8870_writereg(state, 0x0309, 0x0400); + + // fractional carrier offset + sp8870_writereg(state, 0x030A, 0x0000); + + // filter for 6/7/8 Mhz channel + if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + sp8870_writereg(state, 0x0311, 0x0002); + else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + sp8870_writereg(state, 0x0311, 0x0001); + else + sp8870_writereg(state, 0x0311, 0x0000); + + // scan order: 2k first = 0x0000, 8k first = 0x0001 + if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) + sp8870_writereg(state, 0x0338, 0x0000); + else + sp8870_writereg(state, 0x0338, 0x0001); + + sp8870_writereg(state, 0xc05, reg0xc05); + + // read status reg in order to clear pending irqs + sp8870_readreg(state, 0x200); + + // system controller start + sp8870_microcontroller_start(state); + + return 0; +} + +static int sp8870_init (struct dvb_frontend* fe) +{ + struct sp8870_state* state = fe->demodulator_priv; + const struct firmware *fw = NULL; + + sp8870_wake_up(state); + if (state->initialised) return 0; + state->initialised = 1; + + dprintk ("%s\n", __func__); + + + /* request the firmware, this will block until someone uploads it */ + printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE); + if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) { + printk("sp8870: no firmware upload (timeout or file not found?)\n"); + return -EIO; + } + + if (sp8870_firmware_upload(state, fw)) { + printk("sp8870: writing firmware to device failed\n"); + release_firmware(fw); + return -EIO; + } + release_firmware(fw); + printk("sp8870: firmware upload complete\n"); + + /* enable TS output and interface pins */ + sp8870_writereg(state, 0xc18, 0x00d); + + // system controller stop + sp8870_microcontroller_stop(state); + + // ADC mode + sp8870_writereg(state, 0x0301, 0x0003); + + // Reed Solomon parity bytes passed to output + sp8870_writereg(state, 0x0C13, 0x0001); + + // MPEG clock is suppressed if no valid data + sp8870_writereg(state, 0x0C14, 0x0001); + + /* bit 0x010: enable data valid signal */ + sp8870_writereg(state, 0x0D00, 0x010); + sp8870_writereg(state, 0x0D01, 0x000); + + return 0; +} + +static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status) +{ + struct sp8870_state* state = fe->demodulator_priv; + int status; + int signal; + + *fe_status = 0; + + status = sp8870_readreg (state, 0x0200); + if (status < 0) + return -EIO; + + signal = sp8870_readreg (state, 0x0303); + if (signal < 0) + return -EIO; + + if (signal > 0x0F) + *fe_status |= FE_HAS_SIGNAL; + if (status & 0x08) + *fe_status |= FE_HAS_SYNC; + if (status & 0x04) + *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI; + + return 0; +} + +static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber) +{ + struct sp8870_state* state = fe->demodulator_priv; + int ret; + u32 tmp; + + *ber = 0; + + ret = sp8870_readreg(state, 0xC08); + if (ret < 0) + return -EIO; + + tmp = ret & 0x3F; + + ret = sp8870_readreg(state, 0xC07); + if (ret < 0) + return -EIO; + + tmp = ret << 6; + + if (tmp >= 0x3FFF0) + tmp = ~0; + + *ber = tmp; + + return 0; +} + +static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal) +{ + struct sp8870_state* state = fe->demodulator_priv; + int ret; + u16 tmp; + + *signal = 0; + + ret = sp8870_readreg (state, 0x306); + if (ret < 0) + return -EIO; + + tmp = ret << 8; + + ret = sp8870_readreg (state, 0x303); + if (ret < 0) + return -EIO; + + tmp |= ret; + + if (tmp) + *signal = 0xFFFF - tmp; + + return 0; +} + +static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks) +{ + struct sp8870_state* state = fe->demodulator_priv; + int ret; + + *ublocks = 0; + + ret = sp8870_readreg(state, 0xC0C); + if (ret < 0) + return -EIO; + + if (ret == 0xFFFF) + ret = ~0; + + *ublocks = ret; + + return 0; +} + +/* number of trials to recover from lockup */ +#define MAXTRIALS 5 +/* maximum checks for data valid signal */ +#define MAXCHECKS 100 + +/* only for debugging: counter for detected lockups */ +static int lockups; +/* only for debugging: counter for channel switches */ +static int switches; + +static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct sp8870_state* state = fe->demodulator_priv; + + /* + The firmware of the sp8870 sometimes locks up after setting frontend parameters. + We try to detect this by checking the data valid signal. + If it is not set after MAXCHECKS we try to recover the lockup by setting + the frontend parameters again. + */ + + int err = 0; + int valid = 0; + int trials = 0; + int check_count = 0; + + dprintk("%s: frequency = %i\n", __func__, p->frequency); + + for (trials = 1; trials <= MAXTRIALS; trials++) { + + if ((err = sp8870_set_frontend_parameters(fe, p))) + return err; + + for (check_count = 0; check_count < MAXCHECKS; check_count++) { +// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0); + valid = sp8870_read_data_valid_signal(state); + if (valid) { + dprintk("%s: delay = %i usec\n", + __func__, check_count * 10); + break; + } + udelay(10); + } + if (valid) + break; + } + + if (!valid) { + printk("%s: firmware crash!!!!!!\n", __func__); + return -EIO; + } + + if (debug) { + if (valid) { + if (trials > 1) { + printk("%s: firmware lockup!!!\n", __func__); + printk("%s: recovered after %i trial(s))\n", __func__, trials - 1); + lockups++; + } + } + switches++; + printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups); + } + + return 0; +} + +static int sp8870_sleep(struct dvb_frontend* fe) +{ + struct sp8870_state* state = fe->demodulator_priv; + + // tristate TS output and disable interface pins + return sp8870_writereg(state, 0xC18, 0x000); +} + +static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 350; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct sp8870_state* state = fe->demodulator_priv; + + if (enable) { + return sp8870_writereg(state, 0x206, 0x001); + } else { + return sp8870_writereg(state, 0x206, 0x000); + } +} + +static void sp8870_release(struct dvb_frontend* fe) +{ + struct sp8870_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops sp8870_ops; + +struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, + struct i2c_adapter* i2c) +{ + struct sp8870_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->initialised = 0; + + /* check if the demod is there */ + if (sp8870_readreg(state, 0x0200) < 0) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops sp8870_ops = { + + .info = { + .name = "Spase SP8870 DVB-T", + .type = FE_OFDM, + .frequency_min = 470000000, + .frequency_max = 860000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | + FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER + }, + + .release = sp8870_release, + + .init = sp8870_init, + .sleep = sp8870_sleep, + .i2c_gate_ctrl = sp8870_i2c_gate_ctrl, + + .set_frontend = sp8870_set_frontend, + .get_tune_settings = sp8870_get_tune_settings, + + .read_status = sp8870_read_status, + .read_ber = sp8870_read_ber, + .read_signal_strength = sp8870_read_signal_strength, + .read_ucblocks = sp8870_read_uncorrected_blocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver"); +MODULE_AUTHOR("Juergen Peitz"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(sp8870_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp8870.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp8870.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp8870.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp8870.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + Driver for Spase SP8870 demodulator + + Copyright (C) 1999 Juergen Peitz + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef SP8870_H +#define SP8870_H + +#include +#include + +struct sp8870_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +#if defined(CONFIG_DVB_SP8870) || (defined(CONFIG_DVB_SP8870_MODULE) && defined(MODULE)) +extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_SP8870 + +#endif // SP8870_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp887x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp887x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp887x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp887x.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,617 @@ +/* + Driver for the Spase sp887x demodulator +*/ + +/* + * This driver needs external firmware. Please use the command + * "/Documentation/dvb/get_dvb_firmware sp887x" to + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). + */ +#define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw" + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "sp887x.h" + + +struct sp887x_state { + struct i2c_adapter* i2c; + const struct sp887x_config* config; + struct dvb_frontend frontend; + + /* demodulator private data */ + u8 initialised:1; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "sp887x: " args); \ + } while (0) + +static int i2c_writebytes (struct sp887x_state* state, u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = len }; + int err; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk ("%s: i2c write error (addr %02x, err == %i)\n", + __func__, state->config->demod_address, err); + return -EREMOTEIO; + } + + return 0; +} + +static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data) +{ + u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 4 }; + int ret; + + if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) { + /** + * in case of soft reset we ignore ACK errors... + */ + if (!(reg == 0xf1a && data == 0x000 && + (ret == -EREMOTEIO || ret == -EFAULT))) + { + printk("%s: writereg error " + "(reg %03x, data %03x, ret == %i)\n", + __func__, reg & 0xffff, data & 0xffff, ret); + return ret; + } + } + + return 0; +} + +static int sp887x_readreg (struct sp887x_state* state, u16 reg) +{ + u8 b0 [] = { reg >> 8 , reg & 0xff }; + u8 b1 [2]; + int ret; + struct i2c_msg msg[] = {{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 }}; + + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { + printk("%s: readreg error (ret == %i)\n", __func__, ret); + return -1; + } + + return (((b1[0] << 8) | b1[1]) & 0xfff); +} + +static void sp887x_microcontroller_stop (struct sp887x_state* state) +{ + dprintk("%s\n", __func__); + sp887x_writereg(state, 0xf08, 0x000); + sp887x_writereg(state, 0xf09, 0x000); + + /* microcontroller STOP */ + sp887x_writereg(state, 0xf00, 0x000); +} + +static void sp887x_microcontroller_start (struct sp887x_state* state) +{ + dprintk("%s\n", __func__); + sp887x_writereg(state, 0xf08, 0x000); + sp887x_writereg(state, 0xf09, 0x000); + + /* microcontroller START */ + sp887x_writereg(state, 0xf00, 0x001); +} + +static void sp887x_setup_agc (struct sp887x_state* state) +{ + /* setup AGC parameters */ + dprintk("%s\n", __func__); + sp887x_writereg(state, 0x33c, 0x054); + sp887x_writereg(state, 0x33b, 0x04c); + sp887x_writereg(state, 0x328, 0x000); + sp887x_writereg(state, 0x327, 0x005); + sp887x_writereg(state, 0x326, 0x001); + sp887x_writereg(state, 0x325, 0x001); + sp887x_writereg(state, 0x324, 0x001); + sp887x_writereg(state, 0x318, 0x050); + sp887x_writereg(state, 0x317, 0x3fe); + sp887x_writereg(state, 0x316, 0x001); + sp887x_writereg(state, 0x313, 0x005); + sp887x_writereg(state, 0x312, 0x002); + sp887x_writereg(state, 0x306, 0x000); + sp887x_writereg(state, 0x303, 0x000); +} + +#define BLOCKSIZE 30 +#define FW_SIZE 0x4000 +/** + * load firmware and setup MPEG interface... + */ +static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw) +{ + struct sp887x_state* state = fe->demodulator_priv; + u8 buf [BLOCKSIZE+2]; + int i; + int fw_size = fw->size; + const unsigned char *mem = fw->data; + + dprintk("%s\n", __func__); + + /* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */ + if (fw_size < FW_SIZE+10) + return -ENODEV; + + mem = fw->data + 10; + + /* soft reset */ + sp887x_writereg(state, 0xf1a, 0x000); + + sp887x_microcontroller_stop (state); + + printk ("%s: firmware upload... ", __func__); + + /* setup write pointer to -1 (end of memory) */ + /* bit 0x8000 in address is set to enable 13bit mode */ + sp887x_writereg(state, 0x8f08, 0x1fff); + + /* dummy write (wrap around to start of memory) */ + sp887x_writereg(state, 0x8f0a, 0x0000); + + for (i = 0; i < FW_SIZE; i += BLOCKSIZE) { + int c = BLOCKSIZE; + int err; + + if (i+c > FW_SIZE) + c = FW_SIZE - i; + + /* bit 0x8000 in address is set to enable 13bit mode */ + /* bit 0x4000 enables multibyte read/write transfers */ + /* write register is 0xf0a */ + buf[0] = 0xcf; + buf[1] = 0x0a; + + memcpy(&buf[2], mem + i, c); + + if ((err = i2c_writebytes (state, buf, c+2)) < 0) { + printk ("failed.\n"); + printk ("%s: i2c error (err == %i)\n", __func__, err); + return err; + } + } + + /* don't write RS bytes between packets */ + sp887x_writereg(state, 0xc13, 0x001); + + /* suppress clock if (!data_valid) */ + sp887x_writereg(state, 0xc14, 0x000); + + /* setup MPEG interface... */ + sp887x_writereg(state, 0xc1a, 0x872); + sp887x_writereg(state, 0xc1b, 0x001); + sp887x_writereg(state, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */ + sp887x_writereg(state, 0xc1a, 0x871); + + /* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */ + sp887x_writereg(state, 0x301, 0x002); + + sp887x_setup_agc(state); + + /* bit 0x010: enable data valid signal */ + sp887x_writereg(state, 0xd00, 0x010); + sp887x_writereg(state, 0x0d1, 0x000); + return 0; +}; + +static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) +{ + int known_parameters = 1; + + *reg0xc05 = 0x000; + + switch (p->u.ofdm.constellation) { + case QPSK: + break; + case QAM_16: + *reg0xc05 |= (1 << 10); + break; + case QAM_64: + *reg0xc05 |= (2 << 10); + break; + case QAM_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + switch (p->u.ofdm.hierarchy_information) { + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + *reg0xc05 |= (1 << 7); + break; + case HIERARCHY_2: + *reg0xc05 |= (2 << 7); + break; + case HIERARCHY_4: + *reg0xc05 |= (3 << 7); + break; + case HIERARCHY_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + switch (p->u.ofdm.code_rate_HP) { + case FEC_1_2: + break; + case FEC_2_3: + *reg0xc05 |= (1 << 3); + break; + case FEC_3_4: + *reg0xc05 |= (2 << 3); + break; + case FEC_5_6: + *reg0xc05 |= (3 << 3); + break; + case FEC_7_8: + *reg0xc05 |= (4 << 3); + break; + case FEC_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + if (known_parameters) + *reg0xc05 |= (2 << 1); /* use specified parameters */ + else + *reg0xc05 |= (1 << 1); /* enable autoprobing */ + + return 0; +} + +/** + * estimates division of two 24bit numbers, + * derived from the ves1820/stv0299 driver code + */ +static void divide (int n, int d, int *quotient_i, int *quotient_f) +{ + unsigned int q, r; + + r = (n % d) << 8; + q = (r / d); + + if (quotient_i) + *quotient_i = q; + + if (quotient_f) { + r = (r % d) << 8; + q = (q << 8) | (r / d); + r = (r % d) << 8; + *quotient_f = (q << 8) | (r / d); + } +} + +static void sp887x_correct_offsets (struct sp887x_state* state, + struct dvb_frontend_parameters *p, + int actual_freq) +{ + static const u32 srate_correction [] = { 1879617, 4544878, 8098561 }; + int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; + int freq_offset = actual_freq - p->frequency; + int sysclock = 61003; //[kHz] + int ifreq = 36000000; + int freq; + int frequency_shift; + + if (p->inversion == INVERSION_ON) + freq = ifreq - freq_offset; + else + freq = ifreq + freq_offset; + + divide(freq / 333, sysclock, NULL, &frequency_shift); + + if (p->inversion == INVERSION_ON) + frequency_shift = -frequency_shift; + + /* sample rate correction */ + sp887x_writereg(state, 0x319, srate_correction[bw_index] >> 12); + sp887x_writereg(state, 0x31a, srate_correction[bw_index] & 0xfff); + + /* carrier offset correction */ + sp887x_writereg(state, 0x309, frequency_shift >> 12); + sp887x_writereg(state, 0x30a, frequency_shift & 0xfff); +} + +static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct sp887x_state* state = fe->demodulator_priv; + unsigned actual_freq; + int err; + u16 val, reg0xc05; + + if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && + p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ && + p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ) + return -EINVAL; + + if ((err = configure_reg0xc05(p, ®0xc05))) + return err; + + sp887x_microcontroller_stop(state); + + /* setup the PLL */ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + if (fe->ops.tuner_ops.get_frequency) { + fe->ops.tuner_ops.get_frequency(fe, &actual_freq); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } else { + actual_freq = p->frequency; + } + + /* read status reg in order to clear u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + val = 2; + else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + val = 1; + else + val = 0; + + sp887x_writereg(state, 0x311, val); + + /* scan order: 2k first = 0, 8k first = 1 */ + if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) + sp887x_writereg(state, 0x338, 0x000); + else + sp887x_writereg(state, 0x338, 0x001); + + sp887x_writereg(state, 0xc05, reg0xc05); + + if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + val = 2 << 3; + else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + val = 3 << 3; + else + val = 0 << 3; + + /* enable OFDM and SAW bits as lock indicators in sync register 0xf17, + * optimize algorithm for given bandwidth... + */ + sp887x_writereg(state, 0xf14, 0x160 | val); + sp887x_writereg(state, 0xf15, 0x000); + + sp887x_microcontroller_start(state); + return 0; +} + +static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct sp887x_state* state = fe->demodulator_priv; + u16 snr12 = sp887x_readreg(state, 0xf16); + u16 sync0x200 = sp887x_readreg(state, 0x200); + u16 sync0xf17 = sp887x_readreg(state, 0xf17); + + *status = 0; + + if (snr12 > 0x00f) + *status |= FE_HAS_SIGNAL; + + //if (sync0x200 & 0x004) + // *status |= FE_HAS_SYNC | FE_HAS_CARRIER; + + //if (sync0x200 & 0x008) + // *status |= FE_HAS_VITERBI; + + if ((sync0xf17 & 0x00f) == 0x002) { + *status |= FE_HAS_LOCK; + *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER; + } + + if (sync0x200 & 0x001) { /* tuner adjustment requested...*/ + int steps = (sync0x200 >> 4) & 0x00f; + if (steps & 0x008) + steps = -steps; + dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n", + steps); + } + + return 0; +} + +static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct sp887x_state* state = fe->demodulator_priv; + + *ber = (sp887x_readreg(state, 0xc08) & 0x3f) | + (sp887x_readreg(state, 0xc07) << 6); + sp887x_writereg(state, 0xc08, 0x000); + sp887x_writereg(state, 0xc07, 0x000); + if (*ber >= 0x3fff0) + *ber = ~0; + + return 0; +} + +static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct sp887x_state* state = fe->demodulator_priv; + + u16 snr12 = sp887x_readreg(state, 0xf16); + u32 signal = 3 * (snr12 << 4); + *strength = (signal < 0xffff) ? signal : 0xffff; + + return 0; +} + +static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct sp887x_state* state = fe->demodulator_priv; + + u16 snr12 = sp887x_readreg(state, 0xf16); + *snr = (snr12 << 4) | (snr12 >> 8); + + return 0; +} + +static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct sp887x_state* state = fe->demodulator_priv; + + *ucblocks = sp887x_readreg(state, 0xc0c); + if (*ucblocks == 0xfff) + *ucblocks = ~0; + + return 0; +} + +static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct sp887x_state* state = fe->demodulator_priv; + + if (enable) { + return sp887x_writereg(state, 0x206, 0x001); + } else { + return sp887x_writereg(state, 0x206, 0x000); + } +} + +static int sp887x_sleep(struct dvb_frontend* fe) +{ + struct sp887x_state* state = fe->demodulator_priv; + + /* tristate TS output and disable interface pins */ + sp887x_writereg(state, 0xc18, 0x000); + + return 0; +} + +static int sp887x_init(struct dvb_frontend* fe) +{ + struct sp887x_state* state = fe->demodulator_priv; + const struct firmware *fw = NULL; + int ret; + + if (!state->initialised) { + /* request the firmware, this will block until someone uploads it */ + printk("sp887x: waiting for firmware upload (%s)...\n", SP887X_DEFAULT_FIRMWARE); + ret = state->config->request_firmware(fe, &fw, SP887X_DEFAULT_FIRMWARE); + if (ret) { + printk("sp887x: no firmware upload (timeout or file not found?)\n"); + return ret; + } + + ret = sp887x_initial_setup(fe, fw); + release_firmware(fw); + if (ret) { + printk("sp887x: writing firmware to device failed\n"); + return ret; + } + printk("sp887x: firmware upload complete\n"); + state->initialised = 1; + } + + /* enable TS output and interface pins */ + sp887x_writereg(state, 0xc18, 0x00d); + + return 0; +} + +static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 350; + fesettings->step_size = 166666*2; + fesettings->max_drift = (166666*2)+1; + return 0; +} + +static void sp887x_release(struct dvb_frontend* fe) +{ + struct sp887x_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops sp887x_ops; + +struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, + struct i2c_adapter* i2c) +{ + struct sp887x_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct sp887x_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->initialised = 0; + + /* check if the demod is there */ + if (sp887x_readreg(state, 0x0200) < 0) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops sp887x_ops = { + + .info = { + .name = "Spase SP887x DVB-T", + .type = FE_OFDM, + .frequency_min = 50500000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_RECOVER + }, + + .release = sp887x_release, + + .init = sp887x_init, + .sleep = sp887x_sleep, + .i2c_gate_ctrl = sp887x_i2c_gate_ctrl, + + .set_frontend = sp887x_setup_frontend_parameters, + .get_tune_settings = sp887x_get_tune_settings, + + .read_status = sp887x_read_status, + .read_ber = sp887x_read_ber, + .read_signal_strength = sp887x_read_signal_strength, + .read_snr = sp887x_read_snr, + .read_ucblocks = sp887x_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(sp887x_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp887x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp887x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp887x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/sp887x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,32 @@ +/* + Driver for the Spase sp887x demodulator +*/ + +#ifndef SP887X_H +#define SP887X_H + +#include +#include + +struct sp887x_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +#if defined(CONFIG_DVB_SP887X) || (defined(CONFIG_DVB_SP887X_MODULE) && defined(MODULE)) +extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_SP887X + +#endif // SP887X_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_algo.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_algo.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_algo.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_algo.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1522 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "stb0899_drv.h" +#include "stb0899_priv.h" +#include "stb0899_reg.h" + +static inline u32 stb0899_do_div(u64 n, u32 d) +{ + /* wrap do_div() for ease of use */ + + do_div(n, d); + return n; +} + +#if 0 +/* These functions are currently unused */ +/* + * stb0899_calc_srate + * Compute symbol rate + */ +static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr) +{ + u64 tmp; + + /* srate = (SFR * master_clk) >> 20 */ + + /* sfr is of size 20 bit, stored with an offset of 4 bit */ + tmp = (((u32)sfr[0]) << 16) | (((u32)sfr[1]) << 8) | sfr[2]; + tmp &= ~0xf; + tmp *= master_clk; + tmp >>= 24; + + return tmp; +} + +/* + * stb0899_get_srate + * Get the current symbol rate + */ +static u32 stb0899_get_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + u8 sfr[3]; + + stb0899_read_regs(state, STB0899_SFRH, sfr, 3); + + return stb0899_calc_srate(internal->master_clk, sfr); +} +#endif + +/* + * stb0899_set_srate + * Set symbol frequency + * MasterClock: master clock frequency (hz) + * SymbolRate: symbol rate (bauds) + * return symbol frequency + */ +static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 srate) +{ + u32 tmp; + u8 sfr[3]; + + dprintk(state->verbose, FE_DEBUG, 1, "-->"); + /* + * in order to have the maximum precision, the symbol rate entered into + * the chip is computed as the closest value of the "true value". + * In this purpose, the symbol rate value is rounded (1 is added on the bit + * below the LSB ) + * + * srate = (SFR * master_clk) >> 20 + * <=> + * SFR = srate << 20 / master_clk + * + * rounded: + * SFR = (srate << 21 + master_clk) / (2 * master_clk) + * + * stored as 20 bit number with an offset of 4 bit: + * sfr = SFR << 4; + */ + + tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk); + tmp <<= 4; + + sfr[0] = tmp >> 16; + sfr[1] = tmp >> 8; + sfr[2] = tmp; + + stb0899_write_regs(state, STB0899_SFRH, sfr, 3); + + return srate; +} + +/* + * stb0899_calc_derot_time + * Compute the amount of time needed by the derotator to lock + * SymbolRate: Symbol rate + * return: derotator time constant (ms) + */ +static long stb0899_calc_derot_time(long srate) +{ + if (srate > 0) + return (100000 / (srate / 1000)); + else + return 0; +} + +/* + * stb0899_carr_width + * Compute the width of the carrier + * return: width of carrier (kHz or Mhz) + */ +long stb0899_carr_width(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + + return (internal->srate + (internal->srate * internal->rolloff) / 100); +} + +/* + * stb0899_first_subrange + * Compute the first subrange of the search + */ +static void stb0899_first_subrange(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + struct stb0899_config *config = state->config; + + int range = 0; + u32 bandwidth = 0; + + if (config->tuner_get_bandwidth) { + stb0899_i2c_gate_ctrl(&state->frontend, 1); + config->tuner_get_bandwidth(&state->frontend, &bandwidth); + stb0899_i2c_gate_ctrl(&state->frontend, 0); + range = bandwidth - stb0899_carr_width(state) / 2; + } + + if (range > 0) + internal->sub_range = min(internal->srch_range, range); + else + internal->sub_range = 0; + + internal->freq = params->freq; + internal->tuner_offst = 0L; + internal->sub_dir = 1; +} + +/* + * stb0899_check_tmg + * check for timing lock + * internal.Ttiming: time to wait for loop lock + */ +static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + int lock; + u8 reg; + s8 timing; + + msleep(internal->t_derot); + + stb0899_write_reg(state, STB0899_RTF, 0xf2); + reg = stb0899_read_reg(state, STB0899_TLIR); + lock = STB0899_GETFIELD(TLIR_TMG_LOCK_IND, reg); + timing = stb0899_read_reg(state, STB0899_RTF); + + if (lock >= 42) { + if ((lock > 48) && (abs(timing) >= 110)) { + internal->status = ANALOGCARRIER; + dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !"); + } else { + internal->status = TIMINGOK; + dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK !"); + } + } else { + internal->status = NOTIMING; + dprintk(state->verbose, FE_DEBUG, 1, "-->NO TIMING !"); + } + return internal->status; +} + +/* + * stb0899_search_tmg + * perform a fs/2 zig-zag to find timing + */ +static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + short int derot_step, derot_freq = 0, derot_limit, next_loop = 3; + int index = 0; + u8 cfr[2]; + + internal->status = NOTIMING; + + /* timing loop computation & symbol rate optimisation */ + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_step = (params->srate / 2L) / internal->mclk; + + while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) { + index++; + derot_freq += index * internal->direction * derot_step; /* next derot zig zag position */ + + if (abs(derot_freq) > derot_limit) + next_loop--; + + if (next_loop) { + STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + } + internal->direction = -internal->direction; /* Change zigzag direction */ + } + + if (internal->status == TIMINGOK) { + stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ + internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); + dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq); + } + + return internal->status; +} + +/* + * stb0899_check_carrier + * Check for carrier found + */ +static enum stb0899_status stb0899_check_carrier(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + u8 reg; + + msleep(internal->t_derot); /* wait for derotator ok */ + + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + reg = stb0899_read_reg(state, STB0899_DSTATUS); + dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg); + if (STB0899_GETFIELD(CARRIER_FOUND, reg)) { + internal->status = CARRIEROK; + dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !"); + } else { + internal->status = NOCARRIER; + dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !"); + } + + return internal->status; +} + +/* + * stb0899_search_carrier + * Search for a QPSK carrier with the derotator + */ +static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + + short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3; + int index = 0; + u8 cfr[2]; + u8 reg; + + internal->status = NOCARRIER; + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_freq = internal->derot_freq; + + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + do { + dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk); + if (stb0899_check_carrier(state) == NOCARRIER) { + index++; + last_derot_freq = derot_freq; + derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */ + + if(abs(derot_freq) > derot_limit) + next_loop--; + + if (next_loop) { + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + } + } + + internal->direction = -internal->direction; /* Change zigzag direction */ + } while ((internal->status != CARRIEROK) && next_loop); + + if (internal->status == CARRIEROK) { + stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ + internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); + dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq); + } else { + internal->derot_freq = last_derot_freq; + } + + return internal->status; +} + +/* + * stb0899_check_data + * Check for data found + */ +static enum stb0899_status stb0899_check_data(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + int lock = 0, index = 0, dataTime = 500, loop; + u8 reg; + + internal->status = NODATA; + + /* RESET FEC */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESACS, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + msleep(1); + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESACS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + if (params->srate <= 2000000) + dataTime = 2000; + else if (params->srate <= 5000000) + dataTime = 1500; + else if (params->srate <= 15000000) + dataTime = 1000; + else + dataTime = 500; + + stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop */ + while (1) { + /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP */ + reg = stb0899_read_reg(state, STB0899_VSTATUS); + lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg); + loop = STB0899_GETFIELD(VSTATUS_END_LOOPVIT, reg); + + if (lock || loop || (index > dataTime)) + break; + index++; + } + + if (lock) { /* DATA LOCK indicator */ + internal->status = DATAOK; + dprintk(state->verbose, FE_DEBUG, 1, "-----------------> DATA OK !"); + } + + return internal->status; +} + +/* + * stb0899_search_data + * Search for a QPSK carrier with the derotator + */ +static enum stb0899_status stb0899_search_data(struct stb0899_state *state) +{ + short int derot_freq, derot_step, derot_limit, next_loop = 3; + u8 cfr[2]; + u8 reg; + int index = 1; + + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + derot_step = (params->srate / 4L) / internal->mclk; + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_freq = internal->derot_freq; + + do { + if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) { + + derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */ + if (abs(derot_freq) > derot_limit) + next_loop--; + + if (next_loop) { + dprintk(state->verbose, FE_DEBUG, 1, "Derot freq=%d, mclk=%d", derot_freq, internal->mclk); + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + + stb0899_check_carrier(state); + index++; + } + } + internal->direction = -internal->direction; /* change zig zag direction */ + } while ((internal->status != DATAOK) && next_loop); + + if (internal->status == DATAOK) { + stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ + internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); + dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq); + } + + return internal->status; +} + +/* + * stb0899_check_range + * check if the found frequency is in the correct range + */ +static enum stb0899_status stb0899_check_range(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + int range_offst, tp_freq; + + range_offst = internal->srch_range / 2000; + tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000; + + if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) { + internal->status = RANGEOK; + dprintk(state->verbose, FE_DEBUG, 1, "----> RANGEOK !"); + } else { + internal->status = OUTOFRANGE; + dprintk(state->verbose, FE_DEBUG, 1, "----> OUT OF RANGE !"); + } + + return internal->status; +} + +/* + * NextSubRange + * Compute the next subrange of the search + */ +static void next_sub_range(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + long old_sub_range; + + if (internal->sub_dir > 0) { + old_sub_range = internal->sub_range; + internal->sub_range = min((internal->srch_range / 2) - + (internal->tuner_offst + internal->sub_range / 2), + internal->sub_range); + + if (internal->sub_range < 0) + internal->sub_range = 0; + + internal->tuner_offst += (old_sub_range + internal->sub_range) / 2; + } + + internal->freq = params->freq + (internal->sub_dir * internal->tuner_offst) / 1000; + internal->sub_dir = -internal->sub_dir; +} + +/* + * stb0899_dvbs_algo + * Search for a signal, timing, carrier and data for a + * given frequency in a given range + */ +enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state) +{ + struct stb0899_params *params = &state->params; + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u8 bclc, reg; + u8 cfr[2]; + u8 eq_const[10]; + s32 clnI = 3; + u32 bandwidth = 0; + + /* BETA values rated @ 99MHz */ + s32 betaTab[5][4] = { + /* 5 10 20 30MBps */ + { 37, 34, 32, 31 }, /* QPSK 1/2 */ + { 37, 35, 33, 31 }, /* QPSK 2/3 */ + { 37, 35, 33, 31 }, /* QPSK 3/4 */ + { 37, 36, 33, 32 }, /* QPSK 5/6 */ + { 37, 36, 33, 32 } /* QPSK 7/8 */ + }; + + internal->direction = 1; + + stb0899_set_srate(state, internal->master_clk, params->srate); + /* Carrier loop optimization versus symbol rate for acquisition*/ + if (params->srate <= 5000000) { + stb0899_write_reg(state, STB0899_ACLC, 0x89); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x1c); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 0; + } else if (params->srate <= 15000000) { + stb0899_write_reg(state, STB0899_ACLC, 0xc9); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x22); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 1; + } else if(params->srate <= 25000000) { + stb0899_write_reg(state, STB0899_ACLC, 0x89); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x27); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 2; + } else { + stb0899_write_reg(state, STB0899_ACLC, 0xc8); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x29); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 3; + } + + dprintk(state->verbose, FE_DEBUG, 1, "Set the timing loop to acquisition"); + /* Set the timing loop to acquisition */ + stb0899_write_reg(state, STB0899_RTC, 0x46); + stb0899_write_reg(state, STB0899_CFD, 0xee); + + /* !! WARNING !! + * Do not read any status variables while acquisition, + * If any needed, read before the acquisition starts + * querying status while acquiring causes the + * acquisition to go bad and hence no locks. + */ + dprintk(state->verbose, FE_DEBUG, 1, "Derot Percent=%d Srate=%d mclk=%d", + internal->derot_percent, params->srate, internal->mclk); + + /* Initial calculations */ + internal->derot_step = internal->derot_percent * (params->srate / 1000L) / internal->mclk; /* DerotStep/1000 * Fsymbol */ + internal->t_derot = stb0899_calc_derot_time(params->srate); + internal->t_data = 500; + + dprintk(state->verbose, FE_DEBUG, 1, "RESET stream merger"); + /* RESET Stream merger */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + /* + * Set KDIVIDER to an intermediate value between + * 1/2 and 7/8 for acquisition + */ + reg = stb0899_read_reg(state, STB0899_DEMAPVIT); + STB0899_SETFIELD_VAL(DEMAPVIT_KDIVIDER, reg, 60); + stb0899_write_reg(state, STB0899_DEMAPVIT, reg); + + stb0899_write_reg(state, STB0899_EQON, 0x01); /* Equalizer OFF while acquiring */ + stb0899_write_reg(state, STB0899_VITSYNC, 0x19); + + stb0899_first_subrange(state); + do { + /* Initialisations */ + cfr[0] = cfr[1] = 0; + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* RESET derotator frequency */ + + stb0899_write_reg(state, STB0899_RTF, 0); + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + internal->derot_freq = 0; + internal->status = NOAGC1; + + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + /* Move tuner to frequency */ + dprintk(state->verbose, FE_DEBUG, 1, "Tuner set frequency"); + if (state->config->tuner_set_frequency) + state->config->tuner_set_frequency(&state->frontend, internal->freq); + + if (state->config->tuner_get_frequency) + state->config->tuner_get_frequency(&state->frontend, &internal->freq); + + msleep(internal->t_agc1 + internal->t_agc2 + internal->t_derot); /* AGC1, AGC2 and timing loop */ + dprintk(state->verbose, FE_DEBUG, 1, "current derot freq=%d", internal->derot_freq); + internal->status = AGC1OK; + + /* There is signal in the band */ + if (config->tuner_get_bandwidth) + config->tuner_get_bandwidth(&state->frontend, &bandwidth); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + + if (params->srate <= bandwidth / 2) + stb0899_search_tmg(state); /* For low rates (SCPC) */ + else + stb0899_check_tmg(state); /* For high rates (MCPC) */ + + if (internal->status == TIMINGOK) { + dprintk(state->verbose, FE_DEBUG, 1, + "TIMING OK ! Derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + if (stb0899_search_carrier(state) == CARRIEROK) { /* Search for carrier */ + dprintk(state->verbose, FE_DEBUG, 1, + "CARRIER OK ! Derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + if (stb0899_search_data(state) == DATAOK) { /* Check for data */ + dprintk(state->verbose, FE_DEBUG, 1, + "DATA OK ! Derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + if (stb0899_check_range(state) == RANGEOK) { + dprintk(state->verbose, FE_DEBUG, 1, + "RANGE OK ! derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000); + reg = stb0899_read_reg(state, STB0899_PLPARM); + internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg); + dprintk(state->verbose, FE_DEBUG, 1, + "freq=%d, internal resultant freq=%d", + params->freq, internal->freq); + + dprintk(state->verbose, FE_DEBUG, 1, + "internal puncture rate=%d", + internal->fecrate); + } + } + } + } + if (internal->status != RANGEOK) + next_sub_range(state); + + } while (internal->sub_range && internal->status != RANGEOK); + + /* Set the timing loop to tracking */ + stb0899_write_reg(state, STB0899_RTC, 0x33); + stb0899_write_reg(state, STB0899_CFD, 0xf7); + /* if locked and range ok, set Kdiv */ + if (internal->status == RANGEOK) { + dprintk(state->verbose, FE_DEBUG, 1, "Locked & Range OK !"); + stb0899_write_reg(state, STB0899_EQON, 0x41); /* Equalizer OFF while acquiring */ + stb0899_write_reg(state, STB0899_VITSYNC, 0x39); /* SN to b'11 for acquisition */ + + /* + * Carrier loop optimization versus + * symbol Rate/Puncture Rate for Tracking + */ + reg = stb0899_read_reg(state, STB0899_BCLC); + switch (internal->fecrate) { + case STB0899_FEC_1_2: /* 13 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 0x1a); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[0][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_2_3: /* 18 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 44); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[1][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_3_4: /* 21 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 60); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[2][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_5_6: /* 24 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 75); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[3][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_6_7: /* 25 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 88); + stb0899_write_reg(state, STB0899_ACLC, 0x88); + stb0899_write_reg(state, STB0899_BCLC, 0x9a); + break; + case STB0899_FEC_7_8: /* 26 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 94); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[4][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported Puncture Rate"); + break; + } + /* release stream merger RESET */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + /* disable carrier detector */ + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 0); + stb0899_write_reg(state, STB0899_CFD, reg); + + stb0899_read_regs(state, STB0899_EQUAI1, eq_const, 10); + } + + return internal->status; +} + +/* + * stb0899_dvbs2_config_uwp + * Configure UWP state machine + */ +static void stb0899_dvbs2_config_uwp(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + u32 uwp1, uwp2, uwp3, reg; + + uwp1 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1); + uwp2 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL2); + uwp3 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL3); + + STB0899_SETFIELD_VAL(UWP_ESN0_AVE, uwp1, config->esno_ave); + STB0899_SETFIELD_VAL(UWP_ESN0_QUANT, uwp1, config->esno_quant); + STB0899_SETFIELD_VAL(UWP_TH_SOF, uwp1, config->uwp_threshold_sof); + + STB0899_SETFIELD_VAL(FE_COARSE_TRK, uwp2, internal->av_frame_coarse); + STB0899_SETFIELD_VAL(FE_FINE_TRK, uwp2, internal->av_frame_fine); + STB0899_SETFIELD_VAL(UWP_MISS_TH, uwp2, config->miss_threshold); + + STB0899_SETFIELD_VAL(UWP_TH_ACQ, uwp3, config->uwp_threshold_acq); + STB0899_SETFIELD_VAL(UWP_TH_TRACK, uwp3, config->uwp_threshold_track); + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL1, STB0899_OFF0_UWP_CNTRL1, uwp1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL2, STB0899_OFF0_UWP_CNTRL2, uwp2); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL3, STB0899_OFF0_UWP_CNTRL3, uwp3); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, SOF_SRCH_TO); + STB0899_SETFIELD_VAL(SOF_SEARCH_TIMEOUT, reg, config->sof_search_timeout); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_SOF_SRCH_TO, STB0899_OFF0_SOF_SRCH_TO, reg); +} + +/* + * stb0899_dvbs2_config_csm_auto + * Set CSM to AUTO mode + */ +static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state) +{ + u32 reg; + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg); +} + +static long Log2Int(int number) +{ + int i; + + i = 0; + while ((1 << i) <= abs(number)) + i++; + + if (number == 0) + i = 1; + + return i - 1; +} + +/* + * stb0899_dvbs2_calc_srate + * compute BTR_NOM_FREQ for the symbol rate + */ +static u32 stb0899_dvbs2_calc_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u32 dec_ratio, dec_rate, decim, remain, intval, btr_nom_freq; + u32 master_clk, srate; + + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + dec_rate = Log2Int(dec_ratio); + decim = 1 << dec_rate; + master_clk = internal->master_clk / 1000; + srate = internal->srate / 1000; + + if (decim <= 4) { + intval = (decim * (1 << (config->btr_nco_bits - 1))) / master_clk; + remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk; + } else { + intval = (1 << (config->btr_nco_bits - 1)) / (master_clk / 100) * decim / 100; + remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk; + } + btr_nom_freq = (intval * srate) + ((remain * srate) / master_clk); + + return btr_nom_freq; +} + +/* + * stb0899_dvbs2_calc_dev + * compute the correction to be applied to symbol rate + */ +static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + u32 dec_ratio, correction, master_clk, srate; + + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + + master_clk = internal->master_clk / 1000; /* for integer Caculation*/ + srate = internal->srate / 1000; /* for integer Caculation*/ + correction = (512 * master_clk) / (2 * dec_ratio * srate); + + return correction; +} + +/* + * stb0899_dvbs2_set_srate + * Set DVBS2 symbol rate + */ +static void stb0899_dvbs2_set_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + + u32 dec_ratio, dec_rate, win_sel, decim, f_sym, btr_nom_freq; + u32 correction, freq_adj, band_lim, decim_cntrl, reg; + u8 anti_alias; + + /*set decimation to 1*/ + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + dec_rate = Log2Int(dec_ratio); + + win_sel = 0; + if (dec_rate >= 5) + win_sel = dec_rate - 4; + + decim = (1 << dec_rate); + /* (FSamp/Fsymbol *100) for integer Caculation */ + f_sym = internal->master_clk / ((decim * internal->srate) / 1000); + + if (f_sym <= 2250) /* don't band limit signal going into btr block*/ + band_lim = 1; + else + band_lim = 0; /* band limit signal going into btr block*/ + + decim_cntrl = ((win_sel << 3) & 0x18) + ((band_lim << 5) & 0x20) + (dec_rate & 0x7); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DECIM_CNTRL, STB0899_OFF0_DECIM_CNTRL, decim_cntrl); + + if (f_sym <= 3450) + anti_alias = 0; + else if (f_sym <= 4250) + anti_alias = 1; + else + anti_alias = 2; + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ANTI_ALIAS_SEL, STB0899_OFF0_ANTI_ALIAS_SEL, anti_alias); + btr_nom_freq = stb0899_dvbs2_calc_srate(state); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_NOM_FREQ, STB0899_OFF0_BTR_NOM_FREQ, btr_nom_freq); + + correction = stb0899_dvbs2_calc_dev(state); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL); + STB0899_SETFIELD_VAL(BTR_FREQ_CORR, reg, correction); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg); + + /* scale UWP+CSM frequency to sample rate*/ + freq_adj = internal->srate / (internal->master_clk / 4096); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_FREQ_ADJ_SCALE, STB0899_OFF0_FREQ_ADJ_SCALE, freq_adj); +} + +/* + * stb0899_dvbs2_set_btr_loopbw + * set bit timing loop bandwidth as a percentage of the symbol rate + */ +static void stb0899_dvbs2_set_btr_loopbw(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u32 sym_peak = 23, zeta = 707, loopbw_percent = 60; + s32 dec_ratio, dec_rate, k_btr1_rshft, k_btr1, k_btr0_rshft; + s32 k_btr0, k_btr2_rshft, k_direct_shift, k_indirect_shift; + u32 decim, K, wn, k_direct, k_indirect; + u32 reg; + + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + dec_rate = Log2Int(dec_ratio); + decim = (1 << dec_rate); + + sym_peak *= 576000; + K = (1 << config->btr_nco_bits) / (internal->master_clk / 1000); + K *= (internal->srate / 1000000) * decim; /*k=k 10^-8*/ + + if (K != 0) { + K = sym_peak / K; + wn = (4 * zeta * zeta) + 1000000; + wn = (2 * (loopbw_percent * 1000) * 40 * zeta) /wn; /*wn =wn 10^-8*/ + + k_indirect = (wn * wn) / K; + k_indirect = k_indirect; /*kindirect = kindirect 10^-6*/ + k_direct = (2 * wn * zeta) / K; /*kDirect = kDirect 10^-2*/ + k_direct *= 100; + + k_direct_shift = Log2Int(k_direct) - Log2Int(10000) - 2; + k_btr1_rshft = (-1 * k_direct_shift) + config->btr_gain_shift_offset; + k_btr1 = k_direct / (1 << k_direct_shift); + k_btr1 /= 10000; + + k_indirect_shift = Log2Int(k_indirect + 15) - 20 /*- 2*/; + k_btr0_rshft = (-1 * k_indirect_shift) + config->btr_gain_shift_offset; + k_btr0 = k_indirect * (1 << (-k_indirect_shift)); + k_btr0 /= 1000000; + + k_btr2_rshft = 0; + if (k_btr0_rshft > 15) { + k_btr2_rshft = k_btr0_rshft - 15; + k_btr0_rshft = 15; + } + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_LOOP_GAIN); + STB0899_SETFIELD_VAL(KBTR0_RSHFT, reg, k_btr0_rshft); + STB0899_SETFIELD_VAL(KBTR0, reg, k_btr0); + STB0899_SETFIELD_VAL(KBTR1_RSHFT, reg, k_btr1_rshft); + STB0899_SETFIELD_VAL(KBTR1, reg, k_btr1); + STB0899_SETFIELD_VAL(KBTR2_RSHFT, reg, k_btr2_rshft); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, reg); + } else + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, 0xc4c4f); +} + +/* + * stb0899_dvbs2_set_carr_freq + * set nominal frequency for carrier search + */ +static void stb0899_dvbs2_set_carr_freq(struct stb0899_state *state, s32 carr_freq, u32 master_clk) +{ + struct stb0899_config *config = state->config; + s32 crl_nom_freq; + u32 reg; + + crl_nom_freq = (1 << config->crl_nco_bits) / master_clk; + crl_nom_freq *= carr_freq; + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); + STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, crl_nom_freq); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); +} + +/* + * stb0899_dvbs2_init_calc + * Initialize DVBS2 UWP, CSM, carrier and timing loops + */ +static void stb0899_dvbs2_init_calc(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + s32 steps, step_size; + u32 range, reg; + + /* config uwp and csm */ + stb0899_dvbs2_config_uwp(state); + stb0899_dvbs2_config_csm_auto(state); + + /* initialize BTR */ + stb0899_dvbs2_set_srate(state); + stb0899_dvbs2_set_btr_loopbw(state); + + if (internal->srate / 1000000 >= 15) + step_size = (1 << 17) / 5; + else if (internal->srate / 1000000 >= 10) + step_size = (1 << 17) / 7; + else if (internal->srate / 1000000 >= 5) + step_size = (1 << 17) / 10; + else + step_size = (1 << 17) / 4; + + range = internal->srch_range / 1000000; + steps = (10 * range * (1 << 17)) / (step_size * (internal->srate / 1000000)); + steps = (steps + 6) / 10; + steps = (steps == 0) ? 1 : steps; + if (steps % 2 == 0) + stb0899_dvbs2_set_carr_freq(state, internal->center_freq - + (internal->step_size * (internal->srate / 20000000)), + (internal->master_clk) / 1000000); + else + stb0899_dvbs2_set_carr_freq(state, internal->center_freq, (internal->master_clk) / 1000000); + + /*Set Carrier Search params (zigzag, num steps and freq step size*/ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, ACQ_CNTRL2); + STB0899_SETFIELD_VAL(ZIGZAG, reg, 1); + STB0899_SETFIELD_VAL(NUM_STEPS, reg, steps); + STB0899_SETFIELD_VAL(FREQ_STEPSIZE, reg, step_size); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQ_CNTRL2, STB0899_OFF0_ACQ_CNTRL2, reg); +} + +/* + * stb0899_dvbs2_btr_init + * initialize the timing loop + */ +static void stb0899_dvbs2_btr_init(struct stb0899_state *state) +{ + u32 reg; + + /* set enable BTR loopback */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL); + STB0899_SETFIELD_VAL(INTRP_PHS_SENSE, reg, 1); + STB0899_SETFIELD_VAL(BTR_ERR_ENA, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg); + + /* fix btr freq accum at 0 */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x10000000); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x00000000); + + /* fix btr freq accum at 0 */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x10000000); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x00000000); +} + +/* + * stb0899_dvbs2_reacquire + * trigger a DVB-S2 acquisition + */ +static void stb0899_dvbs2_reacquire(struct stb0899_state *state) +{ + u32 reg = 0; + + /* demod soft reset */ + STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg); + + /*Reset Timing Loop */ + stb0899_dvbs2_btr_init(state); + + /* reset Carrier loop */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, (1 << 30)); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_LOOP_GAIN, STB0899_OFF0_CRL_LOOP_GAIN, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, (1 << 30)); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, 0); + + /*release demod soft reset */ + reg = 0; + STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg); + + /* start acquisition process */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQUIRE_TRIG, STB0899_OFF0_ACQUIRE_TRIG, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_LOCK_LOST, STB0899_OFF0_LOCK_LOST, 0); + + /* equalizer Init */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 1); + + /*Start equilizer */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 0); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); + STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0); + STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 0); + STB0899_SETFIELD_VAL(EQ_DELAY, reg, 0x05); + STB0899_SETFIELD_VAL(EQ_ADAPT_MODE, reg, 0x01); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); + + /* RESET Packet delineator */ + stb0899_write_reg(state, STB0899_PDELCTRL, 0x4a); +} + +/* + * stb0899_dvbs2_get_dmd_status + * get DVB-S2 Demod LOCK status + */ +static enum stb0899_status stb0899_dvbs2_get_dmd_status(struct stb0899_state *state, int timeout) +{ + int time = -10, lock = 0, uwp, csm; + u32 reg; + + do { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS); + dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg); + if (STB0899_GETFIELD(IF_AGC_LOCK, reg)) + dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !"); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2); + dprintk(state->verbose, FE_DEBUG, 1, "----------->DMD STAT2=[0x%02x]", reg); + uwp = STB0899_GETFIELD(UWP_LOCK, reg); + csm = STB0899_GETFIELD(CSM_LOCK, reg); + if (uwp && csm) + lock = 1; + + time += 10; + msleep(10); + + } while ((!lock) && (time <= timeout)); + + if (lock) { + dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 LOCK !"); + return DVBS2_DEMOD_LOCK; + } else { + return DVBS2_DEMOD_NOLOCK; + } +} + +/* + * stb0899_dvbs2_get_data_lock + * get FEC status + */ +static int stb0899_dvbs2_get_data_lock(struct stb0899_state *state, int timeout) +{ + int time = 0, lock = 0; + u8 reg; + + while ((!lock) && (time < timeout)) { + reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1); + dprintk(state->verbose, FE_DEBUG, 1, "---------> CFGPDELSTATUS=[0x%02x]", reg); + lock = STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg); + time++; + } + + return lock; +} + +/* + * stb0899_dvbs2_get_fec_status + * get DVB-S2 FEC LOCK status + */ +static enum stb0899_status stb0899_dvbs2_get_fec_status(struct stb0899_state *state, int timeout) +{ + int time = 0, Locked; + + do { + Locked = stb0899_dvbs2_get_data_lock(state, 1); + time++; + msleep(1); + + } while ((!Locked) && (time < timeout)); + + if (Locked) { + dprintk(state->verbose, FE_DEBUG, 1, "---------->DVB-S2 FEC LOCK !"); + return DVBS2_FEC_LOCK; + } else { + return DVBS2_FEC_NOLOCK; + } +} + + +/* + * stb0899_dvbs2_init_csm + * set parameters for manual mode + */ +static void stb0899_dvbs2_init_csm(struct stb0899_state *state, int pilots, enum stb0899_modcod modcod) +{ + struct stb0899_internal *internal = &state->internal; + + s32 dvt_tbl = 1, two_pass = 0, agc_gain = 6, agc_shift = 0, loop_shift = 0, phs_diff_thr = 0x80; + s32 gamma_acq, gamma_rho_acq, gamma_trk, gamma_rho_trk, lock_count_thr; + u32 csm1, csm2, csm3, csm4; + + if (((internal->master_clk / internal->srate) <= 4) && (modcod <= 11) && (pilots == 1)) { + switch (modcod) { + case STB0899_QPSK_12: + gamma_acq = 25; + gamma_rho_acq = 2700; + gamma_trk = 12; + gamma_rho_trk = 180; + lock_count_thr = 8; + break; + case STB0899_QPSK_35: + gamma_acq = 38; + gamma_rho_acq = 7182; + gamma_trk = 14; + gamma_rho_trk = 308; + lock_count_thr = 8; + break; + case STB0899_QPSK_23: + gamma_acq = 42; + gamma_rho_acq = 9408; + gamma_trk = 17; + gamma_rho_trk = 476; + lock_count_thr = 8; + break; + case STB0899_QPSK_34: + gamma_acq = 53; + gamma_rho_acq = 16642; + gamma_trk = 19; + gamma_rho_trk = 646; + lock_count_thr = 8; + break; + case STB0899_QPSK_45: + gamma_acq = 53; + gamma_rho_acq = 17119; + gamma_trk = 22; + gamma_rho_trk = 880; + lock_count_thr = 8; + break; + case STB0899_QPSK_56: + gamma_acq = 55; + gamma_rho_acq = 19250; + gamma_trk = 23; + gamma_rho_trk = 989; + lock_count_thr = 8; + break; + case STB0899_QPSK_89: + gamma_acq = 60; + gamma_rho_acq = 24240; + gamma_trk = 24; + gamma_rho_trk = 1176; + lock_count_thr = 8; + break; + case STB0899_QPSK_910: + gamma_acq = 66; + gamma_rho_acq = 29634; + gamma_trk = 24; + gamma_rho_trk = 1176; + lock_count_thr = 8; + break; + default: + gamma_acq = 66; + gamma_rho_acq = 29634; + gamma_trk = 24; + gamma_rho_trk = 1176; + lock_count_thr = 8; + break; + } + + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, csm1, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + csm2 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL2); + csm3 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL3); + csm4 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL4); + + STB0899_SETFIELD_VAL(CSM_DVT_TABLE, csm1, dvt_tbl); + STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, two_pass); + STB0899_SETFIELD_VAL(CSM_AGC_GAIN, csm1, agc_gain); + STB0899_SETFIELD_VAL(CSM_AGC_SHIFT, csm1, agc_shift); + STB0899_SETFIELD_VAL(FE_LOOP_SHIFT, csm1, loop_shift); + STB0899_SETFIELD_VAL(CSM_GAMMA_ACQ, csm2, gamma_acq); + STB0899_SETFIELD_VAL(CSM_GAMMA_RHOACQ, csm2, gamma_rho_acq); + STB0899_SETFIELD_VAL(CSM_GAMMA_TRACK, csm3, gamma_trk); + STB0899_SETFIELD_VAL(CSM_GAMMA_RHOTRACK, csm3, gamma_rho_trk); + STB0899_SETFIELD_VAL(CSM_LOCKCOUNT_THRESH, csm4, lock_count_thr); + STB0899_SETFIELD_VAL(CSM_PHASEDIFF_THRESH, csm4, phs_diff_thr); + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL2, STB0899_OFF0_CSM_CNTRL2, csm2); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL3, STB0899_OFF0_CSM_CNTRL3, csm3); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL4, STB0899_OFF0_CSM_CNTRL4, csm4); + } +} + +/* + * stb0899_dvbs2_get_srate + * get DVB-S2 Symbol Rate + */ +static u32 stb0899_dvbs2_get_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u32 bTrNomFreq, srate, decimRate, intval1, intval2, reg; + int div1, div2, rem1, rem2; + + div1 = config->btr_nco_bits / 2; + div2 = config->btr_nco_bits - div1 - 1; + + bTrNomFreq = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_NOM_FREQ); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DECIM_CNTRL); + decimRate = STB0899_GETFIELD(DECIM_RATE, reg); + decimRate = (1 << decimRate); + + intval1 = internal->master_clk / (1 << div1); + intval2 = bTrNomFreq / (1 << div2); + + rem1 = internal->master_clk % (1 << div1); + rem2 = bTrNomFreq % (1 << div2); + /* only for integer calculation */ + srate = (intval1 * intval2) + ((intval1 * rem2) / (1 << div2)) + ((intval2 * rem1) / (1 << div1)); + srate /= decimRate; /*symbrate = (btrnomfreq_register_val*MasterClock)/2^(27+decim_rate_field) */ + + return srate; +} + +/* + * stb0899_dvbs2_algo + * Search for signal, timing, carrier and data for a given + * frequency in a given range + */ +enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + enum stb0899_modcod modcod; + + s32 offsetfreq, searchTime, FecLockTime, pilots, iqSpectrum; + int i = 0; + u32 reg, csm1; + + if (internal->srate <= 2000000) { + searchTime = 5000; /* 5000 ms max time to lock UWP and CSM, SYMB <= 2Mbs */ + FecLockTime = 350; /* 350 ms max time to lock FEC, SYMB <= 2Mbs */ + } else if (internal->srate <= 5000000) { + searchTime = 2500; /* 2500 ms max time to lock UWP and CSM, 2Mbs < SYMB <= 5Mbs */ + FecLockTime = 170; /* 170 ms max time to lock FEC, 2Mbs< SYMB <= 5Mbs */ + } else if (internal->srate <= 10000000) { + searchTime = 1500; /* 1500 ms max time to lock UWP and CSM, 5Mbs srate <= 15000000) { + searchTime = 500; /* 500 ms max time to lock UWP and CSM, 10Mbs srate <= 20000000) { + searchTime = 300; /* 300 ms max time to lock UWP and CSM, 15Mbs < SYMB <= 20Mbs */ + FecLockTime = 30; /* 50 ms max time to lock FEC, 15Mbs< SYMB <= 20Mbs */ + } else if (internal->srate <= 25000000) { + searchTime = 250; /* 250 ms max time to lock UWP and CSM, 20 Mbs < SYMB <= 25Mbs */ + FecLockTime = 25; /* 25 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs */ + } else { + searchTime = 150; /* 150 ms max time to lock UWP and CSM, SYMB > 25Mbs */ + FecLockTime = 20; /* 20 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs */ + } + + /* Maintain Stream Merger in reset during acquisition */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + /* Move tuner to frequency */ + if (state->config->tuner_set_frequency) + state->config->tuner_set_frequency(&state->frontend, internal->freq); + if (state->config->tuner_get_frequency) + state->config->tuner_get_frequency(&state->frontend, &internal->freq); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + + /* Set IF AGC to acquisition */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); + STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg, 4); + STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 32); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2); + STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg); + + /* Initialisation */ + stb0899_dvbs2_init_calc(state); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); + switch (internal->inversion) { + case IQ_SWAP_OFF: + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 0); + break; + case IQ_SWAP_ON: + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1); + break; + case IQ_SWAP_AUTO: /* use last successful search first */ + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1); + break; + } + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg); + stb0899_dvbs2_reacquire(state); + + /* Wait for demod lock (UWP and CSM) */ + internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime); + + if (internal->status == DVBS2_DEMOD_LOCK) { + dprintk(state->verbose, FE_DEBUG, 1, "------------> DVB-S2 DEMOD LOCK !"); + i = 0; + /* Demod Locked, check FEC status */ + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + + /*If false lock (UWP and CSM Locked but no FEC) try 3 time max*/ + while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { + /* Read the frequency offset*/ + offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); + + /* Set the Nominal frequency to the found frequency offset for the next reacquire*/ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); + STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); + stb0899_dvbs2_reacquire(state); + internal->status = stb0899_dvbs2_get_fec_status(state, searchTime); + i++; + } + } + + if (internal->status != DVBS2_FEC_LOCK) { + if (internal->inversion == IQ_SWAP_AUTO) { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); + iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg); + /* IQ Spectrum Inversion */ + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg); + /* start acquistion process */ + stb0899_dvbs2_reacquire(state); + + /* Wait for demod lock (UWP and CSM) */ + internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime); + if (internal->status == DVBS2_DEMOD_LOCK) { + i = 0; + /* Demod Locked, check FEC */ + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + /*try thrice for false locks, (UWP and CSM Locked but no FEC) */ + while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { + /* Read the frequency offset*/ + offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); + + /* Set the Nominal frequency to the found frequency offset for the next reacquire*/ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); + STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); + + stb0899_dvbs2_reacquire(state); + internal->status = stb0899_dvbs2_get_fec_status(state, searchTime); + i++; + } + } +/* + if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED) + pParams->IQLocked = !iqSpectrum; +*/ + } + } + if (internal->status == DVBS2_FEC_LOCK) { + dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !"); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2; + pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01; + + if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) && + (INRANGE(STB0899_QPSK_23, modcod, STB0899_QPSK_910)) && + (pilots == 1)) { + + stb0899_dvbs2_init_csm(state, pilots, modcod); + /* Wait for UWP,CSM and data LOCK 20ms max */ + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + + i = 0; + while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + i++; + } + } + + if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) && + (INRANGE(STB0899_QPSK_12, modcod, STB0899_QPSK_35)) && + (pilots == 1)) { + + /* Equalizer Disable update */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); + STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); + } + + /* slow down the Equalizer once locked */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); + STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0x02); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); + + /* Store signal parameters */ + offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); + + offsetfreq = offsetfreq / ((1 << 30) / 1000); + offsetfreq *= (internal->master_clk / 1000000); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); + if (STB0899_GETFIELD(SPECTRUM_INVERT, reg)) + offsetfreq *= -1; + + internal->freq = internal->freq - offsetfreq; + internal->srate = stb0899_dvbs2_get_srate(state); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + internal->modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2; + internal->pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01; + internal->frame_length = (STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 1) & 0x01; + + /* Set IF AGC to tracking */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); + STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg, 3); + + /* if QPSK 1/2,QPSK 3/5 or QPSK 2/3 set IF AGC reference to 16 otherwise 32*/ + if (INRANGE(STB0899_QPSK_12, internal->modcod, STB0899_QPSK_23)) + STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 16); + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2); + STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 7); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg); + } + + /* Release Stream Merger Reset */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + return internal->status; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_cfg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_cfg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_cfg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_cfg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,287 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STB0899_CFG_H +#define __STB0899_CFG_H + +static const struct stb0899_s2_reg stb0899_s2_init_2[] = { + + { STB0899_OFF0_DMD_STATUS , STB0899_BASE_DMD_STATUS , 0x00000103 }, /* DMDSTATUS */ + { STB0899_OFF0_CRL_FREQ , STB0899_BASE_CRL_FREQ , 0x3ed1da56 }, /* CRLFREQ */ + { STB0899_OFF0_BTR_FREQ , STB0899_BASE_BTR_FREQ , 0x00004000 }, /* BTRFREQ */ + { STB0899_OFF0_IF_AGC_GAIN , STB0899_BASE_IF_AGC_GAIN , 0x00002ade }, /* IFAGCGAIN */ + { STB0899_OFF0_BB_AGC_GAIN , STB0899_BASE_BB_AGC_GAIN , 0x000001bc }, /* BBAGCGAIN */ + { STB0899_OFF0_DC_OFFSET , STB0899_BASE_DC_OFFSET , 0x00000200 }, /* DCOFFSET */ + { STB0899_OFF0_DMD_CNTRL , STB0899_BASE_DMD_CNTRL , 0x0000000f }, /* DMDCNTRL */ + + { STB0899_OFF0_IF_AGC_CNTRL , STB0899_BASE_IF_AGC_CNTRL , 0x03fb4a20 }, /* IFAGCCNTRL */ + { STB0899_OFF0_BB_AGC_CNTRL , STB0899_BASE_BB_AGC_CNTRL , 0x00200c97 }, /* BBAGCCNTRL */ + + { STB0899_OFF0_CRL_CNTRL , STB0899_BASE_CRL_CNTRL , 0x00000016 }, /* CRLCNTRL */ + { STB0899_OFF0_CRL_PHS_INIT , STB0899_BASE_CRL_PHS_INIT , 0x00000000 }, /* CRLPHSINIT */ + { STB0899_OFF0_CRL_FREQ_INIT , STB0899_BASE_CRL_FREQ_INIT , 0x00000000 }, /* CRLFREQINIT */ + { STB0899_OFF0_CRL_LOOP_GAIN , STB0899_BASE_CRL_LOOP_GAIN , 0x00000000 }, /* CRLLOOPGAIN */ + { STB0899_OFF0_CRL_NOM_FREQ , STB0899_BASE_CRL_NOM_FREQ , 0x3ed097b6 }, /* CRLNOMFREQ */ + { STB0899_OFF0_CRL_SWP_RATE , STB0899_BASE_CRL_SWP_RATE , 0x00000000 }, /* CRLSWPRATE */ + { STB0899_OFF0_CRL_MAX_SWP , STB0899_BASE_CRL_MAX_SWP , 0x00000000 }, /* CRLMAXSWP */ + { STB0899_OFF0_CRL_LK_CNTRL , STB0899_BASE_CRL_LK_CNTRL , 0x0f6cdc01 }, /* CRLLKCNTRL */ + { STB0899_OFF0_DECIM_CNTRL , STB0899_BASE_DECIM_CNTRL , 0x00000000 }, /* DECIMCNTRL */ + { STB0899_OFF0_BTR_CNTRL , STB0899_BASE_BTR_CNTRL , 0x00003993 }, /* BTRCNTRL */ + { STB0899_OFF0_BTR_LOOP_GAIN , STB0899_BASE_BTR_LOOP_GAIN , 0x000d3c6f }, /* BTRLOOPGAIN */ + { STB0899_OFF0_BTR_PHS_INIT , STB0899_BASE_BTR_PHS_INIT , 0x00000000 }, /* BTRPHSINIT */ + { STB0899_OFF0_BTR_FREQ_INIT , STB0899_BASE_BTR_FREQ_INIT , 0x00000000 }, /* BTRFREQINIT */ + { STB0899_OFF0_BTR_NOM_FREQ , STB0899_BASE_BTR_NOM_FREQ , 0x0238e38e }, /* BTRNOMFREQ */ + { STB0899_OFF0_BTR_LK_CNTRL , STB0899_BASE_BTR_LK_CNTRL , 0x00000000 }, /* BTRLKCNTRL */ + { STB0899_OFF0_DECN_CNTRL , STB0899_BASE_DECN_CNTRL , 0x00000000 }, /* DECNCNTRL */ + { STB0899_OFF0_TP_CNTRL , STB0899_BASE_TP_CNTRL , 0x00000000 }, /* TPCNTRL */ + { STB0899_OFF0_TP_BUF_STATUS , STB0899_BASE_TP_BUF_STATUS , 0x00000000 }, /* TPBUFSTATUS */ + { STB0899_OFF0_DC_ESTIM , STB0899_BASE_DC_ESTIM , 0x00000000 }, /* DCESTIM */ + { STB0899_OFF0_FLL_CNTRL , STB0899_BASE_FLL_CNTRL , 0x00000000 }, /* FLLCNTRL */ + { STB0899_OFF0_FLL_FREQ_WD , STB0899_BASE_FLL_FREQ_WD , 0x40070000 }, /* FLLFREQWD */ + { STB0899_OFF0_ANTI_ALIAS_SEL , STB0899_BASE_ANTI_ALIAS_SEL , 0x00000001 }, /* ANTIALIASSEL */ + { STB0899_OFF0_RRC_ALPHA , STB0899_BASE_RRC_ALPHA , 0x00000002 }, /* RRCALPHA */ + { STB0899_OFF0_DC_ADAPT_LSHFT , STB0899_BASE_DC_ADAPT_LSHFT , 0x00000000 }, /* DCADAPTISHFT */ + { STB0899_OFF0_IMB_OFFSET , STB0899_BASE_IMB_OFFSET , 0x0000fe01 }, /* IMBOFFSET */ + { STB0899_OFF0_IMB_ESTIMATE , STB0899_BASE_IMB_ESTIMATE , 0x00000000 }, /* IMBESTIMATE */ + { STB0899_OFF0_IMB_CNTRL , STB0899_BASE_IMB_CNTRL , 0x00000001 }, /* IMBCNTRL */ + { STB0899_OFF0_IF_AGC_CNTRL2 , STB0899_BASE_IF_AGC_CNTRL2 , 0x00005007 }, /* IFAGCCNTRL2 */ + { STB0899_OFF0_DMD_CNTRL2 , STB0899_BASE_DMD_CNTRL2 , 0x00000002 }, /* DMDCNTRL2 */ + { STB0899_OFF0_TP_BUFFER , STB0899_BASE_TP_BUFFER , 0x00000000 }, /* TPBUFFER */ + { STB0899_OFF0_TP_BUFFER1 , STB0899_BASE_TP_BUFFER1 , 0x00000000 }, /* TPBUFFER1 */ + { STB0899_OFF0_TP_BUFFER2 , STB0899_BASE_TP_BUFFER2 , 0x00000000 }, /* TPBUFFER2 */ + { STB0899_OFF0_TP_BUFFER3 , STB0899_BASE_TP_BUFFER3 , 0x00000000 }, /* TPBUFFER3 */ + { STB0899_OFF0_TP_BUFFER4 , STB0899_BASE_TP_BUFFER4 , 0x00000000 }, /* TPBUFFER4 */ + { STB0899_OFF0_TP_BUFFER5 , STB0899_BASE_TP_BUFFER5 , 0x00000000 }, /* TPBUFFER5 */ + { STB0899_OFF0_TP_BUFFER6 , STB0899_BASE_TP_BUFFER6 , 0x00000000 }, /* TPBUFFER6 */ + { STB0899_OFF0_TP_BUFFER7 , STB0899_BASE_TP_BUFFER7 , 0x00000000 }, /* TPBUFFER7 */ + { STB0899_OFF0_TP_BUFFER8 , STB0899_BASE_TP_BUFFER8 , 0x00000000 }, /* TPBUFFER8 */ + { STB0899_OFF0_TP_BUFFER9 , STB0899_BASE_TP_BUFFER9 , 0x00000000 }, /* TPBUFFER9 */ + { STB0899_OFF0_TP_BUFFER10 , STB0899_BASE_TP_BUFFER10 , 0x00000000 }, /* TPBUFFER10 */ + { STB0899_OFF0_TP_BUFFER11 , STB0899_BASE_TP_BUFFER11 , 0x00000000 }, /* TPBUFFER11 */ + { STB0899_OFF0_TP_BUFFER12 , STB0899_BASE_TP_BUFFER12 , 0x00000000 }, /* TPBUFFER12 */ + { STB0899_OFF0_TP_BUFFER13 , STB0899_BASE_TP_BUFFER13 , 0x00000000 }, /* TPBUFFER13 */ + { STB0899_OFF0_TP_BUFFER14 , STB0899_BASE_TP_BUFFER14 , 0x00000000 }, /* TPBUFFER14 */ + { STB0899_OFF0_TP_BUFFER15 , STB0899_BASE_TP_BUFFER15 , 0x00000000 }, /* TPBUFFER15 */ + { STB0899_OFF0_TP_BUFFER16 , STB0899_BASE_TP_BUFFER16 , 0x0000ff00 }, /* TPBUFFER16 */ + { STB0899_OFF0_TP_BUFFER17 , STB0899_BASE_TP_BUFFER17 , 0x00000100 }, /* TPBUFFER17 */ + { STB0899_OFF0_TP_BUFFER18 , STB0899_BASE_TP_BUFFER18 , 0x0000fe01 }, /* TPBUFFER18 */ + { STB0899_OFF0_TP_BUFFER19 , STB0899_BASE_TP_BUFFER19 , 0x000004fe }, /* TPBUFFER19 */ + { STB0899_OFF0_TP_BUFFER20 , STB0899_BASE_TP_BUFFER20 , 0x0000cfe7 }, /* TPBUFFER20 */ + { STB0899_OFF0_TP_BUFFER21 , STB0899_BASE_TP_BUFFER21 , 0x0000bec6 }, /* TPBUFFER21 */ + { STB0899_OFF0_TP_BUFFER22 , STB0899_BASE_TP_BUFFER22 , 0x0000c2bf }, /* TPBUFFER22 */ + { STB0899_OFF0_TP_BUFFER23 , STB0899_BASE_TP_BUFFER23 , 0x0000c1c1 }, /* TPBUFFER23 */ + { STB0899_OFF0_TP_BUFFER24 , STB0899_BASE_TP_BUFFER24 , 0x0000c1c1 }, /* TPBUFFER24 */ + { STB0899_OFF0_TP_BUFFER25 , STB0899_BASE_TP_BUFFER25 , 0x0000c1c1 }, /* TPBUFFER25 */ + { STB0899_OFF0_TP_BUFFER26 , STB0899_BASE_TP_BUFFER26 , 0x0000c1c1 }, /* TPBUFFER26 */ + { STB0899_OFF0_TP_BUFFER27 , STB0899_BASE_TP_BUFFER27 , 0x0000c1c0 }, /* TPBUFFER27 */ + { STB0899_OFF0_TP_BUFFER28 , STB0899_BASE_TP_BUFFER28 , 0x0000c0c0 }, /* TPBUFFER28 */ + { STB0899_OFF0_TP_BUFFER29 , STB0899_BASE_TP_BUFFER29 , 0x0000c1c1 }, /* TPBUFFER29 */ + { STB0899_OFF0_TP_BUFFER30 , STB0899_BASE_TP_BUFFER30 , 0x0000c1c1 }, /* TPBUFFER30 */ + { STB0899_OFF0_TP_BUFFER31 , STB0899_BASE_TP_BUFFER31 , 0x0000c0c1 }, /* TPBUFFER31 */ + { STB0899_OFF0_TP_BUFFER32 , STB0899_BASE_TP_BUFFER32 , 0x0000c0c1 }, /* TPBUFFER32 */ + { STB0899_OFF0_TP_BUFFER33 , STB0899_BASE_TP_BUFFER33 , 0x0000c1c1 }, /* TPBUFFER33 */ + { STB0899_OFF0_TP_BUFFER34 , STB0899_BASE_TP_BUFFER34 , 0x0000c1c1 }, /* TPBUFFER34 */ + { STB0899_OFF0_TP_BUFFER35 , STB0899_BASE_TP_BUFFER35 , 0x0000c0c1 }, /* TPBUFFER35 */ + { STB0899_OFF0_TP_BUFFER36 , STB0899_BASE_TP_BUFFER36 , 0x0000c1c1 }, /* TPBUFFER36 */ + { STB0899_OFF0_TP_BUFFER37 , STB0899_BASE_TP_BUFFER37 , 0x0000c0c1 }, /* TPBUFFER37 */ + { STB0899_OFF0_TP_BUFFER38 , STB0899_BASE_TP_BUFFER38 , 0x0000c1c1 }, /* TPBUFFER38 */ + { STB0899_OFF0_TP_BUFFER39 , STB0899_BASE_TP_BUFFER39 , 0x0000c0c0 }, /* TPBUFFER39 */ + { STB0899_OFF0_TP_BUFFER40 , STB0899_BASE_TP_BUFFER40 , 0x0000c1c0 }, /* TPBUFFER40 */ + { STB0899_OFF0_TP_BUFFER41 , STB0899_BASE_TP_BUFFER41 , 0x0000c1c1 }, /* TPBUFFER41 */ + { STB0899_OFF0_TP_BUFFER42 , STB0899_BASE_TP_BUFFER42 , 0x0000c0c0 }, /* TPBUFFER42 */ + { STB0899_OFF0_TP_BUFFER43 , STB0899_BASE_TP_BUFFER43 , 0x0000c1c0 }, /* TPBUFFER43 */ + { STB0899_OFF0_TP_BUFFER44 , STB0899_BASE_TP_BUFFER44 , 0x0000c0c1 }, /* TPBUFFER44 */ + { STB0899_OFF0_TP_BUFFER45 , STB0899_BASE_TP_BUFFER45 , 0x0000c1be }, /* TPBUFFER45 */ + { STB0899_OFF0_TP_BUFFER46 , STB0899_BASE_TP_BUFFER46 , 0x0000c1c9 }, /* TPBUFFER46 */ + { STB0899_OFF0_TP_BUFFER47 , STB0899_BASE_TP_BUFFER47 , 0x0000c0da }, /* TPBUFFER47 */ + { STB0899_OFF0_TP_BUFFER48 , STB0899_BASE_TP_BUFFER48 , 0x0000c0ba }, /* TPBUFFER48 */ + { STB0899_OFF0_TP_BUFFER49 , STB0899_BASE_TP_BUFFER49 , 0x0000c1c4 }, /* TPBUFFER49 */ + { STB0899_OFF0_TP_BUFFER50 , STB0899_BASE_TP_BUFFER50 , 0x0000c1bf }, /* TPBUFFER50 */ + { STB0899_OFF0_TP_BUFFER51 , STB0899_BASE_TP_BUFFER51 , 0x0000c0c1 }, /* TPBUFFER51 */ + { STB0899_OFF0_TP_BUFFER52 , STB0899_BASE_TP_BUFFER52 , 0x0000c1c0 }, /* TPBUFFER52 */ + { STB0899_OFF0_TP_BUFFER53 , STB0899_BASE_TP_BUFFER53 , 0x0000c0c1 }, /* TPBUFFER53 */ + { STB0899_OFF0_TP_BUFFER54 , STB0899_BASE_TP_BUFFER54 , 0x0000c1c1 }, /* TPBUFFER54 */ + { STB0899_OFF0_TP_BUFFER55 , STB0899_BASE_TP_BUFFER55 , 0x0000c1c1 }, /* TPBUFFER55 */ + { STB0899_OFF0_TP_BUFFER56 , STB0899_BASE_TP_BUFFER56 , 0x0000c1c1 }, /* TPBUFFER56 */ + { STB0899_OFF0_TP_BUFFER57 , STB0899_BASE_TP_BUFFER57 , 0x0000c1c1 }, /* TPBUFFER57 */ + { STB0899_OFF0_TP_BUFFER58 , STB0899_BASE_TP_BUFFER58 , 0x0000c1c1 }, /* TPBUFFER58 */ + { STB0899_OFF0_TP_BUFFER59 , STB0899_BASE_TP_BUFFER59 , 0x0000c1c1 }, /* TPBUFFER59 */ + { STB0899_OFF0_TP_BUFFER60 , STB0899_BASE_TP_BUFFER60 , 0x0000c1c1 }, /* TPBUFFER60 */ + { STB0899_OFF0_TP_BUFFER61 , STB0899_BASE_TP_BUFFER61 , 0x0000c1c1 }, /* TPBUFFER61 */ + { STB0899_OFF0_TP_BUFFER62 , STB0899_BASE_TP_BUFFER62 , 0x0000c1c1 }, /* TPBUFFER62 */ + { STB0899_OFF0_TP_BUFFER63 , STB0899_BASE_TP_BUFFER63 , 0x0000c1c0 }, /* TPBUFFER63 */ + { STB0899_OFF0_RESET_CNTRL , STB0899_BASE_RESET_CNTRL , 0x00000001 }, /* RESETCNTRL */ + { STB0899_OFF0_ACM_ENABLE , STB0899_BASE_ACM_ENABLE , 0x00005654 }, /* ACMENABLE */ + { STB0899_OFF0_DESCR_CNTRL , STB0899_BASE_DESCR_CNTRL , 0x00000000 }, /* DESCRCNTRL */ + { STB0899_OFF0_CSM_CNTRL1 , STB0899_BASE_CSM_CNTRL1 , 0x00020019 }, /* CSMCNTRL1 */ + { STB0899_OFF0_CSM_CNTRL2 , STB0899_BASE_CSM_CNTRL2 , 0x004b3237 }, /* CSMCNTRL2 */ + { STB0899_OFF0_CSM_CNTRL3 , STB0899_BASE_CSM_CNTRL3 , 0x0003dd17 }, /* CSMCNTRL3 */ + { STB0899_OFF0_CSM_CNTRL4 , STB0899_BASE_CSM_CNTRL4 , 0x00008008 }, /* CSMCNTRL4 */ + { STB0899_OFF0_UWP_CNTRL1 , STB0899_BASE_UWP_CNTRL1 , 0x002a3106 }, /* UWPCNTRL1 */ + { STB0899_OFF0_UWP_CNTRL2 , STB0899_BASE_UWP_CNTRL2 , 0x0006140a }, /* UWPCNTRL2 */ + { STB0899_OFF0_UWP_STAT1 , STB0899_BASE_UWP_STAT1 , 0x00008000 }, /* UWPSTAT1 */ + { STB0899_OFF0_UWP_STAT2 , STB0899_BASE_UWP_STAT2 , 0x00000000 }, /* UWPSTAT2 */ + { STB0899_OFF0_DMD_STAT2 , STB0899_BASE_DMD_STAT2 , 0x00000000 }, /* DMDSTAT2 */ + { STB0899_OFF0_FREQ_ADJ_SCALE , STB0899_BASE_FREQ_ADJ_SCALE , 0x00000471 }, /* FREQADJSCALE */ + { STB0899_OFF0_UWP_CNTRL3 , STB0899_BASE_UWP_CNTRL3 , 0x017b0465 }, /* UWPCNTRL3 */ + { STB0899_OFF0_SYM_CLK_SEL , STB0899_BASE_SYM_CLK_SEL , 0x00000002 }, /* SYMCLKSEL */ + { STB0899_OFF0_SOF_SRCH_TO , STB0899_BASE_SOF_SRCH_TO , 0x00196464 }, /* SOFSRCHTO */ + { STB0899_OFF0_ACQ_CNTRL1 , STB0899_BASE_ACQ_CNTRL1 , 0x00000603 }, /* ACQCNTRL1 */ + { STB0899_OFF0_ACQ_CNTRL2 , STB0899_BASE_ACQ_CNTRL2 , 0x02046666 }, /* ACQCNTRL2 */ + { STB0899_OFF0_ACQ_CNTRL3 , STB0899_BASE_ACQ_CNTRL3 , 0x10046583 }, /* ACQCNTRL3 */ + { STB0899_OFF0_FE_SETTLE , STB0899_BASE_FE_SETTLE , 0x00010404 }, /* FESETTLE */ + { STB0899_OFF0_AC_DWELL , STB0899_BASE_AC_DWELL , 0x0002aa8a }, /* ACDWELL */ + { STB0899_OFF0_ACQUIRE_TRIG , STB0899_BASE_ACQUIRE_TRIG , 0x00000000 }, /* ACQUIRETRIG */ + { STB0899_OFF0_LOCK_LOST , STB0899_BASE_LOCK_LOST , 0x00000001 }, /* LOCKLOST */ + { STB0899_OFF0_ACQ_STAT1 , STB0899_BASE_ACQ_STAT1 , 0x00000500 }, /* ACQSTAT1 */ + { STB0899_OFF0_ACQ_TIMEOUT , STB0899_BASE_ACQ_TIMEOUT , 0x0028a0a0 }, /* ACQTIMEOUT */ + { STB0899_OFF0_ACQ_TIME , STB0899_BASE_ACQ_TIME , 0x00000000 }, /* ACQTIME */ + { STB0899_OFF0_FINAL_AGC_CNTRL , STB0899_BASE_FINAL_AGC_CNTRL , 0x00800c17 }, /* FINALAGCCNTRL*/ + { STB0899_OFF0_FINAL_AGC_GAIN , STB0899_BASE_FINAL_AGC_GAIN , 0x00000000 }, /* FINALAGCCGAIN*/ + { STB0899_OFF0_EQUALIZER_INIT , STB0899_BASE_EQUALIZER_INIT , 0x00000000 }, /* EQUILIZERINIT*/ + { STB0899_OFF0_EQ_CNTRL , STB0899_BASE_EQ_CNTRL , 0x00054802 }, /* EQCNTL */ + { STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF0 */ + { STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF1 */ + { STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF2 */ + { STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF3 */ + { STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF4 */ + { STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 }, /* EQIINITCOEFF5 */ + { STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF6 */ + { STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF7 */ + { STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF8 */ + { STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF9 */ + { STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF10*/ + { STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF0 */ + { STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF1 */ + { STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF2 */ + { STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF3 */ + { STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF4 */ + { STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF5 */ + { STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF6 */ + { STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF7 */ + { STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF8 */ + { STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF9 */ + { STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF10*/ + { STB0899_OFF0_EQ_I_OUT_COEFF_0 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT0 */ + { STB0899_OFF1_EQ_I_OUT_COEFF_1 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT1 */ + { STB0899_OFF2_EQ_I_OUT_COEFF_2 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT2 */ + { STB0899_OFF3_EQ_I_OUT_COEFF_3 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT3 */ + { STB0899_OFF4_EQ_I_OUT_COEFF_4 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT4 */ + { STB0899_OFF5_EQ_I_OUT_COEFF_5 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT5 */ + { STB0899_OFF6_EQ_I_OUT_COEFF_6 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT6 */ + { STB0899_OFF7_EQ_I_OUT_COEFF_7 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT7 */ + { STB0899_OFF8_EQ_I_OUT_COEFF_8 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT8 */ + { STB0899_OFF9_EQ_I_OUT_COEFF_9 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT9 */ + { STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT10*/ + { STB0899_OFF0_EQ_Q_OUT_COEFF_0 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT0 */ + { STB0899_OFF1_EQ_Q_OUT_COEFF_1 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT1 */ + { STB0899_OFF2_EQ_Q_OUT_COEFF_2 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT2 */ + { STB0899_OFF3_EQ_Q_OUT_COEFF_3 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT3 */ + { STB0899_OFF4_EQ_Q_OUT_COEFF_4 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT4 */ + { STB0899_OFF5_EQ_Q_OUT_COEFF_5 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT5 */ + { STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT6 */ + { STB0899_OFF7_EQ_Q_OUT_COEFF_7 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT7 */ + { STB0899_OFF8_EQ_Q_OUT_COEFF_8 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT8 */ + { STB0899_OFF9_EQ_Q_OUT_COEFF_9 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT9 */ + { STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT10*/ + { 0xffff , 0xffffffff , 0xffffffff }, +}; +static const struct stb0899_s2_reg stb0899_s2_init_4[] = { + { STB0899_OFF0_BLOCK_LNGTH , STB0899_BASE_BLOCK_LNGTH , 0x00000008 }, /* BLOCKLNGTH */ + { STB0899_OFF0_ROW_STR , STB0899_BASE_ROW_STR , 0x000000b4 }, /* ROWSTR */ + { STB0899_OFF0_BN_END_ADDR , STB0899_BASE_BN_END_ADDR , 0x000004b5 }, /* BNANDADDR */ + { STB0899_OFF0_CN_END_ADDR , STB0899_BASE_CN_END_ADDR , 0x00000b4b }, /* CNANDADDR */ + { STB0899_OFF0_INFO_LENGTH , STB0899_BASE_INFO_LENGTH , 0x00000078 }, /* INFOLENGTH */ + { STB0899_OFF0_BOT_ADDR , STB0899_BASE_BOT_ADDR , 0x000001e0 }, /* BOT_ADDR */ + { STB0899_OFF0_BCH_BLK_LN , STB0899_BASE_BCH_BLK_LN , 0x0000a8c0 }, /* BCHBLKLN */ + { STB0899_OFF0_BCH_T , STB0899_BASE_BCH_T , 0x0000000c }, /* BCHT */ + { STB0899_OFF0_CNFG_MODE , STB0899_BASE_CNFG_MODE , 0x00000001 }, /* CNFGMODE */ + { STB0899_OFF0_LDPC_STAT , STB0899_BASE_LDPC_STAT , 0x0000000d }, /* LDPCSTAT */ + { STB0899_OFF0_ITER_SCALE , STB0899_BASE_ITER_SCALE , 0x00000040 }, /* ITERSCALE */ + { STB0899_OFF0_INPUT_MODE , STB0899_BASE_INPUT_MODE , 0x00000000 }, /* INPUTMODE */ + { STB0899_OFF0_LDPCDECRST , STB0899_BASE_LDPCDECRST , 0x00000000 }, /* LDPCDECRST */ + { STB0899_OFF0_CLK_PER_BYTE_RW , STB0899_BASE_CLK_PER_BYTE_RW , 0x00000008 }, /* CLKPERBYTE */ + { STB0899_OFF0_BCH_ERRORS , STB0899_BASE_BCH_ERRORS , 0x00000000 }, /* BCHERRORS */ + { STB0899_OFF0_LDPC_ERRORS , STB0899_BASE_LDPC_ERRORS , 0x00000000 }, /* LDPCERRORS */ + { STB0899_OFF0_BCH_MODE , STB0899_BASE_BCH_MODE , 0x00000000 }, /* BCHMODE */ + { STB0899_OFF0_ERR_ACC_PER , STB0899_BASE_ERR_ACC_PER , 0x00000008 }, /* ERRACCPER */ + { STB0899_OFF0_BCH_ERR_ACC , STB0899_BASE_BCH_ERR_ACC , 0x00000000 }, /* BCHERRACC */ + { STB0899_OFF0_FEC_TP_SEL , STB0899_BASE_FEC_TP_SEL , 0x00000000 }, /* FECTPSEL */ + { 0xffff , 0xffffffff , 0xffffffff }, +}; + +static const struct stb0899_s1_reg stb0899_s1_init_5[] = { + { STB0899_TSTCK , 0x00 }, + { STB0899_TSTRES , 0x00 }, + { STB0899_TSTOUT , 0x00 }, + { STB0899_TSTIN , 0x00 }, + { STB0899_TSTSYS , 0x00 }, + { STB0899_TSTCHIP , 0x00 }, + { STB0899_TSTFREE , 0x00 }, + { STB0899_TSTI2C , 0x00 }, + { STB0899_BITSPEEDM , 0x00 }, + { STB0899_BITSPEEDL , 0x00 }, + { STB0899_TBUSBIT , 0x00 }, + { STB0899_TSTDIS , 0x00 }, + { STB0899_TSTDISRX , 0x00 }, + { STB0899_TSTJETON , 0x00 }, + { STB0899_TSTDCADJ , 0x00 }, + { STB0899_TSTAGC1 , 0x00 }, + { STB0899_TSTAGC1N , 0x00 }, + { STB0899_TSTPOLYPH , 0x00 }, + { STB0899_TSTR , 0x00 }, + { STB0899_TSTAGC2 , 0x00 }, + { STB0899_TSTCTL1 , 0x00 }, + { STB0899_TSTCTL2 , 0x00 }, + { STB0899_TSTCTL3 , 0x00 }, + { STB0899_TSTDEMAP , 0x00 }, + { STB0899_TSTDEMAP2 , 0x00 }, + { STB0899_TSTDEMMON , 0x00 }, + { STB0899_TSTRATE , 0x00 }, + { STB0899_TSTSELOUT , 0x00 }, + { STB0899_TSYNC , 0x00 }, + { STB0899_TSTERR , 0x00 }, + { STB0899_TSTRAM1 , 0x00 }, + { STB0899_TSTVSELOUT , 0x00 }, + { STB0899_TSTFORCEIN , 0x00 }, + { STB0899_TSTRS1 , 0x00 }, + { STB0899_TSTRS2 , 0x00 }, + { STB0899_TSTRS3 , 0x00 }, + { STB0899_GHOSTREG , 0x81 }, + { 0xffff , 0xff }, +}; + +#define STB0899_DVBS2_ESNO_AVE 3 +#define STB0899_DVBS2_ESNO_QUANT 32 +#define STB0899_DVBS2_AVFRAMES_COARSE 10 +#define STB0899_DVBS2_AVFRAMES_FINE 20 +#define STB0899_DVBS2_MISS_THRESHOLD 6 +#define STB0899_DVBS2_UWP_THRESHOLD_ACQ 1125 +#define STB0899_DVBS2_UWP_THRESHOLD_TRACK 758 +#define STB0899_DVBS2_UWP_THRESHOLD_SOF 1350 +#define STB0899_DVBS2_SOF_SEARCH_TIMEOUT 1664100 + +#define STB0899_DVBS2_BTR_NCO_BITS 28 +#define STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET 15 +#define STB0899_DVBS2_CRL_NCO_BITS 30 +#define STB0899_DVBS2_LDPC_MAX_ITER 70 + +#endif //__STB0899_CFG_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_drv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_drv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_drv.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_drv.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1686 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include + +#include +#include "dvb_frontend.h" + +#include "stb0899_drv.h" +#include "stb0899_priv.h" +#include "stb0899_reg.h" + +static unsigned int verbose = 0;//1; +module_param(verbose, int, 0644); + +/* C/N in dB/10, NIRM/NIRL */ +static const struct stb0899_tab stb0899_cn_tab[] = { + { 200, 2600 }, + { 190, 2700 }, + { 180, 2860 }, + { 170, 3020 }, + { 160, 3210 }, + { 150, 3440 }, + { 140, 3710 }, + { 130, 4010 }, + { 120, 4360 }, + { 110, 4740 }, + { 100, 5190 }, + { 90, 5670 }, + { 80, 6200 }, + { 70, 6770 }, + { 60, 7360 }, + { 50, 7970 }, + { 40, 8250 }, + { 30, 9000 }, + { 20, 9450 }, + { 15, 9600 }, +}; + +/* DVB-S AGCIQ_VALUE vs. signal level in dBm/10. + * As measured, connected to a modulator. + * -8.0 to -50.0 dBm directly connected, + * -52.0 to -74.8 with extra attenuation. + * Cut-off to AGCIQ_VALUE = 0x80 below -74.8dBm. + * Crude linear extrapolation below -84.8dBm and above -8.0dBm. + */ +static const struct stb0899_tab stb0899_dvbsrf_tab[] = { + { -950, -128 }, + { -748, -94 }, + { -745, -92 }, + { -735, -90 }, + { -720, -87 }, + { -670, -77 }, + { -640, -70 }, + { -610, -62 }, + { -600, -60 }, + { -590, -56 }, + { -560, -41 }, + { -540, -25 }, + { -530, -17 }, + { -520, -11 }, + { -500, 1 }, + { -490, 6 }, + { -480, 10 }, + { -440, 22 }, + { -420, 27 }, + { -400, 31 }, + { -380, 34 }, + { -340, 40 }, + { -320, 43 }, + { -280, 48 }, + { -250, 52 }, + { -230, 55 }, + { -180, 61 }, + { -140, 66 }, + { -90, 73 }, + { -80, 74 }, + { 500, 127 } +}; + +/* DVB-S2 IF_AGC_GAIN vs. signal level in dBm/10. + * As measured, connected to a modulator. + * -8.0 to -50.1 dBm directly connected, + * -53.0 to -76.6 with extra attenuation. + * Cut-off to IF_AGC_GAIN = 0x3fff below -76.6dBm. + * Crude linear extrapolation below -76.6dBm and above -8.0dBm. + */ +static const struct stb0899_tab stb0899_dvbs2rf_tab[] = { + { 700, 0 }, + { -80, 3217 }, + { -150, 3893 }, + { -190, 4217 }, + { -240, 4621 }, + { -280, 4945 }, + { -320, 5273 }, + { -350, 5545 }, + { -370, 5741 }, + { -410, 6147 }, + { -450, 6671 }, + { -490, 7413 }, + { -501, 7665 }, + { -530, 8767 }, + { -560, 10219 }, + { -580, 10939 }, + { -590, 11518 }, + { -600, 11723 }, + { -650, 12659 }, + { -690, 13219 }, + { -730, 13645 }, + { -750, 13909 }, + { -766, 14153 }, + { -999, 16383 } +}; + +/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/ +static struct stb0899_tab stb0899_quant_tab[] = { + { 0, 0 }, + { 0, 100 }, + { 600, 200 }, + { 950, 299 }, + { 1200, 398 }, + { 1400, 501 }, + { 1560, 603 }, + { 1690, 700 }, + { 1810, 804 }, + { 1910, 902 }, + { 2000, 1000 }, + { 2080, 1096 }, + { 2160, 1202 }, + { 2230, 1303 }, + { 2350, 1496 }, + { 2410, 1603 }, + { 2460, 1698 }, + { 2510, 1799 }, + { 2600, 1995 }, + { 2650, 2113 }, + { 2690, 2213 }, + { 2720, 2291 }, + { 2760, 2399 }, + { 2800, 2512 }, + { 2860, 2692 }, + { 2930, 2917 }, + { 2960, 3020 }, + { 3010, 3199 }, + { 3040, 3311 }, + { 3060, 3388 }, + { 3120, 3631 }, + { 3190, 3936 }, + { 3400, 5012 }, + { 3610, 6383 }, + { 3800, 7943 }, + { 4210, 12735 }, + { 4500, 17783 }, + { 4690, 22131 }, + { 4810, 25410 } +}; + +/* DVB-S2 Es/N0 estimate in dB/100 vs read value */ +static struct stb0899_tab stb0899_est_tab[] = { + { 0, 0 }, + { 0, 1 }, + { 301, 2 }, + { 1204, 16 }, + { 1806, 64 }, + { 2408, 256 }, + { 2709, 512 }, + { 3010, 1023 }, + { 3311, 2046 }, + { 3612, 4093 }, + { 3823, 6653 }, + { 3913, 8185 }, + { 4010, 10233 }, + { 4107, 12794 }, + { 4214, 16368 }, + { 4266, 18450 }, + { 4311, 20464 }, + { 4353, 22542 }, + { 4391, 24604 }, + { 4425, 26607 }, + { 4457, 28642 }, + { 4487, 30690 }, + { 4515, 32734 }, + { 4612, 40926 }, + { 4692, 49204 }, + { 4816, 65464 }, + { 4913, 81846 }, + { 4993, 98401 }, + { 5060, 114815 }, + { 5118, 131220 }, + { 5200, 158489 }, + { 5300, 199526 }, + { 5400, 251189 }, + { 5500, 316228 }, + { 5600, 398107 }, + { 5720, 524807 }, + { 5721, 526017 }, +}; + +static int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg) +{ + int ret; + + u8 b0[] = { reg >> 8, reg & 0xff }; + u8 buf; + + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 2 + },{ + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = &buf, + .len = 1 + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + if (ret != -ERESTARTSYS) + dprintk(state->verbose, FE_ERROR, 1, + "Read error, Reg=[0x%02x], Status=%d", + reg, ret); + + return ret < 0 ? ret : -EREMOTEIO; + } + if (unlikely(*state->verbose >= FE_DEBUGREG)) + dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%02x], data=%02x", + reg, buf); + + return (unsigned int)buf; +} + +int stb0899_read_reg(struct stb0899_state *state, unsigned int reg) +{ + int result; + + result = _stb0899_read_reg(state, reg); + /* + * Bug ID 9: + * access to 0xf2xx/0xf6xx + * must be followed by read from 0xf2ff/0xf6ff. + */ + if ((reg != 0xf2ff) && (reg != 0xf6ff) && + (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) + _stb0899_read_reg(state, (reg | 0x00ff)); + + return result; +} + +u32 _stb0899_read_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset) +{ + int status; + u32 data; + u8 buf[7] = { 0 }; + u16 tmpaddr; + + u8 buf_0[] = { + GETBYTE(stb0899_i2cdev, BYTE1), /* 0xf3 S2 Base Address (MSB) */ + GETBYTE(stb0899_i2cdev, BYTE0), /* 0xfc S2 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE0), /* 0x00 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE1), /* 0x04 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE2), /* 0x00 Base Address (MSB) */ + GETBYTE(stb0899_base_addr, BYTE3), /* 0x00 Base Address (MSB) */ + }; + u8 buf_1[] = { + 0x00, /* 0xf3 Reg Offset */ + 0x00, /* 0x44 Reg Offset */ + }; + + struct i2c_msg msg_0 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_0, + .len = 6 + }; + + struct i2c_msg msg_1 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_1, + .len = 2 + }; + + struct i2c_msg msg_r = { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = buf, + .len = 4 + }; + + tmpaddr = stb0899_reg_offset & 0xff00; + if (!(stb0899_reg_offset & 0x8)) + tmpaddr = stb0899_reg_offset | 0x20; + + buf_1[0] = GETBYTE(tmpaddr, BYTE1); + buf_1[1] = GETBYTE(tmpaddr, BYTE0); + + status = i2c_transfer(state->i2c, &msg_0, 1); + if (status < 1) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR(1), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); + + goto err; + } + + /* Dummy */ + status = i2c_transfer(state->i2c, &msg_1, 1); + if (status < 1) + goto err; + + status = i2c_transfer(state->i2c, &msg_r, 1); + if (status < 1) + goto err; + + buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1); + buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0); + + /* Actual */ + status = i2c_transfer(state->i2c, &msg_1, 1); + if (status < 1) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR(2), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); + goto err; + } + + status = i2c_transfer(state->i2c, &msg_r, 1); + if (status < 1) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR(3), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); + return status < 0 ? status : -EREMOTEIO; + } + + data = MAKEWORD32(buf[3], buf[2], buf[1], buf[0]); + if (unlikely(*state->verbose >= FE_DEBUGREG)) + printk(KERN_DEBUG "%s Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, data); + + return data; + +err: + return status < 0 ? status : -EREMOTEIO; +} + +int stb0899_write_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset, + u32 stb0899_data) +{ + int status; + + /* Base Address Setup */ + u8 buf_0[] = { + GETBYTE(stb0899_i2cdev, BYTE1), /* 0xf3 S2 Base Address (MSB) */ + GETBYTE(stb0899_i2cdev, BYTE0), /* 0xfc S2 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE0), /* 0x00 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE1), /* 0x04 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE2), /* 0x00 Base Address (MSB) */ + GETBYTE(stb0899_base_addr, BYTE3), /* 0x00 Base Address (MSB) */ + }; + u8 buf_1[] = { + 0x00, /* 0xf3 Reg Offset */ + 0x00, /* 0x44 Reg Offset */ + 0x00, /* data */ + 0x00, /* data */ + 0x00, /* data */ + 0x00, /* data */ + }; + + struct i2c_msg msg_0 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_0, + .len = 6 + }; + + struct i2c_msg msg_1 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_1, + .len = 6 + }; + + buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1); + buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0); + buf_1[2] = GETBYTE(stb0899_data, BYTE0); + buf_1[3] = GETBYTE(stb0899_data, BYTE1); + buf_1[4] = GETBYTE(stb0899_data, BYTE2); + buf_1[5] = GETBYTE(stb0899_data, BYTE3); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) + printk(KERN_DEBUG "%s Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data); + + status = i2c_transfer(state->i2c, &msg_0, 1); + if (unlikely(status < 1)) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR (1), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status); + goto err; + } + status = i2c_transfer(state->i2c, &msg_1, 1); + if (unlikely(status < 1)) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR (2), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status); + + return status < 0 ? status : -EREMOTEIO; + } + + return 0; + +err: + return status < 0 ? status : -EREMOTEIO; +} + +int stb0899_read_regs(struct stb0899_state *state, unsigned int reg, u8 *buf, u32 count) +{ + int status; + + u8 b0[] = { reg >> 8, reg & 0xff }; + + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 2 + },{ + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = buf, + .len = count + } + }; + + status = i2c_transfer(state->i2c, msg, 2); + if (status != 2) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s Read error, Reg=[0x%04x], Count=%u, Status=%d\n", + __func__, reg, count, status); + goto err; + } + /* + * Bug ID 9: + * access to 0xf2xx/0xf6xx + * must be followed by read from 0xf2ff/0xf6ff. + */ + if ((reg != 0xf2ff) && (reg != 0xf6ff) && + (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) + _stb0899_read_reg(state, (reg | 0x00ff)); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) { + int i; + + printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); + for (i = 0; i < count; i++) { + printk(" %02x", buf[i]); + } + printk("\n"); + } + + return 0; +err: + return status < 0 ? status : -EREMOTEIO; +} + +int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, u32 count) +{ + int ret; + u8 buf[2 + count]; + struct i2c_msg i2c_msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + count + }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + memcpy(&buf[2], data, count); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) { + int i; + + printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); + for (i = 0; i < count; i++) + printk(" %02x", data[i]); + printk("\n"); + } + ret = i2c_transfer(state->i2c, &i2c_msg, 1); + + /* + * Bug ID 9: + * access to 0xf2xx/0xf6xx + * must be followed by read from 0xf2ff/0xf6ff. + */ + if ((((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) + stb0899_read_reg(state, (reg | 0x00ff)); + + if (ret != 1) { + if (ret != -ERESTARTSYS) + dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d", + reg, data[0], count, ret); + return ret < 0 ? ret : -EREMOTEIO; + } + + return 0; +} + +int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data) +{ + return stb0899_write_regs(state, reg, &data, 1); +} + +/* + * stb0899_get_mclk + * Get STB0899 master clock frequency + * ExtClk: external clock frequency (Hz) + */ +static u32 stb0899_get_mclk(struct stb0899_state *state) +{ + u32 mclk = 0, div = 0; + + div = stb0899_read_reg(state, STB0899_NCOARSE); + mclk = (div + 1) * state->config->xtal_freq / 6; + dprintk(state->verbose, FE_DEBUG, 1, "div=%d, mclk=%d", div, mclk); + + return mclk; +} + +/* + * stb0899_set_mclk + * Set STB0899 master Clock frequency + * Mclk: demodulator master clock + * ExtClk: external clock frequency (Hz) + */ +static void stb0899_set_mclk(struct stb0899_state *state, u32 Mclk) +{ + struct stb0899_internal *internal = &state->internal; + u8 mdiv = 0; + + dprintk(state->verbose, FE_DEBUG, 1, "state->config=%p", state->config); + mdiv = ((6 * Mclk) / state->config->xtal_freq) - 1; + dprintk(state->verbose, FE_DEBUG, 1, "mdiv=%d", mdiv); + + stb0899_write_reg(state, STB0899_NCOARSE, mdiv); + internal->master_clk = stb0899_get_mclk(state); + + dprintk(state->verbose, FE_DEBUG, 1, "MasterCLOCK=%d", internal->master_clk); +} + +static int stb0899_postproc(struct stb0899_state *state, u8 ctl, int enable) +{ + struct stb0899_config *config = state->config; + const struct stb0899_postproc *postproc = config->postproc; + + /* post process event */ + if (postproc) { + if (enable) { + if (postproc[ctl].level == STB0899_GPIOPULLUP) + stb0899_write_reg(state, postproc[ctl].gpio, 0x02); + else + stb0899_write_reg(state, postproc[ctl].gpio, 0x82); + } else { + if (postproc[ctl].level == STB0899_GPIOPULLUP) + stb0899_write_reg(state, postproc[ctl].gpio, 0x82); + else + stb0899_write_reg(state, postproc[ctl].gpio, 0x02); + } + } + return 0; +} + +static void stb0899_release(struct dvb_frontend *fe) +{ + struct stb0899_state *state = fe->demodulator_priv; + + dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend"); + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0); + kfree(state); +} + +/* + * stb0899_get_alpha + * return: rolloff + */ +static int stb0899_get_alpha(struct stb0899_state *state) +{ + u8 mode_coeff; + + mode_coeff = stb0899_read_reg(state, STB0899_DEMOD); + + if (STB0899_GETFIELD(MODECOEFF, mode_coeff) == 1) + return 20; + else + return 35; +} + +/* + * stb0899_init_calc + */ +static void stb0899_init_calc(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + int master_clk; + u8 agc[2]; + u8 agc1cn; + u32 reg; + + /* Read registers (in burst mode) */ + agc1cn = stb0899_read_reg(state, STB0899_AGC1CN); + stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O */ + + /* Initial calculations */ + master_clk = stb0899_get_mclk(state); + internal->t_agc1 = 0; + internal->t_agc2 = 0; + internal->master_clk = master_clk; + internal->mclk = master_clk / 65536L; + internal->rolloff = stb0899_get_alpha(state); + + /* DVBS2 Initial calculations */ + /* Set AGC value to the middle */ + internal->agc_gain = 8154; + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); + STB0899_SETFIELD_VAL(IF_GAIN_INIT, reg, internal->agc_gain); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, RRC_ALPHA); + internal->rrc_alpha = STB0899_GETFIELD(RRC_ALPHA, reg); + + internal->center_freq = 0; + internal->av_frame_coarse = 10; + internal->av_frame_fine = 20; + internal->step_size = 2; +/* + if ((pParams->SpectralInv == FE_IQ_NORMAL) || (pParams->SpectralInv == FE_IQ_AUTO)) + pParams->IQLocked = 0; + else + pParams->IQLocked = 1; +*/ +} + +static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeout) +{ + u8 reg = 0; + unsigned long start = jiffies; + + while (1) { + reg = stb0899_read_reg(state, STB0899_DISSTATUS); + if (!STB0899_GETFIELD(FIFOFULL, reg)) + break; + if ((jiffies - start) > timeout) { + dprintk(state->verbose, FE_ERROR, 1, "timed out !!"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct stb0899_state *state = fe->demodulator_priv; + u8 reg, i; + + if (cmd->msg_len > 8) + return -EINVAL; + + /* enable FIFO precharge */ + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 1); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + for (i = 0; i < cmd->msg_len; i++) { + /* wait for FIFO empty */ + if (stb0899_wait_diseqc_fifo_empty(state, 10) < 0) + return -ETIMEDOUT; + + stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]); + } + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + msleep(100); + return 0; +} + +static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout) +{ + u8 reg = 0; + unsigned long start = jiffies; + + while (!STB0899_GETFIELD(RXEND, reg)) { + reg = stb0899_read_reg(state, STB0899_DISRX_ST0); + if (jiffies - start > timeout) { + dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); + return -ETIMEDOUT; + } + msleep(10); + } + + return 0; +} + +static int stb0899_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply) +{ + struct stb0899_state *state = fe->demodulator_priv; + u8 reg, length = 0, i; + int result; + + if (stb0899_wait_diseqc_rxidle(state, 100) < 0) + return -ETIMEDOUT; + + reg = stb0899_read_reg(state, STB0899_DISRX_ST0); + if (STB0899_GETFIELD(RXEND, reg)) { + + reg = stb0899_read_reg(state, STB0899_DISRX_ST1); + length = STB0899_GETFIELD(FIFOBYTENBR, reg); + + if (length > sizeof (reply->msg)) { + result = -EOVERFLOW; + goto exit; + } + reply->msg_len = length; + + /* extract data */ + for (i = 0; i < length; i++) + reply->msg[i] = stb0899_read_reg(state, STB0899_DISFIFO); + } + + return 0; +exit: + + return result; +} + +static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout) +{ + u8 reg = 0; + unsigned long start = jiffies; + + while (!STB0899_GETFIELD(TXIDLE, reg)) { + reg = stb0899_read_reg(state, STB0899_DISSTATUS); + if (jiffies - start > timeout) { + dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); + return -ETIMEDOUT; + } + msleep(10); + } + return 0; +} + +static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +{ + struct stb0899_state *state = fe->demodulator_priv; + u8 reg, old_state; + + /* wait for diseqc idle */ + if (stb0899_wait_diseqc_txidle(state, 100) < 0) + return -ETIMEDOUT; + + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + old_state = reg; + /* set to burst mode */ + STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x03); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x01); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + switch (burst) { + case SEC_MINI_A: + /* unmodulated */ + stb0899_write_reg(state, STB0899_DISFIFO, 0x00); + break; + case SEC_MINI_B: + /* modulated */ + stb0899_write_reg(state, STB0899_DISFIFO, 0xff); + break; + } + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x00); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + /* wait for diseqc idle */ + if (stb0899_wait_diseqc_txidle(state, 100) < 0) + return -ETIMEDOUT; + + /* restore state */ + stb0899_write_reg(state, STB0899_DISCNTRL1, old_state); + + return 0; +} + +static int stb0899_diseqc_init(struct stb0899_state *state) +{ + struct dvb_diseqc_master_cmd tx_data; +/* + struct dvb_diseqc_slave_reply rx_data; +*/ + u8 f22_tx, f22_rx, reg; + + u32 mclk, tx_freq = 22000;/* count = 0, i; */ + tx_data.msg[0] = 0xe2; + tx_data.msg_len = 3; + reg = stb0899_read_reg(state, STB0899_DISCNTRL2); + STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0); + stb0899_write_reg(state, STB0899_DISCNTRL2, reg); + + /* disable Tx spy */ + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISEQCRESET, reg, 1); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISEQCRESET, reg, 0); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + + mclk = stb0899_get_mclk(state); + f22_tx = mclk / (tx_freq * 32); + stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq */ + state->rx_freq = 20000; + f22_rx = mclk / (state->rx_freq * 32); + + return 0; +} + +static int stb0899_sleep(struct dvb_frontend *fe) +{ + struct stb0899_state *state = fe->demodulator_priv; +/* + u8 reg; +*/ + dprintk(state->verbose, FE_DEBUG, 1, "Going to Sleep .. (Really tired .. :-))"); + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0); + + return 0; +} + +static int stb0899_wakeup(struct dvb_frontend *fe) +{ + int rc; + struct stb0899_state *state = fe->demodulator_priv; + + if ((rc = stb0899_write_reg(state, STB0899_SYNTCTRL, STB0899_SELOSCI))) + return rc; + /* Activate all clocks; DVB-S2 registers are inaccessible otherwise. */ + if ((rc = stb0899_write_reg(state, STB0899_STOPCLK1, 0x00))) + return rc; + if ((rc = stb0899_write_reg(state, STB0899_STOPCLK2, 0x00))) + return rc; + + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 1); + + return 0; +} + +static int stb0899_init(struct dvb_frontend *fe) +{ + int i; + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_config *config = state->config; + + dprintk(state->verbose, FE_DEBUG, 1, "Initializing STB0899 ... "); + + /* init device */ + dprintk(state->verbose, FE_DEBUG, 1, "init device"); + for (i = 0; config->init_dev[i].address != 0xffff; i++) + stb0899_write_reg(state, config->init_dev[i].address, config->init_dev[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init S2 demod"); + /* init S2 demod */ + for (i = 0; config->init_s2_demod[i].offset != 0xffff; i++) + stb0899_write_s2reg(state, STB0899_S2DEMOD, + config->init_s2_demod[i].base_address, + config->init_s2_demod[i].offset, + config->init_s2_demod[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init S1 demod"); + /* init S1 demod */ + for (i = 0; config->init_s1_demod[i].address != 0xffff; i++) + stb0899_write_reg(state, config->init_s1_demod[i].address, config->init_s1_demod[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init S2 FEC"); + /* init S2 fec */ + for (i = 0; config->init_s2_fec[i].offset != 0xffff; i++) + stb0899_write_s2reg(state, STB0899_S2FEC, + config->init_s2_fec[i].base_address, + config->init_s2_fec[i].offset, + config->init_s2_fec[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init TST"); + /* init test */ + for (i = 0; config->init_tst[i].address != 0xffff; i++) + stb0899_write_reg(state, config->init_tst[i].address, config->init_tst[i].data); + + stb0899_init_calc(state); + stb0899_diseqc_init(state); + + return 0; +} + +static int stb0899_table_lookup(const struct stb0899_tab *tab, int max, int val) +{ + int res = 0; + int min = 0, med; + + if (val < tab[min].read) + res = tab[min].real; + else if (val >= tab[max].read) + res = tab[max].real; + else { + while ((max - min) > 1) { + med = (max + min) / 2; + if (val >= tab[min].read && val < tab[med].read) + max = med; + else + min = med; + } + res = ((val - tab[min].read) * + (tab[max].real - tab[min].real) / + (tab[max].read - tab[min].read)) + + tab[min].real; + } + + return res; +} + +static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + int val; + u32 reg; + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + if (internal->lock) { + reg = stb0899_read_reg(state, STB0899_VSTATUS); + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + + reg = stb0899_read_reg(state, STB0899_AGCIQIN); + val = (s32)(s8)STB0899_GETFIELD(AGCIQVALUE, reg); + + *strength = stb0899_table_lookup(stb0899_dvbsrf_tab, ARRAY_SIZE(stb0899_dvbsrf_tab) - 1, val); + *strength += 750; + dprintk(state->verbose, FE_DEBUG, 1, "AGCIQVALUE = 0x%02x, C = %d * 0.1 dBm", + val & 0xff, *strength); + } + } + break; + case SYS_DVBS2: + if (internal->lock) { + reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN); + val = STB0899_GETFIELD(IF_AGC_GAIN, reg); + + *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val); + *strength += 750; + dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm", + val & 0x3fff, *strength); + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + + return 0; +} + +static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + unsigned int val, quant, quantn = -1, est, estn = -1; + u8 buf[2]; + u32 reg; + + reg = stb0899_read_reg(state, STB0899_VSTATUS); + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + if (internal->lock) { + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + + stb0899_read_regs(state, STB0899_NIRM, buf, 2); + val = MAKEWORD16(buf[0], buf[1]); + + *snr = stb0899_table_lookup(stb0899_cn_tab, ARRAY_SIZE(stb0899_cn_tab) - 1, val); + dprintk(state->verbose, FE_DEBUG, 1, "NIR = 0x%02x%02x = %u, C/N = %d * 0.1 dBm\n", + buf[0], buf[1], val, *snr); + } + } + break; + case SYS_DVBS2: + if (internal->lock) { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1); + quant = STB0899_GETFIELD(UWP_ESN0_QUANT, reg); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + est = STB0899_GETFIELD(ESN0_EST, reg); + if (est == 1) + val = 301; /* C/N = 30.1 dB */ + else if (est == 2) + val = 270; /* C/N = 27.0 dB */ + else { + /* quantn = 100 * log(quant^2) */ + quantn = stb0899_table_lookup(stb0899_quant_tab, ARRAY_SIZE(stb0899_quant_tab) - 1, quant * 100); + /* estn = 100 * log(est) */ + estn = stb0899_table_lookup(stb0899_est_tab, ARRAY_SIZE(stb0899_est_tab) - 1, est); + /* snr(dBm/10) = -10*(log(est)-log(quant^2)) => snr(dBm/10) = (100*log(quant^2)-100*log(est))/10 */ + val = (quantn - estn) / 10; + } + *snr = val; + dprintk(state->verbose, FE_DEBUG, 1, "Es/N0 quant = %d (%d) estimate = %u (%d), C/N = %d * 0.1 dBm", + quant, quantn, est, estn, val); + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + + return 0; +} + +static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + u8 reg; + *status = 0; + + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S/DSS"); + if (internal->lock) { + reg = stb0899_read_reg(state, STB0899_VSTATUS); + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK"); + *status |= FE_HAS_CARRIER | FE_HAS_LOCK; + + reg = stb0899_read_reg(state, STB0899_PLPARM); + if (STB0899_GETFIELD(VITCURPUN, reg)) { + dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_VITERBI | FE_HAS_SYNC"); + *status |= FE_HAS_VITERBI | FE_HAS_SYNC; + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1); + } + } + } + break; + case SYS_DVBS2: + dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S2"); + if (internal->lock) { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2); + if (STB0899_GETFIELD(UWP_LOCK, reg) && STB0899_GETFIELD(CSM_LOCK, reg)) { + *status |= FE_HAS_CARRIER; + dprintk(state->verbose, FE_DEBUG, 1, + "UWP & CSM Lock ! ---> DVB-S2 FE_HAS_CARRIER"); + + reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1); + if (STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg)) { + *status |= FE_HAS_LOCK; + dprintk(state->verbose, FE_DEBUG, 1, + "Packet Delineator Locked ! -----> DVB-S2 FE_HAS_LOCK"); + + } + if (STB0899_GETFIELD(CONTINUOUS_STREAM, reg)) { + *status |= FE_HAS_VITERBI; + dprintk(state->verbose, FE_DEBUG, 1, + "Packet Delineator found VITERBI ! -----> DVB-S2 FE_HAS_VITERBI"); + } + if (STB0899_GETFIELD(ACCEPTED_STREAM, reg)) { + *status |= FE_HAS_SYNC; + dprintk(state->verbose, FE_DEBUG, 1, + "Packet Delineator found SYNC ! -----> DVB-S2 FE_HAS_SYNC"); + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1); + } + } + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + return 0; +} + +/* + * stb0899_get_error + * viterbi error for DVB-S/DSS + * packet error for DVB-S2 + * Bit Error Rate or Packet Error Rate * 10 ^ 7 + */ +static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + u8 lsb, msb; + u32 i; + + *ber = 0; + + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + if (internal->lock) { + /* average 5 BER values */ + for (i = 0; i < 5; i++) { + msleep(100); + lsb = stb0899_read_reg(state, STB0899_ECNT1L); + msb = stb0899_read_reg(state, STB0899_ECNT1M); + *ber += MAKEWORD16(msb, lsb); + } + *ber /= 5; + /* Viterbi Check */ + if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) { + /* Error Rate */ + *ber *= 9766; + /* ber = ber * 10 ^ 7 */ + *ber /= (-1 + (1 << (2 * STB0899_GETFIELD(NOE, internal->err_ctrl)))); + *ber /= 8; + } + } + break; + case SYS_DVBS2: + if (internal->lock) { + /* Average 5 PER values */ + for (i = 0; i < 5; i++) { + msleep(100); + lsb = stb0899_read_reg(state, STB0899_ECNT1L); + msb = stb0899_read_reg(state, STB0899_ECNT1M); + *ber += MAKEWORD16(msb, lsb); + } + /* ber = ber * 10 ^ 7 */ + *ber *= 10000000; + *ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl)))); + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + + return 0; +} + +static int stb0899_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct stb0899_state *state = fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82); + stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02); + stb0899_write_reg(state, STB0899_GPIO02CFG, 0x00); + break; + case SEC_VOLTAGE_18: + stb0899_write_reg(state, STB0899_GPIO00CFG, 0x02); + stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02); + stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82); + break; + case SEC_VOLTAGE_OFF: + stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82); + stb0899_write_reg(state, STB0899_GPIO01CFG, 0x82); + stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int stb0899_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + u8 div, reg; + + /* wait for diseqc idle */ + if (stb0899_wait_diseqc_txidle(state, 100) < 0) + return -ETIMEDOUT; + + switch (tone) { + case SEC_TONE_ON: + div = (internal->master_clk / 100) / 5632; + div = (div + 5) / 10; + stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x66); + reg = stb0899_read_reg(state, STB0899_ACRPRESC); + STB0899_SETFIELD_VAL(ACRPRESC, reg, 0x03); + stb0899_write_reg(state, STB0899_ACRPRESC, reg); + stb0899_write_reg(state, STB0899_ACRDIV1, div); + break; + case SEC_TONE_OFF: + stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x20); + break; + default: + return -EINVAL; + } + return 0; +} + +int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int i2c_stat; + struct stb0899_state *state = fe->demodulator_priv; + + i2c_stat = stb0899_read_reg(state, STB0899_I2CRPT); + if (i2c_stat < 0) + goto err; + + if (enable) { + dprintk(state->verbose, FE_DEBUG, 1, "Enabling I2C Repeater ..."); + i2c_stat |= STB0899_I2CTON; + if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0) + goto err; + } else { + dprintk(state->verbose, FE_DEBUG, 1, "Disabling I2C Repeater ..."); + i2c_stat &= ~STB0899_I2CTON; + if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0) + goto err; + } + return 0; +err: + dprintk(state->verbose, FE_ERROR, 1, "I2C Repeater control failed"); + return -EREMOTEIO; +} + + +static inline void CONVERT32(u32 x, char *str) +{ + *str++ = (x >> 24) & 0xff; + *str++ = (x >> 16) & 0xff; + *str++ = (x >> 8) & 0xff; + *str++ = (x >> 0) & 0xff; + *str = '\0'; +} + +int stb0899_get_dev_id(struct stb0899_state *state) +{ + u8 chip_id, release; + u16 id; + u32 demod_ver = 0, fec_ver = 0; + char demod_str[5] = { 0 }; + char fec_str[5] = { 0 }; + + id = stb0899_read_reg(state, STB0899_DEV_ID); + dprintk(state->verbose, FE_DEBUG, 1, "ID reg=[0x%02x]", id); + chip_id = STB0899_GETFIELD(CHIP_ID, id); + release = STB0899_GETFIELD(CHIP_REL, id); + + dprintk(state->verbose, FE_ERROR, 1, "Device ID=[%d], Release=[%d]", + chip_id, release); + + CONVERT32(STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CORE_ID), (char *)&demod_str); + + demod_ver = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_VERSION_ID); + dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver); + CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str); + fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG); + if (! (chip_id > 0)) { + dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899"); + + return -ENODEV; + } + dprintk(state->verbose, FE_ERROR, 1, "FEC Core ID=[%s], Version=[%d]", (char*) &fec_str, fec_ver); + + return 0; +} + +static void stb0899_set_delivery(struct stb0899_state *state) +{ + u8 reg; + u8 stop_clk[2]; + + stop_clk[0] = stb0899_read_reg(state, STB0899_STOPCLK1); + stop_clk[1] = stb0899_read_reg(state, STB0899_STOPCLK2); + + switch (state->delsys) { + case SYS_DVBS: + dprintk(state->verbose, FE_DEBUG, 1, "Delivery System -- DVB-S"); + /* FECM/Viterbi ON */ + reg = stb0899_read_reg(state, STB0899_FECM); + STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0); + STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1); + stb0899_write_reg(state, STB0899_FECM, reg); + + stb0899_write_reg(state, STB0899_RSULC, 0xb1); + stb0899_write_reg(state, STB0899_TSULC, 0x40); + stb0899_write_reg(state, STB0899_RSLLC, 0x42); + stb0899_write_reg(state, STB0899_TSLPL, 0x12); + + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESLDPC, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1); + + STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1); + STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1); + + STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1); + break; + case SYS_DVBS2: + /* FECM/Viterbi OFF */ + reg = stb0899_read_reg(state, STB0899_FECM); + STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0); + STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 0); + stb0899_write_reg(state, STB0899_FECM, reg); + + stb0899_write_reg(state, STB0899_RSULC, 0xb1); + stb0899_write_reg(state, STB0899_TSULC, 0x42); + stb0899_write_reg(state, STB0899_RSLLC, 0x40); + stb0899_write_reg(state, STB0899_TSLPL, 0x02); + + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESLDPC, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 0); + STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 0); + STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 0); + + STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 0); + STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 0); + break; + case SYS_DSS: + /* FECM/Viterbi ON */ + reg = stb0899_read_reg(state, STB0899_FECM); + STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 1); + STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1); + stb0899_write_reg(state, STB0899_FECM, reg); + + stb0899_write_reg(state, STB0899_RSULC, 0xa1); + stb0899_write_reg(state, STB0899_TSULC, 0x61); + stb0899_write_reg(state, STB0899_RSLLC, 0x42); + + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESLDPC, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1); + + STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1); + STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1); + + STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1); + break; + default: + dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system"); + break; + } + STB0899_SETFIELD_VAL(STOP_CKADCI108, stop_clk[0], 0); + stb0899_write_regs(state, STB0899_STOPCLK1, stop_clk, 2); +} + +/* + * stb0899_set_iterations + * set the LDPC iteration scale function + */ +static void stb0899_set_iterations(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + s32 iter_scale; + u32 reg; + + iter_scale = 17 * (internal->master_clk / 1000); + iter_scale += 410000; + iter_scale /= (internal->srate / 1000000); + iter_scale /= 1000; + + if (iter_scale > config->ldpc_max_iter) + iter_scale = config->ldpc_max_iter; + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, MAX_ITER); + STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg); +} + +static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_params *i_params = &state->params; + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + struct dtv_frontend_properties *props = &fe->dtv_property_cache; + + u32 SearchRange, gain; + + i_params->freq = p->frequency; + i_params->srate = p->u.qpsk.symbol_rate; + state->delsys = props->delivery_system; + dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys); + + SearchRange = 10000000; + dprintk(state->verbose, FE_DEBUG, 1, "Frequency=%d, Srate=%d", i_params->freq, i_params->srate); + /* checking Search Range is meaningless for a fixed 3 Mhz */ + if (INRANGE(i_params->srate, 1000000, 45000000)) { + dprintk(state->verbose, FE_DEBUG, 1, "Parameters IN RANGE"); + stb0899_set_delivery(state); + + if (state->config->tuner_set_rfsiggain) { + if (internal->srate > 15000000) + gain = 8; /* 15Mb < srate < 45Mb, gain = 8dB */ + else if (internal->srate > 5000000) + gain = 12; /* 5Mb < srate < 15Mb, gain = 12dB */ + else + gain = 14; /* 1Mb < srate < 5Mb, gain = 14db */ + state->config->tuner_set_rfsiggain(fe, gain); + } + + if (i_params->srate <= 5000000) + stb0899_set_mclk(state, config->lo_clk); + else + stb0899_set_mclk(state, config->hi_clk); + + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + dprintk(state->verbose, FE_DEBUG, 1, "DVB-S delivery system"); + internal->freq = i_params->freq; + internal->srate = i_params->srate; + /* + * search = user search range + + * 500Khz + + * 2 * Tuner_step_size + + * 10% of the symbol rate + */ + internal->srch_range = SearchRange + 1500000 + (i_params->srate / 5); + internal->derot_percent = 30; + + /* What to do for tuners having no bandwidth setup ? */ + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + if (state->config->tuner_set_bandwidth) + state->config->tuner_set_bandwidth(fe, (13 * (stb0899_carr_width(state) + SearchRange)) / 10); + if (state->config->tuner_get_bandwidth) + state->config->tuner_get_bandwidth(fe, &internal->tuner_bw); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + + /* Set DVB-S1 AGC */ + stb0899_write_reg(state, STB0899_AGCRFCFG, 0x11); + + /* Run the search algorithm */ + dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S search algo .."); + if (stb0899_dvbs_algo(state) == RANGEOK) { + internal->lock = 1; + dprintk(state->verbose, FE_DEBUG, 1, + "-------------------------------------> DVB-S LOCK !"); + +// stb0899_write_reg(state, STB0899_ERRCTRL1, 0x3d); /* Viterbi Errors */ +// internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS); +// internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1); +// dprintk(state->verbose, FE_DEBUG, 1, "VSTATUS=0x%02x", internal->v_status); +// dprintk(state->verbose, FE_DEBUG, 1, "ERR_CTRL=0x%02x", internal->err_ctrl); + + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + internal->lock = 0; + + return DVBFE_ALGO_SEARCH_FAILED; + } + break; + case SYS_DVBS2: + internal->freq = i_params->freq; + internal->srate = i_params->srate; + internal->srch_range = SearchRange; + + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + if (state->config->tuner_set_bandwidth) + state->config->tuner_set_bandwidth(fe, (stb0899_carr_width(state) + SearchRange)); + if (state->config->tuner_get_bandwidth) + state->config->tuner_get_bandwidth(fe, &internal->tuner_bw); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + +// pParams->SpectralInv = pSearch->IQ_Inversion; + + /* Set DVB-S2 AGC */ + stb0899_write_reg(state, STB0899_AGCRFCFG, 0x1c); + + /* Set IterScale =f(MCLK,SYMB) */ + stb0899_set_iterations(state); + + /* Run the search algorithm */ + dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S2 search algo .."); + if (stb0899_dvbs2_algo(state) == DVBS2_FEC_LOCK) { + internal->lock = 1; + dprintk(state->verbose, FE_DEBUG, 1, + "-------------------------------------> DVB-S2 LOCK !"); + +// stb0899_write_reg(state, STB0899_ERRCTRL1, 0xb6); /* Packet Errors */ +// internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS); +// internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1); + + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + internal->lock = 0; + + return DVBFE_ALGO_SEARCH_FAILED; + } + break; + default: + dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system"); + return DVBFE_ALGO_SEARCH_INVALID; + } + } + + return DVBFE_ALGO_SEARCH_ERROR; +} +/* + * stb0899_track + * periodically check the signal level against a specified + * threshold level and perform derotator centering. + * called once we have a lock from a successful search + * event. + * + * Will be called periodically called to maintain the + * lock. + * + * Will be used to get parameters as well as info from + * the decoded baseband header + * + * Once a new lock has established, the internal state + * frequency (internal->freq) is updated + */ +static int stb0899_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + return 0; +} + +static int stb0899_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + dprintk(state->verbose, FE_DEBUG, 1, "Get params"); + p->u.qpsk.symbol_rate = internal->srate; + + return 0; +} + +static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static struct dvb_frontend_ops stb0899_ops = { + + .info = { + .name = "STB0899 Multistandard", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 0, + .frequency_tolerance = 0, + .symbol_rate_min = 5000000, + .symbol_rate_max = 45000000, + + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_AUTO | + FE_CAN_2G_MODULATION | + FE_CAN_QPSK + }, + + .release = stb0899_release, + .init = stb0899_init, + .sleep = stb0899_sleep, +// .wakeup = stb0899_wakeup, + + .i2c_gate_ctrl = stb0899_i2c_gate_ctrl, + + .get_frontend_algo = stb0899_frontend_algo, + .search = stb0899_search, + .track = stb0899_track, + .get_frontend = stb0899_get_frontend, + + + .read_status = stb0899_read_status, + .read_snr = stb0899_read_snr, + .read_signal_strength = stb0899_read_signal_strength, + .read_ber = stb0899_read_ber, + + .set_voltage = stb0899_set_voltage, + .set_tone = stb0899_set_tone, + + .diseqc_send_master_cmd = stb0899_send_diseqc_msg, + .diseqc_recv_slave_reply = stb0899_recv_slave_reply, + .diseqc_send_burst = stb0899_send_diseqc_burst, +}; + +struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c) +{ + struct stb0899_state *state = NULL; + enum stb0899_inversion inversion; + + state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL); + if (state == NULL) + goto error; + + inversion = config->inversion; + state->verbose = &verbose; + state->config = config; + state->i2c = i2c; + state->frontend.ops = stb0899_ops; + state->frontend.demodulator_priv = state; + state->internal.inversion = inversion; + + stb0899_wakeup(&state->frontend); + if (stb0899_get_dev_id(state) == -ENODEV) { + printk("%s: Exiting .. !\n", __func__); + goto error; + } + + printk("%s: Attaching STB0899 \n", __func__); + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stb0899_attach); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STB0899 Multi-Std frontend"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_drv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_drv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_drv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_drv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,162 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STB0899_DRV_H +#define __STB0899_DRV_H + +#include +#include + +#include "dvb_frontend.h" + +#define STB0899_TSMODE_SERIAL 1 +#define STB0899_CLKPOL_FALLING 2 +#define STB0899_CLKNULL_PARITY 3 +#define STB0899_SYNC_FORCED 4 +#define STB0899_FECMODE_DSS 5 + +struct stb0899_s1_reg { + u16 address; + u8 data; +}; + +struct stb0899_s2_reg { + u16 offset; + u32 base_address; + u32 data; +}; + +enum stb0899_inversion { + IQ_SWAP_OFF = 0, + IQ_SWAP_ON, + IQ_SWAP_AUTO +}; + +#define STB0899_GPIO00 0xf140 +#define STB0899_GPIO01 0xf141 +#define STB0899_GPIO02 0xf142 +#define STB0899_GPIO03 0xf143 +#define STB0899_GPIO04 0xf144 +#define STB0899_GPIO05 0xf145 +#define STB0899_GPIO06 0xf146 +#define STB0899_GPIO07 0xf147 +#define STB0899_GPIO08 0xf148 +#define STB0899_GPIO09 0xf149 +#define STB0899_GPIO10 0xf14a +#define STB0899_GPIO11 0xf14b +#define STB0899_GPIO12 0xf14c +#define STB0899_GPIO13 0xf14d +#define STB0899_GPIO14 0xf14e +#define STB0899_GPIO15 0xf14f +#define STB0899_GPIO16 0xf150 +#define STB0899_GPIO17 0xf151 +#define STB0899_GPIO18 0xf152 +#define STB0899_GPIO19 0xf153 +#define STB0899_GPIO20 0xf154 + +#define STB0899_GPIOPULLUP 0x01 /* Output device is connected to Vdd */ +#define STB0899_GPIOPULLDN 0x00 /* Output device is connected to Vss */ + +#define STB0899_POSTPROC_GPIO_POWER 0x00 +#define STB0899_POSTPROC_GPIO_LOCK 0x01 + +/* + * Post process output configuration control + * 1. POWER ON/OFF (index 0) + * 2. FE_HAS_LOCK/LOCK_LOSS (index 1) + * + * @gpio = one of the above listed GPIO's + * @level = output state: pulled up or low + */ +struct stb0899_postproc { + u16 gpio; + u8 level; +}; + +struct stb0899_config { + const struct stb0899_s1_reg *init_dev; + const struct stb0899_s2_reg *init_s2_demod; + const struct stb0899_s1_reg *init_s1_demod; + const struct stb0899_s2_reg *init_s2_fec; + const struct stb0899_s1_reg *init_tst; + + const struct stb0899_postproc *postproc; + + enum stb0899_inversion inversion; + + u32 xtal_freq; + + u8 demod_address; + u8 ts_output_mode; + u8 block_sync_mode; + u8 ts_pfbit_toggle; + + u8 clock_polarity; + u8 data_clk_parity; + u8 fec_mode; + u8 data_output_ctl; + u8 data_fifo_mode; + u8 out_rate_comp; + u8 i2c_repeater; +// int inversion; + int lo_clk; + int hi_clk; + + u32 esno_ave; + u32 esno_quant; + u32 avframes_coarse; + u32 avframes_fine; + u32 miss_threshold; + u32 uwp_threshold_acq; + u32 uwp_threshold_track; + u32 uwp_threshold_sof; + u32 sof_search_timeout; + + u32 btr_nco_bits; + u32 btr_gain_shift_offset; + u32 crl_nco_bits; + u32 ldpc_max_iter; + + int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency); + int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency); + int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); + int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); + int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain); +}; + +#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *stb0899_attach(struct stb0899_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif //CONFIG_DVB_STB0899 + + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,263 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STB0899_PRIV_H +#define __STB0899_PRIV_H + +#include "dvb_frontend.h" +#include "stb0899_drv.h" + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 +#define FE_DEBUGREG 4 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((*x > FE_ERROR) && (*x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((*x > FE_NOTICE) && (*x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((*x > FE_INFO) && (*x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((*x > FE_DEBUG) && (*x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (*x > y) \ + printk(format, ##arg); \ + } \ +} while(0) + +#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \ + ((y <= val) && (val <= x)) ? 1 : 0) + +#define BYTE0 0 +#define BYTE1 8 +#define BYTE2 16 +#define BYTE3 24 + +#define GETBYTE(x, y) (((x) >> (y)) & 0xff) +#define MAKEWORD32(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +#define MAKEWORD16(a, b) (((a) << 8) | (b)) + +#define LSB(x) ((x & 0xff)) +#define MSB(y) ((y >> 8) & 0xff) + + +#define STB0899_GETFIELD(bitf, val) ((val >> STB0899_OFFST_##bitf) & ((1 << STB0899_WIDTH_##bitf) - 1)) + + +#define STB0899_SETFIELD(mask, val, width, offset) (mask & (~(((1 << width) - 1) << \ + offset))) | ((val & \ + ((1 << width) - 1)) << offset) + +#define STB0899_SETFIELD_VAL(bitf, mask, val) (mask = (mask & (~(((1 << STB0899_WIDTH_##bitf) - 1) <<\ + STB0899_OFFST_##bitf))) | \ + (val << STB0899_OFFST_##bitf)) + + +enum stb0899_status { + NOAGC1 = 0, + AGC1OK, + NOTIMING, + ANALOGCARRIER, + TIMINGOK, + NOAGC2, + AGC2OK, + NOCARRIER, + CARRIEROK, + NODATA, + FALSELOCK, + DATAOK, + OUTOFRANGE, + RANGEOK, + DVBS2_DEMOD_LOCK, + DVBS2_DEMOD_NOLOCK, + DVBS2_FEC_LOCK, + DVBS2_FEC_NOLOCK +}; + +enum stb0899_modcod { + STB0899_DUMMY_PLF, + STB0899_QPSK_14, + STB0899_QPSK_13, + STB0899_QPSK_25, + STB0899_QPSK_12, + STB0899_QPSK_35, + STB0899_QPSK_23, + STB0899_QPSK_34, + STB0899_QPSK_45, + STB0899_QPSK_56, + STB0899_QPSK_89, + STB0899_QPSK_910, + STB0899_8PSK_35, + STB0899_8PSK_23, + STB0899_8PSK_34, + STB0899_8PSK_56, + STB0899_8PSK_89, + STB0899_8PSK_910, + STB0899_16APSK_23, + STB0899_16APSK_34, + STB0899_16APSK_45, + STB0899_16APSK_56, + STB0899_16APSK_89, + STB0899_16APSK_910, + STB0899_32APSK_34, + STB0899_32APSK_45, + STB0899_32APSK_56, + STB0899_32APSK_89, + STB0899_32APSK_910 +}; + +enum stb0899_frame { + STB0899_LONG_FRAME, + STB0899_SHORT_FRAME +}; + +enum stb0899_alpha { + RRC_20, + RRC_25, + RRC_35 +}; + +struct stb0899_tab { + s32 real; + s32 read; +}; + +enum stb0899_fec { + STB0899_FEC_1_2 = 13, + STB0899_FEC_2_3 = 18, + STB0899_FEC_3_4 = 21, + STB0899_FEC_5_6 = 24, + STB0899_FEC_6_7 = 25, + STB0899_FEC_7_8 = 26 +}; + +struct stb0899_params { + u32 freq; /* Frequency */ + u32 srate; /* Symbol rate */ + enum fe_code_rate fecrate; +}; + +struct stb0899_internal { + u32 master_clk; + u32 freq; /* Demod internal Frequency */ + u32 srate; /* Demod internal Symbol rate */ + enum stb0899_fec fecrate; /* Demod internal FEC rate */ + s32 srch_range; /* Demod internal Search Range */ + s32 sub_range; /* Demod current sub range (Hz) */ + s32 tuner_step; /* Tuner step (Hz) */ + s32 tuner_offst; /* Relative offset to carrier (Hz) */ + u32 tuner_bw; /* Current bandwidth of the tuner (Hz) */ + + s32 mclk; /* Masterclock Divider factor (binary) */ + s32 rolloff; /* Current RollOff of the filter (x100) */ + + s16 derot_freq; /* Current derotator frequency (Hz) */ + s16 derot_percent; + + s16 direction; /* Current derotator search direction */ + s16 derot_step; /* Derotator step (binary value) */ + s16 t_derot; /* Derotator time constant (ms) */ + s16 t_data; /* Data recovery time constant (ms) */ + s16 sub_dir; /* Direction of the next sub range */ + + s16 t_agc1; /* Agc1 time constant (ms) */ + s16 t_agc2; /* Agc2 time constant (ms) */ + + u32 lock; /* Demod internal lock state */ + enum stb0899_status status; /* Demod internal status */ + + /* DVB-S2 */ + s32 agc_gain; /* RF AGC Gain */ + s32 center_freq; /* Nominal carrier frequency */ + s32 av_frame_coarse; /* Coarse carrier freq search frames */ + s32 av_frame_fine; /* Fine carrier freq search frames */ + + s16 step_size; /* Carrier frequency search step size */ + + enum stb0899_alpha rrc_alpha; + enum stb0899_inversion inversion; + enum stb0899_modcod modcod; + u8 pilots; /* Pilots found */ + + enum stb0899_frame frame_length; + u8 v_status; /* VSTATUS */ + u8 err_ctrl; /* ERRCTRLn */ +}; + +struct stb0899_state { + struct i2c_adapter *i2c; + struct stb0899_config *config; + struct dvb_frontend frontend; + + u32 *verbose; /* Cached module verbosity level */ + + struct stb0899_internal internal; /* Device internal parameters */ + + /* cached params from API */ + enum fe_delivery_system delsys; + struct stb0899_params params; + + u32 rx_freq; /* DiSEqC 2.0 receiver freq */ + struct mutex search_lock; +}; +/* stb0899.c */ +extern int stb0899_read_reg(struct stb0899_state *state, + unsigned int reg); + +extern u32 _stb0899_read_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset); + +extern int stb0899_read_regs(struct stb0899_state *state, + unsigned int reg, u8 *buf, + u32 count); + +extern int stb0899_write_regs(struct stb0899_state *state, + unsigned int reg, u8 *data, + u32 count); + +extern int stb0899_write_reg(struct stb0899_state *state, + unsigned int reg, + u8 data); + +extern int stb0899_write_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset, + u32 stb0899_data); + +extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable); + + +#define STB0899_READ_S2REG(DEVICE, REG) (_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG)) +//#define STB0899_WRITE_S2REG(DEVICE, REG, DATA) (_stb0899_write_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG, DATA)) + +/* stb0899_algo.c */ +extern enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state); +extern enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state); +extern long stb0899_carr_width(struct stb0899_state *state); + +#endif //__STB0899_PRIV_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb0899_reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,2027 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STB0899_REG_H +#define __STB0899_REG_H + +/* S1 */ +#define STB0899_DEV_ID 0xf000 +#define STB0899_CHIP_ID (0x0f << 4) +#define STB0899_OFFST_CHIP_ID 4 +#define STB0899_WIDTH_CHIP_ID 4 +#define STB0899_CHIP_REL (0x0f << 0) +#define STB0899_OFFST_CHIP_REL 0 +#define STB0899_WIDTH_CHIP_REL 4 + +#define STB0899_DEMOD 0xf40e +#define STB0899_MODECOEFF (0x01 << 0) +#define STB0899_OFFST_MODECOEFF 0 +#define STB0899_WIDTH_MODECOEFF 1 + +#define STB0899_RCOMPC 0xf410 +#define STB0899_AGC1CN 0xf412 +#define STB0899_AGC1REF 0xf413 +#define STB0899_RTC 0xf417 +#define STB0899_TMGCFG 0xf418 +#define STB0899_AGC2REF 0xf419 +#define STB0899_TLSR 0xf41a + +#define STB0899_CFD 0xf41b +#define STB0899_CFD_ON (0x01 << 7) +#define STB0899_OFFST_CFD_ON 7 +#define STB0899_WIDTH_CFD_ON 1 + +#define STB0899_ACLC 0xf41c + +#define STB0899_BCLC 0xf41d +#define STB0899_OFFST_ALGO 6 +#define STB0899_WIDTH_ALGO_QPSK2 2 +#define STB0899_ALGO_QPSK2 (2 << 6) +#define STB0899_ALGO_QPSK1 (1 << 6) +#define STB0899_ALGO_BPSK (0 << 6) +#define STB0899_OFFST_BETA 0 +#define STB0899_WIDTH_BETA 6 + +#define STB0899_EQON 0xf41e +#define STB0899_LDT 0xf41f +#define STB0899_LDT2 0xf420 +#define STB0899_EQUALREF 0xf425 +#define STB0899_TMGRAMP 0xf426 +#define STB0899_TMGTHD 0xf427 +#define STB0899_IDCCOMP 0xf428 +#define STB0899_QDCCOMP 0xf429 +#define STB0899_POWERI 0xf42a +#define STB0899_POWERQ 0xf42b +#define STB0899_RCOMP 0xf42c + +#define STB0899_AGCIQIN 0xf42e +#define STB0899_AGCIQVALUE (0xff << 0) +#define STB0899_OFFST_AGCIQVALUE 0 +#define STB0899_WIDTH_AGCIQVALUE 8 + +#define STB0899_AGC2I1 0xf436 +#define STB0899_AGC2I2 0xf437 + +#define STB0899_TLIR 0xf438 +#define STB0899_TLIR_TMG_LOCK_IND (0xff << 0) +#define STB0899_OFFST_TLIR_TMG_LOCK_IND 0 +#define STB0899_WIDTH_TLIR_TMG_LOCK_IND 8 + +#define STB0899_RTF 0xf439 +#define STB0899_RTF_TIMING_LOOP_FREQ (0xff << 0) +#define STB0899_OFFST_RTF_TIMING_LOOP_FREQ 0 +#define STB0899_WIDTH_RTF_TIMING_LOOP_FREQ 8 + +#define STB0899_DSTATUS 0xf43a +#define STB0899_CARRIER_FOUND (0x01 << 7) +#define STB0899_OFFST_CARRIER_FOUND 7 +#define STB0899_WIDTH_CARRIER_FOUND 1 +#define STB0899_TMG_LOCK (0x01 << 6) +#define STB0899_OFFST_TMG_LOCK 6 +#define STB0899_WIDTH_TMG_LOCK 1 +#define STB0899_DEMOD_LOCK (0x01 << 5) +#define STB0899_OFFST_DEMOD_LOCK 5 +#define STB0899_WIDTH_DEMOD_LOCK 1 +#define STB0899_TMG_AUTO (0x01 << 4) +#define STB0899_OFFST_TMG_AUTO 4 +#define STB0899_WIDTH_TMG_AUTO 1 +#define STB0899_END_MAIN (0x01 << 3) +#define STB0899_OFFST_END_MAIN 3 +#define STB0899_WIDTH_END_MAIN 1 + +#define STB0899_LDI 0xf43b +#define STB0899_OFFST_LDI 0 +#define STB0899_WIDTH_LDI 8 + +#define STB0899_CFRM 0xf43e +#define STB0899_OFFST_CFRM 0 +#define STB0899_WIDTH_CFRM 8 + +#define STB0899_CFRL 0xf43f +#define STB0899_OFFST_CFRL 0 +#define STB0899_WIDTH_CFRL 8 + +#define STB0899_NIRM 0xf440 +#define STB0899_OFFST_NIRM 0 +#define STB0899_WIDTH_NIRM 8 + +#define STB0899_NIRL 0xf441 +#define STB0899_OFFST_NIRL 0 +#define STB0899_WIDTH_NIRL 8 + +#define STB0899_ISYMB 0xf444 +#define STB0899_QSYMB 0xf445 + +#define STB0899_SFRH 0xf446 +#define STB0899_OFFST_SFRH 0 +#define STB0899_WIDTH_SFRH 8 + +#define STB0899_SFRM 0xf447 +#define STB0899_OFFST_SFRM 0 +#define STB0899_WIDTH_SFRM 8 + +#define STB0899_SFRL 0xf448 +#define STB0899_OFFST_SFRL 4 +#define STB0899_WIDTH_SFRL 4 + +#define STB0899_SFRUPH 0xf44c +#define STB0899_SFRUPM 0xf44d +#define STB0899_SFRUPL 0xf44e + +#define STB0899_EQUAI1 0xf4e0 +#define STB0899_EQUAQ1 0xf4e1 +#define STB0899_EQUAI2 0xf4e2 +#define STB0899_EQUAQ2 0xf4e3 +#define STB0899_EQUAI3 0xf4e4 +#define STB0899_EQUAQ3 0xf4e5 +#define STB0899_EQUAI4 0xf4e6 +#define STB0899_EQUAQ4 0xf4e7 +#define STB0899_EQUAI5 0xf4e8 +#define STB0899_EQUAQ5 0xf4e9 + +#define STB0899_DSTATUS2 0xf50c +#define STB0899_DS2_TMG_AUTOSRCH (0x01 << 7) +#define STB8999_OFFST_DS2_TMG_AUTOSRCH 7 +#define STB0899_WIDTH_DS2_TMG_AUTOSRCH 1 +#define STB0899_DS2_END_MAINLOOP (0x01 << 6) +#define STB0899_OFFST_DS2_END_MAINLOOP 6 +#define STB0899_WIDTH_DS2_END_MAINLOOP 1 +#define STB0899_DS2_CFSYNC (0x01 << 5) +#define STB0899_OFFST_DS2_CFSYNC 5 +#define STB0899_WIDTH_DS2_CFSYNC 1 +#define STB0899_DS2_TMGLOCK (0x01 << 4) +#define STB0899_OFFST_DS2_TMGLOCK 4 +#define STB0899_WIDTH_DS2_TMGLOCK 1 +#define STB0899_DS2_DEMODWAIT (0x01 << 3) +#define STB0899_OFFST_DS2_DEMODWAIT 3 +#define STB0899_WIDTH_DS2_DEMODWAIT 1 +#define STB0899_DS2_FECON (0x01 << 1) +#define STB0899_OFFST_DS2_FECON 1 +#define STB0899_WIDTH_DS2_FECON 1 + +/* S1 FEC */ +#define STB0899_VSTATUS 0xf50d +#define STB0899_VSTATUS_VITERBI_ON (0x01 << 7) +#define STB0899_OFFST_VSTATUS_VITERBI_ON 7 +#define STB0899_WIDTH_VSTATUS_VITERBI_ON 1 +#define STB0899_VSTATUS_END_LOOPVIT (0x01 << 6) +#define STB0899_OFFST_VSTATUS_END_LOOPVIT 6 +#define STB0899_WIDTH_VSTATUS_END_LOOPVIT 1 +#define STB0899_VSTATUS_PRFVIT (0x01 << 4) +#define STB0899_OFFST_VSTATUS_PRFVIT 4 +#define STB0899_WIDTH_VSTATUS_PRFVIT 1 +#define STB0899_VSTATUS_LOCKEDVIT (0x01 << 3) +#define STB0899_OFFST_VSTATUS_LOCKEDVIT 3 +#define STB0899_WIDTH_VSTATUS_LOCKEDVIT 1 + +#define STB0899_VERROR 0xf50f + +#define STB0899_IQSWAP 0xf523 +#define STB0899_SYM (0x01 << 3) +#define STB0899_OFFST_SYM 3 +#define STB0899_WIDTH_SYM 1 + +#define STB0899_FECAUTO1 0xf530 +#define STB0899_DSSSRCH (0x01 << 3) +#define STB0899_OFFST_DSSSRCH 3 +#define STB0899_WIDTH_DSSSRCH 1 +#define STB0899_SYMSRCH (0x01 << 2) +#define STB0899_OFFST_SYMSRCH 2 +#define STB0899_WIDTH_SYMSRCH 1 +#define STB0899_QPSKSRCH (0x01 << 1) +#define STB0899_OFFST_QPSKSRCH 1 +#define STB0899_WIDTH_QPSKSRCH 1 +#define STB0899_BPSKSRCH (0x01 << 0) +#define STB0899_OFFST_BPSKSRCH 0 +#define STB0899_WIDTH_BPSKSRCH 1 + +#define STB0899_FECM 0xf533 +#define STB0899_FECM_NOT_DVB (0x01 << 7) +#define STB0899_OFFST_FECM_NOT_DVB 7 +#define STB0899_WIDTH_FECM_NOT_DVB 1 +#define STB0899_FECM_RSVD1 (0x07 << 4) +#define STB0899_OFFST_FECM_RSVD1 4 +#define STB0899_WIDTH_FECM_RSVD1 3 +#define STB0899_FECM_VITERBI_ON (0x01 << 3) +#define STB0899_OFFST_FECM_VITERBI_ON 3 +#define STB0899_WIDTH_FECM_VITERBI_ON 1 +#define STB0899_FECM_RSVD0 (0x01 << 2) +#define STB0899_OFFST_FECM_RSVD0 2 +#define STB0899_WIDTH_FECM_RSVD0 1 +#define STB0899_FECM_SYNCDIS (0x01 << 1) +#define STB0899_OFFST_FECM_SYNCDIS 1 +#define STB0899_WIDTH_FECM_SYNCDIS 1 +#define STB0899_FECM_SYMI (0x01 << 0) +#define STB0899_OFFST_FECM_SYMI 0 +#define STB0899_WIDTH_FECM_SYMI 1 + +#define STB0899_VTH12 0xf534 +#define STB0899_VTH23 0xf535 +#define STB0899_VTH34 0xf536 +#define STB0899_VTH56 0xf537 +#define STB0899_VTH67 0xf538 +#define STB0899_VTH78 0xf539 + +#define STB0899_PRVIT 0xf53c +#define STB0899_PR_7_8 (0x01 << 5) +#define STB0899_OFFST_PR_7_8 5 +#define STB0899_WIDTH_PR_7_8 1 +#define STB0899_PR_6_7 (0x01 << 4) +#define STB0899_OFFST_PR_6_7 4 +#define STB0899_WIDTH_PR_6_7 1 +#define STB0899_PR_5_6 (0x01 << 3) +#define STB0899_OFFST_PR_5_6 3 +#define STB0899_WIDTH_PR_5_6 1 +#define STB0899_PR_3_4 (0x01 << 2) +#define STB0899_OFFST_PR_3_4 2 +#define STB0899_WIDTH_PR_3_4 1 +#define STB0899_PR_2_3 (0x01 << 1) +#define STB0899_OFFST_PR_2_3 1 +#define STB0899_WIDTH_PR_2_3 1 +#define STB0899_PR_1_2 (0x01 << 0) +#define STB0899_OFFST_PR_1_2 0 +#define STB0899_WIDTH_PR_1_2 1 + +#define STB0899_VITSYNC 0xf53d +#define STB0899_AM (0x01 << 7) +#define STB0899_OFFST_AM 7 +#define STB0899_WIDTH_AM 1 +#define STB0899_FREEZE (0x01 << 6) +#define STB0899_OFFST_FREEZE 6 +#define STB0899_WIDTH_FREEZE 1 +#define STB0899_SN_65536 (0x03 << 4) +#define STB0899_OFFST_SN_65536 4 +#define STB0899_WIDTH_SN_65536 2 +#define STB0899_SN_16384 (0x01 << 5) +#define STB0899_OFFST_SN_16384 5 +#define STB0899_WIDTH_SN_16384 1 +#define STB0899_SN_4096 (0x01 << 4) +#define STB0899_OFFST_SN_4096 4 +#define STB0899_WIDTH_SN_4096 1 +#define STB0899_SN_1024 (0x00 << 4) +#define STB0899_OFFST_SN_1024 4 +#define STB0899_WIDTH_SN_1024 0 +#define STB0899_TO_128 (0x03 << 2) +#define STB0899_OFFST_TO_128 2 +#define STB0899_WIDTH_TO_128 2 +#define STB0899_TO_64 (0x01 << 3) +#define STB0899_OFFST_TO_64 3 +#define STB0899_WIDTH_TO_64 1 +#define STB0899_TO_32 (0x01 << 2) +#define STB0899_OFFST_TO_32 2 +#define STB0899_WIDTH_TO_32 1 +#define STB0899_TO_16 (0x00 << 2) +#define STB0899_OFFST_TO_16 2 +#define STB0899_WIDTH_TO_16 0 +#define STB0899_HYST_128 (0x03 << 1) +#define STB0899_OFFST_HYST_128 1 +#define STB0899_WIDTH_HYST_128 2 +#define STB0899_HYST_64 (0x01 << 1) +#define STB0899_OFFST_HYST_64 1 +#define STB0899_WIDTH_HYST_64 1 +#define STB0899_HYST_32 (0x01 << 0) +#define STB0899_OFFST_HYST_32 0 +#define STB0899_WIDTH_HYST_32 1 +#define STB0899_HYST_16 (0x00 << 0) +#define STB0899_OFFST_HYST_16 0 +#define STB0899_WIDTH_HYST_16 0 + +#define STB0899_RSULC 0xf548 +#define STB0899_ULDIL_ON (0x01 << 7) +#define STB0899_OFFST_ULDIL_ON 7 +#define STB0899_WIDTH_ULDIL_ON 1 +#define STB0899_ULAUTO_ON (0x01 << 6) +#define STB0899_OFFST_ULAUTO_ON 6 +#define STB0899_WIDTH_ULAUTO_ON 1 +#define STB0899_ULRS_ON (0x01 << 5) +#define STB0899_OFFST_ULRS_ON 5 +#define STB0899_WIDTH_ULRS_ON 1 +#define STB0899_ULDESCRAM_ON (0x01 << 4) +#define STB0899_OFFST_ULDESCRAM_ON 4 +#define STB0899_WIDTH_ULDESCRAM_ON 1 +#define STB0899_UL_DISABLE (0x01 << 2) +#define STB0899_OFFST_UL_DISABLE 2 +#define STB0899_WIDTH_UL_DISABLE 1 +#define STB0899_NOFTHRESHOLD (0x01 << 0) +#define STB0899_OFFST_NOFTHRESHOLD 0 +#define STB0899_WIDTH_NOFTHRESHOLD 1 + +#define STB0899_RSLLC 0xf54a +#define STB0899_DEMAPVIT 0xf583 +#define STB0899_DEMAPVIT_RSVD (0x01 << 7) +#define STB0899_OFFST_DEMAPVIT_RSVD 7 +#define STB0899_WIDTH_DEMAPVIT_RSVD 1 +#define STB0899_DEMAPVIT_KDIVIDER (0x7f << 0) +#define STB0899_OFFST_DEMAPVIT_KDIVIDER 0 +#define STB0899_WIDTH_DEMAPVIT_KDIVIDER 7 + +#define STB0899_PLPARM 0xf58c +#define STB0899_VITMAPPING (0x07 << 5) +#define STB0899_OFFST_VITMAPPING 5 +#define STB0899_WIDTH_VITMAPPING 3 +#define STB0899_VITMAPPING_BPSK (0x01 << 5) +#define STB0899_OFFST_VITMAPPING_BPSK 5 +#define STB0899_WIDTH_VITMAPPING_BPSK 1 +#define STB0899_VITMAPPING_QPSK (0x00 << 5) +#define STB0899_OFFST_VITMAPPING_QPSK 5 +#define STB0899_WIDTH_VITMAPPING_QPSK 0 +#define STB0899_VITCURPUN (0x1f << 0) +#define STB0899_OFFST_VITCURPUN 0 +#define STB0899_WIDTH_VITCURPUN 5 +#define STB0899_VITCURPUN_1_2 (0x0d << 0) +#define STB0899_VITCURPUN_2_3 (0x12 << 0) +#define STB0899_VITCURPUN_3_4 (0x15 << 0) +#define STB0899_VITCURPUN_5_6 (0x18 << 0) +#define STB0899_VITCURPUN_6_7 (0x19 << 0) +#define STB0899_VITCURPUN_7_8 (0x1a << 0) + +/* S2 DEMOD */ +#define STB0899_OFF0_DMD_STATUS 0xf300 +#define STB0899_BASE_DMD_STATUS 0x00000000 +#define STB0899_IF_AGC_LOCK (0x01 << 8) +#define STB0899_OFFST_IF_AGC_LOCK 0 +#define STB0899_WIDTH_IF_AGC_LOCK 1 + +#define STB0899_OFF0_CRL_FREQ 0xf304 +#define STB0899_BASE_CRL_FREQ 0x00000000 +#define STB0899_CARR_FREQ (0x3fffffff << 0) +#define STB0899_OFFST_CARR_FREQ 0 +#define STB0899_WIDTH_CARR_FREQ 30 + +#define STB0899_OFF0_BTR_FREQ 0xf308 +#define STB0899_BASE_BTR_FREQ 0x00000000 +#define STB0899_BTR_FREQ (0xfffffff << 0) +#define STB0899_OFFST_BTR_FREQ 0 +#define STB0899_WIDTH_BTR_FREQ 28 + +#define STB0899_OFF0_IF_AGC_GAIN 0xf30c +#define STB0899_BASE_IF_AGC_GAIN 0x00000000 +#define STB0899_IF_AGC_GAIN (0x3fff < 0) +#define STB0899_OFFST_IF_AGC_GAIN 0 +#define STB0899_WIDTH_IF_AGC_GAIN 14 + +#define STB0899_OFF0_BB_AGC_GAIN 0xf310 +#define STB0899_BASE_BB_AGC_GAIN 0x00000000 +#define STB0899_BB_AGC_GAIN (0x3fff < 0) +#define STB0899_OFFST_BB_AGC_GAIN 0 +#define STB0899_WIDTH_BB_AGC_GAIN 14 + +#define STB0899_OFF0_DC_OFFSET 0xf314 +#define STB0899_BASE_DC_OFFSET 0x00000000 +#define STB0899_I (0xff < 8) +#define STB0899_OFFST_I 8 +#define STB0899_WIDTH_I 8 +#define STB0899_Q (0xff < 0) +#define STB0899_OFFST_Q 8 +#define STB0899_WIDTH_Q 8 + +#define STB0899_OFF0_DMD_CNTRL 0xf31c +#define STB0899_BASE_DMD_CNTRL 0x00000000 +#define STB0899_ADC0_PINS1IN (0x01 << 6) +#define STB0899_OFFST_ADC0_PINS1IN 6 +#define STB0899_WIDTH_ADC0_PINS1IN 1 +#define STB0899_IN2COMP1_OFFBIN0 (0x01 << 3) +#define STB0899_OFFST_IN2COMP1_OFFBIN0 3 +#define STB0899_WIDTH_IN2COMP1_OFFBIN0 1 +#define STB0899_DC_COMP (0x01 << 2) +#define STB0899_OFFST_DC_COMP 2 +#define STB0899_WIDTH_DC_COMP 1 +#define STB0899_MODMODE (0x03 << 0) +#define STB0899_OFFST_MODMODE 0 +#define STB0899_WIDTH_MODMODE 2 + +#define STB0899_OFF0_IF_AGC_CNTRL 0xf320 +#define STB0899_BASE_IF_AGC_CNTRL 0x00000000 +#define STB0899_IF_GAIN_INIT (0x3fff << 13) +#define STB0899_OFFST_IF_GAIN_INIT 13 +#define STB0899_WIDTH_IF_GAIN_INIT 14 +#define STB0899_IF_GAIN_SENSE (0x01 << 12) +#define STB0899_OFFST_IF_GAIN_SENSE 12 +#define STB0899_WIDTH_IF_GAIN_SENSE 1 +#define STB0899_IF_LOOP_GAIN (0x0f << 8) +#define STB0899_OFFST_IF_LOOP_GAIN 8 +#define STB0899_WIDTH_IF_LOOP_GAIN 4 +#define STB0899_IF_LD_GAIN_INIT (0x01 << 7) +#define STB0899_OFFST_IF_LD_GAIN_INIT 7 +#define STB0899_WIDTH_IF_LD_GAIN_INIT 1 +#define STB0899_IF_AGC_REF (0x7f << 0) +#define STB0899_OFFST_IF_AGC_REF 0 +#define STB0899_WIDTH_IF_AGC_REF 7 + +#define STB0899_OFF0_BB_AGC_CNTRL 0xf324 +#define STB0899_BASE_BB_AGC_CNTRL 0x00000000 +#define STB0899_BB_GAIN_INIT (0x3fff << 12) +#define STB0899_OFFST_BB_GAIN_INIT 12 +#define STB0899_WIDTH_BB_GAIN_INIT 14 +#define STB0899_BB_LOOP_GAIN (0x0f << 8) +#define STB0899_OFFST_BB_LOOP_GAIN 8 +#define STB0899_WIDTH_BB_LOOP_GAIN 4 +#define STB0899_BB_LD_GAIN_INIT (0x01 << 7) +#define STB0899_OFFST_BB_LD_GAIN_INIT 7 +#define STB0899_WIDTH_BB_LD_GAIN_INIT 1 +#define STB0899_BB_AGC_REF (0x7f << 0) +#define STB0899_OFFST_BB_AGC_REF 0 +#define STB0899_WIDTH_BB_AGC_REF 7 + +#define STB0899_OFF0_CRL_CNTRL 0xf328 +#define STB0899_BASE_CRL_CNTRL 0x00000000 +#define STB0899_CRL_LOCK_CLEAR (0x01 << 5) +#define STB0899_OFFST_CRL_LOCK_CLEAR 5 +#define STB0899_WIDTH_CRL_LOCK_CLEAR 1 +#define STB0899_CRL_SWPR_CLEAR (0x01 << 4) +#define STB0899_OFFST_CRL_SWPR_CLEAR 4 +#define STB0899_WIDTH_CRL_SWPR_CLEAR 1 +#define STB0899_CRL_SWP_ENA (0x01 << 3) +#define STB0899_OFFST_CRL_SWP_ENA 3 +#define STB0899_WIDTH_CRL_SWP_ENA 1 +#define STB0899_CRL_DET_SEL (0x01 << 2) +#define STB0899_OFFST_CRL_DET_SEL 2 +#define STB0899_WIDTH_CRL_DET_SEL 1 +#define STB0899_CRL_SENSE (0x01 << 1) +#define STB0899_OFFST_CRL_SENSE 1 +#define STB0899_WIDTH_CRL_SENSE 1 +#define STB0899_CRL_PHSERR_CLEAR (0x01 << 0) +#define STB0899_OFFST_CRL_PHSERR_CLEAR 0 +#define STB0899_WIDTH_CRL_PHSERR_CLEAR 1 + +#define STB0899_OFF0_CRL_PHS_INIT 0xf32c +#define STB0899_BASE_CRL_PHS_INIT 0x00000000 +#define STB0899_CRL_PHS_INIT_31 (0x1 << 30) +#define STB0899_OFFST_CRL_PHS_INIT_31 30 +#define STB0899_WIDTH_CRL_PHS_INIT_31 1 +#define STB0899_CRL_LD_INIT_PHASE (0x1 << 24) +#define STB0899_OFFST_CRL_LD_INIT_PHASE 24 +#define STB0899_WIDTH_CRL_LD_INIT_PHASE 1 +#define STB0899_CRL_INIT_PHASE (0xffffff << 0) +#define STB0899_OFFST_CRL_INIT_PHASE 0 +#define STB0899_WIDTH_CRL_INIT_PHASE 24 + +#define STB0899_OFF0_CRL_FREQ_INIT 0xf330 +#define STB0899_BASE_CRL_FREQ_INIT 0x00000000 +#define STB0899_CRL_FREQ_INIT_31 (0x1 << 30) +#define STB0899_OFFST_CRL_FREQ_INIT_31 30 +#define STB0899_WIDTH_CRL_FREQ_INIT_31 1 +#define STB0899_CRL_LD_FREQ_INIT (0x1 << 24) +#define STB0899_OFFST_CRL_LD_FREQ_INIT 24 +#define STB0899_WIDTH_CRL_LD_FREQ_INIT 1 +#define STB0899_CRL_FREQ_INIT (0xffffff << 0) +#define STB0899_OFFST_CRL_FREQ_INIT 0 +#define STB0899_WIDTH_CRL_FREQ_INIT 24 + +#define STB0899_OFF0_CRL_LOOP_GAIN 0xf334 +#define STB0899_BASE_CRL_LOOP_GAIN 0x00000000 +#define STB0899_KCRL2_RSHFT (0xf << 16) +#define STB0899_OFFST_KCRL2_RSHFT 16 +#define STB0899_WIDTH_KCRL2_RSHFT 4 +#define STB0899_KCRL1 (0xf << 12) +#define STB0899_OFFST_KCRL1 12 +#define STB0899_WIDTH_KCRL1 4 +#define STB0899_KCRL1_RSHFT (0xf << 8) +#define STB0899_OFFST_KCRL1_RSHFT 8 +#define STB0899_WIDTH_KCRL1_RSHFT 4 +#define STB0899_KCRL0 (0xf << 4) +#define STB0899_OFFST_KCRL0 4 +#define STB0899_WIDTH_KCRL0 4 +#define STB0899_KCRL0_RSHFT (0xf << 0) +#define STB0899_OFFST_KCRL0_RSHFT 0 +#define STB0899_WIDTH_KCRL0_RSHFT 4 + +#define STB0899_OFF0_CRL_NOM_FREQ 0xf338 +#define STB0899_BASE_CRL_NOM_FREQ 0x00000000 +#define STB0899_CRL_NOM_FREQ (0x3fffffff << 0) +#define STB0899_OFFST_CRL_NOM_FREQ 0 +#define STB0899_WIDTH_CRL_NOM_FREQ 30 + +#define STB0899_OFF0_CRL_SWP_RATE 0xf33c +#define STB0899_BASE_CRL_SWP_RATE 0x00000000 +#define STB0899_CRL_SWP_RATE (0x3fffffff << 0) +#define STB0899_OFFST_CRL_SWP_RATE 0 +#define STB0899_WIDTH_CRL_SWP_RATE 30 + +#define STB0899_OFF0_CRL_MAX_SWP 0xf340 +#define STB0899_BASE_CRL_MAX_SWP 0x00000000 +#define STB0899_CRL_MAX_SWP (0x3fffffff << 0) +#define STB0899_OFFST_CRL_MAX_SWP 0 +#define STB0899_WIDTH_CRL_MAX_SWP 30 + +#define STB0899_OFF0_CRL_LK_CNTRL 0xf344 +#define STB0899_BASE_CRL_LK_CNTRL 0x00000000 + +#define STB0899_OFF0_DECIM_CNTRL 0xf348 +#define STB0899_BASE_DECIM_CNTRL 0x00000000 +#define STB0899_BAND_LIMIT_B (0x01 << 5) +#define STB0899_OFFST_BAND_LIMIT_B 5 +#define STB0899_WIDTH_BAND_LIMIT_B 1 +#define STB0899_WIN_SEL (0x03 << 3) +#define STB0899_OFFST_WIN_SEL 3 +#define STB0899_WIDTH_WIN_SEL 2 +#define STB0899_DECIM_RATE (0x07 << 0) +#define STB0899_OFFST_DECIM_RATE 0 +#define STB0899_WIDTH_DECIM_RATE 3 + +#define STB0899_OFF0_BTR_CNTRL 0xf34c +#define STB0899_BASE_BTR_CNTRL 0x00000000 +#define STB0899_BTR_FREQ_CORR (0x7ff << 4) +#define STB0899_OFFST_BTR_FREQ_CORR 4 +#define STB0899_WIDTH_BTR_FREQ_CORR 11 +#define STB0899_BTR_CLR_LOCK (0x01 << 3) +#define STB0899_OFFST_BTR_CLR_LOCK 3 +#define STB0899_WIDTH_BTR_CLR_LOCK 1 +#define STB0899_BTR_SENSE (0x01 << 2) +#define STB0899_OFFST_BTR_SENSE 2 +#define STB0899_WIDTH_BTR_SENSE 1 +#define STB0899_BTR_ERR_ENA (0x01 << 1) +#define STB0899_OFFST_BTR_ERR_ENA 1 +#define STB0899_WIDTH_BTR_ERR_ENA 1 +#define STB0899_INTRP_PHS_SENSE (0x01 << 0) +#define STB0899_OFFST_INTRP_PHS_SENSE 0 +#define STB0899_WIDTH_INTRP_PHS_SENSE 1 + +#define STB0899_OFF0_BTR_LOOP_GAIN 0xf350 +#define STB0899_BASE_BTR_LOOP_GAIN 0x00000000 +#define STB0899_KBTR2_RSHFT (0x0f << 16) +#define STB0899_OFFST_KBTR2_RSHFT 16 +#define STB0899_WIDTH_KBTR2_RSHFT 4 +#define STB0899_KBTR1 (0x0f << 12) +#define STB0899_OFFST_KBTR1 12 +#define STB0899_WIDTH_KBTR1 4 +#define STB0899_KBTR1_RSHFT (0x0f << 8) +#define STB0899_OFFST_KBTR1_RSHFT 8 +#define STB0899_WIDTH_KBTR1_RSHFT 4 +#define STB0899_KBTR0 (0x0f << 4) +#define STB0899_OFFST_KBTR0 4 +#define STB0899_WIDTH_KBTR0 4 +#define STB0899_KBTR0_RSHFT (0x0f << 0) +#define STB0899_OFFST_KBTR0_RSHFT 0 +#define STB0899_WIDTH_KBTR0_RSHFT 4 + +#define STB0899_OFF0_BTR_PHS_INIT 0xf354 +#define STB0899_BASE_BTR_PHS_INIT 0x00000000 +#define STB0899_BTR_LD_PHASE_INIT (0x01 << 28) +#define STB0899_OFFST_BTR_LD_PHASE_INIT 28 +#define STB0899_WIDTH_BTR_LD_PHASE_INIT 1 +#define STB0899_BTR_INIT_PHASE (0xfffffff << 0) +#define STB0899_OFFST_BTR_INIT_PHASE 0 +#define STB0899_WIDTH_BTR_INIT_PHASE 28 + +#define STB0899_OFF0_BTR_FREQ_INIT 0xf358 +#define STB0899_BASE_BTR_FREQ_INIT 0x00000000 +#define STB0899_BTR_LD_FREQ_INIT (1 << 28) +#define STB0899_OFFST_BTR_LD_FREQ_INIT 28 +#define STB0899_WIDTH_BTR_LD_FREQ_INIT 1 +#define STB0899_BTR_FREQ_INIT (0xfffffff << 0) +#define STB0899_OFFST_BTR_FREQ_INIT 0 +#define STB0899_WIDTH_BTR_FREQ_INIT 28 + +#define STB0899_OFF0_BTR_NOM_FREQ 0xf35c +#define STB0899_BASE_BTR_NOM_FREQ 0x00000000 +#define STB0899_BTR_NOM_FREQ (0xfffffff << 0) +#define STB0899_OFFST_BTR_NOM_FREQ 0 +#define STB0899_WIDTH_BTR_NOM_FREQ 28 + +#define STB0899_OFF0_BTR_LK_CNTRL 0xf360 +#define STB0899_BASE_BTR_LK_CNTRL 0x00000000 +#define STB0899_BTR_MIN_ENERGY (0x0f << 24) +#define STB0899_OFFST_BTR_MIN_ENERGY 24 +#define STB0899_WIDTH_BTR_MIN_ENERGY 4 +#define STB0899_BTR_LOCK_TH_LO (0xff << 16) +#define STB0899_OFFST_BTR_LOCK_TH_LO 16 +#define STB0899_WIDTH_BTR_LOCK_TH_LO 8 +#define STB0899_BTR_LOCK_TH_HI (0xff << 8) +#define STB0899_OFFST_BTR_LOCK_TH_HI 8 +#define STB0899_WIDTH_BTR_LOCK_TH_HI 8 +#define STB0899_BTR_LOCK_GAIN (0x03 << 6) +#define STB0899_OFFST_BTR_LOCK_GAIN 6 +#define STB0899_WIDTH_BTR_LOCK_GAIN 2 +#define STB0899_BTR_LOCK_LEAK (0x3f << 0) +#define STB0899_OFFST_BTR_LOCK_LEAK 0 +#define STB0899_WIDTH_BTR_LOCK_LEAK 6 + +#define STB0899_OFF0_DECN_CNTRL 0xf364 +#define STB0899_BASE_DECN_CNTRL 0x00000000 + +#define STB0899_OFF0_TP_CNTRL 0xf368 +#define STB0899_BASE_TP_CNTRL 0x00000000 + +#define STB0899_OFF0_TP_BUF_STATUS 0xf36c +#define STB0899_BASE_TP_BUF_STATUS 0x00000000 +#define STB0899_TP_BUFFER_FULL (1 << 0) + +#define STB0899_OFF0_DC_ESTIM 0xf37c +#define STB0899_BASE_DC_ESTIM 0x0000 +#define STB0899_I_DC_ESTIMATE (0xff << 8) +#define STB0899_OFFST_I_DC_ESTIMATE 8 +#define STB0899_WIDTH_I_DC_ESTIMATE 8 +#define STB0899_Q_DC_ESTIMATE (0xff << 0) +#define STB0899_OFFST_Q_DC_ESTIMATE 0 +#define STB0899_WIDTH_Q_DC_ESTIMATE 8 + +#define STB0899_OFF0_FLL_CNTRL 0xf310 +#define STB0899_BASE_FLL_CNTRL 0x00000020 +#define STB0899_CRL_FLL_ACC (0x01 << 4) +#define STB0899_OFFST_CRL_FLL_ACC 4 +#define STB0899_WIDTH_CRL_FLL_ACC 1 +#define STB0899_FLL_AVG_PERIOD (0x0f << 0) +#define STB0899_OFFST_FLL_AVG_PERIOD 0 +#define STB0899_WIDTH_FLL_AVG_PERIOD 4 + +#define STB0899_OFF0_FLL_FREQ_WD 0xf314 +#define STB0899_BASE_FLL_FREQ_WD 0x00000020 +#define STB0899_FLL_FREQ_WD (0xffffffff << 0) +#define STB0899_OFFST_FLL_FREQ_WD 0 +#define STB0899_WIDTH_FLL_FREQ_WD 32 + +#define STB0899_OFF0_ANTI_ALIAS_SEL 0xf358 +#define STB0899_BASE_ANTI_ALIAS_SEL 0x00000020 +#define STB0899_ANTI_ALIAS_SELB (0x03 << 0) +#define STB0899_OFFST_ANTI_ALIAS_SELB 0 +#define STB0899_WIDTH_ANTI_ALIAS_SELB 2 + +#define STB0899_OFF0_RRC_ALPHA 0xf35c +#define STB0899_BASE_RRC_ALPHA 0x00000020 +#define STB0899_RRC_ALPHA (0x03 << 0) +#define STB0899_OFFST_RRC_ALPHA 0 +#define STB0899_WIDTH_RRC_ALPHA 2 + +#define STB0899_OFF0_DC_ADAPT_LSHFT 0xf360 +#define STB0899_BASE_DC_ADAPT_LSHFT 0x00000020 +#define STB0899_DC_ADAPT_LSHFT (0x077 << 0) +#define STB0899_OFFST_DC_ADAPT_LSHFT 0 +#define STB0899_WIDTH_DC_ADAPT_LSHFT 3 + +#define STB0899_OFF0_IMB_OFFSET 0xf364 +#define STB0899_BASE_IMB_OFFSET 0x00000020 +#define STB0899_PHS_IMB_COMP (0xff << 8) +#define STB0899_OFFST_PHS_IMB_COMP 8 +#define STB0899_WIDTH_PHS_IMB_COMP 8 +#define STB0899_AMPL_IMB_COMP (0xff << 0) +#define STB0899_OFFST_AMPL_IMB_COMP 0 +#define STB0899_WIDTH_AMPL_IMB_COMP 8 + +#define STB0899_OFF0_IMB_ESTIMATE 0xf368 +#define STB0899_BASE_IMB_ESTIMATE 0x00000020 +#define STB0899_PHS_IMB_ESTIMATE (0xff << 8) +#define STB0899_OFFST_PHS_IMB_ESTIMATE 8 +#define STB0899_WIDTH_PHS_IMB_ESTIMATE 8 +#define STB0899_AMPL_IMB_ESTIMATE (0xff << 0) +#define STB0899_OFFST_AMPL_IMB_ESTIMATE 0 +#define STB0899_WIDTH_AMPL_IMB_ESTIMATE 8 + +#define STB0899_OFF0_IMB_CNTRL 0xf36c +#define STB0899_BASE_IMB_CNTRL 0x00000020 +#define STB0899_PHS_ADAPT_LSHFT (0x07 << 4) +#define STB0899_OFFST_PHS_ADAPT_LSHFT 4 +#define STB0899_WIDTH_PHS_ADAPT_LSHFT 3 +#define STB0899_AMPL_ADAPT_LSHFT (0x07 << 1) +#define STB0899_OFFST_AMPL_ADAPT_LSHFT 1 +#define STB0899_WIDTH_AMPL_ADAPT_LSHFT 3 +#define STB0899_IMB_COMP (0x01 << 0) +#define STB0899_OFFST_IMB_COMP 0 +#define STB0899_WIDTH_IMB_COMP 1 + +#define STB0899_OFF0_IF_AGC_CNTRL2 0xf374 +#define STB0899_BASE_IF_AGC_CNTRL2 0x00000020 +#define STB0899_IF_AGC_LOCK_TH (0xff << 11) +#define STB0899_OFFST_IF_AGC_LOCK_TH 11 +#define STB0899_WIDTH_IF_AGC_LOCK_TH 8 +#define STB0899_IF_AGC_SD_DIV (0xff << 3) +#define STB0899_OFFST_IF_AGC_SD_DIV 3 +#define STB0899_WIDTH_IF_AGC_SD_DIV 8 +#define STB0899_IF_AGC_DUMP_PER (0x07 << 0) +#define STB0899_OFFST_IF_AGC_DUMP_PER 0 +#define STB0899_WIDTH_IF_AGC_DUMP_PER 3 + +#define STB0899_OFF0_DMD_CNTRL2 0xf378 +#define STB0899_BASE_DMD_CNTRL2 0x00000020 +#define STB0899_SPECTRUM_INVERT (0x01 << 2) +#define STB0899_OFFST_SPECTRUM_INVERT 2 +#define STB0899_WIDTH_SPECTRUM_INVERT 1 +#define STB0899_AGC_MODE (0x01 << 1) +#define STB0899_OFFST_AGC_MODE 1 +#define STB0899_WIDTH_AGC_MODE 1 +#define STB0899_CRL_FREQ_ADJ (0x01 << 0) +#define STB0899_OFFST_CRL_FREQ_ADJ 0 +#define STB0899_WIDTH_CRL_FREQ_ADJ 1 + +#define STB0899_OFF0_TP_BUFFER 0xf300 +#define STB0899_BASE_TP_BUFFER 0x00000040 +#define STB0899_TP_BUFFER_IN (0xffff << 0) +#define STB0899_OFFST_TP_BUFFER_IN 0 +#define STB0899_WIDTH_TP_BUFFER_IN 16 + +#define STB0899_OFF0_TP_BUFFER1 0xf304 +#define STB0899_BASE_TP_BUFFER1 0x00000040 +#define STB0899_OFF0_TP_BUFFER2 0xf308 +#define STB0899_BASE_TP_BUFFER2 0x00000040 +#define STB0899_OFF0_TP_BUFFER3 0xf30c +#define STB0899_BASE_TP_BUFFER3 0x00000040 +#define STB0899_OFF0_TP_BUFFER4 0xf310 +#define STB0899_BASE_TP_BUFFER4 0x00000040 +#define STB0899_OFF0_TP_BUFFER5 0xf314 +#define STB0899_BASE_TP_BUFFER5 0x00000040 +#define STB0899_OFF0_TP_BUFFER6 0xf318 +#define STB0899_BASE_TP_BUFFER6 0x00000040 +#define STB0899_OFF0_TP_BUFFER7 0xf31c +#define STB0899_BASE_TP_BUFFER7 0x00000040 +#define STB0899_OFF0_TP_BUFFER8 0xf320 +#define STB0899_BASE_TP_BUFFER8 0x00000040 +#define STB0899_OFF0_TP_BUFFER9 0xf324 +#define STB0899_BASE_TP_BUFFER9 0x00000040 +#define STB0899_OFF0_TP_BUFFER10 0xf328 +#define STB0899_BASE_TP_BUFFER10 0x00000040 +#define STB0899_OFF0_TP_BUFFER11 0xf32c +#define STB0899_BASE_TP_BUFFER11 0x00000040 +#define STB0899_OFF0_TP_BUFFER12 0xf330 +#define STB0899_BASE_TP_BUFFER12 0x00000040 +#define STB0899_OFF0_TP_BUFFER13 0xf334 +#define STB0899_BASE_TP_BUFFER13 0x00000040 +#define STB0899_OFF0_TP_BUFFER14 0xf338 +#define STB0899_BASE_TP_BUFFER14 0x00000040 +#define STB0899_OFF0_TP_BUFFER15 0xf33c +#define STB0899_BASE_TP_BUFFER15 0x00000040 +#define STB0899_OFF0_TP_BUFFER16 0xf340 +#define STB0899_BASE_TP_BUFFER16 0x00000040 +#define STB0899_OFF0_TP_BUFFER17 0xf344 +#define STB0899_BASE_TP_BUFFER17 0x00000040 +#define STB0899_OFF0_TP_BUFFER18 0xf348 +#define STB0899_BASE_TP_BUFFER18 0x00000040 +#define STB0899_OFF0_TP_BUFFER19 0xf34c +#define STB0899_BASE_TP_BUFFER19 0x00000040 +#define STB0899_OFF0_TP_BUFFER20 0xf350 +#define STB0899_BASE_TP_BUFFER20 0x00000040 +#define STB0899_OFF0_TP_BUFFER21 0xf354 +#define STB0899_BASE_TP_BUFFER21 0x00000040 +#define STB0899_OFF0_TP_BUFFER22 0xf358 +#define STB0899_BASE_TP_BUFFER22 0x00000040 +#define STB0899_OFF0_TP_BUFFER23 0xf35c +#define STB0899_BASE_TP_BUFFER23 0x00000040 +#define STB0899_OFF0_TP_BUFFER24 0xf360 +#define STB0899_BASE_TP_BUFFER24 0x00000040 +#define STB0899_OFF0_TP_BUFFER25 0xf364 +#define STB0899_BASE_TP_BUFFER25 0x00000040 +#define STB0899_OFF0_TP_BUFFER26 0xf368 +#define STB0899_BASE_TP_BUFFER26 0x00000040 +#define STB0899_OFF0_TP_BUFFER27 0xf36c +#define STB0899_BASE_TP_BUFFER27 0x00000040 +#define STB0899_OFF0_TP_BUFFER28 0xf370 +#define STB0899_BASE_TP_BUFFER28 0x00000040 +#define STB0899_OFF0_TP_BUFFER29 0xf374 +#define STB0899_BASE_TP_BUFFER29 0x00000040 +#define STB0899_OFF0_TP_BUFFER30 0xf378 +#define STB0899_BASE_TP_BUFFER30 0x00000040 +#define STB0899_OFF0_TP_BUFFER31 0xf37c +#define STB0899_BASE_TP_BUFFER31 0x00000040 +#define STB0899_OFF0_TP_BUFFER32 0xf300 +#define STB0899_BASE_TP_BUFFER32 0x00000060 +#define STB0899_OFF0_TP_BUFFER33 0xf304 +#define STB0899_BASE_TP_BUFFER33 0x00000060 +#define STB0899_OFF0_TP_BUFFER34 0xf308 +#define STB0899_BASE_TP_BUFFER34 0x00000060 +#define STB0899_OFF0_TP_BUFFER35 0xf30c +#define STB0899_BASE_TP_BUFFER35 0x00000060 +#define STB0899_OFF0_TP_BUFFER36 0xf310 +#define STB0899_BASE_TP_BUFFER36 0x00000060 +#define STB0899_OFF0_TP_BUFFER37 0xf314 +#define STB0899_BASE_TP_BUFFER37 0x00000060 +#define STB0899_OFF0_TP_BUFFER38 0xf318 +#define STB0899_BASE_TP_BUFFER38 0x00000060 +#define STB0899_OFF0_TP_BUFFER39 0xf31c +#define STB0899_BASE_TP_BUFFER39 0x00000060 +#define STB0899_OFF0_TP_BUFFER40 0xf320 +#define STB0899_BASE_TP_BUFFER40 0x00000060 +#define STB0899_OFF0_TP_BUFFER41 0xf324 +#define STB0899_BASE_TP_BUFFER41 0x00000060 +#define STB0899_OFF0_TP_BUFFER42 0xf328 +#define STB0899_BASE_TP_BUFFER42 0x00000060 +#define STB0899_OFF0_TP_BUFFER43 0xf32c +#define STB0899_BASE_TP_BUFFER43 0x00000060 +#define STB0899_OFF0_TP_BUFFER44 0xf330 +#define STB0899_BASE_TP_BUFFER44 0x00000060 +#define STB0899_OFF0_TP_BUFFER45 0xf334 +#define STB0899_BASE_TP_BUFFER45 0x00000060 +#define STB0899_OFF0_TP_BUFFER46 0xf338 +#define STB0899_BASE_TP_BUFFER46 0x00000060 +#define STB0899_OFF0_TP_BUFFER47 0xf33c +#define STB0899_BASE_TP_BUFFER47 0x00000060 +#define STB0899_OFF0_TP_BUFFER48 0xf340 +#define STB0899_BASE_TP_BUFFER48 0x00000060 +#define STB0899_OFF0_TP_BUFFER49 0xf344 +#define STB0899_BASE_TP_BUFFER49 0x00000060 +#define STB0899_OFF0_TP_BUFFER50 0xf348 +#define STB0899_BASE_TP_BUFFER50 0x00000060 +#define STB0899_OFF0_TP_BUFFER51 0xf34c +#define STB0899_BASE_TP_BUFFER51 0x00000060 +#define STB0899_OFF0_TP_BUFFER52 0xf350 +#define STB0899_BASE_TP_BUFFER52 0x00000060 +#define STB0899_OFF0_TP_BUFFER53 0xf354 +#define STB0899_BASE_TP_BUFFER53 0x00000060 +#define STB0899_OFF0_TP_BUFFER54 0xf358 +#define STB0899_BASE_TP_BUFFER54 0x00000060 +#define STB0899_OFF0_TP_BUFFER55 0xf35c +#define STB0899_BASE_TP_BUFFER55 0x00000060 +#define STB0899_OFF0_TP_BUFFER56 0xf360 +#define STB0899_BASE_TP_BUFFER56 0x00000060 +#define STB0899_OFF0_TP_BUFFER57 0xf364 +#define STB0899_BASE_TP_BUFFER57 0x00000060 +#define STB0899_OFF0_TP_BUFFER58 0xf368 +#define STB0899_BASE_TP_BUFFER58 0x00000060 +#define STB0899_OFF0_TP_BUFFER59 0xf36c +#define STB0899_BASE_TP_BUFFER59 0x00000060 +#define STB0899_OFF0_TP_BUFFER60 0xf370 +#define STB0899_BASE_TP_BUFFER60 0x00000060 +#define STB0899_OFF0_TP_BUFFER61 0xf374 +#define STB0899_BASE_TP_BUFFER61 0x00000060 +#define STB0899_OFF0_TP_BUFFER62 0xf378 +#define STB0899_BASE_TP_BUFFER62 0x00000060 +#define STB0899_OFF0_TP_BUFFER63 0xf37c +#define STB0899_BASE_TP_BUFFER63 0x00000060 + +#define STB0899_OFF0_RESET_CNTRL 0xf300 +#define STB0899_BASE_RESET_CNTRL 0x00000400 +#define STB0899_DVBS2_RESET (0x01 << 0) +#define STB0899_OFFST_DVBS2_RESET 0 +#define STB0899_WIDTH_DVBS2_RESET 1 + +#define STB0899_OFF0_ACM_ENABLE 0xf304 +#define STB0899_BASE_ACM_ENABLE 0x00000400 +#define STB0899_ACM_ENABLE 1 + +#define STB0899_OFF0_DESCR_CNTRL 0xf30c +#define STB0899_BASE_DESCR_CNTRL 0x00000400 +#define STB0899_OFFST_DESCR_CNTRL 0 +#define STB0899_WIDTH_DESCR_CNTRL 16 + +#define STB0899_OFF0_UWP_CNTRL1 0xf320 +#define STB0899_BASE_UWP_CNTRL1 0x00000400 +#define STB0899_UWP_TH_SOF (0x7fff << 11) +#define STB0899_OFFST_UWP_TH_SOF 11 +#define STB0899_WIDTH_UWP_TH_SOF 15 +#define STB0899_UWP_ESN0_QUANT (0xff << 3) +#define STB0899_OFFST_UWP_ESN0_QUANT 3 +#define STB0899_WIDTH_UWP_ESN0_QUANT 8 +#define STB0899_UWP_ESN0_AVE (0x03 << 1) +#define STB0899_OFFST_UWP_ESN0_AVE 1 +#define STB0899_WIDTH_UWP_ESN0_AVE 2 +#define STB0899_UWP_START (0x01 << 0) +#define STB0899_OFFST_UWP_START 0 +#define STB0899_WIDTH_UWP_START 1 + +#define STB0899_OFF0_UWP_CNTRL2 0xf324 +#define STB0899_BASE_UWP_CNTRL2 0x00000400 +#define STB0899_UWP_MISS_TH (0xff << 16) +#define STB0899_OFFST_UWP_MISS_TH 16 +#define STB0899_WIDTH_UWP_MISS_TH 8 +#define STB0899_FE_FINE_TRK (0xff << 8) +#define STB0899_OFFST_FE_FINE_TRK 8 +#define STB0899_WIDTH_FE_FINE_TRK 8 +#define STB0899_FE_COARSE_TRK (0xff << 0) +#define STB0899_OFFST_FE_COARSE_TRK 0 +#define STB0899_WIDTH_FE_COARSE_TRK 8 + +#define STB0899_OFF0_UWP_STAT1 0xf328 +#define STB0899_BASE_UWP_STAT1 0x00000400 +#define STB0899_UWP_STATE (0x03ff << 15) +#define STB0899_OFFST_UWP_STATE 15 +#define STB0899_WIDTH_UWP_STATE 10 +#define STB0899_UW_MAX_PEAK (0x7fff << 0) +#define STB0899_OFFST_UW_MAX_PEAK 0 +#define STB0899_WIDTH_UW_MAX_PEAK 15 + +#define STB0899_OFF0_UWP_STAT2 0xf32c +#define STB0899_BASE_UWP_STAT2 0x00000400 +#define STB0899_ESNO_EST (0x07ffff << 7) +#define STB0899_OFFST_ESN0_EST 7 +#define STB0899_WIDTH_ESN0_EST 19 +#define STB0899_UWP_DECODE_MOD (0x7f << 0) +#define STB0899_OFFST_UWP_DECODE_MOD 0 +#define STB0899_WIDTH_UWP_DECODE_MOD 7 + +#define STB0899_OFF0_DMD_CORE_ID 0xf334 +#define STB0899_BASE_DMD_CORE_ID 0x00000400 +#define STB0899_CORE_ID (0xffffffff << 0) +#define STB0899_OFFST_CORE_ID 0 +#define STB0899_WIDTH_CORE_ID 32 + +#define STB0899_OFF0_DMD_VERSION_ID 0xf33c +#define STB0899_BASE_DMD_VERSION_ID 0x00000400 +#define STB0899_VERSION_ID (0xff << 0) +#define STB0899_OFFST_VERSION_ID 0 +#define STB0899_WIDTH_VERSION_ID 8 + +#define STB0899_OFF0_DMD_STAT2 0xf340 +#define STB0899_BASE_DMD_STAT2 0x00000400 +#define STB0899_CSM_LOCK (0x01 << 1) +#define STB0899_OFFST_CSM_LOCK 1 +#define STB0899_WIDTH_CSM_LOCK 1 +#define STB0899_UWP_LOCK (0x01 << 0) +#define STB0899_OFFST_UWP_LOCK 0 +#define STB0899_WIDTH_UWP_LOCK 1 + +#define STB0899_OFF0_FREQ_ADJ_SCALE 0xf344 +#define STB0899_BASE_FREQ_ADJ_SCALE 0x00000400 +#define STB0899_FREQ_ADJ_SCALE (0x0fff << 0) +#define STB0899_OFFST_FREQ_ADJ_SCALE 0 +#define STB0899_WIDTH_FREQ_ADJ_SCALE 12 + +#define STB0899_OFF0_UWP_CNTRL3 0xf34c +#define STB0899_BASE_UWP_CNTRL3 0x00000400 +#define STB0899_UWP_TH_TRACK (0x7fff << 15) +#define STB0899_OFFST_UWP_TH_TRACK 15 +#define STB0899_WIDTH_UWP_TH_TRACK 15 +#define STB0899_UWP_TH_ACQ (0x7fff << 0) +#define STB0899_OFFST_UWP_TH_ACQ 0 +#define STB0899_WIDTH_UWP_TH_ACQ 15 + +#define STB0899_OFF0_SYM_CLK_SEL 0xf350 +#define STB0899_BASE_SYM_CLK_SEL 0x00000400 +#define STB0899_SYM_CLK_SEL (0x03 << 0) +#define STB0899_OFFST_SYM_CLK_SEL 0 +#define STB0899_WIDTH_SYM_CLK_SEL 2 + +#define STB0899_OFF0_SOF_SRCH_TO 0xf354 +#define STB0899_BASE_SOF_SRCH_TO 0x00000400 +#define STB0899_SOF_SEARCH_TIMEOUT (0x3fffff << 0) +#define STB0899_OFFST_SOF_SEARCH_TIMEOUT 0 +#define STB0899_WIDTH_SOF_SEARCH_TIMEOUT 22 + +#define STB0899_OFF0_ACQ_CNTRL1 0xf358 +#define STB0899_BASE_ACQ_CNTRL1 0x00000400 +#define STB0899_FE_FINE_ACQ (0xff << 8) +#define STB0899_OFFST_FE_FINE_ACQ 8 +#define STB0899_WIDTH_FE_FINE_ACQ 8 +#define STB0899_FE_COARSE_ACQ (0xff << 0) +#define STB0899_OFFST_FE_COARSE_ACQ 0 +#define STB0899_WIDTH_FE_COARSE_ACQ 8 + +#define STB0899_OFF0_ACQ_CNTRL2 0xf35c +#define STB0899_BASE_ACQ_CNTRL2 0x00000400 +#define STB0899_ZIGZAG (0x01 << 25) +#define STB0899_OFFST_ZIGZAG 25 +#define STB0899_WIDTH_ZIGZAG 1 +#define STB0899_NUM_STEPS (0xff << 17) +#define STB0899_OFFST_NUM_STEPS 17 +#define STB0899_WIDTH_NUM_STEPS 8 +#define STB0899_FREQ_STEPSIZE (0x1ffff << 0) +#define STB0899_OFFST_FREQ_STEPSIZE 0 +#define STB0899_WIDTH_FREQ_STEPSIZE 17 + +#define STB0899_OFF0_ACQ_CNTRL3 0xf360 +#define STB0899_BASE_ACQ_CNTRL3 0x00000400 +#define STB0899_THRESHOLD_SCL (0x3f << 23) +#define STB0899_OFFST_THRESHOLD_SCL 23 +#define STB0899_WIDTH_THRESHOLD_SCL 6 +#define STB0899_UWP_TH_SRCH (0x7fff << 8) +#define STB0899_OFFST_UWP_TH_SRCH 8 +#define STB0899_WIDTH_UWP_TH_SRCH 15 +#define STB0899_AUTO_REACQUIRE (0x01 << 7) +#define STB0899_OFFST_AUTO_REACQUIRE 7 +#define STB0899_WIDTH_AUTO_REACQUIRE 1 +#define STB0899_TRACK_LOCK_SEL (0x01 << 6) +#define STB0899_OFFST_TRACK_LOCK_SEL 6 +#define STB0899_WIDTH_TRACK_LOCK_SEL 1 +#define STB0899_ACQ_SEARCH_MODE (0x03 << 4) +#define STB0899_OFFST_ACQ_SEARCH_MODE 4 +#define STB0899_WIDTH_ACQ_SEARCH_MODE 2 +#define STB0899_CONFIRM_FRAMES (0x0f << 0) +#define STB0899_OFFST_CONFIRM_FRAMES 0 +#define STB0899_WIDTH_CONFIRM_FRAMES 4 + +#define STB0899_OFF0_FE_SETTLE 0xf364 +#define STB0899_BASE_FE_SETTLE 0x00000400 +#define STB0899_SETTLING_TIME (0x3fffff << 0) +#define STB0899_OFFST_SETTLING_TIME 0 +#define STB0899_WIDTH_SETTLING_TIME 22 + +#define STB0899_OFF0_AC_DWELL 0xf368 +#define STB0899_BASE_AC_DWELL 0x00000400 +#define STB0899_DWELL_TIME (0x3fffff << 0) +#define STB0899_OFFST_DWELL_TIME 0 +#define STB0899_WIDTH_DWELL_TIME 22 + +#define STB0899_OFF0_ACQUIRE_TRIG 0xf36c +#define STB0899_BASE_ACQUIRE_TRIG 0x00000400 +#define STB0899_ACQUIRE (0x01 << 0) +#define STB0899_OFFST_ACQUIRE 0 +#define STB0899_WIDTH_ACQUIRE 1 + +#define STB0899_OFF0_LOCK_LOST 0xf370 +#define STB0899_BASE_LOCK_LOST 0x00000400 +#define STB0899_LOCK_LOST (0x01 << 0) +#define STB0899_OFFST_LOCK_LOST 0 +#define STB0899_WIDTH_LOCK_LOST 1 + +#define STB0899_OFF0_ACQ_STAT1 0xf374 +#define STB0899_BASE_ACQ_STAT1 0x00000400 +#define STB0899_STEP_FREQ (0x1fffff << 11) +#define STB0899_OFFST_STEP_FREQ 11 +#define STB0899_WIDTH_STEP_FREQ 21 +#define STB0899_ACQ_STATE (0x07 << 8) +#define STB0899_OFFST_ACQ_STATE 8 +#define STB0899_WIDTH_ACQ_STATE 3 +#define STB0899_UW_DETECT_COUNT (0xff << 0) +#define STB0899_OFFST_UW_DETECT_COUNT 0 +#define STB0899_WIDTH_UW_DETECT_COUNT 8 + +#define STB0899_OFF0_ACQ_TIMEOUT 0xf378 +#define STB0899_BASE_ACQ_TIMEOUT 0x00000400 +#define STB0899_ACQ_TIMEOUT (0x3fffff << 0) +#define STB0899_OFFST_ACQ_TIMEOUT 0 +#define STB0899_WIDTH_ACQ_TIMEOUT 22 + +#define STB0899_OFF0_ACQ_TIME 0xf37c +#define STB0899_BASE_ACQ_TIME 0x00000400 +#define STB0899_ACQ_TIME_SYM (0xffffff << 0) +#define STB0899_OFFST_ACQ_TIME_SYM 0 +#define STB0899_WIDTH_ACQ_TIME_SYM 24 + +#define STB0899_OFF0_FINAL_AGC_CNTRL 0xf308 +#define STB0899_BASE_FINAL_AGC_CNTRL 0x00000440 +#define STB0899_FINAL_GAIN_INIT (0x3fff << 12) +#define STB0899_OFFST_FINAL_GAIN_INIT 12 +#define STB0899_WIDTH_FINAL_GAIN_INIT 14 +#define STB0899_FINAL_LOOP_GAIN (0x0f << 8) +#define STB0899_OFFST_FINAL_LOOP_GAIN 8 +#define STB0899_WIDTH_FINAL_LOOP_GAIN 4 +#define STB0899_FINAL_LD_GAIN_INIT (0x01 << 7) +#define STB0899_OFFST_FINAL_LD_GAIN_INIT 7 +#define STB0899_WIDTH_FINAL_LD_GAIN_INIT 1 +#define STB0899_FINAL_AGC_REF (0x7f << 0) +#define STB0899_OFFST_FINAL_AGC_REF 0 +#define STB0899_WIDTH_FINAL_AGC_REF 7 + +#define STB0899_OFF0_FINAL_AGC_GAIN 0xf30c +#define STB0899_BASE_FINAL_AGC_GAIN 0x00000440 +#define STB0899_FINAL_AGC_GAIN (0x3fff << 0) +#define STB0899_OFFST_FINAL_AGC_GAIN 0 +#define STB0899_WIDTH_FINAL_AGC_GAIN 14 + +#define STB0899_OFF0_EQUALIZER_INIT 0xf310 +#define STB0899_BASE_EQUALIZER_INIT 0x00000440 +#define STB0899_EQ_SRST (0x01 << 1) +#define STB0899_OFFST_EQ_SRST 1 +#define STB0899_WIDTH_EQ_SRST 1 +#define STB0899_EQ_INIT (0x01 << 0) +#define STB0899_OFFST_EQ_INIT 0 +#define STB0899_WIDTH_EQ_INIT 1 + +#define STB0899_OFF0_EQ_CNTRL 0xf314 +#define STB0899_BASE_EQ_CNTRL 0x00000440 +#define STB0899_EQ_ADAPT_MODE (0x01 << 18) +#define STB0899_OFFST_EQ_ADAPT_MODE 18 +#define STB0899_WIDTH_EQ_ADAPT_MODE 1 +#define STB0899_EQ_DELAY (0x0f << 14) +#define STB0899_OFFST_EQ_DELAY 14 +#define STB0899_WIDTH_EQ_DELAY 4 +#define STB0899_EQ_QUANT_LEVEL (0xff << 6) +#define STB0899_OFFST_EQ_QUANT_LEVEL 6 +#define STB0899_WIDTH_EQ_QUANT_LEVEL 8 +#define STB0899_EQ_DISABLE_UPDATE (0x01 << 5) +#define STB0899_OFFST_EQ_DISABLE_UPDATE 5 +#define STB0899_WIDTH_EQ_DISABLE_UPDATE 1 +#define STB0899_EQ_BYPASS (0x01 << 4) +#define STB0899_OFFST_EQ_BYPASS 4 +#define STB0899_WIDTH_EQ_BYPASS 1 +#define STB0899_EQ_SHIFT (0x0f << 0) +#define STB0899_OFFST_EQ_SHIFT 0 +#define STB0899_WIDTH_EQ_SHIFT 4 + +#define STB0899_OFF0_EQ_I_INIT_COEFF_0 0xf320 +#define STB0899_OFF1_EQ_I_INIT_COEFF_1 0xf324 +#define STB0899_OFF2_EQ_I_INIT_COEFF_2 0xf328 +#define STB0899_OFF3_EQ_I_INIT_COEFF_3 0xf32c +#define STB0899_OFF4_EQ_I_INIT_COEFF_4 0xf330 +#define STB0899_OFF5_EQ_I_INIT_COEFF_5 0xf334 +#define STB0899_OFF6_EQ_I_INIT_COEFF_6 0xf338 +#define STB0899_OFF7_EQ_I_INIT_COEFF_7 0xf33c +#define STB0899_OFF8_EQ_I_INIT_COEFF_8 0xf340 +#define STB0899_OFF9_EQ_I_INIT_COEFF_9 0xf344 +#define STB0899_OFFa_EQ_I_INIT_COEFF_10 0xf348 +#define STB0899_BASE_EQ_I_INIT_COEFF_N 0x00000440 +#define STB0899_EQ_I_INIT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_I_INIT_COEFF_N 0 +#define STB0899_WIDTH_EQ_I_INIT_COEFF_N 12 + +#define STB0899_OFF0_EQ_Q_INIT_COEFF_0 0xf350 +#define STB0899_OFF1_EQ_Q_INIT_COEFF_1 0xf354 +#define STB0899_OFF2_EQ_Q_INIT_COEFF_2 0xf358 +#define STB0899_OFF3_EQ_Q_INIT_COEFF_3 0xf35c +#define STB0899_OFF4_EQ_Q_INIT_COEFF_4 0xf360 +#define STB0899_OFF5_EQ_Q_INIT_COEFF_5 0xf364 +#define STB0899_OFF6_EQ_Q_INIT_COEFF_6 0xf368 +#define STB0899_OFF7_EQ_Q_INIT_COEFF_7 0xf36c +#define STB0899_OFF8_EQ_Q_INIT_COEFF_8 0xf370 +#define STB0899_OFF9_EQ_Q_INIT_COEFF_9 0xf374 +#define STB0899_OFFa_EQ_Q_INIT_COEFF_10 0xf378 +#define STB0899_BASE_EQ_Q_INIT_COEFF_N 0x00000440 +#define STB0899_EQ_Q_INIT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_Q_INIT_COEFF_N 0 +#define STB0899_WIDTH_EQ_Q_INIT_COEFF_N 12 + +#define STB0899_OFF0_EQ_I_OUT_COEFF_0 0xf300 +#define STB0899_OFF1_EQ_I_OUT_COEFF_1 0xf304 +#define STB0899_OFF2_EQ_I_OUT_COEFF_2 0xf308 +#define STB0899_OFF3_EQ_I_OUT_COEFF_3 0xf30c +#define STB0899_OFF4_EQ_I_OUT_COEFF_4 0xf310 +#define STB0899_OFF5_EQ_I_OUT_COEFF_5 0xf314 +#define STB0899_OFF6_EQ_I_OUT_COEFF_6 0xf318 +#define STB0899_OFF7_EQ_I_OUT_COEFF_7 0xf31c +#define STB0899_OFF8_EQ_I_OUT_COEFF_8 0xf320 +#define STB0899_OFF9_EQ_I_OUT_COEFF_9 0xf324 +#define STB0899_OFFa_EQ_I_OUT_COEFF_10 0xf328 +#define STB0899_BASE_EQ_I_OUT_COEFF_N 0x00000460 +#define STB0899_EQ_I_OUT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_I_OUT_COEFF_N 0 +#define STB0899_WIDTH_EQ_I_OUT_COEFF_N 12 + +#define STB0899_OFF0_EQ_Q_OUT_COEFF_0 0xf330 +#define STB0899_OFF1_EQ_Q_OUT_COEFF_1 0xf334 +#define STB0899_OFF2_EQ_Q_OUT_COEFF_2 0xf338 +#define STB0899_OFF3_EQ_Q_OUT_COEFF_3 0xf33c +#define STB0899_OFF4_EQ_Q_OUT_COEFF_4 0xf340 +#define STB0899_OFF5_EQ_Q_OUT_COEFF_5 0xf344 +#define STB0899_OFF6_EQ_Q_OUT_COEFF_6 0xf348 +#define STB0899_OFF7_EQ_Q_OUT_COEFF_7 0xf34c +#define STB0899_OFF8_EQ_Q_OUT_COEFF_8 0xf350 +#define STB0899_OFF9_EQ_Q_OUT_COEFF_9 0xf354 +#define STB0899_OFFa_EQ_Q_OUT_COEFF_10 0xf358 +#define STB0899_BASE_EQ_Q_OUT_COEFF_N 0x00000460 +#define STB0899_EQ_Q_OUT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_Q_OUT_COEFF_N 0 +#define STB0899_WIDTH_EQ_Q_OUT_COEFF_N 12 + +/* S2 FEC */ +#define STB0899_OFF0_BLOCK_LNGTH 0xfa04 +#define STB0899_BASE_BLOCK_LNGTH 0x00000000 +#define STB0899_BLOCK_LENGTH (0xff << 0) +#define STB0899_OFFST_BLOCK_LENGTH 0 +#define STB0899_WIDTH_BLOCK_LENGTH 8 + +#define STB0899_OFF0_ROW_STR 0xfa08 +#define STB0899_BASE_ROW_STR 0x00000000 +#define STB0899_ROW_STRIDE (0xff << 0) +#define STB0899_OFFST_ROW_STRIDE 0 +#define STB0899_WIDTH_ROW_STRIDE 8 + +#define STB0899_OFF0_MAX_ITER 0xfa0c +#define STB0899_BASE_MAX_ITER 0x00000000 +#define STB0899_MAX_ITERATIONS (0xff << 0) +#define STB0899_OFFST_MAX_ITERATIONS 0 +#define STB0899_WIDTH_MAX_ITERATIONS 8 + +#define STB0899_OFF0_BN_END_ADDR 0xfa10 +#define STB0899_BASE_BN_END_ADDR 0x00000000 +#define STB0899_BN_END_ADDR (0x0fff << 0) +#define STB0899_OFFST_BN_END_ADDR 0 +#define STB0899_WIDTH_BN_END_ADDR 12 + +#define STB0899_OFF0_CN_END_ADDR 0xfa14 +#define STB0899_BASE_CN_END_ADDR 0x00000000 +#define STB0899_CN_END_ADDR (0x0fff << 0) +#define STB0899_OFFST_CN_END_ADDR 0 +#define STB0899_WIDTH_CN_END_ADDR 12 + +#define STB0899_OFF0_INFO_LENGTH 0xfa1c +#define STB0899_BASE_INFO_LENGTH 0x00000000 +#define STB0899_INFO_LENGTH (0xff << 0) +#define STB0899_OFFST_INFO_LENGTH 0 +#define STB0899_WIDTH_INFO_LENGTH 8 + +#define STB0899_OFF0_BOT_ADDR 0xfa20 +#define STB0899_BASE_BOT_ADDR 0x00000000 +#define STB0899_BOTTOM_BASE_ADDR (0x03ff << 0) +#define STB0899_OFFST_BOTTOM_BASE_ADDR 0 +#define STB0899_WIDTH_BOTTOM_BASE_ADDR 10 + +#define STB0899_OFF0_BCH_BLK_LN 0xfa24 +#define STB0899_BASE_BCH_BLK_LN 0x00000000 +#define STB0899_BCH_BLOCK_LENGTH (0xffff << 0) +#define STB0899_OFFST_BCH_BLOCK_LENGTH 0 +#define STB0899_WIDTH_BCH_BLOCK_LENGTH 16 + +#define STB0899_OFF0_BCH_T 0xfa28 +#define STB0899_BASE_BCH_T 0x00000000 +#define STB0899_BCH_T (0x0f << 0) +#define STB0899_OFFST_BCH_T 0 +#define STB0899_WIDTH_BCH_T 4 + +#define STB0899_OFF0_CNFG_MODE 0xfa00 +#define STB0899_BASE_CNFG_MODE 0x00000800 +#define STB0899_MODCOD (0x1f << 2) +#define STB0899_OFFST_MODCOD 2 +#define STB0899_WIDTH_MODCOD 5 +#define STB0899_MODCOD_SEL (0x01 << 1) +#define STB0899_OFFST_MODCOD_SEL 1 +#define STB0899_WIDTH_MODCOD_SEL 1 +#define STB0899_CONFIG_MODE (0x01 << 0) +#define STB0899_OFFST_CONFIG_MODE 0 +#define STB0899_WIDTH_CONFIG_MODE 1 + +#define STB0899_OFF0_LDPC_STAT 0xfa04 +#define STB0899_BASE_LDPC_STAT 0x00000800 +#define STB0899_ITERATION (0xff << 3) +#define STB0899_OFFST_ITERATION 3 +#define STB0899_WIDTH_ITERATION 8 +#define STB0899_LDPC_DEC_STATE (0x07 << 0) +#define STB0899_OFFST_LDPC_DEC_STATE 0 +#define STB0899_WIDTH_LDPC_DEC_STATE 3 + +#define STB0899_OFF0_ITER_SCALE 0xfa08 +#define STB0899_BASE_ITER_SCALE 0x00000800 +#define STB0899_ITERATION_SCALE (0xff << 0) +#define STB0899_OFFST_ITERATION_SCALE 0 +#define STB0899_WIDTH_ITERATION_SCALE 8 + +#define STB0899_OFF0_INPUT_MODE 0xfa0c +#define STB0899_BASE_INPUT_MODE 0x00000800 +#define STB0899_SD_BLOCK1_STREAM0 (0x01 << 0) +#define STB0899_OFFST_SD_BLOCK1_STREAM0 0 +#define STB0899_WIDTH_SD_BLOCK1_STREAM0 1 + +#define STB0899_OFF0_LDPCDECRST 0xfa10 +#define STB0899_BASE_LDPCDECRST 0x00000800 +#define STB0899_LDPC_DEC_RST (0x01 << 0) +#define STB0899_OFFST_LDPC_DEC_RST 0 +#define STB0899_WIDTH_LDPC_DEC_RST 1 + +#define STB0899_OFF0_CLK_PER_BYTE_RW 0xfa14 +#define STB0899_BASE_CLK_PER_BYTE_RW 0x00000800 +#define STB0899_CLKS_PER_BYTE (0x0f << 0) +#define STB0899_OFFST_CLKS_PER_BYTE 0 +#define STB0899_WIDTH_CLKS_PER_BYTE 5 + +#define STB0899_OFF0_BCH_ERRORS 0xfa18 +#define STB0899_BASE_BCH_ERRORS 0x00000800 +#define STB0899_BCH_ERRORS (0x0f << 0) +#define STB0899_OFFST_BCH_ERRORS 0 +#define STB0899_WIDTH_BCH_ERRORS 4 + +#define STB0899_OFF0_LDPC_ERRORS 0xfa1c +#define STB0899_BASE_LDPC_ERRORS 0x00000800 +#define STB0899_LDPC_ERRORS (0xffff << 0) +#define STB0899_OFFST_LDPC_ERRORS 0 +#define STB0899_WIDTH_LDPC_ERRORS 16 + +#define STB0899_OFF0_BCH_MODE 0xfa20 +#define STB0899_BASE_BCH_MODE 0x00000800 +#define STB0899_BCH_CORRECT_N (0x01 << 1) +#define STB0899_OFFST_BCH_CORRECT_N 1 +#define STB0899_WIDTH_BCH_CORRECT_N 1 +#define STB0899_FULL_BYPASS (0x01 << 0) +#define STB0899_OFFST_FULL_BYPASS 0 +#define STB0899_WIDTH_FULL_BYPASS 1 + +#define STB0899_OFF0_ERR_ACC_PER 0xfa24 +#define STB0899_BASE_ERR_ACC_PER 0x00000800 +#define STB0899_BCH_ERR_ACC_PERIOD (0x0f << 0) +#define STB0899_OFFST_BCH_ERR_ACC_PERIOD 0 +#define STB0899_WIDTH_BCH_ERR_ACC_PERIOD 4 + +#define STB0899_OFF0_BCH_ERR_ACC 0xfa28 +#define STB0899_BASE_BCH_ERR_ACC 0x00000800 +#define STB0899_BCH_ERR_ACCUM (0xff << 0) +#define STB0899_OFFST_BCH_ERR_ACCUM 0 +#define STB0899_WIDTH_BCH_ERR_ACCUM 8 + +#define STB0899_OFF0_FEC_CORE_ID_REG 0xfa2c +#define STB0899_BASE_FEC_CORE_ID_REG 0x00000800 +#define STB0899_FEC_CORE_ID (0xffffffff << 0) +#define STB0899_OFFST_FEC_CORE_ID 0 +#define STB0899_WIDTH_FEC_CORE_ID 32 + +#define STB0899_OFF0_FEC_VER_ID_REG 0xfa34 +#define STB0899_BASE_FEC_VER_ID_REG 0x00000800 +#define STB0899_FEC_VER_ID (0xff << 0) +#define STB0899_OFFST_FEC_VER_ID 0 +#define STB0899_WIDTH_FEC_VER_ID 8 + +#define STB0899_OFF0_FEC_TP_SEL 0xfa38 +#define STB0899_BASE_FEC_TP_SEL 0x00000800 + +#define STB0899_OFF0_CSM_CNTRL1 0xf310 +#define STB0899_BASE_CSM_CNTRL1 0x00000400 +#define STB0899_CSM_FORCE_FREQLOCK (0x01 << 19) +#define STB0899_OFFST_CSM_FORCE_FREQLOCK 19 +#define STB0899_WIDTH_CSM_FORCE_FREQLOCK 1 +#define STB0899_CSM_FREQ_LOCKSTATE (0x01 << 18) +#define STB0899_OFFST_CSM_FREQ_LOCKSTATE 18 +#define STB0899_WIDTH_CSM_FREQ_LOCKSTATE 1 +#define STB0899_CSM_AUTO_PARAM (0x01 << 17) +#define STB0899_OFFST_CSM_AUTO_PARAM 17 +#define STB0899_WIDTH_CSM_AUTO_PARAM 1 +#define STB0899_FE_LOOP_SHIFT (0x07 << 14) +#define STB0899_OFFST_FE_LOOP_SHIFT 14 +#define STB0899_WIDTH_FE_LOOP_SHIFT 3 +#define STB0899_CSM_AGC_SHIFT (0x07 << 11) +#define STB0899_OFFST_CSM_AGC_SHIFT 11 +#define STB0899_WIDTH_CSM_AGC_SHIFT 3 +#define STB0899_CSM_AGC_GAIN (0x1ff << 2) +#define STB0899_OFFST_CSM_AGC_GAIN 2 +#define STB0899_WIDTH_CSM_AGC_GAIN 9 +#define STB0899_CSM_TWO_PASS (0x01 << 1) +#define STB0899_OFFST_CSM_TWO_PASS 1 +#define STB0899_WIDTH_CSM_TWO_PASS 1 +#define STB0899_CSM_DVT_TABLE (0x01 << 0) +#define STB0899_OFFST_CSM_DVT_TABLE 0 +#define STB0899_WIDTH_CSM_DVT_TABLE 1 + +#define STB0899_OFF0_CSM_CNTRL2 0xf314 +#define STB0899_BASE_CSM_CNTRL2 0x00000400 +#define STB0899_CSM_GAMMA_RHO_ACQ (0x1ff << 9) +#define STB0899_OFFST_CSM_GAMMA_RHOACQ 9 +#define STB0899_WIDTH_CSM_GAMMA_RHOACQ 9 +#define STB0899_CSM_GAMMA_ACQ (0x1ff << 0) +#define STB0899_OFFST_CSM_GAMMA_ACQ 0 +#define STB0899_WIDTH_CSM_GAMMA_ACQ 9 + +#define STB0899_OFF0_CSM_CNTRL3 0xf318 +#define STB0899_BASE_CSM_CNTRL3 0x00000400 +#define STB0899_CSM_GAMMA_RHO_TRACK (0x1ff << 9) +#define STB0899_OFFST_CSM_GAMMA_RHOTRACK 9 +#define STB0899_WIDTH_CSM_GAMMA_RHOTRACK 9 +#define STB0899_CSM_GAMMA_TRACK (0x1ff << 0) +#define STB0899_OFFST_CSM_GAMMA_TRACK 0 +#define STB0899_WIDTH_CSM_GAMMA_TRACK 9 + +#define STB0899_OFF0_CSM_CNTRL4 0xf31c +#define STB0899_BASE_CSM_CNTRL4 0x00000400 +#define STB0899_CSM_PHASEDIFF_THRESH (0x0f << 8) +#define STB0899_OFFST_CSM_PHASEDIFF_THRESH 8 +#define STB0899_WIDTH_CSM_PHASEDIFF_THRESH 4 +#define STB0899_CSM_LOCKCOUNT_THRESH (0xff << 0) +#define STB0899_OFFST_CSM_LOCKCOUNT_THRESH 0 +#define STB0899_WIDTH_CSM_LOCKCOUNT_THRESH 8 + +/* Check on chapter 8 page 42 */ +#define STB0899_ERRCTRL1 0xf574 +#define STB0899_ERRCTRL2 0xf575 +#define STB0899_ERRCTRL3 0xf576 +#define STB0899_ERR_SRC_S1 (0x1f << 3) +#define STB0899_OFFST_ERR_SRC_S1 3 +#define STB0899_WIDTH_ERR_SRC_S1 5 +#define STB0899_ERR_SRC_S2 (0x0f << 0) +#define STB0899_OFFST_ERR_SRC_S2 0 +#define STB0899_WIDTH_ERR_SRC_S2 4 +#define STB0899_NOE (0x07 << 0) +#define STB0899_OFFST_NOE 0 +#define STB0899_WIDTH_NOE 3 + +#define STB0899_ECNT1M 0xf524 +#define STB0899_ECNT1L 0xf525 +#define STB0899_ECNT2M 0xf526 +#define STB0899_ECNT2L 0xf527 +#define STB0899_ECNT3M 0xf528 +#define STB0899_ECNT3L 0xf529 + +#define STB0899_DMONMSK1 0xf57b +#define STB0899_DMONMSK1_WAIT_1STEP (1 << 7) +#define STB0899_DMONMSK1_FREE_14 (1 << 6) +#define STB0899_DMONMSK1_AVRGVIT_CALC (1 << 5) +#define STB0899_DMONMSK1_FREE_12 (1 << 4) +#define STB0899_DMONMSK1_FREE_11 (1 << 3) +#define STB0899_DMONMSK1_B0DIV_CALC (1 << 2) +#define STB0899_DMONMSK1_KDIVB1_CALC (1 << 1) +#define STB0899_DMONMSK1_KDIVB2_CALC (1 << 0) + +#define STB0899_DMONMSK0 0xf57c +#define STB0899_DMONMSK0_SMOTTH_CALC (1 << 7) +#define STB0899_DMONMSK0_FREE_6 (1 << 6) +#define STB0899_DMONMSK0_SIGPOWER_CALC (1 << 5) +#define STB0899_DMONMSK0_QSEUIL_CALC (1 << 4) +#define STB0899_DMONMSK0_FREE_3 (1 << 3) +#define STB0899_DMONMSK0_FREE_2 (1 << 2) +#define STB0899_DMONMSK0_KVDIVB1_CALC (1 << 1) +#define STB0899_DMONMSK0_KVDIVB2_CALC (1 << 0) + +#define STB0899_TSULC 0xf549 +#define STB0899_ULNOSYNCBYTES (0x01 << 7) +#define STB0899_OFFST_ULNOSYNCBYTES 7 +#define STB0899_WIDTH_ULNOSYNCBYTES 1 +#define STB0899_ULPARITY_ON (0x01 << 6) +#define STB0899_OFFST_ULPARITY_ON 6 +#define STB0899_WIDTH_ULPARITY_ON 1 +#define STB0899_ULSYNCOUTRS (0x01 << 5) +#define STB0899_OFFST_ULSYNCOUTRS 5 +#define STB0899_WIDTH_ULSYNCOUTRS 1 +#define STB0899_ULDSS_PACKETS (0x01 << 0) +#define STB0899_OFFST_ULDSS_PACKETS 0 +#define STB0899_WIDTH_ULDSS_PACKETS 1 + +#define STB0899_TSLPL 0xf54b +#define STB0899_LLDVBS2_MODE (0x01 << 4) +#define STB0899_OFFST_LLDVBS2_MODE 4 +#define STB0899_WIDTH_LLDVBS2_MODE 1 +#define STB0899_LLISSYI_ON (0x01 << 3) +#define STB0899_OFFST_LLISSYI_ON 3 +#define STB0899_WIDTH_LLISSYI_ON 1 +#define STB0899_LLNPD_ON (0x01 << 2) +#define STB0899_OFFST_LLNPD_ON 2 +#define STB0899_WIDTH_LLNPD_ON 1 +#define STB0899_LLCRC8_ON (0x01 << 1) +#define STB0899_OFFST_LLCRC8_ON 1 +#define STB0899_WIDTH_LLCRC8_ON 1 + +#define STB0899_TSCFGH 0xf54c +#define STB0899_OUTRS_PS (0x01 << 6) +#define STB0899_OFFST_OUTRS_PS 6 +#define STB0899_WIDTH_OUTRS_PS 1 +#define STB0899_SYNCBYTE (0x01 << 5) +#define STB0899_OFFST_SYNCBYTE 5 +#define STB0899_WIDTH_SYNCBYTE 1 +#define STB0899_PFBIT (0x01 << 4) +#define STB0899_OFFST_PFBIT 4 +#define STB0899_WIDTH_PFBIT 1 +#define STB0899_ERR_BIT (0x01 << 3) +#define STB0899_OFFST_ERR_BIT 3 +#define STB0899_WIDTH_ERR_BIT 1 +#define STB0899_MPEG (0x01 << 2) +#define STB0899_OFFST_MPEG 2 +#define STB0899_WIDTH_MPEG 1 +#define STB0899_CLK_POL (0x01 << 1) +#define STB0899_OFFST_CLK_POL 1 +#define STB0899_WIDTH_CLK_POL 1 +#define STB0899_FORCE0 (0x01 << 0) +#define STB0899_OFFST_FORCE0 0 +#define STB0899_WIDTH_FORCE0 1 + +#define STB0899_TSCFGM 0xf54d +#define STB0899_LLPRIORITY (0x01 << 3) +#define STB0899_OFFST_LLPRIORIY 3 +#define STB0899_WIDTH_LLPRIORITY 1 +#define STB0899_EN188 (0x01 << 2) +#define STB0899_OFFST_EN188 2 +#define STB0899_WIDTH_EN188 1 + +#define STB0899_TSCFGL 0xf54e +#define STB0899_DEL_ERRPCK (0x01 << 7) +#define STB0899_OFFST_DEL_ERRPCK 7 +#define STB0899_WIDTH_DEL_ERRPCK 1 +#define STB0899_ERRFLAGSTD (0x01 << 5) +#define STB0899_OFFST_ERRFLAGSTD 5 +#define STB0899_WIDTH_ERRFLAGSTD 1 +#define STB0899_MPEGERR (0x01 << 4) +#define STB0899_OFFST_MPEGERR 4 +#define STB0899_WIDTH_MPEGERR 1 +#define STB0899_BCH_CHK (0x01 << 3) +#define STB0899_OFFST_BCH_CHK 5 +#define STB0899_WIDTH_BCH_CHK 1 +#define STB0899_CRC8CHK (0x01 << 2) +#define STB0899_OFFST_CRC8CHK 2 +#define STB0899_WIDTH_CRC8CHK 1 +#define STB0899_SPEC_INFO (0x01 << 1) +#define STB0899_OFFST_SPEC_INFO 1 +#define STB0899_WIDTH_SPEC_INFO 1 +#define STB0899_LOW_PRIO_CLK (0x01 << 0) +#define STB0899_OFFST_LOW_PRIO_CLK 0 +#define STB0899_WIDTH_LOW_PRIO_CLK 1 +#define STB0899_ERROR_NORM (0x00 << 0) +#define STB0899_OFFST_ERROR_NORM 0 +#define STB0899_WIDTH_ERROR_NORM 0 + +#define STB0899_TSOUT 0xf54f +#define STB0899_RSSYNCDEL 0xf550 +#define STB0899_TSINHDELH 0xf551 +#define STB0899_TSINHDELM 0xf552 +#define STB0899_TSINHDELL 0xf553 +#define STB0899_TSLLSTKM 0xf55a +#define STB0899_TSLLSTKL 0xf55b +#define STB0899_TSULSTKM 0xf55c +#define STB0899_TSULSTKL 0xf55d +#define STB0899_TSSTATUS 0xf561 + +#define STB0899_PDELCTRL 0xf600 +#define STB0899_INVERT_RES (0x01 << 7) +#define STB0899_OFFST_INVERT_RES 7 +#define STB0899_WIDTH_INVERT_RES 1 +#define STB0899_FORCE_ACCEPTED (0x01 << 6) +#define STB0899_OFFST_FORCE_ACCEPTED 6 +#define STB0899_WIDTH_FORCE_ACCEPTED 1 +#define STB0899_FILTER_EN (0x01 << 5) +#define STB0899_OFFST_FILTER_EN 5 +#define STB0899_WIDTH_FILTER_EN 1 +#define STB0899_LOCKFALL_THRESH (0x01 << 4) +#define STB0899_OFFST_LOCKFALL_THRESH 4 +#define STB0899_WIDTH_LOCKFALL_THRESH 1 +#define STB0899_HYST_EN (0x01 << 3) +#define STB0899_OFFST_HYST_EN 3 +#define STB0899_WIDTH_HYST_EN 1 +#define STB0899_HYST_SWRST (0x01 << 2) +#define STB0899_OFFST_HYST_SWRST 2 +#define STB0899_WIDTH_HYST_SWRST 1 +#define STB0899_ALGO_EN (0x01 << 1) +#define STB0899_OFFST_ALGO_EN 1 +#define STB0899_WIDTH_ALGO_EN 1 +#define STB0899_ALGO_SWRST (0x01 << 0) +#define STB0899_OFFST_ALGO_SWRST 0 +#define STB0899_WIDTH_ALGO_SWRST 1 + +#define STB0899_PDELCTRL2 0xf601 +#define STB0899_BBHCTRL1 0xf602 +#define STB0899_BBHCTRL2 0xf603 +#define STB0899_HYSTTHRESH 0xf604 + +#define STB0899_MATCSTM 0xf605 +#define STB0899_MATCSTL 0xf606 +#define STB0899_UPLCSTM 0xf607 +#define STB0899_UPLCSTL 0xf608 +#define STB0899_DFLCSTM 0xf609 +#define STB0899_DFLCSTL 0xf60a +#define STB0899_SYNCCST 0xf60b +#define STB0899_SYNCDCSTM 0xf60c +#define STB0899_SYNCDCSTL 0xf60d +#define STB0899_ISI_ENTRY 0xf60e +#define STB0899_ISI_BIT_EN 0xf60f +#define STB0899_MATSTRM 0xf610 +#define STB0899_MATSTRL 0xf611 +#define STB0899_UPLSTRM 0xf612 +#define STB0899_UPLSTRL 0xf613 +#define STB0899_DFLSTRM 0xf614 +#define STB0899_DFLSTRL 0xf615 +#define STB0899_SYNCSTR 0xf616 +#define STB0899_SYNCDSTRM 0xf617 +#define STB0899_SYNCDSTRL 0xf618 + +#define STB0899_CFGPDELSTATUS1 0xf619 +#define STB0899_BADDFL (0x01 << 6) +#define STB0899_OFFST_BADDFL 6 +#define STB0899_WIDTH_BADDFL 1 +#define STB0899_CONTINUOUS_STREAM (0x01 << 5) +#define STB0899_OFFST_CONTINUOUS_STREAM 5 +#define STB0899_WIDTH_CONTINUOUS_STREAM 1 +#define STB0899_ACCEPTED_STREAM (0x01 << 4) +#define STB0899_OFFST_ACCEPTED_STREAM 4 +#define STB0899_WIDTH_ACCEPTED_STREAM 1 +#define STB0899_BCH_ERRFLAG (0x01 << 3) +#define STB0899_OFFST_BCH_ERRFLAG 3 +#define STB0899_WIDTH_BCH_ERRFLAG 1 +#define STB0899_CRCRES (0x01 << 2) +#define STB0899_OFFST_CRCRES 2 +#define STB0899_WIDTH_CRCRES 1 +#define STB0899_CFGPDELSTATUS_LOCK (0x01 << 1) +#define STB0899_OFFST_CFGPDELSTATUS_LOCK 1 +#define STB0899_WIDTH_CFGPDELSTATUS_LOCK 1 +#define STB0899_1STLOCK (0x01 << 0) +#define STB0899_OFFST_1STLOCK 0 +#define STB0899_WIDTH_1STLOCK 1 + +#define STB0899_CFGPDELSTATUS2 0xf61a +#define STB0899_BBFERRORM 0xf61b +#define STB0899_BBFERRORL 0xf61c +#define STB0899_UPKTERRORM 0xf61d +#define STB0899_UPKTERRORL 0xf61e + +#define STB0899_TSTCK 0xff10 + +#define STB0899_TSTRES 0xff11 +#define STB0899_FRESLDPC (0x01 << 7) +#define STB0899_OFFST_FRESLDPC 7 +#define STB0899_WIDTH_FRESLDPC 1 +#define STB0899_FRESRS (0x01 << 6) +#define STB0899_OFFST_FRESRS 6 +#define STB0899_WIDTH_FRESRS 1 +#define STB0899_FRESVIT (0x01 << 5) +#define STB0899_OFFST_FRESVIT 5 +#define STB0899_WIDTH_FRESVIT 1 +#define STB0899_FRESMAS1_2 (0x01 << 4) +#define STB0899_OFFST_FRESMAS1_2 4 +#define STB0899_WIDTH_FRESMAS1_2 1 +#define STB0899_FRESACS (0x01 << 3) +#define STB0899_OFFST_FRESACS 3 +#define STB0899_WIDTH_FRESACS 1 +#define STB0899_FRESSYM (0x01 << 2) +#define STB0899_OFFST_FRESSYM 2 +#define STB0899_WIDTH_FRESSYM 1 +#define STB0899_FRESMAS (0x01 << 1) +#define STB0899_OFFST_FRESMAS 1 +#define STB0899_WIDTH_FRESMAS 1 +#define STB0899_FRESINT (0x01 << 0) +#define STB0899_OFFST_FRESINIT 0 +#define STB0899_WIDTH_FRESINIT 1 + +#define STB0899_TSTOUT 0xff12 +#define STB0899_EN_SIGNATURE (0x01 << 7) +#define STB0899_OFFST_EN_SIGNATURE 7 +#define STB0899_WIDTH_EN_SIGNATURE 1 +#define STB0899_BCLK_CLK (0x01 << 6) +#define STB0899_OFFST_BCLK_CLK 6 +#define STB0899_WIDTH_BCLK_CLK 1 +#define STB0899_SGNL_OUT (0x01 << 5) +#define STB0899_OFFST_SGNL_OUT 5 +#define STB0899_WIDTH_SGNL_OUT 1 +#define STB0899_TS (0x01 << 4) +#define STB0899_OFFST_TS 4 +#define STB0899_WIDTH_TS 1 +#define STB0899_CTEST (0x01 << 0) +#define STB0899_OFFST_CTEST 0 +#define STB0899_WIDTH_CTEST 1 + +#define STB0899_TSTIN 0xff13 +#define STB0899_TEST_IN (0x01 << 7) +#define STB0899_OFFST_TEST_IN 7 +#define STB0899_WIDTH_TEST_IN 1 +#define STB0899_EN_ADC (0x01 << 6) +#define STB0899_OFFST_EN_ADC 6 +#define STB0899_WIDTH_ENADC 1 +#define STB0899_SGN_ADC (0x01 << 5) +#define STB0899_OFFST_SGN_ADC 5 +#define STB0899_WIDTH_SGN_ADC 1 +#define STB0899_BCLK_IN (0x01 << 4) +#define STB0899_OFFST_BCLK_IN 4 +#define STB0899_WIDTH_BCLK_IN 1 +#define STB0899_JETONIN_MODE (0x01 << 3) +#define STB0899_OFFST_JETONIN_MODE 3 +#define STB0899_WIDTH_JETONIN_MODE 1 +#define STB0899_BCLK_VALUE (0x01 << 2) +#define STB0899_OFFST_BCLK_VALUE 2 +#define STB0899_WIDTH_BCLK_VALUE 1 +#define STB0899_SGNRST_T12 (0x01 << 1) +#define STB0899_OFFST_SGNRST_T12 1 +#define STB0899_WIDTH_SGNRST_T12 1 +#define STB0899_LOWSP_ENAX (0x01 << 0) +#define STB0899_OFFST_LOWSP_ENAX 0 +#define STB0899_WIDTH_LOWSP_ENAX 1 + +#define STB0899_TSTSYS 0xff14 +#define STB0899_TSTCHIP 0xff15 +#define STB0899_TSTFREE 0xff16 +#define STB0899_TSTI2C 0xff17 +#define STB0899_BITSPEEDM 0xff1c +#define STB0899_BITSPEEDL 0xff1d +#define STB0899_TBUSBIT 0xff1e +#define STB0899_TSTDIS 0xff24 +#define STB0899_TSTDISRX 0xff25 +#define STB0899_TSTJETON 0xff28 +#define STB0899_TSTDCADJ 0xff40 +#define STB0899_TSTAGC1 0xff41 +#define STB0899_TSTAGC1N 0xff42 +#define STB0899_TSTPOLYPH 0xff48 +#define STB0899_TSTR 0xff49 +#define STB0899_TSTAGC2 0xff4a +#define STB0899_TSTCTL1 0xff4b +#define STB0899_TSTCTL2 0xff4c +#define STB0899_TSTCTL3 0xff4d +#define STB0899_TSTDEMAP 0xff50 +#define STB0899_TSTDEMAP2 0xff51 +#define STB0899_TSTDEMMON 0xff52 +#define STB0899_TSTRATE 0xff53 +#define STB0899_TSTSELOUT 0xff54 +#define STB0899_TSYNC 0xff55 +#define STB0899_TSTERR 0xff56 +#define STB0899_TSTRAM1 0xff58 +#define STB0899_TSTVSELOUT 0xff59 +#define STB0899_TSTFORCEIN 0xff5a +#define STB0899_TSTRS1 0xff5c +#define STB0899_TSTRS2 0xff5d +#define STB0899_TSTRS3 0xff53 + +#define STB0899_INTBUFSTATUS 0xf200 +#define STB0899_INTBUFCTRL 0xf201 +#define STB0899_PCKLENUL 0xf55e +#define STB0899_PCKLENLL 0xf55f +#define STB0899_RSPCKLEN 0xf560 + +/* 2 registers */ +#define STB0899_SYNCDCST 0xf60c + +/* DiSEqC */ +#define STB0899_DISCNTRL1 0xf0a0 +#define STB0899_TIMOFF (0x01 << 7) +#define STB0899_OFFST_TIMOFF 7 +#define STB0899_WIDTH_TIMOFF 1 +#define STB0899_DISEQCRESET (0x01 << 6) +#define STB0899_OFFST_DISEQCRESET 6 +#define STB0899_WIDTH_DISEQCRESET 1 +#define STB0899_TIMCMD (0x03 << 4) +#define STB0899_OFFST_TIMCMD 4 +#define STB0899_WIDTH_TIMCMD 2 +#define STB0899_DISPRECHARGE (0x01 << 2) +#define STB0899_OFFST_DISPRECHARGE 2 +#define STB0899_WIDTH_DISPRECHARGE 1 +#define STB0899_DISEQCMODE (0x03 << 0) +#define STB0899_OFFST_DISEQCMODE 0 +#define STB0899_WIDTH_DISEQCMODE 2 + +#define STB0899_DISCNTRL2 0xf0a1 +#define STB0899_RECEIVER_ON (0x01 << 7) +#define STB0899_OFFST_RECEIVER_ON 7 +#define STB0899_WIDTH_RECEIVER_ON 1 +#define STB0899_IGNO_SHORT_22K (0x01 << 6) +#define STB0899_OFFST_IGNO_SHORT_22K 6 +#define STB0899_WIDTH_IGNO_SHORT_22K 1 +#define STB0899_ONECHIP_TRX (0x01 << 5) +#define STB0899_OFFST_ONECHIP_TRX 5 +#define STB0899_WIDTH_ONECHIP_TRX 1 +#define STB0899_EXT_ENVELOP (0x01 << 4) +#define STB0899_OFFST_EXT_ENVELOP 4 +#define STB0899_WIDTH_EXT_ENVELOP 1 +#define STB0899_PIN_SELECT (0x03 << 2) +#define STB0899_OFFST_PIN_SELCT 2 +#define STB0899_WIDTH_PIN_SELCT 2 +#define STB0899_IRQ_RXEND (0x01 << 1) +#define STB0899_OFFST_IRQ_RXEND 1 +#define STB0899_WIDTH_IRQ_RXEND 1 +#define STB0899_IRQ_4NBYTES (0x01 << 0) +#define STB0899_OFFST_IRQ_4NBYTES 0 +#define STB0899_WIDTH_IRQ_4NBYTES 1 + +#define STB0899_DISRX_ST0 0xf0a4 +#define STB0899_RXEND (0x01 << 7) +#define STB0899_OFFST_RXEND 7 +#define STB0899_WIDTH_RXEND 1 +#define STB0899_RXACTIVE (0x01 << 6) +#define STB0899_OFFST_RXACTIVE 6 +#define STB0899_WIDTH_RXACTIVE 1 +#define STB0899_SHORT22K (0x01 << 5) +#define STB0899_OFFST_SHORT22K 5 +#define STB0899_WIDTH_SHORT22K 1 +#define STB0899_CONTTONE (0x01 << 4) +#define STB0899_OFFST_CONTTONE 4 +#define STB0899_WIDTH_CONTONE 1 +#define STB0899_4BFIFOREDY (0x01 << 3) +#define STB0899_OFFST_4BFIFOREDY 3 +#define STB0899_WIDTH_4BFIFOREDY 1 +#define STB0899_FIFOEMPTY (0x01 << 2) +#define STB0899_OFFST_FIFOEMPTY 2 +#define STB0899_WIDTH_FIFOEMPTY 1 +#define STB0899_ABORTTRX (0x01 << 0) +#define STB0899_OFFST_ABORTTRX 0 +#define STB0899_WIDTH_ABORTTRX 1 + +#define STB0899_DISRX_ST1 0xf0a5 +#define STB0899_RXFAIL (0x01 << 7) +#define STB0899_OFFST_RXFAIL 7 +#define STB0899_WIDTH_RXFAIL 1 +#define STB0899_FIFOPFAIL (0x01 << 6) +#define STB0899_OFFST_FIFOPFAIL 6 +#define STB0899_WIDTH_FIFOPFAIL 1 +#define STB0899_RXNONBYTES (0x01 << 5) +#define STB0899_OFFST_RXNONBYTES 5 +#define STB0899_WIDTH_RXNONBYTES 1 +#define STB0899_FIFOOVF (0x01 << 4) +#define STB0899_OFFST_FIFOOVF 4 +#define STB0899_WIDTH_FIFOOVF 1 +#define STB0899_FIFOBYTENBR (0x0f << 0) +#define STB0899_OFFST_FIFOBYTENBR 0 +#define STB0899_WIDTH_FIFOBYTENBR 4 + +#define STB0899_DISPARITY 0xf0a6 + +#define STB0899_DISFIFO 0xf0a7 + +#define STB0899_DISSTATUS 0xf0a8 +#define STB0899_FIFOFULL (0x01 << 6) +#define STB0899_OFFST_FIFOFULL 6 +#define STB0899_WIDTH_FIFOFULL 1 +#define STB0899_TXIDLE (0x01 << 5) +#define STB0899_OFFST_TXIDLE 5 +#define STB0899_WIDTH_TXIDLE 1 +#define STB0899_GAPBURST (0x01 << 4) +#define STB0899_OFFST_GAPBURST 4 +#define STB0899_WIDTH_GAPBURST 1 +#define STB0899_TXFIFOBYTES (0x0f << 0) +#define STB0899_OFFST_TXFIFOBYTES 0 +#define STB0899_WIDTH_TXFIFOBYTES 4 +#define STB0899_DISF22 0xf0a9 + +#define STB0899_DISF22RX 0xf0aa + +/* General Purpose */ +#define STB0899_SYSREG 0xf101 +#define STB0899_ACRPRESC 0xf110 +#define STB0899_OFFST_RSVD2 7 +#define STB0899_WIDTH_RSVD2 1 +#define STB0899_OFFST_ACRPRESC 4 +#define STB0899_WIDTH_ACRPRESC 3 +#define STB0899_OFFST_RSVD1 3 +#define STB0899_WIDTH_RSVD1 1 +#define STB0899_OFFST_ACRPRESC2 0 +#define STB0899_WIDTH_ACRPRESC2 3 + +#define STB0899_ACRDIV1 0xf111 +#define STB0899_ACRDIV2 0xf112 +#define STB0899_DACR1 0xf113 +#define STB0899_DACR2 0xf114 +#define STB0899_OUTCFG 0xf11c +#define STB0899_MODECFG 0xf11d +#define STB0899_NCOARSE 0xf1b3 + +#define STB0899_SYNTCTRL 0xf1b6 +#define STB0899_STANDBY (0x01 << 7) +#define STB0899_OFFST_STANDBY 7 +#define STB0899_WIDTH_STANDBY 1 +#define STB0899_BYPASSPLL (0x01 << 6) +#define STB0899_OFFST_BYPASSPLL 6 +#define STB0899_WIDTH_BYPASSPLL 1 +#define STB0899_SEL1XRATIO (0x01 << 5) +#define STB0899_OFFST_SEL1XRATIO 5 +#define STB0899_WIDTH_SEL1XRATIO 1 +#define STB0899_SELOSCI (0x01 << 1) +#define STB0899_OFFST_SELOSCI 1 +#define STB0899_WIDTH_SELOSCI 1 + +#define STB0899_FILTCTRL 0xf1b7 +#define STB0899_SYSCTRL 0xf1b8 + +#define STB0899_STOPCLK1 0xf1c2 +#define STB0899_STOP_CKINTBUF108 (0x01 << 7) +#define STB0899_OFFST_STOP_CKINTBUF108 7 +#define STB0899_WIDTH_STOP_CKINTBUF108 1 +#define STB0899_STOP_CKINTBUF216 (0x01 << 6) +#define STB0899_OFFST_STOP_CKINTBUF216 6 +#define STB0899_WIDTH_STOP_CKINTBUF216 1 +#define STB0899_STOP_CHK8PSK (0x01 << 5) +#define STB0899_OFFST_STOP_CHK8PSK 5 +#define STB0899_WIDTH_STOP_CHK8PSK 1 +#define STB0899_STOP_CKFEC108 (0x01 << 4) +#define STB0899_OFFST_STOP_CKFEC108 4 +#define STB0899_WIDTH_STOP_CKFEC108 1 +#define STB0899_STOP_CKFEC216 (0x01 << 3) +#define STB0899_OFFST_STOP_CKFEC216 3 +#define STB0899_WIDTH_STOP_CKFEC216 1 +#define STB0899_STOP_CKCORE216 (0x01 << 2) +#define STB0899_OFFST_STOP_CKCORE216 2 +#define STB0899_WIDTH_STOP_CKCORE216 1 +#define STB0899_STOP_CKADCI108 (0x01 << 1) +#define STB0899_OFFST_STOP_CKADCI108 1 +#define STB0899_WIDTH_STOP_CKADCI108 1 +#define STB0899_STOP_INVCKADCI108 (0x01 << 0) +#define STB0899_OFFST_STOP_INVCKADCI108 0 +#define STB0899_WIDTH_STOP_INVCKADCI108 1 + +#define STB0899_STOPCLK2 0xf1c3 +#define STB0899_STOP_CKS2DMD108 (0x01 << 2) +#define STB0899_OFFST_STOP_CKS2DMD108 2 +#define STB0899_WIDTH_STOP_CKS2DMD108 1 +#define STB0899_STOP_CKPKDLIN108 (0x01 << 1) +#define STB0899_OFFST_STOP_CKPKDLIN108 1 +#define STB0899_WIDTH_STOP_CKPKDLIN108 1 +#define STB0899_STOP_CKPKDLIN216 (0x01 << 0) +#define STB0899_OFFST_STOP_CKPKDLIN216 0 +#define STB0899_WIDTH_STOP_CKPKDLIN216 1 + +#define STB0899_TSTTNR1 0xf1e0 +#define STB0899_BYPASS_ADC (0x01 << 7) +#define STB0899_OFFST_BYPASS_ADC 7 +#define STB0899_WIDTH_BYPASS_ADC 1 +#define STB0899_INVADCICKOUT (0x01 << 6) +#define STB0899_OFFST_INVADCICKOUT 6 +#define STB0899_WIDTH_INVADCICKOUT 1 +#define STB0899_ADCTEST_VOLTAGE (0x03 << 4) +#define STB0899_OFFST_ADCTEST_VOLTAGE 4 +#define STB0899_WIDTH_ADCTEST_VOLTAGE 1 +#define STB0899_ADC_RESET (0x01 << 3) +#define STB0899_OFFST_ADC_RESET 3 +#define STB0899_WIDTH_ADC_RESET 1 +#define STB0899_TSTTNR1_2 (0x01 << 2) +#define STB0899_OFFST_TSTTNR1_2 2 +#define STB0899_WIDTH_TSTTNR1_2 1 +#define STB0899_ADCPON (0x01 << 1) +#define STB0899_OFFST_ADCPON 1 +#define STB0899_WIDTH_ADCPON 1 +#define STB0899_ADCIN_MODE (0x01 << 0) +#define STB0899_OFFST_ADCIN_MODE 0 +#define STB0899_WIDTH_ADCIN_MODE 1 + +#define STB0899_TSTTNR2 0xf1e1 +#define STB0899_TSTTNR2_7 (0x01 << 7) +#define STB0899_OFFST_TSTTNR2_7 7 +#define STB0899_WIDTH_TSTTNR2_7 1 +#define STB0899_NOT_DISRX_WIRED (0x01 << 6) +#define STB0899_OFFST_NOT_DISRX_WIRED 6 +#define STB0899_WIDTH_NOT_DISRX_WIRED 1 +#define STB0899_DISEQC_DCURRENT (0x01 << 5) +#define STB0899_OFFST_DISEQC_DCURRENT 5 +#define STB0899_WIDTH_DISEQC_DCURRENT 1 +#define STB0899_DISEQC_ZCURRENT (0x01 << 4) +#define STB0899_OFFST_DISEQC_ZCURRENT 4 +#define STB0899_WIDTH_DISEQC_ZCURRENT 1 +#define STB0899_DISEQC_SINC_SOURCE (0x03 << 2) +#define STB0899_OFFST_DISEQC_SINC_SOURCE 2 +#define STB0899_WIDTH_DISEQC_SINC_SOURCE 2 +#define STB0899_SELIQSRC (0x03 << 0) +#define STB0899_OFFST_SELIQSRC 0 +#define STB0899_WIDTH_SELIQSRC 2 + +#define STB0899_TSTTNR3 0xf1e2 + +#define STB0899_I2CCFG 0xf129 +#define STB0899_I2CCFGRSVD (0x0f << 4) +#define STB0899_OFFST_I2CCFGRSVD 4 +#define STB0899_WIDTH_I2CCFGRSVD 4 +#define STB0899_I2CFASTMODE (0x01 << 3) +#define STB0899_OFFST_I2CFASTMODE 3 +#define STB0899_WIDTH_I2CFASTMODE 1 +#define STB0899_STATUSWR (0x01 << 2) +#define STB0899_OFFST_STATUSWR 2 +#define STB0899_WIDTH_STATUSWR 1 +#define STB0899_I2CADDRINC (0x03 << 0) +#define STB0899_OFFST_I2CADDRINC 0 +#define STB0899_WIDTH_I2CADDRINC 2 + +#define STB0899_I2CRPT 0xf12a +#define STB0899_I2CTON (0x01 << 7) +#define STB0899_OFFST_I2CTON 7 +#define STB0899_WIDTH_I2CTON 1 +#define STB0899_ENARPTLEVEL (0x01 << 6) +#define STB0899_OFFST_ENARPTLEVEL 6 +#define STB0899_WIDTH_ENARPTLEVEL 2 +#define STB0899_SCLTDELAY (0x01 << 3) +#define STB0899_OFFST_SCLTDELAY 3 +#define STB0899_WIDTH_SCLTDELAY 1 +#define STB0899_STOPENA (0x01 << 2) +#define STB0899_OFFST_STOPENA 2 +#define STB0899_WIDTH_STOPENA 1 +#define STB0899_STOPSDAT2SDA (0x01 << 1) +#define STB0899_OFFST_STOPSDAT2SDA 1 +#define STB0899_WIDTH_STOPSDAT2SDA 1 + +#define STB0899_IOPVALUE8 0xf136 +#define STB0899_IOPVALUE7 0xf137 +#define STB0899_IOPVALUE6 0xf138 +#define STB0899_IOPVALUE5 0xf139 +#define STB0899_IOPVALUE4 0xf13a +#define STB0899_IOPVALUE3 0xf13b +#define STB0899_IOPVALUE2 0xf13c +#define STB0899_IOPVALUE1 0xf13d +#define STB0899_IOPVALUE0 0xf13e + +#define STB0899_GPIO00CFG 0xf140 + +#define STB0899_GPIO01CFG 0xf141 +#define STB0899_GPIO02CFG 0xf142 +#define STB0899_GPIO03CFG 0xf143 +#define STB0899_GPIO04CFG 0xf144 +#define STB0899_GPIO05CFG 0xf145 +#define STB0899_GPIO06CFG 0xf146 +#define STB0899_GPIO07CFG 0xf147 +#define STB0899_GPIO08CFG 0xf148 +#define STB0899_GPIO09CFG 0xf149 +#define STB0899_GPIO10CFG 0xf14a +#define STB0899_GPIO11CFG 0xf14b +#define STB0899_GPIO12CFG 0xf14c +#define STB0899_GPIO13CFG 0xf14d +#define STB0899_GPIO14CFG 0xf14e +#define STB0899_GPIO15CFG 0xf14f +#define STB0899_GPIO16CFG 0xf150 +#define STB0899_GPIO17CFG 0xf151 +#define STB0899_GPIO18CFG 0xf152 +#define STB0899_GPIO19CFG 0xf153 +#define STB0899_GPIO20CFG 0xf154 + +#define STB0899_SDATCFG 0xf155 +#define STB0899_SCLTCFG 0xf156 +#define STB0899_AGCRFCFG 0xf157 +#define STB0899_GPIO22 0xf158 /* AGCBB2CFG */ +#define STB0899_GPIO21 0xf159 /* AGCBB1CFG */ +#define STB0899_DIRCLKCFG 0xf15a +#define STB0899_CLKOUT27CFG 0xf15b +#define STB0899_STDBYCFG 0xf15c +#define STB0899_CS0CFG 0xf15d +#define STB0899_CS1CFG 0xf15e +#define STB0899_DISEQCOCFG 0xf15f + +#define STB0899_GPIO32CFG 0xf160 +#define STB0899_GPIO33CFG 0xf161 +#define STB0899_GPIO34CFG 0xf162 +#define STB0899_GPIO35CFG 0xf163 +#define STB0899_GPIO36CFG 0xf164 +#define STB0899_GPIO37CFG 0xf165 +#define STB0899_GPIO38CFG 0xf166 +#define STB0899_GPIO39CFG 0xf167 + +#define STB0899_IRQSTATUS_3 0xf120 +#define STB0899_IRQSTATUS_2 0xf121 +#define STB0899_IRQSTATUS_1 0xf122 +#define STB0899_IRQSTATUS_0 0xf123 + +#define STB0899_IRQMSK_3 0xf124 +#define STB0899_IRQMSK_2 0xf125 +#define STB0899_IRQMSK_1 0xf126 +#define STB0899_IRQMSK_0 0xf127 + +#define STB0899_IRQCFG 0xf128 + +#define STB0899_GHOSTREG 0xf000 + +#define STB0899_S2DEMOD 0xf3fc +#define STB0899_S2FEC 0xfafc + + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6000.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6000.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6000.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6000.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,256 @@ + /* + Driver for ST STB6000 DVBS Silicon tuner + + Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include +#include + +#include "stb6000.h" + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "stb6000: " args); \ + } while (0) + +struct stb6000_priv { + /* i2c details */ + int i2c_address; + struct i2c_adapter *i2c; + u32 frequency; +}; + +static int stb6000_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int stb6000_sleep(struct dvb_frontend *fe) +{ + struct stb6000_priv *priv = fe->tuner_priv; + int ret; + u8 buf[] = { 10, 0 }; + struct i2c_msg msg = { + .addr = priv->i2c_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + dprintk("%s:\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer(priv->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: i2c error\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return (ret == 1) ? 0 : ret; +} + +static int stb6000_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct stb6000_priv *priv = fe->tuner_priv; + unsigned int n, m; + int ret; + u32 freq_mhz; + int bandwidth; + u8 buf[12]; + struct i2c_msg msg = { + .addr = priv->i2c_address, + .flags = 0, + .buf = buf, + .len = 12 + }; + + dprintk("%s:\n", __func__); + + freq_mhz = params->frequency / 1000; + bandwidth = params->u.qpsk.symbol_rate / 1000000; + + if (bandwidth > 31) + bandwidth = 31; + + if ((freq_mhz > 949) && (freq_mhz < 2151)) { + buf[0] = 0x01; + buf[1] = 0xac; + if (freq_mhz < 1950) + buf[1] = 0xaa; + if (freq_mhz < 1800) + buf[1] = 0xa8; + if (freq_mhz < 1650) + buf[1] = 0xa6; + if (freq_mhz < 1530) + buf[1] = 0xa5; + if (freq_mhz < 1470) + buf[1] = 0xa4; + if (freq_mhz < 1370) + buf[1] = 0xa2; + if (freq_mhz < 1300) + buf[1] = 0xa1; + if (freq_mhz < 1200) + buf[1] = 0xa0; + if (freq_mhz < 1075) + buf[1] = 0xbc; + if (freq_mhz < 1000) + buf[1] = 0xba; + if (freq_mhz < 1075) { + n = freq_mhz / 8; /* vco=lo*4 */ + m = 2; + } else { + n = freq_mhz / 16; /* vco=lo*2 */ + m = 1; + } + buf[2] = n >> 1; + buf[3] = (unsigned char)(((n & 1) << 7) | + (m * freq_mhz - n * 16) | 0x60); + buf[4] = 0x04; + buf[5] = 0x0e; + + buf[6] = (unsigned char)(bandwidth); + + buf[7] = 0xd8; + buf[8] = 0xd0; + buf[9] = 0x50; + buf[10] = 0xeb; + buf[11] = 0x4f; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer(priv->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: i2c error\n", __func__); + + udelay(10); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + buf[0] = 0x07; + buf[1] = 0xdf; + buf[2] = 0xd0; + buf[3] = 0x50; + buf[4] = 0xfb; + msg.len = 5; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer(priv->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: i2c error\n", __func__); + + udelay(10); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + priv->frequency = freq_mhz * 1000; + + return (ret == 1) ? 0 : ret; + } + return -1; +} + +static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct stb6000_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops stb6000_tuner_ops = { + .info = { + .name = "ST STB6000", + .frequency_min = 950000, + .frequency_max = 2150000 + }, + .release = stb6000_release, + .sleep = stb6000_sleep, + .set_params = stb6000_set_params, + .get_frequency = stb6000_get_frequency, +}; + +struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c) +{ + struct stb6000_priv *priv = NULL; + u8 b0[] = { 0 }; + u8 b1[] = { 0, 0 }; + struct i2c_msg msg[2] = { + { + .addr = addr, + .flags = 0, + .buf = b0, + .len = 0 + }, { + .addr = addr, + .flags = I2C_M_RD, + .buf = b1, + .len = 2 + } + }; + int ret; + + dprintk("%s:\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* is some i2c device here ? */ + ret = i2c_transfer(i2c, msg, 2); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret != 2) + return NULL; + + priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_address = addr; + priv->i2c = i2c; + + memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + return fe; +} +EXPORT_SYMBOL(stb6000_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("DVB STB6000 driver"); +MODULE_AUTHOR("Igor M. Liplianin "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6000.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6000.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6000.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6000.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,51 @@ + /* + Driver for ST stb6000 DVBS Silicon tuner + + Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef __DVB_STB6000_H__ +#define __DVB_STB6000_H__ + +#include +#include "dvb_frontend.h" + +/** + * Attach a stb6000 tuner to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param addr i2c address of the tuner. + * @param i2c i2c adapter to use. + * @return FE pointer on success, NULL on failure. + */ +#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, + int addr, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_STB6000 */ + +#endif /* __DVB_STB6000_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,612 @@ +/* + STB6100 Silicon Tuner + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "stb6100.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); + + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > FE_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((x > FE_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((x > FE_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((x > FE_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ +} while (0) + +struct stb6100_lkup { + u32 val_low; + u32 val_high; + u8 reg; +}; + +static int stb6100_release(struct dvb_frontend *fe); + +static const struct stb6100_lkup lkup[] = { + { 0, 950000, 0x0a }, + { 950000, 1000000, 0x0a }, + { 1000000, 1075000, 0x0c }, + { 1075000, 1200000, 0x00 }, + { 1200000, 1300000, 0x01 }, + { 1300000, 1370000, 0x02 }, + { 1370000, 1470000, 0x04 }, + { 1470000, 1530000, 0x05 }, + { 1530000, 1650000, 0x06 }, + { 1650000, 1800000, 0x08 }, + { 1800000, 1950000, 0x0a }, + { 1950000, 2150000, 0x0c }, + { 2150000, 9999999, 0x0c }, + { 0, 0, 0x00 } +}; + +/* Register names for easy debugging. */ +static const char *stb6100_regnames[] = { + [STB6100_LD] = "LD", + [STB6100_VCO] = "VCO", + [STB6100_NI] = "NI", + [STB6100_NF_LSB] = "NF", + [STB6100_K] = "K", + [STB6100_G] = "G", + [STB6100_F] = "F", + [STB6100_DLB] = "DLB", + [STB6100_TEST1] = "TEST1", + [STB6100_FCCK] = "FCCK", + [STB6100_LPEN] = "LPEN", + [STB6100_TEST3] = "TEST3", +}; + +/* Template for normalisation, i.e. setting unused or undocumented + * bits as required according to the documentation. + */ +struct stb6100_regmask { + u8 mask; + u8 set; +}; + +static const struct stb6100_regmask stb6100_template[] = { + [STB6100_LD] = { 0xff, 0x00 }, + [STB6100_VCO] = { 0xff, 0x00 }, + [STB6100_NI] = { 0xff, 0x00 }, + [STB6100_NF_LSB] = { 0xff, 0x00 }, + [STB6100_K] = { 0xc7, 0x38 }, + [STB6100_G] = { 0xef, 0x10 }, + [STB6100_F] = { 0x1f, 0xc0 }, + [STB6100_DLB] = { 0x38, 0xc4 }, + [STB6100_TEST1] = { 0x00, 0x8f }, + [STB6100_FCCK] = { 0x40, 0x0d }, + [STB6100_LPEN] = { 0xf0, 0x0b }, + [STB6100_TEST3] = { 0x00, 0xde }, +}; + +/* + * Currently unused. Some boards might need it in the future + */ +static inline void stb6100_normalise_regs(u8 regs[]) +{ + int i; + + for (i = 0; i < STB6100_NUMREGS; i++) + regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set; +} + +static int stb6100_read_regs(struct stb6100_state *state, u8 regs[]) +{ + int rc; + struct i2c_msg msg = { + .addr = state->config->tuner_address, + .flags = I2C_M_RD, + .buf = regs, + .len = STB6100_NUMREGS + }; + + rc = i2c_transfer(state->i2c, &msg, 1); + if (unlikely(rc != 1)) { + dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]", + state->config->tuner_address, rc); + + return -EREMOTEIO; + } + if (unlikely(verbose > FE_DEBUG)) { + int i; + + dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address); + for (i = 0; i < STB6100_NUMREGS; i++) + dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[i], regs[i]); + } + return 0; +} + +static int stb6100_read_reg(struct stb6100_state *state, u8 reg) +{ + u8 regs[STB6100_NUMREGS]; + int rc; + + struct i2c_msg msg = { + .addr = state->config->tuner_address + reg, + .flags = I2C_M_RD, + .buf = regs, + .len = 1 + }; + + rc = i2c_transfer(state->i2c, &msg, 1); + + if (unlikely(reg >= STB6100_NUMREGS)) { + dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); + return -EINVAL; + } + if (unlikely(verbose > FE_DEBUG)) { + dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address); + dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[reg], regs[0]); + } + + return (unsigned int)regs[0]; +} + +static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len) +{ + int rc; + u8 cmdbuf[len + 1]; + struct i2c_msg msg = { + .addr = state->config->tuner_address, + .flags = 0, + .buf = cmdbuf, + .len = len + 1 + }; + + if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) { + dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d", + start, len); + return -EINVAL; + } + memcpy(&cmdbuf[1], buf, len); + cmdbuf[0] = start; + + if (unlikely(verbose > FE_DEBUG)) { + int i; + + dprintk(verbose, FE_DEBUG, 1, " Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len); + for (i = 0; i < len; i++) + dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[start + i], buf[i]); + } + rc = i2c_transfer(state->i2c, &msg, 1); + if (unlikely(rc != 1)) { + dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]", + (unsigned int)state->config->tuner_address, start, len, rc); + return -EREMOTEIO; + } + return 0; +} + +static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data) +{ + if (unlikely(reg >= STB6100_NUMREGS)) { + dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); + return -EREMOTEIO; + } + data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set; + return stb6100_write_reg_range(state, &data, reg, 1); +} + + +static int stb6100_get_status(struct dvb_frontend *fe, u32 *status) +{ + int rc; + struct stb6100_state *state = fe->tuner_priv; + + rc = stb6100_read_reg(state, STB6100_LD); + if (rc < 0) { + dprintk(verbose, FE_ERROR, 1, "%s failed", __func__); + return rc; + } + return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0; +} + +static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + int rc; + u8 f; + struct stb6100_state *state = fe->tuner_priv; + + rc = stb6100_read_reg(state, STB6100_F); + if (rc < 0) + return rc; + f = rc & STB6100_F_F; + + state->status.bandwidth = (f + 5) * 2000; /* x2 for ZIF */ + + *bandwidth = state->bandwidth = state->status.bandwidth * 1000; + dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth); + return 0; +} + +static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + u32 tmp; + int rc; + struct stb6100_state *state = fe->tuner_priv; + + dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth); + + bandwidth /= 2; /* ZIF */ + + if (bandwidth >= 36000000) /* F[4:0] BW/2 max =31+5=36 mhz for F=31 */ + tmp = 31; + else if (bandwidth <= 5000000) /* bw/2 min = 5Mhz for F=0 */ + tmp = 0; + else /* if 5 < bw/2 < 36 */ + tmp = (bandwidth + 500000) / 1000000 - 5; + + /* Turn on LPF bandwidth setting clock control, + * set bandwidth, wait 10ms, turn off. + */ + rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK); + if (rc < 0) + return rc; + rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp); + if (rc < 0) + return rc; + + msleep(5); /* This is dangerous as another (related) thread may start */ + + rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d); + if (rc < 0) + return rc; + + msleep(10); /* This is dangerous as another (related) thread may start */ + + return 0; +} + +static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + int rc; + u32 nint, nfrac, fvco; + int psd2, odiv; + struct stb6100_state *state = fe->tuner_priv; + u8 regs[STB6100_NUMREGS]; + + rc = stb6100_read_regs(state, regs); + if (rc < 0) + return rc; + + odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT; + psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT; + nint = regs[STB6100_NI]; + nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB]; + fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2); + *frequency = state->frequency = fvco >> (odiv + 1); + + dprintk(verbose, FE_DEBUG, 1, + "frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u", + state->frequency, odiv, psd2, state->reference, fvco, nint, nfrac); + return 0; +} + + +static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + int rc; + const struct stb6100_lkup *ptr; + struct stb6100_state *state = fe->tuner_priv; + struct dvb_frontend_parameters p; + + u32 srate = 0, fvco, nint, nfrac; + u8 regs[STB6100_NUMREGS]; + u8 g, psd2, odiv; + + dprintk(verbose, FE_DEBUG, 1, "Version 2010-8-14 13:51"); + + if (fe->ops.get_frontend) { + dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters"); + fe->ops.get_frontend(fe, &p); + } + srate = p.u.qpsk.symbol_rate; + + /* Set up tuner cleanly, LPF calibration on */ + rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK); + if (rc < 0) + return rc; /* allow LPF calibration */ + + /* PLL Loop disabled, bias on, VCO on, synth on */ + regs[STB6100_LPEN] = 0xeb; + rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]); + if (rc < 0) + return rc; + + /* Program the registers with their data values */ + + /* VCO divide ratio (LO divide ratio, VCO prescaler enable). */ + if (frequency <= 1075000) + odiv = 1; + else + odiv = 0; + + /* VCO enabled, search clock off as per LL3.7, 3.4.1 */ + regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT); + + /* OSM */ + for (ptr = lkup; + (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high); + ptr++); + + if (ptr->val_high == 0) { + printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency); + return -EINVAL; + } + regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg; + rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); + if (rc < 0) + return rc; + + if ((frequency > 1075000) && (frequency <= 1325000)) + psd2 = 0; + else + psd2 = 1; + /* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */ + fvco = frequency << (1 + odiv); + /* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */ + nint = fvco / (state->reference << psd2); + /* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */ + nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2)) + << (9 - psd2), state->reference); + + /* NI */ + regs[STB6100_NI] = nint; + rc = stb6100_write_reg(state, STB6100_NI, regs[STB6100_NI]); + if (rc < 0) + return rc; + + /* NF */ + regs[STB6100_NF_LSB] = nfrac; + rc = stb6100_write_reg(state, STB6100_NF_LSB, regs[STB6100_NF_LSB]); + if (rc < 0) + return rc; + + /* K */ + regs[STB6100_K] = (0x38 & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT); + regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB); + rc = stb6100_write_reg(state, STB6100_K, regs[STB6100_K]); + if (rc < 0) + return rc; + + /* G Baseband gain. */ + if (srate >= 15000000) + g = 9; /* +4 dB */ + else if (srate >= 5000000) + g = 11; /* +8 dB */ + else + g = 14; /* +14 dB */ + + regs[STB6100_G] = (0x10 & ~STB6100_G_G) | g; + regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */ + regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */ + rc = stb6100_write_reg(state, STB6100_G, regs[STB6100_G]); + if (rc < 0) + return rc; + + /* F we don't write as it is set up in BW set */ + + /* DLB set DC servo loop BW to 160Hz (LLA 3.8 / 2.1) */ + regs[STB6100_DLB] = 0xcc; + rc = stb6100_write_reg(state, STB6100_DLB, regs[STB6100_DLB]); + if (rc < 0) + return rc; + + dprintk(verbose, FE_DEBUG, 1, + "frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u", + frequency, srate, (unsigned int)g, (unsigned int)odiv, + (unsigned int)psd2, state->reference, + ptr->reg, fvco, nint, nfrac); + + /* Set up the test registers */ + regs[STB6100_TEST1] = 0x8f; + rc = stb6100_write_reg(state, STB6100_TEST1, regs[STB6100_TEST1]); + if (rc < 0) + return rc; + regs[STB6100_TEST3] = 0xde; + rc = stb6100_write_reg(state, STB6100_TEST3, regs[STB6100_TEST3]); + if (rc < 0) + return rc; + + /* Bring up tuner according to LLA 3.7 3.4.1, step 2 */ + regs[STB6100_LPEN] = 0xfb; /* PLL Loop enabled, bias on, VCO on, synth on */ + rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]); + if (rc < 0) + return rc; + + msleep(2); + + /* Bring up tuner according to LLA 3.7 3.4.1, step 3 */ + regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */ + rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); + if (rc < 0) + return rc; + + msleep(10); /* This is dangerous as another (related) thread may start */ /* wait for LO to lock */ + + regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */ + regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */ + rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); + if (rc < 0) + return rc; + + rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d); + if (rc < 0) + return rc; /* Stop LPF calibration */ + + msleep(10); /* This is dangerous as another (related) thread may start */ + /* wait for stabilisation, (should not be necessary) */ + return 0; +} + +static int stb6100_sleep(struct dvb_frontend *fe) +{ + /* TODO: power down */ + return 0; +} + +static int stb6100_init(struct dvb_frontend *fe) +{ + struct stb6100_state *state = fe->tuner_priv; + struct tuner_state *status = &state->status; + + status->tunerstep = 125000; + status->ifreq = 0; + status->refclock = 27000000; /* Hz */ + status->iqsense = 1; + status->bandwidth = 36000; /* kHz */ + state->bandwidth = status->bandwidth * 1000; /* Hz */ + state->reference = status->refclock / 1000; /* kHz */ + + /* Set default bandwidth. Modified, PN 13-May-10 */ + return 0; +} + +static int stb6100_get_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *state) +{ + switch (param) { + case DVBFE_TUNER_FREQUENCY: + stb6100_get_frequency(fe, &state->frequency); + break; + case DVBFE_TUNER_TUNERSTEP: + break; + case DVBFE_TUNER_IFFREQ: + break; + case DVBFE_TUNER_BANDWIDTH: + stb6100_get_bandwidth(fe, &state->bandwidth); + break; + case DVBFE_TUNER_REFCLOCK: + break; + default: + break; + } + + return 0; +} + +static int stb6100_set_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *state) +{ + struct stb6100_state *tstate = fe->tuner_priv; + + switch (param) { + case DVBFE_TUNER_FREQUENCY: + stb6100_set_frequency(fe, state->frequency); + tstate->frequency = state->frequency; + break; + case DVBFE_TUNER_TUNERSTEP: + break; + case DVBFE_TUNER_IFFREQ: + break; + case DVBFE_TUNER_BANDWIDTH: + stb6100_set_bandwidth(fe, state->bandwidth); + tstate->bandwidth = state->bandwidth; + break; + case DVBFE_TUNER_REFCLOCK: + break; + default: + break; + } + + return 0; +} + +static struct dvb_tuner_ops stb6100_ops = { + .info = { + .name = "STB6100 Silicon Tuner", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 0, + }, + + .init = stb6100_init, + .sleep = stb6100_sleep, + .get_status = stb6100_get_status, + .get_state = stb6100_get_state, + .set_state = stb6100_set_state, + .release = stb6100_release +}; + +struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, + const struct stb6100_config *config, + struct i2c_adapter *i2c) +{ + struct stb6100_state *state = NULL; + + state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->config = config; + state->i2c = i2c; + state->frontend = fe; + state->reference = config->refclock / 1000; /* kHz */ + fe->tuner_priv = state; + fe->ops.tuner_ops = stb6100_ops; + + printk("%s: Attaching STB6100 \n", __func__); + return fe; + +error: + kfree(state); + return NULL; +} + +static int stb6100_release(struct dvb_frontend *fe) +{ + struct stb6100_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + + return 0; +} + +EXPORT_SYMBOL(stb6100_attach); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); + +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STB6100 Silicon tuner"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100_cfg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100_cfg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100_cfg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100_cfg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,104 @@ +/* + STB6100 Silicon Tuner + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *frequency = t_state.frequency; + } + return 0; +} + +static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + t_state.frequency = frequency; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + } + return 0; +} + +static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = &fe->ops; + struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *bandwidth = t_state.bandwidth; + } + return 0; +} + +static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + t_state.bandwidth = bandwidth; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + } + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,115 @@ +/* + STB6100 Silicon Tuner + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STB_6100_REG_H +#define __STB_6100_REG_H + +#include +#include "dvb_frontend.h" + +#define STB6100_LD 0x00 +#define STB6100_LD_LOCK (1 << 0) + +#define STB6100_VCO 0x01 +#define STB6100_VCO_OSCH (0x01 << 7) +#define STB6100_VCO_OSCH_SHIFT 7 +#define STB6100_VCO_OCK (0x03 << 5) +#define STB6100_VCO_OCK_SHIFT 5 +#define STB6100_VCO_ODIV (0x01 << 4) +#define STB6100_VCO_ODIV_SHIFT 4 +#define STB6100_VCO_OSM (0x0f << 0) + +#define STB6100_NI 0x02 +#define STB6100_NF_LSB 0x03 + +#define STB6100_K 0x04 +#define STB6100_K_PSD2 (0x01 << 2) +#define STB6100_K_PSD2_SHIFT 2 +#define STB6100_K_NF_MSB (0x03 << 0) + +#define STB6100_G 0x05 +#define STB6100_G_G (0x0f << 0) +#define STB6100_G_GCT (0x07 << 5) + +#define STB6100_F 0x06 +#define STB6100_F_F (0x1f << 0) + +#define STB6100_DLB 0x07 + +#define STB6100_TEST1 0x08 + +#define STB6100_FCCK 0x09 +#define STB6100_FCCK_FCCK (0x01 << 6) + +#define STB6100_LPEN 0x0a +#define STB6100_LPEN_LPEN (0x01 << 4) +#define STB6100_LPEN_SYNP (0x01 << 5) +#define STB6100_LPEN_OSCP (0x01 << 6) +#define STB6100_LPEN_BEN (0x01 << 7) + +#define STB6100_TEST3 0x0b + +#define STB6100_NUMREGS 0x0c + + +#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \ + ((y <= val) && (val <= x)) ? 1 : 0) + +#define CHKRANGE(val, x, y) (((val >= x) && (val < y)) ? 1 : 0) + +struct stb6100_config { + u8 tuner_address; + u32 refclock; +}; + +struct stb6100_state { + struct i2c_adapter *i2c; + + const struct stb6100_config *config; + struct dvb_tuner_ops ops; + struct dvb_frontend *frontend; + struct tuner_state status; + + u32 frequency; + u32 srate; + u32 bandwidth; + u32 reference; +}; + +#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, + const struct stb6100_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, + const struct stb6100_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif //CONFIG_DVB_STB6100 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100_proc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100_proc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100_proc.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stb6100_proc.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,138 @@ +/* + STB6100 Silicon Tuner wrapper + Copyright (C)2009 Igor M. Liplianin (liplianin@me.by) + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if (frontend_ops->i2c_gate_ctrl) + frontend_ops->i2c_gate_ctrl(fe, 1); + + err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &state); + if (err < 0) { + printk(KERN_ERR "%s: Invalid parameter\n", __func__); + return err; + } + + if (frontend_ops->i2c_gate_ctrl) + frontend_ops->i2c_gate_ctrl(fe, 0); + + *frequency = state.frequency; + } + + return 0; +} + +static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state state; + int err = 0; + + state.frequency = frequency; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if (frontend_ops->i2c_gate_ctrl) + frontend_ops->i2c_gate_ctrl(fe, 1); + + err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &state); + if (err < 0) { + printk(KERN_ERR "%s: Invalid parameter\n", __func__); + return err; + } + + if (frontend_ops->i2c_gate_ctrl) + frontend_ops->i2c_gate_ctrl(fe, 0); + + } + + return 0; +} + +static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if (frontend_ops->i2c_gate_ctrl) + frontend_ops->i2c_gate_ctrl(fe, 1); + + err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &state); + if (err < 0) { + printk(KERN_ERR "%s: Invalid parameter\n", __func__); + return err; + } + + if (frontend_ops->i2c_gate_ctrl) + frontend_ops->i2c_gate_ctrl(fe, 0); + + *bandwidth = state.bandwidth; + } + + return 0; +} + +static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state state; + int err = 0; + + state.bandwidth = bandwidth; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if (frontend_ops->i2c_gate_ctrl) + frontend_ops->i2c_gate_ctrl(fe, 1); + + err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &state); + if (err < 0) { + printk(KERN_ERR "%s: Invalid parameter\n", __func__); + return err; + } + + if (frontend_ops->i2c_gate_ctrl) + frontend_ops->i2c_gate_ctrl(fe, 0); + + } + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0288.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0288.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0288.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0288.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,624 @@ +/* + Driver for ST STV0288 demodulator + Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de + for Reel Multimedia + Copyright (C) 2008 TurboSight.com, Bob Liu + Copyright (C) 2008 Igor M. Liplianin + Removed stb6000 specific tuner code and revised some + procedures. + 2010-09-01 Josef Pavlik + Fixed diseqc_msg, diseqc_burst and set_tone problems + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "stv0288.h" + +struct stv0288_state { + struct i2c_adapter *i2c; + const struct stv0288_config *config; + struct dvb_frontend frontend; + + u8 initialised:1; + u32 tuner_frequency; + u32 symbol_rate; + fe_code_rate_t fec_inner; + int errmode; +}; + +#define STATUS_BER 0 +#define STATUS_UCBLOCKS 1 + +static int debug; +static int debug_legacy_dish_switch; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "stv0288: " args); \ + } while (0) + + +static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len) +{ + struct stv0288_state *state = fe->demodulator_priv; + + if (len != 2) + return -EINVAL; + + return stv0288_writeregI(state, buf[0], buf[1]); +} + +static u8 stv0288_readreg(struct stv0288_state *state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 1 + }, { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __func__, reg, ret); + + return b1[0]; +} + +static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate) +{ + struct stv0288_state *state = fe->demodulator_priv; + unsigned int temp; + unsigned char b[3]; + + if ((srate < 1000000) || (srate > 45000000)) + return -EINVAL; + + temp = (unsigned int)srate / 1000; + + temp = temp * 32768; + temp = temp / 25; + temp = temp / 125; + b[0] = (unsigned char)((temp >> 12) & 0xff); + b[1] = (unsigned char)((temp >> 4) & 0xff); + b[2] = (unsigned char)((temp << 4) & 0xf0); + stv0288_writeregI(state, 0x28, 0x80); /* SFRH */ + stv0288_writeregI(state, 0x29, 0); /* SFRM */ + stv0288_writeregI(state, 0x2a, 0); /* SFRL */ + + stv0288_writeregI(state, 0x28, b[0]); + stv0288_writeregI(state, 0x29, b[1]); + stv0288_writeregI(state, 0x2a, b[2]); + dprintk("stv0288: stv0288_set_symbolrate\n"); + + return 0; +} + +static int stv0288_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *m) +{ + struct stv0288_state *state = fe->demodulator_priv; + + int i; + + dprintk("%s\n", __func__); + + stv0288_writeregI(state, 0x09, 0); + msleep(30); + stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */ + + for (i = 0; i < m->msg_len; i++) { + if (stv0288_writeregI(state, 0x06, m->msg[i])) + return -EREMOTEIO; + } + msleep(m->msg_len*12); + return 0; +} + +static int stv0288_send_diseqc_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t burst) +{ + struct stv0288_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */ + return -EREMOTEIO; + + if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff)) + return -EREMOTEIO; + + msleep(15); + if (stv0288_writeregI(state, 0x05, 0x12)) + return -EREMOTEIO; + + return 0; +} + +static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct stv0288_state *state = fe->demodulator_priv; + + switch (tone) { + case SEC_TONE_ON: + if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */ + return -EREMOTEIO; + break; + + case SEC_TONE_OFF: + if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/ + return -EREMOTEIO; + break; + + default: + return -EINVAL; + } + return 0; +} + +static u8 stv0288_inittab[] = { + 0x01, 0x15, + 0x02, 0x20, + 0x09, 0x0, + 0x0a, 0x4, + 0x0b, 0x0, + 0x0c, 0x0, + 0x0d, 0x0, + 0x0e, 0xd4, + 0x0f, 0x30, + 0x11, 0x80, + 0x12, 0x03, + 0x13, 0x48, + 0x14, 0x84, + 0x15, 0x45, + 0x16, 0xb7, + 0x17, 0x9c, + 0x18, 0x0, + 0x19, 0xa6, + 0x1a, 0x88, + 0x1b, 0x8f, + 0x1c, 0xf0, + 0x20, 0x0b, + 0x21, 0x54, + 0x22, 0x0, + 0x23, 0x0, + 0x2b, 0xff, + 0x2c, 0xf7, + 0x30, 0x0, + 0x31, 0x1e, + 0x32, 0x14, + 0x33, 0x0f, + 0x34, 0x09, + 0x35, 0x0c, + 0x36, 0x05, + 0x37, 0x2f, + 0x38, 0x16, + 0x39, 0xbe, + 0x3a, 0x0, + 0x3b, 0x13, + 0x3c, 0x11, + 0x3d, 0x30, + 0x40, 0x63, + 0x41, 0x04, + 0x42, 0x20, + 0x43, 0x00, + 0x44, 0x00, + 0x45, 0x00, + 0x46, 0x00, + 0x47, 0x00, + 0x4a, 0x00, + 0x50, 0x10, + 0x51, 0x38, + 0x52, 0x21, + 0x58, 0x54, + 0x59, 0x86, + 0x5a, 0x0, + 0x5b, 0x9b, + 0x5c, 0x08, + 0x5d, 0x7f, + 0x5e, 0x0, + 0x5f, 0xff, + 0x70, 0x0, + 0x71, 0x0, + 0x72, 0x0, + 0x74, 0x0, + 0x75, 0x0, + 0x76, 0x0, + 0x81, 0x0, + 0x82, 0x3f, + 0x83, 0x3f, + 0x84, 0x0, + 0x85, 0x0, + 0x88, 0x0, + 0x89, 0x0, + 0x8a, 0x0, + 0x8b, 0x0, + 0x8c, 0x0, + 0x90, 0x0, + 0x91, 0x0, + 0x92, 0x0, + 0x93, 0x0, + 0x94, 0x1c, + 0x97, 0x0, + 0xa0, 0x48, + 0xa1, 0x0, + 0xb0, 0xb8, + 0xb1, 0x3a, + 0xb2, 0x10, + 0xb3, 0x82, + 0xb4, 0x80, + 0xb5, 0x82, + 0xb6, 0x82, + 0xb7, 0x82, + 0xb8, 0x20, + 0xb9, 0x0, + 0xf0, 0x0, + 0xf1, 0x0, + 0xf2, 0xc0, + 0x51, 0x36, + 0x52, 0x09, + 0x53, 0x94, + 0x54, 0x62, + 0x55, 0x29, + 0x56, 0x64, + 0x57, 0x2b, + 0xff, 0xff, +}; + +static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +{ + dprintk("%s: %s\n", __func__, + volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : + volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); + + return 0; +} + +static int stv0288_init(struct dvb_frontend *fe) +{ + struct stv0288_state *state = fe->demodulator_priv; + int i; + u8 reg; + u8 val; + + dprintk("stv0288: init chip\n"); + stv0288_writeregI(state, 0x41, 0x04); + msleep(50); + + /* we have default inittab */ + if (state->config->inittab == NULL) { + for (i = 0; !(stv0288_inittab[i] == 0xff && + stv0288_inittab[i + 1] == 0xff); i += 2) + stv0288_writeregI(state, stv0288_inittab[i], + stv0288_inittab[i + 1]); + } else { + for (i = 0; ; i += 2) { + reg = state->config->inittab[i]; + val = state->config->inittab[i+1]; + if (reg == 0xff && val == 0xff) + break; + stv0288_writeregI(state, reg, val); + } + } + return 0; +} + +static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct stv0288_state *state = fe->demodulator_priv; + + u8 sync = stv0288_readreg(state, 0x24); + if (sync == 255) + sync = 0; + + dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); + + *status = 0; + if (sync & 0x80) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + if (sync & 0x10) + *status |= FE_HAS_VITERBI; + if (sync & 0x08) { + *status |= FE_HAS_LOCK; + dprintk("stv0288 has locked\n"); + } + + return 0; +} + +static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stv0288_state *state = fe->demodulator_priv; + + if (state->errmode != STATUS_BER) + return 0; + *ber = (stv0288_readreg(state, 0x26) << 8) | + stv0288_readreg(state, 0x27); + dprintk("stv0288_read_ber %d\n", *ber); + + return 0; +} + + +static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stv0288_state *state = fe->demodulator_priv; + + s32 signal = 0xffff - ((stv0288_readreg(state, 0x10) << 8)); + + + signal = signal * 5 / 4; + *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; + dprintk("stv0288_read_signal_strength %d\n", *strength); + + return 0; +} +static int stv0288_sleep(struct dvb_frontend *fe) +{ + struct stv0288_state *state = fe->demodulator_priv; + + stv0288_writeregI(state, 0x41, 0x84); + state->initialised = 0; + + return 0; +} +static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stv0288_state *state = fe->demodulator_priv; + + s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8) + | stv0288_readreg(state, 0x2e)); + xsnr = 3 * (xsnr - 0xa100); + *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; + dprintk("stv0288_read_snr %d\n", *snr); + + return 0; +} + +static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct stv0288_state *state = fe->demodulator_priv; + + if (state->errmode != STATUS_BER) + return 0; + *ucblocks = (stv0288_readreg(state, 0x26) << 8) | + stv0288_readreg(state, 0x27); + dprintk("stv0288_read_ber %d\n", *ucblocks); + + return 0; +} + +static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int stv0288_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *dfp) +{ + struct stv0288_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + char tm; + unsigned char tda[3]; + + dprintk("%s : FE_SET_FRONTEND\n", __func__); + + if (c->delivery_system != SYS_DVBS) { + dprintk("%s: unsupported delivery " + "system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; + } + + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + /* only frequency & symbol_rate are used for tuner*/ + dfp->frequency = c->frequency; + dfp->u.qpsk.symbol_rate = c->symbol_rate; + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, dfp); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + udelay(10); + stv0288_set_symbolrate(fe, c->symbol_rate); + /* Carrier lock control register */ + stv0288_writeregI(state, 0x15, 0xc5); + + tda[0] = 0x2b; /* CFRM */ + tda[2] = 0x0; /* CFRL */ + for (tm = -6; tm < 7;) { + /* Viterbi status */ + if (stv0288_readreg(state, 0x24) & 0x8) + break; + + tda[2] += 40; + if (tda[2] < 40) + tm++; + tda[1] = (unsigned char)tm; + stv0288_writeregI(state, 0x2b, tda[1]); + stv0288_writeregI(state, 0x2c, tda[2]); + udelay(30); + } + + state->tuner_frequency = c->frequency; + state->fec_inner = FEC_AUTO; + state->symbol_rate = c->symbol_rate; + + return 0; +} + +static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv0288_state *state = fe->demodulator_priv; + + if (enable) + stv0288_writeregI(state, 0x01, 0xb5); + else + stv0288_writeregI(state, 0x01, 0x35); + + udelay(1); + + return 0; +} + +static void stv0288_release(struct dvb_frontend *fe) +{ + struct stv0288_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops stv0288_ops = { + + .info = { + .name = "ST STV0288 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + + .release = stv0288_release, + .init = stv0288_init, + .sleep = stv0288_sleep, + .write = stv0288_write, + .i2c_gate_ctrl = stv0288_i2c_gate_ctrl, + .read_status = stv0288_read_status, + .read_ber = stv0288_read_ber, + .read_signal_strength = stv0288_read_signal_strength, + .read_snr = stv0288_read_snr, + .read_ucblocks = stv0288_read_ucblocks, + .diseqc_send_master_cmd = stv0288_send_diseqc_msg, + .diseqc_send_burst = stv0288_send_diseqc_burst, + .set_tone = stv0288_set_tone, + .set_voltage = stv0288_set_voltage, + + .set_property = stv0288_set_property, + .get_property = stv0288_get_property, + .set_frontend = stv0288_set_frontend, +}; + +struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, + struct i2c_adapter *i2c) +{ + struct stv0288_state *state = NULL; + int id; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct stv0288_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->initialised = 0; + state->tuner_frequency = 0; + state->symbol_rate = 0; + state->fec_inner = 0; + state->errmode = STATUS_BER; + + stv0288_writeregI(state, 0x41, 0x04); + msleep(200); + id = stv0288_readreg(state, 0x00); + dprintk("stv0288 id %x\n", id); + + /* register 0x00 contains 0x11 for STV0288 */ + if (id != 0x11) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &stv0288_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + + return NULL; +} +EXPORT_SYMBOL(stv0288_attach); + +module_param(debug_legacy_dish_switch, int, 0444); +MODULE_PARM_DESC(debug_legacy_dish_switch, + "Enable timing analysis for Dish Network legacy switches"); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver"); +MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin"); +MODULE_LICENSE("GPL"); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0288.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0288.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0288.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0288.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,67 @@ +/* + Driver for ST STV0288 demodulator + + Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de + for Reel Multimedia + Copyright (C) 2008 TurboSight.com, + Copyright (C) 2008 Igor M. Liplianin + Removed stb6000 specific tuner code and revised some + procedures. + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef STV0288_H +#define STV0288_H + +#include +#include "dvb_frontend.h" + +struct stv0288_config { + /* the demodulator's i2c address */ + u8 demod_address; + + u8* inittab; + + /* minimum delay before retuning */ + int min_delay_ms; + + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); +}; + +#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \ + defined(MODULE)) +extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_STV0288 */ + +static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val) +{ + int r = 0; + u8 buf[] = { reg, val }; + if (fe->ops.write) + r = fe->ops.write(fe, buf, 2); + return r; +} + +#endif /* STV0288_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0297.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0297.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0297.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0297.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,723 @@ +/* + Driver for STV0297 demodulator + + Copyright (C) 2004 Andrew de Quincey + Copyright (C) 2003-2004 Dennis Noermann + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "stv0297.h" + +struct stv0297_state { + struct i2c_adapter *i2c; + const struct stv0297_config *config; + struct dvb_frontend frontend; + + unsigned long last_ber; + unsigned long base_freq; +}; + +#if 1 +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +#define STV0297_CLOCK_KHZ 28900 + + +static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static int stv0297_readreg(struct stv0297_state *state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, + {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} + }; + + // this device needs a STOP between the register and data + if (state->config->stop_during_read) { + if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); + return -1; + } + if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); + return -1; + } + } else { + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg, ret); + return -1; + } + } + + return b1[0]; +} + +static int stv0297_writereg_mask(struct stv0297_state *state, u8 reg, u8 mask, u8 data) +{ + int val; + + val = stv0297_readreg(state, reg); + val &= ~mask; + val |= (data & mask); + stv0297_writereg(state, reg, val); + + return 0; +} + +static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len) +{ + int ret; + struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = + ®1,.len = 1}, + {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len} + }; + + // this device needs a STOP between the register and data + if (state->config->stop_during_read) { + if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); + return -1; + } + if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); + return -1; + } + } else { + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __func__, reg1, ret); + return -1; + } + } + + return 0; +} + +static u32 stv0297_get_symbolrate(struct stv0297_state *state) +{ + u64 tmp; + + tmp = stv0297_readreg(state, 0x55); + tmp |= stv0297_readreg(state, 0x56) << 8; + tmp |= stv0297_readreg(state, 0x57) << 16; + tmp |= stv0297_readreg(state, 0x58) << 24; + + tmp *= STV0297_CLOCK_KHZ; + tmp >>= 32; + + return (u32) tmp; +} + +static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate) +{ + long tmp; + + tmp = 131072L * srate; /* 131072 = 2^17 */ + tmp = tmp / (STV0297_CLOCK_KHZ / 4); /* 1/4 = 2^-2 */ + tmp = tmp * 8192L; /* 8192 = 2^13 */ + + stv0297_writereg(state, 0x55, (unsigned char) (tmp & 0xFF)); + stv0297_writereg(state, 0x56, (unsigned char) (tmp >> 8)); + stv0297_writereg(state, 0x57, (unsigned char) (tmp >> 16)); + stv0297_writereg(state, 0x58, (unsigned char) (tmp >> 24)); +} + +static void stv0297_set_sweeprate(struct stv0297_state *state, short fshift, long symrate) +{ + long tmp; + + tmp = (long) fshift *262144L; /* 262144 = 2*18 */ + tmp /= symrate; + tmp *= 1024; /* 1024 = 2*10 */ + + // adjust + if (tmp >= 0) { + tmp += 500000; + } else { + tmp -= 500000; + } + tmp /= 1000000; + + stv0297_writereg(state, 0x60, tmp & 0xFF); + stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0); +} + +static void stv0297_set_carrieroffset(struct stv0297_state *state, long offset) +{ + long tmp; + + /* symrate is hardcoded to 10000 */ + tmp = offset * 26844L; /* (2**28)/10000 */ + if (tmp < 0) + tmp += 0x10000000; + tmp &= 0x0FFFFFFF; + + stv0297_writereg(state, 0x66, (unsigned char) (tmp & 0xFF)); + stv0297_writereg(state, 0x67, (unsigned char) (tmp >> 8)); + stv0297_writereg(state, 0x68, (unsigned char) (tmp >> 16)); + stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f); +} + +/* +static long stv0297_get_carrieroffset(struct stv0297_state *state) +{ + s64 tmp; + + stv0297_writereg(state, 0x6B, 0x00); + + tmp = stv0297_readreg(state, 0x66); + tmp |= (stv0297_readreg(state, 0x67) << 8); + tmp |= (stv0297_readreg(state, 0x68) << 16); + tmp |= (stv0297_readreg(state, 0x69) & 0x0F) << 24; + + tmp *= stv0297_get_symbolrate(state); + tmp >>= 28; + + return (s32) tmp; +} +*/ + +static void stv0297_set_initialdemodfreq(struct stv0297_state *state, long freq) +{ + s32 tmp; + + if (freq > 10000) + freq -= STV0297_CLOCK_KHZ; + + tmp = (STV0297_CLOCK_KHZ * 1000) / (1 << 16); + tmp = (freq * 1000) / tmp; + if (tmp > 0xffff) + tmp = 0xffff; + + stv0297_writereg_mask(state, 0x25, 0x80, 0x80); + stv0297_writereg(state, 0x21, tmp >> 8); + stv0297_writereg(state, 0x20, tmp); +} + +static int stv0297_set_qam(struct stv0297_state *state, fe_modulation_t modulation) +{ + int val = 0; + + switch (modulation) { + case QAM_16: + val = 0; + break; + + case QAM_32: + val = 1; + break; + + case QAM_64: + val = 4; + break; + + case QAM_128: + val = 2; + break; + + case QAM_256: + val = 3; + break; + + default: + return -EINVAL; + } + + stv0297_writereg_mask(state, 0x00, 0x70, val << 4); + + return 0; +} + +static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_inversion_t inversion) +{ + int val = 0; + + switch (inversion) { + case INVERSION_OFF: + val = 0; + break; + + case INVERSION_ON: + val = 1; + break; + + default: + return -EINVAL; + } + + stv0297_writereg_mask(state, 0x83, 0x08, val << 3); + + return 0; +} + +static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv0297_state *state = fe->demodulator_priv; + + if (enable) { + stv0297_writereg(state, 0x87, 0x78); + stv0297_writereg(state, 0x86, 0xc8); + } + + return 0; +} + +static int stv0297_init(struct dvb_frontend *fe) +{ + struct stv0297_state *state = fe->demodulator_priv; + int i; + + /* load init table */ + for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2) + stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]); + msleep(200); + + state->last_ber = 0; + + return 0; +} + +static int stv0297_sleep(struct dvb_frontend *fe) +{ + struct stv0297_state *state = fe->demodulator_priv; + + stv0297_writereg_mask(state, 0x80, 1, 1); + + return 0; +} + +static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status) +{ + struct stv0297_state *state = fe->demodulator_priv; + + u8 sync = stv0297_readreg(state, 0xDF); + + *status = 0; + if (sync & 0x80) + *status |= + FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; + return 0; +} + +static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber) +{ + struct stv0297_state *state = fe->demodulator_priv; + u8 BER[3]; + + stv0297_readregs(state, 0xA0, BER, 3); + if (!(BER[0] & 0x80)) { + state->last_ber = BER[2] << 8 | BER[1]; + stv0297_writereg_mask(state, 0xA0, 0x80, 0x80); + } + + *ber = state->last_ber; + + return 0; +} + + +static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength) +{ + struct stv0297_state *state = fe->demodulator_priv; + u8 STRENGTH[3]; + u16 tmp; + + stv0297_readregs(state, 0x41, STRENGTH, 3); + tmp = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0]; + if (STRENGTH[2] & 0x20) { + if (tmp < 0x200) + tmp = 0; + else + tmp = tmp - 0x200; + } else { + if (tmp > 0x1ff) + tmp = 0; + else + tmp = 0x1ff - tmp; + } + *strength = (tmp << 7) | (tmp >> 2); + return 0; +} + +static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + struct stv0297_state *state = fe->demodulator_priv; + u8 SNR[2]; + + stv0297_readregs(state, 0x07, SNR, 2); + *snr = SNR[1] << 8 | SNR[0]; + + return 0; +} + +static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) +{ + struct stv0297_state *state = fe->demodulator_priv; + + stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */ + + *ucblocks = (stv0297_readreg(state, 0xD5) << 8) + | stv0297_readreg(state, 0xD4); + + stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */ + stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */ + + return 0; +} + +static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stv0297_state *state = fe->demodulator_priv; + int u_threshold; + int initial_u; + int blind_u; + int delay; + int sweeprate; + int carrieroffset; + unsigned long starttime; + unsigned long timeout; + fe_spectral_inversion_t inversion; + + switch (p->u.qam.modulation) { + case QAM_16: + case QAM_32: + case QAM_64: + delay = 100; + sweeprate = 1000; + break; + + case QAM_128: + case QAM_256: + delay = 200; + sweeprate = 500; + break; + + default: + return -EINVAL; + } + + // determine inversion dependent parameters + inversion = p->inversion; + if (state->config->invert) + inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; + carrieroffset = -330; + switch (inversion) { + case INVERSION_OFF: + break; + + case INVERSION_ON: + sweeprate = -sweeprate; + carrieroffset = -carrieroffset; + break; + + default: + return -EINVAL; + } + + stv0297_init(fe); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* clear software interrupts */ + stv0297_writereg(state, 0x82, 0x0); + + /* set initial demodulation frequency */ + stv0297_set_initialdemodfreq(state, 7250); + + /* setup AGC */ + stv0297_writereg_mask(state, 0x43, 0x10, 0x00); + stv0297_writereg(state, 0x41, 0x00); + stv0297_writereg_mask(state, 0x42, 0x03, 0x01); + stv0297_writereg_mask(state, 0x36, 0x60, 0x00); + stv0297_writereg_mask(state, 0x36, 0x18, 0x00); + stv0297_writereg_mask(state, 0x71, 0x80, 0x80); + stv0297_writereg(state, 0x72, 0x00); + stv0297_writereg(state, 0x73, 0x00); + stv0297_writereg_mask(state, 0x74, 0x0F, 0x00); + stv0297_writereg_mask(state, 0x43, 0x08, 0x00); + stv0297_writereg_mask(state, 0x71, 0x80, 0x00); + + /* setup STL */ + stv0297_writereg_mask(state, 0x5a, 0x20, 0x20); + stv0297_writereg_mask(state, 0x5b, 0x02, 0x02); + stv0297_writereg_mask(state, 0x5b, 0x02, 0x00); + stv0297_writereg_mask(state, 0x5b, 0x01, 0x00); + stv0297_writereg_mask(state, 0x5a, 0x40, 0x40); + + /* disable frequency sweep */ + stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); + + /* reset deinterleaver */ + stv0297_writereg_mask(state, 0x81, 0x01, 0x01); + stv0297_writereg_mask(state, 0x81, 0x01, 0x00); + + /* ??? */ + stv0297_writereg_mask(state, 0x83, 0x20, 0x20); + stv0297_writereg_mask(state, 0x83, 0x20, 0x00); + + /* reset equaliser */ + u_threshold = stv0297_readreg(state, 0x00) & 0xf; + initial_u = stv0297_readreg(state, 0x01) >> 4; + blind_u = stv0297_readreg(state, 0x01) & 0xf; + stv0297_writereg_mask(state, 0x84, 0x01, 0x01); + stv0297_writereg_mask(state, 0x84, 0x01, 0x00); + stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold); + stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4); + stv0297_writereg_mask(state, 0x01, 0x0f, blind_u); + + /* data comes from internal A/D */ + stv0297_writereg_mask(state, 0x87, 0x80, 0x00); + + /* clear phase registers */ + stv0297_writereg(state, 0x63, 0x00); + stv0297_writereg(state, 0x64, 0x00); + stv0297_writereg(state, 0x65, 0x00); + stv0297_writereg(state, 0x66, 0x00); + stv0297_writereg(state, 0x67, 0x00); + stv0297_writereg(state, 0x68, 0x00); + stv0297_writereg_mask(state, 0x69, 0x0f, 0x00); + + /* set parameters */ + stv0297_set_qam(state, p->u.qam.modulation); + stv0297_set_symbolrate(state, p->u.qam.symbol_rate / 1000); + stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000); + stv0297_set_carrieroffset(state, carrieroffset); + stv0297_set_inversion(state, inversion); + + /* kick off lock */ + /* Disable corner detection for higher QAMs */ + if (p->u.qam.modulation == QAM_128 || + p->u.qam.modulation == QAM_256) + stv0297_writereg_mask(state, 0x88, 0x08, 0x00); + else + stv0297_writereg_mask(state, 0x88, 0x08, 0x08); + + stv0297_writereg_mask(state, 0x5a, 0x20, 0x00); + stv0297_writereg_mask(state, 0x6a, 0x01, 0x01); + stv0297_writereg_mask(state, 0x43, 0x40, 0x40); + stv0297_writereg_mask(state, 0x5b, 0x30, 0x00); + stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c); + stv0297_writereg_mask(state, 0x03, 0x03, 0x03); + stv0297_writereg_mask(state, 0x43, 0x10, 0x10); + + /* wait for WGAGC lock */ + starttime = jiffies; + timeout = jiffies + msecs_to_jiffies(2000); + while (time_before(jiffies, timeout)) { + msleep(10); + if (stv0297_readreg(state, 0x43) & 0x08) + break; + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + msleep(20); + + /* wait for equaliser partial convergence */ + timeout = jiffies + msecs_to_jiffies(500); + while (time_before(jiffies, timeout)) { + msleep(10); + + if (stv0297_readreg(state, 0x82) & 0x04) { + break; + } + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + + /* wait for equaliser full convergence */ + timeout = jiffies + msecs_to_jiffies(delay); + while (time_before(jiffies, timeout)) { + msleep(10); + + if (stv0297_readreg(state, 0x82) & 0x08) { + break; + } + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + + /* disable sweep */ + stv0297_writereg_mask(state, 0x6a, 1, 0); + stv0297_writereg_mask(state, 0x88, 8, 0); + + /* wait for main lock */ + timeout = jiffies + msecs_to_jiffies(20); + while (time_before(jiffies, timeout)) { + msleep(10); + + if (stv0297_readreg(state, 0xDF) & 0x80) { + break; + } + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + msleep(100); + + /* is it still locked after that delay? */ + if (!(stv0297_readreg(state, 0xDF) & 0x80)) { + goto timeout; + } + + /* success!! */ + stv0297_writereg_mask(state, 0x5a, 0x40, 0x00); + state->base_freq = p->frequency; + return 0; + +timeout: + stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); + return 0; +} + +static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stv0297_state *state = fe->demodulator_priv; + int reg_00, reg_83; + + reg_00 = stv0297_readreg(state, 0x00); + reg_83 = stv0297_readreg(state, 0x83); + + p->frequency = state->base_freq; + p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; + if (state->config->invert) + p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; + p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000; + p->u.qam.fec_inner = FEC_NONE; + + switch ((reg_00 >> 4) & 0x7) { + case 0: + p->u.qam.modulation = QAM_16; + break; + case 1: + p->u.qam.modulation = QAM_32; + break; + case 2: + p->u.qam.modulation = QAM_128; + break; + case 3: + p->u.qam.modulation = QAM_256; + break; + case 4: + p->u.qam.modulation = QAM_64; + break; + } + + return 0; +} + +static void stv0297_release(struct dvb_frontend *fe) +{ + struct stv0297_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops stv0297_ops; + +struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, + struct i2c_adapter *i2c) +{ + struct stv0297_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct stv0297_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->last_ber = 0; + state->base_freq = 0; + + /* check if the demod is there */ + if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops stv0297_ops = { + + .info = { + .name = "ST STV0297 DVB-C", + .type = FE_QAM, + .frequency_min = 47000000, + .frequency_max = 862000000, + .frequency_stepsize = 62500, + .symbol_rate_min = 870000, + .symbol_rate_max = 11700000, + .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO}, + + .release = stv0297_release, + + .init = stv0297_init, + .sleep = stv0297_sleep, + .i2c_gate_ctrl = stv0297_i2c_gate_ctrl, + + .set_frontend = stv0297_set_frontend, + .get_frontend = stv0297_get_frontend, + + .read_status = stv0297_read_status, + .read_ber = stv0297_read_ber, + .read_signal_strength = stv0297_read_signal_strength, + .read_snr = stv0297_read_snr, + .read_ucblocks = stv0297_read_ucblocks, +}; + +MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver"); +MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(stv0297_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0297.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0297.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0297.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0297.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,57 @@ +/* + Driver for STV0297 demodulator + + Copyright (C) 2003-2004 Dennis Noermann + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef STV0297_H +#define STV0297_H + +#include +#include "dvb_frontend.h" + +struct stv0297_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* inittab - array of pairs of values. + * First of each pair is the register, second is the value. + * List should be terminated with an 0xff, 0xff pair. + */ + u8* inittab; + + /* does the "inversion" need inverted? */ + u8 invert:1; + + /* set to 1 if the device requires an i2c STOP during reading */ + u8 stop_during_read:1; +}; + +#if defined(CONFIG_DVB_STV0297) || (defined(CONFIG_DVB_STV0297_MODULE) && defined(MODULE)) +extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_STV0297 + +#endif // STV0297_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0299.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0299.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0299.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0299.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,760 @@ +/* + Driver for ST STV0299 demodulator + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + , + , + + + + Philips SU1278/SH + + Copyright (C) 2002 by Peter Schildmann + + + LG TDQF-S001F + + Copyright (C) 2002 Felix Domke + & Andreas Oberritter + + + Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B + + Copyright (C) 2003 Vadim Catana : + + Support for Philips SU1278 on Technotrend hardware + + Copyright (C) 2004 Andrew de Quincey + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "stv0299.h" + +struct stv0299_state { + struct i2c_adapter* i2c; + const struct stv0299_config* config; + struct dvb_frontend frontend; + + u8 initialised:1; + u32 tuner_frequency; + u32 symbol_rate; + fe_code_rate_t fec_inner; + int errmode; + u32 ucblocks; + u8 mcr_reg; +}; + +#define STATUS_BER 0 +#define STATUS_UCBLOCKS 1 + +static int debug; +static int debug_legacy_dish_switch; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "stv0299: " args); \ + } while (0) + + +static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) +{ + int ret; + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + + ret = i2c_transfer (state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len) +{ + struct stv0299_state* state = fe->demodulator_priv; + + if (len != 2) + return -EINVAL; + + return stv0299_writeregI(state, buf[0], buf[1]); +} + +static u8 stv0299_readreg (struct stv0299_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + ret = i2c_transfer (state->i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __func__, reg, ret); + + return b1[0]; +} + +static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len) +{ + int ret; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; + + ret = i2c_transfer (state->i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (ret == %i)\n", __func__, ret); + + return ret == 2 ? 0 : ret; +} + +static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) +{ + dprintk ("%s\n", __func__); + + switch (fec) { + case FEC_AUTO: + { + return stv0299_writeregI (state, 0x31, 0x1f); + } + case FEC_1_2: + { + return stv0299_writeregI (state, 0x31, 0x01); + } + case FEC_2_3: + { + return stv0299_writeregI (state, 0x31, 0x02); + } + case FEC_3_4: + { + return stv0299_writeregI (state, 0x31, 0x04); + } + case FEC_5_6: + { + return stv0299_writeregI (state, 0x31, 0x08); + } + case FEC_7_8: + { + return stv0299_writeregI (state, 0x31, 0x10); + } + default: + { + return -EINVAL; + } + } +} + +static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state) +{ + static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6, + FEC_7_8, FEC_1_2 }; + u8 index; + + dprintk ("%s\n", __func__); + + index = stv0299_readreg (state, 0x1b); + index &= 0x7; + + if (index > 4) + return FEC_AUTO; + + return fec_tab [index]; +} + +static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) +{ + unsigned long start = jiffies; + + dprintk ("%s\n", __func__); + + while (stv0299_readreg(state, 0x0a) & 1) { + if (jiffies - start > timeout) { + dprintk ("%s: timeout!!\n", __func__); + return -ETIMEDOUT; + } + msleep(10); + }; + + return 0; +} + +static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) +{ + unsigned long start = jiffies; + + dprintk ("%s\n", __func__); + + while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) { + if (jiffies - start > timeout) { + dprintk ("%s: timeout!!\n", __func__); + return -ETIMEDOUT; + } + msleep(10); + }; + + return 0; +} + +static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate) +{ + struct stv0299_state* state = fe->demodulator_priv; + u64 big = srate; + u32 ratio; + + // check rate is within limits + if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; + + // calculate value to program + big = big << 20; + big += (state->config->mclk-1); // round correctly + do_div(big, state->config->mclk); + ratio = big << 4; + + return state->config->set_symbol_rate(fe, srate, ratio); +} + +static int stv0299_get_symbolrate (struct stv0299_state* state) +{ + u32 Mclk = state->config->mclk / 4096L; + u32 srate; + s32 offset; + u8 sfr[3]; + s8 rtf; + + dprintk ("%s\n", __func__); + + stv0299_readregs (state, 0x1f, sfr, 3); + stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1); + + srate = (sfr[0] << 8) | sfr[1]; + srate *= Mclk; + srate /= 16; + srate += (sfr[2] >> 4) * Mclk / 256; + offset = (s32) rtf * (srate / 4096L); + offset /= 128; + + dprintk ("%s : srate = %i\n", __func__, srate); + dprintk ("%s : ofset = %i\n", __func__, offset); + + srate += offset; + + srate += 1000; + srate /= 2000; + srate *= 2000; + + return srate; +} + +static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + struct stv0299_state* state = fe->demodulator_priv; + u8 val; + int i; + + dprintk ("%s\n", __func__); + + if (stv0299_wait_diseqc_idle (state, 100) < 0) + return -ETIMEDOUT; + + val = stv0299_readreg (state, 0x08); + + if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ + return -EREMOTEIO; + + for (i=0; imsg_len; i++) { + if (stv0299_wait_diseqc_fifo (state, 100) < 0) + return -ETIMEDOUT; + + if (stv0299_writeregI (state, 0x09, m->msg[i])) + return -EREMOTEIO; + } + + if (stv0299_wait_diseqc_idle (state, 100) < 0) + return -ETIMEDOUT; + + return 0; +} + +static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + struct stv0299_state* state = fe->demodulator_priv; + u8 val; + + dprintk ("%s\n", __func__); + + if (stv0299_wait_diseqc_idle (state, 100) < 0) + return -ETIMEDOUT; + + val = stv0299_readreg (state, 0x08); + + if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ + return -EREMOTEIO; + + if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) + return -EREMOTEIO; + + if (stv0299_wait_diseqc_idle (state, 100) < 0) + return -ETIMEDOUT; + + if (stv0299_writeregI (state, 0x08, val)) + return -EREMOTEIO; + + return 0; +} + +static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct stv0299_state* state = fe->demodulator_priv; + u8 val; + + if (stv0299_wait_diseqc_idle (state, 100) < 0) + return -ETIMEDOUT; + + val = stv0299_readreg (state, 0x08); + + switch (tone) { + case SEC_TONE_ON: + return stv0299_writeregI (state, 0x08, val | 0x3); + + case SEC_TONE_OFF: + return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02); + + default: + return -EINVAL; + } +} + +static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct stv0299_state* state = fe->demodulator_priv; + u8 reg0x08; + u8 reg0x0c; + + dprintk("%s: %s\n", __func__, + voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : + voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); + + reg0x08 = stv0299_readreg (state, 0x08); + reg0x0c = stv0299_readreg (state, 0x0c); + + /** + * H/V switching over OP0, OP1 and OP2 are LNB power enable bits + */ + reg0x0c &= 0x0f; + reg0x08 = (reg0x08 & 0x3f) | (state->config->lock_output << 6); + + switch (voltage) { + case SEC_VOLTAGE_13: + if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) + reg0x0c |= 0x10; /* OP1 off, OP0 on */ + else + reg0x0c |= 0x40; /* OP1 on, OP0 off */ + break; + case SEC_VOLTAGE_18: + reg0x0c |= 0x50; /* OP1 on, OP0 on */ + break; + case SEC_VOLTAGE_OFF: + /* LNB power off! */ + reg0x08 = 0x00; + reg0x0c = 0x00; + break; + default: + return -EINVAL; + }; + + if (state->config->op0_off) + reg0x0c &= ~0x10; + + stv0299_writeregI(state, 0x08, reg0x08); + return stv0299_writeregI(state, 0x0c, reg0x0c); +} + +static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd) +{ + struct stv0299_state* state = fe->demodulator_priv; + u8 reg0x08; + u8 reg0x0c; + u8 lv_mask = 0x40; + u8 last = 1; + int i; + struct timeval nexttime; + struct timeval tv[10]; + + reg0x08 = stv0299_readreg (state, 0x08); + reg0x0c = stv0299_readreg (state, 0x0c); + reg0x0c &= 0x0f; + stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); + if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) + lv_mask = 0x10; + + cmd = cmd << 1; + if (debug_legacy_dish_switch) + printk ("%s switch command: 0x%04lx\n",__func__, cmd); + + do_gettimeofday (&nexttime); + if (debug_legacy_dish_switch) + memcpy (&tv[0], &nexttime, sizeof (struct timeval)); + stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ + + dvb_frontend_sleep_until(&nexttime, 32000); + + for (i=0; i<9; i++) { + if (debug_legacy_dish_switch) + do_gettimeofday (&tv[i+1]); + if((cmd & 0x01) != last) { + /* set voltage to (last ? 13V : 18V) */ + stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50)); + last = (last) ? 0 : 1; + } + + cmd = cmd >> 1; + + if (i != 8) + dvb_frontend_sleep_until(&nexttime, 8000); + } + if (debug_legacy_dish_switch) { + printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", + __func__, fe->dvb->num); + for (i = 1; i < 10; i++) + printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); + } + + return 0; +} + +static int stv0299_init (struct dvb_frontend* fe) +{ + struct stv0299_state* state = fe->demodulator_priv; + int i; + u8 reg; + u8 val; + + dprintk("stv0299: init chip\n"); + + stv0299_writeregI(state, 0x02, 0x30 | state->mcr_reg); + msleep(50); + + for (i = 0; ; i += 2) { + reg = state->config->inittab[i]; + val = state->config->inittab[i+1]; + if (reg == 0xff && val == 0xff) + break; + if (reg == 0x0c && state->config->op0_off) + val &= ~0x10; + if (reg == 0x2) + state->mcr_reg = val & 0xf; + stv0299_writeregI(state, reg, val); + } + + return 0; +} + +static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct stv0299_state* state = fe->demodulator_priv; + + u8 signal = 0xff - stv0299_readreg (state, 0x18); + u8 sync = stv0299_readreg (state, 0x1b); + + dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); + *status = 0; + + if (signal > 10) + *status |= FE_HAS_SIGNAL; + + if (sync & 0x80) + *status |= FE_HAS_CARRIER; + + if (sync & 0x10) + *status |= FE_HAS_VITERBI; + + if (sync & 0x08) + *status |= FE_HAS_SYNC; + + if ((sync & 0x98) == 0x98) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct stv0299_state* state = fe->demodulator_priv; + + if (state->errmode != STATUS_BER) + return -ENOSYS; + + *ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8); + + return 0; +} + +static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct stv0299_state* state = fe->demodulator_priv; + + s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8) + | stv0299_readreg (state, 0x19)); + + dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __func__, + stv0299_readreg (state, 0x18), + stv0299_readreg (state, 0x19), (int) signal); + + signal = signal * 5 / 4; + *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; + + return 0; +} + +static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct stv0299_state* state = fe->demodulator_priv; + + s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8) + | stv0299_readreg (state, 0x25)); + xsnr = 3 * (xsnr - 0xa100); + *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; + + return 0; +} + +static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct stv0299_state* state = fe->demodulator_priv; + + if (state->errmode != STATUS_UCBLOCKS) + return -ENOSYS; + + state->ucblocks += stv0299_readreg(state, 0x1e); + state->ucblocks += (stv0299_readreg(state, 0x1d) << 8); + *ucblocks = state->ucblocks; + + return 0; +} + +static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +{ + struct stv0299_state* state = fe->demodulator_priv; + int invval = 0; + + dprintk ("%s : FE_SET_FRONTEND\n", __func__); + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + // set the inversion + if (p->inversion == INVERSION_OFF) invval = 0; + else if (p->inversion == INVERSION_ON) invval = 1; + else { + printk("stv0299 does not support auto-inversion\n"); + return -EINVAL; + } + if (state->config->invert) invval = (~invval) & 1; + stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + stv0299_set_FEC (state, p->u.qpsk.fec_inner); + stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); + stv0299_writeregI(state, 0x22, 0x00); + stv0299_writeregI(state, 0x23, 0x00); + + state->tuner_frequency = p->frequency; + state->fec_inner = p->u.qpsk.fec_inner; + state->symbol_rate = p->u.qpsk.symbol_rate; + + return 0; +} + +static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +{ + struct stv0299_state* state = fe->demodulator_priv; + s32 derot_freq; + int invval; + + derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8) + | stv0299_readreg (state, 0x23)); + + derot_freq *= (state->config->mclk >> 16); + derot_freq += 500; + derot_freq /= 1000; + + p->frequency += derot_freq; + + invval = stv0299_readreg (state, 0x0c) & 1; + if (state->config->invert) invval = (~invval) & 1; + p->inversion = invval ? INVERSION_ON : INVERSION_OFF; + + p->u.qpsk.fec_inner = stv0299_get_fec (state); + p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state); + + return 0; +} + +static int stv0299_sleep(struct dvb_frontend* fe) +{ + struct stv0299_state* state = fe->demodulator_priv; + + stv0299_writeregI(state, 0x02, 0xb0 | state->mcr_reg); + state->initialised = 0; + + return 0; +} + +static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct stv0299_state* state = fe->demodulator_priv; + + if (enable) { + stv0299_writeregI(state, 0x05, 0xb5); + } else { + stv0299_writeregI(state, 0x05, 0x35); + } + udelay(1); + return 0; +} + +static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + struct stv0299_state* state = fe->demodulator_priv; + + fesettings->min_delay_ms = state->config->min_delay_ms; + if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { + fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000; + fesettings->max_drift = 5000; + } else { + fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; + fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; + } + return 0; +} + +static void stv0299_release(struct dvb_frontend* fe) +{ + struct stv0299_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops stv0299_ops; + +struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, + struct i2c_adapter* i2c) +{ + struct stv0299_state* state = NULL; + int id; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct stv0299_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->initialised = 0; + state->tuner_frequency = 0; + state->symbol_rate = 0; + state->fec_inner = 0; + state->errmode = STATUS_BER; + + /* check if the demod is there */ + stv0299_writeregI(state, 0x02, 0x30); /* standby off */ + msleep(200); + id = stv0299_readreg(state, 0x00); + + /* register 0x00 contains 0xa1 for STV0299 and STV0299B */ + /* register 0x00 might contain 0x80 when returning from standby */ + if (id != 0xa1 && id != 0x80) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops stv0299_ops = { + + .info = { + .name = "ST STV0299 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + + .release = stv0299_release, + + .init = stv0299_init, + .sleep = stv0299_sleep, + .write = stv0299_write, + .i2c_gate_ctrl = stv0299_i2c_gate_ctrl, + + .set_frontend = stv0299_set_frontend, + .get_frontend = stv0299_get_frontend, + .get_tune_settings = stv0299_get_tune_settings, + + .read_status = stv0299_read_status, + .read_ber = stv0299_read_ber, + .read_signal_strength = stv0299_read_signal_strength, + .read_snr = stv0299_read_snr, + .read_ucblocks = stv0299_read_ucblocks, + + .diseqc_send_master_cmd = stv0299_send_diseqc_msg, + .diseqc_send_burst = stv0299_send_diseqc_burst, + .set_tone = stv0299_set_tone, + .set_voltage = stv0299_set_voltage, + .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd, +}; + +module_param(debug_legacy_dish_switch, int, 0444); +MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches"); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver"); +MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, " + "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(stv0299_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0299.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0299.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0299.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0299.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,118 @@ +/* + Driver for ST STV0299 demodulator + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + , + , + + + + Philips SU1278/SH + + Copyright (C) 2002 by Peter Schildmann + + + LG TDQF-S001F + + Copyright (C) 2002 Felix Domke + & Andreas Oberritter + + + Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B + + Copyright (C) 2003 Vadim Catana : + + Support for Philips SU1278 on Technotrend hardware + + Copyright (C) 2004 Andrew de Quincey + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef STV0299_H +#define STV0299_H + +#include +#include "dvb_frontend.h" + +#define STV0299_LOCKOUTPUT_0 0 +#define STV0299_LOCKOUTPUT_1 1 +#define STV0299_LOCKOUTPUT_CF 2 +#define STV0299_LOCKOUTPUT_LK 3 + +#define STV0299_VOLT13_OP0 0 +#define STV0299_VOLT13_OP1 1 + +struct stv0299_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* inittab - array of pairs of values. + * First of each pair is the register, second is the value. + * List should be terminated with an 0xff, 0xff pair. + */ + const u8* inittab; + + /* master clock to use */ + u32 mclk; + + /* does the inversion require inversion? */ + u8 invert:1; + + /* Skip reinitialisation? */ + u8 skip_reinit:1; + + /* LOCK OUTPUT setting */ + u8 lock_output:2; + + /* Is 13v controlled by OP0 or OP1? */ + u8 volt13_op0_op1:1; + + /* Turn-off OP0? */ + u8 op0_off:1; + + /* minimum delay before retuning */ + int min_delay_ms; + + /* Set the symbol rate */ + int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio); + + /* Set device param to start dma */ + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); +}; + +#if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE)) +extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_STV0299 + +static inline int stv0299_writereg(struct dvb_frontend *fe, u8 reg, u8 val) { + int r = 0; + u8 buf[] = {reg, val}; + if (fe->ops.write) + r = fe->ops.write(fe, buf, 2); + return r; +} + +#endif // STV0299_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,3459 @@ +/* + * stv0367.c + * + * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "stv0367.h" +#include "stv0367_regs.h" +#include "stv0367_priv.h" + +static int stvdebug; +module_param_named(debug, stvdebug, int, 0644); + +static int i2cdebug; +module_param_named(i2c_debug, i2cdebug, int, 0644); + +#define dprintk(args...) \ + do { \ + if (stvdebug) \ + printk(KERN_DEBUG args); \ + } while (0) + /* DVB-C */ + +struct stv0367cab_state { + enum stv0367_cab_signal_type state; + u32 mclk; + u32 adc_clk; + s32 search_range; + s32 derot_offset; + /* results */ + int locked; /* channel found */ + u32 freq_khz; /* found frequency (in kHz) */ + u32 symbol_rate; /* found symbol rate (in Bds) */ + enum stv0367cab_mod modulation; /* modulation */ + fe_spectral_inversion_t spect_inv; /* Spectrum Inversion */ +}; + +struct stv0367ter_state { + /* DVB-T */ + enum stv0367_ter_signal_type state; + enum stv0367_ter_if_iq_mode if_iq_mode; + enum stv0367_ter_mode mode;/* mode 2K or 8K */ + fe_guard_interval_t guard; + enum stv0367_ter_hierarchy hierarchy; + u32 frequency; + fe_spectral_inversion_t sense; /* current search spectrum */ + u8 force; /* force mode/guard */ + u8 bw; /* channel width 6, 7 or 8 in MHz */ + u8 pBW; /* channel width used during previous lock */ + u32 pBER; + u32 pPER; + u32 ucblocks; + s8 echo_pos; /* echo position */ + u8 first_lock; + u8 unlock_counter; + u32 agc_val; +}; + +struct stv0367_state { + struct dvb_frontend fe; + struct i2c_adapter *i2c; + /* config settings */ + const struct stv0367_config *config; + u8 chip_id; + /* DVB-C */ + struct stv0367cab_state *cab_state; + /* DVB-T */ + struct stv0367ter_state *ter_state; +}; + +struct st_register { + u16 addr; + u8 value; +}; + +/* values for STV4100 XTAL=30M int clk=53.125M*/ +static struct st_register def0367ter[STV0367TER_NBREGS] = { + {R367TER_ID, 0x60}, + {R367TER_I2CRPT, 0xa0}, + /* {R367TER_I2CRPT, 0x22},*/ + {R367TER_TOPCTRL, 0x00},/* for xc5000; was 0x02 */ + {R367TER_IOCFG0, 0x40}, + {R367TER_DAC0R, 0x00}, + {R367TER_IOCFG1, 0x00}, + {R367TER_DAC1R, 0x00}, + {R367TER_IOCFG2, 0x62}, + {R367TER_SDFR, 0x00}, + {R367TER_STATUS, 0xf8}, + {R367TER_AUX_CLK, 0x0a}, + {R367TER_FREESYS1, 0x00}, + {R367TER_FREESYS2, 0x00}, + {R367TER_FREESYS3, 0x00}, + {R367TER_GPIO_CFG, 0x55}, + {R367TER_GPIO_CMD, 0x00}, + {R367TER_AGC2MAX, 0xff}, + {R367TER_AGC2MIN, 0x00}, + {R367TER_AGC1MAX, 0xff}, + {R367TER_AGC1MIN, 0x00}, + {R367TER_AGCR, 0xbc}, + {R367TER_AGC2TH, 0x00}, + {R367TER_AGC12C, 0x00}, + {R367TER_AGCCTRL1, 0x85}, + {R367TER_AGCCTRL2, 0x1f}, + {R367TER_AGC1VAL1, 0x00}, + {R367TER_AGC1VAL2, 0x00}, + {R367TER_AGC2VAL1, 0x6f}, + {R367TER_AGC2VAL2, 0x05}, + {R367TER_AGC2PGA, 0x00}, + {R367TER_OVF_RATE1, 0x00}, + {R367TER_OVF_RATE2, 0x00}, + {R367TER_GAIN_SRC1, 0xaa},/* for xc5000; was 0x2b */ + {R367TER_GAIN_SRC2, 0xd6},/* for xc5000; was 0x04 */ + {R367TER_INC_DEROT1, 0x55}, + {R367TER_INC_DEROT2, 0x55}, + {R367TER_PPM_CPAMP_DIR, 0x2c}, + {R367TER_PPM_CPAMP_INV, 0x00}, + {R367TER_FREESTFE_1, 0x00}, + {R367TER_FREESTFE_2, 0x1c}, + {R367TER_DCOFFSET, 0x00}, + {R367TER_EN_PROCESS, 0x05}, + {R367TER_SDI_SMOOTHER, 0x80}, + {R367TER_FE_LOOP_OPEN, 0x1c}, + {R367TER_FREQOFF1, 0x00}, + {R367TER_FREQOFF2, 0x00}, + {R367TER_FREQOFF3, 0x00}, + {R367TER_TIMOFF1, 0x00}, + {R367TER_TIMOFF2, 0x00}, + {R367TER_EPQ, 0x02}, + {R367TER_EPQAUTO, 0x01}, + {R367TER_SYR_UPDATE, 0xf5}, + {R367TER_CHPFREE, 0x00}, + {R367TER_PPM_STATE_MAC, 0x23}, + {R367TER_INR_THRESHOLD, 0xff}, + {R367TER_EPQ_TPS_ID_CELL, 0xf9}, + {R367TER_EPQ_CFG, 0x00}, + {R367TER_EPQ_STATUS, 0x01}, + {R367TER_AUTORELOCK, 0x81}, + {R367TER_BER_THR_VMSB, 0x00}, + {R367TER_BER_THR_MSB, 0x00}, + {R367TER_BER_THR_LSB, 0x00}, + {R367TER_CCD, 0x83}, + {R367TER_SPECTR_CFG, 0x00}, + {R367TER_CHC_DUMMY, 0x18}, + {R367TER_INC_CTL, 0x88}, + {R367TER_INCTHRES_COR1, 0xb4}, + {R367TER_INCTHRES_COR2, 0x96}, + {R367TER_INCTHRES_DET1, 0x0e}, + {R367TER_INCTHRES_DET2, 0x11}, + {R367TER_IIR_CELLNB, 0x8d}, + {R367TER_IIRCX_COEFF1_MSB, 0x00}, + {R367TER_IIRCX_COEFF1_LSB, 0x00}, + {R367TER_IIRCX_COEFF2_MSB, 0x09}, + {R367TER_IIRCX_COEFF2_LSB, 0x18}, + {R367TER_IIRCX_COEFF3_MSB, 0x14}, + {R367TER_IIRCX_COEFF3_LSB, 0x9c}, + {R367TER_IIRCX_COEFF4_MSB, 0x00}, + {R367TER_IIRCX_COEFF4_LSB, 0x00}, + {R367TER_IIRCX_COEFF5_MSB, 0x36}, + {R367TER_IIRCX_COEFF5_LSB, 0x42}, + {R367TER_FEPATH_CFG, 0x00}, + {R367TER_PMC1_FUNC, 0x65}, + {R367TER_PMC1_FOR, 0x00}, + {R367TER_PMC2_FUNC, 0x00}, + {R367TER_STATUS_ERR_DA, 0xe0}, + {R367TER_DIG_AGC_R, 0xfe}, + {R367TER_COMAGC_TARMSB, 0x0b}, + {R367TER_COM_AGC_TAR_ENMODE, 0x41}, + {R367TER_COM_AGC_CFG, 0x3e}, + {R367TER_COM_AGC_GAIN1, 0x39}, + {R367TER_AUT_AGC_TARGETMSB, 0x0b}, + {R367TER_LOCK_DET_MSB, 0x01}, + {R367TER_AGCTAR_LOCK_LSBS, 0x40}, + {R367TER_AUT_GAIN_EN, 0xf4}, + {R367TER_AUT_CFG, 0xf0}, + {R367TER_LOCKN, 0x23}, + {R367TER_INT_X_3, 0x00}, + {R367TER_INT_X_2, 0x03}, + {R367TER_INT_X_1, 0x8d}, + {R367TER_INT_X_0, 0xa0}, + {R367TER_MIN_ERRX_MSB, 0x00}, + {R367TER_COR_CTL, 0x23}, + {R367TER_COR_STAT, 0xf6}, + {R367TER_COR_INTEN, 0x00}, + {R367TER_COR_INTSTAT, 0x3f}, + {R367TER_COR_MODEGUARD, 0x03}, + {R367TER_AGC_CTL, 0x08}, + {R367TER_AGC_MANUAL1, 0x00}, + {R367TER_AGC_MANUAL2, 0x00}, + {R367TER_AGC_TARG, 0x16}, + {R367TER_AGC_GAIN1, 0x53}, + {R367TER_AGC_GAIN2, 0x1d}, + {R367TER_RESERVED_1, 0x00}, + {R367TER_RESERVED_2, 0x00}, + {R367TER_RESERVED_3, 0x00}, + {R367TER_CAS_CTL, 0x44}, + {R367TER_CAS_FREQ, 0xb3}, + {R367TER_CAS_DAGCGAIN, 0x12}, + {R367TER_SYR_CTL, 0x04}, + {R367TER_SYR_STAT, 0x10}, + {R367TER_SYR_NCO1, 0x00}, + {R367TER_SYR_NCO2, 0x00}, + {R367TER_SYR_OFFSET1, 0x00}, + {R367TER_SYR_OFFSET2, 0x00}, + {R367TER_FFT_CTL, 0x00}, + {R367TER_SCR_CTL, 0x70}, + {R367TER_PPM_CTL1, 0xf8}, + {R367TER_TRL_CTL, 0x14},/* for xc5000; was 0xac */ + {R367TER_TRL_NOMRATE1, 0xae},/* for xc5000; was 0x1e */ + {R367TER_TRL_NOMRATE2, 0x56},/* for xc5000; was 0x58 */ + {R367TER_TRL_TIME1, 0x1d}, + {R367TER_TRL_TIME2, 0xfc}, + {R367TER_CRL_CTL, 0x24}, + {R367TER_CRL_FREQ1, 0xad}, + {R367TER_CRL_FREQ2, 0x9d}, + {R367TER_CRL_FREQ3, 0xff}, + {R367TER_CHC_CTL, 0x01}, + {R367TER_CHC_SNR, 0xf0}, + {R367TER_BDI_CTL, 0x00}, + {R367TER_DMP_CTL, 0x00}, + {R367TER_TPS_RCVD1, 0x30}, + {R367TER_TPS_RCVD2, 0x02}, + {R367TER_TPS_RCVD3, 0x01}, + {R367TER_TPS_RCVD4, 0x00}, + {R367TER_TPS_ID_CELL1, 0x00}, + {R367TER_TPS_ID_CELL2, 0x00}, + {R367TER_TPS_RCVD5_SET1, 0x02}, + {R367TER_TPS_SET2, 0x02}, + {R367TER_TPS_SET3, 0x01}, + {R367TER_TPS_CTL, 0x00}, + {R367TER_CTL_FFTOSNUM, 0x34}, + {R367TER_TESTSELECT, 0x09}, + {R367TER_MSC_REV, 0x0a}, + {R367TER_PIR_CTL, 0x00}, + {R367TER_SNR_CARRIER1, 0xa1}, + {R367TER_SNR_CARRIER2, 0x9a}, + {R367TER_PPM_CPAMP, 0x2c}, + {R367TER_TSM_AP0, 0x00}, + {R367TER_TSM_AP1, 0x00}, + {R367TER_TSM_AP2 , 0x00}, + {R367TER_TSM_AP3, 0x00}, + {R367TER_TSM_AP4, 0x00}, + {R367TER_TSM_AP5, 0x00}, + {R367TER_TSM_AP6, 0x00}, + {R367TER_TSM_AP7, 0x00}, + {R367TER_TSTRES, 0x00}, + {R367TER_ANACTRL, 0x0D},/* PLL stoped, restart at init!!! */ + {R367TER_TSTBUS, 0x00}, + {R367TER_TSTRATE, 0x00}, + {R367TER_CONSTMODE, 0x01}, + {R367TER_CONSTCARR1, 0x00}, + {R367TER_CONSTCARR2, 0x00}, + {R367TER_ICONSTEL, 0x0a}, + {R367TER_QCONSTEL, 0x15}, + {R367TER_TSTBISTRES0, 0x00}, + {R367TER_TSTBISTRES1, 0x00}, + {R367TER_TSTBISTRES2, 0x28}, + {R367TER_TSTBISTRES3, 0x00}, + {R367TER_RF_AGC1, 0xff}, + {R367TER_RF_AGC2, 0x83}, + {R367TER_ANADIGCTRL, 0x19}, + {R367TER_PLLMDIV, 0x01},/* for xc5000; was 0x0c */ + {R367TER_PLLNDIV, 0x06},/* for xc5000; was 0x55 */ + {R367TER_PLLSETUP, 0x18}, + {R367TER_DUAL_AD12, 0x0C},/* for xc5000 AGC voltage 1.6V */ + {R367TER_TSTBIST, 0x00}, + {R367TER_PAD_COMP_CTRL, 0x00}, + {R367TER_PAD_COMP_WR, 0x00}, + {R367TER_PAD_COMP_RD, 0xe0}, + {R367TER_SYR_TARGET_FFTADJT_MSB, 0x00}, + {R367TER_SYR_TARGET_FFTADJT_LSB, 0x00}, + {R367TER_SYR_TARGET_CHCADJT_MSB, 0x00}, + {R367TER_SYR_TARGET_CHCADJT_LSB, 0x00}, + {R367TER_SYR_FLAG, 0x00}, + {R367TER_CRL_TARGET1, 0x00}, + {R367TER_CRL_TARGET2, 0x00}, + {R367TER_CRL_TARGET3, 0x00}, + {R367TER_CRL_TARGET4, 0x00}, + {R367TER_CRL_FLAG, 0x00}, + {R367TER_TRL_TARGET1, 0x00}, + {R367TER_TRL_TARGET2, 0x00}, + {R367TER_TRL_CHC, 0x00}, + {R367TER_CHC_SNR_TARG, 0x00}, + {R367TER_TOP_TRACK, 0x00}, + {R367TER_TRACKER_FREE1, 0x00}, + {R367TER_ERROR_CRL1, 0x00}, + {R367TER_ERROR_CRL2, 0x00}, + {R367TER_ERROR_CRL3, 0x00}, + {R367TER_ERROR_CRL4, 0x00}, + {R367TER_DEC_NCO1, 0x2c}, + {R367TER_DEC_NCO2, 0x0f}, + {R367TER_DEC_NCO3, 0x20}, + {R367TER_SNR, 0xf1}, + {R367TER_SYR_FFTADJ1, 0x00}, + {R367TER_SYR_FFTADJ2, 0x00}, + {R367TER_SYR_CHCADJ1, 0x00}, + {R367TER_SYR_CHCADJ2, 0x00}, + {R367TER_SYR_OFF, 0x00}, + {R367TER_PPM_OFFSET1, 0x00}, + {R367TER_PPM_OFFSET2, 0x03}, + {R367TER_TRACKER_FREE2, 0x00}, + {R367TER_DEBG_LT10, 0x00}, + {R367TER_DEBG_LT11, 0x00}, + {R367TER_DEBG_LT12, 0x00}, + {R367TER_DEBG_LT13, 0x00}, + {R367TER_DEBG_LT14, 0x00}, + {R367TER_DEBG_LT15, 0x00}, + {R367TER_DEBG_LT16, 0x00}, + {R367TER_DEBG_LT17, 0x00}, + {R367TER_DEBG_LT18, 0x00}, + {R367TER_DEBG_LT19, 0x00}, + {R367TER_DEBG_LT1A, 0x00}, + {R367TER_DEBG_LT1B, 0x00}, + {R367TER_DEBG_LT1C, 0x00}, + {R367TER_DEBG_LT1D, 0x00}, + {R367TER_DEBG_LT1E, 0x00}, + {R367TER_DEBG_LT1F, 0x00}, + {R367TER_RCCFGH, 0x00}, + {R367TER_RCCFGM, 0x00}, + {R367TER_RCCFGL, 0x00}, + {R367TER_RCINSDELH, 0x00}, + {R367TER_RCINSDELM, 0x00}, + {R367TER_RCINSDELL, 0x00}, + {R367TER_RCSTATUS, 0x00}, + {R367TER_RCSPEED, 0x6f}, + {R367TER_RCDEBUGM, 0xe7}, + {R367TER_RCDEBUGL, 0x9b}, + {R367TER_RCOBSCFG, 0x00}, + {R367TER_RCOBSM, 0x00}, + {R367TER_RCOBSL, 0x00}, + {R367TER_RCFECSPY, 0x00}, + {R367TER_RCFSPYCFG, 0x00}, + {R367TER_RCFSPYDATA, 0x00}, + {R367TER_RCFSPYOUT, 0x00}, + {R367TER_RCFSTATUS, 0x00}, + {R367TER_RCFGOODPACK, 0x00}, + {R367TER_RCFPACKCNT, 0x00}, + {R367TER_RCFSPYMISC, 0x00}, + {R367TER_RCFBERCPT4, 0x00}, + {R367TER_RCFBERCPT3, 0x00}, + {R367TER_RCFBERCPT2, 0x00}, + {R367TER_RCFBERCPT1, 0x00}, + {R367TER_RCFBERCPT0, 0x00}, + {R367TER_RCFBERERR2, 0x00}, + {R367TER_RCFBERERR1, 0x00}, + {R367TER_RCFBERERR0, 0x00}, + {R367TER_RCFSTATESM, 0x00}, + {R367TER_RCFSTATESL, 0x00}, + {R367TER_RCFSPYBER, 0x00}, + {R367TER_RCFSPYDISTM, 0x00}, + {R367TER_RCFSPYDISTL, 0x00}, + {R367TER_RCFSPYOBS7, 0x00}, + {R367TER_RCFSPYOBS6, 0x00}, + {R367TER_RCFSPYOBS5, 0x00}, + {R367TER_RCFSPYOBS4, 0x00}, + {R367TER_RCFSPYOBS3, 0x00}, + {R367TER_RCFSPYOBS2, 0x00}, + {R367TER_RCFSPYOBS1, 0x00}, + {R367TER_RCFSPYOBS0, 0x00}, + {R367TER_TSGENERAL, 0x00}, + {R367TER_RC1SPEED, 0x6f}, + {R367TER_TSGSTATUS, 0x18}, + {R367TER_FECM, 0x01}, + {R367TER_VTH12, 0xff}, + {R367TER_VTH23, 0xa1}, + {R367TER_VTH34, 0x64}, + {R367TER_VTH56, 0x40}, + {R367TER_VTH67, 0x00}, + {R367TER_VTH78, 0x2c}, + {R367TER_VITCURPUN, 0x12}, + {R367TER_VERROR, 0x01}, + {R367TER_PRVIT, 0x3f}, + {R367TER_VAVSRVIT, 0x00}, + {R367TER_VSTATUSVIT, 0xbd}, + {R367TER_VTHINUSE, 0xa1}, + {R367TER_KDIV12, 0x20}, + {R367TER_KDIV23, 0x40}, + {R367TER_KDIV34, 0x20}, + {R367TER_KDIV56, 0x30}, + {R367TER_KDIV67, 0x00}, + {R367TER_KDIV78, 0x30}, + {R367TER_SIGPOWER, 0x54}, + {R367TER_DEMAPVIT, 0x40}, + {R367TER_VITSCALE, 0x00}, + {R367TER_FFEC1PRG, 0x00}, + {R367TER_FVITCURPUN, 0x12}, + {R367TER_FVERROR, 0x01}, + {R367TER_FVSTATUSVIT, 0xbd}, + {R367TER_DEBUG_LT1, 0x00}, + {R367TER_DEBUG_LT2, 0x00}, + {R367TER_DEBUG_LT3, 0x00}, + {R367TER_TSTSFMET, 0x00}, + {R367TER_SELOUT, 0x00}, + {R367TER_TSYNC, 0x00}, + {R367TER_TSTERR, 0x00}, + {R367TER_TSFSYNC, 0x00}, + {R367TER_TSTSFERR, 0x00}, + {R367TER_TSTTSSF1, 0x01}, + {R367TER_TSTTSSF2, 0x1f}, + {R367TER_TSTTSSF3, 0x00}, + {R367TER_TSTTS1, 0x00}, + {R367TER_TSTTS2, 0x1f}, + {R367TER_TSTTS3, 0x01}, + {R367TER_TSTTS4, 0x00}, + {R367TER_TSTTSRC, 0x00}, + {R367TER_TSTTSRS, 0x00}, + {R367TER_TSSTATEM, 0xb0}, + {R367TER_TSSTATEL, 0x40}, + {R367TER_TSCFGH, 0xC0}, + {R367TER_TSCFGM, 0xc0},/* for xc5000; was 0x00 */ + {R367TER_TSCFGL, 0x20}, + {R367TER_TSSYNC, 0x00}, + {R367TER_TSINSDELH, 0x00}, + {R367TER_TSINSDELM, 0x00}, + {R367TER_TSINSDELL, 0x00}, + {R367TER_TSDIVN, 0x03}, + {R367TER_TSDIVPM, 0x00}, + {R367TER_TSDIVPL, 0x00}, + {R367TER_TSDIVQM, 0x00}, + {R367TER_TSDIVQL, 0x00}, + {R367TER_TSDILSTKM, 0x00}, + {R367TER_TSDILSTKL, 0x00}, + {R367TER_TSSPEED, 0x40},/* for xc5000; was 0x6f */ + {R367TER_TSSTATUS, 0x81}, + {R367TER_TSSTATUS2, 0x6a}, + {R367TER_TSBITRATEM, 0x0f}, + {R367TER_TSBITRATEL, 0xc6}, + {R367TER_TSPACKLENM, 0x00}, + {R367TER_TSPACKLENL, 0xfc}, + {R367TER_TSBLOCLENM, 0x0a}, + {R367TER_TSBLOCLENL, 0x80}, + {R367TER_TSDLYH, 0x90}, + {R367TER_TSDLYM, 0x68}, + {R367TER_TSDLYL, 0x01}, + {R367TER_TSNPDAV, 0x00}, + {R367TER_TSBUFSTATH, 0x00}, + {R367TER_TSBUFSTATM, 0x00}, + {R367TER_TSBUFSTATL, 0x00}, + {R367TER_TSDEBUGM, 0xcf}, + {R367TER_TSDEBUGL, 0x1e}, + {R367TER_TSDLYSETH, 0x00}, + {R367TER_TSDLYSETM, 0x68}, + {R367TER_TSDLYSETL, 0x00}, + {R367TER_TSOBSCFG, 0x00}, + {R367TER_TSOBSM, 0x47}, + {R367TER_TSOBSL, 0x1f}, + {R367TER_ERRCTRL1, 0x95}, + {R367TER_ERRCNT1H, 0x80}, + {R367TER_ERRCNT1M, 0x00}, + {R367TER_ERRCNT1L, 0x00}, + {R367TER_ERRCTRL2, 0x95}, + {R367TER_ERRCNT2H, 0x00}, + {R367TER_ERRCNT2M, 0x00}, + {R367TER_ERRCNT2L, 0x00}, + {R367TER_FECSPY, 0x88}, + {R367TER_FSPYCFG, 0x2c}, + {R367TER_FSPYDATA, 0x3a}, + {R367TER_FSPYOUT, 0x06}, + {R367TER_FSTATUS, 0x61}, + {R367TER_FGOODPACK, 0xff}, + {R367TER_FPACKCNT, 0xff}, + {R367TER_FSPYMISC, 0x66}, + {R367TER_FBERCPT4, 0x00}, + {R367TER_FBERCPT3, 0x00}, + {R367TER_FBERCPT2, 0x36}, + {R367TER_FBERCPT1, 0x36}, + {R367TER_FBERCPT0, 0x14}, + {R367TER_FBERERR2, 0x00}, + {R367TER_FBERERR1, 0x03}, + {R367TER_FBERERR0, 0x28}, + {R367TER_FSTATESM, 0x00}, + {R367TER_FSTATESL, 0x02}, + {R367TER_FSPYBER, 0x00}, + {R367TER_FSPYDISTM, 0x01}, + {R367TER_FSPYDISTL, 0x9f}, + {R367TER_FSPYOBS7, 0xc9}, + {R367TER_FSPYOBS6, 0x99}, + {R367TER_FSPYOBS5, 0x08}, + {R367TER_FSPYOBS4, 0xec}, + {R367TER_FSPYOBS3, 0x01}, + {R367TER_FSPYOBS2, 0x0f}, + {R367TER_FSPYOBS1, 0xf5}, + {R367TER_FSPYOBS0, 0x08}, + {R367TER_SFDEMAP, 0x40}, + {R367TER_SFERROR, 0x00}, + {R367TER_SFAVSR, 0x30}, + {R367TER_SFECSTATUS, 0xcc}, + {R367TER_SFKDIV12, 0x20}, + {R367TER_SFKDIV23, 0x40}, + {R367TER_SFKDIV34, 0x20}, + {R367TER_SFKDIV56, 0x20}, + {R367TER_SFKDIV67, 0x00}, + {R367TER_SFKDIV78, 0x20}, + {R367TER_SFDILSTKM, 0x00}, + {R367TER_SFDILSTKL, 0x00}, + {R367TER_SFSTATUS, 0xb5}, + {R367TER_SFDLYH, 0x90}, + {R367TER_SFDLYM, 0x60}, + {R367TER_SFDLYL, 0x01}, + {R367TER_SFDLYSETH, 0xc0}, + {R367TER_SFDLYSETM, 0x60}, + {R367TER_SFDLYSETL, 0x00}, + {R367TER_SFOBSCFG, 0x00}, + {R367TER_SFOBSM, 0x47}, + {R367TER_SFOBSL, 0x05}, + {R367TER_SFECINFO, 0x40}, + {R367TER_SFERRCTRL, 0x74}, + {R367TER_SFERRCNTH, 0x80}, + {R367TER_SFERRCNTM , 0x00}, + {R367TER_SFERRCNTL, 0x00}, + {R367TER_SYMBRATEM, 0x2f}, + {R367TER_SYMBRATEL, 0x50}, + {R367TER_SYMBSTATUS, 0x7f}, + {R367TER_SYMBCFG, 0x00}, + {R367TER_SYMBFIFOM, 0xf4}, + {R367TER_SYMBFIFOL, 0x0d}, + {R367TER_SYMBOFFSM, 0xf0}, + {R367TER_SYMBOFFSL, 0x2d}, + {R367TER_DEBUG_LT4, 0x00}, + {R367TER_DEBUG_LT5, 0x00}, + {R367TER_DEBUG_LT6, 0x00}, + {R367TER_DEBUG_LT7, 0x00}, + {R367TER_DEBUG_LT8, 0x00}, + {R367TER_DEBUG_LT9, 0x00}, +}; + +#define RF_LOOKUP_TABLE_SIZE 31 +#define RF_LOOKUP_TABLE2_SIZE 16 +/* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/ +s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = { + {/*AGC1*/ + 48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 80, 83, 85, 88, + }, {/*RF(dbm)*/ + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, + 49, 50, 52, 53, 54, 55, 56, + } +}; +/* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/ +s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = { + {/*AGC2*/ + 28, 29, 31, 32, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, + }, {/*RF(dbm)*/ + 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + } +}; + +static struct st_register def0367cab[STV0367CAB_NBREGS] = { + {R367CAB_ID, 0x60}, + {R367CAB_I2CRPT, 0xa0}, + /*{R367CAB_I2CRPT, 0x22},*/ + {R367CAB_TOPCTRL, 0x10}, + {R367CAB_IOCFG0, 0x80}, + {R367CAB_DAC0R, 0x00}, + {R367CAB_IOCFG1, 0x00}, + {R367CAB_DAC1R, 0x00}, + {R367CAB_IOCFG2, 0x00}, + {R367CAB_SDFR, 0x00}, + {R367CAB_AUX_CLK, 0x00}, + {R367CAB_FREESYS1, 0x00}, + {R367CAB_FREESYS2, 0x00}, + {R367CAB_FREESYS3, 0x00}, + {R367CAB_GPIO_CFG, 0x55}, + {R367CAB_GPIO_CMD, 0x01}, + {R367CAB_TSTRES, 0x00}, + {R367CAB_ANACTRL, 0x0d},/* was 0x00 need to check - I.M.L.*/ + {R367CAB_TSTBUS, 0x00}, + {R367CAB_RF_AGC1, 0xea}, + {R367CAB_RF_AGC2, 0x82}, + {R367CAB_ANADIGCTRL, 0x0b}, + {R367CAB_PLLMDIV, 0x01}, + {R367CAB_PLLNDIV, 0x08}, + {R367CAB_PLLSETUP, 0x18}, + {R367CAB_DUAL_AD12, 0x0C}, /* for xc5000 AGC voltage 1.6V */ + {R367CAB_TSTBIST, 0x00}, + {R367CAB_CTRL_1, 0x00}, + {R367CAB_CTRL_2, 0x03}, + {R367CAB_IT_STATUS1, 0x2b}, + {R367CAB_IT_STATUS2, 0x08}, + {R367CAB_IT_EN1, 0x00}, + {R367CAB_IT_EN2, 0x00}, + {R367CAB_CTRL_STATUS, 0x04}, + {R367CAB_TEST_CTL, 0x00}, + {R367CAB_AGC_CTL, 0x73}, + {R367CAB_AGC_IF_CFG, 0x50}, + {R367CAB_AGC_RF_CFG, 0x00}, + {R367CAB_AGC_PWM_CFG, 0x03}, + {R367CAB_AGC_PWR_REF_L, 0x5a}, + {R367CAB_AGC_PWR_REF_H, 0x00}, + {R367CAB_AGC_RF_TH_L, 0xff}, + {R367CAB_AGC_RF_TH_H, 0x07}, + {R367CAB_AGC_IF_LTH_L, 0x00}, + {R367CAB_AGC_IF_LTH_H, 0x08}, + {R367CAB_AGC_IF_HTH_L, 0xff}, + {R367CAB_AGC_IF_HTH_H, 0x07}, + {R367CAB_AGC_PWR_RD_L, 0xa0}, + {R367CAB_AGC_PWR_RD_M, 0xe9}, + {R367CAB_AGC_PWR_RD_H, 0x03}, + {R367CAB_AGC_PWM_IFCMD_L, 0xe4}, + {R367CAB_AGC_PWM_IFCMD_H, 0x00}, + {R367CAB_AGC_PWM_RFCMD_L, 0xff}, + {R367CAB_AGC_PWM_RFCMD_H, 0x07}, + {R367CAB_IQDEM_CFG, 0x01}, + {R367CAB_MIX_NCO_LL, 0x22}, + {R367CAB_MIX_NCO_HL, 0x96}, + {R367CAB_MIX_NCO_HH, 0x55}, + {R367CAB_SRC_NCO_LL, 0xff}, + {R367CAB_SRC_NCO_LH, 0x0c}, + {R367CAB_SRC_NCO_HL, 0xf5}, + {R367CAB_SRC_NCO_HH, 0x20}, + {R367CAB_IQDEM_GAIN_SRC_L, 0x06}, + {R367CAB_IQDEM_GAIN_SRC_H, 0x01}, + {R367CAB_IQDEM_DCRM_CFG_LL, 0xfe}, + {R367CAB_IQDEM_DCRM_CFG_LH, 0xff}, + {R367CAB_IQDEM_DCRM_CFG_HL, 0x0f}, + {R367CAB_IQDEM_DCRM_CFG_HH, 0x00}, + {R367CAB_IQDEM_ADJ_COEFF0, 0x34}, + {R367CAB_IQDEM_ADJ_COEFF1, 0xae}, + {R367CAB_IQDEM_ADJ_COEFF2, 0x46}, + {R367CAB_IQDEM_ADJ_COEFF3, 0x77}, + {R367CAB_IQDEM_ADJ_COEFF4, 0x96}, + {R367CAB_IQDEM_ADJ_COEFF5, 0x69}, + {R367CAB_IQDEM_ADJ_COEFF6, 0xc7}, + {R367CAB_IQDEM_ADJ_COEFF7, 0x01}, + {R367CAB_IQDEM_ADJ_EN, 0x04}, + {R367CAB_IQDEM_ADJ_AGC_REF, 0x94}, + {R367CAB_ALLPASSFILT1, 0xc9}, + {R367CAB_ALLPASSFILT2, 0x2d}, + {R367CAB_ALLPASSFILT3, 0xa3}, + {R367CAB_ALLPASSFILT4, 0xfb}, + {R367CAB_ALLPASSFILT5, 0xf6}, + {R367CAB_ALLPASSFILT6, 0x45}, + {R367CAB_ALLPASSFILT7, 0x6f}, + {R367CAB_ALLPASSFILT8, 0x7e}, + {R367CAB_ALLPASSFILT9, 0x05}, + {R367CAB_ALLPASSFILT10, 0x0a}, + {R367CAB_ALLPASSFILT11, 0x51}, + {R367CAB_TRL_AGC_CFG, 0x20}, + {R367CAB_TRL_LPF_CFG, 0x28}, + {R367CAB_TRL_LPF_ACQ_GAIN, 0x44}, + {R367CAB_TRL_LPF_TRK_GAIN, 0x22}, + {R367CAB_TRL_LPF_OUT_GAIN, 0x03}, + {R367CAB_TRL_LOCKDET_LTH, 0x04}, + {R367CAB_TRL_LOCKDET_HTH, 0x11}, + {R367CAB_TRL_LOCKDET_TRGVAL, 0x20}, + {R367CAB_IQ_QAM, 0x01}, + {R367CAB_FSM_STATE, 0xa0}, + {R367CAB_FSM_CTL, 0x08}, + {R367CAB_FSM_STS, 0x0c}, + {R367CAB_FSM_SNR0_HTH, 0x00}, + {R367CAB_FSM_SNR1_HTH, 0x00}, + {R367CAB_FSM_SNR2_HTH, 0x23},/* 0x00 */ + {R367CAB_FSM_SNR0_LTH, 0x00}, + {R367CAB_FSM_SNR1_LTH, 0x00}, + {R367CAB_FSM_EQA1_HTH, 0x00}, + {R367CAB_FSM_TEMPO, 0x32}, + {R367CAB_FSM_CONFIG, 0x03}, + {R367CAB_EQU_I_TESTTAP_L, 0x11}, + {R367CAB_EQU_I_TESTTAP_M, 0x00}, + {R367CAB_EQU_I_TESTTAP_H, 0x00}, + {R367CAB_EQU_TESTAP_CFG, 0x00}, + {R367CAB_EQU_Q_TESTTAP_L, 0xff}, + {R367CAB_EQU_Q_TESTTAP_M, 0x00}, + {R367CAB_EQU_Q_TESTTAP_H, 0x00}, + {R367CAB_EQU_TAP_CTRL, 0x00}, + {R367CAB_EQU_CTR_CRL_CONTROL_L, 0x11}, + {R367CAB_EQU_CTR_CRL_CONTROL_H, 0x05}, + {R367CAB_EQU_CTR_HIPOW_L, 0x00}, + {R367CAB_EQU_CTR_HIPOW_H, 0x00}, + {R367CAB_EQU_I_EQU_LO, 0xef}, + {R367CAB_EQU_I_EQU_HI, 0x00}, + {R367CAB_EQU_Q_EQU_LO, 0xee}, + {R367CAB_EQU_Q_EQU_HI, 0x00}, + {R367CAB_EQU_MAPPER, 0xc5}, + {R367CAB_EQU_SWEEP_RATE, 0x80}, + {R367CAB_EQU_SNR_LO, 0x64}, + {R367CAB_EQU_SNR_HI, 0x03}, + {R367CAB_EQU_GAMMA_LO, 0x00}, + {R367CAB_EQU_GAMMA_HI, 0x00}, + {R367CAB_EQU_ERR_GAIN, 0x36}, + {R367CAB_EQU_RADIUS, 0xaa}, + {R367CAB_EQU_FFE_MAINTAP, 0x00}, + {R367CAB_EQU_FFE_LEAKAGE, 0x63}, + {R367CAB_EQU_FFE_MAINTAP_POS, 0xdf}, + {R367CAB_EQU_GAIN_WIDE, 0x88}, + {R367CAB_EQU_GAIN_NARROW, 0x41}, + {R367CAB_EQU_CTR_LPF_GAIN, 0xd1}, + {R367CAB_EQU_CRL_LPF_GAIN, 0xa7}, + {R367CAB_EQU_GLOBAL_GAIN, 0x06}, + {R367CAB_EQU_CRL_LD_SEN, 0x85}, + {R367CAB_EQU_CRL_LD_VAL, 0xe2}, + {R367CAB_EQU_CRL_TFR, 0x20}, + {R367CAB_EQU_CRL_BISTH_LO, 0x00}, + {R367CAB_EQU_CRL_BISTH_HI, 0x00}, + {R367CAB_EQU_SWEEP_RANGE_LO, 0x00}, + {R367CAB_EQU_SWEEP_RANGE_HI, 0x00}, + {R367CAB_EQU_CRL_LIMITER, 0x40}, + {R367CAB_EQU_MODULUS_MAP, 0x90}, + {R367CAB_EQU_PNT_GAIN, 0xa7}, + {R367CAB_FEC_AC_CTR_0, 0x16}, + {R367CAB_FEC_AC_CTR_1, 0x0b}, + {R367CAB_FEC_AC_CTR_2, 0x88}, + {R367CAB_FEC_AC_CTR_3, 0x02}, + {R367CAB_FEC_STATUS, 0x12}, + {R367CAB_RS_COUNTER_0, 0x7d}, + {R367CAB_RS_COUNTER_1, 0xd0}, + {R367CAB_RS_COUNTER_2, 0x19}, + {R367CAB_RS_COUNTER_3, 0x0b}, + {R367CAB_RS_COUNTER_4, 0xa3}, + {R367CAB_RS_COUNTER_5, 0x00}, + {R367CAB_BERT_0, 0x01}, + {R367CAB_BERT_1, 0x25}, + {R367CAB_BERT_2, 0x41}, + {R367CAB_BERT_3, 0x39}, + {R367CAB_OUTFORMAT_0, 0xc2}, + {R367CAB_OUTFORMAT_1, 0x22}, + {R367CAB_SMOOTHER_2, 0x28}, + {R367CAB_TSMF_CTRL_0, 0x01}, + {R367CAB_TSMF_CTRL_1, 0xc6}, + {R367CAB_TSMF_CTRL_3, 0x43}, + {R367CAB_TS_ON_ID_0, 0x00}, + {R367CAB_TS_ON_ID_1, 0x00}, + {R367CAB_TS_ON_ID_2, 0x00}, + {R367CAB_TS_ON_ID_3, 0x00}, + {R367CAB_RE_STATUS_0, 0x00}, + {R367CAB_RE_STATUS_1, 0x00}, + {R367CAB_RE_STATUS_2, 0x00}, + {R367CAB_RE_STATUS_3, 0x00}, + {R367CAB_TS_STATUS_0, 0x00}, + {R367CAB_TS_STATUS_1, 0x00}, + {R367CAB_TS_STATUS_2, 0xa0}, + {R367CAB_TS_STATUS_3, 0x00}, + {R367CAB_T_O_ID_0, 0x00}, + {R367CAB_T_O_ID_1, 0x00}, + {R367CAB_T_O_ID_2, 0x00}, + {R367CAB_T_O_ID_3, 0x00}, +}; + +static +int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len) +{ + u8 buf[len + 2]; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = len + 2 + }; + int ret; + + buf[0] = MSB(reg); + buf[1] = LSB(reg); + memcpy(buf + 2, data, len); + + if (i2cdebug) + printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, buf[2]); + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) + printk(KERN_ERR "%s: i2c write error!\n", __func__); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data) +{ + return stv0367_writeregs(state, reg, &data, 1); +} + +static u8 stv0367_readreg(struct stv0367_state *state, u16 reg) +{ + u8 b0[] = { 0, 0 }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 2 + }, { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + int ret; + + b0[0] = MSB(reg); + b0[1] = LSB(reg); + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) + printk(KERN_ERR "%s: i2c read error\n", __func__); + + if (i2cdebug) + printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, b1[0]); + + return b1[0]; +} + +static void extract_mask_pos(u32 label, u8 *mask, u8 *pos) +{ + u8 position = 0, i = 0; + + (*mask) = label & 0xff; + + while ((position == 0) && (i < 8)) { + position = ((*mask) >> i) & 0x01; + i++; + } + + (*pos) = (i - 1); +} + +static void stv0367_writebits(struct stv0367_state *state, u32 label, u8 val) +{ + u8 reg, mask, pos; + + reg = stv0367_readreg(state, (label >> 16) & 0xffff); + extract_mask_pos(label, &mask, &pos); + + val = mask & (val << pos); + + reg = (reg & (~mask)) | val; + stv0367_writereg(state, (label >> 16) & 0xffff, reg); + +} + +static void stv0367_setbits(u8 *reg, u32 label, u8 val) +{ + u8 mask, pos; + + extract_mask_pos(label, &mask, &pos); + + val = mask & (val << pos); + + (*reg) = ((*reg) & (~mask)) | val; +} + +static u8 stv0367_readbits(struct stv0367_state *state, u32 label) +{ + u8 val = 0xff; + u8 mask, pos; + + extract_mask_pos(label, &mask, &pos); + + val = stv0367_readreg(state, label >> 16); + val = (val & mask) >> pos; + + return val; +} + +u8 stv0367_getbits(u8 reg, u32 label) +{ + u8 mask, pos; + + extract_mask_pos(label, &mask, &pos); + + return (reg & mask) >> pos; +} + +static int stv0367ter_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv0367_state *state = fe->demodulator_priv; + u8 tmp = stv0367_readreg(state, R367TER_I2CRPT); + + dprintk("%s:\n", __func__); + + if (enable) { + stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 0); + stv0367_setbits(&tmp, F367TER_I2CT_ON, 1); + } else { + stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 1); + stv0367_setbits(&tmp, F367TER_I2CT_ON, 0); + } + + stv0367_writereg(state, R367TER_I2CRPT, tmp); + + return 0; +} + +static u32 stv0367_get_tuner_freq(struct dvb_frontend *fe) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + u32 freq = 0; + int err = 0; + + dprintk("%s:\n", __func__); + + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_frequency) { + err = tuner_ops->get_frequency(fe, &freq); + if (err < 0) { + printk(KERN_ERR "%s: Invalid parameter\n", __func__); + return err; + } + + dprintk("%s: frequency=%d\n", __func__, freq); + + } else + return -1; + + return freq; +} + +static u16 CellsCoeffs_8MHz_367cofdm[3][6][5] = { + { + {0x10EF, 0xE205, 0x10EF, 0xCE49, 0x6DA7}, /* CELL 1 COEFFS 27M*/ + {0x2151, 0xc557, 0x2151, 0xc705, 0x6f93}, /* CELL 2 COEFFS */ + {0x2503, 0xc000, 0x2503, 0xc375, 0x7194}, /* CELL 3 COEFFS */ + {0x20E9, 0xca94, 0x20e9, 0xc153, 0x7194}, /* CELL 4 COEFFS */ + {0x06EF, 0xF852, 0x06EF, 0xC057, 0x7207}, /* CELL 5 COEFFS */ + {0x0000, 0x0ECC, 0x0ECC, 0x0000, 0x3647} /* CELL 6 COEFFS */ + }, { + {0x10A0, 0xE2AF, 0x10A1, 0xCE76, 0x6D6D}, /* CELL 1 COEFFS 25M*/ + {0x20DC, 0xC676, 0x20D9, 0xC80A, 0x6F29}, + {0x2532, 0xC000, 0x251D, 0xC391, 0x706F}, + {0x1F7A, 0xCD2B, 0x2032, 0xC15E, 0x711F}, + {0x0698, 0xFA5E, 0x0568, 0xC059, 0x7193}, + {0x0000, 0x0918, 0x149C, 0x0000, 0x3642} /* CELL 6 COEFFS */ + }, { + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */ + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000} + } +}; + +static u16 CellsCoeffs_7MHz_367cofdm[3][6][5] = { + { + {0x12CA, 0xDDAF, 0x12CA, 0xCCEB, 0x6FB1}, /* CELL 1 COEFFS 27M*/ + {0x2329, 0xC000, 0x2329, 0xC6B0, 0x725F}, /* CELL 2 COEFFS */ + {0x2394, 0xC000, 0x2394, 0xC2C7, 0x7410}, /* CELL 3 COEFFS */ + {0x251C, 0xC000, 0x251C, 0xC103, 0x74D9}, /* CELL 4 COEFFS */ + {0x0804, 0xF546, 0x0804, 0xC040, 0x7544}, /* CELL 5 COEFFS */ + {0x0000, 0x0CD9, 0x0CD9, 0x0000, 0x370A} /* CELL 6 COEFFS */ + }, { + {0x1285, 0xDE47, 0x1285, 0xCD17, 0x6F76}, /*25M*/ + {0x234C, 0xC000, 0x2348, 0xC6DA, 0x7206}, + {0x23B4, 0xC000, 0x23AC, 0xC2DB, 0x73B3}, + {0x253D, 0xC000, 0x25B6, 0xC10B, 0x747F}, + {0x0721, 0xF79C, 0x065F, 0xC041, 0x74EB}, + {0x0000, 0x08FA, 0x1162, 0x0000, 0x36FF} + }, { + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */ + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000} + } +}; + +static u16 CellsCoeffs_6MHz_367cofdm[3][6][5] = { + { + {0x1699, 0xD5B8, 0x1699, 0xCBC3, 0x713B}, /* CELL 1 COEFFS 27M*/ + {0x2245, 0xC000, 0x2245, 0xC568, 0x74D5}, /* CELL 2 COEFFS */ + {0x227F, 0xC000, 0x227F, 0xC1FC, 0x76C6}, /* CELL 3 COEFFS */ + {0x235E, 0xC000, 0x235E, 0xC0A7, 0x778A}, /* CELL 4 COEFFS */ + {0x0ECB, 0xEA0B, 0x0ECB, 0xC027, 0x77DD}, /* CELL 5 COEFFS */ + {0x0000, 0x0B68, 0x0B68, 0x0000, 0xC89A}, /* CELL 6 COEFFS */ + }, { + {0x1655, 0xD64E, 0x1658, 0xCBEF, 0x70FE}, /*25M*/ + {0x225E, 0xC000, 0x2256, 0xC589, 0x7489}, + {0x2293, 0xC000, 0x2295, 0xC209, 0x767E}, + {0x2377, 0xC000, 0x23AA, 0xC0AB, 0x7746}, + {0x0DC7, 0xEBC8, 0x0D07, 0xC027, 0x7799}, + {0x0000, 0x0888, 0x0E9C, 0x0000, 0x3757} + + }, { + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */ + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000} + } +}; + +static u32 stv0367ter_get_mclk(struct stv0367_state *state, u32 ExtClk_Hz) +{ + u32 mclk_Hz = 0; /* master clock frequency (Hz) */ + u32 m, n, p; + + dprintk("%s:\n", __func__); + + if (stv0367_readbits(state, F367TER_BYPASS_PLLXN) == 0) { + n = (u32)stv0367_readbits(state, F367TER_PLL_NDIV); + if (n == 0) + n = n + 1; + + m = (u32)stv0367_readbits(state, F367TER_PLL_MDIV); + if (m == 0) + m = m + 1; + + p = (u32)stv0367_readbits(state, F367TER_PLL_PDIV); + if (p > 5) + p = 5; + + mclk_Hz = ((ExtClk_Hz / 2) * n) / (m * (1 << p)); + + dprintk("N=%d M=%d P=%d mclk_Hz=%d ExtClk_Hz=%d\n", + n, m, p, mclk_Hz, ExtClk_Hz); + } else + mclk_Hz = ExtClk_Hz; + + dprintk("%s: mclk_Hz=%d\n", __func__, mclk_Hz); + + return mclk_Hz; +} + +static int stv0367ter_filt_coeff_init(struct stv0367_state *state, + u16 CellsCoeffs[3][6][5], u32 DemodXtal) +{ + int i, j, k, freq; + + dprintk("%s:\n", __func__); + + freq = stv0367ter_get_mclk(state, DemodXtal); + + if (freq == 53125000) + k = 1; /* equivalent to Xtal 25M on 362*/ + else if (freq == 54000000) + k = 0; /* equivalent to Xtal 27M on 362*/ + else if (freq == 52500000) + k = 2; /* equivalent to Xtal 30M on 362*/ + else + return 0; + + for (i = 1; i <= 6; i++) { + stv0367_writebits(state, F367TER_IIR_CELL_NB, i - 1); + + for (j = 1; j <= 5; j++) { + stv0367_writereg(state, + (R367TER_IIRCX_COEFF1_MSB + 2 * (j - 1)), + MSB(CellsCoeffs[k][i-1][j-1])); + stv0367_writereg(state, + (R367TER_IIRCX_COEFF1_LSB + 2 * (j - 1)), + LSB(CellsCoeffs[k][i-1][j-1])); + } + } + + return 1; + +} + +static void stv0367ter_agc_iir_lock_detect_set(struct stv0367_state *state) +{ + dprintk("%s:\n", __func__); + + stv0367_writebits(state, F367TER_LOCK_DETECT_LSB, 0x00); + + /* Lock detect 1 */ + stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x00); + stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04); + + /* Lock detect 2 */ + stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x01); + stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04); + + /* Lock detect 3 */ + stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x02); + stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00); + + /* Lock detect 4 */ + stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x03); + stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00); + +} + +static int stv0367_iir_filt_init(struct stv0367_state *state, u8 Bandwidth, + u32 DemodXtalValue) +{ + dprintk("%s:\n", __func__); + + stv0367_writebits(state, F367TER_NRST_IIR, 0); + + switch (Bandwidth) { + case 6: + if (!stv0367ter_filt_coeff_init(state, + CellsCoeffs_6MHz_367cofdm, + DemodXtalValue)) + return 0; + break; + case 7: + if (!stv0367ter_filt_coeff_init(state, + CellsCoeffs_7MHz_367cofdm, + DemodXtalValue)) + return 0; + break; + case 8: + if (!stv0367ter_filt_coeff_init(state, + CellsCoeffs_8MHz_367cofdm, + DemodXtalValue)) + return 0; + break; + default: + return 0; + } + + stv0367_writebits(state, F367TER_NRST_IIR, 1); + + return 1; +} + +static void stv0367ter_agc_iir_rst(struct stv0367_state *state) +{ + + u8 com_n; + + dprintk("%s:\n", __func__); + + com_n = stv0367_readbits(state, F367TER_COM_N); + + stv0367_writebits(state, F367TER_COM_N, 0x07); + + stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x00); + stv0367_writebits(state, F367TER_COM_AGC_ON, 0x00); + + stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x01); + stv0367_writebits(state, F367TER_COM_AGC_ON, 0x01); + + stv0367_writebits(state, F367TER_COM_N, com_n); + +} + +static int stv0367ter_duration(s32 mode, int tempo1, int tempo2, int tempo3) +{ + int local_tempo = 0; + switch (mode) { + case 0: + local_tempo = tempo1; + break; + case 1: + local_tempo = tempo2; + break ; + + case 2: + local_tempo = tempo3; + break; + + default: + break; + } + /* msleep(local_tempo); */ + return local_tempo; +} + +static enum +stv0367_ter_signal_type stv0367ter_check_syr(struct stv0367_state *state) +{ + int wd = 100; + unsigned short int SYR_var; + s32 SYRStatus; + + dprintk("%s:\n", __func__); + + SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK); + + while ((!SYR_var) && (wd > 0)) { + usleep_range(2000, 3000); + wd -= 2; + SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK); + } + + if (!SYR_var) + SYRStatus = FE_TER_NOSYMBOL; + else + SYRStatus = FE_TER_SYMBOLOK; + + dprintk("stv0367ter_check_syr SYRStatus %s\n", + SYR_var == 0 ? "No Symbol" : "OK"); + + return SYRStatus; +} + +static enum +stv0367_ter_signal_type stv0367ter_check_cpamp(struct stv0367_state *state, + s32 FFTmode) +{ + + s32 CPAMPvalue = 0, CPAMPStatus, CPAMPMin; + int wd = 0; + + dprintk("%s:\n", __func__); + + switch (FFTmode) { + case 0: /*2k mode*/ + CPAMPMin = 20; + wd = 10; + break; + case 1: /*8k mode*/ + CPAMPMin = 80; + wd = 55; + break; + case 2: /*4k mode*/ + CPAMPMin = 40; + wd = 30; + break; + default: + CPAMPMin = 0xffff; /*drives to NOCPAMP */ + break; + } + + dprintk("%s: CPAMPMin=%d wd=%d\n", __func__, CPAMPMin, wd); + + CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT); + while ((CPAMPvalue < CPAMPMin) && (wd > 0)) { + usleep_range(1000, 2000); + wd -= 1; + CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT); + /*dprintk("CPAMPvalue= %d at wd=%d\n",CPAMPvalue,wd); */ + } + dprintk("******last CPAMPvalue= %d at wd=%d\n", CPAMPvalue, wd); + if (CPAMPvalue < CPAMPMin) { + CPAMPStatus = FE_TER_NOCPAMP; + printk(KERN_ERR "CPAMP failed\n"); + } else { + printk(KERN_ERR "CPAMP OK !\n"); + CPAMPStatus = FE_TER_CPAMPOK; + } + + return CPAMPStatus; +} + +enum +stv0367_ter_signal_type stv0367ter_lock_algo(struct stv0367_state *state) +{ + enum stv0367_ter_signal_type ret_flag; + short int wd, tempo; + u8 try, u_var1 = 0, u_var2 = 0, u_var3 = 0, u_var4 = 0, mode, guard; + u8 tmp, tmp2; + + dprintk("%s:\n", __func__); + + if (state == NULL) + return FE_TER_SWNOK; + + try = 0; + do { + ret_flag = FE_TER_LOCKOK; + + stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); + + if (state->config->if_iq_mode != 0) + stv0367_writebits(state, F367TER_COM_N, 0x07); + + stv0367_writebits(state, F367TER_GUARD, 3);/* suggest 2k 1/4 */ + stv0367_writebits(state, F367TER_MODE, 0); + stv0367_writebits(state, F367TER_SYR_TR_DIS, 0); + usleep_range(5000, 10000); + + stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); + + + if (stv0367ter_check_syr(state) == FE_TER_NOSYMBOL) + return FE_TER_NOSYMBOL; + else { /* + if chip locked on wrong mode first try, + it must lock correctly second try */ + mode = stv0367_readbits(state, F367TER_SYR_MODE); + if (stv0367ter_check_cpamp(state, mode) == + FE_TER_NOCPAMP) { + if (try == 0) + ret_flag = FE_TER_NOCPAMP; + + } + } + + try++; + } while ((try < 10) && (ret_flag != FE_TER_LOCKOK)); + + tmp = stv0367_readreg(state, R367TER_SYR_STAT); + tmp2 = stv0367_readreg(state, R367TER_STATUS); + dprintk("state=%p\n", state); + dprintk("LOCK OK! mode=%d SYR_STAT=0x%x R367TER_STATUS=0x%x\n", + mode, tmp, tmp2); + + tmp = stv0367_readreg(state, R367TER_PRVIT); + tmp2 = stv0367_readreg(state, R367TER_I2CRPT); + dprintk("PRVIT=0x%x I2CRPT=0x%x\n", tmp, tmp2); + + tmp = stv0367_readreg(state, R367TER_GAIN_SRC1); + dprintk("GAIN_SRC1=0x%x\n", tmp); + + if ((mode != 0) && (mode != 1) && (mode != 2)) + return FE_TER_SWNOK; + + /*guard=stv0367_readbits(state,F367TER_SYR_GUARD); */ + + /*suppress EPQ auto for SYR_GARD 1/16 or 1/32 + and set channel predictor in automatic */ +#if 0 + switch (guard) { + + case 0: + case 1: + stv0367_writebits(state, F367TER_AUTO_LE_EN, 0); + stv0367_writereg(state, R367TER_CHC_CTL, 0x01); + break; + case 2: + case 3: + stv0367_writebits(state, F367TER_AUTO_LE_EN, 1); + stv0367_writereg(state, R367TER_CHC_CTL, 0x11); + break; + + default: + return FE_TER_SWNOK; + } +#endif + + /*reset fec an reedsolo FOR 367 only*/ + stv0367_writebits(state, F367TER_RST_SFEC, 1); + stv0367_writebits(state, F367TER_RST_REEDSOLO, 1); + usleep_range(1000, 2000); + stv0367_writebits(state, F367TER_RST_SFEC, 0); + stv0367_writebits(state, F367TER_RST_REEDSOLO, 0); + + u_var1 = stv0367_readbits(state, F367TER_LK); + u_var2 = stv0367_readbits(state, F367TER_PRF); + u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK); + /* u_var4=stv0367_readbits(state,F367TER_TSFIFO_LINEOK); */ + + wd = stv0367ter_duration(mode, 125, 500, 250); + tempo = stv0367ter_duration(mode, 4, 16, 8); + + /*while ( ((!u_var1)||(!u_var2)||(!u_var3)||(!u_var4)) && (wd>=0)) */ + while (((!u_var1) || (!u_var2) || (!u_var3)) && (wd >= 0)) { + usleep_range(1000 * tempo, 1000 * (tempo + 1)); + wd -= tempo; + u_var1 = stv0367_readbits(state, F367TER_LK); + u_var2 = stv0367_readbits(state, F367TER_PRF); + u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK); + /*u_var4=stv0367_readbits(state, F367TER_TSFIFO_LINEOK); */ + } + + if (!u_var1) + return FE_TER_NOLOCK; + + + if (!u_var2) + return FE_TER_NOPRFOUND; + + if (!u_var3) + return FE_TER_NOTPS; + + guard = stv0367_readbits(state, F367TER_SYR_GUARD); + stv0367_writereg(state, R367TER_CHC_CTL, 0x11); + switch (guard) { + case 0: + case 1: + stv0367_writebits(state, F367TER_AUTO_LE_EN, 0); + /*stv0367_writereg(state,R367TER_CHC_CTL, 0x1);*/ + stv0367_writebits(state, F367TER_SYR_FILTER, 0); + break; + case 2: + case 3: + stv0367_writebits(state, F367TER_AUTO_LE_EN, 1); + /*stv0367_writereg(state,R367TER_CHC_CTL, 0x11);*/ + stv0367_writebits(state, F367TER_SYR_FILTER, 1); + break; + + default: + return FE_TER_SWNOK; + } + + /* apply Sfec workaround if 8K 64QAM CR!=1/2*/ + if ((stv0367_readbits(state, F367TER_TPS_CONST) == 2) && + (mode == 1) && + (stv0367_readbits(state, F367TER_TPS_HPCODE) != 0)) { + stv0367_writereg(state, R367TER_SFDLYSETH, 0xc0); + stv0367_writereg(state, R367TER_SFDLYSETM, 0x60); + stv0367_writereg(state, R367TER_SFDLYSETL, 0x0); + } else + stv0367_writereg(state, R367TER_SFDLYSETH, 0x0); + + wd = stv0367ter_duration(mode, 125, 500, 250); + u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK); + + while ((!u_var4) && (wd >= 0)) { + usleep_range(1000 * tempo, 1000 * (tempo + 1)); + wd -= tempo; + u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK); + } + + if (!u_var4) + return FE_TER_NOLOCK; + + /* for 367 leave COM_N at 0x7 for IQ_mode*/ + /*if(ter_state->if_iq_mode!=FE_TER_NORMAL_IF_TUNER) { + tempo=0; + while ((stv0367_readbits(state,F367TER_COM_USEGAINTRK)!=1) && + (stv0367_readbits(state,F367TER_COM_AGCLOCK)!=1)&&(tempo<100)) { + ChipWaitOrAbort(state,1); + tempo+=1; + } + + stv0367_writebits(state,F367TER_COM_N,0x17); + } */ + + stv0367_writebits(state, F367TER_SYR_TR_DIS, 1); + + dprintk("FE_TER_LOCKOK !!!\n"); + + return FE_TER_LOCKOK; + +} + +static void stv0367ter_set_ts_mode(struct stv0367_state *state, + enum stv0367_ts_mode PathTS) +{ + + dprintk("%s:\n", __func__); + + if (state == NULL) + return; + + stv0367_writebits(state, F367TER_TS_DIS, 0); + switch (PathTS) { + default: + /*for removing warning :default we can assume in parallel mode*/ + case STV0367_PARALLEL_PUNCT_CLOCK: + stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 0); + stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 0); + break; + case STV0367_SERIAL_PUNCT_CLOCK: + stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 1); + stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 1); + break; + } +} + +static void stv0367ter_set_clk_pol(struct stv0367_state *state, + enum stv0367_clk_pol clock) +{ + + dprintk("%s:\n", __func__); + + if (state == NULL) + return; + + switch (clock) { + case STV0367_RISINGEDGE_CLOCK: + stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 1); + break; + case STV0367_FALLINGEDGE_CLOCK: + stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0); + break; + /*case FE_TER_CLOCK_POLARITY_DEFAULT:*/ + default: + stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0); + break; + } +} + +#if 0 +static void stv0367ter_core_sw(struct stv0367_state *state) +{ + + dprintk("%s:\n", __func__); + + stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); + stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); + msleep(350); +} +#endif +static int stv0367ter_standby(struct dvb_frontend *fe, u8 standby_on) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + if (standby_on) { + stv0367_writebits(state, F367TER_STDBY, 1); + stv0367_writebits(state, F367TER_STDBY_FEC, 1); + stv0367_writebits(state, F367TER_STDBY_CORE, 1); + } else { + stv0367_writebits(state, F367TER_STDBY, 0); + stv0367_writebits(state, F367TER_STDBY_FEC, 0); + stv0367_writebits(state, F367TER_STDBY_CORE, 0); + } + + return 0; +} + +static int stv0367ter_sleep(struct dvb_frontend *fe) +{ + return stv0367ter_standby(fe, 1); +} + +int stv0367ter_init(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + int i; + + dprintk("%s:\n", __func__); + + ter_state->pBER = 0; + + for (i = 0; i < STV0367TER_NBREGS; i++) + stv0367_writereg(state, def0367ter[i].addr, + def0367ter[i].value); + + switch (state->config->xtal) { + /*set internal freq to 53.125MHz */ + case 25000000: + stv0367_writereg(state, R367TER_PLLMDIV, 0xa); + stv0367_writereg(state, R367TER_PLLNDIV, 0x55); + stv0367_writereg(state, R367TER_PLLSETUP, 0x18); + break; + default: + case 27000000: + dprintk("FE_STV0367TER_SetCLKgen for 27Mhz\n"); + stv0367_writereg(state, R367TER_PLLMDIV, 0x1); + stv0367_writereg(state, R367TER_PLLNDIV, 0x8); + stv0367_writereg(state, R367TER_PLLSETUP, 0x18); + break; + case 30000000: + stv0367_writereg(state, R367TER_PLLMDIV, 0xc); + stv0367_writereg(state, R367TER_PLLNDIV, 0x55); + stv0367_writereg(state, R367TER_PLLSETUP, 0x18); + break; + } + + stv0367_writereg(state, R367TER_I2CRPT, 0xa0); + stv0367_writereg(state, R367TER_ANACTRL, 0x00); + + /*Set TS1 and TS2 to serial or parallel mode */ + stv0367ter_set_ts_mode(state, state->config->ts_mode); + stv0367ter_set_clk_pol(state, state->config->clk_pol); + + state->chip_id = stv0367_readreg(state, R367TER_ID); + ter_state->first_lock = 0; + ter_state->unlock_counter = 2; + + return 0; +} + +static int stv0367ter_algo(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + int offset = 0, tempo = 0; + u8 u_var; + u8 /*constell,*/ counter, tps_rcvd[2]; + s8 step; + s32 timing_offset = 0; + u32 trl_nomrate = 0, InternalFreq = 0, temp = 0; + + dprintk("%s:\n", __func__); + + ter_state->frequency = param->frequency; + ter_state->force = FE_TER_FORCENONE + + stv0367_readbits(state, F367TER_FORCE) * 2; + ter_state->if_iq_mode = state->config->if_iq_mode; + switch (state->config->if_iq_mode) { + case FE_TER_NORMAL_IF_TUNER: /* Normal IF mode */ + dprintk("ALGO: FE_TER_NORMAL_IF_TUNER selected\n"); + stv0367_writebits(state, F367TER_TUNER_BB, 0); + stv0367_writebits(state, F367TER_LONGPATH_IF, 0); + stv0367_writebits(state, F367TER_DEMUX_SWAP, 0); + break; + case FE_TER_LONGPATH_IF_TUNER: /* Long IF mode */ + dprintk("ALGO: FE_TER_LONGPATH_IF_TUNER selected\n"); + stv0367_writebits(state, F367TER_TUNER_BB, 0); + stv0367_writebits(state, F367TER_LONGPATH_IF, 1); + stv0367_writebits(state, F367TER_DEMUX_SWAP, 1); + break; + case FE_TER_IQ_TUNER: /* IQ mode */ + dprintk("ALGO: FE_TER_IQ_TUNER selected\n"); + stv0367_writebits(state, F367TER_TUNER_BB, 1); + stv0367_writebits(state, F367TER_PPM_INVSEL, 0); + break; + default: + printk(KERN_ERR "ALGO: wrong TUNER type selected\n"); + return -EINVAL; + } + + usleep_range(5000, 7000); + + switch (param->inversion) { + case INVERSION_AUTO: + default: + dprintk("%s: inversion AUTO\n", __func__); + if (ter_state->if_iq_mode == FE_TER_IQ_TUNER) + stv0367_writebits(state, F367TER_IQ_INVERT, + ter_state->sense); + else + stv0367_writebits(state, F367TER_INV_SPECTR, + ter_state->sense); + + break; + case INVERSION_ON: + case INVERSION_OFF: + if (ter_state->if_iq_mode == FE_TER_IQ_TUNER) + stv0367_writebits(state, F367TER_IQ_INVERT, + param->inversion); + else + stv0367_writebits(state, F367TER_INV_SPECTR, + param->inversion); + + break; + } + + if ((ter_state->if_iq_mode != FE_TER_NORMAL_IF_TUNER) && + (ter_state->pBW != ter_state->bw)) { + stv0367ter_agc_iir_lock_detect_set(state); + + /*set fine agc target to 180 for LPIF or IQ mode*/ + /* set Q_AGCTarget */ + stv0367_writebits(state, F367TER_SEL_IQNTAR, 1); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB); + /*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */ + + /* set Q_AGCTarget */ + stv0367_writebits(state, F367TER_SEL_IQNTAR, 0); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB); + /*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */ + + if (!stv0367_iir_filt_init(state, ter_state->bw, + state->config->xtal)) + return -EINVAL; + /*set IIR filter once for 6,7 or 8MHz BW*/ + ter_state->pBW = ter_state->bw; + + stv0367ter_agc_iir_rst(state); + } + + if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO) + stv0367_writebits(state, F367TER_BDI_LPSEL, 0x01); + else + stv0367_writebits(state, F367TER_BDI_LPSEL, 0x00); + + InternalFreq = stv0367ter_get_mclk(state, state->config->xtal) / 1000; + temp = (int) + ((((ter_state->bw * 64 * (1 << 15) * 100) + / (InternalFreq)) * 10) / 7); + + stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB, temp % 2); + temp = temp / 2; + stv0367_writebits(state, F367TER_TRL_NOMRATE_HI, temp / 256); + stv0367_writebits(state, F367TER_TRL_NOMRATE_LO, temp % 256); + + temp = stv0367_readbits(state, F367TER_TRL_NOMRATE_HI) * 512 + + stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2 + + stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB); + temp = (int)(((1 << 17) * ter_state->bw * 1000) / (7 * (InternalFreq))); + stv0367_writebits(state, F367TER_GAIN_SRC_HI, temp / 256); + stv0367_writebits(state, F367TER_GAIN_SRC_LO, temp % 256); + temp = stv0367_readbits(state, F367TER_GAIN_SRC_HI) * 256 + + stv0367_readbits(state, F367TER_GAIN_SRC_LO); + + temp = (int) + ((InternalFreq - state->config->if_khz) * (1 << 16) + / (InternalFreq)); + + dprintk("DEROT temp=0x%x\n", temp); + stv0367_writebits(state, F367TER_INC_DEROT_HI, temp / 256); + stv0367_writebits(state, F367TER_INC_DEROT_LO, temp % 256); + + ter_state->echo_pos = 0; + ter_state->ucblocks = 0; /* liplianin */ + ter_state->pBER = 0; /* liplianin */ + stv0367_writebits(state, F367TER_LONG_ECHO, ter_state->echo_pos); + + if (stv0367ter_lock_algo(state) != FE_TER_LOCKOK) + return 0; + + ter_state->state = FE_TER_LOCKOK; + /* update results */ + tps_rcvd[0] = stv0367_readreg(state, R367TER_TPS_RCVD2); + tps_rcvd[1] = stv0367_readreg(state, R367TER_TPS_RCVD3); + + ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE); + ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD); + + ter_state->first_lock = 1; /* we know sense now :) */ + + ter_state->agc_val = + (stv0367_readbits(state, F367TER_AGC1_VAL_LO) << 16) + + (stv0367_readbits(state, F367TER_AGC1_VAL_HI) << 24) + + stv0367_readbits(state, F367TER_AGC2_VAL_LO) + + (stv0367_readbits(state, F367TER_AGC2_VAL_HI) << 8); + + /* Carrier offset calculation */ + stv0367_writebits(state, F367TER_FREEZE, 1); + offset = (stv0367_readbits(state, F367TER_CRL_FOFFSET_VHI) << 16) ; + offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_HI) << 8); + offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_LO)); + stv0367_writebits(state, F367TER_FREEZE, 0); + if (offset > 8388607) + offset -= 16777216; + + offset = offset * 2 / 16384; + + if (ter_state->mode == FE_TER_MODE_2K) + offset = (offset * 4464) / 1000;/*** 1 FFT BIN=4.464khz***/ + else if (ter_state->mode == FE_TER_MODE_4K) + offset = (offset * 223) / 100;/*** 1 FFT BIN=2.23khz***/ + else if (ter_state->mode == FE_TER_MODE_8K) + offset = (offset * 111) / 100;/*** 1 FFT BIN=1.1khz***/ + + if (stv0367_readbits(state, F367TER_PPM_INVSEL) == 1) { + if ((stv0367_readbits(state, F367TER_INV_SPECTR) == + (stv0367_readbits(state, + F367TER_STATUS_INV_SPECRUM) == 1))) + offset = offset * -1; + } + + if (ter_state->bw == 6) + offset = (offset * 6) / 8; + else if (ter_state->bw == 7) + offset = (offset * 7) / 8; + + ter_state->frequency += offset; + + tempo = 10; /* exit even if timing_offset stays null */ + while ((timing_offset == 0) && (tempo > 0)) { + usleep_range(10000, 20000); /*was 20ms */ + /* fine tuning of timing offset if required */ + timing_offset = stv0367_readbits(state, F367TER_TRL_TOFFSET_LO) + + 256 * stv0367_readbits(state, + F367TER_TRL_TOFFSET_HI); + if (timing_offset >= 32768) + timing_offset -= 65536; + trl_nomrate = (512 * stv0367_readbits(state, + F367TER_TRL_NOMRATE_HI) + + stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2 + + stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB)); + + timing_offset = ((signed)(1000000 / trl_nomrate) * + timing_offset) / 2048; + tempo--; + } + + if (timing_offset <= 0) { + timing_offset = (timing_offset - 11) / 22; + step = -1; + } else { + timing_offset = (timing_offset + 11) / 22; + step = 1; + } + + for (counter = 0; counter < abs(timing_offset); counter++) { + trl_nomrate += step; + stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB, + trl_nomrate % 2); + stv0367_writebits(state, F367TER_TRL_NOMRATE_LO, + trl_nomrate / 2); + usleep_range(1000, 2000); + } + + usleep_range(5000, 6000); + /* unlocks could happen in case of trl centring big step, + then a core off/on restarts demod */ + u_var = stv0367_readbits(state, F367TER_LK); + + if (!u_var) { + stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); + msleep(20); + stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); + } + + return 0; +} + +static int stv0367ter_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + + /*u8 trials[2]; */ + s8 num_trials, index; + u8 SenseTrials[] = { INVERSION_ON, INVERSION_OFF }; + + stv0367ter_init(fe); + + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + switch (op->transmission_mode) { + default: + case TRANSMISSION_MODE_AUTO: + case TRANSMISSION_MODE_2K: + ter_state->mode = FE_TER_MODE_2K; + break; +/* case TRANSMISSION_MODE_4K: + pLook.mode = FE_TER_MODE_4K; + break;*/ + case TRANSMISSION_MODE_8K: + ter_state->mode = FE_TER_MODE_8K; + break; + } + + switch (op->guard_interval) { + default: + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_1_16: + case GUARD_INTERVAL_1_8: + case GUARD_INTERVAL_1_4: + ter_state->guard = op->guard_interval; + break; + case GUARD_INTERVAL_AUTO: + ter_state->guard = GUARD_INTERVAL_1_32; + break; + } + + switch (op->bandwidth) { + case BANDWIDTH_6_MHZ: + ter_state->bw = FE_TER_CHAN_BW_6M; + break; + case BANDWIDTH_7_MHZ: + ter_state->bw = FE_TER_CHAN_BW_7M; + break; + case BANDWIDTH_8_MHZ: + default: + ter_state->bw = FE_TER_CHAN_BW_8M; + } + + ter_state->hierarchy = FE_TER_HIER_NONE; + + switch (param->inversion) { + case INVERSION_OFF: + case INVERSION_ON: + num_trials = 1; + break; + default: + num_trials = 2; + if (ter_state->first_lock) + num_trials = 1; + break; + } + + ter_state->state = FE_TER_NOLOCK; + index = 0; + + while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) { + if (!ter_state->first_lock) { + if (param->inversion == INVERSION_AUTO) + ter_state->sense = SenseTrials[index]; + + } + stv0367ter_algo(fe,/* &pLook, result,*/ param); + + if ((ter_state->state == FE_TER_LOCKOK) && + (param->inversion == INVERSION_AUTO) && + (index == 1)) { + /* invert spectrum sense */ + SenseTrials[index] = SenseTrials[0]; + SenseTrials[(index + 1) % 2] = (SenseTrials[1] + 1) % 2; + } + + index++; + } + + return 0; +} + +static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + u32 errs = 0; + + /*wait for counting completion*/ + if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0) { + errs = + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1) + * (1 << 16)) + + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI) + * (1 << 8)) + + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO)); + ter_state->ucblocks = errs; + } + + (*ucblocks) = ter_state->ucblocks; + + return 0; +} + +static int stv0367ter_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + int error = 0; + enum stv0367_ter_mode mode; + int constell = 0,/* snr = 0,*/ Data = 0; + + param->frequency = stv0367_get_tuner_freq(fe); + if ((int)param->frequency < 0) + param->frequency = c->frequency; + + constell = stv0367_readbits(state, F367TER_TPS_CONST); + if (constell == 0) + op->constellation = QPSK; + else if (constell == 1) + op->constellation = QAM_16; + else + op->constellation = QAM_64; + + param->inversion = stv0367_readbits(state, F367TER_INV_SPECTR); + + /* Get the Hierarchical mode */ + Data = stv0367_readbits(state, F367TER_TPS_HIERMODE); + + switch (Data) { + case 0: + op->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + op->hierarchy_information = HIERARCHY_1; + break; + case 2: + op->hierarchy_information = HIERARCHY_2; + break; + case 3: + op->hierarchy_information = HIERARCHY_4; + break; + default: + op->hierarchy_information = HIERARCHY_AUTO; + break; /* error */ + } + + /* Get the FEC Rate */ + if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO) + Data = stv0367_readbits(state, F367TER_TPS_LPCODE); + else + Data = stv0367_readbits(state, F367TER_TPS_HPCODE); + + switch (Data) { + case 0: + op->code_rate_HP = FEC_1_2; + break; + case 1: + op->code_rate_HP = FEC_2_3; + break; + case 2: + op->code_rate_HP = FEC_3_4; + break; + case 3: + op->code_rate_HP = FEC_5_6; + break; + case 4: + op->code_rate_HP = FEC_7_8; + break; + default: + op->code_rate_HP = FEC_AUTO; + break; /* error */ + } + + mode = stv0367_readbits(state, F367TER_SYR_MODE); + + switch (mode) { + case FE_TER_MODE_2K: + op->transmission_mode = TRANSMISSION_MODE_2K; + break; +/* case FE_TER_MODE_4K: + op->transmission_mode = TRANSMISSION_MODE_4K; + break;*/ + case FE_TER_MODE_8K: + op->transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + op->transmission_mode = TRANSMISSION_MODE_AUTO; + } + + op->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD); + + return error; +} + +static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 snru32 = 0; + int cpt = 0; + u8 cut = stv0367_readbits(state, F367TER_IDENTIFICATIONREG); + + while (cpt < 10) { + usleep_range(2000, 3000); + if (cut == 0x50) /*cut 1.0 cut 1.1*/ + snru32 += stv0367_readbits(state, F367TER_CHCSNR) / 4; + else /*cu2.0*/ + snru32 += 125 * stv0367_readbits(state, F367TER_CHCSNR); + + cpt++; + } + + snru32 /= 10;/*average on 10 values*/ + + *snr = snru32 / 1000; + + return 0; +} + +#if 0 +static int stv0367ter_status(struct dvb_frontend *fe) +{ + + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + int locked = FALSE; + + locked = (stv0367_readbits(state, F367TER_LK)); + if (!locked) + ter_state->unlock_counter += 1; + else + ter_state->unlock_counter = 0; + + if (ter_state->unlock_counter > 2) { + if (!stv0367_readbits(state, F367TER_TPS_LOCK) || + (!stv0367_readbits(state, F367TER_LK))) { + stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); + usleep_range(2000, 3000); + stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); + msleep(350); + locked = (stv0367_readbits(state, F367TER_TPS_LOCK)) && + (stv0367_readbits(state, F367TER_LK)); + } + + } + + return locked; +} +#endif +static int stv0367ter_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + *status = 0; + + if (stv0367_readbits(state, F367TER_LK)) { + *status |= FE_HAS_LOCK; + dprintk("%s: stv0367 has locked\n", __func__); + } + + return 0; +} + +static int stv0367ter_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + u32 Errors = 0, tber = 0, temporary = 0; + int abc = 0, def = 0; + + + /*wait for counting completion*/ + if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0) + Errors = ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT) + * (1 << 16)) + + ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT_HI) + * (1 << 8)) + + ((u32)stv0367_readbits(state, + F367TER_SFEC_ERR_CNT_LO)); + /*measurement not completed, load previous value*/ + else { + tber = ter_state->pBER; + return 0; + } + + abc = stv0367_readbits(state, F367TER_SFEC_ERR_SOURCE); + def = stv0367_readbits(state, F367TER_SFEC_NUM_EVENT); + + if (Errors == 0) { + tber = 0; + } else if (abc == 0x7) { + if (Errors <= 4) { + temporary = (Errors * 1000000000) / (8 * (1 << 14)); + temporary = temporary; + } else if (Errors <= 42) { + temporary = (Errors * 100000000) / (8 * (1 << 14)); + temporary = temporary * 10; + } else if (Errors <= 429) { + temporary = (Errors * 10000000) / (8 * (1 << 14)); + temporary = temporary * 100; + } else if (Errors <= 4294) { + temporary = (Errors * 1000000) / (8 * (1 << 14)); + temporary = temporary * 1000; + } else if (Errors <= 42949) { + temporary = (Errors * 100000) / (8 * (1 << 14)); + temporary = temporary * 10000; + } else if (Errors <= 429496) { + temporary = (Errors * 10000) / (8 * (1 << 14)); + temporary = temporary * 100000; + } else { /*if (Errors<4294967) 2^22 max error*/ + temporary = (Errors * 1000) / (8 * (1 << 14)); + temporary = temporary * 100000; /* still to *10 */ + } + + /* Byte error*/ + if (def == 2) + /*tber=Errors/(8*(1 <<14));*/ + tber = temporary; + else if (def == 3) + /*tber=Errors/(8*(1 <<16));*/ + tber = temporary / 4; + else if (def == 4) + /*tber=Errors/(8*(1 <<18));*/ + tber = temporary / 16; + else if (def == 5) + /*tber=Errors/(8*(1 <<20));*/ + tber = temporary / 64; + else if (def == 6) + /*tber=Errors/(8*(1 <<22));*/ + tber = temporary / 256; + else + /* should not pass here*/ + tber = 0; + + if ((Errors < 4294967) && (Errors > 429496)) + tber *= 10; + + } + + /* save actual value */ + ter_state->pBER = tber; + + (*ber) = tber; + + return 0; +} +#if 0 +static u32 stv0367ter_get_per(struct stv0367_state *state) +{ + struct stv0367ter_state *ter_state = state->ter_state; + u32 Errors = 0, Per = 0, temporary = 0; + int abc = 0, def = 0, cpt = 0; + + while (((stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 1) && + (cpt < 400)) || ((Errors == 0) && (cpt < 400))) { + usleep_range(1000, 2000); + Errors = ((u32)stv0367_readbits(state, F367TER_ERR_CNT1) + * (1 << 16)) + + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI) + * (1 << 8)) + + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO)); + cpt++; + } + abc = stv0367_readbits(state, F367TER_ERR_SRC1); + def = stv0367_readbits(state, F367TER_NUM_EVT1); + + if (Errors == 0) + Per = 0; + else if (abc == 0x9) { + if (Errors <= 4) { + temporary = (Errors * 1000000000) / (8 * (1 << 8)); + temporary = temporary; + } else if (Errors <= 42) { + temporary = (Errors * 100000000) / (8 * (1 << 8)); + temporary = temporary * 10; + } else if (Errors <= 429) { + temporary = (Errors * 10000000) / (8 * (1 << 8)); + temporary = temporary * 100; + } else if (Errors <= 4294) { + temporary = (Errors * 1000000) / (8 * (1 << 8)); + temporary = temporary * 1000; + } else if (Errors <= 42949) { + temporary = (Errors * 100000) / (8 * (1 << 8)); + temporary = temporary * 10000; + } else { /*if(Errors<=429496) 2^16 errors max*/ + temporary = (Errors * 10000) / (8 * (1 << 8)); + temporary = temporary * 100000; + } + + /* pkt error*/ + if (def == 2) + /*Per=Errors/(1 << 8);*/ + Per = temporary; + else if (def == 3) + /*Per=Errors/(1 << 10);*/ + Per = temporary / 4; + else if (def == 4) + /*Per=Errors/(1 << 12);*/ + Per = temporary / 16; + else if (def == 5) + /*Per=Errors/(1 << 14);*/ + Per = temporary / 64; + else if (def == 6) + /*Per=Errors/(1 << 16);*/ + Per = temporary / 256; + else + Per = 0; + + } + /* save actual value */ + ter_state->pPER = Per; + + return Per; +} +#endif +static int stv0367_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings + *fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 1000; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + + return 0; +} + +static void stv0367_release(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + + kfree(state->ter_state); + kfree(state->cab_state); + kfree(state); +} + +static struct dvb_frontend_ops stv0367ter_ops = { + .info = { + .name = "ST STV0367 DVB-T", + .type = FE_OFDM, + .frequency_min = 47000000, + .frequency_max = 862000000, + .frequency_stepsize = 15625, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | + FE_CAN_INVERSION_AUTO | + FE_CAN_MUTE_TS + }, + .release = stv0367_release, + .init = stv0367ter_init, + .sleep = stv0367ter_sleep, + .i2c_gate_ctrl = stv0367ter_gate_ctrl, + .set_frontend = stv0367ter_set_frontend, + .get_frontend = stv0367ter_get_frontend, + .get_tune_settings = stv0367_get_tune_settings, + .read_status = stv0367ter_read_status, + .read_ber = stv0367ter_read_ber,/* too slow */ +/* .read_signal_strength = stv0367_read_signal_strength,*/ + .read_snr = stv0367ter_read_snr, + .read_ucblocks = stv0367ter_read_ucblocks, +}; + +struct dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c) +{ + struct stv0367_state *state = NULL; + struct stv0367ter_state *ter_state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL); + if (state == NULL) + goto error; + ter_state = kzalloc(sizeof(struct stv0367ter_state), GFP_KERNEL); + if (ter_state == NULL) + goto error; + + /* setup the state */ + state->i2c = i2c; + state->config = config; + state->ter_state = ter_state; + state->fe.ops = stv0367ter_ops; + state->fe.demodulator_priv = state; + state->chip_id = stv0367_readreg(state, 0xf000); + + dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id); + + /* check if the demod is there */ + if ((state->chip_id != 0x50) && (state->chip_id != 0x60)) + goto error; + + return &state->fe; + +error: + kfree(ter_state); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stv0367ter_attach); + +static int stv0367cab_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + stv0367_writebits(state, F367CAB_I2CT_ON, (enable > 0) ? 1 : 0); + + return 0; +} + +static u32 stv0367cab_get_mclk(struct dvb_frontend *fe, u32 ExtClk_Hz) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 mclk_Hz = 0;/* master clock frequency (Hz) */ + u32 M, N, P; + + + if (stv0367_readbits(state, F367CAB_BYPASS_PLLXN) == 0) { + N = (u32)stv0367_readbits(state, F367CAB_PLL_NDIV); + if (N == 0) + N = N + 1; + + M = (u32)stv0367_readbits(state, F367CAB_PLL_MDIV); + if (M == 0) + M = M + 1; + + P = (u32)stv0367_readbits(state, F367CAB_PLL_PDIV); + + if (P > 5) + P = 5; + + mclk_Hz = ((ExtClk_Hz / 2) * N) / (M * (1 << P)); + dprintk("stv0367cab_get_mclk BYPASS_PLLXN mclk_Hz=%d\n", + mclk_Hz); + } else + mclk_Hz = ExtClk_Hz; + + dprintk("stv0367cab_get_mclk final mclk_Hz=%d\n", mclk_Hz); + + return mclk_Hz; +} + +static u32 stv0367cab_get_adc_freq(struct dvb_frontend *fe, u32 ExtClk_Hz) +{ + u32 ADCClk_Hz = ExtClk_Hz; + + ADCClk_Hz = stv0367cab_get_mclk(fe, ExtClk_Hz); + + return ADCClk_Hz; +} + +enum stv0367cab_mod stv0367cab_SetQamSize(struct stv0367_state *state, + u32 SymbolRate, + enum stv0367cab_mod QAMSize) +{ + /* Set QAM size */ + stv0367_writebits(state, F367CAB_QAM_MODE, QAMSize); + + /* Set Registers settings specific to the QAM size */ + switch (QAMSize) { + case FE_CAB_MOD_QAM4: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + break; + case FE_CAB_MOD_QAM16: + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x64); + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + stv0367_writereg(state, R367CAB_FSM_STATE, 0x90); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x8a); + break; + case FE_CAB_MOD_QAM32: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x6e); + stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xb7); + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x9d); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7); + break; + case FE_CAB_MOD_QAM64: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x82); + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a); + if (SymbolRate > 45000000) { + stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa5); + } else if (SymbolRate > 25000000) { + stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6); + } else { + stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); + } + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x99); + break; + case FE_CAB_MOD_QAM128: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x76); + stv0367_writereg(state, R367CAB_FSM_STATE, 0x90); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xb1); + if (SymbolRate > 45000000) + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); + else if (SymbolRate > 25000000) + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6); + else + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0x97); + + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x8e); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7); + break; + case FE_CAB_MOD_QAM256: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x94); + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a); + stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0); + if (SymbolRate > 45000000) + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + else if (SymbolRate > 25000000) + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + else + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1); + + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x85); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7); + break; + case FE_CAB_MOD_QAM512: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + break; + case FE_CAB_MOD_QAM1024: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + break; + default: + break; + } + + return QAMSize; +} + +static u32 stv0367cab_set_derot_freq(struct stv0367_state *state, + u32 adc_hz, s32 derot_hz) +{ + u32 sampled_if = 0; + u32 adc_khz; + + adc_khz = adc_hz / 1000; + + dprintk("%s: adc_hz=%d derot_hz=%d\n", __func__, adc_hz, derot_hz); + + if (adc_khz != 0) { + if (derot_hz < 1000000) + derot_hz = adc_hz / 4; /* ZIF operation */ + if (derot_hz > adc_hz) + derot_hz = derot_hz - adc_hz; + sampled_if = (u32)derot_hz / 1000; + sampled_if *= 32768; + sampled_if /= adc_khz; + sampled_if *= 256; + } + + if (sampled_if > 8388607) + sampled_if = 8388607; + + dprintk("%s: sampled_if=0x%x\n", __func__, sampled_if); + + stv0367_writereg(state, R367CAB_MIX_NCO_LL, sampled_if); + stv0367_writereg(state, R367CAB_MIX_NCO_HL, (sampled_if >> 8)); + stv0367_writebits(state, F367CAB_MIX_NCO_INC_HH, (sampled_if >> 16)); + + return derot_hz; +} + +static u32 stv0367cab_get_derot_freq(struct stv0367_state *state, u32 adc_hz) +{ + u32 sampled_if; + + sampled_if = stv0367_readbits(state, F367CAB_MIX_NCO_INC_LL) + + (stv0367_readbits(state, F367CAB_MIX_NCO_INC_HL) << 8) + + (stv0367_readbits(state, F367CAB_MIX_NCO_INC_HH) << 16); + + sampled_if /= 256; + sampled_if *= (adc_hz / 1000); + sampled_if += 1; + sampled_if /= 32768; + + return sampled_if; +} + +static u32 stv0367cab_set_srate(struct stv0367_state *state, u32 adc_hz, + u32 mclk_hz, u32 SymbolRate, + enum stv0367cab_mod QAMSize) +{ + u32 QamSizeCorr = 0; + u32 u32_tmp = 0, u32_tmp1 = 0; + u32 adp_khz; + + dprintk("%s:\n", __func__); + + /* Set Correction factor of SRC gain */ + switch (QAMSize) { + case FE_CAB_MOD_QAM4: + QamSizeCorr = 1110; + break; + case FE_CAB_MOD_QAM16: + QamSizeCorr = 1032; + break; + case FE_CAB_MOD_QAM32: + QamSizeCorr = 954; + break; + case FE_CAB_MOD_QAM64: + QamSizeCorr = 983; + break; + case FE_CAB_MOD_QAM128: + QamSizeCorr = 957; + break; + case FE_CAB_MOD_QAM256: + QamSizeCorr = 948; + break; + case FE_CAB_MOD_QAM512: + QamSizeCorr = 0; + break; + case FE_CAB_MOD_QAM1024: + QamSizeCorr = 944; + break; + default: + break; + } + + /* Transfer ratio calculation */ + if (adc_hz != 0) { + u32_tmp = 256 * SymbolRate; + u32_tmp = u32_tmp / adc_hz; + } + stv0367_writereg(state, R367CAB_EQU_CRL_TFR, (u8)u32_tmp); + + /* Symbol rate and SRC gain calculation */ + adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */ + if (adp_khz != 0) { + u32_tmp = SymbolRate; + u32_tmp1 = SymbolRate; + + if (u32_tmp < 2097152) { /* 2097152 = 2^21 */ + /* Symbol rate calculation */ + u32_tmp *= 2048; /* 2048 = 2^11 */ + u32_tmp = u32_tmp / adp_khz; + u32_tmp = u32_tmp * 16384; /* 16384 = 2^14 */ + u32_tmp /= 125 ; /* 125 = 1000/2^3 */ + u32_tmp = u32_tmp * 8; /* 8 = 2^3 */ + + /* SRC Gain Calculation */ + u32_tmp1 *= 2048; /* *2*2^10 */ + u32_tmp1 /= 439; /* *2/878 */ + u32_tmp1 *= 256; /* *2^8 */ + u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */ + u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ + u32_tmp1 = u32_tmp1 / 10000000; + + } else if (u32_tmp < 4194304) { /* 4194304 = 2**22 */ + /* Symbol rate calculation */ + u32_tmp *= 1024 ; /* 1024 = 2**10 */ + u32_tmp = u32_tmp / adp_khz; + u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */ + u32_tmp /= 125 ; /* 125 = 1000/2**3 */ + u32_tmp = u32_tmp * 16; /* 16 = 2**4 */ + + /* SRC Gain Calculation */ + u32_tmp1 *= 1024; /* *2*2^9 */ + u32_tmp1 /= 439; /* *2/878 */ + u32_tmp1 *= 256; /* *2^8 */ + u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz)*/ + u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ + u32_tmp1 = u32_tmp1 / 5000000; + } else if (u32_tmp < 8388607) { /* 8388607 = 2**23 */ + /* Symbol rate calculation */ + u32_tmp *= 512 ; /* 512 = 2**9 */ + u32_tmp = u32_tmp / adp_khz; + u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */ + u32_tmp /= 125 ; /* 125 = 1000/2**3 */ + u32_tmp = u32_tmp * 32; /* 32 = 2**5 */ + + /* SRC Gain Calculation */ + u32_tmp1 *= 512; /* *2*2^8 */ + u32_tmp1 /= 439; /* *2/878 */ + u32_tmp1 *= 256; /* *2^8 */ + u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */ + u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ + u32_tmp1 = u32_tmp1 / 2500000; + } else { + /* Symbol rate calculation */ + u32_tmp *= 256 ; /* 256 = 2**8 */ + u32_tmp = u32_tmp / adp_khz; + u32_tmp = u32_tmp * 16384; /* 16384 = 2**13 */ + u32_tmp /= 125 ; /* 125 = 1000/2**3 */ + u32_tmp = u32_tmp * 64; /* 64 = 2**6 */ + + /* SRC Gain Calculation */ + u32_tmp1 *= 256; /* 2*2^7 */ + u32_tmp1 /= 439; /* *2/878 */ + u32_tmp1 *= 256; /* *2^8 */ + u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */ + u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ + u32_tmp1 = u32_tmp1 / 1250000; + } + } +#if 0 + /* Filters' coefficients are calculated and written + into registers only if the filters are enabled */ + if (stv0367_readbits(state, F367CAB_ADJ_EN)) { + stv0367cab_SetIirAdjacentcoefficient(state, mclk_hz, + SymbolRate); + /* AllPass filter must be enabled + when the adjacents filter is used */ + stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 1); + stv0367cab_SetAllPasscoefficient(state, mclk_hz, SymbolRate); + } else + /* AllPass filter must be disabled + when the adjacents filter is not used */ +#endif + stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0); + + stv0367_writereg(state, R367CAB_SRC_NCO_LL, u32_tmp); + stv0367_writereg(state, R367CAB_SRC_NCO_LH, (u32_tmp >> 8)); + stv0367_writereg(state, R367CAB_SRC_NCO_HL, (u32_tmp >> 16)); + stv0367_writereg(state, R367CAB_SRC_NCO_HH, (u32_tmp >> 24)); + + stv0367_writereg(state, R367CAB_IQDEM_GAIN_SRC_L, u32_tmp1 & 0x00ff); + stv0367_writebits(state, F367CAB_GAIN_SRC_HI, (u32_tmp1 >> 8) & 0x00ff); + + return SymbolRate ; +} + +static u32 stv0367cab_GetSymbolRate(struct stv0367_state *state, u32 mclk_hz) +{ + u32 regsym; + u32 adp_khz; + + regsym = stv0367_readreg(state, R367CAB_SRC_NCO_LL) + + (stv0367_readreg(state, R367CAB_SRC_NCO_LH) << 8) + + (stv0367_readreg(state, R367CAB_SRC_NCO_HL) << 16) + + (stv0367_readreg(state, R367CAB_SRC_NCO_HH) << 24); + + adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */ + + if (regsym < 134217728) { /* 134217728L = 2**27*/ + regsym = regsym * 32; /* 32 = 2**5 */ + regsym = regsym / 32768; /* 32768L = 2**15 */ + regsym = adp_khz * regsym; /* AdpClk in kHz */ + regsym = regsym / 128; /* 128 = 2**7 */ + regsym *= 125 ; /* 125 = 1000/2**3 */ + regsym /= 2048 ; /* 2048 = 2**11 */ + } else if (regsym < 268435456) { /* 268435456L = 2**28 */ + regsym = regsym * 16; /* 16 = 2**4 */ + regsym = regsym / 32768; /* 32768L = 2**15 */ + regsym = adp_khz * regsym; /* AdpClk in kHz */ + regsym = regsym / 128; /* 128 = 2**7 */ + regsym *= 125 ; /* 125 = 1000/2**3*/ + regsym /= 1024 ; /* 256 = 2**10*/ + } else if (regsym < 536870912) { /* 536870912L = 2**29*/ + regsym = regsym * 8; /* 8 = 2**3 */ + regsym = regsym / 32768; /* 32768L = 2**15 */ + regsym = adp_khz * regsym; /* AdpClk in kHz */ + regsym = regsym / 128; /* 128 = 2**7 */ + regsym *= 125 ; /* 125 = 1000/2**3 */ + regsym /= 512 ; /* 128 = 2**9 */ + } else { + regsym = regsym * 4; /* 4 = 2**2 */ + regsym = regsym / 32768; /* 32768L = 2**15 */ + regsym = adp_khz * regsym; /* AdpClk in kHz */ + regsym = regsym / 128; /* 128 = 2**7 */ + regsym *= 125 ; /* 125 = 1000/2**3 */ + regsym /= 256 ; /* 64 = 2**8 */ + } + + return regsym; +} + +static int stv0367cab_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + *status = 0; + + if (stv0367_readbits(state, F367CAB_QAMFEC_LOCK)) { + *status |= FE_HAS_LOCK; + dprintk("%s: stv0367 has locked\n", __func__); + } + + return 0; +} + +static int stv0367cab_standby(struct dvb_frontend *fe, u8 standby_on) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + if (standby_on) { + stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x03); + stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x01); + stv0367_writebits(state, F367CAB_STDBY, 1); + stv0367_writebits(state, F367CAB_STDBY_CORE, 1); + stv0367_writebits(state, F367CAB_EN_BUFFER_I, 0); + stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 0); + stv0367_writebits(state, F367CAB_POFFQ, 1); + stv0367_writebits(state, F367CAB_POFFI, 1); + } else { + stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x00); + stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x00); + stv0367_writebits(state, F367CAB_STDBY, 0); + stv0367_writebits(state, F367CAB_STDBY_CORE, 0); + stv0367_writebits(state, F367CAB_EN_BUFFER_I, 1); + stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 1); + stv0367_writebits(state, F367CAB_POFFQ, 0); + stv0367_writebits(state, F367CAB_POFFI, 0); + } + + return 0; +} + +static int stv0367cab_sleep(struct dvb_frontend *fe) +{ + return stv0367cab_standby(fe, 1); +} + +int stv0367cab_init(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367cab_state *cab_state = state->cab_state; + int i; + + dprintk("%s:\n", __func__); + + for (i = 0; i < STV0367CAB_NBREGS; i++) + stv0367_writereg(state, def0367cab[i].addr, + def0367cab[i].value); + + switch (state->config->ts_mode) { + case STV0367_DVBCI_CLOCK: + dprintk("Setting TSMode = STV0367_DVBCI_CLOCK\n"); + stv0367_writebits(state, F367CAB_OUTFORMAT, 0x03); + break; + case STV0367_SERIAL_PUNCT_CLOCK: + case STV0367_SERIAL_CONT_CLOCK: + stv0367_writebits(state, F367CAB_OUTFORMAT, 0x01); + break; + case STV0367_PARALLEL_PUNCT_CLOCK: + case STV0367_OUTPUTMODE_DEFAULT: + stv0367_writebits(state, F367CAB_OUTFORMAT, 0x00); + break; + } + + switch (state->config->clk_pol) { + case STV0367_RISINGEDGE_CLOCK: + stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x00); + break; + case STV0367_FALLINGEDGE_CLOCK: + case STV0367_CLOCKPOLARITY_DEFAULT: + stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x01); + break; + } + + stv0367_writebits(state, F367CAB_SYNC_STRIP, 0x00); + + stv0367_writebits(state, F367CAB_CT_NBST, 0x01); + + stv0367_writebits(state, F367CAB_TS_SWAP, 0x01); + + stv0367_writebits(state, F367CAB_FIFO_BYPASS, 0x00); + + stv0367_writereg(state, R367CAB_ANACTRL, 0x00);/*PLL enabled and used */ + + cab_state->mclk = stv0367cab_get_mclk(fe, state->config->xtal); + cab_state->adc_clk = stv0367cab_get_adc_freq(fe, state->config->xtal); + + return 0; +} +static +enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, + struct dvb_frontend_parameters *param) +{ + struct dvb_qam_parameters *op = ¶m->u.qam; + struct stv0367cab_state *cab_state = state->cab_state; + enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC; + u32 QAMFEC_Lock, QAM_Lock, u32_tmp, + LockTime, TRLTimeOut, AGCTimeOut, CRLSymbols, + CRLTimeOut, EQLTimeOut, DemodTimeOut, FECTimeOut; + u8 TrackAGCAccum; + s32 tmp; + + dprintk("%s:\n", __func__); + + /* Timeouts calculation */ + /* A max lock time of 25 ms is allowed for delayed AGC */ + AGCTimeOut = 25; + /* 100000 symbols needed by the TRL as a maximum value */ + TRLTimeOut = 100000000 / op->symbol_rate; + /* CRLSymbols is the needed number of symbols to achieve a lock + within [-4%, +4%] of the symbol rate. + CRL timeout is calculated + for a lock within [-search_range, +search_range]. + EQL timeout can be changed depending on + the micro-reflections we want to handle. + A characterization must be performed + with these echoes to get new timeout values. + */ + switch (op->modulation) { + case QAM_16: + CRLSymbols = 150000; + EQLTimeOut = 100; + break; + case QAM_32: + CRLSymbols = 250000; + EQLTimeOut = 100; + break; + case QAM_64: + CRLSymbols = 200000; + EQLTimeOut = 100; + break; + case QAM_128: + CRLSymbols = 250000; + EQLTimeOut = 100; + break; + case QAM_256: + CRLSymbols = 250000; + EQLTimeOut = 100; + break; + default: + CRLSymbols = 200000; + EQLTimeOut = 100; + break; + } +#if 0 + if (pIntParams->search_range < 0) { + CRLTimeOut = (25 * CRLSymbols * + (-pIntParams->search_range / 1000)) / + (pIntParams->symbol_rate / 1000); + } else +#endif + CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) / + (op->symbol_rate / 1000); + + CRLTimeOut = (1000 * CRLTimeOut) / op->symbol_rate; + /* Timeouts below 50ms are coerced */ + if (CRLTimeOut < 50) + CRLTimeOut = 50; + /* A maximum of 100 TS packets is needed to get FEC lock even in case + the spectrum inversion needs to be changed. + This is equal to 20 ms in case of the lowest symbol rate of 0.87Msps + */ + FECTimeOut = 20; + DemodTimeOut = AGCTimeOut + TRLTimeOut + CRLTimeOut + EQLTimeOut; + + dprintk("%s: DemodTimeOut=%d\n", __func__, DemodTimeOut); + + /* Reset the TRL to ensure nothing starts until the + AGC is stable which ensures a better lock time + */ + stv0367_writereg(state, R367CAB_CTRL_1, 0x04); + /* Set AGC accumulation time to minimum and lock threshold to maximum + in order to speed up the AGC lock */ + TrackAGCAccum = stv0367_readbits(state, F367CAB_AGC_ACCUMRSTSEL); + stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, 0x0); + /* Modulus Mapper is disabled */ + stv0367_writebits(state, F367CAB_MODULUSMAP_EN, 0); + /* Disable the sweep function */ + stv0367_writebits(state, F367CAB_SWEEP_EN, 0); + /* The sweep function is never used, Sweep rate must be set to 0 */ + /* Set the derotator frequency in Hz */ + stv0367cab_set_derot_freq(state, cab_state->adc_clk, + (1000 * (s32)state->config->if_khz + cab_state->derot_offset)); + /* Disable the Allpass Filter when the symbol rate is out of range */ + if ((op->symbol_rate > 10800000) | (op->symbol_rate < 1800000)) { + stv0367_writebits(state, F367CAB_ADJ_EN, 0); + stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0); + } +#if 0 + /* Check if the tuner is locked */ + tuner_lock = stv0367cab_tuner_get_status(fe); + if (tuner_lock == 0) + return FE_367CAB_NOTUNER; +#endif + /* Relase the TRL to start demodulator acquisition */ + /* Wait for QAM lock */ + LockTime = 0; + stv0367_writereg(state, R367CAB_CTRL_1, 0x00); + do { + QAM_Lock = stv0367_readbits(state, F367CAB_FSM_STATUS); + if ((LockTime >= (DemodTimeOut - EQLTimeOut)) && + (QAM_Lock == 0x04)) + /* + * We don't wait longer, the frequency/phase offset + * must be too big + */ + LockTime = DemodTimeOut; + else if ((LockTime >= (AGCTimeOut + TRLTimeOut)) && + (QAM_Lock == 0x02)) + /* + * We don't wait longer, either there is no signal or + * it is not the right symbol rate or it is an analog + * carrier + */ + { + LockTime = DemodTimeOut; + u32_tmp = stv0367_readbits(state, + F367CAB_AGC_PWR_WORD_LO) + + (stv0367_readbits(state, + F367CAB_AGC_PWR_WORD_ME) << 8) + + (stv0367_readbits(state, + F367CAB_AGC_PWR_WORD_HI) << 16); + if (u32_tmp >= 131072) + u32_tmp = 262144 - u32_tmp; + u32_tmp = u32_tmp / (1 << (11 - stv0367_readbits(state, + F367CAB_AGC_IF_BWSEL))); + + if (u32_tmp < stv0367_readbits(state, + F367CAB_AGC_PWRREF_LO) + + 256 * stv0367_readbits(state, + F367CAB_AGC_PWRREF_HI) - 10) + QAM_Lock = 0x0f; + } else { + usleep_range(10000, 20000); + LockTime += 10; + } + dprintk("QAM_Lock=0x%x LockTime=%d\n", QAM_Lock, LockTime); + tmp = stv0367_readreg(state, R367CAB_IT_STATUS1); + + dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp); + + } while (((QAM_Lock != 0x0c) && (QAM_Lock != 0x0b)) && + (LockTime < DemodTimeOut)); + + dprintk("QAM_Lock=0x%x\n", QAM_Lock); + + tmp = stv0367_readreg(state, R367CAB_IT_STATUS1); + dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp); + tmp = stv0367_readreg(state, R367CAB_IT_STATUS2); + dprintk("R367CAB_IT_STATUS2=0x%x\n", tmp); + + tmp = stv0367cab_get_derot_freq(state, cab_state->adc_clk); + dprintk("stv0367cab_get_derot_freq=0x%x\n", tmp); + + if ((QAM_Lock == 0x0c) || (QAM_Lock == 0x0b)) { + /* Wait for FEC lock */ + LockTime = 0; + do { + usleep_range(5000, 7000); + LockTime += 5; + QAMFEC_Lock = stv0367_readbits(state, + F367CAB_QAMFEC_LOCK); + } while (!QAMFEC_Lock && (LockTime < FECTimeOut)); + } else + QAMFEC_Lock = 0; + + if (QAMFEC_Lock) { + signalType = FE_CAB_DATAOK; + cab_state->modulation = op->modulation; + cab_state->spect_inv = stv0367_readbits(state, + F367CAB_QUAD_INV); +#if 0 +/* not clear for me */ + if (state->config->if_khz != 0) { + if (state->config->if_khz > cab_state->adc_clk / 1000) { + cab_state->freq_khz = + FE_Cab_TunerGetFrequency(pIntParams->hTuner) + - stv0367cab_get_derot_freq(state, cab_state->adc_clk) + - cab_state->adc_clk / 1000 + state->config->if_khz; + } else { + cab_state->freq_khz = + FE_Cab_TunerGetFrequency(pIntParams->hTuner) + - stv0367cab_get_derot_freq(state, cab_state->adc_clk) + + state->config->if_khz; + } + } else { + cab_state->freq_khz = + FE_Cab_TunerGetFrequency(pIntParams->hTuner) + + stv0367cab_get_derot_freq(state, + cab_state->adc_clk) - + cab_state->adc_clk / 4000; + } +#endif + cab_state->symbol_rate = stv0367cab_GetSymbolRate(state, + cab_state->mclk); + cab_state->locked = 1; + + /* stv0367_setbits(state, F367CAB_AGC_ACCUMRSTSEL,7);*/ + } else { + switch (QAM_Lock) { + case 1: + signalType = FE_CAB_NOAGC; + break; + case 2: + signalType = FE_CAB_NOTIMING; + break; + case 3: + signalType = FE_CAB_TIMINGOK; + break; + case 4: + signalType = FE_CAB_NOCARRIER; + break; + case 5: + signalType = FE_CAB_CARRIEROK; + break; + case 7: + signalType = FE_CAB_NOBLIND; + break; + case 8: + signalType = FE_CAB_BLINDOK; + break; + case 10: + signalType = FE_CAB_NODEMOD; + break; + case 11: + signalType = FE_CAB_DEMODOK; + break; + case 12: + signalType = FE_CAB_DEMODOK; + break; + case 13: + signalType = FE_CAB_NODEMOD; + break; + case 14: + signalType = FE_CAB_NOBLIND; + break; + case 15: + signalType = FE_CAB_NOSIGNAL; + break; + default: + break; + } + + } + + /* Set the AGC control values to tracking values */ + stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, TrackAGCAccum); + return signalType; +} + +static int stv0367cab_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367cab_state *cab_state = state->cab_state; + struct dvb_qam_parameters *op = ¶m->u.qam; + enum stv0367cab_mod QAMSize = 0; + + dprintk("%s: freq = %d, srate = %d\n", __func__, + param->frequency, op->symbol_rate); + + cab_state->derot_offset = 0; + + switch (op->modulation) { + case QAM_16: + QAMSize = FE_CAB_MOD_QAM16; + break; + case QAM_32: + QAMSize = FE_CAB_MOD_QAM32; + break; + case QAM_64: + QAMSize = FE_CAB_MOD_QAM64; + break; + case QAM_128: + QAMSize = FE_CAB_MOD_QAM128; + break; + case QAM_256: + QAMSize = FE_CAB_MOD_QAM256; + break; + default: + break; + } + + stv0367cab_init(fe); + + /* Tuner Frequency Setting */ + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + stv0367cab_SetQamSize( + state, + op->symbol_rate, + QAMSize); + + stv0367cab_set_srate(state, + cab_state->adc_clk, + cab_state->mclk, + op->symbol_rate, + QAMSize); + /* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */ + cab_state->state = stv0367cab_algo(state, param); + return 0; +} + +static int stv0367cab_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367cab_state *cab_state = state->cab_state; + struct dvb_qam_parameters *op = ¶m->u.qam; + + enum stv0367cab_mod QAMSize; + + dprintk("%s:\n", __func__); + + op->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk); + + QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); + switch (QAMSize) { + case FE_CAB_MOD_QAM16: + op->modulation = QAM_16; + break; + case FE_CAB_MOD_QAM32: + op->modulation = QAM_32; + break; + case FE_CAB_MOD_QAM64: + op->modulation = QAM_64; + break; + case FE_CAB_MOD_QAM128: + op->modulation = QAM_128; + break; + case QAM_256: + op->modulation = QAM_256; + break; + default: + break; + } + + param->frequency = stv0367_get_tuner_freq(fe); + + dprintk("%s: tuner frequency = %d\n", __func__, param->frequency); + + if (state->config->if_khz == 0) { + param->frequency += + (stv0367cab_get_derot_freq(state, cab_state->adc_clk) - + cab_state->adc_clk / 4000); + return 0; + } + + if (state->config->if_khz > cab_state->adc_clk / 1000) + param->frequency += (state->config->if_khz + - stv0367cab_get_derot_freq(state, cab_state->adc_clk) + - cab_state->adc_clk / 1000); + else + param->frequency += (state->config->if_khz + - stv0367cab_get_derot_freq(state, cab_state->adc_clk)); + + return 0; +} + +#if 0 +void stv0367cab_GetErrorCount(state, enum stv0367cab_mod QAMSize, + u32 symbol_rate, FE_367qam_Monitor *Monitor_results) +{ + stv0367cab_OptimiseNByteAndGetBER(state, QAMSize, symbol_rate, Monitor_results); + stv0367cab_GetPacketsCount(state, Monitor_results); + + return; +} + +static int stv0367cab_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stv0367_state *state = fe->demodulator_priv; + + return 0; +} +#endif +static s32 stv0367cab_get_rf_lvl(struct stv0367_state *state) +{ + s32 rfLevel = 0; + s32 RfAgcPwm = 0, IfAgcPwm = 0; + u8 i; + + stv0367_writebits(state, F367CAB_STDBY_ADCGP, 0x0); + + RfAgcPwm = + (stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_LO) & 0x03) + + (stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_HI) << 2); + RfAgcPwm = 100 * RfAgcPwm / 1023; + + IfAgcPwm = + stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_LO) + + (stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_HI) << 8); + if (IfAgcPwm >= 2048) + IfAgcPwm -= 2048; + else + IfAgcPwm += 2048; + + IfAgcPwm = 100 * IfAgcPwm / 4095; + + /* For DTT75467 on NIM */ + if (RfAgcPwm < 90 && IfAgcPwm < 28) { + for (i = 0; i < RF_LOOKUP_TABLE_SIZE; i++) { + if (RfAgcPwm <= stv0367cab_RF_LookUp1[0][i]) { + rfLevel = (-1) * stv0367cab_RF_LookUp1[1][i]; + break; + } + } + if (i == RF_LOOKUP_TABLE_SIZE) + rfLevel = -56; + } else { /*if IF AGC>10*/ + for (i = 0; i < RF_LOOKUP_TABLE2_SIZE; i++) { + if (IfAgcPwm <= stv0367cab_RF_LookUp2[0][i]) { + rfLevel = (-1) * stv0367cab_RF_LookUp2[1][i]; + break; + } + } + if (i == RF_LOOKUP_TABLE2_SIZE) + rfLevel = -72; + } + return rfLevel; +} + +static int stv0367cab_read_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stv0367_state *state = fe->demodulator_priv; + + s32 signal = stv0367cab_get_rf_lvl(state); + + dprintk("%s: signal=%d dBm\n", __func__, signal); + + if (signal <= -72) + *strength = 65535; + else + *strength = (22 + signal) * (-1311); + + dprintk("%s: strength=%d\n", __func__, (*strength)); + + return 0; +} + +static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 noisepercentage; + enum stv0367cab_mod QAMSize; + u32 regval = 0, temp = 0; + int power, i; + + QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); + switch (QAMSize) { + case FE_CAB_MOD_QAM4: + power = 21904; + break; + case FE_CAB_MOD_QAM16: + power = 20480; + break; + case FE_CAB_MOD_QAM32: + power = 23040; + break; + case FE_CAB_MOD_QAM64: + power = 21504; + break; + case FE_CAB_MOD_QAM128: + power = 23616; + break; + case FE_CAB_MOD_QAM256: + power = 21760; + break; + case FE_CAB_MOD_QAM512: + power = 1; + break; + case FE_CAB_MOD_QAM1024: + power = 21280; + break; + default: + power = 1; + break; + } + + for (i = 0; i < 10; i++) { + regval += (stv0367_readbits(state, F367CAB_SNR_LO) + + 256 * stv0367_readbits(state, F367CAB_SNR_HI)); + } + + regval /= 10; /*for average over 10 times in for loop above*/ + if (regval != 0) { + temp = power + * (1 << (3 + stv0367_readbits(state, F367CAB_SNR_PER))); + temp /= regval; + } + + /* table values, not needed to calculate logarithms */ + if (temp >= 5012) + noisepercentage = 100; + else if (temp >= 3981) + noisepercentage = 93; + else if (temp >= 3162) + noisepercentage = 86; + else if (temp >= 2512) + noisepercentage = 79; + else if (temp >= 1995) + noisepercentage = 72; + else if (temp >= 1585) + noisepercentage = 65; + else if (temp >= 1259) + noisepercentage = 58; + else if (temp >= 1000) + noisepercentage = 50; + else if (temp >= 794) + noisepercentage = 43; + else if (temp >= 501) + noisepercentage = 36; + else if (temp >= 316) + noisepercentage = 29; + else if (temp >= 200) + noisepercentage = 22; + else if (temp >= 158) + noisepercentage = 14; + else if (temp >= 126) + noisepercentage = 7; + else + noisepercentage = 0; + + dprintk("%s: noisepercentage=%d\n", __func__, noisepercentage); + + *snr = (noisepercentage * 65535) / 100; + + return 0; +} + +static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct stv0367_state *state = fe->demodulator_priv; + int corrected, tscount; + + *ucblocks = (stv0367_readreg(state, R367CAB_RS_COUNTER_5) << 8) + | stv0367_readreg(state, R367CAB_RS_COUNTER_4); + corrected = (stv0367_readreg(state, R367CAB_RS_COUNTER_3) << 8) + | stv0367_readreg(state, R367CAB_RS_COUNTER_2); + tscount = (stv0367_readreg(state, R367CAB_RS_COUNTER_2) << 8) + | stv0367_readreg(state, R367CAB_RS_COUNTER_1); + + dprintk("%s: uncorrected blocks=%d corrected blocks=%d tscount=%d\n", + __func__, *ucblocks, corrected, tscount); + + return 0; +}; + +static struct dvb_frontend_ops stv0367cab_ops = { + .info = { + .name = "ST STV0367 DVB-C", + .type = FE_QAM, + .frequency_min = 47000000, + .frequency_max = 862000000, + .frequency_stepsize = 62500, + .symbol_rate_min = 870000, + .symbol_rate_max = 11700000, + .caps = 0x400 |/* FE_CAN_QAM_4 */ + FE_CAN_QAM_16 | FE_CAN_QAM_32 | + FE_CAN_QAM_64 | FE_CAN_QAM_128 | + FE_CAN_QAM_256 | FE_CAN_FEC_AUTO + }, + .release = stv0367_release, + .init = stv0367cab_init, + .sleep = stv0367cab_sleep, + .i2c_gate_ctrl = stv0367cab_gate_ctrl, + .set_frontend = stv0367cab_set_frontend, + .get_frontend = stv0367cab_get_frontend, + .read_status = stv0367cab_read_status, +/* .read_ber = stv0367cab_read_ber, */ + .read_signal_strength = stv0367cab_read_strength, + .read_snr = stv0367cab_read_snr, + .read_ucblocks = stv0367cab_read_ucblcks, + .get_tune_settings = stv0367_get_tune_settings, +}; + +struct dvb_frontend *stv0367cab_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c) +{ + struct stv0367_state *state = NULL; + struct stv0367cab_state *cab_state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL); + if (state == NULL) + goto error; + cab_state = kzalloc(sizeof(struct stv0367cab_state), GFP_KERNEL); + if (cab_state == NULL) + goto error; + + /* setup the state */ + state->i2c = i2c; + state->config = config; + cab_state->search_range = 280000; + state->cab_state = cab_state; + state->fe.ops = stv0367cab_ops; + state->fe.demodulator_priv = state; + state->chip_id = stv0367_readreg(state, 0xf000); + + dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id); + + /* check if the demod is there */ + if ((state->chip_id != 0x50) && (state->chip_id != 0x60)) + goto error; + + return &state->fe; + +error: + kfree(cab_state); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stv0367cab_attach); + +MODULE_PARM_DESC(debug, "Set debug"); +MODULE_PARM_DESC(i2c_debug, "Set i2c debug"); + +MODULE_AUTHOR("Igor M. Liplianin"); +MODULE_DESCRIPTION("ST STV0367 DVB-C/T demodulator driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * stv0367.h + * + * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef STV0367_H +#define STV0367_H + +#include +#include "dvb_frontend.h" + +struct stv0367_config { + u8 demod_address; + u32 xtal; + u32 if_khz;/*4500*/ + int if_iq_mode; + int ts_mode; + int clk_pol; +}; + +#if defined(CONFIG_DVB_STV0367) || (defined(CONFIG_DVB_STV0367_MODULE) \ + && defined(MODULE)) +extern struct +dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c); +extern struct +dvb_frontend *stv0367cab_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c); +#else +static inline struct +dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline struct +dvb_frontend *stv0367cab_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,212 @@ +/* + * stv0367_priv.h + * + * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* Common driver error constants */ + +#ifndef STV0367_PRIV_H +#define STV0367_PRIV_H + +#ifndef TRUE + #define TRUE (1 == 1) +#endif +#ifndef FALSE + #define FALSE (!TRUE) +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* MACRO definitions */ +#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X)) +#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) +#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) +#define INRANGE(X, Y, Z) \ + ((((X) <= (Y)) && ((Y) <= (Z))) || \ + (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0) + +#ifndef MAKEWORD +#define MAKEWORD(X, Y) (((X) << 8) + (Y)) +#endif + +#define LSB(X) (((X) & 0xff)) +#define MSB(Y) (((Y) >> 8) & 0xff) +#define MMSB(Y)(((Y) >> 16) & 0xff) + +enum stv0367_ter_signal_type { + FE_TER_NOAGC = 0, + FE_TER_AGCOK = 5, + FE_TER_NOTPS = 6, + FE_TER_TPSOK = 7, + FE_TER_NOSYMBOL = 8, + FE_TER_BAD_CPQ = 9, + FE_TER_PRFOUNDOK = 10, + FE_TER_NOPRFOUND = 11, + FE_TER_LOCKOK = 12, + FE_TER_NOLOCK = 13, + FE_TER_SYMBOLOK = 15, + FE_TER_CPAMPOK = 16, + FE_TER_NOCPAMP = 17, + FE_TER_SWNOK = 18 +}; + +enum stv0367_ts_mode { + STV0367_OUTPUTMODE_DEFAULT, + STV0367_SERIAL_PUNCT_CLOCK, + STV0367_SERIAL_CONT_CLOCK, + STV0367_PARALLEL_PUNCT_CLOCK, + STV0367_DVBCI_CLOCK +}; + +enum stv0367_clk_pol { + STV0367_CLOCKPOLARITY_DEFAULT, + STV0367_RISINGEDGE_CLOCK, + STV0367_FALLINGEDGE_CLOCK +}; + +enum stv0367_ter_bw { + FE_TER_CHAN_BW_6M = 6, + FE_TER_CHAN_BW_7M = 7, + FE_TER_CHAN_BW_8M = 8 +}; + +#if 0 +enum FE_TER_Rate_TPS { + FE_TER_TPS_1_2 = 0, + FE_TER_TPS_2_3 = 1, + FE_TER_TPS_3_4 = 2, + FE_TER_TPS_5_6 = 3, + FE_TER_TPS_7_8 = 4 +}; +#endif + +enum stv0367_ter_mode { + FE_TER_MODE_2K, + FE_TER_MODE_8K, + FE_TER_MODE_4K +}; +#if 0 +enum FE_TER_Hierarchy_Alpha { + FE_TER_HIER_ALPHA_NONE, /* Regular modulation */ + FE_TER_HIER_ALPHA_1, /* Hierarchical modulation a = 1*/ + FE_TER_HIER_ALPHA_2, /* Hierarchical modulation a = 2*/ + FE_TER_HIER_ALPHA_4 /* Hierarchical modulation a = 4*/ +}; +#endif +enum stv0367_ter_hierarchy { + FE_TER_HIER_NONE, /*Hierarchy None*/ + FE_TER_HIER_LOW_PRIO, /*Hierarchy : Low Priority*/ + FE_TER_HIER_HIGH_PRIO, /*Hierarchy : High Priority*/ + FE_TER_HIER_PRIO_ANY /*Hierarchy :Any*/ +}; + +#if 0 +enum fe_stv0367_ter_spec { + FE_TER_INVERSION_NONE = 0, + FE_TER_INVERSION = 1, + FE_TER_INVERSION_AUTO = 2, + FE_TER_INVERSION_UNK = 4 +}; +#endif + +enum stv0367_ter_if_iq_mode { + FE_TER_NORMAL_IF_TUNER = 0, + FE_TER_LONGPATH_IF_TUNER = 1, + FE_TER_IQ_TUNER = 2 + +}; + +#if 0 +enum FE_TER_FECRate { + FE_TER_FEC_NONE = 0x00, /* no FEC rate specified */ + FE_TER_FEC_ALL = 0xFF, /* Logical OR of all FECs */ + FE_TER_FEC_1_2 = 1, + FE_TER_FEC_2_3 = (1 << 1), + FE_TER_FEC_3_4 = (1 << 2), + FE_TER_FEC_4_5 = (1 << 3), + FE_TER_FEC_5_6 = (1 << 4), + FE_TER_FEC_6_7 = (1 << 5), + FE_TER_FEC_7_8 = (1 << 6), + FE_TER_FEC_8_9 = (1 << 7) +}; + +enum FE_TER_Rate { + FE_TER_FE_1_2 = 0, + FE_TER_FE_2_3 = 1, + FE_TER_FE_3_4 = 2, + FE_TER_FE_5_6 = 3, + FE_TER_FE_6_7 = 4, + FE_TER_FE_7_8 = 5 +}; +#endif + +enum stv0367_ter_force { + FE_TER_FORCENONE = 0, + FE_TER_FORCE_M_G = 1 +}; + +enum stv0367cab_mod { + FE_CAB_MOD_QAM4, + FE_CAB_MOD_QAM16, + FE_CAB_MOD_QAM32, + FE_CAB_MOD_QAM64, + FE_CAB_MOD_QAM128, + FE_CAB_MOD_QAM256, + FE_CAB_MOD_QAM512, + FE_CAB_MOD_QAM1024 +}; +#if 0 +enum { + FE_CAB_FEC_A = 1, /* J83 Annex A */ + FE_CAB_FEC_B = (1 << 1),/* J83 Annex B */ + FE_CAB_FEC_C = (1 << 2) /* J83 Annex C */ +} FE_CAB_FECType_t; +#endif +struct stv0367_cab_signal_info { + int locked; + u32 frequency; /* kHz */ + u32 symbol_rate; /* Mbds */ + enum stv0367cab_mod modulation; + fe_spectral_inversion_t spect_inv; + s32 Power_dBmx10; /* Power of the RF signal (dBm x 10) */ + u32 CN_dBx10; /* Carrier to noise ratio (dB x 10) */ + u32 BER; /* Bit error rate (x 10000000) */ +}; + +enum stv0367_cab_signal_type { + FE_CAB_NOTUNER, + FE_CAB_NOAGC, + FE_CAB_NOSIGNAL, + FE_CAB_NOTIMING, + FE_CAB_TIMINGOK, + FE_CAB_NOCARRIER, + FE_CAB_CARRIEROK, + FE_CAB_NOBLIND, + FE_CAB_BLINDOK, + FE_CAB_NODEMOD, + FE_CAB_DEMODOK, + FE_CAB_DATAOK +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367_regs.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0367_regs.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3614 @@ +/* + * stv0367_regs.h + * + * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef STV0367_REGS_H +#define STV0367_REGS_H + +/* ID */ +#define R367TER_ID 0xf000 +#define F367TER_IDENTIFICATIONREG 0xf00000ff + +/* I2CRPT */ +#define R367TER_I2CRPT 0xf001 +#define F367TER_I2CT_ON 0xf0010080 +#define F367TER_ENARPT_LEVEL 0xf0010070 +#define F367TER_SCLT_DELAY 0xf0010008 +#define F367TER_SCLT_NOD 0xf0010004 +#define F367TER_STOP_ENABLE 0xf0010002 +#define F367TER_SDAT_NOD 0xf0010001 + +/* TOPCTRL */ +#define R367TER_TOPCTRL 0xf002 +#define F367TER_STDBY 0xf0020080 +#define F367TER_STDBY_FEC 0xf0020040 +#define F367TER_STDBY_CORE 0xf0020020 +#define F367TER_QAM_COFDM 0xf0020010 +#define F367TER_TS_DIS 0xf0020008 +#define F367TER_DIR_CLK_216 0xf0020004 +#define F367TER_TUNER_BB 0xf0020002 +#define F367TER_DVBT_H 0xf0020001 + +/* IOCFG0 */ +#define R367TER_IOCFG0 0xf003 +#define F367TER_OP0_SD 0xf0030080 +#define F367TER_OP0_VAL 0xf0030040 +#define F367TER_OP0_OD 0xf0030020 +#define F367TER_OP0_INV 0xf0030010 +#define F367TER_OP0_DACVALUE_HI 0xf003000f + +/* DAc0R */ +#define R367TER_DAC0R 0xf004 +#define F367TER_OP0_DACVALUE_LO 0xf00400ff + +/* IOCFG1 */ +#define R367TER_IOCFG1 0xf005 +#define F367TER_IP0 0xf0050040 +#define F367TER_OP1_OD 0xf0050020 +#define F367TER_OP1_INV 0xf0050010 +#define F367TER_OP1_DACVALUE_HI 0xf005000f + +/* DAC1R */ +#define R367TER_DAC1R 0xf006 +#define F367TER_OP1_DACVALUE_LO 0xf00600ff + +/* IOCFG2 */ +#define R367TER_IOCFG2 0xf007 +#define F367TER_OP2_LOCK_CONF 0xf00700e0 +#define F367TER_OP2_OD 0xf0070010 +#define F367TER_OP2_VAL 0xf0070008 +#define F367TER_OP1_LOCK_CONF 0xf0070007 + +/* SDFR */ +#define R367TER_SDFR 0xf008 +#define F367TER_OP0_FREQ 0xf00800f0 +#define F367TER_OP1_FREQ 0xf008000f + +/* STATUS */ +#define R367TER_STATUS 0xf009 +#define F367TER_TPS_LOCK 0xf0090080 +#define F367TER_SYR_LOCK 0xf0090040 +#define F367TER_AGC_LOCK 0xf0090020 +#define F367TER_PRF 0xf0090010 +#define F367TER_LK 0xf0090008 +#define F367TER_PR 0xf0090007 + +/* AUX_CLK */ +#define R367TER_AUX_CLK 0xf00a +#define F367TER_AUXFEC_CTL 0xf00a00c0 +#define F367TER_DIS_CKX4 0xf00a0020 +#define F367TER_CKSEL 0xf00a0018 +#define F367TER_CKDIV_PROG 0xf00a0006 +#define F367TER_AUXCLK_ENA 0xf00a0001 + +/* FREESYS1 */ +#define R367TER_FREESYS1 0xf00b +#define F367TER_FREE_SYS1 0xf00b00ff + +/* FREESYS2 */ +#define R367TER_FREESYS2 0xf00c +#define F367TER_FREE_SYS2 0xf00c00ff + +/* FREESYS3 */ +#define R367TER_FREESYS3 0xf00d +#define F367TER_FREE_SYS3 0xf00d00ff + +/* GPIO_CFG */ +#define R367TER_GPIO_CFG 0xf00e +#define F367TER_GPIO7_NOD 0xf00e0080 +#define F367TER_GPIO7_CFG 0xf00e0040 +#define F367TER_GPIO6_NOD 0xf00e0020 +#define F367TER_GPIO6_CFG 0xf00e0010 +#define F367TER_GPIO5_NOD 0xf00e0008 +#define F367TER_GPIO5_CFG 0xf00e0004 +#define F367TER_GPIO4_NOD 0xf00e0002 +#define F367TER_GPIO4_CFG 0xf00e0001 + +/* GPIO_CMD */ +#define R367TER_GPIO_CMD 0xf00f +#define F367TER_GPIO7_VAL 0xf00f0008 +#define F367TER_GPIO6_VAL 0xf00f0004 +#define F367TER_GPIO5_VAL 0xf00f0002 +#define F367TER_GPIO4_VAL 0xf00f0001 + +/* AGC2MAX */ +#define R367TER_AGC2MAX 0xf010 +#define F367TER_AGC2_MAX 0xf01000ff + +/* AGC2MIN */ +#define R367TER_AGC2MIN 0xf011 +#define F367TER_AGC2_MIN 0xf01100ff + +/* AGC1MAX */ +#define R367TER_AGC1MAX 0xf012 +#define F367TER_AGC1_MAX 0xf01200ff + +/* AGC1MIN */ +#define R367TER_AGC1MIN 0xf013 +#define F367TER_AGC1_MIN 0xf01300ff + +/* AGCR */ +#define R367TER_AGCR 0xf014 +#define F367TER_RATIO_A 0xf01400e0 +#define F367TER_RATIO_B 0xf0140018 +#define F367TER_RATIO_C 0xf0140007 + +/* AGC2TH */ +#define R367TER_AGC2TH 0xf015 +#define F367TER_AGC2_THRES 0xf01500ff + +/* AGC12c */ +#define R367TER_AGC12C 0xf016 +#define F367TER_AGC1_IV 0xf0160080 +#define F367TER_AGC1_OD 0xf0160040 +#define F367TER_AGC1_LOAD 0xf0160020 +#define F367TER_AGC2_IV 0xf0160010 +#define F367TER_AGC2_OD 0xf0160008 +#define F367TER_AGC2_LOAD 0xf0160004 +#define F367TER_AGC12_MODE 0xf0160003 + +/* AGCCTRL1 */ +#define R367TER_AGCCTRL1 0xf017 +#define F367TER_DAGC_ON 0xf0170080 +#define F367TER_INVERT_AGC12 0xf0170040 +#define F367TER_AGC1_MODE 0xf0170008 +#define F367TER_AGC2_MODE 0xf0170007 + +/* AGCCTRL2 */ +#define R367TER_AGCCTRL2 0xf018 +#define F367TER_FRZ2_CTRL 0xf0180060 +#define F367TER_FRZ1_CTRL 0xf0180018 +#define F367TER_TIME_CST 0xf0180007 + +/* AGC1VAL1 */ +#define R367TER_AGC1VAL1 0xf019 +#define F367TER_AGC1_VAL_LO 0xf01900ff + +/* AGC1VAL2 */ +#define R367TER_AGC1VAL2 0xf01a +#define F367TER_AGC1_VAL_HI 0xf01a000f + +/* AGC2VAL1 */ +#define R367TER_AGC2VAL1 0xf01b +#define F367TER_AGC2_VAL_LO 0xf01b00ff + +/* AGC2VAL2 */ +#define R367TER_AGC2VAL2 0xf01c +#define F367TER_AGC2_VAL_HI 0xf01c000f + +/* AGC2PGA */ +#define R367TER_AGC2PGA 0xf01d +#define F367TER_AGC2_PGA 0xf01d00ff + +/* OVF_RATE1 */ +#define R367TER_OVF_RATE1 0xf01e +#define F367TER_OVF_RATE_HI 0xf01e000f + +/* OVF_RATE2 */ +#define R367TER_OVF_RATE2 0xf01f +#define F367TER_OVF_RATE_LO 0xf01f00ff + +/* GAIN_SRC1 */ +#define R367TER_GAIN_SRC1 0xf020 +#define F367TER_INV_SPECTR 0xf0200080 +#define F367TER_IQ_INVERT 0xf0200040 +#define F367TER_INR_BYPASS 0xf0200020 +#define F367TER_STATUS_INV_SPECRUM 0xf0200010 +#define F367TER_GAIN_SRC_HI 0xf020000f + +/* GAIN_SRC2 */ +#define R367TER_GAIN_SRC2 0xf021 +#define F367TER_GAIN_SRC_LO 0xf02100ff + +/* INC_DEROT1 */ +#define R367TER_INC_DEROT1 0xf022 +#define F367TER_INC_DEROT_HI 0xf02200ff + +/* INC_DEROT2 */ +#define R367TER_INC_DEROT2 0xf023 +#define F367TER_INC_DEROT_LO 0xf02300ff + +/* PPM_CPAMP_DIR */ +#define R367TER_PPM_CPAMP_DIR 0xf024 +#define F367TER_PPM_CPAMP_DIRECT 0xf02400ff + +/* PPM_CPAMP_INV */ +#define R367TER_PPM_CPAMP_INV 0xf025 +#define F367TER_PPM_CPAMP_INVER 0xf02500ff + +/* FREESTFE_1 */ +#define R367TER_FREESTFE_1 0xf026 +#define F367TER_SYMBOL_NUMBER_INC 0xf02600c0 +#define F367TER_SEL_LSB 0xf0260004 +#define F367TER_AVERAGE_ON 0xf0260002 +#define F367TER_DC_ADJ 0xf0260001 + +/* FREESTFE_2 */ +#define R367TER_FREESTFE_2 0xf027 +#define F367TER_SEL_SRCOUT 0xf02700c0 +#define F367TER_SEL_SYRTHR 0xf027001f + +/* DCOFFSET */ +#define R367TER_DCOFFSET 0xf028 +#define F367TER_SELECT_I_Q 0xf0280080 +#define F367TER_DC_OFFSET 0xf028007f + +/* EN_PROCESS */ +#define R367TER_EN_PROCESS 0xf029 +#define F367TER_FREE 0xf02900f0 +#define F367TER_ENAB_MANUAL 0xf0290001 + +/* SDI_SMOOTHER */ +#define R367TER_SDI_SMOOTHER 0xf02a +#define F367TER_DIS_SMOOTH 0xf02a0080 +#define F367TER_SDI_INC_SMOOTHER 0xf02a007f + +/* FE_LOOP_OPEN */ +#define R367TER_FE_LOOP_OPEN 0xf02b +#define F367TER_TRL_LOOP_OP 0xf02b0002 +#define F367TER_CRL_LOOP_OP 0xf02b0001 + +/* FREQOFF1 */ +#define R367TER_FREQOFF1 0xf02c +#define F367TER_FREQ_OFFSET_LOOP_OPEN_VHI 0xf02c00ff + +/* FREQOFF2 */ +#define R367TER_FREQOFF2 0xf02d +#define F367TER_FREQ_OFFSET_LOOP_OPEN_HI 0xf02d00ff + +/* FREQOFF3 */ +#define R367TER_FREQOFF3 0xf02e +#define F367TER_FREQ_OFFSET_LOOP_OPEN_LO 0xf02e00ff + +/* TIMOFF1 */ +#define R367TER_TIMOFF1 0xf02f +#define F367TER_TIM_OFFSET_LOOP_OPEN_HI 0xf02f00ff + +/* TIMOFF2 */ +#define R367TER_TIMOFF2 0xf030 +#define F367TER_TIM_OFFSET_LOOP_OPEN_LO 0xf03000ff + +/* EPQ */ +#define R367TER_EPQ 0xf031 +#define F367TER_EPQ1 0xf03100ff + +/* EPQAUTO */ +#define R367TER_EPQAUTO 0xf032 +#define F367TER_EPQ2 0xf03200ff + +/* SYR_UPDATE */ +#define R367TER_SYR_UPDATE 0xf033 +#define F367TER_SYR_PROTV 0xf0330080 +#define F367TER_SYR_PROTV_GAIN 0xf0330060 +#define F367TER_SYR_FILTER 0xf0330010 +#define F367TER_SYR_TRACK_THRES 0xf033000c + +/* CHPFREE */ +#define R367TER_CHPFREE 0xf034 +#define F367TER_CHP_FREE 0xf03400ff + +/* PPM_STATE_MAC */ +#define R367TER_PPM_STATE_MAC 0xf035 +#define F367TER_PPM_STATE_MACHINE_DECODER 0xf035003f + +/* INR_THRESHOLD */ +#define R367TER_INR_THRESHOLD 0xf036 +#define F367TER_INR_THRESH 0xf03600ff + +/* EPQ_TPS_ID_CELL */ +#define R367TER_EPQ_TPS_ID_CELL 0xf037 +#define F367TER_ENABLE_LGTH_TO_CF 0xf0370080 +#define F367TER_DIS_TPS_RSVD 0xf0370040 +#define F367TER_DIS_BCH 0xf0370020 +#define F367TER_DIS_ID_CEL 0xf0370010 +#define F367TER_TPS_ADJUST_SYM 0xf037000f + +/* EPQ_CFG */ +#define R367TER_EPQ_CFG 0xf038 +#define F367TER_EPQ_RANGE 0xf0380002 +#define F367TER_EPQ_SOFT 0xf0380001 + +/* EPQ_STATUS */ +#define R367TER_EPQ_STATUS 0xf039 +#define F367TER_SLOPE_INC 0xf03900fc +#define F367TER_TPS_FIELD 0xf0390003 + +/* AUTORELOCK */ +#define R367TER_AUTORELOCK 0xf03a +#define F367TER_BYPASS_BER_TEMPO 0xf03a0080 +#define F367TER_BER_TEMPO 0xf03a0070 +#define F367TER_BYPASS_COFDM_TEMPO 0xf03a0008 +#define F367TER_COFDM_TEMPO 0xf03a0007 + +/* BER_THR_VMSB */ +#define R367TER_BER_THR_VMSB 0xf03b +#define F367TER_BER_THRESHOLD_HI 0xf03b00ff + +/* BER_THR_MSB */ +#define R367TER_BER_THR_MSB 0xf03c +#define F367TER_BER_THRESHOLD_MID 0xf03c00ff + +/* BER_THR_LSB */ +#define R367TER_BER_THR_LSB 0xf03d +#define F367TER_BER_THRESHOLD_LO 0xf03d00ff + +/* CCD */ +#define R367TER_CCD 0xf03e +#define F367TER_CCD_DETECTED 0xf03e0080 +#define F367TER_CCD_RESET 0xf03e0040 +#define F367TER_CCD_THRESHOLD 0xf03e000f + +/* SPECTR_CFG */ +#define R367TER_SPECTR_CFG 0xf03f +#define F367TER_SPECT_CFG 0xf03f0003 + +/* CONSTMU_MSB */ +#define R367TER_CONSTMU_MSB 0xf040 +#define F367TER_CONSTMU_FREEZE 0xf0400080 +#define F367TER_CONSTNU_FORCE_EN 0xf0400040 +#define F367TER_CONST_MU_MSB 0xf040003f + +/* CONSTMU_LSB */ +#define R367TER_CONSTMU_LSB 0xf041 +#define F367TER_CONST_MU_LSB 0xf04100ff + +/* CONSTMU_MAX_MSB */ +#define R367TER_CONSTMU_MAX_MSB 0xf042 +#define F367TER_CONST_MU_MAX_MSB 0xf042003f + +/* CONSTMU_MAX_LSB */ +#define R367TER_CONSTMU_MAX_LSB 0xf043 +#define F367TER_CONST_MU_MAX_LSB 0xf04300ff + +/* ALPHANOISE */ +#define R367TER_ALPHANOISE 0xf044 +#define F367TER_USE_ALLFILTER 0xf0440080 +#define F367TER_INTER_ON 0xf0440040 +#define F367TER_ALPHA_NOISE 0xf044001f + +/* MAXGP_MSB */ +#define R367TER_MAXGP_MSB 0xf045 +#define F367TER_MUFILTER_LENGTH 0xf04500f0 +#define F367TER_MAX_GP_MSB 0xf045000f + +/* MAXGP_LSB */ +#define R367TER_MAXGP_LSB 0xf046 +#define F367TER_MAX_GP_LSB 0xf04600ff + +/* ALPHAMSB */ +#define R367TER_ALPHAMSB 0xf047 +#define F367TER_CHC_DATARATE 0xf04700c0 +#define F367TER_ALPHA_MSB 0xf047003f + +/* ALPHALSB */ +#define R367TER_ALPHALSB 0xf048 +#define F367TER_ALPHA_LSB 0xf04800ff + +/* PILOT_ACCU */ +#define R367TER_PILOT_ACCU 0xf049 +#define F367TER_USE_SCAT4ADDAPT 0xf0490080 +#define F367TER_PILOT_ACC 0xf049001f + +/* PILOTMU_ACCU */ +#define R367TER_PILOTMU_ACCU 0xf04a +#define F367TER_DISCARD_BAD_SP 0xf04a0080 +#define F367TER_DISCARD_BAD_CP 0xf04a0040 +#define F367TER_PILOT_MU_ACCU 0xf04a001f + +/* FILT_CHANNEL_EST */ +#define R367TER_FILT_CHANNEL_EST 0xf04b +#define F367TER_USE_FILT_PILOT 0xf04b0080 +#define F367TER_FILT_CHANNEL 0xf04b007f + +/* ALPHA_NOPISE_FREQ */ +#define R367TER_ALPHA_NOPISE_FREQ 0xf04c +#define F367TER_NOISE_FREQ_FILT 0xf04c0040 +#define F367TER_ALPHA_NOISE_FREQ 0xf04c003f + +/* RATIO_PILOT */ +#define R367TER_RATIO_PILOT 0xf04d +#define F367TER_RATIO_MEAN_SP 0xf04d00f0 +#define F367TER_RATIO_MEAN_CP 0xf04d000f + +/* CHC_CTL */ +#define R367TER_CHC_CTL 0xf04e +#define F367TER_TRACK_EN 0xf04e0080 +#define F367TER_NOISE_NORM_EN 0xf04e0040 +#define F367TER_FORCE_CHC_RESET 0xf04e0020 +#define F367TER_SHORT_TIME 0xf04e0010 +#define F367TER_FORCE_STATE_EN 0xf04e0008 +#define F367TER_FORCE_STATE 0xf04e0007 + +/* EPQ_ADJUST */ +#define R367TER_EPQ_ADJUST 0xf04f +#define F367TER_ADJUST_SCAT_IND 0xf04f00c0 +#define F367TER_ONE_SYMBOL 0xf04f0010 +#define F367TER_EPQ_DECAY 0xf04f000e +#define F367TER_HOLD_SLOPE 0xf04f0001 + +/* EPQ_THRES */ +#define R367TER_EPQ_THRES 0xf050 +#define F367TER_EPQ_THR 0xf05000ff + +/* OMEGA_CTL */ +#define R367TER_OMEGA_CTL 0xf051 +#define F367TER_OMEGA_RST 0xf0510080 +#define F367TER_FREEZE_OMEGA 0xf0510040 +#define F367TER_OMEGA_SEL 0xf051003f + +/* GP_CTL */ +#define R367TER_GP_CTL 0xf052 +#define F367TER_CHC_STATE 0xf05200e0 +#define F367TER_FREEZE_GP 0xf0520010 +#define F367TER_GP_SEL 0xf052000f + +/* MUMSB */ +#define R367TER_MUMSB 0xf053 +#define F367TER_MU_MSB 0xf053007f + +/* MULSB */ +#define R367TER_MULSB 0xf054 +#define F367TER_MU_LSB 0xf05400ff + +/* GPMSB */ +#define R367TER_GPMSB 0xf055 +#define F367TER_CSI_THRESHOLD 0xf05500e0 +#define F367TER_GP_MSB 0xf055000f + +/* GPLSB */ +#define R367TER_GPLSB 0xf056 +#define F367TER_GP_LSB 0xf05600ff + +/* OMEGAMSB */ +#define R367TER_OMEGAMSB 0xf057 +#define F367TER_OMEGA_MSB 0xf057007f + +/* OMEGALSB */ +#define R367TER_OMEGALSB 0xf058 +#define F367TER_OMEGA_LSB 0xf05800ff + +/* SCAT_NB */ +#define R367TER_SCAT_NB 0xf059 +#define F367TER_CHC_TEST 0xf05900f8 +#define F367TER_SCAT_NUMB 0xf0590003 + +/* CHC_DUMMY */ +#define R367TER_CHC_DUMMY 0xf05a +#define F367TER_CHC_DUM 0xf05a00ff + +/* INC_CTL */ +#define R367TER_INC_CTL 0xf05b +#define F367TER_INC_BYPASS 0xf05b0080 +#define F367TER_INC_NDEPTH 0xf05b000c +#define F367TER_INC_MADEPTH 0xf05b0003 + +/* INCTHRES_COR1 */ +#define R367TER_INCTHRES_COR1 0xf05c +#define F367TER_INC_THRES_COR1 0xf05c00ff + +/* INCTHRES_COR2 */ +#define R367TER_INCTHRES_COR2 0xf05d +#define F367TER_INC_THRES_COR2 0xf05d00ff + +/* INCTHRES_DET1 */ +#define R367TER_INCTHRES_DET1 0xf05e +#define F367TER_INC_THRES_DET1 0xf05e003f + +/* INCTHRES_DET2 */ +#define R367TER_INCTHRES_DET2 0xf05f +#define F367TER_INC_THRES_DET2 0xf05f003f + +/* IIR_CELLNB */ +#define R367TER_IIR_CELLNB 0xf060 +#define F367TER_NRST_IIR 0xf0600080 +#define F367TER_IIR_CELL_NB 0xf0600007 + +/* IIRCX_COEFF1_MSB */ +#define R367TER_IIRCX_COEFF1_MSB 0xf061 +#define F367TER_IIR_CX_COEFF1_MSB 0xf06100ff + +/* IIRCX_COEFF1_LSB */ +#define R367TER_IIRCX_COEFF1_LSB 0xf062 +#define F367TER_IIR_CX_COEFF1_LSB 0xf06200ff + +/* IIRCX_COEFF2_MSB */ +#define R367TER_IIRCX_COEFF2_MSB 0xf063 +#define F367TER_IIR_CX_COEFF2_MSB 0xf06300ff + +/* IIRCX_COEFF2_LSB */ +#define R367TER_IIRCX_COEFF2_LSB 0xf064 +#define F367TER_IIR_CX_COEFF2_LSB 0xf06400ff + +/* IIRCX_COEFF3_MSB */ +#define R367TER_IIRCX_COEFF3_MSB 0xf065 +#define F367TER_IIR_CX_COEFF3_MSB 0xf06500ff + +/* IIRCX_COEFF3_LSB */ +#define R367TER_IIRCX_COEFF3_LSB 0xf066 +#define F367TER_IIR_CX_COEFF3_LSB 0xf06600ff + +/* IIRCX_COEFF4_MSB */ +#define R367TER_IIRCX_COEFF4_MSB 0xf067 +#define F367TER_IIR_CX_COEFF4_MSB 0xf06700ff + +/* IIRCX_COEFF4_LSB */ +#define R367TER_IIRCX_COEFF4_LSB 0xf068 +#define F367TER_IIR_CX_COEFF4_LSB 0xf06800ff + +/* IIRCX_COEFF5_MSB */ +#define R367TER_IIRCX_COEFF5_MSB 0xf069 +#define F367TER_IIR_CX_COEFF5_MSB 0xf06900ff + +/* IIRCX_COEFF5_LSB */ +#define R367TER_IIRCX_COEFF5_LSB 0xf06a +#define F367TER_IIR_CX_COEFF5_LSB 0xf06a00ff + +/* FEPATH_CFG */ +#define R367TER_FEPATH_CFG 0xf06b +#define F367TER_DEMUX_SWAP 0xf06b0004 +#define F367TER_DIGAGC_SWAP 0xf06b0002 +#define F367TER_LONGPATH_IF 0xf06b0001 + +/* PMC1_FUNC */ +#define R367TER_PMC1_FUNC 0xf06c +#define F367TER_SOFT_RSTN 0xf06c0080 +#define F367TER_PMC1_AVERAGE_TIME 0xf06c0078 +#define F367TER_PMC1_WAIT_TIME 0xf06c0006 +#define F367TER_PMC1_2N_SEL 0xf06c0001 + +/* PMC1_FOR */ +#define R367TER_PMC1_FOR 0xf06d +#define F367TER_PMC1_FORCE 0xf06d0080 +#define F367TER_PMC1_FORCE_VALUE 0xf06d007c + +/* PMC2_FUNC */ +#define R367TER_PMC2_FUNC 0xf06e +#define F367TER_PMC2_SOFT_STN 0xf06e0080 +#define F367TER_PMC2_ACCU_TIME 0xf06e0070 +#define F367TER_PMC2_CMDP_MN 0xf06e0008 +#define F367TER_PMC2_SWAP 0xf06e0004 + +/* STATUS_ERR_DA */ +#define R367TER_STATUS_ERR_DA 0xf06f +#define F367TER_COM_USEGAINTRK 0xf06f0080 +#define F367TER_COM_AGCLOCK 0xf06f0040 +#define F367TER_AUT_AGCLOCK 0xf06f0020 +#define F367TER_MIN_ERR_X_LSB 0xf06f000f + +/* DIG_AGC_R */ +#define R367TER_DIG_AGC_R 0xf070 +#define F367TER_COM_SOFT_RSTN 0xf0700080 +#define F367TER_COM_AGC_ON 0xf0700040 +#define F367TER_COM_EARLY 0xf0700020 +#define F367TER_AUT_SOFT_RESETN 0xf0700010 +#define F367TER_AUT_AGC_ON 0xf0700008 +#define F367TER_AUT_EARLY 0xf0700004 +#define F367TER_AUT_ROT_EN 0xf0700002 +#define F367TER_LOCK_SOFT_RESETN 0xf0700001 + +/* COMAGC_TARMSB */ +#define R367TER_COMAGC_TARMSB 0xf071 +#define F367TER_COM_AGC_TARGET_MSB 0xf07100ff + +/* COM_AGC_TAR_ENMODE */ +#define R367TER_COM_AGC_TAR_ENMODE 0xf072 +#define F367TER_COM_AGC_TARGET_LSB 0xf07200f0 +#define F367TER_COM_ENMODE 0xf072000f + +/* COM_AGC_CFG */ +#define R367TER_COM_AGC_CFG 0xf073 +#define F367TER_COM_N 0xf07300f8 +#define F367TER_COM_STABMODE 0xf0730006 +#define F367TER_ERR_SEL 0xf0730001 + +/* COM_AGC_GAIN1 */ +#define R367TER_COM_AGC_GAIN1 0xf074 +#define F367TER_COM_GAIN1aCK 0xf07400f0 +#define F367TER_COM_GAIN1TRK 0xf074000f + +/* AUT_AGC_TARGETMSB */ +#define R367TER_AUT_AGC_TARGETMSB 0xf075 +#define F367TER_AUT_AGC_TARGET_MSB 0xf07500ff + +/* LOCK_DET_MSB */ +#define R367TER_LOCK_DET_MSB 0xf076 +#define F367TER_LOCK_DETECT_MSB 0xf07600ff + +/* AGCTAR_LOCK_LSBS */ +#define R367TER_AGCTAR_LOCK_LSBS 0xf077 +#define F367TER_AUT_AGC_TARGET_LSB 0xf07700f0 +#define F367TER_LOCK_DETECT_LSB 0xf077000f + +/* AUT_GAIN_EN */ +#define R367TER_AUT_GAIN_EN 0xf078 +#define F367TER_AUT_ENMODE 0xf07800f0 +#define F367TER_AUT_GAIN2 0xf078000f + +/* AUT_CFG */ +#define R367TER_AUT_CFG 0xf079 +#define F367TER_AUT_N 0xf07900f8 +#define F367TER_INT_CHOICE 0xf0790006 +#define F367TER_INT_LOAD 0xf0790001 + +/* LOCKN */ +#define R367TER_LOCKN 0xf07a +#define F367TER_LOCK_N 0xf07a00f8 +#define F367TER_SEL_IQNTAR 0xf07a0004 +#define F367TER_LOCK_DETECT_CHOICE 0xf07a0003 + +/* INT_X_3 */ +#define R367TER_INT_X_3 0xf07b +#define F367TER_INT_X3 0xf07b00ff + +/* INT_X_2 */ +#define R367TER_INT_X_2 0xf07c +#define F367TER_INT_X2 0xf07c00ff + +/* INT_X_1 */ +#define R367TER_INT_X_1 0xf07d +#define F367TER_INT_X1 0xf07d00ff + +/* INT_X_0 */ +#define R367TER_INT_X_0 0xf07e +#define F367TER_INT_X0 0xf07e00ff + +/* MIN_ERRX_MSB */ +#define R367TER_MIN_ERRX_MSB 0xf07f +#define F367TER_MIN_ERR_X_MSB 0xf07f00ff + +/* COR_CTL */ +#define R367TER_COR_CTL 0xf080 +#define F367TER_CORE_ACTIVE 0xf0800020 +#define F367TER_HOLD 0xf0800010 +#define F367TER_CORE_STATE_CTL 0xf080000f + +/* COR_STAT */ +#define R367TER_COR_STAT 0xf081 +#define F367TER_SCATT_LOCKED 0xf0810080 +#define F367TER_TPS_LOCKED 0xf0810040 +#define F367TER_SYR_LOCKED_COR 0xf0810020 +#define F367TER_AGC_LOCKED_STAT 0xf0810010 +#define F367TER_CORE_STATE_STAT 0xf081000f + +/* COR_INTEN */ +#define R367TER_COR_INTEN 0xf082 +#define F367TER_INTEN 0xf0820080 +#define F367TER_INTEN_SYR 0xf0820020 +#define F367TER_INTEN_FFT 0xf0820010 +#define F367TER_INTEN_AGC 0xf0820008 +#define F367TER_INTEN_TPS1 0xf0820004 +#define F367TER_INTEN_TPS2 0xf0820002 +#define F367TER_INTEN_TPS3 0xf0820001 + +/* COR_INTSTAT */ +#define R367TER_COR_INTSTAT 0xf083 +#define F367TER_INTSTAT_SYR 0xf0830020 +#define F367TER_INTSTAT_FFT 0xf0830010 +#define F367TER_INTSAT_AGC 0xf0830008 +#define F367TER_INTSTAT_TPS1 0xf0830004 +#define F367TER_INTSTAT_TPS2 0xf0830002 +#define F367TER_INTSTAT_TPS3 0xf0830001 + +/* COR_MODEGUARD */ +#define R367TER_COR_MODEGUARD 0xf084 +#define F367TER_FORCE 0xf0840010 +#define F367TER_MODE 0xf084000c +#define F367TER_GUARD 0xf0840003 + +/* AGC_CTL */ +#define R367TER_AGC_CTL 0xf085 +#define F367TER_AGC_TIMING_FACTOR 0xf08500e0 +#define F367TER_AGC_LAST 0xf0850010 +#define F367TER_AGC_GAIN 0xf085000c +#define F367TER_AGC_NEG 0xf0850002 +#define F367TER_AGC_SET 0xf0850001 + +/* AGC_MANUAL1 */ +#define R367TER_AGC_MANUAL1 0xf086 +#define F367TER_AGC_VAL_LO 0xf08600ff + +/* AGC_MANUAL2 */ +#define R367TER_AGC_MANUAL2 0xf087 +#define F367TER_AGC_VAL_HI 0xf087000f + +/* AGC_TARG */ +#define R367TER_AGC_TARG 0xf088 +#define F367TER_AGC_TARGET 0xf08800ff + +/* AGC_GAIN1 */ +#define R367TER_AGC_GAIN1 0xf089 +#define F367TER_AGC_GAIN_LO 0xf08900ff + +/* AGC_GAIN2 */ +#define R367TER_AGC_GAIN2 0xf08a +#define F367TER_AGC_LOCKED_GAIN2 0xf08a0010 +#define F367TER_AGC_GAIN_HI 0xf08a000f + +/* RESERVED_1 */ +#define R367TER_RESERVED_1 0xf08b +#define F367TER_RESERVED1 0xf08b00ff + +/* RESERVED_2 */ +#define R367TER_RESERVED_2 0xf08c +#define F367TER_RESERVED2 0xf08c00ff + +/* RESERVED_3 */ +#define R367TER_RESERVED_3 0xf08d +#define F367TER_RESERVED3 0xf08d00ff + +/* CAS_CTL */ +#define R367TER_CAS_CTL 0xf08e +#define F367TER_CCS_ENABLE 0xf08e0080 +#define F367TER_ACS_DISABLE 0xf08e0040 +#define F367TER_DAGC_DIS 0xf08e0020 +#define F367TER_DAGC_GAIN 0xf08e0018 +#define F367TER_CCSMU 0xf08e0007 + +/* CAS_FREQ */ +#define R367TER_CAS_FREQ 0xf08f +#define F367TER_CCS_FREQ 0xf08f00ff + +/* CAS_DAGCGAIN */ +#define R367TER_CAS_DAGCGAIN 0xf090 +#define F367TER_CAS_DAGC_GAIN 0xf09000ff + +/* SYR_CTL */ +#define R367TER_SYR_CTL 0xf091 +#define F367TER_SICTH_ENABLE 0xf0910080 +#define F367TER_LONG_ECHO 0xf0910078 +#define F367TER_AUTO_LE_EN 0xf0910004 +#define F367TER_SYR_BYPASS 0xf0910002 +#define F367TER_SYR_TR_DIS 0xf0910001 + +/* SYR_STAT */ +#define R367TER_SYR_STAT 0xf092 +#define F367TER_SYR_LOCKED_STAT 0xf0920010 +#define F367TER_SYR_MODE 0xf092000c +#define F367TER_SYR_GUARD 0xf0920003 + +/* SYR_NCO1 */ +#define R367TER_SYR_NCO1 0xf093 +#define F367TER_SYR_NCO_LO 0xf09300ff + +/* SYR_NCO2 */ +#define R367TER_SYR_NCO2 0xf094 +#define F367TER_SYR_NCO_HI 0xf094003f + +/* SYR_OFFSET1 */ +#define R367TER_SYR_OFFSET1 0xf095 +#define F367TER_SYR_OFFSET_LO 0xf09500ff + +/* SYR_OFFSET2 */ +#define R367TER_SYR_OFFSET2 0xf096 +#define F367TER_SYR_OFFSET_HI 0xf096003f + +/* FFT_CTL */ +#define R367TER_FFT_CTL 0xf097 +#define F367TER_SHIFT_FFT_TRIG 0xf0970018 +#define F367TER_FFT_TRIGGER 0xf0970004 +#define F367TER_FFT_MANUAL 0xf0970002 +#define F367TER_IFFT_MODE 0xf0970001 + +/* SCR_CTL */ +#define R367TER_SCR_CTL 0xf098 +#define F367TER_SYRADJDECAY 0xf0980070 +#define F367TER_SCR_CPEDIS 0xf0980002 +#define F367TER_SCR_DIS 0xf0980001 + +/* PPM_CTL1 */ +#define R367TER_PPM_CTL1 0xf099 +#define F367TER_PPM_MAXFREQ 0xf0990030 +#define F367TER_PPM_MAXTIM 0xf0990008 +#define F367TER_PPM_INVSEL 0xf0990004 +#define F367TER_PPM_SCATDIS 0xf0990002 +#define F367TER_PPM_BYP 0xf0990001 + +/* TRL_CTL */ +#define R367TER_TRL_CTL 0xf09a +#define F367TER_TRL_NOMRATE_LSB 0xf09a0080 +#define F367TER_TRL_GAIN_FACTOR 0xf09a0078 +#define F367TER_TRL_LOOPGAIN 0xf09a0007 + +/* TRL_NOMRATE1 */ +#define R367TER_TRL_NOMRATE1 0xf09b +#define F367TER_TRL_NOMRATE_LO 0xf09b00ff + +/* TRL_NOMRATE2 */ +#define R367TER_TRL_NOMRATE2 0xf09c +#define F367TER_TRL_NOMRATE_HI 0xf09c00ff + +/* TRL_TIME1 */ +#define R367TER_TRL_TIME1 0xf09d +#define F367TER_TRL_TOFFSET_LO 0xf09d00ff + +/* TRL_TIME2 */ +#define R367TER_TRL_TIME2 0xf09e +#define F367TER_TRL_TOFFSET_HI 0xf09e00ff + +/* CRL_CTL */ +#define R367TER_CRL_CTL 0xf09f +#define F367TER_CRL_DIS 0xf09f0080 +#define F367TER_CRL_GAIN_FACTOR 0xf09f0078 +#define F367TER_CRL_LOOPGAIN 0xf09f0007 + +/* CRL_FREQ1 */ +#define R367TER_CRL_FREQ1 0xf0a0 +#define F367TER_CRL_FOFFSET_LO 0xf0a000ff + +/* CRL_FREQ2 */ +#define R367TER_CRL_FREQ2 0xf0a1 +#define F367TER_CRL_FOFFSET_HI 0xf0a100ff + +/* CRL_FREQ3 */ +#define R367TER_CRL_FREQ3 0xf0a2 +#define F367TER_CRL_FOFFSET_VHI 0xf0a200ff + +/* TPS_SFRAME_CTL */ +#define R367TER_TPS_SFRAME_CTL 0xf0a3 +#define F367TER_TPS_SFRAME_SYNC 0xf0a30001 + +/* CHC_SNR */ +#define R367TER_CHC_SNR 0xf0a4 +#define F367TER_CHCSNR 0xf0a400ff + +/* BDI_CTL */ +#define R367TER_BDI_CTL 0xf0a5 +#define F367TER_BDI_LPSEL 0xf0a50002 +#define F367TER_BDI_SERIAL 0xf0a50001 + +/* DMP_CTL */ +#define R367TER_DMP_CTL 0xf0a6 +#define F367TER_DMP_SCALING_FACTOR 0xf0a6001e +#define F367TER_DMP_SDDIS 0xf0a60001 + +/* TPS_RCVD1 */ +#define R367TER_TPS_RCVD1 0xf0a7 +#define F367TER_TPS_CHANGE 0xf0a70040 +#define F367TER_BCH_OK 0xf0a70020 +#define F367TER_TPS_SYNC 0xf0a70010 +#define F367TER_TPS_FRAME 0xf0a70003 + +/* TPS_RCVD2 */ +#define R367TER_TPS_RCVD2 0xf0a8 +#define F367TER_TPS_HIERMODE 0xf0a80070 +#define F367TER_TPS_CONST 0xf0a80003 + +/* TPS_RCVD3 */ +#define R367TER_TPS_RCVD3 0xf0a9 +#define F367TER_TPS_LPCODE 0xf0a90070 +#define F367TER_TPS_HPCODE 0xf0a90007 + +/* TPS_RCVD4 */ +#define R367TER_TPS_RCVD4 0xf0aa +#define F367TER_TPS_GUARD 0xf0aa0030 +#define F367TER_TPS_MODE 0xf0aa0003 + +/* TPS_ID_CELL1 */ +#define R367TER_TPS_ID_CELL1 0xf0ab +#define F367TER_TPS_ID_CELL_LO 0xf0ab00ff + +/* TPS_ID_CELL2 */ +#define R367TER_TPS_ID_CELL2 0xf0ac +#define F367TER_TPS_ID_CELL_HI 0xf0ac00ff + +/* TPS_RCVD5_SET1 */ +#define R367TER_TPS_RCVD5_SET1 0xf0ad +#define F367TER_TPS_NA 0xf0ad00fC +#define F367TER_TPS_SETFRAME 0xf0ad0003 + +/* TPS_SET2 */ +#define R367TER_TPS_SET2 0xf0ae +#define F367TER_TPS_SETHIERMODE 0xf0ae0070 +#define F367TER_TPS_SETCONST 0xf0ae0003 + +/* TPS_SET3 */ +#define R367TER_TPS_SET3 0xf0af +#define F367TER_TPS_SETLPCODE 0xf0af0070 +#define F367TER_TPS_SETHPCODE 0xf0af0007 + +/* TPS_CTL */ +#define R367TER_TPS_CTL 0xf0b0 +#define F367TER_TPS_IMM 0xf0b00004 +#define F367TER_TPS_BCHDIS 0xf0b00002 +#define F367TER_TPS_UPDDIS 0xf0b00001 + +/* CTL_FFTOSNUM */ +#define R367TER_CTL_FFTOSNUM 0xf0b1 +#define F367TER_SYMBOL_NUMBER 0xf0b1007f + +/* TESTSELECT */ +#define R367TER_TESTSELECT 0xf0b2 +#define F367TER_TEST_SELECT 0xf0b2001f + +/* MSC_REV */ +#define R367TER_MSC_REV 0xf0b3 +#define F367TER_REV_NUMBER 0xf0b300ff + +/* PIR_CTL */ +#define R367TER_PIR_CTL 0xf0b4 +#define F367TER_FREEZE 0xf0b40001 + +/* SNR_CARRIER1 */ +#define R367TER_SNR_CARRIER1 0xf0b5 +#define F367TER_SNR_CARRIER_LO 0xf0b500ff + +/* SNR_CARRIER2 */ +#define R367TER_SNR_CARRIER2 0xf0b6 +#define F367TER_MEAN 0xf0b600c0 +#define F367TER_SNR_CARRIER_HI 0xf0b6001f + +/* PPM_CPAMP */ +#define R367TER_PPM_CPAMP 0xf0b7 +#define F367TER_PPM_CPC 0xf0b700ff + +/* TSM_AP0 */ +#define R367TER_TSM_AP0 0xf0b8 +#define F367TER_ADDRESS_BYTE_0 0xf0b800ff + +/* TSM_AP1 */ +#define R367TER_TSM_AP1 0xf0b9 +#define F367TER_ADDRESS_BYTE_1 0xf0b900ff + +/* TSM_AP2 */ +#define R367TER_TSM_AP2 0xf0bA +#define F367TER_DATA_BYTE_0 0xf0ba00ff + +/* TSM_AP3 */ +#define R367TER_TSM_AP3 0xf0bB +#define F367TER_DATA_BYTE_1 0xf0bb00ff + +/* TSM_AP4 */ +#define R367TER_TSM_AP4 0xf0bC +#define F367TER_DATA_BYTE_2 0xf0bc00ff + +/* TSM_AP5 */ +#define R367TER_TSM_AP5 0xf0bD +#define F367TER_DATA_BYTE_3 0xf0bd00ff + +/* TSM_AP6 */ +#define R367TER_TSM_AP6 0xf0bE +#define F367TER_TSM_AP_6 0xf0be00ff + +/* TSM_AP7 */ +#define R367TER_TSM_AP7 0xf0bF +#define F367TER_MEM_SELECT_BYTE 0xf0bf00ff + +/* TSTRES */ +#define R367TER_TSTRES 0xf0c0 +#define F367TER_FRES_DISPLAY 0xf0c00080 +#define F367TER_FRES_FIFO_AD 0xf0c00020 +#define F367TER_FRESRS 0xf0c00010 +#define F367TER_FRESACS 0xf0c00008 +#define F367TER_FRESFEC 0xf0c00004 +#define F367TER_FRES_PRIF 0xf0c00002 +#define F367TER_FRESCORE 0xf0c00001 + +/* ANACTRL */ +#define R367TER_ANACTRL 0xf0c1 +#define F367TER_BYPASS_XTAL 0xf0c10040 +#define F367TER_BYPASS_PLLXN 0xf0c1000c +#define F367TER_DIS_PAD_OSC 0xf0c10002 +#define F367TER_STDBY_PLLXN 0xf0c10001 + +/* TSTBUS */ +#define R367TER_TSTBUS 0xf0c2 +#define F367TER_TS_BYTE_CLK_INV 0xf0c20080 +#define F367TER_CFG_IP 0xf0c20070 +#define F367TER_CFG_TST 0xf0c2000f + +/* TSTRATE */ +#define R367TER_TSTRATE 0xf0c6 +#define F367TER_FORCEPHA 0xf0c60080 +#define F367TER_FNEWPHA 0xf0c60010 +#define F367TER_FROT90 0xf0c60008 +#define F367TER_FR 0xf0c60007 + +/* CONSTMODE */ +#define R367TER_CONSTMODE 0xf0cb +#define F367TER_TST_PRIF 0xf0cb00e0 +#define F367TER_CAR_TYPE 0xf0cb0018 +#define F367TER_CONST_MODE 0xf0cb0003 + +/* CONSTCARR1 */ +#define R367TER_CONSTCARR1 0xf0cc +#define F367TER_CONST_CARR_LO 0xf0cc00ff + +/* CONSTCARR2 */ +#define R367TER_CONSTCARR2 0xf0cd +#define F367TER_CONST_CARR_HI 0xf0cd001f + +/* ICONSTEL */ +#define R367TER_ICONSTEL 0xf0ce +#define F367TER_PICONSTEL 0xf0ce00ff + +/* QCONSTEL */ +#define R367TER_QCONSTEL 0xf0cf +#define F367TER_PQCONSTEL 0xf0cf00ff + +/* TSTBISTRES0 */ +#define R367TER_TSTBISTRES0 0xf0d0 +#define F367TER_BEND_PPM 0xf0d00080 +#define F367TER_BBAD_PPM 0xf0d00040 +#define F367TER_BEND_FFTW 0xf0d00020 +#define F367TER_BBAD_FFTW 0xf0d00010 +#define F367TER_BEND_FFT_BUF 0xf0d00008 +#define F367TER_BBAD_FFT_BUF 0xf0d00004 +#define F367TER_BEND_SYR 0xf0d00002 +#define F367TER_BBAD_SYR 0xf0d00001 + +/* TSTBISTRES1 */ +#define R367TER_TSTBISTRES1 0xf0d1 +#define F367TER_BEND_CHC_CP 0xf0d10080 +#define F367TER_BBAD_CHC_CP 0xf0d10040 +#define F367TER_BEND_CHCI 0xf0d10020 +#define F367TER_BBAD_CHCI 0xf0d10010 +#define F367TER_BEND_BDI 0xf0d10008 +#define F367TER_BBAD_BDI 0xf0d10004 +#define F367TER_BEND_SDI 0xf0d10002 +#define F367TER_BBAD_SDI 0xf0d10001 + +/* TSTBISTRES2 */ +#define R367TER_TSTBISTRES2 0xf0d2 +#define F367TER_BEND_CHC_INC 0xf0d20080 +#define F367TER_BBAD_CHC_INC 0xf0d20040 +#define F367TER_BEND_CHC_SPP 0xf0d20020 +#define F367TER_BBAD_CHC_SPP 0xf0d20010 +#define F367TER_BEND_CHC_CPP 0xf0d20008 +#define F367TER_BBAD_CHC_CPP 0xf0d20004 +#define F367TER_BEND_CHC_SP 0xf0d20002 +#define F367TER_BBAD_CHC_SP 0xf0d20001 + +/* TSTBISTRES3 */ +#define R367TER_TSTBISTRES3 0xf0d3 +#define F367TER_BEND_QAM 0xf0d30080 +#define F367TER_BBAD_QAM 0xf0d30040 +#define F367TER_BEND_SFEC_VIT 0xf0d30020 +#define F367TER_BBAD_SFEC_VIT 0xf0d30010 +#define F367TER_BEND_SFEC_DLINE 0xf0d30008 +#define F367TER_BBAD_SFEC_DLINE 0xf0d30004 +#define F367TER_BEND_SFEC_HW 0xf0d30002 +#define F367TER_BBAD_SFEC_HW 0xf0d30001 + +/* RF_AGC1 */ +#define R367TER_RF_AGC1 0xf0d4 +#define F367TER_RF_AGC1_LEVEL_HI 0xf0d400ff + +/* RF_AGC2 */ +#define R367TER_RF_AGC2 0xf0d5 +#define F367TER_REF_ADGP 0xf0d50080 +#define F367TER_STDBY_ADCGP 0xf0d50020 +#define F367TER_CHANNEL_SEL 0xf0d5001c +#define F367TER_RF_AGC1_LEVEL_LO 0xf0d50003 + +/* ANADIGCTRL */ +#define R367TER_ANADIGCTRL 0xf0d7 +#define F367TER_SEL_CLKDEM 0xf0d70020 +#define F367TER_EN_BUFFER_Q 0xf0d70010 +#define F367TER_EN_BUFFER_I 0xf0d70008 +#define F367TER_ADC_RIS_EGDE 0xf0d70004 +#define F367TER_SGN_ADC 0xf0d70002 +#define F367TER_SEL_AD12_SYNC 0xf0d70001 + +/* PLLMDIV */ +#define R367TER_PLLMDIV 0xf0d8 +#define F367TER_PLL_MDIV 0xf0d800ff + +/* PLLNDIV */ +#define R367TER_PLLNDIV 0xf0d9 +#define F367TER_PLL_NDIV 0xf0d900ff + +/* PLLSETUP */ +#define R367TER_PLLSETUP 0xf0dA +#define F367TER_PLL_PDIV 0xf0da0070 +#define F367TER_PLL_KDIV 0xf0da000f + +/* DUAL_AD12 */ +#define R367TER_DUAL_AD12 0xf0dB +#define F367TER_FS20M 0xf0db0020 +#define F367TER_FS50M 0xf0db0010 +#define F367TER_INMODe0 0xf0db0008 +#define F367TER_POFFQ 0xf0db0004 +#define F367TER_POFFI 0xf0db0002 +#define F367TER_INMODE1 0xf0db0001 + +/* TSTBIST */ +#define R367TER_TSTBIST 0xf0dC +#define F367TER_TST_BYP_CLK 0xf0dc0080 +#define F367TER_TST_GCLKENA_STD 0xf0dc0040 +#define F367TER_TST_GCLKENA 0xf0dc0020 +#define F367TER_TST_MEMBIST 0xf0dc001f + +/* PAD_COMP_CTRL */ +#define R367TER_PAD_COMP_CTRL 0xf0dD +#define F367TER_COMPTQ 0xf0dd0010 +#define F367TER_COMPEN 0xf0dd0008 +#define F367TER_FREEZE2 0xf0dd0004 +#define F367TER_SLEEP_INHBT 0xf0dd0002 +#define F367TER_CHIP_SLEEP 0xf0dd0001 + +/* PAD_COMP_WR */ +#define R367TER_PAD_COMP_WR 0xf0de +#define F367TER_WR_ASRC 0xf0de007f + +/* PAD_COMP_RD */ +#define R367TER_PAD_COMP_RD 0xf0df +#define F367TER_COMPOK 0xf0df0080 +#define F367TER_RD_ASRC 0xf0df007f + +/* SYR_TARGET_FFTADJT_MSB */ +#define R367TER_SYR_TARGET_FFTADJT_MSB 0xf100 +#define F367TER_SYR_START 0xf1000080 +#define F367TER_SYR_TARGET_FFTADJ_HI 0xf100000f + +/* SYR_TARGET_FFTADJT_LSB */ +#define R367TER_SYR_TARGET_FFTADJT_LSB 0xf101 +#define F367TER_SYR_TARGET_FFTADJ_LO 0xf10100ff + +/* SYR_TARGET_CHCADJT_MSB */ +#define R367TER_SYR_TARGET_CHCADJT_MSB 0xf102 +#define F367TER_SYR_TARGET_CHCADJ_HI 0xf102000f + +/* SYR_TARGET_CHCADJT_LSB */ +#define R367TER_SYR_TARGET_CHCADJT_LSB 0xf103 +#define F367TER_SYR_TARGET_CHCADJ_LO 0xf10300ff + +/* SYR_FLAG */ +#define R367TER_SYR_FLAG 0xf104 +#define F367TER_TRIG_FLG1 0xf1040080 +#define F367TER_TRIG_FLG0 0xf1040040 +#define F367TER_FFT_FLG1 0xf1040008 +#define F367TER_FFT_FLG0 0xf1040004 +#define F367TER_CHC_FLG1 0xf1040002 +#define F367TER_CHC_FLG0 0xf1040001 + +/* CRL_TARGET1 */ +#define R367TER_CRL_TARGET1 0xf105 +#define F367TER_CRL_START 0xf1050080 +#define F367TER_CRL_TARGET_VHI 0xf105000f + +/* CRL_TARGET2 */ +#define R367TER_CRL_TARGET2 0xf106 +#define F367TER_CRL_TARGET_HI 0xf10600ff + +/* CRL_TARGET3 */ +#define R367TER_CRL_TARGET3 0xf107 +#define F367TER_CRL_TARGET_LO 0xf10700ff + +/* CRL_TARGET4 */ +#define R367TER_CRL_TARGET4 0xf108 +#define F367TER_CRL_TARGET_VLO 0xf10800ff + +/* CRL_FLAG */ +#define R367TER_CRL_FLAG 0xf109 +#define F367TER_CRL_FLAG1 0xf1090002 +#define F367TER_CRL_FLAG0 0xf1090001 + +/* TRL_TARGET1 */ +#define R367TER_TRL_TARGET1 0xf10a +#define F367TER_TRL_TARGET_HI 0xf10a00ff + +/* TRL_TARGET2 */ +#define R367TER_TRL_TARGET2 0xf10b +#define F367TER_TRL_TARGET_LO 0xf10b00ff + +/* TRL_CHC */ +#define R367TER_TRL_CHC 0xf10c +#define F367TER_TRL_START 0xf10c0080 +#define F367TER_CHC_START 0xf10c0040 +#define F367TER_TRL_FLAG1 0xf10c0002 +#define F367TER_TRL_FLAG0 0xf10c0001 + +/* CHC_SNR_TARG */ +#define R367TER_CHC_SNR_TARG 0xf10d +#define F367TER_CHC_SNR_TARGET 0xf10d00ff + +/* TOP_TRACK */ +#define R367TER_TOP_TRACK 0xf10e +#define F367TER_TOP_START 0xf10e0080 +#define F367TER_FIRST_FLAG 0xf10e0070 +#define F367TER_TOP_FLAG1 0xf10e0008 +#define F367TER_TOP_FLAG0 0xf10e0004 +#define F367TER_CHC_FLAG1 0xf10e0002 +#define F367TER_CHC_FLAG0 0xf10e0001 + +/* TRACKER_FREE1 */ +#define R367TER_TRACKER_FREE1 0xf10f +#define F367TER_TRACKER_FREE_1 0xf10f00ff + +/* ERROR_CRL1 */ +#define R367TER_ERROR_CRL1 0xf110 +#define F367TER_ERROR_CRL_VHI 0xf11000ff + +/* ERROR_CRL2 */ +#define R367TER_ERROR_CRL2 0xf111 +#define F367TER_ERROR_CRL_HI 0xf11100ff + +/* ERROR_CRL3 */ +#define R367TER_ERROR_CRL3 0xf112 +#define F367TER_ERROR_CRL_LOI 0xf11200ff + +/* ERROR_CRL4 */ +#define R367TER_ERROR_CRL4 0xf113 +#define F367TER_ERROR_CRL_VLO 0xf11300ff + +/* DEC_NCO1 */ +#define R367TER_DEC_NCO1 0xf114 +#define F367TER_DEC_NCO_VHI 0xf11400ff + +/* DEC_NCO2 */ +#define R367TER_DEC_NCO2 0xf115 +#define F367TER_DEC_NCO_HI 0xf11500ff + +/* DEC_NCO3 */ +#define R367TER_DEC_NCO3 0xf116 +#define F367TER_DEC_NCO_LO 0xf11600ff + +/* SNR */ +#define R367TER_SNR 0xf117 +#define F367TER_SNRATIO 0xf11700ff + +/* SYR_FFTADJ1 */ +#define R367TER_SYR_FFTADJ1 0xf118 +#define F367TER_SYR_FFTADJ_HI 0xf11800ff + +/* SYR_FFTADJ2 */ +#define R367TER_SYR_FFTADJ2 0xf119 +#define F367TER_SYR_FFTADJ_LO 0xf11900ff + +/* SYR_CHCADJ1 */ +#define R367TER_SYR_CHCADJ1 0xf11a +#define F367TER_SYR_CHCADJ_HI 0xf11a00ff + +/* SYR_CHCADJ2 */ +#define R367TER_SYR_CHCADJ2 0xf11b +#define F367TER_SYR_CHCADJ_LO 0xf11b00ff + +/* SYR_OFF */ +#define R367TER_SYR_OFF 0xf11c +#define F367TER_SYR_OFFSET 0xf11c00ff + +/* PPM_OFFSET1 */ +#define R367TER_PPM_OFFSET1 0xf11d +#define F367TER_PPM_OFFSET_HI 0xf11d00ff + +/* PPM_OFFSET2 */ +#define R367TER_PPM_OFFSET2 0xf11e +#define F367TER_PPM_OFFSET_LO 0xf11e00ff + +/* TRACKER_FREE2 */ +#define R367TER_TRACKER_FREE2 0xf11f +#define F367TER_TRACKER_FREE_2 0xf11f00ff + +/* DEBG_LT10 */ +#define R367TER_DEBG_LT10 0xf120 +#define F367TER_DEBUG_LT10 0xf12000ff + +/* DEBG_LT11 */ +#define R367TER_DEBG_LT11 0xf121 +#define F367TER_DEBUG_LT11 0xf12100ff + +/* DEBG_LT12 */ +#define R367TER_DEBG_LT12 0xf122 +#define F367TER_DEBUG_LT12 0xf12200ff + +/* DEBG_LT13 */ +#define R367TER_DEBG_LT13 0xf123 +#define F367TER_DEBUG_LT13 0xf12300ff + +/* DEBG_LT14 */ +#define R367TER_DEBG_LT14 0xf124 +#define F367TER_DEBUG_LT14 0xf12400ff + +/* DEBG_LT15 */ +#define R367TER_DEBG_LT15 0xf125 +#define F367TER_DEBUG_LT15 0xf12500ff + +/* DEBG_LT16 */ +#define R367TER_DEBG_LT16 0xf126 +#define F367TER_DEBUG_LT16 0xf12600ff + +/* DEBG_LT17 */ +#define R367TER_DEBG_LT17 0xf127 +#define F367TER_DEBUG_LT17 0xf12700ff + +/* DEBG_LT18 */ +#define R367TER_DEBG_LT18 0xf128 +#define F367TER_DEBUG_LT18 0xf12800ff + +/* DEBG_LT19 */ +#define R367TER_DEBG_LT19 0xf129 +#define F367TER_DEBUG_LT19 0xf12900ff + +/* DEBG_LT1a */ +#define R367TER_DEBG_LT1A 0xf12a +#define F367TER_DEBUG_LT1A 0xf12a00ff + +/* DEBG_LT1b */ +#define R367TER_DEBG_LT1B 0xf12b +#define F367TER_DEBUG_LT1B 0xf12b00ff + +/* DEBG_LT1c */ +#define R367TER_DEBG_LT1C 0xf12c +#define F367TER_DEBUG_LT1C 0xf12c00ff + +/* DEBG_LT1D */ +#define R367TER_DEBG_LT1D 0xf12d +#define F367TER_DEBUG_LT1D 0xf12d00ff + +/* DEBG_LT1E */ +#define R367TER_DEBG_LT1E 0xf12e +#define F367TER_DEBUG_LT1E 0xf12e00ff + +/* DEBG_LT1F */ +#define R367TER_DEBG_LT1F 0xf12f +#define F367TER_DEBUG_LT1F 0xf12f00ff + +/* RCCFGH */ +#define R367TER_RCCFGH 0xf200 +#define F367TER_TSRCFIFO_DVBCI 0xf2000080 +#define F367TER_TSRCFIFO_SERIAL 0xf2000040 +#define F367TER_TSRCFIFO_DISABLE 0xf2000020 +#define F367TER_TSFIFO_2TORC 0xf2000010 +#define F367TER_TSRCFIFO_HSGNLOUT 0xf2000008 +#define F367TER_TSRCFIFO_ERRMODE 0xf2000006 +#define F367TER_RCCFGH_0 0xf2000001 + +/* RCCFGM */ +#define R367TER_RCCFGM 0xf201 +#define F367TER_TSRCFIFO_MANSPEED 0xf20100c0 +#define F367TER_TSRCFIFO_PERMDATA 0xf2010020 +#define F367TER_TSRCFIFO_NONEWSGNL 0xf2010010 +#define F367TER_RCBYTE_OVERSAMPLING 0xf201000e +#define F367TER_TSRCFIFO_INVDATA 0xf2010001 + +/* RCCFGL */ +#define R367TER_RCCFGL 0xf202 +#define F367TER_TSRCFIFO_BCLKDEL1cK 0xf20200c0 +#define F367TER_RCCFGL_5 0xf2020020 +#define F367TER_TSRCFIFO_DUTY50 0xf2020010 +#define F367TER_TSRCFIFO_NSGNL2dATA 0xf2020008 +#define F367TER_TSRCFIFO_DISSERMUX 0xf2020004 +#define F367TER_RCCFGL_1 0xf2020002 +#define F367TER_TSRCFIFO_STOPCKDIS 0xf2020001 + +/* RCINSDELH */ +#define R367TER_RCINSDELH 0xf203 +#define F367TER_TSRCDEL_SYNCBYTE 0xf2030080 +#define F367TER_TSRCDEL_XXHEADER 0xf2030040 +#define F367TER_TSRCDEL_BBHEADER 0xf2030020 +#define F367TER_TSRCDEL_DATAFIELD 0xf2030010 +#define F367TER_TSRCINSDEL_ISCR 0xf2030008 +#define F367TER_TSRCINSDEL_NPD 0xf2030004 +#define F367TER_TSRCINSDEL_RSPARITY 0xf2030002 +#define F367TER_TSRCINSDEL_CRC8 0xf2030001 + +/* RCINSDELM */ +#define R367TER_RCINSDELM 0xf204 +#define F367TER_TSRCINS_BBPADDING 0xf2040080 +#define F367TER_TSRCINS_BCHFEC 0xf2040040 +#define F367TER_TSRCINS_LDPCFEC 0xf2040020 +#define F367TER_TSRCINS_EMODCOD 0xf2040010 +#define F367TER_TSRCINS_TOKEN 0xf2040008 +#define F367TER_TSRCINS_XXXERR 0xf2040004 +#define F367TER_TSRCINS_MATYPE 0xf2040002 +#define F367TER_TSRCINS_UPL 0xf2040001 + +/* RCINSDELL */ +#define R367TER_RCINSDELL 0xf205 +#define F367TER_TSRCINS_DFL 0xf2050080 +#define F367TER_TSRCINS_SYNCD 0xf2050040 +#define F367TER_TSRCINS_BLOCLEN 0xf2050020 +#define F367TER_TSRCINS_SIGPCOUNT 0xf2050010 +#define F367TER_TSRCINS_FIFO 0xf2050008 +#define F367TER_TSRCINS_REALPACK 0xf2050004 +#define F367TER_TSRCINS_TSCONFIG 0xf2050002 +#define F367TER_TSRCINS_LATENCY 0xf2050001 + +/* RCSTATUS */ +#define R367TER_RCSTATUS 0xf206 +#define F367TER_TSRCFIFO_LINEOK 0xf2060080 +#define F367TER_TSRCFIFO_ERROR 0xf2060040 +#define F367TER_TSRCFIFO_DATA7 0xf2060020 +#define F367TER_RCSTATUS_4 0xf2060010 +#define F367TER_TSRCFIFO_DEMODSEL 0xf2060008 +#define F367TER_TSRC1FIFOSPEED_STORE 0xf2060004 +#define F367TER_RCSTATUS_1 0xf2060002 +#define F367TER_TSRCSERIAL_IMPOSSIBLE 0xf2060001 + +/* RCSPEED */ +#define R367TER_RCSPEED 0xf207 +#define F367TER_TSRCFIFO_OUTSPEED 0xf20700ff + +/* RCDEBUGM */ +#define R367TER_RCDEBUGM 0xf208 +#define F367TER_SD_UNSYNC 0xf2080080 +#define F367TER_ULFLOCK_DETECTM 0xf2080040 +#define F367TER_SUL_SELECTOS 0xf2080020 +#define F367TER_DILUL_NOSCRBLE 0xf2080010 +#define F367TER_NUL_SCRB 0xf2080008 +#define F367TER_UL_SCRB 0xf2080004 +#define F367TER_SCRAULBAD 0xf2080002 +#define F367TER_SCRAUL_UNSYNC 0xf2080001 + +/* RCDEBUGL */ +#define R367TER_RCDEBUGL 0xf209 +#define F367TER_RS_ERR 0xf2090080 +#define F367TER_LLFLOCK_DETECTM 0xf2090040 +#define F367TER_NOT_SUL_SELECTOS 0xf2090020 +#define F367TER_DILLL_NOSCRBLE 0xf2090010 +#define F367TER_NLL_SCRB 0xf2090008 +#define F367TER_LL_SCRB 0xf2090004 +#define F367TER_SCRALLBAD 0xf2090002 +#define F367TER_SCRALL_UNSYNC 0xf2090001 + +/* RCOBSCFG */ +#define R367TER_RCOBSCFG 0xf20a +#define F367TER_TSRCFIFO_OBSCFG 0xf20a00ff + +/* RCOBSM */ +#define R367TER_RCOBSM 0xf20b +#define F367TER_TSRCFIFO_OBSDATA_HI 0xf20b00ff + +/* RCOBSL */ +#define R367TER_RCOBSL 0xf20c +#define F367TER_TSRCFIFO_OBSDATA_LO 0xf20c00ff + +/* RCFECSPY */ +#define R367TER_RCFECSPY 0xf210 +#define F367TER_SPYRC_ENABLE 0xf2100080 +#define F367TER_RCNO_SYNCBYTE 0xf2100040 +#define F367TER_RCSERIAL_MODE 0xf2100020 +#define F367TER_RCUNUSUAL_PACKET 0xf2100010 +#define F367TER_BERRCMETER_DATAMODE 0xf210000c +#define F367TER_BERRCMETER_LMODE 0xf2100002 +#define F367TER_BERRCMETER_RESET 0xf2100001 + +/* RCFSPYCFG */ +#define R367TER_RCFSPYCFG 0xf211 +#define F367TER_FECSPYRC_INPUT 0xf21100c0 +#define F367TER_RCRST_ON_ERROR 0xf2110020 +#define F367TER_RCONE_SHOT 0xf2110010 +#define F367TER_RCI2C_MODE 0xf211000c +#define F367TER_SPYRC_HSTERESIS 0xf2110003 + +/* RCFSPYDATA */ +#define R367TER_RCFSPYDATA 0xf212 +#define F367TER_SPYRC_STUFFING 0xf2120080 +#define F367TER_RCNOERR_PKTJITTER 0xf2120040 +#define F367TER_SPYRC_CNULLPKT 0xf2120020 +#define F367TER_SPYRC_OUTDATA_MODE 0xf212001f + +/* RCFSPYOUT */ +#define R367TER_RCFSPYOUT 0xf213 +#define F367TER_FSPYRC_DIRECT 0xf2130080 +#define F367TER_RCFSPYOUT_6 0xf2130040 +#define F367TER_SPYRC_OUTDATA_BUS 0xf2130038 +#define F367TER_RCSTUFF_MODE 0xf2130007 + +/* RCFSTATUS */ +#define R367TER_RCFSTATUS 0xf214 +#define F367TER_SPYRC_ENDSIM 0xf2140080 +#define F367TER_RCVALID_SIM 0xf2140040 +#define F367TER_RCFOUND_SIGNAL 0xf2140020 +#define F367TER_RCDSS_SYNCBYTE 0xf2140010 +#define F367TER_RCRESULT_STATE 0xf214000f + +/* RCFGOODPACK */ +#define R367TER_RCFGOODPACK 0xf215 +#define F367TER_RCGOOD_PACKET 0xf21500ff + +/* RCFPACKCNT */ +#define R367TER_RCFPACKCNT 0xf216 +#define F367TER_RCPACKET_COUNTER 0xf21600ff + +/* RCFSPYMISC */ +#define R367TER_RCFSPYMISC 0xf217 +#define F367TER_RCLABEL_COUNTER 0xf21700ff + +/* RCFBERCPT4 */ +#define R367TER_RCFBERCPT4 0xf218 +#define F367TER_FBERRCMETER_CPT_MMMMSB 0xf21800ff + +/* RCFBERCPT3 */ +#define R367TER_RCFBERCPT3 0xf219 +#define F367TER_FBERRCMETER_CPT_MMMSB 0xf21900ff + +/* RCFBERCPT2 */ +#define R367TER_RCFBERCPT2 0xf21a +#define F367TER_FBERRCMETER_CPT_MMSB 0xf21a00ff + +/* RCFBERCPT1 */ +#define R367TER_RCFBERCPT1 0xf21b +#define F367TER_FBERRCMETER_CPT_MSB 0xf21b00ff + +/* RCFBERCPT0 */ +#define R367TER_RCFBERCPT0 0xf21c +#define F367TER_FBERRCMETER_CPT_LSB 0xf21c00ff + +/* RCFBERERR2 */ +#define R367TER_RCFBERERR2 0xf21d +#define F367TER_FBERRCMETER_ERR_HI 0xf21d00ff + +/* RCFBERERR1 */ +#define R367TER_RCFBERERR1 0xf21e +#define F367TER_FBERRCMETER_ERR 0xf21e00ff + +/* RCFBERERR0 */ +#define R367TER_RCFBERERR0 0xf21f +#define F367TER_FBERRCMETER_ERR_LO 0xf21f00ff + +/* RCFSTATESM */ +#define R367TER_RCFSTATESM 0xf220 +#define F367TER_RCRSTATE_F 0xf2200080 +#define F367TER_RCRSTATE_E 0xf2200040 +#define F367TER_RCRSTATE_D 0xf2200020 +#define F367TER_RCRSTATE_C 0xf2200010 +#define F367TER_RCRSTATE_B 0xf2200008 +#define F367TER_RCRSTATE_A 0xf2200004 +#define F367TER_RCRSTATE_9 0xf2200002 +#define F367TER_RCRSTATE_8 0xf2200001 + +/* RCFSTATESL */ +#define R367TER_RCFSTATESL 0xf221 +#define F367TER_RCRSTATE_7 0xf2210080 +#define F367TER_RCRSTATE_6 0xf2210040 +#define F367TER_RCRSTATE_5 0xf2210020 +#define F367TER_RCRSTATE_4 0xf2210010 +#define F367TER_RCRSTATE_3 0xf2210008 +#define F367TER_RCRSTATE_2 0xf2210004 +#define F367TER_RCRSTATE_1 0xf2210002 +#define F367TER_RCRSTATE_0 0xf2210001 + +/* RCFSPYBER */ +#define R367TER_RCFSPYBER 0xf222 +#define F367TER_RCFSPYBER_7 0xf2220080 +#define F367TER_SPYRCOBS_XORREAD 0xf2220040 +#define F367TER_FSPYRCBER_OBSMODE 0xf2220020 +#define F367TER_FSPYRCBER_SYNCBYT 0xf2220010 +#define F367TER_FSPYRCBER_UNSYNC 0xf2220008 +#define F367TER_FSPYRCBER_CTIME 0xf2220007 + +/* RCFSPYDISTM */ +#define R367TER_RCFSPYDISTM 0xf223 +#define F367TER_RCPKTTIME_DISTANCE_HI 0xf22300ff + +/* RCFSPYDISTL */ +#define R367TER_RCFSPYDISTL 0xf224 +#define F367TER_RCPKTTIME_DISTANCE_LO 0xf22400ff + +/* RCFSPYOBS7 */ +#define R367TER_RCFSPYOBS7 0xf228 +#define F367TER_RCSPYOBS_SPYFAIL 0xf2280080 +#define F367TER_RCSPYOBS_SPYFAIL1 0xf2280040 +#define F367TER_RCSPYOBS_ERROR 0xf2280020 +#define F367TER_RCSPYOBS_STROUT 0xf2280010 +#define F367TER_RCSPYOBS_RESULTSTATE1 0xf228000f + +/* RCFSPYOBS6 */ +#define R367TER_RCFSPYOBS6 0xf229 +#define F367TER_RCSPYOBS_RESULTSTATe0 0xf22900f0 +#define F367TER_RCSPYOBS_RESULTSTATEM1 0xf229000f + +/* RCFSPYOBS5 */ +#define R367TER_RCFSPYOBS5 0xf22a +#define F367TER_RCSPYOBS_BYTEOFPACKET1 0xf22a00ff + +/* RCFSPYOBS4 */ +#define R367TER_RCFSPYOBS4 0xf22b +#define F367TER_RCSPYOBS_BYTEVALUE1 0xf22b00ff + +/* RCFSPYOBS3 */ +#define R367TER_RCFSPYOBS3 0xf22c +#define F367TER_RCSPYOBS_DATA1 0xf22c00ff + +/* RCFSPYOBS2 */ +#define R367TER_RCFSPYOBS2 0xf22d +#define F367TER_RCSPYOBS_DATa0 0xf22d00ff + +/* RCFSPYOBS1 */ +#define R367TER_RCFSPYOBS1 0xf22e +#define F367TER_RCSPYOBS_DATAM1 0xf22e00ff + +/* RCFSPYOBS0 */ +#define R367TER_RCFSPYOBS0 0xf22f +#define F367TER_RCSPYOBS_DATAM2 0xf22f00ff + +/* TSGENERAL */ +#define R367TER_TSGENERAL 0xf230 +#define F367TER_TSGENERAL_7 0xf2300080 +#define F367TER_TSGENERAL_6 0xf2300040 +#define F367TER_TSFIFO_BCLK1aLL 0xf2300020 +#define F367TER_TSGENERAL_4 0xf2300010 +#define F367TER_MUXSTREAM_OUTMODE 0xf2300008 +#define F367TER_TSFIFO_PERMPARAL 0xf2300006 +#define F367TER_RST_REEDSOLO 0xf2300001 + +/* RC1SPEED */ +#define R367TER_RC1SPEED 0xf231 +#define F367TER_TSRCFIFO1_OUTSPEED 0xf23100ff + +/* TSGSTATUS */ +#define R367TER_TSGSTATUS 0xf232 +#define F367TER_TSGSTATUS_7 0xf2320080 +#define F367TER_TSGSTATUS_6 0xf2320040 +#define F367TER_RSMEM_FULL 0xf2320020 +#define F367TER_RS_MULTCALC 0xf2320010 +#define F367TER_RSIN_OVERTIME 0xf2320008 +#define F367TER_TSFIFO3_DEMODSEL 0xf2320004 +#define F367TER_TSFIFO2_DEMODSEL 0xf2320002 +#define F367TER_TSFIFO1_DEMODSEL 0xf2320001 + + +/* FECM */ +#define R367TER_FECM 0xf233 +#define F367TER_DSS_DVB 0xf2330080 +#define F367TER_DEMOD_BYPASS 0xf2330040 +#define F367TER_CMP_SLOWMODE 0xf2330020 +#define F367TER_DSS_SRCH 0xf2330010 +#define F367TER_FECM_3 0xf2330008 +#define F367TER_DIFF_MODEVIT 0xf2330004 +#define F367TER_SYNCVIT 0xf2330002 +#define F367TER_I2CSYM 0xf2330001 + +/* VTH12 */ +#define R367TER_VTH12 0xf234 +#define F367TER_VTH_12 0xf23400ff + +/* VTH23 */ +#define R367TER_VTH23 0xf235 +#define F367TER_VTH_23 0xf23500ff + +/* VTH34 */ +#define R367TER_VTH34 0xf236 +#define F367TER_VTH_34 0xf23600ff + +/* VTH56 */ +#define R367TER_VTH56 0xf237 +#define F367TER_VTH_56 0xf23700ff + +/* VTH67 */ +#define R367TER_VTH67 0xf238 +#define F367TER_VTH_67 0xf23800ff + +/* VTH78 */ +#define R367TER_VTH78 0xf239 +#define F367TER_VTH_78 0xf23900ff + +/* VITCURPUN */ +#define R367TER_VITCURPUN 0xf23a +#define F367TER_VIT_MAPPING 0xf23a00e0 +#define F367TER_VIT_CURPUN 0xf23a001f + +/* VERROR */ +#define R367TER_VERROR 0xf23b +#define F367TER_REGERR_VIT 0xf23b00ff + +/* PRVIT */ +#define R367TER_PRVIT 0xf23c +#define F367TER_PRVIT_7 0xf23c0080 +#define F367TER_DIS_VTHLOCK 0xf23c0040 +#define F367TER_E7_8VIT 0xf23c0020 +#define F367TER_E6_7VIT 0xf23c0010 +#define F367TER_E5_6VIT 0xf23c0008 +#define F367TER_E3_4VIT 0xf23c0004 +#define F367TER_E2_3VIT 0xf23c0002 +#define F367TER_E1_2VIT 0xf23c0001 + +/* VAVSRVIT */ +#define R367TER_VAVSRVIT 0xf23d +#define F367TER_AMVIT 0xf23d0080 +#define F367TER_FROZENVIT 0xf23d0040 +#define F367TER_SNVIT 0xf23d0030 +#define F367TER_TOVVIT 0xf23d000c +#define F367TER_HYPVIT 0xf23d0003 + +/* VSTATUSVIT */ +#define R367TER_VSTATUSVIT 0xf23e +#define F367TER_VITERBI_ON 0xf23e0080 +#define F367TER_END_LOOPVIT 0xf23e0040 +#define F367TER_VITERBI_DEPRF 0xf23e0020 +#define F367TER_PRFVIT 0xf23e0010 +#define F367TER_LOCKEDVIT 0xf23e0008 +#define F367TER_VITERBI_DELOCK 0xf23e0004 +#define F367TER_VIT_DEMODSEL 0xf23e0002 +#define F367TER_VITERBI_COMPOUT 0xf23e0001 + +/* VTHINUSE */ +#define R367TER_VTHINUSE 0xf23f +#define F367TER_VIT_INUSE 0xf23f00ff + +/* KDIV12 */ +#define R367TER_KDIV12 0xf240 +#define F367TER_KDIV12_MANUAL 0xf2400080 +#define F367TER_K_DIVIDER_12 0xf240007f + +/* KDIV23 */ +#define R367TER_KDIV23 0xf241 +#define F367TER_KDIV23_MANUAL 0xf2410080 +#define F367TER_K_DIVIDER_23 0xf241007f + +/* KDIV34 */ +#define R367TER_KDIV34 0xf242 +#define F367TER_KDIV34_MANUAL 0xf2420080 +#define F367TER_K_DIVIDER_34 0xf242007f + +/* KDIV56 */ +#define R367TER_KDIV56 0xf243 +#define F367TER_KDIV56_MANUAL 0xf2430080 +#define F367TER_K_DIVIDER_56 0xf243007f + +/* KDIV67 */ +#define R367TER_KDIV67 0xf244 +#define F367TER_KDIV67_MANUAL 0xf2440080 +#define F367TER_K_DIVIDER_67 0xf244007f + +/* KDIV78 */ +#define R367TER_KDIV78 0xf245 +#define F367TER_KDIV78_MANUAL 0xf2450080 +#define F367TER_K_DIVIDER_78 0xf245007f + +/* SIGPOWER */ +#define R367TER_SIGPOWER 0xf246 +#define F367TER_SIGPOWER_MANUAL 0xf2460080 +#define F367TER_SIG_POWER 0xf246007f + +/* DEMAPVIT */ +#define R367TER_DEMAPVIT 0xf247 +#define F367TER_DEMAPVIT_7 0xf2470080 +#define F367TER_K_DIVIDER_VIT 0xf247007f + +/* VITSCALE */ +#define R367TER_VITSCALE 0xf248 +#define F367TER_NVTH_NOSRANGE 0xf2480080 +#define F367TER_VERROR_MAXMODE 0xf2480040 +#define F367TER_KDIV_MODE 0xf2480030 +#define F367TER_NSLOWSN_LOCKED 0xf2480008 +#define F367TER_DELOCK_PRFLOSS 0xf2480004 +#define F367TER_DIS_RSFLOCK 0xf2480002 +#define F367TER_VITSCALE_0 0xf2480001 + +/* FFEC1PRG */ +#define R367TER_FFEC1PRG 0xf249 +#define F367TER_FDSS_DVB 0xf2490080 +#define F367TER_FDSS_SRCH 0xf2490040 +#define F367TER_FFECPROG_5 0xf2490020 +#define F367TER_FFECPROG_4 0xf2490010 +#define F367TER_FFECPROG_3 0xf2490008 +#define F367TER_FFECPROG_2 0xf2490004 +#define F367TER_FTS1_DISABLE 0xf2490002 +#define F367TER_FTS2_DISABLE 0xf2490001 + +/* FVITCURPUN */ +#define R367TER_FVITCURPUN 0xf24a +#define F367TER_FVIT_MAPPING 0xf24a00e0 +#define F367TER_FVIT_CURPUN 0xf24a001f + +/* FVERROR */ +#define R367TER_FVERROR 0xf24b +#define F367TER_FREGERR_VIT 0xf24b00ff + +/* FVSTATUSVIT */ +#define R367TER_FVSTATUSVIT 0xf24c +#define F367TER_FVITERBI_ON 0xf24c0080 +#define F367TER_F1END_LOOPVIT 0xf24c0040 +#define F367TER_FVITERBI_DEPRF 0xf24c0020 +#define F367TER_FPRFVIT 0xf24c0010 +#define F367TER_FLOCKEDVIT 0xf24c0008 +#define F367TER_FVITERBI_DELOCK 0xf24c0004 +#define F367TER_FVIT_DEMODSEL 0xf24c0002 +#define F367TER_FVITERBI_COMPOUT 0xf24c0001 + +/* DEBUG_LT1 */ +#define R367TER_DEBUG_LT1 0xf24d +#define F367TER_DBG_LT1 0xf24d00ff + +/* DEBUG_LT2 */ +#define R367TER_DEBUG_LT2 0xf24e +#define F367TER_DBG_LT2 0xf24e00ff + +/* DEBUG_LT3 */ +#define R367TER_DEBUG_LT3 0xf24f +#define F367TER_DBG_LT3 0xf24f00ff + +/* TSTSFMET */ +#define R367TER_TSTSFMET 0xf250 +#define F367TER_TSTSFEC_METRIQUES 0xf25000ff + +/* SELOUT */ +#define R367TER_SELOUT 0xf252 +#define F367TER_EN_SYNC 0xf2520080 +#define F367TER_EN_TBUSDEMAP 0xf2520040 +#define F367TER_SELOUT_5 0xf2520020 +#define F367TER_SELOUT_4 0xf2520010 +#define F367TER_TSTSYNCHRO_MODE 0xf2520002 + +/* TSYNC */ +#define R367TER_TSYNC 0xf253 +#define F367TER_CURPUN_INCMODE 0xf2530080 +#define F367TER_CERR_TSTMODE 0xf2530040 +#define F367TER_SHIFTSOF_MODE 0xf2530030 +#define F367TER_SLOWPHA_MODE 0xf2530008 +#define F367TER_PXX_BYPALL 0xf2530004 +#define F367TER_FROTA45_FIRST 0xf2530002 +#define F367TER_TST_BCHERROR 0xf2530001 + +/* TSTERR */ +#define R367TER_TSTERR 0xf254 +#define F367TER_TST_LONGPKT 0xf2540080 +#define F367TER_TST_ISSYION 0xf2540040 +#define F367TER_TST_NPDON 0xf2540020 +#define F367TER_TSTERR_4 0xf2540010 +#define F367TER_TRACEBACK_MODE 0xf2540008 +#define F367TER_TST_RSPARITY 0xf2540004 +#define F367TER_METRIQUE_MODE 0xf2540003 + +/* TSFSYNC */ +#define R367TER_TSFSYNC 0xf255 +#define F367TER_EN_SFECSYNC 0xf2550080 +#define F367TER_EN_SFECDEMAP 0xf2550040 +#define F367TER_SFCERR_TSTMODE 0xf2550020 +#define F367TER_SFECPXX_BYPALL 0xf2550010 +#define F367TER_SFECTSTSYNCHRO_MODE 0xf255000f + +/* TSTSFERR */ +#define R367TER_TSTSFERR 0xf256 +#define F367TER_TSTSTERR_7 0xf2560080 +#define F367TER_TSTSTERR_6 0xf2560040 +#define F367TER_TSTSTERR_5 0xf2560020 +#define F367TER_TSTSTERR_4 0xf2560010 +#define F367TER_SFECTRACEBACK_MODE 0xf2560008 +#define F367TER_SFEC_NCONVPROG 0xf2560004 +#define F367TER_SFECMETRIQUE_MODE 0xf2560003 + +/* TSTTSSF1 */ +#define R367TER_TSTTSSF1 0xf258 +#define F367TER_TSTERSSF 0xf2580080 +#define F367TER_TSTTSSFEN 0xf2580040 +#define F367TER_SFEC_OUTMODE 0xf2580030 +#define F367TER_XLSF_NOFTHRESHOLD 0xf2580008 +#define F367TER_TSTTSSF_STACKSEL 0xf2580007 + +/* TSTTSSF2 */ +#define R367TER_TSTTSSF2 0xf259 +#define F367TER_DILSF_DBBHEADER 0xf2590080 +#define F367TER_TSTTSSF_DISBUG 0xf2590040 +#define F367TER_TSTTSSF_NOBADSTART 0xf2590020 +#define F367TER_TSTTSSF_SELECT 0xf259001f + +/* TSTTSSF3 */ +#define R367TER_TSTTSSF3 0xf25a +#define F367TER_TSTTSSF3_7 0xf25a0080 +#define F367TER_TSTTSSF3_6 0xf25a0040 +#define F367TER_TSTTSSF3_5 0xf25a0020 +#define F367TER_TSTTSSF3_4 0xf25a0010 +#define F367TER_TSTTSSF3_3 0xf25a0008 +#define F367TER_TSTTSSF3_2 0xf25a0004 +#define F367TER_TSTTSSF3_1 0xf25a0002 +#define F367TER_DISSF_CLKENABLE 0xf25a0001 + +/* TSTTS1 */ +#define R367TER_TSTTS1 0xf25c +#define F367TER_TSTERS 0xf25c0080 +#define F367TER_TSFIFO_DSSSYNCB 0xf25c0040 +#define F367TER_TSTTS_FSPYBEFRS 0xf25c0020 +#define F367TER_NFORCE_SYNCBYTE 0xf25c0010 +#define F367TER_XL_NOFTHRESHOLD 0xf25c0008 +#define F367TER_TSTTS_FRFORCEPKT 0xf25c0004 +#define F367TER_DESCR_NOTAUTO 0xf25c0002 +#define F367TER_TSTTSEN 0xf25c0001 + +/* TSTTS2 */ +#define R367TER_TSTTS2 0xf25d +#define F367TER_DIL_DBBHEADER 0xf25d0080 +#define F367TER_TSTTS_NOBADXXX 0xf25d0040 +#define F367TER_TSFIFO_DELSPEEDUP 0xf25d0020 +#define F367TER_TSTTS_SELECT 0xf25d001f + +/* TSTTS3 */ +#define R367TER_TSTTS3 0xf25e +#define F367TER_TSTTS_NOPKTGAIN 0xf25e0080 +#define F367TER_TSTTS_NOPKTENE 0xf25e0040 +#define F367TER_TSTTS_ISOLATION 0xf25e0020 +#define F367TER_TSTTS_DISBUG 0xf25e0010 +#define F367TER_TSTTS_NOBADSTART 0xf25e0008 +#define F367TER_TSTTS_STACKSEL 0xf25e0007 + +/* TSTTS4 */ +#define R367TER_TSTTS4 0xf25f +#define F367TER_TSTTS4_7 0xf25f0080 +#define F367TER_TSTTS4_6 0xf25f0040 +#define F367TER_TSTTS4_5 0xf25f0020 +#define F367TER_TSTTS_DISDSTATE 0xf25f0010 +#define F367TER_TSTTS_FASTNOSYNC 0xf25f0008 +#define F367TER_EXT_FECSPYIN 0xf25f0004 +#define F367TER_TSTTS_NODPZERO 0xf25f0002 +#define F367TER_TSTTS_NODIV3 0xf25f0001 + +/* TSTTSRC */ +#define R367TER_TSTTSRC 0xf26c +#define F367TER_TSTTSRC_7 0xf26c0080 +#define F367TER_TSRCFIFO_DSSSYNCB 0xf26c0040 +#define F367TER_TSRCFIFO_DPUNACTIVE 0xf26c0020 +#define F367TER_TSRCFIFO_DELSPEEDUP 0xf26c0010 +#define F367TER_TSTTSRC_NODIV3 0xf26c0008 +#define F367TER_TSTTSRC_FRFORCEPKT 0xf26c0004 +#define F367TER_SAT25_SDDORIGINE 0xf26c0002 +#define F367TER_TSTTSRC_INACTIVE 0xf26c0001 + +/* TSTTSRS */ +#define R367TER_TSTTSRS 0xf26d +#define F367TER_TSTTSRS_7 0xf26d0080 +#define F367TER_TSTTSRS_6 0xf26d0040 +#define F367TER_TSTTSRS_5 0xf26d0020 +#define F367TER_TSTTSRS_4 0xf26d0010 +#define F367TER_TSTTSRS_3 0xf26d0008 +#define F367TER_TSTTSRS_2 0xf26d0004 +#define F367TER_TSTRS_DISRS2 0xf26d0002 +#define F367TER_TSTRS_DISRS1 0xf26d0001 + +/* TSSTATEM */ +#define R367TER_TSSTATEM 0xf270 +#define F367TER_TSDIL_ON 0xf2700080 +#define F367TER_TSSKIPRS_ON 0xf2700040 +#define F367TER_TSRS_ON 0xf2700020 +#define F367TER_TSDESCRAMB_ON 0xf2700010 +#define F367TER_TSFRAME_MODE 0xf2700008 +#define F367TER_TS_DISABLE 0xf2700004 +#define F367TER_TSACM_MODE 0xf2700002 +#define F367TER_TSOUT_NOSYNC 0xf2700001 + +/* TSSTATEL */ +#define R367TER_TSSTATEL 0xf271 +#define F367TER_TSNOSYNCBYTE 0xf2710080 +#define F367TER_TSPARITY_ON 0xf2710040 +#define F367TER_TSSYNCOUTRS_ON 0xf2710020 +#define F367TER_TSDVBS2_MODE 0xf2710010 +#define F367TER_TSISSYI_ON 0xf2710008 +#define F367TER_TSNPD_ON 0xf2710004 +#define F367TER_TSCRC8_ON 0xf2710002 +#define F367TER_TSDSS_PACKET 0xf2710001 + +/* TSCFGH */ +#define R367TER_TSCFGH 0xf272 +#define F367TER_TSFIFO_DVBCI 0xf2720080 +#define F367TER_TSFIFO_SERIAL 0xf2720040 +#define F367TER_TSFIFO_TEIUPDATE 0xf2720020 +#define F367TER_TSFIFO_DUTY50 0xf2720010 +#define F367TER_TSFIFO_HSGNLOUT 0xf2720008 +#define F367TER_TSFIFO_ERRMODE 0xf2720006 +#define F367TER_RST_HWARE 0xf2720001 + +/* TSCFGM */ +#define R367TER_TSCFGM 0xf273 +#define F367TER_TSFIFO_MANSPEED 0xf27300c0 +#define F367TER_TSFIFO_PERMDATA 0xf2730020 +#define F367TER_TSFIFO_NONEWSGNL 0xf2730010 +#define F367TER_TSFIFO_BITSPEED 0xf2730008 +#define F367TER_NPD_SPECDVBS2 0xf2730004 +#define F367TER_TSFIFO_STOPCKDIS 0xf2730002 +#define F367TER_TSFIFO_INVDATA 0xf2730001 + +/* TSCFGL */ +#define R367TER_TSCFGL 0xf274 +#define F367TER_TSFIFO_BCLKDEL1cK 0xf27400c0 +#define F367TER_BCHERROR_MODE 0xf2740030 +#define F367TER_TSFIFO_NSGNL2dATA 0xf2740008 +#define F367TER_TSFIFO_EMBINDVB 0xf2740004 +#define F367TER_TSFIFO_DPUNACT 0xf2740002 +#define F367TER_TSFIFO_NPDOFF 0xf2740001 + +/* TSSYNC */ +#define R367TER_TSSYNC 0xf275 +#define F367TER_TSFIFO_PERMUTE 0xf2750080 +#define F367TER_TSFIFO_FISCR3B 0xf2750060 +#define F367TER_TSFIFO_SYNCMODE 0xf2750018 +#define F367TER_TSFIFO_SYNCSEL 0xf2750007 + +/* TSINSDELH */ +#define R367TER_TSINSDELH 0xf276 +#define F367TER_TSDEL_SYNCBYTE 0xf2760080 +#define F367TER_TSDEL_XXHEADER 0xf2760040 +#define F367TER_TSDEL_BBHEADER 0xf2760020 +#define F367TER_TSDEL_DATAFIELD 0xf2760010 +#define F367TER_TSINSDEL_ISCR 0xf2760008 +#define F367TER_TSINSDEL_NPD 0xf2760004 +#define F367TER_TSINSDEL_RSPARITY 0xf2760002 +#define F367TER_TSINSDEL_CRC8 0xf2760001 + +/* TSINSDELM */ +#define R367TER_TSINSDELM 0xf277 +#define F367TER_TSINS_BBPADDING 0xf2770080 +#define F367TER_TSINS_BCHFEC 0xf2770040 +#define F367TER_TSINS_LDPCFEC 0xf2770020 +#define F367TER_TSINS_EMODCOD 0xf2770010 +#define F367TER_TSINS_TOKEN 0xf2770008 +#define F367TER_TSINS_XXXERR 0xf2770004 +#define F367TER_TSINS_MATYPE 0xf2770002 +#define F367TER_TSINS_UPL 0xf2770001 + +/* TSINSDELL */ +#define R367TER_TSINSDELL 0xf278 +#define F367TER_TSINS_DFL 0xf2780080 +#define F367TER_TSINS_SYNCD 0xf2780040 +#define F367TER_TSINS_BLOCLEN 0xf2780020 +#define F367TER_TSINS_SIGPCOUNT 0xf2780010 +#define F367TER_TSINS_FIFO 0xf2780008 +#define F367TER_TSINS_REALPACK 0xf2780004 +#define F367TER_TSINS_TSCONFIG 0xf2780002 +#define F367TER_TSINS_LATENCY 0xf2780001 + +/* TSDIVN */ +#define R367TER_TSDIVN 0xf279 +#define F367TER_TSFIFO_LOWSPEED 0xf2790080 +#define F367TER_BYTE_OVERSAMPLING 0xf2790070 +#define F367TER_TSMANUAL_PACKETNBR 0xf279000f + +/* TSDIVPM */ +#define R367TER_TSDIVPM 0xf27a +#define F367TER_TSMANUAL_P_HI 0xf27a00ff + +/* TSDIVPL */ +#define R367TER_TSDIVPL 0xf27b +#define F367TER_TSMANUAL_P_LO 0xf27b00ff + +/* TSDIVQM */ +#define R367TER_TSDIVQM 0xf27c +#define F367TER_TSMANUAL_Q_HI 0xf27c00ff + +/* TSDIVQL */ +#define R367TER_TSDIVQL 0xf27d +#define F367TER_TSMANUAL_Q_LO 0xf27d00ff + +/* TSDILSTKM */ +#define R367TER_TSDILSTKM 0xf27e +#define F367TER_TSFIFO_DILSTK_HI 0xf27e00ff + +/* TSDILSTKL */ +#define R367TER_TSDILSTKL 0xf27f +#define F367TER_TSFIFO_DILSTK_LO 0xf27f00ff + +/* TSSPEED */ +#define R367TER_TSSPEED 0xf280 +#define F367TER_TSFIFO_OUTSPEED 0xf28000ff + +/* TSSTATUS */ +#define R367TER_TSSTATUS 0xf281 +#define F367TER_TSFIFO_LINEOK 0xf2810080 +#define F367TER_TSFIFO_ERROR 0xf2810040 +#define F367TER_TSFIFO_DATA7 0xf2810020 +#define F367TER_TSFIFO_NOSYNC 0xf2810010 +#define F367TER_ISCR_INITIALIZED 0xf2810008 +#define F367TER_ISCR_UPDATED 0xf2810004 +#define F367TER_SOFFIFO_UNREGUL 0xf2810002 +#define F367TER_DIL_READY 0xf2810001 + +/* TSSTATUS2 */ +#define R367TER_TSSTATUS2 0xf282 +#define F367TER_TSFIFO_DEMODSEL 0xf2820080 +#define F367TER_TSFIFOSPEED_STORE 0xf2820040 +#define F367TER_DILXX_RESET 0xf2820020 +#define F367TER_TSSERIAL_IMPOSSIBLE 0xf2820010 +#define F367TER_TSFIFO_UNDERSPEED 0xf2820008 +#define F367TER_BITSPEED_EVENT 0xf2820004 +#define F367TER_UL_SCRAMBDETECT 0xf2820002 +#define F367TER_ULDTV67_FALSELOCK 0xf2820001 + +/* TSBITRATEM */ +#define R367TER_TSBITRATEM 0xf283 +#define F367TER_TSFIFO_BITRATE_HI 0xf28300ff + +/* TSBITRATEL */ +#define R367TER_TSBITRATEL 0xf284 +#define F367TER_TSFIFO_BITRATE_LO 0xf28400ff + +/* TSPACKLENM */ +#define R367TER_TSPACKLENM 0xf285 +#define F367TER_TSFIFO_PACKCPT 0xf28500e0 +#define F367TER_DIL_RPLEN_HI 0xf285001f + +/* TSPACKLENL */ +#define R367TER_TSPACKLENL 0xf286 +#define F367TER_DIL_RPLEN_LO 0xf28600ff + +/* TSBLOCLENM */ +#define R367TER_TSBLOCLENM 0xf287 +#define F367TER_TSFIFO_PFLEN_HI 0xf28700ff + +/* TSBLOCLENL */ +#define R367TER_TSBLOCLENL 0xf288 +#define F367TER_TSFIFO_PFLEN_LO 0xf28800ff + +/* TSDLYH */ +#define R367TER_TSDLYH 0xf289 +#define F367TER_SOFFIFO_TSTIMEVALID 0xf2890080 +#define F367TER_SOFFIFO_SPEEDUP 0xf2890040 +#define F367TER_SOFFIFO_STOP 0xf2890020 +#define F367TER_SOFFIFO_REGULATED 0xf2890010 +#define F367TER_SOFFIFO_REALSBOFF_HI 0xf289000f + +/* TSDLYM */ +#define R367TER_TSDLYM 0xf28a +#define F367TER_SOFFIFO_REALSBOFF_MED 0xf28a00ff + +/* TSDLYL */ +#define R367TER_TSDLYL 0xf28b +#define F367TER_SOFFIFO_REALSBOFF_LO 0xf28b00ff + +/* TSNPDAV */ +#define R367TER_TSNPDAV 0xf28c +#define F367TER_TSNPD_AVERAGE 0xf28c00ff + +/* TSBUFSTATH */ +#define R367TER_TSBUFSTATH 0xf28d +#define F367TER_TSISCR_3BYTES 0xf28d0080 +#define F367TER_TSISCR_NEWDATA 0xf28d0040 +#define F367TER_TSISCR_BUFSTAT_HI 0xf28d003f + +/* TSBUFSTATM */ +#define R367TER_TSBUFSTATM 0xf28e +#define F367TER_TSISCR_BUFSTAT_MED 0xf28e00ff + +/* TSBUFSTATL */ +#define R367TER_TSBUFSTATL 0xf28f +#define F367TER_TSISCR_BUFSTAT_LO 0xf28f00ff + +/* TSDEBUGM */ +#define R367TER_TSDEBUGM 0xf290 +#define F367TER_TSFIFO_ILLPACKET 0xf2900080 +#define F367TER_DIL_NOSYNC 0xf2900040 +#define F367TER_DIL_ISCR 0xf2900020 +#define F367TER_DILOUT_BSYNCB 0xf2900010 +#define F367TER_TSFIFO_EMPTYPKT 0xf2900008 +#define F367TER_TSFIFO_EMPTYRD 0xf2900004 +#define F367TER_SOFFIFO_STOPM 0xf2900002 +#define F367TER_SOFFIFO_SPEEDUPM 0xf2900001 + +/* TSDEBUGL */ +#define R367TER_TSDEBUGL 0xf291 +#define F367TER_TSFIFO_PACKLENFAIL 0xf2910080 +#define F367TER_TSFIFO_SYNCBFAIL 0xf2910040 +#define F367TER_TSFIFO_VITLIBRE 0xf2910020 +#define F367TER_TSFIFO_BOOSTSPEEDM 0xf2910010 +#define F367TER_TSFIFO_UNDERSPEEDM 0xf2910008 +#define F367TER_TSFIFO_ERROR_EVNT 0xf2910004 +#define F367TER_TSFIFO_FULL 0xf2910002 +#define F367TER_TSFIFO_OVERFLOWM 0xf2910001 + +/* TSDLYSETH */ +#define R367TER_TSDLYSETH 0xf292 +#define F367TER_SOFFIFO_OFFSET 0xf29200e0 +#define F367TER_SOFFIFO_SYMBOFFSET_HI 0xf292001f + +/* TSDLYSETM */ +#define R367TER_TSDLYSETM 0xf293 +#define F367TER_SOFFIFO_SYMBOFFSET_MED 0xf29300ff + +/* TSDLYSETL */ +#define R367TER_TSDLYSETL 0xf294 +#define F367TER_SOFFIFO_SYMBOFFSET_LO 0xf29400ff + +/* TSOBSCFG */ +#define R367TER_TSOBSCFG 0xf295 +#define F367TER_TSFIFO_OBSCFG 0xf29500ff + +/* TSOBSM */ +#define R367TER_TSOBSM 0xf296 +#define F367TER_TSFIFO_OBSDATA_HI 0xf29600ff + +/* TSOBSL */ +#define R367TER_TSOBSL 0xf297 +#define F367TER_TSFIFO_OBSDATA_LO 0xf29700ff + +/* ERRCTRL1 */ +#define R367TER_ERRCTRL1 0xf298 +#define F367TER_ERR_SRC1 0xf29800f0 +#define F367TER_ERRCTRL1_3 0xf2980008 +#define F367TER_NUM_EVT1 0xf2980007 + +/* ERRCNT1H */ +#define R367TER_ERRCNT1H 0xf299 +#define F367TER_ERRCNT1_OLDVALUE 0xf2990080 +#define F367TER_ERR_CNT1 0xf299007f + +/* ERRCNT1M */ +#define R367TER_ERRCNT1M 0xf29a +#define F367TER_ERR_CNT1_HI 0xf29a00ff + +/* ERRCNT1L */ +#define R367TER_ERRCNT1L 0xf29b +#define F367TER_ERR_CNT1_LO 0xf29b00ff + +/* ERRCTRL2 */ +#define R367TER_ERRCTRL2 0xf29c +#define F367TER_ERR_SRC2 0xf29c00f0 +#define F367TER_ERRCTRL2_3 0xf29c0008 +#define F367TER_NUM_EVT2 0xf29c0007 + +/* ERRCNT2H */ +#define R367TER_ERRCNT2H 0xf29d +#define F367TER_ERRCNT2_OLDVALUE 0xf29d0080 +#define F367TER_ERR_CNT2_HI 0xf29d007f + +/* ERRCNT2M */ +#define R367TER_ERRCNT2M 0xf29e +#define F367TER_ERR_CNT2_MED 0xf29e00ff + +/* ERRCNT2L */ +#define R367TER_ERRCNT2L 0xf29f +#define F367TER_ERR_CNT2_LO 0xf29f00ff + +/* FECSPY */ +#define R367TER_FECSPY 0xf2a0 +#define F367TER_SPY_ENABLE 0xf2a00080 +#define F367TER_NO_SYNCBYTE 0xf2a00040 +#define F367TER_SERIAL_MODE 0xf2a00020 +#define F367TER_UNUSUAL_PACKET 0xf2a00010 +#define F367TER_BERMETER_DATAMODE 0xf2a0000c +#define F367TER_BERMETER_LMODE 0xf2a00002 +#define F367TER_BERMETER_RESET 0xf2a00001 + +/* FSPYCFG */ +#define R367TER_FSPYCFG 0xf2a1 +#define F367TER_FECSPY_INPUT 0xf2a100c0 +#define F367TER_RST_ON_ERROR 0xf2a10020 +#define F367TER_ONE_SHOT 0xf2a10010 +#define F367TER_I2C_MOD 0xf2a1000c +#define F367TER_SPY_HYSTERESIS 0xf2a10003 + +/* FSPYDATA */ +#define R367TER_FSPYDATA 0xf2a2 +#define F367TER_SPY_STUFFING 0xf2a20080 +#define F367TER_NOERROR_PKTJITTER 0xf2a20040 +#define F367TER_SPY_CNULLPKT 0xf2a20020 +#define F367TER_SPY_OUTDATA_MODE 0xf2a2001f + +/* FSPYOUT */ +#define R367TER_FSPYOUT 0xf2a3 +#define F367TER_FSPY_DIRECT 0xf2a30080 +#define F367TER_FSPYOUT_6 0xf2a30040 +#define F367TER_SPY_OUTDATA_BUS 0xf2a30038 +#define F367TER_STUFF_MODE 0xf2a30007 + +/* FSTATUS */ +#define R367TER_FSTATUS 0xf2a4 +#define F367TER_SPY_ENDSIM 0xf2a40080 +#define F367TER_VALID_SIM 0xf2a40040 +#define F367TER_FOUND_SIGNAL 0xf2a40020 +#define F367TER_DSS_SYNCBYTE 0xf2a40010 +#define F367TER_RESULT_STATE 0xf2a4000f + +/* FGOODPACK */ +#define R367TER_FGOODPACK 0xf2a5 +#define F367TER_FGOOD_PACKET 0xf2a500ff + +/* FPACKCNT */ +#define R367TER_FPACKCNT 0xf2a6 +#define F367TER_FPACKET_COUNTER 0xf2a600ff + +/* FSPYMISC */ +#define R367TER_FSPYMISC 0xf2a7 +#define F367TER_FLABEL_COUNTER 0xf2a700ff + +/* FBERCPT4 */ +#define R367TER_FBERCPT4 0xf2a8 +#define F367TER_FBERMETER_CPT5 0xf2a800ff + +/* FBERCPT3 */ +#define R367TER_FBERCPT3 0xf2a9 +#define F367TER_FBERMETER_CPT4 0xf2a900ff + +/* FBERCPT2 */ +#define R367TER_FBERCPT2 0xf2aa +#define F367TER_FBERMETER_CPT3 0xf2aa00ff + +/* FBERCPT1 */ +#define R367TER_FBERCPT1 0xf2ab +#define F367TER_FBERMETER_CPT2 0xf2ab00ff + +/* FBERCPT0 */ +#define R367TER_FBERCPT0 0xf2ac +#define F367TER_FBERMETER_CPT1 0xf2ac00ff + +/* FBERERR2 */ +#define R367TER_FBERERR2 0xf2ad +#define F367TER_FBERMETER_ERR_HI 0xf2ad00ff + +/* FBERERR1 */ +#define R367TER_FBERERR1 0xf2ae +#define F367TER_FBERMETER_ERR_MED 0xf2ae00ff + +/* FBERERR0 */ +#define R367TER_FBERERR0 0xf2af +#define F367TER_FBERMETER_ERR_LO 0xf2af00ff + +/* FSTATESM */ +#define R367TER_FSTATESM 0xf2b0 +#define F367TER_RSTATE_F 0xf2b00080 +#define F367TER_RSTATE_E 0xf2b00040 +#define F367TER_RSTATE_D 0xf2b00020 +#define F367TER_RSTATE_C 0xf2b00010 +#define F367TER_RSTATE_B 0xf2b00008 +#define F367TER_RSTATE_A 0xf2b00004 +#define F367TER_RSTATE_9 0xf2b00002 +#define F367TER_RSTATE_8 0xf2b00001 + +/* FSTATESL */ +#define R367TER_FSTATESL 0xf2b1 +#define F367TER_RSTATE_7 0xf2b10080 +#define F367TER_RSTATE_6 0xf2b10040 +#define F367TER_RSTATE_5 0xf2b10020 +#define F367TER_RSTATE_4 0xf2b10010 +#define F367TER_RSTATE_3 0xf2b10008 +#define F367TER_RSTATE_2 0xf2b10004 +#define F367TER_RSTATE_1 0xf2b10002 +#define F367TER_RSTATE_0 0xf2b10001 + +/* FSPYBER */ +#define R367TER_FSPYBER 0xf2b2 +#define F367TER_FSPYBER_7 0xf2b20080 +#define F367TER_FSPYOBS_XORREAD 0xf2b20040 +#define F367TER_FSPYBER_OBSMODE 0xf2b20020 +#define F367TER_FSPYBER_SYNCBYTE 0xf2b20010 +#define F367TER_FSPYBER_UNSYNC 0xf2b20008 +#define F367TER_FSPYBER_CTIME 0xf2b20007 + +/* FSPYDISTM */ +#define R367TER_FSPYDISTM 0xf2b3 +#define F367TER_PKTTIME_DISTANCE_HI 0xf2b300ff + +/* FSPYDISTL */ +#define R367TER_FSPYDISTL 0xf2b4 +#define F367TER_PKTTIME_DISTANCE_LO 0xf2b400ff + +/* FSPYOBS7 */ +#define R367TER_FSPYOBS7 0xf2b8 +#define F367TER_FSPYOBS_SPYFAIL 0xf2b80080 +#define F367TER_FSPYOBS_SPYFAIL1 0xf2b80040 +#define F367TER_FSPYOBS_ERROR 0xf2b80020 +#define F367TER_FSPYOBS_STROUT 0xf2b80010 +#define F367TER_FSPYOBS_RESULTSTATE1 0xf2b8000f + +/* FSPYOBS6 */ +#define R367TER_FSPYOBS6 0xf2b9 +#define F367TER_FSPYOBS_RESULTSTATe0 0xf2b900f0 +#define F367TER_FSPYOBS_RESULTSTATEM1 0xf2b9000f + +/* FSPYOBS5 */ +#define R367TER_FSPYOBS5 0xf2ba +#define F367TER_FSPYOBS_BYTEOFPACKET1 0xf2ba00ff + +/* FSPYOBS4 */ +#define R367TER_FSPYOBS4 0xf2bb +#define F367TER_FSPYOBS_BYTEVALUE1 0xf2bb00ff + +/* FSPYOBS3 */ +#define R367TER_FSPYOBS3 0xf2bc +#define F367TER_FSPYOBS_DATA1 0xf2bc00ff + +/* FSPYOBS2 */ +#define R367TER_FSPYOBS2 0xf2bd +#define F367TER_FSPYOBS_DATa0 0xf2bd00ff + +/* FSPYOBS1 */ +#define R367TER_FSPYOBS1 0xf2be +#define F367TER_FSPYOBS_DATAM1 0xf2be00ff + +/* FSPYOBS0 */ +#define R367TER_FSPYOBS0 0xf2bf +#define F367TER_FSPYOBS_DATAM2 0xf2bf00ff + +/* SFDEMAP */ +#define R367TER_SFDEMAP 0xf2c0 +#define F367TER_SFDEMAP_7 0xf2c00080 +#define F367TER_SFEC_K_DIVIDER_VIT 0xf2c0007f + +/* SFERROR */ +#define R367TER_SFERROR 0xf2c1 +#define F367TER_SFEC_REGERR_VIT 0xf2c100ff + +/* SFAVSR */ +#define R367TER_SFAVSR 0xf2c2 +#define F367TER_SFEC_SUMERRORS 0xf2c20080 +#define F367TER_SERROR_MAXMODE 0xf2c20040 +#define F367TER_SN_SFEC 0xf2c20030 +#define F367TER_KDIV_MODE_SFEC 0xf2c2000c +#define F367TER_SFAVSR_1 0xf2c20002 +#define F367TER_SFAVSR_0 0xf2c20001 + +/* SFECSTATUS */ +#define R367TER_SFECSTATUS 0xf2c3 +#define F367TER_SFEC_ON 0xf2c30080 +#define F367TER_SFSTATUS_6 0xf2c30040 +#define F367TER_SFSTATUS_5 0xf2c30020 +#define F367TER_SFSTATUS_4 0xf2c30010 +#define F367TER_LOCKEDSFEC 0xf2c30008 +#define F367TER_SFEC_DELOCK 0xf2c30004 +#define F367TER_SFEC_DEMODSEL1 0xf2c30002 +#define F367TER_SFEC_OVFON 0xf2c30001 + +/* SFKDIV12 */ +#define R367TER_SFKDIV12 0xf2c4 +#define F367TER_SFECKDIV12_MAN 0xf2c40080 +#define F367TER_SFEC_K_DIVIDER_12 0xf2c4007f + +/* SFKDIV23 */ +#define R367TER_SFKDIV23 0xf2c5 +#define F367TER_SFECKDIV23_MAN 0xf2c50080 +#define F367TER_SFEC_K_DIVIDER_23 0xf2c5007f + +/* SFKDIV34 */ +#define R367TER_SFKDIV34 0xf2c6 +#define F367TER_SFECKDIV34_MAN 0xf2c60080 +#define F367TER_SFEC_K_DIVIDER_34 0xf2c6007f + +/* SFKDIV56 */ +#define R367TER_SFKDIV56 0xf2c7 +#define F367TER_SFECKDIV56_MAN 0xf2c70080 +#define F367TER_SFEC_K_DIVIDER_56 0xf2c7007f + +/* SFKDIV67 */ +#define R367TER_SFKDIV67 0xf2c8 +#define F367TER_SFECKDIV67_MAN 0xf2c80080 +#define F367TER_SFEC_K_DIVIDER_67 0xf2c8007f + +/* SFKDIV78 */ +#define R367TER_SFKDIV78 0xf2c9 +#define F367TER_SFECKDIV78_MAN 0xf2c90080 +#define F367TER_SFEC_K_DIVIDER_78 0xf2c9007f + +/* SFDILSTKM */ +#define R367TER_SFDILSTKM 0xf2ca +#define F367TER_SFEC_PACKCPT 0xf2ca00e0 +#define F367TER_SFEC_DILSTK_HI 0xf2ca001f + +/* SFDILSTKL */ +#define R367TER_SFDILSTKL 0xf2cb +#define F367TER_SFEC_DILSTK_LO 0xf2cb00ff + +/* SFSTATUS */ +#define R367TER_SFSTATUS 0xf2cc +#define F367TER_SFEC_LINEOK 0xf2cc0080 +#define F367TER_SFEC_ERROR 0xf2cc0040 +#define F367TER_SFEC_DATA7 0xf2cc0020 +#define F367TER_SFEC_OVERFLOW 0xf2cc0010 +#define F367TER_SFEC_DEMODSEL2 0xf2cc0008 +#define F367TER_SFEC_NOSYNC 0xf2cc0004 +#define F367TER_SFEC_UNREGULA 0xf2cc0002 +#define F367TER_SFEC_READY 0xf2cc0001 + +/* SFDLYH */ +#define R367TER_SFDLYH 0xf2cd +#define F367TER_SFEC_TSTIMEVALID 0xf2cd0080 +#define F367TER_SFEC_SPEEDUP 0xf2cd0040 +#define F367TER_SFEC_STOP 0xf2cd0020 +#define F367TER_SFEC_REGULATED 0xf2cd0010 +#define F367TER_SFEC_REALSYMBOFFSET 0xf2cd000f + +/* SFDLYM */ +#define R367TER_SFDLYM 0xf2ce +#define F367TER_SFEC_REALSYMBOFFSET_HI 0xf2ce00ff + +/* SFDLYL */ +#define R367TER_SFDLYL 0xf2cf +#define F367TER_SFEC_REALSYMBOFFSET_LO 0xf2cf00ff + +/* SFDLYSETH */ +#define R367TER_SFDLYSETH 0xf2d0 +#define F367TER_SFEC_OFFSET 0xf2d000e0 +#define F367TER_SFECDLYSETH_4 0xf2d00010 +#define F367TER_RST_SFEC 0xf2d00008 +#define F367TER_SFECDLYSETH_2 0xf2d00004 +#define F367TER_SFEC_DISABLE 0xf2d00002 +#define F367TER_SFEC_UNREGUL 0xf2d00001 + +/* SFDLYSETM */ +#define R367TER_SFDLYSETM 0xf2d1 +#define F367TER_SFECDLYSETM_7 0xf2d10080 +#define F367TER_SFEC_SYMBOFFSET_HI 0xf2d1007f + +/* SFDLYSETL */ +#define R367TER_SFDLYSETL 0xf2d2 +#define F367TER_SFEC_SYMBOFFSET_LO 0xf2d200ff + +/* SFOBSCFG */ +#define R367TER_SFOBSCFG 0xf2d3 +#define F367TER_SFEC_OBSCFG 0xf2d300ff + +/* SFOBSM */ +#define R367TER_SFOBSM 0xf2d4 +#define F367TER_SFEC_OBSDATA_HI 0xf2d400ff + +/* SFOBSL */ +#define R367TER_SFOBSL 0xf2d5 +#define F367TER_SFEC_OBSDATA_LO 0xf2d500ff + +/* SFECINFO */ +#define R367TER_SFECINFO 0xf2d6 +#define F367TER_SFECINFO_7 0xf2d60080 +#define F367TER_SFEC_SYNCDLSB 0xf2d60070 +#define F367TER_SFCE_S1cPHASE 0xf2d6000f + +/* SFERRCTRL */ +#define R367TER_SFERRCTRL 0xf2d8 +#define F367TER_SFEC_ERR_SOURCE 0xf2d800f0 +#define F367TER_SFERRCTRL_3 0xf2d80008 +#define F367TER_SFEC_NUM_EVENT 0xf2d80007 + +/* SFERRCNTH */ +#define R367TER_SFERRCNTH 0xf2d9 +#define F367TER_SFERRC_OLDVALUE 0xf2d90080 +#define F367TER_SFEC_ERR_CNT 0xf2d9007f + +/* SFERRCNTM */ +#define R367TER_SFERRCNTM 0xf2da +#define F367TER_SFEC_ERR_CNT_HI 0xf2da00ff + +/* SFERRCNTL */ +#define R367TER_SFERRCNTL 0xf2db +#define F367TER_SFEC_ERR_CNT_LO 0xf2db00ff + +/* SYMBRATEM */ +#define R367TER_SYMBRATEM 0xf2e0 +#define F367TER_DEFGEN_SYMBRATE_HI 0xf2e000ff + +/* SYMBRATEL */ +#define R367TER_SYMBRATEL 0xf2e1 +#define F367TER_DEFGEN_SYMBRATE_LO 0xf2e100ff + +/* SYMBSTATUS */ +#define R367TER_SYMBSTATUS 0xf2e2 +#define F367TER_SYMBDLINE2_OFF 0xf2e20080 +#define F367TER_SDDL_REINIT1 0xf2e20040 +#define F367TER_SDD_REINIT1 0xf2e20020 +#define F367TER_TOKENID_ERROR 0xf2e20010 +#define F367TER_SYMBRATE_OVERFLOW 0xf2e20008 +#define F367TER_SYMBRATE_UNDERFLOW 0xf2e20004 +#define F367TER_TOKENID_RSTEVENT 0xf2e20002 +#define F367TER_TOKENID_RESET1 0xf2e20001 + +/* SYMBCFG */ +#define R367TER_SYMBCFG 0xf2e3 +#define F367TER_SYMBCFG_7 0xf2e30080 +#define F367TER_SYMBCFG_6 0xf2e30040 +#define F367TER_SYMBCFG_5 0xf2e30020 +#define F367TER_SYMBCFG_4 0xf2e30010 +#define F367TER_SYMRATE_FSPEED 0xf2e3000c +#define F367TER_SYMRATE_SSPEED 0xf2e30003 + +/* SYMBFIFOM */ +#define R367TER_SYMBFIFOM 0xf2e4 +#define F367TER_SYMBFIFOM_7 0xf2e40080 +#define F367TER_SYMBFIFOM_6 0xf2e40040 +#define F367TER_DEFGEN_SYMFIFO_HI 0xf2e4003f + +/* SYMBFIFOL */ +#define R367TER_SYMBFIFOL 0xf2e5 +#define F367TER_DEFGEN_SYMFIFO_LO 0xf2e500ff + +/* SYMBOFFSM */ +#define R367TER_SYMBOFFSM 0xf2e6 +#define F367TER_TOKENID_RESET2 0xf2e60080 +#define F367TER_SDDL_REINIT2 0xf2e60040 +#define F367TER_SDD_REINIT2 0xf2e60020 +#define F367TER_SYMBOFFSM_4 0xf2e60010 +#define F367TER_SYMBOFFSM_3 0xf2e60008 +#define F367TER_DEFGEN_SYMBOFFSET_HI 0xf2e60007 + +/* SYMBOFFSL */ +#define R367TER_SYMBOFFSL 0xf2e7 +#define F367TER_DEFGEN_SYMBOFFSET_LO 0xf2e700ff + +/* DEBUG_LT4 */ +#define R367TER_DEBUG_LT4 0xf400 +#define F367TER_F_DEBUG_LT4 0xf40000ff + +/* DEBUG_LT5 */ +#define R367TER_DEBUG_LT5 0xf401 +#define F367TER_F_DEBUG_LT5 0xf40100ff + +/* DEBUG_LT6 */ +#define R367TER_DEBUG_LT6 0xf402 +#define F367TER_F_DEBUG_LT6 0xf40200ff + +/* DEBUG_LT7 */ +#define R367TER_DEBUG_LT7 0xf403 +#define F367TER_F_DEBUG_LT7 0xf40300ff + +/* DEBUG_LT8 */ +#define R367TER_DEBUG_LT8 0xf404 +#define F367TER_F_DEBUG_LT8 0xf40400ff + +/* DEBUG_LT9 */ +#define R367TER_DEBUG_LT9 0xf405 +#define F367TER_F_DEBUG_LT9 0xf40500ff + +#define STV0367TER_NBREGS 445 + +/* ID */ +#define R367CAB_ID 0xf000 +#define F367CAB_IDENTIFICATIONREGISTER 0xf00000ff + +/* I2CRPT */ +#define R367CAB_I2CRPT 0xf001 +#define F367CAB_I2CT_ON 0xf0010080 +#define F367CAB_ENARPT_LEVEL 0xf0010070 +#define F367CAB_SCLT_DELAY 0xf0010008 +#define F367CAB_SCLT_NOD 0xf0010004 +#define F367CAB_STOP_ENABLE 0xf0010002 +#define F367CAB_SDAT_NOD 0xf0010001 + +/* TOPCTRL */ +#define R367CAB_TOPCTRL 0xf002 +#define F367CAB_STDBY 0xf0020080 +#define F367CAB_STDBY_CORE 0xf0020020 +#define F367CAB_QAM_COFDM 0xf0020010 +#define F367CAB_TS_DIS 0xf0020008 +#define F367CAB_DIR_CLK_216 0xf0020004 + +/* IOCFG0 */ +#define R367CAB_IOCFG0 0xf003 +#define F367CAB_OP0_SD 0xf0030080 +#define F367CAB_OP0_VAL 0xf0030040 +#define F367CAB_OP0_OD 0xf0030020 +#define F367CAB_OP0_INV 0xf0030010 +#define F367CAB_OP0_DACVALUE_HI 0xf003000f + +/* DAc0R */ +#define R367CAB_DAC0R 0xf004 +#define F367CAB_OP0_DACVALUE_LO 0xf00400ff + +/* IOCFG1 */ +#define R367CAB_IOCFG1 0xf005 +#define F367CAB_IP0 0xf0050040 +#define F367CAB_OP1_OD 0xf0050020 +#define F367CAB_OP1_INV 0xf0050010 +#define F367CAB_OP1_DACVALUE_HI 0xf005000f + +/* DAC1R */ +#define R367CAB_DAC1R 0xf006 +#define F367CAB_OP1_DACVALUE_LO 0xf00600ff + +/* IOCFG2 */ +#define R367CAB_IOCFG2 0xf007 +#define F367CAB_OP2_LOCK_CONF 0xf00700e0 +#define F367CAB_OP2_OD 0xf0070010 +#define F367CAB_OP2_VAL 0xf0070008 +#define F367CAB_OP1_LOCK_CONF 0xf0070007 + +/* SDFR */ +#define R367CAB_SDFR 0xf008 +#define F367CAB_OP0_FREQ 0xf00800f0 +#define F367CAB_OP1_FREQ 0xf008000f + +/* AUX_CLK */ +#define R367CAB_AUX_CLK 0xf00a +#define F367CAB_AUXFEC_CTL 0xf00a00c0 +#define F367CAB_DIS_CKX4 0xf00a0020 +#define F367CAB_CKSEL 0xf00a0018 +#define F367CAB_CKDIV_PROG 0xf00a0006 +#define F367CAB_AUXCLK_ENA 0xf00a0001 + +/* FREESYS1 */ +#define R367CAB_FREESYS1 0xf00b +#define F367CAB_FREESYS_1 0xf00b00ff + +/* FREESYS2 */ +#define R367CAB_FREESYS2 0xf00c +#define F367CAB_FREESYS_2 0xf00c00ff + +/* FREESYS3 */ +#define R367CAB_FREESYS3 0xf00d +#define F367CAB_FREESYS_3 0xf00d00ff + +/* GPIO_CFG */ +#define R367CAB_GPIO_CFG 0xf00e +#define F367CAB_GPIO7_OD 0xf00e0080 +#define F367CAB_GPIO7_CFG 0xf00e0040 +#define F367CAB_GPIO6_OD 0xf00e0020 +#define F367CAB_GPIO6_CFG 0xf00e0010 +#define F367CAB_GPIO5_OD 0xf00e0008 +#define F367CAB_GPIO5_CFG 0xf00e0004 +#define F367CAB_GPIO4_OD 0xf00e0002 +#define F367CAB_GPIO4_CFG 0xf00e0001 + +/* GPIO_CMD */ +#define R367CAB_GPIO_CMD 0xf00f +#define F367CAB_GPIO7_VAL 0xf00f0008 +#define F367CAB_GPIO6_VAL 0xf00f0004 +#define F367CAB_GPIO5_VAL 0xf00f0002 +#define F367CAB_GPIO4_VAL 0xf00f0001 + +/* TSTRES */ +#define R367CAB_TSTRES 0xf0c0 +#define F367CAB_FRES_DISPLAY 0xf0c00080 +#define F367CAB_FRES_FIFO_AD 0xf0c00020 +#define F367CAB_FRESRS 0xf0c00010 +#define F367CAB_FRESACS 0xf0c00008 +#define F367CAB_FRESFEC 0xf0c00004 +#define F367CAB_FRES_PRIF 0xf0c00002 +#define F367CAB_FRESCORE 0xf0c00001 + +/* ANACTRL */ +#define R367CAB_ANACTRL 0xf0c1 +#define F367CAB_BYPASS_XTAL 0xf0c10040 +#define F367CAB_BYPASS_PLLXN 0xf0c1000c +#define F367CAB_DIS_PAD_OSC 0xf0c10002 +#define F367CAB_STDBY_PLLXN 0xf0c10001 + +/* TSTBUS */ +#define R367CAB_TSTBUS 0xf0c2 +#define F367CAB_TS_BYTE_CLK_INV 0xf0c20080 +#define F367CAB_CFG_IP 0xf0c20070 +#define F367CAB_CFG_TST 0xf0c2000f + +/* RF_AGC1 */ +#define R367CAB_RF_AGC1 0xf0d4 +#define F367CAB_RF_AGC1_LEVEL_HI 0xf0d400ff + +/* RF_AGC2 */ +#define R367CAB_RF_AGC2 0xf0d5 +#define F367CAB_REF_ADGP 0xf0d50080 +#define F367CAB_STDBY_ADCGP 0xf0d50020 +#define F367CAB_RF_AGC1_LEVEL_LO 0xf0d50003 + +/* ANADIGCTRL */ +#define R367CAB_ANADIGCTRL 0xf0d7 +#define F367CAB_SEL_CLKDEM 0xf0d70020 +#define F367CAB_EN_BUFFER_Q 0xf0d70010 +#define F367CAB_EN_BUFFER_I 0xf0d70008 +#define F367CAB_ADC_RIS_EGDE 0xf0d70004 +#define F367CAB_SGN_ADC 0xf0d70002 +#define F367CAB_SEL_AD12_SYNC 0xf0d70001 + +/* PLLMDIV */ +#define R367CAB_PLLMDIV 0xf0d8 +#define F367CAB_PLL_MDIV 0xf0d800ff + +/* PLLNDIV */ +#define R367CAB_PLLNDIV 0xf0d9 +#define F367CAB_PLL_NDIV 0xf0d900ff + +/* PLLSETUP */ +#define R367CAB_PLLSETUP 0xf0da +#define F367CAB_PLL_PDIV 0xf0da0070 +#define F367CAB_PLL_KDIV 0xf0da000f + +/* DUAL_AD12 */ +#define R367CAB_DUAL_AD12 0xf0db +#define F367CAB_FS20M 0xf0db0020 +#define F367CAB_FS50M 0xf0db0010 +#define F367CAB_INMODe0 0xf0db0008 +#define F367CAB_POFFQ 0xf0db0004 +#define F367CAB_POFFI 0xf0db0002 +#define F367CAB_INMODE1 0xf0db0001 + +/* TSTBIST */ +#define R367CAB_TSTBIST 0xf0dc +#define F367CAB_TST_BYP_CLK 0xf0dc0080 +#define F367CAB_TST_GCLKENA_STD 0xf0dc0040 +#define F367CAB_TST_GCLKENA 0xf0dc0020 +#define F367CAB_TST_MEMBIST 0xf0dc001f + +/* CTRL_1 */ +#define R367CAB_CTRL_1 0xf402 +#define F367CAB_SOFT_RST 0xf4020080 +#define F367CAB_EQU_RST 0xf4020008 +#define F367CAB_CRL_RST 0xf4020004 +#define F367CAB_TRL_RST 0xf4020002 +#define F367CAB_AGC_RST 0xf4020001 + +/* CTRL_2 */ +#define R367CAB_CTRL_2 0xf403 +#define F367CAB_DEINT_RST 0xf4030008 +#define F367CAB_RS_RST 0xf4030004 + +/* IT_STATUS1 */ +#define R367CAB_IT_STATUS1 0xf408 +#define F367CAB_SWEEP_OUT 0xf4080080 +#define F367CAB_FSM_CRL 0xf4080040 +#define F367CAB_CRL_LOCK 0xf4080020 +#define F367CAB_MFSM 0xf4080010 +#define F367CAB_TRL_LOCK 0xf4080008 +#define F367CAB_TRL_AGC_LIMIT 0xf4080004 +#define F367CAB_ADJ_AGC_LOCK 0xf4080002 +#define F367CAB_AGC_QAM_LOCK 0xf4080001 + +/* IT_STATUS2 */ +#define R367CAB_IT_STATUS2 0xf409 +#define F367CAB_TSMF_CNT 0xf4090080 +#define F367CAB_TSMF_EOF 0xf4090040 +#define F367CAB_TSMF_RDY 0xf4090020 +#define F367CAB_FEC_NOCORR 0xf4090010 +#define F367CAB_SYNCSTATE 0xf4090008 +#define F367CAB_DEINT_LOCK 0xf4090004 +#define F367CAB_FADDING_FRZ 0xf4090002 +#define F367CAB_TAPMON_ALARM 0xf4090001 + +/* IT_EN1 */ +#define R367CAB_IT_EN1 0xf40a +#define F367CAB_SWEEP_OUTE 0xf40a0080 +#define F367CAB_FSM_CRLE 0xf40a0040 +#define F367CAB_CRL_LOCKE 0xf40a0020 +#define F367CAB_MFSME 0xf40a0010 +#define F367CAB_TRL_LOCKE 0xf40a0008 +#define F367CAB_TRL_AGC_LIMITE 0xf40a0004 +#define F367CAB_ADJ_AGC_LOCKE 0xf40a0002 +#define F367CAB_AGC_LOCKE 0xf40a0001 + +/* IT_EN2 */ +#define R367CAB_IT_EN2 0xf40b +#define F367CAB_TSMF_CNTE 0xf40b0080 +#define F367CAB_TSMF_EOFE 0xf40b0040 +#define F367CAB_TSMF_RDYE 0xf40b0020 +#define F367CAB_FEC_NOCORRE 0xf40b0010 +#define F367CAB_SYNCSTATEE 0xf40b0008 +#define F367CAB_DEINT_LOCKE 0xf40b0004 +#define F367CAB_FADDING_FRZE 0xf40b0002 +#define F367CAB_TAPMON_ALARME 0xf40b0001 + +/* CTRL_STATUS */ +#define R367CAB_CTRL_STATUS 0xf40c +#define F367CAB_QAMFEC_LOCK 0xf40c0004 +#define F367CAB_TSMF_LOCK 0xf40c0002 +#define F367CAB_TSMF_ERROR 0xf40c0001 + +/* TEST_CTL */ +#define R367CAB_TEST_CTL 0xf40f +#define F367CAB_TST_BLK_SEL 0xf40f0060 +#define F367CAB_TST_BUS_SEL 0xf40f001f + +/* AGC_CTL */ +#define R367CAB_AGC_CTL 0xf410 +#define F367CAB_AGC_LCK_TH 0xf41000f0 +#define F367CAB_AGC_ACCUMRSTSEL 0xf4100007 + +/* AGC_IF_CFG */ +#define R367CAB_AGC_IF_CFG 0xf411 +#define F367CAB_AGC_IF_BWSEL 0xf41100f0 +#define F367CAB_AGC_IF_FREEZE 0xf4110002 + +/* AGC_RF_CFG */ +#define R367CAB_AGC_RF_CFG 0xf412 +#define F367CAB_AGC_RF_BWSEL 0xf4120070 +#define F367CAB_AGC_RF_FREEZE 0xf4120002 + +/* AGC_PWM_CFG */ +#define R367CAB_AGC_PWM_CFG 0xf413 +#define F367CAB_AGC_RF_PWM_TST 0xf4130080 +#define F367CAB_AGC_RF_PWM_INV 0xf4130040 +#define F367CAB_AGC_IF_PWM_TST 0xf4130008 +#define F367CAB_AGC_IF_PWM_INV 0xf4130004 +#define F367CAB_AGC_PWM_CLKDIV 0xf4130003 + +/* AGC_PWR_REF_L */ +#define R367CAB_AGC_PWR_REF_L 0xf414 +#define F367CAB_AGC_PWRREF_LO 0xf41400ff + +/* AGC_PWR_REF_H */ +#define R367CAB_AGC_PWR_REF_H 0xf415 +#define F367CAB_AGC_PWRREF_HI 0xf4150003 + +/* AGC_RF_TH_L */ +#define R367CAB_AGC_RF_TH_L 0xf416 +#define F367CAB_AGC_RF_TH_LO 0xf41600ff + +/* AGC_RF_TH_H */ +#define R367CAB_AGC_RF_TH_H 0xf417 +#define F367CAB_AGC_RF_TH_HI 0xf417000f + +/* AGC_IF_LTH_L */ +#define R367CAB_AGC_IF_LTH_L 0xf418 +#define F367CAB_AGC_IF_THLO_LO 0xf41800ff + +/* AGC_IF_LTH_H */ +#define R367CAB_AGC_IF_LTH_H 0xf419 +#define F367CAB_AGC_IF_THLO_HI 0xf419000f + +/* AGC_IF_HTH_L */ +#define R367CAB_AGC_IF_HTH_L 0xf41a +#define F367CAB_AGC_IF_THHI_LO 0xf41a00ff + +/* AGC_IF_HTH_H */ +#define R367CAB_AGC_IF_HTH_H 0xf41b +#define F367CAB_AGC_IF_THHI_HI 0xf41b000f + +/* AGC_PWR_RD_L */ +#define R367CAB_AGC_PWR_RD_L 0xf41c +#define F367CAB_AGC_PWR_WORD_LO 0xf41c00ff + +/* AGC_PWR_RD_M */ +#define R367CAB_AGC_PWR_RD_M 0xf41d +#define F367CAB_AGC_PWR_WORD_ME 0xf41d00ff + +/* AGC_PWR_RD_H */ +#define R367CAB_AGC_PWR_RD_H 0xf41e +#define F367CAB_AGC_PWR_WORD_HI 0xf41e0003 + +/* AGC_PWM_IFCMD_L */ +#define R367CAB_AGC_PWM_IFCMD_L 0xf420 +#define F367CAB_AGC_IF_PWMCMD_LO 0xf42000ff + +/* AGC_PWM_IFCMD_H */ +#define R367CAB_AGC_PWM_IFCMD_H 0xf421 +#define F367CAB_AGC_IF_PWMCMD_HI 0xf421000f + +/* AGC_PWM_RFCMD_L */ +#define R367CAB_AGC_PWM_RFCMD_L 0xf422 +#define F367CAB_AGC_RF_PWMCMD_LO 0xf42200ff + +/* AGC_PWM_RFCMD_H */ +#define R367CAB_AGC_PWM_RFCMD_H 0xf423 +#define F367CAB_AGC_RF_PWMCMD_HI 0xf423000f + +/* IQDEM_CFG */ +#define R367CAB_IQDEM_CFG 0xf424 +#define F367CAB_IQDEM_CLK_SEL 0xf4240004 +#define F367CAB_IQDEM_INVIQ 0xf4240002 +#define F367CAB_IQDEM_A2dTYPE 0xf4240001 + +/* MIX_NCO_LL */ +#define R367CAB_MIX_NCO_LL 0xf425 +#define F367CAB_MIX_NCO_INC_LL 0xf42500ff + +/* MIX_NCO_HL */ +#define R367CAB_MIX_NCO_HL 0xf426 +#define F367CAB_MIX_NCO_INC_HL 0xf42600ff + +/* MIX_NCO_HH */ +#define R367CAB_MIX_NCO_HH 0xf427 +#define F367CAB_MIX_NCO_INVCNST 0xf4270080 +#define F367CAB_MIX_NCO_INC_HH 0xf427007f + +/* SRC_NCO_LL */ +#define R367CAB_SRC_NCO_LL 0xf428 +#define F367CAB_SRC_NCO_INC_LL 0xf42800ff + +/* SRC_NCO_LH */ +#define R367CAB_SRC_NCO_LH 0xf429 +#define F367CAB_SRC_NCO_INC_LH 0xf42900ff + +/* SRC_NCO_HL */ +#define R367CAB_SRC_NCO_HL 0xf42a +#define F367CAB_SRC_NCO_INC_HL 0xf42a00ff + +/* SRC_NCO_HH */ +#define R367CAB_SRC_NCO_HH 0xf42b +#define F367CAB_SRC_NCO_INC_HH 0xf42b007f + +/* IQDEM_GAIN_SRC_L */ +#define R367CAB_IQDEM_GAIN_SRC_L 0xf42c +#define F367CAB_GAIN_SRC_LO 0xf42c00ff + +/* IQDEM_GAIN_SRC_H */ +#define R367CAB_IQDEM_GAIN_SRC_H 0xf42d +#define F367CAB_GAIN_SRC_HI 0xf42d0003 + +/* IQDEM_DCRM_CFG_LL */ +#define R367CAB_IQDEM_DCRM_CFG_LL 0xf430 +#define F367CAB_DCRM0_DCIN_L 0xf43000ff + +/* IQDEM_DCRM_CFG_LH */ +#define R367CAB_IQDEM_DCRM_CFG_LH 0xf431 +#define F367CAB_DCRM1_I_DCIN_L 0xf43100fc +#define F367CAB_DCRM0_DCIN_H 0xf4310003 + +/* IQDEM_DCRM_CFG_HL */ +#define R367CAB_IQDEM_DCRM_CFG_HL 0xf432 +#define F367CAB_DCRM1_Q_DCIN_L 0xf43200f0 +#define F367CAB_DCRM1_I_DCIN_H 0xf432000f + +/* IQDEM_DCRM_CFG_HH */ +#define R367CAB_IQDEM_DCRM_CFG_HH 0xf433 +#define F367CAB_DCRM1_FRZ 0xf4330080 +#define F367CAB_DCRM0_FRZ 0xf4330040 +#define F367CAB_DCRM1_Q_DCIN_H 0xf433003f + +/* IQDEM_ADJ_COEFf0 */ +#define R367CAB_IQDEM_ADJ_COEFF0 0xf434 +#define F367CAB_ADJIIR_COEFF10_L 0xf43400ff + +/* IQDEM_ADJ_COEFF1 */ +#define R367CAB_IQDEM_ADJ_COEFF1 0xf435 +#define F367CAB_ADJIIR_COEFF11_L 0xf43500fc +#define F367CAB_ADJIIR_COEFF10_H 0xf4350003 + +/* IQDEM_ADJ_COEFF2 */ +#define R367CAB_IQDEM_ADJ_COEFF2 0xf436 +#define F367CAB_ADJIIR_COEFF12_L 0xf43600f0 +#define F367CAB_ADJIIR_COEFF11_H 0xf436000f + +/* IQDEM_ADJ_COEFF3 */ +#define R367CAB_IQDEM_ADJ_COEFF3 0xf437 +#define F367CAB_ADJIIR_COEFF20_L 0xf43700c0 +#define F367CAB_ADJIIR_COEFF12_H 0xf437003f + +/* IQDEM_ADJ_COEFF4 */ +#define R367CAB_IQDEM_ADJ_COEFF4 0xf438 +#define F367CAB_ADJIIR_COEFF20_H 0xf43800ff + +/* IQDEM_ADJ_COEFF5 */ +#define R367CAB_IQDEM_ADJ_COEFF5 0xf439 +#define F367CAB_ADJIIR_COEFF21_L 0xf43900ff + +/* IQDEM_ADJ_COEFF6 */ +#define R367CAB_IQDEM_ADJ_COEFF6 0xf43a +#define F367CAB_ADJIIR_COEFF22_L 0xf43a00fc +#define F367CAB_ADJIIR_COEFF21_H 0xf43a0003 + +/* IQDEM_ADJ_COEFF7 */ +#define R367CAB_IQDEM_ADJ_COEFF7 0xf43b +#define F367CAB_ADJIIR_COEFF22_H 0xf43b000f + +/* IQDEM_ADJ_EN */ +#define R367CAB_IQDEM_ADJ_EN 0xf43c +#define F367CAB_ALLPASSFILT_EN 0xf43c0008 +#define F367CAB_ADJ_AGC_EN 0xf43c0004 +#define F367CAB_ADJ_COEFF_FRZ 0xf43c0002 +#define F367CAB_ADJ_EN 0xf43c0001 + +/* IQDEM_ADJ_AGC_REF */ +#define R367CAB_IQDEM_ADJ_AGC_REF 0xf43d +#define F367CAB_ADJ_AGC_REF 0xf43d00ff + +/* ALLPASSFILT1 */ +#define R367CAB_ALLPASSFILT1 0xf440 +#define F367CAB_ALLPASSFILT_COEFF1_LO 0xf44000ff + +/* ALLPASSFILT2 */ +#define R367CAB_ALLPASSFILT2 0xf441 +#define F367CAB_ALLPASSFILT_COEFF1_ME 0xf44100ff + +/* ALLPASSFILT3 */ +#define R367CAB_ALLPASSFILT3 0xf442 +#define F367CAB_ALLPASSFILT_COEFF2_LO 0xf44200c0 +#define F367CAB_ALLPASSFILT_COEFF1_HI 0xf442003f + +/* ALLPASSFILT4 */ +#define R367CAB_ALLPASSFILT4 0xf443 +#define F367CAB_ALLPASSFILT_COEFF2_MEL 0xf44300ff + +/* ALLPASSFILT5 */ +#define R367CAB_ALLPASSFILT5 0xf444 +#define F367CAB_ALLPASSFILT_COEFF2_MEH 0xf44400ff + +/* ALLPASSFILT6 */ +#define R367CAB_ALLPASSFILT6 0xf445 +#define F367CAB_ALLPASSFILT_COEFF3_LO 0xf44500f0 +#define F367CAB_ALLPASSFILT_COEFF2_HI 0xf445000f + +/* ALLPASSFILT7 */ +#define R367CAB_ALLPASSFILT7 0xf446 +#define F367CAB_ALLPASSFILT_COEFF3_MEL 0xf44600ff + +/* ALLPASSFILT8 */ +#define R367CAB_ALLPASSFILT8 0xf447 +#define F367CAB_ALLPASSFILT_COEFF3_MEH 0xf44700ff + +/* ALLPASSFILT9 */ +#define R367CAB_ALLPASSFILT9 0xf448 +#define F367CAB_ALLPASSFILT_COEFF4_LO 0xf44800fc +#define F367CAB_ALLPASSFILT_COEFF3_HI 0xf4480003 + +/* ALLPASSFILT10 */ +#define R367CAB_ALLPASSFILT10 0xf449 +#define F367CAB_ALLPASSFILT_COEFF4_ME 0xf44900ff + +/* ALLPASSFILT11 */ +#define R367CAB_ALLPASSFILT11 0xf44a +#define F367CAB_ALLPASSFILT_COEFF4_HI 0xf44a00ff + +/* TRL_AGC_CFG */ +#define R367CAB_TRL_AGC_CFG 0xf450 +#define F367CAB_TRL_AGC_FREEZE 0xf4500080 +#define F367CAB_TRL_AGC_REF 0xf450007f + +/* TRL_LPF_CFG */ +#define R367CAB_TRL_LPF_CFG 0xf454 +#define F367CAB_NYQPOINT_INV 0xf4540040 +#define F367CAB_TRL_SHIFT 0xf4540030 +#define F367CAB_NYQ_COEFF_SEL 0xf454000c +#define F367CAB_TRL_LPF_FREEZE 0xf4540002 +#define F367CAB_TRL_LPF_CRT 0xf4540001 + +/* TRL_LPF_ACQ_GAIN */ +#define R367CAB_TRL_LPF_ACQ_GAIN 0xf455 +#define F367CAB_TRL_GDIR_ACQ 0xf4550070 +#define F367CAB_TRL_GINT_ACQ 0xf4550007 + +/* TRL_LPF_TRK_GAIN */ +#define R367CAB_TRL_LPF_TRK_GAIN 0xf456 +#define F367CAB_TRL_GDIR_TRK 0xf4560070 +#define F367CAB_TRL_GINT_TRK 0xf4560007 + +/* TRL_LPF_OUT_GAIN */ +#define R367CAB_TRL_LPF_OUT_GAIN 0xf457 +#define F367CAB_TRL_GAIN_OUT 0xf4570007 + +/* TRL_LOCKDET_LTH */ +#define R367CAB_TRL_LOCKDET_LTH 0xf458 +#define F367CAB_TRL_LCK_THLO 0xf4580007 + +/* TRL_LOCKDET_HTH */ +#define R367CAB_TRL_LOCKDET_HTH 0xf459 +#define F367CAB_TRL_LCK_THHI 0xf45900ff + +/* TRL_LOCKDET_TRGVAL */ +#define R367CAB_TRL_LOCKDET_TRGVAL 0xf45a +#define F367CAB_TRL_LCK_TRG 0xf45a00ff + +/* IQ_QAM */ +#define R367CAB_IQ_QAM 0xf45c +#define F367CAB_IQ_INPUT 0xf45c0008 +#define F367CAB_DETECT_MODE 0xf45c0007 + +/* FSM_STATE */ +#define R367CAB_FSM_STATE 0xf460 +#define F367CAB_CRL_DFE 0xf4600080 +#define F367CAB_DFE_START 0xf4600040 +#define F367CAB_CTRLG_START 0xf4600030 +#define F367CAB_FSM_FORCESTATE 0xf460000f + +/* FSM_CTL */ +#define R367CAB_FSM_CTL 0xf461 +#define F367CAB_FEC2_EN 0xf4610040 +#define F367CAB_SIT_EN 0xf4610020 +#define F367CAB_TRL_AHEAD 0xf4610010 +#define F367CAB_TRL2_EN 0xf4610008 +#define F367CAB_FSM_EQA1_EN 0xf4610004 +#define F367CAB_FSM_BKP_DIS 0xf4610002 +#define F367CAB_FSM_FORCE_EN 0xf4610001 + +/* FSM_STS */ +#define R367CAB_FSM_STS 0xf462 +#define F367CAB_FSM_STATUS 0xf462000f + +/* FSM_SNR0_HTH */ +#define R367CAB_FSM_SNR0_HTH 0xf463 +#define F367CAB_SNR0_HTH 0xf46300ff + +/* FSM_SNR1_HTH */ +#define R367CAB_FSM_SNR1_HTH 0xf464 +#define F367CAB_SNR1_HTH 0xf46400ff + +/* FSM_SNR2_HTH */ +#define R367CAB_FSM_SNR2_HTH 0xf465 +#define F367CAB_SNR2_HTH 0xf46500ff + +/* FSM_SNR0_LTH */ +#define R367CAB_FSM_SNR0_LTH 0xf466 +#define F367CAB_SNR0_LTH 0xf46600ff + +/* FSM_SNR1_LTH */ +#define R367CAB_FSM_SNR1_LTH 0xf467 +#define F367CAB_SNR1_LTH 0xf46700ff + +/* FSM_EQA1_HTH */ +#define R367CAB_FSM_EQA1_HTH 0xf468 +#define F367CAB_SNR3_HTH_LO 0xf46800f0 +#define F367CAB_EQA1_HTH 0xf468000f + +/* FSM_TEMPO */ +#define R367CAB_FSM_TEMPO 0xf469 +#define F367CAB_SIT 0xf46900c0 +#define F367CAB_WST 0xf4690038 +#define F367CAB_ELT 0xf4690006 +#define F367CAB_SNR3_HTH_HI 0xf4690001 + +/* FSM_CONFIG */ +#define R367CAB_FSM_CONFIG 0xf46a +#define F367CAB_FEC2_DFEOFF 0xf46a0004 +#define F367CAB_PRIT_STATE 0xf46a0002 +#define F367CAB_MODMAP_STATE 0xf46a0001 + +/* EQU_I_TESTTAP_L */ +#define R367CAB_EQU_I_TESTTAP_L 0xf474 +#define F367CAB_I_TEST_TAP_L 0xf47400ff + +/* EQU_I_TESTTAP_M */ +#define R367CAB_EQU_I_TESTTAP_M 0xf475 +#define F367CAB_I_TEST_TAP_M 0xf47500ff + +/* EQU_I_TESTTAP_H */ +#define R367CAB_EQU_I_TESTTAP_H 0xf476 +#define F367CAB_I_TEST_TAP_H 0xf476001f + +/* EQU_TESTAP_CFG */ +#define R367CAB_EQU_TESTAP_CFG 0xf477 +#define F367CAB_TEST_FFE_DFE_SEL 0xf4770040 +#define F367CAB_TEST_TAP_SELECT 0xf477003f + +/* EQU_Q_TESTTAP_L */ +#define R367CAB_EQU_Q_TESTTAP_L 0xf478 +#define F367CAB_Q_TEST_TAP_L 0xf47800ff + +/* EQU_Q_TESTTAP_M */ +#define R367CAB_EQU_Q_TESTTAP_M 0xf479 +#define F367CAB_Q_TEST_TAP_M 0xf47900ff + +/* EQU_Q_TESTTAP_H */ +#define R367CAB_EQU_Q_TESTTAP_H 0xf47a +#define F367CAB_Q_TEST_TAP_H 0xf47a001f + +/* EQU_TAP_CTRL */ +#define R367CAB_EQU_TAP_CTRL 0xf47b +#define F367CAB_MTAP_FRZ 0xf47b0010 +#define F367CAB_PRE_FREEZE 0xf47b0008 +#define F367CAB_DFE_TAPMON_EN 0xf47b0004 +#define F367CAB_FFE_TAPMON_EN 0xf47b0002 +#define F367CAB_MTAP_ONLY 0xf47b0001 + +/* EQU_CTR_CRL_CONTROL_L */ +#define R367CAB_EQU_CTR_CRL_CONTROL_L 0xf47c +#define F367CAB_EQU_CTR_CRL_CONTROL_LO 0xf47c00ff + +/* EQU_CTR_CRL_CONTROL_H */ +#define R367CAB_EQU_CTR_CRL_CONTROL_H 0xf47d +#define F367CAB_EQU_CTR_CRL_CONTROL_HI 0xf47d00ff + +/* EQU_CTR_HIPOW_L */ +#define R367CAB_EQU_CTR_HIPOW_L 0xf47e +#define F367CAB_CTR_HIPOW_L 0xf47e00ff + +/* EQU_CTR_HIPOW_H */ +#define R367CAB_EQU_CTR_HIPOW_H 0xf47f +#define F367CAB_CTR_HIPOW_H 0xf47f00ff + +/* EQU_I_EQU_LO */ +#define R367CAB_EQU_I_EQU_LO 0xf480 +#define F367CAB_EQU_I_EQU_L 0xf48000ff + +/* EQU_I_EQU_HI */ +#define R367CAB_EQU_I_EQU_HI 0xf481 +#define F367CAB_EQU_I_EQU_H 0xf4810003 + +/* EQU_Q_EQU_LO */ +#define R367CAB_EQU_Q_EQU_LO 0xf482 +#define F367CAB_EQU_Q_EQU_L 0xf48200ff + +/* EQU_Q_EQU_HI */ +#define R367CAB_EQU_Q_EQU_HI 0xf483 +#define F367CAB_EQU_Q_EQU_H 0xf4830003 + +/* EQU_MAPPER */ +#define R367CAB_EQU_MAPPER 0xf484 +#define F367CAB_QUAD_AUTO 0xf4840080 +#define F367CAB_QUAD_INV 0xf4840040 +#define F367CAB_QAM_MODE 0xf4840007 + +/* EQU_SWEEP_RATE */ +#define R367CAB_EQU_SWEEP_RATE 0xf485 +#define F367CAB_SNR_PER 0xf48500c0 +#define F367CAB_SWEEP_RATE 0xf485003f + +/* EQU_SNR_LO */ +#define R367CAB_EQU_SNR_LO 0xf486 +#define F367CAB_SNR_LO 0xf48600ff + +/* EQU_SNR_HI */ +#define R367CAB_EQU_SNR_HI 0xf487 +#define F367CAB_SNR_HI 0xf48700ff + +/* EQU_GAMMA_LO */ +#define R367CAB_EQU_GAMMA_LO 0xf488 +#define F367CAB_GAMMA_LO 0xf48800ff + +/* EQU_GAMMA_HI */ +#define R367CAB_EQU_GAMMA_HI 0xf489 +#define F367CAB_GAMMA_ME 0xf48900ff + +/* EQU_ERR_GAIN */ +#define R367CAB_EQU_ERR_GAIN 0xf48a +#define F367CAB_EQA1MU 0xf48a0070 +#define F367CAB_CRL2MU 0xf48a000e +#define F367CAB_GAMMA_HI 0xf48a0001 + +/* EQU_RADIUS */ +#define R367CAB_EQU_RADIUS 0xf48b +#define F367CAB_RADIUS 0xf48b00ff + +/* EQU_FFE_MAINTAP */ +#define R367CAB_EQU_FFE_MAINTAP 0xf48c +#define F367CAB_FFE_MAINTAP_INIT 0xf48c00ff + +/* EQU_FFE_LEAKAGE */ +#define R367CAB_EQU_FFE_LEAKAGE 0xf48e +#define F367CAB_LEAK_PER 0xf48e00f0 +#define F367CAB_EQU_OUTSEL 0xf48e0002 +#define F367CAB_PNT2dFE 0xf48e0001 + +/* EQU_FFE_MAINTAP_POS */ +#define R367CAB_EQU_FFE_MAINTAP_POS 0xf48f +#define F367CAB_FFE_LEAK_EN 0xf48f0080 +#define F367CAB_DFE_LEAK_EN 0xf48f0040 +#define F367CAB_FFE_MAINTAP_POS 0xf48f003f + +/* EQU_GAIN_WIDE */ +#define R367CAB_EQU_GAIN_WIDE 0xf490 +#define F367CAB_DFE_GAIN_WIDE 0xf49000f0 +#define F367CAB_FFE_GAIN_WIDE 0xf490000f + +/* EQU_GAIN_NARROW */ +#define R367CAB_EQU_GAIN_NARROW 0xf491 +#define F367CAB_DFE_GAIN_NARROW 0xf49100f0 +#define F367CAB_FFE_GAIN_NARROW 0xf491000f + +/* EQU_CTR_LPF_GAIN */ +#define R367CAB_EQU_CTR_LPF_GAIN 0xf492 +#define F367CAB_CTR_GTO 0xf4920080 +#define F367CAB_CTR_GDIR 0xf4920070 +#define F367CAB_SWEEP_EN 0xf4920008 +#define F367CAB_CTR_GINT 0xf4920007 + +/* EQU_CRL_LPF_GAIN */ +#define R367CAB_EQU_CRL_LPF_GAIN 0xf493 +#define F367CAB_CRL_GTO 0xf4930080 +#define F367CAB_CRL_GDIR 0xf4930070 +#define F367CAB_SWEEP_DIR 0xf4930008 +#define F367CAB_CRL_GINT 0xf4930007 + +/* EQU_GLOBAL_GAIN */ +#define R367CAB_EQU_GLOBAL_GAIN 0xf494 +#define F367CAB_CRL_GAIN 0xf49400f8 +#define F367CAB_CTR_INC_GAIN 0xf4940004 +#define F367CAB_CTR_FRAC 0xf4940003 + +/* EQU_CRL_LD_SEN */ +#define R367CAB_EQU_CRL_LD_SEN 0xf495 +#define F367CAB_CTR_BADPOINT_EN 0xf4950080 +#define F367CAB_CTR_GAIN 0xf4950070 +#define F367CAB_LIMANEN 0xf4950008 +#define F367CAB_CRL_LD_SEN 0xf4950007 + +/* EQU_CRL_LD_VAL */ +#define R367CAB_EQU_CRL_LD_VAL 0xf496 +#define F367CAB_CRL_BISTH_LIMIT 0xf4960080 +#define F367CAB_CARE_EN 0xf4960040 +#define F367CAB_CRL_LD_PER 0xf4960030 +#define F367CAB_CRL_LD_WST 0xf496000c +#define F367CAB_CRL_LD_TFS 0xf4960003 + +/* EQU_CRL_TFR */ +#define R367CAB_EQU_CRL_TFR 0xf497 +#define F367CAB_CRL_LD_TFR 0xf49700ff + +/* EQU_CRL_BISTH_LO */ +#define R367CAB_EQU_CRL_BISTH_LO 0xf498 +#define F367CAB_CRL_BISTH_LO 0xf49800ff + +/* EQU_CRL_BISTH_HI */ +#define R367CAB_EQU_CRL_BISTH_HI 0xf499 +#define F367CAB_CRL_BISTH_HI 0xf49900ff + +/* EQU_SWEEP_RANGE_LO */ +#define R367CAB_EQU_SWEEP_RANGE_LO 0xf49a +#define F367CAB_SWEEP_RANGE_LO 0xf49a00ff + +/* EQU_SWEEP_RANGE_HI */ +#define R367CAB_EQU_SWEEP_RANGE_HI 0xf49b +#define F367CAB_SWEEP_RANGE_HI 0xf49b00ff + +/* EQU_CRL_LIMITER */ +#define R367CAB_EQU_CRL_LIMITER 0xf49c +#define F367CAB_BISECTOR_EN 0xf49c0080 +#define F367CAB_PHEST128_EN 0xf49c0040 +#define F367CAB_CRL_LIM 0xf49c003f + +/* EQU_MODULUS_MAP */ +#define R367CAB_EQU_MODULUS_MAP 0xf49d +#define F367CAB_PNT_DEPTH 0xf49d00e0 +#define F367CAB_MODULUS_CMP 0xf49d001f + +/* EQU_PNT_GAIN */ +#define R367CAB_EQU_PNT_GAIN 0xf49e +#define F367CAB_PNT_EN 0xf49e0080 +#define F367CAB_MODULUSMAP_EN 0xf49e0040 +#define F367CAB_PNT_GAIN 0xf49e003f + +/* FEC_AC_CTR_0 */ +#define R367CAB_FEC_AC_CTR_0 0xf4a8 +#define F367CAB_BE_BYPASS 0xf4a80020 +#define F367CAB_REFRESH47 0xf4a80010 +#define F367CAB_CT_NBST 0xf4a80008 +#define F367CAB_TEI_ENA 0xf4a80004 +#define F367CAB_DS_ENA 0xf4a80002 +#define F367CAB_TSMF_EN 0xf4a80001 + +/* FEC_AC_CTR_1 */ +#define R367CAB_FEC_AC_CTR_1 0xf4a9 +#define F367CAB_DEINT_DEPTH 0xf4a900ff + +/* FEC_AC_CTR_2 */ +#define R367CAB_FEC_AC_CTR_2 0xf4aa +#define F367CAB_DEINT_M 0xf4aa00f8 +#define F367CAB_DIS_UNLOCK 0xf4aa0004 +#define F367CAB_DESCR_MODE 0xf4aa0003 + +/* FEC_AC_CTR_3 */ +#define R367CAB_FEC_AC_CTR_3 0xf4ab +#define F367CAB_DI_UNLOCK 0xf4ab0080 +#define F367CAB_DI_FREEZE 0xf4ab0040 +#define F367CAB_MISMATCH 0xf4ab0030 +#define F367CAB_ACQ_MODE 0xf4ab000c +#define F367CAB_TRK_MODE 0xf4ab0003 + +/* FEC_STATUS */ +#define R367CAB_FEC_STATUS 0xf4ac +#define F367CAB_DEINT_SMCNTR 0xf4ac00e0 +#define F367CAB_DEINT_SYNCSTATE 0xf4ac0018 +#define F367CAB_DEINT_SYNLOST 0xf4ac0004 +#define F367CAB_DESCR_SYNCSTATE 0xf4ac0002 + +/* RS_COUNTER_0 */ +#define R367CAB_RS_COUNTER_0 0xf4ae +#define F367CAB_BK_CT_L 0xf4ae00ff + +/* RS_COUNTER_1 */ +#define R367CAB_RS_COUNTER_1 0xf4af +#define F367CAB_BK_CT_H 0xf4af00ff + +/* RS_COUNTER_2 */ +#define R367CAB_RS_COUNTER_2 0xf4b0 +#define F367CAB_CORR_CT_L 0xf4b000ff + +/* RS_COUNTER_3 */ +#define R367CAB_RS_COUNTER_3 0xf4b1 +#define F367CAB_CORR_CT_H 0xf4b100ff + +/* RS_COUNTER_4 */ +#define R367CAB_RS_COUNTER_4 0xf4b2 +#define F367CAB_UNCORR_CT_L 0xf4b200ff + +/* RS_COUNTER_5 */ +#define R367CAB_RS_COUNTER_5 0xf4b3 +#define F367CAB_UNCORR_CT_H 0xf4b300ff + +/* BERT_0 */ +#define R367CAB_BERT_0 0xf4b4 +#define F367CAB_RS_NOCORR 0xf4b40004 +#define F367CAB_CT_HOLD 0xf4b40002 +#define F367CAB_CT_CLEAR 0xf4b40001 + +/* BERT_1 */ +#define R367CAB_BERT_1 0xf4b5 +#define F367CAB_BERT_ON 0xf4b50020 +#define F367CAB_BERT_ERR_SRC 0xf4b50010 +#define F367CAB_BERT_ERR_MODE 0xf4b50008 +#define F367CAB_BERT_NBYTE 0xf4b50007 + +/* BERT_2 */ +#define R367CAB_BERT_2 0xf4b6 +#define F367CAB_BERT_ERRCOUNT_L 0xf4b600ff + +/* BERT_3 */ +#define R367CAB_BERT_3 0xf4b7 +#define F367CAB_BERT_ERRCOUNT_H 0xf4b700ff + +/* OUTFORMAT_0 */ +#define R367CAB_OUTFORMAT_0 0xf4b8 +#define F367CAB_CLK_POLARITY 0xf4b80080 +#define F367CAB_FEC_TYPE 0xf4b80040 +#define F367CAB_SYNC_STRIP 0xf4b80008 +#define F367CAB_TS_SWAP 0xf4b80004 +#define F367CAB_OUTFORMAT 0xf4b80003 + +/* OUTFORMAT_1 */ +#define R367CAB_OUTFORMAT_1 0xf4b9 +#define F367CAB_CI_DIVRANGE 0xf4b900ff + +/* SMOOTHER_2 */ +#define R367CAB_SMOOTHER_2 0xf4be +#define F367CAB_FIFO_BYPASS 0xf4be0020 + +/* TSMF_CTRL_0 */ +#define R367CAB_TSMF_CTRL_0 0xf4c0 +#define F367CAB_TS_NUMBER 0xf4c0001e +#define F367CAB_SEL_MODE 0xf4c00001 + +/* TSMF_CTRL_1 */ +#define R367CAB_TSMF_CTRL_1 0xf4c1 +#define F367CAB_CHECK_ERROR_BIT 0xf4c10080 +#define F367CAB_CHCK_F_SYNC 0xf4c10040 +#define F367CAB_H_MODE 0xf4c10008 +#define F367CAB_D_V_MODE 0xf4c10004 +#define F367CAB_MODE 0xf4c10003 + +/* TSMF_CTRL_3 */ +#define R367CAB_TSMF_CTRL_3 0xf4c3 +#define F367CAB_SYNC_IN_COUNT 0xf4c300f0 +#define F367CAB_SYNC_OUT_COUNT 0xf4c3000f + +/* TS_ON_ID_0 */ +#define R367CAB_TS_ON_ID_0 0xf4c4 +#define F367CAB_TS_ID_L 0xf4c400ff + +/* TS_ON_ID_1 */ +#define R367CAB_TS_ON_ID_1 0xf4c5 +#define F367CAB_TS_ID_H 0xf4c500ff + +/* TS_ON_ID_2 */ +#define R367CAB_TS_ON_ID_2 0xf4c6 +#define F367CAB_ON_ID_L 0xf4c600ff + +/* TS_ON_ID_3 */ +#define R367CAB_TS_ON_ID_3 0xf4c7 +#define F367CAB_ON_ID_H 0xf4c700ff + +/* RE_STATUS_0 */ +#define R367CAB_RE_STATUS_0 0xf4c8 +#define F367CAB_RECEIVE_STATUS_L 0xf4c800ff + +/* RE_STATUS_1 */ +#define R367CAB_RE_STATUS_1 0xf4c9 +#define F367CAB_RECEIVE_STATUS_LH 0xf4c900ff + +/* RE_STATUS_2 */ +#define R367CAB_RE_STATUS_2 0xf4ca +#define F367CAB_RECEIVE_STATUS_HL 0xf4ca00ff + +/* RE_STATUS_3 */ +#define R367CAB_RE_STATUS_3 0xf4cb +#define F367CAB_RECEIVE_STATUS_HH 0xf4cb003f + +/* TS_STATUS_0 */ +#define R367CAB_TS_STATUS_0 0xf4cc +#define F367CAB_TS_STATUS_L 0xf4cc00ff + +/* TS_STATUS_1 */ +#define R367CAB_TS_STATUS_1 0xf4cd +#define F367CAB_TS_STATUS_H 0xf4cd007f + +/* TS_STATUS_2 */ +#define R367CAB_TS_STATUS_2 0xf4ce +#define F367CAB_ERROR 0xf4ce0080 +#define F367CAB_EMERGENCY 0xf4ce0040 +#define F367CAB_CRE_TS 0xf4ce0030 +#define F367CAB_VER 0xf4ce000e +#define F367CAB_M_LOCK 0xf4ce0001 + +/* TS_STATUS_3 */ +#define R367CAB_TS_STATUS_3 0xf4cf +#define F367CAB_UPDATE_READY 0xf4cf0080 +#define F367CAB_END_FRAME_HEADER 0xf4cf0040 +#define F367CAB_CONTCNT 0xf4cf0020 +#define F367CAB_TS_IDENTIFIER_SEL 0xf4cf000f + +/* T_O_ID_0 */ +#define R367CAB_T_O_ID_0 0xf4d0 +#define F367CAB_ON_ID_I_L 0xf4d000ff + +/* T_O_ID_1 */ +#define R367CAB_T_O_ID_1 0xf4d1 +#define F367CAB_ON_ID_I_H 0xf4d100ff + +/* T_O_ID_2 */ +#define R367CAB_T_O_ID_2 0xf4d2 +#define F367CAB_TS_ID_I_L 0xf4d200ff + +/* T_O_ID_3 */ +#define R367CAB_T_O_ID_3 0xf4d3 +#define F367CAB_TS_ID_I_H 0xf4d300ff + +#define STV0367CAB_NBREGS 187 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1986 @@ +/* + * stv0900_core.c + * + * Driver for ST STV0900 satellite demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "stv0900.h" +#include "stv0900_reg.h" +#include "stv0900_priv.h" +#include "stv0900_init.h" + +int stvdebug = 1; +module_param_named(debug, stvdebug, int, 0644); + +/* internal params node */ +struct stv0900_inode { + /* pointer for internal params, one for each pair of demods */ + struct stv0900_internal *internal; + struct stv0900_inode *next_inode; +}; + +/* first internal params */ +static struct stv0900_inode *stv0900_first_inode; + +/* find chip by i2c adapter and i2c address */ +static struct stv0900_inode *find_inode(struct i2c_adapter *i2c_adap, + u8 i2c_addr) +{ + struct stv0900_inode *temp_chip = stv0900_first_inode; + + if (temp_chip != NULL) { + /* + Search of the last stv0900 chip or + find it by i2c adapter and i2c address */ + while ((temp_chip != NULL) && + ((temp_chip->internal->i2c_adap != i2c_adap) || + (temp_chip->internal->i2c_addr != i2c_addr))) + + temp_chip = temp_chip->next_inode; + + } + + return temp_chip; +} + +/* deallocating chip */ +static void remove_inode(struct stv0900_internal *internal) +{ + struct stv0900_inode *prev_node = stv0900_first_inode; + struct stv0900_inode *del_node = find_inode(internal->i2c_adap, + internal->i2c_addr); + + if (del_node != NULL) { + if (del_node == stv0900_first_inode) { + stv0900_first_inode = del_node->next_inode; + } else { + while (prev_node->next_inode != del_node) + prev_node = prev_node->next_inode; + + if (del_node->next_inode == NULL) + prev_node->next_inode = NULL; + else + prev_node->next_inode = + prev_node->next_inode->next_inode; + } + + kfree(del_node); + } +} + +/* allocating new chip */ +static struct stv0900_inode *append_internal(struct stv0900_internal *internal) +{ + struct stv0900_inode *new_node = stv0900_first_inode; + + if (new_node == NULL) { + new_node = kmalloc(sizeof(struct stv0900_inode), GFP_KERNEL); + stv0900_first_inode = new_node; + } else { + while (new_node->next_inode != NULL) + new_node = new_node->next_inode; + + new_node->next_inode = kmalloc(sizeof(struct stv0900_inode), + GFP_KERNEL); + if (new_node->next_inode != NULL) + new_node = new_node->next_inode; + else + new_node = NULL; + } + + if (new_node != NULL) { + new_node->internal = internal; + new_node->next_inode = NULL; + } + + return new_node; +} + +s32 ge2comp(s32 a, s32 width) +{ + if (width == 32) + return a; + else + return (a >= (1 << (width - 1))) ? (a - (1 << width)) : a; +} + +void stv0900_write_reg(struct stv0900_internal *intp, u16 reg_addr, + u8 reg_data) +{ + u8 data[3]; + int ret; + struct i2c_msg i2cmsg = { + .addr = intp->i2c_addr, + .flags = 0, + .len = 3, + .buf = data, + }; + + data[0] = MSB(reg_addr); + data[1] = LSB(reg_addr); + data[2] = reg_data; + + ret = i2c_transfer(intp->i2c_adap, &i2cmsg, 1); + if (ret != 1) + dprintk("%s: i2c error %d\n", __func__, ret); +} + +u8 stv0900_read_reg(struct stv0900_internal *intp, u16 reg) +{ + int ret; + u8 b0[] = { MSB(reg), LSB(reg) }; + u8 buf = 0; + struct i2c_msg msg[] = { + { + .addr = intp->i2c_addr, + .flags = 0, + .buf = b0, + .len = 2, + }, { + .addr = intp->i2c_addr, + .flags = I2C_M_RD, + .buf = &buf, + .len = 1, + }, + }; + + ret = i2c_transfer(intp->i2c_adap, msg, 2); + if (ret != 2) + dprintk("%s: i2c error %d, reg[0x%02x]\n", + __func__, ret, reg); + + return buf; +} + +static void extract_mask_pos(u32 label, u8 *mask, u8 *pos) +{ + u8 position = 0, i = 0; + + (*mask) = label & 0xff; + + while ((position == 0) && (i < 8)) { + position = ((*mask) >> i) & 0x01; + i++; + } + + (*pos) = (i - 1); +} + +void stv0900_write_bits(struct stv0900_internal *intp, u32 label, u8 val) +{ + u8 reg, mask, pos; + + reg = stv0900_read_reg(intp, (label >> 16) & 0xffff); + extract_mask_pos(label, &mask, &pos); + + val = mask & (val << pos); + + reg = (reg & (~mask)) | val; + stv0900_write_reg(intp, (label >> 16) & 0xffff, reg); + +} + +u8 stv0900_get_bits(struct stv0900_internal *intp, u32 label) +{ + u8 val = 0xff; + u8 mask, pos; + + extract_mask_pos(label, &mask, &pos); + + val = stv0900_read_reg(intp, label >> 16); + val = (val & mask) >> pos; + + return val; +} + +static enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp) +{ + s32 i; + + if (intp == NULL) + return STV0900_INVALID_HANDLE; + + intp->chip_id = stv0900_read_reg(intp, R0900_MID); + + if (intp->errs != STV0900_NO_ERROR) + return intp->errs; + + /*Startup sequence*/ + stv0900_write_reg(intp, R0900_P1_DMDISTATE, 0x5c); + stv0900_write_reg(intp, R0900_P2_DMDISTATE, 0x5c); + msleep(3); + stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x6c); + stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x6f); + stv0900_write_reg(intp, R0900_P1_I2CRPT, 0x20); + stv0900_write_reg(intp, R0900_P2_I2CRPT, 0x20); + stv0900_write_reg(intp, R0900_NCOARSE, 0x13); + msleep(3); + stv0900_write_reg(intp, R0900_I2CCFG, 0x08); + + switch (intp->clkmode) { + case 0: + case 2: + stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 + | intp->clkmode); + break; + default: + /* preserve SELOSCI bit */ + i = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL); + stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | i); + break; + } + + msleep(3); + for (i = 0; i < 181; i++) + stv0900_write_reg(intp, STV0900_InitVal[i][0], + STV0900_InitVal[i][1]); + + if (stv0900_read_reg(intp, R0900_MID) >= 0x20) { + stv0900_write_reg(intp, R0900_TSGENERAL, 0x0c); + for (i = 0; i < 32; i++) + stv0900_write_reg(intp, STV0900_Cut20_AddOnVal[i][0], + STV0900_Cut20_AddOnVal[i][1]); + } + + stv0900_write_reg(intp, R0900_P1_FSPYCFG, 0x6c); + stv0900_write_reg(intp, R0900_P2_FSPYCFG, 0x6c); + + stv0900_write_reg(intp, R0900_P1_PDELCTRL2, 0x01); + stv0900_write_reg(intp, R0900_P2_PDELCTRL2, 0x21); + + stv0900_write_reg(intp, R0900_P1_PDELCTRL3, 0x20); + stv0900_write_reg(intp, R0900_P2_PDELCTRL3, 0x20); + + stv0900_write_reg(intp, R0900_TSTRES0, 0x80); + stv0900_write_reg(intp, R0900_TSTRES0, 0x00); + + return STV0900_NO_ERROR; +} + +static u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk) +{ + u32 mclk = 90000000, div = 0, ad_div = 0; + + div = stv0900_get_bits(intp, F0900_M_DIV); + ad_div = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6); + + mclk = (div + 1) * ext_clk / ad_div; + + dprintk("%s: Calculated Mclk = %d\n", __func__, mclk); + + return mclk; +} + +static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk) +{ + u32 m_div, clk_sel; + + dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk, + intp->quartz); + + if (intp == NULL) + return STV0900_INVALID_HANDLE; + + if (intp->errs) + return STV0900_I2C_ERROR; + + clk_sel = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6); + m_div = ((clk_sel * mclk) / intp->quartz) - 1; + stv0900_write_bits(intp, F0900_M_DIV, m_div); + intp->mclk = stv0900_get_mclk_freq(intp, + intp->quartz); + + /*Set the DiseqC frequency to 22KHz */ + /* + Formula: + DiseqC_TX_Freq= MasterClock/(32*F22TX_Reg) + DiseqC_RX_Freq= MasterClock/(32*F22RX_Reg) + */ + m_div = intp->mclk / 704000; + stv0900_write_reg(intp, R0900_P1_F22TX, m_div); + stv0900_write_reg(intp, R0900_P1_F22RX, m_div); + + stv0900_write_reg(intp, R0900_P2_F22TX, m_div); + stv0900_write_reg(intp, R0900_P2_F22RX, m_div); + + if ((intp->errs)) + return STV0900_I2C_ERROR; + + return STV0900_NO_ERROR; +} + +static u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr, + enum fe_stv0900_demod_num demod) +{ + u32 lsb, msb, hsb, err_val; + + switch (cntr) { + case 0: + default: + hsb = stv0900_get_bits(intp, ERR_CNT12); + msb = stv0900_get_bits(intp, ERR_CNT11); + lsb = stv0900_get_bits(intp, ERR_CNT10); + break; + case 1: + hsb = stv0900_get_bits(intp, ERR_CNT22); + msb = stv0900_get_bits(intp, ERR_CNT21); + lsb = stv0900_get_bits(intp, ERR_CNT20); + break; + } + + err_val = (hsb << 16) + (msb << 8) + (lsb); + + return err_val; +} + +static int stv0900_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + + stv0900_write_bits(intp, I2CT_ON, enable); + + return 0; +} + +static void stv0900_set_ts_parallel_serial(struct stv0900_internal *intp, + enum fe_stv0900_clock_type path1_ts, + enum fe_stv0900_clock_type path2_ts) +{ + + dprintk("%s\n", __func__); + + if (intp->chip_id >= 0x20) { + switch (path1_ts) { + case STV0900_PARALLEL_PUNCT_CLOCK: + case STV0900_DVBCI_CLOCK: + switch (path2_ts) { + case STV0900_SERIAL_PUNCT_CLOCK: + case STV0900_SERIAL_CONT_CLOCK: + default: + stv0900_write_reg(intp, R0900_TSGENERAL, + 0x00); + break; + case STV0900_PARALLEL_PUNCT_CLOCK: + case STV0900_DVBCI_CLOCK: + stv0900_write_reg(intp, R0900_TSGENERAL, + 0x06); + stv0900_write_bits(intp, + F0900_P1_TSFIFO_MANSPEED, 3); + stv0900_write_bits(intp, + F0900_P2_TSFIFO_MANSPEED, 0); + stv0900_write_reg(intp, + R0900_P1_TSSPEED, 0x14); + stv0900_write_reg(intp, + R0900_P2_TSSPEED, 0x28); + break; + } + break; + case STV0900_SERIAL_PUNCT_CLOCK: + case STV0900_SERIAL_CONT_CLOCK: + default: + switch (path2_ts) { + case STV0900_SERIAL_PUNCT_CLOCK: + case STV0900_SERIAL_CONT_CLOCK: + default: + stv0900_write_reg(intp, + R0900_TSGENERAL, 0x0C); + break; + case STV0900_PARALLEL_PUNCT_CLOCK: + case STV0900_DVBCI_CLOCK: + stv0900_write_reg(intp, + R0900_TSGENERAL, 0x0A); + dprintk("%s: 0x0a\n", __func__); + break; + } + break; + } + } else { + switch (path1_ts) { + case STV0900_PARALLEL_PUNCT_CLOCK: + case STV0900_DVBCI_CLOCK: + switch (path2_ts) { + case STV0900_SERIAL_PUNCT_CLOCK: + case STV0900_SERIAL_CONT_CLOCK: + default: + stv0900_write_reg(intp, R0900_TSGENERAL1X, + 0x10); + break; + case STV0900_PARALLEL_PUNCT_CLOCK: + case STV0900_DVBCI_CLOCK: + stv0900_write_reg(intp, R0900_TSGENERAL1X, + 0x16); + stv0900_write_bits(intp, + F0900_P1_TSFIFO_MANSPEED, 3); + stv0900_write_bits(intp, + F0900_P2_TSFIFO_MANSPEED, 0); + stv0900_write_reg(intp, R0900_P1_TSSPEED, + 0x14); + stv0900_write_reg(intp, R0900_P2_TSSPEED, + 0x28); + break; + } + + break; + case STV0900_SERIAL_PUNCT_CLOCK: + case STV0900_SERIAL_CONT_CLOCK: + default: + switch (path2_ts) { + case STV0900_SERIAL_PUNCT_CLOCK: + case STV0900_SERIAL_CONT_CLOCK: + default: + stv0900_write_reg(intp, R0900_TSGENERAL1X, + 0x14); + break; + case STV0900_PARALLEL_PUNCT_CLOCK: + case STV0900_DVBCI_CLOCK: + stv0900_write_reg(intp, R0900_TSGENERAL1X, + 0x12); + dprintk("%s: 0x12\n", __func__); + break; + } + + break; + } + } + + switch (path1_ts) { + case STV0900_PARALLEL_PUNCT_CLOCK: + stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00); + stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x00); + break; + case STV0900_DVBCI_CLOCK: + stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x00); + stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x01); + break; + case STV0900_SERIAL_PUNCT_CLOCK: + stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01); + stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x00); + break; + case STV0900_SERIAL_CONT_CLOCK: + stv0900_write_bits(intp, F0900_P1_TSFIFO_SERIAL, 0x01); + stv0900_write_bits(intp, F0900_P1_TSFIFO_DVBCI, 0x01); + break; + default: + break; + } + + switch (path2_ts) { + case STV0900_PARALLEL_PUNCT_CLOCK: + stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00); + stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x00); + break; + case STV0900_DVBCI_CLOCK: + stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x00); + stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x01); + break; + case STV0900_SERIAL_PUNCT_CLOCK: + stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01); + stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x00); + break; + case STV0900_SERIAL_CONT_CLOCK: + stv0900_write_bits(intp, F0900_P2_TSFIFO_SERIAL, 0x01); + stv0900_write_bits(intp, F0900_P2_TSFIFO_DVBCI, 0x01); + break; + default: + break; + } + + stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1); + stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0); + stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1); + stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0); +} + +void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency, + u32 bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + + if (&fe->ops) + frontend_ops = &fe->ops; + + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + + if (tuner_ops->set_frequency) { + if ((tuner_ops->set_frequency(fe, frequency)) < 0) + dprintk("%s: Invalid parameter\n", __func__); + else + dprintk("%s: Frequency=%d\n", __func__, frequency); + + } + + if (tuner_ops->set_bandwidth) { + if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0) + dprintk("%s: Invalid parameter\n", __func__); + else + dprintk("%s: Bandwidth=%d\n", __func__, bandwidth); + + } +} + +void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + + if (&fe->ops) + frontend_ops = &fe->ops; + + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + + if (tuner_ops->set_bandwidth) { + if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0) + dprintk("%s: Invalid parameter\n", __func__); + else + dprintk("%s: Bandwidth=%d\n", __func__, bandwidth); + + } +} + +u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod) +{ + u32 freq, round; + /* Formulat : + Tuner_Frequency(MHz) = Regs / 64 + Tuner_granularity(MHz) = Regs / 2048 + real_Tuner_Frequency = Tuner_Frequency(MHz) - Tuner_granularity(MHz) + */ + freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) + + (stv0900_get_bits(intp, TUN_RFFREQ1) << 2) + + stv0900_get_bits(intp, TUN_RFFREQ0); + + freq = (freq * 1000) / 64; + + round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) + + stv0900_get_bits(intp, TUN_RFRESTE0); + + round = (round * 1000) / 2048; + + return freq + round; +} + +void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency, + u32 Bandwidth, int demod) +{ + u32 tunerFrequency; + /* Formulat: + Tuner_frequency_reg= Frequency(MHz)*64 + */ + tunerFrequency = (Frequency * 64) / 1000; + + stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10)); + stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff); + stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03)); + /* Low Pass Filter = BW /2 (MHz)*/ + stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000); + /* Tuner Write trig */ + stv0900_write_reg(intp, TNRLD, 1); +} + +static s32 stv0900_get_rf_level(struct stv0900_internal *intp, + const struct stv0900_table *lookup, + enum fe_stv0900_demod_num demod) +{ + s32 agc_gain = 0, + imin, + imax, + i, + rf_lvl = 0; + + dprintk("%s\n", __func__); + + if ((lookup == NULL) || (lookup->size <= 0)) + return 0; + + agc_gain = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1), + stv0900_get_bits(intp, AGCIQ_VALUE0)); + + imin = 0; + imax = lookup->size - 1; + if (INRANGE(lookup->table[imin].regval, agc_gain, + lookup->table[imax].regval)) { + while ((imax - imin) > 1) { + i = (imax + imin) >> 1; + + if (INRANGE(lookup->table[imin].regval, + agc_gain, + lookup->table[i].regval)) + imax = i; + else + imin = i; + } + + rf_lvl = (s32)agc_gain - lookup->table[imin].regval; + rf_lvl *= (lookup->table[imax].realval - + lookup->table[imin].realval); + rf_lvl /= (lookup->table[imax].regval - + lookup->table[imin].regval); + rf_lvl += lookup->table[imin].realval; + } else if (agc_gain > lookup->table[0].regval) + rf_lvl = 5; + else if (agc_gain < lookup->table[lookup->size-1].regval) + rf_lvl = -100; + + dprintk("%s: RFLevel = %d\n", __func__, rf_lvl); + + return rf_lvl; +} + +static int stv0900_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *internal = state->internal; + s32 rflevel = stv0900_get_rf_level(internal, &stv0900_rf, + state->demod); + + rflevel = (rflevel + 100) * (65535 / 70); + if (rflevel < 0) + rflevel = 0; + + if (rflevel > 65535) + rflevel = 65535; + + *strength = rflevel; + + return 0; +} + +static s32 stv0900_carr_get_quality(struct dvb_frontend *fe, + const struct stv0900_table *lookup) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + + s32 c_n = -100, + regval, + imin, + imax, + i, + noise_field1, + noise_field0; + + dprintk("%s\n", __func__); + + if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) { + noise_field1 = NOSPLHT_NORMED1; + noise_field0 = NOSPLHT_NORMED0; + } else { + noise_field1 = NOSDATAT_NORMED1; + noise_field0 = NOSDATAT_NORMED0; + } + + if (stv0900_get_bits(intp, LOCK_DEFINITIF)) { + if ((lookup != NULL) && lookup->size) { + regval = 0; + msleep(5); + for (i = 0; i < 16; i++) { + regval += MAKEWORD(stv0900_get_bits(intp, + noise_field1), + stv0900_get_bits(intp, + noise_field0)); + msleep(1); + } + + regval /= 16; + imin = 0; + imax = lookup->size - 1; + if (INRANGE(lookup->table[imin].regval, + regval, + lookup->table[imax].regval)) { + while ((imax - imin) > 1) { + i = (imax + imin) >> 1; + if (INRANGE(lookup->table[imin].regval, + regval, + lookup->table[i].regval)) + imax = i; + else + imin = i; + } + + c_n = ((regval - lookup->table[imin].regval) + * (lookup->table[imax].realval + - lookup->table[imin].realval) + / (lookup->table[imax].regval + - lookup->table[imin].regval)) + + lookup->table[imin].realval; + } else if (regval < lookup->table[imin].regval) + c_n = 1000; + } + } + + return c_n; +} + +static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + u8 err_val1, err_val0; + u32 header_err_val = 0; + + *ucblocks = 0x0; + if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) { + /* DVB-S2 delineator errors count */ + + /* retreiving number for errnous headers */ + err_val1 = stv0900_read_reg(intp, BBFCRCKO1); + err_val0 = stv0900_read_reg(intp, BBFCRCKO0); + header_err_val = (err_val1 << 8) | err_val0; + + /* retreiving number for errnous packets */ + err_val1 = stv0900_read_reg(intp, UPCRCKO1); + err_val0 = stv0900_read_reg(intp, UPCRCKO0); + *ucblocks = (err_val1 << 8) | err_val0; + *ucblocks += header_err_val; + } + + return 0; +} + +static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + s32 snrlcl = stv0900_carr_get_quality(fe, + (const struct stv0900_table *)&stv0900_s2_cn); + snrlcl = (snrlcl + 30) * 384; + if (snrlcl < 0) + snrlcl = 0; + + if (snrlcl > 65535) + snrlcl = 65535; + + *snr = snrlcl; + + return 0; +} + +static u32 stv0900_get_ber(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + u32 ber = 10000000, i; + s32 demod_state; + + demod_state = stv0900_get_bits(intp, HEADER_MODE); + + switch (demod_state) { + case STV0900_SEARCH: + case STV0900_PLH_DETECTED: + default: + ber = 10000000; + break; + case STV0900_DVBS_FOUND: + ber = 0; + for (i = 0; i < 5; i++) { + msleep(5); + ber += stv0900_get_err_count(intp, 0, demod); + } + + ber /= 5; + if (stv0900_get_bits(intp, PRFVIT)) { + ber *= 9766; + ber = ber >> 13; + } + + break; + case STV0900_DVBS2_FOUND: + ber = 0; + for (i = 0; i < 5; i++) { + msleep(5); + ber += stv0900_get_err_count(intp, 0, demod); + } + + ber /= 5; + if (stv0900_get_bits(intp, PKTDELIN_LOCK)) { + ber *= 9766; + ber = ber >> 13; + } + + break; + } + + return ber; +} + +static int stv0900_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *internal = state->internal; + + *ber = stv0900_get_ber(internal, state->demod); + + return 0; +} + +int stv0900_get_demod_lock(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod, s32 time_out) +{ + s32 timer = 0, + lock = 0; + + enum fe_stv0900_search_state dmd_state; + + while ((timer < time_out) && (lock == 0)) { + dmd_state = stv0900_get_bits(intp, HEADER_MODE); + dprintk("Demod State = %d\n", dmd_state); + switch (dmd_state) { + case STV0900_SEARCH: + case STV0900_PLH_DETECTED: + default: + lock = 0; + break; + case STV0900_DVBS2_FOUND: + case STV0900_DVBS_FOUND: + lock = stv0900_get_bits(intp, LOCK_DEFINITIF); + break; + } + + if (lock == 0) + msleep(10); + + timer += 10; + } + + if (lock) + dprintk("DEMOD LOCK OK\n"); + else + dprintk("DEMOD LOCK FAIL\n"); + + return lock; +} + +void stv0900_stop_all_s2_modcod(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + s32 regflist, + i; + + dprintk("%s\n", __func__); + + regflist = MODCODLST0; + + for (i = 0; i < 16; i++) + stv0900_write_reg(intp, regflist + i, 0xff); +} + +void stv0900_activate_s2_modcod(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + u32 matype, + mod_code, + fmod, + reg_index, + field_index; + + dprintk("%s\n", __func__); + + if (intp->chip_id <= 0x11) { + msleep(5); + + mod_code = stv0900_read_reg(intp, PLHMODCOD); + matype = mod_code & 0x3; + mod_code = (mod_code & 0x7f) >> 2; + + reg_index = MODCODLSTF - mod_code / 2; + field_index = mod_code % 2; + + switch (matype) { + case 0: + default: + fmod = 14; + break; + case 1: + fmod = 13; + break; + case 2: + fmod = 11; + break; + case 3: + fmod = 7; + break; + } + + if ((INRANGE(STV0900_QPSK_12, mod_code, STV0900_8PSK_910)) + && (matype <= 1)) { + if (field_index == 0) + stv0900_write_reg(intp, reg_index, + 0xf0 | fmod); + else + stv0900_write_reg(intp, reg_index, + (fmod << 4) | 0xf); + } + + } else if (intp->chip_id >= 0x12) { + for (reg_index = 0; reg_index < 7; reg_index++) + stv0900_write_reg(intp, MODCODLST0 + reg_index, 0xff); + + stv0900_write_reg(intp, MODCODLSTE, 0xff); + stv0900_write_reg(intp, MODCODLSTF, 0xcf); + for (reg_index = 0; reg_index < 8; reg_index++) + stv0900_write_reg(intp, MODCODLST7 + reg_index, 0xcc); + + + } +} + +void stv0900_activate_s2_modcod_single(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + u32 reg_index; + + dprintk("%s\n", __func__); + + stv0900_write_reg(intp, MODCODLST0, 0xff); + stv0900_write_reg(intp, MODCODLST1, 0xf0); + stv0900_write_reg(intp, MODCODLSTF, 0x0f); + for (reg_index = 0; reg_index < 13; reg_index++) + stv0900_write_reg(intp, MODCODLST2 + reg_index, 0); + +} + +static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static int stb0900_set_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + dprintk("%s(..)\n", __func__); + + return 0; +} + +static int stb0900_get_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + dprintk("%s(..)\n", __func__); + + return 0; +} + +void stv0900_start_search(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + u32 freq; + s16 freq_s16 ; + + stv0900_write_bits(intp, DEMOD_MODE, 0x1f); + if (intp->chip_id == 0x10) + stv0900_write_reg(intp, CORRELEXP, 0xaa); + + if (intp->chip_id < 0x20) + stv0900_write_reg(intp, CARHDR, 0x55); + + if (intp->chip_id <= 0x20) { + if (intp->symbol_rate[0] <= 5000000) { + stv0900_write_reg(intp, CARCFG, 0x44); + stv0900_write_reg(intp, CFRUP1, 0x0f); + stv0900_write_reg(intp, CFRUP0, 0xff); + stv0900_write_reg(intp, CFRLOW1, 0xf0); + stv0900_write_reg(intp, CFRLOW0, 0x00); + stv0900_write_reg(intp, RTCS2, 0x68); + } else { + stv0900_write_reg(intp, CARCFG, 0xc4); + stv0900_write_reg(intp, RTCS2, 0x44); + } + + } else { /*cut 3.0 above*/ + if (intp->symbol_rate[demod] <= 5000000) + stv0900_write_reg(intp, RTCS2, 0x68); + else + stv0900_write_reg(intp, RTCS2, 0x44); + + stv0900_write_reg(intp, CARCFG, 0x46); + if (intp->srch_algo[demod] == STV0900_WARM_START) { + freq = 1000 << 16; + freq /= (intp->mclk / 1000); + freq_s16 = (s16)freq; + } else { + freq = (intp->srch_range[demod] / 2000); + if (intp->symbol_rate[demod] <= 5000000) + freq += 80; + else + freq += 600; + + freq = freq << 16; + freq /= (intp->mclk / 1000); + freq_s16 = (s16)freq; + } + + stv0900_write_bits(intp, CFR_UP1, MSB(freq_s16)); + stv0900_write_bits(intp, CFR_UP0, LSB(freq_s16)); + freq_s16 *= (-1); + stv0900_write_bits(intp, CFR_LOW1, MSB(freq_s16)); + stv0900_write_bits(intp, CFR_LOW0, LSB(freq_s16)); + } + + stv0900_write_reg(intp, CFRINIT1, 0); + stv0900_write_reg(intp, CFRINIT0, 0); + + if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, EQUALCFG, 0x41); + stv0900_write_reg(intp, FFECFG, 0x41); + + if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) || + (intp->srch_standard[demod] == STV0900_SEARCH_DSS) || + (intp->srch_standard[demod] == STV0900_AUTO_SEARCH)) { + stv0900_write_reg(intp, VITSCALE, + 0x82); + stv0900_write_reg(intp, VAVSRVIT, 0x0); + } + } + + stv0900_write_reg(intp, SFRSTEP, 0x00); + stv0900_write_reg(intp, TMGTHRISE, 0xe0); + stv0900_write_reg(intp, TMGTHFALL, 0xc0); + stv0900_write_bits(intp, SCAN_ENABLE, 0); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + stv0900_write_bits(intp, S1S2_SEQUENTIAL, 0); + stv0900_write_reg(intp, RTC, 0x88); + if (intp->chip_id >= 0x20) { + if (intp->symbol_rate[demod] < 2000000) { + if (intp->chip_id <= 0x20) + stv0900_write_reg(intp, CARFREQ, 0x39); + else /*cut 3.0*/ + stv0900_write_reg(intp, CARFREQ, 0x89); + + stv0900_write_reg(intp, CARHDR, 0x40); + } else if (intp->symbol_rate[demod] < 10000000) { + stv0900_write_reg(intp, CARFREQ, 0x4c); + stv0900_write_reg(intp, CARHDR, 0x20); + } else { + stv0900_write_reg(intp, CARFREQ, 0x4b); + stv0900_write_reg(intp, CARHDR, 0x20); + } + + } else { + if (intp->symbol_rate[demod] < 10000000) + stv0900_write_reg(intp, CARFREQ, 0xef); + else + stv0900_write_reg(intp, CARFREQ, 0xed); + } + + switch (intp->srch_algo[demod]) { + case STV0900_WARM_START: + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, DMDISTATE, 0x18); + break; + case STV0900_COLD_START: + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, DMDISTATE, 0x15); + break; + default: + break; + } +} + +u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode, + s32 pilot, u8 chip_id) +{ + u8 aclc_value = 0x29; + s32 i; + const struct stv0900_car_loop_optim *cls2, *cllqs2, *cllas2; + + dprintk("%s\n", __func__); + + if (chip_id <= 0x12) { + cls2 = FE_STV0900_S2CarLoop; + cllqs2 = FE_STV0900_S2LowQPCarLoopCut30; + cllas2 = FE_STV0900_S2APSKCarLoopCut30; + } else if (chip_id == 0x20) { + cls2 = FE_STV0900_S2CarLoopCut20; + cllqs2 = FE_STV0900_S2LowQPCarLoopCut20; + cllas2 = FE_STV0900_S2APSKCarLoopCut20; + } else { + cls2 = FE_STV0900_S2CarLoopCut30; + cllqs2 = FE_STV0900_S2LowQPCarLoopCut30; + cllas2 = FE_STV0900_S2APSKCarLoopCut30; + } + + if (modcode < STV0900_QPSK_12) { + i = 0; + while ((i < 3) && (modcode != cllqs2[i].modcode)) + i++; + + if (i >= 3) + i = 2; + } else { + i = 0; + while ((i < 14) && (modcode != cls2[i].modcode)) + i++; + + if (i >= 14) { + i = 0; + while ((i < 11) && (modcode != cllas2[i].modcode)) + i++; + + if (i >= 11) + i = 10; + } + } + + if (modcode <= STV0900_QPSK_25) { + if (pilot) { + if (srate <= 3000000) + aclc_value = cllqs2[i].car_loop_pilots_on_2; + else if (srate <= 7000000) + aclc_value = cllqs2[i].car_loop_pilots_on_5; + else if (srate <= 15000000) + aclc_value = cllqs2[i].car_loop_pilots_on_10; + else if (srate <= 25000000) + aclc_value = cllqs2[i].car_loop_pilots_on_20; + else + aclc_value = cllqs2[i].car_loop_pilots_on_30; + } else { + if (srate <= 3000000) + aclc_value = cllqs2[i].car_loop_pilots_off_2; + else if (srate <= 7000000) + aclc_value = cllqs2[i].car_loop_pilots_off_5; + else if (srate <= 15000000) + aclc_value = cllqs2[i].car_loop_pilots_off_10; + else if (srate <= 25000000) + aclc_value = cllqs2[i].car_loop_pilots_off_20; + else + aclc_value = cllqs2[i].car_loop_pilots_off_30; + } + + } else if (modcode <= STV0900_8PSK_910) { + if (pilot) { + if (srate <= 3000000) + aclc_value = cls2[i].car_loop_pilots_on_2; + else if (srate <= 7000000) + aclc_value = cls2[i].car_loop_pilots_on_5; + else if (srate <= 15000000) + aclc_value = cls2[i].car_loop_pilots_on_10; + else if (srate <= 25000000) + aclc_value = cls2[i].car_loop_pilots_on_20; + else + aclc_value = cls2[i].car_loop_pilots_on_30; + } else { + if (srate <= 3000000) + aclc_value = cls2[i].car_loop_pilots_off_2; + else if (srate <= 7000000) + aclc_value = cls2[i].car_loop_pilots_off_5; + else if (srate <= 15000000) + aclc_value = cls2[i].car_loop_pilots_off_10; + else if (srate <= 25000000) + aclc_value = cls2[i].car_loop_pilots_off_20; + else + aclc_value = cls2[i].car_loop_pilots_off_30; + } + + } else { + if (srate <= 3000000) + aclc_value = cllas2[i].car_loop_pilots_on_2; + else if (srate <= 7000000) + aclc_value = cllas2[i].car_loop_pilots_on_5; + else if (srate <= 15000000) + aclc_value = cllas2[i].car_loop_pilots_on_10; + else if (srate <= 25000000) + aclc_value = cllas2[i].car_loop_pilots_on_20; + else + aclc_value = cllas2[i].car_loop_pilots_on_30; + } + + return aclc_value; +} + +u8 stv0900_get_optim_short_carr_loop(s32 srate, + enum fe_stv0900_modulation modulation, + u8 chip_id) +{ + const struct stv0900_short_frames_car_loop_optim *s2scl; + const struct stv0900_short_frames_car_loop_optim_vs_mod *s2sclc30; + s32 mod_index = 0; + u8 aclc_value = 0x0b; + + dprintk("%s\n", __func__); + + s2scl = FE_STV0900_S2ShortCarLoop; + s2sclc30 = FE_STV0900_S2ShortCarLoopCut30; + + switch (modulation) { + case STV0900_QPSK: + default: + mod_index = 0; + break; + case STV0900_8PSK: + mod_index = 1; + break; + case STV0900_16APSK: + mod_index = 2; + break; + case STV0900_32APSK: + mod_index = 3; + break; + } + + if (chip_id >= 0x30) { + if (srate <= 3000000) + aclc_value = s2sclc30[mod_index].car_loop_2; + else if (srate <= 7000000) + aclc_value = s2sclc30[mod_index].car_loop_5; + else if (srate <= 15000000) + aclc_value = s2sclc30[mod_index].car_loop_10; + else if (srate <= 25000000) + aclc_value = s2sclc30[mod_index].car_loop_20; + else + aclc_value = s2sclc30[mod_index].car_loop_30; + + } else if (chip_id >= 0x20) { + if (srate <= 3000000) + aclc_value = s2scl[mod_index].car_loop_cut20_2; + else if (srate <= 7000000) + aclc_value = s2scl[mod_index].car_loop_cut20_5; + else if (srate <= 15000000) + aclc_value = s2scl[mod_index].car_loop_cut20_10; + else if (srate <= 25000000) + aclc_value = s2scl[mod_index].car_loop_cut20_20; + else + aclc_value = s2scl[mod_index].car_loop_cut20_30; + + } else { + if (srate <= 3000000) + aclc_value = s2scl[mod_index].car_loop_cut12_2; + else if (srate <= 7000000) + aclc_value = s2scl[mod_index].car_loop_cut12_5; + else if (srate <= 15000000) + aclc_value = s2scl[mod_index].car_loop_cut12_10; + else if (srate <= 25000000) + aclc_value = s2scl[mod_index].car_loop_cut12_20; + else + aclc_value = s2scl[mod_index].car_loop_cut12_30; + + } + + return aclc_value; +} + +static +enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp, + enum fe_stv0900_demod_mode LDPC_Mode, + enum fe_stv0900_demod_num demod) +{ + enum fe_stv0900_error error = STV0900_NO_ERROR; + s32 reg_ind; + + dprintk("%s\n", __func__); + + switch (LDPC_Mode) { + case STV0900_DUAL: + default: + if ((intp->demod_mode != STV0900_DUAL) + || (stv0900_get_bits(intp, F0900_DDEMOD) != 1)) { + stv0900_write_reg(intp, R0900_GENCFG, 0x1d); + + intp->demod_mode = STV0900_DUAL; + + stv0900_write_bits(intp, F0900_FRESFEC, 1); + stv0900_write_bits(intp, F0900_FRESFEC, 0); + + for (reg_ind = 0; reg_ind < 7; reg_ind++) + stv0900_write_reg(intp, + R0900_P1_MODCODLST0 + reg_ind, + 0xff); + for (reg_ind = 0; reg_ind < 8; reg_ind++) + stv0900_write_reg(intp, + R0900_P1_MODCODLST7 + reg_ind, + 0xcc); + + stv0900_write_reg(intp, R0900_P1_MODCODLSTE, 0xff); + stv0900_write_reg(intp, R0900_P1_MODCODLSTF, 0xcf); + + for (reg_ind = 0; reg_ind < 7; reg_ind++) + stv0900_write_reg(intp, + R0900_P2_MODCODLST0 + reg_ind, + 0xff); + for (reg_ind = 0; reg_ind < 8; reg_ind++) + stv0900_write_reg(intp, + R0900_P2_MODCODLST7 + reg_ind, + 0xcc); + + stv0900_write_reg(intp, R0900_P2_MODCODLSTE, 0xff); + stv0900_write_reg(intp, R0900_P2_MODCODLSTF, 0xcf); + } + + break; + case STV0900_SINGLE: + if (demod == STV0900_DEMOD_2) { + stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_1); + stv0900_activate_s2_modcod_single(intp, + STV0900_DEMOD_2); + stv0900_write_reg(intp, R0900_GENCFG, 0x06); + } else { + stv0900_stop_all_s2_modcod(intp, STV0900_DEMOD_2); + stv0900_activate_s2_modcod_single(intp, + STV0900_DEMOD_1); + stv0900_write_reg(intp, R0900_GENCFG, 0x04); + } + + intp->demod_mode = STV0900_SINGLE; + + stv0900_write_bits(intp, F0900_FRESFEC, 1); + stv0900_write_bits(intp, F0900_FRESFEC, 0); + stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 1); + stv0900_write_bits(intp, F0900_P1_ALGOSWRST, 0); + stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 1); + stv0900_write_bits(intp, F0900_P2_ALGOSWRST, 0); + break; + } + + return error; +} + +static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, + struct stv0900_init_params *p_init) +{ + struct stv0900_state *state = fe->demodulator_priv; + enum fe_stv0900_error error = STV0900_NO_ERROR; + enum fe_stv0900_error demodError = STV0900_NO_ERROR; + struct stv0900_internal *intp = NULL; + int selosci, i; + + struct stv0900_inode *temp_int = find_inode(state->i2c_adap, + state->config->demod_address); + + dprintk("%s\n", __func__); + + if ((temp_int != NULL) && (p_init->demod_mode == STV0900_DUAL)) { + state->internal = temp_int->internal; + (state->internal->dmds_used)++; + dprintk("%s: Find Internal Structure!\n", __func__); + return STV0900_NO_ERROR; + } else { + state->internal = kmalloc(sizeof(struct stv0900_internal), + GFP_KERNEL); + if (state->internal == NULL) + return STV0900_INVALID_HANDLE; + temp_int = append_internal(state->internal); + if (temp_int == NULL) { + kfree(state->internal); + state->internal = NULL; + return STV0900_INVALID_HANDLE; + } + state->internal->dmds_used = 1; + state->internal->i2c_adap = state->i2c_adap; + state->internal->i2c_addr = state->config->demod_address; + state->internal->clkmode = state->config->clkmode; + state->internal->errs = STV0900_NO_ERROR; + dprintk("%s: Create New Internal Structure!\n", __func__); + } + + if (state->internal == NULL) { + error = STV0900_INVALID_HANDLE; + return error; + } + + demodError = stv0900_initialize(state->internal); + if (demodError == STV0900_NO_ERROR) { + error = STV0900_NO_ERROR; + } else { + if (demodError == STV0900_INVALID_HANDLE) + error = STV0900_INVALID_HANDLE; + else + error = STV0900_I2C_ERROR; + + return error; + } + + intp = state->internal; + + intp->demod_mode = p_init->demod_mode; + stv0900_st_dvbs2_single(intp, intp->demod_mode, STV0900_DEMOD_1); + intp->chip_id = stv0900_read_reg(intp, R0900_MID); + intp->rolloff = p_init->rolloff; + intp->quartz = p_init->dmd_ref_clk; + + stv0900_write_bits(intp, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff); + stv0900_write_bits(intp, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff); + + intp->ts_config = p_init->ts_config; + if (intp->ts_config == NULL) + stv0900_set_ts_parallel_serial(intp, + p_init->path1_ts_clock, + p_init->path2_ts_clock); + else { + for (i = 0; intp->ts_config[i].addr != 0xffff; i++) + stv0900_write_reg(intp, + intp->ts_config[i].addr, + intp->ts_config[i].val); + + stv0900_write_bits(intp, F0900_P2_RST_HWARE, 1); + stv0900_write_bits(intp, F0900_P2_RST_HWARE, 0); + stv0900_write_bits(intp, F0900_P1_RST_HWARE, 1); + stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0); + } + + intp->tuner_type[0] = p_init->tuner1_type; + intp->tuner_type[1] = p_init->tuner2_type; + /* tuner init */ + switch (p_init->tuner1_type) { + case 3: /*FE_AUTO_STB6100:*/ + stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c); + stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86); + stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18); + stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */ + stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05); + stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17); + stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f); + stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0); + stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3); + break; + /* case FE_SW_TUNER: */ + default: + stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6); + break; + } + + stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress); + switch (p_init->tuner1_adc) { + case 1: + stv0900_write_reg(intp, R0900_TSTTNR1, 0x26); + break; + default: + break; + } + + stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */ + + /* tuner init */ + switch (p_init->tuner2_type) { + case 3: /*FE_AUTO_STB6100:*/ + stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c); + stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86); + stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18); + stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */ + stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05); + stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17); + stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f); + stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0); + stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3); + break; + /* case FE_SW_TUNER: */ + default: + stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6); + break; + } + + stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress); + switch (p_init->tuner2_adc) { + case 1: + stv0900_write_reg(intp, R0900_TSTTNR3, 0x26); + break; + default: + break; + } + + stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */ + + stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv); + stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv); + stv0900_set_mclk(intp, 135000000); + msleep(3); + + switch (intp->clkmode) { + case 0: + case 2: + stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | intp->clkmode); + break; + default: + selosci = 0x02 & stv0900_read_reg(intp, R0900_SYNTCTRL); + stv0900_write_reg(intp, R0900_SYNTCTRL, 0x20 | selosci); + break; + } + msleep(3); + + intp->mclk = stv0900_get_mclk_freq(intp, intp->quartz); + if (intp->errs) + error = STV0900_I2C_ERROR; + + return error; +} + +static int stv0900_status(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + enum fe_stv0900_search_state demod_state; + int locked = FALSE; + u8 tsbitrate0_val, tsbitrate1_val; + s32 bitrate; + + demod_state = stv0900_get_bits(intp, HEADER_MODE); + switch (demod_state) { + case STV0900_SEARCH: + case STV0900_PLH_DETECTED: + default: + locked = FALSE; + break; + case STV0900_DVBS2_FOUND: + locked = stv0900_get_bits(intp, LOCK_DEFINITIF) && + stv0900_get_bits(intp, PKTDELIN_LOCK) && + stv0900_get_bits(intp, TSFIFO_LINEOK); + break; + case STV0900_DVBS_FOUND: + locked = stv0900_get_bits(intp, LOCK_DEFINITIF) && + stv0900_get_bits(intp, LOCKEDVIT) && + stv0900_get_bits(intp, TSFIFO_LINEOK); + break; + } + + dprintk("%s: locked = %d\n", __func__, locked); + + if (stvdebug) { + /* Print TS bitrate */ + tsbitrate0_val = stv0900_read_reg(intp, TSBITRATE0); + tsbitrate1_val = stv0900_read_reg(intp, TSBITRATE1); + /* Formula Bit rate = Mclk * px_tsfifo_bitrate / 16384 */ + bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000) + * (tsbitrate1_val << 8 | tsbitrate0_val); + bitrate /= 16384; + dprintk("TS bitrate = %d Mbit/sec \n", bitrate); + }; + + return locked; +} + +static enum dvbfe_search stv0900_search(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + struct stv0900_search_params p_search; + struct stv0900_signal_info p_result = intp->result[demod]; + + enum fe_stv0900_error error = STV0900_NO_ERROR; + + dprintk("%s: ", __func__); + + if (!(INRANGE(100000, c->symbol_rate, 70000000))) + return DVBFE_ALGO_SEARCH_FAILED; + + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + p_result.locked = FALSE; + p_search.path = demod; + p_search.frequency = c->frequency; + p_search.symbol_rate = c->symbol_rate; + p_search.search_range = 10000000; + p_search.fec = STV0900_FEC_UNKNOWN; + p_search.standard = STV0900_AUTO_SEARCH; + p_search.iq_inversion = STV0900_IQ_AUTO; + p_search.search_algo = STV0900_BLIND_SEARCH; + /* Speeds up DVB-S searching */ + if (c->delivery_system == SYS_DVBS) + p_search.standard = STV0900_SEARCH_DVBS1; + + intp->srch_standard[demod] = p_search.standard; + intp->symbol_rate[demod] = p_search.symbol_rate; + intp->srch_range[demod] = p_search.search_range; + intp->freq[demod] = p_search.frequency; + intp->srch_algo[demod] = p_search.search_algo; + intp->srch_iq_inv[demod] = p_search.iq_inversion; + intp->fec[demod] = p_search.fec; + if ((stv0900_algo(fe) == STV0900_RANGEOK) && + (intp->errs == STV0900_NO_ERROR)) { + p_result.locked = intp->result[demod].locked; + p_result.standard = intp->result[demod].standard; + p_result.frequency = intp->result[demod].frequency; + p_result.symbol_rate = intp->result[demod].symbol_rate; + p_result.fec = intp->result[demod].fec; + p_result.modcode = intp->result[demod].modcode; + p_result.pilot = intp->result[demod].pilot; + p_result.frame_len = intp->result[demod].frame_len; + p_result.spectrum = intp->result[demod].spectrum; + p_result.rolloff = intp->result[demod].rolloff; + p_result.modulation = intp->result[demod].modulation; + } else { + p_result.locked = FALSE; + switch (intp->err[demod]) { + case STV0900_I2C_ERROR: + error = STV0900_I2C_ERROR; + break; + case STV0900_NO_ERROR: + default: + error = STV0900_SEARCH_FAILED; + break; + } + } + + if ((p_result.locked == TRUE) && (error == STV0900_NO_ERROR)) { + dprintk("Search Success\n"); + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + dprintk("Search Fail\n"); + return DVBFE_ALGO_SEARCH_FAILED; + } + +} + +static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status) +{ + struct stv0900_state *state = fe->demodulator_priv; + + dprintk("%s: ", __func__); + + if ((stv0900_status(state->internal, state->demod)) == TRUE) { + dprintk("DEMOD LOCK OK\n"); + *status = FE_HAS_CARRIER + | FE_HAS_VITERBI + | FE_HAS_SYNC + | FE_HAS_LOCK; + if (state->config->set_lock_led) + state->config->set_lock_led(fe, 1); + } else { + *status = 0; + if (state->config->set_lock_led) + state->config->set_lock_led(fe, 0); + dprintk("DEMOD LOCK FAIL\n"); + } + + return 0; +} + +static int stv0900_track(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + return 0; +} + +static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts) +{ + + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + + if (stop_ts == TRUE) + stv0900_write_bits(intp, RST_HWARE, 1); + else + stv0900_write_bits(intp, RST_HWARE, 0); + + return 0; +} + +static int stv0900_diseqc_init(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + + stv0900_write_bits(intp, DISTX_MODE, state->config->diseqc_mode); + stv0900_write_bits(intp, DISEQC_RESET, 1); + stv0900_write_bits(intp, DISEQC_RESET, 0); + + return 0; +} + +static int stv0900_init(struct dvb_frontend *fe) +{ + dprintk("%s\n", __func__); + + stv0900_stop_ts(fe, 1); + stv0900_diseqc_init(fe); + + return 0; +} + +static int stv0900_diseqc_send(struct stv0900_internal *intp , u8 *data, + u32 NbData, enum fe_stv0900_demod_num demod) +{ + s32 i = 0; + + stv0900_write_bits(intp, DIS_PRECHARGE, 1); + while (i < NbData) { + while (stv0900_get_bits(intp, FIFO_FULL)) + ;/* checkpatch complains */ + stv0900_write_reg(intp, DISTXDATA, data[i]); + i++; + } + + stv0900_write_bits(intp, DIS_PRECHARGE, 0); + i = 0; + while ((stv0900_get_bits(intp, TX_IDLE) != 1) && (i < 10)) { + msleep(10); + i++; + } + + return 0; +} + +static int stv0900_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct stv0900_state *state = fe->demodulator_priv; + + return stv0900_diseqc_send(state->internal, + cmd->msg, + cmd->msg_len, + state->demod); +} + +static int stv0900_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + u8 data; + + + switch (burst) { + case SEC_MINI_A: + stv0900_write_bits(intp, DISTX_MODE, 3);/* Unmodulated */ + data = 0x00; + stv0900_diseqc_send(intp, &data, 1, state->demod); + break; + case SEC_MINI_B: + stv0900_write_bits(intp, DISTX_MODE, 2);/* Modulated */ + data = 0xff; + stv0900_diseqc_send(intp, &data, 1, state->demod); + break; + } + + return 0; +} + +static int stv0900_recv_slave_reply(struct dvb_frontend *fe, + struct dvb_diseqc_slave_reply *reply) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + s32 i = 0; + + reply->msg_len = 0; + + while ((stv0900_get_bits(intp, RX_END) != 1) && (i < 10)) { + msleep(10); + i++; + } + + if (stv0900_get_bits(intp, RX_END)) { + reply->msg_len = stv0900_get_bits(intp, FIFO_BYTENBR); + + for (i = 0; i < reply->msg_len; i++) + reply->msg[i] = stv0900_read_reg(intp, DISRXDATA); + } + + return 0; +} + +static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t toneoff) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + + dprintk("%s: %s\n", __func__, ((toneoff == 0) ? "On" : "Off")); + + switch (toneoff) { + case SEC_TONE_ON: + /*Set the DiseqC mode to 22Khz _continues_ tone*/ + stv0900_write_bits(intp, DISTX_MODE, 0); + stv0900_write_bits(intp, DISEQC_RESET, 1); + /*release DiseqC reset to enable the 22KHz tone*/ + stv0900_write_bits(intp, DISEQC_RESET, 0); + break; + case SEC_TONE_OFF: + /*return diseqc mode to config->diseqc_mode. + Usually it's without _continues_ tone */ + stv0900_write_bits(intp, DISTX_MODE, + state->config->diseqc_mode); + /*maintain the DiseqC reset to disable the 22KHz tone*/ + stv0900_write_bits(intp, DISEQC_RESET, 1); + stv0900_write_bits(intp, DISEQC_RESET, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void stv0900_release(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (state->config->set_lock_led) + state->config->set_lock_led(fe, 0); + + if ((--(state->internal->dmds_used)) <= 0) { + + dprintk("%s: Actually removing\n", __func__); + + remove_inode(state->internal); + kfree(state->internal); + } + + kfree(state); +} + +static int stv0900_sleep(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (state->config->set_lock_led) + state->config->set_lock_led(fe, 0); + + return 0; +} + +static int stv0900_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + struct stv0900_signal_info p_result = intp->result[demod]; + + p->frequency = p_result.locked ? p_result.frequency : 0; + p->u.qpsk.symbol_rate = p_result.locked ? p_result.symbol_rate : 0; + return 0; +} + +static struct dvb_frontend_ops stv0900_ops = { + + .info = { + .name = "STV0900 frontend", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | FE_CAN_QPSK | + FE_CAN_2G_MODULATION | + FE_CAN_FEC_AUTO + }, + .release = stv0900_release, + .init = stv0900_init, + .get_frontend = stv0900_get_frontend, + .sleep = stv0900_sleep, + .get_frontend_algo = stv0900_frontend_algo, + .i2c_gate_ctrl = stv0900_i2c_gate_ctrl, + .diseqc_send_master_cmd = stv0900_send_master_cmd, + .diseqc_send_burst = stv0900_send_burst, + .diseqc_recv_slave_reply = stv0900_recv_slave_reply, + .set_tone = stv0900_set_tone, + .set_property = stb0900_set_property, + .get_property = stb0900_get_property, + .search = stv0900_search, + .track = stv0900_track, + .read_status = stv0900_read_status, + .read_ber = stv0900_read_ber, + .read_signal_strength = stv0900_read_signal_strength, + .read_snr = stv0900_read_snr, + .read_ucblocks = stv0900_read_ucblocks, +}; + +struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, + struct i2c_adapter *i2c, + int demod) +{ + struct stv0900_state *state = NULL; + struct stv0900_init_params init_params; + enum fe_stv0900_error err_stv0900; + + state = kzalloc(sizeof(struct stv0900_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->demod = demod; + state->config = config; + state->i2c_adap = i2c; + + memcpy(&state->frontend.ops, &stv0900_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + switch (demod) { + case 0: + case 1: + init_params.dmd_ref_clk = config->xtal; + init_params.demod_mode = config->demod_mode; + init_params.rolloff = STV0900_35; + init_params.path1_ts_clock = config->path1_mode; + init_params.tun1_maddress = config->tun1_maddress; + init_params.tun1_iq_inv = STV0900_IQ_NORMAL; + init_params.tuner1_adc = config->tun1_adc; + init_params.tuner1_type = config->tun1_type; + init_params.path2_ts_clock = config->path2_mode; + init_params.ts_config = config->ts_config_regs; + init_params.tun2_maddress = config->tun2_maddress; + init_params.tuner2_adc = config->tun2_adc; + init_params.tuner2_type = config->tun2_type; + init_params.tun2_iq_inv = STV0900_IQ_SWAPPED; + + err_stv0900 = stv0900_init_internal(&state->frontend, + &init_params); + + if (err_stv0900) + goto error; + + break; + default: + goto error; + break; + } + + dprintk("%s: Attaching STV0900 demodulator(%d) \n", __func__, demod); + return &state->frontend; + +error: + dprintk("%s: Failed to attach STV0900 demodulator(%d) \n", + __func__, demod); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stv0900_attach); + +MODULE_PARM_DESC(debug, "Set debug"); + +MODULE_AUTHOR("Igor M. Liplianin"); +MODULE_DESCRIPTION("ST STV0900 frontend"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * stv0900.h + * + * Driver for ST STV0900 satellite demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef STV0900_H +#define STV0900_H + +#include +#include "dvb_frontend.h" + +struct stv0900_reg { + u16 addr; + u8 val; +}; + +struct stv0900_config { + u8 demod_address; + u8 demod_mode; + u32 xtal; + u8 clkmode;/* 0 for CLKI, 2 for XTALI */ + + u8 diseqc_mode; + + u8 path1_mode; + u8 path2_mode; + struct stv0900_reg *ts_config_regs; + u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */ + u8 tun2_maddress; + u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */ + u8 tun2_adc; + u8 tun1_type;/* for now 3 for stb6100 auto, else - software */ + u8 tun2_type; + /* Set device param to start dma */ + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); + /* Hook for Lock LED */ + void (*set_lock_led)(struct dvb_frontend *fe, int offon); +}; + +#if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, + struct i2c_adapter *i2c, int demod); +#else +static inline struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, + struct i2c_adapter *i2c, int demod) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_init.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_init.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_init.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_init.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,584 @@ +/* + * stv0900_init.h + * + * Driver for ST STV0900 satellite demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef STV0900_INIT_H +#define STV0900_INIT_H + +#include "stv0900_priv.h" + +/* DVBS2 C/N Look-Up table */ +static const struct stv0900_table stv0900_s2_cn = { + 55, + { + { -30, 13348 }, /*C/N=-3dB*/ + { -20, 12640 }, /*C/N=-2dB*/ + { -10, 11883 }, /*C/N=-1dB*/ + { 0, 11101 }, /*C/N=-0dB*/ + { 5, 10718 }, /*C/N=0.5dB*/ + { 10, 10339 }, /*C/N=1.0dB*/ + { 15, 9947 }, /*C/N=1.5dB*/ + { 20, 9552 }, /*C/N=2.0dB*/ + { 25, 9183 }, /*C/N=2.5dB*/ + { 30, 8799 }, /*C/N=3.0dB*/ + { 35, 8422 }, /*C/N=3.5dB*/ + { 40, 8062 }, /*C/N=4.0dB*/ + { 45, 7707 }, /*C/N=4.5dB*/ + { 50, 7353 }, /*C/N=5.0dB*/ + { 55, 7025 }, /*C/N=5.5dB*/ + { 60, 6684 }, /*C/N=6.0dB*/ + { 65, 6331 }, /*C/N=6.5dB*/ + { 70, 6036 }, /*C/N=7.0dB*/ + { 75, 5727 }, /*C/N=7.5dB*/ + { 80, 5437 }, /*C/N=8.0dB*/ + { 85, 5164 }, /*C/N=8.5dB*/ + { 90, 4902 }, /*C/N=9.0dB*/ + { 95, 4653 }, /*C/N=9.5dB*/ + { 100, 4408 }, /*C/N=10.0dB*/ + { 105, 4187 }, /*C/N=10.5dB*/ + { 110, 3961 }, /*C/N=11.0dB*/ + { 115, 3751 }, /*C/N=11.5dB*/ + { 120, 3558 }, /*C/N=12.0dB*/ + { 125, 3368 }, /*C/N=12.5dB*/ + { 130, 3191 }, /*C/N=13.0dB*/ + { 135, 3017 }, /*C/N=13.5dB*/ + { 140, 2862 }, /*C/N=14.0dB*/ + { 145, 2710 }, /*C/N=14.5dB*/ + { 150, 2565 }, /*C/N=15.0dB*/ + { 160, 2300 }, /*C/N=16.0dB*/ + { 170, 2058 }, /*C/N=17.0dB*/ + { 180, 1849 }, /*C/N=18.0dB*/ + { 190, 1663 }, /*C/N=19.0dB*/ + { 200, 1495 }, /*C/N=20.0dB*/ + { 210, 1349 }, /*C/N=21.0dB*/ + { 220, 1222 }, /*C/N=22.0dB*/ + { 230, 1110 }, /*C/N=23.0dB*/ + { 240, 1011 }, /*C/N=24.0dB*/ + { 250, 925 }, /*C/N=25.0dB*/ + { 260, 853 }, /*C/N=26.0dB*/ + { 270, 789 }, /*C/N=27.0dB*/ + { 280, 734 }, /*C/N=28.0dB*/ + { 290, 690 }, /*C/N=29.0dB*/ + { 300, 650 }, /*C/N=30.0dB*/ + { 310, 619 }, /*C/N=31.0dB*/ + { 320, 593 }, /*C/N=32.0dB*/ + { 330, 571 }, /*C/N=33.0dB*/ + { 400, 498 }, /*C/N=40.0dB*/ + { 450, 484 }, /*C/N=45.0dB*/ + { 500, 481 } /*C/N=50.0dB*/ + } +}; + +/* RF level C/N Look-Up table */ +static const struct stv0900_table stv0900_rf = { + 14, + { + { -5, 0xCAA1 }, /*-5dBm*/ + { -10, 0xC229 }, /*-10dBm*/ + { -15, 0xBB08 }, /*-15dBm*/ + { -20, 0xB4BC }, /*-20dBm*/ + { -25, 0xAD5A }, /*-25dBm*/ + { -30, 0xA298 }, /*-30dBm*/ + { -35, 0x98A8 }, /*-35dBm*/ + { -40, 0x8389 }, /*-40dBm*/ + { -45, 0x59BE }, /*-45dBm*/ + { -50, 0x3A14 }, /*-50dBm*/ + { -55, 0x2D11 }, /*-55dBm*/ + { -60, 0x210D }, /*-60dBm*/ + { -65, 0xA14F }, /*-65dBm*/ + { -70, 0x7AA } /*-70dBm*/ + } +}; + +struct stv0900_car_loop_optim { + enum fe_stv0900_modcode modcode; + u8 car_loop_pilots_on_2; + u8 car_loop_pilots_off_2; + u8 car_loop_pilots_on_5; + u8 car_loop_pilots_off_5; + u8 car_loop_pilots_on_10; + u8 car_loop_pilots_off_10; + u8 car_loop_pilots_on_20; + u8 car_loop_pilots_off_20; + u8 car_loop_pilots_on_30; + u8 car_loop_pilots_off_30; + +}; + +struct stv0900_short_frames_car_loop_optim { + enum fe_stv0900_modulation modulation; + u8 car_loop_cut12_2; /* Cut 1.2, SR<=3msps */ + u8 car_loop_cut20_2; /* Cut 2.0, SR<3msps */ + u8 car_loop_cut12_5; /* Cut 1.2, 3 + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef STV0900_PRIV_H +#define STV0900_PRIV_H + +#include + +#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X)) +#define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \ + || (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0) + +#ifndef MAKEWORD +#define MAKEWORD(X, Y) (((X) << 8) + (Y)) +#endif + +#define LSB(X) (((X) & 0xFF)) +#define MSB(Y) (((Y) >> 8) & 0xFF) + +#ifndef TRUE +#define TRUE (1 == 1) +#endif +#ifndef FALSE +#define FALSE (!TRUE) +#endif + +#define dprintk(args...) \ + do { \ + if (stvdebug) \ + printk(KERN_DEBUG args); \ + } while (0) + +#define STV0900_MAXLOOKUPSIZE 500 +#define STV0900_BLIND_SEARCH_AGC2_TH 700 +#define STV0900_BLIND_SEARCH_AGC2_TH_CUT30 1400 +#define IQPOWER_THRESHOLD 30 + +/* One point of the lookup table */ +struct stv000_lookpoint { + s32 realval;/* real value */ + s32 regval;/* binary value */ +}; + +/* Lookup table definition */ +struct stv0900_table{ + s32 size;/* Size of the lookup table */ + struct stv000_lookpoint table[STV0900_MAXLOOKUPSIZE];/* Lookup table */ +}; + +enum fe_stv0900_error { + STV0900_NO_ERROR = 0, + STV0900_INVALID_HANDLE, + STV0900_BAD_PARAMETER, + STV0900_I2C_ERROR, + STV0900_SEARCH_FAILED, +}; + +enum fe_stv0900_clock_type { + STV0900_USE_REGISTERS_DEFAULT, + STV0900_SERIAL_PUNCT_CLOCK,/*Serial punctured clock */ + STV0900_SERIAL_CONT_CLOCK,/*Serial continues clock */ + STV0900_PARALLEL_PUNCT_CLOCK,/*Parallel punctured clock */ + STV0900_DVBCI_CLOCK/*Parallel continues clock : DVBCI */ +}; + +enum fe_stv0900_search_state { + STV0900_SEARCH = 0, + STV0900_PLH_DETECTED, + STV0900_DVBS2_FOUND, + STV0900_DVBS_FOUND + +}; + +enum fe_stv0900_ldpc_state { + STV0900_PATH1_OFF_PATH2_OFF = 0, + STV0900_PATH1_ON_PATH2_OFF = 1, + STV0900_PATH1_OFF_PATH2_ON = 2, + STV0900_PATH1_ON_PATH2_ON = 3 +}; + +enum fe_stv0900_signal_type { + STV0900_NOAGC1 = 0, + STV0900_AGC1OK, + STV0900_NOTIMING, + STV0900_ANALOGCARRIER, + STV0900_TIMINGOK, + STV0900_NOAGC2, + STV0900_AGC2OK, + STV0900_NOCARRIER, + STV0900_CARRIEROK, + STV0900_NODATA, + STV0900_DATAOK, + STV0900_OUTOFRANGE, + STV0900_RANGEOK +}; + +enum fe_stv0900_demod_num { + STV0900_DEMOD_1, + STV0900_DEMOD_2 +}; + +enum fe_stv0900_tracking_standard { + STV0900_DVBS1_STANDARD,/* Found Standard*/ + STV0900_DVBS2_STANDARD, + STV0900_DSS_STANDARD, + STV0900_TURBOCODE_STANDARD, + STV0900_UNKNOWN_STANDARD +}; + +enum fe_stv0900_search_standard { + STV0900_AUTO_SEARCH, + STV0900_SEARCH_DVBS1,/* Search Standard*/ + STV0900_SEARCH_DVBS2, + STV0900_SEARCH_DSS, + STV0900_SEARCH_TURBOCODE +}; + +enum fe_stv0900_search_algo { + STV0900_BLIND_SEARCH,/* offset freq and SR are Unknown */ + STV0900_COLD_START,/* only the SR is known */ + STV0900_WARM_START/* offset freq and SR are known */ +}; + +enum fe_stv0900_modulation { + STV0900_QPSK, + STV0900_8PSK, + STV0900_16APSK, + STV0900_32APSK, + STV0900_UNKNOWN +}; + +enum fe_stv0900_modcode { + STV0900_DUMMY_PLF, + STV0900_QPSK_14, + STV0900_QPSK_13, + STV0900_QPSK_25, + STV0900_QPSK_12, + STV0900_QPSK_35, + STV0900_QPSK_23, + STV0900_QPSK_34, + STV0900_QPSK_45, + STV0900_QPSK_56, + STV0900_QPSK_89, + STV0900_QPSK_910, + STV0900_8PSK_35, + STV0900_8PSK_23, + STV0900_8PSK_34, + STV0900_8PSK_56, + STV0900_8PSK_89, + STV0900_8PSK_910, + STV0900_16APSK_23, + STV0900_16APSK_34, + STV0900_16APSK_45, + STV0900_16APSK_56, + STV0900_16APSK_89, + STV0900_16APSK_910, + STV0900_32APSK_34, + STV0900_32APSK_45, + STV0900_32APSK_56, + STV0900_32APSK_89, + STV0900_32APSK_910, + STV0900_MODCODE_UNKNOWN +}; + +enum fe_stv0900_fec {/*DVBS1, DSS and turbo code puncture rate*/ + STV0900_FEC_1_2 = 0, + STV0900_FEC_2_3, + STV0900_FEC_3_4, + STV0900_FEC_4_5,/*for turbo code only*/ + STV0900_FEC_5_6, + STV0900_FEC_6_7,/*for DSS only */ + STV0900_FEC_7_8, + STV0900_FEC_8_9,/*for turbo code only*/ + STV0900_FEC_UNKNOWN +}; + +enum fe_stv0900_frame_length { + STV0900_LONG_FRAME, + STV0900_SHORT_FRAME +}; + +enum fe_stv0900_pilot { + STV0900_PILOTS_OFF, + STV0900_PILOTS_ON +}; + +enum fe_stv0900_rolloff { + STV0900_35, + STV0900_25, + STV0900_20 +}; + +enum fe_stv0900_search_iq { + STV0900_IQ_AUTO, + STV0900_IQ_AUTO_NORMAL_FIRST, + STV0900_IQ_FORCE_NORMAL, + STV0900_IQ_FORCE_SWAPPED +}; + +enum stv0900_iq_inversion { + STV0900_IQ_NORMAL, + STV0900_IQ_SWAPPED +}; + +enum fe_stv0900_diseqc_mode { + STV0900_22KHZ_Continues = 0, + STV0900_DISEQC_2_3_PWM = 2, + STV0900_DISEQC_3_3_PWM = 3, + STV0900_DISEQC_2_3_ENVELOP = 4, + STV0900_DISEQC_3_3_ENVELOP = 5 +}; + +enum fe_stv0900_demod_mode { + STV0900_SINGLE = 0, + STV0900_DUAL +}; + +struct stv0900_init_params{ + u32 dmd_ref_clk;/* Reference,Input clock for the demod in Hz */ + + /* Demodulator Type (single demod or dual demod) */ + enum fe_stv0900_demod_mode demod_mode; + enum fe_stv0900_rolloff rolloff; + enum fe_stv0900_clock_type path1_ts_clock; + + u8 tun1_maddress; + int tuner1_adc; + int tuner1_type; + + /* IQ from the tuner1 to the demod */ + enum stv0900_iq_inversion tun1_iq_inv; + enum fe_stv0900_clock_type path2_ts_clock; + + u8 tun2_maddress; + int tuner2_adc; + int tuner2_type; + + /* IQ from the tuner2 to the demod */ + enum stv0900_iq_inversion tun2_iq_inv; + struct stv0900_reg *ts_config; +}; + +struct stv0900_search_params { + enum fe_stv0900_demod_num path;/* Path Used demod1 or 2 */ + + u32 frequency;/* Transponder frequency (in KHz) */ + u32 symbol_rate;/* Transponder symbol rate (in bds)*/ + u32 search_range;/* Range of the search (in Hz) */ + + enum fe_stv0900_search_standard standard; + enum fe_stv0900_modulation modulation; + enum fe_stv0900_fec fec; + enum fe_stv0900_modcode modcode; + enum fe_stv0900_search_iq iq_inversion; + enum fe_stv0900_search_algo search_algo; + +}; + +struct stv0900_signal_info { + int locked;/* Transponder locked */ + u32 frequency;/* Transponder frequency (in KHz) */ + u32 symbol_rate;/* Transponder symbol rate (in Mbds) */ + + enum fe_stv0900_tracking_standard standard; + enum fe_stv0900_fec fec; + enum fe_stv0900_modcode modcode; + enum fe_stv0900_modulation modulation; + enum fe_stv0900_pilot pilot; + enum fe_stv0900_frame_length frame_len; + enum stv0900_iq_inversion spectrum; + enum fe_stv0900_rolloff rolloff; + + s32 Power;/* Power of the RF signal (dBm) */ + s32 C_N;/* Carrier to noise ratio (dB x10)*/ + u32 BER;/* Bit error rate (x10^7) */ + +}; + +struct stv0900_internal{ + s32 quartz; + s32 mclk; + /* manual RollOff for DVBS1/DSS only */ + enum fe_stv0900_rolloff rolloff; + /* Demodulator use for single demod or for dual demod) */ + enum fe_stv0900_demod_mode demod_mode; + + /*Demods */ + s32 freq[2]; + s32 bw[2]; + s32 symbol_rate[2]; + s32 srch_range[2]; + /* for software/auto tuner */ + int tuner_type[2]; + + /* algorithm for search Blind, Cold or Warm*/ + enum fe_stv0900_search_algo srch_algo[2]; + /* search standard: Auto, DVBS1/DSS only or DVBS2 only*/ + enum fe_stv0900_search_standard srch_standard[2]; + /* inversion search : auto, auto norma first, normal or inverted */ + enum fe_stv0900_search_iq srch_iq_inv[2]; + enum fe_stv0900_modcode modcode[2]; + enum fe_stv0900_modulation modulation[2]; + enum fe_stv0900_fec fec[2]; + + struct stv0900_signal_info result[2]; + enum fe_stv0900_error err[2]; + + + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + u8 clkmode;/* 0 for CLKI, 2 for XTALI */ + u8 chip_id; + struct stv0900_reg *ts_config; + enum fe_stv0900_error errs; + int dmds_used; +}; + +/* state for each demod */ +struct stv0900_state { + /* pointer for internal params, one for each pair of demods */ + struct stv0900_internal *internal; + struct i2c_adapter *i2c_adap; + const struct stv0900_config *config; + struct dvb_frontend frontend; + int demod; +}; + +extern int stvdebug; + +extern s32 ge2comp(s32 a, s32 width); + +extern void stv0900_write_reg(struct stv0900_internal *i_params, + u16 reg_addr, u8 reg_data); + +extern u8 stv0900_read_reg(struct stv0900_internal *i_params, + u16 reg_addr); + +extern void stv0900_write_bits(struct stv0900_internal *i_params, + u32 label, u8 val); + +extern u8 stv0900_get_bits(struct stv0900_internal *i_params, + u32 label); + +extern int stv0900_get_demod_lock(struct stv0900_internal *i_params, + enum fe_stv0900_demod_num demod, s32 time_out); +extern int stv0900_check_signal_presence(struct stv0900_internal *i_params, + enum fe_stv0900_demod_num demod); + +extern enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe); + +extern void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency, + u32 bandwidth); +extern void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth); + +extern void stv0900_start_search(struct stv0900_internal *i_params, + enum fe_stv0900_demod_num demod); + +extern u8 stv0900_get_optim_carr_loop(s32 srate, + enum fe_stv0900_modcode modcode, + s32 pilot, u8 chip_id); + +extern u8 stv0900_get_optim_short_carr_loop(s32 srate, + enum fe_stv0900_modulation modulation, + u8 chip_id); + +extern void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params, + enum fe_stv0900_demod_num demod); + +extern void stv0900_activate_s2_modcod(struct stv0900_internal *i_params, + enum fe_stv0900_demod_num demod); + +extern void stv0900_activate_s2_modcod_single(struct stv0900_internal *i_params, + enum fe_stv0900_demod_num demod); + +extern enum +fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe, + enum fe_stv0900_demod_num demod); + +extern u32 +stv0900_get_freq_auto(struct stv0900_internal *intp, int demod); + +extern void +stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency, + u32 Bandwidth, int demod); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3981 @@ +/* + * stv0900_reg.h + * + * Driver for ST STV0900 satellite demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef STV0900_REG_H +#define STV0900_REG_H + +extern s32 shiftx(s32 x, int demod, s32 shift); + +#define REGx(x) shiftx(x, demod, 0x200) +#define FLDx(x) shiftx(x, demod, 0x2000000) + +/*MID*/ +#define R0900_MID 0xf100 +#define F0900_MCHIP_IDENT 0xf10000f0 +#define F0900_MRELEASE 0xf100000f + +/*DACR1*/ +#define R0900_DACR1 0xf113 +#define F0900_DAC_MODE 0xf11300e0 +#define F0900_DAC_VALUE1 0xf113000f + +/*DACR2*/ +#define R0900_DACR2 0xf114 +#define F0900_DAC_VALUE0 0xf11400ff + +/*OUTCFG*/ +#define R0900_OUTCFG 0xf11c +#define F0900_OUTSERRS1_HZ 0xf11c0040 +#define F0900_OUTSERRS2_HZ 0xf11c0020 +#define F0900_OUTSERRS3_HZ 0xf11c0010 +#define F0900_OUTPARRS3_HZ 0xf11c0008 + +/*IRQSTATUS3*/ +#define R0900_IRQSTATUS3 0xf120 +#define F0900_SPLL_LOCK 0xf1200020 +#define F0900_SSTREAM_LCK_3 0xf1200010 +#define F0900_SSTREAM_LCK_2 0xf1200008 +#define F0900_SSTREAM_LCK_1 0xf1200004 +#define F0900_SDVBS1_PRF_2 0xf1200002 +#define F0900_SDVBS1_PRF_1 0xf1200001 + +/*IRQSTATUS2*/ +#define R0900_IRQSTATUS2 0xf121 +#define F0900_SSPY_ENDSIM_3 0xf1210080 +#define F0900_SSPY_ENDSIM_2 0xf1210040 +#define F0900_SSPY_ENDSIM_1 0xf1210020 +#define F0900_SPKTDEL_ERROR_2 0xf1210010 +#define F0900_SPKTDEL_LOCKB_2 0xf1210008 +#define F0900_SPKTDEL_LOCK_2 0xf1210004 +#define F0900_SPKTDEL_ERROR_1 0xf1210002 +#define F0900_SPKTDEL_LOCKB_1 0xf1210001 + +/*IRQSTATUS1*/ +#define R0900_IRQSTATUS1 0xf122 +#define F0900_SPKTDEL_LOCK_1 0xf1220080 +#define F0900_SDEMOD_LOCKB_2 0xf1220004 +#define F0900_SDEMOD_LOCK_2 0xf1220002 +#define F0900_SDEMOD_IRQ_2 0xf1220001 + +/*IRQSTATUS0*/ +#define R0900_IRQSTATUS0 0xf123 +#define F0900_SDEMOD_LOCKB_1 0xf1230080 +#define F0900_SDEMOD_LOCK_1 0xf1230040 +#define F0900_SDEMOD_IRQ_1 0xf1230020 +#define F0900_SBCH_ERRFLAG 0xf1230010 +#define F0900_SDISEQC2RX_IRQ 0xf1230008 +#define F0900_SDISEQC2TX_IRQ 0xf1230004 +#define F0900_SDISEQC1RX_IRQ 0xf1230002 +#define F0900_SDISEQC1TX_IRQ 0xf1230001 + +/*IRQMASK3*/ +#define R0900_IRQMASK3 0xf124 +#define F0900_MPLL_LOCK 0xf1240020 +#define F0900_MSTREAM_LCK_3 0xf1240010 +#define F0900_MSTREAM_LCK_2 0xf1240008 +#define F0900_MSTREAM_LCK_1 0xf1240004 +#define F0900_MDVBS1_PRF_2 0xf1240002 +#define F0900_MDVBS1_PRF_1 0xf1240001 + +/*IRQMASK2*/ +#define R0900_IRQMASK2 0xf125 +#define F0900_MSPY_ENDSIM_3 0xf1250080 +#define F0900_MSPY_ENDSIM_2 0xf1250040 +#define F0900_MSPY_ENDSIM_1 0xf1250020 +#define F0900_MPKTDEL_ERROR_2 0xf1250010 +#define F0900_MPKTDEL_LOCKB_2 0xf1250008 +#define F0900_MPKTDEL_LOCK_2 0xf1250004 +#define F0900_MPKTDEL_ERROR_1 0xf1250002 +#define F0900_MPKTDEL_LOCKB_1 0xf1250001 + +/*IRQMASK1*/ +#define R0900_IRQMASK1 0xf126 +#define F0900_MPKTDEL_LOCK_1 0xf1260080 +#define F0900_MEXTPINB2 0xf1260040 +#define F0900_MEXTPIN2 0xf1260020 +#define F0900_MEXTPINB1 0xf1260010 +#define F0900_MEXTPIN1 0xf1260008 +#define F0900_MDEMOD_LOCKB_2 0xf1260004 +#define F0900_MDEMOD_LOCK_2 0xf1260002 +#define F0900_MDEMOD_IRQ_2 0xf1260001 + +/*IRQMASK0*/ +#define R0900_IRQMASK0 0xf127 +#define F0900_MDEMOD_LOCKB_1 0xf1270080 +#define F0900_MDEMOD_LOCK_1 0xf1270040 +#define F0900_MDEMOD_IRQ_1 0xf1270020 +#define F0900_MBCH_ERRFLAG 0xf1270010 +#define F0900_MDISEQC2RX_IRQ 0xf1270008 +#define F0900_MDISEQC2TX_IRQ 0xf1270004 +#define F0900_MDISEQC1RX_IRQ 0xf1270002 +#define F0900_MDISEQC1TX_IRQ 0xf1270001 + +/*I2CCFG*/ +#define R0900_I2CCFG 0xf129 +#define F0900_I2C_FASTMODE 0xf1290008 +#define F0900_I2CADDR_INC 0xf1290003 + +/*P1_I2CRPT*/ +#define R0900_P1_I2CRPT 0xf12a +#define I2CRPT shiftx(R0900_P1_I2CRPT, demod, -1) +#define F0900_P1_I2CT_ON 0xf12a0080 +#define I2CT_ON shiftx(F0900_P1_I2CT_ON, demod, -0x10000) +#define F0900_P1_ENARPT_LEVEL 0xf12a0070 +#define F0900_P1_SCLT_DELAY 0xf12a0008 +#define F0900_P1_STOP_ENABLE 0xf12a0004 +#define F0900_P1_STOP_SDAT2SDA 0xf12a0002 + +/*P2_I2CRPT*/ +#define R0900_P2_I2CRPT 0xf12b +#define F0900_P2_I2CT_ON 0xf12b0080 +#define F0900_P2_ENARPT_LEVEL 0xf12b0070 +#define F0900_P2_SCLT_DELAY 0xf12b0008 +#define F0900_P2_STOP_ENABLE 0xf12b0004 +#define F0900_P2_STOP_SDAT2SDA 0xf12b0002 + +/*IOPVALUE6*/ +#define R0900_IOPVALUE6 0xf138 +#define F0900_VSCL 0xf1380004 +#define F0900_VSDA 0xf1380002 +#define F0900_VDATA3_0 0xf1380001 + +/*IOPVALUE5*/ +#define R0900_IOPVALUE5 0xf139 +#define F0900_VDATA3_1 0xf1390080 +#define F0900_VDATA3_2 0xf1390040 +#define F0900_VDATA3_3 0xf1390020 +#define F0900_VDATA3_4 0xf1390010 +#define F0900_VDATA3_5 0xf1390008 +#define F0900_VDATA3_6 0xf1390004 +#define F0900_VDATA3_7 0xf1390002 +#define F0900_VCLKOUT3 0xf1390001 + +/*IOPVALUE4*/ +#define R0900_IOPVALUE4 0xf13a +#define F0900_VSTROUT3 0xf13a0080 +#define F0900_VDPN3 0xf13a0040 +#define F0900_VERROR3 0xf13a0020 +#define F0900_VDATA2_7 0xf13a0010 +#define F0900_VCLKOUT2 0xf13a0008 +#define F0900_VSTROUT2 0xf13a0004 +#define F0900_VDPN2 0xf13a0002 +#define F0900_VERROR2 0xf13a0001 + +/*IOPVALUE3*/ +#define R0900_IOPVALUE3 0xf13b +#define F0900_VDATA1_7 0xf13b0080 +#define F0900_VCLKOUT1 0xf13b0040 +#define F0900_VSTROUT1 0xf13b0020 +#define F0900_VDPN1 0xf13b0010 +#define F0900_VERROR1 0xf13b0008 +#define F0900_VCLKOUT27 0xf13b0004 +#define F0900_VDISEQCOUT2 0xf13b0002 +#define F0900_VSCLT2 0xf13b0001 + +/*IOPVALUE2*/ +#define R0900_IOPVALUE2 0xf13c +#define F0900_VSDAT2 0xf13c0080 +#define F0900_VAGCRF2 0xf13c0040 +#define F0900_VDISEQCOUT1 0xf13c0020 +#define F0900_VSCLT1 0xf13c0010 +#define F0900_VSDAT1 0xf13c0008 +#define F0900_VAGCRF1 0xf13c0004 +#define F0900_VDIRCLK 0xf13c0002 +#define F0900_VSTDBY 0xf13c0001 + +/*IOPVALUE1*/ +#define R0900_IOPVALUE1 0xf13d +#define F0900_VCS1 0xf13d0080 +#define F0900_VCS0 0xf13d0040 +#define F0900_VGPIO13 0xf13d0020 +#define F0900_VGPIO12 0xf13d0010 +#define F0900_VGPIO11 0xf13d0008 +#define F0900_VGPIO10 0xf13d0004 +#define F0900_VGPIO9 0xf13d0002 +#define F0900_VGPIO8 0xf13d0001 + +/*IOPVALUE0*/ +#define R0900_IOPVALUE0 0xf13e +#define F0900_VGPIO7 0xf13e0080 +#define F0900_VGPIO6 0xf13e0040 +#define F0900_VGPIO5 0xf13e0020 +#define F0900_VGPIO4 0xf13e0010 +#define F0900_VGPIO3 0xf13e0008 +#define F0900_VGPIO2 0xf13e0004 +#define F0900_VGPIO1 0xf13e0002 +#define F0900_VCLKI2 0xf13e0001 + +/*CLKI2CFG*/ +#define R0900_CLKI2CFG 0xf140 +#define F0900_CLKI2_OPD 0xf1400080 +#define F0900_CLKI2_CONFIG 0xf140007e +#define F0900_CLKI2_XOR 0xf1400001 + +/*GPIO1CFG*/ +#define R0900_GPIO1CFG 0xf141 +#define F0900_GPIO1_OPD 0xf1410080 +#define F0900_GPIO1_CONFIG 0xf141007e +#define F0900_GPIO1_XOR 0xf1410001 + +/*GPIO2CFG*/ +#define R0900_GPIO2CFG 0xf142 +#define F0900_GPIO2_OPD 0xf1420080 +#define F0900_GPIO2_CONFIG 0xf142007e +#define F0900_GPIO2_XOR 0xf1420001 + +/*GPIO3CFG*/ +#define R0900_GPIO3CFG 0xf143 +#define F0900_GPIO3_OPD 0xf1430080 +#define F0900_GPIO3_CONFIG 0xf143007e +#define F0900_GPIO3_XOR 0xf1430001 + +/*GPIO4CFG*/ +#define R0900_GPIO4CFG 0xf144 +#define F0900_GPIO4_OPD 0xf1440080 +#define F0900_GPIO4_CONFIG 0xf144007e +#define F0900_GPIO4_XOR 0xf1440001 + +/*GPIO5CFG*/ +#define R0900_GPIO5CFG 0xf145 +#define F0900_GPIO5_OPD 0xf1450080 +#define F0900_GPIO5_CONFIG 0xf145007e +#define F0900_GPIO5_XOR 0xf1450001 + +/*GPIO6CFG*/ +#define R0900_GPIO6CFG 0xf146 +#define F0900_GPIO6_OPD 0xf1460080 +#define F0900_GPIO6_CONFIG 0xf146007e +#define F0900_GPIO6_XOR 0xf1460001 + +/*GPIO7CFG*/ +#define R0900_GPIO7CFG 0xf147 +#define F0900_GPIO7_OPD 0xf1470080 +#define F0900_GPIO7_CONFIG 0xf147007e +#define F0900_GPIO7_XOR 0xf1470001 + +/*GPIO8CFG*/ +#define R0900_GPIO8CFG 0xf148 +#define F0900_GPIO8_OPD 0xf1480080 +#define F0900_GPIO8_CONFIG 0xf148007e +#define F0900_GPIO8_XOR 0xf1480001 + +/*GPIO9CFG*/ +#define R0900_GPIO9CFG 0xf149 +#define F0900_GPIO9_OPD 0xf1490080 +#define F0900_GPIO9_CONFIG 0xf149007e +#define F0900_GPIO9_XOR 0xf1490001 + +/*GPIO10CFG*/ +#define R0900_GPIO10CFG 0xf14a +#define F0900_GPIO10_OPD 0xf14a0080 +#define F0900_GPIO10_CONFIG 0xf14a007e +#define F0900_GPIO10_XOR 0xf14a0001 + +/*GPIO11CFG*/ +#define R0900_GPIO11CFG 0xf14b +#define F0900_GPIO11_OPD 0xf14b0080 +#define F0900_GPIO11_CONFIG 0xf14b007e +#define F0900_GPIO11_XOR 0xf14b0001 + +/*GPIO12CFG*/ +#define R0900_GPIO12CFG 0xf14c +#define F0900_GPIO12_OPD 0xf14c0080 +#define F0900_GPIO12_CONFIG 0xf14c007e +#define F0900_GPIO12_XOR 0xf14c0001 + +/*GPIO13CFG*/ +#define R0900_GPIO13CFG 0xf14d +#define F0900_GPIO13_OPD 0xf14d0080 +#define F0900_GPIO13_CONFIG 0xf14d007e +#define F0900_GPIO13_XOR 0xf14d0001 + +/*CS0CFG*/ +#define R0900_CS0CFG 0xf14e +#define F0900_CS0_OPD 0xf14e0080 +#define F0900_CS0_CONFIG 0xf14e007e +#define F0900_CS0_XOR 0xf14e0001 + +/*CS1CFG*/ +#define R0900_CS1CFG 0xf14f +#define F0900_CS1_OPD 0xf14f0080 +#define F0900_CS1_CONFIG 0xf14f007e +#define F0900_CS1_XOR 0xf14f0001 + +/*STDBYCFG*/ +#define R0900_STDBYCFG 0xf150 +#define F0900_STDBY_OPD 0xf1500080 +#define F0900_STDBY_CONFIG 0xf150007e +#define F0900_STBDY_XOR 0xf1500001 + +/*DIRCLKCFG*/ +#define R0900_DIRCLKCFG 0xf151 +#define F0900_DIRCLK_OPD 0xf1510080 +#define F0900_DIRCLK_CONFIG 0xf151007e +#define F0900_DIRCLK_XOR 0xf1510001 + +/*AGCRF1CFG*/ +#define R0900_AGCRF1CFG 0xf152 +#define F0900_AGCRF1_OPD 0xf1520080 +#define F0900_AGCRF1_CONFIG 0xf152007e +#define F0900_AGCRF1_XOR 0xf1520001 + +/*SDAT1CFG*/ +#define R0900_SDAT1CFG 0xf153 +#define F0900_SDAT1_OPD 0xf1530080 +#define F0900_SDAT1_CONFIG 0xf153007e +#define F0900_SDAT1_XOR 0xf1530001 + +/*SCLT1CFG*/ +#define R0900_SCLT1CFG 0xf154 +#define F0900_SCLT1_OPD 0xf1540080 +#define F0900_SCLT1_CONFIG 0xf154007e +#define F0900_SCLT1_XOR 0xf1540001 + +/*DISEQCO1CFG*/ +#define R0900_DISEQCO1CFG 0xf155 +#define F0900_DISEQCO1_OPD 0xf1550080 +#define F0900_DISEQCO1_CONFIG 0xf155007e +#define F0900_DISEQC1_XOR 0xf1550001 + +/*AGCRF2CFG*/ +#define R0900_AGCRF2CFG 0xf156 +#define F0900_AGCRF2_OPD 0xf1560080 +#define F0900_AGCRF2_CONFIG 0xf156007e +#define F0900_AGCRF2_XOR 0xf1560001 + +/*SDAT2CFG*/ +#define R0900_SDAT2CFG 0xf157 +#define F0900_SDAT2_OPD 0xf1570080 +#define F0900_SDAT2_CONFIG 0xf157007e +#define F0900_SDAT2_XOR 0xf1570001 + +/*SCLT2CFG*/ +#define R0900_SCLT2CFG 0xf158 +#define F0900_SCLT2_OPD 0xf1580080 +#define F0900_SCLT2_CONFIG 0xf158007e +#define F0900_SCLT2_XOR 0xf1580001 + +/*DISEQCO2CFG*/ +#define R0900_DISEQCO2CFG 0xf159 +#define F0900_DISEQCO2_OPD 0xf1590080 +#define F0900_DISEQCO2_CONFIG 0xf159007e +#define F0900_DISEQC2_XOR 0xf1590001 + +/*CLKOUT27CFG*/ +#define R0900_CLKOUT27CFG 0xf15a +#define F0900_CLKOUT27_OPD 0xf15a0080 +#define F0900_CLKOUT27_CONFIG 0xf15a007e +#define F0900_CLKOUT27_XOR 0xf15a0001 + +/*ERROR1CFG*/ +#define R0900_ERROR1CFG 0xf15b +#define F0900_ERROR1_OPD 0xf15b0080 +#define F0900_ERROR1_CONFIG 0xf15b007e +#define F0900_ERROR1_XOR 0xf15b0001 + +/*DPN1CFG*/ +#define R0900_DPN1CFG 0xf15c +#define F0900_DPN1_OPD 0xf15c0080 +#define F0900_DPN1_CONFIG 0xf15c007e +#define F0900_DPN1_XOR 0xf15c0001 + +/*STROUT1CFG*/ +#define R0900_STROUT1CFG 0xf15d +#define F0900_STROUT1_OPD 0xf15d0080 +#define F0900_STROUT1_CONFIG 0xf15d007e +#define F0900_STROUT1_XOR 0xf15d0001 + +/*CLKOUT1CFG*/ +#define R0900_CLKOUT1CFG 0xf15e +#define F0900_CLKOUT1_OPD 0xf15e0080 +#define F0900_CLKOUT1_CONFIG 0xf15e007e +#define F0900_CLKOUT1_XOR 0xf15e0001 + +/*DATA71CFG*/ +#define R0900_DATA71CFG 0xf15f +#define F0900_DATA71_OPD 0xf15f0080 +#define F0900_DATA71_CONFIG 0xf15f007e +#define F0900_DATA71_XOR 0xf15f0001 + +/*ERROR2CFG*/ +#define R0900_ERROR2CFG 0xf160 +#define F0900_ERROR2_OPD 0xf1600080 +#define F0900_ERROR2_CONFIG 0xf160007e +#define F0900_ERROR2_XOR 0xf1600001 + +/*DPN2CFG*/ +#define R0900_DPN2CFG 0xf161 +#define F0900_DPN2_OPD 0xf1610080 +#define F0900_DPN2_CONFIG 0xf161007e +#define F0900_DPN2_XOR 0xf1610001 + +/*STROUT2CFG*/ +#define R0900_STROUT2CFG 0xf162 +#define F0900_STROUT2_OPD 0xf1620080 +#define F0900_STROUT2_CONFIG 0xf162007e +#define F0900_STROUT2_XOR 0xf1620001 + +/*CLKOUT2CFG*/ +#define R0900_CLKOUT2CFG 0xf163 +#define F0900_CLKOUT2_OPD 0xf1630080 +#define F0900_CLKOUT2_CONFIG 0xf163007e +#define F0900_CLKOUT2_XOR 0xf1630001 + +/*DATA72CFG*/ +#define R0900_DATA72CFG 0xf164 +#define F0900_DATA72_OPD 0xf1640080 +#define F0900_DATA72_CONFIG 0xf164007e +#define F0900_DATA72_XOR 0xf1640001 + +/*ERROR3CFG*/ +#define R0900_ERROR3CFG 0xf165 +#define F0900_ERROR3_OPD 0xf1650080 +#define F0900_ERROR3_CONFIG 0xf165007e +#define F0900_ERROR3_XOR 0xf1650001 + +/*DPN3CFG*/ +#define R0900_DPN3CFG 0xf166 +#define F0900_DPN3_OPD 0xf1660080 +#define F0900_DPN3_CONFIG 0xf166007e +#define F0900_DPN3_XOR 0xf1660001 + +/*STROUT3CFG*/ +#define R0900_STROUT3CFG 0xf167 +#define F0900_STROUT3_OPD 0xf1670080 +#define F0900_STROUT3_CONFIG 0xf167007e +#define F0900_STROUT3_XOR 0xf1670001 + +/*CLKOUT3CFG*/ +#define R0900_CLKOUT3CFG 0xf168 +#define F0900_CLKOUT3_OPD 0xf1680080 +#define F0900_CLKOUT3_CONFIG 0xf168007e +#define F0900_CLKOUT3_XOR 0xf1680001 + +/*DATA73CFG*/ +#define R0900_DATA73CFG 0xf169 +#define F0900_DATA73_OPD 0xf1690080 +#define F0900_DATA73_CONFIG 0xf169007e +#define F0900_DATA73_XOR 0xf1690001 + +/*STRSTATUS1*/ +#define R0900_STRSTATUS1 0xf16a +#define F0900_STRSTATUS_SEL2 0xf16a00f0 +#define F0900_STRSTATUS_SEL1 0xf16a000f + +/*STRSTATUS2*/ +#define R0900_STRSTATUS2 0xf16b +#define F0900_STRSTATUS_SEL4 0xf16b00f0 +#define F0900_STRSTATUS_SEL3 0xf16b000f + +/*STRSTATUS3*/ +#define R0900_STRSTATUS3 0xf16c +#define F0900_STRSTATUS_SEL6 0xf16c00f0 +#define F0900_STRSTATUS_SEL5 0xf16c000f + +/*FSKTFC2*/ +#define R0900_FSKTFC2 0xf170 +#define F0900_FSKT_KMOD 0xf17000fc +#define F0900_FSKT_CAR2 0xf1700003 + +/*FSKTFC1*/ +#define R0900_FSKTFC1 0xf171 +#define F0900_FSKT_CAR1 0xf17100ff + +/*FSKTFC0*/ +#define R0900_FSKTFC0 0xf172 +#define F0900_FSKT_CAR0 0xf17200ff + +/*FSKTDELTAF1*/ +#define R0900_FSKTDELTAF1 0xf173 +#define F0900_FSKT_DELTAF1 0xf173000f + +/*FSKTDELTAF0*/ +#define R0900_FSKTDELTAF0 0xf174 +#define F0900_FSKT_DELTAF0 0xf17400ff + +/*FSKTCTRL*/ +#define R0900_FSKTCTRL 0xf175 +#define F0900_FSKT_EN_SGN 0xf1750040 +#define F0900_FSKT_MOD_SGN 0xf1750020 +#define F0900_FSKT_MOD_EN 0xf175001c +#define F0900_FSKT_DACMODE 0xf1750003 + +/*FSKRFC2*/ +#define R0900_FSKRFC2 0xf176 +#define F0900_FSKR_DETSGN 0xf1760040 +#define F0900_FSKR_OUTSGN 0xf1760020 +#define F0900_FSKR_KAGC 0xf176001c +#define F0900_FSKR_CAR2 0xf1760003 + +/*FSKRFC1*/ +#define R0900_FSKRFC1 0xf177 +#define F0900_FSKR_CAR1 0xf17700ff + +/*FSKRFC0*/ +#define R0900_FSKRFC0 0xf178 +#define F0900_FSKR_CAR0 0xf17800ff + +/*FSKRK1*/ +#define R0900_FSKRK1 0xf179 +#define F0900_FSKR_K1_EXP 0xf17900e0 +#define F0900_FSKR_K1_MANT 0xf179001f + +/*FSKRK2*/ +#define R0900_FSKRK2 0xf17a +#define F0900_FSKR_K2_EXP 0xf17a00e0 +#define F0900_FSKR_K2_MANT 0xf17a001f + +/*FSKRAGCR*/ +#define R0900_FSKRAGCR 0xf17b +#define F0900_FSKR_OUTCTL 0xf17b00c0 +#define F0900_FSKR_AGC_REF 0xf17b003f + +/*FSKRAGC*/ +#define R0900_FSKRAGC 0xf17c +#define F0900_FSKR_AGC_ACCU 0xf17c00ff + +/*FSKRALPHA*/ +#define R0900_FSKRALPHA 0xf17d +#define F0900_FSKR_ALPHA_EXP 0xf17d001c +#define F0900_FSKR_ALPHA_M 0xf17d0003 + +/*FSKRPLTH1*/ +#define R0900_FSKRPLTH1 0xf17e +#define F0900_FSKR_BETA 0xf17e00f0 +#define F0900_FSKR_PLL_TRESH1 0xf17e000f + +/*FSKRPLTH0*/ +#define R0900_FSKRPLTH0 0xf17f +#define F0900_FSKR_PLL_TRESH0 0xf17f00ff + +/*FSKRDF1*/ +#define R0900_FSKRDF1 0xf180 +#define F0900_FSKR_OUT 0xf1800080 +#define F0900_FSKR_DELTAF1 0xf180001f + +/*FSKRDF0*/ +#define R0900_FSKRDF0 0xf181 +#define F0900_FSKR_DELTAF0 0xf18100ff + +/*FSKRSTEPP*/ +#define R0900_FSKRSTEPP 0xf182 +#define F0900_FSKR_STEP_PLUS 0xf18200ff + +/*FSKRSTEPM*/ +#define R0900_FSKRSTEPM 0xf183 +#define F0900_FSKR_STEP_MINUS 0xf18300ff + +/*FSKRDET1*/ +#define R0900_FSKRDET1 0xf184 +#define F0900_FSKR_DETECT 0xf1840080 +#define F0900_FSKR_CARDET_ACCU1 0xf184000f + +/*FSKRDET0*/ +#define R0900_FSKRDET0 0xf185 +#define F0900_FSKR_CARDET_ACCU0 0xf18500ff + +/*FSKRDTH1*/ +#define R0900_FSKRDTH1 0xf186 +#define F0900_FSKR_CARLOSS_THRESH1 0xf18600f0 +#define F0900_FSKR_CARDET_THRESH1 0xf186000f + +/*FSKRDTH0*/ +#define R0900_FSKRDTH0 0xf187 +#define F0900_FSKR_CARDET_THRESH0 0xf18700ff + +/*FSKRLOSS*/ +#define R0900_FSKRLOSS 0xf188 +#define F0900_FSKR_CARLOSS_THRESH0 0xf18800ff + +/*P2_DISTXCTL*/ +#define R0900_P2_DISTXCTL 0xf190 +#define F0900_P2_TIM_OFF 0xf1900080 +#define F0900_P2_DISEQC_RESET 0xf1900040 +#define F0900_P2_TIM_CMD 0xf1900030 +#define F0900_P2_DIS_PRECHARGE 0xf1900008 +#define F0900_P2_DISTX_MODE 0xf1900007 + +/*P2_DISRXCTL*/ +#define R0900_P2_DISRXCTL 0xf191 +#define F0900_P2_RECEIVER_ON 0xf1910080 +#define F0900_P2_IGNO_SHORT22K 0xf1910040 +#define F0900_P2_ONECHIP_TRX 0xf1910020 +#define F0900_P2_EXT_ENVELOP 0xf1910010 +#define F0900_P2_PIN_SELECT0 0xf191000c +#define F0900_P2_IRQ_RXEND 0xf1910002 +#define F0900_P2_IRQ_4NBYTES 0xf1910001 + +/*P2_DISRX_ST0*/ +#define R0900_P2_DISRX_ST0 0xf194 +#define F0900_P2_RX_END 0xf1940080 +#define F0900_P2_RX_ACTIVE 0xf1940040 +#define F0900_P2_SHORT_22KHZ 0xf1940020 +#define F0900_P2_CONT_TONE 0xf1940010 +#define F0900_P2_FIFO_4BREADY 0xf1940008 +#define F0900_P2_FIFO_EMPTY 0xf1940004 +#define F0900_P2_ABORT_DISRX 0xf1940001 + +/*P2_DISRX_ST1*/ +#define R0900_P2_DISRX_ST1 0xf195 +#define F0900_P2_RX_FAIL 0xf1950080 +#define F0900_P2_FIFO_PARITYFAIL 0xf1950040 +#define F0900_P2_RX_NONBYTE 0xf1950020 +#define F0900_P2_FIFO_OVERFLOW 0xf1950010 +#define F0900_P2_FIFO_BYTENBR 0xf195000f + +/*P2_DISRXDATA*/ +#define R0900_P2_DISRXDATA 0xf196 +#define F0900_P2_DISRX_DATA 0xf19600ff + +/*P2_DISTXDATA*/ +#define R0900_P2_DISTXDATA 0xf197 +#define F0900_P2_DISEQC_FIFO 0xf19700ff + +/*P2_DISTXSTATUS*/ +#define R0900_P2_DISTXSTATUS 0xf198 +#define F0900_P2_TX_FAIL 0xf1980080 +#define F0900_P2_FIFO_FULL 0xf1980040 +#define F0900_P2_TX_IDLE 0xf1980020 +#define F0900_P2_GAP_BURST 0xf1980010 +#define F0900_P2_TXFIFO_BYTES 0xf198000f + +/*P2_F22TX*/ +#define R0900_P2_F22TX 0xf199 +#define F0900_P2_F22_REG 0xf19900ff + +/*P2_F22RX*/ +#define R0900_P2_F22RX 0xf19a +#define F0900_P2_F22RX_REG 0xf19a00ff + +/*P2_ACRPRESC*/ +#define R0900_P2_ACRPRESC 0xf19c +#define F0900_P2_ACR_PRESC 0xf19c0007 + +/*P2_ACRDIV*/ +#define R0900_P2_ACRDIV 0xf19d +#define F0900_P2_ACR_DIV 0xf19d00ff + +/*P1_DISTXCTL*/ +#define R0900_P1_DISTXCTL 0xf1a0 +#define DISTXCTL shiftx(R0900_P1_DISTXCTL, demod, 0x10) +#define F0900_P1_TIM_OFF 0xf1a00080 +#define F0900_P1_DISEQC_RESET 0xf1a00040 +#define DISEQC_RESET shiftx(F0900_P1_DISEQC_RESET, demod, 0x100000) +#define F0900_P1_TIM_CMD 0xf1a00030 +#define F0900_P1_DIS_PRECHARGE 0xf1a00008 +#define DIS_PRECHARGE shiftx(F0900_P1_DIS_PRECHARGE, demod, 0x100000) +#define F0900_P1_DISTX_MODE 0xf1a00007 +#define DISTX_MODE shiftx(F0900_P1_DISTX_MODE, demod, 0x100000) + +/*P1_DISRXCTL*/ +#define R0900_P1_DISRXCTL 0xf1a1 +#define DISRXCTL shiftx(R0900_P1_DISRXCTL, demod, 0x10) +#define F0900_P1_RECEIVER_ON 0xf1a10080 +#define F0900_P1_IGNO_SHORT22K 0xf1a10040 +#define F0900_P1_ONECHIP_TRX 0xf1a10020 +#define F0900_P1_EXT_ENVELOP 0xf1a10010 +#define F0900_P1_PIN_SELECT0 0xf1a1000c +#define F0900_P1_IRQ_RXEND 0xf1a10002 +#define F0900_P1_IRQ_4NBYTES 0xf1a10001 + +/*P1_DISRX_ST0*/ +#define R0900_P1_DISRX_ST0 0xf1a4 +#define DISRX_ST0 shiftx(R0900_P1_DISRX_ST0, demod, 0x10) +#define F0900_P1_RX_END 0xf1a40080 +#define RX_END shiftx(F0900_P1_RX_END, demod, 0x100000) +#define F0900_P1_RX_ACTIVE 0xf1a40040 +#define F0900_P1_SHORT_22KHZ 0xf1a40020 +#define F0900_P1_CONT_TONE 0xf1a40010 +#define F0900_P1_FIFO_4BREADY 0xf1a40008 +#define F0900_P1_FIFO_EMPTY 0xf1a40004 +#define F0900_P1_ABORT_DISRX 0xf1a40001 + +/*P1_DISRX_ST1*/ +#define R0900_P1_DISRX_ST1 0xf1a5 +#define DISRX_ST1 shiftx(R0900_P1_DISRX_ST1, demod, 0x10) +#define F0900_P1_RX_FAIL 0xf1a50080 +#define F0900_P1_FIFO_PARITYFAIL 0xf1a50040 +#define F0900_P1_RX_NONBYTE 0xf1a50020 +#define F0900_P1_FIFO_OVERFLOW 0xf1a50010 +#define F0900_P1_FIFO_BYTENBR 0xf1a5000f +#define FIFO_BYTENBR shiftx(F0900_P1_FIFO_BYTENBR, demod, 0x100000) + +/*P1_DISRXDATA*/ +#define R0900_P1_DISRXDATA 0xf1a6 +#define DISRXDATA shiftx(R0900_P1_DISRXDATA, demod, 0x10) +#define F0900_P1_DISRX_DATA 0xf1a600ff + +/*P1_DISTXDATA*/ +#define R0900_P1_DISTXDATA 0xf1a7 +#define DISTXDATA shiftx(R0900_P1_DISTXDATA, demod, 0x10) +#define F0900_P1_DISEQC_FIFO 0xf1a700ff + +/*P1_DISTXSTATUS*/ +#define R0900_P1_DISTXSTATUS 0xf1a8 +#define F0900_P1_TX_FAIL 0xf1a80080 +#define F0900_P1_FIFO_FULL 0xf1a80040 +#define FIFO_FULL shiftx(F0900_P1_FIFO_FULL, demod, 0x100000) +#define F0900_P1_TX_IDLE 0xf1a80020 +#define TX_IDLE shiftx(F0900_P1_TX_IDLE, demod, 0x100000) +#define F0900_P1_GAP_BURST 0xf1a80010 +#define F0900_P1_TXFIFO_BYTES 0xf1a8000f + +/*P1_F22TX*/ +#define R0900_P1_F22TX 0xf1a9 +#define F22TX shiftx(R0900_P1_F22TX, demod, 0x10) +#define F0900_P1_F22_REG 0xf1a900ff + +/*P1_F22RX*/ +#define R0900_P1_F22RX 0xf1aa +#define F22RX shiftx(R0900_P1_F22RX, demod, 0x10) +#define F0900_P1_F22RX_REG 0xf1aa00ff + +/*P1_ACRPRESC*/ +#define R0900_P1_ACRPRESC 0xf1ac +#define ACRPRESC shiftx(R0900_P1_ACRPRESC, demod, 0x10) +#define F0900_P1_ACR_PRESC 0xf1ac0007 + +/*P1_ACRDIV*/ +#define R0900_P1_ACRDIV 0xf1ad +#define ACRDIV shiftx(R0900_P1_ACRDIV, demod, 0x10) +#define F0900_P1_ACR_DIV 0xf1ad00ff + +/*NCOARSE*/ +#define R0900_NCOARSE 0xf1b3 +#define F0900_M_DIV 0xf1b300ff + +/*SYNTCTRL*/ +#define R0900_SYNTCTRL 0xf1b6 +#define F0900_STANDBY 0xf1b60080 +#define F0900_BYPASSPLLCORE 0xf1b60040 +#define F0900_SELX1RATIO 0xf1b60020 +#define F0900_STOP_PLL 0xf1b60008 +#define F0900_BYPASSPLLFSK 0xf1b60004 +#define F0900_SELOSCI 0xf1b60002 +#define F0900_BYPASSPLLADC 0xf1b60001 + +/*FILTCTRL*/ +#define R0900_FILTCTRL 0xf1b7 +#define F0900_INV_CLK135 0xf1b70080 +#define F0900_SEL_FSKCKDIV 0xf1b70004 +#define F0900_INV_CLKFSK 0xf1b70002 +#define F0900_BYPASS_APPLI 0xf1b70001 + +/*PLLSTAT*/ +#define R0900_PLLSTAT 0xf1b8 +#define F0900_PLLLOCK 0xf1b80001 + +/*STOPCLK1*/ +#define R0900_STOPCLK1 0xf1c2 +#define F0900_STOP_CLKPKDT2 0xf1c20040 +#define F0900_STOP_CLKPKDT1 0xf1c20020 +#define F0900_STOP_CLKFEC 0xf1c20010 +#define F0900_STOP_CLKADCI2 0xf1c20008 +#define F0900_INV_CLKADCI2 0xf1c20004 +#define F0900_STOP_CLKADCI1 0xf1c20002 +#define F0900_INV_CLKADCI1 0xf1c20001 + +/*STOPCLK2*/ +#define R0900_STOPCLK2 0xf1c3 +#define F0900_STOP_CLKSAMP2 0xf1c30010 +#define F0900_STOP_CLKSAMP1 0xf1c30008 +#define F0900_STOP_CLKVIT2 0xf1c30004 +#define F0900_STOP_CLKVIT1 0xf1c30002 +#define STOP_CLKVIT shiftx(F0900_STOP_CLKVIT1, demod, -2) +#define F0900_STOP_CLKTS 0xf1c30001 + +/*TSTTNR0*/ +#define R0900_TSTTNR0 0xf1df +#define F0900_SEL_FSK 0xf1df0080 +#define F0900_FSK_PON 0xf1df0004 + +/*TSTTNR1*/ +#define R0900_TSTTNR1 0xf1e0 +#define F0900_ADC1_PON 0xf1e00002 +#define F0900_ADC1_INMODE 0xf1e00001 + +/*TSTTNR2*/ +#define R0900_TSTTNR2 0xf1e1 +#define F0900_DISEQC1_PON 0xf1e10020 + +/*TSTTNR3*/ +#define R0900_TSTTNR3 0xf1e2 +#define F0900_ADC2_PON 0xf1e20002 +#define F0900_ADC2_INMODE 0xf1e20001 + +/*TSTTNR4*/ +#define R0900_TSTTNR4 0xf1e3 +#define F0900_DISEQC2_PON 0xf1e30020 + +/*P2_IQCONST*/ +#define R0900_P2_IQCONST 0xf200 +#define F0900_P2_CONSTEL_SELECT 0xf2000060 +#define F0900_P2_IQSYMB_SEL 0xf200001f + +/*P2_NOSCFG*/ +#define R0900_P2_NOSCFG 0xf201 +#define F0900_P2_DUMMYPL_NOSDATA 0xf2010020 +#define F0900_P2_NOSPLH_BETA 0xf2010018 +#define F0900_P2_NOSDATA_BETA 0xf2010007 + +/*P2_ISYMB*/ +#define R0900_P2_ISYMB 0xf202 +#define F0900_P2_I_SYMBOL 0xf20201ff + +/*P2_QSYMB*/ +#define R0900_P2_QSYMB 0xf203 +#define F0900_P2_Q_SYMBOL 0xf20301ff + +/*P2_AGC1CFG*/ +#define R0900_P2_AGC1CFG 0xf204 +#define F0900_P2_DC_FROZEN 0xf2040080 +#define F0900_P2_DC_CORRECT 0xf2040040 +#define F0900_P2_AMM_FROZEN 0xf2040020 +#define F0900_P2_AMM_CORRECT 0xf2040010 +#define F0900_P2_QUAD_FROZEN 0xf2040008 +#define F0900_P2_QUAD_CORRECT 0xf2040004 + +/*P2_AGC1CN*/ +#define R0900_P2_AGC1CN 0xf206 +#define F0900_P2_AGC1_LOCKED 0xf2060080 +#define F0900_P2_AGC1_MINPOWER 0xf2060010 +#define F0900_P2_AGCOUT_FAST 0xf2060008 +#define F0900_P2_AGCIQ_BETA 0xf2060007 + +/*P2_AGC1REF*/ +#define R0900_P2_AGC1REF 0xf207 +#define F0900_P2_AGCIQ_REF 0xf20700ff + +/*P2_IDCCOMP*/ +#define R0900_P2_IDCCOMP 0xf208 +#define F0900_P2_IAVERAGE_ADJ 0xf20801ff + +/*P2_QDCCOMP*/ +#define R0900_P2_QDCCOMP 0xf209 +#define F0900_P2_QAVERAGE_ADJ 0xf20901ff + +/*P2_POWERI*/ +#define R0900_P2_POWERI 0xf20a +#define F0900_P2_POWER_I 0xf20a00ff + +/*P2_POWERQ*/ +#define R0900_P2_POWERQ 0xf20b +#define F0900_P2_POWER_Q 0xf20b00ff + +/*P2_AGC1AMM*/ +#define R0900_P2_AGC1AMM 0xf20c +#define F0900_P2_AMM_VALUE 0xf20c00ff + +/*P2_AGC1QUAD*/ +#define R0900_P2_AGC1QUAD 0xf20d +#define F0900_P2_QUAD_VALUE 0xf20d01ff + +/*P2_AGCIQIN1*/ +#define R0900_P2_AGCIQIN1 0xf20e +#define F0900_P2_AGCIQ_VALUE1 0xf20e00ff + +/*P2_AGCIQIN0*/ +#define R0900_P2_AGCIQIN0 0xf20f +#define F0900_P2_AGCIQ_VALUE0 0xf20f00ff + +/*P2_DEMOD*/ +#define R0900_P2_DEMOD 0xf210 +#define F0900_P2_MANUALS2_ROLLOFF 0xf2100080 +#define F0900_P2_SPECINV_CONTROL 0xf2100030 +#define F0900_P2_FORCE_ENASAMP 0xf2100008 +#define F0900_P2_MANUALSX_ROLLOFF 0xf2100004 +#define F0900_P2_ROLLOFF_CONTROL 0xf2100003 + +/*P2_DMDMODCOD*/ +#define R0900_P2_DMDMODCOD 0xf211 +#define F0900_P2_MANUAL_MODCOD 0xf2110080 +#define F0900_P2_DEMOD_MODCOD 0xf211007c +#define F0900_P2_DEMOD_TYPE 0xf2110003 + +/*P2_DSTATUS*/ +#define R0900_P2_DSTATUS 0xf212 +#define F0900_P2_CAR_LOCK 0xf2120080 +#define F0900_P2_TMGLOCK_QUALITY 0xf2120060 +#define F0900_P2_LOCK_DEFINITIF 0xf2120008 +#define F0900_P2_OVADC_DETECT 0xf2120001 + +/*P2_DSTATUS2*/ +#define R0900_P2_DSTATUS2 0xf213 +#define F0900_P2_DEMOD_DELOCK 0xf2130080 +#define F0900_P2_AGC1_NOSIGNALACK 0xf2130008 +#define F0900_P2_AGC2_OVERFLOW 0xf2130004 +#define F0900_P2_CFR_OVERFLOW 0xf2130002 +#define F0900_P2_GAMMA_OVERUNDER 0xf2130001 + +/*P2_DMDCFGMD*/ +#define R0900_P2_DMDCFGMD 0xf214 +#define F0900_P2_DVBS2_ENABLE 0xf2140080 +#define F0900_P2_DVBS1_ENABLE 0xf2140040 +#define F0900_P2_SCAN_ENABLE 0xf2140010 +#define F0900_P2_CFR_AUTOSCAN 0xf2140008 +#define F0900_P2_TUN_RNG 0xf2140003 + +/*P2_DMDCFG2*/ +#define R0900_P2_DMDCFG2 0xf215 +#define F0900_P2_S1S2_SEQUENTIAL 0xf2150040 +#define F0900_P2_INFINITE_RELOCK 0xf2150010 + +/*P2_DMDISTATE*/ +#define R0900_P2_DMDISTATE 0xf216 +#define F0900_P2_I2C_DEMOD_MODE 0xf216001f + +/*P2_DMDT0M*/ +#define R0900_P2_DMDT0M 0xf217 +#define F0900_P2_DMDT0_MIN 0xf21700ff + +/*P2_DMDSTATE*/ +#define R0900_P2_DMDSTATE 0xf21b +#define F0900_P2_HEADER_MODE 0xf21b0060 + +/*P2_DMDFLYW*/ +#define R0900_P2_DMDFLYW 0xf21c +#define F0900_P2_I2C_IRQVAL 0xf21c00f0 +#define F0900_P2_FLYWHEEL_CPT 0xf21c000f + +/*P2_DSTATUS3*/ +#define R0900_P2_DSTATUS3 0xf21d +#define F0900_P2_DEMOD_CFGMODE 0xf21d0060 + +/*P2_DMDCFG3*/ +#define R0900_P2_DMDCFG3 0xf21e +#define F0900_P2_NOSTOP_FIFOFULL 0xf21e0008 + +/*P2_DMDCFG4*/ +#define R0900_P2_DMDCFG4 0xf21f +#define F0900_P2_TUNER_NRELAUNCH 0xf21f0008 + +/*P2_CORRELMANT*/ +#define R0900_P2_CORRELMANT 0xf220 +#define F0900_P2_CORREL_MANT 0xf22000ff + +/*P2_CORRELABS*/ +#define R0900_P2_CORRELABS 0xf221 +#define F0900_P2_CORREL_ABS 0xf22100ff + +/*P2_CORRELEXP*/ +#define R0900_P2_CORRELEXP 0xf222 +#define F0900_P2_CORREL_ABSEXP 0xf22200f0 +#define F0900_P2_CORREL_EXP 0xf222000f + +/*P2_PLHMODCOD*/ +#define R0900_P2_PLHMODCOD 0xf224 +#define F0900_P2_SPECINV_DEMOD 0xf2240080 +#define F0900_P2_PLH_MODCOD 0xf224007c +#define F0900_P2_PLH_TYPE 0xf2240003 + +/*P2_DMDREG*/ +#define R0900_P2_DMDREG 0xf225 +#define F0900_P2_DECIM_PLFRAMES 0xf2250001 + +/*P2_AGC2O*/ +#define R0900_P2_AGC2O 0xf22c +#define F0900_P2_AGC2_COEF 0xf22c0007 + +/*P2_AGC2REF*/ +#define R0900_P2_AGC2REF 0xf22d +#define F0900_P2_AGC2_REF 0xf22d00ff + +/*P2_AGC1ADJ*/ +#define R0900_P2_AGC1ADJ 0xf22e +#define F0900_P2_AGC1_ADJUSTED 0xf22e007f + +/*P2_AGC2I1*/ +#define R0900_P2_AGC2I1 0xf236 +#define F0900_P2_AGC2_INTEGRATOR1 0xf23600ff + +/*P2_AGC2I0*/ +#define R0900_P2_AGC2I0 0xf237 +#define F0900_P2_AGC2_INTEGRATOR0 0xf23700ff + +/*P2_CARCFG*/ +#define R0900_P2_CARCFG 0xf238 +#define F0900_P2_CFRUPLOW_AUTO 0xf2380080 +#define F0900_P2_CFRUPLOW_TEST 0xf2380040 +#define F0900_P2_ROTAON 0xf2380004 +#define F0900_P2_PH_DET_ALGO 0xf2380003 + +/*P2_ACLC*/ +#define R0900_P2_ACLC 0xf239 +#define F0900_P2_CAR_ALPHA_MANT 0xf2390030 +#define F0900_P2_CAR_ALPHA_EXP 0xf239000f + +/*P2_BCLC*/ +#define R0900_P2_BCLC 0xf23a +#define F0900_P2_CAR_BETA_MANT 0xf23a0030 +#define F0900_P2_CAR_BETA_EXP 0xf23a000f + +/*P2_CARFREQ*/ +#define R0900_P2_CARFREQ 0xf23d +#define F0900_P2_KC_COARSE_EXP 0xf23d00f0 +#define F0900_P2_BETA_FREQ 0xf23d000f + +/*P2_CARHDR*/ +#define R0900_P2_CARHDR 0xf23e +#define F0900_P2_K_FREQ_HDR 0xf23e00ff + +/*P2_LDT*/ +#define R0900_P2_LDT 0xf23f +#define F0900_P2_CARLOCK_THRES 0xf23f01ff + +/*P2_LDT2*/ +#define R0900_P2_LDT2 0xf240 +#define F0900_P2_CARLOCK_THRES2 0xf24001ff + +/*P2_CFRICFG*/ +#define R0900_P2_CFRICFG 0xf241 +#define F0900_P2_NEG_CFRSTEP 0xf2410001 + +/*P2_CFRUP1*/ +#define R0900_P2_CFRUP1 0xf242 +#define F0900_P2_CFR_UP1 0xf24201ff + +/*P2_CFRUP0*/ +#define R0900_P2_CFRUP0 0xf243 +#define F0900_P2_CFR_UP0 0xf24300ff + +/*P2_CFRLOW1*/ +#define R0900_P2_CFRLOW1 0xf246 +#define F0900_P2_CFR_LOW1 0xf24601ff + +/*P2_CFRLOW0*/ +#define R0900_P2_CFRLOW0 0xf247 +#define F0900_P2_CFR_LOW0 0xf24700ff + +/*P2_CFRINIT1*/ +#define R0900_P2_CFRINIT1 0xf248 +#define F0900_P2_CFR_INIT1 0xf24801ff + +/*P2_CFRINIT0*/ +#define R0900_P2_CFRINIT0 0xf249 +#define F0900_P2_CFR_INIT0 0xf24900ff + +/*P2_CFRINC1*/ +#define R0900_P2_CFRINC1 0xf24a +#define F0900_P2_MANUAL_CFRINC 0xf24a0080 +#define F0900_P2_CFR_INC1 0xf24a003f + +/*P2_CFRINC0*/ +#define R0900_P2_CFRINC0 0xf24b +#define F0900_P2_CFR_INC0 0xf24b00f8 + +/*P2_CFR2*/ +#define R0900_P2_CFR2 0xf24c +#define F0900_P2_CAR_FREQ2 0xf24c01ff + +/*P2_CFR1*/ +#define R0900_P2_CFR1 0xf24d +#define F0900_P2_CAR_FREQ1 0xf24d00ff + +/*P2_CFR0*/ +#define R0900_P2_CFR0 0xf24e +#define F0900_P2_CAR_FREQ0 0xf24e00ff + +/*P2_LDI*/ +#define R0900_P2_LDI 0xf24f +#define F0900_P2_LOCK_DET_INTEGR 0xf24f01ff + +/*P2_TMGCFG*/ +#define R0900_P2_TMGCFG 0xf250 +#define F0900_P2_TMGLOCK_BETA 0xf25000c0 +#define F0900_P2_DO_TIMING_CORR 0xf2500010 +#define F0900_P2_TMG_MINFREQ 0xf2500003 + +/*P2_RTC*/ +#define R0900_P2_RTC 0xf251 +#define F0900_P2_TMGALPHA_EXP 0xf25100f0 +#define F0900_P2_TMGBETA_EXP 0xf251000f + +/*P2_RTCS2*/ +#define R0900_P2_RTCS2 0xf252 +#define F0900_P2_TMGALPHAS2_EXP 0xf25200f0 +#define F0900_P2_TMGBETAS2_EXP 0xf252000f + +/*P2_TMGTHRISE*/ +#define R0900_P2_TMGTHRISE 0xf253 +#define F0900_P2_TMGLOCK_THRISE 0xf25300ff + +/*P2_TMGTHFALL*/ +#define R0900_P2_TMGTHFALL 0xf254 +#define F0900_P2_TMGLOCK_THFALL 0xf25400ff + +/*P2_SFRUPRATIO*/ +#define R0900_P2_SFRUPRATIO 0xf255 +#define F0900_P2_SFR_UPRATIO 0xf25500ff + +/*P2_SFRLOWRATIO*/ +#define R0900_P2_SFRLOWRATIO 0xf256 +#define F0900_P2_SFR_LOWRATIO 0xf25600ff + +/*P2_KREFTMG*/ +#define R0900_P2_KREFTMG 0xf258 +#define F0900_P2_KREF_TMG 0xf25800ff + +/*P2_SFRSTEP*/ +#define R0900_P2_SFRSTEP 0xf259 +#define F0900_P2_SFR_SCANSTEP 0xf25900f0 +#define F0900_P2_SFR_CENTERSTEP 0xf259000f + +/*P2_TMGCFG2*/ +#define R0900_P2_TMGCFG2 0xf25a +#define F0900_P2_SFRRATIO_FINE 0xf25a0001 + +/*P2_KREFTMG2*/ +#define R0900_P2_KREFTMG2 0xf25b +#define F0900_P2_KREF_TMG2 0xf25b00ff + +/*P2_SFRINIT1*/ +#define R0900_P2_SFRINIT1 0xf25e +#define F0900_P2_SFR_INIT1 0xf25e007f + +/*P2_SFRINIT0*/ +#define R0900_P2_SFRINIT0 0xf25f +#define F0900_P2_SFR_INIT0 0xf25f00ff + +/*P2_SFRUP1*/ +#define R0900_P2_SFRUP1 0xf260 +#define F0900_P2_AUTO_GUP 0xf2600080 +#define F0900_P2_SYMB_FREQ_UP1 0xf260007f + +/*P2_SFRUP0*/ +#define R0900_P2_SFRUP0 0xf261 +#define F0900_P2_SYMB_FREQ_UP0 0xf26100ff + +/*P2_SFRLOW1*/ +#define R0900_P2_SFRLOW1 0xf262 +#define F0900_P2_AUTO_GLOW 0xf2620080 +#define F0900_P2_SYMB_FREQ_LOW1 0xf262007f + +/*P2_SFRLOW0*/ +#define R0900_P2_SFRLOW0 0xf263 +#define F0900_P2_SYMB_FREQ_LOW0 0xf26300ff + +/*P2_SFR3*/ +#define R0900_P2_SFR3 0xf264 +#define F0900_P2_SYMB_FREQ3 0xf26400ff + +/*P2_SFR2*/ +#define R0900_P2_SFR2 0xf265 +#define F0900_P2_SYMB_FREQ2 0xf26500ff + +/*P2_SFR1*/ +#define R0900_P2_SFR1 0xf266 +#define F0900_P2_SYMB_FREQ1 0xf26600ff + +/*P2_SFR0*/ +#define R0900_P2_SFR0 0xf267 +#define F0900_P2_SYMB_FREQ0 0xf26700ff + +/*P2_TMGREG2*/ +#define R0900_P2_TMGREG2 0xf268 +#define F0900_P2_TMGREG2 0xf26800ff + +/*P2_TMGREG1*/ +#define R0900_P2_TMGREG1 0xf269 +#define F0900_P2_TMGREG1 0xf26900ff + +/*P2_TMGREG0*/ +#define R0900_P2_TMGREG0 0xf26a +#define F0900_P2_TMGREG0 0xf26a00ff + +/*P2_TMGLOCK1*/ +#define R0900_P2_TMGLOCK1 0xf26b +#define F0900_P2_TMGLOCK_LEVEL1 0xf26b01ff + +/*P2_TMGLOCK0*/ +#define R0900_P2_TMGLOCK0 0xf26c +#define F0900_P2_TMGLOCK_LEVEL0 0xf26c00ff + +/*P2_TMGOBS*/ +#define R0900_P2_TMGOBS 0xf26d +#define F0900_P2_ROLLOFF_STATUS 0xf26d00c0 + +/*P2_EQUALCFG*/ +#define R0900_P2_EQUALCFG 0xf26f +#define F0900_P2_EQUAL_ON 0xf26f0040 +#define F0900_P2_MU_EQUALDFE 0xf26f0007 + +/*P2_EQUAI1*/ +#define R0900_P2_EQUAI1 0xf270 +#define F0900_P2_EQUA_ACCI1 0xf27001ff + +/*P2_EQUAQ1*/ +#define R0900_P2_EQUAQ1 0xf271 +#define F0900_P2_EQUA_ACCQ1 0xf27101ff + +/*P2_EQUAI2*/ +#define R0900_P2_EQUAI2 0xf272 +#define F0900_P2_EQUA_ACCI2 0xf27201ff + +/*P2_EQUAQ2*/ +#define R0900_P2_EQUAQ2 0xf273 +#define F0900_P2_EQUA_ACCQ2 0xf27301ff + +/*P2_EQUAI3*/ +#define R0900_P2_EQUAI3 0xf274 +#define F0900_P2_EQUA_ACCI3 0xf27401ff + +/*P2_EQUAQ3*/ +#define R0900_P2_EQUAQ3 0xf275 +#define F0900_P2_EQUA_ACCQ3 0xf27501ff + +/*P2_EQUAI4*/ +#define R0900_P2_EQUAI4 0xf276 +#define F0900_P2_EQUA_ACCI4 0xf27601ff + +/*P2_EQUAQ4*/ +#define R0900_P2_EQUAQ4 0xf277 +#define F0900_P2_EQUA_ACCQ4 0xf27701ff + +/*P2_EQUAI5*/ +#define R0900_P2_EQUAI5 0xf278 +#define F0900_P2_EQUA_ACCI5 0xf27801ff + +/*P2_EQUAQ5*/ +#define R0900_P2_EQUAQ5 0xf279 +#define F0900_P2_EQUA_ACCQ5 0xf27901ff + +/*P2_EQUAI6*/ +#define R0900_P2_EQUAI6 0xf27a +#define F0900_P2_EQUA_ACCI6 0xf27a01ff + +/*P2_EQUAQ6*/ +#define R0900_P2_EQUAQ6 0xf27b +#define F0900_P2_EQUA_ACCQ6 0xf27b01ff + +/*P2_EQUAI7*/ +#define R0900_P2_EQUAI7 0xf27c +#define F0900_P2_EQUA_ACCI7 0xf27c01ff + +/*P2_EQUAQ7*/ +#define R0900_P2_EQUAQ7 0xf27d +#define F0900_P2_EQUA_ACCQ7 0xf27d01ff + +/*P2_EQUAI8*/ +#define R0900_P2_EQUAI8 0xf27e +#define F0900_P2_EQUA_ACCI8 0xf27e01ff + +/*P2_EQUAQ8*/ +#define R0900_P2_EQUAQ8 0xf27f +#define F0900_P2_EQUA_ACCQ8 0xf27f01ff + +/*P2_NNOSDATAT1*/ +#define R0900_P2_NNOSDATAT1 0xf280 +#define F0900_P2_NOSDATAT_NORMED1 0xf28000ff + +/*P2_NNOSDATAT0*/ +#define R0900_P2_NNOSDATAT0 0xf281 +#define F0900_P2_NOSDATAT_NORMED0 0xf28100ff + +/*P2_NNOSDATA1*/ +#define R0900_P2_NNOSDATA1 0xf282 +#define F0900_P2_NOSDATA_NORMED1 0xf28200ff + +/*P2_NNOSDATA0*/ +#define R0900_P2_NNOSDATA0 0xf283 +#define F0900_P2_NOSDATA_NORMED0 0xf28300ff + +/*P2_NNOSPLHT1*/ +#define R0900_P2_NNOSPLHT1 0xf284 +#define F0900_P2_NOSPLHT_NORMED1 0xf28400ff + +/*P2_NNOSPLHT0*/ +#define R0900_P2_NNOSPLHT0 0xf285 +#define F0900_P2_NOSPLHT_NORMED0 0xf28500ff + +/*P2_NNOSPLH1*/ +#define R0900_P2_NNOSPLH1 0xf286 +#define F0900_P2_NOSPLH_NORMED1 0xf28600ff + +/*P2_NNOSPLH0*/ +#define R0900_P2_NNOSPLH0 0xf287 +#define F0900_P2_NOSPLH_NORMED0 0xf28700ff + +/*P2_NOSDATAT1*/ +#define R0900_P2_NOSDATAT1 0xf288 +#define F0900_P2_NOSDATAT_UNNORMED1 0xf28800ff + +/*P2_NOSDATAT0*/ +#define R0900_P2_NOSDATAT0 0xf289 +#define F0900_P2_NOSDATAT_UNNORMED0 0xf28900ff + +/*P2_NOSDATA1*/ +#define R0900_P2_NOSDATA1 0xf28a +#define F0900_P2_NOSDATA_UNNORMED1 0xf28a00ff + +/*P2_NOSDATA0*/ +#define R0900_P2_NOSDATA0 0xf28b +#define F0900_P2_NOSDATA_UNNORMED0 0xf28b00ff + +/*P2_NOSPLHT1*/ +#define R0900_P2_NOSPLHT1 0xf28c +#define F0900_P2_NOSPLHT_UNNORMED1 0xf28c00ff + +/*P2_NOSPLHT0*/ +#define R0900_P2_NOSPLHT0 0xf28d +#define F0900_P2_NOSPLHT_UNNORMED0 0xf28d00ff + +/*P2_NOSPLH1*/ +#define R0900_P2_NOSPLH1 0xf28e +#define F0900_P2_NOSPLH_UNNORMED1 0xf28e00ff + +/*P2_NOSPLH0*/ +#define R0900_P2_NOSPLH0 0xf28f +#define F0900_P2_NOSPLH_UNNORMED0 0xf28f00ff + +/*P2_CAR2CFG*/ +#define R0900_P2_CAR2CFG 0xf290 +#define F0900_P2_CARRIER3_DISABLE 0xf2900040 +#define F0900_P2_ROTA2ON 0xf2900004 +#define F0900_P2_PH_DET_ALGO2 0xf2900003 + +/*P2_CFR2CFR1*/ +#define R0900_P2_CFR2CFR1 0xf291 +#define F0900_P2_CFR2TOCFR1_DVBS1 0xf29100c0 +#define F0900_P2_EN_S2CAR2CENTER 0xf2910020 +#define F0900_P2_DIS_BCHERRCFR2 0xf2910010 +#define F0900_P2_CFR2TOCFR1_BETA 0xf2910007 + +/*P2_CFR22*/ +#define R0900_P2_CFR22 0xf293 +#define F0900_P2_CAR2_FREQ2 0xf29301ff + +/*P2_CFR21*/ +#define R0900_P2_CFR21 0xf294 +#define F0900_P2_CAR2_FREQ1 0xf29400ff + +/*P2_CFR20*/ +#define R0900_P2_CFR20 0xf295 +#define F0900_P2_CAR2_FREQ0 0xf29500ff + +/*P2_ACLC2S2Q*/ +#define R0900_P2_ACLC2S2Q 0xf297 +#define F0900_P2_ENAB_SPSKSYMB 0xf2970080 +#define F0900_P2_CAR2S2_Q_ALPH_M 0xf2970030 +#define F0900_P2_CAR2S2_Q_ALPH_E 0xf297000f + +/*P2_ACLC2S28*/ +#define R0900_P2_ACLC2S28 0xf298 +#define F0900_P2_OLDI3Q_MODE 0xf2980080 +#define F0900_P2_CAR2S2_8_ALPH_M 0xf2980030 +#define F0900_P2_CAR2S2_8_ALPH_E 0xf298000f + +/*P2_ACLC2S216A*/ +#define R0900_P2_ACLC2S216A 0xf299 +#define F0900_P2_DIS_C3STOPA2 0xf2990080 +#define F0900_P2_CAR2S2_16ADERAT 0xf2990040 +#define F0900_P2_CAR2S2_16A_ALPH_M 0xf2990030 +#define F0900_P2_CAR2S2_16A_ALPH_E 0xf299000f + +/*P2_ACLC2S232A*/ +#define R0900_P2_ACLC2S232A 0xf29a +#define F0900_P2_CAR2S2_32ADERAT 0xf29a0040 +#define F0900_P2_CAR2S2_32A_ALPH_M 0xf29a0030 +#define F0900_P2_CAR2S2_32A_ALPH_E 0xf29a000f + +/*P2_BCLC2S2Q*/ +#define R0900_P2_BCLC2S2Q 0xf29c +#define F0900_P2_CAR2S2_Q_BETA_M 0xf29c0030 +#define F0900_P2_CAR2S2_Q_BETA_E 0xf29c000f + +/*P2_BCLC2S28*/ +#define R0900_P2_BCLC2S28 0xf29d +#define F0900_P2_CAR2S2_8_BETA_M 0xf29d0030 +#define F0900_P2_CAR2S2_8_BETA_E 0xf29d000f + +/*P2_BCLC2S216A*/ +#define R0900_P2_BCLC2S216A 0xf29e + +/*P2_BCLC2S232A*/ +#define R0900_P2_BCLC2S232A 0xf29f + +/*P2_PLROOT2*/ +#define R0900_P2_PLROOT2 0xf2ac +#define F0900_P2_PLSCRAMB_MODE 0xf2ac000c +#define F0900_P2_PLSCRAMB_ROOT2 0xf2ac0003 + +/*P2_PLROOT1*/ +#define R0900_P2_PLROOT1 0xf2ad +#define F0900_P2_PLSCRAMB_ROOT1 0xf2ad00ff + +/*P2_PLROOT0*/ +#define R0900_P2_PLROOT0 0xf2ae +#define F0900_P2_PLSCRAMB_ROOT0 0xf2ae00ff + +/*P2_MODCODLST0*/ +#define R0900_P2_MODCODLST0 0xf2b0 + +/*P2_MODCODLST1*/ +#define R0900_P2_MODCODLST1 0xf2b1 +#define F0900_P2_DIS_MODCOD29 0xf2b100f0 +#define F0900_P2_DIS_32PSK_9_10 0xf2b1000f + +/*P2_MODCODLST2*/ +#define R0900_P2_MODCODLST2 0xf2b2 +#define F0900_P2_DIS_32PSK_8_9 0xf2b200f0 +#define F0900_P2_DIS_32PSK_5_6 0xf2b2000f + +/*P2_MODCODLST3*/ +#define R0900_P2_MODCODLST3 0xf2b3 +#define F0900_P2_DIS_32PSK_4_5 0xf2b300f0 +#define F0900_P2_DIS_32PSK_3_4 0xf2b3000f + +/*P2_MODCODLST4*/ +#define R0900_P2_MODCODLST4 0xf2b4 +#define F0900_P2_DIS_16PSK_9_10 0xf2b400f0 +#define F0900_P2_DIS_16PSK_8_9 0xf2b4000f + +/*P2_MODCODLST5*/ +#define R0900_P2_MODCODLST5 0xf2b5 +#define F0900_P2_DIS_16PSK_5_6 0xf2b500f0 +#define F0900_P2_DIS_16PSK_4_5 0xf2b5000f + +/*P2_MODCODLST6*/ +#define R0900_P2_MODCODLST6 0xf2b6 +#define F0900_P2_DIS_16PSK_3_4 0xf2b600f0 +#define F0900_P2_DIS_16PSK_2_3 0xf2b6000f + +/*P2_MODCODLST7*/ +#define R0900_P2_MODCODLST7 0xf2b7 +#define F0900_P2_DIS_8P_9_10 0xf2b700f0 +#define F0900_P2_DIS_8P_8_9 0xf2b7000f + +/*P2_MODCODLST8*/ +#define R0900_P2_MODCODLST8 0xf2b8 +#define F0900_P2_DIS_8P_5_6 0xf2b800f0 +#define F0900_P2_DIS_8P_3_4 0xf2b8000f + +/*P2_MODCODLST9*/ +#define R0900_P2_MODCODLST9 0xf2b9 +#define F0900_P2_DIS_8P_2_3 0xf2b900f0 +#define F0900_P2_DIS_8P_3_5 0xf2b9000f + +/*P2_MODCODLSTA*/ +#define R0900_P2_MODCODLSTA 0xf2ba +#define F0900_P2_DIS_QP_9_10 0xf2ba00f0 +#define F0900_P2_DIS_QP_8_9 0xf2ba000f + +/*P2_MODCODLSTB*/ +#define R0900_P2_MODCODLSTB 0xf2bb +#define F0900_P2_DIS_QP_5_6 0xf2bb00f0 +#define F0900_P2_DIS_QP_4_5 0xf2bb000f + +/*P2_MODCODLSTC*/ +#define R0900_P2_MODCODLSTC 0xf2bc +#define F0900_P2_DIS_QP_3_4 0xf2bc00f0 +#define F0900_P2_DIS_QP_2_3 0xf2bc000f + +/*P2_MODCODLSTD*/ +#define R0900_P2_MODCODLSTD 0xf2bd +#define F0900_P2_DIS_QP_3_5 0xf2bd00f0 +#define F0900_P2_DIS_QP_1_2 0xf2bd000f + +/*P2_MODCODLSTE*/ +#define R0900_P2_MODCODLSTE 0xf2be +#define F0900_P2_DIS_QP_2_5 0xf2be00f0 +#define F0900_P2_DIS_QP_1_3 0xf2be000f + +/*P2_MODCODLSTF*/ +#define R0900_P2_MODCODLSTF 0xf2bf +#define F0900_P2_DIS_QP_1_4 0xf2bf00f0 + +/*P2_GAUSSR0*/ +#define R0900_P2_GAUSSR0 0xf2c0 +#define F0900_P2_EN_CCIMODE 0xf2c00080 +#define F0900_P2_R0_GAUSSIEN 0xf2c0007f + +/*P2_CCIR0*/ +#define R0900_P2_CCIR0 0xf2c1 +#define F0900_P2_CCIDETECT_PLHONLY 0xf2c10080 +#define F0900_P2_R0_CCI 0xf2c1007f + +/*P2_CCIQUANT*/ +#define R0900_P2_CCIQUANT 0xf2c2 +#define F0900_P2_CCI_BETA 0xf2c200e0 +#define F0900_P2_CCI_QUANT 0xf2c2001f + +/*P2_CCITHRES*/ +#define R0900_P2_CCITHRES 0xf2c3 +#define F0900_P2_CCI_THRESHOLD 0xf2c300ff + +/*P2_CCIACC*/ +#define R0900_P2_CCIACC 0xf2c4 +#define F0900_P2_CCI_VALUE 0xf2c400ff + +/*P2_DMDRESCFG*/ +#define R0900_P2_DMDRESCFG 0xf2c6 +#define F0900_P2_DMDRES_RESET 0xf2c60080 +#define F0900_P2_DMDRES_STRALL 0xf2c60008 +#define F0900_P2_DMDRES_NEWONLY 0xf2c60004 +#define F0900_P2_DMDRES_NOSTORE 0xf2c60002 + +/*P2_DMDRESADR*/ +#define R0900_P2_DMDRESADR 0xf2c7 +#define F0900_P2_DMDRES_VALIDCFR 0xf2c70040 +#define F0900_P2_DMDRES_MEMFULL 0xf2c70030 +#define F0900_P2_DMDRES_RESNBR 0xf2c7000f + +/*P2_DMDRESDATA7*/ +#define R0900_P2_DMDRESDATA7 0xf2c8 +#define F0900_P2_DMDRES_DATA7 0xf2c800ff + +/*P2_DMDRESDATA6*/ +#define R0900_P2_DMDRESDATA6 0xf2c9 +#define F0900_P2_DMDRES_DATA6 0xf2c900ff + +/*P2_DMDRESDATA5*/ +#define R0900_P2_DMDRESDATA5 0xf2ca +#define F0900_P2_DMDRES_DATA5 0xf2ca00ff + +/*P2_DMDRESDATA4*/ +#define R0900_P2_DMDRESDATA4 0xf2cb +#define F0900_P2_DMDRES_DATA4 0xf2cb00ff + +/*P2_DMDRESDATA3*/ +#define R0900_P2_DMDRESDATA3 0xf2cc +#define F0900_P2_DMDRES_DATA3 0xf2cc00ff + +/*P2_DMDRESDATA2*/ +#define R0900_P2_DMDRESDATA2 0xf2cd +#define F0900_P2_DMDRES_DATA2 0xf2cd00ff + +/*P2_DMDRESDATA1*/ +#define R0900_P2_DMDRESDATA1 0xf2ce +#define F0900_P2_DMDRES_DATA1 0xf2ce00ff + +/*P2_DMDRESDATA0*/ +#define R0900_P2_DMDRESDATA0 0xf2cf +#define F0900_P2_DMDRES_DATA0 0xf2cf00ff + +/*P2_FFEI1*/ +#define R0900_P2_FFEI1 0xf2d0 +#define F0900_P2_FFE_ACCI1 0xf2d001ff + +/*P2_FFEQ1*/ +#define R0900_P2_FFEQ1 0xf2d1 +#define F0900_P2_FFE_ACCQ1 0xf2d101ff + +/*P2_FFEI2*/ +#define R0900_P2_FFEI2 0xf2d2 +#define F0900_P2_FFE_ACCI2 0xf2d201ff + +/*P2_FFEQ2*/ +#define R0900_P2_FFEQ2 0xf2d3 +#define F0900_P2_FFE_ACCQ2 0xf2d301ff + +/*P2_FFEI3*/ +#define R0900_P2_FFEI3 0xf2d4 +#define F0900_P2_FFE_ACCI3 0xf2d401ff + +/*P2_FFEQ3*/ +#define R0900_P2_FFEQ3 0xf2d5 +#define F0900_P2_FFE_ACCQ3 0xf2d501ff + +/*P2_FFEI4*/ +#define R0900_P2_FFEI4 0xf2d6 +#define F0900_P2_FFE_ACCI4 0xf2d601ff + +/*P2_FFEQ4*/ +#define R0900_P2_FFEQ4 0xf2d7 +#define F0900_P2_FFE_ACCQ4 0xf2d701ff + +/*P2_FFECFG*/ +#define R0900_P2_FFECFG 0xf2d8 +#define F0900_P2_EQUALFFE_ON 0xf2d80040 +#define F0900_P2_MU_EQUALFFE 0xf2d80007 + +/*P2_TNRCFG*/ +#define R0900_P2_TNRCFG 0xf2e0 +#define F0900_P2_TUN_ACKFAIL 0xf2e00080 +#define F0900_P2_TUN_TYPE 0xf2e00070 +#define F0900_P2_TUN_SECSTOP 0xf2e00008 +#define F0900_P2_TUN_VCOSRCH 0xf2e00004 +#define F0900_P2_TUN_MADDRESS 0xf2e00003 + +/*P2_TNRCFG2*/ +#define R0900_P2_TNRCFG2 0xf2e1 +#define F0900_P2_TUN_IQSWAP 0xf2e10080 +#define F0900_P2_DIS_BWCALC 0xf2e10004 +#define F0900_P2_SHORT_WAITSTATES 0xf2e10002 + +/*P2_TNRXTAL*/ +#define R0900_P2_TNRXTAL 0xf2e4 +#define F0900_P2_TUN_XTALFREQ 0xf2e4001f + +/*P2_TNRSTEPS*/ +#define R0900_P2_TNRSTEPS 0xf2e7 +#define F0900_P2_TUNER_BW0P125 0xf2e70080 +#define F0900_P2_BWINC_OFFSET 0xf2e70170 +#define F0900_P2_SOFTSTEP_RNG 0xf2e70008 +#define F0900_P2_TUN_BWOFFSET 0xf2e70007 + +/*P2_TNRGAIN*/ +#define R0900_P2_TNRGAIN 0xf2e8 +#define F0900_P2_TUN_KDIVEN 0xf2e800c0 +#define F0900_P2_STB6X00_OCK 0xf2e80030 +#define F0900_P2_TUN_GAIN 0xf2e8000f + +/*P2_TNRRF1*/ +#define R0900_P2_TNRRF1 0xf2e9 +#define F0900_P2_TUN_RFFREQ2 0xf2e900ff + +/*P2_TNRRF0*/ +#define R0900_P2_TNRRF0 0xf2ea +#define F0900_P2_TUN_RFFREQ1 0xf2ea00ff + +/*P2_TNRBW*/ +#define R0900_P2_TNRBW 0xf2eb +#define F0900_P2_TUN_RFFREQ0 0xf2eb00c0 +#define F0900_P2_TUN_BW 0xf2eb003f + +/*P2_TNRADJ*/ +#define R0900_P2_TNRADJ 0xf2ec +#define F0900_P2_STB61X0_CALTIME 0xf2ec0040 + +/*P2_TNRCTL2*/ +#define R0900_P2_TNRCTL2 0xf2ed +#define F0900_P2_STB61X0_RCCKOFF 0xf2ed0080 +#define F0900_P2_STB61X0_ICP_SDOFF 0xf2ed0040 +#define F0900_P2_STB61X0_DCLOOPOFF 0xf2ed0020 +#define F0900_P2_STB61X0_REFOUTSEL 0xf2ed0010 +#define F0900_P2_STB61X0_CALOFF 0xf2ed0008 +#define F0900_P2_STB6XX0_LPT_BEN 0xf2ed0004 +#define F0900_P2_STB6XX0_RX_OSCP 0xf2ed0002 +#define F0900_P2_STB6XX0_SYN 0xf2ed0001 + +/*P2_TNRCFG3*/ +#define R0900_P2_TNRCFG3 0xf2ee +#define F0900_P2_TUN_PLLFREQ 0xf2ee001c +#define F0900_P2_TUN_I2CFREQ_MODE 0xf2ee0003 + +/*P2_TNRLAUNCH*/ +#define R0900_P2_TNRLAUNCH 0xf2f0 + +/*P2_TNRLD*/ +#define R0900_P2_TNRLD 0xf2f0 +#define F0900_P2_TUNLD_VCOING 0xf2f00080 +#define F0900_P2_TUN_REG1FAIL 0xf2f00040 +#define F0900_P2_TUN_REG2FAIL 0xf2f00020 +#define F0900_P2_TUN_REG3FAIL 0xf2f00010 +#define F0900_P2_TUN_REG4FAIL 0xf2f00008 +#define F0900_P2_TUN_REG5FAIL 0xf2f00004 +#define F0900_P2_TUN_BWING 0xf2f00002 +#define F0900_P2_TUN_LOCKED 0xf2f00001 + +/*P2_TNROBSL*/ +#define R0900_P2_TNROBSL 0xf2f6 +#define F0900_P2_TUN_I2CABORTED 0xf2f60080 +#define F0900_P2_TUN_LPEN 0xf2f60040 +#define F0900_P2_TUN_FCCK 0xf2f60020 +#define F0900_P2_TUN_I2CLOCKED 0xf2f60010 +#define F0900_P2_TUN_PROGDONE 0xf2f6000c +#define F0900_P2_TUN_RFRESTE1 0xf2f60003 + +/*P2_TNRRESTE*/ +#define R0900_P2_TNRRESTE 0xf2f7 +#define F0900_P2_TUN_RFRESTE0 0xf2f700ff + +/*P2_SMAPCOEF7*/ +#define R0900_P2_SMAPCOEF7 0xf300 +#define F0900_P2_DIS_QSCALE 0xf3000080 +#define F0900_P2_SMAPCOEF_Q_LLR12 0xf300017f + +/*P2_SMAPCOEF6*/ +#define R0900_P2_SMAPCOEF6 0xf301 +#define F0900_P2_ADJ_8PSKLLR1 0xf3010004 +#define F0900_P2_OLD_8PSKLLR1 0xf3010002 +#define F0900_P2_DIS_AB8PSK 0xf3010001 + +/*P2_SMAPCOEF5*/ +#define R0900_P2_SMAPCOEF5 0xf302 +#define F0900_P2_DIS_8SCALE 0xf3020080 +#define F0900_P2_SMAPCOEF_8P_LLR23 0xf302017f + +/*P2_NCO2MAX1*/ +#define R0900_P2_NCO2MAX1 0xf314 +#define F0900_P2_TETA2_MAXVABS1 0xf31400ff + +/*P2_NCO2MAX0*/ +#define R0900_P2_NCO2MAX0 0xf315 +#define F0900_P2_TETA2_MAXVABS0 0xf31500ff + +/*P2_NCO2FR1*/ +#define R0900_P2_NCO2FR1 0xf316 +#define F0900_P2_NCO2FINAL_ANGLE1 0xf31600ff + +/*P2_NCO2FR0*/ +#define R0900_P2_NCO2FR0 0xf317 +#define F0900_P2_NCO2FINAL_ANGLE0 0xf31700ff + +/*P2_CFR2AVRGE1*/ +#define R0900_P2_CFR2AVRGE1 0xf318 +#define F0900_P2_I2C_CFR2AVERAGE1 0xf31800ff + +/*P2_CFR2AVRGE0*/ +#define R0900_P2_CFR2AVRGE0 0xf319 +#define F0900_P2_I2C_CFR2AVERAGE0 0xf31900ff + +/*P2_DMDPLHSTAT*/ +#define R0900_P2_DMDPLHSTAT 0xf320 +#define F0900_P2_PLH_STATISTIC 0xf32000ff + +/*P2_LOCKTIME3*/ +#define R0900_P2_LOCKTIME3 0xf322 +#define F0900_P2_DEMOD_LOCKTIME3 0xf32200ff + +/*P2_LOCKTIME2*/ +#define R0900_P2_LOCKTIME2 0xf323 +#define F0900_P2_DEMOD_LOCKTIME2 0xf32300ff + +/*P2_LOCKTIME1*/ +#define R0900_P2_LOCKTIME1 0xf324 +#define F0900_P2_DEMOD_LOCKTIME1 0xf32400ff + +/*P2_LOCKTIME0*/ +#define R0900_P2_LOCKTIME0 0xf325 +#define F0900_P2_DEMOD_LOCKTIME0 0xf32500ff + +/*P2_VITSCALE*/ +#define R0900_P2_VITSCALE 0xf332 +#define F0900_P2_NVTH_NOSRANGE 0xf3320080 +#define F0900_P2_VERROR_MAXMODE 0xf3320040 +#define F0900_P2_NSLOWSN_LOCKED 0xf3320008 +#define F0900_P2_DIS_RSFLOCK 0xf3320002 + +/*P2_FECM*/ +#define R0900_P2_FECM 0xf333 +#define F0900_P2_DSS_DVB 0xf3330080 +#define F0900_P2_DSS_SRCH 0xf3330010 +#define F0900_P2_SYNCVIT 0xf3330002 +#define F0900_P2_IQINV 0xf3330001 + +/*P2_VTH12*/ +#define R0900_P2_VTH12 0xf334 +#define F0900_P2_VTH12 0xf33400ff + +/*P2_VTH23*/ +#define R0900_P2_VTH23 0xf335 +#define F0900_P2_VTH23 0xf33500ff + +/*P2_VTH34*/ +#define R0900_P2_VTH34 0xf336 +#define F0900_P2_VTH34 0xf33600ff + +/*P2_VTH56*/ +#define R0900_P2_VTH56 0xf337 +#define F0900_P2_VTH56 0xf33700ff + +/*P2_VTH67*/ +#define R0900_P2_VTH67 0xf338 +#define F0900_P2_VTH67 0xf33800ff + +/*P2_VTH78*/ +#define R0900_P2_VTH78 0xf339 +#define F0900_P2_VTH78 0xf33900ff + +/*P2_VITCURPUN*/ +#define R0900_P2_VITCURPUN 0xf33a +#define F0900_P2_VIT_CURPUN 0xf33a001f + +/*P2_VERROR*/ +#define R0900_P2_VERROR 0xf33b +#define F0900_P2_REGERR_VIT 0xf33b00ff + +/*P2_PRVIT*/ +#define R0900_P2_PRVIT 0xf33c +#define F0900_P2_DIS_VTHLOCK 0xf33c0040 +#define F0900_P2_E7_8VIT 0xf33c0020 +#define F0900_P2_E6_7VIT 0xf33c0010 +#define F0900_P2_E5_6VIT 0xf33c0008 +#define F0900_P2_E3_4VIT 0xf33c0004 +#define F0900_P2_E2_3VIT 0xf33c0002 +#define F0900_P2_E1_2VIT 0xf33c0001 + +/*P2_VAVSRVIT*/ +#define R0900_P2_VAVSRVIT 0xf33d +#define F0900_P2_AMVIT 0xf33d0080 +#define F0900_P2_FROZENVIT 0xf33d0040 +#define F0900_P2_SNVIT 0xf33d0030 +#define F0900_P2_TOVVIT 0xf33d000c +#define F0900_P2_HYPVIT 0xf33d0003 + +/*P2_VSTATUSVIT*/ +#define R0900_P2_VSTATUSVIT 0xf33e +#define F0900_P2_PRFVIT 0xf33e0010 +#define F0900_P2_LOCKEDVIT 0xf33e0008 + +/*P2_VTHINUSE*/ +#define R0900_P2_VTHINUSE 0xf33f +#define F0900_P2_VIT_INUSE 0xf33f00ff + +/*P2_KDIV12*/ +#define R0900_P2_KDIV12 0xf340 +#define F0900_P2_K_DIVIDER_12 0xf340007f + +/*P2_KDIV23*/ +#define R0900_P2_KDIV23 0xf341 +#define F0900_P2_K_DIVIDER_23 0xf341007f + +/*P2_KDIV34*/ +#define R0900_P2_KDIV34 0xf342 +#define F0900_P2_K_DIVIDER_34 0xf342007f + +/*P2_KDIV56*/ +#define R0900_P2_KDIV56 0xf343 +#define F0900_P2_K_DIVIDER_56 0xf343007f + +/*P2_KDIV67*/ +#define R0900_P2_KDIV67 0xf344 +#define F0900_P2_K_DIVIDER_67 0xf344007f + +/*P2_KDIV78*/ +#define R0900_P2_KDIV78 0xf345 +#define F0900_P2_K_DIVIDER_78 0xf345007f + +/*P2_PDELCTRL1*/ +#define R0900_P2_PDELCTRL1 0xf350 +#define F0900_P2_INV_MISMASK 0xf3500080 +#define F0900_P2_FILTER_EN 0xf3500020 +#define F0900_P2_EN_MIS00 0xf3500002 +#define F0900_P2_ALGOSWRST 0xf3500001 + +/*P2_PDELCTRL2*/ +#define R0900_P2_PDELCTRL2 0xf351 +#define F0900_P2_RESET_UPKO_COUNT 0xf3510040 +#define F0900_P2_FRAME_MODE 0xf3510002 +#define F0900_P2_NOBCHERRFLG_USE 0xf3510001 + +/*P2_HYSTTHRESH*/ +#define R0900_P2_HYSTTHRESH 0xf354 +#define F0900_P2_UNLCK_THRESH 0xf35400f0 +#define F0900_P2_DELIN_LCK_THRESH 0xf354000f + +/*P2_ISIENTRY*/ +#define R0900_P2_ISIENTRY 0xf35e +#define F0900_P2_ISI_ENTRY 0xf35e00ff + +/*P2_ISIBITENA*/ +#define R0900_P2_ISIBITENA 0xf35f +#define F0900_P2_ISI_BIT_EN 0xf35f00ff + +/*P2_MATSTR1*/ +#define R0900_P2_MATSTR1 0xf360 +#define F0900_P2_MATYPE_CURRENT1 0xf36000ff + +/*P2_MATSTR0*/ +#define R0900_P2_MATSTR0 0xf361 +#define F0900_P2_MATYPE_CURRENT0 0xf36100ff + +/*P2_UPLSTR1*/ +#define R0900_P2_UPLSTR1 0xf362 +#define F0900_P2_UPL_CURRENT1 0xf36200ff + +/*P2_UPLSTR0*/ +#define R0900_P2_UPLSTR0 0xf363 +#define F0900_P2_UPL_CURRENT0 0xf36300ff + +/*P2_DFLSTR1*/ +#define R0900_P2_DFLSTR1 0xf364 +#define F0900_P2_DFL_CURRENT1 0xf36400ff + +/*P2_DFLSTR0*/ +#define R0900_P2_DFLSTR0 0xf365 +#define F0900_P2_DFL_CURRENT0 0xf36500ff + +/*P2_SYNCSTR*/ +#define R0900_P2_SYNCSTR 0xf366 +#define F0900_P2_SYNC_CURRENT 0xf36600ff + +/*P2_SYNCDSTR1*/ +#define R0900_P2_SYNCDSTR1 0xf367 +#define F0900_P2_SYNCD_CURRENT1 0xf36700ff + +/*P2_SYNCDSTR0*/ +#define R0900_P2_SYNCDSTR0 0xf368 +#define F0900_P2_SYNCD_CURRENT0 0xf36800ff + +/*P2_PDELSTATUS1*/ +#define R0900_P2_PDELSTATUS1 0xf369 +#define F0900_P2_PKTDELIN_DELOCK 0xf3690080 +#define F0900_P2_SYNCDUPDFL_BADDFL 0xf3690040 +#define F0900_P2_CONTINUOUS_STREAM 0xf3690020 +#define F0900_P2_UNACCEPTED_STREAM 0xf3690010 +#define F0900_P2_BCH_ERROR_FLAG 0xf3690008 +#define F0900_P2_PKTDELIN_LOCK 0xf3690002 +#define F0900_P2_FIRST_LOCK 0xf3690001 + +/*P2_PDELSTATUS2*/ +#define R0900_P2_PDELSTATUS2 0xf36a +#define F0900_P2_FRAME_MODCOD 0xf36a007c +#define F0900_P2_FRAME_TYPE 0xf36a0003 + +/*P2_BBFCRCKO1*/ +#define R0900_P2_BBFCRCKO1 0xf36b +#define F0900_P2_BBHCRC_KOCNT1 0xf36b00ff + +/*P2_BBFCRCKO0*/ +#define R0900_P2_BBFCRCKO0 0xf36c +#define F0900_P2_BBHCRC_KOCNT0 0xf36c00ff + +/*P2_UPCRCKO1*/ +#define R0900_P2_UPCRCKO1 0xf36d +#define F0900_P2_PKTCRC_KOCNT1 0xf36d00ff + +/*P2_UPCRCKO0*/ +#define R0900_P2_UPCRCKO0 0xf36e +#define F0900_P2_PKTCRC_KOCNT0 0xf36e00ff + +/*P2_PDELCTRL3*/ +#define R0900_P2_PDELCTRL3 0xf36f +#define F0900_P2_PKTDEL_CONTFAIL 0xf36f0080 +#define F0900_P2_NOFIFO_BCHERR 0xf36f0020 + +/*P2_TSSTATEM*/ +#define R0900_P2_TSSTATEM 0xf370 +#define F0900_P2_TSDIL_ON 0xf3700080 +#define F0900_P2_TSRS_ON 0xf3700020 +#define F0900_P2_TSDESCRAMB_ON 0xf3700010 +#define F0900_P2_TSFRAME_MODE 0xf3700008 +#define F0900_P2_TS_DISABLE 0xf3700004 +#define F0900_P2_TSOUT_NOSYNC 0xf3700001 + +/*P2_TSCFGH*/ +#define R0900_P2_TSCFGH 0xf372 +#define F0900_P2_TSFIFO_DVBCI 0xf3720080 +#define F0900_P2_TSFIFO_SERIAL 0xf3720040 +#define F0900_P2_TSFIFO_TEIUPDATE 0xf3720020 +#define F0900_P2_TSFIFO_DUTY50 0xf3720010 +#define F0900_P2_TSFIFO_HSGNLOUT 0xf3720008 +#define F0900_P2_TSFIFO_ERRMODE 0xf3720006 +#define F0900_P2_RST_HWARE 0xf3720001 + +/*P2_TSCFGM*/ +#define R0900_P2_TSCFGM 0xf373 +#define F0900_P2_TSFIFO_MANSPEED 0xf37300c0 +#define F0900_P2_TSFIFO_PERMDATA 0xf3730020 +#define F0900_P2_TSFIFO_DPUNACT 0xf3730002 +#define F0900_P2_TSFIFO_INVDATA 0xf3730001 + +/*P2_TSCFGL*/ +#define R0900_P2_TSCFGL 0xf374 +#define F0900_P2_TSFIFO_BCLKDEL1CK 0xf37400c0 +#define F0900_P2_BCHERROR_MODE 0xf3740030 +#define F0900_P2_TSFIFO_NSGNL2DATA 0xf3740008 +#define F0900_P2_TSFIFO_EMBINDVB 0xf3740004 +#define F0900_P2_TSFIFO_BITSPEED 0xf3740003 + +/*P2_TSINSDELH*/ +#define R0900_P2_TSINSDELH 0xf376 +#define F0900_P2_TSDEL_SYNCBYTE 0xf3760080 +#define F0900_P2_TSDEL_XXHEADER 0xf3760040 +#define F0900_P2_TSDEL_BBHEADER 0xf3760020 +#define F0900_P2_TSDEL_DATAFIELD 0xf3760010 +#define F0900_P2_TSINSDEL_ISCR 0xf3760008 +#define F0900_P2_TSINSDEL_NPD 0xf3760004 +#define F0900_P2_TSINSDEL_RSPARITY 0xf3760002 +#define F0900_P2_TSINSDEL_CRC8 0xf3760001 + +/*P2_TSDIVN*/ +#define R0900_P2_TSDIVN 0xf379 +#define F0900_P2_TSFIFO_SPEEDMODE 0xf37900c0 + +/*P2_TSCFG4*/ +#define R0900_P2_TSCFG4 0xf37a +#define F0900_P2_TSFIFO_TSSPEEDMODE 0xf37a00c0 + +/*P2_TSSPEED*/ +#define R0900_P2_TSSPEED 0xf380 +#define F0900_P2_TSFIFO_OUTSPEED 0xf38000ff + +/*P2_TSSTATUS*/ +#define R0900_P2_TSSTATUS 0xf381 +#define F0900_P2_TSFIFO_LINEOK 0xf3810080 +#define F0900_P2_TSFIFO_ERROR 0xf3810040 +#define F0900_P2_DIL_READY 0xf3810001 + +/*P2_TSSTATUS2*/ +#define R0900_P2_TSSTATUS2 0xf382 +#define F0900_P2_TSFIFO_DEMODSEL 0xf3820080 +#define F0900_P2_TSFIFOSPEED_STORE 0xf3820040 +#define F0900_P2_DILXX_RESET 0xf3820020 +#define F0900_P2_TSSERIAL_IMPOS 0xf3820010 +#define F0900_P2_SCRAMBDETECT 0xf3820002 + +/*P2_TSBITRATE1*/ +#define R0900_P2_TSBITRATE1 0xf383 +#define F0900_P2_TSFIFO_BITRATE1 0xf38300ff + +/*P2_TSBITRATE0*/ +#define R0900_P2_TSBITRATE0 0xf384 +#define F0900_P2_TSFIFO_BITRATE0 0xf38400ff + +/*P2_ERRCTRL1*/ +#define R0900_P2_ERRCTRL1 0xf398 +#define F0900_P2_ERR_SOURCE1 0xf39800f0 +#define F0900_P2_NUM_EVENT1 0xf3980007 + +/*P2_ERRCNT12*/ +#define R0900_P2_ERRCNT12 0xf399 +#define F0900_P2_ERRCNT1_OLDVALUE 0xf3990080 +#define F0900_P2_ERR_CNT12 0xf399007f + +/*P2_ERRCNT11*/ +#define R0900_P2_ERRCNT11 0xf39a +#define F0900_P2_ERR_CNT11 0xf39a00ff + +/*P2_ERRCNT10*/ +#define R0900_P2_ERRCNT10 0xf39b +#define F0900_P2_ERR_CNT10 0xf39b00ff + +/*P2_ERRCTRL2*/ +#define R0900_P2_ERRCTRL2 0xf39c +#define F0900_P2_ERR_SOURCE2 0xf39c00f0 +#define F0900_P2_NUM_EVENT2 0xf39c0007 + +/*P2_ERRCNT22*/ +#define R0900_P2_ERRCNT22 0xf39d +#define F0900_P2_ERRCNT2_OLDVALUE 0xf39d0080 +#define F0900_P2_ERR_CNT22 0xf39d007f + +/*P2_ERRCNT21*/ +#define R0900_P2_ERRCNT21 0xf39e +#define F0900_P2_ERR_CNT21 0xf39e00ff + +/*P2_ERRCNT20*/ +#define R0900_P2_ERRCNT20 0xf39f +#define F0900_P2_ERR_CNT20 0xf39f00ff + +/*P2_FECSPY*/ +#define R0900_P2_FECSPY 0xf3a0 +#define F0900_P2_SPY_ENABLE 0xf3a00080 +#define F0900_P2_NO_SYNCBYTE 0xf3a00040 +#define F0900_P2_SERIAL_MODE 0xf3a00020 +#define F0900_P2_UNUSUAL_PACKET 0xf3a00010 +#define F0900_P2_BERMETER_DATAMODE 0xf3a00008 +#define F0900_P2_BERMETER_LMODE 0xf3a00002 +#define F0900_P2_BERMETER_RESET 0xf3a00001 + +/*P2_FSPYCFG*/ +#define R0900_P2_FSPYCFG 0xf3a1 +#define F0900_P2_FECSPY_INPUT 0xf3a100c0 +#define F0900_P2_RST_ON_ERROR 0xf3a10020 +#define F0900_P2_ONE_SHOT 0xf3a10010 +#define F0900_P2_I2C_MODE 0xf3a1000c +#define F0900_P2_SPY_HYSTERESIS 0xf3a10003 + +/*P2_FSPYDATA*/ +#define R0900_P2_FSPYDATA 0xf3a2 +#define F0900_P2_SPY_STUFFING 0xf3a20080 +#define F0900_P2_SPY_CNULLPKT 0xf3a20020 +#define F0900_P2_SPY_OUTDATA_MODE 0xf3a2001f + +/*P2_FSPYOUT*/ +#define R0900_P2_FSPYOUT 0xf3a3 +#define F0900_P2_FSPY_DIRECT 0xf3a30080 +#define F0900_P2_STUFF_MODE 0xf3a30007 + +/*P2_FSTATUS*/ +#define R0900_P2_FSTATUS 0xf3a4 +#define F0900_P2_SPY_ENDSIM 0xf3a40080 +#define F0900_P2_VALID_SIM 0xf3a40040 +#define F0900_P2_FOUND_SIGNAL 0xf3a40020 +#define F0900_P2_DSS_SYNCBYTE 0xf3a40010 +#define F0900_P2_RESULT_STATE 0xf3a4000f + +/*P2_FBERCPT4*/ +#define R0900_P2_FBERCPT4 0xf3a8 +#define F0900_P2_FBERMETER_CPT4 0xf3a800ff + +/*P2_FBERCPT3*/ +#define R0900_P2_FBERCPT3 0xf3a9 +#define F0900_P2_FBERMETER_CPT3 0xf3a900ff + +/*P2_FBERCPT2*/ +#define R0900_P2_FBERCPT2 0xf3aa +#define F0900_P2_FBERMETER_CPT2 0xf3aa00ff + +/*P2_FBERCPT1*/ +#define R0900_P2_FBERCPT1 0xf3ab +#define F0900_P2_FBERMETER_CPT1 0xf3ab00ff + +/*P2_FBERCPT0*/ +#define R0900_P2_FBERCPT0 0xf3ac +#define F0900_P2_FBERMETER_CPT0 0xf3ac00ff + +/*P2_FBERERR2*/ +#define R0900_P2_FBERERR2 0xf3ad +#define F0900_P2_FBERMETER_ERR2 0xf3ad00ff + +/*P2_FBERERR1*/ +#define R0900_P2_FBERERR1 0xf3ae +#define F0900_P2_FBERMETER_ERR1 0xf3ae00ff + +/*P2_FBERERR0*/ +#define R0900_P2_FBERERR0 0xf3af +#define F0900_P2_FBERMETER_ERR0 0xf3af00ff + +/*P2_FSPYBER*/ +#define R0900_P2_FSPYBER 0xf3b2 +#define F0900_P2_FSPYBER_SYNCBYTE 0xf3b20010 +#define F0900_P2_FSPYBER_UNSYNC 0xf3b20008 +#define F0900_P2_FSPYBER_CTIME 0xf3b20007 + +/*P1_IQCONST*/ +#define R0900_P1_IQCONST 0xf400 +#define IQCONST REGx(R0900_P1_IQCONST) +#define F0900_P1_CONSTEL_SELECT 0xf4000060 +#define F0900_P1_IQSYMB_SEL 0xf400001f + +/*P1_NOSCFG*/ +#define R0900_P1_NOSCFG 0xf401 +#define NOSCFG REGx(R0900_P1_NOSCFG) +#define F0900_P1_DUMMYPL_NOSDATA 0xf4010020 +#define F0900_P1_NOSPLH_BETA 0xf4010018 +#define F0900_P1_NOSDATA_BETA 0xf4010007 + +/*P1_ISYMB*/ +#define R0900_P1_ISYMB 0xf402 +#define ISYMB REGx(R0900_P1_ISYMB) +#define F0900_P1_I_SYMBOL 0xf40201ff + +/*P1_QSYMB*/ +#define R0900_P1_QSYMB 0xf403 +#define QSYMB REGx(R0900_P1_QSYMB) +#define F0900_P1_Q_SYMBOL 0xf40301ff + +/*P1_AGC1CFG*/ +#define R0900_P1_AGC1CFG 0xf404 +#define AGC1CFG REGx(R0900_P1_AGC1CFG) +#define F0900_P1_DC_FROZEN 0xf4040080 +#define F0900_P1_DC_CORRECT 0xf4040040 +#define F0900_P1_AMM_FROZEN 0xf4040020 +#define F0900_P1_AMM_CORRECT 0xf4040010 +#define F0900_P1_QUAD_FROZEN 0xf4040008 +#define F0900_P1_QUAD_CORRECT 0xf4040004 + +/*P1_AGC1CN*/ +#define R0900_P1_AGC1CN 0xf406 +#define AGC1CN REGx(R0900_P1_AGC1CN) +#define F0900_P1_AGC1_LOCKED 0xf4060080 +#define F0900_P1_AGC1_MINPOWER 0xf4060010 +#define F0900_P1_AGCOUT_FAST 0xf4060008 +#define F0900_P1_AGCIQ_BETA 0xf4060007 + +/*P1_AGC1REF*/ +#define R0900_P1_AGC1REF 0xf407 +#define AGC1REF REGx(R0900_P1_AGC1REF) +#define F0900_P1_AGCIQ_REF 0xf40700ff + +/*P1_IDCCOMP*/ +#define R0900_P1_IDCCOMP 0xf408 +#define IDCCOMP REGx(R0900_P1_IDCCOMP) +#define F0900_P1_IAVERAGE_ADJ 0xf40801ff + +/*P1_QDCCOMP*/ +#define R0900_P1_QDCCOMP 0xf409 +#define QDCCOMP REGx(R0900_P1_QDCCOMP) +#define F0900_P1_QAVERAGE_ADJ 0xf40901ff + +/*P1_POWERI*/ +#define R0900_P1_POWERI 0xf40a +#define POWERI REGx(R0900_P1_POWERI) +#define F0900_P1_POWER_I 0xf40a00ff +#define POWER_I FLDx(F0900_P1_POWER_I) + +/*P1_POWERQ*/ +#define R0900_P1_POWERQ 0xf40b +#define POWERQ REGx(R0900_P1_POWERQ) +#define F0900_P1_POWER_Q 0xf40b00ff +#define POWER_Q FLDx(F0900_P1_POWER_Q) + +/*P1_AGC1AMM*/ +#define R0900_P1_AGC1AMM 0xf40c +#define AGC1AMM REGx(R0900_P1_AGC1AMM) +#define F0900_P1_AMM_VALUE 0xf40c00ff + +/*P1_AGC1QUAD*/ +#define R0900_P1_AGC1QUAD 0xf40d +#define AGC1QUAD REGx(R0900_P1_AGC1QUAD) +#define F0900_P1_QUAD_VALUE 0xf40d01ff + +/*P1_AGCIQIN1*/ +#define R0900_P1_AGCIQIN1 0xf40e +#define AGCIQIN1 REGx(R0900_P1_AGCIQIN1) +#define F0900_P1_AGCIQ_VALUE1 0xf40e00ff +#define AGCIQ_VALUE1 FLDx(F0900_P1_AGCIQ_VALUE1) + +/*P1_AGCIQIN0*/ +#define R0900_P1_AGCIQIN0 0xf40f +#define AGCIQIN0 REGx(R0900_P1_AGCIQIN0) +#define F0900_P1_AGCIQ_VALUE0 0xf40f00ff +#define AGCIQ_VALUE0 FLDx(F0900_P1_AGCIQ_VALUE0) + +/*P1_DEMOD*/ +#define R0900_P1_DEMOD 0xf410 +#define DEMOD REGx(R0900_P1_DEMOD) +#define F0900_P1_MANUALS2_ROLLOFF 0xf4100080 +#define MANUALS2_ROLLOFF FLDx(F0900_P1_MANUALS2_ROLLOFF) + +#define F0900_P1_SPECINV_CONTROL 0xf4100030 +#define SPECINV_CONTROL FLDx(F0900_P1_SPECINV_CONTROL) +#define F0900_P1_FORCE_ENASAMP 0xf4100008 +#define F0900_P1_MANUALSX_ROLLOFF 0xf4100004 +#define MANUALSX_ROLLOFF FLDx(F0900_P1_MANUALSX_ROLLOFF) +#define F0900_P1_ROLLOFF_CONTROL 0xf4100003 +#define ROLLOFF_CONTROL FLDx(F0900_P1_ROLLOFF_CONTROL) + +/*P1_DMDMODCOD*/ +#define R0900_P1_DMDMODCOD 0xf411 +#define DMDMODCOD REGx(R0900_P1_DMDMODCOD) +#define F0900_P1_MANUAL_MODCOD 0xf4110080 +#define F0900_P1_DEMOD_MODCOD 0xf411007c +#define DEMOD_MODCOD FLDx(F0900_P1_DEMOD_MODCOD) +#define F0900_P1_DEMOD_TYPE 0xf4110003 +#define DEMOD_TYPE FLDx(F0900_P1_DEMOD_TYPE) + +/*P1_DSTATUS*/ +#define R0900_P1_DSTATUS 0xf412 +#define DSTATUS REGx(R0900_P1_DSTATUS) +#define F0900_P1_CAR_LOCK 0xf4120080 +#define F0900_P1_TMGLOCK_QUALITY 0xf4120060 +#define TMGLOCK_QUALITY FLDx(F0900_P1_TMGLOCK_QUALITY) +#define F0900_P1_LOCK_DEFINITIF 0xf4120008 +#define LOCK_DEFINITIF FLDx(F0900_P1_LOCK_DEFINITIF) +#define F0900_P1_OVADC_DETECT 0xf4120001 + +/*P1_DSTATUS2*/ +#define R0900_P1_DSTATUS2 0xf413 +#define DSTATUS2 REGx(R0900_P1_DSTATUS2) +#define F0900_P1_DEMOD_DELOCK 0xf4130080 +#define F0900_P1_AGC1_NOSIGNALACK 0xf4130008 +#define F0900_P1_AGC2_OVERFLOW 0xf4130004 +#define F0900_P1_CFR_OVERFLOW 0xf4130002 +#define F0900_P1_GAMMA_OVERUNDER 0xf4130001 + +/*P1_DMDCFGMD*/ +#define R0900_P1_DMDCFGMD 0xf414 +#define DMDCFGMD REGx(R0900_P1_DMDCFGMD) +#define F0900_P1_DVBS2_ENABLE 0xf4140080 +#define DVBS2_ENABLE FLDx(F0900_P1_DVBS2_ENABLE) +#define F0900_P1_DVBS1_ENABLE 0xf4140040 +#define DVBS1_ENABLE FLDx(F0900_P1_DVBS1_ENABLE) +#define F0900_P1_SCAN_ENABLE 0xf4140010 +#define SCAN_ENABLE FLDx(F0900_P1_SCAN_ENABLE) +#define F0900_P1_CFR_AUTOSCAN 0xf4140008 +#define CFR_AUTOSCAN FLDx(F0900_P1_CFR_AUTOSCAN) +#define F0900_P1_TUN_RNG 0xf4140003 + +/*P1_DMDCFG2*/ +#define R0900_P1_DMDCFG2 0xf415 +#define DMDCFG2 REGx(R0900_P1_DMDCFG2) +#define F0900_P1_S1S2_SEQUENTIAL 0xf4150040 +#define S1S2_SEQUENTIAL FLDx(F0900_P1_S1S2_SEQUENTIAL) +#define F0900_P1_INFINITE_RELOCK 0xf4150010 + +/*P1_DMDISTATE*/ +#define R0900_P1_DMDISTATE 0xf416 +#define DMDISTATE REGx(R0900_P1_DMDISTATE) +#define F0900_P1_I2C_DEMOD_MODE 0xf416001f +#define DEMOD_MODE FLDx(F0900_P1_I2C_DEMOD_MODE) + +/*P1_DMDT0M*/ +#define R0900_P1_DMDT0M 0xf417 +#define DMDT0M REGx(R0900_P1_DMDT0M) +#define F0900_P1_DMDT0_MIN 0xf41700ff + +/*P1_DMDSTATE*/ +#define R0900_P1_DMDSTATE 0xf41b +#define DMDSTATE REGx(R0900_P1_DMDSTATE) +#define F0900_P1_HEADER_MODE 0xf41b0060 +#define HEADER_MODE FLDx(F0900_P1_HEADER_MODE) + +/*P1_DMDFLYW*/ +#define R0900_P1_DMDFLYW 0xf41c +#define DMDFLYW REGx(R0900_P1_DMDFLYW) +#define F0900_P1_I2C_IRQVAL 0xf41c00f0 +#define F0900_P1_FLYWHEEL_CPT 0xf41c000f +#define FLYWHEEL_CPT FLDx(F0900_P1_FLYWHEEL_CPT) + +/*P1_DSTATUS3*/ +#define R0900_P1_DSTATUS3 0xf41d +#define DSTATUS3 REGx(R0900_P1_DSTATUS3) +#define F0900_P1_DEMOD_CFGMODE 0xf41d0060 + +/*P1_DMDCFG3*/ +#define R0900_P1_DMDCFG3 0xf41e +#define DMDCFG3 REGx(R0900_P1_DMDCFG3) +#define F0900_P1_NOSTOP_FIFOFULL 0xf41e0008 + +/*P1_DMDCFG4*/ +#define R0900_P1_DMDCFG4 0xf41f +#define DMDCFG4 REGx(R0900_P1_DMDCFG4) +#define F0900_P1_TUNER_NRELAUNCH 0xf41f0008 + +/*P1_CORRELMANT*/ +#define R0900_P1_CORRELMANT 0xf420 +#define CORRELMANT REGx(R0900_P1_CORRELMANT) +#define F0900_P1_CORREL_MANT 0xf42000ff + +/*P1_CORRELABS*/ +#define R0900_P1_CORRELABS 0xf421 +#define CORRELABS REGx(R0900_P1_CORRELABS) +#define F0900_P1_CORREL_ABS 0xf42100ff + +/*P1_CORRELEXP*/ +#define R0900_P1_CORRELEXP 0xf422 +#define CORRELEXP REGx(R0900_P1_CORRELEXP) +#define F0900_P1_CORREL_ABSEXP 0xf42200f0 +#define F0900_P1_CORREL_EXP 0xf422000f + +/*P1_PLHMODCOD*/ +#define R0900_P1_PLHMODCOD 0xf424 +#define PLHMODCOD REGx(R0900_P1_PLHMODCOD) +#define F0900_P1_SPECINV_DEMOD 0xf4240080 +#define SPECINV_DEMOD FLDx(F0900_P1_SPECINV_DEMOD) +#define F0900_P1_PLH_MODCOD 0xf424007c +#define F0900_P1_PLH_TYPE 0xf4240003 + +/*P1_DMDREG*/ +#define R0900_P1_DMDREG 0xf425 +#define DMDREG REGx(R0900_P1_DMDREG) +#define F0900_P1_DECIM_PLFRAMES 0xf4250001 + +/*P1_AGC2O*/ +#define R0900_P1_AGC2O 0xf42c +#define AGC2O REGx(R0900_P1_AGC2O) +#define F0900_P1_AGC2_COEF 0xf42c0007 + +/*P1_AGC2REF*/ +#define R0900_P1_AGC2REF 0xf42d +#define AGC2REF REGx(R0900_P1_AGC2REF) +#define F0900_P1_AGC2_REF 0xf42d00ff + +/*P1_AGC1ADJ*/ +#define R0900_P1_AGC1ADJ 0xf42e +#define AGC1ADJ REGx(R0900_P1_AGC1ADJ) +#define F0900_P1_AGC1_ADJUSTED 0xf42e007f + +/*P1_AGC2I1*/ +#define R0900_P1_AGC2I1 0xf436 +#define AGC2I1 REGx(R0900_P1_AGC2I1) +#define F0900_P1_AGC2_INTEGRATOR1 0xf43600ff + +/*P1_AGC2I0*/ +#define R0900_P1_AGC2I0 0xf437 +#define AGC2I0 REGx(R0900_P1_AGC2I0) +#define F0900_P1_AGC2_INTEGRATOR0 0xf43700ff + +/*P1_CARCFG*/ +#define R0900_P1_CARCFG 0xf438 +#define CARCFG REGx(R0900_P1_CARCFG) +#define F0900_P1_CFRUPLOW_AUTO 0xf4380080 +#define F0900_P1_CFRUPLOW_TEST 0xf4380040 +#define F0900_P1_ROTAON 0xf4380004 +#define F0900_P1_PH_DET_ALGO 0xf4380003 + +/*P1_ACLC*/ +#define R0900_P1_ACLC 0xf439 +#define ACLC REGx(R0900_P1_ACLC) +#define F0900_P1_CAR_ALPHA_MANT 0xf4390030 +#define F0900_P1_CAR_ALPHA_EXP 0xf439000f + +/*P1_BCLC*/ +#define R0900_P1_BCLC 0xf43a +#define BCLC REGx(R0900_P1_BCLC) +#define F0900_P1_CAR_BETA_MANT 0xf43a0030 +#define F0900_P1_CAR_BETA_EXP 0xf43a000f + +/*P1_CARFREQ*/ +#define R0900_P1_CARFREQ 0xf43d +#define CARFREQ REGx(R0900_P1_CARFREQ) +#define F0900_P1_KC_COARSE_EXP 0xf43d00f0 +#define F0900_P1_BETA_FREQ 0xf43d000f + +/*P1_CARHDR*/ +#define R0900_P1_CARHDR 0xf43e +#define CARHDR REGx(R0900_P1_CARHDR) +#define F0900_P1_K_FREQ_HDR 0xf43e00ff + +/*P1_LDT*/ +#define R0900_P1_LDT 0xf43f +#define LDT REGx(R0900_P1_LDT) +#define F0900_P1_CARLOCK_THRES 0xf43f01ff + +/*P1_LDT2*/ +#define R0900_P1_LDT2 0xf440 +#define LDT2 REGx(R0900_P1_LDT2) +#define F0900_P1_CARLOCK_THRES2 0xf44001ff + +/*P1_CFRICFG*/ +#define R0900_P1_CFRICFG 0xf441 +#define CFRICFG REGx(R0900_P1_CFRICFG) +#define F0900_P1_NEG_CFRSTEP 0xf4410001 + +/*P1_CFRUP1*/ +#define R0900_P1_CFRUP1 0xf442 +#define CFRUP1 REGx(R0900_P1_CFRUP1) +#define F0900_P1_CFR_UP1 0xf44201ff +#define CFR_UP1 FLDx(F0900_P1_CFR_UP1) + +/*P1_CFRUP0*/ +#define R0900_P1_CFRUP0 0xf443 +#define CFRUP0 REGx(R0900_P1_CFRUP0) +#define F0900_P1_CFR_UP0 0xf44300ff +#define CFR_UP0 FLDx(F0900_P1_CFR_UP0) + +/*P1_CFRLOW1*/ +#define R0900_P1_CFRLOW1 0xf446 +#define CFRLOW1 REGx(R0900_P1_CFRLOW1) +#define F0900_P1_CFR_LOW1 0xf44601ff +#define CFR_LOW1 FLDx(F0900_P1_CFR_LOW1) + +/*P1_CFRLOW0*/ +#define R0900_P1_CFRLOW0 0xf447 +#define CFRLOW0 REGx(R0900_P1_CFRLOW0) +#define F0900_P1_CFR_LOW0 0xf44700ff +#define CFR_LOW0 FLDx(F0900_P1_CFR_LOW0) + +/*P1_CFRINIT1*/ +#define R0900_P1_CFRINIT1 0xf448 +#define CFRINIT1 REGx(R0900_P1_CFRINIT1) +#define F0900_P1_CFR_INIT1 0xf44801ff +#define CFR_INIT1 FLDx(F0900_P1_CFR_INIT1) + +/*P1_CFRINIT0*/ +#define R0900_P1_CFRINIT0 0xf449 +#define CFRINIT0 REGx(R0900_P1_CFRINIT0) +#define F0900_P1_CFR_INIT0 0xf44900ff +#define CFR_INIT0 FLDx(F0900_P1_CFR_INIT0) + +/*P1_CFRINC1*/ +#define R0900_P1_CFRINC1 0xf44a +#define CFRINC1 REGx(R0900_P1_CFRINC1) +#define F0900_P1_MANUAL_CFRINC 0xf44a0080 +#define F0900_P1_CFR_INC1 0xf44a003f + +/*P1_CFRINC0*/ +#define R0900_P1_CFRINC0 0xf44b +#define CFRINC0 REGx(R0900_P1_CFRINC0) +#define F0900_P1_CFR_INC0 0xf44b00f8 + +/*P1_CFR2*/ +#define R0900_P1_CFR2 0xf44c +#define CFR2 REGx(R0900_P1_CFR2) +#define F0900_P1_CAR_FREQ2 0xf44c01ff +#define CAR_FREQ2 FLDx(F0900_P1_CAR_FREQ2) + +/*P1_CFR1*/ +#define R0900_P1_CFR1 0xf44d +#define CFR1 REGx(R0900_P1_CFR1) +#define F0900_P1_CAR_FREQ1 0xf44d00ff +#define CAR_FREQ1 FLDx(F0900_P1_CAR_FREQ1) + +/*P1_CFR0*/ +#define R0900_P1_CFR0 0xf44e +#define CFR0 REGx(R0900_P1_CFR0) +#define F0900_P1_CAR_FREQ0 0xf44e00ff +#define CAR_FREQ0 FLDx(F0900_P1_CAR_FREQ0) + +/*P1_LDI*/ +#define R0900_P1_LDI 0xf44f +#define LDI REGx(R0900_P1_LDI) +#define F0900_P1_LOCK_DET_INTEGR 0xf44f01ff + +/*P1_TMGCFG*/ +#define R0900_P1_TMGCFG 0xf450 +#define TMGCFG REGx(R0900_P1_TMGCFG) +#define F0900_P1_TMGLOCK_BETA 0xf45000c0 +#define F0900_P1_DO_TIMING_CORR 0xf4500010 +#define F0900_P1_TMG_MINFREQ 0xf4500003 + +/*P1_RTC*/ +#define R0900_P1_RTC 0xf451 +#define RTC REGx(R0900_P1_RTC) +#define F0900_P1_TMGALPHA_EXP 0xf45100f0 +#define F0900_P1_TMGBETA_EXP 0xf451000f + +/*P1_RTCS2*/ +#define R0900_P1_RTCS2 0xf452 +#define RTCS2 REGx(R0900_P1_RTCS2) +#define F0900_P1_TMGALPHAS2_EXP 0xf45200f0 +#define F0900_P1_TMGBETAS2_EXP 0xf452000f + +/*P1_TMGTHRISE*/ +#define R0900_P1_TMGTHRISE 0xf453 +#define TMGTHRISE REGx(R0900_P1_TMGTHRISE) +#define F0900_P1_TMGLOCK_THRISE 0xf45300ff + +/*P1_TMGTHFALL*/ +#define R0900_P1_TMGTHFALL 0xf454 +#define TMGTHFALL REGx(R0900_P1_TMGTHFALL) +#define F0900_P1_TMGLOCK_THFALL 0xf45400ff + +/*P1_SFRUPRATIO*/ +#define R0900_P1_SFRUPRATIO 0xf455 +#define SFRUPRATIO REGx(R0900_P1_SFRUPRATIO) +#define F0900_P1_SFR_UPRATIO 0xf45500ff + +/*P1_SFRLOWRATIO*/ +#define R0900_P1_SFRLOWRATIO 0xf456 +#define F0900_P1_SFR_LOWRATIO 0xf45600ff + +/*P1_KREFTMG*/ +#define R0900_P1_KREFTMG 0xf458 +#define KREFTMG REGx(R0900_P1_KREFTMG) +#define F0900_P1_KREF_TMG 0xf45800ff + +/*P1_SFRSTEP*/ +#define R0900_P1_SFRSTEP 0xf459 +#define SFRSTEP REGx(R0900_P1_SFRSTEP) +#define F0900_P1_SFR_SCANSTEP 0xf45900f0 +#define F0900_P1_SFR_CENTERSTEP 0xf459000f + +/*P1_TMGCFG2*/ +#define R0900_P1_TMGCFG2 0xf45a +#define TMGCFG2 REGx(R0900_P1_TMGCFG2) +#define F0900_P1_SFRRATIO_FINE 0xf45a0001 + +/*P1_KREFTMG2*/ +#define R0900_P1_KREFTMG2 0xf45b +#define KREFTMG2 REGx(R0900_P1_KREFTMG2) +#define F0900_P1_KREF_TMG2 0xf45b00ff + +/*P1_SFRINIT1*/ +#define R0900_P1_SFRINIT1 0xf45e +#define SFRINIT1 REGx(R0900_P1_SFRINIT1) +#define F0900_P1_SFR_INIT1 0xf45e007f + +/*P1_SFRINIT0*/ +#define R0900_P1_SFRINIT0 0xf45f +#define SFRINIT0 REGx(R0900_P1_SFRINIT0) +#define F0900_P1_SFR_INIT0 0xf45f00ff + +/*P1_SFRUP1*/ +#define R0900_P1_SFRUP1 0xf460 +#define SFRUP1 REGx(R0900_P1_SFRUP1) +#define F0900_P1_AUTO_GUP 0xf4600080 +#define AUTO_GUP FLDx(F0900_P1_AUTO_GUP) +#define F0900_P1_SYMB_FREQ_UP1 0xf460007f + +/*P1_SFRUP0*/ +#define R0900_P1_SFRUP0 0xf461 +#define SFRUP0 REGx(R0900_P1_SFRUP0) +#define F0900_P1_SYMB_FREQ_UP0 0xf46100ff + +/*P1_SFRLOW1*/ +#define R0900_P1_SFRLOW1 0xf462 +#define SFRLOW1 REGx(R0900_P1_SFRLOW1) +#define F0900_P1_AUTO_GLOW 0xf4620080 +#define AUTO_GLOW FLDx(F0900_P1_AUTO_GLOW) +#define F0900_P1_SYMB_FREQ_LOW1 0xf462007f + +/*P1_SFRLOW0*/ +#define R0900_P1_SFRLOW0 0xf463 +#define SFRLOW0 REGx(R0900_P1_SFRLOW0) +#define F0900_P1_SYMB_FREQ_LOW0 0xf46300ff + +/*P1_SFR3*/ +#define R0900_P1_SFR3 0xf464 +#define SFR3 REGx(R0900_P1_SFR3) +#define F0900_P1_SYMB_FREQ3 0xf46400ff +#define SYMB_FREQ3 FLDx(F0900_P1_SYMB_FREQ3) + +/*P1_SFR2*/ +#define R0900_P1_SFR2 0xf465 +#define SFR2 REGx(R0900_P1_SFR2) +#define F0900_P1_SYMB_FREQ2 0xf46500ff +#define SYMB_FREQ2 FLDx(F0900_P1_SYMB_FREQ2) + +/*P1_SFR1*/ +#define R0900_P1_SFR1 0xf466 +#define SFR1 REGx(R0900_P1_SFR1) +#define F0900_P1_SYMB_FREQ1 0xf46600ff +#define SYMB_FREQ1 FLDx(F0900_P1_SYMB_FREQ1) + +/*P1_SFR0*/ +#define R0900_P1_SFR0 0xf467 +#define SFR0 REGx(R0900_P1_SFR0) +#define F0900_P1_SYMB_FREQ0 0xf46700ff +#define SYMB_FREQ0 FLDx(F0900_P1_SYMB_FREQ0) + +/*P1_TMGREG2*/ +#define R0900_P1_TMGREG2 0xf468 +#define TMGREG2 REGx(R0900_P1_TMGREG2) +#define F0900_P1_TMGREG2 0xf46800ff + +/*P1_TMGREG1*/ +#define R0900_P1_TMGREG1 0xf469 +#define TMGREG1 REGx(R0900_P1_TMGREG1) +#define F0900_P1_TMGREG1 0xf46900ff + +/*P1_TMGREG0*/ +#define R0900_P1_TMGREG0 0xf46a +#define TMGREG0 REGx(R0900_P1_TMGREG0) +#define F0900_P1_TMGREG0 0xf46a00ff + +/*P1_TMGLOCK1*/ +#define R0900_P1_TMGLOCK1 0xf46b +#define TMGLOCK1 REGx(R0900_P1_TMGLOCK1) +#define F0900_P1_TMGLOCK_LEVEL1 0xf46b01ff + +/*P1_TMGLOCK0*/ +#define R0900_P1_TMGLOCK0 0xf46c +#define TMGLOCK0 REGx(R0900_P1_TMGLOCK0) +#define F0900_P1_TMGLOCK_LEVEL0 0xf46c00ff + +/*P1_TMGOBS*/ +#define R0900_P1_TMGOBS 0xf46d +#define TMGOBS REGx(R0900_P1_TMGOBS) +#define F0900_P1_ROLLOFF_STATUS 0xf46d00c0 +#define ROLLOFF_STATUS FLDx(F0900_P1_ROLLOFF_STATUS) + +/*P1_EQUALCFG*/ +#define R0900_P1_EQUALCFG 0xf46f +#define EQUALCFG REGx(R0900_P1_EQUALCFG) +#define F0900_P1_EQUAL_ON 0xf46f0040 +#define F0900_P1_MU_EQUALDFE 0xf46f0007 + +/*P1_EQUAI1*/ +#define R0900_P1_EQUAI1 0xf470 +#define EQUAI1 REGx(R0900_P1_EQUAI1) +#define F0900_P1_EQUA_ACCI1 0xf47001ff + +/*P1_EQUAQ1*/ +#define R0900_P1_EQUAQ1 0xf471 +#define EQUAQ1 REGx(R0900_P1_EQUAQ1) +#define F0900_P1_EQUA_ACCQ1 0xf47101ff + +/*P1_EQUAI2*/ +#define R0900_P1_EQUAI2 0xf472 +#define EQUAI2 REGx(R0900_P1_EQUAI2) +#define F0900_P1_EQUA_ACCI2 0xf47201ff + +/*P1_EQUAQ2*/ +#define R0900_P1_EQUAQ2 0xf473 +#define EQUAQ2 REGx(R0900_P1_EQUAQ2) +#define F0900_P1_EQUA_ACCQ2 0xf47301ff + +/*P1_EQUAI3*/ +#define R0900_P1_EQUAI3 0xf474 +#define EQUAI3 REGx(R0900_P1_EQUAI3) +#define F0900_P1_EQUA_ACCI3 0xf47401ff + +/*P1_EQUAQ3*/ +#define R0900_P1_EQUAQ3 0xf475 +#define EQUAQ3 REGx(R0900_P1_EQUAQ3) +#define F0900_P1_EQUA_ACCQ3 0xf47501ff + +/*P1_EQUAI4*/ +#define R0900_P1_EQUAI4 0xf476 +#define EQUAI4 REGx(R0900_P1_EQUAI4) +#define F0900_P1_EQUA_ACCI4 0xf47601ff + +/*P1_EQUAQ4*/ +#define R0900_P1_EQUAQ4 0xf477 +#define EQUAQ4 REGx(R0900_P1_EQUAQ4) +#define F0900_P1_EQUA_ACCQ4 0xf47701ff + +/*P1_EQUAI5*/ +#define R0900_P1_EQUAI5 0xf478 +#define EQUAI5 REGx(R0900_P1_EQUAI5) +#define F0900_P1_EQUA_ACCI5 0xf47801ff + +/*P1_EQUAQ5*/ +#define R0900_P1_EQUAQ5 0xf479 +#define EQUAQ5 REGx(R0900_P1_EQUAQ5) +#define F0900_P1_EQUA_ACCQ5 0xf47901ff + +/*P1_EQUAI6*/ +#define R0900_P1_EQUAI6 0xf47a +#define EQUAI6 REGx(R0900_P1_EQUAI6) +#define F0900_P1_EQUA_ACCI6 0xf47a01ff + +/*P1_EQUAQ6*/ +#define R0900_P1_EQUAQ6 0xf47b +#define EQUAQ6 REGx(R0900_P1_EQUAQ6) +#define F0900_P1_EQUA_ACCQ6 0xf47b01ff + +/*P1_EQUAI7*/ +#define R0900_P1_EQUAI7 0xf47c +#define EQUAI7 REGx(R0900_P1_EQUAI7) +#define F0900_P1_EQUA_ACCI7 0xf47c01ff + +/*P1_EQUAQ7*/ +#define R0900_P1_EQUAQ7 0xf47d +#define EQUAQ7 REGx(R0900_P1_EQUAQ7) +#define F0900_P1_EQUA_ACCQ7 0xf47d01ff + +/*P1_EQUAI8*/ +#define R0900_P1_EQUAI8 0xf47e +#define EQUAI8 REGx(R0900_P1_EQUAI8) +#define F0900_P1_EQUA_ACCI8 0xf47e01ff + +/*P1_EQUAQ8*/ +#define R0900_P1_EQUAQ8 0xf47f +#define EQUAQ8 REGx(R0900_P1_EQUAQ8) +#define F0900_P1_EQUA_ACCQ8 0xf47f01ff + +/*P1_NNOSDATAT1*/ +#define R0900_P1_NNOSDATAT1 0xf480 +#define NNOSDATAT1 REGx(R0900_P1_NNOSDATAT1) +#define F0900_P1_NOSDATAT_NORMED1 0xf48000ff +#define NOSDATAT_NORMED1 FLDx(F0900_P1_NOSDATAT_NORMED1) + +/*P1_NNOSDATAT0*/ +#define R0900_P1_NNOSDATAT0 0xf481 +#define NNOSDATAT0 REGx(R0900_P1_NNOSDATAT0) +#define F0900_P1_NOSDATAT_NORMED0 0xf48100ff +#define NOSDATAT_NORMED0 FLDx(F0900_P1_NOSDATAT_NORMED0) + +/*P1_NNOSDATA1*/ +#define R0900_P1_NNOSDATA1 0xf482 +#define NNOSDATA1 REGx(R0900_P1_NNOSDATA1) +#define F0900_P1_NOSDATA_NORMED1 0xf48200ff + +/*P1_NNOSDATA0*/ +#define R0900_P1_NNOSDATA0 0xf483 +#define NNOSDATA0 REGx(R0900_P1_NNOSDATA0) +#define F0900_P1_NOSDATA_NORMED0 0xf48300ff + +/*P1_NNOSPLHT1*/ +#define R0900_P1_NNOSPLHT1 0xf484 +#define NNOSPLHT1 REGx(R0900_P1_NNOSPLHT1) +#define F0900_P1_NOSPLHT_NORMED1 0xf48400ff +#define NOSPLHT_NORMED1 FLDx(F0900_P1_NOSPLHT_NORMED1) + +/*P1_NNOSPLHT0*/ +#define R0900_P1_NNOSPLHT0 0xf485 +#define NNOSPLHT0 REGx(R0900_P1_NNOSPLHT0) +#define F0900_P1_NOSPLHT_NORMED0 0xf48500ff +#define NOSPLHT_NORMED0 FLDx(F0900_P1_NOSPLHT_NORMED0) + +/*P1_NNOSPLH1*/ +#define R0900_P1_NNOSPLH1 0xf486 +#define NNOSPLH1 REGx(R0900_P1_NNOSPLH1) +#define F0900_P1_NOSPLH_NORMED1 0xf48600ff + +/*P1_NNOSPLH0*/ +#define R0900_P1_NNOSPLH0 0xf487 +#define NNOSPLH0 REGx(R0900_P1_NNOSPLH0) +#define F0900_P1_NOSPLH_NORMED0 0xf48700ff + +/*P1_NOSDATAT1*/ +#define R0900_P1_NOSDATAT1 0xf488 +#define NOSDATAT1 REGx(R0900_P1_NOSDATAT1) +#define F0900_P1_NOSDATAT_UNNORMED1 0xf48800ff + +/*P1_NOSDATAT0*/ +#define R0900_P1_NOSDATAT0 0xf489 +#define NOSDATAT0 REGx(R0900_P1_NOSDATAT0) +#define F0900_P1_NOSDATAT_UNNORMED0 0xf48900ff + +/*P1_NOSDATA1*/ +#define R0900_P1_NOSDATA1 0xf48a +#define NOSDATA1 REGx(R0900_P1_NOSDATA1) +#define F0900_P1_NOSDATA_UNNORMED1 0xf48a00ff + +/*P1_NOSDATA0*/ +#define R0900_P1_NOSDATA0 0xf48b +#define NOSDATA0 REGx(R0900_P1_NOSDATA0) +#define F0900_P1_NOSDATA_UNNORMED0 0xf48b00ff + +/*P1_NOSPLHT1*/ +#define R0900_P1_NOSPLHT1 0xf48c +#define NOSPLHT1 REGx(R0900_P1_NOSPLHT1) +#define F0900_P1_NOSPLHT_UNNORMED1 0xf48c00ff + +/*P1_NOSPLHT0*/ +#define R0900_P1_NOSPLHT0 0xf48d +#define NOSPLHT0 REGx(R0900_P1_NOSPLHT0) +#define F0900_P1_NOSPLHT_UNNORMED0 0xf48d00ff + +/*P1_NOSPLH1*/ +#define R0900_P1_NOSPLH1 0xf48e +#define NOSPLH1 REGx(R0900_P1_NOSPLH1) +#define F0900_P1_NOSPLH_UNNORMED1 0xf48e00ff + +/*P1_NOSPLH0*/ +#define R0900_P1_NOSPLH0 0xf48f +#define NOSPLH0 REGx(R0900_P1_NOSPLH0) +#define F0900_P1_NOSPLH_UNNORMED0 0xf48f00ff + +/*P1_CAR2CFG*/ +#define R0900_P1_CAR2CFG 0xf490 +#define CAR2CFG REGx(R0900_P1_CAR2CFG) +#define F0900_P1_CARRIER3_DISABLE 0xf4900040 +#define F0900_P1_ROTA2ON 0xf4900004 +#define F0900_P1_PH_DET_ALGO2 0xf4900003 + +/*P1_CFR2CFR1*/ +#define R0900_P1_CFR2CFR1 0xf491 +#define CFR2CFR1 REGx(R0900_P1_CFR2CFR1) +#define F0900_P1_CFR2TOCFR1_DVBS1 0xf49100c0 +#define F0900_P1_EN_S2CAR2CENTER 0xf4910020 +#define F0900_P1_DIS_BCHERRCFR2 0xf4910010 +#define F0900_P1_CFR2TOCFR1_BETA 0xf4910007 + +/*P1_CFR22*/ +#define R0900_P1_CFR22 0xf493 +#define CFR22 REGx(R0900_P1_CFR22) +#define F0900_P1_CAR2_FREQ2 0xf49301ff + +/*P1_CFR21*/ +#define R0900_P1_CFR21 0xf494 +#define CFR21 REGx(R0900_P1_CFR21) +#define F0900_P1_CAR2_FREQ1 0xf49400ff + +/*P1_CFR20*/ +#define R0900_P1_CFR20 0xf495 +#define CFR20 REGx(R0900_P1_CFR20) +#define F0900_P1_CAR2_FREQ0 0xf49500ff + +/*P1_ACLC2S2Q*/ +#define R0900_P1_ACLC2S2Q 0xf497 +#define ACLC2S2Q REGx(R0900_P1_ACLC2S2Q) +#define F0900_P1_ENAB_SPSKSYMB 0xf4970080 +#define F0900_P1_CAR2S2_Q_ALPH_M 0xf4970030 +#define F0900_P1_CAR2S2_Q_ALPH_E 0xf497000f + +/*P1_ACLC2S28*/ +#define R0900_P1_ACLC2S28 0xf498 +#define ACLC2S28 REGx(R0900_P1_ACLC2S28) +#define F0900_P1_OLDI3Q_MODE 0xf4980080 +#define F0900_P1_CAR2S2_8_ALPH_M 0xf4980030 +#define F0900_P1_CAR2S2_8_ALPH_E 0xf498000f + +/*P1_ACLC2S216A*/ +#define R0900_P1_ACLC2S216A 0xf499 +#define ACLC2S216A REGx(R0900_P1_ACLC2S216A) +#define F0900_P1_DIS_C3STOPA2 0xf4990080 +#define F0900_P1_CAR2S2_16ADERAT 0xf4990040 +#define F0900_P1_CAR2S2_16A_ALPH_M 0xf4990030 +#define F0900_P1_CAR2S2_16A_ALPH_E 0xf499000f + +/*P1_ACLC2S232A*/ +#define R0900_P1_ACLC2S232A 0xf49a +#define ACLC2S232A REGx(R0900_P1_ACLC2S232A) +#define F0900_P1_CAR2S2_32ADERAT 0xf49a0040 +#define F0900_P1_CAR2S2_32A_ALPH_M 0xf49a0030 +#define F0900_P1_CAR2S2_32A_ALPH_E 0xf49a000f + +/*P1_BCLC2S2Q*/ +#define R0900_P1_BCLC2S2Q 0xf49c +#define BCLC2S2Q REGx(R0900_P1_BCLC2S2Q) +#define F0900_P1_CAR2S2_Q_BETA_M 0xf49c0030 +#define F0900_P1_CAR2S2_Q_BETA_E 0xf49c000f + +/*P1_BCLC2S28*/ +#define R0900_P1_BCLC2S28 0xf49d +#define BCLC2S28 REGx(R0900_P1_BCLC2S28) +#define F0900_P1_CAR2S2_8_BETA_M 0xf49d0030 +#define F0900_P1_CAR2S2_8_BETA_E 0xf49d000f + +/*P1_BCLC2S216A*/ +#define R0900_P1_BCLC2S216A 0xf49e +#define BCLC2S216A REGx(R0900_P1_BCLC2S216A) + +/*P1_BCLC2S232A*/ +#define R0900_P1_BCLC2S232A 0xf49f +#define BCLC2S232A REGx(R0900_P1_BCLC2S232A) + +/*P1_PLROOT2*/ +#define R0900_P1_PLROOT2 0xf4ac +#define PLROOT2 REGx(R0900_P1_PLROOT2) +#define F0900_P1_PLSCRAMB_MODE 0xf4ac000c +#define F0900_P1_PLSCRAMB_ROOT2 0xf4ac0003 + +/*P1_PLROOT1*/ +#define R0900_P1_PLROOT1 0xf4ad +#define PLROOT1 REGx(R0900_P1_PLROOT1) +#define F0900_P1_PLSCRAMB_ROOT1 0xf4ad00ff + +/*P1_PLROOT0*/ +#define R0900_P1_PLROOT0 0xf4ae +#define PLROOT0 REGx(R0900_P1_PLROOT0) +#define F0900_P1_PLSCRAMB_ROOT0 0xf4ae00ff + +/*P1_MODCODLST0*/ +#define R0900_P1_MODCODLST0 0xf4b0 +#define MODCODLST0 REGx(R0900_P1_MODCODLST0) + +/*P1_MODCODLST1*/ +#define R0900_P1_MODCODLST1 0xf4b1 +#define MODCODLST1 REGx(R0900_P1_MODCODLST1) +#define F0900_P1_DIS_MODCOD29 0xf4b100f0 +#define F0900_P1_DIS_32PSK_9_10 0xf4b1000f + +/*P1_MODCODLST2*/ +#define R0900_P1_MODCODLST2 0xf4b2 +#define MODCODLST2 REGx(R0900_P1_MODCODLST2) +#define F0900_P1_DIS_32PSK_8_9 0xf4b200f0 +#define F0900_P1_DIS_32PSK_5_6 0xf4b2000f + +/*P1_MODCODLST3*/ +#define R0900_P1_MODCODLST3 0xf4b3 +#define MODCODLST3 REGx(R0900_P1_MODCODLST3) +#define F0900_P1_DIS_32PSK_4_5 0xf4b300f0 +#define F0900_P1_DIS_32PSK_3_4 0xf4b3000f + +/*P1_MODCODLST4*/ +#define R0900_P1_MODCODLST4 0xf4b4 +#define MODCODLST4 REGx(R0900_P1_MODCODLST4) +#define F0900_P1_DIS_16PSK_9_10 0xf4b400f0 +#define F0900_P1_DIS_16PSK_8_9 0xf4b4000f + +/*P1_MODCODLST5*/ +#define R0900_P1_MODCODLST5 0xf4b5 +#define MODCODLST5 REGx(R0900_P1_MODCODLST5) +#define F0900_P1_DIS_16PSK_5_6 0xf4b500f0 +#define F0900_P1_DIS_16PSK_4_5 0xf4b5000f + +/*P1_MODCODLST6*/ +#define R0900_P1_MODCODLST6 0xf4b6 +#define MODCODLST6 REGx(R0900_P1_MODCODLST6) +#define F0900_P1_DIS_16PSK_3_4 0xf4b600f0 +#define F0900_P1_DIS_16PSK_2_3 0xf4b6000f + +/*P1_MODCODLST7*/ +#define R0900_P1_MODCODLST7 0xf4b7 +#define MODCODLST7 REGx(R0900_P1_MODCODLST7) +#define F0900_P1_DIS_8P_9_10 0xf4b700f0 +#define F0900_P1_DIS_8P_8_9 0xf4b7000f + +/*P1_MODCODLST8*/ +#define R0900_P1_MODCODLST8 0xf4b8 +#define MODCODLST8 REGx(R0900_P1_MODCODLST8) +#define F0900_P1_DIS_8P_5_6 0xf4b800f0 +#define F0900_P1_DIS_8P_3_4 0xf4b8000f + +/*P1_MODCODLST9*/ +#define R0900_P1_MODCODLST9 0xf4b9 +#define MODCODLST9 REGx(R0900_P1_MODCODLST9) +#define F0900_P1_DIS_8P_2_3 0xf4b900f0 +#define F0900_P1_DIS_8P_3_5 0xf4b9000f + +/*P1_MODCODLSTA*/ +#define R0900_P1_MODCODLSTA 0xf4ba +#define MODCODLSTA REGx(R0900_P1_MODCODLSTA) +#define F0900_P1_DIS_QP_9_10 0xf4ba00f0 +#define F0900_P1_DIS_QP_8_9 0xf4ba000f + +/*P1_MODCODLSTB*/ +#define R0900_P1_MODCODLSTB 0xf4bb +#define MODCODLSTB REGx(R0900_P1_MODCODLSTB) +#define F0900_P1_DIS_QP_5_6 0xf4bb00f0 +#define F0900_P1_DIS_QP_4_5 0xf4bb000f + +/*P1_MODCODLSTC*/ +#define R0900_P1_MODCODLSTC 0xf4bc +#define MODCODLSTC REGx(R0900_P1_MODCODLSTC) +#define F0900_P1_DIS_QP_3_4 0xf4bc00f0 +#define F0900_P1_DIS_QP_2_3 0xf4bc000f + +/*P1_MODCODLSTD*/ +#define R0900_P1_MODCODLSTD 0xf4bd +#define MODCODLSTD REGx(R0900_P1_MODCODLSTD) +#define F0900_P1_DIS_QP_3_5 0xf4bd00f0 +#define F0900_P1_DIS_QP_1_2 0xf4bd000f + +/*P1_MODCODLSTE*/ +#define R0900_P1_MODCODLSTE 0xf4be +#define MODCODLSTE REGx(R0900_P1_MODCODLSTE) +#define F0900_P1_DIS_QP_2_5 0xf4be00f0 +#define F0900_P1_DIS_QP_1_3 0xf4be000f + +/*P1_MODCODLSTF*/ +#define R0900_P1_MODCODLSTF 0xf4bf +#define MODCODLSTF REGx(R0900_P1_MODCODLSTF) +#define F0900_P1_DIS_QP_1_4 0xf4bf00f0 + +/*P1_GAUSSR0*/ +#define R0900_P1_GAUSSR0 0xf4c0 +#define GAUSSR0 REGx(R0900_P1_GAUSSR0) +#define F0900_P1_EN_CCIMODE 0xf4c00080 +#define F0900_P1_R0_GAUSSIEN 0xf4c0007f + +/*P1_CCIR0*/ +#define R0900_P1_CCIR0 0xf4c1 +#define CCIR0 REGx(R0900_P1_CCIR0) +#define F0900_P1_CCIDETECT_PLHONLY 0xf4c10080 +#define F0900_P1_R0_CCI 0xf4c1007f + +/*P1_CCIQUANT*/ +#define R0900_P1_CCIQUANT 0xf4c2 +#define CCIQUANT REGx(R0900_P1_CCIQUANT) +#define F0900_P1_CCI_BETA 0xf4c200e0 +#define F0900_P1_CCI_QUANT 0xf4c2001f + +/*P1_CCITHRES*/ +#define R0900_P1_CCITHRES 0xf4c3 +#define CCITHRES REGx(R0900_P1_CCITHRES) +#define F0900_P1_CCI_THRESHOLD 0xf4c300ff + +/*P1_CCIACC*/ +#define R0900_P1_CCIACC 0xf4c4 +#define CCIACC REGx(R0900_P1_CCIACC) +#define F0900_P1_CCI_VALUE 0xf4c400ff + +/*P1_DMDRESCFG*/ +#define R0900_P1_DMDRESCFG 0xf4c6 +#define DMDRESCFG REGx(R0900_P1_DMDRESCFG) +#define F0900_P1_DMDRES_RESET 0xf4c60080 +#define F0900_P1_DMDRES_STRALL 0xf4c60008 +#define F0900_P1_DMDRES_NEWONLY 0xf4c60004 +#define F0900_P1_DMDRES_NOSTORE 0xf4c60002 + +/*P1_DMDRESADR*/ +#define R0900_P1_DMDRESADR 0xf4c7 +#define DMDRESADR REGx(R0900_P1_DMDRESADR) +#define F0900_P1_DMDRES_VALIDCFR 0xf4c70040 +#define F0900_P1_DMDRES_MEMFULL 0xf4c70030 +#define F0900_P1_DMDRES_RESNBR 0xf4c7000f + +/*P1_DMDRESDATA7*/ +#define R0900_P1_DMDRESDATA7 0xf4c8 +#define F0900_P1_DMDRES_DATA7 0xf4c800ff + +/*P1_DMDRESDATA6*/ +#define R0900_P1_DMDRESDATA6 0xf4c9 +#define F0900_P1_DMDRES_DATA6 0xf4c900ff + +/*P1_DMDRESDATA5*/ +#define R0900_P1_DMDRESDATA5 0xf4ca +#define F0900_P1_DMDRES_DATA5 0xf4ca00ff + +/*P1_DMDRESDATA4*/ +#define R0900_P1_DMDRESDATA4 0xf4cb +#define F0900_P1_DMDRES_DATA4 0xf4cb00ff + +/*P1_DMDRESDATA3*/ +#define R0900_P1_DMDRESDATA3 0xf4cc +#define F0900_P1_DMDRES_DATA3 0xf4cc00ff + +/*P1_DMDRESDATA2*/ +#define R0900_P1_DMDRESDATA2 0xf4cd +#define F0900_P1_DMDRES_DATA2 0xf4cd00ff + +/*P1_DMDRESDATA1*/ +#define R0900_P1_DMDRESDATA1 0xf4ce +#define F0900_P1_DMDRES_DATA1 0xf4ce00ff + +/*P1_DMDRESDATA0*/ +#define R0900_P1_DMDRESDATA0 0xf4cf +#define F0900_P1_DMDRES_DATA0 0xf4cf00ff + +/*P1_FFEI1*/ +#define R0900_P1_FFEI1 0xf4d0 +#define FFEI1 REGx(R0900_P1_FFEI1) +#define F0900_P1_FFE_ACCI1 0xf4d001ff + +/*P1_FFEQ1*/ +#define R0900_P1_FFEQ1 0xf4d1 +#define FFEQ1 REGx(R0900_P1_FFEQ1) +#define F0900_P1_FFE_ACCQ1 0xf4d101ff + +/*P1_FFEI2*/ +#define R0900_P1_FFEI2 0xf4d2 +#define FFEI2 REGx(R0900_P1_FFEI2) +#define F0900_P1_FFE_ACCI2 0xf4d201ff + +/*P1_FFEQ2*/ +#define R0900_P1_FFEQ2 0xf4d3 +#define FFEQ2 REGx(R0900_P1_FFEQ2) +#define F0900_P1_FFE_ACCQ2 0xf4d301ff + +/*P1_FFEI3*/ +#define R0900_P1_FFEI3 0xf4d4 +#define FFEI3 REGx(R0900_P1_FFEI3) +#define F0900_P1_FFE_ACCI3 0xf4d401ff + +/*P1_FFEQ3*/ +#define R0900_P1_FFEQ3 0xf4d5 +#define FFEQ3 REGx(R0900_P1_FFEQ3) +#define F0900_P1_FFE_ACCQ3 0xf4d501ff + +/*P1_FFEI4*/ +#define R0900_P1_FFEI4 0xf4d6 +#define FFEI4 REGx(R0900_P1_FFEI4) +#define F0900_P1_FFE_ACCI4 0xf4d601ff + +/*P1_FFEQ4*/ +#define R0900_P1_FFEQ4 0xf4d7 +#define FFEQ4 REGx(R0900_P1_FFEQ4) +#define F0900_P1_FFE_ACCQ4 0xf4d701ff + +/*P1_FFECFG*/ +#define R0900_P1_FFECFG 0xf4d8 +#define FFECFG REGx(R0900_P1_FFECFG) +#define F0900_P1_EQUALFFE_ON 0xf4d80040 +#define F0900_P1_MU_EQUALFFE 0xf4d80007 + +/*P1_TNRCFG*/ +#define R0900_P1_TNRCFG 0xf4e0 +#define TNRCFG REGx(R0900_P1_TNRCFG) +#define F0900_P1_TUN_ACKFAIL 0xf4e00080 +#define F0900_P1_TUN_TYPE 0xf4e00070 +#define F0900_P1_TUN_SECSTOP 0xf4e00008 +#define F0900_P1_TUN_VCOSRCH 0xf4e00004 +#define F0900_P1_TUN_MADDRESS 0xf4e00003 + +/*P1_TNRCFG2*/ +#define R0900_P1_TNRCFG2 0xf4e1 +#define TNRCFG2 REGx(R0900_P1_TNRCFG2) +#define F0900_P1_TUN_IQSWAP 0xf4e10080 +#define F0900_P1_DIS_BWCALC 0xf4e10004 +#define F0900_P1_SHORT_WAITSTATES 0xf4e10002 + +/*P1_TNRXTAL*/ +#define R0900_P1_TNRXTAL 0xf4e4 +#define TNRXTAL REGx(R0900_P1_TNRXTAL) +#define F0900_P1_TUN_XTALFREQ 0xf4e4001f + +/*P1_TNRSTEPS*/ +#define R0900_P1_TNRSTEPS 0xf4e7 +#define TNRSTEPS REGx(R0900_P1_TNRSTEPS) +#define F0900_P1_TUNER_BW0P125 0xf4e70080 +#define F0900_P1_BWINC_OFFSET 0xf4e70170 +#define F0900_P1_SOFTSTEP_RNG 0xf4e70008 +#define F0900_P1_TUN_BWOFFSET 0xf4e70007 + +/*P1_TNRGAIN*/ +#define R0900_P1_TNRGAIN 0xf4e8 +#define TNRGAIN REGx(R0900_P1_TNRGAIN) +#define F0900_P1_TUN_KDIVEN 0xf4e800c0 +#define F0900_P1_STB6X00_OCK 0xf4e80030 +#define F0900_P1_TUN_GAIN 0xf4e8000f + +/*P1_TNRRF1*/ +#define R0900_P1_TNRRF1 0xf4e9 +#define TNRRF1 REGx(R0900_P1_TNRRF1) +#define F0900_P1_TUN_RFFREQ2 0xf4e900ff +#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2) + +/*P1_TNRRF0*/ +#define R0900_P1_TNRRF0 0xf4ea +#define TNRRF0 REGx(R0900_P1_TNRRF0) +#define F0900_P1_TUN_RFFREQ1 0xf4ea00ff +#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1) + +/*P1_TNRBW*/ +#define R0900_P1_TNRBW 0xf4eb +#define TNRBW REGx(R0900_P1_TNRBW) +#define F0900_P1_TUN_RFFREQ0 0xf4eb00c0 +#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0) +#define F0900_P1_TUN_BW 0xf4eb003f +#define TUN_BW FLDx(F0900_P1_TUN_BW) + +/*P1_TNRADJ*/ +#define R0900_P1_TNRADJ 0xf4ec +#define TNRADJ REGx(R0900_P1_TNRADJ) +#define F0900_P1_STB61X0_CALTIME 0xf4ec0040 + +/*P1_TNRCTL2*/ +#define R0900_P1_TNRCTL2 0xf4ed +#define TNRCTL2 REGx(R0900_P1_TNRCTL2) +#define F0900_P1_STB61X0_RCCKOFF 0xf4ed0080 +#define F0900_P1_STB61X0_ICP_SDOFF 0xf4ed0040 +#define F0900_P1_STB61X0_DCLOOPOFF 0xf4ed0020 +#define F0900_P1_STB61X0_REFOUTSEL 0xf4ed0010 +#define F0900_P1_STB61X0_CALOFF 0xf4ed0008 +#define F0900_P1_STB6XX0_LPT_BEN 0xf4ed0004 +#define F0900_P1_STB6XX0_RX_OSCP 0xf4ed0002 +#define F0900_P1_STB6XX0_SYN 0xf4ed0001 + +/*P1_TNRCFG3*/ +#define R0900_P1_TNRCFG3 0xf4ee +#define TNRCFG3 REGx(R0900_P1_TNRCFG3) +#define F0900_P1_TUN_PLLFREQ 0xf4ee001c +#define F0900_P1_TUN_I2CFREQ_MODE 0xf4ee0003 + +/*P1_TNRLAUNCH*/ +#define R0900_P1_TNRLAUNCH 0xf4f0 +#define TNRLAUNCH REGx(R0900_P1_TNRLAUNCH) + +/*P1_TNRLD*/ +#define R0900_P1_TNRLD 0xf4f0 +#define TNRLD REGx(R0900_P1_TNRLD) +#define F0900_P1_TUNLD_VCOING 0xf4f00080 +#define F0900_P1_TUN_REG1FAIL 0xf4f00040 +#define F0900_P1_TUN_REG2FAIL 0xf4f00020 +#define F0900_P1_TUN_REG3FAIL 0xf4f00010 +#define F0900_P1_TUN_REG4FAIL 0xf4f00008 +#define F0900_P1_TUN_REG5FAIL 0xf4f00004 +#define F0900_P1_TUN_BWING 0xf4f00002 +#define F0900_P1_TUN_LOCKED 0xf4f00001 + +/*P1_TNROBSL*/ +#define R0900_P1_TNROBSL 0xf4f6 +#define TNROBSL REGx(R0900_P1_TNROBSL) +#define F0900_P1_TUN_I2CABORTED 0xf4f60080 +#define F0900_P1_TUN_LPEN 0xf4f60040 +#define F0900_P1_TUN_FCCK 0xf4f60020 +#define F0900_P1_TUN_I2CLOCKED 0xf4f60010 +#define F0900_P1_TUN_PROGDONE 0xf4f6000c +#define F0900_P1_TUN_RFRESTE1 0xf4f60003 +#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1) + +/*P1_TNRRESTE*/ +#define R0900_P1_TNRRESTE 0xf4f7 +#define TNRRESTE REGx(R0900_P1_TNRRESTE) +#define F0900_P1_TUN_RFRESTE0 0xf4f700ff +#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0) + +/*P1_SMAPCOEF7*/ +#define R0900_P1_SMAPCOEF7 0xf500 +#define SMAPCOEF7 REGx(R0900_P1_SMAPCOEF7) +#define F0900_P1_DIS_QSCALE 0xf5000080 +#define F0900_P1_SMAPCOEF_Q_LLR12 0xf500017f + +/*P1_SMAPCOEF6*/ +#define R0900_P1_SMAPCOEF6 0xf501 +#define SMAPCOEF6 REGx(R0900_P1_SMAPCOEF6) +#define F0900_P1_ADJ_8PSKLLR1 0xf5010004 +#define F0900_P1_OLD_8PSKLLR1 0xf5010002 +#define F0900_P1_DIS_AB8PSK 0xf5010001 + +/*P1_SMAPCOEF5*/ +#define R0900_P1_SMAPCOEF5 0xf502 +#define SMAPCOEF5 REGx(R0900_P1_SMAPCOEF5) +#define F0900_P1_DIS_8SCALE 0xf5020080 +#define F0900_P1_SMAPCOEF_8P_LLR23 0xf502017f + +/*P1_NCO2MAX1*/ +#define R0900_P1_NCO2MAX1 0xf514 +#define NCO2MAX1 REGx(R0900_P1_NCO2MAX1) +#define F0900_P1_TETA2_MAXVABS1 0xf51400ff + +/*P1_NCO2MAX0*/ +#define R0900_P1_NCO2MAX0 0xf515 +#define NCO2MAX0 REGx(R0900_P1_NCO2MAX0) +#define F0900_P1_TETA2_MAXVABS0 0xf51500ff + +/*P1_NCO2FR1*/ +#define R0900_P1_NCO2FR1 0xf516 +#define NCO2FR1 REGx(R0900_P1_NCO2FR1) +#define F0900_P1_NCO2FINAL_ANGLE1 0xf51600ff + +/*P1_NCO2FR0*/ +#define R0900_P1_NCO2FR0 0xf517 +#define NCO2FR0 REGx(R0900_P1_NCO2FR0) +#define F0900_P1_NCO2FINAL_ANGLE0 0xf51700ff + +/*P1_CFR2AVRGE1*/ +#define R0900_P1_CFR2AVRGE1 0xf518 +#define CFR2AVRGE1 REGx(R0900_P1_CFR2AVRGE1) +#define F0900_P1_I2C_CFR2AVERAGE1 0xf51800ff + +/*P1_CFR2AVRGE0*/ +#define R0900_P1_CFR2AVRGE0 0xf519 +#define CFR2AVRGE0 REGx(R0900_P1_CFR2AVRGE0) +#define F0900_P1_I2C_CFR2AVERAGE0 0xf51900ff + +/*P1_DMDPLHSTAT*/ +#define R0900_P1_DMDPLHSTAT 0xf520 +#define DMDPLHSTAT REGx(R0900_P1_DMDPLHSTAT) +#define F0900_P1_PLH_STATISTIC 0xf52000ff + +/*P1_LOCKTIME3*/ +#define R0900_P1_LOCKTIME3 0xf522 +#define LOCKTIME3 REGx(R0900_P1_LOCKTIME3) +#define F0900_P1_DEMOD_LOCKTIME3 0xf52200ff + +/*P1_LOCKTIME2*/ +#define R0900_P1_LOCKTIME2 0xf523 +#define LOCKTIME2 REGx(R0900_P1_LOCKTIME2) +#define F0900_P1_DEMOD_LOCKTIME2 0xf52300ff + +/*P1_LOCKTIME1*/ +#define R0900_P1_LOCKTIME1 0xf524 +#define LOCKTIME1 REGx(R0900_P1_LOCKTIME1) +#define F0900_P1_DEMOD_LOCKTIME1 0xf52400ff + +/*P1_LOCKTIME0*/ +#define R0900_P1_LOCKTIME0 0xf525 +#define LOCKTIME0 REGx(R0900_P1_LOCKTIME0) +#define F0900_P1_DEMOD_LOCKTIME0 0xf52500ff + +/*P1_VITSCALE*/ +#define R0900_P1_VITSCALE 0xf532 +#define VITSCALE REGx(R0900_P1_VITSCALE) +#define F0900_P1_NVTH_NOSRANGE 0xf5320080 +#define F0900_P1_VERROR_MAXMODE 0xf5320040 +#define F0900_P1_NSLOWSN_LOCKED 0xf5320008 +#define F0900_P1_DIS_RSFLOCK 0xf5320002 + +/*P1_FECM*/ +#define R0900_P1_FECM 0xf533 +#define FECM REGx(R0900_P1_FECM) +#define F0900_P1_DSS_DVB 0xf5330080 +#define DSS_DVB FLDx(F0900_P1_DSS_DVB) +#define F0900_P1_DSS_SRCH 0xf5330010 +#define F0900_P1_SYNCVIT 0xf5330002 +#define F0900_P1_IQINV 0xf5330001 +#define IQINV FLDx(F0900_P1_IQINV) + +/*P1_VTH12*/ +#define R0900_P1_VTH12 0xf534 +#define VTH12 REGx(R0900_P1_VTH12) +#define F0900_P1_VTH12 0xf53400ff + +/*P1_VTH23*/ +#define R0900_P1_VTH23 0xf535 +#define VTH23 REGx(R0900_P1_VTH23) +#define F0900_P1_VTH23 0xf53500ff + +/*P1_VTH34*/ +#define R0900_P1_VTH34 0xf536 +#define VTH34 REGx(R0900_P1_VTH34) +#define F0900_P1_VTH34 0xf53600ff + +/*P1_VTH56*/ +#define R0900_P1_VTH56 0xf537 +#define VTH56 REGx(R0900_P1_VTH56) +#define F0900_P1_VTH56 0xf53700ff + +/*P1_VTH67*/ +#define R0900_P1_VTH67 0xf538 +#define VTH67 REGx(R0900_P1_VTH67) +#define F0900_P1_VTH67 0xf53800ff + +/*P1_VTH78*/ +#define R0900_P1_VTH78 0xf539 +#define VTH78 REGx(R0900_P1_VTH78) +#define F0900_P1_VTH78 0xf53900ff + +/*P1_VITCURPUN*/ +#define R0900_P1_VITCURPUN 0xf53a +#define VITCURPUN REGx(R0900_P1_VITCURPUN) +#define F0900_P1_VIT_CURPUN 0xf53a001f +#define VIT_CURPUN FLDx(F0900_P1_VIT_CURPUN) + +/*P1_VERROR*/ +#define R0900_P1_VERROR 0xf53b +#define VERROR REGx(R0900_P1_VERROR) +#define F0900_P1_REGERR_VIT 0xf53b00ff + +/*P1_PRVIT*/ +#define R0900_P1_PRVIT 0xf53c +#define PRVIT REGx(R0900_P1_PRVIT) +#define F0900_P1_DIS_VTHLOCK 0xf53c0040 +#define F0900_P1_E7_8VIT 0xf53c0020 +#define F0900_P1_E6_7VIT 0xf53c0010 +#define F0900_P1_E5_6VIT 0xf53c0008 +#define F0900_P1_E3_4VIT 0xf53c0004 +#define F0900_P1_E2_3VIT 0xf53c0002 +#define F0900_P1_E1_2VIT 0xf53c0001 + +/*P1_VAVSRVIT*/ +#define R0900_P1_VAVSRVIT 0xf53d +#define VAVSRVIT REGx(R0900_P1_VAVSRVIT) +#define F0900_P1_AMVIT 0xf53d0080 +#define F0900_P1_FROZENVIT 0xf53d0040 +#define F0900_P1_SNVIT 0xf53d0030 +#define F0900_P1_TOVVIT 0xf53d000c +#define F0900_P1_HYPVIT 0xf53d0003 + +/*P1_VSTATUSVIT*/ +#define R0900_P1_VSTATUSVIT 0xf53e +#define VSTATUSVIT REGx(R0900_P1_VSTATUSVIT) +#define F0900_P1_PRFVIT 0xf53e0010 +#define PRFVIT FLDx(F0900_P1_PRFVIT) +#define F0900_P1_LOCKEDVIT 0xf53e0008 +#define LOCKEDVIT FLDx(F0900_P1_LOCKEDVIT) + +/*P1_VTHINUSE*/ +#define R0900_P1_VTHINUSE 0xf53f +#define VTHINUSE REGx(R0900_P1_VTHINUSE) +#define F0900_P1_VIT_INUSE 0xf53f00ff + +/*P1_KDIV12*/ +#define R0900_P1_KDIV12 0xf540 +#define KDIV12 REGx(R0900_P1_KDIV12) +#define F0900_P1_K_DIVIDER_12 0xf540007f + +/*P1_KDIV23*/ +#define R0900_P1_KDIV23 0xf541 +#define KDIV23 REGx(R0900_P1_KDIV23) +#define F0900_P1_K_DIVIDER_23 0xf541007f + +/*P1_KDIV34*/ +#define R0900_P1_KDIV34 0xf542 +#define KDIV34 REGx(R0900_P1_KDIV34) +#define F0900_P1_K_DIVIDER_34 0xf542007f + +/*P1_KDIV56*/ +#define R0900_P1_KDIV56 0xf543 +#define KDIV56 REGx(R0900_P1_KDIV56) +#define F0900_P1_K_DIVIDER_56 0xf543007f + +/*P1_KDIV67*/ +#define R0900_P1_KDIV67 0xf544 +#define KDIV67 REGx(R0900_P1_KDIV67) +#define F0900_P1_K_DIVIDER_67 0xf544007f + +/*P1_KDIV78*/ +#define R0900_P1_KDIV78 0xf545 +#define KDIV78 REGx(R0900_P1_KDIV78) +#define F0900_P1_K_DIVIDER_78 0xf545007f + +/*P1_PDELCTRL1*/ +#define R0900_P1_PDELCTRL1 0xf550 +#define PDELCTRL1 REGx(R0900_P1_PDELCTRL1) +#define F0900_P1_INV_MISMASK 0xf5500080 +#define F0900_P1_FILTER_EN 0xf5500020 +#define F0900_P1_EN_MIS00 0xf5500002 +#define F0900_P1_ALGOSWRST 0xf5500001 +#define ALGOSWRST FLDx(F0900_P1_ALGOSWRST) + +/*P1_PDELCTRL2*/ +#define R0900_P1_PDELCTRL2 0xf551 +#define PDELCTRL2 REGx(R0900_P1_PDELCTRL2) +#define F0900_P1_RESET_UPKO_COUNT 0xf5510040 +#define RESET_UPKO_COUNT FLDx(F0900_P1_RESET_UPKO_COUNT) +#define F0900_P1_FRAME_MODE 0xf5510002 +#define F0900_P1_NOBCHERRFLG_USE 0xf5510001 + +/*P1_HYSTTHRESH*/ +#define R0900_P1_HYSTTHRESH 0xf554 +#define HYSTTHRESH REGx(R0900_P1_HYSTTHRESH) +#define F0900_P1_UNLCK_THRESH 0xf55400f0 +#define F0900_P1_DELIN_LCK_THRESH 0xf554000f + +/*P1_ISIENTRY*/ +#define R0900_P1_ISIENTRY 0xf55e +#define ISIENTRY REGx(R0900_P1_ISIENTRY) +#define F0900_P1_ISI_ENTRY 0xf55e00ff + +/*P1_ISIBITENA*/ +#define R0900_P1_ISIBITENA 0xf55f +#define ISIBITENA REGx(R0900_P1_ISIBITENA) +#define F0900_P1_ISI_BIT_EN 0xf55f00ff + +/*P1_MATSTR1*/ +#define R0900_P1_MATSTR1 0xf560 +#define MATSTR1 REGx(R0900_P1_MATSTR1) +#define F0900_P1_MATYPE_CURRENT1 0xf56000ff + +/*P1_MATSTR0*/ +#define R0900_P1_MATSTR0 0xf561 +#define MATSTR0 REGx(R0900_P1_MATSTR0) +#define F0900_P1_MATYPE_CURRENT0 0xf56100ff + +/*P1_UPLSTR1*/ +#define R0900_P1_UPLSTR1 0xf562 +#define UPLSTR1 REGx(R0900_P1_UPLSTR1) +#define F0900_P1_UPL_CURRENT1 0xf56200ff + +/*P1_UPLSTR0*/ +#define R0900_P1_UPLSTR0 0xf563 +#define UPLSTR0 REGx(R0900_P1_UPLSTR0) +#define F0900_P1_UPL_CURRENT0 0xf56300ff + +/*P1_DFLSTR1*/ +#define R0900_P1_DFLSTR1 0xf564 +#define DFLSTR1 REGx(R0900_P1_DFLSTR1) +#define F0900_P1_DFL_CURRENT1 0xf56400ff + +/*P1_DFLSTR0*/ +#define R0900_P1_DFLSTR0 0xf565 +#define DFLSTR0 REGx(R0900_P1_DFLSTR0) +#define F0900_P1_DFL_CURRENT0 0xf56500ff + +/*P1_SYNCSTR*/ +#define R0900_P1_SYNCSTR 0xf566 +#define SYNCSTR REGx(R0900_P1_SYNCSTR) +#define F0900_P1_SYNC_CURRENT 0xf56600ff + +/*P1_SYNCDSTR1*/ +#define R0900_P1_SYNCDSTR1 0xf567 +#define SYNCDSTR1 REGx(R0900_P1_SYNCDSTR1) +#define F0900_P1_SYNCD_CURRENT1 0xf56700ff + +/*P1_SYNCDSTR0*/ +#define R0900_P1_SYNCDSTR0 0xf568 +#define SYNCDSTR0 REGx(R0900_P1_SYNCDSTR0) +#define F0900_P1_SYNCD_CURRENT0 0xf56800ff + +/*P1_PDELSTATUS1*/ +#define R0900_P1_PDELSTATUS1 0xf569 +#define F0900_P1_PKTDELIN_DELOCK 0xf5690080 +#define F0900_P1_SYNCDUPDFL_BADDFL 0xf5690040 +#define F0900_P1_CONTINUOUS_STREAM 0xf5690020 +#define F0900_P1_UNACCEPTED_STREAM 0xf5690010 +#define F0900_P1_BCH_ERROR_FLAG 0xf5690008 +#define F0900_P1_PKTDELIN_LOCK 0xf5690002 +#define PKTDELIN_LOCK FLDx(F0900_P1_PKTDELIN_LOCK) +#define F0900_P1_FIRST_LOCK 0xf5690001 + +/*P1_PDELSTATUS2*/ +#define R0900_P1_PDELSTATUS2 0xf56a +#define F0900_P1_FRAME_MODCOD 0xf56a007c +#define F0900_P1_FRAME_TYPE 0xf56a0003 + +/*P1_BBFCRCKO1*/ +#define R0900_P1_BBFCRCKO1 0xf56b +#define BBFCRCKO1 REGx(R0900_P1_BBFCRCKO1) +#define F0900_P1_BBHCRC_KOCNT1 0xf56b00ff + +/*P1_BBFCRCKO0*/ +#define R0900_P1_BBFCRCKO0 0xf56c +#define BBFCRCKO0 REGx(R0900_P1_BBFCRCKO0) +#define F0900_P1_BBHCRC_KOCNT0 0xf56c00ff + +/*P1_UPCRCKO1*/ +#define R0900_P1_UPCRCKO1 0xf56d +#define UPCRCKO1 REGx(R0900_P1_UPCRCKO1) +#define F0900_P1_PKTCRC_KOCNT1 0xf56d00ff + +/*P1_UPCRCKO0*/ +#define R0900_P1_UPCRCKO0 0xf56e +#define UPCRCKO0 REGx(R0900_P1_UPCRCKO0) +#define F0900_P1_PKTCRC_KOCNT0 0xf56e00ff + +/*P1_PDELCTRL3*/ +#define R0900_P1_PDELCTRL3 0xf56f +#define PDELCTRL3 REGx(R0900_P1_PDELCTRL3) +#define F0900_P1_PKTDEL_CONTFAIL 0xf56f0080 +#define F0900_P1_NOFIFO_BCHERR 0xf56f0020 + +/*P1_TSSTATEM*/ +#define R0900_P1_TSSTATEM 0xf570 +#define TSSTATEM REGx(R0900_P1_TSSTATEM) +#define F0900_P1_TSDIL_ON 0xf5700080 +#define F0900_P1_TSRS_ON 0xf5700020 +#define F0900_P1_TSDESCRAMB_ON 0xf5700010 +#define F0900_P1_TSFRAME_MODE 0xf5700008 +#define F0900_P1_TS_DISABLE 0xf5700004 +#define F0900_P1_TSOUT_NOSYNC 0xf5700001 + +/*P1_TSCFGH*/ +#define R0900_P1_TSCFGH 0xf572 +#define TSCFGH REGx(R0900_P1_TSCFGH) +#define F0900_P1_TSFIFO_DVBCI 0xf5720080 +#define F0900_P1_TSFIFO_SERIAL 0xf5720040 +#define F0900_P1_TSFIFO_TEIUPDATE 0xf5720020 +#define F0900_P1_TSFIFO_DUTY50 0xf5720010 +#define F0900_P1_TSFIFO_HSGNLOUT 0xf5720008 +#define F0900_P1_TSFIFO_ERRMODE 0xf5720006 +#define F0900_P1_RST_HWARE 0xf5720001 +#define RST_HWARE FLDx(F0900_P1_RST_HWARE) + +/*P1_TSCFGM*/ +#define R0900_P1_TSCFGM 0xf573 +#define TSCFGM REGx(R0900_P1_TSCFGM) +#define F0900_P1_TSFIFO_MANSPEED 0xf57300c0 +#define F0900_P1_TSFIFO_PERMDATA 0xf5730020 +#define F0900_P1_TSFIFO_DPUNACT 0xf5730002 +#define F0900_P1_TSFIFO_INVDATA 0xf5730001 + +/*P1_TSCFGL*/ +#define R0900_P1_TSCFGL 0xf574 +#define TSCFGL REGx(R0900_P1_TSCFGL) +#define F0900_P1_TSFIFO_BCLKDEL1CK 0xf57400c0 +#define F0900_P1_BCHERROR_MODE 0xf5740030 +#define F0900_P1_TSFIFO_NSGNL2DATA 0xf5740008 +#define F0900_P1_TSFIFO_EMBINDVB 0xf5740004 +#define F0900_P1_TSFIFO_BITSPEED 0xf5740003 + +/*P1_TSINSDELH*/ +#define R0900_P1_TSINSDELH 0xf576 +#define TSINSDELH REGx(R0900_P1_TSINSDELH) +#define F0900_P1_TSDEL_SYNCBYTE 0xf5760080 +#define F0900_P1_TSDEL_XXHEADER 0xf5760040 +#define F0900_P1_TSDEL_BBHEADER 0xf5760020 +#define F0900_P1_TSDEL_DATAFIELD 0xf5760010 +#define F0900_P1_TSINSDEL_ISCR 0xf5760008 +#define F0900_P1_TSINSDEL_NPD 0xf5760004 +#define F0900_P1_TSINSDEL_RSPARITY 0xf5760002 +#define F0900_P1_TSINSDEL_CRC8 0xf5760001 + +/*P1_TSDIVN*/ +#define R0900_P1_TSDIVN 0xf579 +#define TSDIVN REGx(R0900_P1_TSDIVN) +#define F0900_P1_TSFIFO_SPEEDMODE 0xf57900c0 + +/*P1_TSCFG4*/ +#define R0900_P1_TSCFG4 0xf57a +#define TSCFG4 REGx(R0900_P1_TSCFG4) +#define F0900_P1_TSFIFO_TSSPEEDMODE 0xf57a00c0 + +/*P1_TSSPEED*/ +#define R0900_P1_TSSPEED 0xf580 +#define TSSPEED REGx(R0900_P1_TSSPEED) +#define F0900_P1_TSFIFO_OUTSPEED 0xf58000ff + +/*P1_TSSTATUS*/ +#define R0900_P1_TSSTATUS 0xf581 +#define TSSTATUS REGx(R0900_P1_TSSTATUS) +#define F0900_P1_TSFIFO_LINEOK 0xf5810080 +#define TSFIFO_LINEOK FLDx(F0900_P1_TSFIFO_LINEOK) +#define F0900_P1_TSFIFO_ERROR 0xf5810040 +#define F0900_P1_DIL_READY 0xf5810001 + +/*P1_TSSTATUS2*/ +#define R0900_P1_TSSTATUS2 0xf582 +#define TSSTATUS2 REGx(R0900_P1_TSSTATUS2) +#define F0900_P1_TSFIFO_DEMODSEL 0xf5820080 +#define F0900_P1_TSFIFOSPEED_STORE 0xf5820040 +#define F0900_P1_DILXX_RESET 0xf5820020 +#define F0900_P1_TSSERIAL_IMPOS 0xf5820010 +#define F0900_P1_SCRAMBDETECT 0xf5820002 + +/*P1_TSBITRATE1*/ +#define R0900_P1_TSBITRATE1 0xf583 +#define TSBITRATE1 REGx(R0900_P1_TSBITRATE1) +#define F0900_P1_TSFIFO_BITRATE1 0xf58300ff + +/*P1_TSBITRATE0*/ +#define R0900_P1_TSBITRATE0 0xf584 +#define TSBITRATE0 REGx(R0900_P1_TSBITRATE0) +#define F0900_P1_TSFIFO_BITRATE0 0xf58400ff + +/*P1_ERRCTRL1*/ +#define R0900_P1_ERRCTRL1 0xf598 +#define ERRCTRL1 REGx(R0900_P1_ERRCTRL1) +#define F0900_P1_ERR_SOURCE1 0xf59800f0 +#define F0900_P1_NUM_EVENT1 0xf5980007 + +/*P1_ERRCNT12*/ +#define R0900_P1_ERRCNT12 0xf599 +#define ERRCNT12 REGx(R0900_P1_ERRCNT12) +#define F0900_P1_ERRCNT1_OLDVALUE 0xf5990080 +#define F0900_P1_ERR_CNT12 0xf599007f +#define ERR_CNT12 FLDx(F0900_P1_ERR_CNT12) + +/*P1_ERRCNT11*/ +#define R0900_P1_ERRCNT11 0xf59a +#define ERRCNT11 REGx(R0900_P1_ERRCNT11) +#define F0900_P1_ERR_CNT11 0xf59a00ff +#define ERR_CNT11 FLDx(F0900_P1_ERR_CNT11) + +/*P1_ERRCNT10*/ +#define R0900_P1_ERRCNT10 0xf59b +#define ERRCNT10 REGx(R0900_P1_ERRCNT10) +#define F0900_P1_ERR_CNT10 0xf59b00ff +#define ERR_CNT10 FLDx(F0900_P1_ERR_CNT10) + +/*P1_ERRCTRL2*/ +#define R0900_P1_ERRCTRL2 0xf59c +#define ERRCTRL2 REGx(R0900_P1_ERRCTRL2) +#define F0900_P1_ERR_SOURCE2 0xf59c00f0 +#define F0900_P1_NUM_EVENT2 0xf59c0007 + +/*P1_ERRCNT22*/ +#define R0900_P1_ERRCNT22 0xf59d +#define ERRCNT22 REGx(R0900_P1_ERRCNT22) +#define F0900_P1_ERRCNT2_OLDVALUE 0xf59d0080 +#define F0900_P1_ERR_CNT22 0xf59d007f +#define ERR_CNT22 FLDx(F0900_P1_ERR_CNT22) + +/*P1_ERRCNT21*/ +#define R0900_P1_ERRCNT21 0xf59e +#define ERRCNT21 REGx(R0900_P1_ERRCNT21) +#define F0900_P1_ERR_CNT21 0xf59e00ff +#define ERR_CNT21 FLDx(F0900_P1_ERR_CNT21) + +/*P1_ERRCNT20*/ +#define R0900_P1_ERRCNT20 0xf59f +#define ERRCNT20 REGx(R0900_P1_ERRCNT20) +#define F0900_P1_ERR_CNT20 0xf59f00ff +#define ERR_CNT20 FLDx(F0900_P1_ERR_CNT20) + +/*P1_FECSPY*/ +#define R0900_P1_FECSPY 0xf5a0 +#define FECSPY REGx(R0900_P1_FECSPY) +#define F0900_P1_SPY_ENABLE 0xf5a00080 +#define F0900_P1_NO_SYNCBYTE 0xf5a00040 +#define F0900_P1_SERIAL_MODE 0xf5a00020 +#define F0900_P1_UNUSUAL_PACKET 0xf5a00010 +#define F0900_P1_BERMETER_DATAMODE 0xf5a00008 +#define F0900_P1_BERMETER_LMODE 0xf5a00002 +#define F0900_P1_BERMETER_RESET 0xf5a00001 + +/*P1_FSPYCFG*/ +#define R0900_P1_FSPYCFG 0xf5a1 +#define FSPYCFG REGx(R0900_P1_FSPYCFG) +#define F0900_P1_FECSPY_INPUT 0xf5a100c0 +#define F0900_P1_RST_ON_ERROR 0xf5a10020 +#define F0900_P1_ONE_SHOT 0xf5a10010 +#define F0900_P1_I2C_MODE 0xf5a1000c +#define F0900_P1_SPY_HYSTERESIS 0xf5a10003 + +/*P1_FSPYDATA*/ +#define R0900_P1_FSPYDATA 0xf5a2 +#define FSPYDATA REGx(R0900_P1_FSPYDATA) +#define F0900_P1_SPY_STUFFING 0xf5a20080 +#define F0900_P1_SPY_CNULLPKT 0xf5a20020 +#define F0900_P1_SPY_OUTDATA_MODE 0xf5a2001f + +/*P1_FSPYOUT*/ +#define R0900_P1_FSPYOUT 0xf5a3 +#define FSPYOUT REGx(R0900_P1_FSPYOUT) +#define F0900_P1_FSPY_DIRECT 0xf5a30080 +#define F0900_P1_STUFF_MODE 0xf5a30007 + +/*P1_FSTATUS*/ +#define R0900_P1_FSTATUS 0xf5a4 +#define FSTATUS REGx(R0900_P1_FSTATUS) +#define F0900_P1_SPY_ENDSIM 0xf5a40080 +#define F0900_P1_VALID_SIM 0xf5a40040 +#define F0900_P1_FOUND_SIGNAL 0xf5a40020 +#define F0900_P1_DSS_SYNCBYTE 0xf5a40010 +#define F0900_P1_RESULT_STATE 0xf5a4000f + +/*P1_FBERCPT4*/ +#define R0900_P1_FBERCPT4 0xf5a8 +#define FBERCPT4 REGx(R0900_P1_FBERCPT4) +#define F0900_P1_FBERMETER_CPT4 0xf5a800ff + +/*P1_FBERCPT3*/ +#define R0900_P1_FBERCPT3 0xf5a9 +#define FBERCPT3 REGx(R0900_P1_FBERCPT3) +#define F0900_P1_FBERMETER_CPT3 0xf5a900ff + +/*P1_FBERCPT2*/ +#define R0900_P1_FBERCPT2 0xf5aa +#define FBERCPT2 REGx(R0900_P1_FBERCPT2) +#define F0900_P1_FBERMETER_CPT2 0xf5aa00ff + +/*P1_FBERCPT1*/ +#define R0900_P1_FBERCPT1 0xf5ab +#define FBERCPT1 REGx(R0900_P1_FBERCPT1) +#define F0900_P1_FBERMETER_CPT1 0xf5ab00ff + +/*P1_FBERCPT0*/ +#define R0900_P1_FBERCPT0 0xf5ac +#define FBERCPT0 REGx(R0900_P1_FBERCPT0) +#define F0900_P1_FBERMETER_CPT0 0xf5ac00ff + +/*P1_FBERERR2*/ +#define R0900_P1_FBERERR2 0xf5ad +#define FBERERR2 REGx(R0900_P1_FBERERR2) +#define F0900_P1_FBERMETER_ERR2 0xf5ad00ff + +/*P1_FBERERR1*/ +#define R0900_P1_FBERERR1 0xf5ae +#define FBERERR1 REGx(R0900_P1_FBERERR1) +#define F0900_P1_FBERMETER_ERR1 0xf5ae00ff + +/*P1_FBERERR0*/ +#define R0900_P1_FBERERR0 0xf5af +#define FBERERR0 REGx(R0900_P1_FBERERR0) +#define F0900_P1_FBERMETER_ERR0 0xf5af00ff + +/*P1_FSPYBER*/ +#define R0900_P1_FSPYBER 0xf5b2 +#define FSPYBER REGx(R0900_P1_FSPYBER) +#define F0900_P1_FSPYBER_SYNCBYTE 0xf5b20010 +#define F0900_P1_FSPYBER_UNSYNC 0xf5b20008 +#define F0900_P1_FSPYBER_CTIME 0xf5b20007 + +/*RCCFG2*/ +#define R0900_RCCFG2 0xf600 + +/*TSGENERAL*/ +#define R0900_TSGENERAL 0xf630 +#define F0900_TSFIFO_DISTS2PAR 0xf6300040 +#define F0900_MUXSTREAM_OUTMODE 0xf6300008 +#define F0900_TSFIFO_PERMPARAL 0xf6300006 + +/*TSGENERAL1X*/ +#define R0900_TSGENERAL1X 0xf670 + +/*NBITER_NF4*/ +#define R0900_NBITER_NF4 0xfa03 +#define F0900_NBITER_NF_QP_1_2 0xfa0300ff + +/*NBITER_NF5*/ +#define R0900_NBITER_NF5 0xfa04 +#define F0900_NBITER_NF_QP_3_5 0xfa0400ff + +/*NBITER_NF6*/ +#define R0900_NBITER_NF6 0xfa05 +#define F0900_NBITER_NF_QP_2_3 0xfa0500ff + +/*NBITER_NF7*/ +#define R0900_NBITER_NF7 0xfa06 +#define F0900_NBITER_NF_QP_3_4 0xfa0600ff + +/*NBITER_NF8*/ +#define R0900_NBITER_NF8 0xfa07 +#define F0900_NBITER_NF_QP_4_5 0xfa0700ff + +/*NBITER_NF9*/ +#define R0900_NBITER_NF9 0xfa08 +#define F0900_NBITER_NF_QP_5_6 0xfa0800ff + +/*NBITER_NF10*/ +#define R0900_NBITER_NF10 0xfa09 +#define F0900_NBITER_NF_QP_8_9 0xfa0900ff + +/*NBITER_NF11*/ +#define R0900_NBITER_NF11 0xfa0a +#define F0900_NBITER_NF_QP_9_10 0xfa0a00ff + +/*NBITER_NF12*/ +#define R0900_NBITER_NF12 0xfa0b +#define F0900_NBITER_NF_8P_3_5 0xfa0b00ff + +/*NBITER_NF13*/ +#define R0900_NBITER_NF13 0xfa0c +#define F0900_NBITER_NF_8P_2_3 0xfa0c00ff + +/*NBITER_NF14*/ +#define R0900_NBITER_NF14 0xfa0d +#define F0900_NBITER_NF_8P_3_4 0xfa0d00ff + +/*NBITER_NF15*/ +#define R0900_NBITER_NF15 0xfa0e +#define F0900_NBITER_NF_8P_5_6 0xfa0e00ff + +/*NBITER_NF16*/ +#define R0900_NBITER_NF16 0xfa0f +#define F0900_NBITER_NF_8P_8_9 0xfa0f00ff + +/*NBITER_NF17*/ +#define R0900_NBITER_NF17 0xfa10 +#define F0900_NBITER_NF_8P_9_10 0xfa1000ff + +/*NBITERNOERR*/ +#define R0900_NBITERNOERR 0xfa3f +#define F0900_NBITER_STOP_CRIT 0xfa3f000f + +/*GAINLLR_NF4*/ +#define R0900_GAINLLR_NF4 0xfa43 +#define F0900_GAINLLR_NF_QP_1_2 0xfa43007f + +/*GAINLLR_NF5*/ +#define R0900_GAINLLR_NF5 0xfa44 +#define F0900_GAINLLR_NF_QP_3_5 0xfa44007f + +/*GAINLLR_NF6*/ +#define R0900_GAINLLR_NF6 0xfa45 +#define F0900_GAINLLR_NF_QP_2_3 0xfa45007f + +/*GAINLLR_NF7*/ +#define R0900_GAINLLR_NF7 0xfa46 +#define F0900_GAINLLR_NF_QP_3_4 0xfa46007f + +/*GAINLLR_NF8*/ +#define R0900_GAINLLR_NF8 0xfa47 +#define F0900_GAINLLR_NF_QP_4_5 0xfa47007f + +/*GAINLLR_NF9*/ +#define R0900_GAINLLR_NF9 0xfa48 +#define F0900_GAINLLR_NF_QP_5_6 0xfa48007f + +/*GAINLLR_NF10*/ +#define R0900_GAINLLR_NF10 0xfa49 +#define F0900_GAINLLR_NF_QP_8_9 0xfa49007f + +/*GAINLLR_NF11*/ +#define R0900_GAINLLR_NF11 0xfa4a +#define F0900_GAINLLR_NF_QP_9_10 0xfa4a007f + +/*GAINLLR_NF12*/ +#define R0900_GAINLLR_NF12 0xfa4b +#define F0900_GAINLLR_NF_8P_3_5 0xfa4b007f + +/*GAINLLR_NF13*/ +#define R0900_GAINLLR_NF13 0xfa4c +#define F0900_GAINLLR_NF_8P_2_3 0xfa4c007f + +/*GAINLLR_NF14*/ +#define R0900_GAINLLR_NF14 0xfa4d +#define F0900_GAINLLR_NF_8P_3_4 0xfa4d007f + +/*GAINLLR_NF15*/ +#define R0900_GAINLLR_NF15 0xfa4e +#define F0900_GAINLLR_NF_8P_5_6 0xfa4e007f + +/*GAINLLR_NF16*/ +#define R0900_GAINLLR_NF16 0xfa4f +#define F0900_GAINLLR_NF_8P_8_9 0xfa4f007f + +/*GAINLLR_NF17*/ +#define R0900_GAINLLR_NF17 0xfa50 +#define F0900_GAINLLR_NF_8P_9_10 0xfa50007f + +/*CFGEXT*/ +#define R0900_CFGEXT 0xfa80 +#define F0900_STAGMODE 0xfa800080 +#define F0900_BYPBCH 0xfa800040 +#define F0900_BYPLDPC 0xfa800020 +#define F0900_LDPCMODE 0xfa800010 +#define F0900_INVLLRSIGN 0xfa800008 +#define F0900_SHORTMULT 0xfa800004 +#define F0900_EXTERNTX 0xfa800001 + +/*GENCFG*/ +#define R0900_GENCFG 0xfa86 +#define F0900_BROADCAST 0xfa860010 +#define F0900_PRIORITY 0xfa860002 +#define F0900_DDEMOD 0xfa860001 + +/*LDPCERR1*/ +#define R0900_LDPCERR1 0xfa96 +#define F0900_LDPC_ERRORS_COUNTER1 0xfa9600ff + +/*LDPCERR0*/ +#define R0900_LDPCERR0 0xfa97 +#define F0900_LDPC_ERRORS_COUNTER0 0xfa9700ff + +/*BCHERR*/ +#define R0900_BCHERR 0xfa98 +#define F0900_ERRORFLAG 0xfa980010 +#define F0900_BCH_ERRORS_COUNTER 0xfa98000f + +/*TSTRES0*/ +#define R0900_TSTRES0 0xff11 +#define F0900_FRESFEC 0xff110080 + +/*P2_TCTL4*/ +#define R0900_P2_TCTL4 0xff28 +#define F0900_P2_PN4_SELECT 0xff280020 + +/*P1_TCTL4*/ +#define R0900_P1_TCTL4 0xff48 +#define TCTL4 shiftx(R0900_P1_TCTL4, demod, 0x20) +#define F0900_P1_PN4_SELECT 0xff480020 + +/*P2_TSTDISRX*/ +#define R0900_P2_TSTDISRX 0xff65 +#define F0900_P2_PIN_SELECT1 0xff650008 + +/*P1_TSTDISRX*/ +#define R0900_P1_TSTDISRX 0xff67 +#define TSTDISRX shiftx(R0900_P1_TSTDISRX, demod, 2) +#define F0900_P1_PIN_SELECT1 0xff670008 +#define PIN_SELECT1 shiftx(F0900_P1_PIN_SELECT1, demod, 0x20000) + +#define STV0900_NBREGS 723 +#define STV0900_NBFIELDS 1420 + +#endif + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_sw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_sw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_sw.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv0900_sw.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2034 @@ +/* + * stv0900_sw.c + * + * Driver for ST STV0900 satellite demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "stv0900.h" +#include "stv0900_reg.h" +#include "stv0900_priv.h" + +s32 shiftx(s32 x, int demod, s32 shift) +{ + if (demod == 1) + return x - shift; + + return x; +} + +int stv0900_check_signal_presence(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + s32 carr_offset, + agc2_integr, + max_carrier; + + int no_signal = FALSE; + + carr_offset = (stv0900_read_reg(intp, CFR2) << 8) + | stv0900_read_reg(intp, CFR1); + carr_offset = ge2comp(carr_offset, 16); + agc2_integr = (stv0900_read_reg(intp, AGC2I1) << 8) + | stv0900_read_reg(intp, AGC2I0); + max_carrier = intp->srch_range[demod] / 1000; + + max_carrier += (max_carrier / 10); + max_carrier = 65536 * (max_carrier / 2); + max_carrier /= intp->mclk / 1000; + if (max_carrier > 0x4000) + max_carrier = 0x4000; + + if ((agc2_integr > 0x2000) + || (carr_offset > (2 * max_carrier)) + || (carr_offset < (-2 * max_carrier))) + no_signal = TRUE; + + return no_signal; +} + +static void stv0900_get_sw_loop_params(struct stv0900_internal *intp, + s32 *frequency_inc, s32 *sw_timeout, + s32 *steps, + enum fe_stv0900_demod_num demod) +{ + s32 timeout, freq_inc, max_steps, srate, max_carrier; + + enum fe_stv0900_search_standard standard; + + srate = intp->symbol_rate[demod]; + max_carrier = intp->srch_range[demod] / 1000; + max_carrier += max_carrier / 10; + standard = intp->srch_standard[demod]; + + max_carrier = 65536 * (max_carrier / 2); + max_carrier /= intp->mclk / 1000; + + if (max_carrier > 0x4000) + max_carrier = 0x4000; + + freq_inc = srate; + freq_inc /= intp->mclk >> 10; + freq_inc = freq_inc << 6; + + switch (standard) { + case STV0900_SEARCH_DVBS1: + case STV0900_SEARCH_DSS: + freq_inc *= 3; + timeout = 20; + break; + case STV0900_SEARCH_DVBS2: + freq_inc *= 4; + timeout = 25; + break; + case STV0900_AUTO_SEARCH: + default: + freq_inc *= 3; + timeout = 25; + break; + } + + freq_inc /= 100; + + if ((freq_inc > max_carrier) || (freq_inc < 0)) + freq_inc = max_carrier / 2; + + timeout *= 27500; + + if (srate > 0) + timeout /= srate / 1000; + + if ((timeout > 100) || (timeout < 0)) + timeout = 100; + + max_steps = (max_carrier / freq_inc) + 1; + + if ((max_steps > 100) || (max_steps < 0)) { + max_steps = 100; + freq_inc = max_carrier / max_steps; + } + + *frequency_inc = freq_inc; + *sw_timeout = timeout; + *steps = max_steps; + +} + +static int stv0900_search_carr_sw_loop(struct stv0900_internal *intp, + s32 FreqIncr, s32 Timeout, int zigzag, + s32 MaxStep, enum fe_stv0900_demod_num demod) +{ + int no_signal, + lock = FALSE; + s32 stepCpt, + freqOffset, + max_carrier; + + max_carrier = intp->srch_range[demod] / 1000; + max_carrier += (max_carrier / 10); + + max_carrier = 65536 * (max_carrier / 2); + max_carrier /= intp->mclk / 1000; + + if (max_carrier > 0x4000) + max_carrier = 0x4000; + + if (zigzag == TRUE) + freqOffset = 0; + else + freqOffset = -max_carrier + FreqIncr; + + stepCpt = 0; + + do { + stv0900_write_reg(intp, DMDISTATE, 0x1c); + stv0900_write_reg(intp, CFRINIT1, (freqOffset / 256) & 0xff); + stv0900_write_reg(intp, CFRINIT0, freqOffset & 0xff); + stv0900_write_reg(intp, DMDISTATE, 0x18); + stv0900_write_bits(intp, ALGOSWRST, 1); + + if (intp->chip_id == 0x12) { + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_bits(intp, RST_HWARE, 0); + } + + if (zigzag == TRUE) { + if (freqOffset >= 0) + freqOffset = -freqOffset - 2 * FreqIncr; + else + freqOffset = -freqOffset; + } else + freqOffset += + 2 * FreqIncr; + + stepCpt++; + lock = stv0900_get_demod_lock(intp, demod, Timeout); + no_signal = stv0900_check_signal_presence(intp, demod); + + } while ((lock == FALSE) + && (no_signal == FALSE) + && ((freqOffset - FreqIncr) < max_carrier) + && ((freqOffset + FreqIncr) > -max_carrier) + && (stepCpt < MaxStep)); + + stv0900_write_bits(intp, ALGOSWRST, 0); + + return lock; +} + +static int stv0900_sw_algo(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + int lock = FALSE, + no_signal, + zigzag; + s32 s2fw, + fqc_inc, + sft_stp_tout, + trial_cntr, + max_steps; + + stv0900_get_sw_loop_params(intp, &fqc_inc, &sft_stp_tout, + &max_steps, demod); + switch (intp->srch_standard[demod]) { + case STV0900_SEARCH_DVBS1: + case STV0900_SEARCH_DSS: + if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, CARFREQ, 0x3b); + else + stv0900_write_reg(intp, CARFREQ, 0xef); + + stv0900_write_reg(intp, DMDCFGMD, 0x49); + zigzag = FALSE; + break; + case STV0900_SEARCH_DVBS2: + if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, CORRELABS, 0x79); + else + stv0900_write_reg(intp, CORRELABS, 0x68); + + stv0900_write_reg(intp, DMDCFGMD, 0x89); + + zigzag = TRUE; + break; + case STV0900_AUTO_SEARCH: + default: + if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, CARFREQ, 0x3b); + stv0900_write_reg(intp, CORRELABS, 0x79); + } else { + stv0900_write_reg(intp, CARFREQ, 0xef); + stv0900_write_reg(intp, CORRELABS, 0x68); + } + + stv0900_write_reg(intp, DMDCFGMD, 0xc9); + zigzag = FALSE; + break; + } + + trial_cntr = 0; + do { + lock = stv0900_search_carr_sw_loop(intp, + fqc_inc, + sft_stp_tout, + zigzag, + max_steps, + demod); + no_signal = stv0900_check_signal_presence(intp, demod); + trial_cntr++; + if ((lock == TRUE) + || (no_signal == TRUE) + || (trial_cntr == 2)) { + + if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, CARFREQ, 0x49); + stv0900_write_reg(intp, CORRELABS, 0x9e); + } else { + stv0900_write_reg(intp, CARFREQ, 0xed); + stv0900_write_reg(intp, CORRELABS, 0x88); + } + + if ((stv0900_get_bits(intp, HEADER_MODE) == + STV0900_DVBS2_FOUND) && + (lock == TRUE)) { + msleep(sft_stp_tout); + s2fw = stv0900_get_bits(intp, FLYWHEEL_CPT); + + if (s2fw < 0xd) { + msleep(sft_stp_tout); + s2fw = stv0900_get_bits(intp, + FLYWHEEL_CPT); + } + + if (s2fw < 0xd) { + lock = FALSE; + + if (trial_cntr < 2) { + if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, + CORRELABS, + 0x79); + else + stv0900_write_reg(intp, + CORRELABS, + 0x68); + + stv0900_write_reg(intp, + DMDCFGMD, + 0x89); + } + } + } + } + + } while ((lock == FALSE) + && (trial_cntr < 2) + && (no_signal == FALSE)); + + return lock; +} + +static u32 stv0900_get_symbol_rate(struct stv0900_internal *intp, + u32 mclk, + enum fe_stv0900_demod_num demod) +{ + s32 rem1, rem2, intval1, intval2, srate; + + srate = (stv0900_get_bits(intp, SYMB_FREQ3) << 24) + + (stv0900_get_bits(intp, SYMB_FREQ2) << 16) + + (stv0900_get_bits(intp, SYMB_FREQ1) << 8) + + (stv0900_get_bits(intp, SYMB_FREQ0)); + dprintk("lock: srate=%d r0=0x%x r1=0x%x r2=0x%x r3=0x%x \n", + srate, stv0900_get_bits(intp, SYMB_FREQ0), + stv0900_get_bits(intp, SYMB_FREQ1), + stv0900_get_bits(intp, SYMB_FREQ2), + stv0900_get_bits(intp, SYMB_FREQ3)); + + intval1 = (mclk) >> 16; + intval2 = (srate) >> 16; + + rem1 = (mclk) % 0x10000; + rem2 = (srate) % 0x10000; + srate = (intval1 * intval2) + + ((intval1 * rem2) >> 16) + + ((intval2 * rem1) >> 16); + + return srate; +} + +static void stv0900_set_symbol_rate(struct stv0900_internal *intp, + u32 mclk, u32 srate, + enum fe_stv0900_demod_num demod) +{ + u32 symb; + + dprintk("%s: Mclk %d, SR %d, Dmd %d\n", __func__, mclk, + srate, demod); + + if (srate > 60000000) { + symb = srate << 4; + symb /= (mclk >> 12); + } else if (srate > 6000000) { + symb = srate << 6; + symb /= (mclk >> 10); + } else { + symb = srate << 9; + symb /= (mclk >> 7); + } + + stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0x7f); + stv0900_write_reg(intp, SFRINIT1 + 1, (symb & 0xff)); +} + +static void stv0900_set_max_symbol_rate(struct stv0900_internal *intp, + u32 mclk, u32 srate, + enum fe_stv0900_demod_num demod) +{ + u32 symb; + + srate = 105 * (srate / 100); + + if (srate > 60000000) { + symb = srate << 4; + symb /= (mclk >> 12); + } else if (srate > 6000000) { + symb = srate << 6; + symb /= (mclk >> 10); + } else { + symb = srate << 9; + symb /= (mclk >> 7); + } + + if (symb < 0x7fff) { + stv0900_write_reg(intp, SFRUP1, (symb >> 8) & 0x7f); + stv0900_write_reg(intp, SFRUP1 + 1, (symb & 0xff)); + } else { + stv0900_write_reg(intp, SFRUP1, 0x7f); + stv0900_write_reg(intp, SFRUP1 + 1, 0xff); + } +} + +static void stv0900_set_min_symbol_rate(struct stv0900_internal *intp, + u32 mclk, u32 srate, + enum fe_stv0900_demod_num demod) +{ + u32 symb; + + srate = 95 * (srate / 100); + if (srate > 60000000) { + symb = srate << 4; + symb /= (mclk >> 12); + + } else if (srate > 6000000) { + symb = srate << 6; + symb /= (mclk >> 10); + + } else { + symb = srate << 9; + symb /= (mclk >> 7); + } + + stv0900_write_reg(intp, SFRLOW1, (symb >> 8) & 0xff); + stv0900_write_reg(intp, SFRLOW1 + 1, (symb & 0xff)); +} + +static s32 stv0900_get_timing_offst(struct stv0900_internal *intp, + u32 srate, + enum fe_stv0900_demod_num demod) +{ + s32 timingoffset; + + + timingoffset = (stv0900_read_reg(intp, TMGREG2) << 16) + + (stv0900_read_reg(intp, TMGREG2 + 1) << 8) + + (stv0900_read_reg(intp, TMGREG2 + 2)); + + timingoffset = ge2comp(timingoffset, 24); + + + if (timingoffset == 0) + timingoffset = 1; + + timingoffset = ((s32)srate * 10) / ((s32)0x1000000 / timingoffset); + timingoffset /= 320; + + return timingoffset; +} + +static void stv0900_set_dvbs2_rolloff(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + s32 rolloff; + + if (intp->chip_id == 0x10) { + stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1); + rolloff = stv0900_read_reg(intp, MATSTR1) & 0x03; + stv0900_write_bits(intp, ROLLOFF_CONTROL, rolloff); + } else if (intp->chip_id <= 0x20) + stv0900_write_bits(intp, MANUALSX_ROLLOFF, 0); + else /* cut 3.0 */ + stv0900_write_bits(intp, MANUALS2_ROLLOFF, 0); +} + +static u32 stv0900_carrier_width(u32 srate, enum fe_stv0900_rolloff ro) +{ + u32 rolloff; + + switch (ro) { + case STV0900_20: + rolloff = 20; + break; + case STV0900_25: + rolloff = 25; + break; + case STV0900_35: + default: + rolloff = 35; + break; + } + + return srate + (srate * rolloff) / 100; +} + +static int stv0900_check_timing_lock(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + int timingLock = FALSE; + s32 i, + timingcpt = 0; + u8 car_freq, + tmg_th_high, + tmg_th_low; + + car_freq = stv0900_read_reg(intp, CARFREQ); + tmg_th_high = stv0900_read_reg(intp, TMGTHRISE); + tmg_th_low = stv0900_read_reg(intp, TMGTHFALL); + stv0900_write_reg(intp, TMGTHRISE, 0x20); + stv0900_write_reg(intp, TMGTHFALL, 0x0); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + stv0900_write_reg(intp, RTC, 0x80); + stv0900_write_reg(intp, RTCS2, 0x40); + stv0900_write_reg(intp, CARFREQ, 0x0); + stv0900_write_reg(intp, CFRINIT1, 0x0); + stv0900_write_reg(intp, CFRINIT0, 0x0); + stv0900_write_reg(intp, AGC2REF, 0x65); + stv0900_write_reg(intp, DMDISTATE, 0x18); + msleep(7); + + for (i = 0; i < 10; i++) { + if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2) + timingcpt++; + + msleep(1); + } + + if (timingcpt >= 3) + timingLock = TRUE; + + stv0900_write_reg(intp, AGC2REF, 0x38); + stv0900_write_reg(intp, RTC, 0x88); + stv0900_write_reg(intp, RTCS2, 0x68); + stv0900_write_reg(intp, CARFREQ, car_freq); + stv0900_write_reg(intp, TMGTHRISE, tmg_th_high); + stv0900_write_reg(intp, TMGTHFALL, tmg_th_low); + + return timingLock; +} + +static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe, + s32 demod_timeout) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + int lock = FALSE, + d = demod; + s32 srate, + search_range, + locktimeout, + currier_step, + nb_steps, + current_step, + direction, + tuner_freq, + timeout, + freq; + + srate = intp->symbol_rate[d]; + search_range = intp->srch_range[d]; + + if (srate >= 10000000) + locktimeout = demod_timeout / 3; + else + locktimeout = demod_timeout / 2; + + lock = stv0900_get_demod_lock(intp, d, locktimeout); + + if (lock != FALSE) + return lock; + + if (srate >= 10000000) { + if (stv0900_check_timing_lock(intp, d) == TRUE) { + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, DMDISTATE, 0x15); + lock = stv0900_get_demod_lock(intp, d, demod_timeout); + } else + lock = FALSE; + + return lock; + } + + if (intp->chip_id <= 0x20) { + if (srate <= 1000000) + currier_step = 500; + else if (srate <= 4000000) + currier_step = 1000; + else if (srate <= 7000000) + currier_step = 2000; + else if (srate <= 10000000) + currier_step = 3000; + else + currier_step = 5000; + + if (srate >= 2000000) { + timeout = (demod_timeout / 3); + if (timeout > 1000) + timeout = 1000; + } else + timeout = (demod_timeout / 2); + } else { + /*cut 3.0 */ + currier_step = srate / 4000; + timeout = (demod_timeout * 3) / 4; + } + + nb_steps = ((search_range / 1000) / currier_step); + + if ((nb_steps % 2) != 0) + nb_steps += 1; + + if (nb_steps <= 0) + nb_steps = 2; + else if (nb_steps > 12) + nb_steps = 12; + + current_step = 1; + direction = 1; + + if (intp->chip_id <= 0x20) { + tuner_freq = intp->freq[d]; + intp->bw[d] = stv0900_carrier_width(intp->symbol_rate[d], + intp->rolloff) + intp->symbol_rate[d]; + } else + tuner_freq = 0; + + while ((current_step <= nb_steps) && (lock == FALSE)) { + if (direction > 0) + tuner_freq += (current_step * currier_step); + else + tuner_freq -= (current_step * currier_step); + + if (intp->chip_id <= 0x20) { + if (intp->tuner_type[d] == 3) + stv0900_set_tuner_auto(intp, tuner_freq, + intp->bw[d], demod); + else + stv0900_set_tuner(fe, tuner_freq, intp->bw[d]); + + stv0900_write_reg(intp, DMDISTATE, 0x1c); + stv0900_write_reg(intp, CFRINIT1, 0); + stv0900_write_reg(intp, CFRINIT0, 0); + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, DMDISTATE, 0x15); + } else { + stv0900_write_reg(intp, DMDISTATE, 0x1c); + freq = (tuner_freq * 65536) / (intp->mclk / 1000); + stv0900_write_bits(intp, CFR_INIT1, MSB(freq)); + stv0900_write_bits(intp, CFR_INIT0, LSB(freq)); + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, DMDISTATE, 0x05); + } + + lock = stv0900_get_demod_lock(intp, d, timeout); + direction *= -1; + current_step++; + } + + return lock; +} + +static void stv0900_get_lock_timeout(s32 *demod_timeout, s32 *fec_timeout, + s32 srate, + enum fe_stv0900_search_algo algo) +{ + switch (algo) { + case STV0900_BLIND_SEARCH: + if (srate <= 1500000) { + (*demod_timeout) = 1500; + (*fec_timeout) = 400; + } else if (srate <= 5000000) { + (*demod_timeout) = 1000; + (*fec_timeout) = 300; + } else { + (*demod_timeout) = 700; + (*fec_timeout) = 100; + } + + break; + case STV0900_COLD_START: + case STV0900_WARM_START: + default: + if (srate <= 1000000) { + (*demod_timeout) = 3000; + (*fec_timeout) = 1700; + } else if (srate <= 2000000) { + (*demod_timeout) = 2500; + (*fec_timeout) = 1100; + } else if (srate <= 5000000) { + (*demod_timeout) = 1000; + (*fec_timeout) = 550; + } else if (srate <= 10000000) { + (*demod_timeout) = 700; + (*fec_timeout) = 250; + } else if (srate <= 20000000) { + (*demod_timeout) = 400; + (*fec_timeout) = 130; + } else { + (*demod_timeout) = 300; + (*fec_timeout) = 100; + } + + break; + + } + + if (algo == STV0900_WARM_START) + (*demod_timeout) /= 2; +} + +static void stv0900_set_viterbi_tracq(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + + s32 vth_reg = VTH12; + + dprintk("%s\n", __func__); + + stv0900_write_reg(intp, vth_reg++, 0xd0); + stv0900_write_reg(intp, vth_reg++, 0x7d); + stv0900_write_reg(intp, vth_reg++, 0x53); + stv0900_write_reg(intp, vth_reg++, 0x2f); + stv0900_write_reg(intp, vth_reg++, 0x24); + stv0900_write_reg(intp, vth_reg++, 0x1f); +} + +static void stv0900_set_viterbi_standard(struct stv0900_internal *intp, + enum fe_stv0900_search_standard standard, + enum fe_stv0900_fec fec, + enum fe_stv0900_demod_num demod) +{ + dprintk("%s: ViterbiStandard = ", __func__); + + switch (standard) { + case STV0900_AUTO_SEARCH: + dprintk("Auto\n"); + stv0900_write_reg(intp, FECM, 0x10); + stv0900_write_reg(intp, PRVIT, 0x3f); + break; + case STV0900_SEARCH_DVBS1: + dprintk("DVBS1\n"); + stv0900_write_reg(intp, FECM, 0x00); + switch (fec) { + case STV0900_FEC_UNKNOWN: + default: + stv0900_write_reg(intp, PRVIT, 0x2f); + break; + case STV0900_FEC_1_2: + stv0900_write_reg(intp, PRVIT, 0x01); + break; + case STV0900_FEC_2_3: + stv0900_write_reg(intp, PRVIT, 0x02); + break; + case STV0900_FEC_3_4: + stv0900_write_reg(intp, PRVIT, 0x04); + break; + case STV0900_FEC_5_6: + stv0900_write_reg(intp, PRVIT, 0x08); + break; + case STV0900_FEC_7_8: + stv0900_write_reg(intp, PRVIT, 0x20); + break; + } + + break; + case STV0900_SEARCH_DSS: + dprintk("DSS\n"); + stv0900_write_reg(intp, FECM, 0x80); + switch (fec) { + case STV0900_FEC_UNKNOWN: + default: + stv0900_write_reg(intp, PRVIT, 0x13); + break; + case STV0900_FEC_1_2: + stv0900_write_reg(intp, PRVIT, 0x01); + break; + case STV0900_FEC_2_3: + stv0900_write_reg(intp, PRVIT, 0x02); + break; + case STV0900_FEC_6_7: + stv0900_write_reg(intp, PRVIT, 0x10); + break; + } + break; + default: + break; + } +} + +static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + enum fe_stv0900_fec prate; + s32 rate_fld = stv0900_get_bits(intp, VIT_CURPUN); + + switch (rate_fld) { + case 13: + prate = STV0900_FEC_1_2; + break; + case 18: + prate = STV0900_FEC_2_3; + break; + case 21: + prate = STV0900_FEC_3_4; + break; + case 24: + prate = STV0900_FEC_5_6; + break; + case 25: + prate = STV0900_FEC_6_7; + break; + case 26: + prate = STV0900_FEC_7_8; + break; + default: + prate = STV0900_FEC_UNKNOWN; + break; + } + + return prate; +} + +static void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod, + u32 srate) +{ + if (intp->chip_id >= 0x30) { + if (srate >= 15000000) { + stv0900_write_reg(intp, ACLC, 0x2b); + stv0900_write_reg(intp, BCLC, 0x1a); + } else if ((srate >= 7000000) && (15000000 > srate)) { + stv0900_write_reg(intp, ACLC, 0x0c); + stv0900_write_reg(intp, BCLC, 0x1b); + } else if (srate < 7000000) { + stv0900_write_reg(intp, ACLC, 0x2c); + stv0900_write_reg(intp, BCLC, 0x1c); + } + + } else { /*cut 2.0 and 1.x*/ + stv0900_write_reg(intp, ACLC, 0x1a); + stv0900_write_reg(intp, BCLC, 0x09); + } + +} + +static void stv0900_track_optimization(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + + s32 srate, + pilots, + aclc, + freq1, + freq0, + i = 0, + timed, + timef, + blind_tun_sw = 0, + modulation; + + enum fe_stv0900_rolloff rolloff; + enum fe_stv0900_modcode foundModcod; + + dprintk("%s\n", __func__); + + srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + srate += stv0900_get_timing_offst(intp, srate, demod); + + switch (intp->result[demod].standard) { + case STV0900_DVBS1_STANDARD: + case STV0900_DSS_STANDARD: + dprintk("%s: found DVB-S or DSS\n", __func__); + if (intp->srch_standard[demod] == STV0900_AUTO_SEARCH) { + stv0900_write_bits(intp, DVBS1_ENABLE, 1); + stv0900_write_bits(intp, DVBS2_ENABLE, 0); + } + + stv0900_write_bits(intp, ROLLOFF_CONTROL, intp->rolloff); + stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1); + + if (intp->chip_id < 0x30) { + stv0900_write_reg(intp, ERRCTRL1, 0x75); + break; + } + + if (stv0900_get_vit_fec(intp, demod) == STV0900_FEC_1_2) { + stv0900_write_reg(intp, GAUSSR0, 0x98); + stv0900_write_reg(intp, CCIR0, 0x18); + } else { + stv0900_write_reg(intp, GAUSSR0, 0x18); + stv0900_write_reg(intp, CCIR0, 0x18); + } + + stv0900_write_reg(intp, ERRCTRL1, 0x75); + break; + case STV0900_DVBS2_STANDARD: + dprintk("%s: found DVB-S2\n", __func__); + stv0900_write_bits(intp, DVBS1_ENABLE, 0); + stv0900_write_bits(intp, DVBS2_ENABLE, 1); + stv0900_write_reg(intp, ACLC, 0); + stv0900_write_reg(intp, BCLC, 0); + if (intp->result[demod].frame_len == STV0900_LONG_FRAME) { + foundModcod = stv0900_get_bits(intp, DEMOD_MODCOD); + pilots = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01; + aclc = stv0900_get_optim_carr_loop(srate, + foundModcod, + pilots, + intp->chip_id); + if (foundModcod <= STV0900_QPSK_910) + stv0900_write_reg(intp, ACLC2S2Q, aclc); + else if (foundModcod <= STV0900_8PSK_910) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S28, aclc); + } + + if ((intp->demod_mode == STV0900_SINGLE) && + (foundModcod > STV0900_8PSK_910)) { + if (foundModcod <= STV0900_16APSK_910) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S216A, + aclc); + } else if (foundModcod <= STV0900_32APSK_910) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S232A, + aclc); + } + } + + } else { + modulation = intp->result[demod].modulation; + aclc = stv0900_get_optim_short_carr_loop(srate, + modulation, intp->chip_id); + if (modulation == STV0900_QPSK) + stv0900_write_reg(intp, ACLC2S2Q, aclc); + else if (modulation == STV0900_8PSK) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S28, aclc); + } else if (modulation == STV0900_16APSK) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S216A, aclc); + } else if (modulation == STV0900_32APSK) { + stv0900_write_reg(intp, ACLC2S2Q, 0x2a); + stv0900_write_reg(intp, ACLC2S232A, aclc); + } + + } + + if (intp->chip_id <= 0x11) { + if (intp->demod_mode != STV0900_SINGLE) + stv0900_activate_s2_modcod(intp, demod); + + } + + stv0900_write_reg(intp, ERRCTRL1, 0x67); + break; + case STV0900_UNKNOWN_STANDARD: + default: + dprintk("%s: found unknown standard\n", __func__); + stv0900_write_bits(intp, DVBS1_ENABLE, 1); + stv0900_write_bits(intp, DVBS2_ENABLE, 1); + break; + } + + freq1 = stv0900_read_reg(intp, CFR2); + freq0 = stv0900_read_reg(intp, CFR1); + rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS); + if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) { + stv0900_write_reg(intp, SFRSTEP, 0x00); + stv0900_write_bits(intp, SCAN_ENABLE, 0); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + stv0900_write_reg(intp, TMGCFG2, 0xc1); + stv0900_set_symbol_rate(intp, intp->mclk, srate, demod); + blind_tun_sw = 1; + if (intp->result[demod].standard != STV0900_DVBS2_STANDARD) + stv0900_set_dvbs1_track_car_loop(intp, demod, srate); + + } + + if (intp->chip_id >= 0x20) { + if ((intp->srch_standard[demod] == STV0900_SEARCH_DVBS1) || + (intp->srch_standard[demod] == + STV0900_SEARCH_DSS) || + (intp->srch_standard[demod] == + STV0900_AUTO_SEARCH)) { + stv0900_write_reg(intp, VAVSRVIT, 0x0a); + stv0900_write_reg(intp, VITSCALE, 0x0); + } + } + + if (intp->chip_id < 0x20) + stv0900_write_reg(intp, CARHDR, 0x08); + + if (intp->chip_id == 0x10) + stv0900_write_reg(intp, CORRELEXP, 0x0a); + + stv0900_write_reg(intp, AGC2REF, 0x38); + + if ((intp->chip_id >= 0x20) || + (blind_tun_sw == 1) || + (intp->symbol_rate[demod] < 10000000)) { + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + intp->bw[demod] = stv0900_carrier_width(srate, + intp->rolloff) + 10000000; + + if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) { + if (intp->srch_algo[demod] != STV0900_WARM_START) { + if (intp->tuner_type[demod] == 3) + stv0900_set_tuner_auto(intp, + intp->freq[demod], + intp->bw[demod], + demod); + else + stv0900_set_bandwidth(fe, + intp->bw[demod]); + } + } + + if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) || + (intp->symbol_rate[demod] < 10000000)) + msleep(50); + else + msleep(5); + + stv0900_get_lock_timeout(&timed, &timef, srate, + STV0900_WARM_START); + + if (stv0900_get_demod_lock(intp, demod, timed / 2) == FALSE) { + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + stv0900_write_reg(intp, DMDISTATE, 0x18); + i = 0; + while ((stv0900_get_demod_lock(intp, + demod, + timed / 2) == FALSE) && + (i <= 2)) { + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + stv0900_write_reg(intp, DMDISTATE, 0x18); + i++; + } + } + + } + + if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, CARFREQ, 0x49); + + if ((intp->result[demod].standard == STV0900_DVBS1_STANDARD) || + (intp->result[demod].standard == STV0900_DSS_STANDARD)) + stv0900_set_viterbi_tracq(intp, demod); + +} + +static int stv0900_get_fec_lock(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod, s32 time_out) +{ + s32 timer = 0, lock = 0; + + enum fe_stv0900_search_state dmd_state; + + dprintk("%s\n", __func__); + + dmd_state = stv0900_get_bits(intp, HEADER_MODE); + + while ((timer < time_out) && (lock == 0)) { + switch (dmd_state) { + case STV0900_SEARCH: + case STV0900_PLH_DETECTED: + default: + lock = 0; + break; + case STV0900_DVBS2_FOUND: + lock = stv0900_get_bits(intp, PKTDELIN_LOCK); + break; + case STV0900_DVBS_FOUND: + lock = stv0900_get_bits(intp, LOCKEDVIT); + break; + } + + if (lock == 0) { + msleep(10); + timer += 10; + } + } + + if (lock) + dprintk("%s: DEMOD FEC LOCK OK\n", __func__); + else + dprintk("%s: DEMOD FEC LOCK FAIL\n", __func__); + + return lock; +} + +static int stv0900_wait_for_lock(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod, + s32 dmd_timeout, s32 fec_timeout) +{ + + s32 timer = 0, lock = 0; + + dprintk("%s\n", __func__); + + lock = stv0900_get_demod_lock(intp, demod, dmd_timeout); + + if (lock) + lock = lock && stv0900_get_fec_lock(intp, demod, fec_timeout); + + if (lock) { + lock = 0; + + dprintk("%s: Timer = %d, time_out = %d\n", + __func__, timer, fec_timeout); + + while ((timer < fec_timeout) && (lock == 0)) { + lock = stv0900_get_bits(intp, TSFIFO_LINEOK); + msleep(1); + timer++; + } + } + + if (lock) + dprintk("%s: DEMOD LOCK OK\n", __func__); + else + dprintk("%s: DEMOD LOCK FAIL\n", __func__); + + if (lock) + return TRUE; + else + return FALSE; +} + +enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe, + enum fe_stv0900_demod_num demod) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_tracking_standard fnd_standard; + + int hdr_mode = stv0900_get_bits(intp, HEADER_MODE); + + switch (hdr_mode) { + case 2: + fnd_standard = STV0900_DVBS2_STANDARD; + break; + case 3: + if (stv0900_get_bits(intp, DSS_DVB) == 1) + fnd_standard = STV0900_DSS_STANDARD; + else + fnd_standard = STV0900_DVBS1_STANDARD; + + break; + default: + fnd_standard = STV0900_UNKNOWN_STANDARD; + } + + dprintk("%s: standard %d\n", __func__, fnd_standard); + + return fnd_standard; +} + +static s32 stv0900_get_carr_freq(struct stv0900_internal *intp, u32 mclk, + enum fe_stv0900_demod_num demod) +{ + s32 derot, + rem1, + rem2, + intval1, + intval2; + + derot = (stv0900_get_bits(intp, CAR_FREQ2) << 16) + + (stv0900_get_bits(intp, CAR_FREQ1) << 8) + + (stv0900_get_bits(intp, CAR_FREQ0)); + + derot = ge2comp(derot, 24); + intval1 = mclk >> 12; + intval2 = derot >> 12; + rem1 = mclk % 0x1000; + rem2 = derot % 0x1000; + derot = (intval1 * intval2) + + ((intval1 * rem2) >> 12) + + ((intval2 * rem1) >> 12); + + return derot; +} + +static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + u32 freq = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + + if (tuner_ops->get_frequency) { + if ((tuner_ops->get_frequency(fe, &freq)) < 0) + dprintk("%s: Invalid parameter\n", __func__); + else + dprintk("%s: Frequency=%d\n", __func__, freq); + + } + + return freq; +} + +static enum +fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + enum fe_stv0900_signal_type range = STV0900_OUTOFRANGE; + struct stv0900_signal_info *result = &intp->result[demod]; + s32 offsetFreq, + srate_offset; + int i = 0, + d = demod; + + u8 timing; + + msleep(5); + if (intp->srch_algo[d] == STV0900_BLIND_SEARCH) { + timing = stv0900_read_reg(intp, TMGREG2); + i = 0; + stv0900_write_reg(intp, SFRSTEP, 0x5c); + + while ((i <= 50) && (timing != 0) && (timing != 0xff)) { + timing = stv0900_read_reg(intp, TMGREG2); + msleep(5); + i += 5; + } + } + + result->standard = stv0900_get_standard(fe, d); + if (intp->tuner_type[demod] == 3) + result->frequency = stv0900_get_freq_auto(intp, d); + else + result->frequency = stv0900_get_tuner_freq(fe); + + offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000; + result->frequency += offsetFreq; + result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d); + srate_offset = stv0900_get_timing_offst(intp, result->symbol_rate, d); + result->symbol_rate += srate_offset; + result->fec = stv0900_get_vit_fec(intp, d); + result->modcode = stv0900_get_bits(intp, DEMOD_MODCOD); + result->pilot = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01; + result->frame_len = ((u32)stv0900_get_bits(intp, DEMOD_TYPE)) >> 1; + result->rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS); + + dprintk("%s: modcode=0x%x \n", __func__, result->modcode); + + switch (result->standard) { + case STV0900_DVBS2_STANDARD: + result->spectrum = stv0900_get_bits(intp, SPECINV_DEMOD); + if (result->modcode <= STV0900_QPSK_910) + result->modulation = STV0900_QPSK; + else if (result->modcode <= STV0900_8PSK_910) + result->modulation = STV0900_8PSK; + else if (result->modcode <= STV0900_16APSK_910) + result->modulation = STV0900_16APSK; + else if (result->modcode <= STV0900_32APSK_910) + result->modulation = STV0900_32APSK; + else + result->modulation = STV0900_UNKNOWN; + break; + case STV0900_DVBS1_STANDARD: + case STV0900_DSS_STANDARD: + result->spectrum = stv0900_get_bits(intp, IQINV); + result->modulation = STV0900_QPSK; + break; + default: + break; + } + + if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) || + (intp->symbol_rate[d] < 10000000)) { + offsetFreq = result->frequency - intp->freq[d]; + if (intp->tuner_type[demod] == 3) + intp->freq[d] = stv0900_get_freq_auto(intp, d); + else + intp->freq[d] = stv0900_get_tuner_freq(fe); + + if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) + range = STV0900_RANGEOK; + else if (ABS(offsetFreq) <= + (stv0900_carrier_width(result->symbol_rate, + result->rolloff) / 2000)) + range = STV0900_RANGEOK; + + } else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) + range = STV0900_RANGEOK; + + dprintk("%s: range %d\n", __func__, range); + + return range; +} + +static enum +fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + enum fe_stv0900_signal_type signal_type = STV0900_NODATA; + + s32 srate, + demod_timeout, + fec_timeout, + freq1, + freq0; + + intp->result[demod].locked = FALSE; + + if (stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) { + srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + srate += stv0900_get_timing_offst(intp, srate, demod); + if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) + stv0900_set_symbol_rate(intp, intp->mclk, srate, demod); + + stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, + srate, STV0900_WARM_START); + freq1 = stv0900_read_reg(intp, CFR2); + freq0 = stv0900_read_reg(intp, CFR1); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + stv0900_write_bits(intp, SPECINV_CONTROL, + STV0900_IQ_FORCE_SWAPPED); + stv0900_write_reg(intp, DMDISTATE, 0x1c); + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + stv0900_write_reg(intp, DMDISTATE, 0x18); + if (stv0900_wait_for_lock(intp, demod, + demod_timeout, fec_timeout) == TRUE) { + intp->result[demod].locked = TRUE; + signal_type = stv0900_get_signal_params(fe); + stv0900_track_optimization(fe); + } else { + stv0900_write_bits(intp, SPECINV_CONTROL, + STV0900_IQ_FORCE_NORMAL); + stv0900_write_reg(intp, DMDISTATE, 0x1c); + stv0900_write_reg(intp, CFRINIT1, freq1); + stv0900_write_reg(intp, CFRINIT0, freq0); + stv0900_write_reg(intp, DMDISTATE, 0x18); + if (stv0900_wait_for_lock(intp, demod, + demod_timeout, fec_timeout) == TRUE) { + intp->result[demod].locked = TRUE; + signal_type = stv0900_get_signal_params(fe); + stv0900_track_optimization(fe); + } + + } + + } else + intp->result[demod].locked = FALSE; + + return signal_type; +} + +static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + u32 minagc2level = 0xffff, + agc2level, + init_freq, freq_step; + + s32 i, j, nb_steps, direction; + + dprintk("%s\n", __func__); + + stv0900_write_reg(intp, AGC2REF, 0x38); + stv0900_write_bits(intp, SCAN_ENABLE, 0); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + + stv0900_write_bits(intp, AUTO_GUP, 1); + stv0900_write_bits(intp, AUTO_GLOW, 1); + + stv0900_write_reg(intp, DMDT0M, 0x0); + + stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod); + nb_steps = -1 + (intp->srch_range[demod] / 1000000); + nb_steps /= 2; + nb_steps = (2 * nb_steps) + 1; + + if (nb_steps < 0) + nb_steps = 1; + + direction = 1; + + freq_step = (1000000 << 8) / (intp->mclk >> 8); + + init_freq = 0; + + for (i = 0; i < nb_steps; i++) { + if (direction > 0) + init_freq = init_freq + (freq_step * i); + else + init_freq = init_freq - (freq_step * i); + + direction *= -1; + stv0900_write_reg(intp, DMDISTATE, 0x5C); + stv0900_write_reg(intp, CFRINIT1, (init_freq >> 8) & 0xff); + stv0900_write_reg(intp, CFRINIT0, init_freq & 0xff); + stv0900_write_reg(intp, DMDISTATE, 0x58); + msleep(10); + agc2level = 0; + + for (j = 0; j < 10; j++) + agc2level += (stv0900_read_reg(intp, AGC2I1) << 8) + | stv0900_read_reg(intp, AGC2I0); + + agc2level /= 10; + + if (agc2level < minagc2level) + minagc2level = agc2level; + + } + + return (u16)minagc2level; +} + +static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + int timing_lck = FALSE; + s32 i, timingcpt = 0, + direction = 1, + nb_steps, + current_step = 0, + tuner_freq; + u32 agc2_th, + coarse_srate = 0, + agc2_integr = 0, + currier_step = 1200; + + if (intp->chip_id >= 0x30) + agc2_th = 0x2e00; + else + agc2_th = 0x1f00; + + stv0900_write_bits(intp, DEMOD_MODE, 0x1f); + stv0900_write_reg(intp, TMGCFG, 0x12); + stv0900_write_reg(intp, TMGTHRISE, 0xf0); + stv0900_write_reg(intp, TMGTHFALL, 0xe0); + stv0900_write_bits(intp, SCAN_ENABLE, 1); + stv0900_write_bits(intp, CFR_AUTOSCAN, 1); + stv0900_write_reg(intp, SFRUP1, 0x83); + stv0900_write_reg(intp, SFRUP0, 0xc0); + stv0900_write_reg(intp, SFRLOW1, 0x82); + stv0900_write_reg(intp, SFRLOW0, 0xa0); + stv0900_write_reg(intp, DMDT0M, 0x0); + stv0900_write_reg(intp, AGC2REF, 0x50); + + if (intp->chip_id >= 0x30) { + stv0900_write_reg(intp, CARFREQ, 0x99); + stv0900_write_reg(intp, SFRSTEP, 0x98); + } else if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, CARFREQ, 0x6a); + stv0900_write_reg(intp, SFRSTEP, 0x95); + } else { + stv0900_write_reg(intp, CARFREQ, 0xed); + stv0900_write_reg(intp, SFRSTEP, 0x73); + } + + if (intp->symbol_rate[demod] <= 2000000) + currier_step = 1000; + else if (intp->symbol_rate[demod] <= 5000000) + currier_step = 2000; + else if (intp->symbol_rate[demod] <= 12000000) + currier_step = 3000; + else + currier_step = 5000; + + nb_steps = -1 + ((intp->srch_range[demod] / 1000) / currier_step); + nb_steps /= 2; + nb_steps = (2 * nb_steps) + 1; + + if (nb_steps < 0) + nb_steps = 1; + else if (nb_steps > 10) { + nb_steps = 11; + currier_step = (intp->srch_range[demod] / 1000) / 10; + } + + current_step = 0; + direction = 1; + + tuner_freq = intp->freq[demod]; + + while ((timing_lck == FALSE) && (current_step < nb_steps)) { + stv0900_write_reg(intp, DMDISTATE, 0x5f); + stv0900_write_bits(intp, DEMOD_MODE, 0); + + msleep(50); + + for (i = 0; i < 10; i++) { + if (stv0900_get_bits(intp, TMGLOCK_QUALITY) >= 2) + timingcpt++; + + agc2_integr += (stv0900_read_reg(intp, AGC2I1) << 8) | + stv0900_read_reg(intp, AGC2I0); + } + + agc2_integr /= 10; + coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + current_step++; + direction *= -1; + + dprintk("lock: I2C_DEMOD_MODE_FIELD =0. Search started." + " tuner freq=%d agc2=0x%x srate_coarse=%d tmg_cpt=%d\n", + tuner_freq, agc2_integr, coarse_srate, timingcpt); + + if ((timingcpt >= 5) && + (agc2_integr < agc2_th) && + (coarse_srate < 55000000) && + (coarse_srate > 850000)) + timing_lck = TRUE; + else if (current_step < nb_steps) { + if (direction > 0) + tuner_freq += (current_step * currier_step); + else + tuner_freq -= (current_step * currier_step); + + if (intp->tuner_type[demod] == 3) + stv0900_set_tuner_auto(intp, tuner_freq, + intp->bw[demod], demod); + else + stv0900_set_tuner(fe, tuner_freq, + intp->bw[demod]); + } + } + + if (timing_lck == FALSE) + coarse_srate = 0; + else + coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + + return coarse_srate; +} + +static u32 stv0900_search_srate_fine(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + u32 coarse_srate, + coarse_freq, + symb, + symbmax, + symbmin, + symbcomp; + + coarse_srate = stv0900_get_symbol_rate(intp, intp->mclk, demod); + + if (coarse_srate > 3000000) { + symbmax = 13 * (coarse_srate / 10); + symbmax = (symbmax / 1000) * 65536; + symbmax /= (intp->mclk / 1000); + + symbmin = 10 * (coarse_srate / 13); + symbmin = (symbmin / 1000)*65536; + symbmin /= (intp->mclk / 1000); + + symb = (coarse_srate / 1000) * 65536; + symb /= (intp->mclk / 1000); + } else { + symbmax = 13 * (coarse_srate / 10); + symbmax = (symbmax / 100) * 65536; + symbmax /= (intp->mclk / 100); + + symbmin = 10 * (coarse_srate / 14); + symbmin = (symbmin / 100) * 65536; + symbmin /= (intp->mclk / 100); + + symb = (coarse_srate / 100) * 65536; + symb /= (intp->mclk / 100); + } + + symbcomp = 13 * (coarse_srate / 10); + coarse_freq = (stv0900_read_reg(intp, CFR2) << 8) + | stv0900_read_reg(intp, CFR1); + + if (symbcomp < intp->symbol_rate[demod]) + coarse_srate = 0; + else { + stv0900_write_reg(intp, DMDISTATE, 0x1f); + stv0900_write_reg(intp, TMGCFG2, 0xc1); + stv0900_write_reg(intp, TMGTHRISE, 0x20); + stv0900_write_reg(intp, TMGTHFALL, 0x00); + stv0900_write_reg(intp, TMGCFG, 0xd2); + stv0900_write_bits(intp, CFR_AUTOSCAN, 0); + stv0900_write_reg(intp, AGC2REF, 0x38); + + if (intp->chip_id >= 0x30) + stv0900_write_reg(intp, CARFREQ, 0x79); + else if (intp->chip_id >= 0x20) + stv0900_write_reg(intp, CARFREQ, 0x49); + else + stv0900_write_reg(intp, CARFREQ, 0xed); + + stv0900_write_reg(intp, SFRUP1, (symbmax >> 8) & 0x7f); + stv0900_write_reg(intp, SFRUP0, (symbmax & 0xff)); + + stv0900_write_reg(intp, SFRLOW1, (symbmin >> 8) & 0x7f); + stv0900_write_reg(intp, SFRLOW0, (symbmin & 0xff)); + + stv0900_write_reg(intp, SFRINIT1, (symb >> 8) & 0xff); + stv0900_write_reg(intp, SFRINIT0, (symb & 0xff)); + + stv0900_write_reg(intp, DMDT0M, 0x20); + stv0900_write_reg(intp, CFRINIT1, (coarse_freq >> 8) & 0xff); + stv0900_write_reg(intp, CFRINIT0, coarse_freq & 0xff); + stv0900_write_reg(intp, DMDISTATE, 0x15); + } + + return coarse_srate; +} + +static int stv0900_blind_search_algo(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + u8 k_ref_tmg, + k_ref_tmg_max, + k_ref_tmg_min; + u32 coarse_srate, + agc2_th; + int lock = FALSE, + coarse_fail = FALSE; + s32 demod_timeout = 500, + fec_timeout = 50, + fail_cpt, + i, + agc2_overflow; + u16 agc2_int; + u8 dstatus2; + + dprintk("%s\n", __func__); + + if (intp->chip_id < 0x20) { + k_ref_tmg_max = 233; + k_ref_tmg_min = 143; + } else { + k_ref_tmg_max = 110; + k_ref_tmg_min = 10; + } + + if (intp->chip_id <= 0x20) + agc2_th = STV0900_BLIND_SEARCH_AGC2_TH; + else + agc2_th = STV0900_BLIND_SEARCH_AGC2_TH_CUT30; + + agc2_int = stv0900_blind_check_agc2_min_level(intp, demod); + + dprintk("%s agc2_int=%d agc2_th=%d \n", __func__, agc2_int, agc2_th); + if (agc2_int > agc2_th) + return FALSE; + + if (intp->chip_id == 0x10) + stv0900_write_reg(intp, CORRELEXP, 0xaa); + + if (intp->chip_id < 0x20) + stv0900_write_reg(intp, CARHDR, 0x55); + else + stv0900_write_reg(intp, CARHDR, 0x20); + + if (intp->chip_id <= 0x20) + stv0900_write_reg(intp, CARCFG, 0xc4); + else + stv0900_write_reg(intp, CARCFG, 0x6); + + stv0900_write_reg(intp, RTCS2, 0x44); + + if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, EQUALCFG, 0x41); + stv0900_write_reg(intp, FFECFG, 0x41); + stv0900_write_reg(intp, VITSCALE, 0x82); + stv0900_write_reg(intp, VAVSRVIT, 0x0); + } + + k_ref_tmg = k_ref_tmg_max; + + do { + stv0900_write_reg(intp, KREFTMG, k_ref_tmg); + if (stv0900_search_srate_coarse(fe) != 0) { + coarse_srate = stv0900_search_srate_fine(fe); + + if (coarse_srate != 0) { + stv0900_get_lock_timeout(&demod_timeout, + &fec_timeout, + coarse_srate, + STV0900_BLIND_SEARCH); + lock = stv0900_get_demod_lock(intp, + demod, + demod_timeout); + } else + lock = FALSE; + } else { + fail_cpt = 0; + agc2_overflow = 0; + + for (i = 0; i < 10; i++) { + agc2_int = (stv0900_read_reg(intp, AGC2I1) << 8) + | stv0900_read_reg(intp, AGC2I0); + + if (agc2_int >= 0xff00) + agc2_overflow++; + + dstatus2 = stv0900_read_reg(intp, DSTATUS2); + + if (((dstatus2 & 0x1) == 0x1) && + ((dstatus2 >> 7) == 1)) + fail_cpt++; + } + + if ((fail_cpt > 7) || (agc2_overflow > 7)) + coarse_fail = TRUE; + + lock = FALSE; + } + k_ref_tmg -= 30; + } while ((k_ref_tmg >= k_ref_tmg_min) && + (lock == FALSE) && + (coarse_fail == FALSE)); + + return lock; +} + +static void stv0900_set_viterbi_acq(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + s32 vth_reg = VTH12; + + dprintk("%s\n", __func__); + + stv0900_write_reg(intp, vth_reg++, 0x96); + stv0900_write_reg(intp, vth_reg++, 0x64); + stv0900_write_reg(intp, vth_reg++, 0x36); + stv0900_write_reg(intp, vth_reg++, 0x23); + stv0900_write_reg(intp, vth_reg++, 0x1e); + stv0900_write_reg(intp, vth_reg++, 0x19); +} + +static void stv0900_set_search_standard(struct stv0900_internal *intp, + enum fe_stv0900_demod_num demod) +{ + + dprintk("%s\n", __func__); + + switch (intp->srch_standard[demod]) { + case STV0900_SEARCH_DVBS1: + dprintk("Search Standard = DVBS1\n"); + break; + case STV0900_SEARCH_DSS: + dprintk("Search Standard = DSS\n"); + case STV0900_SEARCH_DVBS2: + break; + dprintk("Search Standard = DVBS2\n"); + case STV0900_AUTO_SEARCH: + default: + dprintk("Search Standard = AUTO\n"); + break; + } + + switch (intp->srch_standard[demod]) { + case STV0900_SEARCH_DVBS1: + case STV0900_SEARCH_DSS: + stv0900_write_bits(intp, DVBS1_ENABLE, 1); + stv0900_write_bits(intp, DVBS2_ENABLE, 0); + stv0900_write_bits(intp, STOP_CLKVIT, 0); + stv0900_set_dvbs1_track_car_loop(intp, + demod, + intp->symbol_rate[demod]); + stv0900_write_reg(intp, CAR2CFG, 0x22); + + stv0900_set_viterbi_acq(intp, demod); + stv0900_set_viterbi_standard(intp, + intp->srch_standard[demod], + intp->fec[demod], demod); + + break; + case STV0900_SEARCH_DVBS2: + stv0900_write_bits(intp, DVBS1_ENABLE, 0); + stv0900_write_bits(intp, DVBS2_ENABLE, 1); + stv0900_write_bits(intp, STOP_CLKVIT, 1); + stv0900_write_reg(intp, ACLC, 0x1a); + stv0900_write_reg(intp, BCLC, 0x09); + if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/ + stv0900_write_reg(intp, CAR2CFG, 0x26); + else + stv0900_write_reg(intp, CAR2CFG, 0x66); + + if (intp->demod_mode != STV0900_SINGLE) { + if (intp->chip_id <= 0x11) + stv0900_stop_all_s2_modcod(intp, demod); + else + stv0900_activate_s2_modcod(intp, demod); + + } else + stv0900_activate_s2_modcod_single(intp, demod); + + stv0900_set_viterbi_tracq(intp, demod); + + break; + case STV0900_AUTO_SEARCH: + default: + stv0900_write_bits(intp, DVBS1_ENABLE, 1); + stv0900_write_bits(intp, DVBS2_ENABLE, 1); + stv0900_write_bits(intp, STOP_CLKVIT, 0); + stv0900_write_reg(intp, ACLC, 0x1a); + stv0900_write_reg(intp, BCLC, 0x09); + stv0900_set_dvbs1_track_car_loop(intp, + demod, + intp->symbol_rate[demod]); + if (intp->chip_id <= 0x20) /*cut 1.x and 2.0*/ + stv0900_write_reg(intp, CAR2CFG, 0x26); + else + stv0900_write_reg(intp, CAR2CFG, 0x66); + + if (intp->demod_mode != STV0900_SINGLE) { + if (intp->chip_id <= 0x11) + stv0900_stop_all_s2_modcod(intp, demod); + else + stv0900_activate_s2_modcod(intp, demod); + + } else + stv0900_activate_s2_modcod_single(intp, demod); + + stv0900_set_viterbi_tracq(intp, demod); + stv0900_set_viterbi_standard(intp, + intp->srch_standard[demod], + intp->fec[demod], demod); + + break; + } +} + +enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *intp = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + + s32 demod_timeout = 500, fec_timeout = 50; + s32 aq_power, agc1_power, i; + + int lock = FALSE, low_sr = FALSE; + + enum fe_stv0900_signal_type signal_type = STV0900_NOCARRIER; + enum fe_stv0900_search_algo algo; + int no_signal = FALSE; + + dprintk("%s\n", __func__); + + algo = intp->srch_algo[demod]; + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_reg(intp, DMDISTATE, 0x5c); + if (intp->chip_id >= 0x20) { + if (intp->symbol_rate[demod] > 5000000) + stv0900_write_reg(intp, CORRELABS, 0x9e); + else + stv0900_write_reg(intp, CORRELABS, 0x82); + } else + stv0900_write_reg(intp, CORRELABS, 0x88); + + stv0900_get_lock_timeout(&demod_timeout, &fec_timeout, + intp->symbol_rate[demod], + intp->srch_algo[demod]); + + if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) { + intp->bw[demod] = 2 * 36000000; + + stv0900_write_reg(intp, TMGCFG2, 0xc0); + stv0900_write_reg(intp, CORRELMANT, 0x70); + + stv0900_set_symbol_rate(intp, intp->mclk, 1000000, demod); + } else { + stv0900_write_reg(intp, DMDT0M, 0x20); + stv0900_write_reg(intp, TMGCFG, 0xd2); + + if (intp->symbol_rate[demod] < 2000000) + stv0900_write_reg(intp, CORRELMANT, 0x63); + else + stv0900_write_reg(intp, CORRELMANT, 0x70); + + stv0900_write_reg(intp, AGC2REF, 0x38); + + intp->bw[demod] = + stv0900_carrier_width(intp->symbol_rate[demod], + intp->rolloff); + if (intp->chip_id >= 0x20) { + stv0900_write_reg(intp, KREFTMG, 0x5a); + + if (intp->srch_algo[demod] == STV0900_COLD_START) { + intp->bw[demod] += 10000000; + intp->bw[demod] *= 15; + intp->bw[demod] /= 10; + } else if (intp->srch_algo[demod] == STV0900_WARM_START) + intp->bw[demod] += 10000000; + + } else { + stv0900_write_reg(intp, KREFTMG, 0xc1); + intp->bw[demod] += 10000000; + intp->bw[demod] *= 15; + intp->bw[demod] /= 10; + } + + stv0900_write_reg(intp, TMGCFG2, 0xc1); + + stv0900_set_symbol_rate(intp, intp->mclk, + intp->symbol_rate[demod], demod); + stv0900_set_max_symbol_rate(intp, intp->mclk, + intp->symbol_rate[demod], demod); + stv0900_set_min_symbol_rate(intp, intp->mclk, + intp->symbol_rate[demod], demod); + if (intp->symbol_rate[demod] >= 10000000) + low_sr = FALSE; + else + low_sr = TRUE; + + } + + if (intp->tuner_type[demod] == 3) + stv0900_set_tuner_auto(intp, intp->freq[demod], + intp->bw[demod], demod); + else + stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]); + + agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1), + stv0900_get_bits(intp, AGCIQ_VALUE0)); + + aq_power = 0; + + if (agc1_power == 0) { + for (i = 0; i < 5; i++) + aq_power += (stv0900_get_bits(intp, POWER_I) + + stv0900_get_bits(intp, POWER_Q)) / 2; + + aq_power /= 5; + } + + if ((agc1_power == 0) && (aq_power < IQPOWER_THRESHOLD)) { + intp->result[demod].locked = FALSE; + signal_type = STV0900_NOAGC1; + dprintk("%s: NO AGC1, POWERI, POWERQ\n", __func__); + } else { + stv0900_write_bits(intp, SPECINV_CONTROL, + intp->srch_iq_inv[demod]); + if (intp->chip_id <= 0x20) /*cut 2.0*/ + stv0900_write_bits(intp, MANUALSX_ROLLOFF, 1); + else /*cut 3.0*/ + stv0900_write_bits(intp, MANUALS2_ROLLOFF, 1); + + stv0900_set_search_standard(intp, demod); + + if (intp->srch_algo[demod] != STV0900_BLIND_SEARCH) + stv0900_start_search(intp, demod); + } + + if (signal_type == STV0900_NOAGC1) + return signal_type; + + if (intp->chip_id == 0x12) { + stv0900_write_bits(intp, RST_HWARE, 0); + msleep(3); + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_bits(intp, RST_HWARE, 0); + } + + if (algo == STV0900_BLIND_SEARCH) + lock = stv0900_blind_search_algo(fe); + else if (algo == STV0900_COLD_START) + lock = stv0900_get_demod_cold_lock(fe, demod_timeout); + else if (algo == STV0900_WARM_START) + lock = stv0900_get_demod_lock(intp, demod, demod_timeout); + + if ((lock == FALSE) && (algo == STV0900_COLD_START)) { + if (low_sr == FALSE) { + if (stv0900_check_timing_lock(intp, demod) == TRUE) + lock = stv0900_sw_algo(intp, demod); + } + } + + if (lock == TRUE) + signal_type = stv0900_get_signal_params(fe); + + if ((lock == TRUE) && (signal_type == STV0900_RANGEOK)) { + stv0900_track_optimization(fe); + if (intp->chip_id <= 0x11) { + if ((stv0900_get_standard(fe, 0) == + STV0900_DVBS1_STANDARD) && + (stv0900_get_standard(fe, 1) == + STV0900_DVBS1_STANDARD)) { + msleep(20); + stv0900_write_bits(intp, RST_HWARE, 0); + } else { + stv0900_write_bits(intp, RST_HWARE, 0); + msleep(3); + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_bits(intp, RST_HWARE, 0); + } + + } else if (intp->chip_id >= 0x20) { + stv0900_write_bits(intp, RST_HWARE, 0); + msleep(3); + stv0900_write_bits(intp, RST_HWARE, 1); + stv0900_write_bits(intp, RST_HWARE, 0); + } + + if (stv0900_wait_for_lock(intp, demod, + fec_timeout, fec_timeout) == TRUE) { + lock = TRUE; + intp->result[demod].locked = TRUE; + if (intp->result[demod].standard == + STV0900_DVBS2_STANDARD) { + stv0900_set_dvbs2_rolloff(intp, demod); + stv0900_write_bits(intp, RESET_UPKO_COUNT, 1); + stv0900_write_bits(intp, RESET_UPKO_COUNT, 0); + stv0900_write_reg(intp, ERRCTRL1, 0x67); + } else { + stv0900_write_reg(intp, ERRCTRL1, 0x75); + } + + stv0900_write_reg(intp, FBERCPT4, 0); + stv0900_write_reg(intp, ERRCTRL2, 0xc1); + } else { + lock = FALSE; + signal_type = STV0900_NODATA; + no_signal = stv0900_check_signal_presence(intp, demod); + + intp->result[demod].locked = FALSE; + } + } + + if ((signal_type != STV0900_NODATA) || (no_signal != FALSE)) + return signal_type; + + if (intp->chip_id > 0x11) { + intp->result[demod].locked = FALSE; + return signal_type; + } + + if ((stv0900_get_bits(intp, HEADER_MODE) == STV0900_DVBS_FOUND) && + (intp->srch_iq_inv[demod] <= STV0900_IQ_AUTO_NORMAL_FIRST)) + signal_type = stv0900_dvbs1_acq_workaround(fe); + + return signal_type; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,4831 @@ +/* + STV0900/0903 Multistandard Broadcast Frontend driver + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include "dvb_frontend.h" + +#include "stv6110x.h" /* for demodulator internal modes */ + +#include "stv090x_reg.h" +#include "stv090x.h" +#include "stv090x_priv.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); + +/* internal params node */ +struct stv090x_dev { + /* pointer for internal params, one for each pair of demods */ + struct stv090x_internal *internal; + struct stv090x_dev *next_dev; +}; + +/* first internal params */ +static struct stv090x_dev *stv090x_first_dev; + +/* find chip by i2c adapter and i2c address */ +static struct stv090x_dev *find_dev(struct i2c_adapter *i2c_adap, + u8 i2c_addr) +{ + struct stv090x_dev *temp_dev = stv090x_first_dev; + + /* + Search of the last stv0900 chip or + find it by i2c adapter and i2c address */ + while ((temp_dev != NULL) && + ((temp_dev->internal->i2c_adap != i2c_adap) || + (temp_dev->internal->i2c_addr != i2c_addr))) { + + temp_dev = temp_dev->next_dev; + } + + return temp_dev; +} + +/* deallocating chip */ +static void remove_dev(struct stv090x_internal *internal) +{ + struct stv090x_dev *prev_dev = stv090x_first_dev; + struct stv090x_dev *del_dev = find_dev(internal->i2c_adap, + internal->i2c_addr); + + if (del_dev != NULL) { + if (del_dev == stv090x_first_dev) { + stv090x_first_dev = del_dev->next_dev; + } else { + while (prev_dev->next_dev != del_dev) + prev_dev = prev_dev->next_dev; + + prev_dev->next_dev = del_dev->next_dev; + } + + kfree(del_dev); + } +} + +/* allocating new chip */ +static struct stv090x_dev *append_internal(struct stv090x_internal *internal) +{ + struct stv090x_dev *new_dev; + struct stv090x_dev *temp_dev; + + new_dev = kmalloc(sizeof(struct stv090x_dev), GFP_KERNEL); + if (new_dev != NULL) { + new_dev->internal = internal; + new_dev->next_dev = NULL; + + /* append to list */ + if (stv090x_first_dev == NULL) { + stv090x_first_dev = new_dev; + } else { + temp_dev = stv090x_first_dev; + while (temp_dev->next_dev != NULL) + temp_dev = temp_dev->next_dev; + + temp_dev->next_dev = new_dev; + } + } + + return new_dev; +} + + +/* DVBS1 and DSS C/N Lookup table */ +static const struct stv090x_tab stv090x_s1cn_tab[] = { + { 0, 8917 }, /* 0.0dB */ + { 5, 8801 }, /* 0.5dB */ + { 10, 8667 }, /* 1.0dB */ + { 15, 8522 }, /* 1.5dB */ + { 20, 8355 }, /* 2.0dB */ + { 25, 8175 }, /* 2.5dB */ + { 30, 7979 }, /* 3.0dB */ + { 35, 7763 }, /* 3.5dB */ + { 40, 7530 }, /* 4.0dB */ + { 45, 7282 }, /* 4.5dB */ + { 50, 7026 }, /* 5.0dB */ + { 55, 6781 }, /* 5.5dB */ + { 60, 6514 }, /* 6.0dB */ + { 65, 6241 }, /* 6.5dB */ + { 70, 5965 }, /* 7.0dB */ + { 75, 5690 }, /* 7.5dB */ + { 80, 5424 }, /* 8.0dB */ + { 85, 5161 }, /* 8.5dB */ + { 90, 4902 }, /* 9.0dB */ + { 95, 4654 }, /* 9.5dB */ + { 100, 4417 }, /* 10.0dB */ + { 105, 4186 }, /* 10.5dB */ + { 110, 3968 }, /* 11.0dB */ + { 115, 3757 }, /* 11.5dB */ + { 120, 3558 }, /* 12.0dB */ + { 125, 3366 }, /* 12.5dB */ + { 130, 3185 }, /* 13.0dB */ + { 135, 3012 }, /* 13.5dB */ + { 140, 2850 }, /* 14.0dB */ + { 145, 2698 }, /* 14.5dB */ + { 150, 2550 }, /* 15.0dB */ + { 160, 2283 }, /* 16.0dB */ + { 170, 2042 }, /* 17.0dB */ + { 180, 1827 }, /* 18.0dB */ + { 190, 1636 }, /* 19.0dB */ + { 200, 1466 }, /* 20.0dB */ + { 210, 1315 }, /* 21.0dB */ + { 220, 1181 }, /* 22.0dB */ + { 230, 1064 }, /* 23.0dB */ + { 240, 960 }, /* 24.0dB */ + { 250, 869 }, /* 25.0dB */ + { 260, 792 }, /* 26.0dB */ + { 270, 724 }, /* 27.0dB */ + { 280, 665 }, /* 28.0dB */ + { 290, 616 }, /* 29.0dB */ + { 300, 573 }, /* 30.0dB */ + { 310, 537 }, /* 31.0dB */ + { 320, 507 }, /* 32.0dB */ + { 330, 483 }, /* 33.0dB */ + { 400, 398 }, /* 40.0dB */ + { 450, 381 }, /* 45.0dB */ + { 500, 377 } /* 50.0dB */ +}; + +/* DVBS2 C/N Lookup table */ +static const struct stv090x_tab stv090x_s2cn_tab[] = { + { -30, 13348 }, /* -3.0dB */ + { -20, 12640 }, /* -2d.0B */ + { -10, 11883 }, /* -1.0dB */ + { 0, 11101 }, /* -0.0dB */ + { 5, 10718 }, /* 0.5dB */ + { 10, 10339 }, /* 1.0dB */ + { 15, 9947 }, /* 1.5dB */ + { 20, 9552 }, /* 2.0dB */ + { 25, 9183 }, /* 2.5dB */ + { 30, 8799 }, /* 3.0dB */ + { 35, 8422 }, /* 3.5dB */ + { 40, 8062 }, /* 4.0dB */ + { 45, 7707 }, /* 4.5dB */ + { 50, 7353 }, /* 5.0dB */ + { 55, 7025 }, /* 5.5dB */ + { 60, 6684 }, /* 6.0dB */ + { 65, 6331 }, /* 6.5dB */ + { 70, 6036 }, /* 7.0dB */ + { 75, 5727 }, /* 7.5dB */ + { 80, 5437 }, /* 8.0dB */ + { 85, 5164 }, /* 8.5dB */ + { 90, 4902 }, /* 9.0dB */ + { 95, 4653 }, /* 9.5dB */ + { 100, 4408 }, /* 10.0dB */ + { 105, 4187 }, /* 10.5dB */ + { 110, 3961 }, /* 11.0dB */ + { 115, 3751 }, /* 11.5dB */ + { 120, 3558 }, /* 12.0dB */ + { 125, 3368 }, /* 12.5dB */ + { 130, 3191 }, /* 13.0dB */ + { 135, 3017 }, /* 13.5dB */ + { 140, 2862 }, /* 14.0dB */ + { 145, 2710 }, /* 14.5dB */ + { 150, 2565 }, /* 15.0dB */ + { 160, 2300 }, /* 16.0dB */ + { 170, 2058 }, /* 17.0dB */ + { 180, 1849 }, /* 18.0dB */ + { 190, 1663 }, /* 19.0dB */ + { 200, 1495 }, /* 20.0dB */ + { 210, 1349 }, /* 21.0dB */ + { 220, 1222 }, /* 22.0dB */ + { 230, 1110 }, /* 23.0dB */ + { 240, 1011 }, /* 24.0dB */ + { 250, 925 }, /* 25.0dB */ + { 260, 853 }, /* 26.0dB */ + { 270, 789 }, /* 27.0dB */ + { 280, 734 }, /* 28.0dB */ + { 290, 690 }, /* 29.0dB */ + { 300, 650 }, /* 30.0dB */ + { 310, 619 }, /* 31.0dB */ + { 320, 593 }, /* 32.0dB */ + { 330, 571 }, /* 33.0dB */ + { 400, 498 }, /* 40.0dB */ + { 450, 484 }, /* 45.0dB */ + { 500, 481 } /* 50.0dB */ +}; + +/* RF level C/N lookup table */ +static const struct stv090x_tab stv090x_rf_tab[] = { + { -5, 0xcaa1 }, /* -5dBm */ + { -10, 0xc229 }, /* -10dBm */ + { -15, 0xbb08 }, /* -15dBm */ + { -20, 0xb4bc }, /* -20dBm */ + { -25, 0xad5a }, /* -25dBm */ + { -30, 0xa298 }, /* -30dBm */ + { -35, 0x98a8 }, /* -35dBm */ + { -40, 0x8389 }, /* -40dBm */ + { -45, 0x59be }, /* -45dBm */ + { -50, 0x3a14 }, /* -50dBm */ + { -55, 0x2d11 }, /* -55dBm */ + { -60, 0x210d }, /* -60dBm */ + { -65, 0xa14f }, /* -65dBm */ + { -70, 0x07aa } /* -70dBm */ +}; + + +static struct stv090x_reg stv0900_initval[] = { + + { STV090x_OUTCFG, 0x00 }, + { STV090x_MODECFG, 0xff }, + { STV090x_AGCRF1CFG, 0x11 }, + { STV090x_AGCRF2CFG, 0x13 }, + { STV090x_TSGENERAL1X, 0x14 }, + { STV090x_TSTTNR2, 0x21 }, + { STV090x_TSTTNR4, 0x21 }, + { STV090x_P2_DISTXCTL, 0x22 }, + { STV090x_P2_F22TX, 0xc0 }, + { STV090x_P2_F22RX, 0xc0 }, + { STV090x_P2_DISRXCTL, 0x00 }, + { STV090x_P2_DMDCFGMD, 0xF9 }, + { STV090x_P2_DEMOD, 0x08 }, + { STV090x_P2_DMDCFG3, 0xc4 }, + { STV090x_P2_CARFREQ, 0xed }, + { STV090x_P2_LDT, 0xd0 }, + { STV090x_P2_LDT2, 0xb8 }, + { STV090x_P2_TMGCFG, 0xd2 }, + { STV090x_P2_TMGTHRISE, 0x20 }, + { STV090x_P1_TMGCFG, 0xd2 }, + + { STV090x_P2_TMGTHFALL, 0x00 }, + { STV090x_P2_FECSPY, 0x88 }, + { STV090x_P2_FSPYDATA, 0x3a }, + { STV090x_P2_FBERCPT4, 0x00 }, + { STV090x_P2_FSPYBER, 0x10 }, + { STV090x_P2_ERRCTRL1, 0x35 }, + { STV090x_P2_ERRCTRL2, 0xc1 }, + { STV090x_P2_CFRICFG, 0xf8 }, + { STV090x_P2_NOSCFG, 0x1c }, + { STV090x_P2_DMDTOM, 0x20 }, + { STV090x_P2_CORRELMANT, 0x70 }, + { STV090x_P2_CORRELABS, 0x88 }, + { STV090x_P2_AGC2O, 0x5b }, + { STV090x_P2_AGC2REF, 0x38 }, + { STV090x_P2_CARCFG, 0xe4 }, + { STV090x_P2_ACLC, 0x1A }, + { STV090x_P2_BCLC, 0x09 }, + { STV090x_P2_CARHDR, 0x08 }, + { STV090x_P2_KREFTMG, 0xc1 }, + { STV090x_P2_SFRUPRATIO, 0xf0 }, + { STV090x_P2_SFRLOWRATIO, 0x70 }, + { STV090x_P2_SFRSTEP, 0x58 }, + { STV090x_P2_TMGCFG2, 0x01 }, + { STV090x_P2_CAR2CFG, 0x26 }, + { STV090x_P2_BCLC2S2Q, 0x86 }, + { STV090x_P2_BCLC2S28, 0x86 }, + { STV090x_P2_SMAPCOEF7, 0x77 }, + { STV090x_P2_SMAPCOEF6, 0x85 }, + { STV090x_P2_SMAPCOEF5, 0x77 }, + { STV090x_P2_TSCFGL, 0x20 }, + { STV090x_P2_DMDCFG2, 0x3b }, + { STV090x_P2_MODCODLST0, 0xff }, + { STV090x_P2_MODCODLST1, 0xff }, + { STV090x_P2_MODCODLST2, 0xff }, + { STV090x_P2_MODCODLST3, 0xff }, + { STV090x_P2_MODCODLST4, 0xff }, + { STV090x_P2_MODCODLST5, 0xff }, + { STV090x_P2_MODCODLST6, 0xff }, + { STV090x_P2_MODCODLST7, 0xcc }, + { STV090x_P2_MODCODLST8, 0xcc }, + { STV090x_P2_MODCODLST9, 0xcc }, + { STV090x_P2_MODCODLSTA, 0xcc }, + { STV090x_P2_MODCODLSTB, 0xcc }, + { STV090x_P2_MODCODLSTC, 0xcc }, + { STV090x_P2_MODCODLSTD, 0xcc }, + { STV090x_P2_MODCODLSTE, 0xcc }, + { STV090x_P2_MODCODLSTF, 0xcf }, + { STV090x_P1_DISTXCTL, 0x22 }, + { STV090x_P1_F22TX, 0xc0 }, + { STV090x_P1_F22RX, 0xc0 }, + { STV090x_P1_DISRXCTL, 0x00 }, + { STV090x_P1_DMDCFGMD, 0xf9 }, + { STV090x_P1_DEMOD, 0x08 }, + { STV090x_P1_DMDCFG3, 0xc4 }, + { STV090x_P1_DMDTOM, 0x20 }, + { STV090x_P1_CARFREQ, 0xed }, + { STV090x_P1_LDT, 0xd0 }, + { STV090x_P1_LDT2, 0xb8 }, + { STV090x_P1_TMGCFG, 0xd2 }, + { STV090x_P1_TMGTHRISE, 0x20 }, + { STV090x_P1_TMGTHFALL, 0x00 }, + { STV090x_P1_SFRUPRATIO, 0xf0 }, + { STV090x_P1_SFRLOWRATIO, 0x70 }, + { STV090x_P1_TSCFGL, 0x20 }, + { STV090x_P1_FECSPY, 0x88 }, + { STV090x_P1_FSPYDATA, 0x3a }, + { STV090x_P1_FBERCPT4, 0x00 }, + { STV090x_P1_FSPYBER, 0x10 }, + { STV090x_P1_ERRCTRL1, 0x35 }, + { STV090x_P1_ERRCTRL2, 0xc1 }, + { STV090x_P1_CFRICFG, 0xf8 }, + { STV090x_P1_NOSCFG, 0x1c }, + { STV090x_P1_CORRELMANT, 0x70 }, + { STV090x_P1_CORRELABS, 0x88 }, + { STV090x_P1_AGC2O, 0x5b }, + { STV090x_P1_AGC2REF, 0x38 }, + { STV090x_P1_CARCFG, 0xe4 }, + { STV090x_P1_ACLC, 0x1A }, + { STV090x_P1_BCLC, 0x09 }, + { STV090x_P1_CARHDR, 0x08 }, + { STV090x_P1_KREFTMG, 0xc1 }, + { STV090x_P1_SFRSTEP, 0x58 }, + { STV090x_P1_TMGCFG2, 0x01 }, + { STV090x_P1_CAR2CFG, 0x26 }, + { STV090x_P1_BCLC2S2Q, 0x86 }, + { STV090x_P1_BCLC2S28, 0x86 }, + { STV090x_P1_SMAPCOEF7, 0x77 }, + { STV090x_P1_SMAPCOEF6, 0x85 }, + { STV090x_P1_SMAPCOEF5, 0x77 }, + { STV090x_P1_DMDCFG2, 0x3b }, + { STV090x_P1_MODCODLST0, 0xff }, + { STV090x_P1_MODCODLST1, 0xff }, + { STV090x_P1_MODCODLST2, 0xff }, + { STV090x_P1_MODCODLST3, 0xff }, + { STV090x_P1_MODCODLST4, 0xff }, + { STV090x_P1_MODCODLST5, 0xff }, + { STV090x_P1_MODCODLST6, 0xff }, + { STV090x_P1_MODCODLST7, 0xcc }, + { STV090x_P1_MODCODLST8, 0xcc }, + { STV090x_P1_MODCODLST9, 0xcc }, + { STV090x_P1_MODCODLSTA, 0xcc }, + { STV090x_P1_MODCODLSTB, 0xcc }, + { STV090x_P1_MODCODLSTC, 0xcc }, + { STV090x_P1_MODCODLSTD, 0xcc }, + { STV090x_P1_MODCODLSTE, 0xcc }, + { STV090x_P1_MODCODLSTF, 0xcf }, + { STV090x_GENCFG, 0x1d }, + { STV090x_NBITER_NF4, 0x37 }, + { STV090x_NBITER_NF5, 0x29 }, + { STV090x_NBITER_NF6, 0x37 }, + { STV090x_NBITER_NF7, 0x33 }, + { STV090x_NBITER_NF8, 0x31 }, + { STV090x_NBITER_NF9, 0x2f }, + { STV090x_NBITER_NF10, 0x39 }, + { STV090x_NBITER_NF11, 0x3a }, + { STV090x_NBITER_NF12, 0x29 }, + { STV090x_NBITER_NF13, 0x37 }, + { STV090x_NBITER_NF14, 0x33 }, + { STV090x_NBITER_NF15, 0x2f }, + { STV090x_NBITER_NF16, 0x39 }, + { STV090x_NBITER_NF17, 0x3a }, + { STV090x_NBITERNOERR, 0x04 }, + { STV090x_GAINLLR_NF4, 0x0C }, + { STV090x_GAINLLR_NF5, 0x0F }, + { STV090x_GAINLLR_NF6, 0x11 }, + { STV090x_GAINLLR_NF7, 0x14 }, + { STV090x_GAINLLR_NF8, 0x17 }, + { STV090x_GAINLLR_NF9, 0x19 }, + { STV090x_GAINLLR_NF10, 0x20 }, + { STV090x_GAINLLR_NF11, 0x21 }, + { STV090x_GAINLLR_NF12, 0x0D }, + { STV090x_GAINLLR_NF13, 0x0F }, + { STV090x_GAINLLR_NF14, 0x13 }, + { STV090x_GAINLLR_NF15, 0x1A }, + { STV090x_GAINLLR_NF16, 0x1F }, + { STV090x_GAINLLR_NF17, 0x21 }, + { STV090x_RCCFGH, 0x20 }, + { STV090x_P1_FECM, 0x01 }, /* disable DSS modes */ + { STV090x_P2_FECM, 0x01 }, /* disable DSS modes */ + { STV090x_P1_PRVIT, 0x2F }, /* disable PR 6/7 */ + { STV090x_P2_PRVIT, 0x2F }, /* disable PR 6/7 */ +}; + +static struct stv090x_reg stv0903_initval[] = { + { STV090x_OUTCFG, 0x00 }, + { STV090x_AGCRF1CFG, 0x11 }, + { STV090x_STOPCLK1, 0x48 }, + { STV090x_STOPCLK2, 0x14 }, + { STV090x_TSTTNR1, 0x27 }, + { STV090x_TSTTNR2, 0x21 }, + { STV090x_P1_DISTXCTL, 0x22 }, + { STV090x_P1_F22TX, 0xc0 }, + { STV090x_P1_F22RX, 0xc0 }, + { STV090x_P1_DISRXCTL, 0x00 }, + { STV090x_P1_DMDCFGMD, 0xF9 }, + { STV090x_P1_DEMOD, 0x08 }, + { STV090x_P1_DMDCFG3, 0xc4 }, + { STV090x_P1_CARFREQ, 0xed }, + { STV090x_P1_TNRCFG2, 0x82 }, + { STV090x_P1_LDT, 0xd0 }, + { STV090x_P1_LDT2, 0xb8 }, + { STV090x_P1_TMGCFG, 0xd2 }, + { STV090x_P1_TMGTHRISE, 0x20 }, + { STV090x_P1_TMGTHFALL, 0x00 }, + { STV090x_P1_SFRUPRATIO, 0xf0 }, + { STV090x_P1_SFRLOWRATIO, 0x70 }, + { STV090x_P1_TSCFGL, 0x20 }, + { STV090x_P1_FECSPY, 0x88 }, + { STV090x_P1_FSPYDATA, 0x3a }, + { STV090x_P1_FBERCPT4, 0x00 }, + { STV090x_P1_FSPYBER, 0x10 }, + { STV090x_P1_ERRCTRL1, 0x35 }, + { STV090x_P1_ERRCTRL2, 0xc1 }, + { STV090x_P1_CFRICFG, 0xf8 }, + { STV090x_P1_NOSCFG, 0x1c }, + { STV090x_P1_DMDTOM, 0x20 }, + { STV090x_P1_CORRELMANT, 0x70 }, + { STV090x_P1_CORRELABS, 0x88 }, + { STV090x_P1_AGC2O, 0x5b }, + { STV090x_P1_AGC2REF, 0x38 }, + { STV090x_P1_CARCFG, 0xe4 }, + { STV090x_P1_ACLC, 0x1A }, + { STV090x_P1_BCLC, 0x09 }, + { STV090x_P1_CARHDR, 0x08 }, + { STV090x_P1_KREFTMG, 0xc1 }, + { STV090x_P1_SFRSTEP, 0x58 }, + { STV090x_P1_TMGCFG2, 0x01 }, + { STV090x_P1_CAR2CFG, 0x26 }, + { STV090x_P1_BCLC2S2Q, 0x86 }, + { STV090x_P1_BCLC2S28, 0x86 }, + { STV090x_P1_SMAPCOEF7, 0x77 }, + { STV090x_P1_SMAPCOEF6, 0x85 }, + { STV090x_P1_SMAPCOEF5, 0x77 }, + { STV090x_P1_DMDCFG2, 0x3b }, + { STV090x_P1_MODCODLST0, 0xff }, + { STV090x_P1_MODCODLST1, 0xff }, + { STV090x_P1_MODCODLST2, 0xff }, + { STV090x_P1_MODCODLST3, 0xff }, + { STV090x_P1_MODCODLST4, 0xff }, + { STV090x_P1_MODCODLST5, 0xff }, + { STV090x_P1_MODCODLST6, 0xff }, + { STV090x_P1_MODCODLST7, 0xcc }, + { STV090x_P1_MODCODLST8, 0xcc }, + { STV090x_P1_MODCODLST9, 0xcc }, + { STV090x_P1_MODCODLSTA, 0xcc }, + { STV090x_P1_MODCODLSTB, 0xcc }, + { STV090x_P1_MODCODLSTC, 0xcc }, + { STV090x_P1_MODCODLSTD, 0xcc }, + { STV090x_P1_MODCODLSTE, 0xcc }, + { STV090x_P1_MODCODLSTF, 0xcf }, + { STV090x_GENCFG, 0x1c }, + { STV090x_NBITER_NF4, 0x37 }, + { STV090x_NBITER_NF5, 0x29 }, + { STV090x_NBITER_NF6, 0x37 }, + { STV090x_NBITER_NF7, 0x33 }, + { STV090x_NBITER_NF8, 0x31 }, + { STV090x_NBITER_NF9, 0x2f }, + { STV090x_NBITER_NF10, 0x39 }, + { STV090x_NBITER_NF11, 0x3a }, + { STV090x_NBITER_NF12, 0x29 }, + { STV090x_NBITER_NF13, 0x37 }, + { STV090x_NBITER_NF14, 0x33 }, + { STV090x_NBITER_NF15, 0x2f }, + { STV090x_NBITER_NF16, 0x39 }, + { STV090x_NBITER_NF17, 0x3a }, + { STV090x_NBITERNOERR, 0x04 }, + { STV090x_GAINLLR_NF4, 0x0C }, + { STV090x_GAINLLR_NF5, 0x0F }, + { STV090x_GAINLLR_NF6, 0x11 }, + { STV090x_GAINLLR_NF7, 0x14 }, + { STV090x_GAINLLR_NF8, 0x17 }, + { STV090x_GAINLLR_NF9, 0x19 }, + { STV090x_GAINLLR_NF10, 0x20 }, + { STV090x_GAINLLR_NF11, 0x21 }, + { STV090x_GAINLLR_NF12, 0x0D }, + { STV090x_GAINLLR_NF13, 0x0F }, + { STV090x_GAINLLR_NF14, 0x13 }, + { STV090x_GAINLLR_NF15, 0x1A }, + { STV090x_GAINLLR_NF16, 0x1F }, + { STV090x_GAINLLR_NF17, 0x21 }, + { STV090x_RCCFGH, 0x20 }, + { STV090x_P1_FECM, 0x01 }, /*disable the DSS mode */ + { STV090x_P1_PRVIT, 0x2f } /*disable puncture rate 6/7*/ +}; + +static struct stv090x_reg stv0900_cut20_val[] = { + + { STV090x_P2_DMDCFG3, 0xe8 }, + { STV090x_P2_DMDCFG4, 0x10 }, + { STV090x_P2_CARFREQ, 0x38 }, + { STV090x_P2_CARHDR, 0x20 }, + { STV090x_P2_KREFTMG, 0x5a }, + { STV090x_P2_SMAPCOEF7, 0x06 }, + { STV090x_P2_SMAPCOEF6, 0x00 }, + { STV090x_P2_SMAPCOEF5, 0x04 }, + { STV090x_P2_NOSCFG, 0x0c }, + { STV090x_P1_DMDCFG3, 0xe8 }, + { STV090x_P1_DMDCFG4, 0x10 }, + { STV090x_P1_CARFREQ, 0x38 }, + { STV090x_P1_CARHDR, 0x20 }, + { STV090x_P1_KREFTMG, 0x5a }, + { STV090x_P1_SMAPCOEF7, 0x06 }, + { STV090x_P1_SMAPCOEF6, 0x00 }, + { STV090x_P1_SMAPCOEF5, 0x04 }, + { STV090x_P1_NOSCFG, 0x0c }, + { STV090x_GAINLLR_NF4, 0x21 }, + { STV090x_GAINLLR_NF5, 0x21 }, + { STV090x_GAINLLR_NF6, 0x20 }, + { STV090x_GAINLLR_NF7, 0x1F }, + { STV090x_GAINLLR_NF8, 0x1E }, + { STV090x_GAINLLR_NF9, 0x1E }, + { STV090x_GAINLLR_NF10, 0x1D }, + { STV090x_GAINLLR_NF11, 0x1B }, + { STV090x_GAINLLR_NF12, 0x20 }, + { STV090x_GAINLLR_NF13, 0x20 }, + { STV090x_GAINLLR_NF14, 0x20 }, + { STV090x_GAINLLR_NF15, 0x20 }, + { STV090x_GAINLLR_NF16, 0x20 }, + { STV090x_GAINLLR_NF17, 0x21 }, +}; + +static struct stv090x_reg stv0903_cut20_val[] = { + { STV090x_P1_DMDCFG3, 0xe8 }, + { STV090x_P1_DMDCFG4, 0x10 }, + { STV090x_P1_CARFREQ, 0x38 }, + { STV090x_P1_CARHDR, 0x20 }, + { STV090x_P1_KREFTMG, 0x5a }, + { STV090x_P1_SMAPCOEF7, 0x06 }, + { STV090x_P1_SMAPCOEF6, 0x00 }, + { STV090x_P1_SMAPCOEF5, 0x04 }, + { STV090x_P1_NOSCFG, 0x0c }, + { STV090x_GAINLLR_NF4, 0x21 }, + { STV090x_GAINLLR_NF5, 0x21 }, + { STV090x_GAINLLR_NF6, 0x20 }, + { STV090x_GAINLLR_NF7, 0x1F }, + { STV090x_GAINLLR_NF8, 0x1E }, + { STV090x_GAINLLR_NF9, 0x1E }, + { STV090x_GAINLLR_NF10, 0x1D }, + { STV090x_GAINLLR_NF11, 0x1B }, + { STV090x_GAINLLR_NF12, 0x20 }, + { STV090x_GAINLLR_NF13, 0x20 }, + { STV090x_GAINLLR_NF14, 0x20 }, + { STV090x_GAINLLR_NF15, 0x20 }, + { STV090x_GAINLLR_NF16, 0x20 }, + { STV090x_GAINLLR_NF17, 0x21 } +}; + +/* Cut 2.0 Long Frame Tracking CR loop */ +static struct stv090x_long_frame_crloop stv090x_s2_crl_cut20[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_QPSK_12, 0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x1e }, + { STV090x_QPSK_35, 0x2f, 0x3f, 0x2e, 0x2f, 0x3d, 0x0f, 0x0e, 0x2e, 0x3d, 0x0e }, + { STV090x_QPSK_23, 0x2f, 0x3f, 0x2e, 0x2f, 0x0e, 0x0f, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_34, 0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_45, 0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_56, 0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_89, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_910, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_8PSK_35, 0x3c, 0x3e, 0x1c, 0x2e, 0x0c, 0x1e, 0x2b, 0x2d, 0x1b, 0x1d }, + { STV090x_8PSK_23, 0x1d, 0x3e, 0x3c, 0x2e, 0x2c, 0x1e, 0x0c, 0x2d, 0x2b, 0x1d }, + { STV090x_8PSK_34, 0x0e, 0x3e, 0x3d, 0x2e, 0x0d, 0x1e, 0x2c, 0x2d, 0x0c, 0x1d }, + { STV090x_8PSK_56, 0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d }, + { STV090x_8PSK_89, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d }, + { STV090x_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d } +}; + +/* Cut 3.0 Long Frame Tracking CR loop */ +static struct stv090x_long_frame_crloop stv090x_s2_crl_cut30[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_QPSK_12, 0x3c, 0x2c, 0x0c, 0x2c, 0x1b, 0x2c, 0x1b, 0x1c, 0x0b, 0x3b }, + { STV090x_QPSK_35, 0x0d, 0x0d, 0x0c, 0x0d, 0x1b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b }, + { STV090x_QPSK_23, 0x1d, 0x0d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b }, + { STV090x_QPSK_34, 0x1d, 0x1d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b }, + { STV090x_QPSK_45, 0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, + { STV090x_QPSK_56, 0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, + { STV090x_QPSK_89, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, + { STV090x_QPSK_910, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, + { STV090x_8PSK_35, 0x39, 0x29, 0x39, 0x19, 0x19, 0x19, 0x19, 0x19, 0x09, 0x19 }, + { STV090x_8PSK_23, 0x2a, 0x39, 0x1a, 0x0a, 0x39, 0x0a, 0x29, 0x39, 0x29, 0x0a }, + { STV090x_8PSK_34, 0x2b, 0x3a, 0x1b, 0x1b, 0x3a, 0x1b, 0x1a, 0x0b, 0x1a, 0x3a }, + { STV090x_8PSK_56, 0x0c, 0x1b, 0x3b, 0x3b, 0x1b, 0x3b, 0x3a, 0x3b, 0x3a, 0x1b }, + { STV090x_8PSK_89, 0x0d, 0x3c, 0x2c, 0x2c, 0x2b, 0x0c, 0x0b, 0x3b, 0x0b, 0x1b }, + { STV090x_8PSK_910, 0x0d, 0x0d, 0x2c, 0x3c, 0x3b, 0x1c, 0x0b, 0x3b, 0x0b, 0x1b } +}; + +/* Cut 2.0 Long Frame Tracking CR Loop */ +static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut20[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_16APSK_23, 0x0c, 0x0c, 0x0c, 0x0c, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x0c }, + { STV090x_16APSK_34, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0c, 0x2d, 0x0c, 0x1d, 0x0c }, + { STV090x_16APSK_45, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c }, + { STV090x_16APSK_56, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c }, + { STV090x_16APSK_89, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c }, + { STV090x_16APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c }, + { STV090x_32APSK_34, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, + { STV090x_32APSK_45, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, + { STV090x_32APSK_56, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, + { STV090x_32APSK_89, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, + { STV090x_32APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c } +}; + +/* Cut 3.0 Long Frame Tracking CR Loop */ +static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut30[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_16APSK_23, 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x0a, 0x3a, 0x0a, 0x2a, 0x0a }, + { STV090x_16APSK_34, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x3b, 0x0a, 0x1b, 0x0a }, + { STV090x_16APSK_45, 0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a }, + { STV090x_16APSK_56, 0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a }, + { STV090x_16APSK_89, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a }, + { STV090x_16APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a }, + { STV090x_32APSK_34, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, + { STV090x_32APSK_45, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, + { STV090x_32APSK_56, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, + { STV090x_32APSK_89, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, + { STV090x_32APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } +}; + +static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut20[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_QPSK_14, 0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x2d, 0x1f, 0x3d, 0x3e }, + { STV090x_QPSK_13, 0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x3d, 0x0f, 0x3d, 0x2e }, + { STV090x_QPSK_25, 0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x2e } +}; + +static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut30[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_QPSK_14, 0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x2a, 0x1c, 0x3a, 0x3b }, + { STV090x_QPSK_13, 0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x3a, 0x0c, 0x3a, 0x2b }, + { STV090x_QPSK_25, 0x1c, 0x3c, 0x1b, 0x3c, 0x3a, 0x1c, 0x3a, 0x3b, 0x3a, 0x2b } +}; + +/* Cut 2.0 Short Frame Tracking CR Loop */ +static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut20[] = { + /* MODCOD 2M 5M 10M 20M 30M */ + { STV090x_QPSK, 0x2f, 0x2e, 0x0e, 0x0e, 0x3d }, + { STV090x_8PSK, 0x3e, 0x0e, 0x2d, 0x0d, 0x3c }, + { STV090x_16APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d }, + { STV090x_32APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d } +}; + +/* Cut 3.0 Short Frame Tracking CR Loop */ +static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut30[] = { + /* MODCOD 2M 5M 10M 20M 30M */ + { STV090x_QPSK, 0x2C, 0x2B, 0x0B, 0x0B, 0x3A }, + { STV090x_8PSK, 0x3B, 0x0B, 0x2A, 0x0A, 0x39 }, + { STV090x_16APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A }, + { STV090x_32APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A } +}; + +static inline s32 comp2(s32 __x, s32 __width) +{ + if (__width == 32) + return __x; + else + return (__x >= (1 << (__width - 1))) ? (__x - (1 << __width)) : __x; +} + +static int stv090x_read_reg(struct stv090x_state *state, unsigned int reg) +{ + const struct stv090x_config *config = state->config; + int ret; + + u8 b0[] = { reg >> 8, reg & 0xff }; + u8 buf; + + struct i2c_msg msg[] = { + { .addr = config->address, .flags = 0, .buf = b0, .len = 2 }, + { .addr = config->address, .flags = I2C_M_RD, .buf = &buf, .len = 1 } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + if (ret != -ERESTARTSYS) + dprintk(FE_ERROR, 1, + "Read error, Reg=[0x%02x], Status=%d", + reg, ret); + + return ret < 0 ? ret : -EREMOTEIO; + } + if (unlikely(*state->verbose >= FE_DEBUGREG)) + dprintk(FE_ERROR, 1, "Reg=[0x%02x], data=%02x", + reg, buf); + + return (unsigned int) buf; +} + +static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 *data, u32 count) +{ + const struct stv090x_config *config = state->config; + int ret; + u8 buf[2 + count]; + struct i2c_msg i2c_msg = { .addr = config->address, .flags = 0, .buf = buf, .len = 2 + count }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + memcpy(&buf[2], data, count); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) { + int i; + + printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); + for (i = 0; i < count; i++) + printk(" %02x", data[i]); + printk("\n"); + } + + ret = i2c_transfer(state->i2c, &i2c_msg, 1); + if (ret != 1) { + if (ret != -ERESTARTSYS) + dprintk(FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d", + reg, data[0], count, ret); + return ret < 0 ? ret : -EREMOTEIO; + } + + return 0; +} + +static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data) +{ + return stv090x_write_regs(state, reg, &data, 1); +} + +static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) +{ + u32 reg; + + /* + * NOTE! A lock is used as a FSM to control the state in which + * access is serialized between two tuners on the same demod. + * This has nothing to do with a lock to protect a critical section + * which may in some other cases be confused with protecting I/O + * access to the demodulator gate. + * In case of any error, the lock is unlocked and exit within the + * relevant operations themselves. + */ + if (enable) { + if (state->config->tuner_i2c_lock) + state->config->tuner_i2c_lock(&state->frontend, 1); + else + mutex_lock(&state->internal->tuner_lock); + } + + reg = STV090x_READ_DEMOD(state, I2CRPT); + if (enable) { + dprintk(FE_DEBUG, 1, "Enable Gate"); + STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0) + goto err; + + } else { + dprintk(FE_DEBUG, 1, "Disable Gate"); + STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 0); + if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0) + goto err; + } + + if (!enable) { + if (state->config->tuner_i2c_lock) + state->config->tuner_i2c_lock(&state->frontend, 0); + else + mutex_unlock(&state->internal->tuner_lock); + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + if (state->config->tuner_i2c_lock) + state->config->tuner_i2c_lock(&state->frontend, 0); + else + mutex_unlock(&state->internal->tuner_lock); + return -1; +} + +static void stv090x_get_lock_tmg(struct stv090x_state *state) +{ + switch (state->algo) { + case STV090x_BLIND_SEARCH: + dprintk(FE_DEBUG, 1, "Blind Search"); + if (state->srate <= 1500000) { /*10Msps< SR <=15Msps*/ + state->DemodTimeout = 1500; + state->FecTimeout = 400; + } else if (state->srate <= 5000000) { /*10Msps< SR <=15Msps*/ + state->DemodTimeout = 1000; + state->FecTimeout = 300; + } else { /*SR >20Msps*/ + state->DemodTimeout = 700; + state->FecTimeout = 100; + } + break; + + case STV090x_COLD_SEARCH: + case STV090x_WARM_SEARCH: + default: + dprintk(FE_DEBUG, 1, "Normal Search"); + if (state->srate <= 1000000) { /*SR <=1Msps*/ + state->DemodTimeout = 4500; + state->FecTimeout = 1700; + } else if (state->srate <= 2000000) { /*1Msps < SR <= 2Msps */ + state->DemodTimeout = 2500; + state->FecTimeout = 1100; + } else if (state->srate <= 5000000) { /*2Msps < SR <= 5Msps */ + state->DemodTimeout = 1000; + state->FecTimeout = 550; + } else if (state->srate <= 10000000) { /*5Msps < SR <= 10Msps */ + state->DemodTimeout = 700; + state->FecTimeout = 250; + } else if (state->srate <= 20000000) { /*10Msps < SR <= 20Msps */ + state->DemodTimeout = 400; + state->FecTimeout = 130; + } else { /*SR >20Msps*/ + state->DemodTimeout = 300; + state->FecTimeout = 100; + } + break; + } + + if (state->algo == STV090x_WARM_SEARCH) + state->DemodTimeout /= 2; +} + +static int stv090x_set_srate(struct stv090x_state *state, u32 srate) +{ + u32 sym; + + if (srate > 60000000) { + sym = (srate << 4); /* SR * 2^16 / master_clk */ + sym /= (state->internal->mclk >> 12); + } else if (srate > 6000000) { + sym = (srate << 6); + sym /= (state->internal->mclk >> 10); + } else { + sym = (srate << 9); + sym /= (state->internal->mclk >> 7); + } + + if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRINIT0, (sym & 0xff)) < 0) /* LSB */ + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate) +{ + u32 sym; + + srate = 105 * (srate / 100); + if (srate > 60000000) { + sym = (srate << 4); /* SR * 2^16 / master_clk */ + sym /= (state->internal->mclk >> 12); + } else if (srate > 6000000) { + sym = (srate << 6); + sym /= (state->internal->mclk >> 10); + } else { + sym = (srate << 9); + sym /= (state->internal->mclk >> 7); + } + + if (sym < 0x7fff) { + if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) /* MSB */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) /* LSB */ + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x7f) < 0) /* MSB */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xff) < 0) /* LSB */ + goto err; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate) +{ + u32 sym; + + srate = 95 * (srate / 100); + if (srate > 60000000) { + sym = (srate << 4); /* SR * 2^16 / master_clk */ + sym /= (state->internal->mclk >> 12); + } else if (srate > 6000000) { + sym = (srate << 6); + sym /= (state->internal->mclk >> 10); + } else { + sym = (srate << 9); + sym /= (state->internal->mclk >> 7); + } + + if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0x7f)) < 0) /* MSB */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */ + goto err; + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static u32 stv090x_car_width(u32 srate, enum stv090x_rolloff rolloff) +{ + u32 ro; + + switch (rolloff) { + case STV090x_RO_20: + ro = 20; + break; + case STV090x_RO_25: + ro = 25; + break; + case STV090x_RO_35: + default: + ro = 35; + break; + } + + return srate + (srate * ro) / 100; +} + +static int stv090x_set_vit_thacq(struct stv090x_state *state) +{ + if (STV090x_WRITE_DEMOD(state, VTH12, 0x96) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH23, 0x64) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH34, 0x36) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH56, 0x23) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH67, 0x1e) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH78, 0x19) < 0) + goto err; + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_vit_thtracq(struct stv090x_state *state) +{ + if (STV090x_WRITE_DEMOD(state, VTH12, 0xd0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH23, 0x7d) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH34, 0x53) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH56, 0x2f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH67, 0x24) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH78, 0x1f) < 0) + goto err; + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_viterbi(struct stv090x_state *state) +{ + switch (state->search_mode) { + case STV090x_SEARCH_AUTO: + if (STV090x_WRITE_DEMOD(state, FECM, 0x10) < 0) /* DVB-S and DVB-S2 */ + goto err; + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x3f) < 0) /* all puncture rate */ + goto err; + break; + case STV090x_SEARCH_DVBS1: + if (STV090x_WRITE_DEMOD(state, FECM, 0x00) < 0) /* disable DSS */ + goto err; + switch (state->fec) { + case STV090x_PR12: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0) + goto err; + break; + + case STV090x_PR23: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0) + goto err; + break; + + case STV090x_PR34: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x04) < 0) + goto err; + break; + + case STV090x_PR56: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x08) < 0) + goto err; + break; + + case STV090x_PR78: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x20) < 0) + goto err; + break; + + default: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x2f) < 0) /* all */ + goto err; + break; + } + break; + case STV090x_SEARCH_DSS: + if (STV090x_WRITE_DEMOD(state, FECM, 0x80) < 0) + goto err; + switch (state->fec) { + case STV090x_PR12: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0) + goto err; + break; + + case STV090x_PR23: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0) + goto err; + break; + + case STV090x_PR67: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x10) < 0) + goto err; + break; + + default: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x13) < 0) /* 1/2, 2/3, 6/7 */ + goto err; + break; + } + break; + default: + break; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_stop_modcod(struct stv090x_state *state) +{ + if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xff) < 0) + goto err; + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_activate_modcod(struct stv090x_state *state) +{ + if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xfc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_activate_modcod_single(struct stv090x_state *state) +{ + + if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xf0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0x0f) < 0) + goto err; + + return 0; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable) +{ + u32 reg; + + switch (state->demod) { + case STV090x_DEMODULATOR_0: + mutex_lock(&state->internal->demod_lock); + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + mutex_unlock(&state->internal->demod_lock); + break; + + case STV090x_DEMODULATOR_1: + mutex_lock(&state->internal->demod_lock); + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + mutex_unlock(&state->internal->demod_lock); + break; + + default: + dprintk(FE_ERROR, 1, "Wrong demodulator!"); + break; + } + return 0; +err: + mutex_unlock(&state->internal->demod_lock); + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_dvbs_track_crl(struct stv090x_state *state) +{ + if (state->internal->dev_ver >= 0x30) { + /* Set ACLC BCLC optimised value vs SR */ + if (state->srate >= 15000000) { + if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x1a) < 0) + goto err; + } else if ((state->srate >= 7000000) && (15000000 > state->srate)) { + if (STV090x_WRITE_DEMOD(state, ACLC, 0x0c) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x1b) < 0) + goto err; + } else if (state->srate < 7000000) { + if (STV090x_WRITE_DEMOD(state, ACLC, 0x2c) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x1c) < 0) + goto err; + } + + } else { + /* Cut 2.0 */ + if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0) + goto err; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_delivery_search(struct stv090x_state *state) +{ + u32 reg; + + switch (state->search_mode) { + case STV090x_SEARCH_DVBS1: + case STV090x_SEARCH_DSS: + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + /* Activate Viterbi decoder in legacy search, + * do not use FRESVIT1, might impact VITERBI2 + */ + if (stv090x_vitclk_ctl(state, 0) < 0) + goto err; + + if (stv090x_dvbs_track_crl(state) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x22) < 0) /* disable DVB-S2 */ + goto err; + + if (stv090x_set_vit_thacq(state) < 0) + goto err; + if (stv090x_set_viterbi(state) < 0) + goto err; + break; + + case STV090x_SEARCH_DVBS2: + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (stv090x_vitclk_ctl(state, 1) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) /* stop DVB-S CR loop */ + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0) + goto err; + + if (state->internal->dev_ver <= 0x20) { + /* enable S2 carrier loop */ + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0) + goto err; + } else { + /* > Cut 3: Stop carrier 3 */ + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0) + goto err; + } + + if (state->demod_mode != STV090x_SINGLE) { + /* Cut 2: enable link during search */ + if (stv090x_activate_modcod(state) < 0) + goto err; + } else { + /* Single demodulator + * Authorize SHORT and LONG frames, + * QPSK, 8PSK, 16APSK and 32APSK + */ + if (stv090x_activate_modcod_single(state) < 0) + goto err; + } + + if (stv090x_set_vit_thtracq(state) < 0) + goto err; + break; + + case STV090x_SEARCH_AUTO: + default: + /* enable DVB-S2 and DVB-S2 in Auto MODE */ + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (stv090x_vitclk_ctl(state, 0) < 0) + goto err; + + if (stv090x_dvbs_track_crl(state) < 0) + goto err; + + if (state->internal->dev_ver <= 0x20) { + /* enable S2 carrier loop */ + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0) + goto err; + } else { + /* > Cut 3: Stop carrier 3 */ + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0) + goto err; + } + + if (state->demod_mode != STV090x_SINGLE) { + /* Cut 2: enable link during search */ + if (stv090x_activate_modcod(state) < 0) + goto err; + } else { + /* Single demodulator + * Authorize SHORT and LONG frames, + * QPSK, 8PSK, 16APSK and 32APSK + */ + if (stv090x_activate_modcod_single(state) < 0) + goto err; + } + + if (stv090x_set_vit_thacq(state) < 0) + goto err; + + if (stv090x_set_viterbi(state) < 0) + goto err; + break; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_start_search(struct stv090x_state *state) +{ + u32 reg, freq_abs; + s16 freq; + + /* Reset demodulator */ + reg = STV090x_READ_DEMOD(state, DMDISTATE); + STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); + if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0) + goto err; + + if (state->internal->dev_ver <= 0x20) { + if (state->srate <= 5000000) { + if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRUP0, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRLOW0, 0x00) < 0) + goto err; + + /*enlarge the timing bandwidth for Low SR*/ + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) + goto err; + } else { + /* If the symbol rate is >5 Msps + Set The carrier search up and low to auto mode */ + if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0) + goto err; + /*reduce the timing bandwidth for high SR*/ + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0) + goto err; + } + } else { + /* >= Cut 3 */ + if (state->srate <= 5000000) { + /* enlarge the timing bandwidth for Low SR */ + STV090x_WRITE_DEMOD(state, RTCS2, 0x68); + } else { + /* reduce timing bandwidth for high SR */ + STV090x_WRITE_DEMOD(state, RTCS2, 0x44); + } + + /* Set CFR min and max to manual mode */ + STV090x_WRITE_DEMOD(state, CARCFG, 0x46); + + if (state->algo == STV090x_WARM_SEARCH) { + /* WARM Start + * CFR min = -1MHz, + * CFR max = +1MHz + */ + freq_abs = 1000 << 16; + freq_abs /= (state->internal->mclk / 1000); + freq = (s16) freq_abs; + } else { + /* COLD Start + * CFR min =- (SearchRange / 2 + 600KHz) + * CFR max = +(SearchRange / 2 + 600KHz) + * (600KHz for the tuner step size) + */ + freq_abs = (state->search_range / 2000) + 600; + freq_abs = freq_abs << 16; + freq_abs /= (state->internal->mclk / 1000); + freq = (s16) freq_abs; + } + + if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRUP0, LSB(freq)) < 0) + goto err; + + freq *= -1; + + if (STV090x_WRITE_DEMOD(state, CFRLOW1, MSB(freq)) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRLOW0, LSB(freq)) < 0) + goto err; + + } + + if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0) + goto err; + + if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0) + goto err; + + if ((state->search_mode == STV090x_SEARCH_DVBS1) || + (state->search_mode == STV090x_SEARCH_DSS) || + (state->search_mode == STV090x_SEARCH_AUTO)) { + + if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) + goto err; + } + } + + if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xe0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xc0) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DMDCFG2); + STV090x_SETFIELD_Px(reg, S1S2_SEQUENTIAL_FIELD, 0x0); + if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) + goto err; + + if (state->internal->dev_ver >= 0x20) { + /*Frequency offset detector setting*/ + if (state->srate < 2000000) { + if (state->internal->dev_ver <= 0x20) { + /* Cut 2 */ + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0) + goto err; + } else { + /* Cut 3 */ + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0) + goto err; + } + if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0) + goto err; + } else if (state->srate < 10000000) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0) + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0) + goto err; + } + } else { + if (state->srate < 10000000) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xef) < 0) + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xed) < 0) + goto err; + } + } + + switch (state->algo) { + case STV090x_WARM_SEARCH: + /* The symbol rate and the exact + * carrier Frequency are known + */ + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) + goto err; + break; + + case STV090x_COLD_SEARCH: + /* The symbol rate is known */ + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) + goto err; + break; + + default: + break; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_agc2_min_level(struct stv090x_state *state) +{ + u32 agc2_min = 0xffff, agc2 = 0, freq_init, freq_step, reg; + s32 i, j, steps, dir; + + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) /* SR = 65 Msps Max */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) /* SR= 400 ksps Min */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) /* stop acq @ coarse carrier state */ + goto err; + if (stv090x_set_srate(state, 1000000) < 0) + goto err; + + steps = state->search_range / 1000000; + if (steps <= 0) + steps = 1; + + dir = 1; + freq_step = (1000000 * 256) / (state->internal->mclk / 256); + freq_init = 0; + + for (i = 0; i < steps; i++) { + if (dir > 0) + freq_init = freq_init + (freq_step * i); + else + freq_init = freq_init - (freq_step * i); + + dir *= -1; + + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */ + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_init >> 8) & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_init & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */ + goto err; + msleep(10); + + agc2 = 0; + for (j = 0; j < 10; j++) { + agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) | + STV090x_READ_DEMOD(state, AGC2I0); + } + agc2 /= 10; + if (agc2 < agc2_min) + agc2_min = agc2; + } + + return agc2_min; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static u32 stv090x_get_srate(struct stv090x_state *state, u32 clk) +{ + u8 r3, r2, r1, r0; + s32 srate, int_1, int_2, tmp_1, tmp_2; + + r3 = STV090x_READ_DEMOD(state, SFR3); + r2 = STV090x_READ_DEMOD(state, SFR2); + r1 = STV090x_READ_DEMOD(state, SFR1); + r0 = STV090x_READ_DEMOD(state, SFR0); + + srate = ((r3 << 24) | (r2 << 16) | (r1 << 8) | r0); + + int_1 = clk >> 16; + int_2 = srate >> 16; + + tmp_1 = clk % 0x10000; + tmp_2 = srate % 0x10000; + + srate = (int_1 * int_2) + + ((int_1 * tmp_2) >> 16) + + ((int_2 * tmp_1) >> 16); + + return srate; +} + +static u32 stv090x_srate_srch_coarse(struct stv090x_state *state) +{ + struct dvb_frontend *fe = &state->frontend; + + int tmg_lock = 0, i; + s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq; + u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg; + u32 agc2th; + + if (state->internal->dev_ver >= 0x30) + agc2th = 0x2e00; + else + agc2th = 0x1f00; + + reg = STV090x_READ_DEMOD(state, DMDISTATE); + STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */ + if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x50) < 0) + goto err; + + if (state->internal->dev_ver >= 0x30) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x98) < 0) + goto err; + + } else if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0) + goto err; + } + + if (state->srate <= 2000000) + car_step = 1000; + else if (state->srate <= 5000000) + car_step = 2000; + else if (state->srate <= 12000000) + car_step = 3000; + else + car_step = 5000; + + steps = -1 + ((state->search_range / 1000) / car_step); + steps /= 2; + steps = (2 * steps) + 1; + if (steps < 0) + steps = 1; + else if (steps > 10) { + steps = 11; + car_step = (state->search_range / 1000) / 10; + } + cur_step = 0; + dir = 1; + freq = state->frequency; + + while ((!tmg_lock) && (cur_step < steps)) { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */ + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRINIT1, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRINIT0, 0x00) < 0) + goto err; + /* trigger acquisition */ + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x40) < 0) + goto err; + msleep(50); + for (i = 0; i < 10; i++) { + reg = STV090x_READ_DEMOD(state, DSTATUS); + if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2) + tmg_cpt++; + agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) | + STV090x_READ_DEMOD(state, AGC2I0); + } + agc2 /= 10; + srate_coarse = stv090x_get_srate(state, state->internal->mclk); + cur_step++; + dir *= -1; + if ((tmg_cpt >= 5) && (agc2 < agc2th) && + (srate_coarse < 50000000) && (srate_coarse > 850000)) + tmg_lock = 1; + else if (cur_step < steps) { + if (dir > 0) + freq += cur_step * car_step; + else + freq -= cur_step * car_step; + + /* Setup tuner */ + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_set_frequency) { + if (state->config->tuner_set_frequency(fe, freq) < 0) + goto err_gateoff; + } + + if (state->config->tuner_set_bandwidth) { + if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + msleep(50); + + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_get_status) { + if (state->config->tuner_get_status(fe, ®) < 0) + goto err_gateoff; + } + + if (reg) + dprintk(FE_DEBUG, 1, "Tuner phase locked"); + else + dprintk(FE_DEBUG, 1, "Tuner unlocked"); + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + } + } + if (!tmg_lock) + srate_coarse = 0; + else + srate_coarse = stv090x_get_srate(state, state->internal->mclk); + + return srate_coarse; + +err_gateoff: + stv090x_i2c_gate_ctrl(state, 0); +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static u32 stv090x_srate_srch_fine(struct stv090x_state *state) +{ + u32 srate_coarse, freq_coarse, sym, reg; + + srate_coarse = stv090x_get_srate(state, state->internal->mclk); + freq_coarse = STV090x_READ_DEMOD(state, CFR2) << 8; + freq_coarse |= STV090x_READ_DEMOD(state, CFR1); + sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */ + + if (sym < state->srate) + srate_coarse = 0; + else { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */ + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) + goto err; + + if (state->internal->dev_ver >= 0x30) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0) + goto err; + } else if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0) + goto err; + } + + if (srate_coarse > 3000000) { + sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */ + sym = (sym / 1000) * 65536; + sym /= (state->internal->mclk / 1000); + if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) + goto err; + sym = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */ + sym = (sym / 1000) * 65536; + sym /= (state->internal->mclk / 1000); + if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0) + goto err; + sym = (srate_coarse / 1000) * 65536; + sym /= (state->internal->mclk / 1000); + if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0) + goto err; + } else { + sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */ + sym = (sym / 100) * 65536; + sym /= (state->internal->mclk / 100); + if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) + goto err; + sym = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */ + sym = (sym / 100) * 65536; + sym /= (state->internal->mclk / 100); + if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0) + goto err; + sym = (srate_coarse / 100) * 65536; + sym /= (state->internal->mclk / 100); + if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0) + goto err; + } + if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_coarse >> 8) & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_coarse & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) /* trigger acquisition */ + goto err; + } + + return srate_coarse; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout) +{ + s32 timer = 0, lock = 0; + u32 reg; + u8 stat; + + while ((timer < timeout) && (!lock)) { + reg = STV090x_READ_DEMOD(state, DMDSTATE); + stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); + + switch (stat) { + case 0: /* searching */ + case 1: /* first PLH detected */ + default: + dprintk(FE_DEBUG, 1, "Demodulator searching .."); + lock = 0; + break; + case 2: /* DVB-S2 mode */ + case 3: /* DVB-S1/legacy mode */ + reg = STV090x_READ_DEMOD(state, DSTATUS); + lock = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD); + break; + } + + if (!lock) + msleep(10); + else + dprintk(FE_DEBUG, 1, "Demodulator acquired LOCK"); + + timer += 10; + } + return lock; +} + +static int stv090x_blind_search(struct stv090x_state *state) +{ + u32 agc2, reg, srate_coarse; + s32 cpt_fail, agc2_ovflw, i; + u8 k_ref, k_max, k_min; + int coarse_fail = 0; + int lock; + + k_max = 110; + k_min = 10; + + agc2 = stv090x_get_agc2_min_level(state); + + if (agc2 > STV090x_SEARCH_AGC2_TH(state->internal->dev_ver)) { + lock = 0; + } else { + + if (state->internal->dev_ver <= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0) + goto err; + } else { + /* > Cut 3 */ + if (STV090x_WRITE_DEMOD(state, CARCFG, 0x06) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0) + goto err; + + if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) /* set viterbi hysteresis */ + goto err; + } + + k_ref = k_max; + do { + if (STV090x_WRITE_DEMOD(state, KREFTMG, k_ref) < 0) + goto err; + if (stv090x_srate_srch_coarse(state) != 0) { + srate_coarse = stv090x_srate_srch_fine(state); + if (srate_coarse != 0) { + stv090x_get_lock_tmg(state); + lock = stv090x_get_dmdlock(state, + state->DemodTimeout); + } else { + lock = 0; + } + } else { + cpt_fail = 0; + agc2_ovflw = 0; + for (i = 0; i < 10; i++) { + agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) | + STV090x_READ_DEMOD(state, AGC2I0); + if (agc2 >= 0xff00) + agc2_ovflw++; + reg = STV090x_READ_DEMOD(state, DSTATUS2); + if ((STV090x_GETFIELD_Px(reg, CFR_OVERFLOW_FIELD) == 0x01) && + (STV090x_GETFIELD_Px(reg, DEMOD_DELOCK_FIELD) == 0x01)) + + cpt_fail++; + } + if ((cpt_fail > 7) || (agc2_ovflw > 7)) + coarse_fail = 1; + + lock = 0; + } + k_ref -= 20; + } while ((k_ref >= k_min) && (!lock) && (!coarse_fail)); + } + + return lock; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_chk_tmg(struct stv090x_state *state) +{ + u32 reg; + s32 tmg_cpt = 0, i; + u8 freq, tmg_thh, tmg_thl; + int tmg_lock = 0; + + freq = STV090x_READ_DEMOD(state, CARFREQ); + tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE); + tmg_thl = STV090x_READ_DEMOD(state, TMGTHFALL); + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); /* stop carrier offset search */ + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, RTC, 0x80) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x40) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x00) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) /* set car ofset to 0 */ + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x65) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) /* trigger acquisition */ + goto err; + msleep(10); + + for (i = 0; i < 10; i++) { + reg = STV090x_READ_DEMOD(state, DSTATUS); + if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2) + tmg_cpt++; + msleep(1); + } + if (tmg_cpt >= 3) + tmg_lock = 1; + + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) /* DVB-S1 timing */ + goto err; + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) /* DVB-S2 timing */ + goto err; + + if (STV090x_WRITE_DEMOD(state, CARFREQ, freq) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, tmg_thh) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, tmg_thl) < 0) + goto err; + + return tmg_lock; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd) +{ + struct dvb_frontend *fe = &state->frontend; + + u32 reg; + s32 car_step, steps, cur_step, dir, freq, timeout_lock; + int lock = 0; + + if (state->srate >= 10000000) + timeout_lock = timeout_dmd / 3; + else + timeout_lock = timeout_dmd / 2; + + lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */ + if (!lock) { + if (state->srate >= 10000000) { + if (stv090x_chk_tmg(state)) { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) + goto err; + lock = stv090x_get_dmdlock(state, timeout_dmd); + } else { + lock = 0; + } + } else { + if (state->srate <= 4000000) + car_step = 1000; + else if (state->srate <= 7000000) + car_step = 2000; + else if (state->srate <= 10000000) + car_step = 3000; + else + car_step = 5000; + + steps = (state->search_range / 1000) / car_step; + steps /= 2; + steps = 2 * (steps + 1); + if (steps < 0) + steps = 2; + else if (steps > 12) + steps = 12; + + cur_step = 1; + dir = 1; + + if (!lock) { + freq = state->frequency; + state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate; + while ((cur_step <= steps) && (!lock)) { + if (dir > 0) + freq += cur_step * car_step; + else + freq -= cur_step * car_step; + + /* Setup tuner */ + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_set_frequency) { + if (state->config->tuner_set_frequency(fe, freq) < 0) + goto err_gateoff; + } + + if (state->config->tuner_set_bandwidth) { + if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + msleep(50); + + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_get_status) { + if (state->config->tuner_get_status(fe, ®) < 0) + goto err_gateoff; + } + + if (reg) + dprintk(FE_DEBUG, 1, "Tuner phase locked"); + else + dprintk(FE_DEBUG, 1, "Tuner unlocked"); + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c); + if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) + goto err; + lock = stv090x_get_dmdlock(state, (timeout_dmd / 3)); + + dir *= -1; + cur_step++; + } + } + } + } + + return lock; + +err_gateoff: + stv090x_i2c_gate_ctrl(state, 0); +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s32 *timeout_sw, s32 *steps) +{ + s32 timeout, inc, steps_max, srate, car_max; + + srate = state->srate; + car_max = state->search_range / 1000; + car_max += car_max / 10; + car_max = 65536 * (car_max / 2); + car_max /= (state->internal->mclk / 1000); + + if (car_max > 0x4000) + car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */ + + inc = srate; + inc /= state->internal->mclk / 1000; + inc *= 256; + inc *= 256; + inc /= 1000; + + switch (state->search_mode) { + case STV090x_SEARCH_DVBS1: + case STV090x_SEARCH_DSS: + inc *= 3; /* freq step = 3% of srate */ + timeout = 20; + break; + + case STV090x_SEARCH_DVBS2: + inc *= 4; + timeout = 25; + break; + + case STV090x_SEARCH_AUTO: + default: + inc *= 3; + timeout = 25; + break; + } + inc /= 100; + if ((inc > car_max) || (inc < 0)) + inc = car_max / 2; /* increment <= 1/8 Mclk */ + + timeout *= 27500; /* 27.5 Msps reference */ + if (srate > 0) + timeout /= (srate / 1000); + + if ((timeout > 100) || (timeout < 0)) + timeout = 100; + + steps_max = (car_max / inc) + 1; /* min steps = 3 */ + if ((steps_max > 100) || (steps_max < 0)) { + steps_max = 100; /* max steps <= 100 */ + inc = car_max / steps_max; + } + *freq_inc = inc; + *timeout_sw = timeout; + *steps = steps_max; + + return 0; +} + +static int stv090x_chk_signal(struct stv090x_state *state) +{ + s32 offst_car, agc2, car_max; + int no_signal; + + offst_car = STV090x_READ_DEMOD(state, CFR2) << 8; + offst_car |= STV090x_READ_DEMOD(state, CFR1); + offst_car = comp2(offst_car, 16); + + agc2 = STV090x_READ_DEMOD(state, AGC2I1) << 8; + agc2 |= STV090x_READ_DEMOD(state, AGC2I0); + car_max = state->search_range / 1000; + + car_max += (car_max / 10); /* 10% margin */ + car_max = (65536 * car_max / 2); + car_max /= state->internal->mclk / 1000; + + if (car_max > 0x4000) + car_max = 0x4000; + + if ((agc2 > 0x2000) || (offst_car > 2 * car_max) || (offst_car < -2 * car_max)) { + no_signal = 1; + dprintk(FE_DEBUG, 1, "No Signal"); + } else { + no_signal = 0; + dprintk(FE_DEBUG, 1, "Found Signal"); + } + + return no_signal; +} + +static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 timeout, int zigzag, s32 steps_max) +{ + int no_signal, lock = 0; + s32 cpt_step = 0, offst_freq, car_max; + u32 reg; + + car_max = state->search_range / 1000; + car_max += (car_max / 10); + car_max = (65536 * car_max / 2); + car_max /= (state->internal->mclk / 1000); + if (car_max > 0x4000) + car_max = 0x4000; + + if (zigzag) + offst_freq = 0; + else + offst_freq = -car_max + inc; + + do { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, ((offst_freq / 256) & 0xff)) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, offst_freq & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, PDELCTRL1); + STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x1); /* stop DVB-S2 packet delin */ + if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) + goto err; + + if (zigzag) { + if (offst_freq >= 0) + offst_freq = -offst_freq - 2 * inc; + else + offst_freq = -offst_freq; + } else { + offst_freq += 2 * inc; + } + + cpt_step++; + + lock = stv090x_get_dmdlock(state, timeout); + no_signal = stv090x_chk_signal(state); + + } while ((!lock) && + (!no_signal) && + ((offst_freq - inc) < car_max) && + ((offst_freq + inc) > -car_max) && + (cpt_step < steps_max)); + + reg = STV090x_READ_DEMOD(state, PDELCTRL1); + STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) + goto err; + + return lock; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_sw_algo(struct stv090x_state *state) +{ + int no_signal, zigzag, lock = 0; + u32 reg; + + s32 dvbs2_fly_wheel; + s32 inc, timeout_step, trials, steps_max; + + /* get params */ + stv090x_get_loop_params(state, &inc, &timeout_step, &steps_max); + + switch (state->search_mode) { + case STV090x_SEARCH_DVBS1: + case STV090x_SEARCH_DSS: + /* accelerate the frequency detector */ + if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x49) < 0) + goto err; + zigzag = 0; + break; + + case STV090x_SEARCH_DVBS2: + if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0) + goto err; + zigzag = 1; + break; + + case STV090x_SEARCH_AUTO: + default: + /* accelerate the frequency detector */ + if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0xc9) < 0) + goto err; + zigzag = 0; + break; + } + + trials = 0; + do { + lock = stv090x_search_car_loop(state, inc, timeout_step, zigzag, steps_max); + no_signal = stv090x_chk_signal(state); + trials++; + + /*run the SW search 2 times maximum*/ + if (lock || no_signal || (trials == 2)) { + /*Check if the demod is not losing lock in DVBS2*/ + if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) + goto err; + } + + reg = STV090x_READ_DEMOD(state, DMDSTATE); + if ((lock) && (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == STV090x_DVBS2)) { + /*Check if the demod is not losing lock in DVBS2*/ + msleep(timeout_step); + reg = STV090x_READ_DEMOD(state, DMDFLYW); + dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD); + if (dvbs2_fly_wheel < 0xd) { /*if correct frames is decrementing */ + msleep(timeout_step); + reg = STV090x_READ_DEMOD(state, DMDFLYW); + dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD); + } + if (dvbs2_fly_wheel < 0xd) { + /*FALSE lock, The demod is losing lock */ + lock = 0; + if (trials < 2) { + if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0) + goto err; + } + } + } + } + } while ((!lock) && (trials < 2) && (!no_signal)); + + return lock; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static enum stv090x_delsys stv090x_get_std(struct stv090x_state *state) +{ + u32 reg; + enum stv090x_delsys delsys; + + reg = STV090x_READ_DEMOD(state, DMDSTATE); + if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 2) + delsys = STV090x_DVBS2; + else if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 3) { + reg = STV090x_READ_DEMOD(state, FECM); + if (STV090x_GETFIELD_Px(reg, DSS_DVB_FIELD) == 1) + delsys = STV090x_DSS; + else + delsys = STV090x_DVBS1; + } else { + delsys = STV090x_ERROR; + } + + return delsys; +} + +/* in Hz */ +static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk) +{ + s32 derot, int_1, int_2, tmp_1, tmp_2; + + derot = STV090x_READ_DEMOD(state, CFR2) << 16; + derot |= STV090x_READ_DEMOD(state, CFR1) << 8; + derot |= STV090x_READ_DEMOD(state, CFR0); + + derot = comp2(derot, 24); + int_1 = mclk >> 12; + int_2 = derot >> 12; + + /* carrier_frequency = MasterClock * Reg / 2^24 */ + tmp_1 = mclk % 0x1000; + tmp_2 = derot % 0x1000; + + derot = (int_1 * int_2) + + ((int_1 * tmp_2) >> 12) + + ((int_2 * tmp_1) >> 12); + + return derot; +} + +static int stv090x_get_viterbi(struct stv090x_state *state) +{ + u32 reg, rate; + + reg = STV090x_READ_DEMOD(state, VITCURPUN); + rate = STV090x_GETFIELD_Px(reg, VIT_CURPUN_FIELD); + + switch (rate) { + case 13: + state->fec = STV090x_PR12; + break; + + case 18: + state->fec = STV090x_PR23; + break; + + case 21: + state->fec = STV090x_PR34; + break; + + case 24: + state->fec = STV090x_PR56; + break; + + case 25: + state->fec = STV090x_PR67; + break; + + case 26: + state->fec = STV090x_PR78; + break; + + default: + state->fec = STV090x_PRERR; + break; + } + + return 0; +} + +static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *state) +{ + struct dvb_frontend *fe = &state->frontend; + + u8 tmg; + u32 reg; + s32 i = 0, offst_freq; + + msleep(5); + + if (state->algo == STV090x_BLIND_SEARCH) { + tmg = STV090x_READ_DEMOD(state, TMGREG2); + STV090x_WRITE_DEMOD(state, SFRSTEP, 0x5c); + while ((i <= 50) && (tmg != 0) && (tmg != 0xff)) { + tmg = STV090x_READ_DEMOD(state, TMGREG2); + msleep(5); + i += 5; + } + } + state->delsys = stv090x_get_std(state); + + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_get_frequency) { + if (state->config->tuner_get_frequency(fe, &state->frequency) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + offst_freq = stv090x_get_car_freq(state, state->internal->mclk) / 1000; + state->frequency += offst_freq; + + if (stv090x_get_viterbi(state) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, DMDMODCOD); + state->modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD); + state->pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01; + state->frame_len = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) >> 1; + reg = STV090x_READ_DEMOD(state, TMGOBS); + state->rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD); + reg = STV090x_READ_DEMOD(state, FECM); + state->inversion = STV090x_GETFIELD_Px(reg, IQINV_FIELD); + + if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) { + + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_get_frequency) { + if (state->config->tuner_get_frequency(fe, &state->frequency) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + if (abs(offst_freq) <= ((state->search_range / 2000) + 500)) + return STV090x_RANGEOK; + else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000)) + return STV090x_RANGEOK; + else + return STV090x_OUTOFRANGE; /* Out of Range */ + } else { + if (abs(offst_freq) <= ((state->search_range / 2000) + 500)) + return STV090x_RANGEOK; + else + return STV090x_OUTOFRANGE; + } + + return STV090x_OUTOFRANGE; + +err_gateoff: + stv090x_i2c_gate_ctrl(state, 0); +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static u32 stv090x_get_tmgoffst(struct stv090x_state *state, u32 srate) +{ + s32 offst_tmg; + + offst_tmg = STV090x_READ_DEMOD(state, TMGREG2) << 16; + offst_tmg |= STV090x_READ_DEMOD(state, TMGREG1) << 8; + offst_tmg |= STV090x_READ_DEMOD(state, TMGREG0); + + offst_tmg = comp2(offst_tmg, 24); /* 2's complement */ + if (!offst_tmg) + offst_tmg = 1; + + offst_tmg = ((s32) srate * 10) / ((s32) 0x1000000 / offst_tmg); + offst_tmg /= 320; + + return offst_tmg; +} + +static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_modcod modcod, s32 pilots) +{ + u8 aclc = 0x29; + s32 i; + struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low; + + if (state->internal->dev_ver == 0x20) { + car_loop = stv090x_s2_crl_cut20; + car_loop_qpsk_low = stv090x_s2_lowqpsk_crl_cut20; + car_loop_apsk_low = stv090x_s2_apsk_crl_cut20; + } else { + /* >= Cut 3 */ + car_loop = stv090x_s2_crl_cut30; + car_loop_qpsk_low = stv090x_s2_lowqpsk_crl_cut30; + car_loop_apsk_low = stv090x_s2_apsk_crl_cut30; + } + + if (modcod < STV090x_QPSK_12) { + i = 0; + while ((i < 3) && (modcod != car_loop_qpsk_low[i].modcod)) + i++; + + if (i >= 3) + i = 2; + + } else { + i = 0; + while ((i < 14) && (modcod != car_loop[i].modcod)) + i++; + + if (i >= 14) { + i = 0; + while ((i < 11) && (modcod != car_loop_apsk_low[i].modcod)) + i++; + + if (i >= 11) + i = 10; + } + } + + if (modcod <= STV090x_QPSK_25) { + if (pilots) { + if (state->srate <= 3000000) + aclc = car_loop_qpsk_low[i].crl_pilots_on_2; + else if (state->srate <= 7000000) + aclc = car_loop_qpsk_low[i].crl_pilots_on_5; + else if (state->srate <= 15000000) + aclc = car_loop_qpsk_low[i].crl_pilots_on_10; + else if (state->srate <= 25000000) + aclc = car_loop_qpsk_low[i].crl_pilots_on_20; + else + aclc = car_loop_qpsk_low[i].crl_pilots_on_30; + } else { + if (state->srate <= 3000000) + aclc = car_loop_qpsk_low[i].crl_pilots_off_2; + else if (state->srate <= 7000000) + aclc = car_loop_qpsk_low[i].crl_pilots_off_5; + else if (state->srate <= 15000000) + aclc = car_loop_qpsk_low[i].crl_pilots_off_10; + else if (state->srate <= 25000000) + aclc = car_loop_qpsk_low[i].crl_pilots_off_20; + else + aclc = car_loop_qpsk_low[i].crl_pilots_off_30; + } + + } else if (modcod <= STV090x_8PSK_910) { + if (pilots) { + if (state->srate <= 3000000) + aclc = car_loop[i].crl_pilots_on_2; + else if (state->srate <= 7000000) + aclc = car_loop[i].crl_pilots_on_5; + else if (state->srate <= 15000000) + aclc = car_loop[i].crl_pilots_on_10; + else if (state->srate <= 25000000) + aclc = car_loop[i].crl_pilots_on_20; + else + aclc = car_loop[i].crl_pilots_on_30; + } else { + if (state->srate <= 3000000) + aclc = car_loop[i].crl_pilots_off_2; + else if (state->srate <= 7000000) + aclc = car_loop[i].crl_pilots_off_5; + else if (state->srate <= 15000000) + aclc = car_loop[i].crl_pilots_off_10; + else if (state->srate <= 25000000) + aclc = car_loop[i].crl_pilots_off_20; + else + aclc = car_loop[i].crl_pilots_off_30; + } + } else { /* 16APSK and 32APSK */ + if (state->srate <= 3000000) + aclc = car_loop_apsk_low[i].crl_pilots_on_2; + else if (state->srate <= 7000000) + aclc = car_loop_apsk_low[i].crl_pilots_on_5; + else if (state->srate <= 15000000) + aclc = car_loop_apsk_low[i].crl_pilots_on_10; + else if (state->srate <= 25000000) + aclc = car_loop_apsk_low[i].crl_pilots_on_20; + else + aclc = car_loop_apsk_low[i].crl_pilots_on_30; + } + + return aclc; +} + +static u8 stv090x_optimize_carloop_short(struct stv090x_state *state) +{ + struct stv090x_short_frame_crloop *short_crl = NULL; + s32 index = 0; + u8 aclc = 0x0b; + + switch (state->modulation) { + case STV090x_QPSK: + default: + index = 0; + break; + case STV090x_8PSK: + index = 1; + break; + case STV090x_16APSK: + index = 2; + break; + case STV090x_32APSK: + index = 3; + break; + } + + if (state->internal->dev_ver >= 0x30) { + /* Cut 3.0 and up */ + short_crl = stv090x_s2_short_crl_cut30; + } else { + /* Cut 2.0 and up: we don't support cuts older than 2.0 */ + short_crl = stv090x_s2_short_crl_cut20; + } + + if (state->srate <= 3000000) + aclc = short_crl[index].crl_2; + else if (state->srate <= 7000000) + aclc = short_crl[index].crl_5; + else if (state->srate <= 15000000) + aclc = short_crl[index].crl_10; + else if (state->srate <= 25000000) + aclc = short_crl[index].crl_20; + else + aclc = short_crl[index].crl_30; + + return aclc; +} + +static int stv090x_optimize_track(struct stv090x_state *state) +{ + struct dvb_frontend *fe = &state->frontend; + + enum stv090x_rolloff rolloff; + enum stv090x_modcod modcod; + + s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0; + u32 reg; + + srate = stv090x_get_srate(state, state->internal->mclk); + srate += stv090x_get_tmgoffst(state, srate); + + switch (state->delsys) { + case STV090x_DVBS1: + case STV090x_DSS: + if (state->search_mode == STV090x_SEARCH_AUTO) { + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + } + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff); + STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x01); + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + + if (state->internal->dev_ver >= 0x30) { + if (stv090x_get_viterbi(state) < 0) + goto err; + + if (state->fec == STV090x_PR12) { + if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x98) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0) + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x18) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0) + goto err; + } + } + + if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0) + goto err; + break; + + case STV090x_DVBS2: + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + if (state->internal->dev_ver >= 0x30) { + if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0) + goto err; + } + if (state->frame_len == STV090x_LONG_FRAME) { + reg = STV090x_READ_DEMOD(state, DMDMODCOD); + modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD); + pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01; + aclc = stv090x_optimize_carloop(state, modcod, pilots); + if (modcod <= STV090x_QPSK_910) { + STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc); + } else if (modcod <= STV090x_8PSK_910) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0) + goto err; + } + if ((state->demod_mode == STV090x_SINGLE) && (modcod > STV090x_8PSK_910)) { + if (modcod <= STV090x_16APSK_910) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0) + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0) + goto err; + } + } + } else { + /*Carrier loop setting for short frame*/ + aclc = stv090x_optimize_carloop_short(state); + if (state->modulation == STV090x_QPSK) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc) < 0) + goto err; + } else if (state->modulation == STV090x_8PSK) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0) + goto err; + } else if (state->modulation == STV090x_16APSK) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0) + goto err; + } else if (state->modulation == STV090x_32APSK) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0) + goto err; + } + } + + STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */ + break; + + case STV090x_ERROR: + default: + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + break; + } + + f_1 = STV090x_READ_DEMOD(state, CFR2); + f_0 = STV090x_READ_DEMOD(state, CFR1); + reg = STV090x_READ_DEMOD(state, TMGOBS); + rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD); + + if (state->algo == STV090x_BLIND_SEARCH) { + STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00); + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) + goto err; + + if (stv090x_set_srate(state, srate) < 0) + goto err; + blind_tune = 1; + + if (stv090x_dvbs_track_crl(state) < 0) + goto err; + } + + if (state->internal->dev_ver >= 0x20) { + if ((state->search_mode == STV090x_SEARCH_DVBS1) || + (state->search_mode == STV090x_SEARCH_DSS) || + (state->search_mode == STV090x_SEARCH_AUTO)) { + + if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x0a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x00) < 0) + goto err; + } + } + + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) + goto err; + + /* AUTO tracking MODE */ + if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x80) < 0) + goto err; + /* AUTO tracking MODE */ + if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0) + goto err; + + if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1) || + (state->srate < 10000000)) { + /* update initial carrier freq with the found freq offset */ + if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0) + goto err; + state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000; + + if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1)) { + + if (state->algo != STV090x_WARM_SEARCH) { + + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_set_bandwidth) { + if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + } + } + if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) + msleep(50); /* blind search: wait 50ms for SR stabilization */ + else + msleep(5); + + stv090x_get_lock_tmg(state); + + if (!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) + goto err; + + i = 0; + + while ((!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) && (i <= 2)) { + + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) + goto err; + i++; + } + } + + } + + if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0) + goto err; + } + + if ((state->delsys == STV090x_DVBS1) || (state->delsys == STV090x_DSS)) + stv090x_set_vit_thtracq(state); + + return 0; + +err_gateoff: + stv090x_i2c_gate_ctrl(state, 0); +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_feclock(struct stv090x_state *state, s32 timeout) +{ + s32 timer = 0, lock = 0, stat; + u32 reg; + + while ((timer < timeout) && (!lock)) { + reg = STV090x_READ_DEMOD(state, DMDSTATE); + stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); + + switch (stat) { + case 0: /* searching */ + case 1: /* first PLH detected */ + default: + lock = 0; + break; + + case 2: /* DVB-S2 mode */ + reg = STV090x_READ_DEMOD(state, PDELSTATUS1); + lock = STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD); + break; + + case 3: /* DVB-S1/legacy mode */ + reg = STV090x_READ_DEMOD(state, VSTATUSVIT); + lock = STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD); + break; + } + if (!lock) { + msleep(10); + timer += 10; + } + } + return lock; +} + +static int stv090x_get_lock(struct stv090x_state *state, s32 timeout_dmd, s32 timeout_fec) +{ + u32 reg; + s32 timer = 0; + int lock; + + lock = stv090x_get_dmdlock(state, timeout_dmd); + if (lock) + lock = stv090x_get_feclock(state, timeout_fec); + + if (lock) { + lock = 0; + + while ((timer < timeout_fec) && (!lock)) { + reg = STV090x_READ_DEMOD(state, TSSTATUS); + lock = STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD); + msleep(1); + timer++; + } + } + + return lock; +} + +static int stv090x_set_s2rolloff(struct stv090x_state *state) +{ + u32 reg; + + if (state->internal->dev_ver <= 0x20) { + /* rolloff to auto mode if DVBS2 */ + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + } else { + /* DVB-S2 rolloff to auto mode if DVBS2 */ + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + + +static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state) +{ + struct dvb_frontend *fe = &state->frontend; + enum stv090x_signal_state signal_state = STV090x_NOCARRIER; + u32 reg; + s32 agc1_power, power_iq = 0, i; + int lock = 0, low_sr = 0, no_signal = 0; + + reg = STV090x_READ_DEMOD(state, TSCFGH); + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */ + if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */ + goto err; + + if (state->internal->dev_ver >= 0x20) { + if (state->srate > 5000000) { + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x82) < 0) + goto err; + } + } + + stv090x_get_lock_tmg(state); + + if (state->algo == STV090x_BLIND_SEARCH) { + state->tuner_bw = 2 * 36000000; /* wide bw for unknown srate */ + if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) /* wider srate scan */ + goto err; + if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0) + goto err; + if (stv090x_set_srate(state, 1000000) < 0) /* initial srate = 1Msps */ + goto err; + } else { + /* known srate */ + if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0) + goto err; + + if (state->srate < 2000000) { + /* SR < 2MSPS */ + if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x63) < 0) + goto err; + } else { + /* SR >= 2Msps */ + if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) + goto err; + + if (state->internal->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0) + goto err; + if (state->algo == STV090x_COLD_SEARCH) + state->tuner_bw = (15 * (stv090x_car_width(state->srate, state->rolloff) + 10000000)) / 10; + else if (state->algo == STV090x_WARM_SEARCH) + state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + 10000000; + } + + /* if cold start or warm (Symbolrate is known) + * use a Narrow symbol rate scan range + */ + if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) /* narrow srate scan */ + goto err; + + if (stv090x_set_srate(state, state->srate) < 0) + goto err; + + if (stv090x_set_max_srate(state, state->internal->mclk, + state->srate) < 0) + goto err; + if (stv090x_set_min_srate(state, state->internal->mclk, + state->srate) < 0) + goto err; + + if (state->srate >= 10000000) + low_sr = 0; + else + low_sr = 1; + } + + /* Setup tuner */ + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_set_bbgain) { + reg = state->config->tuner_bbgain; + if (reg == 0) + reg = 10; /* default: 10dB */ + if (state->config->tuner_set_bbgain(fe, reg) < 0) + goto err_gateoff; + } + + if (state->config->tuner_set_frequency) { + if (state->config->tuner_set_frequency(fe, state->frequency) < 0) + goto err_gateoff; + } + + if (state->config->tuner_set_bandwidth) { + if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + msleep(50); + + if (state->config->tuner_get_status) { + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + if (state->config->tuner_get_status(fe, ®) < 0) + goto err_gateoff; + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + if (reg) + dprintk(FE_DEBUG, 1, "Tuner phase locked"); + else { + dprintk(FE_DEBUG, 1, "Tuner unlocked"); + return STV090x_NOCARRIER; + } + } + + msleep(10); + agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1), + STV090x_READ_DEMOD(state, AGCIQIN0)); + + if (agc1_power == 0) { + /* If AGC1 integrator value is 0 + * then read POWERI, POWERQ + */ + for (i = 0; i < 5; i++) { + power_iq += (STV090x_READ_DEMOD(state, POWERI) + + STV090x_READ_DEMOD(state, POWERQ)) >> 1; + } + power_iq /= 5; + } + + if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) { + dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq); + lock = 0; + signal_state = STV090x_NOAGC1; + } else { + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion); + + if (state->internal->dev_ver <= 0x20) { + /* rolloff to auto mode if DVBS2 */ + STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1); + } else { + /* DVB-S2 rolloff to auto mode if DVBS2 */ + STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 1); + } + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + + if (stv090x_delivery_search(state) < 0) + goto err; + + if (state->algo != STV090x_BLIND_SEARCH) { + if (stv090x_start_search(state) < 0) + goto err; + } + } + + if (signal_state == STV090x_NOAGC1) + return signal_state; + + if (state->algo == STV090x_BLIND_SEARCH) + lock = stv090x_blind_search(state); + + else if (state->algo == STV090x_COLD_SEARCH) + lock = stv090x_get_coldlock(state, state->DemodTimeout); + + else if (state->algo == STV090x_WARM_SEARCH) + lock = stv090x_get_dmdlock(state, state->DemodTimeout); + + if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) { + if (!low_sr) { + if (stv090x_chk_tmg(state)) + lock = stv090x_sw_algo(state); + } + } + + if (lock) + signal_state = stv090x_get_sig_params(state); + + if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */ + stv090x_optimize_track(state); + + if (state->internal->dev_ver >= 0x20) { + /* >= Cut 2.0 :release TS reset after + * demod lock and optimized Tracking + */ + reg = STV090x_READ_DEMOD(state, TSCFGH); + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */ + if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) + goto err; + + msleep(3); + + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* merger reset */ + if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) + goto err; + + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */ + if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) + goto err; + } + + lock = stv090x_get_lock(state, state->FecTimeout, + state->FecTimeout); + if (lock) { + if (state->delsys == STV090x_DVBS2) { + stv090x_set_s2rolloff(state); + + reg = STV090x_READ_DEMOD(state, PDELCTRL2); + STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 1); + if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0) + goto err; + /* Reset DVBS2 packet delinator error counter */ + reg = STV090x_READ_DEMOD(state, PDELCTRL2); + STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 0); + if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */ + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0) + goto err; + } + /* Reset the Total packet counter */ + if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0x00) < 0) + goto err; + /* Reset the packet Error counter2 */ + if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0) + goto err; + } else { + signal_state = STV090x_NODATA; + no_signal = stv090x_chk_signal(state); + } + } + return signal_state; + +err_gateoff: + stv090x_i2c_gate_ctrl(state, 0); +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stv090x_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *props = &fe->dtv_property_cache; + + if (p->frequency == 0) + return DVBFE_ALGO_SEARCH_INVALID; + + state->delsys = props->delivery_system; + state->frequency = p->frequency; + state->srate = p->u.qpsk.symbol_rate; + state->search_mode = STV090x_SEARCH_AUTO; + state->algo = STV090x_COLD_SEARCH; + state->fec = STV090x_PRERR; + if (state->srate > 10000000) { + dprintk(FE_DEBUG, 1, "Search range: 10 MHz"); + state->search_range = 10000000; + } else { + dprintk(FE_DEBUG, 1, "Search range: 5 MHz"); + state->search_range = 5000000; + } + + if (stv090x_algo(state) == STV090x_RANGEOK) { + dprintk(FE_DEBUG, 1, "Search success!"); + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + dprintk(FE_DEBUG, 1, "Search failed!"); + return DVBFE_ALGO_SEARCH_FAILED; + } + + return DVBFE_ALGO_SEARCH_ERROR; +} + +static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + u8 search_state; + + reg = STV090x_READ_DEMOD(state, DMDSTATE); + search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); + + switch (search_state) { + case 0: /* searching */ + case 1: /* first PLH detected */ + default: + dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)"); + *status = 0; + break; + + case 2: /* DVB-S2 mode */ + dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2"); + reg = STV090x_READ_DEMOD(state, DSTATUS); + if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) { + reg = STV090x_READ_DEMOD(state, PDELSTATUS1); + if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) { + reg = STV090x_READ_DEMOD(state, TSSTATUS); + if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) { + *status = FE_HAS_SIGNAL | + FE_HAS_CARRIER | + FE_HAS_VITERBI | + FE_HAS_SYNC | + FE_HAS_LOCK; + } + } + } + break; + + case 3: /* DVB-S1/legacy mode */ + dprintk(FE_DEBUG, 1, "Delivery system: DVB-S"); + reg = STV090x_READ_DEMOD(state, DSTATUS); + if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) { + reg = STV090x_READ_DEMOD(state, VSTATUSVIT); + if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) { + reg = STV090x_READ_DEMOD(state, TSSTATUS); + if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) { + *status = FE_HAS_SIGNAL | + FE_HAS_CARRIER | + FE_HAS_VITERBI | + FE_HAS_SYNC | + FE_HAS_LOCK; + } + } + } + break; + } + + return 0; +} + +static int stv090x_read_per(struct dvb_frontend *fe, u32 *per) +{ + struct stv090x_state *state = fe->demodulator_priv; + + s32 count_4, count_3, count_2, count_1, count_0, count; + u32 reg, h, m, l; + enum fe_status status; + + stv090x_read_status(fe, &status); + if (!(status & FE_HAS_LOCK)) { + *per = 1 << 23; /* Max PER */ + } else { + /* Counter 2 */ + reg = STV090x_READ_DEMOD(state, ERRCNT22); + h = STV090x_GETFIELD_Px(reg, ERR_CNT2_FIELD); + + reg = STV090x_READ_DEMOD(state, ERRCNT21); + m = STV090x_GETFIELD_Px(reg, ERR_CNT21_FIELD); + + reg = STV090x_READ_DEMOD(state, ERRCNT20); + l = STV090x_GETFIELD_Px(reg, ERR_CNT20_FIELD); + + *per = ((h << 16) | (m << 8) | l); + + count_4 = STV090x_READ_DEMOD(state, FBERCPT4); + count_3 = STV090x_READ_DEMOD(state, FBERCPT3); + count_2 = STV090x_READ_DEMOD(state, FBERCPT2); + count_1 = STV090x_READ_DEMOD(state, FBERCPT1); + count_0 = STV090x_READ_DEMOD(state, FBERCPT0); + + if ((!count_4) && (!count_3)) { + count = (count_2 & 0xff) << 16; + count |= (count_1 & 0xff) << 8; + count |= count_0 & 0xff; + } else { + count = 1 << 24; + } + if (count == 0) + *per = 1; + } + if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val) +{ + int res = 0; + int min = 0, med; + + if ((val >= tab[min].read && val < tab[max].read) || + (val >= tab[max].read && val < tab[min].read)) { + while ((max - min) > 1) { + med = (max + min) / 2; + if ((val >= tab[min].read && val < tab[med].read) || + (val >= tab[med].read && val < tab[min].read)) + max = med; + else + min = med; + } + res = ((val - tab[min].read) * + (tab[max].real - tab[min].real) / + (tab[max].read - tab[min].read)) + + tab[min].real; + } else { + if (tab[min].read < tab[max].read) { + if (val < tab[min].read) + res = tab[min].real; + else if (val >= tab[max].read) + res = tab[max].real; + } else { + if (val >= tab[min].read) + res = tab[min].real; + else if (val < tab[max].read) + res = tab[max].real; + } + } + + return res; +} + +static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + s32 agc_0, agc_1, agc; + s32 str; + + reg = STV090x_READ_DEMOD(state, AGCIQIN1); + agc_1 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD); + reg = STV090x_READ_DEMOD(state, AGCIQIN0); + agc_0 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD); + agc = MAKEWORD16(agc_1, agc_0); + + str = stv090x_table_lookup(stv090x_rf_tab, + ARRAY_SIZE(stv090x_rf_tab) - 1, agc); + if (agc > stv090x_rf_tab[0].read) + str = 0; + else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read) + str = -100; + *strength = (str + 100) * 0xFFFF / 100; + + return 0; +} + +static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg_0, reg_1, reg, i; + s32 val_0, val_1, val = 0; + u8 lock_f; + s32 div; + u32 last; + + switch (state->delsys) { + case STV090x_DVBS2: + reg = STV090x_READ_DEMOD(state, DSTATUS); + lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD); + if (lock_f) { + msleep(5); + for (i = 0; i < 16; i++) { + reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1); + val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD); + reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0); + val_0 = STV090x_GETFIELD_Px(reg_0, NOSPLHT_NORMED_FIELD); + val += MAKEWORD16(val_1, val_0); + msleep(1); + } + val /= 16; + last = ARRAY_SIZE(stv090x_s2cn_tab) - 1; + div = stv090x_s2cn_tab[0].read - + stv090x_s2cn_tab[last].read; + *cnr = 0xFFFF - ((val * 0xFFFF) / div); + } + break; + + case STV090x_DVBS1: + case STV090x_DSS: + reg = STV090x_READ_DEMOD(state, DSTATUS); + lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD); + if (lock_f) { + msleep(5); + for (i = 0; i < 16; i++) { + reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1); + val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD); + reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0); + val_0 = STV090x_GETFIELD_Px(reg_0, NOSDATAT_UNNORMED_FIELD); + val += MAKEWORD16(val_1, val_0); + msleep(1); + } + val /= 16; + last = ARRAY_SIZE(stv090x_s1cn_tab) - 1; + div = stv090x_s1cn_tab[0].read - + stv090x_s1cn_tab[last].read; + *cnr = 0xFFFF - ((val * 0xFFFF) / div); + } + break; + default: + break; + } + + return 0; +} + +static int stv090x_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + + reg = STV090x_READ_DEMOD(state, DISTXCTL); + switch (tone) { + case SEC_TONE_ON: + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + break; + + case SEC_TONE_OFF: + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + break; + default: + return -EINVAL; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + + +static enum dvbfe_algo stv090x_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg, idle = 0, fifo_full = 1; + int i; + + reg = STV090x_READ_DEMOD(state, DISTXCTL); + + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, + (state->config->diseqc_envelope_mode) ? 4 : 2); + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + for (i = 0; i < cmd->msg_len; i++) { + + while (fifo_full) { + reg = STV090x_READ_DEMOD(state, DISTXSTATUS); + fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD); + } + + if (STV090x_WRITE_DEMOD(state, DISTXDATA, cmd->msg[i]) < 0) + goto err; + } + reg = STV090x_READ_DEMOD(state, DISTXCTL); + STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + i = 0; + + while ((!idle) && (i < 10)) { + reg = STV090x_READ_DEMOD(state, DISTXSTATUS); + idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD); + msleep(10); + i++; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg, idle = 0, fifo_full = 1; + u8 mode, value; + int i; + + reg = STV090x_READ_DEMOD(state, DISTXCTL); + + if (burst == SEC_MINI_A) { + mode = (state->config->diseqc_envelope_mode) ? 5 : 3; + value = 0x00; + } else { + mode = (state->config->diseqc_envelope_mode) ? 4 : 2; + value = 0xFF; + } + + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, mode); + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + while (fifo_full) { + reg = STV090x_READ_DEMOD(state, DISTXSTATUS); + fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD); + } + + if (STV090x_WRITE_DEMOD(state, DISTXDATA, value) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, DISTXCTL); + STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + i = 0; + + while ((!idle) && (i < 10)) { + reg = STV090x_READ_DEMOD(state, DISTXSTATUS); + idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD); + msleep(10); + i++; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg = 0, i = 0, rx_end = 0; + + while ((rx_end != 1) && (i < 10)) { + msleep(10); + i++; + reg = STV090x_READ_DEMOD(state, DISRX_ST0); + rx_end = STV090x_GETFIELD_Px(reg, RX_END_FIELD); + } + + if (rx_end) { + reply->msg_len = STV090x_GETFIELD_Px(reg, FIFO_BYTENBR_FIELD); + for (i = 0; i < reply->msg_len; i++) + reply->msg[i] = STV090x_READ_DEMOD(state, DISRXDATA); + } + + return 0; +} + +static int stv090x_sleep(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + u8 full_standby = 0; + + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (state->config->tuner_sleep) { + if (state->config->tuner_sleep(fe) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + dprintk(FE_DEBUG, 1, "Set %s(%d) to sleep", + state->device == STV0900 ? "STV0900" : "STV0903", + state->demod); + + mutex_lock(&state->internal->demod_lock); + + switch (state->demod) { + case STV090x_DEMODULATOR_0: + /* power off ADC 1 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR1); + STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0); + if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) + goto err; + /* power off DiSEqC 1 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR2); + STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 0); + if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0) + goto err; + + /* check whether path 2 is already sleeping, that is when + ADC2 is off */ + reg = stv090x_read_reg(state, STV090x_TSTTNR3); + if (STV090x_GETFIELD(reg, ADC2_PON_FIELD) == 0) + full_standby = 1; + + /* stop clocks */ + reg = stv090x_read_reg(state, STV090x_STOPCLK1); + /* packet delineator 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 1); + /* ADC 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 1); + /* FEC clock is shared between the two paths, only stop it + when full standby is possible */ + if (full_standby) + STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1); + if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + /* sampling 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 1); + /* viterbi 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 1); + /* TS clock is shared between the two paths, only stop it + when full standby is possible */ + if (full_standby) + STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + break; + + case STV090x_DEMODULATOR_1: + /* power off ADC 2 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR3); + STV090x_SETFIELD(reg, ADC2_PON_FIELD, 0); + if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0) + goto err; + /* power off DiSEqC 2 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR4); + STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 0); + if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0) + goto err; + + /* check whether path 1 is already sleeping, that is when + ADC1 is off */ + reg = stv090x_read_reg(state, STV090x_TSTTNR1); + if (STV090x_GETFIELD(reg, ADC1_PON_FIELD) == 0) + full_standby = 1; + + /* stop clocks */ + reg = stv090x_read_reg(state, STV090x_STOPCLK1); + /* packet delineator 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 1); + /* ADC 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 1); + /* FEC clock is shared between the two paths, only stop it + when full standby is possible */ + if (full_standby) + STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1); + if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + /* sampling 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 1); + /* viterbi 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 1); + /* TS clock is shared between the two paths, only stop it + when full standby is possible */ + if (full_standby) + STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + break; + + default: + dprintk(FE_ERROR, 1, "Wrong demodulator!"); + break; + } + + if (full_standby) { + /* general power off */ + reg = stv090x_read_reg(state, STV090x_SYNTCTRL); + STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) + goto err; + } + + mutex_unlock(&state->internal->demod_lock); + return 0; + +err_gateoff: + stv090x_i2c_gate_ctrl(state, 0); +err: + mutex_unlock(&state->internal->demod_lock); + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_wakeup(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + + dprintk(FE_DEBUG, 1, "Wake %s(%d) from standby", + state->device == STV0900 ? "STV0900" : "STV0903", + state->demod); + + mutex_lock(&state->internal->demod_lock); + + /* general power on */ + reg = stv090x_read_reg(state, STV090x_SYNTCTRL); + STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) + goto err; + + switch (state->demod) { + case STV090x_DEMODULATOR_0: + /* power on ADC 1 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR1); + STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1); + if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) + goto err; + /* power on DiSEqC 1 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR2); + STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 1); + if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0) + goto err; + + /* activate clocks */ + reg = stv090x_read_reg(state, STV090x_STOPCLK1); + /* packet delineator 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 0); + /* ADC 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 0); + /* FEC clock */ + STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0); + if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + /* sampling 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 0); + /* viterbi 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 0); + /* TS clock */ + STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + break; + + case STV090x_DEMODULATOR_1: + /* power on ADC 2 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR3); + STV090x_SETFIELD(reg, ADC2_PON_FIELD, 1); + if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0) + goto err; + /* power on DiSEqC 2 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR4); + STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 1); + if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0) + goto err; + + /* activate clocks */ + reg = stv090x_read_reg(state, STV090x_STOPCLK1); + /* packet delineator 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 0); + /* ADC 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 0); + /* FEC clock */ + STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0); + if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + /* sampling 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 0); + /* viterbi 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 0); + /* TS clock */ + STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + break; + + default: + dprintk(FE_ERROR, 1, "Wrong demodulator!"); + break; + } + + mutex_unlock(&state->internal->demod_lock); + return 0; +err: + mutex_unlock(&state->internal->demod_lock); + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static void stv090x_release(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + + state->internal->num_used--; + if (state->internal->num_used <= 0) { + + dprintk(FE_ERROR, 1, "Actually removing"); + + remove_dev(state->internal); + kfree(state->internal); + } + + kfree(state); +} + +static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc_mode) +{ + u32 reg = 0; + + reg = stv090x_read_reg(state, STV090x_GENCFG); + + switch (ldpc_mode) { + case STV090x_DUAL: + default: + if ((state->demod_mode != STV090x_DUAL) || (STV090x_GETFIELD(reg, DDEMOD_FIELD) != 1)) { + /* set LDPC to dual mode */ + if (stv090x_write_reg(state, STV090x_GENCFG, 0x1d) < 0) + goto err; + + state->demod_mode = STV090x_DUAL; + + reg = stv090x_read_reg(state, STV090x_TSTRES0); + STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1); + if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) + goto err; + STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0); + if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0) + goto err; + } + break; + + case STV090x_SINGLE: + if (stv090x_stop_modcod(state) < 0) + goto err; + if (stv090x_activate_modcod_single(state) < 0) + goto err; + + if (state->demod == STV090x_DEMODULATOR_1) { + if (stv090x_write_reg(state, STV090x_GENCFG, 0x06) < 0) /* path 2 */ + goto err; + } else { + if (stv090x_write_reg(state, STV090x_GENCFG, 0x04) < 0) /* path 1 */ + goto err; + } + + reg = stv090x_read_reg(state, STV090x_TSTRES0); + STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1); + if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) + goto err; + STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0); + if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, PDELCTRL1); + STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x01); + if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) + goto err; + break; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +/* return (Hz), clk in Hz*/ +static u32 stv090x_get_mclk(struct stv090x_state *state) +{ + const struct stv090x_config *config = state->config; + u32 div, reg; + u8 ratio; + + div = stv090x_read_reg(state, STV090x_NCOARSE); + reg = stv090x_read_reg(state, STV090x_SYNTCTRL); + ratio = STV090x_GETFIELD(reg, SELX1RATIO_FIELD) ? 4 : 6; + + return (div + 1) * config->xtal / ratio; /* kHz */ +} + +static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk) +{ + const struct stv090x_config *config = state->config; + u32 reg, div, clk_sel; + + reg = stv090x_read_reg(state, STV090x_SYNTCTRL); + clk_sel = ((STV090x_GETFIELD(reg, SELX1RATIO_FIELD) == 1) ? 4 : 6); + + div = ((clk_sel * mclk) / config->xtal) - 1; + + reg = stv090x_read_reg(state, STV090x_NCOARSE); + STV090x_SETFIELD(reg, M_DIV_FIELD, div); + if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0) + goto err; + + state->internal->mclk = stv090x_get_mclk(state); + + /*Set the DiseqC frequency to 22KHz */ + div = state->internal->mclk / 704000; + if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_tspath(struct stv090x_state *state) +{ + u32 reg; + + if (state->internal->dev_ver >= 0x20) { + switch (state->config->ts1_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + switch (state->config->ts2_mode) { + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + stv090x_write_reg(state, STV090x_TSGENERAL, 0x00); + break; + + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x06) < 0) /* Mux'd stream mode */ + goto err; + reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); + if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_P2_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); + if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0) + goto err; + break; + } + break; + + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + switch (state->config->ts2_mode) { + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0) + goto err; + break; + + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0a) < 0) + goto err; + break; + } + break; + } + } else { + switch (state->config->ts1_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + switch (state->config->ts2_mode) { + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10); + break; + + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x16); + reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); + if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 0); + if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0) + goto err; + break; + } + break; + + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + switch (state->config->ts2_mode) { + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14); + break; + + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x12); + break; + } + break; + } + } + + switch (state->config->ts1_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_DVBCI: + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_SERIAL_PUNCTURED: + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_SERIAL_CONTINUOUS: + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + break; + + default: + break; + } + + switch (state->config->ts2_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_DVBCI: + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_SERIAL_PUNCTURED: + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_SERIAL_CONTINUOUS: + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + break; + + default: + break; + } + + if (state->config->ts1_clk > 0) { + u32 speed; + + switch (state->config->ts1_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + default: + speed = state->internal->mclk / + (state->config->ts1_clk / 4); + if (speed < 0x08) + speed = 0x08; + if (speed > 0xFF) + speed = 0xFF; + break; + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + speed = state->internal->mclk / + (state->config->ts1_clk / 32); + if (speed < 0x20) + speed = 0x20; + if (speed > 0xFF) + speed = 0xFF; + break; + } + reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); + if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P1_TSSPEED, speed) < 0) + goto err; + } + + if (state->config->ts2_clk > 0) { + u32 speed; + + switch (state->config->ts2_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + default: + speed = state->internal->mclk / + (state->config->ts2_clk / 4); + if (speed < 0x08) + speed = 0x08; + if (speed > 0xFF) + speed = 0xFF; + break; + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + speed = state->internal->mclk / + (state->config->ts2_clk / 32); + if (speed < 0x20) + speed = 0x20; + if (speed > 0xFF) + speed = 0xFF; + break; + } + reg = stv090x_read_reg(state, STV090x_P2_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); + if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P2_TSSPEED, speed) < 0) + goto err; + } + + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_init(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + const struct stv090x_config *config = state->config; + u32 reg; + + if (state->internal->mclk == 0) { + /* call tuner init to configure the tuner's clock output + divider directly before setting up the master clock of + the stv090x. */ + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (config->tuner_init) { + if (config->tuner_init(fe) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */ + msleep(5); + if (stv090x_write_reg(state, STV090x_SYNTCTRL, + 0x20 | config->clk_mode) < 0) + goto err; + stv090x_get_mclk(state); + } + + if (stv090x_wakeup(fe) < 0) { + dprintk(FE_ERROR, 1, "Error waking device"); + goto err; + } + + if (stv090x_ldpc_mode(state, state->demod_mode) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, TNRCFG2); + STV090x_SETFIELD_Px(reg, TUN_IQSWAP_FIELD, state->inversion); + if (STV090x_WRITE_DEMOD(state, TNRCFG2, reg) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff); + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + + if (stv090x_i2c_gate_ctrl(state, 1) < 0) + goto err; + + if (config->tuner_set_mode) { + if (config->tuner_set_mode(fe, TUNER_WAKE) < 0) + goto err_gateoff; + } + + if (config->tuner_init) { + if (config->tuner_init(fe) < 0) + goto err_gateoff; + } + + if (stv090x_i2c_gate_ctrl(state, 0) < 0) + goto err; + + if (stv090x_set_tspath(state) < 0) + goto err; + + return 0; + +err_gateoff: + stv090x_i2c_gate_ctrl(state, 0); +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_setup(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + const struct stv090x_config *config = state->config; + const struct stv090x_reg *stv090x_initval = NULL; + const struct stv090x_reg *stv090x_cut20_val = NULL; + unsigned long t1_size = 0, t2_size = 0; + u32 reg = 0; + + int i; + + if (state->device == STV0900) { + dprintk(FE_DEBUG, 1, "Initializing STV0900"); + stv090x_initval = stv0900_initval; + t1_size = ARRAY_SIZE(stv0900_initval); + stv090x_cut20_val = stv0900_cut20_val; + t2_size = ARRAY_SIZE(stv0900_cut20_val); + } else if (state->device == STV0903) { + dprintk(FE_DEBUG, 1, "Initializing STV0903"); + stv090x_initval = stv0903_initval; + t1_size = ARRAY_SIZE(stv0903_initval); + stv090x_cut20_val = stv0903_cut20_val; + t2_size = ARRAY_SIZE(stv0903_cut20_val); + } + + /* STV090x init */ + + /* Stop Demod */ + if (stv090x_write_reg(state, STV090x_P1_DMDISTATE, 0x5c) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0) + goto err; + + msleep(5); + + /* Set No Tuner Mode */ + if (stv090x_write_reg(state, STV090x_P1_TNRCFG, 0x6c) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0) + goto err; + + /* I2C repeater OFF */ + STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level); + if (stv090x_write_reg(state, STV090x_P1_I2CRPT, reg) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0) + goto err; + + if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */ + goto err; + msleep(5); + if (stv090x_write_reg(state, STV090x_I2CCFG, 0x08) < 0) /* 1/41 oversampling */ + goto err; + if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0) /* enable PLL */ + goto err; + msleep(5); + + /* write initval */ + dprintk(FE_DEBUG, 1, "Setting up initial values"); + for (i = 0; i < t1_size; i++) { + if (stv090x_write_reg(state, stv090x_initval[i].addr, stv090x_initval[i].data) < 0) + goto err; + } + + state->internal->dev_ver = stv090x_read_reg(state, STV090x_MID); + if (state->internal->dev_ver >= 0x20) { + if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0) + goto err; + + /* write cut20_val*/ + dprintk(FE_DEBUG, 1, "Setting up Cut 2.0 initial values"); + for (i = 0; i < t2_size; i++) { + if (stv090x_write_reg(state, stv090x_cut20_val[i].addr, stv090x_cut20_val[i].data) < 0) + goto err; + } + + } else if (state->internal->dev_ver < 0x20) { + dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!", + state->internal->dev_ver); + + goto err; + } else if (state->internal->dev_ver > 0x30) { + /* we shouldn't bail out from here */ + dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!", + state->internal->dev_ver); + } + + /* ADC1 range */ + reg = stv090x_read_reg(state, STV090x_TSTTNR1); + STV090x_SETFIELD(reg, ADC1_INMODE_FIELD, + (config->adc1_range == STV090x_ADC_1Vpp) ? 0 : 1); + if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) + goto err; + + /* ADC2 range */ + reg = stv090x_read_reg(state, STV090x_TSTTNR3); + STV090x_SETFIELD(reg, ADC2_INMODE_FIELD, + (config->adc2_range == STV090x_ADC_1Vpp) ? 0 : 1); + if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0) + goto err; + + if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, + u8 xor_value) +{ + struct stv090x_state *state = fe->demodulator_priv; + u8 reg = 0; + + STV090x_SETFIELD(reg, GPIOx_OPD_FIELD, dir); + STV090x_SETFIELD(reg, GPIOx_CONFIG_FIELD, value); + STV090x_SETFIELD(reg, GPIOx_XOR_FIELD, xor_value); + + return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg); +} +EXPORT_SYMBOL(stv090x_set_gpio); + +static struct dvb_frontend_ops stv090x_ops = { + + .info = { + .name = "STV090x Multistandard", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 0, + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_2G_MODULATION + }, + + .release = stv090x_release, + .init = stv090x_init, + + .sleep = stv090x_sleep, + .get_frontend_algo = stv090x_frontend_algo, + + .diseqc_send_master_cmd = stv090x_send_diseqc_msg, + .diseqc_send_burst = stv090x_send_diseqc_burst, + .diseqc_recv_slave_reply = stv090x_recv_slave_reply, + .set_tone = stv090x_set_tone, + + .search = stv090x_search, + .read_status = stv090x_read_status, + .read_ber = stv090x_read_per, + .read_signal_strength = stv090x_read_signal_strength, + .read_snr = stv090x_read_cnr +}; + + +struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, + struct i2c_adapter *i2c, + enum stv090x_demodulator demod) +{ + struct stv090x_state *state = NULL; + struct stv090x_dev *temp_int; + + state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->verbose = &verbose; + state->config = config; + state->i2c = i2c; + state->frontend.ops = stv090x_ops; + state->frontend.demodulator_priv = state; + state->demod = demod; + state->demod_mode = config->demod_mode; /* Single or Dual mode */ + state->device = config->device; + state->rolloff = STV090x_RO_35; /* default */ + + temp_int = find_dev(state->i2c, + state->config->address); + + if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) { + state->internal = temp_int->internal; + state->internal->num_used++; + dprintk(FE_INFO, 1, "Found Internal Structure!"); + } else { + state->internal = kmalloc(sizeof(struct stv090x_internal), + GFP_KERNEL); + if (!state->internal) + goto error; + temp_int = append_internal(state->internal); + if (!temp_int) { + kfree(state->internal); + goto error; + } + state->internal->num_used = 1; + state->internal->mclk = 0; + state->internal->dev_ver = 0; + state->internal->i2c_adap = state->i2c; + state->internal->i2c_addr = state->config->address; + dprintk(FE_INFO, 1, "Create New Internal Structure!"); + + mutex_init(&state->internal->demod_lock); + mutex_init(&state->internal->tuner_lock); + + if (stv090x_setup(&state->frontend) < 0) { + dprintk(FE_ERROR, 1, "Error setting up device"); + goto err_remove; + } + } + + /* workaround for stuck DiSEqC output */ + if (config->diseqc_envelope_mode) + stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A); + + dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x", + state->device == STV0900 ? "STV0900" : "STV0903", + demod, + state->internal->dev_ver); + + return &state->frontend; + +err_remove: + remove_dev(state->internal); + kfree(state->internal); +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stv090x_attach); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,134 @@ +/* + STV0900/0903 Multistandard Broadcast Frontend driver + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STV090x_H +#define __STV090x_H + +enum stv090x_demodulator { + STV090x_DEMODULATOR_0 = 1, + STV090x_DEMODULATOR_1 +}; + +enum stv090x_device { + STV0903 = 0, + STV0900, +}; + +enum stv090x_mode { + STV090x_DUAL = 0, + STV090x_SINGLE +}; + +enum stv090x_tsmode { + STV090x_TSMODE_SERIAL_PUNCTURED = 1, + STV090x_TSMODE_SERIAL_CONTINUOUS, + STV090x_TSMODE_PARALLEL_PUNCTURED, + STV090x_TSMODE_DVBCI +}; + +enum stv090x_clkmode { + STV090x_CLK_INT = 0, /* Clk i/p = CLKI */ + STV090x_CLK_EXT = 2 /* Clk i/p = XTALI */ +}; + +enum stv090x_i2crpt { + STV090x_RPTLEVEL_256 = 0, + STV090x_RPTLEVEL_128 = 1, + STV090x_RPTLEVEL_64 = 2, + STV090x_RPTLEVEL_32 = 3, + STV090x_RPTLEVEL_16 = 4, + STV090x_RPTLEVEL_8 = 5, + STV090x_RPTLEVEL_4 = 6, + STV090x_RPTLEVEL_2 = 7, +}; + +enum stv090x_adc_range { + STV090x_ADC_2Vpp = 0, + STV090x_ADC_1Vpp = 1 +}; + +struct stv090x_config { + enum stv090x_device device; + enum stv090x_mode demod_mode; + enum stv090x_clkmode clk_mode; + + u32 xtal; /* default: 8000000 */ + u8 address; /* default: 0x68 */ + + u8 ts1_mode; + u8 ts2_mode; + u32 ts1_clk; + u32 ts2_clk; + + u8 ts1_tei : 1; + u8 ts2_tei : 1; + + enum stv090x_i2crpt repeater_level; + + u8 tuner_bbgain; /* default: 10db */ + enum stv090x_adc_range adc1_range; /* default: 2Vpp */ + enum stv090x_adc_range adc2_range; /* default: 2Vpp */ + + bool diseqc_envelope_mode; + + int (*tuner_init) (struct dvb_frontend *fe); + int (*tuner_sleep) (struct dvb_frontend *fe); + int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); + int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); + int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency); + int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth); + int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth); + int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain); + int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain); + int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk); + int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status); + void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock); +}; + +#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, + struct i2c_adapter *i2c, + enum stv090x_demodulator demod); + +/* dir = 0 -> output, dir = 1 -> input/open-drain */ +extern int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, + u8 dir, u8 value, u8 xor_value); + +#else + +static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, + struct i2c_adapter *i2c, + enum stv090x_demodulator demod) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, + u8 opd, u8 value, u8 xor_value) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +#endif /* CONFIG_DVB_STV090x */ + +#endif /* __STV090x_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,279 @@ +/* + STV0900/0903 Multistandard Broadcast Frontend driver + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STV090x_PRIV_H +#define __STV090x_PRIV_H + +#include "dvb_frontend.h" + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 +#define FE_DEBUGREG 4 + +#define dprintk(__y, __z, format, arg...) do { \ + if (__z) { \ + if ((verbose > FE_ERROR) && (verbose > __y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_NOTICE) && (verbose > __y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_INFO) && (verbose > __y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_DEBUG) && (verbose > __y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (verbose > __y) \ + printk(format, ##arg); \ + } \ +} while (0) + +#define STV090x_READ_DEMOD(__state, __reg) (( \ + (__state)->demod == STV090x_DEMODULATOR_1) ? \ + stv090x_read_reg(__state, STV090x_P2_##__reg) : \ + stv090x_read_reg(__state, STV090x_P1_##__reg)) + +#define STV090x_WRITE_DEMOD(__state, __reg, __data) (( \ + (__state)->demod == STV090x_DEMODULATOR_1) ? \ + stv090x_write_reg(__state, STV090x_P2_##__reg, __data) :\ + stv090x_write_reg(__state, STV090x_P1_##__reg, __data)) + +#define STV090x_ADDR_OFFST(__state, __x) (( \ + (__state->demod) == STV090x_DEMODULATOR_1) ? \ + STV090x_P1_##__x : \ + STV090x_P2_##__x) + + +#define STV090x_SETFIELD(mask, bitf, val) (mask = (mask & (~(((1 << STV090x_WIDTH_##bitf) - 1) <<\ + STV090x_OFFST_##bitf))) | \ + (val << STV090x_OFFST_##bitf)) + +#define STV090x_GETFIELD(val, bitf) ((val >> STV090x_OFFST_##bitf) & ((1 << STV090x_WIDTH_##bitf) - 1)) + + +#define STV090x_SETFIELD_Px(mask, bitf, val) (mask = (mask & (~(((1 << STV090x_WIDTH_Px_##bitf) - 1) <<\ + STV090x_OFFST_Px_##bitf))) | \ + (val << STV090x_OFFST_Px_##bitf)) + +#define STV090x_GETFIELD_Px(val, bitf) ((val >> STV090x_OFFST_Px_##bitf) & ((1 << STV090x_WIDTH_Px_##bitf) - 1)) + +#define MAKEWORD16(__a, __b) (((__a) << 8) | (__b)) + +#define MSB(__x) ((__x >> 8) & 0xff) +#define LSB(__x) (__x & 0xff) + + +#define STV090x_IQPOWER_THRESHOLD 30 +#define STV090x_SEARCH_AGC2_TH_CUT20 700 +#define STV090x_SEARCH_AGC2_TH_CUT30 1400 + +#define STV090x_SEARCH_AGC2_TH(__ver) \ + ((__ver <= 0x20) ? \ + STV090x_SEARCH_AGC2_TH_CUT20 : \ + STV090x_SEARCH_AGC2_TH_CUT30) + +enum stv090x_signal_state { + STV090x_NOAGC1, + STV090x_NOCARRIER, + STV090x_NODATA, + STV090x_DATAOK, + STV090x_RANGEOK, + STV090x_OUTOFRANGE +}; + +enum stv090x_fec { + STV090x_PR12 = 0, + STV090x_PR23, + STV090x_PR34, + STV090x_PR45, + STV090x_PR56, + STV090x_PR67, + STV090x_PR78, + STV090x_PR89, + STV090x_PR910, + STV090x_PRERR +}; + +enum stv090x_modulation { + STV090x_QPSK, + STV090x_8PSK, + STV090x_16APSK, + STV090x_32APSK, + STV090x_UNKNOWN +}; + +enum stv090x_frame { + STV090x_LONG_FRAME, + STV090x_SHORT_FRAME +}; + +enum stv090x_pilot { + STV090x_PILOTS_OFF, + STV090x_PILOTS_ON +}; + +enum stv090x_rolloff { + STV090x_RO_35, + STV090x_RO_25, + STV090x_RO_20 +}; + +enum stv090x_inversion { + STV090x_IQ_AUTO, + STV090x_IQ_NORMAL, + STV090x_IQ_SWAP +}; + +enum stv090x_modcod { + STV090x_DUMMY_PLF = 0, + STV090x_QPSK_14, + STV090x_QPSK_13, + STV090x_QPSK_25, + STV090x_QPSK_12, + STV090x_QPSK_35, + STV090x_QPSK_23, + STV090x_QPSK_34, + STV090x_QPSK_45, + STV090x_QPSK_56, + STV090x_QPSK_89, + STV090x_QPSK_910, + STV090x_8PSK_35, + STV090x_8PSK_23, + STV090x_8PSK_34, + STV090x_8PSK_56, + STV090x_8PSK_89, + STV090x_8PSK_910, + STV090x_16APSK_23, + STV090x_16APSK_34, + STV090x_16APSK_45, + STV090x_16APSK_56, + STV090x_16APSK_89, + STV090x_16APSK_910, + STV090x_32APSK_34, + STV090x_32APSK_45, + STV090x_32APSK_56, + STV090x_32APSK_89, + STV090x_32APSK_910, + STV090x_MODCODE_UNKNOWN +}; + +enum stv090x_search { + STV090x_SEARCH_DSS = 0, + STV090x_SEARCH_DVBS1, + STV090x_SEARCH_DVBS2, + STV090x_SEARCH_AUTO +}; + +enum stv090x_algo { + STV090x_BLIND_SEARCH, + STV090x_COLD_SEARCH, + STV090x_WARM_SEARCH +}; + +enum stv090x_delsys { + STV090x_ERROR = 0, + STV090x_DVBS1 = 1, + STV090x_DVBS2, + STV090x_DSS +}; + +struct stv090x_long_frame_crloop { + enum stv090x_modcod modcod; + + u8 crl_pilots_on_2; + u8 crl_pilots_off_2; + u8 crl_pilots_on_5; + u8 crl_pilots_off_5; + u8 crl_pilots_on_10; + u8 crl_pilots_off_10; + u8 crl_pilots_on_20; + u8 crl_pilots_off_20; + u8 crl_pilots_on_30; + u8 crl_pilots_off_30; +}; + +struct stv090x_short_frame_crloop { + enum stv090x_modulation modulation; + + u8 crl_2; /* SR < 3M */ + u8 crl_5; /* 3 < SR <= 7M */ + u8 crl_10; /* 7 < SR <= 15M */ + u8 crl_20; /* 10 < SR <= 25M */ + u8 crl_30; /* 10 < SR <= 45M */ +}; + +struct stv090x_reg { + u16 addr; + u8 data; +}; + +struct stv090x_tab { + s32 real; + s32 read; +}; + +struct stv090x_internal { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + + struct mutex demod_lock; /* Lock access to shared register */ + struct mutex tuner_lock; /* Lock access to tuners */ + s32 mclk; /* Masterclock Divider factor */ + u32 dev_ver; + + int num_used; +}; + +struct stv090x_state { + enum stv090x_device device; + enum stv090x_demodulator demod; + enum stv090x_mode demod_mode; + struct stv090x_internal *internal; + + struct i2c_adapter *i2c; + const struct stv090x_config *config; + struct dvb_frontend frontend; + + u32 *verbose; /* Cached module verbosity */ + + enum stv090x_delsys delsys; + enum stv090x_fec fec; + enum stv090x_modulation modulation; + enum stv090x_modcod modcod; + enum stv090x_search search_mode; + enum stv090x_frame frame_len; + enum stv090x_pilot pilots; + enum stv090x_rolloff rolloff; + enum stv090x_inversion inversion; + enum stv090x_algo algo; + + u32 frequency; + u32 srate; + + s32 tuner_bw; + + s32 search_range; + + s32 DemodTimeout; + s32 FecTimeout; +}; + +#endif /* __STV090x_PRIV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x_reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv090x_reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,2371 @@ +/* + STV0900/0903 Multistandard Broadcast Frontend driver + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STV090x_REG_H +#define __STV090x_REG_H + +#define STV090x_MID 0xf100 +#define STV090x_OFFST_MCHIP_IDENT_FIELD 4 +#define STV090x_WIDTH_MCHIP_IDENT_FIELD 4 +#define STV090x_OFFST_MRELEASE_FIELD 0 +#define STV090x_WIDTH_MRELEASE_FIELD 4 + +#define STV090x_DACR1 0xf113 +#define STV090x_OFFST_DACR1_MODE_FIELD 5 +#define STV090x_WIDTH_DACR1_MODE_FIELD 3 +#define STV090x_OFFST_DACR1_VALUE_FIELD 0 +#define STV090x_WIDTH_DACR1_VALUE_FIELD 4 + +#define STV090x_DACR2 0xf114 +#define STV090x_OFFST_DACR2_VALUE_FIELD 0 +#define STV090x_WIDTH_DACR2_VALUE_FIELD 8 + +#define STV090x_OUTCFG 0xf11c +#define STV090x_OFFST_OUTSERRS1_HZ_FIELD 6 +#define STV090x_WIDTH_OUTSERRS1_HZ_FIELD 1 +#define STV090x_OFFST_OUTSERRS2_HZ_FIELD 5 +#define STV090x_WIDTH_OUTSERRS2_HZ_FIELD 1 +#define STV090x_OFFST_OUTSERRS3_HZ_FIELD 4 +#define STV090x_WIDTH_OUTSERRS3_HZ_FIELD 1 +#define STV090x_OFFST_OUTPARRS3_HZ_FIELD 3 +#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD 1 + +#define STV090x_MODECFG 0xf11d + +#define STV090x_IRQSTATUS3 0xf120 +#define STV090x_OFFST_SPLL_LOCK_FIELD 5 +#define STV090x_WIDTH_SPLL_LOCK_FIELD 1 +#define STV090x_OFFST_SSTREAM_LCK_3_FIELD 4 +#define STV090x_WIDTH_SSTREAM_LCK_3_FIELD 1 +#define STV090x_OFFST_SSTREAM_LCK_2_FIELD 3 +#define STV090x_WIDTH_SSTREAM_LCK_2_FIELD 1 +#define STV090x_OFFST_SSTREAM_LCK_1_FIELD 2 +#define STV090x_WIDTH_SSTREAM_LCK_1_FIELD 1 +#define STV090x_OFFST_SDVBS1_PRF_2_FIELD 1 +#define STV090x_WIDTH_SDVBS1_PRF_2_FIELD 1 +#define STV090x_OFFST_SDVBS1_PRF_1_FIELD 0 +#define STV090x_WIDTH_SDVBS1_PRF_1_FIELD 1 + +#define STV090x_IRQSTATUS2 0xf121 +#define STV090x_OFFST_SSPY_ENDSIM_3_FIELD 7 +#define STV090x_WIDTH_SSPY_ENDSIM_3_FIELD 1 +#define STV090x_OFFST_SSPY_ENDSIM_2_FIELD 6 +#define STV090x_WIDTH_SSPY_ENDSIM_2_FIELD 1 +#define STV090x_OFFST_SSPY_ENDSIM_1_FIELD 5 +#define STV090x_WIDTH_SSPY_ENDSIM_1_FIELD 1 +#define STV090x_OFFST_SPKTDEL_ERROR_2_FIELD 4 +#define STV090x_WIDTH_SPKTDEL_ERROR_2_FIELD 1 +#define STV090x_OFFST_SPKTDEL_LOCKB_2_FIELD 3 +#define STV090x_WIDTH_SPKTDEL_LOCKB_2_FIELD 1 +#define STV090x_OFFST_SPKTDEL_LOCK_2_FIELD 2 +#define STV090x_WIDTH_SPKTDEL_LOCK_2_FIELD 1 +#define STV090x_OFFST_SPKTDEL_ERROR_1_FIELD 1 +#define STV090x_WIDTH_SPKTDEL_ERROR_1_FIELD 1 +#define STV090x_OFFST_SPKTDEL_LOCKB_1_FIELD 0 +#define STV090x_WIDTH_SPKTDEL_LOCKB_1_FIELD 1 + +#define STV090x_IRQSTATUS1 0xf122 +#define STV090x_OFFST_SPKTDEL_LOCK_1_FIELD 7 +#define STV090x_WIDTH_SPKTDEL_LOCK_1_FIELD 1 +#define STV090x_OFFST_SDEMOD_LOCKB_2_FIELD 2 +#define STV090x_WIDTH_SDEMOD_LOCKB_2_FIELD 1 +#define STV090x_OFFST_SDEMOD_LOCK_2_FIELD 1 +#define STV090x_WIDTH_SDEMOD_LOCK_2_FIELD 1 +#define STV090x_OFFST_SDEMOD_IRQ_2_FIELD 0 +#define STV090x_WIDTH_SDEMOD_IRQ_2_FIELD 1 + +#define STV090x_IRQSTATUS0 0xf123 +#define STV090x_OFFST_SDEMOD_LOCKB_1_FIELD 7 +#define STV090x_WIDTH_SDEMOD_LOCKB_1_FIELD 1 +#define STV090x_OFFST_SDEMOD_LOCK_1_FIELD 6 +#define STV090x_WIDTH_SDEMOD_LOCK_1_FIELD 1 +#define STV090x_OFFST_SDEMOD_IRQ_1_FIELD 5 +#define STV090x_WIDTH_SDEMOD_IRQ_1_FIELD 1 +#define STV090x_OFFST_SBCH_ERRFLAG_FIELD 4 +#define STV090x_WIDTH_SBCH_ERRFLAG_FIELD 1 +#define STV090x_OFFST_SDISEQC2RX_IRQ_FIELD 3 +#define STV090x_WIDTH_SDISEQC2RX_IRQ_FIELD 1 +#define STV090x_OFFST_SDISEQC2TX_IRQ_FIELD 2 +#define STV090x_WIDTH_SDISEQC2TX_IRQ_FIELD 1 +#define STV090x_OFFST_SDISEQC1RX_IRQ_FIELD 1 +#define STV090x_WIDTH_SDISEQC1RX_IRQ_FIELD 1 +#define STV090x_OFFST_SDISEQC1TX_IRQ_FIELD 0 +#define STV090x_WIDTH_SDISEQC1TX_IRQ_FIELD 1 + +#define STV090x_IRQMASK3 0xf124 +#define STV090x_OFFST_MPLL_LOCK_FIELD 5 +#define STV090x_WIDTH_MPLL_LOCK_FIELD 1 +#define STV090x_OFFST_MSTREAM_LCK_3_FIELD 4 +#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD 1 +#define STV090x_OFFST_MSTREAM_LCK_2_FIELD 3 +#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD 1 +#define STV090x_OFFST_MSTREAM_LCK_1_FIELD 2 +#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD 1 +#define STV090x_OFFST_MDVBS1_PRF_2_FIELD 1 +#define STV090x_WIDTH_MDVBS1_PRF_2_FIELD 1 +#define STV090x_OFFST_MDVBS1_PRF_1_FIELD 0 +#define STV090x_WIDTH_MDVBS1_PRF_1_FIELD 1 + +#define STV090x_IRQMASK2 0xf125 +#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD 7 +#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD 1 +#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD 6 +#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD 1 +#define STV090x_OFFST_MSPY_ENDSIM_1_FIELD 5 +#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD 1 +#define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD 4 +#define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD 1 +#define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD 3 +#define STV090x_WIDTH_MPKTDEL_LOCKB_2_FIELD 1 +#define STV090x_OFFST_MPKTDEL_LOCK_2_FIELD 2 +#define STV090x_WIDTH_MPKTDEL_LOCK_2_FIELD 1 +#define STV090x_OFFST_MPKTDEL_ERROR_1_FIELD 1 +#define STV090x_WIDTH_MPKTDEL_ERROR_1_FIELD 1 +#define STV090x_OFFST_MPKTDEL_LOCKB_1_FIELD 0 +#define STV090x_WIDTH_MPKTDEL_LOCKB_1_FIELD 1 + +#define STV090x_IRQMASK1 0xf126 +#define STV090x_OFFST_MPKTDEL_LOCK_1_FIELD 7 +#define STV090x_WIDTH_MPKTDEL_LOCK_1_FIELD 1 +#define STV090x_OFFST_MEXTPINB2_FIELD 6 +#define STV090x_WIDTH_MEXTPINB2_FIELD 1 +#define STV090x_OFFST_MEXTPIN2_FIELD 5 +#define STV090x_WIDTH_MEXTPIN2_FIELD 1 +#define STV090x_OFFST_MEXTPINB1_FIELD 4 +#define STV090x_WIDTH_MEXTPINB1_FIELD 1 +#define STV090x_OFFST_MEXTPIN1_FIELD 3 +#define STV090x_WIDTH_MEXTPIN1_FIELD 1 +#define STV090x_OFFST_MDEMOD_LOCKB_2_FIELD 2 +#define STV090x_WIDTH_MDEMOD_LOCKB_2_FIELD 1 +#define STV090x_OFFST_MDEMOD_LOCK_2_FIELD 1 +#define STV090x_WIDTH_MDEMOD_LOCK_2_FIELD 1 +#define STV090x_OFFST_MDEMOD_IRQ_2_FIELD 0 +#define STV090x_WIDTH_MDEMOD_IRQ_2_FIELD 1 + +#define STV090x_IRQMASK0 0xf127 +#define STV090x_OFFST_MDEMOD_LOCKB_1_FIELD 7 +#define STV090x_WIDTH_MDEMOD_LOCKB_1_FIELD 1 +#define STV090x_OFFST_MDEMOD_LOCK_1_FIELD 6 +#define STV090x_WIDTH_MDEMOD_LOCK_1_FIELD 1 +#define STV090x_OFFST_MDEMOD_IRQ_1_FIELD 5 +#define STV090x_WIDTH_MDEMOD_IRQ_1_FIELD 1 +#define STV090x_OFFST_MBCH_ERRFLAG_FIELD 4 +#define STV090x_WIDTH_MBCH_ERRFLAG_FIELD 1 +#define STV090x_OFFST_MDISEQC2RX_IRQ_FIELD 3 +#define STV090x_WIDTH_MDISEQC2RX_IRQ_FIELD 1 +#define STV090x_OFFST_MDISEQC2TX_IRQ_FIELD 2 +#define STV090x_WIDTH_MDISEQC2TX_IRQ_FIELD 1 +#define STV090x_OFFST_MDISEQC1RX_IRQ_FIELD 1 +#define STV090x_WIDTH_MDISEQC1RX_IRQ_FIELD 1 +#define STV090x_OFFST_MDISEQC1TX_IRQ_FIELD 0 +#define STV090x_WIDTH_MDISEQC1TX_IRQ_FIELD 1 + +#define STV090x_I2CCFG 0xf129 +#define STV090x_OFFST_12C_FASTMODE_FIELD 3 +#define STV090x_WIDTH_12C_FASTMODE_FIELD 1 +#define STV090x_OFFST_12CADDR_INC_FIELD 0 +#define STV090x_WIDTH_12CADDR_INC_FIELD 2 + +#define STV090x_Px_I2CRPT(__x) (0xf12a + (__x - 1) * 0x1) +#define STV090x_P1_I2CRPT STV090x_Px_I2CRPT(1) +#define STV090x_P2_I2CRPT STV090x_Px_I2CRPT(2) +#define STV090x_OFFST_Px_I2CT_ON_FIELD 7 +#define STV090x_WIDTH_Px_I2CT_ON_FIELD 1 +#define STV090x_OFFST_Px_ENARPT_LEVEL_FIELD 4 +#define STV090x_WIDTH_Px_ENARPT_LEVEL_FIELD 3 +#define STV090x_OFFST_Px_SCLT_DELAY_FIELD 3 +#define STV090x_WIDTH_Px_SCLT_DELAY_FIELD 1 +#define STV090x_OFFST_Px_STOP_ENABLE_FIELD 2 +#define STV090x_WIDTH_Px_STOP_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_STOP_SDAT2SDA_FIELD 1 +#define STV090x_WIDTH_Px_STOP_SDAT2SDA_FIELD 1 + +#define STV090x_CLKI2CFG 0xf140 +#define STV090x_OFFST_CLKI2_OPD_FIELD 7 +#define STV090x_WIDTH_CLKI2_OPD_FIELD 1 +#define STV090x_OFFST_CLKI2_CONFIG_FIELD 1 +#define STV090x_WIDTH_CLKI2_CONFIG_FIELD 6 +#define STV090x_OFFST_CLKI2_XOR_FIELD 0 +#define STV090x_WIDTH_CLKI2_XOR_FIELD 1 + +#define STV090x_GPIOxCFG(__x) (0xf141 + (__x - 1)) +#define STV090x_GPIO1CFG STV090x_GPIOxCFG(1) +#define STV090x_GPIO2CFG STV090x_GPIOxCFG(2) +#define STV090x_GPIO3CFG STV090x_GPIOxCFG(3) +#define STV090x_GPIO4CFG STV090x_GPIOxCFG(4) +#define STV090x_GPIO5CFG STV090x_GPIOxCFG(5) +#define STV090x_GPIO6CFG STV090x_GPIOxCFG(6) +#define STV090x_GPIO7CFG STV090x_GPIOxCFG(7) +#define STV090x_GPIO8CFG STV090x_GPIOxCFG(8) +#define STV090x_GPIO9CFG STV090x_GPIOxCFG(9) +#define STV090x_GPIO10CFG STV090x_GPIOxCFG(10) +#define STV090x_GPIO11CFG STV090x_GPIOxCFG(11) +#define STV090x_GPIO12CFG STV090x_GPIOxCFG(12) +#define STV090x_GPIO13CFG STV090x_GPIOxCFG(13) +#define STV090x_OFFST_GPIOx_OPD_FIELD 7 +#define STV090x_WIDTH_GPIOx_OPD_FIELD 1 +#define STV090x_OFFST_GPIOx_CONFIG_FIELD 1 +#define STV090x_WIDTH_GPIOx_CONFIG_FIELD 6 +#define STV090x_OFFST_GPIOx_XOR_FIELD 0 +#define STV090x_WIDTH_GPIOx_XOR_FIELD 1 + +#define STV090x_CSxCFG(__x) (0xf14e + __x * 0x1) +#define STV090x_CS0CFG STV090x_CSxCFG(0) +#define STV090x_CS1CFG STV090x_CSxCFG(1) +#define STV090x_OFFST_CSX_OPD_FIELD 7 +#define STV090x_WIDTH_CSX_OPD_FIELD 1 +#define STV090x_OFFST_CSX_CONFIG_FIELD 1 +#define STV090x_WIDTH_CSX_CONFIG_FIELD 6 +#define STV090x_OFFST_CSX_XOR_FIELD 0 +#define STV090x_WIDTH_CSX_XOR_FIELD 1 + + +#define STV090x_STDBYCFG 0xf150 +#define STV090x_OFFST_STDBY_OPD_FIELD 7 +#define STV090x_WIDTH_STDBY_OPD_FIELD 1 +#define STV090x_OFFST_STDBY_CONFIG_FIELD 1 +#define STV090x_WIDTH_STDBY_CONFIG_FIELD 6 +#define STV090x_OFFST_STDBY_XOR_FIELD 0 +#define STV090x_WIDTH_STDBY_XOR_FIELD 1 + +#define STV090x_DIRCLKCFG 0xf151 +#define STV090x_OFFST_DIRCLK_OPD_FIELD 7 +#define STV090x_WIDTH_DIRCLK_OPD_FIELD 1 +#define STV090x_OFFST_DIRCLK_CONFIG_FIELD 1 +#define STV090x_WIDTH_DIRCLK_CONFIG_FIELD 6 +#define STV090x_OFFST_DIRCLK_XOR_FIELD 0 +#define STV090x_WIDTH_DIRCLK_XOR_FIELD 1 + + +#define STV090x_AGCRFxCFG(__x) (0xf152 + (__x - 1) * 0x4) +#define STV090x_AGCRF1CFG STV090x_AGCRFxCFG(1) +#define STV090x_AGCRF2CFG STV090x_AGCRFxCFG(2) +#define STV090x_OFFST_AGCRFx_OPD_FIELD 7 +#define STV090x_WIDTH_AGCRFx_OPD_FIELD 1 +#define STV090x_OFFST_AGCRFx_CONFIG_FIELD 1 +#define STV090x_WIDTH_AGCRFx_CONFIG_FIELD 6 +#define STV090x_OFFST_AGCRFx_XOR_FIELD 0 +#define STV090x_WIDTH_AGCRFx_XOR_FIELD 1 + +#define STV090x_SDATxCFG(__x) (0xf153 + (__x - 1) * 0x4) +#define STV090x_SDAT1CFG STV090x_SDATxCFG(1) +#define STV090x_SDAT2CFG STV090x_SDATxCFG(2) +#define STV090x_OFFST_SDATx_OPD_FIELD 7 +#define STV090x_WIDTH_SDATx_OPD_FIELD 1 +#define STV090x_OFFST_SDATx_CONFIG_FIELD 1 +#define STV090x_WIDTH_SDATx_CONFIG_FIELD 6 +#define STV090x_OFFST_SDATx_XOR_FIELD 0 +#define STV090x_WIDTH_SDATx_XOR_FIELD 1 + +#define STV090x_SCLTxCFG(__x) (0xf154 + (__x - 1) * 0x4) +#define STV090x_SCLT1CFG STV090x_SCLTxCFG(1) +#define STV090x_SCLT2CFG STV090x_SCLTxCFG(2) +#define STV090x_OFFST_SCLTx_OPD_FIELD 7 +#define STV090x_WIDTH_SCLTx_OPD_FIELD 1 +#define STV090x_OFFST_SCLTx_CONFIG_FIELD 1 +#define STV090x_WIDTH_SCLTx_CONFIG_FIELD 6 +#define STV090x_OFFST_SCLTx_XOR_FIELD 0 +#define STV090x_WIDTH_SCLTx_XOR_FIELD 1 + +#define STV090x_DISEQCOxCFG(__x) (0xf155 + (__x - 1) * 0x4) +#define STV090x_DISEQCO1CFG STV090x_DISEQCOxCFG(1) +#define STV090x_DISEQCO2CFG STV090x_DISEQCOxCFG(2) +#define STV090x_OFFST_DISEQCOx_OPD_FIELD 7 +#define STV090x_WIDTH_DISEQCOx_OPD_FIELD 1 +#define STV090x_OFFST_DISEQCOx_CONFIG_FIELD 1 +#define STV090x_WIDTH_DISEQCOx_CONFIG_FIELD 6 +#define STV090x_OFFST_DISEQCOx_XOR_FIELD 0 +#define STV090x_WIDTH_DISEQCOx_XOR_FIELD 1 + +#define STV090x_CLKOUT27CFG 0xf15a +#define STV090x_OFFST_CLKOUT27_OPD_FIELD 7 +#define STV090x_WIDTH_CLKOUT27_OPD_FIELD 1 +#define STV090x_OFFST_CLKOUT27_CONFIG_FIELD 1 +#define STV090x_WIDTH_CLKOUT27_CONFIG_FIELD 6 +#define STV090x_OFFST_CLKOUT27_XOR_FIELD 0 +#define STV090x_WIDTH_CLKOUT27_XOR_FIELD 1 + +#define STV090x_ERRORxCFG(__x) (0xf15b + (__x - 1) * 0x5) +#define STV090x_ERROR1CFG STV090x_ERRORxCFG(1) +#define STV090x_ERROR2CFG STV090x_ERRORxCFG(2) +#define STV090x_ERROR3CFG STV090x_ERRORxCFG(3) +#define STV090x_OFFST_ERRORx_OPD_FIELD 7 +#define STV090x_WIDTH_ERRORx_OPD_FIELD 1 +#define STV090x_OFFST_ERRORx_CONFIG_FIELD 1 +#define STV090x_WIDTH_ERRORx_CONFIG_FIELD 6 +#define STV090x_OFFST_ERRORx_XOR_FIELD 0 +#define STV090x_WIDTH_ERRORx_XOR_FIELD 1 + +#define STV090x_DPNxCFG(__x) (0xf15c + (__x - 1) * 0x5) +#define STV090x_DPN1CFG STV090x_DPNxCFG(1) +#define STV090x_DPN2CFG STV090x_DPNxCFG(2) +#define STV090x_DPN3CFG STV090x_DPNxCFG(3) +#define STV090x_OFFST_DPNx_OPD_FIELD 7 +#define STV090x_WIDTH_DPNx_OPD_FIELD 1 +#define STV090x_OFFST_DPNx_CONFIG_FIELD 1 +#define STV090x_WIDTH_DPNx_CONFIG_FIELD 6 +#define STV090x_OFFST_DPNx_XOR_FIELD 0 +#define STV090x_WIDTH_DPNx_XOR_FIELD 1 + +#define STV090x_STROUTxCFG(__x) (0xf15d + (__x - 1) * 0x5) +#define STV090x_STROUT1CFG STV090x_STROUTxCFG(1) +#define STV090x_STROUT2CFG STV090x_STROUTxCFG(2) +#define STV090x_STROUT3CFG STV090x_STROUTxCFG(3) +#define STV090x_OFFST_STROUTx_OPD_FIELD 7 +#define STV090x_WIDTH_STROUTx_OPD_FIELD 1 +#define STV090x_OFFST_STROUTx_CONFIG_FIELD 1 +#define STV090x_WIDTH_STROUTx_CONFIG_FIELD 6 +#define STV090x_OFFST_STROUTx_XOR_FIELD 0 +#define STV090x_WIDTH_STROUTx_XOR_FIELD 1 + +#define STV090x_CLKOUTxCFG(__x) (0xf15e + (__x - 1) * 0x5) +#define STV090x_CLKOUT1CFG STV090x_CLKOUTxCFG(1) +#define STV090x_CLKOUT2CFG STV090x_CLKOUTxCFG(2) +#define STV090x_CLKOUT3CFG STV090x_CLKOUTxCFG(3) +#define STV090x_OFFST_CLKOUTx_OPD_FIELD 7 +#define STV090x_WIDTH_CLKOUTx_OPD_FIELD 1 +#define STV090x_OFFST_CLKOUTx_CONFIG_FIELD 1 +#define STV090x_WIDTH_CLKOUTx_CONFIG_FIELD 6 +#define STV090x_OFFST_CLKOUTx_XOR_FIELD 0 +#define STV090x_WIDTH_CLKOUTx_XOR_FIELD 1 + +#define STV090x_DATAxCFG(__x) (0xf15f + (__x - 71) * 0x5) +#define STV090x_DATA71CFG STV090x_DATAxCFG(71) +#define STV090x_DATA72CFG STV090x_DATAxCFG(72) +#define STV090x_DATA73CFG STV090x_DATAxCFG(73) +#define STV090x_OFFST_DATAx_OPD_FIELD 7 +#define STV090x_WIDTH_DATAx_OPD_FIELD 1 +#define STV090x_OFFST_DATAx_CONFIG_FIELD 1 +#define STV090x_WIDTH_DATAx_CONFIG_FIELD 6 +#define STV090x_OFFST_DATAx_XOR_FIELD 0 +#define STV090x_WIDTH_DATAx_XOR_FIELD 1 + +#define STV090x_NCOARSE 0xf1b3 +#define STV090x_OFFST_M_DIV_FIELD 0 +#define STV090x_WIDTH_M_DIV_FIELD 8 + +#define STV090x_SYNTCTRL 0xf1b6 +#define STV090x_OFFST_STANDBY_FIELD 7 +#define STV090x_WIDTH_STANDBY_FIELD 1 +#define STV090x_OFFST_BYPASSPLLCORE_FIELD 6 +#define STV090x_WIDTH_BYPASSPLLCORE_FIELD 1 +#define STV090x_OFFST_SELX1RATIO_FIELD 5 +#define STV090x_WIDTH_SELX1RATIO_FIELD 1 +#define STV090x_OFFST_STOP_PLL_FIELD 3 +#define STV090x_WIDTH_STOP_PLL_FIELD 1 +#define STV090x_OFFST_BYPASSPLLFSK_FIELD 2 +#define STV090x_WIDTH_BYPASSPLLFSK_FIELD 1 +#define STV090x_OFFST_SELOSCI_FIELD 1 +#define STV090x_WIDTH_SELOSCI_FIELD 1 +#define STV090x_OFFST_BYPASSPLLADC_FIELD 0 +#define STV090x_WIDTH_BYPASSPLLADC_FIELD 1 + +#define STV090x_FILTCTRL 0xf1b7 +#define STV090x_OFFST_INV_CLK135_FIELD 7 +#define STV090x_WIDTH_INV_CLK135_FIELD 1 +#define STV090x_OFFST_SEL_FSKCKDIV_FIELD 2 +#define STV090x_WIDTH_SEL_FSKCKDIV_FIELD 1 +#define STV090x_OFFST_INV_CLKFSK_FIELD 1 +#define STV090x_WIDTH_INV_CLKFSK_FIELD 1 +#define STV090x_OFFST_BYPASS_APPLI_FIELD 0 +#define STV090x_WIDTH_BYPASS_APPLI_FIELD 1 + +#define STV090x_PLLSTAT 0xf1b8 +#define STV090x_OFFST_PLLLOCK_FIELD 0 +#define STV090x_WIDTH_PLLLOCK_FIELD 1 + +#define STV090x_STOPCLK1 0xf1c2 +#define STV090x_OFFST_STOP_CLKPKDT2_FIELD 6 +#define STV090x_WIDTH_STOP_CLKPKDT2_FIELD 1 +#define STV090x_OFFST_STOP_CLKPKDT1_FIELD 5 +#define STV090x_WIDTH_STOP_CLKPKDT1_FIELD 1 +#define STV090x_OFFST_STOP_CLKFEC_FIELD 4 +#define STV090x_WIDTH_STOP_CLKFEC_FIELD 1 +#define STV090x_OFFST_STOP_CLKADCI2_FIELD 3 +#define STV090x_WIDTH_STOP_CLKADCI2_FIELD 1 +#define STV090x_OFFST_INV_CLKADCI2_FIELD 2 +#define STV090x_WIDTH_INV_CLKADCI2_FIELD 1 +#define STV090x_OFFST_STOP_CLKADCI1_FIELD 1 +#define STV090x_WIDTH_STOP_CLKADCI1_FIELD 1 +#define STV090x_OFFST_INV_CLKADCI1_FIELD 0 +#define STV090x_WIDTH_INV_CLKADCI1_FIELD 1 + +#define STV090x_STOPCLK2 0xf1c3 +#define STV090x_OFFST_STOP_CLKSAMP2_FIELD 4 +#define STV090x_WIDTH_STOP_CLKSAMP2_FIELD 1 +#define STV090x_OFFST_STOP_CLKSAMP1_FIELD 3 +#define STV090x_WIDTH_STOP_CLKSAMP1_FIELD 1 +#define STV090x_OFFST_STOP_CLKVIT2_FIELD 2 +#define STV090x_WIDTH_STOP_CLKVIT2_FIELD 1 +#define STV090x_OFFST_STOP_CLKVIT1_FIELD 1 +#define STV090x_WIDTH_STOP_CLKVIT1_FIELD 1 +#define STV090x_OFFST_STOP_CLKTS_FIELD 0 +#define STV090x_WIDTH_STOP_CLKTS_FIELD 1 + +#define STV090x_TSTTNR0 0xf1df +#define STV090x_OFFST_SEL_FSK_FIELD 7 +#define STV090x_WIDTH_SEL_FSK_FIELD 1 +#define STV090x_OFFST_FSK_PON_FIELD 2 +#define STV090x_WIDTH_FSK_PON_FIELD 1 + +#define STV090x_TSTTNR1 0xf1e0 +#define STV090x_OFFST_ADC1_PON_FIELD 1 +#define STV090x_WIDTH_ADC1_PON_FIELD 1 +#define STV090x_OFFST_ADC1_INMODE_FIELD 0 +#define STV090x_WIDTH_ADC1_INMODE_FIELD 1 + +#define STV090x_TSTTNR2 0xf1e1 +#define STV090x_OFFST_DISEQC1_PON_FIELD 5 +#define STV090x_WIDTH_DISEQC1_PON_FIELD 1 + +#define STV090x_TSTTNR3 0xf1e2 +#define STV090x_OFFST_ADC2_PON_FIELD 1 +#define STV090x_WIDTH_ADC2_PON_FIELD 1 +#define STV090x_OFFST_ADC2_INMODE_FIELD 0 +#define STV090x_WIDTH_ADC2_INMODE_FIELD 1 + +#define STV090x_TSTTNR4 0xf1e3 +#define STV090x_OFFST_DISEQC2_PON_FIELD 5 +#define STV090x_WIDTH_DISEQC2_PON_FIELD 1 + +#define STV090x_FSKTFC2 0xf170 +#define STV090x_OFFST_FSKT_KMOD_FIELD 2 +#define STV090x_WIDTH_FSKT_KMOD_FIELD 6 +#define STV090x_OFFST_FSKT_CAR_FIELD 0 +#define STV090x_WIDTH_FSKT_CAR_FIELD 2 + +#define STV090x_FSKTFC1 0xf171 +#define STV090x_OFFST_FSKTC1_CAR_FIELD 0 +#define STV090x_WIDTH_FSKTC1_CAR_FIELD 8 + +#define STV090x_FSKTFC0 0xf172 +#define STV090x_OFFST_FSKTC0_CAR_FIELD 0 +#define STV090x_WIDTH_FSKTC0_CAR_FIELD 8 + +#define STV090x_FSKTDELTAF1 0xf173 +#define STV090x_OFFST_FSKTF1_DELTAF_FIELD 0 +#define STV090x_WIDTH_FSKTF1_DELTAF_FIELD 4 + +#define STV090x_FSKTDELTAF0 0xf174 +#define STV090x_OFFST_FSKTF0_DELTAF_FIELD 0 +#define STV090x_WIDTH_FSKTF0_DELTAF_FIELD 8 + +#define STV090x_FSKTCTRL 0xf175 +#define STV090x_OFFST_FSKT_EN_SGN_FIELD 6 +#define STV090x_WIDTH_FSKT_EN_SGN_FIELD 1 +#define STV090x_OFFST_FSKT_MOD_SGN_FIELD 5 +#define STV090x_WIDTH_FSKT_MOD_SGN_FIELD 1 +#define STV090x_OFFST_FSKT_MOD_EN_FIELD 2 +#define STV090x_WIDTH_FSKT_MOD_EN_FIELD 3 +#define STV090x_OFFST_FSKT_DACMODE_FIELD 0 +#define STV090x_WIDTH_FSKT_DACMODE_FIELD 2 + +#define STV090x_FSKRFC2 0xf176 +#define STV090x_OFFST_FSKRC2_DETSGN_FIELD 6 +#define STV090x_WIDTH_FSKRC2_DETSGN_FIELD 1 +#define STV090x_OFFST_FSKRC2_OUTSGN_FIELD 5 +#define STV090x_WIDTH_FSKRC2_OUTSGN_FIELD 1 +#define STV090x_OFFST_FSKRC2_KAGC_FIELD 2 +#define STV090x_WIDTH_FSKRC2_KAGC_FIELD 3 +#define STV090x_OFFST_FSKRC2_CAR_FIELD 0 +#define STV090x_WIDTH_FSKRC2_CAR_FIELD 2 + +#define STV090x_FSKRFC1 0xf177 +#define STV090x_OFFST_FSKRC1_CAR_FIELD 0 +#define STV090x_WIDTH_FSKRC1_CAR_FIELD 8 + +#define STV090x_FSKRFC0 0xf178 +#define STV090x_OFFST_FSKRC0_CAR_FIELD 0 +#define STV090x_WIDTH_FSKRC0_CAR_FIELD 8 + +#define STV090x_FSKRK1 0xf179 +#define STV090x_OFFST_FSKR_K1_EXP_FIELD 5 +#define STV090x_WIDTH_FSKR_K1_EXP_FIELD 3 +#define STV090x_OFFST_FSKR_K1_MANT_FIELD 0 +#define STV090x_WIDTH_FSKR_K1_MANT_FIELD 5 + +#define STV090x_FSKRK2 0xf17a +#define STV090x_OFFST_FSKR_K2_EXP_FIELD 5 +#define STV090x_WIDTH_FSKR_K2_EXP_FIELD 3 +#define STV090x_OFFST_FSKR_K2_MANT_FIELD 0 +#define STV090x_WIDTH_FSKR_K2_MANT_FIELD 5 + +#define STV090x_FSKRAGCR 0xf17b +#define STV090x_OFFST_FSKR_OUTCTL_FIELD 6 +#define STV090x_WIDTH_FSKR_OUTCTL_FIELD 2 +#define STV090x_OFFST_FSKR_AGC_REF_FIELD 0 +#define STV090x_WIDTH_FSKR_AGC_REF_FIELD 6 + +#define STV090x_FSKRAGC 0xf17c +#define STV090x_OFFST_FSKR_AGC_ACCU_FIELD 0 +#define STV090x_WIDTH_FSKR_AGC_ACCU_FIELD 8 + +#define STV090x_FSKRALPHA 0xf17d +#define STV090x_OFFST_FSKR_ALPHA_EXP_FIELD 2 +#define STV090x_WIDTH_FSKR_ALPHA_EXP_FIELD 3 +#define STV090x_OFFST_FSKR_ALPHA_M_FIELD 0 +#define STV090x_WIDTH_FSKR_ALPHA_M_FIELD 2 + +#define STV090x_FSKRPLTH1 0xf17e +#define STV090x_OFFST_FSKR_BETA_FIELD 4 +#define STV090x_WIDTH_FSKR_BETA_FIELD 4 +#define STV090x_OFFST_FSKR_PLL_TRESH1_FIELD 0 +#define STV090x_WIDTH_FSKR_PLL_TRESH1_FIELD 4 + +#define STV090x_FSKRPLTH0 0xf17f +#define STV090x_OFFST_FSKR_PLL_TRESH0_FIELD 0 +#define STV090x_WIDTH_FSKR_PLL_TRESH0_FIELD 8 + +#define STV090x_FSKRDF1 0xf180 +#define STV090x_OFFST_FSKR_DELTAF1_FIELD 0 +#define STV090x_WIDTH_FSKR_DELTAF1_FIELD 5 + +#define STV090x_FSKRDF0 0xf181 +#define STV090x_OFFST_FSKR_DELTAF0_FIELD 0 +#define STV090x_WIDTH_FSKR_DELTAF0_FIELD 8 + +#define STV090x_FSKRSTEPP 0xf182 +#define STV090x_OFFST_FSKR_STEP_PLUS_FIELD 0 +#define STV090x_WIDTH_FSKR_STEP_PLUS_FIELD 8 + +#define STV090x_FSKRSTEPM 0xf183 +#define STV090x_OFFST_FSKR_STEP_MINUS_FIELD 0 +#define STV090x_WIDTH_FSKR_STEP_MINUS_FIELD 8 + +#define STV090x_FSKRDET1 0xf184 +#define STV090x_OFFST_FSKR_CARDET1_ACCU_FIELD 0 +#define STV090x_WIDTH_FSKR_CARDET1_ACCU_FIELD 4 + +#define STV090x_FSKRDET0 0xf185 +#define STV090x_OFFST_FSKR_CARDET0_ACCU_FIELD 0 +#define STV090x_WIDTH_FSKR_CARDET0_ACCU_FIELD 8 + +#define STV090x_FSKRDTH1 0xf186 +#define STV090x_OFFST_FSKR_CARLOSS_THRESH1_FIELD 4 +#define STV090x_WIDTH_FSKR_CARLOSS_THRESH1_FIELD 4 +#define STV090x_OFFST_FSKR_CARDET_THRESH1_FIELD 0 +#define STV090x_WIDTH_FSKR_CARDET_THRESH1_FIELD 4 + +#define STV090x_FSKRDTH0 0xf187 +#define STV090x_OFFST_FSKR_CARDET_THRESH0_FIELD 0 +#define STV090x_WIDTH_FSKR_CARDET_THRESH0_FIELD 8 + +#define STV090x_FSKRLOSS 0xf188 +#define STV090x_OFFST_FSKR_CARLOSS_THRESH_FIELD 0 +#define STV090x_WIDTH_FSKR_CARLOSS_THRESH_FIELD 8 + +#define STV090x_Px_DISTXCTL(__x) (0xF1A0 - (__x - 1) * 0x10) +#define STV090x_P1_DISTXCTL STV090x_Px_DISTXCTL(1) +#define STV090x_P2_DISTXCTL STV090x_Px_DISTXCTL(2) +#define STV090x_OFFST_Px_TIM_OFF_FIELD 7 +#define STV090x_WIDTH_Px_TIM_OFF_FIELD 1 +#define STV090x_OFFST_Px_DISEQC_RESET_FIELD 6 +#define STV090x_WIDTH_Px_DISEQC_RESET_FIELD 1 +#define STV090x_OFFST_Px_TIM_CMD_FIELD 4 +#define STV090x_WIDTH_Px_TIM_CMD_FIELD 2 +#define STV090x_OFFST_Px_DIS_PRECHARGE_FIELD 3 +#define STV090x_WIDTH_Px_DIS_PRECHARGE_FIELD 1 +#define STV090x_OFFST_Px_DISTX_MODE_FIELD 0 +#define STV090x_WIDTH_Px_DISTX_MODE_FIELD 3 + +#define STV090x_Px_DISRXCTL(__x) (0xf1a1 - (__x - 1) * 0x10) +#define STV090x_P1_DISRXCTL STV090x_Px_DISRXCTL(1) +#define STV090x_P2_DISRXCTL STV090x_Px_DISRXCTL(2) +#define STV090x_OFFST_Px_RECEIVER_ON_FIELD 7 +#define STV090x_WIDTH_Px_RECEIVER_ON_FIELD 1 +#define STV090x_OFFST_Px_IGNO_SHORT22K_FIELD 6 +#define STV090x_WIDTH_Px_IGNO_SHORT22K_FIELD 1 +#define STV090x_OFFST_Px_ONECHIP_TRX_FIELD 5 +#define STV090x_WIDTH_Px_ONECHIP_TRX_FIELD 1 +#define STV090x_OFFST_Px_EXT_ENVELOP_FIELD 4 +#define STV090x_WIDTH_Px_EXT_ENVELOP_FIELD 1 +#define STV090x_OFFST_Px_PIN_SELECT_FIELD 2 +#define STV090x_WIDTH_Px_PIN_SELECT_FIELD 2 +#define STV090x_OFFST_Px_IRQ_RXEND_FIELD 1 +#define STV090x_WIDTH_Px_IRQ_RXEND_FIELD 1 +#define STV090x_OFFST_Px_IRQ_4NBYTES_FIELD 0 +#define STV090x_WIDTH_Px_IRQ_4NBYTES_FIELD 1 + +#define STV090x_Px_DISRX_ST0(__x) (0xf1a4 - (__x - 1) * 0x10) +#define STV090x_P1_DISRX_ST0 STV090x_Px_DISRX_ST0(1) +#define STV090x_P2_DISRX_ST0 STV090x_Px_DISRX_ST0(2) +#define STV090x_OFFST_Px_RX_END_FIELD 7 +#define STV090x_WIDTH_Px_RX_END_FIELD 1 +#define STV090x_OFFST_Px_RX_ACTIVE_FIELD 6 +#define STV090x_WIDTH_Px_RX_ACTIVE_FIELD 1 +#define STV090x_OFFST_Px_SHORT_22KHZ_FIELD 5 +#define STV090x_WIDTH_Px_SHORT_22KHZ_FIELD 1 +#define STV090x_OFFST_Px_CONT_TONE_FIELD 4 +#define STV090x_WIDTH_Px_CONT_TONE_FIELD 1 +#define STV090x_OFFST_Px_FIFO_4BREADY_FIELD 3 +#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD 1 +#define STV090x_OFFST_Px_FIFO_EMPTY_FIELD 2 +#define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD 1 +#define STV090x_OFFST_Px_ABORT_DISRX_FIELD 0 +#define STV090x_WIDTH_Px_ABORT_DISRX_FIELD 1 + +#define STV090x_Px_DISRX_ST1(__x) (0xf1a5 - (__x - 1) * 0x10) +#define STV090x_P1_DISRX_ST1 STV090x_Px_DISRX_ST1(1) +#define STV090x_P2_DISRX_ST1 STV090x_Px_DISRX_ST1(2) +#define STV090x_OFFST_Px_RX_FAIL_FIELD 7 +#define STV090x_WIDTH_Px_RX_FAIL_FIELD 1 +#define STV090x_OFFST_Px_FIFO_PARITYFAIL_FIELD 6 +#define STV090x_WIDTH_Px_FIFO_PARITYFAIL_FIELD 1 +#define STV090x_OFFST_Px_RX_NONBYTE_FIELD 5 +#define STV090x_WIDTH_Px_RX_NONBYTE_FIELD 1 +#define STV090x_OFFST_Px_FIFO_OVERFLOW_FIELD 4 +#define STV090x_WIDTH_Px_FIFO_OVERFLOW_FIELD 1 +#define STV090x_OFFST_Px_FIFO_BYTENBR_FIELD 0 +#define STV090x_WIDTH_Px_FIFO_BYTENBR_FIELD 4 + +#define STV090x_Px_DISRXDATA(__x) (0xf1a6 - (__x - 1) * 0x10) +#define STV090x_P1_DISRXDATA STV090x_Px_DISRXDATA(1) +#define STV090x_P2_DISRXDATA STV090x_Px_DISRXDATA(2) +#define STV090x_OFFST_Px_DISRX_DATA_FIELD 0 +#define STV090x_WIDTH_Px_DISRX_DATA_FIELD 8 + +#define STV090x_Px_DISTXDATA(__x) (0xf1a7 - (__x - 1) * 0x10) +#define STV090x_P1_DISTXDATA STV090x_Px_DISTXDATA(1) +#define STV090x_P2_DISTXDATA STV090x_Px_DISTXDATA(2) +#define STV090x_OFFST_Px_DISEQC_FIFO_FIELD 0 +#define STV090x_WIDTH_Px_DISEQC_FIFO_FIELD 8 + +#define STV090x_Px_DISTXSTATUS(__x) (0xf1a8 - (__x - 1) * 0x10) +#define STV090x_P1_DISTXSTATUS STV090x_Px_DISTXSTATUS(1) +#define STV090x_P2_DISTXSTATUS STV090x_Px_DISTXSTATUS(2) +#define STV090x_OFFST_Px_TX_FAIL_FIELD 7 +#define STV090x_WIDTH_Px_TX_FAIL_FIELD 1 +#define STV090x_OFFST_Px_FIFO_FULL_FIELD 6 +#define STV090x_WIDTH_Px_FIFO_FULL_FIELD 1 +#define STV090x_OFFST_Px_TX_IDLE_FIELD 5 +#define STV090x_WIDTH_Px_TX_IDLE_FIELD 1 +#define STV090x_OFFST_Px_GAP_BURST_FIELD 4 +#define STV090x_WIDTH_Px_GAP_BURST_FIELD 1 +#define STV090x_OFFST_Px_TXFIFO_BYTES_FIELD 0 +#define STV090x_WIDTH_Px_TXFIFO_BYTES_FIELD 4 + +#define STV090x_Px_F22TX(__x) (0xf1a9 - (__x - 1) * 0x10) +#define STV090x_P1_F22TX STV090x_Px_F22TX(1) +#define STV090x_P2_F22TX STV090x_Px_F22TX(2) +#define STV090x_OFFST_Px_F22_REG_FIELD 0 +#define STV090x_WIDTH_Px_F22_REG_FIELD 8 + +#define STV090x_Px_F22RX(__x) (0xf1aa - (__x - 1) * 0x10) +#define STV090x_P1_F22RX STV090x_Px_F22RX(1) +#define STV090x_P2_F22RX STV090x_Px_F22RX(2) +#define STV090x_OFFST_Px_F22RX_REG_FIELD 0 +#define STV090x_WIDTH_Px_F22RX_REG_FIELD 8 + +#define STV090x_Px_ACRPRESC(__x) (0xf1ac - (__x - 1) * 0x10) +#define STV090x_P1_ACRPRESC STV090x_Px_ACRPRESC(1) +#define STV090x_P2_ACRPRESC STV090x_Px_ACRPRESC(2) +#define STV090x_OFFST_Px_ACR_PRESC_FIELD 0 +#define STV090x_WIDTH_Px_ACR_PRESC_FIELD 3 + +#define STV090x_Px_ACRDIV(__x) (0xf1ad - (__x - 1) * 0x10) +#define STV090x_P1_ACRDIV STV090x_Px_ACRDIV(1) +#define STV090x_P2_ACRDIV STV090x_Px_ACRDIV(2) +#define STV090x_OFFST_Px_ACR_DIV_FIELD 0 +#define STV090x_WIDTH_Px_ACR_DIV_FIELD 8 + +#define STV090x_Px_IQCONST(__x) (0xF400 - (__x - 1) * 0x200) +#define STV090x_P1_IQCONST STV090x_Px_IQCONST(1) +#define STV090x_P2_IQCONST STV090x_Px_IQCONST(2) +#define STV090x_OFFST_Px_CONSTEL_SELECT_FIELD 5 +#define STV090x_WIDTH_Px_CONSTEL_SELECT_FIELD 2 + +#define STV090x_Px_NOSCFG(__x) (0xF401 - (__x - 1) * 0x200) +#define STV090x_P1_NOSCFG STV090x_Px_NOSCFG(1) +#define STV090x_P2_NOSCFG STV090x_Px_NOSCFG(2) +#define STV090x_OFFST_Px_NOSPLH_BETA_FIELD 3 +#define STV090x_WIDTH_Px_NOSPLH_BETA_FIELD 2 +#define STV090x_OFFST_Px_NOSDATA_BETA_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATA_BETA_FIELD 3 + +#define STV090x_Px_ISYMB(__x) (0xF402 - (__x - 1) * 0x200) +#define STV090x_P1_ISYMB STV090x_Px_ISYMB(1) +#define STV090x_P2_ISYMB STV090x_Px_ISYMB(2) +#define STV090x_OFFST_Px_I_SYMBOL_FIELD 0 +#define STV090x_WIDTH_Px_I_SYMBOL_FIELD 8 + +#define STV090x_Px_QSYMB(__x) (0xF403 - (__x - 1) * 0x200) +#define STV090x_P1_QSYMB STV090x_Px_QSYMB(1) +#define STV090x_P2_QSYMB STV090x_Px_QSYMB(2) +#define STV090x_OFFST_Px_Q_SYMBOL_FIELD 0 +#define STV090x_WIDTH_Px_Q_SYMBOL_FIELD 8 + +#define STV090x_Px_AGC1CFG(__x) (0xF404 - (__x - 1) * 0x200) +#define STV090x_P1_AGC1CFG STV090x_Px_AGC1CFG(1) +#define STV090x_P2_AGC1CFG STV090x_Px_AGC1CFG(2) +#define STV090x_OFFST_Px_DC_FROZEN_FIELD 7 +#define STV090x_WIDTH_Px_DC_FROZEN_FIELD 1 +#define STV090x_OFFST_Px_DC_CORRECT_FIELD 6 +#define STV090x_WIDTH_Px_DC_CORRECT_FIELD 1 +#define STV090x_OFFST_Px_AMM_FROZEN_FIELD 5 +#define STV090x_WIDTH_Px_AMM_FROZEN_FIELD 1 +#define STV090x_OFFST_Px_AMM_CORRECT_FIELD 4 +#define STV090x_WIDTH_Px_AMM_CORRECT_FIELD 1 +#define STV090x_OFFST_Px_QUAD_FROZEN_FIELD 3 +#define STV090x_WIDTH_Px_QUAD_FROZEN_FIELD 1 +#define STV090x_OFFST_Px_QUAD_CORRECT_FIELD 2 +#define STV090x_WIDTH_Px_QUAD_CORRECT_FIELD 1 + +#define STV090x_Px_AGC1CN(__x) (0xF406 - (__x - 1) * 0x200) +#define STV090x_P1_AGC1CN STV090x_Px_AGC1CN(1) +#define STV090x_P2_AGC1CN STV090x_Px_AGC1CN(2) +#define STV090x_WIDTH_Px_AGC1_LOCKED_FIELD 7 +#define STV090x_OFFST_Px_AGC1_LOCKED_FIELD 1 +#define STV090x_OFFST_Px_AGC1_MINPOWER_FIELD 4 +#define STV090x_WIDTH_Px_AGC1_MINPOWER_FIELD 1 +#define STV090x_OFFST_Px_AGCOUT_FAST_FIELD 3 +#define STV090x_WIDTH_Px_AGCOUT_FAST_FIELD 1 +#define STV090x_OFFST_Px_AGCIQ_BETA_FIELD 0 +#define STV090x_WIDTH_Px_AGCIQ_BETA_FIELD 3 + +#define STV090x_Px_AGC1REF(__x) (0xF407 - (__x - 1) * 0x200) +#define STV090x_P1_AGC1REF STV090x_Px_AGC1REF(1) +#define STV090x_P2_AGC1REF STV090x_Px_AGC1REF(2) +#define STV090x_OFFST_Px_AGCIQ_REF_FIELD 0 +#define STV090x_WIDTH_Px_AGCIQ_REF_FIELD 8 + +#define STV090x_Px_IDCCOMP(__x) (0xF408 - (__x - 1) * 0x200) +#define STV090x_P1_IDCCOMP STV090x_Px_IDCCOMP(1) +#define STV090x_P2_IDCCOMP STV090x_Px_IDCCOMP(2) +#define STV090x_OFFST_Px_IAVERAGE_ADJ_FIELD 0 +#define STV090x_WIDTH_Px_IAVERAGE_ADJ_FIELD 8 + +#define STV090x_Px_QDCCOMP(__x) (0xF409 - (__x - 1) * 0x200) +#define STV090x_P1_QDCCOMP STV090x_Px_QDCCOMP(1) +#define STV090x_P2_QDCCOMP STV090x_Px_QDCCOMP(2) +#define STV090x_OFFST_Px_QAVERAGE_ADJ_FIELD 0 +#define STV090x_WIDTH_Px_QAVERAGE_ADJ_FIELD 8 + +#define STV090x_Px_POWERI(__x) (0xF40A - (__x - 1) * 0x200) +#define STV090x_P1_POWERI STV090x_Px_POWERI(1) +#define STV090x_P2_POWERI STV090x_Px_POWERI(2) +#define STV090x_OFFST_Px_POWER_I_FIELD 0 +#define STV090x_WIDTH_Px_POWER_I_FIELD 8 + +#define STV090x_Px_POWERQ(__x) (0xF40B - (__x - 1) * 0x200) +#define STV090x_P1_POWERQ STV090x_Px_POWERQ(1) +#define STV090x_P2_POWERQ STV090x_Px_POWERQ(2) +#define STV090x_OFFST_Px_POWER_Q_FIELD 0 +#define STV090x_WIDTH_Px_POWER_Q_FIELD 8 + +#define STV090x_Px_AGC1AMM(__x) (0xF40C - (__x - 1) * 0x200) +#define STV090x_P1_AGC1AMM STV090x_Px_AGC1AMM(1) +#define STV090x_P2_AGC1AMM STV090x_Px_AGC1AMM(2) +#define STV090x_OFFST_Px_AMM_VALUE_FIELD 0 +#define STV090x_WIDTH_Px_AMM_VALUE_FIELD 8 + +#define STV090x_Px_AGC1QUAD(__x) (0xF40D - (__x - 1) * 0x200) +#define STV090x_P1_AGC1QUAD STV090x_Px_AGC1QUAD(1) +#define STV090x_P2_AGC1QUAD STV090x_Px_AGC1QUAD(2) +#define STV090x_OFFST_Px_QUAD_VALUE_FIELD 0 +#define STV090x_WIDTH_Px_QUAD_VALUE_FIELD 8 + +#define STV090x_Px_AGCIQINy(__x, __y) (0xF40F - (__x-1) * 0x200 - __y * 0x1) +#define STV090x_P1_AGCIQIN0 STV090x_Px_AGCIQINy(1, 0) +#define STV090x_P1_AGCIQIN1 STV090x_Px_AGCIQINy(1, 1) +#define STV090x_P2_AGCIQIN0 STV090x_Px_AGCIQINy(2, 0) +#define STV090x_P2_AGCIQIN1 STV090x_Px_AGCIQINy(2, 1) +#define STV090x_OFFST_Px_AGCIQ_VALUE_FIELD 0 +#define STV090x_WIDTH_Px_AGCIQ_VALUE_FIELD 8 + +#define STV090x_Px_DEMOD(__x) (0xF410 - (__x - 1) * 0x200) +#define STV090x_P1_DEMOD STV090x_Px_DEMOD(1) +#define STV090x_P2_DEMOD STV090x_Px_DEMOD(2) +#define STV090x_OFFST_Px_MANUAL_S2ROLLOFF_FIELD 7 +#define STV090x_WIDTH_Px_MANUAL_S2ROLLOFF_FIELD 1 +#define STV090x_OFFST_Px_DEMOD_STOP_FIELD 6 +#define STV090x_WIDTH_Px_DEMOD_STOP_FIELD 1 +#define STV090x_OFFST_Px_SPECINV_CONTROL_FIELD 4 +#define STV090x_WIDTH_Px_SPECINV_CONTROL_FIELD 2 +#define STV090x_OFFST_Px_FORCE_ENASAMP_FIELD 3 +#define STV090x_WIDTH_Px_FORCE_ENASAMP_FIELD 1 +#define STV090x_OFFST_Px_MANUAL_SXROLLOFF_FIELD 2 +#define STV090x_WIDTH_Px_MANUAL_SXROLLOFF_FIELD 1 +#define STV090x_OFFST_Px_ROLLOFF_CONTROL_FIELD 0 +#define STV090x_WIDTH_Px_ROLLOFF_CONTROL_FIELD 2 + +#define STV090x_Px_DMDMODCOD(__x) (0xF411 - (__x - 1) * 0x200) +#define STV090x_P1_DMDMODCOD STV090x_Px_DMDMODCOD(1) +#define STV090x_P2_DMDMODCOD STV090x_Px_DMDMODCOD(2) +#define STV090x_OFFST_Px_MANUAL_MODCOD_FIELD 7 +#define STV090x_WIDTH_Px_MANUAL_MODCOD_FIELD 1 +#define STV090x_OFFST_Px_DEMOD_MODCOD_FIELD 2 +#define STV090x_WIDTH_Px_DEMOD_MODCOD_FIELD 5 +#define STV090x_OFFST_Px_DEMOD_TYPE_FIELD 0 +#define STV090x_WIDTH_Px_DEMOD_TYPE_FIELD 2 + +#define STV090x_Px_DSTATUS(__x) (0xF412 - (__x - 1) * 0x200) +#define STV090x_P1_DSTATUS STV090x_Px_DSTATUS(1) +#define STV090x_P2_DSTATUS STV090x_Px_DSTATUS(2) +#define STV090x_OFFST_Px_CAR_LOCK_FIELD 7 +#define STV090x_WIDTH_Px_CAR_LOCK_FIELD 1 +#define STV090x_OFFST_Px_TMGLOCK_QUALITY_FIELD 5 +#define STV090x_WIDTH_Px_TMGLOCK_QUALITY_FIELD 2 +#define STV090x_OFFST_Px_LOCK_DEFINITIF_FIELD 3 +#define STV090x_WIDTH_Px_LOCK_DEFINITIF_FIELD 1 + +#define STV090x_Px_DSTATUS2(__x) (0xF413 - (__x - 1) * 0x200) +#define STV090x_P1_DSTATUS2 STV090x_Px_DSTATUS2(1) +#define STV090x_P2_DSTATUS2 STV090x_Px_DSTATUS2(2) +#define STV090x_OFFST_Px_DEMOD_DELOCK_FIELD 7 +#define STV090x_WIDTH_Px_DEMOD_DELOCK_FIELD 1 +#define STV090x_OFFST_Px_AGC1_NOSIGNALACK_FIELD 3 +#define STV090x_WIDTH_Px_AGC1_NOSIGNALACK_FIELD 1 +#define STV090x_OFFST_Px_AGC2_OVERFLOW_FIELD 2 +#define STV090x_WIDTH_Px_AGC2_OVERFLOW_FIELD 1 +#define STV090x_OFFST_Px_CFR_OVERFLOW_FIELD 1 +#define STV090x_WIDTH_Px_CFR_OVERFLOW_FIELD 1 +#define STV090x_OFFST_Px_GAMMA_OVERUNDER_FIELD 0 +#define STV090x_WIDTH_Px_GAMMA_OVERUNDER_FIELD 1 + +#define STV090x_Px_DMDCFGMD(__x) (0xF414 - (__x - 1) * 0x200) +#define STV090x_P1_DMDCFGMD STV090x_Px_DMDCFGMD(1) +#define STV090x_P2_DMDCFGMD STV090x_Px_DMDCFGMD(2) +#define STV090x_OFFST_Px_DVBS2_ENABLE_FIELD 7 +#define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD 6 +#define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD 4 +#define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD 3 +#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD 1 +#define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD 2 +#define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD 1 +#define STV090x_OFFST_Px_TUN_RNG_FIELD 0 +#define STV090x_WIDTH_Px_TUN_RNG_FIELD 2 + +#define STV090x_Px_DMDCFG2(__x) (0xF415 - (__x - 1) * 0x200) +#define STV090x_P1_DMDCFG2 STV090x_Px_DMDCFG2(1) +#define STV090x_P2_DMDCFG2 STV090x_Px_DMDCFG2(2) +#define STV090x_OFFST_Px_S1S2_SEQUENTIAL_FIELD 6 +#define STV090x_WIDTH_Px_S1S2_SEQUENTIAL_FIELD 1 + +#define STV090x_Px_DMDISTATE(__x) (0xF416 - (__x - 1) * 0x200) +#define STV090x_P1_DMDISTATE STV090x_Px_DMDISTATE(1) +#define STV090x_P2_DMDISTATE STV090x_Px_DMDISTATE(2) +#define STV090x_OFFST_Px_I2C_DEMOD_MODE_FIELD 0 +#define STV090x_WIDTH_Px_I2C_DEMOD_MODE_FIELD 5 + +#define STV090x_Px_DMDTOM(__x) (0xF417 - (__x - 1) * 0x200) /* check */ +#define STV090x_P1_DMDTOM STV090x_Px_DMDTOM(1) +#define STV090x_P2_DMDTOM STV090x_Px_DMDTOM(2) + +#define STV090x_Px_DMDSTATE(__x) (0xF41B - (__x - 1) * 0x200) +#define STV090x_P1_DMDSTATE STV090x_Px_DMDSTATE(1) +#define STV090x_P2_DMDSTATE STV090x_Px_DMDSTATE(2) +#define STV090x_OFFST_Px_HEADER_MODE_FIELD 5 +#define STV090x_WIDTH_Px_HEADER_MODE_FIELD 2 + +#define STV090x_Px_DMDFLYW(__x) (0xF41C - (__x - 1) * 0x200) +#define STV090x_P1_DMDFLYW STV090x_Px_DMDFLYW(1) +#define STV090x_P2_DMDFLYW STV090x_Px_DMDFLYW(2) +#define STV090x_OFFST_Px_I2C_IRQVAL_FIELD 4 +#define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD 4 +#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD 4 + +#define STV090x_Px_DSTATUS3(__x) (0xF41D - (__x - 1) * 0x200) +#define STV090x_P1_DSTATUS3 STV090x_Px_DSTATUS3(1) +#define STV090x_P2_DSTATUS3 STV090x_Px_DSTATUS3(2) +#define STV090x_OFFST_Px_DEMOD_CFGMODE_FIELD 5 +#define STV090x_WIDTH_Px_DEMOD_CFGMODE_FIELD 2 + +#define STV090x_Px_DMDCFG3(__x) (0xF41E - (__x - 1) * 0x200) +#define STV090x_P1_DMDCFG3 STV090x_Px_DMDCFG3(1) +#define STV090x_P2_DMDCFG3 STV090x_Px_DMDCFG3(2) +#define STV090x_OFFST_Px_NOSTOP_FIFOFULL_FIELD 3 +#define STV090x_WIDTH_Px_NOSTOP_FIFOFULL_FIELD 1 + +#define STV090x_Px_DMDCFG4(__x) (0xf41f - (__x - 1) * 0x200) +#define STV090x_P1_DMDCFG4 STV090x_Px_DMDCFG4(1) +#define STV090x_P2_DMDCFG4 STV090x_Px_DMDCFG4(2) + +#define STV090x_Px_CORRELMANT(__x) (0xF420 - (__x - 1) * 0x200) +#define STV090x_P1_CORRELMANT STV090x_Px_CORRELMANT(1) +#define STV090x_P2_CORRELMANT STV090x_Px_CORRELMANT(2) +#define STV090x_OFFST_Px_CORREL_MANT_FIELD 0 +#define STV090x_WIDTH_Px_CORREL_MANT_FIELD 8 + +#define STV090x_Px_CORRELABS(__x) (0xF421 - (__x - 1) * 0x200) +#define STV090x_P1_CORRELABS STV090x_Px_CORRELABS(1) +#define STV090x_P2_CORRELABS STV090x_Px_CORRELABS(2) +#define STV090x_OFFST_Px_CORREL_ABS_FIELD 0 +#define STV090x_WIDTH_Px_CORREL_ABS_FIELD 8 + +#define STV090x_Px_CORRELEXP(__x) (0xF422 - (__x - 1) * 0x200) +#define STV090x_P1_CORRELEXP STV090x_Px_CORRELEXP(1) +#define STV090x_P2_CORRELEXP STV090x_Px_CORRELEXP(2) +#define STV090x_OFFST_Px_CORREL_ABSEXP_FIELD 4 +#define STV090x_WIDTH_Px_CORREL_ABSEXP_FIELD 4 +#define STV090x_OFFST_Px_CORREL_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CORREL_EXP_FIELD 4 + +#define STV090x_Px_PLHMODCOD(__x) (0xF424 - (__x - 1) * 0x200) +#define STV090x_P1_PLHMODCOD STV090x_Px_PLHMODCOD(1) +#define STV090x_P2_PLHMODCOD STV090x_Px_PLHMODCOD(2) +#define STV090x_OFFST_Px_SPECINV_DEMOD_FIELD 7 +#define STV090x_WIDTH_Px_SPECINV_DEMOD_FIELD 1 +#define STV090x_OFFST_Px_PLH_MODCOD_FIELD 2 +#define STV090x_WIDTH_Px_PLH_MODCOD_FIELD 5 +#define STV090x_OFFST_Px_PLH_TYPE_FIELD 0 +#define STV090x_WIDTH_Px_PLH_TYPE_FIELD 2 + +#define STV090x_Px_AGCK32(__x) (0xf42b - (__x - 1) * 0x200) +#define STV090x_P1_AGCK32 STV090x_Px_AGCK32(1) +#define STV090x_P2_AGCK32 STV090x_Px_AGCK32(2) + +#define STV090x_Px_AGC2O(__x) (0xF42C - (__x - 1) * 0x200) +#define STV090x_P1_AGC2O STV090x_Px_AGC2O(1) +#define STV090x_P2_AGC2O STV090x_Px_AGC2O(2) + +#define STV090x_Px_AGC2REF(__x) (0xF42D - (__x - 1) * 0x200) +#define STV090x_P1_AGC2REF STV090x_Px_AGC2REF(1) +#define STV090x_P2_AGC2REF STV090x_Px_AGC2REF(2) +#define STV090x_OFFST_Px_AGC2_REF_FIELD 0 +#define STV090x_WIDTH_Px_AGC2_REF_FIELD 8 + +#define STV090x_Px_AGC1ADJ(__x) (0xF42E - (__x - 1) * 0x200) +#define STV090x_P1_AGC1ADJ STV090x_Px_AGC1ADJ(1) +#define STV090x_P2_AGC1ADJ STV090x_Px_AGC1ADJ(2) +#define STV090x_OFFST_Px_AGC1_ADJUSTED_FIELD 0 +#define STV090x_WIDTH_Px_AGC1_ADJUSTED_FIELD 7 + +#define STV090x_Px_AGC2Iy(__x, __y) (0xF437 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_AGC2I0 STV090x_Px_AGC2Iy(1, 0) +#define STV090x_P1_AGC2I1 STV090x_Px_AGC2Iy(1, 1) +#define STV090x_P2_AGC2I0 STV090x_Px_AGC2Iy(2, 0) +#define STV090x_P2_AGC2I1 STV090x_Px_AGC2Iy(2, 1) +#define STV090x_OFFST_Px_AGC2_INTEGRATOR_FIELD 0 +#define STV090x_WIDTH_Px_AGC2_INTEGRATOR_FIELD 8 + +#define STV090x_Px_CARCFG(__x) (0xF438 - (__x - 1) * 0x200) +#define STV090x_P1_CARCFG STV090x_Px_CARCFG(1) +#define STV090x_P2_CARCFG STV090x_Px_CARCFG(2) +#define STV090x_OFFST_Px_EN_CAR2CENTER_FIELD 5 +#define STV090x_WIDTH_Px_EN_CAR2CENTER_FIELD 1 +#define STV090x_OFFST_Px_ROTATON_FIELD 2 +#define STV090x_WIDTH_Px_ROTATON_FIELD 1 +#define STV090x_OFFST_Px_PH_DET_ALGO_FIELD 0 +#define STV090x_WIDTH_Px_PH_DET_ALGO_FIELD 2 + +#define STV090x_Px_ACLC(__x) (0xF439 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC STV090x_Px_ACLC(1) +#define STV090x_P2_ACLC STV090x_Px_ACLC(2) +#define STV090x_OFFST_Px_CAR_ALPHA_MANT_FIELD 4 +#define STV090x_WIDTH_Px_CAR_ALPHA_MANT_FIELD 2 +#define STV090x_OFFST_Px_CAR_ALPHA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CAR_ALPHA_EXP_FIELD 4 + +#define STV090x_Px_BCLC(__x) (0xF43A - (__x - 1) * 0x200) +#define STV090x_P1_BCLC STV090x_Px_BCLC(1) +#define STV090x_P2_BCLC STV090x_Px_BCLC(2) +#define STV090x_OFFST_Px_CAR_BETA_MANT_FIELD 4 +#define STV090x_WIDTH_Px_CAR_BETA_MANT_FIELD 2 +#define STV090x_OFFST_Px_CAR_BETA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CAR_BETA_EXP_FIELD 4 + +#define STV090x_Px_CARFREQ(__x) (0xF43D - (__x - 1) * 0x200) +#define STV090x_P1_CARFREQ STV090x_Px_CARFREQ(1) +#define STV090x_P2_CARFREQ STV090x_Px_CARFREQ(2) +#define STV090x_OFFST_Px_KC_COARSE_EXP_FIELD 4 +#define STV090x_WIDTH_Px_KC_COARSE_EXP_FIELD 4 +#define STV090x_OFFST_Px_BETA_FREQ_FIELD 0 +#define STV090x_WIDTH_Px_BETA_FREQ_FIELD 4 + +#define STV090x_Px_CARHDR(__x) (0xF43E - (__x - 1) * 0x200) +#define STV090x_P1_CARHDR STV090x_Px_CARHDR(1) +#define STV090x_P2_CARHDR STV090x_Px_CARHDR(2) +#define STV090x_OFFST_Px_FREQ_HDR_FIELD 0 +#define STV090x_WIDTH_Px_FREQ_HDR_FIELD 8 + +#define STV090x_Px_LDT(__x) (0xF43F - (__x - 1) * 0x200) +#define STV090x_P1_LDT STV090x_Px_LDT(1) +#define STV090x_P2_LDT STV090x_Px_LDT(2) +#define STV090x_OFFST_Px_CARLOCK_THRES_FIELD 0 +#define STV090x_WIDTH_Px_CARLOCK_THRES_FIELD 8 + +#define STV090x_Px_LDT2(__x) (0xF440 - (__x - 1) * 0x200) +#define STV090x_P1_LDT2 STV090x_Px_LDT2(1) +#define STV090x_P2_LDT2 STV090x_Px_LDT2(2) +#define STV090x_OFFST_Px_CARLOCK_THRES2_FIELD 0 +#define STV090x_WIDTH_Px_CARLOCK_THRES2_FIELD 8 + +#define STV090x_Px_CFRICFG(__x) (0xF441 - (__x - 1) * 0x200) +#define STV090x_P1_CFRICFG STV090x_Px_CFRICFG(1) +#define STV090x_P2_CFRICFG STV090x_Px_CFRICFG(2) +#define STV090x_OFFST_Px_NEG_CFRSTEP_FIELD 0 +#define STV090x_WIDTH_Px_NEG_CFRSTEP_FIELD 1 + +#define STV090x_Pn_CFRUPy(__x, __y) (0xF443 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_CFRUP0 STV090x_Pn_CFRUPy(1, 0) +#define STV090x_P1_CFRUP1 STV090x_Pn_CFRUPy(1, 1) +#define STV090x_P2_CFRUP0 STV090x_Pn_CFRUPy(2, 0) +#define STV090x_P2_CFRUP1 STV090x_Pn_CFRUPy(2, 1) +#define STV090x_OFFST_Px_CFR_UP_FIELD 0 +#define STV090x_WIDTH_Px_CFR_UP_FIELD 8 + +#define STV090x_Pn_CFRLOWy(__x, __y) (0xF447 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_CFRLOW0 STV090x_Pn_CFRLOWy(1, 0) +#define STV090x_P1_CFRLOW1 STV090x_Pn_CFRLOWy(1, 1) +#define STV090x_P2_CFRLOW0 STV090x_Pn_CFRLOWy(2, 0) +#define STV090x_P2_CFRLOW1 STV090x_Pn_CFRLOWy(2, 1) +#define STV090x_OFFST_Px_CFR_LOW_FIELD 0 +#define STV090x_WIDTH_Px_CFR_LOW_FIELD 8 + +#define STV090x_Pn_CFRINITy(__x, __y) (0xF449 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_CFRINIT0 STV090x_Pn_CFRINITy(1, 0) +#define STV090x_P1_CFRINIT1 STV090x_Pn_CFRINITy(1, 1) +#define STV090x_P2_CFRINIT0 STV090x_Pn_CFRINITy(2, 0) +#define STV090x_P2_CFRINIT1 STV090x_Pn_CFRINITy(2, 1) +#define STV090x_OFFST_Px_CFR_INIT_FIELD 0 +#define STV090x_WIDTH_Px_CFR_INIT_FIELD 8 + +#define STV090x_Px_CFRINC1(__x) (0xF44A - (__x - 1) * 0x200) +#define STV090x_P1_CFRINC1 STV090x_Px_CFRINC1(1) +#define STV090x_P2_CFRINC1 STV090x_Px_CFRINC1(2) +#define STV090x_OFFST_Px_CFR_INC1_FIELD 0 +#define STV090x_WIDTH_Px_CFR_INC1_FIELD 7 /* check */ + +#define STV090x_Px_CFRINC0(__x) (0xF44B - (__x - 1) * 0x200) +#define STV090x_P1_CFRINC0 STV090x_Px_CFRINC0(1) +#define STV090x_P2_CFRINC0 STV090x_Px_CFRINC0(2) +#define STV090x_OFFST_Px_CFR_INC0_FIELD 4 /* check */ +#define STV090x_WIDTH_Px_CFR_INC0_FIELD 4 + +#define STV090x_Pn_CFRy(__x, __y) (0xF44E - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_CFR0 STV090x_Pn_CFRy(1, 0) +#define STV090x_P1_CFR1 STV090x_Pn_CFRy(1, 1) +#define STV090x_P1_CFR2 STV090x_Pn_CFRy(1, 2) +#define STV090x_P2_CFR0 STV090x_Pn_CFRy(2, 0) +#define STV090x_P2_CFR1 STV090x_Pn_CFRy(2, 1) +#define STV090x_P2_CFR2 STV090x_Pn_CFRy(2, 2) +#define STV090x_OFFST_Px_CAR_FREQ_FIELD 0 +#define STV090x_WIDTH_Px_CAR_FREQ_FIELD 8 + +#define STV090x_Px_LDI(__x) (0xF44F - (__x - 1) * 0x200) +#define STV090x_P1_LDI STV090x_Px_LDI(1) +#define STV090x_P2_LDI STV090x_Px_LDI(2) +#define STV090x_OFFST_Px_LOCK_DET_INTEGR_FIELD 0 +#define STV090x_WIDTH_Px_LOCK_DET_INTEGR_FIELD 8 + +#define STV090x_Px_TMGCFG(__x) (0xF450 - (__x - 1) * 0x200) +#define STV090x_P1_TMGCFG STV090x_Px_TMGCFG(1) +#define STV090x_P2_TMGCFG STV090x_Px_TMGCFG(2) +#define STV090x_OFFST_Px_TMGLOCK_BETA_FIELD 6 +#define STV090x_WIDTH_Px_TMGLOCK_BETA_FIELD 2 +#define STV090x_OFFST_Px_DO_TIMING_FIELD 4 +#define STV090x_WIDTH_Px_DO_TIMING_FIELD 1 +#define STV090x_OFFST_Px_TMG_MINFREQ_FIELD 0 +#define STV090x_WIDTH_Px_TMG_MINFREQ_FIELD 2 + +#define STV090x_Px_RTC(__x) (0xF451 - (__x - 1) * 0x200) +#define STV090x_P1_RTC STV090x_Px_RTC(1) +#define STV090x_P2_RTC STV090x_Px_RTC(2) +#define STV090x_OFFST_Px_TMGALPHA_EXP_FIELD 4 +#define STV090x_WIDTH_Px_TMGALPHA_EXP_FIELD 4 +#define STV090x_OFFST_Px_TMGBETA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_TMGBETA_EXP_FIELD 4 + +#define STV090x_Px_RTCS2(__x) (0xF452 - (__x - 1) * 0x200) +#define STV090x_P1_RTCS2 STV090x_Px_RTCS2(1) +#define STV090x_P2_RTCS2 STV090x_Px_RTCS2(2) +#define STV090x_OFFST_Px_TMGALPHAS2_EXP_FIELD 4 +#define STV090x_WIDTH_Px_TMGALPHAS2_EXP_FIELD 4 +#define STV090x_OFFST_Px_TMGBETAS2_EXP_FIELD 0 +#define STV090x_WIDTH_Px_TMGBETAS2_EXP_FIELD 4 + +#define STV090x_Px_TMGTHRISE(__x) (0xF453 - (__x - 1) * 0x200) +#define STV090x_P1_TMGTHRISE STV090x_Px_TMGTHRISE(1) +#define STV090x_P2_TMGTHRISE STV090x_Px_TMGTHRISE(2) +#define STV090x_OFFST_Px_TMGLOCK_THRISE_FIELD 0 +#define STV090x_WIDTH_Px_TMGLOCK_THRISE_FIELD 8 + +#define STV090x_Px_TMGTHFALL(__x) (0xF454 - (__x - 1) * 0x200) +#define STV090x_P1_TMGTHFALL STV090x_Px_TMGTHFALL(1) +#define STV090x_P2_TMGTHFALL STV090x_Px_TMGTHFALL(2) +#define STV090x_OFFST_Px_TMGLOCK_THFALL_FIELD 0 +#define STV090x_WIDTH_Px_TMGLOCK_THFALL_FIELD 8 + +#define STV090x_Px_SFRUPRATIO(__x) (0xF455 - (__x - 1) * 0x200) +#define STV090x_P1_SFRUPRATIO STV090x_Px_SFRUPRATIO(1) +#define STV090x_P2_SFRUPRATIO STV090x_Px_SFRUPRATIO(2) +#define STV090x_OFFST_Px_SFR_UPRATIO_FIELD 0 +#define STV090x_WIDTH_Px_SFR_UPRATIO_FIELD 8 + +#define STV090x_Px_SFRLOWRATIO(__x) (0xF456 - (__x - 1) * 0x200) +#define STV090x_P1_SFRLOWRATIO STV090x_Px_SFRLOWRATIO(1) +#define STV090x_P2_SFRLOWRATIO STV090x_Px_SFRLOWRATIO(2) +#define STV090x_OFFST_Px_SFR_LOWRATIO_FIELD 0 +#define STV090x_WIDTH_Px_SFR_LOWRATIO_FIELD 8 + +#define STV090x_Px_KREFTMG(__x) (0xF458 - (__x - 1) * 0x200) +#define STV090x_P1_KREFTMG STV090x_Px_KREFTMG(1) +#define STV090x_P2_KREFTMG STV090x_Px_KREFTMG(2) +#define STV090x_OFFST_Px_KREF_TMG_FIELD 0 +#define STV090x_WIDTH_Px_KREF_TMG_FIELD 8 + +#define STV090x_Px_SFRSTEP(__x) (0xF459 - (__x - 1) * 0x200) +#define STV090x_P1_SFRSTEP STV090x_Px_SFRSTEP(1) +#define STV090x_P2_SFRSTEP STV090x_Px_SFRSTEP(2) +#define STV090x_OFFST_Px_SFR_SCANSTEP_FIELD 4 +#define STV090x_WIDTH_Px_SFR_SCANSTEP_FIELD 4 +#define STV090x_OFFST_Px_SFR_CENTERSTEP_FIELD 0 +#define STV090x_WIDTH_Px_SFR_CENTERSTEP_FIELD 4 + +#define STV090x_Px_TMGCFG2(__x) (0xF45A - (__x - 1) * 0x200) +#define STV090x_P1_TMGCFG2 STV090x_Px_TMGCFG2(1) +#define STV090x_P2_TMGCFG2 STV090x_Px_TMGCFG2(2) +#define STV090x_OFFST_Px_SFRRATIO_FINE_FIELD 0 +#define STV090x_WIDTH_Px_SFRRATIO_FINE_FIELD 1 + +#define STV090x_Px_SFRINIT1(__x) (0xF45E - (__x - 1) * 0x200) +#define STV090x_P1_SFRINIT1 STV090x_Px_SFRINIT1(1) +#define STV090x_P2_SFRINIT1 STV090x_Px_SFRINIT1(2) +#define STV090x_OFFST_Px_SFR_INIT1_FIELD 0 +#define STV090x_WIDTH_Px_SFR_INIT1_FIELD 7 + +#define STV090x_Px_SFRINIT0(__x) (0xF45F - (__x - 1) * 0x200) +#define STV090x_P1_SFRINIT0 STV090x_Px_SFRINIT0(1) +#define STV090x_P2_SFRINIT0 STV090x_Px_SFRINIT0(2) +#define STV090x_OFFST_Px_SFR_INIT0_FIELD 0 +#define STV090x_WIDTH_Px_SFR_INIT0_FIELD 8 + +#define STV090x_Px_SFRUP1(__x) (0xF460 - (__x - 1) * 0x200) +#define STV090x_P1_SFRUP1 STV090x_Px_SFRUP1(1) +#define STV090x_P2_SFRUP1 STV090x_Px_SFRUP1(2) +#define STV090x_OFFST_Px_SYMB_FREQ_UP1_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_UP1_FIELD 7 + +#define STV090x_Px_SFRUP0(__x) (0xF461 - (__x - 1) * 0x200) +#define STV090x_P1_SFRUP0 STV090x_Px_SFRUP0(1) +#define STV090x_P2_SFRUP0 STV090x_Px_SFRUP0(2) +#define STV090x_OFFST_Px_SYMB_FREQ_UP0_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_UP0_FIELD 8 + +#define STV090x_Px_SFRLOW1(__x) (0xF462 - (__x - 1) * 0x200) +#define STV090x_P1_SFRLOW1 STV090x_Px_SFRLOW1(1) +#define STV090x_P2_SFRLOW1 STV090x_Px_SFRLOW1(2) +#define STV090x_OFFST_Px_SYMB_FREQ_LOW1_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_LOW1_FIELD 7 + +#define STV090x_Px_SFRLOW0(__x) (0xF463 - (__x - 1) * 0x200) +#define STV090x_P1_SFRLOW0 STV090x_Px_SFRLOW0(1) +#define STV090x_P2_SFRLOW0 STV090x_Px_SFRLOW0(2) +#define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD 8 + +#define STV090x_Px_SFRy(__x, __y) (0xF467 - (__x-1) * 0x200 - __y) +#define STV090x_P1_SFR0 STV090x_Px_SFRy(1, 0) +#define STV090x_P1_SFR1 STV090x_Px_SFRy(1, 1) +#define STV090x_P1_SFR2 STV090x_Px_SFRy(1, 2) +#define STV090x_P1_SFR3 STV090x_Px_SFRy(1, 3) +#define STV090x_P2_SFR0 STV090x_Px_SFRy(2, 0) +#define STV090x_P2_SFR1 STV090x_Px_SFRy(2, 1) +#define STV090x_P2_SFR2 STV090x_Px_SFRy(2, 2) +#define STV090x_P2_SFR3 STV090x_Px_SFRy(2, 3) +#define STV090x_OFFST_Px_SYMB_FREQ_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD 8 + +#define STV090x_Px_TMGREG2(__x) (0xF468 - (__x - 1) * 0x200) +#define STV090x_P1_TMGREG2 STV090x_Px_TMGREG2(1) +#define STV090x_P2_TMGREG2 STV090x_Px_TMGREG2(2) +#define STV090x_OFFST_Px_TMGREG_FIELD 0 +#define STV090x_WIDTH_Px_TMGREG_FIELD 8 + +#define STV090x_Px_TMGREG1(__x) (0xF469 - (__x - 1) * 0x200) +#define STV090x_P1_TMGREG1 STV090x_Px_TMGREG1(1) +#define STV090x_P2_TMGREG1 STV090x_Px_TMGREG1(2) +#define STV090x_OFFST_Px_TMGREG_FIELD 0 +#define STV090x_WIDTH_Px_TMGREG_FIELD 8 + +#define STV090x_Px_TMGREG0(__x) (0xF46A - (__x - 1) * 0x200) +#define STV090x_P1_TMGREG0 STV090x_Px_TMGREG0(1) +#define STV090x_P2_TMGREG0 STV090x_Px_TMGREG0(2) +#define STV090x_OFFST_Px_TMGREG_FIELD 0 +#define STV090x_WIDTH_Px_TMGREG_FIELD 8 + +#define STV090x_Px_TMGLOCKy(__x, __y) (0xF46C - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_TMGLOCK0 STV090x_Px_TMGLOCKy(1, 0) +#define STV090x_P1_TMGLOCK1 STV090x_Px_TMGLOCKy(1, 1) +#define STV090x_P2_TMGLOCK0 STV090x_Px_TMGLOCKy(2, 0) +#define STV090x_P2_TMGLOCK1 STV090x_Px_TMGLOCKy(2, 1) +#define STV090x_OFFST_Px_TMGLOCK_LEVEL_FIELD 0 +#define STV090x_WIDTH_Px_TMGLOCK_LEVEL_FIELD 8 + +#define STV090x_Px_TMGOBS(__x) (0xF46D - (__x - 1) * 0x200) +#define STV090x_P1_TMGOBS STV090x_Px_TMGOBS(1) +#define STV090x_P2_TMGOBS STV090x_Px_TMGOBS(2) +#define STV090x_OFFST_Px_ROLLOFF_STATUS_FIELD 6 +#define STV090x_WIDTH_Px_ROLLOFF_STATUS_FIELD 2 + +#define STV090x_Px_EQUALCFG(__x) (0xF46F - (__x - 1) * 0x200) +#define STV090x_P1_EQUALCFG STV090x_Px_EQUALCFG(1) +#define STV090x_P2_EQUALCFG STV090x_Px_EQUALCFG(2) +#define STV090x_OFFST_Px_EQUAL_ON_FIELD 6 +#define STV090x_WIDTH_Px_EQUAL_ON_FIELD 1 +#define STV090x_OFFST_Px_MU_EQUALDFE_FIELD 0 +#define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD 3 + +#define STV090x_Px_EQUAIy(__x, __y) (0xf470 - (__x-1) * 0x200 + 2 * (__y-1)) +#define STV090x_P1_EQUAI1 STV090x_Px_EQUAIy(1, 1) +#define STV090x_P1_EQUAI2 STV090x_Px_EQUAIy(1, 2) +#define STV090x_P1_EQUAI3 STV090x_Px_EQUAIy(1, 3) +#define STV090x_P1_EQUAI4 STV090x_Px_EQUAIy(1, 4) +#define STV090x_P1_EQUAI5 STV090x_Px_EQUAIy(1, 5) +#define STV090x_P1_EQUAI6 STV090x_Px_EQUAIy(1, 6) +#define STV090x_P1_EQUAI7 STV090x_Px_EQUAIy(1, 7) +#define STV090x_P1_EQUAI8 STV090x_Px_EQUAIy(1, 8) + +#define STV090x_P2_EQUAI1 STV090x_Px_EQUAIy(2, 1) +#define STV090x_P2_EQUAI2 STV090x_Px_EQUAIy(2, 2) +#define STV090x_P2_EQUAI3 STV090x_Px_EQUAIy(2, 3) +#define STV090x_P2_EQUAI4 STV090x_Px_EQUAIy(2, 4) +#define STV090x_P2_EQUAI5 STV090x_Px_EQUAIy(2, 5) +#define STV090x_P2_EQUAI6 STV090x_Px_EQUAIy(2, 6) +#define STV090x_P2_EQUAI7 STV090x_Px_EQUAIy(2, 7) +#define STV090x_P2_EQUAI8 STV090x_Px_EQUAIy(2, 8) +#define STV090x_OFFST_Px_EQUA_ACCIy_FIELD 0 +#define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD 8 + +#define STV090x_Px_EQUAQy(__x, __y) (0xf471 - (__x-1) * 0x200 + 2 * (__y-1)) +#define STV090x_P1_EQUAQ1 STV090x_Px_EQUAQy(1, 1) +#define STV090x_P1_EQUAQ2 STV090x_Px_EQUAQy(1, 2) +#define STV090x_P1_EQUAQ3 STV090x_Px_EQUAQy(1, 3) +#define STV090x_P1_EQUAQ4 STV090x_Px_EQUAQy(1, 4) +#define STV090x_P1_EQUAQ5 STV090x_Px_EQUAQy(1, 5) +#define STV090x_P1_EQUAQ6 STV090x_Px_EQUAQy(1, 6) +#define STV090x_P1_EQUAQ7 STV090x_Px_EQUAQy(1, 7) +#define STV090x_P1_EQUAQ8 STV090x_Px_EQUAQy(1, 8) + +#define STV090x_P2_EQUAQ1 STV090x_Px_EQUAQy(2, 1) +#define STV090x_P2_EQUAQ2 STV090x_Px_EQUAQy(2, 2) +#define STV090x_P2_EQUAQ3 STV090x_Px_EQUAQy(2, 3) +#define STV090x_P2_EQUAQ4 STV090x_Px_EQUAQy(2, 4) +#define STV090x_P2_EQUAQ5 STV090x_Px_EQUAQy(2, 5) +#define STV090x_P2_EQUAQ6 STV090x_Px_EQUAQy(2, 6) +#define STV090x_P2_EQUAQ7 STV090x_Px_EQUAQy(2, 7) +#define STV090x_P2_EQUAQ8 STV090x_Px_EQUAQy(2, 8) +#define STV090x_OFFST_Px_EQUA_ACCQy_FIELD 0 +#define STV090x_WIDTH_Px_EQUA_ACCQy_FIELD 8 + +#define STV090x_Px_NNOSDATATy(__x, __y) (0xf481 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NNOSDATAT0 STV090x_Px_NNOSDATATy(1, 0) +#define STV090x_P1_NNOSDATAT1 STV090x_Px_NNOSDATATy(1, 1) +#define STV090x_P2_NNOSDATAT0 STV090x_Px_NNOSDATATy(2, 0) +#define STV090x_P2_NNOSDATAT1 STV090x_Px_NNOSDATATy(2, 1) +#define STV090x_OFFST_Px_NOSDATAT_NORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATAT_NORMED_FIELD 8 + +#define STV090x_Px_NNOSDATAy(__x, __y) (0xf483 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NNOSDATA0 STV090x_Px_NNOSDATAy(1, 0) +#define STV090x_P1_NNOSDATA1 STV090x_Px_NNOSDATAy(1, 1) +#define STV090x_P2_NNOSDATA0 STV090x_Px_NNOSDATAy(2, 0) +#define STV090x_P2_NNOSDATA1 STV090x_Px_NNOSDATAy(2, 1) +#define STV090x_OFFST_Px_NOSDATA_NORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATA_NORMED_FIELD 8 + +#define STV090x_Px_NNOSPLHTy(__x, __y) (0xf485 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NNOSPLHT0 STV090x_Px_NNOSPLHTy(1, 0) +#define STV090x_P1_NNOSPLHT1 STV090x_Px_NNOSPLHTy(1, 1) +#define STV090x_P2_NNOSPLHT0 STV090x_Px_NNOSPLHTy(2, 0) +#define STV090x_P2_NNOSPLHT1 STV090x_Px_NNOSPLHTy(2, 1) +#define STV090x_OFFST_Px_NOSPLHT_NORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSPLHT_NORMED_FIELD 8 + +#define STV090x_Px_NNOSPLHy(__x, __y) (0xf487 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NNOSPLH0 STV090x_Px_NNOSPLHy(1, 0) +#define STV090x_P1_NNOSPLH1 STV090x_Px_NNOSPLHy(1, 1) +#define STV090x_P2_NNOSPLH0 STV090x_Px_NNOSPLHy(2, 0) +#define STV090x_P2_NNOSPLH1 STV090x_Px_NNOSPLHy(2, 1) +#define STV090x_OFFST_Px_NOSPLH_NORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSPLH_NORMED_FIELD 8 + +#define STV090x_Px_NOSDATATy(__x, __y) (0xf489 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NOSDATAT0 STV090x_Px_NOSDATATy(1, 0) +#define STV090x_P1_NOSDATAT1 STV090x_Px_NOSDATATy(1, 1) +#define STV090x_P2_NOSDATAT0 STV090x_Px_NOSDATATy(2, 0) +#define STV090x_P2_NOSDATAT1 STV090x_Px_NOSDATATy(2, 1) +#define STV090x_OFFST_Px_NOSDATAT_UNNORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATAT_UNNORMED_FIELD 8 + +#define STV090x_Px_NOSDATAy(__x, __y) (0xf48b - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NOSDATA0 STV090x_Px_NOSDATAy(1, 0) +#define STV090x_P1_NOSDATA1 STV090x_Px_NOSDATAy(1, 1) +#define STV090x_P2_NOSDATA0 STV090x_Px_NOSDATAy(2, 0) +#define STV090x_P2_NOSDATA1 STV090x_Px_NOSDATAy(2, 1) +#define STV090x_OFFST_Px_NOSDATA_UNNORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATA_UNNORMED_FIELD 8 + +#define STV090x_Px_NOSPLHTy(__x, __y) (0xf48d - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NOSPLHT0 STV090x_Px_NOSPLHTy(1, 0) +#define STV090x_P1_NOSPLHT1 STV090x_Px_NOSPLHTy(1, 1) +#define STV090x_P2_NOSPLHT0 STV090x_Px_NOSPLHTy(2, 0) +#define STV090x_P2_NOSPLHT1 STV090x_Px_NOSPLHTy(2, 1) +#define STV090x_OFFST_Px_NOSPLHT_UNNORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD 8 + +#define STV090x_Px_NOSPLHy(__x, __y) (0xf48f - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NOSPLH0 STV090x_Px_NOSPLHy(1, 0) +#define STV090x_P1_NOSPLH1 STV090x_Px_NOSPLHy(1, 1) +#define STV090x_P2_NOSPLH0 STV090x_Px_NOSPLHy(2, 0) +#define STV090x_P2_NOSPLH1 STV090x_Px_NOSPLHy(2, 1) +#define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD 8 + +#define STV090x_Px_CAR2CFG(__x) (0xf490 - (__x - 1) * 0x200) +#define STV090x_P1_CAR2CFG STV090x_Px_CAR2CFG(1) +#define STV090x_P2_CAR2CFG STV090x_Px_CAR2CFG(2) +#define STV090x_OFFST_Px_PN4_SELECT_FIELD 6 +#define STV090x_WIDTH_Px_PN4_SELECT_FIELD 1 +#define STV090x_OFFST_Px_CFR2_STOPDVBS1_FIELD 5 +#define STV090x_WIDTH_Px_CFR2_STOPDVBS1_FIELD 1 +#define STV090x_OFFST_Px_ROTA2ON_FIELD 2 +#define STV090x_WIDTH_Px_ROTA2ON_FIELD 1 +#define STV090x_OFFST_Px_PH_DET_ALGO2_FIELD 0 +#define STV090x_WIDTH_Px_PH_DET_ALGO2_FIELD 2 + +#define STV090x_Px_ACLC2(__x) (0xf491 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2 STV090x_Px_ACLC2(1) +#define STV090x_P2_ACLC2 STV090x_Px_ACLC2(2) +#define STV090x_OFFST_Px_CAR2_ALPHA_MANT_FIELD 4 +#define STV090x_WIDTH_Px_CAR2_ALPHA_MANT_FIELD 2 +#define STV090x_OFFST_Px_CAR2_ALPHA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CAR2_ALPHA_EXP_FIELD 4 + +#define STV090x_Px_BCLC2(__x) (0xf492 - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2 STV090x_Px_BCLC2(1) +#define STV090x_P2_BCLC2 STV090x_Px_BCLC2(2) +#define STV090x_OFFST_Px_CAR2_BETA_MANT_FIELD 4 +#define STV090x_WIDTH_Px_CAR2_BETA_MANT_FIELD 2 +#define STV090x_OFFST_Px_CAR2_BETA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CAR2_BETA_EXP_FIELD 4 + +#define STV090x_Px_ACLC2S2Q(__x) (0xf497 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2S2Q STV090x_Px_ACLC2S2Q(1) +#define STV090x_P2_ACLC2S2Q STV090x_Px_ACLC2S2Q(2) +#define STV090x_OFFST_Px_ENAB_SPSKSYMB_FIELD 7 +#define STV090x_WIDTH_Px_ENAB_SPSKSYMB_FIELD 1 +#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_E_FIELD 4 + +#define STV090x_Px_ACLC2S28(__x) (0xf498 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2S28 STV090x_Px_ACLC2S28(1) +#define STV090x_P2_ACLC2S28 STV090x_Px_ACLC2S28(2) +#define STV090x_OFFST_Px_CAR2S2_8_ALPH_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_8_ALPH_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_E_FIELD 4 + +#define STV090x_Px_ACLC2S216A(__x) (0xf499 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2S216A STV090x_Px_ACLC2S216A(1) +#define STV090x_P2_ACLC2S216A STV090x_Px_ACLC2S216A(2) +#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD 4 + +#define STV090x_Px_ACLC2S232A(__x) (0xf49A - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2S232A STV090x_Px_ACLC2S232A(1) +#define STV090x_P2_ACLC2S232A STV090x_Px_ACLC2S232A(2) +#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_E_FIELD 4 + +#define STV090x_Px_BCLC2S2Q(__x) (0xf49c - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2S2Q STV090x_Px_BCLC2S2Q(1) +#define STV090x_P2_BCLC2S2Q STV090x_Px_BCLC2S2Q(2) +#define STV090x_OFFST_Px_CAR2S2_Q_BETA_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_Q_BETA_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_E_FIELD 4 + +#define STV090x_Px_BCLC2S28(__x) (0xf49d - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2S28 STV090x_Px_BCLC2S28(1) +#define STV090x_P2_BCLC2S28 STV090x_Px_BCLC2S28(2) +#define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD 4 + +#define STV090x_Px_BCLC2S216A(__x) (0xf49e - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2S216A STV090x_Px_BCLC2S216A(1) +#define STV090x_P2_BCLC2S216A STV090x_Px_BCLC2S216A(2) +#define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD 4 + +#define STV090x_Px_BCLC2S232A(__x) (0xf49f - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2S232A STV090x_Px_BCLC2S232A(1) +#define STV090x_P2_BCLC2S232A STV090x_Px_BCLC2S232A(2) +#define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_E_FIELD 4 + +#define STV090x_Px_PLROOT2(__x) (0xf4ac - (__x - 1) * 0x200) +#define STV090x_P1_PLROOT2 STV090x_Px_PLROOT2(1) +#define STV090x_P2_PLROOT2 STV090x_Px_PLROOT2(2) +#define STV090x_OFFST_Px_PLSCRAMB_MODE_FIELD 2 +#define STV090x_WIDTH_Px_PLSCRAMB_MODE_FIELD 2 +#define STV090x_OFFST_Px_PLSCRAMB_ROOT_FIELD 0 +#define STV090x_WIDTH_Px_PLSCRAMB_ROOT_FIELD 2 + +#define STV090x_Px_PLROOT1(__x) (0xf4ad - (__x - 1) * 0x200) +#define STV090x_P1_PLROOT1 STV090x_Px_PLROOT1(1) +#define STV090x_P2_PLROOT1 STV090x_Px_PLROOT1(2) +#define STV090x_OFFST_Px_PLSCRAMB_ROOT1_FIELD 0 +#define STV090x_WIDTH_Px_PLSCRAMB_ROOT1_FIELD 8 + +#define STV090x_Px_PLROOT0(__x) (0xf4ae - (__x - 1) * 0x200) +#define STV090x_P1_PLROOT0 STV090x_Px_PLROOT0(1) +#define STV090x_P2_PLROOT0 STV090x_Px_PLROOT0(2) +#define STV090x_OFFST_Px_PLSCRAMB_ROOT0_FIELD 0 +#define STV090x_WIDTH_Px_PLSCRAMB_ROOT0_FIELD 8 + +#define STV090x_Px_MODCODLST0(__x) (0xf4b0 - (__x - 1) * 0x200) /* check */ +#define STV090x_P1_MODCODLST0 STV090x_Px_MODCODLST0(1) +#define STV090x_P2_MODCODLST0 STV090x_Px_MODCODLST0(2) + +#define STV090x_Px_MODCODLST1(__x) (0xf4b1 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST1 STV090x_Px_MODCODLST1(1) +#define STV090x_P2_MODCODLST1 STV090x_Px_MODCODLST1(2) +#define STV090x_OFFST_Px_DIS_MODCOD29_FIELD 4 +#define STV090x_WIDTH_Px_DIS_MODCOD29_FIELD 4 +#define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD 0 +#define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD 4 + +#define STV090x_Px_MODCODLST2(__x) (0xf4b2 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST2 STV090x_Px_MODCODLST2(1) +#define STV090x_P2_MODCODLST2 STV090x_Px_MODCODLST2(2) +#define STV090x_OFFST_Px_DIS_32PSK_8_9_FIELD 4 +#define STV090x_WIDTH_Px_DIS_32PSK_8_9_FIELD 4 +#define STV090x_OFFST_Px_DIS_32PSK_5_6_FIELD 0 +#define STV090x_WIDTH_Px_DIS_32PSK_5_6_FIELD 4 + +#define STV090x_Px_MODCODLST3(__x) (0xf4b3 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST3 STV090x_Px_MODCODLST3(1) +#define STV090x_P2_MODCODLST3 STV090x_Px_MODCODLST3(2) +#define STV090x_OFFST_Px_DIS_32PSK_4_5_FIELD 4 +#define STV090x_WIDTH_Px_DIS_32PSK_4_5_FIELD 4 +#define STV090x_OFFST_Px_DIS_32PSK_3_4_FIELD 0 +#define STV090x_WIDTH_Px_DIS_32PSK_3_4_FIELD 4 + +#define STV090x_Px_MODCODLST4(__x) (0xf4b4 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST4 STV090x_Px_MODCODLST4(1) +#define STV090x_P2_MODCODLST4 STV090x_Px_MODCODLST4(2) +#define STV090x_OFFST_Px_DIS_16PSK_9_10_FIELD 4 +#define STV090x_WIDTH_Px_DIS_16PSK_9_10_FIELD 4 +#define STV090x_OFFST_Px_DIS_16PSK_8_9_FIELD 0 +#define STV090x_WIDTH_Px_DIS_16PSK_8_9_FIELD 4 + +#define STV090x_Px_MODCODLST5(__x) (0xf4b5 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST5 STV090x_Px_MODCODLST5(1) +#define STV090x_P2_MODCODLST5 STV090x_Px_MODCODLST5(2) +#define STV090x_OFFST_Px_DIS_16PSK_5_6_FIELD 4 +#define STV090x_WIDTH_Px_DIS_16PSK_5_6_FIELD 4 +#define STV090x_OFFST_Px_DIS_16PSK_4_5_FIELD 0 +#define STV090x_WIDTH_Px_DIS_16PSK_4_5_FIELD 4 + +#define STV090x_Px_MODCODLST6(__x) (0xf4b6 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST6 STV090x_Px_MODCODLST6(1) +#define STV090x_P2_MODCODLST6 STV090x_Px_MODCODLST6(2) +#define STV090x_OFFST_Px_DIS_16PSK_3_4_FIELD 4 +#define STV090x_WIDTH_Px_DIS_16PSK_3_4_FIELD 4 +#define STV090x_OFFST_Px_DIS_16PSK_2_3_FIELD 0 +#define STV090x_WIDTH_Px_DIS_16PSK_2_3_FIELD 4 + +#define STV090x_Px_MODCODLST7(__x) (0xf4b7 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST7 STV090x_Px_MODCODLST7(1) +#define STV090x_P2_MODCODLST7 STV090x_Px_MODCODLST7(2) +#define STV090x_OFFST_Px_DIS_8P_9_10_FIELD 4 +#define STV090x_WIDTH_Px_DIS_8P_9_10_FIELD 4 +#define STV090x_OFFST_Px_DIS_8P_8_9_FIELD 0 +#define STV090x_WIDTH_Px_DIS_8P_8_9_FIELD 4 + +#define STV090x_Px_MODCODLST8(__x) (0xf4b8 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST8 STV090x_Px_MODCODLST8(1) +#define STV090x_P2_MODCODLST8 STV090x_Px_MODCODLST8(2) +#define STV090x_OFFST_Px_DIS_8P_5_6_FIELD 4 +#define STV090x_WIDTH_Px_DIS_8P_5_6_FIELD 4 +#define STV090x_OFFST_Px_DIS_8P_3_4_FIELD 0 +#define STV090x_WIDTH_Px_DIS_8P_3_4_FIELD 4 + +#define STV090x_Px_MODCODLST9(__x) (0xf4b9 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST9 STV090x_Px_MODCODLST9(1) +#define STV090x_P2_MODCODLST9 STV090x_Px_MODCODLST9(2) +#define STV090x_OFFST_Px_DIS_8P_2_3_FIELD 4 +#define STV090x_WIDTH_Px_DIS_8P_2_3_FIELD 4 +#define STV090x_OFFST_Px_DIS_8P_3_5_FIELD 0 +#define STV090x_WIDTH_Px_DIS_8P_3_5_FIELD 4 + +#define STV090x_Px_MODCODLSTA(__x) (0xf4ba - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTA STV090x_Px_MODCODLSTA(1) +#define STV090x_P2_MODCODLSTA STV090x_Px_MODCODLSTA(2) +#define STV090x_OFFST_Px_DIS_QP_9_10_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_9_10_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_8_9_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_8_9_FIELD 4 + +#define STV090x_Px_MODCODLSTB(__x) (0xf4bb - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTB STV090x_Px_MODCODLSTB(1) +#define STV090x_P2_MODCODLSTB STV090x_Px_MODCODLSTB(2) +#define STV090x_OFFST_Px_DIS_QP_5_6_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_5_6_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_4_5_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_4_5_FIELD 4 + +#define STV090x_Px_MODCODLSTC(__x) (0xf4bc - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTC STV090x_Px_MODCODLSTC(1) +#define STV090x_P2_MODCODLSTC STV090x_Px_MODCODLSTC(2) +#define STV090x_OFFST_Px_DIS_QP_3_4_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_3_4_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_2_3_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_2_3_FIELD 4 + +#define STV090x_Px_MODCODLSTD(__x) (0xf4bd - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTD STV090x_Px_MODCODLSTD(1) +#define STV090x_P2_MODCODLSTD STV090x_Px_MODCODLSTD(2) +#define STV090x_OFFST_Px_DIS_QP_3_5_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_3_5_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_1_2_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_1_2_FIELD 4 + +#define STV090x_Px_MODCODLSTE(__x) (0xf4be - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTE STV090x_Px_MODCODLSTE(1) +#define STV090x_P2_MODCODLSTE STV090x_Px_MODCODLSTE(2) +#define STV090x_OFFST_Px_DIS_QP_2_5_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_2_5_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_1_3_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_1_3_FIELD 4 + +#define STV090x_Px_MODCODLSTF(__x) (0xf4bf - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTF STV090x_Px_MODCODLSTF(1) +#define STV090x_P2_MODCODLSTF STV090x_Px_MODCODLSTF(2) +#define STV090x_OFFST_Px_DIS_QP_1_4_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_1_4_FIELD 4 + +#define STV090x_Px_GAUSSR0(__x) (0xf4c0 - (__x - 1) * 0x200) +#define STV090x_P1_GAUSSR0 STV090x_Px_GAUSSR0(1) +#define STV090x_P2_GAUSSR0 STV090x_Px_GAUSSR0(2) +#define STV090x_OFFST_Px_EN_CCIMODE_FIELD 7 +#define STV090x_WIDTH_Px_EN_CCIMODE_FIELD 1 +#define STV090x_OFFST_Px_R0_GAUSSIEN_FIELD 0 +#define STV090x_WIDTH_Px_R0_GAUSSIEN_FIELD 7 + +#define STV090x_Px_CCIR0(__x) (0xf4c1 - (__x - 1) * 0x200) +#define STV090x_P1_CCIR0 STV090x_Px_CCIR0(1) +#define STV090x_P2_CCIR0 STV090x_Px_CCIR0(2) +#define STV090x_OFFST_Px_CCIDETECT_PLH_FIELD 7 +#define STV090x_WIDTH_Px_CCIDETECT_PLH_FIELD 1 +#define STV090x_OFFST_Px_R0_CCI_FIELD 0 +#define STV090x_WIDTH_Px_R0_CCI_FIELD 7 + +#define STV090x_Px_CCIQUANT(__x) (0xf4c2 - (__x - 1) * 0x200) +#define STV090x_P1_CCIQUANT STV090x_Px_CCIQUANT(1) +#define STV090x_P2_CCIQUANT STV090x_Px_CCIQUANT(2) +#define STV090x_OFFST_Px_CCI_BETA_FIELD 5 +#define STV090x_WIDTH_Px_CCI_BETA_FIELD 3 +#define STV090x_OFFST_Px_CCI_QUANT_FIELD 0 +#define STV090x_WIDTH_Px_CCI_QUANT_FIELD 5 + +#define STV090x_Px_CCITHRESH(__x) (0xf4c3 - (__x - 1) * 0x200) +#define STV090x_P1_CCITHRESH STV090x_Px_CCITHRESH(1) +#define STV090x_P2_CCITHRESH STV090x_Px_CCITHRESH(2) +#define STV090x_OFFST_Px_CCI_THRESHOLD_FIELD 0 +#define STV090x_WIDTH_Px_CCI_THRESHOLD_FIELD 8 + +#define STV090x_Px_CCIACC(__x) (0xf4c4 - (__x - 1) * 0x200) +#define STV090x_P1_CCIACC STV090x_Px_CCIACC(1) +#define STV090x_P2_CCIACC STV090x_Px_CCIACC(2) +#define STV090x_OFFST_Px_CCI_VALUE_FIELD 0 +#define STV090x_WIDTH_Px_CCI_VALUE_FIELD 8 + +#define STV090x_Px_DMDRESCFG(__x) (0xF4C6 - (__x - 1) * 0x200) +#define STV090x_P1_DMDRESCFG STV090x_Px_DMDRESCFG(1) +#define STV090x_P2_DMDRESCFG STV090x_Px_DMDRESCFG(2) +#define STV090x_OFFST_Px_DMDRES_RESET_FIELD 7 +#define STV090x_WIDTH_Px_DMDRES_RESET_FIELD 1 + +#define STV090x_Px_DMDRESADR(__x) (0xF4C7 - (__x - 1) * 0x200) +#define STV090x_P1_DMDRESADR STV090x_Px_DMDRESADR(1) +#define STV090x_P2_DMDRESADR STV090x_Px_DMDRESADR(2) +#define STV090x_OFFST_Px_DMDRES_RESNBR_FIELD 0 +#define STV090x_WIDTH_Px_DMDRES_RESNBR_FIELD 4 + +#define STV090x_Px_DMDRESDATAy(__x, __y) (0xF4C8 - (__x - 1) * 0x200 + (7 - __y)) +#define STV090x_P1_DMDRESDATA0 STV090x_Px_DMDRESDATAy(1, 0) +#define STV090x_P1_DMDRESDATA1 STV090x_Px_DMDRESDATAy(1, 1) +#define STV090x_P1_DMDRESDATA2 STV090x_Px_DMDRESDATAy(1, 2) +#define STV090x_P1_DMDRESDATA3 STV090x_Px_DMDRESDATAy(1, 3) +#define STV090x_P1_DMDRESDATA4 STV090x_Px_DMDRESDATAy(1, 4) +#define STV090x_P1_DMDRESDATA5 STV090x_Px_DMDRESDATAy(1, 5) +#define STV090x_P1_DMDRESDATA6 STV090x_Px_DMDRESDATAy(1, 6) +#define STV090x_P1_DMDRESDATA7 STV090x_Px_DMDRESDATAy(1, 7) +#define STV090x_P2_DMDRESDATA0 STV090x_Px_DMDRESDATAy(2, 0) +#define STV090x_P2_DMDRESDATA1 STV090x_Px_DMDRESDATAy(2, 1) +#define STV090x_P2_DMDRESDATA2 STV090x_Px_DMDRESDATAy(2, 2) +#define STV090x_P2_DMDRESDATA3 STV090x_Px_DMDRESDATAy(2, 3) +#define STV090x_P2_DMDRESDATA4 STV090x_Px_DMDRESDATAy(2, 4) +#define STV090x_P2_DMDRESDATA5 STV090x_Px_DMDRESDATAy(2, 5) +#define STV090x_P2_DMDRESDATA6 STV090x_Px_DMDRESDATAy(2, 6) +#define STV090x_P2_DMDRESDATA7 STV090x_Px_DMDRESDATAy(2, 7) +#define STV090x_OFFST_Px_DMDRES_DATA_FIELD 0 +#define STV090x_WIDTH_Px_DMDRES_DATA_FIELD 8 + +#define STV090x_Px_FFEIy(__x, __y) (0xf4d0 - (__x - 1) * 0x200 + 0x2 * (__y - 1)) +#define STV090x_P1_FFEI1 STV090x_Px_FFEIy(1, 1) +#define STV090x_P1_FFEI2 STV090x_Px_FFEIy(1, 2) +#define STV090x_P1_FFEI3 STV090x_Px_FFEIy(1, 3) +#define STV090x_P1_FFEI4 STV090x_Px_FFEIy(1, 4) +#define STV090x_P2_FFEI1 STV090x_Px_FFEIy(2, 1) +#define STV090x_P2_FFEI2 STV090x_Px_FFEIy(2, 2) +#define STV090x_P2_FFEI3 STV090x_Px_FFEIy(2, 3) +#define STV090x_P2_FFEI4 STV090x_Px_FFEIy(2, 4) +#define STV090x_OFFST_Px_FFE_ACCIy_FIELD 0 +#define STV090x_WIDTH_Px_FFE_ACCIy_FIELD 8 + +#define STV090x_Px_FFEQy(__x, __y) (0xf4d1 - (__x - 1) * 0x200 + 0x2 * (__y - 1)) +#define STV090x_P1_FFEQ1 STV090x_Px_FFEQy(1, 1) +#define STV090x_P1_FFEQ2 STV090x_Px_FFEQy(1, 2) +#define STV090x_P1_FFEQ3 STV090x_Px_FFEQy(1, 3) +#define STV090x_P1_FFEQ4 STV090x_Px_FFEQy(1, 4) +#define STV090x_P2_FFEQ1 STV090x_Px_FFEQy(2, 1) +#define STV090x_P2_FFEQ2 STV090x_Px_FFEQy(2, 2) +#define STV090x_P2_FFEQ3 STV090x_Px_FFEQy(2, 3) +#define STV090x_P2_FFEQ4 STV090x_Px_FFEQy(2, 4) +#define STV090x_OFFST_Px_FFE_ACCQy_FIELD 0 +#define STV090x_WIDTH_Px_FFE_ACCQy_FIELD 8 + +#define STV090x_Px_FFECFG(__x) (0xf4d8 - (__x - 1) * 0x200) +#define STV090x_P1_FFECFG STV090x_Px_FFECFG(1) +#define STV090x_P2_FFECFG STV090x_Px_FFECFG(2) +#define STV090x_OFFST_Px_EQUALFFE_ON_FIELD 6 +#define STV090x_WIDTH_Px_EQUALFFE_ON_FIELD 1 + +#define STV090x_Px_SMAPCOEF7(__x) (0xf500 - (__x - 1) * 0x200) +#define STV090x_P1_SMAPCOEF7 STV090x_Px_SMAPCOEF7(1) +#define STV090x_P2_SMAPCOEF7 STV090x_Px_SMAPCOEF7(2) +#define STV090x_OFFST_Px_DIS_QSCALE_FIELD 7 +#define STV090x_WIDTH_Px_DIS_QSCALE_FIELD 1 +#define STV090x_OFFST_Px_SMAPCOEF_Q_LLR12_FIELD 0 +#define STV090x_WIDTH_Px_SMAPCOEF_Q_LLR12_FIELD 7 + +#define STV090x_Px_SMAPCOEF6(__x) (0xf501 - (__x - 1) * 0x200) +#define STV090x_P1_SMAPCOEF6 STV090x_Px_SMAPCOEF6(1) +#define STV090x_P2_SMAPCOEF6 STV090x_Px_SMAPCOEF6(2) +#define STV090x_OFFST_Px_ADJ_8PSKLLR1_FIELD 2 +#define STV090x_WIDTH_Px_ADJ_8PSKLLR1_FIELD 1 +#define STV090x_OFFST_Px_OLD_8PSKLLR1_FIELD 1 +#define STV090x_WIDTH_Px_OLD_8PSKLLR1_FIELD 1 +#define STV090x_OFFST_Px_DIS_AB8PSK_FIELD 0 +#define STV090x_WIDTH_Px_DIS_AB8PSK_FIELD 1 + +#define STV090x_Px_SMAPCOEF5(__x) (0xf502 - (__x - 1) * 0x200) +#define STV090x_P1_SMAPCOEF5 STV090x_Px_SMAPCOEF5(1) +#define STV090x_P2_SMAPCOEF5 STV090x_Px_SMAPCOEF5(2) +#define STV090x_OFFST_Px_DIS_8SCALE_FIELD 7 +#define STV090x_WIDTH_Px_DIS_8SCALE_FIELD 1 +#define STV090x_OFFST_Px_SMAPCOEF_8P_LLR23_FIELD 0 +#define STV090x_WIDTH_Px_SMAPCOEF_8P_LLR23_FIELD 7 + +#define STV090x_Px_DMDPLHSTAT(__x) (0xF520 - (__x - 1) * 0x200) +#define STV090x_P1_DMDPLHSTAT STV090x_Px_DMDPLHSTAT(1) +#define STV090x_P2_DMDPLHSTAT STV090x_Px_DMDPLHSTAT(2) +#define STV090x_OFFST_Px_PLH_STATISTIC_FIELD 0 +#define STV090x_WIDTH_Px_PLH_STATISTIC_FIELD 8 + +#define STV090x_Px_LOCKTIMEy(__x, __y) (0xF525 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_LOCKTIME0 STV090x_Px_LOCKTIMEy(1, 0) +#define STV090x_P1_LOCKTIME1 STV090x_Px_LOCKTIMEy(1, 1) +#define STV090x_P1_LOCKTIME2 STV090x_Px_LOCKTIMEy(1, 2) +#define STV090x_P1_LOCKTIME3 STV090x_Px_LOCKTIMEy(1, 3) +#define STV090x_P2_LOCKTIME0 STV090x_Px_LOCKTIMEy(2, 0) +#define STV090x_P2_LOCKTIME1 STV090x_Px_LOCKTIMEy(2, 1) +#define STV090x_P2_LOCKTIME2 STV090x_Px_LOCKTIMEy(2, 2) +#define STV090x_P2_LOCKTIME3 STV090x_Px_LOCKTIMEy(2, 3) +#define STV090x_OFFST_Px_DEMOD_LOCKTIME_FIELD 0 +#define STV090x_WIDTH_Px_DEMOD_LOCKTIME_FIELD 8 + +#define STV090x_Px_TNRCFG(__x) (0xf4e0 - (__x - 1) * 0x200) /* check */ +#define STV090x_P1_TNRCFG STV090x_Px_TNRCFG(1) +#define STV090x_P2_TNRCFG STV090x_Px_TNRCFG(2) + +#define STV090x_Px_TNRCFG2(__x) (0xf4e1 - (__x - 1) * 0x200) +#define STV090x_P1_TNRCFG2 STV090x_Px_TNRCFG2(1) +#define STV090x_P2_TNRCFG2 STV090x_Px_TNRCFG2(2) +#define STV090x_OFFST_Px_TUN_IQSWAP_FIELD 7 +#define STV090x_WIDTH_Px_TUN_IQSWAP_FIELD 1 + +#define STV090x_Px_VITSCALE(__x) (0xf532 - (__x - 1) * 0x200) +#define STV090x_P1_VITSCALE STV090x_Px_VITSCALE(1) +#define STV090x_P2_VITSCALE STV090x_Px_VITSCALE(2) +#define STV090x_OFFST_Px_NVTH_NOSRANGE_FIELD 7 +#define STV090x_WIDTH_Px_NVTH_NOSRANGE_FIELD 1 +#define STV090x_OFFST_Px_VERROR_MAXMODE_FIELD 6 +#define STV090x_WIDTH_Px_VERROR_MAXMODE_FIELD 1 +#define STV090x_OFFST_Px_NSLOWSN_LOCKED_FIELD 3 +#define STV090x_WIDTH_Px_NSLOWSN_LOCKED_FIELD 1 +#define STV090x_OFFST_Px_DIS_RSFLOCK_FIELD 1 +#define STV090x_WIDTH_Px_DIS_RSFLOCK_FIELD 1 + +#define STV090x_Px_FECM(__x) (0xf533 - (__x - 1) * 0x200) +#define STV090x_P1_FECM STV090x_Px_FECM(1) +#define STV090x_P2_FECM STV090x_Px_FECM(2) +#define STV090x_OFFST_Px_DSS_DVB_FIELD 7 +#define STV090x_WIDTH_Px_DSS_DVB_FIELD 1 +#define STV090x_OFFST_Px_DSS_SRCH_FIELD 4 +#define STV090x_WIDTH_Px_DSS_SRCH_FIELD 1 +#define STV090x_OFFST_Px_SYNCVIT_FIELD 1 +#define STV090x_WIDTH_Px_SYNCVIT_FIELD 1 +#define STV090x_OFFST_Px_IQINV_FIELD 0 +#define STV090x_WIDTH_Px_IQINV_FIELD 1 + +#define STV090x_Px_VTH12(__x) (0xf534 - (__x - 1) * 0x200) +#define STV090x_P1_VTH12 STV090x_Px_VTH12(1) +#define STV090x_P2_VTH12 STV090x_Px_VTH12(2) +#define STV090x_OFFST_Px_VTH12_FIELD 0 +#define STV090x_WIDTH_Px_VTH12_FIELD 8 + +#define STV090x_Px_VTH23(__x) (0xf535 - (__x - 1) * 0x200) +#define STV090x_P1_VTH23 STV090x_Px_VTH23(1) +#define STV090x_P2_VTH23 STV090x_Px_VTH23(2) +#define STV090x_OFFST_Px_VTH23_FIELD 0 +#define STV090x_WIDTH_Px_VTH23_FIELD 8 + +#define STV090x_Px_VTH34(__x) (0xf536 - (__x - 1) * 0x200) +#define STV090x_P1_VTH34 STV090x_Px_VTH34(1) +#define STV090x_P2_VTH34 STV090x_Px_VTH34(2) +#define STV090x_OFFST_Px_VTH34_FIELD 0 +#define STV090x_WIDTH_Px_VTH34_FIELD 8 + +#define STV090x_Px_VTH56(__x) (0xf537 - (__x - 1) * 0x200) +#define STV090x_P1_VTH56 STV090x_Px_VTH56(1) +#define STV090x_P2_VTH56 STV090x_Px_VTH56(2) +#define STV090x_OFFST_Px_VTH56_FIELD 0 +#define STV090x_WIDTH_Px_VTH56_FIELD 8 + +#define STV090x_Px_VTH67(__x) (0xf538 - (__x - 1) * 0x200) +#define STV090x_P1_VTH67 STV090x_Px_VTH67(1) +#define STV090x_P2_VTH67 STV090x_Px_VTH67(2) +#define STV090x_OFFST_Px_VTH67_FIELD 0 +#define STV090x_WIDTH_Px_VTH67_FIELD 8 + +#define STV090x_Px_VTH78(__x) (0xf539 - (__x - 1) * 0x200) +#define STV090x_P1_VTH78 STV090x_Px_VTH78(1) +#define STV090x_P2_VTH78 STV090x_Px_VTH78(2) +#define STV090x_OFFST_Px_VTH78_FIELD 0 +#define STV090x_WIDTH_Px_VTH78_FIELD 8 + +#define STV090x_Px_VITCURPUN(__x) (0xf53a - (__x - 1) * 0x200) +#define STV090x_P1_VITCURPUN STV090x_Px_VITCURPUN(1) +#define STV090x_P2_VITCURPUN STV090x_Px_VITCURPUN(2) +#define STV090x_OFFST_Px_VIT_CURPUN_FIELD 0 +#define STV090x_WIDTH_Px_VIT_CURPUN_FIELD 5 + +#define STV090x_Px_VERROR(__x) (0xf53b - (__x - 1) * 0x200) +#define STV090x_P1_VERROR STV090x_Px_VERROR(1) +#define STV090x_P2_VERROR STV090x_Px_VERROR(2) +#define STV090x_OFFST_Px_REGERR_VIT_FIELD 0 +#define STV090x_WIDTH_Px_REGERR_VIT_FIELD 8 + +#define STV090x_Px_PRVIT(__x) (0xf53c - (__x - 1) * 0x200) +#define STV090x_P1_PRVIT STV090x_Px_PRVIT(1) +#define STV090x_P2_PRVIT STV090x_Px_PRVIT(2) +#define STV090x_OFFST_Px_DIS_VTHLOCK_FIELD 6 +#define STV090x_WIDTH_Px_DIS_VTHLOCK_FIELD 1 +#define STV090x_OFFST_Px_E7_8VIT_FIELD 5 +#define STV090x_WIDTH_Px_E7_8VIT_FIELD 1 +#define STV090x_OFFST_Px_E6_7VIT_FIELD 4 +#define STV090x_WIDTH_Px_E6_7VIT_FIELD 1 +#define STV090x_OFFST_Px_E5_6VIT_FIELD 3 +#define STV090x_WIDTH_Px_E5_6VIT_FIELD 1 +#define STV090x_OFFST_Px_E3_4VIT_FIELD 2 +#define STV090x_WIDTH_Px_E3_4VIT_FIELD 1 +#define STV090x_OFFST_Px_E2_3VIT_FIELD 1 +#define STV090x_WIDTH_Px_E2_3VIT_FIELD 1 +#define STV090x_OFFST_Px_E1_2VIT_FIELD 0 +#define STV090x_WIDTH_Px_E1_2VIT_FIELD 1 + +#define STV090x_Px_VAVSRVIT(__x) (0xf53d - (__x - 1) * 0x200) +#define STV090x_P1_VAVSRVIT STV090x_Px_VAVSRVIT(1) +#define STV090x_P2_VAVSRVIT STV090x_Px_VAVSRVIT(2) +#define STV090x_OFFST_Px_SNVIT_FIELD 4 +#define STV090x_WIDTH_Px_SNVIT_FIELD 2 +#define STV090x_OFFST_Px_TOVVIT_FIELD 2 +#define STV090x_WIDTH_Px_TOVVIT_FIELD 2 +#define STV090x_OFFST_Px_HYPVIT_FIELD 0 +#define STV090x_WIDTH_Px_HYPVIT_FIELD 2 + +#define STV090x_Px_VSTATUSVIT(__x) (0xf53e - (__x - 1) * 0x200) +#define STV090x_P1_VSTATUSVIT STV090x_Px_VSTATUSVIT(1) +#define STV090x_P2_VSTATUSVIT STV090x_Px_VSTATUSVIT(2) +#define STV090x_OFFST_Px_PRFVIT_FIELD 4 +#define STV090x_WIDTH_Px_PRFVIT_FIELD 1 +#define STV090x_OFFST_Px_LOCKEDVIT_FIELD 3 +#define STV090x_WIDTH_Px_LOCKEDVIT_FIELD 1 + +#define STV090x_Px_VTHINUSE(__x) (0xf53f - (__x - 1) * 0x200) +#define STV090x_P1_VTHINUSE STV090x_Px_VTHINUSE(1) +#define STV090x_P2_VTHINUSE STV090x_Px_VTHINUSE(2) +#define STV090x_OFFST_Px_VIT_INUSE_FIELD 0 +#define STV090x_WIDTH_Px_VIT_INUSE_FIELD 8 + +#define STV090x_Px_KDIV12(__x) (0xf540 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV12 STV090x_Px_KDIV12(1) +#define STV090x_P2_KDIV12 STV090x_Px_KDIV12(2) +#define STV090x_OFFST_Px_K_DIVIDER_12_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_12_FIELD 7 + +#define STV090x_Px_KDIV23(__x) (0xf541 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV23 STV090x_Px_KDIV23(1) +#define STV090x_P2_KDIV23 STV090x_Px_KDIV23(2) +#define STV090x_OFFST_Px_K_DIVIDER_23_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_23_FIELD 7 + +#define STV090x_Px_KDIV34(__x) (0xf542 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV34 STV090x_Px_KDIV34(1) +#define STV090x_P2_KDIV34 STV090x_Px_KDIV34(2) +#define STV090x_OFFST_Px_K_DIVIDER_34_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_34_FIELD 7 + +#define STV090x_Px_KDIV56(__x) (0xf543 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV56 STV090x_Px_KDIV56(1) +#define STV090x_P2_KDIV56 STV090x_Px_KDIV56(2) +#define STV090x_OFFST_Px_K_DIVIDER_56_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_56_FIELD 7 + +#define STV090x_Px_KDIV67(__x) (0xf544 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV67 STV090x_Px_KDIV67(1) +#define STV090x_P2_KDIV67 STV090x_Px_KDIV67(2) +#define STV090x_OFFST_Px_K_DIVIDER_67_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_67_FIELD 7 + +#define STV090x_Px_KDIV78(__x) (0xf545 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV78 STV090x_Px_KDIV78(1) +#define STV090x_P2_KDIV78 STV090x_Px_KDIV78(2) +#define STV090x_OFFST_Px_K_DIVIDER_78_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_78_FIELD 7 + +#define STV090x_Px_PDELCTRL1(__x) (0xf550 - (__x - 1) * 0x200) +#define STV090x_P1_PDELCTRL1 STV090x_Px_PDELCTRL1(1) +#define STV090x_P2_PDELCTRL1 STV090x_Px_PDELCTRL1(2) +#define STV090x_OFFST_Px_INV_MISMASK_FIELD 7 +#define STV090x_WIDTH_Px_INV_MISMASK_FIELD 1 +#define STV090x_OFFST_Px_FILTER_EN_FIELD 5 +#define STV090x_WIDTH_Px_FILTER_EN_FIELD 1 +#define STV090x_OFFST_Px_EN_MIS00_FIELD 1 +#define STV090x_WIDTH_Px_EN_MIS00_FIELD 1 +#define STV090x_OFFST_Px_ALGOSWRST_FIELD 0 +#define STV090x_WIDTH_Px_ALGOSWRST_FIELD 1 + +#define STV090x_Px_PDELCTRL2(__x) (0xf551 - (__x - 1) * 0x200) +#define STV090x_P1_PDELCTRL2 STV090x_Px_PDELCTRL2(1) +#define STV090x_P2_PDELCTRL2 STV090x_Px_PDELCTRL2(2) +#define STV090x_OFFST_Px_FORCE_CONTINUOUS 7 +#define STV090x_WIDTH_Px_FORCE_CONTINUOUS 1 +#define STV090x_OFFST_Px_RESET_UPKO_COUNT 6 +#define STV090x_WIDTH_Px_RESET_UPKO_COUNT 1 +#define STV090x_OFFST_Px_USER_PKTDELIN_NB 5 +#define STV090x_WIDTH_Px_USER_PKTDELIN_NB 1 +#define STV090x_OFFST_Px_FORCE_LOCKED 4 +#define STV090x_WIDTH_Px_FORCE_LOCKED 1 +#define STV090x_OFFST_Px_DATA_UNBBSCRAM 3 +#define STV090x_WIDTH_Px_DATA_UNBBSCRAM 1 +#define STV090x_OFFST_Px_FORCE_LONGPACKET 2 +#define STV090x_WIDTH_Px_FORCE_LONGPACKET 1 +#define STV090x_OFFST_Px_FRAME_MODE_FIELD 1 +#define STV090x_WIDTH_Px_FRAME_MODE_FIELD 1 + +#define STV090x_Px_HYSTTHRESH(__x) (0xf554 - (__x - 1) * 0x200) +#define STV090x_P1_HYSTTHRESH STV090x_Px_HYSTTHRESH(1) +#define STV090x_P2_HYSTTHRESH STV090x_Px_HYSTTHRESH(2) +#define STV090x_OFFST_Px_UNLCK_THRESH_FIELD 4 +#define STV090x_WIDTH_Px_UNLCK_THRESH_FIELD 4 +#define STV090x_OFFST_Px_DELIN_LCK_THRESH_FIELD 0 +#define STV090x_WIDTH_Px_DELIN_LCK_THRESH_FIELD 4 + +#define STV090x_Px_ISIENTRY(__x) (0xf55e - (__x - 1) * 0x200) +#define STV090x_P1_ISIENTRY STV090x_Px_ISIENTRY(1) +#define STV090x_P2_ISIENTRY STV090x_Px_ISIENTRY(2) +#define STV090x_OFFST_Px_ISI_ENTRY_FIELD 0 +#define STV090x_WIDTH_Px_ISI_ENTRY_FIELD 8 + +#define STV090x_Px_ISIBITENA(__x) (0xf55f - (__x - 1) * 0x200) +#define STV090x_P1_ISIBITENA STV090x_Px_ISIBITENA(1) +#define STV090x_P2_ISIBITENA STV090x_Px_ISIBITENA(2) +#define STV090x_OFFST_Px_ISI_BIT_EN_FIELD 0 +#define STV090x_WIDTH_Px_ISI_BIT_EN_FIELD 8 + +#define STV090x_Px_MATSTRy(__x, __y) (0xf561 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_MATSTR0 STV090x_Px_MATSTRy(1, 0) +#define STV090x_P1_MATSTR1 STV090x_Px_MATSTRy(1, 1) +#define STV090x_P2_MATSTR0 STV090x_Px_MATSTRy(2, 0) +#define STV090x_P2_MATSTR1 STV090x_Px_MATSTRy(2, 1) +#define STV090x_OFFST_Px_MATYPE_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_MATYPE_CURRENT_FIELD 8 + +#define STV090x_Px_UPLSTRy(__x, __y) (0xf563 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_UPLSTR0 STV090x_Px_UPLSTRy(1, 0) +#define STV090x_P1_UPLSTR1 STV090x_Px_UPLSTRy(1, 1) +#define STV090x_P2_UPLSTR0 STV090x_Px_UPLSTRy(2, 0) +#define STV090x_P2_UPLSTR1 STV090x_Px_UPLSTRy(2, 1) +#define STV090x_OFFST_Px_UPL_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_UPL_CURRENT_FIELD 8 + +#define STV090x_Px_DFLSTRy(__x, __y) (0xf565 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_DFLSTR0 STV090x_Px_DFLSTRy(1, 0) +#define STV090x_P1_DFLSTR1 STV090x_Px_DFLSTRy(1, 1) +#define STV090x_P2_DFLSTR0 STV090x_Px_DFLSTRy(2, 0) +#define STV090x_P2_DFLSTR1 STV090x_Px_DFLSTRy(2, 1) +#define STV090x_OFFST_Px_DFL_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_DFL_CURRENT_FIELD 8 + +#define STV090x_Px_SYNCSTR(__x) (0xf566 - (__x - 1) * 0x200) +#define STV090x_P1_SYNCSTR STV090x_Px_SYNCSTR(1) +#define STV090x_P2_SYNCSTR STV090x_Px_SYNCSTR(2) +#define STV090x_OFFST_Px_SYNC_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_SYNC_CURRENT_FIELD 8 + +#define STV090x_Px_SYNCDSTRy(__x, __y) (0xf568 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_SYNCDSTR0 STV090x_Px_SYNCDSTRy(1, 0) +#define STV090x_P1_SYNCDSTR1 STV090x_Px_SYNCDSTRy(1, 1) +#define STV090x_P2_SYNCDSTR0 STV090x_Px_SYNCDSTRy(2, 0) +#define STV090x_P2_SYNCDSTR1 STV090x_Px_SYNCDSTRy(2, 1) +#define STV090x_OFFST_Px_SYNCD_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_SYNCD_CURRENT_FIELD 8 + +#define STV090x_Px_PDELSTATUS1(__x) (0xf569 - (__x - 1) * 0x200) +#define STV090x_P1_PDELSTATUS1 STV090x_Px_PDELSTATUS1(1) +#define STV090x_P2_PDELSTATUS1 STV090x_Px_PDELSTATUS1(2) +#define STV090x_OFFST_Px_PKTDELIN_LOCK_FIELD 1 +#define STV090x_WIDTH_Px_PKTDELIN_LOCK_FIELD 1 +#define STV090x_OFFST_Px_FIRST_LOCK_FIELD 0 +#define STV090x_WIDTH_Px_FIRST_LOCK_FIELD 1 + +#define STV090x_Px_PDELSTATUS2(__x) (0xf56a - (__x - 1) * 0x200) +#define STV090x_P1_PDELSTATUS2 STV090x_Px_PDELSTATUS2(1) +#define STV090x_P2_PDELSTATUS2 STV090x_Px_PDELSTATUS2(2) +#define STV090x_OFFST_Px_FRAME_MODCOD_FIELD 2 +#define STV090x_WIDTH_Px_FRAME_MODCOD_FIELD 5 +#define STV090x_OFFST_Px_FRAME_TYPE_FIELD 0 +#define STV090x_WIDTH_Px_FRAME_TYPE_FIELD 2 + +#define STV090x_Px_BBFCRCKO1(__x) (0xf56b - (__x - 1) * 0x200) +#define STV090x_P1_BBFCRCKO1 STV090x_Px_BBFCRCKO1(1) +#define STV090x_P2_BBFCRCKO1 STV090x_Px_BBFCRCKO1(2) +#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD 0 +#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD 8 + +#define STV090x_Px_BBFCRCKO0(__x) (0xf56c - (__x - 1) * 0x200) +#define STV090x_P1_BBFCRCKO0 STV090x_Px_BBFCRCKO0(1) +#define STV090x_P2_BBFCRCKO0 STV090x_Px_BBFCRCKO0(2) +#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD 0 +#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD 8 + +#define STV090x_Px_UPCRCKO1(__x) (0xf56d - (__x - 1) * 0x200) +#define STV090x_P1_UPCRCKO1 STV090x_Px_UPCRCKO1(1) +#define STV090x_P2_UPCRCKO1 STV090x_Px_UPCRCKO1(2) +#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD 0 +#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD 8 + +#define STV090x_Px_UPCRCKO0(__x) (0xf56e - (__x - 1) * 0x200) +#define STV090x_P1_UPCRCKO0 STV090x_Px_UPCRCKO0(1) +#define STV090x_P2_UPCRCKO0 STV090x_Px_UPCRCKO0(2) +#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD 0 +#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD 8 + +#define STV090x_NBITER_NFx(__x) (0xFA03 + (__x - 4) * 0x1) +#define STV090x_NBITER_NF4 STV090x_NBITER_NFx(4) +#define STV090x_NBITER_NF5 STV090x_NBITER_NFx(5) +#define STV090x_NBITER_NF6 STV090x_NBITER_NFx(6) +#define STV090x_NBITER_NF7 STV090x_NBITER_NFx(7) +#define STV090x_NBITER_NF8 STV090x_NBITER_NFx(8) +#define STV090x_NBITER_NF9 STV090x_NBITER_NFx(9) +#define STV090x_NBITER_NF10 STV090x_NBITER_NFx(10) +#define STV090x_NBITER_NF11 STV090x_NBITER_NFx(11) +#define STV090x_NBITER_NF12 STV090x_NBITER_NFx(12) +#define STV090x_NBITER_NF13 STV090x_NBITER_NFx(13) +#define STV090x_NBITER_NF14 STV090x_NBITER_NFx(14) +#define STV090x_NBITER_NF15 STV090x_NBITER_NFx(15) +#define STV090x_NBITER_NF16 STV090x_NBITER_NFx(16) +#define STV090x_NBITER_NF17 STV090x_NBITER_NFx(17) + +#define STV090x_NBITERNOERR 0xFA3F +#define STV090x_OFFST_NBITER_STOP_CRIT_FIELD 0 +#define STV090x_WIDTH_NBITER_STOP_CRIT_FIELD 4 + +#define STV090x_GAINLLR_NFx(__x) (0xFA43 + (__x - 4) * 0x1) +#define STV090x_GAINLLR_NF4 STV090x_GAINLLR_NFx(4) +#define STV090x_OFFST_GAINLLR_NF_QP_1_2_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_1_2_FIELD 7 + +#define STV090x_GAINLLR_NF5 STV090x_GAINLLR_NFx(5) +#define STV090x_OFFST_GAINLLR_NF_QP_3_5_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_3_5_FIELD 7 + +#define STV090x_GAINLLR_NF6 STV090x_GAINLLR_NFx(6) +#define STV090x_OFFST_GAINLLR_NF_QP_2_3_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_2_3_FIELD 7 + +#define STV090x_GAINLLR_NF7 STV090x_GAINLLR_NFx(7) +#define STV090x_OFFST_GAINLLR_NF_QP_3_4_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_3_4_FIELD 7 + +#define STV090x_GAINLLR_NF8 STV090x_GAINLLR_NFx(8) +#define STV090x_OFFST_GAINLLR_NF_QP_4_5_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_4_5_FIELD 7 + +#define STV090x_GAINLLR_NF9 STV090x_GAINLLR_NFx(9) +#define STV090x_OFFST_GAINLLR_NF_QP_5_6_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_5_6_FIELD 7 + +#define STV090x_GAINLLR_NF10 STV090x_GAINLLR_NFx(10) +#define STV090x_OFFST_GAINLLR_NF_QP_8_9_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_8_9_FIELD 7 + +#define STV090x_GAINLLR_NF11 STV090x_GAINLLR_NFx(11) +#define STV090x_OFFST_GAINLLR_NF_QP_9_10_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_9_10_FIELD 7 + +#define STV090x_GAINLLR_NF12 STV090x_GAINLLR_NFx(12) +#define STV090x_OFFST_GAINLLR_NF_8P_3_5_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_3_5_FIELD 7 + +#define STV090x_GAINLLR_NF13 STV090x_GAINLLR_NFx(13) +#define STV090x_OFFST_GAINLLR_NF_8P_2_3_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_2_3_FIELD 7 + +#define STV090x_GAINLLR_NF14 STV090x_GAINLLR_NFx(14) +#define STV090x_OFFST_GAINLLR_NF_8P_3_4_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_3_4_FIELD 7 + +#define STV090x_GAINLLR_NF15 STV090x_GAINLLR_NFx(15) +#define STV090x_OFFST_GAINLLR_NF_8P_5_6_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_5_6_FIELD 7 + +#define STV090x_GAINLLR_NF16 STV090x_GAINLLR_NFx(16) +#define STV090x_OFFST_GAINLLR_NF_8P_8_9_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_8_9_FIELD 7 + +#define STV090x_GAINLLR_NF17 STV090x_GAINLLR_NFx(17) +#define STV090x_OFFST_GAINLLR_NF_8P_9_10_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_9_10_FIELD 7 + +#define STV090x_GENCFG 0xFA86 +#define STV090x_OFFST_BROADCAST_FIELD 4 +#define STV090x_WIDTH_BROADCAST_FIELD 1 +#define STV090x_OFFST_PRIORITY_FIELD 1 +#define STV090x_WIDTH_PRIORITY_FIELD 1 +#define STV090x_OFFST_DDEMOD_FIELD 0 +#define STV090x_WIDTH_DDEMOD_FIELD 1 + +#define STV090x_LDPCERRx(__x) (0xFA97 - (__x * 0x1)) +#define STV090x_LDPCERR0 STV090x_LDPCERRx(0) +#define STV090x_LDPCERR1 STV090x_LDPCERRx(1) +#define STV090x_OFFST_Px_LDPC_ERRORS_COUNTER_FIELD 0 +#define STV090x_WIDTH_Px_LDPC_ERRORS_COUNTER_FIELD 8 + +#define STV090x_BCHERR 0xFA98 +#define STV090x_OFFST_Px_ERRORFLAG_FIELD 4 +#define STV090x_WIDTH_Px_ERRORFLAG_FIELD 1 +#define STV090x_OFFST_Px_BCH_ERRORS_COUNTER_FIELD 0 +#define STV090x_WIDTH_Px_BCH_ERRORS_COUNTER_FIELD 4 + +#define STV090x_Px_TSSTATEM(__x) (0xF570 - (__x - 1) * 0x200) +#define STV090x_P1_TSSTATEM STV090x_Px_TSSTATEM(1) +#define STV090x_P2_TSSTATEM STV090x_Px_TSSTATEM(2) +#define STV090x_OFFST_Px_TSDIL_ON_FIELD 7 +#define STV090x_WIDTH_Px_TSDIL_ON_FIELD 1 +#define STV090x_OFFST_Px_TSRS_ON_FIELD 5 +#define STV090x_WIDTH_Px_TSRS_ON_FIELD 1 + +#define STV090x_Px_TSCFGH(__x) (0xF572 - (__x - 1) * 0x200) +#define STV090x_P1_TSCFGH STV090x_Px_TSCFGH(1) +#define STV090x_P2_TSCFGH STV090x_Px_TSCFGH(2) +#define STV090x_OFFST_Px_TSFIFO_DVBCI_FIELD 7 +#define STV090x_WIDTH_Px_TSFIFO_DVBCI_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_SERIAL_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFO_SERIAL_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_TEIUPDATE_FIELD 5 +#define STV090x_WIDTH_Px_TSFIFO_TEIUPDATE_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_DUTY50_FIELD 4 +#define STV090x_WIDTH_Px_TSFIFO_DUTY50_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_HSGNLOUT_FIELD 3 +#define STV090x_WIDTH_Px_TSFIFO_HSGNLOUT_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_ERRORMODE_FIELD 1 +#define STV090x_WIDTH_Px_TSFIFO_ERRORMODE_FIELD 2 +#define STV090x_OFFST_Px_RST_HWARE_FIELD 0 +#define STV090x_WIDTH_Px_RST_HWARE_FIELD 1 + +#define STV090x_Px_TSCFGM(__x) (0xF573 - (__x - 1) * 0x200) +#define STV090x_P1_TSCFGM STV090x_Px_TSCFGM(1) +#define STV090x_P2_TSCFGM STV090x_Px_TSCFGM(2) +#define STV090x_OFFST_Px_TSFIFO_MANSPEED_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFO_MANSPEED_FIELD 2 +#define STV090x_OFFST_Px_TSFIFO_PERMDATA_FIELD 5 +#define STV090x_WIDTH_Px_TSFIFO_PERMDATA_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_INVDATA_FIELD 0 +#define STV090x_WIDTH_Px_TSFIFO_INVDATA_FIELD 1 + +#define STV090x_Px_TSCFGL(__x) (0xF574 - (__x - 1) * 0x200) +#define STV090x_P1_TSCFGL STV090x_Px_TSCFGL(1) +#define STV090x_P2_TSCFGL STV090x_Px_TSCFGL(2) +#define STV090x_OFFST_Px_TSFIFO_BCLKDEL1CK_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFO_BCLKDEL1CK_FIELD 2 +#define STV090x_OFFST_Px_BCHERROR_MODE_FIELD 4 +#define STV090x_WIDTH_Px_BCHERROR_MODE_FIELD 2 +#define STV090x_OFFST_Px_TSFIFO_NSGNL2DATA_FIELD 3 +#define STV090x_WIDTH_Px_TSFIFO_NSGNL2DATA_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_EMBINDVB_FIELD 2 +#define STV090x_WIDTH_Px_TSFIFO_EMBINDVB_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_DPUNACT_FIELD 1 +#define STV090x_WIDTH_Px_TSFIFO_DPUNACT_FIELD 1 + +#define STV090x_Px_TSINSDELH(__x) (0xF576 - (__x - 1) * 0x200) +#define STV090x_P1_TSINSDELH STV090x_Px_TSINSDELH(1) +#define STV090x_P2_TSINSDELH STV090x_Px_TSINSDELH(2) +#define STV090x_OFFST_Px_TSDEL_SYNCBYTE_FIELD 7 +#define STV090x_WIDTH_Px_TSDEL_SYNCBYTE_FIELD 1 +#define STV090x_OFFST_Px_TSDEL_XXHEADER_FIELD 6 +#define STV090x_WIDTH_Px_TSDEL_XXHEADER_FIELD 1 + +#define STV090x_Px_TSSPEED(__x) (0xF580 - (__x - 1) * 0x200) +#define STV090x_P1_TSSPEED STV090x_Px_TSSPEED(1) +#define STV090x_P2_TSSPEED STV090x_Px_TSSPEED(2) +#define STV090x_OFFST_Px_TSFIFO_OUTSPEED_FIELD 0 +#define STV090x_WIDTH_Px_TSFIFO_OUTSPEED_FIELD 8 + +#define STV090x_Px_TSSTATUS(__x) (0xF581 - (__x - 1) * 0x200) +#define STV090x_P1_TSSTATUS STV090x_Px_TSSTATUS(1) +#define STV090x_P2_TSSTATUS STV090x_Px_TSSTATUS(2) +#define STV090x_OFFST_Px_TSFIFO_LINEOK_FIELD 7 +#define STV090x_WIDTH_Px_TSFIFO_LINEOK_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_ERROR_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFO_ERROR_FIELD 1 + +#define STV090x_Px_TSSTATUS2(__x) (0xF582 - (__x - 1) * 0x200) +#define STV090x_P1_TSSTATUS2 STV090x_Px_TSSTATUS2(1) +#define STV090x_P2_TSSTATUS2 STV090x_Px_TSSTATUS2(2) +#define STV090x_OFFST_Px_TSFIFO_DEMODSEL_FIELD 7 +#define STV090x_WIDTH_Px_TSFIFO_DEMODSEL_FIELD 1 +#define STV090x_OFFST_Px_TSFIFOSPEED_STORE_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD 1 +#define STV090x_OFFST_Px_DILXX_RESET_FIELD 5 +#define STV090x_WIDTH_Px_DILXX_RESET_FIELD 1 +#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD 4 +#define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD 1 +#define STV090x_OFFST_Px_SCRAMBDETECT_FIELD 1 +#define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD 1 + +#define STV090x_Px_TSBITRATEy(__x, __y) (0xF584 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_TSBITRATE0 STV090x_Px_TSBITRATEy(1, 0) +#define STV090x_P1_TSBITRATE1 STV090x_Px_TSBITRATEy(1, 1) +#define STV090x_P2_TSBITRATE0 STV090x_Px_TSBITRATEy(2, 0) +#define STV090x_P2_TSBITRATE1 STV090x_Px_TSBITRATEy(2, 1) +#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD 0 +#define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD 8 + +#define STV090x_Px_ERRCTRL1(__x) (0xF598 - (__x - 1) * 0x200) +#define STV090x_P1_ERRCTRL1 STV090x_Px_ERRCTRL1(1) +#define STV090x_P2_ERRCTRL1 STV090x_Px_ERRCTRL1(2) +#define STV090x_OFFST_Px_ERR_SOURCE_FIELD 4 +#define STV090x_WIDTH_Px_ERR_SOURCE_FIELD 4 +#define STV090x_OFFST_Px_NUM_EVENT_FIELD 0 +#define STV090x_WIDTH_Px_NUM_EVENT_FIELD 3 + +#define STV090x_Px_ERRCNT12(__x) (0xF599 - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT12 STV090x_Px_ERRCNT12(1) +#define STV090x_P2_ERRCNT12 STV090x_Px_ERRCNT12(2) +#define STV090x_OFFST_Px_ERRCNT1_OLDVALUE_FIELD 7 +#define STV090x_WIDTH_Px_ERRCNT1_OLDVALUE_FIELD 1 +#define STV090x_OFFST_Px_ERR_CNT12_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT12_FIELD 7 + +#define STV090x_Px_ERRCNT11(__x) (0xF59A - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT11 STV090x_Px_ERRCNT11(1) +#define STV090x_P2_ERRCNT11 STV090x_Px_ERRCNT11(2) +#define STV090x_OFFST_Px_ERR_CNT11_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT11_FIELD 8 + +#define STV090x_Px_ERRCNT10(__x) (0xF59B - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT10 STV090x_Px_ERRCNT10(1) +#define STV090x_P2_ERRCNT10 STV090x_Px_ERRCNT10(2) +#define STV090x_OFFST_Px_ERR_CNT10_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT10_FIELD 8 + +#define STV090x_Px_ERRCTRL2(__x) (0xF59C - (__x - 1) * 0x200) +#define STV090x_P1_ERRCTRL2 STV090x_Px_ERRCTRL2(1) +#define STV090x_P2_ERRCTRL2 STV090x_Px_ERRCTRL2(2) +#define STV090x_OFFST_Px_ERR_SOURCE2_FIELD 4 +#define STV090x_WIDTH_Px_ERR_SOURCE2_FIELD 4 +#define STV090x_OFFST_Px_NUM_EVENT2_FIELD 0 +#define STV090x_WIDTH_Px_NUM_EVENT2_FIELD 3 + +#define STV090x_Px_ERRCNT22(__x) (0xF59D - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT22 STV090x_Px_ERRCNT22(1) +#define STV090x_P2_ERRCNT22 STV090x_Px_ERRCNT22(2) +#define STV090x_OFFST_Px_ERRCNT2_OLDVALUE_FIELD 7 +#define STV090x_WIDTH_Px_ERRCNT2_OLDVALUE_FIELD 1 +#define STV090x_OFFST_Px_ERR_CNT2_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT2_FIELD 7 + +#define STV090x_Px_ERRCNT21(__x) (0xF59E - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT21 STV090x_Px_ERRCNT21(1) +#define STV090x_P2_ERRCNT21 STV090x_Px_ERRCNT21(2) +#define STV090x_OFFST_Px_ERR_CNT21_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT21_FIELD 8 + +#define STV090x_Px_ERRCNT20(__x) (0xF59F - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT20 STV090x_Px_ERRCNT20(1) +#define STV090x_P2_ERRCNT20 STV090x_Px_ERRCNT20(2) +#define STV090x_OFFST_Px_ERR_CNT20_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT20_FIELD 8 + +#define STV090x_Px_FECSPY(__x) (0xF5A0 - (__x - 1) * 0x200) +#define STV090x_P1_FECSPY STV090x_Px_FECSPY(1) +#define STV090x_P2_FECSPY STV090x_Px_FECSPY(2) +#define STV090x_OFFST_Px_SPY_ENABLE_FIELD 7 +#define STV090x_WIDTH_Px_SPY_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_BERMETER_DATAMAODE_FIELD 2 +#define STV090x_WIDTH_Px_BERMETER_DATAMAODE_FIELD 2 + +#define STV090x_Px_FSPYCFG(__x) (0xF5A1 - (__x - 1) * 0x200) +#define STV090x_P1_FSPYCFG STV090x_Px_FSPYCFG(1) +#define STV090x_P2_FSPYCFG STV090x_Px_FSPYCFG(2) +#define STV090x_OFFST_Px_RST_ON_ERROR_FIELD 5 +#define STV090x_WIDTH_Px_RST_ON_ERROR_FIELD 1 +#define STV090x_OFFST_Px_ONE_SHOT_FIELD 4 +#define STV090x_WIDTH_Px_ONE_SHOT_FIELD 1 +#define STV090x_OFFST_Px_I2C_MODE_FIELD 2 +#define STV090x_WIDTH_Px_I2C_MODE_FIELD 2 + +#define STV090x_Px_FSPYDATA(__x) (0xF5A2 - (__x - 1) * 0x200) +#define STV090x_P1_FSPYDATA STV090x_Px_FSPYDATA(1) +#define STV090x_P2_FSPYDATA STV090x_Px_FSPYDATA(2) +#define STV090x_OFFST_Px_SPY_STUFFING_FIELD 7 +#define STV090x_WIDTH_Px_SPY_STUFFING_FIELD 1 +#define STV090x_OFFST_Px_SPY_CNULLPKT_FIELD 5 +#define STV090x_WIDTH_Px_SPY_CNULLPKT_FIELD 1 +#define STV090x_OFFST_Px_SPY_OUTDATA_MODE_FIELD 0 +#define STV090x_WIDTH_Px_SPY_OUTDATA_MODE_FIELD 5 + +#define STV090x_Px_FSPYOUT(__x) (0xF5A3 - (__x - 1) * 0x200) +#define STV090x_P1_FSPYOUT STV090x_Px_FSPYOUT(1) +#define STV090x_P2_FSPYOUT STV090x_Px_FSPYOUT(2) +#define STV090x_OFFST_Px_FSPY_DIRECT_FIELD 7 +#define STV090x_WIDTH_Px_FSPY_DIRECT_FIELD 1 +#define STV090x_OFFST_Px_STUFF_MODE_FIELD 0 +#define STV090x_WIDTH_Px_STUFF_MODE_FIELD 3 + +#define STV090x_Px_FSTATUS(__x) (0xF5A4 - (__x - 1) * 0x200) +#define STV090x_P1_FSTATUS STV090x_Px_FSTATUS(1) +#define STV090x_P2_FSTATUS STV090x_Px_FSTATUS(2) +#define STV090x_OFFST_Px_SPY_ENDSIM_FIELD 7 +#define STV090x_WIDTH_Px_SPY_ENDSIM_FIELD 1 +#define STV090x_OFFST_Px_VALID_SIM_FIELD 6 +#define STV090x_WIDTH_Px_VALID_SIM_FIELD 1 +#define STV090x_OFFST_Px_FOUND_SIGNAL_FIELD 5 +#define STV090x_WIDTH_Px_FOUND_SIGNAL_FIELD 1 +#define STV090x_OFFST_Px_DSS_SYNCBYTE_FIELD 4 +#define STV090x_WIDTH_Px_DSS_SYNCBYTE_FIELD 1 +#define STV090x_OFFST_Px_RESULT_STATE_FIELD 0 +#define STV090x_WIDTH_Px_RESULT_STATE_FIELD 4 + +#define STV090x_Px_FBERCPT4(__x) (0xF5A8 - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT4 STV090x_Px_FBERCPT4(1) +#define STV090x_P2_FBERCPT4 STV090x_Px_FBERCPT4(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERCPT3(__x) (0xF5A9 - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT3 STV090x_Px_FBERCPT3(1) +#define STV090x_P2_FBERCPT3 STV090x_Px_FBERCPT3(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERCPT2(__x) (0xF5AA - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT2 STV090x_Px_FBERCPT2(1) +#define STV090x_P2_FBERCPT2 STV090x_Px_FBERCPT2(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERCPT1(__x) (0xF5AB - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT1 STV090x_Px_FBERCPT1(1) +#define STV090x_P2_FBERCPT1 STV090x_Px_FBERCPT1(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERCPT0(__x) (0xF5AC - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT0 STV090x_Px_FBERCPT0(1) +#define STV090x_P2_FBERCPT0 STV090x_Px_FBERCPT0(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERERRy(__x, __y) (0xF5AF - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_FBERERR0 STV090x_Px_FBERERRy(1, 0) +#define STV090x_P1_FBERERR1 STV090x_Px_FBERERRy(1, 1) +#define STV090x_P1_FBERERR2 STV090x_Px_FBERERRy(1, 2) +#define STV090x_P2_FBERERR0 STV090x_Px_FBERERRy(2, 0) +#define STV090x_P2_FBERERR1 STV090x_Px_FBERERRy(2, 1) +#define STV090x_P2_FBERERR2 STV090x_Px_FBERERRy(2, 2) +#define STV090x_OFFST_Px_FBERMETER_CPT_ERR_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_ERR_FIELD 8 + +#define STV090x_Px_FSPYBER(__x) (0xF5B2 - (__x - 1) * 0x200) +#define STV090x_P1_FSPYBER STV090x_Px_FSPYBER(1) +#define STV090x_P2_FSPYBER STV090x_Px_FSPYBER(2) +#define STV090x_OFFST_Px_FSPYBER_SYNCBYTE_FIELD 4 +#define STV090x_WIDTH_Px_FSPYBER_SYNCBYTE_FIELD 1 +#define STV090x_OFFST_Px_FSPYBER_UNSYNC_FIELD 3 +#define STV090x_WIDTH_Px_FSPYBER_UNSYNC_FIELD 1 +#define STV090x_OFFST_Px_FSPYBER_CTIME_FIELD 0 +#define STV090x_WIDTH_Px_FSPYBER_CTIME_FIELD 3 + +#define STV090x_RCCFGH 0xf600 + +#define STV090x_TSGENERAL 0xF630 +#define STV090x_OFFST_Px_MUXSTREAM_OUT_FIELD 3 +#define STV090x_WIDTH_Px_MUXSTREAM_OUT_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_PERMPARAL_FIELD 1 +#define STV090x_WIDTH_Px_TSFIFO_PERMPARAL_FIELD 2 + +#define STV090x_TSGENERAL1X 0xf670 +#define STV090x_CFGEXT 0xfa80 + +#define STV090x_TSTRES0 0xFF11 +#define STV090x_OFFST_FRESFEC_FIELD 7 +#define STV090x_WIDTH_FRESFEC_FIELD 1 + +#define STV090x_Px_TSTDISRX(__x) (0xFF67 - (__x - 1) * 0x2) +#define STV090x_P1_TSTDISRX STV090x_Px_TSTDISRX(1) +#define STV090x_P2_TSTDISRX STV090x_Px_TSTDISRX(2) +#define STV090x_OFFST_Px_TSTDISRX_SELECT_FIELD 3 +#define STV090x_WIDTH_Px_TSTDISRX_SELECT_FIELD 1 + +#endif /* __STV090x_REG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,452 @@ +/* + * stv6110.c + * + * Driver for ST STV6110 satellite tuner IC. + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include + +#include "stv6110.h" + +static int debug; + +struct stv6110_priv { + int i2c_address; + struct i2c_adapter *i2c; + + u32 mclk; + u8 clk_div; + u8 gain; + u8 regs[8]; +}; + +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG args); \ + } while (0) + +static s32 abssub(s32 a, s32 b) +{ + if (a > b) + return a - b; + else + return b - a; +}; + +static int stv6110_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[], + int start, int len) +{ + struct stv6110_priv *priv = fe->tuner_priv; + int rc; + u8 cmdbuf[len + 1]; + struct i2c_msg msg = { + .addr = priv->i2c_address, + .flags = 0, + .buf = cmdbuf, + .len = len + 1 + }; + + dprintk("%s\n", __func__); + + if (start + len > 8) + return -EINVAL; + + memcpy(&cmdbuf[1], buf, len); + cmdbuf[0] = start; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + rc = i2c_transfer(priv->i2c, &msg, 1); + if (rc != 1) + dprintk("%s: i2c error\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int stv6110_read_regs(struct dvb_frontend *fe, u8 regs[], + int start, int len) +{ + struct stv6110_priv *priv = fe->tuner_priv; + int rc; + u8 reg[] = { start }; + struct i2c_msg msg[] = { + { + .addr = priv->i2c_address, + .flags = 0, + .buf = reg, + .len = 1, + }, { + .addr = priv->i2c_address, + .flags = I2C_M_RD, + .buf = regs, + .len = len, + }, + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + rc = i2c_transfer(priv->i2c, msg, 2); + if (rc != 2) + dprintk("%s: i2c error\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + memcpy(&priv->regs[start], regs, len); + + return 0; +} + +static int stv6110_read_reg(struct dvb_frontend *fe, int start) +{ + u8 buf[] = { 0 }; + stv6110_read_regs(fe, buf, start, 1); + + return buf[0]; +} + +static int stv6110_sleep(struct dvb_frontend *fe) +{ + u8 reg[] = { 0 }; + stv6110_write_regs(fe, reg, 0, 1); + + return 0; +} + +static u32 carrier_width(u32 symbol_rate, fe_rolloff_t rolloff) +{ + u32 rlf; + + switch (rolloff) { + case ROLLOFF_20: + rlf = 20; + break; + case ROLLOFF_25: + rlf = 25; + break; + default: + rlf = 35; + break; + } + + return symbol_rate + ((symbol_rate * rlf) / 100); +} + +static int stv6110_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + struct stv6110_priv *priv = fe->tuner_priv; + u8 r8, ret = 0x04; + int i; + + if ((bandwidth / 2) > 36000000) /*BW/2 max=31+5=36 mhz for r8=31*/ + r8 = 31; + else if ((bandwidth / 2) < 5000000) /* BW/2 min=5Mhz for F=0 */ + r8 = 0; + else /*if 5 < BW/2 < 36*/ + r8 = (bandwidth / 2) / 1000000 - 5; + + /* ctrl3, RCCLKOFF = 0 Activate the calibration Clock */ + /* ctrl3, CF = r8 Set the LPF value */ + priv->regs[RSTV6110_CTRL3] &= ~((1 << 6) | 0x1f); + priv->regs[RSTV6110_CTRL3] |= (r8 & 0x1f); + stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1); + /* stat1, CALRCSTRT = 1 Start LPF auto calibration*/ + priv->regs[RSTV6110_STAT1] |= 0x02; + stv6110_write_regs(fe, &priv->regs[RSTV6110_STAT1], RSTV6110_STAT1, 1); + + i = 0; + /* Wait for CALRCSTRT == 0 */ + while ((i < 10) && (ret != 0)) { + ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x02); + mdelay(1); /* wait for LPF auto calibration */ + i++; + } + + /* RCCLKOFF = 1 calibration done, desactivate the calibration Clock */ + priv->regs[RSTV6110_CTRL3] |= (1 << 6); + stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1); + return 0; +} + +static int stv6110_init(struct dvb_frontend *fe) +{ + struct stv6110_priv *priv = fe->tuner_priv; + u8 buf0[] = { 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e }; + + memcpy(priv->regs, buf0, 8); + /* K = (Reference / 1000000) - 16 */ + priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3); + priv->regs[RSTV6110_CTRL1] |= + ((((priv->mclk / 1000000) - 16) & 0x1f) << 3); + + /* divisor value for the output clock */ + priv->regs[RSTV6110_CTRL2] &= ~0xc0; + priv->regs[RSTV6110_CTRL2] |= (priv->clk_div << 6); + + stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], RSTV6110_CTRL1, 8); + msleep(1); + stv6110_set_bandwidth(fe, 72000000); + + return 0; +} + +static int stv6110_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct stv6110_priv *priv = fe->tuner_priv; + u32 nbsteps, divider, psd2, freq; + u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + stv6110_read_regs(fe, regs, 0, 8); + /*N*/ + divider = (priv->regs[RSTV6110_TUNING2] & 0x0f) << 8; + divider += priv->regs[RSTV6110_TUNING1]; + + /*R*/ + nbsteps = (priv->regs[RSTV6110_TUNING2] >> 6) & 3; + /*p*/ + psd2 = (priv->regs[RSTV6110_TUNING2] >> 4) & 1; + + freq = divider * (priv->mclk / 1000); + freq /= (1 << (nbsteps + psd2)); + freq /= 4; + + *frequency = freq; + + return 0; +} + +static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + struct stv6110_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 ret = 0x04; + u32 divider, ref, p, presc, i, result_freq, vco_freq; + s32 p_calc, p_calc_opt = 1000, r_div, r_div_opt = 0, p_val; + s32 srate; + + dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__, + frequency, priv->mclk); + + /* K = (Reference / 1000000) - 16 */ + priv->regs[RSTV6110_CTRL1] &= ~(0x1f << 3); + priv->regs[RSTV6110_CTRL1] |= + ((((priv->mclk / 1000000) - 16) & 0x1f) << 3); + + /* BB_GAIN = db/2 */ + if (fe->ops.set_property && fe->ops.get_property) { + srate = c->symbol_rate; + dprintk("%s: Get Frontend parameters: srate=%d\n", + __func__, srate); + } else + srate = 15000000; + + priv->regs[RSTV6110_CTRL2] &= ~0x0f; + priv->regs[RSTV6110_CTRL2] |= (priv->gain & 0x0f); + + if (frequency <= 1023000) { + p = 1; + presc = 0; + } else if (frequency <= 1300000) { + p = 1; + presc = 1; + } else if (frequency <= 2046000) { + p = 0; + presc = 0; + } else { + p = 0; + presc = 1; + } + /* DIV4SEL = p*/ + priv->regs[RSTV6110_TUNING2] &= ~(1 << 4); + priv->regs[RSTV6110_TUNING2] |= (p << 4); + + /* PRESC32ON = presc */ + priv->regs[RSTV6110_TUNING2] &= ~(1 << 5); + priv->regs[RSTV6110_TUNING2] |= (presc << 5); + + p_val = (int)(1 << (p + 1)) * 10;/* P = 2 or P = 4 */ + for (r_div = 0; r_div <= 3; r_div++) { + p_calc = (priv->mclk / 100000); + p_calc /= (1 << (r_div + 1)); + if ((abssub(p_calc, p_val)) < (abssub(p_calc_opt, p_val))) + r_div_opt = r_div; + + p_calc_opt = (priv->mclk / 100000); + p_calc_opt /= (1 << (r_div_opt + 1)); + } + + ref = priv->mclk / ((1 << (r_div_opt + 1)) * (1 << (p + 1))); + divider = (((frequency * 1000) + (ref >> 1)) / ref); + + /* RDIV = r_div_opt */ + priv->regs[RSTV6110_TUNING2] &= ~(3 << 6); + priv->regs[RSTV6110_TUNING2] |= (((r_div_opt) & 3) << 6); + + /* NDIV_MSB = MSB(divider) */ + priv->regs[RSTV6110_TUNING2] &= ~0x0f; + priv->regs[RSTV6110_TUNING2] |= (((divider) >> 8) & 0x0f); + + /* NDIV_LSB, LSB(divider) */ + priv->regs[RSTV6110_TUNING1] = (divider & 0xff); + + /* CALVCOSTRT = 1 VCO Auto Calibration */ + priv->regs[RSTV6110_STAT1] |= 0x04; + stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], + RSTV6110_CTRL1, 8); + + i = 0; + /* Wait for CALVCOSTRT == 0 */ + while ((i < 10) && (ret != 0)) { + ret = ((stv6110_read_reg(fe, RSTV6110_STAT1)) & 0x04); + msleep(1); /* wait for VCO auto calibration */ + i++; + } + + ret = stv6110_read_reg(fe, RSTV6110_STAT1); + stv6110_get_frequency(fe, &result_freq); + + vco_freq = divider * ((priv->mclk / 1000) / ((1 << (r_div_opt + 1)))); + dprintk("%s, stat1=%x, lo_freq=%d kHz, vco_frec=%d kHz\n", __func__, + ret, result_freq, vco_freq); + + return 0; +} + +static int stv6110_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff); + + stv6110_set_frequency(fe, c->frequency); + stv6110_set_bandwidth(fe, bandwidth); + + return 0; +} + +static int stv6110_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct stv6110_priv *priv = fe->tuner_priv; + u8 r8 = 0; + u8 regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + stv6110_read_regs(fe, regs, 0, 8); + + /* CF */ + r8 = priv->regs[RSTV6110_CTRL3] & 0x1f; + *bandwidth = (r8 + 5) * 2000000;/* x2 for ZIF tuner BW/2 = F+5 Mhz */ + + return 0; +} + +static struct dvb_tuner_ops stv6110_tuner_ops = { + .info = { + .name = "ST STV6110", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 1000, + }, + .init = stv6110_init, + .release = stv6110_release, + .sleep = stv6110_sleep, + .set_params = stv6110_set_params, + .get_frequency = stv6110_get_frequency, + .set_frequency = stv6110_set_frequency, + .get_bandwidth = stv6110_get_bandwidth, + .set_bandwidth = stv6110_set_bandwidth, + +}; + +struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, + const struct stv6110_config *config, + struct i2c_adapter *i2c) +{ + struct stv6110_priv *priv = NULL; + u8 reg0[] = { 0x00, 0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e }; + + struct i2c_msg msg[] = { + { + .addr = config->i2c_address, + .flags = 0, + .buf = reg0, + .len = 9 + } + }; + int ret; + + /* divisor value for the output clock */ + reg0[2] &= ~0xc0; + reg0[2] |= (config->clk_div << 6); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer(i2c, msg, 1); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret != 1) + return NULL; + + priv = kzalloc(sizeof(struct stv6110_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_address = config->i2c_address; + priv->i2c = i2c; + priv->mclk = config->mclk; + priv->clk_div = config->clk_div; + priv->gain = config->gain; + + memcpy(&priv->regs, ®0[1], 8); + + memcpy(&fe->ops.tuner_ops, &stv6110_tuner_ops, + sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = priv; + printk(KERN_INFO "STV6110 attached on addr=%x!\n", priv->i2c_address); + + return fe; +} +EXPORT_SYMBOL(stv6110_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("ST STV6110 driver"); +MODULE_AUTHOR("Igor M. Liplianin"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * stv6110.h + * + * Driver for ST STV6110 satellite tuner IC. + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __DVB_STV6110_H__ +#define __DVB_STV6110_H__ + +#include +#include "dvb_frontend.h" + +/* registers */ +#define RSTV6110_CTRL1 0 +#define RSTV6110_CTRL2 1 +#define RSTV6110_TUNING1 2 +#define RSTV6110_TUNING2 3 +#define RSTV6110_CTRL3 4 +#define RSTV6110_STAT1 5 +#define RSTV6110_STAT2 6 +#define RSTV6110_STAT3 7 + +struct stv6110_config { + u8 i2c_address; + u32 mclk; + u8 gain; + u8 clk_div; /* divisor value for the output clock */ +}; + +#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, + const struct stv6110_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, + const struct stv6110_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,405 @@ +/* + STV6110(A) Silicon tuner driver + + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "stv6110x_reg.h" +#include "stv6110x.h" +#include "stv6110x_priv.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); + +static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data) +{ + int ret; + const struct stv6110x_config *config = stv6110x->config; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { .addr = config->addr, .flags = 0, .buf = b0, .len = 1 }, + { .addr = config->addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } + }; + + ret = i2c_transfer(stv6110x->i2c, msg, 2); + if (ret != 2) { + dprintk(FE_ERROR, 1, "I/O Error"); + return -EREMOTEIO; + } + *data = b1[0]; + + return 0; +} + +static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 data[], int len) +{ + int ret; + const struct stv6110x_config *config = stv6110x->config; + u8 buf[len + 1]; + struct i2c_msg msg = { + .addr = config->addr, + .flags = 0, + .buf = buf, + .len = len + 1 + }; + + if (start + len > 8) + return -EINVAL; + + buf[0] = start; + memcpy(&buf[1], data, len); + + ret = i2c_transfer(stv6110x->i2c, &msg, 1); + if (ret != 1) { + dprintk(FE_ERROR, 1, "I/O Error"); + return -EREMOTEIO; + } + + return 0; +} + +static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data) +{ + return stv6110x_write_regs(stv6110x, reg, &data, 1); +} + +static int stv6110x_init(struct dvb_frontend *fe) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + int ret; + + ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs, + ARRAY_SIZE(stv6110x->regs)); + if (ret < 0) { + dprintk(FE_ERROR, 1, "Initialization failed"); + return -1; + } + + return 0; +} + +static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + u32 rDiv, divider; + s32 pVal, pCalc, rDivOpt = 0, pCalcOpt = 1000; + u8 i; + + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16)); + + if (frequency <= 1023000) { + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0); + pVal = 40; + } else if (frequency <= 1300000) { + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1); + pVal = 40; + } else if (frequency <= 2046000) { + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0); + pVal = 20; + } else { + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1); + pVal = 20; + } + + for (rDiv = 0; rDiv <= 3; rDiv++) { + pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv); + + if ((abs((s32)(pCalc - pVal))) < (abs((s32)(pCalcOpt - pVal)))) + rDivOpt = rDiv; + + pCalcOpt = (REFCLOCK_kHz / 100) / R_DIV(rDivOpt); + } + + divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz; + divider = (divider + 5) / 10; + + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider)); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider)); + + /* VCO Auto calibration */ + STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1); + + stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]); + stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x->regs[STV6110x_TNG1]); + stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x->regs[STV6110x_TNG0]); + stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]); + + for (i = 0; i < TRIALS; i++) { + stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]); + if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x->regs[STV6110x_STAT1])) + break; + msleep(1); + } + + return 0; +} + +static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x->regs[STV6110x_TNG1]); + stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x->regs[STV6110x_TNG0]); + + *frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x->regs[STV6110x_TNG1]), + STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x->regs[STV6110x_TNG0]))) * REFCLOCK_kHz; + + *frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x->regs[STV6110x_TNG1]) + + STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x->regs[STV6110x_TNG1]))); + + *frequency >>= 2; + + return 0; +} + +static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + u32 halfbw; + u8 i; + + halfbw = bandwidth >> 1; + + if (halfbw > 36000000) + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */ + else if (halfbw < 5000000) + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */ + else + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */ + + + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */ + STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */ + + stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]); + stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]); + + for (i = 0; i < TRIALS; i++) { + stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]); + if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x->regs[STV6110x_STAT1])) + break; + msleep(1); + } + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */ + stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]); + + return 0; +} + +static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x->regs[STV6110x_CTRL3]); + *bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x->regs[STV6110x_CTRL3]) + 5) * 2000000; + + return 0; +} + +static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + /* setup divider */ + switch (refclock) { + default: + case 1: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0); + break; + case 2: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1); + break; + case 4: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2); + break; + case 8: + case 0: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3); + break; + } + stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]); + + return 0; +} + +static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x->regs[STV6110x_CTRL2]); + *gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x->regs[STV6110x_CTRL2]); + + return 0; +} + +static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2); + stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]); + + return 0; +} + +static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + int ret; + + switch (mode) { + case TUNER_SLEEP: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 0); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 0); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 0); + break; + + case TUNER_WAKE: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 1); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 1); + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 1); + break; + } + + ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]); + if (ret < 0) { + dprintk(FE_ERROR, 1, "I/O Error"); + return -EIO; + } + + return 0; +} + +static int stv6110x_sleep(struct dvb_frontend *fe) +{ + if (fe->tuner_priv) + return stv6110x_set_mode(fe, TUNER_SLEEP); + + return 0; +} + +static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]); + + if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x->regs[STV6110x_STAT1])) + *status = TUNER_PHASELOCKED; + else + *status = 0; + + return 0; +} + + +static int stv6110x_release(struct dvb_frontend *fe) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(stv6110x); + + return 0; +} + +static struct dvb_tuner_ops stv6110x_ops = { + .info = { + .name = "STV6110(A) Silicon Tuner", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 0, + }, + .release = stv6110x_release +}; + +static struct stv6110x_devctl stv6110x_ctl = { + .tuner_init = stv6110x_init, + .tuner_sleep = stv6110x_sleep, + .tuner_set_mode = stv6110x_set_mode, + .tuner_set_frequency = stv6110x_set_frequency, + .tuner_get_frequency = stv6110x_get_frequency, + .tuner_set_bandwidth = stv6110x_set_bandwidth, + .tuner_get_bandwidth = stv6110x_get_bandwidth, + .tuner_set_bbgain = stv6110x_set_bbgain, + .tuner_get_bbgain = stv6110x_get_bbgain, + .tuner_set_refclk = stv6110x_set_refclock, + .tuner_get_status = stv6110x_get_status, +}; + +struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, + const struct stv6110x_config *config, + struct i2c_adapter *i2c) +{ + struct stv6110x_state *stv6110x; + u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e}; + + stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL); + if (!stv6110x) + return NULL; + + stv6110x->i2c = i2c; + stv6110x->config = config; + stv6110x->devctl = &stv6110x_ctl; + memcpy(stv6110x->regs, default_regs, 8); + + /* setup divider */ + switch (stv6110x->config->clk_div) { + default: + case 1: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0); + break; + case 2: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1); + break; + case 4: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2); + break; + case 8: + case 0: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3); + break; + } + + fe->tuner_priv = stv6110x; + fe->ops.tuner_ops = stv6110x_ops; + + printk(KERN_INFO "%s: Attaching STV6110x\n", __func__); + return stv6110x->devctl; +} +EXPORT_SYMBOL(stv6110x_attach); + +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STV6110x Silicon tuner"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,73 @@ +/* + STV6110(A) Silicon tuner driver + + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STV6110x_H +#define __STV6110x_H + +struct stv6110x_config { + u8 addr; + u32 refclk; + u8 clk_div; /* divisor value for the output clock */ +}; + +enum tuner_mode { + TUNER_SLEEP = 1, + TUNER_WAKE, +}; + +enum tuner_status { + TUNER_PHASELOCKED = 1, +}; + +struct stv6110x_devctl { + int (*tuner_init) (struct dvb_frontend *fe); + int (*tuner_sleep) (struct dvb_frontend *fe); + int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); + int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); + int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency); + int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth); + int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth); + int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain); + int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain); + int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk); + int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status); +}; + + +#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE)) + +extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, + const struct stv6110x_config *config, + struct i2c_adapter *i2c); + +#else +static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, + const struct stv6110x_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_STV6110x */ + +#endif /* __STV6110x_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,76 @@ +/* + STV6110(A) Silicon tuner driver + + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STV6110x_PRIV_H +#define __STV6110x_PRIV_H + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 +#define FE_DEBUGREG 4 + +#define dprintk(__y, __z, format, arg...) do { \ + if (__z) { \ + if ((verbose > FE_ERROR) && (verbose > __y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_NOTICE) && (verbose > __y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_INFO) && (verbose > __y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_DEBUG) && (verbose > __y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (verbose > __y) \ + printk(format, ##arg); \ + } \ +} while (0) + + +#define STV6110x_SETFIELD(mask, bitf, val) \ + (mask = (mask & (~(((1 << STV6110x_WIDTH_##bitf) - 1) << \ + STV6110x_OFFST_##bitf))) | \ + (val << STV6110x_OFFST_##bitf)) + +#define STV6110x_GETFIELD(bitf, val) \ + ((val >> STV6110x_OFFST_##bitf) & \ + ((1 << STV6110x_WIDTH_##bitf) - 1)) + +#define MAKEWORD16(a, b) (((a) << 8) | (b)) + +#define LSB(x) ((x & 0xff)) +#define MSB(y) ((y >> 8) & 0xff) + +#define TRIALS 10 +#define R_DIV(__div) (1 << (__div + 1)) +#define REFCLOCK_kHz (stv6110x->config->refclk / 1000) +#define REFCLOCK_MHz (stv6110x->config->refclk / 1000000) + +struct stv6110x_state { + struct i2c_adapter *i2c; + const struct stv6110x_config *config; + u8 regs[8]; + + struct stv6110x_devctl *devctl; +}; + +#endif /* __STV6110x_PRIV_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x_reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/stv6110x_reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + STV6110(A) Silicon tuner driver + + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __STV6110x_REG_H +#define __STV6110x_REG_H + +#define STV6110x_CTRL1 0x00 +#define STV6110x_OFFST_CTRL1_K 3 +#define STV6110x_WIDTH_CTRL1_K 5 +#define STV6110x_OFFST_CTRL1_LPT 2 +#define STV6110x_WIDTH_CTRL1_LPT 1 +#define STV6110x_OFFST_CTRL1_RX 1 +#define STV6110x_WIDTH_CTRL1_RX 1 +#define STV6110x_OFFST_CTRL1_SYN 0 +#define STV6110x_WIDTH_CTRL1_SYN 1 + +#define STV6110x_CTRL2 0x01 +#define STV6110x_OFFST_CTRL2_CO_DIV 6 +#define STV6110x_WIDTH_CTRL2_CO_DIV 2 +#define STV6110x_OFFST_CTRL2_RSVD 5 +#define STV6110x_WIDTH_CTRL2_RSVD 1 +#define STV6110x_OFFST_CTRL2_REFOUT_SEL 4 +#define STV6110x_WIDTH_CTRL2_REFOUT_SEL 1 +#define STV6110x_OFFST_CTRL2_BBGAIN 0 +#define STV6110x_WIDTH_CTRL2_BBGAIN 4 + +#define STV6110x_TNG0 0x02 +#define STV6110x_OFFST_TNG0_N_DIV_7_0 0 +#define STV6110x_WIDTH_TNG0_N_DIV_7_0 8 + +#define STV6110x_TNG1 0x03 +#define STV6110x_OFFST_TNG1_R_DIV 6 +#define STV6110x_WIDTH_TNG1_R_DIV 2 +#define STV6110x_OFFST_TNG1_PRESC32_ON 5 +#define STV6110x_WIDTH_TNG1_PRESC32_ON 1 +#define STV6110x_OFFST_TNG1_DIV4SEL 4 +#define STV6110x_WIDTH_TNG1_DIV4SEL 1 +#define STV6110x_OFFST_TNG1_N_DIV_11_8 0 +#define STV6110x_WIDTH_TNG1_N_DIV_11_8 4 + + +#define STV6110x_CTRL3 0x04 +#define STV6110x_OFFST_CTRL3_DCLOOP_OFF 7 +#define STV6110x_WIDTH_CTRL3_DCLOOP_OFF 1 +#define STV6110x_OFFST_CTRL3_RCCLK_OFF 6 +#define STV6110x_WIDTH_CTRL3_RCCLK_OFF 1 +#define STV6110x_OFFST_CTRL3_ICP 5 +#define STV6110x_WIDTH_CTRL3_ICP 1 +#define STV6110x_OFFST_CTRL3_CF 0 +#define STV6110x_WIDTH_CTRL3_CF 5 + +#define STV6110x_STAT1 0x05 +#define STV6110x_OFFST_STAT1_CALVCO_STRT 2 +#define STV6110x_WIDTH_STAT1_CALVCO_STRT 1 +#define STV6110x_OFFST_STAT1_CALRC_STRT 1 +#define STV6110x_WIDTH_STAT1_CALRC_STRT 1 +#define STV6110x_OFFST_STAT1_LOCK 0 +#define STV6110x_WIDTH_STAT1_LOCK 1 + +#define STV6110x_STAT2 0x06 +#define STV6110x_STAT3 0x07 + +#endif /* __STV6110x_REG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10021.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10021.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10021.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10021.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,489 @@ +/* + TDA10021 - Single Chip Cable Channel Receiver driver module + used on the Siemens DVB-C cards + + Copyright (C) 1999 Convergence Integrated Media GmbH + Copyright (C) 2004 Markus Schulz + Support for TDA10021 + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "tda1002x.h" + + +struct tda10021_state { + struct i2c_adapter* i2c; + /* configuration settings */ + const struct tda1002x_config* config; + struct dvb_frontend frontend; + + u8 pwm; + u8 reg0; +}; + + +#if 0 +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +static int verbose; + +#define XIN 57840000UL + +#define FIN (XIN >> 4) + +static int tda10021_inittab_size = 0x40; +static u8 tda10021_inittab[0x40]= +{ + 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a, + 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40, + 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff, + 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58, + 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00, + 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00, +}; + +static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int ret; + + ret = i2c_transfer (state->i2c, &msg, 1); + if (ret != 1) + printk("DVB: TDA10021(%d): %s, writereg error " + "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", + state->frontend.dvb->num, __func__, reg, data, ret); + + msleep(10); + return (ret != 1) ? -EREMOTEIO : 0; +} + +static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) +{ + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + int ret; + + ret = i2c_transfer (state->i2c, msg, 2); + // Don't print an error message if the id is read. + if (ret != 2 && reg != 0x1a) + printk("DVB: TDA10021: %s: readreg error (ret == %i)\n", + __func__, ret); + return b1[0]; +} + +//get access to tuner +static int lock_tuner(struct tda10021_state* state) +{ + u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 }; + struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; + + if(i2c_transfer(state->i2c, &msg, 1) != 1) + { + printk("tda10021: lock tuner fails\n"); + return -EREMOTEIO; + } + return 0; +} + +//release access from tuner +static int unlock_tuner(struct tda10021_state* state) +{ + u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f }; + struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; + + if(i2c_transfer(state->i2c, &msg_post, 1) != 1) + { + printk("tda10021: unlock tuner fails\n"); + return -EREMOTEIO; + } + return 0; +} + +static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0, + fe_spectral_inversion_t inversion) +{ + reg0 |= state->reg0 & 0x63; + + if ((INVERSION_ON == inversion) ^ (state->config->invert == 0)) + reg0 &= ~0x20; + else + reg0 |= 0x20; + + _tda10021_writereg (state, 0x00, reg0 & 0xfe); + _tda10021_writereg (state, 0x00, reg0 | 0x01); + + state->reg0 = reg0; + return 0; +} + +static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate) +{ + s32 BDR; + s32 BDRI; + s16 SFIL=0; + u16 NDEC = 0; + u32 tmp, ratio; + + if (symbolrate > XIN/2) + symbolrate = XIN/2; + if (symbolrate < 500000) + symbolrate = 500000; + + if (symbolrate < XIN/16) NDEC = 1; + if (symbolrate < XIN/32) NDEC = 2; + if (symbolrate < XIN/64) NDEC = 3; + + if (symbolrate < (u32)(XIN/12.3)) SFIL = 1; + if (symbolrate < (u32)(XIN/16)) SFIL = 0; + if (symbolrate < (u32)(XIN/24.6)) SFIL = 1; + if (symbolrate < (u32)(XIN/32)) SFIL = 0; + if (symbolrate < (u32)(XIN/49.2)) SFIL = 1; + if (symbolrate < (u32)(XIN/64)) SFIL = 0; + if (symbolrate < (u32)(XIN/98.4)) SFIL = 1; + + symbolrate <<= NDEC; + ratio = (symbolrate << 4) / FIN; + tmp = ((symbolrate << 4) % FIN) << 8; + ratio = (ratio << 8) + tmp / FIN; + tmp = (tmp % FIN) << 8; + ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN); + + BDR = ratio; + BDRI = (((XIN << 5) / symbolrate) + 1) / 2; + + if (BDRI > 0xFF) + BDRI = 0xFF; + + SFIL = (SFIL << 4) | tda10021_inittab[0x0E]; + + NDEC = (NDEC << 6) | tda10021_inittab[0x03]; + + _tda10021_writereg (state, 0x03, NDEC); + _tda10021_writereg (state, 0x0a, BDR&0xff); + _tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff); + _tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f); + + _tda10021_writereg (state, 0x0d, BDRI); + _tda10021_writereg (state, 0x0e, SFIL); + + return 0; +} + +static int tda10021_init (struct dvb_frontend *fe) +{ + struct tda10021_state* state = fe->demodulator_priv; + int i; + + dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num); + + //_tda10021_writereg (fe, 0, 0); + + for (i=0; ipwm); + + //Comment by markus + //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0) + //0x2A[4] == BYPPLL -> Power down mode (default 1) + //0x2A[5] == LCK -> PLL Lock Flag + //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0) + + //Activate PLL + _tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef); + return 0; +} + +static int tda10021_set_parameters (struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct tda10021_state* state = fe->demodulator_priv; + + //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256 + //CONF + static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c, 0x10 }; + //AGCREF value + static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78, 0x5c }; + //LTHR value + static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36, 0x26 }; + //MSETH + static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34, 0x23 }; + //AREF + static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e, 0x6b }; + + int qam = p->u.qam.modulation; + + if (qam < 0 || qam > 5) + return -EINVAL; + + if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF) + return -EINVAL; + + //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + tda10021_set_symbolrate (state, p->u.qam.symbol_rate); + _tda10021_writereg (state, 0x34, state->pwm); + + _tda10021_writereg (state, 0x01, reg0x01[qam]); + _tda10021_writereg (state, 0x05, reg0x05[qam]); + _tda10021_writereg (state, 0x08, reg0x08[qam]); + _tda10021_writereg (state, 0x09, reg0x09[qam]); + + tda10021_setup_reg0 (state, reg0x00[qam], p->inversion); + + return 0; +} + +static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct tda10021_state* state = fe->demodulator_priv; + int sync; + + *status = 0; + //0x11[0] == EQALGO -> Equalizer algorithms state + //0x11[1] == CARLOCK -> Carrier locked + //0x11[2] == FSYNC -> Frame synchronisation + //0x11[3] == FEL -> Front End locked + //0x11[6] == NODVB -> DVB Mode Information + sync = tda10021_readreg (state, 0x11); + + if (sync & 2) + *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; + + if (sync & 4) + *status |= FE_HAS_SYNC|FE_HAS_VITERBI; + + if (sync & 8) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct tda10021_state* state = fe->demodulator_priv; + + u32 _ber = tda10021_readreg(state, 0x14) | + (tda10021_readreg(state, 0x15) << 8) | + ((tda10021_readreg(state, 0x16) & 0x0f) << 16); + _tda10021_writereg(state, 0x10, (tda10021_readreg(state, 0x10) & ~0xc0) + | (tda10021_inittab[0x10] & 0xc0)); + *ber = 10 * _ber; + + return 0; +} + +static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct tda10021_state* state = fe->demodulator_priv; + + u8 config = tda10021_readreg(state, 0x02); + u8 gain = tda10021_readreg(state, 0x17); + if (config & 0x02) + /* the agc value is inverted */ + gain = ~gain; + *strength = (gain << 8) | gain; + + return 0; +} + +static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct tda10021_state* state = fe->demodulator_priv; + + u8 quality = ~tda10021_readreg(state, 0x18); + *snr = (quality << 8) | quality; + + return 0; +} + +static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct tda10021_state* state = fe->demodulator_priv; + + *ucblocks = tda10021_readreg (state, 0x13) & 0x7f; + if (*ucblocks == 0x7f) + *ucblocks = 0xffffffff; + + /* reset uncorrected block counter */ + _tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf); + _tda10021_writereg (state, 0x10, tda10021_inittab[0x10]); + + return 0; +} + +static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda10021_state* state = fe->demodulator_priv; + int sync; + s8 afc = 0; + + sync = tda10021_readreg(state, 0x11); + afc = tda10021_readreg(state, 0x19); + if (verbose) { + /* AFC only valid when carrier has been recovered */ + printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" : + "DVB: TDA10021(%d): [AFC (%d) %dHz]\n", + state->frontend.dvb->num, afc, + -((s32)p->u.qam.symbol_rate * afc) >> 10); + } + + p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF; + p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + + p->u.qam.fec_inner = FEC_NONE; + p->frequency = ((p->frequency + 31250) / 62500) * 62500; + + if (sync & 2) + p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; + + return 0; +} + +static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct tda10021_state* state = fe->demodulator_priv; + + if (enable) { + lock_tuner(state); + } else { + unlock_tuner(state); + } + return 0; +} + +static int tda10021_sleep(struct dvb_frontend* fe) +{ + struct tda10021_state* state = fe->demodulator_priv; + + _tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */ + _tda10021_writereg (state, 0x00, 0x80); /* standby */ + + return 0; +} + +static void tda10021_release(struct dvb_frontend* fe) +{ + struct tda10021_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops tda10021_ops; + +struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, + struct i2c_adapter* i2c, + u8 pwm) +{ + struct tda10021_state* state = NULL; + u8 id; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct tda10021_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->pwm = pwm; + state->reg0 = tda10021_inittab[0]; + + /* check if the demod is there */ + id = tda10021_readreg(state, 0x1a); + if ((id & 0xf0) != 0x70) goto error; + + /* Don't claim TDA10023 */ + if (id == 0x7d) + goto error; + + printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n", + state->config->demod_address, id); + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops tda10021_ops = { + + .info = { + .name = "Philips TDA10021 DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 47000000, + .frequency_max = 862000000, + .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ + .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ + #if 0 + .frequency_tolerance = ???, + .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ + #endif + .caps = 0x400 | //FE_CAN_QAM_4 + FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO + }, + + .release = tda10021_release, + + .init = tda10021_init, + .sleep = tda10021_sleep, + .i2c_gate_ctrl = tda10021_i2c_gate_ctrl, + + .set_frontend = tda10021_set_parameters, + .get_frontend = tda10021_get_frontend, + + .read_status = tda10021_read_status, + .read_ber = tda10021_read_ber, + .read_signal_strength = tda10021_read_signal_strength, + .read_snr = tda10021_read_snr, + .read_ucblocks = tda10021_read_ucblocks, +}; + +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting"); + +MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver"); +MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(tda10021_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10023.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10023.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10023.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10023.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,573 @@ +/* + TDA10023 - DVB-C decoder + (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card) + + Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de) + Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com) + + Remotely based on tda10021.c + Copyright (C) 1999 Convergence Integrated Media GmbH + Copyright (C) 2004 Markus Schulz + Support for TDA10021 + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dvb_frontend.h" +#include "tda1002x.h" + +#define REG0_INIT_VAL 0x23 + +struct tda10023_state { + struct i2c_adapter* i2c; + /* configuration settings */ + const struct tda10023_config *config; + struct dvb_frontend frontend; + + u8 pwm; + u8 reg0; + + /* clock settings */ + u32 xtal; + u8 pll_m; + u8 pll_p; + u8 pll_n; + u32 sysclk; +}; + +#define dprintk(x...) + +static int verbose; + +static u8 tda10023_readreg (struct tda10023_state* state, u8 reg) +{ + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + int ret; + + ret = i2c_transfer (state->i2c, msg, 2); + if (ret != 2) { + int num = state->frontend.dvb ? state->frontend.dvb->num : -1; + printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error " + "(reg == 0x%02x, ret == %i)\n", + num, __func__, reg, ret); + } + return b1[0]; +} + +static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int ret; + + ret = i2c_transfer (state->i2c, &msg, 1); + if (ret != 1) { + int num = state->frontend.dvb ? state->frontend.dvb->num : -1; + printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error " + "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", + num, __func__, reg, data, ret); + } + return (ret != 1) ? -EREMOTEIO : 0; +} + + +static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data) +{ + if (mask==0xff) + return tda10023_writereg(state, reg, data); + else { + u8 val; + val=tda10023_readreg(state,reg); + val&=~mask; + val|=(data&mask); + return tda10023_writereg(state, reg, val); + } +} + +static void tda10023_writetab(struct tda10023_state* state, u8* tab) +{ + u8 r,m,v; + while (1) { + r=*tab++; + m=*tab++; + v=*tab++; + if (r==0xff) { + if (m==0xff) + break; + else + msleep(m); + } + else + tda10023_writebit(state,r,m,v); + } +} + +//get access to tuner +static int lock_tuner(struct tda10023_state* state) +{ + u8 buf[2] = { 0x0f, 0xc0 }; + struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; + + if(i2c_transfer(state->i2c, &msg, 1) != 1) + { + printk("tda10023: lock tuner fails\n"); + return -EREMOTEIO; + } + return 0; +} + +//release access from tuner +static int unlock_tuner(struct tda10023_state* state) +{ + u8 buf[2] = { 0x0f, 0x40 }; + struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; + + if(i2c_transfer(state->i2c, &msg_post, 1) != 1) + { + printk("tda10023: unlock tuner fails\n"); + return -EREMOTEIO; + } + return 0; +} + +static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0) +{ + reg0 |= state->reg0 & 0x63; + + tda10023_writereg (state, 0x00, reg0 & 0xfe); + tda10023_writereg (state, 0x00, reg0 | 0x01); + + state->reg0 = reg0; + return 0; +} + +static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) +{ + s32 BDR; + s32 BDRI; + s16 SFIL=0; + u16 NDEC = 0; + + /* avoid floating point operations multiplying syscloc and divider + by 10 */ + u32 sysclk_x_10 = state->sysclk * 10; + + if (sr < (u32)(sysclk_x_10/984)) { + NDEC=3; + SFIL=1; + } else if (sr < (u32)(sysclk_x_10/640)) { + NDEC=3; + SFIL=0; + } else if (sr < (u32)(sysclk_x_10/492)) { + NDEC=2; + SFIL=1; + } else if (sr < (u32)(sysclk_x_10/320)) { + NDEC=2; + SFIL=0; + } else if (sr < (u32)(sysclk_x_10/246)) { + NDEC=1; + SFIL=1; + } else if (sr < (u32)(sysclk_x_10/160)) { + NDEC=1; + SFIL=0; + } else if (sr < (u32)(sysclk_x_10/123)) { + NDEC=0; + SFIL=1; + } + + BDRI = (state->sysclk)*16; + BDRI>>=NDEC; + BDRI +=sr/2; + BDRI /=sr; + + if (BDRI>255) + BDRI=255; + + { + u64 BDRX; + + BDRX=1<<(24+NDEC); + BDRX*=sr; + do_div(BDRX, state->sysclk); /* BDRX/=SYSCLK; */ + + BDR=(s32)BDRX; + } + dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n", + sr, BDR, BDRI, NDEC); + tda10023_writebit (state, 0x03, 0xc0, NDEC<<6); + tda10023_writereg (state, 0x0a, BDR&255); + tda10023_writereg (state, 0x0b, (BDR>>8)&255); + tda10023_writereg (state, 0x0c, (BDR>>16)&31); + tda10023_writereg (state, 0x0d, BDRI); + tda10023_writereg (state, 0x3d, (SFIL<<7)); + return 0; +} + +static int tda10023_init (struct dvb_frontend *fe) +{ + struct tda10023_state* state = fe->demodulator_priv; + u8 tda10023_inittab[] = { +/* reg mask val */ +/* 000 */ 0x2a, 0xff, 0x02, /* PLL3, Bypass, Power Down */ +/* 003 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ +/* 006 */ 0x2a, 0xff, 0x03, /* PLL3, Bypass, Power Down */ +/* 009 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ + /* PLL1 */ +/* 012 */ 0x28, 0xff, (state->pll_m-1), + /* PLL2 */ +/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1), + /* GPR FSAMPLING=1 */ +/* 018 */ 0x00, 0xff, REG0_INIT_VAL, +/* 021 */ 0x2a, 0xff, 0x08, /* PLL3 PSACLK=1 */ +/* 024 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ +/* 027 */ 0x1f, 0xff, 0x00, /* RESET */ +/* 030 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ +/* 033 */ 0xe6, 0x0c, 0x04, /* RSCFG_IND */ +/* 036 */ 0x10, 0xc0, 0x80, /* DECDVBCFG1 PBER=1 */ + +/* 039 */ 0x0e, 0xff, 0x82, /* GAIN1 */ +/* 042 */ 0x03, 0x08, 0x08, /* CLKCONF DYN=1 */ +/* 045 */ 0x2e, 0xbf, 0x30, /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 + PPWMTUN=0 PPWMIF=0 */ +/* 048 */ 0x01, 0xff, 0x30, /* AGCREF */ +/* 051 */ 0x1e, 0x84, 0x84, /* CONTROL SACLK_ON=1 */ +/* 054 */ 0x1b, 0xff, 0xc8, /* ADC TWOS=1 */ +/* 057 */ 0x3b, 0xff, 0xff, /* IFMAX */ +/* 060 */ 0x3c, 0xff, 0x00, /* IFMIN */ +/* 063 */ 0x34, 0xff, 0x00, /* PWMREF */ +/* 066 */ 0x35, 0xff, 0xff, /* TUNMAX */ +/* 069 */ 0x36, 0xff, 0x00, /* TUNMIN */ +/* 072 */ 0x06, 0xff, 0x7f, /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */ +/* 075 */ 0x1c, 0x30, 0x30, /* EQCONF2 STEPALGO=SGNALGO=1 */ +/* 078 */ 0x37, 0xff, 0xf6, /* DELTAF_LSB */ +/* 081 */ 0x38, 0xff, 0xff, /* DELTAF_MSB */ +/* 084 */ 0x02, 0xff, 0x93, /* AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 */ +/* 087 */ 0x2d, 0xff, 0xf6, /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */ +/* 090 */ 0x04, 0x10, 0x00, /* SWRAMP=1 */ +/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /* + INTP1 POCLKP=1 FEL=1 MFS=0 */ +/* 096 */ 0x2b, 0x01, 0xa1, /* INTS1 */ +/* 099 */ 0x20, 0xff, 0x04, /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */ +/* 102 */ 0x2c, 0xff, 0x0d, /* INTP/S TRIP=0 TRIS=0 */ +/* 105 */ 0xc4, 0xff, 0x00, +/* 108 */ 0xc3, 0x30, 0x00, +/* 111 */ 0xb5, 0xff, 0x19, /* ERAGC_THD */ +/* 114 */ 0x00, 0x03, 0x01, /* GPR, CLBS soft reset */ +/* 117 */ 0x00, 0x03, 0x03, /* GPR, CLBS soft reset */ +/* 120 */ 0xff, 0x64, 0x00, /* Sleep 100ms */ +/* 123 */ 0xff, 0xff, 0xff +}; + dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num); + + /* override default values if set in config */ + if (state->config->deltaf) { + tda10023_inittab[80] = (state->config->deltaf & 0xff); + tda10023_inittab[83] = (state->config->deltaf >> 8); + } + + if (state->config->output_mode) + tda10023_inittab[95] = state->config->output_mode; + + tda10023_writetab(state, tda10023_inittab); + + return 0; +} + +static int tda10023_set_parameters (struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct tda10023_state* state = fe->demodulator_priv; + + static int qamvals[6][6] = { + // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD + { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM + { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM + { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM + { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM + { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM + { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM + }; + + int qam = p->u.qam.modulation; + + if (qam < 0 || qam > 5) + return -EINVAL; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + tda10023_set_symbolrate (state, p->u.qam.symbol_rate); + tda10023_writereg (state, 0x05, qamvals[qam][1]); + tda10023_writereg (state, 0x08, qamvals[qam][2]); + tda10023_writereg (state, 0x09, qamvals[qam][3]); + tda10023_writereg (state, 0xb4, qamvals[qam][4]); + tda10023_writereg (state, 0xb6, qamvals[qam][5]); + +// tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32)); +// tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20)); + tda10023_writebit (state, 0x04, 0x40, 0x40); + tda10023_setup_reg0 (state, qamvals[qam][0]); + + return 0; +} + +static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct tda10023_state* state = fe->demodulator_priv; + int sync; + + *status = 0; + + //0x11[1] == CARLOCK -> Carrier locked + //0x11[2] == FSYNC -> Frame synchronisation + //0x11[3] == FEL -> Front End locked + //0x11[6] == NODVB -> DVB Mode Information + sync = tda10023_readreg (state, 0x11); + + if (sync & 2) + *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; + + if (sync & 4) + *status |= FE_HAS_SYNC|FE_HAS_VITERBI; + + if (sync & 8) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct tda10023_state* state = fe->demodulator_priv; + u8 a,b,c; + a=tda10023_readreg(state, 0x14); + b=tda10023_readreg(state, 0x15); + c=tda10023_readreg(state, 0x16)&0xf; + tda10023_writebit (state, 0x10, 0xc0, 0x00); + + *ber = a | (b<<8)| (c<<16); + return 0; +} + +static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct tda10023_state* state = fe->demodulator_priv; + u8 ifgain=tda10023_readreg(state, 0x2f); + + u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16; + // Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90 + if (gain>0x90) + gain=gain+2*(gain-0x90); + if (gain>255) + gain=255; + + *strength = (gain<<8)|gain; + return 0; +} + +static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct tda10023_state* state = fe->demodulator_priv; + + u8 quality = ~tda10023_readreg(state, 0x18); + *snr = (quality << 8) | quality; + return 0; +} + +static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct tda10023_state* state = fe->demodulator_priv; + u8 a,b,c,d; + a= tda10023_readreg (state, 0x74); + b= tda10023_readreg (state, 0x75); + c= tda10023_readreg (state, 0x76); + d= tda10023_readreg (state, 0x77); + *ucblocks = a | (b<<8)|(c<<16)|(d<<24); + + tda10023_writebit (state, 0x10, 0x20,0x00); + tda10023_writebit (state, 0x10, 0x20,0x20); + tda10023_writebit (state, 0x13, 0x01, 0x00); + + return 0; +} + +static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda10023_state* state = fe->demodulator_priv; + int sync,inv; + s8 afc = 0; + + sync = tda10023_readreg(state, 0x11); + afc = tda10023_readreg(state, 0x19); + inv = tda10023_readreg(state, 0x04); + + if (verbose) { + /* AFC only valid when carrier has been recovered */ + printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" : + "DVB: TDA10023(%d): [AFC (%d) %dHz]\n", + state->frontend.dvb->num, afc, + -((s32)p->u.qam.symbol_rate * afc) >> 10); + } + + p->inversion = (inv&0x20?0:1); + p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + + p->u.qam.fec_inner = FEC_NONE; + p->frequency = ((p->frequency + 31250) / 62500) * 62500; + + if (sync & 2) + p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; + + return 0; +} + +static int tda10023_sleep(struct dvb_frontend* fe) +{ + struct tda10023_state* state = fe->demodulator_priv; + + tda10023_writereg (state, 0x1b, 0x02); /* pdown ADC */ + tda10023_writereg (state, 0x00, 0x80); /* standby */ + + return 0; +} + +static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct tda10023_state* state = fe->demodulator_priv; + + if (enable) { + lock_tuner(state); + } else { + unlock_tuner(state); + } + return 0; +} + +static void tda10023_release(struct dvb_frontend* fe) +{ + struct tda10023_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops tda10023_ops; + +struct dvb_frontend *tda10023_attach(const struct tda10023_config *config, + struct i2c_adapter *i2c, + u8 pwm) +{ + struct tda10023_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* wakeup if in standby */ + tda10023_writereg (state, 0x00, 0x33); + /* check if the demod is there */ + if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); + state->pwm = pwm; + state->reg0 = REG0_INIT_VAL; + if (state->config->xtal) { + state->xtal = state->config->xtal; + state->pll_m = state->config->pll_m; + state->pll_p = state->config->pll_p; + state->pll_n = state->config->pll_n; + } else { + /* set default values if not defined in config */ + state->xtal = 28920000; + state->pll_m = 8; + state->pll_p = 4; + state->pll_n = 1; + } + + /* calc sysclk */ + state->sysclk = (state->xtal * state->pll_m / \ + (state->pll_n * state->pll_p)); + + state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64; + state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4; + + dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n", + __func__, state->xtal, state->pll_m, state->pll_p, + state->pll_n); + + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops tda10023_ops = { + + .info = { + .name = "Philips TDA10023 DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 47000000, + .frequency_max = 862000000, + .symbol_rate_min = 0, /* set in tda10023_attach */ + .symbol_rate_max = 0, /* set in tda10023_attach */ + .caps = 0x400 | //FE_CAN_QAM_4 + FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO + }, + + .release = tda10023_release, + + .init = tda10023_init, + .sleep = tda10023_sleep, + .i2c_gate_ctrl = tda10023_i2c_gate_ctrl, + + .set_frontend = tda10023_set_parameters, + .get_frontend = tda10023_get_frontend, + + .read_status = tda10023_read_status, + .read_ber = tda10023_read_ber, + .read_signal_strength = tda10023_read_signal_strength, + .read_snr = tda10023_read_snr, + .read_ucblocks = tda10023_read_ucblocks, +}; + + +MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver"); +MODULE_AUTHOR("Georg Acher, Hartmut Birr"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(tda10023_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1002x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1002x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1002x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1002x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,87 @@ +/* + TDA10021/TDA10023 - Single Chip Cable Channel Receiver driver module + used on the the Siemens DVB-C cards + + Copyright (C) 1999 Convergence Integrated Media GmbH + Copyright (C) 2004 Markus Schulz + Support for TDA10021 + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef TDA1002x_H +#define TDA1002x_H + +#include + +struct tda1002x_config { + /* the demodulator's i2c address */ + u8 demod_address; + u8 invert; +}; + +enum tda10023_output_mode { + TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0, + TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1, + TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0, + TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */ +}; + +struct tda10023_config { + /* the demodulator's i2c address */ + u8 demod_address; + u8 invert; + + /* clock settings */ + u32 xtal; /* defaults: 28920000 */ + u8 pll_m; /* defaults: 8 */ + u8 pll_p; /* defaults: 4 */ + u8 pll_n; /* defaults: 1 */ + + /* MPEG2 TS output mode */ + u8 output_mode; + + /* input freq offset + baseband conversion type */ + u16 deltaf; +}; + +#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, + struct i2c_adapter* i2c, u8 pwm); +#else +static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, + struct i2c_adapter* i2c, u8 pwm) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_TDA10021 + +#if defined(CONFIG_DVB_TDA10023) || \ + (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda10023_attach( + const struct tda10023_config *config, + struct i2c_adapter *i2c, u8 pwm); +#else +static inline struct dvb_frontend *tda10023_attach( + const struct tda10023_config *config, + struct i2c_adapter *i2c, u8 pwm) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_TDA10023 + +#endif // TDA1002x_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10048.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10048.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10048.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10048.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,1193 @@ +/* + NXP TDA10048HN DVB OFDM demodulator driver + + Copyright (C) 2009 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "dvb_math.h" +#include "tda10048.h" + +#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw" +#define TDA10048_DEFAULT_FIRMWARE_SIZE 24878 + +/* Register name definitions */ +#define TDA10048_IDENTITY 0x00 +#define TDA10048_VERSION 0x01 +#define TDA10048_DSP_CODE_CPT 0x0C +#define TDA10048_DSP_CODE_IN 0x0E +#define TDA10048_IN_CONF1 0x10 +#define TDA10048_IN_CONF2 0x11 +#define TDA10048_IN_CONF3 0x12 +#define TDA10048_OUT_CONF1 0x14 +#define TDA10048_OUT_CONF2 0x15 +#define TDA10048_OUT_CONF3 0x16 +#define TDA10048_AUTO 0x18 +#define TDA10048_SYNC_STATUS 0x1A +#define TDA10048_CONF_C4_1 0x1E +#define TDA10048_CONF_C4_2 0x1F +#define TDA10048_CODE_IN_RAM 0x20 +#define TDA10048_CHANNEL_INFO1_R 0x22 +#define TDA10048_CHANNEL_INFO2_R 0x23 +#define TDA10048_CHANNEL_INFO1 0x24 +#define TDA10048_CHANNEL_INFO2 0x25 +#define TDA10048_TIME_ERROR_R 0x26 +#define TDA10048_TIME_ERROR 0x27 +#define TDA10048_FREQ_ERROR_LSB_R 0x28 +#define TDA10048_FREQ_ERROR_MSB_R 0x29 +#define TDA10048_FREQ_ERROR_LSB 0x2A +#define TDA10048_FREQ_ERROR_MSB 0x2B +#define TDA10048_IT_SEL 0x30 +#define TDA10048_IT_STAT 0x32 +#define TDA10048_DSP_AD_LSB 0x3C +#define TDA10048_DSP_AD_MSB 0x3D +#define TDA10048_DSP_REG_LSB 0x3E +#define TDA10048_DSP_REG_MSB 0x3F +#define TDA10048_CONF_TRISTATE1 0x44 +#define TDA10048_CONF_TRISTATE2 0x45 +#define TDA10048_CONF_POLARITY 0x46 +#define TDA10048_GPIO_SP_DS0 0x48 +#define TDA10048_GPIO_SP_DS1 0x49 +#define TDA10048_GPIO_SP_DS2 0x4A +#define TDA10048_GPIO_SP_DS3 0x4B +#define TDA10048_GPIO_OUT_SEL 0x4C +#define TDA10048_GPIO_SELECT 0x4D +#define TDA10048_IC_MODE 0x4E +#define TDA10048_CONF_XO 0x50 +#define TDA10048_CONF_PLL1 0x51 +#define TDA10048_CONF_PLL2 0x52 +#define TDA10048_CONF_PLL3 0x53 +#define TDA10048_CONF_ADC 0x54 +#define TDA10048_CONF_ADC_2 0x55 +#define TDA10048_CONF_C1_1 0x60 +#define TDA10048_CONF_C1_3 0x62 +#define TDA10048_AGC_CONF 0x70 +#define TDA10048_AGC_THRESHOLD_LSB 0x72 +#define TDA10048_AGC_THRESHOLD_MSB 0x73 +#define TDA10048_AGC_RENORM 0x74 +#define TDA10048_AGC_GAINS 0x76 +#define TDA10048_AGC_TUN_MIN 0x78 +#define TDA10048_AGC_TUN_MAX 0x79 +#define TDA10048_AGC_IF_MIN 0x7A +#define TDA10048_AGC_IF_MAX 0x7B +#define TDA10048_AGC_TUN_LEVEL 0x7E +#define TDA10048_AGC_IF_LEVEL 0x7F +#define TDA10048_DIG_AGC_LEVEL 0x81 +#define TDA10048_FREQ_PHY2_LSB 0x86 +#define TDA10048_FREQ_PHY2_MSB 0x87 +#define TDA10048_TIME_INVWREF_LSB 0x88 +#define TDA10048_TIME_INVWREF_MSB 0x89 +#define TDA10048_TIME_WREF_LSB 0x8A +#define TDA10048_TIME_WREF_MID1 0x8B +#define TDA10048_TIME_WREF_MID2 0x8C +#define TDA10048_TIME_WREF_MSB 0x8D +#define TDA10048_NP_OUT 0xA2 +#define TDA10048_CELL_ID_LSB 0xA4 +#define TDA10048_CELL_ID_MSB 0xA5 +#define TDA10048_EXTTPS_ODD 0xAA +#define TDA10048_EXTTPS_EVEN 0xAB +#define TDA10048_TPS_LENGTH 0xAC +#define TDA10048_FREE_REG_1 0xB2 +#define TDA10048_FREE_REG_2 0xB3 +#define TDA10048_CONF_C3_1 0xC0 +#define TDA10048_CVBER_CTRL 0xC2 +#define TDA10048_CBER_NMAX_LSB 0xC4 +#define TDA10048_CBER_NMAX_MSB 0xC5 +#define TDA10048_CBER_LSB 0xC6 +#define TDA10048_CBER_MSB 0xC7 +#define TDA10048_VBER_LSB 0xC8 +#define TDA10048_VBER_MID 0xC9 +#define TDA10048_VBER_MSB 0xCA +#define TDA10048_CVBER_LUT 0xCC +#define TDA10048_UNCOR_CTRL 0xCD +#define TDA10048_UNCOR_CPT_LSB 0xCE +#define TDA10048_UNCOR_CPT_MSB 0xCF +#define TDA10048_SOFT_IT_C3 0xD6 +#define TDA10048_CONF_TS2 0xE0 +#define TDA10048_CONF_TS1 0xE1 + +static unsigned int debug; + +#define dprintk(level, fmt, arg...)\ + do { if (debug >= level)\ + printk(KERN_DEBUG "tda10048: " fmt, ## arg);\ + } while (0) + +struct tda10048_state { + + struct i2c_adapter *i2c; + + /* We'll cache and update the attach config settings */ + struct tda10048_config config; + struct dvb_frontend frontend; + + int fwloaded; + + u32 freq_if_hz; + u32 xtal_hz; + u32 pll_mfactor; + u32 pll_nfactor; + u32 pll_pfactor; + u32 sample_freq; + + enum fe_bandwidth bandwidth; +}; + +static struct init_tab { + u8 reg; + u16 data; +} init_tab[] = { + { TDA10048_CONF_PLL1, 0x08 }, + { TDA10048_CONF_ADC_2, 0x00 }, + { TDA10048_CONF_C4_1, 0x00 }, + { TDA10048_CONF_PLL1, 0x0f }, + { TDA10048_CONF_PLL2, 0x0a }, + { TDA10048_CONF_PLL3, 0x43 }, + { TDA10048_FREQ_PHY2_LSB, 0x02 }, + { TDA10048_FREQ_PHY2_MSB, 0x0a }, + { TDA10048_TIME_WREF_LSB, 0xbd }, + { TDA10048_TIME_WREF_MID1, 0xe4 }, + { TDA10048_TIME_WREF_MID2, 0xa8 }, + { TDA10048_TIME_WREF_MSB, 0x02 }, + { TDA10048_TIME_INVWREF_LSB, 0x04 }, + { TDA10048_TIME_INVWREF_MSB, 0x06 }, + { TDA10048_CONF_C4_1, 0x00 }, + { TDA10048_CONF_C1_1, 0xa8 }, + { TDA10048_AGC_CONF, 0x16 }, + { TDA10048_CONF_C1_3, 0x0b }, + { TDA10048_AGC_TUN_MIN, 0x00 }, + { TDA10048_AGC_TUN_MAX, 0xff }, + { TDA10048_AGC_IF_MIN, 0x00 }, + { TDA10048_AGC_IF_MAX, 0xff }, + { TDA10048_AGC_THRESHOLD_MSB, 0x00 }, + { TDA10048_AGC_THRESHOLD_LSB, 0x70 }, + { TDA10048_CVBER_CTRL, 0x38 }, + { TDA10048_AGC_GAINS, 0x12 }, + { TDA10048_CONF_XO, 0x00 }, + { TDA10048_CONF_TS1, 0x07 }, + { TDA10048_IC_MODE, 0x00 }, + { TDA10048_CONF_TS2, 0xc0 }, + { TDA10048_CONF_TRISTATE1, 0x21 }, + { TDA10048_CONF_TRISTATE2, 0x00 }, + { TDA10048_CONF_POLARITY, 0x00 }, + { TDA10048_CONF_C4_2, 0x04 }, + { TDA10048_CONF_ADC, 0x60 }, + { TDA10048_CONF_ADC_2, 0x10 }, + { TDA10048_CONF_ADC, 0x60 }, + { TDA10048_CONF_ADC_2, 0x00 }, + { TDA10048_CONF_C1_1, 0xa8 }, + { TDA10048_UNCOR_CTRL, 0x00 }, + { TDA10048_CONF_C4_2, 0x04 }, +}; + +static struct pll_tab { + u32 clk_freq_khz; + u32 if_freq_khz; + u8 m, n, p; +} pll_tab[] = { + { TDA10048_CLK_4000, TDA10048_IF_36130, 10, 0, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_3300, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_3500, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_3800, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_4000, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_4300, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 }, +}; + +static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) +{ + struct tda10048_config *config = &state->config; + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = config->demod_address, + .flags = 0, .buf = buf, .len = 2 }; + + dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data); + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (ret == %i)\n", __func__, ret); + + return (ret != 1) ? -1 : 0; +} + +static u8 tda10048_readreg(struct tda10048_state *state, u8 reg) +{ + struct tda10048_config *config = &state->config; + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { .addr = config->demod_address, + .flags = 0, .buf = b0, .len = 1 }, + { .addr = config->demod_address, + .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg); + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk(KERN_ERR "%s: readreg error (ret == %i)\n", + __func__, ret); + + return b1[0]; +} + +static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg, + const u8 *data, u16 len) +{ + struct tda10048_config *config = &state->config; + int ret = -EREMOTEIO; + struct i2c_msg msg; + u8 *buf; + + dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len); + + buf = kmalloc(len + 1, GFP_KERNEL); + if (buf == NULL) { + ret = -ENOMEM; + goto error; + } + + *buf = reg; + memcpy(buf + 1, data, len); + + msg.addr = config->demod_address; + msg.flags = 0; + msg.buf = buf; + msg.len = len + 1; + + dprintk(2, "%s(): write len = %d\n", + __func__, msg.len); + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) { + printk(KERN_ERR "%s(): writereg error err %i\n", + __func__, ret); + ret = -EREMOTEIO; + } + +error: + kfree(buf); + + return ret; +} + +static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz, + u32 if_hz) +{ + struct tda10048_state *state = fe->demodulator_priv; + u64 t; + + dprintk(1, "%s()\n", __func__); + + if (sample_freq_hz == 0) + return -EINVAL; + + if (if_hz < (sample_freq_hz / 2)) { + /* PHY2 = (if2/fs) * 2^15 */ + t = if_hz; + t *= 10; + t *= 32768; + do_div(t, sample_freq_hz); + t += 5; + do_div(t, 10); + } else { + /* PHY2 = ((IF1-fs)/fs) * 2^15 */ + t = sample_freq_hz - if_hz; + t *= 10; + t *= 32768; + do_div(t, sample_freq_hz); + t += 5; + do_div(t, 10); + t = ~t + 1; + } + + tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t); + tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8)); + + return 0; +} + +static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz, + u32 bw) +{ + struct tda10048_state *state = fe->demodulator_priv; + u64 t, z; + u32 b = 8000000; + + dprintk(1, "%s()\n", __func__); + + if (sample_freq_hz == 0) + return -EINVAL; + + if (bw == BANDWIDTH_6_MHZ) + b = 6000000; + else + if (bw == BANDWIDTH_7_MHZ) + b = 7000000; + + /* WREF = (B / (7 * fs)) * 2^31 */ + t = b * 10; + /* avoid warning: this decimal constant is unsigned only in ISO C90 */ + /* t *= 2147483648 on 32bit platforms */ + t *= (2048 * 1024); + t *= 1024; + z = 7 * sample_freq_hz; + do_div(t, z); + t += 5; + do_div(t, 10); + + tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t); + tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8)); + tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16)); + tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24)); + + return 0; +} + +static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz, + u32 bw) +{ + struct tda10048_state *state = fe->demodulator_priv; + u64 t; + u32 b = 8000000; + + dprintk(1, "%s()\n", __func__); + + if (sample_freq_hz == 0) + return -EINVAL; + + if (bw == BANDWIDTH_6_MHZ) + b = 6000000; + else + if (bw == BANDWIDTH_7_MHZ) + b = 7000000; + + /* INVWREF = ((7 * fs) / B) * 2^5 */ + t = sample_freq_hz; + t *= 7; + t *= 32; + t *= 10; + do_div(t, b); + t += 5; + do_div(t, 10); + + tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t); + tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8)); + + return 0; +} + +static int tda10048_set_bandwidth(struct dvb_frontend *fe, + enum fe_bandwidth bw) +{ + struct tda10048_state *state = fe->demodulator_priv; + dprintk(1, "%s(bw=%d)\n", __func__, bw); + + /* Bandwidth setting may need to be adjusted */ + switch (bw) { + case BANDWIDTH_6_MHZ: + case BANDWIDTH_7_MHZ: + case BANDWIDTH_8_MHZ: + tda10048_set_wref(fe, state->sample_freq, bw); + tda10048_set_invwref(fe, state->sample_freq, bw); + break; + default: + printk(KERN_ERR "%s() invalid bandwidth\n", __func__); + return -EINVAL; + } + + state->bandwidth = bw; + + return 0; +} + +static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw) +{ + struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; + int i; + u32 if_freq_khz; + + dprintk(1, "%s(bw = %d)\n", __func__, bw); + + /* based on target bandwidth and clk we calculate pll factors */ + switch (bw) { + case BANDWIDTH_6_MHZ: + if_freq_khz = config->dtv6_if_freq_khz; + break; + case BANDWIDTH_7_MHZ: + if_freq_khz = config->dtv7_if_freq_khz; + break; + case BANDWIDTH_8_MHZ: + if_freq_khz = config->dtv8_if_freq_khz; + break; + default: + printk(KERN_ERR "%s() no default\n", __func__); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(pll_tab); i++) { + if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) && + (pll_tab[i].if_freq_khz == if_freq_khz)) { + + state->freq_if_hz = pll_tab[i].if_freq_khz * 1000; + state->xtal_hz = pll_tab[i].clk_freq_khz * 1000; + state->pll_mfactor = pll_tab[i].m; + state->pll_nfactor = pll_tab[i].n; + state->pll_pfactor = pll_tab[i].p; + break; + } + } + if (i == ARRAY_SIZE(pll_tab)) { + printk(KERN_ERR "%s() Incorrect attach settings\n", + __func__); + return -EINVAL; + } + + dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz); + dprintk(1, "- xtal_hz = %d\n", state->xtal_hz); + dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor); + dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor); + dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor); + + /* Calculate the sample frequency */ + state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45); + state->sample_freq /= (state->pll_nfactor + 1); + state->sample_freq /= (state->pll_pfactor + 4); + dprintk(1, "- sample_freq = %d\n", state->sample_freq); + + /* Update the I/F */ + tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz); + + return 0; +} + +static int tda10048_firmware_upload(struct dvb_frontend *fe) +{ + struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; + const struct firmware *fw; + int ret; + int pos = 0; + int cnt; + u8 wlen = config->fwbulkwritelen; + + if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50)) + wlen = TDA10048_BULKWRITE_200; + + /* request the firmware, this will block and timeout */ + printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n", + __func__, + TDA10048_DEFAULT_FIRMWARE); + + ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE, + state->i2c->dev.parent); + if (ret) { + printk(KERN_ERR "%s: Upload failed. (file not found?)\n", + __func__); + return -EIO; + } else { + printk(KERN_INFO "%s: firmware read %Zu bytes.\n", + __func__, + fw->size); + ret = 0; + } + + if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) { + printk(KERN_ERR "%s: firmware incorrect size\n", __func__); + ret = -EIO; + } else { + printk(KERN_INFO "%s: firmware uploading\n", __func__); + + /* Soft reset */ + tda10048_writereg(state, TDA10048_CONF_TRISTATE1, + tda10048_readreg(state, TDA10048_CONF_TRISTATE1) + & 0xfe); + tda10048_writereg(state, TDA10048_CONF_TRISTATE1, + tda10048_readreg(state, TDA10048_CONF_TRISTATE1) + | 0x01); + + /* Put the demod into host download mode */ + tda10048_writereg(state, TDA10048_CONF_C4_1, + tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9); + + /* Boot the DSP */ + tda10048_writereg(state, TDA10048_CONF_C4_1, + tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08); + + /* Prepare for download */ + tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0); + + /* Download the firmware payload */ + while (pos < fw->size) { + + if ((fw->size - pos) > wlen) + cnt = wlen; + else + cnt = fw->size - pos; + + tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN, + &fw->data[pos], cnt); + + pos += cnt; + } + + ret = -EIO; + /* Wait up to 250ms for the DSP to boot */ + for (cnt = 0; cnt < 250 ; cnt += 10) { + + msleep(10); + + if (tda10048_readreg(state, TDA10048_SYNC_STATUS) + & 0x40) { + ret = 0; + break; + } + } + } + + release_firmware(fw); + + if (ret == 0) { + printk(KERN_INFO "%s: firmware uploaded\n", __func__); + state->fwloaded = 1; + } else + printk(KERN_ERR "%s: firmware upload failed\n", __func__); + + return ret; +} + +static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion) +{ + struct tda10048_state *state = fe->demodulator_priv; + + dprintk(1, "%s(%d)\n", __func__, inversion); + + if (inversion == TDA10048_INVERSION_ON) + tda10048_writereg(state, TDA10048_CONF_C1_1, + tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20); + else + tda10048_writereg(state, TDA10048_CONF_C1_1, + tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf); + + return 0; +} + +/* Retrieve the demod settings */ +static int tda10048_get_tps(struct tda10048_state *state, + struct dvb_ofdm_parameters *p) +{ + u8 val; + + /* Make sure the TPS regs are valid */ + if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01)) + return -EAGAIN; + + val = tda10048_readreg(state, TDA10048_OUT_CONF2); + switch ((val & 0x60) >> 5) { + case 0: + p->constellation = QPSK; + break; + case 1: + p->constellation = QAM_16; + break; + case 2: + p->constellation = QAM_64; + break; + } + switch ((val & 0x18) >> 3) { + case 0: + p->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + p->hierarchy_information = HIERARCHY_1; + break; + case 2: + p->hierarchy_information = HIERARCHY_2; + break; + case 3: + p->hierarchy_information = HIERARCHY_4; + break; + } + switch (val & 0x07) { + case 0: + p->code_rate_HP = FEC_1_2; + break; + case 1: + p->code_rate_HP = FEC_2_3; + break; + case 2: + p->code_rate_HP = FEC_3_4; + break; + case 3: + p->code_rate_HP = FEC_5_6; + break; + case 4: + p->code_rate_HP = FEC_7_8; + break; + } + + val = tda10048_readreg(state, TDA10048_OUT_CONF3); + switch (val & 0x07) { + case 0: + p->code_rate_LP = FEC_1_2; + break; + case 1: + p->code_rate_LP = FEC_2_3; + break; + case 2: + p->code_rate_LP = FEC_3_4; + break; + case 3: + p->code_rate_LP = FEC_5_6; + break; + case 4: + p->code_rate_LP = FEC_7_8; + break; + } + + val = tda10048_readreg(state, TDA10048_OUT_CONF1); + switch ((val & 0x0c) >> 2) { + case 0: + p->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + p->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + p->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + p->guard_interval = GUARD_INTERVAL_1_4; + break; + } + switch (val & 0x03) { + case 0: + p->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + p->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + return 0; +} + +static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; + dprintk(1, "%s(%d)\n", __func__, enable); + + if (config->disable_gate_access) + return 0; + + if (enable) + return tda10048_writereg(state, TDA10048_CONF_C4_1, + tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02); + else + return tda10048_writereg(state, TDA10048_CONF_C4_1, + tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd); +} + +static int tda10048_output_mode(struct dvb_frontend *fe, int serial) +{ + struct tda10048_state *state = fe->demodulator_priv; + dprintk(1, "%s(%d)\n", __func__, serial); + + /* Ensure pins are out of tri-state */ + tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21); + tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00); + + if (serial) { + tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20); + tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0); + } else { + tda10048_writereg(state, TDA10048_IC_MODE, 0x00); + tda10048_writereg(state, TDA10048_CONF_TS2, 0x01); + } + + return 0; +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +/* TODO: Support manual tuning with specific params */ +static int tda10048_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct tda10048_state *state = fe->demodulator_priv; + + dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); + + /* Update the I/F pll's if the bandwidth changes */ + if (p->u.ofdm.bandwidth != state->bandwidth) { + tda10048_set_if(fe, p->u.ofdm.bandwidth); + tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth); + } + + if (fe->ops.tuner_ops.set_params) { + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + fe->ops.tuner_ops.set_params(fe, p); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* Enable demod TPS auto detection and begin acquisition */ + tda10048_writereg(state, TDA10048_AUTO, 0x57); + /* trigger cber and vber acquisition */ + tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B); + + return 0; +} + +/* Establish sane defaults and load firmware. */ +static int tda10048_init(struct dvb_frontend *fe) +{ + struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; + int ret = 0, i; + + dprintk(1, "%s()\n", __func__); + + /* Apply register defaults */ + for (i = 0; i < ARRAY_SIZE(init_tab); i++) + tda10048_writereg(state, init_tab[i].reg, init_tab[i].data); + + if (state->fwloaded == 0) + ret = tda10048_firmware_upload(fe); + + /* Set either serial or parallel */ + tda10048_output_mode(fe, config->output_mode); + + /* Set inversion */ + tda10048_set_inversion(fe, config->inversion); + + /* Establish default RF values */ + tda10048_set_if(fe, BANDWIDTH_8_MHZ); + tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ); + + /* Ensure we leave the gate closed */ + tda10048_i2c_gate_ctrl(fe, 0); + + return ret; +} + +static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct tda10048_state *state = fe->demodulator_priv; + u8 reg; + + *status = 0; + + reg = tda10048_readreg(state, TDA10048_SYNC_STATUS); + + dprintk(1, "%s() status =0x%02x\n", __func__, reg); + + if (reg & 0x02) + *status |= FE_HAS_CARRIER; + + if (reg & 0x04) + *status |= FE_HAS_SIGNAL; + + if (reg & 0x08) { + *status |= FE_HAS_LOCK; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + } + + return 0; +} + +static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct tda10048_state *state = fe->demodulator_priv; + static u32 cber_current; + u32 cber_nmax; + u64 cber_tmp; + + dprintk(1, "%s()\n", __func__); + + /* update cber on interrupt */ + if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) { + cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 | + tda10048_readreg(state, TDA10048_CBER_LSB); + cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 | + tda10048_readreg(state, TDA10048_CBER_NMAX_LSB); + cber_tmp *= 100000000; + cber_tmp *= 2; + cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1); + cber_current = (u32)cber_tmp; + /* retrigger cber acquisition */ + tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39); + } + /* actual cber is (*ber)/1e8 */ + *ber = cber_current; + + return 0; +} + +static int tda10048_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) +{ + struct tda10048_state *state = fe->demodulator_priv; + u8 v; + + dprintk(1, "%s()\n", __func__); + + *signal_strength = 65535; + + v = tda10048_readreg(state, TDA10048_NP_OUT); + if (v > 0) + *signal_strength -= (v << 8) | v; + + return 0; +} + +/* SNR lookup table */ +static struct snr_tab { + u8 val; + u8 data; +} snr_tab[] = { + { 0, 0 }, + { 1, 246 }, + { 2, 215 }, + { 3, 198 }, + { 4, 185 }, + { 5, 176 }, + { 6, 168 }, + { 7, 161 }, + { 8, 155 }, + { 9, 150 }, + { 10, 146 }, + { 11, 141 }, + { 12, 138 }, + { 13, 134 }, + { 14, 131 }, + { 15, 128 }, + { 16, 125 }, + { 17, 122 }, + { 18, 120 }, + { 19, 118 }, + { 20, 115 }, + { 21, 113 }, + { 22, 111 }, + { 23, 109 }, + { 24, 107 }, + { 25, 106 }, + { 26, 104 }, + { 27, 102 }, + { 28, 101 }, + { 29, 99 }, + { 30, 98 }, + { 31, 96 }, + { 32, 95 }, + { 33, 94 }, + { 34, 92 }, + { 35, 91 }, + { 36, 90 }, + { 37, 89 }, + { 38, 88 }, + { 39, 86 }, + { 40, 85 }, + { 41, 84 }, + { 42, 83 }, + { 43, 82 }, + { 44, 81 }, + { 45, 80 }, + { 46, 79 }, + { 47, 78 }, + { 48, 77 }, + { 49, 76 }, + { 50, 76 }, + { 51, 75 }, + { 52, 74 }, + { 53, 73 }, + { 54, 72 }, + { 56, 71 }, + { 57, 70 }, + { 58, 69 }, + { 60, 68 }, + { 61, 67 }, + { 63, 66 }, + { 64, 65 }, + { 66, 64 }, + { 67, 63 }, + { 68, 62 }, + { 69, 62 }, + { 70, 61 }, + { 72, 60 }, + { 74, 59 }, + { 75, 58 }, + { 77, 57 }, + { 79, 56 }, + { 81, 55 }, + { 83, 54 }, + { 85, 53 }, + { 87, 52 }, + { 89, 51 }, + { 91, 50 }, + { 93, 49 }, + { 95, 48 }, + { 97, 47 }, + { 100, 46 }, + { 102, 45 }, + { 104, 44 }, + { 107, 43 }, + { 109, 42 }, + { 112, 41 }, + { 114, 40 }, + { 117, 39 }, + { 120, 38 }, + { 123, 37 }, + { 125, 36 }, + { 128, 35 }, + { 131, 34 }, + { 134, 33 }, + { 138, 32 }, + { 141, 31 }, + { 144, 30 }, + { 147, 29 }, + { 151, 28 }, + { 154, 27 }, + { 158, 26 }, + { 162, 25 }, + { 165, 24 }, + { 169, 23 }, + { 173, 22 }, + { 177, 21 }, + { 181, 20 }, + { 186, 19 }, + { 190, 18 }, + { 194, 17 }, + { 199, 16 }, + { 204, 15 }, + { 208, 14 }, + { 213, 13 }, + { 218, 12 }, + { 223, 11 }, + { 229, 10 }, + { 234, 9 }, + { 239, 8 }, + { 245, 7 }, + { 251, 6 }, + { 255, 5 }, +}; + +static int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct tda10048_state *state = fe->demodulator_priv; + u8 v; + int i, ret = -EINVAL; + + dprintk(1, "%s()\n", __func__); + + v = tda10048_readreg(state, TDA10048_NP_OUT); + for (i = 0; i < ARRAY_SIZE(snr_tab); i++) { + if (v <= snr_tab[i].val) { + *snr = snr_tab[i].data; + ret = 0; + break; + } + } + + return ret; +} + +static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct tda10048_state *state = fe->demodulator_priv; + + dprintk(1, "%s()\n", __func__); + + *ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 | + tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB); + /* clear the uncorrected TS packets counter when saturated */ + if (*ucblocks == 0xFFFF) + tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80); + + return 0; +} + +static int tda10048_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct tda10048_state *state = fe->demodulator_priv; + + dprintk(1, "%s()\n", __func__); + + p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1) + & 0x20 ? INVERSION_ON : INVERSION_OFF; + + return tda10048_get_tps(state, &p->u.ofdm); +} + +static int tda10048_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void tda10048_release(struct dvb_frontend *fe) +{ + struct tda10048_state *state = fe->demodulator_priv; + dprintk(1, "%s()\n", __func__); + kfree(state); +} + +static void tda10048_establish_defaults(struct dvb_frontend *fe) +{ + struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; + + /* Validate/default the config */ + if (config->dtv6_if_freq_khz == 0) { + config->dtv6_if_freq_khz = TDA10048_IF_4300; + printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->dtv6_if_freq_khz); + } + + if (config->dtv7_if_freq_khz == 0) { + config->dtv7_if_freq_khz = TDA10048_IF_4300; + printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->dtv7_if_freq_khz); + } + + if (config->dtv8_if_freq_khz == 0) { + config->dtv8_if_freq_khz = TDA10048_IF_4300; + printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->dtv8_if_freq_khz); + } + + if (config->clk_freq_khz == 0) { + config->clk_freq_khz = TDA10048_CLK_16000; + printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->clk_freq_khz); + } +} + +static struct dvb_frontend_ops tda10048_ops; + +struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, + struct i2c_adapter *i2c) +{ + struct tda10048_state *state = NULL; + + dprintk(1, "%s()\n", __func__); + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct tda10048_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state and clone the config */ + memcpy(&state->config, config, sizeof(*config)); + state->i2c = i2c; + state->fwloaded = 0; + state->bandwidth = BANDWIDTH_8_MHZ; + + /* check if the demod is present */ + if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &tda10048_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* Establish any defaults the the user didn't pass */ + tda10048_establish_defaults(&state->frontend); + + /* Set the xtal and freq defaults */ + if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0) + goto error; + + /* Default bandwidth */ + if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0) + goto error; + + /* Leave the gate closed */ + tda10048_i2c_gate_ctrl(&state->frontend, 0); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(tda10048_attach); + +static struct dvb_frontend_ops tda10048_ops = { + + .info = { + .name = "NXP TDA10048HN DVB-T", + .type = FE_OFDM, + .frequency_min = 177000000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER + }, + + .release = tda10048_release, + .init = tda10048_init, + .i2c_gate_ctrl = tda10048_i2c_gate_ctrl, + .set_frontend = tda10048_set_frontend, + .get_frontend = tda10048_get_frontend, + .get_tune_settings = tda10048_get_tune_settings, + .read_status = tda10048_read_status, + .read_ber = tda10048_read_ber, + .read_signal_strength = tda10048_read_signal_strength, + .read_snr = tda10048_read_snr, + .read_ucblocks = tda10048_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +MODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10048.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10048.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10048.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10048.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + NXP TDA10048HN DVB OFDM demodulator driver + + Copyright (C) 2009 Steven Toth + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef TDA10048_H +#define TDA10048_H + +#include +#include + +struct tda10048_config { + + /* the demodulator's i2c address */ + u8 demod_address; + + /* serial/parallel output */ +#define TDA10048_PARALLEL_OUTPUT 0 +#define TDA10048_SERIAL_OUTPUT 1 + u8 output_mode; + +#define TDA10048_BULKWRITE_200 200 +#define TDA10048_BULKWRITE_50 50 + u8 fwbulkwritelen; + + /* Spectral Inversion */ +#define TDA10048_INVERSION_OFF 0 +#define TDA10048_INVERSION_ON 1 + u8 inversion; + +#define TDA10048_IF_3300 3300 +#define TDA10048_IF_3500 3500 +#define TDA10048_IF_3800 3800 +#define TDA10048_IF_4000 4000 +#define TDA10048_IF_4300 4300 +#define TDA10048_IF_4500 4500 +#define TDA10048_IF_4750 4750 +#define TDA10048_IF_36130 36130 + u16 dtv6_if_freq_khz; + u16 dtv7_if_freq_khz; + u16 dtv8_if_freq_khz; + +#define TDA10048_CLK_4000 4000 +#define TDA10048_CLK_16000 16000 + u16 clk_freq_khz; + + /* Disable I2C gate access */ + u8 disable_gate_access; +}; + +#if defined(CONFIG_DVB_TDA10048) || \ + (defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda10048_attach( + const struct tda10048_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *tda10048_attach( + const struct tda10048_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_TDA10048 */ + +#endif /* TDA10048_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1004x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1004x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1004x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1004x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1380 @@ + /* + Driver for Philips tda1004xh OFDM Demodulator + + (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ +/* + * This driver needs external firmware. Please use the commands + * "/Documentation/dvb/get_dvb_firmware tda10045", + * "/Documentation/dvb/get_dvb_firmware tda10046" to + * download/extract them, and then copy them to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). + */ +#define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw" +#define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw" + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "tda1004x.h" + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "tda1004x: " args); \ + } while (0) + +#define TDA1004X_CHIPID 0x00 +#define TDA1004X_AUTO 0x01 +#define TDA1004X_IN_CONF1 0x02 +#define TDA1004X_IN_CONF2 0x03 +#define TDA1004X_OUT_CONF1 0x04 +#define TDA1004X_OUT_CONF2 0x05 +#define TDA1004X_STATUS_CD 0x06 +#define TDA1004X_CONFC4 0x07 +#define TDA1004X_DSSPARE2 0x0C +#define TDA10045H_CODE_IN 0x0D +#define TDA10045H_FWPAGE 0x0E +#define TDA1004X_SCAN_CPT 0x10 +#define TDA1004X_DSP_CMD 0x11 +#define TDA1004X_DSP_ARG 0x12 +#define TDA1004X_DSP_DATA1 0x13 +#define TDA1004X_DSP_DATA2 0x14 +#define TDA1004X_CONFADC1 0x15 +#define TDA1004X_CONFC1 0x16 +#define TDA10045H_S_AGC 0x1a +#define TDA10046H_AGC_TUN_LEVEL 0x1a +#define TDA1004X_SNR 0x1c +#define TDA1004X_CONF_TS1 0x1e +#define TDA1004X_CONF_TS2 0x1f +#define TDA1004X_CBER_RESET 0x20 +#define TDA1004X_CBER_MSB 0x21 +#define TDA1004X_CBER_LSB 0x22 +#define TDA1004X_CVBER_LUT 0x23 +#define TDA1004X_VBER_MSB 0x24 +#define TDA1004X_VBER_MID 0x25 +#define TDA1004X_VBER_LSB 0x26 +#define TDA1004X_UNCOR 0x27 + +#define TDA10045H_CONFPLL_P 0x2D +#define TDA10045H_CONFPLL_M_MSB 0x2E +#define TDA10045H_CONFPLL_M_LSB 0x2F +#define TDA10045H_CONFPLL_N 0x30 + +#define TDA10046H_CONFPLL1 0x2D +#define TDA10046H_CONFPLL2 0x2F +#define TDA10046H_CONFPLL3 0x30 +#define TDA10046H_TIME_WREF1 0x31 +#define TDA10046H_TIME_WREF2 0x32 +#define TDA10046H_TIME_WREF3 0x33 +#define TDA10046H_TIME_WREF4 0x34 +#define TDA10046H_TIME_WREF5 0x35 + +#define TDA10045H_UNSURW_MSB 0x31 +#define TDA10045H_UNSURW_LSB 0x32 +#define TDA10045H_WREF_MSB 0x33 +#define TDA10045H_WREF_MID 0x34 +#define TDA10045H_WREF_LSB 0x35 +#define TDA10045H_MUXOUT 0x36 +#define TDA1004X_CONFADC2 0x37 + +#define TDA10045H_IOFFSET 0x38 + +#define TDA10046H_CONF_TRISTATE1 0x3B +#define TDA10046H_CONF_TRISTATE2 0x3C +#define TDA10046H_CONF_POLARITY 0x3D +#define TDA10046H_FREQ_OFFSET 0x3E +#define TDA10046H_GPIO_OUT_SEL 0x41 +#define TDA10046H_GPIO_SELECT 0x42 +#define TDA10046H_AGC_CONF 0x43 +#define TDA10046H_AGC_THR 0x44 +#define TDA10046H_AGC_RENORM 0x45 +#define TDA10046H_AGC_GAINS 0x46 +#define TDA10046H_AGC_TUN_MIN 0x47 +#define TDA10046H_AGC_TUN_MAX 0x48 +#define TDA10046H_AGC_IF_MIN 0x49 +#define TDA10046H_AGC_IF_MAX 0x4A + +#define TDA10046H_FREQ_PHY2_MSB 0x4D +#define TDA10046H_FREQ_PHY2_LSB 0x4E + +#define TDA10046H_CVBER_CTRL 0x4F +#define TDA10046H_AGC_IF_LEVEL 0x52 +#define TDA10046H_CODE_CPT 0x57 +#define TDA10046H_CODE_IN 0x58 + + +static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; + + dprintk("%s: reg=0x%x, data=0x%x\n", __func__, reg, data); + + msg.addr = state->config->demod_address; + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", + __func__, reg, data, ret); + + dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__, + reg, data, ret); + return (ret != 1) ? -1 : 0; +} + +static int tda1004x_read_byte(struct tda1004x_state *state, int reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 }, + { .flags = I2C_M_RD, .buf = b1, .len = 1 }}; + + dprintk("%s: reg=0x%x\n", __func__, reg); + + msg[0].addr = state->config->demod_address; + msg[1].addr = state->config->demod_address; + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, + ret); + return -EINVAL; + } + + dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__, + reg, b1[0], ret); + return b1[0]; +} + +static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data) +{ + int val; + dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __func__, reg, + mask, data); + + // read a byte and check + val = tda1004x_read_byte(state, reg); + if (val < 0) + return val; + + // mask if off + val = val & ~mask; + val |= data & 0xff; + + // write it out again + return tda1004x_write_byteI(state, reg, val); +} + +static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len) +{ + int i; + int result; + + dprintk("%s: reg=0x%x, len=0x%x\n", __func__, reg, len); + + result = 0; + for (i = 0; i < len; i++) { + result = tda1004x_write_byteI(state, reg + i, buf[i]); + if (result != 0) + break; + } + + return result; +} + +static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state) +{ + int result; + dprintk("%s\n", __func__); + + result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2); + msleep(20); + return result; +} + +static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state) +{ + dprintk("%s\n", __func__); + + return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0); +} + +static int tda10045h_set_bandwidth(struct tda1004x_state *state, + fe_bandwidth_t bandwidth) +{ + static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; + static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb }; + static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 }; + + switch (bandwidth) { + case BANDWIDTH_6_MHZ: + tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); + break; + + case BANDWIDTH_7_MHZ: + tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); + break; + + case BANDWIDTH_8_MHZ: + tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); + break; + + default: + return -EINVAL; + } + + tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0); + + return 0; +} + +static int tda10046h_set_bandwidth(struct tda1004x_state *state, + fe_bandwidth_t bandwidth) +{ + static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 }; + static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f }; + static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d }; + + static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 }; + static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab }; + static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 }; + int tda10046_clk53m; + + if ((state->config->if_freq == TDA10046_FREQ_045) || + (state->config->if_freq == TDA10046_FREQ_052)) + tda10046_clk53m = 0; + else + tda10046_clk53m = 1; + switch (bandwidth) { + case BANDWIDTH_6_MHZ: + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M, + sizeof(bandwidth_6mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M, + sizeof(bandwidth_6mhz_48M)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab); + } + break; + + case BANDWIDTH_7_MHZ: + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M, + sizeof(bandwidth_7mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M, + sizeof(bandwidth_7mhz_48M)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); + } + break; + + case BANDWIDTH_8_MHZ: + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M, + sizeof(bandwidth_8mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M, + sizeof(bandwidth_8mhz_48M)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55); + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int tda1004x_do_upload(struct tda1004x_state *state, + const unsigned char *mem, unsigned int len, + u8 dspCodeCounterReg, u8 dspCodeInReg) +{ + u8 buf[65]; + struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 }; + int tx_size; + int pos = 0; + + /* clear code counter */ + tda1004x_write_byteI(state, dspCodeCounterReg, 0); + fw_msg.addr = state->config->demod_address; + + buf[0] = dspCodeInReg; + while (pos != len) { + // work out how much to send this time + tx_size = len - pos; + if (tx_size > 0x10) + tx_size = 0x10; + + // send the chunk + memcpy(buf + 1, mem + pos, tx_size); + fw_msg.len = tx_size + 1; + if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) { + printk(KERN_ERR "tda1004x: Error during firmware upload\n"); + return -EIO; + } + pos += tx_size; + + dprintk("%s: fw_pos=0x%x\n", __func__, pos); + } + // give the DSP a chance to settle 03/10/05 Hac + msleep(100); + + return 0; +} + +static int tda1004x_check_upload_ok(struct tda1004x_state *state) +{ + u8 data1, data2; + unsigned long timeout; + + if (state->demod_type == TDA1004X_DEMOD_TDA10046) { + timeout = jiffies + 2 * HZ; + while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n"); + break; + } + msleep(1); + } + } else + msleep(100); + + // check upload was OK + tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP + tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67); + + data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1); + data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2); + if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) { + printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2); + return -EIO; + } + printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2); + return 0; +} + +static int tda10045_fwupload(struct dvb_frontend* fe) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int ret; + const struct firmware *fw; + + /* don't re-upload unless necessary */ + if (tda1004x_check_upload_ok(state) == 0) + return 0; + + /* request the firmware, this will block until someone uploads it */ + printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE); + ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); + if (ret) { + printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); + return ret; + } + + /* reset chip */ + tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); + msleep(10); + + /* set parameters */ + tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ); + + ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); + release_firmware(fw); + if (ret) + return ret; + printk(KERN_INFO "tda1004x: firmware upload complete\n"); + + /* wait for DSP to initialise */ + /* DSPREADY doesn't seem to work on the TDA10045H */ + msleep(100); + + return tda1004x_check_upload_ok(state); +} + +static void tda10046_init_plls(struct dvb_frontend* fe) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int tda10046_clk53m; + + if ((state->config->if_freq == TDA10046_FREQ_045) || + (state->config->if_freq == TDA10046_FREQ_052)) + tda10046_clk53m = 0; + else + tda10046_clk53m = 1; + + tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0); + if(tda10046_clk53m) { + printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n"); + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8 + } else { + printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n"); + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3 + } + if (state->config->xtal_freq == TDA10046_XTAL_4M ) { + dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __func__); + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 + } else { + dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __func__); + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3 + } + if(tda10046_clk53m) + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67); + else + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72); + /* Note clock frequency is handled implicitly */ + switch (state->config->if_freq) { + case TDA10046_FREQ_045: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); + break; + case TDA10046_FREQ_052: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7); + break; + case TDA10046_FREQ_3617: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59); + break; + case TDA10046_FREQ_3613: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f); + break; + } + tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz + /* let the PLLs settle */ + msleep(120); +} + +static int tda10046_fwupload(struct dvb_frontend* fe) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int ret, confc4; + const struct firmware *fw; + + /* reset + wake up chip */ + if (state->config->xtal_freq == TDA10046_XTAL_4M) { + confc4 = 0; + } else { + dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__); + confc4 = 0x80; + } + tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4); + + tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); + /* set GPIO 1 and 3 */ + if (state->config->gpio_config != TDA10046_GPTRI) { + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33); + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f); + } + /* let the clocks recover from sleep */ + msleep(10); + + /* The PLLs need to be reprogrammed after sleep */ + tda10046_init_plls(fe); + tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0); + + /* don't re-upload unless necessary */ + if (tda1004x_check_upload_ok(state) == 0) + return 0; + + /* + For i2c normal work, we need to slow down the bus speed. + However, the slow down breaks the eeprom firmware load. + So, use normal speed for eeprom booting and then restore the + i2c speed after that. Tested with MSI TV @nyware A/D board, + that comes with firmware version 29 inside their eeprom. + + It should also be noticed that no other I2C transfer should + be in course while booting from eeprom, otherwise, tda10046 + goes into an instable state. So, proper locking are needed + at the i2c bus master. + */ + printk(KERN_INFO "tda1004x: trying to boot from eeprom\n"); + tda1004x_write_byteI(state, TDA1004X_CONFC4, 4); + msleep(300); + tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4); + + /* Checks if eeprom firmware went without troubles */ + if (tda1004x_check_upload_ok(state) == 0) + return 0; + + /* eeprom firmware didn't work. Load one manually. */ + + if (state->config->request_firmware != NULL) { + /* request the firmware, this will block until someone uploads it */ + printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); + ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); + if (ret) { + /* remain compatible to old bug: try to load with tda10045 image name */ + ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); + if (ret) { + printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); + return ret; + } else { + printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n", + TDA10046_DEFAULT_FIRMWARE); + } + } + } else { + printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n"); + return -EIO; + } + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST + ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); + release_firmware(fw); + return tda1004x_check_upload_ok(state); +} + +static int tda1004x_encode_fec(int fec) +{ + // convert known FEC values + switch (fec) { + case FEC_1_2: + return 0; + case FEC_2_3: + return 1; + case FEC_3_4: + return 2; + case FEC_5_6: + return 3; + case FEC_7_8: + return 4; + } + + // unsupported + return -EINVAL; +} + +static int tda1004x_decode_fec(int tdafec) +{ + // convert known FEC values + switch (tdafec) { + case 0: + return FEC_1_2; + case 1: + return FEC_2_3; + case 2: + return FEC_3_4; + case 3: + return FEC_5_6; + case 4: + return FEC_7_8; + } + + // unsupported + return -1; +} + +static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len) +{ + struct tda1004x_state* state = fe->demodulator_priv; + + if (len != 2) + return -EINVAL; + + return tda1004x_write_byteI(state, buf[0], buf[1]); +} + +static int tda10045_init(struct dvb_frontend* fe) +{ + struct tda1004x_state* state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (tda10045_fwupload(fe)) { + printk("tda1004x: firmware upload failed\n"); + return -EIO; + } + + tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC + + // tda setup + tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer + tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer + tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset + tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface + tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface + tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity + tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e); + + tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk); + + return 0; +} + +static int tda10046_init(struct dvb_frontend* fe) +{ + struct tda1004x_state* state = fe->demodulator_priv; + dprintk("%s\n", __func__); + + if (tda10046_fwupload(fe)) { + printk("tda1004x: firmware upload failed\n"); + return -EIO; + } + + // tda setup + tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer + tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream + tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88); // enable pulse killer + + switch (state->config->agc_config) { + case TDA10046_AGC_DEFAULT: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities + break; + case TDA10046_AGC_IFO_AUTO_NEG: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities + break; + case TDA10046_AGC_IFO_AUTO_POS: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00); // set AGC polarities + break; + case TDA10046_AGC_TDA827X: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup + tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold + tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities + break; + } + if (state->config->ts_mode == 0) { + tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40); + tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); + } else { + tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80); + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10, + state->config->invert_oclk << 4); + } + tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); + tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on + tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } + tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values + tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } + tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } + tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1 + tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits + tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config + tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config + // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes + + return 0; +} + +static int tda1004x_set_fe(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fe_params) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int tmp; + int inversion; + + dprintk("%s\n", __func__); + + if (state->demod_type == TDA1004X_DEMOD_TDA10046) { + // setup auto offset + tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0); + + // disable agc_conf[2] + tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0); + } + + // set frequency + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, fe_params); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + // Hardcoded to use auto as much as possible on the TDA10045 as it + // is very unreliable if AUTO mode is _not_ used. + if (state->demod_type == TDA1004X_DEMOD_TDA10045) { + fe_params->u.ofdm.code_rate_HP = FEC_AUTO; + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + } + + // Set standard params.. or put them to auto + if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) || + (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || + (fe_params->u.ofdm.constellation == QAM_AUTO) || + (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { + tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits + } else { + tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto + + // set HP FEC + tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP); + if (tmp < 0) + return tmp; + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp); + + // set LP FEC + tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP); + if (tmp < 0) + return tmp; + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3); + + // set constellation + switch (fe_params->u.ofdm.constellation) { + case QPSK: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0); + break; + + case QAM_16: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1); + break; + + case QAM_64: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2); + break; + + default: + return -EINVAL; + } + + // set hierarchy + switch (fe_params->u.ofdm.hierarchy_information) { + case HIERARCHY_NONE: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5); + break; + + case HIERARCHY_1: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5); + break; + + case HIERARCHY_2: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5); + break; + + case HIERARCHY_4: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5); + break; + + default: + return -EINVAL; + } + } + + // set bandwidth + switch (state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); + break; + + case TDA1004X_DEMOD_TDA10046: + tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); + break; + } + + // set inversion + inversion = fe_params->inversion; + if (state->config->invert) + inversion = inversion ? INVERSION_OFF : INVERSION_ON; + switch (inversion) { + case INVERSION_OFF: + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0); + break; + + case INVERSION_ON: + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20); + break; + + default: + return -EINVAL; + } + + // set guard interval + switch (fe_params->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); + break; + + case GUARD_INTERVAL_1_16: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2); + break; + + case GUARD_INTERVAL_1_8: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2); + break; + + case GUARD_INTERVAL_1_4: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2); + break; + + case GUARD_INTERVAL_AUTO: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); + break; + + default: + return -EINVAL; + } + + // set transmission mode + switch (fe_params->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: + tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4); + break; + + case TRANSMISSION_MODE_8K: + tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4); + break; + + case TRANSMISSION_MODE_AUTO: + tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0); + break; + + default: + return -EINVAL; + } + + // start the lock + switch (state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); + break; + + case TDA1004X_DEMOD_TDA10046: + tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40); + msleep(1); + tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1); + break; + } + + msleep(10); + + return 0; +} + +static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) +{ + struct tda1004x_state* state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + // inversion status + fe_params->inversion = INVERSION_OFF; + if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) + fe_params->inversion = INVERSION_ON; + if (state->config->invert) + fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON; + + // bandwidth + switch (state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) { + case 0x14: + fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + break; + case 0xdb: + fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + break; + case 0x4f: + fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + break; + } + break; + case TDA1004X_DEMOD_TDA10046: + switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { + case 0x5c: + case 0x54: + fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + break; + case 0x6a: + case 0x60: + fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + break; + case 0x7b: + case 0x70: + fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + break; + } + break; + } + + // FEC + fe_params->u.ofdm.code_rate_HP = + tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7); + fe_params->u.ofdm.code_rate_LP = + tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7); + + // constellation + switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) { + case 0: + fe_params->u.ofdm.constellation = QPSK; + break; + case 1: + fe_params->u.ofdm.constellation = QAM_16; + break; + case 2: + fe_params->u.ofdm.constellation = QAM_64; + break; + } + + // transmission mode + fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) + fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + + // guard interval + switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { + case 0: + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + break; + } + + // hierarchy + switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { + case 0: + fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + break; + case 1: + fe_params->u.ofdm.hierarchy_information = HIERARCHY_1; + break; + case 2: + fe_params->u.ofdm.hierarchy_information = HIERARCHY_2; + break; + case 3: + fe_params->u.ofdm.hierarchy_information = HIERARCHY_4; + break; + } + + return 0; +} + +static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int status; + int cber; + int vber; + + dprintk("%s\n", __func__); + + // read status + status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); + if (status == -1) + return -EIO; + + // decode + *fe_status = 0; + if (status & 4) + *fe_status |= FE_HAS_SIGNAL; + if (status & 2) + *fe_status |= FE_HAS_CARRIER; + if (status & 8) + *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + + // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi + // is getting anything valid + if (!(*fe_status & FE_HAS_VITERBI)) { + // read the CBER + cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB); + if (cber == -1) + return -EIO; + status = tda1004x_read_byte(state, TDA1004X_CBER_MSB); + if (status == -1) + return -EIO; + cber |= (status << 8); + // The address 0x20 should be read to cope with a TDA10046 bug + tda1004x_read_byte(state, TDA1004X_CBER_RESET); + + if (cber != 65535) + *fe_status |= FE_HAS_VITERBI; + } + + // if we DO have some valid VITERBI output, but don't already have SYNC + // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid. + if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) { + // read the VBER + vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB); + if (vber == -1) + return -EIO; + status = tda1004x_read_byte(state, TDA1004X_VBER_MID); + if (status == -1) + return -EIO; + vber |= (status << 8); + status = tda1004x_read_byte(state, TDA1004X_VBER_MSB); + if (status == -1) + return -EIO; + vber |= (status & 0x0f) << 16; + // The CVBER_LUT should be read to cope with TDA10046 hardware bug + tda1004x_read_byte(state, TDA1004X_CVBER_LUT); + + // if RS has passed some valid TS packets, then we must be + // getting some SYNC bytes + if (vber < 16632) + *fe_status |= FE_HAS_SYNC; + } + + // success + dprintk("%s: fe_status=0x%x\n", __func__, *fe_status); + return 0; +} + +static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int tmp; + int reg = 0; + + dprintk("%s\n", __func__); + + // determine the register to use + switch (state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + reg = TDA10045H_S_AGC; + break; + + case TDA1004X_DEMOD_TDA10046: + reg = TDA10046H_AGC_IF_LEVEL; + break; + } + + // read it + tmp = tda1004x_read_byte(state, reg); + if (tmp < 0) + return -EIO; + + *signal = (tmp << 8) | tmp; + dprintk("%s: signal=0x%x\n", __func__, *signal); + return 0; +} + +static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int tmp; + + dprintk("%s\n", __func__); + + // read it + tmp = tda1004x_read_byte(state, TDA1004X_SNR); + if (tmp < 0) + return -EIO; + tmp = 255 - tmp; + + *snr = ((tmp << 8) | tmp); + dprintk("%s: snr=0x%x\n", __func__, *snr); + return 0; +} + +static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int tmp; + int tmp2; + int counter; + + dprintk("%s\n", __func__); + + // read the UCBLOCKS and reset + counter = 0; + tmp = tda1004x_read_byte(state, TDA1004X_UNCOR); + if (tmp < 0) + return -EIO; + tmp &= 0x7f; + while (counter++ < 5) { + tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); + tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); + tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); + + tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR); + if (tmp2 < 0) + return -EIO; + tmp2 &= 0x7f; + if ((tmp2 < tmp) || (tmp2 == 0)) + break; + } + + if (tmp != 0x7f) + *ucblocks = tmp; + else + *ucblocks = 0xffffffff; + + dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks); + return 0; +} + +static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int tmp; + + dprintk("%s\n", __func__); + + // read it in + tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB); + if (tmp < 0) + return -EIO; + *ber = tmp << 1; + tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB); + if (tmp < 0) + return -EIO; + *ber |= (tmp << 9); + // The address 0x20 should be read to cope with a TDA10046 bug + tda1004x_read_byte(state, TDA1004X_CBER_RESET); + + dprintk("%s: ber=0x%x\n", __func__, *ber); + return 0; +} + +static int tda1004x_sleep(struct dvb_frontend* fe) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int gpio_conf; + + switch (state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10); + break; + + case TDA1004X_DEMOD_TDA10046: + /* set outputs to tristate */ + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff); + /* invert GPIO 1 and 3 if desired*/ + gpio_conf = state->config->gpio_config; + if (gpio_conf >= TDA10046_GP00_I) + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, + (gpio_conf & 0x0f) ^ 0x0a); + + tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0); + tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); + break; + } + + return 0; +} + +static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct tda1004x_state* state = fe->demodulator_priv; + + if (enable) { + return tda1004x_enable_tuner_i2c(state); + } else { + return tda1004x_disable_tuner_i2c(state); + } +} + +static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 800; + /* Drift compensation makes no sense for DVB-T */ + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static void tda1004x_release(struct dvb_frontend* fe) +{ + struct tda1004x_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops tda10045_ops = { + .info = { + .name = "Philips TDA10045H DVB-T", + .type = FE_OFDM, + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_stepsize = 166667, + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = tda1004x_release, + + .init = tda10045_init, + .sleep = tda1004x_sleep, + .write = tda1004x_write, + .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl, + + .set_frontend = tda1004x_set_fe, + .get_frontend = tda1004x_get_fe, + .get_tune_settings = tda1004x_get_tune_settings, + + .read_status = tda1004x_read_status, + .read_ber = tda1004x_read_ber, + .read_signal_strength = tda1004x_read_signal_strength, + .read_snr = tda1004x_read_snr, + .read_ucblocks = tda1004x_read_ucblocks, +}; + +struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c) +{ + struct tda1004x_state *state; + int id; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + if (!state) { + printk(KERN_ERR "Can't alocate memory for tda10045 state\n"); + return NULL; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->demod_type = TDA1004X_DEMOD_TDA10045; + + /* check if the demod is there */ + id = tda1004x_read_byte(state, TDA1004X_CHIPID); + if (id < 0) { + printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n"); + kfree(state); + return NULL; + } + + if (id != 0x25) { + printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id); + kfree(state); + return NULL; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +static struct dvb_frontend_ops tda10046_ops = { + .info = { + .name = "Philips TDA10046H DVB-T", + .type = FE_OFDM, + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_stepsize = 166667, + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = tda1004x_release, + + .init = tda10046_init, + .sleep = tda1004x_sleep, + .write = tda1004x_write, + .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl, + + .set_frontend = tda1004x_set_fe, + .get_frontend = tda1004x_get_fe, + .get_tune_settings = tda1004x_get_tune_settings, + + .read_status = tda1004x_read_status, + .read_ber = tda1004x_read_ber, + .read_signal_strength = tda1004x_read_signal_strength, + .read_snr = tda1004x_read_snr, + .read_ucblocks = tda1004x_read_ucblocks, +}; + +struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c) +{ + struct tda1004x_state *state; + int id; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + if (!state) { + printk(KERN_ERR "Can't alocate memory for tda10046 state\n"); + return NULL; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->demod_type = TDA1004X_DEMOD_TDA10046; + + /* check if the demod is there */ + id = tda1004x_read_byte(state, TDA1004X_CHIPID); + if (id < 0) { + printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n"); + kfree(state); + return NULL; + } + if (id != 0x46) { + printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id); + kfree(state); + return NULL; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator"); +MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(tda10045_attach); +EXPORT_SYMBOL(tda10046_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1004x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1004x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1004x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda1004x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,149 @@ + /* + Driver for Philips tda1004xh OFDM Frontend + + (c) 2004 Andrew de Quincey + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef TDA1004X_H +#define TDA1004X_H + +#include +#include + +enum tda10046_xtal { + TDA10046_XTAL_4M, + TDA10046_XTAL_16M, +}; + +enum tda10046_agc { + TDA10046_AGC_DEFAULT, /* original configuration */ + TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ + TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ + TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ +}; + +/* Many (hybrid) boards use GPIO 1 and 3 + GPIO1 analog - dvb switch + GPIO3 firmware eeprom address switch +*/ +enum tda10046_gpio { + TDA10046_GPTRI = 0x00, /* All GPIOs tristate */ + TDA10046_GP00 = 0x40, /* GPIO3=0, GPIO1=0 */ + TDA10046_GP01 = 0x42, /* GPIO3=0, GPIO1=1 */ + TDA10046_GP10 = 0x48, /* GPIO3=1, GPIO1=0 */ + TDA10046_GP11 = 0x4a, /* GPIO3=1, GPIO1=1 */ + TDA10046_GP00_I = 0x80, /* GPIO3=0, GPIO1=0, invert in sleep mode*/ + TDA10046_GP01_I = 0x82, /* GPIO3=0, GPIO1=1, invert in sleep mode */ + TDA10046_GP10_I = 0x88, /* GPIO3=1, GPIO1=0, invert in sleep mode */ + TDA10046_GP11_I = 0x8a, /* GPIO3=1, GPIO1=1, invert in sleep mode */ +}; + +enum tda10046_if { + TDA10046_FREQ_3617, /* original config, 36,166 MHZ */ + TDA10046_FREQ_3613, /* 36,13 MHZ */ + TDA10046_FREQ_045, /* low IF, 4.0, 4.5, or 5.0 MHZ */ + TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */ +}; + +enum tda10046_tsout { + TDA10046_TS_PARALLEL = 0x00, /* parallel transport stream, default */ + TDA10046_TS_SERIAL = 0x01, /* serial transport stream */ +}; + +struct tda1004x_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* does the "inversion" need inverted? */ + u8 invert; + + /* Does the OCLK signal need inverted? */ + u8 invert_oclk; + + /* parallel or serial transport stream */ + enum tda10046_tsout ts_mode; + + /* Xtal frequency, 4 or 16MHz*/ + enum tda10046_xtal xtal_freq; + + /* IF frequency */ + enum tda10046_if if_freq; + + /* AGC configuration */ + enum tda10046_agc agc_config; + + /* setting of GPIO1 and 3 */ + enum tda10046_gpio gpio_config; + + /* slave address and configuration of the tuner */ + u8 tuner_address; + u8 antenna_switch; + + /* if the board uses another I2c Bridge (tda8290), its address */ + u8 i2c_gate; + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +enum tda1004x_demod { + TDA1004X_DEMOD_TDA10045, + TDA1004X_DEMOD_TDA10046, +}; + +struct tda1004x_state { + struct i2c_adapter* i2c; + const struct tda1004x_config* config; + struct dvb_frontend frontend; + + /* private demod data */ + enum tda1004x_demod demod_type; +}; + +#if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c); + +extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_TDA1004X + +static inline int tda1004x_writereg(struct dvb_frontend *fe, u8 reg, u8 val) { + int r = 0; + u8 buf[] = {reg, val}; + if (fe->ops.write) + r = fe->ops.write(fe, buf, 2); + return r; +} + +#endif // TDA1004X_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10086.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10086.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10086.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10086.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,775 @@ + /* + Driver for Philips tda10086 DVBS Demodulator + + (c) 2006 Andrew de Quincey + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "tda10086.h" + +#define SACLK 96000000 + +struct tda10086_state { + struct i2c_adapter* i2c; + const struct tda10086_config* config; + struct dvb_frontend frontend; + + /* private demod data */ + u32 frequency; + u32 symbol_rate; + bool has_lock; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "tda10086: " args); \ + } while (0) + +static int tda10086_write_byte(struct tda10086_state *state, int reg, int data) +{ + int ret; + u8 b0[] = { reg, data }; + struct i2c_msg msg = { .flags = 0, .buf = b0, .len = 2 }; + + msg.addr = state->config->demod_address; + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", + __func__, reg, data, ret); + + return (ret != 1) ? ret : 0; +} + +static int tda10086_read_byte(struct tda10086_state *state, int reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 }, + { .flags = I2C_M_RD, .buf = b1, .len = 1 }}; + + msg[0].addr = state->config->demod_address; + msg[1].addr = state->config->demod_address; + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, + ret); + return ret; + } + + return b1[0]; +} + +static int tda10086_write_mask(struct tda10086_state *state, int reg, int mask, int data) +{ + int val; + + /* read a byte and check */ + val = tda10086_read_byte(state, reg); + if (val < 0) + return val; + + /* mask if off */ + val = val & ~mask; + val |= data & 0xff; + + /* write it out again */ + return tda10086_write_byte(state, reg, val); +} + +static int tda10086_init(struct dvb_frontend* fe) +{ + struct tda10086_state* state = fe->demodulator_priv; + u8 t22k_off = 0x80; + + dprintk ("%s\n", __func__); + + if (state->config->diseqc_tone) + t22k_off = 0; + /* reset */ + tda10086_write_byte(state, 0x00, 0x00); + msleep(10); + + /* misc setup */ + tda10086_write_byte(state, 0x01, 0x94); + tda10086_write_byte(state, 0x02, 0x35); /* NOTE: TT drivers appear to disable CSWP */ + tda10086_write_byte(state, 0x03, 0xe4); + tda10086_write_byte(state, 0x04, 0x43); + tda10086_write_byte(state, 0x0c, 0x0c); + tda10086_write_byte(state, 0x1b, 0xb0); /* noise threshold */ + tda10086_write_byte(state, 0x20, 0x89); /* misc */ + tda10086_write_byte(state, 0x30, 0x04); /* acquisition period length */ + tda10086_write_byte(state, 0x32, 0x00); /* irq off */ + tda10086_write_byte(state, 0x31, 0x56); /* setup AFC */ + + /* setup PLL (this assumes SACLK = 96MHz) */ + tda10086_write_byte(state, 0x55, 0x2c); /* misc PLL setup */ + if (state->config->xtal_freq == TDA10086_XTAL_16M) { + tda10086_write_byte(state, 0x3a, 0x0b); /* M=12 */ + tda10086_write_byte(state, 0x3b, 0x01); /* P=2 */ + } else { + tda10086_write_byte(state, 0x3a, 0x17); /* M=24 */ + tda10086_write_byte(state, 0x3b, 0x00); /* P=1 */ + } + tda10086_write_mask(state, 0x55, 0x20, 0x00); /* powerup PLL */ + + /* setup TS interface */ + tda10086_write_byte(state, 0x11, 0x81); + tda10086_write_byte(state, 0x12, 0x81); + tda10086_write_byte(state, 0x19, 0x40); /* parallel mode A + MSBFIRST */ + tda10086_write_byte(state, 0x56, 0x80); /* powerdown WPLL - unused in the mode we use */ + tda10086_write_byte(state, 0x57, 0x08); /* bypass WPLL - unused in the mode we use */ + tda10086_write_byte(state, 0x10, 0x2a); + + /* setup ADC */ + tda10086_write_byte(state, 0x58, 0x61); /* ADC setup */ + tda10086_write_mask(state, 0x58, 0x01, 0x00); /* powerup ADC */ + + /* setup AGC */ + tda10086_write_byte(state, 0x05, 0x0B); + tda10086_write_byte(state, 0x37, 0x63); + tda10086_write_byte(state, 0x3f, 0x0a); /* NOTE: flydvb varies it */ + tda10086_write_byte(state, 0x40, 0x64); + tda10086_write_byte(state, 0x41, 0x4f); + tda10086_write_byte(state, 0x42, 0x43); + + /* setup viterbi */ + tda10086_write_byte(state, 0x1a, 0x11); /* VBER 10^6, DVB, QPSK */ + + /* setup carrier recovery */ + tda10086_write_byte(state, 0x3d, 0x80); + + /* setup SEC */ + tda10086_write_byte(state, 0x36, t22k_off); /* all SEC off, 22k tone */ + tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000))); + tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); + + return 0; +} + +static void tda10086_diseqc_wait(struct tda10086_state *state) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(200); + while (!(tda10086_read_byte(state, 0x50) & 0x01)) { + if(time_after(jiffies, timeout)) { + printk("%s: diseqc queue not ready, command may be lost.\n", __func__); + break; + } + msleep(10); + } +} + +static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct tda10086_state* state = fe->demodulator_priv; + u8 t22k_off = 0x80; + + dprintk ("%s\n", __func__); + + if (state->config->diseqc_tone) + t22k_off = 0; + + switch (tone) { + case SEC_TONE_OFF: + tda10086_write_byte(state, 0x36, t22k_off); + break; + + case SEC_TONE_ON: + tda10086_write_byte(state, 0x36, 0x01 + t22k_off); + break; + } + + return 0; +} + +static int tda10086_send_master_cmd (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) +{ + struct tda10086_state* state = fe->demodulator_priv; + int i; + u8 oldval; + u8 t22k_off = 0x80; + + dprintk ("%s\n", __func__); + + if (state->config->diseqc_tone) + t22k_off = 0; + + if (cmd->msg_len > 6) + return -EINVAL; + oldval = tda10086_read_byte(state, 0x36); + + for(i=0; i< cmd->msg_len; i++) { + tda10086_write_byte(state, 0x48+i, cmd->msg[i]); + } + tda10086_write_byte(state, 0x36, (0x08 + t22k_off) + | ((cmd->msg_len - 1) << 4)); + + tda10086_diseqc_wait(state); + + tda10086_write_byte(state, 0x36, oldval); + + return 0; +} + +static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct tda10086_state* state = fe->demodulator_priv; + u8 oldval = tda10086_read_byte(state, 0x36); + u8 t22k_off = 0x80; + + dprintk ("%s\n", __func__); + + if (state->config->diseqc_tone) + t22k_off = 0; + + switch(minicmd) { + case SEC_MINI_A: + tda10086_write_byte(state, 0x36, 0x04 + t22k_off); + break; + + case SEC_MINI_B: + tda10086_write_byte(state, 0x36, 0x06 + t22k_off); + break; + } + + tda10086_diseqc_wait(state); + + tda10086_write_byte(state, 0x36, oldval); + + return 0; +} + +static int tda10086_set_inversion(struct tda10086_state *state, + struct dvb_frontend_parameters *fe_params) +{ + u8 invval = 0x80; + + dprintk ("%s %i %i\n", __func__, fe_params->inversion, state->config->invert); + + switch(fe_params->inversion) { + case INVERSION_OFF: + if (state->config->invert) + invval = 0x40; + break; + case INVERSION_ON: + if (!state->config->invert) + invval = 0x40; + break; + case INVERSION_AUTO: + invval = 0x00; + break; + } + tda10086_write_mask(state, 0x0c, 0xc0, invval); + + return 0; +} + +static int tda10086_set_symbol_rate(struct tda10086_state *state, + struct dvb_frontend_parameters *fe_params) +{ + u8 dfn = 0; + u8 afs = 0; + u8 byp = 0; + u8 reg37 = 0x43; + u8 reg42 = 0x43; + u64 big; + u32 tmp; + u32 bdr; + u32 bdri; + u32 symbol_rate = fe_params->u.qpsk.symbol_rate; + + dprintk ("%s %i\n", __func__, symbol_rate); + + /* setup the decimation and anti-aliasing filters.. */ + if (symbol_rate < (u32) (SACLK * 0.0137)) { + dfn=4; + afs=1; + } else if (symbol_rate < (u32) (SACLK * 0.0208)) { + dfn=4; + afs=0; + } else if (symbol_rate < (u32) (SACLK * 0.0270)) { + dfn=3; + afs=1; + } else if (symbol_rate < (u32) (SACLK * 0.0416)) { + dfn=3; + afs=0; + } else if (symbol_rate < (u32) (SACLK * 0.0550)) { + dfn=2; + afs=1; + } else if (symbol_rate < (u32) (SACLK * 0.0833)) { + dfn=2; + afs=0; + } else if (symbol_rate < (u32) (SACLK * 0.1100)) { + dfn=1; + afs=1; + } else if (symbol_rate < (u32) (SACLK * 0.1666)) { + dfn=1; + afs=0; + } else if (symbol_rate < (u32) (SACLK * 0.2200)) { + dfn=0; + afs=1; + } else if (symbol_rate < (u32) (SACLK * 0.3333)) { + dfn=0; + afs=0; + } else { + reg37 = 0x63; + reg42 = 0x4f; + byp=1; + } + + /* calculate BDR */ + big = (1ULL<<21) * ((u64) symbol_rate/1000ULL) * (1ULL<> 8); + tda10086_write_byte(state, 0x08, bdr >> 16); + tda10086_write_byte(state, 0x09, bdri); + tda10086_write_byte(state, 0x37, reg37); + tda10086_write_byte(state, 0x42, reg42); + + return 0; +} + +static int tda10086_set_fec(struct tda10086_state *state, + struct dvb_frontend_parameters *fe_params) +{ + u8 fecval; + + dprintk ("%s %i\n", __func__, fe_params->u.qpsk.fec_inner); + + switch(fe_params->u.qpsk.fec_inner) { + case FEC_1_2: + fecval = 0x00; + break; + case FEC_2_3: + fecval = 0x01; + break; + case FEC_3_4: + fecval = 0x02; + break; + case FEC_4_5: + fecval = 0x03; + break; + case FEC_5_6: + fecval = 0x04; + break; + case FEC_6_7: + fecval = 0x05; + break; + case FEC_7_8: + fecval = 0x06; + break; + case FEC_8_9: + fecval = 0x07; + break; + case FEC_AUTO: + fecval = 0x08; + break; + default: + return -1; + } + tda10086_write_byte(state, 0x0d, fecval); + + return 0; +} + +static int tda10086_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fe_params) +{ + struct tda10086_state *state = fe->demodulator_priv; + int ret; + u32 freq = 0; + int freqoff; + + dprintk ("%s\n", __func__); + + /* modify parameters for tuning */ + tda10086_write_byte(state, 0x02, 0x35); + state->has_lock = false; + + /* set params */ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, fe_params); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (fe->ops.tuner_ops.get_frequency) + fe->ops.tuner_ops.get_frequency(fe, &freq); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* calcluate the frequency offset (in *Hz* not kHz) */ + freqoff = fe_params->frequency - freq; + freqoff = ((1<<16) * freqoff) / (SACLK/1000); + tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f)); + tda10086_write_byte(state, 0x3e, freqoff); + + if ((ret = tda10086_set_inversion(state, fe_params)) < 0) + return ret; + if ((ret = tda10086_set_symbol_rate(state, fe_params)) < 0) + return ret; + if ((ret = tda10086_set_fec(state, fe_params)) < 0) + return ret; + + /* soft reset + disable TS output until lock */ + tda10086_write_mask(state, 0x10, 0x40, 0x40); + tda10086_write_mask(state, 0x00, 0x01, 0x00); + + state->symbol_rate = fe_params->u.qpsk.symbol_rate; + state->frequency = fe_params->frequency; + return 0; +} + +static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) +{ + struct tda10086_state* state = fe->demodulator_priv; + u8 val; + int tmp; + u64 tmp64; + + dprintk ("%s\n", __func__); + + /* check for invalid symbol rate */ + if (fe_params->u.qpsk.symbol_rate < 500000) + return -EINVAL; + + /* calculate the updated frequency (note: we convert from Hz->kHz) */ + tmp64 = tda10086_read_byte(state, 0x52); + tmp64 |= (tda10086_read_byte(state, 0x51) << 8); + if (tmp64 & 0x8000) + tmp64 |= 0xffffffffffff0000ULL; + tmp64 = (tmp64 * (SACLK/1000ULL)); + do_div(tmp64, (1ULL<<15) * (1ULL<<1)); + fe_params->frequency = (int) state->frequency + (int) tmp64; + + /* the inversion */ + val = tda10086_read_byte(state, 0x0c); + if (val & 0x80) { + switch(val & 0x40) { + case 0x00: + fe_params->inversion = INVERSION_OFF; + if (state->config->invert) + fe_params->inversion = INVERSION_ON; + break; + default: + fe_params->inversion = INVERSION_ON; + if (state->config->invert) + fe_params->inversion = INVERSION_OFF; + break; + } + } else { + tda10086_read_byte(state, 0x0f); + switch(val & 0x02) { + case 0x00: + fe_params->inversion = INVERSION_OFF; + if (state->config->invert) + fe_params->inversion = INVERSION_ON; + break; + default: + fe_params->inversion = INVERSION_ON; + if (state->config->invert) + fe_params->inversion = INVERSION_OFF; + break; + } + } + + /* calculate the updated symbol rate */ + tmp = tda10086_read_byte(state, 0x1d); + if (tmp & 0x80) + tmp |= 0xffffff00; + tmp = (tmp * 480 * (1<<1)) / 128; + tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000); + fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp; + + /* the FEC */ + val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4; + switch(val) { + case 0x00: + fe_params->u.qpsk.fec_inner = FEC_1_2; + break; + case 0x01: + fe_params->u.qpsk.fec_inner = FEC_2_3; + break; + case 0x02: + fe_params->u.qpsk.fec_inner = FEC_3_4; + break; + case 0x03: + fe_params->u.qpsk.fec_inner = FEC_4_5; + break; + case 0x04: + fe_params->u.qpsk.fec_inner = FEC_5_6; + break; + case 0x05: + fe_params->u.qpsk.fec_inner = FEC_6_7; + break; + case 0x06: + fe_params->u.qpsk.fec_inner = FEC_7_8; + break; + case 0x07: + fe_params->u.qpsk.fec_inner = FEC_8_9; + break; + } + + return 0; +} + +static int tda10086_read_status(struct dvb_frontend* fe, fe_status_t *fe_status) +{ + struct tda10086_state* state = fe->demodulator_priv; + u8 val; + + dprintk ("%s\n", __func__); + + val = tda10086_read_byte(state, 0x0e); + *fe_status = 0; + if (val & 0x01) + *fe_status |= FE_HAS_SIGNAL; + if (val & 0x02) + *fe_status |= FE_HAS_CARRIER; + if (val & 0x04) + *fe_status |= FE_HAS_VITERBI; + if (val & 0x08) + *fe_status |= FE_HAS_SYNC; + if (val & 0x10) { + *fe_status |= FE_HAS_LOCK; + if (!state->has_lock) { + state->has_lock = true; + /* modify parameters for stable reception */ + tda10086_write_byte(state, 0x02, 0x00); + } + } + + return 0; +} + +static int tda10086_read_signal_strength(struct dvb_frontend* fe, u16 * signal) +{ + struct tda10086_state* state = fe->demodulator_priv; + u8 _str; + + dprintk ("%s\n", __func__); + + _str = 0xff - tda10086_read_byte(state, 0x43); + *signal = (_str << 8) | _str; + + return 0; +} + +static int tda10086_read_snr(struct dvb_frontend* fe, u16 * snr) +{ + struct tda10086_state* state = fe->demodulator_priv; + u8 _snr; + + dprintk ("%s\n", __func__); + + _snr = 0xff - tda10086_read_byte(state, 0x1c); + *snr = (_snr << 8) | _snr; + + return 0; +} + +static int tda10086_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct tda10086_state* state = fe->demodulator_priv; + + dprintk ("%s\n", __func__); + + /* read it */ + *ucblocks = tda10086_read_byte(state, 0x18) & 0x7f; + + /* reset counter */ + tda10086_write_byte(state, 0x18, 0x00); + tda10086_write_byte(state, 0x18, 0x80); + + return 0; +} + +static int tda10086_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct tda10086_state* state = fe->demodulator_priv; + + dprintk ("%s\n", __func__); + + /* read it */ + *ber = 0; + *ber |= tda10086_read_byte(state, 0x15); + *ber |= tda10086_read_byte(state, 0x16) << 8; + *ber |= (tda10086_read_byte(state, 0x17) & 0xf) << 16; + + return 0; +} + +static int tda10086_sleep(struct dvb_frontend* fe) +{ + struct tda10086_state* state = fe->demodulator_priv; + + dprintk ("%s\n", __func__); + + tda10086_write_mask(state, 0x00, 0x08, 0x08); + + return 0; +} + +static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct tda10086_state* state = fe->demodulator_priv; + + dprintk ("%s\n", __func__); + + if (enable) { + tda10086_write_mask(state, 0x00, 0x10, 0x10); + } else { + tda10086_write_mask(state, 0x00, 0x10, 0x00); + } + + return 0; +} + +static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { + fesettings->min_delay_ms = 50; + fesettings->step_size = 2000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1500; + fesettings->max_drift = 9000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 500; + fesettings->max_drift = 7000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 14 * fesettings->step_size; + } else { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 18 * fesettings->step_size; + } + + return 0; +} + +static void tda10086_release(struct dvb_frontend* fe) +{ + struct tda10086_state *state = fe->demodulator_priv; + tda10086_sleep(fe); + kfree(state); +} + +static struct dvb_frontend_ops tda10086_ops = { + + .info = { + .name = "Philips TDA10086 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = tda10086_release, + + .init = tda10086_init, + .sleep = tda10086_sleep, + .i2c_gate_ctrl = tda10086_i2c_gate_ctrl, + + .set_frontend = tda10086_set_frontend, + .get_frontend = tda10086_get_frontend, + .get_tune_settings = tda10086_get_tune_settings, + + .read_status = tda10086_read_status, + .read_ber = tda10086_read_ber, + .read_signal_strength = tda10086_read_signal_strength, + .read_snr = tda10086_read_snr, + .read_ucblocks = tda10086_read_ucblocks, + + .diseqc_send_master_cmd = tda10086_send_master_cmd, + .diseqc_send_burst = tda10086_send_burst, + .set_tone = tda10086_set_tone, +}; + +struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, + struct i2c_adapter* i2c) +{ + struct tda10086_state *state; + + dprintk ("%s\n", __func__); + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct tda10086_state), GFP_KERNEL); + if (!state) + return NULL; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* check if the demod is there */ + if (tda10086_read_byte(state, 0x1e) != 0xe1) { + kfree(state); + return NULL; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &tda10086_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Philips TDA10086 DVB-S Demodulator"); +MODULE_AUTHOR("Andrew de Quincey"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(tda10086_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10086.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10086.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10086.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda10086.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,61 @@ + /* + Driver for Philips tda10086 DVBS Frontend + + (c) 2006 Andrew de Quincey + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef TDA10086_H +#define TDA10086_H + +#include +#include + +enum tda10086_xtal { + TDA10086_XTAL_16M, + TDA10086_XTAL_4M +}; + +struct tda10086_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* does the "inversion" need inverted? */ + u8 invert; + + /* do we need the diseqc signal with carrier? */ + u8 diseqc_tone; + + /* frequency of the reference xtal */ + enum tda10086_xtal xtal_freq; +}; + +#if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_TDA10086 */ + +#endif /* TDA10086_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda665x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda665x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda665x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda665x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,258 @@ +/* + TDA665x tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "tda665x.h" + +struct tda665x_state { + struct dvb_frontend *fe; + struct i2c_adapter *i2c; + const struct tda665x_config *config; + + u32 frequency; + u32 bandwidth; +}; + +static int tda665x_read(struct tda665x_state *state, u8 *buf) +{ + const struct tda665x_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 }; + + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) + goto exit; + + return err; +exit: + printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err); + return err; +} + +static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length) +{ + const struct tda665x_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length }; + + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) + goto exit; + + return err; +exit: + printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err); + return err; +} + +static int tda665x_get_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda665x_state *state = fe->tuner_priv; + int err = 0; + + switch (param) { + case DVBFE_TUNER_FREQUENCY: + tstate->frequency = state->frequency; + break; + case DVBFE_TUNER_BANDWIDTH: + break; + default: + printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); + err = -EINVAL; + break; + } + + return err; +} + +static int tda665x_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tda665x_state *state = fe->tuner_priv; + u8 result = 0; + int err = 0; + + *status = 0; + + err = tda665x_read(state, &result); + if (err < 0) + goto exit; + + if ((result >> 6) & 0x01) { + printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__); + *status = 1; + } + + return err; +exit: + printk(KERN_ERR "%s: I/O Error\n", __func__); + return err; +} + +static int tda665x_set_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda665x_state *state = fe->tuner_priv; + const struct tda665x_config *config = state->config; + u32 frequency, status = 0; + u8 buf[4]; + int err = 0; + + if (param & DVBFE_TUNER_FREQUENCY) { + + frequency = tstate->frequency; + if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) { + printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); + return -EINVAL; + } + + frequency += config->frequency_offst; + frequency *= config->ref_multiplier; + frequency += config->ref_divider >> 1; + frequency /= config->ref_divider; + + buf[0] = (u8) ((frequency & 0x7f00) >> 8); + buf[1] = (u8) (frequency & 0x00ff) >> 0; + buf[2] = 0x80 | 0x40 | 0x02; + buf[3] = 0x00; + + /* restore frequency */ + frequency = tstate->frequency; + + if (frequency < 153000000) { + /* VHF-L */ + buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */ + if (frequency < 68000000) + buf[3] |= 0x40; /* 83uA */ + if (frequency < 1040000000) + buf[3] |= 0x60; /* 122uA */ + if (frequency < 1250000000) + buf[3] |= 0x80; /* 163uA */ + else + buf[3] |= 0xa0; /* 254uA */ + } else if (frequency < 438000000) { + /* VHF-H */ + buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */ + if (frequency < 230000000) + buf[3] |= 0x40; + if (frequency < 300000000) + buf[3] |= 0x60; + else + buf[3] |= 0x80; + } else { + /* UHF */ + buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */ + if (frequency < 470000000) + buf[3] |= 0x60; + if (frequency < 526000000) + buf[3] |= 0x80; + else + buf[3] |= 0xa0; + } + + /* Set params */ + err = tda665x_write(state, buf, 5); + if (err < 0) + goto exit; + + /* sleep for some time */ + printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__); + msleep(20); + /* check status */ + err = tda665x_get_status(fe, &status); + if (err < 0) + goto exit; + + if (status == 1) { + printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status); + state->frequency = frequency; /* cache successful state */ + } else { + printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status); + } + } else { + printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); + return -EINVAL; + } + + return 0; +exit: + printk(KERN_ERR "%s: I/O Error\n", __func__); + return err; +} + +static int tda665x_release(struct dvb_frontend *fe) +{ + struct tda665x_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + return 0; +} + +static struct dvb_tuner_ops tda665x_ops = { + + .set_state = tda665x_set_state, + .get_state = tda665x_get_state, + .get_status = tda665x_get_status, + .release = tda665x_release +}; + +struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, + const struct tda665x_config *config, + struct i2c_adapter *i2c) +{ + struct tda665x_state *state = NULL; + struct dvb_tuner_info *info; + + state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL); + if (state == NULL) + goto exit; + + state->config = config; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + fe->ops.tuner_ops = tda665x_ops; + info = &fe->ops.tuner_ops.info; + + memcpy(info->name, config->name, sizeof(config->name)); + info->frequency_min = config->frequency_min; + info->frequency_max = config->frequency_max; + info->frequency_step = config->frequency_offst; + + printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name); + + return fe; + +exit: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(tda665x_attach); + +MODULE_DESCRIPTION("TDA665x driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda665x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda665x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda665x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda665x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* + TDA665x tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA665x_H +#define __TDA665x_H + +struct tda665x_config { + char name[128]; + + u8 addr; + u32 frequency_min; + u32 frequency_max; + u32 frequency_offst; + u32 ref_multiplier; + u32 ref_divider; +}; + +#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, + const struct tda665x_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, + const struct tda665x_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_TDA665x */ + +#endif /* __TDA665x_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8083.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8083.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8083.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8083.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,486 @@ +/* + Driver for Philips TDA8083 based QPSK Demodulator + + Copyright (C) 2001 Convergence Integrated Media GmbH + + written by Ralph Metzler + + adoption to the new DVB frontend API and diagnostic ioctl's + by Holger Waechtler + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "tda8083.h" + + +struct tda8083_state { + struct i2c_adapter* i2c; + /* configuration settings */ + const struct tda8083_config* config; + struct dvb_frontend frontend; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "tda8083: " args); \ + } while (0) + + +static u8 tda8083_init_tab [] = { + 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea, + 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10, + 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8, + 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00, + 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + + +static int tda8083_writereg (struct tda8083_state* state, u8 reg, u8 data) +{ + int ret; + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk ("%s: writereg error (reg %02x, ret == %i)\n", + __func__, reg, ret); + + return (ret != 1) ? -1 : 0; +} + +static int tda8083_readregs (struct tda8083_state* state, u8 reg1, u8 *b, u8 len) +{ + int ret; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + dprintk ("%s: readreg error (reg %02x, ret == %i)\n", + __func__, reg1, ret); + + return ret == 2 ? 0 : -1; +} + +static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg) +{ + u8 val; + + tda8083_readregs (state, reg, &val, 1); + + return val; +} + +static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion) +{ + /* XXX FIXME: implement other modes than FEC_AUTO */ + if (inversion == INVERSION_AUTO) + return 0; + + return -EINVAL; +} + +static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec) +{ + if (fec == FEC_AUTO) + return tda8083_writereg (state, 0x07, 0xff); + + if (fec >= FEC_1_2 && fec <= FEC_8_9) + return tda8083_writereg (state, 0x07, 1 << (FEC_8_9 - fec)); + + return -EINVAL; +} + +static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state) +{ + u8 index; + static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, + FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 }; + + index = tda8083_readreg(state, 0x0e) & 0x07; + + return fec_tab [index]; +} + +static int tda8083_set_symbolrate (struct tda8083_state* state, u32 srate) +{ + u32 ratio; + u32 tmp; + u8 filter; + + if (srate > 32000000) + srate = 32000000; + if (srate < 500000) + srate = 500000; + + filter = 0; + if (srate < 24000000) + filter = 2; + if (srate < 16000000) + filter = 3; + + tmp = 31250 << 16; + ratio = tmp / srate; + + tmp = (tmp % srate) << 8; + ratio = (ratio << 8) + tmp / srate; + + tmp = (tmp % srate) << 8; + ratio = (ratio << 8) + tmp / srate; + + dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio); + + tda8083_writereg (state, 0x05, filter); + tda8083_writereg (state, 0x02, (ratio >> 16) & 0xff); + tda8083_writereg (state, 0x03, (ratio >> 8) & 0xff); + tda8083_writereg (state, 0x04, (ratio ) & 0xff); + + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 1; +} + +static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout) +{ + unsigned long start = jiffies; + + while (jiffies - start < timeout && + !(tda8083_readreg(state, 0x02) & 0x80)) + { + msleep(50); + }; +} + +static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone) +{ + tda8083_writereg (state, 0x26, 0xf1); + + switch (tone) { + case SEC_TONE_OFF: + return tda8083_writereg (state, 0x29, 0x00); + case SEC_TONE_ON: + return tda8083_writereg (state, 0x29, 0x80); + default: + return -EINVAL; + }; +} + +static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage) +{ + switch (voltage) { + case SEC_VOLTAGE_13: + return tda8083_writereg (state, 0x20, 0x00); + case SEC_VOLTAGE_18: + return tda8083_writereg (state, 0x20, 0x11); + default: + return -EINVAL; + }; +} + +static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst) +{ + switch (burst) { + case SEC_MINI_A: + tda8083_writereg (state, 0x29, (5 << 2)); /* send burst A */ + break; + case SEC_MINI_B: + tda8083_writereg (state, 0x29, (7 << 2)); /* send B */ + break; + default: + return -EINVAL; + }; + + tda8083_wait_diseqc_fifo (state, 100); + + return 0; +} + +static int tda8083_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + struct tda8083_state* state = fe->demodulator_priv; + int i; + + tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */ + + for (i=0; imsg_len; i++) + tda8083_writereg (state, 0x23 + i, m->msg[i]); + + tda8083_writereg (state, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */ + + tda8083_wait_diseqc_fifo (state, 100); + + return 0; +} + +static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct tda8083_state* state = fe->demodulator_priv; + + u8 signal = ~tda8083_readreg (state, 0x01); + u8 sync = tda8083_readreg (state, 0x02); + + *status = 0; + + if (signal > 10) + *status |= FE_HAS_SIGNAL; + + if (sync & 0x01) + *status |= FE_HAS_CARRIER; + + if (sync & 0x02) + *status |= FE_HAS_VITERBI; + + if (sync & 0x10) + *status |= FE_HAS_SYNC; + + if (sync & 0x20) /* frontend can not lock */ + *status |= FE_TIMEDOUT; + + if ((sync & 0x1f) == 0x1f) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int tda8083_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct tda8083_state* state = fe->demodulator_priv; + int ret; + u8 buf[3]; + + if ((ret = tda8083_readregs(state, 0x0b, buf, sizeof(buf)))) + return ret; + + *ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2]; + + return 0; +} + +static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct tda8083_state* state = fe->demodulator_priv; + + u8 signal = ~tda8083_readreg (state, 0x01); + *strength = (signal << 8) | signal; + + return 0; +} + +static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct tda8083_state* state = fe->demodulator_priv; + + u8 _snr = tda8083_readreg (state, 0x08); + *snr = (_snr << 8) | _snr; + + return 0; +} + +static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct tda8083_state* state = fe->demodulator_priv; + + *ucblocks = tda8083_readreg(state, 0x0f); + if (*ucblocks == 0xff) + *ucblocks = 0xffffffff; + + return 0; +} + +static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda8083_state* state = fe->demodulator_priv; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + tda8083_set_inversion (state, p->inversion); + tda8083_set_fec (state, p->u.qpsk.fec_inner); + tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate); + + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda8083_state* state = fe->demodulator_priv; + + /* FIXME: get symbolrate & frequency offset...*/ + /*p->frequency = ???;*/ + p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ? + INVERSION_ON : INVERSION_OFF; + p->u.qpsk.fec_inner = tda8083_get_fec (state); + /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/ + + return 0; +} + +static int tda8083_sleep(struct dvb_frontend* fe) +{ + struct tda8083_state* state = fe->demodulator_priv; + + tda8083_writereg (state, 0x00, 0x02); + return 0; +} + +static int tda8083_init(struct dvb_frontend* fe) +{ + struct tda8083_state* state = fe->demodulator_priv; + int i; + + for (i=0; i<44; i++) + tda8083_writereg (state, i, tda8083_init_tab[i]); + + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + struct tda8083_state* state = fe->demodulator_priv; + + tda8083_send_diseqc_burst (state, burst); + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct tda8083_state* state = fe->demodulator_priv; + + tda8083_set_tone (state, tone); + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct tda8083_state* state = fe->demodulator_priv; + + tda8083_set_voltage (state, voltage); + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static void tda8083_release(struct dvb_frontend* fe) +{ + struct tda8083_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops tda8083_ops; + +struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, + struct i2c_adapter* i2c) +{ + struct tda8083_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct tda8083_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + + /* check if the demod is there */ + if ((tda8083_readreg(state, 0x00)) != 0x05) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops tda8083_ops = { + + .info = { + .name = "Philips TDA8083 DVB-S", + .type = FE_QPSK, + .frequency_min = 920000, /* TDA8060 */ + .frequency_max = 2200000, /* TDA8060 */ + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + /* .frequency_tolerance = ???,*/ + .symbol_rate_min = 12000000, + .symbol_rate_max = 30000000, + /* .symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_MUTE_TS + }, + + .release = tda8083_release, + + .init = tda8083_init, + .sleep = tda8083_sleep, + + .set_frontend = tda8083_set_frontend, + .get_frontend = tda8083_get_frontend, + + .read_status = tda8083_read_status, + .read_signal_strength = tda8083_read_signal_strength, + .read_snr = tda8083_read_snr, + .read_ber = tda8083_read_ber, + .read_ucblocks = tda8083_read_ucblocks, + + .diseqc_send_master_cmd = tda8083_send_diseqc_msg, + .diseqc_send_burst = tda8083_diseqc_send_burst, + .set_tone = tda8083_diseqc_set_tone, + .set_voltage = tda8083_diseqc_set_voltage, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Philips TDA8083 DVB-S Demodulator"); +MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(tda8083_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8083.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8083.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8083.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8083.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* + Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend + + Copyright (C) 2001 Convergence Integrated Media GmbH + + written by Ralph Metzler + + adoption to the new DVB frontend API and diagnostic ioctl's + by Holger Waechtler + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef TDA8083_H +#define TDA8083_H + +#include + +struct tda8083_config +{ + /* the demodulator's i2c address */ + u8 demod_address; +}; + +#if defined(CONFIG_DVB_TDA8083) || (defined(CONFIG_DVB_TDA8083_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_TDA8083 + +#endif // TDA8083_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,230 @@ +/* + TDA8261 8PSK/QPSK tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "tda8261.h" + +struct tda8261_state { + struct dvb_frontend *fe; + struct i2c_adapter *i2c; + const struct tda8261_config *config; + + /* state cache */ + u32 frequency; + u32 bandwidth; +}; + +static int tda8261_read(struct tda8261_state *state, u8 *buf) +{ + const struct tda8261_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 1 }; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) + printk("%s: read error, err=%d\n", __func__, err); + + return err; +} + +static int tda8261_write(struct tda8261_state *state, u8 *buf) +{ + const struct tda8261_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 }; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) + printk("%s: write error, err=%d\n", __func__, err); + + return err; +} + +static int tda8261_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tda8261_state *state = fe->tuner_priv; + u8 result = 0; + int err = 0; + + *status = 0; + + if ((err = tda8261_read(state, &result)) < 0) { + printk("%s: I/O Error\n", __func__); + return err; + } + if ((result >> 6) & 0x01) { + printk("%s: Tuner Phase Locked\n", __func__); + *status = 1; + } + + return err; +} + +static const u32 div_tab[] = { 2000, 1000, 500, 250, 125 }; /* kHz */ +static const u8 ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 }; + +static int tda8261_get_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda8261_state *state = fe->tuner_priv; + int err = 0; + + switch (param) { + case DVBFE_TUNER_FREQUENCY: + tstate->frequency = state->frequency; + break; + case DVBFE_TUNER_BANDWIDTH: + tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */ + break; + default: + printk("%s: Unknown parameter (param=%d)\n", __func__, param); + err = -EINVAL; + break; + } + + return err; +} + +static int tda8261_set_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda8261_state *state = fe->tuner_priv; + const struct tda8261_config *config = state->config; + u32 frequency, N, status = 0; + u8 buf[4]; + int err = 0; + + if (param & DVBFE_TUNER_FREQUENCY) { + /** + * N = Max VCO Frequency / Channel Spacing + * Max VCO Frequency = VCO frequency + (channel spacing - 1) + * (to account for half channel spacing on either side) + */ + frequency = tstate->frequency; + if ((frequency < 950000) || (frequency > 2150000)) { + printk("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); + return -EINVAL; + } + N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size]; + printk("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n", + __func__, config->step_size, div_tab[config->step_size], N, N); + + buf[0] = (N >> 8) & 0xff; + buf[1] = N & 0xff; + buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1); + + if (frequency < 1450000) + buf[3] = 0x00; + else if (frequency < 2000000) + buf[3] = 0x40; + else if (frequency < 2150000) + buf[3] = 0x80; + + /* Set params */ + if ((err = tda8261_write(state, buf)) < 0) { + printk("%s: I/O Error\n", __func__); + return err; + } + /* sleep for some time */ + printk("%s: Waiting to Phase LOCK\n", __func__); + msleep(20); + /* check status */ + if ((err = tda8261_get_status(fe, &status)) < 0) { + printk("%s: I/O Error\n", __func__); + return err; + } + if (status == 1) { + printk("%s: Tuner Phase locked: status=%d\n", __func__, status); + state->frequency = frequency; /* cache successful state */ + } else { + printk("%s: No Phase lock: status=%d\n", __func__, status); + } + } else { + printk("%s: Unknown parameter (param=%d)\n", __func__, param); + return -EINVAL; + } + + return 0; +} + +static int tda8261_release(struct dvb_frontend *fe) +{ + struct tda8261_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + return 0; +} + +static struct dvb_tuner_ops tda8261_ops = { + + .info = { + .name = "TDA8261", +// .tuner_name = NULL, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 0 + }, + + .set_state = tda8261_set_state, + .get_state = tda8261_get_state, + .get_status = tda8261_get_status, + .release = tda8261_release +}; + +struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, + const struct tda8261_config *config, + struct i2c_adapter *i2c) +{ + struct tda8261_state *state = NULL; + + if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL) + goto exit; + + state->config = config; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + fe->ops.tuner_ops = tda8261_ops; + + fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size]; +// fe->ops.tuner_ops.tuner_name = &config->buf; + +// printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n", +// __func__, fe->ops.tuner_ops.tuner_name); + printk("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__); + + return fe; + +exit: + kfree(state); + return NULL; +} + +EXPORT_SYMBOL(tda8261_attach); + +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261_cfg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261_cfg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261_cfg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261_cfg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,84 @@ +/* + TDA8261 8PSK/QPSK tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *frequency = t_state.frequency; + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + } + return 0; +} + +static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + t_state.frequency = frequency; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + } + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + return 0; +} + +static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = &fe->ops; + struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *bandwidth = t_state.bandwidth; + } + printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth); + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda8261.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + TDA8261 8PSK/QPSK tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA8261_H +#define __TDA8261_H + +enum tda8261_step { + TDA8261_STEP_2000 = 0, /* 2000 kHz */ + TDA8261_STEP_1000, /* 1000 kHz */ + TDA8261_STEP_500, /* 500 kHz */ + TDA8261_STEP_250, /* 250 kHz */ + TDA8261_STEP_125 /* 125 kHz */ +}; + +struct tda8261_config { +// u8 buf[16]; + u8 addr; + enum tda8261_step step_size; +}; + +#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, + const struct tda8261_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, + const struct tda8261_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif //CONFIG_DVB_TDA8261 + +#endif// __TDA8261_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda826x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda826x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda826x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda826x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,187 @@ + /* + Driver for Philips tda8262/tda8263 DVBS Silicon tuners + + (c) 2006 Andrew de Quincey + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include +#include + +#include "tda826x.h" + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "tda826x: " args); \ + } while (0) + +struct tda826x_priv { + /* i2c details */ + int i2c_address; + struct i2c_adapter *i2c; + u8 has_loopthrough:1; + u32 frequency; +}; + +static int tda826x_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int tda826x_sleep(struct dvb_frontend *fe) +{ + struct tda826x_priv *priv = fe->tuner_priv; + int ret; + u8 buf [] = { 0x00, 0x8d }; + struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 2 }; + + dprintk("%s:\n", __func__); + + if (!priv->has_loopthrough) + buf[1] = 0xad; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) { + dprintk("%s: i2c error\n", __func__); + } + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return (ret == 1) ? 0 : ret; +} + +static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct tda826x_priv *priv = fe->tuner_priv; + int ret; + u32 div; + u32 ksyms; + u32 bandwidth; + u8 buf [11]; + struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 11 }; + + dprintk("%s:\n", __func__); + + div = (params->frequency + (1000-1)) / 1000; + + /* BW = ((1 + RO) * SR/2 + 5) * 1.3 [SR in MSPS, BW in MHz] */ + /* with R0 = 0.35 and some transformations: */ + ksyms = params->u.qpsk.symbol_rate / 1000; + bandwidth = (878 * ksyms + 6500000) / 1000000 + 1; + if (bandwidth < 5) + bandwidth = 5; + else if (bandwidth > 36) + bandwidth = 36; + + buf[0] = 0x00; // subaddress + buf[1] = 0x09; // powerdown RSSI + the magic value 1 + if (!priv->has_loopthrough) + buf[1] |= 0x20; // power down loopthrough if not needed + buf[2] = (1<<5) | 0x0b; // 1Mhz + 0.45 VCO + buf[3] = div >> 7; + buf[4] = div << 1; + buf[5] = ((bandwidth - 5) << 3) | 7; /* baseband cut-off */ + buf[6] = 0xfe; // baseband gain 9 db + no RF attenuation + buf[7] = 0x83; // charge pumps at high, tests off + buf[8] = 0x80; // recommended value 4 for AMPVCO + disable ports. + buf[9] = 0x1a; // normal caltime + recommended values for SELTH + SELVTL + buf[10] = 0xd4; // recommended value 13 for BBIAS + unknown bit set on + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) { + dprintk("%s: i2c error\n", __func__); + } + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + priv->frequency = div * 1000; + + return (ret == 1) ? 0 : ret; +} + +static int tda826x_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda826x_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tda826x_tuner_ops = { + .info = { + .name = "Philips TDA826X", + .frequency_min = 950000, + .frequency_max = 2175000 + }, + .release = tda826x_release, + .sleep = tda826x_sleep, + .set_params = tda826x_set_params, + .get_frequency = tda826x_get_frequency, +}; + +struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough) +{ + struct tda826x_priv *priv = NULL; + u8 b1 [] = { 0, 0 }; + struct i2c_msg msg[2] = { + { .addr = addr, .flags = 0, .buf = NULL, .len = 0 }, + { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } + }; + int ret; + + dprintk("%s:\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = i2c_transfer (i2c, msg, 2); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret != 2) + return NULL; + if (!(b1[1] & 0x80)) + return NULL; + + priv = kzalloc(sizeof(struct tda826x_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_address = addr; + priv->i2c = i2c; + priv->has_loopthrough = has_loopthrough; + + memcpy(&fe->ops.tuner_ops, &tda826x_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + return fe; +} +EXPORT_SYMBOL(tda826x_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("DVB TDA826x driver"); +MODULE_AUTHOR("Andrew de Quincey"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda826x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda826x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda826x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tda826x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,53 @@ + /* + Driver for Philips tda8262/tda8263 DVBS Silicon tuners + + (c) 2006 Andrew de Quincey + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef __DVB_TDA826X_H__ +#define __DVB_TDA826X_H__ + +#include +#include "dvb_frontend.h" + +/** + * Attach a tda826x tuner to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param addr i2c address of the tuner. + * @param i2c i2c adapter to use. + * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector. + * @return FE pointer on success, NULL on failure. + */ +#if defined(CONFIG_DVB_TDA826X) || (defined(CONFIG_DVB_TDA826X_MODULE) && defined(MODULE)) +extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c, + int has_loopthrough); +#else +static inline struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, + int addr, + struct i2c_adapter *i2c, + int has_loopthrough) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_TDA826X + +#endif // __DVB_TDA826X_H__ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tdhd1.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tdhd1.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tdhd1.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tdhd1.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * tdhd1.h - ALPS TDHD1-204A tuner support + * + * Copyright (C) 2008 Oliver Endriss + * + * + * 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, or (at your option) any later version. + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * The project's page is at http://www.linuxtv.org + */ + +#ifndef TDHD1_H +#define TDHD1_H + +#include "tda1004x.h" + +static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name); + +static struct tda1004x_config alps_tdhd1_204a_config = { + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = alps_tdhd1_204_request_firmware +}; + +static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct i2c_adapter *i2c = fe->tuner_priv; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + u32 div; + + div = (params->frequency + 36166666) / 166666; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85; + + if (params->frequency >= 174000000 && params->frequency <= 230000000) + data[3] = 0x02; + else if (params->frequency >= 470000000 && params->frequency <= 823000000) + data[3] = 0x0C; + else if (params->frequency > 823000000 && params->frequency <= 862000000) + data[3] = 0x8C; + else + return -EINVAL; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + + return 0; +} + +#endif /* TDHD1_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tua6100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tua6100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tua6100.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tua6100.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,205 @@ +/** + * Driver for Infineon tua6100 pll. + * + * (c) 2006 Andrew de Quincey + * + * Based on code found in budget-av.c, which has the following: + * Compiled from various sources by Michael Hunold + * + * CI interface support (c) 2004 Olivier Gournet & + * Andrew de Quincey + * + * Copyright (C) 2002 Ralph Metzler + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "tua6100.h" + +struct tua6100_priv { + /* i2c details */ + int i2c_address; + struct i2c_adapter *i2c; + u32 frequency; +}; + +static int tua6100_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int tua6100_sleep(struct dvb_frontend *fe) +{ + struct tua6100_priv *priv = fe->tuner_priv; + int ret; + u8 reg0[] = { 0x00, 0x00 }; + struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) { + printk("%s: i2c error\n", __func__); + } + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return (ret == 1) ? 0 : ret; +} + +static int tua6100_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tua6100_priv *priv = fe->tuner_priv; + u32 div; + u32 prediv; + u8 reg0[] = { 0x00, 0x00 }; + u8 reg1[] = { 0x01, 0x00, 0x00, 0x00 }; + u8 reg2[] = { 0x02, 0x00, 0x00 }; + struct i2c_msg msg0 = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 }; + struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 }; + struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 }; + +#define _R 4 +#define _P 32 +#define _ri 4000000 + + // setup register 0 + if (params->frequency < 2000000) { + reg0[1] = 0x03; + } else { + reg0[1] = 0x07; + } + + // setup register 1 + if (params->frequency < 1630000) { + reg1[1] = 0x2c; + } else { + reg1[1] = 0x0c; + } + if (_P == 64) + reg1[1] |= 0x40; + if (params->frequency >= 1525000) + reg1[1] |= 0x80; + + // register 2 + reg2[1] = (_R >> 8) & 0x03; + reg2[2] = _R; + if (params->frequency < 1455000) { + reg2[1] |= 0x1c; + } else if (params->frequency < 1630000) { + reg2[1] |= 0x0c; + } else { + reg2[1] |= 0x1c; + } + + // The N divisor ratio (note: params->frequency is in kHz, but we need it in Hz) + prediv = (params->frequency * _R) / (_ri / 1000); + div = prediv / _P; + reg1[1] |= (div >> 9) & 0x03; + reg1[2] = div >> 1; + reg1[3] = (div << 7); + priv->frequency = ((div * _P) * (_ri / 1000)) / _R; + + // Finally, calculate and store the value for A + reg1[3] |= (prediv - (div*_P)) & 0x7f; + +#undef _R +#undef _P +#undef _ri + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(priv->i2c, &msg0, 1) != 1) + return -EIO; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(priv->i2c, &msg2, 1) != 1) + return -EIO; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(priv->i2c, &msg1, 1) != 1) + return -EIO; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tua6100_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tua6100_tuner_ops = { + .info = { + .name = "Infineon TUA6100", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 1000, + }, + .release = tua6100_release, + .sleep = tua6100_sleep, + .set_params = tua6100_set_params, + .get_frequency = tua6100_get_frequency, +}; + +struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c) +{ + struct tua6100_priv *priv = NULL; + u8 b1 [] = { 0x80 }; + u8 b2 [] = { 0x00 }; + struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b1, .len = 1 }, + { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } }; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = i2c_transfer (i2c, msg, 2); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret != 2) + return NULL; + + priv = kzalloc(sizeof(struct tua6100_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_address = addr; + priv->i2c = i2c; + + memcpy(&fe->ops.tuner_ops, &tua6100_tuner_ops, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(tua6100_attach); + +MODULE_DESCRIPTION("DVB tua6100 driver"); +MODULE_AUTHOR("Andrew de Quincey"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tua6100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tua6100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tua6100.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/tua6100.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,47 @@ +/** + * Driver for Infineon tua6100 PLL. + * + * (c) 2006 Andrew de Quincey + * + * Based on code found in budget-av.c, which has the following: + * Compiled from various sources by Michael Hunold + * + * CI interface support (c) 2004 Olivier Gournet & + * Andrew de Quincey + * + * Copyright (C) 2002 Ralph Metzler + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __DVB_TUA6100_H__ +#define __DVB_TUA6100_H__ + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_DVB_TUA6100) || (defined(CONFIG_DVB_TUA6100_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_TUA6100 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1820.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1820.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1820.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1820.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,446 @@ +/* + VES1820 - Single Chip Cable Channel Receiver driver module + + Copyright (C) 1999 Convergence Integrated Media GmbH + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "ves1820.h" + + + +struct ves1820_state { + struct i2c_adapter* i2c; + /* configuration settings */ + const struct ves1820_config* config; + struct dvb_frontend frontend; + + /* private demodulator data */ + u8 reg0; + u8 pwm; +}; + + +static int verbose; + +static u8 ves1820_inittab[] = { + 0x69, 0x6A, 0x93, 0x1A, 0x12, 0x46, 0x26, 0x1A, + 0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20, + 0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40 +}; + +static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) +{ + u8 buf[] = { 0x00, reg, data }; + struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 }; + int ret; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk("ves1820: %s(): writereg error (reg == 0x%02x, " + "val == 0x%02x, ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) +{ + u8 b0[] = { 0x00, reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2}, + {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} + }; + int ret; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk("ves1820: %s(): readreg error (reg == 0x%02x, " + "ret == %i)\n", __func__, reg, ret); + + return b1[0]; +} + +static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion) +{ + reg0 |= state->reg0 & 0x62; + + if (INVERSION_ON == inversion) { + if (!state->config->invert) reg0 |= 0x20; + else reg0 &= ~0x20; + } else if (INVERSION_OFF == inversion) { + if (!state->config->invert) reg0 &= ~0x20; + else reg0 |= 0x20; + } + + ves1820_writereg(state, 0x00, reg0 & 0xfe); + ves1820_writereg(state, 0x00, reg0 | 0x01); + + state->reg0 = reg0; + + return 0; +} + +static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) +{ + s32 BDR; + s32 BDRI; + s16 SFIL = 0; + u16 NDEC = 0; + u32 ratio; + u32 fin; + u32 tmp; + u64 fptmp; + u64 fpxin; + + if (symbolrate > state->config->xin / 2) + symbolrate = state->config->xin / 2; + + if (symbolrate < 500000) + symbolrate = 500000; + + if (symbolrate < state->config->xin / 16) + NDEC = 1; + if (symbolrate < state->config->xin / 32) + NDEC = 2; + if (symbolrate < state->config->xin / 64) + NDEC = 3; + + /* yeuch! */ + fpxin = state->config->xin * 10; + fptmp = fpxin; do_div(fptmp, 123); + if (symbolrate < fptmp) + SFIL = 1; + fptmp = fpxin; do_div(fptmp, 160); + if (symbolrate < fptmp) + SFIL = 0; + fptmp = fpxin; do_div(fptmp, 246); + if (symbolrate < fptmp) + SFIL = 1; + fptmp = fpxin; do_div(fptmp, 320); + if (symbolrate < fptmp) + SFIL = 0; + fptmp = fpxin; do_div(fptmp, 492); + if (symbolrate < fptmp) + SFIL = 1; + fptmp = fpxin; do_div(fptmp, 640); + if (symbolrate < fptmp) + SFIL = 0; + fptmp = fpxin; do_div(fptmp, 984); + if (symbolrate < fptmp) + SFIL = 1; + + fin = state->config->xin >> 4; + symbolrate <<= NDEC; + ratio = (symbolrate << 4) / fin; + tmp = ((symbolrate << 4) % fin) << 8; + ratio = (ratio << 8) + tmp / fin; + tmp = (tmp % fin) << 8; + ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin); + + BDR = ratio; + BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2; + + if (BDRI > 0xFF) + BDRI = 0xFF; + + SFIL = (SFIL << 4) | ves1820_inittab[0x0E]; + + NDEC = (NDEC << 6) | ves1820_inittab[0x03]; + + ves1820_writereg(state, 0x03, NDEC); + ves1820_writereg(state, 0x0a, BDR & 0xff); + ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff); + ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f); + + ves1820_writereg(state, 0x0d, BDRI); + ves1820_writereg(state, 0x0e, SFIL); + + return 0; +} + +static int ves1820_init(struct dvb_frontend* fe) +{ + struct ves1820_state* state = fe->demodulator_priv; + int i; + + ves1820_writereg(state, 0, 0); + + for (i = 0; i < sizeof(ves1820_inittab); i++) + ves1820_writereg(state, i, ves1820_inittab[i]); + if (state->config->selagc) + ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08); + + ves1820_writereg(state, 0x34, state->pwm); + + return 0; +} + +static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ves1820_state* state = fe->demodulator_priv; + static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 }; + static const u8 reg0x01[] = { 140, 140, 106, 100, 92 }; + static const u8 reg0x05[] = { 135, 100, 70, 54, 38 }; + static const u8 reg0x08[] = { 162, 116, 67, 52, 35 }; + static const u8 reg0x09[] = { 145, 150, 106, 126, 107 }; + int real_qam = p->u.qam.modulation - QAM_16; + + if (real_qam < 0 || real_qam > 4) + return -EINVAL; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + ves1820_set_symbolrate(state, p->u.qam.symbol_rate); + ves1820_writereg(state, 0x34, state->pwm); + + ves1820_writereg(state, 0x01, reg0x01[real_qam]); + ves1820_writereg(state, 0x05, reg0x05[real_qam]); + ves1820_writereg(state, 0x08, reg0x08[real_qam]); + ves1820_writereg(state, 0x09, reg0x09[real_qam]); + + ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion); + ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0)); + return 0; +} + +static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct ves1820_state* state = fe->demodulator_priv; + int sync; + + *status = 0; + sync = ves1820_readreg(state, 0x11); + + if (sync & 1) + *status |= FE_HAS_SIGNAL; + + if (sync & 2) + *status |= FE_HAS_CARRIER; + + if (sync & 2) /* XXX FIXME! */ + *status |= FE_HAS_VITERBI; + + if (sync & 4) + *status |= FE_HAS_SYNC; + + if (sync & 8) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct ves1820_state* state = fe->demodulator_priv; + + u32 _ber = ves1820_readreg(state, 0x14) | + (ves1820_readreg(state, 0x15) << 8) | + ((ves1820_readreg(state, 0x16) & 0x0f) << 16); + *ber = 10 * _ber; + + return 0; +} + +static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct ves1820_state* state = fe->demodulator_priv; + + u8 gain = ves1820_readreg(state, 0x17); + *strength = (gain << 8) | gain; + + return 0; +} + +static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct ves1820_state* state = fe->demodulator_priv; + + u8 quality = ~ves1820_readreg(state, 0x18); + *snr = (quality << 8) | quality; + + return 0; +} + +static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct ves1820_state* state = fe->demodulator_priv; + + *ucblocks = ves1820_readreg(state, 0x13) & 0x7f; + if (*ucblocks == 0x7f) + *ucblocks = 0xffffffff; + + /* reset uncorrected block counter */ + ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf); + ves1820_writereg(state, 0x10, ves1820_inittab[0x10]); + + return 0; +} + +static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ves1820_state* state = fe->demodulator_priv; + int sync; + s8 afc = 0; + + sync = ves1820_readreg(state, 0x11); + afc = ves1820_readreg(state, 0x19); + if (verbose) { + /* AFC only valid when carrier has been recovered */ + printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" : + "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10); + } + + if (!state->config->invert) { + p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF; + } else { + p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF; + } + + p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + + p->u.qam.fec_inner = FEC_NONE; + + p->frequency = ((p->frequency + 31250) / 62500) * 62500; + if (sync & 2) + p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10; + + return 0; +} + +static int ves1820_sleep(struct dvb_frontend* fe) +{ + struct ves1820_state* state = fe->demodulator_priv; + + ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */ + ves1820_writereg(state, 0x00, 0x80); /* standby */ + + return 0; +} + +static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + + fesettings->min_delay_ms = 200; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static void ves1820_release(struct dvb_frontend* fe) +{ + struct ves1820_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops ves1820_ops; + +struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, + struct i2c_adapter* i2c, + u8 pwm) +{ + struct ves1820_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->reg0 = ves1820_inittab[0]; + state->config = config; + state->i2c = i2c; + state->pwm = pwm; + + /* check if the demod is there */ + if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70) + goto error; + + if (verbose) + printk("ves1820: pwm=0x%02x\n", state->pwm); + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */ + state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */ + state->frontend.demodulator_priv = state; + + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops ves1820_ops = { + + .info = { + .name = "VLSI VES1820 DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 47000000, + .frequency_max = 862000000, + .caps = FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO + }, + + .release = ves1820_release, + + .init = ves1820_init, + .sleep = ves1820_sleep, + + .set_frontend = ves1820_set_parameters, + .get_frontend = ves1820_get_frontend, + .get_tune_settings = ves1820_get_tune_settings, + + .read_status = ves1820_read_status, + .read_ber = ves1820_read_ber, + .read_signal_strength = ves1820_read_signal_strength, + .read_snr = ves1820_read_snr, + .read_ucblocks = ves1820_read_ucblocks, +}; + +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting"); + +MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver"); +MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(ves1820_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1820.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1820.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1820.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1820.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,56 @@ +/* + VES1820 - Single Chip Cable Channel Receiver driver module + + Copyright (C) 1999 Convergence Integrated Media GmbH + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef VES1820_H +#define VES1820_H + +#include + +#define VES1820_SELAGC_PWM 0 +#define VES1820_SELAGC_SIGNAMPERR 1 + +struct ves1820_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* value of XIN to use */ + u32 xin; + + /* does inversion need inverted? */ + u8 invert:1; + + /* SELAGC control */ + u8 selagc:1; +}; + +#if defined(CONFIG_DVB_VES1820) || (defined(CONFIG_DVB_VES1820_MODULE) && defined(MODULE)) +extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, + struct i2c_adapter* i2c, u8 pwm); +#else +static inline struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, + struct i2c_adapter* i2c, u8 pwm) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_VES1820 + +#endif // VES1820_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1x93.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1x93.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1x93.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1x93.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,550 @@ +/* + Driver for VES1893 and VES1993 QPSK Demodulators + + Copyright (C) 1999 Convergence Integrated Media GmbH + Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de> + Copyright (C) 2002 Dennis Noermann + Copyright (C) 2002-2003 Andreas Oberritter + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "ves1x93.h" + + +struct ves1x93_state { + struct i2c_adapter* i2c; + /* configuration settings */ + const struct ves1x93_config* config; + struct dvb_frontend frontend; + + /* previous uncorrected block counter */ + fe_spectral_inversion_t inversion; + u8 *init_1x93_tab; + u8 *init_1x93_wtab; + u8 tab_size; + u8 demod_type; +}; + +static int debug; +#define dprintk if (debug) printk + +#define DEMOD_VES1893 0 +#define DEMOD_VES1993 1 + +static u8 init_1893_tab [] = { + 0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4, + 0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7f, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x21, 0xb0, 0x14, 0x00, 0xdc, 0x00, + 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x55, 0x00, 0x00, 0x7f, 0x00 +}; + +static u8 init_1993_tab [] = { + 0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c, + 0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x40, 0x21, 0xb0, 0x00, 0x00, 0x00, 0x10, + 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x0e, 0x80, 0x00 +}; + +static u8 init_1893_wtab[] = +{ + 1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0, + 0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1, + 1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0, + 1,1,1,0,1,1 +}; + +static u8 init_1993_wtab[] = +{ + 1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0, + 0,1,0,0,0,0,0,0, 1,1,1,1,0,0,0,1, + 1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0, + 1,1,1,0,1,1,1,1, 1,1,1,1,1 +}; + +static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data) +{ + u8 buf [] = { 0x00, reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; + int err; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { 0x00, reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + ret = i2c_transfer (state->i2c, msg, 2); + + if (ret != 2) return ret; + + return b1[0]; +} + +static int ves1x93_clr_bit (struct ves1x93_state* state) +{ + msleep(10); + ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe); + ves1x93_writereg (state, 0, state->init_1x93_tab[0]); + msleep(50); + return 0; +} + +static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion) +{ + u8 val; + + /* + * inversion on/off are interchanged because i and q seem to + * be swapped on the hardware + */ + + switch (inversion) { + case INVERSION_OFF: + val = 0xc0; + break; + case INVERSION_ON: + val = 0x80; + break; + case INVERSION_AUTO: + val = 0x00; + break; + default: + return -EINVAL; + } + + return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val); +} + +static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec) +{ + if (fec == FEC_AUTO) + return ves1x93_writereg (state, 0x0d, 0x08); + else if (fec < FEC_1_2 || fec > FEC_8_9) + return -EINVAL; + else + return ves1x93_writereg (state, 0x0d, fec - FEC_1_2); +} + +static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state) +{ + return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7); +} + +static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate) +{ + u32 BDR; + u32 ratio; + u8 ADCONF, FCONF, FNR, AGCR; + u32 BDRI; + u32 tmp; + u32 FIN; + + dprintk("%s: srate == %d\n", __func__, (unsigned int) srate); + + if (srate > state->config->xin/2) + srate = state->config->xin/2; + + if (srate < 500000) + srate = 500000; + +#define MUL (1UL<<26) + + FIN = (state->config->xin + 6000) >> 4; + + tmp = srate << 6; + ratio = tmp / FIN; + + tmp = (tmp % FIN) << 8; + ratio = (ratio << 8) + tmp / FIN; + + tmp = (tmp % FIN) << 8; + ratio = (ratio << 8) + tmp / FIN; + + FNR = 0xff; + + if (ratio < MUL/3) FNR = 0; + if (ratio < (MUL*11)/50) FNR = 1; + if (ratio < MUL/6) FNR = 2; + if (ratio < MUL/9) FNR = 3; + if (ratio < MUL/12) FNR = 4; + if (ratio < (MUL*11)/200) FNR = 5; + if (ratio < MUL/24) FNR = 6; + if (ratio < (MUL*27)/1000) FNR = 7; + if (ratio < MUL/48) FNR = 8; + if (ratio < (MUL*137)/10000) FNR = 9; + + if (FNR == 0xff) { + ADCONF = 0x89; + FCONF = 0x80; + FNR = 0; + } else { + ADCONF = 0x81; + FCONF = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5); + /*FCONF = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/ + } + + BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1; + BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1; + + dprintk("FNR= %d\n", FNR); + dprintk("ratio= %08x\n", (unsigned int) ratio); + dprintk("BDR= %08x\n", (unsigned int) BDR); + dprintk("BDRI= %02x\n", (unsigned int) BDRI); + + if (BDRI > 0xff) + BDRI = 0xff; + + ves1x93_writereg (state, 0x06, 0xff & BDR); + ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8)); + ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16)); + + ves1x93_writereg (state, 0x09, BDRI); + ves1x93_writereg (state, 0x20, ADCONF); + ves1x93_writereg (state, 0x21, FCONF); + + AGCR = state->init_1x93_tab[0x05]; + if (state->config->invert_pwm) + AGCR |= 0x20; + + if (srate < 6000000) + AGCR |= 0x80; + else + AGCR &= ~0x80; + + ves1x93_writereg (state, 0x05, AGCR); + + /* ves1993 hates this, will lose lock */ + if (state->demod_type != DEMOD_VES1993) + ves1x93_clr_bit (state); + + return 0; +} + +static int ves1x93_init (struct dvb_frontend* fe) +{ + struct ves1x93_state* state = fe->demodulator_priv; + int i; + int val; + + dprintk("%s: init chip\n", __func__); + + for (i = 0; i < state->tab_size; i++) { + if (state->init_1x93_wtab[i]) { + val = state->init_1x93_tab[i]; + + if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */ + ves1x93_writereg (state, i, val); + } + } + + return 0; +} + +static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + return ves1x93_writereg (state, 0x1f, 0x20); + case SEC_VOLTAGE_18: + return ves1x93_writereg (state, 0x1f, 0x30); + case SEC_VOLTAGE_OFF: + return ves1x93_writereg (state, 0x1f, 0x00); + default: + return -EINVAL; + } +} + +static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + u8 sync = ves1x93_readreg (state, 0x0e); + + /* + * The ves1893 sometimes returns sync values that make no sense, + * because, e.g., the SIGNAL bit is 0, while some of the higher + * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?). + * Tests showed that the VITERBI and SYNC bits are returned + * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong. + * If such a case occurs, we read the value again, until we get a + * valid value. + */ + int maxtry = 10; /* just for safety - let's not get stuck here */ + while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) { + msleep(10); + sync = ves1x93_readreg (state, 0x0e); + } + + *status = 0; + + if (sync & 1) + *status |= FE_HAS_SIGNAL; + + if (sync & 2) + *status |= FE_HAS_CARRIER; + + if (sync & 4) + *status |= FE_HAS_VITERBI; + + if (sync & 8) + *status |= FE_HAS_SYNC; + + if ((sync & 0x1f) == 0x1f) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + *ber = ves1x93_readreg (state, 0x15); + *ber |= (ves1x93_readreg (state, 0x16) << 8); + *ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16); + *ber *= 10; + + return 0; +} + +static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + u8 signal = ~ves1x93_readreg (state, 0x0b); + *strength = (signal << 8) | signal; + + return 0; +} + +static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + u8 _snr = ~ves1x93_readreg (state, 0x1c); + *snr = (_snr << 8) | _snr; + + return 0; +} + +static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + *ucblocks = ves1x93_readreg (state, 0x18) & 0x7f; + + if (*ucblocks == 0x7f) + *ucblocks = 0xffffffff; /* counter overflow... */ + + ves1x93_writereg (state, 0x18, 0x00); /* reset the counter */ + ves1x93_writereg (state, 0x18, 0x80); /* dto. */ + + return 0; +} + +static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + ves1x93_set_inversion (state, p->inversion); + ves1x93_set_fec (state, p->u.qpsk.fec_inner); + ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate); + state->inversion = p->inversion; + + return 0; +} + +static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ves1x93_state* state = fe->demodulator_priv; + int afc; + + afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2; + afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16; + + p->frequency -= afc; + + /* + * inversion indicator is only valid + * if auto inversion was used + */ + if (state->inversion == INVERSION_AUTO) + p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ? + INVERSION_OFF : INVERSION_ON; + p->u.qpsk.fec_inner = ves1x93_get_fec (state); + /* XXX FIXME: timing offset !! */ + + return 0; +} + +static int ves1x93_sleep(struct dvb_frontend* fe) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + return ves1x93_writereg (state, 0x00, 0x08); +} + +static void ves1x93_release(struct dvb_frontend* fe) +{ + struct ves1x93_state* state = fe->demodulator_priv; + kfree(state); +} + +static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + if (enable) { + return ves1x93_writereg(state, 0x00, 0x11); + } else { + return ves1x93_writereg(state, 0x00, 0x01); + } +} + +static struct dvb_frontend_ops ves1x93_ops; + +struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, + struct i2c_adapter* i2c) +{ + struct ves1x93_state* state = NULL; + u8 identity; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct ves1x93_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->inversion = INVERSION_OFF; + + /* check if the demod is there + identify it */ + identity = ves1x93_readreg(state, 0x1e); + switch (identity) { + case 0xdc: /* VES1893A rev1 */ + printk("ves1x93: Detected ves1893a rev1\n"); + state->demod_type = DEMOD_VES1893; + state->init_1x93_tab = init_1893_tab; + state->init_1x93_wtab = init_1893_wtab; + state->tab_size = sizeof(init_1893_tab); + break; + + case 0xdd: /* VES1893A rev2 */ + printk("ves1x93: Detected ves1893a rev2\n"); + state->demod_type = DEMOD_VES1893; + state->init_1x93_tab = init_1893_tab; + state->init_1x93_wtab = init_1893_wtab; + state->tab_size = sizeof(init_1893_tab); + break; + + case 0xde: /* VES1993 */ + printk("ves1x93: Detected ves1993\n"); + state->demod_type = DEMOD_VES1993; + state->init_1x93_tab = init_1993_tab; + state->init_1x93_wtab = init_1993_wtab; + state->tab_size = sizeof(init_1993_tab); + break; + + default: + goto error; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops ves1x93_ops = { + + .info = { + .name = "VLSI VES1x93 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* .symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = ves1x93_release, + + .init = ves1x93_init, + .sleep = ves1x93_sleep, + .i2c_gate_ctrl = ves1x93_i2c_gate_ctrl, + + .set_frontend = ves1x93_set_frontend, + .get_frontend = ves1x93_get_frontend, + + .read_status = ves1x93_read_status, + .read_ber = ves1x93_read_ber, + .read_signal_strength = ves1x93_read_signal_strength, + .read_snr = ves1x93_read_snr, + .read_ucblocks = ves1x93_read_ucblocks, + + .set_voltage = ves1x93_set_voltage, +}; + +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver"); +MODULE_AUTHOR("Ralph Metzler"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(ves1x93_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1x93.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1x93.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1x93.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/ves1x93.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,55 @@ +/* + Driver for VES1893 and VES1993 QPSK Demodulators + + Copyright (C) 1999 Convergence Integrated Media GmbH + Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de> + Copyright (C) 2002 Dennis Noermann + Copyright (C) 2002-2003 Andreas Oberritter + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef VES1X93_H +#define VES1X93_H + +#include + +struct ves1x93_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* value of XIN to use */ + u32 xin; + + /* should PWM be inverted? */ + u8 invert_pwm:1; +}; + +#if defined(CONFIG_DVB_VES1X93) || (defined(CONFIG_DVB_VES1X93_MODULE) && defined(MODULE)) +extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_VES1X93 + +#endif // VES1X93_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/z0194a.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/z0194a.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/z0194a.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/z0194a.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* z0194a.h Sharp z0194a tuner support +* +* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) +* +* 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, version 2. +* +* see Documentation/dvb/README.dvb-usb for more information +*/ + +#ifndef Z0194A +#define Z0194A + +static int sharp_z0194a_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { + aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { + aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { + aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { + aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { + aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + + return 0; +} + +static u8 sharp_z0194a_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, /* AGC2 0x3d */ + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, /* lock detector threshold */ + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, /* out imp: normal out type: parallel FEC mode:0 */ + 0x29, 0x1e, /* 1/2 threshold */ + 0x2a, 0x14, /* 2/3 threshold */ + 0x2b, 0x0f, /* 3/4 threshold */ + 0x2c, 0x09, /* 5/6 threshold */ + 0x2d, 0x05, /* 7/8 threshold */ + 0x2e, 0x01, + 0x31, 0x1f, /* test all FECs */ + 0x32, 0x19, /* viterbi and synchro search */ + 0x33, 0xfc, /* rs control */ + 0x34, 0x93, /* error control */ + 0x0f, 0x52, + 0xff, 0xff +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10036.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10036.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10036.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10036.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,520 @@ +/** + * Driver for Zarlink zl10036 DVB-S silicon tuner + * + * Copyright (C) 2006 Tino Reichardt + * Copyright (C) 2007-2009 Matthias Schwarzott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ** + * The data sheet for this tuner can be found at: + * http://www.mcmilk.de/projects/dvb-card/datasheets/ZL10036.pdf + * + * This one is working: (at my Avermedia DVB-S Pro) + * - zl10036 (40pin, FTA) + * + * A driver for zl10038 should be very similar. + */ + +#include +#include +#include +#include + +#include "zl10036.h" + +static int zl10036_debug; +#define dprintk(level, args...) \ + do { if (zl10036_debug & level) printk(KERN_DEBUG "zl10036: " args); \ + } while (0) + +#define deb_info(args...) dprintk(0x01, args) +#define deb_i2c(args...) dprintk(0x02, args) + +struct zl10036_state { + struct i2c_adapter *i2c; + const struct zl10036_config *config; + u32 frequency; + u8 br, bf; +}; + + +/* This driver assumes the tuner is driven by a 10.111MHz Cristal */ +#define _XTAL 10111 + +/* Some of the possible dividers: + * 64, (write 0x05 to reg), freq step size 158kHz + * 10, (write 0x0a to reg), freq step size 1.011kHz (used here) + * 5, (write 0x09 to reg), freq step size 2.022kHz + */ + +#define _RDIV 10 +#define _RDIV_REG 0x0a +#define _FR (_XTAL/_RDIV) + +#define STATUS_POR 0x80 /* Power on Reset */ +#define STATUS_FL 0x40 /* Frequency & Phase Lock */ + +/* read/write for zl10036 and zl10038 */ + +static int zl10036_read_status_reg(struct zl10036_state *state) +{ + u8 status; + struct i2c_msg msg[1] = { + { .addr = state->config->tuner_address, .flags = I2C_M_RD, + .buf = &status, .len = sizeof(status) }, + }; + + if (i2c_transfer(state->i2c, msg, 1) != 1) { + printk(KERN_ERR "%s: i2c read failed at addr=%02x\n", + __func__, state->config->tuner_address); + return -EIO; + } + + deb_i2c("R(status): %02x [FL=%d]\n", status, + (status & STATUS_FL) ? 1 : 0); + if (status & STATUS_POR) + deb_info("%s: Power-On-Reset bit enabled - " + "need to initialize the tuner\n", __func__); + + return status; +} + +static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count) +{ + struct i2c_msg msg[1] = { + { .addr = state->config->tuner_address, .flags = 0, + .buf = buf, .len = count }, + }; + u8 reg = 0; + int ret; + + if (zl10036_debug & 0x02) { + /* every 8bit-value satisifes this! + * so only check for debug log */ + if ((buf[0] & 0x80) == 0x00) + reg = 2; + else if ((buf[0] & 0xc0) == 0x80) + reg = 4; + else if ((buf[0] & 0xf0) == 0xc0) + reg = 6; + else if ((buf[0] & 0xf0) == 0xd0) + reg = 8; + else if ((buf[0] & 0xf0) == 0xe0) + reg = 10; + else if ((buf[0] & 0xf0) == 0xf0) + reg = 12; + + deb_i2c("W(%d):", reg); + { + int i; + for (i = 0; i < count; i++) + printk(KERN_CONT " %02x", buf[i]); + printk(KERN_CONT "\n"); + } + } + + ret = i2c_transfer(state->i2c, msg, 1); + if (ret != 1) { + printk(KERN_ERR "%s: i2c error, ret=%d\n", __func__, ret); + return -EIO; + } + + return 0; +} + +static int zl10036_release(struct dvb_frontend *fe) +{ + struct zl10036_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + + return 0; +} + +static int zl10036_sleep(struct dvb_frontend *fe) +{ + struct zl10036_state *state = fe->tuner_priv; + u8 buf[] = { 0xf0, 0x80 }; /* regs 12/13 */ + int ret; + + deb_info("%s\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = zl10036_write(state, buf, sizeof(buf)); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return ret; +} + +/** + * register map of the ZL10036/ZL10038 + * + * reg[default] content + * 2[0x00]: 0 | N14 | N13 | N12 | N11 | N10 | N9 | N8 + * 3[0x00]: N7 | N6 | N5 | N4 | N3 | N2 | N1 | N0 + * 4[0x80]: 1 | 0 | RFG | BA1 | BA0 | BG1 | BG0 | LEN + * 5[0x00]: P0 | C1 | C0 | R4 | R3 | R2 | R1 | R0 + * 6[0xc0]: 1 | 1 | 0 | 0 | RSD | 0 | 0 | 0 + * 7[0x20]: P1 | BF6 | BF5 | BF4 | BF3 | BF2 | BF1 | 0 + * 8[0xdb]: 1 | 1 | 0 | 1 | 0 | CC | 1 | 1 + * 9[0x30]: VSD | V2 | V1 | V0 | S3 | S2 | S1 | S0 + * 10[0xe1]: 1 | 1 | 1 | 0 | 0 | LS2 | LS1 | LS0 + * 11[0xf5]: WS | WH2 | WH1 | WH0 | WL2 | WL1 | WL0 | WRE + * 12[0xf0]: 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 + * 13[0x28]: PD | BR4 | BR3 | BR2 | BR1 | BR0 | CLR | TL + */ + +static int zl10036_set_frequency(struct zl10036_state *state, u32 frequency) +{ + u8 buf[2]; + u32 div, foffset; + + div = (frequency + _FR/2) / _FR; + state->frequency = div * _FR; + + foffset = frequency - state->frequency; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + + deb_info("%s: ftodo=%u fpriv=%u ferr=%d div=%u\n", __func__, + frequency, state->frequency, foffset, div); + + return zl10036_write(state, buf, sizeof(buf)); +} + +static int zl10036_set_bandwidth(struct zl10036_state *state, u32 fbw) +{ + /* fbw is measured in kHz */ + u8 br, bf; + int ret; + u8 buf_bf[] = { + 0xc0, 0x00, /* 6/7: rsd=0 bf=0 */ + }; + u8 buf_br[] = { + 0xf0, 0x00, /* 12/13: br=0xa clr=0 tl=0*/ + }; + u8 zl10036_rsd_off[] = { 0xc8 }; /* set RSD=1 */ + + /* ensure correct values */ + if (fbw > 35000) + fbw = 35000; + if (fbw < 8000) + fbw = 8000; + +#define _BR_MAXIMUM (_XTAL/575) /* _XTAL / 575kHz = 17 */ + + /* <= 28,82 MHz */ + if (fbw <= 28820) { + br = _BR_MAXIMUM; + } else { + /** + * f(bw)=34,6MHz f(xtal)=10.111MHz + * br = (10111/34600) * 63 * 1/K = 14; + */ + br = ((_XTAL * 21 * 1000) / (fbw * 419)); + } + + /* ensure correct values */ + if (br < 4) + br = 4; + if (br > _BR_MAXIMUM) + br = _BR_MAXIMUM; + + /* + * k = 1.257 + * bf = fbw/_XTAL * br * k - 1 */ + + bf = (fbw * br * 1257) / (_XTAL * 1000) - 1; + + /* ensure correct values */ + if (bf > 62) + bf = 62; + + buf_bf[1] = (bf << 1) & 0x7e; + buf_br[1] = (br << 2) & 0x7c; + deb_info("%s: BW=%d br=%u bf=%u\n", __func__, fbw, br, bf); + + if (br != state->br) { + ret = zl10036_write(state, buf_br, sizeof(buf_br)); + if (ret < 0) + return ret; + } + + if (bf != state->bf) { + ret = zl10036_write(state, buf_bf, sizeof(buf_bf)); + if (ret < 0) + return ret; + + /* time = br/(32* fxtal) */ + /* minimal sleep time to be calculated + * maximum br is 63 -> max time = 2 /10 MHz = 2e-7 */ + msleep(1); + + ret = zl10036_write(state, zl10036_rsd_off, + sizeof(zl10036_rsd_off)); + if (ret < 0) + return ret; + } + + state->br = br; + state->bf = bf; + + return 0; +} + +static int zl10036_set_gain_params(struct zl10036_state *state, + int c) +{ + u8 buf[2]; + u8 rfg, ba, bg; + + /* default values */ + rfg = 0; /* enable when using an lna */ + ba = 1; + bg = 1; + + /* reg 4 */ + buf[0] = 0x80 | ((rfg << 5) & 0x20) + | ((ba << 3) & 0x18) | ((bg << 1) & 0x06); + + if (!state->config->rf_loop_enable) + buf[0] |= 0x01; + + /* P0=0 */ + buf[1] = _RDIV_REG | ((c << 5) & 0x60); + + deb_info("%s: c=%u rfg=%u ba=%u bg=%u\n", __func__, c, rfg, ba, bg); + return zl10036_write(state, buf, sizeof(buf)); +} + +static int zl10036_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct zl10036_state *state = fe->tuner_priv; + int ret = 0; + u32 frequency = params->frequency; + u32 fbw; + int i; + u8 c; + + /* ensure correct values + * maybe redundant as core already checks this */ + if ((frequency < fe->ops.info.frequency_min) + || (frequency > fe->ops.info.frequency_max)) + return -EINVAL; + + /** + * alpha = 1.35 for dvb-s + * fBW = (alpha*symbolrate)/(2*0.8) + * 1.35 / (2*0.8) = 27 / 32 + */ + fbw = (27 * params->u.qpsk.symbol_rate) / 32; + + /* scale to kHz */ + fbw /= 1000; + + /* Add safe margin of 3MHz */ + fbw += 3000; + + /* setting the charge pump - guessed values */ + if (frequency < 950000) + return -EINVAL; + else if (frequency < 1250000) + c = 0; + else if (frequency < 1750000) + c = 1; + else if (frequency < 2175000) + c = 2; + else + return -EINVAL; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = zl10036_set_gain_params(state, c); + if (ret < 0) + goto error; + + ret = zl10036_set_frequency(state, params->frequency); + if (ret < 0) + goto error; + + ret = zl10036_set_bandwidth(state, fbw); + if (ret < 0) + goto error; + + /* wait for tuner lock - no idea if this is really needed */ + for (i = 0; i < 20; i++) { + ret = zl10036_read_status_reg(state); + if (ret < 0) + goto error; + + /* check Frequency & Phase Lock Bit */ + if (ret & STATUS_FL) + break; + + msleep(10); + } + +error: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return ret; +} + +static int zl10036_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct zl10036_state *state = fe->tuner_priv; + + *frequency = state->frequency; + + return 0; +} + +static int zl10036_init_regs(struct zl10036_state *state) +{ + int ret; + int i; + + /* could also be one block from reg 2 to 13 and additional 10/11 */ + u8 zl10036_init_tab[][2] = { + { 0x04, 0x00 }, /* 2/3: div=0x400 - arbitrary value */ + { 0x8b, _RDIV_REG }, /* 4/5: rfg=0 ba=1 bg=1 len=? */ + /* p0=0 c=0 r=_RDIV_REG */ + { 0xc0, 0x20 }, /* 6/7: rsd=0 bf=0x10 */ + { 0xd3, 0x40 }, /* 8/9: from datasheet */ + { 0xe3, 0x5b }, /* 10/11: lock window level */ + { 0xf0, 0x28 }, /* 12/13: br=0xa clr=0 tl=0*/ + { 0xe3, 0xf9 }, /* 10/11: unlock window level */ + }; + + /* invalid values to trigger writing */ + state->br = 0xff; + state->bf = 0xff; + + if (!state->config->rf_loop_enable) + zl10036_init_tab[1][0] |= 0x01; + + deb_info("%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(zl10036_init_tab); i++) { + ret = zl10036_write(state, zl10036_init_tab[i], 2); + if (ret < 0) + return ret; + } + + return 0; +} + +static int zl10036_init(struct dvb_frontend *fe) +{ + struct zl10036_state *state = fe->tuner_priv; + int ret = 0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = zl10036_read_status_reg(state); + if (ret < 0) + return ret; + + /* Only init if Power-on-Reset bit is set? */ + ret = zl10036_init_regs(state); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + return ret; +} + +static struct dvb_tuner_ops zl10036_tuner_ops = { + .info = { + .name = "Zarlink ZL10036", + .frequency_min = 950000, + .frequency_max = 2175000 + }, + .init = zl10036_init, + .release = zl10036_release, + .sleep = zl10036_sleep, + .set_params = zl10036_set_params, + .get_frequency = zl10036_get_frequency, +}; + +struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, + const struct zl10036_config *config, + struct i2c_adapter *i2c) +{ + struct zl10036_state *state; + int ret; + + if (!config) { + printk(KERN_ERR "%s: no config specified", __func__); + return NULL; + } + + state = kzalloc(sizeof(struct zl10036_state), GFP_KERNEL); + if (!state) + return NULL; + + state->config = config; + state->i2c = i2c; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ + + ret = zl10036_read_status_reg(state); + if (ret < 0) { + printk(KERN_ERR "%s: No zl10036 found\n", __func__); + goto error; + } + + ret = zl10036_init_regs(state); + if (ret < 0) { + printk(KERN_ERR "%s: tuner initialization failed\n", + __func__); + goto error; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ + + fe->tuner_priv = state; + + memcpy(&fe->ops.tuner_ops, &zl10036_tuner_ops, + sizeof(struct dvb_tuner_ops)); + printk(KERN_INFO "%s: tuner initialization (%s addr=0x%02x) ok\n", + __func__, fe->ops.tuner_ops.info.name, config->tuner_address); + + return fe; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(zl10036_attach); + +module_param_named(debug, zl10036_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +MODULE_DESCRIPTION("DVB ZL10036 driver"); +MODULE_AUTHOR("Tino Reichardt"); +MODULE_AUTHOR("Matthias Schwarzott"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10036.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10036.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10036.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10036.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,53 @@ +/** + * Driver for Zarlink ZL10036 DVB-S silicon tuner + * + * Copyright (C) 2006 Tino Reichardt + * Copyright (C) 2007-2009 Matthias Schwarzott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2, as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DVB_ZL10036_H +#define DVB_ZL10036_H + +#include +#include "dvb_frontend.h" + +/** + * Attach a zl10036 tuner to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param config zl10036_config structure + * @return FE pointer on success, NULL on failure. + */ + +struct zl10036_config { + u8 tuner_address; + int rf_loop_enable; +}; + +#if defined(CONFIG_DVB_ZL10036) || \ + (defined(CONFIG_DVB_ZL10036_MODULE) && defined(MODULE)) +extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, + const struct zl10036_config *config, struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, + const struct zl10036_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* DVB_ZL10036_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10039.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10039.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10039.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10039.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,307 @@ +/* + * Driver for Zarlink ZL10039 DVB-S tuner + * + * Copyright 2007 Jan D. Louw + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "zl10039.h" + +static int debug; + +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG args); \ + } while (0) + +enum zl10039_model_id { + ID_ZL10039 = 1 +}; + +struct zl10039_state { + struct i2c_adapter *i2c; + u8 i2c_addr; + u8 id; +}; + +enum zl10039_reg_addr { + PLL0 = 0, + PLL1, + PLL2, + PLL3, + RFFE, + BASE0, + BASE1, + BASE2, + LO0, + LO1, + LO2, + LO3, + LO4, + LO5, + LO6, + GENERAL +}; + +static int zl10039_read(const struct zl10039_state *state, + const enum zl10039_reg_addr reg, u8 *buf, + const size_t count) +{ + u8 regbuf[] = { reg }; + struct i2c_msg msg[] = { + {/* Write register address */ + .addr = state->i2c_addr, + .flags = 0, + .buf = regbuf, + .len = 1, + }, {/* Read count bytes */ + .addr = state->i2c_addr, + .flags = I2C_M_RD, + .buf = buf, + .len = count, + }, + }; + + dprintk("%s\n", __func__); + + if (i2c_transfer(state->i2c, msg, 2) != 2) { + dprintk("%s: i2c read error\n", __func__); + return -EREMOTEIO; + } + + return 0; /* Success */ +} + +static int zl10039_write(struct zl10039_state *state, + const enum zl10039_reg_addr reg, const u8 *src, + const size_t count) +{ + u8 buf[count + 1]; + struct i2c_msg msg = { + .addr = state->i2c_addr, + .flags = 0, + .buf = buf, + .len = count + 1, + }; + + dprintk("%s\n", __func__); + /* Write register address and data in one go */ + buf[0] = reg; + memcpy(&buf[1], src, count); + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + dprintk("%s: i2c write error\n", __func__); + return -EREMOTEIO; + } + + return 0; /* Success */ +} + +static inline int zl10039_readreg(struct zl10039_state *state, + const enum zl10039_reg_addr reg, u8 *val) +{ + return zl10039_read(state, reg, val, 1); +} + +static inline int zl10039_writereg(struct zl10039_state *state, + const enum zl10039_reg_addr reg, + const u8 val) +{ + return zl10039_write(state, reg, &val, 1); +} + +static int zl10039_init(struct dvb_frontend *fe) +{ + struct zl10039_state *state = fe->tuner_priv; + int ret; + + dprintk("%s\n", __func__); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + /* Reset logic */ + ret = zl10039_writereg(state, GENERAL, 0x40); + if (ret < 0) { + dprintk("Note: i2c write error normal when resetting the " + "tuner\n"); + } + /* Wake up */ + ret = zl10039_writereg(state, GENERAL, 0x01); + if (ret < 0) { + dprintk("Tuner power up failed\n"); + return ret; + } + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int zl10039_sleep(struct dvb_frontend *fe) +{ + struct zl10039_state *state = fe->tuner_priv; + int ret; + + dprintk("%s\n", __func__); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = zl10039_writereg(state, GENERAL, 0x80); + if (ret < 0) { + dprintk("Tuner sleep failed\n"); + return ret; + } + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int zl10039_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct zl10039_state *state = fe->tuner_priv; + u8 buf[6]; + u8 bf; + u32 fbw; + u32 div; + int ret; + + dprintk("%s\n", __func__); + dprintk("Set frequency = %d, symbol rate = %d\n", + params->frequency, params->u.qpsk.symbol_rate); + + /* Assumed 10.111 MHz crystal oscillator */ + /* Cancelled num/den 80 to prevent overflow */ + div = (params->frequency * 1000) / 126387; + fbw = (params->u.qpsk.symbol_rate * 27) / 32000; + /* Cancelled num/den 10 to prevent overflow */ + bf = ((fbw * 5088) / 1011100) - 1; + + /*PLL divider*/ + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + /*Reference divider*/ + /* Select reference ratio of 80 */ + buf[2] = 0x1D; + /*PLL test modes*/ + buf[3] = 0x40; + /*RF Control register*/ + buf[4] = 0x6E; /* Bypass enable */ + /*Baseband filter cutoff */ + buf[5] = bf; + + /* Open i2c gate */ + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + /* BR = 10, Enable filter adjustment */ + ret = zl10039_writereg(state, BASE1, 0x0A); + if (ret < 0) + goto error; + /* Write new config values */ + ret = zl10039_write(state, PLL0, buf, sizeof(buf)); + if (ret < 0) + goto error; + /* BR = 10, Disable filter adjustment */ + ret = zl10039_writereg(state, BASE1, 0x6A); + if (ret < 0) + goto error; + + /* Close i2c gate */ + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + return 0; +error: + dprintk("Error setting tuner\n"); + return ret; +} + +static int zl10039_release(struct dvb_frontend *fe) +{ + struct zl10039_state *state = fe->tuner_priv; + + dprintk("%s\n", __func__); + kfree(state); + fe->tuner_priv = NULL; + return 0; +} + +static struct dvb_tuner_ops zl10039_ops = { + .release = zl10039_release, + .init = zl10039_init, + .sleep = zl10039_sleep, + .set_params = zl10039_set_params, +}; + +struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, + u8 i2c_addr, struct i2c_adapter *i2c) +{ + struct zl10039_state *state = NULL; + + dprintk("%s\n", __func__); + state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->i2c = i2c; + state->i2c_addr = i2c_addr; + + /* Open i2c gate */ + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + /* check if this is a valid tuner */ + if (zl10039_readreg(state, GENERAL, &state->id) < 0) { + /* Close i2c gate */ + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + goto error; + } + /* Close i2c gate */ + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + state->id = state->id & 0x0f; + switch (state->id) { + case ID_ZL10039: + strcpy(fe->ops.tuner_ops.info.name, + "Zarlink ZL10039 DVB-S tuner"); + break; + default: + dprintk("Chip ID=%x does not match a known type\n", state->id); + goto error; + } + + memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = state; + dprintk("Tuner attached @ i2c address 0x%02x\n", i2c_addr); + return fe; +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(zl10039_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver"); +MODULE_AUTHOR("Jan D. Louw "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10039.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10039.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10039.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10039.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,40 @@ +/* + Driver for Zarlink ZL10039 DVB-S tuner + + Copyright (C) 2007 Jan D. Louw + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef ZL10039_H +#define ZL10039_H + +#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \ + && defined(MODULE)) +struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, + u8 i2c_addr, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, + u8 i2c_addr, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_ZL10039 */ + +#endif /* ZL10039_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,699 @@ +/* + * Driver for Zarlink DVB-T ZL10353 demodulator + * + * Copyright (C) 2006, 2007 Christopher Pascoe + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "zl10353_priv.h" +#include "zl10353.h" + +struct zl10353_state { + struct i2c_adapter *i2c; + struct dvb_frontend frontend; + + struct zl10353_config config; + + enum fe_bandwidth bandwidth; + u32 ucblocks; + u32 frequency; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "zl10353: " args); \ + } while (0) + +static int debug_regs; + +static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val) +{ + struct zl10353_state *state = fe->demodulator_priv; + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0, + .buf = buf, .len = 2 }; + int err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk("zl10353: write to reg %x failed (err = %d)!\n", reg, err); + return err; + } + return 0; +} + +static int zl10353_write(struct dvb_frontend *fe, const u8 ibuf[], int ilen) +{ + int err, i; + for (i = 0; i < ilen - 1; i++) + if ((err = zl10353_single_write(fe, ibuf[0] + i, ibuf[i + 1]))) + return err; + + return 0; +} + +static int zl10353_read_register(struct zl10353_state *state, u8 reg) +{ + int ret; + u8 b0[1] = { reg }; + u8 b1[1] = { 0 }; + struct i2c_msg msg[2] = { { .addr = state->config.demod_address, + .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config.demod_address, + .flags = I2C_M_RD, + .buf = b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk("%s: readreg error (reg=%d, ret==%i)\n", + __func__, reg, ret); + return ret; + } + + return b1[0]; +} + +static void zl10353_dump_regs(struct dvb_frontend *fe) +{ + struct zl10353_state *state = fe->demodulator_priv; + int ret; + u8 reg; + + /* Dump all registers. */ + for (reg = 0; ; reg++) { + if (reg % 16 == 0) { + if (reg) + printk(KERN_CONT "\n"); + printk(KERN_DEBUG "%02x:", reg); + } + ret = zl10353_read_register(state, reg); + if (ret >= 0) + printk(KERN_CONT " %02x", (u8)ret); + else + printk(KERN_CONT " --"); + if (reg == 0xff) + break; + } + printk(KERN_CONT "\n"); +} + +static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, + enum fe_bandwidth bandwidth, + u16 *nominal_rate) +{ + struct zl10353_state *state = fe->demodulator_priv; + u32 adc_clock = 450560; /* 45.056 MHz */ + u64 value; + u8 bw; + + if (state->config.adc_clock) + adc_clock = state->config.adc_clock; + + switch (bandwidth) { + case BANDWIDTH_6_MHZ: + bw = 6; + break; + case BANDWIDTH_7_MHZ: + bw = 7; + break; + case BANDWIDTH_8_MHZ: + default: + bw = 8; + break; + } + + value = (u64)10 * (1 << 23) / 7 * 125; + value = (bw * value) + adc_clock / 2; + do_div(value, adc_clock); + *nominal_rate = value; + + dprintk("%s: bw %d, adc_clock %d => 0x%x\n", + __func__, bw, adc_clock, *nominal_rate); +} + +static void zl10353_calc_input_freq(struct dvb_frontend *fe, + u16 *input_freq) +{ + struct zl10353_state *state = fe->demodulator_priv; + u32 adc_clock = 450560; /* 45.056 MHz */ + int if2 = 361667; /* 36.1667 MHz */ + int ife; + u64 value; + + if (state->config.adc_clock) + adc_clock = state->config.adc_clock; + if (state->config.if2) + if2 = state->config.if2; + + if (adc_clock >= if2 * 2) + ife = if2; + else { + ife = adc_clock - (if2 % adc_clock); + if (ife > adc_clock / 2) + ife = adc_clock - ife; + } + value = (u64)65536 * ife + adc_clock / 2; + do_div(value, adc_clock); + *input_freq = -value; + + dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", + __func__, if2, ife, adc_clock, -(int)value, *input_freq); +} + +static int zl10353_sleep(struct dvb_frontend *fe) +{ + static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 }; + + zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown)); + return 0; +} + +static int zl10353_set_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct zl10353_state *state = fe->demodulator_priv; + u16 nominal_rate, input_freq; + u8 pllbuf[6] = { 0x67 }, acq_ctl = 0; + u16 tps = 0; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + + state->frequency = param->frequency; + + zl10353_single_write(fe, RESET, 0x80); + udelay(200); + zl10353_single_write(fe, 0xEA, 0x01); + udelay(200); + zl10353_single_write(fe, 0xEA, 0x00); + + zl10353_single_write(fe, AGC_TARGET, 0x28); + + if (op->transmission_mode != TRANSMISSION_MODE_AUTO) + acq_ctl |= (1 << 0); + if (op->guard_interval != GUARD_INTERVAL_AUTO) + acq_ctl |= (1 << 1); + zl10353_single_write(fe, ACQ_CTL, acq_ctl); + + switch (op->bandwidth) { + case BANDWIDTH_6_MHZ: + /* These are extrapolated from the 7 and 8MHz values */ + zl10353_single_write(fe, MCLK_RATIO, 0x97); + zl10353_single_write(fe, 0x64, 0x34); + zl10353_single_write(fe, 0xcc, 0xdd); + break; + case BANDWIDTH_7_MHZ: + zl10353_single_write(fe, MCLK_RATIO, 0x86); + zl10353_single_write(fe, 0x64, 0x35); + zl10353_single_write(fe, 0xcc, 0x73); + break; + case BANDWIDTH_8_MHZ: + default: + zl10353_single_write(fe, MCLK_RATIO, 0x75); + zl10353_single_write(fe, 0x64, 0x36); + zl10353_single_write(fe, 0xcc, 0x73); + } + + zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); + zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate)); + zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate)); + state->bandwidth = op->bandwidth; + + zl10353_calc_input_freq(fe, &input_freq); + zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq)); + zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq)); + + /* Hint at TPS settings */ + switch (op->code_rate_HP) { + case FEC_2_3: + tps |= (1 << 7); + break; + case FEC_3_4: + tps |= (2 << 7); + break; + case FEC_5_6: + tps |= (3 << 7); + break; + case FEC_7_8: + tps |= (4 << 7); + break; + case FEC_1_2: + case FEC_AUTO: + break; + default: + return -EINVAL; + } + + switch (op->code_rate_LP) { + case FEC_2_3: + tps |= (1 << 4); + break; + case FEC_3_4: + tps |= (2 << 4); + break; + case FEC_5_6: + tps |= (3 << 4); + break; + case FEC_7_8: + tps |= (4 << 4); + break; + case FEC_1_2: + case FEC_AUTO: + break; + case FEC_NONE: + if (op->hierarchy_information == HIERARCHY_AUTO || + op->hierarchy_information == HIERARCHY_NONE) + break; + default: + return -EINVAL; + } + + switch (op->constellation) { + case QPSK: + break; + case QAM_AUTO: + case QAM_16: + tps |= (1 << 13); + break; + case QAM_64: + tps |= (2 << 13); + break; + default: + return -EINVAL; + } + + switch (op->transmission_mode) { + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + break; + case TRANSMISSION_MODE_8K: + tps |= (1 << 0); + break; + default: + return -EINVAL; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + break; + case GUARD_INTERVAL_1_16: + tps |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + tps |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + tps |= (3 << 2); + break; + default: + return -EINVAL; + } + + switch (op->hierarchy_information) { + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + tps |= (1 << 10); + break; + case HIERARCHY_2: + tps |= (2 << 10); + break; + case HIERARCHY_4: + tps |= (3 << 10); + break; + default: + return -EINVAL; + } + + zl10353_single_write(fe, TPS_GIVEN_1, msb(tps)); + zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps)); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + /* + * If there is no tuner attached to the secondary I2C bus, we call + * set_params to program a potential tuner attached somewhere else. + * Otherwise, we update the PLL registers via calc_regs. + */ + if (state->config.no_tuner) { + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + } else if (fe->ops.tuner_ops.calc_regs) { + fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5); + pllbuf[1] <<= 1; + zl10353_write(fe, pllbuf, sizeof(pllbuf)); + } + + zl10353_single_write(fe, 0x5F, 0x13); + + /* If no attached tuner or invalid PLL registers, just start the FSM. */ + if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL) + zl10353_single_write(fe, FSM_GO, 0x01); + else + zl10353_single_write(fe, TUNER_GO, 0x01); + + return 0; +} + +static int zl10353_get_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct zl10353_state *state = fe->demodulator_priv; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + int s6, s9; + u16 tps; + static const u8 tps_fec_to_api[8] = { + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_5_6, + FEC_7_8, + FEC_AUTO, + FEC_AUTO, + FEC_AUTO + }; + + s6 = zl10353_read_register(state, STATUS_6); + s9 = zl10353_read_register(state, STATUS_9); + if (s6 < 0 || s9 < 0) + return -EREMOTEIO; + if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0) + return -EINVAL; /* no FE or TPS lock */ + + tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 | + zl10353_read_register(state, TPS_RECEIVED_0); + + op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; + op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; + + switch ((tps >> 13) & 3) { + case 0: + op->constellation = QPSK; + break; + case 1: + op->constellation = QAM_16; + break; + case 2: + op->constellation = QAM_64; + break; + default: + op->constellation = QAM_AUTO; + break; + } + + op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : + TRANSMISSION_MODE_2K; + + switch ((tps >> 2) & 3) { + case 0: + op->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + op->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + op->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + op->guard_interval = GUARD_INTERVAL_1_4; + break; + default: + op->guard_interval = GUARD_INTERVAL_AUTO; + break; + } + + switch ((tps >> 10) & 7) { + case 0: + op->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + op->hierarchy_information = HIERARCHY_1; + break; + case 2: + op->hierarchy_information = HIERARCHY_2; + break; + case 3: + op->hierarchy_information = HIERARCHY_4; + break; + default: + op->hierarchy_information = HIERARCHY_AUTO; + break; + } + + param->frequency = state->frequency; + op->bandwidth = state->bandwidth; + param->inversion = INVERSION_AUTO; + + return 0; +} + +static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct zl10353_state *state = fe->demodulator_priv; + int s6, s7, s8; + + if ((s6 = zl10353_read_register(state, STATUS_6)) < 0) + return -EREMOTEIO; + if ((s7 = zl10353_read_register(state, STATUS_7)) < 0) + return -EREMOTEIO; + if ((s8 = zl10353_read_register(state, STATUS_8)) < 0) + return -EREMOTEIO; + + *status = 0; + if (s6 & (1 << 2)) + *status |= FE_HAS_CARRIER; + if (s6 & (1 << 1)) + *status |= FE_HAS_VITERBI; + if (s6 & (1 << 5)) + *status |= FE_HAS_LOCK; + if (s7 & (1 << 4)) + *status |= FE_HAS_SYNC; + if (s8 & (1 << 6)) + *status |= FE_HAS_SIGNAL; + + if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != + (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) + *status &= ~FE_HAS_LOCK; + + return 0; +} + +static int zl10353_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct zl10353_state *state = fe->demodulator_priv; + + *ber = zl10353_read_register(state, RS_ERR_CNT_2) << 16 | + zl10353_read_register(state, RS_ERR_CNT_1) << 8 | + zl10353_read_register(state, RS_ERR_CNT_0); + + return 0; +} + +static int zl10353_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct zl10353_state *state = fe->demodulator_priv; + + u16 signal = zl10353_read_register(state, AGC_GAIN_1) << 10 | + zl10353_read_register(state, AGC_GAIN_0) << 2 | 3; + + *strength = ~signal; + + return 0; +} + +static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct zl10353_state *state = fe->demodulator_priv; + u8 _snr; + + if (debug_regs) + zl10353_dump_regs(fe); + + _snr = zl10353_read_register(state, SNR); + *snr = (_snr << 8) | _snr; + + return 0; +} + +static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct zl10353_state *state = fe->demodulator_priv; + u32 ubl = 0; + + ubl = zl10353_read_register(state, RS_UBC_1) << 8 | + zl10353_read_register(state, RS_UBC_0); + + state->ucblocks += ubl; + *ucblocks = state->ucblocks; + + return 0; +} + +static int zl10353_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings + *fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 1000; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + + return 0; +} + +static int zl10353_init(struct dvb_frontend *fe) +{ + struct zl10353_state *state = fe->demodulator_priv; + u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F }; + int rc = 0; + + if (debug_regs) + zl10353_dump_regs(fe); + if (state->config.parallel_ts) + zl10353_reset_attach[2] &= ~0x20; + if (state->config.clock_ctl_1) + zl10353_reset_attach[3] = state->config.clock_ctl_1; + if (state->config.pll_0) + zl10353_reset_attach[4] = state->config.pll_0; + + /* Do a "hard" reset if not already done */ + if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] || + zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) { + rc = zl10353_write(fe, zl10353_reset_attach, + sizeof(zl10353_reset_attach)); + if (debug_regs) + zl10353_dump_regs(fe); + } + + return 0; +} + +static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct zl10353_state *state = fe->demodulator_priv; + u8 val = 0x0a; + + if (state->config.disable_i2c_gate_ctrl) { + /* No tuner attached to the internal I2C bus */ + /* If set enable I2C bridge, the main I2C bus stopped hardly */ + return 0; + } + + if (enable) + val |= 0x10; + + return zl10353_single_write(fe, 0x62, val); +} + +static void zl10353_release(struct dvb_frontend *fe) +{ + struct zl10353_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops zl10353_ops; + +struct dvb_frontend *zl10353_attach(const struct zl10353_config *config, + struct i2c_adapter *i2c) +{ + struct zl10353_state *state = NULL; + int id; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->i2c = i2c; + memcpy(&state->config, config, sizeof(struct zl10353_config)); + + /* check if the demod is there */ + id = zl10353_read_register(state, CHIP_ID); + if ((id != ID_ZL10353) && (id != ID_CE6230) && (id != ID_CE6231)) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops zl10353_ops = { + + .info = { + .name = "Zarlink ZL10353 DVB-T", + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + + .release = zl10353_release, + + .init = zl10353_init, + .sleep = zl10353_sleep, + .i2c_gate_ctrl = zl10353_i2c_gate_ctrl, + .write = zl10353_write, + + .set_frontend = zl10353_set_parameters, + .get_frontend = zl10353_get_parameters, + .get_tune_settings = zl10353_get_tune_settings, + + .read_status = zl10353_read_status, + .read_ber = zl10353_read_ber, + .read_signal_strength = zl10353_read_signal_strength, + .read_snr = zl10353_read_snr, + .read_ucblocks = zl10353_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +module_param(debug_regs, int, 0644); +MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off)."); + +MODULE_DESCRIPTION("Zarlink ZL10353 DVB-T demodulator driver"); +MODULE_AUTHOR("Chris Pascoe"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(zl10353_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,62 @@ +/* + * Driver for Zarlink DVB-T ZL10353 demodulator + * + * Copyright (C) 2006, 2007 Christopher Pascoe + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef ZL10353_H +#define ZL10353_H + +#include + +struct zl10353_config +{ + /* demodulator's I2C address */ + u8 demod_address; + + /* frequencies in units of 0.1kHz */ + int adc_clock; /* default: 450560 (45.056 MHz) */ + int if2; /* default: 361667 (36.1667 MHz) */ + + /* set if no pll is connected to the secondary i2c bus */ + int no_tuner; + + /* set if parallel ts output is required */ + int parallel_ts; + + /* set if i2c_gate_ctrl disable is required */ + u8 disable_i2c_gate_ctrl:1; + + /* clock control registers (0x51-0x54) */ + u8 clock_ctl_1; /* default: 0x46 */ + u8 pll_0; /* default: 0x15 */ +}; + +#if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE)) +extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_ZL10353 */ + +#endif /* ZL10353_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353_priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353_priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353_priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/frontends/zl10353_priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * Driver for Zarlink DVB-T ZL10353 demodulator + * + * Copyright (C) 2006, 2007 Christopher Pascoe + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ZL10353_PRIV_ +#define _ZL10353_PRIV_ + +#define ID_ZL10353 0x14 /* Zarlink ZL10353 */ +#define ID_CE6230 0x18 /* Intel CE6230 */ +#define ID_CE6231 0x19 /* Intel CE6231 */ + +#define msb(x) (((x) >> 8) & 0xff) +#define lsb(x) ((x) & 0xff) + +enum zl10353_reg_addr { + INTERRUPT_0 = 0x00, + INTERRUPT_1 = 0x01, + INTERRUPT_2 = 0x02, + INTERRUPT_3 = 0x03, + INTERRUPT_4 = 0x04, + INTERRUPT_5 = 0x05, + STATUS_6 = 0x06, + STATUS_7 = 0x07, + STATUS_8 = 0x08, + STATUS_9 = 0x09, + AGC_GAIN_1 = 0x0A, + AGC_GAIN_0 = 0x0B, + SNR = 0x10, + RS_ERR_CNT_2 = 0x11, + RS_ERR_CNT_1 = 0x12, + RS_ERR_CNT_0 = 0x13, + RS_UBC_1 = 0x14, + RS_UBC_0 = 0x15, + TPS_RECEIVED_1 = 0x1D, + TPS_RECEIVED_0 = 0x1E, + TPS_CURRENT_1 = 0x1F, + TPS_CURRENT_0 = 0x20, + CLOCK_CTL_0 = 0x51, + CLOCK_CTL_1 = 0x52, + PLL_0 = 0x53, + PLL_1 = 0x54, + RESET = 0x55, + AGC_TARGET = 0x56, + MCLK_RATIO = 0x5C, + ACQ_CTL = 0x5E, + TRL_NOMINAL_RATE_1 = 0x65, + TRL_NOMINAL_RATE_0 = 0x66, + INPUT_FREQ_1 = 0x6C, + INPUT_FREQ_0 = 0x6D, + TPS_GIVEN_1 = 0x6E, + TPS_GIVEN_0 = 0x6F, + TUNER_GO = 0x70, + FSM_GO = 0x71, + CHIP_ID = 0x7F, + CHAN_STEP_1 = 0xE4, + CHAN_STEP_0 = 0xE5, + OFDM_LOCK_TIME = 0xE7, + FEC_LOCK_TIME = 0xE8, + ACQ_DELAY = 0xE9, +}; + +#endif /* _ZL10353_PRIV_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,87 @@ +# +# DVB device configuration +# + +config DVB_MAX_ADAPTERS + int "maximum number of DVB/ATSC adapters" + depends on DVB_CORE + default 8 + range 1 255 + help + Maximum number of DVB/ATSC adapters. Increasing this number + increases the memory consumption of the DVB subsystem even + if a much lower number of DVB/ATSC adapters is present. + Only values in the range 4-32 are tested. + + If you are unsure about this, use the default value 8 + +config DVB_DYNAMIC_MINORS + bool "Dynamic DVB minor allocation" + depends on DVB_CORE + default n + help + If you say Y here, the DVB subsystem will use dynamic minor + allocation for any device that uses the DVB major number. + This means that you can have more than 4 of a single type + of device (like demuxes and frontends) per adapter, but udev + will be required to manage the device nodes. + + If you are unsure about this, say N here. + +menuconfig DVB_CAPTURE_DRIVERS + bool "DVB/ATSC adapters" + depends on DVB_CORE + default y + ---help--- + Say Y to select Digital TV adapters + +if DVB_CAPTURE_DRIVERS && DVB_CORE + +comment "Supported SAA7146 based PCI Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/dvb/ttpci/Kconfig" + +comment "Supported USB Adapters" + depends on DVB_CORE && USB && I2C +source "drivers/media/dvb/dvb-usb/Kconfig" +source "drivers/media/dvb/ttusb-budget/Kconfig" +source "drivers/media/dvb/ttusb-dec/Kconfig" +source "drivers/media/dvb/siano/Kconfig" + +comment "Supported FlexCopII (B2C2) Adapters" + depends on DVB_CORE && (PCI || USB) && I2C +source "drivers/media/dvb/b2c2/Kconfig" + +comment "Supported BT878 Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/dvb/bt8xx/Kconfig" + +comment "Supported Pluto2 Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/dvb/pluto2/Kconfig" + +comment "Supported SDMC DM1105 Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/dvb/dm1105/Kconfig" + +comment "Supported FireWire (IEEE 1394) Adapters" + depends on DVB_CORE && FIREWIRE +source "drivers/media/dvb/firewire/Kconfig" + +comment "Supported Earthsoft PT1 Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/dvb/pt1/Kconfig" + +comment "Supported Mantis Adapters" + depends on DVB_CORE && PCI && I2C + source "drivers/media/dvb/mantis/Kconfig" + +comment "Supported nGene Adapters" + depends on DVB_CORE && PCI && I2C + source "drivers/media/dvb/ngene/Kconfig" + +comment "Supported DVB Frontends" + depends on DVB_CORE +source "drivers/media/dvb/frontends/Kconfig" + +endif # DVB_CAPTURE_DRIVERS diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,20 @@ +# +# Makefile for the kernel multimedia device drivers. +# + +obj-y := dvb-core/ \ + frontends/ \ + ttpci/ \ + ttusb-dec/ \ + ttusb-budget/ \ + b2c2/ \ + bt8xx/ \ + dvb-usb/ \ + pluto2/ \ + siano/ \ + dm1105/ \ + pt1/ \ + mantis/ \ + ngene/ + +obj-$(CONFIG_DVB_FIREDTV) += firewire/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_cards.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,278 @@ +/* + Hopper PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "hopper_vp3028.h" +#include "mantis_dma.h" +#include "mantis_dvb.h" +#include "mantis_uart.h" +#include "mantis_ioc.h" +#include "mantis_pci.h" +#include "mantis_i2c.h" +#include "mantis_reg.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)"); + +#define DRIVER_NAME "Hopper" + +static char *label[10] = { + "DMA", + "IRQ-0", + "IRQ-1", + "OCERR", + "PABRT", + "RIPRR", + "PPERR", + "FTRGT", + "RISCI", + "RACK" +}; + +static int devs; + +static irqreturn_t hopper_irq_handler(int irq, void *dev_id) +{ + u32 stat = 0, mask = 0, lstat = 0, mstat = 0; + u32 rst_stat = 0, rst_mask = 0; + + struct mantis_pci *mantis; + struct mantis_ca *ca; + + mantis = (struct mantis_pci *) dev_id; + if (unlikely(mantis == NULL)) { + dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); + return IRQ_NONE; + } + ca = mantis->mantis_ca; + + stat = mmread(MANTIS_INT_STAT); + mask = mmread(MANTIS_INT_MASK); + mstat = lstat = stat & ~MANTIS_INT_RISCSTAT; + if (!(stat & mask)) + return IRQ_NONE; + + rst_mask = MANTIS_GPIF_WRACK | + MANTIS_GPIF_OTHERR | + MANTIS_SBUF_WSTO | + MANTIS_GPIF_EXTIRQ; + + rst_stat = mmread(MANTIS_GPIF_STATUS); + rst_stat &= rst_mask; + mmwrite(rst_stat, MANTIS_GPIF_STATUS); + + mantis->mantis_int_stat = stat; + mantis->mantis_int_mask = mask; + dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); + if (stat & MANTIS_INT_RISCEN) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); + } + if (stat & MANTIS_INT_IRQ0) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); + mantis->gpif_status = rst_stat; + wake_up(&ca->hif_write_wq); + schedule_work(&ca->hif_evm_work); + } + if (stat & MANTIS_INT_IRQ1) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + schedule_work(&mantis->uart_work); + } + if (stat & MANTIS_INT_OCERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); + } + if (stat & MANTIS_INT_PABORT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); + } + if (stat & MANTIS_INT_RIPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); + } + if (stat & MANTIS_INT_PPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); + } + if (stat & MANTIS_INT_FTRGT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); + } + if (stat & MANTIS_INT_RISCI) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); + mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; + tasklet_schedule(&mantis->tasklet); + } + if (stat & MANTIS_INT_I2CDONE) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); + wake_up(&mantis->i2c_wq); + } + mmwrite(stat, MANTIS_INT_STAT); + stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | + MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | + MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | + MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | + MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | + MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | + MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | + MANTIS_INT_PABORT | MANTIS_INT_RIPERR | + MANTIS_INT_PPERR | MANTIS_INT_FTRGT | + MANTIS_INT_RISCI); + + if (stat) + dprintk(MANTIS_DEBUG, 0, " Stat=<%02x> Mask=<%02x>", stat, mask); + + dprintk(MANTIS_DEBUG, 0, "\n"); + return IRQ_HANDLED; +} + +static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct mantis_pci *mantis; + struct mantis_hwconfig *config; + int err = 0; + + mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); + if (mantis == NULL) { + printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); + err = -ENOMEM; + goto fail0; + } + + mantis->num = devs; + mantis->verbose = verbose; + mantis->pdev = pdev; + config = (struct mantis_hwconfig *) pci_id->driver_data; + config->irq_handler = &hopper_irq_handler; + mantis->hwconfig = config; + + err = mantis_pci_init(mantis); + if (err) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); + goto fail1; + } + + err = mantis_stream_control(mantis, STREAM_TO_HIF); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); + goto fail1; + } + + err = mantis_i2c_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); + goto fail2; + } + + err = mantis_get_mac(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); + goto fail2; + } + + err = mantis_dma_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); + goto fail3; + } + + err = mantis_dvb_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); + goto fail4; + } + devs++; + + return err; + +fail4: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); + mantis_dma_exit(mantis); + +fail3: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); + mantis_i2c_exit(mantis); + +fail2: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); + mantis_pci_exit(mantis); + +fail1: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); + kfree(mantis); + +fail0: + return err; +} + +static void __devexit hopper_pci_remove(struct pci_dev *pdev) +{ + struct mantis_pci *mantis = pci_get_drvdata(pdev); + + if (mantis) { + mantis_dvb_exit(mantis); + mantis_dma_exit(mantis); + mantis_i2c_exit(mantis); + mantis_pci_exit(mantis); + kfree(mantis); + } + return; + +} + +static struct pci_device_id hopper_pci_table[] = { + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config), + { } +}; + +MODULE_DEVICE_TABLE(pci, hopper_pci_table); + +static struct pci_driver hopper_pci_driver = { + .name = DRIVER_NAME, + .id_table = hopper_pci_table, + .probe = hopper_pci_probe, + .remove = hopper_pci_remove, +}; + +static int __devinit hopper_init(void) +{ + return pci_register_driver(&hopper_pci_driver); +} + +static void __devexit hopper_exit(void) +{ + return pci_unregister_driver(&hopper_pci_driver); +} + +module_init(hopper_init); +module_exit(hopper_exit); + +MODULE_DESCRIPTION("HOPPER driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_vp3028.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_vp3028.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_vp3028.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_vp3028.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,88 @@ +/* + Hopper VP-3028 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "zl10353.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "hopper_vp3028.h" + +struct zl10353_config hopper_vp3028_config = { + .demod_address = 0x0f, +}; + +#define MANTIS_MODEL_NAME "VP-3028" +#define MANTIS_DEV_TYPE "DVB-T" + +static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + struct mantis_hwconfig *config = mantis->hwconfig; + int err = 0; + + mantis_gpio_set_bits(mantis, config->reset, 0); + msleep(100); + err = mantis_frontend_power(mantis, POWER_ON); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 1); + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + msleep(250); + dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); + fe = dvb_attach(zl10353_attach, &hopper_vp3028_config, adapter); + + if (!fe) + return -1; + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp3028_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp3028_frontend_init, + .power = GPIF_A00, + .reset = GPIF_A03, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_vp3028.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_vp3028.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_vp3028.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/hopper_vp3028.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + Hopper VP-3028 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP3028_H +#define __MANTIS_VP3028_H + +#include "mantis_common.h" + +#define MANTIS_VP_3028_DVB_T 0x0028 + +extern struct mantis_hwconfig vp3028_config; + +#endif /* __MANTIS_VP3028_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,38 @@ +config MANTIS_CORE + tristate "Mantis/Hopper PCI bridge based devices" + depends on PCI && I2C && INPUT && RC_CORE + + help + Support for PCI cards based on the Mantis and Hopper PCi bridge. + + Say Y if you own such a device and want to use it. + +config DVB_MANTIS + tristate "MANTIS based cards" + depends on MANTIS_CORE && DVB_CORE && PCI && I2C + select DVB_MB86A16 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_TDA665x if !DVB_FE_CUSTOMISE + select DVB_TDA10021 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_PLL + help + Support for PCI cards based on the Mantis PCI bridge. + Say Y when you have a Mantis based DVB card and want to use it. + + If unsure say N. + +config DVB_HOPPER + tristate "HOPPER based cards" + depends on MANTIS_CORE && DVB_CORE && PCI && I2C + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_PLL + help + Support for PCI cards based on the Hopper PCI bridge. + Say Y when you have a Hopper based DVB card and want to use it. + + If unsure say N diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,28 @@ +mantis_core-objs := mantis_ioc.o \ + mantis_uart.o \ + mantis_dma.o \ + mantis_pci.o \ + mantis_i2c.o \ + mantis_dvb.o \ + mantis_evm.o \ + mantis_hif.o \ + mantis_ca.o \ + mantis_pcmcia.o \ + mantis_input.o + +mantis-objs := mantis_cards.o \ + mantis_vp1033.o \ + mantis_vp1034.o \ + mantis_vp1041.o \ + mantis_vp2033.o \ + mantis_vp2040.o \ + mantis_vp3030.o + +hopper-objs := hopper_cards.o \ + hopper_vp3028.o + +obj-$(CONFIG_MANTIS_CORE) += mantis_core.o +obj-$(CONFIG_DVB_MANTIS) += mantis.o +obj-$(CONFIG_DVB_HOPPER) += hopper.o + +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ca.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ca.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ca.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ca.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,208 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" +#include "mantis_hif.h" +#include "mantis_reg.h" + +#include "mantis_ca.h" + +static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_read_mem(ca, addr); +} + +static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_write_mem(ca, addr, data); +} + +static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_read_iom(ca, addr); +} + +static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_write_iom(ca, addr, data); +} + +static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot); + udelay(500); /* Wait.. */ + mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */ + udelay(500); + mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */ + msleep(1000); + dvb_ca_en50221_camready_irq(&ca->en50221, 0); + + return 0; +} + +static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot); + + return 0; +} + +static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot); +/* mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */ + + return 0; +} + +static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot); + + if (ca->slot_state == MODULE_INSERTED) { + dprintk(MANTIS_DEBUG, 1, "CA Module present and ready"); + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + } else { + dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready"); + } + + return 0; +} + +int mantis_ca_init(struct mantis_pci *mantis) +{ + struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter; + struct mantis_ca *ca; + int ca_flags = 0, result; + + dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA"); + ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL); + if (!ca) { + dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting .."); + result = -ENOMEM; + goto err; + } + + ca->ca_priv = mantis; + mantis->mantis_ca = ca; + ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE; + /* register CA interface */ + ca->en50221.owner = THIS_MODULE; + ca->en50221.read_attribute_mem = mantis_ca_read_attr_mem; + ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem; + ca->en50221.read_cam_control = mantis_ca_read_cam_ctl; + ca->en50221.write_cam_control = mantis_ca_write_cam_ctl; + ca->en50221.slot_reset = mantis_ca_slot_reset; + ca->en50221.slot_shutdown = mantis_ca_slot_shutdown; + ca->en50221.slot_ts_enable = mantis_ts_control; + ca->en50221.poll_slot_status = mantis_slot_status; + ca->en50221.data = ca; + + mutex_init(&ca->ca_lock); + + init_waitqueue_head(&ca->hif_data_wq); + init_waitqueue_head(&ca->hif_opdone_wq); + init_waitqueue_head(&ca->hif_write_wq); + + dprintk(MANTIS_ERROR, 1, "Registering EN50221 device"); + result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1); + if (result != 0) { + dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result); + goto err; + } + dprintk(MANTIS_ERROR, 1, "Registered EN50221 device"); + mantis_evmgr_init(ca); + return 0; +err: + kfree(ca); + return result; +} +EXPORT_SYMBOL_GPL(mantis_ca_init); + +void mantis_ca_exit(struct mantis_pci *mantis) +{ + struct mantis_ca *ca = mantis->mantis_ca; + + dprintk(MANTIS_DEBUG, 1, "Mantis CA exit"); + + mantis_evmgr_exit(ca); + dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device"); + if (ca) + dvb_ca_en50221_release(&ca->en50221); + + kfree(ca); +} +EXPORT_SYMBOL_GPL(mantis_ca_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ca.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ca.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ca.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ca.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_CA_H +#define __MANTIS_CA_H + +extern int mantis_ca_init(struct mantis_pci *mantis); +extern void mantis_ca_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_CA_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_cards.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,308 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" + +#include "mantis_vp1033.h" +#include "mantis_vp1034.h" +#include "mantis_vp1041.h" +#include "mantis_vp2033.h" +#include "mantis_vp2040.h" +#include "mantis_vp3030.h" + +#include "mantis_dma.h" +#include "mantis_ca.h" +#include "mantis_dvb.h" +#include "mantis_uart.h" +#include "mantis_ioc.h" +#include "mantis_pci.h" +#include "mantis_i2c.h" +#include "mantis_reg.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)"); + +static int devs; + +#define DRIVER_NAME "Mantis" + +static char *label[10] = { + "DMA", + "IRQ-0", + "IRQ-1", + "OCERR", + "PABRT", + "RIPRR", + "PPERR", + "FTRGT", + "RISCI", + "RACK" +}; + +static irqreturn_t mantis_irq_handler(int irq, void *dev_id) +{ + u32 stat = 0, mask = 0, lstat = 0, mstat = 0; + u32 rst_stat = 0, rst_mask = 0; + + struct mantis_pci *mantis; + struct mantis_ca *ca; + + mantis = (struct mantis_pci *) dev_id; + if (unlikely(mantis == NULL)) { + dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); + return IRQ_NONE; + } + ca = mantis->mantis_ca; + + stat = mmread(MANTIS_INT_STAT); + mask = mmread(MANTIS_INT_MASK); + mstat = lstat = stat & ~MANTIS_INT_RISCSTAT; + if (!(stat & mask)) + return IRQ_NONE; + + rst_mask = MANTIS_GPIF_WRACK | + MANTIS_GPIF_OTHERR | + MANTIS_SBUF_WSTO | + MANTIS_GPIF_EXTIRQ; + + rst_stat = mmread(MANTIS_GPIF_STATUS); + rst_stat &= rst_mask; + mmwrite(rst_stat, MANTIS_GPIF_STATUS); + + mantis->mantis_int_stat = stat; + mantis->mantis_int_mask = mask; + dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); + if (stat & MANTIS_INT_RISCEN) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); + } + if (stat & MANTIS_INT_IRQ0) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); + mantis->gpif_status = rst_stat; + wake_up(&ca->hif_write_wq); + schedule_work(&ca->hif_evm_work); + } + if (stat & MANTIS_INT_IRQ1) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + schedule_work(&mantis->uart_work); + } + if (stat & MANTIS_INT_OCERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); + } + if (stat & MANTIS_INT_PABORT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); + } + if (stat & MANTIS_INT_RIPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); + } + if (stat & MANTIS_INT_PPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); + } + if (stat & MANTIS_INT_FTRGT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); + } + if (stat & MANTIS_INT_RISCI) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); + mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; + tasklet_schedule(&mantis->tasklet); + } + if (stat & MANTIS_INT_I2CDONE) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); + wake_up(&mantis->i2c_wq); + } + mmwrite(stat, MANTIS_INT_STAT); + stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | + MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | + MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | + MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | + MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | + MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | + MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | + MANTIS_INT_PABORT | MANTIS_INT_RIPERR | + MANTIS_INT_PPERR | MANTIS_INT_FTRGT | + MANTIS_INT_RISCI); + + if (stat) + dprintk(MANTIS_DEBUG, 0, " Stat=<%02x> Mask=<%02x>", stat, mask); + + dprintk(MANTIS_DEBUG, 0, "\n"); + return IRQ_HANDLED; +} + +static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct mantis_pci *mantis; + struct mantis_hwconfig *config; + int err = 0; + + mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); + if (mantis == NULL) { + printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); + err = -ENOMEM; + goto fail0; + } + + mantis->num = devs; + mantis->verbose = verbose; + mantis->pdev = pdev; + config = (struct mantis_hwconfig *) pci_id->driver_data; + config->irq_handler = &mantis_irq_handler; + mantis->hwconfig = config; + + err = mantis_pci_init(mantis); + if (err) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); + goto fail1; + } + + err = mantis_stream_control(mantis, STREAM_TO_HIF); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); + goto fail1; + } + + err = mantis_i2c_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); + goto fail2; + } + + err = mantis_get_mac(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); + goto fail2; + } + + err = mantis_dma_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); + goto fail3; + } + + err = mantis_dvb_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); + goto fail4; + } + err = mantis_uart_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err); + goto fail6; + } + + devs++; + + return err; + + + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err); + mantis_uart_exit(mantis); + +fail6: +fail4: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); + mantis_dma_exit(mantis); + +fail3: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); + mantis_i2c_exit(mantis); + +fail2: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); + mantis_pci_exit(mantis); + +fail1: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); + kfree(mantis); + +fail0: + return err; +} + +static void __devexit mantis_pci_remove(struct pci_dev *pdev) +{ + struct mantis_pci *mantis = pci_get_drvdata(pdev); + + if (mantis) { + + mantis_uart_exit(mantis); + mantis_dvb_exit(mantis); + mantis_dma_exit(mantis); + mantis_i2c_exit(mantis); + mantis_pci_exit(mantis); + kfree(mantis); + } + return; +} + +static struct pci_device_id mantis_pci_table[] = { + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config), + MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config), + MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config), + MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config), + MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config), + MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2033_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config), + { } +}; + +MODULE_DEVICE_TABLE(pci, mantis_pci_table); + +static struct pci_driver mantis_pci_driver = { + .name = DRIVER_NAME, + .id_table = mantis_pci_table, + .probe = mantis_pci_probe, + .remove = mantis_pci_remove, +}; + +static int __devinit mantis_init(void) +{ + return pci_register_driver(&mantis_pci_driver); +} + +static void __devexit mantis_exit(void) +{ + return pci_unregister_driver(&mantis_pci_driver); +} + +module_init(mantis_init); +module_exit(mantis_exit); + +MODULE_DESCRIPTION("MANTIS driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_common.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_common.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,181 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_COMMON_H +#define __MANTIS_COMMON_H + +#include +#include + +#include "mantis_uart.h" + +#include "mantis_link.h" + +#define MANTIS_ERROR 0 +#define MANTIS_NOTICE 1 +#define MANTIS_INFO 2 +#define MANTIS_DEBUG 3 +#define MANTIS_TMG 9 + +#define dprintk(y, z, format, arg...) do { \ + if (z) { \ + if ((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y)) \ + printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y)) \ + printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y)) \ + printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y)) \ + printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y)) \ + printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + } else { \ + if (mantis->verbose > y) \ + printk(format , ##arg); \ + } \ +} while(0) + +#define mwrite(dat, addr) writel((dat), addr) +#define mread(addr) readl(addr) + +#define mmwrite(dat, addr) mwrite((dat), (mantis->mmio + (addr))) +#define mmread(addr) mread(mantis->mmio + (addr)) + +#define MANTIS_TS_188 0 +#define MANTIS_TS_204 1 + +#define TWINHAN_TECHNOLOGIES 0x1822 +#define MANTIS 0x4e35 + +#define TECHNISAT 0x1ae4 +#define TERRATEC 0x153b + +#define MAKE_ENTRY(__subven, __subdev, __configptr) { \ + .vendor = TWINHAN_TECHNOLOGIES, \ + .device = MANTIS, \ + .subvendor = (__subven), \ + .subdevice = (__subdev), \ + .driver_data = (unsigned long) (__configptr) \ +} + +enum mantis_i2c_mode { + MANTIS_PAGE_MODE = 0, + MANTIS_BYTE_MODE, +}; + +struct mantis_pci; + +struct mantis_hwconfig { + char *model_name; + char *dev_type; + u32 ts_size; + + enum mantis_baud baud_rate; + enum mantis_parity parity; + u32 bytes; + + irqreturn_t (*irq_handler)(int irq, void *dev_id); + int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe); + + u8 power; + u8 reset; + + enum mantis_i2c_mode i2c_mode; +}; + +struct mantis_pci { + unsigned int verbose; + + /* PCI stuff */ + u16 vendor_id; + u16 device_id; + u16 subsystem_vendor; + u16 subsystem_device; + + u8 latency; + + struct pci_dev *pdev; + + unsigned long mantis_addr; + void __iomem *mmio; + + u8 irq; + u8 revision; + + unsigned int num; + + /* RISC Core */ + u32 finished_block; + u32 last_block; + u32 line_bytes; + u32 line_count; + u32 risc_pos; + u8 *buf_cpu; + dma_addr_t buf_dma; + u32 *risc_cpu; + dma_addr_t risc_dma; + + struct tasklet_struct tasklet; + + struct i2c_adapter adapter; + int i2c_rc; + wait_queue_head_t i2c_wq; + struct mutex i2c_lock; + + /* DVB stuff */ + struct dvb_adapter dvb_adapter; + struct dvb_frontend *fe; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net dvbnet; + + u8 feeds; + + struct mantis_hwconfig *hwconfig; + + u32 mantis_int_stat; + u32 mantis_int_mask; + + /* board specific */ + u8 mac_address[8]; + u32 sub_vendor_id; + u32 sub_device_id; + + /* A12 A13 A14 */ + u32 gpio_status; + + u32 gpif_status; + + struct mantis_ca *mantis_ca; + + wait_queue_head_t uart_wq; + struct work_struct uart_work; + spinlock_t uart_lock; + + struct rc_dev *rc; + char input_name[80]; + char input_phys[80]; +}; + +#define MANTIS_HIF_STATUS (mantis->gpio_status) + +#endif /* __MANTIS_COMMON_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,235 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "mantis_common.h" +#include "mantis_core.h" +#include "mantis_vp1033.h" +#include "mantis_vp1034.h" +#include "mantis_vp1041.h" +#include "mantis_vp2033.h" +#include "mantis_vp2040.h" +#include "mantis_vp3030.h" + +static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) +{ + int err; + struct i2c_msg msg[] = { + { + .addr = 0x50, + .flags = 0, + .buf = data, + .len = 1 + }, { + .addr = 0x50, + .flags = I2C_M_RD, + .buf = data, + .len = length + }, + }; + + err = i2c_transfer(&mantis->adapter, msg, 2); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, + "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", + err, data[0], data[1]); + + return err; + } + + return 0; +} + +static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) +{ + int err; + + struct i2c_msg msg = { + .addr = 0x50, + .flags = 0, + .buf = data, + .len = length + }; + + err = i2c_transfer(&mantis->adapter, &msg, 1); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, + "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >", + err, length, data[0], data[1]); + + return err; + } + + return 0; +} + +static int get_mac_address(struct mantis_pci *mantis) +{ + int err; + + mantis->mac_address[0] = 0x08; + err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error"); + + return err; + } + dprintk(verbose, MANTIS_ERROR, 0, + " MAC Address=[%pM]\n", mantis->mac_address); + + return 0; +} + +#define MANTIS_MODEL_UNKNOWN "UNKNOWN" +#define MANTIS_DEV_UNKNOWN "UNKNOWN" + +struct mantis_hwconfig unknown_device = { + .model_name = MANTIS_MODEL_UNKNOWN, + .dev_type = MANTIS_DEV_UNKNOWN, +}; + +static void mantis_load_config(struct mantis_pci *mantis) +{ + switch (mantis->subsystem_device) { + case MANTIS_VP_1033_DVB_S: /* VP-1033 */ + mantis->hwconfig = &vp1033_mantis_config; + break; + case MANTIS_VP_1034_DVB_S: /* VP-1034 */ + mantis->hwconfig = &vp1034_mantis_config; + break; + case MANTIS_VP_1041_DVB_S2: /* VP-1041 */ + case TECHNISAT_SKYSTAR_HD2: + mantis->hwconfig = &vp1041_mantis_config; + break; + case MANTIS_VP_2033_DVB_C: /* VP-2033 */ + mantis->hwconfig = &vp2033_mantis_config; + break; + case MANTIS_VP_2040_DVB_C: /* VP-2040 */ + case TERRATEC_CINERGY_C_PCI: /* VP-2040 clone */ + case TECHNISAT_CABLESTAR_HD2: + mantis->hwconfig = &vp2040_mantis_config; + break; + case MANTIS_VP_3030_DVB_T: /* VP-3030 */ + mantis->hwconfig = &vp3030_mantis_config; + break; + default: + mantis->hwconfig = &unknown_device; + break; + } +} + +int mantis_core_init(struct mantis_pci *mantis) +{ + int err = 0; + + mantis_load_config(mantis); + dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", + mantis->hwconfig->model_name, mantis->hwconfig->dev_type, + mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn)); + dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", + mantis->revision, + mantis->subsystem_vendor, mantis->subsystem_device); + dprintk(verbose, MANTIS_ERROR, 0, + "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", + mantis->pdev->irq, mantis->latency, + mantis->mantis_addr, mantis->mantis_mmio); + + err = mantis_i2c_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed"); + return err; + } + err = get_mac_address(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed"); + return err; + } + err = mantis_dma_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed"); + return err; + } + err = mantis_dvb_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed"); + return err; + } + err = mantis_uart_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed"); + return err; + } + + return 0; +} + +int mantis_core_exit(struct mantis_pci *mantis) +{ + mantis_dma_stop(mantis); + dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping"); + + mantis_uart_exit(mantis); + dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed"); + + if (mantis_dma_exit(mantis) < 0) + dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed"); + if (mantis_dvb_exit(mantis) < 0) + dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed"); + if (mantis_i2c_exit(mantis) < 0) + dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed"); + + return 0; +} + +/* Turn the given bit on or off. */ +void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) +{ + u32 cur; + + cur = mmread(MANTIS_GPIF_ADDR); + if (value) + mantis->gpio_status = cur | (1 << bitpos); + else + mantis->gpio_status = cur & (~(1 << bitpos)); + + mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); + mmwrite(0x00, MANTIS_GPIF_DOUT); + udelay(100); +} + +/* direction = 0 , no CI passthrough ; 1 , CI passthrough */ +void mantis_set_direction(struct mantis_pci *mantis, int direction) +{ + u32 reg; + + reg = mmread(0x28); + dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup"); + if (direction == 0x01) { + /* to CI */ + reg |= 0x04; + mmwrite(reg, 0x28); + reg &= 0xff - 0x04; + mmwrite(reg, 0x28); + } else { + reg &= 0xff - 0x04; + mmwrite(reg, 0x28); + reg |= 0x04; + mmwrite(reg, 0x28); + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_core.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_core.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,57 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_CORE_H +#define __MANTIS_CORE_H + +#include "mantis_common.h" + + +#define FE_TYPE_SAT 0 +#define FE_TYPE_CAB 1 +#define FE_TYPE_TER 2 + +#define FE_TYPE_TS204 0 +#define FE_TYPE_TS188 1 + + +struct vendorname { + u8 *sub_vendor_name; + u32 sub_vendor_id; +}; + +struct devicetype { + u8 *sub_device_name; + u32 sub_device_id; + u8 device_type; + u32 type_flags; +}; + + +extern int mantis_dma_init(struct mantis_pci *mantis); +extern int mantis_dma_exit(struct mantis_pci *mantis); +extern void mantis_dma_start(struct mantis_pci *mantis); +extern void mantis_dma_stop(struct mantis_pci *mantis); +extern int mantis_i2c_init(struct mantis_pci *mantis); +extern int mantis_i2c_exit(struct mantis_pci *mantis); +extern int mantis_core_init(struct mantis_pci *mantis); +extern int mantis_core_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_CORE_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dma.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dma.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dma.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dma.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,256 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_dma.h" + +#define RISC_WRITE (0x01 << 28) +#define RISC_JUMP (0x07 << 28) +#define RISC_IRQ (0x01 << 24) + +#define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) +#define RISC_FLUSH() (mantis->risc_pos = 0) +#define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode)) + +#define MANTIS_BUF_SIZE (64 * 1024) +#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4) +#define MANTIS_BLOCK_COUNT (1 << 4) +#define MANTIS_RISC_SIZE PAGE_SIZE + +int mantis_dma_exit(struct mantis_pci *mantis) +{ + if (mantis->buf_cpu) { + dprintk(MANTIS_ERROR, 1, + "DMA=0x%lx cpu=0x%p size=%d", + (unsigned long) mantis->buf_dma, + mantis->buf_cpu, + MANTIS_BUF_SIZE); + + pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE, + mantis->buf_cpu, mantis->buf_dma); + + mantis->buf_cpu = NULL; + } + if (mantis->risc_cpu) { + dprintk(MANTIS_ERROR, 1, + "RISC=0x%lx cpu=0x%p size=%lx", + (unsigned long) mantis->risc_dma, + mantis->risc_cpu, + MANTIS_RISC_SIZE); + + pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE, + mantis->risc_cpu, mantis->risc_dma); + + mantis->risc_cpu = NULL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_dma_exit); + +static inline int mantis_alloc_buffers(struct mantis_pci *mantis) +{ + if (!mantis->buf_cpu) { + mantis->buf_cpu = pci_alloc_consistent(mantis->pdev, + MANTIS_BUF_SIZE, + &mantis->buf_dma); + if (!mantis->buf_cpu) { + dprintk(MANTIS_ERROR, 1, + "DMA buffer allocation failed"); + + goto err; + } + dprintk(MANTIS_ERROR, 1, + "DMA=0x%lx cpu=0x%p size=%d", + (unsigned long) mantis->buf_dma, + mantis->buf_cpu, MANTIS_BUF_SIZE); + } + if (!mantis->risc_cpu) { + mantis->risc_cpu = pci_alloc_consistent(mantis->pdev, + MANTIS_RISC_SIZE, + &mantis->risc_dma); + + if (!mantis->risc_cpu) { + dprintk(MANTIS_ERROR, 1, + "RISC program allocation failed"); + + mantis_dma_exit(mantis); + + goto err; + } + dprintk(MANTIS_ERROR, 1, + "RISC=0x%lx cpu=0x%p size=%lx", + (unsigned long) mantis->risc_dma, + mantis->risc_cpu, MANTIS_RISC_SIZE); + } + + return 0; +err: + dprintk(MANTIS_ERROR, 1, "Out of memory (?) ....."); + return -ENOMEM; +} + +static inline int mantis_calc_lines(struct mantis_pci *mantis) +{ + mantis->line_bytes = MANTIS_BLOCK_BYTES; + mantis->line_count = MANTIS_BLOCK_COUNT; + + while (mantis->line_bytes > 4095) { + mantis->line_bytes >>= 1; + mantis->line_count <<= 1; + } + + dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]", + MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count); + + if (mantis->line_count > 255) { + dprintk(MANTIS_ERROR, 1, "Buffer size error"); + return -EINVAL; + } + + return 0; +} + +int mantis_dma_init(struct mantis_pci *mantis) +{ + int err = 0; + + dprintk(MANTIS_DEBUG, 1, "Mantis DMA init"); + if (mantis_alloc_buffers(mantis) < 0) { + dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer"); + + /* Stop RISC Engine */ + mmwrite(0, MANTIS_DMA_CTL); + + goto err; + } + err = mantis_calc_lines(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed"); + + goto err; + } + + return 0; +err: + return err; +} +EXPORT_SYMBOL_GPL(mantis_dma_init); + +static inline void mantis_risc_program(struct mantis_pci *mantis) +{ + u32 buf_pos = 0; + u32 line; + + dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program"); + RISC_FLUSH(); + + dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u", + mantis->line_count, mantis->line_bytes); + + for (line = 0; line < mantis->line_count; line++) { + dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line); + if (!(buf_pos % MANTIS_BLOCK_BYTES)) { + RISC_INSTR(RISC_WRITE | + RISC_IRQ | + RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) + + (MANTIS_BLOCK_COUNT - 1)) % + MANTIS_BLOCK_COUNT) | + mantis->line_bytes); + } else { + RISC_INSTR(RISC_WRITE | mantis->line_bytes); + } + RISC_INSTR(mantis->buf_dma + buf_pos); + buf_pos += mantis->line_bytes; + } + RISC_INSTR(RISC_JUMP); + RISC_INSTR(mantis->risc_dma); +} + +void mantis_dma_start(struct mantis_pci *mantis) +{ + dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine"); + + mantis_risc_program(mantis); + mmwrite(mantis->risc_dma, MANTIS_RISC_START); + mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + + mmwrite(0, MANTIS_DMA_CTL); + mantis->last_block = mantis->finished_block = 0; + + mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); + + mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN + | MANTIS_RISC_EN, MANTIS_DMA_CTL); + +} + +void mantis_dma_stop(struct mantis_pci *mantis) +{ + u32 stat = 0, mask = 0; + + stat = mmread(MANTIS_INT_STAT); + mask = mmread(MANTIS_INT_MASK); + dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine"); + + mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR); + + mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN | + MANTIS_DCAP_EN | + MANTIS_RISC_EN)), MANTIS_DMA_CTL); + + mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); + + mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI | + MANTIS_INT_RISCEN), MANTIS_INT_MASK); +} + + +void mantis_dma_xfer(unsigned long data) +{ + struct mantis_pci *mantis = (struct mantis_pci *) data; + struct mantis_hwconfig *config = mantis->hwconfig; + + while (mantis->last_block != mantis->finished_block) { + dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]", + mantis->last_block, mantis->finished_block); + + (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) + (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); + mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT; + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dma.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dma.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dma.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dma.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_DMA_H +#define __MANTIS_DMA_H + +extern int mantis_dma_init(struct mantis_pci *mantis); +extern int mantis_dma_exit(struct mantis_pci *mantis); +extern void mantis_dma_start(struct mantis_pci *mantis); +extern void mantis_dma_stop(struct mantis_pci *mantis); +extern void mantis_dma_xfer(unsigned long data); + +#endif /* __MANTIS_DMA_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dvb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,299 @@ +/* + Mantis PCI bridge driver + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_dma.h" +#include "mantis_ca.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + + switch (power) { + case POWER_ON: + dprintk(MANTIS_DEBUG, 1, "Power ON"); + mantis_gpio_set_bits(mantis, config->power, POWER_ON); + msleep(100); + mantis_gpio_set_bits(mantis, config->power, POWER_ON); + msleep(100); + break; + + case POWER_OFF: + dprintk(MANTIS_DEBUG, 1, "Power OFF"); + mantis_gpio_set_bits(mantis, config->power, POWER_OFF); + msleep(100); + break; + + default: + dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power); + return -1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_frontend_power); + +void mantis_frontend_soft_reset(struct mantis_pci *mantis) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + + dprintk(MANTIS_DEBUG, 1, "Frontend RESET"); + mantis_gpio_set_bits(mantis, config->reset, 0); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 0); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 1); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 1); + msleep(100); + + return; +} +EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset); + +static int mantis_frontend_shutdown(struct mantis_pci *mantis) +{ + int err; + + mantis_frontend_soft_reset(mantis); + err = mantis_frontend_power(mantis, POWER_OFF); + if (err != 0) { + dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err); + return 1; + } + + return 0; +} + +static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct mantis_pci *mantis = dvbdmx->priv; + + dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed"); + if (!dvbdmx->dmx.frontend) { + dprintk(MANTIS_DEBUG, 1, "no frontend ?"); + return -EINVAL; + } + + mantis->feeds++; + dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds); + + if (mantis->feeds == 1) { + dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); + mantis_dma_start(mantis); + tasklet_enable(&mantis->tasklet); + } + + return mantis->feeds; +} + +static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct mantis_pci *mantis = dvbdmx->priv; + + dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed"); + if (!dvbdmx->dmx.frontend) { + dprintk(MANTIS_DEBUG, 1, "no frontend ?"); + return -EINVAL; + } + + mantis->feeds--; + if (mantis->feeds == 0) { + dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); + tasklet_disable(&mantis->tasklet); + mantis_dma_stop(mantis); + } + + return 0; +} + +int __devinit mantis_dvb_init(struct mantis_pci *mantis) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + int result = -1; + + dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter"); + + result = dvb_register_adapter(&mantis->dvb_adapter, + "Mantis DVB adapter", + THIS_MODULE, + &mantis->pdev->dev, + adapter_nr); + + if (result < 0) { + + dprintk(MANTIS_ERROR, 1, "Error registering adapter"); + return -ENODEV; + } + + mantis->dvb_adapter.priv = mantis; + mantis->demux.dmx.capabilities = DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + + mantis->demux.priv = mantis; + mantis->demux.filternum = 256; + mantis->demux.feednum = 256; + mantis->demux.start_feed = mantis_dvb_start_feed; + mantis->demux.stop_feed = mantis_dvb_stop_feed; + mantis->demux.write_to_decoder = NULL; + + dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init"); + result = dvb_dmx_init(&mantis->demux); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + + goto err0; + } + + mantis->dmxdev.filternum = 256; + mantis->dmxdev.demux = &mantis->demux.dmx; + mantis->dmxdev.capabilities = 0; + dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init"); + + result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter); + if (result < 0) { + + dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result); + goto err1; + } + + mantis->fe_hw.source = DMX_FRONTEND_0; + result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw); + if (result < 0) { + + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err2; + } + + mantis->fe_mem.source = DMX_MEMORY_FE; + result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err3; + } + + result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err4; + } + + dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); + tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis); + tasklet_disable(&mantis->tasklet); + if (mantis->hwconfig) { + result = config->frontend_init(mantis, mantis->fe); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!"); + goto err5; + } else { + if (mantis->fe == NULL) { + dprintk(MANTIS_ERROR, 1, "FE "); + goto err5; + } + + if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) { + dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed"); + + if (mantis->fe->ops.release) + mantis->fe->ops.release(mantis->fe); + + mantis->fe = NULL; + goto err5; + } + } + } + + return 0; + + /* Error conditions .. */ +err5: + tasklet_kill(&mantis->tasklet); + dvb_net_release(&mantis->dvbnet); + dvb_unregister_frontend(mantis->fe); + dvb_frontend_detach(mantis->fe); +err4: + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); + +err3: + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); + +err2: + dvb_dmxdev_release(&mantis->dmxdev); + +err1: + dvb_dmx_release(&mantis->demux); + +err0: + dvb_unregister_adapter(&mantis->dvb_adapter); + + return result; +} +EXPORT_SYMBOL_GPL(mantis_dvb_init); + +int __devexit mantis_dvb_exit(struct mantis_pci *mantis) +{ + int err; + + if (mantis->fe) { + /* mantis_ca_exit(mantis); */ + err = mantis_frontend_shutdown(mantis); + if (err != 0) + dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err); + dvb_unregister_frontend(mantis->fe); + dvb_frontend_detach(mantis->fe); + } + + tasklet_kill(&mantis->tasklet); + dvb_net_release(&mantis->dvbnet); + + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); + + dvb_dmxdev_release(&mantis->dmxdev); + dvb_dmx_release(&mantis->demux); + + dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter"); + dvb_unregister_adapter(&mantis->dvb_adapter); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_dvb_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dvb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dvb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dvb.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_dvb.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_DVB_H +#define __MANTIS_DVB_H + +enum mantis_power { + POWER_OFF = 0, + POWER_ON = 1 +}; + +extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power); +extern void mantis_frontend_soft_reset(struct mantis_pci *mantis); + +extern int mantis_dvb_init(struct mantis_pci *mantis); +extern int mantis_dvb_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_DVB_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_evm.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_evm.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_evm.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_evm.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,117 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" +#include "mantis_hif.h" +#include "mantis_reg.h" + +static void mantis_hifevm_work(struct work_struct *work) +{ + struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work); + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_stat, gpif_mask; + + gpif_stat = mmread(MANTIS_GPIF_STATUS); + gpif_mask = mmread(MANTIS_GPIF_IRQCFG); + + if (gpif_stat & MANTIS_GPIF_DETSTAT) { + if (gpif_stat & MANTIS_CARD_PLUGIN) { + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num); + mmwrite(0xdada0000, MANTIS_CARD_RESET); + mantis_event_cam_plugin(ca); + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_INSERTED); + } + } else { + if (gpif_stat & MANTIS_CARD_PLUGOUT) { + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num); + mmwrite(0xdada0000, MANTIS_CARD_RESET); + mantis_event_cam_unplug(ca); + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_REMOVED); + } + } + + if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num); + + if (mantis->gpif_status & MANTIS_SBUF_WSTO) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num); + + if (mantis->gpif_status & MANTIS_GPIF_OTHERR) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num); + + if (gpif_stat & MANTIS_SBUF_OVFLW) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num); + + if (gpif_stat & MANTIS_GPIF_BRRDY) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num); + + if (gpif_stat & MANTIS_GPIF_INTSTAT) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num); + + if (gpif_stat & MANTIS_SBUF_EMPTY) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num); + + if (gpif_stat & MANTIS_SBUF_OPDONE) { + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num); + ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL; + ca->hif_event = MANTIS_SBUF_OPDONE; + wake_up(&ca->hif_opdone_wq); + } +} + +int mantis_evmgr_init(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager"); + INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work); + mantis_pcmcia_init(ca); + schedule_work(&ca->hif_evm_work); + mantis_hif_init(ca); + return 0; +} + +void mantis_evmgr_exit(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting"); + flush_work_sync(&ca->hif_evm_work); + mantis_hif_exit(ca); + mantis_pcmcia_exit(ca); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_hif.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_hif.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_hif.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_hif.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,238 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" + +#include "mantis_hif.h" +#include "mantis_link.h" /* temporary due to physical layer stuff */ + +#include "mantis_reg.h" + + +static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + int rc = 0; + + if (wait_event_timeout(ca->hif_opdone_wq, + ca->hif_event & MANTIS_SBUF_OPDONE, + msecs_to_jiffies(500)) == -ERESTARTSYS) { + + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num); + rc = -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete"); + ca->hif_event &= ~MANTIS_SBUF_OPDONE; + return rc; +} + +static int mantis_hif_write_wait(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 opdone = 0, timeout = 0; + int rc = 0; + + if (wait_event_timeout(ca->hif_write_wq, + mantis->gpif_status & MANTIS_GPIF_WRACK, + msecs_to_jiffies(500)) == -ERESTARTSYS) { + + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num); + rc = -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "Write Acknowledged"); + mantis->gpif_status &= ~MANTIS_GPIF_WRACK; + while (!opdone) { + opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE); + udelay(500); + timeout++; + if (timeout > 100) { + dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num); + rc = -ETIMEDOUT; + break; + } + } + dprintk(MANTIS_DEBUG, 1, "HIF Write success"); + return rc; +} + + +int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 hif_addr = 0, data, count = 4; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(hif_addr, MANTIS_GPIF_BRADDR); + mmwrite(count, MANTIS_GPIF_BRBYTES); + udelay(20); + mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + + if (mantis_hif_sbuf_opdone_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + data = mmread(MANTIS_GPIF_DIN); + mutex_unlock(&ca->ca_lock); + dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data); + return (data >> 24) & 0xff; +} + +int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data) +{ + struct mantis_slot *slot = ca->slot; + struct mantis_pci *mantis = ca->ca_priv; + u32 hif_addr = 0; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_HIFRDWRN; + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */ + mmwrite(hif_addr, MANTIS_GPIF_ADDR); + mmwrite(data, MANTIS_GPIF_DOUT); + + if (mantis_hif_write_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr); + mutex_unlock(&ca->ca_lock); + + return 0; +} + +int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 data, hif_addr = 0; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr |= MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(hif_addr, MANTIS_GPIF_BRADDR); + mmwrite(1, MANTIS_GPIF_BRBYTES); + udelay(20); + mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + + if (mantis_hif_sbuf_opdone_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + data = mmread(MANTIS_GPIF_DIN); + dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data); + udelay(50); + mutex_unlock(&ca->ca_lock); + + return (u8) data; +} + +int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 hif_addr = 0; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr &= ~MANTIS_GPIF_HIFRDWRN; + hif_addr |= MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(hif_addr, MANTIS_GPIF_ADDR); + mmwrite(data, MANTIS_GPIF_DOUT); + + if (mantis_hif_write_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr); + mutex_unlock(&ca->ca_lock); + udelay(50); + + return 0; +} + +int mantis_hif_init(struct mantis_ca *ca) +{ + struct mantis_slot *slot = ca->slot; + struct mantis_pci *mantis = ca->ca_priv; + u32 irqcfg; + + slot[0].slave_cfg = 0x70773028; + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num); + + mutex_lock(&ca->ca_lock); + irqcfg = mmread(MANTIS_GPIF_IRQCFG); + irqcfg = MANTIS_MASK_BRRDY | + MANTIS_MASK_WRACK | + MANTIS_MASK_EXTIRQ | + MANTIS_MASK_WSTO | + MANTIS_MASK_OTHERR | + MANTIS_MASK_OVFLW; + + mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); + mutex_unlock(&ca->ca_lock); + + return 0; +} + +void mantis_hif_exit(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 irqcfg; + + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num); + mutex_lock(&ca->ca_lock); + irqcfg = mmread(MANTIS_GPIF_IRQCFG); + irqcfg &= ~MANTIS_MASK_BRRDY; + mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); + mutex_unlock(&ca->ca_lock); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_hif.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_hif.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_hif.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_hif.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,29 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_HIF_H +#define __MANTIS_HIF_H + +#define MANTIS_HIF_MEMRD 1 +#define MANTIS_HIF_MEMWR 2 +#define MANTIS_HIF_IOMRD 3 +#define MANTIS_HIF_IOMWR 4 + +#endif /* __MANTIS_HIF_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,266 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_i2c.h" + +#define TRIALS 10000 + +static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg) +{ + u32 rxd, i, stat, trials; + + dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] [ ", + __func__, msg->addr); + + for (i = 0; i < msg->len; i++) { + rxd = (msg->addr << 25) | (1 << 24) + | MANTIS_I2C_RATE_3 + | MANTIS_I2C_STOP + | MANTIS_I2C_PGMODE; + + if (i == (msg->len - 1)) + rxd &= ~MANTIS_I2C_STOP; + + mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); + mmwrite(rxd, MANTIS_I2CDATA_CTL); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CDONE) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CRACK) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); + + rxd = mmread(MANTIS_I2CDATA_CTL); + msg->buf[i] = (u8)((rxd >> 8) & 0xFF); + dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); + } + dprintk(MANTIS_INFO, 0, "]\n"); + + return 0; +} + +static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg) +{ + int i; + u32 txd = 0, stat, trials; + + dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] [ ", + __func__, msg->addr); + + for (i = 0; i < msg->len; i++) { + dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); + txd = (msg->addr << 25) | (msg->buf[i] << 8) + | MANTIS_I2C_RATE_3 + | MANTIS_I2C_STOP + | MANTIS_I2C_PGMODE; + + if (i == (msg->len - 1)) + txd &= ~MANTIS_I2C_STOP; + + mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); + mmwrite(txd, MANTIS_I2CDATA_CTL); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CDONE) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CRACK) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); + } + dprintk(MANTIS_INFO, 0, "]\n"); + + return 0; +} + +static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) +{ + int ret = 0, i = 0, trials; + u32 stat, data, txd; + struct mantis_pci *mantis; + struct mantis_hwconfig *config; + + mantis = i2c_get_adapdata(adapter); + BUG_ON(!mantis); + config = mantis->hwconfig; + BUG_ON(!config); + + dprintk(MANTIS_DEBUG, 1, "Messages:%d", num); + mutex_lock(&mantis->i2c_lock); + + while (i < num) { + /* Byte MODE */ + if ((config->i2c_mode & MANTIS_BYTE_MODE) && + ((i + 1) < num) && + (msgs[i].len < 2) && + (msgs[i + 1].len < 2) && + (msgs[i + 1].flags & I2C_M_RD)) { + + dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n"); + + /* Read operation */ + txd = msgs[i].addr << 25 | (0x1 << 24) + | (msgs[i].buf[0] << 16) + | MANTIS_I2C_RATE_3; + + mmwrite(txd, MANTIS_I2CDATA_CTL); + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CDONE) + break; + } + + /* check for xfer completion */ + if (stat & MANTIS_INT_I2CDONE) { + /* check xfer was acknowledged */ + if (stat & MANTIS_INT_I2CRACK) { + data = mmread(MANTIS_I2CDATA_CTL); + msgs[i + 1].buf[0] = (data >> 8) & 0xff; + dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]); + } else { + /* I/O error */ + dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); + ret = -EIO; + break; + } + } else { + /* I/O error */ + dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); + ret = -EIO; + break; + } + i += 2; /* Write/Read operation in one go */ + } + + if (i < num) { + if (msgs[i].flags & I2C_M_RD) + ret = mantis_i2c_read(mantis, &msgs[i]); + else + ret = mantis_i2c_write(mantis, &msgs[i]); + + i++; + if (ret < 0) + goto bail_out; + } + + } + + mutex_unlock(&mantis->i2c_lock); + + return num; + +bail_out: + mutex_unlock(&mantis->i2c_lock); + return ret; +} + +static u32 mantis_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm mantis_algo = { + .master_xfer = mantis_i2c_xfer, + .functionality = mantis_i2c_func, +}; + +int __devinit mantis_i2c_init(struct mantis_pci *mantis) +{ + u32 intstat, intmask; + struct i2c_adapter *i2c_adapter = &mantis->adapter; + struct pci_dev *pdev = mantis->pdev; + + init_waitqueue_head(&mantis->i2c_wq); + mutex_init(&mantis->i2c_lock); + strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); + i2c_set_adapdata(i2c_adapter, mantis); + + i2c_adapter->owner = THIS_MODULE; + i2c_adapter->algo = &mantis_algo; + i2c_adapter->algo_data = NULL; + i2c_adapter->timeout = 500; + i2c_adapter->retries = 3; + i2c_adapter->dev.parent = &pdev->dev; + + mantis->i2c_rc = i2c_add_adapter(i2c_adapter); + if (mantis->i2c_rc < 0) + return mantis->i2c_rc; + + dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); + + intstat = mmread(MANTIS_INT_STAT); + intmask = mmread(MANTIS_INT_MASK); + mmwrite(intstat, MANTIS_INT_STAT); + dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); + intmask = mmread(MANTIS_INT_MASK); + mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_i2c_init); + +int mantis_i2c_exit(struct mantis_pci *mantis) +{ + u32 intmask; + + dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); + intmask = mmread(MANTIS_INT_MASK); + mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + + dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); + return i2c_del_adapter(&mantis->adapter); +} +EXPORT_SYMBOL_GPL(mantis_i2c_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_i2c.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_i2c.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_I2C_H +#define __MANTIS_I2C_H + +#define I2C_STOP (1 << 0) +#define I2C_READ (1 << 1) + +extern int mantis_i2c_init(struct mantis_pci *mantis); +extern int mantis_i2c_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_I2C_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_input.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_input.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,159 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_uart.h" + +#define MODULE_NAME "mantis_core" +#define RC_MAP_MANTIS "rc-mantis" + +static struct rc_map_table mantis_ir_table[] = { + { 0x29, KEY_POWER }, + { 0x28, KEY_FAVORITES }, + { 0x30, KEY_TEXT }, + { 0x17, KEY_INFO }, /* Preview */ + { 0x23, KEY_EPG }, + { 0x3b, KEY_F22 }, /* Record List */ + { 0x3c, KEY_1 }, + { 0x3e, KEY_2 }, + { 0x39, KEY_3 }, + { 0x36, KEY_4 }, + { 0x22, KEY_5 }, + { 0x20, KEY_6 }, + { 0x32, KEY_7 }, + { 0x26, KEY_8 }, + { 0x24, KEY_9 }, + { 0x2a, KEY_0 }, + + { 0x33, KEY_CANCEL }, + { 0x2c, KEY_BACK }, + { 0x15, KEY_CLEAR }, + { 0x3f, KEY_TAB }, + { 0x10, KEY_ENTER }, + { 0x14, KEY_UP }, + { 0x0d, KEY_RIGHT }, + { 0x0e, KEY_DOWN }, + { 0x11, KEY_LEFT }, + + { 0x21, KEY_VOLUMEUP }, + { 0x35, KEY_VOLUMEDOWN }, + { 0x3d, KEY_CHANNELDOWN }, + { 0x3a, KEY_CHANNELUP }, + { 0x2e, KEY_RECORD }, + { 0x2b, KEY_PLAY }, + { 0x13, KEY_PAUSE }, + { 0x25, KEY_STOP }, + + { 0x1f, KEY_REWIND }, + { 0x2d, KEY_FASTFORWARD }, + { 0x1e, KEY_PREVIOUS }, /* Replay |< */ + { 0x1d, KEY_NEXT }, /* Skip >| */ + + { 0x0b, KEY_CAMERA }, /* Capture */ + { 0x0f, KEY_LANGUAGE }, /* SAP */ + { 0x18, KEY_MODE }, /* PIP */ + { 0x12, KEY_ZOOM }, /* Full screen */ + { 0x1c, KEY_SUBTITLE }, + { 0x2f, KEY_MUTE }, + { 0x16, KEY_F20 }, /* L/R */ + { 0x38, KEY_F21 }, /* Hibernate */ + + { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */ + { 0x31, KEY_AGAIN }, /* Recall */ + { 0x1a, KEY_KPPLUS }, /* Zoom+ */ + { 0x19, KEY_KPMINUS }, /* Zoom- */ + { 0x27, KEY_RED }, + { 0x0C, KEY_GREEN }, + { 0x01, KEY_YELLOW }, + { 0x00, KEY_BLUE }, +}; + +static struct rc_map_list ir_mantis_map = { + .map = { + .scan = mantis_ir_table, + .size = ARRAY_SIZE(mantis_ir_table), + .rc_type = RC_TYPE_UNKNOWN, + .name = RC_MAP_MANTIS, + } +}; + +int mantis_input_init(struct mantis_pci *mantis) +{ + struct rc_dev *dev; + int err; + + err = rc_map_register(&ir_mantis_map); + if (err) + goto out; + + dev = rc_allocate_device(); + if (!dev) { + dprintk(MANTIS_ERROR, 1, "Remote device allocation failed"); + err = -ENOMEM; + goto out_map; + } + + sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name); + sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev)); + + dev->input_name = mantis->input_name; + dev->input_phys = mantis->input_phys; + dev->input_id.bustype = BUS_PCI; + dev->input_id.vendor = mantis->vendor_id; + dev->input_id.product = mantis->device_id; + dev->input_id.version = 1; + dev->driver_name = MODULE_NAME; + dev->map_name = RC_MAP_MANTIS; + dev->dev.parent = &mantis->pdev->dev; + + err = rc_register_device(dev); + if (err) { + dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err); + goto out_dev; + } + + mantis->rc = dev; + return 0; + +out_dev: + rc_free_device(dev); +out_map: + rc_map_unregister(&ir_mantis_map); +out: + return err; +} + +int mantis_exit(struct mantis_pci *mantis) +{ + rc_unregister_device(mantis->rc); + rc_map_unregister(&ir_mantis_map); + return 0; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ioc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ioc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ioc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ioc.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,123 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_ioc.h" + +static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length) +{ + struct i2c_adapter *adapter = &mantis->adapter; + int err; + u8 buf = reg; + + struct i2c_msg msg[] = { + { .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length }, + }; + + err = i2c_transfer(adapter, msg, 2); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", + err, data[0], data[1]); + + return err; + } + + return 0; +} +int mantis_get_mac(struct mantis_pci *mantis) +{ + int err; + u8 mac_addr[6] = {0}; + + err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err); + + return err; + } + + dprintk(MANTIS_ERROR, 0, " MAC Address=[%pM]\n", mac_addr); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_get_mac); + +/* Turn the given bit on or off. */ +void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) +{ + u32 cur; + + dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value); + cur = mmread(MANTIS_GPIF_ADDR); + if (value) + mantis->gpio_status = cur | (1 << bitpos); + else + mantis->gpio_status = cur & (~(1 << bitpos)); + + dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status); + mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); + mmwrite(0x00, MANTIS_GPIF_DOUT); +} +EXPORT_SYMBOL_GPL(mantis_gpio_set_bits); + +int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl) +{ + u32 reg; + + reg = mmread(MANTIS_CONTROL); + switch (stream_ctl) { + case STREAM_TO_HIF: + dprintk(MANTIS_DEBUG, 1, "Set stream to HIF"); + reg &= 0xff - MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + reg |= MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + break; + + case STREAM_TO_CAM: + dprintk(MANTIS_DEBUG, 1, "Set stream to CAM"); + reg |= MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + reg &= 0xff - MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + break; + default: + dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl); + return -1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_stream_control); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ioc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ioc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ioc.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_ioc.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_IOC_H +#define __MANTIS_IOC_H + +#define GPIF_A00 0x00 +#define GPIF_A01 0x01 +#define GPIF_A02 0x02 +#define GPIF_A03 0x03 +#define GPIF_A04 0x04 +#define GPIF_A05 0x05 +#define GPIF_A06 0x06 +#define GPIF_A07 0x07 +#define GPIF_A08 0x08 +#define GPIF_A09 0x09 +#define GPIF_A10 0x0a +#define GPIF_A11 0x0b + +#define GPIF_A12 0x0c +#define GPIF_A13 0x0d +#define GPIF_A14 0x0e + +enum mantis_stream_control { + STREAM_TO_HIF = 0, + STREAM_TO_CAM +}; + +extern int mantis_get_mac(struct mantis_pci *mantis); +extern void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value); + +extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl); + +#endif /* __MANTIS_IOC_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_link.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_link.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_link.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_link.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_LINK_H +#define __MANTIS_LINK_H + +#include +#include +#include "dvb_ca_en50221.h" + +enum mantis_sbuf_status { + MANTIS_SBUF_DATA_AVAIL = 1, + MANTIS_SBUF_DATA_EMPTY = 2, + MANTIS_SBUF_DATA_OVFLW = 3 +}; + +struct mantis_slot { + u32 timeout; + u32 slave_cfg; + u32 bar; +}; + +/* Physical layer */ +enum mantis_slot_state { + MODULE_INSERTED = 3, + MODULE_XTRACTED = 4 +}; + +struct mantis_ca { + struct mantis_slot slot[4]; + + struct work_struct hif_evm_work; + + u32 hif_event; + wait_queue_head_t hif_opdone_wq; + wait_queue_head_t hif_brrdyw_wq; + wait_queue_head_t hif_data_wq; + wait_queue_head_t hif_write_wq; /* HIF Write op */ + + enum mantis_sbuf_status sbuf_status; + + enum mantis_slot_state slot_state; + + void *ca_priv; + + struct dvb_ca_en50221 en50221; + struct mutex ca_lock; +}; + +/* CA */ +extern void mantis_event_cam_plugin(struct mantis_ca *ca); +extern void mantis_event_cam_unplug(struct mantis_ca *ca); +extern int mantis_pcmcia_init(struct mantis_ca *ca); +extern void mantis_pcmcia_exit(struct mantis_ca *ca); +extern int mantis_evmgr_init(struct mantis_ca *ca); +extern void mantis_evmgr_exit(struct mantis_ca *ca); + +/* HIF */ +extern int mantis_hif_init(struct mantis_ca *ca); +extern void mantis_hif_exit(struct mantis_ca *ca); +extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr); +extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data); +extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr); +extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data); + +#endif /* __MANTIS_LINK_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pci.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pci.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,170 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_pci.h" + +#define DRIVER_NAME "Mantis Core" + +int __devinit mantis_pci_init(struct mantis_pci *mantis) +{ + u8 latency; + struct mantis_hwconfig *config = mantis->hwconfig; + struct pci_dev *pdev = mantis->pdev; + int err, ret = 0; + + dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", + config->model_name, + config->dev_type, + mantis->pdev->bus->number, + PCI_SLOT(mantis->pdev->devfn), + PCI_FUNC(mantis->pdev->devfn)); + + err = pci_enable_device(pdev); + if (err != 0) { + ret = -ENODEV; + dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err); + goto fail0; + } + + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err != 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err); + ret = -ENOMEM; + goto fail1; + } + + pci_set_master(pdev); + + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), + DRIVER_NAME)) { + + dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !"); + ret = -ENODEV; + goto fail1; + } + + mantis->mmio = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + + if (!mantis->mmio) { + dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !"); + ret = -ENODEV; + goto fail2; + } + + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency); + mantis->latency = latency; + mantis->revision = pdev->revision; + + dprintk(MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", + mantis->revision, + mantis->pdev->subsystem_vendor, + mantis->pdev->subsystem_device); + + dprintk(MANTIS_ERROR, 0, + "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", + mantis->pdev->irq, + mantis->latency, + mantis->mantis_addr, + mantis->mmio); + + err = request_irq(pdev->irq, + config->irq_handler, + IRQF_SHARED, + DRIVER_NAME, + mantis); + + if (err != 0) { + + dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err); + ret = -ENODEV; + goto fail3; + } + + pci_set_drvdata(pdev, mantis); + return ret; + + /* Error conditions */ +fail3: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret); + if (mantis->mmio) + iounmap(mantis->mmio); + +fail2: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + +fail1: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret); + pci_disable_device(pdev); + +fail0: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret); + pci_set_drvdata(pdev, NULL); + return ret; +} +EXPORT_SYMBOL_GPL(mantis_pci_init); + +void mantis_pci_exit(struct mantis_pci *mantis) +{ + struct pci_dev *pdev = mantis->pdev; + + dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio); + free_irq(pdev->irq, mantis); + if (mantis->mmio) { + iounmap(mantis->mmio); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + } + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} +EXPORT_SYMBOL_GPL(mantis_pci_exit); + +MODULE_DESCRIPTION("Mantis PCI DTV bridge driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pci.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pci.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pci.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pci.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_PCI_H +#define __MANTIS_PCI_H + +extern int mantis_pci_init(struct mantis_pci *mantis); +extern void mantis_pci_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_PCI_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pcmcia.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pcmcia.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pcmcia.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_pcmcia.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,120 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" /* temporary due to physical layer stuff */ +#include "mantis_reg.h" + +/* + * If Slot state is already PLUG_IN event and we are called + * again, definitely it is jitter alone + */ +void mantis_event_cam_plugin(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_irqcfg; + + if (ca->slot_state == MODULE_XTRACTED) { + dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num); + udelay(50); + mmwrite(0xda000000, MANTIS_CARD_RESET); + gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); + gpif_irqcfg |= MANTIS_MASK_PLUGOUT; + gpif_irqcfg &= ~MANTIS_MASK_PLUGIN; + mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); + udelay(500); + ca->slot_state = MODULE_INSERTED; + } + udelay(100); +} + +/* + * If Slot state is already UN_PLUG event and we are called + * again, definitely it is jitter alone + */ +void mantis_event_cam_unplug(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_irqcfg; + + if (ca->slot_state == MODULE_INSERTED) { + dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num); + udelay(50); + mmwrite(0x00da0000, MANTIS_CARD_RESET); + gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); + gpif_irqcfg |= MANTIS_MASK_PLUGIN; + gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT; + mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); + udelay(500); + ca->slot_state = MODULE_XTRACTED; + } + udelay(100); +} + +int mantis_pcmcia_init(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_stat, card_stat; + + mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK); + gpif_stat = mmread(MANTIS_GPIF_STATUS); + card_stat = mmread(MANTIS_GPIF_IRQCFG); + + if (gpif_stat & MANTIS_GPIF_DETSTAT) { + dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num); + mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG); + ca->slot_state = MODULE_INSERTED; + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_INSERTED); + } else { + dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num); + mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG); + ca->slot_state = MODULE_XTRACTED; + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_REMOVED); + } + + return 0; +} + +void mantis_pcmcia_exit(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS); + mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,197 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_REG_H +#define __MANTIS_REG_H + +/* Interrupts */ +#define MANTIS_INT_STAT 0x00 +#define MANTIS_INT_MASK 0x04 + +#define MANTIS_INT_RISCSTAT (0x0f << 28) +#define MANTIS_INT_RISCEN (0x01 << 27) +#define MANTIS_INT_I2CRACK (0x01 << 26) + +/* #define MANTIS_INT_GPIF (0xff << 12) */ + +#define MANTIS_INT_PCMCIA7 (0x01 << 19) +#define MANTIS_INT_PCMCIA6 (0x01 << 18) +#define MANTIS_INT_PCMCIA5 (0x01 << 17) +#define MANTIS_INT_PCMCIA4 (0x01 << 16) +#define MANTIS_INT_PCMCIA3 (0x01 << 15) +#define MANTIS_INT_PCMCIA2 (0x01 << 14) +#define MANTIS_INT_PCMCIA1 (0x01 << 13) +#define MANTIS_INT_PCMCIA0 (0x01 << 12) +#define MANTIS_INT_IRQ1 (0x01 << 11) +#define MANTIS_INT_IRQ0 (0x01 << 10) +#define MANTIS_INT_OCERR (0x01 << 8) +#define MANTIS_INT_PABORT (0x01 << 7) +#define MANTIS_INT_RIPERR (0x01 << 6) +#define MANTIS_INT_PPERR (0x01 << 5) +#define MANTIS_INT_FTRGT (0x01 << 3) +#define MANTIS_INT_RISCI (0x01 << 1) +#define MANTIS_INT_I2CDONE (0x01 << 0) + +/* DMA */ +#define MANTIS_DMA_CTL 0x08 +#define MANTIS_GPIF_RD (0xff << 24) +#define MANTIS_GPIF_WR (0xff << 16) +#define MANTIS_CPU_DO (0x01 << 10) +#define MANTIS_DRV_DO (0x01 << 9) +#define MANTIS_I2C_RD (0x01 << 7) +#define MANTIS_I2C_WR (0x01 << 6) +#define MANTIS_DCAP_MODE (0x01 << 5) +#define MANTIS_FIFO_TP_4 (0x00 << 3) +#define MANTIS_FIFO_TP_8 (0x01 << 3) +#define MANTIS_FIFO_TP_16 (0x02 << 3) +#define MANTIS_FIFO_EN (0x01 << 2) +#define MANTIS_DCAP_EN (0x01 << 1) +#define MANTIS_RISC_EN (0x01 << 0) + +/* DEBUG */ +#define MANTIS_DEBUGREG 0x0c +#define MANTIS_DATINV (0x0e << 7) +#define MANTIS_TOP_DEBUGSEL (0x07 << 4) +#define MANTIS_PCMCIA_DEBUGSEL (0x0f << 0) + +#define MANTIS_RISC_START 0x10 +#define MANTIS_RISC_PC 0x14 + +/* I2C */ +#define MANTIS_I2CDATA_CTL 0x18 +#define MANTIS_I2C_RATE_1 (0x00 << 6) +#define MANTIS_I2C_RATE_2 (0x01 << 6) +#define MANTIS_I2C_RATE_3 (0x02 << 6) +#define MANTIS_I2C_RATE_4 (0x03 << 6) +#define MANTIS_I2C_STOP (0x01 << 5) +#define MANTIS_I2C_PGMODE (0x01 << 3) + +/* DATA */ +#define MANTIS_CMD_DATA_R1 0x20 +#define MANTIS_CMD_DATA_3 (0xff << 24) +#define MANTIS_CMD_DATA_2 (0xff << 16) +#define MANTIS_CMD_DATA_1 (0xff << 8) +#define MANTIS_CMD_DATA_0 (0xff << 0) + +#define MANTIS_CMD_DATA_R2 0x24 +#define MANTIS_CMD_DATA_7 (0xff << 24) +#define MANTIS_CMD_DATA_6 (0xff << 16) +#define MANTIS_CMD_DATA_5 (0xff << 8) +#define MANTIS_CMD_DATA_4 (0xff << 0) + +#define MANTIS_CONTROL 0x28 +#define MANTIS_DET (0x01 << 7) +#define MANTIS_DAT_CF_EN (0x01 << 6) +#define MANTIS_ACS (0x03 << 4) +#define MANTIS_VCCEN (0x01 << 3) +#define MANTIS_BYPASS (0x01 << 2) +#define MANTIS_MRST (0x01 << 1) +#define MANTIS_CRST_INT (0x01 << 0) + +#define MANTIS_GPIF_CFGSLA 0x84 +#define MANTIS_GPIF_WAITSMPL (0x07 << 28) +#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25) +#define MANTIS_GPIF_WAITPOL (0x01 << 24) +#define MANTIS_GPIF_NCDELAY (0x07 << 20) +#define MANTIS_GPIF_RW2CSDELAY (0x07 << 16) +#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15) +#define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8) +#define MANTIS_GPIF_DEVTYPE (0x07 << 4) +#define MANTIS_GPIF_BIGENDIAN (0x01 << 3) +#define MANTIS_GPIF_FETCHCMD (0x03 << 1) +#define MANTIS_GPIF_HWORDDEV (0x01 << 0) + +#define MANTIS_GPIF_WSTOPER 0x90 +#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31) +#define MANTIS_GPIF_PARBOOTN (0x01 << 29) +#define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24) +#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23) +#define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16) +#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15) +#define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8) +#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7) +#define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0) + +#define MANTIS_GPIF_CS2RW 0x94 +#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31) +#define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24) +#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23) +#define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16) +#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15) +#define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8) +#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7) +#define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0) + +#define MANTIS_GPIF_IRQCFG 0x98 +#define MANTIS_GPIF_IRQPOL (0x01 << 8) +#define MANTIS_MASK_WRACK (0x01 << 7) +#define MANTIS_MASK_BRRDY (0x01 << 6) +#define MANTIS_MASK_OVFLW (0x01 << 5) +#define MANTIS_MASK_OTHERR (0x01 << 4) +#define MANTIS_MASK_WSTO (0x01 << 3) +#define MANTIS_MASK_EXTIRQ (0x01 << 2) +#define MANTIS_MASK_PLUGIN (0x01 << 1) +#define MANTIS_MASK_PLUGOUT (0x01 << 0) + +#define MANTIS_GPIF_STATUS 0x9c +#define MANTIS_SBUF_KILLOP (0x01 << 15) +#define MANTIS_SBUF_OPDONE (0x01 << 14) +#define MANTIS_SBUF_EMPTY (0x01 << 13) +#define MANTIS_GPIF_DETSTAT (0x01 << 9) +#define MANTIS_GPIF_INTSTAT (0x01 << 8) +#define MANTIS_GPIF_WRACK (0x01 << 7) +#define MANTIS_GPIF_BRRDY (0x01 << 6) +#define MANTIS_SBUF_OVFLW (0x01 << 5) +#define MANTIS_GPIF_OTHERR (0x01 << 4) +#define MANTIS_SBUF_WSTO (0x01 << 3) +#define MANTIS_GPIF_EXTIRQ (0x01 << 2) +#define MANTIS_CARD_PLUGIN (0x01 << 1) +#define MANTIS_CARD_PLUGOUT (0x01 << 0) + +#define MANTIS_GPIF_BRADDR 0xa0 +#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) +#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_BR_ADDR (0xfffffff << 0) + +#define MANTIS_GPIF_BRBYTES 0xa4 +#define MANTIS_GPIF_BRCNT (0xfff << 0) + +#define MANTIS_PCMCIA_RESET 0xa8 +#define MANTIS_PCMCIA_RSTVAL (0xff << 0) + +#define MANTIS_CARD_RESET 0xac + +#define MANTIS_GPIF_ADDR 0xb0 +#define MANTIS_GPIF_HIFRDWRN (0x01 << 31) +#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) +#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_HIFADDR (0xfffffff << 0) + +#define MANTIS_GPIF_DOUT 0xb4 +#define MANTIS_GPIF_HIFDOUT (0xfffffff << 0) + +#define MANTIS_GPIF_DIN 0xb8 +#define MANTIS_GPIF_HIFDIN (0xfffffff << 0) + +#define MANTIS_GPIF_SPARE 0xbc +#define MANTIS_GPIF_LOGICRD (0xffff << 16) +#define MANTIS_GPIF_LOGICRW (0xffff << 0) + +#endif /* __MANTIS_REG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_uart.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_uart.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_uart.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_uart.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,187 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_uart.h" + +struct mantis_uart_params { + enum mantis_baud baud_rate; + enum mantis_parity parity; +}; + +static struct { + char string[7]; +} rates[5] = { + { "9600" }, + { "19200" }, + { "38400" }, + { "57600" }, + { "115200" } +}; + +static struct { + char string[5]; +} parity[3] = { + { "NONE" }, + { "ODD" }, + { "EVEN" } +}; + +#define UART_MAX_BUF 16 + +int mantis_uart_read(struct mantis_pci *mantis, u8 *data) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + u32 stat = 0, i; + + /* get data */ + for (i = 0; i < (config->bytes + 1); i++) { + + stat = mmread(MANTIS_UART_STAT); + + if (stat & MANTIS_UART_RXFIFO_FULL) { + dprintk(MANTIS_ERROR, 1, "RX Fifo FULL"); + } + data[i] = mmread(MANTIS_UART_RXD) & 0x3f; + + dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f); + + if (data[i] & (1 << 7)) { + dprintk(MANTIS_ERROR, 1, "UART framing error"); + return -EINVAL; + } + if (data[i] & (1 << 6)) { + dprintk(MANTIS_ERROR, 1, "UART parity error"); + return -EINVAL; + } + } + + return 0; +} + +static void mantis_uart_work(struct work_struct *work) +{ + struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work); + struct mantis_hwconfig *config = mantis->hwconfig; + u8 buf[16]; + int i; + + mantis_uart_read(mantis, buf); + + for (i = 0; i < (config->bytes + 1); i++) + dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]); + + dprintk(MANTIS_DEBUG, 0, "\n"); +} + +static int mantis_uart_setup(struct mantis_pci *mantis, + struct mantis_uart_params *params) +{ + u32 reg; + + mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL); + + reg = mmread(MANTIS_UART_BAUD); + + switch (params->baud_rate) { + case MANTIS_BAUD_9600: + reg |= 0xd8; + break; + case MANTIS_BAUD_19200: + reg |= 0x6c; + break; + case MANTIS_BAUD_38400: + reg |= 0x36; + break; + case MANTIS_BAUD_57600: + reg |= 0x23; + break; + case MANTIS_BAUD_115200: + reg |= 0x11; + break; + default: + return -EINVAL; + } + + mmwrite(reg, MANTIS_UART_BAUD); + + return 0; +} + +int mantis_uart_init(struct mantis_pci *mantis) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + struct mantis_uart_params params; + + /* default parity: */ + params.baud_rate = config->baud_rate; + params.parity = config->parity; + dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s", + rates[params.baud_rate].string, + parity[params.parity].string); + + init_waitqueue_head(&mantis->uart_wq); + spin_lock_init(&mantis->uart_lock); + + INIT_WORK(&mantis->uart_work, mantis_uart_work); + + /* disable interrupt */ + mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); + + mantis_uart_setup(mantis, ¶ms); + + /* default 1 byte */ + mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD); + + /* flush buffer */ + mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL); + + /* enable interrupt */ + mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK); + mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL); + + schedule_work(&mantis->uart_work); + dprintk(MANTIS_DEBUG, 1, "UART successfully initialized"); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_uart_init); + +void mantis_uart_exit(struct mantis_pci *mantis) +{ + /* disable interrupt */ + mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); + flush_work_sync(&mantis->uart_work); +} +EXPORT_SYMBOL_GPL(mantis_uart_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_uart.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_uart.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_uart.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_uart.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,58 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_UART_H +#define __MANTIS_UART_H + +#define MANTIS_UART_CTL 0xe0 +#define MANTIS_UART_RXINT (1 << 4) +#define MANTIS_UART_RXFLUSH (1 << 2) + +#define MANTIS_UART_RXD 0xe8 +#define MANTIS_UART_BAUD 0xec + +#define MANTIS_UART_STAT 0xf0 +#define MANTIS_UART_RXFIFO_DATA (1 << 7) +#define MANTIS_UART_RXFIFO_EMPTY (1 << 6) +#define MANTIS_UART_RXFIFO_FULL (1 << 3) +#define MANTIS_UART_FRAME_ERR (1 << 2) +#define MANTIS_UART_PARITY_ERR (1 << 1) +#define MANTIS_UART_RXTHRESH_INT (1 << 0) + +enum mantis_baud { + MANTIS_BAUD_9600 = 0, + MANTIS_BAUD_19200, + MANTIS_BAUD_38400, + MANTIS_BAUD_57600, + MANTIS_BAUD_115200 +}; + +enum mantis_parity { + MANTIS_PARITY_NONE = 0, + MANTIS_PARITY_EVEN, + MANTIS_PARITY_ODD, +}; + +struct mantis_pci; + +extern int mantis_uart_init(struct mantis_pci *mantis); +extern void mantis_uart_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_UART_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1033.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1033.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1033.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1033.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,212 @@ +/* + Mantis VP-1033 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "stv0299.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1033.h" +#include "mantis_reg.h" + +u8 lgtdqcs001f_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x2a, + 0x05, 0x85, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0x00, + 0x0c, 0x01, + 0x0d, 0x81, + 0x0e, 0x44, + 0x0f, 0x94, + 0x10, 0x3c, + 0x11, 0x84, + 0x12, 0xb9, + 0x13, 0xb5, + 0x14, 0x4f, + 0x15, 0xc9, + 0x16, 0x80, + 0x17, 0x36, + 0x18, 0xfb, + 0x19, 0xcf, + 0x1a, 0xbc, + 0x1c, 0x2b, + 0x1d, 0x27, + 0x1e, 0x00, + 0x1f, 0x0b, + 0x20, 0xa1, + 0x21, 0x60, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, + 0x29, 0x28, + 0x2a, 0x14, + 0x2b, 0x0f, + 0x2c, 0x09, + 0x2d, 0x05, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x13, + 0xff, 0xff, +}; + +#define MANTIS_MODEL_NAME "VP-1033" +#define MANTIS_DEV_TYPE "DVB-S/DSS" + +int lgtdqcs001f_tuner_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mantis_pci *mantis = fe->dvb->priv; + struct i2c_adapter *adapter = &mantis->adapter; + + u8 buf[4]; + u32 div; + + + struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)}; + + div = params->frequency / 250; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x83; + buf[3] = 0xc0; + + if (params->frequency < 1531000) + buf[3] |= 0x04; + else + buf[3] &= ~0x04; + if (i2c_transfer(adapter, &msg, 1) < 0) { + dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed"); + return -EIO; + } + msleep_interruptible(100); + + return 0; +} + +int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; + bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; + bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; + bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; + bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; + bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; + bclk = 0x51; + } + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, ratio & 0xf0); + + return 0; +} + +struct stv0299_config lgtdqcs001f_config = { + .demod_address = 0x68, + .inittab = lgtdqcs001f_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = lgtdqcs001f_set_symbol_rate, +}; + +static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)"); + fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter); + + if (fe) { + fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set; + dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x", + lgtdqcs001f_config.demod_address); + + dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success"); + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + mantis->fe = fe; + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp1033_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp1033_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1033.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1033.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1033.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1033.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + Mantis VP-1033 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP1033_H +#define __MANTIS_VP1033_H + +#include "mantis_common.h" + +#define MANTIS_VP_1033_DVB_S 0x0016 + +extern struct mantis_hwconfig vp1033_config; + +#endif /* __MANTIS_VP1033_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1034.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1034.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1034.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1034.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,119 @@ +/* + Mantis VP-1034 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mb86a16.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1034.h" +#include "mantis_reg.h" + +struct mb86a16_config vp1034_mb86a16_config = { + .demod_address = 0x08, + .set_voltage = vp1034_set_voltage, +}; + +#define MANTIS_MODEL_NAME "VP-1034" +#define MANTIS_DEV_TYPE "DVB-S/DSS" + +int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct mantis_pci *mantis = fe->dvb->priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk(MANTIS_ERROR, 1, "Polarization=[13V]"); + mantis_gpio_set_bits(mantis, 13, 1); + mantis_gpio_set_bits(mantis, 14, 0); + break; + case SEC_VOLTAGE_18: + dprintk(MANTIS_ERROR, 1, "Polarization=[18V]"); + mantis_gpio_set_bits(mantis, 13, 1); + mantis_gpio_set_bits(mantis, 14, 1); + break; + case SEC_VOLTAGE_OFF: + dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN"); + break; + default: + dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage); + return -EINVAL; + } + mmwrite(0x00, MANTIS_GPIF_DOUT); + + return 0; +} + +static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)"); + fe = dvb_attach(mb86a16_attach, &vp1034_mb86a16_config, adapter); + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found MB86A16 DVB-S/DSS frontend @0x%02x", + vp1034_mb86a16_config.demod_address); + + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + mantis->fe = fe; + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp1034_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp1034_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1034.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1034.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1034.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1034.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Mantis VP-1034 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP1034_H +#define __MANTIS_VP1034_H + +#include "dvb_frontend.h" +#include "mantis_common.h" + + +#define MANTIS_VP_1034_DVB_S 0x0014 + +extern struct mantis_hwconfig vp1034_config; +extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + +#endif /* __MANTIS_VP1034_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1041.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1041.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1041.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1041.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,358 @@ +/* + Mantis VP-1041 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1041.h" +#include "stb0899_reg.h" +#include "stb0899_drv.h" +#include "stb0899_cfg.h" +#include "stb6100_cfg.h" +#include "stb6100.h" +#include "lnbp21.h" + +#define MANTIS_MODEL_NAME "VP-1041" +#define MANTIS_DEV_TYPE "DSS/DVB-S/DVB-S2" + +static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = { + + /* 0x0000000b, *//* SYSREG */ + { STB0899_DEV_ID , 0x30 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISFIFO , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x99 }, + { STB0899_DISF22RX , 0xa8 }, + /* SYSREG ? */ + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0xfe }, + { STB0899_IRQSTATUS_2 , 0x03 }, + { STB0899_IRQSTATUS_1 , 0x7c }, + { STB0899_IRQSTATUS_0 , 0xf4 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x58 }, + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x33 }, + { STB0899_IOPVALUE3 , 0x6d }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x60 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x01 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x01 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x23 }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xf7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xf1 }, + { STB0899_LDT2 , 0xe3 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfd }, + { STB0899_QDCCOMP , 0xff }, + { STB0899_POWERI , 0x0c }, + { STB0899_POWERQ , 0x0f }, + { STB0899_RCOMP , 0x6c }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x06 }, + { STB0899_AGC2I2 , 0x00 }, + { STB0899_TLIR , 0x30 }, + { STB0899_RTF , 0x7f }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xbc }, + { STB0899_CFRM , 0xea }, + { STB0899_CFRL , 0x31 }, + { STB0899_NIRM , 0x2b }, + { STB0899_NIRL , 0x80 }, + { STB0899_ISYMB , 0x1d }, + { STB0899_QSYMB , 0xa6 }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0x02 }, + { STB0899_EQUAQ1 , 0xff }, + { STB0899_EQUAI2 , 0x04 }, + { STB0899_EQUAQ2 , 0x05 }, + { STB0899_EQUAI3 , 0x02 }, + { STB0899_EQUAQ3 , 0xfd }, + { STB0899_EQUAI4 , 0x03 }, + { STB0899_EQUAQ4 , 0x07 }, + { STB0899_EQUAI5 , 0x08 }, + { STB0899_EQUAQ5 , 0xf5 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0x86 }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x0a }, + { STB0899_ECNT3L , 0xad }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xb0 }, + { STB0899_VTH23 , 0x7a }, + { STB0899_VTH34 , 0x58 }, + { STB0899_VTH56 , 0x38 }, + { STB0899_VTH67 , 0x34 }, + { STB0899_VTH78 , 0x24 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x41 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x00 }, + { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x1b }, + { STB0899_TSLLSTKL , 0xb3 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0x00 }, + { STB0899_PCKLENUL , 0xbc }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xbd }, + { STB0899_TSSTATUS , 0x90 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x95 }, + { STB0899_ERRCTRL3 , 0x8d }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x19 }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0xf0 }, + { STB0899_MATSTRL , 0x02 }, + { STB0899_UPLSTRM , 0x45 }, + { STB0899_UPLSTRL , 0x60 }, + { STB0899_DFLSTRM , 0xe3 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x47 }, + { STB0899_SYNCDSTRM , 0x05 }, + { STB0899_SYNCDSTRL , 0x18 }, + { STB0899_CFGPDELSTATUS1 , 0x19 }, + { STB0899_CFGPDELSTATUS2 , 0x2b }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x01 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + +struct stb0899_config vp1041_stb0899_config = { + .init_dev = vp1041_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = vp1041_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .demod_address = 0x68, /* 0xd0 >> 1 */ + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_ON, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL, +}; + +struct stb6100_config vp1041_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + mantis->fe = dvb_attach(stb0899_attach, &vp1041_stb0899_config, adapter); + if (mantis->fe) { + dprintk(MANTIS_ERROR, 1, + "found STB0899 DVB-S/DVB-S2 frontend @0x%02x", + vp1041_stb0899_config.demod_address); + + if (dvb_attach(stb6100_attach, mantis->fe, &vp1041_stb6100_config, adapter)) { + if (!dvb_attach(lnbp21_attach, mantis->fe, adapter, 0, 0)) + dprintk(MANTIS_ERROR, 1, "No LNBP21 found!"); + } + } else { + return -EREMOTEIO; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + + + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp1041_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp1041_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1041.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1041.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1041.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp1041.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Mantis VP-1041 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP1041_H +#define __MANTIS_VP1041_H + +#include "mantis_common.h" + +#define MANTIS_VP_1041_DVB_S2 0x0031 +#define SKYSTAR_HD2_10 0x0001 +#define SKYSTAR_HD2_20 0x0003 +#define CINERGY_S2_PCI_HD 0x1179 + +extern struct mantis_hwconfig vp1041_config; + +#endif /* __MANTIS_VP1041_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2033.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2033.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2033.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2033.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,187 @@ +/* + Mantis VP-2033 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "tda1002x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp2033.h" + +#define MANTIS_MODEL_NAME "VP-2033" +#define MANTIS_DEV_TYPE "DVB-C" + +struct tda1002x_config vp2033_tda1002x_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +struct tda10023_config vp2033_tda10023_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +static u8 read_pwm(struct mantis_pci *mantis) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { + {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, + {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} + }; + + if ((i2c_transfer(adapter, msg, 2) != 2) + || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mantis_pci *mantis = fe->dvb->priv; + struct i2c_adapter *adapter = &mantis->adapter; + + u8 buf[6]; + struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; + int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + + u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0xce; + buf[3] = (params->frequency < 150000000 ? 0x01 : + params->frequency < 445000000 ? 0x02 : 0x04); + buf[4] = 0xde; + buf[5] = 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + /* wait for the pll lock */ + msg.flags = I2C_M_RD; + msg.len = 1; + for (i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) + break; + + msleep(10); + } + + /* switch the charge pump to the lower current */ + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[2]; + buf[2] &= ~0x40; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); + fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", + vp2033_tda1002x_cu1216_config.demod_address); + } else { + fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", + vp2033_tda1002x_cu1216_config.demod_address); + } + } + + if (fe) { + fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; + dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + + mantis->fe = fe; + dprintk(MANTIS_DEBUG, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp2033_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp2033_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2033.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2033.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2033.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2033.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + Mantis VP-2033 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP2033_H +#define __MANTIS_VP2033_H + +#include "mantis_common.h" + +#define MANTIS_VP_2033_DVB_C 0x0008 + +extern struct mantis_hwconfig vp2033_config; + +#endif /* __MANTIS_VP2033_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2040.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2040.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2040.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2040.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,186 @@ +/* + Mantis VP-2040 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "tda1002x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp2040.h" + +#define MANTIS_MODEL_NAME "VP-2040" +#define MANTIS_DEV_TYPE "DVB-C" + +struct tda1002x_config vp2040_tda1002x_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +struct tda10023_config vp2040_tda10023_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mantis_pci *mantis = fe->dvb->priv; + struct i2c_adapter *adapter = &mantis->adapter; + + u8 buf[6]; + struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; + int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + + u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0xce; + buf[3] = (params->frequency < 150000000 ? 0x01 : + params->frequency < 445000000 ? 0x02 : 0x04); + buf[4] = 0xde; + buf[5] = 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + /* wait for the pll lock */ + msg.flags = I2C_M_RD; + msg.len = 1; + for (i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) + break; + + msleep(10); + } + + /* switch the charge pump to the lower current */ + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[2]; + buf[2] &= ~0x40; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static u8 read_pwm(struct mantis_pci *mantis) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { + {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, + {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} + }; + + if ((i2c_transfer(adapter, msg, 2) != 2) + || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); + fe = dvb_attach(tda10021_attach, &vp2040_tda1002x_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", + vp2040_tda1002x_cu1216_config.demod_address); + } else { + fe = dvb_attach(tda10023_attach, &vp2040_tda10023_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", + vp2040_tda1002x_cu1216_config.demod_address); + } + } + + if (fe) { + fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; + dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + mantis->fe = fe; + dprintk(MANTIS_DEBUG, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp2040_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp2040_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2040.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2040.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2040.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp2040.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,32 @@ +/* + Mantis VP-2040 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP2040_H +#define __MANTIS_VP2040_H + +#include "mantis_common.h" + +#define MANTIS_VP_2040_DVB_C 0x0043 +#define CINERGY_C 0x1178 +#define CABLESTAR_HD2 0x0002 + +extern struct mantis_hwconfig vp2040_config; + +#endif /* __MANTIS_VP2040_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3028.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3028.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3028.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3028.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,38 @@ +/* + Mantis VP-3028 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "mantis_common.h" +#include "mantis_vp3028.h" + +struct zl10353_config mantis_vp3028_config = { + .demod_address = 0x0f, +}; + +#define MANTIS_MODEL_NAME "VP-3028" +#define MANTIS_DEV_TYPE "DVB-T" + +struct mantis_hwconfig vp3028_mantis_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3028.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3028.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3028.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3028.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Mantis VP-3028 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP3028_H +#define __MANTIS_VP3028_H + +#include "dvb_frontend.h" +#include "mantis_common.h" +#include "zl10353.h" + +#define MANTIS_VP_3028_DVB_T 0x0028 + +extern struct zl10353_config mantis_vp3028_config; +extern struct mantis_hwconfig vp3028_mantis_config; + +#endif /* __MANTIS_VP3028_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3030.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3030.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3030.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3030.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,105 @@ +/* + Mantis VP-3030 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "zl10353.h" +#include "tda665x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp3030.h" + +struct zl10353_config mantis_vp3030_config = { + .demod_address = 0x0f, +}; + +struct tda665x_config env57h12d5_config = { + .name = "ENV57H12D5 (ET-50DT)", + .addr = 0x60, + .frequency_min = 47000000, + .frequency_max = 862000000, + .frequency_offst = 3616667, + .ref_multiplier = 6, /* 1/6 MHz */ + .ref_divider = 100000, /* 1/6 MHz */ +}; + +#define MANTIS_MODEL_NAME "VP-3030" +#define MANTIS_DEV_TYPE "DVB-T" + + +static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + struct mantis_hwconfig *config = mantis->hwconfig; + int err = 0; + + mantis_gpio_set_bits(mantis, config->reset, 0); + msleep(100); + err = mantis_frontend_power(mantis, POWER_ON); + msleep(100); + mantis_gpio_set_bits(mantis, config->reset, 1); + + if (err == 0) { + msleep(250); + dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); + fe = dvb_attach(zl10353_attach, &mantis_vp3030_config, adapter); + + if (!fe) + return -1; + + dvb_attach(tda665x_attach, fe, &env57h12d5_config, adapter); + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + + } + mantis->fe = fe; + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp3030_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp3030_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, + + .i2c_mode = MANTIS_BYTE_MODE +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3030.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3030.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3030.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/mantis/mantis_vp3030.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + Mantis VP-3030 driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MANTIS_VP3030_H +#define __MANTIS_VP3030_H + +#include "mantis_common.h" + +#define MANTIS_VP_3030_DVB_T 0x0024 + +extern struct mantis_hwconfig vp3030_config; + +#endif /* __MANTIS_VP3030_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,11 @@ +config DVB_NGENE + tristate "Micronas nGene support" + depends on DVB_CORE && PCI && I2C + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE + ---help--- + Support for Micronas PCI express cards with nGene bridge. + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,14 @@ +# +# Makefile for the nGene device driver +# + +ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o + +obj-$(CONFIG_DVB_NGENE) += ngene.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ + +# For the staging CI driver cxd2099 +EXTRA_CFLAGS += -Idrivers/staging/cxd2099/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-cards.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,460 @@ +/* + * ngene-cards.c: nGene PCIe bridge driver - card specific info + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include + +#include "ngene.h" + +/* demods/tuners */ +#include "stv6110x.h" +#include "stv090x.h" +#include "lnbh24.h" +#include "lgdt330x.h" +#include "mt2131.h" + + +/****************************************************************************/ +/* Demod/tuner attachment ***************************************************/ +/****************************************************************************/ + +static int tuner_attach_stv6110(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *feconf = (struct stv090x_config *) + chan->dev->card_info->fe_config[chan->number]; + struct stv6110x_config *tunerconf = (struct stv6110x_config *) + chan->dev->card_info->tuner_config[chan->number]; + struct stv6110x_devctl *ctl; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); + if (ctl == NULL) { + printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); + return -ENODEV; + } + + feconf->tuner_init = ctl->tuner_init; + feconf->tuner_sleep = ctl->tuner_sleep; + feconf->tuner_set_mode = ctl->tuner_set_mode; + feconf->tuner_set_frequency = ctl->tuner_set_frequency; + feconf->tuner_get_frequency = ctl->tuner_get_frequency; + feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; + feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; + feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; + feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; + feconf->tuner_set_refclk = ctl->tuner_set_refclk; + feconf->tuner_get_status = ctl->tuner_get_status; + + return 0; +} + + +static int demod_attach_stv0900(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *feconf = (struct stv090x_config *) + chan->dev->card_info->fe_config[chan->number]; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + /* Note: Both adapters share the same i2c bus, but the demod */ + /* driver requires that each demod has its own i2c adapter */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + chan->fe = dvb_attach(stv090x_attach, feconf, i2c, + (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 + : STV090x_DEMODULATOR_1); + if (chan->fe == NULL) { + printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); + return -ENODEV; + } + + /* store channel info */ + if (feconf->tuner_i2c_lock) + chan->fe->analog_demod_priv = chan; + + if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, + 0, chan->dev->card_info->lnb[chan->number])) { + printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + return -ENODEV; + } + + return 0; +} + +static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) +{ + struct ngene_channel *chan = fe->analog_demod_priv; + + if (lock) + down(&chan->dev->pll_mutex); + else + up(&chan->dev->pll_mutex); +} + +static int cineS2_probe(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *fe_conf; + u8 buf[3]; + struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; + int rc; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + fe_conf = chan->dev->card_info->fe_config[chan->number]; + i2c_msg.addr = fe_conf->address; + + /* probe demod */ + i2c_msg.len = 2; + buf[0] = 0xf1; + buf[1] = 0x00; + rc = i2c_transfer(i2c, &i2c_msg, 1); + if (rc != 1) + return -ENODEV; + + /* demod found, attach it */ + rc = demod_attach_stv0900(chan); + if (rc < 0 || chan->number < 2) + return rc; + + /* demod #2: reprogram outputs DPN1 & DPN2 */ + i2c_msg.len = 3; + buf[0] = 0xf1; + switch (chan->number) { + case 2: + buf[1] = 0x5c; + buf[2] = 0xc2; + break; + case 3: + buf[1] = 0x61; + buf[2] = 0xcc; + break; + default: + return -ENODEV; + } + rc = i2c_transfer(i2c, &i2c_msg, 1); + if (rc != 1) { + printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); + return -EIO; + } + + return 0; +} + + +static struct lgdt330x_config aver_m780 = { + .demod_address = 0xb2 >> 1, + .demod_chip = LGDT3303, + .serial_mpeg = 0x00, /* PARALLEL */ + .clock_polarity_flip = 1, +}; + +static struct mt2131_config m780_tunerconfig = { + 0xc0 >> 1 +}; + +/* A single func to attach the demo and tuner, rather than + * use two sep funcs like the current design mandates. + */ +static int demod_attach_lg330x(struct ngene_channel *chan) +{ + chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter); + if (chan->fe == NULL) { + printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n"); + return -ENODEV; + } + + dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter, + &m780_tunerconfig, 0); + + return (chan->fe) ? 0 : -ENODEV; +} + +/****************************************************************************/ +/* Switch control (I2C gates, etc.) *****************************************/ +/****************************************************************************/ + + +static struct stv090x_config fe_cineS2 = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, + + .tuner_i2c_lock = cineS2_tuner_i2c_lock, +}; + +static struct stv090x_config fe_cineS2_2 = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x69, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, + + .tuner_i2c_lock = cineS2_tuner_i2c_lock, +}; + +static struct stv6110x_config tuner_cineS2_0 = { + .addr = 0x60, + .refclk = 27000000, + .clk_div = 1, +}; + +static struct stv6110x_config tuner_cineS2_1 = { + .addr = 0x63, + .refclk = 27000000, + .clk_div = 1, +}; + +static struct ngene_info ngene_info_cineS2 = { + .type = NGENE_SIDEWINDER, + .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0b, 0x08}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_satixS2 = { + .type = NGENE_SIDEWINDER, + .name = "Mystique SaTiX-S2 Dual", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0b, 0x08}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_satixS2v2 = { + .type = NGENE_SIDEWINDER, + .name = "Mystique SaTiX-S2 Dual (v2)", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_cineS2v5 = { + .type = NGENE_SIDEWINDER, + .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + + +static struct ngene_info ngene_info_duoFlexS2 = { + .type = NGENE_SIDEWINDER, + .name = "Digital Devices DuoFlex S2 miniPCIe", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, + .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, + .tsf = {3, 3}, + .fw_version = 18, + .msi_supported = true, +}; + +static struct ngene_info ngene_info_m780 = { + .type = NGENE_APP, + .name = "Aver M780 ATSC/QAM-B", + + /* Channel 0 is analog, which is currently unsupported */ + .io_type = { NGENE_IO_NONE, NGENE_IO_TSIN }, + .demod_attach = { NULL, demod_attach_lg330x }, + + /* Ensure these are NULL else the frame will call them (as funcs) */ + .tuner_attach = { 0, 0, 0, 0 }, + .fe_config = { NULL, &aver_m780 }, + .avf = { 0 }, + + /* A custom electrical interface config for the demod to bridge */ + .tsf = { 4, 4 }, + .fw_version = 15, +}; + +/****************************************************************************/ + + + +/****************************************************************************/ +/* PCI Subsystem ID *********************************************************/ +/****************************************************************************/ + +#define NGENE_ID(_subvend, _subdev, _driverdata) { \ + .vendor = NGENE_VID, .device = NGENE_PID, \ + .subvendor = _subvend, .subdevice = _subdev, \ + .driver_data = (unsigned long) &_driverdata } + +/****************************************************************************/ + +static const struct pci_device_id ngene_id_tbl[] __devinitdata = { + NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), + NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), + NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), + NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2), + NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2), + NGENE_ID(0x1461, 0x062e, ngene_info_m780), + {0} +}; +MODULE_DEVICE_TABLE(pci, ngene_id_tbl); + +/****************************************************************************/ +/* Init/Exit ****************************************************************/ +/****************************************************************************/ + +static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, + enum pci_channel_state state) +{ + printk(KERN_ERR DEVICE_NAME ": PCI error\n"); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (state == pci_channel_io_frozen) + return PCI_ERS_RESULT_NEED_RESET; + return PCI_ERS_RESULT_CAN_RECOVER; +} + +static pci_ers_result_t ngene_link_reset(struct pci_dev *dev) +{ + printk(KERN_INFO DEVICE_NAME ": link reset\n"); + return 0; +} + +static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) +{ + printk(KERN_INFO DEVICE_NAME ": slot reset\n"); + return 0; +} + +static void ngene_resume(struct pci_dev *dev) +{ + printk(KERN_INFO DEVICE_NAME ": resume\n"); +} + +static struct pci_error_handlers ngene_errors = { + .error_detected = ngene_error_detected, + .link_reset = ngene_link_reset, + .slot_reset = ngene_slot_reset, + .resume = ngene_resume, +}; + +static struct pci_driver ngene_pci_driver = { + .name = "ngene", + .id_table = ngene_id_tbl, + .probe = ngene_probe, + .remove = __devexit_p(ngene_remove), + .err_handler = &ngene_errors, + .shutdown = ngene_shutdown, +}; + +static __init int module_init_ngene(void) +{ + printk(KERN_INFO + "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); + return pci_register_driver(&ngene_pci_driver); +} + +static __exit void module_exit_ngene(void) +{ + pci_unregister_driver(&ngene_pci_driver); +} + +module_init(module_init_ngene); +module_exit(module_exit_ngene); + +MODULE_DESCRIPTION("nGene"); +MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1697 @@ +/* + * ngene.c: nGene PCIe bridge driver + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngene.h" + +static int one_adapter = 1; +module_param(one_adapter, int, 0444); +MODULE_PARM_DESC(one_adapter, "Use only one adapter."); + +static int shutdown_workaround; +module_param(shutdown_workaround, int, 0644); +MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets."); + +static int debug; +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "Print debugging information."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk if (debug) printk + +#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) +#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr))) +#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) +#define ngreadl(adr) readl(dev->iomem + (adr)) +#define ngreadb(adr) readb(dev->iomem + (adr)) +#define ngcpyto(adr, src, count) memcpy_toio((char *) \ + (dev->iomem + (adr)), (src), (count)) +#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \ + (dev->iomem + (adr)), (count)) + +/****************************************************************************/ +/* nGene interrupt handler **************************************************/ +/****************************************************************************/ + +static void event_tasklet(unsigned long data) +{ + struct ngene *dev = (struct ngene *)data; + + while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { + struct EVENT_BUFFER Event = + dev->EventQueue[dev->EventQueueReadIndex]; + dev->EventQueueReadIndex = + (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1); + + if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify)) + dev->TxEventNotify(dev, Event.TimeStamp); + if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify)) + dev->RxEventNotify(dev, Event.TimeStamp, + Event.RXCharacter); + } +} + +static void demux_tasklet(unsigned long data) +{ + struct ngene_channel *chan = (struct ngene_channel *)data; + struct SBufferHeader *Cur = chan->nextBuffer; + + spin_lock_irq(&chan->state_lock); + + while (Cur->ngeneBuffer.SR.Flags & 0x80) { + if (chan->mode & NGENE_IO_TSOUT) { + u32 Flags = chan->DataFormatFlags; + if (Cur->ngeneBuffer.SR.Flags & 0x20) + Flags |= BEF_OVERFLOW; + if (chan->pBufferExchange) { + if (!chan->pBufferExchange(chan, + Cur->Buffer1, + chan->Capture1Length, + Cur->ngeneBuffer.SR. + Clock, Flags)) { + /* + We didn't get data + Clear in service flag to make sure we + get called on next interrupt again. + leave fill/empty (0x80) flag alone + to avoid hardware running out of + buffers during startup, we hold only + in run state ( the source may be late + delivering data ) + */ + + if (chan->HWState == HWSTATE_RUN) { + Cur->ngeneBuffer.SR.Flags &= + ~0x40; + break; + /* Stop processing stream */ + } + } else { + /* We got a valid buffer, + so switch to run state */ + chan->HWState = HWSTATE_RUN; + } + } else { + printk(KERN_ERR DEVICE_NAME ": OOPS\n"); + if (chan->HWState == HWSTATE_RUN) { + Cur->ngeneBuffer.SR.Flags &= ~0x40; + break; /* Stop processing stream */ + } + } + if (chan->AudioDTOUpdated) { + printk(KERN_INFO DEVICE_NAME + ": Update AudioDTO = %d\n", + chan->AudioDTOValue); + Cur->ngeneBuffer.SR.DTOUpdate = + chan->AudioDTOValue; + chan->AudioDTOUpdated = 0; + } + } else { + if (chan->HWState == HWSTATE_RUN) { + u32 Flags = chan->DataFormatFlags; + IBufferExchange *exch1 = chan->pBufferExchange; + IBufferExchange *exch2 = chan->pBufferExchange2; + if (Cur->ngeneBuffer.SR.Flags & 0x01) + Flags |= BEF_EVEN_FIELD; + if (Cur->ngeneBuffer.SR.Flags & 0x20) + Flags |= BEF_OVERFLOW; + spin_unlock_irq(&chan->state_lock); + if (exch1) + exch1(chan, Cur->Buffer1, + chan->Capture1Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + if (exch2) + exch2(chan, Cur->Buffer2, + chan->Capture2Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + spin_lock_irq(&chan->state_lock); + } else if (chan->HWState != HWSTATE_STOP) + chan->HWState = HWSTATE_RUN; + } + Cur->ngeneBuffer.SR.Flags = 0x00; + Cur = Cur->Next; + } + chan->nextBuffer = Cur; + + spin_unlock_irq(&chan->state_lock); +} + +static irqreturn_t irq_handler(int irq, void *dev_id) +{ + struct ngene *dev = (struct ngene *)dev_id; + u32 icounts = 0; + irqreturn_t rc = IRQ_NONE; + u32 i = MAX_STREAM; + u8 *tmpCmdDoneByte; + + if (dev->BootFirmware) { + icounts = ngreadl(NGENE_INT_COUNTS); + if (icounts != dev->icounts) { + ngwritel(0, FORCE_NMI); + dev->cmd_done = 1; + wake_up(&dev->cmd_wq); + dev->icounts = icounts; + rc = IRQ_HANDLED; + } + return rc; + } + + ngwritel(0, FORCE_NMI); + + spin_lock(&dev->cmd_lock); + tmpCmdDoneByte = dev->CmdDoneByte; + if (tmpCmdDoneByte && + (*tmpCmdDoneByte || + (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) { + dev->CmdDoneByte = NULL; + dev->cmd_done = 1; + wake_up(&dev->cmd_wq); + rc = IRQ_HANDLED; + } + spin_unlock(&dev->cmd_lock); + + if (dev->EventBuffer->EventStatus & 0x80) { + u8 nextWriteIndex = + (dev->EventQueueWriteIndex + 1) & + (EVENT_QUEUE_SIZE - 1); + if (nextWriteIndex != dev->EventQueueReadIndex) { + dev->EventQueue[dev->EventQueueWriteIndex] = + *(dev->EventBuffer); + dev->EventQueueWriteIndex = nextWriteIndex; + } else { + printk(KERN_ERR DEVICE_NAME ": event overflow\n"); + dev->EventQueueOverflowCount += 1; + dev->EventQueueOverflowFlag = 1; + } + dev->EventBuffer->EventStatus &= ~0x80; + tasklet_schedule(&dev->event_tasklet); + rc = IRQ_HANDLED; + } + + while (i > 0) { + i--; + spin_lock(&dev->channel[i].state_lock); + /* if (dev->channel[i].State>=KSSTATE_RUN) { */ + if (dev->channel[i].nextBuffer) { + if ((dev->channel[i].nextBuffer-> + ngeneBuffer.SR.Flags & 0xC0) == 0x80) { + dev->channel[i].nextBuffer-> + ngeneBuffer.SR.Flags |= 0x40; + tasklet_schedule( + &dev->channel[i].demux_tasklet); + rc = IRQ_HANDLED; + } + } + spin_unlock(&dev->channel[i].state_lock); + } + + /* Request might have been processed by a previous call. */ + return IRQ_HANDLED; +} + +/****************************************************************************/ +/* nGene command interface **************************************************/ +/****************************************************************************/ + +static void dump_command_io(struct ngene *dev) +{ + u8 buf[8], *b; + + ngcpyfrom(buf, HOST_TO_NGENE, 8); + printk(KERN_ERR "host_to_ngene (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n", + HOST_TO_NGENE, buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + ngcpyfrom(buf, NGENE_TO_HOST, 8); + printk(KERN_ERR "ngene_to_host (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n", + NGENE_TO_HOST, buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + b = dev->hosttongene; + printk(KERN_ERR "dev->hosttongene (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n", + b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); + + b = dev->ngenetohost; + printk(KERN_ERR "dev->ngenetohost (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n", + b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); +} + +static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) +{ + int ret; + u8 *tmpCmdDoneByte; + + dev->cmd_done = 0; + + if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) { + dev->BootFirmware = 1; + dev->icounts = ngreadl(NGENE_INT_COUNTS); + ngwritel(0, NGENE_COMMAND); + ngwritel(0, NGENE_COMMAND_HI); + ngwritel(0, NGENE_STATUS); + ngwritel(0, NGENE_STATUS_HI); + ngwritel(0, NGENE_EVENT); + ngwritel(0, NGENE_EVENT_HI); + } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) { + u64 fwio = dev->PAFWInterfaceBuffer; + + ngwritel(fwio & 0xffffffff, NGENE_COMMAND); + ngwritel(fwio >> 32, NGENE_COMMAND_HI); + ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS); + ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI); + ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT); + ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI); + } + + memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2); + + if (dev->BootFirmware) + ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2); + + spin_lock_irq(&dev->cmd_lock); + tmpCmdDoneByte = dev->ngenetohost + com->out_len; + if (!com->out_len) + tmpCmdDoneByte++; + *tmpCmdDoneByte = 0; + dev->ngenetohost[0] = 0; + dev->ngenetohost[1] = 0; + dev->CmdDoneByte = tmpCmdDoneByte; + spin_unlock_irq(&dev->cmd_lock); + + /* Notify 8051. */ + ngwritel(1, FORCE_INT); + + ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ); + if (!ret) { + /*ngwritel(0, FORCE_NMI);*/ + + printk(KERN_ERR DEVICE_NAME + ": Command timeout cmd=%02x prev=%02x\n", + com->cmd.hdr.Opcode, dev->prev_cmd); + dump_command_io(dev); + return -1; + } + if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) + dev->BootFirmware = 0; + + dev->prev_cmd = com->cmd.hdr.Opcode; + + if (!com->out_len) + return 0; + + memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len); + + return 0; +} + +int ngene_command(struct ngene *dev, struct ngene_command *com) +{ + int result; + + down(&dev->cmd_mutex); + result = ngene_command_mutex(dev, com); + up(&dev->cmd_mutex); + return result; +} + + +static int ngene_command_load_firmware(struct ngene *dev, + u8 *ngene_fw, u32 size) +{ +#define FIRSTCHUNK (1024) + u32 cleft; + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE; + com.cmd.hdr.Length = 0; + com.in_len = 0; + com.out_len = 0; + + ngene_command(dev, &com); + + cleft = (size + 3) & ~3; + if (cleft > FIRSTCHUNK) { + ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK, + cleft - FIRSTCHUNK); + cleft = FIRSTCHUNK; + } + ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft); + + memset(&com, 0, sizeof(struct ngene_command)); + com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH; + com.cmd.hdr.Length = 4; + com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA; + com.cmd.FWLoadFinish.Length = (unsigned short)cleft; + com.in_len = 4; + com.out_len = 0; + + return ngene_command(dev, &com); +} + + +static int ngene_command_config_buf(struct ngene *dev, u8 config) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER; + com.cmd.hdr.Length = 1; + com.cmd.ConfigureBuffers.config = config; + com.in_len = 1; + com.out_len = 0; + + if (ngene_command(dev, &com) < 0) + return -EIO; + return 0; +} + +static int ngene_command_config_free_buf(struct ngene *dev, u8 *config) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER; + com.cmd.hdr.Length = 6; + memcpy(&com.cmd.ConfigureBuffers.config, config, 6); + com.in_len = 6; + com.out_len = 0; + + if (ngene_command(dev, &com) < 0) + return -EIO; + + return 0; +} + +int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN; + com.cmd.hdr.Length = 1; + com.cmd.SetGpioPin.select = select | (level << 7); + com.in_len = 1; + com.out_len = 0; + + return ngene_command(dev, &com); +} + + +/* + 02000640 is sample on rising edge. + 02000740 is sample on falling edge. + 02000040 is ignore "valid" signal + + 0: FD_CTL1 Bit 7,6 must be 0,1 + 7 disable(fw controlled) + 6 0-AUX,1-TS + 5 0-par,1-ser + 4 0-lsb/1-msb + 3,2 reserved + 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both + 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge + 2: FD_STA is read-only. 0-sync + 3: FD_INSYNC is number of 47s to trigger "in sync". + 4: FD_OUTSYNC is number of 47s to trigger "out of sync". + 5: FD_MAXBYTE1 is low-order of bytes per packet. + 6: FD_MAXBYTE2 is high-order of bytes per packet. + 7: Top byte is unused. +*/ + +/****************************************************************************/ + +static u8 TSFeatureDecoderSetup[8 * 5] = { + 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, + 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ + 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ + 0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ + 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */ +}; + +/* Set NGENE I2S Config to 16 bit packed */ +static u8 I2SConfiguration[] = { + 0x00, 0x10, 0x00, 0x00, + 0x80, 0x10, 0x00, 0x00, +}; + +static u8 SPDIFConfiguration[10] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Set NGENE I2S Config to transport stream compatible mode */ + +static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 }; + +static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 }; + +static u8 ITUDecoderSetup[4][16] = { + {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */ + 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00}, + {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, + {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */ + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, + {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */ + 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00}, +}; + +/* + * 50 48 60 gleich + * 27p50 9f 00 22 80 42 69 18 ... + * 27p60 93 00 22 80 82 69 1c ... + */ + +/* Maxbyte to 1144 (for raw data) */ +static u8 ITUFeatureDecoderSetup[8] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00 +}; + +void FillTSBuffer(void *Buffer, int Length, u32 Flags) +{ + u32 *ptr = Buffer; + + memset(Buffer, 0xff, Length); + while (Length > 0) { + if (Flags & DF_SWAP32) + *ptr = 0x471FFF10; + else + *ptr = 0x10FF1F47; + ptr += (188 / 4); + Length -= 188; + } +} + + +static void flush_buffers(struct ngene_channel *chan) +{ + u8 val; + + do { + msleep(1); + spin_lock_irq(&chan->state_lock); + val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80; + spin_unlock_irq(&chan->state_lock); + } while (val); +} + +static void clear_buffers(struct ngene_channel *chan) +{ + struct SBufferHeader *Cur = chan->nextBuffer; + + do { + memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR)); + if (chan->mode & NGENE_IO_TSOUT) + FillTSBuffer(Cur->Buffer1, + chan->Capture1Length, + chan->DataFormatFlags); + Cur = Cur->Next; + } while (Cur != chan->nextBuffer); + + if (chan->mode & NGENE_IO_TSOUT) { + chan->nextBuffer->ngeneBuffer.SR.DTOUpdate = + chan->AudioDTOValue; + chan->AudioDTOUpdated = 0; + + Cur = chan->TSIdleBuffer.Head; + + do { + memset(&Cur->ngeneBuffer.SR, 0, + sizeof(Cur->ngeneBuffer.SR)); + FillTSBuffer(Cur->Buffer1, + chan->Capture1Length, + chan->DataFormatFlags); + Cur = Cur->Next; + } while (Cur != chan->TSIdleBuffer.Head); + } +} + +static int ngene_command_stream_control(struct ngene *dev, u8 stream, + u8 control, u8 mode, u8 flags) +{ + struct ngene_channel *chan = &dev->channel[stream]; + struct ngene_command com; + u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300); + u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500); + u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700); + u16 BsSDO = 0x9B00; + + down(&dev->stream_mutex); + memset(&com, 0, sizeof(com)); + com.cmd.hdr.Opcode = CMD_CONTROL; + com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2; + com.cmd.StreamControl.Stream = stream | (control ? 8 : 0); + if (chan->mode & NGENE_IO_TSOUT) + com.cmd.StreamControl.Stream |= 0x07; + com.cmd.StreamControl.Control = control | + (flags & SFLAG_ORDER_LUMA_CHROMA); + com.cmd.StreamControl.Mode = mode; + com.in_len = sizeof(struct FW_STREAM_CONTROL); + com.out_len = 0; + + dprintk(KERN_INFO DEVICE_NAME + ": Stream=%02x, Control=%02x, Mode=%02x\n", + com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control, + com.cmd.StreamControl.Mode); + + chan->Mode = mode; + + if (!(control & 0x80)) { + spin_lock_irq(&chan->state_lock); + if (chan->State == KSSTATE_RUN) { + chan->State = KSSTATE_ACQUIRE; + chan->HWState = HWSTATE_STOP; + spin_unlock_irq(&chan->state_lock); + if (ngene_command(dev, &com) < 0) { + up(&dev->stream_mutex); + return -1; + } + /* clear_buffers(chan); */ + flush_buffers(chan); + up(&dev->stream_mutex); + return 0; + } + spin_unlock_irq(&chan->state_lock); + up(&dev->stream_mutex); + return 0; + } + + if (mode & SMODE_AUDIO_CAPTURE) { + com.cmd.StreamControl.CaptureBlockCount = + chan->Capture1Length / AUDIO_BLOCK_SIZE; + com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; + } else if (mode & SMODE_TRANSPORT_STREAM) { + com.cmd.StreamControl.CaptureBlockCount = + chan->Capture1Length / TS_BLOCK_SIZE; + com.cmd.StreamControl.MaxLinesPerField = + chan->Capture1Length / TS_BLOCK_SIZE; + com.cmd.StreamControl.Buffer_Address = + chan->TSRingBuffer.PAHead; + if (chan->mode & NGENE_IO_TSOUT) { + com.cmd.StreamControl.BytesPerVBILine = + chan->Capture1Length / TS_BLOCK_SIZE; + com.cmd.StreamControl.Stream |= 0x07; + } + } else { + com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine; + com.cmd.StreamControl.MaxLinesPerField = chan->nLines; + com.cmd.StreamControl.MinLinesPerField = 100; + com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead; + + if (mode & SMODE_VBI_CAPTURE) { + com.cmd.StreamControl.MaxVBILinesPerField = + chan->nVBILines; + com.cmd.StreamControl.MinVBILinesPerField = 0; + com.cmd.StreamControl.BytesPerVBILine = + chan->nBytesPerVBILine; + } + if (flags & SFLAG_COLORBAR) + com.cmd.StreamControl.Stream |= 0x04; + } + + spin_lock_irq(&chan->state_lock); + if (mode & SMODE_AUDIO_CAPTURE) { + chan->nextBuffer = chan->RingBuffer.Head; + if (mode & SMODE_AUDIO_SPDIF) { + com.cmd.StreamControl.SetupDataLen = + sizeof(SPDIFConfiguration); + com.cmd.StreamControl.SetupDataAddr = BsSPI; + memcpy(com.cmd.StreamControl.SetupData, + SPDIFConfiguration, sizeof(SPDIFConfiguration)); + } else { + com.cmd.StreamControl.SetupDataLen = 4; + com.cmd.StreamControl.SetupDataAddr = BsSDI; + memcpy(com.cmd.StreamControl.SetupData, + I2SConfiguration + + 4 * dev->card_info->i2s[stream], 4); + } + } else if (mode & SMODE_TRANSPORT_STREAM) { + chan->nextBuffer = chan->TSRingBuffer.Head; + if (stream >= STREAM_AUDIOIN1) { + if (chan->mode & NGENE_IO_TSOUT) { + com.cmd.StreamControl.SetupDataLen = + sizeof(TS_I2SOutConfiguration); + com.cmd.StreamControl.SetupDataAddr = BsSDO; + memcpy(com.cmd.StreamControl.SetupData, + TS_I2SOutConfiguration, + sizeof(TS_I2SOutConfiguration)); + } else { + com.cmd.StreamControl.SetupDataLen = + sizeof(TS_I2SConfiguration); + com.cmd.StreamControl.SetupDataAddr = BsSDI; + memcpy(com.cmd.StreamControl.SetupData, + TS_I2SConfiguration, + sizeof(TS_I2SConfiguration)); + } + } else { + com.cmd.StreamControl.SetupDataLen = 8; + com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10; + memcpy(com.cmd.StreamControl.SetupData, + TSFeatureDecoderSetup + + 8 * dev->card_info->tsf[stream], 8); + } + } else { + chan->nextBuffer = chan->RingBuffer.Head; + com.cmd.StreamControl.SetupDataLen = + 16 + sizeof(ITUFeatureDecoderSetup); + com.cmd.StreamControl.SetupDataAddr = BsUVI; + memcpy(com.cmd.StreamControl.SetupData, + ITUDecoderSetup[chan->itumode], 16); + memcpy(com.cmd.StreamControl.SetupData + 16, + ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup)); + } + clear_buffers(chan); + chan->State = KSSTATE_RUN; + if (mode & SMODE_TRANSPORT_STREAM) + chan->HWState = HWSTATE_RUN; + else + chan->HWState = HWSTATE_STARTUP; + spin_unlock_irq(&chan->state_lock); + + if (ngene_command(dev, &com) < 0) { + up(&dev->stream_mutex); + return -1; + } + up(&dev->stream_mutex); + return 0; +} + +void set_transfer(struct ngene_channel *chan, int state) +{ + u8 control = 0, mode = 0, flags = 0; + struct ngene *dev = chan->dev; + int ret; + + /* + printk(KERN_INFO DEVICE_NAME ": st %d\n", state); + msleep(100); + */ + + if (state) { + if (chan->running) { + printk(KERN_INFO DEVICE_NAME ": already running\n"); + return; + } + } else { + if (!chan->running) { + printk(KERN_INFO DEVICE_NAME ": already stopped\n"); + return; + } + } + + if (dev->card_info->switch_ctrl) + dev->card_info->switch_ctrl(chan, 1, state ^ 1); + + if (state) { + spin_lock_irq(&chan->state_lock); + + /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + ngreadl(0x9310)); */ + dvb_ringbuffer_flush(&dev->tsout_rbuf); + control = 0x80; + if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + chan->Capture1Length = 512 * 188; + mode = SMODE_TRANSPORT_STREAM; + } + if (chan->mode & NGENE_IO_TSOUT) { + chan->pBufferExchange = tsout_exchange; + /* 0x66666666 = 50MHz *2^33 /250MHz */ + chan->AudioDTOValue = 0x80000000; + chan->AudioDTOUpdated = 1; + } + if (chan->mode & NGENE_IO_TSIN) + chan->pBufferExchange = tsin_exchange; + spin_unlock_irq(&chan->state_lock); + } else + ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + ngreadl(0x9310)); */ + + ret = ngene_command_stream_control(dev, chan->number, + control, mode, flags); + if (!ret) + chan->running = state; + else + printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n", + state); + if (!state) { + spin_lock_irq(&chan->state_lock); + chan->pBufferExchange = NULL; + dvb_ringbuffer_flush(&dev->tsout_rbuf); + spin_unlock_irq(&chan->state_lock); + } +} + + +/****************************************************************************/ +/* nGene hardware init and release functions ********************************/ +/****************************************************************************/ + +static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb) +{ + struct SBufferHeader *Cur = rb->Head; + u32 j; + + if (!Cur) + return; + + for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) { + if (Cur->Buffer1) + pci_free_consistent(dev->pci_dev, + rb->Buffer1Length, + Cur->Buffer1, + Cur->scList1->Address); + + if (Cur->Buffer2) + pci_free_consistent(dev->pci_dev, + rb->Buffer2Length, + Cur->Buffer2, + Cur->scList2->Address); + } + + if (rb->SCListMem) + pci_free_consistent(dev->pci_dev, rb->SCListMemSize, + rb->SCListMem, rb->PASCListMem); + + pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead); +} + +static void free_idlebuffer(struct ngene *dev, + struct SRingBufferDescriptor *rb, + struct SRingBufferDescriptor *tb) +{ + int j; + struct SBufferHeader *Cur = tb->Head; + + if (!rb->Head) + return; + free_ringbuffer(dev, rb); + for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) { + Cur->Buffer2 = NULL; + Cur->scList2 = NULL; + Cur->ngeneBuffer.Address_of_first_entry_2 = 0; + Cur->ngeneBuffer.Number_of_entries_2 = 0; + } +} + +static void free_common_buffers(struct ngene *dev) +{ + u32 i; + struct ngene_channel *chan; + + for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { + chan = &dev->channel[i]; + free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer); + free_ringbuffer(dev, &chan->RingBuffer); + free_ringbuffer(dev, &chan->TSRingBuffer); + } + + if (dev->OverflowBuffer) + pci_free_consistent(dev->pci_dev, + OVERFLOW_BUFFER_SIZE, + dev->OverflowBuffer, dev->PAOverflowBuffer); + + if (dev->FWInterfaceBuffer) + pci_free_consistent(dev->pci_dev, + 4096, + dev->FWInterfaceBuffer, + dev->PAFWInterfaceBuffer); +} + +/****************************************************************************/ +/* Ring buffer handling *****************************************************/ +/****************************************************************************/ + +static int create_ring_buffer(struct pci_dev *pci_dev, + struct SRingBufferDescriptor *descr, u32 NumBuffers) +{ + dma_addr_t tmp; + struct SBufferHeader *Head; + u32 i; + u32 MemSize = SIZEOF_SBufferHeader * NumBuffers; + u64 PARingBufferHead; + u64 PARingBufferCur; + u64 PARingBufferNext; + struct SBufferHeader *Cur, *Next; + + descr->Head = NULL; + descr->MemSize = 0; + descr->PAHead = 0; + descr->NumBuffers = 0; + + if (MemSize < 4096) + MemSize = 4096; + + Head = pci_alloc_consistent(pci_dev, MemSize, &tmp); + PARingBufferHead = tmp; + + if (!Head) + return -ENOMEM; + + memset(Head, 0, MemSize); + + PARingBufferCur = PARingBufferHead; + Cur = Head; + + for (i = 0; i < NumBuffers - 1; i++) { + Next = (struct SBufferHeader *) + (((u8 *) Cur) + SIZEOF_SBufferHeader); + PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader; + Cur->Next = Next; + Cur->ngeneBuffer.Next = PARingBufferNext; + Cur = Next; + PARingBufferCur = PARingBufferNext; + } + /* Last Buffer points back to first one */ + Cur->Next = Head; + Cur->ngeneBuffer.Next = PARingBufferHead; + + descr->Head = Head; + descr->MemSize = MemSize; + descr->PAHead = PARingBufferHead; + descr->NumBuffers = NumBuffers; + + return 0; +} + +static int AllocateRingBuffers(struct pci_dev *pci_dev, + dma_addr_t of, + struct SRingBufferDescriptor *pRingBuffer, + u32 Buffer1Length, u32 Buffer2Length) +{ + dma_addr_t tmp; + u32 i, j; + int status = 0; + u32 SCListMemSize = pRingBuffer->NumBuffers + * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) : + NUM_SCATTER_GATHER_ENTRIES) + * sizeof(struct HW_SCATTER_GATHER_ELEMENT); + + u64 PASCListMem; + struct HW_SCATTER_GATHER_ELEMENT *SCListEntry; + u64 PASCListEntry; + struct SBufferHeader *Cur; + void *SCListMem; + + if (SCListMemSize < 4096) + SCListMemSize = 4096; + + SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp); + + PASCListMem = tmp; + if (SCListMem == NULL) + return -ENOMEM; + + memset(SCListMem, 0, SCListMemSize); + + pRingBuffer->SCListMem = SCListMem; + pRingBuffer->PASCListMem = PASCListMem; + pRingBuffer->SCListMemSize = SCListMemSize; + pRingBuffer->Buffer1Length = Buffer1Length; + pRingBuffer->Buffer2Length = Buffer2Length; + + SCListEntry = SCListMem; + PASCListEntry = PASCListMem; + Cur = pRingBuffer->Head; + + for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) { + u64 PABuffer; + + void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length, + &tmp); + PABuffer = tmp; + + if (Buffer == NULL) + return -ENOMEM; + + Cur->Buffer1 = Buffer; + + SCListEntry->Address = PABuffer; + SCListEntry->Length = Buffer1Length; + + Cur->scList1 = SCListEntry; + Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry; + Cur->ngeneBuffer.Number_of_entries_1 = + NUM_SCATTER_GATHER_ENTRIES; + + SCListEntry += 1; + PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); + +#if NUM_SCATTER_GATHER_ENTRIES > 1 + for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) { + SCListEntry->Address = of; + SCListEntry->Length = OVERFLOW_BUFFER_SIZE; + SCListEntry += 1; + PASCListEntry += + sizeof(struct HW_SCATTER_GATHER_ELEMENT); + } +#endif + + if (!Buffer2Length) + continue; + + Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp); + PABuffer = tmp; + + if (Buffer == NULL) + return -ENOMEM; + + Cur->Buffer2 = Buffer; + + SCListEntry->Address = PABuffer; + SCListEntry->Length = Buffer2Length; + + Cur->scList2 = SCListEntry; + Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry; + Cur->ngeneBuffer.Number_of_entries_2 = + NUM_SCATTER_GATHER_ENTRIES; + + SCListEntry += 1; + PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT); + +#if NUM_SCATTER_GATHER_ENTRIES > 1 + for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) { + SCListEntry->Address = of; + SCListEntry->Length = OVERFLOW_BUFFER_SIZE; + SCListEntry += 1; + PASCListEntry += + sizeof(struct HW_SCATTER_GATHER_ELEMENT); + } +#endif + + } + + return status; +} + +static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer, + struct SRingBufferDescriptor *pRingBuffer) +{ + int status = 0; + + /* Copy pointer to scatter gather list in TSRingbuffer + structure for buffer 2 + Load number of buffer + */ + u32 n = pRingBuffer->NumBuffers; + + /* Point to first buffer entry */ + struct SBufferHeader *Cur = pRingBuffer->Head; + int i; + /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */ + for (i = 0; i < n; i++) { + Cur->Buffer2 = pIdleBuffer->Head->Buffer1; + Cur->scList2 = pIdleBuffer->Head->scList1; + Cur->ngeneBuffer.Address_of_first_entry_2 = + pIdleBuffer->Head->ngeneBuffer. + Address_of_first_entry_1; + Cur->ngeneBuffer.Number_of_entries_2 = + pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1; + Cur = Cur->Next; + } + return status; +} + +static u32 RingBufferSizes[MAX_STREAM] = { + RING_SIZE_VIDEO, + RING_SIZE_VIDEO, + RING_SIZE_AUDIO, + RING_SIZE_AUDIO, + RING_SIZE_AUDIO, +}; + +static u32 Buffer1Sizes[MAX_STREAM] = { + MAX_VIDEO_BUFFER_SIZE, + MAX_VIDEO_BUFFER_SIZE, + MAX_AUDIO_BUFFER_SIZE, + MAX_AUDIO_BUFFER_SIZE, + MAX_AUDIO_BUFFER_SIZE +}; + +static u32 Buffer2Sizes[MAX_STREAM] = { + MAX_VBI_BUFFER_SIZE, + MAX_VBI_BUFFER_SIZE, + 0, + 0, + 0 +}; + + +static int AllocCommonBuffers(struct ngene *dev) +{ + int status = 0, i; + + dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096, + &dev->PAFWInterfaceBuffer); + if (!dev->FWInterfaceBuffer) + return -ENOMEM; + dev->hosttongene = dev->FWInterfaceBuffer; + dev->ngenetohost = dev->FWInterfaceBuffer + 256; + dev->EventBuffer = dev->FWInterfaceBuffer + 512; + + dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev, + OVERFLOW_BUFFER_SIZE, + &dev->PAOverflowBuffer); + if (!dev->OverflowBuffer) + return -ENOMEM; + memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE); + + for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) { + int type = dev->card_info->io_type[i]; + + dev->channel[i].State = KSSTATE_STOP; + + if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) { + status = create_ring_buffer(dev->pci_dev, + &dev->channel[i].RingBuffer, + RingBufferSizes[i]); + if (status < 0) + break; + + if (type & (NGENE_IO_TV | NGENE_IO_AIN)) { + status = AllocateRingBuffers(dev->pci_dev, + dev-> + PAOverflowBuffer, + &dev->channel[i]. + RingBuffer, + Buffer1Sizes[i], + Buffer2Sizes[i]); + if (status < 0) + break; + } else if (type & NGENE_IO_HDTV) { + status = AllocateRingBuffers(dev->pci_dev, + dev-> + PAOverflowBuffer, + &dev->channel[i]. + RingBuffer, + MAX_HDTV_BUFFER_SIZE, + 0); + if (status < 0) + break; + } + } + + if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + + status = create_ring_buffer(dev->pci_dev, + &dev->channel[i]. + TSRingBuffer, RING_SIZE_TS); + if (status < 0) + break; + + status = AllocateRingBuffers(dev->pci_dev, + dev->PAOverflowBuffer, + &dev->channel[i]. + TSRingBuffer, + MAX_TS_BUFFER_SIZE, 0); + if (status) + break; + } + + if (type & NGENE_IO_TSOUT) { + status = create_ring_buffer(dev->pci_dev, + &dev->channel[i]. + TSIdleBuffer, 1); + if (status < 0) + break; + status = AllocateRingBuffers(dev->pci_dev, + dev->PAOverflowBuffer, + &dev->channel[i]. + TSIdleBuffer, + MAX_TS_BUFFER_SIZE, 0); + if (status) + break; + FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer, + &dev->channel[i].TSRingBuffer); + } + } + return status; +} + +static void ngene_release_buffers(struct ngene *dev) +{ + if (dev->iomem) + iounmap(dev->iomem); + free_common_buffers(dev); + vfree(dev->tsout_buf); + vfree(dev->tsin_buf); + vfree(dev->ain_buf); + vfree(dev->vin_buf); + vfree(dev); +} + +static int ngene_get_buffers(struct ngene *dev) +{ + if (AllocCommonBuffers(dev)) + return -ENOMEM; + if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) { + dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE); + if (!dev->tsout_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->tsout_rbuf, + dev->tsout_buf, TSOUT_BUF_SIZE); + } + if (dev->card_info->io_type[2]&NGENE_IO_TSIN) { + dev->tsin_buf = vmalloc(TSIN_BUF_SIZE); + if (!dev->tsin_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->tsin_rbuf, + dev->tsin_buf, TSIN_BUF_SIZE); + } + if (dev->card_info->io_type[2] & NGENE_IO_AIN) { + dev->ain_buf = vmalloc(AIN_BUF_SIZE); + if (!dev->ain_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE); + } + if (dev->card_info->io_type[0] & NGENE_IO_HDTV) { + dev->vin_buf = vmalloc(VIN_BUF_SIZE); + if (!dev->vin_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE); + } + dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0), + pci_resource_len(dev->pci_dev, 0)); + if (!dev->iomem) + return -ENOMEM; + + return 0; +} + +static void ngene_init(struct ngene *dev) +{ + int i; + + tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev); + + memset_io(dev->iomem + 0xc000, 0x00, 0x220); + memset_io(dev->iomem + 0xc400, 0x00, 0x100); + + for (i = 0; i < MAX_STREAM; i++) { + dev->channel[i].dev = dev; + dev->channel[i].number = i; + } + + dev->fw_interface_version = 0; + + ngwritel(0, NGENE_INT_ENABLE); + + dev->icounts = ngreadl(NGENE_INT_COUNTS); + + dev->device_version = ngreadl(DEV_VER) & 0x0f; + printk(KERN_INFO DEVICE_NAME ": Device version %d\n", + dev->device_version); +} + +static int ngene_load_firm(struct ngene *dev) +{ + u32 size; + const struct firmware *fw = NULL; + u8 *ngene_fw; + char *fw_name; + int err, version; + + version = dev->card_info->fw_version; + + switch (version) { + default: + case 15: + version = 15; + size = 23466; + fw_name = "ngene_15.fw"; + dev->cmd_timeout_workaround = true; + break; + case 16: + size = 23498; + fw_name = "ngene_16.fw"; + dev->cmd_timeout_workaround = true; + break; + case 17: + size = 24446; + fw_name = "ngene_17.fw"; + dev->cmd_timeout_workaround = true; + break; + case 18: + size = 0; + fw_name = "ngene_18.fw"; + break; + } + + if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { + printk(KERN_ERR DEVICE_NAME + ": Could not load firmware file %s.\n", fw_name); + printk(KERN_INFO DEVICE_NAME + ": Copy %s to your hotplug directory!\n", fw_name); + return -1; + } + if (size == 0) + size = fw->size; + if (size != fw->size) { + printk(KERN_ERR DEVICE_NAME + ": Firmware %s has invalid size!", fw_name); + err = -1; + } else { + printk(KERN_INFO DEVICE_NAME + ": Loading firmware file %s.\n", fw_name); + ngene_fw = (u8 *) fw->data; + err = ngene_command_load_firmware(dev, ngene_fw, size); + } + + release_firmware(fw); + + return err; +} + +static void ngene_stop(struct ngene *dev) +{ + down(&dev->cmd_mutex); + i2c_del_adapter(&(dev->channel[0].i2c_adapter)); + i2c_del_adapter(&(dev->channel[1].i2c_adapter)); + ngwritel(0, NGENE_INT_ENABLE); + ngwritel(0, NGENE_COMMAND); + ngwritel(0, NGENE_COMMAND_HI); + ngwritel(0, NGENE_STATUS); + ngwritel(0, NGENE_STATUS_HI); + ngwritel(0, NGENE_EVENT); + ngwritel(0, NGENE_EVENT_HI); + free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); +#endif +} + +static int ngene_buffer_config(struct ngene *dev) +{ + int stat; + + if (dev->card_info->fw_version >= 17) { + u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }; + u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 }; + u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 }; + u8 *bconf = tsin12_config; + + if (dev->card_info->io_type[2]&NGENE_IO_TSIN && + dev->card_info->io_type[3]&NGENE_IO_TSIN) { + bconf = tsin1234_config; + if (dev->card_info->io_type[4]&NGENE_IO_TSOUT && + dev->ci.en) + bconf = tsio1235_config; + } + stat = ngene_command_config_free_buf(dev, bconf); + } else { + int bconf = BUFFER_CONFIG_4422; + + if (dev->card_info->io_type[3] == NGENE_IO_TSIN) + bconf = BUFFER_CONFIG_3333; + stat = ngene_command_config_buf(dev, bconf); + } + return stat; +} + + +static int ngene_start(struct ngene *dev) +{ + int stat; + int i; + + pci_set_master(dev->pci_dev); + ngene_init(dev); + + stat = request_irq(dev->pci_dev->irq, irq_handler, + IRQF_SHARED, "nGene", + (void *)dev); + if (stat < 0) + return stat; + + init_waitqueue_head(&dev->cmd_wq); + init_waitqueue_head(&dev->tx_wq); + init_waitqueue_head(&dev->rx_wq); + sema_init(&dev->cmd_mutex, 1); + sema_init(&dev->stream_mutex, 1); + sema_init(&dev->pll_mutex, 1); + sema_init(&dev->i2c_switch_mutex, 1); + spin_lock_init(&dev->cmd_lock); + for (i = 0; i < MAX_STREAM; i++) + spin_lock_init(&dev->channel[i].state_lock); + ngwritel(1, TIMESTAMPS); + + ngwritel(1, NGENE_INT_ENABLE); + + stat = ngene_load_firm(dev); + if (stat < 0) + goto fail; + +#ifdef CONFIG_PCI_MSI + /* enable MSI if kernel and card support it */ + if (pci_msi_enabled() && dev->card_info->msi_supported) { + unsigned long flags; + + ngwritel(0, NGENE_INT_ENABLE); + free_irq(dev->pci_dev->irq, dev); + stat = pci_enable_msi(dev->pci_dev); + if (stat) { + printk(KERN_INFO DEVICE_NAME + ": MSI not available\n"); + flags = IRQF_SHARED; + } else { + flags = 0; + dev->msi_enabled = true; + } + stat = request_irq(dev->pci_dev->irq, irq_handler, + flags, "nGene", dev); + if (stat < 0) + goto fail2; + ngwritel(1, NGENE_INT_ENABLE); + } +#endif + + stat = ngene_i2c_init(dev, 0); + if (stat < 0) + goto fail; + + stat = ngene_i2c_init(dev, 1); + if (stat < 0) + goto fail; + + if (!stat) + return stat; + + /* otherwise error: fall through */ +fail: + ngwritel(0, NGENE_INT_ENABLE); + free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI +fail2: + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); +#endif + return stat; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void release_channel(struct ngene_channel *chan) +{ + struct dvb_demux *dvbdemux = &chan->demux; + struct ngene *dev = chan->dev; + + if (chan->running) + set_transfer(chan, 0); + + tasklet_kill(&chan->demux_tasklet); + + if (chan->ci_dev) { + dvb_unregister_device(chan->ci_dev); + chan->ci_dev = NULL; + } + + if (chan->fe) { + dvb_unregister_frontend(chan->fe); + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + } + + if (chan->has_demux) { + dvb_net_release(&chan->dvbnet); + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &chan->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, + &chan->mem_frontend); + dvb_dmxdev_release(&chan->dmxdev); + dvb_dmx_release(&chan->demux); + chan->has_demux = false; + } + + if (chan->has_adapter) { + dvb_unregister_adapter(&dev->adapter[chan->number]); + chan->has_adapter = false; + } +} + +static int init_channel(struct ngene_channel *chan) +{ + int ret = 0, nr = chan->number; + struct dvb_adapter *adapter = NULL; + struct dvb_demux *dvbdemux = &chan->demux; + struct ngene *dev = chan->dev; + struct ngene_info *ni = dev->card_info; + int io = ni->io_type[nr]; + + tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan); + chan->users = 0; + chan->type = io; + chan->mode = chan->type; /* for now only one mode */ + + if (io & NGENE_IO_TSIN) { + chan->fe = NULL; + if (ni->demod_attach[nr]) { + ret = ni->demod_attach[nr](chan); + if (ret < 0) + goto err; + } + if (chan->fe && ni->tuner_attach[nr]) { + ret = ni->tuner_attach[nr](chan); + if (ret < 0) + goto err; + } + } + + if (!dev->ci.en && (io & NGENE_IO_TSOUT)) + return 0; + + if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + if (nr >= STREAM_AUDIOIN1) + chan->DataFormatFlags = DF_SWAP32; + + if (nr == 0 || !one_adapter || dev->first_adapter == NULL) { + adapter = &dev->adapter[nr]; + ret = dvb_register_adapter(adapter, "nGene", + THIS_MODULE, + &chan->dev->pci_dev->dev, + adapter_nr); + if (ret < 0) + goto err; + if (dev->first_adapter == NULL) + dev->first_adapter = adapter; + chan->has_adapter = true; + } else + adapter = dev->first_adapter; + } + + if (dev->ci.en && (io & NGENE_IO_TSOUT)) { + dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); + set_transfer(chan, 1); + chan->dev->channel[2].DataFormatFlags = DF_SWAP32; + set_transfer(&chan->dev->channel[2], 1); + dvb_register_device(adapter, &chan->ci_dev, + &ngene_dvbdev_ci, (void *) chan, + DVB_DEVICE_SEC); + if (!chan->ci_dev) + goto err; + } + + if (chan->fe) { + if (dvb_register_frontend(adapter, chan->fe) < 0) + goto err; + chan->has_demux = true; + } + + if (chan->has_demux) { + ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", + ngene_start_feed, + ngene_stop_feed, chan); + ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, + &chan->hw_frontend, + &chan->mem_frontend, adapter); + ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx); + } + + return ret; + +err: + if (chan->fe) { + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + } + release_channel(chan); + return 0; +} + +static int init_channels(struct ngene *dev) +{ + int i, j; + + for (i = 0; i < MAX_STREAM; i++) { + dev->channel[i].number = i; + if (init_channel(&dev->channel[i]) < 0) { + for (j = i - 1; j >= 0; j--) + release_channel(&dev->channel[j]); + return -1; + } + } + return 0; +} + +static void cxd_attach(struct ngene *dev) +{ + struct ngene_ci *ci = &dev->ci; + + ci->en = cxd2099_attach(0x40, dev, &dev->channel[0].i2c_adapter); + ci->dev = dev; + return; +} + +static void cxd_detach(struct ngene *dev) +{ + struct ngene_ci *ci = &dev->ci; + + dvb_ca_en50221_release(ci->en); + kfree(ci->en); + ci->en = 0; +} + +/***********************************/ +/* workaround for shutdown failure */ +/***********************************/ + +static void ngene_unlink(struct ngene *dev) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_MEM_WRITE; + com.cmd.hdr.Length = 3; + com.cmd.MemoryWrite.address = 0x910c; + com.cmd.MemoryWrite.data = 0xff; + com.in_len = 3; + com.out_len = 1; + + down(&dev->cmd_mutex); + ngwritel(0, NGENE_INT_ENABLE); + ngene_command_mutex(dev, &com); + up(&dev->cmd_mutex); +} + +void ngene_shutdown(struct pci_dev *pdev) +{ + struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev); + + if (!dev || !shutdown_workaround) + return; + + printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n"); + ngene_unlink(dev); + pci_disable_device(pdev); +} + +/****************************************************************************/ +/* device probe/remove calls ************************************************/ +/****************************************************************************/ + +void __devexit ngene_remove(struct pci_dev *pdev) +{ + struct ngene *dev = pci_get_drvdata(pdev); + int i; + + tasklet_kill(&dev->event_tasklet); + for (i = MAX_STREAM - 1; i >= 0; i--) + release_channel(&dev->channel[i]); + if (dev->ci.en) + cxd_detach(dev); + ngene_stop(dev); + ngene_release_buffers(dev); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); +} + +int __devinit ngene_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + struct ngene *dev; + int stat = 0; + + if (pci_enable_device(pci_dev) < 0) + return -ENODEV; + + dev = vzalloc(sizeof(struct ngene)); + if (dev == NULL) { + stat = -ENOMEM; + goto fail0; + } + + dev->pci_dev = pci_dev; + dev->card_info = (struct ngene_info *)id->driver_data; + printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name); + + pci_set_drvdata(pci_dev, dev); + + /* Alloc buffers and start nGene */ + stat = ngene_get_buffers(dev); + if (stat < 0) + goto fail1; + stat = ngene_start(dev); + if (stat < 0) + goto fail1; + + cxd_attach(dev); + + stat = ngene_buffer_config(dev); + if (stat < 0) + goto fail1; + + + dev->i2c_current_bus = -1; + + /* Register DVB adapters and devices for both channels */ + if (init_channels(dev) < 0) + goto fail2; + + return 0; + +fail2: + ngene_stop(dev); +fail1: + ngene_release_buffers(dev); +fail0: + pci_disable_device(pci_dev); + pci_set_drvdata(pci_dev, NULL); + return stat; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-dvb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,231 @@ +/* + * ngene-dvb.c: nGene PCIe bridge driver - DVB functions + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngene.h" + + +/****************************************************************************/ +/* COMMAND API interface ****************************************************/ +/****************************************************************************/ + +static ssize_t ts_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + + if (wait_event_interruptible(dev->tsout_rbuf.queue, + dvb_ringbuffer_free + (&dev->tsout_rbuf) >= count) < 0) + return 0; + + dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count); + + return count; +} + +static ssize_t ts_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + int left, avail; + + left = count; + while (left) { + if (wait_event_interruptible( + dev->tsin_rbuf.queue, + dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0) + return -EAGAIN; + avail = dvb_ringbuffer_avail(&dev->tsin_rbuf); + if (avail > left) + avail = left; + dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail); + left -= avail; + buf += avail; + } + return count; +} + +static const struct file_operations ci_fops = { + .owner = THIS_MODULE, + .read = ts_read, + .write = ts_write, + .open = dvb_generic_open, + .release = dvb_generic_release, +}; + +struct dvb_device ngene_dvbdev_ci = { + .priv = 0, + .readers = -1, + .writers = -1, + .users = -1, + .fops = &ci_fops, +}; + + +/****************************************************************************/ +/* DVB functions and API interface ******************************************/ +/****************************************************************************/ + +static void swap_buffer(u32 *p, u32 len) +{ + while (len) { + *p = swab32(*p); + p++; + len -= 4; + } +} + +void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) +{ + struct ngene_channel *chan = priv; + struct ngene *dev = chan->dev; + + + if (flags & DF_SWAP32) + swap_buffer(buf, len); + if (dev->ci.en && chan->number == 2) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) > len) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, len); + wake_up_interruptible(&dev->tsin_rbuf.queue); + } + return 0; + } + if (chan->users > 0) { + dvb_dmx_swfilter(&chan->demux, buf, len); + } + return NULL; +} + +u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 }; + +void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) +{ + struct ngene_channel *chan = priv; + struct ngene *dev = chan->dev; + u32 alen; + + alen = dvb_ringbuffer_avail(&dev->tsout_rbuf); + alen -= alen % 188; + + if (alen < len) + FillTSBuffer(buf + alen, len - alen, flags); + else + alen = len; + dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen); + if (flags & DF_SWAP32) + swap_buffer((u32 *)buf, alen); + wake_up_interruptible(&dev->tsout_rbuf.queue); + return buf; +} + + + +int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ngene_channel *chan = dvbdmx->priv; + + if (chan->users == 0) { + if (!chan->dev->cmd_timeout_workaround || !chan->running) + set_transfer(chan, 1); + } + + return ++chan->users; +} + +int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ngene_channel *chan = dvbdmx->priv; + + if (--chan->users) + return chan->users; + + if (!chan->dev->cmd_timeout_workaround) + set_transfer(chan, 0); + + return 0; +} + +int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, + int (*start_feed)(struct dvb_demux_feed *), + int (*stop_feed)(struct dvb_demux_feed *), + void *priv) +{ + dvbdemux->priv = priv; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = start_feed; + dvbdemux->stop_feed = stop_feed; + dvbdemux->write_to_decoder = NULL; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + return dvb_dmx_init(dvbdemux); +} + +int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, + struct dvb_demux *dvbdemux, + struct dmx_frontend *hw_frontend, + struct dmx_frontend *mem_frontend, + struct dvb_adapter *dvb_adapter) +{ + int ret; + + dmxdev->filternum = 256; + dmxdev->demux = &dvbdemux->dmx; + dmxdev->capabilities = 0; + ret = dvb_dmxdev_init(dmxdev, dvb_adapter); + if (ret < 0) + return ret; + + hw_frontend->source = DMX_FRONTEND_0; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); + mem_frontend->source = DMX_MEMORY_FE; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); + return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,916 @@ +/* + * ngene.h: nGene PCIe bridge driver + * + * Copyright (C) 2005-2007 Micronas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _NGENE_H_ +#define _NGENE_H_ + +#include +#include +#include +#include +#include +#include + +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_ca_en50221.h" +#include "dvb_frontend.h" +#include "dvb_ringbuffer.h" +#include "dvb_net.h" +#include "cxd2099.h" + +#define DEVICE_NAME "ngene" + +#define NGENE_VID 0x18c3 +#define NGENE_PID 0x0720 + +#ifndef VIDEO_CAP_VC1 +#define VIDEO_CAP_AVC 128 +#define VIDEO_CAP_H264 128 +#define VIDEO_CAP_VC1 256 +#define VIDEO_CAP_WMV9 256 +#define VIDEO_CAP_MPEG4 512 +#endif + +enum STREAM { + STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ + STREAM_VIDEOIN2, + STREAM_AUDIOIN1, /* I2S or SPI Input */ + STREAM_AUDIOIN2, + STREAM_AUDIOOUT, + MAX_STREAM +}; + +enum SMODE_BITS { + SMODE_AUDIO_SPDIF = 0x20, + SMODE_AVSYNC = 0x10, + SMODE_TRANSPORT_STREAM = 0x08, + SMODE_AUDIO_CAPTURE = 0x04, + SMODE_VBI_CAPTURE = 0x02, + SMODE_VIDEO_CAPTURE = 0x01 +}; + +enum STREAM_FLAG_BITS { + SFLAG_CHROMA_FORMAT_2COMP = 0x01, /* Chroma Format : 2's complement */ + SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */ + SFLAG_ORDER_LUMA_CHROMA = 0x02, /* Byte order: Y,Cb,Y,Cr */ + SFLAG_ORDER_CHROMA_LUMA = 0x00, /* Byte order: Cb,Y,Cr,Y */ + SFLAG_COLORBAR = 0x04, /* Select colorbar */ +}; + +#define PROGRAM_ROM 0x0000 +#define PROGRAM_SRAM 0x1000 +#define PERIPHERALS0 0x8000 +#define PERIPHERALS1 0x9000 +#define SHARED_BUFFER 0xC000 + +#define HOST_TO_NGENE (SHARED_BUFFER+0x0000) +#define NGENE_TO_HOST (SHARED_BUFFER+0x0100) +#define NGENE_COMMAND (SHARED_BUFFER+0x0200) +#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204) +#define NGENE_STATUS (SHARED_BUFFER+0x0208) +#define NGENE_STATUS_HI (SHARED_BUFFER+0x020C) +#define NGENE_EVENT (SHARED_BUFFER+0x0210) +#define NGENE_EVENT_HI (SHARED_BUFFER+0x0214) +#define VARIABLES (SHARED_BUFFER+0x0210) + +#define NGENE_INT_COUNTS (SHARED_BUFFER+0x0260) +#define NGENE_INT_ENABLE (SHARED_BUFFER+0x0264) +#define NGENE_VBI_LINE_COUNT (SHARED_BUFFER+0x0268) + +#define BUFFER_GP_XMIT (SHARED_BUFFER+0x0800) +#define BUFFER_GP_RECV (SHARED_BUFFER+0x0900) +#define EEPROM_AREA (SHARED_BUFFER+0x0A00) + +#define SG_V_IN_1 (SHARED_BUFFER+0x0A80) +#define SG_VBI_1 (SHARED_BUFFER+0x0B00) +#define SG_A_IN_1 (SHARED_BUFFER+0x0B80) +#define SG_V_IN_2 (SHARED_BUFFER+0x0C00) +#define SG_VBI_2 (SHARED_BUFFER+0x0C80) +#define SG_A_IN_2 (SHARED_BUFFER+0x0D00) +#define SG_V_OUT (SHARED_BUFFER+0x0D80) +#define SG_A_OUT2 (SHARED_BUFFER+0x0E00) + +#define DATA_A_IN_1 (SHARED_BUFFER+0x0E80) +#define DATA_A_IN_2 (SHARED_BUFFER+0x0F00) +#define DATA_A_OUT (SHARED_BUFFER+0x0F80) +#define DATA_V_IN_1 (SHARED_BUFFER+0x1000) +#define DATA_V_IN_2 (SHARED_BUFFER+0x2000) +#define DATA_V_OUT (SHARED_BUFFER+0x3000) + +#define DATA_FIFO_AREA (SHARED_BUFFER+0x1000) + +#define TIMESTAMPS 0xA000 +#define SCRATCHPAD 0xA080 +#define FORCE_INT 0xA088 +#define FORCE_NMI 0xA090 +#define INT_STATUS 0xA0A0 + +#define DEV_VER 0x9004 + +#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF) + +struct SG_ADDR { + u64 start; + u64 curr; + u16 curr_ptr; + u16 elements; + u32 pad[3]; +} __attribute__ ((__packed__)); + +struct SHARED_MEMORY { + /* C000 */ + u32 HostToNgene[64]; + + /* C100 */ + u32 NgeneToHost[64]; + + /* C200 */ + u64 NgeneCommand; + u64 NgeneStatus; + u64 NgeneEvent; + + /* C210 */ + u8 pad1[0xc260 - 0xc218]; + + /* C260 */ + u32 IntCounts; + u32 IntEnable; + + /* C268 */ + u8 pad2[0xd000 - 0xc268]; + +} __attribute__ ((__packed__)); + +struct BUFFER_STREAM_RESULTS { + u32 Clock; /* Stream time in 100ns units */ + u16 RemainingLines; /* Remaining lines in this field. + 0 for complete field */ + u8 FieldCount; /* Video field number */ + u8 Flags; /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow, + Bit 0 = FieldID */ + u16 BlockCount; /* Audio block count (unused) */ + u8 Reserved[2]; + u32 DTOUpdate; +} __attribute__ ((__packed__)); + +struct HW_SCATTER_GATHER_ELEMENT { + u64 Address; + u32 Length; + u32 Reserved; +} __attribute__ ((__packed__)); + +struct BUFFER_HEADER { + u64 Next; + struct BUFFER_STREAM_RESULTS SR; + + u32 Number_of_entries_1; + u32 Reserved5; + u64 Address_of_first_entry_1; + + u32 Number_of_entries_2; + u32 Reserved7; + u64 Address_of_first_entry_2; +} __attribute__ ((__packed__)); + +struct EVENT_BUFFER { + u32 TimeStamp; + u8 GPIOStatus; + u8 UARTStatus; + u8 RXCharacter; + u8 EventStatus; + u32 Reserved[2]; +} __attribute__ ((__packed__)); + +/* Firmware commands. */ + +enum OPCODES { + CMD_NOP = 0, + CMD_FWLOAD_PREPARE = 0x01, + CMD_FWLOAD_FINISH = 0x02, + CMD_I2C_READ = 0x03, + CMD_I2C_WRITE = 0x04, + + CMD_I2C_WRITE_NOSTOP = 0x05, + CMD_I2C_CONTINUE_WRITE = 0x06, + CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07, + + CMD_DEBUG_OUTPUT = 0x09, + + CMD_CONTROL = 0x10, + CMD_CONFIGURE_BUFFER = 0x11, + CMD_CONFIGURE_FREE_BUFFER = 0x12, + + CMD_SPI_READ = 0x13, + CMD_SPI_WRITE = 0x14, + + CMD_MEM_READ = 0x20, + CMD_MEM_WRITE = 0x21, + CMD_SFR_READ = 0x22, + CMD_SFR_WRITE = 0x23, + CMD_IRAM_READ = 0x24, + CMD_IRAM_WRITE = 0x25, + CMD_SET_GPIO_PIN = 0x26, + CMD_SET_GPIO_INT = 0x27, + CMD_CONFIGURE_UART = 0x28, + CMD_WRITE_UART = 0x29, + MAX_CMD +}; + +enum RESPONSES { + OK = 0, + ERROR = 1 +}; + +struct FW_HEADER { + u8 Opcode; + u8 Length; +} __attribute__ ((__packed__)); + +struct FW_I2C_WRITE { + struct FW_HEADER hdr; + u8 Device; + u8 Data[250]; +} __attribute__ ((__packed__)); + +struct FW_I2C_CONTINUE_WRITE { + struct FW_HEADER hdr; + u8 Data[250]; +} __attribute__ ((__packed__)); + +struct FW_I2C_READ { + struct FW_HEADER hdr; + u8 Device; + u8 Data[252]; /* followed by two bytes of read data count */ +} __attribute__ ((__packed__)); + +struct FW_SPI_WRITE { + struct FW_HEADER hdr; + u8 ModeSelect; + u8 Data[250]; +} __attribute__ ((__packed__)); + +struct FW_SPI_READ { + struct FW_HEADER hdr; + u8 ModeSelect; + u8 Data[252]; /* followed by two bytes of read data count */ +} __attribute__ ((__packed__)); + +struct FW_FWLOAD_PREPARE { + struct FW_HEADER hdr; +} __attribute__ ((__packed__)); + +struct FW_FWLOAD_FINISH { + struct FW_HEADER hdr; + u16 Address; /* address of final block */ + u16 Length; +} __attribute__ ((__packed__)); + +/* + * Meaning of FW_STREAM_CONTROL::Mode bits: + * Bit 7: Loopback PEXin to PEXout using TVOut channel + * Bit 6: AVLOOP + * Bit 5: Audio select; 0=I2S, 1=SPDIF + * Bit 4: AVSYNC + * Bit 3: Enable transport stream + * Bit 2: Enable audio capture + * Bit 1: Enable ITU-Video VBI capture + * Bit 0: Enable ITU-Video capture + * + * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL) + * Bit 7: continuous capture + * Bit 6: capture one field + * Bit 5: capture one frame + * Bit 4: unused + * Bit 3: starting field; 0=odd, 1=even + * Bit 2: sample size; 0=8-bit, 1=10-bit + * Bit 1: data format; 0=UYVY, 1=YUY2 + * Bit 0: resets buffer pointers +*/ + +enum FSC_MODE_BITS { + SMODE_LOOPBACK = 0x80, + SMODE_AVLOOP = 0x40, + _SMODE_AUDIO_SPDIF = 0x20, + _SMODE_AVSYNC = 0x10, + _SMODE_TRANSPORT_STREAM = 0x08, + _SMODE_AUDIO_CAPTURE = 0x04, + _SMODE_VBI_CAPTURE = 0x02, + _SMODE_VIDEO_CAPTURE = 0x01 +}; + + +/* Meaning of FW_STREAM_CONTROL::Stream bits: + * Bit 3: Audio sample count: 0 = relative, 1 = absolute + * Bit 2: color bar select; 1=color bars, 0=CV3 decoder + * Bits 1-0: stream select, UVI1, UVI2, TVOUT + */ + +struct FW_STREAM_CONTROL { + struct FW_HEADER hdr; + u8 Stream; /* Stream number (UVI1, UVI2, TVOUT) */ + u8 Control; /* Value written to UVI1_CTL */ + u8 Mode; /* Controls clock source */ + u8 SetupDataLen; /* Length of setup data, MSB=1 write + backwards */ + u16 CaptureBlockCount; /* Blocks (a 256 Bytes) to capture per buffer + for TS and Audio */ + u64 Buffer_Address; /* Address of first buffer header */ + u16 BytesPerVideoLine; + u16 MaxLinesPerField; + u16 MinLinesPerField; + u16 Reserved_1; + u16 BytesPerVBILine; + u16 MaxVBILinesPerField; + u16 MinVBILinesPerField; + u16 SetupDataAddr; /* ngene relative address of setup data */ + u8 SetupData[32]; /* setup data */ +} __attribute__((__packed__)); + +#define AUDIO_BLOCK_SIZE 256 +#define TS_BLOCK_SIZE 256 + +struct FW_MEM_READ { + struct FW_HEADER hdr; + u16 address; +} __attribute__ ((__packed__)); + +struct FW_MEM_WRITE { + struct FW_HEADER hdr; + u16 address; + u8 data; +} __attribute__ ((__packed__)); + +struct FW_SFR_IRAM_READ { + struct FW_HEADER hdr; + u8 address; +} __attribute__ ((__packed__)); + +struct FW_SFR_IRAM_WRITE { + struct FW_HEADER hdr; + u8 address; + u8 data; +} __attribute__ ((__packed__)); + +struct FW_SET_GPIO_PIN { + struct FW_HEADER hdr; + u8 select; +} __attribute__ ((__packed__)); + +struct FW_SET_GPIO_INT { + struct FW_HEADER hdr; + u8 select; +} __attribute__ ((__packed__)); + +struct FW_SET_DEBUGMODE { + struct FW_HEADER hdr; + u8 debug_flags; +} __attribute__ ((__packed__)); + +struct FW_CONFIGURE_BUFFERS { + struct FW_HEADER hdr; + u8 config; +} __attribute__ ((__packed__)); + +enum _BUFFER_CONFIGS { + /* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2 (standard usage) */ + BUFFER_CONFIG_4422 = 0, + /* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2 (4x TS input usage) */ + BUFFER_CONFIG_3333 = 1, + /* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut (HDTV decoder usage) */ + BUFFER_CONFIG_8022 = 2, + BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */ +}; + +struct FW_CONFIGURE_FREE_BUFFERS { + struct FW_HEADER hdr; + u8 UVI1_BufferLength; + u8 UVI2_BufferLength; + u8 TVO_BufferLength; + u8 AUD1_BufferLength; + u8 AUD2_BufferLength; + u8 TVA_BufferLength; +} __attribute__ ((__packed__)); + +struct FW_CONFIGURE_UART { + struct FW_HEADER hdr; + u8 UartControl; +} __attribute__ ((__packed__)); + +enum _UART_CONFIG { + _UART_BAUDRATE_19200 = 0, + _UART_BAUDRATE_9600 = 1, + _UART_BAUDRATE_4800 = 2, + _UART_BAUDRATE_2400 = 3, + _UART_RX_ENABLE = 0x40, + _UART_TX_ENABLE = 0x80, +}; + +struct FW_WRITE_UART { + struct FW_HEADER hdr; + u8 Data[252]; +} __attribute__ ((__packed__)); + + +struct ngene_command { + u32 in_len; + u32 out_len; + union { + u32 raw[64]; + u8 raw8[256]; + struct FW_HEADER hdr; + struct FW_I2C_WRITE I2CWrite; + struct FW_I2C_CONTINUE_WRITE I2CContinueWrite; + struct FW_I2C_READ I2CRead; + struct FW_STREAM_CONTROL StreamControl; + struct FW_FWLOAD_PREPARE FWLoadPrepare; + struct FW_FWLOAD_FINISH FWLoadFinish; + struct FW_MEM_READ MemoryRead; + struct FW_MEM_WRITE MemoryWrite; + struct FW_SFR_IRAM_READ SfrIramRead; + struct FW_SFR_IRAM_WRITE SfrIramWrite; + struct FW_SPI_WRITE SPIWrite; + struct FW_SPI_READ SPIRead; + struct FW_SET_GPIO_PIN SetGpioPin; + struct FW_SET_GPIO_INT SetGpioInt; + struct FW_SET_DEBUGMODE SetDebugMode; + struct FW_CONFIGURE_BUFFERS ConfigureBuffers; + struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers; + struct FW_CONFIGURE_UART ConfigureUart; + struct FW_WRITE_UART WriteUart; + } cmd; +} __attribute__ ((__packed__)); + +#define NGENE_INTERFACE_VERSION 0x103 +#define MAX_VIDEO_BUFFER_SIZE (417792) /* 288*1440 rounded up to next page */ +#define MAX_AUDIO_BUFFER_SIZE (8192) /* Gives room for about 23msec@48KHz */ +#define MAX_VBI_BUFFER_SIZE (28672) /* 1144*18 rounded up to next page */ +#define MAX_TS_BUFFER_SIZE (98304) /* 512*188 rounded up to next page */ +#define MAX_HDTV_BUFFER_SIZE (2080768) /* 541*1920*2 rounded up to next page + Max: (1920x1080i60) */ + +#define OVERFLOW_BUFFER_SIZE (8192) + +#define RING_SIZE_VIDEO 4 +#define RING_SIZE_AUDIO 8 +#define RING_SIZE_TS 8 + +#define NUM_SCATTER_GATHER_ENTRIES 8 + +#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \ + RING_SIZE_VIDEO * 2) + \ + (MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \ + (MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \ + (RING_SIZE_VIDEO * PAGE_SIZE * 2) + \ + (RING_SIZE_AUDIO * PAGE_SIZE * 2) + \ + (RING_SIZE_TS * PAGE_SIZE * 4) + \ + 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE) + +#define EVENT_QUEUE_SIZE 16 + +/* Gathers the current state of a single channel. */ + +struct SBufferHeader { + struct BUFFER_HEADER ngeneBuffer; /* Physical descriptor */ + struct SBufferHeader *Next; + void *Buffer1; + struct HW_SCATTER_GATHER_ELEMENT *scList1; + void *Buffer2; + struct HW_SCATTER_GATHER_ELEMENT *scList2; +}; + +/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */ +#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63) + +enum HWSTATE { + HWSTATE_STOP, + HWSTATE_STARTUP, + HWSTATE_RUN, + HWSTATE_PAUSE, +}; + +enum KSSTATE { + KSSTATE_STOP, + KSSTATE_ACQUIRE, + KSSTATE_PAUSE, + KSSTATE_RUN, +}; + +struct SRingBufferDescriptor { + struct SBufferHeader *Head; /* Points to first buffer in ring buffer + structure*/ + u64 PAHead; /* Physical address of first buffer */ + u32 MemSize; /* Memory size of allocated ring buffers + (needed for freeing) */ + u32 NumBuffers; /* Number of buffers in the ring */ + u32 Buffer1Length; /* Allocated length of Buffer 1 */ + u32 Buffer2Length; /* Allocated length of Buffer 2 */ + void *SCListMem; /* Memory to hold scatter gather lists for this + ring */ + u64 PASCListMem; /* Physical address .. */ + u32 SCListMemSize; /* Size of this memory */ +}; + +enum STREAMMODEFLAGS { + StreamMode_NONE = 0, /* Stream not used */ + StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */ + StreamMode_TSIN = 2, /* Transport stream input (all) */ + StreamMode_HDTV = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60 + (only stream 0) */ + StreamMode_TSOUT = 8, /* Transport stream output (only stream 3) */ +}; + + +enum BufferExchangeFlags { + BEF_EVEN_FIELD = 0x00000001, + BEF_CONTINUATION = 0x00000002, + BEF_MORE_DATA = 0x00000004, + BEF_OVERFLOW = 0x00000008, + DF_SWAP32 = 0x00010000, +}; + +typedef void *(IBufferExchange)(void *, void *, u32, u32, u32); + +struct MICI_STREAMINFO { + IBufferExchange *pExchange; + IBufferExchange *pExchangeVBI; /* Secondary (VBI, ancillary) */ + u8 Stream; + u8 Flags; + u8 Mode; + u8 Reserved; + u16 nLinesVideo; + u16 nBytesPerLineVideo; + u16 nLinesVBI; + u16 nBytesPerLineVBI; + u32 CaptureLength; /* Used for audio and transport stream */ +}; + +/****************************************************************************/ +/* STRUCTS ******************************************************************/ +/****************************************************************************/ + +/* sound hardware definition */ +#define MIXER_ADDR_TVTUNER 0 +#define MIXER_ADDR_LAST 0 + +struct ngene_channel; + +/*struct sound chip*/ + +struct mychip { + struct ngene_channel *chan; + struct snd_card *card; + struct pci_dev *pci; + struct snd_pcm_substream *substream; + struct snd_pcm *pcm; + unsigned long port; + int irq; + spinlock_t mixer_lock; + spinlock_t lock; + int mixer_volume[MIXER_ADDR_LAST + 1][2]; + int capture_source[MIXER_ADDR_LAST + 1][2]; +}; + +#ifdef NGENE_V4L +struct ngene_overlay { + int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct ngene_tvnorm { + int v4l2_id; + char *name; + u16 swidth, sheight; /* scaled standard width, height */ + int tuner_norm; + int soundstd; +}; + +struct ngene_vopen { + struct ngene_channel *ch; + enum v4l2_priority prio; + int width; + int height; + int depth; + struct videobuf_queue vbuf_q; + struct videobuf_queue vbi; + int fourcc; + int picxcount; + int resources; + enum v4l2_buf_type type; + const struct ngene_format *fmt; + + const struct ngene_format *ovfmt; + struct ngene_overlay ov; +}; +#endif + +struct ngene_channel { + struct device device; + struct i2c_adapter i2c_adapter; + + struct ngene *dev; + int number; + int type; + int mode; + bool has_adapter; + bool has_demux; + + struct dvb_frontend *fe; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvbnet; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + int users; + struct video_device *v4l_dev; + struct dvb_device *ci_dev; + struct tasklet_struct demux_tasklet; + + struct SBufferHeader *nextBuffer; + enum KSSTATE State; + enum HWSTATE HWState; + u8 Stream; + u8 Flags; + u8 Mode; + IBufferExchange *pBufferExchange; + IBufferExchange *pBufferExchange2; + + spinlock_t state_lock; + u16 nLines; + u16 nBytesPerLine; + u16 nVBILines; + u16 nBytesPerVBILine; + u16 itumode; + u32 Capture1Length; + u32 Capture2Length; + struct SRingBufferDescriptor RingBuffer; + struct SRingBufferDescriptor TSRingBuffer; + struct SRingBufferDescriptor TSIdleBuffer; + + u32 DataFormatFlags; + + int AudioDTOUpdated; + u32 AudioDTOValue; + + int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t); + u8 lnbh; + + /* stuff from analog driver */ + + int minor; + struct mychip *mychip; + struct snd_card *soundcard; + u8 *evenbuffer; + u8 dma_on; + int soundstreamon; + int audiomute; + int soundbuffisallocated; + int sndbuffflag; + int tun_rdy; + int dec_rdy; + int tun_dec_rdy; + int lastbufferflag; + + struct ngene_tvnorm *tvnorms; + int tvnorm_num; + int tvnorm; + +#ifdef NGENE_V4L + int videousers; + struct v4l2_prio_state prio; + struct ngene_vopen init; + int resources; + struct v4l2_framebuffer fbuf; + struct ngene_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + spinlock_t s_lock; + struct semaphore reslock; +#endif + + int running; +}; + + +struct ngene_ci { + struct device device; + struct i2c_adapter i2c_adapter; + + struct ngene *dev; + struct dvb_ca_en50221 *en; +}; + +struct ngene; + +typedef void (rx_cb_t)(struct ngene *, u32, u8); +typedef void (tx_cb_t)(struct ngene *, u32); + +struct ngene { + int nr; + struct pci_dev *pci_dev; + unsigned char *iomem; + + /*struct i2c_adapter i2c_adapter;*/ + + u32 device_version; + u32 fw_interface_version; + u32 icounts; + bool msi_enabled; + bool cmd_timeout_workaround; + + u8 *CmdDoneByte; + int BootFirmware; + void *OverflowBuffer; + dma_addr_t PAOverflowBuffer; + void *FWInterfaceBuffer; + dma_addr_t PAFWInterfaceBuffer; + u8 *ngenetohost; + u8 *hosttongene; + + struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; + int EventQueueOverflowCount; + int EventQueueOverflowFlag; + struct tasklet_struct event_tasklet; + struct EVENT_BUFFER *EventBuffer; + int EventQueueWriteIndex; + int EventQueueReadIndex; + + wait_queue_head_t cmd_wq; + int cmd_done; + struct semaphore cmd_mutex; + struct semaphore stream_mutex; + struct semaphore pll_mutex; + struct semaphore i2c_switch_mutex; + int i2c_current_channel; + int i2c_current_bus; + spinlock_t cmd_lock; + + struct dvb_adapter adapter[MAX_STREAM]; + struct dvb_adapter *first_adapter; /* "one_adapter" modprobe opt */ + struct ngene_channel channel[MAX_STREAM]; + + struct ngene_info *card_info; + + tx_cb_t *TxEventNotify; + rx_cb_t *RxEventNotify; + int tx_busy; + wait_queue_head_t tx_wq; + wait_queue_head_t rx_wq; +#define UART_RBUF_LEN 4096 + u8 uart_rbuf[UART_RBUF_LEN]; + int uart_rp, uart_wp; + + u8 *tsout_buf; +#define TSOUT_BUF_SIZE (512*188*8) + struct dvb_ringbuffer tsout_rbuf; + + u8 *tsin_buf; +#define TSIN_BUF_SIZE (512*188*8) + struct dvb_ringbuffer tsin_rbuf; + + u8 *ain_buf; +#define AIN_BUF_SIZE (128*1024) + struct dvb_ringbuffer ain_rbuf; + + + u8 *vin_buf; +#define VIN_BUF_SIZE (4*1920*1080) + struct dvb_ringbuffer vin_rbuf; + + unsigned long exp_val; + int prev_cmd; + + struct ngene_ci ci; +}; + +struct ngene_info { + int type; +#define NGENE_APP 0 +#define NGENE_TERRATEC 1 +#define NGENE_SIDEWINDER 2 +#define NGENE_RACER 3 +#define NGENE_VIPER 4 +#define NGENE_PYTHON 5 +#define NGENE_VBOX_V1 6 +#define NGENE_VBOX_V2 7 + + int fw_version; + bool msi_supported; + char *name; + + int io_type[MAX_STREAM]; +#define NGENE_IO_NONE 0 +#define NGENE_IO_TV 1 +#define NGENE_IO_HDTV 2 +#define NGENE_IO_TSIN 4 +#define NGENE_IO_TSOUT 8 +#define NGENE_IO_AIN 16 + + void *fe_config[4]; + void *tuner_config[4]; + + int (*demod_attach[4])(struct ngene_channel *); + int (*tuner_attach[4])(struct ngene_channel *); + + u8 avf[4]; + u8 msp[4]; + u8 demoda[4]; + u8 lnb[4]; + int i2c_access; + u8 ntsc; + u8 tsf[4]; + u8 i2s[4]; + + int (*gate_ctrl)(struct dvb_frontend *, int); + int (*switch_ctrl)(struct ngene_channel *, int, int); +}; + +#ifdef NGENE_V4L +struct ngene_format{ + char *name; + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int format; + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift, vshift; /* for planar modes */ + int palette; +}; + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 + +struct ngene_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* ngene specific */ + const struct ngene_format *fmt; + int tvnorm; + int btformat; + int btswap; +}; +#endif + + +/* Provided by ngene-core.c */ +int __devinit ngene_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id); +void __devexit ngene_remove(struct pci_dev *pdev); +void ngene_shutdown(struct pci_dev *pdev); +int ngene_command(struct ngene *dev, struct ngene_command *com); +int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); +void set_transfer(struct ngene_channel *chan, int state); +void FillTSBuffer(void *Buffer, int Length, u32 Flags); + +/* Provided by ngene-i2c.c */ +int ngene_i2c_init(struct ngene *dev, int dev_nr); + +/* Provided by ngene-dvb.c */ +extern struct dvb_device ngene_dvbdev_ci; +void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); +void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); +int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed); +int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed); +int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, + int (*start_feed)(struct dvb_demux_feed *), + int (*stop_feed)(struct dvb_demux_feed *), + void *priv); +int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, + struct dvb_demux *dvbdemux, + struct dmx_frontend *hw_frontend, + struct dmx_frontend *mem_frontend, + struct dvb_adapter *dvb_adapter); + +#endif + +/* LocalWords: Endif + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ngene/ngene-i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,176 @@ +/* + * ngene-i2c.c: nGene PCIe bridge driver i2c functions + * + * Copyright (C) 2005-2007 Micronas + * + * Copyright (C) 2008-2009 Ralph Metzler + * Modifications for new nGene firmware, + * support for EEPROM-copying, + * support for new dual DVB-S2 card prototype + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +/* FIXME - some of these can probably be removed */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ngene.h" + +/* Firmware command for i2c operations */ +static int ngene_command_i2c_read(struct ngene *dev, u8 adr, + u8 *out, u8 outlen, u8 *in, u8 inlen, int flag) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_I2C_READ; + com.cmd.hdr.Length = outlen + 3; + com.cmd.I2CRead.Device = adr << 1; + memcpy(com.cmd.I2CRead.Data, out, outlen); + com.cmd.I2CRead.Data[outlen] = inlen; + com.cmd.I2CRead.Data[outlen + 1] = 0; + com.in_len = outlen + 3; + com.out_len = inlen + 1; + + if (ngene_command(dev, &com) < 0) + return -EIO; + + if ((com.cmd.raw8[0] >> 1) != adr) + return -EIO; + + if (flag) + memcpy(in, com.cmd.raw8, inlen + 1); + else + memcpy(in, com.cmd.raw8 + 1, inlen); + return 0; +} + +static int ngene_command_i2c_write(struct ngene *dev, u8 adr, + u8 *out, u8 outlen) +{ + struct ngene_command com; + + + com.cmd.hdr.Opcode = CMD_I2C_WRITE; + com.cmd.hdr.Length = outlen + 1; + com.cmd.I2CRead.Device = adr << 1; + memcpy(com.cmd.I2CRead.Data, out, outlen); + com.in_len = outlen + 1; + com.out_len = 1; + + if (ngene_command(dev, &com) < 0) + return -EIO; + + if (com.cmd.raw8[0] == 1) + return -EIO; + + return 0; +} + +static void ngene_i2c_set_bus(struct ngene *dev, int bus) +{ + if (!(dev->card_info->i2c_access & 2)) + return; + if (dev->i2c_current_bus == bus) + return; + + switch (bus) { + case 0: + ngene_command_gpio_set(dev, 3, 0); + ngene_command_gpio_set(dev, 2, 1); + break; + + case 1: + ngene_command_gpio_set(dev, 2, 0); + ngene_command_gpio_set(dev, 3, 1); + break; + } + dev->i2c_current_bus = bus; +} + +static int ngene_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg msg[], int num) +{ + struct ngene_channel *chan = + (struct ngene_channel *)i2c_get_adapdata(adapter); + struct ngene *dev = chan->dev; + + down(&dev->i2c_switch_mutex); + ngene_i2c_set_bus(dev, chan->number); + + if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD)) + if (!ngene_command_i2c_read(dev, msg[0].addr, + msg[0].buf, msg[0].len, + msg[1].buf, msg[1].len, 0)) + goto done; + + if (num == 1 && !(msg[0].flags & I2C_M_RD)) + if (!ngene_command_i2c_write(dev, msg[0].addr, + msg[0].buf, msg[0].len)) + goto done; + if (num == 1 && (msg[0].flags & I2C_M_RD)) + if (!ngene_command_i2c_read(dev, msg[0].addr, NULL, 0, + msg[0].buf, msg[0].len, 0)) + goto done; + + up(&dev->i2c_switch_mutex); + return -EIO; + +done: + up(&dev->i2c_switch_mutex); + return num; +} + + +static u32 ngene_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm ngene_i2c_algo = { + .master_xfer = ngene_i2c_master_xfer, + .functionality = ngene_i2c_functionality, +}; + +int ngene_i2c_init(struct ngene *dev, int dev_nr) +{ + struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter); + + i2c_set_adapdata(adap, &(dev->channel[dev_nr])); + + strcpy(adap->name, "nGene"); + + adap->algo = &ngene_i2c_algo; + adap->algo_data = (void *)&(dev->channel[dev_nr]); + adap->dev.parent = &dev->pci_dev->dev; + + return i2c_add_adapter(adap); +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,15 @@ +config DVB_PLUTO2 + tristate "Pluto2 cards" + depends on DVB_CORE && PCI && I2C + select I2C_ALGOBIT + select DVB_TDA1004X + help + Support for PCI cards based on the Pluto2 FPGA like the Satelco + Easywatch Mobile Terrestrial DVB-T Receiver. + + Since these cards have no MPEG decoder onboard, they transmit + only compressed MPEG data over the PCI bus, so you need + an external software decoder to watch TV on your computer. + + Say Y or M if you own such a device and want to use it. + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_PLUTO2) += pluto2.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/pluto2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/pluto2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/pluto2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pluto2/pluto2.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,822 @@ +/* + * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T] + * + * Copyright (C) 2005 Andreas Oberritter + * + * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/ + * by Dany Salman + * Copyright (c) 2004 TDF + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" +#include "tda1004x.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define DRIVER_NAME "pluto2" + +#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */ +#define REG_PCAR 0x0020 /* PC address register */ +#define REG_TSCR 0x0024 /* TS ctrl & status */ +#define REG_MISC 0x0028 /* miscellaneous */ +#define REG_MMAC 0x002c /* MSB MAC address */ +#define REG_IMAC 0x0030 /* ISB MAC address */ +#define REG_LMAC 0x0034 /* LSB MAC address */ +#define REG_SPID 0x0038 /* SPI data */ +#define REG_SLCS 0x003c /* serial links ctrl/status */ + +#define PID0_NOFIL (0x0001 << 16) +#define PIDn_ENP (0x0001 << 15) +#define PID0_END (0x0001 << 14) +#define PID0_AFIL (0x0001 << 13) +#define PIDn_PID (0x1fff << 0) + +#define TSCR_NBPACKETS (0x00ff << 24) +#define TSCR_DEM (0x0001 << 17) +#define TSCR_DE (0x0001 << 16) +#define TSCR_RSTN (0x0001 << 15) +#define TSCR_MSKO (0x0001 << 14) +#define TSCR_MSKA (0x0001 << 13) +#define TSCR_MSKL (0x0001 << 12) +#define TSCR_OVR (0x0001 << 11) +#define TSCR_AFUL (0x0001 << 10) +#define TSCR_LOCK (0x0001 << 9) +#define TSCR_IACK (0x0001 << 8) +#define TSCR_ADEF (0x007f << 0) + +#define MISC_DVR (0x0fff << 4) +#define MISC_ALED (0x0001 << 3) +#define MISC_FRST (0x0001 << 2) +#define MISC_LED1 (0x0001 << 1) +#define MISC_LED0 (0x0001 << 0) + +#define SPID_SPIDR (0x00ff << 0) + +#define SLCS_SCL (0x0001 << 7) +#define SLCS_SDA (0x0001 << 6) +#define SLCS_CSN (0x0001 << 2) +#define SLCS_OVR (0x0001 << 1) +#define SLCS_SWC (0x0001 << 0) + +#define TS_DMA_PACKETS (8) +#define TS_DMA_BYTES (188 * TS_DMA_PACKETS) + +#define I2C_ADDR_TDA10046 0x10 +#define I2C_ADDR_TUA6034 0xc2 +#define NHWFILTERS 8 + +struct pluto { + /* pci */ + struct pci_dev *pdev; + u8 __iomem *io_mem; + + /* dvb */ + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + unsigned int full_ts_users; + unsigned int users; + + /* i2c */ + struct i2c_algo_bit_data i2c_bit; + struct i2c_adapter i2c_adap; + unsigned int i2cbug; + + /* irq */ + unsigned int overflow; + unsigned int dead; + + /* dma */ + dma_addr_t dma_addr; + u8 dma_buf[TS_DMA_BYTES]; + u8 dummy[4096]; +}; + +static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed) +{ + return container_of(feed->demux, struct pluto, demux); +} + +static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe) +{ + return container_of(fe->dvb, struct pluto, dvb_adapter); +} + +static inline u32 pluto_readreg(struct pluto *pluto, u32 reg) +{ + return readl(&pluto->io_mem[reg]); +} + +static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val) +{ + writel(val, &pluto->io_mem[reg]); +} + +static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits) +{ + u32 val = readl(&pluto->io_mem[reg]); + val &= ~mask; + val |= bits; + writel(val, &pluto->io_mem[reg]); +} + +static void pluto_write_tscr(struct pluto *pluto, u32 val) +{ + /* set the number of packets */ + val &= ~TSCR_ADEF; + val |= TS_DMA_PACKETS / 2; + + pluto_writereg(pluto, REG_TSCR, val); +} + +static void pluto_setsda(void *data, int state) +{ + struct pluto *pluto = data; + + if (state) + pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA); + else + pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0); +} + +static void pluto_setscl(void *data, int state) +{ + struct pluto *pluto = data; + + if (state) + pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL); + else + pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0); + + /* try to detect i2c_inb() to workaround hardware bug: + * reset SDA to high after SCL has been set to low */ + if ((state) && (pluto->i2cbug == 0)) { + pluto->i2cbug = 1; + } else { + if ((!state) && (pluto->i2cbug == 1)) + pluto_setsda(pluto, 1); + pluto->i2cbug = 0; + } +} + +static int pluto_getsda(void *data) +{ + struct pluto *pluto = data; + + return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA; +} + +static int pluto_getscl(void *data) +{ + struct pluto *pluto = data; + + return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL; +} + +static void pluto_reset_frontend(struct pluto *pluto, int reenable) +{ + u32 val = pluto_readreg(pluto, REG_MISC); + + if (val & MISC_FRST) { + val &= ~MISC_FRST; + pluto_writereg(pluto, REG_MISC, val); + } + if (reenable) { + val |= MISC_FRST; + pluto_writereg(pluto, REG_MISC, val); + } +} + +static void pluto_reset_ts(struct pluto *pluto, int reenable) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + if (val & TSCR_RSTN) { + val &= ~TSCR_RSTN; + pluto_write_tscr(pluto, val); + } + if (reenable) { + val |= TSCR_RSTN; + pluto_write_tscr(pluto, val); + } +} + +static void pluto_set_dma_addr(struct pluto *pluto) +{ + pluto_writereg(pluto, REG_PCAR, pluto->dma_addr); +} + +static int __devinit pluto_dma_map(struct pluto *pluto) +{ + pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + + return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr); +} + +static void pluto_dma_unmap(struct pluto *pluto) +{ + pci_unmap_single(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); +} + +static int pluto_start_feed(struct dvb_demux_feed *f) +{ + struct pluto *pluto = feed_to_pluto(f); + + /* enable PID filtering */ + if (pluto->users++ == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0); + + if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) + pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid); + else if (pluto->full_ts_users++ == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL); + + return 0; +} + +static int pluto_stop_feed(struct dvb_demux_feed *f) +{ + struct pluto *pluto = feed_to_pluto(f); + + /* disable PID filtering */ + if (--pluto->users == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL); + + if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) + pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff); + else if (--pluto->full_ts_users == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0); + + return 0; +} + +static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) +{ + /* synchronize the DMA transfer with the CPU + * first so that we see updated contents. */ + pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + + /* Workaround for broken hardware: + * [1] On startup NBPACKETS seems to contain an uninitialized value, + * but no packets have been transferred. + * [2] Sometimes (actually very often) NBPACKETS stays at zero + * although one packet has been transferred. + * [3] Sometimes (actually rarely), the card gets into an erroneous + * mode where it continuously generates interrupts, claiming it + * has received nbpackets>TS_DMA_PACKETS packets, but no packet + * has been transferred. Only a reset seems to solve this + */ + if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { + unsigned int i = 0; + while (pluto->dma_buf[i] == 0x47) + i += 188; + nbpackets = i / 188; + if (i == 0) { + pluto_reset_ts(pluto, 1); + dev_printk(KERN_DEBUG, &pluto->pdev->dev, "resetting TS because of invalid packet counter\n"); + } + } + + dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets); + + /* clear the dma buffer. this is needed to be able to identify + * new valid ts packets above */ + memset(pluto->dma_buf, 0, nbpackets * 188); + + /* reset the dma address */ + pluto_set_dma_addr(pluto); + + /* sync the buffer and give it back to the card */ + pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); +} + +static irqreturn_t pluto_irq(int irq, void *dev_id) +{ + struct pluto *pluto = dev_id; + u32 tscr; + + /* check whether an interrupt occurred on this device */ + tscr = pluto_readreg(pluto, REG_TSCR); + if (!(tscr & (TSCR_DE | TSCR_OVR))) + return IRQ_NONE; + + if (tscr == 0xffffffff) { + if (pluto->dead == 0) + dev_err(&pluto->pdev->dev, "card has hung or been ejected.\n"); + /* It's dead Jim */ + pluto->dead = 1; + return IRQ_HANDLED; + } + + /* dma end interrupt */ + if (tscr & TSCR_DE) { + pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24); + /* overflow interrupt */ + if (tscr & TSCR_OVR) + pluto->overflow++; + if (pluto->overflow) { + dev_err(&pluto->pdev->dev, "overflow irq (%d)\n", + pluto->overflow); + pluto_reset_ts(pluto, 1); + pluto->overflow = 0; + } + } else if (tscr & TSCR_OVR) { + pluto->overflow++; + } + + /* ACK the interrupt */ + pluto_write_tscr(pluto, tscr | TSCR_IACK); + + return IRQ_HANDLED; +} + +static void __devinit pluto_enable_irqs(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + /* disable AFUL and LOCK interrupts */ + val |= (TSCR_MSKA | TSCR_MSKL); + /* enable DMA and OVERFLOW interrupts */ + val &= ~(TSCR_DEM | TSCR_MSKO); + /* clear pending interrupts */ + val |= TSCR_IACK; + + pluto_write_tscr(pluto, val); +} + +static void pluto_disable_irqs(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + /* disable all interrupts */ + val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL); + /* clear pending interrupts */ + val |= TSCR_IACK; + + pluto_write_tscr(pluto, val); +} + +static int __devinit pluto_hw_init(struct pluto *pluto) +{ + pluto_reset_frontend(pluto, 1); + + /* set automatic LED control by FPGA */ + pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED); + + /* set data endianess */ +#ifdef __LITTLE_ENDIAN + pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END); +#else + pluto_rw(pluto, REG_PIDn(0), PID0_END, 0); +#endif + /* map DMA and set address */ + pluto_dma_map(pluto); + pluto_set_dma_addr(pluto); + + /* enable interrupts */ + pluto_enable_irqs(pluto); + + /* reset TS logic */ + pluto_reset_ts(pluto, 1); + + return 0; +} + +static void pluto_hw_exit(struct pluto *pluto) +{ + /* disable interrupts */ + pluto_disable_irqs(pluto); + + pluto_reset_ts(pluto, 0); + + /* LED: disable automatic control, enable yellow, disable green */ + pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1); + + /* unmap DMA */ + pluto_dma_unmap(pluto); + + pluto_reset_frontend(pluto, 0); +} + +static inline u32 divide(u32 numerator, u32 denominator) +{ + if (denominator == 0) + return ~0; + + return DIV_ROUND_CLOSEST(numerator, denominator); +} + +/* LG Innotek TDTE-E001P (Infineon TUA6034) */ +static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct pluto *pluto = frontend_to_pluto(fe); + struct i2c_msg msg; + int ret; + u8 buf[4]; + u32 div; + + // Fref = 166.667 Hz + // Fref * 3 = 500.000 Hz + // IF = 36166667 + // IF / Fref = 217 + //div = divide(p->frequency + 36166667, 166667); + div = divide(p->frequency * 3, 500000) + 217; + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + + if (p->frequency < 611000000) + buf[2] = 0xb4; + else if (p->frequency < 811000000) + buf[2] = 0xbc; + else + buf[2] = 0xf4; + + // VHF: 174-230 MHz + // center: 350 MHz + // UHF: 470-862 MHz + if (p->frequency < 350000000) + buf[3] = 0x02; + else + buf[3] = 0x04; + + if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + buf[3] |= 0x08; + + if (sizeof(buf) == 6) { + buf[4] = buf[2]; + buf[4] &= ~0x1c; + buf[4] |= 0x18; + + buf[5] = (0 << 7) | (2 << 4); + } + + msg.addr = I2C_ADDR_TUA6034 >> 1; + msg.flags = 0; + msg.buf = buf; + msg.len = sizeof(buf); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = i2c_transfer(&pluto->i2c_adap, &msg, 1); + if (ret < 0) + return ret; + else if (ret == 0) + return -EREMOTEIO; + + return 0; +} + +static int pluto2_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct pluto *pluto = frontend_to_pluto(fe); + + return request_firmware(fw, name, &pluto->pdev->dev); +} + +static struct tda1004x_config pluto2_fe_config __devinitdata = { + .demod_address = I2C_ADDR_TDA10046 >> 1, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = pluto2_request_firmware, +}; + +static int __devinit frontend_init(struct pluto *pluto) +{ + int ret; + + pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap); + if (!pluto->fe) { + dev_err(&pluto->pdev->dev, "could not attach frontend\n"); + return -ENODEV; + } + pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params; + + ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe); + if (ret < 0) { + if (pluto->fe->ops.release) + pluto->fe->ops.release(pluto->fe); + return ret; + } + + return 0; +} + +static void __devinit pluto_read_rev(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR; + dev_info(&pluto->pdev->dev, "board revision %d.%d\n", + (val >> 12) & 0x0f, (val >> 4) & 0xff); +} + +static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac) +{ + u32 val = pluto_readreg(pluto, REG_MMAC); + mac[0] = (val >> 8) & 0xff; + mac[1] = (val >> 0) & 0xff; + + val = pluto_readreg(pluto, REG_IMAC); + mac[2] = (val >> 8) & 0xff; + mac[3] = (val >> 0) & 0xff; + + val = pluto_readreg(pluto, REG_LMAC); + mac[4] = (val >> 8) & 0xff; + mac[5] = (val >> 0) & 0xff; + + dev_info(&pluto->pdev->dev, "MAC %pM\n", mac); +} + +static int __devinit pluto_read_serial(struct pluto *pluto) +{ + struct pci_dev *pdev = pluto->pdev; + unsigned int i, j; + u8 __iomem *cis; + + cis = pci_iomap(pdev, 1, 0); + if (!cis) + return -EIO; + + dev_info(&pdev->dev, "S/N "); + + for (i = 0xe0; i < 0x100; i += 4) { + u32 val = readl(&cis[i]); + for (j = 0; j < 32; j += 8) { + if ((val & 0xff) == 0xff) + goto out; + printk("%c", val & 0xff); + val >>= 8; + } + } +out: + printk("\n"); + pci_iounmap(pdev, cis); + + return 0; +} + +static int __devinit pluto2_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct pluto *pluto; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret = -ENOMEM; + + pluto = kzalloc(sizeof(struct pluto), GFP_KERNEL); + if (!pluto) + goto out; + + pluto->pdev = pdev; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_kfree; + + /* enable interrupts */ + pci_write_config_dword(pdev, 0x6c, 0x8000); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret < 0) + goto err_pci_disable_device; + + pci_set_master(pdev); + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret < 0) + goto err_pci_disable_device; + + pluto->io_mem = pci_iomap(pdev, 0, 0x40); + if (!pluto->io_mem) { + ret = -EIO; + goto err_pci_release_regions; + } + + pci_set_drvdata(pdev, pluto); + + ret = request_irq(pdev->irq, pluto_irq, IRQF_SHARED, DRIVER_NAME, pluto); + if (ret < 0) + goto err_pci_iounmap; + + ret = pluto_hw_init(pluto); + if (ret < 0) + goto err_free_irq; + + /* i2c */ + i2c_set_adapdata(&pluto->i2c_adap, pluto); + strcpy(pluto->i2c_adap.name, DRIVER_NAME); + pluto->i2c_adap.owner = THIS_MODULE; + pluto->i2c_adap.dev.parent = &pdev->dev; + pluto->i2c_adap.algo_data = &pluto->i2c_bit; + pluto->i2c_bit.data = pluto; + pluto->i2c_bit.setsda = pluto_setsda; + pluto->i2c_bit.setscl = pluto_setscl; + pluto->i2c_bit.getsda = pluto_getsda; + pluto->i2c_bit.getscl = pluto_getscl; + pluto->i2c_bit.udelay = 10; + pluto->i2c_bit.timeout = 10; + + /* Raise SCL and SDA */ + pluto_setsda(pluto, 1); + pluto_setscl(pluto, 1); + + ret = i2c_bit_add_bus(&pluto->i2c_adap); + if (ret < 0) + goto err_pluto_hw_exit; + + /* dvb */ + ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, + THIS_MODULE, &pdev->dev, adapter_nr); + if (ret < 0) + goto err_i2c_del_adapter; + + dvb_adapter = &pluto->dvb_adapter; + + pluto_read_rev(pluto); + pluto_read_serial(pluto); + pluto_read_mac(pluto, dvb_adapter->proposed_mac); + + dvbdemux = &pluto->demux; + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = pluto_start_feed; + dvbdemux->stop_feed = pluto_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + + pluto->hw_frontend.source = DMX_FRONTEND_0; + pluto->mem_frontend.source = DMX_MEMORY_FE; + pluto->dmxdev.filternum = NHWFILTERS; + pluto->dmxdev.demux = dmx; + + ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + ret = dmx->add_frontend(dmx, &pluto->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + ret = dmx->add_frontend(dmx, &pluto->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &pluto->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = frontend_init(pluto); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx); +out: + return ret; + +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &pluto->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &pluto->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&pluto->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_i2c_del_adapter: + i2c_del_adapter(&pluto->i2c_adap); +err_pluto_hw_exit: + pluto_hw_exit(pluto); +err_free_irq: + free_irq(pdev->irq, pluto); +err_pci_iounmap: + pci_iounmap(pdev, pluto->io_mem); +err_pci_release_regions: + pci_release_regions(pdev); +err_pci_disable_device: + pci_disable_device(pdev); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(pluto); + goto out; +} + +static void __devexit pluto2_remove(struct pci_dev *pdev) +{ + struct pluto *pluto = pci_get_drvdata(pdev); + struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter; + struct dvb_demux *dvbdemux = &pluto->demux; + struct dmx_demux *dmx = &dvbdemux->dmx; + + dmx->close(dmx); + dvb_net_release(&pluto->dvbnet); + if (pluto->fe) + dvb_unregister_frontend(pluto->fe); + + dmx->disconnect_frontend(dmx); + dmx->remove_frontend(dmx, &pluto->mem_frontend); + dmx->remove_frontend(dmx, &pluto->hw_frontend); + dvb_dmxdev_release(&pluto->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_adapter(dvb_adapter); + i2c_del_adapter(&pluto->i2c_adap); + pluto_hw_exit(pluto); + free_irq(pdev->irq, pluto); + pci_iounmap(pdev, pluto->io_mem); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + kfree(pluto); +} + +#ifndef PCI_VENDOR_ID_SCM +#define PCI_VENDOR_ID_SCM 0x0432 +#endif +#ifndef PCI_DEVICE_ID_PLUTO2 +#define PCI_DEVICE_ID_PLUTO2 0x0001 +#endif + +static struct pci_device_id pluto2_id_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_SCM, + .device = PCI_DEVICE_ID_PLUTO2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + /* empty */ + }, +}; + +MODULE_DEVICE_TABLE(pci, pluto2_id_table); + +static struct pci_driver pluto2_driver = { + .name = DRIVER_NAME, + .id_table = pluto2_id_table, + .probe = pluto2_probe, + .remove = __devexit_p(pluto2_remove), +}; + +static int __init pluto2_init(void) +{ + return pci_register_driver(&pluto2_driver); +} + +static void __exit pluto2_exit(void) +{ + pci_unregister_driver(&pluto2_driver); +} + +module_init(pluto2_init); +module_exit(pluto2_exit); + +MODULE_AUTHOR("Andreas Oberritter "); +MODULE_DESCRIPTION("Pluto2 driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,12 @@ +config DVB_PT1 + tristate "PT1 cards" + depends on DVB_CORE && PCI && I2C + help + Support for Earthsoft PT1 PCI cards. + + Since these cards have no MPEG decoder onboard, they transmit + only compressed MPEG data over the PCI bus, so you need + an external software decoder to watch TV on your computer. + + Say Y or M if you own such a device and want to use it. + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,5 @@ +earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o + +obj-$(CONFIG_DVB_PT1) += earth-pt1.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/pt1.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/pt1.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/pt1.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/pt1.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1209 @@ +/* + * driver for Earthsoft PT1/PT2 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_net.h" +#include "dvb_frontend.h" + +#include "va1j5jf8007t.h" +#include "va1j5jf8007s.h" + +#define DRIVER_NAME "earth-pt1" + +#define PT1_PAGE_SHIFT 12 +#define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT) +#define PT1_NR_UPACKETS 1024 +#define PT1_NR_BUFS 511 + +struct pt1_buffer_page { + __le32 upackets[PT1_NR_UPACKETS]; +}; + +struct pt1_table_page { + __le32 next_pfn; + __le32 buf_pfns[PT1_NR_BUFS]; +}; + +struct pt1_buffer { + struct pt1_buffer_page *page; + dma_addr_t addr; +}; + +struct pt1_table { + struct pt1_table_page *page; + dma_addr_t addr; + struct pt1_buffer bufs[PT1_NR_BUFS]; +}; + +#define PT1_NR_ADAPS 4 + +struct pt1_adapter; + +struct pt1 { + struct pci_dev *pdev; + void __iomem *regs; + struct i2c_adapter i2c_adap; + int i2c_running; + struct pt1_adapter *adaps[PT1_NR_ADAPS]; + struct pt1_table *tables; + struct task_struct *kthread; + + struct mutex lock; + int power; + int reset; +}; + +struct pt1_adapter { + struct pt1 *pt1; + int index; + + u8 *buf; + int upacket_count; + int packet_count; + + struct dvb_adapter adap; + struct dvb_demux demux; + int users; + struct dmxdev dmxdev; + struct dvb_net net; + struct dvb_frontend *fe; + int (*orig_set_voltage)(struct dvb_frontend *fe, + fe_sec_voltage_t voltage); + int (*orig_sleep)(struct dvb_frontend *fe); + int (*orig_init)(struct dvb_frontend *fe); + + fe_sec_voltage_t voltage; + int sleep; +}; + +#define pt1_printk(level, pt1, format, arg...) \ + dev_printk(level, &(pt1)->pdev->dev, format, ##arg) + +static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data) +{ + writel(data, pt1->regs + reg * 4); +} + +static u32 pt1_read_reg(struct pt1 *pt1, int reg) +{ + return readl(pt1->regs + reg * 4); +} + +static int pt1_nr_tables = 64; +module_param_named(nr_tables, pt1_nr_tables, int, 0); + +static void pt1_increment_table_count(struct pt1 *pt1) +{ + pt1_write_reg(pt1, 0, 0x00000020); +} + +static void pt1_init_table_count(struct pt1 *pt1) +{ + pt1_write_reg(pt1, 0, 0x00000010); +} + +static void pt1_register_tables(struct pt1 *pt1, u32 first_pfn) +{ + pt1_write_reg(pt1, 5, first_pfn); + pt1_write_reg(pt1, 0, 0x0c000040); +} + +static void pt1_unregister_tables(struct pt1 *pt1) +{ + pt1_write_reg(pt1, 0, 0x08080000); +} + +static int pt1_sync(struct pt1 *pt1) +{ + int i; + for (i = 0; i < 57; i++) { + if (pt1_read_reg(pt1, 0) & 0x20000000) + return 0; + pt1_write_reg(pt1, 0, 0x00000008); + } + pt1_printk(KERN_ERR, pt1, "could not sync\n"); + return -EIO; +} + +static u64 pt1_identify(struct pt1 *pt1) +{ + int i; + u64 id; + id = 0; + for (i = 0; i < 57; i++) { + id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i; + pt1_write_reg(pt1, 0, 0x00000008); + } + return id; +} + +static int pt1_unlock(struct pt1 *pt1) +{ + int i; + pt1_write_reg(pt1, 0, 0x00000008); + for (i = 0; i < 3; i++) { + if (pt1_read_reg(pt1, 0) & 0x80000000) + return 0; + schedule_timeout_uninterruptible((HZ + 999) / 1000); + } + pt1_printk(KERN_ERR, pt1, "could not unlock\n"); + return -EIO; +} + +static int pt1_reset_pci(struct pt1 *pt1) +{ + int i; + pt1_write_reg(pt1, 0, 0x01010000); + pt1_write_reg(pt1, 0, 0x01000000); + for (i = 0; i < 10; i++) { + if (pt1_read_reg(pt1, 0) & 0x00000001) + return 0; + schedule_timeout_uninterruptible((HZ + 999) / 1000); + } + pt1_printk(KERN_ERR, pt1, "could not reset PCI\n"); + return -EIO; +} + +static int pt1_reset_ram(struct pt1 *pt1) +{ + int i; + pt1_write_reg(pt1, 0, 0x02020000); + pt1_write_reg(pt1, 0, 0x02000000); + for (i = 0; i < 10; i++) { + if (pt1_read_reg(pt1, 0) & 0x00000002) + return 0; + schedule_timeout_uninterruptible((HZ + 999) / 1000); + } + pt1_printk(KERN_ERR, pt1, "could not reset RAM\n"); + return -EIO; +} + +static int pt1_do_enable_ram(struct pt1 *pt1) +{ + int i, j; + u32 status; + status = pt1_read_reg(pt1, 0) & 0x00000004; + pt1_write_reg(pt1, 0, 0x00000002); + for (i = 0; i < 10; i++) { + for (j = 0; j < 1024; j++) { + if ((pt1_read_reg(pt1, 0) & 0x00000004) != status) + return 0; + } + schedule_timeout_uninterruptible((HZ + 999) / 1000); + } + pt1_printk(KERN_ERR, pt1, "could not enable RAM\n"); + return -EIO; +} + +static int pt1_enable_ram(struct pt1 *pt1) +{ + int i, ret; + int phase; + schedule_timeout_uninterruptible((HZ + 999) / 1000); + phase = pt1->pdev->device == 0x211a ? 128 : 166; + for (i = 0; i < phase; i++) { + ret = pt1_do_enable_ram(pt1); + if (ret < 0) + return ret; + } + return 0; +} + +static void pt1_disable_ram(struct pt1 *pt1) +{ + pt1_write_reg(pt1, 0, 0x0b0b0000); +} + +static void pt1_set_stream(struct pt1 *pt1, int index, int enabled) +{ + pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index); +} + +static void pt1_init_streams(struct pt1 *pt1) +{ + int i; + for (i = 0; i < PT1_NR_ADAPS; i++) + pt1_set_stream(pt1, i, 0); +} + +static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page) +{ + u32 upacket; + int i; + int index; + struct pt1_adapter *adap; + int offset; + u8 *buf; + + if (!page->upackets[PT1_NR_UPACKETS - 1]) + return 0; + + for (i = 0; i < PT1_NR_UPACKETS; i++) { + upacket = le32_to_cpu(page->upackets[i]); + index = (upacket >> 29) - 1; + if (index < 0 || index >= PT1_NR_ADAPS) + continue; + + adap = pt1->adaps[index]; + if (upacket >> 25 & 1) + adap->upacket_count = 0; + else if (!adap->upacket_count) + continue; + + buf = adap->buf; + offset = adap->packet_count * 188 + adap->upacket_count * 3; + buf[offset] = upacket >> 16; + buf[offset + 1] = upacket >> 8; + if (adap->upacket_count != 62) + buf[offset + 2] = upacket; + + if (++adap->upacket_count >= 63) { + adap->upacket_count = 0; + if (++adap->packet_count >= 21) { + dvb_dmx_swfilter_packets(&adap->demux, buf, 21); + adap->packet_count = 0; + } + } + } + + page->upackets[PT1_NR_UPACKETS - 1] = 0; + return 1; +} + +static int pt1_thread(void *data) +{ + struct pt1 *pt1; + int table_index; + int buf_index; + struct pt1_buffer_page *page; + + pt1 = data; + set_freezable(); + + table_index = 0; + buf_index = 0; + + while (!kthread_should_stop()) { + try_to_freeze(); + + page = pt1->tables[table_index].bufs[buf_index].page; + if (!pt1_filter(pt1, page)) { + schedule_timeout_interruptible((HZ + 999) / 1000); + continue; + } + + if (++buf_index >= PT1_NR_BUFS) { + pt1_increment_table_count(pt1); + buf_index = 0; + if (++table_index >= pt1_nr_tables) + table_index = 0; + } + } + + return 0; +} + +static void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr) +{ + dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr); +} + +static void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp) +{ + void *page; + dma_addr_t addr; + + page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr, + GFP_KERNEL); + if (page == NULL) + return NULL; + + BUG_ON(addr & (PT1_PAGE_SIZE - 1)); + BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1); + + *addrp = addr; + *pfnp = addr >> PT1_PAGE_SHIFT; + return page; +} + +static void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf) +{ + pt1_free_page(pt1, buf->page, buf->addr); +} + +static int +pt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf, u32 *pfnp) +{ + struct pt1_buffer_page *page; + dma_addr_t addr; + + page = pt1_alloc_page(pt1, &addr, pfnp); + if (page == NULL) + return -ENOMEM; + + page->upackets[PT1_NR_UPACKETS - 1] = 0; + + buf->page = page; + buf->addr = addr; + return 0; +} + +static void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table) +{ + int i; + + for (i = 0; i < PT1_NR_BUFS; i++) + pt1_cleanup_buffer(pt1, &table->bufs[i]); + + pt1_free_page(pt1, table->page, table->addr); +} + +static int +pt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp) +{ + struct pt1_table_page *page; + dma_addr_t addr; + int i, ret; + u32 buf_pfn; + + page = pt1_alloc_page(pt1, &addr, pfnp); + if (page == NULL) + return -ENOMEM; + + for (i = 0; i < PT1_NR_BUFS; i++) { + ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn); + if (ret < 0) + goto err; + + page->buf_pfns[i] = cpu_to_le32(buf_pfn); + } + + pt1_increment_table_count(pt1); + table->page = page; + table->addr = addr; + return 0; + +err: + while (i--) + pt1_cleanup_buffer(pt1, &table->bufs[i]); + + pt1_free_page(pt1, page, addr); + return ret; +} + +static void pt1_cleanup_tables(struct pt1 *pt1) +{ + struct pt1_table *tables; + int i; + + tables = pt1->tables; + pt1_unregister_tables(pt1); + + for (i = 0; i < pt1_nr_tables; i++) + pt1_cleanup_table(pt1, &tables[i]); + + vfree(tables); +} + +static int pt1_init_tables(struct pt1 *pt1) +{ + struct pt1_table *tables; + int i, ret; + u32 first_pfn, pfn; + + tables = vmalloc(sizeof(struct pt1_table) * pt1_nr_tables); + if (tables == NULL) + return -ENOMEM; + + pt1_init_table_count(pt1); + + i = 0; + if (pt1_nr_tables) { + ret = pt1_init_table(pt1, &tables[0], &first_pfn); + if (ret) + goto err; + i++; + } + + while (i < pt1_nr_tables) { + ret = pt1_init_table(pt1, &tables[i], &pfn); + if (ret) + goto err; + tables[i - 1].page->next_pfn = cpu_to_le32(pfn); + i++; + } + + tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn); + + pt1_register_tables(pt1, first_pfn); + pt1->tables = tables; + return 0; + +err: + while (i--) + pt1_cleanup_table(pt1, &tables[i]); + + vfree(tables); + return ret; +} + +static int pt1_start_feed(struct dvb_demux_feed *feed) +{ + struct pt1_adapter *adap; + adap = container_of(feed->demux, struct pt1_adapter, demux); + if (!adap->users++) + pt1_set_stream(adap->pt1, adap->index, 1); + return 0; +} + +static int pt1_stop_feed(struct dvb_demux_feed *feed) +{ + struct pt1_adapter *adap; + adap = container_of(feed->demux, struct pt1_adapter, demux); + if (!--adap->users) + pt1_set_stream(adap->pt1, adap->index, 0); + return 0; +} + +static void +pt1_update_power(struct pt1 *pt1) +{ + int bits; + int i; + struct pt1_adapter *adap; + static const int sleep_bits[] = { + 1 << 4, + 1 << 6 | 1 << 7, + 1 << 5, + 1 << 6 | 1 << 8, + }; + + bits = pt1->power | !pt1->reset << 3; + mutex_lock(&pt1->lock); + for (i = 0; i < PT1_NR_ADAPS; i++) { + adap = pt1->adaps[i]; + switch (adap->voltage) { + case SEC_VOLTAGE_13: /* actually 11V */ + bits |= 1 << 1; + break; + case SEC_VOLTAGE_18: /* actually 15V */ + bits |= 1 << 1 | 1 << 2; + break; + default: + break; + } + + /* XXX: The bits should be changed depending on adap->sleep. */ + bits |= sleep_bits[i]; + } + pt1_write_reg(pt1, 1, bits); + mutex_unlock(&pt1->lock); +} + +static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct pt1_adapter *adap; + + adap = container_of(fe->dvb, struct pt1_adapter, adap); + adap->voltage = voltage; + pt1_update_power(adap->pt1); + + if (adap->orig_set_voltage) + return adap->orig_set_voltage(fe, voltage); + else + return 0; +} + +static int pt1_sleep(struct dvb_frontend *fe) +{ + struct pt1_adapter *adap; + + adap = container_of(fe->dvb, struct pt1_adapter, adap); + adap->sleep = 1; + pt1_update_power(adap->pt1); + + if (adap->orig_sleep) + return adap->orig_sleep(fe); + else + return 0; +} + +static int pt1_wakeup(struct dvb_frontend *fe) +{ + struct pt1_adapter *adap; + + adap = container_of(fe->dvb, struct pt1_adapter, adap); + adap->sleep = 0; + pt1_update_power(adap->pt1); + schedule_timeout_uninterruptible((HZ + 999) / 1000); + + if (adap->orig_init) + return adap->orig_init(fe); + else + return 0; +} + +static void pt1_free_adapter(struct pt1_adapter *adap) +{ + dvb_net_release(&adap->net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->adap); + free_page((unsigned long)adap->buf); + kfree(adap); +} + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static struct pt1_adapter * +pt1_alloc_adapter(struct pt1 *pt1) +{ + struct pt1_adapter *adap; + void *buf; + struct dvb_adapter *dvb_adap; + struct dvb_demux *demux; + struct dmxdev *dmxdev; + int ret; + + adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL); + if (!adap) { + ret = -ENOMEM; + goto err; + } + + adap->pt1 = pt1; + + adap->voltage = SEC_VOLTAGE_OFF; + adap->sleep = 1; + + buf = (u8 *)__get_free_page(GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto err_kfree; + } + + adap->buf = buf; + adap->upacket_count = 0; + adap->packet_count = 0; + + dvb_adap = &adap->adap; + dvb_adap->priv = adap; + ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE, + &pt1->pdev->dev, adapter_nr); + if (ret < 0) + goto err_free_page; + + demux = &adap->demux; + demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + demux->priv = adap; + demux->feednum = 256; + demux->filternum = 256; + demux->start_feed = pt1_start_feed; + demux->stop_feed = pt1_stop_feed; + demux->write_to_decoder = NULL; + ret = dvb_dmx_init(demux); + if (ret < 0) + goto err_unregister_adapter; + + dmxdev = &adap->dmxdev; + dmxdev->filternum = 256; + dmxdev->demux = &demux->dmx; + dmxdev->capabilities = 0; + ret = dvb_dmxdev_init(dmxdev, dvb_adap); + if (ret < 0) + goto err_dmx_release; + + dvb_net_init(dvb_adap, &adap->net, &demux->dmx); + + return adap; + +err_dmx_release: + dvb_dmx_release(demux); +err_unregister_adapter: + dvb_unregister_adapter(dvb_adap); +err_free_page: + free_page((unsigned long)buf); +err_kfree: + kfree(adap); +err: + return ERR_PTR(ret); +} + +static void pt1_cleanup_adapters(struct pt1 *pt1) +{ + int i; + for (i = 0; i < PT1_NR_ADAPS; i++) + pt1_free_adapter(pt1->adaps[i]); +} + +static int pt1_init_adapters(struct pt1 *pt1) +{ + int i; + struct pt1_adapter *adap; + int ret; + + for (i = 0; i < PT1_NR_ADAPS; i++) { + adap = pt1_alloc_adapter(pt1); + if (IS_ERR(adap)) { + ret = PTR_ERR(adap); + goto err; + } + + adap->index = i; + pt1->adaps[i] = adap; + } + return 0; + +err: + while (i--) + pt1_free_adapter(pt1->adaps[i]); + + return ret; +} + +static void pt1_cleanup_frontend(struct pt1_adapter *adap) +{ + dvb_unregister_frontend(adap->fe); +} + +static int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe) +{ + int ret; + + adap->orig_set_voltage = fe->ops.set_voltage; + adap->orig_sleep = fe->ops.sleep; + adap->orig_init = fe->ops.init; + fe->ops.set_voltage = pt1_set_voltage; + fe->ops.sleep = pt1_sleep; + fe->ops.init = pt1_wakeup; + + ret = dvb_register_frontend(&adap->adap, fe); + if (ret < 0) + return ret; + + adap->fe = fe; + return 0; +} + +static void pt1_cleanup_frontends(struct pt1 *pt1) +{ + int i; + for (i = 0; i < PT1_NR_ADAPS; i++) + pt1_cleanup_frontend(pt1->adaps[i]); +} + +struct pt1_config { + struct va1j5jf8007s_config va1j5jf8007s_config; + struct va1j5jf8007t_config va1j5jf8007t_config; +}; + +static const struct pt1_config pt1_configs[2] = { + { + { + .demod_address = 0x1b, + .frequency = VA1J5JF8007S_20MHZ, + }, + { + .demod_address = 0x1a, + .frequency = VA1J5JF8007T_20MHZ, + }, + }, { + { + .demod_address = 0x19, + .frequency = VA1J5JF8007S_20MHZ, + }, + { + .demod_address = 0x18, + .frequency = VA1J5JF8007T_20MHZ, + }, + }, +}; + +static const struct pt1_config pt2_configs[2] = { + { + { + .demod_address = 0x1b, + .frequency = VA1J5JF8007S_25MHZ, + }, + { + .demod_address = 0x1a, + .frequency = VA1J5JF8007T_25MHZ, + }, + }, { + { + .demod_address = 0x19, + .frequency = VA1J5JF8007S_25MHZ, + }, + { + .demod_address = 0x18, + .frequency = VA1J5JF8007T_25MHZ, + }, + }, +}; + +static int pt1_init_frontends(struct pt1 *pt1) +{ + int i, j; + struct i2c_adapter *i2c_adap; + const struct pt1_config *configs, *config; + struct dvb_frontend *fe[4]; + int ret; + + i = 0; + j = 0; + + i2c_adap = &pt1->i2c_adap; + configs = pt1->pdev->device == 0x211a ? pt1_configs : pt2_configs; + do { + config = &configs[i / 2]; + + fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config, + i2c_adap); + if (!fe[i]) { + ret = -ENODEV; /* This does not sound nice... */ + goto err; + } + i++; + + fe[i] = va1j5jf8007t_attach(&config->va1j5jf8007t_config, + i2c_adap); + if (!fe[i]) { + ret = -ENODEV; + goto err; + } + i++; + + ret = va1j5jf8007s_prepare(fe[i - 2]); + if (ret < 0) + goto err; + + ret = va1j5jf8007t_prepare(fe[i - 1]); + if (ret < 0) + goto err; + + } while (i < 4); + + do { + ret = pt1_init_frontend(pt1->adaps[j], fe[j]); + if (ret < 0) + goto err; + } while (++j < 4); + + return 0; + +err: + while (i-- > j) + fe[i]->ops.release(fe[i]); + + while (j--) + dvb_unregister_frontend(fe[j]); + + return ret; +} + +static void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable, + int clock, int data, int next_addr) +{ + pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 | + !clock << 11 | !data << 10 | next_addr); +} + +static void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data) +{ + pt1_i2c_emit(pt1, addr, 1, 0, 0, data, addr + 1); + pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2); + pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3); + *addrp = addr + 3; +} + +static void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp) +{ + pt1_i2c_emit(pt1, addr, 1, 0, 0, 1, addr + 1); + pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2); + pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3); + pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4); + *addrp = addr + 4; +} + +static void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data) +{ + int i; + for (i = 0; i < 8; i++) + pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1); + pt1_i2c_write_bit(pt1, addr, &addr, 1); + *addrp = addr; +} + +static void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last) +{ + int i; + for (i = 0; i < 8; i++) + pt1_i2c_read_bit(pt1, addr, &addr); + pt1_i2c_write_bit(pt1, addr, &addr, last); + *addrp = addr; +} + +static void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp) +{ + pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); + pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); + pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3); + *addrp = addr + 3; +} + +static void +pt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) +{ + int i; + pt1_i2c_prepare(pt1, addr, &addr); + pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1); + for (i = 0; i < msg->len; i++) + pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]); + *addrp = addr; +} + +static void +pt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) +{ + int i; + pt1_i2c_prepare(pt1, addr, &addr); + pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1); + for (i = 0; i < msg->len; i++) + pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1); + *addrp = addr; +} + +static int pt1_i2c_end(struct pt1 *pt1, int addr) +{ + pt1_i2c_emit(pt1, addr, 1, 0, 0, 0, addr + 1); + pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); + pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0); + + pt1_write_reg(pt1, 0, 0x00000004); + do { + if (signal_pending(current)) + return -EINTR; + schedule_timeout_interruptible((HZ + 999) / 1000); + } while (pt1_read_reg(pt1, 0) & 0x00000080); + return 0; +} + +static void pt1_i2c_begin(struct pt1 *pt1, int *addrp) +{ + int addr; + addr = 0; + + pt1_i2c_emit(pt1, addr, 0, 0, 1, 1, addr /* itself */); + addr = addr + 1; + + if (!pt1->i2c_running) { + pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); + pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); + addr = addr + 2; + pt1->i2c_running = 1; + } + *addrp = addr; +} + +static int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct pt1 *pt1; + int i; + struct i2c_msg *msg, *next_msg; + int addr, ret; + u16 len; + u32 word; + + pt1 = i2c_get_adapdata(adap); + + for (i = 0; i < num; i++) { + msg = &msgs[i]; + if (msg->flags & I2C_M_RD) + return -ENOTSUPP; + + if (i + 1 < num) + next_msg = &msgs[i + 1]; + else + next_msg = NULL; + + if (next_msg && next_msg->flags & I2C_M_RD) { + i++; + + len = next_msg->len; + if (len > 4) + return -ENOTSUPP; + + pt1_i2c_begin(pt1, &addr); + pt1_i2c_write_msg(pt1, addr, &addr, msg); + pt1_i2c_read_msg(pt1, addr, &addr, next_msg); + ret = pt1_i2c_end(pt1, addr); + if (ret < 0) + return ret; + + word = pt1_read_reg(pt1, 2); + while (len--) { + next_msg->buf[len] = word; + word >>= 8; + } + } else { + pt1_i2c_begin(pt1, &addr); + pt1_i2c_write_msg(pt1, addr, &addr, msg); + ret = pt1_i2c_end(pt1, addr); + if (ret < 0) + return ret; + } + } + + return num; +} + +static u32 pt1_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static const struct i2c_algorithm pt1_i2c_algo = { + .master_xfer = pt1_i2c_xfer, + .functionality = pt1_i2c_func, +}; + +static void pt1_i2c_wait(struct pt1 *pt1) +{ + int i; + for (i = 0; i < 128; i++) + pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0); +} + +static void pt1_i2c_init(struct pt1 *pt1) +{ + int i; + for (i = 0; i < 1024; i++) + pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0); +} + +static void __devexit pt1_remove(struct pci_dev *pdev) +{ + struct pt1 *pt1; + void __iomem *regs; + + pt1 = pci_get_drvdata(pdev); + regs = pt1->regs; + + kthread_stop(pt1->kthread); + pt1_cleanup_tables(pt1); + pt1_cleanup_frontends(pt1); + pt1_disable_ram(pt1); + pt1->power = 0; + pt1->reset = 1; + pt1_update_power(pt1); + pt1_cleanup_adapters(pt1); + i2c_del_adapter(&pt1->i2c_adap); + pci_set_drvdata(pdev, NULL); + kfree(pt1); + pci_iounmap(pdev, regs); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static int __devinit +pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int ret; + void __iomem *regs; + struct pt1 *pt1; + struct i2c_adapter *i2c_adap; + struct task_struct *kthread; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err; + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret < 0) + goto err_pci_disable_device; + + pci_set_master(pdev); + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret < 0) + goto err_pci_disable_device; + + regs = pci_iomap(pdev, 0, 0); + if (!regs) { + ret = -EIO; + goto err_pci_release_regions; + } + + pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL); + if (!pt1) { + ret = -ENOMEM; + goto err_pci_iounmap; + } + + mutex_init(&pt1->lock); + pt1->pdev = pdev; + pt1->regs = regs; + pci_set_drvdata(pdev, pt1); + + ret = pt1_init_adapters(pt1); + if (ret < 0) + goto err_kfree; + + mutex_init(&pt1->lock); + + pt1->power = 0; + pt1->reset = 1; + pt1_update_power(pt1); + + i2c_adap = &pt1->i2c_adap; + i2c_adap->algo = &pt1_i2c_algo; + i2c_adap->algo_data = NULL; + i2c_adap->dev.parent = &pdev->dev; + strcpy(i2c_adap->name, DRIVER_NAME); + i2c_set_adapdata(i2c_adap, pt1); + ret = i2c_add_adapter(i2c_adap); + if (ret < 0) + goto err_pt1_cleanup_adapters; + + pt1_i2c_init(pt1); + pt1_i2c_wait(pt1); + + ret = pt1_sync(pt1); + if (ret < 0) + goto err_i2c_del_adapter; + + pt1_identify(pt1); + + ret = pt1_unlock(pt1); + if (ret < 0) + goto err_i2c_del_adapter; + + ret = pt1_reset_pci(pt1); + if (ret < 0) + goto err_i2c_del_adapter; + + ret = pt1_reset_ram(pt1); + if (ret < 0) + goto err_i2c_del_adapter; + + ret = pt1_enable_ram(pt1); + if (ret < 0) + goto err_i2c_del_adapter; + + pt1_init_streams(pt1); + + pt1->power = 1; + pt1_update_power(pt1); + schedule_timeout_uninterruptible((HZ + 49) / 50); + + pt1->reset = 0; + pt1_update_power(pt1); + schedule_timeout_uninterruptible((HZ + 999) / 1000); + + ret = pt1_init_frontends(pt1); + if (ret < 0) + goto err_pt1_disable_ram; + + ret = pt1_init_tables(pt1); + if (ret < 0) + goto err_pt1_cleanup_frontends; + + kthread = kthread_run(pt1_thread, pt1, "pt1"); + if (IS_ERR(kthread)) { + ret = PTR_ERR(kthread); + goto err_pt1_cleanup_tables; + } + + pt1->kthread = kthread; + return 0; + +err_pt1_cleanup_tables: + pt1_cleanup_tables(pt1); +err_pt1_cleanup_frontends: + pt1_cleanup_frontends(pt1); +err_pt1_disable_ram: + pt1_disable_ram(pt1); + pt1->power = 0; + pt1->reset = 1; + pt1_update_power(pt1); +err_i2c_del_adapter: + i2c_del_adapter(i2c_adap); +err_pt1_cleanup_adapters: + pt1_cleanup_adapters(pt1); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(pt1); +err_pci_iounmap: + pci_iounmap(pdev, regs); +err_pci_release_regions: + pci_release_regions(pdev); +err_pci_disable_device: + pci_disable_device(pdev); +err: + return ret; + +} + +static struct pci_device_id pt1_id_table[] = { + { PCI_DEVICE(0x10ee, 0x211a) }, + { PCI_DEVICE(0x10ee, 0x222a) }, + { }, +}; +MODULE_DEVICE_TABLE(pci, pt1_id_table); + +static struct pci_driver pt1_driver = { + .name = DRIVER_NAME, + .probe = pt1_probe, + .remove = __devexit_p(pt1_remove), + .id_table = pt1_id_table, +}; + + +static int __init pt1_init(void) +{ + return pci_register_driver(&pt1_driver); +} + + +static void __exit pt1_cleanup(void) +{ + pci_unregister_driver(&pt1_driver); +} + +module_init(pt1_init); +module_exit(pt1_cleanup); + +MODULE_AUTHOR("Takahito HIRANO "); +MODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007s.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007s.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007s.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007s.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,735 @@ +/* + * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "va1j5jf8007s.h" + +enum va1j5jf8007s_tune_state { + VA1J5JF8007S_IDLE, + VA1J5JF8007S_SET_FREQUENCY_1, + VA1J5JF8007S_SET_FREQUENCY_2, + VA1J5JF8007S_SET_FREQUENCY_3, + VA1J5JF8007S_CHECK_FREQUENCY, + VA1J5JF8007S_SET_MODULATION, + VA1J5JF8007S_CHECK_MODULATION, + VA1J5JF8007S_SET_TS_ID, + VA1J5JF8007S_CHECK_TS_ID, + VA1J5JF8007S_TRACK, +}; + +struct va1j5jf8007s_state { + const struct va1j5jf8007s_config *config; + struct i2c_adapter *adap; + struct dvb_frontend fe; + enum va1j5jf8007s_tune_state tune_state; +}; + +static int va1j5jf8007s_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct va1j5jf8007s_state *state; + u8 addr; + int i; + u8 write_buf[1], read_buf[1]; + struct i2c_msg msgs[2]; + s32 word, x1, x2, x3, x4, x5, y; + + state = fe->demodulator_priv; + addr = state->config->demod_address; + + word = 0; + for (i = 0; i < 2; i++) { + write_buf[0] = 0xbc + i; + + msgs[0].addr = addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(write_buf); + msgs[0].buf = write_buf; + + msgs[1].addr = addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(read_buf); + msgs[1].buf = read_buf; + + if (i2c_transfer(state->adap, msgs, 2) != 2) + return -EREMOTEIO; + + word <<= 8; + word |= read_buf[0]; + } + + word -= 3000; + if (word < 0) + word = 0; + + x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000); + x2 = (s64)x1 * x1 >> 31; + x3 = (s64)x2 * x1 >> 31; + x4 = (s64)x2 * x2 >> 31; + x5 = (s64)x4 * x1 >> 31; + + y = (58857ll << 23) / 1000; + y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30; + y += (s64)x2 * ((88977ll << 24) / 1000) >> 28; + y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27; + y += (s64)x4 * ((14341ll << 27) / 1000) >> 27; + y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28; + + *snr = y < 0 ? 0 : y >> 15; + return 0; +} + +static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +static int +va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct va1j5jf8007s_state *state; + + state = fe->demodulator_priv; + + switch (state->tune_state) { + case VA1J5JF8007S_IDLE: + case VA1J5JF8007S_SET_FREQUENCY_1: + case VA1J5JF8007S_SET_FREQUENCY_2: + case VA1J5JF8007S_SET_FREQUENCY_3: + case VA1J5JF8007S_CHECK_FREQUENCY: + *status = 0; + return 0; + + + case VA1J5JF8007S_SET_MODULATION: + case VA1J5JF8007S_CHECK_MODULATION: + *status |= FE_HAS_SIGNAL; + return 0; + + case VA1J5JF8007S_SET_TS_ID: + case VA1J5JF8007S_CHECK_TS_ID: + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + return 0; + + case VA1J5JF8007S_TRACK: + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; + } + + BUG(); +} + +struct va1j5jf8007s_cb_map { + u32 frequency; + u8 cb; +}; + +static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = { + { 986000, 0xb2 }, + { 1072000, 0xd2 }, + { 1154000, 0xe2 }, + { 1291000, 0x20 }, + { 1447000, 0x40 }, + { 1615000, 0x60 }, + { 1791000, 0x80 }, + { 1972000, 0xa0 }, +}; + +static u8 va1j5jf8007s_lookup_cb(u32 frequency) +{ + int i; + const struct va1j5jf8007s_cb_map *map; + + for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) { + map = &va1j5jf8007s_cb_maps[i]; + if (frequency < map->frequency) + return map->cb; + } + return 0xc0; +} + +static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state) +{ + u32 frequency; + u16 word; + u8 buf[6]; + struct i2c_msg msg; + + frequency = state->fe.dtv_property_cache.frequency; + + word = (frequency + 500) / 1000; + if (frequency < 1072000) + word = (word << 1 & ~0x1f) | (word & 0x0f); + + buf[0] = 0xfe; + buf[1] = 0xc0; + buf[2] = 0x40 | word >> 8; + buf[3] = word; + buf[4] = 0xe0; + buf[5] = va1j5jf8007s_lookup_cb(frequency); + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state) +{ + u8 buf[3]; + struct i2c_msg msg; + + buf[0] = 0xfe; + buf[1] = 0xc0; + buf[2] = 0xe4; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state) +{ + u32 frequency; + u8 buf[4]; + struct i2c_msg msg; + + frequency = state->fe.dtv_property_cache.frequency; + + buf[0] = 0xfe; + buf[1] = 0xc0; + buf[2] = 0xf4; + buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int +va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock) +{ + u8 addr; + u8 write_buf[2], read_buf[1]; + struct i2c_msg msgs[2]; + + addr = state->config->demod_address; + + write_buf[0] = 0xfe; + write_buf[1] = 0xc1; + + msgs[0].addr = addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(write_buf); + msgs[0].buf = write_buf; + + msgs[1].addr = addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(read_buf); + msgs[1].buf = read_buf; + + if (i2c_transfer(state->adap, msgs, 2) != 2) + return -EREMOTEIO; + + *lock = read_buf[0] & 0x40; + return 0; +} + +static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state) +{ + u8 buf[2]; + struct i2c_msg msg; + + buf[0] = 0x03; + buf[1] = 0x01; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int +va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock) +{ + u8 addr; + u8 write_buf[1], read_buf[1]; + struct i2c_msg msgs[2]; + + addr = state->config->demod_address; + + write_buf[0] = 0xc3; + + msgs[0].addr = addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(write_buf); + msgs[0].buf = write_buf; + + msgs[1].addr = addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(read_buf); + msgs[1].buf = read_buf; + + if (i2c_transfer(state->adap, msgs, 2) != 2) + return -EREMOTEIO; + + *lock = !(read_buf[0] & 0x10); + return 0; +} + +static int +va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state) +{ + u32 ts_id; + u8 buf[3]; + struct i2c_msg msg; + + ts_id = state->fe.dtv_property_cache.isdbs_ts_id; + if (!ts_id) + return 0; + + buf[0] = 0x8f; + buf[1] = ts_id >> 8; + buf[2] = ts_id; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int +va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock) +{ + u8 addr; + u8 write_buf[1], read_buf[2]; + struct i2c_msg msgs[2]; + u32 ts_id; + + ts_id = state->fe.dtv_property_cache.isdbs_ts_id; + if (!ts_id) { + *lock = 1; + return 0; + } + + addr = state->config->demod_address; + + write_buf[0] = 0xe6; + + msgs[0].addr = addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(write_buf); + msgs[0].buf = write_buf; + + msgs[1].addr = addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(read_buf); + msgs[1].buf = read_buf; + + if (i2c_transfer(state->adap, msgs, 2) != 2) + return -EREMOTEIO; + + *lock = (read_buf[0] << 8 | read_buf[1]) == ts_id; + return 0; +} + +static int +va1j5jf8007s_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + unsigned int mode_flags, unsigned int *delay, + fe_status_t *status) +{ + struct va1j5jf8007s_state *state; + int ret; + int lock = 0; + + state = fe->demodulator_priv; + + if (params != NULL) + state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1; + + switch (state->tune_state) { + case VA1J5JF8007S_IDLE: + *delay = 3 * HZ; + *status = 0; + return 0; + + case VA1J5JF8007S_SET_FREQUENCY_1: + ret = va1j5jf8007s_set_frequency_1(state); + if (ret < 0) + return ret; + + state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2; + *delay = 0; + *status = 0; + return 0; + + case VA1J5JF8007S_SET_FREQUENCY_2: + ret = va1j5jf8007s_set_frequency_2(state); + if (ret < 0) + return ret; + + state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3; + *delay = (HZ + 99) / 100; + *status = 0; + return 0; + + case VA1J5JF8007S_SET_FREQUENCY_3: + ret = va1j5jf8007s_set_frequency_3(state); + if (ret < 0) + return ret; + + state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY; + *delay = 0; + *status = 0; + return 0; + + case VA1J5JF8007S_CHECK_FREQUENCY: + ret = va1j5jf8007s_check_frequency(state, &lock); + if (ret < 0) + return ret; + + if (!lock) { + *delay = (HZ + 999) / 1000; + *status = 0; + return 0; + } + + state->tune_state = VA1J5JF8007S_SET_MODULATION; + *delay = 0; + *status = FE_HAS_SIGNAL; + return 0; + + case VA1J5JF8007S_SET_MODULATION: + ret = va1j5jf8007s_set_modulation(state); + if (ret < 0) + return ret; + + state->tune_state = VA1J5JF8007S_CHECK_MODULATION; + *delay = 0; + *status = FE_HAS_SIGNAL; + return 0; + + case VA1J5JF8007S_CHECK_MODULATION: + ret = va1j5jf8007s_check_modulation(state, &lock); + if (ret < 0) + return ret; + + if (!lock) { + *delay = (HZ + 49) / 50; + *status = FE_HAS_SIGNAL; + return 0; + } + + state->tune_state = VA1J5JF8007S_SET_TS_ID; + *delay = 0; + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + return 0; + + case VA1J5JF8007S_SET_TS_ID: + ret = va1j5jf8007s_set_ts_id(state); + if (ret < 0) + return ret; + + state->tune_state = VA1J5JF8007S_CHECK_TS_ID; + return 0; + + case VA1J5JF8007S_CHECK_TS_ID: + ret = va1j5jf8007s_check_ts_id(state, &lock); + if (ret < 0) + return ret; + + if (!lock) { + *delay = (HZ + 99) / 100; + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + return 0; + } + + state->tune_state = VA1J5JF8007S_TRACK; + /* fall through */ + + case VA1J5JF8007S_TRACK: + *delay = 3 * HZ; + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; + } + + BUG(); +} + +static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state) +{ + u8 buf[4]; + struct i2c_msg msg; + + buf[0] = 0xfe; + buf[1] = 0xc0; + buf[2] = 0xf0; + buf[3] = 0x04; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep) +{ + u8 buf[2]; + struct i2c_msg msg; + + buf[0] = 0x17; + buf[1] = sleep ? 0x01 : 0x00; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int va1j5jf8007s_sleep(struct dvb_frontend *fe) +{ + struct va1j5jf8007s_state *state; + int ret; + + state = fe->demodulator_priv; + + ret = va1j5jf8007s_init_frequency(state); + if (ret < 0) + return ret; + + return va1j5jf8007s_set_sleep(state, 1); +} + +static int va1j5jf8007s_init(struct dvb_frontend *fe) +{ + struct va1j5jf8007s_state *state; + + state = fe->demodulator_priv; + state->tune_state = VA1J5JF8007S_IDLE; + + return va1j5jf8007s_set_sleep(state, 0); +} + +static void va1j5jf8007s_release(struct dvb_frontend *fe) +{ + struct va1j5jf8007s_state *state; + state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops va1j5jf8007s_ops = { + .info = { + .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, + .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, + }, + + .read_snr = va1j5jf8007s_read_snr, + .get_frontend_algo = va1j5jf8007s_get_frontend_algo, + .read_status = va1j5jf8007s_read_status, + .tune = va1j5jf8007s_tune, + .sleep = va1j5jf8007s_sleep, + .init = va1j5jf8007s_init, + .release = va1j5jf8007s_release, +}; + +static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state) +{ + u8 addr; + u8 write_buf[1], read_buf[1]; + struct i2c_msg msgs[2]; + + addr = state->config->demod_address; + + write_buf[0] = 0x07; + + msgs[0].addr = addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(write_buf); + msgs[0].buf = write_buf; + + msgs[1].addr = addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(read_buf); + msgs[1].buf = read_buf; + + if (i2c_transfer(state->adap, msgs, 2) != 2) + return -EREMOTEIO; + + if (read_buf[0] != 0x41) + return -EIO; + + return 0; +} + +static const u8 va1j5jf8007s_20mhz_prepare_bufs[][2] = { + {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, + {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, + {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, + {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0}, +}; + +static const u8 va1j5jf8007s_25mhz_prepare_bufs[][2] = { + {0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a}, + {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89}, + {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04}, + {0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0}, +}; + +static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state) +{ + const u8 (*bufs)[2]; + int size; + u8 addr; + u8 buf[2]; + struct i2c_msg msg; + int i; + + switch (state->config->frequency) { + case VA1J5JF8007S_20MHZ: + bufs = va1j5jf8007s_20mhz_prepare_bufs; + size = ARRAY_SIZE(va1j5jf8007s_20mhz_prepare_bufs); + break; + case VA1J5JF8007S_25MHZ: + bufs = va1j5jf8007s_25mhz_prepare_bufs; + size = ARRAY_SIZE(va1j5jf8007s_25mhz_prepare_bufs); + break; + default: + return -EINVAL; + } + + addr = state->config->demod_address; + + msg.addr = addr; + msg.flags = 0; + msg.len = 2; + msg.buf = buf; + for (i = 0; i < size; i++) { + memcpy(buf, bufs[i], sizeof(buf)); + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + } + + return 0; +} + +/* must be called after va1j5jf8007t_attach */ +int va1j5jf8007s_prepare(struct dvb_frontend *fe) +{ + struct va1j5jf8007s_state *state; + int ret; + + state = fe->demodulator_priv; + + ret = va1j5jf8007s_prepare_1(state); + if (ret < 0) + return ret; + + ret = va1j5jf8007s_prepare_2(state); + if (ret < 0) + return ret; + + return va1j5jf8007s_init_frequency(state); +} + +struct dvb_frontend * +va1j5jf8007s_attach(const struct va1j5jf8007s_config *config, + struct i2c_adapter *adap) +{ + struct va1j5jf8007s_state *state; + struct dvb_frontend *fe; + u8 buf[2]; + struct i2c_msg msg; + + state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL); + if (!state) + return NULL; + + state->config = config; + state->adap = adap; + + fe = &state->fe; + memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops)); + fe->demodulator_priv = state; + + buf[0] = 0x01; + buf[1] = 0x80; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) { + kfree(state); + return NULL; + } + + return fe; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007s.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007s.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007s.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007s.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * ISDB-S driver for VA1J5JF8007/VA1J5JF8011 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef VA1J5JF8007S_H +#define VA1J5JF8007S_H + +enum va1j5jf8007s_frequency { + VA1J5JF8007S_20MHZ, + VA1J5JF8007S_25MHZ, +}; + +struct va1j5jf8007s_config { + u8 demod_address; + enum va1j5jf8007s_frequency frequency; +}; + +struct i2c_adapter; + +struct dvb_frontend * +va1j5jf8007s_attach(const struct va1j5jf8007s_config *config, + struct i2c_adapter *adap); + +/* must be called after va1j5jf8007t_attach */ +int va1j5jf8007s_prepare(struct dvb_frontend *fe); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007t.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007t.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007t.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007t.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,536 @@ +/* + * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "dvb_math.h" +#include "va1j5jf8007t.h" + +enum va1j5jf8007t_tune_state { + VA1J5JF8007T_IDLE, + VA1J5JF8007T_SET_FREQUENCY, + VA1J5JF8007T_CHECK_FREQUENCY, + VA1J5JF8007T_SET_MODULATION, + VA1J5JF8007T_CHECK_MODULATION, + VA1J5JF8007T_TRACK, + VA1J5JF8007T_ABORT, +}; + +struct va1j5jf8007t_state { + const struct va1j5jf8007t_config *config; + struct i2c_adapter *adap; + struct dvb_frontend fe; + enum va1j5jf8007t_tune_state tune_state; +}; + +static int va1j5jf8007t_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct va1j5jf8007t_state *state; + u8 addr; + int i; + u8 write_buf[1], read_buf[1]; + struct i2c_msg msgs[2]; + s32 word, x, y; + + state = fe->demodulator_priv; + addr = state->config->demod_address; + + word = 0; + for (i = 0; i < 3; i++) { + write_buf[0] = 0x8b + i; + + msgs[0].addr = addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(write_buf); + msgs[0].buf = write_buf; + + msgs[1].addr = addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(read_buf); + msgs[1].buf = read_buf; + + if (i2c_transfer(state->adap, msgs, 2) != 2) + return -EREMOTEIO; + + word <<= 8; + word |= read_buf[0]; + } + + if (!word) + return -EIO; + + x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24)); + y = (24ll << 46) / 1000000; + y = ((s64)y * x >> 30) - (16ll << 40) / 10000; + y = ((s64)y * x >> 29) + (398ll << 35) / 10000; + y = ((s64)y * x >> 30) + (5491ll << 29) / 10000; + y = ((s64)y * x >> 30) + (30965ll << 23) / 10000; + *snr = y >> 15; + return 0; +} + +static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +static int +va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct va1j5jf8007t_state *state; + + state = fe->demodulator_priv; + + switch (state->tune_state) { + case VA1J5JF8007T_IDLE: + case VA1J5JF8007T_SET_FREQUENCY: + case VA1J5JF8007T_CHECK_FREQUENCY: + *status = 0; + return 0; + + + case VA1J5JF8007T_SET_MODULATION: + case VA1J5JF8007T_CHECK_MODULATION: + case VA1J5JF8007T_ABORT: + *status |= FE_HAS_SIGNAL; + return 0; + + case VA1J5JF8007T_TRACK: + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; + } + + BUG(); +} + +struct va1j5jf8007t_cb_map { + u32 frequency; + u8 cb; +}; + +static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = { + { 90000000, 0x80 }, + { 140000000, 0x81 }, + { 170000000, 0xa1 }, + { 220000000, 0x62 }, + { 330000000, 0xa2 }, + { 402000000, 0xe2 }, + { 450000000, 0x64 }, + { 550000000, 0x84 }, + { 600000000, 0xa4 }, + { 700000000, 0xc4 }, +}; + +static u8 va1j5jf8007t_lookup_cb(u32 frequency) +{ + int i; + const struct va1j5jf8007t_cb_map *map; + + for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) { + map = &va1j5jf8007t_cb_maps[i]; + if (frequency < map->frequency) + return map->cb; + } + return 0xe4; +} + +static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state) +{ + u32 frequency; + u16 word; + u8 buf[6]; + struct i2c_msg msg; + + frequency = state->fe.dtv_property_cache.frequency; + + word = (frequency + 71428) / 142857 + 399; + buf[0] = 0xfe; + buf[1] = 0xc2; + buf[2] = word >> 8; + buf[3] = word; + buf[4] = 0x80; + buf[5] = va1j5jf8007t_lookup_cb(frequency); + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int +va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock) +{ + u8 addr; + u8 write_buf[2], read_buf[1]; + struct i2c_msg msgs[2]; + + addr = state->config->demod_address; + + write_buf[0] = 0xfe; + write_buf[1] = 0xc3; + + msgs[0].addr = addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(write_buf); + msgs[0].buf = write_buf; + + msgs[1].addr = addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(read_buf); + msgs[1].buf = read_buf; + + if (i2c_transfer(state->adap, msgs, 2) != 2) + return -EREMOTEIO; + + *lock = read_buf[0] & 0x40; + return 0; +} + +static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state) +{ + u8 buf[2]; + struct i2c_msg msg; + + buf[0] = 0x01; + buf[1] = 0x40; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state, + int *lock, int *retry) +{ + u8 addr; + u8 write_buf[1], read_buf[1]; + struct i2c_msg msgs[2]; + + addr = state->config->demod_address; + + write_buf[0] = 0x80; + + msgs[0].addr = addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(write_buf); + msgs[0].buf = write_buf; + + msgs[1].addr = addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(read_buf); + msgs[1].buf = read_buf; + + if (i2c_transfer(state->adap, msgs, 2) != 2) + return -EREMOTEIO; + + *lock = !(read_buf[0] & 0x10); + *retry = read_buf[0] & 0x80; + return 0; +} + +static int +va1j5jf8007t_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + unsigned int mode_flags, unsigned int *delay, + fe_status_t *status) +{ + struct va1j5jf8007t_state *state; + int ret; + int lock = 0, retry = 0; + + state = fe->demodulator_priv; + + if (params != NULL) + state->tune_state = VA1J5JF8007T_SET_FREQUENCY; + + switch (state->tune_state) { + case VA1J5JF8007T_IDLE: + *delay = 3 * HZ; + *status = 0; + return 0; + + case VA1J5JF8007T_SET_FREQUENCY: + ret = va1j5jf8007t_set_frequency(state); + if (ret < 0) + return ret; + + state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY; + *delay = 0; + *status = 0; + return 0; + + case VA1J5JF8007T_CHECK_FREQUENCY: + ret = va1j5jf8007t_check_frequency(state, &lock); + if (ret < 0) + return ret; + + if (!lock) { + *delay = (HZ + 999) / 1000; + *status = 0; + return 0; + } + + state->tune_state = VA1J5JF8007T_SET_MODULATION; + *delay = 0; + *status = FE_HAS_SIGNAL; + return 0; + + case VA1J5JF8007T_SET_MODULATION: + ret = va1j5jf8007t_set_modulation(state); + if (ret < 0) + return ret; + + state->tune_state = VA1J5JF8007T_CHECK_MODULATION; + *delay = 0; + *status = FE_HAS_SIGNAL; + return 0; + + case VA1J5JF8007T_CHECK_MODULATION: + ret = va1j5jf8007t_check_modulation(state, &lock, &retry); + if (ret < 0) + return ret; + + if (!lock) { + if (!retry) { + state->tune_state = VA1J5JF8007T_ABORT; + *delay = 3 * HZ; + *status = FE_HAS_SIGNAL; + return 0; + } + *delay = (HZ + 999) / 1000; + *status = FE_HAS_SIGNAL; + return 0; + } + + state->tune_state = VA1J5JF8007T_TRACK; + /* fall through */ + + case VA1J5JF8007T_TRACK: + *delay = 3 * HZ; + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; + + case VA1J5JF8007T_ABORT: + *delay = 3 * HZ; + *status = FE_HAS_SIGNAL; + return 0; + } + + BUG(); +} + +static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state) +{ + u8 buf[7]; + struct i2c_msg msg; + + buf[0] = 0xfe; + buf[1] = 0xc2; + buf[2] = 0x01; + buf[3] = 0x8f; + buf[4] = 0xc1; + buf[5] = 0x80; + buf[6] = 0x80; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep) +{ + u8 buf[2]; + struct i2c_msg msg; + + buf[0] = 0x03; + buf[1] = sleep ? 0x90 : 0x80; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + + return 0; +} + +static int va1j5jf8007t_sleep(struct dvb_frontend *fe) +{ + struct va1j5jf8007t_state *state; + int ret; + + state = fe->demodulator_priv; + + ret = va1j5jf8007t_init_frequency(state); + if (ret < 0) + return ret; + + return va1j5jf8007t_set_sleep(state, 1); +} + +static int va1j5jf8007t_init(struct dvb_frontend *fe) +{ + struct va1j5jf8007t_state *state; + + state = fe->demodulator_priv; + state->tune_state = VA1J5JF8007T_IDLE; + + return va1j5jf8007t_set_sleep(state, 0); +} + +static void va1j5jf8007t_release(struct dvb_frontend *fe) +{ + struct va1j5jf8007t_state *state; + state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops va1j5jf8007t_ops = { + .info = { + .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T", + .type = FE_OFDM, + .frequency_min = 90000000, + .frequency_max = 770000000, + .frequency_stepsize = 142857, + .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, + }, + + .read_snr = va1j5jf8007t_read_snr, + .get_frontend_algo = va1j5jf8007t_get_frontend_algo, + .read_status = va1j5jf8007t_read_status, + .tune = va1j5jf8007t_tune, + .sleep = va1j5jf8007t_sleep, + .init = va1j5jf8007t_init, + .release = va1j5jf8007t_release, +}; + +static const u8 va1j5jf8007t_20mhz_prepare_bufs[][2] = { + {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, + {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00}, + {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03}, + {0xef, 0x01} +}; + +static const u8 va1j5jf8007t_25mhz_prepare_bufs[][2] = { + {0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83}, + {0x3a, 0x00}, {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x0a}, {0x76, 0x4c}, + {0x77, 0x03}, {0xef, 0x01} +}; + +int va1j5jf8007t_prepare(struct dvb_frontend *fe) +{ + struct va1j5jf8007t_state *state; + const u8 (*bufs)[2]; + int size; + u8 buf[2]; + struct i2c_msg msg; + int i; + + state = fe->demodulator_priv; + + switch (state->config->frequency) { + case VA1J5JF8007T_20MHZ: + bufs = va1j5jf8007t_20mhz_prepare_bufs; + size = ARRAY_SIZE(va1j5jf8007t_20mhz_prepare_bufs); + break; + case VA1J5JF8007T_25MHZ: + bufs = va1j5jf8007t_25mhz_prepare_bufs; + size = ARRAY_SIZE(va1j5jf8007t_25mhz_prepare_bufs); + break; + default: + return -EINVAL; + } + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + for (i = 0; i < size; i++) { + memcpy(buf, bufs[i], sizeof(buf)); + if (i2c_transfer(state->adap, &msg, 1) != 1) + return -EREMOTEIO; + } + + return va1j5jf8007t_init_frequency(state); +} + +struct dvb_frontend * +va1j5jf8007t_attach(const struct va1j5jf8007t_config *config, + struct i2c_adapter *adap) +{ + struct va1j5jf8007t_state *state; + struct dvb_frontend *fe; + u8 buf[2]; + struct i2c_msg msg; + + state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL); + if (!state) + return NULL; + + state->config = config; + state->adap = adap; + + fe = &state->fe; + memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops)); + fe->demodulator_priv = state; + + buf[0] = 0x01; + buf[1] = 0x80; + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.len = sizeof(buf); + msg.buf = buf; + + if (i2c_transfer(state->adap, &msg, 1) != 1) { + kfree(state); + return NULL; + } + + return fe; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007t.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007t.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007t.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/pt1/va1j5jf8007t.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * ISDB-T driver for VA1J5JF8007/VA1J5JF8011 + * + * Copyright (C) 2009 HIRANO Takahito + * + * based on pt1dvr - http://pt1dvr.sourceforge.jp/ + * by Tomoaki Ishikawa + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef VA1J5JF8007T_H +#define VA1J5JF8007T_H + +enum va1j5jf8007t_frequency { + VA1J5JF8007T_20MHZ, + VA1J5JF8007T_25MHZ, +}; + +struct va1j5jf8007t_config { + u8 demod_address; + enum va1j5jf8007t_frequency frequency; +}; + +struct i2c_adapter; + +struct dvb_frontend * +va1j5jf8007t_attach(const struct va1j5jf8007t_config *config, + struct i2c_adapter *adap); + +/* must be called after va1j5jf8007s_attach */ +int va1j5jf8007t_prepare(struct dvb_frontend *fe); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,34 @@ +# +# Siano Mobile Silicon Digital TV device configuration +# + +config SMS_SIANO_MDTV + tristate "Siano SMS1xxx based MDTV receiver" + depends on DVB_CORE && RC_CORE && HAS_DMA + ---help--- + Choose Y or M here if you have MDTV receiver with a Siano chipset. + + To compile this driver as a module, choose M here + (The module will be called smsmdtv). + + Further documentation on this driver can be found on the WWW + at http://www.siano-ms.com/ + +if SMS_SIANO_MDTV +menu "Siano module components" + +# Hardware interfaces support + +config SMS_USB_DRV + tristate "USB interface support" + depends on DVB_CORE && USB + ---help--- + Choose if you would like to have Siano's support for USB interface + +config SMS_SDIO_DRV + tristate "SDIO interface support" + depends on DVB_CORE && MMC + ---help--- + Choose if you would like to have Siano's support for SDIO interface +endmenu +endif # SMS_SIANO_MDTV diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,11 @@ + +smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o + +obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o +obj-$(CONFIG_SMS_USB_DRV) += smsusb.o +obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core + +EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/sms-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/sms-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/sms-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/sms-cards.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,310 @@ +/* + * Card-specific functions for the Siano SMS1xxx USB dongle + * + * Copyright (c) 2008 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "sms-cards.h" +#include "smsir.h" + +static int sms_dbg; +module_param_named(cards_dbg, sms_dbg, int, 0644); +MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))"); + +static struct sms_board sms_boards[] = { + [SMS_BOARD_UNKNOWN] = { + .name = "Unknown board", + }, + [SMS1XXX_BOARD_SIANO_STELLAR] = { + .name = "Siano Stellar Digital Receiver", + .type = SMS_STELLAR, + }, + [SMS1XXX_BOARD_SIANO_NOVA_A] = { + .name = "Siano Nova A Digital Receiver", + .type = SMS_NOVA_A0, + }, + [SMS1XXX_BOARD_SIANO_NOVA_B] = { + .name = "Siano Nova B Digital Receiver", + .type = SMS_NOVA_B0, + }, + [SMS1XXX_BOARD_SIANO_VEGA] = { + .name = "Siano Vega Digital Receiver", + .type = SMS_VEGA, + }, + [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = { + .name = "Hauppauge Catamount", + .type = SMS_STELLAR, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = { + .name = "Hauppauge Okemo-A", + .type = SMS_NOVA_A0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = { + .name = "Hauppauge Okemo-B", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { + .name = "Hauppauge WinTV MiniStick", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw", + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .rc_codes = RC_MAP_HAUPPAUGE, + .board_cfg.leds_power = 26, + .board_cfg.led0 = 27, + .board_cfg.led1 = 28, + .board_cfg.ir = 9, + .led_power = 26, + .led_lo = 27, + .led_hi = 28, + }, + [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = { + .name = "Hauppauge WinTV MiniCard", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .lna_ctrl = 29, + .board_cfg.foreign_lna0_ctrl = 29, + .rf_switch = 17, + .board_cfg.rf_switch_uhf = 17, + }, + [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { + .name = "Hauppauge WinTV MiniCard", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .lna_ctrl = -1, + }, + [SMS1XXX_BOARD_SIANO_NICE] = { + /* 11 */ + .name = "Siano Nice Digital Receiver", + .type = SMS_NOVA_B0, + }, + [SMS1XXX_BOARD_SIANO_VENICE] = { + /* 12 */ + .name = "Siano Venice Digital Receiver", + .type = SMS_VEGA, + }, +}; + +struct sms_board *sms_get_board(unsigned id) +{ + BUG_ON(id >= ARRAY_SIZE(sms_boards)); + + return &sms_boards[id]; +} +EXPORT_SYMBOL_GPL(sms_get_board); +static inline void sms_gpio_assign_11xx_default_led_config( + struct smscore_gpio_config *pGpioConfig) { + pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT; + pGpioConfig->InputCharacteristics = + SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL; + pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA; + pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; + pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE; +} + +int sms_board_event(struct smscore_device_t *coredev, + enum SMS_BOARD_EVENTS gevent) { + struct smscore_gpio_config MyGpioConfig; + + sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); + + switch (gevent) { + case BOARD_EVENT_POWER_INIT: /* including hotplug */ + break; /* BOARD_EVENT_BIND */ + + case BOARD_EVENT_POWER_SUSPEND: + break; /* BOARD_EVENT_POWER_SUSPEND */ + + case BOARD_EVENT_POWER_RESUME: + break; /* BOARD_EVENT_POWER_RESUME */ + + case BOARD_EVENT_BIND: + break; /* BOARD_EVENT_BIND */ + + case BOARD_EVENT_SCAN_PROG: + break; /* BOARD_EVENT_SCAN_PROG */ + case BOARD_EVENT_SCAN_COMP: + break; /* BOARD_EVENT_SCAN_COMP */ + case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL: + break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */ + case BOARD_EVENT_FE_LOCK: + break; /* BOARD_EVENT_FE_LOCK */ + case BOARD_EVENT_FE_UNLOCK: + break; /* BOARD_EVENT_FE_UNLOCK */ + case BOARD_EVENT_DEMOD_LOCK: + break; /* BOARD_EVENT_DEMOD_LOCK */ + case BOARD_EVENT_DEMOD_UNLOCK: + break; /* BOARD_EVENT_DEMOD_UNLOCK */ + case BOARD_EVENT_RECEPTION_MAX_4: + break; /* BOARD_EVENT_RECEPTION_MAX_4 */ + case BOARD_EVENT_RECEPTION_3: + break; /* BOARD_EVENT_RECEPTION_3 */ + case BOARD_EVENT_RECEPTION_2: + break; /* BOARD_EVENT_RECEPTION_2 */ + case BOARD_EVENT_RECEPTION_1: + break; /* BOARD_EVENT_RECEPTION_1 */ + case BOARD_EVENT_RECEPTION_LOST_0: + break; /* BOARD_EVENT_RECEPTION_LOST_0 */ + case BOARD_EVENT_MULTIPLEX_OK: + break; /* BOARD_EVENT_MULTIPLEX_OK */ + case BOARD_EVENT_MULTIPLEX_ERRORS: + break; /* BOARD_EVENT_MULTIPLEX_ERRORS */ + + default: + sms_err("Unknown SMS board event"); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_event); + +static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable) +{ + int lvl, ret; + u32 gpio; + struct smscore_config_gpio gpioconfig = { + .direction = SMS_GPIO_DIRECTION_OUTPUT, + .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, + .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, + .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST, + .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA, + }; + + if (pin == 0) + return -EINVAL; + + if (pin < 0) { + /* inverted gpio */ + gpio = pin * -1; + lvl = enable ? 0 : 1; + } else { + gpio = pin; + lvl = enable ? 1 : 0; + } + + ret = smscore_configure_gpio(coredev, gpio, &gpioconfig); + if (ret < 0) + return ret; + + return smscore_set_gpio(coredev, gpio, lvl); +} + +int sms_board_setup(struct smscore_device_t *coredev) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* turn off all LEDs */ + sms_set_gpio(coredev, board->led_power, 0); + sms_set_gpio(coredev, board->led_hi, 0); + sms_set_gpio(coredev, board->led_lo, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* turn off LNA */ + sms_set_gpio(coredev, board->lna_ctrl, 0); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_setup); + +int sms_board_power(struct smscore_device_t *coredev, int onoff) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* power LED */ + sms_set_gpio(coredev, + board->led_power, onoff ? 1 : 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* LNA */ + if (!onoff) + sms_set_gpio(coredev, board->lna_ctrl, 0); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_power); + +int sms_board_led_feedback(struct smscore_device_t *coredev, int led) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + /* dont touch GPIO if LEDs are already set */ + if (smscore_led_state(coredev, -1) == led) + return 0; + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + sms_set_gpio(coredev, + board->led_lo, (led & SMS_LED_LO) ? 1 : 0); + sms_set_gpio(coredev, + board->led_hi, (led & SMS_LED_HI) ? 1 : 0); + + smscore_led_state(coredev, led); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_led_feedback); + +int sms_board_lna_control(struct smscore_device_t *coredev, int onoff) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled"); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + sms_set_gpio(coredev, + board->rf_switch, onoff ? 1 : 0); + return sms_set_gpio(coredev, + board->lna_ctrl, onoff ? 1 : 0); + } + return -EINVAL; +} +EXPORT_SYMBOL_GPL(sms_board_lna_control); + +int sms_board_load_modules(int id) +{ + switch (id) { + case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT: + case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A: + case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B: + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + request_module("smsdvb"); + break; + default: + /* do nothing */ + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_load_modules); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/sms-cards.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/sms-cards.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/sms-cards.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/sms-cards.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,123 @@ +/* + * Card-specific functions for the Siano SMS1xxx USB dongle + * + * Copyright (c) 2008 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __SMS_CARDS_H__ +#define __SMS_CARDS_H__ + +#include +#include "smscoreapi.h" +#include "smsir.h" + +#define SMS_BOARD_UNKNOWN 0 +#define SMS1XXX_BOARD_SIANO_STELLAR 1 +#define SMS1XXX_BOARD_SIANO_NOVA_A 2 +#define SMS1XXX_BOARD_SIANO_NOVA_B 3 +#define SMS1XXX_BOARD_SIANO_VEGA 4 +#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5 +#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6 +#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7 +#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8 +#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9 +#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 +#define SMS1XXX_BOARD_SIANO_NICE 11 +#define SMS1XXX_BOARD_SIANO_VENICE 12 + +struct sms_board_gpio_cfg { + int lna_vhf_exist; + int lna_vhf_ctrl; + int lna_uhf_exist; + int lna_uhf_ctrl; + int lna_uhf_d_ctrl; + int lna_sband_exist; + int lna_sband_ctrl; + int lna_sband_d_ctrl; + int foreign_lna0_ctrl; + int foreign_lna1_ctrl; + int foreign_lna2_ctrl; + int rf_switch_vhf; + int rf_switch_uhf; + int rf_switch_sband; + int leds_power; + int led0; + int led1; + int led2; + int led3; + int led4; + int ir; + int eeprom_wp; + int mrc_sense; + int mrc_pdn_resetn; + int mrc_gp0; /* mrcs spi int */ + int mrc_gp1; + int mrc_gp2; + int mrc_gp3; + int mrc_gp4; + int host_spi_gsp_ts_int; +}; + +struct sms_board { + enum sms_device_type_st type; + char *name, *fw[DEVICE_MODE_MAX]; + struct sms_board_gpio_cfg board_cfg; + char *rc_codes; /* Name of IR codes table */ + + /* gpios */ + int led_power, led_hi, led_lo, lna_ctrl, rf_switch; +}; + +struct sms_board *sms_get_board(unsigned id); + +extern struct smscore_device_t *coredev; + +enum SMS_BOARD_EVENTS { + BOARD_EVENT_POWER_INIT, + BOARD_EVENT_POWER_SUSPEND, + BOARD_EVENT_POWER_RESUME, + BOARD_EVENT_BIND, + BOARD_EVENT_SCAN_PROG, + BOARD_EVENT_SCAN_COMP, + BOARD_EVENT_EMERGENCY_WARNING_SIGNAL, + BOARD_EVENT_FE_LOCK, + BOARD_EVENT_FE_UNLOCK, + BOARD_EVENT_DEMOD_LOCK, + BOARD_EVENT_DEMOD_UNLOCK, + BOARD_EVENT_RECEPTION_MAX_4, + BOARD_EVENT_RECEPTION_3, + BOARD_EVENT_RECEPTION_2, + BOARD_EVENT_RECEPTION_1, + BOARD_EVENT_RECEPTION_LOST_0, + BOARD_EVENT_MULTIPLEX_OK, + BOARD_EVENT_MULTIPLEX_ERRORS +}; + +int sms_board_event(struct smscore_device_t *coredev, + enum SMS_BOARD_EVENTS gevent); + +int sms_board_setup(struct smscore_device_t *coredev); + +#define SMS_LED_OFF 0 +#define SMS_LED_LO 1 +#define SMS_LED_HI 2 +int sms_board_led_feedback(struct smscore_device_t *coredev, int led); +int sms_board_power(struct smscore_device_t *coredev, int onoff); +int sms_board_lna_control(struct smscore_device_t *coredev, int onoff); + +extern int sms_board_load_modules(int id); + +#endif /* __SMS_CARDS_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smscoreapi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smscoreapi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smscoreapi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smscoreapi.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1644 @@ +/* + * Siano core API module + * + * This file contains implementation for the interface to sms core component + * + * author: Uri Shkolnik + * + * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "smscoreapi.h" +#include "sms-cards.h" +#include "smsir.h" +#include "smsendian.h" + +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + +struct smscore_device_notifyee_t { + struct list_head entry; + hotplug_t hotplug; +}; + +struct smscore_idlist_t { + struct list_head entry; + int id; + int data_type; +}; + +struct smscore_client_t { + struct list_head entry; + struct smscore_device_t *coredev; + void *context; + struct list_head idlist; + onresponse_t onresponse_handler; + onremove_t onremove_handler; +}; + +void smscore_set_board_id(struct smscore_device_t *core, int id) +{ + core->board_id = id; +} + +int smscore_led_state(struct smscore_device_t *core, int led) +{ + if (led >= 0) + core->led_state = led; + return core->led_state; +} +EXPORT_SYMBOL_GPL(smscore_set_board_id); + +int smscore_get_board_id(struct smscore_device_t *core) +{ + return core->board_id; +} +EXPORT_SYMBOL_GPL(smscore_get_board_id); + +struct smscore_registry_entry_t { + struct list_head entry; + char devpath[32]; + int mode; + enum sms_device_type_st type; +}; + +static struct list_head g_smscore_notifyees; +static struct list_head g_smscore_devices; +static struct mutex g_smscore_deviceslock; + +static struct list_head g_smscore_registry; +static struct mutex g_smscore_registrylock; + +static int default_mode = 4; + +module_param(default_mode, int, 0644); +MODULE_PARM_DESC(default_mode, "default firmware id (device mode)"); + +static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) +{ + struct smscore_registry_entry_t *entry; + struct list_head *next; + + kmutex_lock(&g_smscore_registrylock); + for (next = g_smscore_registry.next; + next != &g_smscore_registry; + next = next->next) { + entry = (struct smscore_registry_entry_t *) next; + if (!strcmp(entry->devpath, devpath)) { + kmutex_unlock(&g_smscore_registrylock); + return entry; + } + } + entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL); + if (entry) { + entry->mode = default_mode; + strcpy(entry->devpath, devpath); + list_add(&entry->entry, &g_smscore_registry); + } else + sms_err("failed to create smscore_registry."); + kmutex_unlock(&g_smscore_registrylock); + return entry; +} + +int smscore_registry_getmode(char *devpath) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + return entry->mode; + else + sms_err("No registry found."); + + return default_mode; +} +EXPORT_SYMBOL_GPL(smscore_registry_getmode); + +static enum sms_device_type_st smscore_registry_gettype(char *devpath) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + return entry->type; + else + sms_err("No registry found."); + + return -1; +} + +void smscore_registry_setmode(char *devpath, int mode) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + entry->mode = mode; + else + sms_err("No registry found."); +} + +static void smscore_registry_settype(char *devpath, + enum sms_device_type_st type) +{ + struct smscore_registry_entry_t *entry; + + entry = smscore_find_registry(devpath); + if (entry) + entry->type = type; + else + sms_err("No registry found."); +} + + +static void list_add_locked(struct list_head *new, struct list_head *head, + spinlock_t *lock) +{ + unsigned long flags; + + spin_lock_irqsave(lock, flags); + + list_add(new, head); + + spin_unlock_irqrestore(lock, flags); +} + +/** + * register a client callback that called when device plugged in/unplugged + * NOTE: if devices exist callback is called immediately for each device + * + * @param hotplug callback + * + * @return 0 on success, <0 on error. + */ +int smscore_register_hotplug(hotplug_t hotplug) +{ + struct smscore_device_notifyee_t *notifyee; + struct list_head *next, *first; + int rc = 0; + + kmutex_lock(&g_smscore_deviceslock); + + notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t), + GFP_KERNEL); + if (notifyee) { + /* now notify callback about existing devices */ + first = &g_smscore_devices; + for (next = first->next; + next != first && !rc; + next = next->next) { + struct smscore_device_t *coredev = + (struct smscore_device_t *) next; + rc = hotplug(coredev, coredev->device, 1); + } + + if (rc >= 0) { + notifyee->hotplug = hotplug; + list_add(¬ifyee->entry, &g_smscore_notifyees); + } else + kfree(notifyee); + } else + rc = -ENOMEM; + + kmutex_unlock(&g_smscore_deviceslock); + + return rc; +} +EXPORT_SYMBOL_GPL(smscore_register_hotplug); + +/** + * unregister a client callback that called when device plugged in/unplugged + * + * @param hotplug callback + * + */ +void smscore_unregister_hotplug(hotplug_t hotplug) +{ + struct list_head *next, *first; + + kmutex_lock(&g_smscore_deviceslock); + + first = &g_smscore_notifyees; + + for (next = first->next; next != first;) { + struct smscore_device_notifyee_t *notifyee = + (struct smscore_device_notifyee_t *) next; + next = next->next; + + if (notifyee->hotplug == hotplug) { + list_del(¬ifyee->entry); + kfree(notifyee); + } + } + + kmutex_unlock(&g_smscore_deviceslock); +} +EXPORT_SYMBOL_GPL(smscore_unregister_hotplug); + +static void smscore_notify_clients(struct smscore_device_t *coredev) +{ + struct smscore_client_t *client; + + /* the client must call smscore_unregister_client from remove handler */ + while (!list_empty(&coredev->clients)) { + client = (struct smscore_client_t *) coredev->clients.next; + client->onremove_handler(client->context); + } +} + +static int smscore_notify_callbacks(struct smscore_device_t *coredev, + struct device *device, int arrival) +{ + struct list_head *next, *first; + int rc = 0; + + /* note: must be called under g_deviceslock */ + + first = &g_smscore_notifyees; + + for (next = first->next; next != first; next = next->next) { + rc = ((struct smscore_device_notifyee_t *) next)-> + hotplug(coredev, device, arrival); + if (rc < 0) + break; + } + + return rc; +} + +static struct +smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, + dma_addr_t common_buffer_phys) +{ + struct smscore_buffer_t *cb = + kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); + if (!cb) { + sms_info("kmalloc(...) failed"); + return NULL; + } + + cb->p = buffer; + cb->offset_in_common = buffer - (u8 *) common_buffer; + cb->phys = common_buffer_phys + cb->offset_in_common; + + return cb; +} + +/** + * creates coredev object for a device, prepares buffers, + * creates buffer mappings, notifies registered hotplugs about new device. + * + * @param params device pointer to struct with device specific parameters + * and handlers + * @param coredev pointer to a value that receives created coredev object + * + * @return 0 on success, <0 on error. + */ +int smscore_register_device(struct smsdevice_params_t *params, + struct smscore_device_t **coredev) +{ + struct smscore_device_t *dev; + u8 *buffer; + + dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); + if (!dev) { + sms_info("kzalloc(...) failed"); + return -ENOMEM; + } + + /* init list entry so it could be safe in smscore_unregister_device */ + INIT_LIST_HEAD(&dev->entry); + + /* init queues */ + INIT_LIST_HEAD(&dev->clients); + INIT_LIST_HEAD(&dev->buffers); + + /* init locks */ + spin_lock_init(&dev->clientslock); + spin_lock_init(&dev->bufferslock); + + /* init completion events */ + init_completion(&dev->version_ex_done); + init_completion(&dev->data_download_done); + init_completion(&dev->trigger_done); + init_completion(&dev->init_device_done); + init_completion(&dev->reload_start_done); + init_completion(&dev->resume_done); + init_completion(&dev->gpio_configuration_done); + init_completion(&dev->gpio_set_level_done); + init_completion(&dev->gpio_get_level_done); + init_completion(&dev->ir_init_done); + + /* Buffer management */ + init_waitqueue_head(&dev->buffer_mng_waitq); + + /* alloc common buffer */ + dev->common_buffer_size = params->buffer_size * params->num_buffers; + dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, + &dev->common_buffer_phys, + GFP_KERNEL | GFP_DMA); + if (!dev->common_buffer) { + smscore_unregister_device(dev); + return -ENOMEM; + } + + /* prepare dma buffers */ + for (buffer = dev->common_buffer; + dev->num_buffers < params->num_buffers; + dev->num_buffers++, buffer += params->buffer_size) { + struct smscore_buffer_t *cb = + smscore_createbuffer(buffer, dev->common_buffer, + dev->common_buffer_phys); + if (!cb) { + smscore_unregister_device(dev); + return -ENOMEM; + } + + smscore_putbuffer(dev, cb); + } + + sms_info("allocated %d buffers", dev->num_buffers); + + dev->mode = DEVICE_MODE_NONE; + dev->context = params->context; + dev->device = params->device; + dev->setmode_handler = params->setmode_handler; + dev->detectmode_handler = params->detectmode_handler; + dev->sendrequest_handler = params->sendrequest_handler; + dev->preload_handler = params->preload_handler; + dev->postload_handler = params->postload_handler; + + dev->device_flags = params->flags; + strcpy(dev->devpath, params->devpath); + + smscore_registry_settype(dev->devpath, params->device_type); + + /* add device to devices list */ + kmutex_lock(&g_smscore_deviceslock); + list_add(&dev->entry, &g_smscore_devices); + kmutex_unlock(&g_smscore_deviceslock); + + *coredev = dev; + + sms_info("device %p created", dev); + + return 0; +} +EXPORT_SYMBOL_GPL(smscore_register_device); + + +static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, + void *buffer, size_t size, struct completion *completion) { + int rc = coredev->sendrequest_handler(coredev->context, buffer, size); + if (rc < 0) { + sms_info("sendrequest returned error %d", rc); + return rc; + } + + return wait_for_completion_timeout(completion, + msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ? + 0 : -ETIME; +} + +/** + * Starts & enables IR operations + * + * @return 0 on success, < 0 on error. + */ +static int smscore_init_ir(struct smscore_device_t *coredev) +{ + int ir_io; + int rc; + void *buffer; + + coredev->ir.dev = NULL; + ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir; + if (ir_io) {/* only if IR port exist we use IR sub-module */ + sms_info("IR loading"); + rc = sms_ir_init(coredev); + + if (rc != 0) + sms_err("Error initialization DTV IR sub-module"); + else { + buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (buffer) { + struct SmsMsgData_ST2 *msg = + (struct SmsMsgData_ST2 *) + SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->xMsgHeader, + MSG_SMS_START_IR_REQ, + sizeof(struct SmsMsgData_ST2)); + msg->msgData[0] = coredev->ir.controller; + msg->msgData[1] = coredev->ir.timeout; + + smsendian_handle_tx_message( + (struct SmsMsgHdr_ST2 *)msg); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->xMsgHeader. msgLength, + &coredev->ir_init_done); + + kfree(buffer); + } else + sms_err + ("Sending IR initialization message failed"); + } + } else + sms_info("IR port has not been detected"); + + return 0; +} + +/** + * sets initial device mode and notifies client hotplugs that device is ready + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return 0 on success, <0 on error. + */ +int smscore_start_device(struct smscore_device_t *coredev) +{ + int rc = smscore_set_device_mode( + coredev, smscore_registry_getmode(coredev->devpath)); + if (rc < 0) { + sms_info("set device mode faile , rc %d", rc); + return rc; + } + + kmutex_lock(&g_smscore_deviceslock); + + rc = smscore_notify_callbacks(coredev, coredev->device, 1); + smscore_init_ir(coredev); + + sms_info("device %p started, rc %d", coredev, rc); + + kmutex_unlock(&g_smscore_deviceslock); + + return rc; +} +EXPORT_SYMBOL_GPL(smscore_start_device); + + +static int smscore_load_firmware_family2(struct smscore_device_t *coredev, + void *buffer, size_t size) +{ + struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; + struct SmsMsgHdr_ST *msg; + u32 mem_address; + u8 *payload = firmware->Payload; + int rc = 0; + firmware->StartAddress = le32_to_cpu(firmware->StartAddress); + firmware->Length = le32_to_cpu(firmware->Length); + + mem_address = firmware->StartAddress; + + sms_info("loading FW to addr 0x%x size %d", + mem_address, firmware->Length); + if (coredev->preload_handler) { + rc = coredev->preload_handler(coredev->context); + if (rc < 0) + return rc; + } + + /* PAGE_SIZE buffer shall be enough and dma aligned */ + msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); + if (!msg) + return -ENOMEM; + + if (coredev->mode != DEVICE_MODE_NONE) { + sms_debug("sending reload command."); + SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, + sizeof(struct SmsMsgHdr_ST)); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->msgLength, + &coredev->reload_start_done); + mem_address = *(u32 *) &payload[20]; + } + + while (size && rc >= 0) { + struct SmsDataDownload_ST *DataMsg = + (struct SmsDataDownload_ST *) msg; + int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); + + SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, + (u16)(sizeof(struct SmsMsgHdr_ST) + + sizeof(u32) + payload_size)); + + DataMsg->MemAddr = mem_address; + memcpy(DataMsg->Payload, payload, payload_size); + + if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && + (coredev->mode == DEVICE_MODE_NONE)) + rc = coredev->sendrequest_handler( + coredev->context, DataMsg, + DataMsg->xMsgHeader.msgLength); + else + rc = smscore_sendrequest_and_wait( + coredev, DataMsg, + DataMsg->xMsgHeader.msgLength, + &coredev->data_download_done); + + payload += payload_size; + size -= payload_size; + mem_address += payload_size; + } + + if (rc >= 0) { + if (coredev->mode == DEVICE_MODE_NONE) { + struct SmsMsgData_ST *TriggerMsg = + (struct SmsMsgData_ST *) msg; + + SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, + sizeof(struct SmsMsgHdr_ST) + + sizeof(u32) * 5); + + TriggerMsg->msgData[0] = firmware->StartAddress; + /* Entry point */ + TriggerMsg->msgData[1] = 5; /* Priority */ + TriggerMsg->msgData[2] = 0x200; /* Stack size */ + TriggerMsg->msgData[3] = 0; /* Parameter */ + TriggerMsg->msgData[4] = 4; /* Task ID */ + + if (coredev->device_flags & SMS_ROM_NO_RESPONSE) { + rc = coredev->sendrequest_handler( + coredev->context, TriggerMsg, + TriggerMsg->xMsgHeader.msgLength); + msleep(100); + } else + rc = smscore_sendrequest_and_wait( + coredev, TriggerMsg, + TriggerMsg->xMsgHeader.msgLength, + &coredev->trigger_done); + } else { + SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, + sizeof(struct SmsMsgHdr_ST)); + + rc = coredev->sendrequest_handler(coredev->context, + msg, msg->msgLength); + } + msleep(500); + } + + sms_debug("rc=%d, postload=%p ", rc, + coredev->postload_handler); + + kfree(msg); + + return ((rc >= 0) && coredev->postload_handler) ? + coredev->postload_handler(coredev->context) : + rc; +} + +/** + * loads specified firmware into a buffer and calls device loadfirmware_handler + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param filename null-terminated string specifies firmware file name + * @param loadfirmware_handler device handler that loads firmware + * + * @return 0 on success, <0 on error. + */ +static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, + char *filename, + loadfirmware_t loadfirmware_handler) +{ + int rc = -ENOENT; + const struct firmware *fw; + u8 *fw_buffer; + + if (loadfirmware_handler == NULL && !(coredev->device_flags & + SMS_DEVICE_FAMILY2)) + return -EINVAL; + + rc = request_firmware(&fw, filename, coredev->device); + if (rc < 0) { + sms_info("failed to open \"%s\"", filename); + return rc; + } + sms_info("read FW %s, size=%zd", filename, fw->size); + fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), + GFP_KERNEL | GFP_DMA); + if (fw_buffer) { + memcpy(fw_buffer, fw->data, fw->size); + + rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? + smscore_load_firmware_family2(coredev, + fw_buffer, + fw->size) : + loadfirmware_handler(coredev->context, + fw_buffer, fw->size); + + kfree(fw_buffer); + } else { + sms_info("failed to allocate firmware buffer"); + rc = -ENOMEM; + } + + release_firmware(fw); + + return rc; +} + +/** + * notifies all clients registered with the device, notifies hotplugs, + * frees all buffers and coredev object + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return 0 on success, <0 on error. + */ +void smscore_unregister_device(struct smscore_device_t *coredev) +{ + struct smscore_buffer_t *cb; + int num_buffers = 0; + int retry = 0; + + kmutex_lock(&g_smscore_deviceslock); + + /* Release input device (IR) resources */ + sms_ir_exit(coredev); + + smscore_notify_clients(coredev); + smscore_notify_callbacks(coredev, NULL, 0); + + /* at this point all buffers should be back + * onresponse must no longer be called */ + + while (1) { + while (!list_empty(&coredev->buffers)) { + cb = (struct smscore_buffer_t *) coredev->buffers.next; + list_del(&cb->entry); + kfree(cb); + num_buffers++; + } + if (num_buffers == coredev->num_buffers) + break; + if (++retry > 10) { + sms_info("exiting although " + "not all buffers released."); + break; + } + + sms_info("waiting for %d buffer(s)", + coredev->num_buffers - num_buffers); + msleep(100); + } + + sms_info("freed %d buffers", num_buffers); + + if (coredev->common_buffer) + dma_free_coherent(NULL, coredev->common_buffer_size, + coredev->common_buffer, coredev->common_buffer_phys); + + if (coredev->fw_buf != NULL) + kfree(coredev->fw_buf); + + list_del(&coredev->entry); + kfree(coredev); + + kmutex_unlock(&g_smscore_deviceslock); + + sms_info("device %p destroyed", coredev); +} +EXPORT_SYMBOL_GPL(smscore_unregister_device); + +static int smscore_detect_mode(struct smscore_device_t *coredev) +{ + void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + struct SmsMsgHdr_ST *msg = + (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); + int rc; + + if (!buffer) + return -ENOMEM; + + SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, + sizeof(struct SmsMsgHdr_ST)); + + rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, + &coredev->version_ex_done); + if (rc == -ETIME) { + sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); + + if (wait_for_completion_timeout(&coredev->resume_done, + msecs_to_jiffies(5000))) { + rc = smscore_sendrequest_and_wait( + coredev, msg, msg->msgLength, + &coredev->version_ex_done); + if (rc < 0) + sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " + "second try, rc %d", rc); + } else + rc = -ETIME; + } + + kfree(buffer); + + return rc; +} + +static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { + /*Stellar NOVA A0 Nova B0 VEGA*/ + /*DVBT*/ + {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, + /*DVBH*/ + {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, + /*TDMB*/ + {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"}, + /*DABIP*/ + {"none", "none", "none", "none"}, + /*BDA*/ + {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, + /*ISDBT*/ + {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, + /*ISDBTBDA*/ + {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, + /*CMMB*/ + {"none", "none", "none", "cmmb_vega_12mhz.inp"} +}; + +static inline char *sms_get_fw_name(struct smscore_device_t *coredev, + int mode, enum sms_device_type_st type) +{ + char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; + return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; +} + +/** + * calls device handler to change mode of operation + * NOTE: stellar/usb may disconnect when changing mode + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param mode requested mode of operation + * + * @return 0 on success, <0 on error. + */ +int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) +{ + void *buffer; + int rc = 0; + enum sms_device_type_st type; + + sms_debug("set device mode to %d", mode); + if (coredev->device_flags & SMS_DEVICE_FAMILY2) { + if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) { + sms_err("invalid mode specified %d", mode); + return -EINVAL; + } + + smscore_registry_setmode(coredev->devpath, mode); + + if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) { + rc = smscore_detect_mode(coredev); + if (rc < 0) { + sms_err("mode detect failed %d", rc); + return rc; + } + } + + if (coredev->mode == mode) { + sms_info("device mode %d already set", mode); + return 0; + } + + if (!(coredev->modes_supported & (1 << mode))) { + char *fw_filename; + + type = smscore_registry_gettype(coredev->devpath); + fw_filename = sms_get_fw_name(coredev, mode, type); + + rc = smscore_load_firmware_from_file(coredev, + fw_filename, NULL); + if (rc < 0) { + sms_warn("error %d loading firmware: %s, " + "trying again with default firmware", + rc, fw_filename); + + /* try again with the default firmware */ + fw_filename = smscore_fw_lkup[mode][type]; + rc = smscore_load_firmware_from_file(coredev, + fw_filename, NULL); + + if (rc < 0) { + sms_warn("error %d loading " + "firmware: %s", rc, + fw_filename); + return rc; + } + } + sms_log("firmware download success: %s", fw_filename); + } else + sms_info("mode %d supported by running " + "firmware", mode); + + buffer = kmalloc(sizeof(struct SmsMsgData_ST) + + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); + if (buffer) { + struct SmsMsgData_ST *msg = + (struct SmsMsgData_ST *) + SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct SmsMsgData_ST)); + msg->msgData[0] = mode; + + rc = smscore_sendrequest_and_wait( + coredev, msg, msg->xMsgHeader.msgLength, + &coredev->init_device_done); + + kfree(buffer); + } else { + sms_err("Could not allocate buffer for " + "init device message."); + rc = -ENOMEM; + } + } else { + if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { + sms_err("invalid mode specified %d", mode); + return -EINVAL; + } + + smscore_registry_setmode(coredev->devpath, mode); + + if (coredev->detectmode_handler) + coredev->detectmode_handler(coredev->context, + &coredev->mode); + + if (coredev->mode != mode && coredev->setmode_handler) + rc = coredev->setmode_handler(coredev->context, mode); + } + + if (rc >= 0) { + coredev->mode = mode; + coredev->device_flags &= ~SMS_DEVICE_NOT_READY; + } + + if (rc < 0) + sms_err("return error code %d.", rc); + return rc; +} + +/** + * calls device handler to get current mode of operation + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return current mode + */ +int smscore_get_device_mode(struct smscore_device_t *coredev) +{ + return coredev->mode; +} +EXPORT_SYMBOL_GPL(smscore_get_device_mode); + +/** + * find client by response id & type within the clients list. + * return client handle or NULL. + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param data_type client data type (SMS_DONT_CARE for all types) + * @param id client id (SMS_DONT_CARE for all id) + * + */ +static struct +smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, + int data_type, int id) +{ + struct smscore_client_t *client = NULL; + struct list_head *next, *first; + unsigned long flags; + struct list_head *firstid, *nextid; + + + spin_lock_irqsave(&coredev->clientslock, flags); + first = &coredev->clients; + for (next = first->next; + (next != first) && !client; + next = next->next) { + firstid = &((struct smscore_client_t *)next)->idlist; + for (nextid = firstid->next; + nextid != firstid; + nextid = nextid->next) { + if ((((struct smscore_idlist_t *)nextid)->id == id) && + (((struct smscore_idlist_t *)nextid)->data_type == data_type || + (((struct smscore_idlist_t *)nextid)->data_type == 0))) { + client = (struct smscore_client_t *) next; + break; + } + } + } + spin_unlock_irqrestore(&coredev->clientslock, flags); + return client; +} + +/** + * find client by response id/type, call clients onresponse handler + * return buffer to pool on error + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param cb pointer to response buffer descriptor + * + */ +void smscore_onresponse(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb) { + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p + + cb->offset); + struct smscore_client_t *client; + int rc = -EBUSY; + static unsigned long last_sample_time; /* = 0; */ + static int data_total; /* = 0; */ + unsigned long time_now = jiffies_to_msecs(jiffies); + + if (!last_sample_time) + last_sample_time = time_now; + + if (time_now - last_sample_time > 10000) { + sms_debug("\ndata rate %d bytes/secs", + (int)((data_total * 1000) / + (time_now - last_sample_time))); + + last_sample_time = time_now; + data_total = 0; + } + + data_total += cb->size; + /* Do we need to re-route? */ + if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || + (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { + if (coredev->mode == DEVICE_MODE_DVBT_BDA) + phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; + } + + + client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); + + /* If no client registered for type & id, + * check for control client where type is not registered */ + if (client) + rc = client->onresponse_handler(client->context, cb); + + if (rc < 0) { + switch (phdr->msgType) { + case MSG_SMS_GET_VERSION_EX_RES: + { + struct SmsVersionRes_ST *ver = + (struct SmsVersionRes_ST *) phdr; + sms_debug("MSG_SMS_GET_VERSION_EX_RES " + "id %d prots 0x%x ver %d.%d", + ver->FirmwareId, ver->SupportedProtocols, + ver->RomVersionMajor, ver->RomVersionMinor); + + coredev->mode = ver->FirmwareId == 255 ? + DEVICE_MODE_NONE : ver->FirmwareId; + coredev->modes_supported = ver->SupportedProtocols; + + complete(&coredev->version_ex_done); + break; + } + case MSG_SMS_INIT_DEVICE_RES: + sms_debug("MSG_SMS_INIT_DEVICE_RES"); + complete(&coredev->init_device_done); + break; + case MSG_SW_RELOAD_START_RES: + sms_debug("MSG_SW_RELOAD_START_RES"); + complete(&coredev->reload_start_done); + break; + case MSG_SMS_DATA_DOWNLOAD_RES: + complete(&coredev->data_download_done); + break; + case MSG_SW_RELOAD_EXEC_RES: + sms_debug("MSG_SW_RELOAD_EXEC_RES"); + break; + case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: + sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); + complete(&coredev->trigger_done); + break; + case MSG_SMS_SLEEP_RESUME_COMP_IND: + complete(&coredev->resume_done); + break; + case MSG_SMS_GPIO_CONFIG_EX_RES: + sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES"); + complete(&coredev->gpio_configuration_done); + break; + case MSG_SMS_GPIO_SET_LEVEL_RES: + sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES"); + complete(&coredev->gpio_set_level_done); + break; + case MSG_SMS_GPIO_GET_LEVEL_RES: + { + u32 *msgdata = (u32 *) phdr; + coredev->gpio_get_res = msgdata[1]; + sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", + coredev->gpio_get_res); + complete(&coredev->gpio_get_level_done); + break; + } + case MSG_SMS_START_IR_RES: + complete(&coredev->ir_init_done); + break; + case MSG_SMS_IR_SAMPLES_IND: + sms_ir_event(coredev, + (const char *) + ((char *)phdr + + sizeof(struct SmsMsgHdr_ST)), + (int)phdr->msgLength + - sizeof(struct SmsMsgHdr_ST)); + break; + + default: + break; + } + smscore_putbuffer(coredev, cb); + } +} +EXPORT_SYMBOL_GPL(smscore_onresponse); + +/** + * return pointer to next free buffer descriptor from core pool + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return pointer to descriptor on success, NULL on error. + */ + +struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev) +{ + struct smscore_buffer_t *cb = NULL; + unsigned long flags; + + spin_lock_irqsave(&coredev->bufferslock, flags); + if (!list_empty(&coredev->buffers)) { + cb = (struct smscore_buffer_t *) coredev->buffers.next; + list_del(&cb->entry); + } + spin_unlock_irqrestore(&coredev->bufferslock, flags); + return cb; +} + +struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) +{ + struct smscore_buffer_t *cb = NULL; + + wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev))); + + return cb; +} +EXPORT_SYMBOL_GPL(smscore_getbuffer); + +/** + * return buffer descriptor to a pool + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param cb pointer buffer descriptor + * + */ +void smscore_putbuffer(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb) { + wake_up_interruptible(&coredev->buffer_mng_waitq); + list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); +} +EXPORT_SYMBOL_GPL(smscore_putbuffer); + +static int smscore_validate_client(struct smscore_device_t *coredev, + struct smscore_client_t *client, + int data_type, int id) +{ + struct smscore_idlist_t *listentry; + struct smscore_client_t *registered_client; + + if (!client) { + sms_err("bad parameter."); + return -EFAULT; + } + registered_client = smscore_find_client(coredev, data_type, id); + if (registered_client == client) + return 0; + + if (registered_client) { + sms_err("The msg ID already registered to another client."); + return -EEXIST; + } + listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); + if (!listentry) { + sms_err("Can't allocate memory for client id."); + return -ENOMEM; + } + listentry->id = id; + listentry->data_type = data_type; + list_add_locked(&listentry->entry, &client->idlist, + &coredev->clientslock); + return 0; +} + +/** + * creates smsclient object, check that id is taken by another client + * + * @param coredev pointer to a coredev object from clients hotplug + * @param initial_id all messages with this id would be sent to this client + * @param data_type all messages of this type would be sent to this client + * @param onresponse_handler client handler that is called to + * process incoming messages + * @param onremove_handler client handler that is called when device is removed + * @param context client-specific context + * @param client pointer to a value that receives created smsclient object + * + * @return 0 on success, <0 on error. + */ +int smscore_register_client(struct smscore_device_t *coredev, + struct smsclient_params_t *params, + struct smscore_client_t **client) +{ + struct smscore_client_t *newclient; + /* check that no other channel with same parameters exists */ + if (smscore_find_client(coredev, params->data_type, + params->initial_id)) { + sms_err("Client already exist."); + return -EEXIST; + } + + newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); + if (!newclient) { + sms_err("Failed to allocate memory for client."); + return -ENOMEM; + } + + INIT_LIST_HEAD(&newclient->idlist); + newclient->coredev = coredev; + newclient->onresponse_handler = params->onresponse_handler; + newclient->onremove_handler = params->onremove_handler; + newclient->context = params->context; + list_add_locked(&newclient->entry, &coredev->clients, + &coredev->clientslock); + smscore_validate_client(coredev, newclient, params->data_type, + params->initial_id); + *client = newclient; + sms_debug("%p %d %d", params->context, params->data_type, + params->initial_id); + + return 0; +} +EXPORT_SYMBOL_GPL(smscore_register_client); + +/** + * frees smsclient object and all subclients associated with it + * + * @param client pointer to smsclient object returned by + * smscore_register_client + * + */ +void smscore_unregister_client(struct smscore_client_t *client) +{ + struct smscore_device_t *coredev = client->coredev; + unsigned long flags; + + spin_lock_irqsave(&coredev->clientslock, flags); + + + while (!list_empty(&client->idlist)) { + struct smscore_idlist_t *identry = + (struct smscore_idlist_t *) client->idlist.next; + list_del(&identry->entry); + kfree(identry); + } + + sms_info("%p", client->context); + + list_del(&client->entry); + kfree(client); + + spin_unlock_irqrestore(&coredev->clientslock, flags); +} +EXPORT_SYMBOL_GPL(smscore_unregister_client); + +/** + * verifies that source id is not taken by another client, + * calls device handler to send requests to the device + * + * @param client pointer to smsclient object returned by + * smscore_register_client + * @param buffer pointer to a request buffer + * @param size size (in bytes) of request buffer + * + * @return 0 on success, <0 on error. + */ +int smsclient_sendrequest(struct smscore_client_t *client, + void *buffer, size_t size) +{ + struct smscore_device_t *coredev; + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; + int rc; + + if (client == NULL) { + sms_err("Got NULL client"); + return -EINVAL; + } + + coredev = client->coredev; + + /* check that no other channel with same id exists */ + if (coredev == NULL) { + sms_err("Got NULL coredev"); + return -EINVAL; + } + + rc = smscore_validate_client(client->coredev, client, 0, + phdr->msgSrcId); + if (rc < 0) + return rc; + + return coredev->sendrequest_handler(coredev->context, buffer, size); +} +EXPORT_SYMBOL_GPL(smsclient_sendrequest); + + +/* old GPIO managements implementation */ +int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, + struct smscore_config_gpio *pinconfig) +{ + struct { + struct SmsMsgHdr_ST hdr; + u32 data[6]; + } msg; + + if (coredev->device_flags & SMS_DEVICE_FAMILY2) { + msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msgDstId = HIF_TASK; + msg.hdr.msgFlags = 0; + msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; + msg.hdr.msgLength = sizeof(msg); + + msg.data[0] = pin; + msg.data[1] = pinconfig->pullupdown; + + /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */ + msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; + + switch (pinconfig->outputdriving) { + case SMS_GPIO_OUTPUTDRIVING_16mA: + msg.data[3] = 7; /* Nova - 16mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_12mA: + msg.data[3] = 5; /* Nova - 11mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_8mA: + msg.data[3] = 3; /* Nova - 7mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_4mA: + default: + msg.data[3] = 2; /* Nova - 4mA */ + break; + } + + msg.data[4] = pinconfig->direction; + msg.data[5] = 0; + } else /* TODO: SMS_DEVICE_FAMILY1 */ + return -EINVAL; + + return coredev->sendrequest_handler(coredev->context, + &msg, sizeof(msg)); +} + +int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) +{ + struct { + struct SmsMsgHdr_ST hdr; + u32 data[3]; + } msg; + + if (pin > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msgDstId = HIF_TASK; + msg.hdr.msgFlags = 0; + msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; + msg.hdr.msgLength = sizeof(msg); + + msg.data[0] = pin; + msg.data[1] = level ? 1 : 0; + msg.data[2] = 0; + + return coredev->sendrequest_handler(coredev->context, + &msg, sizeof(msg)); +} + +/* new GPIO management implementation */ +static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, + u32 *pGroupNum, u32 *pGroupCfg) { + + *pGroupCfg = 1; + + if (PinNum <= 1) { + *pTranslatedPinNum = 0; + *pGroupNum = 9; + *pGroupCfg = 2; + } else if (PinNum >= 2 && PinNum <= 6) { + *pTranslatedPinNum = 2; + *pGroupNum = 0; + *pGroupCfg = 2; + } else if (PinNum >= 7 && PinNum <= 11) { + *pTranslatedPinNum = 7; + *pGroupNum = 1; + } else if (PinNum >= 12 && PinNum <= 15) { + *pTranslatedPinNum = 12; + *pGroupNum = 2; + *pGroupCfg = 3; + } else if (PinNum == 16) { + *pTranslatedPinNum = 16; + *pGroupNum = 23; + } else if (PinNum >= 17 && PinNum <= 24) { + *pTranslatedPinNum = 17; + *pGroupNum = 3; + } else if (PinNum == 25) { + *pTranslatedPinNum = 25; + *pGroupNum = 6; + } else if (PinNum >= 26 && PinNum <= 28) { + *pTranslatedPinNum = 26; + *pGroupNum = 4; + } else if (PinNum == 29) { + *pTranslatedPinNum = 29; + *pGroupNum = 5; + *pGroupCfg = 2; + } else if (PinNum == 30) { + *pTranslatedPinNum = 30; + *pGroupNum = 8; + } else if (PinNum == 31) { + *pTranslatedPinNum = 31; + *pGroupNum = 17; + } else + return -1; + + *pGroupCfg <<= 24; + + return 0; +} + +int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, + struct smscore_gpio_config *pGpioConfig) { + + u32 totalLen; + u32 TranslatedPinNum = 0; + u32 GroupNum = 0; + u32 ElectricChar; + u32 groupCfg; + void *buffer; + int rc; + + struct SetGpioMsg { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[6]; + } *pMsg; + + + if (PinNum > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + if (pGpioConfig == NULL) + return -EINVAL; + + totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6); + + buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + + pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + pMsg->xMsgHeader.msgDstId = HIF_TASK; + pMsg->xMsgHeader.msgFlags = 0; + pMsg->xMsgHeader.msgLength = (u16) totalLen; + pMsg->msgData[0] = PinNum; + + if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ; + if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum, + &groupCfg) != 0) { + rc = -EINVAL; + goto free; + } + + pMsg->msgData[1] = TranslatedPinNum; + pMsg->msgData[2] = GroupNum; + ElectricChar = (pGpioConfig->PullUpDown) + | (pGpioConfig->InputCharacteristics << 2) + | (pGpioConfig->OutputSlewRate << 3) + | (pGpioConfig->OutputDriving << 4); + pMsg->msgData[3] = ElectricChar; + pMsg->msgData[4] = pGpioConfig->Direction; + pMsg->msgData[5] = groupCfg; + } else { + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; + pMsg->msgData[1] = pGpioConfig->PullUpDown; + pMsg->msgData[2] = pGpioConfig->OutputSlewRate; + pMsg->msgData[3] = pGpioConfig->OutputDriving; + pMsg->msgData[4] = pGpioConfig->Direction; + pMsg->msgData[5] = 0; + } + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); + rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + &coredev->gpio_configuration_done); + + if (rc != 0) { + if (rc == -ETIME) + sms_err("smscore_gpio_configure timeout"); + else + sms_err("smscore_gpio_configure error"); + } +free: + kfree(buffer); + + return rc; +} + +int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, + u8 NewLevel) { + + u32 totalLen; + int rc; + void *buffer; + + struct SetGpioMsg { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[3]; /* keep it 3 ! */ + } *pMsg; + + if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER)) + return -EINVAL; + + totalLen = sizeof(struct SmsMsgHdr_ST) + + (3 * sizeof(u32)); /* keep it 3 ! */ + + buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + + pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + pMsg->xMsgHeader.msgDstId = HIF_TASK; + pMsg->xMsgHeader.msgFlags = 0; + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; + pMsg->xMsgHeader.msgLength = (u16) totalLen; + pMsg->msgData[0] = PinNum; + pMsg->msgData[1] = NewLevel; + + /* Send message to SMS */ + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); + rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + &coredev->gpio_set_level_done); + + if (rc != 0) { + if (rc == -ETIME) + sms_err("smscore_gpio_set_level timeout"); + else + sms_err("smscore_gpio_set_level error"); + } + kfree(buffer); + + return rc; +} + +int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, + u8 *level) { + + u32 totalLen; + int rc; + void *buffer; + + struct SetGpioMsg { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[2]; + } *pMsg; + + + if (PinNum > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32)); + + buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + + pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + pMsg->xMsgHeader.msgDstId = HIF_TASK; + pMsg->xMsgHeader.msgFlags = 0; + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ; + pMsg->xMsgHeader.msgLength = (u16) totalLen; + pMsg->msgData[0] = PinNum; + pMsg->msgData[1] = 0; + + /* Send message to SMS */ + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); + rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + &coredev->gpio_get_level_done); + + if (rc != 0) { + if (rc == -ETIME) + sms_err("smscore_gpio_get_level timeout"); + else + sms_err("smscore_gpio_get_level error"); + } + kfree(buffer); + + /* Its a race between other gpio_get_level() and the copy of the single + * global 'coredev->gpio_get_res' to the function's variable 'level' + */ + *level = coredev->gpio_get_res; + + return rc; +} + +static int __init smscore_module_init(void) +{ + int rc = 0; + + INIT_LIST_HEAD(&g_smscore_notifyees); + INIT_LIST_HEAD(&g_smscore_devices); + kmutex_init(&g_smscore_deviceslock); + + INIT_LIST_HEAD(&g_smscore_registry); + kmutex_init(&g_smscore_registrylock); + + return rc; +} + +static void __exit smscore_module_exit(void) +{ + kmutex_lock(&g_smscore_deviceslock); + while (!list_empty(&g_smscore_notifyees)) { + struct smscore_device_notifyee_t *notifyee = + (struct smscore_device_notifyee_t *) + g_smscore_notifyees.next; + + list_del(¬ifyee->entry); + kfree(notifyee); + } + kmutex_unlock(&g_smscore_deviceslock); + + kmutex_lock(&g_smscore_registrylock); + while (!list_empty(&g_smscore_registry)) { + struct smscore_registry_entry_t *entry = + (struct smscore_registry_entry_t *) + g_smscore_registry.next; + + list_del(&entry->entry); + kfree(entry); + } + kmutex_unlock(&g_smscore_registrylock); + + sms_debug(""); +} + +module_init(smscore_module_init); +module_exit(smscore_module_exit); + +MODULE_DESCRIPTION("Siano MDTV Core module"); +MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smscoreapi.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smscoreapi.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smscoreapi.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smscoreapi.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,776 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat + +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, or +(at your option) any later version. + + 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, see . + +****************************************************************/ + +#ifndef __SMS_CORE_API_H__ +#define __SMS_CORE_API_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "smsir.h" + +#define kmutex_init(_p_) mutex_init(_p_) +#define kmutex_lock(_p_) mutex_lock(_p_) +#define kmutex_trylock(_p_) mutex_trylock(_p_) +#define kmutex_unlock(_p_) mutex_unlock(_p_) + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000) +#define SMS_ALLOC_ALIGNMENT 128 +#define SMS_DMA_ALIGNMENT 16 +#define SMS_ALIGN_ADDRESS(addr) \ + ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) + +#define SMS_DEVICE_FAMILY2 1 +#define SMS_ROM_NO_RESPONSE 2 +#define SMS_DEVICE_NOT_READY 0x8000000 + +enum sms_device_type_st { + SMS_STELLAR = 0, + SMS_NOVA_A0, + SMS_NOVA_B0, + SMS_VEGA, + SMS_NUM_OF_DEVICE_TYPES +}; + +struct smscore_device_t; +struct smscore_client_t; +struct smscore_buffer_t; + +typedef int (*hotplug_t)(struct smscore_device_t *coredev, + struct device *device, int arrival); + +typedef int (*setmode_t)(void *context, int mode); +typedef void (*detectmode_t)(void *context, int *mode); +typedef int (*sendrequest_t)(void *context, void *buffer, size_t size); +typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size); +typedef int (*preload_t)(void *context); +typedef int (*postload_t)(void *context); + +typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb); +typedef void (*onremove_t)(void *context); + +struct smscore_buffer_t { + /* public members, once passed to clients can be changed freely */ + struct list_head entry; + int size; + int offset; + + /* private members, read-only for clients */ + void *p; + dma_addr_t phys; + unsigned long offset_in_common; +}; + +struct smsdevice_params_t { + struct device *device; + + int buffer_size; + int num_buffers; + + char devpath[32]; + unsigned long flags; + + setmode_t setmode_handler; + detectmode_t detectmode_handler; + sendrequest_t sendrequest_handler; + preload_t preload_handler; + postload_t postload_handler; + + void *context; + enum sms_device_type_st device_type; +}; + +struct smsclient_params_t { + int initial_id; + int data_type; + onresponse_t onresponse_handler; + onremove_t onremove_handler; + void *context; +}; + +struct smscore_device_t { + struct list_head entry; + + struct list_head clients; + struct list_head subclients; + spinlock_t clientslock; + + struct list_head buffers; + spinlock_t bufferslock; + int num_buffers; + + void *common_buffer; + int common_buffer_size; + dma_addr_t common_buffer_phys; + + void *context; + struct device *device; + + char devpath[32]; + unsigned long device_flags; + + setmode_t setmode_handler; + detectmode_t detectmode_handler; + sendrequest_t sendrequest_handler; + preload_t preload_handler; + postload_t postload_handler; + + int mode, modes_supported; + + /* host <--> device messages */ + struct completion version_ex_done, data_download_done, trigger_done; + struct completion init_device_done, reload_start_done, resume_done; + struct completion gpio_configuration_done, gpio_set_level_done; + struct completion gpio_get_level_done, ir_init_done; + + /* Buffer management */ + wait_queue_head_t buffer_mng_waitq; + + /* GPIO */ + int gpio_get_res; + + /* Target hardware board */ + int board_id; + + /* Firmware */ + u8 *fw_buf; + u32 fw_buf_size; + + /* Infrared (IR) */ + struct ir_t ir; + + int led_state; +}; + +/* GPIO definitions for antenna frequency domain control (SMS8021) */ +#define SMS_ANTENNA_GPIO_0 1 +#define SMS_ANTENNA_GPIO_1 0 + +#define BW_8_MHZ 0 +#define BW_7_MHZ 1 +#define BW_6_MHZ 2 +#define BW_5_MHZ 3 +#define BW_ISDBT_1SEG 4 +#define BW_ISDBT_3SEG 5 + +#define MSG_HDR_FLAG_SPLIT_MSG 4 + +#define MAX_GPIO_PIN_NUMBER 31 + +#define HIF_TASK 11 +#define SMS_HOST_LIB 150 +#define DVBT_BDA_CONTROL_MSG_ID 201 + +#define SMS_MAX_PAYLOAD_SIZE 240 +#define SMS_TUNE_TIMEOUT 500 + +#define MSG_SMS_GPIO_CONFIG_REQ 507 +#define MSG_SMS_GPIO_CONFIG_RES 508 +#define MSG_SMS_GPIO_SET_LEVEL_REQ 509 +#define MSG_SMS_GPIO_SET_LEVEL_RES 510 +#define MSG_SMS_GPIO_GET_LEVEL_REQ 511 +#define MSG_SMS_GPIO_GET_LEVEL_RES 512 +#define MSG_SMS_RF_TUNE_REQ 561 +#define MSG_SMS_RF_TUNE_RES 562 +#define MSG_SMS_INIT_DEVICE_REQ 578 +#define MSG_SMS_INIT_DEVICE_RES 579 +#define MSG_SMS_ADD_PID_FILTER_REQ 601 +#define MSG_SMS_ADD_PID_FILTER_RES 602 +#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 +#define MSG_SMS_REMOVE_PID_FILTER_RES 604 +#define MSG_SMS_DAB_CHANNEL 607 +#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 +#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 +#define MSG_SMS_GET_STATISTICS_RES 616 +#define MSG_SMS_GET_STATISTICS_REQ 615 +#define MSG_SMS_HO_PER_SLICES_IND 630 +#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 +#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 +#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 +#define MSG_SMS_DATA_DOWNLOAD_REQ 660 +#define MSG_SMS_DATA_DOWNLOAD_RES 661 +#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 +#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 +#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 +#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 +#define MSG_SMS_GET_VERSION_EX_REQ 668 +#define MSG_SMS_GET_VERSION_EX_RES 669 +#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 +#define MSG_SMS_I2C_SET_FREQ_REQ 685 +#define MSG_SMS_GENERIC_I2C_REQ 687 +#define MSG_SMS_GENERIC_I2C_RES 688 +#define MSG_SMS_DVBT_BDA_DATA 693 +#define MSG_SW_RELOAD_REQ 697 +#define MSG_SMS_DATA_MSG 699 +#define MSG_SW_RELOAD_START_REQ 702 +#define MSG_SW_RELOAD_START_RES 703 +#define MSG_SW_RELOAD_EXEC_REQ 704 +#define MSG_SW_RELOAD_EXEC_RES 705 +#define MSG_SMS_SPI_INT_LINE_SET_REQ 710 +#define MSG_SMS_GPIO_CONFIG_EX_REQ 712 +#define MSG_SMS_GPIO_CONFIG_EX_RES 713 +#define MSG_SMS_ISDBT_TUNE_REQ 776 +#define MSG_SMS_ISDBT_TUNE_RES 777 +#define MSG_SMS_TRANSMISSION_IND 782 +#define MSG_SMS_START_IR_REQ 800 +#define MSG_SMS_START_IR_RES 801 +#define MSG_SMS_IR_SAMPLES_IND 802 +#define MSG_SMS_SIGNAL_DETECTED_IND 827 +#define MSG_SMS_NO_SIGNAL_IND 828 + +#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ + (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ + (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ +} while (0) + +#define SMS_INIT_MSG(ptr, type, len) \ + SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len) + +enum SMS_DVB3_EVENTS { + DVB3_EVENT_INIT = 0, + DVB3_EVENT_SLEEP, + DVB3_EVENT_HOTPLUG, + DVB3_EVENT_FE_LOCK, + DVB3_EVENT_FE_UNLOCK, + DVB3_EVENT_UNC_OK, + DVB3_EVENT_UNC_ERR +}; + +enum SMS_DEVICE_MODE { + DEVICE_MODE_NONE = -1, + DEVICE_MODE_DVBT = 0, + DEVICE_MODE_DVBH, + DEVICE_MODE_DAB_TDMB, + DEVICE_MODE_DAB_TDMB_DABIP, + DEVICE_MODE_DVBT_BDA, + DEVICE_MODE_ISDBT, + DEVICE_MODE_ISDBT_BDA, + DEVICE_MODE_CMMB, + DEVICE_MODE_RAW_TUNER, + DEVICE_MODE_MAX, +}; + +struct SmsMsgHdr_ST { + u16 msgType; + u8 msgSrcId; + u8 msgDstId; + u16 msgLength; /* Length of entire message, including header */ + u16 msgFlags; +}; + +struct SmsMsgData_ST { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[1]; +}; + +struct SmsMsgData_ST2 { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[2]; +}; + +struct SmsDataDownload_ST { + struct SmsMsgHdr_ST xMsgHeader; + u32 MemAddr; + u8 Payload[SMS_MAX_PAYLOAD_SIZE]; +}; + +struct SmsVersionRes_ST { + struct SmsMsgHdr_ST xMsgHeader; + + u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ + u8 Step; /* 0 - Step A */ + u8 MetalFix; /* 0 - Metal 0 */ + + /* FirmwareId 0xFF if ROM, otherwise the + * value indicated by SMSHOSTLIB_DEVICE_MODES_E */ + u8 FirmwareId; + /* SupportedProtocols Bitwise OR combination of + * supported protocols */ + u8 SupportedProtocols; + + u8 VersionMajor; + u8 VersionMinor; + u8 VersionPatch; + u8 VersionFieldPatch; + + u8 RomVersionMajor; + u8 RomVersionMinor; + u8 RomVersionPatch; + u8 RomVersionFieldPatch; + + u8 TextLabel[34]; +}; + +struct SmsFirmware_ST { + u32 CheckSum; + u32 Length; + u32 StartAddress; + u8 Payload[1]; +}; + +/* Statistics information returned as response for + * SmsHostApiGetStatistics_Req */ +struct SMSHOSTLIB_STATISTICS_ST { + u32 Reserved; /* Reserved */ + + /* Common parameters */ + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + /* Reception quality */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ + u32 TS_PER; /* Transport stream PER, + 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */ + u32 MFER; /* DVB-H frame error rate in percentage, + 0xFFFFFFFF indicate N/A, valid only for DVB-H */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + + /* Transmission parameters */ + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ + u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, + for DVB-T/H FFT mode carriers in Kilos */ + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, + valid only for DVB-T/H */ + u32 GuardInterval; /* Guard Interval from + SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + valid only for DVB-T/H */ + u32 LPCodeRate; /* Low Priority Code Rate from + SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ + u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, + valid only for DVB-T/H */ + u32 Constellation; /* Constellation from + SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ + + /* Burst parameters, valid only for DVB-H */ + u32 BurstSize; /* Current burst size in bytes, + valid only for DVB-H */ + u32 BurstDuration; /* Current burst duration in mSec, + valid only for DVB-H */ + u32 BurstCycleTime; /* Current burst cycle time in mSec, + valid only for DVB-H */ + u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, + as calculated by demodulator, valid only for DVB-H */ + u32 NumOfRows; /* Number of rows in MPE table, + valid only for DVB-H */ + u32 NumOfPaddCols; /* Number of padding columns in MPE table, + valid only for DVB-H */ + u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, + valid only for DVB-H */ + u32 ErrorTSPackets; /* Number of erroneous + transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include + errors after MPE RS decoding */ + u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors + after MPE RS decoding */ + u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were + corrected by MPE RS decoding */ + /* Common params */ + u32 BERErrorCount; /* Number of errornous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ + + /* Interface information */ + u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + + /* DAB/T-DMB */ + u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + + /* DVB-H TPS parameters */ + u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + if set to 0xFFFFFFFF cell_id not yet recovered */ + u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + + u32 NumMPEReceived; /* DVB-H, Num MPE section received */ + + u32 ReservedFields[10]; /* Reserved */ +}; + +struct SmsMsgStatisticsInfo_ST { + u32 RequestResult; + + struct SMSHOSTLIB_STATISTICS_ST Stat; + + /* Split the calc of the SNR in DAB */ + u32 Signal; /* dB */ + u32 Noise; /* dB */ + +}; + +struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST { + /* Per-layer information */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + * 255 means layer does not exist */ + u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET, + * 255 means layer does not exist */ + u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ + u32 BERErrorCount; /* Post Viterbi Error Bits Count */ + u32 BERBitCount; /* Post Viterbi Total Bits Count */ + u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ + u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ + u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 TILdepthI; /* Time interleaver depth I parameter, + * 255 means layer does not exist */ + u32 NumberOfSegments; /* Number of segments in layer A, + * 255 means layer does not exist */ + u32 TMCCErrors; /* TMCC errors */ +}; + +struct SMSHOSTLIB_STATISTICS_ISDBT_ST { + u32 StatisticsType; /* Enumerator identifying the type of the + * structure. Values are the same as + * SMSHOSTLIB_DEVICE_MODES_E + * + * This field MUST always be first in any + * statistics structure */ + + u32 FullSize; /* Total size of the structure returned by the modem. + * If the size requested by the host is smaller than + * FullSize, the struct will be truncated */ + + /* Common parameters */ + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + /* Reception quality */ + s32 SNR; /* dB */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in Hz */ + + /* Transmission parameters */ + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz */ + u32 TransmissionMode; /* ISDB-T transmission mode */ + u32 ModemState; /* 0 - Acquisition, 1 - Locked */ + u32 GuardInterval; /* Guard Interval, 1 divided by value */ + u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ + u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */ + u32 NumOfLayers; /* Number of ISDB-T layers in the network */ + + /* Per-layer information */ + /* Layers A, B and C */ + struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; + /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ + + /* Interface information */ + u32 SmsToHostTxErrors; /* Total number of transmission errors. */ +}; + +struct PID_STATISTICS_DATA_S { + struct PID_BURST_S { + u32 size; + u32 padding_cols; + u32 punct_cols; + u32 duration; + u32 cycle; + u32 calc_cycle; + } burst; + + u32 tot_tbl_cnt; + u32 invalid_tbl_cnt; + u32 tot_cor_tbl; +}; + +struct PID_DATA_S { + u32 pid; + u32 num_rows; + struct PID_STATISTICS_DATA_S pid_statistics; +}; + +#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) +#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) +#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ + if (_stat.TransmissionMode == 0) \ + _stat.TransmissionMode = 2; \ + else if (_stat.TransmissionMode == 1) \ + _stat.TransmissionMode = 8; \ + else \ + _stat.TransmissionMode = 4; + +struct TRANSMISSION_STATISTICS_S { + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz */ + u32 TransmissionMode; /* FFT mode carriers in Kilos */ + u32 GuardInterval; /* Guard Interval from + SMSHOSTLIB_GUARD_INTERVALS_ET */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ + u32 LPCodeRate; /* Low Priority Code Rate from + SMSHOSTLIB_CODE_RATE_ET */ + u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ + u32 Constellation; /* Constellation from + SMSHOSTLIB_CONSTELLATION_ET */ + + /* DVB-H TPS parameters */ + u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + if set to 0xFFFFFFFF cell_id not yet recovered */ + u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ +}; + +struct RECEPTION_STATISTICS_S { + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 BERErrorCount; /* Number of erronous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ + u32 TS_PER; /* Transport stream PER, + 0xFFFFFFFF indicate N/A */ + u32 MFER; /* DVB-H frame error rate in percentage, + 0xFFFFFFFF indicate N/A, valid only for DVB-H */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + u32 ErrorTSPackets; /* Number of erroneous + transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + + s32 MRC_SNR; /* dB */ + s32 MRC_RSSI; /* dBm */ + s32 MRC_InBandPwr; /* In band power in dBM */ +}; + + +/* Statistics information returned as response for + * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ +struct SMSHOSTLIB_STATISTICS_DVB_S { + /* Reception */ + struct RECEPTION_STATISTICS_S ReceptionData; + + /* Transmission parameters */ + struct TRANSMISSION_STATISTICS_S TransmissionData; + + /* Burst parameters, valid only for DVB-H */ +#define SRVM_MAX_PID_FILTERS 8 + struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; +}; + +struct SRVM_SIGNAL_STATUS_S { + u32 result; + u32 snr; + u32 tsPackets; + u32 etsPackets; + u32 constellation; + u32 hpCode; + u32 tpsSrvIndLP; + u32 tpsSrvIndHP; + u32 cellId; + u32 reason; + + s32 inBandPower; + u32 requestId; +}; + +struct SMSHOSTLIB_I2C_REQ_ST { + u32 DeviceAddress; /* I2c device address */ + u32 WriteCount; /* number of bytes to write */ + u32 ReadCount; /* number of bytes to read */ + u8 Data[1]; +}; + +struct SMSHOSTLIB_I2C_RES_ST { + u32 Status; /* non-zero value in case of failure */ + u32 ReadCount; /* number of bytes read */ + u8 Data[1]; +}; + + +struct smscore_config_gpio { +#define SMS_GPIO_DIRECTION_INPUT 0 +#define SMS_GPIO_DIRECTION_OUTPUT 1 + u8 direction; + +#define SMS_GPIO_PULLUPDOWN_NONE 0 +#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1 +#define SMS_GPIO_PULLUPDOWN_PULLUP 2 +#define SMS_GPIO_PULLUPDOWN_KEEPER 3 + u8 pullupdown; + +#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0 +#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 + u8 inputcharacteristics; + +#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 +#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 + u8 outputslewrate; + +#define SMS_GPIO_OUTPUTDRIVING_4mA 0 +#define SMS_GPIO_OUTPUTDRIVING_8mA 1 +#define SMS_GPIO_OUTPUTDRIVING_12mA 2 +#define SMS_GPIO_OUTPUTDRIVING_16mA 3 + u8 outputdriving; +}; + +struct smscore_gpio_config { +#define SMS_GPIO_DIRECTION_INPUT 0 +#define SMS_GPIO_DIRECTION_OUTPUT 1 + u8 Direction; + +#define SMS_GPIO_PULL_UP_DOWN_NONE 0 +#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1 +#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2 +#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3 + u8 PullUpDown; + +#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0 +#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1 + u8 InputCharacteristics; + +#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */ + + +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */ + u8 OutputSlewRate; + +#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */ +#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */ +#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */ +#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */ + +#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */ + u8 OutputDriving; +}; + +extern void smscore_registry_setmode(char *devpath, int mode); +extern int smscore_registry_getmode(char *devpath); + +extern int smscore_register_hotplug(hotplug_t hotplug); +extern void smscore_unregister_hotplug(hotplug_t hotplug); + +extern int smscore_register_device(struct smsdevice_params_t *params, + struct smscore_device_t **coredev); +extern void smscore_unregister_device(struct smscore_device_t *coredev); + +extern int smscore_start_device(struct smscore_device_t *coredev); +extern int smscore_load_firmware(struct smscore_device_t *coredev, + char *filename, + loadfirmware_t loadfirmware_handler); + +extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode); +extern int smscore_get_device_mode(struct smscore_device_t *coredev); + +extern int smscore_register_client(struct smscore_device_t *coredev, + struct smsclient_params_t *params, + struct smscore_client_t **client); +extern void smscore_unregister_client(struct smscore_client_t *client); + +extern int smsclient_sendrequest(struct smscore_client_t *client, + void *buffer, size_t size); +extern void smscore_onresponse(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb); + +extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); +extern int smscore_map_common_buffer(struct smscore_device_t *coredev, + struct vm_area_struct *vma); +extern int smscore_get_fw_filename(struct smscore_device_t *coredev, + int mode, char *filename); +extern int smscore_send_fw_file(struct smscore_device_t *coredev, + u8 *ufwbuf, int size); + +extern +struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev); +extern void smscore_putbuffer(struct smscore_device_t *coredev, + struct smscore_buffer_t *cb); + +/* old GPIO management */ +int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, + struct smscore_config_gpio *pinconfig); +int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); + +/* new GPIO management */ +extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, + struct smscore_gpio_config *pGpioConfig); +extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, + u8 NewLevel); +extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, + u8 *level); + +void smscore_set_board_id(struct smscore_device_t *core, int id); +int smscore_get_board_id(struct smscore_device_t *core); + +int smscore_led_state(struct smscore_device_t *core, int led); + + +/* ------------------------------------------------------------------------ */ + +#define DBG_INFO 1 +#define DBG_ADV 2 + +#define sms_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define dprintk(kern, lvl, fmt, arg...) do {\ + if (sms_dbg & lvl) \ + sms_printk(kern, fmt, ##arg); } while (0) + +#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) +#define sms_err(fmt, arg...) \ + sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg) +#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg) +#define sms_info(fmt, arg...) \ + dprintk(KERN_INFO, DBG_INFO, fmt, ##arg) +#define sms_debug(fmt, arg...) \ + dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) + + +#endif /* __SMS_CORE_API_H__ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsdvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsdvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsdvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsdvb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,962 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +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, or +(at your option) any later version. + + 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, see . + +****************************************************************/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include "smscoreapi.h" +#include "smsendian.h" +#include "sms-cards.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct smsdvb_client_t { + struct list_head entry; + + struct smscore_device_t *coredev; + struct smscore_client_t *smsclient; + + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dvb_frontend frontend; + + fe_status_t fe_status; + + struct completion tune_done; + + /* todo: save freq/band instead whole struct */ + struct dvb_frontend_parameters fe_params; + + struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; + int event_fe_state; + int event_unc_state; +}; + +static struct list_head g_smsdvb_clients; +static struct mutex g_smsdvb_clientslock; + +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + +/* Events that may come from DVB v3 adapter */ +static void sms_board_dvb3_event(struct smsdvb_client_t *client, + enum SMS_DVB3_EVENTS event) { + + struct smscore_device_t *coredev = client->coredev; + switch (event) { + case DVB3_EVENT_INIT: + sms_debug("DVB3_EVENT_INIT"); + sms_board_event(coredev, BOARD_EVENT_BIND); + break; + case DVB3_EVENT_SLEEP: + sms_debug("DVB3_EVENT_SLEEP"); + sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); + break; + case DVB3_EVENT_HOTPLUG: + sms_debug("DVB3_EVENT_HOTPLUG"); + sms_board_event(coredev, BOARD_EVENT_POWER_INIT); + break; + case DVB3_EVENT_FE_LOCK: + if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { + client->event_fe_state = DVB3_EVENT_FE_LOCK; + sms_debug("DVB3_EVENT_FE_LOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_LOCK); + } + break; + case DVB3_EVENT_FE_UNLOCK: + if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { + client->event_fe_state = DVB3_EVENT_FE_UNLOCK; + sms_debug("DVB3_EVENT_FE_UNLOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); + } + break; + case DVB3_EVENT_UNC_OK: + if (client->event_unc_state != DVB3_EVENT_UNC_OK) { + client->event_unc_state = DVB3_EVENT_UNC_OK; + sms_debug("DVB3_EVENT_UNC_OK"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); + } + break; + case DVB3_EVENT_UNC_ERR: + if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { + client->event_unc_state = DVB3_EVENT_UNC_ERR; + sms_debug("DVB3_EVENT_UNC_ERR"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); + } + break; + + default: + sms_err("Unknown dvb3 api event"); + break; + } +} + + +static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData, + struct SMSHOSTLIB_STATISTICS_ST *p) +{ + if (sms_dbg & 2) { + printk(KERN_DEBUG "Reserved = %d", p->Reserved); + printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); + printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); + printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); + printk(KERN_DEBUG "SNR = %d", p->SNR); + printk(KERN_DEBUG "BER = %d", p->BER); + printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC); + printk(KERN_DEBUG "TS_PER = %d", p->TS_PER); + printk(KERN_DEBUG "MFER = %d", p->MFER); + printk(KERN_DEBUG "RSSI = %d", p->RSSI); + printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); + printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); + printk(KERN_DEBUG "Frequency = %d", p->Frequency); + printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); + printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); + printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); + printk(KERN_DEBUG "CodeRate = %d", p->CodeRate); + printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate); + printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy); + printk(KERN_DEBUG "Constellation = %d", p->Constellation); + printk(KERN_DEBUG "BurstSize = %d", p->BurstSize); + printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration); + printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime); + printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime); + printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows); + printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols); + printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols); + printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets); + printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets); + printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs); + printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs); + printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs); + printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount); + printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount); + printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); + printk(KERN_DEBUG "PreBER = %d", p->PreBER); + printk(KERN_DEBUG "CellId = %d", p->CellId); + printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP); + printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP); + printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived); + } + + pReceptionData->IsDemodLocked = p->IsDemodLocked; + + pReceptionData->SNR = p->SNR; + pReceptionData->BER = p->BER; + pReceptionData->BERErrorCount = p->BERErrorCount; + pReceptionData->InBandPwr = p->InBandPwr; + pReceptionData->ErrorTSPackets = p->ErrorTSPackets; +}; + + +static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData, + struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) +{ + int i; + + if (sms_dbg & 2) { + printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); + printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); + printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); + printk(KERN_DEBUG "SNR = %d", p->SNR); + printk(KERN_DEBUG "RSSI = %d", p->RSSI); + printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); + printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); + printk(KERN_DEBUG "Frequency = %d", p->Frequency); + printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); + printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); + printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); + printk(KERN_DEBUG "SystemType = %d", p->SystemType); + printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); + printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); + printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); + + for (i = 0; i < 3; i++) { + printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); + printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); + printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); + printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); + printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); + printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); + printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); + printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); + printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); + printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); + printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); + printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); + } + } + + pReceptionData->IsDemodLocked = p->IsDemodLocked; + + pReceptionData->SNR = p->SNR; + pReceptionData->InBandPwr = p->InBandPwr; + + pReceptionData->ErrorTSPackets = 0; + pReceptionData->BER = 0; + pReceptionData->BERErrorCount = 0; + for (i = 0; i < 3; i++) { + pReceptionData->BER += p->LayerInfo[i].BER; + pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount; + pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets; + } +} + +static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) +{ + struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) + + cb->offset); + u32 *pMsgData = (u32 *) phdr + 1; + /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/ + bool is_status_update = false; + + smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); + + switch (phdr->msgType) { + case MSG_SMS_DVBT_BDA_DATA: + dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1), + cb->size - sizeof(struct SmsMsgHdr_ST)); + break; + + case MSG_SMS_RF_TUNE_RES: + case MSG_SMS_ISDBT_TUNE_RES: + complete(&client->tune_done); + break; + + case MSG_SMS_SIGNAL_DETECTED_IND: + sms_info("MSG_SMS_SIGNAL_DETECTED_IND"); + client->sms_stat_dvb.TransmissionData.IsDemodLocked = true; + is_status_update = true; + break; + + case MSG_SMS_NO_SIGNAL_IND: + sms_info("MSG_SMS_NO_SIGNAL_IND"); + client->sms_stat_dvb.TransmissionData.IsDemodLocked = false; + is_status_update = true; + break; + + case MSG_SMS_TRANSMISSION_IND: { + sms_info("MSG_SMS_TRANSMISSION_IND"); + + pMsgData++; + memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, + sizeof(struct TRANSMISSION_STATISTICS_S)); + + /* Mo need to correct guard interval + * (as opposed to old statistics message). + */ + CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData); + CORRECT_STAT_TRANSMISSON_MODE( + client->sms_stat_dvb.TransmissionData); + is_status_update = true; + break; + } + case MSG_SMS_HO_PER_SLICES_IND: { + struct RECEPTION_STATISTICS_S *pReceptionData = + &client->sms_stat_dvb.ReceptionData; + struct SRVM_SIGNAL_STATUS_S SignalStatusData; + + /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/ + pMsgData++; + SignalStatusData.result = pMsgData[0]; + SignalStatusData.snr = pMsgData[1]; + SignalStatusData.inBandPower = (s32) pMsgData[2]; + SignalStatusData.tsPackets = pMsgData[3]; + SignalStatusData.etsPackets = pMsgData[4]; + SignalStatusData.constellation = pMsgData[5]; + SignalStatusData.hpCode = pMsgData[6]; + SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03; + SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03; + SignalStatusData.cellId = pMsgData[9] & 0xFFFF; + SignalStatusData.reason = pMsgData[10]; + SignalStatusData.requestId = pMsgData[11]; + pReceptionData->IsRfLocked = pMsgData[16]; + pReceptionData->IsDemodLocked = pMsgData[17]; + pReceptionData->ModemState = pMsgData[12]; + pReceptionData->SNR = pMsgData[1]; + pReceptionData->BER = pMsgData[13]; + pReceptionData->RSSI = pMsgData[14]; + CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData); + + pReceptionData->InBandPwr = (s32) pMsgData[2]; + pReceptionData->CarrierOffset = (s32) pMsgData[15]; + pReceptionData->TotalTSPackets = pMsgData[3]; + pReceptionData->ErrorTSPackets = pMsgData[4]; + + /* TS PER */ + if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets) + > 0) { + pReceptionData->TS_PER = (SignalStatusData.etsPackets + * 100) / (SignalStatusData.tsPackets + + SignalStatusData.etsPackets); + } else { + pReceptionData->TS_PER = 0; + } + + pReceptionData->BERBitCount = pMsgData[18]; + pReceptionData->BERErrorCount = pMsgData[19]; + + pReceptionData->MRC_SNR = pMsgData[20]; + pReceptionData->MRC_InBandPwr = pMsgData[21]; + pReceptionData->MRC_RSSI = pMsgData[22]; + + is_status_update = true; + break; + } + case MSG_SMS_GET_STATISTICS_RES: { + union { + struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt; + struct SmsMsgStatisticsInfo_ST dvb; + } *p = (void *) (phdr + 1); + struct RECEPTION_STATISTICS_S *pReceptionData = + &client->sms_stat_dvb.ReceptionData; + + sms_info("MSG_SMS_GET_STATISTICS_RES"); + + is_status_update = true; + + switch (smscore_get_device_mode(client->coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt); + break; + default: + smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat); + } + if (!pReceptionData->IsDemodLocked) { + pReceptionData->SNR = 0; + pReceptionData->BER = 0; + pReceptionData->BERErrorCount = 0; + pReceptionData->InBandPwr = 0; + pReceptionData->ErrorTSPackets = 0; + } + + complete(&client->tune_done); + break; + } + default: + sms_info("Unhandled message %d", phdr->msgType); + + } + smscore_putbuffer(client->coredev, cb); + + if (is_status_update) { + if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) { + client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER + | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); + if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets + == 0) + sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); + else + sms_board_dvb3_event(client, + DVB3_EVENT_UNC_ERR); + + } else { + if (client->sms_stat_dvb.ReceptionData.IsRfLocked) + client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + else + client->fe_status = 0; + sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); + } + } + + return 0; +} + +static void smsdvb_unregister_client(struct smsdvb_client_t *client) +{ + /* must be called under clientslock */ + + list_del(&client->entry); + + smscore_unregister_client(client->smsclient); + dvb_unregister_frontend(&client->frontend); + dvb_dmxdev_release(&client->dmxdev); + dvb_dmx_release(&client->demux); + dvb_unregister_adapter(&client->adapter); + kfree(client); +} + +static void smsdvb_onremove(void *context) +{ + kmutex_lock(&g_smsdvb_clientslock); + + smsdvb_unregister_client((struct smsdvb_client_t *) context); + + kmutex_unlock(&g_smsdvb_clientslock); +} + +static int smsdvb_start_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct SmsMsgData_ST PidMsg; + + sms_debug("add pid %d(%x)", + feed->pid, feed->pid); + + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.xMsgHeader.msgDstId = HIF_TASK; + PidMsg.xMsgHeader.msgFlags = 0; + PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ; + PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.msgData[0] = feed->pid; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); + return smsclient_sendrequest(client->smsclient, + &PidMsg, sizeof(PidMsg)); +} + +static int smsdvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct SmsMsgData_ST PidMsg; + + sms_debug("remove pid %d(%x)", + feed->pid, feed->pid); + + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.xMsgHeader.msgDstId = HIF_TASK; + PidMsg.xMsgHeader.msgFlags = 0; + PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ; + PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.msgData[0] = feed->pid; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); + return smsclient_sendrequest(client->smsclient, + &PidMsg, sizeof(PidMsg)); +} + +static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, + void *buffer, size_t size, + struct completion *completion) +{ + int rc; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer); + rc = smsclient_sendrequest(client->smsclient, buffer, size); + if (rc < 0) + return rc; + + return wait_for_completion_timeout(completion, + msecs_to_jiffies(2000)) ? + 0 : -ETIME; +} + +static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) +{ + int rc; + struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, + DVBT_BDA_CONTROL_MSG_ID, + HIF_TASK, + sizeof(struct SmsMsgHdr_ST), 0 }; + + rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); + + return rc; +} + +static inline int led_feedback(struct smsdvb_client_t *client) +{ + if (client->fe_status & FE_HAS_LOCK) + return sms_board_led_feedback(client->coredev, + (client->sms_stat_dvb.ReceptionData.BER + == 0) ? SMS_LED_HI : SMS_LED_LO); + else + return sms_board_led_feedback(client->coredev, SMS_LED_OFF); +} + +static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *stat = client->fe_status; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *ber = client->sms_stat_dvb.ReceptionData.BER; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + int rc; + + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95) + *strength = 0; + else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29) + *strength = 100; + else + *strength = + (client->sms_stat_dvb.ReceptionData.InBandPwr + + 95) * 3 / 2; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *snr = client->sms_stat_dvb.ReceptionData.SNR; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets; + + led_feedback(client); + + return rc; +} + +static int smsdvb_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + sms_debug(""); + + tune->min_delay_ms = 400; + tune->step_size = 250000; + tune->max_drift = 0; + return 0; +} + +static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + struct { + struct SmsMsgHdr_ST Msg; + u32 Data[3]; + } Msg; + + int ret; + + client->fe_status = FE_HAS_SIGNAL; + client->event_fe_state = -1; + client->event_unc_state = -1; + fe->dtv_property_cache.delivery_system = SYS_DVBT; + + Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msgDstId = HIF_TASK; + Msg.Msg.msgFlags = 0; + Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; + Msg.Msg.msgLength = sizeof(Msg); + Msg.Data[0] = c->frequency; + Msg.Data[2] = 12000000; + + sms_info("%s: freq %d band %d", __func__, c->frequency, + c->bandwidth_hz); + + switch (c->bandwidth_hz / 1000000) { + case 8: + Msg.Data[1] = BW_8_MHZ; + break; + case 7: + Msg.Data[1] = BW_7_MHZ; + break; + case 6: + Msg.Data[1] = BW_6_MHZ; + break; + case 0: + return -EOPNOTSUPP; + default: + return -EINVAL; + } + /* Disable LNA, if any. An error is returned if no LNA is present */ + ret = sms_board_lna_control(client->coredev, 0); + if (ret == 0) { + fe_status_t status; + + /* tune with LNA off at first */ + ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); + + smsdvb_read_status(fe, &status); + + if (status & FE_HAS_LOCK) + return ret; + + /* previous tune didn't lock - enable LNA and tune again */ + sms_board_lna_control(client->coredev, 1); + } + + return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); +} + +static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + struct { + struct SmsMsgHdr_ST Msg; + u32 Data[4]; + } Msg; + + fe->dtv_property_cache.delivery_system = SYS_ISDBT; + + Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msgDstId = HIF_TASK; + Msg.Msg.msgFlags = 0; + Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ; + Msg.Msg.msgLength = sizeof(Msg); + + if (c->isdbt_sb_segment_idx == -1) + c->isdbt_sb_segment_idx = 0; + + switch (c->isdbt_sb_segment_count) { + case 3: + Msg.Data[1] = BW_ISDBT_3SEG; + break; + case 1: + Msg.Data[1] = BW_ISDBT_1SEG; + break; + case 0: /* AUTO */ + switch (c->bandwidth_hz / 1000000) { + case 8: + case 7: + c->isdbt_sb_segment_count = 3; + Msg.Data[1] = BW_ISDBT_3SEG; + break; + case 6: + c->isdbt_sb_segment_count = 1; + Msg.Data[1] = BW_ISDBT_1SEG; + break; + default: /* Assumes 6 MHZ bw */ + c->isdbt_sb_segment_count = 1; + c->bandwidth_hz = 6000; + Msg.Data[1] = BW_ISDBT_1SEG; + break; + } + break; + default: + sms_info("Segment count %d not supported", c->isdbt_sb_segment_count); + return -EINVAL; + } + + Msg.Data[0] = c->frequency; + Msg.Data[2] = 12000000; + Msg.Data[3] = c->isdbt_sb_segment_idx; + + sms_info("%s: freq %d segwidth %d segindex %d\n", __func__, + c->frequency, c->isdbt_sb_segment_count, + c->isdbt_sb_segment_idx); + + return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); +} + +static int smsdvb_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct smscore_device_t *coredev = client->coredev; + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + return smsdvb_dvbt_set_frontend(fe, fep); + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + return smsdvb_isdbt_set_frontend(fe, fep); + default: + return -EINVAL; + } +} + +static int smsdvb_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_debug(""); + + /* todo: */ + memcpy(fep, &client->fe_params, + sizeof(struct dvb_frontend_parameters)); + + return 0; +} + +static int smsdvb_init(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_power(client->coredev, 1); + + sms_board_dvb3_event(client, DVB3_EVENT_INIT); + return 0; +} + +static int smsdvb_sleep(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_led_feedback(client->coredev, SMS_LED_OFF); + sms_board_power(client->coredev, 0); + + sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); + + return 0; +} + +static void smsdvb_release(struct dvb_frontend *fe) +{ + /* do nothing */ +} + +static struct dvb_frontend_ops smsdvb_fe_ops = { + .info = { + .name = "Siano Mobile Digital MDTV Receiver", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = smsdvb_release, + + .set_frontend = smsdvb_set_frontend, + .get_frontend = smsdvb_get_frontend, + .get_tune_settings = smsdvb_get_tune_settings, + + .read_status = smsdvb_read_status, + .read_ber = smsdvb_read_ber, + .read_signal_strength = smsdvb_read_signal_strength, + .read_snr = smsdvb_read_snr, + .read_ucblocks = smsdvb_read_ucblocks, + + .init = smsdvb_init, + .sleep = smsdvb_sleep, +}; + +static int smsdvb_hotplug(struct smscore_device_t *coredev, + struct device *device, int arrival) +{ + struct smsclient_params_t params; + struct smsdvb_client_t *client; + int rc; + + /* device removal handled by onremove callback */ + if (!arrival) + return 0; + client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); + if (!client) { + sms_err("kmalloc() failed"); + return -ENOMEM; + } + + /* register dvb adapter */ + rc = dvb_register_adapter(&client->adapter, + sms_get_board( + smscore_get_board_id(coredev))->name, + THIS_MODULE, device, adapter_nr); + if (rc < 0) { + sms_err("dvb_register_adapter() failed %d", rc); + goto adapter_error; + } + + /* init dvb demux */ + client->demux.dmx.capabilities = DMX_TS_FILTERING; + client->demux.filternum = 32; /* todo: nova ??? */ + client->demux.feednum = 32; + client->demux.start_feed = smsdvb_start_feed; + client->demux.stop_feed = smsdvb_stop_feed; + + rc = dvb_dmx_init(&client->demux); + if (rc < 0) { + sms_err("dvb_dmx_init failed %d", rc); + goto dvbdmx_error; + } + + /* init dmxdev */ + client->dmxdev.filternum = 32; + client->dmxdev.demux = &client->demux.dmx; + client->dmxdev.capabilities = 0; + + rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); + if (rc < 0) { + sms_err("dvb_dmxdev_init failed %d", rc); + goto dmxdev_error; + } + + /* init and register frontend */ + memcpy(&client->frontend.ops, &smsdvb_fe_ops, + sizeof(struct dvb_frontend_ops)); + + rc = dvb_register_frontend(&client->adapter, &client->frontend); + if (rc < 0) { + sms_err("frontend registration failed %d", rc); + goto frontend_error; + } + + params.initial_id = 1; + params.data_type = MSG_SMS_DVBT_BDA_DATA; + params.onresponse_handler = smsdvb_onresponse; + params.onremove_handler = smsdvb_onremove; + params.context = client; + + rc = smscore_register_client(coredev, ¶ms, &client->smsclient); + if (rc < 0) { + sms_err("smscore_register_client() failed %d", rc); + goto client_error; + } + + client->coredev = coredev; + + init_completion(&client->tune_done); + + kmutex_lock(&g_smsdvb_clientslock); + + list_add(&client->entry, &g_smsdvb_clients); + + kmutex_unlock(&g_smsdvb_clientslock); + + client->event_fe_state = -1; + client->event_unc_state = -1; + sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); + + sms_info("success"); + sms_board_setup(coredev); + + return 0; + +client_error: + dvb_unregister_frontend(&client->frontend); + +frontend_error: + dvb_dmxdev_release(&client->dmxdev); + +dmxdev_error: + dvb_dmx_release(&client->demux); + +dvbdmx_error: + dvb_unregister_adapter(&client->adapter); + +adapter_error: + kfree(client); + return rc; +} + +static int __init smsdvb_module_init(void) +{ + int rc; + + INIT_LIST_HEAD(&g_smsdvb_clients); + kmutex_init(&g_smsdvb_clientslock); + + rc = smscore_register_hotplug(smsdvb_hotplug); + + sms_debug(""); + + return rc; +} + +static void __exit smsdvb_module_exit(void) +{ + smscore_unregister_hotplug(smsdvb_hotplug); + + kmutex_lock(&g_smsdvb_clientslock); + + while (!list_empty(&g_smsdvb_clients)) + smsdvb_unregister_client( + (struct smsdvb_client_t *) g_smsdvb_clients.next); + + kmutex_unlock(&g_smsdvb_clientslock); +} + +module_init(smsdvb_module_init); +module_exit(smsdvb_module_exit); + +MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); +MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsendian.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsendian.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsendian.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsendian.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,102 @@ +/**************************************************************** + + Siano Mobile Silicon, Inc. + MDTV receiver kernel modules. + Copyright (C) 2006-2009, Uri Shkolnik + + 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, or + (at your option) any later version. + + 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, see . + + ****************************************************************/ + +#include + +#include "smsendian.h" +#include "smscoreapi.h" + +void smsendian_handle_tx_message(void *buffer) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + int i; + int msgWords; + + switch (msg->xMsgHeader.msgType) { + case MSG_SMS_DATA_DOWNLOAD_REQ: + { + msg->msgData[0] = le32_to_cpu(msg->msgData[0]); + break; + } + + default: + msgWords = (msg->xMsgHeader.msgLength - + sizeof(struct SmsMsgHdr_ST))/4; + + for (i = 0; i < msgWords; i++) + msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + + break; + } +#endif /* __BIG_ENDIAN */ +} +EXPORT_SYMBOL_GPL(smsendian_handle_tx_message); + +void smsendian_handle_rx_message(void *buffer) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + int i; + int msgWords; + + switch (msg->xMsgHeader.msgType) { + case MSG_SMS_GET_VERSION_EX_RES: + { + struct SmsVersionRes_ST *ver = + (struct SmsVersionRes_ST *) msg; + ver->ChipModel = le16_to_cpu(ver->ChipModel); + break; + } + + case MSG_SMS_DVBT_BDA_DATA: + case MSG_SMS_DAB_CHANNEL: + case MSG_SMS_DATA_MSG: + { + break; + } + + default: + { + msgWords = (msg->xMsgHeader.msgLength - + sizeof(struct SmsMsgHdr_ST))/4; + + for (i = 0; i < msgWords; i++) + msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + + break; + } + } +#endif /* __BIG_ENDIAN */ +} +EXPORT_SYMBOL_GPL(smsendian_handle_rx_message); + +void smsendian_handle_message_header(void *msg) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg; + + phdr->msgType = le16_to_cpu(phdr->msgType); + phdr->msgLength = le16_to_cpu(phdr->msgLength); + phdr->msgFlags = le16_to_cpu(phdr->msgFlags); +#endif /* __BIG_ENDIAN */ +} +EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsendian.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsendian.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsendian.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsendian.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,32 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2009, Uri Shkolnik + +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, or +(at your option) any later version. + + 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, see . + +****************************************************************/ + +#ifndef __SMS_ENDIAN_H__ +#define __SMS_ENDIAN_H__ + +#include + +extern void smsendian_handle_tx_message(void *buffer); +extern void smsendian_handle_rx_message(void *buffer); +extern void smsendian_handle_message_header(void *msg); + +#endif /* __SMS_ENDIAN_H__ */ + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsir.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,114 @@ +/**************************************************************** + + Siano Mobile Silicon, Inc. + MDTV receiver kernel modules. + Copyright (C) 2006-2009, Uri Shkolnik + + Copyright (c) 2010 - Mauro Carvalho Chehab + - Ported the driver to use rc-core + - IR raw event decoding is now done at rc-core + - Code almost re-written + + 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, or + (at your option) any later version. + + 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, see . + + ****************************************************************/ + + +#include +#include + +#include "smscoreapi.h" +#include "smsir.h" +#include "sms-cards.h" + +#define MODULE_NAME "smsmdtv" + +void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len) +{ + int i; + const s32 *samples = (const void *)buf; + + for (i = 0; i < len >> 2; i++) { + DEFINE_IR_RAW_EVENT(ev); + + ev.duration = abs(samples[i]) * 1000; /* Convert to ns */ + ev.pulse = (samples[i] > 0) ? false : true; + + ir_raw_event_store(coredev->ir.dev, &ev); + } + ir_raw_event_handle(coredev->ir.dev); +} + +int sms_ir_init(struct smscore_device_t *coredev) +{ + int err; + int board_id = smscore_get_board_id(coredev); + struct rc_dev *dev; + + sms_log("Allocating rc device"); + dev = rc_allocate_device(); + if (!dev) { + sms_err("Not enough memory"); + return -ENOMEM; + } + + coredev->ir.controller = 0; /* Todo: vega/nova SPI number */ + coredev->ir.timeout = IR_DEFAULT_TIMEOUT; + sms_log("IR port %d, timeout %d ms", + coredev->ir.controller, coredev->ir.timeout); + + snprintf(coredev->ir.name, sizeof(coredev->ir.name), + "SMS IR (%s)", sms_get_board(board_id)->name); + + strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys)); + strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys)); + + dev->input_name = coredev->ir.name; + dev->input_phys = coredev->ir.phys; + dev->dev.parent = coredev->device; + +#if 0 + /* TODO: properly initialize the parameters bellow */ + dev->input_id.bustype = BUS_USB; + dev->input_id.version = 1; + dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); +#endif + + dev->priv = coredev; + dev->driver_type = RC_DRIVER_IR_RAW; + dev->allowed_protos = RC_TYPE_ALL; + dev->map_name = sms_get_board(board_id)->rc_codes; + dev->driver_name = MODULE_NAME; + + sms_log("Input device (IR) %s is set for key events", dev->input_name); + + err = rc_register_device(dev); + if (err < 0) { + sms_err("Failed to register device"); + rc_free_device(dev); + return err; + } + + coredev->ir.dev = dev; + return 0; +} + +void sms_ir_exit(struct smscore_device_t *coredev) +{ + if (coredev->ir.dev) + rc_unregister_device(coredev->ir.dev); + + sms_log(""); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsir.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsir.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,55 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2009, Uri Shkolnik + + Copyright (c) 2010 - Mauro Carvalho Chehab + - Ported the driver to use rc-core + - IR raw event decoding is now done at rc-core + - Code almost re-written + +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, or +(at your option) any later version. + + 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, see . + +****************************************************************/ + +#ifndef __SMS_IR_H__ +#define __SMS_IR_H__ + +#include +#include + +#define IR_DEFAULT_TIMEOUT 100 + +struct smscore_device_t; + +struct ir_t { + struct rc_dev *dev; + char name[40]; + char phys[32]; + + char *rc_codes; + u64 protocol; + + u32 timeout; + u32 controller; +}; + +int sms_ir_init(struct smscore_device_t *coredev); +void sms_ir_exit(struct smscore_device_t *coredev); +void sms_ir_event(struct smscore_device_t *coredev, + const char *buf, int len); + +#endif /* __SMS_IR_H__ */ + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smssdio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smssdio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smssdio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smssdio.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,364 @@ +/* + * smssdio.c - Siano 1xxx SDIO interface driver + * + * Copyright 2008 Pierre Ossman + * + * Based on code by Siano Mobile Silicon, Inc., + * Copyright (C) 2006-2008, Uri Shkolnik + * + * 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, or (at + * your option) any later version. + * + * + * This hardware is a bit odd in that all transfers should be done + * to/from the SMSSDIO_DATA register, yet the "increase address" bit + * always needs to be set. + * + * Also, buffers from the card are always aligned to 128 byte + * boundaries. + */ + +/* + * General cleanup notes: + * + * - only typedefs should be name *_t + * + * - use ERR_PTR and friends for smscore_register_device() + * + * - smscore_getbuffer should zero fields + * + * Fix stop command + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "smscoreapi.h" +#include "sms-cards.h" + +/* Registers */ + +#define SMSSDIO_DATA 0x00 +#define SMSSDIO_INT 0x04 +#define SMSSDIO_BLOCK_SIZE 128 + +static const struct sdio_device_id smssdio_ids[] __devinitconst = { + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), + .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), + .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0), + .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0), + .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE), + .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, smssdio_ids); + +struct smssdio_device { + struct sdio_func *func; + + struct smscore_device_t *coredev; + + struct smscore_buffer_t *split_cb; +}; + +/*******************************************************************/ +/* Siano core callbacks */ +/*******************************************************************/ + +static int smssdio_sendrequest(void *context, void *buffer, size_t size) +{ + int ret = 0; + struct smssdio_device *smsdev; + + smsdev = context; + + sdio_claim_host(smsdev->func); + + while (size >= smsdev->func->cur_blksize) { + ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, + buffer, smsdev->func->cur_blksize); + if (ret) + goto out; + + buffer += smsdev->func->cur_blksize; + size -= smsdev->func->cur_blksize; + } + + if (size) { + ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, + buffer, size); + } + +out: + sdio_release_host(smsdev->func); + + return ret; +} + +/*******************************************************************/ +/* SDIO callbacks */ +/*******************************************************************/ + +static void smssdio_interrupt(struct sdio_func *func) +{ + int ret, isr; + + struct smssdio_device *smsdev; + struct smscore_buffer_t *cb; + struct SmsMsgHdr_ST *hdr; + size_t size; + + smsdev = sdio_get_drvdata(func); + + /* + * The interrupt register has no defined meaning. It is just + * a way of turning of the level triggered interrupt. + */ + isr = sdio_readb(func, SMSSDIO_INT, &ret); + if (ret) { + sms_err("Unable to read interrupt register!\n"); + return; + } + + if (smsdev->split_cb == NULL) { + cb = smscore_getbuffer(smsdev->coredev); + if (!cb) { + sms_err("Unable to allocate data buffer!\n"); + return; + } + + ret = sdio_memcpy_fromio(smsdev->func, + cb->p, + SMSSDIO_DATA, + SMSSDIO_BLOCK_SIZE); + if (ret) { + sms_err("Error %d reading initial block!\n", ret); + return; + } + + hdr = cb->p; + + if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) { + smsdev->split_cb = cb; + return; + } + + if (hdr->msgLength > smsdev->func->cur_blksize) + size = hdr->msgLength - smsdev->func->cur_blksize; + else + size = 0; + } else { + cb = smsdev->split_cb; + hdr = cb->p; + + size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST); + + smsdev->split_cb = NULL; + } + + if (size) { + void *buffer; + + buffer = cb->p + (hdr->msgLength - size); + size = ALIGN(size, SMSSDIO_BLOCK_SIZE); + + BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE); + + /* + * First attempt to transfer all of it in one go... + */ + ret = sdio_memcpy_fromio(smsdev->func, + buffer, + SMSSDIO_DATA, + size); + if (ret && ret != -EINVAL) { + smscore_putbuffer(smsdev->coredev, cb); + sms_err("Error %d reading data from card!\n", ret); + return; + } + + /* + * ..then fall back to one block at a time if that is + * not possible... + * + * (we have to do this manually because of the + * problem with the "increase address" bit) + */ + if (ret == -EINVAL) { + while (size) { + ret = sdio_memcpy_fromio(smsdev->func, + buffer, SMSSDIO_DATA, + smsdev->func->cur_blksize); + if (ret) { + smscore_putbuffer(smsdev->coredev, cb); + sms_err("Error %d reading " + "data from card!\n", ret); + return; + } + + buffer += smsdev->func->cur_blksize; + if (size > smsdev->func->cur_blksize) + size -= smsdev->func->cur_blksize; + else + size = 0; + } + } + } + + cb->size = hdr->msgLength; + cb->offset = 0; + + smscore_onresponse(smsdev->coredev, cb); +} + +static int __devinit smssdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret; + + int board_id; + struct smssdio_device *smsdev; + struct smsdevice_params_t params; + + board_id = id->driver_data; + + smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL); + if (!smsdev) + return -ENOMEM; + + smsdev->func = func; + + memset(¶ms, 0, sizeof(struct smsdevice_params_t)); + + params.device = &func->dev; + params.buffer_size = 0x5000; /* ?? */ + params.num_buffers = 22; /* ?? */ + params.context = smsdev; + + snprintf(params.devpath, sizeof(params.devpath), + "sdio\\%s", sdio_func_id(func)); + + params.sendrequest_handler = smssdio_sendrequest; + + params.device_type = sms_get_board(board_id)->type; + + if (params.device_type != SMS_STELLAR) + params.flags |= SMS_DEVICE_FAMILY2; + else { + /* + * FIXME: Stellar needs special handling... + */ + ret = -ENODEV; + goto free; + } + + ret = smscore_register_device(¶ms, &smsdev->coredev); + if (ret < 0) + goto free; + + smscore_set_board_id(smsdev->coredev, board_id); + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) + goto release; + + ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE); + if (ret) + goto disable; + + ret = sdio_claim_irq(func, smssdio_interrupt); + if (ret) + goto disable; + + sdio_set_drvdata(func, smsdev); + + sdio_release_host(func); + + ret = smscore_start_device(smsdev->coredev); + if (ret < 0) + goto reclaim; + + return 0; + +reclaim: + sdio_claim_host(func); + sdio_release_irq(func); +disable: + sdio_disable_func(func); +release: + sdio_release_host(func); + smscore_unregister_device(smsdev->coredev); +free: + kfree(smsdev); + + return ret; +} + +static void smssdio_remove(struct sdio_func *func) +{ + struct smssdio_device *smsdev; + + smsdev = sdio_get_drvdata(func); + + /* FIXME: racy! */ + if (smsdev->split_cb) + smscore_putbuffer(smsdev->coredev, smsdev->split_cb); + + smscore_unregister_device(smsdev->coredev); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); + + kfree(smsdev); +} + +static struct sdio_driver smssdio_driver = { + .name = "smssdio", + .id_table = smssdio_ids, + .probe = smssdio_probe, + .remove = smssdio_remove, +}; + +/*******************************************************************/ +/* Module functions */ +/*******************************************************************/ + +static int __init smssdio_module_init(void) +{ + int ret = 0; + + printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n"); + printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n"); + + ret = sdio_register_driver(&smssdio_driver); + + return ret; +} + +static void __exit smssdio_module_exit(void) +{ + sdio_unregister_driver(&smssdio_driver); +} + +module_init(smssdio_module_init); +module_exit(smssdio_module_exit); + +MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver"); +MODULE_AUTHOR("Pierre Ossman"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsusb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsusb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsusb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/siano/smsusb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,582 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat + +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, or +(at your option) any later version. + + 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, see . + +****************************************************************/ + +#include +#include +#include +#include +#include + +#include "smscoreapi.h" +#include "sms-cards.h" +#include "smsendian.h" + +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + +#define USB1_BUFFER_SIZE 0x1000 +#define USB2_BUFFER_SIZE 0x4000 + +#define MAX_BUFFERS 50 +#define MAX_URBS 10 + +struct smsusb_device_t; + +struct smsusb_urb_t { + struct smscore_buffer_t *cb; + struct smsusb_device_t *dev; + + struct urb urb; +}; + +struct smsusb_device_t { + struct usb_device *udev; + struct smscore_device_t *coredev; + + struct smsusb_urb_t surbs[MAX_URBS]; + + int response_alignment; + int buffer_size; +}; + +static int smsusb_submit_urb(struct smsusb_device_t *dev, + struct smsusb_urb_t *surb); + +static void smsusb_onresponse(struct urb *urb) +{ + struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context; + struct smsusb_device_t *dev = surb->dev; + + if (urb->status == -ESHUTDOWN) { + sms_err("error, urb status %d (-ESHUTDOWN), %d bytes", + urb->status, urb->actual_length); + return; + } + + if ((urb->actual_length > 0) && (urb->status == 0)) { + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p; + + smsendian_handle_message_header(phdr); + if (urb->actual_length >= phdr->msgLength) { + surb->cb->size = phdr->msgLength; + + if (dev->response_alignment && + (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) { + + surb->cb->offset = + dev->response_alignment + + ((phdr->msgFlags >> 8) & 3); + + /* sanity check */ + if (((int) phdr->msgLength + + surb->cb->offset) > urb->actual_length) { + sms_err("invalid response " + "msglen %d offset %d " + "size %d", + phdr->msgLength, + surb->cb->offset, + urb->actual_length); + goto exit_and_resubmit; + } + + /* move buffer pointer and + * copy header to its new location */ + memcpy((char *) phdr + surb->cb->offset, + phdr, sizeof(struct SmsMsgHdr_ST)); + } else + surb->cb->offset = 0; + + smscore_onresponse(dev->coredev, surb->cb); + surb->cb = NULL; + } else { + sms_err("invalid response " + "msglen %d actual %d", + phdr->msgLength, urb->actual_length); + } + } else + sms_err("error, urb status %d, %d bytes", + urb->status, urb->actual_length); + + +exit_and_resubmit: + smsusb_submit_urb(dev, surb); +} + +static int smsusb_submit_urb(struct smsusb_device_t *dev, + struct smsusb_urb_t *surb) +{ + if (!surb->cb) { + surb->cb = smscore_getbuffer(dev->coredev); + if (!surb->cb) { + sms_err("smscore_getbuffer(...) returned NULL"); + return -ENOMEM; + } + } + + usb_fill_bulk_urb( + &surb->urb, + dev->udev, + usb_rcvbulkpipe(dev->udev, 0x81), + surb->cb->p, + dev->buffer_size, + smsusb_onresponse, + surb + ); + surb->urb.transfer_dma = surb->cb->phys; + surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + return usb_submit_urb(&surb->urb, GFP_ATOMIC); +} + +static void smsusb_stop_streaming(struct smsusb_device_t *dev) +{ + int i; + + for (i = 0; i < MAX_URBS; i++) { + usb_kill_urb(&dev->surbs[i].urb); + + if (dev->surbs[i].cb) { + smscore_putbuffer(dev->coredev, dev->surbs[i].cb); + dev->surbs[i].cb = NULL; + } + } +} + +static int smsusb_start_streaming(struct smsusb_device_t *dev) +{ + int i, rc; + + for (i = 0; i < MAX_URBS; i++) { + rc = smsusb_submit_urb(dev, &dev->surbs[i]); + if (rc < 0) { + sms_err("smsusb_submit_urb(...) failed"); + smsusb_stop_streaming(dev); + break; + } + } + + return rc; +} + +static int smsusb_sendrequest(void *context, void *buffer, size_t size) +{ + struct smsusb_device_t *dev = (struct smsusb_device_t *) context; + int dummy; + + smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); + return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), + buffer, size, &dummy, 1000); +} + +static char *smsusb1_fw_lkup[] = { + "dvbt_stellar_usb.inp", + "dvbh_stellar_usb.inp", + "tdmb_stellar_usb.inp", + "none", + "dvbt_bda_stellar_usb.inp", +}; + +static inline char *sms_get_fw_name(int mode, int board_id) +{ + char **fw = sms_get_board(board_id)->fw; + return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode]; +} + +static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) +{ + const struct firmware *fw; + u8 *fw_buffer; + int rc, dummy; + char *fw_filename; + + if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) { + sms_err("invalid firmware id specified %d", id); + return -EINVAL; + } + + fw_filename = sms_get_fw_name(id, board_id); + + rc = request_firmware(&fw, fw_filename, &udev->dev); + if (rc < 0) { + sms_warn("failed to open \"%s\" mode %d, " + "trying again with default firmware", fw_filename, id); + + fw_filename = smsusb1_fw_lkup[id]; + rc = request_firmware(&fw, fw_filename, &udev->dev); + if (rc < 0) { + sms_warn("failed to open \"%s\" mode %d", + fw_filename, id); + + return rc; + } + } + + fw_buffer = kmalloc(fw->size, GFP_KERNEL); + if (fw_buffer) { + memcpy(fw_buffer, fw->data, fw->size); + + rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), + fw_buffer, fw->size, &dummy, 1000); + + sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc); + + kfree(fw_buffer); + } else { + sms_err("failed to allocate firmware buffer"); + rc = -ENOMEM; + } + sms_info("read FW %s, size=%zd", fw_filename, fw->size); + + release_firmware(fw); + + return rc; +} + +static void smsusb1_detectmode(void *context, int *mode) +{ + char *product_string = + ((struct smsusb_device_t *) context)->udev->product; + + *mode = DEVICE_MODE_NONE; + + if (!product_string) { + product_string = "none"; + sms_err("product string not found"); + } else if (strstr(product_string, "DVBH")) + *mode = 1; + else if (strstr(product_string, "BDA")) + *mode = 4; + else if (strstr(product_string, "DVBT")) + *mode = 0; + else if (strstr(product_string, "TDMB")) + *mode = 2; + + sms_info("%d \"%s\"", *mode, product_string); +} + +static int smsusb1_setmode(void *context, int mode) +{ + struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, + sizeof(struct SmsMsgHdr_ST), 0 }; + + if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { + sms_err("invalid firmware id specified %d", mode); + return -EINVAL; + } + + return smsusb_sendrequest(context, &Msg, sizeof(Msg)); +} + +static void smsusb_term_device(struct usb_interface *intf) +{ + struct smsusb_device_t *dev = usb_get_intfdata(intf); + + if (dev) { + smsusb_stop_streaming(dev); + + /* unregister from smscore */ + if (dev->coredev) + smscore_unregister_device(dev->coredev); + + sms_info("device %p destroyed", dev); + kfree(dev); + } + + usb_set_intfdata(intf, NULL); +} + +static int smsusb_init_device(struct usb_interface *intf, int board_id) +{ + struct smsdevice_params_t params; + struct smsusb_device_t *dev; + int i, rc; + + /* create device object */ + dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL); + if (!dev) { + sms_err("kzalloc(sizeof(struct smsusb_device_t) failed"); + return -ENOMEM; + } + + memset(¶ms, 0, sizeof(params)); + usb_set_intfdata(intf, dev); + dev->udev = interface_to_usbdev(intf); + + params.device_type = sms_get_board(board_id)->type; + + switch (params.device_type) { + case SMS_STELLAR: + dev->buffer_size = USB1_BUFFER_SIZE; + + params.setmode_handler = smsusb1_setmode; + params.detectmode_handler = smsusb1_detectmode; + break; + default: + sms_err("Unspecified sms device type!"); + /* fall-thru */ + case SMS_NOVA_A0: + case SMS_NOVA_B0: + case SMS_VEGA: + dev->buffer_size = USB2_BUFFER_SIZE; + dev->response_alignment = + le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - + sizeof(struct SmsMsgHdr_ST); + + params.flags |= SMS_DEVICE_FAMILY2; + break; + } + + params.device = &dev->udev->dev; + params.buffer_size = dev->buffer_size; + params.num_buffers = MAX_BUFFERS; + params.sendrequest_handler = smsusb_sendrequest; + params.context = dev; + usb_make_path(dev->udev, params.devpath, sizeof(params.devpath)); + + /* register in smscore */ + rc = smscore_register_device(¶ms, &dev->coredev); + if (rc < 0) { + sms_err("smscore_register_device(...) failed, rc %d", rc); + smsusb_term_device(intf); + return rc; + } + + smscore_set_board_id(dev->coredev, board_id); + + /* initialize urbs */ + for (i = 0; i < MAX_URBS; i++) { + dev->surbs[i].dev = dev; + usb_init_urb(&dev->surbs[i].urb); + } + + sms_info("smsusb_start_streaming(...)."); + rc = smsusb_start_streaming(dev); + if (rc < 0) { + sms_err("smsusb_start_streaming(...) failed"); + smsusb_term_device(intf); + return rc; + } + + rc = smscore_start_device(dev->coredev); + if (rc < 0) { + sms_err("smscore_start_device(...) failed"); + smsusb_term_device(intf); + return rc; + } + + sms_info("device %p created", dev); + + return rc; +} + +static int __devinit smsusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + char devpath[32]; + int i, rc; + + rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); + rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); + + if (intf->num_altsetting > 0) { + rc = usb_set_interface( + udev, intf->cur_altsetting->desc.bInterfaceNumber, 0); + if (rc < 0) { + sms_err("usb_set_interface failed, rc %d", rc); + return rc; + } + } + + sms_info("smsusb_probe %d", + intf->cur_altsetting->desc.bInterfaceNumber); + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) + sms_info("endpoint %d %02x %02x %d", i, + intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, + intf->cur_altsetting->endpoint[i].desc.bmAttributes, + intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); + + if ((udev->actconfig->desc.bNumInterfaces == 2) && + (intf->cur_altsetting->desc.bInterfaceNumber == 0)) { + sms_err("rom interface 0 is not used"); + return -ENODEV; + } + + if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { + snprintf(devpath, sizeof(devpath), "usb\\%d-%s", + udev->bus->busnum, udev->devpath); + sms_info("stellar device was found."); + return smsusb1_load_firmware( + udev, smscore_registry_getmode(devpath), + id->driver_info); + } + + rc = smsusb_init_device(intf, id->driver_info); + sms_info("rc %d", rc); + sms_board_load_modules(id->driver_info); + return rc; +} + +static void smsusb_disconnect(struct usb_interface *intf) +{ + smsusb_term_device(intf); +} + +static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct smsusb_device_t *dev = usb_get_intfdata(intf); + printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event); + smsusb_stop_streaming(dev); + return 0; +} + +static int smsusb_resume(struct usb_interface *intf) +{ + int rc, i; + struct smsusb_device_t *dev = usb_get_intfdata(intf); + struct usb_device *udev = interface_to_usbdev(intf); + + printk(KERN_INFO "%s: Entering.\n", __func__); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); + + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) + printk(KERN_INFO "endpoint %d %02x %02x %d\n", i, + intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, + intf->cur_altsetting->endpoint[i].desc.bmAttributes, + intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); + + if (intf->num_altsetting > 0) { + rc = usb_set_interface(udev, + intf->cur_altsetting->desc. + bInterfaceNumber, 0); + if (rc < 0) { + printk(KERN_INFO "%s usb_set_interface failed, " + "rc %d\n", __func__, rc); + return rc; + } + } + + smsusb_start_streaming(dev); + return 0; +} + +static const struct usb_device_id smsusb_id_table[] __devinitconst = { + { USB_DEVICE(0x187f, 0x0010), + .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + { USB_DEVICE(0x187f, 0x0100), + .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + { USB_DEVICE(0x187f, 0x0200), + .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A }, + { USB_DEVICE(0x187f, 0x0201), + .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B }, + { USB_DEVICE(0x187f, 0x0300), + .driver_info = SMS1XXX_BOARD_SIANO_VEGA }, + { USB_DEVICE(0x2040, 0x1700), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT }, + { USB_DEVICE(0x2040, 0x1800), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A }, + { USB_DEVICE(0x2040, 0x1801), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B }, + { USB_DEVICE(0x2040, 0x2000), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2009), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 }, + { USB_DEVICE(0x2040, 0x200a), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2010), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2011), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2019), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x5500), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5510), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5520), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5530), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5580), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5590), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x187f, 0x0202), + .driver_info = SMS1XXX_BOARD_SIANO_NICE }, + { USB_DEVICE(0x187f, 0x0301), + .driver_info = SMS1XXX_BOARD_SIANO_VENICE }, + { USB_DEVICE(0x2040, 0xb900), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb910), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb980), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb990), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc000), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc010), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc080), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc090), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { } /* Terminating entry */ + }; + +MODULE_DEVICE_TABLE(usb, smsusb_id_table); + +static struct usb_driver smsusb_driver = { + .name = "smsusb", + .probe = smsusb_probe, + .disconnect = smsusb_disconnect, + .id_table = smsusb_id_table, + + .suspend = smsusb_suspend, + .resume = smsusb_resume, +}; + +static int __init smsusb_module_init(void) +{ + int rc = usb_register(&smsusb_driver); + if (rc) + sms_err("usb_register failed. Error number %d", rc); + + sms_debug(""); + + return rc; +} + +static void __exit smsusb_module_exit(void) +{ + /* Regular USB Cleanup */ + usb_deregister(&smsusb_driver); + sms_info("end"); +} + +module_init(smsusb_module_init); +module_exit(smsusb_module_exit); + +MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle"); +MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_av.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_av.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_av.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_av.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1626 @@ +/* + * av7110_av.c: audio and video MPEG decoder stuff + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_av.h" +#include "av7110_ipack.h" + +/* MPEG-2 (ISO 13818 / H.222.0) stream types */ +#define PROG_STREAM_MAP 0xBC +#define PRIVATE_STREAM1 0xBD +#define PADDING_STREAM 0xBE +#define PRIVATE_STREAM2 0xBF +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define PTS_DTS_FLAGS 0xC0 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + +static void p_to_t(u8 const *buf, long int length, u16 pid, + u8 *counter, struct dvb_demux_feed *feed); +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len); + + +int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv; + + if (!(dvbdmxfeed->ts_type & TS_PACKET)) + return 0; + if (buf[3] == 0xe0) // video PES do not have a length in TS + buf[4] = buf[5] = 0; + if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) + return dvbdmxfeed->cb.ts(buf, len, NULL, 0, + &dvbdmxfeed->feed.ts, DMX_OK); + else + return dvb_filter_pes2ts(p2t, buf, len, 1); +} + +static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; + + dvbdmxfeed->cb.ts(data, 188, NULL, 0, + &dvbdmxfeed->feed.ts, DMX_OK); + return 0; +} + +int av7110_av_start_record(struct av7110 *av7110, int av, + struct dvb_demux_feed *dvbdmxfeed) +{ + int ret = 0; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed); + + if (av7110->playing || (av7110->rec_mode & av)) + return -EBUSY; + av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + dvbdmx->recording = 1; + av7110->rec_mode |= av; + + switch (av7110->rec_mode) { + case RP_AUDIO: + dvb_filter_pes2ts_init(&av7110->p2t[0], + dvbdmx->pesfilter[0]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[0]); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + break; + + case RP_VIDEO: + dvb_filter_pes2ts_init(&av7110->p2t[1], + dvbdmx->pesfilter[1]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[1]); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + break; + + case RP_AV: + dvb_filter_pes2ts_init(&av7110->p2t[0], + dvbdmx->pesfilter[0]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[0]); + dvb_filter_pes2ts_init(&av7110->p2t[1], + dvbdmx->pesfilter[1]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[1]); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); + break; + } + return ret; +} + +int av7110_av_start_play(struct av7110 *av7110, int av) +{ + int ret = 0; + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->rec_mode) + return -EBUSY; + if (av7110->playing & av) + return -EBUSY; + + av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + + if (av7110->playing == RP_NONE) { + av7110_ipack_reset(&av7110->ipack[0]); + av7110_ipack_reset(&av7110->ipack[1]); + } + + av7110->playing |= av; + switch (av7110->playing) { + case RP_AUDIO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + break; + case RP_VIDEO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + av7110->sinfo = 0; + break; + case RP_AV: + av7110->sinfo = 0; + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); + break; + } + return ret; +} + +int av7110_av_stop(struct av7110 *av7110, int av) +{ + int ret = 0; + dprintk(2, "av7110:%p, \n", av7110); + + if (!(av7110->playing & av) && !(av7110->rec_mode & av)) + return 0; + av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + if (av7110->playing) { + av7110->playing &= ~av; + switch (av7110->playing) { + case RP_AUDIO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + break; + case RP_VIDEO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + break; + case RP_NONE: + ret = av7110_set_vidmode(av7110, av7110->vidmode); + break; + } + } else { + av7110->rec_mode &= ~av; + switch (av7110->rec_mode) { + case RP_AUDIO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + break; + case RP_VIDEO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + break; + case RP_NONE: + break; + } + } + return ret; +} + + +int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen) +{ + int len; + u32 sync; + u16 blen; + + if (!dlen) { + wake_up(&buf->queue); + return -1; + } + while (1) { + len = dvb_ringbuffer_avail(buf); + if (len < 6) { + wake_up(&buf->queue); + return -1; + } + sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24; + sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16; + sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8; + sync |= DVB_RINGBUFFER_PEEK(buf, 3); + + if (((sync &~ 0x0f) == 0x000001e0) || + ((sync &~ 0x1f) == 0x000001c0) || + (sync == 0x000001bd)) + break; + printk("resync\n"); + DVB_RINGBUFFER_SKIP(buf, 1); + } + blen = DVB_RINGBUFFER_PEEK(buf, 4) << 8; + blen |= DVB_RINGBUFFER_PEEK(buf, 5); + blen += 6; + if (len < blen || blen > dlen) { + //printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen); + wake_up(&buf->queue); + return -1; + } + + dvb_ringbuffer_read(buf, dest, (size_t) blen); + + dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n", + (unsigned long) buf->pread, (unsigned long) buf->pwrite); + wake_up(&buf->queue); + return blen; +} + + +int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) +{ + int err, vol, val, balance = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + av7110->mixer.volume_left = volleft; + av7110->mixer.volume_right = volright; + + switch (av7110->adac_type) { + case DVB_ADAC_TI: + volleft = (volleft * 256) / 1036; + volright = (volright * 256) / 1036; + if (volleft > 0x3f) + volleft = 0x3f; + if (volright > 0x3f) + volright = 0x3f; + if ((err = SendDAC(av7110, 3, 0x80 + volleft))) + return err; + return SendDAC(av7110, 4, volright); + + case DVB_ADAC_CRYSTAL: + volleft = 127 - volleft / 2; + volright = 127 - volright / 2; + i2c_writereg(av7110, 0x20, 0x03, volleft); + i2c_writereg(av7110, 0x20, 0x04, volright); + return 0; + + case DVB_ADAC_MSP34x0: + vol = (volleft > volright) ? volleft : volright; + val = (vol * 0x73 / 255) << 8; + if (vol > 0) + balance = ((volright - volleft) * 127) / vol; + msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ + msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ + return 0; + + case DVB_ADAC_MSP34x5: + vol = (volleft > volright) ? volleft : volright; + val = (vol * 0x73 / 255) << 8; + if (vol > 0) + balance = ((volright - volleft) * 127) / vol; + msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ + return 0; + } + + return 0; +} + +int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) +{ + int ret; + dprintk(2, "av7110:%p, \n", av7110); + + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); + + if (!ret && !av7110->playing) { + ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], + av7110->pids[DMX_PES_AUDIO], + av7110->pids[DMX_PES_TELETEXT], + 0, av7110->pids[DMX_PES_PCR]); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + } + return ret; +} + + +static enum av7110_video_mode sw2mode[16] = { + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, +}; + +static int get_video_format(struct av7110 *av7110, u8 *buf, int count) +{ + int i; + int hsize, vsize; + int sw; + u8 *p; + int ret = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->sinfo) + return 0; + for (i = 7; i < count - 10; i++) { + p = buf + i; + if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3) + continue; + p += 4; + hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4); + vsize = ((p[1] &0x0F) << 8) | (p[2]); + sw = (p[3] & 0x0F); + ret = av7110_set_vidmode(av7110, sw2mode[sw]); + if (!ret) { + dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); + av7110->sinfo = 1; + } + break; + } + return ret; +} + + +/**************************************************************************** + * I/O buffer management and control + ****************************************************************************/ + +static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf, + const u8 *buf, unsigned long count) +{ + unsigned long todo = count; + int free; + + while (todo > 0) { + if (dvb_ringbuffer_free(rbuf) < 2048) { + if (wait_event_interruptible(rbuf->queue, + (dvb_ringbuffer_free(rbuf) >= 2048))) + return count - todo; + } + free = dvb_ringbuffer_free(rbuf); + if (free > todo) + free = todo; + dvb_ringbuffer_write(rbuf, buf, free); + todo -= free; + buf += free; + } + + return count - todo; +} + +static void play_video_cb(u8 *buf, int count, void *priv) +{ + struct av7110 *av7110 = (struct av7110 *) priv; + dprintk(2, "av7110:%p, \n", av7110); + + if ((buf[3] & 0xe0) == 0xe0) { + get_video_format(av7110, buf, count); + aux_ring_buffer_write(&av7110->avout, buf, count); + } else + aux_ring_buffer_write(&av7110->aout, buf, count); +} + +static void play_audio_cb(u8 *buf, int count, void *priv) +{ + struct av7110 *av7110 = (struct av7110 *) priv; + dprintk(2, "av7110:%p, \n", av7110); + + aux_ring_buffer_write(&av7110->aout, buf, count); +} + + +#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096) + +static ssize_t ts_play(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + struct dvb_ringbuffer *rb; + u8 *kb; + unsigned long todo = count; + + dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count); + + rb = (type) ? &av7110->avout : &av7110->aout; + kb = av7110->kbuf[type]; + + if (!kb) + return -ENOBUFS; + + if (nonblock && !FREE_COND_TS) + return -EWOULDBLOCK; + + while (todo >= TS_SIZE) { + if (!FREE_COND_TS) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(rb->queue, FREE_COND_TS)) + return count - todo; + } + if (copy_from_user(kb, buf, TS_SIZE)) + return -EFAULT; + write_ts_to_decoder(av7110, type, kb, TS_SIZE); + todo -= TS_SIZE; + buf += TS_SIZE; + } + + return count - todo; +} + + +#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ + dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) + +static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + dprintk(2, "av7110:%p, \n", av7110); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + + if (nonblock && !FREE_COND) + return -EWOULDBLOCK; + + while (todo > 0) { + if (!FREE_COND) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->avout.queue, + FREE_COND)) + return count - todo; + } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + if (copy_from_user(av7110->kbuf[type], buf, n)) + return -EFAULT; + av7110_ipack_instant_repack(av7110->kbuf[type], n, + &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + dprintk(2, "av7110:%p, \n", av7110); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + + if (nonblock && !FREE_COND) + return -EWOULDBLOCK; + + while (todo > 0) { + if (!FREE_COND) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->avout.queue, + FREE_COND)) + return count - todo; + } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + dprintk(2, "av7110:%p, \n", av7110); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) + return -EWOULDBLOCK; + + while (todo > 0) { + if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->aout.queue, + (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024))) + return count-todo; + } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + if (copy_from_user(av7110->kbuf[type], buf, n)) + return -EFAULT; + av7110_ipack_instant_repack(av7110->kbuf[type], n, + &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed) +{ + memset(p->pes, 0, TS_SIZE); + p->counter = 0; + p->pos = 0; + p->frags = 0; + if (feed) + p->feed = feed; +} + +static void clear_p2t(struct av7110_p2t *p) +{ + memset(p->pes, 0, TS_SIZE); +// p->counter = 0; + p->pos = 0; + p->frags = 0; +} + + +static int find_pes_header(u8 const *buf, long int length, int *frags) +{ + int c = 0; + int found = 0; + + *frags = 0; + + while (c < length - 3 && !found) { + if (buf[c] == 0x00 && buf[c + 1] == 0x00 && + buf[c + 2] == 0x01) { + switch ( buf[c + 3] ) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + found = 1; + break; + + default: + c++; + break; + } + } else + c++; + } + if (c == length - 3 && !found) { + if (buf[length - 1] == 0x00) + *frags = 1; + if (buf[length - 2] == 0x00 && + buf[length - 1] == 0x00) + *frags = 2; + if (buf[length - 3] == 0x00 && + buf[length - 2] == 0x00 && + buf[length - 1] == 0x01) + *frags = 3; + return -1; + } + + return c; +} + +void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p) +{ + int c, c2, l, add; + int check, rest; + + c = 0; + c2 = 0; + if (p->frags){ + check = 0; + switch(p->frags) { + case 1: + if (buf[c] == 0x00 && buf[c + 1] == 0x01) { + check = 1; + c += 2; + } + break; + case 2: + if (buf[c] == 0x01) { + check = 1; + c++; + } + break; + case 3: + check = 1; + } + if (check) { + switch (buf[c]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + p->pes[0] = 0x00; + p->pes[1] = 0x00; + p->pes[2] = 0x01; + p->pes[3] = buf[c]; + p->pos = 4; + memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos); + c += (TS_SIZE - 4) - p->pos; + p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed); + clear_p2t(p); + break; + + default: + c = 0; + break; + } + } + p->frags = 0; + } + + if (p->pos) { + c2 = find_pes_header(buf + c, length - c, &p->frags); + if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos) + l = c2+c; + else + l = (TS_SIZE - 4) - p->pos; + memcpy(p->pes + p->pos, buf, l); + c += l; + p->pos += l; + p_to_t(p->pes, p->pos, pid, &p->counter, p->feed); + clear_p2t(p); + } + + add = 0; + while (c < length) { + c2 = find_pes_header(buf + c + add, length - c - add, &p->frags); + if (c2 >= 0) { + c2 += c + add; + if (c2 > c){ + p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed); + c = c2; + clear_p2t(p); + add = 0; + } else + add = 1; + } else { + l = length - c; + rest = l % (TS_SIZE - 4); + l -= rest; + p_to_t(buf + c, l, pid, &p->counter, p->feed); + memcpy(p->pes, buf + c + l, rest); + p->pos = rest; + c = length; + } + } +} + + +static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length) +{ + int i; + int c = 0; + int fill; + u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 }; + + fill = (TS_SIZE - 4) - length; + if (pes_start) + tshead[1] = 0x40; + if (fill) + tshead[3] = 0x30; + tshead[1] |= (u8)((pid & 0x1F00) >> 8); + tshead[2] |= (u8)(pid & 0x00FF); + tshead[3] |= ((*counter)++ & 0x0F); + memcpy(buf, tshead, 4); + c += 4; + + if (fill) { + buf[4] = fill - 1; + c++; + if (fill > 1) { + buf[5] = 0x00; + c++; + } + for (i = 6; i < fill + 4; i++) { + buf[i] = 0xFF; + c++; + } + } + + return c; +} + + +static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, + struct dvb_demux_feed *feed) +{ + int l, pes_start; + u8 obuf[TS_SIZE]; + long c = 0; + + pes_start = 0; + if (length > 3 && + buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) + switch (buf[3]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + pes_start = 1; + break; + + default: + break; + } + + while (c < length) { + memset(obuf, 0, TS_SIZE); + if (length - c >= (TS_SIZE - 4)){ + l = write_ts_header2(pid, counter, pes_start, + obuf, (TS_SIZE - 4)); + memcpy(obuf + l, buf + c, TS_SIZE - l); + c += TS_SIZE - l; + } else { + l = write_ts_header2(pid, counter, pes_start, + obuf, length - c); + memcpy(obuf + l, buf + c, TS_SIZE - l); + c = length; + } + feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, DMX_OK); + pes_start = 0; + } +} + + +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len) +{ + struct ipack *ipack = &av7110->ipack[type]; + + if (buf[1] & TRANS_ERROR) { + av7110_ipack_reset(ipack); + return -1; + } + + if (!(buf[3] & PAYLOAD)) + return -1; + + if (buf[1] & PAY_START) + av7110_ipack_flush(ipack); + + if (buf[3] & ADAPT_FIELD) { + len -= buf[4] + 1; + buf += buf[4] + 1; + if (!len) + return 0; + } + + av7110_ipack_instant_repack(buf + 4, len - 4, ipack); + return 0; +} + + +int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *av7110 = (struct av7110 *) demux->priv; + + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE) + return 0; + + switch (feed->pes_type) { + case 0: + if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) + return -EINVAL; + break; + case 1: + if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) + return -EINVAL; + break; + default: + return -1; + } + + return write_ts_to_decoder(av7110, feed->pes_type, buf, len); +} + + + +/****************************************************************************** + * Video MPEG decoder events + ******************************************************************************/ +void dvb_video_add_event(struct av7110 *av7110, struct video_event *event) +{ + struct dvb_video_events *events = &av7110->video_events; + int wp; + + spin_lock_bh(&events->lock); + + wp = (events->eventw + 1) % MAX_VIDEO_EVENT; + if (wp == events->eventr) { + events->overflow = 1; + events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; + } + + //FIXME: timestamp? + memcpy(&events->events[events->eventw], event, sizeof(struct video_event)); + events->eventw = wp; + + spin_unlock_bh(&events->lock); + + wake_up_interruptible(&events->wait_queue); +} + + +static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags) +{ + struct dvb_video_events *events = &av7110->video_events; + + if (events->overflow) { + events->overflow = 0; + return -EOVERFLOW; + } + if (events->eventw == events->eventr) { + int ret; + + if (flags & O_NONBLOCK) + return -EWOULDBLOCK; + + ret = wait_event_interruptible(events->wait_queue, + events->eventw != events->eventr); + if (ret < 0) + return ret; + } + + spin_lock_bh(&events->lock); + + memcpy(event, &events->events[events->eventr], + sizeof(struct video_event)); + events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; + + spin_unlock_bh(&events->lock); + + return 0; +} + + +/****************************************************************************** + * DVB device file operations + ******************************************************************************/ + +static unsigned int dvb_video_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned int mask = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) + poll_wait(file, &av7110->avout.queue, wait); + + poll_wait(file, &av7110->video_events.wait_queue, wait); + + if (av7110->video_events.eventw != av7110->video_events.eventr) + mask = POLLPRI; + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if (av7110->playing) { + if (FREE_COND) + mask |= (POLLOUT | POLLWRNORM); + } else /* if not playing: may play if asked for */ + mask |= (POLLOUT | POLLWRNORM); + } + + return mask; +} + +static ssize_t dvb_video_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned char c; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + return -EPERM; + + if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) + return -EPERM; + + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); + else + return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); +} + +static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned int mask = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + poll_wait(file, &av7110->aout.queue, wait); + + if (av7110->playing) { + if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) + mask |= (POLLOUT | POLLWRNORM); + } else /* if not playing: may play if asked for */ + mask = (POLLOUT | POLLWRNORM); + + return mask; +} + +static ssize_t dvb_audio_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned char c; + + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) { + printk(KERN_ERR "not audio source memory\n"); + return -EPERM; + } + + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); + else + return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); +} + +static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; + +#define MIN_IFRAME 400000 + +static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock) +{ + unsigned i, n; + int progressive = 0; + int match = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + if (!(av7110->playing & RP_VIDEO)) { + if (av7110_av_start_play(av7110, RP_VIDEO) < 0) + return -EBUSY; + } + + /* search in buf for instances of 00 00 01 b5 1? */ + for (i = 0; i < len; i++) { + unsigned char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (match == 5) { + progressive = c & 0x08; + match = 0; + } + if (c == 0x00) { + match = (match == 1 || match == 2) ? 2 : 1; + continue; + } + switch (match++) { + case 2: if (c == 0x01) + continue; + break; + case 3: if (c == 0xb5) + continue; + break; + case 4: if ((c & 0xf0) == 0x10) + continue; + break; + } + match = 0; + } + + /* setting n always > 1, fixes problems when playing stillframes + consisting of I- and P-Frames */ + n = MIN_IFRAME / len + 1; + + /* FIXME: nonblock? */ + dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1); + + for (i = 0; i < n; i++) + dvb_play(av7110, buf, len, 0, 1); + + av7110_ipack_flush(&av7110->ipack[1]); + + if (progressive) + return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); + else + return 0; +} + + +static int dvb_video_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned long arg = (unsigned long) parg; + int ret = 0; + + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT && + cmd != VIDEO_GET_SIZE ) { + return -EPERM; + } + } + + switch (cmd) { + case VIDEO_STOP: + av7110->videostate.play_state = VIDEO_STOPPED; + if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) + ret = av7110_av_stop(av7110, RP_VIDEO); + else + ret = vidcom(av7110, AV_VIDEO_CMD_STOP, + av7110->videostate.video_blank ? 0 : 1); + if (!ret) + av7110->trickmode = TRICK_NONE; + break; + + case VIDEO_PLAY: + av7110->trickmode = TRICK_NONE; + if (av7110->videostate.play_state == VIDEO_FREEZED) { + av7110->videostate.play_state = VIDEO_PLAYING; + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (ret) + break; + } + if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { + if (av7110->playing == RP_AV) { + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + if (ret) + break; + av7110->playing &= ~RP_VIDEO; + } + ret = av7110_av_start_play(av7110, RP_VIDEO); + } + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (!ret) + av7110->videostate.play_state = VIDEO_PLAYING; + break; + + case VIDEO_FREEZE: + av7110->videostate.play_state = VIDEO_FREEZED; + if (av7110->playing & RP_VIDEO) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); + else + ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); + if (!ret) + av7110->trickmode = TRICK_FREEZE; + break; + + case VIDEO_CONTINUE: + if (av7110->playing & RP_VIDEO) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (!ret) { + av7110->videostate.play_state = VIDEO_PLAYING; + av7110->trickmode = TRICK_NONE; + } + break; + + case VIDEO_SELECT_SOURCE: + av7110->videostate.stream_source = (video_stream_source_t) arg; + break; + + case VIDEO_SET_BLANK: + av7110->videostate.video_blank = (int) arg; + break; + + case VIDEO_GET_STATUS: + memcpy(parg, &av7110->videostate, sizeof(struct video_status)); + break; + + case VIDEO_GET_EVENT: + ret = dvb_video_get_event(av7110, parg, file->f_flags); + break; + + case VIDEO_GET_SIZE: + memcpy(parg, &av7110->video_size, sizeof(video_size_t)); + break; + + case VIDEO_SET_DISPLAY_FORMAT: + { + video_displayformat_t format = (video_displayformat_t) arg; + switch (format) { + case VIDEO_PAN_SCAN: + av7110->display_panscan = VID_PAN_SCAN_PREF; + break; + case VIDEO_LETTER_BOX: + av7110->display_panscan = VID_VC_AND_PS_PREF; + break; + case VIDEO_CENTER_CUT_OUT: + av7110->display_panscan = VID_CENTRE_CUT_PREF; + break; + default: + ret = -EINVAL; + } + if (ret < 0) + break; + av7110->videostate.display_format = format; + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, + 1, av7110->display_panscan); + break; + } + + case VIDEO_SET_FORMAT: + if (arg > 1) { + ret = -EINVAL; + break; + } + av7110->display_ar = arg; + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, + 1, (u16) arg); + break; + + case VIDEO_STILLPICTURE: + { + struct video_still_picture *pic = + (struct video_still_picture *) parg; + av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY; + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + ret = play_iframe(av7110, pic->iFrame, pic->size, + file->f_flags & O_NONBLOCK); + break; + } + + case VIDEO_FAST_FORWARD: + //note: arg is ignored by firmware + if (av7110->playing & RP_VIDEO) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Scan_I, 2, AV_PES, 0); + else + ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg); + if (!ret) { + av7110->trickmode = TRICK_FAST; + av7110->videostate.play_state = VIDEO_PLAYING; + } + break; + + case VIDEO_SLOWMOTION: + if (av7110->playing&RP_VIDEO) { + if (av7110->trickmode != TRICK_SLOW) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + } else { + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + } + if (!ret) { + av7110->trickmode = TRICK_SLOW; + av7110->videostate.play_state = VIDEO_PLAYING; + } + break; + + case VIDEO_GET_CAPABILITIES: + *(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 | + VIDEO_CAP_SYS | VIDEO_CAP_PROG; + break; + + case VIDEO_CLEAR_BUFFER: + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + av7110_ipack_reset(&av7110->ipack[1]); + if (av7110->playing == RP_AV) { + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Play, 2, AV_PES, 0); + if (ret) + break; + if (av7110->trickmode == TRICK_FAST) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Scan_I, 2, AV_PES, 0); + if (av7110->trickmode == TRICK_SLOW) { + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Slow, 2, 0, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + } + if (av7110->trickmode == TRICK_FREEZE) + ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1); + } + break; + + case VIDEO_SET_STREAMTYPE: + break; + + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +static int dvb_audio_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned long arg = (unsigned long) parg; + int ret = 0; + + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); + + if (((file->f_flags & O_ACCMODE) == O_RDONLY) && + (cmd != AUDIO_GET_STATUS)) + return -EPERM; + + switch (cmd) { + case AUDIO_STOP: + if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) + ret = av7110_av_stop(av7110, RP_AUDIO); + else + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_STOPPED; + break; + + case AUDIO_PLAY: + if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) + ret = av7110_av_start_play(av7110, RP_AUDIO); + if (!ret) + ret = audcom(av7110, AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PLAYING; + break; + + case AUDIO_PAUSE: + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PAUSED; + break; + + case AUDIO_CONTINUE: + if (av7110->audiostate.play_state == AUDIO_PAUSED) { + av7110->audiostate.play_state = AUDIO_PLAYING; + ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); + } + break; + + case AUDIO_SELECT_SOURCE: + av7110->audiostate.stream_source = (audio_stream_source_t) arg; + break; + + case AUDIO_SET_MUTE: + { + ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.mute_state = (int) arg; + break; + } + + case AUDIO_SET_AV_SYNC: + av7110->audiostate.AV_sync_state = (int) arg; + ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); + break; + + case AUDIO_SET_BYPASS_MODE: + if (FW_VERSION(av7110->arm_app) < 0x2621) + ret = -EINVAL; + av7110->audiostate.bypass_mode = (int)arg; + break; + + case AUDIO_CHANNEL_SELECT: + av7110->audiostate.channel_select = (audio_channel_select_t) arg; + switch(av7110->audiostate.channel_select) { + case AUDIO_STEREO: + ret = audcom(av7110, AUDIO_CMD_STEREO); + if (!ret) { + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x49); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); + } + break; + case AUDIO_MONO_LEFT: + ret = audcom(av7110, AUDIO_CMD_MONO_L); + if (!ret) { + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x4a); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); + } + break; + case AUDIO_MONO_RIGHT: + ret = audcom(av7110, AUDIO_CMD_MONO_R); + if (!ret) { + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x45); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); + } + break; + default: + ret = -EINVAL; + break; + } + break; + + case AUDIO_GET_STATUS: + memcpy(parg, &av7110->audiostate, sizeof(struct audio_status)); + break; + + case AUDIO_GET_CAPABILITIES: + if (FW_VERSION(av7110->arm_app) < 0x2621) + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + else + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 | + AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + break; + + case AUDIO_CLEAR_BUFFER: + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + av7110_ipack_reset(&av7110->ipack[0]); + if (av7110->playing == RP_AV) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Play, 2, AV_PES, 0); + break; + + case AUDIO_SET_ID: + break; + + case AUDIO_SET_MIXER: + { + struct audio_mixer *amix = (struct audio_mixer *)parg; + ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right); + break; + } + + case AUDIO_SET_STREAMTYPE: + break; + + default: + ret = -ENOIOCTLCMD; + } + + return ret; +} + + +static int dvb_video_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + int err; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((err = dvb_generic_open(inode, file)) < 0) + return err; + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + av7110->video_blank = 1; + av7110->audiostate.AV_sync_state = 1; + av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; + + /* empty event queue */ + av7110->video_events.eventr = av7110->video_events.eventw = 0; + } + + return 0; +} + +static int dvb_video_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + av7110_av_stop(av7110, RP_VIDEO); + } + + return dvb_generic_release(inode, file); +} + +static int dvb_audio_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + int err = dvb_generic_open(inode, file); + + dprintk(2, "av7110:%p, \n", av7110); + + if (err < 0) + return err; + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; + return 0; +} + +static int dvb_audio_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(2, "av7110:%p, \n", av7110); + + av7110_av_stop(av7110, RP_AUDIO); + return dvb_generic_release(inode, file); +} + + + +/****************************************************************************** + * driver registration + ******************************************************************************/ + +static const struct file_operations dvb_video_fops = { + .owner = THIS_MODULE, + .write = dvb_video_write, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_video_open, + .release = dvb_video_release, + .poll = dvb_video_poll, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_video = { + .priv = NULL, + .users = 6, + .readers = 5, /* arbitrary */ + .writers = 1, + .fops = &dvb_video_fops, + .kernel_ioctl = dvb_video_ioctl, +}; + +static const struct file_operations dvb_audio_fops = { + .owner = THIS_MODULE, + .write = dvb_audio_write, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_audio_open, + .release = dvb_audio_release, + .poll = dvb_audio_poll, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_audio = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_audio_fops, + .kernel_ioctl = dvb_audio_ioctl, +}; + + +int av7110_av_register(struct av7110 *av7110) +{ + av7110->audiostate.AV_sync_state = 0; + av7110->audiostate.mute_state = 0; + av7110->audiostate.play_state = AUDIO_STOPPED; + av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; + av7110->audiostate.channel_select = AUDIO_STEREO; + av7110->audiostate.bypass_mode = 0; + + av7110->videostate.video_blank = 0; + av7110->videostate.play_state = VIDEO_STOPPED; + av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; + av7110->videostate.video_format = VIDEO_FORMAT_4_3; + av7110->videostate.display_format = VIDEO_LETTER_BOX; + av7110->display_ar = VIDEO_FORMAT_4_3; + av7110->display_panscan = VID_VC_AND_PS_PREF; + + init_waitqueue_head(&av7110->video_events.wait_queue); + spin_lock_init(&av7110->video_events.lock); + av7110->video_events.eventw = av7110->video_events.eventr = 0; + av7110->video_events.overflow = 0; + memset(&av7110->video_size, 0, sizeof (video_size_t)); + + dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev, + &dvbdev_video, av7110, DVB_DEVICE_VIDEO); + + dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev, + &dvbdev_audio, av7110, DVB_DEVICE_AUDIO); + + return 0; +} + +void av7110_av_unregister(struct av7110 *av7110) +{ + dvb_unregister_device(av7110->audio_dev); + dvb_unregister_device(av7110->video_dev); +} + +int av7110_av_init(struct av7110 *av7110) +{ + void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb }; + int i, ret; + + for (i = 0; i < 2; i++) { + struct ipack *ipack = av7110->ipack + i; + + ret = av7110_ipack_init(ipack, IPACKS, play[i]); + if (ret < 0) { + if (i) + av7110_ipack_free(--ipack); + goto out; + } + ipack->data = av7110; + } + + dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN); + dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN); + + av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN); + av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS; +out: + return ret; +} + +void av7110_av_exit(struct av7110 *av7110) +{ + av7110_ipack_free(&av7110->ipack[0]); + av7110_ipack_free(&av7110->ipack[1]); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_av.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_av.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_av.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_av.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,30 @@ +#ifndef _AV7110_AV_H_ +#define _AV7110_AV_H_ + +struct av7110; + +extern int av7110_set_vidmode(struct av7110 *av7110, + enum av7110_video_mode mode); + +extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); +extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); +extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len); + +extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright); +extern int av7110_av_stop(struct av7110 *av7110, int av); +extern int av7110_av_start_record(struct av7110 *av7110, int av, + struct dvb_demux_feed *dvbdmxfeed); +extern int av7110_av_start_play(struct av7110 *av7110, int av); + +extern void dvb_video_add_event(struct av7110 *av7110, struct video_event *event); + +extern void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed); +extern void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p); + +extern int av7110_av_register(struct av7110 *av7110); +extern void av7110_av_unregister(struct av7110 *av7110); +extern int av7110_av_init(struct av7110 *av7110); +extern void av7110_av_exit(struct av7110 *av7110); + + +#endif /* _AV7110_AV_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2920 @@ +/* + * driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB) + * av7110.c: initialization and demux stuff + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "dvb_frontend.h" + +#include "ttpci-eeprom.h" +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_av.h" +#include "av7110_ca.h" +#include "av7110_ipack.h" + +#include "bsbe1.h" +#include "lnbp21.h" +#include "bsru6.h" + +#define TS_WIDTH 376 +#define TS_HEIGHT 512 +#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT) +#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE) + + +int av7110_debug; + +static int vidmode = CVBS_RGB_OUT; +static int pids_off; +static int adac = DVB_ADAC_TI; +static int hw_sections; +static int rgb_on; +static int volume = 255; +static int budgetpatch; +static int wss_cfg_4_3 = 0x4008; +static int wss_cfg_16_9 = 0x0007; +static int tv_standard; +static int full_ts; + +module_param_named(debug, av7110_debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); +module_param(vidmode, int, 0444); +MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC"); +module_param(pids_off, int, 0444); +MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed"); +module_param(adac, int, 0444); +MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)"); +module_param(hw_sections, int, 0444); +MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware"); +module_param(rgb_on, int, 0444); +MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control" + " signal on SCART pin 16 to switch SCART video mode from CVBS to RGB"); +module_param(volume, int, 0444); +MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); +module_param(budgetpatch, int, 0444); +MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); +module_param(full_ts, int, 0444); +MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable"); +module_param(wss_cfg_4_3, int, 0444); +MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); +module_param(wss_cfg_16_9, int, 0444); +MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data"); +module_param(tv_standard, int, 0444); +MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static void restart_feeds(struct av7110 *av7110); +static int budget_start_feed(struct dvb_demux_feed *feed); +static int budget_stop_feed(struct dvb_demux_feed *feed); + +static int av7110_num; + +#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \ +{\ + if (fe_func != NULL) { \ + av7110_copy = fe_func; \ + fe_func = av7110_func; \ + } \ +} + + +static void init_av7110_av(struct av7110 *av7110) +{ + int ret; + struct saa7146_dev *dev = av7110->dev; + + /* set internal volume control to maximum */ + av7110->adac_type = DVB_ADAC_TI; + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret < 0) + printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret); + + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, + 1, (u16) av7110->display_ar); + if (ret < 0) + printk("dvb-ttpci: unable to set aspect ratio\n"); + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, + 1, av7110->display_panscan); + if (ret < 0) + printk("dvb-ttpci: unable to set pan scan\n"); + + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3); + if (ret < 0) + printk("dvb-ttpci: unable to configure 4:3 wss\n"); + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9); + if (ret < 0) + printk("dvb-ttpci: unable to configure 16:9 wss\n"); + + ret = av7710_set_video_mode(av7110, vidmode); + if (ret < 0) + printk("dvb-ttpci:cannot set video mode:%d\n",ret); + + /* handle different card types */ + /* remaining inits according to card and frontend type */ + av7110->analog_tuner_flags = 0; + av7110->current_input = 0; + if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) + av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on + if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { + printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_CRYSTAL; + i2c_writereg(av7110, 0x20, 0x01, 0xd2); + i2c_writereg(av7110, 0x20, 0x02, 0x49); + i2c_writereg(av7110, 0x20, 0x03, 0x00); + i2c_writereg(av7110, 0x20, 0x04, 0x00); + + /** + * some special handling for the Siemens DVB-C cards... + */ + } else if (0 == av7110_init_analog_module(av7110)) { + /* done. */ + } + else if (dev->pci->subsystem_vendor == 0x110a) { + printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_NONE; + } + else { + av7110->adac_type = adac; + printk("dvb-ttpci: adac type set to %d @ card %d\n", + av7110->adac_type, av7110->dvb_adapter.num); + } + + if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) { + // switch DVB SCART on + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); + if (ret < 0) + printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret); + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); + if (ret < 0) + printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); + if (rgb_on && + ((av7110->dev->pci->subsystem_vendor == 0x110a) || + (av7110->dev->pci->subsystem_vendor == 0x13c2)) && + (av7110->dev->pci->subsystem_device == 0x0000)) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16 + //saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8 + } + } + + if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000e) + av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, SpdifSwitch, 1, 0); // SPDIF on + + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret < 0) + printk("dvb-ttpci:cannot set volume :%d\n",ret); +} + +static void recover_arm(struct av7110 *av7110) +{ + dprintk(4, "%p\n",av7110); + + av7110_bootarm(av7110); + msleep(100); + + init_av7110_av(av7110); + + /* card-specific recovery */ + if (av7110->recover) + av7110->recover(av7110); + + restart_feeds(av7110); + +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_check_ir_config(av7110, true); +#endif +} + +static void av7110_arm_sync(struct av7110 *av7110) +{ + if (av7110->arm_thread) + kthread_stop(av7110->arm_thread); + + av7110->arm_thread = NULL; +} + +static int arm_thread(void *data) +{ + struct av7110 *av7110 = data; + u16 newloops = 0; + int timeout; + + dprintk(4, "%p\n",av7110); + + for (;;) { + timeout = wait_event_interruptible_timeout(av7110->arm_wait, + kthread_should_stop(), 5 * HZ); + + if (-ERESTARTSYS == timeout || kthread_should_stop()) { + /* got signal or told to quit*/ + break; + } + + if (!av7110->arm_ready) + continue; + +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_check_ir_config(av7110, false); +#endif + + if (mutex_lock_interruptible(&av7110->dcomlock)) + break; + newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); + mutex_unlock(&av7110->dcomlock); + + if (newloops == av7110->arm_loops || av7110->arm_errors > 3) { + printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", + av7110->dvb_adapter.num); + + recover_arm(av7110); + + if (mutex_lock_interruptible(&av7110->dcomlock)) + break; + newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1; + mutex_unlock(&av7110->dcomlock); + } + av7110->arm_loops = newloops; + av7110->arm_errors = 0; + } + + return 0; +} + + +/**************************************************************************** + * IRQ handling + ****************************************************************************/ + +static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len, + u8 *buffer2, size_t buffer2_len, + struct dvb_demux_filter *dvbdmxfilter, + enum dmx_success success, + struct av7110 *av7110) +{ + if (!dvbdmxfilter->feed->demux->dmx.frontend) + return 0; + if (dvbdmxfilter->feed->demux->dmx.frontend->source == DMX_MEMORY_FE) + return 0; + + switch (dvbdmxfilter->type) { + case DMX_TYPE_SEC: + if ((((buffer1[1] << 8) | buffer1[2]) & 0xfff) + 3 != buffer1_len) + return 0; + if (dvbdmxfilter->doneq) { + struct dmx_section_filter *filter = &dvbdmxfilter->filter; + int i; + u8 xor, neq = 0; + + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { + xor = filter->filter_value[i] ^ buffer1[i]; + neq |= dvbdmxfilter->maskandnotmode[i] & xor; + } + if (!neq) + return 0; + } + return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len, + buffer2, buffer2_len, + &dvbdmxfilter->filter, + DMX_OK); + case DMX_TYPE_TS: + if (!(dvbdmxfilter->feed->ts_type & TS_PACKET)) + return 0; + if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY) + return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len, + buffer2, buffer2_len, + &dvbdmxfilter->feed->feed.ts, + DMX_OK); + else + av7110_p2t_write(buffer1, buffer1_len, + dvbdmxfilter->feed->pid, + &av7110->p2t_filter[dvbdmxfilter->index]); + default: + return 0; + } +} + + +//#define DEBUG_TIMING +static inline void print_time(char *s) +{ +#ifdef DEBUG_TIMING + struct timeval tv; + do_gettimeofday(&tv); + printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec); +#endif +} + +#define DEBI_READ 0 +#define DEBI_WRITE 1 +static inline void start_debi_dma(struct av7110 *av7110, int dir, + unsigned long addr, unsigned int len) +{ + dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len); + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); + return; + } + + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */ + SAA7146_IER_ENABLE(av7110->dev, MASK_19); + if (len < 5) + len = 5; /* we want a real DEBI DMA */ + if (dir == DEBI_WRITE) + iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3); + else + irdebi(av7110, DEBISWAB, addr, 0, len); +} + +static void debiirq(unsigned long cookie) +{ + struct av7110 *av7110 = (struct av7110 *)cookie; + int type = av7110->debitype; + int handle = (type >> 8) & 0x1f; + unsigned int xfer = 0; + + print_time("debi"); + dprintk(4, "type 0x%04x\n", type); + + if (type == -1) { + printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", + jiffies, saa7146_read(av7110->dev, PSR), + saa7146_read(av7110->dev, SSR)); + goto debi_done; + } + av7110->debitype = -1; + + switch (type & 0xff) { + + case DATA_TS_RECORD: + dvb_dmx_swfilter_packets(&av7110->demux, + (const u8 *) av7110->debi_virt, + av7110->debilen / 188); + xfer = RX_BUFF; + break; + + case DATA_PES_RECORD: + if (av7110->demux.recording) + av7110_record_cb(&av7110->p2t[handle], + (u8 *) av7110->debi_virt, + av7110->debilen); + xfer = RX_BUFF; + break; + + case DATA_IPMPE: + case DATA_FSECTION: + case DATA_PIPING: + if (av7110->handle2filter[handle]) + DvbDmxFilterCallback((u8 *)av7110->debi_virt, + av7110->debilen, NULL, 0, + av7110->handle2filter[handle], + DMX_OK, av7110); + xfer = RX_BUFF; + break; + + case DATA_CI_GET: + { + u8 *data = av7110->debi_virt; + + if ((data[0] < 2) && data[2] == 0xff) { + int flags = 0; + if (data[5] > 0) + flags |= CA_CI_MODULE_PRESENT; + if (data[5] > 5) + flags |= CA_CI_MODULE_READY; + av7110->ci_slot[data[0]].flags = flags; + } else + ci_get_data(&av7110->ci_rbuffer, + av7110->debi_virt, + av7110->debilen); + xfer = RX_BUFF; + break; + } + + case DATA_COMMON_INTERFACE: + CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen); +#if 0 + { + int i; + + printk("av7110%d: ", av7110->num); + printk("%02x ", *(u8 *)av7110->debi_virt); + printk("%02x ", *(1+(u8 *)av7110->debi_virt)); + for (i = 2; i < av7110->debilen; i++) + printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt))); + for (i = 2; i < av7110->debilen; i++) + printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt))); + + printk("\n"); + } +#endif + xfer = RX_BUFF; + break; + + case DATA_DEBUG_MESSAGE: + ((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0; + printk("%s\n", (s8 *) av7110->debi_virt); + xfer = RX_BUFF; + break; + + case DATA_CI_PUT: + dprintk(4, "debi DATA_CI_PUT\n"); + case DATA_MPEG_PLAY: + dprintk(4, "debi DATA_MPEG_PLAY\n"); + case DATA_BMP_LOAD: + dprintk(4, "debi DATA_BMP_LOAD\n"); + xfer = TX_BUFF; + break; + default: + break; + } +debi_done: + spin_lock(&av7110->debilock); + if (xfer) + iwdebi(av7110, DEBINOSWAP, xfer, 0, 2); + ARM_ClearMailBox(av7110); + spin_unlock(&av7110->debilock); +} + +/* irq from av7110 firmware writing the mailbox register in the DPRAM */ +static void gpioirq(unsigned long cookie) +{ + struct av7110 *av7110 = (struct av7110 *)cookie; + u32 rxbuf, txbuf; + int len; + + if (av7110->debitype != -1) + /* we shouldn't get any irq while a debi xfer is running */ + printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", + jiffies, saa7146_read(av7110->dev, PSR), + saa7146_read(av7110->dev, SSR)); + + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); + BUG(); /* maybe we should try resetting the debi? */ + } + + spin_lock(&av7110->debilock); + ARM_ClearIrq(av7110); + + /* see what the av7110 wants */ + av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2); + av7110->debilen = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + len = (av7110->debilen + 3) & ~3; + + print_time("gpio"); + dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen); + + switch (av7110->debitype & 0xff) { + + case DATA_TS_PLAY: + case DATA_PES_PLAY: + break; + + case DATA_MPEG_VIDEO_EVENT: + { + u32 h_ar; + struct video_event event; + + av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2); + h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2); + + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + + av7110->video_size.h = h_ar & 0xfff; + + event.type = VIDEO_EVENT_SIZE_CHANGED; + event.u.size.w = av7110->video_size.w; + event.u.size.h = av7110->video_size.h; + switch ((h_ar >> 12) & 0xf) + { + case 3: + av7110->video_size.aspect_ratio = VIDEO_FORMAT_16_9; + event.u.size.aspect_ratio = VIDEO_FORMAT_16_9; + av7110->videostate.video_format = VIDEO_FORMAT_16_9; + break; + case 4: + av7110->video_size.aspect_ratio = VIDEO_FORMAT_221_1; + event.u.size.aspect_ratio = VIDEO_FORMAT_221_1; + av7110->videostate.video_format = VIDEO_FORMAT_221_1; + break; + default: + av7110->video_size.aspect_ratio = VIDEO_FORMAT_4_3; + event.u.size.aspect_ratio = VIDEO_FORMAT_4_3; + av7110->videostate.video_format = VIDEO_FORMAT_4_3; + } + + dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n", + av7110->video_size.w, av7110->video_size.h, + av7110->video_size.aspect_ratio); + + dvb_video_add_event(av7110, &event); + break; + } + + case DATA_CI_PUT: + { + int avail; + struct dvb_ringbuffer *cibuf = &av7110->ci_wbuffer; + + avail = dvb_ringbuffer_avail(cibuf); + if (avail <= 2) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; + len |= DVB_RINGBUFFER_PEEK(cibuf, 1); + if (avail < len + 2) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + DVB_RINGBUFFER_SKIP(cibuf, 2); + + dvb_ringbuffer_read(cibuf, av7110->debi_virt, len); + + iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); + dprintk(8, "DMA: CI\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); + spin_unlock(&av7110->debilock); + wake_up(&cibuf->queue); + return; + } + + case DATA_MPEG_PLAY: + if (!av7110->playing) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + len = 0; + if (av7110->debitype & 0x100) { + spin_lock(&av7110->aout.lock); + len = av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048); + spin_unlock(&av7110->aout.lock); + } + if (len <= 0 && (av7110->debitype & 0x200) + &&av7110->videostate.play_state != VIDEO_FREEZED) { + spin_lock(&av7110->avout.lock); + len = av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048); + spin_unlock(&av7110->avout.lock); + } + if (len <= 0) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len); + iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); + dprintk(8, "DMA: MPEG_PLAY\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_BMP_LOAD: + len = av7110->debilen; + dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len); + if (!len) { + av7110->bmp_state = BMP_LOADED; + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + wake_up(&av7110->bmpq); + dprintk(8, "gpio DATA_BMP_LOAD done\n"); + break; + } + if (len > av7110->bmplen) + len = av7110->bmplen; + if (len > 2 * 1024) + len = 2 * 1024; + iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); + memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len); + av7110->bmpp += len; + av7110->bmplen -= len; + dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_CI_GET: + case DATA_COMMON_INTERFACE: + case DATA_FSECTION: + case DATA_IPMPE: + case DATA_PIPING: + if (!len || len > 4 * 1024) { + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + break; + } + /* fall through */ + + case DATA_TS_RECORD: + case DATA_PES_RECORD: + dprintk(8, "DMA: TS_REC etc.\n"); + start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_DEBUG_MESSAGE: + if (!len || len > 0xff) { + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + break; + } + start_debi_dma(av7110, DEBI_READ, Reserved, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_IRCOMMAND: + if (av7110->ir.ir_handler) + av7110->ir.ir_handler(av7110, + swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + break; + + default: + printk("dvb-ttpci: gpioirq unknown type=%d len=%d\n", + av7110->debitype, av7110->debilen); + break; + } + av7110->debitype = -1; + ARM_ClearMailBox(av7110); + spin_unlock(&av7110->debilock); +} + + +#ifdef CONFIG_DVB_AV7110_OSD +static int dvb_osd_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(4, "%p\n", av7110); + + if (cmd == OSD_SEND_CMD) + return av7110_osd_cmd(av7110, (osd_cmd_t *) parg); + if (cmd == OSD_GET_CAPABILITY) + return av7110_osd_capability(av7110, (osd_cap_t *) parg); + + return -EINVAL; +} + + +static const struct file_operations dvb_osd_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_generic_open, + .release = dvb_generic_release, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_osd = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_osd_fops, + .kernel_ioctl = dvb_osd_ioctl, +}; +#endif /* CONFIG_DVB_AV7110_OSD */ + + +static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, + u16 subpid, u16 pcrpid) +{ + u16 aflags = 0; + + dprintk(4, "%p\n", av7110); + + if (vpid == 0x1fff || apid == 0x1fff || + ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) { + vpid = apid = ttpid = subpid = pcrpid = 0; + av7110->pids[DMX_PES_VIDEO] = 0; + av7110->pids[DMX_PES_AUDIO] = 0; + av7110->pids[DMX_PES_TELETEXT] = 0; + av7110->pids[DMX_PES_PCR] = 0; + } + + if (av7110->audiostate.bypass_mode) + aflags |= 0x8000; + + return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6, + pcrpid, vpid, apid, ttpid, subpid, aflags); +} + +int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, + u16 subpid, u16 pcrpid) +{ + int ret = 0; + dprintk(4, "%p\n", av7110); + + if (mutex_lock_interruptible(&av7110->pid_mutex)) + return -ERESTARTSYS; + + if (!(vpid & 0x8000)) + av7110->pids[DMX_PES_VIDEO] = vpid; + if (!(apid & 0x8000)) + av7110->pids[DMX_PES_AUDIO] = apid; + if (!(ttpid & 0x8000)) + av7110->pids[DMX_PES_TELETEXT] = ttpid; + if (!(pcrpid & 0x8000)) + av7110->pids[DMX_PES_PCR] = pcrpid; + + av7110->pids[DMX_PES_SUBTITLE] = 0; + + if (av7110->fe_synced) { + pcrpid = av7110->pids[DMX_PES_PCR]; + ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); + } + + mutex_unlock(&av7110->pid_mutex); + return ret; +} + + +/****************************************************************************** + * hardware filter functions + ******************************************************************************/ + +static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) +{ + struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed; + struct av7110 *av7110 = dvbdmxfeed->demux->priv; + u16 buf[20]; + int ret, i; + u16 handle; +// u16 mode = 0x0320; + u16 mode = 0xb96a; + + dprintk(4, "%p\n", av7110); + + if (av7110->full_ts) + return 0; + + if (dvbdmxfilter->type == DMX_TYPE_SEC) { + if (hw_sections) { + buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | + dvbdmxfilter->maskandmode[0]; + for (i = 3; i < 18; i++) + buf[i + 4 - 2] = + (dvbdmxfilter->filter.filter_value[i] << 8) | + dvbdmxfilter->maskandmode[i]; + mode = 4; + } + } else if ((dvbdmxfeed->ts_type & TS_PACKET) && + !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) { + av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed); + } + + buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter; + buf[1] = 16; + buf[2] = dvbdmxfeed->pid; + buf[3] = mode; + + ret = av7110_fw_request(av7110, buf, 20, &handle, 1); + if (ret != 0 || handle >= 32) { + printk("dvb-ttpci: %s error buf %04x %04x %04x %04x " + "ret %d handle %04x\n", + __func__, buf[0], buf[1], buf[2], buf[3], + ret, handle); + dvbdmxfilter->hw_handle = 0xffff; + if (!ret) + ret = -1; + return ret; + } + + av7110->handle2filter[handle] = dvbdmxfilter; + dvbdmxfilter->hw_handle = handle; + + return ret; +} + +static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) +{ + struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv; + u16 buf[3]; + u16 answ[2]; + int ret; + u16 handle; + + dprintk(4, "%p\n", av7110); + + if (av7110->full_ts) + return 0; + + handle = dvbdmxfilter->hw_handle; + if (handle >= 32) { + printk("%s tried to stop invalid filter %04x, filter type = %x\n", + __func__, handle, dvbdmxfilter->type); + return -EINVAL; + } + + av7110->handle2filter[handle] = NULL; + + buf[0] = (COMTYPE_PID_FILTER << 8) + DelPIDFilter; + buf[1] = 1; + buf[2] = handle; + ret = av7110_fw_request(av7110, buf, 3, answ, 2); + if (ret != 0 || answ[1] != handle) { + printk("dvb-ttpci: %s error cmd %04x %04x %04x ret %x " + "resp %04x %04x pid %d\n", + __func__, buf[0], buf[1], buf[2], ret, + answ[0], answ[1], dvbdmxfilter->feed->pid); + if (!ret) + ret = -1; + } + return ret; +} + + +static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct av7110 *av7110 = dvbdmx->priv; + u16 *pid = dvbdmx->pids, npids[5]; + int i; + int ret = 0; + + dprintk(4, "%p\n", av7110); + + npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; + i = dvbdmxfeed->pes_type; + npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; + if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) { + npids[i] = 0; + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (!ret) + ret = StartHWFilter(dvbdmxfeed->filter); + return ret; + } + if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) { + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (ret) + return ret; + } + + if (dvbdmxfeed->pes_type < 2 && npids[0]) + if (av7110->fe_synced) + { + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + if (ret) + return ret; + } + + if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) { + if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) + ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); + if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) + ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); + } + return ret; +} + +static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct av7110 *av7110 = dvbdmx->priv; + u16 *pid = dvbdmx->pids, npids[5]; + int i; + + int ret = 0; + + dprintk(4, "%p\n", av7110); + + if (dvbdmxfeed->pes_type <= 1) { + ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); + if (ret) + return ret; + if (!av7110->rec_mode) + dvbdmx->recording = 0; + if (!av7110->playing) + dvbdmx->playing = 0; + } + npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; + i = dvbdmxfeed->pes_type; + switch (i) { + case 2: //teletext + if (dvbdmxfeed->ts_type & TS_PACKET) + ret = StopHWFilter(dvbdmxfeed->filter); + npids[2] = 0; + break; + case 0: + case 1: + case 4: + if (!pids_off) + return 0; + npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; + break; + } + if (!ret) + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + return ret; +} + +static int av7110_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *av7110 = demux->priv; + int ret = 0; + + dprintk(4, "%p\n", av7110); + + if (!demux->dmx.frontend) + return -EINVAL; + + if (!av7110->full_ts && feed->pid > 0x1fff) + return -EINVAL; + + if (feed->type == DMX_TYPE_TS) { + if ((feed->ts_type & TS_DECODER) && + (feed->pes_type < DMX_TS_PES_OTHER)) { + switch (demux->dmx.frontend->source) { + case DMX_MEMORY_FE: + if (feed->ts_type & TS_DECODER) + if (feed->pes_type < 2 && + !(demux->pids[0] & 0x8000) && + !(demux->pids[1] & 0x8000)) { + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + ret = av7110_av_start_play(av7110,RP_AV); + if (!ret) + demux->playing = 1; + } + break; + default: + ret = dvb_feed_start_pid(feed); + break; + } + } else if ((feed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE)) { + ret = StartHWFilter(feed->filter); + } + } + + if (av7110->full_ts) { + budget_start_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { + int i; + + for (i = 0; i < demux->filternum; i++) { + if (demux->filter[i].state != DMX_STATE_READY) + continue; + if (demux->filter[i].type != DMX_TYPE_SEC) + continue; + if (demux->filter[i].filter.parent != &feed->feed.sec) + continue; + demux->filter[i].state = DMX_STATE_GO; + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + ret = StartHWFilter(&demux->filter[i]); + if (ret) + break; + } + } + } + + return ret; +} + + +static int av7110_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *av7110 = demux->priv; + int i, rc, ret = 0; + dprintk(4, "%p\n", av7110); + + if (feed->type == DMX_TYPE_TS) { + if (feed->ts_type & TS_DECODER) { + if (feed->pes_type >= DMX_TS_PES_OTHER || + !demux->pesfilter[feed->pes_type]) + return -EINVAL; + demux->pids[feed->pes_type] |= 0x8000; + demux->pesfilter[feed->pes_type] = NULL; + } + if (feed->ts_type & TS_DECODER && + feed->pes_type < DMX_TS_PES_OTHER) { + ret = dvb_feed_stop_pid(feed); + } else + if ((feed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE)) + ret = StopHWFilter(feed->filter); + } + + if (av7110->full_ts) { + budget_stop_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { + for (i = 0; ifilternum; i++) { + if (demux->filter[i].state == DMX_STATE_GO && + demux->filter[i].filter.parent == &feed->feed.sec) { + demux->filter[i].state = DMX_STATE_READY; + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + rc = StopHWFilter(&demux->filter[i]); + if (!ret) + ret = rc; + /* keep going, stop as many filters as possible */ + } + } + } + } + + return ret; +} + + +static void restart_feeds(struct av7110 *av7110) +{ + struct dvb_demux *dvbdmx = &av7110->demux; + struct dvb_demux_feed *feed; + int mode; + int feeding; + int i, j; + + dprintk(4, "%p\n", av7110); + + mode = av7110->playing; + av7110->playing = 0; + av7110->rec_mode = 0; + + feeding = av7110->feeding1; /* full_ts mod */ + + for (i = 0; i < dvbdmx->feednum; i++) { + feed = &dvbdmx->feed[i]; + if (feed->state == DMX_STATE_GO) { + if (feed->type == DMX_TYPE_SEC) { + for (j = 0; j < dvbdmx->filternum; j++) { + if (dvbdmx->filter[j].type != DMX_TYPE_SEC) + continue; + if (dvbdmx->filter[j].filter.parent != &feed->feed.sec) + continue; + if (dvbdmx->filter[j].state == DMX_STATE_GO) + dvbdmx->filter[j].state = DMX_STATE_READY; + } + } + av7110_start_feed(feed); + } + } + + av7110->feeding1 = feeding; /* full_ts mod */ + + if (mode) + av7110_av_start_play(av7110, mode); +} + +static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, + uint64_t *stc, unsigned int *base) +{ + int ret; + u16 fwstc[4]; + u16 tag = ((COMTYPE_REQUEST << 8) + ReqSTC); + struct dvb_demux *dvbdemux; + struct av7110 *av7110; + + /* pointer casting paranoia... */ + BUG_ON(!demux); + dvbdemux = demux->priv; + BUG_ON(!dvbdemux); + av7110 = dvbdemux->priv; + + dprintk(4, "%p\n", av7110); + + if (num != 0) + return -EINVAL; + + ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4); + if (ret) { + printk(KERN_ERR "%s: av7110_fw_request error\n", __func__); + return ret; + } + dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n", + fwstc[0], fwstc[1], fwstc[2], fwstc[3]); + + *stc = (((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) | + (((uint64_t) fwstc[1]) << 16) | ((uint64_t) fwstc[0]); + *base = 1; + + dprintk(4, "stc = %lu\n", (unsigned long)*stc); + + return 0; +} + + +/****************************************************************************** + * SEC device file operations + ******************************************************************************/ + + +static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct av7110* av7110 = fe->dvb->priv; + + switch (tone) { + case SEC_TONE_ON: + return Set22K(av7110, 1); + + case SEC_TONE_OFF: + return Set22K(av7110, 0); + + default: + return -EINVAL; + } +} + +static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); +} + +static int av7110_diseqc_send_burst(struct dvb_frontend* fe, + fe_sec_mini_cmd_t minicmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + return av7110_diseqc_send(av7110, 0, NULL, minicmd); +} + +/* simplified code from budget-core.c */ +static int stop_ts_capture(struct av7110 *budget) +{ + dprintk(2, "budget: %p\n", budget); + + if (--budget->feeding1) + return budget->feeding1; + saa7146_write(budget->dev, MC1, MASK_20); /* DMA3 off */ + SAA7146_IER_DISABLE(budget->dev, MASK_10); + SAA7146_ISR_CLEAR(budget->dev, MASK_10); + return 0; +} + +static int start_ts_capture(struct av7110 *budget) +{ + dprintk(2, "budget: %p\n", budget); + + if (budget->feeding1) + return ++budget->feeding1; + memset(budget->grabbing, 0x00, TS_BUFLEN); + budget->ttbp = 0; + SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ + SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ + saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ + return ++budget->feeding1; +} + +static int budget_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *budget = demux->priv; + int status; + + dprintk(2, "av7110: %p\n", budget); + + spin_lock(&budget->feedlock1); + feed->pusi_seen = 0; /* have a clean section start */ + status = start_ts_capture(budget); + spin_unlock(&budget->feedlock1); + return status; +} + +static int budget_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *budget = demux->priv; + int status; + + dprintk(2, "budget: %p\n", budget); + + spin_lock(&budget->feedlock1); + status = stop_ts_capture(budget); + spin_unlock(&budget->feedlock1); + return status; +} + +static void vpeirq(unsigned long cookie) +{ + struct av7110 *budget = (struct av7110 *)cookie; + u8 *mem = (u8 *) (budget->grabbing); + u32 olddma = budget->ttbp; + u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1; + + /* nearest lower position divisible by 188 */ + newdma -= newdma % 188; + + if (newdma >= TS_BUFLEN) + return; + + budget->ttbp = newdma; + + if (!budget->feeding1 || (newdma == olddma)) + return; + + /* Ensure streamed PCI data is synced to CPU */ + pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); + +#if 0 + /* track rps1 activity */ + printk("vpeirq: %02x Event Counter 1 0x%04x\n", + mem[olddma], + saa7146_read(budget->dev, EC1R) & 0x3fff); +#endif + + if (newdma > olddma) + /* no wraparound, dump olddma..newdma */ + dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188); + else { + /* wraparound, dump olddma..buflen and 0..newdma */ + dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188); + dvb_dmx_swfilter_packets(demux, mem, newdma / 188); + } +} + +static int av7110_register(struct av7110 *av7110) +{ + int ret, i; + struct dvb_demux *dvbdemux = &av7110->demux; + struct dvb_demux *dvbdemux1 = &av7110->demux1; + + dprintk(4, "%p\n", av7110); + + if (av7110->registered) + return -1; + + av7110->registered = 1; + + dvbdemux->priv = (void *) av7110; + + for (i = 0; i < 32; i++) + av7110->handle2filter[i] = NULL; + + dvbdemux->filternum = (av7110->full_ts) ? 256 : 32; + dvbdemux->feednum = (av7110->full_ts) ? 256 : 32; + dvbdemux->start_feed = av7110_start_feed; + dvbdemux->stop_feed = av7110_stop_feed; + dvbdemux->write_to_decoder = av7110_write_to_decoder; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&av7110->demux); + av7110->demux.dmx.get_stc = dvb_get_stc; + + av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32; + av7110->dmxdev.demux = &dvbdemux->dmx; + av7110->dmxdev.capabilities = 0; + + dvb_dmxdev_init(&av7110->dmxdev, &av7110->dvb_adapter); + + av7110->hw_frontend.source = DMX_FRONTEND_0; + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->hw_frontend); + + if (ret < 0) + return ret; + + av7110->mem_frontend.source = DMX_MEMORY_FE; + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->mem_frontend); + + if (ret < 0) + return ret; + + ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, + &av7110->hw_frontend); + if (ret < 0) + return ret; + + av7110_av_register(av7110); + av7110_ca_register(av7110); + +#ifdef CONFIG_DVB_AV7110_OSD + dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev, + &dvbdev_osd, av7110, DVB_DEVICE_OSD); +#endif + + dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); + + if (budgetpatch) { + /* initialize software demux1 without its own frontend + * demux1 hardware is connected to frontend0 of demux0 + */ + dvbdemux1->priv = (void *) av7110; + + dvbdemux1->filternum = 256; + dvbdemux1->feednum = 256; + dvbdemux1->start_feed = budget_start_feed; + dvbdemux1->stop_feed = budget_stop_feed; + dvbdemux1->write_to_decoder = NULL; + + dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&av7110->demux1); + + av7110->dmxdev1.filternum = 256; + av7110->dmxdev1.demux = &dvbdemux1->dmx; + av7110->dmxdev1.capabilities = 0; + + dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter); + + dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx); + printk("dvb-ttpci: additional demux1 for budget-patch registered\n"); + } + return 0; +} + + +static void dvb_unregister(struct av7110 *av7110) +{ + struct dvb_demux *dvbdemux = &av7110->demux; + struct dvb_demux *dvbdemux1 = &av7110->demux1; + + dprintk(4, "%p\n", av7110); + + if (!av7110->registered) + return; + + if (budgetpatch) { + dvb_net_release(&av7110->dvb_net1); + dvbdemux->dmx.close(&dvbdemux1->dmx); + dvb_dmxdev_release(&av7110->dmxdev1); + dvb_dmx_release(&av7110->demux1); + } + + dvb_net_release(&av7110->dvb_net); + + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend); + + dvb_dmxdev_release(&av7110->dmxdev); + dvb_dmx_release(&av7110->demux); + + if (av7110->fe != NULL) { + dvb_unregister_frontend(av7110->fe); + dvb_frontend_detach(av7110->fe); + } + dvb_unregister_device(av7110->osd_dev); + av7110_av_unregister(av7110); + av7110_ca_unregister(av7110); +} + + +/**************************************************************************** + * I2C client commands + ****************************************************************************/ + +int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val) +{ + u8 msg[2] = { reg, val }; + struct i2c_msg msgs; + + msgs.flags = 0; + msgs.addr = id / 2; + msgs.len = 2; + msgs.buf = msg; + return i2c_transfer(&av7110->i2c_adap, &msgs, 1); +} + +u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) +{ + u8 mm1[] = {0x00}; + u8 mm2[] = {0x00}; + struct i2c_msg msgs[2]; + + msgs[0].flags = 0; + msgs[1].flags = I2C_M_RD; + msgs[0].addr = msgs[1].addr = id / 2; + mm1[0] = reg; + msgs[0].len = 1; msgs[1].len = 1; + msgs[0].buf = mm1; msgs[1].buf = mm2; + i2c_transfer(&av7110->i2c_adap, msgs, 2); + + return mm2[0]; +} + +/**************************************************************************** + * INITIALIZATION + ****************************************************************************/ + + +static int check_firmware(struct av7110* av7110) +{ + u32 crc = 0, len = 0; + unsigned char *ptr; + + /* check for firmware magic */ + ptr = av7110->bin_fw; + if (ptr[0] != 'A' || ptr[1] != 'V' || + ptr[2] != 'F' || ptr[3] != 'W') { + printk("dvb-ttpci: this is not an av7110 firmware\n"); + return -EINVAL; + } + ptr += 4; + + /* check dpram file */ + crc = get_unaligned_be32(ptr); + ptr += 4; + len = get_unaligned_be32(ptr); + ptr += 4; + if (len >= 512) { + printk("dvb-ttpci: dpram file is way too big.\n"); + return -EINVAL; + } + if (crc != crc32_le(0, ptr, len)) { + printk("dvb-ttpci: crc32 of dpram file does not match.\n"); + return -EINVAL; + } + av7110->bin_dpram = ptr; + av7110->size_dpram = len; + ptr += len; + + /* check root file */ + crc = get_unaligned_be32(ptr); + ptr += 4; + len = get_unaligned_be32(ptr); + ptr += 4; + + if (len <= 200000 || len >= 300000 || + len > ((av7110->bin_fw + av7110->size_fw) - ptr)) { + printk("dvb-ttpci: root file has strange size (%d). aborting.\n", len); + return -EINVAL; + } + if( crc != crc32_le(0, ptr, len)) { + printk("dvb-ttpci: crc32 of root file does not match.\n"); + return -EINVAL; + } + av7110->bin_root = ptr; + av7110->size_root = len; + return 0; +} + +static void put_firmware(struct av7110* av7110) +{ + vfree(av7110->bin_fw); +} + +static int get_firmware(struct av7110* av7110) +{ + int ret; + const struct firmware *fw; + + /* request the av7110 firmware, this will block until someone uploads it */ + ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev); + if (ret) { + if (ret == -ENOENT) { + printk(KERN_ERR "dvb-ttpci: could not load firmware," + " file not found: dvb-ttpci-01.fw\n"); + printk(KERN_ERR "dvb-ttpci: usually this should be in " + "/usr/lib/hotplug/firmware or /lib/firmware\n"); + printk(KERN_ERR "dvb-ttpci: and can be downloaded from" + " http://www.linuxtv.org/download/dvb/firmware/\n"); + } else + printk(KERN_ERR "dvb-ttpci: cannot request firmware" + " (error %i)\n", ret); + return -EINVAL; + } + + if (fw->size <= 200000) { + printk("dvb-ttpci: this firmware is way too small.\n"); + release_firmware(fw); + return -EINVAL; + } + + /* check if the firmware is available */ + av7110->bin_fw = vmalloc(fw->size); + if (NULL == av7110->bin_fw) { + dprintk(1, "out of memory\n"); + release_firmware(fw); + return -ENOMEM; + } + + memcpy(av7110->bin_fw, fw->data, fw->size); + av7110->size_fw = fw->size; + if ((ret = check_firmware(av7110))) + vfree(av7110->bin_fw); + + release_firmware(fw); + return ret; +} + +static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +{ + struct av7110* av7110 = fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (params->frequency + 479500) / 125; + + if (params->frequency > 2000000) pwr = 3; + else if (params->frequency > 1800000) pwr = 2; + else if (params->frequency > 1600000) pwr = 1; + else if (params->frequency > 1200000) pwr = 0; + else if (params->frequency >= 1100000) pwr = 1; + else pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; + + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = { + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, +}; + +static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +{ + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (params->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + + + + +static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +{ + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = params->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, +}; + + + +static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +{ + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u32 f = params->frequency; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (f + 36125000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1820_config philips_cd1516_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + + + +static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +{ + struct av7110* av7110 = fe->dvb->priv; + u32 div, pwr; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (params->frequency + 36200000) / 166666; + + if (params->frequency <= 782000000) + pwr = 1; + else + pwr = 2; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85; + data[3] = pwr << 6; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ +#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE) + struct av7110* av7110 = fe->dvb->priv; + + return request_firmware(fw, name, &av7110->dev->pci->dev); +#else + return -EINVAL; +#endif +} + +static struct sp8870_config alps_tdlb7_config = { + + .demod_address = 0x71, + .request_firmware = alps_tdlb7_request_firmware, +}; + + +static u8 nexusca_stv0297_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0x7b, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x49, + 0x62, 0x0b, + 0x53, 0x08, + 0x59, 0x08, + 0xff, 0xff, +}; + +static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +{ + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) }; + struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 }; + int i; + + div = (params->frequency + 36150000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xce; + + if (params->frequency < 45000000) + return -EINVAL; + else if (params->frequency < 137000000) + data[3] = 0x01; + else if (params->frequency < 403000000) + data[3] = 0x02; + else if (params->frequency < 860000000) + data[3] = 0x04; + else + return -EINVAL; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) { + printk("nexusca: pll transfer failed!\n"); + return -EIO; + } + + // wait for PLL lock + for(i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1) + if (data[0] & 0x40) break; + msleep(10); + } + + return 0; +} + +static struct stv0297_config nexusca_stv0297_config = { + + .demod_address = 0x1C, + .inittab = nexusca_stv0297_inittab, + .invert = 1, + .stop_during_read = 1, +}; + + + +static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +{ + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 cfg, cpump, band_select; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (36125000 + params->frequency) / 166666; + + cfg = 0x88; + + if (params->frequency < 175000000) cpump = 2; + else if (params->frequency < 390000000) cpump = 1; + else if (params->frequency < 470000000) cpump = 2; + else if (params->frequency < 750000000) cpump = 1; + else cpump = 3; + + if (params->frequency < 175000000) band_select = 0x0e; + else if (params->frequency < 470000000) band_select = 0x05; + else band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = (cpump << 6) | band_select; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct l64781_config grundig_29504_401_config = { + .demod_address = 0x55, +}; + + + +static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) +{ + int ret = 0; + int synced = (status & FE_HAS_LOCK) ? 1 : 0; + + av7110->fe_status = status; + + if (av7110->fe_synced == synced) + return 0; + + if (av7110->playing) { + av7110->fe_synced = synced; + return 0; + } + + if (mutex_lock_interruptible(&av7110->pid_mutex)) + return -ERESTARTSYS; + + if (synced) { + ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], + av7110->pids[DMX_PES_AUDIO], + av7110->pids[DMX_PES_TELETEXT], 0, + av7110->pids[DMX_PES_PCR]); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + } else { + ret = SetPIDs(av7110, 0, 0, 0, 0, 0); + if (!ret) { + ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); + if (!ret) + ret = av7110_wait_msgstate(av7110, GPMQBusy); + } + } + + if (!ret) + av7110->fe_synced = synced; + + mutex_unlock(&av7110->pid_mutex); + return ret; +} + +static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_fe_params = *params; + ret = av7110->fe_set_frontend(fe, params); + } + return ret; +} + +static int av7110_fe_init(struct dvb_frontend* fe) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_init(fe); + return ret; +} + +static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct av7110* av7110 = fe->dvb->priv; + + /* call the real implementation */ + int ret = av7110->fe_read_status(fe, status); + if (!ret) + if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) + ret = av7110_fe_lock_fix(av7110, *status); + return ret; +} + +static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_diseqc_reset_overload(fe); + return ret; +} + +static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_master_cmd = *cmd; + ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); + } + return ret; +} + +static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_minicmd = minicmd; + ret = av7110->fe_diseqc_send_burst(fe, minicmd); + } + return ret; +} + +static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_tone = tone; + ret = av7110->fe_set_tone(fe, tone); + } + return ret; +} + +static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_voltage = voltage; + ret = av7110->fe_set_voltage(fe, voltage); + } + return ret; +} + +static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd); + return ret; +} + +static void dvb_s_recover(struct av7110* av7110) +{ + av7110_fe_init(av7110->fe); + + av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage); + if (av7110->saved_master_cmd.msg_len) { + msleep(20); + av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd); + } + msleep(20); + av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd); + msleep(20); + av7110_fe_set_tone(av7110->fe, av7110->saved_tone); + + av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params); +} + +static u8 read_pwm(struct av7110* av7110) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static int frontend_init(struct av7110 *av7110) +{ + int ret; + + if (av7110->dev->pci->subsystem_vendor == 0x110a) { + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??)) + av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, + &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; + } + break; + } + + } else if (av7110->dev->pci->subsystem_vendor == 0x13c2) { + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X + case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X + case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE + + // try the ALPS BSRV2 first of all + av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + break; + } + + // try the ALPS BSRU6 now + av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + av7110->fe->tuner_priv = &av7110->i2c_adap; + + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + break; + } + + // Try the grundig 29504-451 + av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + break; + } + + /* Try DVB-C cards */ + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: + /* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */ + av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap, + read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; + } + break; + case 0x0003: + /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */ + av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, + read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + } + break; + } + break; + + case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X + // try ALPS TDLB7 first, then Grundig 29504-401 + av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params; + break; + } + /* fall-thru */ + + case 0x0008: // Hauppauge/TT DVB-T + // Grundig 29504-401 + av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap); + if (av7110->fe) + av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + break; + + case 0x0002: // Hauppauge/TT DVB-C premium rev2.X + + av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + } + break; + + case 0x0004: // Galaxis DVB-S rev1.3 + /* ALPS BSRV2 */ + av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + } + break; + + case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */ + /* Grundig 29504-451 */ + av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + } + break; + + case 0x000A: // Hauppauge/TT Nexus-CA rev1.X + + av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params; + + /* set TDA9819 into DVB mode */ + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) + + /* tuner on this needs a slower i2c bus speed */ + av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; + break; + } + break; + + case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ + /* ALPS BSBE1 */ + av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; + av7110->fe->tuner_priv = &av7110->i2c_adap; + + if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) { + printk("dvb-ttpci: LNBP21 not found!\n"); + if (av7110->fe->ops.release) + av7110->fe->ops.release(av7110->fe); + av7110->fe = NULL; + } else { + av7110->fe->ops.dishnetwork_send_legacy_command = NULL; + av7110->recover = dvb_s_recover; + } + } + break; + } + } + + if (!av7110->fe) { + /* FIXME: propagate the failure code from the lower layers */ + ret = -ENOMEM; + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + av7110->dev->pci->vendor, + av7110->dev->pci->device, + av7110->dev->pci->subsystem_vendor, + av7110->dev->pci->subsystem_device); + } else { + FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init); + FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage); + FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend); + + ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe); + if (ret < 0) { + printk("av7110: Frontend registration failed!\n"); + dvb_frontend_detach(av7110->fe); + av7110->fe = NULL; + } + } + return ret; +} + +/* Budgetpatch note: + * Original hardware design by Roberto Deza: + * There is a DVB_Wiki at + * http://www.linuxtv.org/ + * + * New software triggering design by Emard that works on + * original Roberto Deza's hardware: + * + * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin. + * GPIO3 is in budget-patch hardware connectd to port B VSYNC + * HS is an internal event of 7146, accessible with RPS + * and temporarily raised high every n lines + * (n in defined in the RPS_THRESH1 counter threshold) + * I think HS is raised high on the beginning of the n-th line + * and remains high until this n-th line that triggered + * it is completely received. When the receiption of n-th line + * ends, HS is lowered. + * + * To transmit data over DMA, 7146 needs changing state at + * port B VSYNC pin. Any changing of port B VSYNC will + * cause some DMA data transfer, with more or less packets loss. + * It depends on the phase and frequency of VSYNC and + * the way of 7146 is instructed to trigger on port B (defined + * in DD1_INIT register, 3rd nibble from the right valid + * numbers are 0-7, see datasheet) + * + * The correct triggering can minimize packet loss, + * dvbtraffic should give this stable bandwidths: + * 22k transponder = 33814 kbit/s + * 27.5k transponder = 38045 kbit/s + * by experiment it is found that the best results + * (stable bandwidths and almost no packet loss) + * are obtained using DD1_INIT triggering number 2 + * (Va at rising edge of VS Fa = HS x VS-failing forced toggle) + * and a VSYNC phase that occurs in the middle of DMA transfer + * (about byte 188*512=96256 in the DMA window). + * + * Phase of HS is still not clear to me how to control, + * It just happens to be so. It can be seen if one enables + * RPS_IRQ and print Event Counter 1 in vpeirq(). Every + * time RPS_INTERRUPT is called, the Event Counter 1 will + * increment. That's how the 7146 is programmed to do event + * counting in this budget-patch.c + * I *think* HPS setting has something to do with the phase + * of HS but I can't be 100% sure in that. + * + * hardware debug note: a working budget card (including budget patch) + * with vpeirq() interrupt setup in mode "0x90" (every 64K) will + * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes + * and that means 3*25=75 Hz of interrupt freqency, as seen by + * watch cat /proc/interrupts + * + * If this frequency is 3x lower (and data received in the DMA + * buffer don't start with 0x47, but in the middle of packets, + * whose lengths appear to be like 188 292 188 104 etc. + * this means VSYNC line is not connected in the hardware. + * (check soldering pcb and pins) + * The same behaviour of missing VSYNC can be duplicated on budget + * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. + */ +static int __devinit av7110_attach(struct saa7146_dev* dev, + struct saa7146_pci_extension_data *pci_ext) +{ + const int length = TS_WIDTH * TS_HEIGHT; + struct pci_dev *pdev = dev->pci; + struct av7110 *av7110; + struct task_struct *thread; + int ret, count = 0; + + dprintk(4, "dev: %p\n", dev); + + /* Set RPS_IRQ to 1 to track rps1 activity. + * Enabling this won't send any interrupt to PC CPU. + */ +#define RPS_IRQ 0 + + if (budgetpatch == 1) { + budgetpatch = 0; + /* autodetect the presence of budget patch + * this only works if saa7146 has been recently + * reset with with MASK_31 to MC1 + * + * will wait for VBI_B event (vertical blank at port B) + * and will reset GPIO3 after VBI_B is detected. + * (GPIO3 should be raised high by CPU to + * test if GPIO3 will generate vertical blank signal + * in budget patch GPIO3 is connected to VSYNC_B + */ + + /* RESET SAA7146 */ + saa7146_write(dev, MC1, MASK_31); + /* autodetection success seems to be time-dependend after reset */ + + /* Fix VSYNC level */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + /* set vsync_b triggering */ + saa7146_write(dev, DD1_STREAM_B, 0); + /* port B VSYNC at rising edge */ + saa7146_write(dev, DD1_INIT, 0x00000200); + saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI + saa7146_write(dev, MC2, + 1 * (MASK_08 | MASK_24) | // BRS control + 0 * (MASK_09 | MASK_25) | // a + 1 * (MASK_10 | MASK_26) | // b + 0 * (MASK_06 | MASK_22) | // HPS_CTRL1 + 0 * (MASK_05 | MASK_21) | // HPS_CTRL2 + 0 * (MASK_01 | MASK_15) // DEBI + ); + + /* start writing RPS1 code from beginning */ + count = 0; + /* Disable RPS1 */ + saa7146_write(dev, MC1, MASK_29); + /* RPS1 timeout disable */ + saa7146_write(dev, RPS_TOV1, 0); + WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + /* issue RPS1 interrupt to increment counter */ + WRITE_RPS1(CMD_INTERRUPT); +#endif + WRITE_RPS1(CMD_STOP); + /* Jump to begin of RPS program as safety measure (p37) */ + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); + +#if RPS_IRQ + /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + */ + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + /* set event counter 1 threshold to maximum allowed value (rEC p55) */ + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + /* Set RPS1 Address register to point to RPS code (r108 p42) */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + /* Enable RPS1, (rFC p33) */ + saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); + + mdelay(10); + /* now send VSYNC_B to rps1 by rising GPIO3 */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + mdelay(10); + /* if rps1 responded by lowering the GPIO3, + * then we have budgetpatch hardware + */ + if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) { + budgetpatch = 1; + printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n"); + } + /* Disable RPS1 */ + saa7146_write(dev, MC1, ( MASK_29 )); +#if RPS_IRQ + printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); +#endif + } + + /* prepare the av7110 device struct */ + av7110 = kzalloc(sizeof(struct av7110), GFP_KERNEL); + if (!av7110) { + dprintk(1, "out of memory\n"); + return -ENOMEM; + } + + av7110->card_name = (char*) pci_ext->ext_priv; + av7110->dev = dev; + dev->ext_priv = av7110; + + ret = get_firmware(av7110); + if (ret < 0) + goto err_kfree_0; + + ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, + THIS_MODULE, &dev->pci->dev, adapter_nr); + if (ret < 0) + goto err_put_firmware_1; + + /* the Siemens DVB needs this if you want to have the i2c chips + get recognized before the main driver is fully loaded */ + saa7146_write(dev, GPIO_CTRL, 0x500000); + + strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name)); + + saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */ + + ret = i2c_add_adapter(&av7110->i2c_adap); + if (ret < 0) + goto err_dvb_unregister_adapter_2; + + ttpci_eeprom_parse_mac(&av7110->i2c_adap, + av7110->dvb_adapter.proposed_mac); + ret = -ENOMEM; + + /* full-ts mod? */ + if (full_ts) + av7110->full_ts = true; + + /* check for full-ts flag in eeprom */ + if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) { + u8 flags = i2c_readreg(av7110, 0xaa, 2); + if (flags != 0xff && (flags & 0x01)) + av7110->full_ts = true; + } + + if (av7110->full_ts) { + printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n"); + spin_lock_init(&av7110->feedlock1); + av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, + &av7110->pt); + if (!av7110->grabbing) + goto err_i2c_del_3; + + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + + saa7146_write(dev, DD1_INIT, 0x00000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, MC2, MASK_08 | MASK_24); + + /* dma3 */ + saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, 0); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, PITCH3, TS_WIDTH); + saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); + saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); + saa7146_write(dev, MC2, MASK_04 | MASK_20); + + tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); + + } else if (budgetpatch) { + spin_lock_init(&av7110->feedlock1); + av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, + &av7110->pt); + if (!av7110->grabbing) + goto err_i2c_del_3; + + saa7146_write(dev, PCI_BT_V1, 0x1c1f101f); + saa7146_write(dev, BCS_CTRL, 0x80400040); + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x03000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, 0); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); + + saa7146_write(dev, PITCH3, TS_WIDTH); + saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); + + /* upload all */ + saa7146_write(dev, MC2, 0x077c077c); + saa7146_write(dev, GPIO_CTRL, 0x000000); +#if RPS_IRQ + /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + */ + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + /* set event counter 1 threshold to maximum allowed value (rEC p55) */ + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + /* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */ + count = 0; + + /* Wait Source Line Counter Threshold (p36) */ + WRITE_RPS1(CMD_PAUSE | EVT_HS); + /* Set GPIO3=1 (p42) */ + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); +#if RPS_IRQ + /* issue RPS1 interrupt */ + WRITE_RPS1(CMD_INTERRUPT); +#endif + /* Wait reset Source Line Counter Threshold (p36) */ + WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); + /* Set GPIO3=0 (p42) */ + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + /* issue RPS1 interrupt */ + WRITE_RPS1(CMD_INTERRUPT); +#endif + /* Jump to begin of RPS program (p37) */ + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); + + /* Fix VSYNC level */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + /* Set RPS1 Address register to point to RPS code (r108 p42) */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + /* Set Source Line Counter Threshold, using BRS (rCC p43) + * It generates HS event every TS_HEIGHT lines + * this is related to TS_WIDTH set in register + * NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits + * are set to TS_WIDTH bytes (TS_WIDTH=2*188), + * then RPS_THRESH1 should be set to trigger + * every TS_HEIGHT (512) lines. + */ + saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 ); + + /* Enable RPS1 (rFC p33) */ + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + /* end of budgetpatch register initialization */ + tasklet_init (&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); + } else { + saa7146_write(dev, PCI_BT_V1, 0x1c00101f); + saa7146_write(dev, BCS_CTRL, 0x80400040); + + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x03000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* upload all */ + saa7146_write(dev, MC2, 0x077c077c); + saa7146_write(dev, GPIO_CTRL, 0x000000); + } + + tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110); + tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110); + + mutex_init(&av7110->pid_mutex); + + /* locks for data transfers from/to AV7110 */ + spin_lock_init(&av7110->debilock); + mutex_init(&av7110->dcomlock); + av7110->debitype = -1; + + /* default OSD window */ + av7110->osdwin = 1; + mutex_init(&av7110->osd_mutex); + + /* TV standard */ + av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC + : AV7110_VIDEO_MODE_PAL; + + /* ARM "watchdog" */ + init_waitqueue_head(&av7110->arm_wait); + av7110->arm_thread = NULL; + + /* allocate and init buffers */ + av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus); + if (!av7110->debi_virt) + goto err_saa71466_vfree_4; + + + av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS); + if (!av7110->iobuf) + goto err_pci_free_5; + + ret = av7110_av_init(av7110); + if (ret < 0) + goto err_iobuf_vfree_6; + + /* init BMP buffer */ + av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN; + init_waitqueue_head(&av7110->bmpq); + + ret = av7110_ca_init(av7110); + if (ret < 0) + goto err_av7110_av_exit_7; + + /* load firmware into AV7110 cards */ + ret = av7110_bootarm(av7110); + if (ret < 0) + goto err_av7110_ca_exit_8; + + ret = av7110_firmversion(av7110); + if (ret < 0) + goto err_stop_arm_9; + + if (FW_VERSION(av7110->arm_app)<0x2501) + printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. " + "System might be unstable!\n", FW_VERSION(av7110->arm_app)); + + thread = kthread_run(arm_thread, (void *) av7110, "arm_mon"); + if (IS_ERR(thread)) { + ret = PTR_ERR(thread); + goto err_stop_arm_9; + } + av7110->arm_thread = thread; + + /* set initial volume in mixer struct */ + av7110->mixer.volume_left = volume; + av7110->mixer.volume_right = volume; + + ret = av7110_register(av7110); + if (ret < 0) + goto err_arm_thread_stop_10; + + init_av7110_av(av7110); + + /* special case DVB-C: these cards have an analog tuner + plus need some special handling, so we have separate + saa7146_ext_vv data for these... */ + ret = av7110_init_v4l(av7110); + if (ret < 0) + goto err_av7110_unregister_11; + + av7110->dvb_adapter.priv = av7110; + ret = frontend_init(av7110); + if (ret < 0) + goto err_av7110_exit_v4l_12; + +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_ir_init(av7110); +#endif + printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); + av7110_num++; +out: + return ret; + +err_av7110_exit_v4l_12: + av7110_exit_v4l(av7110); +err_av7110_unregister_11: + dvb_unregister(av7110); +err_arm_thread_stop_10: + av7110_arm_sync(av7110); +err_stop_arm_9: + /* Nothing to do. Rejoice. */ +err_av7110_ca_exit_8: + av7110_ca_exit(av7110); +err_av7110_av_exit_7: + av7110_av_exit(av7110); +err_iobuf_vfree_6: + vfree(av7110->iobuf); +err_pci_free_5: + pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus); +err_saa71466_vfree_4: + if (av7110->grabbing) + saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt); +err_i2c_del_3: + i2c_del_adapter(&av7110->i2c_adap); +err_dvb_unregister_adapter_2: + dvb_unregister_adapter(&av7110->dvb_adapter); +err_put_firmware_1: + put_firmware(av7110); +err_kfree_0: + kfree(av7110); + goto out; +} + +static int __devexit av7110_detach(struct saa7146_dev* saa) +{ + struct av7110 *av7110 = saa->ext_priv; + dprintk(4, "%p\n", av7110); + +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_ir_exit(av7110); +#endif + if (budgetpatch || av7110->full_ts) { + if (budgetpatch) { + /* Disable RPS1 */ + saa7146_write(saa, MC1, MASK_29); + /* VSYNC LOW (inactive) */ + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + } + saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ + SAA7146_IER_DISABLE(saa, MASK_10); + SAA7146_ISR_CLEAR(saa, MASK_10); + msleep(50); + tasklet_kill(&av7110->vpe_tasklet); + saa7146_vfree_destroy_pgtable(saa->pci, av7110->grabbing, &av7110->pt); + } + av7110_exit_v4l(av7110); + + av7110_arm_sync(av7110); + + tasklet_kill(&av7110->debi_tasklet); + tasklet_kill(&av7110->gpio_tasklet); + + dvb_unregister(av7110); + + SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03); + SAA7146_ISR_CLEAR(saa, MASK_19 | MASK_03); + + av7110_ca_exit(av7110); + av7110_av_exit(av7110); + + vfree(av7110->iobuf); + pci_free_consistent(saa->pci, 8192, av7110->debi_virt, + av7110->debi_bus); + + i2c_del_adapter(&av7110->i2c_adap); + + dvb_unregister_adapter (&av7110->dvb_adapter); + + av7110_num--; + + put_firmware(av7110); + + kfree(av7110); + + saa->ext_priv = NULL; + + return 0; +} + + +static void av7110_irq(struct saa7146_dev* dev, u32 *isr) +{ + struct av7110 *av7110 = dev->ext_priv; + + //print_time("av7110_irq"); + + /* Note: Don't try to handle the DEBI error irq (MASK_18), in + * intel mode the timeout is asserted all the time... + */ + + if (*isr & MASK_19) { + //printk("av7110_irq: DEBI\n"); + /* Note 1: The DEBI irq is level triggered: We must enable it + * only after we started a DMA xfer, and disable it here + * immediately, or it will be signalled all the time while + * DEBI is idle. + * Note 2: You would think that an irq which is masked is + * not signalled by the hardware. Not so for the SAA7146: + * An irq is signalled as long as the corresponding bit + * in the ISR is set, and disabling irqs just prevents the + * hardware from setting the ISR bit. This means a) that we + * must clear the ISR *after* disabling the irq (which is why + * we must do it here even though saa7146_core did it already), + * and b) that if we were to disable an edge triggered irq + * (like the gpio irqs sadly are) temporarily we would likely + * loose some. This sucks :-( + */ + SAA7146_IER_DISABLE(av7110->dev, MASK_19); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); + tasklet_schedule(&av7110->debi_tasklet); + } + + if (*isr & MASK_03) { + //printk("av7110_irq: GPIO\n"); + tasklet_schedule(&av7110->gpio_tasklet); + } + + if (*isr & MASK_10) + tasklet_schedule(&av7110->vpe_tasklet); +} + + +static struct saa7146_extension av7110_extension_driver; + +#define MAKE_AV7110_INFO(x_var,x_name) \ +static struct saa7146_pci_extension_data x_var = { \ + .ext_priv = x_name, \ + .ext = &av7110_extension_driver } + +MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C"); +MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); +MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); +MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); +MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X"); +MAKE_AV7110_INFO(tts_2_3, "Technotrend/Hauppauge WinTV Nexus-S rev2.3"); +MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE"); +MAKE_AV7110_INFO(ttt, "Technotrend/Hauppauge DVB-T"); +MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); +MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); +MAKE_AV7110_INFO(gxs_1_3, "Galaxis DVB-S rev1.3"); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), + MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000), + MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), + MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), + MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), + MAKE_EXTENSION_PCI(gxs_1_3, 0x13c2, 0x0004), + MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), + MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), + MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), + MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), + MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), + +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v???? + + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + + +static struct saa7146_extension av7110_extension_driver = { + .name = "av7110", + .flags = SAA7146_USE_I2C_IRQ, + + .module = THIS_MODULE, + .pci_tbl = &pci_tbl[0], + .attach = av7110_attach, + .detach = __devexit_p(av7110_detach), + + .irq_mask = MASK_19 | MASK_03 | MASK_10, + .irq_func = av7110_irq, +}; + + +static int __init av7110_init(void) +{ + int retval; + retval = saa7146_register_extension(&av7110_extension_driver); + return retval; +} + + +static void __exit av7110_exit(void) +{ + saa7146_unregister_extension(&av7110_extension_driver); +} + +module_init(av7110_init); +module_exit(av7110_exit); + +MODULE_DESCRIPTION("driver for the SAA7146 based AV110 PCI DVB cards by " + "Siemens, Technotrend, Hauppauge"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ca.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ca.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ca.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ca.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,387 @@ +/* + * av7110_ca.c: CA and CI stuff + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_ca.h" + + +void CI_handle(struct av7110 *av7110, u8 *data, u16 len) +{ + dprintk(8, "av7110:%p\n",av7110); + + if (len < 3) + return; + switch (data[0]) { + case CI_MSG_CI_INFO: + if (data[2] != 1 && data[2] != 2) + break; + switch (data[1]) { + case 0: + av7110->ci_slot[data[2] - 1].flags = 0; + break; + case 1: + av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT; + break; + case 2: + av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY; + break; + } + break; + case CI_SWITCH_PRG_REPLY: + //av7110->ci_stat=data[1]; + break; + default: + break; + } +} + + +void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len) +{ + if (dvb_ringbuffer_free(cibuf) < len + 2) + return; + + DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8); + DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff); + dvb_ringbuffer_write(cibuf, data, len); + wake_up_interruptible(&cibuf->queue); +} + + +/****************************************************************************** + * CI link layer file ops + ******************************************************************************/ + +static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size) +{ + struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p; + void *data; + + for (p = tab; *p; p++) { + data = vmalloc(size); + if (!data) { + while (p-- != tab) { + vfree(p[0]->data); + p[0]->data = NULL; + } + return -ENOMEM; + } + dvb_ringbuffer_init(*p, data, size); + } + return 0; +} + +static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) +{ + dvb_ringbuffer_flush_spinlock_wakeup(cirbuf); + dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf); +} + +static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) +{ + vfree(cirbuf->data); + cirbuf->data = NULL; + vfree(ciwbuf->data); + ciwbuf->data = NULL; +} + +static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, + int slots, ca_slot_info_t *slot) +{ + int i; + int len = 0; + u8 msg[8] = { 0x00, 0x06, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00 }; + + for (i = 0; i < 2; i++) { + if (slots & (1 << i)) + len += 8; + } + + if (dvb_ringbuffer_free(cibuf) < len) + return -EBUSY; + + for (i = 0; i < 2; i++) { + if (slots & (1 << i)) { + msg[2] = i; + dvb_ringbuffer_write(cibuf, msg, 8); + slot[i].flags = 0; + } + } + + return 0; +} + +static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + int free; + int non_blocking = file->f_flags & O_NONBLOCK; + u8 *page = (u8 *)__get_free_page(GFP_USER); + int res; + + if (!page) + return -ENOMEM; + + res = -EINVAL; + if (count > 2048) + goto out; + + res = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + free = dvb_ringbuffer_free(cibuf); + if (count + 2 > free) { + res = -EWOULDBLOCK; + if (non_blocking) + goto out; + res = -ERESTARTSYS; + if (wait_event_interruptible(cibuf->queue, + (dvb_ringbuffer_free(cibuf) >= count + 2))) + goto out; + } + + DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8); + DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff); + + res = dvb_ringbuffer_write(cibuf, page, count); +out: + free_page((unsigned long)page); + return res; +} + +static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + int avail; + int non_blocking = file->f_flags & O_NONBLOCK; + ssize_t len; + + if (!cibuf->data || !count) + return 0; + if (non_blocking && (dvb_ringbuffer_empty(cibuf))) + return -EWOULDBLOCK; + if (wait_event_interruptible(cibuf->queue, + !dvb_ringbuffer_empty(cibuf))) + return -ERESTARTSYS; + avail = dvb_ringbuffer_avail(cibuf); + if (avail < 4) + return 0; + len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; + len |= DVB_RINGBUFFER_PEEK(cibuf, 1); + if (avail < len + 2 || count < len) + return -EINVAL; + DVB_RINGBUFFER_SKIP(cibuf, 2); + + return dvb_ringbuffer_read_user(cibuf, buf, len); +} + +static int dvb_ca_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + int err = dvb_generic_open(inode, file); + + dprintk(8, "av7110:%p\n",av7110); + + if (err < 0) + return err; + ci_ll_flush(&av7110->ci_rbuffer, &av7110->ci_wbuffer); + return 0; +} + +static unsigned int dvb_ca_poll (struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer; + struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer; + unsigned int mask = 0; + + dprintk(8, "av7110:%p\n",av7110); + + poll_wait(file, &rbuf->queue, wait); + poll_wait(file, &wbuf->queue, wait); + + if (!dvb_ringbuffer_empty(rbuf)) + mask |= (POLLIN | POLLRDNORM); + + if (dvb_ringbuffer_free(wbuf) > 1024) + mask |= (POLLOUT | POLLWRNORM); + + return mask; +} + +static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned long arg = (unsigned long) parg; + + dprintk(8, "av7110:%p\n",av7110); + + switch (cmd) { + case CA_RESET: + return ci_ll_reset(&av7110->ci_wbuffer, file, arg, &av7110->ci_slot[0]); + break; + case CA_GET_CAP: + { + ca_caps_t cap; + + cap.slot_num = 2; + cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ? + CA_CI_LINK : CA_CI) | CA_DESCR; + cap.descr_num = 16; + cap.descr_type = CA_ECD; + memcpy(parg, &cap, sizeof(cap)); + break; + } + + case CA_GET_SLOT_INFO: + { + ca_slot_info_t *info=(ca_slot_info_t *)parg; + + if (info->num < 0 || info->num > 1) + return -EINVAL; + av7110->ci_slot[info->num].num = info->num; + av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? + CA_CI_LINK : CA_CI; + memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); + break; + } + + case CA_GET_MSG: + break; + + case CA_SEND_MSG: + break; + + case CA_GET_DESCR_INFO: + { + ca_descr_info_t info; + + info.num = 16; + info.type = CA_ECD; + memcpy(parg, &info, sizeof (info)); + break; + } + + case CA_SET_DESCR: + { + ca_descr_t *descr = (ca_descr_t*) parg; + + if (descr->index >= 16) + return -EINVAL; + if (descr->parity > 1) + return -EINVAL; + av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5, + (descr->index<<8)|descr->parity, + (descr->cw[0]<<8)|descr->cw[1], + (descr->cw[2]<<8)|descr->cw[3], + (descr->cw[4]<<8)|descr->cw[5], + (descr->cw[6]<<8)|descr->cw[7]); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +static ssize_t dvb_ca_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(8, "av7110:%p\n",av7110); + return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos); +} + +static ssize_t dvb_ca_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(8, "av7110:%p\n",av7110); + return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos); +} + +static const struct file_operations dvb_ca_fops = { + .owner = THIS_MODULE, + .read = dvb_ca_read, + .write = dvb_ca_write, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_ca_open, + .release = dvb_generic_release, + .poll = dvb_ca_poll, + .llseek = default_llseek, +}; + +static struct dvb_device dvbdev_ca = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_ca_fops, + .kernel_ioctl = dvb_ca_ioctl, +}; + + +int av7110_ca_register(struct av7110 *av7110) +{ + return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev, + &dvbdev_ca, av7110, DVB_DEVICE_CA); +} + +void av7110_ca_unregister(struct av7110 *av7110) +{ + dvb_unregister_device(av7110->ca_dev); +} + +int av7110_ca_init(struct av7110* av7110) +{ + return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192); +} + +void av7110_ca_exit(struct av7110* av7110) +{ + ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ca.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ca.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ca.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ca.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,14 @@ +#ifndef _AV7110_CA_H_ +#define _AV7110_CA_H_ + +struct av7110; + +extern void CI_handle(struct av7110 *av7110, u8 *data, u16 len); +extern void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len); + +extern int av7110_ca_register(struct av7110 *av7110); +extern void av7110_ca_unregister(struct av7110 *av7110); +extern int av7110_ca_init(struct av7110* av7110); +extern void av7110_ca_exit(struct av7110* av7110); + +#endif /* _AV7110_CA_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,315 @@ +#ifndef _AV7110_H_ +#define _AV7110_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "dvbdev.h" +#include "demux.h" +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_filter.h" +#include "dvb_net.h" +#include "dvb_ringbuffer.h" +#include "dvb_frontend.h" +#include "ves1820.h" +#include "ves1x93.h" +#include "stv0299.h" +#include "tda8083.h" +#include "sp8870.h" +#include "stv0297.h" +#include "l64781.h" + +#include + + +#define ANALOG_TUNER_VES1820 1 +#define ANALOG_TUNER_STV0297 2 + +extern int av7110_debug; + +#define dprintk(level,args...) \ + do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __func__); printk(args); } } while (0) + +#define MAXFILT 32 + +enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM}; + +enum av7110_video_mode { + AV7110_VIDEO_MODE_PAL = 0, + AV7110_VIDEO_MODE_NTSC = 1 +}; + +struct av7110_p2t { + u8 pes[TS_SIZE]; + u8 counter; + long int pos; + int frags; + struct dvb_demux_feed *feed; +}; + +/* video MPEG decoder events: */ +/* (code copied from dvb_frontend.c, should maybe be factored out...) */ +#define MAX_VIDEO_EVENT 8 +struct dvb_video_events { + struct video_event events[MAX_VIDEO_EVENT]; + int eventw; + int eventr; + int overflow; + wait_queue_head_t wait_queue; + spinlock_t lock; +}; + + +struct av7110; + +/* infrared remote control */ +struct infrared { + u16 key_map[256]; + struct input_dev *input_dev; + char input_phys[32]; + struct timer_list keyup_timer; + struct tasklet_struct ir_tasklet; + void (*ir_handler)(struct av7110 *av7110, u32 ircom); + u32 ir_command; + u32 ir_config; + u32 device_mask; + u8 protocol; + u8 inversion; + u16 last_key; + u16 last_toggle; + u8 delay_timer_finished; +}; + + +/* place to store all the necessary device information */ +struct av7110 { + + /* devices */ + + struct dvb_device dvb_dev; + struct dvb_net dvb_net; + + struct video_device *v4l_dev; + struct video_device *vbi_dev; + + struct saa7146_dev *dev; + + struct i2c_adapter i2c_adap; + + char *card_name; + + /* support for analog module of dvb-c */ + int analog_tuner_flags; + int current_input; + u32 current_freq; + + struct tasklet_struct debi_tasklet; + struct tasklet_struct gpio_tasklet; + + int adac_type; /* audio DAC type */ +#define DVB_ADAC_TI 0 +#define DVB_ADAC_CRYSTAL 1 +#define DVB_ADAC_MSP34x0 2 +#define DVB_ADAC_MSP34x5 3 +#define DVB_ADAC_NONE -1 + + + /* buffers */ + + void *iobuf; /* memory for all buffers */ + struct dvb_ringbuffer avout; /* buffer for video or A/V mux */ +#define AVOUTLEN (128*1024) + struct dvb_ringbuffer aout; /* buffer for audio */ +#define AOUTLEN (64*1024) + void *bmpbuf; +#define BMPLEN (8*32768+1024) + + /* bitmap buffers and states */ + + int bmpp; + int bmplen; + volatile int bmp_state; +#define BMP_NONE 0 +#define BMP_LOADING 1 +#define BMP_LOADED 2 + wait_queue_head_t bmpq; + + + /* DEBI and polled command interface */ + + spinlock_t debilock; + struct mutex dcomlock; + volatile int debitype; + volatile int debilen; + + + /* Recording and playback flags */ + + int rec_mode; + int playing; +#define RP_NONE 0 +#define RP_VIDEO 1 +#define RP_AUDIO 2 +#define RP_AV 3 + + + /* OSD */ + + int osdwin; /* currently active window */ + u16 osdbpp[8]; + struct mutex osd_mutex; + + /* CA */ + + ca_slot_info_t ci_slot[2]; + + enum av7110_video_mode vidmode; + struct dmxdev dmxdev; + struct dvb_demux demux; + + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + + /* for budget mode demux1 */ + struct dmxdev dmxdev1; + struct dvb_demux demux1; + struct dvb_net dvb_net1; + spinlock_t feedlock1; + int feeding1; + u32 ttbp; + unsigned char *grabbing; + struct saa7146_pgtable pt; + struct tasklet_struct vpe_tasklet; + bool full_ts; + + int fe_synced; + struct mutex pid_mutex; + + int video_blank; + struct video_status videostate; + u16 display_panscan; + int display_ar; + int trickmode; +#define TRICK_NONE 0 +#define TRICK_FAST 1 +#define TRICK_SLOW 2 +#define TRICK_FREEZE 3 + struct audio_status audiostate; + + struct dvb_demux_filter *handle2filter[32]; + struct av7110_p2t p2t_filter[MAXFILT]; + struct dvb_filter_pes2ts p2t[2]; + struct ipack ipack[2]; + u8 *kbuf[2]; + + int sinfo; + int feeding; + + int arm_errors; + int registered; + + + /* AV711X */ + + u32 arm_fw; + u32 arm_rtsl; + u32 arm_vid; + u32 arm_app; + u32 avtype; + int arm_ready; + struct task_struct *arm_thread; + wait_queue_head_t arm_wait; + u16 arm_loops; + + void *debi_virt; + dma_addr_t debi_bus; + + u16 pids[DMX_PES_OTHER]; + + struct dvb_ringbuffer ci_rbuffer; + struct dvb_ringbuffer ci_wbuffer; + + struct audio_mixer mixer; + + struct dvb_adapter dvb_adapter; + struct dvb_device *video_dev; + struct dvb_device *audio_dev; + struct dvb_device *ca_dev; + struct dvb_device *osd_dev; + + struct dvb_video_events video_events; + video_size_t video_size; + + u16 wssMode; + u16 wssData; + + struct infrared ir; + + /* firmware stuff */ + unsigned char *bin_fw; + unsigned long size_fw; + + unsigned char *bin_dpram; + unsigned long size_dpram; + + unsigned char *bin_root; + unsigned long size_root; + + struct dvb_frontend* fe; + fe_status_t fe_status; + + /* crash recovery */ + void (*recover)(struct av7110* av7110); + struct dvb_frontend_parameters saved_fe_params; + fe_sec_voltage_t saved_voltage; + fe_sec_tone_mode_t saved_tone; + struct dvb_diseqc_master_cmd saved_master_cmd; + fe_sec_mini_cmd_t saved_minicmd; + + int (*fe_init)(struct dvb_frontend* fe); + int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); + int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); + int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); + int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); + int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); + int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); + int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); + int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + + +extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, + u16 subpid, u16 pcrpid); + +extern int av7110_check_ir_config(struct av7110 *av7110, int force); +extern int av7110_ir_init(struct av7110 *av7110); +extern void av7110_ir_exit(struct av7110 *av7110); + +/* msp3400 i2c subaddresses */ +#define MSP_WR_DEM 0x10 +#define MSP_RD_DEM 0x11 +#define MSP_WR_DSP 0x12 +#define MSP_RD_DSP 0x13 + +extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val); +extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg); +extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val); + + +extern int av7110_init_analog_module(struct av7110 *av7110); +extern int av7110_init_v4l(struct av7110 *av7110); +extern int av7110_exit_v4l(struct av7110 *av7110); + +#endif /* _AV7110_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_hw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_hw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_hw.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_hw.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1208 @@ +/* + * av7110_hw.c: av7110 low level hardware access and firmware interface + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * 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, or (at your option) any later version. + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * the project's page is at http://www.linuxtv.org/ + */ + +/* for debugging ARM communication: */ +//#define COM_DEBUG + +#include +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" + +#define _NOHANDSHAKE + +/**************************************************************************** + * DEBI functions + ****************************************************************************/ + +/* This DEBI code is based on the Stradis driver + by Nathan Laredo */ + +int av7110_debiwrite(struct av7110 *av7110, u32 config, + int addr, u32 val, int count) +{ + struct saa7146_dev *dev = av7110->dev; + + if (count <= 0 || count > 32764) { + printk("%s: invalid count %d\n", __func__, count); + return -1; + } + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done failed\n", __func__); + return -1; + } + saa7146_write(dev, DEBI_CONFIG, config); + if (count <= 4) /* immediate transfer */ + saa7146_write(dev, DEBI_AD, val); + else /* block transfer */ + saa7146_write(dev, DEBI_AD, av7110->debi_bus); + saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff)); + saa7146_write(dev, MC2, (2 << 16) | 2); + return 0; +} + +u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count) +{ + struct saa7146_dev *dev = av7110->dev; + u32 result = 0; + + if (count > 32764 || count <= 0) { + printk("%s: invalid count %d\n", __func__, count); + return 0; + } + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done #1 failed\n", __func__); + return 0; + } + saa7146_write(dev, DEBI_AD, av7110->debi_bus); + saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); + + saa7146_write(dev, DEBI_CONFIG, config); + saa7146_write(dev, MC2, (2 << 16) | 2); + if (count > 4) + return count; + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done #2 failed\n", __func__); + return 0; + } + + result = saa7146_read(dev, DEBI_AD); + result &= (0xffffffffUL >> ((4 - count) * 8)); + return result; +} + + + +/* av7110 ARM core boot stuff */ +#if 0 +void av7110_reset_arm(struct av7110 *av7110) +{ + saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO); + + /* Disable DEBI and GPIO irq */ + SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + + saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI); + msleep(30); /* the firmware needs some time to initialize */ + + ARM_ResetMailBox(av7110); + + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + SAA7146_IER_ENABLE(av7110->dev, MASK_03); + + av7110->arm_ready = 1; + dprintk(1, "reset ARM\n"); +} +#endif /* 0 */ + +static int waitdebi(struct av7110 *av7110, int adr, int state) +{ + int k; + + dprintk(4, "%p\n", av7110); + + for (k = 0; k < 100; k++) { + if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state) + return 0; + udelay(5); + } + return -ETIMEDOUT; +} + +static int load_dram(struct av7110 *av7110, u32 *data, int len) +{ + int i; + int blocks, rest; + u32 base, bootblock = AV7110_BOOT_BLOCK; + + dprintk(4, "%p\n", av7110); + + blocks = len / AV7110_BOOT_MAX_SIZE; + rest = len % AV7110_BOOT_MAX_SIZE; + base = DRAM_START_CODE; + + for (i = 0; i < blocks; i++) { + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); + return -ETIMEDOUT; + } + dprintk(4, "writing DRAM block %d\n", i); + mwdebi(av7110, DEBISWAB, bootblock, + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE); + bootblock ^= 0x1400; + iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + base += AV7110_BOOT_MAX_SIZE; + } + + if (rest > 0) { + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); + return -ETIMEDOUT; + } + if (rest > 4) + mwdebi(av7110, DEBISWAB, bootblock, + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest); + else + mwdebi(av7110, DEBISWAB, bootblock, + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4); + + iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + } + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); + return -ETIMEDOUT; + } + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); + return -ETIMEDOUT; + } + return 0; +} + + +/* we cannot write av7110 DRAM directly, so load a bootloader into + * the DPRAM which implements a simple boot protocol */ +int av7110_bootarm(struct av7110 *av7110) +{ + const struct firmware *fw; + const char *fw_name = "av7110/bootcode.bin"; + struct saa7146_dev *dev = av7110->dev; + u32 ret; + int i; + + dprintk(4, "%p\n", av7110); + + av7110->arm_ready = 0; + + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); + + /* Disable DEBI and GPIO irq */ + SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + + /* enable DEBI */ + saa7146_write(av7110->dev, MC1, 0x08800880); + saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); + saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* test DEBI */ + iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); + /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */ + iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); + + if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) { + printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: " + "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n", + ret, 0x10325476); + return -1; + } + for (i = 0; i < 8192; i += 4) + iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4); + dprintk(2, "debi test OK\n"); + + /* boot */ + dprintk(1, "load boot code\n"); + saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO); + //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT); + //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT); + + ret = request_firmware(&fw, fw_name, &dev->pci->dev); + if (ret) { + printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n", + fw_name); + return ret; + } + + mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size); + release_firmware(fw); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + + if (saa7146_wait_for_debi_done(av7110->dev, 1)) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " + "saa7146_wait_for_debi_done() timed out\n"); + return -ETIMEDOUT; + } + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); + mdelay(1); + + dprintk(1, "load dram code\n"); + if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " + "load_dram() failed\n"); + return -1; + } + + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); + mdelay(1); + + dprintk(1, "load dpram code\n"); + mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram); + + if (saa7146_wait_for_debi_done(av7110->dev, 1)) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " + "saa7146_wait_for_debi_done() timed out after loading DRAM\n"); + return -ETIMEDOUT; + } + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); + msleep(30); /* the firmware needs some time to initialize */ + + //ARM_ClearIrq(av7110); + ARM_ResetMailBox(av7110); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + SAA7146_IER_ENABLE(av7110->dev, MASK_03); + + av7110->arm_errors = 0; + av7110->arm_ready = 1; + return 0; +} +MODULE_FIRMWARE("av7110/bootcode.bin"); + +/**************************************************************************** + * DEBI command polling + ****************************************************************************/ + +int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) +{ + unsigned long start; + u32 stat; + int err; + + if (FW_VERSION(av7110->arm_app) <= 0x261c) { + /* not supported by old firmware */ + msleep(50); + return 0; + } + + /* new firmware */ + start = jiffies; + for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + mutex_unlock(&av7110->dcomlock); + if ((stat & flags) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", + __func__, stat & flags); + return -ETIMEDOUT; + } + msleep(1); + } + return 0; +} + +static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) +{ + int i; + unsigned long start; + char *type = NULL; + u16 flags[2] = {0, 0}; + u32 stat; + int err; + +// dprintk(4, "%p\n", av7110); + + if (!av7110->arm_ready) { + dprintk(1, "arm not ready.\n"); + return -ENXIO; + } + + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__); + av7110->arm_errors++; + return -ETIMEDOUT; + } + msleep(1); + } + + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); + +#ifndef _NOHANDSHAKE + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__); + return -ETIMEDOUT; + } + msleep(1); + } +#endif + + switch ((buf[0] >> 8) & 0xff) { + case COMTYPE_PIDFILTER: + case COMTYPE_ENCODER: + case COMTYPE_REC_PLAY: + case COMTYPE_MPEGDECODER: + type = "MSG"; + flags[0] = GPMQOver; + flags[1] = GPMQFull; + break; + case COMTYPE_OSD: + type = "OSD"; + flags[0] = OSDQOver; + flags[1] = OSDQFull; + break; + case COMTYPE_MISC: + if (FW_VERSION(av7110->arm_app) >= 0x261d) { + type = "MSG"; + flags[0] = GPMQOver; + flags[1] = GPMQBusy; + } + break; + default: + break; + } + + if (type != NULL) { + /* non-immediate COMMAND type */ + start = jiffies; + for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + if (stat & flags[0]) { + printk(KERN_ERR "%s: %s QUEUE overflow\n", + __func__, type); + return -1; + } + if ((stat & flags[1]) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", + __func__, type); + av7110->arm_errors++; + return -ETIMEDOUT; + } + msleep(1); + } + } + + for (i = 2; i < length; i++) + wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2); + + if (length) + wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2); + else + wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2); + + wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2); + + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); + +#ifdef COM_DEBUG + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", + __func__, (buf[0] >> 8) & 0xff); + return -ETIMEDOUT; + } + msleep(1); + } + + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + if (stat & GPMQOver) { + printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__); + return -ENOSPC; + } + else if (stat & OSDQOver) { + printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__); + return -ENOSPC; + } +#endif + + return 0; +} + +static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) +{ + int ret; + +// dprintk(4, "%p\n", av7110); + + if (!av7110->arm_ready) { + dprintk(1, "arm not ready.\n"); + return -1; + } + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + + ret = __av7110_send_fw_cmd(av7110, buf, length); + mutex_unlock(&av7110->dcomlock); + if (ret && ret!=-ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n", + __func__, ret); + return ret; +} + +int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) +{ + va_list args; + u16 buf[num + 2]; + int i, ret; + +// dprintk(4, "%p\n", av7110); + + buf[0] = ((type << 8) | com); + buf[1] = num; + + if (num) { + va_start(args, num); + for (i = 0; i < num; i++) + buf[i + 2] = va_arg(args, u32); + va_end(args); + } + + ret = av7110_send_fw_cmd(av7110, buf, num + 2); + if (ret && ret != -ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret); + return ret; +} + +#if 0 +int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) +{ + int i, ret; + u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + dprintk(4, "%p\n", av7110); + + for(i = 0; i < len && i < 32; i++) + { + if(i % 2 == 0) + cmd[(i / 2) + 2] = (u16)(buf[i]) << 8; + else + cmd[(i / 2) + 2] |= buf[i]; + } + + ret = av7110_send_fw_cmd(av7110, cmd, 18); + if (ret && ret != -ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); + return ret; +} +#endif /* 0 */ + +int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, + int request_buf_len, u16 *reply_buf, int reply_buf_len) +{ + int err; + s16 i; + unsigned long start; +#ifdef COM_DEBUG + u32 stat; +#endif + + dprintk(4, "%p\n", av7110); + + if (!av7110->arm_ready) { + dprintk(1, "arm not ready.\n"); + return -1; + } + + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + + if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) { + mutex_unlock(&av7110->dcomlock); + printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err); + return err; + } + + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } +#ifdef _NOHANDSHAKE + msleep(1); +#endif + } + +#ifndef _NOHANDSHAKE + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } +#endif + +#ifdef COM_DEBUG + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + if (stat & GPMQOver) { + printk(KERN_ERR "%s: GPMQOver\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -1; + } + else if (stat & OSDQOver) { + printk(KERN_ERR "%s: OSDQOver\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -1; + } +#endif + + for (i = 0; i < reply_buf_len; i++) + reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2); + + mutex_unlock(&av7110->dcomlock); + return 0; +} + +static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length) +{ + int ret; + ret = av7110_fw_request(av7110, &tag, 0, buf, length); + if (ret) + printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret); + return ret; +} + + +/**************************************************************************** + * Firmware commands + ****************************************************************************/ + +/* get version of the firmware ROM, RTSL, video ucode and ARM application */ +int av7110_firmversion(struct av7110 *av7110) +{ + u16 buf[20]; + u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion); + + dprintk(4, "%p\n", av7110); + + if (av7110_fw_query(av7110, tag, buf, 16)) { + printk("dvb-ttpci: failed to boot firmware @ card %d\n", + av7110->dvb_adapter.num); + return -EIO; + } + + av7110->arm_fw = (buf[0] << 16) + buf[1]; + av7110->arm_rtsl = (buf[2] << 16) + buf[3]; + av7110->arm_vid = (buf[4] << 16) + buf[5]; + av7110->arm_app = (buf[6] << 16) + buf[7]; + av7110->avtype = (buf[8] << 16) + buf[9]; + + printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n", + av7110->dvb_adapter.num, av7110->arm_fw, + av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app); + + /* print firmware capabilities */ + if (FW_CI_LL_SUPPORT(av7110->arm_app)) + printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n", + av7110->dvb_adapter.num); + else + printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n", + av7110->dvb_adapter.num); + + return 0; +} + + +int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst) +{ + int i, ret; + u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + dprintk(4, "%p\n", av7110); + + if (len > 10) + len = 10; + + buf[1] = len + 2; + buf[2] = len; + + if (burst != -1) + buf[3] = burst ? 0x01 : 0x00; + else + buf[3] = 0xffff; + + for (i = 0; i < len; i++) + buf[i + 4] = msg[i]; + + ret = av7110_send_fw_cmd(av7110, buf, 18); + if (ret && ret!=-ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret); + return ret; +} + + +#ifdef CONFIG_DVB_AV7110_OSD + +static inline int SetColorBlend(struct av7110 *av7110, u8 windownr) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr); +} + +static inline int SetBlend_(struct av7110 *av7110, u8 windownr, + enum av7110_osd_palette_type colordepth, u16 index, u8 blending) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4, + windownr, colordepth, index, blending); +} + +static inline int SetColor_(struct av7110 *av7110, u8 windownr, + enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5, + windownr, colordepth, index, colorhi, colorlo); +} + +static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize, + u16 colorfg, u16 colorbg) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4, + windownr, fontsize, colorfg, colorbg); +} + +static int FlushText(struct av7110 *av7110) +{ + unsigned long start; + int err; + + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", + __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } + mutex_unlock(&av7110->dcomlock); + return 0; +} + +static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf) +{ + int i, ret; + unsigned long start; + int length = strlen(buf) + 1; + u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y }; + + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + + start = jiffies; + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (ret) { + printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", + __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } +#ifndef _NOHANDSHAKE + start = jiffies; + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (ret) { + printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", + __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } +#endif + for (i = 0; i < length / 2; i++) + wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, + swab16(*(u16 *)(buf + 2 * i)), 2); + if (length & 1) + wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2); + ret = __av7110_send_fw_cmd(av7110, cbuf, 5); + mutex_unlock(&av7110->dcomlock); + if (ret && ret!=-ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret); + return ret; +} + +static inline int DrawLine(struct av7110 *av7110, u8 windownr, + u16 x, u16 y, u16 dx, u16 dy, u16 color) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6, + windownr, x, y, dx, dy, color); +} + +static inline int DrawBlock(struct av7110 *av7110, u8 windownr, + u16 x, u16 y, u16 dx, u16 dy, u16 color) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6, + windownr, x, y, dx, dy, color); +} + +static inline int HideWindow(struct av7110 *av7110, u8 windownr) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr); +} + +static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y); +} + +static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y); +} + +static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr); +} + +static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr, + osd_raw_window_t disptype, + u16 width, u16 height) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4, + windownr, disptype, width, height); +} + + +static enum av7110_osd_palette_type bpp2pal[8] = { + Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit +}; +static osd_raw_window_t bpp2bit[8] = { + OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8 +}; + +static inline int WaitUntilBmpLoaded(struct av7110 *av7110) +{ + int ret = wait_event_timeout(av7110->bmpq, + av7110->bmp_state != BMP_LOADING, 10*HZ); + if (ret == 0) { + printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", + ret, av7110->bmp_state); + av7110->bmp_state = BMP_NONE; + return -ETIMEDOUT; + } + return 0; +} + +static inline int LoadBitmap(struct av7110 *av7110, + u16 dx, u16 dy, int inc, u8 __user * data) +{ + u16 format; + int bpp; + int i; + int d, delta; + u8 c; + int ret; + + dprintk(4, "%p\n", av7110); + + format = bpp2bit[av7110->osdbpp[av7110->osdwin]]; + + av7110->bmp_state = BMP_LOADING; + if (format == OSD_BITMAP8) { + bpp=8; delta = 1; + } else if (format == OSD_BITMAP4) { + bpp=4; delta = 2; + } else if (format == OSD_BITMAP2) { + bpp=2; delta = 4; + } else if (format == OSD_BITMAP1) { + bpp=1; delta = 8; + } else { + av7110->bmp_state = BMP_NONE; + return -EINVAL; + } + av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8; + av7110->bmpp = 0; + if (av7110->bmplen > 32768) { + av7110->bmp_state = BMP_NONE; + return -EINVAL; + } + for (i = 0; i < dy; i++) { + if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) { + av7110->bmp_state = BMP_NONE; + return -EINVAL; + } + } + if (format != OSD_BITMAP8) { + for (i = 0; i < dx * dy / delta; i++) { + c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1]; + for (d = delta - 2; d >= 0; d--) { + c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d] + << ((delta - d - 1) * bpp)); + ((u8 *)av7110->bmpbuf)[1024 + i] = c; + } + } + } + av7110->bmplen += 1024; + dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen); + ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); + if (!ret) + ret = WaitUntilBmpLoaded(av7110); + return ret; +} + +static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y) +{ + dprintk(4, "%p\n", av7110); + + return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0); +} + +static inline int ReleaseBitmap(struct av7110 *av7110) +{ + dprintk(4, "%p\n", av7110); + + if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e) + return -1; + if (av7110->bmp_state == BMP_LOADING) + dprintk(1,"ReleaseBitmap called while BMP_LOADING\n"); + av7110->bmp_state = BMP_NONE; + return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0); +} + +static u32 RGB2YUV(u16 R, u16 G, u16 B) +{ + u16 y, u, v; + u16 Y, Cr, Cb; + + y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */ + u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */ + v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */ + + Y = y / 256; + Cb = u / 16; + Cr = v / 16; + + return Cr | (Cb << 16) | (Y << 8); +} + +static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) +{ + int ret; + + u16 ch, cl; + u32 yuv; + + yuv = blend ? RGB2YUV(r,g,b) : 0; + cl = (yuv & 0xffff); + ch = ((yuv >> 16) & 0xffff); + ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ch, cl); + if (!ret) + ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ((blend >> 4) & 0x0f)); + return ret; +} + +static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) +{ + int i; + int length = last - first + 1; + + if (length * 4 > DATA_BUFF3_SIZE) + return -EINVAL; + + for (i = 0; i < length; i++) { + u32 color, blend, yuv; + + if (get_user(color, colors + i)) + return -EFAULT; + blend = (color & 0xF0000000) >> 4; + yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, + (color >> 16) & 0xFF) | blend : 0; + yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); + wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); + } + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, + av7110->osdwin, + bpp2pal[av7110->osdbpp[av7110->osdwin]], + first, last); +} + +static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, + int x1, int y1, int inc, u8 __user * data) +{ + uint w, h, bpp, bpl, size, lpb, bnum, brest; + int i; + int rc,release_rc; + + w = x1 - x0 + 1; + h = y1 - y0 + 1; + if (inc <= 0) + inc = w; + if (w <= 0 || w > 720 || h <= 0 || h > 576) + return -EINVAL; + bpp = av7110->osdbpp[av7110->osdwin] + 1; + bpl = ((w * bpp + 7) & ~7) / 8; + size = h * bpl; + lpb = (32 * 1024) / bpl; + bnum = size / (lpb * bpl); + brest = size - bnum * lpb * bpl; + + if (av7110->bmp_state == BMP_LOADING) { + /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */ + BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e); + rc = WaitUntilBmpLoaded(av7110); + if (rc) + return rc; + /* just continue. This should work for all fw versions + * if bnum==1 && !brest && LoadBitmap was successful + */ + } + + rc = 0; + for (i = 0; i < bnum; i++) { + rc = LoadBitmap(av7110, w, lpb, inc, data); + if (rc) + break; + rc = BlitBitmap(av7110, x0, y0 + i * lpb); + if (rc) + break; + data += lpb * inc; + } + if (!rc && brest) { + rc = LoadBitmap(av7110, w, brest / bpl, inc, data); + if (!rc) + rc = BlitBitmap(av7110, x0, y0 + bnum * lpb); + } + release_rc = ReleaseBitmap(av7110); + if (!rc) + rc = release_rc; + if (rc) + dprintk(1,"returns %d\n",rc); + return rc; +} + +int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc) +{ + int ret; + + if (mutex_lock_interruptible(&av7110->osd_mutex)) + return -ERESTARTSYS; + + switch (dc->cmd) { + case OSD_Close: + ret = DestroyOSDWindow(av7110, av7110->osdwin); + break; + case OSD_Open: + av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7; + ret = CreateOSDWindow(av7110, av7110->osdwin, + bpp2bit[av7110->osdbpp[av7110->osdwin]], + dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; + if (!dc->data) { + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (ret) + break; + ret = SetColorBlend(av7110, av7110->osdwin); + } + break; + case OSD_Show: + ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0); + break; + case OSD_Hide: + ret = HideWindow(av7110, av7110->osdwin); + break; + case OSD_Clear: + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); + break; + case OSD_Fill: + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); + break; + case OSD_SetColor: + ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); + break; + case OSD_SetPalette: + if (FW_VERSION(av7110->arm_app) >= 0x2618) + ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0); + else { + int i, len = dc->x0-dc->color+1; + u8 __user *colors = (u8 __user *)dc->data; + u8 r, g = 0, b = 0, blend = 0; + ret = 0; + for (i = 0; icolor + i, r, g, b, blend); + if (ret) + break; + } + } + break; + case OSD_SetPixel: + ret = DrawLine(av7110, av7110->osdwin, + dc->x0, dc->y0, 0, 0, dc->color); + break; + case OSD_SetRow: + dc->y1 = dc->y0; + /* fall through */ + case OSD_SetBlock: + ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); + break; + case OSD_FillRow: + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + dc->x1-dc->x0+1, dc->y1, dc->color); + break; + case OSD_FillBlock: + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color); + break; + case OSD_Line: + ret = DrawLine(av7110, av7110->osdwin, + dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color); + break; + case OSD_Text: + { + char textbuf[240]; + + if (strncpy_from_user(textbuf, dc->data, 240) < 0) { + ret = -EFAULT; + break; + } + textbuf[239] = 0; + if (dc->x1 > 3) + dc->x1 = 3; + ret = SetFont(av7110, av7110->osdwin, dc->x1, + (u16) (dc->color & 0xffff), (u16) (dc->color >> 16)); + if (!ret) + ret = FlushText(av7110); + if (!ret) + ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); + break; + } + case OSD_SetWindow: + if (dc->x0 < 1 || dc->x0 > 7) + ret = -EINVAL; + else { + av7110->osdwin = dc->x0; + ret = 0; + } + break; + case OSD_MoveWindow: + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); + break; + case OSD_OpenRaw: + if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) { + ret = -EINVAL; + break; + } + if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) + av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1; + else + av7110->osdbpp[av7110->osdwin] = 0; + ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, + dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; + if (!dc->data) { + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); + } + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&av7110->osd_mutex); + if (ret==-ERESTARTSYS) + dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd); + else if (ret) + dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret); + + return ret; +} + +int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap) +{ + switch (cap->cmd) { + case OSD_CAP_MEMSIZE: + if (FW_4M_SDRAM(av7110->arm_app)) + cap->val = 1000000; + else + cap->val = 92000; + return 0; + default: + return -EINVAL; + } +} +#endif /* CONFIG_DVB_AV7110_OSD */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_hw.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_hw.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_hw.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_hw.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,495 @@ +#ifndef _AV7110_HW_H_ +#define _AV7110_HW_H_ + +#include "av7110.h" + +/* DEBI transfer mode defs */ + +#define DEBINOSWAP 0x000e0000 +#define DEBISWAB 0x001e0000 +#define DEBISWAP 0x002e0000 + +#define ARM_WAIT_FREE (HZ) +#define ARM_WAIT_SHAKE (HZ/5) +#define ARM_WAIT_OSD (HZ) + + +enum av7110_bootstate +{ + BOOTSTATE_BUFFER_EMPTY = 0, + BOOTSTATE_BUFFER_FULL = 1, + BOOTSTATE_AV7110_BOOT_COMPLETE = 2 +}; + +enum av7110_type_rec_play_format +{ RP_None, + AudioPES, + AudioMp2, + AudioPCM, + VideoPES, + AV_PES +}; + +enum av7110_osd_palette_type +{ + NoPalet = 0, /* No palette */ + Pal1Bit = 2, /* 2 colors for 1 Bit Palette */ + Pal2Bit = 4, /* 4 colors for 2 bit palette */ + Pal4Bit = 16, /* 16 colors for 4 bit palette */ + Pal8Bit = 256 /* 256 colors for 16 bit palette */ +}; + +/* switch defines */ +#define SB_GPIO 3 +#define SB_OFF SAA7146_GPIO_OUTLO /* SlowBlank off (TV-Mode) */ +#define SB_ON SAA7146_GPIO_INPUT /* SlowBlank on (AV-Mode) */ +#define SB_WIDE SAA7146_GPIO_OUTHI /* SlowBlank 6V (16/9-Mode) (not implemented) */ + +#define FB_GPIO 1 +#define FB_OFF SAA7146_GPIO_LO /* FastBlank off (CVBS-Mode) */ +#define FB_ON SAA7146_GPIO_OUTHI /* FastBlank on (RGB-Mode) */ +#define FB_LOOP SAA7146_GPIO_INPUT /* FastBlank loop-through (PC graphics ???) */ + +enum av7110_video_output_mode +{ + NO_OUT = 0, /* disable analog output */ + CVBS_RGB_OUT = 1, + CVBS_YC_OUT = 2, + YC_OUT = 3 +}; + +/* firmware internal msg q status: */ +#define GPMQFull 0x0001 /* Main Message Queue Full */ +#define GPMQOver 0x0002 /* Main Message Queue Overflow */ +#define HPQFull 0x0004 /* High Priority Msg Queue Full */ +#define HPQOver 0x0008 +#define OSDQFull 0x0010 /* OSD Queue Full */ +#define OSDQOver 0x0020 +#define GPMQBusy 0x0040 /* Queue not empty, FW >= 261d */ +#define HPQBusy 0x0080 +#define OSDQBusy 0x0100 + +/* hw section filter flags */ +#define SECTION_EIT 0x01 +#define SECTION_SINGLE 0x00 +#define SECTION_CYCLE 0x02 +#define SECTION_CONTINUOS 0x04 +#define SECTION_MODE 0x06 +#define SECTION_IPMPE 0x0C /* size up to 4k */ +#define SECTION_HIGH_SPEED 0x1C /* larger buffer */ +#define DATA_PIPING_FLAG 0x20 /* for Data Piping Filter */ + +#define PBUFSIZE_NONE 0x0000 +#define PBUFSIZE_1P 0x0100 +#define PBUFSIZE_2P 0x0200 +#define PBUFSIZE_1K 0x0300 +#define PBUFSIZE_2K 0x0400 +#define PBUFSIZE_4K 0x0500 +#define PBUFSIZE_8K 0x0600 +#define PBUFSIZE_16K 0x0700 +#define PBUFSIZE_32K 0x0800 + + +/* firmware command codes */ +enum av7110_osd_command { + WCreate, + WDestroy, + WMoveD, + WMoveA, + WHide, + WTop, + DBox, + DLine, + DText, + Set_Font, + SetColor, + SetBlend, + SetWBlend, + SetCBlend, + SetNonBlend, + LoadBmp, + BlitBmp, + ReleaseBmp, + SetWTrans, + SetWNoTrans, + Set_Palette +}; + +enum av7110_pid_command { + MultiPID, + VideoPID, + AudioPID, + InitFilt, + FiltError, + NewVersion, + CacheError, + AddPIDFilter, + DelPIDFilter, + Scan, + SetDescr, + SetIR, + FlushTSQueue +}; + +enum av7110_mpeg_command { + SelAudChannels +}; + +enum av7110_audio_command { + AudioDAC, + CabADAC, + ON22K, + OFF22K, + MainSwitch, + ADSwitch, + SendDiSEqC, + SetRegister, + SpdifSwitch +}; + +enum av7110_request_command { + AudioState, + AudioBuffState, + VideoState1, + VideoState2, + VideoState3, + CrashCounter, + ReqVersion, + ReqVCXO, + ReqRegister, + ReqSecFilterError, + ReqSTC +}; + +enum av7110_encoder_command { + SetVidMode, + SetTestMode, + LoadVidCode, + SetMonitorType, + SetPanScanType, + SetFreezeMode, + SetWSSConfig +}; + +enum av7110_rec_play_state { + __Record, + __Stop, + __Play, + __Pause, + __Slow, + __FF_IP, + __Scan_I, + __Continue +}; + +enum av7110_fw_cmd_misc { + AV7110_FW_VIDEO_ZOOM = 1, + AV7110_FW_VIDEO_COMMAND, + AV7110_FW_AUDIO_COMMAND +}; + +enum av7110_command_type { + COMTYPE_NOCOM, + COMTYPE_PIDFILTER, + COMTYPE_MPEGDECODER, + COMTYPE_OSD, + COMTYPE_BMP, + COMTYPE_ENCODER, + COMTYPE_AUDIODAC, + COMTYPE_REQUEST, + COMTYPE_SYSTEM, + COMTYPE_REC_PLAY, + COMTYPE_COMMON_IF, + COMTYPE_PID_FILTER, + COMTYPE_PES, + COMTYPE_TS, + COMTYPE_VIDEO, + COMTYPE_AUDIO, + COMTYPE_CI_LL, + COMTYPE_MISC = 0x80 +}; + +#define VID_NONE_PREF 0x00 /* No aspect ration processing preferred */ +#define VID_PAN_SCAN_PREF 0x01 /* Pan and Scan Display preferred */ +#define VID_VERT_COMP_PREF 0x02 /* Vertical compression display preferred */ +#define VID_VC_AND_PS_PREF 0x03 /* PanScan and vertical Compression if allowed */ +#define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */ + +/* MPEG video decoder commands */ +#define AV_VIDEO_CMD_STOP 0x000e +#define AV_VIDEO_CMD_PLAY 0x000d +#define AV_VIDEO_CMD_FREEZE 0x0102 +#define AV_VIDEO_CMD_FFWD 0x0016 +#define AV_VIDEO_CMD_SLOW 0x0022 + +/* MPEG audio decoder commands */ +#define AUDIO_CMD_MUTE 0x0001 +#define AUDIO_CMD_UNMUTE 0x0002 +#define AUDIO_CMD_PCM16 0x0010 +#define AUDIO_CMD_STEREO 0x0080 +#define AUDIO_CMD_MONO_L 0x0100 +#define AUDIO_CMD_MONO_R 0x0200 +#define AUDIO_CMD_SYNC_OFF 0x000e +#define AUDIO_CMD_SYNC_ON 0x000f + +/* firmware data interface codes */ +#define DATA_NONE 0x00 +#define DATA_FSECTION 0x01 +#define DATA_IPMPE 0x02 +#define DATA_MPEG_RECORD 0x03 +#define DATA_DEBUG_MESSAGE 0x04 +#define DATA_COMMON_INTERFACE 0x05 +#define DATA_MPEG_PLAY 0x06 +#define DATA_BMP_LOAD 0x07 +#define DATA_IRCOMMAND 0x08 +#define DATA_PIPING 0x09 +#define DATA_STREAMING 0x0a +#define DATA_CI_GET 0x0b +#define DATA_CI_PUT 0x0c +#define DATA_MPEG_VIDEO_EVENT 0x0d + +#define DATA_PES_RECORD 0x10 +#define DATA_PES_PLAY 0x11 +#define DATA_TS_RECORD 0x12 +#define DATA_TS_PLAY 0x13 + +/* ancient CI command codes, only two are actually still used + * by the link level CI firmware */ +#define CI_CMD_ERROR 0x00 +#define CI_CMD_ACK 0x01 +#define CI_CMD_SYSTEM_READY 0x02 +#define CI_CMD_KEYPRESS 0x03 +#define CI_CMD_ON_TUNED 0x04 +#define CI_CMD_ON_SWITCH_PROGRAM 0x05 +#define CI_CMD_SECTION_ARRIVED 0x06 +#define CI_CMD_SECTION_TIMEOUT 0x07 +#define CI_CMD_TIME 0x08 +#define CI_CMD_ENTER_MENU 0x09 +#define CI_CMD_FAST_PSI 0x0a +#define CI_CMD_GET_SLOT_INFO 0x0b + +#define CI_MSG_NONE 0x00 +#define CI_MSG_CI_INFO 0x01 +#define CI_MSG_MENU 0x02 +#define CI_MSG_LIST 0x03 +#define CI_MSG_TEXT 0x04 +#define CI_MSG_REQUEST_INPUT 0x05 +#define CI_MSG_INPUT_COMPLETE 0x06 +#define CI_MSG_LIST_MORE 0x07 +#define CI_MSG_MENU_MORE 0x08 +#define CI_MSG_CLOSE_MMI_IMM 0x09 +#define CI_MSG_SECTION_REQUEST 0x0a +#define CI_MSG_CLOSE_FILTER 0x0b +#define CI_PSI_COMPLETE 0x0c +#define CI_MODULE_READY 0x0d +#define CI_SWITCH_PRG_REPLY 0x0e +#define CI_MSG_TEXT_MORE 0x0f + +#define CI_MSG_CA_PMT 0xe0 +#define CI_MSG_ERROR 0xf0 + + +/* base address of the dual ported RAM which serves as communication + * area between PCI bus and av7110, + * as seen by the DEBI bus of the saa7146 */ +#define DPRAM_BASE 0x4000 + +/* boot protocol area */ +#define AV7110_BOOT_STATE (DPRAM_BASE + 0x3F8) +#define AV7110_BOOT_SIZE (DPRAM_BASE + 0x3FA) +#define AV7110_BOOT_BASE (DPRAM_BASE + 0x3FC) +#define AV7110_BOOT_BLOCK (DPRAM_BASE + 0x400) +#define AV7110_BOOT_MAX_SIZE 0xc00 + +/* firmware command protocol area */ +#define IRQ_STATE (DPRAM_BASE + 0x0F4) +#define IRQ_STATE_EXT (DPRAM_BASE + 0x0F6) +#define MSGSTATE (DPRAM_BASE + 0x0F8) +#define COMMAND (DPRAM_BASE + 0x0FC) +#define COM_BUFF (DPRAM_BASE + 0x100) +#define COM_BUFF_SIZE 0x20 + +/* various data buffers */ +#define BUFF1_BASE (DPRAM_BASE + 0x120) +#define BUFF1_SIZE 0xE0 + +#define DATA_BUFF0_BASE (DPRAM_BASE + 0x200) +#define DATA_BUFF0_SIZE 0x0800 + +#define DATA_BUFF1_BASE (DATA_BUFF0_BASE+DATA_BUFF0_SIZE) +#define DATA_BUFF1_SIZE 0x0800 + +#define DATA_BUFF2_BASE (DATA_BUFF1_BASE+DATA_BUFF1_SIZE) +#define DATA_BUFF2_SIZE 0x0800 + +#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE) +#define DATA_BUFF3_SIZE 0x0400 + +#define Reserved (DPRAM_BASE + 0x1E00) +#define Reserved_SIZE 0x1C0 + + +/* firmware status area */ +#define STATUS_BASE (DPRAM_BASE + 0x1FC0) +#define STATUS_LOOPS (STATUS_BASE + 0x08) + +#define STATUS_MPEG_WIDTH (STATUS_BASE + 0x0C) +/* ((aspect_ratio & 0xf) << 12) | (height & 0xfff) */ +#define STATUS_MPEG_HEIGHT_AR (STATUS_BASE + 0x0E) + +/* firmware data protocol area */ +#define RX_TYPE (DPRAM_BASE + 0x1FE8) +#define RX_LEN (DPRAM_BASE + 0x1FEA) +#define TX_TYPE (DPRAM_BASE + 0x1FEC) +#define TX_LEN (DPRAM_BASE + 0x1FEE) + +#define RX_BUFF (DPRAM_BASE + 0x1FF4) +#define TX_BUFF (DPRAM_BASE + 0x1FF6) + +#define HANDSHAKE_REG (DPRAM_BASE + 0x1FF8) +#define COM_IF_LOCK (DPRAM_BASE + 0x1FFA) + +#define IRQ_RX (DPRAM_BASE + 0x1FFC) +#define IRQ_TX (DPRAM_BASE + 0x1FFE) + +/* used by boot protocol to load firmware into av7110 DRAM */ +#define DRAM_START_CODE 0x2e000404 +#define DRAM_MAX_CODE_SIZE 0x00100000 + +/* saa7146 gpio lines */ +#define RESET_LINE 2 +#define DEBI_DONE_LINE 1 +#define ARM_IRQ_LINE 0 + + + +extern int av7110_bootarm(struct av7110 *av7110); +extern int av7110_firmversion(struct av7110 *av7110); +#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000) +#define FW_4M_SDRAM(arm_app) ((arm_app) & 0x40000000) +#define FW_VERSION(arm_app) ((arm_app) & 0x0000FFFF) + +extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags); +extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...); +extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, + int request_buf_len, u16 *reply_buf, int reply_buf_len); + + +/* DEBI (saa7146 data extension bus interface) access */ +extern int av7110_debiwrite(struct av7110 *av7110, u32 config, + int addr, u32 val, int count); +extern u32 av7110_debiread(struct av7110 *av7110, u32 config, + int addr, int count); + + +/* DEBI during interrupt */ +/* single word writes */ +static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +{ + av7110_debiwrite(av7110, config, addr, val, count); +} + +/* buffer writes */ +static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, + const u8 *val, int count) +{ + memcpy(av7110->debi_virt, val, count); + av7110_debiwrite(av7110, config, addr, 0, count); +} + +static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +{ + u32 res; + + res=av7110_debiread(av7110, config, addr, count); + if (count<=4) + memcpy(av7110->debi_virt, (char *) &res, count); + return res; +} + +/* DEBI outside interrupts, only for count <= 4! */ +static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +{ + unsigned long flags; + + spin_lock_irqsave(&av7110->debilock, flags); + av7110_debiwrite(av7110, config, addr, val, count); + spin_unlock_irqrestore(&av7110->debilock, flags); +} + +static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count) +{ + unsigned long flags; + u32 res; + + spin_lock_irqsave(&av7110->debilock, flags); + res=av7110_debiread(av7110, config, addr, count); + spin_unlock_irqrestore(&av7110->debilock, flags); + return res; +} + +/* handle mailbox registers of the dual ported RAM */ +static inline void ARM_ResetMailBox(struct av7110 *av7110) +{ + unsigned long flags; + + spin_lock_irqsave(&av7110->debilock, flags); + av7110_debiread(av7110, DEBINOSWAP, IRQ_RX, 2); + av7110_debiwrite(av7110, DEBINOSWAP, IRQ_RX, 0, 2); + spin_unlock_irqrestore(&av7110->debilock, flags); +} + +static inline void ARM_ClearMailBox(struct av7110 *av7110) +{ + iwdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); +} + +static inline void ARM_ClearIrq(struct av7110 *av7110) +{ + irdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); +} + +/**************************************************************************** + * Firmware commands + ****************************************************************************/ + +static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data) +{ + return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data); +} + +static inline int av7710_set_video_mode(struct av7110 *av7110, int mode) +{ + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); +} + +static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg) +{ + return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4, + (com>>16), (com&0xffff), + (arg>>16), (arg&0xffff)); +} + +static inline int audcom(struct av7110 *av7110, u32 com) +{ + return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2, + (com>>16), (com&0xffff)); +} + +static inline int Set22K(struct av7110 *av7110, int state) +{ + return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0); +} + + +extern int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst); + + +#ifdef CONFIG_DVB_AV7110_OSD +extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc); +extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap); +#endif /* CONFIG_DVB_AV7110_OSD */ + + + +#endif /* _AV7110_HW_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ipack.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ipack.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ipack.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ipack.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,403 @@ +#include "dvb_filter.h" +#include "av7110_ipack.h" +#include /* for memcpy() */ +#include + + +void av7110_ipack_reset(struct ipack *p) +{ + p->found = 0; + p->cid = 0; + p->plength = 0; + p->flag1 = 0; + p->flag2 = 0; + p->hlength = 0; + p->mpeg = 0; + p->check = 0; + p->which = 0; + p->done = 0; + p->count = 0; +} + + +int av7110_ipack_init(struct ipack *p, int size, + void (*func)(u8 *buf, int size, void *priv)) +{ + if (!(p->buf = vmalloc(size*sizeof(u8)))) { + printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); + return -ENOMEM; + } + p->size = size; + p->func = func; + p->repack_subids = 0; + av7110_ipack_reset(p); + return 0; +} + + +void av7110_ipack_free(struct ipack *p) +{ + vfree(p->buf); +} + + +static void send_ipack(struct ipack *p) +{ + int off; + struct dvb_audio_info ai; + int ac3_off = 0; + int streamid = 0; + int nframes = 0; + int f = 0; + + switch (p->mpeg) { + case 2: + if (p->count < 10) + return; + p->buf[3] = p->cid; + p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); + p->buf[5] = (u8)((p->count - 6) & 0x00ff); + if (p->repack_subids && p->cid == PRIVATE_STREAM1) { + off = 9 + p->buf[8]; + streamid = p->buf[off]; + if ((streamid & 0xf8) == 0x80) { + ai.off = 0; + ac3_off = ((p->buf[off + 2] << 8)| + p->buf[off + 3]); + if (ac3_off < p->count) + f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off, + p->count - ac3_off, &ai, 0); + if (!f) { + nframes = (p->count - off - 3 - ac3_off) / + ai.framesize + 1; + p->buf[off + 2] = (ac3_off >> 8) & 0xff; + p->buf[off + 3] = (ac3_off) & 0xff; + p->buf[off + 1] = nframes; + ac3_off += nframes * ai.framesize - p->count; + } + } + } + p->func(p->buf, p->count, p->data); + + p->buf[6] = 0x80; + p->buf[7] = 0x00; + p->buf[8] = 0x00; + p->count = 9; + if (p->repack_subids && p->cid == PRIVATE_STREAM1 + && (streamid & 0xf8) == 0x80) { + p->count += 4; + p->buf[9] = streamid; + p->buf[10] = (ac3_off >> 8) & 0xff; + p->buf[11] = (ac3_off) & 0xff; + p->buf[12] = 0; + } + break; + + case 1: + if (p->count < 8) + return; + p->buf[3] = p->cid; + p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); + p->buf[5] = (u8)((p->count - 6) & 0x00ff); + p->func(p->buf, p->count, p->data); + + p->buf[6] = 0x0f; + p->count = 7; + break; + } +} + + +void av7110_ipack_flush(struct ipack *p) +{ + if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6) + return; + p->plength = p->found - 6; + p->found = 0; + send_ipack(p); + av7110_ipack_reset(p); +} + + +static void write_ipack(struct ipack *p, const u8 *data, int count) +{ + u8 headr[3] = { 0x00, 0x00, 0x01 }; + + if (p->count < 6) { + memcpy(p->buf, headr, 3); + p->count = 6; + } + + if (p->count + count < p->size){ + memcpy(p->buf+p->count, data, count); + p->count += count; + } else { + int rest = p->size - p->count; + memcpy(p->buf+p->count, data, rest); + p->count += rest; + send_ipack(p); + if (count - rest > 0) + write_ipack(p, data + rest, count - rest); + } +} + + +int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p) +{ + int l; + int c = 0; + + while (c < count && (p->mpeg == 0 || + (p->mpeg == 1 && p->found < 7) || + (p->mpeg == 2 && p->found < 9)) + && (p->found < 5 || !p->done)) { + switch (p->found) { + case 0: + case 1: + if (buf[c] == 0x00) + p->found++; + else + p->found = 0; + c++; + break; + case 2: + if (buf[c] == 0x01) + p->found++; + else if (buf[c] == 0) + p->found = 2; + else + p->found = 0; + c++; + break; + case 3: + p->cid = 0; + switch (buf[c]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + p->done = 1; + /* fall through */ + case PRIVATE_STREAM1: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + p->found++; + p->cid = buf[c]; + c++; + break; + default: + p->found = 0; + break; + } + break; + + case 4: + if (count-c > 1) { + p->plen[0] = buf[c]; + c++; + p->plen[1] = buf[c]; + c++; + p->found += 2; + p->plength = (p->plen[0] << 8) | p->plen[1]; + } else { + p->plen[0] = buf[c]; + p->found++; + return count; + } + break; + case 5: + p->plen[1] = buf[c]; + c++; + p->found++; + p->plength = (p->plen[0] << 8) | p->plen[1]; + break; + case 6: + if (!p->done) { + p->flag1 = buf[c]; + c++; + p->found++; + if ((p->flag1 & 0xc0) == 0x80) + p->mpeg = 2; + else { + p->hlength = 0; + p->which = 0; + p->mpeg = 1; + p->flag2 = 0; + } + } + break; + + case 7: + if (!p->done && p->mpeg == 2) { + p->flag2 = buf[c]; + c++; + p->found++; + } + break; + + case 8: + if (!p->done && p->mpeg == 2) { + p->hlength = buf[c]; + c++; + p->found++; + } + break; + } + } + + if (c == count) + return count; + + if (!p->plength) + p->plength = MMAX_PLENGTH - 6; + + if (p->done || ((p->mpeg == 2 && p->found >= 9) || + (p->mpeg == 1 && p->found >= 7))) { + switch (p->cid) { + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case PRIVATE_STREAM1: + if (p->mpeg == 2 && p->found == 9) { + write_ipack(p, &p->flag1, 1); + write_ipack(p, &p->flag2, 1); + write_ipack(p, &p->hlength, 1); + } + + if (p->mpeg == 1 && p->found == 7) + write_ipack(p, &p->flag1, 1); + + if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && + p->found < 14) { + while (c < count && p->found < 14) { + p->pts[p->found - 9] = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + } + if (c == count) + return count; + } + + if (p->mpeg == 1 && p->which < 2000) { + + if (p->found == 7) { + p->check = p->flag1; + p->hlength = 1; + } + + while (!p->which && c < count && + p->check == 0xff){ + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + } + + if (c == count) + return count; + + if ((p->check & 0xc0) == 0x40 && !p->which) { + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + + p->which = 1; + if (c == count) + return count; + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if (c == count) + return count; + } + + if (p->which == 1) { + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if (c == count) + return count; + } + + if ((p->check & 0x30) && p->check != 0xff) { + p->flag2 = (p->check & 0xf0) << 2; + p->pts[0] = p->check; + p->which = 3; + } + + if (c == count) + return count; + if (p->which > 2){ + if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) { + while (c < count && p->which < 7) { + p->pts[p->which - 2] = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if (c == count) + return count; + } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) { + while (c < count && p->which < 12) { + if (p->which < 7) + p->pts[p->which - 2] = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if (c == count) + return count; + } + p->which = 2000; + } + + } + + while (c < count && p->found < p->plength + 6) { + l = count - c; + if (l + p->found > p->plength + 6) + l = p->plength + 6 - p->found; + write_ipack(p, buf + c, l); + p->found += l; + c += l; + } + break; + } + + + if (p->done) { + if (p->found + count - c < p->plength + 6) { + p->found += count - c; + c = count; + } else { + c += p->plength + 6 - p->found; + p->found = p->plength + 6; + } + } + + if (p->plength && p->found == p->plength + 6) { + send_ipack(p); + av7110_ipack_reset(p); + if (c < count) + av7110_ipack_instant_repack(buf + c, count - c, p); + } + } + return count; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ipack.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ipack.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ipack.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ipack.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,12 @@ +#ifndef _AV7110_IPACK_H_ +#define _AV7110_IPACK_H_ + +extern int av7110_ipack_init(struct ipack *p, int size, + void (*func)(u8 *buf, int size, void *priv)); + +extern void av7110_ipack_reset(struct ipack *p); +extern int av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p); +extern void av7110_ipack_free(struct ipack * p); +extern void av7110_ipack_flush(struct ipack *p); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_ir.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,415 @@ +/* + * Driver for the remote control of SAA7146 based AV7110 cards + * + * Copyright (C) 1999-2003 Holger Waechtler + * Copyright (C) 2003-2007 Oliver Endriss + * + * 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, or (at your option) any later version. + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + */ + + +#include +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" + + +#define AV_CNT 4 + +#define IR_RC5 0 +#define IR_RCMM 1 +#define IR_RC5_EXT 2 /* internal only */ + +#define IR_ALL 0xffffffff + +#define UP_TIMEOUT (HZ*7/25) + + +/* Note: enable ir debugging by or'ing debug with 16 */ + +static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM}; +module_param_array(ir_protocol, int, NULL, 0644); +MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)"); + +static int ir_inversion[AV_CNT]; +module_param_array(ir_inversion, int, NULL, 0644); +MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted"); + +static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL }; +module_param_array(ir_device_mask, uint, NULL, 0644); +MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)"); + + +static int av_cnt; +static struct av7110 *av_list[AV_CNT]; + +static u16 default_key_map [256] = { + KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, + KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, + KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + KEY_CHANNELUP, KEY_CHANNELDOWN, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0, + 0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0, + KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0, + KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW, + KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN, + 0, 0, 0, 0, KEY_EPG, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR +}; + + +/* key-up timer */ +static void av7110_emit_keyup(unsigned long parm) +{ + struct infrared *ir = (struct infrared *) parm; + + if (!ir || !test_bit(ir->last_key, ir->input_dev->key)) + return; + + input_report_key(ir->input_dev, ir->last_key, 0); + input_sync(ir->input_dev); +} + + +/* tasklet */ +static void av7110_emit_key(unsigned long parm) +{ + struct infrared *ir = (struct infrared *) parm; + u32 ircom = ir->ir_command; + u8 data; + u8 addr; + u16 toggle; + u16 keycode; + + /* extract device address and data */ + switch (ir->protocol) { + case IR_RC5: /* RC5: 5 bits device address, 6 bits data */ + data = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + toggle = ircom & 0x0800; + break; + + case IR_RCMM: /* RCMM: ? bits device address, ? bits data */ + data = ircom & 0xff; + addr = (ircom >> 8) & 0x1f; + toggle = ircom & 0x8000; + break; + + case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */ + data = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + /* invert 7th data bit for backward compatibility with RC5 keymaps */ + if (!(ircom & 0x1000)) + data |= 0x40; + toggle = ircom & 0x0800; + break; + + default: + printk("%s invalid protocol %x\n", __func__, ir->protocol); + return; + } + + input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); + input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); + + keycode = ir->key_map[data]; + + dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", + __func__, ircom, addr, data, keycode); + + /* check device address */ + if (!(ir->device_mask & (1 << addr))) + return; + + if (!keycode) { + printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", + __func__, ircom, addr, data); + return; + } + + if (timer_pending(&ir->keyup_timer)) { + del_timer(&ir->keyup_timer); + if (ir->last_key != keycode || toggle != ir->last_toggle) { + ir->delay_timer_finished = 0; + input_event(ir->input_dev, EV_KEY, ir->last_key, 0); + input_event(ir->input_dev, EV_KEY, keycode, 1); + input_sync(ir->input_dev); + } else if (ir->delay_timer_finished) { + input_event(ir->input_dev, EV_KEY, keycode, 2); + input_sync(ir->input_dev); + } + } else { + ir->delay_timer_finished = 0; + input_event(ir->input_dev, EV_KEY, keycode, 1); + input_sync(ir->input_dev); + } + + ir->last_key = keycode; + ir->last_toggle = toggle; + + ir->keyup_timer.expires = jiffies + UP_TIMEOUT; + add_timer(&ir->keyup_timer); + +} + + +/* register with input layer */ +static void input_register_keys(struct infrared *ir) +{ + int i; + + set_bit(EV_KEY, ir->input_dev->evbit); + set_bit(EV_REP, ir->input_dev->evbit); + set_bit(EV_MSC, ir->input_dev->evbit); + + set_bit(MSC_RAW, ir->input_dev->mscbit); + set_bit(MSC_SCAN, ir->input_dev->mscbit); + + memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); + + for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { + if (ir->key_map[i] > KEY_MAX) + ir->key_map[i] = 0; + else if (ir->key_map[i] > KEY_RESERVED) + set_bit(ir->key_map[i], ir->input_dev->keybit); + } + + ir->input_dev->keycode = ir->key_map; + ir->input_dev->keycodesize = sizeof(ir->key_map[0]); + ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); +} + + +/* called by the input driver after rep[REP_DELAY] ms */ +static void input_repeat_key(unsigned long parm) +{ + struct infrared *ir = (struct infrared *) parm; + + ir->delay_timer_finished = 1; +} + + +/* check for configuration changes */ +int av7110_check_ir_config(struct av7110 *av7110, int force) +{ + int i; + int modified = force; + int ret = -ENODEV; + + for (i = 0; i < av_cnt; i++) + if (av7110 == av_list[i]) + break; + + if (i < av_cnt && av7110) { + if ((av7110->ir.protocol & 1) != ir_protocol[i] || + av7110->ir.inversion != ir_inversion[i]) + modified = true; + + if (modified) { + /* protocol */ + if (ir_protocol[i]) { + ir_protocol[i] = 1; + av7110->ir.protocol = IR_RCMM; + av7110->ir.ir_config = 0x0001; + } else if (FW_VERSION(av7110->arm_app) >= 0x2620) { + av7110->ir.protocol = IR_RC5_EXT; + av7110->ir.ir_config = 0x0002; + } else { + av7110->ir.protocol = IR_RC5; + av7110->ir.ir_config = 0x0000; + } + /* inversion */ + if (ir_inversion[i]) { + ir_inversion[i] = 1; + av7110->ir.ir_config |= 0x8000; + } + av7110->ir.inversion = ir_inversion[i]; + /* update ARM */ + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, + av7110->ir.ir_config); + } else + ret = 0; + + /* address */ + if (av7110->ir.device_mask != ir_device_mask[i]) + av7110->ir.device_mask = ir_device_mask[i]; + } + + return ret; +} + + +/* /proc/av7110_ir interface */ +static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + char *page; + u32 ir_config; + int size = sizeof ir_config + sizeof av_list[0]->ir.key_map; + int i; + + if (count < size) + return -EINVAL; + + page = vmalloc(size); + if (!page) + return -ENOMEM; + + if (copy_from_user(page, buffer, size)) { + vfree(page); + return -EFAULT; + } + + memcpy(&ir_config, page, sizeof ir_config); + + for (i = 0; i < av_cnt; i++) { + /* keymap */ + memcpy(av_list[i]->ir.key_map, page + sizeof ir_config, + sizeof(av_list[i]->ir.key_map)); + /* protocol, inversion, address */ + ir_protocol[i] = ir_config & 0x0001; + ir_inversion[i] = ir_config & 0x8000 ? 1 : 0; + if (ir_config & 0x4000) + ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f); + else + ir_device_mask[i] = IR_ALL; + /* update configuration */ + av7110_check_ir_config(av_list[i], false); + input_register_keys(&av_list[i]->ir); + } + vfree(page); + return count; +} + +static const struct file_operations av7110_ir_proc_fops = { + .owner = THIS_MODULE, + .write = av7110_ir_proc_write, + .llseek = noop_llseek, +}; + +/* interrupt handler */ +static void ir_handler(struct av7110 *av7110, u32 ircom) +{ + dprintk(4, "ir command = %08x\n", ircom); + av7110->ir.ir_command = ircom; + tasklet_schedule(&av7110->ir.ir_tasklet); +} + + +int __devinit av7110_ir_init(struct av7110 *av7110) +{ + struct input_dev *input_dev; + static struct proc_dir_entry *e; + int err; + + if (av_cnt >= ARRAY_SIZE(av_list)) + return -ENOSPC; + + av_list[av_cnt++] = av7110; + av7110_check_ir_config(av7110, true); + + init_timer(&av7110->ir.keyup_timer); + av7110->ir.keyup_timer.function = av7110_emit_keyup; + av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + av7110->ir.input_dev = input_dev; + snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), + "pci-%s/ir0", pci_name(av7110->dev->pci)); + + input_dev->name = "DVB on-card IR receiver"; + + input_dev->phys = av7110->ir.input_phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 2; + if (av7110->dev->pci->subsystem_vendor) { + input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; + input_dev->id.product = av7110->dev->pci->subsystem_device; + } else { + input_dev->id.vendor = av7110->dev->pci->vendor; + input_dev->id.product = av7110->dev->pci->device; + } + input_dev->dev.parent = &av7110->dev->pci->dev; + /* initial keymap */ + memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); + input_register_keys(&av7110->ir); + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } + input_dev->timer.function = input_repeat_key; + input_dev->timer.data = (unsigned long) &av7110->ir; + + if (av_cnt == 1) { + e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops); + if (e) + e->size = 4 + 256 * sizeof(u16); + } + + tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir); + av7110->ir.ir_handler = ir_handler; + + return 0; +} + + +void __devexit av7110_ir_exit(struct av7110 *av7110) +{ + int i; + + if (av_cnt == 0) + return; + + del_timer_sync(&av7110->ir.keyup_timer); + av7110->ir.ir_handler = NULL; + tasklet_kill(&av7110->ir.ir_tasklet); + + for (i = 0; i < av_cnt; i++) + if (av_list[i] == av7110) { + av_list[i] = av_list[av_cnt-1]; + av_list[av_cnt-1] = NULL; + break; + } + + if (av_cnt == 1) + remove_proc_entry("av7110_ir", NULL); + + input_unregister_device(av7110->ir.input_dev); + + av_cnt--; +} + +//MODULE_AUTHOR("Holger Waechtler , Oliver Endriss "); +//MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_v4l.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_v4l.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_v4l.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/av7110_v4l.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,932 @@ +/* + * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss + * + * 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, or (at your option) any later version. + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include +#include +#include +#include +#include +#include + +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_av.h" + +int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) +{ + u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; + struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg }; + + switch (av7110->adac_type) { + case DVB_ADAC_MSP34x0: + msgs.addr = 0x40; + break; + case DVB_ADAC_MSP34x5: + msgs.addr = 0x42; + break; + default: + return 0; + } + + if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { + dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", + av7110->dvb_adapter.num, reg, val); + return -EIO; + } + return 0; +} + +static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) +{ + u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; + u8 msg2[2]; + struct i2c_msg msgs[2] = { + { .flags = 0 , .len = 3, .buf = msg1 }, + { .flags = I2C_M_RD, .len = 2, .buf = msg2 } + }; + + switch (av7110->adac_type) { + case DVB_ADAC_MSP34x0: + msgs[0].addr = 0x40; + msgs[1].addr = 0x40; + break; + case DVB_ADAC_MSP34x5: + msgs[0].addr = 0x42; + msgs[1].addr = 0x42; + break; + default: + return 0; + } + + if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { + dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", + av7110->dvb_adapter.num, reg); + return -EIO; + } + *val = (msg2[0] << 8) | msg2[1]; + return 0; +} + +static struct v4l2_input inputs[4] = { + { + .index = 0, + .name = "DVB", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, /* ignored */ + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + }, { + .index = 1, + .name = "Television", + .type = V4L2_INPUT_TYPE_TUNER, + .audioset = 2, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + }, { + .index = 2, + .name = "Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + }, { + .index = 3, + .name = "Y/C", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + } +}; + +static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) +{ + struct av7110 *av7110 = dev->ext_priv; + u8 buf[] = { 0x00, reg, data }; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; + + dprintk(4, "dev: %p\n", dev); + + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) + return -1; + return 0; +} + +static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) +{ + struct av7110 *av7110 = dev->ext_priv; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; + + dprintk(4, "dev: %p\n", dev); + + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) + return -1; + return 0; +} + +static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq) +{ + u32 div; + u8 config; + u8 buf[4]; + + dprintk(4, "freq: 0x%08x\n", freq); + + /* magic number: 614. tuning with the frequency given by v4l2 + is always off by 614*62.5 = 38375 kHz...*/ + div = freq + 614; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x8e; + + if (freq < (u32) (16 * 168.25)) + config = 0xa0; + else if (freq < (u32) (16 * 447.25)) + config = 0x90; + else + config = 0x30; + config &= ~0x02; + + buf[3] = config; + + return tuner_write(dev, 0x61, buf); +} + +static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq) +{ + struct av7110 *av7110 = (struct av7110*)dev->ext_priv; + u32 div; + u8 data[4]; + + div = (freq + 38900000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xce; + + if (freq < 45000000) + return -EINVAL; + else if (freq < 137000000) + data[3] = 0x01; + else if (freq < 403000000) + data[3] = 0x02; + else if (freq < 860000000) + data[3] = 0x04; + else + return -EINVAL; + + if (av7110->fe->ops.i2c_gate_ctrl) + av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1); + return tuner_write(dev, 0x63, data); +} + + + +static struct saa7146_standard analog_standard[]; +static struct saa7146_standard dvb_standard[]; +static struct saa7146_standard standard[]; + +static struct v4l2_audio msp3400_v4l2_audio = { + .index = 0, + .name = "Television", + .capability = V4L2_AUDCAP_STEREO +}; + +static int av7110_dvb_c_switch(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct av7110 *av7110 = (struct av7110*)dev->ext_priv; + u16 adswitch; + int source, sync, err; + + dprintk(4, "%p\n", av7110); + + if ((vv->video_status & STATUS_OVERLAY) != 0) { + vv->ov_suspend = vv->video_fh; + err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ + if (err != 0) { + dprintk(2, "suspending video failed\n"); + vv->ov_suspend = NULL; + } + } + + if (0 != av7110->current_input) { + dprintk(1, "switching to analog TV:\n"); + adswitch = 1; + source = SAA7146_HPS_SOURCE_PORT_B; + sync = SAA7146_HPS_SYNC_PORT_B; + memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2); + + switch (av7110->current_input) { + case 1: + dprintk(1, "switching SAA7113 to Analog Tuner Input.\n"); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume + + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) + dprintk(1, "setting band in demodulator failed.\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF) + } + if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 2: + dprintk(1, "switching SAA7113 to Video AV CVBS Input.\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 3: + dprintk(1, "switching SAA7113 to Video AV Y/C Input.\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + default: + dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input.\n"); + } + } else { + adswitch = 0; + source = SAA7146_HPS_SOURCE_PORT_A; + sync = SAA7146_HPS_SYNC_PORT_A; + memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); + dprintk(1, "switching DVB mode\n"); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume + + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(dev, 0x09, 0x0f, 0x20)) + dprintk(1, "setting band in demodulator failed.\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) + } + } + + /* hmm, this does not do anything!? */ + if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch)) + dprintk(1, "ADSwitch error\n"); + + saa7146_set_hps_source_and_sync(dev, source, sync); + + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } + + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + u16 stereo_det; + s8 stereo; + + dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index); + + if (!av7110->analog_tuner_flags || t->index != 0) + return -EINVAL; + + memset(t, 0, sizeof(*t)); + strcpy((char *)t->name, "Television"); + + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ + t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ + /* FIXME: add the real signal strength here */ + t->signal = 0xffff; + t->afc = 0; + + /* FIXME: standard / stereo detection is still broken */ + msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); + dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); + msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); + dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); + stereo = (s8)(stereo_det >> 8); + if (stereo > 0x10) { + /* stereo */ + t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; + t->audmode = V4L2_TUNER_MODE_STEREO; + } else if (stereo < -0x10) { + /* bilingual */ + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1; + } else /* mono */ + t->rxsubchans = V4L2_TUNER_SUB_MONO; + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + u16 fm_matrix, src; + dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index); + + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; + + switch (t->audmode) { + case V4L2_TUNER_MODE_STEREO: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"); + fm_matrix = 0x3001; /* stereo */ + src = 0x0020; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"); + fm_matrix = 0x3000; /* bilingual */ + src = 0x0020; + break; + case V4L2_TUNER_MODE_LANG1: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0000; + break; + case V4L2_TUNER_MODE_LANG2: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0010; + break; + default: /* case V4L2_TUNER_MODE_MONO: */ + dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0030; + break; + } + msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, src); + msp_writereg(av7110, MSP_WR_DSP, 0x0009, src); + msp_writereg(av7110, MSP_WR_DSP, 0x000a, src); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency); + + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; + + memset(f, 0, sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = av7110->current_freq; + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency); + + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; + + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */ + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0); + + /* tune in desired frequency */ + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) + ves1820_set_tv_freq(dev, f->frequency); + else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) + stv0297_set_tv_freq(dev, f->frequency); + av7110->current_freq = f->frequency; + + msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */ + msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */ + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */ + return 0; +} + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); + + if (av7110->analog_tuner_flags) { + if (i->index >= 4) + return -EINVAL; + } else { + if (i->index != 0) + return -EINVAL; + } + + memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); + + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + *input = av7110->current_input; + dprintk(2, "VIDIOC_G_INPUT: %d\n", *input); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_INPUT: %d\n", input); + + if (!av7110->analog_tuner_flags) + return 0; + + if (input >= 4) + return -EINVAL; + + av7110->current_input = input; + return av7110_dvb_c_switch(fh); +} + +static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); + if (a->index != 0) + return -EINVAL; + memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio)); + return 0; +} + +static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); + return 0; +} + +static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_sliced_vbi_cap *cap) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); + if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) + return -EINVAL; + if (FW_VERSION(av7110->arm_app) >= 0x2623) { + cap->service_set = V4L2_SLICED_WSS_625; + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; + } + return 0; +} + +static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_FMT:\n"); + if (FW_VERSION(av7110->arm_app) < 0x2623) + return -EINVAL; + memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); + if (av7110->wssMode) { + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); + } + return 0; +} + +static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_FMT\n"); + if (FW_VERSION(av7110->arm_app) < 0x2623) + return -EINVAL; + if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && + f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { + memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); + /* WSS controlled by firmware */ + av7110->wssMode = 0; + av7110->wssData = 0; + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, + SetWSSConfig, 1, 0); + } else { + memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); + /* WSS controlled by userspace */ + av7110->wssMode = 1; + av7110->wssData = 0; + } + return 0; +} + +static int av7110_vbi_reset(struct file *file) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + + dprintk(2, "%s\n", __func__); + av7110->wssMode = 0; + av7110->wssData = 0; + if (FW_VERSION(av7110->arm_app) < 0x2623) + return 0; + else + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0); +} + +static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + struct v4l2_sliced_vbi_data d; + int rc; + + dprintk(2, "%s\n", __func__); + if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d) + return -EINVAL; + if (copy_from_user(&d, data, count)) + return -EFAULT; + if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23) + return -EINVAL; + if (d.id) + av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0]; + else + av7110->wssData = 0x8000; + rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData); + return (rc < 0) ? rc : count; +} + +/**************************************************************************** + * INITIALIZATION + ****************************************************************************/ + +static u8 saa7113_init_regs[] = { + 0x02, 0xd0, + 0x03, 0x23, + 0x04, 0x00, + 0x05, 0x00, + 0x06, 0xe9, + 0x07, 0x0d, + 0x08, 0x98, + 0x09, 0x02, + 0x0a, 0x80, + 0x0b, 0x40, + 0x0c, 0x40, + 0x0d, 0x00, + 0x0e, 0x01, + 0x0f, 0x7c, + 0x10, 0x48, + 0x11, 0x0c, + 0x12, 0x8b, + 0x13, 0x1a, + 0x14, 0x00, + 0x15, 0x00, + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1b, 0x00, + 0x1c, 0x00, + 0x1d, 0x00, + 0x1e, 0x00, + + 0x41, 0x77, + 0x42, 0x77, + 0x43, 0x77, + 0x44, 0x77, + 0x45, 0x77, + 0x46, 0x77, + 0x47, 0x77, + 0x48, 0x77, + 0x49, 0x77, + 0x4a, 0x77, + 0x4b, 0x77, + 0x4c, 0x77, + 0x4d, 0x77, + 0x4e, 0x77, + 0x4f, 0x77, + 0x50, 0x77, + 0x51, 0x77, + 0x52, 0x77, + 0x53, 0x77, + 0x54, 0x77, + 0x55, 0x77, + 0x56, 0x77, + 0x57, 0xff, + + 0xff +}; + + +static struct saa7146_ext_vv av7110_vv_data_st; +static struct saa7146_ext_vv av7110_vv_data_c; + +int av7110_init_analog_module(struct av7110 *av7110) +{ + u16 version1, version2; + + if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 && + i2c_writereg(av7110, 0x80, 0x0, 0) == 1) { + printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x0; + } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 && + i2c_writereg(av7110, 0x84, 0x0, 0) == 1) { + printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x5; + } else + return -ENODEV; + + msleep(100); // the probing above resets the msp... + msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); + msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); + dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n", + av7110->dvb_adapter.num, version1, version2); + msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume + msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART + + if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { + INFO(("saa7113 not accessible.\n")); + } else { + u8 *i = saa7113_init_regs; + + if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { + /* Fujitsu/Siemens DVB-Cable */ + av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; + } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) { + /* Hauppauge/TT DVB-C premium */ + av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; + } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) { + /* Hauppauge/TT DVB-C premium */ + av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297; + } + + /* setup for DVB by default */ + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20)) + dprintk(1, "setting band in demodulator failed.\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) + } + + /* init the saa7113 */ + while (*i != 0xff) { + if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) { + dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num); + break; + } + i += 2; + } + /* setup msp for analog sound: B/G Dual-FM */ + msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 3); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 4); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 0); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 3); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG + msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz + msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI + msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz + msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI + msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2 + } + + memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); + /* set dd1 stream a & b */ + saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); + saa7146_write(av7110->dev, DD1_INIT, 0x03000700); + saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + return 0; +} + +int av7110_init_v4l(struct av7110 *av7110) +{ + struct saa7146_dev* dev = av7110->dev; + struct saa7146_ext_vv *vv_data; + int ret; + + /* special case DVB-C: these cards have an analog tuner + plus need some special handling, so we have separate + saa7146_ext_vv data for these... */ + if (av7110->analog_tuner_flags) + vv_data = &av7110_vv_data_c; + else + vv_data = &av7110_vv_data_st; + ret = saa7146_vv_init(dev, vv_data); + + if (ret) { + ERR(("cannot init capture device. skipping.\n")); + return -ENODEV; + } + vv_data->ops.vidioc_enum_input = vidioc_enum_input; + vv_data->ops.vidioc_g_input = vidioc_g_input; + vv_data->ops.vidioc_s_input = vidioc_s_input; + vv_data->ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data->ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data->ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data->ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data->ops.vidioc_g_audio = vidioc_g_audio; + vv_data->ops.vidioc_s_audio = vidioc_s_audio; + vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; + vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; + vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; + + if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { + ERR(("cannot register capture device. skipping.\n")); + saa7146_vv_release(dev); + return -ENODEV; + } + if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) + ERR(("cannot register vbi v4l2 device. skipping.\n")); + return 0; +} + +int av7110_exit_v4l(struct av7110 *av7110) +{ + struct saa7146_dev* dev = av7110->dev; + + saa7146_unregister_device(&av7110->v4l_dev, av7110->dev); + saa7146_unregister_device(&av7110->vbi_dev, av7110->dev); + + saa7146_vv_release(dev); + + return 0; +} + + + +/* FIXME: these values are experimental values that look better than the + values from the latest "official" driver -- at least for me... (MiHu) */ +static struct saa7146_standard standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL_BG, + .v_offset = 0x15, .v_field = 288, + .h_offset = 0x48, .h_pixels = 708, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x10, .v_field = 244, + .h_offset = 0x40, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + } +}; + +static struct saa7146_standard analog_standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL_BG, + .v_offset = 0x1b, .v_field = 288, + .h_offset = 0x08, .h_pixels = 708, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x10, .v_field = 244, + .h_offset = 0x40, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + } +}; + +static struct saa7146_standard dvb_standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL_BG, + .v_offset = 0x14, .v_field = 288, + .h_offset = 0x48, .h_pixels = 708, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x10, .v_field = 244, + .h_offset = 0x40, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + } +}; + +static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) +{ + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + + if (std->id & V4L2_STD_PAL) { + av7110->vidmode = AV7110_VIDEO_MODE_PAL; + av7110_set_vidmode(av7110, av7110->vidmode); + } + else if (std->id & V4L2_STD_NTSC) { + av7110->vidmode = AV7110_VIDEO_MODE_NTSC; + av7110_set_vidmode(av7110, av7110->vidmode); + } + else + return -1; + + return 0; +} + + +static struct saa7146_ext_vv av7110_vv_data_st = { + .inputs = 1, + .audios = 1, + .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT, + .flags = 0, + + .stds = &standard[0], + .num_stds = ARRAY_SIZE(standard), + .std_callback = &std_callback, + + .vbi_fops.open = av7110_vbi_reset, + .vbi_fops.release = av7110_vbi_reset, + .vbi_fops.write = av7110_vbi_write, +}; + +static struct saa7146_ext_vv av7110_vv_data_c = { + .inputs = 1, + .audios = 1, + .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT, + .flags = SAA7146_USE_PORT_B_FOR_VBI, + + .stds = &standard[0], + .num_stds = ARRAY_SIZE(standard), + .std_callback = &std_callback, + + .vbi_fops.open = av7110_vbi_reset, + .vbi_fops.release = av7110_vbi_reset, + .vbi_fops.write = av7110_vbi_write, +}; + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-av.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-av.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-av.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-av.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1635 @@ +/* + * budget-av.c: driver for the SAA7146 based Budget DVB cards + * with analog video in + * + * Compiled from various sources by Michael Hunold + * + * CI interface support (c) 2004 Olivier Gournet & + * Andrew de Quincey + * + * Copyright (C) 2002 Ralph Metzler + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include "budget.h" +#include "stv0299.h" +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +#include "tda8261.h" +#include "tda8261_cfg.h" +#include "tda1002x.h" +#include "tda1004x.h" +#include "tua6100.h" +#include "dvb-pll.h" +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_ca_en50221.h" + +#define DEBICICAM 0x02420000 + +#define SLOTSTATUS_NONE 1 +#define SLOTSTATUS_PRESENT 2 +#define SLOTSTATUS_RESET 4 +#define SLOTSTATUS_READY 8 +#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct budget_av { + struct budget budget; + struct video_device *vd; + int cur_input; + int has_saa7113; + struct tasklet_struct ciintf_irq_tasklet; + int slot_status; + struct dvb_ca_en50221 ca; + u8 reinitialise_demod:1; +}; + +static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); + + +/* GPIO Connections: + * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! + * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory + * 2 - CI Card Enable (Active Low) + * 3 - CI Card Detect + */ + +/**************************************************************************** + * INITIALIZATION + ****************************************************************************/ + +static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg) +{ + u8 mm1[] = { 0x00 }; + u8 mm2[] = { 0x00 }; + struct i2c_msg msgs[2]; + + msgs[0].flags = 0; + msgs[1].flags = I2C_M_RD; + msgs[0].addr = msgs[1].addr = id / 2; + mm1[0] = reg; + msgs[0].len = 1; + msgs[1].len = 1; + msgs[0].buf = mm1; + msgs[1].buf = mm2; + + i2c_transfer(i2c, msgs, 2); + + return mm2[0]; +} + +static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len) +{ + u8 mm1[] = { reg }; + struct i2c_msg msgs[2] = { + {.addr = id / 2,.flags = 0,.buf = mm1,.len = 1}, + {.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len} + }; + + if (i2c_transfer(i2c, msgs, 2) != 2) + return -EIO; + + return 0; +} + +static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val) +{ + u8 msg[2] = { reg, val }; + struct i2c_msg msgs; + + msgs.flags = 0; + msgs.addr = id / 2; + msgs.len = 2; + msgs.buf = msg; + return i2c_transfer(i2c, &msgs, 1); +} + +static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); + udelay(1); + + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 1\n"); + } + return result; +} + +static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); + udelay(1); + + result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 2\n"); + } + return result; +} + +static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + udelay(1); + + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 3\n"); + return -ETIMEDOUT; + } + return result; +} + +static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + udelay(1); + + result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 5\n"); + } + return result; +} + +static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + + if (slot != 0) + return -EINVAL; + + dprintk(1, "ciintf_slot_reset\n"); + budget_av->slot_status = SLOTSTATUS_RESET; + + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ + + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ + msleep(2); + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */ + msleep(20); /* 20 ms Vcc settling time */ + + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + msleep(20); + + /* reinitialise the frontend if necessary */ + if (budget_av->reinitialise_demod) + dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); + + return 0; +} + +static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + + if (slot != 0) + return -EINVAL; + + dprintk(1, "ciintf_slot_shutdown\n"); + + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + budget_av->slot_status = SLOTSTATUS_NONE; + + return 0; +} + +static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + + if (slot != 0) + return -EINVAL; + + dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); + + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); + + return 0; +} + +static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + int result; + + if (slot != 0) + return -EINVAL; + + /* test the card detect line - needs to be done carefully + * since it never goes high for some CAMs on this interface (e.g. topuptv) */ + if (budget_av->slot_status == SLOTSTATUS_NONE) { + saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); + udelay(1); + if (saa7146_read(saa, PSR) & MASK_06) { + if (budget_av->slot_status == SLOTSTATUS_NONE) { + budget_av->slot_status = SLOTSTATUS_PRESENT; + printk(KERN_INFO "budget-av: cam inserted A\n"); + } + } + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + } + + /* We also try and read from IO memory to work round the above detection bug. If + * there is no CAM, we will get a timeout. Only done if there is no cam + * present, since this test actually breaks some cams :( + * + * if the CI interface is not open, we also do the above test since we + * don't care if the cam has problems - we'll be resetting it on open() anyway */ + if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) { + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1); + if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) { + budget_av->slot_status = SLOTSTATUS_PRESENT; + printk(KERN_INFO "budget-av: cam inserted B\n"); + } else if (result < 0) { + if (budget_av->slot_status != SLOTSTATUS_NONE) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 5\n"); + return 0; + } + } + } + + /* read from attribute memory in reset/ready state to know when the CAM is ready */ + if (budget_av->slot_status == SLOTSTATUS_RESET) { + result = ciintf_read_attribute_mem(ca, slot, 0); + if (result == 0x1d) { + budget_av->slot_status = SLOTSTATUS_READY; + } + } + + /* work out correct return code */ + if (budget_av->slot_status != SLOTSTATUS_NONE) { + if (budget_av->slot_status & SLOTSTATUS_READY) { + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + } + return DVB_CA_EN50221_POLL_CAM_PRESENT; + } + return 0; +} + +static int ciintf_init(struct budget_av *budget_av) +{ + struct saa7146_dev *saa = budget_av->budget.dev; + int result; + + memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221)); + + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + + /* Enable DEBI pins */ + saa7146_write(saa, MC1, MASK_27 | MASK_11); + + /* register CI interface */ + budget_av->ca.owner = THIS_MODULE; + budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem; + budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem; + budget_av->ca.read_cam_control = ciintf_read_cam_control; + budget_av->ca.write_cam_control = ciintf_write_cam_control; + budget_av->ca.slot_reset = ciintf_slot_reset; + budget_av->ca.slot_shutdown = ciintf_slot_shutdown; + budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; + budget_av->ca.poll_slot_status = ciintf_poll_slot_status; + budget_av->ca.data = budget_av; + budget_av->budget.ci_present = 1; + budget_av->slot_status = SLOTSTATUS_NONE; + + if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, + &budget_av->ca, 0, 1)) != 0) { + printk(KERN_ERR "budget-av: ci initialisation failed.\n"); + goto error; + } + + printk(KERN_INFO "budget-av: ci interface initialised.\n"); + return 0; + +error: + saa7146_write(saa, MC1, MASK_27); + return result; +} + +static void ciintf_deinit(struct budget_av *budget_av) +{ + struct saa7146_dev *saa = budget_av->budget.dev; + + saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); + saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); + saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); + saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); + + /* release the CA device */ + dvb_ca_en50221_release(&budget_av->ca); + + /* disable DEBI pins */ + saa7146_write(saa, MC1, MASK_27); +} + + +static const u8 saa7113_tab[] = { + 0x01, 0x08, + 0x02, 0xc0, + 0x03, 0x33, + 0x04, 0x00, + 0x05, 0x00, + 0x06, 0xeb, + 0x07, 0xe0, + 0x08, 0x28, + 0x09, 0x00, + 0x0a, 0x80, + 0x0b, 0x47, + 0x0c, 0x40, + 0x0d, 0x00, + 0x0e, 0x01, + 0x0f, 0x44, + + 0x10, 0x08, + 0x11, 0x0c, + 0x12, 0x7b, + 0x13, 0x00, + 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, + + 0x57, 0xff, + 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07, + 0x5b, 0x83, 0x5e, 0x00, + 0xff +}; + +static int saa7113_init(struct budget_av *budget_av) +{ + struct budget *budget = &budget_av->budget; + struct saa7146_dev *saa = budget->dev; + const u8 *data = saa7113_tab; + + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); + msleep(200); + + if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) { + dprintk(1, "saa7113 not found on KNC card\n"); + return -ENODEV; + } + + dprintk(1, "saa7113 detected and initializing\n"); + + while (*data != 0xff) { + i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1)); + data += 2; + } + + dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f)); + + return 0; +} + +static int saa7113_setinput(struct budget_av *budget_av, int input) +{ + struct budget *budget = &budget_av->budget; + + if (1 != budget_av->has_saa7113) + return -ENODEV; + + if (input == 1) { + i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7); + i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80); + } else if (input == 0) { + i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0); + i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00); + } else + return -EINVAL; + + budget_av->cur_input = input; + return 0; +} + + +static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + u8 m1; + + aclk = 0xb5; + if (srate < 2000000) + bclk = 0x86; + else if (srate < 5000000) + bclk = 0x89; + else if (srate < 15000000) + bclk = 0x8f; + else if (srate < 45000000) + bclk = 0x95; + + m1 = 0x14; + if (srate < 4000000) + m1 = 0x10; + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + stv0299_writereg(fe, 0x0f, 0x80 | m1); + + return 0; +} + +static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + u32 div; + u8 buf[4]; + struct budget *budget = (struct budget *) fe->dvb->priv; + struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + buf[3] = 0x20; + + if (params->u.qpsk.symbol_rate < 4000000) + buf[3] |= 1; + + if (params->frequency < 1250000) + buf[3] |= 0; + else if (params->frequency < 1550000) + buf[3] |= 0x40; + else if (params->frequency < 2050000) + buf[3] |= 0x80; + else if (params->frequency < 2150000) + buf[3] |= 0xC0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static u8 typhoon_cinergy1200s_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x92, + 0xff, 0xff +}; + +static struct stv0299_config typhoon_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, +}; + + +static struct stv0299_config cinergy_1200s_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_0, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, +}; + +static struct stv0299_config cinergy_1200s_1894_0010_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, +}; + +static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + u8 buf[6]; + struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; + int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + + u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0xce; + buf[3] = (params->frequency < 150000000 ? 0x01 : + params->frequency < 445000000 ? 0x02 : 0x04); + buf[4] = 0xde; + buf[5] = 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + + /* wait for the pll lock */ + msg.flags = I2C_M_RD; + msg.len = 1; + for (i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40)) + break; + msleep(10); + } + + /* switch the charge pump to the lower current */ + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[2]; + buf[2] &= ~0x40; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static struct tda1002x_config philips_cu1216_config = { + .demod_address = 0x0c, + .invert = 1, +}; + +static struct tda1002x_config philips_cu1216_config_altaddress = { + .demod_address = 0x0d, + .invert = 0, +}; + +static struct tda10023_config philips_cu1216_tda10023_config = { + .demod_address = 0x0c, + .invert = 1, +}; + +static int philips_tu1216_tuner_init(struct dvb_frontend *fe) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; + + // setup PLL configuration + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + + return 0; +} + +static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = + sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36166000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) + cp = 3; + else if (tuner_frequency < 160000000) + cp = 5; + else if (tuner_frequency < 200000000) + cp = 6; + else if (tuner_frequency < 290000000) + cp = 3; + else if (tuner_frequency < 420000000) + cp = 5; + else if (tuner_frequency < 480000000) + cp = 6; + else if (tuner_frequency < 620000000) + cp = 3; + else if (tuner_frequency < 830000000) + cp = 5; + else if (tuner_frequency < 895000000) + cp = 7; + else + return -EINVAL; + + // determine band + if (params->frequency < 49000000) + return -EINVAL; + else if (params->frequency < 161000000) + band = 1; + else if (params->frequency < 444000000) + band = 2; + else if (params->frequency < 861000000) + band = 4; + else + return -EINVAL; + + // setup PLL filter + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + filter = 0; + break; + + case BANDWIDTH_7_MHZ: + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + filter = 1; + break; + + default: + return -EINVAL; + } + + // calculate divisor + // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; + + // setup tuner buffer + tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + return 0; +} + +static int philips_tu1216_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + + return request_firmware(fw, name, &budget->dev->pci->dev); +} + +static struct tda1004x_config philips_tu1216_config = { + + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 1, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = philips_tu1216_request_firmware, +}; + +static u8 philips_sd1878_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, + 0x05, 0x35, + 0x06, 0x40, + 0x07, 0x00, + 0x08, 0x43, + 0x09, 0x02, + 0x0C, 0x51, + 0x0D, 0x82, + 0x0E, 0x23, + 0x10, 0x3f, + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, + 0x16, 0x19, + 0x17, 0x8c, + 0x18, 0x59, + 0x19, 0xf8, + 0x1a, 0xfe, + 0x1c, 0x7f, + 0x1d, 0x00, + 0x1e, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, + 0x29, 0x28, + 0x2a, 0x14, + 0x2b, 0x0f, + 0x2c, 0x09, + 0x2d, 0x09, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x93, + 0xff, 0xff +}; + +static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + u8 m1; + + aclk = 0xb5; + if (srate < 2000000) + bclk = 0x86; + else if (srate < 5000000) + bclk = 0x89; + else if (srate < 15000000) + bclk = 0x8f; + else if (srate < 45000000) + bclk = 0x95; + + m1 = 0x14; + if (srate < 4000000) + m1 = 0x10; + + stv0299_writereg(fe, 0x0e, 0x23); + stv0299_writereg(fe, 0x0f, 0x94); + stv0299_writereg(fe, 0x10, 0x39); + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x15, 0xc9); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + stv0299_writereg(fe, 0x0f, 0x80 | m1); + + return 0; +} + +static struct stv0299_config philips_sd1878_config = { + .demod_address = 0x68, + .inittab = philips_sd1878_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, +}; + +/* KNC1 DVB-S (STB0899) Inittab */ +static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = { + + { STB0899_DEV_ID , 0x81 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISFIFO , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x8c }, + { STB0899_DISF22RX , 0x9a }, + { STB0899_SYSREG , 0x0b }, + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0x30 }, + { STB0899_IRQSTATUS_2 , 0x00 }, + { STB0899_IRQSTATUS_1 , 0x00 }, + { STB0899_IRQSTATUS_0 , 0x00 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */ + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x20 }, + { STB0899_IOPVALUE3 , 0xc9 }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x40 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x08 }, /* 0x1c */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x00 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x41 }, + { STB0899_AGC1REF , 0x08 }, + { STB0899_RTC , 0x7a }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x33 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xee }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xdd }, + { STB0899_LDT2 , 0xc9 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfb }, + { STB0899_QDCCOMP , 0x03 }, + { STB0899_POWERI , 0x3b }, + { STB0899_POWERQ , 0x3d }, + { STB0899_RCOMP , 0x81 }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x04 }, + { STB0899_AGC2I2 , 0xf5 }, + { STB0899_TLIR , 0x25 }, + { STB0899_RTF , 0x80 }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xca }, + { STB0899_CFRM , 0xf1 }, + { STB0899_CFRL , 0xf3 }, + { STB0899_NIRM , 0x2a }, + { STB0899_NIRL , 0x05 }, + { STB0899_ISYMB , 0x17 }, + { STB0899_QSYMB , 0xfa }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0xfd }, + { STB0899_EQUAQ1 , 0x04 }, + { STB0899_EQUAI2 , 0x0f }, + { STB0899_EQUAQ2 , 0xff }, + { STB0899_EQUAI3 , 0xdf }, + { STB0899_EQUAQ3 , 0xfa }, + { STB0899_EQUAI4 , 0x37 }, + { STB0899_EQUAQ4 , 0x0d }, + { STB0899_EQUAI5 , 0xbd }, + { STB0899_EQUAQ5 , 0xf7 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0xff }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x00 }, + { STB0899_ECNT3L , 0x00 }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xf0 }, + { STB0899_VTH23 , 0xa0 }, + { STB0899_VTH34 , 0x78 }, + { STB0899_VTH56 , 0x4e }, + { STB0899_VTH67 , 0x48 }, + { STB0899_VTH78 , 0x38 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x40 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x0c }, + { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x00 }, + { STB0899_TSLLSTKL , 0x00 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0xab }, + { STB0899_PCKLENUL , 0x00 }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xcc }, + { STB0899_TSSTATUS , 0x80 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x96 }, + { STB0899_ERRCTRL3 , 0x89 }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x1f }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0x00 }, + { STB0899_MATSTRL , 0x00 }, + { STB0899_UPLSTRM , 0x00 }, + { STB0899_UPLSTRL , 0x00 }, + { STB0899_DFLSTRM , 0x00 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x00 }, + { STB0899_SYNCDSTRM , 0x00 }, + { STB0899_SYNCDSTRL , 0x00 }, + { STB0899_CFGPDELSTATUS1 , 0x10 }, + { STB0899_CFGPDELSTATUS2 , 0x00 }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x00 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + +/* STB0899 demodulator config for the KNC1 and clones */ +static struct stb0899_config knc1_dvbs2_config = { + .init_dev = knc1_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = knc1_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .postproc = NULL, + + .demod_address = 0x68, +// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */ + .block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */ +// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */ + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_OFF, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 90000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = tda8261_get_frequency, + .tuner_set_frequency = tda8261_set_frequency, + .tuner_set_bandwidth = NULL, + .tuner_get_bandwidth = tda8261_get_bandwidth, + .tuner_set_rfsiggain = NULL +}; + +/* + * SD1878/SHA tuner config + * 1F, Single I/P, Horizontal mount, High Sensitivity + */ +static const struct tda8261_config sd1878c_config = { +// .name = "SD1878/SHA", + .addr = 0x60, + .step_size = TDA8261_STEP_1000 /* kHz */ +}; + +static u8 read_pwm(struct budget_av *budget_av) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1}, + {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} + }; + + if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2) + || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +#define SUBID_DVBS_KNC1 0x0010 +#define SUBID_DVBS_KNC1_PLUS 0x0011 +#define SUBID_DVBS_TYPHOON 0x4f56 +#define SUBID_DVBS_CINERGY1200 0x1154 +#define SUBID_DVBS_CYNERGY1200N 0x1155 +#define SUBID_DVBS_TV_STAR 0x0014 +#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015 +#define SUBID_DVBS_TV_STAR_CI 0x0016 +#define SUBID_DVBS2_KNC1 0x0018 +#define SUBID_DVBS2_KNC1_OEM 0x0019 +#define SUBID_DVBS_EASYWATCH_1 0x001a +#define SUBID_DVBS_EASYWATCH_2 0x001b +#define SUBID_DVBS2_EASYWATCH 0x001d +#define SUBID_DVBS_EASYWATCH 0x001e + +#define SUBID_DVBC_EASYWATCH 0x002a +#define SUBID_DVBC_EASYWATCH_MK3 0x002c +#define SUBID_DVBC_KNC1 0x0020 +#define SUBID_DVBC_KNC1_PLUS 0x0021 +#define SUBID_DVBC_KNC1_MK3 0x0022 +#define SUBID_DVBC_KNC1_PLUS_MK3 0x0023 +#define SUBID_DVBC_CINERGY1200 0x1156 +#define SUBID_DVBC_CINERGY1200_MK3 0x1176 + +#define SUBID_DVBT_EASYWATCH 0x003a +#define SUBID_DVBT_KNC1_PLUS 0x0031 +#define SUBID_DVBT_KNC1 0x0030 +#define SUBID_DVBT_CINERGY1200 0x1157 + +static void frontend_init(struct budget_av *budget_av) +{ + struct saa7146_dev * saa = budget_av->budget.dev; + struct dvb_frontend * fe = NULL; + + /* Enable / PowerON Frontend */ + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); + + /* Wait for PowerON */ + msleep(100); + + /* additional setup necessary for the PLUS cards */ + switch (saa->pci->subsystem_device) { + case SUBID_DVBS_KNC1_PLUS: + case SUBID_DVBC_KNC1_PLUS: + case SUBID_DVBT_KNC1_PLUS: + case SUBID_DVBC_EASYWATCH: + case SUBID_DVBC_KNC1_PLUS_MK3: + case SUBID_DVBS2_KNC1: + case SUBID_DVBS2_KNC1_OEM: + case SUBID_DVBS2_EASYWATCH: + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); + break; + } + + switch (saa->pci->subsystem_device) { + + case SUBID_DVBS_KNC1: + /* + * maybe that setting is needed for other dvb-s cards as well, + * but so far it has been only confirmed for this type + */ + budget_av->reinitialise_demod = 1; + /* fall through */ + case SUBID_DVBS_KNC1_PLUS: + case SUBID_DVBS_EASYWATCH_1: + if (saa->pci->subsystem_vendor == 0x1894) { + fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config, + &budget_av->budget.i2c_adap); + if (fe) { + dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap); + } + } else { + fe = dvb_attach(stv0299_attach, &typhoon_config, + &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; + } + } + break; + + case SUBID_DVBS_TV_STAR: + case SUBID_DVBS_TV_STAR_PLUS_X4: + case SUBID_DVBS_TV_STAR_CI: + case SUBID_DVBS_CYNERGY1200N: + case SUBID_DVBS_EASYWATCH: + case SUBID_DVBS_EASYWATCH_2: + fe = dvb_attach(stv0299_attach, &philips_sd1878_config, + &budget_av->budget.i2c_adap); + if (fe) { + dvb_attach(dvb_pll_attach, fe, 0x60, + &budget_av->budget.i2c_adap, + DVB_PLL_PHILIPS_SD1878_TDA8261); + } + break; + + case SUBID_DVBS_TYPHOON: + fe = dvb_attach(stv0299_attach, &typhoon_config, + &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; + } + break; + case SUBID_DVBS2_KNC1: + case SUBID_DVBS2_KNC1_OEM: + case SUBID_DVBS2_EASYWATCH: + budget_av->reinitialise_demod = 1; + if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap))) + dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap); + + break; + case SUBID_DVBS_CINERGY1200: + fe = dvb_attach(stv0299_attach, &cinergy_1200s_config, + &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; + } + break; + + case SUBID_DVBC_KNC1: + case SUBID_DVBC_KNC1_PLUS: + case SUBID_DVBC_CINERGY1200: + case SUBID_DVBC_EASYWATCH: + budget_av->reinitialise_demod = 1; + budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; + fe = dvb_attach(tda10021_attach, &philips_cu1216_config, + &budget_av->budget.i2c_adap, + read_pwm(budget_av)); + if (fe == NULL) + fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress, + &budget_av->budget.i2c_adap, + read_pwm(budget_av)); + if (fe) { + fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; + } + break; + + case SUBID_DVBC_EASYWATCH_MK3: + case SUBID_DVBC_CINERGY1200_MK3: + case SUBID_DVBC_KNC1_MK3: + case SUBID_DVBC_KNC1_PLUS_MK3: + budget_av->reinitialise_demod = 1; + budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; + fe = dvb_attach(tda10023_attach, + &philips_cu1216_tda10023_config, + &budget_av->budget.i2c_adap, + read_pwm(budget_av)); + if (fe) { + fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; + } + break; + + case SUBID_DVBT_EASYWATCH: + case SUBID_DVBT_KNC1: + case SUBID_DVBT_KNC1_PLUS: + case SUBID_DVBT_CINERGY1200: + budget_av->reinitialise_demod = 1; + fe = dvb_attach(tda10046_attach, &philips_tu1216_config, + &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.init = philips_tu1216_tuner_init; + fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params; + } + break; + } + + if (fe == NULL) { + printk(KERN_ERR "budget-av: A frontend driver was not found " + "for device [%04x:%04x] subsystem [%04x:%04x]\n", + saa->pci->vendor, + saa->pci->device, + saa->pci->subsystem_vendor, + saa->pci->subsystem_device); + return; + } + + budget_av->budget.dvb_frontend = fe; + + if (dvb_register_frontend(&budget_av->budget.dvb_adapter, + budget_av->budget.dvb_frontend)) { + printk(KERN_ERR "budget-av: Frontend registration failed!\n"); + dvb_frontend_detach(budget_av->budget.dvb_frontend); + budget_av->budget.dvb_frontend = NULL; + } +} + + +static void budget_av_irq(struct saa7146_dev *dev, u32 * isr) +{ + struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; + + dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av); + + if (*isr & MASK_10) + ttpci_budget_irq10_handler(dev, isr); +} + +static int budget_av_detach(struct saa7146_dev *dev) +{ + struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; + int err; + + dprintk(2, "dev: %p\n", dev); + + if (1 == budget_av->has_saa7113) { + saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); + + msleep(200); + + saa7146_unregister_device(&budget_av->vd, dev); + + saa7146_vv_release(dev); + } + + if (budget_av->budget.ci_present) + ciintf_deinit(budget_av); + + if (budget_av->budget.dvb_frontend != NULL) { + dvb_unregister_frontend(budget_av->budget.dvb_frontend); + dvb_frontend_detach(budget_av->budget.dvb_frontend); + } + err = ttpci_budget_deinit(&budget_av->budget); + + kfree(budget_av); + + return err; +} + +#define KNC1_INPUTS 2 +static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { + { 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, + V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, + V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, +}; + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); + if (i->index >= KNC1_INPUTS) + return -EINVAL; + memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; + + *i = budget_av->cur_input; + + dprintk(1, "VIDIOC_G_INPUT %d.\n", *i); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; + + dprintk(1, "VIDIOC_S_INPUT %d.\n", input); + return saa7113_setinput(budget_av, input); +} + +static struct saa7146_ext_vv vv_data; + +static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct budget_av *budget_av; + u8 *mac; + int err; + + dprintk(2, "dev: %p\n", dev); + + if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL))) + return -ENOMEM; + + budget_av->has_saa7113 = 0; + budget_av->budget.ci_present = 0; + + dev->ext_priv = budget_av; + + err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE, + adapter_nr); + if (err) { + kfree(budget_av); + return err; + } + + /* knc1 initialization */ + saa7146_write(dev, DD1_STREAM_B, 0x04000000); + saa7146_write(dev, DD1_INIT, 0x07000600); + saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26); + + if (saa7113_init(budget_av) == 0) { + budget_av->has_saa7113 = 1; + + if (0 != saa7146_vv_init(dev, &vv_data)) { + /* fixme: proper cleanup here */ + ERR(("cannot init vv subsystem.\n")); + return err; + } + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; + + if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { + /* fixme: proper cleanup here */ + ERR(("cannot register capture v4l2 device.\n")); + saa7146_vv_release(dev); + return err; + } + + /* beware: this modifies dev->vv ... */ + saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A, + SAA7146_HPS_SYNC_PORT_A); + + saa7113_setinput(budget_av, 0); + } + + /* fixme: find some sane values here... */ + saa7146_write(dev, PCI_BT_V1, 0x1c00101f); + + mac = budget_av->budget.dvb_adapter.proposed_mac; + if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) { + printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n", + budget_av->budget.dvb_adapter.num); + memset(mac, 0, 6); + } else { + printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + budget_av->budget.dvb_adapter.num, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + + budget_av->budget.dvb_adapter.priv = budget_av; + frontend_init(budget_av); + ciintf_init(budget_av); + + ttpci_budget_init_hooks(&budget_av->budget); + + return 0; +} + +static struct saa7146_standard standard[] = { + {.name = "PAL",.id = V4L2_STD_PAL, + .v_offset = 0x17,.v_field = 288, + .h_offset = 0x14,.h_pixels = 680, + .v_max_out = 576,.h_max_out = 768 }, + + {.name = "NTSC",.id = V4L2_STD_NTSC, + .v_offset = 0x16,.v_field = 240, + .h_offset = 0x06,.h_pixels = 708, + .v_max_out = 480,.h_max_out = 640, }, +}; + +static struct saa7146_ext_vv vv_data = { + .inputs = 2, + .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 + .flags = 0, + .stds = &standard[0], + .num_stds = ARRAY_SIZE(standard), +}; + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); +MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2); +MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2); +MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); +MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); +MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); +MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); +MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); +MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S); +MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); +MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); +MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T); +MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); +MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP); +MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); +MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); +MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); +MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); +MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); +MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); +MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); +MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); +MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), + MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), + MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), + MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), + MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011), + MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), + MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015), + MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), + MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018), + MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019), + MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d), + MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), + MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), + MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), + MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), + MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), + MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a), + MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), + MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), + MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), + MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023), + MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), + MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), + MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), + MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), + MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), + MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176), + MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_extension budget_extension = { + .name = "budget_av", + .flags = SAA7146_USE_I2C_IRQ, + + .pci_tbl = pci_tbl, + + .module = THIS_MODULE, + .attach = budget_av_attach, + .detach = budget_av_detach, + + .irq_mask = MASK_10, + .irq_func = budget_av_irq, +}; + +static int __init budget_av_init(void) +{ + return saa7146_register_extension(&budget_extension); +} + +static void __exit budget_av_exit(void) +{ + saa7146_unregister_extension(&budget_extension); +} + +module_init(budget_av_init); +module_exit(budget_av_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called " + "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,793 @@ +/* + * budget.c: driver for the SAA7146 based Budget DVB cards + * + * Compiled from various sources by Michael Hunold + * + * Copyright (C) 2002 Ralph Metzler + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * 26feb2004 Support for FS Activy Card (Grundig tuner) by + * Michael Dreher , + * Oliver Endriss and + * Andreas 'randy' Weinberger + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include "budget.h" +#include "stv0299.h" +#include "ves1x93.h" +#include "ves1820.h" +#include "l64781.h" +#include "tda8083.h" +#include "s5h1420.h" +#include "tda10086.h" +#include "tda826x.h" +#include "lnbp21.h" +#include "bsru6.h" +#include "bsbe1.h" +#include "tdhd1.h" +#include "stv6110x.h" +#include "stv090x.h" +#include "isl6423.h" + +static int diseqc_method; +module_param(diseqc_method, int, 0444); +MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static void Set22K (struct budget *budget, int state) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); +} + +/* Diseqc functions only for TT Budget card */ +/* taken from the Skyvision DVB driver by + Ralph Metzler */ + +static void DiseqcSendBit (struct budget *budget, int data) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + udelay(data ? 500 : 1000); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + udelay(data ? 1000 : 500); +} + +static void DiseqcSendByte (struct budget *budget, int data) +{ + int i, par=1, d; + + dprintk(2, "budget: %p\n", budget); + + for (i=7; i>=0; i--) { + d = (data>>i)&1; + par ^= d; + DiseqcSendBit(budget, d); + } + + DiseqcSendBit(budget, par); +} + +static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) +{ + struct saa7146_dev *dev=budget->dev; + int i; + + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + mdelay(16); + + for (i=0; idev; + + dprintk(2, "budget: %p\n", budget); + + switch (voltage) { + case SEC_VOLTAGE_13: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); + break; + case SEC_VOLTAGE_18: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + break; + case SEC_VOLTAGE_OFF: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + return SetVoltage_Activy (budget, voltage); +} + +static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + switch (tone) { + case SEC_TONE_ON: + Set22K (budget, 1); + break; + + case SEC_TONE_OFF: + Set22K (budget, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); + + return 0; +} + +static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, 0, NULL, minicmd); + + return 0; +} + +static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (params->frequency + 479500) / 125; + + if (params->frequency > 2000000) pwr = 3; + else if (params->frequency > 1800000) pwr = 2; + else if (params->frequency > 1600000) pwr = 1; + else if (params->frequency > 1200000) pwr = 0; + else if (params->frequency >= 1100000) pwr = 1; + else pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; + + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = +{ + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, +}; + +static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (params->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + +static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget *budget = fe->dvb->priv; + u8 *tuner_addr = fe->tuner_priv; + u32 div; + u8 cfg, cpump, band_select; + u8 data[4]; + struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) }; + + if (tuner_addr) + msg.addr = *tuner_addr; + else + msg.addr = 0x61; + + div = (36125000 + params->frequency) / 166666; + + cfg = 0x88; + + if (params->frequency < 175000000) cpump = 2; + else if (params->frequency < 390000000) cpump = 1; + else if (params->frequency < 470000000) cpump = 2; + else if (params->frequency < 750000000) cpump = 1; + else cpump = 3; + + if (params->frequency < 175000000) band_select = 0x0e; + else if (params->frequency < 470000000) band_select = 0x05; + else band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = (cpump << 6) | band_select; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct l64781_config grundig_29504_401_config = { + .demod_address = 0x55, +}; + +static struct l64781_config grundig_29504_401_config_activy = { + .demod_address = 0x54, +}; + +static u8 tuner_address_grundig_29504_401_activy = 0x60; + +static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = params->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, +}; + +static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = params->frequency / 1000; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xc2; + + if (div < 1450) + data[3] = 0x00; + else if (div < 1850) + data[3] = 0x40; + else if (div < 2000) + data[3] = 0x80; + else + data[3] = 0xc0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + return 0; +} + +static struct s5h1420_config s5h1420_config = { + .demod_address = 0x53, + .invert = 1, + .cdclk_polarity = 1, +}; + +static struct tda10086_config tda10086_config = { + .demod_address = 0x0e, + .invert = 0, + .diseqc_tone = 1, + .xtal_freq = TDA10086_XTAL_16M, +}; + +static struct stv0299_config alps_bsru6_config_activy = { + .demod_address = 0x68, + .inittab = alps_bsru6_inittab, + .mclk = 88000000UL, + .invert = 1, + .op0_off = 1, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsru6_set_symbol_rate, +}; + +static struct stv0299_config alps_bsbe1_config_activy = { + .demod_address = 0x68, + .inittab = alps_bsbe1_inittab, + .mclk = 88000000UL, + .invert = 1, + .op0_off = 1, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsbe1_set_symbol_rate, +}; + +static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) +{ + struct budget *budget = (struct budget *)fe->dvb->priv; + + return request_firmware(fw, name, &budget->dev->pci->dev); +} + + +static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) +{ + u8 val; + struct i2c_msg msg[] = { + { .addr = adr, .flags = 0, .buf = ®, .len = 1 }, + { .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 } + }; + + return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val; +} + +static u8 read_pwm(struct budget* budget) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static struct stv090x_config tt1600_stv090x_config = { + .device = STV0903, + .demod_mode = STV090x_SINGLE, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 13500000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_DVBCI, + .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, + + .repeater_level = STV090x_RPTLEVEL_16, + + .tuner_init = NULL, + .tuner_sleep = NULL, + .tuner_set_mode = NULL, + .tuner_set_frequency = NULL, + .tuner_get_frequency = NULL, + .tuner_set_bandwidth = NULL, + .tuner_get_bandwidth = NULL, + .tuner_set_bbgain = NULL, + .tuner_get_bbgain = NULL, + .tuner_set_refclk = NULL, + .tuner_get_status = NULL, +}; + +static struct stv6110x_config tt1600_stv6110x_config = { + .addr = 0x60, + .refclk = 27000000, + .clk_div = 2, +}; + +static struct isl6423_config tt1600_isl6423_config = { + .current_max = SEC_CURRENT_515m, + .curlim = SEC_CURRENT_LIM_ON, + .mod_extern = 1, + .addr = 0x08, +}; + +static void frontend_init(struct budget *budget) +{ + (void)alps_bsbe1_config; /* avoid warning */ + + switch(budget->dev->pci->subsystem_device) { + case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659)) + case 0x1013: + // try the ALPS BSRV2 first of all + budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + break; + } + + // try the ALPS BSRU6 now + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) { + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + } + break; + } + break; + + case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) + + budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget)); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + break; + } + break; + + case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060)) + + budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + budget->dvb_frontend->tuner_priv = NULL; + break; + } + break; + + case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */ + { + int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67); + + if (subtype < 0) + break; + /* fixme: find a better way to identify the card */ + if (subtype < 0x36) { + /* assume ALPS BSRU6 */ + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap); + if (budget->dvb_frontend) { + printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n"); + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; + budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; + break; + } + } else { + /* assume ALPS BSBE1 */ + /* reset tuner */ + saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO); + msleep(50); + saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI); + msleep(250); + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap); + if (budget->dvb_frontend) { + printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n"); + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; + budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; + break; + } + } + break; + } + + case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522)) + budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; + budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; + } + break; + + case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */ + budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + } + break; + + case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ + budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy; + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + } + break; + + case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) + budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params; + if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { + printk("%s: No LNBP21 found!\n", __func__); + goto error_out; + } + break; + } + + case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262) + // gpio2 is connected to CLB - reset it + leave it high + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); + msleep(1); + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); + msleep(1); + + budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL) + printk("%s: No tda826x found!\n", __func__); + if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { + printk("%s: No LNBP21 found!\n", __func__); + goto error_out; + } + break; + } + + case 0x101c: { /* TT S2-1600 */ + struct stv6110x_devctl *ctl; + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); + msleep(50); + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); + msleep(250); + + budget->dvb_frontend = dvb_attach(stv090x_attach, + &tt1600_stv090x_config, + &budget->i2c_adap, + STV090x_DEMODULATOR_0); + + if (budget->dvb_frontend) { + + ctl = dvb_attach(stv6110x_attach, + budget->dvb_frontend, + &tt1600_stv6110x_config, + &budget->i2c_adap); + + if (ctl) { + tt1600_stv090x_config.tuner_init = ctl->tuner_init; + tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; + tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; + tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; + tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; + tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; + tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; + tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; + tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; + tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; + tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; + + /* call the init function once to initialize + tuner's clock output divider and demod's + master clock */ + if (budget->dvb_frontend->ops.init) + budget->dvb_frontend->ops.init(budget->dvb_frontend); + + if (dvb_attach(isl6423_attach, + budget->dvb_frontend, + &budget->i2c_adap, + &tt1600_isl6423_config) == NULL) { + printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__); + goto error_out; + } + } else { + printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); + goto error_out; + } + } + } + break; + } + + if (budget->dvb_frontend == NULL) { + printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + budget->dev->pci->vendor, + budget->dev->pci->device, + budget->dev->pci->subsystem_vendor, + budget->dev->pci->subsystem_device); + } else { + if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) + goto error_out; + } + return; + +error_out: + printk("budget: Frontend registration failed!\n"); + dvb_frontend_detach(budget->dvb_frontend); + budget->dvb_frontend = NULL; + return; +} + +static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) +{ + struct budget *budget = NULL; + int err; + + budget = kmalloc(sizeof(struct budget), GFP_KERNEL); + if( NULL == budget ) { + return -ENOMEM; + } + + dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget); + + dev->ext_priv = budget; + + err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); + if (err) { + printk("==> failed\n"); + kfree (budget); + return err; + } + + budget->dvb_adapter.priv = budget; + frontend_init(budget); + + ttpci_budget_init_hooks(budget); + + return 0; +} + +static int budget_detach (struct saa7146_dev* dev) +{ + struct budget *budget = (struct budget*) dev->ext_priv; + int err; + + if (budget->dvb_frontend) { + dvb_unregister_frontend(budget->dvb_frontend); + dvb_frontend_detach(budget->dvb_frontend); + } + + err = ttpci_budget_deinit (budget); + + kfree (budget); + dev->ext_priv = NULL; + + return err; +} + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); +MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); +MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); +MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); +MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); +MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), + MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), + MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), + MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), + MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), + MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), + MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c), + MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), + MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), + MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), + MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_extension budget_extension = { + .name = "budget dvb", + .flags = SAA7146_USE_I2C_IRQ, + + .module = THIS_MODULE, + .pci_tbl = pci_tbl, + .attach = budget_attach, + .detach = budget_detach, + + .irq_mask = MASK_10, + .irq_func = ttpci_budget_irq10_handler, +}; + +static int __init budget_init(void) +{ + return saa7146_register_extension(&budget_extension); +} + +static void __exit budget_exit(void) +{ + saa7146_unregister_extension(&budget_extension); +} + +module_init(budget_init); +module_exit(budget_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called " + "budget PCI DVB cards by Siemens, Technotrend, Hauppauge"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-ci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-ci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-ci.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-ci.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1589 @@ +/* + * budget-ci.c: driver for the SAA7146 based Budget DVB cards + * + * Compiled from various sources by Michael Hunold + * + * msp430 IR support contributed by Jack Thomasson + * partially based on the Siemens DVB driver by Ralph+Marcus Metzler + * + * CI interface support (c) 2004 Andrew de Quincey + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include +#include +#include +#include +#include +#include + +#include "budget.h" + +#include "dvb_ca_en50221.h" +#include "stv0299.h" +#include "stv0297.h" +#include "tda1004x.h" +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +#include "stb6100.h" +#include "stb6100_cfg.h" +#include "lnbp21.h" +#include "bsbe1.h" +#include "bsru6.h" +#include "tda1002x.h" +#include "tda827x.h" +#include "bsbe1-d01a.h" + +#define MODULE_NAME "budget_ci" + +/* + * Regarding DEBIADDR_IR: + * Some CI modules hang if random addresses are read. + * Using address 0x4000 for the IR read means that we + * use the same address as for CI version, which should + * be a safe default. + */ +#define DEBIADDR_IR 0x4000 +#define DEBIADDR_CICONTROL 0x0000 +#define DEBIADDR_CIVERSION 0x4000 +#define DEBIADDR_IO 0x1000 +#define DEBIADDR_ATTR 0x3000 + +#define CICONTROL_RESET 0x01 +#define CICONTROL_ENABLETS 0x02 +#define CICONTROL_CAMDETECT 0x08 + +#define DEBICICTL 0x00420000 +#define DEBICICAM 0x02420000 + +#define SLOTSTATUS_NONE 1 +#define SLOTSTATUS_PRESENT 2 +#define SLOTSTATUS_RESET 4 +#define SLOTSTATUS_READY 8 +#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) + +/* RC5 device wildcard */ +#define IR_DEVICE_ANY 255 + +static int rc5_device = -1; +module_param(rc5_device, int, 0644); +MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)"); + +static int ir_debug; +module_param(ir_debug, int, 0644); +MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct budget_ci_ir { + struct rc_dev *dev; + struct tasklet_struct msp430_irq_tasklet; + char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ + char phys[32]; + int rc5_device; + u32 ir_key; + bool have_command; + bool full_rc5; /* Outputs a full RC5 code */ +}; + +struct budget_ci { + struct budget budget; + struct tasklet_struct ciintf_irq_tasklet; + int slot_status; + int ci_irq; + struct dvb_ca_en50221 ca; + struct budget_ci_ir ir; + u8 tuner_pll_address; /* used for philips_tdm1316l configs */ +}; + +static void msp430_ir_interrupt(unsigned long data) +{ + struct budget_ci *budget_ci = (struct budget_ci *) data; + struct rc_dev *dev = budget_ci->ir.dev; + u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; + + /* + * The msp430 chip can generate two different bytes, command and device + * + * type1: X1CCCCCC, C = command bits (0 - 63) + * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit + * + * Each signal from the remote control can generate one or more command + * bytes and one or more device bytes. For the repeated bytes, the + * highest bit (X) is set. The first command byte is always generated + * before the first device byte. Other than that, no specific order + * seems to apply. To make life interesting, bytes can also be lost. + * + * Only when we have a command and device byte, a keypress is + * generated. + */ + + if (ir_debug) + printk("budget_ci: received byte 0x%02x\n", command); + + /* Remove repeat bit, we use every command */ + command = command & 0x7f; + + /* Is this a RC5 command byte? */ + if (command & 0x40) { + budget_ci->ir.have_command = true; + budget_ci->ir.ir_key = command & 0x3f; + return; + } + + /* It's a RC5 device byte */ + if (!budget_ci->ir.have_command) + return; + budget_ci->ir.have_command = false; + + if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && + budget_ci->ir.rc5_device != (command & 0x1f)) + return; + + if (budget_ci->ir.full_rc5) { + rc_keydown(dev, + budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key, + (command & 0x20) ? 1 : 0); + return; + } + + /* FIXME: We should generate complete scancodes for all devices */ + rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0); +} + +static int msp430_ir_init(struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + struct rc_dev *dev; + int error; + + dev = rc_allocate_device(); + if (!dev) { + printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); + return -ENOMEM; + } + + snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), + "Budget-CI dvb ir receiver %s", saa->name); + snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys), + "pci-%s/ir0", pci_name(saa->pci)); + + dev->driver_name = MODULE_NAME; + dev->input_name = budget_ci->ir.name; + dev->input_phys = budget_ci->ir.phys; + dev->input_id.bustype = BUS_PCI; + dev->input_id.version = 1; + dev->scanmask = 0xff; + if (saa->pci->subsystem_vendor) { + dev->input_id.vendor = saa->pci->subsystem_vendor; + dev->input_id.product = saa->pci->subsystem_device; + } else { + dev->input_id.vendor = saa->pci->vendor; + dev->input_id.product = saa->pci->device; + } + dev->dev.parent = &saa->pci->dev; + + if (rc5_device < 0) + budget_ci->ir.rc5_device = IR_DEVICE_ANY; + else + budget_ci->ir.rc5_device = rc5_device; + + /* Select keymap and address */ + switch (budget_ci->budget.dev->pci->subsystem_device) { + case 0x100c: + case 0x100f: + case 0x1011: + case 0x1012: + /* The hauppauge keymap is a superset of these remotes */ + dev->map_name = RC_MAP_HAUPPAUGE; + budget_ci->ir.full_rc5 = true; + + if (rc5_device < 0) + budget_ci->ir.rc5_device = 0x1f; + break; + case 0x1010: + case 0x1017: + case 0x1019: + case 0x101a: + case 0x101b: + /* for the Technotrend 1500 bundled remote */ + dev->map_name = RC_MAP_TT_1500; + break; + default: + /* unknown remote */ + dev->map_name = RC_MAP_BUDGET_CI_OLD; + break; + } + + error = rc_register_device(dev); + if (error) { + printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); + rc_free_device(dev); + return error; + } + + budget_ci->ir.dev = dev; + + tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt, + (unsigned long) budget_ci); + + SAA7146_IER_ENABLE(saa, MASK_06); + saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); + + return 0; +} + +static void msp430_ir_deinit(struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + + SAA7146_IER_DISABLE(saa, MASK_06); + saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); + tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); + + rc_unregister_device(budget_ci->ir.dev); +} + +static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + + if (slot != 0) + return -EINVAL; + + return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, + DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0); +} + +static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + + if (slot != 0) + return -EINVAL; + + return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, + DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0); +} + +static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + + if (slot != 0) + return -EINVAL; + + return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, + DEBIADDR_IO | (address & 3), 1, 1, 0); +} + +static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + + if (slot != 0) + return -EINVAL; + + return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, + DEBIADDR_IO | (address & 3), 1, value, 1, 0); +} + +static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + struct saa7146_dev *saa = budget_ci->budget.dev; + + if (slot != 0) + return -EINVAL; + + if (budget_ci->ci_irq) { + // trigger on RISING edge during reset so we know when READY is re-asserted + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + } + budget_ci->slot_status = SLOTSTATUS_RESET; + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); + msleep(1); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + CICONTROL_RESET, 1, 0); + + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + return 0; +} + +static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + struct saa7146_dev *saa = budget_ci->budget.dev; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + return 0; +} + +static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + struct saa7146_dev *saa = budget_ci->budget.dev; + int tmp; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); + + tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + tmp | CICONTROL_ENABLETS, 1, 0); + + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); + return 0; +} + +static void ciintf_interrupt(unsigned long data) +{ + struct budget_ci *budget_ci = (struct budget_ci *) data; + struct saa7146_dev *saa = budget_ci->budget.dev; + unsigned int flags; + + // ensure we don't get spurious IRQs during initialisation + if (!budget_ci->budget.ci_present) + return; + + // read the CAM status + flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + if (flags & CICONTROL_CAMDETECT) { + + // GPIO should be set to trigger on falling edge if a CAM is present + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); + + if (budget_ci->slot_status & SLOTSTATUS_NONE) { + // CAM insertion IRQ + budget_ci->slot_status = SLOTSTATUS_PRESENT; + dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, + DVB_CA_EN50221_CAMCHANGE_INSERTED); + + } else if (budget_ci->slot_status & SLOTSTATUS_RESET) { + // CAM ready (reset completed) + budget_ci->slot_status = SLOTSTATUS_READY; + dvb_ca_en50221_camready_irq(&budget_ci->ca, 0); + + } else if (budget_ci->slot_status & SLOTSTATUS_READY) { + // FR/DA IRQ + dvb_ca_en50221_frda_irq(&budget_ci->ca, 0); + } + } else { + + // trigger on rising edge if a CAM is not present - when a CAM is inserted, we + // only want to get the IRQ when it sets READY. If we trigger on the falling edge, + // the CAM might not actually be ready yet. + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + + // generate a CAM removal IRQ if we haven't already + if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) { + // CAM removal IRQ + budget_ci->slot_status = SLOTSTATUS_NONE; + dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, + DVB_CA_EN50221_CAMCHANGE_REMOVED); + } + } +} + +static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct budget_ci *budget_ci = (struct budget_ci *) ca->data; + unsigned int flags; + + // ensure we don't get spurious IRQs during initialisation + if (!budget_ci->budget.ci_present) + return -EINVAL; + + // read the CAM status + flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + if (flags & CICONTROL_CAMDETECT) { + // mark it as present if it wasn't before + if (budget_ci->slot_status & SLOTSTATUS_NONE) { + budget_ci->slot_status = SLOTSTATUS_PRESENT; + } + + // during a RESET, we check if we can read from IO memory to see when CAM is ready + if (budget_ci->slot_status & SLOTSTATUS_RESET) { + if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) { + budget_ci->slot_status = SLOTSTATUS_READY; + } + } + } else { + budget_ci->slot_status = SLOTSTATUS_NONE; + } + + if (budget_ci->slot_status != SLOTSTATUS_NONE) { + if (budget_ci->slot_status & SLOTSTATUS_READY) { + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + } + return DVB_CA_EN50221_POLL_CAM_PRESENT; + } + + return 0; +} + +static int ciintf_init(struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + int flags; + int result; + int ci_version; + int ca_flags; + + memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); + + // enable DEBI pins + saa7146_write(saa, MC1, MASK_27 | MASK_11); + + // test if it is there + ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0); + if ((ci_version & 0xa0) != 0xa0) { + result = -ENODEV; + goto error; + } + + // determine whether a CAM is present or not + flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + budget_ci->slot_status = SLOTSTATUS_NONE; + if (flags & CICONTROL_CAMDETECT) + budget_ci->slot_status = SLOTSTATUS_PRESENT; + + // version 0xa2 of the CI firmware doesn't generate interrupts + if (ci_version == 0xa2) { + ca_flags = 0; + budget_ci->ci_irq = 0; + } else { + ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | + DVB_CA_EN50221_FLAG_IRQ_FR | + DVB_CA_EN50221_FLAG_IRQ_DA; + budget_ci->ci_irq = 1; + } + + // register CI interface + budget_ci->ca.owner = THIS_MODULE; + budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; + budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem; + budget_ci->ca.read_cam_control = ciintf_read_cam_control; + budget_ci->ca.write_cam_control = ciintf_write_cam_control; + budget_ci->ca.slot_reset = ciintf_slot_reset; + budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; + budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; + budget_ci->ca.poll_slot_status = ciintf_poll_slot_status; + budget_ci->ca.data = budget_ci; + if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, + &budget_ci->ca, + ca_flags, 1)) != 0) { + printk("budget_ci: CI interface detected, but initialisation failed.\n"); + goto error; + } + + // Setup CI slot IRQ + if (budget_ci->ci_irq) { + tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci); + if (budget_ci->slot_status != SLOTSTATUS_NONE) { + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); + } else { + saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); + } + SAA7146_IER_ENABLE(saa, MASK_03); + } + + // enable interface + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + CICONTROL_RESET, 1, 0); + + // success! + printk("budget_ci: CI interface initialised\n"); + budget_ci->budget.ci_present = 1; + + // forge a fake CI IRQ so the CAM state is setup correctly + if (budget_ci->ci_irq) { + flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; + if (budget_ci->slot_status != SLOTSTATUS_NONE) + flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; + dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); + } + + return 0; + +error: + saa7146_write(saa, MC1, MASK_27); + return result; +} + +static void ciintf_deinit(struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + + // disable CI interrupts + if (budget_ci->ci_irq) { + SAA7146_IER_DISABLE(saa, MASK_03); + saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); + tasklet_kill(&budget_ci->ciintf_irq_tasklet); + } + + // reset interface + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); + msleep(1); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + CICONTROL_RESET, 1, 0); + + // disable TS data stream to CI interface + saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); + + // release the CA device + dvb_ca_en50221_release(&budget_ci->ca); + + // disable DEBI pins + saa7146_write(saa, MC1, MASK_27); +} + +static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr) +{ + struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; + + dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); + + if (*isr & MASK_06) + tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet); + + if (*isr & MASK_10) + ttpci_budget_irq10_handler(dev, isr); + + if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) + tasklet_schedule(&budget_ci->ciintf_irq_tasklet); +} + +static u8 philips_su1278_tt_inittab[] = { + 0x01, 0x0f, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x5b, + 0x05, 0x85, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0x02, + 0x09, 0x00, + 0x0C, 0x01, + 0x0D, 0x81, + 0x0E, 0x44, + 0x0f, 0x14, + 0x10, 0x3c, + 0x11, 0x84, + 0x12, 0xda, + 0x13, 0x97, + 0x14, 0x95, + 0x15, 0xc9, + 0x16, 0x19, + 0x17, 0x8c, + 0x18, 0x59, + 0x19, 0xf8, + 0x1a, 0xfe, + 0x1c, 0x7f, + 0x1d, 0x00, + 0x1e, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, + 0x29, 0x28, + 0x2a, 0x14, + 0x2b, 0x0f, + 0x2c, 0x09, + 0x2d, 0x09, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x93, + 0xff, 0xff +}; + +static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + stv0299_writereg(fe, 0x0e, 0x44); + if (srate >= 10000000) { + stv0299_writereg(fe, 0x13, 0x97); + stv0299_writereg(fe, 0x14, 0x95); + stv0299_writereg(fe, 0x15, 0xc9); + stv0299_writereg(fe, 0x17, 0x8c); + stv0299_writereg(fe, 0x1a, 0xfe); + stv0299_writereg(fe, 0x1c, 0x7f); + stv0299_writereg(fe, 0x2d, 0x09); + } else { + stv0299_writereg(fe, 0x13, 0x99); + stv0299_writereg(fe, 0x14, 0x8d); + stv0299_writereg(fe, 0x15, 0xce); + stv0299_writereg(fe, 0x17, 0x43); + stv0299_writereg(fe, 0x1a, 0x1d); + stv0299_writereg(fe, 0x1c, 0x12); + stv0299_writereg(fe, 0x2d, 0x05); + } + stv0299_writereg(fe, 0x0e, 0x23); + stv0299_writereg(fe, 0x0f, 0x94); + stv0299_writereg(fe, 0x10, 0x39); + stv0299_writereg(fe, 0x15, 0xc9); + + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + + return 0; +} + +static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u32 div; + u8 buf[4]; + struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (500 - 1)) / 500; // round correctly + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; + buf[3] = 0x20; + + if (params->u.qpsk.symbol_rate < 4000000) + buf[3] |= 1; + + if (params->frequency < 1250000) + buf[3] |= 0; + else if (params->frequency < 1550000) + buf[3] |= 0x40; + else if (params->frequency < 2050000) + buf[3] |= 0x80; + else if (params->frequency < 2150000) + buf[3] |= 0xC0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct stv0299_config philips_su1278_tt_config = { + + .demod_address = 0x68, + .inittab = philips_su1278_tt_inittab, + .mclk = 64000000UL, + .invert = 0, + .skip_reinit = 1, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 50, + .set_symbol_rate = philips_su1278_tt_set_symbol_rate, +}; + + + +static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len = + sizeof(td1316_init) }; + + // setup PLL configuration + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + + // disable the mc44BC374c (do not check for errors) + tuner_msg.addr = 0x65; + tuner_msg.buf = disable_mc44BC374c; + tuner_msg.len = sizeof(disable_mc44BC374c); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1); + } + + return 0; +} + +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36130000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) + cp = 3; + else if (tuner_frequency < 160000000) + cp = 5; + else if (tuner_frequency < 200000000) + cp = 6; + else if (tuner_frequency < 290000000) + cp = 3; + else if (tuner_frequency < 420000000) + cp = 5; + else if (tuner_frequency < 480000000) + cp = 6; + else if (tuner_frequency < 620000000) + cp = 3; + else if (tuner_frequency < 830000000) + cp = 5; + else if (tuner_frequency < 895000000) + cp = 7; + else + return -EINVAL; + + // determine band + if (params->frequency < 49000000) + return -EINVAL; + else if (params->frequency < 159000000) + band = 1; + else if (params->frequency < 444000000) + band = 2; + else if (params->frequency < 861000000) + band = 4; + else + return -EINVAL; + + // setup PLL filter and TDA9889 + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + tda1004x_writereg(fe, 0x0C, 0x14); + filter = 0; + break; + + case BANDWIDTH_7_MHZ: + tda1004x_writereg(fe, 0x0C, 0x80); + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + tda1004x_writereg(fe, 0x0C, 0x14); + filter = 1; + break; + + default: + return -EINVAL; + } + + // calculate divisor + // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + return 0; +} + +static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + + return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev); +} + +static struct tda1004x_config philips_tdm1316l_config = { + + .demod_address = 0x8, + .invert = 0, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = philips_tdm1316l_request_firmware, +}; + +static struct tda1004x_config philips_tdm1316l_config_invert = { + + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = philips_tdm1316l_request_firmware, +}; + +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u8 tuner_buf[5]; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, + .flags = 0, + .buf = tuner_buf, + .len = sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36125000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) { + cp = 3; + band = 1; + } else if (tuner_frequency < 160000000) { + cp = 5; + band = 1; + } else if (tuner_frequency < 200000000) { + cp = 6; + band = 1; + } else if (tuner_frequency < 290000000) { + cp = 3; + band = 2; + } else if (tuner_frequency < 420000000) { + cp = 5; + band = 2; + } else if (tuner_frequency < 480000000) { + cp = 6; + band = 2; + } else if (tuner_frequency < 620000000) { + cp = 3; + band = 4; + } else if (tuner_frequency < 830000000) { + cp = 5; + band = 4; + } else if (tuner_frequency < 895000000) { + cp = 7; + band = 4; + } else + return -EINVAL; + + // assume PLL filter should always be 8MHz for the moment. + filter = 1; + + // calculate divisor + tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xc8; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + tuner_buf[4] = 0x80; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(50); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + + return 0; +} + +static u8 dvbc_philips_tdm1316l_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x20, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0x7b, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x38, + 0x62, 0x0a, + 0x53, 0x13, + 0x59, 0x08, + 0xff, 0xff, +}; + +static struct stv0297_config dvbc_philips_tdm1316l_config = { + .demod_address = 0x1c, + .inittab = dvbc_philips_tdm1316l_inittab, + .invert = 0, + .stop_during_read = 1, +}; + +static struct tda10023_config tda10023_config = { + .demod_address = 0xc, + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .deltaf = 0xa511, +}; + +static struct tda827x_config tda827x_config = { + .config = 0, +}; + +/* TT S2-3200 DVB-S (STB0899) Inittab */ +static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { + + { STB0899_DEV_ID , 0x81 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISFIFO , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x8c }, + { STB0899_DISF22RX , 0x9a }, + { STB0899_SYSREG , 0x0b }, + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0x30 }, + { STB0899_IRQSTATUS_2 , 0x00 }, + { STB0899_IRQSTATUS_1 , 0x00 }, + { STB0899_IRQSTATUS_0 , 0x00 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */ + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x20 }, + { STB0899_IOPVALUE3 , 0xc9 }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x40 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x00 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x41 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x7a }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xc7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xdd }, + { STB0899_LDT2 , 0xc9 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfb }, + { STB0899_QDCCOMP , 0x03 }, + { STB0899_POWERI , 0x3b }, + { STB0899_POWERQ , 0x3d }, + { STB0899_RCOMP , 0x81 }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x04 }, + { STB0899_AGC2I2 , 0xf5 }, + { STB0899_TLIR , 0x25 }, + { STB0899_RTF , 0x80 }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xca }, + { STB0899_CFRM , 0xf1 }, + { STB0899_CFRL , 0xf3 }, + { STB0899_NIRM , 0x2a }, + { STB0899_NIRL , 0x05 }, + { STB0899_ISYMB , 0x17 }, + { STB0899_QSYMB , 0xfa }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0xfd }, + { STB0899_EQUAQ1 , 0x04 }, + { STB0899_EQUAI2 , 0x0f }, + { STB0899_EQUAQ2 , 0xff }, + { STB0899_EQUAI3 , 0xdf }, + { STB0899_EQUAQ3 , 0xfa }, + { STB0899_EQUAI4 , 0x37 }, + { STB0899_EQUAQ4 , 0x0d }, + { STB0899_EQUAI5 , 0xbd }, + { STB0899_EQUAQ5 , 0xf7 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0xff }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x00 }, + { STB0899_ECNT3L , 0x00 }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xf0 }, + { STB0899_VTH23 , 0xa0 }, + { STB0899_VTH34 , 0x78 }, + { STB0899_VTH56 , 0x4e }, + { STB0899_VTH67 , 0x48 }, + { STB0899_VTH78 , 0x38 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x40 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x0c }, + { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x00 }, + { STB0899_TSLLSTKL , 0x00 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0xab }, + { STB0899_PCKLENUL , 0x00 }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xcc }, + { STB0899_TSSTATUS , 0x80 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x96 }, + { STB0899_ERRCTRL3 , 0x89 }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x1f }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0x00 }, + { STB0899_MATSTRL , 0x00 }, + { STB0899_UPLSTRM , 0x00 }, + { STB0899_UPLSTRL , 0x00 }, + { STB0899_DFLSTRM , 0x00 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x00 }, + { STB0899_SYNCDSTRM , 0x00 }, + { STB0899_SYNCDSTRL , 0x00 }, + { STB0899_CFGPDELSTATUS1 , 0x10 }, + { STB0899_CFGPDELSTATUS2 , 0x00 }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x00 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + +static struct stb0899_config tt3200_config = { + .init_dev = tt3200_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = tt3200_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .postproc = NULL, + + .demod_address = 0x68, + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_ON, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL +}; + +static struct stb6100_config tt3200_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static void frontend_init(struct budget_ci *budget_ci) +{ + switch (budget_ci->budget.dev->pci->subsystem_device) { + case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059)) + budget_ci->budget.dvb_frontend = + dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; + break; + } + break; + + case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059)) + budget_ci->budget.dvb_frontend = + dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params; + break; + } + break; + + case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) + budget_ci->tuner_pll_address = 0x61; + budget_ci->budget.dvb_frontend = + dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; + break; + } + break; + + case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) + budget_ci->tuner_pll_address = 0x63; + budget_ci->budget.dvb_frontend = + dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; + break; + } + break; + + case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) + budget_ci->tuner_pll_address = 0x60; + budget_ci->budget.dvb_frontend = + dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; + break; + } + break; + + case 0x1017: // TT S-1500 PCI + budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; + budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; + + budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; + if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) { + printk("%s: No LNBP21 found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + + case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */ + budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48); + if (budget_ci->budget.dvb_frontend) { + if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) { + printk(KERN_ERR "%s: No tda827x found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + + case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */ + budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) { + if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { + printk(KERN_ERR "%s: No LNBP21 found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } else { + printk(KERN_ERR "%s: No STB6000 found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + + case 0x1019: // TT S2-3200 PCI + /* + * NOTE! on some STB0899 versions, the internal PLL takes a longer time + * to settle, aka LOCK. On the older revisions of the chip, we don't see + * this, as a result on the newer chips the entire clock tree, will not + * be stable after a freshly POWER 'ed up situation. + * In this case, we should RESET the STB0899 (Active LOW) and wait for + * PLL stabilization. + * + * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is + * connected to the SAA7146 GPIO, GPIO2, Pin 142 + */ + /* Reset Demodulator */ + saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO); + /* Wait for everything to die */ + msleep(50); + /* Pull it up out of Reset state */ + saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI); + /* Wait for PLL to stabilize */ + msleep(250); + /* + * PLL state should be stable now. Ideally, we should check + * for PLL LOCK status. But well, never mind! + */ + budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) { + if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { + printk("%s: No LNBP21 found!\n", __func__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } else { + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + + } + + if (budget_ci->budget.dvb_frontend == NULL) { + printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + budget_ci->budget.dev->pci->vendor, + budget_ci->budget.dev->pci->device, + budget_ci->budget.dev->pci->subsystem_vendor, + budget_ci->budget.dev->pci->subsystem_device); + } else { + if (dvb_register_frontend + (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { + printk("budget-ci: Frontend registration failed!\n"); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } +} + +static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct budget_ci *budget_ci; + int err; + + budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL); + if (!budget_ci) { + err = -ENOMEM; + goto out1; + } + + dprintk(2, "budget_ci: %p\n", budget_ci); + + dev->ext_priv = budget_ci; + + err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE, + adapter_nr); + if (err) + goto out2; + + err = msp430_ir_init(budget_ci); + if (err) + goto out3; + + ciintf_init(budget_ci); + + budget_ci->budget.dvb_adapter.priv = budget_ci; + frontend_init(budget_ci); + + ttpci_budget_init_hooks(&budget_ci->budget); + + return 0; + +out3: + ttpci_budget_deinit(&budget_ci->budget); +out2: + kfree(budget_ci); +out1: + return err; +} + +static int budget_ci_detach(struct saa7146_dev *dev) +{ + struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; + struct saa7146_dev *saa = budget_ci->budget.dev; + int err; + + if (budget_ci->budget.ci_present) + ciintf_deinit(budget_ci); + msp430_ir_deinit(budget_ci); + if (budget_ci->budget.dvb_frontend) { + dvb_unregister_frontend(budget_ci->budget.dvb_frontend); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + } + err = ttpci_budget_deinit(&budget_ci->budget); + + // disable frontend and CI interface + saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); + + kfree(budget_ci); + + return err; +} + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); +MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), + MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), + MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), + MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), + MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), + MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), + MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), + MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), + MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b), + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_extension budget_extension = { + .name = "budget_ci dvb", + .flags = SAA7146_USE_I2C_IRQ, + + .module = THIS_MODULE, + .pci_tbl = &pci_tbl[0], + .attach = budget_ci_attach, + .detach = budget_ci_detach, + + .irq_mask = MASK_03 | MASK_06 | MASK_10, + .irq_func = budget_ci_irq, +}; + +static int __init budget_ci_init(void) +{ + return saa7146_register_extension(&budget_extension); +} + +static void __exit budget_ci_exit(void) +{ + saa7146_unregister_extension(&budget_extension); +} + +module_init(budget_ci_init); +module_exit(budget_ci_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called " + "budget PCI DVB cards w/ CI-module produced by " + "Siemens, Technotrend, Hauppauge"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,600 @@ +/* + * budget-core.c: driver for the SAA7146 based Budget DVB cards + * + * Compiled from various sources by Michael Hunold + * + * Copyright (C) 2002 Ralph Metzler + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * 26feb2004 Support for FS Activy Card (Grundig tuner) by + * Michael Dreher , + * Oliver Endriss , + * Andreas 'randy' Weinberger + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + + +#include "budget.h" +#include "ttpci-eeprom.h" + +#define TS_WIDTH (2 * TS_SIZE) +#define TS_WIDTH_ACTIVY TS_SIZE +#define TS_WIDTH_DVBC TS_SIZE +#define TS_HEIGHT_MASK 0xf00 +#define TS_HEIGHT_MASK_ACTIVY 0xc00 +#define TS_HEIGHT_MASK_DVBC 0xe00 +#define TS_MIN_BUFSIZE_K 188 +#define TS_MAX_BUFSIZE_K 1410 +#define TS_MAX_BUFSIZE_K_ACTIVY 564 +#define TS_MAX_BUFSIZE_K_DVBC 1316 +#define BUFFER_WARNING_WAIT (30*HZ) + +int budget_debug; +static int dma_buffer_size = TS_MIN_BUFSIZE_K; +module_param_named(debug, budget_debug, int, 0644); +module_param_named(bufsize, dma_buffer_size, int, 0444); +MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); +MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); + +/**************************************************************************** + * TT budget / WinTV Nova + ****************************************************************************/ + +static int stop_ts_capture(struct budget *budget) +{ + dprintk(2, "budget: %p\n", budget); + + saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off + SAA7146_IER_DISABLE(budget->dev, MASK_10); + return 0; +} + +static int start_ts_capture(struct budget *budget) +{ + struct saa7146_dev *dev = budget->dev; + + dprintk(2, "budget: %p\n", budget); + + if (!budget->feeding || !budget->fe_synced) + return 0; + + saa7146_write(dev, MC1, MASK_20); // DMA3 off + + memset(budget->grabbing, 0x00, budget->buffer_size); + + saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); + + budget->ttbp = 0; + + /* + * Signal path on the Activy: + * + * tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory + * + * Since the tuner feeds 204 bytes packets into the SAA7146, + * DMA3 is configured to strip the trailing 16 FEC bytes: + * Pitch: 188, NumBytes3: 188, NumLines3: 1024 + */ + + switch(budget->card->type) { + case BUDGET_FS_ACTIVY: + saa7146_write(dev, DD1_INIT, 0x04000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25)); + saa7146_write(dev, BRS_CTRL, 0x00000000); + break; + case BUDGET_PATCH: + saa7146_write(dev, DD1_INIT, 0x00000200); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + break; + case BUDGET_CIN1200C_MK3: + case BUDGET_KNC1C_MK3: + case BUDGET_KNC1CP_MK3: + if (budget->video_port == BUDGET_VIDEO_PORTA) { + saa7146_write(dev, DD1_INIT, 0x06000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x00000000); + } else { + saa7146_write(dev, DD1_INIT, 0x00000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + } + break; + default: + if (budget->video_port == BUDGET_VIDEO_PORTA) { + saa7146_write(dev, DD1_INIT, 0x06000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x00000000); + } else { + saa7146_write(dev, DD1_INIT, 0x02000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + } + } + + saa7146_write(dev, MC2, (MASK_08 | MASK_24)); + mdelay(10); + + saa7146_write(dev, BASE_ODD3, 0); + if (budget->buffer_size > budget->buffer_height * budget->buffer_width) { + // using odd/even buffers + saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width); + } else { + // using a single buffer + saa7146_write(dev, BASE_EVEN3, 0); + } + saa7146_write(dev, PROT_ADDR3, budget->buffer_size); + saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); + + saa7146_write(dev, PITCH3, budget->buffer_width); + saa7146_write(dev, NUM_LINE_BYTE3, + (budget->buffer_height << 16) | budget->buffer_width); + + saa7146_write(dev, MC2, (MASK_04 | MASK_20)); + + SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ + SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ + saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ + + return 0; +} + +static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + int synced; + int ret; + + if (budget->read_fe_status) + ret = budget->read_fe_status(fe, status); + else + ret = -EINVAL; + + if (!ret) { + synced = (*status & FE_HAS_LOCK); + if (synced != budget->fe_synced) { + budget->fe_synced = synced; + spin_lock(&budget->feedlock); + if (synced) + start_ts_capture(budget); + else + stop_ts_capture(budget); + spin_unlock(&budget->feedlock); + } + } + return ret; +} + +static void vpeirq(unsigned long data) +{ + struct budget *budget = (struct budget *) data; + u8 *mem = (u8 *) (budget->grabbing); + u32 olddma = budget->ttbp; + u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + u32 count; + + /* Ensure streamed PCI data is synced to CPU */ + pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); + + /* nearest lower position divisible by 188 */ + newdma -= newdma % 188; + + if (newdma >= budget->buffer_size) + return; + + budget->ttbp = newdma; + + if (budget->feeding == 0 || newdma == olddma) + return; + + if (newdma > olddma) { /* no wraparound, dump olddma..newdma */ + count = newdma - olddma; + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); + } else { /* wraparound, dump olddma..buflen and 0..newdma */ + count = budget->buffer_size - olddma; + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); + count += newdma; + dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188); + } + + if (count > budget->buffer_warning_threshold) + budget->buffer_warnings++; + + if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) { + printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n", + budget->dev->name, __func__, budget->buffer_warnings, count); + budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT; + budget->buffer_warnings = 0; + } +} + + +int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, + int uselocks, int nobusyloop) +{ + struct saa7146_dev *saa = budget->dev; + int result = 0; + unsigned long flags = 0; + + if (count > 4 || count <= 0) + return 0; + + if (uselocks) + spin_lock_irqsave(&budget->debilock, flags); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); + saa7146_write(saa, DEBI_CONFIG, config); + saa7146_write(saa, DEBI_PAGE, 0); + saa7146_write(saa, MC2, (2 << 16) | 2); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + result = saa7146_read(saa, DEBI_AD); + result &= (0xffffffffUL >> ((4 - count) * 8)); + + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + + return result; +} + +int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, + int count, u32 value, int uselocks, int nobusyloop) +{ + struct saa7146_dev *saa = budget->dev; + unsigned long flags = 0; + int result; + + if (count > 4 || count <= 0) + return 0; + + if (uselocks) + spin_lock_irqsave(&budget->debilock, flags); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff)); + saa7146_write(saa, DEBI_CONFIG, config); + saa7146_write(saa, DEBI_PAGE, 0); + saa7146_write(saa, DEBI_AD, value); + saa7146_write(saa, MC2, (2 << 16) | 2); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return 0; +} + + +/**************************************************************************** + * DVB API SECTION + ****************************************************************************/ + +static int budget_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct budget *budget = (struct budget *) demux->priv; + int status = 0; + + dprintk(2, "budget: %p\n", budget); + + if (!demux->dmx.frontend) + return -EINVAL; + + spin_lock(&budget->feedlock); + feed->pusi_seen = 0; /* have a clean section start */ + if (budget->feeding++ == 0) + status = start_ts_capture(budget); + spin_unlock(&budget->feedlock); + return status; +} + +static int budget_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct budget *budget = (struct budget *) demux->priv; + int status = 0; + + dprintk(2, "budget: %p\n", budget); + + spin_lock(&budget->feedlock); + if (--budget->feeding == 0) + status = stop_ts_capture(budget); + spin_unlock(&budget->feedlock); + return status; +} + +static int budget_register(struct budget *budget) +{ + struct dvb_demux *dvbdemux = &budget->demux; + int ret; + + dprintk(2, "budget: %p\n", budget); + + dvbdemux->priv = (void *) budget; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = budget_start_feed; + dvbdemux->stop_feed = budget_stop_feed; + dvbdemux->write_to_decoder = NULL; + + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&budget->demux); + + budget->dmxdev.filternum = 256; + budget->dmxdev.demux = &dvbdemux->dmx; + budget->dmxdev.capabilities = 0; + + dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter); + + budget->hw_frontend.source = DMX_FRONTEND_0; + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend); + + if (ret < 0) + return ret; + + budget->mem_frontend.source = DMX_MEMORY_FE; + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend); + if (ret < 0) + return ret; + + ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend); + if (ret < 0) + return ret; + + dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); + + return 0; +} + +static void budget_unregister(struct budget *budget) +{ + struct dvb_demux *dvbdemux = &budget->demux; + + dprintk(2, "budget: %p\n", budget); + + dvb_net_release(&budget->dvb_net); + + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend); + + dvb_dmxdev_release(&budget->dmxdev); + dvb_dmx_release(&budget->demux); +} + +int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, + struct saa7146_pci_extension_data *info, + struct module *owner, short *adapter_nums) +{ + int ret = 0; + struct budget_info *bi = info->ext_priv; + int max_bufsize; + int height_mask; + + memset(budget, 0, sizeof(struct budget)); + + dprintk(2, "dev: %p, budget: %p\n", dev, budget); + + budget->card = bi; + budget->dev = (struct saa7146_dev *) dev; + + switch(budget->card->type) { + case BUDGET_FS_ACTIVY: + budget->buffer_width = TS_WIDTH_ACTIVY; + max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; + height_mask = TS_HEIGHT_MASK_ACTIVY; + break; + + case BUDGET_KNC1C: + case BUDGET_KNC1CP: + case BUDGET_CIN1200C: + case BUDGET_KNC1C_MK3: + case BUDGET_KNC1CP_MK3: + case BUDGET_CIN1200C_MK3: + budget->buffer_width = TS_WIDTH_DVBC; + max_bufsize = TS_MAX_BUFSIZE_K_DVBC; + height_mask = TS_HEIGHT_MASK_DVBC; + break; + + default: + budget->buffer_width = TS_WIDTH; + max_bufsize = TS_MAX_BUFSIZE_K; + height_mask = TS_HEIGHT_MASK; + } + + if (dma_buffer_size < TS_MIN_BUFSIZE_K) + dma_buffer_size = TS_MIN_BUFSIZE_K; + else if (dma_buffer_size > max_bufsize) + dma_buffer_size = max_bufsize; + + budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; + if (budget->buffer_height > 0xfff) { + budget->buffer_height /= 2; + budget->buffer_height &= height_mask; + budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width; + } else { + budget->buffer_height &= height_mask; + budget->buffer_size = budget->buffer_height * budget->buffer_width; + } + budget->buffer_warning_threshold = budget->buffer_size * 80/100; + budget->buffer_warnings = 0; + budget->buffer_warning_time = jiffies; + + dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n", + budget->dev->name, + budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single", + budget->buffer_width, budget->buffer_height); + printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); + + ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, + owner, &budget->dev->pci->dev, adapter_nums); + if (ret < 0) + return ret; + + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25)); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + saa7146_write(dev, DD1_INIT, 0x02000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + if (bi->type != BUDGET_FS_ACTIVY) + budget->video_port = BUDGET_VIDEO_PORTB; + else + budget->video_port = BUDGET_VIDEO_PORTA; + spin_lock_init(&budget->feedlock); + spin_lock_init(&budget->debilock); + + /* the Siemens DVB needs this if you want to have the i2c chips + get recognized before the main driver is loaded */ + if (bi->type != BUDGET_FS_ACTIVY) + saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */ + + strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name)); + + saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); + strcpy(budget->i2c_adap.name, budget->card->name); + + if (i2c_add_adapter(&budget->i2c_adap) < 0) { + ret = -ENOMEM; + goto err_dvb_unregister; + } + + ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); + + budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt); + if (NULL == budget->grabbing) { + ret = -ENOMEM; + goto err_del_i2c; + } + + saa7146_write(dev, PCI_BT_V1, 0x001c0000); + /* upload all */ + saa7146_write(dev, GPIO_CTRL, 0x000000); + + tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget); + + /* frontend power on */ + if (bi->type != BUDGET_FS_ACTIVY) + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + + if ((ret = budget_register(budget)) == 0) + return 0; /* Everything OK */ + + /* An error occurred, cleanup resources */ + saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); + +err_del_i2c: + i2c_del_adapter(&budget->i2c_adap); + +err_dvb_unregister: + dvb_unregister_adapter(&budget->dvb_adapter); + + return ret; +} + +void ttpci_budget_init_hooks(struct budget *budget) +{ + if (budget->dvb_frontend && !budget->read_fe_status) { + budget->read_fe_status = budget->dvb_frontend->ops.read_status; + budget->dvb_frontend->ops.read_status = budget_read_fe_status; + } +} + +int ttpci_budget_deinit(struct budget *budget) +{ + struct saa7146_dev *dev = budget->dev; + + dprintk(2, "budget: %p\n", budget); + + budget_unregister(budget); + + tasklet_kill(&budget->vpe_tasklet); + + saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); + + i2c_del_adapter(&budget->i2c_adap); + + dvb_unregister_adapter(&budget->dvb_adapter); + + return 0; +} + +void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr) +{ + struct budget *budget = (struct budget *) dev->ext_priv; + + dprintk(8, "dev: %p, budget: %p\n", dev, budget); + + if (*isr & MASK_10) + tasklet_schedule(&budget->vpe_tasklet); +} + +void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port) +{ + struct budget *budget = (struct budget *) dev->ext_priv; + + spin_lock(&budget->feedlock); + budget->video_port = video_port; + if (budget->feeding) { + stop_ts_capture(budget); + start_ts_capture(budget); + } + spin_unlock(&budget->feedlock); +} + +EXPORT_SYMBOL_GPL(ttpci_budget_debiread); +EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite); +EXPORT_SYMBOL_GPL(ttpci_budget_init); +EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks); +EXPORT_SYMBOL_GPL(ttpci_budget_deinit); +EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); +EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port); +EXPORT_SYMBOL_GPL(budget_debug); + +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,123 @@ + +#ifndef __BUDGET_DVB__ +#define __BUDGET_DVB__ + +#include "dvb_frontend.h" +#include "dvbdev.h" +#include "demux.h" +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_filter.h" +#include "dvb_net.h" + +#include +#include + +#include + +extern int budget_debug; + +#ifdef dprintk +#undef dprintk +#endif + +#define dprintk(level,args...) \ + do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __func__); printk(args); } } while (0) + +struct budget_info { + char *name; + int type; +}; + +/* place to store all the necessary device information */ +struct budget { + + /* devices */ + struct dvb_device dvb_dev; + struct dvb_net dvb_net; + + struct saa7146_dev *dev; + + struct i2c_adapter i2c_adap; + struct budget_info *card; + + unsigned char *grabbing; + struct saa7146_pgtable pt; + + struct tasklet_struct fidb_tasklet; + struct tasklet_struct vpe_tasklet; + + struct dmxdev dmxdev; + struct dvb_demux demux; + + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + + int ci_present; + int video_port; + + u32 buffer_width; + u32 buffer_height; + u32 buffer_size; + u32 buffer_warning_threshold; + u32 buffer_warnings; + unsigned long buffer_warning_time; + + u32 ttbp; + int feeding; + + spinlock_t feedlock; + + spinlock_t debilock; + + struct dvb_adapter dvb_adapter; + struct dvb_frontend *dvb_frontend; + int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status); + int fe_synced; + + void *priv; +}; + +#define MAKE_BUDGET_INFO(x_var,x_name,x_type) \ +static struct budget_info x_var ## _info = { \ + .name=x_name, \ + .type=x_type }; \ +static struct saa7146_pci_extension_data x_var = { \ + .ext_priv = &x_var ## _info, \ + .ext = &budget_extension }; + +#define BUDGET_TT 0 +#define BUDGET_TT_HW_DISEQC 1 +#define BUDGET_PATCH 3 +#define BUDGET_FS_ACTIVY 4 +#define BUDGET_CIN1200S 5 +#define BUDGET_CIN1200C 6 +#define BUDGET_CIN1200T 7 +#define BUDGET_KNC1S 8 +#define BUDGET_KNC1C 9 +#define BUDGET_KNC1T 10 +#define BUDGET_KNC1SP 11 +#define BUDGET_KNC1CP 12 +#define BUDGET_KNC1TP 13 +#define BUDGET_TVSTAR 14 +#define BUDGET_CIN1200C_MK3 15 +#define BUDGET_KNC1C_MK3 16 +#define BUDGET_KNC1CP_MK3 17 +#define BUDGET_KNC1S2 18 + +#define BUDGET_VIDEO_PORTA 0 +#define BUDGET_VIDEO_PORTB 1 + +extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, + struct saa7146_pci_extension_data *info, + struct module *owner, short *adapter_nums); +extern void ttpci_budget_init_hooks(struct budget *budget); +extern int ttpci_budget_deinit(struct budget *budget); +extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr); +extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port); +extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, + int uselocks, int nobusyloop); +extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value, + int uselocks, int nobusyloop); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-patch.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-patch.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-patch.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/budget-patch.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,673 @@ +/* + * budget-patch.c: driver for Budget Patch, + * hardware modification of DVB-S cards enabling full TS + * + * Written by Emard + * + * Original idea by Roberto Deza + * + * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic + * and Metzlerbros + * + * 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, or (at your option) any later version. + * + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org/ + */ + +#include "av7110.h" +#include "av7110_hw.h" +#include "budget.h" +#include "stv0299.h" +#include "ves1x93.h" +#include "tda8083.h" + +#include "bsru6.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define budget_patch budget + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH); +//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC); + +static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000), +// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), + { + .vendor = 0, + } +}; + +/* those lines are for budget-patch to be tried +** on a true budget card and observe the +** behaviour of VSYNC generated by rps1. +** this code was shamelessly copy/pasted from budget.c +*/ +static void gpio_Set22K (struct budget *budget, int state) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); +} + +/* Diseqc functions only for TT Budget card */ +/* taken from the Skyvision DVB driver by + Ralph Metzler */ + +static void DiseqcSendBit (struct budget *budget, int data) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + udelay(data ? 500 : 1000); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + udelay(data ? 1000 : 500); +} + +static void DiseqcSendByte (struct budget *budget, int data) +{ + int i, par=1, d; + + dprintk(2, "budget: %p\n", budget); + + for (i=7; i>=0; i--) { + d = (data>>i)&1; + par ^= d; + DiseqcSendBit(budget, d); + } + + DiseqcSendBit(budget, par); +} + +static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) +{ + struct saa7146_dev *dev=budget->dev; + int i; + + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + mdelay(16); + + for (i=0; idvb->priv; + + switch (tone) { + case SEC_TONE_ON: + gpio_Set22K (budget, 1); + break; + + case SEC_TONE_OFF: + gpio_Set22K (budget, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); + + return 0; +} + +static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, 0, NULL, minicmd); + + return 0; +} + +static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length) +{ + int i; + + dprintk(2, "budget: %p\n", budget); + + for (i = 2; i < length; i++) + { + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0); + msleep(5); + } + if (length) + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0); + else + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0); + msleep(5); + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0); + msleep(5); + return 0; +} + +static void av7110_set22k(struct budget_patch *budget, int state) +{ + u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0}; + + dprintk(2, "budget: %p\n", budget); + budget_av7110_send_fw_cmd(budget, buf, 2); +} + +static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst) +{ + int i; + u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + dprintk(2, "budget: %p\n", budget); + + if (len>10) + len=10; + + buf[1] = len+2; + buf[2] = len; + + if (burst != -1) + buf[3]=burst ? 0x01 : 0x00; + else + buf[3]=0xffff; + + for (i=0; idvb->priv; + + switch (tone) { + case SEC_TONE_ON: + av7110_set22k (budget, 1); + break; + + case SEC_TONE_OFF: + av7110_set22k (budget, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + + av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0); + + return 0; +} + +static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + + av7110_send_diseqc_msg (budget, 0, NULL, minicmd); + + return 0; +} + +static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (params->frequency + 479500) / 125; + + if (params->frequency > 2000000) pwr = 3; + else if (params->frequency > 1800000) pwr = 2; + else if (params->frequency > 1600000) pwr = 1; + else if (params->frequency > 1200000) pwr = 0; + else if (params->frequency >= 1100000) pwr = 1; + else pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; + + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = { + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, +}; + +static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = params->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, +}; + +static void frontend_init(struct budget_patch* budget) +{ + switch(budget->dev->pci->subsystem_device) { + case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X + case 0x1013: // SATELCO Multimedia PCI + + // try the ALPS BSRV2 first of all + budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_patch_set_tone; + break; + } + + // try the ALPS BSRU6 now + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + break; + } + + // Try the grundig 29504-451 + budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + break; + } + break; + } + + if (budget->dvb_frontend == NULL) { + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + budget->dev->pci->vendor, + budget->dev->pci->device, + budget->dev->pci->subsystem_vendor, + budget->dev->pci->subsystem_device); + } else { + if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { + printk("budget-av: Frontend registration failed!\n"); + dvb_frontend_detach(budget->dvb_frontend); + budget->dvb_frontend = NULL; + } + } +} + +/* written by Emard */ +static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) +{ + struct budget_patch *budget; + int err; + int count = 0; + int detected = 0; + +#define PATCH_RESET 0 +#define RPS_IRQ 0 +#define HPS_SETUP 0 +#if PATCH_RESET + saa7146_write(dev, MC1, MASK_31); + msleep(40); +#endif +#if HPS_SETUP + // initialize registers. Better to have it like this + // than leaving something unconfigured + saa7146_write(dev, DD1_STREAM_B, 0); + // port B VSYNC at rising edge + saa7146_write(dev, DD1_INIT, 0x00000200); // have this in budget-core too! + saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI + + // debi config + // saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18); + + // zero all HPS registers + saa7146_write(dev, HPS_H_PRESCALE, 0); // r68 + saa7146_write(dev, HPS_H_SCALE, 0); // r6c + saa7146_write(dev, BCS_CTRL, 0); // r70 + saa7146_write(dev, HPS_V_SCALE, 0); // r60 + saa7146_write(dev, HPS_V_GAIN, 0); // r64 + saa7146_write(dev, CHROMA_KEY_RANGE, 0); // r74 + saa7146_write(dev, CLIP_FORMAT_CTRL, 0); // r78 + // Set HPS prescaler for port B input + saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) ); + saa7146_write(dev, MC2, + 0 * (MASK_08 | MASK_24) | // BRS control + 0 * (MASK_09 | MASK_25) | // a + 0 * (MASK_10 | MASK_26) | // b + 1 * (MASK_06 | MASK_22) | // HPS_CTRL1 + 1 * (MASK_05 | MASK_21) | // HPS_CTRL2 + 0 * (MASK_01 | MASK_15) // DEBI + ); +#endif + // Disable RPS1 and RPS0 + saa7146_write(dev, MC1, ( MASK_29 | MASK_28)); + // RPS1 timeout disable + saa7146_write(dev, RPS_TOV1, 0); + + // code for autodetection + // will wait for VBI_B event (vertical blank at port B) + // and will reset GPIO3 after VBI_B is detected. + // (GPIO3 should be raised high by CPU to + // test if GPIO3 will generate vertical blank signal + // in budget patch GPIO3 is connected to VSYNC_B + count = 0; +#if 0 + WRITE_RPS1(CMD_UPLOAD | + MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ); +#endif + WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + // issue RPS1 interrupt to increment counter + WRITE_RPS1(CMD_INTERRUPT); + // at least a NOP is neede between two interrupts + WRITE_RPS1(CMD_NOP); + // interrupt again + WRITE_RPS1(CMD_INTERRUPT); +#endif + WRITE_RPS1(CMD_STOP); + +#if RPS_IRQ + // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + // set event counter 1 threshold to maximum allowed value (rEC p55) + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + // Fix VSYNC level + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + // Set RPS1 Address register to point to RPS code (r108 p42) + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + // Enable RPS1, (rFC p33) + saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); + + + mdelay(50); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + mdelay(150); + + + if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) + detected = 1; + +#if RPS_IRQ + printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); +#endif + // Disable RPS1 + saa7146_write(dev, MC1, ( MASK_29 )); + + if(detected == 0) + printk("budget-patch not detected or saa7146 in non-default state.\n" + "try enabling ressetting of 7146 with MASK_31 in MC1 register\n"); + + else + printk("BUDGET-PATCH DETECTED.\n"); + + +/* OLD (Original design by Roberto Deza): +** This code will setup the SAA7146_RPS1 to generate a square +** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of +** TS_WIDTH packets) has been acquired on SAA7146_D1B video port; +** then, this GPIO3 output which is connected to the D1B_VSYNC +** input, will trigger the acquisition of the alternate field +** and so on. +** Currently, the TT_budget / WinTV_Nova cards have two ICs +** (74HCT4040, LVC74) for the generation of this VSYNC signal, +** which seems that can be done perfectly without this :-)). +*/ + +/* New design (By Emard) +** this rps1 code will copy internal HS event to GPIO3 pin. +** GPIO3 is in budget-patch hardware connected to port B VSYNC + +** HS is an internal event of 7146, accessible with RPS +** and temporarily raised high every n lines +** (n in defined in the RPS_THRESH1 counter threshold) +** I think HS is raised high on the beginning of the n-th line +** and remains high until this n-th line that triggered +** it is completely received. When the reception of n-th line +** ends, HS is lowered. + +** To transmit data over DMA, 7146 needs changing state at +** port B VSYNC pin. Any changing of port B VSYNC will +** cause some DMA data transfer, with more or less packets loss. +** It depends on the phase and frequency of VSYNC and +** the way of 7146 is instructed to trigger on port B (defined +** in DD1_INIT register, 3rd nibble from the right valid +** numbers are 0-7, see datasheet) +** +** The correct triggering can minimize packet loss, +** dvbtraffic should give this stable bandwidths: +** 22k transponder = 33814 kbit/s +** 27.5k transponder = 38045 kbit/s +** by experiment it is found that the best results +** (stable bandwidths and almost no packet loss) +** are obtained using DD1_INIT triggering number 2 +** (Va at rising edge of VS Fa = HS x VS-failing forced toggle) +** and a VSYNC phase that occurs in the middle of DMA transfer +** (about byte 188*512=96256 in the DMA window). +** +** Phase of HS is still not clear to me how to control, +** It just happens to be so. It can be seen if one enables +** RPS_IRQ and print Event Counter 1 in vpeirq(). Every +** time RPS_INTERRUPT is called, the Event Counter 1 will +** increment. That's how the 7146 is programmed to do event +** counting in this budget-patch.c +** I *think* HPS setting has something to do with the phase +** of HS but I can't be 100% sure in that. + +** hardware debug note: a working budget card (including budget patch) +** with vpeirq() interrupt setup in mode "0x90" (every 64K) will +** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes +** and that means 3*25=75 Hz of interrupt frequency, as seen by +** watch cat /proc/interrupts +** +** If this frequency is 3x lower (and data received in the DMA +** buffer don't start with 0x47, but in the middle of packets, +** whose lengths appear to be like 188 292 188 104 etc. +** this means VSYNC line is not connected in the hardware. +** (check soldering pcb and pins) +** The same behaviour of missing VSYNC can be duplicated on budget +** cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. +*/ + + // Setup RPS1 "program" (p35) + count = 0; + + + // Wait Source Line Counter Threshold (p36) + WRITE_RPS1(CMD_PAUSE | EVT_HS); + // Set GPIO3=1 (p42) + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); +#if RPS_IRQ + // issue RPS1 interrupt + WRITE_RPS1(CMD_INTERRUPT); +#endif + // Wait reset Source Line Counter Threshold (p36) + WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); + // Set GPIO3=0 (p42) + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + // issue RPS1 interrupt + WRITE_RPS1(CMD_INTERRUPT); +#endif + // Jump to begin of RPS program (p37) + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); + + // Fix VSYNC level + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + // Set RPS1 Address register to point to RPS code (r108 p42) + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + + if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) + return -ENOMEM; + + dprintk(2, "budget: %p\n", budget); + + err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); + if (err) { + kfree(budget); + return err; + } + + // Set Source Line Counter Threshold, using BRS (rCC p43) + // It generates HS event every TS_HEIGHT lines + // this is related to TS_WIDTH set in register + // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE + // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188 + //,then RPS_THRESH1 + // should be set to trigger every TS_HEIGHT (512) lines. + // + saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 ); + + // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); + // Enable RPS1 (rFC p33) + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + + dev->ext_priv = budget; + + budget->dvb_adapter.priv = budget; + frontend_init(budget); + + ttpci_budget_init_hooks(budget); + + return 0; +} + +static int budget_patch_detach (struct saa7146_dev* dev) +{ + struct budget_patch *budget = (struct budget_patch*) dev->ext_priv; + int err; + + if (budget->dvb_frontend) { + dvb_unregister_frontend(budget->dvb_frontend); + dvb_frontend_detach(budget->dvb_frontend); + } + err = ttpci_budget_deinit (budget); + + kfree (budget); + + return err; +} + +static int __init budget_patch_init(void) +{ + return saa7146_register_extension(&budget_extension); +} + +static void __exit budget_patch_exit(void) +{ + saa7146_unregister_extension(&budget_extension); +} + +static struct saa7146_extension budget_extension = { + .name = "budget_patch dvb", + .flags = 0, + + .module = THIS_MODULE, + .pci_tbl = pci_tbl, + .attach = budget_patch_attach, + .detach = budget_patch_detach, + + .irq_mask = MASK_10, + .irq_func = ttpci_budget_irq10_handler, +}; + +module_init(budget_patch_init); +module_exit(budget_patch_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others"); +MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 " + "based so-called Budget Patch cards"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,159 @@ +config TTPCI_EEPROM + tristate + depends on I2C + default n + +config DVB_AV7110 + tristate "AV7110 cards" + depends on DVB_CORE && PCI && I2C + select TTPCI_EEPROM + select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV + select DVB_VES1820 if !DVB_FE_CUSTOMISE + select DVB_VES1X93 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_TDA8083 if !DVB_FE_CUSTOMISE + select DVB_SP8870 if !DVB_FE_CUSTOMISE + select DVB_STV0297 if !DVB_FE_CUSTOMISE + select DVB_L64781 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + help + Support for SAA7146 and AV7110 based DVB cards as produced + by Fujitsu-Siemens, Technotrend, Hauppauge and others. + + This driver only supports the fullfeatured cards with + onboard MPEG2 decoder. + + This driver needs an external firmware. Please use the script + "/Documentation/dvb/get_dvb_firmware av7110" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + + Alternatively, you can download the file and use the kernel's + EXTRA_FIRMWARE configuration option to build it into your + kernel image by adding the filename to the EXTRA_FIRMWARE + configuration option string. + + Say Y if you own such a card and want to use it. + +config DVB_AV7110_OSD + bool "AV7110 OSD support" + depends on DVB_AV7110 + default y if DVB_AV7110=y || DVB_AV7110=m + help + The AV7110 firmware provides some code to generate an OnScreenDisplay + on the video output. This is kind of nonstandard and not guaranteed to + be maintained. + + Anyway, some popular DVB software like VDR uses this OSD to render + its menus, so say Y if you want to use this software. + + All other people say N. + +config DVB_BUDGET_CORE + tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" + depends on DVB_CORE && PCI && I2C + select VIDEO_SAA7146 + select TTPCI_EEPROM + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder. + +config DVB_BUDGET + tristate "Budget cards" + depends on DVB_BUDGET_CORE && I2C + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_VES1X93 if !DVB_FE_CUSTOMISE + select DVB_VES1820 if !DVB_FE_CUSTOMISE + select DVB_L64781 if !DVB_FE_CUSTOMISE + select DVB_TDA8083 if !DVB_FE_CUSTOMISE + select DVB_S5H1420 if !DVB_FE_CUSTOMISE + select DVB_TDA10086 if !DVB_FE_CUSTOMISE + select DVB_TDA826X if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_ISL6423 if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE + help + Support for simple SAA7146 based DVB cards (so called Budget- + or Nova-PCI cards) without onboard MPEG2 decoder, and without + analog inputs or an onboard Common Interface connector. + + Say Y if you own such a card and want to use it. + + To compile this driver as a module, choose M here: the + module will be called budget. + +config DVB_BUDGET_CI + tristate "Budget cards with onboard CI connector" + depends on DVB_BUDGET_CORE && I2C + select DVB_STV0297 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE + depends on RC_CORE + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder, but with onboard Common Interface connector. + + Note: The Common Interface is not yet supported by this driver + due to lack of information from the vendor. + + Say Y if you own such a card and want to use it. + + To compile this driver as a module, choose M here: the + module will be called budget-ci. + +config DVB_BUDGET_AV + tristate "Budget cards with analog video inputs" + depends on DVB_BUDGET_CORE && I2C + select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_TDA10021 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_TDA8261 if !DVB_FE_CUSTOMISE + select DVB_TUA6100 if !DVB_FE_CUSTOMISE + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder, but with one or more analog video inputs. + + Say Y if you own such a card and want to use it. + + To compile this driver as a module, choose M here: the + module will be called budget-av. + +config DVB_BUDGET_PATCH + tristate "AV7110 cards with Budget Patch" + depends on DVB_BUDGET_CORE && I2C + depends on DVB_AV7110 + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_VES1X93 if !DVB_FE_CUSTOMISE + select DVB_TDA8083 if !DVB_FE_CUSTOMISE + help + Support for Budget Patch (full TS) modification on + SAA7146+AV7110 based cards (DVB-S cards). This + driver doesn't use onboard MPEG2 decoder. The + card is driven in Budget-only mode. Card is + required to have loaded firmware to tune properly. + Firmware can be loaded by insertion and removal of + standard AV7110 driver prior to loading this + driver. + + Say Y if you own such a card and want to use it. + + To compile this driver as a module, choose M here: the + module will be called budget-patch. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,21 @@ +# +# Makefile for the kernel SAA7146 FULL TS DVB device driver +# and the AV7110 DVB device driver +# + +dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o + +ifdef CONFIG_INPUT_EVDEV +dvb-ttpci-objs += av7110_ir.o +endif + +obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o +obj-$(CONFIG_DVB_BUDGET) += budget.o +obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o +obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o +obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o +obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/ttpci-eeprom.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/ttpci-eeprom.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/ttpci-eeprom.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/ttpci-eeprom.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,147 @@ +/* + Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM, + decode it and store it in the associated adapter struct for + use by dvb_net.c + + This card appear to have the 24C16 write protect held to ground, + thus permitting normal read/write operation. Theoretically it + would be possible to write routines to burn a different (encoded) + MAC address into the EEPROM. + + Robert Schlabbach GMX + Michael Glaum KVH Industries + Holger Waechtler Convergence + + Copyright (C) 2002-2003 Ralph Metzler + Metzler Brothers Systementwicklung GbR + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include + +#include "ttpci-eeprom.h" + +#if 1 +#define dprintk(x...) do { printk(x); } while (0) +#else +#define dprintk(x...) do { } while (0) +#endif + + +static int check_mac_tt(u8 *buf) +{ + int i; + u16 tmp = 0xffff; + + for (i = 0; i < 8; i++) { + tmp = (tmp << 8) | ((tmp >> 8) ^ buf[i]); + tmp ^= (tmp >> 4) & 0x0f; + tmp ^= (tmp << 12) ^ ((tmp & 0xff) << 5); + } + tmp ^= 0xffff; + return (((tmp >> 8) ^ buf[8]) | ((tmp & 0xff) ^ buf[9])); +} + +static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC) +{ + u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, + 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, + 0x1d, 0x36, 0x64, 0x78}; + u8 data[20]; + int i; + + /* In case there is a sig check failure have the orig contents available */ + memcpy(data, encodedMAC, 20); + + for (i = 0; i < 20; i++) + data[i] ^= xor[i]; + for (i = 0; i < 10; i++) + data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) + >> ((data[2 * i + 1] >> 6) & 3); + + if (check_mac_tt(data)) + return -ENODEV; + + decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0]; + decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4]; + return 0; +} + +static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC) +{ + int ret; + u8 b0[] = { 0xcc }; + + struct i2c_msg msg[] = { + { .addr = 0x50, .flags = 0, .buf = b0, .len = 1 }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 } + }; + + /* dprintk("%s\n", __func__); */ + + ret = i2c_transfer(adapter, msg, 2); + + if (ret != 2) /* Assume EEPROM isn't there */ + return (-ENODEV); + + return 0; +} + + +int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) +{ + int ret, i; + u8 encodedMAC[20]; + u8 decodedMAC[6]; + + ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC); + + if (ret != 0) { /* Will only be -ENODEV */ + dprintk("Couldn't read from EEPROM: not there?\n"); + memset(proposed_mac, 0, 6); + return ret; + } + + ret = getmac_tt(decodedMAC, encodedMAC); + if( ret != 0 ) { + dprintk("adapter failed MAC signature check\n"); + dprintk("encoded MAC from EEPROM was " ); + for(i=0; i<19; i++) { + dprintk( "%.2x:", encodedMAC[i]); + } + dprintk("%.2x\n", encodedMAC[19]); + memset(proposed_mac, 0, 6); + return ret; + } + + memcpy(proposed_mac, decodedMAC, 6); + dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + decodedMAC[0], decodedMAC[1], decodedMAC[2], + decodedMAC[3], decodedMAC[4], decodedMAC[5]); + return 0; +} + +EXPORT_SYMBOL(ttpci_eeprom_parse_mac); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); +MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards " + "made by Siemens, Technotrend, Hauppauge"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/ttpci-eeprom.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/ttpci-eeprom.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/ttpci-eeprom.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttpci/ttpci-eeprom.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Retrieve encoded MAC address from ATMEL ttpci_eeprom serial 2-wire EEPROM, + decode it and store it in associated adapter net device + + Robert Schlabbach GMX + Michael Glaum KVH Industries + Holger Waechtler Convergence + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __TTPCI_EEPROM_H__ +#define __TTPCI_EEPROM_H__ + +#include +#include + +extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1821 @@ +/* + * TTUSB DVB driver + * + * Copyright (c) 2002 Holger Waechtler + * Copyright (c) 2003 Felix Domke + * + * 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, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_net.h" +#include "ves1820.h" +#include "cx22700.h" +#include "tda1004x.h" +#include "stv0299.h" +#include "tda8083.h" +#include "stv0297.h" +#include "lnbp21.h" + +#include +#include +#include + +/* + TTUSB_HWSECTIONS: + the DSP supports filtering in hardware, however, since the "muxstream" + is a bit braindead (no matching channel masks or no matching filter mask), + we won't support this - yet. it doesn't event support negative filters, + so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just + parse TS data. USB bandwidth will be a problem when having large + datastreams, especially for dvb-net, but hey, that's not my problem. + + TTUSB_DISEQC, TTUSB_TONE: + let the STC do the diseqc/tone stuff. this isn't supported at least with + my TTUSB, so let it undef'd unless you want to implement another + frontend. never tested. + + debug: + define it to > 3 for really hardcore debugging. you probably don't want + this unless the device doesn't load at all. > 2 for bandwidth statistics. +*/ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0) + +#define ISO_BUF_COUNT 4 +#define FRAMES_PER_ISO_BUF 4 +#define ISO_FRAME_SIZE 912 +#define TTUSB_MAXCHANNEL 32 +#ifdef TTUSB_HWSECTIONS +#define TTUSB_MAXFILTER 16 /* ??? */ +#endif + +#define TTUSB_REV_2_2 0x22 +#define TTUSB_BUDGET_NAME "ttusb_stc_fw" + +/** + * since we're casting (struct ttusb*) <-> (struct dvb_demux*) around + * the dvb_demux field must be the first in struct!! + */ +struct ttusb { + struct dvb_demux dvb_demux; + struct dmxdev dmxdev; + struct dvb_net dvbnet; + + /* and one for USB access. */ + struct mutex semi2c; + struct mutex semusb; + + struct dvb_adapter adapter; + struct usb_device *dev; + + struct i2c_adapter i2c_adap; + + int disconnecting; + int iso_streaming; + + unsigned int bulk_out_pipe; + unsigned int bulk_in_pipe; + unsigned int isoc_in_pipe; + + void *iso_buffer; + dma_addr_t iso_dma_handle; + + struct urb *iso_urb[ISO_BUF_COUNT]; + + int running_feed_count; + int last_channel; + int last_filter; + + u8 c; /* transaction counter, wraps around... */ + fe_sec_tone_mode_t tone; + fe_sec_voltage_t voltage; + + int mux_state; // 0..2 - MuxSyncWord, 3 - nMuxPacks, 4 - muxpack + u8 mux_npacks; + u8 muxpack[256 + 8]; + int muxpack_ptr, muxpack_len; + + int insync; + + int cc; /* MuxCounter - will increment on EVERY MUX PACKET */ + /* (including stuffing. yes. really.) */ + + u8 last_result[32]; + + int revision; + + struct dvb_frontend* fe; +}; + +/* ugly workaround ... don't know why it's necessary to read */ +/* all result codes. */ + +static int ttusb_cmd(struct ttusb *ttusb, + const u8 * data, int len, int needresult) +{ + int actual_len; + int err; + int i; + + if (debug >= 3) { + printk(KERN_DEBUG ">"); + for (i = 0; i < len; ++i) + printk(KERN_CONT " %02x", data[i]); + printk(KERN_CONT "\n"); + } + + if (mutex_lock_interruptible(&ttusb->semusb) < 0) + return -EAGAIN; + + err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe, + (u8 *) data, len, &actual_len, 1000); + if (err != 0) { + dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n", + __func__, err); + mutex_unlock(&ttusb->semusb); + return err; + } + if (actual_len != len) { + dprintk("%s: only wrote %d of %d bytes\n", __func__, + actual_len, len); + mutex_unlock(&ttusb->semusb); + return -1; + } + + err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe, + ttusb->last_result, 32, &actual_len, 1000); + + if (err != 0) { + printk("%s: failed, receive error %d\n", __func__, + err); + mutex_unlock(&ttusb->semusb); + return err; + } + + if (debug >= 3) { + actual_len = ttusb->last_result[3] + 4; + printk(KERN_DEBUG "<"); + for (i = 0; i < actual_len; ++i) + printk(KERN_CONT " %02x", ttusb->last_result[i]); + printk(KERN_CONT "\n"); + } + + if (!needresult) + mutex_unlock(&ttusb->semusb); + return 0; +} + +static int ttusb_result(struct ttusb *ttusb, u8 * data, int len) +{ + memcpy(data, ttusb->last_result, len); + mutex_unlock(&ttusb->semusb); + return 0; +} + +static int ttusb_i2c_msg(struct ttusb *ttusb, + u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf, + u8 rcv_len) +{ + u8 b[0x28]; + u8 id = ++ttusb->c; + int i, err; + + if (snd_len > 0x28 - 7 || rcv_len > 0x20 - 7) + return -EINVAL; + + b[0] = 0xaa; + b[1] = id; + b[2] = 0x31; + b[3] = snd_len + 3; + b[4] = addr << 1; + b[5] = snd_len; + b[6] = rcv_len; + + for (i = 0; i < snd_len; i++) + b[7 + i] = snd_buf[i]; + + err = ttusb_cmd(ttusb, b, snd_len + 7, 1); + + if (err) + return -EREMOTEIO; + + err = ttusb_result(ttusb, b, 0x20); + + /* check if the i2c transaction was successful */ + if ((snd_len != b[5]) || (rcv_len != b[6])) return -EREMOTEIO; + + if (rcv_len > 0) { + + if (err || b[0] != 0x55 || b[1] != id) { + dprintk + ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ", + __func__, err, id); + return -EREMOTEIO; + } + + for (i = 0; i < rcv_len; i++) + rcv_buf[i] = b[7 + i]; + } + + return rcv_len; +} + +static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) +{ + struct ttusb *ttusb = i2c_get_adapdata(adapter); + int i = 0; + int inc; + + if (mutex_lock_interruptible(&ttusb->semi2c) < 0) + return -EAGAIN; + + while (i < num) { + u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf; + int err; + + if (num > i + 1 && (msg[i + 1].flags & I2C_M_RD)) { + addr = msg[i].addr; + snd_buf = msg[i].buf; + snd_len = msg[i].len; + rcv_buf = msg[i + 1].buf; + rcv_len = msg[i + 1].len; + inc = 2; + } else { + addr = msg[i].addr; + snd_buf = msg[i].buf; + snd_len = msg[i].len; + rcv_buf = NULL; + rcv_len = 0; + inc = 1; + } + + err = ttusb_i2c_msg(ttusb, addr, + snd_buf, snd_len, rcv_buf, rcv_len); + + if (err < rcv_len) { + dprintk("%s: i == %i\n", __func__, i); + break; + } + + i += inc; + } + + mutex_unlock(&ttusb->semi2c); + return i; +} + +static int ttusb_boot_dsp(struct ttusb *ttusb) +{ + const struct firmware *fw; + int i, err; + u8 b[40]; + + err = request_firmware(&fw, "ttusb-budget/dspbootcode.bin", + &ttusb->dev->dev); + if (err) { + printk(KERN_ERR "ttusb-budget: failed to request firmware\n"); + return err; + } + + /* BootBlock */ + b[0] = 0xaa; + b[2] = 0x13; + b[3] = 28; + + /* upload dsp code in 32 byte steps (36 didn't work for me ...) */ + /* 32 is max packet size, no messages should be splitted. */ + for (i = 0; i < fw->size; i += 28) { + memcpy(&b[4], &fw->data[i], 28); + + b[1] = ++ttusb->c; + + err = ttusb_cmd(ttusb, b, 32, 0); + if (err) + goto done; + } + + /* last block ... */ + b[1] = ++ttusb->c; + b[2] = 0x13; + b[3] = 0; + + err = ttusb_cmd(ttusb, b, 4, 0); + if (err) + goto done; + + /* BootEnd */ + b[1] = ++ttusb->c; + b[2] = 0x14; + b[3] = 0; + + err = ttusb_cmd(ttusb, b, 4, 0); + + done: + release_firmware(fw); + if (err) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __func__, err); + } + + return err; +} + +static int ttusb_set_channel(struct ttusb *ttusb, int chan_id, int filter_type, + int pid) +{ + int err; + /* SetChannel */ + u8 b[] = { 0xaa, ++ttusb->c, 0x22, 4, chan_id, filter_type, + (pid >> 8) & 0xff, pid & 0xff + }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} + +static int ttusb_del_channel(struct ttusb *ttusb, int channel_id) +{ + int err; + /* DelChannel */ + u8 b[] = { 0xaa, ++ttusb->c, 0x23, 1, channel_id }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} + +#ifdef TTUSB_HWSECTIONS +static int ttusb_set_filter(struct ttusb *ttusb, int filter_id, + int associated_chan, u8 filter[8], u8 mask[8]) +{ + int err; + /* SetFilter */ + u8 b[] = { 0xaa, 0, 0x24, 0x1a, filter_id, associated_chan, + filter[0], filter[1], filter[2], filter[3], + filter[4], filter[5], filter[6], filter[7], + filter[8], filter[9], filter[10], filter[11], + mask[0], mask[1], mask[2], mask[3], + mask[4], mask[5], mask[6], mask[7], + mask[8], mask[9], mask[10], mask[11] + }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} + +static int ttusb_del_filter(struct ttusb *ttusb, int filter_id) +{ + int err; + /* DelFilter */ + u8 b[] = { 0xaa, ++ttusb->c, 0x25, 1, filter_id }; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + return err; +} +#endif + +static int ttusb_init_controller(struct ttusb *ttusb) +{ + u8 b0[] = { 0xaa, ++ttusb->c, 0x15, 1, 0 }; + u8 b1[] = { 0xaa, ++ttusb->c, 0x15, 1, 1 }; + u8 b2[] = { 0xaa, ++ttusb->c, 0x32, 1, 0 }; + /* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */ + u8 b3[] = + { 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e }; + u8 b4[] = + { 0x55, ttusb->c, 0x31, 4, 0x10, 0x02, 0x01, 0x00, 0x1e }; + + u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 }; + u8 get_dsp_version[0x20] = + { 0xaa, ++ttusb->c, 0x26, 28, 0, 0, 0, 0, 0 }; + int err; + + /* reset board */ + if ((err = ttusb_cmd(ttusb, b0, sizeof(b0), 0))) + return err; + + /* reset board (again?) */ + if ((err = ttusb_cmd(ttusb, b1, sizeof(b1), 0))) + return err; + + ttusb_boot_dsp(ttusb); + + /* set i2c bit rate */ + if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0))) + return err; + + if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 1))) + return err; + + err = ttusb_result(ttusb, b4, sizeof(b4)); + + if ((err = ttusb_cmd(ttusb, get_version, sizeof(get_version), 1))) + return err; + + if ((err = ttusb_result(ttusb, get_version, sizeof(get_version)))) + return err; + + dprintk("%s: stc-version: %c%c%c%c%c\n", __func__, + get_version[4], get_version[5], get_version[6], + get_version[7], get_version[8]); + + if (memcmp(get_version + 4, "V 0.0", 5) && + memcmp(get_version + 4, "V 1.1", 5) && + memcmp(get_version + 4, "V 2.1", 5) && + memcmp(get_version + 4, "V 2.2", 5)) { + printk + ("%s: unknown STC version %c%c%c%c%c, please report!\n", + __func__, get_version[4], get_version[5], + get_version[6], get_version[7], get_version[8]); + } + + ttusb->revision = ((get_version[6] - '0') << 4) | + (get_version[8] - '0'); + + err = + ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1); + if (err) + return err; + + err = + ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version)); + if (err) + return err; + printk("%s: dsp-version: %c%c%c\n", __func__, + get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]); + return 0; +} + +#ifdef TTUSB_DISEQC +static int ttusb_send_diseqc(struct dvb_frontend* fe, + const struct dvb_diseqc_master_cmd *cmd) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 b[12] = { 0xaa, ++ttusb->c, 0x18 }; + + int err; + + b[3] = 4 + 2 + cmd->msg_len; + b[4] = 0xFF; /* send diseqc master, not burst */ + b[5] = cmd->msg_len; + + memcpy(b + 5, cmd->msg, cmd->msg_len); + + /* Diseqc */ + if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __func__, err); + } + + return err; +} +#endif + +static int ttusb_update_lnb(struct ttusb *ttusb) +{ + u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1, + ttusb->voltage == SEC_VOLTAGE_18 ? 0 : 1, + ttusb->tone == SEC_TONE_ON ? 1 : 0, 1, 1 + }; + int err; + + /* SetLNB */ + if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __func__, err); + } + + return err; +} + +static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + + ttusb->voltage = voltage; + return ttusb_update_lnb(ttusb); +} + +#ifdef TTUSB_TONE +static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + + ttusb->tone = tone; + return ttusb_update_lnb(ttusb); +} +#endif + + +#if 0 +static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq) +{ + u8 b[] = { 0xaa, ++ttusb->c, 0x19, 1, freq }; + int err, actual_len; + + err = ttusb_cmd(ttusb, b, sizeof(b), 0); + if (err) { + dprintk("%s: usb_bulk_msg() failed, return value %i!\n", + __func__, err); + } +} +#endif + +/*****************************************************************************/ + +#ifdef TTUSB_HWSECTIONS +static void ttusb_handle_ts_data(struct ttusb_channel *channel, + const u8 * data, int len); +static void ttusb_handle_sec_data(struct ttusb_channel *channel, + const u8 * data, int len); +#endif + +static int numpkt, numts, numstuff, numsec, numinvalid; +static unsigned long lastj; + +static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack, + int len) +{ + u16 csum = 0, cc; + int i; + for (i = 0; i < len; i += 2) + csum ^= le16_to_cpup((__le16 *) (muxpack + i)); + if (csum) { + printk("%s: muxpack with incorrect checksum, ignoring\n", + __func__); + numinvalid++; + return; + } + + cc = (muxpack[len - 4] << 8) | muxpack[len - 3]; + cc &= 0x7FFF; + if ((cc != ttusb->cc) && (ttusb->cc != -1)) + printk("%s: cc discontinuity (%d frames missing)\n", + __func__, (cc - ttusb->cc) & 0x7FFF); + ttusb->cc = (cc + 1) & 0x7FFF; + if (muxpack[0] & 0x80) { +#ifdef TTUSB_HWSECTIONS + /* section data */ + int pusi = muxpack[0] & 0x40; + int channel = muxpack[0] & 0x1F; + int payload = muxpack[1]; + const u8 *data = muxpack + 2; + /* check offset flag */ + if (muxpack[0] & 0x20) + data++; + + ttusb_handle_sec_data(ttusb->channel + channel, data, + payload); + data += payload; + + if ((!!(ttusb->muxpack[0] & 0x20)) ^ + !!(ttusb->muxpack[1] & 1)) + data++; +#warning TODO: pusi + printk("cc: %04x\n", (data[0] << 8) | data[1]); +#endif + numsec++; + } else if (muxpack[0] == 0x47) { +#ifdef TTUSB_HWSECTIONS + /* we have TS data here! */ + int pid = ((muxpack[1] & 0x0F) << 8) | muxpack[2]; + int channel; + for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel) + if (ttusb->channel[channel].active + && (pid == ttusb->channel[channel].pid)) + ttusb_handle_ts_data(ttusb->channel + + channel, muxpack, + 188); +#endif + numts++; + dvb_dmx_swfilter_packets(&ttusb->dvb_demux, muxpack, 1); + } else if (muxpack[0] != 0) { + numinvalid++; + printk("illegal muxpack type %02x\n", muxpack[0]); + } else + numstuff++; +} + +static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len) +{ + int maxwork = 1024; + while (len) { + if (!(maxwork--)) { + printk("%s: too much work\n", __func__); + break; + } + + switch (ttusb->mux_state) { + case 0: + case 1: + case 2: + len--; + if (*data++ == 0xAA) + ++ttusb->mux_state; + else { + ttusb->mux_state = 0; + if (ttusb->insync) { + dprintk("%s: %02x\n", + __func__, data[-1]); + printk(KERN_INFO "%s: lost sync.\n", + __func__); + ttusb->insync = 0; + } + } + break; + case 3: + ttusb->insync = 1; + len--; + ttusb->mux_npacks = *data++; + ++ttusb->mux_state; + ttusb->muxpack_ptr = 0; + /* maximum bytes, until we know the length */ + ttusb->muxpack_len = 2; + break; + case 4: + { + int avail; + avail = len; + if (avail > + (ttusb->muxpack_len - + ttusb->muxpack_ptr)) + avail = + ttusb->muxpack_len - + ttusb->muxpack_ptr; + memcpy(ttusb->muxpack + ttusb->muxpack_ptr, + data, avail); + ttusb->muxpack_ptr += avail; + BUG_ON(ttusb->muxpack_ptr > 264); + data += avail; + len -= avail; + /* determine length */ + if (ttusb->muxpack_ptr == 2) { + if (ttusb->muxpack[0] & 0x80) { + ttusb->muxpack_len = + ttusb->muxpack[1] + 2; + if (ttusb-> + muxpack[0] & 0x20) + ttusb-> + muxpack_len++; + if ((!! + (ttusb-> + muxpack[0] & 0x20)) ^ + !!(ttusb-> + muxpack[1] & 1)) + ttusb-> + muxpack_len++; + ttusb->muxpack_len += 4; + } else if (ttusb->muxpack[0] == + 0x47) + ttusb->muxpack_len = + 188 + 4; + else if (ttusb->muxpack[0] == 0x00) + ttusb->muxpack_len = + ttusb->muxpack[1] + 2 + + 4; + else { + dprintk + ("%s: invalid state: first byte is %x\n", + __func__, + ttusb->muxpack[0]); + ttusb->mux_state = 0; + } + } + + /** + * if length is valid and we reached the end: + * goto next muxpack + */ + if ((ttusb->muxpack_ptr >= 2) && + (ttusb->muxpack_ptr == + ttusb->muxpack_len)) { + ttusb_process_muxpack(ttusb, + ttusb-> + muxpack, + ttusb-> + muxpack_ptr); + ttusb->muxpack_ptr = 0; + /* maximum bytes, until we know the length */ + ttusb->muxpack_len = 2; + + /** + * no muxpacks left? + * return to search-sync state + */ + if (!ttusb->mux_npacks--) { + ttusb->mux_state = 0; + break; + } + } + break; + } + default: + BUG(); + break; + } + } +} + +static void ttusb_iso_irq(struct urb *urb) +{ + struct ttusb *ttusb = urb->context; + struct usb_iso_packet_descriptor *d; + u8 *data; + int len, i; + + if (!ttusb->iso_streaming) + return; + +#if 0 + printk("%s: status %d, errcount == %d, length == %i\n", + __func__, + urb->status, urb->error_count, urb->actual_length); +#endif + + if (!urb->status) { + for (i = 0; i < urb->number_of_packets; ++i) { + numpkt++; + if (time_after_eq(jiffies, lastj + HZ)) { + dprintk("frames/s: %lu (ts: %d, stuff %d, " + "sec: %d, invalid: %d, all: %d)\n", + numpkt * HZ / (jiffies - lastj), + numts, numstuff, numsec, numinvalid, + numts + numstuff + numsec + numinvalid); + numts = numstuff = numsec = numinvalid = 0; + lastj = jiffies; + numpkt = 0; + } + d = &urb->iso_frame_desc[i]; + data = urb->transfer_buffer + d->offset; + len = d->actual_length; + d->actual_length = 0; + d->status = 0; + ttusb_process_frame(ttusb, data, len); + } + } + usb_submit_urb(urb, GFP_ATOMIC); +} + +static void ttusb_free_iso_urbs(struct ttusb *ttusb) +{ + int i; + + for (i = 0; i < ISO_BUF_COUNT; i++) + if (ttusb->iso_urb[i]) + usb_free_urb(ttusb->iso_urb[i]); + + pci_free_consistent(NULL, + ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT, ttusb->iso_buffer, + ttusb->iso_dma_handle); +} + +static int ttusb_alloc_iso_urbs(struct ttusb *ttusb) +{ + int i; + + ttusb->iso_buffer = pci_alloc_consistent(NULL, + ISO_FRAME_SIZE * + FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT, + &ttusb->iso_dma_handle); + + if (!ttusb->iso_buffer) { + dprintk("%s: pci_alloc_consistent - not enough memory\n", + __func__); + return -ENOMEM; + } + + memset(ttusb->iso_buffer, 0, + ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + struct urb *urb; + + if (! + (urb = + usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { + ttusb_free_iso_urbs(ttusb); + return -ENOMEM; + } + + ttusb->iso_urb[i] = urb; + } + + return 0; +} + +static void ttusb_stop_iso_xfer(struct ttusb *ttusb) +{ + int i; + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_kill_urb(ttusb->iso_urb[i]); + + ttusb->iso_streaming = 0; +} + +static int ttusb_start_iso_xfer(struct ttusb *ttusb) +{ + int i, j, err, buffer_offset = 0; + + if (ttusb->iso_streaming) { + printk("%s: iso xfer already running!\n", __func__); + return 0; + } + + ttusb->cc = -1; + ttusb->insync = 0; + ttusb->mux_state = 0; + + for (i = 0; i < ISO_BUF_COUNT; i++) { + int frame_offset = 0; + struct urb *urb = ttusb->iso_urb[i]; + + urb->dev = ttusb->dev; + urb->context = ttusb; + urb->complete = ttusb_iso_irq; + urb->pipe = ttusb->isoc_in_pipe; + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + urb->number_of_packets = FRAMES_PER_ISO_BUF; + urb->transfer_buffer_length = + ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; + urb->transfer_buffer = ttusb->iso_buffer + buffer_offset; + buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; + + for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; + frame_offset += ISO_FRAME_SIZE; + } + } + + for (i = 0; i < ISO_BUF_COUNT; i++) { + if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_ATOMIC))) { + ttusb_stop_iso_xfer(ttusb); + printk + ("%s: failed urb submission (%i: err = %i)!\n", + __func__, i, err); + return err; + } + } + + ttusb->iso_streaming = 1; + + return 0; +} + +#ifdef TTUSB_HWSECTIONS +static void ttusb_handle_ts_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data, + int len) +{ + dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0); +} + +static void ttusb_handle_sec_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data, + int len) +{ +// struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed; +#error TODO: handle ugly stuff +// dvbdmxfeed->cb.sec(data, len, 0, 0, &dvbdmxfeed->feed.sec, 0); +} +#endif + +static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; + int feed_type = 1; + + dprintk("ttusb_start_feed\n"); + + switch (dvbdmxfeed->type) { + case DMX_TYPE_TS: + break; + case DMX_TYPE_SEC: + break; + default: + return -EINVAL; + } + + if (dvbdmxfeed->type == DMX_TYPE_TS) { + switch (dvbdmxfeed->pes_type) { + case DMX_TS_PES_VIDEO: + case DMX_TS_PES_AUDIO: + case DMX_TS_PES_TELETEXT: + case DMX_TS_PES_PCR: + case DMX_TS_PES_OTHER: + break; + default: + return -EINVAL; + } + } + +#ifdef TTUSB_HWSECTIONS +#error TODO: allocate filters + if (dvbdmxfeed->type == DMX_TYPE_TS) { + feed_type = 1; + } else if (dvbdmxfeed->type == DMX_TYPE_SEC) { + feed_type = 2; + } +#endif + + ttusb_set_channel(ttusb, dvbdmxfeed->index, feed_type, dvbdmxfeed->pid); + + if (0 == ttusb->running_feed_count++) + ttusb_start_iso_xfer(ttusb); + + return 0; +} + +static int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux; + + ttusb_del_channel(ttusb, dvbdmxfeed->index); + + if (--ttusb->running_feed_count == 0) + ttusb_stop_iso_xfer(ttusb); + + return 0; +} + +static int ttusb_setup_interfaces(struct ttusb *ttusb) +{ + usb_set_interface(ttusb->dev, 1, 1); + + ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1); + ttusb->bulk_in_pipe = usb_rcvbulkpipe(ttusb->dev, 1); + ttusb->isoc_in_pipe = usb_rcvisocpipe(ttusb->dev, 2); + + return 0; +} + +#if 0 +static u8 stc_firmware[8192]; + +static int stc_open(struct inode *inode, struct file *file) +{ + struct ttusb *ttusb = file->private_data; + int addr; + + for (addr = 0; addr < 8192; addr += 16) { + u8 snd_buf[2] = { addr >> 8, addr & 0xFF }; + ttusb_i2c_msg(ttusb, 0x50, snd_buf, 2, stc_firmware + addr, + 16); + } + + return 0; +} + +static ssize_t stc_read(struct file *file, char *buf, size_t count, + loff_t *offset) +{ + return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192); +} + +static int stc_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static const struct file_operations stc_fops = { + .owner = THIS_MODULE, + .read = stc_read, + .open = stc_open, + .release = stc_release, +}; +#endif + +static u32 functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + + + +static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 data[4]; + struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) }; + u32 div; + + div = (params->frequency + 36166667) / 166667; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | 0x85; + data[3] = params->frequency < 592000000 ? 0x40 : 0x80; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct cx22700_config alps_tdmb7_config = { + .demod_address = 0x43, +}; + + + + + +static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; + struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) }; + + // setup PLL configuration + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; + msleep(1); + + // disable the mc44BC374c (do not check for errors) + tuner_msg.addr = 0x65; + tuner_msg.buf = disable_mc44BC374c; + tuner_msg.len = sizeof(disable_mc44BC374c); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1); + } + + return 0; +} + +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36130000; + if (tuner_frequency < 87000000) return -EINVAL; + else if (tuner_frequency < 130000000) cp = 3; + else if (tuner_frequency < 160000000) cp = 5; + else if (tuner_frequency < 200000000) cp = 6; + else if (tuner_frequency < 290000000) cp = 3; + else if (tuner_frequency < 420000000) cp = 5; + else if (tuner_frequency < 480000000) cp = 6; + else if (tuner_frequency < 620000000) cp = 3; + else if (tuner_frequency < 830000000) cp = 5; + else if (tuner_frequency < 895000000) cp = 7; + else return -EINVAL; + + // determine band + if (params->frequency < 49000000) return -EINVAL; + else if (params->frequency < 159000000) band = 1; + else if (params->frequency < 444000000) band = 2; + else if (params->frequency < 861000000) band = 4; + else return -EINVAL; + + // setup PLL filter + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + tda1004x_writereg(fe, 0x0C, 0); + filter = 0; + break; + + case BANDWIDTH_7_MHZ: + tda1004x_writereg(fe, 0x0C, 0); + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + tda1004x_writereg(fe, 0x0C, 0xFF); + filter = 1; + break; + + default: + return -EINVAL; + } + + // calculate divisor + // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + return 0; +} + +static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + + return request_firmware(fw, name, &ttusb->dev->dev); +} + +static struct tda1004x_config philips_tdm1316l_config = { + + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 0, + .request_firmware = philips_tdm1316l_request_firmware, +}; + +static u8 alps_bsbe1_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x92, + 0xff, 0xff +}; + +static u8 alps_bsru6_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x52, + 0xff, 0xff +}; + +static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; + bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; + bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; + bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; + bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; + bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; + bclk = 0x51; + } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + + return 0; +} + +static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + buf[3] = 0xC4; + + if (params->frequency > 1530000) + buf[3] = 0xC0; + + /* BSBE1 wants XCE bit set */ + if (ttusb->revision == TTUSB_REV_2_2) + buf[3] |= 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static struct stv0299_config alps_stv0299_config = { + .demod_address = 0x68, + .inittab = alps_bsru6_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = alps_stv0299_set_symbol_rate, +}; + +static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + div = params->frequency / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x8e; + buf[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static struct tda8083_config ttusb_novas_grundig_29504_491_config = { + + .demod_address = 0x68, +}; + +static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct ttusb* ttusb = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (params->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + +static u8 read_pwm(struct ttusb* ttusb) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + + +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv; + u8 tuner_buf[5]; + struct i2c_msg tuner_msg = {.addr = 0x60, + .flags = 0, + .buf = tuner_buf, + .len = sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency; + if (tuner_frequency < 87000000) {return -EINVAL;} + else if (tuner_frequency < 130000000) {cp = 3; band = 1;} + else if (tuner_frequency < 160000000) {cp = 5; band = 1;} + else if (tuner_frequency < 200000000) {cp = 6; band = 1;} + else if (tuner_frequency < 290000000) {cp = 3; band = 2;} + else if (tuner_frequency < 420000000) {cp = 5; band = 2;} + else if (tuner_frequency < 480000000) {cp = 6; band = 2;} + else if (tuner_frequency < 620000000) {cp = 3; band = 4;} + else if (tuner_frequency < 830000000) {cp = 5; band = 4;} + else if (tuner_frequency < 895000000) {cp = 7; band = 4;} + else {return -EINVAL;} + + // assume PLL filter should always be 8MHz for the moment. + filter = 1; + + // calculate divisor + // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz + tuner_frequency = ((params->frequency + 36125000) / 62500); + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xc8; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + tuner_buf[4] = 0x80; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n"); + return -EIO; + } + + msleep(50); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n"); + return -EIO; + } + + msleep(1); + + return 0; +} + +static u8 dvbc_philips_tdm1316l_inittab[] = { + 0x80, 0x21, + 0x80, 0x20, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x20, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0xff, + 0x4b, 0x7f, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x00, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x00, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x4b, + 0xc1, 0x00, + 0xc2, 0x00, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x38, + 0x62, 0x0a, + 0x53, 0x13, + 0x59, 0x08, + 0x55, 0x00, + 0x56, 0x40, + 0x57, 0x08, + 0x58, 0x3d, + 0x88, 0x10, + 0xa0, 0x00, + 0xa0, 0x00, + 0xa0, 0x00, + 0xa0, 0x04, + 0xff, 0xff, +}; + +static struct stv0297_config dvbc_philips_tdm1316l_config = { + .demod_address = 0x1c, + .inittab = dvbc_philips_tdm1316l_inittab, + .invert = 0, +}; + +static void frontend_init(struct ttusb* ttusb) +{ + switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) { + case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059)) + // try the stv0299 based first + ttusb->fe = dvb_attach(stv0299_attach, &alps_stv0299_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params; + + if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1 + alps_stv0299_config.inittab = alps_bsbe1_inittab; + dvb_attach(lnbp21_attach, ttusb->fe, &ttusb->i2c_adap, 0, 0); + } else { // ALPS BSRU6 + ttusb->fe->ops.set_voltage = ttusb_set_voltage; + } + break; + } + + // Grundig 29504-491 + ttusb->fe = dvb_attach(tda8083_attach, &ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params; + ttusb->fe->ops.set_voltage = ttusb_set_voltage; + break; + } + break; + + case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) + ttusb->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb)); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + break; + } + + ttusb->fe = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; + break; + } + break; + + case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??)) + // try the ALPS TDMB7 first + ttusb->fe = dvb_attach(cx22700_attach, &alps_tdmb7_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params; + break; + } + + // Philips td1316 + ttusb->fe = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init; + ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; + break; + } + break; + } + + if (ttusb->fe == NULL) { + printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n", + le16_to_cpu(ttusb->dev->descriptor.idVendor), + le16_to_cpu(ttusb->dev->descriptor.idProduct)); + } else { + if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) { + printk("dvb-ttusb-budget: Frontend registration failed!\n"); + dvb_frontend_detach(ttusb->fe); + ttusb->fe = NULL; + } + } +} + + + +static struct i2c_algorithm ttusb_dec_algo = { + .master_xfer = master_xfer, + .functionality = functionality, +}; + +static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev; + struct ttusb *ttusb; + int result; + + dprintk("%s: TTUSB DVB connected\n", __func__); + + udev = interface_to_usbdev(intf); + + if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV; + + if (!(ttusb = kzalloc(sizeof(struct ttusb), GFP_KERNEL))) + return -ENOMEM; + + ttusb->dev = udev; + ttusb->c = 0; + ttusb->mux_state = 0; + mutex_init(&ttusb->semi2c); + + mutex_lock(&ttusb->semi2c); + + mutex_init(&ttusb->semusb); + + ttusb_setup_interfaces(ttusb); + + result = ttusb_alloc_iso_urbs(ttusb); + if (result < 0) { + dprintk("%s: ttusb_alloc_iso_urbs - failed\n", __func__); + mutex_unlock(&ttusb->semi2c); + kfree(ttusb); + return result; + } + + if (ttusb_init_controller(ttusb)) + printk("ttusb_init_controller: error\n"); + + mutex_unlock(&ttusb->semi2c); + + result = dvb_register_adapter(&ttusb->adapter, + "Technotrend/Hauppauge Nova-USB", + THIS_MODULE, &udev->dev, adapter_nr); + if (result < 0) { + ttusb_free_iso_urbs(ttusb); + kfree(ttusb); + return result; + } + ttusb->adapter.priv = ttusb; + + /* i2c */ + memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter)); + strcpy(ttusb->i2c_adap.name, "TTUSB DEC"); + + i2c_set_adapdata(&ttusb->i2c_adap, ttusb); + + ttusb->i2c_adap.algo = &ttusb_dec_algo; + ttusb->i2c_adap.algo_data = NULL; + ttusb->i2c_adap.dev.parent = &udev->dev; + + result = i2c_add_adapter(&ttusb->i2c_adap); + if (result) { + dvb_unregister_adapter (&ttusb->adapter); + return result; + } + + memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); + + ttusb->dvb_demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING; + ttusb->dvb_demux.priv = NULL; +#ifdef TTUSB_HWSECTIONS + ttusb->dvb_demux.filternum = TTUSB_MAXFILTER; +#else + ttusb->dvb_demux.filternum = 32; +#endif + ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL; + ttusb->dvb_demux.start_feed = ttusb_start_feed; + ttusb->dvb_demux.stop_feed = ttusb_stop_feed; + ttusb->dvb_demux.write_to_decoder = NULL; + + if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) { + printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result); + i2c_del_adapter(&ttusb->i2c_adap); + dvb_unregister_adapter (&ttusb->adapter); + return -ENODEV; + } +//FIXME dmxdev (nur WAS?) + ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum; + ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx; + ttusb->dmxdev.capabilities = 0; + + if ((result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter)) < 0) { + printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n", + result); + dvb_dmx_release(&ttusb->dvb_demux); + i2c_del_adapter(&ttusb->i2c_adap); + dvb_unregister_adapter (&ttusb->adapter); + return -ENODEV; + } + + if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { + printk("ttusb_dvb: dvb_net_init failed!\n"); + dvb_dmxdev_release(&ttusb->dmxdev); + dvb_dmx_release(&ttusb->dvb_demux); + i2c_del_adapter(&ttusb->i2c_adap); + dvb_unregister_adapter (&ttusb->adapter); + return -ENODEV; + } + + usb_set_intfdata(intf, (void *) ttusb); + + frontend_init(ttusb); + + return 0; +} + +static void ttusb_disconnect(struct usb_interface *intf) +{ + struct ttusb *ttusb = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + ttusb->disconnecting = 1; + + ttusb_stop_iso_xfer(ttusb); + + ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx); + dvb_net_release(&ttusb->dvbnet); + dvb_dmxdev_release(&ttusb->dmxdev); + dvb_dmx_release(&ttusb->dvb_demux); + if (ttusb->fe != NULL) { + dvb_unregister_frontend(ttusb->fe); + dvb_frontend_detach(ttusb->fe); + } + i2c_del_adapter(&ttusb->i2c_adap); + dvb_unregister_adapter(&ttusb->adapter); + + ttusb_free_iso_urbs(ttusb); + + kfree(ttusb); + + dprintk("%s: TTUSB DVB disconnected\n", __func__); +} + +static struct usb_device_id ttusb_table[] = { + {USB_DEVICE(0xb48, 0x1003)}, + {USB_DEVICE(0xb48, 0x1004)}, + {USB_DEVICE(0xb48, 0x1005)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, ttusb_table); + +static struct usb_driver ttusb_driver = { + .name = "ttusb", + .probe = ttusb_probe, + .disconnect = ttusb_disconnect, + .id_table = ttusb_table, +}; + +static int __init ttusb_init(void) +{ + int err; + + if ((err = usb_register(&ttusb_driver)) < 0) { + printk("%s: usb_register failed! Error number %d", + __FILE__, err); + return err; + } + + return 0; +} + +static void __exit ttusb_exit(void) +{ + usb_deregister(&ttusb_driver); +} + +module_init(ttusb_init); +module_exit(ttusb_exit); + +MODULE_AUTHOR("Holger Waechtler "); +MODULE_DESCRIPTION("TTUSB DVB Driver"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("ttusb-budget/dspbootcode.bin"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,18 @@ +config DVB_TTUSB_BUDGET + tristate "Technotrend/Hauppauge Nova-USB devices" + depends on DVB_CORE && USB && I2C && PCI + select DVB_CX22700 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_VES1820 if !DVB_FE_CUSTOMISE + select DVB_TDA8083 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0297 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + help + Support for external USB adapters designed by Technotrend and + produced by Hauppauge, shipped under the brand name 'Nova-USB'. + + These devices don't have a MPEG decoder built in, so you need + an external software decoder to watch TV. + + Say Y if you own such a device and want to use it. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-budget/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,21 @@ +config DVB_TTUSB_DEC + tristate "Technotrend/Hauppauge USB DEC devices" + depends on DVB_CORE && USB && INPUT && PCI + select CRC32 + help + Support for external USB adapters designed by Technotrend and + produced by Hauppauge, shipped under the brand name 'DEC2000-t' + and 'DEC3000-s'. + + Even if these devices have a MPEG decoder built in, they transmit + only compressed MPEG data over the USB bus, so you need + an external software decoder to watch TV on your computer. + + This driver needs external firmware. Please use the commands + "/Documentation/dvb/get_dvb_firmware dec2000t", + "/Documentation/dvb/get_dvb_firmware dec2540t", + "/Documentation/dvb/get_dvb_firmware dec3000s", + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + + Say Y if you own such a device and want to use it. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1783 @@ +/* + * TTUSB DEC Driver + * + * Copyright (C) 2003-2004 Alex Woods + * IR support by Peter Beutner + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_filter.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "ttusbdecfe.h" + +static int debug; +static int output_pva; +static int enable_rc; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); +module_param(output_pva, int, 0444); +MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)"); +module_param(enable_rc, int, 0644); +MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk if (debug) printk + +#define DRIVER_NAME "TechnoTrend/Hauppauge DEC USB" + +#define COMMAND_PIPE 0x03 +#define RESULT_PIPE 0x04 +#define IN_PIPE 0x08 +#define OUT_PIPE 0x07 +#define IRQ_PIPE 0x0A + +#define COMMAND_PACKET_SIZE 0x3c +#define ARM_PACKET_SIZE 0x1000 +#define IRQ_PACKET_SIZE 0x8 + +#define ISO_BUF_COUNT 0x04 +#define FRAMES_PER_ISO_BUF 0x04 +#define ISO_FRAME_SIZE 0x0380 + +#define MAX_PVA_LENGTH 6144 + +enum ttusb_dec_model { + TTUSB_DEC2000T, + TTUSB_DEC2540T, + TTUSB_DEC3000S +}; + +enum ttusb_dec_packet_type { + TTUSB_DEC_PACKET_PVA, + TTUSB_DEC_PACKET_SECTION, + TTUSB_DEC_PACKET_EMPTY +}; + +enum ttusb_dec_interface { + TTUSB_DEC_INTERFACE_INITIAL, + TTUSB_DEC_INTERFACE_IN, + TTUSB_DEC_INTERFACE_OUT +}; + +struct ttusb_dec { + enum ttusb_dec_model model; + char *model_name; + char *firmware_name; + int can_playback; + + /* DVB bits */ + struct dvb_adapter adapter; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dmx_frontend frontend; + struct dvb_net dvb_net; + struct dvb_frontend* fe; + + u16 pid[DMX_PES_OTHER]; + + /* USB bits */ + struct usb_device *udev; + u8 trans_count; + unsigned int command_pipe; + unsigned int result_pipe; + unsigned int in_pipe; + unsigned int out_pipe; + unsigned int irq_pipe; + enum ttusb_dec_interface interface; + struct mutex usb_mutex; + + void *irq_buffer; + struct urb *irq_urb; + dma_addr_t irq_dma_handle; + void *iso_buffer; + dma_addr_t iso_dma_handle; + struct urb *iso_urb[ISO_BUF_COUNT]; + int iso_stream_count; + struct mutex iso_mutex; + + u8 packet[MAX_PVA_LENGTH + 4]; + enum ttusb_dec_packet_type packet_type; + int packet_state; + int packet_length; + int packet_payload_length; + u16 next_packet_id; + + int pva_stream_count; + int filter_stream_count; + + struct dvb_filter_pes2ts a_pes2ts; + struct dvb_filter_pes2ts v_pes2ts; + + u8 v_pes[16 + MAX_PVA_LENGTH]; + int v_pes_length; + int v_pes_postbytes; + + struct list_head urb_frame_list; + struct tasklet_struct urb_tasklet; + spinlock_t urb_frame_list_lock; + + struct dvb_demux_filter *audio_filter; + struct dvb_demux_filter *video_filter; + struct list_head filter_info_list; + spinlock_t filter_info_list_lock; + + struct input_dev *rc_input_dev; + char rc_phys[64]; + + int active; /* Loaded successfully */ +}; + +struct urb_frame { + u8 data[ISO_FRAME_SIZE]; + int length; + struct list_head urb_frame_list; +}; + +struct filter_info { + u8 stream_id; + struct dvb_demux_filter *filter; + struct list_head filter_info_list; +}; + +static u16 rc_keys[] = { + KEY_POWER, + KEY_MUTE, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_CHANNELUP, + KEY_VOLUMEDOWN, + KEY_OK, + KEY_VOLUMEUP, + KEY_CHANNELDOWN, + KEY_PREVIOUS, + KEY_ESC, + KEY_RED, + KEY_GREEN, + KEY_YELLOW, + KEY_BLUE, + KEY_OPTION, + KEY_M, + KEY_RADIO +}; + +static void ttusb_dec_set_model(struct ttusb_dec *dec, + enum ttusb_dec_model model); + +static void ttusb_dec_handle_irq( struct urb *urb) +{ + struct ttusb_dec * dec = urb->context; + char *buffer = dec->irq_buffer; + int retval; + + switch(urb->status) { + case 0: /*success*/ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -ETIME: + /* this urb is dead, cleanup */ + dprintk("%s:urb shutting down with status: %d\n", + __func__, urb->status); + return; + default: + dprintk("%s:nonzero status received: %d\n", + __func__,urb->status); + goto exit; + } + + if( (buffer[0] == 0x1) && (buffer[2] == 0x15) ) { + /* IR - Event */ + /* this is an fact a bit too simple implementation; + * the box also reports a keyrepeat signal + * (with buffer[3] == 0x40) in an intervall of ~100ms. + * But to handle this correctly we had to imlemenent some + * kind of timer which signals a 'key up' event if no + * keyrepeat signal is received for lets say 200ms. + * this should/could be added later ... + * for now lets report each signal as a key down and up*/ + dprintk("%s:rc signal:%d\n", __func__, buffer[4]); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); + input_sync(dec->rc_input_dev); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); + input_sync(dec->rc_input_dev); + } + +exit: retval = usb_submit_urb(urb, GFP_ATOMIC); + if(retval) + printk("%s - usb_commit_urb failed with result: %d\n", + __func__, retval); +} + +static u16 crc16(u16 crc, const u8 *buf, size_t len) +{ + u16 tmp; + + while (len--) { + crc ^= *buf++; + crc ^= (u8)crc >> 4; + tmp = (u8)crc; + crc ^= (tmp ^ (tmp << 1)) << 4; + } + return crc; +} + +static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]) +{ + int result, actual_len, i; + u8 *b; + + dprintk("%s\n", __func__); + + b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); + if (!b) + return -ENOMEM; + + if ((result = mutex_lock_interruptible(&dec->usb_mutex))) { + kfree(b); + printk("%s: Failed to lock usb mutex.\n", __func__); + return result; + } + + b[0] = 0xaa; + b[1] = ++dec->trans_count; + b[2] = command; + b[3] = param_length; + + if (params) + memcpy(&b[4], params, param_length); + + if (debug) { + printk("%s: command: ", __func__); + for (i = 0; i < param_length + 4; i++) + printk("0x%02X ", b[i]); + printk("\n"); + } + + result = usb_bulk_msg(dec->udev, dec->command_pipe, b, + COMMAND_PACKET_SIZE + 4, &actual_len, 1000); + + if (result) { + printk("%s: command bulk message failed: error %d\n", + __func__, result); + mutex_unlock(&dec->usb_mutex); + kfree(b); + return result; + } + + result = usb_bulk_msg(dec->udev, dec->result_pipe, b, + COMMAND_PACKET_SIZE + 4, &actual_len, 1000); + + if (result) { + printk("%s: result bulk message failed: error %d\n", + __func__, result); + mutex_unlock(&dec->usb_mutex); + kfree(b); + return result; + } else { + if (debug) { + printk("%s: result: ", __func__); + for (i = 0; i < actual_len; i++) + printk("0x%02X ", b[i]); + printk("\n"); + } + + if (result_length) + *result_length = b[3]; + if (cmd_result && b[3] > 0) + memcpy(cmd_result, &b[4], b[3]); + + mutex_unlock(&dec->usb_mutex); + + kfree(b); + return 0; + } +} + +static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, + unsigned int *model, unsigned int *version) +{ + u8 c[COMMAND_PACKET_SIZE]; + int c_length; + int result; + __be32 tmp; + + dprintk("%s\n", __func__); + + result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); + if (result) + return result; + + if (c_length >= 0x0c) { + if (mode != NULL) { + memcpy(&tmp, c, 4); + *mode = ntohl(tmp); + } + if (model != NULL) { + memcpy(&tmp, &c[4], 4); + *model = ntohl(tmp); + } + if (version != NULL) { + memcpy(&tmp, &c[8], 4); + *version = ntohl(tmp); + } + return 0; + } else { + return -1; + } +} + +static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) +{ + struct ttusb_dec *dec = priv; + + dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, + &dec->audio_filter->feed->feed.ts, + DMX_OK); + + return 0; +} + +static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) +{ + struct ttusb_dec *dec = priv; + + dec->video_filter->feed->cb.ts(data, 188, NULL, 0, + &dec->video_filter->feed->feed.ts, + DMX_OK); + + return 0; +} + +static void ttusb_dec_set_pids(struct ttusb_dec *dec) +{ + u8 b[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff }; + + __be16 pcr = htons(dec->pid[DMX_PES_PCR]); + __be16 audio = htons(dec->pid[DMX_PES_AUDIO]); + __be16 video = htons(dec->pid[DMX_PES_VIDEO]); + + dprintk("%s\n", __func__); + + memcpy(&b[0], &pcr, 2); + memcpy(&b[2], &audio, 2); + memcpy(&b[4], &video, 2); + + ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL); + + dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], + ttusb_dec_audio_pes2ts_cb, dec); + dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], + ttusb_dec_video_pes2ts_cb, dec); + dec->v_pes_length = 0; + dec->v_pes_postbytes = 0; +} + +static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) +{ + if (length < 8) { + printk("%s: packet too short - discarding\n", __func__); + return; + } + + if (length > 8 + MAX_PVA_LENGTH) { + printk("%s: packet too long - discarding\n", __func__); + return; + } + + switch (pva[2]) { + + case 0x01: { /* VideoStream */ + int prebytes = pva[5] & 0x03; + int postbytes = (pva[5] & 0x0c) >> 2; + __be16 v_pes_payload_length; + + if (output_pva) { + dec->video_filter->feed->cb.ts(pva, length, NULL, 0, + &dec->video_filter->feed->feed.ts, DMX_OK); + return; + } + + if (dec->v_pes_postbytes > 0 && + dec->v_pes_postbytes == prebytes) { + memcpy(&dec->v_pes[dec->v_pes_length], + &pva[12], prebytes); + + dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, + dec->v_pes_length + prebytes, 1); + } + + if (pva[5] & 0x10) { + dec->v_pes[7] = 0x80; + dec->v_pes[8] = 0x05; + + dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5); + dec->v_pes[10] = ((pva[8] & 0x3f) << 2) | + ((pva[9] & 0xc0) >> 6); + dec->v_pes[11] = 0x01 | + ((pva[9] & 0x3f) << 2) | + ((pva[10] & 0x80) >> 6); + dec->v_pes[12] = ((pva[10] & 0x7f) << 1) | + ((pva[11] & 0xc0) >> 7); + dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1); + + memcpy(&dec->v_pes[14], &pva[12 + prebytes], + length - 12 - prebytes); + dec->v_pes_length = 14 + length - 12 - prebytes; + } else { + dec->v_pes[7] = 0x00; + dec->v_pes[8] = 0x00; + + memcpy(&dec->v_pes[9], &pva[8], length - 8); + dec->v_pes_length = 9 + length - 8; + } + + dec->v_pes_postbytes = postbytes; + + if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 && + dec->v_pes[10 + dec->v_pes[8]] == 0x00 && + dec->v_pes[11 + dec->v_pes[8]] == 0x01) + dec->v_pes[6] = 0x84; + else + dec->v_pes[6] = 0x80; + + v_pes_payload_length = htons(dec->v_pes_length - 6 + + postbytes); + memcpy(&dec->v_pes[4], &v_pes_payload_length, 2); + + if (postbytes == 0) + dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, + dec->v_pes_length, 1); + + break; + } + + case 0x02: /* MainAudioStream */ + if (output_pva) { + dec->audio_filter->feed->cb.ts(pva, length, NULL, 0, + &dec->audio_filter->feed->feed.ts, DMX_OK); + return; + } + + dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8, + pva[5] & 0x10); + break; + + default: + printk("%s: unknown PVA type: %02x.\n", __func__, + pva[2]); + break; + } +} + +static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet, + int length) +{ + struct list_head *item; + struct filter_info *finfo; + struct dvb_demux_filter *filter = NULL; + unsigned long flags; + u8 sid; + + sid = packet[1]; + spin_lock_irqsave(&dec->filter_info_list_lock, flags); + for (item = dec->filter_info_list.next; item != &dec->filter_info_list; + item = item->next) { + finfo = list_entry(item, struct filter_info, filter_info_list); + if (finfo->stream_id == sid) { + filter = finfo->filter; + break; + } + } + spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); + + if (filter) + filter->feed->cb.sec(&packet[2], length - 2, NULL, 0, + &filter->filter, DMX_OK); +} + +static void ttusb_dec_process_packet(struct ttusb_dec *dec) +{ + int i; + u16 csum = 0; + u16 packet_id; + + if (dec->packet_length % 2) { + printk("%s: odd sized packet - discarding\n", __func__); + return; + } + + for (i = 0; i < dec->packet_length; i += 2) + csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]); + + if (csum) { + printk("%s: checksum failed - discarding\n", __func__); + return; + } + + packet_id = dec->packet[dec->packet_length - 4] << 8; + packet_id += dec->packet[dec->packet_length - 3]; + + if ((packet_id != dec->next_packet_id) && dec->next_packet_id) { + printk("%s: warning: lost packets between %u and %u\n", + __func__, dec->next_packet_id - 1, packet_id); + } + + if (packet_id == 0xffff) + dec->next_packet_id = 0x8000; + else + dec->next_packet_id = packet_id + 1; + + switch (dec->packet_type) { + case TTUSB_DEC_PACKET_PVA: + if (dec->pva_stream_count) + ttusb_dec_process_pva(dec, dec->packet, + dec->packet_payload_length); + break; + + case TTUSB_DEC_PACKET_SECTION: + if (dec->filter_stream_count) + ttusb_dec_process_filter(dec, dec->packet, + dec->packet_payload_length); + break; + + case TTUSB_DEC_PACKET_EMPTY: + break; + } +} + +static void swap_bytes(u8 *b, int length) +{ + u8 c; + + length -= length % 2; + for (; length; b += 2, length -= 2) { + c = *b; + *b = *(b + 1); + *(b + 1) = c; + } +} + +static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, + int length) +{ + swap_bytes(b, length); + + while (length) { + switch (dec->packet_state) { + + case 0: + case 1: + case 2: + if (*b++ == 0xaa) + dec->packet_state++; + else + dec->packet_state = 0; + + length--; + break; + + case 3: + if (*b == 0x00) { + dec->packet_state++; + dec->packet_length = 0; + } else if (*b != 0xaa) { + dec->packet_state = 0; + } + + b++; + length--; + break; + + case 4: + dec->packet[dec->packet_length++] = *b++; + + if (dec->packet_length == 2) { + if (dec->packet[0] == 'A' && + dec->packet[1] == 'V') { + dec->packet_type = + TTUSB_DEC_PACKET_PVA; + dec->packet_state++; + } else if (dec->packet[0] == 'S') { + dec->packet_type = + TTUSB_DEC_PACKET_SECTION; + dec->packet_state++; + } else if (dec->packet[0] == 0x00) { + dec->packet_type = + TTUSB_DEC_PACKET_EMPTY; + dec->packet_payload_length = 2; + dec->packet_state = 7; + } else { + printk("%s: unknown packet type: " + "%02x%02x\n", __func__, + dec->packet[0], dec->packet[1]); + dec->packet_state = 0; + } + } + + length--; + break; + + case 5: + dec->packet[dec->packet_length++] = *b++; + + if (dec->packet_type == TTUSB_DEC_PACKET_PVA && + dec->packet_length == 8) { + dec->packet_state++; + dec->packet_payload_length = 8 + + (dec->packet[6] << 8) + + dec->packet[7]; + } else if (dec->packet_type == + TTUSB_DEC_PACKET_SECTION && + dec->packet_length == 5) { + dec->packet_state++; + dec->packet_payload_length = 5 + + ((dec->packet[3] & 0x0f) << 8) + + dec->packet[4]; + } + + length--; + break; + + case 6: { + int remainder = dec->packet_payload_length - + dec->packet_length; + + if (length >= remainder) { + memcpy(dec->packet + dec->packet_length, + b, remainder); + dec->packet_length += remainder; + b += remainder; + length -= remainder; + dec->packet_state++; + } else { + memcpy(&dec->packet[dec->packet_length], + b, length); + dec->packet_length += length; + length = 0; + } + + break; + } + + case 7: { + int tail = 4; + + dec->packet[dec->packet_length++] = *b++; + + if (dec->packet_type == TTUSB_DEC_PACKET_SECTION && + dec->packet_payload_length % 2) + tail++; + + if (dec->packet_length == + dec->packet_payload_length + tail) { + ttusb_dec_process_packet(dec); + dec->packet_state = 0; + } + + length--; + break; + } + + default: + printk("%s: illegal packet state encountered.\n", + __func__); + dec->packet_state = 0; + } + } +} + +static void ttusb_dec_process_urb_frame_list(unsigned long data) +{ + struct ttusb_dec *dec = (struct ttusb_dec *)data; + struct list_head *item; + struct urb_frame *frame; + unsigned long flags; + + while (1) { + spin_lock_irqsave(&dec->urb_frame_list_lock, flags); + if ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { + frame = list_entry(item, struct urb_frame, + urb_frame_list); + list_del(&frame->urb_frame_list); + } else { + spin_unlock_irqrestore(&dec->urb_frame_list_lock, + flags); + return; + } + spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); + + ttusb_dec_process_urb_frame(dec, frame->data, frame->length); + kfree(frame); + } +} + +static void ttusb_dec_process_urb(struct urb *urb) +{ + struct ttusb_dec *dec = urb->context; + + if (!urb->status) { + int i; + + for (i = 0; i < FRAMES_PER_ISO_BUF; i++) { + struct usb_iso_packet_descriptor *d; + u8 *b; + int length; + struct urb_frame *frame; + + d = &urb->iso_frame_desc[i]; + b = urb->transfer_buffer + d->offset; + length = d->actual_length; + + if ((frame = kmalloc(sizeof(struct urb_frame), + GFP_ATOMIC))) { + unsigned long flags; + + memcpy(frame->data, b, length); + frame->length = length; + + spin_lock_irqsave(&dec->urb_frame_list_lock, + flags); + list_add_tail(&frame->urb_frame_list, + &dec->urb_frame_list); + spin_unlock_irqrestore(&dec->urb_frame_list_lock, + flags); + + tasklet_schedule(&dec->urb_tasklet); + } + } + } else { + /* -ENOENT is expected when unlinking urbs */ + if (urb->status != -ENOENT) + dprintk("%s: urb error: %d\n", __func__, + urb->status); + } + + if (dec->iso_stream_count) + usb_submit_urb(urb, GFP_ATOMIC); +} + +static void ttusb_dec_setup_urbs(struct ttusb_dec *dec) +{ + int i, j, buffer_offset = 0; + + dprintk("%s\n", __func__); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + int frame_offset = 0; + struct urb *urb = dec->iso_urb[i]; + + urb->dev = dec->udev; + urb->context = dec; + urb->complete = ttusb_dec_process_urb; + urb->pipe = dec->in_pipe; + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + urb->number_of_packets = FRAMES_PER_ISO_BUF; + urb->transfer_buffer_length = ISO_FRAME_SIZE * + FRAMES_PER_ISO_BUF; + urb->transfer_buffer = dec->iso_buffer + buffer_offset; + buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; + + for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; + frame_offset += ISO_FRAME_SIZE; + } + } +} + +static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __func__); + + if (mutex_lock_interruptible(&dec->iso_mutex)) + return; + + dec->iso_stream_count--; + + if (!dec->iso_stream_count) { + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_kill_urb(dec->iso_urb[i]); + } + + mutex_unlock(&dec->iso_mutex); +} + +/* Setting the interface of the DEC tends to take down the USB communications + * for a short period, so it's important not to call this function just before + * trying to talk to it. + */ +static int ttusb_dec_set_interface(struct ttusb_dec *dec, + enum ttusb_dec_interface interface) +{ + int result = 0; + u8 b[] = { 0x05 }; + + if (interface != dec->interface) { + switch (interface) { + case TTUSB_DEC_INTERFACE_INITIAL: + result = usb_set_interface(dec->udev, 0, 0); + break; + case TTUSB_DEC_INTERFACE_IN: + result = ttusb_dec_send_command(dec, 0x80, sizeof(b), + b, NULL, NULL); + if (result) + return result; + result = usb_set_interface(dec->udev, 0, 8); + break; + case TTUSB_DEC_INTERFACE_OUT: + result = usb_set_interface(dec->udev, 0, 1); + break; + } + + if (result) + return result; + + dec->interface = interface; + } + + return 0; +} + +static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) +{ + int i, result; + + dprintk("%s\n", __func__); + + if (mutex_lock_interruptible(&dec->iso_mutex)) + return -EAGAIN; + + if (!dec->iso_stream_count) { + ttusb_dec_setup_urbs(dec); + + dec->packet_state = 0; + dec->v_pes_postbytes = 0; + dec->next_packet_id = 0; + + for (i = 0; i < ISO_BUF_COUNT; i++) { + if ((result = usb_submit_urb(dec->iso_urb[i], + GFP_ATOMIC))) { + printk("%s: failed urb submission %d: " + "error %d\n", __func__, i, result); + + while (i) { + usb_kill_urb(dec->iso_urb[i - 1]); + i--; + } + + mutex_unlock(&dec->iso_mutex); + return result; + } + } + } + + dec->iso_stream_count++; + + mutex_unlock(&dec->iso_mutex); + + return 0; +} + +static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ttusb_dec *dec = dvbdmx->priv; + u8 b0[] = { 0x05 }; + int result = 0; + + dprintk("%s\n", __func__); + + dprintk(" ts_type:"); + + if (dvbdmxfeed->ts_type & TS_DECODER) + dprintk(" TS_DECODER"); + + if (dvbdmxfeed->ts_type & TS_PACKET) + dprintk(" TS_PACKET"); + + if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) + dprintk(" TS_PAYLOAD_ONLY"); + + dprintk("\n"); + + switch (dvbdmxfeed->pes_type) { + + case DMX_TS_PES_VIDEO: + dprintk(" pes_type: DMX_TS_PES_VIDEO\n"); + dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; + dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; + dec->video_filter = dvbdmxfeed->filter; + ttusb_dec_set_pids(dec); + break; + + case DMX_TS_PES_AUDIO: + dprintk(" pes_type: DMX_TS_PES_AUDIO\n"); + dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; + dec->audio_filter = dvbdmxfeed->filter; + ttusb_dec_set_pids(dec); + break; + + case DMX_TS_PES_TELETEXT: + dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; + dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n"); + return -ENOSYS; + + case DMX_TS_PES_PCR: + dprintk(" pes_type: DMX_TS_PES_PCR\n"); + dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; + ttusb_dec_set_pids(dec); + break; + + case DMX_TS_PES_OTHER: + dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n"); + return -ENOSYS; + + default: + dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); + return -EINVAL; + + } + + result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); + if (result) + return result; + + dec->pva_stream_count++; + return ttusb_dec_start_iso_xfer(dec); +} + +static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb_dec *dec = dvbdmxfeed->demux->priv; + u8 b0[] = { 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00 }; + __be16 pid; + u8 c[COMMAND_PACKET_SIZE]; + int c_length; + int result; + struct filter_info *finfo; + unsigned long flags; + u8 x = 1; + + dprintk("%s\n", __func__); + + pid = htons(dvbdmxfeed->pid); + memcpy(&b0[0], &pid, 2); + memcpy(&b0[4], &x, 1); + memcpy(&b0[5], &dvbdmxfeed->filter->filter.filter_value[0], 1); + + result = ttusb_dec_send_command(dec, 0x60, sizeof(b0), b0, + &c_length, c); + + if (!result) { + if (c_length == 2) { + if (!(finfo = kmalloc(sizeof(struct filter_info), + GFP_ATOMIC))) + return -ENOMEM; + + finfo->stream_id = c[1]; + finfo->filter = dvbdmxfeed->filter; + + spin_lock_irqsave(&dec->filter_info_list_lock, flags); + list_add_tail(&finfo->filter_info_list, + &dec->filter_info_list); + spin_unlock_irqrestore(&dec->filter_info_list_lock, + flags); + + dvbdmxfeed->priv = finfo; + + dec->filter_stream_count++; + return ttusb_dec_start_iso_xfer(dec); + } + + return -EAGAIN; + } else + return result; +} + +static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + dprintk("%s\n", __func__); + + if (!dvbdmx->dmx.frontend) + return -EINVAL; + + dprintk(" pid: 0x%04X\n", dvbdmxfeed->pid); + + switch (dvbdmxfeed->type) { + + case DMX_TYPE_TS: + return ttusb_dec_start_ts_feed(dvbdmxfeed); + break; + + case DMX_TYPE_SEC: + return ttusb_dec_start_sec_feed(dvbdmxfeed); + break; + + default: + dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); + return -EINVAL; + + } +} + +static int ttusb_dec_stop_ts_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb_dec *dec = dvbdmxfeed->demux->priv; + u8 b0[] = { 0x00 }; + + ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL); + + dec->pva_stream_count--; + + ttusb_dec_stop_iso_xfer(dec); + + return 0; +} + +static int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct ttusb_dec *dec = dvbdmxfeed->demux->priv; + u8 b0[] = { 0x00, 0x00 }; + struct filter_info *finfo = (struct filter_info *)dvbdmxfeed->priv; + unsigned long flags; + + b0[1] = finfo->stream_id; + spin_lock_irqsave(&dec->filter_info_list_lock, flags); + list_del(&finfo->filter_info_list); + spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); + kfree(finfo); + ttusb_dec_send_command(dec, 0x62, sizeof(b0), b0, NULL, NULL); + + dec->filter_stream_count--; + + ttusb_dec_stop_iso_xfer(dec); + + return 0; +} + +static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + dprintk("%s\n", __func__); + + switch (dvbdmxfeed->type) { + case DMX_TYPE_TS: + return ttusb_dec_stop_ts_feed(dvbdmxfeed); + break; + + case DMX_TYPE_SEC: + return ttusb_dec_stop_sec_feed(dvbdmxfeed); + break; + } + + return 0; +} + +static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __func__); + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_free_urb(dec->iso_urb[i]); + + pci_free_consistent(NULL, + ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT), + dec->iso_buffer, dec->iso_dma_handle); +} + +static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __func__); + + dec->iso_buffer = pci_alloc_consistent(NULL, + ISO_FRAME_SIZE * + (FRAMES_PER_ISO_BUF * + ISO_BUF_COUNT), + &dec->iso_dma_handle); + + if (!dec->iso_buffer) { + dprintk("%s: pci_alloc_consistent - not enough memory\n", + __func__); + return -ENOMEM; + } + + memset(dec->iso_buffer, 0, + ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)); + + for (i = 0; i < ISO_BUF_COUNT; i++) { + struct urb *urb; + + if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { + ttusb_dec_free_iso_urbs(dec); + return -ENOMEM; + } + + dec->iso_urb[i] = urb; + } + + ttusb_dec_setup_urbs(dec); + + return 0; +} + +static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) +{ + spin_lock_init(&dec->urb_frame_list_lock); + INIT_LIST_HEAD(&dec->urb_frame_list); + tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list, + (unsigned long)dec); +} + +static int ttusb_init_rc( struct ttusb_dec *dec) +{ + struct input_dev *input_dev; + u8 b[] = { 0x00, 0x01 }; + int i; + int err; + + usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); + strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "ttusb_dec remote control"; + input_dev->phys = dec->rc_phys; + input_dev->evbit[0] = BIT_MASK(EV_KEY); + input_dev->keycodesize = sizeof(u16); + input_dev->keycodemax = 0x1a; + input_dev->keycode = rc_keys; + + for (i = 0; i < ARRAY_SIZE(rc_keys); i++) + set_bit(rc_keys[i], input_dev->keybit); + + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } + + dec->rc_input_dev = input_dev; + if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) + printk("%s: usb_submit_urb failed\n",__func__); + /* enable irq pipe */ + ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); + + return 0; +} + +static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) +{ + dprintk("%s\n", __func__); + + dec->v_pes[0] = 0x00; + dec->v_pes[1] = 0x00; + dec->v_pes[2] = 0x01; + dec->v_pes[3] = 0xe0; +} + +static int ttusb_dec_init_usb(struct ttusb_dec *dec) +{ + dprintk("%s\n", __func__); + + mutex_init(&dec->usb_mutex); + mutex_init(&dec->iso_mutex); + + dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); + dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); + dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE); + dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE); + dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE); + + if(enable_rc) { + dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if(!dec->irq_urb) { + return -ENOMEM; + } + dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE, + GFP_ATOMIC, &dec->irq_dma_handle); + if(!dec->irq_buffer) { + usb_free_urb(dec->irq_urb); + return -ENOMEM; + } + usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe, + dec->irq_buffer, IRQ_PACKET_SIZE, + ttusb_dec_handle_irq, dec, 1); + dec->irq_urb->transfer_dma = dec->irq_dma_handle; + dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + } + + return ttusb_dec_alloc_iso_urbs(dec); +} + +static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) +{ + int i, j, actual_len, result, size, trans_count; + u8 b0[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x61, 0x00 }; + u8 b1[] = { 0x61 }; + u8 *b; + char idstring[21]; + const u8 *firmware = NULL; + size_t firmware_size = 0; + u16 firmware_csum = 0; + __be16 firmware_csum_ns; + __be32 firmware_size_nl; + u32 crc32_csum, crc32_check; + __be32 tmp; + const struct firmware *fw_entry = NULL; + + dprintk("%s\n", __func__); + + if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) { + printk(KERN_ERR "%s: Firmware (%s) unavailable.\n", + __func__, dec->firmware_name); + return 1; + } + + firmware = fw_entry->data; + firmware_size = fw_entry->size; + + if (firmware_size < 60) { + printk("%s: firmware size too small for DSP code (%zu < 60).\n", + __func__, firmware_size); + release_firmware(fw_entry); + return -1; + } + + /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored + at offset 56 of file, so use it to check if the firmware file is + valid. */ + crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; + memcpy(&tmp, &firmware[56], 4); + crc32_check = ntohl(tmp); + if (crc32_csum != crc32_check) { + printk("%s: crc32 check of DSP code failed (calculated " + "0x%08x != 0x%08x in file), file invalid.\n", + __func__, crc32_csum, crc32_check); + release_firmware(fw_entry); + return -1; + } + memcpy(idstring, &firmware[36], 20); + idstring[20] = '\0'; + printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); + + firmware_size_nl = htonl(firmware_size); + memcpy(b0, &firmware_size_nl, 4); + firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0; + firmware_csum_ns = htons(firmware_csum); + memcpy(&b0[6], &firmware_csum_ns, 2); + + result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); + + if (result) { + release_firmware(fw_entry); + return result; + } + + trans_count = 0; + j = 0; + + b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); + if (b == NULL) { + release_firmware(fw_entry); + return -ENOMEM; + } + + for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { + size = firmware_size - i; + if (size > COMMAND_PACKET_SIZE) + size = COMMAND_PACKET_SIZE; + + b[j + 0] = 0xaa; + b[j + 1] = trans_count++; + b[j + 2] = 0xf0; + b[j + 3] = size; + memcpy(&b[j + 4], &firmware[i], size); + + j += COMMAND_PACKET_SIZE + 4; + + if (j >= ARM_PACKET_SIZE) { + result = usb_bulk_msg(dec->udev, dec->command_pipe, b, + ARM_PACKET_SIZE, &actual_len, + 100); + j = 0; + } else if (size < COMMAND_PACKET_SIZE) { + result = usb_bulk_msg(dec->udev, dec->command_pipe, b, + j - COMMAND_PACKET_SIZE + size, + &actual_len, 100); + } + } + + result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); + + release_firmware(fw_entry); + kfree(b); + + return result; +} + +static int ttusb_dec_init_stb(struct ttusb_dec *dec) +{ + int result; + unsigned int mode = 0, model = 0, version = 0; + + dprintk("%s\n", __func__); + + result = ttusb_dec_get_stb_state(dec, &mode, &model, &version); + + if (!result) { + if (!mode) { + if (version == 0xABCDEFAB) + printk(KERN_INFO "ttusb_dec: no version " + "info in Firmware\n"); + else + printk(KERN_INFO "ttusb_dec: Firmware " + "%x.%02x%c%c\n", + version >> 24, (version >> 16) & 0xff, + (version >> 8) & 0xff, version & 0xff); + + result = ttusb_dec_boot_dsp(dec); + if (result) + return result; + else + return 1; + } else { + /* We can't trust the USB IDs that some firmwares + give the box */ + switch (model) { + case 0x00070001: + case 0x00070008: + case 0x0007000c: + ttusb_dec_set_model(dec, TTUSB_DEC3000S); + break; + case 0x00070009: + case 0x00070013: + ttusb_dec_set_model(dec, TTUSB_DEC2000T); + break; + case 0x00070011: + ttusb_dec_set_model(dec, TTUSB_DEC2540T); + break; + default: + printk(KERN_ERR "%s: unknown model returned " + "by firmware (%08x) - please report\n", + __func__, model); + return -1; + break; + } + + if (version >= 0x01770000) + dec->can_playback = 1; + + return 0; + } + } + else + return result; +} + +static int ttusb_dec_init_dvb(struct ttusb_dec *dec) +{ + int result; + + dprintk("%s\n", __func__); + + if ((result = dvb_register_adapter(&dec->adapter, + dec->model_name, THIS_MODULE, + &dec->udev->dev, + adapter_nr)) < 0) { + printk("%s: dvb_register_adapter failed: error %d\n", + __func__, result); + + return result; + } + + dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + + dec->demux.priv = (void *)dec; + dec->demux.filternum = 31; + dec->demux.feednum = 31; + dec->demux.start_feed = ttusb_dec_start_feed; + dec->demux.stop_feed = ttusb_dec_stop_feed; + dec->demux.write_to_decoder = NULL; + + if ((result = dvb_dmx_init(&dec->demux)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __func__, + result); + + dvb_unregister_adapter(&dec->adapter); + + return result; + } + + dec->dmxdev.filternum = 32; + dec->dmxdev.demux = &dec->demux.dmx; + dec->dmxdev.capabilities = 0; + + if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) { + printk("%s: dvb_dmxdev_init failed: error %d\n", + __func__, result); + + dvb_dmx_release(&dec->demux); + dvb_unregister_adapter(&dec->adapter); + + return result; + } + + dec->frontend.source = DMX_FRONTEND_0; + + if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx, + &dec->frontend)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __func__, + result); + + dvb_dmxdev_release(&dec->dmxdev); + dvb_dmx_release(&dec->demux); + dvb_unregister_adapter(&dec->adapter); + + return result; + } + + if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx, + &dec->frontend)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __func__, + result); + + dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); + dvb_dmxdev_release(&dec->dmxdev); + dvb_dmx_release(&dec->demux); + dvb_unregister_adapter(&dec->adapter); + + return result; + } + + dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx); + + return 0; +} + +static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) +{ + dprintk("%s\n", __func__); + + dvb_net_release(&dec->dvb_net); + dec->demux.dmx.close(&dec->demux.dmx); + dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); + dvb_dmxdev_release(&dec->dmxdev); + dvb_dmx_release(&dec->demux); + if (dec->fe) { + dvb_unregister_frontend(dec->fe); + if (dec->fe->ops.release) + dec->fe->ops.release(dec->fe); + } + dvb_unregister_adapter(&dec->adapter); +} + +static void ttusb_dec_exit_rc(struct ttusb_dec *dec) +{ + + dprintk("%s\n", __func__); + /* we have to check whether the irq URB is already submitted. + * As the irq is submitted after the interface is changed, + * this is the best method i figured out. + * Any others?*/ + if (dec->interface == TTUSB_DEC_INTERFACE_IN) + usb_kill_urb(dec->irq_urb); + + usb_free_urb(dec->irq_urb); + + usb_free_coherent(dec->udev,IRQ_PACKET_SIZE, + dec->irq_buffer, dec->irq_dma_handle); + + if (dec->rc_input_dev) { + input_unregister_device(dec->rc_input_dev); + dec->rc_input_dev = NULL; + } +} + + +static void ttusb_dec_exit_usb(struct ttusb_dec *dec) +{ + int i; + + dprintk("%s\n", __func__); + + dec->iso_stream_count = 0; + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_kill_urb(dec->iso_urb[i]); + + ttusb_dec_free_iso_urbs(dec); +} + +static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) +{ + struct list_head *item; + struct urb_frame *frame; + + tasklet_kill(&dec->urb_tasklet); + + while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { + frame = list_entry(item, struct urb_frame, urb_frame_list); + list_del(&frame->urb_frame_list); + kfree(frame); + } +} + +static void ttusb_dec_init_filters(struct ttusb_dec *dec) +{ + INIT_LIST_HEAD(&dec->filter_info_list); + spin_lock_init(&dec->filter_info_list_lock); +} + +static void ttusb_dec_exit_filters(struct ttusb_dec *dec) +{ + struct list_head *item; + struct filter_info *finfo; + + while ((item = dec->filter_info_list.next) != &dec->filter_info_list) { + finfo = list_entry(item, struct filter_info, filter_info_list); + list_del(&finfo->filter_info_list); + kfree(finfo); + } +} + +static int fe_send_command(struct dvb_frontend* fe, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]) +{ + struct ttusb_dec* dec = fe->dvb->priv; + return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); +} + +static struct ttusbdecfe_config fe_config = { + .send_command = fe_send_command +}; + +static int ttusb_dec_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev; + struct ttusb_dec *dec; + + dprintk("%s\n", __func__); + + udev = interface_to_usbdev(intf); + + if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { + printk("%s: couldn't allocate memory.\n", __func__); + return -ENOMEM; + } + + usb_set_intfdata(intf, (void *)dec); + + switch (id->idProduct) { + case 0x1006: + ttusb_dec_set_model(dec, TTUSB_DEC3000S); + break; + + case 0x1008: + ttusb_dec_set_model(dec, TTUSB_DEC2000T); + break; + + case 0x1009: + ttusb_dec_set_model(dec, TTUSB_DEC2540T); + break; + } + + dec->udev = udev; + + if (ttusb_dec_init_usb(dec)) + return 0; + if (ttusb_dec_init_stb(dec)) { + ttusb_dec_exit_usb(dec); + return 0; + } + ttusb_dec_init_dvb(dec); + + dec->adapter.priv = dec; + switch (id->idProduct) { + case 0x1006: + dec->fe = ttusbdecfe_dvbs_attach(&fe_config); + break; + + case 0x1008: + case 0x1009: + dec->fe = ttusbdecfe_dvbt_attach(&fe_config); + break; + } + + if (dec->fe == NULL) { + printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n", + le16_to_cpu(dec->udev->descriptor.idVendor), + le16_to_cpu(dec->udev->descriptor.idProduct)); + } else { + if (dvb_register_frontend(&dec->adapter, dec->fe)) { + printk("budget-ci: Frontend registration failed!\n"); + if (dec->fe->ops.release) + dec->fe->ops.release(dec->fe); + dec->fe = NULL; + } + } + + ttusb_dec_init_v_pes(dec); + ttusb_dec_init_filters(dec); + ttusb_dec_init_tasklet(dec); + + dec->active = 1; + + ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); + + if (enable_rc) + ttusb_init_rc(dec); + + return 0; +} + +static void ttusb_dec_disconnect(struct usb_interface *intf) +{ + struct ttusb_dec *dec = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + dprintk("%s\n", __func__); + + if (dec->active) { + ttusb_dec_exit_tasklet(dec); + ttusb_dec_exit_filters(dec); + if(enable_rc) + ttusb_dec_exit_rc(dec); + ttusb_dec_exit_usb(dec); + ttusb_dec_exit_dvb(dec); + } + + kfree(dec); +} + +static void ttusb_dec_set_model(struct ttusb_dec *dec, + enum ttusb_dec_model model) +{ + dec->model = model; + + switch (model) { + case TTUSB_DEC2000T: + dec->model_name = "DEC2000-t"; + dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; + break; + + case TTUSB_DEC2540T: + dec->model_name = "DEC2540-t"; + dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; + break; + + case TTUSB_DEC3000S: + dec->model_name = "DEC3000-s"; + dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; + break; + } +} + +static struct usb_device_id ttusb_dec_table[] = { + {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */ + /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */ + {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */ + {USB_DEVICE(0x0b48, 0x1009)}, /* DEC2540-t */ + {} +}; + +static struct usb_driver ttusb_dec_driver = { + .name = "ttusb-dec", + .probe = ttusb_dec_probe, + .disconnect = ttusb_dec_disconnect, + .id_table = ttusb_dec_table, +}; + +static int __init ttusb_dec_init(void) +{ + int result; + + if ((result = usb_register(&ttusb_dec_driver)) < 0) { + printk("%s: initialisation failed: error %d.\n", __func__, + result); + return result; + } + + return 0; +} + +static void __exit ttusb_dec_exit(void) +{ + usb_deregister(&ttusb_dec_driver); +} + +module_init(ttusb_dec_init); +module_exit(ttusb_dec_exit); + +MODULE_AUTHOR("Alex Woods "); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, ttusb_dec_table); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,298 @@ +/* + * TTUSB DEC Frontend Driver + * + * Copyright (C) 2003-2004 Alex Woods + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "dvb_frontend.h" +#include "ttusbdecfe.h" + + +#define LOF_HI 10600000 +#define LOF_LO 9750000 + +struct ttusbdecfe_state { + + /* configuration settings */ + const struct ttusbdecfe_config* config; + + struct dvb_frontend frontend; + + u8 hi_band; + u8 voltage; +}; + + +static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; +} + + +static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + struct ttusbdecfe_state* state = fe->demodulator_priv; + u8 b[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + u8 result[4]; + int len, ret; + + *status=0; + + ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result); + if(ret) + return ret; + + if(len != 4) { + printk(KERN_ERR "%s: unexpected reply\n", __func__); + return -EIO; + } + + switch(result[3]) { + case 1: /* not tuned yet */ + case 2: /* no signal/no lock*/ + break; + case 3: /* signal found and locked*/ + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + break; + case 4: + *status = FE_TIMEDOUT; + break; + default: + pr_info("%s: returned unknown value: %d\n", + __func__, result[3]); + return -EIO; + } + + return 0; +} + +static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + u8 b[] = { 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff }; + + __be32 freq = htonl(p->frequency / 1000); + memcpy(&b[4], &freq, sizeof (u32)); + state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); + + return 0; +} + +static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 1500; + /* Drift compensation makes no sense for DVB-T */ + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + u8 b[] = { 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + __be32 freq; + __be32 sym_rate; + __be32 band; + __be32 lnb_voltage; + + freq = htonl(p->frequency + + (state->hi_band ? LOF_HI : LOF_LO)); + memcpy(&b[4], &freq, sizeof(u32)); + sym_rate = htonl(p->u.qam.symbol_rate); + memcpy(&b[12], &sym_rate, sizeof(u32)); + band = htonl(state->hi_band ? LOF_HI : LOF_LO); + memcpy(&b[24], &band, sizeof(u32)); + lnb_voltage = htonl(state->voltage); + memcpy(&b[28], &lnb_voltage, sizeof(u32)); + + state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); + + return 0; +} + +static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + u8 b[] = { 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + + memcpy(&b[4], cmd->msg, cmd->msg_len); + + state->config->send_command(fe, 0x72, + sizeof(b) - (6 - cmd->msg_len), b, + NULL, NULL); + + return 0; +} + + +static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + state->hi_band = (SEC_TONE_ON == tone); + + return 0; +} + + +static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + state->voltage = 13; + break; + case SEC_VOLTAGE_18: + state->voltage = 18; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void ttusbdecfe_release(struct dvb_frontend* fe) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops ttusbdecfe_dvbt_ops; + +struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config) +{ + struct ttusbdecfe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + /* setup the state */ + state->config = config; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +static struct dvb_frontend_ops ttusbdecfe_dvbs_ops; + +struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config) +{ + struct ttusbdecfe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + /* setup the state */ + state->config = config; + state->voltage = 0; + state->hi_band = 0; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { + + .info = { + .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", + .type = FE_OFDM, + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = ttusbdecfe_release, + + .set_frontend = ttusbdecfe_dvbt_set_frontend, + + .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, + + .read_status = ttusbdecfe_dvbt_read_status, +}; + +static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { + + .info = { + .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, + .symbol_rate_min = 1000000, /* guessed */ + .symbol_rate_max = 45000000, /* guessed */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = ttusbdecfe_release, + + .set_frontend = ttusbdecfe_dvbs_set_frontend, + + .read_status = ttusbdecfe_dvbs_read_status, + + .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, + .set_voltage = ttusbdecfe_dvbs_set_voltage, + .set_tone = ttusbdecfe_dvbs_set_tone, +}; + +MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver"); +MODULE_AUTHOR("Alex Woods/Andrew de Quincey"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(ttusbdecfe_dvbt_attach); +EXPORT_SYMBOL(ttusbdecfe_dvbs_attach); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,38 @@ +/* + * TTUSB DEC Driver + * + * Copyright (C) 2003-2004 Alex Woods + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef TTUSBDECFE_H +#define TTUSBDECFE_H + +#include + +struct ttusbdecfe_config +{ + int (*send_command)(struct dvb_frontend* fe, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]); +}; + +extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config); + +extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config); + +#endif // TTUSBDECFE_H diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,129 @@ +# +# Multimedia device configuration +# + +menuconfig MEDIA_SUPPORT + tristate "Multimedia support" + depends on HAS_IOMEM + help + If you want to use Video for Linux, DVB for Linux, or DAB adapters, + enable this option and other options below. + +if MEDIA_SUPPORT + +comment "Multimedia core support" + +# +# Media controller +# + +config MEDIA_CONTROLLER + bool "Media Controller API (EXPERIMENTAL)" + depends on EXPERIMENTAL + ---help--- + Enable the media controller API used to query media devices internal + topology and configure it dynamically. + + This API is mostly used by camera interfaces in embedded platforms. + +# +# V4L core and enabled API's +# + +config VIDEO_DEV + tristate "Video For Linux" + ---help--- + V4L core support for video capture and overlay devices, webcams and + AM/FM radio cards. + + This kernel includes support for the new Video for Linux Two API, + (V4L2). + + Additional info and docs are available on the web at + + + Documentation for V4L2 is also available on the web at + . + + To compile this driver as a module, choose M here: the + module will be called videodev. + +config VIDEO_V4L2_COMMON + tristate + depends on (I2C || I2C=n) && VIDEO_DEV + default (I2C || I2C=n) && VIDEO_DEV + +config VIDEO_V4L2_SUBDEV_API + bool "V4L2 sub-device userspace API (EXPERIMENTAL)" + depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL + ---help--- + Enables the V4L2 sub-device pad-level userspace API used to configure + video format, size and frame rate between hardware blocks. + + This API is mostly used by camera interfaces in embedded platforms. + +# +# DVB Core +# + +config DVB_CORE + tristate "DVB for Linux" + select CRC32 + help + DVB core utility functions for device handling, software fallbacks etc. + + Enable this if you own a DVB/ATSC adapter and want to use it or if + you compile Linux for a digital SetTopBox. + + Say Y when you have a DVB or an ATSC card and want to use it. + + API specs and user tools are available from . + + Please report problems regarding this support to the LinuxDVB + mailing list. + + If unsure say N. + +config DVB_NET + bool "DVB Network Support" + default (NET && INET) + depends on NET && INET && DVB_CORE + help + This option enables DVB Network Support which is a part of the DVB + standard. It is used, for example, by automatic firmware updates used + on Set-Top-Boxes. It can also be used to access the Internet via the + DVB card, if the network provider supports it. + + You may want to disable the network support on embedded devices. If + unsure say Y. + +config VIDEO_MEDIA + tristate + default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV) + +comment "Multimedia drivers" + +source "drivers/media/common/Kconfig" +source "drivers/media/rc/Kconfig" + +# +# Tuner drivers for DVB and V4L +# + +source "drivers/media/common/tuners/Kconfig" + +# +# Video/Radio/Hybrid adapters +# + +source "drivers/media/video/Kconfig" + +source "drivers/media/radio/Kconfig" + +# +# DVB adapters +# + +source "drivers/media/dvb/Kconfig" + +endif # MEDIA_SUPPORT diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,14 @@ +# +# Makefile for the kernel multimedia device drivers. +# + +media-objs := media-device.o media-devnode.o media-entity.o + +ifeq ($(CONFIG_MEDIA_CONTROLLER),y) + obj-$(CONFIG_MEDIA_SUPPORT) += media.o +endif + +obj-y += common/ rc/ video/ + +obj-$(CONFIG_VIDEO_DEV) += radio/ +obj-$(CONFIG_DVB_CORE) += dvb/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-device.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-device.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-device.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-device.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,382 @@ +/* + * Media device + * + * Copyright (C) 2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 +#include +#include + +#include +#include +#include + +/* ----------------------------------------------------------------------------- + * Userspace API + */ + +static int media_device_open(struct file *filp) +{ + return 0; +} + +static int media_device_close(struct file *filp) +{ + return 0; +} + +static int media_device_get_info(struct media_device *dev, + struct media_device_info __user *__info) +{ + struct media_device_info info; + + memset(&info, 0, sizeof(info)); + + strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver)); + strlcpy(info.model, dev->model, sizeof(info.model)); + strlcpy(info.serial, dev->serial, sizeof(info.serial)); + strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info)); + + info.media_version = MEDIA_API_VERSION; + info.hw_revision = dev->hw_revision; + info.driver_version = dev->driver_version; + + return copy_to_user(__info, &info, sizeof(*__info)); +} + +static struct media_entity *find_entity(struct media_device *mdev, u32 id) +{ + struct media_entity *entity; + int next = id & MEDIA_ENT_ID_FLAG_NEXT; + + id &= ~MEDIA_ENT_ID_FLAG_NEXT; + + spin_lock(&mdev->lock); + + media_device_for_each_entity(entity, mdev) { + if ((entity->id == id && !next) || + (entity->id > id && next)) { + spin_unlock(&mdev->lock); + return entity; + } + } + + spin_unlock(&mdev->lock); + + return NULL; +} + +static long media_device_enum_entities(struct media_device *mdev, + struct media_entity_desc __user *uent) +{ + struct media_entity *ent; + struct media_entity_desc u_ent; + + if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id))) + return -EFAULT; + + ent = find_entity(mdev, u_ent.id); + + if (ent == NULL) + return -EINVAL; + + u_ent.id = ent->id; + u_ent.name[0] = '\0'; + if (ent->name) + strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); + u_ent.type = ent->type; + u_ent.revision = ent->revision; + u_ent.flags = ent->flags; + u_ent.group_id = ent->group_id; + u_ent.pads = ent->num_pads; + u_ent.links = ent->num_links - ent->num_backlinks; + u_ent.v4l.major = ent->v4l.major; + u_ent.v4l.minor = ent->v4l.minor; + if (copy_to_user(uent, &u_ent, sizeof(u_ent))) + return -EFAULT; + return 0; +} + +static void media_device_kpad_to_upad(const struct media_pad *kpad, + struct media_pad_desc *upad) +{ + upad->entity = kpad->entity->id; + upad->index = kpad->index; + upad->flags = kpad->flags; +} + +static long media_device_enum_links(struct media_device *mdev, + struct media_links_enum __user *ulinks) +{ + struct media_entity *entity; + struct media_links_enum links; + + if (copy_from_user(&links, ulinks, sizeof(links))) + return -EFAULT; + + entity = find_entity(mdev, links.entity); + if (entity == NULL) + return -EINVAL; + + if (links.pads) { + unsigned int p; + + for (p = 0; p < entity->num_pads; p++) { + struct media_pad_desc pad; + media_device_kpad_to_upad(&entity->pads[p], &pad); + if (copy_to_user(&links.pads[p], &pad, sizeof(pad))) + return -EFAULT; + } + } + + if (links.links) { + struct media_link_desc __user *ulink; + unsigned int l; + + for (l = 0, ulink = links.links; l < entity->num_links; l++) { + struct media_link_desc link; + + /* Ignore backlinks. */ + if (entity->links[l].source->entity != entity) + continue; + + media_device_kpad_to_upad(entity->links[l].source, + &link.source); + media_device_kpad_to_upad(entity->links[l].sink, + &link.sink); + link.flags = entity->links[l].flags; + if (copy_to_user(ulink, &link, sizeof(*ulink))) + return -EFAULT; + ulink++; + } + } + if (copy_to_user(ulinks, &links, sizeof(*ulinks))) + return -EFAULT; + return 0; +} + +static long media_device_setup_link(struct media_device *mdev, + struct media_link_desc __user *_ulink) +{ + struct media_link *link = NULL; + struct media_link_desc ulink; + struct media_entity *source; + struct media_entity *sink; + int ret; + + if (copy_from_user(&ulink, _ulink, sizeof(ulink))) + return -EFAULT; + + /* Find the source and sink entities and link. + */ + source = find_entity(mdev, ulink.source.entity); + sink = find_entity(mdev, ulink.sink.entity); + + if (source == NULL || sink == NULL) + return -EINVAL; + + if (ulink.source.index >= source->num_pads || + ulink.sink.index >= sink->num_pads) + return -EINVAL; + + link = media_entity_find_link(&source->pads[ulink.source.index], + &sink->pads[ulink.sink.index]); + if (link == NULL) + return -EINVAL; + + /* Setup the link on both entities. */ + ret = __media_entity_setup_link(link, ulink.flags); + + if (copy_to_user(_ulink, &ulink, sizeof(ulink))) + return -EFAULT; + + return ret; +} + +static long media_device_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct media_devnode *devnode = media_devnode_data(filp); + struct media_device *dev = to_media_device(devnode); + long ret; + + switch (cmd) { + case MEDIA_IOC_DEVICE_INFO: + ret = media_device_get_info(dev, + (struct media_device_info __user *)arg); + break; + + case MEDIA_IOC_ENUM_ENTITIES: + ret = media_device_enum_entities(dev, + (struct media_entity_desc __user *)arg); + break; + + case MEDIA_IOC_ENUM_LINKS: + mutex_lock(&dev->graph_mutex); + ret = media_device_enum_links(dev, + (struct media_links_enum __user *)arg); + mutex_unlock(&dev->graph_mutex); + break; + + case MEDIA_IOC_SETUP_LINK: + mutex_lock(&dev->graph_mutex); + ret = media_device_setup_link(dev, + (struct media_link_desc __user *)arg); + mutex_unlock(&dev->graph_mutex); + break; + + default: + ret = -ENOIOCTLCMD; + } + + return ret; +} + +static const struct media_file_operations media_device_fops = { + .owner = THIS_MODULE, + .open = media_device_open, + .ioctl = media_device_ioctl, + .release = media_device_close, +}; + +/* ----------------------------------------------------------------------------- + * sysfs + */ + +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct media_device *mdev = to_media_device(to_media_devnode(cd)); + + return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); +} + +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); + +/* ----------------------------------------------------------------------------- + * Registration/unregistration + */ + +static void media_device_release(struct media_devnode *mdev) +{ +} + +/** + * media_device_register - register a media device + * @mdev: The media device + * + * The caller is responsible for initializing the media device before + * registration. The following fields must be set: + * + * - dev must point to the parent device + * - model must be filled with the device model name + */ +int __must_check media_device_register(struct media_device *mdev) +{ + int ret; + + if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0)) + return -EINVAL; + + mdev->entity_id = 1; + INIT_LIST_HEAD(&mdev->entities); + spin_lock_init(&mdev->lock); + mutex_init(&mdev->graph_mutex); + + /* Register the device node. */ + mdev->devnode.fops = &media_device_fops; + mdev->devnode.parent = mdev->dev; + mdev->devnode.release = media_device_release; + ret = media_devnode_register(&mdev->devnode); + if (ret < 0) + return ret; + + ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); + if (ret < 0) { + media_devnode_unregister(&mdev->devnode); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(media_device_register); + +/** + * media_device_unregister - unregister a media device + * @mdev: The media device + * + */ +void media_device_unregister(struct media_device *mdev) +{ + struct media_entity *entity; + struct media_entity *next; + + list_for_each_entry_safe(entity, next, &mdev->entities, list) + media_device_unregister_entity(entity); + + device_remove_file(&mdev->devnode.dev, &dev_attr_model); + media_devnode_unregister(&mdev->devnode); +} +EXPORT_SYMBOL_GPL(media_device_unregister); + +/** + * media_device_register_entity - Register an entity with a media device + * @mdev: The media device + * @entity: The entity + */ +int __must_check media_device_register_entity(struct media_device *mdev, + struct media_entity *entity) +{ + /* Warn if we apparently re-register an entity */ + WARN_ON(entity->parent != NULL); + entity->parent = mdev; + + spin_lock(&mdev->lock); + if (entity->id == 0) + entity->id = mdev->entity_id++; + else + mdev->entity_id = max(entity->id + 1, mdev->entity_id); + list_add_tail(&entity->list, &mdev->entities); + spin_unlock(&mdev->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(media_device_register_entity); + +/** + * media_device_unregister_entity - Unregister an entity + * @entity: The entity + * + * If the entity has never been registered this function will return + * immediately. + */ +void media_device_unregister_entity(struct media_entity *entity) +{ + struct media_device *mdev = entity->parent; + + if (mdev == NULL) + return; + + spin_lock(&mdev->lock); + list_del(&entity->list); + spin_unlock(&mdev->lock); + entity->parent = NULL; +} +EXPORT_SYMBOL_GPL(media_device_unregister_entity); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-devnode.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-devnode.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-devnode.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-devnode.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,320 @@ +/* + * Media device node + * + * Copyright (C) 2010 Nokia Corporation + * + * Based on drivers/media/video/v4l2_dev.c code authored by + * Mauro Carvalho Chehab (version 2) + * Alan Cox, (version 1) + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + * + * -- + * + * Generic media device node infrastructure to register and unregister + * character devices using a dynamic major number and proper reference + * counting. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MEDIA_NUM_DEVICES 256 +#define MEDIA_NAME "media" + +static dev_t media_dev_t; + +/* + * Active devices + */ +static DEFINE_MUTEX(media_devnode_lock); +static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); + +/* Called when the last user of the media device exits. */ +static void media_devnode_release(struct device *cd) +{ + struct media_devnode *mdev = to_media_devnode(cd); + + mutex_lock(&media_devnode_lock); + + /* Delete the cdev on this minor as well */ + cdev_del(&mdev->cdev); + + /* Mark device node number as free */ + clear_bit(mdev->minor, media_devnode_nums); + + mutex_unlock(&media_devnode_lock); + + /* Release media_devnode and perform other cleanups as needed. */ + if (mdev->release) + mdev->release(mdev); +} + +static struct bus_type media_bus_type = { + .name = MEDIA_NAME, +}; + +static ssize_t media_read(struct file *filp, char __user *buf, + size_t sz, loff_t *off) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + if (!mdev->fops->read) + return -EINVAL; + if (!media_devnode_is_registered(mdev)) + return -EIO; + return mdev->fops->read(filp, buf, sz, off); +} + +static ssize_t media_write(struct file *filp, const char __user *buf, + size_t sz, loff_t *off) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + if (!mdev->fops->write) + return -EINVAL; + if (!media_devnode_is_registered(mdev)) + return -EIO; + return mdev->fops->write(filp, buf, sz, off); +} + +static unsigned int media_poll(struct file *filp, + struct poll_table_struct *poll) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + if (!media_devnode_is_registered(mdev)) + return POLLERR | POLLHUP; + if (!mdev->fops->poll) + return DEFAULT_POLLMASK; + return mdev->fops->poll(filp, poll); +} + +static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + if (!mdev->fops->ioctl) + return -ENOTTY; + + if (!media_devnode_is_registered(mdev)) + return -EIO; + + return mdev->fops->ioctl(filp, cmd, arg); +} + +/* Override for the open function */ +static int media_open(struct inode *inode, struct file *filp) +{ + struct media_devnode *mdev; + int ret; + + /* Check if the media device is available. This needs to be done with + * the media_devnode_lock held to prevent an open/unregister race: + * without the lock, the device could be unregistered and freed between + * the media_devnode_is_registered() and get_device() calls, leading to + * a crash. + */ + mutex_lock(&media_devnode_lock); + mdev = container_of(inode->i_cdev, struct media_devnode, cdev); + /* return ENXIO if the media device has been removed + already or if it is not registered anymore. */ + if (!media_devnode_is_registered(mdev)) { + mutex_unlock(&media_devnode_lock); + return -ENXIO; + } + /* and increase the device refcount */ + get_device(&mdev->dev); + mutex_unlock(&media_devnode_lock); + + filp->private_data = mdev; + + if (mdev->fops->open) { + ret = mdev->fops->open(filp); + if (ret) { + put_device(&mdev->dev); + return ret; + } + } + + return 0; +} + +/* Override for the release function */ +static int media_release(struct inode *inode, struct file *filp) +{ + struct media_devnode *mdev = media_devnode_data(filp); + int ret = 0; + + if (mdev->fops->release) + mdev->fops->release(filp); + + /* decrease the refcount unconditionally since the release() + return value is ignored. */ + put_device(&mdev->dev); + filp->private_data = NULL; + return ret; +} + +static const struct file_operations media_devnode_fops = { + .owner = THIS_MODULE, + .read = media_read, + .write = media_write, + .open = media_open, + .unlocked_ioctl = media_ioctl, + .release = media_release, + .poll = media_poll, + .llseek = no_llseek, +}; + +/** + * media_devnode_register - register a media device node + * @mdev: media device node structure we want to register + * + * The registration code assigns minor numbers and registers the new device node + * with the kernel. An error is returned if no free minor number can be found, + * or if the registration of the device node fails. + * + * Zero is returned on success. + * + * Note that if the media_devnode_register call fails, the release() callback of + * the media_devnode structure is *not* called, so the caller is responsible for + * freeing any data. + */ +int __must_check media_devnode_register(struct media_devnode *mdev) +{ + int minor; + int ret; + + /* Part 1: Find a free minor number */ + mutex_lock(&media_devnode_lock); + minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0); + if (minor == MEDIA_NUM_DEVICES) { + mutex_unlock(&media_devnode_lock); + printk(KERN_ERR "could not get a free minor\n"); + return -ENFILE; + } + + set_bit(minor, media_devnode_nums); + mutex_unlock(&media_devnode_lock); + + mdev->minor = minor; + + /* Part 2: Initialize and register the character device */ + cdev_init(&mdev->cdev, &media_devnode_fops); + mdev->cdev.owner = mdev->fops->owner; + + ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1); + if (ret < 0) { + printk(KERN_ERR "%s: cdev_add failed\n", __func__); + goto error; + } + + /* Part 3: Register the media device */ + mdev->dev.bus = &media_bus_type; + mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor); + mdev->dev.release = media_devnode_release; + if (mdev->parent) + mdev->dev.parent = mdev->parent; + dev_set_name(&mdev->dev, "media%d", mdev->minor); + ret = device_register(&mdev->dev); + if (ret < 0) { + printk(KERN_ERR "%s: device_register failed\n", __func__); + goto error; + } + + /* Part 4: Activate this minor. The char device can now be used. */ + set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + + return 0; + +error: + cdev_del(&mdev->cdev); + clear_bit(mdev->minor, media_devnode_nums); + return ret; +} + +/** + * media_devnode_unregister - unregister a media device node + * @mdev: the device node to unregister + * + * This unregisters the passed device. Future open calls will be met with + * errors. + * + * This function can safely be called if the device node has never been + * registered or has already been unregistered. + */ +void media_devnode_unregister(struct media_devnode *mdev) +{ + /* Check if mdev was ever registered at all */ + if (!media_devnode_is_registered(mdev)) + return; + + mutex_lock(&media_devnode_lock); + clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + mutex_unlock(&media_devnode_lock); + device_unregister(&mdev->dev); +} + +/* + * Initialise media for linux + */ +static int __init media_devnode_init(void) +{ + int ret; + + printk(KERN_INFO "Linux media interface: v0.10\n"); + ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES, + MEDIA_NAME); + if (ret < 0) { + printk(KERN_WARNING "media: unable to allocate major\n"); + return ret; + } + + ret = bus_register(&media_bus_type); + if (ret < 0) { + unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); + printk(KERN_WARNING "media: bus_register failed\n"); + return -EIO; + } + + return 0; +} + +static void __exit media_devnode_exit(void) +{ + bus_unregister(&media_bus_type); + unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); +} + +module_init(media_devnode_init) +module_exit(media_devnode_exit) + +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_DESCRIPTION("Device node registration for media drivers"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-entity.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-entity.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-entity.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/media-entity.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,540 @@ +/* + * Media entity + * + * Copyright (C) 2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 +#include +#include +#include + +/** + * media_entity_init - Initialize a media entity + * + * @num_pads: Total number of sink and source pads. + * @extra_links: Initial estimate of the number of extra links. + * @pads: Array of 'num_pads' pads. + * + * The total number of pads is an intrinsic property of entities known by the + * entity driver, while the total number of links depends on hardware design + * and is an extrinsic property unknown to the entity driver. However, in most + * use cases the entity driver can guess the number of links which can safely + * be assumed to be equal to or larger than the number of pads. + * + * For those reasons the links array can be preallocated based on the entity + * driver guess and will be reallocated later if extra links need to be + * created. + * + * This function allocates a links array with enough space to hold at least + * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will + * be set to the number of allocated elements. + * + * The pads array is managed by the entity driver and passed to + * media_entity_init() where its pointer will be stored in the entity structure. + */ +int +media_entity_init(struct media_entity *entity, u16 num_pads, + struct media_pad *pads, u16 extra_links) +{ + struct media_link *links; + unsigned int max_links = num_pads + extra_links; + unsigned int i; + + links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL); + if (links == NULL) + return -ENOMEM; + + entity->group_id = 0; + entity->max_links = max_links; + entity->num_links = 0; + entity->num_backlinks = 0; + entity->num_pads = num_pads; + entity->pads = pads; + entity->links = links; + + for (i = 0; i < num_pads; i++) { + pads[i].entity = entity; + pads[i].index = i; + } + + return 0; +} +EXPORT_SYMBOL_GPL(media_entity_init); + +void +media_entity_cleanup(struct media_entity *entity) +{ + kfree(entity->links); +} +EXPORT_SYMBOL_GPL(media_entity_cleanup); + +/* ----------------------------------------------------------------------------- + * Graph traversal + */ + +static struct media_entity * +media_entity_other(struct media_entity *entity, struct media_link *link) +{ + if (link->source->entity == entity) + return link->sink->entity; + else + return link->source->entity; +} + +/* push an entity to traversal stack */ +static void stack_push(struct media_entity_graph *graph, + struct media_entity *entity) +{ + if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) { + WARN_ON(1); + return; + } + graph->top++; + graph->stack[graph->top].link = 0; + graph->stack[graph->top].entity = entity; +} + +static struct media_entity *stack_pop(struct media_entity_graph *graph) +{ + struct media_entity *entity; + + entity = graph->stack[graph->top].entity; + graph->top--; + + return entity; +} + +#define stack_peek(en) ((en)->stack[(en)->top - 1].entity) +#define link_top(en) ((en)->stack[(en)->top].link) +#define stack_top(en) ((en)->stack[(en)->top].entity) + +/** + * media_entity_graph_walk_start - Start walking the media graph at a given entity + * @graph: Media graph structure that will be used to walk the graph + * @entity: Starting entity + * + * This function initializes the graph traversal structure to walk the entities + * graph starting at the given entity. The traversal structure must not be + * modified by the caller during graph traversal. When done the structure can + * safely be freed. + */ +void media_entity_graph_walk_start(struct media_entity_graph *graph, + struct media_entity *entity) +{ + graph->top = 0; + graph->stack[graph->top].entity = NULL; + stack_push(graph, entity); +} +EXPORT_SYMBOL_GPL(media_entity_graph_walk_start); + +/** + * media_entity_graph_walk_next - Get the next entity in the graph + * @graph: Media graph structure + * + * Perform a depth-first traversal of the given media entities graph. + * + * The graph structure must have been previously initialized with a call to + * media_entity_graph_walk_start(). + * + * Return the next entity in the graph or NULL if the whole graph have been + * traversed. + */ +struct media_entity * +media_entity_graph_walk_next(struct media_entity_graph *graph) +{ + if (stack_top(graph) == NULL) + return NULL; + + /* + * Depth first search. Push entity to stack and continue from + * top of the stack until no more entities on the level can be + * found. + */ + while (link_top(graph) < stack_top(graph)->num_links) { + struct media_entity *entity = stack_top(graph); + struct media_link *link = &entity->links[link_top(graph)]; + struct media_entity *next; + + /* The link is not enabled so we do not follow. */ + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) { + link_top(graph)++; + continue; + } + + /* Get the entity in the other end of the link . */ + next = media_entity_other(entity, link); + + /* Was it the entity we came here from? */ + if (next == stack_peek(graph)) { + link_top(graph)++; + continue; + } + + /* Push the new entity to stack and start over. */ + link_top(graph)++; + stack_push(graph, next); + } + + return stack_pop(graph); +} +EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); + +/* ----------------------------------------------------------------------------- + * Pipeline management + */ + +/** + * media_entity_pipeline_start - Mark a pipeline as streaming + * @entity: Starting entity + * @pipe: Media pipeline to be assigned to all entities in the pipeline. + * + * Mark all entities connected to a given entity through enabled links, either + * directly or indirectly, as streaming. The given pipeline object is assigned to + * every entity in the pipeline and stored in the media_entity pipe field. + * + * Calls to this function can be nested, in which case the same number of + * media_entity_pipeline_stop() calls will be required to stop streaming. The + * pipeline pointer must be identical for all nested calls to + * media_entity_pipeline_start(). + */ +void media_entity_pipeline_start(struct media_entity *entity, + struct media_pipeline *pipe) +{ + struct media_device *mdev = entity->parent; + struct media_entity_graph graph; + + mutex_lock(&mdev->graph_mutex); + + media_entity_graph_walk_start(&graph, entity); + + while ((entity = media_entity_graph_walk_next(&graph))) { + entity->stream_count++; + WARN_ON(entity->pipe && entity->pipe != pipe); + entity->pipe = pipe; + } + + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_entity_pipeline_start); + +/** + * media_entity_pipeline_stop - Mark a pipeline as not streaming + * @entity: Starting entity + * + * Mark all entities connected to a given entity through enabled links, either + * directly or indirectly, as not streaming. The media_entity pipe field is + * reset to NULL. + * + * If multiple calls to media_entity_pipeline_start() have been made, the same + * number of calls to this function are required to mark the pipeline as not + * streaming. + */ +void media_entity_pipeline_stop(struct media_entity *entity) +{ + struct media_device *mdev = entity->parent; + struct media_entity_graph graph; + + mutex_lock(&mdev->graph_mutex); + + media_entity_graph_walk_start(&graph, entity); + + while ((entity = media_entity_graph_walk_next(&graph))) { + entity->stream_count--; + if (entity->stream_count == 0) + entity->pipe = NULL; + } + + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_entity_pipeline_stop); + +/* ----------------------------------------------------------------------------- + * Module use count + */ + +/* + * media_entity_get - Get a reference to the parent module + * @entity: The entity + * + * Get a reference to the parent media device module. + * + * The function will return immediately if @entity is NULL. + * + * Return a pointer to the entity on success or NULL on failure. + */ +struct media_entity *media_entity_get(struct media_entity *entity) +{ + if (entity == NULL) + return NULL; + + if (entity->parent->dev && + !try_module_get(entity->parent->dev->driver->owner)) + return NULL; + + return entity; +} +EXPORT_SYMBOL_GPL(media_entity_get); + +/* + * media_entity_put - Release the reference to the parent module + * @entity: The entity + * + * Release the reference count acquired by media_entity_get(). + * + * The function will return immediately if @entity is NULL. + */ +void media_entity_put(struct media_entity *entity) +{ + if (entity == NULL) + return; + + if (entity->parent->dev) + module_put(entity->parent->dev->driver->owner); +} +EXPORT_SYMBOL_GPL(media_entity_put); + +/* ----------------------------------------------------------------------------- + * Links management + */ + +static struct media_link *media_entity_add_link(struct media_entity *entity) +{ + if (entity->num_links >= entity->max_links) { + struct media_link *links = entity->links; + unsigned int max_links = entity->max_links + 2; + unsigned int i; + + links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL); + if (links == NULL) + return NULL; + + for (i = 0; i < entity->num_links; i++) + links[i].reverse->reverse = &links[i]; + + entity->max_links = max_links; + entity->links = links; + } + + return &entity->links[entity->num_links++]; +} + +int +media_entity_create_link(struct media_entity *source, u16 source_pad, + struct media_entity *sink, u16 sink_pad, u32 flags) +{ + struct media_link *link; + struct media_link *backlink; + + BUG_ON(source == NULL || sink == NULL); + BUG_ON(source_pad >= source->num_pads); + BUG_ON(sink_pad >= sink->num_pads); + + link = media_entity_add_link(source); + if (link == NULL) + return -ENOMEM; + + link->source = &source->pads[source_pad]; + link->sink = &sink->pads[sink_pad]; + link->flags = flags; + + /* Create the backlink. Backlinks are used to help graph traversal and + * are not reported to userspace. + */ + backlink = media_entity_add_link(sink); + if (backlink == NULL) { + source->num_links--; + return -ENOMEM; + } + + backlink->source = &source->pads[source_pad]; + backlink->sink = &sink->pads[sink_pad]; + backlink->flags = flags; + + link->reverse = backlink; + backlink->reverse = link; + + sink->num_backlinks++; + + return 0; +} +EXPORT_SYMBOL_GPL(media_entity_create_link); + +static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) +{ + int ret; + + /* Notify both entities. */ + ret = media_entity_call(link->source->entity, link_setup, + link->source, link->sink, flags); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + + ret = media_entity_call(link->sink->entity, link_setup, + link->sink, link->source, flags); + if (ret < 0 && ret != -ENOIOCTLCMD) { + media_entity_call(link->source->entity, link_setup, + link->source, link->sink, link->flags); + return ret; + } + + link->flags = flags; + link->reverse->flags = link->flags; + + return 0; +} + +/** + * __media_entity_setup_link - Configure a media link + * @link: The link being configured + * @flags: Link configuration flags + * + * The bulk of link setup is handled by the two entities connected through the + * link. This function notifies both entities of the link configuration change. + * + * If the link is immutable or if the current and new configuration are + * identical, return immediately. + * + * The user is expected to hold link->source->parent->mutex. If not, + * media_entity_setup_link() should be used instead. + */ +int __media_entity_setup_link(struct media_link *link, u32 flags) +{ + const u32 mask = MEDIA_LNK_FL_ENABLED; + struct media_device *mdev; + struct media_entity *source, *sink; + int ret = -EBUSY; + + if (link == NULL) + return -EINVAL; + + /* The non-modifiable link flags must not be modified. */ + if ((link->flags & ~mask) != (flags & ~mask)) + return -EINVAL; + + if (link->flags & MEDIA_LNK_FL_IMMUTABLE) + return link->flags == flags ? 0 : -EINVAL; + + if (link->flags == flags) + return 0; + + source = link->source->entity; + sink = link->sink->entity; + + if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) && + (source->stream_count || sink->stream_count)) + return -EBUSY; + + mdev = source->parent; + + if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) { + ret = mdev->link_notify(link->source, link->sink, + MEDIA_LNK_FL_ENABLED); + if (ret < 0) + return ret; + } + + ret = __media_entity_setup_link_notify(link, flags); + if (ret < 0) + goto err; + + if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) + mdev->link_notify(link->source, link->sink, 0); + + return 0; + +err: + if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) + mdev->link_notify(link->source, link->sink, 0); + + return ret; +} + +int media_entity_setup_link(struct media_link *link, u32 flags) +{ + int ret; + + mutex_lock(&link->source->entity->parent->graph_mutex); + ret = __media_entity_setup_link(link, flags); + mutex_unlock(&link->source->entity->parent->graph_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(media_entity_setup_link); + +/** + * media_entity_find_link - Find a link between two pads + * @source: Source pad + * @sink: Sink pad + * + * Return a pointer to the link between the two entities. If no such link + * exists, return NULL. + */ +struct media_link * +media_entity_find_link(struct media_pad *source, struct media_pad *sink) +{ + struct media_link *link; + unsigned int i; + + for (i = 0; i < source->entity->num_links; ++i) { + link = &source->entity->links[i]; + + if (link->source->entity == source->entity && + link->source->index == source->index && + link->sink->entity == sink->entity && + link->sink->index == sink->index) + return link; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(media_entity_find_link); + +/** + * media_entity_remote_source - Find the source pad at the remote end of a link + * @pad: Sink pad at the local end of the link + * + * Search for a remote source pad connected to the given sink pad by iterating + * over all links originating or terminating at that pad until an enabled link + * is found. + * + * Return a pointer to the pad at the remote end of the first found enabled + * link, or NULL if no enabled link has been found. + */ +struct media_pad *media_entity_remote_source(struct media_pad *pad) +{ + unsigned int i; + + for (i = 0; i < pad->entity->num_links; i++) { + struct media_link *link = &pad->entity->links[i]; + + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; + + if (link->source == pad) + return link->sink; + + if (link->sink == pad) + return link->source; + } + + return NULL; + +} +EXPORT_SYMBOL_GPL(media_entity_remote_source); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/dsbr100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/dsbr100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/dsbr100.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/dsbr100.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,649 @@ +/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21. + The device plugs into both the USB and an analog audio input, so this thing + only deals with initialisation and frequency setting, the + audio data has to be handled by a sound driver. + + Major issue: I can't find out where the device reports the signal + strength, and indeed the windows software appearantly just looks + at the stereo indicator as well. So, scanning will only find + stereo stations. Sad, but I can't help it. + + Also, the windows program sends oodles of messages over to the + device, and I couldn't figure out their meaning. My suspicion + is that they don't have any:-) + + You might find some interesting stuff about this module at + http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr + + Copyright (c) 2000 Markus Demleitner + + 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, or + (at your option) any later version. + + 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 + + History: + + Version 0.46: + Removed usb_dsbr100_open/close calls and radio->users counter. Also, + radio->muted changed to radio->status and suspend/resume calls updated. + + Version 0.45: + Converted to v4l2_device. + + Version 0.44: + Add suspend/resume functions, fix unplug of device, + a lot of cleanups and fixes by Alexey Klimov + + Version 0.43: + Oliver Neukum: avoided DMA coherency issue + + Version 0.42: + Converted dsbr100 to use video_ioctl2 + by Douglas Landgraf + + Version 0.41-ac1: + Alan Cox: Some cleanups and fixes + + Version 0.41: + Converted to V4L2 API by Mauro Carvalho Chehab + + Version 0.40: + Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing + + Version 0.30: + Markus: Updates for 2.5.x kernel and more ISO compliant source + + Version 0.25: + PSL and Markus: Cleanup, radio now doesn't stop on device close + + Version 0.24: + Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally + right. Some minor cleanup, improved standalone compilation + + Version 0.23: + Markus: Sign extension bug fixed by declaring transfer_buffer unsigned + + Version 0.22: + Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, + thanks to Mike Cox for pointing the problem out. + + Version 0.21: + Markus: Minor cleanup, warnings if something goes wrong, lame attempt + to adhere to Documentation/CodingStyle + + Version 0.2: + Brad Hards : Fixes to make it work as non-module + Markus: Copyright clarification + + Version 0.01: Markus: initial release + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Version Information + */ +#include /* for KERNEL_VERSION MACRO */ + +#define DRIVER_VERSION "v0.46" +#define RADIO_VERSION KERNEL_VERSION(0, 4, 6) + +#define DRIVER_AUTHOR "Markus Demleitner " +#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" + +#define DSB100_VENDOR 0x04b4 +#define DSB100_PRODUCT 0x1002 + +/* Commands the device appears to understand */ +#define DSB100_TUNE 1 +#define DSB100_ONOFF 2 + +#define TB_LEN 16 + +/* Frequency limits in MHz -- these are European values. For Japanese +devices, that would be 76 and 91. */ +#define FREQ_MIN 87.5 +#define FREQ_MAX 108.0 +#define FREQ_MUL 16000 + +/* defines for radio->status */ +#define STARTED 0 +#define STOPPED 1 + +#define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev) + +static int usb_dsbr100_probe(struct usb_interface *intf, + const struct usb_device_id *id); +static void usb_dsbr100_disconnect(struct usb_interface *intf); +static int usb_dsbr100_suspend(struct usb_interface *intf, + pm_message_t message); +static int usb_dsbr100_resume(struct usb_interface *intf); + +static int radio_nr = -1; +module_param(radio_nr, int, 0); + +/* Data for one (physical) device */ +struct dsbr100_device { + struct usb_device *usbdev; + struct video_device videodev; + struct v4l2_device v4l2_dev; + + u8 *transfer_buffer; + struct mutex v4l2_lock; + int curfreq; + int stereo; + int status; +}; + +static struct usb_device_id usb_dsbr100_device_table [] = { + { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); + +/* USB subsystem interface */ +static struct usb_driver usb_dsbr100_driver = { + .name = "dsbr100", + .probe = usb_dsbr100_probe, + .disconnect = usb_dsbr100_disconnect, + .id_table = usb_dsbr100_device_table, + .suspend = usb_dsbr100_suspend, + .resume = usb_dsbr100_resume, + .reset_resume = usb_dsbr100_resume, + .supports_autosuspend = 0, +}; + +/* Low-level device interface begins here */ + +/* switch on radio */ +static int dsbr100_start(struct dsbr100_device *radio) +{ + int retval; + int request; + + retval = usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x00, 0xC7, radio->transfer_buffer, 8, 300); + + if (retval < 0) { + request = USB_REQ_GET_STATUS; + goto usb_control_msg_failed; + } + + retval = usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + DSB100_ONOFF, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x01, 0x00, radio->transfer_buffer, 8, 300); + + if (retval < 0) { + request = DSB100_ONOFF; + goto usb_control_msg_failed; + } + + radio->status = STARTED; + return (radio->transfer_buffer)[0]; + +usb_control_msg_failed: + dev_err(&radio->usbdev->dev, + "%s - usb_control_msg returned %i, request %i\n", + __func__, retval, request); + return retval; + +} + +/* switch off radio */ +static int dsbr100_stop(struct dsbr100_device *radio) +{ + int retval; + int request; + + retval = usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x16, 0x1C, radio->transfer_buffer, 8, 300); + + if (retval < 0) { + request = USB_REQ_GET_STATUS; + goto usb_control_msg_failed; + } + + retval = usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + DSB100_ONOFF, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x00, 0x00, radio->transfer_buffer, 8, 300); + + if (retval < 0) { + request = DSB100_ONOFF; + goto usb_control_msg_failed; + } + + radio->status = STOPPED; + return (radio->transfer_buffer)[0]; + +usb_control_msg_failed: + dev_err(&radio->usbdev->dev, + "%s - usb_control_msg returned %i, request %i\n", + __func__, retval, request); + return retval; + +} + +/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ +static int dsbr100_setfreq(struct dsbr100_device *radio) +{ + int retval; + int request; + int freq = (radio->curfreq / 16 * 80) / 1000 + 856; + + retval = usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + DSB100_TUNE, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + (freq >> 8) & 0x00ff, freq & 0xff, + radio->transfer_buffer, 8, 300); + + if (retval < 0) { + request = DSB100_TUNE; + goto usb_control_msg_failed; + } + + retval = usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x96, 0xB7, radio->transfer_buffer, 8, 300); + + if (retval < 0) { + request = USB_REQ_GET_STATUS; + goto usb_control_msg_failed; + } + + retval = usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x00, 0x24, radio->transfer_buffer, 8, 300); + + if (retval < 0) { + request = USB_REQ_GET_STATUS; + goto usb_control_msg_failed; + } + + radio->stereo = !((radio->transfer_buffer)[0] & 0x01); + return (radio->transfer_buffer)[0]; + +usb_control_msg_failed: + radio->stereo = -1; + dev_err(&radio->usbdev->dev, + "%s - usb_control_msg returned %i, request %i\n", + __func__, retval, request); + return retval; +} + +/* return the device status. This is, in effect, just whether it +sees a stereo signal or not. Pity. */ +static void dsbr100_getstat(struct dsbr100_device *radio) +{ + int retval; + + retval = usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + USB_REQ_GET_STATUS, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x00 , 0x24, radio->transfer_buffer, 8, 300); + + if (retval < 0) { + radio->stereo = -1; + dev_err(&radio->usbdev->dev, + "%s - usb_control_msg returned %i, request %i\n", + __func__, retval, USB_REQ_GET_STATUS); + } else { + radio->stereo = !(radio->transfer_buffer[0] & 0x01); + } +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + struct dsbr100_device *radio = video_drvdata(file); + + strlcpy(v->driver, "dsbr100", sizeof(v->driver)); + strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card)); + usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct dsbr100_device *radio = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + dsbr100_getstat(radio); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; + v->rangelow = FREQ_MIN * FREQ_MUL; + v->rangehigh = FREQ_MAX * FREQ_MUL; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + if(radio->stereo) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xffff; /* We can't get the signal strength */ + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct dsbr100_device *radio = video_drvdata(file); + int retval; + + radio->curfreq = f->frequency; + + retval = dsbr100_setfreq(radio); + if (retval < 0) + dev_warn(&radio->usbdev->dev, "Set frequency failed\n"); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct dsbr100_device *radio = video_drvdata(file); + + f->type = V4L2_TUNER_RADIO; + f->frequency = radio->curfreq; + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + } + + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct dsbr100_device *radio = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = radio->status; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct dsbr100_device *radio = video_drvdata(file); + int retval; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + retval = dsbr100_stop(radio); + if (retval < 0) { + dev_warn(&radio->usbdev->dev, + "Radio did not respond properly\n"); + return -EBUSY; + } + } else { + retval = dsbr100_start(radio); + if (retval < 0) { + dev_warn(&radio->usbdev->dev, + "Radio did not respond properly\n"); + return -EBUSY; + } + } + return 0; + } + return -EINVAL; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index > 1) + return -EINVAL; + + strcpy(a->name, "Radio"); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +/* USB subsystem interface begins here */ + +/* + * Handle unplugging of the device. + * We call video_unregister_device in any case. + * The last function called in this procedure is + * usb_dsbr100_video_device_release + */ +static void usb_dsbr100_disconnect(struct usb_interface *intf) +{ + struct dsbr100_device *radio = usb_get_intfdata(intf); + + v4l2_device_get(&radio->v4l2_dev); + mutex_lock(&radio->v4l2_lock); + usb_set_intfdata(intf, NULL); + video_unregister_device(&radio->videodev); + v4l2_device_disconnect(&radio->v4l2_dev); + mutex_unlock(&radio->v4l2_lock); + v4l2_device_put(&radio->v4l2_dev); +} + + +/* Suspend device - stop device. */ +static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct dsbr100_device *radio = usb_get_intfdata(intf); + int retval; + + mutex_lock(&radio->v4l2_lock); + if (radio->status == STARTED) { + retval = dsbr100_stop(radio); + if (retval < 0) + dev_warn(&intf->dev, "dsbr100_stop failed\n"); + + /* After dsbr100_stop() status set to STOPPED. + * If we want driver to start radio on resume + * we set status equal to STARTED. + * On resume we will check status and run radio if needed. + */ + radio->status = STARTED; + } + mutex_unlock(&radio->v4l2_lock); + + dev_info(&intf->dev, "going into suspend..\n"); + + return 0; +} + +/* Resume device - start device. */ +static int usb_dsbr100_resume(struct usb_interface *intf) +{ + struct dsbr100_device *radio = usb_get_intfdata(intf); + int retval; + + mutex_lock(&radio->v4l2_lock); + if (radio->status == STARTED) { + retval = dsbr100_start(radio); + if (retval < 0) + dev_warn(&intf->dev, "dsbr100_start failed\n"); + } + mutex_unlock(&radio->v4l2_lock); + + dev_info(&intf->dev, "coming out of suspend..\n"); + + return 0; +} + +/* free data structures */ +static void usb_dsbr100_release(struct v4l2_device *v4l2_dev) +{ + struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev); + + v4l2_device_unregister(&radio->v4l2_dev); + kfree(radio->transfer_buffer); + kfree(radio); +} + +/* File system interface */ +static const struct v4l2_file_operations usb_dsbr100_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +/* check if the device is present and register with v4l and usb if it is */ +static int usb_dsbr100_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dsbr100_device *radio; + struct v4l2_device *v4l2_dev; + int retval; + + radio = kzalloc(sizeof(struct dsbr100_device), GFP_KERNEL); + + if (!radio) + return -ENOMEM; + + radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL); + + if (!(radio->transfer_buffer)) { + kfree(radio); + return -ENOMEM; + } + + v4l2_dev = &radio->v4l2_dev; + v4l2_dev->release = usb_dsbr100_release; + + retval = v4l2_device_register(&intf->dev, v4l2_dev); + if (retval < 0) { + v4l2_err(v4l2_dev, "couldn't register v4l2_device\n"); + kfree(radio->transfer_buffer); + kfree(radio); + return retval; + } + + mutex_init(&radio->v4l2_lock); + strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name)); + radio->videodev.v4l2_dev = v4l2_dev; + radio->videodev.fops = &usb_dsbr100_fops; + radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops; + radio->videodev.release = video_device_release_empty; + radio->videodev.lock = &radio->v4l2_lock; + + radio->usbdev = interface_to_usbdev(intf); + radio->curfreq = FREQ_MIN * FREQ_MUL; + radio->status = STOPPED; + + video_set_drvdata(&radio->videodev, radio); + + retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); + if (retval < 0) { + v4l2_err(v4l2_dev, "couldn't register video device\n"); + v4l2_device_unregister(v4l2_dev); + kfree(radio->transfer_buffer); + kfree(radio); + return -EIO; + } + usb_set_intfdata(intf, radio); + return 0; +} + +static int __init dsbr100_init(void) +{ + int retval = usb_register(&usb_dsbr100_driver); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); + return retval; +} + +static void __exit dsbr100_exit(void) +{ + usb_deregister(&usb_dsbr100_driver); +} + +module_init (dsbr100_init); +module_exit (dsbr100_exit); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,446 @@ +# +# Multimedia Video device configuration +# + +menuconfig RADIO_ADAPTERS + bool "Radio Adapters" + depends on VIDEO_V4L2 + default y + ---help--- + Say Y here to enable selecting AM/FM radio adapters. + +if RADIO_ADAPTERS && VIDEO_V4L2 + +config RADIO_CADET + tristate "ADS Cadet AM/FM Tuner" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have one of these AM/FM radio cards, and then + fill in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + Further documentation on this driver can be found on the WWW at + . + + To compile this driver as a module, choose M here: the + module will be called radio-cadet. + +config RADIO_RTRACK + tristate "AIMSlab RadioTrack (aka RadioReveal) support" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + Note that newer AIMSlab RadioTrack cards have a different chipset + and are not supported by this driver. For these cards, use the + RadioTrack II driver below. + + If you have a GemTeks combined (PnP) sound- and radio card you must + use this driver as a module and setup the card with isapnptools. + You must also pass the module a suitable io parameter, 0x248 has + been reported to be used by these cards. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . More information is + contained in the file + . + + To compile this driver as a module, choose M here: the + module will be called radio-aimslab. + +config RADIO_RTRACK_PORT + hex "RadioTrack i/o port (0x20f or 0x30f)" + depends on RADIO_RTRACK=y + default "20f" + help + Enter either 0x30f or 0x20f here. The card default is 0x30f, if you + haven't changed the jumper setting on the card. + +config RADIO_RTRACK2 + tristate "AIMSlab RadioTrack II support" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have this FM radio card, and then fill in the + port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-rtrack2. + +config RADIO_RTRACK2_PORT + hex "RadioTrack II i/o port (0x20c or 0x30c)" + depends on RADIO_RTRACK2=y + default "30c" + help + Enter either 0x30c or 0x20c here. The card default is 0x30c, if you + haven't changed the jumper setting on the card. + +config RADIO_AZTECH + tristate "Aztech/Packard Bell Radio" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-aztech. + +config RADIO_AZTECH_PORT + hex "Aztech/Packard Bell I/O port (0x350 or 0x358)" + depends on RADIO_AZTECH=y + default "350" + help + Enter either 0x350 or 0x358 here. The card default is 0x350, if you + haven't changed the setting of jumper JP3 on the card. Removing the + jumper sets the card to 0x358. + +config RADIO_GEMTEK + tristate "GemTek Radio card (or compatible) support" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have this FM radio card, and then fill in the + I/O port address and settings below. The following cards either have + GemTek Radio tuner or are rebranded GemTek Radio cards: + + - Sound Vision 16 Gold with FM Radio + - Typhoon Radio card (some models) + - Hama Radio card + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-gemtek. + +config RADIO_GEMTEK_PORT + hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)" + depends on RADIO_GEMTEK=y + default "34c" + help + Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is + 0x34c, if you haven't changed the jumper setting on the card. On + Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O + port is 0x20c, 0x248 or 0x28c. + If automatic I/O port probing is enabled this port will be used only + in case of automatic probing failure, ie. as a fallback. + +config RADIO_GEMTEK_PROBE + bool "Automatic I/O port probing" + depends on RADIO_GEMTEK=y + default y + help + Say Y here to enable automatic probing for GemTek Radio card. The + following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and + 0x28c. + +config RADIO_MAXIRADIO + tristate "Guillemot MAXI Radio FM 2000 radio" + depends on VIDEO_V4L2 && PCI + ---help--- + Choose Y here if you have this radio card. This card may also be + found as Gemtek PCI FM. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-maxiradio. + +config RADIO_MIROPCM20 + tristate "miroSOUND PCM20 radio" + depends on ISA && VIDEO_V4L2 && SND + select SND_ISA + select SND_MIRO + ---help--- + Choose Y here if you have this FM radio card. You also need to enable + the ALSA sound system. This choice automatically selects the ALSA + sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this + is required for the radio-miropcm20. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-miropcm20. + +config RADIO_SF16FMI + tristate "SF16-FMI/SF16-FMP Radio" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have one of these FM radio cards. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-sf16fmi. + +config RADIO_SF16FMR2 + tristate "SF16FMR2 Radio" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have one of these FM radio cards. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + . + + To compile this driver as a module, choose M here: the + module will be called radio-sf16fmr2. + +config RADIO_TERRATEC + tristate "TerraTec ActiveRadio ISA Standalone" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have this FM radio card, and then fill in the + port address below. (TODO) + + Note: This driver is in its early stages. Right now volume and + frequency control and muting works at least for me, but + unfortunately I have not found anybody who wants to use this card + with Linux. So if it is this what YOU are trying to do right now, + PLEASE DROP ME A NOTE!! Rolf Offermanns . + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-terratec. + +config RADIO_TERRATEC_PORT + hex "Terratec i/o port (normally 0x590)" + depends on RADIO_TERRATEC=y + default "590" + help + Fill in the I/O port of your TerraTec FM radio card. If unsure, go + with the default. + +config RADIO_TRUST + tristate "Trust FM radio card" + depends on ISA && VIDEO_V4L2 + help + This is a driver for the Trust FM radio cards. Say Y if you have + such a card and want to use it under Linux. + + To compile this driver as a module, choose M here: the + module will be called radio-trust. + +config RADIO_TRUST_PORT + hex "Trust i/o port (usually 0x350 or 0x358)" + depends on RADIO_TRUST=y + default "350" + help + Enter the I/O port of your Trust FM radio card. If unsure, try the + values "0x350" or "0x358". + +config RADIO_TYPHOON + tristate "Typhoon Radio (a.k.a. EcoRadio)" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address and the frequency used for muting below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-typhoon. + +config RADIO_TYPHOON_PORT + hex "Typhoon I/O port (0x316 or 0x336)" + depends on RADIO_TYPHOON=y + default "316" + help + Enter the I/O port of your Typhoon or EcoRadio radio card. + +config RADIO_TYPHOON_MUTEFREQ + int "Typhoon frequency set when muting the device (kHz)" + depends on RADIO_TYPHOON=y + default "87500" + help + Enter the frequency used for muting the radio. The device is never + completely silent. If the volume is just turned down, you can still + hear silent voices and music. For that reason, the frequency of the + radio device is set to the frequency you can enter here whenever + the device is muted. There should be no local radio station at that + frequency. + +config RADIO_ZOLTRIX + tristate "Zoltrix Radio" + depends on ISA && VIDEO_V4L2 + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-zoltrix. + +config RADIO_ZOLTRIX_PORT + hex "ZOLTRIX I/O port (0x20c or 0x30c)" + depends on RADIO_ZOLTRIX=y + default "20c" + help + Enter the I/O port of your Zoltrix radio card. + +config I2C_SI4713 + tristate "I2C driver for Silicon Labs Si4713 device" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want support to Si4713 I2C device. + This device driver supports only i2c bus. + + To compile this driver as a module, choose M here: the + module will be called si4713. + +config RADIO_SI4713 + tristate "Silicon Labs Si4713 FM Radio Transmitter support" + depends on I2C && VIDEO_V4L2 + select I2C_SI4713 + ---help--- + Say Y here if you want support to Si4713 FM Radio Transmitter. + This device can transmit audio through FM. It can transmit + RDS and RBDS signals as well. This module is the v4l2 radio + interface for the i2c driver of this device. + + To compile this driver as a module, choose M here: the + module will be called radio-si4713. + +config USB_DSBR + tristate "D-Link/GemTek USB FM radio support" + depends on USB && VIDEO_V4L2 + ---help--- + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + + To compile this driver as a module, choose M here: the + module will be called dsbr100. + +config RADIO_SI470X + bool "Silicon Labs Si470x FM Radio Receiver support" + depends on VIDEO_V4L2 + +source "drivers/media/radio/si470x/Kconfig" + +config USB_MR800 + tristate "AverMedia MR 800 USB FM radio support" + depends on USB && VIDEO_V4L2 + ---help--- + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + + To compile this driver as a module, choose M here: the + module will be called radio-mr800. + +config RADIO_TEA5764 + tristate "TEA5764 I2C FM radio support" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want to use the TEA5764 FM chip found in + EZX phones. This FM chip is present in EZX phones from Motorola, + connected to internal pxa I2C bus. + + To compile this driver as a module, choose M here: the + module will be called radio-tea5764. + +config RADIO_TEA5764_XTAL + bool "TEA5764 crystal reference" + depends on RADIO_TEA5764=y + default y + help + Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N + here if TEA5764 reference frequency is connected in FREQIN. + +config RADIO_SAA7706H + tristate "SAA7706H Car Radio DSP" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want to use the SAA7706H Car radio Digital + Signal Processor, found for instance on the Russellville development + board. On the russellville the device is connected to internal + timberdale I2C bus. + + To compile this driver as a module, choose M here: the + module will be called SAA7706H. + +config RADIO_TEF6862 + tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want to use the TEF6862 Car Radio Enhanced + Selectivity Tuner, found for instance on the Russellville development + board. On the russellville the device is connected to internal + timberdale I2C bus. + + To compile this driver as a module, choose M here: the + module will be called TEF6862. + +config RADIO_TIMBERDALE + tristate "Enable the Timberdale radio driver" + depends on MFD_TIMBERDALE && VIDEO_V4L2 + depends on I2C # for RADIO_SAA7706H + select RADIO_TEF6862 + select RADIO_SAA7706H + ---help--- + This is a kind of umbrella driver for the Radio Tuner and DSP + found behind the Timberdale FPGA on the Russellville board. + Enabling this driver will automatically select the DSP and tuner. + +config RADIO_WL1273 + tristate "Texas Instruments WL1273 I2C FM Radio" + depends on I2C && VIDEO_V4L2 + select MFD_CORE + select MFD_WL1273_CORE + select FW_LOADER + ---help--- + Choose Y here if you have this FM radio chip. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-wl1273. + +# TI's ST based wl128x FM radio +source "drivers/media/radio/wl128x/Kconfig" + +endif # RADIO_ADAPTERS diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,30 @@ +# +# Makefile for the kernel character device drivers. +# + +obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o +obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o +obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o +obj-$(CONFIG_RADIO_SF16FMR2) += radio-sf16fmr2.o +obj-$(CONFIG_RADIO_CADET) += radio-cadet.o +obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o +obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o +obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o +obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o +obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o +obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o +obj-$(CONFIG_RADIO_TRUST) += radio-trust.o +obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o +obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o +obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o +obj-$(CONFIG_USB_DSBR) += dsbr100.o +obj-$(CONFIG_RADIO_SI470X) += si470x/ +obj-$(CONFIG_USB_MR800) += radio-mr800.o +obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o +obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o +obj-$(CONFIG_RADIO_TEF6862) += tef6862.o +obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o +obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o +obj-$(CONFIG_RADIO_WL128X) += wl128x/ + +EXTRA_CFLAGS += -Isound diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-aimslab.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-aimslab.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-aimslab.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-aimslab.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,437 @@ +/* radiotrack (radioreveal) driver for Linux radio support + * (c) 1997 M. Kirkwood + * Converted to V4L2 API by Mauro Carvalho Chehab + * Converted to new API by Alan Cox + * Various bugfixes and enhancements by Russell Kroll + * + * History: + * 1999-02-24 Russell Kroll + * Fine tuning/VIDEO_TUNER_LOW + * Frequency range expanded to start at 87 MHz + * + * TODO: Allow for more than one of these foolish entities :-) + * + * Notes on the hardware (reverse engineered from other peoples' + * reverse engineering of AIMS' code :-) + * + * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); + * + * The signal strength query is unsurprisingly inaccurate. And it seems + * to indicate that (on my card, at least) the frequency setting isn't + * too great. (I have to tune up .025MHz from what the freq should be + * to get a report that the thing is tuned.) + * + * Volume control is (ugh) analogue: + * out(port, start_increasing_volume); + * wait(a_wee_while); + * out(port, stop_changing_the_volume); + * + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* msleep */ +#include /* kernel radio structs */ +#include /* for KERNEL_VERSION MACRO */ +#include /* outb, outb_p */ +#include +#include + +MODULE_AUTHOR("M.Kirkwood"); +MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); +MODULE_LICENSE("GPL"); + +#ifndef CONFIG_RADIO_RTRACK_PORT +#define CONFIG_RADIO_RTRACK_PORT -1 +#endif + +static int io = CONFIG_RADIO_RTRACK_PORT; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct rtrack +{ + struct v4l2_device v4l2_dev; + struct video_device vdev; + int port; + int curvol; + unsigned long curfreq; + int muted; + int io; + struct mutex lock; +}; + +static struct rtrack rtrack_card; + +/* local things */ + +static void rt_decvol(struct rtrack *rt) +{ + outb(0x58, rt->io); /* volume down + sigstr + on */ + msleep(100); + outb(0xd8, rt->io); /* volume steady + sigstr + on */ +} + +static void rt_incvol(struct rtrack *rt) +{ + outb(0x98, rt->io); /* volume up + sigstr + on */ + msleep(100); + outb(0xd8, rt->io); /* volume steady + sigstr + on */ +} + +static void rt_mute(struct rtrack *rt) +{ + rt->muted = 1; + mutex_lock(&rt->lock); + outb(0xd0, rt->io); /* volume steady, off */ + mutex_unlock(&rt->lock); +} + +static int rt_setvol(struct rtrack *rt, int vol) +{ + int i; + + mutex_lock(&rt->lock); + + if (vol == rt->curvol) { /* requested volume = current */ + if (rt->muted) { /* user is unmuting the card */ + rt->muted = 0; + outb(0xd8, rt->io); /* enable card */ + } + mutex_unlock(&rt->lock); + return 0; + } + + if (vol == 0) { /* volume = 0 means mute the card */ + outb(0x48, rt->io); /* volume down but still "on" */ + msleep(2000); /* make sure it's totally down */ + outb(0xd0, rt->io); /* volume steady, off */ + rt->curvol = 0; /* track the volume state! */ + mutex_unlock(&rt->lock); + return 0; + } + + rt->muted = 0; + if (vol > rt->curvol) + for (i = rt->curvol; i < vol; i++) + rt_incvol(rt); + else + for (i = rt->curvol; i > vol; i--) + rt_decvol(rt); + + rt->curvol = vol; + mutex_unlock(&rt->lock); + return 0; +} + +/* the 128+64 on these outb's is to keep the volume stable while tuning + * without them, the volume _will_ creep up with each frequency change + * and bit 4 (+16) is to keep the signal strength meter enabled + */ + +static void send_0_byte(struct rtrack *rt) +{ + if (rt->curvol == 0 || rt->muted) { + outb_p(128+64+16+ 1, rt->io); /* wr-enable + data low */ + outb_p(128+64+16+2+1, rt->io); /* clock */ + } + else { + outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */ + outb_p(128+64+16+8+2+1, rt->io); /* clock */ + } + msleep(1); +} + +static void send_1_byte(struct rtrack *rt) +{ + if (rt->curvol == 0 || rt->muted) { + outb_p(128+64+16+4 +1, rt->io); /* wr-enable+data high */ + outb_p(128+64+16+4+2+1, rt->io); /* clock */ + } + else { + outb_p(128+64+16+8+4 +1, rt->io); /* on+wr-enable+data high */ + outb_p(128+64+16+8+4+2+1, rt->io); /* clock */ + } + + msleep(1); +} + +static int rt_setfreq(struct rtrack *rt, unsigned long freq) +{ + int i; + + mutex_lock(&rt->lock); /* Stop other ops interfering */ + + rt->curfreq = freq; + + /* now uses VIDEO_TUNER_LOW for fine tuning */ + + freq += 171200; /* Add 10.7 MHz IF */ + freq /= 800; /* Convert to 50 kHz units */ + + send_0_byte(rt); /* 0: LSB of frequency */ + + for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ + if (freq & (1 << i)) + send_1_byte(rt); + else + send_0_byte(rt); + + send_0_byte(rt); /* 14: test bit - always 0 */ + send_0_byte(rt); /* 15: test bit - always 0 */ + + send_0_byte(rt); /* 16: band data 0 - always 0 */ + send_0_byte(rt); /* 17: band data 1 - always 0 */ + send_0_byte(rt); /* 18: band data 2 - always 0 */ + send_0_byte(rt); /* 19: time base - always 0 */ + + send_0_byte(rt); /* 20: spacing (0 = 25 kHz) */ + send_1_byte(rt); /* 21: spacing (1 = 25 kHz) */ + send_0_byte(rt); /* 22: spacing (0 = 25 kHz) */ + send_1_byte(rt); /* 23: AM/FM (FM = 1, always) */ + + if (rt->curvol == 0 || rt->muted) + outb(0xd0, rt->io); /* volume steady + sigstr */ + else + outb(0xd8, rt->io); /* volume steady + sigstr + on */ + + mutex_unlock(&rt->lock); + + return 0; +} + +static int rt_getsigstr(struct rtrack *rt) +{ + int sig = 1; + + mutex_lock(&rt->lock); + if (inb(rt->io) & 2) /* bit set = no signal present */ + sig = 0; + mutex_unlock(&rt->lock); + return sig; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-aimslab", sizeof(v->driver)); + strlcpy(v->card, "RadioTrack", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct rtrack *rt = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = 87 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO; + v->capability = V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xffff * rt_getsigstr(rt); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct rtrack *rt = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + rt_setfreq(rt, f->frequency); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct rtrack *rt = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = rt->curfreq; + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct rtrack *rt = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = rt->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = rt->curvol; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct rtrack *rt = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + rt_mute(rt); + else + rt_setvol(rt, rt->curvol); + return 0; + case V4L2_CID_AUDIO_VOLUME: + rt_setvol(rt, ctrl->value); + return 0; + } + return -EINVAL; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static const struct v4l2_file_operations rtrack_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; + +static int __init rtrack_init(void) +{ + struct rtrack *rt = &rtrack_card; + struct v4l2_device *v4l2_dev = &rt->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name)); + rt->io = io; + + if (rt->io == -1) { + v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n"); + return -EINVAL; + } + + if (!request_region(rt->io, 2, "rtrack")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io); + return -EBUSY; + } + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(rt->io, 2); + v4l2_err(v4l2_dev, "could not register v4l2_device\n"); + return res; + } + + strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name)); + rt->vdev.v4l2_dev = v4l2_dev; + rt->vdev.fops = &rtrack_fops; + rt->vdev.ioctl_ops = &rtrack_ioctl_ops; + rt->vdev.release = video_device_release_empty; + video_set_drvdata(&rt->vdev, rt); + + /* Set up the I/O locking */ + + mutex_init(&rt->lock); + + /* mute card - prevents noisy bootups */ + + /* this ensures that the volume is all the way down */ + outb(0x48, rt->io); /* volume down but still "on" */ + msleep(2000); /* make sure it's totally down */ + outb(0xc0, rt->io); /* steady volume, mute card */ + + if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(&rt->v4l2_dev); + release_region(rt->io, 2); + return -EINVAL; + } + v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); + + return 0; +} + +static void __exit rtrack_exit(void) +{ + struct rtrack *rt = &rtrack_card; + + video_unregister_device(&rt->vdev); + v4l2_device_unregister(&rt->v4l2_dev); + release_region(rt->io, 2); +} + +module_init(rtrack_init); +module_exit(rtrack_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-aztech.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-aztech.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-aztech.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-aztech.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,401 @@ +/* radio-aztech.c - Aztech radio card driver for Linux 2.2 + * + * Converted to V4L2 API by Mauro Carvalho Chehab + * Adapted to support the Video for Linux API by + * Russell Kroll . Based on original tuner code by: + * + * Quay Ly + * Donald Song + * Jason Lewis (jlewis@twilight.vtc.vsc.edu) + * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) + * William McGrath (wmcgrath@twilight.vtc.vsc.edu) + * + * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ + * along with more information on the card itself. + * + * History: + * 1999-02-24 Russell Kroll + * Fine tuning/VIDEO_TUNER_LOW + * Range expanded to 87-108 MHz (from 87.9-107.8) + * + * Notable changes from the original source: + * - includes stripped down to the essentials + * - for loops used as delays replaced with udelay() + * - #defines removed, changed to static values + * - tuning structure changed - no more character arrays, other changes +*/ + +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* udelay */ +#include /* kernel radio structs */ +#include /* for KERNEL_VERSION MACRO */ +#include /* outb, outb_p */ +#include +#include + +MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the Aztech radio card."); +MODULE_LICENSE("GPL"); + +/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ + +#ifndef CONFIG_RADIO_AZTECH_PORT +#define CONFIG_RADIO_AZTECH_PORT -1 +#endif + +static int io = CONFIG_RADIO_AZTECH_PORT; +static int radio_nr = -1; +static int radio_wait_time = 1000; + +module_param(io, int, 0); +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct aztech +{ + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + int curvol; + unsigned long curfreq; + int stereo; + struct mutex lock; +}; + +static struct aztech aztech_card; + +static int volconvert(int level) +{ + level >>= 14; /* Map 16bits down to 2 bit */ + level &= 3; + + /* convert to card-friendly values */ + switch (level) { + case 0: + return 0; + case 1: + return 1; + case 2: + return 4; + case 3: + return 5; + } + return 0; /* Quieten gcc */ +} + +static void send_0_byte(struct aztech *az) +{ + udelay(radio_wait_time); + outb_p(2 + volconvert(az->curvol), az->io); + outb_p(64 + 2 + volconvert(az->curvol), az->io); +} + +static void send_1_byte(struct aztech *az) +{ + udelay (radio_wait_time); + outb_p(128 + 2 + volconvert(az->curvol), az->io); + outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io); +} + +static int az_setvol(struct aztech *az, int vol) +{ + mutex_lock(&az->lock); + outb(volconvert(vol), az->io); + mutex_unlock(&az->lock); + return 0; +} + +/* thanks to Michael Dwyer for giving me a dose of clues in + * the signal strength department.. + * + * This card has a stereo bit - bit 0 set = mono, not set = stereo + * It also has a "signal" bit - bit 1 set = bad signal, not set = good + * + */ + +static int az_getsigstr(struct aztech *az) +{ + int sig = 1; + + mutex_lock(&az->lock); + if (inb(az->io) & 2) /* bit set = no signal present */ + sig = 0; + mutex_unlock(&az->lock); + return sig; +} + +static int az_getstereo(struct aztech *az) +{ + int stereo = 1; + + mutex_lock(&az->lock); + if (inb(az->io) & 1) /* bit set = mono */ + stereo = 0; + mutex_unlock(&az->lock); + return stereo; +} + +static int az_setfreq(struct aztech *az, unsigned long frequency) +{ + int i; + + mutex_lock(&az->lock); + + az->curfreq = frequency; + frequency += 171200; /* Add 10.7 MHz IF */ + frequency /= 800; /* Convert to 50 kHz units */ + + send_0_byte(az); /* 0: LSB of frequency */ + + for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ + if (frequency & (1 << i)) + send_1_byte(az); + else + send_0_byte(az); + + send_0_byte(az); /* 14: test bit - always 0 */ + send_0_byte(az); /* 15: test bit - always 0 */ + send_0_byte(az); /* 16: band data 0 - always 0 */ + if (az->stereo) /* 17: stereo (1 to enable) */ + send_1_byte(az); + else + send_0_byte(az); + + send_1_byte(az); /* 18: band data 1 - unknown */ + send_0_byte(az); /* 19: time base - always 0 */ + send_0_byte(az); /* 20: spacing (0 = 25 kHz) */ + send_1_byte(az); /* 21: spacing (1 = 25 kHz) */ + send_0_byte(az); /* 22: spacing (0 = 25 kHz) */ + send_1_byte(az); /* 23: AM/FM (FM = 1, always) */ + + /* latch frequency */ + + udelay(radio_wait_time); + outb_p(128 + 64 + volconvert(az->curvol), az->io); + + mutex_unlock(&az->lock); + + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-aztech", sizeof(v->driver)); + strlcpy(v->card, "Aztech Radio", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct aztech *az = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + + v->rangelow = 87 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + if (az_getstereo(az)) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xFFFF * az_getsigstr(az); + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct aztech *az = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + az_setfreq(az, f->frequency); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct aztech *az = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = az->curfreq; + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct aztech *az = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (az->curvol == 0) + ctrl->value = 1; + else + ctrl->value = 0; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = az->curvol * 6554; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct aztech *az = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + az_setvol(az, 0); + else + az_setvol(az, az->curvol); + return 0; + case V4L2_CID_AUDIO_VOLUME: + az_setvol(az, ctrl->value); + return 0; + } + return -EINVAL; +} + +static const struct v4l2_file_operations aztech_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops aztech_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; + +static int __init aztech_init(void) +{ + struct aztech *az = &aztech_card; + struct v4l2_device *v4l2_dev = &az->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name)); + az->io = io; + + if (az->io == -1) { + v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n"); + return -EINVAL; + } + + if (!request_region(az->io, 2, "aztech")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io); + return -EBUSY; + } + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(az->io, 2); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + mutex_init(&az->lock); + strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name)); + az->vdev.v4l2_dev = v4l2_dev; + az->vdev.fops = &aztech_fops; + az->vdev.ioctl_ops = &aztech_ioctl_ops; + az->vdev.release = video_device_release_empty; + video_set_drvdata(&az->vdev, az); + /* mute card - prevents noisy bootups */ + outb(0, az->io); + + if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(az->io, 2); + return -EINVAL; + } + + v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); + return 0; +} + +static void __exit aztech_exit(void) +{ + struct aztech *az = &aztech_card; + + video_unregister_device(&az->vdev); + v4l2_device_unregister(&az->v4l2_dev); + release_region(az->io, 2); +} + +module_init(aztech_init); +module_exit(aztech_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-cadet.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-cadet.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-cadet.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-cadet.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,717 @@ +/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card + * + * by Fred Gleason + * Version 0.3.3 + * + * (Loosely) based on code for the Aztech radio card by + * + * Russell Kroll (rkroll@exploits.org) + * Quay Ly + * Donald Song + * Jason Lewis (jlewis@twilight.vtc.vsc.edu) + * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) + * William McGrath (wmcgrath@twilight.vtc.vsc.edu) + * + * History: + * 2000-04-29 Russell Kroll + * Added ISAPnP detection for Linux 2.3/2.4 + * + * 2001-01-10 Russell Kroll + * Removed dead CONFIG_RADIO_CADET_PORT code + * PnP detection on load is now default (no args necessary) + * + * 2002-01-17 Adam Belay + * Updated to latest pnp code + * + * 2003-01-31 Alan Cox + * Cleaned up locking, delay code, general odds and ends + * + * 2006-07-30 Hans J. Koch + * Changed API to V4L2 + */ + +#include +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* udelay */ +#include /* V4L2 API defs */ +#include +#include +#include +#include /* outb, outb_p */ +#include +#include + +MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); +MODULE_LICENSE("GPL"); + +static int io = -1; /* default to isapnp activation */ +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); +module_param(radio_nr, int, 0); + +#define CADET_VERSION KERNEL_VERSION(0, 3, 3) + +#define RDS_BUFFER 256 +#define RDS_RX_FLAG 1 +#define MBS_RX_FLAG 2 + +struct cadet { + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + int users; + int curtuner; + int tunestat; + int sigstrength; + wait_queue_head_t read_queue; + struct timer_list readtimer; + __u8 rdsin, rdsout, rdsstat; + unsigned char rdsbuf[RDS_BUFFER]; + struct mutex lock; + int reading; +}; + +static struct cadet cadet_card; + +/* + * Signal Strength Threshold Values + * The V4L API spec does not define any particular unit for the signal + * strength value. These values are in microvolts of RF at the tuner's input. + */ +static __u16 sigtable[2][4] = { + { 5, 10, 30, 150 }, + { 28, 40, 63, 1000 } +}; + + +static int cadet_getstereo(struct cadet *dev) +{ + int ret = V4L2_TUNER_SUB_MONO; + + if (dev->curtuner != 0) /* Only FM has stereo capability! */ + return V4L2_TUNER_SUB_MONO; + + mutex_lock(&dev->lock); + outb(7, dev->io); /* Select tuner control */ + if ((inb(dev->io + 1) & 0x40) == 0) + ret = V4L2_TUNER_SUB_STEREO; + mutex_unlock(&dev->lock); + return ret; +} + +static unsigned cadet_gettune(struct cadet *dev) +{ + int curvol, i; + unsigned fifo = 0; + + /* + * Prepare for read + */ + + mutex_lock(&dev->lock); + + outb(7, dev->io); /* Select tuner control */ + curvol = inb(dev->io + 1); /* Save current volume/mute setting */ + outb(0x00, dev->io + 1); /* Ensure WRITE-ENABLE is LOW */ + dev->tunestat = 0xffff; + + /* + * Read the shift register + */ + for (i = 0; i < 25; i++) { + fifo = (fifo << 1) | ((inb(dev->io + 1) >> 7) & 0x01); + if (i < 24) { + outb(0x01, dev->io + 1); + dev->tunestat &= inb(dev->io + 1); + outb(0x00, dev->io + 1); + } + } + + /* + * Restore volume/mute setting + */ + outb(curvol, dev->io + 1); + mutex_unlock(&dev->lock); + + return fifo; +} + +static unsigned cadet_getfreq(struct cadet *dev) +{ + int i; + unsigned freq = 0, test, fifo = 0; + + /* + * Read current tuning + */ + fifo = cadet_gettune(dev); + + /* + * Convert to actual frequency + */ + if (dev->curtuner == 0) { /* FM */ + test = 12500; + for (i = 0; i < 14; i++) { + if ((fifo & 0x01) != 0) + freq += test; + test = test << 1; + fifo = fifo >> 1; + } + freq -= 10700000; /* IF frequency is 10.7 MHz */ + freq = (freq * 16) / 1000000; /* Make it 1/16 MHz */ + } + if (dev->curtuner == 1) /* AM */ + freq = ((fifo & 0x7fff) - 2010) * 16; + + return freq; +} + +static void cadet_settune(struct cadet *dev, unsigned fifo) +{ + int i; + unsigned test; + + mutex_lock(&dev->lock); + + outb(7, dev->io); /* Select tuner control */ + /* + * Write the shift register + */ + test = 0; + test = (fifo >> 23) & 0x02; /* Align data for SDO */ + test |= 0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */ + outb(7, dev->io); /* Select tuner control */ + outb(test, dev->io + 1); /* Initialize for write */ + for (i = 0; i < 25; i++) { + test |= 0x01; /* Toggle SCK High */ + outb(test, dev->io + 1); + test &= 0xfe; /* Toggle SCK Low */ + outb(test, dev->io + 1); + fifo = fifo << 1; /* Prepare the next bit */ + test = 0x1c | ((fifo >> 23) & 0x02); + outb(test, dev->io + 1); + } + mutex_unlock(&dev->lock); +} + +static void cadet_setfreq(struct cadet *dev, unsigned freq) +{ + unsigned fifo; + int i, j, test; + int curvol; + + /* + * Formulate a fifo command + */ + fifo = 0; + if (dev->curtuner == 0) { /* FM */ + test = 102400; + freq = (freq * 1000) / 16; /* Make it kHz */ + freq += 10700; /* IF is 10700 kHz */ + for (i = 0; i < 14; i++) { + fifo = fifo << 1; + if (freq >= test) { + fifo |= 0x01; + freq -= test; + } + test = test >> 1; + } + } + if (dev->curtuner == 1) { /* AM */ + fifo = (freq / 16) + 2010; /* Make it kHz */ + fifo |= 0x100000; /* Select AM Band */ + } + + /* + * Save current volume/mute setting + */ + + mutex_lock(&dev->lock); + outb(7, dev->io); /* Select tuner control */ + curvol = inb(dev->io + 1); + mutex_unlock(&dev->lock); + + /* + * Tune the card + */ + for (j = 3; j > -1; j--) { + cadet_settune(dev, fifo | (j << 16)); + + mutex_lock(&dev->lock); + outb(7, dev->io); /* Select tuner control */ + outb(curvol, dev->io + 1); + mutex_unlock(&dev->lock); + + msleep(100); + + cadet_gettune(dev); + if ((dev->tunestat & 0x40) == 0) { /* Tuned */ + dev->sigstrength = sigtable[dev->curtuner][j]; + return; + } + } + dev->sigstrength = 0; +} + + +static int cadet_getvol(struct cadet *dev) +{ + int ret = 0; + + mutex_lock(&dev->lock); + + outb(7, dev->io); /* Select tuner control */ + if ((inb(dev->io + 1) & 0x20) != 0) + ret = 0xffff; + + mutex_unlock(&dev->lock); + return ret; +} + + +static void cadet_setvol(struct cadet *dev, int vol) +{ + mutex_lock(&dev->lock); + outb(7, dev->io); /* Select tuner control */ + if (vol > 0) + outb(0x20, dev->io + 1); + else + outb(0x00, dev->io + 1); + mutex_unlock(&dev->lock); +} + +static void cadet_handler(unsigned long data) +{ + struct cadet *dev = (void *)data; + + /* Service the RDS fifo */ + if (mutex_trylock(&dev->lock)) { + outb(0x3, dev->io); /* Select RDS Decoder Control */ + if ((inb(dev->io + 1) & 0x20) != 0) + printk(KERN_CRIT "cadet: RDS fifo overflow\n"); + outb(0x80, dev->io); /* Select RDS fifo */ + while ((inb(dev->io) & 0x80) != 0) { + dev->rdsbuf[dev->rdsin] = inb(dev->io + 1); + if (dev->rdsin == dev->rdsout) + printk(KERN_WARNING "cadet: RDS buffer overflow\n"); + else + dev->rdsin++; + } + mutex_unlock(&dev->lock); + } + + /* + * Service pending read + */ + if (dev->rdsin != dev->rdsout) + wake_up_interruptible(&dev->read_queue); + + /* + * Clean up and exit + */ + init_timer(&dev->readtimer); + dev->readtimer.function = cadet_handler; + dev->readtimer.data = (unsigned long)0; + dev->readtimer.expires = jiffies + msecs_to_jiffies(50); + add_timer(&dev->readtimer); +} + + +static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +{ + struct cadet *dev = video_drvdata(file); + unsigned char readbuf[RDS_BUFFER]; + int i = 0; + + mutex_lock(&dev->lock); + if (dev->rdsstat == 0) { + dev->rdsstat = 1; + outb(0x80, dev->io); /* Select RDS fifo */ + init_timer(&dev->readtimer); + dev->readtimer.function = cadet_handler; + dev->readtimer.data = (unsigned long)dev; + dev->readtimer.expires = jiffies + msecs_to_jiffies(50); + add_timer(&dev->readtimer); + } + if (dev->rdsin == dev->rdsout) { + mutex_unlock(&dev->lock); + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + interruptible_sleep_on(&dev->read_queue); + mutex_lock(&dev->lock); + } + while (i < count && dev->rdsin != dev->rdsout) + readbuf[i++] = dev->rdsbuf[dev->rdsout++]; + mutex_unlock(&dev->lock); + + if (copy_to_user(data, readbuf, i)) + return -EFAULT; + return i; +} + + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "ADS Cadet", sizeof(v->driver)); + strlcpy(v->card, "ADS Cadet", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = CADET_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct cadet *dev = video_drvdata(file); + + v->type = V4L2_TUNER_RADIO; + switch (v->index) { + case 0: + strlcpy(v->name, "FM", sizeof(v->name)); + v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_RDS_BLOCK_IO; + v->rangelow = 1400; /* 87.5 MHz */ + v->rangehigh = 1728; /* 108.0 MHz */ + v->rxsubchans = cadet_getstereo(dev); + switch (v->rxsubchans) { + case V4L2_TUNER_SUB_MONO: + v->audmode = V4L2_TUNER_MODE_MONO; + break; + case V4L2_TUNER_SUB_STEREO: + v->audmode = V4L2_TUNER_MODE_STEREO; + break; + default: + break; + } + v->rxsubchans |= V4L2_TUNER_SUB_RDS; + break; + case 1: + strlcpy(v->name, "AM", sizeof(v->name)); + v->capability = V4L2_TUNER_CAP_LOW; + v->rangelow = 8320; /* 520 kHz */ + v->rangehigh = 26400; /* 1650 kHz */ + v->rxsubchans = V4L2_TUNER_SUB_MONO; + v->audmode = V4L2_TUNER_MODE_MONO; + break; + default: + return -EINVAL; + } + v->signal = dev->sigstrength; /* We might need to modify scaling of this */ + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct cadet *dev = video_drvdata(file); + + if (v->index != 0 && v->index != 1) + return -EINVAL; + dev->curtuner = v->index; + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cadet *dev = video_drvdata(file); + + f->tuner = dev->curtuner; + f->type = V4L2_TUNER_RADIO; + f->frequency = cadet_getfreq(dev); + return 0; +} + + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cadet *dev = video_drvdata(file); + + if (f->type != V4L2_TUNER_RADIO) + return -EINVAL; + if (dev->curtuner == 0 && (f->frequency < 1400 || f->frequency > 1728)) + return -EINVAL; + if (dev->curtuner == 1 && (f->frequency < 8320 || f->frequency > 26400)) + return -EINVAL; + cadet_setfreq(dev, f->frequency); + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct cadet *dev = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ + ctrl->value = (cadet_getvol(dev) == 0); + break; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = cadet_getvol(dev); + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct cadet *dev = video_drvdata(file); + + switch (ctrl->id){ + case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ + if (ctrl->value) + cadet_setvol(dev, 0); + else + cadet_setvol(dev, 0xffff); + break; + case V4L2_CID_AUDIO_VOLUME: + cadet_setvol(dev, ctrl->value); + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static int cadet_open(struct file *file) +{ + struct cadet *dev = video_drvdata(file); + + mutex_lock(&dev->lock); + dev->users++; + if (1 == dev->users) + init_waitqueue_head(&dev->read_queue); + mutex_unlock(&dev->lock); + return 0; +} + +static int cadet_release(struct file *file) +{ + struct cadet *dev = video_drvdata(file); + + mutex_lock(&dev->lock); + dev->users--; + if (0 == dev->users) { + del_timer_sync(&dev->readtimer); + dev->rdsstat = 0; + } + mutex_unlock(&dev->lock); + return 0; +} + +static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait) +{ + struct cadet *dev = video_drvdata(file); + + poll_wait(file, &dev->read_queue, wait); + if (dev->rdsin != dev->rdsout) + return POLLIN | POLLRDNORM; + return 0; +} + + +static const struct v4l2_file_operations cadet_fops = { + .owner = THIS_MODULE, + .open = cadet_open, + .release = cadet_release, + .read = cadet_read, + .unlocked_ioctl = video_ioctl2, + .poll = cadet_poll, +}; + +static const struct v4l2_ioctl_ops cadet_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +#ifdef CONFIG_PNP + +static struct pnp_device_id cadet_pnp_devices[] = { + /* ADS Cadet AM/FM Radio Card */ + {.id = "MSM0c24", .driver_data = 0}, + {.id = ""} +}; + +MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices); + +static int cadet_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) +{ + if (!dev) + return -ENODEV; + /* only support one device */ + if (io > 0) + return -EBUSY; + + if (!pnp_port_valid(dev, 0)) + return -ENODEV; + + io = pnp_port_start(dev, 0); + + printk(KERN_INFO "radio-cadet: PnP reports device at %#x\n", io); + + return io; +} + +static struct pnp_driver cadet_pnp_driver = { + .name = "radio-cadet", + .id_table = cadet_pnp_devices, + .probe = cadet_pnp_probe, + .remove = NULL, +}; + +#else +static struct pnp_driver cadet_pnp_driver; +#endif + +static void cadet_probe(struct cadet *dev) +{ + static int iovals[8] = { 0x330, 0x332, 0x334, 0x336, 0x338, 0x33a, 0x33c, 0x33e }; + int i; + + for (i = 0; i < 8; i++) { + dev->io = iovals[i]; + if (request_region(dev->io, 2, "cadet-probe")) { + cadet_setfreq(dev, 1410); + if (cadet_getfreq(dev) == 1410) { + release_region(dev->io, 2); + return; + } + release_region(dev->io, 2); + } + } + dev->io = -1; +} + +/* + * io should only be set if the user has used something like + * isapnp (the userspace program) to initialize this card for us + */ + +static int __init cadet_init(void) +{ + struct cadet *dev = &cadet_card; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name)); + mutex_init(&dev->lock); + + /* If a probe was requested then probe ISAPnP first (safest) */ + if (io < 0) + pnp_register_driver(&cadet_pnp_driver); + dev->io = io; + + /* If that fails then probe unsafely if probe is requested */ + if (dev->io < 0) + cadet_probe(dev); + + /* Else we bail out */ + if (dev->io < 0) { +#ifdef MODULE + v4l2_err(v4l2_dev, "you must set an I/O address with io=0x330, 0x332, 0x334,\n"); + v4l2_err(v4l2_dev, "0x336, 0x338, 0x33a, 0x33c or 0x33e\n"); +#endif + goto fail; + } + if (!request_region(dev->io, 2, "cadet")) + goto fail; + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(dev->io, 2); + v4l2_err(v4l2_dev, "could not register v4l2_device\n"); + goto fail; + } + + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &cadet_fops; + dev->vdev.ioctl_ops = &cadet_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); + + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(dev->io, 2); + goto fail; + } + v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io); + return 0; +fail: + pnp_unregister_driver(&cadet_pnp_driver); + return -ENODEV; +} + +static void __exit cadet_exit(void) +{ + struct cadet *dev = &cadet_card; + + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); + release_region(dev->io, 2); + pnp_unregister_driver(&cadet_pnp_driver); +} + +module_init(cadet_init); +module_exit(cadet_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-gemtek.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-gemtek.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-gemtek.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-gemtek.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,617 @@ +/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin + * + * GemTek hasn't released any specs on the card, so the protocol had to + * be reverse engineered with dosemu. + * + * Besides the protocol changes, this is mostly a copy of: + * + * RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff + * + * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood + * Converted to new API by Alan Cox + * Various bugfixes and enhancements by Russell Kroll + * + * TODO: Allow for more than one of these foolish entities :-) + * + * Converted to V4L2 API by Mauro Carvalho Chehab + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* udelay */ +#include /* kernel radio structs */ +#include /* for KERNEL_VERSION MACRO */ +#include +#include /* outb, outb_p */ +#include +#include + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 3) + +/* + * Module info. + */ + +MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen "); +MODULE_DESCRIPTION("A driver for the GemTek Radio card."); +MODULE_LICENSE("GPL"); + +/* + * Module params. + */ + +#ifndef CONFIG_RADIO_GEMTEK_PORT +#define CONFIG_RADIO_GEMTEK_PORT -1 +#endif +#ifndef CONFIG_RADIO_GEMTEK_PROBE +#define CONFIG_RADIO_GEMTEK_PROBE 1 +#endif + +static int io = CONFIG_RADIO_GEMTEK_PORT; +static int probe = CONFIG_RADIO_GEMTEK_PROBE; +static int hardmute; +static int shutdown = 1; +static int keepmuted = 1; +static int initmute = 1; +static int radio_nr = -1; + +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " + "probing is disabled or fails. The most common I/O ports are: 0x20c " + "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " + "work for the combined sound/radiocard)."); + +module_param(probe, bool, 0444); +MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " + "common I/O ports used by the card are probed."); + +module_param(hardmute, bool, 0644); +MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may " + "reduce static noise."); + +module_param(shutdown, bool, 0644); +MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when " + "module is unloaded."); + +module_param(keepmuted, bool, 0644); +MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed."); + +module_param(initmute, bool, 0444); +MODULE_PARM_DESC(initmute, "Mute card when module is loaded."); + +module_param(radio_nr, int, 0444); + +/* + * Functions for controlling the card. + */ +#define GEMTEK_LOWFREQ (87*16000) +#define GEMTEK_HIGHFREQ (108*16000) + +/* + * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal + * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz). + */ +#define FSCALE 8 +#define IF_OFFSET ((unsigned int)(10.52 * 16000 * (1<bu2614data = \ + ((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT)) + +/* + * Transmit settings to BU2614FS over GemTek IC. + */ +static void gemtek_bu2614_transmit(struct gemtek *gt) +{ + int i, bit, q, mute; + + mutex_lock(>->lock); + + mute = gt->muted ? GEMTEK_MT : 0x00; + + outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); + udelay(LONG_DELAY); + + for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) { + bit = (q & 1) ? GEMTEK_DA : 0; + outb_p(mute | GEMTEK_CE | bit, gt->io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io); + udelay(SHORT_DELAY); + } + + outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); + udelay(LONG_DELAY); + + mutex_unlock(>->lock); +} + +/* + * Calculate divisor from FM-frequency for BU2614FS (3.125 KHz STDF expected). + */ +static unsigned long gemtek_convfreq(unsigned long freq) +{ + return ((freq<muted) + return; + + freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ); + + gt->lastfreq = freq; + gt->muted = 0; + + gemtek_bu2614_set(gt, BU2614_PORT, 0); + gemtek_bu2614_set(gt, BU2614_FMES, 0); + gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(gt, BU2614_SWAL, 0); + gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */ + gemtek_bu2614_set(gt, BU2614_TEST, 0); + + gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); + gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq)); + + gemtek_bu2614_transmit(gt); +} + +/* + * Set mute flag. + */ +static void gemtek_mute(struct gemtek *gt) +{ + int i; + + gt->muted = 1; + + if (hardmute) { + /* Turn off PLL, disable data output */ + gemtek_bu2614_set(gt, BU2614_PORT, 0); + gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */ + gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(gt, BU2614_SWAL, 0); + gemtek_bu2614_set(gt, BU2614_FMUN, 0); /* GT bit off */ + gemtek_bu2614_set(gt, BU2614_TEST, 0); + gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF); + gemtek_bu2614_set(gt, BU2614_FREQ, 0); + gemtek_bu2614_transmit(gt); + return; + } + + mutex_lock(>->lock); + + /* Read bus contents (CE, CK and DA). */ + i = inb_p(gt->io); + /* Write it back with mute flag set. */ + outb_p((i >> 5) | GEMTEK_MT, gt->io); + udelay(SHORT_DELAY); + + mutex_unlock(>->lock); +} + +/* + * Unset mute flag. + */ +static void gemtek_unmute(struct gemtek *gt) +{ + int i; + + gt->muted = 0; + if (hardmute) { + /* Turn PLL back on. */ + gemtek_setfreq(gt, gt->lastfreq); + return; + } + mutex_lock(>->lock); + + i = inb_p(gt->io); + outb_p(i >> 5, gt->io); + udelay(SHORT_DELAY); + + mutex_unlock(>->lock); +} + +/* + * Get signal strength (= stereo status). + */ +static inline int gemtek_getsigstr(struct gemtek *gt) +{ + int sig; + + mutex_lock(>->lock); + sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1; + mutex_unlock(>->lock); + return sig; +} + +/* + * Check if requested card acts like GemTek Radio card. + */ +static int gemtek_verify(struct gemtek *gt, int port) +{ + int i, q; + + if (gt->verified == port) + return 1; + + mutex_lock(>->lock); + + q = inb_p(port); /* Read bus contents before probing. */ + /* Try to turn on CE, CK and DA respectively and check if card responds + properly. */ + for (i = 0; i < 3; ++i) { + outb_p(1 << i, port); + udelay(SHORT_DELAY); + + if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) { + mutex_unlock(>->lock); + return 0; + } + } + outb_p(q >> 5, port); /* Write bus contents back. */ + udelay(SHORT_DELAY); + + mutex_unlock(>->lock); + gt->verified = port; + + return 1; +} + +/* + * Automatic probing for card. + */ +static int gemtek_probe(struct gemtek *gt) +{ + struct v4l2_device *v4l2_dev = >->v4l2_dev; + int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; + int i; + + if (!probe) { + v4l2_info(v4l2_dev, "Automatic device probing disabled.\n"); + return -1; + } + + v4l2_info(v4l2_dev, "Automatic device probing enabled.\n"); + + for (i = 0; i < ARRAY_SIZE(ioports); ++i) { + v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]); + + if (!request_region(ioports[i], 1, "gemtek-probe")) { + v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n", + ioports[i]); + continue; + } + + if (gemtek_verify(gt, ioports[i])) { + v4l2_info(v4l2_dev, "Card found from I/O port " + "0x%x!\n", ioports[i]); + + release_region(ioports[i], 1); + gt->io = ioports[i]; + return gt->io; + } + + release_region(ioports[i], 1); + } + + v4l2_err(v4l2_dev, "Automatic probing failed!\n"); + return -1; +} + +/* + * Video 4 Linux stuff. + */ + +static const struct v4l2_file_operations gemtek_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); + strlcpy(v->card, "GemTek", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) +{ + struct gemtek *gt = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = GEMTEK_LOWFREQ; + v->rangehigh = GEMTEK_HIGHFREQ; + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + v->signal = 0xffff * gemtek_getsigstr(gt); + if (v->signal) { + v->audmode = V4L2_TUNER_MODE_STEREO; + v->rxsubchans = V4L2_TUNER_SUB_STEREO; + } else { + v->audmode = V4L2_TUNER_MODE_MONO; + v->rxsubchans = V4L2_TUNER_SUB_MONO; + } + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) +{ + return (v->index != 0) ? -EINVAL : 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct gemtek *gt = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = gt->lastfreq; + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct gemtek *gt = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + gemtek_setfreq(gt, f->frequency); + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); + default: + return -EINVAL; + } +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct gemtek *gt = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = gt->muted; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct gemtek *gt = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + gemtek_mute(gt); + else + gemtek_unmute(gt); + return 0; + } + return -EINVAL; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return (i != 0) ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + return (a->index != 0) ? -EINVAL : 0; +} + +static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl +}; + +/* + * Initialization / cleanup related stuff. + */ + +static int __init gemtek_init(void) +{ + struct gemtek *gt = &gemtek_card; + struct v4l2_device *v4l2_dev = >->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name)); + + v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n"); + + mutex_init(>->lock); + + gt->verified = -1; + gt->io = io; + gemtek_probe(gt); + if (gt->io) { + if (!request_region(gt->io, 1, "gemtek")) { + v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io); + return -EBUSY; + } + + if (!gemtek_verify(gt, gt->io)) + v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not " + "respond properly, check your " + "configuration.\n", gt->io); + else + v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io); + } else if (probe) { + v4l2_err(v4l2_dev, "Automatic probing failed and no " + "fixed I/O port defined.\n"); + return -ENODEV; + } else { + v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed " + "I/O port defined."); + return -EINVAL; + } + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + release_region(gt->io, 1); + return res; + } + + strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name)); + gt->vdev.v4l2_dev = v4l2_dev; + gt->vdev.fops = &gemtek_fops; + gt->vdev.ioctl_ops = &gemtek_ioctl_ops; + gt->vdev.release = video_device_release_empty; + video_set_drvdata(>->vdev, gt); + + /* Set defaults */ + gt->lastfreq = GEMTEK_LOWFREQ; + gt->bu2614data = 0; + + if (initmute) + gemtek_mute(gt); + + if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(gt->io, 1); + return -EBUSY; + } + + return 0; +} + +/* + * Module cleanup + */ +static void __exit gemtek_exit(void) +{ + struct gemtek *gt = &gemtek_card; + struct v4l2_device *v4l2_dev = >->v4l2_dev; + + if (shutdown) { + hardmute = 1; /* Turn off PLL */ + gemtek_mute(gt); + } else { + v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n"); + } + + video_unregister_device(>->vdev); + v4l2_device_unregister(>->v4l2_dev); + release_region(gt->io, 1); +} + +module_init(gemtek_init); +module_exit(gemtek_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-maxiradio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-maxiradio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-maxiradio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-maxiradio.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,466 @@ +/* + * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux + * (C) 2001 Dimitromanolakis Apostolos + * + * Based in the radio Maestro PCI driver. Actually it uses the same chip + * for radio but different pci controller. + * + * I didn't have any specs I reversed engineered the protocol from + * the windows driver (radio.dll). + * + * The card uses the TEA5757 chip that includes a search function but it + * is useless as I haven't found any way to read back the frequency. If + * anybody does please mail me. + * + * For the pdf file see: + * http://www.nxp.com/acrobat_download2/expired_datasheets/TEA5757_5759_3.pdf + * + * + * CHANGES: + * 0.75b + * - better pci interface thanks to Francois Romieu + * + * 0.75 Sun Feb 4 22:51:27 EET 2001 + * - tiding up + * - removed support for multiple devices as it didn't work anyway + * + * BUGS: + * - card unmutes if you change frequency + * + * (c) 2006, 2007 by Mauro Carvalho Chehab : + * - Conversion to V4L2 API + * - Uses video_ioctl2 for parsing and to add debug support + */ + + +#include +#include +#include +#include +#include +#include +#include +#include /* for KERNEL_VERSION MACRO */ +#include +#include +#include +#include + +MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); +MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); +MODULE_LICENSE("GPL"); + +static int radio_nr = -1; +module_param(radio_nr, int, 0); + +static int debug; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); + +#define DRIVER_VERSION "0.77" + +#define RADIO_VERSION KERNEL_VERSION(0, 7, 7) + +#define dprintk(dev, num, fmt, arg...) \ + v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg) + +#ifndef PCI_VENDOR_ID_GUILLEMOT +#define PCI_VENDOR_ID_GUILLEMOT 0x5046 +#endif + +#ifndef PCI_DEVICE_ID_GUILLEMOT +#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 +#endif + + +/* TEA5757 pin mappings */ +static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; + +#define FREQ_LO (87 * 16000) +#define FREQ_HI (108 * 16000) + +#define FREQ_IF 171200 /* 10.7*16000 */ +#define FREQ_STEP 200 /* 12.5*16 */ + +/* (x==fmhz*16*1000) -> bits */ +#define FREQ2BITS(x) \ + ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2) + +#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) + + +struct maxiradio +{ + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct pci_dev *pdev; + + u16 io; /* base of radio io */ + u16 muted; /* VIDEO_AUDIO_MUTE */ + u16 stereo; /* VIDEO_TUNER_STEREO_ON */ + u16 tuned; /* signal strength (0 or 0xffff) */ + + unsigned long freq; + + struct mutex lock; +}; + +static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct maxiradio, v4l2_dev); +} + +static void outbit(unsigned long bit, u16 io) +{ + int val = power | wren | (bit ? data : 0); + + outb(val, io); + udelay(4); + outb(val | clk, io); + udelay(4); + outb(val, io); + udelay(4); +} + +static void turn_power(struct maxiradio *dev, int p) +{ + if (p != 0) { + dprintk(dev, 1, "Radio powered on\n"); + outb(power, dev->io); + } else { + dprintk(dev, 1, "Radio powered off\n"); + outb(0, dev->io); + } +} + +static void set_freq(struct maxiradio *dev, u32 freq) +{ + unsigned long int si; + int bl; + int io = dev->io; + int val = FREQ2BITS(freq); + + /* TEA5757 shift register bits (see pdf) */ + + outbit(0, io); /* 24 search */ + outbit(1, io); /* 23 search up/down */ + + outbit(0, io); /* 22 stereo/mono */ + + outbit(0, io); /* 21 band */ + outbit(0, io); /* 20 band (only 00=FM works I think) */ + + outbit(0, io); /* 19 port ? */ + outbit(0, io); /* 18 port ? */ + + outbit(0, io); /* 17 search level */ + outbit(0, io); /* 16 search level */ + + si = 0x8000; + for (bl = 1; bl <= 16; bl++) { + outbit(val & si, io); + si >>= 1; + } + + dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n", + freq / 16000, + freq % 16000 * 100 / 16000); + + turn_power(dev, 1); +} + +static int get_stereo(u16 io) +{ + outb(power,io); + udelay(4); + + return !(inb(io) & mo_st); +} + +static int get_tune(u16 io) +{ + outb(power+clk,io); + udelay(4); + + return !(inb(io) & mo_st); +} + + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + struct maxiradio *dev = video_drvdata(file); + + strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver)); + strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card)); + snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct maxiradio *dev = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + mutex_lock(&dev->lock); + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = FREQ_LO; + v->rangehigh = FREQ_HI; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + if (get_stereo(dev->io)) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xffff * get_tune(dev->io); + mutex_unlock(&dev->lock); + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct maxiradio *dev = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { + dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", + f->frequency / 16000, + f->frequency % 16000 * 100 / 16000, + FREQ_LO / 16000, FREQ_HI / 16000); + + return -EINVAL; + } + + mutex_lock(&dev->lock); + dev->freq = f->frequency; + set_freq(dev, dev->freq); + msleep(125); + mutex_unlock(&dev->lock); + + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct maxiradio *dev = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = dev->freq; + + dprintk(dev, 4, "radio freq is %d.%02d MHz", + f->frequency / 16000, + f->frequency % 16000 * 100 / 16000); + + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct maxiradio *dev = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = dev->muted; + return 0; + } + + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct maxiradio *dev = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + mutex_lock(&dev->lock); + dev->muted = ctrl->value; + if (dev->muted) + turn_power(dev, 0); + else + set_freq(dev, dev->freq); + mutex_unlock(&dev->lock); + return 0; + } + + return -EINVAL; +} + +static const struct v4l2_file_operations maxiradio_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; + +static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct maxiradio *dev; + struct v4l2_device *v4l2_dev; + int retval = -ENOMEM; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&pdev->dev, "not enough memory\n"); + return -ENOMEM; + } + + v4l2_dev = &dev->v4l2_dev; + mutex_init(&dev->lock); + dev->pdev = pdev; + dev->muted = 1; + dev->freq = FREQ_LO; + + strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name)); + + retval = v4l2_device_register(&pdev->dev, v4l2_dev); + if (retval < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + goto errfr; + } + + if (!request_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { + v4l2_err(v4l2_dev, "can't reserve I/O ports\n"); + goto err_out; + } + + if (pci_enable_device(pdev)) + goto err_out_free_region; + + dev->io = pci_resource_start(pdev, 0); + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &maxiradio_fops; + dev->vdev.ioctl_ops = &maxiradio_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); + + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_err(v4l2_dev, "can't register device!"); + goto err_out_free_region; + } + + v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n"); + + v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n", + dev->io); + return 0; + +err_out_free_region: + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +err_out: + v4l2_device_unregister(v4l2_dev); +errfr: + kfree(dev); + return -ENODEV; +} + +static void __devexit maxiradio_remove_one(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct maxiradio *dev = to_maxiradio(v4l2_dev); + + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +} + +static struct pci_device_id maxiradio_pci_tbl[] = { + { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl); + +static struct pci_driver maxiradio_driver = { + .name = "radio-maxiradio", + .id_table = maxiradio_pci_tbl, + .probe = maxiradio_init_one, + .remove = __devexit_p(maxiradio_remove_one), +}; + +static int __init maxiradio_radio_init(void) +{ + return pci_register_driver(&maxiradio_driver); +} + +static void __exit maxiradio_radio_exit(void) +{ + pci_unregister_driver(&maxiradio_driver); +} + +module_init(maxiradio_radio_init); +module_exit(maxiradio_radio_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-miropcm20.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-miropcm20.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-miropcm20.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-miropcm20.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,272 @@ +/* Miro PCM20 radio driver for Linux radio support + * (c) 1998 Ruurd Reitsma + * Thanks to Norberto Pellici for the ACI device interface specification + * The API part is based on the radiotrack driver by M. Kirkwood + * This driver relies on the aci mixer provided by the snd-miro + * ALSA driver. + * Look there for further info... + */ + +/* What ever you think about the ACI, version 0x07 is not very well! + * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono + * conditions... Robert + */ + +#include +#include +#include +#include +#include +#include + +static int radio_nr = -1; +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); + +static int mono; +module_param(mono, bool, 0); +MODULE_PARM_DESC(mono, "Force tuner into mono mode."); + +struct pcm20 { + struct v4l2_device v4l2_dev; + struct video_device vdev; + unsigned long freq; + int muted; + struct snd_miro_aci *aci; + struct mutex lock; +}; + +static struct pcm20 pcm20_card = { + .freq = 87*16000, + .muted = 1, +}; + +static int pcm20_mute(struct pcm20 *dev, unsigned char mute) +{ + dev->muted = mute; + return snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, mute, -1); +} + +static int pcm20_stereo(struct pcm20 *dev, unsigned char stereo) +{ + return snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, !stereo, -1); +} + +static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) +{ + unsigned char freql; + unsigned char freqh; + struct snd_miro_aci *aci = dev->aci; + + dev->freq = freq; + + freq /= 160; + if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0)) + freq /= 10; /* I don't know exactly which version + * needs this hack */ + freql = freq & 0xff; + freqh = freq >> 8; + + pcm20_stereo(dev, !mono); + return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh); +} + +static const struct v4l2_file_operations pcm20_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "Miro PCM20", sizeof(v->driver)); + strlcpy(v->card, "Miro PCM20", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = 0x1; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + if (v->index) /* Only 1 tuner */ + return -EINVAL; + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = 87*16000; + v->rangehigh = 108*16000; + v->signal = 0xffff; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct pcm20 *dev = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + + f->type = V4L2_TUNER_RADIO; + f->frequency = dev->freq; + return 0; +} + + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct pcm20 *dev = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + dev->freq = f->frequency; + pcm20_setfreq(dev, f->frequency); + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct pcm20 *dev = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = dev->muted; + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct pcm20 *dev = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + pcm20_mute(dev, ctrl->value); + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static const struct v4l2_ioctl_ops pcm20_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +static int __init pcm20_init(void) +{ + struct pcm20 *dev = &pcm20_card; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + int res; + + dev->aci = snd_aci_get_aci(); + if (dev->aci == NULL) { + v4l2_err(v4l2_dev, + "you must load the snd-miro driver first!\n"); + return -ENODEV; + } + strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name)); + mutex_init(&dev->lock); + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + v4l2_err(v4l2_dev, "could not register v4l2_device\n"); + return -EINVAL; + } + + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &pcm20_fops; + dev->vdev.ioctl_ops = &pcm20_ioctl_ops; + dev->vdev.release = video_device_release_empty; + dev->vdev.lock = &dev->lock; + video_set_drvdata(&dev->vdev, dev); + + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) + goto fail; + + v4l2_info(v4l2_dev, "Mirosound PCM20 Radio tuner\n"); + return 0; +fail: + v4l2_device_unregister(v4l2_dev); + return -EINVAL; +} + +MODULE_AUTHOR("Ruurd Reitsma, Krzysztof Helt"); +MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); +MODULE_LICENSE("GPL"); + +static void __exit pcm20_cleanup(void) +{ + struct pcm20 *dev = &pcm20_card; + + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); +} + +module_init(pcm20_init); +module_exit(pcm20_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-mr800.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-mr800.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-mr800.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-mr800.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,685 @@ +/* + * A driver for the AverMedia MR 800 USB FM radio. This device plugs + * into both the USB and an analog audio input, so this thing + * only deals with initialization and frequency setting, the + * audio data has to be handled by a sound driver. + * + * Copyright (c) 2008 Alexey Klimov + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +/* + * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c + * + * When work was looked pretty good, i discover this: + * http://av-usbradio.sourceforge.net/index.php + * http://sourceforge.net/projects/av-usbradio/ + * Latest release of theirs project was in 2005. + * Probably, this driver could be improved through using their + * achievements (specifications given). + * Also, Faidon Liambotis wrote nice driver for this radio + * in 2007. He allowed to use his driver to improve current mr800 radio driver. + * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492 + * + * Version 0.01: First working version. + * It's required to blacklist AverMedia USB Radio + * in usbhid/hid-quirks.c + * Version 0.10: A lot of cleanups and fixes: unpluging the device, + * few mutex locks were added, codinstyle issues, etc. + * Added stereo support. Thanks to + * Douglas Schilling Landgraf and + * David Ellingsworth + * for discussion, help and support. + * Version 0.11: Converted to v4l2_device. + * + * Many things to do: + * - Correct power management of device (suspend & resume) + * - Add code for scanning and smooth tuning + * - Add code for sensitivity value + * - Correct mistakes + * - In Japan another FREQ_MIN and FREQ_MAX + */ + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for KERNEL_VERSION MACRO */ +#include + +/* driver and module definitions */ +#define DRIVER_AUTHOR "Alexey Klimov " +#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver" +#define DRIVER_VERSION "0.11" +#define RADIO_VERSION KERNEL_VERSION(0, 1, 1) + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +#define USB_AMRADIO_VENDOR 0x07ca +#define USB_AMRADIO_PRODUCT 0xb800 + +/* dev_warn macro with driver name */ +#define MR800_DRIVER_NAME "radio-mr800" +#define amradio_dev_warn(dev, fmt, arg...) \ + dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) + +#define amradio_dev_err(dev, fmt, arg...) \ + dev_err(dev, MR800_DRIVER_NAME " - " fmt, ##arg) + +/* Probably USB_TIMEOUT should be modified in module parameter */ +#define BUFFER_LENGTH 8 +#define USB_TIMEOUT 500 + +/* Frequency limits in MHz -- these are European values. For Japanese +devices, that would be 76 and 91. */ +#define FREQ_MIN 87.5 +#define FREQ_MAX 108.0 +#define FREQ_MUL 16000 + +/* + * Commands that device should understand + * List isn't full and will be updated with implementation of new functions + */ +#define AMRADIO_SET_FREQ 0xa4 +#define AMRADIO_SET_MUTE 0xab +#define AMRADIO_SET_MONO 0xae + +/* Comfortable defines for amradio_set_mute */ +#define AMRADIO_START 0x00 +#define AMRADIO_STOP 0x01 + +/* Comfortable defines for amradio_set_stereo */ +#define WANT_STEREO 0x00 +#define WANT_MONO 0x01 + +/* module parameter */ +static int radio_nr = -1; +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(radio_nr, "Radio Nr"); + +static int usb_amradio_probe(struct usb_interface *intf, + const struct usb_device_id *id); +static void usb_amradio_disconnect(struct usb_interface *intf); +static int usb_amradio_open(struct file *file); +static int usb_amradio_close(struct file *file); +static int usb_amradio_suspend(struct usb_interface *intf, + pm_message_t message); +static int usb_amradio_resume(struct usb_interface *intf); + +/* Data for one (physical) device */ +struct amradio_device { + /* reference to USB and video device */ + struct usb_device *usbdev; + struct usb_interface *intf; + struct video_device videodev; + struct v4l2_device v4l2_dev; + + unsigned char *buffer; + struct mutex lock; /* buffer locking */ + int curfreq; + int stereo; + int muted; + int initialized; +}; + +static inline struct amradio_device *to_amradio_dev(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct amradio_device, v4l2_dev); +} + +/* USB Device ID List */ +static struct usb_device_id usb_amradio_device_table[] = { + {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, + USB_CLASS_HID, 0, 0) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, usb_amradio_device_table); + +/* USB subsystem interface */ +static struct usb_driver usb_amradio_driver = { + .name = MR800_DRIVER_NAME, + .probe = usb_amradio_probe, + .disconnect = usb_amradio_disconnect, + .suspend = usb_amradio_suspend, + .resume = usb_amradio_resume, + .reset_resume = usb_amradio_resume, + .id_table = usb_amradio_device_table, + .supports_autosuspend = 1, +}; + +/* switch on/off the radio. Send 8 bytes to device */ +static int amradio_set_mute(struct amradio_device *radio, char argument) +{ + int retval; + int size; + + radio->buffer[0] = 0x00; + radio->buffer[1] = 0x55; + radio->buffer[2] = 0xaa; + radio->buffer[3] = 0x00; + radio->buffer[4] = AMRADIO_SET_MUTE; + radio->buffer[5] = argument; + radio->buffer[6] = 0x00; + radio->buffer[7] = 0x00; + + retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), + (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); + + if (retval < 0 || size != BUFFER_LENGTH) { + amradio_dev_warn(&radio->videodev.dev, "set mute failed\n"); + return retval; + } + + radio->muted = argument; + + return retval; +} + +/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ +static int amradio_setfreq(struct amradio_device *radio, int freq) +{ + int retval; + int size; + unsigned short freq_send = 0x10 + (freq >> 3) / 25; + + radio->buffer[0] = 0x00; + radio->buffer[1] = 0x55; + radio->buffer[2] = 0xaa; + radio->buffer[3] = 0x03; + radio->buffer[4] = AMRADIO_SET_FREQ; + radio->buffer[5] = 0x00; + radio->buffer[6] = 0x00; + radio->buffer[7] = 0x08; + + retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), + (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); + + if (retval < 0 || size != BUFFER_LENGTH) + goto out_err; + + /* frequency is calculated from freq_send and placed in first 2 bytes */ + radio->buffer[0] = (freq_send >> 8) & 0xff; + radio->buffer[1] = freq_send & 0xff; + radio->buffer[2] = 0x01; + radio->buffer[3] = 0x00; + radio->buffer[4] = 0x00; + /* 5 and 6 bytes of buffer already = 0x00 */ + radio->buffer[7] = 0x00; + + retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), + (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); + + if (retval < 0 || size != BUFFER_LENGTH) + goto out_err; + + radio->curfreq = freq; + goto out; + +out_err: + amradio_dev_warn(&radio->videodev.dev, "set frequency failed\n"); +out: + return retval; +} + +static int amradio_set_stereo(struct amradio_device *radio, char argument) +{ + int retval; + int size; + + radio->buffer[0] = 0x00; + radio->buffer[1] = 0x55; + radio->buffer[2] = 0xaa; + radio->buffer[3] = 0x00; + radio->buffer[4] = AMRADIO_SET_MONO; + radio->buffer[5] = argument; + radio->buffer[6] = 0x00; + radio->buffer[7] = 0x00; + + retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), + (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); + + if (retval < 0 || size != BUFFER_LENGTH) { + amradio_dev_warn(&radio->videodev.dev, "set stereo failed\n"); + return retval; + } + + if (argument == WANT_STEREO) + radio->stereo = 1; + else + radio->stereo = 0; + + return retval; +} + +/* Handle unplugging the device. + * We call video_unregister_device in any case. + * The last function called in this procedure is + * usb_amradio_device_release. + */ +static void usb_amradio_disconnect(struct usb_interface *intf) +{ + struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); + + mutex_lock(&radio->lock); + /* increase the device node's refcount */ + get_device(&radio->videodev.dev); + v4l2_device_disconnect(&radio->v4l2_dev); + video_unregister_device(&radio->videodev); + mutex_unlock(&radio->lock); + /* decrease the device node's refcount, allowing it to be released */ + put_device(&radio->videodev.dev); +} + +/* vidioc_querycap - query device capabilities */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + struct amradio_device *radio = file->private_data; + + strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); + strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); + usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; + return 0; +} + +/* vidioc_g_tuner - get tuner attributes */ +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct amradio_device *radio = file->private_data; + int retval; + + if (v->index > 0) + return -EINVAL; + +/* TODO: Add function which look is signal stereo or not + * amradio_getstat(radio); + */ + +/* we call amradio_set_stereo to set radio->stereo + * Honestly, amradio_getstat should cover this in future and + * amradio_set_stereo shouldn't be here + */ + retval = amradio_set_stereo(radio, WANT_STEREO); + + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; + v->rangelow = FREQ_MIN * FREQ_MUL; + v->rangehigh = FREQ_MAX * FREQ_MUL; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + if (radio->stereo) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xffff; /* Can't get the signal strength, sad.. */ + v->afc = 0; /* Don't know what is this */ + + return retval; +} + +/* vidioc_s_tuner - set tuner attributes */ +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct amradio_device *radio = file->private_data; + int retval = -EINVAL; + + if (v->index > 0) + return -EINVAL; + + /* mono/stereo selector */ + switch (v->audmode) { + case V4L2_TUNER_MODE_MONO: + retval = amradio_set_stereo(radio, WANT_MONO); + break; + case V4L2_TUNER_MODE_STEREO: + retval = amradio_set_stereo(radio, WANT_STEREO); + break; + } + + return retval; +} + +/* vidioc_s_frequency - set tuner radio frequency */ +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct amradio_device *radio = file->private_data; + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + return amradio_setfreq(radio, f->frequency); +} + +/* vidioc_g_frequency - get tuner radio frequency */ +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct amradio_device *radio = file->private_data; + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = radio->curfreq; + + return 0; +} + +/* vidioc_queryctrl - enumerate control items */ +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + } + + return -EINVAL; +} + +/* vidioc_g_ctrl - get the value of a control */ +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct amradio_device *radio = file->private_data; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = radio->muted; + return 0; + } + + return -EINVAL; +} + +/* vidioc_s_ctrl - set the value of a control */ +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct amradio_device *radio = file->private_data; + int retval = -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + retval = amradio_set_mute(radio, AMRADIO_STOP); + else + retval = amradio_set_mute(radio, AMRADIO_START); + + break; + } + + return retval; +} + +/* vidioc_g_audio - get audio attributes */ +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index > 1) + return -EINVAL; + + strcpy(a->name, "Radio"); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +/* vidioc_s_audio - set audio attributes */ +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index != 0) + return -EINVAL; + return 0; +} + +/* vidioc_g_input - get input */ +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +/* vidioc_s_input - set input */ +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + return 0; +} + +static int usb_amradio_init(struct amradio_device *radio) +{ + int retval; + + retval = amradio_set_mute(radio, AMRADIO_STOP); + if (retval) + goto out_err; + + retval = amradio_set_stereo(radio, WANT_STEREO); + if (retval) + goto out_err; + + radio->initialized = 1; + goto out; + +out_err: + amradio_dev_err(&radio->videodev.dev, "initialization failed\n"); +out: + return retval; +} + +/* open device - amradio_start() and amradio_setfreq() */ +static int usb_amradio_open(struct file *file) +{ + struct amradio_device *radio = video_drvdata(file); + int retval; + + file->private_data = radio; + retval = usb_autopm_get_interface(radio->intf); + if (retval) + return retval; + + if (unlikely(!radio->initialized)) { + retval = usb_amradio_init(radio); + if (retval) + usb_autopm_put_interface(radio->intf); + } + return retval; +} + +/*close device */ +static int usb_amradio_close(struct file *file) +{ + struct amradio_device *radio = file->private_data; + + if (video_is_registered(&radio->videodev)) + usb_autopm_put_interface(radio->intf); + return 0; +} + +/* Suspend device - stop device. Need to be checked and fixed */ +static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); + + mutex_lock(&radio->lock); + if (!radio->muted && radio->initialized) { + amradio_set_mute(radio, AMRADIO_STOP); + radio->muted = 0; + } + mutex_unlock(&radio->lock); + + dev_info(&intf->dev, "going into suspend..\n"); + return 0; +} + +/* Resume device - start device. Need to be checked and fixed */ +static int usb_amradio_resume(struct usb_interface *intf) +{ + struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf)); + + mutex_lock(&radio->lock); + if (unlikely(!radio->initialized)) + goto unlock; + + if (radio->stereo) + amradio_set_stereo(radio, WANT_STEREO); + else + amradio_set_stereo(radio, WANT_MONO); + + amradio_setfreq(radio, radio->curfreq); + + if (!radio->muted) + amradio_set_mute(radio, AMRADIO_START); + +unlock: + mutex_unlock(&radio->lock); + + dev_info(&intf->dev, "coming out of suspend..\n"); + return 0; +} + +/* File system interface */ +static const struct v4l2_file_operations usb_amradio_fops = { + .owner = THIS_MODULE, + .open = usb_amradio_open, + .release = usb_amradio_close, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +static void usb_amradio_video_device_release(struct video_device *videodev) +{ + struct amradio_device *radio = video_get_drvdata(videodev); + + /* free rest memory */ + kfree(radio->buffer); + kfree(radio); +} + +/* check if the device is present and register with v4l and usb if it is */ +static int usb_amradio_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct amradio_device *radio; + int retval = 0; + + radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); + + if (!radio) { + dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); + retval = -ENOMEM; + goto err; + } + + radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); + + if (!radio->buffer) { + dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); + retval = -ENOMEM; + goto err_nobuf; + } + + retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); + if (retval < 0) { + dev_err(&intf->dev, "couldn't register v4l2_device\n"); + goto err_v4l2; + } + + mutex_init(&radio->lock); + + strlcpy(radio->videodev.name, radio->v4l2_dev.name, + sizeof(radio->videodev.name)); + radio->videodev.v4l2_dev = &radio->v4l2_dev; + radio->videodev.fops = &usb_amradio_fops; + radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops; + radio->videodev.release = usb_amradio_video_device_release; + radio->videodev.lock = &radio->lock; + + radio->usbdev = interface_to_usbdev(intf); + radio->intf = intf; + radio->curfreq = 95.16 * FREQ_MUL; + + video_set_drvdata(&radio->videodev, radio); + + retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, + radio_nr); + if (retval < 0) { + dev_err(&intf->dev, "could not register video device\n"); + goto err_vdev; + } + + return 0; + +err_vdev: + v4l2_device_unregister(&radio->v4l2_dev); +err_v4l2: + kfree(radio->buffer); +err_nobuf: + kfree(radio); +err: + return retval; +} + +static int __init amradio_init(void) +{ + int retval = usb_register(&usb_amradio_driver); + + pr_info(KBUILD_MODNAME + ": version " DRIVER_VERSION " " DRIVER_DESC "\n"); + + if (retval) + pr_err(KBUILD_MODNAME + ": usb_register failed. Error number %d\n", retval); + + return retval; +} + +static void __exit amradio_exit(void) +{ + usb_deregister(&usb_amradio_driver); +} + +module_init(amradio_init); +module_exit(amradio_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-rtrack2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-rtrack2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-rtrack2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-rtrack2.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,344 @@ +/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff + * + * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood + * Converted to new API by Alan Cox + * Various bugfixes and enhancements by Russell Kroll + * + * TODO: Allow for more than one of these foolish entities :-) + * + * Converted to V4L2 API by Mauro Carvalho Chehab + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* udelay */ +#include /* kernel radio structs */ +#include +#include /* for KERNEL_VERSION MACRO */ +#include /* outb, outb_p */ +#include +#include + +MODULE_AUTHOR("Ben Pfaff"); +MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); +MODULE_LICENSE("GPL"); + +#ifndef CONFIG_RADIO_RTRACK2_PORT +#define CONFIG_RADIO_RTRACK2_PORT -1 +#endif + +static int io = CONFIG_RADIO_RTRACK2_PORT; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct rtrack2 +{ + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + unsigned long curfreq; + int muted; + struct mutex lock; +}; + +static struct rtrack2 rtrack2_card; + + +/* local things */ + +static void rt_mute(struct rtrack2 *dev) +{ + if (dev->muted) + return; + mutex_lock(&dev->lock); + outb(1, dev->io); + mutex_unlock(&dev->lock); + dev->muted = 1; +} + +static void rt_unmute(struct rtrack2 *dev) +{ + if(dev->muted == 0) + return; + mutex_lock(&dev->lock); + outb(0, dev->io); + mutex_unlock(&dev->lock); + dev->muted = 0; +} + +static void zero(struct rtrack2 *dev) +{ + outb_p(1, dev->io); + outb_p(3, dev->io); + outb_p(1, dev->io); +} + +static void one(struct rtrack2 *dev) +{ + outb_p(5, dev->io); + outb_p(7, dev->io); + outb_p(5, dev->io); +} + +static int rt_setfreq(struct rtrack2 *dev, unsigned long freq) +{ + int i; + + mutex_lock(&dev->lock); + dev->curfreq = freq; + freq = freq / 200 + 856; + + outb_p(0xc8, dev->io); + outb_p(0xc9, dev->io); + outb_p(0xc9, dev->io); + + for (i = 0; i < 10; i++) + zero(dev); + + for (i = 14; i >= 0; i--) + if (freq & (1 << i)) + one(dev); + else + zero(dev); + + outb_p(0xc8, dev->io); + if (!dev->muted) + outb_p(0, dev->io); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver)); + strlcpy(v->card, "RadioTrack II", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int rt_getsigstr(struct rtrack2 *dev) +{ + int sig = 1; + + mutex_lock(&dev->lock); + if (inb(dev->io) & 2) /* bit set = no signal present */ + sig = 0; + mutex_unlock(&dev->lock); + return sig; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct rtrack2 *rt = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = 88 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO; + v->capability = V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xFFFF * rt_getsigstr(rt); + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct rtrack2 *rt = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + rt_setfreq(rt, f->frequency); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct rtrack2 *rt = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = rt->curfreq; + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct rtrack2 *rt = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = rt->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: + if (rt->muted) + ctrl->value = 0; + else + ctrl->value = 65535; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct rtrack2 *rt = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + rt_mute(rt); + else + rt_unmute(rt); + return 0; + case V4L2_CID_AUDIO_VOLUME: + if (ctrl->value) + rt_unmute(rt); + else + rt_mute(rt); + return 0; + } + return -EINVAL; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static const struct v4l2_file_operations rtrack2_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +static int __init rtrack2_init(void) +{ + struct rtrack2 *dev = &rtrack2_card; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name)); + dev->io = io; + if (dev->io == -1) { + v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n"); + return -EINVAL; + } + if (!request_region(dev->io, 4, "rtrack2")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io); + return -EBUSY; + } + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(dev->io, 4); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &rtrack2_fops; + dev->vdev.ioctl_ops = &rtrack2_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); + + /* mute card - prevents noisy bootups */ + outb(1, dev->io); + dev->muted = 1; + + mutex_init(&dev->lock); + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(dev->io, 4); + return -EINVAL; + } + + v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n"); + + return 0; +} + +static void __exit rtrack2_exit(void) +{ + struct rtrack2 *dev = &rtrack2_card; + + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); + release_region(dev->io, 4); +} + +module_init(rtrack2_init); +module_exit(rtrack2_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-sf16fmi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-sf16fmi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-sf16fmi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-sf16fmi.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,412 @@ +/* SF16-FMI and SF16-FMP radio driver for Linux radio support + * heavily based on rtrack driver... + * (c) 1997 M. Kirkwood + * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz + * + * Fitted to new interface by Alan Cox + * Made working and cleaned up functions + * Support for ISAPnP by Ladislav Michl + * + * Notes on the hardware + * + * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); + * No volume control - only mute/unmute - you have to use line volume + * control on SB-part of SF16-FMI/SF16-FMP + * + * Converted to V4L2 API by Mauro Carvalho Chehab + */ + +#include +#include /* __setup */ +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* udelay */ +#include +#include +#include /* kernel radio structs */ +#include /* outb, outb_p */ +#include +#include + +MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); +MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio."); +MODULE_LICENSE("GPL"); + +static int io = -1; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct fmi +{ + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + bool mute; + unsigned long curfreq; /* freq in kHz */ + struct mutex lock; +}; + +static struct fmi fmi_card; +static struct pnp_dev *dev; +bool pnp_attached; + +/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ +/* It is only useful to give freq in interval of 800 (=0.05Mhz), + * other bits will be truncated, e.g 92.7400016 -> 92.7, but + * 92.7400017 -> 92.75 + */ +#define RSF16_ENCODE(x) ((x) / 800 + 214) +#define RSF16_MINFREQ (87 * 16000) +#define RSF16_MAXFREQ (108 * 16000) + +static void outbits(int bits, unsigned int data, int io) +{ + while (bits--) { + if (data & 1) { + outb(5, io); + udelay(6); + outb(7, io); + udelay(6); + } else { + outb(1, io); + udelay(6); + outb(3, io); + udelay(6); + } + data >>= 1; + } +} + +static inline void fmi_mute(struct fmi *fmi) +{ + mutex_lock(&fmi->lock); + outb(0x00, fmi->io); + mutex_unlock(&fmi->lock); +} + +static inline void fmi_unmute(struct fmi *fmi) +{ + mutex_lock(&fmi->lock); + outb(0x08, fmi->io); + mutex_unlock(&fmi->lock); +} + +static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq) +{ + mutex_lock(&fmi->lock); + fmi->curfreq = freq; + + outbits(16, RSF16_ENCODE(freq), fmi->io); + outbits(8, 0xC0, fmi->io); + msleep(143); /* was schedule_timeout(HZ/7) */ + mutex_unlock(&fmi->lock); + if (!fmi->mute) + fmi_unmute(fmi); + return 0; +} + +static inline int fmi_getsigstr(struct fmi *fmi) +{ + int val; + int res; + + mutex_lock(&fmi->lock); + val = fmi->mute ? 0x00 : 0x08; /* mute/unmute */ + outb(val, fmi->io); + outb(val | 0x10, fmi->io); + msleep(143); /* was schedule_timeout(HZ/7) */ + res = (int)inb(fmi->io + 1); + outb(val, fmi->io); + + mutex_unlock(&fmi->lock); + return (res & 2) ? 0 : 0xFFFF; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); + strlcpy(v->card, "SF16-FMx radio", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct fmi *fmi = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = RSF16_MINFREQ; + v->rangehigh = RSF16_MAXFREQ; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_STEREO; + v->signal = fmi_getsigstr(fmi); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct fmi *fmi = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + if (f->frequency < RSF16_MINFREQ || + f->frequency > RSF16_MAXFREQ) + return -EINVAL; + /* rounding in steps of 800 to match the freq + that will be used */ + fmi_setfreq(fmi, (f->frequency / 800) * 800); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct fmi *fmi = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = fmi->curfreq; + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct fmi *fmi = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = fmi->mute; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct fmi *fmi = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + fmi_mute(fmi); + else + fmi_unmute(fmi); + fmi->mute = ctrl->value; + return 0; + } + return -EINVAL; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static const struct v4l2_file_operations fmi_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops fmi_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; + +/* ladis: this is my card. does any other types exist? */ +static struct isapnp_device_id id_table[] __devinitdata = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('M','F','R'), ISAPNP_FUNCTION(0xad10), 0}, + { ISAPNP_CARD_END, }, +}; + +MODULE_DEVICE_TABLE(isapnp, id_table); + +static int __init isapnp_fmi_probe(void) +{ + int i = 0; + + while (id_table[i].card_vendor != 0 && dev == NULL) { + dev = pnp_find_dev(NULL, id_table[i].vendor, + id_table[i].function, NULL); + i++; + } + + if (!dev) + return -ENODEV; + if (pnp_device_attach(dev) < 0) + return -EAGAIN; + if (pnp_activate_dev(dev) < 0) { + printk(KERN_ERR "radio-sf16fmi: PnP configure failed (out of resources?)\n"); + pnp_device_detach(dev); + return -ENOMEM; + } + if (!pnp_port_valid(dev, 0)) { + pnp_device_detach(dev); + return -ENODEV; + } + + i = pnp_port_start(dev, 0); + printk(KERN_INFO "radio-sf16fmi: PnP reports card at %#x\n", i); + + return i; +} + +static int __init fmi_init(void) +{ + struct fmi *fmi = &fmi_card; + struct v4l2_device *v4l2_dev = &fmi->v4l2_dev; + int res, i; + int probe_ports[] = { 0, 0x284, 0x384 }; + + if (io < 0) { + for (i = 0; i < ARRAY_SIZE(probe_ports); i++) { + io = probe_ports[i]; + if (io == 0) { + io = isapnp_fmi_probe(); + if (io < 0) + continue; + pnp_attached = 1; + } + if (!request_region(io, 2, "radio-sf16fmi")) { + if (pnp_attached) + pnp_device_detach(dev); + io = -1; + continue; + } + if (pnp_attached || + ((inb(io) & 0xf9) == 0xf9 && (inb(io) & 0x4) == 0)) + break; + release_region(io, 2); + io = -1; + } + } else { + if (!request_region(io, 2, "radio-sf16fmi")) { + printk(KERN_ERR "radio-sf16fmi: port %#x already in use\n", io); + return -EBUSY; + } + if (inb(io) == 0xff) { + printk(KERN_ERR "radio-sf16fmi: card not present at %#x\n", io); + release_region(io, 2); + return -ENODEV; + } + } + if (io < 0) { + printk(KERN_ERR "radio-sf16fmi: no cards found\n"); + return -ENODEV; + } + + strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name)); + fmi->io = io; + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(fmi->io, 2); + if (pnp_attached) + pnp_device_detach(dev); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name)); + fmi->vdev.v4l2_dev = v4l2_dev; + fmi->vdev.fops = &fmi_fops; + fmi->vdev.ioctl_ops = &fmi_ioctl_ops; + fmi->vdev.release = video_device_release_empty; + video_set_drvdata(&fmi->vdev, fmi); + + mutex_init(&fmi->lock); + + /* mute card - prevents noisy bootups */ + fmi_mute(fmi); + + if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(fmi->io, 2); + if (pnp_attached) + pnp_device_detach(dev); + return -EINVAL; + } + + v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io); + return 0; +} + +static void __exit fmi_exit(void) +{ + struct fmi *fmi = &fmi_card; + + video_unregister_device(&fmi->vdev); + v4l2_device_unregister(&fmi->v4l2_dev); + release_region(fmi->io, 2); + if (dev && pnp_attached) + pnp_device_detach(dev); +} + +module_init(fmi_init); +module_exit(fmi_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-sf16fmr2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-sf16fmr2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-sf16fmr2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-sf16fmr2.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,219 @@ +/* SF16-FMR2 radio driver for Linux + * Copyright (c) 2011 Ondrej Zary + * + * Original driver was (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com + * but almost nothing remained here after conversion to generic TEA575x + * implementation + */ + +#include +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* outb, outb_p */ +#include + +MODULE_AUTHOR("Ondrej Zary"); +MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver"); +MODULE_LICENSE("GPL"); + +struct fmr2 { + int io; + struct snd_tea575x tea; + struct v4l2_ctrl *volume; + struct v4l2_ctrl *balance; +}; + +/* the port is hardwired so no need to support multiple cards */ +#define FMR2_PORT 0x384 +static struct fmr2 fmr2_card; + +/* TEA575x tuner pins */ +#define STR_DATA (1 << 0) +#define STR_CLK (1 << 1) +#define STR_WREN (1 << 2) +#define STR_MOST (1 << 3) +/* PT2254A/TC9154A volume control pins */ +#define PT_ST (1 << 4) +#define PT_CK (1 << 5) +#define PT_DATA (1 << 6) +/* volume control presence pin */ +#define FMR2_HASVOL (1 << 7) + +static void fmr2_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) +{ + struct fmr2 *fmr2 = tea->private_data; + u8 bits = 0; + + bits |= (pins & TEA575X_DATA) ? STR_DATA : 0; + bits |= (pins & TEA575X_CLK) ? STR_CLK : 0; + /* WRITE_ENABLE is inverted, DATA must be high during read */ + bits |= (pins & TEA575X_WREN) ? 0 : STR_WREN | STR_DATA; + + outb(bits, fmr2->io); +} + +static u8 fmr2_tea575x_get_pins(struct snd_tea575x *tea) +{ + struct fmr2 *fmr2 = tea->private_data; + u8 bits = inb(fmr2->io); + + return (bits & STR_DATA) ? TEA575X_DATA : 0 | + (bits & STR_MOST) ? TEA575X_MOST : 0; +} + +static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output) +{ +} + +static struct snd_tea575x_ops fmr2_tea_ops = { + .set_pins = fmr2_tea575x_set_pins, + .get_pins = fmr2_tea575x_get_pins, + .set_direction = fmr2_tea575x_set_direction, +}; + +/* TC9154A/PT2254A volume control */ + +/* 18-bit shift register bit definitions */ +#define TC9154A_ATT_MAJ_0DB (1 << 0) +#define TC9154A_ATT_MAJ_10DB (1 << 1) +#define TC9154A_ATT_MAJ_20DB (1 << 2) +#define TC9154A_ATT_MAJ_30DB (1 << 3) +#define TC9154A_ATT_MAJ_40DB (1 << 4) +#define TC9154A_ATT_MAJ_50DB (1 << 5) +#define TC9154A_ATT_MAJ_60DB (1 << 6) + +#define TC9154A_ATT_MIN_0DB (1 << 7) +#define TC9154A_ATT_MIN_2DB (1 << 8) +#define TC9154A_ATT_MIN_4DB (1 << 9) +#define TC9154A_ATT_MIN_6DB (1 << 10) +#define TC9154A_ATT_MIN_8DB (1 << 11) +/* bit 12 is ignored */ +#define TC9154A_CHANNEL_LEFT (1 << 13) +#define TC9154A_CHANNEL_RIGHT (1 << 14) +/* bits 15, 16, 17 must be 0 */ + +#define TC9154A_ATT_MAJ(x) (1 << x) +#define TC9154A_ATT_MIN(x) (1 << (7 + x)) + +static void tc9154a_set_pins(struct fmr2 *fmr2, u8 pins) +{ + if (!fmr2->tea.mute) + pins |= STR_WREN; + + outb(pins, fmr2->io); +} + +static void tc9154a_set_attenuation(struct fmr2 *fmr2, int att, u32 channel) +{ + int i; + u32 reg; + u8 bit; + + reg = TC9154A_ATT_MAJ(att / 10) | TC9154A_ATT_MIN((att % 10) / 2); + reg |= channel; + /* write 18-bit shift register, LSB first */ + for (i = 0; i < 18; i++) { + bit = reg & (1 << i) ? PT_DATA : 0; + tc9154a_set_pins(fmr2, bit); + udelay(5); + tc9154a_set_pins(fmr2, bit | PT_CK); + udelay(5); + tc9154a_set_pins(fmr2, bit); + } + + /* latch register data */ + udelay(5); + tc9154a_set_pins(fmr2, PT_ST); + udelay(5); + tc9154a_set_pins(fmr2, 0); +} + +static int fmr2_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler); + struct fmr2 *fmr2 = tea->private_data; + int volume, balance, left, right; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + volume = ctrl->val; + balance = fmr2->balance->cur.val; + break; + case V4L2_CID_AUDIO_BALANCE: + balance = ctrl->val; + volume = fmr2->volume->cur.val; + break; + default: + return -EINVAL; + } + + left = right = volume; + if (balance < 0) + right = max(0, right + balance); + if (balance > 0) + left = max(0, left - balance); + + tc9154a_set_attenuation(fmr2, abs(left - 68), TC9154A_CHANNEL_LEFT); + tc9154a_set_attenuation(fmr2, abs(right - 68), TC9154A_CHANNEL_RIGHT); + + return 0; +} + +static const struct v4l2_ctrl_ops fmr2_ctrl_ops = { + .s_ctrl = fmr2_s_ctrl, +}; + +static int fmr2_tea_ext_init(struct snd_tea575x *tea) +{ + struct fmr2 *fmr2 = tea->private_data; + + if (inb(fmr2->io) & FMR2_HASVOL) { + fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56); + fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0); + if (tea->ctrl_handler.error) { + printk(KERN_ERR "radio-sf16fmr2: can't initialize contrls\n"); + return tea->ctrl_handler.error; + } + } + + return 0; +} + +static int __init fmr2_init(void) +{ + struct fmr2 *fmr2 = &fmr2_card; + + fmr2->io = FMR2_PORT; + + if (!request_region(fmr2->io, 2, "SF16-FMR2")) { + printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io); + return -EBUSY; + } + + fmr2->tea.private_data = fmr2; + fmr2->tea.ops = &fmr2_tea_ops; + fmr2->tea.ext_init = fmr2_tea_ext_init; + strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card)); + strcpy(fmr2->tea.bus_info, "ISA"); + + if (snd_tea575x_init(&fmr2->tea)) { + printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n"); + release_region(fmr2->io, 2); + return -ENODEV; + } + + printk(KERN_INFO "radio-sf16fmr2: SF16-FMR2 radio card at 0x%x.\n", fmr2->io); + return 0; +} + +static void __exit fmr2_exit(void) +{ + struct fmr2 *fmr2 = &fmr2_card; + + snd_tea575x_exit(&fmr2->tea); + release_region(fmr2->io, 2); +} + +module_init(fmr2_init); +module_exit(fmr2_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-si4713.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-si4713.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-si4713.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-si4713.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,374 @@ +/* + * drivers/media/radio/radio-si4713.c + * + * Platform Driver for Silicon Labs Si4713 FM Radio Transmitter: + * + * Copyright (c) 2008 Instituto Nokia de Tecnologia - INdT + * Contact: Eduardo Valentin + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* module parameters */ +static int radio_nr = -1; /* radio device minor (-1 ==> auto assign) */ +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(radio_nr, + "Minor number for radio device (-1 ==> auto assign)"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eduardo Valentin "); +MODULE_DESCRIPTION("Platform driver for Si4713 FM Radio Transmitter"); + +/* Driver state struct */ +struct radio_si4713_device { + struct v4l2_device v4l2_dev; + struct video_device *radio_dev; +}; + +/* radio_si4713_fops - file operations interface */ +static const struct v4l2_file_operations radio_si4713_fops = { + .owner = THIS_MODULE, + /* Note: locking is done at the subdev level in the i2c driver. */ + .unlocked_ioctl = video_ioctl2, +}; + +/* Video4Linux Interface */ +static int radio_si4713_fill_audout(struct v4l2_audioout *vao) +{ + /* TODO: check presence of audio output */ + strlcpy(vao->name, "FM Modulator Audio Out", 32); + + return 0; +} + +static int radio_si4713_enumaudout(struct file *file, void *priv, + struct v4l2_audioout *vao) +{ + return radio_si4713_fill_audout(vao); +} + +static int radio_si4713_g_audout(struct file *file, void *priv, + struct v4l2_audioout *vao) +{ + int rval = radio_si4713_fill_audout(vao); + + vao->index = 0; + + return rval; +} + +static int radio_si4713_s_audout(struct file *file, void *priv, + struct v4l2_audioout *vao) +{ + return vao->index ? -EINVAL : 0; +} + +/* radio_si4713_querycap - query device capabilities */ +static int radio_si4713_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + struct radio_si4713_device *rsdev; + + rsdev = video_get_drvdata(video_devdata(file)); + + strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver)); + strlcpy(capability->card, "Silicon Labs Si4713 Modulator", + sizeof(capability->card)); + capability->capabilities = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; + + return 0; +} + +/* radio_si4713_queryctrl - enumerate control items */ +static int radio_si4713_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + /* Must be sorted from low to high control ID! */ + static const u32 user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_AUDIO_MUTE, + 0 + }; + + /* Must be sorted from low to high control ID! */ + static const u32 fmtx_ctrls[] = { + V4L2_CID_FM_TX_CLASS, + V4L2_CID_RDS_TX_DEVIATION, + V4L2_CID_RDS_TX_PI, + V4L2_CID_RDS_TX_PTY, + V4L2_CID_RDS_TX_PS_NAME, + V4L2_CID_RDS_TX_RADIO_TEXT, + V4L2_CID_AUDIO_LIMITER_ENABLED, + V4L2_CID_AUDIO_LIMITER_RELEASE_TIME, + V4L2_CID_AUDIO_LIMITER_DEVIATION, + V4L2_CID_AUDIO_COMPRESSION_ENABLED, + V4L2_CID_AUDIO_COMPRESSION_GAIN, + V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, + V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, + V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME, + V4L2_CID_PILOT_TONE_ENABLED, + V4L2_CID_PILOT_TONE_DEVIATION, + V4L2_CID_PILOT_TONE_FREQUENCY, + V4L2_CID_TUNE_PREEMPHASIS, + V4L2_CID_TUNE_POWER_LEVEL, + V4L2_CID_TUNE_ANTENNA_CAPACITOR, + 0 + }; + static const u32 *ctrl_classes[] = { + user_ctrls, + fmtx_ctrls, + NULL + }; + struct radio_si4713_device *rsdev; + + rsdev = video_get_drvdata(video_devdata(file)); + + qc->id = v4l2_ctrl_next(ctrl_classes, qc->id); + if (qc->id == 0) + return -EINVAL; + + if (qc->id == V4L2_CID_USER_CLASS || qc->id == V4L2_CID_FM_TX_CLASS) + return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0); + + return v4l2_device_call_until_err(&rsdev->v4l2_dev, 0, core, + queryctrl, qc); +} + +/* + * v4l2 ioctl call backs. + * we are just a wrapper for v4l2_sub_devs. + */ +static inline struct v4l2_device *get_v4l2_dev(struct file *file) +{ + return &((struct radio_si4713_device *)video_drvdata(file))->v4l2_dev; +} + +static int radio_si4713_g_ext_ctrls(struct file *file, void *p, + struct v4l2_ext_controls *vecs) +{ + return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, + g_ext_ctrls, vecs); +} + +static int radio_si4713_s_ext_ctrls(struct file *file, void *p, + struct v4l2_ext_controls *vecs) +{ + return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, + s_ext_ctrls, vecs); +} + +static int radio_si4713_g_ctrl(struct file *file, void *p, + struct v4l2_control *vc) +{ + return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, + g_ctrl, vc); +} + +static int radio_si4713_s_ctrl(struct file *file, void *p, + struct v4l2_control *vc) +{ + return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, + s_ctrl, vc); +} + +static int radio_si4713_g_modulator(struct file *file, void *p, + struct v4l2_modulator *vm) +{ + return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, + g_modulator, vm); +} + +static int radio_si4713_s_modulator(struct file *file, void *p, + struct v4l2_modulator *vm) +{ + return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, + s_modulator, vm); +} + +static int radio_si4713_g_frequency(struct file *file, void *p, + struct v4l2_frequency *vf) +{ + return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, + g_frequency, vf); +} + +static int radio_si4713_s_frequency(struct file *file, void *p, + struct v4l2_frequency *vf) +{ + return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, + s_frequency, vf); +} + +static long radio_si4713_default(struct file *file, void *p, + bool valid_prio, int cmd, void *arg) +{ + return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, + ioctl, cmd, arg); +} + +static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = { + .vidioc_enumaudout = radio_si4713_enumaudout, + .vidioc_g_audout = radio_si4713_g_audout, + .vidioc_s_audout = radio_si4713_s_audout, + .vidioc_querycap = radio_si4713_querycap, + .vidioc_queryctrl = radio_si4713_queryctrl, + .vidioc_g_ext_ctrls = radio_si4713_g_ext_ctrls, + .vidioc_s_ext_ctrls = radio_si4713_s_ext_ctrls, + .vidioc_g_ctrl = radio_si4713_g_ctrl, + .vidioc_s_ctrl = radio_si4713_s_ctrl, + .vidioc_g_modulator = radio_si4713_g_modulator, + .vidioc_s_modulator = radio_si4713_s_modulator, + .vidioc_g_frequency = radio_si4713_g_frequency, + .vidioc_s_frequency = radio_si4713_s_frequency, + .vidioc_default = radio_si4713_default, +}; + +/* radio_si4713_vdev_template - video device interface */ +static struct video_device radio_si4713_vdev_template = { + .fops = &radio_si4713_fops, + .name = "radio-si4713", + .release = video_device_release, + .ioctl_ops = &radio_si4713_ioctl_ops, +}; + +/* Platform driver interface */ +/* radio_si4713_pdriver_probe - probe for the device */ +static int radio_si4713_pdriver_probe(struct platform_device *pdev) +{ + struct radio_si4713_platform_data *pdata = pdev->dev.platform_data; + struct radio_si4713_device *rsdev; + struct i2c_adapter *adapter; + struct v4l2_subdev *sd; + int rval = 0; + + if (!pdata) { + dev_err(&pdev->dev, "Cannot proceed without platform data.\n"); + rval = -EINVAL; + goto exit; + } + + rsdev = kzalloc(sizeof *rsdev, GFP_KERNEL); + if (!rsdev) { + dev_err(&pdev->dev, "Failed to alloc video device.\n"); + rval = -ENOMEM; + goto exit; + } + + rval = v4l2_device_register(&pdev->dev, &rsdev->v4l2_dev); + if (rval) { + dev_err(&pdev->dev, "Failed to register v4l2 device.\n"); + goto free_rsdev; + } + + adapter = i2c_get_adapter(pdata->i2c_bus); + if (!adapter) { + dev_err(&pdev->dev, "Cannot get i2c adapter %d\n", + pdata->i2c_bus); + rval = -ENODEV; + goto unregister_v4l2_dev; + } + + sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, + pdata->subdev_board_info, NULL); + if (!sd) { + dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n"); + rval = -ENODEV; + goto put_adapter; + } + + rsdev->radio_dev = video_device_alloc(); + if (!rsdev->radio_dev) { + dev_err(&pdev->dev, "Failed to alloc video device.\n"); + rval = -ENOMEM; + goto put_adapter; + } + + memcpy(rsdev->radio_dev, &radio_si4713_vdev_template, + sizeof(radio_si4713_vdev_template)); + video_set_drvdata(rsdev->radio_dev, rsdev); + if (video_register_device(rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) { + dev_err(&pdev->dev, "Could not register video device.\n"); + rval = -EIO; + goto free_vdev; + } + dev_info(&pdev->dev, "New device successfully probed\n"); + + goto exit; + +free_vdev: + video_device_release(rsdev->radio_dev); +put_adapter: + i2c_put_adapter(adapter); +unregister_v4l2_dev: + v4l2_device_unregister(&rsdev->v4l2_dev); +free_rsdev: + kfree(rsdev); +exit: + return rval; +} + +/* radio_si4713_pdriver_remove - remove the device */ +static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev) +{ + struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); + struct radio_si4713_device *rsdev = container_of(v4l2_dev, + struct radio_si4713_device, + v4l2_dev); + struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next, + struct v4l2_subdev, list); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + video_unregister_device(rsdev->radio_dev); + i2c_put_adapter(client->adapter); + v4l2_device_unregister(&rsdev->v4l2_dev); + kfree(rsdev); + + return 0; +} + +static struct platform_driver radio_si4713_pdriver = { + .driver = { + .name = "radio-si4713", + }, + .probe = radio_si4713_pdriver_probe, + .remove = __exit_p(radio_si4713_pdriver_remove), +}; + +/* Module Interface */ +static int __init radio_si4713_module_init(void) +{ + return platform_driver_register(&radio_si4713_pdriver); +} + +static void __exit radio_si4713_module_exit(void) +{ + platform_driver_unregister(&radio_si4713_pdriver); +} + +module_init(radio_si4713_module_init); +module_exit(radio_si4713_module_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-tea5764.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-tea5764.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-tea5764.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-tea5764.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,605 @@ +/* + * driver/media/radio/radio-tea5764.c + * + * Driver for TEA5764 radio chip for linux 2.6. + * This driver is for TEA5764 chip from NXP, used in EZX phones from Motorola. + * The I2C protocol is used for communicate with chip. + * + * Based in radio-tea5761.c Copyright (C) 2005 Nokia Corporation + * + * Copyright (c) 2008 Fabio Belavenuto + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * History: + * 2008-12-06 Fabio Belavenuto + * initial code + * + * TODO: + * add platform_data support for IRQs platform dependencies + * add RDS support + */ +#include +#include +#include +#include /* Initdata */ +#include /* kernel radio structs */ +#include /* I2C */ +#include +#include +#include /* for KERNEL_VERSION MACRO */ + +#define DRIVER_VERSION "v0.01" +#define RADIO_VERSION KERNEL_VERSION(0, 0, 1) + +#define DRIVER_AUTHOR "Fabio Belavenuto " +#define DRIVER_DESC "A driver for the TEA5764 radio chip for EZX Phones." + +#define PINFO(format, ...)\ + printk(KERN_INFO KBUILD_MODNAME ": "\ + DRIVER_VERSION ": " format "\n", ## __VA_ARGS__) +#define PWARN(format, ...)\ + printk(KERN_WARNING KBUILD_MODNAME ": "\ + DRIVER_VERSION ": " format "\n", ## __VA_ARGS__) +# define PDEBUG(format, ...)\ + printk(KERN_DEBUG KBUILD_MODNAME ": "\ + DRIVER_VERSION ": " format "\n", ## __VA_ARGS__) + +/* Frequency limits in MHz -- these are European values. For Japanese +devices, that would be 76000 and 91000. */ +#define FREQ_MIN 87500 +#define FREQ_MAX 108000 +#define FREQ_MUL 16 + +/* TEA5764 registers */ +#define TEA5764_MANID 0x002b +#define TEA5764_CHIPID 0x5764 + +#define TEA5764_INTREG_BLMSK 0x0001 +#define TEA5764_INTREG_FRRMSK 0x0002 +#define TEA5764_INTREG_LEVMSK 0x0008 +#define TEA5764_INTREG_IFMSK 0x0010 +#define TEA5764_INTREG_BLMFLAG 0x0100 +#define TEA5764_INTREG_FRRFLAG 0x0200 +#define TEA5764_INTREG_LEVFLAG 0x0800 +#define TEA5764_INTREG_IFFLAG 0x1000 + +#define TEA5764_FRQSET_SUD 0x8000 +#define TEA5764_FRQSET_SM 0x4000 + +#define TEA5764_TNCTRL_PUPD1 0x8000 +#define TEA5764_TNCTRL_PUPD0 0x4000 +#define TEA5764_TNCTRL_BLIM 0x2000 +#define TEA5764_TNCTRL_SWPM 0x1000 +#define TEA5764_TNCTRL_IFCTC 0x0800 +#define TEA5764_TNCTRL_AFM 0x0400 +#define TEA5764_TNCTRL_SMUTE 0x0200 +#define TEA5764_TNCTRL_SNC 0x0100 +#define TEA5764_TNCTRL_MU 0x0080 +#define TEA5764_TNCTRL_SSL1 0x0040 +#define TEA5764_TNCTRL_SSL0 0x0020 +#define TEA5764_TNCTRL_HLSI 0x0010 +#define TEA5764_TNCTRL_MST 0x0008 +#define TEA5764_TNCTRL_SWP 0x0004 +#define TEA5764_TNCTRL_DTC 0x0002 +#define TEA5764_TNCTRL_AHLSI 0x0001 + +#define TEA5764_TUNCHK_LEVEL(x) (((x) & 0x00F0) >> 4) +#define TEA5764_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9) +#define TEA5764_TUNCHK_TUNTO 0x0100 +#define TEA5764_TUNCHK_LD 0x0008 +#define TEA5764_TUNCHK_STEREO 0x0004 + +#define TEA5764_TESTREG_TRIGFR 0x0800 + +struct tea5764_regs { + u16 intreg; /* INTFLAG & INTMSK */ + u16 frqset; /* FRQSETMSB & FRQSETLSB */ + u16 tnctrl; /* TNCTRL1 & TNCTRL2 */ + u16 frqchk; /* FRQCHKMSB & FRQCHKLSB */ + u16 tunchk; /* IFCHK & LEVCHK */ + u16 testreg; /* TESTBITS & TESTMODE */ + u16 rdsstat; /* RDSSTAT1 & RDSSTAT2 */ + u16 rdslb; /* RDSLBMSB & RDSLBLSB */ + u16 rdspb; /* RDSPBMSB & RDSPBLSB */ + u16 rdsbc; /* RDSBBC & RDSGBC */ + u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */ + u16 rdsbbl; /* PAUSEDET & RDSBBL */ + u16 manid; /* MANID1 & MANID2 */ + u16 chipid; /* CHIPID1 & CHIPID2 */ +} __attribute__ ((packed)); + +struct tea5764_write_regs { + u8 intreg; /* INTMSK */ + u16 frqset; /* FRQSETMSB & FRQSETLSB */ + u16 tnctrl; /* TNCTRL1 & TNCTRL2 */ + u16 testreg; /* TESTBITS & TESTMODE */ + u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */ + u16 rdsbbl; /* PAUSEDET & RDSBBL */ +} __attribute__ ((packed)); + +#ifndef RADIO_TEA5764_XTAL +#define RADIO_TEA5764_XTAL 1 +#endif + +static int radio_nr = -1; +static int use_xtal = RADIO_TEA5764_XTAL; + +struct tea5764_device { + struct i2c_client *i2c_client; + struct video_device *videodev; + struct tea5764_regs regs; + struct mutex mutex; +}; + +/* I2C code related */ +int tea5764_i2c_read(struct tea5764_device *radio) +{ + int i; + u16 *p = (u16 *) &radio->regs; + + struct i2c_msg msgs[1] = { + { radio->i2c_client->addr, I2C_M_RD, sizeof(radio->regs), + (void *)&radio->regs }, + }; + if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1) + return -EIO; + for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++) + p[i] = __be16_to_cpu(p[i]); + + return 0; +} + +int tea5764_i2c_write(struct tea5764_device *radio) +{ + struct tea5764_write_regs wr; + struct tea5764_regs *r = &radio->regs; + struct i2c_msg msgs[1] = { + { radio->i2c_client->addr, 0, sizeof(wr), (void *) &wr }, + }; + wr.intreg = r->intreg & 0xff; + wr.frqset = __cpu_to_be16(r->frqset); + wr.tnctrl = __cpu_to_be16(r->tnctrl); + wr.testreg = __cpu_to_be16(r->testreg); + wr.rdsctrl = __cpu_to_be16(r->rdsctrl); + wr.rdsbbl = __cpu_to_be16(r->rdsbbl); + if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1) + return -EIO; + return 0; +} + +/* V4L2 code related */ +static struct v4l2_queryctrl radio_qctrl[] = { + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + } +}; + +static void tea5764_power_up(struct tea5764_device *radio) +{ + struct tea5764_regs *r = &radio->regs; + + if (!(r->tnctrl & TEA5764_TNCTRL_PUPD0)) { + r->tnctrl &= ~(TEA5764_TNCTRL_AFM | TEA5764_TNCTRL_MU | + TEA5764_TNCTRL_HLSI); + if (!use_xtal) + r->testreg |= TEA5764_TESTREG_TRIGFR; + else + r->testreg &= ~TEA5764_TESTREG_TRIGFR; + + r->tnctrl |= TEA5764_TNCTRL_PUPD0; + tea5764_i2c_write(radio); + } +} + +static void tea5764_power_down(struct tea5764_device *radio) +{ + struct tea5764_regs *r = &radio->regs; + + if (r->tnctrl & TEA5764_TNCTRL_PUPD0) { + r->tnctrl &= ~TEA5764_TNCTRL_PUPD0; + tea5764_i2c_write(radio); + } +} + +static void tea5764_set_freq(struct tea5764_device *radio, int freq) +{ + struct tea5764_regs *r = &radio->regs; + + /* formula: (freq [+ or -] 225000) / 8192 */ + if (r->tnctrl & TEA5764_TNCTRL_HLSI) + r->frqset = (freq + 225000) / 8192; + else + r->frqset = (freq - 225000) / 8192; +} + +static int tea5764_get_freq(struct tea5764_device *radio) +{ + struct tea5764_regs *r = &radio->regs; + + if (r->tnctrl & TEA5764_TNCTRL_HLSI) + return (r->frqchk * 8192) - 225000; + else + return (r->frqchk * 8192) + 225000; +} + +/* tune an frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ +static void tea5764_tune(struct tea5764_device *radio, int freq) +{ + tea5764_set_freq(radio, freq); + if (tea5764_i2c_write(radio)) + PWARN("Could not set frequency!"); +} + +static void tea5764_set_audout_mode(struct tea5764_device *radio, int audmode) +{ + struct tea5764_regs *r = &radio->regs; + int tnctrl = r->tnctrl; + + if (audmode == V4L2_TUNER_MODE_MONO) + r->tnctrl |= TEA5764_TNCTRL_MST; + else + r->tnctrl &= ~TEA5764_TNCTRL_MST; + if (tnctrl != r->tnctrl) + tea5764_i2c_write(radio); +} + +static int tea5764_get_audout_mode(struct tea5764_device *radio) +{ + struct tea5764_regs *r = &radio->regs; + + if (r->tnctrl & TEA5764_TNCTRL_MST) + return V4L2_TUNER_MODE_MONO; + else + return V4L2_TUNER_MODE_STEREO; +} + +static void tea5764_mute(struct tea5764_device *radio, int on) +{ + struct tea5764_regs *r = &radio->regs; + int tnctrl = r->tnctrl; + + if (on) + r->tnctrl |= TEA5764_TNCTRL_MU; + else + r->tnctrl &= ~TEA5764_TNCTRL_MU; + if (tnctrl != r->tnctrl) + tea5764_i2c_write(radio); +} + +static int tea5764_is_muted(struct tea5764_device *radio) +{ + return radio->regs.tnctrl & TEA5764_TNCTRL_MU; +} + +/* V4L2 vidioc */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + struct tea5764_device *radio = video_drvdata(file); + struct video_device *dev = radio->videodev; + + strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver)); + strlcpy(v->card, dev->name, sizeof(v->card)); + snprintf(v->bus_info, sizeof(v->bus_info), + "I2C:%s", dev_name(&dev->dev)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct tea5764_device *radio = video_drvdata(file); + struct tea5764_regs *r = &radio->regs; + + if (v->index > 0) + return -EINVAL; + + memset(v, 0, sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; + tea5764_i2c_read(radio); + v->rangelow = FREQ_MIN * FREQ_MUL; + v->rangehigh = FREQ_MAX * FREQ_MUL; + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + if (r->tunchk & TEA5764_TUNCHK_STEREO) + v->rxsubchans = V4L2_TUNER_SUB_STEREO; + else + v->rxsubchans = V4L2_TUNER_SUB_MONO; + v->audmode = tea5764_get_audout_mode(radio); + v->signal = TEA5764_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf; + v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk); + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct tea5764_device *radio = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + tea5764_set_audout_mode(radio, v->audmode); + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct tea5764_device *radio = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + if (f->frequency == 0) { + /* We special case this as a power down control. */ + tea5764_power_down(radio); + } + if (f->frequency < (FREQ_MIN * FREQ_MUL)) + return -EINVAL; + if (f->frequency > (FREQ_MAX * FREQ_MUL)) + return -EINVAL; + tea5764_power_up(radio); + tea5764_tune(radio, (f->frequency * 125) / 2); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct tea5764_device *radio = video_drvdata(file); + struct tea5764_regs *r = &radio->regs; + + if (f->tuner != 0) + return -EINVAL; + tea5764_i2c_read(radio); + memset(f, 0, sizeof(*f)); + f->type = V4L2_TUNER_RADIO; + if (r->tnctrl & TEA5764_TNCTRL_PUPD0) + f->frequency = (tea5764_get_freq(radio) * 2) / 125; + else + f->frequency = 0; + + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); + return 0; + } + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct tea5764_device *radio = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + tea5764_i2c_read(radio); + ctrl->value = tea5764_is_muted(radio) ? 1 : 0; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct tea5764_device *radio = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + tea5764_mute(radio, ctrl->value); + return 0; + } + return -EINVAL; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + return 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index > 1) + return -EINVAL; + + strcpy(a->name, "Radio"); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index != 0) + return -EINVAL; + + return 0; +} + +/* File system interface */ +static const struct v4l2_file_operations tea5764_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops tea5764_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; + +/* V4L2 interface */ +static struct video_device tea5764_radio_template = { + .name = "TEA5764 FM-Radio", + .fops = &tea5764_fops, + .ioctl_ops = &tea5764_ioctl_ops, + .release = video_device_release, +}; + +/* I2C probe: check if the device exists and register with v4l if it is */ +static int __devinit tea5764_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tea5764_device *radio; + struct tea5764_regs *r; + int ret; + + PDEBUG("probe"); + radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL); + if (!radio) + return -ENOMEM; + + mutex_init(&radio->mutex); + radio->i2c_client = client; + ret = tea5764_i2c_read(radio); + if (ret) + goto errfr; + r = &radio->regs; + PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid); + if (r->chipid != TEA5764_CHIPID || + (r->manid & 0x0fff) != TEA5764_MANID) { + PWARN("This chip is not a TEA5764!"); + ret = -EINVAL; + goto errfr; + } + + radio->videodev = video_device_alloc(); + if (!(radio->videodev)) { + ret = -ENOMEM; + goto errfr; + } + memcpy(radio->videodev, &tea5764_radio_template, + sizeof(tea5764_radio_template)); + + i2c_set_clientdata(client, radio); + video_set_drvdata(radio->videodev, radio); + radio->videodev->lock = &radio->mutex; + + /* initialize and power off the chip */ + tea5764_i2c_read(radio); + tea5764_set_audout_mode(radio, V4L2_TUNER_MODE_STEREO); + tea5764_mute(radio, 1); + tea5764_power_down(radio); + + ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); + if (ret < 0) { + PWARN("Could not register video device!"); + goto errrel; + } + + PINFO("registered."); + return 0; +errrel: + video_device_release(radio->videodev); +errfr: + kfree(radio); + return ret; +} + +static int __devexit tea5764_i2c_remove(struct i2c_client *client) +{ + struct tea5764_device *radio = i2c_get_clientdata(client); + + PDEBUG("remove"); + if (radio) { + tea5764_power_down(radio); + video_unregister_device(radio->videodev); + kfree(radio); + } + return 0; +} + +/* I2C subsystem interface */ +static const struct i2c_device_id tea5764_id[] = { + { "radio-tea5764", 0 }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(i2c, tea5764_id); + +static struct i2c_driver tea5764_i2c_driver = { + .driver = { + .name = "radio-tea5764", + .owner = THIS_MODULE, + }, + .probe = tea5764_i2c_probe, + .remove = __devexit_p(tea5764_i2c_remove), + .id_table = tea5764_id, +}; + +/* init the driver */ +static int __init tea5764_init(void) +{ + int ret = i2c_add_driver(&tea5764_i2c_driver); + + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": " + DRIVER_DESC "\n"); + return ret; +} + +/* cleanup the driver */ +static void __exit tea5764_exit(void) +{ + i2c_del_driver(&tea5764_i2c_driver); +} + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +module_param(use_xtal, int, 1); +MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board"); +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(radio_nr, "video4linux device number to use"); + +module_init(tea5764_init); +module_exit(tea5764_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-terratec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-terratec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-terratec.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-terratec.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,418 @@ +/* Terratec ActiveRadio ISA Standalone card driver for Linux radio support + * (c) 1999 R. Offermanns (rolf@offermanns.de) + * based on the aimslab radio driver from M. Kirkwood + * many thanks to Michael Becker and Friedhelm Birth (from TerraTec) + * + * + * History: + * 1999-05-21 First preview release + * + * Notes on the hardware: + * There are two "main" chips on the card: + * - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf) + * - Philips SAA6588 (http://www-us.semiconductors.philips.com/acrobat/datasheets/SAA6588_1.pdf) + * (you can get the datasheet at the above links) + * + * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); + * Volume Control is done digitally + * + * there is a I2C controlled RDS decoder (SAA6588) onboard, which i would like to support someday + * (as soon i have understand how to get started :) + * If you can help me out with that, please contact me!! + * + * + * Converted to V4L2 API by Mauro Carvalho Chehab + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* kernel radio structs */ +#include +#include /* for KERNEL_VERSION MACRO */ +#include /* outb, outb_p */ +#include +#include + +MODULE_AUTHOR("R.OFFERMANNS & others"); +MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); +MODULE_LICENSE("GPL"); + +#ifndef CONFIG_RADIO_TERRATEC_PORT +#define CONFIG_RADIO_TERRATEC_PORT 0x590 +#endif + +static int io = CONFIG_RADIO_TERRATEC_PORT; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +static struct v4l2_queryctrl radio_qctrl[] = { + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0xff, + .type = V4L2_CTRL_TYPE_INTEGER, + } +}; + +#define WRT_DIS 0x00 +#define CLK_OFF 0x00 +#define IIC_DATA 0x01 +#define IIC_CLK 0x02 +#define DATA 0x04 +#define CLK_ON 0x08 +#define WRT_EN 0x10 + +struct terratec +{ + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + int curvol; + unsigned long curfreq; + int muted; + struct mutex lock; +}; + +static struct terratec terratec_card; + +/* local things */ + +static void tt_write_vol(struct terratec *tt, int volume) +{ + int i; + + volume = volume + (volume * 32); /* change both channels */ + mutex_lock(&tt->lock); + for (i = 0; i < 8; i++) { + if (volume & (0x80 >> i)) + outb(0x80, tt->io + 1); + else + outb(0x00, tt->io + 1); + } + mutex_unlock(&tt->lock); +} + + + +static void tt_mute(struct terratec *tt) +{ + tt->muted = 1; + tt_write_vol(tt, 0); +} + +static int tt_setvol(struct terratec *tt, int vol) +{ + if (vol == tt->curvol) { /* requested volume = current */ + if (tt->muted) { /* user is unmuting the card */ + tt->muted = 0; + tt_write_vol(tt, vol); /* enable card */ + } + return 0; + } + + if (vol == 0) { /* volume = 0 means mute the card */ + tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */ + tt->curvol = vol; /* track the volume state! */ + return 0; + } + + tt->muted = 0; + tt_write_vol(tt, vol); + tt->curvol = vol; + return 0; +} + + +/* this is the worst part in this driver */ +/* many more or less strange things are going on here, but hey, it works :) */ + +static int tt_setfreq(struct terratec *tt, unsigned long freq1) +{ + int freq; + int i; + int p; + int temp; + long rest; + unsigned char buffer[25]; /* we have to bit shift 25 registers */ + + mutex_lock(&tt->lock); + + tt->curfreq = freq1; + + freq = freq1 / 160; /* convert the freq. to a nice to handle value */ + memset(buffer, 0, sizeof(buffer)); + + rest = freq * 10 + 10700; /* I once had understood what is going on here */ + /* maybe some wise guy (friedhelm?) can comment this stuff */ + i = 13; + p = 10; + temp = 102400; + while (rest != 0) { + if (rest % temp == rest) + buffer[i] = 0; + else { + buffer[i] = 1; + rest = rest - temp; + } + i--; + p--; + temp = temp / 2; + } + + for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */ + if (buffer[i] == 1) { + outb(WRT_EN | DATA, tt->io); + outb(WRT_EN | DATA | CLK_ON, tt->io); + outb(WRT_EN | DATA, tt->io); + } else { + outb(WRT_EN | 0x00, tt->io); + outb(WRT_EN | 0x00 | CLK_ON, tt->io); + } + } + outb(0x00, tt->io); + + mutex_unlock(&tt->lock); + + return 0; +} + +static int tt_getsigstr(struct terratec *tt) +{ + if (inb(tt->io) & 2) /* bit set = no signal present */ + return 0; + return 1; /* signal present */ +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); + strlcpy(v->card, "ActiveRadio", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct terratec *tt = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = 87 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO; + v->capability = V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xFFFF * tt_getsigstr(tt); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct terratec *tt = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + tt_setfreq(tt, f->frequency); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct terratec *tt = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = tt->curfreq; + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); + return 0; + } + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct terratec *tt = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (tt->muted) + ctrl->value = 1; + else + ctrl->value = 0; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = tt->curvol * 6554; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct terratec *tt = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + tt_mute(tt); + else + tt_setvol(tt,tt->curvol); + return 0; + case V4L2_CID_AUDIO_VOLUME: + tt_setvol(tt,ctrl->value); + return 0; + } + return -EINVAL; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static const struct v4l2_file_operations terratec_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops terratec_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +static int __init terratec_init(void) +{ + struct terratec *tt = &terratec_card; + struct v4l2_device *v4l2_dev = &tt->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name)); + tt->io = io; + if (tt->io == -1) { + v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n"); + return -EINVAL; + } + if (!request_region(tt->io, 2, "terratec")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", io); + return -EBUSY; + } + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(tt->io, 2); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name)); + tt->vdev.v4l2_dev = v4l2_dev; + tt->vdev.fops = &terratec_fops; + tt->vdev.ioctl_ops = &terratec_ioctl_ops; + tt->vdev.release = video_device_release_empty; + video_set_drvdata(&tt->vdev, tt); + + mutex_init(&tt->lock); + + /* mute card - prevents noisy bootups */ + tt_write_vol(tt, 0); + + if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(&tt->v4l2_dev); + release_region(tt->io, 2); + return -EINVAL; + } + + v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); + return 0; +} + +static void __exit terratec_exit(void) +{ + struct terratec *tt = &terratec_card; + struct v4l2_device *v4l2_dev = &tt->v4l2_dev; + + video_unregister_device(&tt->vdev); + v4l2_device_unregister(&tt->v4l2_dev); + release_region(tt->io, 2); + v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n"); +} + +module_init(terratec_init); +module_exit(terratec_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-timb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-timb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-timb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-timb.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,248 @@ +/* + * radio-timb.c Timberdale FPGA Radio driver + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "timb-radio" + +struct timbradio { + struct timb_radio_platform_data pdata; + struct v4l2_subdev *sd_tuner; + struct v4l2_subdev *sd_dsp; + struct video_device video_dev; + struct v4l2_device v4l2_dev; + struct mutex lock; +}; + + +static int timbradio_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver)); + strlcpy(v->card, "Timberdale Radio", sizeof(v->card)); + snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME); + v->version = KERNEL_VERSION(0, 0, 1); + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int timbradio_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct timbradio *tr = video_drvdata(file); + return v4l2_subdev_call(tr->sd_tuner, tuner, g_tuner, v); +} + +static int timbradio_vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct timbradio *tr = video_drvdata(file); + return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v); +} + +static int timbradio_vidioc_g_input(struct file *filp, void *priv, + unsigned int *i) +{ + *i = 0; + return 0; +} + +static int timbradio_vidioc_s_input(struct file *filp, void *priv, + unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int timbradio_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int timbradio_vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static int timbradio_vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct timbradio *tr = video_drvdata(file); + return v4l2_subdev_call(tr->sd_tuner, tuner, s_frequency, f); +} + +static int timbradio_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct timbradio *tr = video_drvdata(file); + return v4l2_subdev_call(tr->sd_tuner, tuner, g_frequency, f); +} + +static int timbradio_vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct timbradio *tr = video_drvdata(file); + return v4l2_subdev_call(tr->sd_dsp, core, queryctrl, qc); +} + +static int timbradio_vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct timbradio *tr = video_drvdata(file); + return v4l2_subdev_call(tr->sd_dsp, core, g_ctrl, ctrl); +} + +static int timbradio_vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct timbradio *tr = video_drvdata(file); + return v4l2_subdev_call(tr->sd_dsp, core, s_ctrl, ctrl); +} + +static const struct v4l2_ioctl_ops timbradio_ioctl_ops = { + .vidioc_querycap = timbradio_vidioc_querycap, + .vidioc_g_tuner = timbradio_vidioc_g_tuner, + .vidioc_s_tuner = timbradio_vidioc_s_tuner, + .vidioc_g_frequency = timbradio_vidioc_g_frequency, + .vidioc_s_frequency = timbradio_vidioc_s_frequency, + .vidioc_g_input = timbradio_vidioc_g_input, + .vidioc_s_input = timbradio_vidioc_s_input, + .vidioc_g_audio = timbradio_vidioc_g_audio, + .vidioc_s_audio = timbradio_vidioc_s_audio, + .vidioc_queryctrl = timbradio_vidioc_queryctrl, + .vidioc_g_ctrl = timbradio_vidioc_g_ctrl, + .vidioc_s_ctrl = timbradio_vidioc_s_ctrl +}; + +static const struct v4l2_file_operations timbradio_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static int __devinit timbradio_probe(struct platform_device *pdev) +{ + struct timb_radio_platform_data *pdata = pdev->dev.platform_data; + struct timbradio *tr; + int err; + + if (!pdata) { + dev_err(&pdev->dev, "Platform data missing\n"); + err = -EINVAL; + goto err; + } + + tr = kzalloc(sizeof(*tr), GFP_KERNEL); + if (!tr) { + err = -ENOMEM; + goto err; + } + + tr->pdata = *pdata; + mutex_init(&tr->lock); + + strlcpy(tr->video_dev.name, "Timberdale Radio", + sizeof(tr->video_dev.name)); + tr->video_dev.fops = &timbradio_fops; + tr->video_dev.ioctl_ops = &timbradio_ioctl_ops; + tr->video_dev.release = video_device_release_empty; + tr->video_dev.minor = -1; + tr->video_dev.lock = &tr->lock; + + strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name)); + err = v4l2_device_register(NULL, &tr->v4l2_dev); + if (err) + goto err_v4l2_dev; + + tr->video_dev.v4l2_dev = &tr->v4l2_dev; + + err = video_register_device(&tr->video_dev, VFL_TYPE_RADIO, -1); + if (err) { + dev_err(&pdev->dev, "Error reg video\n"); + goto err_video_req; + } + + video_set_drvdata(&tr->video_dev, tr); + + platform_set_drvdata(pdev, tr); + return 0; + +err_video_req: + video_device_release_empty(&tr->video_dev); + v4l2_device_unregister(&tr->v4l2_dev); +err_v4l2_dev: + kfree(tr); +err: + dev_err(&pdev->dev, "Failed to register: %d\n", err); + + return err; +} + +static int __devexit timbradio_remove(struct platform_device *pdev) +{ + struct timbradio *tr = platform_get_drvdata(pdev); + + video_unregister_device(&tr->video_dev); + video_device_release_empty(&tr->video_dev); + + v4l2_device_unregister(&tr->v4l2_dev); + + kfree(tr); + + return 0; +} + +static struct platform_driver timbradio_platform_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = timbradio_probe, + .remove = timbradio_remove, +}; + +/*--------------------------------------------------------------------------*/ + +static int __init timbradio_init(void) +{ + return platform_driver_register(&timbradio_platform_driver); +} + +static void __exit timbradio_exit(void) +{ + platform_driver_unregister(&timbradio_platform_driver); +} + +module_init(timbradio_init); +module_exit(timbradio_exit); + +MODULE_DESCRIPTION("Timberdale Radio driver"); +MODULE_AUTHOR("Mocean Laboratories "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:"DRIVER_NAME); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-trust.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-trust.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-trust.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-trust.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,434 @@ +/* radio-trust.c - Trust FM Radio card driver for Linux 2.2 + * by Eric Lammerts + * + * Based on radio-aztech.c. Original notes: + * + * Adapted to support the Video for Linux API by + * Russell Kroll . Based on original tuner code by: + * + * Quay Ly + * Donald Song + * Jason Lewis (jlewis@twilight.vtc.vsc.edu) + * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) + * William McGrath (wmcgrath@twilight.vtc.vsc.edu) + * + * Converted to V4L2 API by Mauro Carvalho Chehab + */ + +#include +#include +#include +#include +#include /* for KERNEL_VERSION MACRO */ +#include +#include +#include +#include + +MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); +MODULE_LICENSE("GPL"); + +/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ + +#ifndef CONFIG_RADIO_TRUST_PORT +#define CONFIG_RADIO_TRUST_PORT -1 +#endif + +static int io = CONFIG_RADIO_TRUST_PORT; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct trust { + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + int ioval; + __u16 curvol; + __u16 curbass; + __u16 curtreble; + int muted; + unsigned long curfreq; + int curstereo; + int curmute; + struct mutex lock; +}; + +static struct trust trust_card; + +/* i2c addresses */ +#define TDA7318_ADDR 0x88 +#define TSA6060T_ADDR 0xc4 + +#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0) +#define TR_SET_SCL outb(tr->ioval |= 2, tr->io) +#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io) +#define TR_SET_SDA outb(tr->ioval |= 1, tr->io) +#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io) + +static void write_i2c(struct trust *tr, int n, ...) +{ + unsigned char val, mask; + va_list args; + + va_start(args, n); + + /* start condition */ + TR_SET_SDA; + TR_SET_SCL; + TR_DELAY; + TR_CLR_SDA; + TR_CLR_SCL; + TR_DELAY; + + for(; n; n--) { + val = va_arg(args, unsigned); + for(mask = 0x80; mask; mask >>= 1) { + if(val & mask) + TR_SET_SDA; + else + TR_CLR_SDA; + TR_SET_SCL; + TR_DELAY; + TR_CLR_SCL; + TR_DELAY; + } + /* acknowledge bit */ + TR_SET_SDA; + TR_SET_SCL; + TR_DELAY; + TR_CLR_SCL; + TR_DELAY; + } + + /* stop condition */ + TR_CLR_SDA; + TR_DELAY; + TR_SET_SCL; + TR_DELAY; + TR_SET_SDA; + TR_DELAY; + + va_end(args); +} + +static void tr_setvol(struct trust *tr, __u16 vol) +{ + mutex_lock(&tr->lock); + tr->curvol = vol / 2048; + write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f); + mutex_unlock(&tr->lock); +} + +static int basstreble2chip[15] = { + 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 +}; + +static void tr_setbass(struct trust *tr, __u16 bass) +{ + mutex_lock(&tr->lock); + tr->curbass = bass / 4370; + write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]); + mutex_unlock(&tr->lock); +} + +static void tr_settreble(struct trust *tr, __u16 treble) +{ + mutex_lock(&tr->lock); + tr->curtreble = treble / 4370; + write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]); + mutex_unlock(&tr->lock); +} + +static void tr_setstereo(struct trust *tr, int stereo) +{ + mutex_lock(&tr->lock); + tr->curstereo = !!stereo; + tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2); + outb(tr->ioval, tr->io); + mutex_unlock(&tr->lock); +} + +static void tr_setmute(struct trust *tr, int mute) +{ + mutex_lock(&tr->lock); + tr->curmute = !!mute; + tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3); + outb(tr->ioval, tr->io); + mutex_unlock(&tr->lock); +} + +static int tr_getsigstr(struct trust *tr) +{ + int i, v; + + mutex_lock(&tr->lock); + for (i = 0, v = 0; i < 100; i++) + v |= inb(tr->io); + mutex_unlock(&tr->lock); + return (v & 1) ? 0 : 0xffff; +} + +static int tr_getstereo(struct trust *tr) +{ + /* don't know how to determine it, just return the setting */ + return tr->curstereo; +} + +static void tr_setfreq(struct trust *tr, unsigned long f) +{ + mutex_lock(&tr->lock); + tr->curfreq = f; + f /= 160; /* Convert to 10 kHz units */ + f += 1070; /* Add 10.7 MHz IF */ + write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); + mutex_unlock(&tr->lock); +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-trust", sizeof(v->driver)); + strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct trust *tr = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = 87.5 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + if (tr_getstereo(tr)) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = tr_getsigstr(tr); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct trust *tr = video_drvdata(file); + + if (v->index) + return -EINVAL; + tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO); + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct trust *tr = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + tr_setfreq(tr, f->frequency); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct trust *tr = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = tr->curfreq; + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535); + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct trust *tr = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = tr->curmute; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = tr->curvol * 2048; + return 0; + case V4L2_CID_AUDIO_BASS: + ctrl->value = tr->curbass * 4370; + return 0; + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = tr->curtreble * 4370; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct trust *tr = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + tr_setmute(tr, ctrl->value); + return 0; + case V4L2_CID_AUDIO_VOLUME: + tr_setvol(tr, ctrl->value); + return 0; + case V4L2_CID_AUDIO_BASS: + tr_setbass(tr, ctrl->value); + return 0; + case V4L2_CID_AUDIO_TREBLE: + tr_settreble(tr, ctrl->value); + return 0; + } + return -EINVAL; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static const struct v4l2_file_operations trust_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops trust_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +static int __init trust_init(void) +{ + struct trust *tr = &trust_card; + struct v4l2_device *v4l2_dev = &tr->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name)); + tr->io = io; + tr->ioval = 0xf; + mutex_init(&tr->lock); + + if (tr->io == -1) { + v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n"); + return -EINVAL; + } + if (!request_region(tr->io, 2, "Trust FM Radio")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io); + return -EBUSY; + } + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(tr->io, 2); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name)); + tr->vdev.v4l2_dev = v4l2_dev; + tr->vdev.fops = &trust_fops; + tr->vdev.ioctl_ops = &trust_ioctl_ops; + tr->vdev.release = video_device_release_empty; + video_set_drvdata(&tr->vdev, tr); + + write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ + + tr_setvol(tr, 0xffff); + tr_setbass(tr, 0x8000); + tr_settreble(tr, 0x8000); + tr_setstereo(tr, 1); + + /* mute card - prevents noisy bootups */ + tr_setmute(tr, 1); + + if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(tr->io, 2); + return -EINVAL; + } + + v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); + + return 0; +} + +static void __exit cleanup_trust_module(void) +{ + struct trust *tr = &trust_card; + + video_unregister_device(&tr->vdev); + v4l2_device_unregister(&tr->v4l2_dev); + release_region(tr->io, 2); +} + +module_init(trust_init); +module_exit(cleanup_trust_module); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-typhoon.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-typhoon.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-typhoon.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-typhoon.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,407 @@ +/* Typhoon Radio Card driver for radio support + * (c) 1999 Dr. Henrik Seidel + * + * Notes on the hardware + * + * This card has two output sockets, one for speakers and one for line. + * The speaker output has volume control, but only in four discrete + * steps. The line output has neither volume control nor mute. + * + * The card has auto-stereo according to its manual, although it all + * sounds mono to me (even with the Win/DOS drivers). Maybe it's my + * antenna - I really don't know for sure. + * + * Frequency control is done digitally. + * + * Volume control is done digitally, but there are only four different + * possible values. So you should better always turn the volume up and + * use line control. I got the best results by connecting line output + * to the sound card microphone input. For such a configuration the + * volume control has no effect, since volume control only influences + * the speaker output. + * + * There is no explicit mute/unmute. So I set the radio frequency to a + * value where I do expect just noise and turn the speaker volume down. + * The frequency change is necessary since the card never seems to be + * completely silent. + * + * Converted to V4L2 API by Mauro Carvalho Chehab + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* for KERNEL_VERSION MACRO */ +#include /* kernel radio structs */ +#include /* outb, outb_p */ +#include +#include + +MODULE_AUTHOR("Dr. Henrik Seidel"); +MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); +MODULE_LICENSE("GPL"); + +#ifndef CONFIG_RADIO_TYPHOON_PORT +#define CONFIG_RADIO_TYPHOON_PORT -1 +#endif + +#ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ +#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 +#endif + +static int io = CONFIG_RADIO_TYPHOON_PORT; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); + +module_param(radio_nr, int, 0); + +static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ; +module_param(mutefreq, ulong, 0); +MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); + +#define RADIO_VERSION KERNEL_VERSION(0, 1, 1) + +#define BANNER "Typhoon Radio Card driver v0.1.1\n" + +struct typhoon { + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + int curvol; + int muted; + unsigned long curfreq; + unsigned long mutefreq; + struct mutex lock; +}; + +static struct typhoon typhoon_card; + +static void typhoon_setvol_generic(struct typhoon *dev, int vol) +{ + mutex_lock(&dev->lock); + vol >>= 14; /* Map 16 bit to 2 bit */ + vol &= 3; + outb_p(vol / 2, dev->io); /* Set the volume, high bit. */ + outb_p(vol % 2, dev->io + 2); /* Set the volume, low bit. */ + mutex_unlock(&dev->lock); +} + +static int typhoon_setfreq_generic(struct typhoon *dev, + unsigned long frequency) +{ + unsigned long outval; + unsigned long x; + + /* + * The frequency transfer curve is not linear. The best fit I could + * get is + * + * outval = -155 + exp((f + 15.55) * 0.057)) + * + * where frequency f is in MHz. Since we don't have exp in the kernel, + * I approximate this function by a third order polynomial. + * + */ + + mutex_lock(&dev->lock); + x = frequency / 160; + outval = (x * x + 2500) / 5000; + outval = (outval * x + 5000) / 10000; + outval -= (10 * x * x + 10433) / 20866; + outval += 4 * x - 11505; + + outb_p((outval >> 8) & 0x01, dev->io + 4); + outb_p(outval >> 9, dev->io + 6); + outb_p(outval & 0xff, dev->io + 8); + mutex_unlock(&dev->lock); + + return 0; +} + +static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency) +{ + typhoon_setfreq_generic(dev, frequency); + dev->curfreq = frequency; + return 0; +} + +static void typhoon_mute(struct typhoon *dev) +{ + if (dev->muted == 1) + return; + typhoon_setvol_generic(dev, 0); + typhoon_setfreq_generic(dev, dev->mutefreq); + dev->muted = 1; +} + +static void typhoon_unmute(struct typhoon *dev) +{ + if (dev->muted == 0) + return; + typhoon_setfreq_generic(dev, dev->curfreq); + typhoon_setvol_generic(dev, dev->curvol); + dev->muted = 0; +} + +static int typhoon_setvol(struct typhoon *dev, int vol) +{ + if (dev->muted && vol != 0) { /* user is unmuting the card */ + dev->curvol = vol; + typhoon_unmute(dev); + return 0; + } + if (vol == dev->curvol) /* requested volume == current */ + return 0; + + if (vol == 0) { /* volume == 0 means mute the card */ + typhoon_mute(dev); + dev->curvol = vol; + return 0; + } + typhoon_setvol_generic(dev, vol); + dev->curvol = vol; + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-typhoon", sizeof(v->driver)); + strlcpy(v->card, "Typhoon Radio", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + if (v->index > 0) + return -EINVAL; + + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = 87.5 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO; + v->capability = V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xFFFF; /* We can't get the signal strength */ + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct typhoon *dev = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = dev->curfreq; + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct typhoon *dev = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + dev->curfreq = f->frequency; + typhoon_setfreq(dev, dev->curfreq); + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct typhoon *dev = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = dev->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = dev->curvol; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl (struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct typhoon *dev = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + typhoon_mute(dev); + else + typhoon_unmute(dev); + return 0; + case V4L2_CID_AUDIO_VOLUME: + typhoon_setvol(dev, ctrl->value); + return 0; + } + return -EINVAL; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static int vidioc_log_status(struct file *file, void *priv) +{ + struct typhoon *dev = video_drvdata(file); + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + + v4l2_info(v4l2_dev, BANNER); +#ifdef MODULE + v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n"); +#else + v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n"); +#endif + v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4); + v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol); + v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ? "on" : "off"); + v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io); + v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4); + return 0; +} + +static const struct v4l2_file_operations typhoon_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { + .vidioc_log_status = vidioc_log_status, + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; + +static int __init typhoon_init(void) +{ + struct typhoon *dev = &typhoon_card; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name)); + dev->io = io; + + if (dev->io == -1) { + v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n"); + return -EINVAL; + } + + if (mutefreq < 87000 || mutefreq > 108500) { + v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n"); + v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); + return -EINVAL; + } + dev->curfreq = dev->mutefreq = mutefreq << 4; + + mutex_init(&dev->lock); + if (!request_region(dev->io, 8, "typhoon")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", + dev->io); + return -EBUSY; + } + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(dev->io, 8); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + v4l2_info(v4l2_dev, BANNER); + + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &typhoon_fops; + dev->vdev.ioctl_ops = &typhoon_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); + + /* mute card - prevents noisy bootups */ + typhoon_mute(dev); + + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(&dev->v4l2_dev); + release_region(dev->io, 8); + return -EINVAL; + } + v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io); + v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq); + + return 0; +} + +static void __exit typhoon_exit(void) +{ + struct typhoon *dev = &typhoon_card; + + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); + release_region(dev->io, 8); +} + +module_init(typhoon_init); +module_exit(typhoon_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-wl1273.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-wl1273.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-wl1273.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-wl1273.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,2177 @@ +/* + * Driver for the Texas Instruments WL1273 FM radio. + * + * Copyright (C) 2011 Nokia Corporation + * Author: Matti J. Aaltonen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Wl1273 FM Radio" + +#define WL1273_POWER_SET_OFF 0 +#define WL1273_POWER_SET_FM BIT(0) +#define WL1273_POWER_SET_RDS BIT(1) +#define WL1273_POWER_SET_RETENTION BIT(4) + +#define WL1273_PUPD_SET_OFF 0x00 +#define WL1273_PUPD_SET_ON 0x01 +#define WL1273_PUPD_SET_RETENTION 0x10 + +#define WL1273_FREQ(x) (x * 10000 / 625) +#define WL1273_INV_FREQ(x) (x * 625 / 10000) + +/* + * static int radio_nr - The number of the radio device + * + * The default is 0. + */ +static int radio_nr; +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(radio_nr, "The number of the radio device. Default = 0"); + +struct wl1273_device { + char *bus_type; + + u8 forbidden; + unsigned int preemphasis; + unsigned int spacing; + unsigned int tx_power; + unsigned int rx_frequency; + unsigned int tx_frequency; + unsigned int rangelow; + unsigned int rangehigh; + unsigned int band; + bool stereo; + + /* RDS */ + unsigned int rds_on; + + wait_queue_head_t read_queue; + struct mutex lock; /* for serializing fm radio operations */ + struct completion busy; + + unsigned char *buffer; + unsigned int buf_size; + unsigned int rd_index; + unsigned int wr_index; + + /* Selected interrupts */ + u16 irq_flags; + u16 irq_received; + + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_device v4l2dev; + struct video_device videodev; + struct device *dev; + struct wl1273_core *core; + struct file *owner; + char *write_buf; + unsigned int rds_users; +}; + +#define WL1273_IRQ_MASK (WL1273_FR_EVENT | \ + WL1273_POW_ENB_EVENT) + +/* + * static unsigned int rds_buf - the number of RDS buffer blocks used. + * + * The default number is 100. + */ +static unsigned int rds_buf = 100; +module_param(rds_buf, uint, 0); +MODULE_PARM_DESC(rds_buf, "Number of RDS buffer entries. Default = 100"); + +static int wl1273_fm_write_fw(struct wl1273_core *core, + __u8 *fw, int len) +{ + struct i2c_client *client = core->client; + struct i2c_msg msg; + int i, r = 0; + + msg.addr = client->addr; + msg.flags = 0; + + for (i = 0; i <= len; i++) { + msg.len = fw[0]; + msg.buf = fw + 1; + + fw += msg.len + 1; + dev_dbg(&client->dev, "%s:len[%d]: %d\n", __func__, i, msg.len); + + r = i2c_transfer(client->adapter, &msg, 1); + if (r < 0 && i < len + 1) + break; + } + + dev_dbg(&client->dev, "%s: i: %d\n", __func__, i); + dev_dbg(&client->dev, "%s: len + 1: %d\n", __func__, len + 1); + + /* Last transfer always fails. */ + if (i == len || r == 1) + r = 0; + + return r; +} + +#define WL1273_FIFO_HAS_DATA(status) (1 << 5 & status) +#define WL1273_RDS_CORRECTABLE_ERROR (1 << 3) +#define WL1273_RDS_UNCORRECTABLE_ERROR (1 << 4) + +static int wl1273_fm_rds(struct wl1273_device *radio) +{ + struct wl1273_core *core = radio->core; + struct i2c_client *client = core->client; + u16 val; + u8 b0 = WL1273_RDS_DATA_GET, status; + struct v4l2_rds_data rds = { 0, 0, 0 }; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .buf = &b0, + .len = 1, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = (u8 *) &rds, + .len = sizeof(rds), + } + }; + int r; + + if (core->mode != WL1273_MODE_RX) + return 0; + + r = core->read(core, WL1273_RDS_SYNC_GET, &val); + if (r) + return r; + + if ((val & 0x01) == 0) { + /* RDS decoder not synchronized */ + return -EAGAIN; + } + + /* copy all four RDS blocks to internal buffer */ + do { + r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (r != ARRAY_SIZE(msg)) { + dev_err(radio->dev, WL1273_FM_DRIVER_NAME + ": %s: read_rds error r == %i)\n", + __func__, r); + } + + status = rds.block; + + if (!WL1273_FIFO_HAS_DATA(status)) + break; + + /* copy bits 0-2 (the block ID) to bits 3-5 */ + rds.block = V4L2_RDS_BLOCK_MSK & status; + rds.block |= rds.block << 3; + + /* copy the error bits to standard positions */ + if (WL1273_RDS_UNCORRECTABLE_ERROR & status) { + rds.block |= V4L2_RDS_BLOCK_ERROR; + rds.block &= ~V4L2_RDS_BLOCK_CORRECTED; + } else if (WL1273_RDS_CORRECTABLE_ERROR & status) { + rds.block &= ~V4L2_RDS_BLOCK_ERROR; + rds.block |= V4L2_RDS_BLOCK_CORRECTED; + } + + /* copy RDS block to internal buffer */ + memcpy(&radio->buffer[radio->wr_index], &rds, RDS_BLOCK_SIZE); + radio->wr_index += 3; + + /* wrap write pointer */ + if (radio->wr_index >= radio->buf_size) + radio->wr_index = 0; + + /* check for overflow & start over */ + if (radio->wr_index == radio->rd_index) { + dev_dbg(radio->dev, "RDS OVERFLOW"); + + radio->rd_index = 0; + radio->wr_index = 0; + break; + } + } while (WL1273_FIFO_HAS_DATA(status)); + + /* wake up read queue */ + if (radio->wr_index != radio->rd_index) + wake_up_interruptible(&radio->read_queue); + + return 0; +} + +static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) +{ + struct wl1273_device *radio = dev_id; + struct wl1273_core *core = radio->core; + u16 flags; + int r; + + r = core->read(core, WL1273_FLAG_GET, &flags); + if (r) + goto out; + + if (flags & WL1273_BL_EVENT) { + radio->irq_received = flags; + dev_dbg(radio->dev, "IRQ: BL\n"); + } + + if (flags & WL1273_RDS_EVENT) { + msleep(200); + + wl1273_fm_rds(radio); + } + + if (flags & WL1273_BBLK_EVENT) + dev_dbg(radio->dev, "IRQ: BBLK\n"); + + if (flags & WL1273_LSYNC_EVENT) + dev_dbg(radio->dev, "IRQ: LSYNC\n"); + + if (flags & WL1273_LEV_EVENT) { + u16 level; + + r = core->read(core, WL1273_RSSI_LVL_GET, &level); + if (r) + goto out; + + if (level > 14) + dev_dbg(radio->dev, "IRQ: LEV: 0x%x04\n", level); + } + + if (flags & WL1273_IFFR_EVENT) + dev_dbg(radio->dev, "IRQ: IFFR\n"); + + if (flags & WL1273_PI_EVENT) + dev_dbg(radio->dev, "IRQ: PI\n"); + + if (flags & WL1273_PD_EVENT) + dev_dbg(radio->dev, "IRQ: PD\n"); + + if (flags & WL1273_STIC_EVENT) + dev_dbg(radio->dev, "IRQ: STIC\n"); + + if (flags & WL1273_MAL_EVENT) + dev_dbg(radio->dev, "IRQ: MAL\n"); + + if (flags & WL1273_POW_ENB_EVENT) { + complete(&radio->busy); + dev_dbg(radio->dev, "NOT BUSY\n"); + dev_dbg(radio->dev, "IRQ: POW_ENB\n"); + } + + if (flags & WL1273_SCAN_OVER_EVENT) + dev_dbg(radio->dev, "IRQ: SCAN_OVER\n"); + + if (flags & WL1273_ERROR_EVENT) + dev_dbg(radio->dev, "IRQ: ERROR\n"); + + if (flags & WL1273_FR_EVENT) { + u16 freq; + + dev_dbg(radio->dev, "IRQ: FR:\n"); + + if (core->mode == WL1273_MODE_RX) { + r = core->write(core, WL1273_TUNER_MODE_SET, + TUNER_MODE_STOP_SEARCH); + if (r) { + dev_err(radio->dev, + "%s: TUNER_MODE_SET fails: %d\n", + __func__, r); + goto out; + } + + r = core->read(core, WL1273_FREQ_SET, &freq); + if (r) + goto out; + + if (radio->band == WL1273_BAND_JAPAN) + radio->rx_frequency = WL1273_BAND_JAPAN_LOW + + freq * 50; + else + radio->rx_frequency = WL1273_BAND_OTHER_LOW + + freq * 50; + /* + * The driver works better with this msleep, + * the documentation doesn't mention it. + */ + usleep_range(10000, 15000); + + dev_dbg(radio->dev, "%dkHz\n", radio->rx_frequency); + + } else { + r = core->read(core, WL1273_CHANL_SET, &freq); + if (r) + goto out; + + dev_dbg(radio->dev, "%dkHz\n", freq); + } + dev_dbg(radio->dev, "%s: NOT BUSY\n", __func__); + } + +out: + core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); + complete(&radio->busy); + + return IRQ_HANDLED; +} + +static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) +{ + struct wl1273_core *core = radio->core; + int r = 0; + + if (freq < WL1273_BAND_TX_LOW) { + dev_err(radio->dev, + "Frequency out of range: %d < %d\n", freq, + WL1273_BAND_TX_LOW); + return -ERANGE; + } + + if (freq > WL1273_BAND_TX_HIGH) { + dev_err(radio->dev, + "Frequency out of range: %d > %d\n", freq, + WL1273_BAND_TX_HIGH); + return -ERANGE; + } + + /* + * The driver works better with this sleep, + * the documentation doesn't mention it. + */ + usleep_range(5000, 10000); + + dev_dbg(radio->dev, "%s: freq: %d kHz\n", __func__, freq); + + /* Set the current tx channel */ + r = core->write(core, WL1273_CHANL_SET, freq / 10); + if (r) + return r; + + INIT_COMPLETION(radio->busy); + + /* wait for the FR IRQ */ + r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); + if (!r) + return -ETIMEDOUT; + + dev_dbg(radio->dev, "WL1273_CHANL_SET: %d\n", r); + + /* Enable the output power */ + r = core->write(core, WL1273_POWER_ENB_SET, 1); + if (r) + return r; + + INIT_COMPLETION(radio->busy); + + /* wait for the POWER_ENB IRQ */ + r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); + if (!r) + return -ETIMEDOUT; + + radio->tx_frequency = freq; + dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %d\n", r); + + return 0; +} + +static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq) +{ + struct wl1273_core *core = radio->core; + int r, f; + + if (freq < radio->rangelow) { + dev_err(radio->dev, + "Frequency out of range: %d < %d\n", freq, + radio->rangelow); + r = -ERANGE; + goto err; + } + + if (freq > radio->rangehigh) { + dev_err(radio->dev, + "Frequency out of range: %d > %d\n", freq, + radio->rangehigh); + r = -ERANGE; + goto err; + } + + dev_dbg(radio->dev, "%s: %dkHz\n", __func__, freq); + + core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); + + if (radio->band == WL1273_BAND_JAPAN) + f = (freq - WL1273_BAND_JAPAN_LOW) / 50; + else + f = (freq - WL1273_BAND_OTHER_LOW) / 50; + + r = core->write(core, WL1273_FREQ_SET, f); + if (r) { + dev_err(radio->dev, "FREQ_SET fails\n"); + goto err; + } + + r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET); + if (r) { + dev_err(radio->dev, "TUNER_MODE_SET fails\n"); + goto err; + } + + INIT_COMPLETION(radio->busy); + + r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); + if (!r) { + dev_err(radio->dev, "%s: TIMEOUT\n", __func__); + return -ETIMEDOUT; + } + + radio->rd_index = 0; + radio->wr_index = 0; + radio->rx_frequency = freq; + return 0; +err: + return r; +} + +static int wl1273_fm_get_freq(struct wl1273_device *radio) +{ + struct wl1273_core *core = radio->core; + unsigned int freq; + u16 f; + int r; + + if (core->mode == WL1273_MODE_RX) { + r = core->read(core, WL1273_FREQ_SET, &f); + if (r) + return r; + + dev_dbg(radio->dev, "Freq get: 0x%04x\n", f); + if (radio->band == WL1273_BAND_JAPAN) + freq = WL1273_BAND_JAPAN_LOW + 50 * f; + else + freq = WL1273_BAND_OTHER_LOW + 50 * f; + } else { + r = core->read(core, WL1273_CHANL_SET, &f); + if (r) + return r; + + freq = f * 10; + } + + return freq; +} + +/** + * wl1273_fm_upload_firmware_patch() - Upload the firmware. + * @radio: A pointer to the device struct. + * + * The firmware file consists of arrays of bytes where the first byte + * gives the array length. The first byte in the file gives the + * number of these arrays. + */ +static int wl1273_fm_upload_firmware_patch(struct wl1273_device *radio) +{ + struct wl1273_core *core = radio->core; + unsigned int packet_num; + const struct firmware *fw_p; + const char *fw_name = "radio-wl1273-fw.bin"; + struct device *dev = radio->dev; + __u8 *ptr; + int r; + + dev_dbg(dev, "%s:\n", __func__); + + /* + * Uploading the firmware patch is not always necessary, + * so we only print an info message. + */ + if (request_firmware(&fw_p, fw_name, dev)) { + dev_info(dev, "%s - %s not found\n", __func__, fw_name); + + return 0; + } + + ptr = (__u8 *) fw_p->data; + packet_num = ptr[0]; + dev_dbg(dev, "%s: packets: %d\n", __func__, packet_num); + + r = wl1273_fm_write_fw(core, ptr + 1, packet_num); + if (r) { + dev_err(dev, "FW upload error: %d\n", r); + goto out; + } + + /* ignore possible error here */ + core->write(core, WL1273_RESET, 0); + + dev_dbg(dev, "%s - download OK, r: %d\n", __func__, r); +out: + release_firmware(fw_p); + return r; +} + +static int wl1273_fm_stop(struct wl1273_device *radio) +{ + struct wl1273_core *core = radio->core; + + if (core->mode == WL1273_MODE_RX) { + int r = core->write(core, WL1273_POWER_SET, + WL1273_POWER_SET_OFF); + if (r) + dev_err(radio->dev, "%s: POWER_SET fails: %d\n", + __func__, r); + } else if (core->mode == WL1273_MODE_TX) { + int r = core->write(core, WL1273_PUPD_SET, + WL1273_PUPD_SET_OFF); + if (r) + dev_err(radio->dev, + "%s: PUPD_SET fails: %d\n", __func__, r); + } + + if (core->pdata->disable) { + core->pdata->disable(); + dev_dbg(radio->dev, "Back to reset\n"); + } + + return 0; +} + +static int wl1273_fm_start(struct wl1273_device *radio, int new_mode) +{ + struct wl1273_core *core = radio->core; + struct wl1273_fm_platform_data *pdata = core->pdata; + struct device *dev = radio->dev; + int r = -EINVAL; + + if (pdata->enable && core->mode == WL1273_MODE_OFF) { + dev_dbg(radio->dev, "Out of reset\n"); + + pdata->enable(); + msleep(250); + } + + if (new_mode == WL1273_MODE_RX) { + u16 val = WL1273_POWER_SET_FM; + + if (radio->rds_on) + val |= WL1273_POWER_SET_RDS; + + /* If this fails try again */ + r = core->write(core, WL1273_POWER_SET, val); + if (r) { + msleep(100); + + r = core->write(core, WL1273_POWER_SET, val); + if (r) { + dev_err(dev, "%s: POWER_SET fails\n", __func__); + goto fail; + } + } + + /* rds buffer configuration */ + radio->wr_index = 0; + radio->rd_index = 0; + + } else if (new_mode == WL1273_MODE_TX) { + /* If this fails try again once */ + r = core->write(core, WL1273_PUPD_SET, WL1273_PUPD_SET_ON); + if (r) { + msleep(100); + r = core->write(core, WL1273_PUPD_SET, + WL1273_PUPD_SET_ON); + if (r) { + dev_err(dev, "%s: PUPD_SET fails\n", __func__); + goto fail; + } + } + + if (radio->rds_on) + r = core->write(core, WL1273_RDS_DATA_ENB, 1); + else + r = core->write(core, WL1273_RDS_DATA_ENB, 0); + } else { + dev_warn(dev, "%s: Illegal mode.\n", __func__); + } + + if (core->mode == WL1273_MODE_OFF) { + r = wl1273_fm_upload_firmware_patch(radio); + if (r) + dev_warn(dev, "Firmware upload failed.\n"); + + /* + * Sometimes the chip is in a wrong power state at this point. + * So we set the power once again. + */ + if (new_mode == WL1273_MODE_RX) { + u16 val = WL1273_POWER_SET_FM; + + if (radio->rds_on) + val |= WL1273_POWER_SET_RDS; + + r = core->write(core, WL1273_POWER_SET, val); + if (r) { + dev_err(dev, "%s: POWER_SET fails\n", __func__); + goto fail; + } + } else if (new_mode == WL1273_MODE_TX) { + r = core->write(core, WL1273_PUPD_SET, + WL1273_PUPD_SET_ON); + if (r) { + dev_err(dev, "%s: PUPD_SET fails\n", __func__); + goto fail; + } + } + } + + return 0; +fail: + if (pdata->disable) + pdata->disable(); + + dev_dbg(dev, "%s: return: %d\n", __func__, r); + return r; +} + +static int wl1273_fm_suspend(struct wl1273_device *radio) +{ + struct wl1273_core *core = radio->core; + int r = 0; + + /* Cannot go from OFF to SUSPENDED */ + if (core->mode == WL1273_MODE_RX) + r = core->write(core, WL1273_POWER_SET, + WL1273_POWER_SET_RETENTION); + else if (core->mode == WL1273_MODE_TX) + r = core->write(core, WL1273_PUPD_SET, + WL1273_PUPD_SET_RETENTION); + else + r = -EINVAL; + + if (r) { + dev_err(radio->dev, "%s: POWER_SET fails: %d\n", __func__, r); + goto out; + } + +out: + return r; +} + +static int wl1273_fm_set_mode(struct wl1273_device *radio, int mode) +{ + struct wl1273_core *core = radio->core; + struct device *dev = radio->dev; + int old_mode; + int r; + + dev_dbg(dev, "%s\n", __func__); + dev_dbg(dev, "Forbidden modes: 0x%02x\n", radio->forbidden); + + old_mode = core->mode; + if (mode & radio->forbidden) { + r = -EPERM; + goto out; + } + + switch (mode) { + case WL1273_MODE_RX: + case WL1273_MODE_TX: + r = wl1273_fm_start(radio, mode); + if (r) { + dev_err(dev, "%s: Cannot start.\n", __func__); + wl1273_fm_stop(radio); + goto out; + } + + core->mode = mode; + r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); + if (r) { + dev_err(dev, "INT_MASK_SET fails.\n"); + goto out; + } + + /* remember previous settings */ + if (mode == WL1273_MODE_RX) { + r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); + if (r) { + dev_err(dev, "set freq fails: %d.\n", r); + goto out; + } + + r = core->set_volume(core, core->volume); + if (r) { + dev_err(dev, "set volume fails: %d.\n", r); + goto out; + } + + dev_dbg(dev, "%s: Set vol: %d.\n", __func__, + core->volume); + } else { + r = wl1273_fm_set_tx_freq(radio, radio->tx_frequency); + if (r) { + dev_err(dev, "set freq fails: %d.\n", r); + goto out; + } + } + + dev_dbg(radio->dev, "%s: Set audio mode.\n", __func__); + + r = core->set_audio(core, core->audio_mode); + if (r) + dev_err(dev, "Cannot set audio mode.\n"); + break; + + case WL1273_MODE_OFF: + r = wl1273_fm_stop(radio); + if (r) + dev_err(dev, "%s: Off fails: %d\n", __func__, r); + else + core->mode = WL1273_MODE_OFF; + + break; + + case WL1273_MODE_SUSPENDED: + r = wl1273_fm_suspend(radio); + if (r) + dev_err(dev, "%s: Suspend fails: %d\n", __func__, r); + else + core->mode = WL1273_MODE_SUSPENDED; + + break; + + default: + dev_err(dev, "%s: Unknown mode: %d\n", __func__, mode); + r = -EINVAL; + break; + } +out: + if (r) + core->mode = old_mode; + + return r; +} + +static int wl1273_fm_set_seek(struct wl1273_device *radio, + unsigned int wrap_around, + unsigned int seek_upward, + int level) +{ + struct wl1273_core *core = radio->core; + int r = 0; + unsigned int dir = (seek_upward == 0) ? 0 : 1; + unsigned int f; + + f = radio->rx_frequency; + dev_dbg(radio->dev, "rx_frequency: %d\n", f); + + if (dir && f + radio->spacing <= radio->rangehigh) + r = wl1273_fm_set_rx_freq(radio, f + radio->spacing); + else if (dir && wrap_around) + r = wl1273_fm_set_rx_freq(radio, radio->rangelow); + else if (f - radio->spacing >= radio->rangelow) + r = wl1273_fm_set_rx_freq(radio, f - radio->spacing); + else if (wrap_around) + r = wl1273_fm_set_rx_freq(radio, radio->rangehigh); + + if (r) + goto out; + + if (level < SCHAR_MIN || level > SCHAR_MAX) + return -EINVAL; + + INIT_COMPLETION(radio->busy); + dev_dbg(radio->dev, "%s: BUSY\n", __func__); + + r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); + if (r) + goto out; + + dev_dbg(radio->dev, "%s\n", __func__); + + r = core->write(core, WL1273_SEARCH_LVL_SET, level); + if (r) + goto out; + + r = core->write(core, WL1273_SEARCH_DIR_SET, dir); + if (r) + goto out; + + r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); + if (r) + goto out; + + wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); + if (!(radio->irq_received & WL1273_BL_EVENT)) + goto out; + + radio->irq_received &= ~WL1273_BL_EVENT; + + if (!wrap_around) + goto out; + + /* Wrap around */ + dev_dbg(radio->dev, "Wrap around in HW seek.\n"); + + if (seek_upward) + f = radio->rangelow; + else + f = radio->rangehigh; + + r = wl1273_fm_set_rx_freq(radio, f); + if (r) + goto out; + + INIT_COMPLETION(radio->busy); + dev_dbg(radio->dev, "%s: BUSY\n", __func__); + + r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); + if (r) + goto out; + + wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); +out: + dev_dbg(radio->dev, "%s: Err: %d\n", __func__, r); + return r; +} + +/** + * wl1273_fm_get_tx_ctune() - Get the TX tuning capacitor value. + * @radio: A pointer to the device struct. + */ +static unsigned int wl1273_fm_get_tx_ctune(struct wl1273_device *radio) +{ + struct wl1273_core *core = radio->core; + struct device *dev = radio->dev; + u16 val; + int r; + + if (core->mode == WL1273_MODE_OFF || + core->mode == WL1273_MODE_SUSPENDED) + return -EPERM; + + r = core->read(core, WL1273_READ_FMANT_TUNE_VALUE, &val); + if (r) { + dev_err(dev, "%s: read error: %d\n", __func__, r); + goto out; + } + +out: + return val; +} + +/** + * wl1273_fm_set_preemphasis() - Set the TX pre-emphasis value. + * @radio: A pointer to the device struct. + * @preemphasis: The new pre-amphasis value. + * + * Possible pre-emphasis values are: V4L2_PREEMPHASIS_DISABLED, + * V4L2_PREEMPHASIS_50_uS and V4L2_PREEMPHASIS_75_uS. + */ +static int wl1273_fm_set_preemphasis(struct wl1273_device *radio, + unsigned int preemphasis) +{ + struct wl1273_core *core = radio->core; + int r; + u16 em; + + if (core->mode == WL1273_MODE_OFF || + core->mode == WL1273_MODE_SUSPENDED) + return -EPERM; + + mutex_lock(&core->lock); + + switch (preemphasis) { + case V4L2_PREEMPHASIS_DISABLED: + em = 1; + break; + case V4L2_PREEMPHASIS_50_uS: + em = 0; + break; + case V4L2_PREEMPHASIS_75_uS: + em = 2; + break; + default: + r = -EINVAL; + goto out; + } + + r = core->write(core, WL1273_PREMPH_SET, em); + if (r) + goto out; + + radio->preemphasis = preemphasis; + +out: + mutex_unlock(&core->lock); + return r; +} + +static int wl1273_fm_rds_on(struct wl1273_device *radio) +{ + struct wl1273_core *core = radio->core; + int r; + + dev_dbg(radio->dev, "%s\n", __func__); + if (radio->rds_on) + return 0; + + r = core->write(core, WL1273_POWER_SET, + WL1273_POWER_SET_FM | WL1273_POWER_SET_RDS); + if (r) + goto out; + + r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); + if (r) + dev_err(radio->dev, "set freq fails: %d.\n", r); +out: + return r; +} + +static int wl1273_fm_rds_off(struct wl1273_device *radio) +{ + struct wl1273_core *core = radio->core; + int r; + + if (!radio->rds_on) + return 0; + + radio->irq_flags &= ~WL1273_RDS_EVENT; + + r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); + if (r) + goto out; + + /* Service pending read */ + wake_up_interruptible(&radio->read_queue); + + dev_dbg(radio->dev, "%s\n", __func__); + + r = core->write(core, WL1273_POWER_SET, WL1273_POWER_SET_FM); + if (r) + goto out; + + r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); + if (r) + dev_err(radio->dev, "set freq fails: %d.\n", r); +out: + dev_dbg(radio->dev, "%s: exiting...\n", __func__); + + return r; +} + +static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode) +{ + int r = 0; + struct wl1273_core *core = radio->core; + + if (core->mode == WL1273_MODE_OFF || + core->mode == WL1273_MODE_SUSPENDED) + return -EPERM; + + if (new_mode == WL1273_RDS_RESET) { + r = core->write(core, WL1273_RDS_CNTRL_SET, 1); + return r; + } + + if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_OFF) { + r = core->write(core, WL1273_RDS_DATA_ENB, 0); + } else if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_ON) { + r = core->write(core, WL1273_RDS_DATA_ENB, 1); + } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_OFF) { + r = wl1273_fm_rds_off(radio); + } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_ON) { + r = wl1273_fm_rds_on(radio); + } else { + dev_err(radio->dev, "%s: Unknown mode: %d\n", + __func__, new_mode); + r = -EINVAL; + } + + if (!r) + radio->rds_on = (new_mode == WL1273_RDS_ON) ? true : false; + + return r; +} + +static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + u16 val; + int r; + + dev_dbg(radio->dev, "%s\n", __func__); + + if (core->mode != WL1273_MODE_TX) + return count; + + if (radio->rds_users == 0) { + dev_warn(radio->dev, "%s: RDS not on.\n", __func__); + return 0; + } + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + /* + * Multiple processes can open the device, but only + * one gets to write to it. + */ + if (radio->owner && radio->owner != file) { + r = -EBUSY; + goto out; + } + radio->owner = file; + + /* Manual Mode */ + if (count > 255) + val = 255; + else + val = count; + + core->write(core, WL1273_RDS_CONFIG_DATA_SET, val); + + if (copy_from_user(radio->write_buf + 1, buf, val)) { + r = -EFAULT; + goto out; + } + + dev_dbg(radio->dev, "Count: %d\n", val); + dev_dbg(radio->dev, "From user: \"%s\"\n", radio->write_buf); + + radio->write_buf[0] = WL1273_RDS_DATA_SET; + core->write_data(core, radio->write_buf, val + 1); + + r = val; +out: + mutex_unlock(&core->lock); + + return r; +} + +static unsigned int wl1273_fm_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + + if (radio->owner && radio->owner != file) + return -EBUSY; + + radio->owner = file; + + if (core->mode == WL1273_MODE_RX) { + poll_wait(file, &radio->read_queue, pts); + + if (radio->rd_index != radio->wr_index) + return POLLIN | POLLRDNORM; + + } else if (core->mode == WL1273_MODE_TX) { + return POLLOUT | POLLWRNORM; + } + + return 0; +} + +static int wl1273_fm_fops_open(struct file *file) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + int r = 0; + + dev_dbg(radio->dev, "%s\n", __func__); + + if (core->mode == WL1273_MODE_RX && radio->rds_on && + !radio->rds_users) { + dev_dbg(radio->dev, "%s: Mode: %d\n", __func__, core->mode); + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + radio->irq_flags |= WL1273_RDS_EVENT; + + r = core->write(core, WL1273_INT_MASK_SET, + radio->irq_flags); + if (r) { + mutex_unlock(&core->lock); + goto out; + } + + radio->rds_users++; + + mutex_unlock(&core->lock); + } +out: + return r; +} + +static int wl1273_fm_fops_release(struct file *file) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + int r = 0; + + dev_dbg(radio->dev, "%s\n", __func__); + + if (radio->rds_users > 0) { + radio->rds_users--; + if (radio->rds_users == 0) { + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + radio->irq_flags &= ~WL1273_RDS_EVENT; + + if (core->mode == WL1273_MODE_RX) { + r = core->write(core, + WL1273_INT_MASK_SET, + radio->irq_flags); + if (r) { + mutex_unlock(&core->lock); + goto out; + } + } + mutex_unlock(&core->lock); + } + } + + if (file == radio->owner) + radio->owner = NULL; +out: + return r; +} + +static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int r = 0; + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + unsigned int block_count = 0; + u16 val; + + dev_dbg(radio->dev, "%s\n", __func__); + + if (core->mode != WL1273_MODE_RX) + return 0; + + if (radio->rds_users == 0) { + dev_warn(radio->dev, "%s: RDS not on.\n", __func__); + return 0; + } + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + /* + * Multiple processes can open the device, but only + * one at a time gets read access. + */ + if (radio->owner && radio->owner != file) { + r = -EBUSY; + goto out; + } + radio->owner = file; + + r = core->read(core, WL1273_RDS_SYNC_GET, &val); + if (r) { + dev_err(radio->dev, "%s: Get RDS_SYNC fails.\n", __func__); + goto out; + } else if (val == 0) { + dev_info(radio->dev, "RDS_SYNC: Not synchronized\n"); + r = -ENODATA; + goto out; + } + + /* block if no new data available */ + while (radio->wr_index == radio->rd_index) { + if (file->f_flags & O_NONBLOCK) { + r = -EWOULDBLOCK; + goto out; + } + + dev_dbg(radio->dev, "%s: Wait for RDS data.\n", __func__); + if (wait_event_interruptible(radio->read_queue, + radio->wr_index != + radio->rd_index) < 0) { + r = -EINTR; + goto out; + } + } + + /* calculate block count from byte count */ + count /= RDS_BLOCK_SIZE; + + /* copy RDS blocks from the internal buffer and to user buffer */ + while (block_count < count) { + if (radio->rd_index == radio->wr_index) + break; + + /* always transfer complete RDS blocks */ + if (copy_to_user(buf, &radio->buffer[radio->rd_index], + RDS_BLOCK_SIZE)) + break; + + /* increment and wrap the read pointer */ + radio->rd_index += RDS_BLOCK_SIZE; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + + /* increment counters */ + block_count++; + buf += RDS_BLOCK_SIZE; + r += RDS_BLOCK_SIZE; + } + +out: + dev_dbg(radio->dev, "%s: exit\n", __func__); + mutex_unlock(&core->lock); + + return r; +} + +static const struct v4l2_file_operations wl1273_fops = { + .owner = THIS_MODULE, + .read = wl1273_fm_fops_read, + .write = wl1273_fm_fops_write, + .poll = wl1273_fm_fops_poll, + .unlocked_ioctl = video_ioctl2, + .open = wl1273_fm_fops_open, + .release = wl1273_fm_fops_release, +}; + +static int wl1273_fm_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + + dev_dbg(radio->dev, "%s\n", __func__); + + strlcpy(capability->driver, WL1273_FM_DRIVER_NAME, + sizeof(capability->driver)); + strlcpy(capability->card, "Texas Instruments Wl1273 FM Radio", + sizeof(capability->card)); + strlcpy(capability->bus_info, radio->bus_type, + sizeof(capability->bus_info)); + + capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | + V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_AUDIO | + V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR | + V4L2_CAP_RDS_OUTPUT; + + return 0; +} + +static int wl1273_fm_vidioc_g_input(struct file *file, void *priv, + unsigned int *i) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + + dev_dbg(radio->dev, "%s\n", __func__); + + *i = 0; + + return 0; +} + +static int wl1273_fm_vidioc_s_input(struct file *file, void *priv, + unsigned int i) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + + dev_dbg(radio->dev, "%s\n", __func__); + + if (i != 0) + return -EINVAL; + + return 0; +} + +/** + * wl1273_fm_set_tx_power() - Set the transmission power value. + * @core: A pointer to the device struct. + * @power: The new power value. + */ +static int wl1273_fm_set_tx_power(struct wl1273_device *radio, u16 power) +{ + struct wl1273_core *core = radio->core; + int r; + + if (core->mode == WL1273_MODE_OFF || + core->mode == WL1273_MODE_SUSPENDED) + return -EPERM; + + mutex_lock(&core->lock); + + /* Convert the dBuV value to chip presentation */ + r = core->write(core, WL1273_POWER_LEV_SET, 122 - power); + if (r) + goto out; + + radio->tx_power = power; + +out: + mutex_unlock(&core->lock); + return r; +} + +#define WL1273_SPACING_50kHz 1 +#define WL1273_SPACING_100kHz 2 +#define WL1273_SPACING_200kHz 4 + +static int wl1273_fm_tx_set_spacing(struct wl1273_device *radio, + unsigned int spacing) +{ + struct wl1273_core *core = radio->core; + int r; + + if (spacing == 0) { + r = core->write(core, WL1273_SCAN_SPACING_SET, + WL1273_SPACING_100kHz); + radio->spacing = 100; + } else if (spacing - 50000 < 25000) { + r = core->write(core, WL1273_SCAN_SPACING_SET, + WL1273_SPACING_50kHz); + radio->spacing = 50; + } else if (spacing - 100000 < 50000) { + r = core->write(core, WL1273_SCAN_SPACING_SET, + WL1273_SPACING_100kHz); + radio->spacing = 100; + } else { + r = core->write(core, WL1273_SCAN_SPACING_SET, + WL1273_SPACING_200kHz); + radio->spacing = 200; + } + + return r; +} + +static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct wl1273_device *radio = ctrl->priv; + struct wl1273_core *core = radio->core; + + dev_dbg(radio->dev, "%s\n", __func__); + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + switch (ctrl->id) { + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + ctrl->cur.val = wl1273_fm_get_tx_ctune(radio); + break; + + default: + dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n", + __func__, ctrl->id); + break; + } + + mutex_unlock(&core->lock); + + return 0; +} + +#define WL1273_MUTE_SOFT_ENABLE (1 << 0) +#define WL1273_MUTE_AC (1 << 1) +#define WL1273_MUTE_HARD_LEFT (1 << 2) +#define WL1273_MUTE_HARD_RIGHT (1 << 3) +#define WL1273_MUTE_SOFT_FORCE (1 << 4) + +static inline struct wl1273_device *to_radio(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct wl1273_device, ctrl_handler); +} + +static int wl1273_fm_vidioc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct wl1273_device *radio = to_radio(ctrl); + struct wl1273_core *core = radio->core; + int r = 0; + + dev_dbg(radio->dev, "%s\n", __func__); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + if (core->mode == WL1273_MODE_RX && ctrl->val) + r = core->write(core, + WL1273_MUTE_STATUS_SET, + WL1273_MUTE_HARD_LEFT | + WL1273_MUTE_HARD_RIGHT); + else if (core->mode == WL1273_MODE_RX) + r = core->write(core, + WL1273_MUTE_STATUS_SET, 0x0); + else if (core->mode == WL1273_MODE_TX && ctrl->val) + r = core->write(core, WL1273_MUTE, 1); + else if (core->mode == WL1273_MODE_TX) + r = core->write(core, WL1273_MUTE, 0); + + mutex_unlock(&core->lock); + break; + + case V4L2_CID_AUDIO_VOLUME: + if (ctrl->val == 0) + r = wl1273_fm_set_mode(radio, WL1273_MODE_OFF); + else + r = core->set_volume(core, core->volume); + break; + + case V4L2_CID_TUNE_PREEMPHASIS: + r = wl1273_fm_set_preemphasis(radio, ctrl->val); + break; + + case V4L2_CID_TUNE_POWER_LEVEL: + r = wl1273_fm_set_tx_power(radio, ctrl->val); + break; + + default: + dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n", + __func__, ctrl->id); + break; + } + + dev_dbg(radio->dev, "%s\n", __func__); + return r; +} + +static int wl1273_fm_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + + dev_dbg(radio->dev, "%s\n", __func__); + + if (audio->index > 1) + return -EINVAL; + + strlcpy(audio->name, "Radio", sizeof(audio->name)); + audio->capability = V4L2_AUDCAP_STEREO; + + return 0; +} + +static int wl1273_fm_vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + + dev_dbg(radio->dev, "%s\n", __func__); + + if (audio->index != 0) + return -EINVAL; + + return 0; +} + +#define WL1273_RDS_NOT_SYNCHRONIZED 0 +#define WL1273_RDS_SYNCHRONIZED 1 + +static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + u16 val; + int r; + + dev_dbg(radio->dev, "%s\n", __func__); + + if (tuner->index > 0) + return -EINVAL; + + strlcpy(tuner->name, WL1273_FM_DRIVER_NAME, sizeof(tuner->name)); + tuner->type = V4L2_TUNER_RADIO; + + tuner->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW); + tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH); + + tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO; + + if (radio->stereo) + tuner->audmode = V4L2_TUNER_MODE_STEREO; + else + tuner->audmode = V4L2_TUNER_MODE_MONO; + + if (core->mode != WL1273_MODE_RX) + return 0; + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + r = core->read(core, WL1273_STEREO_GET, &val); + if (r) + goto out; + + if (val == 1) + tuner->rxsubchans = V4L2_TUNER_SUB_STEREO; + else + tuner->rxsubchans = V4L2_TUNER_SUB_MONO; + + r = core->read(core, WL1273_RSSI_LVL_GET, &val); + if (r) + goto out; + + tuner->signal = (s16) val; + dev_dbg(radio->dev, "Signal: %d\n", tuner->signal); + + tuner->afc = 0; + + r = core->read(core, WL1273_RDS_SYNC_GET, &val); + if (r) + goto out; + + if (val == WL1273_RDS_SYNCHRONIZED) + tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; +out: + mutex_unlock(&core->lock); + + return r; +} + +static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + int r = 0; + + dev_dbg(radio->dev, "%s\n", __func__); + dev_dbg(radio->dev, "tuner->index: %d\n", tuner->index); + dev_dbg(radio->dev, "tuner->name: %s\n", tuner->name); + dev_dbg(radio->dev, "tuner->capability: 0x%04x\n", tuner->capability); + dev_dbg(radio->dev, "tuner->rxsubchans: 0x%04x\n", tuner->rxsubchans); + dev_dbg(radio->dev, "tuner->rangelow: %d\n", tuner->rangelow); + dev_dbg(radio->dev, "tuner->rangehigh: %d\n", tuner->rangehigh); + + if (tuner->index > 0) + return -EINVAL; + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + r = wl1273_fm_set_mode(radio, WL1273_MODE_RX); + if (r) + goto out; + + if (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) + r = wl1273_fm_set_rds(radio, WL1273_RDS_ON); + else + r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF); + + if (r) + dev_warn(radio->dev, "%s: RDS fails: %d\n", __func__, r); + + if (tuner->audmode == V4L2_TUNER_MODE_MONO) { + r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO); + if (r < 0) { + dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", + __func__, r); + goto out; + } + radio->stereo = false; + } else if (tuner->audmode == V4L2_TUNER_MODE_STEREO) { + r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO); + if (r < 0) { + dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", + __func__, r); + goto out; + } + radio->stereo = true; + } else { + dev_err(radio->dev, "%s: tuner->audmode: %d\n", + __func__, tuner->audmode); + r = -EINVAL; + goto out; + } + +out: + mutex_unlock(&core->lock); + + return r; +} + +static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + + dev_dbg(radio->dev, "%s\n", __func__); + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + freq->type = V4L2_TUNER_RADIO; + freq->frequency = WL1273_FREQ(wl1273_fm_get_freq(radio)); + + mutex_unlock(&core->lock); + + return 0; +} + +static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + int r; + + dev_dbg(radio->dev, "%s: %d\n", __func__, freq->frequency); + + if (freq->type != V4L2_TUNER_RADIO) { + dev_dbg(radio->dev, + "freq->type != V4L2_TUNER_RADIO: %d\n", freq->type); + return -EINVAL; + } + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + if (core->mode == WL1273_MODE_RX) { + dev_dbg(radio->dev, "freq: %d\n", freq->frequency); + + r = wl1273_fm_set_rx_freq(radio, + WL1273_INV_FREQ(freq->frequency)); + if (r) + dev_warn(radio->dev, WL1273_FM_DRIVER_NAME + ": set frequency failed with %d\n", r); + } else { + r = wl1273_fm_set_tx_freq(radio, + WL1273_INV_FREQ(freq->frequency)); + if (r) + dev_warn(radio->dev, WL1273_FM_DRIVER_NAME + ": set frequency failed with %d\n", r); + } + + mutex_unlock(&core->lock); + + dev_dbg(radio->dev, "wl1273_vidioc_s_frequency: DONE\n"); + return r; +} + +#define WL1273_DEFAULT_SEEK_LEVEL 7 + +static int wl1273_fm_vidioc_s_hw_freq_seek(struct file *file, void *priv, + struct v4l2_hw_freq_seek *seek) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + int r; + + dev_dbg(radio->dev, "%s\n", __func__); + + if (seek->tuner != 0 || seek->type != V4L2_TUNER_RADIO) + return -EINVAL; + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + r = wl1273_fm_set_mode(radio, WL1273_MODE_RX); + if (r) + goto out; + + r = wl1273_fm_tx_set_spacing(radio, seek->spacing); + if (r) + dev_warn(radio->dev, "HW seek failed: %d\n", r); + + r = wl1273_fm_set_seek(radio, seek->wrap_around, seek->seek_upward, + WL1273_DEFAULT_SEEK_LEVEL); + if (r) + dev_warn(radio->dev, "HW seek failed: %d\n", r); + +out: + mutex_unlock(&core->lock); + return r; +} + +static int wl1273_fm_vidioc_s_modulator(struct file *file, void *priv, + struct v4l2_modulator *modulator) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + int r = 0; + + dev_dbg(radio->dev, "%s\n", __func__); + + if (modulator->index > 0) + return -EINVAL; + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + r = wl1273_fm_set_mode(radio, WL1273_MODE_TX); + if (r) + goto out; + + if (modulator->txsubchans & V4L2_TUNER_SUB_RDS) + r = wl1273_fm_set_rds(radio, WL1273_RDS_ON); + else + r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF); + + if (modulator->txsubchans & V4L2_TUNER_SUB_MONO) + r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO); + else + r = core->write(core, WL1273_MONO_SET, + WL1273_RX_STEREO); + if (r < 0) + dev_warn(radio->dev, WL1273_FM_DRIVER_NAME + "MONO_SET fails: %d\n", r); +out: + mutex_unlock(&core->lock); + + return r; +} + +static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv, + struct v4l2_modulator *modulator) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + u16 val; + int r; + + dev_dbg(radio->dev, "%s\n", __func__); + + strlcpy(modulator->name, WL1273_FM_DRIVER_NAME, + sizeof(modulator->name)); + + modulator->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW); + modulator->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH); + + modulator->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO; + + if (core->mode != WL1273_MODE_TX) + return 0; + + if (mutex_lock_interruptible(&core->lock)) + return -EINTR; + + r = core->read(core, WL1273_MONO_SET, &val); + if (r) + goto out; + + if (val == WL1273_TX_STEREO) + modulator->txsubchans = V4L2_TUNER_SUB_STEREO; + else + modulator->txsubchans = V4L2_TUNER_SUB_MONO; + + if (radio->rds_on) + modulator->txsubchans |= V4L2_TUNER_SUB_RDS; +out: + mutex_unlock(&core->lock); + + return 0; +} + +static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) +{ + struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; + struct device *dev = radio->dev; + u16 val; + int r; + + dev_info(dev, DRIVER_DESC); + + if (core->mode == WL1273_MODE_OFF) { + dev_info(dev, "Mode: Off\n"); + return 0; + } + + if (core->mode == WL1273_MODE_SUSPENDED) { + dev_info(dev, "Mode: Suspended\n"); + return 0; + } + + r = core->read(core, WL1273_ASIC_ID_GET, &val); + if (r) + dev_err(dev, "%s: Get ASIC_ID fails.\n", __func__); + else + dev_info(dev, "ASIC_ID: 0x%04x\n", val); + + r = core->read(core, WL1273_ASIC_VER_GET, &val); + if (r) + dev_err(dev, "%s: Get ASIC_VER fails.\n", __func__); + else + dev_info(dev, "ASIC Version: 0x%04x\n", val); + + r = core->read(core, WL1273_FIRM_VER_GET, &val); + if (r) + dev_err(dev, "%s: Get FIRM_VER fails.\n", __func__); + else + dev_info(dev, "FW version: %d(0x%04x)\n", val, val); + + r = core->read(core, WL1273_BAND_SET, &val); + if (r) + dev_err(dev, "%s: Get BAND fails.\n", __func__); + else + dev_info(dev, "BAND: %d\n", val); + + if (core->mode == WL1273_MODE_TX) { + r = core->read(core, WL1273_PUPD_SET, &val); + if (r) + dev_err(dev, "%s: Get PUPD fails.\n", __func__); + else + dev_info(dev, "PUPD: 0x%04x\n", val); + + r = core->read(core, WL1273_CHANL_SET, &val); + if (r) + dev_err(dev, "%s: Get CHANL fails.\n", __func__); + else + dev_info(dev, "Tx frequency: %dkHz\n", val*10); + } else if (core->mode == WL1273_MODE_RX) { + int bf = radio->rangelow; + + r = core->read(core, WL1273_FREQ_SET, &val); + if (r) + dev_err(dev, "%s: Get FREQ fails.\n", __func__); + else + dev_info(dev, "RX Frequency: %dkHz\n", bf + val*50); + + r = core->read(core, WL1273_MOST_MODE_SET, &val); + if (r) + dev_err(dev, "%s: Get MOST_MODE fails.\n", + __func__); + else if (val == 0) + dev_info(dev, "MOST_MODE: Stereo according to blend\n"); + else if (val == 1) + dev_info(dev, "MOST_MODE: Force mono output\n"); + else + dev_info(dev, "MOST_MODE: Unexpected value: %d\n", val); + + r = core->read(core, WL1273_MOST_BLEND_SET, &val); + if (r) + dev_err(dev, "%s: Get MOST_BLEND fails.\n", __func__); + else if (val == 0) + dev_info(dev, + "MOST_BLEND: Switched blend & hysteresis.\n"); + else if (val == 1) + dev_info(dev, "MOST_BLEND: Soft blend.\n"); + else + dev_info(dev, "MOST_BLEND: Unexpected val: %d\n", val); + + r = core->read(core, WL1273_STEREO_GET, &val); + if (r) + dev_err(dev, "%s: Get STEREO fails.\n", __func__); + else if (val == 0) + dev_info(dev, "STEREO: Not detected\n"); + else if (val == 1) + dev_info(dev, "STEREO: Detected\n"); + else + dev_info(dev, "STEREO: Unexpected value: %d\n", val); + + r = core->read(core, WL1273_RSSI_LVL_GET, &val); + if (r) + dev_err(dev, "%s: Get RSSI_LVL fails.\n", __func__); + else + dev_info(dev, "RX signal strength: %d\n", (s16) val); + + r = core->read(core, WL1273_POWER_SET, &val); + if (r) + dev_err(dev, "%s: Get POWER fails.\n", __func__); + else + dev_info(dev, "POWER: 0x%04x\n", val); + + r = core->read(core, WL1273_INT_MASK_SET, &val); + if (r) + dev_err(dev, "%s: Get INT_MASK fails.\n", __func__); + else + dev_info(dev, "INT_MASK: 0x%04x\n", val); + + r = core->read(core, WL1273_RDS_SYNC_GET, &val); + if (r) + dev_err(dev, "%s: Get RDS_SYNC fails.\n", + __func__); + else if (val == 0) + dev_info(dev, "RDS_SYNC: Not synchronized\n"); + + else if (val == 1) + dev_info(dev, "RDS_SYNC: Synchronized\n"); + else + dev_info(dev, "RDS_SYNC: Unexpected value: %d\n", val); + + r = core->read(core, WL1273_I2S_MODE_CONFIG_SET, &val); + if (r) + dev_err(dev, "%s: Get I2S_MODE_CONFIG fails.\n", + __func__); + else + dev_info(dev, "I2S_MODE_CONFIG: 0x%04x\n", val); + + r = core->read(core, WL1273_VOLUME_SET, &val); + if (r) + dev_err(dev, "%s: Get VOLUME fails.\n", __func__); + else + dev_info(dev, "VOLUME: 0x%04x\n", val); + } + + return 0; +} + +static void wl1273_vdev_release(struct video_device *dev) +{ +} + +static const struct v4l2_ctrl_ops wl1273_ctrl_ops = { + .s_ctrl = wl1273_fm_vidioc_s_ctrl, + .g_volatile_ctrl = wl1273_fm_g_volatile_ctrl, +}; + +static const struct v4l2_ioctl_ops wl1273_ioctl_ops = { + .vidioc_querycap = wl1273_fm_vidioc_querycap, + .vidioc_g_input = wl1273_fm_vidioc_g_input, + .vidioc_s_input = wl1273_fm_vidioc_s_input, + .vidioc_g_audio = wl1273_fm_vidioc_g_audio, + .vidioc_s_audio = wl1273_fm_vidioc_s_audio, + .vidioc_g_tuner = wl1273_fm_vidioc_g_tuner, + .vidioc_s_tuner = wl1273_fm_vidioc_s_tuner, + .vidioc_g_frequency = wl1273_fm_vidioc_g_frequency, + .vidioc_s_frequency = wl1273_fm_vidioc_s_frequency, + .vidioc_s_hw_freq_seek = wl1273_fm_vidioc_s_hw_freq_seek, + .vidioc_g_modulator = wl1273_fm_vidioc_g_modulator, + .vidioc_s_modulator = wl1273_fm_vidioc_s_modulator, + .vidioc_log_status = wl1273_fm_vidioc_log_status, +}; + +static struct video_device wl1273_viddev_template = { + .fops = &wl1273_fops, + .ioctl_ops = &wl1273_ioctl_ops, + .name = WL1273_FM_DRIVER_NAME, + .release = wl1273_vdev_release, +}; + +static int wl1273_fm_radio_remove(struct platform_device *pdev) +{ + struct wl1273_device *radio = platform_get_drvdata(pdev); + struct wl1273_core *core = radio->core; + + dev_info(&pdev->dev, "%s.\n", __func__); + + free_irq(core->client->irq, radio); + core->pdata->free_resources(); + + v4l2_ctrl_handler_free(&radio->ctrl_handler); + video_unregister_device(&radio->videodev); + v4l2_device_unregister(&radio->v4l2dev); + kfree(radio->buffer); + kfree(radio->write_buf); + kfree(radio); + + return 0; +} + +static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev) +{ + struct wl1273_core **core = pdev->dev.platform_data; + struct wl1273_device *radio; + struct v4l2_ctrl *ctrl; + int r = 0; + + pr_debug("%s\n", __func__); + + if (!core) { + dev_err(&pdev->dev, "No platform data.\n"); + r = -EINVAL; + goto pdata_err; + } + + radio = kzalloc(sizeof(*radio), GFP_KERNEL); + if (!radio) { + r = -ENOMEM; + goto pdata_err; + } + + /* RDS buffer allocation */ + radio->buf_size = rds_buf * RDS_BLOCK_SIZE; + radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); + if (!radio->buffer) { + pr_err("Cannot allocate memory for RDS buffer.\n"); + r = -ENOMEM; + goto err_kmalloc; + } + + radio->core = *core; + radio->irq_flags = WL1273_IRQ_MASK; + radio->dev = &radio->core->client->dev; + radio->rds_on = false; + radio->core->mode = WL1273_MODE_OFF; + radio->tx_power = 118; + radio->core->audio_mode = WL1273_AUDIO_ANALOG; + radio->band = WL1273_BAND_OTHER; + radio->core->i2s_mode = WL1273_I2S_DEF_MODE; + radio->core->channel_number = 2; + radio->core->volume = WL1273_DEFAULT_VOLUME; + radio->rx_frequency = WL1273_BAND_OTHER_LOW; + radio->tx_frequency = WL1273_BAND_OTHER_HIGH; + radio->rangelow = WL1273_BAND_OTHER_LOW; + radio->rangehigh = WL1273_BAND_OTHER_HIGH; + radio->stereo = true; + radio->bus_type = "I2C"; + + if (radio->core->pdata->request_resources) { + r = radio->core->pdata->request_resources(radio->core->client); + if (r) { + dev_err(radio->dev, WL1273_FM_DRIVER_NAME + ": Cannot get platform data\n"); + goto err_resources; + } + + dev_dbg(radio->dev, "irq: %d\n", radio->core->client->irq); + + r = request_threaded_irq(radio->core->client->irq, NULL, + wl1273_fm_irq_thread_handler, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + "wl1273-fm", radio); + if (r < 0) { + dev_err(radio->dev, WL1273_FM_DRIVER_NAME + ": Unable to register IRQ handler: %d\n", r); + goto err_request_irq; + } + } else { + dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ" + " not configured"); + r = -EINVAL; + goto err_resources; + } + + init_completion(&radio->busy); + init_waitqueue_head(&radio->read_queue); + + radio->write_buf = kmalloc(256, GFP_KERNEL); + if (!radio->write_buf) { + r = -ENOMEM; + goto write_buf_err; + } + + radio->dev = &pdev->dev; + radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; + radio->rds_users = 0; + + r = v4l2_device_register(&pdev->dev, &radio->v4l2dev); + if (r) { + dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); + goto device_register_err; + } + + /* V4L2 configuration */ + memcpy(&radio->videodev, &wl1273_viddev_template, + sizeof(wl1273_viddev_template)); + + radio->videodev.v4l2_dev = &radio->v4l2dev; + + v4l2_ctrl_handler_init(&radio->ctrl_handler, 6); + + /* add in ascending ID order */ + v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, 0, WL1273_MAX_VOLUME, 1, + WL1273_DEFAULT_VOLUME); + + v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + + v4l2_ctrl_new_std_menu(&radio->ctrl_handler, &wl1273_ctrl_ops, + V4L2_CID_TUNE_PREEMPHASIS, + V4L2_PREEMPHASIS_75_uS, 0x03, + V4L2_PREEMPHASIS_50_uS); + + v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, + V4L2_CID_TUNE_POWER_LEVEL, 91, 122, 1, 118); + + ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, + V4L2_CID_TUNE_ANTENNA_CAPACITOR, + 0, 255, 1, 255); + if (ctrl) + ctrl->is_volatile = 1; + + if (radio->ctrl_handler.error) { + r = radio->ctrl_handler.error; + dev_err(&pdev->dev, "Ctrl handler error: %d\n", r); + goto handler_init_err; + } + + video_set_drvdata(&radio->videodev, radio); + platform_set_drvdata(pdev, radio); + + /* register video device */ + r = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); + if (r) { + dev_err(&pdev->dev, WL1273_FM_DRIVER_NAME + ": Could not register video device\n"); + goto handler_init_err; + } + + return 0; + +handler_init_err: + v4l2_ctrl_handler_free(&radio->ctrl_handler); + v4l2_device_unregister(&radio->v4l2dev); +device_register_err: + kfree(radio->write_buf); +write_buf_err: + free_irq(radio->core->client->irq, radio); +err_request_irq: + radio->core->pdata->free_resources(); +err_resources: + kfree(radio->buffer); +err_kmalloc: + kfree(radio); +pdata_err: + return r; +} + +MODULE_ALIAS("platform:wl1273_fm_radio"); + +static struct platform_driver wl1273_fm_radio_driver = { + .probe = wl1273_fm_radio_probe, + .remove = __devexit_p(wl1273_fm_radio_remove), + .driver = { + .name = "wl1273_fm_radio", + .owner = THIS_MODULE, + }, +}; + +static int __init wl1273_fm_module_init(void) +{ + pr_info("%s\n", __func__); + return platform_driver_register(&wl1273_fm_radio_driver); +} +module_init(wl1273_fm_module_init); + +static void __exit wl1273_fm_module_exit(void) +{ + platform_driver_unregister(&wl1273_fm_radio_driver); + pr_info(DRIVER_DESC ", Exiting.\n"); +} +module_exit(wl1273_fm_module_exit); + +MODULE_AUTHOR("Matti Aaltonen "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-zoltrix.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-zoltrix.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-zoltrix.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/radio-zoltrix.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,469 @@ +/* zoltrix radio plus driver for Linux radio support + * (c) 1998 C. van Schaik + * + * BUGS + * Due to the inconsistency in reading from the signal flags + * it is difficult to get an accurate tuned signal. + * + * It seems that the card is not linear to 0 volume. It cuts off + * at a low volume, and it is not possible (at least I have not found) + * to get fine volume control over the low volume range. + * + * Some code derived from code by Romolo Manfredini + * romolo@bicnet.it + * + * 1999-05-06 - (C. van Schaik) + * - Make signal strength and stereo scans + * kinder to cpu while in delay + * 1999-01-05 - (C. van Schaik) + * - Changed tuning to 1/160Mhz accuracy + * - Added stereo support + * (card defaults to stereo) + * (can explicitly force mono on the card) + * (can detect if station is in stereo) + * - Added unmute function + * - Reworked ioctl functions + * 2002-07-15 - Fix Stereo typo + * + * 2006-07-24 - Converted to V4L2 API + * by Mauro Carvalho Chehab + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* request_region */ +#include /* udelay, msleep */ +#include /* kernel radio structs */ +#include +#include /* for KERNEL_VERSION MACRO */ +#include /* outb, outb_p */ +#include +#include + +MODULE_AUTHOR("C.van Schaik"); +MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); +MODULE_LICENSE("GPL"); + +#ifndef CONFIG_RADIO_ZOLTRIX_PORT +#define CONFIG_RADIO_ZOLTRIX_PORT -1 +#endif + +static int io = CONFIG_RADIO_ZOLTRIX_PORT; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct zoltrix { + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + int curvol; + unsigned long curfreq; + int muted; + unsigned int stereo; + struct mutex lock; +}; + +static struct zoltrix zoltrix_card; + +static int zol_setvol(struct zoltrix *zol, int vol) +{ + zol->curvol = vol; + if (zol->muted) + return 0; + + mutex_lock(&zol->lock); + if (vol == 0) { + outb(0, zol->io); + outb(0, zol->io); + inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ + mutex_unlock(&zol->lock); + return 0; + } + + outb(zol->curvol-1, zol->io); + msleep(10); + inb(zol->io + 2); + mutex_unlock(&zol->lock); + return 0; +} + +static void zol_mute(struct zoltrix *zol) +{ + zol->muted = 1; + mutex_lock(&zol->lock); + outb(0, zol->io); + outb(0, zol->io); + inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ + mutex_unlock(&zol->lock); +} + +static void zol_unmute(struct zoltrix *zol) +{ + zol->muted = 0; + zol_setvol(zol, zol->curvol); +} + +static int zol_setfreq(struct zoltrix *zol, unsigned long freq) +{ + /* tunes the radio to the desired frequency */ + struct v4l2_device *v4l2_dev = &zol->v4l2_dev; + unsigned long long bitmask, f, m; + unsigned int stereo = zol->stereo; + int i; + + if (freq == 0) { + v4l2_warn(v4l2_dev, "cannot set a frequency of 0.\n"); + return -EINVAL; + } + + m = (freq / 160 - 8800) * 2; + f = (unsigned long long)m + 0x4d1c; + + bitmask = 0xc480402c10080000ull; + i = 45; + + mutex_lock(&zol->lock); + + zol->curfreq = freq; + + outb(0, zol->io); + outb(0, zol->io); + inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ + + outb(0x40, zol->io); + outb(0xc0, zol->io); + + bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31)); + while (i--) { + if ((bitmask & 0x8000000000000000ull) != 0) { + outb(0x80, zol->io); + udelay(50); + outb(0x00, zol->io); + udelay(50); + outb(0x80, zol->io); + udelay(50); + } else { + outb(0xc0, zol->io); + udelay(50); + outb(0x40, zol->io); + udelay(50); + outb(0xc0, zol->io); + udelay(50); + } + bitmask *= 2; + } + /* termination sequence */ + outb(0x80, zol->io); + outb(0xc0, zol->io); + outb(0x40, zol->io); + udelay(1000); + inb(zol->io + 2); + + udelay(1000); + + if (zol->muted) { + outb(0, zol->io); + outb(0, zol->io); + inb(zol->io + 3); + udelay(1000); + } + + mutex_unlock(&zol->lock); + + if (!zol->muted) + zol_setvol(zol, zol->curvol); + return 0; +} + +/* Get signal strength */ +static int zol_getsigstr(struct zoltrix *zol) +{ + int a, b; + + mutex_lock(&zol->lock); + outb(0x00, zol->io); /* This stuff I found to do nothing */ + outb(zol->curvol, zol->io); + msleep(20); + + a = inb(zol->io); + msleep(10); + b = inb(zol->io); + + mutex_unlock(&zol->lock); + + if (a != b) + return 0; + + /* I found this out by playing with a binary scanner on the card io */ + return a == 0xcf || a == 0xdf || a == 0xef; +} + +static int zol_is_stereo(struct zoltrix *zol) +{ + int x1, x2; + + mutex_lock(&zol->lock); + + outb(0x00, zol->io); + outb(zol->curvol, zol->io); + msleep(20); + + x1 = inb(zol->io); + msleep(10); + x2 = inb(zol->io); + + mutex_unlock(&zol->lock); + + return x1 == x2 && x1 == 0xcf; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); + strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct zoltrix *zol = video_drvdata(file); + + if (v->index > 0) + return -EINVAL; + + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = 88 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + if (zol_is_stereo(zol)) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal = 0xFFFF * zol_getsigstr(zol); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct zoltrix *zol = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + if (zol_setfreq(zol, f->frequency) != 0) + return -EINVAL; + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct zoltrix *zol = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = zol->curfreq; + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535); + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct zoltrix *zol = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = zol->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = zol->curvol * 4096; + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct zoltrix *zol = video_drvdata(file); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + zol_mute(zol); + else { + zol_unmute(zol); + zol_setvol(zol, zol->curvol); + } + return 0; + case V4L2_CID_AUDIO_VOLUME: + zol_setvol(zol, ctrl->value / 4096); + return 0; + } + zol->stereo = 1; + if (zol_setfreq(zol, zol->curfreq) != 0) + return -EINVAL; +#if 0 +/* FIXME: Implement stereo/mono switch on V4L2 */ + if (v->mode & VIDEO_SOUND_STEREO) { + zol->stereo = 1; + zol_setfreq(zol, zol->curfreq); + } + if (v->mode & VIDEO_SOUND_MONO) { + zol->stereo = 0; + zol_setfreq(zol, zol->curfreq); + } +#endif + return -EINVAL; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static const struct v4l2_file_operations zoltrix_fops = +{ + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; + +static int __init zoltrix_init(void) +{ + struct zoltrix *zol = &zoltrix_card; + struct v4l2_device *v4l2_dev = &zol->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name)); + zol->io = io; + if (zol->io == -1) { + v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n"); + return -EINVAL; + } + if (zol->io != 0x20c && zol->io != 0x30c) { + v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n"); + return -ENXIO; + } + + if (!request_region(zol->io, 2, "zoltrix")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io); + return -EBUSY; + } + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(zol->io, 2); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + mutex_init(&zol->lock); + + /* mute card - prevents noisy bootups */ + + /* this ensures that the volume is all the way down */ + + outb(0, zol->io); + outb(0, zol->io); + msleep(20); + inb(zol->io + 3); + + zol->curvol = 0; + zol->stereo = 1; + + strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); + zol->vdev.v4l2_dev = v4l2_dev; + zol->vdev.fops = &zoltrix_fops; + zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; + zol->vdev.release = video_device_release_empty; + video_set_drvdata(&zol->vdev, zol); + + if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(zol->io, 2); + return -EINVAL; + } + v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); + + return 0; +} + +static void __exit zoltrix_exit(void) +{ + struct zoltrix *zol = &zoltrix_card; + + video_unregister_device(&zol->vdev); + v4l2_device_unregister(&zol->v4l2_dev); + release_region(zol->io, 2); +} + +module_init(zoltrix_init); +module_exit(zoltrix_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/saa7706h.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/saa7706h.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/saa7706h.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/saa7706h.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,452 @@ +/* + * saa7706.c Philips SAA7706H Car Radio DSP driver + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "saa7706h" + +/* the I2C memory map looks like this + + $1C00 - $FFFF Not Used + $2200 - $3FFF Reserved YRAM (DSP2) space + $2000 - $21FF YRAM (DSP2) + $1FF0 - $1FFF Hardware Registers + $1280 - $1FEF Reserved XRAM (DSP2) space + $1000 - $127F XRAM (DSP2) + $0FFF DSP CONTROL + $0A00 - $0FFE Reserved + $0980 - $09FF Reserved YRAM (DSP1) space + $0800 - $097F YRAM (DSP1) + $0200 - $07FF Not Used + $0180 - $01FF Reserved XRAM (DSP1) space + $0000 - $017F XRAM (DSP1) +*/ + +#define SAA7706H_REG_CTRL 0x0fff +#define SAA7706H_CTRL_BYP_PLL 0x0001 +#define SAA7706H_CTRL_PLL_DIV_MASK 0x003e +#define SAA7706H_CTRL_PLL3_62975MHZ 0x003e +#define SAA7706H_CTRL_DSP_TURBO 0x0040 +#define SAA7706H_CTRL_PC_RESET_DSP1 0x0080 +#define SAA7706H_CTRL_PC_RESET_DSP2 0x0100 +#define SAA7706H_CTRL_DSP1_ROM_EN_MASK 0x0600 +#define SAA7706H_CTRL_DSP1_FUNC_PROM 0x0000 +#define SAA7706H_CTRL_DSP2_ROM_EN_MASK 0x1800 +#define SAA7706H_CTRL_DSP2_FUNC_PROM 0x0000 +#define SAA7706H_CTRL_DIG_SIL_INTERPOL 0x8000 + +#define SAA7706H_REG_EVALUATION 0x1ff0 +#define SAA7706H_EVAL_DISABLE_CHARGE_PUMP 0x000001 +#define SAA7706H_EVAL_DCS_CLOCK 0x000002 +#define SAA7706H_EVAL_GNDRC1_ENABLE 0x000004 +#define SAA7706H_EVAL_GNDRC2_ENABLE 0x000008 + +#define SAA7706H_REG_CL_GEN1 0x1ff3 +#define SAA7706H_CL_GEN1_MIN_LOOPGAIN_MASK 0x00000f +#define SAA7706H_CL_GEN1_LOOPGAIN_MASK 0x0000f0 +#define SAA7706H_CL_GEN1_COARSE_RATION 0xffff00 + +#define SAA7706H_REG_CL_GEN2 0x1ff4 +#define SAA7706H_CL_GEN2_WSEDGE_FALLING 0x000001 +#define SAA7706H_CL_GEN2_STOP_VCO 0x000002 +#define SAA7706H_CL_GEN2_FRERUN 0x000004 +#define SAA7706H_CL_GEN2_ADAPTIVE 0x000008 +#define SAA7706H_CL_GEN2_FINE_RATIO_MASK 0x0ffff0 + +#define SAA7706H_REG_CL_GEN4 0x1ff6 +#define SAA7706H_CL_GEN4_BYPASS_PLL1 0x001000 +#define SAA7706H_CL_GEN4_PLL1_DIV_MASK 0x03e000 +#define SAA7706H_CL_GEN4_DSP1_TURBO 0x040000 + +#define SAA7706H_REG_SEL 0x1ff7 +#define SAA7706H_SEL_DSP2_SRCA_MASK 0x000007 +#define SAA7706H_SEL_DSP2_FMTA_MASK 0x000031 +#define SAA7706H_SEL_DSP2_SRCB_MASK 0x0001c0 +#define SAA7706H_SEL_DSP2_FMTB_MASK 0x000e00 +#define SAA7706H_SEL_DSP1_SRC_MASK 0x003000 +#define SAA7706H_SEL_DSP1_FMT_MASK 0x01c003 +#define SAA7706H_SEL_SPDIF2 0x020000 +#define SAA7706H_SEL_HOST_IO_FMT_MASK 0x1c0000 +#define SAA7706H_SEL_EN_HOST_IO 0x200000 + +#define SAA7706H_REG_IAC 0x1ff8 +#define SAA7706H_REG_CLK_SET 0x1ff9 +#define SAA7706H_REG_CLK_COEFF 0x1ffa +#define SAA7706H_REG_INPUT_SENS 0x1ffb +#define SAA7706H_INPUT_SENS_RDS_VOL_MASK 0x0003f +#define SAA7706H_INPUT_SENS_FM_VOL_MASK 0x00fc0 +#define SAA7706H_INPUT_SENS_FM_MPX 0x01000 +#define SAA7706H_INPUT_SENS_OFF_FILTER_A_EN 0x02000 +#define SAA7706H_INPUT_SENS_OFF_FILTER_B_EN 0x04000 +#define SAA7706H_REG_PHONE_NAV_AUDIO 0x1ffc +#define SAA7706H_REG_IO_CONF_DSP2 0x1ffd +#define SAA7706H_REG_STATUS_DSP2 0x1ffe +#define SAA7706H_REG_PC_DSP2 0x1fff + +#define SAA7706H_DSP1_MOD0 0x0800 +#define SAA7706H_DSP1_ROM_VER 0x097f +#define SAA7706H_DSP2_MPTR0 0x1000 + +#define SAA7706H_DSP1_MODPNTR 0x0000 + +#define SAA7706H_DSP2_XMEM_CONTLLCW 0x113e +#define SAA7706H_DSP2_XMEM_BUSAMP 0x114a +#define SAA7706H_DSP2_XMEM_FDACPNTR 0x11f9 +#define SAA7706H_DSP2_XMEM_IIS1PNTR 0x11fb + +#define SAA7706H_DSP2_YMEM_PVGA 0x212a +#define SAA7706H_DSP2_YMEM_PVAT1 0x212b +#define SAA7706H_DSP2_YMEM_PVAT 0x212c +#define SAA7706H_DSP2_YMEM_ROM_VER 0x21ff + +#define SUPPORTED_DSP1_ROM_VER 0x667 + +struct saa7706h_state { + struct v4l2_subdev sd; + unsigned muted; +}; + +static inline struct saa7706h_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct saa7706h_state, sd); +} + +static int saa7706h_i2c_send(struct i2c_client *client, const u8 *data, int len) +{ + int err = i2c_master_send(client, data, len); + if (err == len) + return 0; + return err > 0 ? -EIO : err; +} + +static int saa7706h_i2c_transfer(struct i2c_client *client, + struct i2c_msg *msgs, int num) +{ + int err = i2c_transfer(client->adapter, msgs, num); + if (err == num) + return 0; + return err > 0 ? -EIO : err; +} + +static int saa7706h_set_reg24(struct v4l2_subdev *sd, u16 reg, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 buf[5]; + int pos = 0; + + buf[pos++] = reg >> 8; + buf[pos++] = reg; + buf[pos++] = val >> 16; + buf[pos++] = val >> 8; + buf[pos++] = val; + + return saa7706h_i2c_send(client, buf, pos); +} + +static int saa7706h_set_reg24_err(struct v4l2_subdev *sd, u16 reg, u32 val, + int *err) +{ + return *err ? *err : saa7706h_set_reg24(sd, reg, val); +} + +static int saa7706h_set_reg16(struct v4l2_subdev *sd, u16 reg, u16 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 buf[4]; + int pos = 0; + + buf[pos++] = reg >> 8; + buf[pos++] = reg; + buf[pos++] = val >> 8; + buf[pos++] = val; + + return saa7706h_i2c_send(client, buf, pos); +} + +static int saa7706h_set_reg16_err(struct v4l2_subdev *sd, u16 reg, u16 val, + int *err) +{ + return *err ? *err : saa7706h_set_reg16(sd, reg, val); +} + +static int saa7706h_get_reg16(struct v4l2_subdev *sd, u16 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 buf[2]; + int err; + u8 regaddr[] = {reg >> 8, reg}; + struct i2c_msg msg[] = { {client->addr, 0, sizeof(regaddr), regaddr}, + {client->addr, I2C_M_RD, sizeof(buf), buf} }; + + err = saa7706h_i2c_transfer(client, msg, ARRAY_SIZE(msg)); + if (err) + return err; + + return buf[0] << 8 | buf[1]; +} + +static int saa7706h_unmute(struct v4l2_subdev *sd) +{ + struct saa7706h_state *state = to_state(sd); + int err = 0; + + err = saa7706h_set_reg16_err(sd, SAA7706H_REG_CTRL, + SAA7706H_CTRL_PLL3_62975MHZ | SAA7706H_CTRL_PC_RESET_DSP1 | + SAA7706H_CTRL_PC_RESET_DSP2, &err); + + /* newer versions of the chip requires a small sleep after reset */ + msleep(1); + + err = saa7706h_set_reg16_err(sd, SAA7706H_REG_CTRL, + SAA7706H_CTRL_PLL3_62975MHZ, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_EVALUATION, 0, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CL_GEN1, 0x040022, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CL_GEN2, + SAA7706H_CL_GEN2_WSEDGE_FALLING, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CL_GEN4, 0x024080, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_SEL, 0x200080, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_IAC, 0xf4caed, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CLK_SET, 0x124334, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_CLK_COEFF, 0x004a1a, + &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_INPUT_SENS, 0x0071c7, + &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_PHONE_NAV_AUDIO, + 0x0e22ff, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_IO_CONF_DSP2, 0x001ff8, + &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_STATUS_DSP2, 0x080003, + &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_REG_PC_DSP2, 0x000004, &err); + + err = saa7706h_set_reg16_err(sd, SAA7706H_DSP1_MOD0, 0x0c6c, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_MPTR0, 0x000b4b, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_DSP1_MODPNTR, 0x000600, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_DSP1_MODPNTR, 0x0000c0, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_CONTLLCW, 0x000819, + &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_CONTLLCW, 0x00085a, + &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_BUSAMP, 0x7fffff, + &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_FDACPNTR, 0x2000cb, + &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_IIS1PNTR, 0x2000cb, + &err); + + err = saa7706h_set_reg16_err(sd, SAA7706H_DSP2_YMEM_PVGA, 0x0f80, &err); + + err = saa7706h_set_reg16_err(sd, SAA7706H_DSP2_YMEM_PVAT1, 0x0800, + &err); + + err = saa7706h_set_reg16_err(sd, SAA7706H_DSP2_YMEM_PVAT, 0x0800, &err); + + err = saa7706h_set_reg24_err(sd, SAA7706H_DSP2_XMEM_CONTLLCW, 0x000905, + &err); + if (!err) + state->muted = 0; + return err; +} + +static int saa7706h_mute(struct v4l2_subdev *sd) +{ + struct saa7706h_state *state = to_state(sd); + int err; + + err = saa7706h_set_reg16(sd, SAA7706H_REG_CTRL, + SAA7706H_CTRL_PLL3_62975MHZ | SAA7706H_CTRL_PC_RESET_DSP1 | + SAA7706H_CTRL_PC_RESET_DSP2); + if (!err) + state->muted = 1; + return err; +} + +static int saa7706h_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + } + return -EINVAL; +} + +static int saa7706h_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct saa7706h_state *state = to_state(sd); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = state->muted; + return 0; + } + return -EINVAL; +} + +static int saa7706h_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + return saa7706h_mute(sd); + return saa7706h_unmute(sd); + } + return -EINVAL; +} + +static int saa7706h_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7706H, 0); +} + +static const struct v4l2_subdev_core_ops saa7706h_core_ops = { + .g_chip_ident = saa7706h_g_chip_ident, + .queryctrl = saa7706h_queryctrl, + .g_ctrl = saa7706h_g_ctrl, + .s_ctrl = saa7706h_s_ctrl, +}; + +static const struct v4l2_subdev_ops saa7706h_ops = { + .core = &saa7706h_core_ops, +}; + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static int __devinit saa7706h_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct saa7706h_state *state; + struct v4l2_subdev *sd; + int err; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kzalloc(sizeof(struct saa7706h_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &saa7706h_ops); + + /* check the rom versions */ + err = saa7706h_get_reg16(sd, SAA7706H_DSP1_ROM_VER); + if (err < 0) + goto err; + if (err != SUPPORTED_DSP1_ROM_VER) + v4l2_warn(sd, "Unknown DSP1 ROM code version: 0x%x\n", err); + + state->muted = 1; + + /* startup in a muted state */ + err = saa7706h_mute(sd); + if (err) + goto err; + + return 0; + +err: + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); + + printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", err); + + return err; +} + +static int __devexit saa7706h_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + saa7706h_mute(sd); + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); + return 0; +} + +static const struct i2c_device_id saa7706h_id[] = { + {DRIVER_NAME, 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, saa7706h_id); + +static struct i2c_driver saa7706h_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, + .probe = saa7706h_probe, + .remove = saa7706h_remove, + .id_table = saa7706h_id, +}; + +static __init int saa7706h_init(void) +{ + return i2c_add_driver(&saa7706h_driver); +} + +static __exit void saa7706h_exit(void) +{ + i2c_del_driver(&saa7706h_driver); +} + +module_init(saa7706h_init); +module_exit(saa7706h_exit); + +MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver"); +MODULE_AUTHOR("Mocean Laboratories"); +MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,37 @@ +config USB_SI470X + tristate "Silicon Labs Si470x FM Radio Receiver support with USB" + depends on USB && RADIO_SI470X + ---help--- + This is a driver for USB devices with the Silicon Labs SI470x + chip. Currently these devices are known to work: + - 10c4:818a: Silicon Labs USB FM Radio Reference Design + - 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music) + - 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700) + - 10c5:819a: Sanei Electric FM USB Radio (aka DealExtreme.com PCear) + + Sound is provided by the ALSA USB Audio/MIDI driver. Therefore + if you don't want to use the device solely for RDS receiving, + it is recommended to also select SND_USB_AUDIO. + + Please have a look at the documentation, especially on how + to redirect the audio stream from the radio to your sound device: + Documentation/video4linux/si470x.txt + + Say Y here if you want to connect this type of radio to your + computer's USB port. + + To compile this driver as a module, choose M here: the + module will be called radio-usb-si470x. + +config I2C_SI470X + tristate "Silicon Labs Si470x FM Radio Receiver support with I2C" + depends on I2C && RADIO_SI470X && !USB_SI470X + ---help--- + This is a driver for I2C devices with the Silicon Labs SI470x + chip. + + Say Y here if you want to connect this type of radio to your + computer's I2C port. + + To compile this driver as a module, choose M here: the + module will be called radio-i2c-si470x. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,9 @@ +# +# Makefile for radios with Silicon Labs Si470x FM Radio Receivers +# + +radio-usb-si470x-objs := radio-si470x-usb.o radio-si470x-common.o +radio-i2c-si470x-objs := radio-si470x-i2c.o radio-si470x-common.o + +obj-$(CONFIG_USB_SI470X) += radio-usb-si470x.o +obj-$(CONFIG_I2C_SI470X) += radio-i2c-si470x.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-common.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-common.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,931 @@ +/* + * drivers/media/radio/si470x/radio-si470x-common.c + * + * Driver for radios with Silicon Labs Si470x FM Radio Receivers + * + * Copyright (c) 2009 Tobias Lorenz + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + + +/* + * History: + * 2008-01-12 Tobias Lorenz + * Version 1.0.0 + * - First working version + * 2008-01-13 Tobias Lorenz + * Version 1.0.1 + * - Improved error handling, every function now returns errno + * - Improved multi user access (start/mute/stop) + * - Channel doesn't get lost anymore after start/mute/stop + * - RDS support added (polling mode via interrupt EP 1) + * - marked default module parameters with *value* + * - switched from bit structs to bit masks + * - header file cleaned and integrated + * 2008-01-14 Tobias Lorenz + * Version 1.0.2 + * - hex values are now lower case + * - commented USB ID for ADS/Tech moved on todo list + * - blacklisted si470x in hid-quirks.c + * - rds buffer handling functions integrated into *_work, *_read + * - rds_command in si470x_poll exchanged against simple retval + * - check for firmware version 15 + * - code order and prototypes still remain the same + * - spacing and bottom of band codes remain the same + * 2008-01-16 Tobias Lorenz + * Version 1.0.3 + * - code reordered to avoid function prototypes + * - switch/case defaults are now more user-friendly + * - unified comment style + * - applied all checkpatch.pl v1.12 suggestions + * except the warning about the too long lines with bit comments + * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) + * 2008-01-22 Tobias Lorenz + * Version 1.0.4 + * - avoid poss. locking when doing copy_to_user which may sleep + * - RDS is automatically activated on read now + * - code cleaned of unnecessary rds_commands + * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified + * (thanks to Guillaume RAMOUSSE) + * 2008-01-27 Tobias Lorenz + * Version 1.0.5 + * - number of seek_retries changed to tune_timeout + * - fixed problem with incomplete tune operations by own buffers + * - optimization of variables and printf types + * - improved error logging + * 2008-01-31 Tobias Lorenz + * Oliver Neukum + * Version 1.0.6 + * - fixed coverity checker warnings in *_usb_driver_disconnect + * - probe()/open() race by correct ordering in probe() + * - DMA coherency rules by separate allocation of all buffers + * - use of endianness macros + * - abuse of spinlock, replaced by mutex + * - racy handling of timer in disconnect, + * replaced by delayed_work + * - racy interruptible_sleep_on(), + * replaced with wait_event_interruptible() + * - handle signals in read() + * 2008-02-08 Tobias Lorenz + * Oliver Neukum + * Version 1.0.7 + * - usb autosuspend support + * - unplugging fixed + * 2008-05-07 Tobias Lorenz + * Version 1.0.8 + * - hardware frequency seek support + * - afc indication + * - more safety checks, let si470x_get_freq return errno + * - vidioc behavior corrected according to v4l2 spec + * 2008-10-20 Alexey Klimov + * - add support for KWorld USB FM Radio FM700 + * - blacklisted KWorld radio in hid-core.c and hid-ids.h + * 2008-12-03 Mark Lord + * - add support for DealExtreme USB Radio + * 2009-01-31 Bob Ross + * - correction of stereo detection/setting + * - correction of signal strength indicator scaling + * 2009-01-31 Rick Bronson + * Tobias Lorenz + * - add LED status output + * - get HW/SW version from scratchpad + * 2009-06-16 Edouard Lafargue + * Version 1.0.10 + * - add support for interrupt mode for RDS endpoint, + * instead of polling. + * Improves RDS reception significantly + */ + + +/* kernel includes */ +#include "radio-si470x.h" + + + +/************************************************************************** + * Module Parameters + **************************************************************************/ + +/* Spacing (kHz) */ +/* 0: 200 kHz (USA, Australia) */ +/* 1: 100 kHz (Europe, Japan) */ +/* 2: 50 kHz */ +static unsigned short space = 2; +module_param(space, ushort, 0444); +MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*"); + +/* Bottom of Band (MHz) */ +/* 0: 87.5 - 108 MHz (USA, Europe)*/ +/* 1: 76 - 108 MHz (Japan wide band) */ +/* 2: 76 - 90 MHz (Japan) */ +static unsigned short band = 1; +module_param(band, ushort, 0444); +MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz"); + +/* De-emphasis */ +/* 0: 75 us (USA) */ +/* 1: 50 us (Europe, Australia, Japan) */ +static unsigned short de = 1; +module_param(de, ushort, 0444); +MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*"); + +/* Tune timeout */ +static unsigned int tune_timeout = 3000; +module_param(tune_timeout, uint, 0644); +MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*"); + +/* Seek timeout */ +static unsigned int seek_timeout = 5000; +module_param(seek_timeout, uint, 0644); +MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*"); + + + +/************************************************************************** + * Generic Functions + **************************************************************************/ + +/* + * si470x_set_chan - set the channel + */ +static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) +{ + int retval; + unsigned long timeout; + bool timed_out = 0; + + /* start tuning */ + radio->registers[CHANNEL] &= ~CHANNEL_CHAN; + radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; + retval = si470x_set_register(radio, CHANNEL); + if (retval < 0) + goto done; + + /* currently I2C driver only uses interrupt way to tune */ + if (radio->stci_enabled) { + INIT_COMPLETION(radio->completion); + + /* wait till tune operation has completed */ + retval = wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(tune_timeout)); + if (!retval) + timed_out = true; + } else { + /* wait till tune operation has completed */ + timeout = jiffies + msecs_to_jiffies(tune_timeout); + do { + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + goto stop; + timed_out = time_after(jiffies, timeout); + } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) + && (!timed_out)); + } + + if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) + dev_warn(&radio->videodev->dev, "tune does not complete\n"); + if (timed_out) + dev_warn(&radio->videodev->dev, + "tune timed out after %u ms\n", tune_timeout); + +stop: + /* stop tuning */ + radio->registers[CHANNEL] &= ~CHANNEL_TUNE; + retval = si470x_set_register(radio, CHANNEL); + +done: + return retval; +} + + +/* + * si470x_get_freq - get the frequency + */ +static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) +{ + unsigned int spacing, band_bottom; + unsigned short chan; + int retval; + + /* Spacing (kHz) */ + switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) { + /* 0: 200 kHz (USA, Australia) */ + case 0: + spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1: + spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + default: + spacing = 0.050 * FREQ_MUL; break; + }; + + /* Bottom of Band (MHz) */ + switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { + /* 0: 87.5 - 108 MHz (USA, Europe) */ + case 0: + band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + default: + band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2: + band_bottom = 76 * FREQ_MUL; break; + }; + + /* read channel */ + retval = si470x_get_register(radio, READCHAN); + chan = radio->registers[READCHAN] & READCHAN_READCHAN; + + /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */ + *freq = chan * spacing + band_bottom; + + return retval; +} + + +/* + * si470x_set_freq - set the frequency + */ +int si470x_set_freq(struct si470x_device *radio, unsigned int freq) +{ + unsigned int spacing, band_bottom; + unsigned short chan; + + /* Spacing (kHz) */ + switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) { + /* 0: 200 kHz (USA, Australia) */ + case 0: + spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1: + spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + default: + spacing = 0.050 * FREQ_MUL; break; + }; + + /* Bottom of Band (MHz) */ + switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { + /* 0: 87.5 - 108 MHz (USA, Europe) */ + case 0: + band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + default: + band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2: + band_bottom = 76 * FREQ_MUL; break; + }; + + /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ + chan = (freq - band_bottom) / spacing; + + return si470x_set_chan(radio, chan); +} + + +/* + * si470x_set_seek - set seek + */ +static int si470x_set_seek(struct si470x_device *radio, + unsigned int wrap_around, unsigned int seek_upward) +{ + int retval = 0; + unsigned long timeout; + bool timed_out = 0; + + /* start seeking */ + radio->registers[POWERCFG] |= POWERCFG_SEEK; + if (wrap_around == 1) + radio->registers[POWERCFG] &= ~POWERCFG_SKMODE; + else + radio->registers[POWERCFG] |= POWERCFG_SKMODE; + if (seek_upward == 1) + radio->registers[POWERCFG] |= POWERCFG_SEEKUP; + else + radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP; + retval = si470x_set_register(radio, POWERCFG); + if (retval < 0) + goto done; + + /* currently I2C driver only uses interrupt way to seek */ + if (radio->stci_enabled) { + INIT_COMPLETION(radio->completion); + + /* wait till seek operation has completed */ + retval = wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(seek_timeout)); + if (!retval) + timed_out = true; + } else { + /* wait till seek operation has completed */ + timeout = jiffies + msecs_to_jiffies(seek_timeout); + do { + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + goto stop; + timed_out = time_after(jiffies, timeout); + } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) + && (!timed_out)); + } + + if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) + dev_warn(&radio->videodev->dev, "seek does not complete\n"); + if (radio->registers[STATUSRSSI] & STATUSRSSI_SF) + dev_warn(&radio->videodev->dev, + "seek failed / band limit reached\n"); + if (timed_out) + dev_warn(&radio->videodev->dev, + "seek timed out after %u ms\n", seek_timeout); + +stop: + /* stop seeking */ + radio->registers[POWERCFG] &= ~POWERCFG_SEEK; + retval = si470x_set_register(radio, POWERCFG); + +done: + /* try again, if timed out */ + if ((retval == 0) && timed_out) + retval = -EAGAIN; + + return retval; +} + + +/* + * si470x_start - switch on radio + */ +int si470x_start(struct si470x_device *radio) +{ + int retval; + + /* powercfg */ + radio->registers[POWERCFG] = + POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; + retval = si470x_set_register(radio, POWERCFG); + if (retval < 0) + goto done; + + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] = + (de << 11) & SYSCONFIG1_DE; /* DE*/ + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + goto done; + + /* sysconfig 2 */ + radio->registers[SYSCONFIG2] = + (0x3f << 8) | /* SEEKTH */ + ((band << 6) & SYSCONFIG2_BAND) | /* BAND */ + ((space << 4) & SYSCONFIG2_SPACE) | /* SPACE */ + 15; /* VOLUME (max) */ + retval = si470x_set_register(radio, SYSCONFIG2); + if (retval < 0) + goto done; + + /* reset last channel */ + retval = si470x_set_chan(radio, + radio->registers[CHANNEL] & CHANNEL_CHAN); + +done: + return retval; +} + + +/* + * si470x_stop - switch off radio + */ +int si470x_stop(struct si470x_device *radio) +{ + int retval; + + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + goto done; + + /* powercfg */ + radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; + /* POWERCFG_ENABLE has to automatically go low */ + radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; + retval = si470x_set_register(radio, POWERCFG); + +done: + return retval; +} + + +/* + * si470x_rds_on - switch on rds reception + */ +static int si470x_rds_on(struct si470x_device *radio) +{ + int retval; + + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; + + return retval; +} + + + +/************************************************************************** + * File Operations Interface + **************************************************************************/ + +/* + * si470x_fops_read - read RDS data + */ +static ssize_t si470x_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + unsigned int block_count = 0; + + /* switch on rds reception */ + mutex_lock(&radio->lock); + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) + si470x_rds_on(radio); + + /* block if no new data available */ + while (radio->wr_index == radio->rd_index) { + if (file->f_flags & O_NONBLOCK) { + retval = -EWOULDBLOCK; + goto done; + } + if (wait_event_interruptible(radio->read_queue, + radio->wr_index != radio->rd_index) < 0) { + retval = -EINTR; + goto done; + } + } + + /* calculate block count from byte count */ + count /= 3; + + /* copy RDS block out of internal buffer and to user buffer */ + while (block_count < count) { + if (radio->rd_index == radio->wr_index) + break; + + /* always transfer rds complete blocks */ + if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) + /* retval = -EFAULT; */ + break; + + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + + /* increment counters */ + block_count++; + buf += 3; + retval += 3; + } + +done: + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_fops_poll - poll RDS data + */ +static unsigned int si470x_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + /* switch on rds reception */ + + mutex_lock(&radio->lock); + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) + si470x_rds_on(radio); + mutex_unlock(&radio->lock); + + poll_wait(file, &radio->read_queue, pts); + + if (radio->rd_index != radio->wr_index) + retval = POLLIN | POLLRDNORM; + + return retval; +} + + +/* + * si470x_fops - file operations interface + */ +static const struct v4l2_file_operations si470x_fops = { + .owner = THIS_MODULE, + .read = si470x_fops_read, + .poll = si470x_fops_poll, + .unlocked_ioctl = video_ioctl2, + .open = si470x_fops_open, + .release = si470x_fops_release, +}; + + + +/************************************************************************** + * Video4Linux Interface + **************************************************************************/ + +/* + * si470x_vidioc_queryctrl - enumerate control items + */ +static int si470x_vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = -EINVAL; + + /* abort if qc->id is below V4L2_CID_BASE */ + if (qc->id < V4L2_CID_BASE) + goto done; + + /* search video control */ + switch (qc->id) { + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15); + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + } + + /* disable unsupported base controls */ + /* to satisfy kradio and such apps */ + if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) { + qc->flags = V4L2_CTRL_FLAG_DISABLED; + retval = 0; + } + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "query controls failed with %d\n", retval); + return retval; +} + + +/* + * si470x_vidioc_g_ctrl - get the value of a control + */ +static int si470x_vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + /* safety checks */ + retval = si470x_disconnect_check(radio); + if (retval) + goto done; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = radio->registers[SYSCONFIG2] & + SYSCONFIG2_VOLUME; + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = ((radio->registers[POWERCFG] & + POWERCFG_DMUTE) == 0) ? 1 : 0; + break; + default: + retval = -EINVAL; + } + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "get control failed with %d\n", retval); + + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_vidioc_s_ctrl - set the value of a control + */ +static int si470x_vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + /* safety checks */ + retval = si470x_disconnect_check(radio); + if (retval) + goto done; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; + radio->registers[SYSCONFIG2] |= ctrl->value; + retval = si470x_set_register(radio, SYSCONFIG2); + break; + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value == 1) + radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; + else + radio->registers[POWERCFG] |= POWERCFG_DMUTE; + retval = si470x_set_register(radio, POWERCFG); + break; + default: + retval = -EINVAL; + } + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "set control failed with %d\n", retval); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_vidioc_g_audio - get audio attributes + */ +static int si470x_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + /* driver constants */ + audio->index = 0; + strcpy(audio->name, "Radio"); + audio->capability = V4L2_AUDCAP_STEREO; + audio->mode = 0; + + return 0; +} + + +/* + * si470x_vidioc_g_tuner - get tuner attributes + */ +static int si470x_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + /* safety checks */ + retval = si470x_disconnect_check(radio); + if (retval) + goto done; + + if (tuner->index != 0) { + retval = -EINVAL; + goto done; + } + + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + goto done; + + /* driver constants */ + strcpy(tuner->name, "FM"); + tuner->type = V4L2_TUNER_RADIO; + tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; + + /* range limits */ + switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { + /* 0: 87.5 - 108 MHz (USA, Europe, default) */ + default: + tuner->rangelow = 87.5 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 1: 76 - 108 MHz (Japan wide band) */ + case 1: + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 2: 76 - 90 MHz (Japan) */ + case 2: + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 90 * FREQ_MUL; + break; + }; + + /* stereo indicator == stereo (instead of mono) */ + if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0) + tuner->rxsubchans = V4L2_TUNER_SUB_MONO; + else + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + /* If there is a reliable method of detecting an RDS channel, + then this code should check for that before setting this + RDS subchannel. */ + tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; + + /* mono/stereo selector */ + if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0) + tuner->audmode = V4L2_TUNER_MODE_STEREO; + else + tuner->audmode = V4L2_TUNER_MODE_MONO; + + /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */ + /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */ + tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI); + /* the ideal factor is 0xffff/75 = 873,8 */ + tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10); + + /* automatic frequency control: -1: freq to low, 1 freq to high */ + /* AFCRL does only indicate that freq. differs, not if too low/high */ + tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0; + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "get tuner failed with %d\n", retval); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_vidioc_s_tuner - set tuner attributes + */ +static int si470x_vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + /* safety checks */ + retval = si470x_disconnect_check(radio); + if (retval) + goto done; + + if (tuner->index != 0) + goto done; + + /* mono/stereo selector */ + switch (tuner->audmode) { + case V4L2_TUNER_MODE_MONO: + radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ + break; + case V4L2_TUNER_MODE_STEREO: + radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ + break; + default: + goto done; + } + + retval = si470x_set_register(radio, POWERCFG); + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "set tuner failed with %d\n", retval); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_vidioc_g_frequency - get tuner or modulator radio frequency + */ +static int si470x_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + /* safety checks */ + mutex_lock(&radio->lock); + retval = si470x_disconnect_check(radio); + if (retval) + goto done; + + if (freq->tuner != 0) { + retval = -EINVAL; + goto done; + } + + freq->type = V4L2_TUNER_RADIO; + retval = si470x_get_freq(radio, &freq->frequency); + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "get frequency failed with %d\n", retval); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_vidioc_s_frequency - set tuner or modulator radio frequency + */ +static int si470x_vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + /* safety checks */ + retval = si470x_disconnect_check(radio); + if (retval) + goto done; + + if (freq->tuner != 0) { + retval = -EINVAL; + goto done; + } + + retval = si470x_set_freq(radio, freq->frequency); + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "set frequency failed with %d\n", retval); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek + */ +static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, + struct v4l2_hw_freq_seek *seek) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + /* safety checks */ + retval = si470x_disconnect_check(radio); + if (retval) + goto done; + + if (seek->tuner != 0) { + retval = -EINVAL; + goto done; + } + + retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward); + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "set hardware frequency seek failed with %d\n", retval); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_ioctl_ops - video device ioctl operations + */ +static const struct v4l2_ioctl_ops si470x_ioctl_ops = { + .vidioc_querycap = si470x_vidioc_querycap, + .vidioc_queryctrl = si470x_vidioc_queryctrl, + .vidioc_g_ctrl = si470x_vidioc_g_ctrl, + .vidioc_s_ctrl = si470x_vidioc_s_ctrl, + .vidioc_g_audio = si470x_vidioc_g_audio, + .vidioc_g_tuner = si470x_vidioc_g_tuner, + .vidioc_s_tuner = si470x_vidioc_s_tuner, + .vidioc_g_frequency = si470x_vidioc_g_frequency, + .vidioc_s_frequency = si470x_vidioc_s_frequency, + .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, +}; + + +/* + * si470x_viddev_template - video device interface + */ +struct video_device si470x_viddev_template = { + .fops = &si470x_fops, + .name = DRIVER_NAME, + .release = video_device_release, + .ioctl_ops = &si470x_ioctl_ops, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,226 @@ +/* + * drivers/media/radio/si470x/radio-si470x.h + * + * Driver for radios with Silicon Labs Si470x FM Radio Receivers + * + * Copyright (c) 2009 Tobias Lorenz + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + + +/* driver definitions */ +#define DRIVER_NAME "radio-si470x" + + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/************************************************************************** + * Register Definitions + **************************************************************************/ +#define RADIO_REGISTER_SIZE 2 /* 16 register bit width */ +#define RADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ +#define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */ + +#define DEVICEID 0 /* Device ID */ +#define DEVICEID_PN 0xf000 /* bits 15..12: Part Number */ +#define DEVICEID_MFGID 0x0fff /* bits 11..00: Manufacturer ID */ + +#define CHIPID 1 /* Chip ID */ +#define CHIPID_REV 0xfc00 /* bits 15..10: Chip Version */ +#define CHIPID_DEV 0x0200 /* bits 09..09: Device */ +#define CHIPID_FIRMWARE 0x01ff /* bits 08..00: Firmware Version */ + +#define POWERCFG 2 /* Power Configuration */ +#define POWERCFG_DSMUTE 0x8000 /* bits 15..15: Softmute Disable */ +#define POWERCFG_DMUTE 0x4000 /* bits 14..14: Mute Disable */ +#define POWERCFG_MONO 0x2000 /* bits 13..13: Mono Select */ +#define POWERCFG_RDSM 0x0800 /* bits 11..11: RDS Mode (Si4701 only) */ +#define POWERCFG_SKMODE 0x0400 /* bits 10..10: Seek Mode */ +#define POWERCFG_SEEKUP 0x0200 /* bits 09..09: Seek Direction */ +#define POWERCFG_SEEK 0x0100 /* bits 08..08: Seek */ +#define POWERCFG_DISABLE 0x0040 /* bits 06..06: Powerup Disable */ +#define POWERCFG_ENABLE 0x0001 /* bits 00..00: Powerup Enable */ + +#define CHANNEL 3 /* Channel */ +#define CHANNEL_TUNE 0x8000 /* bits 15..15: Tune */ +#define CHANNEL_CHAN 0x03ff /* bits 09..00: Channel Select */ + +#define SYSCONFIG1 4 /* System Configuration 1 */ +#define SYSCONFIG1_RDSIEN 0x8000 /* bits 15..15: RDS Interrupt Enable (Si4701 only) */ +#define SYSCONFIG1_STCIEN 0x4000 /* bits 14..14: Seek/Tune Complete Interrupt Enable */ +#define SYSCONFIG1_RDS 0x1000 /* bits 12..12: RDS Enable (Si4701 only) */ +#define SYSCONFIG1_DE 0x0800 /* bits 11..11: De-emphasis (0=75us 1=50us) */ +#define SYSCONFIG1_AGCD 0x0400 /* bits 10..10: AGC Disable */ +#define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */ +#define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */ +#define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */ +#define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */ + +#define SYSCONFIG2 5 /* System Configuration 2 */ +#define SYSCONFIG2_SEEKTH 0xff00 /* bits 15..08: RSSI Seek Threshold */ +#define SYSCONFIG2_BAND 0x0080 /* bits 07..06: Band Select */ +#define SYSCONFIG2_SPACE 0x0030 /* bits 05..04: Channel Spacing */ +#define SYSCONFIG2_VOLUME 0x000f /* bits 03..00: Volume */ + +#define SYSCONFIG3 6 /* System Configuration 3 */ +#define SYSCONFIG3_SMUTER 0xc000 /* bits 15..14: Softmute Attack/Recover Rate */ +#define SYSCONFIG3_SMUTEA 0x3000 /* bits 13..12: Softmute Attenuation */ +#define SYSCONFIG3_SKSNR 0x00f0 /* bits 07..04: Seek SNR Threshold */ +#define SYSCONFIG3_SKCNT 0x000f /* bits 03..00: Seek FM Impulse Detection Threshold */ + +#define TEST1 7 /* Test 1 */ +#define TEST1_AHIZEN 0x4000 /* bits 14..14: Audio High-Z Enable */ + +#define TEST2 8 /* Test 2 */ +/* TEST2 only contains reserved bits */ + +#define BOOTCONFIG 9 /* Boot Configuration */ +/* BOOTCONFIG only contains reserved bits */ + +#define STATUSRSSI 10 /* Status RSSI */ +#define STATUSRSSI_RDSR 0x8000 /* bits 15..15: RDS Ready (Si4701 only) */ +#define STATUSRSSI_STC 0x4000 /* bits 14..14: Seek/Tune Complete */ +#define STATUSRSSI_SF 0x2000 /* bits 13..13: Seek Fail/Band Limit */ +#define STATUSRSSI_AFCRL 0x1000 /* bits 12..12: AFC Rail */ +#define STATUSRSSI_RDSS 0x0800 /* bits 11..11: RDS Synchronized (Si4701 only) */ +#define STATUSRSSI_BLERA 0x0600 /* bits 10..09: RDS Block A Errors (Si4701 only) */ +#define STATUSRSSI_ST 0x0100 /* bits 08..08: Stereo Indicator */ +#define STATUSRSSI_RSSI 0x00ff /* bits 07..00: RSSI (Received Signal Strength Indicator) */ + +#define READCHAN 11 /* Read Channel */ +#define READCHAN_BLERB 0xc000 /* bits 15..14: RDS Block D Errors (Si4701 only) */ +#define READCHAN_BLERC 0x3000 /* bits 13..12: RDS Block C Errors (Si4701 only) */ +#define READCHAN_BLERD 0x0c00 /* bits 11..10: RDS Block B Errors (Si4701 only) */ +#define READCHAN_READCHAN 0x03ff /* bits 09..00: Read Channel */ + +#define RDSA 12 /* RDSA */ +#define RDSA_RDSA 0xffff /* bits 15..00: RDS Block A Data (Si4701 only) */ + +#define RDSB 13 /* RDSB */ +#define RDSB_RDSB 0xffff /* bits 15..00: RDS Block B Data (Si4701 only) */ + +#define RDSC 14 /* RDSC */ +#define RDSC_RDSC 0xffff /* bits 15..00: RDS Block C Data (Si4701 only) */ + +#define RDSD 15 /* RDSD */ +#define RDSD_RDSD 0xffff /* bits 15..00: RDS Block D Data (Si4701 only) */ + + + +/************************************************************************** + * General Driver Definitions + **************************************************************************/ + +/* + * si470x_device - private data + */ +struct si470x_device { + struct video_device *videodev; + + /* driver management */ + unsigned int users; + + /* Silabs internal registers (0..15) */ + unsigned short registers[RADIO_REGISTER_NUM]; + + /* RDS receive buffer */ + wait_queue_head_t read_queue; + struct mutex lock; /* buffer locking */ + unsigned char *buffer; /* size is always multiple of three */ + unsigned int buf_size; + unsigned int rd_index; + unsigned int wr_index; + + struct completion completion; + bool stci_enabled; /* Seek/Tune Complete Interrupt */ + +#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE) + /* reference to USB and video device */ + struct usb_device *usbdev; + struct usb_interface *intf; + + /* Interrupt endpoint handling */ + char *int_in_buffer; + struct usb_endpoint_descriptor *int_in_endpoint; + struct urb *int_in_urb; + int int_in_running; + + /* scratch page */ + unsigned char software_version; + unsigned char hardware_version; + + /* driver management */ + unsigned char disconnected; +#endif + +#if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE) + struct i2c_client *client; +#endif +}; + + + +/************************************************************************** + * Firmware Versions + **************************************************************************/ + +#define RADIO_FW_VERSION 15 + + + +/************************************************************************** + * Frequency Multiplicator + **************************************************************************/ + +/* + * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, + * 62.5 kHz otherwise. + * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. + * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW + * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 + */ +#define FREQ_MUL (1000000 / 62.5) + + + +/************************************************************************** + * Common Functions + **************************************************************************/ +extern struct video_device si470x_viddev_template; +int si470x_get_register(struct si470x_device *radio, int regnr); +int si470x_set_register(struct si470x_device *radio, int regnr); +int si470x_disconnect_check(struct si470x_device *radio); +int si470x_set_freq(struct si470x_device *radio, unsigned int freq); +int si470x_start(struct si470x_device *radio); +int si470x_stop(struct si470x_device *radio); +int si470x_fops_open(struct file *file); +int si470x_fops_release(struct file *file); +int si470x_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-i2c.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,574 @@ +/* + * drivers/media/radio/si470x/radio-si470x-i2c.c + * + * I2C driver for radios with Silicon Labs Si470x FM Radio Receivers + * + * Copyright (c) 2009 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + + +/* driver definitions */ +#define DRIVER_AUTHOR "Joonyoung Shim "; +#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1) +#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" +#define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" +#define DRIVER_VERSION "1.0.1" + +/* kernel includes */ +#include +#include +#include +#include + +#include "radio-si470x.h" + + +/* I2C Device ID List */ +static const struct i2c_device_id si470x_i2c_id[] = { + /* Generic Entry */ + { "si470x", 0 }, + /* Terminating entry */ + { } +}; +MODULE_DEVICE_TABLE(i2c, si470x_i2c_id); + + + +/************************************************************************** + * Module Parameters + **************************************************************************/ + +/* Radio Nr */ +static int radio_nr = -1; +module_param(radio_nr, int, 0444); +MODULE_PARM_DESC(radio_nr, "Radio Nr"); + +/* RDS buffer blocks */ +static unsigned int rds_buf = 100; +module_param(rds_buf, uint, 0444); +MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); + +/* RDS maximum block errors */ +static unsigned short max_rds_errors = 1; +/* 0 means 0 errors requiring correction */ +/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ +/* 2 means 3-5 errors requiring correction */ +/* 3 means 6+ errors or errors in checkword, correction not possible */ +module_param(max_rds_errors, ushort, 0644); +MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); + + + +/************************************************************************** + * I2C Definitions + **************************************************************************/ + +/* Write starts with the upper byte of register 0x02 */ +#define WRITE_REG_NUM 8 +#define WRITE_INDEX(i) (i + 0x02) + +/* Read starts with the upper byte of register 0x0a */ +#define READ_REG_NUM RADIO_REGISTER_NUM +#define READ_INDEX(i) ((i + RADIO_REGISTER_NUM - 0x0a) % READ_REG_NUM) + + + +/************************************************************************** + * General Driver Functions - REGISTERs + **************************************************************************/ + +/* + * si470x_get_register - read register + */ +int si470x_get_register(struct si470x_device *radio, int regnr) +{ + u16 buf[READ_REG_NUM]; + struct i2c_msg msgs[1] = { + { radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM, + (void *)buf }, + }; + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + radio->registers[regnr] = __be16_to_cpu(buf[READ_INDEX(regnr)]); + + return 0; +} + + +/* + * si470x_set_register - write register + */ +int si470x_set_register(struct si470x_device *radio, int regnr) +{ + int i; + u16 buf[WRITE_REG_NUM]; + struct i2c_msg msgs[1] = { + { radio->client->addr, 0, sizeof(u16) * WRITE_REG_NUM, + (void *)buf }, + }; + + for (i = 0; i < WRITE_REG_NUM; i++) + buf[i] = __cpu_to_be16(radio->registers[WRITE_INDEX(i)]); + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + return 0; +} + + + +/************************************************************************** + * General Driver Functions - ENTIRE REGISTERS + **************************************************************************/ + +/* + * si470x_get_all_registers - read entire registers + */ +static int si470x_get_all_registers(struct si470x_device *radio) +{ + int i; + u16 buf[READ_REG_NUM]; + struct i2c_msg msgs[1] = { + { radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM, + (void *)buf }, + }; + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + for (i = 0; i < READ_REG_NUM; i++) + radio->registers[i] = __be16_to_cpu(buf[READ_INDEX(i)]); + + return 0; +} + + + +/************************************************************************** + * General Driver Functions - DISCONNECT_CHECK + **************************************************************************/ + +/* + * si470x_disconnect_check - check whether radio disconnects + */ +int si470x_disconnect_check(struct si470x_device *radio) +{ + return 0; +} + + + +/************************************************************************** + * File Operations Interface + **************************************************************************/ + +/* + * si470x_fops_open - file open + */ +int si470x_fops_open(struct file *file) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + radio->users++; + + if (radio->users == 1) { + /* start radio */ + retval = si470x_start(radio); + if (retval < 0) + goto done; + + /* enable RDS / STC interrupt */ + radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN; + radio->registers[SYSCONFIG1] |= SYSCONFIG1_STCIEN; + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2; + radio->registers[SYSCONFIG1] |= 0x1 << 2; + retval = si470x_set_register(radio, SYSCONFIG1); + } + +done: + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_fops_release - file release + */ +int si470x_fops_release(struct file *file) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + /* safety check */ + if (!radio) + return -ENODEV; + + mutex_lock(&radio->lock); + radio->users--; + if (radio->users == 0) + /* stop radio */ + retval = si470x_stop(radio); + + mutex_unlock(&radio->lock); + + return retval; +} + + + +/************************************************************************** + * Video4Linux Interface + **************************************************************************/ + +/* + * si470x_vidioc_querycap - query device capabilities + */ +int si470x_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + capability->version = DRIVER_KERNEL_VERSION; + capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | + V4L2_CAP_TUNER | V4L2_CAP_RADIO; + + return 0; +} + + + +/************************************************************************** + * I2C Interface + **************************************************************************/ + +/* + * si470x_i2c_interrupt - interrupt handler + */ +static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id) +{ + struct si470x_device *radio = dev_id; + unsigned char regnr; + unsigned char blocknum; + unsigned short bler; /* rds block errors */ + unsigned short rds; + unsigned char tmpbuf[3]; + int retval = 0; + + /* check Seek/Tune Complete */ + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + goto end; + + if (radio->registers[STATUSRSSI] & STATUSRSSI_STC) + complete(&radio->completion); + + /* safety checks */ + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) + goto end; + + /* Update RDS registers */ + for (regnr = 1; regnr < RDS_REGISTER_NUM; regnr++) { + retval = si470x_get_register(radio, STATUSRSSI + regnr); + if (retval < 0) + goto end; + } + + /* get rds blocks */ + if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) + /* No RDS group ready, better luck next time */ + goto end; + + for (blocknum = 0; blocknum < 4; blocknum++) { + switch (blocknum) { + default: + bler = (radio->registers[STATUSRSSI] & + STATUSRSSI_BLERA) >> 9; + rds = radio->registers[RDSA]; + break; + case 1: + bler = (radio->registers[READCHAN] & + READCHAN_BLERB) >> 14; + rds = radio->registers[RDSB]; + break; + case 2: + bler = (radio->registers[READCHAN] & + READCHAN_BLERC) >> 12; + rds = radio->registers[RDSC]; + break; + case 3: + bler = (radio->registers[READCHAN] & + READCHAN_BLERD) >> 10; + rds = radio->registers[RDSD]; + break; + }; + + /* Fill the V4L2 RDS buffer */ + put_unaligned_le16(rds, &tmpbuf); + tmpbuf[2] = blocknum; /* offset name */ + tmpbuf[2] |= blocknum << 3; /* received offset */ + if (bler > max_rds_errors) + tmpbuf[2] |= 0x80; /* uncorrectable errors */ + else if (bler > 0) + tmpbuf[2] |= 0x40; /* corrected error(s) */ + + /* copy RDS block to internal buffer */ + memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); + radio->wr_index += 3; + + /* wrap write pointer */ + if (radio->wr_index >= radio->buf_size) + radio->wr_index = 0; + + /* check for overflow */ + if (radio->wr_index == radio->rd_index) { + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + } + } + + if (radio->wr_index != radio->rd_index) + wake_up_interruptible(&radio->read_queue); + +end: + return IRQ_HANDLED; +} + + +/* + * si470x_i2c_probe - probe for the device + */ +static int __devinit si470x_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct si470x_device *radio; + int retval = 0; + unsigned char version_warning = 0; + + /* private data allocation and initialization */ + radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); + if (!radio) { + retval = -ENOMEM; + goto err_initial; + } + + radio->users = 0; + radio->client = client; + mutex_init(&radio->lock); + + /* video device allocation and initialization */ + radio->videodev = video_device_alloc(); + if (!radio->videodev) { + retval = -ENOMEM; + goto err_radio; + } + memcpy(radio->videodev, &si470x_viddev_template, + sizeof(si470x_viddev_template)); + video_set_drvdata(radio->videodev, radio); + + /* power up : need 110ms */ + radio->registers[POWERCFG] = POWERCFG_ENABLE; + if (si470x_set_register(radio, POWERCFG) < 0) { + retval = -EIO; + goto err_video; + } + msleep(110); + + /* get device and chip versions */ + if (si470x_get_all_registers(radio) < 0) { + retval = -EIO; + goto err_video; + } + dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID]); + if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) { + dev_warn(&client->dev, + "This driver is known to work with " + "firmware version %hu,\n", RADIO_FW_VERSION); + dev_warn(&client->dev, + "but the device has firmware version %hu.\n", + radio->registers[CHIPID] & CHIPID_FIRMWARE); + version_warning = 1; + } + + /* give out version warning */ + if (version_warning == 1) { + dev_warn(&client->dev, + "If you have some trouble using this driver,\n"); + dev_warn(&client->dev, + "please report to V4L ML at " + "linux-media@vger.kernel.org\n"); + } + + /* set initial frequency */ + si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ + + /* rds buffer allocation */ + radio->buf_size = rds_buf * 3; + radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); + if (!radio->buffer) { + retval = -EIO; + goto err_video; + } + + /* rds buffer configuration */ + radio->wr_index = 0; + radio->rd_index = 0; + init_waitqueue_head(&radio->read_queue); + + /* mark Seek/Tune Complete Interrupt enabled */ + radio->stci_enabled = true; + init_completion(&radio->completion); + + retval = request_threaded_irq(client->irq, NULL, si470x_i2c_interrupt, + IRQF_TRIGGER_FALLING, DRIVER_NAME, radio); + if (retval) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_rds; + } + + /* register video device */ + retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, + radio_nr); + if (retval) { + dev_warn(&client->dev, "Could not register video device\n"); + goto err_all; + } + i2c_set_clientdata(client, radio); + + return 0; +err_all: + free_irq(client->irq, radio); +err_rds: + kfree(radio->buffer); +err_video: + video_device_release(radio->videodev); +err_radio: + kfree(radio); +err_initial: + return retval; +} + + +/* + * si470x_i2c_remove - remove the device + */ +static __devexit int si470x_i2c_remove(struct i2c_client *client) +{ + struct si470x_device *radio = i2c_get_clientdata(client); + + free_irq(client->irq, radio); + video_unregister_device(radio->videodev); + kfree(radio); + + return 0; +} + + +#ifdef CONFIG_PM +/* + * si470x_i2c_suspend - suspend the device + */ +static int si470x_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct si470x_device *radio = i2c_get_clientdata(client); + + /* power down */ + radio->registers[POWERCFG] |= POWERCFG_DISABLE; + if (si470x_set_register(radio, POWERCFG) < 0) + return -EIO; + + return 0; +} + + +/* + * si470x_i2c_resume - resume the device + */ +static int si470x_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct si470x_device *radio = i2c_get_clientdata(client); + + /* power up : need 110ms */ + radio->registers[POWERCFG] |= POWERCFG_ENABLE; + if (si470x_set_register(radio, POWERCFG) < 0) + return -EIO; + msleep(110); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(si470x_i2c_pm, si470x_i2c_suspend, si470x_i2c_resume); +#endif + + +/* + * si470x_i2c_driver - i2c driver interface + */ +static struct i2c_driver si470x_i2c_driver = { + .driver = { + .name = "si470x", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &si470x_i2c_pm, +#endif + }, + .probe = si470x_i2c_probe, + .remove = __devexit_p(si470x_i2c_remove), + .id_table = si470x_i2c_id, +}; + + + +/************************************************************************** + * Module Interface + **************************************************************************/ + +/* + * si470x_i2c_init - module init + */ +static int __init si470x_i2c_init(void) +{ + printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); + return i2c_add_driver(&si470x_i2c_driver); +} + + +/* + * si470x_i2c_exit - module exit + */ +static void __exit si470x_i2c_exit(void) +{ + i2c_del_driver(&si470x_i2c_driver); +} + + +module_init(si470x_i2c_init); +module_exit(si470x_i2c_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-usb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-usb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-usb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si470x/radio-si470x-usb.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,898 @@ +/* + * drivers/media/radio/si470x/radio-si470x-usb.c + * + * USB driver for radios with Silicon Labs Si470x FM Radio Receivers + * + * Copyright (c) 2009 Tobias Lorenz + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + + +/* + * ToDo: + * - add firmware download/update support + */ + + +/* driver definitions */ +#define DRIVER_AUTHOR "Tobias Lorenz " +#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 10) +#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" +#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" +#define DRIVER_VERSION "1.0.10" + +/* kernel includes */ +#include +#include +#include + +#include "radio-si470x.h" + + +/* USB Device ID List */ +static struct usb_device_id si470x_usb_driver_id_table[] = { + /* Silicon Labs USB FM Radio Reference Design */ + { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, + /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) }, + /* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) }, + /* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) }, + /* Terminating entry */ + { } +}; +MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table); + + + +/************************************************************************** + * Module Parameters + **************************************************************************/ + +/* Radio Nr */ +static int radio_nr = -1; +module_param(radio_nr, int, 0444); +MODULE_PARM_DESC(radio_nr, "Radio Nr"); + +/* USB timeout */ +static unsigned int usb_timeout = 500; +module_param(usb_timeout, uint, 0644); +MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*"); + +/* RDS buffer blocks */ +static unsigned int rds_buf = 100; +module_param(rds_buf, uint, 0444); +MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); + +/* RDS maximum block errors */ +static unsigned short max_rds_errors = 1; +/* 0 means 0 errors requiring correction */ +/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ +/* 2 means 3-5 errors requiring correction */ +/* 3 means 6+ errors or errors in checkword, correction not possible */ +module_param(max_rds_errors, ushort, 0644); +MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); + + + +/************************************************************************** + * USB HID Reports + **************************************************************************/ + +/* Reports 1-16 give direct read/write access to the 16 Si470x registers */ +/* with the (REPORT_ID - 1) corresponding to the register address across USB */ +/* endpoint 0 using GET_REPORT and SET_REPORT */ +#define REGISTER_REPORT_SIZE (RADIO_REGISTER_SIZE + 1) +#define REGISTER_REPORT(reg) ((reg) + 1) + +/* Report 17 gives direct read/write access to the entire Si470x register */ +/* map across endpoint 0 using GET_REPORT and SET_REPORT */ +#define ENTIRE_REPORT_SIZE (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) +#define ENTIRE_REPORT 17 + +/* Report 18 is used to send the lowest 6 Si470x registers up the HID */ +/* interrupt endpoint 1 to Windows every 20 milliseconds for status */ +#define RDS_REPORT_SIZE (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) +#define RDS_REPORT 18 + +/* Report 19: LED state */ +#define LED_REPORT_SIZE 3 +#define LED_REPORT 19 + +/* Report 19: stream */ +#define STREAM_REPORT_SIZE 3 +#define STREAM_REPORT 19 + +/* Report 20: scratch */ +#define SCRATCH_PAGE_SIZE 63 +#define SCRATCH_REPORT_SIZE (SCRATCH_PAGE_SIZE + 1) +#define SCRATCH_REPORT 20 + +/* Reports 19-22: flash upgrade of the C8051F321 */ +#define WRITE_REPORT_SIZE 4 +#define WRITE_REPORT 19 +#define FLASH_REPORT_SIZE 64 +#define FLASH_REPORT 20 +#define CRC_REPORT_SIZE 3 +#define CRC_REPORT 21 +#define RESPONSE_REPORT_SIZE 2 +#define RESPONSE_REPORT 22 + +/* Report 23: currently unused, but can accept 60 byte reports on the HID */ +/* interrupt out endpoint 2 every 1 millisecond */ +#define UNUSED_REPORT 23 + + + +/************************************************************************** + * Software/Hardware Versions from Scratch Page + **************************************************************************/ +#define RADIO_SW_VERSION_NOT_BOOTLOADABLE 6 +#define RADIO_SW_VERSION 7 +#define RADIO_HW_VERSION 1 + + + +/************************************************************************** + * LED State Definitions + **************************************************************************/ +#define LED_COMMAND 0x35 + +#define NO_CHANGE_LED 0x00 +#define ALL_COLOR_LED 0x01 /* streaming state */ +#define BLINK_GREEN_LED 0x02 /* connect state */ +#define BLINK_RED_LED 0x04 +#define BLINK_ORANGE_LED 0x10 /* disconnect state */ +#define SOLID_GREEN_LED 0x20 /* tuning/seeking state */ +#define SOLID_RED_LED 0x40 /* bootload state */ +#define SOLID_ORANGE_LED 0x80 + + + +/************************************************************************** + * Stream State Definitions + **************************************************************************/ +#define STREAM_COMMAND 0x36 +#define STREAM_VIDPID 0x00 +#define STREAM_AUDIO 0xff + + + +/************************************************************************** + * Bootloader / Flash Commands + **************************************************************************/ + +/* unique id sent to bootloader and required to put into a bootload state */ +#define UNIQUE_BL_ID 0x34 + +/* mask for the flash data */ +#define FLASH_DATA_MASK 0x55 + +/* bootloader commands */ +#define GET_SW_VERSION_COMMAND 0x00 +#define SET_PAGE_COMMAND 0x01 +#define ERASE_PAGE_COMMAND 0x02 +#define WRITE_PAGE_COMMAND 0x03 +#define CRC_ON_PAGE_COMMAND 0x04 +#define READ_FLASH_BYTE_COMMAND 0x05 +#define RESET_DEVICE_COMMAND 0x06 +#define GET_HW_VERSION_COMMAND 0x07 +#define BLANK 0xff + +/* bootloader command responses */ +#define COMMAND_OK 0x01 +#define COMMAND_FAILED 0x02 +#define COMMAND_PENDING 0x03 + + + +/************************************************************************** + * General Driver Functions - REGISTER_REPORTs + **************************************************************************/ + +/* + * si470x_get_report - receive a HID report + */ +static int si470x_get_report(struct si470x_device *radio, void *buf, int size) +{ + unsigned char *report = (unsigned char *) buf; + int retval; + + retval = usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + HID_REQ_GET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + report[0], 2, + buf, size, usb_timeout); + + if (retval < 0) + dev_warn(&radio->intf->dev, + "si470x_get_report: usb_control_msg returned %d\n", + retval); + return retval; +} + + +/* + * si470x_set_report - send a HID report + */ +static int si470x_set_report(struct si470x_device *radio, void *buf, int size) +{ + unsigned char *report = (unsigned char *) buf; + int retval; + + retval = usb_control_msg(radio->usbdev, + usb_sndctrlpipe(radio->usbdev, 0), + HID_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + report[0], 2, + buf, size, usb_timeout); + + if (retval < 0) + dev_warn(&radio->intf->dev, + "si470x_set_report: usb_control_msg returned %d\n", + retval); + return retval; +} + + +/* + * si470x_get_register - read register + */ +int si470x_get_register(struct si470x_device *radio, int regnr) +{ + unsigned char buf[REGISTER_REPORT_SIZE]; + int retval; + + buf[0] = REGISTER_REPORT(regnr); + + retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); + + if (retval >= 0) + radio->registers[regnr] = get_unaligned_be16(&buf[1]); + + return (retval < 0) ? -EINVAL : 0; +} + + +/* + * si470x_set_register - write register + */ +int si470x_set_register(struct si470x_device *radio, int regnr) +{ + unsigned char buf[REGISTER_REPORT_SIZE]; + int retval; + + buf[0] = REGISTER_REPORT(regnr); + put_unaligned_be16(radio->registers[regnr], &buf[1]); + + retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); + + return (retval < 0) ? -EINVAL : 0; +} + + + +/************************************************************************** + * General Driver Functions - ENTIRE_REPORT + **************************************************************************/ + +/* + * si470x_get_all_registers - read entire registers + */ +static int si470x_get_all_registers(struct si470x_device *radio) +{ + unsigned char buf[ENTIRE_REPORT_SIZE]; + int retval; + unsigned char regnr; + + buf[0] = ENTIRE_REPORT; + + retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); + + if (retval >= 0) + for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) + radio->registers[regnr] = get_unaligned_be16( + &buf[regnr * RADIO_REGISTER_SIZE + 1]); + + return (retval < 0) ? -EINVAL : 0; +} + + + +/************************************************************************** + * General Driver Functions - LED_REPORT + **************************************************************************/ + +/* + * si470x_set_led_state - sets the led state + */ +static int si470x_set_led_state(struct si470x_device *radio, + unsigned char led_state) +{ + unsigned char buf[LED_REPORT_SIZE]; + int retval; + + buf[0] = LED_REPORT; + buf[1] = LED_COMMAND; + buf[2] = led_state; + + retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); + + return (retval < 0) ? -EINVAL : 0; +} + + + +/************************************************************************** + * General Driver Functions - SCRATCH_REPORT + **************************************************************************/ + +/* + * si470x_get_scratch_versions - gets the scratch page and version infos + */ +static int si470x_get_scratch_page_versions(struct si470x_device *radio) +{ + unsigned char buf[SCRATCH_REPORT_SIZE]; + int retval; + + buf[0] = SCRATCH_REPORT; + + retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); + + if (retval < 0) + dev_warn(&radio->intf->dev, "si470x_get_scratch: " + "si470x_get_report returned %d\n", retval); + else { + radio->software_version = buf[1]; + radio->hardware_version = buf[2]; + } + + return (retval < 0) ? -EINVAL : 0; +} + + + +/************************************************************************** + * General Driver Functions - DISCONNECT_CHECK + **************************************************************************/ + +/* + * si470x_disconnect_check - check whether radio disconnects + */ +int si470x_disconnect_check(struct si470x_device *radio) +{ + if (radio->disconnected) + return -EIO; + else + return 0; +} + + + +/************************************************************************** + * RDS Driver Functions + **************************************************************************/ + +/* + * si470x_int_in_callback - rds callback and processing function + * + * TODO: do we need to use mutex locks in some sections? + */ +static void si470x_int_in_callback(struct urb *urb) +{ + struct si470x_device *radio = urb->context; + unsigned char buf[RDS_REPORT_SIZE]; + int retval; + unsigned char regnr; + unsigned char blocknum; + unsigned short bler; /* rds block errors */ + unsigned short rds; + unsigned char tmpbuf[3]; + + if (urb->status) { + if (urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN) { + return; + } else { + dev_warn(&radio->intf->dev, + "non-zero urb status (%d)\n", urb->status); + goto resubmit; /* Maybe we can recover. */ + } + } + + /* safety checks */ + if (radio->disconnected) + return; + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) + goto resubmit; + + if (urb->actual_length > 0) { + /* Update RDS registers with URB data */ + buf[0] = RDS_REPORT; + for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) + radio->registers[STATUSRSSI + regnr] = + get_unaligned_be16(&radio->int_in_buffer[ + regnr * RADIO_REGISTER_SIZE + 1]); + /* get rds blocks */ + if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) { + /* No RDS group ready, better luck next time */ + goto resubmit; + } + if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) { + /* RDS decoder not synchronized */ + goto resubmit; + } + for (blocknum = 0; blocknum < 4; blocknum++) { + switch (blocknum) { + default: + bler = (radio->registers[STATUSRSSI] & + STATUSRSSI_BLERA) >> 9; + rds = radio->registers[RDSA]; + break; + case 1: + bler = (radio->registers[READCHAN] & + READCHAN_BLERB) >> 14; + rds = radio->registers[RDSB]; + break; + case 2: + bler = (radio->registers[READCHAN] & + READCHAN_BLERC) >> 12; + rds = radio->registers[RDSC]; + break; + case 3: + bler = (radio->registers[READCHAN] & + READCHAN_BLERD) >> 10; + rds = radio->registers[RDSD]; + break; + }; + + /* Fill the V4L2 RDS buffer */ + put_unaligned_le16(rds, &tmpbuf); + tmpbuf[2] = blocknum; /* offset name */ + tmpbuf[2] |= blocknum << 3; /* received offset */ + if (bler > max_rds_errors) + tmpbuf[2] |= 0x80; /* uncorrectable errors */ + else if (bler > 0) + tmpbuf[2] |= 0x40; /* corrected error(s) */ + + /* copy RDS block to internal buffer */ + memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); + radio->wr_index += 3; + + /* wrap write pointer */ + if (radio->wr_index >= radio->buf_size) + radio->wr_index = 0; + + /* check for overflow */ + if (radio->wr_index == radio->rd_index) { + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + } + } + if (radio->wr_index != radio->rd_index) + wake_up_interruptible(&radio->read_queue); + } + +resubmit: + /* Resubmit if we're still running. */ + if (radio->int_in_running && radio->usbdev) { + retval = usb_submit_urb(radio->int_in_urb, GFP_ATOMIC); + if (retval) { + dev_warn(&radio->intf->dev, + "resubmitting urb failed (%d)", retval); + radio->int_in_running = 0; + } + } +} + + + +/************************************************************************** + * File Operations Interface + **************************************************************************/ + +/* + * si470x_fops_open - file open + */ +int si470x_fops_open(struct file *file) +{ + struct si470x_device *radio = video_drvdata(file); + int retval; + + mutex_lock(&radio->lock); + radio->users++; + + retval = usb_autopm_get_interface(radio->intf); + if (retval < 0) { + radio->users--; + retval = -EIO; + goto done; + } + + if (radio->users == 1) { + /* start radio */ + retval = si470x_start(radio); + if (retval < 0) { + usb_autopm_put_interface(radio->intf); + goto done; + } + + /* initialize interrupt urb */ + usb_fill_int_urb(radio->int_in_urb, radio->usbdev, + usb_rcvintpipe(radio->usbdev, + radio->int_in_endpoint->bEndpointAddress), + radio->int_in_buffer, + le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize), + si470x_int_in_callback, + radio, + radio->int_in_endpoint->bInterval); + + radio->int_in_running = 1; + mb(); + + retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL); + if (retval) { + dev_info(&radio->intf->dev, + "submitting int urb failed (%d)\n", retval); + radio->int_in_running = 0; + usb_autopm_put_interface(radio->intf); + } + } + +done: + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * si470x_fops_release - file release + */ +int si470x_fops_release(struct file *file) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + /* safety check */ + if (!radio) { + retval = -ENODEV; + goto done; + } + + mutex_lock(&radio->lock); + radio->users--; + if (radio->users == 0) { + /* shutdown interrupt handler */ + if (radio->int_in_running) { + radio->int_in_running = 0; + if (radio->int_in_urb) + usb_kill_urb(radio->int_in_urb); + } + + if (radio->disconnected) { + video_unregister_device(radio->videodev); + kfree(radio->int_in_buffer); + kfree(radio->buffer); + mutex_unlock(&radio->lock); + kfree(radio); + goto done; + } + + /* cancel read processes */ + wake_up_interruptible(&radio->read_queue); + + /* stop radio */ + retval = si470x_stop(radio); + usb_autopm_put_interface(radio->intf); + } + mutex_unlock(&radio->lock); +done: + return retval; +} + + + +/************************************************************************** + * Video4Linux Interface + **************************************************************************/ + +/* + * si470x_vidioc_querycap - query device capabilities + */ +int si470x_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + struct si470x_device *radio = video_drvdata(file); + + strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + usb_make_path(radio->usbdev, capability->bus_info, + sizeof(capability->bus_info)); + capability->version = DRIVER_KERNEL_VERSION; + capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | + V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; + + return 0; +} + + + +/************************************************************************** + * USB Interface + **************************************************************************/ + +/* + * si470x_usb_driver_probe - probe for the device + */ +static int si470x_usb_driver_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct si470x_device *radio; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int i, int_end_size, retval = 0; + unsigned char version_warning = 0; + + /* private data allocation and initialization */ + radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); + if (!radio) { + retval = -ENOMEM; + goto err_initial; + } + radio->users = 0; + radio->disconnected = 0; + radio->usbdev = interface_to_usbdev(intf); + radio->intf = intf; + mutex_init(&radio->lock); + + iface_desc = intf->cur_altsetting; + + /* Set up interrupt endpoint information. */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == + USB_DIR_IN) && ((endpoint->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) + radio->int_in_endpoint = endpoint; + } + if (!radio->int_in_endpoint) { + dev_info(&intf->dev, "could not find interrupt in endpoint\n"); + retval = -EIO; + goto err_radio; + } + + int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize); + + radio->int_in_buffer = kmalloc(int_end_size, GFP_KERNEL); + if (!radio->int_in_buffer) { + dev_info(&intf->dev, "could not allocate int_in_buffer"); + retval = -ENOMEM; + goto err_radio; + } + + radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!radio->int_in_urb) { + dev_info(&intf->dev, "could not allocate int_in_urb"); + retval = -ENOMEM; + goto err_intbuffer; + } + + /* video device allocation and initialization */ + radio->videodev = video_device_alloc(); + if (!radio->videodev) { + retval = -ENOMEM; + goto err_urb; + } + memcpy(radio->videodev, &si470x_viddev_template, + sizeof(si470x_viddev_template)); + video_set_drvdata(radio->videodev, radio); + + /* get device and chip versions */ + if (si470x_get_all_registers(radio) < 0) { + retval = -EIO; + goto err_video; + } + dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID]); + if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) { + dev_warn(&intf->dev, + "This driver is known to work with " + "firmware version %hu,\n", RADIO_FW_VERSION); + dev_warn(&intf->dev, + "but the device has firmware version %hu.\n", + radio->registers[CHIPID] & CHIPID_FIRMWARE); + version_warning = 1; + } + + /* get software and hardware versions */ + if (si470x_get_scratch_page_versions(radio) < 0) { + retval = -EIO; + goto err_video; + } + dev_info(&intf->dev, "software version %d, hardware version %d\n", + radio->software_version, radio->hardware_version); + if (radio->software_version < RADIO_SW_VERSION) { + dev_warn(&intf->dev, + "This driver is known to work with " + "software version %hu,\n", RADIO_SW_VERSION); + dev_warn(&intf->dev, + "but the device has software version %hu.\n", + radio->software_version); + version_warning = 1; + } + if (radio->hardware_version < RADIO_HW_VERSION) { + dev_warn(&intf->dev, + "This driver is known to work with " + "hardware version %hu,\n", RADIO_HW_VERSION); + dev_warn(&intf->dev, + "but the device has hardware version %hu.\n", + radio->hardware_version); + version_warning = 1; + } + + /* give out version warning */ + if (version_warning == 1) { + dev_warn(&intf->dev, + "If you have some trouble using this driver,\n"); + dev_warn(&intf->dev, + "please report to V4L ML at " + "linux-media@vger.kernel.org\n"); + } + + /* set initial frequency */ + si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ + + /* set led to connect state */ + si470x_set_led_state(radio, BLINK_GREEN_LED); + + /* rds buffer allocation */ + radio->buf_size = rds_buf * 3; + radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); + if (!radio->buffer) { + retval = -EIO; + goto err_video; + } + + /* rds buffer configuration */ + radio->wr_index = 0; + radio->rd_index = 0; + init_waitqueue_head(&radio->read_queue); + + /* register video device */ + retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, + radio_nr); + if (retval) { + dev_warn(&intf->dev, "Could not register video device\n"); + goto err_all; + } + usb_set_intfdata(intf, radio); + + return 0; +err_all: + kfree(radio->buffer); +err_video: + video_device_release(radio->videodev); +err_urb: + usb_free_urb(radio->int_in_urb); +err_intbuffer: + kfree(radio->int_in_buffer); +err_radio: + kfree(radio); +err_initial: + return retval; +} + + +/* + * si470x_usb_driver_suspend - suspend the device + */ +static int si470x_usb_driver_suspend(struct usb_interface *intf, + pm_message_t message) +{ + dev_info(&intf->dev, "suspending now...\n"); + + return 0; +} + + +/* + * si470x_usb_driver_resume - resume the device + */ +static int si470x_usb_driver_resume(struct usb_interface *intf) +{ + dev_info(&intf->dev, "resuming now...\n"); + + return 0; +} + + +/* + * si470x_usb_driver_disconnect - disconnect the device + */ +static void si470x_usb_driver_disconnect(struct usb_interface *intf) +{ + struct si470x_device *radio = usb_get_intfdata(intf); + + mutex_lock(&radio->lock); + radio->disconnected = 1; + usb_set_intfdata(intf, NULL); + if (radio->users == 0) { + /* set led to disconnect state */ + si470x_set_led_state(radio, BLINK_ORANGE_LED); + + /* Free data structures. */ + usb_free_urb(radio->int_in_urb); + + kfree(radio->int_in_buffer); + video_unregister_device(radio->videodev); + kfree(radio->buffer); + mutex_unlock(&radio->lock); + kfree(radio); + } else { + mutex_unlock(&radio->lock); + } +} + + +/* + * si470x_usb_driver - usb driver interface + */ +static struct usb_driver si470x_usb_driver = { + .name = DRIVER_NAME, + .probe = si470x_usb_driver_probe, + .disconnect = si470x_usb_driver_disconnect, + .suspend = si470x_usb_driver_suspend, + .resume = si470x_usb_driver_resume, + .id_table = si470x_usb_driver_id_table, + .supports_autosuspend = 1, +}; + + + +/************************************************************************** + * Module Interface + **************************************************************************/ + +/* + * si470x_module_init - module init + */ +static int __init si470x_module_init(void) +{ + printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); + return usb_register(&si470x_usb_driver); +} + + +/* + * si470x_module_exit - module exit + */ +static void __exit si470x_module_exit(void) +{ + usb_deregister(&si470x_usb_driver); +} + + +module_init(si470x_module_init); +module_exit(si470x_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si4713-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si4713-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si4713-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si4713-i2c.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,2120 @@ +/* + * drivers/media/radio/si4713-i2c.c + * + * Silicon Labs Si4713 FM Radio Transmitter I2C commands. + * + * Copyright (c) 2009 Nokia Corporation + * Contact: Eduardo Valentin + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "si4713-i2c.h" + +/* module parameters */ +static int debug; +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug level (0 - 2)"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eduardo Valentin "); +MODULE_DESCRIPTION("I2C driver for Si4713 FM Radio Transmitter"); + +static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = { + "vio", + "vdd", +}; + +#define DEFAULT_RDS_PI 0x00 +#define DEFAULT_RDS_PTY 0x00 +#define DEFAULT_RDS_PS_NAME "" +#define DEFAULT_RDS_RADIO_TEXT DEFAULT_RDS_PS_NAME +#define DEFAULT_RDS_DEVIATION 0x00C8 +#define DEFAULT_RDS_PS_REPEAT_COUNT 0x0003 +#define DEFAULT_LIMITER_RTIME 0x1392 +#define DEFAULT_LIMITER_DEV 0x102CA +#define DEFAULT_PILOT_FREQUENCY 0x4A38 +#define DEFAULT_PILOT_DEVIATION 0x1A5E +#define DEFAULT_ACOMP_ATIME 0x0000 +#define DEFAULT_ACOMP_RTIME 0xF4240L +#define DEFAULT_ACOMP_GAIN 0x0F +#define DEFAULT_ACOMP_THRESHOLD (-0x28) +#define DEFAULT_MUTE 0x01 +#define DEFAULT_POWER_LEVEL 88 +#define DEFAULT_FREQUENCY 8800 +#define DEFAULT_PREEMPHASIS FMPE_EU +#define DEFAULT_TUNE_RNL 0xFF + +#define to_si4713_device(sd) container_of(sd, struct si4713_device, sd) + +/* frequency domain transformation (using times 10 to avoid floats) */ +#define FREQDEV_UNIT 100000 +#define FREQV4L2_MULTI 625 +#define si4713_to_v4l2(f) ((f * FREQDEV_UNIT) / FREQV4L2_MULTI) +#define v4l2_to_si4713(f) ((f * FREQV4L2_MULTI) / FREQDEV_UNIT) +#define FREQ_RANGE_LOW 7600 +#define FREQ_RANGE_HIGH 10800 + +#define MAX_ARGS 7 + +#define RDS_BLOCK 8 +#define RDS_BLOCK_CLEAR 0x03 +#define RDS_BLOCK_LOAD 0x04 +#define RDS_RADIOTEXT_2A 0x20 +#define RDS_RADIOTEXT_BLK_SIZE 4 +#define RDS_RADIOTEXT_INDEX_MAX 0x0F +#define RDS_CARRIAGE_RETURN 0x0D + +#define rds_ps_nblocks(len) ((len / RDS_BLOCK) + (len % RDS_BLOCK ? 1 : 0)) + +#define get_status_bit(p, b, m) (((p) & (m)) >> (b)) +#define set_bits(p, v, b, m) (((p) & ~(m)) | ((v) << (b))) + +#define ATTACK_TIME_UNIT 500 + +#define POWER_OFF 0x00 +#define POWER_ON 0x01 + +#define msb(x) ((u8)((u16) x >> 8)) +#define lsb(x) ((u8)((u16) x & 0x00FF)) +#define compose_u16(msb, lsb) (((u16)msb << 8) | lsb) +#define check_command_failed(status) (!(status & SI4713_CTS) || \ + (status & SI4713_ERR)) +/* mute definition */ +#define set_mute(p) ((p & 1) | ((p & 1) << 1)); +#define get_mute(p) (p & 0x01) + +#ifdef DEBUG +#define DBG_BUFFER(device, message, buffer, size) \ + { \ + int i; \ + char str[(size)*5]; \ + for (i = 0; i < size; i++) \ + sprintf(str + i * 5, " 0x%02x", buffer[i]); \ + v4l2_dbg(2, debug, device, "%s:%s\n", message, str); \ + } +#else +#define DBG_BUFFER(device, message, buffer, size) +#endif + +/* + * Values for limiter release time (sorted by second column) + * device release + * value time (us) + */ +static long limiter_times[] = { + 2000, 250, + 1000, 500, + 510, 1000, + 255, 2000, + 170, 3000, + 127, 4020, + 102, 5010, + 85, 6020, + 73, 7010, + 64, 7990, + 57, 8970, + 51, 10030, + 25, 20470, + 17, 30110, + 13, 39380, + 10, 51190, + 8, 63690, + 7, 73140, + 6, 85330, + 5, 102390, +}; + +/* + * Values for audio compression release time (sorted by second column) + * device release + * value time (us) + */ +static unsigned long acomp_rtimes[] = { + 0, 100000, + 1, 200000, + 2, 350000, + 3, 525000, + 4, 1000000, +}; + +/* + * Values for preemphasis (sorted by second column) + * device preemphasis + * value value (v4l2) + */ +static unsigned long preemphasis_values[] = { + FMPE_DISABLED, V4L2_PREEMPHASIS_DISABLED, + FMPE_EU, V4L2_PREEMPHASIS_50_uS, + FMPE_USA, V4L2_PREEMPHASIS_75_uS, +}; + +static int usecs_to_dev(unsigned long usecs, unsigned long const array[], + int size) +{ + int i; + int rval = -EINVAL; + + for (i = 0; i < size / 2; i++) + if (array[(i * 2) + 1] >= usecs) { + rval = array[i * 2]; + break; + } + + return rval; +} + +static unsigned long dev_to_usecs(int value, unsigned long const array[], + int size) +{ + int i; + int rval = -EINVAL; + + for (i = 0; i < size / 2; i++) + if (array[i * 2] == value) { + rval = array[(i * 2) + 1]; + break; + } + + return rval; +} + +/* si4713_handler: IRQ handler, just complete work */ +static irqreturn_t si4713_handler(int irq, void *dev) +{ + struct si4713_device *sdev = dev; + + v4l2_dbg(2, debug, &sdev->sd, + "%s: sending signal to completion work.\n", __func__); + complete(&sdev->work); + + return IRQ_HANDLED; +} + +/* + * si4713_send_command - sends a command to si4713 and waits its response + * @sdev: si4713_device structure for the device we are communicating + * @command: command id + * @args: command arguments we are sending (up to 7) + * @argn: actual size of @args + * @response: buffer to place the expected response from the device (up to 15) + * @respn: actual size of @response + * @usecs: amount of time to wait before reading the response (in usecs) + */ +static int si4713_send_command(struct si4713_device *sdev, const u8 command, + const u8 args[], const int argn, + u8 response[], const int respn, const int usecs) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); + u8 data1[MAX_ARGS + 1]; + int err; + + if (!client->adapter) + return -ENODEV; + + /* First send the command and its arguments */ + data1[0] = command; + memcpy(data1 + 1, args, argn); + DBG_BUFFER(&sdev->sd, "Parameters", data1, argn + 1); + + err = i2c_master_send(client, data1, argn + 1); + if (err != argn + 1) { + v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n", + command); + return (err > 0) ? -EIO : err; + } + + /* Wait response from interrupt */ + if (!wait_for_completion_timeout(&sdev->work, + usecs_to_jiffies(usecs) + 1)) + v4l2_warn(&sdev->sd, + "(%s) Device took too much time to answer.\n", + __func__); + + /* Then get the response */ + err = i2c_master_recv(client, response, respn); + if (err != respn) { + v4l2_err(&sdev->sd, + "Error while reading response for command 0x%02x\n", + command); + return (err > 0) ? -EIO : err; + } + + DBG_BUFFER(&sdev->sd, "Response", response, respn); + if (check_command_failed(response[0])) + return -EBUSY; + + return 0; +} + +/* + * si4713_read_property - reads a si4713 property + * @sdev: si4713_device structure for the device we are communicating + * @prop: property identification number + * @pv: property value to be returned on success + */ +static int si4713_read_property(struct si4713_device *sdev, u16 prop, u32 *pv) +{ + int err; + u8 val[SI4713_GET_PROP_NRESP]; + /* + * .First byte = 0 + * .Second byte = property's MSB + * .Third byte = property's LSB + */ + const u8 args[SI4713_GET_PROP_NARGS] = { + 0x00, + msb(prop), + lsb(prop), + }; + + err = si4713_send_command(sdev, SI4713_CMD_GET_PROPERTY, + args, ARRAY_SIZE(args), val, + ARRAY_SIZE(val), DEFAULT_TIMEOUT); + + if (err < 0) + return err; + + *pv = compose_u16(val[2], val[3]); + + v4l2_dbg(1, debug, &sdev->sd, + "%s: property=0x%02x value=0x%02x status=0x%02x\n", + __func__, prop, *pv, val[0]); + + return err; +} + +/* + * si4713_write_property - modifies a si4713 property + * @sdev: si4713_device structure for the device we are communicating + * @prop: property identification number + * @val: new value for that property + */ +static int si4713_write_property(struct si4713_device *sdev, u16 prop, u16 val) +{ + int rval; + u8 resp[SI4713_SET_PROP_NRESP]; + /* + * .First byte = 0 + * .Second byte = property's MSB + * .Third byte = property's LSB + * .Fourth byte = value's MSB + * .Fifth byte = value's LSB + */ + const u8 args[SI4713_SET_PROP_NARGS] = { + 0x00, + msb(prop), + lsb(prop), + msb(val), + lsb(val), + }; + + rval = si4713_send_command(sdev, SI4713_CMD_SET_PROPERTY, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + DEFAULT_TIMEOUT); + + if (rval < 0) + return rval; + + v4l2_dbg(1, debug, &sdev->sd, + "%s: property=0x%02x value=0x%02x status=0x%02x\n", + __func__, prop, val, resp[0]); + + /* + * As there is no command response for SET_PROPERTY, + * wait Tcomp time to finish before proceed, in order + * to have property properly set. + */ + msleep(TIMEOUT_SET_PROPERTY); + + return rval; +} + +/* + * si4713_powerup - Powers the device up + * @sdev: si4713_device structure for the device we are communicating + */ +static int si4713_powerup(struct si4713_device *sdev) +{ + int err; + u8 resp[SI4713_PWUP_NRESP]; + /* + * .First byte = Enabled interrupts and boot function + * .Second byte = Input operation mode + */ + const u8 args[SI4713_PWUP_NARGS] = { + SI4713_PWUP_CTSIEN | SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX, + SI4713_PWUP_OPMOD_ANALOG, + }; + + if (sdev->power_state) + return 0; + + err = regulator_bulk_enable(ARRAY_SIZE(sdev->supplies), + sdev->supplies); + if (err) { + v4l2_err(&sdev->sd, "Failed to enable supplies: %d\n", err); + return err; + } + if (gpio_is_valid(sdev->gpio_reset)) { + udelay(50); + gpio_set_value(sdev->gpio_reset, 1); + } + + err = si4713_send_command(sdev, SI4713_CMD_POWER_UP, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + TIMEOUT_POWER_UP); + + if (!err) { + v4l2_dbg(1, debug, &sdev->sd, "Powerup response: 0x%02x\n", + resp[0]); + v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n"); + sdev->power_state = POWER_ON; + + err = si4713_write_property(sdev, SI4713_GPO_IEN, + SI4713_STC_INT | SI4713_CTS); + } else { + if (gpio_is_valid(sdev->gpio_reset)) + gpio_set_value(sdev->gpio_reset, 0); + err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies), + sdev->supplies); + if (err) + v4l2_err(&sdev->sd, + "Failed to disable supplies: %d\n", err); + } + + return err; +} + +/* + * si4713_powerdown - Powers the device down + * @sdev: si4713_device structure for the device we are communicating + */ +static int si4713_powerdown(struct si4713_device *sdev) +{ + int err; + u8 resp[SI4713_PWDN_NRESP]; + + if (!sdev->power_state) + return 0; + + err = si4713_send_command(sdev, SI4713_CMD_POWER_DOWN, + NULL, 0, + resp, ARRAY_SIZE(resp), + DEFAULT_TIMEOUT); + + if (!err) { + v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n", + resp[0]); + v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n"); + if (gpio_is_valid(sdev->gpio_reset)) + gpio_set_value(sdev->gpio_reset, 0); + err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies), + sdev->supplies); + if (err) + v4l2_err(&sdev->sd, + "Failed to disable supplies: %d\n", err); + sdev->power_state = POWER_OFF; + } + + return err; +} + +/* + * si4713_checkrev - Checks if we are treating a device with the correct rev. + * @sdev: si4713_device structure for the device we are communicating + */ +static int si4713_checkrev(struct si4713_device *sdev) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); + int rval; + u8 resp[SI4713_GETREV_NRESP]; + + mutex_lock(&sdev->mutex); + + rval = si4713_send_command(sdev, SI4713_CMD_GET_REV, + NULL, 0, + resp, ARRAY_SIZE(resp), + DEFAULT_TIMEOUT); + + if (rval < 0) + goto unlock; + + if (resp[1] == SI4713_PRODUCT_NUMBER) { + v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + } else { + v4l2_err(&sdev->sd, "Invalid product number\n"); + rval = -EINVAL; + } + +unlock: + mutex_unlock(&sdev->mutex); + return rval; +} + +/* + * si4713_wait_stc - Waits STC interrupt and clears status bits. Useful + * for TX_TUNE_POWER, TX_TUNE_FREQ and TX_TUNE_MEAS + * @sdev: si4713_device structure for the device we are communicating + * @usecs: timeout to wait for STC interrupt signal + */ +static int si4713_wait_stc(struct si4713_device *sdev, const int usecs) +{ + int err; + u8 resp[SI4713_GET_STATUS_NRESP]; + + /* Wait response from STC interrupt */ + if (!wait_for_completion_timeout(&sdev->work, + usecs_to_jiffies(usecs) + 1)) + v4l2_warn(&sdev->sd, + "%s: device took too much time to answer (%d usec).\n", + __func__, usecs); + + /* Clear status bits */ + err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS, + NULL, 0, + resp, ARRAY_SIZE(resp), + DEFAULT_TIMEOUT); + + if (err < 0) + goto exit; + + v4l2_dbg(1, debug, &sdev->sd, + "%s: status bits: 0x%02x\n", __func__, resp[0]); + + if (!(resp[0] & SI4713_STC_INT)) + err = -EIO; + +exit: + return err; +} + +/* + * si4713_tx_tune_freq - Sets the state of the RF carrier and sets the tuning + * frequency between 76 and 108 MHz in 10 kHz units and + * steps of 50 kHz. + * @sdev: si4713_device structure for the device we are communicating + * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz) + */ +static int si4713_tx_tune_freq(struct si4713_device *sdev, u16 frequency) +{ + int err; + u8 val[SI4713_TXFREQ_NRESP]; + /* + * .First byte = 0 + * .Second byte = frequency's MSB + * .Third byte = frequency's LSB + */ + const u8 args[SI4713_TXFREQ_NARGS] = { + 0x00, + msb(frequency), + lsb(frequency), + }; + + err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_FREQ, + args, ARRAY_SIZE(args), val, + ARRAY_SIZE(val), DEFAULT_TIMEOUT); + + if (err < 0) + return err; + + v4l2_dbg(1, debug, &sdev->sd, + "%s: frequency=0x%02x status=0x%02x\n", __func__, + frequency, val[0]); + + err = si4713_wait_stc(sdev, TIMEOUT_TX_TUNE); + if (err < 0) + return err; + + return compose_u16(args[1], args[2]); +} + +/* + * si4713_tx_tune_power - Sets the RF voltage level between 88 and 115 dBuV in + * 1 dB units. A value of 0x00 indicates off. The command + * also sets the antenna tuning capacitance. A value of 0 + * indicates autotuning, and a value of 1 - 191 indicates + * a manual override, which results in a tuning + * capacitance of 0.25 pF x @antcap. + * @sdev: si4713_device structure for the device we are communicating + * @power: tuning power (88 - 115 dBuV, unit/step 1 dB) + * @antcap: value of antenna tuning capacitor (0 - 191) + */ +static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power, + u8 antcap) +{ + int err; + u8 val[SI4713_TXPWR_NRESP]; + /* + * .First byte = 0 + * .Second byte = 0 + * .Third byte = power + * .Fourth byte = antcap + */ + const u8 args[SI4713_TXPWR_NARGS] = { + 0x00, + 0x00, + power, + antcap, + }; + + if (((power > 0) && (power < SI4713_MIN_POWER)) || + power > SI4713_MAX_POWER || antcap > SI4713_MAX_ANTCAP) + return -EDOM; + + err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_POWER, + args, ARRAY_SIZE(args), val, + ARRAY_SIZE(val), DEFAULT_TIMEOUT); + + if (err < 0) + return err; + + v4l2_dbg(1, debug, &sdev->sd, + "%s: power=0x%02x antcap=0x%02x status=0x%02x\n", + __func__, power, antcap, val[0]); + + return si4713_wait_stc(sdev, TIMEOUT_TX_TUNE_POWER); +} + +/* + * si4713_tx_tune_measure - Enters receive mode and measures the received noise + * level in units of dBuV on the selected frequency. + * The Frequency must be between 76 and 108 MHz in 10 kHz + * units and steps of 50 kHz. The command also sets the + * antenna tuning capacitance. A value of 0 means + * autotuning, and a value of 1 to 191 indicates manual + * override. + * @sdev: si4713_device structure for the device we are communicating + * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz) + * @antcap: value of antenna tuning capacitor (0 - 191) + */ +static int si4713_tx_tune_measure(struct si4713_device *sdev, u16 frequency, + u8 antcap) +{ + int err; + u8 val[SI4713_TXMEA_NRESP]; + /* + * .First byte = 0 + * .Second byte = frequency's MSB + * .Third byte = frequency's LSB + * .Fourth byte = antcap + */ + const u8 args[SI4713_TXMEA_NARGS] = { + 0x00, + msb(frequency), + lsb(frequency), + antcap, + }; + + sdev->tune_rnl = DEFAULT_TUNE_RNL; + + if (antcap > SI4713_MAX_ANTCAP) + return -EDOM; + + err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_MEASURE, + args, ARRAY_SIZE(args), val, + ARRAY_SIZE(val), DEFAULT_TIMEOUT); + + if (err < 0) + return err; + + v4l2_dbg(1, debug, &sdev->sd, + "%s: frequency=0x%02x antcap=0x%02x status=0x%02x\n", + __func__, frequency, antcap, val[0]); + + return si4713_wait_stc(sdev, TIMEOUT_TX_TUNE); +} + +/* + * si4713_tx_tune_status- Returns the status of the tx_tune_freq, tx_tune_mea or + * tx_tune_power commands. This command return the current + * frequency, output voltage in dBuV, the antenna tunning + * capacitance value and the received noise level. The + * command also clears the stcint interrupt bit when the + * first bit of its arguments is high. + * @sdev: si4713_device structure for the device we are communicating + * @intack: 0x01 to clear the seek/tune complete interrupt status indicator. + * @frequency: returned frequency + * @power: returned power + * @antcap: returned antenna capacitance + * @noise: returned noise level + */ +static int si4713_tx_tune_status(struct si4713_device *sdev, u8 intack, + u16 *frequency, u8 *power, + u8 *antcap, u8 *noise) +{ + int err; + u8 val[SI4713_TXSTATUS_NRESP]; + /* + * .First byte = intack bit + */ + const u8 args[SI4713_TXSTATUS_NARGS] = { + intack & SI4713_INTACK_MASK, + }; + + err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_STATUS, + args, ARRAY_SIZE(args), val, + ARRAY_SIZE(val), DEFAULT_TIMEOUT); + + if (!err) { + v4l2_dbg(1, debug, &sdev->sd, + "%s: status=0x%02x\n", __func__, val[0]); + *frequency = compose_u16(val[2], val[3]); + sdev->frequency = *frequency; + *power = val[5]; + *antcap = val[6]; + *noise = val[7]; + v4l2_dbg(1, debug, &sdev->sd, "%s: response: %d x 10 kHz " + "(power %d, antcap %d, rnl %d)\n", __func__, + *frequency, *power, *antcap, *noise); + } + + return err; +} + +/* + * si4713_tx_rds_buff - Loads the RDS group buffer FIFO or circular buffer. + * @sdev: si4713_device structure for the device we are communicating + * @mode: the buffer operation mode. + * @rdsb: RDS Block B + * @rdsc: RDS Block C + * @rdsd: RDS Block D + * @cbleft: returns the number of available circular buffer blocks minus the + * number of used circular buffer blocks. + */ +static int si4713_tx_rds_buff(struct si4713_device *sdev, u8 mode, u16 rdsb, + u16 rdsc, u16 rdsd, s8 *cbleft) +{ + int err; + u8 val[SI4713_RDSBUFF_NRESP]; + + const u8 args[SI4713_RDSBUFF_NARGS] = { + mode & SI4713_RDSBUFF_MODE_MASK, + msb(rdsb), + lsb(rdsb), + msb(rdsc), + lsb(rdsc), + msb(rdsd), + lsb(rdsd), + }; + + err = si4713_send_command(sdev, SI4713_CMD_TX_RDS_BUFF, + args, ARRAY_SIZE(args), val, + ARRAY_SIZE(val), DEFAULT_TIMEOUT); + + if (!err) { + v4l2_dbg(1, debug, &sdev->sd, + "%s: status=0x%02x\n", __func__, val[0]); + *cbleft = (s8)val[2] - val[3]; + v4l2_dbg(1, debug, &sdev->sd, "%s: response: interrupts" + " 0x%02x cb avail: %d cb used %d fifo avail" + " %d fifo used %d\n", __func__, val[1], + val[2], val[3], val[4], val[5]); + } + + return err; +} + +/* + * si4713_tx_rds_ps - Loads the program service buffer. + * @sdev: si4713_device structure for the device we are communicating + * @psid: program service id to be loaded. + * @pschar: assumed 4 size char array to be loaded into the program service + */ +static int si4713_tx_rds_ps(struct si4713_device *sdev, u8 psid, + unsigned char *pschar) +{ + int err; + u8 val[SI4713_RDSPS_NRESP]; + + const u8 args[SI4713_RDSPS_NARGS] = { + psid & SI4713_RDSPS_PSID_MASK, + pschar[0], + pschar[1], + pschar[2], + pschar[3], + }; + + err = si4713_send_command(sdev, SI4713_CMD_TX_RDS_PS, + args, ARRAY_SIZE(args), val, + ARRAY_SIZE(val), DEFAULT_TIMEOUT); + + if (err < 0) + return err; + + v4l2_dbg(1, debug, &sdev->sd, "%s: status=0x%02x\n", __func__, val[0]); + + return err; +} + +static int si4713_set_power_state(struct si4713_device *sdev, u8 value) +{ + int rval; + + mutex_lock(&sdev->mutex); + + if (value) + rval = si4713_powerup(sdev); + else + rval = si4713_powerdown(sdev); + + mutex_unlock(&sdev->mutex); + return rval; +} + +static int si4713_set_mute(struct si4713_device *sdev, u16 mute) +{ + int rval = 0; + + mute = set_mute(mute); + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) + rval = si4713_write_property(sdev, + SI4713_TX_LINE_INPUT_MUTE, mute); + + if (rval >= 0) + sdev->mute = get_mute(mute); + + mutex_unlock(&sdev->mutex); + + return rval; +} + +static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name) +{ + int rval = 0, i; + u8 len = 0; + + /* We want to clear the whole thing */ + if (!strlen(ps_name)) + memset(ps_name, 0, MAX_RDS_PS_NAME + 1); + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) { + /* Write the new ps name and clear the padding */ + for (i = 0; i < MAX_RDS_PS_NAME; i += (RDS_BLOCK / 2)) { + rval = si4713_tx_rds_ps(sdev, (i / (RDS_BLOCK / 2)), + ps_name + i); + if (rval < 0) + goto unlock; + } + + /* Setup the size to be sent */ + if (strlen(ps_name)) + len = strlen(ps_name) - 1; + else + len = 1; + + rval = si4713_write_property(sdev, + SI4713_TX_RDS_PS_MESSAGE_COUNT, + rds_ps_nblocks(len)); + if (rval < 0) + goto unlock; + + rval = si4713_write_property(sdev, + SI4713_TX_RDS_PS_REPEAT_COUNT, + DEFAULT_RDS_PS_REPEAT_COUNT * 2); + if (rval < 0) + goto unlock; + } + + strncpy(sdev->rds_info.ps_name, ps_name, MAX_RDS_PS_NAME); + +unlock: + mutex_unlock(&sdev->mutex); + return rval; +} + +static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt) +{ + int rval = 0, i; + u16 t_index = 0; + u8 b_index = 0, cr_inserted = 0; + s8 left; + + mutex_lock(&sdev->mutex); + + if (!sdev->power_state) + goto copy; + + rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_CLEAR, 0, 0, 0, &left); + if (rval < 0) + goto unlock; + + if (!strlen(rt)) + goto copy; + + do { + /* RDS spec says that if the last block isn't used, + * then apply a carriage return + */ + if (t_index < (RDS_RADIOTEXT_INDEX_MAX * + RDS_RADIOTEXT_BLK_SIZE)) { + for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) { + if (!rt[t_index + i] || rt[t_index + i] == + RDS_CARRIAGE_RETURN) { + rt[t_index + i] = RDS_CARRIAGE_RETURN; + cr_inserted = 1; + break; + } + } + } + + rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_LOAD, + compose_u16(RDS_RADIOTEXT_2A, b_index++), + compose_u16(rt[t_index], rt[t_index + 1]), + compose_u16(rt[t_index + 2], rt[t_index + 3]), + &left); + if (rval < 0) + goto unlock; + + t_index += RDS_RADIOTEXT_BLK_SIZE; + + if (cr_inserted) + break; + } while (left > 0); + +copy: + strncpy(sdev->rds_info.radio_text, rt, MAX_RDS_RADIO_TEXT); + +unlock: + mutex_unlock(&sdev->mutex); + return rval; +} + +static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id, + u32 **shadow, s32 *bit, s32 *mask, u16 *property, int *mul, + unsigned long **table, int *size) +{ + s32 rval = 0; + + switch (id) { + /* FM_TX class controls */ + case V4L2_CID_RDS_TX_PI: + *property = SI4713_TX_RDS_PI; + *mul = 1; + *shadow = &sdev->rds_info.pi; + break; + case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: + *property = SI4713_TX_ACOMP_THRESHOLD; + *mul = 1; + *shadow = &sdev->acomp_info.threshold; + break; + case V4L2_CID_AUDIO_COMPRESSION_GAIN: + *property = SI4713_TX_ACOMP_GAIN; + *mul = 1; + *shadow = &sdev->acomp_info.gain; + break; + case V4L2_CID_PILOT_TONE_FREQUENCY: + *property = SI4713_TX_PILOT_FREQUENCY; + *mul = 1; + *shadow = &sdev->pilot_info.frequency; + break; + case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: + *property = SI4713_TX_ACOMP_ATTACK_TIME; + *mul = ATTACK_TIME_UNIT; + *shadow = &sdev->acomp_info.attack_time; + break; + case V4L2_CID_PILOT_TONE_DEVIATION: + *property = SI4713_TX_PILOT_DEVIATION; + *mul = 10; + *shadow = &sdev->pilot_info.deviation; + break; + case V4L2_CID_AUDIO_LIMITER_DEVIATION: + *property = SI4713_TX_AUDIO_DEVIATION; + *mul = 10; + *shadow = &sdev->limiter_info.deviation; + break; + case V4L2_CID_RDS_TX_DEVIATION: + *property = SI4713_TX_RDS_DEVIATION; + *mul = 1; + *shadow = &sdev->rds_info.deviation; + break; + + case V4L2_CID_RDS_TX_PTY: + *property = SI4713_TX_RDS_PS_MISC; + *bit = 5; + *mask = 0x1F << 5; + *shadow = &sdev->rds_info.pty; + break; + case V4L2_CID_AUDIO_LIMITER_ENABLED: + *property = SI4713_TX_ACOMP_ENABLE; + *bit = 1; + *mask = 1 << 1; + *shadow = &sdev->limiter_info.enabled; + break; + case V4L2_CID_AUDIO_COMPRESSION_ENABLED: + *property = SI4713_TX_ACOMP_ENABLE; + *bit = 0; + *mask = 1 << 0; + *shadow = &sdev->acomp_info.enabled; + break; + case V4L2_CID_PILOT_TONE_ENABLED: + *property = SI4713_TX_COMPONENT_ENABLE; + *bit = 0; + *mask = 1 << 0; + *shadow = &sdev->pilot_info.enabled; + break; + + case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: + *property = SI4713_TX_LIMITER_RELEASE_TIME; + *table = limiter_times; + *size = ARRAY_SIZE(limiter_times); + *shadow = &sdev->limiter_info.release_time; + break; + case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: + *property = SI4713_TX_ACOMP_RELEASE_TIME; + *table = acomp_rtimes; + *size = ARRAY_SIZE(acomp_rtimes); + *shadow = &sdev->acomp_info.release_time; + break; + case V4L2_CID_TUNE_PREEMPHASIS: + *property = SI4713_TX_PREEMPHASIS; + *table = preemphasis_values; + *size = ARRAY_SIZE(preemphasis_values); + *shadow = &sdev->preemphasis; + break; + + default: + rval = -EINVAL; + }; + + return rval; +} + +static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc); + +/* write string property */ +static int si4713_write_econtrol_string(struct si4713_device *sdev, + struct v4l2_ext_control *control) +{ + struct v4l2_queryctrl vqc; + int len; + s32 rval = 0; + + vqc.id = control->id; + rval = si4713_queryctrl(&sdev->sd, &vqc); + if (rval < 0) + goto exit; + + switch (control->id) { + case V4L2_CID_RDS_TX_PS_NAME: { + char ps_name[MAX_RDS_PS_NAME + 1]; + + len = control->size - 1; + if (len > MAX_RDS_PS_NAME) { + rval = -ERANGE; + goto exit; + } + rval = copy_from_user(ps_name, control->string, len); + if (rval) { + rval = -EFAULT; + goto exit; + } + ps_name[len] = '\0'; + + if (strlen(ps_name) % vqc.step) { + rval = -ERANGE; + goto exit; + } + + rval = si4713_set_rds_ps_name(sdev, ps_name); + } + break; + + case V4L2_CID_RDS_TX_RADIO_TEXT: { + char radio_text[MAX_RDS_RADIO_TEXT + 1]; + + len = control->size - 1; + if (len > MAX_RDS_RADIO_TEXT) { + rval = -ERANGE; + goto exit; + } + rval = copy_from_user(radio_text, control->string, len); + if (rval) { + rval = -EFAULT; + goto exit; + } + radio_text[len] = '\0'; + + if (strlen(radio_text) % vqc.step) { + rval = -ERANGE; + goto exit; + } + + rval = si4713_set_rds_radio_text(sdev, radio_text); + } + break; + + default: + rval = -EINVAL; + break; + }; + +exit: + return rval; +} + +static int validate_range(struct v4l2_subdev *sd, + struct v4l2_ext_control *control) +{ + struct v4l2_queryctrl vqc; + int rval; + + vqc.id = control->id; + rval = si4713_queryctrl(sd, &vqc); + if (rval < 0) + goto exit; + + if (control->value < vqc.minimum || control->value > vqc.maximum) + rval = -ERANGE; + +exit: + return rval; +} + +/* properties which use tx_tune_power*/ +static int si4713_write_econtrol_tune(struct si4713_device *sdev, + struct v4l2_ext_control *control) +{ + s32 rval = 0; + u8 power, antcap; + + rval = validate_range(&sdev->sd, control); + if (rval < 0) + goto exit; + + mutex_lock(&sdev->mutex); + + switch (control->id) { + case V4L2_CID_TUNE_POWER_LEVEL: + power = control->value; + antcap = sdev->antenna_capacitor; + break; + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + power = sdev->power_level; + antcap = control->value; + break; + default: + rval = -EINVAL; + goto unlock; + }; + + if (sdev->power_state) + rval = si4713_tx_tune_power(sdev, power, antcap); + + if (rval == 0) { + sdev->power_level = power; + sdev->antenna_capacitor = antcap; + } + +unlock: + mutex_unlock(&sdev->mutex); +exit: + return rval; +} + +static int si4713_write_econtrol_integers(struct si4713_device *sdev, + struct v4l2_ext_control *control) +{ + s32 rval; + u32 *shadow = NULL, val = 0; + s32 bit = 0, mask = 0; + u16 property = 0; + int mul = 0; + unsigned long *table = NULL; + int size = 0; + + rval = validate_range(&sdev->sd, control); + if (rval < 0) + goto exit; + + rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit, + &mask, &property, &mul, &table, &size); + if (rval < 0) + goto exit; + + val = control->value; + if (mul) { + val = control->value / mul; + } else if (table) { + rval = usecs_to_dev(control->value, table, size); + if (rval < 0) + goto exit; + val = rval; + rval = 0; + } + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) { + if (mask) { + rval = si4713_read_property(sdev, property, &val); + if (rval < 0) + goto unlock; + val = set_bits(val, control->value, bit, mask); + } + + rval = si4713_write_property(sdev, property, val); + if (rval < 0) + goto unlock; + if (mask) + val = control->value; + } + + if (mul) { + *shadow = val * mul; + } else if (table) { + rval = dev_to_usecs(val, table, size); + if (rval < 0) + goto unlock; + *shadow = rval; + rval = 0; + } else { + *shadow = val; + } + +unlock: + mutex_unlock(&sdev->mutex); +exit: + return rval; +} + +static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f); +static int si4713_s_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *); +/* + * si4713_setup - Sets the device up with current configuration. + * @sdev: si4713_device structure for the device we are communicating + */ +static int si4713_setup(struct si4713_device *sdev) +{ + struct v4l2_ext_control ctrl; + struct v4l2_frequency f; + struct v4l2_modulator vm; + struct si4713_device *tmp; + int rval = 0; + + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + /* Get a local copy to avoid race */ + mutex_lock(&sdev->mutex); + memcpy(tmp, sdev, sizeof(*sdev)); + mutex_unlock(&sdev->mutex); + + ctrl.id = V4L2_CID_RDS_TX_PI; + ctrl.value = tmp->rds_info.pi; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_AUDIO_COMPRESSION_THRESHOLD; + ctrl.value = tmp->acomp_info.threshold; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_AUDIO_COMPRESSION_GAIN; + ctrl.value = tmp->acomp_info.gain; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_PILOT_TONE_FREQUENCY; + ctrl.value = tmp->pilot_info.frequency; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME; + ctrl.value = tmp->acomp_info.attack_time; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_PILOT_TONE_DEVIATION; + ctrl.value = tmp->pilot_info.deviation; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_AUDIO_LIMITER_DEVIATION; + ctrl.value = tmp->limiter_info.deviation; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_RDS_TX_DEVIATION; + ctrl.value = tmp->rds_info.deviation; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_RDS_TX_PTY; + ctrl.value = tmp->rds_info.pty; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_AUDIO_LIMITER_ENABLED; + ctrl.value = tmp->limiter_info.enabled; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ENABLED; + ctrl.value = tmp->acomp_info.enabled; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_PILOT_TONE_ENABLED; + ctrl.value = tmp->pilot_info.enabled; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_AUDIO_LIMITER_RELEASE_TIME; + ctrl.value = tmp->limiter_info.release_time; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME; + ctrl.value = tmp->acomp_info.release_time; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_TUNE_PREEMPHASIS; + ctrl.value = tmp->preemphasis; + rval |= si4713_write_econtrol_integers(sdev, &ctrl); + + ctrl.id = V4L2_CID_RDS_TX_PS_NAME; + rval |= si4713_set_rds_ps_name(sdev, tmp->rds_info.ps_name); + + ctrl.id = V4L2_CID_RDS_TX_RADIO_TEXT; + rval |= si4713_set_rds_radio_text(sdev, tmp->rds_info.radio_text); + + /* Device procedure needs to set frequency first */ + f.frequency = tmp->frequency ? tmp->frequency : DEFAULT_FREQUENCY; + f.frequency = si4713_to_v4l2(f.frequency); + rval |= si4713_s_frequency(&sdev->sd, &f); + + ctrl.id = V4L2_CID_TUNE_POWER_LEVEL; + ctrl.value = tmp->power_level; + rval |= si4713_write_econtrol_tune(sdev, &ctrl); + + ctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR; + ctrl.value = tmp->antenna_capacitor; + rval |= si4713_write_econtrol_tune(sdev, &ctrl); + + vm.index = 0; + if (tmp->stereo) + vm.txsubchans = V4L2_TUNER_SUB_STEREO; + else + vm.txsubchans = V4L2_TUNER_SUB_MONO; + if (tmp->rds_info.enabled) + vm.txsubchans |= V4L2_TUNER_SUB_RDS; + si4713_s_modulator(&sdev->sd, &vm); + + kfree(tmp); + + return rval; +} + +/* + * si4713_initialize - Sets the device up with default configuration. + * @sdev: si4713_device structure for the device we are communicating + */ +static int si4713_initialize(struct si4713_device *sdev) +{ + int rval; + + rval = si4713_set_power_state(sdev, POWER_ON); + if (rval < 0) + goto exit; + + rval = si4713_checkrev(sdev); + if (rval < 0) + goto exit; + + rval = si4713_set_power_state(sdev, POWER_OFF); + if (rval < 0) + goto exit; + + mutex_lock(&sdev->mutex); + + sdev->rds_info.pi = DEFAULT_RDS_PI; + sdev->rds_info.pty = DEFAULT_RDS_PTY; + sdev->rds_info.deviation = DEFAULT_RDS_DEVIATION; + strlcpy(sdev->rds_info.ps_name, DEFAULT_RDS_PS_NAME, MAX_RDS_PS_NAME); + strlcpy(sdev->rds_info.radio_text, DEFAULT_RDS_RADIO_TEXT, + MAX_RDS_RADIO_TEXT); + sdev->rds_info.enabled = 1; + + sdev->limiter_info.release_time = DEFAULT_LIMITER_RTIME; + sdev->limiter_info.deviation = DEFAULT_LIMITER_DEV; + sdev->limiter_info.enabled = 1; + + sdev->pilot_info.deviation = DEFAULT_PILOT_DEVIATION; + sdev->pilot_info.frequency = DEFAULT_PILOT_FREQUENCY; + sdev->pilot_info.enabled = 1; + + sdev->acomp_info.release_time = DEFAULT_ACOMP_RTIME; + sdev->acomp_info.attack_time = DEFAULT_ACOMP_ATIME; + sdev->acomp_info.threshold = DEFAULT_ACOMP_THRESHOLD; + sdev->acomp_info.gain = DEFAULT_ACOMP_GAIN; + sdev->acomp_info.enabled = 1; + + sdev->frequency = DEFAULT_FREQUENCY; + sdev->preemphasis = DEFAULT_PREEMPHASIS; + sdev->mute = DEFAULT_MUTE; + sdev->power_level = DEFAULT_POWER_LEVEL; + sdev->antenna_capacitor = 0; + sdev->stereo = 1; + sdev->tune_rnl = DEFAULT_TUNE_RNL; + + mutex_unlock(&sdev->mutex); + +exit: + return rval; +} + +/* read string property */ +static int si4713_read_econtrol_string(struct si4713_device *sdev, + struct v4l2_ext_control *control) +{ + s32 rval = 0; + + switch (control->id) { + case V4L2_CID_RDS_TX_PS_NAME: + if (strlen(sdev->rds_info.ps_name) + 1 > control->size) { + control->size = MAX_RDS_PS_NAME + 1; + rval = -ENOSPC; + goto exit; + } + rval = copy_to_user(control->string, sdev->rds_info.ps_name, + strlen(sdev->rds_info.ps_name) + 1); + if (rval) + rval = -EFAULT; + break; + + case V4L2_CID_RDS_TX_RADIO_TEXT: + if (strlen(sdev->rds_info.radio_text) + 1 > control->size) { + control->size = MAX_RDS_RADIO_TEXT + 1; + rval = -ENOSPC; + goto exit; + } + rval = copy_to_user(control->string, sdev->rds_info.radio_text, + strlen(sdev->rds_info.radio_text) + 1); + if (rval) + rval = -EFAULT; + break; + + default: + rval = -EINVAL; + break; + }; + +exit: + return rval; +} + +/* + * si4713_update_tune_status - update properties from tx_tune_status + * command. Must be called with sdev->mutex held. + * @sdev: si4713_device structure for the device we are communicating + */ +static int si4713_update_tune_status(struct si4713_device *sdev) +{ + int rval; + u16 f = 0; + u8 p = 0, a = 0, n = 0; + + rval = si4713_tx_tune_status(sdev, 0x00, &f, &p, &a, &n); + + if (rval < 0) + goto exit; + + sdev->power_level = p; + sdev->antenna_capacitor = a; + sdev->tune_rnl = n; + +exit: + return rval; +} + +/* properties which use tx_tune_status */ +static int si4713_read_econtrol_tune(struct si4713_device *sdev, + struct v4l2_ext_control *control) +{ + s32 rval = 0; + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) { + rval = si4713_update_tune_status(sdev); + if (rval < 0) + goto unlock; + } + + switch (control->id) { + case V4L2_CID_TUNE_POWER_LEVEL: + control->value = sdev->power_level; + break; + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + control->value = sdev->antenna_capacitor; + break; + default: + rval = -EINVAL; + }; + +unlock: + mutex_unlock(&sdev->mutex); + return rval; +} + +static int si4713_read_econtrol_integers(struct si4713_device *sdev, + struct v4l2_ext_control *control) +{ + s32 rval; + u32 *shadow = NULL, val = 0; + s32 bit = 0, mask = 0; + u16 property = 0; + int mul = 0; + unsigned long *table = NULL; + int size = 0; + + rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit, + &mask, &property, &mul, &table, &size); + if (rval < 0) + goto exit; + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) { + rval = si4713_read_property(sdev, property, &val); + if (rval < 0) + goto unlock; + + /* Keep negative values for threshold */ + if (control->id == V4L2_CID_AUDIO_COMPRESSION_THRESHOLD) + *shadow = (s16)val; + else if (mask) + *shadow = get_status_bit(val, bit, mask); + else if (mul) + *shadow = val * mul; + else + *shadow = dev_to_usecs(val, table, size); + } + + control->value = *shadow; + +unlock: + mutex_unlock(&sdev->mutex); +exit: + return rval; +} + +/* + * Video4Linux Subdev Interface + */ +/* si4713_s_ext_ctrls - set extended controls value */ +static int si4713_s_ext_ctrls(struct v4l2_subdev *sd, + struct v4l2_ext_controls *ctrls) +{ + struct si4713_device *sdev = to_si4713_device(sd); + int i; + + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) + return -EINVAL; + + for (i = 0; i < ctrls->count; i++) { + int err; + + switch ((ctrls->controls + i)->id) { + case V4L2_CID_RDS_TX_PS_NAME: + case V4L2_CID_RDS_TX_RADIO_TEXT: + err = si4713_write_econtrol_string(sdev, + ctrls->controls + i); + break; + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + case V4L2_CID_TUNE_POWER_LEVEL: + err = si4713_write_econtrol_tune(sdev, + ctrls->controls + i); + break; + default: + err = si4713_write_econtrol_integers(sdev, + ctrls->controls + i); + } + + if (err < 0) { + ctrls->error_idx = i; + return err; + } + } + + return 0; +} + +/* si4713_g_ext_ctrls - get extended controls value */ +static int si4713_g_ext_ctrls(struct v4l2_subdev *sd, + struct v4l2_ext_controls *ctrls) +{ + struct si4713_device *sdev = to_si4713_device(sd); + int i; + + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) + return -EINVAL; + + for (i = 0; i < ctrls->count; i++) { + int err; + + switch ((ctrls->controls + i)->id) { + case V4L2_CID_RDS_TX_PS_NAME: + case V4L2_CID_RDS_TX_RADIO_TEXT: + err = si4713_read_econtrol_string(sdev, + ctrls->controls + i); + break; + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + case V4L2_CID_TUNE_POWER_LEVEL: + err = si4713_read_econtrol_tune(sdev, + ctrls->controls + i); + break; + default: + err = si4713_read_econtrol_integers(sdev, + ctrls->controls + i); + } + + if (err < 0) { + ctrls->error_idx = i; + return err; + } + } + + return 0; +} + +/* si4713_queryctrl - enumerate control items */ +static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + int rval = 0; + + switch (qc->id) { + /* User class controls */ + case V4L2_CID_AUDIO_MUTE: + rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, DEFAULT_MUTE); + break; + /* FM_TX class controls */ + case V4L2_CID_RDS_TX_PI: + rval = v4l2_ctrl_query_fill(qc, 0, 0xFFFF, 1, DEFAULT_RDS_PI); + break; + case V4L2_CID_RDS_TX_PTY: + rval = v4l2_ctrl_query_fill(qc, 0, 31, 1, DEFAULT_RDS_PTY); + break; + case V4L2_CID_RDS_TX_DEVIATION: + rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_DEVIATION, + 10, DEFAULT_RDS_DEVIATION); + break; + case V4L2_CID_RDS_TX_PS_NAME: + /* + * Report step as 8. From RDS spec, psname + * should be 8. But there are receivers which scroll strings + * sized as 8xN. + */ + rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_PS_NAME, 8, 0); + break; + case V4L2_CID_RDS_TX_RADIO_TEXT: + /* + * Report step as 32 (2A block). From RDS spec, + * radio text should be 32 for 2A block. But there are receivers + * which scroll strings sized as 32xN. Setting default to 32. + */ + rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_RADIO_TEXT, 32, 0); + break; + + case V4L2_CID_AUDIO_LIMITER_ENABLED: + rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + break; + case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: + rval = v4l2_ctrl_query_fill(qc, 250, MAX_LIMITER_RELEASE_TIME, + 50, DEFAULT_LIMITER_RTIME); + break; + case V4L2_CID_AUDIO_LIMITER_DEVIATION: + rval = v4l2_ctrl_query_fill(qc, 0, MAX_LIMITER_DEVIATION, + 10, DEFAULT_LIMITER_DEV); + break; + + case V4L2_CID_AUDIO_COMPRESSION_ENABLED: + rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + break; + case V4L2_CID_AUDIO_COMPRESSION_GAIN: + rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_GAIN, 1, + DEFAULT_ACOMP_GAIN); + break; + case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: + rval = v4l2_ctrl_query_fill(qc, MIN_ACOMP_THRESHOLD, + MAX_ACOMP_THRESHOLD, 1, + DEFAULT_ACOMP_THRESHOLD); + break; + case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: + rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_ATTACK_TIME, + 500, DEFAULT_ACOMP_ATIME); + break; + case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: + rval = v4l2_ctrl_query_fill(qc, 100000, MAX_ACOMP_RELEASE_TIME, + 100000, DEFAULT_ACOMP_RTIME); + break; + + case V4L2_CID_PILOT_TONE_ENABLED: + rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + break; + case V4L2_CID_PILOT_TONE_DEVIATION: + rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_DEVIATION, + 10, DEFAULT_PILOT_DEVIATION); + break; + case V4L2_CID_PILOT_TONE_FREQUENCY: + rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_FREQUENCY, + 1, DEFAULT_PILOT_FREQUENCY); + break; + + case V4L2_CID_TUNE_PREEMPHASIS: + rval = v4l2_ctrl_query_fill(qc, V4L2_PREEMPHASIS_DISABLED, + V4L2_PREEMPHASIS_75_uS, 1, + V4L2_PREEMPHASIS_50_uS); + break; + case V4L2_CID_TUNE_POWER_LEVEL: + rval = v4l2_ctrl_query_fill(qc, 0, 120, 1, DEFAULT_POWER_LEVEL); + break; + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + rval = v4l2_ctrl_query_fill(qc, 0, 191, 1, 0); + break; + default: + rval = -EINVAL; + break; + }; + + return rval; +} + +/* si4713_g_ctrl - get the value of a control */ +static int si4713_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct si4713_device *sdev = to_si4713_device(sd); + int rval = 0; + + if (!sdev) + return -ENODEV; + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) { + rval = si4713_read_property(sdev, SI4713_TX_LINE_INPUT_MUTE, + &sdev->mute); + + if (rval < 0) + goto unlock; + } + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = get_mute(sdev->mute); + break; + } + +unlock: + mutex_unlock(&sdev->mutex); + return rval; +} + +/* si4713_s_ctrl - set the value of a control */ +static int si4713_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct si4713_device *sdev = to_si4713_device(sd); + int rval = 0; + + if (!sdev) + return -ENODEV; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + rval = si4713_set_mute(sdev, ctrl->value); + if (rval < 0) + goto exit; + + rval = si4713_set_power_state(sdev, POWER_DOWN); + } else { + rval = si4713_set_power_state(sdev, POWER_UP); + if (rval < 0) + goto exit; + + rval = si4713_setup(sdev); + if (rval < 0) + goto exit; + + rval = si4713_set_mute(sdev, ctrl->value); + } + break; + } + +exit: + return rval; +} + +/* si4713_ioctl - deal with private ioctls (only rnl for now) */ +long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct si4713_device *sdev = to_si4713_device(sd); + struct si4713_rnl *rnl = arg; + u16 frequency; + int rval = 0; + + if (!arg) + return -EINVAL; + + mutex_lock(&sdev->mutex); + switch (cmd) { + case SI4713_IOC_MEASURE_RNL: + frequency = v4l2_to_si4713(rnl->frequency); + + if (sdev->power_state) { + /* Set desired measurement frequency */ + rval = si4713_tx_tune_measure(sdev, frequency, 0); + if (rval < 0) + goto unlock; + /* get results from tune status */ + rval = si4713_update_tune_status(sdev); + if (rval < 0) + goto unlock; + } + rnl->rnl = sdev->tune_rnl; + break; + + default: + /* nothing */ + rval = -ENOIOCTLCMD; + } + +unlock: + mutex_unlock(&sdev->mutex); + return rval; +} + +static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = { + .queryctrl = si4713_queryctrl, + .g_ext_ctrls = si4713_g_ext_ctrls, + .s_ext_ctrls = si4713_s_ext_ctrls, + .g_ctrl = si4713_g_ctrl, + .s_ctrl = si4713_s_ctrl, + .ioctl = si4713_ioctl, +}; + +/* si4713_g_modulator - get modulator attributes */ +static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) +{ + struct si4713_device *sdev = to_si4713_device(sd); + int rval = 0; + + if (!sdev) { + rval = -ENODEV; + goto exit; + } + + if (vm->index > 0) { + rval = -EINVAL; + goto exit; + } + + strncpy(vm->name, "FM Modulator", 32); + vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW | + V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS; + + /* Report current frequency range limits */ + vm->rangelow = si4713_to_v4l2(FREQ_RANGE_LOW); + vm->rangehigh = si4713_to_v4l2(FREQ_RANGE_HIGH); + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) { + u32 comp_en = 0; + + rval = si4713_read_property(sdev, SI4713_TX_COMPONENT_ENABLE, + &comp_en); + if (rval < 0) + goto unlock; + + sdev->stereo = get_status_bit(comp_en, 1, 1 << 1); + sdev->rds_info.enabled = get_status_bit(comp_en, 2, 1 << 2); + } + + /* Report current audio mode: mono or stereo */ + if (sdev->stereo) + vm->txsubchans = V4L2_TUNER_SUB_STEREO; + else + vm->txsubchans = V4L2_TUNER_SUB_MONO; + + /* Report rds feature status */ + if (sdev->rds_info.enabled) + vm->txsubchans |= V4L2_TUNER_SUB_RDS; + else + vm->txsubchans &= ~V4L2_TUNER_SUB_RDS; + +unlock: + mutex_unlock(&sdev->mutex); +exit: + return rval; +} + +/* si4713_s_modulator - set modulator attributes */ +static int si4713_s_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) +{ + struct si4713_device *sdev = to_si4713_device(sd); + int rval = 0; + u16 stereo, rds; + u32 p; + + if (!sdev) + return -ENODEV; + + if (vm->index > 0) + return -EINVAL; + + /* Set audio mode: mono or stereo */ + if (vm->txsubchans & V4L2_TUNER_SUB_STEREO) + stereo = 1; + else if (vm->txsubchans & V4L2_TUNER_SUB_MONO) + stereo = 0; + else + return -EINVAL; + + rds = !!(vm->txsubchans & V4L2_TUNER_SUB_RDS); + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) { + rval = si4713_read_property(sdev, + SI4713_TX_COMPONENT_ENABLE, &p); + if (rval < 0) + goto unlock; + + p = set_bits(p, stereo, 1, 1 << 1); + p = set_bits(p, rds, 2, 1 << 2); + + rval = si4713_write_property(sdev, + SI4713_TX_COMPONENT_ENABLE, p); + if (rval < 0) + goto unlock; + } + + sdev->stereo = stereo; + sdev->rds_info.enabled = rds; + +unlock: + mutex_unlock(&sdev->mutex); + return rval; +} + +/* si4713_g_frequency - get tuner or modulator radio frequency */ +static int si4713_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +{ + struct si4713_device *sdev = to_si4713_device(sd); + int rval = 0; + + f->type = V4L2_TUNER_RADIO; + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) { + u16 freq; + u8 p, a, n; + + rval = si4713_tx_tune_status(sdev, 0x00, &freq, &p, &a, &n); + if (rval < 0) + goto unlock; + + sdev->frequency = freq; + } + + f->frequency = si4713_to_v4l2(sdev->frequency); + +unlock: + mutex_unlock(&sdev->mutex); + return rval; +} + +/* si4713_s_frequency - set tuner or modulator radio frequency */ +static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +{ + struct si4713_device *sdev = to_si4713_device(sd); + int rval = 0; + u16 frequency = v4l2_to_si4713(f->frequency); + + /* Check frequency range */ + if (frequency < FREQ_RANGE_LOW || frequency > FREQ_RANGE_HIGH) + return -EDOM; + + mutex_lock(&sdev->mutex); + + if (sdev->power_state) { + rval = si4713_tx_tune_freq(sdev, frequency); + if (rval < 0) + goto unlock; + frequency = rval; + rval = 0; + } + sdev->frequency = frequency; + f->frequency = si4713_to_v4l2(frequency); + +unlock: + mutex_unlock(&sdev->mutex); + return rval; +} + +static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = { + .g_frequency = si4713_g_frequency, + .s_frequency = si4713_s_frequency, + .g_modulator = si4713_g_modulator, + .s_modulator = si4713_s_modulator, +}; + +static const struct v4l2_subdev_ops si4713_subdev_ops = { + .core = &si4713_subdev_core_ops, + .tuner = &si4713_subdev_tuner_ops, +}; + +/* + * I2C driver interface + */ +/* si4713_probe - probe for the device */ +static int si4713_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct si4713_device *sdev; + struct si4713_platform_data *pdata = client->dev.platform_data; + int rval, i; + + sdev = kzalloc(sizeof *sdev, GFP_KERNEL); + if (!sdev) { + dev_err(&client->dev, "Failed to alloc video device.\n"); + rval = -ENOMEM; + goto exit; + } + + sdev->gpio_reset = -1; + if (pdata && gpio_is_valid(pdata->gpio_reset)) { + rval = gpio_request(pdata->gpio_reset, "si4713 reset"); + if (rval) { + dev_err(&client->dev, + "Failed to request gpio: %d\n", rval); + goto free_sdev; + } + sdev->gpio_reset = pdata->gpio_reset; + gpio_direction_output(sdev->gpio_reset, 0); + } + + for (i = 0; i < ARRAY_SIZE(sdev->supplies); i++) + sdev->supplies[i].supply = si4713_supply_names[i]; + + rval = regulator_bulk_get(&client->dev, ARRAY_SIZE(sdev->supplies), + sdev->supplies); + if (rval) { + dev_err(&client->dev, "Cannot get regulators: %d\n", rval); + goto free_gpio; + } + + v4l2_i2c_subdev_init(&sdev->sd, client, &si4713_subdev_ops); + + mutex_init(&sdev->mutex); + init_completion(&sdev->work); + + if (client->irq) { + rval = request_irq(client->irq, + si4713_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, + client->name, sdev); + if (rval < 0) { + v4l2_err(&sdev->sd, "Could not request IRQ\n"); + goto put_reg; + } + v4l2_dbg(1, debug, &sdev->sd, "IRQ requested.\n"); + } else { + v4l2_warn(&sdev->sd, "IRQ not configured. Using timeouts.\n"); + } + + rval = si4713_initialize(sdev); + if (rval < 0) { + v4l2_err(&sdev->sd, "Failed to probe device information.\n"); + goto free_irq; + } + + return 0; + +free_irq: + if (client->irq) + free_irq(client->irq, sdev); +put_reg: + regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies); +free_gpio: + if (gpio_is_valid(sdev->gpio_reset)) + gpio_free(sdev->gpio_reset); +free_sdev: + kfree(sdev); +exit: + return rval; +} + +/* si4713_remove - remove the device */ +static int si4713_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct si4713_device *sdev = to_si4713_device(sd); + + if (sdev->power_state) + si4713_set_power_state(sdev, POWER_DOWN); + + if (client->irq > 0) + free_irq(client->irq, sdev); + + v4l2_device_unregister_subdev(sd); + regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies); + if (gpio_is_valid(sdev->gpio_reset)) + gpio_free(sdev->gpio_reset); + kfree(sdev); + + return 0; +} + +/* si4713_i2c_driver - i2c driver interface */ +static const struct i2c_device_id si4713_id[] = { + { "si4713" , 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, si4713_id); + +static struct i2c_driver si4713_i2c_driver = { + .driver = { + .name = "si4713", + }, + .probe = si4713_probe, + .remove = si4713_remove, + .id_table = si4713_id, +}; + +/* Module Interface */ +static int __init si4713_module_init(void) +{ + return i2c_add_driver(&si4713_i2c_driver); +} + +static void __exit si4713_module_exit(void) +{ + i2c_del_driver(&si4713_i2c_driver); +} + +module_init(si4713_module_init); +module_exit(si4713_module_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si4713-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si4713-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si4713-i2c.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/si4713-i2c.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,240 @@ +/* + * drivers/media/radio/si4713-i2c.h + * + * Property and commands definitions for Si4713 radio transmitter chip. + * + * Copyright (c) 2008 Instituto Nokia de Tecnologia - INdT + * Contact: Eduardo Valentin + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + */ + +#ifndef SI4713_I2C_H +#define SI4713_I2C_H + +#include +#include + +#define SI4713_PRODUCT_NUMBER 0x0D + +/* Command Timeouts */ +#define DEFAULT_TIMEOUT 500 +#define TIMEOUT_SET_PROPERTY 20 +#define TIMEOUT_TX_TUNE_POWER 30000 +#define TIMEOUT_TX_TUNE 110000 +#define TIMEOUT_POWER_UP 200000 + +/* + * Command and its arguments definitions + */ +#define SI4713_PWUP_CTSIEN (1<<7) +#define SI4713_PWUP_GPO2OEN (1<<6) +#define SI4713_PWUP_PATCH (1<<5) +#define SI4713_PWUP_XOSCEN (1<<4) +#define SI4713_PWUP_FUNC_TX 0x02 +#define SI4713_PWUP_FUNC_PATCH 0x0F +#define SI4713_PWUP_OPMOD_ANALOG 0x50 +#define SI4713_PWUP_OPMOD_DIGITAL 0x0F +#define SI4713_PWUP_NARGS 2 +#define SI4713_PWUP_NRESP 1 +#define SI4713_CMD_POWER_UP 0x01 + +#define SI4713_GETREV_NRESP 9 +#define SI4713_CMD_GET_REV 0x10 + +#define SI4713_PWDN_NRESP 1 +#define SI4713_CMD_POWER_DOWN 0x11 + +#define SI4713_SET_PROP_NARGS 5 +#define SI4713_SET_PROP_NRESP 1 +#define SI4713_CMD_SET_PROPERTY 0x12 + +#define SI4713_GET_PROP_NARGS 3 +#define SI4713_GET_PROP_NRESP 4 +#define SI4713_CMD_GET_PROPERTY 0x13 + +#define SI4713_GET_STATUS_NRESP 1 +#define SI4713_CMD_GET_INT_STATUS 0x14 + +#define SI4713_CMD_PATCH_ARGS 0x15 +#define SI4713_CMD_PATCH_DATA 0x16 + +#define SI4713_MAX_FREQ 10800 +#define SI4713_MIN_FREQ 7600 +#define SI4713_TXFREQ_NARGS 3 +#define SI4713_TXFREQ_NRESP 1 +#define SI4713_CMD_TX_TUNE_FREQ 0x30 + +#define SI4713_MAX_POWER 120 +#define SI4713_MIN_POWER 88 +#define SI4713_MAX_ANTCAP 191 +#define SI4713_MIN_ANTCAP 0 +#define SI4713_TXPWR_NARGS 4 +#define SI4713_TXPWR_NRESP 1 +#define SI4713_CMD_TX_TUNE_POWER 0x31 + +#define SI4713_TXMEA_NARGS 4 +#define SI4713_TXMEA_NRESP 1 +#define SI4713_CMD_TX_TUNE_MEASURE 0x32 + +#define SI4713_INTACK_MASK 0x01 +#define SI4713_TXSTATUS_NARGS 1 +#define SI4713_TXSTATUS_NRESP 8 +#define SI4713_CMD_TX_TUNE_STATUS 0x33 + +#define SI4713_OVERMOD_BIT (1 << 2) +#define SI4713_IALH_BIT (1 << 1) +#define SI4713_IALL_BIT (1 << 0) +#define SI4713_ASQSTATUS_NARGS 1 +#define SI4713_ASQSTATUS_NRESP 5 +#define SI4713_CMD_TX_ASQ_STATUS 0x34 + +#define SI4713_RDSBUFF_MODE_MASK 0x87 +#define SI4713_RDSBUFF_NARGS 7 +#define SI4713_RDSBUFF_NRESP 6 +#define SI4713_CMD_TX_RDS_BUFF 0x35 + +#define SI4713_RDSPS_PSID_MASK 0x1F +#define SI4713_RDSPS_NARGS 5 +#define SI4713_RDSPS_NRESP 1 +#define SI4713_CMD_TX_RDS_PS 0x36 + +#define SI4713_CMD_GPO_CTL 0x80 +#define SI4713_CMD_GPO_SET 0x81 + +/* + * Bits from status response + */ +#define SI4713_CTS (1<<7) +#define SI4713_ERR (1<<6) +#define SI4713_RDS_INT (1<<2) +#define SI4713_ASQ_INT (1<<1) +#define SI4713_STC_INT (1<<0) + +/* + * Property definitions + */ +#define SI4713_GPO_IEN 0x0001 +#define SI4713_DIG_INPUT_FORMAT 0x0101 +#define SI4713_DIG_INPUT_SAMPLE_RATE 0x0103 +#define SI4713_REFCLK_FREQ 0x0201 +#define SI4713_REFCLK_PRESCALE 0x0202 +#define SI4713_TX_COMPONENT_ENABLE 0x2100 +#define SI4713_TX_AUDIO_DEVIATION 0x2101 +#define SI4713_TX_PILOT_DEVIATION 0x2102 +#define SI4713_TX_RDS_DEVIATION 0x2103 +#define SI4713_TX_LINE_INPUT_LEVEL 0x2104 +#define SI4713_TX_LINE_INPUT_MUTE 0x2105 +#define SI4713_TX_PREEMPHASIS 0x2106 +#define SI4713_TX_PILOT_FREQUENCY 0x2107 +#define SI4713_TX_ACOMP_ENABLE 0x2200 +#define SI4713_TX_ACOMP_THRESHOLD 0x2201 +#define SI4713_TX_ACOMP_ATTACK_TIME 0x2202 +#define SI4713_TX_ACOMP_RELEASE_TIME 0x2203 +#define SI4713_TX_ACOMP_GAIN 0x2204 +#define SI4713_TX_LIMITER_RELEASE_TIME 0x2205 +#define SI4713_TX_ASQ_INTERRUPT_SOURCE 0x2300 +#define SI4713_TX_ASQ_LEVEL_LOW 0x2301 +#define SI4713_TX_ASQ_DURATION_LOW 0x2302 +#define SI4713_TX_ASQ_LEVEL_HIGH 0x2303 +#define SI4713_TX_ASQ_DURATION_HIGH 0x2304 +#define SI4713_TX_RDS_INTERRUPT_SOURCE 0x2C00 +#define SI4713_TX_RDS_PI 0x2C01 +#define SI4713_TX_RDS_PS_MIX 0x2C02 +#define SI4713_TX_RDS_PS_MISC 0x2C03 +#define SI4713_TX_RDS_PS_REPEAT_COUNT 0x2C04 +#define SI4713_TX_RDS_PS_MESSAGE_COUNT 0x2C05 +#define SI4713_TX_RDS_PS_AF 0x2C06 +#define SI4713_TX_RDS_FIFO_SIZE 0x2C07 + +#define PREEMPHASIS_USA 75 +#define PREEMPHASIS_EU 50 +#define PREEMPHASIS_DISABLED 0 +#define FMPE_USA 0x00 +#define FMPE_EU 0x01 +#define FMPE_DISABLED 0x02 + +#define POWER_UP 0x01 +#define POWER_DOWN 0x00 + +struct rds_info { + u32 pi; +#define MAX_RDS_PTY 31 + u32 pty; +#define MAX_RDS_DEVIATION 90000 + u32 deviation; +/* + * PSNAME is known to be defined as 8 character sized (RDS Spec). + * However, there is receivers which scroll PSNAME 8xN sized. + */ +#define MAX_RDS_PS_NAME 96 + u8 ps_name[MAX_RDS_PS_NAME + 1]; +/* + * MAX_RDS_RADIO_TEXT is known to be defined as 32 (2A group) or 64 (2B group) + * character sized (RDS Spec). + * However, there is receivers which scroll them as well. + */ +#define MAX_RDS_RADIO_TEXT 384 + u8 radio_text[MAX_RDS_RADIO_TEXT + 1]; + u32 enabled; +}; + +struct limiter_info { +#define MAX_LIMITER_RELEASE_TIME 102390 + u32 release_time; +#define MAX_LIMITER_DEVIATION 90000 + u32 deviation; + u32 enabled; +}; + +struct pilot_info { +#define MAX_PILOT_DEVIATION 90000 + u32 deviation; +#define MAX_PILOT_FREQUENCY 19000 + u32 frequency; + u32 enabled; +}; + +struct acomp_info { +#define MAX_ACOMP_RELEASE_TIME 1000000 + u32 release_time; +#define MAX_ACOMP_ATTACK_TIME 5000 + u32 attack_time; +#define MAX_ACOMP_THRESHOLD 0 +#define MIN_ACOMP_THRESHOLD (-40) + s32 threshold; +#define MAX_ACOMP_GAIN 20 + u32 gain; + u32 enabled; +}; + +#define SI4713_NUM_SUPPLIES 2 + +/* + * si4713_device - private data + */ +struct si4713_device { + /* v4l2_subdev and i2c reference (v4l2_subdev priv data) */ + struct v4l2_subdev sd; + /* private data structures */ + struct mutex mutex; + struct completion work; + struct rds_info rds_info; + struct limiter_info limiter_info; + struct pilot_info pilot_info; + struct acomp_info acomp_info; + struct regulator_bulk_data supplies[SI4713_NUM_SUPPLIES]; + int gpio_reset; + u32 frequency; + u32 preemphasis; + u32 mute; + u32 power_level; + u32 power_state; + u32 antenna_capacitor; + u32 stereo; + u32 tune_rnl; +}; +#endif /* ifndef SI4713_I2C_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/tef6862.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/tef6862.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/tef6862.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/tef6862.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,232 @@ +/* + * tef6862.c Philips TEF6862 Car Radio Enhanced Selectivity Tuner + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "tef6862" + +#define FREQ_MUL 16000 + +#define TEF6862_LO_FREQ (875 * FREQ_MUL / 10) +#define TEF6862_HI_FREQ (108 * FREQ_MUL) + +/* Write mode sub addresses */ +#define WM_SUB_BANDWIDTH 0x0 +#define WM_SUB_PLLM 0x1 +#define WM_SUB_PLLL 0x2 +#define WM_SUB_DAA 0x3 +#define WM_SUB_AGC 0x4 +#define WM_SUB_BAND 0x5 +#define WM_SUB_CONTROL 0x6 +#define WM_SUB_LEVEL 0x7 +#define WM_SUB_IFCF 0x8 +#define WM_SUB_IFCAP 0x9 +#define WM_SUB_ACD 0xA +#define WM_SUB_TEST 0xF + +/* Different modes of the MSA register */ +#define MODE_BUFFER 0x0 +#define MODE_PRESET 0x1 +#define MODE_SEARCH 0x2 +#define MODE_AF_UPDATE 0x3 +#define MODE_JUMP 0x4 +#define MODE_CHECK 0x5 +#define MODE_LOAD 0x6 +#define MODE_END 0x7 +#define MODE_SHIFT 5 + +struct tef6862_state { + struct v4l2_subdev sd; + unsigned long freq; +}; + +static inline struct tef6862_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct tef6862_state, sd); +} + +static u16 tef6862_sigstr(struct i2c_client *client) +{ + u8 buf[4]; + int err = i2c_master_recv(client, buf, sizeof(buf)); + if (err == sizeof(buf)) + return buf[3] << 8; + return 0; +} + +static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) +{ + if (v->index > 0) + return -EINVAL; + + /* only support FM for now */ + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->rangelow = TEF6862_LO_FREQ; + v->rangehigh = TEF6862_HI_FREQ; + v->rxsubchans = V4L2_TUNER_SUB_MONO; + v->capability = V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_STEREO; + v->signal = tef6862_sigstr(v4l2_get_subdevdata(sd)); + + return 0; +} + +static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) +{ + return v->index ? -EINVAL : 0; +} + +static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +{ + struct tef6862_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 pll; + u8 i2cmsg[3]; + int err; + + if (f->tuner != 0) + return -EINVAL; + + pll = 1964 + ((f->frequency - TEF6862_LO_FREQ) * 20) / FREQ_MUL; + i2cmsg[0] = (MODE_PRESET << MODE_SHIFT) | WM_SUB_PLLM; + i2cmsg[1] = (pll >> 8) & 0xff; + i2cmsg[2] = pll & 0xff; + + err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg)); + if (!err) + state->freq = f->frequency; + return err; +} + +static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +{ + struct tef6862_state *state = to_state(sd); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = state->freq; + return 0; +} + +static int tef6862_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEF6862, 0); +} + +static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = { + .g_tuner = tef6862_g_tuner, + .s_tuner = tef6862_s_tuner, + .s_frequency = tef6862_s_frequency, + .g_frequency = tef6862_g_frequency, +}; + +static const struct v4l2_subdev_core_ops tef6862_core_ops = { + .g_chip_ident = tef6862_g_chip_ident, +}; + +static const struct v4l2_subdev_ops tef6862_ops = { + .core = &tef6862_core_ops, + .tuner = &tef6862_tuner_ops, +}; + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static int __devinit tef6862_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tef6862_state *state; + struct v4l2_subdev *sd; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kzalloc(sizeof(struct tef6862_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + state->freq = TEF6862_LO_FREQ; + + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &tef6862_ops); + + return 0; +} + +static int __devexit tef6862_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); + return 0; +} + +static const struct i2c_device_id tef6862_id[] = { + {DRIVER_NAME, 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, tef6862_id); + +static struct i2c_driver tef6862_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, + .probe = tef6862_probe, + .remove = tef6862_remove, + .id_table = tef6862_id, +}; + +static __init int tef6862_init(void) +{ + return i2c_add_driver(&tef6862_driver); +} + +static __exit void tef6862_exit(void) +{ + i2c_del_driver(&tef6862_driver); +} + +module_init(tef6862_init); +module_exit(tef6862_exit); + +MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner"); +MODULE_AUTHOR("Mocean Laboratories"); +MODULE_LICENSE("GPL v2"); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_common.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_common.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_common.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_common.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,1686 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * + * This sub-module of FM driver is common for FM RX and TX + * functionality. This module is responsible for: + * 1) Forming group of Channel-8 commands to perform particular + * functionality (eg., frequency set require more than + * one Channel-8 command to be sent to the chip). + * 2) Sending each Channel-8 command to the chip and reading + * response back over Shared Transport. + * 3) Managing TX and RX Queues and Tasklets. + * 4) Handling FM Interrupt packet and taking appropriate action. + * 5) Loading FM firmware to the chip (common, FM TX, and FM RX + * firmware files based on mode selection) + * + * Copyright (C) 2011 Texas Instruments + * Author: Raja Mani + * Author: Manjunatha Halli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 +#include +#include +#include "fmdrv.h" +#include "fmdrv_v4l2.h" +#include "fmdrv_common.h" +#include +#include "fmdrv_rx.h" +#include "fmdrv_tx.h" + +/* Region info */ +static struct region_info region_configs[] = { + /* Europe/US */ + { + .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, + .bot_freq = 87500, /* 87.5 MHz */ + .top_freq = 108000, /* 108 MHz */ + .fm_band = 0, + }, + /* Japan */ + { + .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, + .bot_freq = 76000, /* 76 MHz */ + .top_freq = 90000, /* 90 MHz */ + .fm_band = 1, + }, +}; + +/* Band selection */ +static u8 default_radio_region; /* Europe/US */ +module_param(default_radio_region, byte, 0); +MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan"); + +/* RDS buffer blocks */ +static u32 default_rds_buf = 300; +module_param(default_rds_buf, uint, 0444); +MODULE_PARM_DESC(rds_buf, "RDS buffer entries"); + +/* Radio Nr */ +static u32 radio_nr = -1; +module_param(radio_nr, int, 0444); +MODULE_PARM_DESC(radio_nr, "Radio Nr"); + +/* FM irq handlers forward declaration */ +static void fm_irq_send_flag_getcmd(struct fmdev *); +static void fm_irq_handle_flag_getcmd_resp(struct fmdev *); +static void fm_irq_handle_hw_malfunction(struct fmdev *); +static void fm_irq_handle_rds_start(struct fmdev *); +static void fm_irq_send_rdsdata_getcmd(struct fmdev *); +static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *); +static void fm_irq_handle_rds_finish(struct fmdev *); +static void fm_irq_handle_tune_op_ended(struct fmdev *); +static void fm_irq_handle_power_enb(struct fmdev *); +static void fm_irq_handle_low_rssi_start(struct fmdev *); +static void fm_irq_afjump_set_pi(struct fmdev *); +static void fm_irq_handle_set_pi_resp(struct fmdev *); +static void fm_irq_afjump_set_pimask(struct fmdev *); +static void fm_irq_handle_set_pimask_resp(struct fmdev *); +static void fm_irq_afjump_setfreq(struct fmdev *); +static void fm_irq_handle_setfreq_resp(struct fmdev *); +static void fm_irq_afjump_enableint(struct fmdev *); +static void fm_irq_afjump_enableint_resp(struct fmdev *); +static void fm_irq_start_afjump(struct fmdev *); +static void fm_irq_handle_start_afjump_resp(struct fmdev *); +static void fm_irq_afjump_rd_freq(struct fmdev *); +static void fm_irq_afjump_rd_freq_resp(struct fmdev *); +static void fm_irq_handle_low_rssi_finish(struct fmdev *); +static void fm_irq_send_intmsk_cmd(struct fmdev *); +static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *); + +/* + * When FM common module receives interrupt packet, following handlers + * will be executed one after another to service the interrupt(s) + */ +enum fmc_irq_handler_index { + FM_SEND_FLAG_GETCMD_IDX, + FM_HANDLE_FLAG_GETCMD_RESP_IDX, + + /* HW malfunction irq handler */ + FM_HW_MAL_FUNC_IDX, + + /* RDS threshold reached irq handler */ + FM_RDS_START_IDX, + FM_RDS_SEND_RDS_GETCMD_IDX, + FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX, + FM_RDS_FINISH_IDX, + + /* Tune operation ended irq handler */ + FM_HW_TUNE_OP_ENDED_IDX, + + /* TX power enable irq handler */ + FM_HW_POWER_ENB_IDX, + + /* Low RSSI irq handler */ + FM_LOW_RSSI_START_IDX, + FM_AF_JUMP_SETPI_IDX, + FM_AF_JUMP_HANDLE_SETPI_RESP_IDX, + FM_AF_JUMP_SETPI_MASK_IDX, + FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX, + FM_AF_JUMP_SET_AF_FREQ_IDX, + FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX, + FM_AF_JUMP_ENABLE_INT_IDX, + FM_AF_JUMP_ENABLE_INT_RESP_IDX, + FM_AF_JUMP_START_AFJUMP_IDX, + FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX, + FM_AF_JUMP_RD_FREQ_IDX, + FM_AF_JUMP_RD_FREQ_RESP_IDX, + FM_LOW_RSSI_FINISH_IDX, + + /* Interrupt process post action */ + FM_SEND_INTMSK_CMD_IDX, + FM_HANDLE_INTMSK_CMD_RESP_IDX, +}; + +/* FM interrupt handler table */ +static int_handler_prototype int_handler_table[] = { + fm_irq_send_flag_getcmd, + fm_irq_handle_flag_getcmd_resp, + fm_irq_handle_hw_malfunction, + fm_irq_handle_rds_start, /* RDS threshold reached irq handler */ + fm_irq_send_rdsdata_getcmd, + fm_irq_handle_rdsdata_getcmd_resp, + fm_irq_handle_rds_finish, + fm_irq_handle_tune_op_ended, + fm_irq_handle_power_enb, /* TX power enable irq handler */ + fm_irq_handle_low_rssi_start, + fm_irq_afjump_set_pi, + fm_irq_handle_set_pi_resp, + fm_irq_afjump_set_pimask, + fm_irq_handle_set_pimask_resp, + fm_irq_afjump_setfreq, + fm_irq_handle_setfreq_resp, + fm_irq_afjump_enableint, + fm_irq_afjump_enableint_resp, + fm_irq_start_afjump, + fm_irq_handle_start_afjump_resp, + fm_irq_afjump_rd_freq, + fm_irq_afjump_rd_freq_resp, + fm_irq_handle_low_rssi_finish, + fm_irq_send_intmsk_cmd, /* Interrupt process post action */ + fm_irq_handle_intmsk_cmd_resp +}; + +long (*g_st_write) (struct sk_buff *skb); +static struct completion wait_for_fmdrv_reg_comp; + +static inline void fm_irq_call(struct fmdev *fmdev) +{ + fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); +} + +/* Continue next function in interrupt handler table */ +static inline void fm_irq_call_stage(struct fmdev *fmdev, u8 stage) +{ + fmdev->irq_info.stage = stage; + fm_irq_call(fmdev); +} + +static inline void fm_irq_timeout_stage(struct fmdev *fmdev, u8 stage) +{ + fmdev->irq_info.stage = stage; + mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); +} + +#ifdef FM_DUMP_TXRX_PKT + /* To dump outgoing FM Channel-8 packets */ +inline void dump_tx_skb_data(struct sk_buff *skb) +{ + int len, len_org; + u8 index; + struct fm_cmd_msg_hdr *cmd_hdr; + + cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data; + printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x", + fm_cb(skb)->completion ? " " : "*", cmd_hdr->hdr, + cmd_hdr->len, cmd_hdr->op, + cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen); + + len_org = skb->len - FM_CMD_MSG_HDR_SIZE; + if (len_org > 0) { + printk("\n data(%d): ", cmd_hdr->dlen); + len = min(len_org, 14); + for (index = 0; index < len; index++) + printk("%x ", + skb->data[FM_CMD_MSG_HDR_SIZE + index]); + printk("%s", (len_org > 14) ? ".." : ""); + } + printk("\n"); +} + + /* To dump incoming FM Channel-8 packets */ +inline void dump_rx_skb_data(struct sk_buff *skb) +{ + int len, len_org; + u8 index; + struct fm_event_msg_hdr *evt_hdr; + + evt_hdr = (struct fm_event_msg_hdr *)skb->data; + printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x " + "opcode:%02x type:%s dlen:%02x", evt_hdr->hdr, evt_hdr->len, + evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op, + (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen); + + len_org = skb->len - FM_EVT_MSG_HDR_SIZE; + if (len_org > 0) { + printk("\n data(%d): ", evt_hdr->dlen); + len = min(len_org, 14); + for (index = 0; index < len; index++) + printk("%x ", + skb->data[FM_EVT_MSG_HDR_SIZE + index]); + printk("%s", (len_org > 14) ? ".." : ""); + } + printk("\n"); +} +#endif + +void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set) +{ + fmdev->rx.region = region_configs[region_to_set]; +} + +/* + * FM common sub-module will schedule this tasklet whenever it receives + * FM packet from ST driver. + */ +static void recv_tasklet(unsigned long arg) +{ + struct fmdev *fmdev; + struct fm_irq *irq_info; + struct fm_event_msg_hdr *evt_hdr; + struct sk_buff *skb; + u8 num_fm_hci_cmds; + unsigned long flags; + + fmdev = (struct fmdev *)arg; + irq_info = &fmdev->irq_info; + /* Process all packets in the RX queue */ + while ((skb = skb_dequeue(&fmdev->rx_q))) { + if (skb->len < sizeof(struct fm_event_msg_hdr)) { + fmerr("skb(%p) has only %d bytes, " + "at least need %zu bytes to decode\n", skb, + skb->len, sizeof(struct fm_event_msg_hdr)); + kfree_skb(skb); + continue; + } + + evt_hdr = (void *)skb->data; + num_fm_hci_cmds = evt_hdr->num_fm_hci_cmds; + + /* FM interrupt packet? */ + if (evt_hdr->op == FM_INTERRUPT) { + /* FM interrupt handler started already? */ + if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { + set_bit(FM_INTTASK_RUNNING, &fmdev->flag); + if (irq_info->stage != 0) { + fmerr("Inval stage resetting to zero\n"); + irq_info->stage = 0; + } + + /* + * Execute first function in interrupt handler + * table. + */ + irq_info->handlers[irq_info->stage](fmdev); + } else { + set_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag); + } + kfree_skb(skb); + } + /* Anyone waiting for this with completion handler? */ + else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp != NULL) { + + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); + fmdev->resp_skb = skb; + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); + complete(fmdev->resp_comp); + + fmdev->resp_comp = NULL; + atomic_set(&fmdev->tx_cnt, 1); + } + /* Is this for interrupt handler? */ + else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp == NULL) { + if (fmdev->resp_skb != NULL) + fmerr("Response SKB ptr not NULL\n"); + + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); + fmdev->resp_skb = skb; + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); + + /* Execute interrupt handler where state index points */ + irq_info->handlers[irq_info->stage](fmdev); + + kfree_skb(skb); + atomic_set(&fmdev->tx_cnt, 1); + } else { + fmerr("Nobody claimed SKB(%p),purging\n", skb); + } + + /* + * Check flow control field. If Num_FM_HCI_Commands field is + * not zero, schedule FM TX tasklet. + */ + if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt)) + if (!skb_queue_empty(&fmdev->tx_q)) + tasklet_schedule(&fmdev->tx_task); + } +} + +/* FM send tasklet: is scheduled when FM packet has to be sent to chip */ +static void send_tasklet(unsigned long arg) +{ + struct fmdev *fmdev; + struct sk_buff *skb; + int len; + + fmdev = (struct fmdev *)arg; + + if (!atomic_read(&fmdev->tx_cnt)) + return; + + /* Check, is there any timeout happened to last transmitted packet */ + if ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT) { + fmerr("TX timeout occurred\n"); + atomic_set(&fmdev->tx_cnt, 1); + } + + /* Send queued FM TX packets */ + skb = skb_dequeue(&fmdev->tx_q); + if (!skb) + return; + + atomic_dec(&fmdev->tx_cnt); + fmdev->pre_op = fm_cb(skb)->fm_op; + + if (fmdev->resp_comp != NULL) + fmerr("Response completion handler is not NULL\n"); + + fmdev->resp_comp = fm_cb(skb)->completion; + + /* Write FM packet to ST driver */ + len = g_st_write(skb); + if (len < 0) { + kfree_skb(skb); + fmdev->resp_comp = NULL; + fmerr("TX tasklet failed to send skb(%p)\n", skb); + atomic_set(&fmdev->tx_cnt, 1); + } else { + fmdev->last_tx_jiffies = jiffies; + } +} + +/* + * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for + * transmission + */ +static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, + int payload_len, struct completion *wait_completion) +{ + struct sk_buff *skb; + struct fm_cmd_msg_hdr *hdr; + int size; + + if (fm_op >= FM_INTERRUPT) { + fmerr("Invalid fm opcode - %d\n", fm_op); + return -EINVAL; + } + if (test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) && payload == NULL) { + fmerr("Payload data is NULL during fw download\n"); + return -EINVAL; + } + if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag)) + size = + FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len); + else + size = payload_len; + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + fmerr("No memory to create new SKB\n"); + return -ENOMEM; + } + /* + * Don't fill FM header info for the commands which come from + * FM firmware file. + */ + if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) || + test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { + /* Fill command header info */ + hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE); + hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */ + + /* 3 (fm_opcode,rd_wr,dlen) + payload len) */ + hdr->len = ((payload == NULL) ? 0 : payload_len) + 3; + + /* FM opcode */ + hdr->op = fm_op; + + /* read/write type */ + hdr->rd_wr = type; + hdr->dlen = payload_len; + fm_cb(skb)->fm_op = fm_op; + + /* + * If firmware download has finished and the command is + * not a read command then payload is != NULL - a write + * command with u16 payload - convert to be16 + */ + if (payload != NULL) + *(u16 *)payload = cpu_to_be16(*(u16 *)payload); + + } else if (payload != NULL) { + fm_cb(skb)->fm_op = *((u8 *)payload + 2); + } + if (payload != NULL) + memcpy(skb_put(skb, payload_len), payload, payload_len); + + fm_cb(skb)->completion = wait_completion; + skb_queue_tail(&fmdev->tx_q, skb); + tasklet_schedule(&fmdev->tx_task); + + return 0; +} + +/* Sends FM Channel-8 command to the chip and waits for the response */ +u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, + unsigned int payload_len, void *response, int *response_len) +{ + struct sk_buff *skb; + struct fm_event_msg_hdr *evt_hdr; + unsigned long flags; + u32 ret; + + init_completion(&fmdev->maintask_comp); + ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len, + &fmdev->maintask_comp); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT); + if (!ret) { + fmerr("Timeout(%d sec),didn't get reg" + "completion signal from RX tasklet\n", + jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); + return -ETIMEDOUT; + } + if (!fmdev->resp_skb) { + fmerr("Response SKB is missing\n"); + return -EFAULT; + } + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); + skb = fmdev->resp_skb; + fmdev->resp_skb = NULL; + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); + + evt_hdr = (void *)skb->data; + if (evt_hdr->status != 0) { + fmerr("Received event pkt status(%d) is not zero\n", + evt_hdr->status); + kfree_skb(skb); + return -EIO; + } + /* Send response data to caller */ + if (response != NULL && response_len != NULL && evt_hdr->dlen) { + /* Skip header info and copy only response data */ + skb_pull(skb, sizeof(struct fm_event_msg_hdr)); + memcpy(response, skb->data, evt_hdr->dlen); + *response_len = evt_hdr->dlen; + } else if (response_len != NULL && evt_hdr->dlen == 0) { + *response_len = 0; + } + kfree_skb(skb); + + return 0; +} + +/* --- Helper functions used in FM interrupt handlers ---*/ +static inline u32 check_cmdresp_status(struct fmdev *fmdev, + struct sk_buff **skb) +{ + struct fm_event_msg_hdr *fm_evt_hdr; + unsigned long flags; + + del_timer(&fmdev->irq_info.timer); + + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); + *skb = fmdev->resp_skb; + fmdev->resp_skb = NULL; + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); + + fm_evt_hdr = (void *)(*skb)->data; + if (fm_evt_hdr->status != 0) { + fmerr("irq: opcode %x response status is not zero " + "Initiating irq recovery process\n", + fm_evt_hdr->op); + + mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); + return -1; + } + + return 0; +} + +static inline void fm_irq_common_cmd_resp_helper(struct fmdev *fmdev, u8 stage) +{ + struct sk_buff *skb; + + if (!check_cmdresp_status(fmdev, &skb)) + fm_irq_call_stage(fmdev, stage); +} + +/* + * Interrupt process timeout handler. + * One of the irq handler did not get proper response from the chip. So take + * recovery action here. FM interrupts are disabled in the beginning of + * interrupt process. Therefore reset stage index to re-enable default + * interrupts. So that next interrupt will be processed as usual. + */ +static void int_timeout_handler(unsigned long data) +{ + struct fmdev *fmdev; + struct fm_irq *fmirq; + + fmdbg("irq: timeout,trying to re-enable fm interrupts\n"); + fmdev = (struct fmdev *)data; + fmirq = &fmdev->irq_info; + fmirq->retry++; + + if (fmirq->retry > FM_IRQ_TIMEOUT_RETRY_MAX) { + /* Stop recovery action (interrupt reenable process) and + * reset stage index & retry count values */ + fmirq->stage = 0; + fmirq->retry = 0; + fmerr("Recovery action failed during" + "irq processing, max retry reached\n"); + return; + } + fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); +} + +/* --------- FM interrupt handlers ------------*/ +static void fm_irq_send_flag_getcmd(struct fmdev *fmdev) +{ + u16 flag; + + /* Send FLAG_GET command , to know the source of interrupt */ + if (!fm_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, sizeof(flag), NULL)) + fm_irq_timeout_stage(fmdev, FM_HANDLE_FLAG_GETCMD_RESP_IDX); +} + +static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + struct fm_event_msg_hdr *fm_evt_hdr; + + if (check_cmdresp_status(fmdev, &skb)) + return; + + fm_evt_hdr = (void *)skb->data; + + /* Skip header info and copy only response data */ + skb_pull(skb, sizeof(struct fm_event_msg_hdr)); + memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen); + + fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag); + fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag); + + /* Continue next function in interrupt handler table */ + fm_irq_call_stage(fmdev, FM_HW_MAL_FUNC_IDX); +} + +static void fm_irq_handle_hw_malfunction(struct fmdev *fmdev) +{ + if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask) + fmerr("irq: HW MAL int received - do nothing\n"); + + /* Continue next function in interrupt handler table */ + fm_irq_call_stage(fmdev, FM_RDS_START_IDX); +} + +static void fm_irq_handle_rds_start(struct fmdev *fmdev) +{ + if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) { + fmdbg("irq: rds threshold reached\n"); + fmdev->irq_info.stage = FM_RDS_SEND_RDS_GETCMD_IDX; + } else { + /* Continue next function in interrupt handler table */ + fmdev->irq_info.stage = FM_HW_TUNE_OP_ENDED_IDX; + } + + fm_irq_call(fmdev); +} + +static void fm_irq_send_rdsdata_getcmd(struct fmdev *fmdev) +{ + /* Send the command to read RDS data from the chip */ + if (!fm_send_cmd(fmdev, RDS_DATA_GET, REG_RD, NULL, + (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL)) + fm_irq_timeout_stage(fmdev, FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX); +} + +/* Keeps track of current RX channel AF (Alternate Frequency) */ +static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af) +{ + struct tuned_station_info *stat_info = &fmdev->rx.stat_info; + u8 reg_idx = fmdev->rx.region.fm_band; + u8 index; + u32 freq; + + /* First AF indicates the number of AF follows. Reset the list */ + if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) { + fmdev->rx.stat_info.af_list_max = (af - FM_RDS_1_AF_FOLLOWS + 1); + fmdev->rx.stat_info.afcache_size = 0; + fmdbg("No of expected AF : %d\n", fmdev->rx.stat_info.af_list_max); + return; + } + + if (af < FM_RDS_MIN_AF) + return; + if (reg_idx == FM_BAND_EUROPE_US && af > FM_RDS_MAX_AF) + return; + if (reg_idx == FM_BAND_JAPAN && af > FM_RDS_MAX_AF_JAPAN) + return; + + freq = fmdev->rx.region.bot_freq + (af * 100); + if (freq == fmdev->rx.freq) { + fmdbg("Current freq(%d) is matching with received AF(%d)\n", + fmdev->rx.freq, freq); + return; + } + /* Do check in AF cache */ + for (index = 0; index < stat_info->afcache_size; index++) { + if (stat_info->af_cache[index] == freq) + break; + } + /* Reached the limit of the list - ignore the next AF */ + if (index == stat_info->af_list_max) { + fmdbg("AF cache is full\n"); + return; + } + /* + * If we reached the end of the list then this AF is not + * in the list - add it. + */ + if (index == stat_info->afcache_size) { + fmdbg("Storing AF %d to cache index %d\n", freq, index); + stat_info->af_cache[index] = freq; + stat_info->afcache_size++; + } +} + +/* + * Converts RDS buffer data from big endian format + * to little endian format. + */ +static void fm_rdsparse_swapbytes(struct fmdev *fmdev, + struct fm_rdsdata_format *rds_format) +{ + u8 byte1; + u8 index = 0; + u8 *rds_buff; + + /* + * Since in Orca the 2 RDS Data bytes are in little endian and + * in Dolphin they are in big endian, the parsing of the RDS data + * is chip dependent + */ + if (fmdev->asci_id != 0x6350) { + rds_buff = &rds_format->data.groupdatabuff.buff[0]; + while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) { + byte1 = rds_buff[index]; + rds_buff[index] = rds_buff[index + 1]; + rds_buff[index + 1] = byte1; + index += 2; + } + } +} + +static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + struct fm_rdsdata_format rds_fmt; + struct fm_rds *rds = &fmdev->rx.rds; + unsigned long group_idx, flags; + u8 *rds_data, meta_data, tmpbuf[3]; + u8 type, blk_idx; + u16 cur_picode; + u32 rds_len; + + if (check_cmdresp_status(fmdev, &skb)) + return; + + /* Skip header info */ + skb_pull(skb, sizeof(struct fm_event_msg_hdr)); + rds_data = skb->data; + rds_len = skb->len; + + /* Parse the RDS data */ + while (rds_len >= FM_RDS_BLK_SIZE) { + meta_data = rds_data[2]; + /* Get the type: 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */ + type = (meta_data & 0x07); + + /* Transform the blk type into index sequence (0, 1, 2, 3, 4) */ + blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); + fmdbg("Block index:%d(%s)\n", blk_idx, + (meta_data & FM_RDS_STATUS_ERR_MASK) ? "Bad" : "Ok"); + + if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0) + break; + + if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) { + fmdbg("Block sequence mismatch\n"); + rds->last_blk_idx = -1; + break; + } + + /* Skip checkword (control) byte and copy only data byte */ + memcpy(&rds_fmt.data.groupdatabuff. + buff[blk_idx * (FM_RDS_BLK_SIZE - 1)], + rds_data, (FM_RDS_BLK_SIZE - 1)); + + rds->last_blk_idx = blk_idx; + + /* If completed a whole group then handle it */ + if (blk_idx == FM_RDS_BLK_IDX_D) { + fmdbg("Good block received\n"); + fm_rdsparse_swapbytes(fmdev, &rds_fmt); + + /* + * Extract PI code and store in local cache. + * We need this during AF switch processing. + */ + cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata); + if (fmdev->rx.stat_info.picode != cur_picode) + fmdev->rx.stat_info.picode = cur_picode; + + fmdbg("picode:%d\n", cur_picode); + + group_idx = (rds_fmt.data.groupgeneral.blk_b[0] >> 3); + fmdbg("(fmdrv):Group:%ld%s\n", group_idx/2, + (group_idx % 2) ? "B" : "A"); + + group_idx = 1 << (rds_fmt.data.groupgeneral.blk_b[0] >> 3); + if (group_idx == FM_RDS_GROUP_TYPE_MASK_0A) { + fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[0]); + fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[1]); + } + } + rds_len -= FM_RDS_BLK_SIZE; + rds_data += FM_RDS_BLK_SIZE; + } + + /* Copy raw rds data to internal rds buffer */ + rds_data = skb->data; + rds_len = skb->len; + + spin_lock_irqsave(&fmdev->rds_buff_lock, flags); + while (rds_len > 0) { + /* + * Fill RDS buffer as per V4L2 specification. + * Store control byte + */ + type = (rds_data[2] & 0x07); + blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); + tmpbuf[2] = blk_idx; /* Offset name */ + tmpbuf[2] |= blk_idx << 3; /* Received offset */ + + /* Store data byte */ + tmpbuf[0] = rds_data[0]; + tmpbuf[1] = rds_data[1]; + + memcpy(&rds->buff[rds->wr_idx], &tmpbuf, FM_RDS_BLK_SIZE); + rds->wr_idx = (rds->wr_idx + FM_RDS_BLK_SIZE) % rds->buf_size; + + /* Check for overflow & start over */ + if (rds->wr_idx == rds->rd_idx) { + fmdbg("RDS buffer overflow\n"); + rds->wr_idx = 0; + rds->rd_idx = 0; + break; + } + rds_len -= FM_RDS_BLK_SIZE; + rds_data += FM_RDS_BLK_SIZE; + } + spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); + + /* Wakeup read queue */ + if (rds->wr_idx != rds->rd_idx) + wake_up_interruptible(&rds->read_queue); + + fm_irq_call_stage(fmdev, FM_RDS_FINISH_IDX); +} + +static void fm_irq_handle_rds_finish(struct fmdev *fmdev) +{ + fm_irq_call_stage(fmdev, FM_HW_TUNE_OP_ENDED_IDX); +} + +static void fm_irq_handle_tune_op_ended(struct fmdev *fmdev) +{ + if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev-> + irq_info.mask) { + fmdbg("irq: tune ended/bandlimit reached\n"); + if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) { + fmdev->irq_info.stage = FM_AF_JUMP_RD_FREQ_IDX; + } else { + complete(&fmdev->maintask_comp); + fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; + } + } else + fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; + + fm_irq_call(fmdev); +} + +static void fm_irq_handle_power_enb(struct fmdev *fmdev) +{ + if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) { + fmdbg("irq: Power Enabled/Disabled\n"); + complete(&fmdev->maintask_comp); + } + + fm_irq_call_stage(fmdev, FM_LOW_RSSI_START_IDX); +} + +static void fm_irq_handle_low_rssi_start(struct fmdev *fmdev) +{ + if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) && + (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) && + (fmdev->rx.freq != FM_UNDEFINED_FREQ) && + (fmdev->rx.stat_info.afcache_size != 0)) { + fmdbg("irq: rssi level has fallen below threshold level\n"); + + /* Disable further low RSSI interrupts */ + fmdev->irq_info.mask &= ~FM_LEV_EVENT; + + fmdev->rx.afjump_idx = 0; + fmdev->rx.freq_before_jump = fmdev->rx.freq; + fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; + } else { + /* Continue next function in interrupt handler table */ + fmdev->irq_info.stage = FM_SEND_INTMSK_CMD_IDX; + } + + fm_irq_call(fmdev); +} + +static void fm_irq_afjump_set_pi(struct fmdev *fmdev) +{ + u16 payload; + + /* Set PI code - must be updated if the AF list is not empty */ + payload = fmdev->rx.stat_info.picode; + if (!fm_send_cmd(fmdev, RDS_PI_SET, REG_WR, &payload, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_RESP_IDX); +} + +static void fm_irq_handle_set_pi_resp(struct fmdev *fmdev) +{ + fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SETPI_MASK_IDX); +} + +/* + * Set PI mask. + * 0xFFFF = Enable PI code matching + * 0x0000 = Disable PI code matching + */ +static void fm_irq_afjump_set_pimask(struct fmdev *fmdev) +{ + u16 payload; + + payload = 0x0000; + if (!fm_send_cmd(fmdev, RDS_PI_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX); +} + +static void fm_irq_handle_set_pimask_resp(struct fmdev *fmdev) +{ + fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SET_AF_FREQ_IDX); +} + +static void fm_irq_afjump_setfreq(struct fmdev *fmdev) +{ + u16 frq_index; + u16 payload; + + fmdbg("Swtich to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]); + frq_index = (fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx] - + fmdev->rx.region.bot_freq) / FM_FREQ_MUL; + + payload = frq_index; + if (!fm_send_cmd(fmdev, AF_FREQ_SET, REG_WR, &payload, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX); +} + +static void fm_irq_handle_setfreq_resp(struct fmdev *fmdev) +{ + fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_ENABLE_INT_IDX); +} + +static void fm_irq_afjump_enableint(struct fmdev *fmdev) +{ + u16 payload; + + /* Enable FR (tuning operation ended) interrupt */ + payload = FM_FR_EVENT; + if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_ENABLE_INT_RESP_IDX); +} + +static void fm_irq_afjump_enableint_resp(struct fmdev *fmdev) +{ + fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_START_AFJUMP_IDX); +} + +static void fm_irq_start_afjump(struct fmdev *fmdev) +{ + u16 payload; + + payload = FM_TUNER_AF_JUMP_MODE; + if (!fm_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX); +} + +static void fm_irq_handle_start_afjump_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + + if (check_cmdresp_status(fmdev, &skb)) + return; + + fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; + set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag); + clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); +} + +static void fm_irq_afjump_rd_freq(struct fmdev *fmdev) +{ + u16 payload; + + if (!fm_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_RD_FREQ_RESP_IDX); +} + +static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + u16 read_freq; + u32 curr_freq, jumped_freq; + + if (check_cmdresp_status(fmdev, &skb)) + return; + + /* Skip header info and copy only response data */ + skb_pull(skb, sizeof(struct fm_event_msg_hdr)); + memcpy(&read_freq, skb->data, sizeof(read_freq)); + read_freq = be16_to_cpu(read_freq); + curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL); + + jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]; + + /* If the frequency was changed the jump succeeded */ + if ((curr_freq != fmdev->rx.freq_before_jump) && (curr_freq == jumped_freq)) { + fmdbg("Successfully switched to alternate freq %d\n", curr_freq); + fmdev->rx.freq = curr_freq; + fm_rx_reset_rds_cache(fmdev); + + /* AF feature is on, enable low level RSSI interrupt */ + if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) + fmdev->irq_info.mask |= FM_LEV_EVENT; + + fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; + } else { /* jump to the next freq in the AF list */ + fmdev->rx.afjump_idx++; + + /* If we reached the end of the list - stop searching */ + if (fmdev->rx.afjump_idx >= fmdev->rx.stat_info.afcache_size) { + fmdbg("AF switch processing failed\n"); + fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; + } else { /* AF List is not over - try next one */ + + fmdbg("Trying next freq in AF cache\n"); + fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; + } + } + fm_irq_call(fmdev); +} + +static void fm_irq_handle_low_rssi_finish(struct fmdev *fmdev) +{ + fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); +} + +static void fm_irq_send_intmsk_cmd(struct fmdev *fmdev) +{ + u16 payload; + + /* Re-enable FM interrupts */ + payload = fmdev->irq_info.mask; + + if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_HANDLE_INTMSK_CMD_RESP_IDX); +} + +static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + + if (check_cmdresp_status(fmdev, &skb)) + return; + /* + * This is last function in interrupt table to be executed. + * So, reset stage index to 0. + */ + fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; + + /* Start processing any pending interrupt */ + if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag)) + fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); + else + clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); +} + +/* Returns availability of RDS data in internel buffer */ +u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, + struct poll_table_struct *pts) +{ + poll_wait(file, &fmdev->rx.rds.read_queue, pts); + if (fmdev->rx.rds.rd_idx != fmdev->rx.rds.wr_idx) + return 0; + + return -EAGAIN; +} + +/* Copies RDS data from internal buffer to user buffer */ +u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, + u8 __user *buf, size_t count) +{ + u32 block_count; + unsigned long flags; + int ret; + + if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) { + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + ret = wait_event_interruptible(fmdev->rx.rds.read_queue, + (fmdev->rx.rds.wr_idx != fmdev->rx.rds.rd_idx)); + if (ret) + return -EINTR; + } + + /* Calculate block count from byte count */ + count /= 3; + block_count = 0; + ret = 0; + + spin_lock_irqsave(&fmdev->rds_buff_lock, flags); + + while (block_count < count) { + if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) + break; + + if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], + FM_RDS_BLK_SIZE)) + break; + + fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE; + if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size) + fmdev->rx.rds.rd_idx = 0; + + block_count++; + buf += FM_RDS_BLK_SIZE; + ret += FM_RDS_BLK_SIZE; + } + spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); + return ret; +} + +u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_freq(fmdev, freq_to_set); + + case FM_MODE_TX: + return fm_tx_set_freq(fmdev, freq_to_set); + + default: + return -EINVAL; + } +} + +u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) +{ + if (fmdev->rx.freq == FM_UNDEFINED_FREQ) { + fmerr("RX frequency is not set\n"); + return -EPERM; + } + if (cur_tuned_frq == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + *cur_tuned_frq = fmdev->rx.freq; + return 0; + + case FM_MODE_TX: + *cur_tuned_frq = 0; /* TODO : Change this later */ + return 0; + + default: + return -EINVAL; + } + +} + +u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_region(fmdev, region_to_set); + + case FM_MODE_TX: + return fm_tx_set_region(fmdev, region_to_set); + + default: + return -EINVAL; + } +} + +u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_mute_mode(fmdev, mute_mode_toset); + + case FM_MODE_TX: + return fm_tx_set_mute_mode(fmdev, mute_mode_toset); + + default: + return -EINVAL; + } +} + +u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_stereo_mono(fmdev, mode); + + case FM_MODE_TX: + return fm_tx_set_stereo_mono(fmdev, mode); + + default: + return -EINVAL; + } +} + +u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_rds_mode(fmdev, rds_en_dis); + + case FM_MODE_TX: + return fm_tx_set_rds_mode(fmdev, rds_en_dis); + + default: + return -EINVAL; + } +} + +/* Sends power off command to the chip */ +static u32 fm_power_down(struct fmdev *fmdev) +{ + u16 payload; + u32 ret; + + if (!test_bit(FM_CORE_READY, &fmdev->flag)) { + fmerr("FM core is not ready\n"); + return -EPERM; + } + if (fmdev->curr_fmmode == FM_MODE_OFF) { + fmdbg("FM chip is already in OFF state\n"); + return 0; + } + + payload = 0x0; + ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return fmc_release(fmdev); +} + +/* Reads init command from FM firmware file and loads to the chip */ +static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) +{ + const struct firmware *fw_entry; + struct bts_header *fw_header; + struct bts_action *action; + struct bts_action_delay *delay; + u8 *fw_data; + int ret, fw_len, cmd_cnt; + + cmd_cnt = 0; + set_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); + + ret = request_firmware(&fw_entry, fw_name, + &fmdev->radio_dev->dev); + if (ret < 0) { + fmerr("Unable to read firmware(%s) content\n", fw_name); + return ret; + } + fmdbg("Firmware(%s) length : %d bytes\n", fw_name, fw_entry->size); + + fw_data = (void *)fw_entry->data; + fw_len = fw_entry->size; + + fw_header = (struct bts_header *)fw_data; + if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) { + fmerr("%s not a legal TI firmware file\n", fw_name); + ret = -EINVAL; + goto rel_fw; + } + fmdbg("FW(%s) magic number : 0x%x\n", fw_name, fw_header->magic); + + /* Skip file header info , we already verified it */ + fw_data += sizeof(struct bts_header); + fw_len -= sizeof(struct bts_header); + + while (fw_data && fw_len > 0) { + action = (struct bts_action *)fw_data; + + switch (action->type) { + case ACTION_SEND_COMMAND: /* Send */ + if (fmc_send_cmd(fmdev, 0, 0, action->data, + action->size, NULL, NULL)) + goto rel_fw; + + cmd_cnt++; + break; + + case ACTION_DELAY: /* Delay */ + delay = (struct bts_action_delay *)action->data; + mdelay(delay->msec); + break; + } + + fw_data += (sizeof(struct bts_action) + (action->size)); + fw_len -= (sizeof(struct bts_action) + (action->size)); + } + fmdbg("Firmware commands(%d) loaded to chip\n", cmd_cnt); +rel_fw: + release_firmware(fw_entry); + clear_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); + + return ret; +} + +/* Loads default RX configuration to the chip */ +static u32 load_default_rx_configuration(struct fmdev *fmdev) +{ + int ret; + + ret = fm_rx_set_volume(fmdev, FM_DEFAULT_RX_VOLUME); + if (ret < 0) + return ret; + + return fm_rx_set_rssi_threshold(fmdev, FM_DEFAULT_RSSI_THRESHOLD); +} + +/* Does FM power on sequence */ +static u32 fm_power_up(struct fmdev *fmdev, u8 mode) +{ + u16 payload, asic_id, asic_ver; + int resp_len, ret; + u8 fw_name[50]; + + if (mode >= FM_MODE_ENTRY_MAX) { + fmerr("Invalid firmware download option\n"); + return -EINVAL; + } + + /* + * Initialize FM common module. FM GPIO toggling is + * taken care in Shared Transport driver. + */ + ret = fmc_prepare(fmdev); + if (ret < 0) { + fmerr("Unable to prepare FM Common\n"); + return ret; + } + + payload = FM_ENABLE; + if (fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, + sizeof(payload), NULL, NULL)) + goto rel; + + /* Allow the chip to settle down in Channel-8 mode */ + msleep(20); + + if (fmc_send_cmd(fmdev, ASIC_ID_GET, REG_RD, NULL, + sizeof(asic_id), &asic_id, &resp_len)) + goto rel; + + if (fmc_send_cmd(fmdev, ASIC_VER_GET, REG_RD, NULL, + sizeof(asic_ver), &asic_ver, &resp_len)) + goto rel; + + fmdbg("ASIC ID: 0x%x , ASIC Version: %d\n", + be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); + + sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START, + be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); + + ret = fm_download_firmware(fmdev, fw_name); + if (ret < 0) { + fmdbg("Failed to download firmware file %s\n", fw_name); + goto rel; + } + sprintf(fw_name, "%s_%x.%d.bts", (mode == FM_MODE_RX) ? + FM_RX_FW_FILE_START : FM_TX_FW_FILE_START, + be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); + + ret = fm_download_firmware(fmdev, fw_name); + if (ret < 0) { + fmdbg("Failed to download firmware file %s\n", fw_name); + goto rel; + } else + return ret; +rel: + return fmc_release(fmdev); +} + +/* Set FM Modes(TX, RX, OFF) */ +u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) +{ + int ret = 0; + + if (fm_mode >= FM_MODE_ENTRY_MAX) { + fmerr("Invalid FM mode\n"); + return -EINVAL; + } + if (fmdev->curr_fmmode == fm_mode) { + fmdbg("Already fm is in mode(%d)\n", fm_mode); + return ret; + } + + switch (fm_mode) { + case FM_MODE_OFF: /* OFF Mode */ + ret = fm_power_down(fmdev); + if (ret < 0) { + fmerr("Failed to set OFF mode\n"); + return ret; + } + break; + + case FM_MODE_TX: /* TX Mode */ + case FM_MODE_RX: /* RX Mode */ + /* Power down before switching to TX or RX mode */ + if (fmdev->curr_fmmode != FM_MODE_OFF) { + ret = fm_power_down(fmdev); + if (ret < 0) { + fmerr("Failed to set OFF mode\n"); + return ret; + } + msleep(30); + } + ret = fm_power_up(fmdev, fm_mode); + if (ret < 0) { + fmerr("Failed to load firmware\n"); + return ret; + } + } + fmdev->curr_fmmode = fm_mode; + + /* Set default configuration */ + if (fmdev->curr_fmmode == FM_MODE_RX) { + fmdbg("Loading default rx configuration..\n"); + ret = load_default_rx_configuration(fmdev); + if (ret < 0) + fmerr("Failed to load default values\n"); + } + + return ret; +} + +/* Returns current FM mode (TX, RX, OFF) */ +u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) +{ + if (!test_bit(FM_CORE_READY, &fmdev->flag)) { + fmerr("FM core is not ready\n"); + return -EPERM; + } + if (fmmode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *fmmode = fmdev->curr_fmmode; + return 0; +} + +/* Called by ST layer when FM packet is available */ +static long fm_st_receive(void *arg, struct sk_buff *skb) +{ + struct fmdev *fmdev; + + fmdev = (struct fmdev *)arg; + + if (skb == NULL) { + fmerr("Invalid SKB received from ST\n"); + return -EFAULT; + } + + if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) { + fmerr("Received SKB (%p) is not FM Channel 8 pkt\n", skb); + return -EINVAL; + } + + memcpy(skb_push(skb, 1), &skb->cb[0], 1); + skb_queue_tail(&fmdev->rx_q, skb); + tasklet_schedule(&fmdev->rx_task); + + return 0; +} + +/* + * Called by ST layer to indicate protocol registration completion + * status. + */ +static void fm_st_reg_comp_cb(void *arg, char data) +{ + struct fmdev *fmdev; + + fmdev = (struct fmdev *)arg; + fmdev->streg_cbdata = data; + complete(&wait_for_fmdrv_reg_comp); +} + +/* + * This function will be called from FM V4L2 open function. + * Register with ST driver and initialize driver data. + */ +u32 fmc_prepare(struct fmdev *fmdev) +{ + static struct st_proto_s fm_st_proto; + u32 ret; + + if (test_bit(FM_CORE_READY, &fmdev->flag)) { + fmdbg("FM Core is already up\n"); + return 0; + } + + memset(&fm_st_proto, 0, sizeof(fm_st_proto)); + fm_st_proto.recv = fm_st_receive; + fm_st_proto.match_packet = NULL; + fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb; + fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */ + fm_st_proto.priv_data = fmdev; + fm_st_proto.chnl_id = 0x08; + fm_st_proto.max_frame_size = 0xff; + fm_st_proto.hdr_len = 1; + fm_st_proto.offset_len_in_hdr = 0; + fm_st_proto.len_size = 1; + fm_st_proto.reserve = 1; + + ret = st_register(&fm_st_proto); + if (ret == -EINPROGRESS) { + init_completion(&wait_for_fmdrv_reg_comp); + fmdev->streg_cbdata = -EINPROGRESS; + fmdbg("%s waiting for ST reg completion signal\n", __func__); + + ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, + FM_ST_REG_TIMEOUT); + + if (!ret) { + fmerr("Timeout(%d sec), didn't get reg " + "completion signal from ST\n", + jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000); + return -ETIMEDOUT; + } + if (fmdev->streg_cbdata != 0) { + fmerr("ST reg comp CB called with error " + "status %d\n", fmdev->streg_cbdata); + return -EAGAIN; + } + + ret = 0; + } else if (ret == -1) { + fmerr("st_register failed %d\n", ret); + return -EAGAIN; + } + + if (fm_st_proto.write != NULL) { + g_st_write = fm_st_proto.write; + } else { + fmerr("Failed to get ST write func pointer\n"); + ret = st_unregister(&fm_st_proto); + if (ret < 0) + fmerr("st_unregister failed %d\n", ret); + return -EAGAIN; + } + + spin_lock_init(&fmdev->rds_buff_lock); + spin_lock_init(&fmdev->resp_skb_lock); + + /* Initialize TX queue and TX tasklet */ + skb_queue_head_init(&fmdev->tx_q); + tasklet_init(&fmdev->tx_task, send_tasklet, (unsigned long)fmdev); + + /* Initialize RX Queue and RX tasklet */ + skb_queue_head_init(&fmdev->rx_q); + tasklet_init(&fmdev->rx_task, recv_tasklet, (unsigned long)fmdev); + + fmdev->irq_info.stage = 0; + atomic_set(&fmdev->tx_cnt, 1); + fmdev->resp_comp = NULL; + + init_timer(&fmdev->irq_info.timer); + fmdev->irq_info.timer.function = &int_timeout_handler; + fmdev->irq_info.timer.data = (unsigned long)fmdev; + /*TODO: add FM_STIC_EVENT later */ + fmdev->irq_info.mask = FM_MAL_EVENT; + + /* Region info */ + memcpy(&fmdev->rx.region, ®ion_configs[default_radio_region], + sizeof(struct region_info)); + + fmdev->rx.mute_mode = FM_MUTE_OFF; + fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF; + fmdev->rx.rds.flag = FM_RDS_DISABLE; + fmdev->rx.freq = FM_UNDEFINED_FREQ; + fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS; + fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF; + fmdev->irq_info.retry = 0; + + fm_rx_reset_rds_cache(fmdev); + init_waitqueue_head(&fmdev->rx.rds.read_queue); + + fm_rx_reset_station_info(fmdev); + set_bit(FM_CORE_READY, &fmdev->flag); + + return ret; +} + +/* + * This function will be called from FM V4L2 release function. + * Unregister from ST driver. + */ +u32 fmc_release(struct fmdev *fmdev) +{ + static struct st_proto_s fm_st_proto; + u32 ret; + + if (!test_bit(FM_CORE_READY, &fmdev->flag)) { + fmdbg("FM Core is already down\n"); + return 0; + } + /* Service pending read */ + wake_up_interruptible(&fmdev->rx.rds.read_queue); + + tasklet_kill(&fmdev->tx_task); + tasklet_kill(&fmdev->rx_task); + + skb_queue_purge(&fmdev->tx_q); + skb_queue_purge(&fmdev->rx_q); + + fmdev->resp_comp = NULL; + fmdev->rx.freq = 0; + + memset(&fm_st_proto, 0, sizeof(fm_st_proto)); + fm_st_proto.chnl_id = 0x08; + + ret = st_unregister(&fm_st_proto); + + if (ret < 0) + fmerr("Failed to de-register FM from ST %d\n", ret); + else + fmdbg("Successfully unregistered from ST\n"); + + clear_bit(FM_CORE_READY, &fmdev->flag); + return ret; +} + +/* + * Module init function. Ask FM V4L module to register video device. + * Allocate memory for FM driver context and RX RDS buffer. + */ +static int __init fm_drv_init(void) +{ + struct fmdev *fmdev = NULL; + u32 ret = -ENOMEM; + + fmdbg("FM driver version %s\n", FM_DRV_VERSION); + + fmdev = kzalloc(sizeof(struct fmdev), GFP_KERNEL); + if (NULL == fmdev) { + fmerr("Can't allocate operation structure memory\n"); + return ret; + } + fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLK_SIZE; + fmdev->rx.rds.buff = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL); + if (NULL == fmdev->rx.rds.buff) { + fmerr("Can't allocate rds ring buffer\n"); + goto rel_dev; + } + + ret = fm_v4l2_init_video_device(fmdev, radio_nr); + if (ret < 0) + goto rel_rdsbuf; + + fmdev->irq_info.handlers = int_handler_table; + fmdev->curr_fmmode = FM_MODE_OFF; + fmdev->tx_data.pwr_lvl = FM_PWR_LVL_DEF; + fmdev->tx_data.preemph = FM_TX_PREEMPH_50US; + return ret; + +rel_rdsbuf: + kfree(fmdev->rx.rds.buff); +rel_dev: + kfree(fmdev); + + return ret; +} + +/* Module exit function. Ask FM V4L module to unregister video device */ +static void __exit fm_drv_exit(void) +{ + struct fmdev *fmdev = NULL; + + fmdev = fm_v4l2_deinit_video_device(); + if (fmdev != NULL) { + kfree(fmdev->rx.rds.buff); + kfree(fmdev); + } +} + +module_init(fm_drv_init); +module_exit(fm_drv_exit); + +/* ------------- Module Info ------------- */ +MODULE_AUTHOR("Manjunatha Halli "); +MODULE_DESCRIPTION("FM Driver for TI's Connectivity chip. " FM_DRV_VERSION); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_common.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_common.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,402 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * FM Common module header file + * + * Copyright (C) 2011 Texas Instruments + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + * + */ + +#ifndef _FMDRV_COMMON_H +#define _FMDRV_COMMON_H + +#define FM_ST_REG_TIMEOUT msecs_to_jiffies(6000) /* 6 sec */ +#define FM_PKT_LOGICAL_CHAN_NUMBER 0x08 /* Logical channel 8 */ + +#define REG_RD 0x1 +#define REG_WR 0x0 + +struct fm_reg_table { + u8 opcode; + u8 type; + u8 *name; +}; + +#define STEREO_GET 0 +#define RSSI_LVL_GET 1 +#define IF_COUNT_GET 2 +#define FLAG_GET 3 +#define RDS_SYNC_GET 4 +#define RDS_DATA_GET 5 +#define FREQ_SET 10 +#define AF_FREQ_SET 11 +#define MOST_MODE_SET 12 +#define MOST_BLEND_SET 13 +#define DEMPH_MODE_SET 14 +#define SEARCH_LVL_SET 15 +#define BAND_SET 16 +#define MUTE_STATUS_SET 17 +#define RDS_PAUSE_LVL_SET 18 +#define RDS_PAUSE_DUR_SET 19 +#define RDS_MEM_SET 20 +#define RDS_BLK_B_SET 21 +#define RDS_MSK_B_SET 22 +#define RDS_PI_MASK_SET 23 +#define RDS_PI_SET 24 +#define RDS_SYSTEM_SET 25 +#define INT_MASK_SET 26 +#define SEARCH_DIR_SET 27 +#define VOLUME_SET 28 +#define AUDIO_ENABLE_SET 29 +#define PCM_MODE_SET 30 +#define I2S_MODE_CONFIG_SET 31 +#define POWER_SET 32 +#define INTX_CONFIG_SET 33 +#define PULL_EN_SET 34 +#define HILO_SET 35 +#define SWITCH2FREF 36 +#define FREQ_DRIFT_REPORT 37 + +#define PCE_GET 40 +#define FIRM_VER_GET 41 +#define ASIC_VER_GET 42 +#define ASIC_ID_GET 43 +#define MAN_ID_GET 44 +#define TUNER_MODE_SET 45 +#define STOP_SEARCH 46 +#define RDS_CNTRL_SET 47 + +#define WRITE_HARDWARE_REG 100 +#define CODE_DOWNLOAD 101 +#define RESET 102 + +#define FM_POWER_MODE 254 +#define FM_INTERRUPT 255 + +/* Transmitter API */ + +#define CHANL_SET 55 +#define CHANL_BW_SET 56 +#define REF_SET 57 +#define POWER_ENB_SET 90 +#define POWER_ATT_SET 58 +#define POWER_LEV_SET 59 +#define AUDIO_DEV_SET 60 +#define PILOT_DEV_SET 61 +#define RDS_DEV_SET 62 +#define TX_BAND_SET 65 +#define PUPD_SET 91 +#define AUDIO_IO_SET 63 +#define PREMPH_SET 64 +#define MONO_SET 66 +#define MUTE 92 +#define MPX_LMT_ENABLE 67 +#define PI_SET 93 +#define ECC_SET 69 +#define PTY 70 +#define AF 71 +#define DISPLAY_MODE 74 +#define RDS_REP_SET 77 +#define RDS_CONFIG_DATA_SET 98 +#define RDS_DATA_SET 99 +#define RDS_DATA_ENB 94 +#define TA_SET 78 +#define TP_SET 79 +#define DI_SET 80 +#define MS_SET 81 +#define PS_SCROLL_SPEED 82 +#define TX_AUDIO_LEVEL_TEST 96 +#define TX_AUDIO_LEVEL_TEST_THRESHOLD 73 +#define TX_AUDIO_INPUT_LEVEL_RANGE_SET 54 +#define RX_ANTENNA_SELECT 87 +#define I2C_DEV_ADDR_SET 86 +#define REF_ERR_CALIB_PARAM_SET 88 +#define REF_ERR_CALIB_PERIODICITY_SET 89 +#define SOC_INT_TRIGGER 52 +#define SOC_AUDIO_PATH_SET 83 +#define SOC_PCMI_OVERRIDE 84 +#define SOC_I2S_OVERRIDE 85 +#define RSSI_BLOCK_SCAN_FREQ_SET 95 +#define RSSI_BLOCK_SCAN_START 97 +#define RSSI_BLOCK_SCAN_DATA_GET 5 +#define READ_FMANT_TUNE_VALUE 104 + +/* SKB helpers */ +struct fm_skb_cb { + __u8 fm_op; + struct completion *completion; +}; + +#define fm_cb(skb) ((struct fm_skb_cb *)(skb->cb)) + +/* FM Channel-8 command message format */ +struct fm_cmd_msg_hdr { + __u8 hdr; /* Logical Channel-8 */ + __u8 len; /* Number of bytes follows */ + __u8 op; /* FM Opcode */ + __u8 rd_wr; /* Read/Write command */ + __u8 dlen; /* Length of payload */ +} __attribute__ ((packed)); + +#define FM_CMD_MSG_HDR_SIZE 5 /* sizeof(struct fm_cmd_msg_hdr) */ + +/* FM Channel-8 event messgage format */ +struct fm_event_msg_hdr { + __u8 header; /* Logical Channel-8 */ + __u8 len; /* Number of bytes follows */ + __u8 status; /* Event status */ + __u8 num_fm_hci_cmds; /* Number of pkts the host allowed to send */ + __u8 op; /* FM Opcode */ + __u8 rd_wr; /* Read/Write command */ + __u8 dlen; /* Length of payload */ +} __attribute__ ((packed)); + +#define FM_EVT_MSG_HDR_SIZE 7 /* sizeof(struct fm_event_msg_hdr) */ + +/* TI's magic number in firmware file */ +#define FM_FW_FILE_HEADER_MAGIC 0x42535442 + +#define FM_ENABLE 1 +#define FM_DISABLE 0 + +/* FLAG_GET register bits */ +#define FM_FR_EVENT (1 << 0) +#define FM_BL_EVENT (1 << 1) +#define FM_RDS_EVENT (1 << 2) +#define FM_BBLK_EVENT (1 << 3) +#define FM_LSYNC_EVENT (1 << 4) +#define FM_LEV_EVENT (1 << 5) +#define FM_IFFR_EVENT (1 << 6) +#define FM_PI_EVENT (1 << 7) +#define FM_PD_EVENT (1 << 8) +#define FM_STIC_EVENT (1 << 9) +#define FM_MAL_EVENT (1 << 10) +#define FM_POW_ENB_EVENT (1 << 11) + +/* + * Firmware files of FM. ASIC ID and ASIC version will be appened to this, + * later. + */ +#define FM_FMC_FW_FILE_START ("fmc_ch8") +#define FM_RX_FW_FILE_START ("fm_rx_ch8") +#define FM_TX_FW_FILE_START ("fm_tx_ch8") + +#define FM_UNDEFINED_FREQ 0xFFFFFFFF + +/* Band types */ +#define FM_BAND_EUROPE_US 0 +#define FM_BAND_JAPAN 1 + +/* Seek directions */ +#define FM_SEARCH_DIRECTION_DOWN 0 +#define FM_SEARCH_DIRECTION_UP 1 + +/* Tunner modes */ +#define FM_TUNER_STOP_SEARCH_MODE 0 +#define FM_TUNER_PRESET_MODE 1 +#define FM_TUNER_AUTONOMOUS_SEARCH_MODE 2 +#define FM_TUNER_AF_JUMP_MODE 3 + +/* Min and Max volume */ +#define FM_RX_VOLUME_MIN 0 +#define FM_RX_VOLUME_MAX 70 + +/* Volume gain step */ +#define FM_RX_VOLUME_GAIN_STEP 0x370 + +/* Mute modes */ +#define FM_MUTE_ON 0 +#define FM_MUTE_OFF 1 +#define FM_MUTE_ATTENUATE 2 + +#define FM_RX_UNMUTE_MODE 0x00 +#define FM_RX_RF_DEP_MODE 0x01 +#define FM_RX_AC_MUTE_MODE 0x02 +#define FM_RX_HARD_MUTE_LEFT_MODE 0x04 +#define FM_RX_HARD_MUTE_RIGHT_MODE 0x08 +#define FM_RX_SOFT_MUTE_FORCE_MODE 0x10 + +/* RF dependent mute mode */ +#define FM_RX_RF_DEPENDENT_MUTE_ON 1 +#define FM_RX_RF_DEPENDENT_MUTE_OFF 0 + +/* RSSI threshold min and max */ +#define FM_RX_RSSI_THRESHOLD_MIN -128 +#define FM_RX_RSSI_THRESHOLD_MAX 127 + +/* Stereo/Mono mode */ +#define FM_STEREO_MODE 0 +#define FM_MONO_MODE 1 +#define FM_STEREO_SOFT_BLEND 1 + +/* FM RX De-emphasis filter modes */ +#define FM_RX_EMPHASIS_FILTER_50_USEC 0 +#define FM_RX_EMPHASIS_FILTER_75_USEC 1 + +/* FM RDS modes */ +#define FM_RDS_DISABLE 0 +#define FM_RDS_ENABLE 1 + +#define FM_NO_PI_CODE 0 + +/* FM and RX RDS block enable/disable */ +#define FM_RX_PWR_SET_FM_ON_RDS_OFF 0x1 +#define FM_RX_PWR_SET_FM_AND_RDS_BLK_ON 0x3 +#define FM_RX_PWR_SET_FM_AND_RDS_BLK_OFF 0x0 + +/* RX RDS */ +#define FM_RX_RDS_FLUSH_FIFO 0x1 +#define FM_RX_RDS_FIFO_THRESHOLD 64 /* tuples */ +#define FM_RDS_BLK_SIZE 3 /* 3 bytes */ + +/* RDS block types */ +#define FM_RDS_BLOCK_A 0 +#define FM_RDS_BLOCK_B 1 +#define FM_RDS_BLOCK_C 2 +#define FM_RDS_BLOCK_Ctag 3 +#define FM_RDS_BLOCK_D 4 +#define FM_RDS_BLOCK_E 5 + +#define FM_RDS_BLK_IDX_A 0 +#define FM_RDS_BLK_IDX_B 1 +#define FM_RDS_BLK_IDX_C 2 +#define FM_RDS_BLK_IDX_D 3 +#define FM_RDS_BLK_IDX_UNKNOWN 0xF0 + +#define FM_RDS_STATUS_ERR_MASK 0x18 + +/* + * Represents an RDS group type & version. + * There are 15 groups, each group has 2 versions: A and B. + */ +#define FM_RDS_GROUP_TYPE_MASK_0A ((unsigned long)1<<0) +#define FM_RDS_GROUP_TYPE_MASK_0B ((unsigned long)1<<1) +#define FM_RDS_GROUP_TYPE_MASK_1A ((unsigned long)1<<2) +#define FM_RDS_GROUP_TYPE_MASK_1B ((unsigned long)1<<3) +#define FM_RDS_GROUP_TYPE_MASK_2A ((unsigned long)1<<4) +#define FM_RDS_GROUP_TYPE_MASK_2B ((unsigned long)1<<5) +#define FM_RDS_GROUP_TYPE_MASK_3A ((unsigned long)1<<6) +#define FM_RDS_GROUP_TYPE_MASK_3B ((unsigned long)1<<7) +#define FM_RDS_GROUP_TYPE_MASK_4A ((unsigned long)1<<8) +#define FM_RDS_GROUP_TYPE_MASK_4B ((unsigned long)1<<9) +#define FM_RDS_GROUP_TYPE_MASK_5A ((unsigned long)1<<10) +#define FM_RDS_GROUP_TYPE_MASK_5B ((unsigned long)1<<11) +#define FM_RDS_GROUP_TYPE_MASK_6A ((unsigned long)1<<12) +#define FM_RDS_GROUP_TYPE_MASK_6B ((unsigned long)1<<13) +#define FM_RDS_GROUP_TYPE_MASK_7A ((unsigned long)1<<14) +#define FM_RDS_GROUP_TYPE_MASK_7B ((unsigned long)1<<15) +#define FM_RDS_GROUP_TYPE_MASK_8A ((unsigned long)1<<16) +#define FM_RDS_GROUP_TYPE_MASK_8B ((unsigned long)1<<17) +#define FM_RDS_GROUP_TYPE_MASK_9A ((unsigned long)1<<18) +#define FM_RDS_GROUP_TYPE_MASK_9B ((unsigned long)1<<19) +#define FM_RDS_GROUP_TYPE_MASK_10A ((unsigned long)1<<20) +#define FM_RDS_GROUP_TYPE_MASK_10B ((unsigned long)1<<21) +#define FM_RDS_GROUP_TYPE_MASK_11A ((unsigned long)1<<22) +#define FM_RDS_GROUP_TYPE_MASK_11B ((unsigned long)1<<23) +#define FM_RDS_GROUP_TYPE_MASK_12A ((unsigned long)1<<24) +#define FM_RDS_GROUP_TYPE_MASK_12B ((unsigned long)1<<25) +#define FM_RDS_GROUP_TYPE_MASK_13A ((unsigned long)1<<26) +#define FM_RDS_GROUP_TYPE_MASK_13B ((unsigned long)1<<27) +#define FM_RDS_GROUP_TYPE_MASK_14A ((unsigned long)1<<28) +#define FM_RDS_GROUP_TYPE_MASK_14B ((unsigned long)1<<29) +#define FM_RDS_GROUP_TYPE_MASK_15A ((unsigned long)1<<30) +#define FM_RDS_GROUP_TYPE_MASK_15B ((unsigned long)1<<31) + +/* RX Alternate Frequency info */ +#define FM_RDS_MIN_AF 1 +#define FM_RDS_MAX_AF 204 +#define FM_RDS_MAX_AF_JAPAN 140 +#define FM_RDS_1_AF_FOLLOWS 225 +#define FM_RDS_25_AF_FOLLOWS 249 + +/* RDS system type (RDS/RBDS) */ +#define FM_RDS_SYSTEM_RDS 0 +#define FM_RDS_SYSTEM_RBDS 1 + +/* AF on/off */ +#define FM_RX_RDS_AF_SWITCH_MODE_ON 1 +#define FM_RX_RDS_AF_SWITCH_MODE_OFF 0 + +/* Retry count when interrupt process goes wrong */ +#define FM_IRQ_TIMEOUT_RETRY_MAX 5 /* 5 times */ + +/* Audio IO set values */ +#define FM_RX_AUDIO_ENABLE_I2S 0x01 +#define FM_RX_AUDIO_ENABLE_ANALOG 0x02 +#define FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG 0x03 +#define FM_RX_AUDIO_ENABLE_DISABLE 0x00 + +/* HI/LO set values */ +#define FM_RX_IFFREQ_TO_HI_SIDE 0x0 +#define FM_RX_IFFREQ_TO_LO_SIDE 0x1 +#define FM_RX_IFFREQ_HILO_AUTOMATIC 0x2 + +/* + * Default RX mode configuration. Chip will be configured + * with this default values after loading RX firmware. + */ +#define FM_DEFAULT_RX_VOLUME 10 +#define FM_DEFAULT_RSSI_THRESHOLD 3 + +/* Range for TX power level in units for dB/uV */ +#define FM_PWR_LVL_LOW 91 +#define FM_PWR_LVL_HIGH 122 + +/* Chip specific default TX power level value */ +#define FM_PWR_LVL_DEF 4 + +/* FM TX Pre-emphasis filter values */ +#define FM_TX_PREEMPH_OFF 1 +#define FM_TX_PREEMPH_50US 0 +#define FM_TX_PREEMPH_75US 2 + +/* FM TX antenna impedance values */ +#define FM_TX_ANT_IMP_50 0 +#define FM_TX_ANT_IMP_200 1 +#define FM_TX_ANT_IMP_500 2 + +/* Functions exported by FM common sub-module */ +u32 fmc_prepare(struct fmdev *); +u32 fmc_release(struct fmdev *); + +void fmc_update_region_info(struct fmdev *, u8); +u32 fmc_send_cmd(struct fmdev *, u8, u16, + void *, unsigned int, void *, int *); +u32 fmc_is_rds_data_available(struct fmdev *, struct file *, + struct poll_table_struct *); +u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *, + u8 __user *, size_t); + +u32 fmc_set_freq(struct fmdev *, u32); +u32 fmc_set_mode(struct fmdev *, u8); +u32 fmc_set_region(struct fmdev *, u8); +u32 fmc_set_mute_mode(struct fmdev *, u8); +u32 fmc_set_stereo_mono(struct fmdev *, u16); +u32 fmc_set_rds_mode(struct fmdev *, u8); + +u32 fmc_get_freq(struct fmdev *, u32 *); +u32 fmc_get_region(struct fmdev *, u8 *); +u32 fmc_get_mode(struct fmdev *, u8 *); + +/* + * channel spacing + */ +#define FM_CHANNEL_SPACING_50KHZ 1 +#define FM_CHANNEL_SPACING_100KHZ 2 +#define FM_CHANNEL_SPACING_200KHZ 4 +#define FM_FREQ_MUL 50 + +#endif + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,242 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * + * Common header for all FM driver sub-modules. + * + * Copyright (C) 2011 Texas Instruments + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + * + */ + +#ifndef _FM_DRV_H +#define _FM_DRV_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FM_DRV_VERSION "0.10" +/* Should match with FM_DRV_VERSION */ +#define FM_DRV_RADIO_VERSION KERNEL_VERSION(0, 0, 1) +#define FM_DRV_NAME "ti_fmdrv" +#define FM_DRV_CARD_SHORT_NAME "TI FM Radio" +#define FM_DRV_CARD_LONG_NAME "Texas Instruments FM Radio" + +/* Flag info */ +#define FM_INTTASK_RUNNING 0 +#define FM_INTTASK_SCHEDULE_PENDING 1 +#define FM_FW_DW_INPROGRESS 2 +#define FM_CORE_READY 3 +#define FM_CORE_TRANSPORT_READY 4 +#define FM_AF_SWITCH_INPROGRESS 5 +#define FM_CORE_TX_XMITING 6 + +#define FM_TUNE_COMPLETE 0x1 +#define FM_BAND_LIMIT 0x2 + +#define FM_DRV_TX_TIMEOUT (5*HZ) /* 5 seconds */ +#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */ + +#define fmerr(format, ...) \ + printk(KERN_ERR "fmdrv: " format, ## __VA_ARGS__) +#define fmwarn(format, ...) \ + printk(KERN_WARNING "fmdrv: " format, ##__VA_ARGS__) +#ifdef DEBUG +#define fmdbg(format, ...) \ + printk(KERN_DEBUG "fmdrv: " format, ## __VA_ARGS__) +#else /* DEBUG */ +#define fmdbg(format, ...) +#endif +enum { + FM_MODE_OFF, + FM_MODE_TX, + FM_MODE_RX, + FM_MODE_ENTRY_MAX +}; + +#define FM_RX_RDS_INFO_FIELD_MAX 8 /* 4 Group * 2 Bytes */ + +/* RX RDS data format */ +struct fm_rdsdata_format { + union { + struct { + u8 buff[FM_RX_RDS_INFO_FIELD_MAX]; + } groupdatabuff; + struct { + u16 pidata; + u8 blk_b[2]; + u8 blk_c[2]; + u8 blk_d[2]; + } groupgeneral; + struct { + u16 pidata; + u8 blk_b[2]; + u8 af[2]; + u8 ps[2]; + } group0A; + struct { + u16 pi[2]; + u8 blk_b[2]; + u8 ps[2]; + } group0B; + } data; +}; + +/* FM region (Europe/US, Japan) info */ +struct region_info { + u32 chanl_space; + u32 bot_freq; + u32 top_freq; + u8 fm_band; +}; +struct fmdev; +typedef void (*int_handler_prototype) (struct fmdev *); + +/* FM Interrupt processing related info */ +struct fm_irq { + u8 stage; + u16 flag; /* FM interrupt flag */ + u16 mask; /* FM interrupt mask */ + /* Interrupt process timeout handler */ + struct timer_list timer; + u8 retry; + int_handler_prototype *handlers; +}; + +/* RDS info */ +struct fm_rds { + u8 flag; /* RX RDS on/off status */ + u8 last_blk_idx; /* Last received RDS block */ + + /* RDS buffer */ + wait_queue_head_t read_queue; + u32 buf_size; /* Size is always multiple of 3 */ + u32 wr_idx; + u32 rd_idx; + u8 *buff; +}; + +#define FM_RDS_MAX_AF_LIST 25 + +/* + * Current RX channel Alternate Frequency cache. + * This info is used to switch to other freq (AF) + * when current channel signal strengh is below RSSI threshold. + */ +struct tuned_station_info { + u16 picode; + u32 af_cache[FM_RDS_MAX_AF_LIST]; + u8 afcache_size; + u8 af_list_max; +}; + +/* FM RX mode info */ +struct fm_rx { + struct region_info region; /* Current selected band */ + u32 freq; /* Current RX frquency */ + u8 mute_mode; /* Current mute mode */ + u8 deemphasis_mode; /* Current deemphasis mode */ + /* RF dependent soft mute mode */ + u8 rf_depend_mute; + u16 volume; /* Current volume level */ + u16 rssi_threshold; /* Current RSSI threshold level */ + /* Holds the index of the current AF jump */ + u8 afjump_idx; + /* Will hold the frequency before the jump */ + u32 freq_before_jump; + u8 rds_mode; /* RDS operation mode (RDS/RDBS) */ + u8 af_mode; /* Alternate frequency on/off */ + struct tuned_station_info stat_info; + struct fm_rds rds; +}; + +#define FMTX_RDS_TXT_STR_SIZE 25 +/* + * FM TX RDS data + * + * @ text_type: is the text following PS or RT + * @ text: radio text string which could either be PS or RT + * @ af_freq: alternate frequency for Tx + * TODO: to be declared in application + */ +struct tx_rds { + u8 text_type; + u8 text[FMTX_RDS_TXT_STR_SIZE]; + u8 flag; + u32 af_freq; +}; +/* + * FM TX global data + * + * @ pwr_lvl: Power Level of the Transmission from mixer control + * @ xmit_state: Transmission state = Updated locally upon Start/Stop + * @ audio_io: i2S/Analog + * @ tx_frq: Transmission frequency + */ +struct fmtx_data { + u8 pwr_lvl; + u8 xmit_state; + u8 audio_io; + u8 region; + u16 aud_mode; + u32 preemph; + u32 tx_frq; + struct tx_rds rds; +}; + +/* FM driver operation structure */ +struct fmdev { + struct video_device *radio_dev; /* V4L2 video device pointer */ + struct snd_card *card; /* Card which holds FM mixer controls */ + u16 asci_id; + spinlock_t rds_buff_lock; /* To protect access to RDS buffer */ + spinlock_t resp_skb_lock; /* To protect access to received SKB */ + + long flag; /* FM driver state machine info */ + u8 streg_cbdata; /* status of ST registration */ + + struct sk_buff_head rx_q; /* RX queue */ + struct tasklet_struct rx_task; /* RX Tasklet */ + + struct sk_buff_head tx_q; /* TX queue */ + struct tasklet_struct tx_task; /* TX Tasklet */ + unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */ + atomic_t tx_cnt; /* Number of packets can send at a time */ + + struct sk_buff *resp_skb; /* Response from the chip */ + /* Main task completion handler */ + struct completion maintask_comp; + /* Opcode of last command sent to the chip */ + u8 pre_op; + /* Handler used for wakeup when response packet is received */ + struct completion *resp_comp; + struct fm_irq irq_info; + u8 curr_fmmode; /* Current FM chip mode (TX, RX, OFF) */ + struct fm_rx rx; /* FM receiver info */ + struct fmtx_data tx_data; + + /* V4L2 ctrl framwork handler*/ + struct v4l2_ctrl_handler ctrl_handler; + + /* For core assisted locking */ + struct mutex mutex; +}; +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_rx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_rx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_rx.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_rx.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,847 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * This sub-module of FM driver implements FM RX functionality. + * + * Copyright (C) 2011 Texas Instruments + * Author: Raja Mani + * Author: Manjunatha Halli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 "fmdrv.h" +#include "fmdrv_common.h" +#include "fmdrv_rx.h" + +void fm_rx_reset_rds_cache(struct fmdev *fmdev) +{ + fmdev->rx.rds.flag = FM_RDS_DISABLE; + fmdev->rx.rds.last_blk_idx = 0; + fmdev->rx.rds.wr_idx = 0; + fmdev->rx.rds.rd_idx = 0; + + if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) + fmdev->irq_info.mask |= FM_LEV_EVENT; +} + +void fm_rx_reset_station_info(struct fmdev *fmdev) +{ + fmdev->rx.stat_info.picode = FM_NO_PI_CODE; + fmdev->rx.stat_info.afcache_size = 0; + fmdev->rx.stat_info.af_list_max = 0; +} + +u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq) +{ + unsigned long timeleft; + u16 payload, curr_frq, intr_flag; + u32 curr_frq_in_khz; + u32 ret, resp_len; + + if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) { + fmerr("Invalid frequency %d\n", freq); + return -EINVAL; + } + + /* Set audio enable */ + payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG; + + ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set hilo to automatic selection */ + payload = FM_RX_IFFREQ_HILO_AUTOMATIC; + ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Calculate frequency index and set*/ + payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; + + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Read flags - just to clear any pending interrupts if we had */ + ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); + if (ret < 0) + return ret; + + /* Enable FR, BL interrupts */ + intr_flag = fmdev->irq_info.mask; + fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Start tune */ + payload = FM_TUNER_PRESET_MODE; + ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + goto exit; + + /* Wait for tune ended interrupt */ + init_completion(&fmdev->maintask_comp); + timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, + FM_DRV_TX_TIMEOUT); + if (!timeleft) { + fmerr("Timeout(%d sec),didn't get tune ended int\n", + jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); + ret = -ETIMEDOUT; + goto exit; + } + + /* Read freq back to confirm */ + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len); + if (ret < 0) + goto exit; + + curr_frq = be16_to_cpu(curr_frq); + curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL)); + + if (curr_frq_in_khz != freq) { + pr_info("Frequency is set to (%d) but " + "requested freq is (%d)\n", curr_frq_in_khz, freq); + } + + /* Update local cache */ + fmdev->rx.freq = curr_frq_in_khz; +exit: + /* Re-enable default FM interrupts */ + fmdev->irq_info.mask = intr_flag; + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Reset RDS cache and current station pointers */ + fm_rx_reset_rds_cache(fmdev); + fm_rx_reset_station_info(fmdev); + + return ret; +} + +static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) +{ + u16 payload; + u32 ret; + + if (spacing > 0 && spacing <= 50000) + spacing = FM_CHANNEL_SPACING_50KHZ; + else if (spacing > 50000 && spacing <= 100000) + spacing = FM_CHANNEL_SPACING_100KHZ; + else + spacing = FM_CHANNEL_SPACING_200KHZ; + + /* set channel spacing */ + payload = spacing; + ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL; + + return ret; +} + +u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, + u32 wrap_around, u32 spacing) +{ + u32 resp_len; + u16 curr_frq, next_frq, last_frq; + u16 payload, int_reason, intr_flag; + u16 offset, space_idx; + unsigned long timeleft; + u32 ret; + + /* Set channel spacing */ + ret = fm_rx_set_channel_spacing(fmdev, spacing); + if (ret < 0) { + fmerr("Failed to set channel spacing\n"); + return ret; + } + + /* Read the current frequency from chip */ + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, + sizeof(curr_frq), &curr_frq, &resp_len); + if (ret < 0) + return ret; + + curr_frq = be16_to_cpu(curr_frq); + last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; + + /* Check the offset in order to be aligned to the channel spacing*/ + space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL; + offset = curr_frq % space_idx; + + next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ : + curr_frq - space_idx /* Seek Down */ ; + + /* + * Add or subtract offset in order to stay aligned to the channel + * spacing. + */ + if ((short)next_frq < 0) + next_frq = last_frq - offset; + else if (next_frq > last_frq) + next_frq = 0 + offset; + +again: + /* Set calculated next frequency to perform seek */ + payload = next_frq; + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set search direction (0:Seek Down, 1:Seek Up) */ + payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN); + ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Read flags - just to clear any pending interrupts if we had */ + ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); + if (ret < 0) + return ret; + + /* Enable FR, BL interrupts */ + intr_flag = fmdev->irq_info.mask; + fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Start seek */ + payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE; + ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Wait for tune ended/band limit reached interrupt */ + init_completion(&fmdev->maintask_comp); + timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, + FM_DRV_RX_SEEK_TIMEOUT); + if (!timeleft) { + fmerr("Timeout(%d sec),didn't get tune ended int\n", + jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000); + return -ETIMEDOUT; + } + + int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT); + + /* Re-enable default FM interrupts */ + fmdev->irq_info.mask = intr_flag; + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + if (int_reason & FM_BL_EVENT) { + if (wrap_around == 0) { + fmdev->rx.freq = seek_upward ? + fmdev->rx.region.top_freq : + fmdev->rx.region.bot_freq; + } else { + fmdev->rx.freq = seek_upward ? + fmdev->rx.region.bot_freq : + fmdev->rx.region.top_freq; + /* Calculate frequency index to write */ + next_frq = (fmdev->rx.freq - + fmdev->rx.region.bot_freq) / FM_FREQ_MUL; + goto again; + } + } else { + /* Read freq to know where operation tune operation stopped */ + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, + &curr_frq, &resp_len); + if (ret < 0) + return ret; + + curr_frq = be16_to_cpu(curr_frq); + fmdev->rx.freq = (fmdev->rx.region.bot_freq + + ((u32)curr_frq * FM_FREQ_MUL)); + + } + /* Reset RDS cache and current station pointers */ + fm_rx_reset_rds_cache(fmdev); + fm_rx_reset_station_info(fmdev); + + return ret; +} + +u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) { + fmerr("Volume is not within(%d-%d) range\n", + FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX); + return -EINVAL; + } + vol_to_set *= FM_RX_VOLUME_GAIN_STEP; + + payload = vol_to_set; + ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.volume = vol_to_set; + return ret; +} + +/* Get volume */ +u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_vol == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP; + + return 0; +} + +/* To get current band's bottom and top frequency */ +u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) +{ + if (bot_freq != NULL) + *bot_freq = fmdev->rx.region.bot_freq; + + if (top_freq != NULL) + *top_freq = fmdev->rx.region.top_freq; + + return 0; +} + +/* Returns current band index (0-Europe/US; 1-Japan) */ +void fm_rx_get_region(struct fmdev *fmdev, u8 *region) +{ + *region = fmdev->rx.region.fm_band; +} + +/* Sets band (0-Europe/US; 1-Japan) */ +u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) +{ + u16 payload; + u32 new_frq = 0; + u32 ret; + + if (region_to_set != FM_BAND_EUROPE_US && + region_to_set != FM_BAND_JAPAN) { + fmerr("Invalid band\n"); + return -EINVAL; + } + + if (fmdev->rx.region.fm_band == region_to_set) { + fmerr("Requested band is already configured\n"); + return 0; + } + + /* Send cmd to set the band */ + payload = (u16)region_to_set; + ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmc_update_region_info(fmdev, region_to_set); + + /* Check whether current RX frequency is within band boundary */ + if (fmdev->rx.freq < fmdev->rx.region.bot_freq) + new_frq = fmdev->rx.region.bot_freq; + else if (fmdev->rx.freq > fmdev->rx.region.top_freq) + new_frq = fmdev->rx.region.top_freq; + + if (new_frq) { + fmdbg("Current freq is not within band limit boundary," + "switching to %d KHz\n", new_frq); + /* Current RX frequency is not in range. So, update it */ + ret = fm_rx_set_freq(fmdev, new_frq); + } + + return ret; +} + +/* Reads current mute mode (Mute Off/On/Attenuate)*/ +u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_mute_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_mute_mode = fmdev->rx.mute_mode; + + return 0; +} + +static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) +{ + u16 payload, muteval; + u32 ret; + + muteval = 0; + switch (fmdev->rx.mute_mode) { + case FM_MUTE_ON: + muteval = FM_RX_AC_MUTE_MODE; + break; + + case FM_MUTE_OFF: + muteval = FM_RX_UNMUTE_MODE; + break; + + case FM_MUTE_ATTENUATE: + muteval = FM_RX_SOFT_MUTE_FORCE_MODE; + break; + } + if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON) + muteval |= FM_RX_RF_DEP_MODE; + else + muteval &= ~FM_RX_RF_DEP_MODE; + + payload = muteval; + ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +/* Configures mute mode (Mute Off/On/Attenuate) */ +u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +{ + u8 org_state; + u32 ret; + + if (fmdev->rx.mute_mode == mute_mode_toset) + return 0; + + org_state = fmdev->rx.mute_mode; + fmdev->rx.mute_mode = mute_mode_toset; + + ret = fm_config_rx_mute_reg(fmdev); + if (ret < 0) { + fmdev->rx.mute_mode = org_state; + return ret; + } + + return 0; +} + +/* Gets RF dependent soft mute mode enable/disable status */ +u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_mute_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_mute_mode = fmdev->rx.rf_depend_mute; + + return 0; +} + +/* Sets RF dependent soft mute mode */ +u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) +{ + u8 org_state; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON && + rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) { + fmerr("Invalid RF dependent soft mute\n"); + return -EINVAL; + } + if (fmdev->rx.rf_depend_mute == rfdepend_mute) + return 0; + + org_state = fmdev->rx.rf_depend_mute; + fmdev->rx.rf_depend_mute = rfdepend_mute; + + ret = fm_config_rx_mute_reg(fmdev); + if (ret < 0) { + fmdev->rx.rf_depend_mute = org_state; + return ret; + } + + return 0; +} + +/* Returns the signal strength level of current channel */ +u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) +{ + u16 curr_rssi_lel; + u32 resp_len; + u32 ret; + + if (rssilvl == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + /* Read current RSSI level */ + ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2, + &curr_rssi_lel, &resp_len); + if (ret < 0) + return ret; + + *rssilvl = be16_to_cpu(curr_rssi_lel); + + return 0; +} + +/* + * Sets the signal strength level that once reached + * will stop the auto search process + */ +u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) +{ + u16 payload; + u32 ret; + + if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN || + rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) { + fmerr("Invalid RSSI threshold level\n"); + return -EINVAL; + } + payload = (u16)rssi_lvl_toset; + ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.rssi_threshold = rssi_lvl_toset; + + return 0; +} + +/* Returns current RX RSSI threshold value */ +u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_rssi_lvl == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_rssi_lvl = fmdev->rx.rssi_threshold; + + return 0; +} + +/* Sets RX stereo/mono modes */ +u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +{ + u16 payload; + u32 ret; + + if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) { + fmerr("Invalid mode\n"); + return -EINVAL; + } + + /* Set stereo/mono mode */ + payload = (u16)mode; + ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set stereo blending mode */ + payload = FM_STEREO_SOFT_BLEND; + ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +/* Gets current RX stereo/mono mode */ +u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) +{ + u16 curr_mode; + u32 ret, resp_len; + + if (mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2, + &curr_mode, &resp_len); + if (ret < 0) + return ret; + + *mode = be16_to_cpu(curr_mode); + + return 0; +} + +/* Choose RX de-emphasis filter mode (50us/75us) */ +u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (mode != FM_RX_EMPHASIS_FILTER_50_USEC && + mode != FM_RX_EMPHASIS_FILTER_75_USEC) { + fmerr("Invalid rx de-emphasis mode (%d)\n", mode); + return -EINVAL; + } + + payload = mode; + ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.deemphasis_mode = mode; + + return 0; +} + +/* Gets current RX de-emphasis filter mode */ +u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_deemphasis_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_deemphasis_mode = fmdev->rx.deemphasis_mode; + + return 0; +} + +/* Enable/Disable RX RDS */ +u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +{ + u16 payload; + u32 ret; + + if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) { + fmerr("Invalid rds option\n"); + return -EINVAL; + } + + if (rds_en_dis == FM_RDS_ENABLE + && fmdev->rx.rds.flag == FM_RDS_DISABLE) { + /* Turn on RX RDS and RDS circuit */ + payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON; + ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Clear and reset RDS FIFO */ + payload = FM_RX_RDS_FLUSH_FIFO; + ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Read flags - just to clear any pending interrupts. */ + ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, + NULL, NULL); + if (ret < 0) + return ret; + + /* Set RDS FIFO threshold value */ + payload = FM_RX_RDS_FIFO_THRESHOLD; + ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Enable RDS interrupt */ + fmdev->irq_info.mask |= FM_RDS_EVENT; + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) { + fmdev->irq_info.mask &= ~FM_RDS_EVENT; + return ret; + } + + /* Update our local flag */ + fmdev->rx.rds.flag = FM_RDS_ENABLE; + } else if (rds_en_dis == FM_RDS_DISABLE + && fmdev->rx.rds.flag == FM_RDS_ENABLE) { + /* Turn off RX RDS */ + payload = FM_RX_PWR_SET_FM_ON_RDS_OFF; + ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Reset RDS pointers */ + fmdev->rx.rds.last_blk_idx = 0; + fmdev->rx.rds.wr_idx = 0; + fmdev->rx.rds.rd_idx = 0; + fm_rx_reset_station_info(fmdev); + + /* Update RDS local cache */ + fmdev->irq_info.mask &= ~(FM_RDS_EVENT); + fmdev->rx.rds.flag = FM_RDS_DISABLE; + } + + return 0; +} + +/* Returns current RX RDS enable/disable status */ +u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_rds_en_dis == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_rds_en_dis = fmdev->rx.rds.flag; + + return 0; +} + +/* Sets RDS operation mode (RDS/RDBS) */ +u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) { + fmerr("Invalid rds mode\n"); + return -EINVAL; + } + /* Set RDS operation mode */ + payload = (u16)rds_mode; + ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.rds_mode = rds_mode; + + return 0; +} + +/* Returns current RDS operation mode */ +u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (rds_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *rds_mode = fmdev->rx.rds_mode; + + return 0; +} + +/* Configures Alternate Frequency switch mode */ +u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON && + af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) { + fmerr("Invalid af mode\n"); + return -EINVAL; + } + /* Enable/disable low RSSI interrupt based on af_mode */ + if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) + fmdev->irq_info.mask |= FM_LEV_EVENT; + else + fmdev->irq_info.mask &= ~FM_LEV_EVENT; + + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.af_mode = af_mode; + + return 0; +} + +/* Returns Alternate Frequency switch status */ +u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (af_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *af_mode = fmdev->rx.af_mode; + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_rx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_rx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_rx.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_rx.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * FM RX module header. + * + * Copyright (C) 2011 Texas Instruments + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + * + */ + +#ifndef _FMDRV_RX_H +#define _FMDRV_RX_H + +u32 fm_rx_set_freq(struct fmdev *, u32); +u32 fm_rx_set_mute_mode(struct fmdev *, u8); +u32 fm_rx_set_stereo_mono(struct fmdev *, u16); +u32 fm_rx_set_rds_mode(struct fmdev *, u8); +u32 fm_rx_set_rds_system(struct fmdev *, u8); +u32 fm_rx_set_volume(struct fmdev *, u16); +u32 fm_rx_set_rssi_threshold(struct fmdev *, short); +u32 fm_rx_set_region(struct fmdev *, u8); +u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8); +u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16); +u32 fm_rx_set_af_switch(struct fmdev *, u8); + +void fm_rx_reset_rds_cache(struct fmdev *); +void fm_rx_reset_station_info(struct fmdev *); + +u32 fm_rx_seek(struct fmdev *, u32, u32, u32); + +u32 fm_rx_get_rds_mode(struct fmdev *, u8 *); +u32 fm_rx_get_rds_system(struct fmdev *, u8 *); +u32 fm_rx_get_mute_mode(struct fmdev *, u8 *); +u32 fm_rx_get_volume(struct fmdev *, u16 *); +u32 fm_rx_get_band_freq_range(struct fmdev *, + u32 *, u32 *); +u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *); +u32 fm_rx_get_rssi_level(struct fmdev *, u16 *); +u32 fm_rx_get_rssi_threshold(struct fmdev *, short *); +u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *); +u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *); +u32 fm_rx_get_af_switch(struct fmdev *, u8 *); +void fm_rx_get_region(struct fmdev *, u8 *); + +u32 fm_rx_set_chanl_spacing(struct fmdev *, u8); +u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *); +#endif + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_tx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_tx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_tx.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_tx.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,425 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * This sub-module of FM driver implements FM TX functionality. + * + * Copyright (C) 2011 Texas Instruments + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 +#include "fmdrv.h" +#include "fmdrv_common.h" +#include "fmdrv_tx.h" + +u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +{ + u16 payload; + u32 ret; + + if (fmdev->tx_data.aud_mode == mode) + return 0; + + fmdbg("stereo mode: %d\n", mode); + + /* Set Stereo/Mono mode */ + payload = (1 - mode); + ret = fmc_send_cmd(fmdev, MONO_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->tx_data.aud_mode = mode; + + return ret; +} + +static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text) +{ + u16 payload; + u32 ret; + + ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text, + strlen(rds_text), NULL, NULL); + if (ret < 0) + return ret; + + /* Scroll mode */ + payload = (u16)0x1; + ret = fmc_send_cmd(fmdev, DISPLAY_MODE, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode) +{ + u16 payload; + u32 ret; + + /* Setting unique PI TODO: how unique? */ + payload = (u16)0xcafe; + ret = fmc_send_cmd(fmdev, PI_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set decoder id */ + payload = (u16)0xa; + ret = fmc_send_cmd(fmdev, DI_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* TODO: RDS_MODE_GET? */ + return 0; +} + +static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len) +{ + u16 payload; + u32 ret; + + len |= type << 8; + payload = len; + ret = fmc_send_cmd(fmdev, RDS_CONFIG_DATA_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* TODO: LENGTH_GET? */ + return 0; +} + +u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +{ + u16 payload; + u32 ret; + u8 rds_text[] = "Zoom2\n"; + + fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis, + FM_RDS_ENABLE, FM_RDS_DISABLE); + + if (rds_en_dis == FM_RDS_ENABLE) { + /* Set RDS length */ + set_rds_len(fmdev, 0, strlen(rds_text)); + + /* Set RDS text */ + set_rds_text(fmdev, rds_text); + + /* Set RDS mode */ + set_rds_data_mode(fmdev, 0x0); + } + + /* Send command to enable RDS */ + if (rds_en_dis == FM_RDS_ENABLE) + payload = 0x01; + else + payload = 0x00; + + ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + if (rds_en_dis == FM_RDS_ENABLE) { + /* Set RDS length */ + set_rds_len(fmdev, 0, strlen(rds_text)); + + /* Set RDS text */ + set_rds_text(fmdev, rds_text); + } + fmdev->tx_data.rds.flag = rds_en_dis; + + return 0; +} + +u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + fm_tx_set_rds_mode(fmdev, 0); + + /* Set RDS length */ + set_rds_len(fmdev, rds_type, strlen(rds_text)); + + /* Set RDS text */ + set_rds_text(fmdev, rds_text); + + /* Set RDS mode */ + set_rds_data_mode(fmdev, 0x0); + + payload = 1; + ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +u32 fm_tx_set_af(struct fmdev *fmdev, u32 af) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + fmdbg("AF: %d\n", af); + + af = (af - 87500) / 100; + payload = (u16)af; + ret = fmc_send_cmd(fmdev, TA_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +u32 fm_tx_set_region(struct fmdev *fmdev, u8 region) +{ + u16 payload; + u32 ret; + + if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) { + fmerr("Invalid band\n"); + return -EINVAL; + } + + /* Send command to set the band */ + payload = (u16)region; + ret = fmc_send_cmd(fmdev, TX_BAND_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +{ + u16 payload; + u32 ret; + + fmdbg("tx: mute mode %d\n", mute_mode_toset); + + payload = mute_mode_toset; + ret = fmc_send_cmd(fmdev, MUTE, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +/* Set TX Audio I/O */ +static u32 set_audio_io(struct fmdev *fmdev) +{ + struct fmtx_data *tx = &fmdev->tx_data; + u16 payload; + u32 ret; + + /* Set Audio I/O Enable */ + payload = tx->audio_io; + ret = fmc_send_cmd(fmdev, AUDIO_IO_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* TODO: is audio set? */ + return 0; +} + +/* Start TX Transmission */ +static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) +{ + struct fmtx_data *tx = &fmdev->tx_data; + unsigned long timeleft; + u16 payload; + u32 ret; + + /* Enable POWER_ENB interrupts */ + payload = FM_POW_ENB_EVENT; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set Power Enable */ + payload = new_xmit_state; + ret = fmc_send_cmd(fmdev, POWER_ENB_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Wait for Power Enabled */ + init_completion(&fmdev->maintask_comp); + timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, + FM_DRV_TX_TIMEOUT); + if (!timeleft) { + fmerr("Timeout(%d sec),didn't get tune ended interrupt\n", + jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); + return -ETIMEDOUT; + } + + set_bit(FM_CORE_TX_XMITING, &fmdev->flag); + tx->xmit_state = new_xmit_state; + + return 0; +} + +/* Set TX power level */ +u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) +{ + u16 payload; + struct fmtx_data *tx = &fmdev->tx_data; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + fmdbg("tx: pwr_level_to_set %ld\n", (long int)new_pwr_lvl); + + /* If the core isn't ready update global variable */ + if (!test_bit(FM_CORE_READY, &fmdev->flag)) { + tx->pwr_lvl = new_pwr_lvl; + return 0; + } + + /* Set power level: Application will specify power level value in + * units of dB/uV, whereas range and step are specific to FM chip. + * For TI's WL chips, convert application specified power level value + * to chip specific value by subtracting 122 from it. Refer to TI FM + * data sheet for details. + * */ + + payload = (FM_PWR_LVL_HIGH - new_pwr_lvl); + ret = fmc_send_cmd(fmdev, POWER_LEV_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* TODO: is the power level set? */ + tx->pwr_lvl = new_pwr_lvl; + + return 0; +} + +/* + * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us) + * Convert V4L2 specified filter values to chip specific filter values. + */ +u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) +{ + struct fmtx_data *tx = &fmdev->tx_data; + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + switch (preemphasis) { + case V4L2_PREEMPHASIS_DISABLED: + payload = FM_TX_PREEMPH_OFF; + break; + case V4L2_PREEMPHASIS_50_uS: + payload = FM_TX_PREEMPH_50US; + break; + case V4L2_PREEMPHASIS_75_uS: + payload = FM_TX_PREEMPH_75US; + break; + } + + ret = fmc_send_cmd(fmdev, PREMPH_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + tx->preemph = payload; + + return ret; +} + +/* Get the TX tuning capacitor value.*/ +u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev) +{ + u16 curr_val; + u32 ret, resp_len; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + ret = fmc_send_cmd(fmdev, READ_FMANT_TUNE_VALUE, REG_RD, + NULL, sizeof(curr_val), &curr_val, &resp_len); + if (ret < 0) + return ret; + + curr_val = be16_to_cpu(curr_val); + + return curr_val; +} + +/* Set TX Frequency */ +u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) +{ + struct fmtx_data *tx = &fmdev->tx_data; + u16 payload, chanl_index; + u32 ret; + + if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) { + enable_xmit(fmdev, 0); + clear_bit(FM_CORE_TX_XMITING, &fmdev->flag); + } + + /* Enable FR, BL interrupts */ + payload = (FM_FR_EVENT | FM_BL_EVENT); + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + tx->tx_frq = (unsigned long)freq_to_set; + fmdbg("tx: freq_to_set %ld\n", (long int)tx->tx_frq); + + chanl_index = freq_to_set / 10; + + /* Set current tuner channel */ + payload = chanl_index; + ret = fmc_send_cmd(fmdev, CHANL_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fm_tx_set_pwr_lvl(fmdev, tx->pwr_lvl); + fm_tx_set_preemph_filter(fmdev, tx->preemph); + + tx->audio_io = 0x01; /* I2S */ + set_audio_io(fmdev); + + enable_xmit(fmdev, 0x01); /* Enable transmission */ + + tx->aud_mode = FM_STEREO_MODE; + tx->rds.flag = FM_RDS_DISABLE; + + return 0; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_tx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_tx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_tx.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_tx.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * FM TX module header. + * + * Copyright (C) 2011 Texas Instruments + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + * + */ + +#ifndef _FMDRV_TX_H +#define _FMDRV_TX_H + +u32 fm_tx_set_freq(struct fmdev *, u32); +u32 fm_tx_set_pwr_lvl(struct fmdev *, u8); +u32 fm_tx_set_region(struct fmdev *, u8); +u32 fm_tx_set_mute_mode(struct fmdev *, u8); +u32 fm_tx_set_stereo_mono(struct fmdev *, u16); +u32 fm_tx_set_rds_mode(struct fmdev *, u8); +u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8); +u32 fm_tx_set_af(struct fmdev *, u32); +u32 fm_tx_set_preemph_filter(struct fmdev *, u32); +u32 fm_tx_get_tune_cap_val(struct fmdev *); + +#endif + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_v4l2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_v4l2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_v4l2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_v4l2.c 2011-06-25 16:16:07.000000000 +0000 @@ -0,0 +1,580 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * This file provides interfaces to V4L2 subsystem. + * + * This module registers with V4L2 subsystem as Radio + * data system interface (/dev/radio). During the registration, + * it will expose two set of function pointers. + * + * 1) File operation related API (open, close, read, write, poll...etc). + * 2) Set of V4L2 IOCTL complaint API. + * + * Copyright (C) 2011 Texas Instruments + * Author: Raja Mani + * Author: Manjunatha Halli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 "fmdrv.h" +#include "fmdrv_v4l2.h" +#include "fmdrv_common.h" +#include "fmdrv_rx.h" +#include "fmdrv_tx.h" + +static struct video_device *gradio_dev; +static u8 radio_disconnected; + +/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */ + +/* Read RX RDS data */ +static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf, + size_t count, loff_t *ppos) +{ + u8 rds_mode; + int ret; + struct fmdev *fmdev; + + fmdev = video_drvdata(file); + + if (!radio_disconnected) { + fmerr("FM device is already disconnected\n"); + return -EIO; + } + + /* Turn on RDS mode , if it is disabled */ + ret = fm_rx_get_rds_mode(fmdev, &rds_mode); + if (ret < 0) { + fmerr("Unable to read current rds mode\n"); + return ret; + } + + if (rds_mode == FM_RDS_DISABLE) { + ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE); + if (ret < 0) { + fmerr("Failed to enable rds mode\n"); + return ret; + } + } + + /* Copy RDS data from internal buffer to user buffer */ + return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count); +} + +/* Write TX RDS data */ +static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf, + size_t count, loff_t *ppos) +{ + struct tx_rds rds; + int ret; + struct fmdev *fmdev; + + ret = copy_from_user(&rds, buf, sizeof(rds)); + fmdbg("(%d)type: %d, text %s, af %d\n", + ret, rds.text_type, rds.text, rds.af_freq); + + fmdev = video_drvdata(file); + fm_tx_set_radio_text(fmdev, rds.text, rds.text_type); + fm_tx_set_af(fmdev, rds.af_freq); + + return 0; +} + +static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts) +{ + int ret; + struct fmdev *fmdev; + + fmdev = video_drvdata(file); + ret = fmc_is_rds_data_available(fmdev, file, pts); + if (ret < 0) + return POLLIN | POLLRDNORM; + + return 0; +} + +/* + * Handle open request for "/dev/radioX" device. + * Start with FM RX mode as default. + */ +static int fm_v4l2_fops_open(struct file *file) +{ + int ret; + struct fmdev *fmdev = NULL; + + /* Don't allow multiple open */ + if (radio_disconnected) { + fmerr("FM device is already opened\n"); + return -EBUSY; + } + + fmdev = video_drvdata(file); + + ret = fmc_prepare(fmdev); + if (ret < 0) { + fmerr("Unable to prepare FM CORE\n"); + return ret; + } + + fmdbg("Load FM RX firmware..\n"); + + ret = fmc_set_mode(fmdev, FM_MODE_RX); + if (ret < 0) { + fmerr("Unable to load FM RX firmware\n"); + return ret; + } + radio_disconnected = 1; + + return ret; +} + +static int fm_v4l2_fops_release(struct file *file) +{ + int ret; + struct fmdev *fmdev; + + fmdev = video_drvdata(file); + if (!radio_disconnected) { + fmdbg("FM device is already closed\n"); + return 0; + } + + ret = fmc_set_mode(fmdev, FM_MODE_OFF); + if (ret < 0) { + fmerr("Unable to turn off the chip\n"); + return ret; + } + + ret = fmc_release(fmdev); + if (ret < 0) { + fmerr("FM CORE release failed\n"); + return ret; + } + radio_disconnected = 0; + + return ret; +} + +/* V4L2 RADIO (/dev/radioX) device IOCTL interfaces */ +static int fm_v4l2_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver)); + strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME, + sizeof(capability->card)); + sprintf(capability->bus_info, "UART"); + capability->version = FM_DRV_RADIO_VERSION; + capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | + V4L2_CAP_RADIO | V4L2_CAP_MODULATOR | + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | + V4L2_CAP_RDS_CAPTURE; + + return 0; +} + +static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fmdev *fmdev = container_of(ctrl->handler, + struct fmdev, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + ctrl->cur.val = fm_tx_get_tune_cap_val(fmdev); + break; + default: + fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id); + break; + } + + return 0; +} + +static int fm_v4l2_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fmdev *fmdev = container_of(ctrl->handler, + struct fmdev, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: /* set volume */ + return fm_rx_set_volume(fmdev, (u16)ctrl->val); + + case V4L2_CID_AUDIO_MUTE: /* set mute */ + return fmc_set_mute_mode(fmdev, (u8)ctrl->val); + + case V4L2_CID_TUNE_POWER_LEVEL: + /* set TX power level - ext control */ + return fm_tx_set_pwr_lvl(fmdev, (u8)ctrl->val); + + case V4L2_CID_TUNE_PREEMPHASIS: + return fm_tx_set_preemph_filter(fmdev, (u8) ctrl->val); + + default: + return -EINVAL; + } +} + +static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + memset(audio, 0, sizeof(*audio)); + strcpy(audio->name, "Radio"); + audio->capability = V4L2_AUDCAP_STEREO; + + return 0; +} + +static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + if (audio->index != 0) + return -EINVAL; + + return 0; +} + +/* Get tuner attributes. If current mode is NOT RX, return error */ +static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct fmdev *fmdev = video_drvdata(file); + u32 bottom_freq; + u32 top_freq; + u16 stereo_mono_mode; + u16 rssilvl; + int ret; + + if (tuner->index != 0) + return -EINVAL; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + ret = fm_rx_get_band_freq_range(fmdev, &bottom_freq, &top_freq); + if (ret != 0) + return ret; + + ret = fm_rx_get_stereo_mono(fmdev, &stereo_mono_mode); + if (ret != 0) + return ret; + + ret = fm_rx_get_rssi_level(fmdev, &rssilvl); + if (ret != 0) + return ret; + + strcpy(tuner->name, "FM"); + tuner->type = V4L2_TUNER_RADIO; + /* Store rangelow and rangehigh freq in unit of 62.5 Hz */ + tuner->rangelow = bottom_freq * 16; + tuner->rangehigh = top_freq * 16; + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO | + ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0); + tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_LOW; + tuner->audmode = (stereo_mono_mode ? + V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO); + + /* + * Actual rssi value lies in between -128 to +127. + * Convert this range from 0 to 255 by adding +128 + */ + rssilvl += 128; + + /* + * Return signal strength value should be within 0 to 65535. + * Find out correct signal radio by multiplying (65535/255) = 257 + */ + tuner->signal = rssilvl * 257; + tuner->afc = 0; + + return ret; +} + +/* + * Set tuner attributes. If current mode is NOT RX, set to RX. + * Currently, we set only audio mode (mono/stereo) and RDS state (on/off). + * Should we set other tuner attributes, too? + */ +static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct fmdev *fmdev = video_drvdata(file); + u16 aud_mode; + u8 rds_mode; + int ret; + + if (tuner->index != 0) + return -EINVAL; + + aud_mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ? + FM_STEREO_MODE : FM_MONO_MODE; + rds_mode = (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ? + FM_RDS_ENABLE : FM_RDS_DISABLE; + + if (fmdev->curr_fmmode != FM_MODE_RX) { + ret = fmc_set_mode(fmdev, FM_MODE_RX); + if (ret < 0) { + fmerr("Failed to set RX mode\n"); + return ret; + } + } + + ret = fmc_set_stereo_mono(fmdev, aud_mode); + if (ret < 0) { + fmerr("Failed to set RX stereo/mono mode\n"); + return ret; + } + + ret = fmc_set_rds_mode(fmdev, rds_mode); + if (ret < 0) + fmerr("Failed to set RX RDS mode\n"); + + return ret; +} + +/* Get tuner or modulator radio frequency */ +static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct fmdev *fmdev = video_drvdata(file); + int ret; + + ret = fmc_get_freq(fmdev, &freq->frequency); + if (ret < 0) { + fmerr("Failed to get frequency\n"); + return ret; + } + + /* Frequency unit of 62.5 Hz*/ + freq->frequency = (u32) freq->frequency * 16; + + return 0; +} + +/* Set tuner or modulator radio frequency */ +static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct fmdev *fmdev = video_drvdata(file); + + /* + * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency + * in units of 62.5 Hz. + */ + freq->frequency = (u32)(freq->frequency / 16); + + return fmc_set_freq(fmdev, freq->frequency); +} + +/* Set hardware frequency seek. If current mode is NOT RX, set it RX. */ +static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv, + struct v4l2_hw_freq_seek *seek) +{ + struct fmdev *fmdev = video_drvdata(file); + int ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) { + ret = fmc_set_mode(fmdev, FM_MODE_RX); + if (ret != 0) { + fmerr("Failed to set RX mode\n"); + return ret; + } + } + + ret = fm_rx_seek(fmdev, seek->seek_upward, seek->wrap_around, + seek->spacing); + if (ret < 0) + fmerr("RX seek failed - %d\n", ret); + + return ret; +} +/* Get modulator attributes. If mode is not TX, return no attributes. */ +static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv, + struct v4l2_modulator *mod) +{ + struct fmdev *fmdev = video_drvdata(file);; + + if (mod->index != 0) + return -EINVAL; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + mod->txsubchans = ((fmdev->tx_data.aud_mode == FM_STEREO_MODE) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO) | + ((fmdev->tx_data.rds.flag == FM_RDS_ENABLE) ? + V4L2_TUNER_SUB_RDS : 0); + + mod->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_LOW; + + return 0; +} + +/* Set modulator attributes. If mode is not TX, set to TX. */ +static int fm_v4l2_vidioc_s_modulator(struct file *file, void *priv, + struct v4l2_modulator *mod) +{ + struct fmdev *fmdev = video_drvdata(file); + u8 rds_mode; + u16 aud_mode; + int ret; + + if (mod->index != 0) + return -EINVAL; + + if (fmdev->curr_fmmode != FM_MODE_TX) { + ret = fmc_set_mode(fmdev, FM_MODE_TX); + if (ret != 0) { + fmerr("Failed to set TX mode\n"); + return ret; + } + } + + aud_mode = (mod->txsubchans & V4L2_TUNER_SUB_STEREO) ? + FM_STEREO_MODE : FM_MONO_MODE; + rds_mode = (mod->txsubchans & V4L2_TUNER_SUB_RDS) ? + FM_RDS_ENABLE : FM_RDS_DISABLE; + ret = fm_tx_set_stereo_mono(fmdev, aud_mode); + if (ret < 0) { + fmerr("Failed to set mono/stereo mode for TX\n"); + return ret; + } + ret = fm_tx_set_rds_mode(fmdev, rds_mode); + if (ret < 0) + fmerr("Failed to set rds mode for TX\n"); + + return ret; +} + +static const struct v4l2_file_operations fm_drv_fops = { + .owner = THIS_MODULE, + .read = fm_v4l2_fops_read, + .write = fm_v4l2_fops_write, + .poll = fm_v4l2_fops_poll, + .unlocked_ioctl = video_ioctl2, + .open = fm_v4l2_fops_open, + .release = fm_v4l2_fops_release, +}; + +static const struct v4l2_ctrl_ops fm_ctrl_ops = { + .s_ctrl = fm_v4l2_s_ctrl, + .g_volatile_ctrl = fm_g_volatile_ctrl, +}; +static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = { + .vidioc_querycap = fm_v4l2_vidioc_querycap, + .vidioc_g_audio = fm_v4l2_vidioc_g_audio, + .vidioc_s_audio = fm_v4l2_vidioc_s_audio, + .vidioc_g_tuner = fm_v4l2_vidioc_g_tuner, + .vidioc_s_tuner = fm_v4l2_vidioc_s_tuner, + .vidioc_g_frequency = fm_v4l2_vidioc_g_freq, + .vidioc_s_frequency = fm_v4l2_vidioc_s_freq, + .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek, + .vidioc_g_modulator = fm_v4l2_vidioc_g_modulator, + .vidioc_s_modulator = fm_v4l2_vidioc_s_modulator +}; + +/* V4L2 RADIO device parent structure */ +static struct video_device fm_viddev_template = { + .fops = &fm_drv_fops, + .ioctl_ops = &fm_drv_ioctl_ops, + .name = FM_DRV_NAME, + .release = video_device_release, +}; + +int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) +{ + struct v4l2_ctrl *ctrl; + int ret; + + /* Init mutex for core locking */ + mutex_init(&fmdev->mutex); + + /* Allocate new video device */ + gradio_dev = video_device_alloc(); + if (NULL == gradio_dev) { + fmerr("Can't allocate video device\n"); + return -ENOMEM; + } + + /* Setup FM driver's V4L2 properties */ + memcpy(gradio_dev, &fm_viddev_template, sizeof(fm_viddev_template)); + + video_set_drvdata(gradio_dev, fmdev); + + gradio_dev->lock = &fmdev->mutex; + + /* Register with V4L2 subsystem as RADIO device */ + if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) { + video_device_release(gradio_dev); + fmerr("Could not register video device\n"); + return -ENOMEM; + } + + fmdev->radio_dev = gradio_dev; + + /* Register to v4l2 ctrl handler framework */ + fmdev->radio_dev->ctrl_handler = &fmdev->ctrl_handler; + + ret = v4l2_ctrl_handler_init(&fmdev->ctrl_handler, 5); + if (ret < 0) { + fmerr("(fmdev): Can't init ctrl handler\n"); + v4l2_ctrl_handler_free(&fmdev->ctrl_handler); + return -EBUSY; + } + + /* + * Following controls are handled by V4L2 control framework. + * Added in ascending ID order. + */ + v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, FM_RX_VOLUME_MIN, + FM_RX_VOLUME_MAX, 1, FM_RX_VOLUME_MAX); + + v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + + v4l2_ctrl_new_std_menu(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_TUNE_PREEMPHASIS, V4L2_PREEMPHASIS_75_uS, + 0, V4L2_PREEMPHASIS_75_uS); + + v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_TUNE_POWER_LEVEL, FM_PWR_LVL_LOW, + FM_PWR_LVL_HIGH, 1, FM_PWR_LVL_HIGH); + + ctrl = v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, + 255, 1, 255); + + if (ctrl) + ctrl->is_volatile = 1; + + return 0; +} + +void *fm_v4l2_deinit_video_device(void) +{ + struct fmdev *fmdev; + + + fmdev = video_get_drvdata(gradio_dev); + + /* Unregister to v4l2 ctrl handler framework*/ + v4l2_ctrl_handler_free(&fmdev->ctrl_handler); + + /* Unregister RADIO device from V4L2 subsystem */ + video_unregister_device(gradio_dev); + + return fmdev; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_v4l2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_v4l2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_v4l2.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/fmdrv_v4l2.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * + * FM V4L2 module header. + * + * Copyright (C) 2011 Texas Instruments + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + * + */ + +#ifndef _FMDRV_V4L2_H +#define _FMDRV_V4L2_H + +#include +#include +#include + +int fm_v4l2_init_video_device(struct fmdev *, int); +void *fm_v4l2_deinit_video_device(void); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,17 @@ +# +# TI's wl128x FM driver based on TI's ST driver. +# +menu "Texas Instruments WL128x FM driver (ST based)" +config RADIO_WL128X + tristate "Texas Instruments WL128x FM Radio" + depends on VIDEO_V4L2 && RFKILL + select TI_ST + help + Choose Y here if you have this FM radio chip. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + . + +endmenu diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/radio/wl128x/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,6 @@ +# +# Makefile for TI's shared transport driver based wl128x +# FM radio. +# +obj-$(CONFIG_RADIO_WL128X) += fm_drv.o +fm_drv-objs := fmdrv_common.o fmdrv_rx.o fmdrv_tx.o fmdrv_v4l2.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ene_ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ene_ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ene_ir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ene_ir.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1213 @@ +/* + * driver for ENE KB3926 B/C/D/E/F CIR (pnp id: ENE0XXX) + * + * Copyright (C) 2010 Maxim Levitsky + * + * 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, or (at your option) any later version. + * + * 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 + * + * Special thanks to: + * Sami R. for lot of help in debugging and therefore + * bringing to life support for transmission & learning mode. + * + * Charlie Andrews for lots of help in + * bringing up the support of new firmware buffer that is popular + * on latest notebooks + * + * ENE for partial device documentation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ene_ir.h" + +static int sample_period; +static bool learning_mode_force; +static int debug; +static bool txsim; + +static void ene_set_reg_addr(struct ene_device *dev, u16 reg) +{ + outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); + outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); +} + +/* read a hardware register */ +static u8 ene_read_reg(struct ene_device *dev, u16 reg) +{ + u8 retval; + ene_set_reg_addr(dev, reg); + retval = inb(dev->hw_io + ENE_IO); + dbg_regs("reg %04x == %02x", reg, retval); + return retval; +} + +/* write a hardware register */ +static void ene_write_reg(struct ene_device *dev, u16 reg, u8 value) +{ + dbg_regs("reg %04x <- %02x", reg, value); + ene_set_reg_addr(dev, reg); + outb(value, dev->hw_io + ENE_IO); +} + +/* Set bits in hardware register */ +static void ene_set_reg_mask(struct ene_device *dev, u16 reg, u8 mask) +{ + dbg_regs("reg %04x |= %02x", reg, mask); + ene_set_reg_addr(dev, reg); + outb(inb(dev->hw_io + ENE_IO) | mask, dev->hw_io + ENE_IO); +} + +/* Clear bits in hardware register */ +static void ene_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask) +{ + dbg_regs("reg %04x &= ~%02x ", reg, mask); + ene_set_reg_addr(dev, reg); + outb(inb(dev->hw_io + ENE_IO) & ~mask, dev->hw_io + ENE_IO); +} + +/* A helper to set/clear a bit in register according to boolean variable */ +static void ene_set_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask, + bool set) +{ + if (set) + ene_set_reg_mask(dev, reg, mask); + else + ene_clear_reg_mask(dev, reg, mask); +} + +/* detect hardware features */ +static int ene_hw_detect(struct ene_device *dev) +{ + u8 chip_major, chip_minor; + u8 hw_revision, old_ver; + u8 fw_reg2, fw_reg1; + + ene_clear_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD); + chip_major = ene_read_reg(dev, ENE_ECVER_MAJOR); + chip_minor = ene_read_reg(dev, ENE_ECVER_MINOR); + ene_set_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD); + + hw_revision = ene_read_reg(dev, ENE_ECHV); + old_ver = ene_read_reg(dev, ENE_HW_VER_OLD); + + dev->pll_freq = (ene_read_reg(dev, ENE_PLLFRH) << 4) + + (ene_read_reg(dev, ENE_PLLFRL) >> 4); + + if (sample_period != ENE_DEFAULT_SAMPLE_PERIOD) + dev->rx_period_adjust = + dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4; + + if (hw_revision == 0xFF) { + ene_warn("device seems to be disabled"); + ene_warn("send a mail to lirc-list@lists.sourceforge.net"); + ene_warn("please attach output of acpidump and dmidecode"); + return -ENODEV; + } + + ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x", + chip_major, chip_minor, old_ver, hw_revision); + + ene_notice("PLL freq = %d", dev->pll_freq); + + if (chip_major == 0x33) { + ene_warn("chips 0x33xx aren't supported"); + return -ENODEV; + } + + if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { + dev->hw_revision = ENE_HW_C; + ene_notice("KB3926C detected"); + } else if (old_ver == 0x24 && hw_revision == 0xC0) { + dev->hw_revision = ENE_HW_B; + ene_notice("KB3926B detected"); + } else { + dev->hw_revision = ENE_HW_D; + ene_notice("KB3926D or higher detected"); + } + + /* detect features hardware supports */ + if (dev->hw_revision < ENE_HW_C) + return 0; + + fw_reg1 = ene_read_reg(dev, ENE_FW1); + fw_reg2 = ene_read_reg(dev, ENE_FW2); + + ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2); + + dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A); + dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING); + dev->hw_extra_buffer = !!(fw_reg1 & ENE_FW1_HAS_EXTRA_BUF); + + if (dev->hw_learning_and_tx_capable) + dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT); + + ene_notice("Hardware features:"); + + if (dev->hw_learning_and_tx_capable) { + ene_notice("* Supports transmitting & learning mode"); + ene_notice(" This feature is rare and therefore,"); + ene_notice(" you are welcome to test it,"); + ene_notice(" and/or contact the author via:"); + ene_notice(" lirc-list@lists.sourceforge.net"); + ene_notice(" or maximlevitsky@gmail.com"); + + ene_notice("* Uses GPIO %s for IR raw input", + dev->hw_use_gpio_0a ? "40" : "0A"); + + if (dev->hw_fan_input) + ene_notice("* Uses unused fan feedback input as source" + " of demodulated IR data"); + } + + if (!dev->hw_fan_input) + ene_notice("* Uses GPIO %s for IR demodulated input", + dev->hw_use_gpio_0a ? "0A" : "40"); + + if (dev->hw_extra_buffer) + ene_notice("* Uses new style input buffer"); + return 0; +} + +/* Read properities of hw sample buffer */ +static void ene_rx_setup_hw_buffer(struct ene_device *dev) +{ + u16 tmp; + + ene_rx_read_hw_pointer(dev); + dev->r_pointer = dev->w_pointer; + + if (!dev->hw_extra_buffer) { + dev->buffer_len = ENE_FW_PACKET_SIZE * 2; + return; + } + + tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER); + tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER+1) << 8; + dev->extra_buf1_address = tmp; + + dev->extra_buf1_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 2); + + tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 3); + tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 4) << 8; + dev->extra_buf2_address = tmp; + + dev->extra_buf2_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 5); + + dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8; + + ene_notice("Hardware uses 2 extended buffers:"); + ene_notice(" 0x%04x - len : %d", dev->extra_buf1_address, + dev->extra_buf1_len); + ene_notice(" 0x%04x - len : %d", dev->extra_buf2_address, + dev->extra_buf2_len); + + ene_notice("Total buffer len = %d", dev->buffer_len); + + if (dev->buffer_len > 64 || dev->buffer_len < 16) + goto error; + + if (dev->extra_buf1_address > 0xFBFC || + dev->extra_buf1_address < 0xEC00) + goto error; + + if (dev->extra_buf2_address > 0xFBFC || + dev->extra_buf2_address < 0xEC00) + goto error; + + if (dev->r_pointer > dev->buffer_len) + goto error; + + ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); + return; +error: + ene_warn("Error validating extra buffers, device probably won't work"); + dev->hw_extra_buffer = false; + ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); +} + + +/* Restore the pointers to extra buffers - to make module reload work*/ +static void ene_rx_restore_hw_buffer(struct ene_device *dev) +{ + if (!dev->hw_extra_buffer) + return; + + ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 0, + dev->extra_buf1_address & 0xFF); + ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 1, + dev->extra_buf1_address >> 8); + ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 2, dev->extra_buf1_len); + + ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 3, + dev->extra_buf2_address & 0xFF); + ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 4, + dev->extra_buf2_address >> 8); + ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 5, + dev->extra_buf2_len); + ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); +} + +/* Read hardware write pointer */ +static void ene_rx_read_hw_pointer(struct ene_device *dev) +{ + if (dev->hw_extra_buffer) + dev->w_pointer = ene_read_reg(dev, ENE_FW_RX_POINTER); + else + dev->w_pointer = ene_read_reg(dev, ENE_FW2) + & ENE_FW2_BUF_WPTR ? 0 : ENE_FW_PACKET_SIZE; + + dbg_verbose("RB: HW write pointer: %02x, driver read pointer: %02x", + dev->w_pointer, dev->r_pointer); +} + +/* Gets address of next sample from HW ring buffer */ +static int ene_rx_get_sample_reg(struct ene_device *dev) +{ + int r_pointer; + + if (dev->r_pointer == dev->w_pointer) { + dbg_verbose("RB: hit end, try update w_pointer"); + ene_rx_read_hw_pointer(dev); + } + + if (dev->r_pointer == dev->w_pointer) { + dbg_verbose("RB: end of data at %d", dev->r_pointer); + return 0; + } + + dbg_verbose("RB: reading at offset %d", dev->r_pointer); + r_pointer = dev->r_pointer; + + dev->r_pointer++; + if (dev->r_pointer == dev->buffer_len) + dev->r_pointer = 0; + + dbg_verbose("RB: next read will be from offset %d", dev->r_pointer); + + if (r_pointer < 8) { + dbg_verbose("RB: read at main buffer at %d", r_pointer); + return ENE_FW_SAMPLE_BUFFER + r_pointer; + } + + r_pointer -= 8; + + if (r_pointer < dev->extra_buf1_len) { + dbg_verbose("RB: read at 1st extra buffer at %d", r_pointer); + return dev->extra_buf1_address + r_pointer; + } + + r_pointer -= dev->extra_buf1_len; + + if (r_pointer < dev->extra_buf2_len) { + dbg_verbose("RB: read at 2nd extra buffer at %d", r_pointer); + return dev->extra_buf2_address + r_pointer; + } + + dbg("attempt to read beyong ring bufer end"); + return 0; +} + +/* Sense current received carrier */ +void ene_rx_sense_carrier(struct ene_device *dev) +{ + DEFINE_IR_RAW_EVENT(ev); + + int carrier, duty_cycle; + int period = ene_read_reg(dev, ENE_CIRCAR_PRD); + int hperiod = ene_read_reg(dev, ENE_CIRCAR_HPRD); + + if (!(period & ENE_CIRCAR_PRD_VALID)) + return; + + period &= ~ENE_CIRCAR_PRD_VALID; + + if (!period) + return; + + dbg("RX: hardware carrier period = %02x", period); + dbg("RX: hardware carrier pulse period = %02x", hperiod); + + carrier = 2000000 / period; + duty_cycle = (hperiod * 100) / period; + dbg("RX: sensed carrier = %d Hz, duty cycle %d%%", + carrier, duty_cycle); + if (dev->carrier_detect_enabled) { + ev.carrier_report = true; + ev.carrier = carrier; + ev.duty_cycle = duty_cycle; + ir_raw_event_store(dev->rdev, &ev); + } +} + +/* this enables/disables the CIR RX engine */ +static void ene_rx_enable_cir_engine(struct ene_device *dev, bool enable) +{ + ene_set_clear_reg_mask(dev, ENE_CIRCFG, + ENE_CIRCFG_RX_EN | ENE_CIRCFG_RX_IRQ, enable); +} + +/* this selects input for CIR engine. Ether GPIO 0A or GPIO40*/ +static void ene_rx_select_input(struct ene_device *dev, bool gpio_0a) +{ + ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_GPIO0A, gpio_0a); +} + +/* + * this enables alternative input via fan tachometer sensor and bypasses + * the hw CIR engine + */ +static void ene_rx_enable_fan_input(struct ene_device *dev, bool enable) +{ + if (!dev->hw_fan_input) + return; + + if (!enable) + ene_write_reg(dev, ENE_FAN_AS_IN1, 0); + else { + ene_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); + ene_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); + } +} + +/* setup the receiver for RX*/ +static void ene_rx_setup(struct ene_device *dev) +{ + bool learning_mode = dev->learning_mode_enabled || + dev->carrier_detect_enabled; + int sample_period_adjust = 0; + + dbg("RX: setup receiver, learning mode = %d", learning_mode); + + + /* This selects RLC input and clears CFG2 settings */ + ene_write_reg(dev, ENE_CIRCFG2, 0x00); + + /* set sample period*/ + if (sample_period == ENE_DEFAULT_SAMPLE_PERIOD) + sample_period_adjust = + dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 1 : 2; + + ene_write_reg(dev, ENE_CIRRLC_CFG, + (sample_period + sample_period_adjust) | + ENE_CIRRLC_CFG_OVERFLOW); + /* revB doesn't support inputs */ + if (dev->hw_revision < ENE_HW_C) + goto select_timeout; + + if (learning_mode) { + + WARN_ON(!dev->hw_learning_and_tx_capable); + + /* Enable the opposite of the normal input + That means that if GPIO40 is normally used, use GPIO0A + and vice versa. + This input will carry non demodulated + signal, and we will tell the hw to demodulate it itself */ + ene_rx_select_input(dev, !dev->hw_use_gpio_0a); + dev->rx_fan_input_inuse = false; + + /* Enable carrier demodulation */ + ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD); + + /* Enable carrier detection */ + ene_write_reg(dev, ENE_CIRCAR_PULS, 0x63); + ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT, + dev->carrier_detect_enabled || debug); + } else { + if (dev->hw_fan_input) + dev->rx_fan_input_inuse = true; + else + ene_rx_select_input(dev, dev->hw_use_gpio_0a); + + /* Disable carrier detection & demodulation */ + ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD); + ene_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT); + } + +select_timeout: + if (dev->rx_fan_input_inuse) { + dev->rdev->rx_resolution = US_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN); + + /* Fan input doesn't support timeouts, it just ends the + input with a maximum sample */ + dev->rdev->min_timeout = dev->rdev->max_timeout = + US_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK * + ENE_FW_SAMPLE_PERIOD_FAN); + } else { + dev->rdev->rx_resolution = US_TO_NS(sample_period); + + /* Theoreticly timeout is unlimited, but we cap it + * because it was seen that on one device, it + * would stop sending spaces after around 250 msec. + * Besides, this is close to 2^32 anyway and timeout is u32. + */ + dev->rdev->min_timeout = US_TO_NS(127 * sample_period); + dev->rdev->max_timeout = US_TO_NS(200000); + } + + if (dev->hw_learning_and_tx_capable) + dev->rdev->tx_resolution = US_TO_NS(sample_period); + + if (dev->rdev->timeout > dev->rdev->max_timeout) + dev->rdev->timeout = dev->rdev->max_timeout; + if (dev->rdev->timeout < dev->rdev->min_timeout) + dev->rdev->timeout = dev->rdev->min_timeout; +} + +/* Enable the device for receive */ +static void ene_rx_enable(struct ene_device *dev) +{ + u8 reg_value; + + /* Enable system interrupt */ + if (dev->hw_revision < ENE_HW_C) { + ene_write_reg(dev, ENEB_IRQ, dev->irq << 1); + ene_write_reg(dev, ENEB_IRQ_UNK1, 0x01); + } else { + reg_value = ene_read_reg(dev, ENE_IRQ) & 0xF0; + reg_value |= ENE_IRQ_UNK_EN; + reg_value &= ~ENE_IRQ_STATUS; + reg_value |= (dev->irq & ENE_IRQ_MASK); + ene_write_reg(dev, ENE_IRQ, reg_value); + } + + /* Enable inputs */ + ene_rx_enable_fan_input(dev, dev->rx_fan_input_inuse); + ene_rx_enable_cir_engine(dev, !dev->rx_fan_input_inuse); + + /* ack any pending irqs - just in case */ + ene_irq_status(dev); + + /* enable firmware bits */ + ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ); + + /* enter idle mode */ + ir_raw_event_set_idle(dev->rdev, true); + dev->rx_enabled = true; +} + +/* Disable the device receiver */ +static void ene_rx_disable(struct ene_device *dev) +{ + /* disable inputs */ + ene_rx_enable_cir_engine(dev, false); + ene_rx_enable_fan_input(dev, false); + + /* disable hardware IRQ and firmware flag */ + ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ); + + ir_raw_event_set_idle(dev->rdev, true); + dev->rx_enabled = false; +} + +/* This resets the receiver. Useful to stop stream of spaces at end of + * transmission + */ +static void ene_rx_reset(struct ene_device *dev) +{ + ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN); + ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN); +} + +/* Set up the TX carrier frequency and duty cycle */ +static void ene_tx_set_carrier(struct ene_device *dev) +{ + u8 tx_puls_width; + unsigned long flags; + + spin_lock_irqsave(&dev->hw_lock, flags); + + ene_set_clear_reg_mask(dev, ENE_CIRCFG, + ENE_CIRCFG_TX_CARR, dev->tx_period > 0); + + if (!dev->tx_period) + goto unlock; + + BUG_ON(dev->tx_duty_cycle >= 100 || dev->tx_duty_cycle <= 0); + + tx_puls_width = dev->tx_period / (100 / dev->tx_duty_cycle); + + if (!tx_puls_width) + tx_puls_width = 1; + + dbg("TX: pulse distance = %d * 500 ns", dev->tx_period); + dbg("TX: pulse width = %d * 500 ns", tx_puls_width); + + ene_write_reg(dev, ENE_CIRMOD_PRD, dev->tx_period | ENE_CIRMOD_PRD_POL); + ene_write_reg(dev, ENE_CIRMOD_HPRD, tx_puls_width); +unlock: + spin_unlock_irqrestore(&dev->hw_lock, flags); +} + +/* Enable/disable transmitters */ +static void ene_tx_set_transmitters(struct ene_device *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->hw_lock, flags); + ene_set_clear_reg_mask(dev, ENE_GPIOFS8, ENE_GPIOFS8_GPIO41, + !!(dev->transmitter_mask & 0x01)); + ene_set_clear_reg_mask(dev, ENE_GPIOFS1, ENE_GPIOFS1_GPIO0D, + !!(dev->transmitter_mask & 0x02)); + spin_unlock_irqrestore(&dev->hw_lock, flags); +} + +/* prepare transmission */ +static void ene_tx_enable(struct ene_device *dev) +{ + u8 conf1 = ene_read_reg(dev, ENE_CIRCFG); + u8 fwreg2 = ene_read_reg(dev, ENE_FW2); + + dev->saved_conf1 = conf1; + + /* Show information about currently connected transmitter jacks */ + if (fwreg2 & ENE_FW2_EMMITER1_CONN) + dbg("TX: Transmitter #1 is connected"); + + if (fwreg2 & ENE_FW2_EMMITER2_CONN) + dbg("TX: Transmitter #2 is connected"); + + if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN))) + ene_warn("TX: transmitter cable isn't connected!"); + + /* disable receive on revc */ + if (dev->hw_revision == ENE_HW_C) + conf1 &= ~ENE_CIRCFG_RX_EN; + + /* Enable TX engine */ + conf1 |= ENE_CIRCFG_TX_EN | ENE_CIRCFG_TX_IRQ; + ene_write_reg(dev, ENE_CIRCFG, conf1); +} + +/* end transmission */ +static void ene_tx_disable(struct ene_device *dev) +{ + ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1); + dev->tx_buffer = NULL; +} + + +/* TX one sample - must be called with dev->hw_lock*/ +static void ene_tx_sample(struct ene_device *dev) +{ + u8 raw_tx; + u32 sample; + bool pulse = dev->tx_sample_pulse; + + if (!dev->tx_buffer) { + ene_warn("TX: BUG: attempt to transmit NULL buffer"); + return; + } + + /* Grab next TX sample */ + if (!dev->tx_sample) { + + if (dev->tx_pos == dev->tx_len) { + if (!dev->tx_done) { + dbg("TX: no more data to send"); + dev->tx_done = true; + goto exit; + } else { + dbg("TX: last sample sent by hardware"); + ene_tx_disable(dev); + complete(&dev->tx_complete); + return; + } + } + + sample = dev->tx_buffer[dev->tx_pos++]; + dev->tx_sample_pulse = !dev->tx_sample_pulse; + + dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period); + + if (!dev->tx_sample) + dev->tx_sample = 1; + } + + raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK); + dev->tx_sample -= raw_tx; + + dbg("TX: sample %8d (%s)", raw_tx * sample_period, + pulse ? "pulse" : "space"); + if (pulse) + raw_tx |= ENE_CIRRLC_OUT_PULSE; + + ene_write_reg(dev, + dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx); + + dev->tx_reg = !dev->tx_reg; +exit: + /* simulate TX done interrupt */ + if (txsim) + mod_timer(&dev->tx_sim_timer, jiffies + HZ / 500); +} + +/* timer to simulate tx done interrupt */ +static void ene_tx_irqsim(unsigned long data) +{ + struct ene_device *dev = (struct ene_device *)data; + unsigned long flags; + + spin_lock_irqsave(&dev->hw_lock, flags); + ene_tx_sample(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); +} + + +/* read irq status and ack it */ +static int ene_irq_status(struct ene_device *dev) +{ + u8 irq_status; + u8 fw_flags1, fw_flags2; + int retval = 0; + + fw_flags2 = ene_read_reg(dev, ENE_FW2); + + if (dev->hw_revision < ENE_HW_C) { + irq_status = ene_read_reg(dev, ENEB_IRQ_STATUS); + + if (!(irq_status & ENEB_IRQ_STATUS_IR)) + return 0; + + ene_clear_reg_mask(dev, ENEB_IRQ_STATUS, ENEB_IRQ_STATUS_IR); + return ENE_IRQ_RX; + } + + irq_status = ene_read_reg(dev, ENE_IRQ); + if (!(irq_status & ENE_IRQ_STATUS)) + return 0; + + /* original driver does that twice - a workaround ? */ + ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS); + ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS); + + /* check RX interrupt */ + if (fw_flags2 & ENE_FW2_RXIRQ) { + retval |= ENE_IRQ_RX; + ene_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_RXIRQ); + } + + /* check TX interrupt */ + fw_flags1 = ene_read_reg(dev, ENE_FW1); + if (fw_flags1 & ENE_FW1_TXIRQ) { + ene_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); + retval |= ENE_IRQ_TX; + } + + return retval; +} + +/* interrupt handler */ +static irqreturn_t ene_isr(int irq, void *data) +{ + u16 hw_value, reg; + int hw_sample, irq_status; + bool pulse; + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct ene_device *dev = (struct ene_device *)data; + DEFINE_IR_RAW_EVENT(ev); + + spin_lock_irqsave(&dev->hw_lock, flags); + + dbg_verbose("ISR called"); + ene_rx_read_hw_pointer(dev); + irq_status = ene_irq_status(dev); + + if (!irq_status) + goto unlock; + + retval = IRQ_HANDLED; + + if (irq_status & ENE_IRQ_TX) { + dbg_verbose("TX interrupt"); + if (!dev->hw_learning_and_tx_capable) { + dbg("TX interrupt on unsupported device!"); + goto unlock; + } + ene_tx_sample(dev); + } + + if (!(irq_status & ENE_IRQ_RX)) + goto unlock; + + dbg_verbose("RX interrupt"); + + if (dev->hw_learning_and_tx_capable) + ene_rx_sense_carrier(dev); + + /* On hardware that don't support extra buffer we need to trust + the interrupt and not track the read pointer */ + if (!dev->hw_extra_buffer) + dev->r_pointer = dev->w_pointer == 0 ? ENE_FW_PACKET_SIZE : 0; + + while (1) { + + reg = ene_rx_get_sample_reg(dev); + + dbg_verbose("next sample to read at: %04x", reg); + if (!reg) + break; + + hw_value = ene_read_reg(dev, reg); + + if (dev->rx_fan_input_inuse) { + + int offset = ENE_FW_SMPL_BUF_FAN - ENE_FW_SAMPLE_BUFFER; + + /* read high part of the sample */ + hw_value |= ene_read_reg(dev, reg + offset) << 8; + pulse = hw_value & ENE_FW_SMPL_BUF_FAN_PLS; + + /* clear space bit, and other unused bits */ + hw_value &= ENE_FW_SMPL_BUF_FAN_MSK; + hw_sample = hw_value * ENE_FW_SAMPLE_PERIOD_FAN; + + } else { + pulse = !(hw_value & ENE_FW_SAMPLE_SPACE); + hw_value &= ~ENE_FW_SAMPLE_SPACE; + hw_sample = hw_value * sample_period; + + if (dev->rx_period_adjust) { + hw_sample *= 100; + hw_sample /= (100 + dev->rx_period_adjust); + } + } + + if (!dev->hw_extra_buffer && !hw_sample) { + dev->r_pointer = dev->w_pointer; + continue; + } + + dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space"); + + ev.duration = US_TO_NS(hw_sample); + ev.pulse = pulse; + ir_raw_event_store_with_filter(dev->rdev, &ev); + } + + ir_raw_event_handle(dev->rdev); +unlock: + spin_unlock_irqrestore(&dev->hw_lock, flags); + return retval; +} + +/* Initialize default settings */ +static void ene_setup_default_settings(struct ene_device *dev) +{ + dev->tx_period = 32; + dev->tx_duty_cycle = 50; /*%*/ + dev->transmitter_mask = 0x03; + dev->learning_mode_enabled = learning_mode_force; + + /* Set reasonable default timeout */ + dev->rdev->timeout = US_TO_NS(150000); +} + +/* Upload all hardware settings at once. Used at load and resume time */ +static void ene_setup_hw_settings(struct ene_device *dev) +{ + if (dev->hw_learning_and_tx_capable) { + ene_tx_set_carrier(dev); + ene_tx_set_transmitters(dev); + } + + ene_rx_setup(dev); +} + +/* outside interface: called on first open*/ +static int ene_open(struct rc_dev *rdev) +{ + struct ene_device *dev = rdev->priv; + unsigned long flags; + + spin_lock_irqsave(&dev->hw_lock, flags); + ene_rx_enable(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); + return 0; +} + +/* outside interface: called on device close*/ +static void ene_close(struct rc_dev *rdev) +{ + struct ene_device *dev = rdev->priv; + unsigned long flags; + spin_lock_irqsave(&dev->hw_lock, flags); + + ene_rx_disable(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); +} + +/* outside interface: set transmitter mask */ +static int ene_set_tx_mask(struct rc_dev *rdev, u32 tx_mask) +{ + struct ene_device *dev = rdev->priv; + dbg("TX: attempt to set transmitter mask %02x", tx_mask); + + /* invalid txmask */ + if (!tx_mask || tx_mask & ~0x03) { + dbg("TX: invalid mask"); + /* return count of transmitters */ + return 2; + } + + dev->transmitter_mask = tx_mask; + ene_tx_set_transmitters(dev); + return 0; +} + +/* outside interface : set tx carrier */ +static int ene_set_tx_carrier(struct rc_dev *rdev, u32 carrier) +{ + struct ene_device *dev = rdev->priv; + u32 period = 2000000 / carrier; + + dbg("TX: attempt to set tx carrier to %d kHz", carrier); + + if (period && (period > ENE_CIRMOD_PRD_MAX || + period < ENE_CIRMOD_PRD_MIN)) { + + dbg("TX: out of range %d-%d kHz carrier", + 2000 / ENE_CIRMOD_PRD_MIN, 2000 / ENE_CIRMOD_PRD_MAX); + return -1; + } + + dev->tx_period = period; + ene_tx_set_carrier(dev); + return 0; +} + +/*outside interface : set tx duty cycle */ +static int ene_set_tx_duty_cycle(struct rc_dev *rdev, u32 duty_cycle) +{ + struct ene_device *dev = rdev->priv; + dbg("TX: setting duty cycle to %d%%", duty_cycle); + dev->tx_duty_cycle = duty_cycle; + ene_tx_set_carrier(dev); + return 0; +} + +/* outside interface: enable learning mode */ +static int ene_set_learning_mode(struct rc_dev *rdev, int enable) +{ + struct ene_device *dev = rdev->priv; + unsigned long flags; + if (enable == dev->learning_mode_enabled) + return 0; + + spin_lock_irqsave(&dev->hw_lock, flags); + dev->learning_mode_enabled = enable; + ene_rx_disable(dev); + ene_rx_setup(dev); + ene_rx_enable(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); + return 0; +} + +static int ene_set_carrier_report(struct rc_dev *rdev, int enable) +{ + struct ene_device *dev = rdev->priv; + unsigned long flags; + + if (enable == dev->carrier_detect_enabled) + return 0; + + spin_lock_irqsave(&dev->hw_lock, flags); + dev->carrier_detect_enabled = enable; + ene_rx_disable(dev); + ene_rx_setup(dev); + ene_rx_enable(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); + return 0; +} + +/* outside interface: enable or disable idle mode */ +static void ene_set_idle(struct rc_dev *rdev, bool idle) +{ + struct ene_device *dev = rdev->priv; + + if (idle) { + ene_rx_reset(dev); + dbg("RX: end of data"); + } +} + +/* outside interface: transmit */ +static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n) +{ + struct ene_device *dev = rdev->priv; + unsigned long flags; + + dev->tx_buffer = buf; + dev->tx_len = n; + dev->tx_pos = 0; + dev->tx_reg = 0; + dev->tx_done = 0; + dev->tx_sample = 0; + dev->tx_sample_pulse = 0; + + dbg("TX: %d samples", dev->tx_len); + + spin_lock_irqsave(&dev->hw_lock, flags); + + ene_tx_enable(dev); + + /* Transmit first two samples */ + ene_tx_sample(dev); + ene_tx_sample(dev); + + spin_unlock_irqrestore(&dev->hw_lock, flags); + + if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) { + dbg("TX: timeout"); + spin_lock_irqsave(&dev->hw_lock, flags); + ene_tx_disable(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); + } else + dbg("TX: done"); + return n; +} + +/* probe entry */ +static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) +{ + int error = -ENOMEM; + struct rc_dev *rdev; + struct ene_device *dev; + + /* allocate memory */ + dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); + rdev = rc_allocate_device(); + if (!dev || !rdev) + goto error1; + + /* validate resources */ + error = -ENODEV; + + /* init these to -1, as 0 is valid for both */ + dev->hw_io = -1; + dev->irq = -1; + + if (!pnp_port_valid(pnp_dev, 0) || + pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE) + goto error; + + if (!pnp_irq_valid(pnp_dev, 0)) + goto error; + + spin_lock_init(&dev->hw_lock); + + /* claim the resources */ + error = -EBUSY; + dev->hw_io = pnp_port_start(pnp_dev, 0); + if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) { + dev->hw_io = -1; + dev->irq = -1; + goto error; + } + + dev->irq = pnp_irq(pnp_dev, 0); + if (request_irq(dev->irq, ene_isr, + IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) { + dev->irq = -1; + goto error; + } + + pnp_set_drvdata(pnp_dev, dev); + dev->pnp_dev = pnp_dev; + + /* don't allow too short/long sample periods */ + if (sample_period < 5 || sample_period > 0x7F) + sample_period = ENE_DEFAULT_SAMPLE_PERIOD; + + /* detect hardware version and features */ + error = ene_hw_detect(dev); + if (error) + goto error; + + if (!dev->hw_learning_and_tx_capable && txsim) { + dev->hw_learning_and_tx_capable = true; + setup_timer(&dev->tx_sim_timer, ene_tx_irqsim, + (long unsigned int)dev); + ene_warn("Simulation of TX activated"); + } + + if (!dev->hw_learning_and_tx_capable) + learning_mode_force = false; + + rdev->driver_type = RC_DRIVER_IR_RAW; + rdev->allowed_protos = RC_TYPE_ALL; + rdev->priv = dev; + rdev->open = ene_open; + rdev->close = ene_close; + rdev->s_idle = ene_set_idle; + rdev->driver_name = ENE_DRIVER_NAME; + rdev->map_name = RC_MAP_RC6_MCE; + rdev->input_name = "ENE eHome Infrared Remote Receiver"; + + if (dev->hw_learning_and_tx_capable) { + rdev->s_learning_mode = ene_set_learning_mode; + init_completion(&dev->tx_complete); + rdev->tx_ir = ene_transmit; + rdev->s_tx_mask = ene_set_tx_mask; + rdev->s_tx_carrier = ene_set_tx_carrier; + rdev->s_tx_duty_cycle = ene_set_tx_duty_cycle; + rdev->s_carrier_report = ene_set_carrier_report; + rdev->input_name = "ENE eHome Infrared Remote Transceiver"; + } + + dev->rdev = rdev; + + ene_rx_setup_hw_buffer(dev); + ene_setup_default_settings(dev); + ene_setup_hw_settings(dev); + + device_set_wakeup_capable(&pnp_dev->dev, true); + device_set_wakeup_enable(&pnp_dev->dev, true); + + error = rc_register_device(rdev); + if (error < 0) + goto error; + + ene_notice("driver has been successfully loaded"); + return 0; +error: + if (dev && dev->irq >= 0) + free_irq(dev->irq, dev); + if (dev && dev->hw_io >= 0) + release_region(dev->hw_io, ENE_IO_SIZE); +error1: + rc_free_device(rdev); + kfree(dev); + return error; +} + +/* main unload function */ +static void ene_remove(struct pnp_dev *pnp_dev) +{ + struct ene_device *dev = pnp_get_drvdata(pnp_dev); + unsigned long flags; + + spin_lock_irqsave(&dev->hw_lock, flags); + ene_rx_disable(dev); + ene_rx_restore_hw_buffer(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); + + free_irq(dev->irq, dev); + release_region(dev->hw_io, ENE_IO_SIZE); + rc_unregister_device(dev->rdev); + kfree(dev); +} + +/* enable wake on IR (wakes on specific button on original remote) */ +static void ene_enable_wake(struct ene_device *dev, int enable) +{ + enable = enable && device_may_wakeup(&dev->pnp_dev->dev); + dbg("wake on IR %s", enable ? "enabled" : "disabled"); + ene_set_clear_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, enable); +} + +#ifdef CONFIG_PM +static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) +{ + struct ene_device *dev = pnp_get_drvdata(pnp_dev); + ene_enable_wake(dev, true); + + /* TODO: add support for wake pattern */ + return 0; +} + +static int ene_resume(struct pnp_dev *pnp_dev) +{ + struct ene_device *dev = pnp_get_drvdata(pnp_dev); + ene_setup_hw_settings(dev); + + if (dev->rx_enabled) + ene_rx_enable(dev); + + ene_enable_wake(dev, false); + return 0; +} +#endif + +static void ene_shutdown(struct pnp_dev *pnp_dev) +{ + struct ene_device *dev = pnp_get_drvdata(pnp_dev); + ene_enable_wake(dev, true); +} + +static const struct pnp_device_id ene_ids[] = { + {.id = "ENE0100",}, + {.id = "ENE0200",}, + {.id = "ENE0201",}, + {.id = "ENE0202",}, + {}, +}; + +static struct pnp_driver ene_driver = { + .name = ENE_DRIVER_NAME, + .id_table = ene_ids, + .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, + + .probe = ene_probe, + .remove = __devexit_p(ene_remove), +#ifdef CONFIG_PM + .suspend = ene_suspend, + .resume = ene_resume, +#endif + .shutdown = ene_shutdown, +}; + +static int __init ene_init(void) +{ + return pnp_register_driver(&ene_driver); +} + +static void ene_exit(void) +{ + pnp_unregister_driver(&ene_driver); +} + +module_param(sample_period, int, S_IRUGO); +MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)"); + +module_param(learning_mode_force, bool, S_IRUGO); +MODULE_PARM_DESC(learning_mode_force, "Enable learning mode by default"); + +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug level"); + +module_param(txsim, bool, S_IRUGO); +MODULE_PARM_DESC(txsim, + "Simulate TX features on unsupported hardware (dangerous)"); + +MODULE_DEVICE_TABLE(pnp, ene_ids); +MODULE_DESCRIPTION + ("Infrared input driver for KB3926B/C/D/E/F " + "(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port"); + +MODULE_AUTHOR("Maxim Levitsky"); +MODULE_LICENSE("GPL"); + +module_init(ene_init); +module_exit(ene_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ene_ir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ene_ir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ene_ir.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ene_ir.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,259 @@ +/* + * driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX) + * + * Copyright (C) 2010 Maxim Levitsky + * + * 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, or (at your option) any later version. + * + * 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 + + +/* hardware address */ +#define ENE_STATUS 0 /* hardware status - unused */ +#define ENE_ADDR_HI 1 /* hi byte of register address */ +#define ENE_ADDR_LO 2 /* low byte of register address */ +#define ENE_IO 3 /* read/write window */ +#define ENE_IO_SIZE 4 + +/* 8 bytes of samples, divided in 2 packets*/ +#define ENE_FW_SAMPLE_BUFFER 0xF8F0 /* sample buffer */ +#define ENE_FW_SAMPLE_SPACE 0x80 /* sample is space */ +#define ENE_FW_PACKET_SIZE 4 + +/* first firmware flag register */ +#define ENE_FW1 0xF8F8 /* flagr */ +#define ENE_FW1_ENABLE 0x01 /* enable fw processing */ +#define ENE_FW1_TXIRQ 0x02 /* TX interrupt pending */ +#define ENE_FW1_HAS_EXTRA_BUF 0x04 /* fw uses extra buffer*/ +#define ENE_FW1_EXTRA_BUF_HND 0x08 /* extra buffer handshake bit*/ +#define ENE_FW1_LED_ON 0x10 /* turn on a led */ + +#define ENE_FW1_WPATTERN 0x20 /* enable wake pattern */ +#define ENE_FW1_WAKE 0x40 /* enable wake from S3 */ +#define ENE_FW1_IRQ 0x80 /* enable interrupt */ + +/* second firmware flag register */ +#define ENE_FW2 0xF8F9 /* flagw */ +#define ENE_FW2_BUF_WPTR 0x01 /* which half of the buffer to read */ +#define ENE_FW2_RXIRQ 0x04 /* RX IRQ pending*/ +#define ENE_FW2_GP0A 0x08 /* Use GPIO0A for demodulated input */ +#define ENE_FW2_EMMITER1_CONN 0x10 /* TX emmiter 1 connected */ +#define ENE_FW2_EMMITER2_CONN 0x20 /* TX emmiter 2 connected */ + +#define ENE_FW2_FAN_INPUT 0x40 /* fan input used for demodulated data*/ +#define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */ + +/* firmware RX pointer for new style buffer */ +#define ENE_FW_RX_POINTER 0xF8FA + +/* high parts of samples for fan input (8 samples)*/ +#define ENE_FW_SMPL_BUF_FAN 0xF8FB +#define ENE_FW_SMPL_BUF_FAN_PLS 0x8000 /* combined sample is pulse */ +#define ENE_FW_SMPL_BUF_FAN_MSK 0x0FFF /* combined sample maximum value */ +#define ENE_FW_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */ + +/* transmitter ports */ +#define ENE_GPIOFS1 0xFC01 +#define ENE_GPIOFS1_GPIO0D 0x20 /* enable tx output on GPIO0D */ +#define ENE_GPIOFS8 0xFC08 +#define ENE_GPIOFS8_GPIO41 0x02 /* enable tx output on GPIO40 */ + +/* IRQ registers block (for revision B) */ +#define ENEB_IRQ 0xFD09 /* IRQ number */ +#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ +#define ENEB_IRQ_STATUS 0xFD80 /* irq status */ +#define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */ + +/* fan as input settings */ +#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ +#define ENE_FAN_AS_IN1_EN 0xCD +#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ +#define ENE_FAN_AS_IN2_EN 0x03 + +/* IRQ registers block (for revision C,D) */ +#define ENE_IRQ 0xFE9B /* new irq settings register */ +#define ENE_IRQ_MASK 0x0F /* irq number mask */ +#define ENE_IRQ_UNK_EN 0x10 /* always enabled */ +#define ENE_IRQ_STATUS 0x20 /* irq status and ACK */ + +/* CIR Config register #1 */ +#define ENE_CIRCFG 0xFEC0 +#define ENE_CIRCFG_RX_EN 0x01 /* RX enable */ +#define ENE_CIRCFG_RX_IRQ 0x02 /* Enable hardware interrupt */ +#define ENE_CIRCFG_REV_POL 0x04 /* Input polarity reversed */ +#define ENE_CIRCFG_CARR_DEMOD 0x08 /* Enable carrier demodulator */ + +#define ENE_CIRCFG_TX_EN 0x10 /* TX enable */ +#define ENE_CIRCFG_TX_IRQ 0x20 /* Send interrupt on TX done */ +#define ENE_CIRCFG_TX_POL_REV 0x40 /* TX polarity reversed */ +#define ENE_CIRCFG_TX_CARR 0x80 /* send TX carrier or not */ + +/* CIR config register #2 */ +#define ENE_CIRCFG2 0xFEC1 +#define ENE_CIRCFG2_RLC 0x00 +#define ENE_CIRCFG2_RC5 0x01 +#define ENE_CIRCFG2_RC6 0x02 +#define ENE_CIRCFG2_NEC 0x03 +#define ENE_CIRCFG2_CARR_DETECT 0x10 /* Enable carrier detection */ +#define ENE_CIRCFG2_GPIO0A 0x20 /* Use GPIO0A instead of GPIO40 for input */ +#define ENE_CIRCFG2_FAST_SAMPL1 0x40 /* Fast leading pulse detection for RC6 */ +#define ENE_CIRCFG2_FAST_SAMPL2 0x80 /* Fast data detection for RC6 */ + +/* Knobs for protocol decoding - will document when/if will use them */ +#define ENE_CIRPF 0xFEC2 +#define ENE_CIRHIGH 0xFEC3 +#define ENE_CIRBIT 0xFEC4 +#define ENE_CIRSTART 0xFEC5 +#define ENE_CIRSTART2 0xFEC6 + +/* Actual register which contains RLC RX data - read by firmware */ +#define ENE_CIRDAT_IN 0xFEC7 + + +/* RLC configuration - sample period (1us resulution) + idle mode */ +#define ENE_CIRRLC_CFG 0xFEC8 +#define ENE_CIRRLC_CFG_OVERFLOW 0x80 /* interrupt on overflows if set */ +#define ENE_DEFAULT_SAMPLE_PERIOD 50 + +/* Two byte RLC TX buffer */ +#define ENE_CIRRLC_OUT0 0xFEC9 +#define ENE_CIRRLC_OUT1 0xFECA +#define ENE_CIRRLC_OUT_PULSE 0x80 /* Transmitted sample is pulse */ +#define ENE_CIRRLC_OUT_MASK 0x7F + + +/* Carrier detect setting + * Low nibble - number of carrier pulses to average + * High nibble - number of initial carrier pulses to discard + */ +#define ENE_CIRCAR_PULS 0xFECB + +/* detected RX carrier period (resolution: 500 ns) */ +#define ENE_CIRCAR_PRD 0xFECC +#define ENE_CIRCAR_PRD_VALID 0x80 /* data valid content valid */ + +/* detected RX carrier pulse width (resolution: 500 ns) */ +#define ENE_CIRCAR_HPRD 0xFECD + +/* TX period (resolution: 500 ns, minimum 2)*/ +#define ENE_CIRMOD_PRD 0xFECE +#define ENE_CIRMOD_PRD_POL 0x80 /* TX carrier polarity*/ + +#define ENE_CIRMOD_PRD_MAX 0x7F /* 15.87 kHz */ +#define ENE_CIRMOD_PRD_MIN 0x02 /* 1 Mhz */ + +/* TX pulse width (resolution: 500 ns)*/ +#define ENE_CIRMOD_HPRD 0xFECF + +/* Hardware versions */ +#define ENE_ECHV 0xFF00 /* hardware revision */ +#define ENE_PLLFRH 0xFF16 +#define ENE_PLLFRL 0xFF17 +#define ENE_DEFAULT_PLL_FREQ 1000 + +#define ENE_ECSTS 0xFF1D +#define ENE_ECSTS_RSRVD 0x04 + +#define ENE_ECVER_MAJOR 0xFF1E /* chip version */ +#define ENE_ECVER_MINOR 0xFF1F +#define ENE_HW_VER_OLD 0xFD00 + +/******************************************************************************/ + +#define ENE_DRIVER_NAME "ene_ir" + +#define ENE_IRQ_RX 1 +#define ENE_IRQ_TX 2 + +#define ENE_HW_B 1 /* 3926B */ +#define ENE_HW_C 2 /* 3926C */ +#define ENE_HW_D 3 /* 3926D or later */ + +#define ene_printk(level, text, ...) \ + printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__) + +#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__) +#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__) + + +#define __dbg(level, format, ...) \ + do { \ + if (debug >= level) \ + printk(KERN_DEBUG ENE_DRIVER_NAME \ + ": " format "\n", ## __VA_ARGS__); \ + } while (0) + + +#define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__) +#define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__) +#define dbg_regs(format, ...) __dbg(3, format, ## __VA_ARGS__) + +struct ene_device { + struct pnp_dev *pnp_dev; + struct rc_dev *rdev; + + /* hw IO settings */ + long hw_io; + int irq; + spinlock_t hw_lock; + + /* HW features */ + int hw_revision; /* hardware revision */ + bool hw_use_gpio_0a; /* gpio0a is demodulated input*/ + bool hw_extra_buffer; /* hardware has 'extra buffer' */ + bool hw_fan_input; /* fan input is IR data source */ + bool hw_learning_and_tx_capable; /* learning & tx capable */ + int pll_freq; + int buffer_len; + + /* Extra RX buffer location */ + int extra_buf1_address; + int extra_buf1_len; + int extra_buf2_address; + int extra_buf2_len; + + /* HW state*/ + int r_pointer; /* pointer to next sample to read */ + int w_pointer; /* pointer to next sample hw will write */ + bool rx_fan_input_inuse; /* is fan input in use for rx*/ + int tx_reg; /* current reg used for TX */ + u8 saved_conf1; /* saved FEC0 reg */ + unsigned int tx_sample; /* current sample for TX */ + bool tx_sample_pulse; /* current sample is pulse */ + + /* TX buffer */ + unsigned *tx_buffer; /* input samples buffer*/ + int tx_pos; /* position in that bufer */ + int tx_len; /* current len of tx buffer */ + int tx_done; /* done transmitting */ + /* one more sample pending*/ + struct completion tx_complete; /* TX completion */ + struct timer_list tx_sim_timer; + + /* TX settings */ + int tx_period; + int tx_duty_cycle; + int transmitter_mask; + + /* RX settings */ + bool learning_mode_enabled; /* learning input enabled */ + bool carrier_detect_enabled; /* carrier detect enabled */ + int rx_period_adjust; + bool rx_enabled; +}; + +static int ene_irq_status(struct ene_device *dev); +static void ene_rx_read_hw_pointer(struct ene_device *dev); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/fintek-cir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/fintek-cir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/fintek-cir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/fintek-cir.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,684 @@ +/* + * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR + * + * Copyright (C) 2011 Jarod Wilson + * + * Special thanks to Fintek for providing hardware and spec sheets. + * This driver is based upon the nuvoton, ite and ene drivers for + * similar hardware. + * + * 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, or (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fintek-cir.h" + +/* write val to config reg */ +static inline void fintek_cr_write(struct fintek_dev *fintek, u8 val, u8 reg) +{ + fit_dbg("%s: reg 0x%02x, val 0x%02x (ip/dp: %02x/%02x)", + __func__, reg, val, fintek->cr_ip, fintek->cr_dp); + outb(reg, fintek->cr_ip); + outb(val, fintek->cr_dp); +} + +/* read val from config reg */ +static inline u8 fintek_cr_read(struct fintek_dev *fintek, u8 reg) +{ + u8 val; + + outb(reg, fintek->cr_ip); + val = inb(fintek->cr_dp); + + fit_dbg("%s: reg 0x%02x, val 0x%02x (ip/dp: %02x/%02x)", + __func__, reg, val, fintek->cr_ip, fintek->cr_dp); + return val; +} + +/* update config register bit without changing other bits */ +static inline void fintek_set_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg) +{ + u8 tmp = fintek_cr_read(fintek, reg) | val; + fintek_cr_write(fintek, tmp, reg); +} + +/* clear config register bit without changing other bits */ +static inline void fintek_clear_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg) +{ + u8 tmp = fintek_cr_read(fintek, reg) & ~val; + fintek_cr_write(fintek, tmp, reg); +} + +/* enter config mode */ +static inline void fintek_config_mode_enable(struct fintek_dev *fintek) +{ + /* Enabling Config Mode explicitly requires writing 2x */ + outb(CONFIG_REG_ENABLE, fintek->cr_ip); + outb(CONFIG_REG_ENABLE, fintek->cr_ip); +} + +/* exit config mode */ +static inline void fintek_config_mode_disable(struct fintek_dev *fintek) +{ + outb(CONFIG_REG_DISABLE, fintek->cr_ip); +} + +/* + * When you want to address a specific logical device, write its logical + * device number to GCR_LOGICAL_DEV_NO + */ +static inline void fintek_select_logical_dev(struct fintek_dev *fintek, u8 ldev) +{ + fintek_cr_write(fintek, ldev, GCR_LOGICAL_DEV_NO); +} + +/* write val to cir config register */ +static inline void fintek_cir_reg_write(struct fintek_dev *fintek, u8 val, u8 offset) +{ + outb(val, fintek->cir_addr + offset); +} + +/* read val from cir config register */ +static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset) +{ + u8 val; + + val = inb(fintek->cir_addr + offset); + + return val; +} + +#define pr_reg(text, ...) \ + printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__) + +/* dump current cir register contents */ +static void cir_dump_regs(struct fintek_dev *fintek) +{ + fintek_config_mode_enable(fintek); + fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); + + pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME); + pr_reg(" * CR CIR BASE ADDR: 0x%x\n", + (fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) | + fintek_cr_read(fintek, CIR_CR_BASE_ADDR_LO)); + pr_reg(" * CR CIR IRQ NUM: 0x%x\n", + fintek_cr_read(fintek, CIR_CR_IRQ_SEL)); + + fintek_config_mode_disable(fintek); + + pr_reg("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME); + pr_reg(" * STATUS: 0x%x\n", fintek_cir_reg_read(fintek, CIR_STATUS)); + pr_reg(" * CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_CONTROL)); + pr_reg(" * RX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_RX_DATA)); + pr_reg(" * TX_CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_CONTROL)); + pr_reg(" * TX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_DATA)); +} + +/* detect hardware features */ +static int fintek_hw_detect(struct fintek_dev *fintek) +{ + unsigned long flags; + u8 chip_major, chip_minor; + u8 vendor_major, vendor_minor; + u8 portsel, ir_class; + u16 vendor; + int ret = 0; + + fintek_config_mode_enable(fintek); + + /* Check if we're using config port 0x4e or 0x2e */ + portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL); + if (portsel == 0xff) { + fit_pr(KERN_INFO, "first portsel read was bunk, trying alt"); + fintek_config_mode_disable(fintek); + fintek->cr_ip = CR_INDEX_PORT2; + fintek->cr_dp = CR_DATA_PORT2; + fintek_config_mode_enable(fintek); + portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL); + } + fit_dbg("portsel reg: 0x%02x", portsel); + + ir_class = fintek_cir_reg_read(fintek, CIR_CR_CLASS); + fit_dbg("ir_class reg: 0x%02x", ir_class); + + switch (ir_class) { + case CLASS_RX_2TX: + case CLASS_RX_1TX: + fintek->hw_tx_capable = true; + break; + case CLASS_RX_ONLY: + default: + fintek->hw_tx_capable = false; + break; + } + + chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI); + chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO); + + vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI); + vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO); + vendor = vendor_major << 8 | vendor_minor; + + if (vendor != VENDOR_ID_FINTEK) + fit_pr(KERN_WARNING, "Unknown vendor ID: 0x%04x", vendor); + else + fit_dbg("Read Fintek vendor ID from chip"); + + fintek_config_mode_disable(fintek); + + spin_lock_irqsave(&fintek->fintek_lock, flags); + fintek->chip_major = chip_major; + fintek->chip_minor = chip_minor; + fintek->chip_vendor = vendor; + spin_unlock_irqrestore(&fintek->fintek_lock, flags); + + return ret; +} + +static void fintek_cir_ldev_init(struct fintek_dev *fintek) +{ + /* Select CIR logical device and enable */ + fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); + fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); + + /* Write allocated CIR address and IRQ information to hardware */ + fintek_cr_write(fintek, fintek->cir_addr >> 8, CIR_CR_BASE_ADDR_HI); + fintek_cr_write(fintek, fintek->cir_addr & 0xff, CIR_CR_BASE_ADDR_LO); + + fintek_cr_write(fintek, fintek->cir_irq, CIR_CR_IRQ_SEL); + + fit_dbg("CIR initialized, base io address: 0x%lx, irq: %d (len: %d)", + fintek->cir_addr, fintek->cir_irq, fintek->cir_port_len); +} + +/* enable CIR interrupts */ +static void fintek_enable_cir_irq(struct fintek_dev *fintek) +{ + fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS); +} + +static void fintek_cir_regs_init(struct fintek_dev *fintek) +{ + /* clear any and all stray interrupts */ + fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); + + /* and finally, enable interrupts */ + fintek_enable_cir_irq(fintek); +} + +static void fintek_enable_wake(struct fintek_dev *fintek) +{ + fintek_config_mode_enable(fintek); + fintek_select_logical_dev(fintek, LOGICAL_DEV_ACPI); + + /* Allow CIR PME's to wake system */ + fintek_set_reg_bit(fintek, ACPI_WAKE_EN_CIR_BIT, LDEV_ACPI_WAKE_EN_REG); + /* Enable CIR PME's */ + fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_EN_REG); + /* Clear CIR PME status register */ + fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_CLR_REG); + /* Save state */ + fintek_set_reg_bit(fintek, ACPI_STATE_CIR_BIT, LDEV_ACPI_STATE_REG); + + fintek_config_mode_disable(fintek); +} + +static int fintek_cmdsize(u8 cmd, u8 subcmd) +{ + int datasize = 0; + + switch (cmd) { + case BUF_COMMAND_NULL: + if (subcmd == BUF_HW_CMD_HEADER) + datasize = 1; + break; + case BUF_HW_CMD_HEADER: + if (subcmd == BUF_CMD_G_REVISION) + datasize = 2; + break; + case BUF_COMMAND_HEADER: + switch (subcmd) { + case BUF_CMD_S_CARRIER: + case BUF_CMD_S_TIMEOUT: + case BUF_RSP_PULSE_COUNT: + datasize = 2; + break; + case BUF_CMD_SIG_END: + case BUF_CMD_S_TXMASK: + case BUF_CMD_S_RXSENSOR: + datasize = 1; + break; + } + } + + return datasize; +} + +/* process ir data stored in driver buffer */ +static void fintek_process_rx_ir_data(struct fintek_dev *fintek) +{ + DEFINE_IR_RAW_EVENT(rawir); + u8 sample; + int i; + + for (i = 0; i < fintek->pkts; i++) { + sample = fintek->buf[i]; + switch (fintek->parser_state) { + case CMD_HEADER: + fintek->cmd = sample; + if ((fintek->cmd == BUF_COMMAND_HEADER) || + ((fintek->cmd & BUF_COMMAND_MASK) != + BUF_PULSE_BIT)) { + fintek->parser_state = SUBCMD; + continue; + } + fintek->rem = (fintek->cmd & BUF_LEN_MASK); + fit_dbg("%s: rem: 0x%02x", __func__, fintek->rem); + if (fintek->rem) + fintek->parser_state = PARSE_IRDATA; + else + ir_raw_event_reset(fintek->rdev); + break; + case SUBCMD: + fintek->rem = fintek_cmdsize(fintek->cmd, sample); + fintek->parser_state = CMD_DATA; + break; + case CMD_DATA: + fintek->rem--; + break; + case PARSE_IRDATA: + fintek->rem--; + init_ir_raw_event(&rawir); + rawir.pulse = ((sample & BUF_PULSE_BIT) != 0); + rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK) + * CIR_SAMPLE_PERIOD); + + fit_dbg("Storing %s with duration %d", + rawir.pulse ? "pulse" : "space", + rawir.duration); + ir_raw_event_store_with_filter(fintek->rdev, &rawir); + break; + } + + if ((fintek->parser_state != CMD_HEADER) && !fintek->rem) + fintek->parser_state = CMD_HEADER; + } + + fintek->pkts = 0; + + fit_dbg("Calling ir_raw_event_handle"); + ir_raw_event_handle(fintek->rdev); +} + +/* copy data from hardware rx register into driver buffer */ +static void fintek_get_rx_ir_data(struct fintek_dev *fintek, u8 rx_irqs) +{ + unsigned long flags; + u8 sample, status; + + spin_lock_irqsave(&fintek->fintek_lock, flags); + + /* + * We must read data from CIR_RX_DATA until the hardware IR buffer + * is empty and clears the RX_TIMEOUT and/or RX_RECEIVE flags in + * the CIR_STATUS register + */ + do { + sample = fintek_cir_reg_read(fintek, CIR_RX_DATA); + fit_dbg("%s: sample: 0x%02x", __func__, sample); + + fintek->buf[fintek->pkts] = sample; + fintek->pkts++; + + status = fintek_cir_reg_read(fintek, CIR_STATUS); + if (!(status & CIR_STATUS_IRQ_EN)) + break; + } while (status & rx_irqs); + + fintek_process_rx_ir_data(fintek); + + spin_unlock_irqrestore(&fintek->fintek_lock, flags); +} + +static void fintek_cir_log_irqs(u8 status) +{ + fit_pr(KERN_INFO, "IRQ 0x%02x:%s%s%s%s%s", status, + status & CIR_STATUS_IRQ_EN ? " IRQEN" : "", + status & CIR_STATUS_TX_FINISH ? " TXF" : "", + status & CIR_STATUS_TX_UNDERRUN ? " TXU" : "", + status & CIR_STATUS_RX_TIMEOUT ? " RXTO" : "", + status & CIR_STATUS_RX_RECEIVE ? " RXOK" : ""); +} + +/* interrupt service routine for incoming and outgoing CIR data */ +static irqreturn_t fintek_cir_isr(int irq, void *data) +{ + struct fintek_dev *fintek = data; + u8 status, rx_irqs; + + fit_dbg_verbose("%s firing", __func__); + + fintek_config_mode_enable(fintek); + fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); + fintek_config_mode_disable(fintek); + + /* + * Get IR Status register contents. Write 1 to ack/clear + * + * bit: reg name - description + * 3: TX_FINISH - TX is finished + * 2: TX_UNDERRUN - TX underrun + * 1: RX_TIMEOUT - RX data timeout + * 0: RX_RECEIVE - RX data received + */ + status = fintek_cir_reg_read(fintek, CIR_STATUS); + if (!(status & CIR_STATUS_IRQ_MASK) || status == 0xff) { + fit_dbg_verbose("%s exiting, IRSTS 0x%02x", __func__, status); + fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); + return IRQ_RETVAL(IRQ_NONE); + } + + if (debug) + fintek_cir_log_irqs(status); + + rx_irqs = status & (CIR_STATUS_RX_RECEIVE | CIR_STATUS_RX_TIMEOUT); + if (rx_irqs) + fintek_get_rx_ir_data(fintek, rx_irqs); + + /* ack/clear all irq flags we've got */ + fintek_cir_reg_write(fintek, status, CIR_STATUS); + + fit_dbg_verbose("%s done", __func__); + return IRQ_RETVAL(IRQ_HANDLED); +} + +static void fintek_enable_cir(struct fintek_dev *fintek) +{ + /* set IRQ enabled */ + fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS); + + fintek_config_mode_enable(fintek); + + /* enable the CIR logical device */ + fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); + fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); + + fintek_config_mode_disable(fintek); + + /* clear all pending interrupts */ + fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); + + /* enable interrupts */ + fintek_enable_cir_irq(fintek); +} + +static void fintek_disable_cir(struct fintek_dev *fintek) +{ + fintek_config_mode_enable(fintek); + + /* disable the CIR logical device */ + fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); + fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); + + fintek_config_mode_disable(fintek); +} + +static int fintek_open(struct rc_dev *dev) +{ + struct fintek_dev *fintek = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&fintek->fintek_lock, flags); + fintek_enable_cir(fintek); + spin_unlock_irqrestore(&fintek->fintek_lock, flags); + + return 0; +} + +static void fintek_close(struct rc_dev *dev) +{ + struct fintek_dev *fintek = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&fintek->fintek_lock, flags); + fintek_disable_cir(fintek); + spin_unlock_irqrestore(&fintek->fintek_lock, flags); +} + +/* Allocate memory, probe hardware, and initialize everything */ +static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) +{ + struct fintek_dev *fintek; + struct rc_dev *rdev; + int ret = -ENOMEM; + + fintek = kzalloc(sizeof(struct fintek_dev), GFP_KERNEL); + if (!fintek) + return ret; + + /* input device for IR remote (and tx) */ + rdev = rc_allocate_device(); + if (!rdev) + goto failure; + + ret = -ENODEV; + /* validate pnp resources */ + if (!pnp_port_valid(pdev, 0)) { + dev_err(&pdev->dev, "IR PNP Port not valid!\n"); + goto failure; + } + + if (!pnp_irq_valid(pdev, 0)) { + dev_err(&pdev->dev, "IR PNP IRQ not valid!\n"); + goto failure; + } + + fintek->cir_addr = pnp_port_start(pdev, 0); + fintek->cir_irq = pnp_irq(pdev, 0); + fintek->cir_port_len = pnp_port_len(pdev, 0); + + fintek->cr_ip = CR_INDEX_PORT; + fintek->cr_dp = CR_DATA_PORT; + + spin_lock_init(&fintek->fintek_lock); + + ret = -EBUSY; + /* now claim resources */ + if (!request_region(fintek->cir_addr, + fintek->cir_port_len, FINTEK_DRIVER_NAME)) + goto failure; + + if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED, + FINTEK_DRIVER_NAME, (void *)fintek)) + goto failure; + + pnp_set_drvdata(pdev, fintek); + fintek->pdev = pdev; + + ret = fintek_hw_detect(fintek); + if (ret) + goto failure; + + /* Initialize CIR & CIR Wake Logical Devices */ + fintek_config_mode_enable(fintek); + fintek_cir_ldev_init(fintek); + fintek_config_mode_disable(fintek); + + /* Initialize CIR & CIR Wake Config Registers */ + fintek_cir_regs_init(fintek); + + /* Set up the rc device */ + rdev->priv = fintek; + rdev->driver_type = RC_DRIVER_IR_RAW; + rdev->allowed_protos = RC_TYPE_ALL; + rdev->open = fintek_open; + rdev->close = fintek_close; + rdev->input_name = FINTEK_DESCRIPTION; + rdev->input_phys = "fintek/cir0"; + rdev->input_id.bustype = BUS_HOST; + rdev->input_id.vendor = VENDOR_ID_FINTEK; + rdev->input_id.product = fintek->chip_major; + rdev->input_id.version = fintek->chip_minor; + rdev->dev.parent = &pdev->dev; + rdev->driver_name = FINTEK_DRIVER_NAME; + rdev->map_name = RC_MAP_RC6_MCE; + rdev->timeout = US_TO_NS(1000); + /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */ + rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD); + + ret = rc_register_device(rdev); + if (ret) + goto failure; + + device_init_wakeup(&pdev->dev, true); + fintek->rdev = rdev; + fit_pr(KERN_NOTICE, "driver has been successfully loaded\n"); + if (debug) + cir_dump_regs(fintek); + + return 0; + +failure: + if (fintek->cir_irq) + free_irq(fintek->cir_irq, fintek); + if (fintek->cir_addr) + release_region(fintek->cir_addr, fintek->cir_port_len); + + rc_free_device(rdev); + kfree(fintek); + + return ret; +} + +static void __devexit fintek_remove(struct pnp_dev *pdev) +{ + struct fintek_dev *fintek = pnp_get_drvdata(pdev); + unsigned long flags; + + spin_lock_irqsave(&fintek->fintek_lock, flags); + /* disable CIR */ + fintek_disable_cir(fintek); + fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); + /* enable CIR Wake (for IR power-on) */ + fintek_enable_wake(fintek); + spin_unlock_irqrestore(&fintek->fintek_lock, flags); + + /* free resources */ + free_irq(fintek->cir_irq, fintek); + release_region(fintek->cir_addr, fintek->cir_port_len); + + rc_unregister_device(fintek->rdev); + + kfree(fintek); +} + +static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state) +{ + struct fintek_dev *fintek = pnp_get_drvdata(pdev); + + fit_dbg("%s called", __func__); + + /* disable all CIR interrupts */ + fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); + + fintek_config_mode_enable(fintek); + + /* disable cir logical dev */ + fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); + fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); + + fintek_config_mode_disable(fintek); + + /* make sure wake is enabled */ + fintek_enable_wake(fintek); + + return 0; +} + +static int fintek_resume(struct pnp_dev *pdev) +{ + int ret = 0; + struct fintek_dev *fintek = pnp_get_drvdata(pdev); + + fit_dbg("%s called", __func__); + + /* open interrupt */ + fintek_enable_cir_irq(fintek); + + /* Enable CIR logical device */ + fintek_config_mode_enable(fintek); + fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); + fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); + + fintek_config_mode_disable(fintek); + + fintek_cir_regs_init(fintek); + + return ret; +} + +static void fintek_shutdown(struct pnp_dev *pdev) +{ + struct fintek_dev *fintek = pnp_get_drvdata(pdev); + fintek_enable_wake(fintek); +} + +static const struct pnp_device_id fintek_ids[] = { + { "FIT0002", 0 }, /* CIR */ + { "", 0 }, +}; + +static struct pnp_driver fintek_driver = { + .name = FINTEK_DRIVER_NAME, + .id_table = fintek_ids, + .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, + .probe = fintek_probe, + .remove = __devexit_p(fintek_remove), + .suspend = fintek_suspend, + .resume = fintek_resume, + .shutdown = fintek_shutdown, +}; + +int fintek_init(void) +{ + return pnp_register_driver(&fintek_driver); +} + +void fintek_exit(void) +{ + pnp_unregister_driver(&fintek_driver); +} + +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging output"); + +MODULE_DEVICE_TABLE(pnp, fintek_ids); +MODULE_DESCRIPTION(FINTEK_DESCRIPTION " driver"); + +MODULE_AUTHOR("Jarod Wilson "); +MODULE_LICENSE("GPL"); + +module_init(fintek_init); +module_exit(fintek_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/fintek-cir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/fintek-cir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/fintek-cir.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/fintek-cir.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,243 @@ +/* + * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR + * + * Copyright (C) 2011 Jarod Wilson + * + * Special thanks to Fintek for providing hardware and spec sheets. + * This driver is based upon the nuvoton, ite and ene drivers for + * similar hardware. + * + * 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, or (at your option) any later version. + * + * 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 +#include + +/* platform driver name to register */ +#define FINTEK_DRIVER_NAME "fintek-cir" +#define FINTEK_DESCRIPTION "Fintek LPC SuperIO Consumer IR Transceiver" +#define VENDOR_ID_FINTEK 0x1934 + + +/* debugging module parameter */ +static int debug; + +#define fit_pr(level, text, ...) \ + printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) + +#define fit_dbg(text, ...) \ + if (debug) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) + +#define fit_dbg_verbose(text, ...) \ + if (debug > 1) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) + +#define fit_dbg_wake(text, ...) \ + if (debug > 2) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) + + +#define TX_BUF_LEN 256 +#define RX_BUF_LEN 32 + +struct fintek_dev { + struct pnp_dev *pdev; + struct rc_dev *rdev; + + spinlock_t fintek_lock; + + /* for rx */ + u8 buf[RX_BUF_LEN]; + unsigned int pkts; + + struct { + spinlock_t lock; + u8 buf[TX_BUF_LEN]; + unsigned int buf_count; + unsigned int cur_buf_num; + wait_queue_head_t queue; + } tx; + + /* Config register index/data port pair */ + u8 cr_ip; + u8 cr_dp; + + /* hardware I/O settings */ + unsigned long cir_addr; + int cir_irq; + int cir_port_len; + + /* hardware id */ + u8 chip_major; + u8 chip_minor; + u16 chip_vendor; + + /* hardware features */ + bool hw_learning_capable; + bool hw_tx_capable; + + /* rx settings */ + bool learning_enabled; + bool carrier_detect_enabled; + + enum { + CMD_HEADER = 0, + SUBCMD, + CMD_DATA, + PARSE_IRDATA, + } parser_state; + + u8 cmd, rem; + + /* carrier period = 1 / frequency */ + u32 carrier; +}; + +/* buffer packet constants, largely identical to mceusb.c */ +#define BUF_PULSE_BIT 0x80 +#define BUF_LEN_MASK 0x1f +#define BUF_SAMPLE_MASK 0x7f + +#define BUF_COMMAND_HEADER 0x9f +#define BUF_COMMAND_MASK 0xe0 +#define BUF_COMMAND_NULL 0x00 +#define BUF_HW_CMD_HEADER 0xff +#define BUF_CMD_G_REVISION 0x0b +#define BUF_CMD_S_CARRIER 0x06 +#define BUF_CMD_S_TIMEOUT 0x0c +#define BUF_CMD_SIG_END 0x01 +#define BUF_CMD_S_TXMASK 0x08 +#define BUF_CMD_S_RXSENSOR 0x14 +#define BUF_RSP_PULSE_COUNT 0x15 + +#define CIR_SAMPLE_PERIOD 50 + +/* + * Configuration Register: + * Index Port + * Data Port + */ +#define CR_INDEX_PORT 0x2e +#define CR_DATA_PORT 0x2f + +/* Possible alternate values, depends on how the chip is wired */ +#define CR_INDEX_PORT2 0x4e +#define CR_DATA_PORT2 0x4f + +/* + * GCR_CONFIG_PORT_SEL bit 4 specifies which Index Port value is + * active. 1 = 0x4e, 0 = 0x2e + */ +#define PORT_SEL_PORT_4E_EN 0x10 + +/* Extended Function Mode enable/disable magic values */ +#define CONFIG_REG_ENABLE 0x87 +#define CONFIG_REG_DISABLE 0xaa + +/* Chip IDs found in CR_CHIP_ID_{HI,LO} */ +#define CHIP_ID_HIGH_F71809U 0x04 +#define CHIP_ID_LOW_F71809U 0x08 + +/* + * Global control regs we need to care about: + * Global Control def. + * Register name addr val. */ +#define GCR_SOFTWARE_RESET 0x02 /* 0x00 */ +#define GCR_LOGICAL_DEV_NO 0x07 /* 0x00 */ +#define GCR_CHIP_ID_HI 0x20 /* 0x04 */ +#define GCR_CHIP_ID_LO 0x21 /* 0x08 */ +#define GCR_VENDOR_ID_HI 0x23 /* 0x19 */ +#define GCR_VENDOR_ID_LO 0x24 /* 0x34 */ +#define GCR_CONFIG_PORT_SEL 0x25 /* 0x01 */ +#define GCR_KBMOUSE_WAKEUP 0x27 + +#define LOGICAL_DEV_DISABLE 0x00 +#define LOGICAL_DEV_ENABLE 0x01 + +/* Logical device number of the CIR function */ +#define LOGICAL_DEV_CIR 0x05 + +/* CIR Logical Device (LDN 0x08) config registers */ +#define CIR_CR_COMMAND_INDEX 0x04 +#define CIR_CR_IRCS 0x05 /* Before host writes command to IR, host + must set to 1. When host finshes write + command to IR, host must clear to 0. */ +#define CIR_CR_COMMAND_DATA 0x06 /* Host read or write comand data */ +#define CIR_CR_CLASS 0x07 /* 0xff = rx-only, 0x66 = rx + 2 tx, + 0x33 = rx + 1 tx */ +#define CIR_CR_DEV_EN 0x30 /* bit0 = 1 enables CIR */ +#define CIR_CR_BASE_ADDR_HI 0x60 /* MSB of CIR IO base addr */ +#define CIR_CR_BASE_ADDR_LO 0x61 /* LSB of CIR IO base addr */ +#define CIR_CR_IRQ_SEL 0x70 /* bits3-0 store CIR IRQ */ +#define CIR_CR_PSOUT_STATUS 0xf1 +#define CIR_CR_WAKE_KEY3_ADDR 0xf8 +#define CIR_CR_WAKE_KEY3_CODE 0xf9 +#define CIR_CR_WAKE_KEY3_DC 0xfa +#define CIR_CR_WAKE_CONTROL 0xfb +#define CIR_CR_WAKE_KEY12_ADDR 0xfc +#define CIR_CR_WAKE_KEY4_ADDR 0xfd +#define CIR_CR_WAKE_KEY5_ADDR 0xfe + +#define CLASS_RX_ONLY 0xff +#define CLASS_RX_2TX 0x66 +#define CLASS_RX_1TX 0x33 + +/* CIR device registers */ +#define CIR_STATUS 0x00 +#define CIR_RX_DATA 0x01 +#define CIR_TX_CONTROL 0x02 +#define CIR_TX_DATA 0x03 +#define CIR_CONTROL 0x04 + +/* Bits to enable CIR wake */ +#define LOGICAL_DEV_ACPI 0x01 +#define LDEV_ACPI_WAKE_EN_REG 0xe8 +#define ACPI_WAKE_EN_CIR_BIT 0x04 + +#define LDEV_ACPI_PME_EN_REG 0xf0 +#define LDEV_ACPI_PME_CLR_REG 0xf1 +#define ACPI_PME_CIR_BIT 0x02 + +#define LDEV_ACPI_STATE_REG 0xf4 +#define ACPI_STATE_CIR_BIT 0x20 + +/* + * CIR status register (0x00): + * 7 - CIR_IRQ_EN (1 = enable CIR IRQ, 0 = disable) + * 3 - TX_FINISH (1 when TX finished, write 1 to clear) + * 2 - TX_UNDERRUN (1 on TX underrun, write 1 to clear) + * 1 - RX_TIMEOUT (1 on RX timeout, write 1 to clear) + * 0 - RX_RECEIVE (1 on RX receive, write 1 to clear) + */ +#define CIR_STATUS_IRQ_EN 0x80 +#define CIR_STATUS_TX_FINISH 0x08 +#define CIR_STATUS_TX_UNDERRUN 0x04 +#define CIR_STATUS_RX_TIMEOUT 0x02 +#define CIR_STATUS_RX_RECEIVE 0x01 +#define CIR_STATUS_IRQ_MASK 0x0f + +/* + * CIR TX control register (0x02): + * 7 - TX_START (1 to indicate TX start, auto-cleared when done) + * 6 - TX_END (1 to indicate TX data written to TX fifo) + */ +#define CIR_TX_CONTROL_TX_START 0x80 +#define CIR_TX_CONTROL_TX_END 0x40 + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/imon.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/imon.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/imon.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/imon.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,2460 @@ +/* + * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD + * + * Copyright(C) 2010 Jarod Wilson + * Portions based on the original lirc_imon driver, + * Copyright(C) 2004 Venky Raju(dev@venky.ws) + * + * Huge thanks to R. Geoff Newbury for invaluable debugging on the + * 0xffdc iMON devices, and for sending me one to hack on, without + * which the support for them wouldn't be nearly as good. Thanks + * also to the numerous 0xffdc device owners that tested auto-config + * support for me and provided debug dumps from their devices. + * + * imon 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define MOD_AUTHOR "Jarod Wilson " +#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" +#define MOD_NAME "imon" +#define MOD_VERSION "0.9.3" + +#define DISPLAY_MINOR_BASE 144 +#define DEVICE_NAME "lcd%d" + +#define BUF_CHUNK_SIZE 8 +#define BUF_SIZE 128 + +#define BIT_DURATION 250 /* each bit received is 250us */ + +#define IMON_CLOCK_ENABLE_PACKETS 2 + +/*** P R O T O T Y P E S ***/ + +/* USB Callback prototypes */ +static int imon_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void imon_disconnect(struct usb_interface *interface); +static void usb_rx_callback_intf0(struct urb *urb); +static void usb_rx_callback_intf1(struct urb *urb); +static void usb_tx_callback(struct urb *urb); + +/* suspend/resume support */ +static int imon_resume(struct usb_interface *intf); +static int imon_suspend(struct usb_interface *intf, pm_message_t message); + +/* Display file_operations function prototypes */ +static int display_open(struct inode *inode, struct file *file); +static int display_close(struct inode *inode, struct file *file); + +/* VFD write operation */ +static ssize_t vfd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos); + +/* LCD file_operations override function prototypes */ +static ssize_t lcd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos); + +/*** G L O B A L S ***/ + +struct imon_context { + struct device *dev; + /* Newer devices have two interfaces */ + struct usb_device *usbdev_intf0; + struct usb_device *usbdev_intf1; + + bool display_supported; /* not all controllers do */ + bool display_isopen; /* display port has been opened */ + bool rf_device; /* true if iMON 2.4G LT/DT RF device */ + bool rf_isassociating; /* RF remote associating */ + bool dev_present_intf0; /* USB device presence, interface 0 */ + bool dev_present_intf1; /* USB device presence, interface 1 */ + + struct mutex lock; /* to lock this object */ + wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ + + struct usb_endpoint_descriptor *rx_endpoint_intf0; + struct usb_endpoint_descriptor *rx_endpoint_intf1; + struct usb_endpoint_descriptor *tx_endpoint; + struct urb *rx_urb_intf0; + struct urb *rx_urb_intf1; + struct urb *tx_urb; + bool tx_control; + unsigned char usb_rx_buf[8]; + unsigned char usb_tx_buf[8]; + + struct tx_t { + unsigned char data_buf[35]; /* user data buffer */ + struct completion finished; /* wait for write to finish */ + bool busy; /* write in progress */ + int status; /* status of tx completion */ + } tx; + + u16 vendor; /* usb vendor ID */ + u16 product; /* usb product ID */ + + struct rc_dev *rdev; /* rc-core device for remote */ + struct input_dev *idev; /* input device for panel & IR mouse */ + struct input_dev *touch; /* input device for touchscreen */ + + spinlock_t kc_lock; /* make sure we get keycodes right */ + u32 kc; /* current input keycode */ + u32 last_keycode; /* last reported input keycode */ + u32 rc_scancode; /* the computed remote scancode */ + u8 rc_toggle; /* the computed remote toggle bit */ + u64 rc_type; /* iMON or MCE (RC6) IR protocol? */ + bool release_code; /* some keys send a release code */ + + u8 display_type; /* store the display type */ + bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */ + + char name_rdev[128]; /* rc input device name */ + char phys_rdev[64]; /* rc input device phys path */ + + char name_idev[128]; /* input device name */ + char phys_idev[64]; /* input device phys path */ + + char name_touch[128]; /* touch screen name */ + char phys_touch[64]; /* touch screen phys path */ + struct timer_list ttimer; /* touch screen timer */ + int touch_x; /* x coordinate on touchscreen */ + int touch_y; /* y coordinate on touchscreen */ +}; + +#define TOUCH_TIMEOUT (HZ/30) + +/* vfd character device file operations */ +static const struct file_operations vfd_fops = { + .owner = THIS_MODULE, + .open = &display_open, + .write = &vfd_write, + .release = &display_close, + .llseek = noop_llseek, +}; + +/* lcd character device file operations */ +static const struct file_operations lcd_fops = { + .owner = THIS_MODULE, + .open = &display_open, + .write = &lcd_write, + .release = &display_close, + .llseek = noop_llseek, +}; + +enum { + IMON_DISPLAY_TYPE_AUTO = 0, + IMON_DISPLAY_TYPE_VFD = 1, + IMON_DISPLAY_TYPE_LCD = 2, + IMON_DISPLAY_TYPE_VGA = 3, + IMON_DISPLAY_TYPE_NONE = 4, +}; + +enum { + IMON_KEY_IMON = 0, + IMON_KEY_MCE = 1, + IMON_KEY_PANEL = 2, +}; + +/* + * USB Device ID for iMON USB Control Boards + * + * The Windows drivers contain 6 different inf files, more or less one for + * each new device until the 0x0034-0x0046 devices, which all use the same + * driver. Some of the devices in the 34-46 range haven't been definitively + * identified yet. Early devices have either a TriGem Computer, Inc. or a + * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later + * devices use the SoundGraph vendor ID (0x15c2). This driver only supports + * the ffdc and later devices, which do onboard decoding. + */ +static struct usb_device_id imon_usb_id_table[] = { + /* + * Several devices with this same device ID, all use iMON_PAD.inf + * SoundGraph iMON PAD (IR & VFD) + * SoundGraph iMON PAD (IR & LCD) + * SoundGraph iMON Knob (IR only) + */ + { USB_DEVICE(0x15c2, 0xffdc) }, + + /* + * Newer devices, all driven by the latest iMON Windows driver, full + * list of device IDs extracted via 'strings Setup/data1.hdr |grep 15c2' + * Need user input to fill in details on unknown devices. + */ + /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ + { USB_DEVICE(0x15c2, 0x0034) }, + /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ + { USB_DEVICE(0x15c2, 0x0035) }, + /* SoundGraph iMON OEM VFD (IR & VFD) */ + { USB_DEVICE(0x15c2, 0x0036) }, + /* device specifics unknown */ + { USB_DEVICE(0x15c2, 0x0037) }, + /* SoundGraph iMON OEM LCD (IR & LCD) */ + { USB_DEVICE(0x15c2, 0x0038) }, + /* SoundGraph iMON UltraBay (IR & LCD) */ + { USB_DEVICE(0x15c2, 0x0039) }, + /* device specifics unknown */ + { USB_DEVICE(0x15c2, 0x003a) }, + /* device specifics unknown */ + { USB_DEVICE(0x15c2, 0x003b) }, + /* SoundGraph iMON OEM Inside (IR only) */ + { USB_DEVICE(0x15c2, 0x003c) }, + /* device specifics unknown */ + { USB_DEVICE(0x15c2, 0x003d) }, + /* device specifics unknown */ + { USB_DEVICE(0x15c2, 0x003e) }, + /* device specifics unknown */ + { USB_DEVICE(0x15c2, 0x003f) }, + /* device specifics unknown */ + { USB_DEVICE(0x15c2, 0x0040) }, + /* SoundGraph iMON MINI (IR only) */ + { USB_DEVICE(0x15c2, 0x0041) }, + /* Antec Veris Multimedia Station EZ External (IR only) */ + { USB_DEVICE(0x15c2, 0x0042) }, + /* Antec Veris Multimedia Station Basic Internal (IR only) */ + { USB_DEVICE(0x15c2, 0x0043) }, + /* Antec Veris Multimedia Station Elite (IR & VFD) */ + { USB_DEVICE(0x15c2, 0x0044) }, + /* Antec Veris Multimedia Station Premiere (IR & LCD) */ + { USB_DEVICE(0x15c2, 0x0045) }, + /* device specifics unknown */ + { USB_DEVICE(0x15c2, 0x0046) }, + {} +}; + +/* USB Device data */ +static struct usb_driver imon_driver = { + .name = MOD_NAME, + .probe = imon_probe, + .disconnect = imon_disconnect, + .suspend = imon_suspend, + .resume = imon_resume, + .id_table = imon_usb_id_table, +}; + +static struct usb_class_driver imon_vfd_class = { + .name = DEVICE_NAME, + .fops = &vfd_fops, + .minor_base = DISPLAY_MINOR_BASE, +}; + +static struct usb_class_driver imon_lcd_class = { + .name = DEVICE_NAME, + .fops = &lcd_fops, + .minor_base = DISPLAY_MINOR_BASE, +}; + +/* imon receiver front panel/knob key table */ +static const struct { + u64 hw_code; + u32 keycode; +} imon_panel_key_table[] = { + { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ + { 0x000000001200ffeell, KEY_UP }, + { 0x000000001300ffeell, KEY_DOWN }, + { 0x000000001400ffeell, KEY_LEFT }, + { 0x000000001500ffeell, KEY_RIGHT }, + { 0x000000001600ffeell, KEY_ENTER }, + { 0x000000001700ffeell, KEY_ESC }, + { 0x000000001f00ffeell, KEY_AUDIO }, + { 0x000000002000ffeell, KEY_VIDEO }, + { 0x000000002100ffeell, KEY_CAMERA }, + { 0x000000002700ffeell, KEY_DVD }, + { 0x000000002300ffeell, KEY_TV }, + { 0x000000002b00ffeell, KEY_EXIT }, + { 0x000000002c00ffeell, KEY_SELECT }, + { 0x000000002d00ffeell, KEY_MENU }, + { 0x000000000500ffeell, KEY_PREVIOUS }, + { 0x000000000700ffeell, KEY_REWIND }, + { 0x000000000400ffeell, KEY_STOP }, + { 0x000000003c00ffeell, KEY_PLAYPAUSE }, + { 0x000000000800ffeell, KEY_FASTFORWARD }, + { 0x000000000600ffeell, KEY_NEXT }, + { 0x000000010000ffeell, KEY_RIGHT }, + { 0x000001000000ffeell, KEY_LEFT }, + { 0x000000003d00ffeell, KEY_SELECT }, + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000000100ffeell, KEY_MUTE }, + /* 0xffdc iMON MCE VFD */ + { 0x00010000ffffffeell, KEY_VOLUMEUP }, + { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, + /* iMON Knob values */ + { 0x000100ffffffffeell, KEY_VOLUMEUP }, + { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, + { 0x000008ffffffffeell, KEY_MUTE }, +}; + +/* to prevent races between open() and disconnect(), probing, etc */ +static DEFINE_MUTEX(driver_lock); + +/* Module bookkeeping bits */ +MODULE_AUTHOR(MOD_AUTHOR); +MODULE_DESCRIPTION(MOD_DESC); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, imon_usb_id_table); + +static bool debug; +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); + +/* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */ +static int display_type; +module_param(display_type, int, S_IRUGO); +MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, " + "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); + +static int pad_stabilize = 1; +module_param(pad_stabilize, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD " + "presses in arrow key mode. 0=disable, 1=enable (default)."); + +/* + * In certain use cases, mouse mode isn't really helpful, and could actually + * cause confusion, so allow disabling it when the IR device is open. + */ +static bool nomouse; +module_param(nomouse, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is " + "open. 0=don't disable, 1=disable. (default: don't disable)"); + +/* threshold at which a pad push registers as an arrow key in kbd mode */ +static int pad_thresh; +module_param(pad_thresh, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an " + "arrow key in kbd mode (default: 28)"); + + +static void free_imon_context(struct imon_context *ictx) +{ + struct device *dev = ictx->dev; + + usb_free_urb(ictx->tx_urb); + usb_free_urb(ictx->rx_urb_intf0); + usb_free_urb(ictx->rx_urb_intf1); + kfree(ictx); + + dev_dbg(dev, "%s: iMON context freed\n", __func__); +} + +/** + * Called when the Display device (e.g. /dev/lcd0) + * is opened by the application. + */ +static int display_open(struct inode *inode, struct file *file) +{ + struct usb_interface *interface; + struct imon_context *ictx = NULL; + int subminor; + int retval = 0; + + /* prevent races with disconnect */ + mutex_lock(&driver_lock); + + subminor = iminor(inode); + interface = usb_find_interface(&imon_driver, subminor); + if (!interface) { + pr_err("could not find interface for minor %d\n", subminor); + retval = -ENODEV; + goto exit; + } + ictx = usb_get_intfdata(interface); + + if (!ictx) { + pr_err("no context found for minor %d\n", subminor); + retval = -ENODEV; + goto exit; + } + + mutex_lock(&ictx->lock); + + if (!ictx->display_supported) { + pr_err("display not supported by device\n"); + retval = -ENODEV; + } else if (ictx->display_isopen) { + pr_err("display port is already open\n"); + retval = -EBUSY; + } else { + ictx->display_isopen = true; + file->private_data = ictx; + dev_dbg(ictx->dev, "display port opened\n"); + } + + mutex_unlock(&ictx->lock); + +exit: + mutex_unlock(&driver_lock); + return retval; +} + +/** + * Called when the display device (e.g. /dev/lcd0) + * is closed by the application. + */ +static int display_close(struct inode *inode, struct file *file) +{ + struct imon_context *ictx = NULL; + int retval = 0; + + ictx = file->private_data; + + if (!ictx) { + pr_err("no context for device\n"); + return -ENODEV; + } + + mutex_lock(&ictx->lock); + + if (!ictx->display_supported) { + pr_err("display not supported by device\n"); + retval = -ENODEV; + } else if (!ictx->display_isopen) { + pr_err("display is not open\n"); + retval = -EIO; + } else { + ictx->display_isopen = false; + dev_dbg(ictx->dev, "display port closed\n"); + } + + mutex_unlock(&ictx->lock); + return retval; +} + +/** + * Sends a packet to the device -- this function must be called with + * ictx->lock held, or its unlock/lock sequence while waiting for tx + * to complete can/will lead to a deadlock. + */ +static int send_packet(struct imon_context *ictx) +{ + unsigned int pipe; + unsigned long timeout; + int interval = 0; + int retval = 0; + struct usb_ctrlrequest *control_req = NULL; + + /* Check if we need to use control or interrupt urb */ + if (!ictx->tx_control) { + pipe = usb_sndintpipe(ictx->usbdev_intf0, + ictx->tx_endpoint->bEndpointAddress); + interval = ictx->tx_endpoint->bInterval; + + usb_fill_int_urb(ictx->tx_urb, ictx->usbdev_intf0, pipe, + ictx->usb_tx_buf, + sizeof(ictx->usb_tx_buf), + usb_tx_callback, ictx, interval); + + ictx->tx_urb->actual_length = 0; + } else { + /* fill request into kmalloc'ed space: */ + control_req = kmalloc(sizeof(struct usb_ctrlrequest), + GFP_KERNEL); + if (control_req == NULL) + return -ENOMEM; + + /* setup packet is '21 09 0200 0001 0008' */ + control_req->bRequestType = 0x21; + control_req->bRequest = 0x09; + control_req->wValue = cpu_to_le16(0x0200); + control_req->wIndex = cpu_to_le16(0x0001); + control_req->wLength = cpu_to_le16(0x0008); + + /* control pipe is endpoint 0x00 */ + pipe = usb_sndctrlpipe(ictx->usbdev_intf0, 0); + + /* build the control urb */ + usb_fill_control_urb(ictx->tx_urb, ictx->usbdev_intf0, + pipe, (unsigned char *)control_req, + ictx->usb_tx_buf, + sizeof(ictx->usb_tx_buf), + usb_tx_callback, ictx); + ictx->tx_urb->actual_length = 0; + } + + init_completion(&ictx->tx.finished); + ictx->tx.busy = true; + smp_rmb(); /* ensure later readers know we're busy */ + + retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL); + if (retval) { + ictx->tx.busy = false; + smp_rmb(); /* ensure later readers know we're not busy */ + pr_err("error submitting urb(%d)\n", retval); + } else { + /* Wait for transmission to complete (or abort) */ + mutex_unlock(&ictx->lock); + retval = wait_for_completion_interruptible( + &ictx->tx.finished); + if (retval) + pr_err("task interrupted\n"); + mutex_lock(&ictx->lock); + + retval = ictx->tx.status; + if (retval) + pr_err("packet tx failed (%d)\n", retval); + } + + kfree(control_req); + + /* + * Induce a mandatory 5ms delay before returning, as otherwise, + * send_packet can get called so rapidly as to overwhelm the device, + * particularly on faster systems and/or those with quirky usb. + */ + timeout = msecs_to_jiffies(5); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(timeout); + + return retval; +} + +/** + * Sends an associate packet to the iMON 2.4G. + * + * This might not be such a good idea, since it has an id collision with + * some versions of the "IR & VFD" combo. The only way to determine if it + * is an RF version is to look at the product description string. (Which + * we currently do not fetch). + */ +static int send_associate_24g(struct imon_context *ictx) +{ + int retval; + const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20 }; + + if (!ictx) { + pr_err("no context for device\n"); + return -ENODEV; + } + + if (!ictx->dev_present_intf0) { + pr_err("no iMON device present\n"); + return -ENODEV; + } + + memcpy(ictx->usb_tx_buf, packet, sizeof(packet)); + retval = send_packet(ictx); + + return retval; +} + +/** + * Sends packets to setup and show clock on iMON display + * + * Arguments: year - last 2 digits of year, month - 1..12, + * day - 1..31, dow - day of the week (0-Sun...6-Sat), + * hour - 0..23, minute - 0..59, second - 0..59 + */ +static int send_set_imon_clock(struct imon_context *ictx, + unsigned int year, unsigned int month, + unsigned int day, unsigned int dow, + unsigned int hour, unsigned int minute, + unsigned int second) +{ + unsigned char clock_enable_pkt[IMON_CLOCK_ENABLE_PACKETS][8]; + int retval = 0; + int i; + + if (!ictx) { + pr_err("no context for device\n"); + return -ENODEV; + } + + switch (ictx->display_type) { + case IMON_DISPLAY_TYPE_LCD: + clock_enable_pkt[0][0] = 0x80; + clock_enable_pkt[0][1] = year; + clock_enable_pkt[0][2] = month-1; + clock_enable_pkt[0][3] = day; + clock_enable_pkt[0][4] = hour; + clock_enable_pkt[0][5] = minute; + clock_enable_pkt[0][6] = second; + + clock_enable_pkt[1][0] = 0x80; + clock_enable_pkt[1][1] = 0; + clock_enable_pkt[1][2] = 0; + clock_enable_pkt[1][3] = 0; + clock_enable_pkt[1][4] = 0; + clock_enable_pkt[1][5] = 0; + clock_enable_pkt[1][6] = 0; + + if (ictx->product == 0xffdc) { + clock_enable_pkt[0][7] = 0x50; + clock_enable_pkt[1][7] = 0x51; + } else { + clock_enable_pkt[0][7] = 0x88; + clock_enable_pkt[1][7] = 0x8a; + } + + break; + + case IMON_DISPLAY_TYPE_VFD: + clock_enable_pkt[0][0] = year; + clock_enable_pkt[0][1] = month-1; + clock_enable_pkt[0][2] = day; + clock_enable_pkt[0][3] = dow; + clock_enable_pkt[0][4] = hour; + clock_enable_pkt[0][5] = minute; + clock_enable_pkt[0][6] = second; + clock_enable_pkt[0][7] = 0x40; + + clock_enable_pkt[1][0] = 0; + clock_enable_pkt[1][1] = 0; + clock_enable_pkt[1][2] = 1; + clock_enable_pkt[1][3] = 0; + clock_enable_pkt[1][4] = 0; + clock_enable_pkt[1][5] = 0; + clock_enable_pkt[1][6] = 0; + clock_enable_pkt[1][7] = 0x42; + + break; + + default: + return -ENODEV; + } + + for (i = 0; i < IMON_CLOCK_ENABLE_PACKETS; i++) { + memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8); + retval = send_packet(ictx); + if (retval) { + pr_err("send_packet failed for packet %d\n", i); + break; + } + } + + return retval; +} + +/** + * These are the sysfs functions to handle the association on the iMON 2.4G LT. + */ +static ssize_t show_associate_remote(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct imon_context *ictx = dev_get_drvdata(d); + + if (!ictx) + return -ENODEV; + + mutex_lock(&ictx->lock); + if (ictx->rf_isassociating) + strcpy(buf, "associating\n"); + else + strcpy(buf, "closed\n"); + + dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for " + "instructions on how to associate your iMON 2.4G DT/LT " + "remote\n"); + mutex_unlock(&ictx->lock); + return strlen(buf); +} + +static ssize_t store_associate_remote(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct imon_context *ictx; + + ictx = dev_get_drvdata(d); + + if (!ictx) + return -ENODEV; + + mutex_lock(&ictx->lock); + ictx->rf_isassociating = true; + send_associate_24g(ictx); + mutex_unlock(&ictx->lock); + + return count; +} + +/** + * sysfs functions to control internal imon clock + */ +static ssize_t show_imon_clock(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct imon_context *ictx = dev_get_drvdata(d); + size_t len; + + if (!ictx) + return -ENODEV; + + mutex_lock(&ictx->lock); + + if (!ictx->display_supported) { + len = snprintf(buf, PAGE_SIZE, "Not supported."); + } else { + len = snprintf(buf, PAGE_SIZE, + "To set the clock on your iMON display:\n" + "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n" + "%s", ictx->display_isopen ? + "\nNOTE: imon device must be closed\n" : ""); + } + + mutex_unlock(&ictx->lock); + + return len; +} + +static ssize_t store_imon_clock(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct imon_context *ictx = dev_get_drvdata(d); + ssize_t retval; + unsigned int year, month, day, dow, hour, minute, second; + + if (!ictx) + return -ENODEV; + + mutex_lock(&ictx->lock); + + if (!ictx->display_supported) { + retval = -ENODEV; + goto exit; + } else if (ictx->display_isopen) { + retval = -EBUSY; + goto exit; + } + + if (sscanf(buf, "%u %u %u %u %u %u %u", &year, &month, &day, &dow, + &hour, &minute, &second) != 7) { + retval = -EINVAL; + goto exit; + } + + if ((month < 1 || month > 12) || + (day < 1 || day > 31) || (dow > 6) || + (hour > 23) || (minute > 59) || (second > 59)) { + retval = -EINVAL; + goto exit; + } + + retval = send_set_imon_clock(ictx, year, month, day, dow, + hour, minute, second); + if (retval) + goto exit; + + retval = count; +exit: + mutex_unlock(&ictx->lock); + + return retval; +} + + +static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock, + store_imon_clock); + +static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote, + store_associate_remote); + +static struct attribute *imon_display_sysfs_entries[] = { + &dev_attr_imon_clock.attr, + NULL +}; + +static struct attribute_group imon_display_attr_group = { + .attrs = imon_display_sysfs_entries +}; + +static struct attribute *imon_rf_sysfs_entries[] = { + &dev_attr_associate_remote.attr, + NULL +}; + +static struct attribute_group imon_rf_attr_group = { + .attrs = imon_rf_sysfs_entries +}; + +/** + * Writes data to the VFD. The iMON VFD is 2x16 characters + * and requires data in 5 consecutive USB interrupt packets, + * each packet but the last carrying 7 bytes. + * + * I don't know if the VFD board supports features such as + * scrolling, clearing rows, blanking, etc. so at + * the caller must provide a full screen of data. If fewer + * than 32 bytes are provided spaces will be appended to + * generate a full screen. + */ +static ssize_t vfd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos) +{ + int i; + int offset; + int seq; + int retval = 0; + struct imon_context *ictx; + const unsigned char vfd_packet6[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; + + ictx = file->private_data; + if (!ictx) { + pr_err("no context for device\n"); + return -ENODEV; + } + + mutex_lock(&ictx->lock); + + if (!ictx->dev_present_intf0) { + pr_err("no iMON device present\n"); + retval = -ENODEV; + goto exit; + } + + if (n_bytes <= 0 || n_bytes > 32) { + pr_err("invalid payload size\n"); + retval = -EINVAL; + goto exit; + } + + if (copy_from_user(ictx->tx.data_buf, buf, n_bytes)) { + retval = -EFAULT; + goto exit; + } + + /* Pad with spaces */ + for (i = n_bytes; i < 32; ++i) + ictx->tx.data_buf[i] = ' '; + + for (i = 32; i < 35; ++i) + ictx->tx.data_buf[i] = 0xFF; + + offset = 0; + seq = 0; + + do { + memcpy(ictx->usb_tx_buf, ictx->tx.data_buf + offset, 7); + ictx->usb_tx_buf[7] = (unsigned char) seq; + + retval = send_packet(ictx); + if (retval) { + pr_err("send packet failed for packet #%d\n", seq / 2); + goto exit; + } else { + seq += 2; + offset += 7; + } + + } while (offset < 35); + + /* Send packet #6 */ + memcpy(ictx->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); + ictx->usb_tx_buf[7] = (unsigned char) seq; + retval = send_packet(ictx); + if (retval) + pr_err("send packet failed for packet #%d\n", seq / 2); + +exit: + mutex_unlock(&ictx->lock); + + return (!retval) ? n_bytes : retval; +} + +/** + * Writes data to the LCD. The iMON OEM LCD screen expects 8-byte + * packets. We accept data as 16 hexadecimal digits, followed by a + * newline (to make it easy to drive the device from a command-line + * -- even though the actual binary data is a bit complicated). + * + * The device itself is not a "traditional" text-mode display. It's + * actually a 16x96 pixel bitmap display. That means if you want to + * display text, you've got to have your own "font" and translate the + * text into bitmaps for display. This is really flexible (you can + * display whatever diacritics you need, and so on), but it's also + * a lot more complicated than most LCDs... + */ +static ssize_t lcd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos) +{ + int retval = 0; + struct imon_context *ictx; + + ictx = file->private_data; + if (!ictx) { + pr_err("no context for device\n"); + return -ENODEV; + } + + mutex_lock(&ictx->lock); + + if (!ictx->display_supported) { + pr_err("no iMON display present\n"); + retval = -ENODEV; + goto exit; + } + + if (n_bytes != 8) { + pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes); + retval = -EINVAL; + goto exit; + } + + if (copy_from_user(ictx->usb_tx_buf, buf, 8)) { + retval = -EFAULT; + goto exit; + } + + retval = send_packet(ictx); + if (retval) { + pr_err("send packet failed!\n"); + goto exit; + } else { + dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", + __func__, (int) n_bytes); + } +exit: + mutex_unlock(&ictx->lock); + return (!retval) ? n_bytes : retval; +} + +/** + * Callback function for USB core API: transmit data + */ +static void usb_tx_callback(struct urb *urb) +{ + struct imon_context *ictx; + + if (!urb) + return; + ictx = (struct imon_context *)urb->context; + if (!ictx) + return; + + ictx->tx.status = urb->status; + + /* notify waiters that write has finished */ + ictx->tx.busy = false; + smp_rmb(); /* ensure later readers know we're not busy */ + complete(&ictx->tx.finished); +} + +/** + * report touchscreen input + */ +static void imon_touch_display_timeout(unsigned long data) +{ + struct imon_context *ictx = (struct imon_context *)data; + + if (ictx->display_type != IMON_DISPLAY_TYPE_VGA) + return; + + input_report_abs(ictx->touch, ABS_X, ictx->touch_x); + input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); + input_report_key(ictx->touch, BTN_TOUCH, 0x00); + input_sync(ictx->touch); +} + +/** + * iMON IR receivers support two different signal sets -- those used by + * the iMON remotes, and those used by the Windows MCE remotes (which is + * really just RC-6), but only one or the other at a time, as the signals + * are decoded onboard the receiver. + * + * This function gets called two different ways, one way is from + * rc_register_device, for initial protocol selection/setup, and the other is + * via a userspace-initiated protocol change request, either by direct sysfs + * prodding or by something like ir-keytable. In the rc_register_device case, + * the imon context lock is already held, but when initiated from userspace, + * it is not, so we must acquire it prior to calling send_packet, which + * requires that the lock is held. + */ +static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) +{ + int retval; + struct imon_context *ictx = rc->priv; + struct device *dev = ictx->dev; + bool unlock = false; + unsigned char ir_proto_packet[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; + + if (rc_type && !(rc_type & rc->allowed_protos)) + dev_warn(dev, "Looks like you're trying to use an IR protocol " + "this device does not support\n"); + + switch (rc_type) { + case RC_TYPE_RC6: + dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); + ir_proto_packet[0] = 0x01; + break; + case RC_TYPE_UNKNOWN: + case RC_TYPE_OTHER: + dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); + if (!pad_stabilize) + dev_dbg(dev, "PAD stabilize functionality disabled\n"); + /* ir_proto_packet[0] = 0x00; // already the default */ + rc_type = RC_TYPE_OTHER; + break; + default: + dev_warn(dev, "Unsupported IR protocol specified, overriding " + "to iMON IR protocol\n"); + if (!pad_stabilize) + dev_dbg(dev, "PAD stabilize functionality disabled\n"); + /* ir_proto_packet[0] = 0x00; // already the default */ + rc_type = RC_TYPE_OTHER; + break; + } + + memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); + + if (!mutex_is_locked(&ictx->lock)) { + unlock = true; + mutex_lock(&ictx->lock); + } + + retval = send_packet(ictx); + if (retval) + goto out; + + ictx->rc_type = rc_type; + ictx->pad_mouse = false; + +out: + if (unlock) + mutex_unlock(&ictx->lock); + + return retval; +} + +static inline int tv2int(const struct timeval *a, const struct timeval *b) +{ + int usecs = 0; + int sec = 0; + + if (b->tv_usec > a->tv_usec) { + usecs = 1000000; + sec--; + } + + usecs += a->tv_usec - b->tv_usec; + + sec += a->tv_sec - b->tv_sec; + sec *= 1000; + usecs /= 1000; + sec += usecs; + + if (sec < 0) + sec = 1000; + + return sec; +} + +/** + * The directional pad behaves a bit differently, depending on whether this is + * one of the older ffdc devices or a newer device. Newer devices appear to + * have a higher resolution matrix for more precise mouse movement, but it + * makes things overly sensitive in keyboard mode, so we do some interesting + * contortions to make it less touchy. Older devices run through the same + * routine with shorter timeout and a smaller threshold. + */ +static int stabilize(int a, int b, u16 timeout, u16 threshold) +{ + struct timeval ct; + static struct timeval prev_time = {0, 0}; + static struct timeval hit_time = {0, 0}; + static int x, y, prev_result, hits; + int result = 0; + int msec, msec_hit; + + do_gettimeofday(&ct); + msec = tv2int(&ct, &prev_time); + msec_hit = tv2int(&ct, &hit_time); + + if (msec > 100) { + x = 0; + y = 0; + hits = 0; + } + + x += a; + y += b; + + prev_time = ct; + + if (abs(x) > threshold || abs(y) > threshold) { + if (abs(y) > abs(x)) + result = (y > 0) ? 0x7F : 0x80; + else + result = (x > 0) ? 0x7F00 : 0x8000; + + x = 0; + y = 0; + + if (result == prev_result) { + hits++; + + if (hits > 3) { + switch (result) { + case 0x7F: + y = 17 * threshold / 30; + break; + case 0x80: + y -= 17 * threshold / 30; + break; + case 0x7F00: + x = 17 * threshold / 30; + break; + case 0x8000: + x -= 17 * threshold / 30; + break; + } + } + + if (hits == 2 && msec_hit < timeout) { + result = 0; + hits = 1; + } + } else { + prev_result = result; + hits = 1; + hit_time = ct; + } + } + + return result; +} + +static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode) +{ + u32 keycode; + u32 release; + bool is_release_code = false; + + /* Look for the initial press of a button */ + keycode = rc_g_keycode_from_table(ictx->rdev, scancode); + ictx->rc_toggle = 0x0; + ictx->rc_scancode = scancode; + + /* Look for the release of a button */ + if (keycode == KEY_RESERVED) { + release = scancode & ~0x4000; + keycode = rc_g_keycode_from_table(ictx->rdev, release); + if (keycode != KEY_RESERVED) + is_release_code = true; + } + + ictx->release_code = is_release_code; + + return keycode; +} + +static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode) +{ + u32 keycode; + +#define MCE_KEY_MASK 0x7000 +#define MCE_TOGGLE_BIT 0x8000 + + /* + * On some receivers, mce keys decode to 0x8000f04xx and 0x8000f84xx + * (the toggle bit flipping between alternating key presses), while + * on other receivers, we see 0x8000f74xx and 0x8000ff4xx. To keep + * the table trim, we always or in the bits to look up 0x8000ff4xx, + * but we can't or them into all codes, as some keys are decoded in + * a different way w/o the same use of the toggle bit... + */ + if (scancode & 0x80000000) + scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT; + + ictx->rc_scancode = scancode; + keycode = rc_g_keycode_from_table(ictx->rdev, scancode); + + /* not used in mce mode, but make sure we know its false */ + ictx->release_code = false; + + return keycode; +} + +static u32 imon_panel_key_lookup(u64 code) +{ + int i; + u32 keycode = KEY_RESERVED; + + for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { + if (imon_panel_key_table[i].hw_code == (code | 0xffee)) { + keycode = imon_panel_key_table[i].keycode; + break; + } + } + + return keycode; +} + +static bool imon_mouse_event(struct imon_context *ictx, + unsigned char *buf, int len) +{ + char rel_x = 0x00, rel_y = 0x00; + u8 right_shift = 1; + bool mouse_input = true; + int dir = 0; + unsigned long flags; + + spin_lock_irqsave(&ictx->kc_lock, flags); + + /* newer iMON device PAD or mouse button */ + if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) { + rel_x = buf[2]; + rel_y = buf[3]; + right_shift = 1; + /* 0xffdc iMON PAD or mouse button input */ + } else if (ictx->product == 0xffdc && (buf[0] & 0x40) && + !((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01))) { + rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | + (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; + if (buf[0] & 0x02) + rel_x |= ~0x0f; + rel_x = rel_x + rel_x / 2; + rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | + (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; + if (buf[0] & 0x01) + rel_y |= ~0x0f; + rel_y = rel_y + rel_y / 2; + right_shift = 2; + /* some ffdc devices decode mouse buttons differently... */ + } else if (ictx->product == 0xffdc && (buf[0] == 0x68)) { + right_shift = 2; + /* ch+/- buttons, which we use for an emulated scroll wheel */ + } else if (ictx->kc == KEY_CHANNELUP && (buf[2] & 0x40) != 0x40) { + dir = 1; + } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) { + dir = -1; + } else + mouse_input = false; + + spin_unlock_irqrestore(&ictx->kc_lock, flags); + + if (mouse_input) { + dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); + + if (dir) { + input_report_rel(ictx->idev, REL_WHEEL, dir); + } else if (rel_x || rel_y) { + input_report_rel(ictx->idev, REL_X, rel_x); + input_report_rel(ictx->idev, REL_Y, rel_y); + } else { + input_report_key(ictx->idev, BTN_LEFT, buf[1] & 0x1); + input_report_key(ictx->idev, BTN_RIGHT, + buf[1] >> right_shift & 0x1); + } + input_sync(ictx->idev); + spin_lock_irqsave(&ictx->kc_lock, flags); + ictx->last_keycode = ictx->kc; + spin_unlock_irqrestore(&ictx->kc_lock, flags); + } + + return mouse_input; +} + +static void imon_touch_event(struct imon_context *ictx, unsigned char *buf) +{ + mod_timer(&ictx->ttimer, jiffies + TOUCH_TIMEOUT); + ictx->touch_x = (buf[0] << 4) | (buf[1] >> 4); + ictx->touch_y = 0xfff - ((buf[2] << 4) | (buf[1] & 0xf)); + input_report_abs(ictx->touch, ABS_X, ictx->touch_x); + input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); + input_report_key(ictx->touch, BTN_TOUCH, 0x01); + input_sync(ictx->touch); +} + +static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) +{ + int dir = 0; + char rel_x = 0x00, rel_y = 0x00; + u16 timeout, threshold; + u32 scancode = KEY_RESERVED; + unsigned long flags; + + /* + * The imon directional pad functions more like a touchpad. Bytes 3 & 4 + * contain a position coordinate (x,y), with each component ranging + * from -14 to 14. We want to down-sample this to only 4 discrete values + * for up/down/left/right arrow keys. Also, when you get too close to + * diagonals, it has a tendency to jump back and forth, so lets try to + * ignore when they get too close. + */ + if (ictx->product != 0xffdc) { + /* first, pad to 8 bytes so it conforms with everything else */ + buf[5] = buf[6] = buf[7] = 0; + timeout = 500; /* in msecs */ + /* (2*threshold) x (2*threshold) square */ + threshold = pad_thresh ? pad_thresh : 28; + rel_x = buf[2]; + rel_y = buf[3]; + + if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) { + if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { + dir = stabilize((int)rel_x, (int)rel_y, + timeout, threshold); + if (!dir) { + spin_lock_irqsave(&ictx->kc_lock, + flags); + ictx->kc = KEY_UNKNOWN; + spin_unlock_irqrestore(&ictx->kc_lock, + flags); + return; + } + buf[2] = dir & 0xFF; + buf[3] = (dir >> 8) & 0xFF; + scancode = be32_to_cpu(*((u32 *)buf)); + } + } else { + /* + * Hack alert: instead of using keycodes, we have + * to use hard-coded scancodes here... + */ + if (abs(rel_y) > abs(rel_x)) { + buf[2] = (rel_y > 0) ? 0x7F : 0x80; + buf[3] = 0; + if (rel_y > 0) + scancode = 0x01007f00; /* KEY_DOWN */ + else + scancode = 0x01008000; /* KEY_UP */ + } else { + buf[2] = 0; + buf[3] = (rel_x > 0) ? 0x7F : 0x80; + if (rel_x > 0) + scancode = 0x0100007f; /* KEY_RIGHT */ + else + scancode = 0x01000080; /* KEY_LEFT */ + } + } + + /* + * Handle on-board decoded pad events for e.g. older VFD/iMON-Pad + * device (15c2:ffdc). The remote generates various codes from + * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates + * 0x688301b7 and the right one 0x688481b7. All other keys generate + * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with + * reversed endianess. Extract direction from buffer, rotate endianess, + * adjust sign and feed the values into stabilize(). The resulting codes + * will be 0x01008000, 0x01007F00, which match the newer devices. + */ + } else { + timeout = 10; /* in msecs */ + /* (2*threshold) x (2*threshold) square */ + threshold = pad_thresh ? pad_thresh : 15; + + /* buf[1] is x */ + rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | + (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; + if (buf[0] & 0x02) + rel_x |= ~0x10+1; + /* buf[2] is y */ + rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | + (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; + if (buf[0] & 0x01) + rel_y |= ~0x10+1; + + buf[0] = 0x01; + buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; + + if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) { + dir = stabilize((int)rel_x, (int)rel_y, + timeout, threshold); + if (!dir) { + spin_lock_irqsave(&ictx->kc_lock, flags); + ictx->kc = KEY_UNKNOWN; + spin_unlock_irqrestore(&ictx->kc_lock, flags); + return; + } + buf[2] = dir & 0xFF; + buf[3] = (dir >> 8) & 0xFF; + scancode = be32_to_cpu(*((u32 *)buf)); + } else { + /* + * Hack alert: instead of using keycodes, we have + * to use hard-coded scancodes here... + */ + if (abs(rel_y) > abs(rel_x)) { + buf[2] = (rel_y > 0) ? 0x7F : 0x80; + buf[3] = 0; + if (rel_y > 0) + scancode = 0x01007f00; /* KEY_DOWN */ + else + scancode = 0x01008000; /* KEY_UP */ + } else { + buf[2] = 0; + buf[3] = (rel_x > 0) ? 0x7F : 0x80; + if (rel_x > 0) + scancode = 0x0100007f; /* KEY_RIGHT */ + else + scancode = 0x01000080; /* KEY_LEFT */ + } + } + } + + if (scancode) { + spin_lock_irqsave(&ictx->kc_lock, flags); + ictx->kc = imon_remote_key_lookup(ictx, scancode); + spin_unlock_irqrestore(&ictx->kc_lock, flags); + } +} + +/** + * figure out if these is a press or a release. We don't actually + * care about repeats, as those will be auto-generated within the IR + * subsystem for repeating scancodes. + */ +static int imon_parse_press_type(struct imon_context *ictx, + unsigned char *buf, u8 ktype) +{ + int press_type = 0; + unsigned long flags; + + spin_lock_irqsave(&ictx->kc_lock, flags); + + /* key release of 0x02XXXXXX key */ + if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00) + ictx->kc = ictx->last_keycode; + + /* mouse button release on (some) 0xffdc devices */ + else if (ictx->kc == KEY_RESERVED && buf[0] == 0x68 && buf[1] == 0x82 && + buf[2] == 0x81 && buf[3] == 0xb7) + ictx->kc = ictx->last_keycode; + + /* mouse button release on (some other) 0xffdc devices */ + else if (ictx->kc == KEY_RESERVED && buf[0] == 0x01 && buf[1] == 0x00 && + buf[2] == 0x81 && buf[3] == 0xb7) + ictx->kc = ictx->last_keycode; + + /* mce-specific button handling, no keyup events */ + else if (ktype == IMON_KEY_MCE) { + ictx->rc_toggle = buf[2]; + press_type = 1; + + /* incoherent or irrelevant data */ + } else if (ictx->kc == KEY_RESERVED) + press_type = -EINVAL; + + /* key release of 0xXXXXXXb7 key */ + else if (ictx->release_code) + press_type = 0; + + /* this is a button press */ + else + press_type = 1; + + spin_unlock_irqrestore(&ictx->kc_lock, flags); + + return press_type; +} + +/** + * Process the incoming packet + */ +static void imon_incoming_packet(struct imon_context *ictx, + struct urb *urb, int intf) +{ + int len = urb->actual_length; + unsigned char *buf = urb->transfer_buffer; + struct device *dev = ictx->dev; + unsigned long flags; + u32 kc; + int i; + u64 scancode; + int press_type = 0; + int msec; + struct timeval t; + static struct timeval prev_time = { 0, 0 }; + u8 ktype; + + /* filter out junk data on the older 0xffdc imon devices */ + if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) + return; + + /* Figure out what key was pressed */ + if (len == 8 && buf[7] == 0xee) { + scancode = be64_to_cpu(*((u64 *)buf)); + ktype = IMON_KEY_PANEL; + kc = imon_panel_key_lookup(scancode); + } else { + scancode = be32_to_cpu(*((u32 *)buf)); + if (ictx->rc_type == RC_TYPE_RC6) { + ktype = IMON_KEY_IMON; + if (buf[0] == 0x80) + ktype = IMON_KEY_MCE; + kc = imon_mce_key_lookup(ictx, scancode); + } else { + ktype = IMON_KEY_IMON; + kc = imon_remote_key_lookup(ictx, scancode); + } + } + + spin_lock_irqsave(&ictx->kc_lock, flags); + /* keyboard/mouse mode toggle button */ + if (kc == KEY_KEYBOARD && !ictx->release_code) { + ictx->last_keycode = kc; + if (!nomouse) { + ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1; + dev_dbg(dev, "toggling to %s mode\n", + ictx->pad_mouse ? "mouse" : "keyboard"); + spin_unlock_irqrestore(&ictx->kc_lock, flags); + return; + } else { + ictx->pad_mouse = false; + dev_dbg(dev, "mouse mode disabled, passing key value\n"); + } + } + + ictx->kc = kc; + spin_unlock_irqrestore(&ictx->kc_lock, flags); + + /* send touchscreen events through input subsystem if touchpad data */ + if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && + buf[7] == 0x86) { + imon_touch_event(ictx, buf); + return; + + /* look for mouse events with pad in mouse mode */ + } else if (ictx->pad_mouse) { + if (imon_mouse_event(ictx, buf, len)) + return; + } + + /* Now for some special handling to convert pad input to arrow keys */ + if (((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) || + ((len == 8) && (buf[0] & 0x40) && + !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) { + len = 8; + imon_pad_to_keys(ictx, buf); + } + + if (debug) { + printk(KERN_INFO "intf%d decoded packet: ", intf); + for (i = 0; i < len; ++i) + printk("%02x ", buf[i]); + printk("\n"); + } + + press_type = imon_parse_press_type(ictx, buf, ktype); + if (press_type < 0) + goto not_input_data; + + spin_lock_irqsave(&ictx->kc_lock, flags); + if (ictx->kc == KEY_UNKNOWN) + goto unknown_key; + spin_unlock_irqrestore(&ictx->kc_lock, flags); + + if (ktype != IMON_KEY_PANEL) { + if (press_type == 0) + rc_keyup(ictx->rdev); + else { + rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle); + spin_lock_irqsave(&ictx->kc_lock, flags); + ictx->last_keycode = ictx->kc; + spin_unlock_irqrestore(&ictx->kc_lock, flags); + } + return; + } + + /* Only panel type events left to process now */ + spin_lock_irqsave(&ictx->kc_lock, flags); + + /* KEY_MUTE repeats from knob need to be suppressed */ + if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) { + do_gettimeofday(&t); + msec = tv2int(&t, &prev_time); + prev_time = t; + if (msec < ictx->idev->rep[REP_DELAY]) { + spin_unlock_irqrestore(&ictx->kc_lock, flags); + return; + } + } + kc = ictx->kc; + + spin_unlock_irqrestore(&ictx->kc_lock, flags); + + input_report_key(ictx->idev, kc, press_type); + input_sync(ictx->idev); + + /* panel keys don't generate a release */ + input_report_key(ictx->idev, kc, 0); + input_sync(ictx->idev); + + ictx->last_keycode = kc; + + return; + +unknown_key: + spin_unlock_irqrestore(&ictx->kc_lock, flags); + dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, + (long long)scancode); + return; + +not_input_data: + if (len != 8) { + dev_warn(dev, "imon %s: invalid incoming packet " + "size (len = %d, intf%d)\n", __func__, len, intf); + return; + } + + /* iMON 2.4G associate frame */ + if (buf[0] == 0x00 && + buf[2] == 0xFF && /* REFID */ + buf[3] == 0xFF && + buf[4] == 0xFF && + buf[5] == 0xFF && /* iMON 2.4G */ + ((buf[6] == 0x4E && buf[7] == 0xDF) || /* LT */ + (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */ + dev_warn(dev, "%s: remote associated refid=%02X\n", + __func__, buf[1]); + ictx->rf_isassociating = false; + } +} + +/** + * Callback function for USB core API: receive data + */ +static void usb_rx_callback_intf0(struct urb *urb) +{ + struct imon_context *ictx; + int intfnum = 0; + + if (!urb) + return; + + ictx = (struct imon_context *)urb->context; + if (!ictx) + return; + + switch (urb->status) { + case -ENOENT: /* usbcore unlink successful! */ + return; + + case -ESHUTDOWN: /* transport endpoint was shut down */ + break; + + case 0: + imon_incoming_packet(ictx, urb, intfnum); + break; + + default: + dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", + __func__, urb->status); + break; + } + + usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); +} + +static void usb_rx_callback_intf1(struct urb *urb) +{ + struct imon_context *ictx; + int intfnum = 1; + + if (!urb) + return; + + ictx = (struct imon_context *)urb->context; + if (!ictx) + return; + + switch (urb->status) { + case -ENOENT: /* usbcore unlink successful! */ + return; + + case -ESHUTDOWN: /* transport endpoint was shut down */ + break; + + case 0: + imon_incoming_packet(ictx, urb, intfnum); + break; + + default: + dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", + __func__, urb->status); + break; + } + + usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); +} + +/* + * The 0x15c2:0xffdc device ID was used for umpteen different imon + * devices, and all of them constantly spew interrupts, even when there + * is no actual data to report. However, byte 6 of this buffer looks like + * its unique across device variants, so we're trying to key off that to + * figure out which display type (if any) and what IR protocol the device + * actually supports. These devices have their IR protocol hard-coded into + * their firmware, they can't be changed on the fly like the newer hardware. + */ +static void imon_get_ffdc_type(struct imon_context *ictx) +{ + u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; + u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; + u64 allowed_protos = RC_TYPE_OTHER; + + switch (ffdc_cfg_byte) { + /* iMON Knob, no display, iMON IR + vol knob */ + case 0x21: + dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR"); + ictx->display_supported = false; + break; + /* iMON 2.4G LT (usb stick), no display, iMON RF */ + case 0x4e: + dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF"); + ictx->display_supported = false; + ictx->rf_device = true; + break; + /* iMON VFD, no IR (does have vol knob tho) */ + case 0x35: + dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR"); + detected_display_type = IMON_DISPLAY_TYPE_VFD; + break; + /* iMON VFD, iMON IR */ + case 0x24: + case 0x85: + dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR"); + detected_display_type = IMON_DISPLAY_TYPE_VFD; + break; + /* iMON VFD, MCE IR */ + case 0x9e: + dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); + detected_display_type = IMON_DISPLAY_TYPE_VFD; + allowed_protos = RC_TYPE_RC6; + break; + /* iMON LCD, MCE IR */ + case 0x9f: + dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); + detected_display_type = IMON_DISPLAY_TYPE_LCD; + allowed_protos = RC_TYPE_RC6; + break; + default: + dev_info(ictx->dev, "Unknown 0xffdc device, " + "defaulting to VFD and iMON IR"); + detected_display_type = IMON_DISPLAY_TYPE_VFD; + break; + } + + printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte); + + ictx->display_type = detected_display_type; + ictx->rc_type = allowed_protos; +} + +static void imon_set_display_type(struct imon_context *ictx) +{ + u8 configured_display_type = IMON_DISPLAY_TYPE_VFD; + + /* + * Try to auto-detect the type of display if the user hasn't set + * it by hand via the display_type modparam. Default is VFD. + */ + + if (display_type == IMON_DISPLAY_TYPE_AUTO) { + switch (ictx->product) { + case 0xffdc: + /* set in imon_get_ffdc_type() */ + configured_display_type = ictx->display_type; + break; + case 0x0034: + case 0x0035: + configured_display_type = IMON_DISPLAY_TYPE_VGA; + break; + case 0x0038: + case 0x0039: + case 0x0045: + configured_display_type = IMON_DISPLAY_TYPE_LCD; + break; + case 0x003c: + case 0x0041: + case 0x0042: + case 0x0043: + configured_display_type = IMON_DISPLAY_TYPE_NONE; + ictx->display_supported = false; + break; + case 0x0036: + case 0x0044: + default: + configured_display_type = IMON_DISPLAY_TYPE_VFD; + break; + } + } else { + configured_display_type = display_type; + if (display_type == IMON_DISPLAY_TYPE_NONE) + ictx->display_supported = false; + else + ictx->display_supported = true; + dev_info(ictx->dev, "%s: overriding display type to %d via " + "modparam\n", __func__, display_type); + } + + ictx->display_type = configured_display_type; +} + +static struct rc_dev *imon_init_rdev(struct imon_context *ictx) +{ + struct rc_dev *rdev; + int ret; + const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x88 }; + + rdev = rc_allocate_device(); + if (!rdev) { + dev_err(ictx->dev, "remote control dev allocation failed\n"); + goto out; + } + + snprintf(ictx->name_rdev, sizeof(ictx->name_rdev), + "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product); + usb_make_path(ictx->usbdev_intf0, ictx->phys_rdev, + sizeof(ictx->phys_rdev)); + strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev)); + + rdev->input_name = ictx->name_rdev; + rdev->input_phys = ictx->phys_rdev; + usb_to_input_id(ictx->usbdev_intf0, &rdev->input_id); + rdev->dev.parent = ictx->dev; + + rdev->priv = ictx; + rdev->driver_type = RC_DRIVER_SCANCODE; + rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */ + rdev->change_protocol = imon_ir_change_protocol; + rdev->driver_name = MOD_NAME; + + /* Enable front-panel buttons and/or knobs */ + memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet)); + ret = send_packet(ictx); + /* Not fatal, but warn about it */ + if (ret) + dev_info(ictx->dev, "panel buttons/knobs setup failed\n"); + + if (ictx->product == 0xffdc) { + imon_get_ffdc_type(ictx); + rdev->allowed_protos = ictx->rc_type; + } + + imon_set_display_type(ictx); + + if (ictx->rc_type == RC_TYPE_RC6) + rdev->map_name = RC_MAP_IMON_MCE; + else + rdev->map_name = RC_MAP_IMON_PAD; + + ret = rc_register_device(rdev); + if (ret < 0) { + dev_err(ictx->dev, "remote input dev register failed\n"); + goto out; + } + + return rdev; + +out: + rc_free_device(rdev); + return NULL; +} + +static struct input_dev *imon_init_idev(struct imon_context *ictx) +{ + struct input_dev *idev; + int ret, i; + + idev = input_allocate_device(); + if (!idev) { + dev_err(ictx->dev, "input dev allocation failed\n"); + goto out; + } + + snprintf(ictx->name_idev, sizeof(ictx->name_idev), + "iMON Panel, Knob and Mouse(%04x:%04x)", + ictx->vendor, ictx->product); + idev->name = ictx->name_idev; + + usb_make_path(ictx->usbdev_intf0, ictx->phys_idev, + sizeof(ictx->phys_idev)); + strlcat(ictx->phys_idev, "/input1", sizeof(ictx->phys_idev)); + idev->phys = ictx->phys_idev; + + idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL); + + idev->keybit[BIT_WORD(BTN_MOUSE)] = + BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); + idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | + BIT_MASK(REL_WHEEL); + + /* panel and/or knob code support */ + for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { + u32 kc = imon_panel_key_table[i].keycode; + __set_bit(kc, idev->keybit); + } + + usb_to_input_id(ictx->usbdev_intf0, &idev->id); + idev->dev.parent = ictx->dev; + input_set_drvdata(idev, ictx); + + ret = input_register_device(idev); + if (ret < 0) { + dev_err(ictx->dev, "input dev register failed\n"); + goto out; + } + + return idev; + +out: + input_free_device(idev); + return NULL; +} + +static struct input_dev *imon_init_touch(struct imon_context *ictx) +{ + struct input_dev *touch; + int ret; + + touch = input_allocate_device(); + if (!touch) { + dev_err(ictx->dev, "touchscreen input dev allocation failed\n"); + goto touch_alloc_failed; + } + + snprintf(ictx->name_touch, sizeof(ictx->name_touch), + "iMON USB Touchscreen (%04x:%04x)", + ictx->vendor, ictx->product); + touch->name = ictx->name_touch; + + usb_make_path(ictx->usbdev_intf1, ictx->phys_touch, + sizeof(ictx->phys_touch)); + strlcat(ictx->phys_touch, "/input2", sizeof(ictx->phys_touch)); + touch->phys = ictx->phys_touch; + + touch->evbit[0] = + BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + touch->keybit[BIT_WORD(BTN_TOUCH)] = + BIT_MASK(BTN_TOUCH); + input_set_abs_params(touch, ABS_X, + 0x00, 0xfff, 0, 0); + input_set_abs_params(touch, ABS_Y, + 0x00, 0xfff, 0, 0); + + input_set_drvdata(touch, ictx); + + usb_to_input_id(ictx->usbdev_intf1, &touch->id); + touch->dev.parent = ictx->dev; + ret = input_register_device(touch); + if (ret < 0) { + dev_info(ictx->dev, "touchscreen input dev register failed\n"); + goto touch_register_failed; + } + + return touch; + +touch_register_failed: + input_free_device(touch); + +touch_alloc_failed: + return NULL; +} + +static bool imon_find_endpoints(struct imon_context *ictx, + struct usb_host_interface *iface_desc) +{ + struct usb_endpoint_descriptor *ep; + struct usb_endpoint_descriptor *rx_endpoint = NULL; + struct usb_endpoint_descriptor *tx_endpoint = NULL; + int ifnum = iface_desc->desc.bInterfaceNumber; + int num_endpts = iface_desc->desc.bNumEndpoints; + int i, ep_dir, ep_type; + bool ir_ep_found = false; + bool display_ep_found = false; + bool tx_control = false; + + /* + * Scan the endpoint list and set: + * first input endpoint = IR endpoint + * first output endpoint = display endpoint + */ + for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { + ep = &iface_desc->endpoint[i].desc; + ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; + ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + if (!ir_ep_found && ep_dir == USB_DIR_IN && + ep_type == USB_ENDPOINT_XFER_INT) { + + rx_endpoint = ep; + ir_ep_found = true; + dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__); + + } else if (!display_ep_found && ep_dir == USB_DIR_OUT && + ep_type == USB_ENDPOINT_XFER_INT) { + tx_endpoint = ep; + display_ep_found = true; + dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__); + } + } + + if (ifnum == 0) { + ictx->rx_endpoint_intf0 = rx_endpoint; + /* + * tx is used to send characters to lcd/vfd, associate RF + * remotes, set IR protocol, and maybe more... + */ + ictx->tx_endpoint = tx_endpoint; + } else { + ictx->rx_endpoint_intf1 = rx_endpoint; + } + + /* + * If we didn't find a display endpoint, this is probably one of the + * newer iMON devices that use control urb instead of interrupt + */ + if (!display_ep_found) { + tx_control = true; + display_ep_found = true; + dev_dbg(ictx->dev, "%s: device uses control endpoint, not " + "interface OUT endpoint\n", __func__); + } + + /* + * Some iMON receivers have no display. Unfortunately, it seems + * that SoundGraph recycles device IDs between devices both with + * and without... :\ + */ + if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) { + display_ep_found = false; + dev_dbg(ictx->dev, "%s: device has no display\n", __func__); + } + + /* + * iMON Touch devices have a VGA touchscreen, but no "display", as + * that refers to e.g. /dev/lcd0 (a character device LCD or VFD). + */ + if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { + display_ep_found = false; + dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__); + } + + /* Input endpoint is mandatory */ + if (!ir_ep_found) + pr_err("no valid input (IR) endpoint found\n"); + + ictx->tx_control = tx_control; + + if (display_ep_found) + ictx->display_supported = true; + + return ir_ep_found; + +} + +static struct imon_context *imon_init_intf0(struct usb_interface *intf) +{ + struct imon_context *ictx; + struct urb *rx_urb; + struct urb *tx_urb; + struct device *dev = &intf->dev; + struct usb_host_interface *iface_desc; + int ret = -ENOMEM; + + ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL); + if (!ictx) { + dev_err(dev, "%s: kzalloc failed for context", __func__); + goto exit; + } + rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rx_urb) { + dev_err(dev, "%s: usb_alloc_urb failed for IR urb", __func__); + goto rx_urb_alloc_failed; + } + tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!tx_urb) { + dev_err(dev, "%s: usb_alloc_urb failed for display urb", + __func__); + goto tx_urb_alloc_failed; + } + + mutex_init(&ictx->lock); + spin_lock_init(&ictx->kc_lock); + + mutex_lock(&ictx->lock); + + ictx->dev = dev; + ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf)); + ictx->dev_present_intf0 = true; + ictx->rx_urb_intf0 = rx_urb; + ictx->tx_urb = tx_urb; + ictx->rf_device = false; + + ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); + ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); + + ret = -ENODEV; + iface_desc = intf->cur_altsetting; + if (!imon_find_endpoints(ictx, iface_desc)) { + goto find_endpoint_failed; + } + + usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, + usb_rcvintpipe(ictx->usbdev_intf0, + ictx->rx_endpoint_intf0->bEndpointAddress), + ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), + usb_rx_callback_intf0, ictx, + ictx->rx_endpoint_intf0->bInterval); + + ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL); + if (ret) { + pr_err("usb_submit_urb failed for intf0 (%d)\n", ret); + goto urb_submit_failed; + } + + ictx->idev = imon_init_idev(ictx); + if (!ictx->idev) { + dev_err(dev, "%s: input device setup failed\n", __func__); + goto idev_setup_failed; + } + + ictx->rdev = imon_init_rdev(ictx); + if (!ictx->rdev) { + dev_err(dev, "%s: rc device setup failed\n", __func__); + goto rdev_setup_failed; + } + + mutex_unlock(&ictx->lock); + return ictx; + +rdev_setup_failed: + input_unregister_device(ictx->idev); +idev_setup_failed: + usb_kill_urb(ictx->rx_urb_intf0); +urb_submit_failed: +find_endpoint_failed: + mutex_unlock(&ictx->lock); + usb_free_urb(tx_urb); +tx_urb_alloc_failed: + usb_free_urb(rx_urb); +rx_urb_alloc_failed: + kfree(ictx); +exit: + dev_err(dev, "unable to initialize intf0, err %d\n", ret); + + return NULL; +} + +static struct imon_context *imon_init_intf1(struct usb_interface *intf, + struct imon_context *ictx) +{ + struct urb *rx_urb; + struct usb_host_interface *iface_desc; + int ret = -ENOMEM; + + rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rx_urb) { + pr_err("usb_alloc_urb failed for IR urb\n"); + goto rx_urb_alloc_failed; + } + + mutex_lock(&ictx->lock); + + if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { + init_timer(&ictx->ttimer); + ictx->ttimer.data = (unsigned long)ictx; + ictx->ttimer.function = imon_touch_display_timeout; + } + + ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); + ictx->dev_present_intf1 = true; + ictx->rx_urb_intf1 = rx_urb; + + ret = -ENODEV; + iface_desc = intf->cur_altsetting; + if (!imon_find_endpoints(ictx, iface_desc)) + goto find_endpoint_failed; + + if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { + ictx->touch = imon_init_touch(ictx); + if (!ictx->touch) + goto touch_setup_failed; + } else + ictx->touch = NULL; + + usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, + usb_rcvintpipe(ictx->usbdev_intf1, + ictx->rx_endpoint_intf1->bEndpointAddress), + ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), + usb_rx_callback_intf1, ictx, + ictx->rx_endpoint_intf1->bInterval); + + ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL); + + if (ret) { + pr_err("usb_submit_urb failed for intf1 (%d)\n", ret); + goto urb_submit_failed; + } + + mutex_unlock(&ictx->lock); + return ictx; + +urb_submit_failed: + if (ictx->touch) + input_unregister_device(ictx->touch); +touch_setup_failed: +find_endpoint_failed: + mutex_unlock(&ictx->lock); + usb_free_urb(rx_urb); +rx_urb_alloc_failed: + dev_err(ictx->dev, "unable to initialize intf0, err %d\n", ret); + + return NULL; +} + +static void imon_init_display(struct imon_context *ictx, + struct usb_interface *intf) +{ + int ret; + + dev_dbg(ictx->dev, "Registering iMON display with sysfs\n"); + + /* set up sysfs entry for built-in clock */ + ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group); + if (ret) + dev_err(ictx->dev, "Could not create display sysfs " + "entries(%d)", ret); + + if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) + ret = usb_register_dev(intf, &imon_lcd_class); + else + ret = usb_register_dev(intf, &imon_vfd_class); + if (ret) + /* Not a fatal error, so ignore */ + dev_info(ictx->dev, "could not get a minor number for " + "display\n"); + +} + +/** + * Callback function for USB core API: Probe + */ +static int __devinit imon_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *usbdev = NULL; + struct usb_host_interface *iface_desc = NULL; + struct usb_interface *first_if; + struct device *dev = &interface->dev; + int ifnum, sysfs_err; + int ret = 0; + struct imon_context *ictx = NULL; + struct imon_context *first_if_ctx = NULL; + u16 vendor, product; + + usbdev = usb_get_dev(interface_to_usbdev(interface)); + iface_desc = interface->cur_altsetting; + ifnum = iface_desc->desc.bInterfaceNumber; + vendor = le16_to_cpu(usbdev->descriptor.idVendor); + product = le16_to_cpu(usbdev->descriptor.idProduct); + + dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", + __func__, vendor, product, ifnum); + + /* prevent races probing devices w/multiple interfaces */ + mutex_lock(&driver_lock); + + first_if = usb_ifnum_to_if(usbdev, 0); + first_if_ctx = usb_get_intfdata(first_if); + + if (ifnum == 0) { + ictx = imon_init_intf0(interface); + if (!ictx) { + pr_err("failed to initialize context!\n"); + ret = -ENODEV; + goto fail; + } + + } else { + /* this is the secondary interface on the device */ + ictx = imon_init_intf1(interface, first_if_ctx); + if (!ictx) { + pr_err("failed to attach to context!\n"); + ret = -ENODEV; + goto fail; + } + + } + + usb_set_intfdata(interface, ictx); + + if (ifnum == 0) { + mutex_lock(&ictx->lock); + + if (product == 0xffdc && ictx->rf_device) { + sysfs_err = sysfs_create_group(&interface->dev.kobj, + &imon_rf_attr_group); + if (sysfs_err) + pr_err("Could not create RF sysfs entries(%d)\n", + sysfs_err); + } + + if (ictx->display_supported) + imon_init_display(ictx, interface); + + mutex_unlock(&ictx->lock); + } + + dev_info(dev, "iMON device (%04x:%04x, intf%d) on " + "usb<%d:%d> initialized\n", vendor, product, ifnum, + usbdev->bus->busnum, usbdev->devnum); + + mutex_unlock(&driver_lock); + + return 0; + +fail: + mutex_unlock(&driver_lock); + dev_err(dev, "unable to register, err %d\n", ret); + + return ret; +} + +/** + * Callback function for USB core API: disconnect + */ +static void __devexit imon_disconnect(struct usb_interface *interface) +{ + struct imon_context *ictx; + struct device *dev; + int ifnum; + + /* prevent races with multi-interface device probing and display_open */ + mutex_lock(&driver_lock); + + ictx = usb_get_intfdata(interface); + dev = ictx->dev; + ifnum = interface->cur_altsetting->desc.bInterfaceNumber; + + /* + * sysfs_remove_group is safe to call even if sysfs_create_group + * hasn't been called + */ + sysfs_remove_group(&interface->dev.kobj, &imon_display_attr_group); + sysfs_remove_group(&interface->dev.kobj, &imon_rf_attr_group); + + usb_set_intfdata(interface, NULL); + + /* Abort ongoing write */ + if (ictx->tx.busy) { + usb_kill_urb(ictx->tx_urb); + complete_all(&ictx->tx.finished); + } + + if (ifnum == 0) { + ictx->dev_present_intf0 = false; + usb_kill_urb(ictx->rx_urb_intf0); + input_unregister_device(ictx->idev); + rc_unregister_device(ictx->rdev); + if (ictx->display_supported) { + if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) + usb_deregister_dev(interface, &imon_lcd_class); + else if (ictx->display_type == IMON_DISPLAY_TYPE_VFD) + usb_deregister_dev(interface, &imon_vfd_class); + } + } else { + ictx->dev_present_intf1 = false; + usb_kill_urb(ictx->rx_urb_intf1); + if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { + input_unregister_device(ictx->touch); + del_timer_sync(&ictx->ttimer); + } + } + + if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) + free_imon_context(ictx); + + mutex_unlock(&driver_lock); + + dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n", + __func__, ifnum); +} + +static int imon_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct imon_context *ictx = usb_get_intfdata(intf); + int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + + if (ifnum == 0) + usb_kill_urb(ictx->rx_urb_intf0); + else + usb_kill_urb(ictx->rx_urb_intf1); + + return 0; +} + +static int imon_resume(struct usb_interface *intf) +{ + int rc = 0; + struct imon_context *ictx = usb_get_intfdata(intf); + int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + + if (ifnum == 0) { + usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, + usb_rcvintpipe(ictx->usbdev_intf0, + ictx->rx_endpoint_intf0->bEndpointAddress), + ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), + usb_rx_callback_intf0, ictx, + ictx->rx_endpoint_intf0->bInterval); + + rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); + + } else { + usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, + usb_rcvintpipe(ictx->usbdev_intf1, + ictx->rx_endpoint_intf1->bEndpointAddress), + ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), + usb_rx_callback_intf1, ictx, + ictx->rx_endpoint_intf1->bInterval); + + rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); + } + + return rc; +} + +static int __init imon_init(void) +{ + int rc; + + rc = usb_register(&imon_driver); + if (rc) { + pr_err("usb register failed(%d)\n", rc); + rc = -ENODEV; + } + + return rc; +} + +static void __exit imon_exit(void) +{ + usb_deregister(&imon_driver); +} + +module_init(imon_init); +module_exit(imon_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-jvc-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-jvc-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-jvc-decoder.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-jvc-decoder.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,198 @@ +/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol + * + * Copyright (C) 2010 by David Härdeman + * + * 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 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. + */ + +#include +#include "rc-core-priv.h" + +#define JVC_NBITS 16 /* dev(8) + func(8) */ +#define JVC_UNIT 525000 /* ns */ +#define JVC_HEADER_PULSE (16 * JVC_UNIT) /* lack of header -> repeat */ +#define JVC_HEADER_SPACE (8 * JVC_UNIT) +#define JVC_BIT_PULSE (1 * JVC_UNIT) +#define JVC_BIT_0_SPACE (1 * JVC_UNIT) +#define JVC_BIT_1_SPACE (3 * JVC_UNIT) +#define JVC_TRAILER_PULSE (1 * JVC_UNIT) +#define JVC_TRAILER_SPACE (35 * JVC_UNIT) + +enum jvc_state { + STATE_INACTIVE, + STATE_HEADER_SPACE, + STATE_BIT_PULSE, + STATE_BIT_SPACE, + STATE_TRAILER_PULSE, + STATE_TRAILER_SPACE, + STATE_CHECK_REPEAT, +}; + +/** + * ir_jvc_decode() - Decode one JVC pulse or space + * @dev: the struct rc_dev descriptor of the device + * @duration: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct jvc_dec *data = &dev->raw->jvc; + + if (!(dev->raw->enabled_protocols & RC_TYPE_JVC)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2)) + goto out; + + IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + +again: + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) + break; + + data->count = 0; + data->first = true; + data->toggle = !data->toggle; + data->state = STATE_HEADER_SPACE; + return 0; + + case STATE_HEADER_SPACE: + if (ev.pulse) + break; + + if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2)) + break; + + data->state = STATE_BIT_PULSE; + return 0; + + case STATE_BIT_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2)) + break; + + data->state = STATE_BIT_SPACE; + return 0; + + case STATE_BIT_SPACE: + if (ev.pulse) + break; + + data->bits <<= 1; + if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) { + data->bits |= 1; + decrease_duration(&ev, JVC_BIT_1_SPACE); + } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2)) + decrease_duration(&ev, JVC_BIT_0_SPACE); + else + break; + data->count++; + + if (data->count == JVC_NBITS) + data->state = STATE_TRAILER_PULSE; + else + data->state = STATE_BIT_PULSE; + return 0; + + case STATE_TRAILER_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2)) + break; + + data->state = STATE_TRAILER_SPACE; + return 0; + + case STATE_TRAILER_SPACE: + if (ev.pulse) + break; + + if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2)) + break; + + if (data->first) { + u32 scancode; + scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | + (bitrev8((data->bits >> 0) & 0xff) << 0); + IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); + rc_keydown(dev, scancode, data->toggle); + data->first = false; + data->old_bits = data->bits; + } else if (data->bits == data->old_bits) { + IR_dprintk(1, "JVC repeat\n"); + rc_repeat(dev); + } else { + IR_dprintk(1, "JVC invalid repeat msg\n"); + break; + } + + data->count = 0; + data->state = STATE_CHECK_REPEAT; + return 0; + + case STATE_CHECK_REPEAT: + if (!ev.pulse) + break; + + if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) + data->state = STATE_INACTIVE; + else + data->state = STATE_BIT_PULSE; + goto again; + } + +out: + IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler jvc_handler = { + .protocols = RC_TYPE_JVC, + .decode = ir_jvc_decode, +}; + +static int __init ir_jvc_decode_init(void) +{ + ir_raw_handler_register(&jvc_handler); + + printk(KERN_INFO "IR JVC protocol handler initialized\n"); + return 0; +} + +static void __exit ir_jvc_decode_exit(void) +{ + ir_raw_handler_unregister(&jvc_handler); +} + +module_init(ir_jvc_decode_init); +module_exit(ir_jvc_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Härdeman "); +MODULE_DESCRIPTION("JVC IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-lirc-codec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-lirc-codec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-lirc-codec.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-lirc-codec.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,409 @@ +/* ir-lirc-codec.c - rc-core to classic lirc interface bridge + * + * Copyright (C) 2010 by Jarod Wilson + * + * 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 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. + */ + +#include +#include +#include +#include +#include +#include "rc-core-priv.h" + +#define LIRCBUF_SIZE 256 + +/** + * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the + * lircd userspace daemon for decoding. + * @input_dev: the struct rc_dev descriptor of the device + * @duration: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the lirc interfaces aren't wired up. + */ +static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct lirc_codec *lirc = &dev->raw->lirc; + int sample; + + if (!(dev->raw->enabled_protocols & RC_TYPE_LIRC)) + return 0; + + if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) + return -EINVAL; + + /* Packet start */ + if (ev.reset) + return 0; + + /* Carrier reports */ + if (ev.carrier_report) { + sample = LIRC_FREQUENCY(ev.carrier); + IR_dprintk(2, "carrier report (freq: %d)\n", sample); + + /* Packet end */ + } else if (ev.timeout) { + + if (lirc->gap) + return 0; + + lirc->gap_start = ktime_get(); + lirc->gap = true; + lirc->gap_duration = ev.duration; + + if (!lirc->send_timeout_reports) + return 0; + + sample = LIRC_TIMEOUT(ev.duration / 1000); + IR_dprintk(2, "timeout report (duration: %d)\n", sample); + + /* Normal sample */ + } else { + + if (lirc->gap) { + int gap_sample; + + lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), + lirc->gap_start)); + + /* Convert to ms and cap by LIRC_VALUE_MASK */ + do_div(lirc->gap_duration, 1000); + lirc->gap_duration = min(lirc->gap_duration, + (u64)LIRC_VALUE_MASK); + + gap_sample = LIRC_SPACE(lirc->gap_duration); + lirc_buffer_write(dev->raw->lirc.drv->rbuf, + (unsigned char *) &gap_sample); + lirc->gap = false; + } + + sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : + LIRC_SPACE(ev.duration / 1000); + IR_dprintk(2, "delivering %uus %s to lirc_dev\n", + TO_US(ev.duration), TO_STR(ev.pulse)); + } + + lirc_buffer_write(dev->raw->lirc.drv->rbuf, + (unsigned char *) &sample); + wake_up(&dev->raw->lirc.drv->rbuf->wait_poll); + + return 0; +} + +static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, + size_t n, loff_t *ppos) +{ + struct lirc_codec *lirc; + struct rc_dev *dev; + unsigned int *txbuf; /* buffer with values to transmit */ + ssize_t ret = 0; + size_t count; + + lirc = lirc_get_pdata(file); + if (!lirc) + return -EFAULT; + + if (n < sizeof(unsigned) || n % sizeof(unsigned)) + return -EINVAL; + + count = n / sizeof(unsigned); + if (count > LIRCBUF_SIZE || count % 2 == 0) + return -EINVAL; + + txbuf = memdup_user(buf, n); + if (IS_ERR(txbuf)) + return PTR_ERR(txbuf); + + dev = lirc->dev; + if (!dev) { + ret = -EFAULT; + goto out; + } + + if (dev->tx_ir) + ret = dev->tx_ir(dev, txbuf, count); + + if (ret > 0) + ret *= sizeof(unsigned); + +out: + kfree(txbuf); + return ret; +} + +static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, + unsigned long __user arg) +{ + struct lirc_codec *lirc; + struct rc_dev *dev; + int ret = 0; + __u32 val = 0, tmp; + + lirc = lirc_get_pdata(filep); + if (!lirc) + return -EFAULT; + + dev = lirc->dev; + if (!dev) + return -EFAULT; + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + ret = get_user(val, (__u32 *)arg); + if (ret) + return ret; + } + + switch (cmd) { + + /* legacy support */ + case LIRC_GET_SEND_MODE: + val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; + break; + + case LIRC_SET_SEND_MODE: + if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) + return -EINVAL; + return 0; + + /* TX settings */ + case LIRC_SET_TRANSMITTER_MASK: + if (!dev->s_tx_mask) + return -EINVAL; + + return dev->s_tx_mask(dev, val); + + case LIRC_SET_SEND_CARRIER: + if (!dev->s_tx_carrier) + return -EINVAL; + + return dev->s_tx_carrier(dev, val); + + case LIRC_SET_SEND_DUTY_CYCLE: + if (!dev->s_tx_duty_cycle) + return -ENOSYS; + + if (val <= 0 || val >= 100) + return -EINVAL; + + return dev->s_tx_duty_cycle(dev, val); + + /* RX settings */ + case LIRC_SET_REC_CARRIER: + if (!dev->s_rx_carrier_range) + return -ENOSYS; + + if (val <= 0) + return -EINVAL; + + return dev->s_rx_carrier_range(dev, + dev->raw->lirc.carrier_low, + val); + + case LIRC_SET_REC_CARRIER_RANGE: + if (val <= 0) + return -EINVAL; + + dev->raw->lirc.carrier_low = val; + return 0; + + case LIRC_GET_REC_RESOLUTION: + val = dev->rx_resolution; + break; + + case LIRC_SET_WIDEBAND_RECEIVER: + if (!dev->s_learning_mode) + return -ENOSYS; + + return dev->s_learning_mode(dev, !!val); + + case LIRC_SET_MEASURE_CARRIER_MODE: + if (!dev->s_carrier_report) + return -ENOSYS; + + return dev->s_carrier_report(dev, !!val); + + /* Generic timeout support */ + case LIRC_GET_MIN_TIMEOUT: + if (!dev->max_timeout) + return -ENOSYS; + val = dev->min_timeout / 1000; + break; + + case LIRC_GET_MAX_TIMEOUT: + if (!dev->max_timeout) + return -ENOSYS; + val = dev->max_timeout / 1000; + break; + + case LIRC_SET_REC_TIMEOUT: + if (!dev->max_timeout) + return -ENOSYS; + + tmp = val * 1000; + + if (tmp < dev->min_timeout || + tmp > dev->max_timeout) + return -EINVAL; + + dev->timeout = tmp; + break; + + case LIRC_SET_REC_TIMEOUT_REPORTS: + lirc->send_timeout_reports = !!val; + break; + + default: + return lirc_dev_fop_ioctl(filep, cmd, arg); + } + + if (_IOC_DIR(cmd) & _IOC_READ) + ret = put_user(val, (__u32 *)arg); + + return ret; +} + +static int ir_lirc_open(void *data) +{ + return 0; +} + +static void ir_lirc_close(void *data) +{ + return; +} + +static struct file_operations lirc_fops = { + .owner = THIS_MODULE, + .write = ir_lirc_transmit_ir, + .unlocked_ioctl = ir_lirc_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ir_lirc_ioctl, +#endif + .read = lirc_dev_fop_read, + .poll = lirc_dev_fop_poll, + .open = lirc_dev_fop_open, + .release = lirc_dev_fop_close, + .llseek = no_llseek, +}; + +static int ir_lirc_register(struct rc_dev *dev) +{ + struct lirc_driver *drv; + struct lirc_buffer *rbuf; + int rc = -ENOMEM; + unsigned long features; + + drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); + if (!drv) + return rc; + + rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); + if (!rbuf) + goto rbuf_alloc_failed; + + rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); + if (rc) + goto rbuf_init_failed; + + features = LIRC_CAN_REC_MODE2; + if (dev->tx_ir) { + features |= LIRC_CAN_SEND_PULSE; + if (dev->s_tx_mask) + features |= LIRC_CAN_SET_TRANSMITTER_MASK; + if (dev->s_tx_carrier) + features |= LIRC_CAN_SET_SEND_CARRIER; + if (dev->s_tx_duty_cycle) + features |= LIRC_CAN_SET_SEND_DUTY_CYCLE; + } + + if (dev->s_rx_carrier_range) + features |= LIRC_CAN_SET_REC_CARRIER | + LIRC_CAN_SET_REC_CARRIER_RANGE; + + if (dev->s_learning_mode) + features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; + + if (dev->s_carrier_report) + features |= LIRC_CAN_MEASURE_CARRIER; + + if (dev->max_timeout) + features |= LIRC_CAN_SET_REC_TIMEOUT; + + snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", + dev->driver_name); + drv->minor = -1; + drv->features = features; + drv->data = &dev->raw->lirc; + drv->rbuf = rbuf; + drv->set_use_inc = &ir_lirc_open; + drv->set_use_dec = &ir_lirc_close; + drv->code_length = sizeof(struct ir_raw_event) * 8; + drv->fops = &lirc_fops; + drv->dev = &dev->dev; + drv->owner = THIS_MODULE; + + drv->minor = lirc_register_driver(drv); + if (drv->minor < 0) { + rc = -ENODEV; + goto lirc_register_failed; + } + + dev->raw->lirc.drv = drv; + dev->raw->lirc.dev = dev; + return 0; + +lirc_register_failed: +rbuf_init_failed: + kfree(rbuf); +rbuf_alloc_failed: + kfree(drv); + + return rc; +} + +static int ir_lirc_unregister(struct rc_dev *dev) +{ + struct lirc_codec *lirc = &dev->raw->lirc; + + lirc_unregister_driver(lirc->drv->minor); + lirc_buffer_free(lirc->drv->rbuf); + kfree(lirc->drv); + + return 0; +} + +static struct ir_raw_handler lirc_handler = { + .protocols = RC_TYPE_LIRC, + .decode = ir_lirc_decode, + .raw_register = ir_lirc_register, + .raw_unregister = ir_lirc_unregister, +}; + +static int __init ir_lirc_codec_init(void) +{ + ir_raw_handler_register(&lirc_handler); + + printk(KERN_INFO "IR LIRC bridge handler initialized\n"); + return 0; +} + +static void __exit ir_lirc_codec_exit(void) +{ + ir_raw_handler_unregister(&lirc_handler); +} + +module_init(ir_lirc_codec_init); +module_exit(ir_lirc_codec_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson "); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("LIRC IR handler bridge"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-nec-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-nec-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-nec-decoder.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-nec-decoder.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,226 @@ +/* ir-nec-decoder.c - handle NEC IR Pulse/Space protocol + * + * Copyright (C) 2010 by Mauro Carvalho Chehab + * + * 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 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. + */ + +#include +#include "rc-core-priv.h" + +#define NEC_NBITS 32 +#define NEC_UNIT 562500 /* ns */ +#define NEC_HEADER_PULSE (16 * NEC_UNIT) +#define NECX_HEADER_PULSE (8 * NEC_UNIT) /* Less common NEC variant */ +#define NEC_HEADER_SPACE (8 * NEC_UNIT) +#define NEC_REPEAT_SPACE (4 * NEC_UNIT) +#define NEC_BIT_PULSE (1 * NEC_UNIT) +#define NEC_BIT_0_SPACE (1 * NEC_UNIT) +#define NEC_BIT_1_SPACE (3 * NEC_UNIT) +#define NEC_TRAILER_PULSE (1 * NEC_UNIT) +#define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */ +#define NECX_REPEAT_BITS 1 + +enum nec_state { + STATE_INACTIVE, + STATE_HEADER_SPACE, + STATE_BIT_PULSE, + STATE_BIT_SPACE, + STATE_TRAILER_PULSE, + STATE_TRAILER_SPACE, +}; + +/** + * ir_nec_decode() - Decode one NEC pulse or space + * @dev: the struct rc_dev descriptor of the device + * @duration: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct nec_dec *data = &dev->raw->nec; + u32 scancode; + u8 address, not_address, command, not_command; + bool send_32bits = false; + + if (!(dev->raw->enabled_protocols & RC_TYPE_NEC)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) { + data->is_nec_x = false; + data->necx_repeat = false; + } else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2)) + data->is_nec_x = true; + else + break; + + data->count = 0; + data->state = STATE_HEADER_SPACE; + return 0; + + case STATE_HEADER_SPACE: + if (ev.pulse) + break; + + if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) { + data->state = STATE_BIT_PULSE; + return 0; + } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) { + if (!dev->keypressed) { + IR_dprintk(1, "Discarding last key repeat: event after key up\n"); + } else { + rc_repeat(dev); + IR_dprintk(1, "Repeat last key\n"); + data->state = STATE_TRAILER_PULSE; + } + return 0; + } + + break; + + case STATE_BIT_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2)) + break; + + data->state = STATE_BIT_SPACE; + return 0; + + case STATE_BIT_SPACE: + if (ev.pulse) + break; + + if (data->necx_repeat && data->count == NECX_REPEAT_BITS && + geq_margin(ev.duration, + NEC_TRAILER_SPACE, NEC_UNIT / 2)) { + IR_dprintk(1, "Repeat last key\n"); + rc_repeat(dev); + data->state = STATE_INACTIVE; + return 0; + + } else if (data->count > NECX_REPEAT_BITS) + data->necx_repeat = false; + + data->bits <<= 1; + if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2)) + data->bits |= 1; + else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2)) + break; + data->count++; + + if (data->count == NEC_NBITS) + data->state = STATE_TRAILER_PULSE; + else + data->state = STATE_BIT_PULSE; + + return 0; + + case STATE_TRAILER_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2)) + break; + + data->state = STATE_TRAILER_SPACE; + return 0; + + case STATE_TRAILER_SPACE: + if (ev.pulse) + break; + + if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) + break; + + address = bitrev8((data->bits >> 24) & 0xff); + not_address = bitrev8((data->bits >> 16) & 0xff); + command = bitrev8((data->bits >> 8) & 0xff); + not_command = bitrev8((data->bits >> 0) & 0xff); + + if ((command ^ not_command) != 0xff) { + IR_dprintk(1, "NEC checksum error: received 0x%08x\n", + data->bits); + send_32bits = true; + } + + if (send_32bits) { + /* NEC transport, but modified protocol, used by at + * least Apple and TiVo remotes */ + scancode = data->bits; + IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode); + } else if ((address ^ not_address) != 0xff) { + /* Extended NEC */ + scancode = address << 16 | + not_address << 8 | + command; + IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode); + } else { + /* Normal NEC */ + scancode = address << 8 | command; + IR_dprintk(1, "NEC scancode 0x%04x\n", scancode); + } + + if (data->is_nec_x) + data->necx_repeat = true; + + rc_keydown(dev, scancode, 0); + data->state = STATE_INACTIVE; + return 0; + } + + IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler nec_handler = { + .protocols = RC_TYPE_NEC, + .decode = ir_nec_decode, +}; + +static int __init ir_nec_decode_init(void) +{ + ir_raw_handler_register(&nec_handler); + + printk(KERN_INFO "IR NEC protocol handler initialized\n"); + return 0; +} + +static void __exit ir_nec_decode_exit(void) +{ + ir_raw_handler_unregister(&nec_handler); +} + +module_init(ir_nec_decode_init); +module_exit(ir_nec_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("NEC IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-raw.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-raw.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-raw.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-raw.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,370 @@ +/* ir-raw.c - handle IR pulse/space events + * + * Copyright (C) 2010 by Mauro Carvalho Chehab + * + * 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 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. + */ + +#include +#include +#include +#include +#include "rc-core-priv.h" + +/* Define the max number of pulse/space transitions to buffer */ +#define MAX_IR_EVENT_SIZE 512 + +/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ +static LIST_HEAD(ir_raw_client_list); + +/* Used to handle IR raw handler extensions */ +static DEFINE_MUTEX(ir_raw_handler_lock); +static LIST_HEAD(ir_raw_handler_list); +static u64 available_protocols; + +#ifdef MODULE +/* Used to load the decoders */ +static struct work_struct wq_load; +#endif + +static int ir_raw_event_thread(void *data) +{ + struct ir_raw_event ev; + struct ir_raw_handler *handler; + struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; + int retval; + + while (!kthread_should_stop()) { + + spin_lock_irq(&raw->lock); + retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev)); + + if (!retval) { + set_current_state(TASK_INTERRUPTIBLE); + + if (kthread_should_stop()) + set_current_state(TASK_RUNNING); + + spin_unlock_irq(&raw->lock); + schedule(); + continue; + } + + spin_unlock_irq(&raw->lock); + + + BUG_ON(retval != sizeof(ev)); + + mutex_lock(&ir_raw_handler_lock); + list_for_each_entry(handler, &ir_raw_handler_list, list) + handler->decode(raw->dev, ev); + raw->prev_ev = ev; + mutex_unlock(&ir_raw_handler_lock); + } + + return 0; +} + +/** + * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders + * @dev: the struct rc_dev device descriptor + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This routine (which may be called from an interrupt context) stores a + * pulse/space duration for the raw ir decoding state machines. Pulses are + * signalled as positive values and spaces as negative values. A zero value + * will reset the decoding state machines. + */ +int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev) +{ + if (!dev->raw) + return -EINVAL; + + IR_dprintk(2, "sample: (%05dus %s)\n", + TO_US(ev->duration), TO_STR(ev->pulse)); + + if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(ir_raw_event_store); + +/** + * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space + * @dev: the struct rc_dev device descriptor + * @type: the type of the event that has occurred + * + * This routine (which may be called from an interrupt context) is used to + * store the beginning of an ir pulse or space (or the start/end of ir + * reception) for the raw ir decoding state machines. This is used by + * hardware which does not provide durations directly but only interrupts + * (or similar events) on state change. + */ +int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type) +{ + ktime_t now; + s64 delta; /* ns */ + DEFINE_IR_RAW_EVENT(ev); + int rc = 0; + + if (!dev->raw) + return -EINVAL; + + now = ktime_get(); + delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); + + /* Check for a long duration since last event or if we're + * being called for the first time, note that delta can't + * possibly be negative. + */ + if (delta > IR_MAX_DURATION || !dev->raw->last_type) + type |= IR_START_EVENT; + else + ev.duration = delta; + + if (type & IR_START_EVENT) + ir_raw_event_reset(dev); + else if (dev->raw->last_type & IR_SPACE) { + ev.pulse = false; + rc = ir_raw_event_store(dev, &ev); + } else if (dev->raw->last_type & IR_PULSE) { + ev.pulse = true; + rc = ir_raw_event_store(dev, &ev); + } else + return 0; + + dev->raw->last_event = now; + dev->raw->last_type = type; + return rc; +} +EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); + +/** + * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing + * @dev: the struct rc_dev device descriptor + * @type: the type of the event that has occurred + * + * This routine (which may be called from an interrupt context) works + * in similar manner to ir_raw_event_store_edge. + * This routine is intended for devices with limited internal buffer + * It automerges samples of same type, and handles timeouts + */ +int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev) +{ + if (!dev->raw) + return -EINVAL; + + /* Ignore spaces in idle mode */ + if (dev->idle && !ev->pulse) + return 0; + else if (dev->idle) + ir_raw_event_set_idle(dev, false); + + if (!dev->raw->this_ev.duration) + dev->raw->this_ev = *ev; + else if (ev->pulse == dev->raw->this_ev.pulse) + dev->raw->this_ev.duration += ev->duration; + else { + ir_raw_event_store(dev, &dev->raw->this_ev); + dev->raw->this_ev = *ev; + } + + /* Enter idle mode if nessesary */ + if (!ev->pulse && dev->timeout && + dev->raw->this_ev.duration >= dev->timeout) + ir_raw_event_set_idle(dev, true); + + return 0; +} +EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter); + +/** + * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not + * @dev: the struct rc_dev device descriptor + * @idle: whether the device is idle or not + */ +void ir_raw_event_set_idle(struct rc_dev *dev, bool idle) +{ + if (!dev->raw) + return; + + IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave"); + + if (idle) { + dev->raw->this_ev.timeout = true; + ir_raw_event_store(dev, &dev->raw->this_ev); + init_ir_raw_event(&dev->raw->this_ev); + } + + if (dev->s_idle) + dev->s_idle(dev, idle); + + dev->idle = idle; +} +EXPORT_SYMBOL_GPL(ir_raw_event_set_idle); + +/** + * ir_raw_event_handle() - schedules the decoding of stored ir data + * @dev: the struct rc_dev device descriptor + * + * This routine will tell rc-core to start decoding stored ir data. + */ +void ir_raw_event_handle(struct rc_dev *dev) +{ + unsigned long flags; + + if (!dev->raw) + return; + + spin_lock_irqsave(&dev->raw->lock, flags); + wake_up_process(dev->raw->thread); + spin_unlock_irqrestore(&dev->raw->lock, flags); +} +EXPORT_SYMBOL_GPL(ir_raw_event_handle); + +/* used internally by the sysfs interface */ +u64 +ir_raw_get_allowed_protocols(void) +{ + u64 protocols; + mutex_lock(&ir_raw_handler_lock); + protocols = available_protocols; + mutex_unlock(&ir_raw_handler_lock); + return protocols; +} + +/* + * Used to (un)register raw event clients + */ +int ir_raw_event_register(struct rc_dev *dev) +{ + int rc; + struct ir_raw_handler *handler; + + if (!dev) + return -EINVAL; + + dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL); + if (!dev->raw) + return -ENOMEM; + + dev->raw->dev = dev; + dev->raw->enabled_protocols = ~0; + rc = kfifo_alloc(&dev->raw->kfifo, + sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, + GFP_KERNEL); + if (rc < 0) + goto out; + + spin_lock_init(&dev->raw->lock); + dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, + "rc%ld", dev->devno); + + if (IS_ERR(dev->raw->thread)) { + rc = PTR_ERR(dev->raw->thread); + goto out; + } + + mutex_lock(&ir_raw_handler_lock); + list_add_tail(&dev->raw->list, &ir_raw_client_list); + list_for_each_entry(handler, &ir_raw_handler_list, list) + if (handler->raw_register) + handler->raw_register(dev); + mutex_unlock(&ir_raw_handler_lock); + + return 0; + +out: + kfree(dev->raw); + dev->raw = NULL; + return rc; +} + +void ir_raw_event_unregister(struct rc_dev *dev) +{ + struct ir_raw_handler *handler; + + if (!dev || !dev->raw) + return; + + kthread_stop(dev->raw->thread); + + mutex_lock(&ir_raw_handler_lock); + list_del(&dev->raw->list); + list_for_each_entry(handler, &ir_raw_handler_list, list) + if (handler->raw_unregister) + handler->raw_unregister(dev); + mutex_unlock(&ir_raw_handler_lock); + + kfifo_free(&dev->raw->kfifo); + kfree(dev->raw); + dev->raw = NULL; +} + +/* + * Extension interface - used to register the IR decoders + */ + +int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) +{ + struct ir_raw_event_ctrl *raw; + + mutex_lock(&ir_raw_handler_lock); + list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); + if (ir_raw_handler->raw_register) + list_for_each_entry(raw, &ir_raw_client_list, list) + ir_raw_handler->raw_register(raw->dev); + available_protocols |= ir_raw_handler->protocols; + mutex_unlock(&ir_raw_handler_lock); + + return 0; +} +EXPORT_SYMBOL(ir_raw_handler_register); + +void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) +{ + struct ir_raw_event_ctrl *raw; + + mutex_lock(&ir_raw_handler_lock); + list_del(&ir_raw_handler->list); + if (ir_raw_handler->raw_unregister) + list_for_each_entry(raw, &ir_raw_client_list, list) + ir_raw_handler->raw_unregister(raw->dev); + available_protocols &= ~ir_raw_handler->protocols; + mutex_unlock(&ir_raw_handler_lock); +} +EXPORT_SYMBOL(ir_raw_handler_unregister); + +#ifdef MODULE +static void init_decoders(struct work_struct *work) +{ + /* Load the decoder modules */ + + load_nec_decode(); + load_rc5_decode(); + load_rc6_decode(); + load_jvc_decode(); + load_sony_decode(); + load_lirc_codec(); + + /* If needed, we may later add some init code. In this case, + it is needed to change the CONFIG_MODULE test at rc-core.h + */ +} +#endif + +void ir_raw_init(void) +{ +#ifdef MODULE + INIT_WORK(&wq_load, init_decoders); + schedule_work(&wq_load); +#endif +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc5-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc5-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc5-decoder.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc5-decoder.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,189 @@ +/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol + * + * Copyright (C) 2010 by Mauro Carvalho Chehab + * + * 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 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. + */ + +/* + * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols. + * There are other variants that use a different number of bits. + * This is currently unsupported. + * It considers a carrier of 36 kHz, with a total of 14/20 bits, where + * the first two bits are start bits, and a third one is a filing bit + */ + +#include "rc-core-priv.h" + +#define RC5_NBITS 14 +#define RC5X_NBITS 20 +#define CHECK_RC5X_NBITS 8 +#define RC5_UNIT 888888 /* ns */ +#define RC5_BIT_START (1 * RC5_UNIT) +#define RC5_BIT_END (1 * RC5_UNIT) +#define RC5X_SPACE (4 * RC5_UNIT) + +enum rc5_state { + STATE_INACTIVE, + STATE_BIT_START, + STATE_BIT_END, + STATE_CHECK_RC5X, + STATE_FINISHED, +}; + +/** + * ir_rc5_decode() - Decode one RC-5 pulse or space + * @dev: the struct rc_dev descriptor of the device + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct rc5_dec *data = &dev->raw->rc5; + u8 toggle; + u32 scancode; + + if (!(dev->raw->enabled_protocols & RC_TYPE_RC5)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) + goto out; + +again: + IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) + return 0; + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + data->state = STATE_BIT_START; + data->count = 1; + /* We just need enough bits to get to STATE_CHECK_RC5X */ + data->wanted_bits = RC5X_NBITS; + decrease_duration(&ev, RC5_BIT_START); + goto again; + + case STATE_BIT_START: + if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) + break; + + data->bits <<= 1; + if (!ev.pulse) + data->bits |= 1; + data->count++; + data->state = STATE_BIT_END; + return 0; + + case STATE_BIT_END: + if (!is_transition(&ev, &dev->raw->prev_ev)) + break; + + if (data->count == data->wanted_bits) + data->state = STATE_FINISHED; + else if (data->count == CHECK_RC5X_NBITS) + data->state = STATE_CHECK_RC5X; + else + data->state = STATE_BIT_START; + + decrease_duration(&ev, RC5_BIT_END); + goto again; + + case STATE_CHECK_RC5X: + if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) { + /* RC5X */ + data->wanted_bits = RC5X_NBITS; + decrease_duration(&ev, RC5X_SPACE); + } else { + /* RC5 */ + data->wanted_bits = RC5_NBITS; + } + data->state = STATE_BIT_START; + goto again; + + case STATE_FINISHED: + if (ev.pulse) + break; + + if (data->wanted_bits == RC5X_NBITS) { + /* RC5X */ + u8 xdata, command, system; + xdata = (data->bits & 0x0003F) >> 0; + command = (data->bits & 0x00FC0) >> 6; + system = (data->bits & 0x1F000) >> 12; + toggle = (data->bits & 0x20000) ? 1 : 0; + command += (data->bits & 0x01000) ? 0 : 0x40; + scancode = system << 16 | command << 8 | xdata; + + IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n", + scancode, toggle); + + } else { + /* RC5 */ + u8 command, system; + command = (data->bits & 0x0003F) >> 0; + system = (data->bits & 0x007C0) >> 6; + toggle = (data->bits & 0x00800) ? 1 : 0; + command += (data->bits & 0x01000) ? 0 : 0x40; + scancode = system << 8 | command; + + IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n", + scancode, toggle); + } + + rc_keydown(dev, scancode, toggle); + data->state = STATE_INACTIVE; + return 0; + } + +out: + IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler rc5_handler = { + .protocols = RC_TYPE_RC5, + .decode = ir_rc5_decode, +}; + +static int __init ir_rc5_decode_init(void) +{ + ir_raw_handler_register(&rc5_handler); + + printk(KERN_INFO "IR RC5(x) protocol handler initialized\n"); + return 0; +} + +static void __exit ir_rc5_decode_exit(void) +{ + ir_raw_handler_unregister(&rc5_handler); +} + +module_init(ir_rc5_decode_init); +module_exit(ir_rc5_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("RC5(x) IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc5-sz-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc5-sz-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc5-sz-decoder.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc5-sz-decoder.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,153 @@ +/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol + * + * Copyright (C) 2010 by Mauro Carvalho Chehab + * Copyright (C) 2010 by Jarod Wilson + * + * 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 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. + */ + +/* + * This code handles the 15 bit RC5-ish protocol used by the Streamzap + * PC Remote. + * It considers a carrier of 36 kHz, with a total of 15 bits, where + * the first two bits are start bits, and a third one is a filing bit + */ + +#include "rc-core-priv.h" + +#define RC5_SZ_NBITS 15 +#define RC5_UNIT 888888 /* ns */ +#define RC5_BIT_START (1 * RC5_UNIT) +#define RC5_BIT_END (1 * RC5_UNIT) + +enum rc5_sz_state { + STATE_INACTIVE, + STATE_BIT_START, + STATE_BIT_END, + STATE_FINISHED, +}; + +/** + * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space + * @dev: the struct rc_dev descriptor of the device + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct rc5_sz_dec *data = &dev->raw->rc5_sz; + u8 toggle, command, system; + u32 scancode; + + if (!(dev->raw->enabled_protocols & RC_TYPE_RC5_SZ)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) + goto out; + +again: + IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) + return 0; + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + data->state = STATE_BIT_START; + data->count = 1; + data->wanted_bits = RC5_SZ_NBITS; + decrease_duration(&ev, RC5_BIT_START); + goto again; + + case STATE_BIT_START: + if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) + break; + + data->bits <<= 1; + if (!ev.pulse) + data->bits |= 1; + data->count++; + data->state = STATE_BIT_END; + return 0; + + case STATE_BIT_END: + if (!is_transition(&ev, &dev->raw->prev_ev)) + break; + + if (data->count == data->wanted_bits) + data->state = STATE_FINISHED; + else + data->state = STATE_BIT_START; + + decrease_duration(&ev, RC5_BIT_END); + goto again; + + case STATE_FINISHED: + if (ev.pulse) + break; + + /* RC5-sz */ + command = (data->bits & 0x0003F) >> 0; + system = (data->bits & 0x02FC0) >> 6; + toggle = (data->bits & 0x01000) ? 1 : 0; + scancode = system << 6 | command; + + IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n", + scancode, toggle); + + rc_keydown(dev, scancode, toggle); + data->state = STATE_INACTIVE; + return 0; + } + +out: + IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler rc5_sz_handler = { + .protocols = RC_TYPE_RC5_SZ, + .decode = ir_rc5_sz_decode, +}; + +static int __init ir_rc5_sz_decode_init(void) +{ + ir_raw_handler_register(&rc5_sz_handler); + + printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n"); + return 0; +} + +static void __exit ir_rc5_sz_decode_exit(void) +{ + ir_raw_handler_unregister(&rc5_sz_handler); +} + +module_init(ir_rc5_sz_decode_init); +module_exit(ir_rc5_sz_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson "); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc6-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc6-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc6-decoder.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-rc6-decoder.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,280 @@ +/* ir-rc6-decoder.c - A decoder for the RC6 IR protocol + * + * Copyright (C) 2010 by David Härdeman + * + * 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 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. + */ + +#include "rc-core-priv.h" + +/* + * This decoder currently supports: + * RC6-0-16 (standard toggle bit in header) + * RC6-6A-24 (no toggle bit) + * RC6-6A-32 (MCE version with toggle bit in body) + */ + +#define RC6_UNIT 444444 /* us */ +#define RC6_HEADER_NBITS 4 /* not including toggle bit */ +#define RC6_0_NBITS 16 +#define RC6_6A_SMALL_NBITS 24 +#define RC6_6A_LARGE_NBITS 32 +#define RC6_PREFIX_PULSE (6 * RC6_UNIT) +#define RC6_PREFIX_SPACE (2 * RC6_UNIT) +#define RC6_BIT_START (1 * RC6_UNIT) +#define RC6_BIT_END (1 * RC6_UNIT) +#define RC6_TOGGLE_START (2 * RC6_UNIT) +#define RC6_TOGGLE_END (2 * RC6_UNIT) +#define RC6_MODE_MASK 0x07 /* for the header bits */ +#define RC6_STARTBIT_MASK 0x08 /* for the header bits */ +#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ + +enum rc6_mode { + RC6_MODE_0, + RC6_MODE_6A, + RC6_MODE_UNKNOWN, +}; + +enum rc6_state { + STATE_INACTIVE, + STATE_PREFIX_SPACE, + STATE_HEADER_BIT_START, + STATE_HEADER_BIT_END, + STATE_TOGGLE_START, + STATE_TOGGLE_END, + STATE_BODY_BIT_START, + STATE_BODY_BIT_END, + STATE_FINISHED, +}; + +static enum rc6_mode rc6_mode(struct rc6_dec *data) +{ + switch (data->header & RC6_MODE_MASK) { + case 0: + return RC6_MODE_0; + case 6: + if (!data->toggle) + return RC6_MODE_6A; + /* fall through */ + default: + return RC6_MODE_UNKNOWN; + } +} + +/** + * ir_rc6_decode() - Decode one RC6 pulse or space + * @dev: the struct rc_dev descriptor of the device + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct rc6_dec *data = &dev->raw->rc6; + u32 scancode; + u8 toggle; + + if (!(dev->raw->enabled_protocols & RC_TYPE_RC6)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) + goto out; + +again: + IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) + return 0; + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + /* Note: larger margin on first pulse since each RC6_UNIT + is quite short and some hardware takes some time to + adjust to the signal */ + if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT)) + break; + + data->state = STATE_PREFIX_SPACE; + data->count = 0; + return 0; + + case STATE_PREFIX_SPACE: + if (ev.pulse) + break; + + if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2)) + break; + + data->state = STATE_HEADER_BIT_START; + return 0; + + case STATE_HEADER_BIT_START: + if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) + break; + + data->header <<= 1; + if (ev.pulse) + data->header |= 1; + data->count++; + data->state = STATE_HEADER_BIT_END; + return 0; + + case STATE_HEADER_BIT_END: + if (!is_transition(&ev, &dev->raw->prev_ev)) + break; + + if (data->count == RC6_HEADER_NBITS) + data->state = STATE_TOGGLE_START; + else + data->state = STATE_HEADER_BIT_START; + + decrease_duration(&ev, RC6_BIT_END); + goto again; + + case STATE_TOGGLE_START: + if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2)) + break; + + data->toggle = ev.pulse; + data->state = STATE_TOGGLE_END; + return 0; + + case STATE_TOGGLE_END: + if (!is_transition(&ev, &dev->raw->prev_ev) || + !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2)) + break; + + if (!(data->header & RC6_STARTBIT_MASK)) { + IR_dprintk(1, "RC6 invalid start bit\n"); + break; + } + + data->state = STATE_BODY_BIT_START; + decrease_duration(&ev, RC6_TOGGLE_END); + data->count = 0; + + switch (rc6_mode(data)) { + case RC6_MODE_0: + data->wanted_bits = RC6_0_NBITS; + break; + case RC6_MODE_6A: + /* This might look weird, but we basically + check the value of the first body bit to + determine the number of bits in mode 6A */ + if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) || + geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) + data->wanted_bits = RC6_6A_LARGE_NBITS; + else + data->wanted_bits = RC6_6A_SMALL_NBITS; + break; + default: + IR_dprintk(1, "RC6 unknown mode\n"); + goto out; + } + goto again; + + case STATE_BODY_BIT_START: + if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) + break; + + data->body <<= 1; + if (ev.pulse) + data->body |= 1; + data->count++; + data->state = STATE_BODY_BIT_END; + return 0; + + case STATE_BODY_BIT_END: + if (!is_transition(&ev, &dev->raw->prev_ev)) + break; + + if (data->count == data->wanted_bits) + data->state = STATE_FINISHED; + else + data->state = STATE_BODY_BIT_START; + + decrease_duration(&ev, RC6_BIT_END); + goto again; + + case STATE_FINISHED: + if (ev.pulse) + break; + + switch (rc6_mode(data)) { + case RC6_MODE_0: + scancode = data->body & 0xffff; + toggle = data->toggle; + IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", + scancode, toggle); + break; + case RC6_MODE_6A: + if (data->wanted_bits == RC6_6A_LARGE_NBITS) { + toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0; + scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK; + } else { + toggle = 0; + scancode = data->body & 0xffffff; + } + + IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n", + scancode, toggle); + break; + default: + IR_dprintk(1, "RC6 unknown mode\n"); + goto out; + } + + rc_keydown(dev, scancode, toggle); + data->state = STATE_INACTIVE; + return 0; + } + +out: + IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler rc6_handler = { + .protocols = RC_TYPE_RC6, + .decode = ir_rc6_decode, +}; + +static int __init ir_rc6_decode_init(void) +{ + ir_raw_handler_register(&rc6_handler); + + printk(KERN_INFO "IR RC6 protocol handler initialized\n"); + return 0; +} + +static void __exit ir_rc6_decode_exit(void) +{ + ir_raw_handler_unregister(&rc6_handler); +} + +module_init(ir_rc6_decode_init); +module_exit(ir_rc6_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Härdeman "); +MODULE_DESCRIPTION("RC6 IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-sony-decoder.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-sony-decoder.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-sony-decoder.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ir-sony-decoder.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,181 @@ +/* ir-sony-decoder.c - handle Sony IR Pulse/Space protocol + * + * Copyright (C) 2010 by David Härdeman + * + * 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 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. + */ + +#include +#include "rc-core-priv.h" + +#define SONY_UNIT 600000 /* ns */ +#define SONY_HEADER_PULSE (4 * SONY_UNIT) +#define SONY_HEADER_SPACE (1 * SONY_UNIT) +#define SONY_BIT_0_PULSE (1 * SONY_UNIT) +#define SONY_BIT_1_PULSE (2 * SONY_UNIT) +#define SONY_BIT_SPACE (1 * SONY_UNIT) +#define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */ + +enum sony_state { + STATE_INACTIVE, + STATE_HEADER_SPACE, + STATE_BIT_PULSE, + STATE_BIT_SPACE, + STATE_FINISHED, +}; + +/** + * ir_sony_decode() - Decode one Sony pulse or space + * @dev: the struct rc_dev descriptor of the device + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct sony_dec *data = &dev->raw->sony; + u32 scancode; + u8 device, subdevice, function; + + if (!(dev->raw->enabled_protocols & RC_TYPE_SONY)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) + goto out; + + IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2)) + break; + + data->count = 0; + data->state = STATE_HEADER_SPACE; + return 0; + + case STATE_HEADER_SPACE: + if (ev.pulse) + break; + + if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2)) + break; + + data->state = STATE_BIT_PULSE; + return 0; + + case STATE_BIT_PULSE: + if (!ev.pulse) + break; + + data->bits <<= 1; + if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2)) + data->bits |= 1; + else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2)) + break; + + data->count++; + data->state = STATE_BIT_SPACE; + return 0; + + case STATE_BIT_SPACE: + if (ev.pulse) + break; + + if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2)) + break; + + decrease_duration(&ev, SONY_BIT_SPACE); + + if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) { + data->state = STATE_BIT_PULSE; + return 0; + } + + data->state = STATE_FINISHED; + /* Fall through */ + + case STATE_FINISHED: + if (ev.pulse) + break; + + if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2)) + break; + + switch (data->count) { + case 12: + device = bitrev8((data->bits << 3) & 0xF8); + subdevice = 0; + function = bitrev8((data->bits >> 4) & 0xFE); + break; + case 15: + device = bitrev8((data->bits >> 0) & 0xFF); + subdevice = 0; + function = bitrev8((data->bits >> 7) & 0xFD); + break; + case 20: + device = bitrev8((data->bits >> 5) & 0xF8); + subdevice = bitrev8((data->bits >> 0) & 0xFF); + function = bitrev8((data->bits >> 12) & 0xFE); + break; + default: + IR_dprintk(1, "Sony invalid bitcount %u\n", data->count); + goto out; + } + + scancode = device << 16 | subdevice << 8 | function; + IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode); + rc_keydown(dev, scancode, 0); + data->state = STATE_INACTIVE; + return 0; + } + +out: + IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler sony_handler = { + .protocols = RC_TYPE_SONY, + .decode = ir_sony_decode, +}; + +static int __init ir_sony_decode_init(void) +{ + ir_raw_handler_register(&sony_handler); + + printk(KERN_INFO "IR Sony protocol handler initialized\n"); + return 0; +} + +static void __exit ir_sony_decode_exit(void) +{ + ir_raw_handler_unregister(&sony_handler); +} + +module_init(ir_sony_decode_init); +module_exit(ir_sony_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Härdeman "); +MODULE_DESCRIPTION("Sony IR protocol decoder"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ite-cir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ite-cir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ite-cir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ite-cir.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1725 @@ +/* + * Driver for ITE Tech Inc. IT8712F/IT8512 CIR + * + * Copyright (C) 2010 Juan Jesús García de Soria + * + * 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, or (at your option) any later version. + * + * 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. + * + * Inspired by the original lirc_it87 and lirc_ite8709 drivers, on top of the + * skeleton provided by the nuvoton-cir driver. + * + * The lirc_it87 driver was originally written by Hans-Gunter Lutke Uphues + * in 2001, with enhancements by Christoph Bartelmus + * , Andrew Calkin and James Edwards + * . + * + * The lirc_ite8709 driver was written by Grégory Lardière + * in 2008. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ite-cir.h" + +/* module parameters */ + +/* debug level */ +static int debug; +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging output"); + +/* low limit for RX carrier freq, Hz, 0 for no RX demodulation */ +static int rx_low_carrier_freq; +module_param(rx_low_carrier_freq, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, " + "0 for no RX demodulation"); + +/* high limit for RX carrier freq, Hz, 0 for no RX demodulation */ +static int rx_high_carrier_freq; +module_param(rx_high_carrier_freq, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, " + "Hz, 0 for no RX demodulation"); + +/* override tx carrier frequency */ +static int tx_carrier_freq; +module_param(tx_carrier_freq, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(tx_carrier_freq, "Override TX carrier frequency, Hz"); + +/* override tx duty cycle */ +static int tx_duty_cycle; +module_param(tx_duty_cycle, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(tx_duty_cycle, "Override TX duty cycle, 1-100"); + +/* override default sample period */ +static long sample_period; +module_param(sample_period, long, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(sample_period, "Override carrier sample period, us"); + +/* override detected model id */ +static int model_number = -1; +module_param(model_number, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(model_number, "Use this model number, don't autodetect"); + + +/* HW-independent code functions */ + +/* check whether carrier frequency is high frequency */ +static inline bool ite_is_high_carrier_freq(unsigned int freq) +{ + return freq >= ITE_HCF_MIN_CARRIER_FREQ; +} + +/* get the bits required to program the carrier frequency in CFQ bits, + * unshifted */ +static u8 ite_get_carrier_freq_bits(unsigned int freq) +{ + if (ite_is_high_carrier_freq(freq)) { + if (freq < 425000) + return ITE_CFQ_400; + + else if (freq < 465000) + return ITE_CFQ_450; + + else if (freq < 490000) + return ITE_CFQ_480; + + else + return ITE_CFQ_500; + } else { + /* trim to limits */ + if (freq < ITE_LCF_MIN_CARRIER_FREQ) + freq = ITE_LCF_MIN_CARRIER_FREQ; + if (freq > ITE_LCF_MAX_CARRIER_FREQ) + freq = ITE_LCF_MAX_CARRIER_FREQ; + + /* convert to kHz and subtract the base freq */ + freq = + DIV_ROUND_CLOSEST(freq - ITE_LCF_MIN_CARRIER_FREQ, + 1000); + + return (u8) freq; + } +} + +/* get the bits required to program the pulse with in TXMPW */ +static u8 ite_get_pulse_width_bits(unsigned int freq, int duty_cycle) +{ + unsigned long period_ns, on_ns; + + /* sanitize freq into range */ + if (freq < ITE_LCF_MIN_CARRIER_FREQ) + freq = ITE_LCF_MIN_CARRIER_FREQ; + if (freq > ITE_HCF_MAX_CARRIER_FREQ) + freq = ITE_HCF_MAX_CARRIER_FREQ; + + period_ns = 1000000000UL / freq; + on_ns = period_ns * duty_cycle / 100; + + if (ite_is_high_carrier_freq(freq)) { + if (on_ns < 750) + return ITE_TXMPW_A; + + else if (on_ns < 850) + return ITE_TXMPW_B; + + else if (on_ns < 950) + return ITE_TXMPW_C; + + else if (on_ns < 1080) + return ITE_TXMPW_D; + + else + return ITE_TXMPW_E; + } else { + if (on_ns < 6500) + return ITE_TXMPW_A; + + else if (on_ns < 7850) + return ITE_TXMPW_B; + + else if (on_ns < 9650) + return ITE_TXMPW_C; + + else if (on_ns < 11950) + return ITE_TXMPW_D; + + else + return ITE_TXMPW_E; + } +} + +/* decode raw bytes as received by the hardware, and push them to the ir-core + * layer */ +static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int + length) +{ + u32 sample_period; + unsigned long *ldata; + unsigned int next_one, next_zero, size; + DEFINE_IR_RAW_EVENT(ev); + + if (length == 0) + return; + + sample_period = dev->params.sample_period; + ldata = (unsigned long *)data; + size = length << 3; + next_one = find_next_bit_le(ldata, size, 0); + if (next_one > 0) { + ev.pulse = true; + ev.duration = + ITE_BITS_TO_NS(next_one, sample_period); + ir_raw_event_store_with_filter(dev->rdev, &ev); + } + + while (next_one < size) { + next_zero = find_next_zero_bit_le(ldata, size, next_one + 1); + ev.pulse = false; + ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period); + ir_raw_event_store_with_filter(dev->rdev, &ev); + + if (next_zero < size) { + next_one = + find_next_bit_le(ldata, + size, + next_zero + 1); + ev.pulse = true; + ev.duration = + ITE_BITS_TO_NS(next_one - next_zero, + sample_period); + ir_raw_event_store_with_filter + (dev->rdev, &ev); + } else + next_one = size; + } + + ir_raw_event_handle(dev->rdev); + + ite_dbg_verbose("decoded %d bytes.", length); +} + +/* set all the rx/tx carrier parameters; this must be called with the device + * spinlock held */ +static void ite_set_carrier_params(struct ite_dev *dev) +{ + unsigned int freq, low_freq, high_freq; + int allowance; + bool use_demodulator; + bool for_tx = dev->transmitting; + + ite_dbg("%s called", __func__); + + if (for_tx) { + /* we don't need no stinking calculations */ + freq = dev->params.tx_carrier_freq; + allowance = ITE_RXDCR_DEFAULT; + use_demodulator = false; + } else { + low_freq = dev->params.rx_low_carrier_freq; + high_freq = dev->params.rx_high_carrier_freq; + + if (low_freq == 0) { + /* don't demodulate */ + freq = + ITE_DEFAULT_CARRIER_FREQ; + allowance = ITE_RXDCR_DEFAULT; + use_demodulator = false; + } else { + /* calculate the middle freq */ + freq = (low_freq + high_freq) / 2; + + /* calculate the allowance */ + allowance = + DIV_ROUND_CLOSEST(10000 * (high_freq - low_freq), + ITE_RXDCR_PER_10000_STEP + * (high_freq + low_freq)); + + if (allowance < 1) + allowance = 1; + + if (allowance > ITE_RXDCR_MAX) + allowance = ITE_RXDCR_MAX; + } + } + + /* set the carrier parameters in a device-dependent way */ + dev->params.set_carrier_params(dev, ite_is_high_carrier_freq(freq), + use_demodulator, ite_get_carrier_freq_bits(freq), allowance, + ite_get_pulse_width_bits(freq, dev->params.tx_duty_cycle)); +} + +/* interrupt service routine for incoming and outgoing CIR data */ +static irqreturn_t ite_cir_isr(int irq, void *data) +{ + struct ite_dev *dev = data; + unsigned long flags; + irqreturn_t ret = IRQ_RETVAL(IRQ_NONE); + u8 rx_buf[ITE_RX_FIFO_LEN]; + int rx_bytes; + int iflags; + + ite_dbg_verbose("%s firing", __func__); + + /* grab the spinlock */ + spin_lock_irqsave(&dev->lock, flags); + + /* read the interrupt flags */ + iflags = dev->params.get_irq_causes(dev); + + /* check for the receive interrupt */ + if (iflags & (ITE_IRQ_RX_FIFO | ITE_IRQ_RX_FIFO_OVERRUN)) { + /* read the FIFO bytes */ + rx_bytes = + dev->params.get_rx_bytes(dev, rx_buf, + ITE_RX_FIFO_LEN); + + if (rx_bytes > 0) { + /* drop the spinlock, since the ir-core layer + * may call us back again through + * ite_s_idle() */ + spin_unlock_irqrestore(&dev-> + lock, + flags); + + /* decode the data we've just received */ + ite_decode_bytes(dev, rx_buf, + rx_bytes); + + /* reacquire the spinlock */ + spin_lock_irqsave(&dev->lock, + flags); + + /* mark the interrupt as serviced */ + ret = IRQ_RETVAL(IRQ_HANDLED); + } + } else if (iflags & ITE_IRQ_TX_FIFO) { + /* FIFO space available interrupt */ + ite_dbg_verbose("got interrupt for TX FIFO"); + + /* wake any sleeping transmitter */ + wake_up_interruptible(&dev->tx_queue); + + /* mark the interrupt as serviced */ + ret = IRQ_RETVAL(IRQ_HANDLED); + } + + /* drop the spinlock */ + spin_unlock_irqrestore(&dev->lock, flags); + + ite_dbg_verbose("%s done returning %d", __func__, (int)ret); + + return ret; +} + +/* set the rx carrier freq range, guess it's in Hz... */ +static int ite_set_rx_carrier_range(struct rc_dev *rcdev, u32 carrier_low, u32 + carrier_high) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + + spin_lock_irqsave(&dev->lock, flags); + dev->params.rx_low_carrier_freq = carrier_low; + dev->params.rx_high_carrier_freq = carrier_high; + ite_set_carrier_params(dev); + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* set the tx carrier freq, guess it's in Hz... */ +static int ite_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + + spin_lock_irqsave(&dev->lock, flags); + dev->params.tx_carrier_freq = carrier; + ite_set_carrier_params(dev); + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* set the tx duty cycle by controlling the pulse width */ +static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + + spin_lock_irqsave(&dev->lock, flags); + dev->params.tx_duty_cycle = duty_cycle; + ite_set_carrier_params(dev); + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* transmit out IR pulses; what you get here is a batch of alternating + * pulse/space/pulse/space lengths that we should write out completely through + * the FIFO, blocking on a full FIFO */ +static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + bool is_pulse = false; + int remaining_us, fifo_avail, fifo_remaining, last_idx = 0; + int max_rle_us, next_rle_us; + int ret = n; + u8 last_sent[ITE_TX_FIFO_LEN]; + u8 val; + + ite_dbg("%s called", __func__); + + /* clear the array just in case */ + memset(last_sent, 0, ARRAY_SIZE(last_sent)); + + spin_lock_irqsave(&dev->lock, flags); + + /* let everybody know we're now transmitting */ + dev->transmitting = true; + + /* and set the carrier values for transmission */ + ite_set_carrier_params(dev); + + /* calculate how much time we can send in one byte */ + max_rle_us = + (ITE_BAUDRATE_DIVISOR * dev->params.sample_period * + ITE_TX_MAX_RLE) / 1000; + + /* disable the receiver */ + dev->params.disable_rx(dev); + + /* this is where we'll begin filling in the FIFO, until it's full. + * then we'll just activate the interrupt, wait for it to wake us up + * again, disable it, continue filling the FIFO... until everything + * has been pushed out */ + fifo_avail = + ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); + + while (n > 0 && dev->in_use) { + /* transmit the next sample */ + is_pulse = !is_pulse; + remaining_us = *(txbuf++); + n--; + + ite_dbg("%s: %ld", + ((is_pulse) ? "pulse" : "space"), + (long int) + remaining_us); + + /* repeat while the pulse is non-zero length */ + while (remaining_us > 0 && dev->in_use) { + if (remaining_us > max_rle_us) + next_rle_us = max_rle_us; + + else + next_rle_us = remaining_us; + + remaining_us -= next_rle_us; + + /* check what's the length we have to pump out */ + val = (ITE_TX_MAX_RLE * next_rle_us) / max_rle_us; + + /* put it into the sent buffer */ + last_sent[last_idx++] = val; + last_idx &= (ITE_TX_FIFO_LEN); + + /* encode it for 7 bits */ + val = (val - 1) & ITE_TX_RLE_MASK; + + /* take into account pulse/space prefix */ + if (is_pulse) + val |= ITE_TX_PULSE; + + else + val |= ITE_TX_SPACE; + + /* + * if we get to 0 available, read again, just in case + * some other slot got freed + */ + if (fifo_avail <= 0) + fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); + + /* if it's still full */ + if (fifo_avail <= 0) { + /* enable the tx interrupt */ + dev->params. + enable_tx_interrupt(dev); + + /* drop the spinlock */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* wait for the FIFO to empty enough */ + wait_event_interruptible(dev->tx_queue, (fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev)) >= 8); + + /* get the spinlock again */ + spin_lock_irqsave(&dev->lock, flags); + + /* disable the tx interrupt again. */ + dev->params. + disable_tx_interrupt(dev); + } + + /* now send the byte through the FIFO */ + dev->params.put_tx_byte(dev, val); + fifo_avail--; + } + } + + /* wait and don't return until the whole FIFO has been sent out; + * otherwise we could configure the RX carrier params instead of the + * TX ones while the transmission is still being performed! */ + fifo_remaining = dev->params.get_tx_used_slots(dev); + remaining_us = 0; + while (fifo_remaining > 0) { + fifo_remaining--; + last_idx--; + last_idx &= (ITE_TX_FIFO_LEN - 1); + remaining_us += last_sent[last_idx]; + } + remaining_us = (remaining_us * max_rle_us) / (ITE_TX_MAX_RLE); + + /* drop the spinlock while we sleep */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* sleep remaining_us microseconds */ + mdelay(DIV_ROUND_UP(remaining_us, 1000)); + + /* reacquire the spinlock */ + spin_lock_irqsave(&dev->lock, flags); + + /* now we're not transmitting anymore */ + dev->transmitting = false; + + /* and set the carrier values for reception */ + ite_set_carrier_params(dev); + + /* reenable the receiver */ + if (dev->in_use) + dev->params.enable_rx(dev); + + /* notify transmission end */ + wake_up_interruptible(&dev->tx_ended); + + spin_unlock_irqrestore(&dev->lock, flags); + + return ret; +} + +/* idle the receiver if needed */ +static void ite_s_idle(struct rc_dev *rcdev, bool enable) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + + ite_dbg("%s called", __func__); + + if (enable) { + spin_lock_irqsave(&dev->lock, flags); + dev->params.idle_rx(dev); + spin_unlock_irqrestore(&dev->lock, flags); + } +} + + +/* IT8712F HW-specific functions */ + +/* retrieve a bitmask of the current causes for a pending interrupt; this may + * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN + * */ +static int it87_get_irq_causes(struct ite_dev *dev) +{ + u8 iflags; + int ret = 0; + + ite_dbg("%s called", __func__); + + /* read the interrupt flags */ + iflags = inb(dev->cir_addr + IT87_IIR) & IT87_II; + + switch (iflags) { + case IT87_II_RXDS: + ret = ITE_IRQ_RX_FIFO; + break; + case IT87_II_RXFO: + ret = ITE_IRQ_RX_FIFO_OVERRUN; + break; + case IT87_II_TXLDL: + ret = ITE_IRQ_TX_FIFO; + break; + } + + return ret; +} + +/* set the carrier parameters; to be called with the spinlock held */ +static void it87_set_carrier_params(struct ite_dev *dev, bool high_freq, + bool use_demodulator, + u8 carrier_freq_bits, u8 allowance_bits, + u8 pulse_width_bits) +{ + u8 val; + + ite_dbg("%s called", __func__); + + /* program the RCR register */ + val = inb(dev->cir_addr + IT87_RCR) + & ~(IT87_HCFS | IT87_RXEND | IT87_RXDCR); + + if (high_freq) + val |= IT87_HCFS; + + if (use_demodulator) + val |= IT87_RXEND; + + val |= allowance_bits; + + outb(val, dev->cir_addr + IT87_RCR); + + /* program the TCR2 register */ + outb((carrier_freq_bits << IT87_CFQ_SHIFT) | pulse_width_bits, + dev->cir_addr + IT87_TCR2); +} + +/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock + * held */ +static int it87_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) +{ + int fifo, read = 0; + + ite_dbg("%s called", __func__); + + /* read how many bytes are still in the FIFO */ + fifo = inb(dev->cir_addr + IT87_RSR) & IT87_RXFBC; + + while (fifo > 0 && buf_size > 0) { + *(buf++) = inb(dev->cir_addr + IT87_DR); + fifo--; + read++; + buf_size--; + } + + return read; +} + +/* return how many bytes are still in the FIFO; this will be called + * with the device spinlock NOT HELD while waiting for the TX FIFO to get + * empty; let's expect this won't be a problem */ +static int it87_get_tx_used_slots(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + return inb(dev->cir_addr + IT87_TSR) & IT87_TXFBC; +} + +/* put a byte to the TX fifo; this should be called with the spinlock held */ +static void it87_put_tx_byte(struct ite_dev *dev, u8 value) +{ + outb(value, dev->cir_addr + IT87_DR); +} + +/* idle the receiver so that we won't receive samples until another + pulse is detected; this must be called with the device spinlock held */ +static void it87_idle_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable streaming by clearing RXACT writing it as 1 */ + outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXACT, + dev->cir_addr + IT87_RCR); + + /* clear the FIFO */ + outb(inb(dev->cir_addr + IT87_TCR1) | IT87_FIFOCLR, + dev->cir_addr + IT87_TCR1); +} + +/* disable the receiver; this must be called with the device spinlock held */ +static void it87_disable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the receiver interrupts */ + outb(inb(dev->cir_addr + IT87_IER) & ~(IT87_RDAIE | IT87_RFOIE), + dev->cir_addr + IT87_IER); + + /* disable the receiver */ + outb(inb(dev->cir_addr + IT87_RCR) & ~IT87_RXEN, + dev->cir_addr + IT87_RCR); + + /* clear the FIFO and RXACT (actually RXACT should have been cleared + * in the previous outb() call) */ + it87_idle_rx(dev); +} + +/* enable the receiver; this must be called with the device spinlock held */ +static void it87_enable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the receiver by setting RXEN */ + outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXEN, + dev->cir_addr + IT87_RCR); + + /* just prepare it to idle for the next reception */ + it87_idle_rx(dev); + + /* enable the receiver interrupts and master enable flag */ + outb(inb(dev->cir_addr + IT87_IER) | IT87_RDAIE | IT87_RFOIE | IT87_IEC, + dev->cir_addr + IT87_IER); +} + +/* disable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it87_disable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the transmitter interrupts */ + outb(inb(dev->cir_addr + IT87_IER) & ~IT87_TLDLIE, + dev->cir_addr + IT87_IER); +} + +/* enable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it87_enable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the transmitter interrupts and master enable flag */ + outb(inb(dev->cir_addr + IT87_IER) | IT87_TLDLIE | IT87_IEC, + dev->cir_addr + IT87_IER); +} + +/* disable the device; this must be called with the device spinlock held */ +static void it87_disable(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* clear out all interrupt enable flags */ + outb(inb(dev->cir_addr + IT87_IER) & + ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE), + dev->cir_addr + IT87_IER); + + /* disable the receiver */ + it87_disable_rx(dev); + + /* erase the FIFO */ + outb(IT87_FIFOCLR | inb(dev->cir_addr + IT87_TCR1), + dev->cir_addr + IT87_TCR1); +} + +/* initialize the hardware */ +static void it87_init_hardware(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable just the baud rate divisor register, + disabling all the interrupts at the same time */ + outb((inb(dev->cir_addr + IT87_IER) & + ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE)) | IT87_BR, + dev->cir_addr + IT87_IER); + + /* write out the baud rate divisor */ + outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT87_BDLR); + outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff, dev->cir_addr + IT87_BDHR); + + /* disable the baud rate divisor register again */ + outb(inb(dev->cir_addr + IT87_IER) & ~IT87_BR, + dev->cir_addr + IT87_IER); + + /* program the RCR register defaults */ + outb(ITE_RXDCR_DEFAULT, dev->cir_addr + IT87_RCR); + + /* program the TCR1 register */ + outb(IT87_TXMPM_DEFAULT | IT87_TXENDF | IT87_TXRLE + | IT87_FIFOTL_DEFAULT | IT87_FIFOCLR, + dev->cir_addr + IT87_TCR1); + + /* program the carrier parameters */ + ite_set_carrier_params(dev); +} + +/* IT8512F on ITE8708 HW-specific functions */ + +/* retrieve a bitmask of the current causes for a pending interrupt; this may + * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN + * */ +static int it8708_get_irq_causes(struct ite_dev *dev) +{ + u8 iflags; + int ret = 0; + + ite_dbg("%s called", __func__); + + /* read the interrupt flags */ + iflags = inb(dev->cir_addr + IT8708_C0IIR); + + if (iflags & IT85_TLDLI) + ret |= ITE_IRQ_TX_FIFO; + if (iflags & IT85_RDAI) + ret |= ITE_IRQ_RX_FIFO; + if (iflags & IT85_RFOI) + ret |= ITE_IRQ_RX_FIFO_OVERRUN; + + return ret; +} + +/* set the carrier parameters; to be called with the spinlock held */ +static void it8708_set_carrier_params(struct ite_dev *dev, bool high_freq, + bool use_demodulator, + u8 carrier_freq_bits, u8 allowance_bits, + u8 pulse_width_bits) +{ + u8 val; + + ite_dbg("%s called", __func__); + + /* program the C0CFR register, with HRAE=1 */ + outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE, + dev->cir_addr + IT8708_BANKSEL); + + val = (inb(dev->cir_addr + IT8708_C0CFR) + & ~(IT85_HCFS | IT85_CFQ)) | carrier_freq_bits; + + if (high_freq) + val |= IT85_HCFS; + + outb(val, dev->cir_addr + IT8708_C0CFR); + + outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE, + dev->cir_addr + IT8708_BANKSEL); + + /* program the C0RCR register */ + val = inb(dev->cir_addr + IT8708_C0RCR) + & ~(IT85_RXEND | IT85_RXDCR); + + if (use_demodulator) + val |= IT85_RXEND; + + val |= allowance_bits; + + outb(val, dev->cir_addr + IT8708_C0RCR); + + /* program the C0TCR register */ + val = inb(dev->cir_addr + IT8708_C0TCR) & ~IT85_TXMPW; + val |= pulse_width_bits; + outb(val, dev->cir_addr + IT8708_C0TCR); +} + +/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock + * held */ +static int it8708_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) +{ + int fifo, read = 0; + + ite_dbg("%s called", __func__); + + /* read how many bytes are still in the FIFO */ + fifo = inb(dev->cir_addr + IT8708_C0RFSR) & IT85_RXFBC; + + while (fifo > 0 && buf_size > 0) { + *(buf++) = inb(dev->cir_addr + IT8708_C0DR); + fifo--; + read++; + buf_size--; + } + + return read; +} + +/* return how many bytes are still in the FIFO; this will be called + * with the device spinlock NOT HELD while waiting for the TX FIFO to get + * empty; let's expect this won't be a problem */ +static int it8708_get_tx_used_slots(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + return inb(dev->cir_addr + IT8708_C0TFSR) & IT85_TXFBC; +} + +/* put a byte to the TX fifo; this should be called with the spinlock held */ +static void it8708_put_tx_byte(struct ite_dev *dev, u8 value) +{ + outb(value, dev->cir_addr + IT8708_C0DR); +} + +/* idle the receiver so that we won't receive samples until another + pulse is detected; this must be called with the device spinlock held */ +static void it8708_idle_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable streaming by clearing RXACT writing it as 1 */ + outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXACT, + dev->cir_addr + IT8708_C0RCR); + + /* clear the FIFO */ + outb(inb(dev->cir_addr + IT8708_C0MSTCR) | IT85_FIFOCLR, + dev->cir_addr + IT8708_C0MSTCR); +} + +/* disable the receiver; this must be called with the device spinlock held */ +static void it8708_disable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the receiver interrupts */ + outb(inb(dev->cir_addr + IT8708_C0IER) & + ~(IT85_RDAIE | IT85_RFOIE), + dev->cir_addr + IT8708_C0IER); + + /* disable the receiver */ + outb(inb(dev->cir_addr + IT8708_C0RCR) & ~IT85_RXEN, + dev->cir_addr + IT8708_C0RCR); + + /* clear the FIFO and RXACT (actually RXACT should have been cleared + * in the previous outb() call) */ + it8708_idle_rx(dev); +} + +/* enable the receiver; this must be called with the device spinlock held */ +static void it8708_enable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the receiver by setting RXEN */ + outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXEN, + dev->cir_addr + IT8708_C0RCR); + + /* just prepare it to idle for the next reception */ + it8708_idle_rx(dev); + + /* enable the receiver interrupts and master enable flag */ + outb(inb(dev->cir_addr + IT8708_C0IER) + |IT85_RDAIE | IT85_RFOIE | IT85_IEC, + dev->cir_addr + IT8708_C0IER); +} + +/* disable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it8708_disable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the transmitter interrupts */ + outb(inb(dev->cir_addr + IT8708_C0IER) & ~IT85_TLDLIE, + dev->cir_addr + IT8708_C0IER); +} + +/* enable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it8708_enable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the transmitter interrupts and master enable flag */ + outb(inb(dev->cir_addr + IT8708_C0IER) + |IT85_TLDLIE | IT85_IEC, + dev->cir_addr + IT8708_C0IER); +} + +/* disable the device; this must be called with the device spinlock held */ +static void it8708_disable(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* clear out all interrupt enable flags */ + outb(inb(dev->cir_addr + IT8708_C0IER) & + ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), + dev->cir_addr + IT8708_C0IER); + + /* disable the receiver */ + it8708_disable_rx(dev); + + /* erase the FIFO */ + outb(IT85_FIFOCLR | inb(dev->cir_addr + IT8708_C0MSTCR), + dev->cir_addr + IT8708_C0MSTCR); +} + +/* initialize the hardware */ +static void it8708_init_hardware(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable all the interrupts */ + outb(inb(dev->cir_addr + IT8708_C0IER) & + ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), + dev->cir_addr + IT8708_C0IER); + + /* program the baud rate divisor */ + outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE, + dev->cir_addr + IT8708_BANKSEL); + + outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT8708_C0BDLR); + outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff, + dev->cir_addr + IT8708_C0BDHR); + + outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE, + dev->cir_addr + IT8708_BANKSEL); + + /* program the C0MSTCR register defaults */ + outb((inb(dev->cir_addr + IT8708_C0MSTCR) & + ~(IT85_ILSEL | IT85_ILE | IT85_FIFOTL | + IT85_FIFOCLR | IT85_RESET)) | + IT85_FIFOTL_DEFAULT, + dev->cir_addr + IT8708_C0MSTCR); + + /* program the C0RCR register defaults */ + outb((inb(dev->cir_addr + IT8708_C0RCR) & + ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND | + IT85_RXACT | IT85_RXDCR)) | + ITE_RXDCR_DEFAULT, + dev->cir_addr + IT8708_C0RCR); + + /* program the C0TCR register defaults */ + outb((inb(dev->cir_addr + IT8708_C0TCR) & + ~(IT85_TXMPM | IT85_TXMPW)) + |IT85_TXRLE | IT85_TXENDF | + IT85_TXMPM_DEFAULT | IT85_TXMPW_DEFAULT, + dev->cir_addr + IT8708_C0TCR); + + /* program the carrier parameters */ + ite_set_carrier_params(dev); +} + +/* IT8512F on ITE8709 HW-specific functions */ + +/* read a byte from the SRAM module */ +static inline u8 it8709_rm(struct ite_dev *dev, int index) +{ + outb(index, dev->cir_addr + IT8709_RAM_IDX); + return inb(dev->cir_addr + IT8709_RAM_VAL); +} + +/* write a byte to the SRAM module */ +static inline void it8709_wm(struct ite_dev *dev, u8 val, int index) +{ + outb(index, dev->cir_addr + IT8709_RAM_IDX); + outb(val, dev->cir_addr + IT8709_RAM_VAL); +} + +static void it8709_wait(struct ite_dev *dev) +{ + int i = 0; + /* + * loop until device tells it's ready to continue + * iterations count is usually ~750 but can sometimes achieve 13000 + */ + for (i = 0; i < 15000; i++) { + udelay(2); + if (it8709_rm(dev, IT8709_MODE) == IT8709_IDLE) + break; + } +} + +/* read the value of a CIR register */ +static u8 it8709_rr(struct ite_dev *dev, int index) +{ + /* just wait in case the previous access was a write */ + it8709_wait(dev); + it8709_wm(dev, index, IT8709_REG_IDX); + it8709_wm(dev, IT8709_READ, IT8709_MODE); + + /* wait for the read data to be available */ + it8709_wait(dev); + + /* return the read value */ + return it8709_rm(dev, IT8709_REG_VAL); +} + +/* write the value of a CIR register */ +static void it8709_wr(struct ite_dev *dev, u8 val, int index) +{ + /* we wait before writing, and not afterwards, since this allows us to + * pipeline the host CPU with the microcontroller */ + it8709_wait(dev); + it8709_wm(dev, val, IT8709_REG_VAL); + it8709_wm(dev, index, IT8709_REG_IDX); + it8709_wm(dev, IT8709_WRITE, IT8709_MODE); +} + +/* retrieve a bitmask of the current causes for a pending interrupt; this may + * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN + * */ +static int it8709_get_irq_causes(struct ite_dev *dev) +{ + u8 iflags; + int ret = 0; + + ite_dbg("%s called", __func__); + + /* read the interrupt flags */ + iflags = it8709_rm(dev, IT8709_IIR); + + if (iflags & IT85_TLDLI) + ret |= ITE_IRQ_TX_FIFO; + if (iflags & IT85_RDAI) + ret |= ITE_IRQ_RX_FIFO; + if (iflags & IT85_RFOI) + ret |= ITE_IRQ_RX_FIFO_OVERRUN; + + return ret; +} + +/* set the carrier parameters; to be called with the spinlock held */ +static void it8709_set_carrier_params(struct ite_dev *dev, bool high_freq, + bool use_demodulator, + u8 carrier_freq_bits, u8 allowance_bits, + u8 pulse_width_bits) +{ + u8 val; + + ite_dbg("%s called", __func__); + + val = (it8709_rr(dev, IT85_C0CFR) + &~(IT85_HCFS | IT85_CFQ)) | + carrier_freq_bits; + + if (high_freq) + val |= IT85_HCFS; + + it8709_wr(dev, val, IT85_C0CFR); + + /* program the C0RCR register */ + val = it8709_rr(dev, IT85_C0RCR) + & ~(IT85_RXEND | IT85_RXDCR); + + if (use_demodulator) + val |= IT85_RXEND; + + val |= allowance_bits; + + it8709_wr(dev, val, IT85_C0RCR); + + /* program the C0TCR register */ + val = it8709_rr(dev, IT85_C0TCR) & ~IT85_TXMPW; + val |= pulse_width_bits; + it8709_wr(dev, val, IT85_C0TCR); +} + +/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock + * held */ +static int it8709_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) +{ + int fifo, read = 0; + + ite_dbg("%s called", __func__); + + /* read how many bytes are still in the FIFO */ + fifo = it8709_rm(dev, IT8709_RFSR) & IT85_RXFBC; + + while (fifo > 0 && buf_size > 0) { + *(buf++) = it8709_rm(dev, IT8709_FIFO + read); + fifo--; + read++; + buf_size--; + } + + /* 'clear' the FIFO by setting the writing index to 0; this is + * completely bound to be racy, but we can't help it, since it's a + * limitation of the protocol */ + it8709_wm(dev, 0, IT8709_RFSR); + + return read; +} + +/* return how many bytes are still in the FIFO; this will be called + * with the device spinlock NOT HELD while waiting for the TX FIFO to get + * empty; let's expect this won't be a problem */ +static int it8709_get_tx_used_slots(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + return it8709_rr(dev, IT85_C0TFSR) & IT85_TXFBC; +} + +/* put a byte to the TX fifo; this should be called with the spinlock held */ +static void it8709_put_tx_byte(struct ite_dev *dev, u8 value) +{ + it8709_wr(dev, value, IT85_C0DR); +} + +/* idle the receiver so that we won't receive samples until another + pulse is detected; this must be called with the device spinlock held */ +static void it8709_idle_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable streaming by clearing RXACT writing it as 1 */ + it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXACT, + IT85_C0RCR); + + /* clear the FIFO */ + it8709_wr(dev, it8709_rr(dev, IT85_C0MSTCR) | IT85_FIFOCLR, + IT85_C0MSTCR); +} + +/* disable the receiver; this must be called with the device spinlock held */ +static void it8709_disable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the receiver interrupts */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & + ~(IT85_RDAIE | IT85_RFOIE), + IT85_C0IER); + + /* disable the receiver */ + it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) & ~IT85_RXEN, + IT85_C0RCR); + + /* clear the FIFO and RXACT (actually RXACT should have been cleared + * in the previous it8709_wr(dev, ) call) */ + it8709_idle_rx(dev); +} + +/* enable the receiver; this must be called with the device spinlock held */ +static void it8709_enable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the receiver by setting RXEN */ + it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXEN, + IT85_C0RCR); + + /* just prepare it to idle for the next reception */ + it8709_idle_rx(dev); + + /* enable the receiver interrupts and master enable flag */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) + |IT85_RDAIE | IT85_RFOIE | IT85_IEC, + IT85_C0IER); +} + +/* disable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it8709_disable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the transmitter interrupts */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & ~IT85_TLDLIE, + IT85_C0IER); +} + +/* enable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it8709_enable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the transmitter interrupts and master enable flag */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) + |IT85_TLDLIE | IT85_IEC, + IT85_C0IER); +} + +/* disable the device; this must be called with the device spinlock held */ +static void it8709_disable(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* clear out all interrupt enable flags */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & + ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), + IT85_C0IER); + + /* disable the receiver */ + it8709_disable_rx(dev); + + /* erase the FIFO */ + it8709_wr(dev, IT85_FIFOCLR | it8709_rr(dev, IT85_C0MSTCR), + IT85_C0MSTCR); +} + +/* initialize the hardware */ +static void it8709_init_hardware(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable all the interrupts */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & + ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), + IT85_C0IER); + + /* program the baud rate divisor */ + it8709_wr(dev, ITE_BAUDRATE_DIVISOR & 0xff, IT85_C0BDLR); + it8709_wr(dev, (ITE_BAUDRATE_DIVISOR >> 8) & 0xff, + IT85_C0BDHR); + + /* program the C0MSTCR register defaults */ + it8709_wr(dev, (it8709_rr(dev, IT85_C0MSTCR) & + ~(IT85_ILSEL | IT85_ILE | IT85_FIFOTL + | IT85_FIFOCLR | IT85_RESET)) | IT85_FIFOTL_DEFAULT, + IT85_C0MSTCR); + + /* program the C0RCR register defaults */ + it8709_wr(dev, (it8709_rr(dev, IT85_C0RCR) & + ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND | IT85_RXACT + | IT85_RXDCR)) | ITE_RXDCR_DEFAULT, + IT85_C0RCR); + + /* program the C0TCR register defaults */ + it8709_wr(dev, (it8709_rr(dev, IT85_C0TCR) & ~(IT85_TXMPM | IT85_TXMPW)) + | IT85_TXRLE | IT85_TXENDF | IT85_TXMPM_DEFAULT + | IT85_TXMPW_DEFAULT, + IT85_C0TCR); + + /* program the carrier parameters */ + ite_set_carrier_params(dev); +} + + +/* generic hardware setup/teardown code */ + +/* activate the device for use */ +static int ite_open(struct rc_dev *rcdev) +{ + struct ite_dev *dev = rcdev->priv; + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + dev->in_use = true; + + /* enable the receiver */ + dev->params.enable_rx(dev); + + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* deactivate the device for use */ +static void ite_close(struct rc_dev *rcdev) +{ + struct ite_dev *dev = rcdev->priv; + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + dev->in_use = false; + + /* wait for any transmission to end */ + spin_unlock_irqrestore(&dev->lock, flags); + wait_event_interruptible(dev->tx_ended, !dev->transmitting); + spin_lock_irqsave(&dev->lock, flags); + + dev->params.disable(dev); + + spin_unlock_irqrestore(&dev->lock, flags); +} + +/* supported models and their parameters */ +static const struct ite_dev_params ite_dev_descs[] = { + { /* 0: ITE8704 */ + .model = "ITE8704 CIR transceiver", + .io_region_size = IT87_IOREG_LENGTH, + .hw_tx_capable = true, + .sample_period = (u32) (1000000000ULL / 115200), + .tx_carrier_freq = 38000, + .tx_duty_cycle = 33, + .rx_low_carrier_freq = 0, + .rx_high_carrier_freq = 0, + + /* operations */ + .get_irq_causes = it87_get_irq_causes, + .enable_rx = it87_enable_rx, + .idle_rx = it87_idle_rx, + .disable_rx = it87_idle_rx, + .get_rx_bytes = it87_get_rx_bytes, + .enable_tx_interrupt = it87_enable_tx_interrupt, + .disable_tx_interrupt = it87_disable_tx_interrupt, + .get_tx_used_slots = it87_get_tx_used_slots, + .put_tx_byte = it87_put_tx_byte, + .disable = it87_disable, + .init_hardware = it87_init_hardware, + .set_carrier_params = it87_set_carrier_params, + }, + { /* 1: ITE8713 */ + .model = "ITE8713 CIR transceiver", + .io_region_size = IT87_IOREG_LENGTH, + .hw_tx_capable = true, + .sample_period = (u32) (1000000000ULL / 115200), + .tx_carrier_freq = 38000, + .tx_duty_cycle = 33, + .rx_low_carrier_freq = 0, + .rx_high_carrier_freq = 0, + + /* operations */ + .get_irq_causes = it87_get_irq_causes, + .enable_rx = it87_enable_rx, + .idle_rx = it87_idle_rx, + .disable_rx = it87_idle_rx, + .get_rx_bytes = it87_get_rx_bytes, + .enable_tx_interrupt = it87_enable_tx_interrupt, + .disable_tx_interrupt = it87_disable_tx_interrupt, + .get_tx_used_slots = it87_get_tx_used_slots, + .put_tx_byte = it87_put_tx_byte, + .disable = it87_disable, + .init_hardware = it87_init_hardware, + .set_carrier_params = it87_set_carrier_params, + }, + { /* 2: ITE8708 */ + .model = "ITE8708 CIR transceiver", + .io_region_size = IT8708_IOREG_LENGTH, + .hw_tx_capable = true, + .sample_period = (u32) (1000000000ULL / 115200), + .tx_carrier_freq = 38000, + .tx_duty_cycle = 33, + .rx_low_carrier_freq = 0, + .rx_high_carrier_freq = 0, + + /* operations */ + .get_irq_causes = it8708_get_irq_causes, + .enable_rx = it8708_enable_rx, + .idle_rx = it8708_idle_rx, + .disable_rx = it8708_idle_rx, + .get_rx_bytes = it8708_get_rx_bytes, + .enable_tx_interrupt = it8708_enable_tx_interrupt, + .disable_tx_interrupt = + it8708_disable_tx_interrupt, + .get_tx_used_slots = it8708_get_tx_used_slots, + .put_tx_byte = it8708_put_tx_byte, + .disable = it8708_disable, + .init_hardware = it8708_init_hardware, + .set_carrier_params = it8708_set_carrier_params, + }, + { /* 3: ITE8709 */ + .model = "ITE8709 CIR transceiver", + .io_region_size = IT8709_IOREG_LENGTH, + .hw_tx_capable = true, + .sample_period = (u32) (1000000000ULL / 115200), + .tx_carrier_freq = 38000, + .tx_duty_cycle = 33, + .rx_low_carrier_freq = 0, + .rx_high_carrier_freq = 0, + + /* operations */ + .get_irq_causes = it8709_get_irq_causes, + .enable_rx = it8709_enable_rx, + .idle_rx = it8709_idle_rx, + .disable_rx = it8709_idle_rx, + .get_rx_bytes = it8709_get_rx_bytes, + .enable_tx_interrupt = it8709_enable_tx_interrupt, + .disable_tx_interrupt = + it8709_disable_tx_interrupt, + .get_tx_used_slots = it8709_get_tx_used_slots, + .put_tx_byte = it8709_put_tx_byte, + .disable = it8709_disable, + .init_hardware = it8709_init_hardware, + .set_carrier_params = it8709_set_carrier_params, + }, +}; + +static const struct pnp_device_id ite_ids[] = { + {"ITE8704", 0}, /* Default model */ + {"ITE8713", 1}, /* CIR found in EEEBox 1501U */ + {"ITE8708", 2}, /* Bridged IT8512 */ + {"ITE8709", 3}, /* SRAM-Bridged IT8512 */ + {"", 0}, +}; + +/* allocate memory, probe hardware, and initialize everything */ +static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id + *dev_id) +{ + const struct ite_dev_params *dev_desc = NULL; + struct ite_dev *itdev = NULL; + struct rc_dev *rdev = NULL; + int ret = -ENOMEM; + int model_no; + + ite_dbg("%s called", __func__); + + itdev = kzalloc(sizeof(struct ite_dev), GFP_KERNEL); + if (!itdev) + return ret; + + /* input device for IR remote (and tx) */ + rdev = rc_allocate_device(); + if (!rdev) + goto failure; + + ret = -ENODEV; + + /* get the model number */ + model_no = (int)dev_id->driver_data; + ite_pr(KERN_NOTICE, "Auto-detected model: %s\n", + ite_dev_descs[model_no].model); + + if (model_number >= 0 && model_number < ARRAY_SIZE(ite_dev_descs)) { + model_no = model_number; + ite_pr(KERN_NOTICE, "The model has been fixed by a module " + "parameter."); + } + + ite_pr(KERN_NOTICE, "Using model: %s\n", ite_dev_descs[model_no].model); + + /* get the description for the device */ + dev_desc = &ite_dev_descs[model_no]; + + /* validate pnp resources */ + if (!pnp_port_valid(pdev, 0) || + pnp_port_len(pdev, 0) != dev_desc->io_region_size) { + dev_err(&pdev->dev, "IR PNP Port not valid!\n"); + goto failure; + } + + if (!pnp_irq_valid(pdev, 0)) { + dev_err(&pdev->dev, "PNP IRQ not valid!\n"); + goto failure; + } + + /* store resource values */ + itdev->cir_addr = pnp_port_start(pdev, 0); + itdev->cir_irq = pnp_irq(pdev, 0); + + /* initialize spinlocks */ + spin_lock_init(&itdev->lock); + + /* initialize raw event */ + init_ir_raw_event(&itdev->rawir); + + ret = -EBUSY; + /* now claim resources */ + if (!request_region(itdev->cir_addr, + dev_desc->io_region_size, ITE_DRIVER_NAME)) + goto failure; + + if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED, + ITE_DRIVER_NAME, (void *)itdev)) + goto failure; + + /* set driver data into the pnp device */ + pnp_set_drvdata(pdev, itdev); + itdev->pdev = pdev; + + /* initialize waitqueues for transmission */ + init_waitqueue_head(&itdev->tx_queue); + init_waitqueue_head(&itdev->tx_ended); + + /* copy model-specific parameters */ + itdev->params = *dev_desc; + + /* apply any overrides */ + if (sample_period > 0) + itdev->params.sample_period = sample_period; + + if (tx_carrier_freq > 0) + itdev->params.tx_carrier_freq = tx_carrier_freq; + + if (tx_duty_cycle > 0 && tx_duty_cycle <= 100) + itdev->params.tx_duty_cycle = tx_duty_cycle; + + if (rx_low_carrier_freq > 0) + itdev->params.rx_low_carrier_freq = rx_low_carrier_freq; + + if (rx_high_carrier_freq > 0) + itdev->params.rx_high_carrier_freq = rx_high_carrier_freq; + + /* print out parameters */ + ite_pr(KERN_NOTICE, "TX-capable: %d\n", (int) + itdev->params.hw_tx_capable); + ite_pr(KERN_NOTICE, "Sample period (ns): %ld\n", (long) + itdev->params.sample_period); + ite_pr(KERN_NOTICE, "TX carrier frequency (Hz): %d\n", (int) + itdev->params.tx_carrier_freq); + ite_pr(KERN_NOTICE, "TX duty cycle (%%): %d\n", (int) + itdev->params.tx_duty_cycle); + ite_pr(KERN_NOTICE, "RX low carrier frequency (Hz): %d\n", (int) + itdev->params.rx_low_carrier_freq); + ite_pr(KERN_NOTICE, "RX high carrier frequency (Hz): %d\n", (int) + itdev->params.rx_high_carrier_freq); + + /* set up hardware initial state */ + itdev->params.init_hardware(itdev); + + /* set up ir-core props */ + rdev->priv = itdev; + rdev->driver_type = RC_DRIVER_IR_RAW; + rdev->allowed_protos = RC_TYPE_ALL; + rdev->open = ite_open; + rdev->close = ite_close; + rdev->s_idle = ite_s_idle; + rdev->s_rx_carrier_range = ite_set_rx_carrier_range; + rdev->min_timeout = ITE_MIN_IDLE_TIMEOUT; + rdev->max_timeout = ITE_MAX_IDLE_TIMEOUT; + rdev->timeout = ITE_IDLE_TIMEOUT; + rdev->rx_resolution = ITE_BAUDRATE_DIVISOR * + itdev->params.sample_period; + rdev->tx_resolution = ITE_BAUDRATE_DIVISOR * + itdev->params.sample_period; + + /* set up transmitter related values if needed */ + if (itdev->params.hw_tx_capable) { + rdev->tx_ir = ite_tx_ir; + rdev->s_tx_carrier = ite_set_tx_carrier; + rdev->s_tx_duty_cycle = ite_set_tx_duty_cycle; + } + + rdev->input_name = dev_desc->model; + rdev->input_id.bustype = BUS_HOST; + rdev->input_id.vendor = PCI_VENDOR_ID_ITE; + rdev->input_id.product = 0; + rdev->input_id.version = 0; + rdev->driver_name = ITE_DRIVER_NAME; + rdev->map_name = RC_MAP_RC6_MCE; + + ret = rc_register_device(rdev); + if (ret) + goto failure; + + itdev->rdev = rdev; + ite_pr(KERN_NOTICE, "driver has been successfully loaded\n"); + + return 0; + +failure: + if (itdev->cir_irq) + free_irq(itdev->cir_irq, itdev); + + if (itdev->cir_addr) + release_region(itdev->cir_addr, itdev->params.io_region_size); + + rc_free_device(rdev); + kfree(itdev); + + return ret; +} + +static void __devexit ite_remove(struct pnp_dev *pdev) +{ + struct ite_dev *dev = pnp_get_drvdata(pdev); + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + + /* disable hardware */ + dev->params.disable(dev); + + spin_unlock_irqrestore(&dev->lock, flags); + + /* free resources */ + free_irq(dev->cir_irq, dev); + release_region(dev->cir_addr, dev->params.io_region_size); + + rc_unregister_device(dev->rdev); + + kfree(dev); +} + +static int ite_suspend(struct pnp_dev *pdev, pm_message_t state) +{ + struct ite_dev *dev = pnp_get_drvdata(pdev); + unsigned long flags; + + ite_dbg("%s called", __func__); + + /* wait for any transmission to end */ + wait_event_interruptible(dev->tx_ended, !dev->transmitting); + + spin_lock_irqsave(&dev->lock, flags); + + /* disable all interrupts */ + dev->params.disable(dev); + + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +static int ite_resume(struct pnp_dev *pdev) +{ + int ret = 0; + struct ite_dev *dev = pnp_get_drvdata(pdev); + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + + /* reinitialize hardware config registers */ + dev->params.init_hardware(dev); + /* enable the receiver */ + dev->params.enable_rx(dev); + + spin_unlock_irqrestore(&dev->lock, flags); + + return ret; +} + +static void ite_shutdown(struct pnp_dev *pdev) +{ + struct ite_dev *dev = pnp_get_drvdata(pdev); + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + + /* disable all interrupts */ + dev->params.disable(dev); + + spin_unlock_irqrestore(&dev->lock, flags); +} + +static struct pnp_driver ite_driver = { + .name = ITE_DRIVER_NAME, + .id_table = ite_ids, + .probe = ite_probe, + .remove = __devexit_p(ite_remove), + .suspend = ite_suspend, + .resume = ite_resume, + .shutdown = ite_shutdown, +}; + +int ite_init(void) +{ + return pnp_register_driver(&ite_driver); +} + +void ite_exit(void) +{ + pnp_unregister_driver(&ite_driver); +} + +MODULE_DEVICE_TABLE(pnp, ite_ids); +MODULE_DESCRIPTION("ITE Tech Inc. IT8712F/ITE8512F CIR driver"); + +MODULE_AUTHOR("Juan J. Garcia de Soria "); +MODULE_LICENSE("GPL"); + +module_init(ite_init); +module_exit(ite_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ite-cir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ite-cir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ite-cir.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/ite-cir.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,481 @@ +/* + * Driver for ITE Tech Inc. IT8712F/IT8512F CIR + * + * Copyright (C) 2010 Juan Jesús García de Soria + * + * 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, or (at your option) any later version. + * + * 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. + */ + +/* platform driver name to register */ +#define ITE_DRIVER_NAME "ite-cir" + +/* logging macros */ +#define ite_pr(level, text, ...) \ + printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) +#define ite_dbg(text, ...) do { \ + if (debug) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \ +} while (0) + +#define ite_dbg_verbose(text, ...) do {\ + if (debug > 1) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \ +} while (0) + +/* FIFO sizes */ +#define ITE_TX_FIFO_LEN 32 +#define ITE_RX_FIFO_LEN 32 + +/* interrupt types */ +#define ITE_IRQ_TX_FIFO 1 +#define ITE_IRQ_RX_FIFO 2 +#define ITE_IRQ_RX_FIFO_OVERRUN 4 + +/* forward declaration */ +struct ite_dev; + +/* struct for storing the parameters of different recognized devices */ +struct ite_dev_params { + /* model of the device */ + const char *model; + + /* size of the I/O region */ + int io_region_size; + + /* true if the hardware supports transmission */ + bool hw_tx_capable; + + /* base sampling period, in ns */ + u32 sample_period; + + /* rx low carrier frequency, in Hz, 0 means no demodulation */ + unsigned int rx_low_carrier_freq; + + /* tx high carrier frequency, in Hz, 0 means no demodulation */ + unsigned int rx_high_carrier_freq; + + /* tx carrier frequency, in Hz */ + unsigned int tx_carrier_freq; + + /* duty cycle, 0-100 */ + int tx_duty_cycle; + + /* hw-specific operation function pointers; most of these must be + * called while holding the spin lock, except for the TX FIFO length + * one */ + /* get pending interrupt causes */ + int (*get_irq_causes) (struct ite_dev *dev); + + /* enable rx */ + void (*enable_rx) (struct ite_dev *dev); + + /* make rx enter the idle state; keep listening for a pulse, but stop + * streaming space bytes */ + void (*idle_rx) (struct ite_dev *dev); + + /* disable rx completely */ + void (*disable_rx) (struct ite_dev *dev); + + /* read bytes from RX FIFO; return read count */ + int (*get_rx_bytes) (struct ite_dev *dev, u8 *buf, int buf_size); + + /* enable tx FIFO space available interrupt */ + void (*enable_tx_interrupt) (struct ite_dev *dev); + + /* disable tx FIFO space available interrupt */ + void (*disable_tx_interrupt) (struct ite_dev *dev); + + /* get number of full TX FIFO slots */ + int (*get_tx_used_slots) (struct ite_dev *dev); + + /* put a byte to the TX FIFO */ + void (*put_tx_byte) (struct ite_dev *dev, u8 value); + + /* disable hardware completely */ + void (*disable) (struct ite_dev *dev); + + /* initialize the hardware */ + void (*init_hardware) (struct ite_dev *dev); + + /* set the carrier parameters */ + void (*set_carrier_params) (struct ite_dev *dev, bool high_freq, + bool use_demodulator, u8 carrier_freq_bits, + u8 allowance_bits, u8 pulse_width_bits); +}; + +/* ITE CIR device structure */ +struct ite_dev { + struct pnp_dev *pdev; + struct rc_dev *rdev; + struct ir_raw_event rawir; + + /* sync data */ + spinlock_t lock; + bool in_use, transmitting; + + /* transmit support */ + int tx_fifo_allowance; + wait_queue_head_t tx_queue, tx_ended; + + /* hardware I/O settings */ + unsigned long cir_addr; + int cir_irq; + + /* overridable copy of model parameters */ + struct ite_dev_params params; +}; + +/* common values for all kinds of hardware */ + +/* baud rate divisor default */ +#define ITE_BAUDRATE_DIVISOR 1 + +/* low-speed carrier frequency limits (Hz) */ +#define ITE_LCF_MIN_CARRIER_FREQ 27000 +#define ITE_LCF_MAX_CARRIER_FREQ 58000 + +/* high-speed carrier frequency limits (Hz) */ +#define ITE_HCF_MIN_CARRIER_FREQ 400000 +#define ITE_HCF_MAX_CARRIER_FREQ 500000 + +/* default carrier freq for when demodulator is off (Hz) */ +#define ITE_DEFAULT_CARRIER_FREQ 38000 + +/* default idling timeout in ns (0.2 seconds) */ +#define ITE_IDLE_TIMEOUT 200000000UL + +/* limit timeout values */ +#define ITE_MIN_IDLE_TIMEOUT 100000000UL +#define ITE_MAX_IDLE_TIMEOUT 1000000000UL + +/* convert bits to us */ +#define ITE_BITS_TO_NS(bits, sample_period) \ +((u32) ((bits) * ITE_BAUDRATE_DIVISOR * sample_period)) + +/* + * n in RDCR produces a tolerance of +/- n * 6.25% around the center + * carrier frequency... + * + * From two limit frequencies, L (low) and H (high), we can get both the + * center frequency F = (L + H) / 2 and the variation from the center + * frequency A = (H - L) / (H + L). We can use this in order to honor the + * s_rx_carrier_range() call in ir-core. We'll suppose that any request + * setting L=0 means we must shut down the demodulator. + */ +#define ITE_RXDCR_PER_10000_STEP 625 + +/* high speed carrier freq values */ +#define ITE_CFQ_400 0x03 +#define ITE_CFQ_450 0x08 +#define ITE_CFQ_480 0x0b +#define ITE_CFQ_500 0x0d + +/* values for pulse widths */ +#define ITE_TXMPW_A 0x02 +#define ITE_TXMPW_B 0x03 +#define ITE_TXMPW_C 0x04 +#define ITE_TXMPW_D 0x05 +#define ITE_TXMPW_E 0x06 + +/* values for demodulator carrier range allowance */ +#define ITE_RXDCR_DEFAULT 0x01 /* default carrier range */ +#define ITE_RXDCR_MAX 0x07 /* default carrier range */ + +/* DR TX bits */ +#define ITE_TX_PULSE 0x00 +#define ITE_TX_SPACE 0x80 +#define ITE_TX_MAX_RLE 0x80 +#define ITE_TX_RLE_MASK 0x7f + +/* + * IT8712F + * + * hardware data obtained from: + * + * IT8712F + * Environment Control – Low Pin Count Input / Output + * (EC - LPC I/O) + * Preliminary Specification V0. 81 + */ + +/* register offsets */ +#define IT87_DR 0x00 /* data register */ +#define IT87_IER 0x01 /* interrupt enable register */ +#define IT87_RCR 0x02 /* receiver control register */ +#define IT87_TCR1 0x03 /* transmitter control register 1 */ +#define IT87_TCR2 0x04 /* transmitter control register 2 */ +#define IT87_TSR 0x05 /* transmitter status register */ +#define IT87_RSR 0x06 /* receiver status register */ +#define IT87_BDLR 0x05 /* baud rate divisor low byte register */ +#define IT87_BDHR 0x06 /* baud rate divisor high byte register */ +#define IT87_IIR 0x07 /* interrupt identification register */ + +#define IT87_IOREG_LENGTH 0x08 /* length of register file */ + +/* IER bits */ +#define IT87_TLDLIE 0x01 /* transmitter low data interrupt enable */ +#define IT87_RDAIE 0x02 /* receiver data available interrupt enable */ +#define IT87_RFOIE 0x04 /* receiver FIFO overrun interrupt enable */ +#define IT87_IEC 0x08 /* interrupt enable control */ +#define IT87_BR 0x10 /* baud rate register enable */ +#define IT87_RESET 0x20 /* reset */ + +/* RCR bits */ +#define IT87_RXDCR 0x07 /* receiver demodulation carrier range mask */ +#define IT87_RXACT 0x08 /* receiver active */ +#define IT87_RXEND 0x10 /* receiver demodulation enable */ +#define IT87_RXEN 0x20 /* receiver enable */ +#define IT87_HCFS 0x40 /* high-speed carrier frequency select */ +#define IT87_RDWOS 0x80 /* receiver data without sync */ + +/* TCR1 bits */ +#define IT87_TXMPM 0x03 /* transmitter modulation pulse mode mask */ +#define IT87_TXMPM_DEFAULT 0x00 /* modulation pulse mode default */ +#define IT87_TXENDF 0x04 /* transmitter deferral */ +#define IT87_TXRLE 0x08 /* transmitter run length enable */ +#define IT87_FIFOTL 0x30 /* FIFO level threshold mask */ +#define IT87_FIFOTL_DEFAULT 0x20 /* FIFO level threshold default + * 0x00 -> 1, 0x10 -> 7, 0x20 -> 17, + * 0x30 -> 25 */ +#define IT87_ILE 0x40 /* internal loopback enable */ +#define IT87_FIFOCLR 0x80 /* FIFO clear bit */ + +/* TCR2 bits */ +#define IT87_TXMPW 0x07 /* transmitter modulation pulse width mask */ +#define IT87_TXMPW_DEFAULT 0x04 /* default modulation pulse width */ +#define IT87_CFQ 0xf8 /* carrier frequency mask */ +#define IT87_CFQ_SHIFT 3 /* carrier frequency bit shift */ + +/* TSR bits */ +#define IT87_TXFBC 0x3f /* transmitter FIFO byte count mask */ + +/* RSR bits */ +#define IT87_RXFBC 0x3f /* receiver FIFO byte count mask */ +#define IT87_RXFTO 0x80 /* receiver FIFO time-out */ + +/* IIR bits */ +#define IT87_IP 0x01 /* interrupt pending */ +#define IT87_II 0x06 /* interrupt identification mask */ +#define IT87_II_NOINT 0x00 /* no interrupt */ +#define IT87_II_TXLDL 0x02 /* transmitter low data level */ +#define IT87_II_RXDS 0x04 /* receiver data stored */ +#define IT87_II_RXFO 0x06 /* receiver FIFO overrun */ + +/* + * IT8512E/F + * + * Hardware data obtained from: + * + * IT8512E/F + * Embedded Controller + * Preliminary Specification V0.4.1 + * + * Note that the CIR registers are not directly available to the host, because + * they only are accessible to the integrated microcontroller. Thus, in order + * use it, some kind of bridging is required. As the bridging may depend on + * the controller firmware in use, we are going to use the PNP ID in order to + * determine the strategy and ports available. See after these generic + * IT8512E/F register definitions for register definitions for those + * strategies. + */ + +/* register offsets */ +#define IT85_C0DR 0x00 /* data register */ +#define IT85_C0MSTCR 0x01 /* master control register */ +#define IT85_C0IER 0x02 /* interrupt enable register */ +#define IT85_C0IIR 0x03 /* interrupt identification register */ +#define IT85_C0CFR 0x04 /* carrier frequency register */ +#define IT85_C0RCR 0x05 /* receiver control register */ +#define IT85_C0TCR 0x06 /* transmitter control register */ +#define IT85_C0SCK 0x07 /* slow clock control register */ +#define IT85_C0BDLR 0x08 /* baud rate divisor low byte register */ +#define IT85_C0BDHR 0x09 /* baud rate divisor high byte register */ +#define IT85_C0TFSR 0x0a /* transmitter FIFO status register */ +#define IT85_C0RFSR 0x0b /* receiver FIFO status register */ +#define IT85_C0WCL 0x0d /* wakeup code length register */ +#define IT85_C0WCR 0x0e /* wakeup code read/write register */ +#define IT85_C0WPS 0x0f /* wakeup power control/status register */ + +#define IT85_IOREG_LENGTH 0x10 /* length of register file */ + +/* C0MSTCR bits */ +#define IT85_RESET 0x01 /* reset */ +#define IT85_FIFOCLR 0x02 /* FIFO clear bit */ +#define IT85_FIFOTL 0x0c /* FIFO level threshold mask */ +#define IT85_FIFOTL_DEFAULT 0x08 /* FIFO level threshold default + * 0x00 -> 1, 0x04 -> 7, 0x08 -> 17, + * 0x0c -> 25 */ +#define IT85_ILE 0x10 /* internal loopback enable */ +#define IT85_ILSEL 0x20 /* internal loopback select */ + +/* C0IER bits */ +#define IT85_TLDLIE 0x01 /* TX low data level interrupt enable */ +#define IT85_RDAIE 0x02 /* RX data available interrupt enable */ +#define IT85_RFOIE 0x04 /* RX FIFO overrun interrupt enable */ +#define IT85_IEC 0x80 /* interrupt enable function control */ + +/* C0IIR bits */ +#define IT85_TLDLI 0x01 /* transmitter low data level interrupt */ +#define IT85_RDAI 0x02 /* receiver data available interrupt */ +#define IT85_RFOI 0x04 /* receiver FIFO overrun interrupt */ +#define IT85_NIP 0x80 /* no interrupt pending */ + +/* C0CFR bits */ +#define IT85_CFQ 0x1f /* carrier frequency mask */ +#define IT85_HCFS 0x20 /* high speed carrier frequency select */ + +/* C0RCR bits */ +#define IT85_RXDCR 0x07 /* receiver demodulation carrier range mask */ +#define IT85_RXACT 0x08 /* receiver active */ +#define IT85_RXEND 0x10 /* receiver demodulation enable */ +#define IT85_RDWOS 0x20 /* receiver data without sync */ +#define IT85_RXEN 0x80 /* receiver enable */ + +/* C0TCR bits */ +#define IT85_TXMPW 0x07 /* transmitter modulation pulse width mask */ +#define IT85_TXMPW_DEFAULT 0x04 /* default modulation pulse width */ +#define IT85_TXMPM 0x18 /* transmitter modulation pulse mode mask */ +#define IT85_TXMPM_DEFAULT 0x00 /* modulation pulse mode default */ +#define IT85_TXENDF 0x20 /* transmitter deferral */ +#define IT85_TXRLE 0x40 /* transmitter run length enable */ + +/* C0SCK bits */ +#define IT85_SCKS 0x01 /* slow clock select */ +#define IT85_TXDCKG 0x02 /* TXD clock gating */ +#define IT85_DLL1P8E 0x04 /* DLL 1.8432M enable */ +#define IT85_DLLTE 0x08 /* DLL test enable */ +#define IT85_BRCM 0x70 /* baud rate count mode */ +#define IT85_DLLOCK 0x80 /* DLL lock */ + +/* C0TFSR bits */ +#define IT85_TXFBC 0x3f /* transmitter FIFO count mask */ + +/* C0RFSR bits */ +#define IT85_RXFBC 0x3f /* receiver FIFO count mask */ +#define IT85_RXFTO 0x80 /* receiver FIFO time-out */ + +/* C0WCL bits */ +#define IT85_WCL 0x3f /* wakeup code length mask */ + +/* C0WPS bits */ +#define IT85_CIRPOSIE 0x01 /* power on/off status interrupt enable */ +#define IT85_CIRPOIS 0x02 /* power on/off interrupt status */ +#define IT85_CIRPOII 0x04 /* power on/off interrupt identification */ +#define IT85_RCRST 0x10 /* wakeup code reading counter reset bit */ +#define IT85_WCRST 0x20 /* wakeup code writing counter reset bit */ + +/* + * ITE8708 + * + * Hardware data obtained from hacked driver for IT8512 in this forum post: + * + * http://ubuntuforums.org/showthread.php?t=1028640 + * + * Although there's no official documentation for that driver, analysis would + * suggest that it maps the 16 registers of IT8512 onto two 8-register banks, + * selectable by a single bank-select bit that's mapped onto both banks. The + * IT8512 registers are mapped in a different order, so that the first bank + * maps the ones that are used more often, and two registers that share a + * reserved high-order bit are placed at the same offset in both banks in + * order to reuse the reserved bit as the bank select bit. + */ + +/* register offsets */ + +/* mapped onto both banks */ +#define IT8708_BANKSEL 0x07 /* bank select register */ +#define IT8708_HRAE 0x80 /* high registers access enable */ + +/* mapped onto the low bank */ +#define IT8708_C0DR 0x00 /* data register */ +#define IT8708_C0MSTCR 0x01 /* master control register */ +#define IT8708_C0IER 0x02 /* interrupt enable register */ +#define IT8708_C0IIR 0x03 /* interrupt identification register */ +#define IT8708_C0RFSR 0x04 /* receiver FIFO status register */ +#define IT8708_C0RCR 0x05 /* receiver control register */ +#define IT8708_C0TFSR 0x06 /* transmitter FIFO status register */ +#define IT8708_C0TCR 0x07 /* transmitter control register */ + +/* mapped onto the high bank */ +#define IT8708_C0BDLR 0x01 /* baud rate divisor low byte register */ +#define IT8708_C0BDHR 0x02 /* baud rate divisor high byte register */ +#define IT8708_C0CFR 0x04 /* carrier frequency register */ + +/* registers whose bank mapping we don't know, since they weren't being used + * in the hacked driver... most probably they belong to the high bank too, + * since they fit in the holes the other registers leave */ +#define IT8708_C0SCK 0x03 /* slow clock control register */ +#define IT8708_C0WCL 0x05 /* wakeup code length register */ +#define IT8708_C0WCR 0x06 /* wakeup code read/write register */ +#define IT8708_C0WPS 0x07 /* wakeup power control/status register */ + +#define IT8708_IOREG_LENGTH 0x08 /* length of register file */ + +/* two more registers that are defined in the hacked driver, but can't be + * found in the data sheets; no idea what they are or how they are accessed, + * since the hacked driver doesn't seem to use them */ +#define IT8708_CSCRR 0x00 +#define IT8708_CGPINTR 0x01 + +/* CSCRR bits */ +#define IT8708_CSCRR_SCRB 0x3f +#define IT8708_CSCRR_PM 0x80 + +/* CGPINTR bits */ +#define IT8708_CGPINT 0x01 + +/* + * ITE8709 + * + * Hardware interfacing data obtained from the original lirc_ite8709 driver. + * Verbatim from its sources: + * + * The ITE8709 device seems to be the combination of IT8512 superIO chip and + * a specific firmware running on the IT8512's embedded micro-controller. + * In addition of the embedded micro-controller, the IT8512 chip contains a + * CIR module and several other modules. A few modules are directly accessible + * by the host CPU, but most of them are only accessible by the + * micro-controller. The CIR module is only accessible by the + * micro-controller. + * + * The battery-backed SRAM module is accessible by the host CPU and the + * micro-controller. So one of the MC's firmware role is to act as a bridge + * between the host CPU and the CIR module. The firmware implements a kind of + * communication protocol using the SRAM module as a shared memory. The IT8512 + * specification is publicly available on ITE's web site, but the + * communication protocol is not, so it was reverse-engineered. + */ + +/* register offsets */ +#define IT8709_RAM_IDX 0x00 /* index into the SRAM module bytes */ +#define IT8709_RAM_VAL 0x01 /* read/write data to the indexed byte */ + +#define IT8709_IOREG_LENGTH 0x02 /* length of register file */ + +/* register offsets inside the SRAM module */ +#define IT8709_MODE 0x1a /* request/ack byte */ +#define IT8709_REG_IDX 0x1b /* index of the CIR register to access */ +#define IT8709_REG_VAL 0x1c /* value read/to be written */ +#define IT8709_IIR 0x1e /* interrupt identification register */ +#define IT8709_RFSR 0x1f /* receiver FIFO status register */ +#define IT8709_FIFO 0x20 /* start of in RAM RX FIFO copy */ + +/* MODE values */ +#define IT8709_IDLE 0x00 +#define IT8709_WRITE 0x01 +#define IT8709_READ 0x02 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,229 @@ +menuconfig RC_CORE + tristate "Remote Controller adapters" + depends on INPUT + default INPUT + ---help--- + Enable support for Remote Controllers on Linux. This is + needed in order to support several video capture adapters. + Currently, all supported devices use InfraRed. + + Enable this option if you have a video capture board even + if you don't need IR, as otherwise, you may not be able to + compile the driver for your adapter. + +if RC_CORE + +config LIRC + tristate + default y + + ---help--- + Enable this option to build the Linux Infrared Remote + Control (LIRC) core device interface driver. The LIRC + interface passes raw IR to and from userspace, where the + LIRC daemon handles protocol decoding for IR reception and + encoding for IR transmitting (aka "blasting"). + +source "drivers/media/rc/keymaps/Kconfig" + +config IR_NEC_DECODER + tristate "Enable IR raw decoder for the NEC protocol" + depends on RC_CORE + select BITREVERSE + default y + + ---help--- + Enable this option if you have IR with NEC protocol, and + if the IR is decoded in software + +config IR_RC5_DECODER + tristate "Enable IR raw decoder for the RC-5 protocol" + depends on RC_CORE + select BITREVERSE + default y + + ---help--- + Enable this option if you have IR with RC-5 protocol, and + if the IR is decoded in software + +config IR_RC6_DECODER + tristate "Enable IR raw decoder for the RC6 protocol" + depends on RC_CORE + select BITREVERSE + default y + + ---help--- + Enable this option if you have an infrared remote control which + uses the RC6 protocol, and you need software decoding support. + +config IR_JVC_DECODER + tristate "Enable IR raw decoder for the JVC protocol" + depends on RC_CORE + select BITREVERSE + default y + + ---help--- + Enable this option if you have an infrared remote control which + uses the JVC protocol, and you need software decoding support. + +config IR_SONY_DECODER + tristate "Enable IR raw decoder for the Sony protocol" + depends on RC_CORE + default y + + ---help--- + Enable this option if you have an infrared remote control which + uses the Sony protocol, and you need software decoding support. + +config IR_RC5_SZ_DECODER + tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol" + depends on RC_CORE + select BITREVERSE + default y + + ---help--- + Enable this option if you have IR with RC-5 (streamzap) protocol, + and if the IR is decoded in software. (The Streamzap PC Remote + uses an IR protocol that is almost standard RC-5, but not quite, + as it uses an additional bit). + +config IR_LIRC_CODEC + tristate "Enable IR to LIRC bridge" + depends on RC_CORE + depends on LIRC + default y + + ---help--- + Enable this option to pass raw IR to and from userspace via + the LIRC interface. + +config IR_ENE + tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)" + depends on PNP + depends on RC_CORE + ---help--- + Say Y here to enable support for integrated infrared receiver + /transceiver made by ENE. + + You can see if you have it by looking at lspnp output. + Output should include ENE0100 ENE0200 or something similar. + + To compile this driver as a module, choose M here: the + module will be called ene_ir. + +config IR_IMON + tristate "SoundGraph iMON Receiver and Display" + depends on USB_ARCH_HAS_HCD + depends on RC_CORE + select USB + ---help--- + Say Y here if you want to use a SoundGraph iMON (aka Antec Veris) + IR Receiver and/or LCD/VFD/VGA display. + + To compile this driver as a module, choose M here: the + module will be called imon. + +config IR_MCEUSB + tristate "Windows Media Center Ed. eHome Infrared Transceiver" + depends on USB_ARCH_HAS_HCD + depends on RC_CORE + select USB + ---help--- + Say Y here if you want to use a Windows Media Center Edition + eHome Infrared Transceiver. + + To compile this driver as a module, choose M here: the + module will be called mceusb. + +config IR_ITE_CIR + tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver" + depends on PNP + depends on RC_CORE + ---help--- + Say Y here to enable support for integrated infrared receivers + /transceivers made by ITE Tech Inc. These are found in + several ASUS devices, like the ASUS Digimatrix or the ASUS + EEEBox 1501U. + + To compile this driver as a module, choose M here: the + module will be called ite-cir. + +config IR_FINTEK + tristate "Fintek Consumer Infrared Transceiver" + depends on PNP + depends on RC_CORE + ---help--- + Say Y here to enable support for integrated infrared receiver + /transciever made by Fintek. This chip is found on assorted + Jetway motherboards (and of course, possibly others). + + To compile this driver as a module, choose M here: the + module will be called fintek-cir. + +config IR_NUVOTON + tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" + depends on PNP + depends on RC_CORE + ---help--- + Say Y here to enable support for integrated infrared receiver + /transciever made by Nuvoton (formerly Winbond). This chip is + found in the ASRock ION 330HT, as well as assorted Intel + DP55-series motherboards (and of course, possibly others). + + To compile this driver as a module, choose M here: the + module will be called nuvoton-cir. + +config IR_REDRAT3 + tristate "RedRat3 IR Transceiver" + depends on USB_ARCH_HAS_HCD + depends on RC_CORE + select USB + ---help--- + Say Y here if you want to use a RedRat3 Infrared Transceiver. + + To compile this driver as a module, choose M here: the + module will be called redrat3. + +config IR_STREAMZAP + tristate "Streamzap PC Remote IR Receiver" + depends on USB_ARCH_HAS_HCD + depends on RC_CORE + select USB + ---help--- + Say Y here if you want to use a Streamzap PC Remote + Infrared Receiver. + + To compile this driver as a module, choose M here: the + module will be called streamzap. + +config IR_WINBOND_CIR + tristate "Winbond IR remote control" + depends on X86 && PNP + depends on RC_CORE + select NEW_LEDS + select LEDS_CLASS + select LEDS_TRIGGERS + select BITREVERSE + ---help--- + Say Y here if you want to use the IR remote functionality found + in some Winbond SuperI/O chips. Currently only the WPCD376I + chip is supported (included in some Intel Media series + motherboards). + + To compile this driver as a module, choose M here: the module will + be called winbond_cir. + +config RC_LOOPBACK + tristate "Remote Control Loopback Driver" + depends on RC_CORE + ---help--- + Say Y here if you want support for the remote control loopback + driver which allows TX data to be sent back as RX data. + This is mostly useful for debugging purposes. + + If you're not sure, select N here. + + To compile this driver as a module, choose M here: the module will + be called rc_loopback. + +endif #RC_CORE diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,15 @@ +config RC_MAP + tristate "Compile Remote Controller keymap modules" + depends on RC_CORE + default y + + ---help--- + This option enables the compilation of lots of Remote + Controller tables. They are short tables, but if you + don't use a remote controller, or prefer to load the + tables on userspace, you should disable it. + + The ir-keytable program, available at v4l-utils package + provide the tool and the same RC maps for load from + userspace. Its available at + http://git.linuxtv.org/v4l-utils diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,89 @@ +obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-alink-dtu-m.o \ + rc-anysee.o \ + rc-apac-viewcomp.o \ + rc-asus-pc39.o \ + rc-ati-tv-wonder-hd-600.o \ + rc-avermedia-a16d.o \ + rc-avermedia.o \ + rc-avermedia-cardbus.o \ + rc-avermedia-dvbt.o \ + rc-avermedia-m135a.o \ + rc-avermedia-m733a-rm-k6.o \ + rc-avermedia-rm-ks.o \ + rc-avertv-303.o \ + rc-azurewave-ad-tu700.o \ + rc-behold.o \ + rc-behold-columbus.o \ + rc-budget-ci-old.o \ + rc-cinergy-1400.o \ + rc-cinergy.o \ + rc-dib0700-nec.o \ + rc-dib0700-rc5.o \ + rc-digitalnow-tinytwin.o \ + rc-digittrade.o \ + rc-dm1105-nec.o \ + rc-dntv-live-dvb-t.o \ + rc-dntv-live-dvbt-pro.o \ + rc-em-terratec.o \ + rc-encore-enltv2.o \ + rc-encore-enltv.o \ + rc-encore-enltv-fm53.o \ + rc-evga-indtube.o \ + rc-eztv.o \ + rc-flydvb.o \ + rc-flyvideo.o \ + rc-fusionhdtv-mce.o \ + rc-gadmei-rm008z.o \ + rc-genius-tvgo-a11mce.o \ + rc-gotview7135.o \ + rc-imon-mce.o \ + rc-imon-pad.o \ + rc-iodata-bctv7e.o \ + rc-kaiomy.o \ + rc-kworld-315u.o \ + rc-kworld-plus-tv-analog.o \ + rc-leadtek-y04g0051.o \ + rc-lirc.o \ + rc-lme2510.o \ + rc-manli.o \ + rc-msi-digivox-ii.o \ + rc-msi-digivox-iii.o \ + rc-msi-tvanywhere.o \ + rc-msi-tvanywhere-plus.o \ + rc-nebula.o \ + rc-nec-terratec-cinergy-xs.o \ + rc-norwood.o \ + rc-npgtech.o \ + rc-pctv-sedna.o \ + rc-pinnacle-color.o \ + rc-pinnacle-grey.o \ + rc-pinnacle-pctv-hd.o \ + rc-pixelview.o \ + rc-pixelview-mk12.o \ + rc-pixelview-002t.o \ + rc-pixelview-new.o \ + rc-powercolor-real-angel.o \ + rc-proteus-2309.o \ + rc-purpletv.o \ + rc-pv951.o \ + rc-hauppauge.o \ + rc-rc6-mce.o \ + rc-real-audio-220-32-keys.o \ + rc-streamzap.o \ + rc-tbs-nec.o \ + rc-technisat-usb2.o \ + rc-terratec-cinergy-xs.o \ + rc-terratec-slim.o \ + rc-terratec-slim-2.o \ + rc-tevii-nec.o \ + rc-tivo.o \ + rc-total-media-in-hand.o \ + rc-trekstor.o \ + rc-tt-1500.o \ + rc-twinhan1027.o \ + rc-videomate-m1f.o \ + rc-videomate-s350.o \ + rc-videomate-tv-pvr.o \ + rc-winfast.o \ + rc-winfast-usbii-deluxe.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,89 @@ +/* adstech-dvb-t-pci.h - Keytable for adstech_dvb_t_pci Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* ADS Tech Instant TV DVB-T PCI Remote */ + +static struct rc_map_table adstech_dvb_t_pci[] = { + /* Keys 0 to 9 */ + { 0x4d, KEY_0 }, + { 0x57, KEY_1 }, + { 0x4f, KEY_2 }, + { 0x53, KEY_3 }, + { 0x56, KEY_4 }, + { 0x4e, KEY_5 }, + { 0x5e, KEY_6 }, + { 0x54, KEY_7 }, + { 0x4c, KEY_8 }, + { 0x5c, KEY_9 }, + + { 0x5b, KEY_POWER }, + { 0x5f, KEY_MUTE }, + { 0x55, KEY_GOTO }, + { 0x5d, KEY_SEARCH }, + { 0x17, KEY_EPG }, /* Guide */ + { 0x1f, KEY_MENU }, + { 0x0f, KEY_UP }, + { 0x46, KEY_DOWN }, + { 0x16, KEY_LEFT }, + { 0x1e, KEY_RIGHT }, + { 0x0e, KEY_SELECT }, /* Enter */ + { 0x5a, KEY_INFO }, + { 0x52, KEY_EXIT }, + { 0x59, KEY_PREVIOUS }, + { 0x51, KEY_NEXT }, + { 0x58, KEY_REWIND }, + { 0x50, KEY_FORWARD }, + { 0x44, KEY_PLAYPAUSE }, + { 0x07, KEY_STOP }, + { 0x1b, KEY_RECORD }, + { 0x13, KEY_TUNER }, /* Live */ + { 0x0a, KEY_A }, + { 0x12, KEY_B }, + { 0x03, KEY_RED }, /* 1 */ + { 0x01, KEY_GREEN }, /* 2 */ + { 0x00, KEY_YELLOW }, /* 3 */ + { 0x06, KEY_DVD }, + { 0x48, KEY_AUX }, /* Photo */ + { 0x40, KEY_VIDEO }, + { 0x19, KEY_AUDIO }, /* Music */ + { 0x0b, KEY_CHANNELUP }, + { 0x08, KEY_CHANNELDOWN }, + { 0x15, KEY_VOLUMEUP }, + { 0x1c, KEY_VOLUMEDOWN }, +}; + +static struct rc_map_list adstech_dvb_t_pci_map = { + .map = { + .scan = adstech_dvb_t_pci, + .size = ARRAY_SIZE(adstech_dvb_t_pci), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ADSTECH_DVB_T_PCI, + } +}; + +static int __init init_rc_map_adstech_dvb_t_pci(void) +{ + return rc_map_register(&adstech_dvb_t_pci_map); +} + +static void __exit exit_rc_map_adstech_dvb_t_pci(void) +{ + rc_map_unregister(&adstech_dvb_t_pci_map); +} + +module_init(init_rc_map_adstech_dvb_t_pci) +module_exit(exit_rc_map_adstech_dvb_t_pci) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-alink-dtu-m.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-alink-dtu-m.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-alink-dtu-m.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-alink-dtu-m.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * A-Link DTU(m) remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* A-Link DTU(m) slim remote, 6 rows, 3 columns. */ +static struct rc_map_table alink_dtu_m[] = { + { 0x0800, KEY_VOLUMEUP }, + { 0x0801, KEY_1 }, + { 0x0802, KEY_3 }, + { 0x0803, KEY_7 }, + { 0x0804, KEY_9 }, + { 0x0805, KEY_NEW }, /* symbol: PIP */ + { 0x0806, KEY_0 }, + { 0x0807, KEY_CHANNEL }, /* JUMP */ + { 0x080d, KEY_5 }, + { 0x080f, KEY_2 }, + { 0x0812, KEY_POWER2 }, + { 0x0814, KEY_CHANNELUP }, + { 0x0816, KEY_VOLUMEDOWN }, + { 0x0818, KEY_6 }, + { 0x081a, KEY_MUTE }, + { 0x081b, KEY_8 }, + { 0x081c, KEY_4 }, + { 0x081d, KEY_CHANNELDOWN }, +}; + +static struct rc_map_list alink_dtu_m_map = { + .map = { + .scan = alink_dtu_m, + .size = ARRAY_SIZE(alink_dtu_m), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_ALINK_DTU_M, + } +}; + +static int __init init_rc_map_alink_dtu_m(void) +{ + return rc_map_register(&alink_dtu_m_map); +} + +static void __exit exit_rc_map_alink_dtu_m(void) +{ + rc_map_unregister(&alink_dtu_m_map); +} + +module_init(init_rc_map_alink_dtu_m) +module_exit(exit_rc_map_alink_dtu_m) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-anysee.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-anysee.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-anysee.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-anysee.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Anysee remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table anysee[] = { + { 0x0800, KEY_0 }, + { 0x0801, KEY_1 }, + { 0x0802, KEY_2 }, + { 0x0803, KEY_3 }, + { 0x0804, KEY_4 }, + { 0x0805, KEY_5 }, + { 0x0806, KEY_6 }, + { 0x0807, KEY_7 }, + { 0x0808, KEY_8 }, + { 0x0809, KEY_9 }, + { 0x080a, KEY_POWER2 }, /* [red power button] */ + { 0x080b, KEY_VIDEO }, /* [*] MODE */ + { 0x080c, KEY_CHANNEL }, /* [symbol counterclockwise arrow] */ + { 0x080d, KEY_NEXT }, /* [>>|] */ + { 0x080e, KEY_MENU }, /* MENU */ + { 0x080f, KEY_EPG }, /* [EPG] */ + { 0x0810, KEY_CLEAR }, /* EXIT */ + { 0x0811, KEY_CHANNELUP }, + { 0x0812, KEY_VOLUMEDOWN }, + { 0x0813, KEY_VOLUMEUP }, + { 0x0814, KEY_CHANNELDOWN }, + { 0x0815, KEY_OK }, + { 0x0816, KEY_RADIO }, /* [symbol TV/radio] */ + { 0x0817, KEY_INFO }, /* [i] */ + { 0x0818, KEY_PREVIOUS }, /* [|<<] */ + { 0x0819, KEY_FAVORITES }, /* FAV. */ + { 0x081a, KEY_SUBTITLE }, /* Subtitle */ + { 0x081b, KEY_CAMERA }, /* [symbol camera] */ + { 0x081c, KEY_YELLOW }, + { 0x081d, KEY_RED }, + { 0x081e, KEY_LANGUAGE }, /* [symbol Second Audio Program] */ + { 0x081f, KEY_GREEN }, + { 0x0820, KEY_SLEEP }, /* Sleep */ + { 0x0821, KEY_SCREEN }, /* 16:9 / 4:3 */ + { 0x0822, KEY_ZOOM }, /* SIZE */ + { 0x0824, KEY_FN }, /* [F1] */ + { 0x0825, KEY_FN }, /* [F2] */ + { 0x0842, KEY_MUTE }, /* symbol mute */ + { 0x0844, KEY_BLUE }, + { 0x0847, KEY_TEXT }, /* TEXT */ + { 0x0848, KEY_STOP }, + { 0x0849, KEY_RECORD }, + { 0x0850, KEY_PLAY }, + { 0x0851, KEY_PAUSE }, +}; + +static struct rc_map_list anysee_map = { + .map = { + .scan = anysee, + .size = ARRAY_SIZE(anysee), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_ANYSEE, + } +}; + +static int __init init_rc_map_anysee(void) +{ + return rc_map_register(&anysee_map); +} + +static void __exit exit_rc_map_anysee(void) +{ + rc_map_unregister(&anysee_map); +} + +module_init(init_rc_map_anysee) +module_exit(exit_rc_map_anysee) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-apac-viewcomp.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-apac-viewcomp.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-apac-viewcomp.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-apac-viewcomp.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,80 @@ +/* apac-viewcomp.h - Keytable for apac_viewcomp Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Attila Kondoros */ + +static struct rc_map_table apac_viewcomp[] = { + + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + { 0x00, KEY_0 }, + { 0x17, KEY_LAST }, /* +100 */ + { 0x0a, KEY_LIST }, /* recall */ + + + { 0x1c, KEY_TUNER }, /* TV/FM */ + { 0x15, KEY_SEARCH }, /* scan */ + { 0x12, KEY_POWER }, /* power */ + { 0x1f, KEY_VOLUMEDOWN }, /* vol up */ + { 0x1b, KEY_VOLUMEUP }, /* vol down */ + { 0x1e, KEY_CHANNELDOWN }, /* chn up */ + { 0x1a, KEY_CHANNELUP }, /* chn down */ + + { 0x11, KEY_VIDEO }, /* video */ + { 0x0f, KEY_ZOOM }, /* full screen */ + { 0x13, KEY_MUTE }, /* mute/unmute */ + { 0x10, KEY_TEXT }, /* min */ + + { 0x0d, KEY_STOP }, /* freeze */ + { 0x0e, KEY_RECORD }, /* record */ + { 0x1d, KEY_PLAYPAUSE }, /* stop */ + { 0x19, KEY_PLAY }, /* play */ + + { 0x16, KEY_GOTO }, /* osd */ + { 0x14, KEY_REFRESH }, /* default */ + { 0x0c, KEY_KPPLUS }, /* fine tune >>>> */ + { 0x18, KEY_KPMINUS }, /* fine tune <<<< */ +}; + +static struct rc_map_list apac_viewcomp_map = { + .map = { + .scan = apac_viewcomp, + .size = ARRAY_SIZE(apac_viewcomp), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_APAC_VIEWCOMP, + } +}; + +static int __init init_rc_map_apac_viewcomp(void) +{ + return rc_map_register(&apac_viewcomp_map); +} + +static void __exit exit_rc_map_apac_viewcomp(void) +{ + rc_map_unregister(&apac_viewcomp_map); +} + +module_init(init_rc_map_apac_viewcomp) +module_exit(exit_rc_map_apac_viewcomp) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-asus-pc39.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-asus-pc39.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-asus-pc39.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-asus-pc39.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,91 @@ +/* asus-pc39.h - Keytable for asus_pc39 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Marc Fargas + * this is the remote control that comes with the asus p7131 + * which has a label saying is "Model PC-39" + */ + +static struct rc_map_table asus_pc39[] = { + /* Keys 0 to 9 */ + { 0x082a, KEY_0 }, + { 0x0816, KEY_1 }, + { 0x0812, KEY_2 }, + { 0x0814, KEY_3 }, + { 0x0836, KEY_4 }, + { 0x0832, KEY_5 }, + { 0x0834, KEY_6 }, + { 0x080e, KEY_7 }, + { 0x080a, KEY_8 }, + { 0x080c, KEY_9 }, + + { 0x0801, KEY_RADIO }, /* radio */ + { 0x083c, KEY_MENU }, /* dvd/menu */ + { 0x0815, KEY_VOLUMEUP }, + { 0x0826, KEY_VOLUMEDOWN }, + { 0x0808, KEY_UP }, + { 0x0804, KEY_DOWN }, + { 0x0818, KEY_LEFT }, + { 0x0810, KEY_RIGHT }, + { 0x081a, KEY_VIDEO }, /* video */ + { 0x0806, KEY_AUDIO }, /* music */ + + { 0x081e, KEY_TV }, /* tv */ + { 0x0822, KEY_EXIT }, /* back */ + { 0x0835, KEY_CHANNELUP }, /* channel / program + */ + { 0x0824, KEY_CHANNELDOWN }, /* channel / program - */ + { 0x0825, KEY_ENTER }, /* enter */ + + { 0x0839, KEY_PAUSE }, /* play/pause */ + { 0x0821, KEY_PREVIOUS }, /* rew */ + { 0x0819, KEY_NEXT }, /* forward */ + { 0x0831, KEY_REWIND }, /* backward << */ + { 0x0805, KEY_FASTFORWARD }, /* forward >> */ + { 0x0809, KEY_STOP }, + { 0x0811, KEY_RECORD }, /* recording */ + { 0x0829, KEY_POWER }, /* the button that reads "close" */ + + { 0x082e, KEY_ZOOM }, /* full screen */ + { 0x082c, KEY_MACRO }, /* recall */ + { 0x081c, KEY_HOME }, /* home */ + { 0x083a, KEY_PVR }, /* picture */ + { 0x0802, KEY_MUTE }, /* mute */ + { 0x083e, KEY_DVD }, /* dvd */ +}; + +static struct rc_map_list asus_pc39_map = { + .map = { + .scan = asus_pc39, + .size = ARRAY_SIZE(asus_pc39), + .rc_type = RC_TYPE_RC5, + .name = RC_MAP_ASUS_PC39, + } +}; + +static int __init init_rc_map_asus_pc39(void) +{ + return rc_map_register(&asus_pc39_map); +} + +static void __exit exit_rc_map_asus_pc39(void) +{ + rc_map_unregister(&asus_pc39_map); +} + +module_init(init_rc_map_asus_pc39) +module_exit(exit_rc_map_asus_pc39) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* ati-tv-wonder-hd-600.h - Keytable for ati_tv_wonder_hd_600 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* ATI TV Wonder HD 600 USB + Devin Heitmueller + */ + +static struct rc_map_table ati_tv_wonder_hd_600[] = { + { 0x00, KEY_RECORD}, /* Row 1 */ + { 0x01, KEY_PLAYPAUSE}, + { 0x02, KEY_STOP}, + { 0x03, KEY_POWER}, + { 0x04, KEY_PREVIOUS}, /* Row 2 */ + { 0x05, KEY_REWIND}, + { 0x06, KEY_FORWARD}, + { 0x07, KEY_NEXT}, + { 0x08, KEY_EPG}, /* Row 3 */ + { 0x09, KEY_HOME}, + { 0x0a, KEY_MENU}, + { 0x0b, KEY_CHANNELUP}, + { 0x0c, KEY_BACK}, /* Row 4 */ + { 0x0d, KEY_UP}, + { 0x0e, KEY_INFO}, + { 0x0f, KEY_CHANNELDOWN}, + { 0x10, KEY_LEFT}, /* Row 5 */ + { 0x11, KEY_SELECT}, + { 0x12, KEY_RIGHT}, + { 0x13, KEY_VOLUMEUP}, + { 0x14, KEY_LAST}, /* Row 6 */ + { 0x15, KEY_DOWN}, + { 0x16, KEY_MUTE}, + { 0x17, KEY_VOLUMEDOWN}, +}; + +static struct rc_map_list ati_tv_wonder_hd_600_map = { + .map = { + .scan = ati_tv_wonder_hd_600, + .size = ARRAY_SIZE(ati_tv_wonder_hd_600), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ATI_TV_WONDER_HD_600, + } +}; + +static int __init init_rc_map_ati_tv_wonder_hd_600(void) +{ + return rc_map_register(&ati_tv_wonder_hd_600_map); +} + +static void __exit exit_rc_map_ati_tv_wonder_hd_600(void) +{ + rc_map_unregister(&ati_tv_wonder_hd_600_map); +} + +module_init(init_rc_map_ati_tv_wonder_hd_600) +module_exit(exit_rc_map_ati_tv_wonder_hd_600) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-a16d.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-a16d.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-a16d.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-a16d.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,75 @@ +/* avermedia-a16d.h - Keytable for avermedia_a16d Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table avermedia_a16d[] = { + { 0x20, KEY_LIST}, + { 0x00, KEY_POWER}, + { 0x28, KEY_1}, + { 0x18, KEY_2}, + { 0x38, KEY_3}, + { 0x24, KEY_4}, + { 0x14, KEY_5}, + { 0x34, KEY_6}, + { 0x2c, KEY_7}, + { 0x1c, KEY_8}, + { 0x3c, KEY_9}, + { 0x12, KEY_SUBTITLE}, + { 0x22, KEY_0}, + { 0x32, KEY_REWIND}, + { 0x3a, KEY_SHUFFLE}, + { 0x02, KEY_PRINT}, + { 0x11, KEY_CHANNELDOWN}, + { 0x31, KEY_CHANNELUP}, + { 0x0c, KEY_ZOOM}, + { 0x1e, KEY_VOLUMEDOWN}, + { 0x3e, KEY_VOLUMEUP}, + { 0x0a, KEY_MUTE}, + { 0x04, KEY_AUDIO}, + { 0x26, KEY_RECORD}, + { 0x06, KEY_PLAY}, + { 0x36, KEY_STOP}, + { 0x16, KEY_PAUSE}, + { 0x2e, KEY_REWIND}, + { 0x0e, KEY_FASTFORWARD}, + { 0x30, KEY_TEXT}, + { 0x21, KEY_GREEN}, + { 0x01, KEY_BLUE}, + { 0x08, KEY_EPG}, + { 0x2a, KEY_MENU}, +}; + +static struct rc_map_list avermedia_a16d_map = { + .map = { + .scan = avermedia_a16d, + .size = ARRAY_SIZE(avermedia_a16d), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERMEDIA_A16D, + } +}; + +static int __init init_rc_map_avermedia_a16d(void) +{ + return rc_map_register(&avermedia_a16d_map); +} + +static void __exit exit_rc_map_avermedia_a16d(void) +{ + rc_map_unregister(&avermedia_a16d_map); +} + +module_init(init_rc_map_avermedia_a16d) +module_exit(exit_rc_map_avermedia_a16d) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,86 @@ +/* avermedia.h - Keytable for avermedia Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Alex Hermann */ + +static struct rc_map_table avermedia[] = { + { 0x28, KEY_1 }, + { 0x18, KEY_2 }, + { 0x38, KEY_3 }, + { 0x24, KEY_4 }, + { 0x14, KEY_5 }, + { 0x34, KEY_6 }, + { 0x2c, KEY_7 }, + { 0x1c, KEY_8 }, + { 0x3c, KEY_9 }, + { 0x22, KEY_0 }, + + { 0x20, KEY_TV }, /* TV/FM */ + { 0x10, KEY_CD }, /* CD */ + { 0x30, KEY_TEXT }, /* TELETEXT */ + { 0x00, KEY_POWER }, /* POWER */ + + { 0x08, KEY_VIDEO }, /* VIDEO */ + { 0x04, KEY_AUDIO }, /* AUDIO */ + { 0x0c, KEY_ZOOM }, /* FULL SCREEN */ + + { 0x12, KEY_SUBTITLE }, /* DISPLAY */ + { 0x32, KEY_REWIND }, /* LOOP */ + { 0x02, KEY_PRINT }, /* PREVIEW */ + + { 0x2a, KEY_SEARCH }, /* AUTOSCAN */ + { 0x1a, KEY_SLEEP }, /* FREEZE */ + { 0x3a, KEY_CAMERA }, /* SNAPSHOT */ + { 0x0a, KEY_MUTE }, /* MUTE */ + + { 0x26, KEY_RECORD }, /* RECORD */ + { 0x16, KEY_PAUSE }, /* PAUSE */ + { 0x36, KEY_STOP }, /* STOP */ + { 0x06, KEY_PLAY }, /* PLAY */ + + { 0x2e, KEY_RED }, /* RED */ + { 0x21, KEY_GREEN }, /* GREEN */ + { 0x0e, KEY_YELLOW }, /* YELLOW */ + { 0x01, KEY_BLUE }, /* BLUE */ + + { 0x1e, KEY_VOLUMEDOWN }, /* VOLUME- */ + { 0x3e, KEY_VOLUMEUP }, /* VOLUME+ */ + { 0x11, KEY_CHANNELDOWN }, /* CHANNEL/PAGE- */ + { 0x31, KEY_CHANNELUP } /* CHANNEL/PAGE+ */ +}; + +static struct rc_map_list avermedia_map = { + .map = { + .scan = avermedia, + .size = ARRAY_SIZE(avermedia), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERMEDIA, + } +}; + +static int __init init_rc_map_avermedia(void) +{ + return rc_map_register(&avermedia_map); +} + +static void __exit exit_rc_map_avermedia(void) +{ + rc_map_unregister(&avermedia_map); +} + +module_init(init_rc_map_avermedia) +module_exit(exit_rc_map_avermedia) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-cardbus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-cardbus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-cardbus.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-cardbus.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,97 @@ +/* avermedia-cardbus.h - Keytable for avermedia_cardbus Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Oldrich Jedlicka */ + +static struct rc_map_table avermedia_cardbus[] = { + { 0x00, KEY_POWER }, + { 0x01, KEY_TUNER }, /* TV/FM */ + { 0x03, KEY_TEXT }, /* Teletext */ + { 0x04, KEY_EPG }, + { 0x05, KEY_1 }, + { 0x06, KEY_2 }, + { 0x07, KEY_3 }, + { 0x08, KEY_AUDIO }, + { 0x09, KEY_4 }, + { 0x0a, KEY_5 }, + { 0x0b, KEY_6 }, + { 0x0c, KEY_ZOOM }, /* Full screen */ + { 0x0d, KEY_7 }, + { 0x0e, KEY_8 }, + { 0x0f, KEY_9 }, + { 0x10, KEY_PAGEUP }, /* 16-CH PREV */ + { 0x11, KEY_0 }, + { 0x12, KEY_INFO }, + { 0x13, KEY_AGAIN }, /* CH RTN - channel return */ + { 0x14, KEY_MUTE }, + { 0x15, KEY_EDIT }, /* Autoscan */ + { 0x17, KEY_SAVE }, /* Screenshot */ + { 0x18, KEY_PLAYPAUSE }, + { 0x19, KEY_RECORD }, + { 0x1a, KEY_PLAY }, + { 0x1b, KEY_STOP }, + { 0x1c, KEY_FASTFORWARD }, + { 0x1d, KEY_REWIND }, + { 0x1e, KEY_VOLUMEDOWN }, + { 0x1f, KEY_VOLUMEUP }, + { 0x22, KEY_SLEEP }, /* Sleep */ + { 0x23, KEY_ZOOM }, /* Aspect */ + { 0x26, KEY_SCREEN }, /* Pos */ + { 0x27, KEY_ANGLE }, /* Size */ + { 0x28, KEY_SELECT }, /* Select */ + { 0x29, KEY_BLUE }, /* Blue/Picture */ + { 0x2a, KEY_BACKSPACE }, /* Back */ + { 0x2b, KEY_VIDEO }, /* PIP (Picture-in-picture) */ + { 0x2c, KEY_DOWN }, + { 0x2e, KEY_DOT }, + { 0x2f, KEY_TV }, /* Live TV */ + { 0x32, KEY_LEFT }, + { 0x33, KEY_CLEAR }, /* Clear */ + { 0x35, KEY_RED }, /* Red/TV */ + { 0x36, KEY_UP }, + { 0x37, KEY_HOME }, /* Home */ + { 0x39, KEY_GREEN }, /* Green/Video */ + { 0x3d, KEY_YELLOW }, /* Yellow/Music */ + { 0x3e, KEY_OK }, /* Ok */ + { 0x3f, KEY_RIGHT }, + { 0x40, KEY_NEXT }, /* Next */ + { 0x41, KEY_PREVIOUS }, /* Previous */ + { 0x42, KEY_CHANNELDOWN }, /* Channel down */ + { 0x43, KEY_CHANNELUP }, /* Channel up */ +}; + +static struct rc_map_list avermedia_cardbus_map = { + .map = { + .scan = avermedia_cardbus, + .size = ARRAY_SIZE(avermedia_cardbus), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERMEDIA_CARDBUS, + } +}; + +static int __init init_rc_map_avermedia_cardbus(void) +{ + return rc_map_register(&avermedia_cardbus_map); +} + +static void __exit exit_rc_map_avermedia_cardbus(void) +{ + rc_map_unregister(&avermedia_cardbus_map); +} + +module_init(init_rc_map_avermedia_cardbus) +module_exit(exit_rc_map_avermedia_cardbus) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-dvbt.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-dvbt.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-dvbt.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-dvbt.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* avermedia-dvbt.h - Keytable for avermedia_dvbt Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Matt Jesson >' */ + { 0x3a, KEY_RECORD }, /* 'capture' */ + { 0x0a, KEY_MUTE }, /* 'mute' */ + { 0x2c, KEY_RECORD }, /* 'record' */ + { 0x1c, KEY_PAUSE }, /* 'pause' */ + { 0x3c, KEY_STOP }, /* 'stop' */ + { 0x0c, KEY_PLAY }, /* 'play' */ + { 0x2e, KEY_RED }, /* 'red' */ + { 0x01, KEY_BLUE }, /* 'blue' / 'cancel' */ + { 0x0e, KEY_YELLOW }, /* 'yellow' / 'ok' */ + { 0x21, KEY_GREEN }, /* 'green' */ + { 0x11, KEY_CHANNELDOWN }, /* 'channel -' */ + { 0x31, KEY_CHANNELUP }, /* 'channel +' */ + { 0x1e, KEY_VOLUMEDOWN }, /* 'volume -' */ + { 0x3e, KEY_VOLUMEUP }, /* 'volume +' */ +}; + +static struct rc_map_list avermedia_dvbt_map = { + .map = { + .scan = avermedia_dvbt, + .size = ARRAY_SIZE(avermedia_dvbt), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERMEDIA_DVBT, + } +}; + +static int __init init_rc_map_avermedia_dvbt(void) +{ + return rc_map_register(&avermedia_dvbt_map); +} + +static void __exit exit_rc_map_avermedia_dvbt(void) +{ + rc_map_unregister(&avermedia_dvbt_map); +} + +module_init(init_rc_map_avermedia_dvbt) +module_exit(exit_rc_map_avermedia_dvbt) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-m135a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-m135a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-m135a.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-m135a.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,147 @@ +/* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * Copyright (c) 2010 by Herton Ronaldo Krzesinski + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Avermedia M135A with RM-JX and RM-K6 remote controls + * + * On Avermedia M135A with IR model RM-JX, the same codes exist on both + * Positivo (BR) and original IR, initial version and remote control codes + * added by Mauro Carvalho Chehab + * + * Positivo also ships Avermedia M135A with model RM-K6, extra control + * codes added by Herton Ronaldo Krzesinski + */ + +static struct rc_map_table avermedia_m135a[] = { + /* RM-JX */ + { 0x0200, KEY_POWER2 }, + { 0x022e, KEY_DOT }, /* '.' */ + { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */ + + { 0x0205, KEY_1 }, + { 0x0206, KEY_2 }, + { 0x0207, KEY_3 }, + { 0x0209, KEY_4 }, + { 0x020a, KEY_5 }, + { 0x020b, KEY_6 }, + { 0x020d, KEY_7 }, + { 0x020e, KEY_8 }, + { 0x020f, KEY_9 }, + { 0x0211, KEY_0 }, + + { 0x0213, KEY_RIGHT }, /* -> or L */ + { 0x0212, KEY_LEFT }, /* <- or R */ + + { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */ + { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */ + + { 0x0303, KEY_CHANNELUP }, + { 0x0302, KEY_CHANNELDOWN }, + { 0x021f, KEY_VOLUMEUP }, + { 0x021e, KEY_VOLUMEDOWN }, + { 0x020c, KEY_ENTER }, /* Full Screen */ + + { 0x0214, KEY_MUTE }, + { 0x0208, KEY_AUDIO }, + + { 0x0203, KEY_TEXT }, /* Teletext */ + { 0x0204, KEY_EPG }, + { 0x022b, KEY_TV2 }, /* TV2 or PIP */ + + { 0x021d, KEY_RED }, + { 0x021c, KEY_YELLOW }, + { 0x0301, KEY_GREEN }, + { 0x0300, KEY_BLUE }, + + { 0x021a, KEY_PLAYPAUSE }, + { 0x0219, KEY_RECORD }, + { 0x0218, KEY_PLAY }, + { 0x021b, KEY_STOP }, + + /* RM-K6 */ + { 0x0401, KEY_POWER2 }, + { 0x0406, KEY_MUTE }, + { 0x0408, KEY_MODE }, /* TV/FM */ + + { 0x0409, KEY_1 }, + { 0x040a, KEY_2 }, + { 0x040b, KEY_3 }, + { 0x040c, KEY_4 }, + { 0x040d, KEY_5 }, + { 0x040e, KEY_6 }, + { 0x040f, KEY_7 }, + { 0x0410, KEY_8 }, + { 0x0411, KEY_9 }, + { 0x044c, KEY_DOT }, /* '.' */ + { 0x0412, KEY_0 }, + { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ + + { 0x0413, KEY_AUDIO }, + { 0x0440, KEY_SCREEN }, /* Full Screen toggle */ + { 0x0441, KEY_HOME }, + { 0x0442, KEY_BACK }, + { 0x0447, KEY_UP }, + { 0x0448, KEY_DOWN }, + { 0x0449, KEY_LEFT }, + { 0x044a, KEY_RIGHT }, + { 0x044b, KEY_OK }, + { 0x0404, KEY_VOLUMEUP }, + { 0x0405, KEY_VOLUMEDOWN }, + { 0x0402, KEY_CHANNELUP }, + { 0x0403, KEY_CHANNELDOWN }, + + { 0x0443, KEY_RED }, + { 0x0444, KEY_GREEN }, + { 0x0445, KEY_YELLOW }, + { 0x0446, KEY_BLUE }, + + { 0x0414, KEY_TEXT }, + { 0x0415, KEY_EPG }, + { 0x041a, KEY_TV2 }, /* PIP */ + { 0x041b, KEY_CAMERA }, /* Snapshot */ + + { 0x0417, KEY_RECORD }, + { 0x0416, KEY_PLAYPAUSE }, + { 0x0418, KEY_STOP }, + { 0x0419, KEY_PAUSE }, + + { 0x041f, KEY_PREVIOUS }, + { 0x041c, KEY_REWIND }, + { 0x041d, KEY_FORWARD }, + { 0x041e, KEY_NEXT }, +}; + +static struct rc_map_list avermedia_m135a_map = { + .map = { + .scan = avermedia_m135a, + .size = ARRAY_SIZE(avermedia_m135a), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_AVERMEDIA_M135A, + } +}; + +static int __init init_rc_map_avermedia_m135a(void) +{ + return rc_map_register(&avermedia_m135a_map); +} + +static void __exit exit_rc_map_avermedia_m135a(void) +{ + rc_map_unregister(&avermedia_m135a_map); +} + +module_init(init_rc_map_avermedia_m135a) +module_exit(exit_rc_map_avermedia_m135a) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,95 @@ +/* avermedia-m733a-rm-k6.h - Keytable for avermedia_m733a_rm_k6 Remote Controller + * + * Copyright (c) 2010 by Herton Ronaldo Krzesinski + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Avermedia M733A with IR model RM-K6 + * This is the stock remote controller used with Positivo machines with M733A + * Herton Ronaldo Krzesinski + */ + +static struct rc_map_table avermedia_m733a_rm_k6[] = { + { 0x0401, KEY_POWER2 }, + { 0x0406, KEY_MUTE }, + { 0x0408, KEY_MODE }, /* TV/FM */ + + { 0x0409, KEY_1 }, + { 0x040a, KEY_2 }, + { 0x040b, KEY_3 }, + { 0x040c, KEY_4 }, + { 0x040d, KEY_5 }, + { 0x040e, KEY_6 }, + { 0x040f, KEY_7 }, + { 0x0410, KEY_8 }, + { 0x0411, KEY_9 }, + { 0x044c, KEY_DOT }, /* '.' */ + { 0x0412, KEY_0 }, + { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ + + { 0x0413, KEY_AUDIO }, + { 0x0440, KEY_SCREEN }, /* Full Screen toggle */ + { 0x0441, KEY_HOME }, + { 0x0442, KEY_BACK }, + { 0x0447, KEY_UP }, + { 0x0448, KEY_DOWN }, + { 0x0449, KEY_LEFT }, + { 0x044a, KEY_RIGHT }, + { 0x044b, KEY_OK }, + { 0x0404, KEY_VOLUMEUP }, + { 0x0405, KEY_VOLUMEDOWN }, + { 0x0402, KEY_CHANNELUP }, + { 0x0403, KEY_CHANNELDOWN }, + + { 0x0443, KEY_RED }, + { 0x0444, KEY_GREEN }, + { 0x0445, KEY_YELLOW }, + { 0x0446, KEY_BLUE }, + + { 0x0414, KEY_TEXT }, + { 0x0415, KEY_EPG }, + { 0x041a, KEY_TV2 }, /* PIP */ + { 0x041b, KEY_CAMERA }, /* Snapshot */ + + { 0x0417, KEY_RECORD }, + { 0x0416, KEY_PLAYPAUSE }, + { 0x0418, KEY_STOP }, + { 0x0419, KEY_PAUSE }, + + { 0x041f, KEY_PREVIOUS }, + { 0x041c, KEY_REWIND }, + { 0x041d, KEY_FORWARD }, + { 0x041e, KEY_NEXT }, +}; + +static struct rc_map_list avermedia_m733a_rm_k6_map = { + .map = { + .scan = avermedia_m733a_rm_k6, + .size = ARRAY_SIZE(avermedia_m733a_rm_k6), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_AVERMEDIA_M733A_RM_K6, + } +}; + +static int __init init_rc_map_avermedia_m733a_rm_k6(void) +{ + return rc_map_register(&avermedia_m733a_rm_k6_map); +} + +static void __exit exit_rc_map_avermedia_m733a_rm_k6(void) +{ + rc_map_unregister(&avermedia_m733a_rm_k6_map); +} + +module_init(init_rc_map_avermedia_m733a_rm_k6) +module_exit(exit_rc_map_avermedia_m733a_rm_k6) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * AverMedia RM-KS remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* Initial keytable is from Jose Alberto Reguero + and Felipe Morales Moreno */ +/* FIXME: mappings are not 100% correct? */ +static struct rc_map_table avermedia_rm_ks[] = { + { 0x0501, KEY_POWER2 }, + { 0x0502, KEY_CHANNELUP }, + { 0x0503, KEY_CHANNELDOWN }, + { 0x0504, KEY_VOLUMEUP }, + { 0x0505, KEY_VOLUMEDOWN }, + { 0x0506, KEY_MUTE }, + { 0x0507, KEY_RIGHT }, + { 0x0508, KEY_RED }, + { 0x0509, KEY_1 }, + { 0x050a, KEY_2 }, + { 0x050b, KEY_3 }, + { 0x050c, KEY_4 }, + { 0x050d, KEY_5 }, + { 0x050e, KEY_6 }, + { 0x050f, KEY_7 }, + { 0x0510, KEY_8 }, + { 0x0511, KEY_9 }, + { 0x0512, KEY_0 }, + { 0x0513, KEY_AUDIO }, + { 0x0515, KEY_EPG }, + { 0x0516, KEY_PLAY }, + { 0x0517, KEY_RECORD }, + { 0x0518, KEY_STOP }, + { 0x051c, KEY_BACK }, + { 0x051d, KEY_FORWARD }, + { 0x054d, KEY_LEFT }, + { 0x0556, KEY_ZOOM }, +}; + +static struct rc_map_list avermedia_rm_ks_map = { + .map = { + .scan = avermedia_rm_ks, + .size = ARRAY_SIZE(avermedia_rm_ks), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_AVERMEDIA_RM_KS, + } +}; + +static int __init init_rc_map_avermedia_rm_ks(void) +{ + return rc_map_register(&avermedia_rm_ks_map); +} + +static void __exit exit_rc_map_avermedia_rm_ks(void) +{ + rc_map_unregister(&avermedia_rm_ks_map); +} + +module_init(init_rc_map_avermedia_rm_ks) +module_exit(exit_rc_map_avermedia_rm_ks) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avertv-303.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avertv-303.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avertv-303.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-avertv-303.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* avertv-303.h - Keytable for avertv_303 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* AVERTV STUDIO 303 Remote */ + +static struct rc_map_table avertv_303[] = { + { 0x2a, KEY_1 }, + { 0x32, KEY_2 }, + { 0x3a, KEY_3 }, + { 0x4a, KEY_4 }, + { 0x52, KEY_5 }, + { 0x5a, KEY_6 }, + { 0x6a, KEY_7 }, + { 0x72, KEY_8 }, + { 0x7a, KEY_9 }, + { 0x0e, KEY_0 }, + + { 0x02, KEY_POWER }, + { 0x22, KEY_VIDEO }, + { 0x42, KEY_AUDIO }, + { 0x62, KEY_ZOOM }, + { 0x0a, KEY_TV }, + { 0x12, KEY_CD }, + { 0x1a, KEY_TEXT }, + + { 0x16, KEY_SUBTITLE }, + { 0x1e, KEY_REWIND }, + { 0x06, KEY_PRINT }, + + { 0x2e, KEY_SEARCH }, + { 0x36, KEY_SLEEP }, + { 0x3e, KEY_SHUFFLE }, + { 0x26, KEY_MUTE }, + + { 0x4e, KEY_RECORD }, + { 0x56, KEY_PAUSE }, + { 0x5e, KEY_STOP }, + { 0x46, KEY_PLAY }, + + { 0x6e, KEY_RED }, + { 0x0b, KEY_GREEN }, + { 0x66, KEY_YELLOW }, + { 0x03, KEY_BLUE }, + + { 0x76, KEY_LEFT }, + { 0x7e, KEY_RIGHT }, + { 0x13, KEY_DOWN }, + { 0x1b, KEY_UP }, +}; + +static struct rc_map_list avertv_303_map = { + .map = { + .scan = avertv_303, + .size = ARRAY_SIZE(avertv_303), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERTV_303, + } +}; + +static int __init init_rc_map_avertv_303(void) +{ + return rc_map_register(&avertv_303_map); +} + +static void __exit exit_rc_map_avertv_303(void) +{ + rc_map_unregister(&avertv_303_map); +} + +module_init(init_rc_map_avertv_303) +module_exit(exit_rc_map_avertv_303) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,102 @@ +/* + * TwinHan AzureWave AD-TU700(704J) remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table azurewave_ad_tu700[] = { + { 0x0000, KEY_TAB }, /* Tab */ + { 0x0001, KEY_2 }, + { 0x0002, KEY_CHANNELDOWN }, + { 0x0003, KEY_1 }, + { 0x0004, KEY_MENU }, /* Record List */ + { 0x0005, KEY_CHANNELUP }, + { 0x0006, KEY_3 }, + { 0x0007, KEY_SLEEP }, /* Hibernate */ + { 0x0008, KEY_VIDEO }, /* A/V */ + { 0x0009, KEY_4 }, + { 0x000a, KEY_VOLUMEDOWN }, + { 0x000c, KEY_CANCEL }, /* Cancel */ + { 0x000d, KEY_7 }, + { 0x000e, KEY_AGAIN }, /* Recall */ + { 0x000f, KEY_TEXT }, /* Teletext */ + { 0x0010, KEY_MUTE }, + { 0x0011, KEY_RECORD }, + { 0x0012, KEY_FASTFORWARD }, /* FF >> */ + { 0x0013, KEY_BACK }, /* Back */ + { 0x0014, KEY_PLAY }, + { 0x0015, KEY_0 }, + { 0x0016, KEY_POWER2 }, /* [red power button] */ + { 0x0017, KEY_FAVORITES }, /* Favorite List */ + { 0x0018, KEY_RED }, + { 0x0019, KEY_8 }, + { 0x001a, KEY_STOP }, + { 0x001b, KEY_9 }, + { 0x001c, KEY_EPG }, /* Info/EPG */ + { 0x001d, KEY_5 }, + { 0x001e, KEY_VOLUMEUP }, + { 0x001f, KEY_6 }, + { 0x0040, KEY_REWIND }, /* FR << */ + { 0x0041, KEY_PREVIOUS }, /* Replay */ + { 0x0042, KEY_NEXT }, /* Skip */ + { 0x0043, KEY_SUBTITLE }, /* Subtitle / CC */ + { 0x0045, KEY_KPPLUS }, /* Zoom+ */ + { 0x0046, KEY_KPMINUS }, /* Zoom- */ + { 0x0047, KEY_NEW }, /* PIP */ + { 0x0048, KEY_INFO }, /* Preview */ + { 0x0049, KEY_MODE }, /* L/R */ + { 0x004a, KEY_CLEAR }, /* Clear */ + { 0x004b, KEY_UP }, /* up arrow */ + { 0x004c, KEY_PAUSE }, + { 0x004d, KEY_ZOOM }, /* Full Screen */ + { 0x004e, KEY_LEFT }, /* left arrow */ + { 0x004f, KEY_OK }, /* Enter / ok */ + { 0x0050, KEY_LANGUAGE }, /* SAP */ + { 0x0051, KEY_DOWN }, /* down arrow */ + { 0x0052, KEY_RIGHT }, /* right arrow */ + { 0x0053, KEY_GREEN }, + { 0x0054, KEY_CAMERA }, /* Capture */ + { 0x005e, KEY_YELLOW }, + { 0x005f, KEY_BLUE }, +}; + +static struct rc_map_list azurewave_ad_tu700_map = { + .map = { + .scan = azurewave_ad_tu700, + .size = ARRAY_SIZE(azurewave_ad_tu700), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_AZUREWAVE_AD_TU700, + } +}; + +static int __init init_rc_map_azurewave_ad_tu700(void) +{ + return rc_map_register(&azurewave_ad_tu700_map); +} + +static void __exit exit_rc_map_azurewave_ad_tu700(void) +{ + rc_map_unregister(&azurewave_ad_tu700_map); +} + +module_init(init_rc_map_azurewave_ad_tu700) +module_exit(exit_rc_map_azurewave_ad_tu700) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-behold.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-behold.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-behold.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-behold.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,141 @@ +/* behold.h - Keytable for behold Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Igor Kuznetsov + * Andrey J. Melnikov + * + * Keytable is used by BeholdTV 60x series, M6 series at + * least, and probably other cards too. + * The "ascii-art picture" below (in comments, first row + * is the keycode in hex, and subsequent row(s) shows + * the button labels (several variants when appropriate) + * helps to descide which keycodes to assign to the buttons. + */ + +static struct rc_map_table behold[] = { + + /* 0x1c 0x12 * + * TV/FM POWER * + * */ + { 0x6b861c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */ + { 0x6b8612, KEY_POWER }, + + /* 0x01 0x02 0x03 * + * 1 2 3 * + * * + * 0x04 0x05 0x06 * + * 4 5 6 * + * * + * 0x07 0x08 0x09 * + * 7 8 9 * + * */ + { 0x6b8601, KEY_1 }, + { 0x6b8602, KEY_2 }, + { 0x6b8603, KEY_3 }, + { 0x6b8604, KEY_4 }, + { 0x6b8605, KEY_5 }, + { 0x6b8606, KEY_6 }, + { 0x6b8607, KEY_7 }, + { 0x6b8608, KEY_8 }, + { 0x6b8609, KEY_9 }, + + /* 0x0a 0x00 0x17 * + * RECALL 0 MODE * + * */ + { 0x6b860a, KEY_AGAIN }, + { 0x6b8600, KEY_0 }, + { 0x6b8617, KEY_MODE }, + + /* 0x14 0x10 * + * ASPECT FULLSCREEN * + * */ + { 0x6b8614, KEY_SCREEN }, + { 0x6b8610, KEY_ZOOM }, + + /* 0x0b * + * Up * + * * + * 0x18 0x16 0x0c * + * Left Ok Right * + * * + * 0x015 * + * Down * + * */ + { 0x6b860b, KEY_CHANNELUP }, + { 0x6b8618, KEY_VOLUMEDOWN }, + { 0x6b8616, KEY_OK }, /* XXX KEY_ENTER */ + { 0x6b860c, KEY_VOLUMEUP }, + { 0x6b8615, KEY_CHANNELDOWN }, + + /* 0x11 0x0d * + * MUTE INFO * + * */ + { 0x6b8611, KEY_MUTE }, + { 0x6b860d, KEY_INFO }, + + /* 0x0f 0x1b 0x1a * + * RECORD PLAY/PAUSE STOP * + * * + * 0x0e 0x1f 0x1e * + *TELETEXT AUDIO SOURCE * + * RED YELLOW * + * */ + { 0x6b860f, KEY_RECORD }, + { 0x6b861b, KEY_PLAYPAUSE }, + { 0x6b861a, KEY_STOP }, + { 0x6b860e, KEY_TEXT }, + { 0x6b861f, KEY_RED }, /*XXX KEY_AUDIO */ + { 0x6b861e, KEY_VIDEO }, + + /* 0x1d 0x13 0x19 * + * SLEEP PREVIEW DVB * + * GREEN BLUE * + * */ + { 0x6b861d, KEY_SLEEP }, + { 0x6b8613, KEY_GREEN }, + { 0x6b8619, KEY_BLUE }, /* XXX KEY_SAT */ + + /* 0x58 0x5c * + * FREEZE SNAPSHOT * + * */ + { 0x6b8658, KEY_SLOW }, + { 0x6b865c, KEY_CAMERA }, + +}; + +static struct rc_map_list behold_map = { + .map = { + .scan = behold, + .size = ARRAY_SIZE(behold), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_BEHOLD, + } +}; + +static int __init init_rc_map_behold(void) +{ + return rc_map_register(&behold_map); +} + +static void __exit exit_rc_map_behold(void) +{ + rc_map_unregister(&behold_map); +} + +module_init(init_rc_map_behold) +module_exit(exit_rc_map_behold) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-behold-columbus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-behold-columbus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-behold-columbus.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-behold-columbus.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,108 @@ +/* behold-columbus.h - Keytable for behold_columbus Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Beholder Intl. Ltd. 2008 + * Dmitry Belimov d.belimov@google.com + * Keytable is used by BeholdTV Columbus + * The "ascii-art picture" below (in comments, first row + * is the keycode in hex, and subsequent row(s) shows + * the button labels (several variants when appropriate) + * helps to descide which keycodes to assign to the buttons. + */ + +static struct rc_map_table behold_columbus[] = { + + /* 0x13 0x11 0x1C 0x12 * + * Mute Source TV/FM Power * + * */ + + { 0x13, KEY_MUTE }, + { 0x11, KEY_VIDEO }, + { 0x1C, KEY_TUNER }, /* KEY_TV/KEY_RADIO */ + { 0x12, KEY_POWER }, + + /* 0x01 0x02 0x03 0x0D * + * 1 2 3 Stereo * + * * + * 0x04 0x05 0x06 0x19 * + * 4 5 6 Snapshot * + * * + * 0x07 0x08 0x09 0x10 * + * 7 8 9 Zoom * + * */ + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x0D, KEY_SETUP }, /* Setup key */ + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x19, KEY_CAMERA }, /* Snapshot key */ + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + { 0x10, KEY_ZOOM }, + + /* 0x0A 0x00 0x0B 0x0C * + * RECALL 0 ChannelUp VolumeUp * + * */ + { 0x0A, KEY_AGAIN }, + { 0x00, KEY_0 }, + { 0x0B, KEY_CHANNELUP }, + { 0x0C, KEY_VOLUMEUP }, + + /* 0x1B 0x1D 0x15 0x18 * + * Timeshift Record ChannelDown VolumeDown * + * */ + + { 0x1B, KEY_TIME }, + { 0x1D, KEY_RECORD }, + { 0x15, KEY_CHANNELDOWN }, + { 0x18, KEY_VOLUMEDOWN }, + + /* 0x0E 0x1E 0x0F 0x1A * + * Stop Pause Previouse Next * + * */ + + { 0x0E, KEY_STOP }, + { 0x1E, KEY_PAUSE }, + { 0x0F, KEY_PREVIOUS }, + { 0x1A, KEY_NEXT }, + +}; + +static struct rc_map_list behold_columbus_map = { + .map = { + .scan = behold_columbus, + .size = ARRAY_SIZE(behold_columbus), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_BEHOLD_COLUMBUS, + } +}; + +static int __init init_rc_map_behold_columbus(void) +{ + return rc_map_register(&behold_columbus_map); +} + +static void __exit exit_rc_map_behold_columbus(void) +{ + rc_map_unregister(&behold_columbus_map); +} + +module_init(init_rc_map_behold_columbus) +module_exit(exit_rc_map_behold_columbus) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-budget-ci-old.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-budget-ci-old.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-budget-ci-old.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-budget-ci-old.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,93 @@ +/* budget-ci-old.h - Keytable for budget_ci_old Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * From reading the following remotes: + * Zenith Universal 7 / TV Mode 807 / VCR Mode 837 + * Hauppauge (from NOVA-CI-s box product) + * This is a "middle of the road" approach, differences are noted + */ + +static struct rc_map_table budget_ci_old[] = { + { 0x00, KEY_0 }, + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + { 0x0a, KEY_ENTER }, + { 0x0b, KEY_RED }, + { 0x0c, KEY_POWER }, /* RADIO on Hauppauge */ + { 0x0d, KEY_MUTE }, + { 0x0f, KEY_A }, /* TV on Hauppauge */ + { 0x10, KEY_VOLUMEUP }, + { 0x11, KEY_VOLUMEDOWN }, + { 0x14, KEY_B }, + { 0x1c, KEY_UP }, + { 0x1d, KEY_DOWN }, + { 0x1e, KEY_OPTION }, /* RESERVED on Hauppauge */ + { 0x1f, KEY_BREAK }, + { 0x20, KEY_CHANNELUP }, + { 0x21, KEY_CHANNELDOWN }, + { 0x22, KEY_PREVIOUS }, /* Prev Ch on Zenith, SOURCE on Hauppauge */ + { 0x24, KEY_RESTART }, + { 0x25, KEY_OK }, + { 0x26, KEY_CYCLEWINDOWS }, /* MINIMIZE on Hauppauge */ + { 0x28, KEY_ENTER }, /* VCR mode on Zenith */ + { 0x29, KEY_PAUSE }, + { 0x2b, KEY_RIGHT }, + { 0x2c, KEY_LEFT }, + { 0x2e, KEY_MENU }, /* FULL SCREEN on Hauppauge */ + { 0x30, KEY_SLOW }, + { 0x31, KEY_PREVIOUS }, /* VCR mode on Zenith */ + { 0x32, KEY_REWIND }, + { 0x34, KEY_FASTFORWARD }, + { 0x35, KEY_PLAY }, + { 0x36, KEY_STOP }, + { 0x37, KEY_RECORD }, + { 0x38, KEY_TUNER }, /* TV/VCR on Zenith */ + { 0x3a, KEY_C }, + { 0x3c, KEY_EXIT }, + { 0x3d, KEY_POWER2 }, + { 0x3e, KEY_TUNER }, +}; + +static struct rc_map_list budget_ci_old_map = { + .map = { + .scan = budget_ci_old, + .size = ARRAY_SIZE(budget_ci_old), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_BUDGET_CI_OLD, + } +}; + +static int __init init_rc_map_budget_ci_old(void) +{ + return rc_map_register(&budget_ci_old_map); +} + +static void __exit exit_rc_map_budget_ci_old(void) +{ + rc_map_unregister(&budget_ci_old_map); +} + +module_init(init_rc_map_budget_ci_old) +module_exit(exit_rc_map_budget_ci_old) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-cinergy-1400.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-cinergy-1400.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-cinergy-1400.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-cinergy-1400.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,84 @@ +/* cinergy-1400.h - Keytable for cinergy_1400 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Cinergy 1400 DVB-T */ + +static struct rc_map_table cinergy_1400[] = { + { 0x01, KEY_POWER }, + { 0x02, KEY_1 }, + { 0x03, KEY_2 }, + { 0x04, KEY_3 }, + { 0x05, KEY_4 }, + { 0x06, KEY_5 }, + { 0x07, KEY_6 }, + { 0x08, KEY_7 }, + { 0x09, KEY_8 }, + { 0x0a, KEY_9 }, + { 0x0c, KEY_0 }, + + { 0x0b, KEY_VIDEO }, + { 0x0d, KEY_REFRESH }, + { 0x0e, KEY_SELECT }, + { 0x0f, KEY_EPG }, + { 0x10, KEY_UP }, + { 0x11, KEY_LEFT }, + { 0x12, KEY_OK }, + { 0x13, KEY_RIGHT }, + { 0x14, KEY_DOWN }, + { 0x15, KEY_TEXT }, + { 0x16, KEY_INFO }, + + { 0x17, KEY_RED }, + { 0x18, KEY_GREEN }, + { 0x19, KEY_YELLOW }, + { 0x1a, KEY_BLUE }, + + { 0x1b, KEY_CHANNELUP }, + { 0x1c, KEY_VOLUMEUP }, + { 0x1d, KEY_MUTE }, + { 0x1e, KEY_VOLUMEDOWN }, + { 0x1f, KEY_CHANNELDOWN }, + + { 0x40, KEY_PAUSE }, + { 0x4c, KEY_PLAY }, + { 0x58, KEY_RECORD }, + { 0x54, KEY_PREVIOUS }, + { 0x48, KEY_STOP }, + { 0x5c, KEY_NEXT }, +}; + +static struct rc_map_list cinergy_1400_map = { + .map = { + .scan = cinergy_1400, + .size = ARRAY_SIZE(cinergy_1400), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_CINERGY_1400, + } +}; + +static int __init init_rc_map_cinergy_1400(void) +{ + return rc_map_register(&cinergy_1400_map); +} + +static void __exit exit_rc_map_cinergy_1400(void) +{ + rc_map_unregister(&cinergy_1400_map); +} + +module_init(init_rc_map_cinergy_1400) +module_exit(exit_rc_map_cinergy_1400) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-cinergy.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-cinergy.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-cinergy.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-cinergy.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* cinergy.h - Keytable for cinergy Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table cinergy[] = { + { 0x00, KEY_0 }, + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + + { 0x0a, KEY_POWER }, + { 0x0b, KEY_MEDIA }, /* app */ + { 0x0c, KEY_ZOOM }, /* zoom/fullscreen */ + { 0x0d, KEY_CHANNELUP }, /* channel */ + { 0x0e, KEY_CHANNELDOWN }, /* channel- */ + { 0x0f, KEY_VOLUMEUP }, + { 0x10, KEY_VOLUMEDOWN }, + { 0x11, KEY_TUNER }, /* AV */ + { 0x12, KEY_NUMLOCK }, /* -/-- */ + { 0x13, KEY_AUDIO }, /* audio */ + { 0x14, KEY_MUTE }, + { 0x15, KEY_UP }, + { 0x16, KEY_DOWN }, + { 0x17, KEY_LEFT }, + { 0x18, KEY_RIGHT }, + { 0x19, BTN_LEFT, }, + { 0x1a, BTN_RIGHT, }, + { 0x1b, KEY_WWW }, /* text */ + { 0x1c, KEY_REWIND }, + { 0x1d, KEY_FORWARD }, + { 0x1e, KEY_RECORD }, + { 0x1f, KEY_PLAY }, + { 0x20, KEY_PREVIOUSSONG }, + { 0x21, KEY_NEXTSONG }, + { 0x22, KEY_PAUSE }, + { 0x23, KEY_STOP }, +}; + +static struct rc_map_list cinergy_map = { + .map = { + .scan = cinergy, + .size = ARRAY_SIZE(cinergy), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_CINERGY, + } +}; + +static int __init init_rc_map_cinergy(void) +{ + return rc_map_register(&cinergy_map); +} + +static void __exit exit_rc_map_cinergy(void) +{ + rc_map_unregister(&cinergy_map); +} + +module_init(init_rc_map_cinergy) +module_exit(exit_rc_map_cinergy) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dib0700-nec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dib0700-nec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dib0700-nec.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dib0700-nec.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,124 @@ +/* rc-dvb0700-big.c - Keytable for devices in dvb0700 + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * TODO: This table is a real mess, as it merges RC codes from several + * devices into a big table. It also has both RC-5 and NEC codes inside. + * It should be broken into small tables, and the protocols should properly + * be indentificated. + * + * The table were imported from dib0700_devices.c. + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table dib0700_nec_table[] = { + /* Key codes for the Pixelview SBTVD remote */ + { 0x866b13, KEY_MUTE }, + { 0x866b12, KEY_POWER }, + { 0x866b01, KEY_1 }, + { 0x866b02, KEY_2 }, + { 0x866b03, KEY_3 }, + { 0x866b04, KEY_4 }, + { 0x866b05, KEY_5 }, + { 0x866b06, KEY_6 }, + { 0x866b07, KEY_7 }, + { 0x866b08, KEY_8 }, + { 0x866b09, KEY_9 }, + { 0x866b00, KEY_0 }, + { 0x866b0d, KEY_CHANNELUP }, + { 0x866b19, KEY_CHANNELDOWN }, + { 0x866b10, KEY_VOLUMEUP }, + { 0x866b0c, KEY_VOLUMEDOWN }, + + { 0x866b0a, KEY_CAMERA }, + { 0x866b0b, KEY_ZOOM }, + { 0x866b1b, KEY_BACKSPACE }, + { 0x866b15, KEY_ENTER }, + + { 0x866b1d, KEY_UP }, + { 0x866b1e, KEY_DOWN }, + { 0x866b0e, KEY_LEFT }, + { 0x866b0f, KEY_RIGHT }, + + { 0x866b18, KEY_RECORD }, + { 0x866b1a, KEY_STOP }, + + /* Key codes for the EvolutePC TVWay+ remote */ + { 0x7a00, KEY_MENU }, + { 0x7a01, KEY_RECORD }, + { 0x7a02, KEY_PLAY }, + { 0x7a03, KEY_STOP }, + { 0x7a10, KEY_CHANNELUP }, + { 0x7a11, KEY_CHANNELDOWN }, + { 0x7a12, KEY_VOLUMEUP }, + { 0x7a13, KEY_VOLUMEDOWN }, + { 0x7a40, KEY_POWER }, + { 0x7a41, KEY_MUTE }, + + /* Key codes for the Elgato EyeTV Diversity silver remote */ + { 0x4501, KEY_POWER }, + { 0x4502, KEY_MUTE }, + { 0x4503, KEY_1 }, + { 0x4504, KEY_2 }, + { 0x4505, KEY_3 }, + { 0x4506, KEY_4 }, + { 0x4507, KEY_5 }, + { 0x4508, KEY_6 }, + { 0x4509, KEY_7 }, + { 0x450a, KEY_8 }, + { 0x450b, KEY_9 }, + { 0x450c, KEY_LAST }, + { 0x450d, KEY_0 }, + { 0x450e, KEY_ENTER }, + { 0x450f, KEY_RED }, + { 0x4510, KEY_CHANNELUP }, + { 0x4511, KEY_GREEN }, + { 0x4512, KEY_VOLUMEDOWN }, + { 0x4513, KEY_OK }, + { 0x4514, KEY_VOLUMEUP }, + { 0x4515, KEY_YELLOW }, + { 0x4516, KEY_CHANNELDOWN }, + { 0x4517, KEY_BLUE }, + { 0x4518, KEY_LEFT }, /* Skip backwards */ + { 0x4519, KEY_PLAYPAUSE }, + { 0x451a, KEY_RIGHT }, /* Skip forward */ + { 0x451b, KEY_REWIND }, + { 0x451c, KEY_L }, /* Live */ + { 0x451d, KEY_FASTFORWARD }, + { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */ + { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */ + { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */ + { 0x4541, KEY_SCREEN }, /* Full screen toggle, 'Hold' for Teletext */ + { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */ +}; + +static struct rc_map_list dib0700_nec_map = { + .map = { + .scan = dib0700_nec_table, + .size = ARRAY_SIZE(dib0700_nec_table), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_DIB0700_NEC_TABLE, + } +}; + +static int __init init_rc_map(void) +{ + return rc_map_register(&dib0700_nec_map); +} + +static void __exit exit_rc_map(void) +{ + rc_map_unregister(&dib0700_nec_map); +} + +module_init(init_rc_map) +module_exit(exit_rc_map) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dib0700-rc5.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dib0700-rc5.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dib0700-rc5.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dib0700-rc5.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,235 @@ +/* rc-dvb0700-big.c - Keytable for devices in dvb0700 + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * TODO: This table is a real mess, as it merges RC codes from several + * devices into a big table. It also has both RC-5 and NEC codes inside. + * It should be broken into small tables, and the protocols should properly + * be indentificated. + * + * The table were imported from dib0700_devices.c. + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table dib0700_rc5_table[] = { + /* Key codes for the tiny Pinnacle remote*/ + { 0x0700, KEY_MUTE }, + { 0x0701, KEY_MENU }, /* Pinnacle logo */ + { 0x0739, KEY_POWER }, + { 0x0703, KEY_VOLUMEUP }, + { 0x0709, KEY_VOLUMEDOWN }, + { 0x0706, KEY_CHANNELUP }, + { 0x070c, KEY_CHANNELDOWN }, + { 0x070f, KEY_1 }, + { 0x0715, KEY_2 }, + { 0x0710, KEY_3 }, + { 0x0718, KEY_4 }, + { 0x071b, KEY_5 }, + { 0x071e, KEY_6 }, + { 0x0711, KEY_7 }, + { 0x0721, KEY_8 }, + { 0x0712, KEY_9 }, + { 0x0727, KEY_0 }, + { 0x0724, KEY_SCREEN }, /* 'Square' key */ + { 0x072a, KEY_TEXT }, /* 'T' key */ + { 0x072d, KEY_REWIND }, + { 0x0730, KEY_PLAY }, + { 0x0733, KEY_FASTFORWARD }, + { 0x0736, KEY_RECORD }, + { 0x073c, KEY_STOP }, + { 0x073f, KEY_CANCEL }, /* '?' key */ + + /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */ + { 0xeb01, KEY_POWER }, + { 0xeb02, KEY_1 }, + { 0xeb03, KEY_2 }, + { 0xeb04, KEY_3 }, + { 0xeb05, KEY_4 }, + { 0xeb06, KEY_5 }, + { 0xeb07, KEY_6 }, + { 0xeb08, KEY_7 }, + { 0xeb09, KEY_8 }, + { 0xeb0a, KEY_9 }, + { 0xeb0b, KEY_VIDEO }, + { 0xeb0c, KEY_0 }, + { 0xeb0d, KEY_REFRESH }, + { 0xeb0f, KEY_EPG }, + { 0xeb10, KEY_UP }, + { 0xeb11, KEY_LEFT }, + { 0xeb12, KEY_OK }, + { 0xeb13, KEY_RIGHT }, + { 0xeb14, KEY_DOWN }, + { 0xeb16, KEY_INFO }, + { 0xeb17, KEY_RED }, + { 0xeb18, KEY_GREEN }, + { 0xeb19, KEY_YELLOW }, + { 0xeb1a, KEY_BLUE }, + { 0xeb1b, KEY_CHANNELUP }, + { 0xeb1c, KEY_VOLUMEUP }, + { 0xeb1d, KEY_MUTE }, + { 0xeb1e, KEY_VOLUMEDOWN }, + { 0xeb1f, KEY_CHANNELDOWN }, + { 0xeb40, KEY_PAUSE }, + { 0xeb41, KEY_HOME }, + { 0xeb42, KEY_MENU }, /* DVD Menu */ + { 0xeb43, KEY_SUBTITLE }, + { 0xeb44, KEY_TEXT }, /* Teletext */ + { 0xeb45, KEY_DELETE }, + { 0xeb46, KEY_TV }, + { 0xeb47, KEY_DVD }, + { 0xeb48, KEY_STOP }, + { 0xeb49, KEY_VIDEO }, + { 0xeb4a, KEY_AUDIO }, /* Music */ + { 0xeb4b, KEY_SCREEN }, /* Pic */ + { 0xeb4c, KEY_PLAY }, + { 0xeb4d, KEY_BACK }, + { 0xeb4e, KEY_REWIND }, + { 0xeb4f, KEY_FASTFORWARD }, + { 0xeb54, KEY_PREVIOUS }, + { 0xeb58, KEY_RECORD }, + { 0xeb5c, KEY_NEXT }, + + /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */ + { 0x1e00, KEY_0 }, + { 0x1e01, KEY_1 }, + { 0x1e02, KEY_2 }, + { 0x1e03, KEY_3 }, + { 0x1e04, KEY_4 }, + { 0x1e05, KEY_5 }, + { 0x1e06, KEY_6 }, + { 0x1e07, KEY_7 }, + { 0x1e08, KEY_8 }, + { 0x1e09, KEY_9 }, + { 0x1e0a, KEY_KPASTERISK }, + { 0x1e0b, KEY_RED }, + { 0x1e0c, KEY_RADIO }, + { 0x1e0d, KEY_MENU }, + { 0x1e0e, KEY_GRAVE }, /* # */ + { 0x1e0f, KEY_MUTE }, + { 0x1e10, KEY_VOLUMEUP }, + { 0x1e11, KEY_VOLUMEDOWN }, + { 0x1e12, KEY_CHANNEL }, + { 0x1e14, KEY_UP }, + { 0x1e15, KEY_DOWN }, + { 0x1e16, KEY_LEFT }, + { 0x1e17, KEY_RIGHT }, + { 0x1e18, KEY_VIDEO }, + { 0x1e19, KEY_AUDIO }, + { 0x1e1a, KEY_MEDIA }, + { 0x1e1b, KEY_EPG }, + { 0x1e1c, KEY_TV }, + { 0x1e1e, KEY_NEXT }, + { 0x1e1f, KEY_BACK }, + { 0x1e20, KEY_CHANNELUP }, + { 0x1e21, KEY_CHANNELDOWN }, + { 0x1e24, KEY_LAST }, /* Skip backwards */ + { 0x1e25, KEY_OK }, + { 0x1e29, KEY_BLUE}, + { 0x1e2e, KEY_GREEN }, + { 0x1e30, KEY_PAUSE }, + { 0x1e32, KEY_REWIND }, + { 0x1e34, KEY_FASTFORWARD }, + { 0x1e35, KEY_PLAY }, + { 0x1e36, KEY_STOP }, + { 0x1e37, KEY_RECORD }, + { 0x1e38, KEY_YELLOW }, + { 0x1e3b, KEY_GOTO }, + { 0x1e3d, KEY_POWER }, + + /* Key codes for the Leadtek Winfast DTV Dongle */ + { 0x0042, KEY_POWER }, + { 0x077c, KEY_TUNER }, + { 0x0f4e, KEY_PRINT }, /* PREVIEW */ + { 0x0840, KEY_SCREEN }, /* full screen toggle*/ + { 0x0f71, KEY_DOT }, /* frequency */ + { 0x0743, KEY_0 }, + { 0x0c41, KEY_1 }, + { 0x0443, KEY_2 }, + { 0x0b7f, KEY_3 }, + { 0x0e41, KEY_4 }, + { 0x0643, KEY_5 }, + { 0x097f, KEY_6 }, + { 0x0d7e, KEY_7 }, + { 0x057c, KEY_8 }, + { 0x0a40, KEY_9 }, + { 0x0e4e, KEY_CLEAR }, + { 0x047c, KEY_CHANNEL }, /* show channel number */ + { 0x0f41, KEY_LAST }, /* recall */ + { 0x0342, KEY_MUTE }, + { 0x064c, KEY_RESERVED }, /* PIP button*/ + { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */ + { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */ + { 0x0b70, KEY_RECORD }, + { 0x037d, KEY_VOLUMEUP }, + { 0x017d, KEY_VOLUMEDOWN }, + { 0x0242, KEY_CHANNELUP }, + { 0x007d, KEY_CHANNELDOWN }, + + /* Key codes for Nova-TD "credit card" remote control. */ + { 0x1d00, KEY_0 }, + { 0x1d01, KEY_1 }, + { 0x1d02, KEY_2 }, + { 0x1d03, KEY_3 }, + { 0x1d04, KEY_4 }, + { 0x1d05, KEY_5 }, + { 0x1d06, KEY_6 }, + { 0x1d07, KEY_7 }, + { 0x1d08, KEY_8 }, + { 0x1d09, KEY_9 }, + { 0x1d0a, KEY_TEXT }, + { 0x1d0d, KEY_MENU }, + { 0x1d0f, KEY_MUTE }, + { 0x1d10, KEY_VOLUMEUP }, + { 0x1d11, KEY_VOLUMEDOWN }, + { 0x1d12, KEY_CHANNEL }, + { 0x1d14, KEY_UP }, + { 0x1d15, KEY_DOWN }, + { 0x1d16, KEY_LEFT }, + { 0x1d17, KEY_RIGHT }, + { 0x1d1c, KEY_TV }, + { 0x1d1e, KEY_NEXT }, + { 0x1d1f, KEY_BACK }, + { 0x1d20, KEY_CHANNELUP }, + { 0x1d21, KEY_CHANNELDOWN }, + { 0x1d24, KEY_LAST }, + { 0x1d25, KEY_OK }, + { 0x1d30, KEY_PAUSE }, + { 0x1d32, KEY_REWIND }, + { 0x1d34, KEY_FASTFORWARD }, + { 0x1d35, KEY_PLAY }, + { 0x1d36, KEY_STOP }, + { 0x1d37, KEY_RECORD }, + { 0x1d3b, KEY_GOTO }, + { 0x1d3d, KEY_POWER }, +}; + +static struct rc_map_list dib0700_rc5_map = { + .map = { + .scan = dib0700_rc5_table, + .size = ARRAY_SIZE(dib0700_rc5_table), + .rc_type = RC_TYPE_RC5, + .name = RC_MAP_DIB0700_RC5_TABLE, + } +}; + +static int __init init_rc_map(void) +{ + return rc_map_register(&dib0700_rc5_map); +} + +static void __exit exit_rc_map(void) +{ + rc_map_unregister(&dib0700_rc5_map); +} + +module_init(init_rc_map) +module_exit(exit_rc_map) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * DigitalNow TinyTwin remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table digitalnow_tinytwin[] = { + { 0x0000, KEY_MUTE }, /* [symbol speaker] */ + { 0x0001, KEY_VOLUMEUP }, + { 0x0002, KEY_POWER2 }, /* TV [power button] */ + { 0x0003, KEY_2 }, + { 0x0004, KEY_3 }, + { 0x0005, KEY_4 }, + { 0x0006, KEY_6 }, + { 0x0007, KEY_7 }, + { 0x0008, KEY_8 }, + { 0x0009, KEY_NUMERIC_STAR }, /* [*] */ + { 0x000a, KEY_0 }, + { 0x000b, KEY_NUMERIC_POUND }, /* [#] */ + { 0x000c, KEY_RIGHT }, /* [right arrow] */ + { 0x000d, KEY_HOMEPAGE }, /* [symbol home] Start */ + { 0x000e, KEY_RED }, /* [red] Videos */ + { 0x0010, KEY_POWER }, /* PC [power button] */ + { 0x0011, KEY_YELLOW }, /* [yellow] Pictures */ + { 0x0012, KEY_DOWN }, /* [down arrow] */ + { 0x0013, KEY_GREEN }, /* [green] Music */ + { 0x0014, KEY_CYCLEWINDOWS }, /* BACK */ + { 0x0015, KEY_FAVORITES }, /* MORE */ + { 0x0016, KEY_UP }, /* [up arrow] */ + { 0x0017, KEY_LEFT }, /* [left arrow] */ + { 0x0018, KEY_OK }, /* OK */ + { 0x0019, KEY_BLUE }, /* [blue] MyTV */ + { 0x001a, KEY_REWIND }, /* REW [<<] */ + { 0x001b, KEY_PLAY }, /* PLAY */ + { 0x001c, KEY_5 }, + { 0x001d, KEY_9 }, + { 0x001e, KEY_VOLUMEDOWN }, + { 0x001f, KEY_1 }, + { 0x0040, KEY_STOP }, /* STOP */ + { 0x0042, KEY_PAUSE }, /* PAUSE */ + { 0x0043, KEY_SCREEN }, /* Aspect */ + { 0x0044, KEY_FORWARD }, /* FWD [>>] */ + { 0x0045, KEY_NEXT }, /* SKIP */ + { 0x0048, KEY_RECORD }, /* RECORD */ + { 0x0049, KEY_VIDEO }, /* RTV */ + { 0x004a, KEY_EPG }, /* Guide */ + { 0x004b, KEY_CHANNELUP }, + { 0x004c, KEY_HELP }, /* Help */ + { 0x004d, KEY_RADIO }, /* Radio */ + { 0x004f, KEY_CHANNELDOWN }, + { 0x0050, KEY_DVD }, /* DVD */ + { 0x0051, KEY_AUDIO }, /* Audio */ + { 0x0052, KEY_TITLE }, /* Title */ + { 0x0053, KEY_NEW }, /* [symbol PIP?] */ + { 0x0057, KEY_MENU }, /* Mouse */ + { 0x005a, KEY_PREVIOUS }, /* REPLAY */ +}; + +static struct rc_map_list digitalnow_tinytwin_map = { + .map = { + .scan = digitalnow_tinytwin, + .size = ARRAY_SIZE(digitalnow_tinytwin), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_DIGITALNOW_TINYTWIN, + } +}; + +static int __init init_rc_map_digitalnow_tinytwin(void) +{ + return rc_map_register(&digitalnow_tinytwin_map); +} + +static void __exit exit_rc_map_digitalnow_tinytwin(void) +{ + rc_map_unregister(&digitalnow_tinytwin_map); +} + +module_init(init_rc_map_digitalnow_tinytwin) +module_exit(exit_rc_map_digitalnow_tinytwin) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-digittrade.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-digittrade.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-digittrade.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-digittrade.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Digittrade DVB-T USB Stick remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* Digittrade DVB-T USB Stick remote controller. */ +/* Imported from af9015.h. + Initial keytable was from Alain Kalker */ + +/* Digittrade DVB-T USB Stick */ +static struct rc_map_table digittrade[] = { + { 0x0000, KEY_9 }, + { 0x0001, KEY_EPG }, /* EPG */ + { 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */ + { 0x0003, KEY_TEXT }, /* TELETEXT */ + { 0x0004, KEY_8 }, + { 0x0005, KEY_MUTE }, /* MUTE */ + { 0x0006, KEY_POWER2 }, /* POWER */ + { 0x0009, KEY_ZOOM }, /* FULLSCREEN */ + { 0x000a, KEY_RECORD }, /* RECORD */ + { 0x000d, KEY_SUBTITLE }, /* SUBTITLE */ + { 0x000e, KEY_STOP }, /* STOP */ + { 0x0010, KEY_OK }, /* RETURN */ + { 0x0011, KEY_2 }, + { 0x0012, KEY_4 }, + { 0x0015, KEY_3 }, + { 0x0016, KEY_5 }, + { 0x0017, KEY_CHANNELDOWN }, /* Ch Dn */ + { 0x0019, KEY_CHANNELUP }, /* CH Up */ + { 0x001a, KEY_PAUSE }, /* PAUSE */ + { 0x001b, KEY_1 }, + { 0x001d, KEY_AUDIO }, /* DUAL SOUND */ + { 0x001e, KEY_PLAY }, /* PLAY */ + { 0x001f, KEY_CAMERA }, /* SNAPSHOT */ + { 0x0040, KEY_VOLUMEUP }, /* Vol Up */ + { 0x0048, KEY_7 }, + { 0x004c, KEY_6 }, + { 0x004d, KEY_PLAYPAUSE }, /* TIMESHIFT */ + { 0x0054, KEY_0 }, +}; + +static struct rc_map_list digittrade_map = { + .map = { + .scan = digittrade, + .size = ARRAY_SIZE(digittrade), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_DIGITTRADE, + } +}; + +static int __init init_rc_map_digittrade(void) +{ + return rc_map_register(&digittrade_map); +} + +static void __exit exit_rc_map_digittrade(void) +{ + rc_map_unregister(&digittrade_map); +} + +module_init(init_rc_map_digittrade) +module_exit(exit_rc_map_digittrade) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dm1105-nec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dm1105-nec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dm1105-nec.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dm1105-nec.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,76 @@ +/* dm1105-nec.h - Keytable for dm1105_nec Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* DVBWorld remotes + Igor M. Liplianin + */ + +static struct rc_map_table dm1105_nec[] = { + { 0x0a, KEY_POWER2}, /* power */ + { 0x0c, KEY_MUTE}, /* mute */ + { 0x11, KEY_1}, + { 0x12, KEY_2}, + { 0x13, KEY_3}, + { 0x14, KEY_4}, + { 0x15, KEY_5}, + { 0x16, KEY_6}, + { 0x17, KEY_7}, + { 0x18, KEY_8}, + { 0x19, KEY_9}, + { 0x10, KEY_0}, + { 0x1c, KEY_CHANNELUP}, /* ch+ */ + { 0x0f, KEY_CHANNELDOWN}, /* ch- */ + { 0x1a, KEY_VOLUMEUP}, /* vol+ */ + { 0x0e, KEY_VOLUMEDOWN}, /* vol- */ + { 0x04, KEY_RECORD}, /* rec */ + { 0x09, KEY_CHANNEL}, /* fav */ + { 0x08, KEY_BACKSPACE}, /* rewind */ + { 0x07, KEY_FASTFORWARD}, /* fast */ + { 0x0b, KEY_PAUSE}, /* pause */ + { 0x02, KEY_ESC}, /* cancel */ + { 0x03, KEY_TAB}, /* tab */ + { 0x00, KEY_UP}, /* up */ + { 0x1f, KEY_ENTER}, /* ok */ + { 0x01, KEY_DOWN}, /* down */ + { 0x05, KEY_RECORD}, /* cap */ + { 0x06, KEY_STOP}, /* stop */ + { 0x40, KEY_ZOOM}, /* full */ + { 0x1e, KEY_TV}, /* tvmode */ + { 0x1b, KEY_B}, /* recall */ +}; + +static struct rc_map_list dm1105_nec_map = { + .map = { + .scan = dm1105_nec, + .size = ARRAY_SIZE(dm1105_nec), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_DM1105_NEC, + } +}; + +static int __init init_rc_map_dm1105_nec(void) +{ + return rc_map_register(&dm1105_nec_map); +} + +static void __exit exit_rc_map_dm1105_nec(void) +{ + rc_map_unregister(&dm1105_nec_map); +} + +module_init(init_rc_map_dm1105_nec) +module_exit(exit_rc_map_dm1105_nec) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* dntv-live-dvb-t.h - Keytable for dntv_live_dvb_t Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* DigitalNow DNTV Live DVB-T Remote */ + +static struct rc_map_table dntv_live_dvb_t[] = { + { 0x00, KEY_ESC }, /* 'go up a level?' */ + /* Keys 0 to 9 */ + { 0x0a, KEY_0 }, + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + + { 0x0b, KEY_TUNER }, /* tv/fm */ + { 0x0c, KEY_SEARCH }, /* scan */ + { 0x0d, KEY_STOP }, + { 0x0e, KEY_PAUSE }, + { 0x0f, KEY_VIDEO }, /* source */ + + { 0x10, KEY_MUTE }, + { 0x11, KEY_REWIND }, /* backward << */ + { 0x12, KEY_POWER }, + { 0x13, KEY_CAMERA }, /* snap */ + { 0x14, KEY_AUDIO }, /* stereo */ + { 0x15, KEY_CLEAR }, /* reset */ + { 0x16, KEY_PLAY }, + { 0x17, KEY_ENTER }, + { 0x18, KEY_ZOOM }, /* full screen */ + { 0x19, KEY_FASTFORWARD }, /* forward >> */ + { 0x1a, KEY_CHANNELUP }, + { 0x1b, KEY_VOLUMEUP }, + { 0x1c, KEY_INFO }, /* preview */ + { 0x1d, KEY_RECORD }, /* record */ + { 0x1e, KEY_CHANNELDOWN }, + { 0x1f, KEY_VOLUMEDOWN }, +}; + +static struct rc_map_list dntv_live_dvb_t_map = { + .map = { + .scan = dntv_live_dvb_t, + .size = ARRAY_SIZE(dntv_live_dvb_t), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_DNTV_LIVE_DVB_T, + } +}; + +static int __init init_rc_map_dntv_live_dvb_t(void) +{ + return rc_map_register(&dntv_live_dvb_t_map); +} + +static void __exit exit_rc_map_dntv_live_dvb_t(void) +{ + rc_map_unregister(&dntv_live_dvb_t_map); +} + +module_init(init_rc_map_dntv_live_dvb_t) +module_exit(exit_rc_map_dntv_live_dvb_t) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,97 @@ +/* dntv-live-dvbt-pro.h - Keytable for dntv_live_dvbt_pro Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* DigitalNow DNTV Live! DVB-T Pro Remote */ + +static struct rc_map_table dntv_live_dvbt_pro[] = { + { 0x16, KEY_POWER }, + { 0x5b, KEY_HOME }, + + { 0x55, KEY_TV }, /* live tv */ + { 0x58, KEY_TUNER }, /* digital Radio */ + { 0x5a, KEY_RADIO }, /* FM radio */ + { 0x59, KEY_DVD }, /* dvd menu */ + { 0x03, KEY_1 }, + { 0x01, KEY_2 }, + { 0x06, KEY_3 }, + { 0x09, KEY_4 }, + { 0x1d, KEY_5 }, + { 0x1f, KEY_6 }, + { 0x0d, KEY_7 }, + { 0x19, KEY_8 }, + { 0x1b, KEY_9 }, + { 0x0c, KEY_CANCEL }, + { 0x15, KEY_0 }, + { 0x4a, KEY_CLEAR }, + { 0x13, KEY_BACK }, + { 0x00, KEY_TAB }, + { 0x4b, KEY_UP }, + { 0x4e, KEY_LEFT }, + { 0x4f, KEY_OK }, + { 0x52, KEY_RIGHT }, + { 0x51, KEY_DOWN }, + { 0x1e, KEY_VOLUMEUP }, + { 0x0a, KEY_VOLUMEDOWN }, + { 0x02, KEY_CHANNELDOWN }, + { 0x05, KEY_CHANNELUP }, + { 0x11, KEY_RECORD }, + { 0x14, KEY_PLAY }, + { 0x4c, KEY_PAUSE }, + { 0x1a, KEY_STOP }, + { 0x40, KEY_REWIND }, + { 0x12, KEY_FASTFORWARD }, + { 0x41, KEY_PREVIOUSSONG }, /* replay |< */ + { 0x42, KEY_NEXTSONG }, /* skip >| */ + { 0x54, KEY_CAMERA }, /* capture */ + { 0x50, KEY_LANGUAGE }, /* sap */ + { 0x47, KEY_TV2 }, /* pip */ + { 0x4d, KEY_SCREEN }, + { 0x43, KEY_SUBTITLE }, + { 0x10, KEY_MUTE }, + { 0x49, KEY_AUDIO }, /* l/r */ + { 0x07, KEY_SLEEP }, + { 0x08, KEY_VIDEO }, /* a/v */ + { 0x0e, KEY_PREVIOUS }, /* recall */ + { 0x45, KEY_ZOOM }, /* zoom + */ + { 0x46, KEY_ANGLE }, /* zoom - */ + { 0x56, KEY_RED }, + { 0x57, KEY_GREEN }, + { 0x5c, KEY_YELLOW }, + { 0x5d, KEY_BLUE }, +}; + +static struct rc_map_list dntv_live_dvbt_pro_map = { + .map = { + .scan = dntv_live_dvbt_pro, + .size = ARRAY_SIZE(dntv_live_dvbt_pro), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_DNTV_LIVE_DVBT_PRO, + } +}; + +static int __init init_rc_map_dntv_live_dvbt_pro(void) +{ + return rc_map_register(&dntv_live_dvbt_pro_map); +} + +static void __exit exit_rc_map_dntv_live_dvbt_pro(void) +{ + rc_map_unregister(&dntv_live_dvbt_pro_map); +} + +module_init(init_rc_map_dntv_live_dvbt_pro) +module_exit(exit_rc_map_dntv_live_dvbt_pro) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-em-terratec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-em-terratec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-em-terratec.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-em-terratec.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* em-terratec.h - Keytable for em_terratec Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table em_terratec[] = { + { 0x01, KEY_CHANNEL }, + { 0x02, KEY_SELECT }, + { 0x03, KEY_MUTE }, + { 0x04, KEY_POWER }, + { 0x05, KEY_1 }, + { 0x06, KEY_2 }, + { 0x07, KEY_3 }, + { 0x08, KEY_CHANNELUP }, + { 0x09, KEY_4 }, + { 0x0a, KEY_5 }, + { 0x0b, KEY_6 }, + { 0x0c, KEY_CHANNELDOWN }, + { 0x0d, KEY_7 }, + { 0x0e, KEY_8 }, + { 0x0f, KEY_9 }, + { 0x10, KEY_VOLUMEUP }, + { 0x11, KEY_0 }, + { 0x12, KEY_MENU }, + { 0x13, KEY_PRINT }, + { 0x14, KEY_VOLUMEDOWN }, + { 0x16, KEY_PAUSE }, + { 0x18, KEY_RECORD }, + { 0x19, KEY_REWIND }, + { 0x1a, KEY_PLAY }, + { 0x1b, KEY_FORWARD }, + { 0x1c, KEY_BACKSPACE }, + { 0x1e, KEY_STOP }, + { 0x40, KEY_ZOOM }, +}; + +static struct rc_map_list em_terratec_map = { + .map = { + .scan = em_terratec, + .size = ARRAY_SIZE(em_terratec), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_EM_TERRATEC, + } +}; + +static int __init init_rc_map_em_terratec(void) +{ + return rc_map_register(&em_terratec_map); +} + +static void __exit exit_rc_map_em_terratec(void) +{ + rc_map_unregister(&em_terratec_map); +} + +module_init(init_rc_map_em_terratec) +module_exit(exit_rc_map_em_terratec) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv2.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,90 @@ +/* encore-enltv2.h - Keytable for encore_enltv2 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton + Mauro Carvalho Chehab */ + +static struct rc_map_table encore_enltv2[] = { + { 0x4c, KEY_POWER2 }, + { 0x4a, KEY_TUNER }, + { 0x40, KEY_1 }, + { 0x60, KEY_2 }, + { 0x50, KEY_3 }, + { 0x70, KEY_4 }, + { 0x48, KEY_5 }, + { 0x68, KEY_6 }, + { 0x58, KEY_7 }, + { 0x78, KEY_8 }, + { 0x44, KEY_9 }, + { 0x54, KEY_0 }, + + { 0x64, KEY_LAST }, /* +100 */ + { 0x4e, KEY_AGAIN }, /* Recall */ + + { 0x6c, KEY_VIDEO }, /* Video Source */ + { 0x5e, KEY_MENU }, + { 0x56, KEY_SCREEN }, + { 0x7a, KEY_SETUP }, + + { 0x46, KEY_MUTE }, + { 0x5c, KEY_MODE }, /* Stereo */ + { 0x74, KEY_INFO }, + { 0x7c, KEY_CLEAR }, + + { 0x55, KEY_UP }, + { 0x49, KEY_DOWN }, + { 0x7e, KEY_LEFT }, + { 0x59, KEY_RIGHT }, + { 0x6a, KEY_ENTER }, + + { 0x42, KEY_VOLUMEUP }, + { 0x62, KEY_VOLUMEDOWN }, + { 0x52, KEY_CHANNELUP }, + { 0x72, KEY_CHANNELDOWN }, + + { 0x41, KEY_RECORD }, + { 0x51, KEY_CAMERA }, /* Snapshot */ + { 0x75, KEY_TIME }, /* Timeshift */ + { 0x71, KEY_TV2 }, /* PIP */ + + { 0x45, KEY_REWIND }, + { 0x6f, KEY_PAUSE }, + { 0x7d, KEY_FORWARD }, + { 0x79, KEY_STOP }, +}; + +static struct rc_map_list encore_enltv2_map = { + .map = { + .scan = encore_enltv2, + .size = ARRAY_SIZE(encore_enltv2), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ENCORE_ENLTV2, + } +}; + +static int __init init_rc_map_encore_enltv2(void) +{ + return rc_map_register(&encore_enltv2_map); +} + +static void __exit exit_rc_map_encore_enltv2(void) +{ + rc_map_unregister(&encore_enltv2_map); +} + +module_init(init_rc_map_encore_enltv2) +module_exit(exit_rc_map_encore_enltv2) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,112 @@ +/* encore-enltv.h - Keytable for encore_enltv Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons + Juan Pablo Sormani */ + +static struct rc_map_table encore_enltv[] = { + + /* Power button does nothing, neither in Windows app, + although it sends data (used for BIOS wakeup?) */ + { 0x0d, KEY_MUTE }, + + { 0x1e, KEY_TV }, + { 0x00, KEY_VIDEO }, + { 0x01, KEY_AUDIO }, /* music */ + { 0x02, KEY_CAMERA }, /* picture */ + + { 0x1f, KEY_1 }, + { 0x03, KEY_2 }, + { 0x04, KEY_3 }, + { 0x05, KEY_4 }, + { 0x1c, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x1d, KEY_9 }, + { 0x0a, KEY_0 }, + + { 0x09, KEY_LIST }, /* -/-- */ + { 0x0b, KEY_LAST }, /* recall */ + + { 0x14, KEY_HOME }, /* win start menu */ + { 0x15, KEY_EXIT }, /* exit */ + { 0x16, KEY_CHANNELUP }, /* UP */ + { 0x12, KEY_CHANNELDOWN }, /* DOWN */ + { 0x0c, KEY_VOLUMEUP }, /* RIGHT */ + { 0x17, KEY_VOLUMEDOWN }, /* LEFT */ + + { 0x18, KEY_ENTER }, /* OK */ + + { 0x0e, KEY_ESC }, + { 0x13, KEY_CYCLEWINDOWS }, /* desktop */ + { 0x11, KEY_TAB }, + { 0x19, KEY_SWITCHVIDEOMODE }, /* switch */ + + { 0x1a, KEY_MENU }, + { 0x1b, KEY_ZOOM }, /* fullscreen */ + { 0x44, KEY_TIME }, /* time shift */ + { 0x40, KEY_MODE }, /* source */ + + { 0x5a, KEY_RECORD }, + { 0x42, KEY_PLAY }, /* play/pause */ + { 0x45, KEY_STOP }, + { 0x43, KEY_CAMERA }, /* camera icon */ + + { 0x48, KEY_REWIND }, + { 0x4a, KEY_FASTFORWARD }, + { 0x49, KEY_PREVIOUS }, + { 0x4b, KEY_NEXT }, + + { 0x4c, KEY_FAVORITES }, /* tv wall */ + { 0x4d, KEY_SOUND }, /* DVD sound */ + { 0x4e, KEY_LANGUAGE }, /* DVD lang */ + { 0x4f, KEY_TEXT }, /* DVD text */ + + { 0x50, KEY_SLEEP }, /* shutdown */ + { 0x51, KEY_MODE }, /* stereo > main */ + { 0x52, KEY_SELECT }, /* stereo > sap */ + { 0x53, KEY_TEXT }, /* teletext */ + + + { 0x59, KEY_RED }, /* AP1 */ + { 0x41, KEY_GREEN }, /* AP2 */ + { 0x47, KEY_YELLOW }, /* AP3 */ + { 0x57, KEY_BLUE }, /* AP4 */ +}; + +static struct rc_map_list encore_enltv_map = { + .map = { + .scan = encore_enltv, + .size = ARRAY_SIZE(encore_enltv), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ENCORE_ENLTV, + } +}; + +static int __init init_rc_map_encore_enltv(void) +{ + return rc_map_register(&encore_enltv_map); +} + +static void __exit exit_rc_map_encore_enltv(void) +{ + rc_map_unregister(&encore_enltv_map); +} + +module_init(init_rc_map_encore_enltv) +module_exit(exit_rc_map_encore_enltv) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,81 @@ +/* encore-enltv-fm53.h - Keytable for encore_enltv_fm53 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Encore ENLTV-FM v5.3 + Mauro Carvalho Chehab + */ + +static struct rc_map_table encore_enltv_fm53[] = { + { 0x10, KEY_POWER2}, + { 0x06, KEY_MUTE}, + + { 0x09, KEY_1}, + { 0x1d, KEY_2}, + { 0x1f, KEY_3}, + { 0x19, KEY_4}, + { 0x1b, KEY_5}, + { 0x11, KEY_6}, + { 0x17, KEY_7}, + { 0x12, KEY_8}, + { 0x16, KEY_9}, + { 0x48, KEY_0}, + + { 0x04, KEY_LIST}, /* -/-- */ + { 0x40, KEY_LAST}, /* recall */ + + { 0x02, KEY_MODE}, /* TV/AV */ + { 0x05, KEY_CAMERA}, /* SNAPSHOT */ + + { 0x4c, KEY_CHANNELUP}, /* UP */ + { 0x00, KEY_CHANNELDOWN}, /* DOWN */ + { 0x0d, KEY_VOLUMEUP}, /* RIGHT */ + { 0x15, KEY_VOLUMEDOWN}, /* LEFT */ + { 0x49, KEY_ENTER}, /* OK */ + + { 0x54, KEY_RECORD}, + { 0x4d, KEY_PLAY}, /* pause */ + + { 0x1e, KEY_MENU}, /* video setting */ + { 0x0e, KEY_RIGHT}, /* <- */ + { 0x1a, KEY_LEFT}, /* -> */ + + { 0x0a, KEY_CLEAR}, /* video default */ + { 0x0c, KEY_ZOOM}, /* hide pannel */ + { 0x47, KEY_SLEEP}, /* shutdown */ +}; + +static struct rc_map_list encore_enltv_fm53_map = { + .map = { + .scan = encore_enltv_fm53, + .size = ARRAY_SIZE(encore_enltv_fm53), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ENCORE_ENLTV_FM53, + } +}; + +static int __init init_rc_map_encore_enltv_fm53(void) +{ + return rc_map_register(&encore_enltv_fm53_map); +} + +static void __exit exit_rc_map_encore_enltv_fm53(void) +{ + rc_map_unregister(&encore_enltv_fm53_map); +} + +module_init(init_rc_map_encore_enltv_fm53) +module_exit(exit_rc_map_encore_enltv_fm53) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-evga-indtube.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-evga-indtube.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-evga-indtube.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-evga-indtube.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* evga-indtube.h - Keytable for evga_indtube Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* EVGA inDtube + Devin Heitmueller + */ + +static struct rc_map_table evga_indtube[] = { + { 0x12, KEY_POWER}, + { 0x02, KEY_MODE}, /* TV */ + { 0x14, KEY_MUTE}, + { 0x1a, KEY_CHANNELUP}, + { 0x16, KEY_TV2}, /* PIP */ + { 0x1d, KEY_VOLUMEUP}, + { 0x05, KEY_CHANNELDOWN}, + { 0x0f, KEY_PLAYPAUSE}, + { 0x19, KEY_VOLUMEDOWN}, + { 0x1c, KEY_REWIND}, + { 0x0d, KEY_RECORD}, + { 0x18, KEY_FORWARD}, + { 0x1e, KEY_PREVIOUS}, + { 0x1b, KEY_STOP}, + { 0x1f, KEY_NEXT}, + { 0x13, KEY_CAMERA}, +}; + +static struct rc_map_list evga_indtube_map = { + .map = { + .scan = evga_indtube, + .size = ARRAY_SIZE(evga_indtube), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_EVGA_INDTUBE, + } +}; + +static int __init init_rc_map_evga_indtube(void) +{ + return rc_map_register(&evga_indtube_map); +} + +static void __exit exit_rc_map_evga_indtube(void) +{ + rc_map_unregister(&evga_indtube_map); +} + +module_init(init_rc_map_evga_indtube) +module_exit(exit_rc_map_evga_indtube) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-eztv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-eztv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-eztv.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-eztv.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,96 @@ +/* eztv.h - Keytable for eztv Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Alfons Geser + * updates from Job D. R. Borges */ + +static struct rc_map_table eztv[] = { + { 0x12, KEY_POWER }, + { 0x01, KEY_TV }, /* DVR */ + { 0x15, KEY_DVD }, /* DVD */ + { 0x17, KEY_AUDIO }, /* music */ + /* DVR mode / DVD mode / music mode */ + + { 0x1b, KEY_MUTE }, /* mute */ + { 0x02, KEY_LANGUAGE }, /* MTS/SAP / audio / autoseek */ + { 0x1e, KEY_SUBTITLE }, /* closed captioning / subtitle / seek */ + { 0x16, KEY_ZOOM }, /* full screen */ + { 0x1c, KEY_VIDEO }, /* video source / eject / delall */ + { 0x1d, KEY_RESTART }, /* playback / angle / del */ + { 0x2f, KEY_SEARCH }, /* scan / menu / playlist */ + { 0x30, KEY_CHANNEL }, /* CH surfing / bookmark / memo */ + + { 0x31, KEY_HELP }, /* help */ + { 0x32, KEY_MODE }, /* num/memo */ + { 0x33, KEY_ESC }, /* cancel */ + + { 0x0c, KEY_UP }, /* up */ + { 0x10, KEY_DOWN }, /* down */ + { 0x08, KEY_LEFT }, /* left */ + { 0x04, KEY_RIGHT }, /* right */ + { 0x03, KEY_SELECT }, /* select */ + + { 0x1f, KEY_REWIND }, /* rewind */ + { 0x20, KEY_PLAYPAUSE },/* play/pause */ + { 0x29, KEY_FORWARD }, /* forward */ + { 0x14, KEY_AGAIN }, /* repeat */ + { 0x2b, KEY_RECORD }, /* recording */ + { 0x2c, KEY_STOP }, /* stop */ + { 0x2d, KEY_PLAY }, /* play */ + { 0x2e, KEY_CAMERA }, /* snapshot / shuffle */ + + { 0x00, KEY_0 }, + { 0x05, KEY_1 }, + { 0x06, KEY_2 }, + { 0x07, KEY_3 }, + { 0x09, KEY_4 }, + { 0x0a, KEY_5 }, + { 0x0b, KEY_6 }, + { 0x0d, KEY_7 }, + { 0x0e, KEY_8 }, + { 0x0f, KEY_9 }, + + { 0x2a, KEY_VOLUMEUP }, + { 0x11, KEY_VOLUMEDOWN }, + { 0x18, KEY_CHANNELUP },/* CH.tracking up */ + { 0x19, KEY_CHANNELDOWN },/* CH.tracking down */ + + { 0x13, KEY_ENTER }, /* enter */ + { 0x21, KEY_DOT }, /* . (decimal dot) */ +}; + +static struct rc_map_list eztv_map = { + .map = { + .scan = eztv, + .size = ARRAY_SIZE(eztv), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_EZTV, + } +}; + +static int __init init_rc_map_eztv(void) +{ + return rc_map_register(&eztv_map); +} + +static void __exit exit_rc_map_eztv(void) +{ + rc_map_unregister(&eztv_map); +} + +module_init(init_rc_map_eztv) +module_exit(exit_rc_map_eztv) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-flydvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-flydvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-flydvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-flydvb.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,77 @@ +/* flydvb.h - Keytable for flydvb Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table flydvb[] = { + { 0x01, KEY_ZOOM }, /* Full Screen */ + { 0x00, KEY_POWER }, /* Power */ + + { 0x03, KEY_1 }, + { 0x04, KEY_2 }, + { 0x05, KEY_3 }, + { 0x07, KEY_4 }, + { 0x08, KEY_5 }, + { 0x09, KEY_6 }, + { 0x0b, KEY_7 }, + { 0x0c, KEY_8 }, + { 0x0d, KEY_9 }, + { 0x06, KEY_AGAIN }, /* Recall */ + { 0x0f, KEY_0 }, + { 0x10, KEY_MUTE }, /* Mute */ + { 0x02, KEY_RADIO }, /* TV/Radio */ + { 0x1b, KEY_LANGUAGE }, /* SAP (Second Audio Program) */ + + { 0x14, KEY_VOLUMEUP }, /* VOL+ */ + { 0x17, KEY_VOLUMEDOWN }, /* VOL- */ + { 0x12, KEY_CHANNELUP }, /* CH+ */ + { 0x13, KEY_CHANNELDOWN }, /* CH- */ + { 0x1d, KEY_ENTER }, /* Enter */ + + { 0x1a, KEY_TV2 }, /* PIP */ + { 0x18, KEY_VIDEO }, /* Source */ + + { 0x1e, KEY_RECORD }, /* Record/Pause */ + { 0x15, KEY_ANGLE }, /* Swap (no label on key) */ + { 0x1c, KEY_PAUSE }, /* Timeshift/Pause */ + { 0x19, KEY_BACK }, /* Rewind << */ + { 0x0a, KEY_PLAYPAUSE }, /* Play/Pause */ + { 0x1f, KEY_FORWARD }, /* Forward >> */ + { 0x16, KEY_PREVIOUS }, /* Back |<< */ + { 0x11, KEY_STOP }, /* Stop */ + { 0x0e, KEY_NEXT }, /* End >>| */ +}; + +static struct rc_map_list flydvb_map = { + .map = { + .scan = flydvb, + .size = ARRAY_SIZE(flydvb), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_FLYDVB, + } +}; + +static int __init init_rc_map_flydvb(void) +{ + return rc_map_register(&flydvb_map); +} + +static void __exit exit_rc_map_flydvb(void) +{ + rc_map_unregister(&flydvb_map); +} + +module_init(init_rc_map_flydvb) +module_exit(exit_rc_map_flydvb) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-flyvideo.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-flyvideo.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-flyvideo.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-flyvideo.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,70 @@ +/* flyvideo.h - Keytable for flyvideo Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table flyvideo[] = { + { 0x0f, KEY_0 }, + { 0x03, KEY_1 }, + { 0x04, KEY_2 }, + { 0x05, KEY_3 }, + { 0x07, KEY_4 }, + { 0x08, KEY_5 }, + { 0x09, KEY_6 }, + { 0x0b, KEY_7 }, + { 0x0c, KEY_8 }, + { 0x0d, KEY_9 }, + + { 0x0e, KEY_MODE }, /* Air/Cable */ + { 0x11, KEY_VIDEO }, /* Video */ + { 0x15, KEY_AUDIO }, /* Audio */ + { 0x00, KEY_POWER }, /* Power */ + { 0x18, KEY_TUNER }, /* AV Source */ + { 0x02, KEY_ZOOM }, /* Fullscreen */ + { 0x1a, KEY_LANGUAGE }, /* Stereo */ + { 0x1b, KEY_MUTE }, /* Mute */ + { 0x14, KEY_VOLUMEUP }, /* Volume + */ + { 0x17, KEY_VOLUMEDOWN },/* Volume - */ + { 0x12, KEY_CHANNELUP },/* Channel + */ + { 0x13, KEY_CHANNELDOWN },/* Channel - */ + { 0x06, KEY_AGAIN }, /* Recall */ + { 0x10, KEY_ENTER }, /* Enter */ + + { 0x19, KEY_BACK }, /* Rewind ( <<< ) */ + { 0x1f, KEY_FORWARD }, /* Forward ( >>> ) */ + { 0x0a, KEY_ANGLE }, /* no label, may be used as the PAUSE button */ +}; + +static struct rc_map_list flyvideo_map = { + .map = { + .scan = flyvideo, + .size = ARRAY_SIZE(flyvideo), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_FLYVIDEO, + } +}; + +static int __init init_rc_map_flyvideo(void) +{ + return rc_map_register(&flyvideo_map); +} + +static void __exit exit_rc_map_flyvideo(void) +{ + rc_map_unregister(&flyvideo_map); +} + +module_init(init_rc_map_flyvideo) +module_exit(exit_rc_map_flyvideo) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* fusionhdtv-mce.h - Keytable for fusionhdtv_mce Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* DViCO FUSION HDTV MCE remote */ + +static struct rc_map_table fusionhdtv_mce[] = { + + { 0x0b, KEY_1 }, + { 0x17, KEY_2 }, + { 0x1b, KEY_3 }, + { 0x07, KEY_4 }, + { 0x50, KEY_5 }, + { 0x54, KEY_6 }, + { 0x48, KEY_7 }, + { 0x4c, KEY_8 }, + { 0x58, KEY_9 }, + { 0x03, KEY_0 }, + + { 0x5e, KEY_OK }, + { 0x51, KEY_UP }, + { 0x53, KEY_DOWN }, + { 0x5b, KEY_LEFT }, + { 0x5f, KEY_RIGHT }, + + { 0x02, KEY_TV }, /* Labeled DTV on remote */ + { 0x0e, KEY_MP3 }, + { 0x1a, KEY_DVD }, + { 0x1e, KEY_FAVORITES }, /* Labeled CPF on remote */ + { 0x16, KEY_SETUP }, + { 0x46, KEY_POWER2 }, /* TV On/Off button on remote */ + { 0x0a, KEY_EPG }, /* Labeled Guide on remote */ + + { 0x49, KEY_BACK }, + { 0x59, KEY_INFO }, /* Labeled MORE on remote */ + { 0x4d, KEY_MENU }, /* Labeled DVDMENU on remote */ + { 0x55, KEY_CYCLEWINDOWS }, /* Labeled ALT-TAB on remote */ + + { 0x0f, KEY_PREVIOUSSONG }, /* Labeled |<< REPLAY on remote */ + { 0x12, KEY_NEXTSONG }, /* Labeled >>| SKIP on remote */ + { 0x42, KEY_ENTER }, /* Labeled START with a green + MS windows logo on remote */ + + { 0x15, KEY_VOLUMEUP }, + { 0x05, KEY_VOLUMEDOWN }, + { 0x11, KEY_CHANNELUP }, + { 0x09, KEY_CHANNELDOWN }, + + { 0x52, KEY_CAMERA }, + { 0x5a, KEY_TUNER }, + { 0x19, KEY_OPEN }, + + { 0x13, KEY_MODE }, /* 4:3 16:9 select */ + { 0x1f, KEY_ZOOM }, + + { 0x43, KEY_REWIND }, + { 0x47, KEY_PLAYPAUSE }, + { 0x4f, KEY_FASTFORWARD }, + { 0x57, KEY_MUTE }, + { 0x0d, KEY_STOP }, + { 0x01, KEY_RECORD }, + { 0x4e, KEY_POWER }, +}; + +static struct rc_map_list fusionhdtv_mce_map = { + .map = { + .scan = fusionhdtv_mce, + .size = ARRAY_SIZE(fusionhdtv_mce), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_FUSIONHDTV_MCE, + } +}; + +static int __init init_rc_map_fusionhdtv_mce(void) +{ + return rc_map_register(&fusionhdtv_mce_map); +} + +static void __exit exit_rc_map_fusionhdtv_mce(void) +{ + rc_map_unregister(&fusionhdtv_mce_map); +} + +module_init(init_rc_map_fusionhdtv_mce) +module_exit(exit_rc_map_fusionhdtv_mce) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-gadmei-rm008z.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-gadmei-rm008z.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-gadmei-rm008z.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-gadmei-rm008z.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,81 @@ +/* gadmei-rm008z.h - Keytable for gadmei_rm008z Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* GADMEI UTV330+ RM008Z remote + Shine Liu + */ + +static struct rc_map_table gadmei_rm008z[] = { + { 0x14, KEY_POWER2}, /* POWER OFF */ + { 0x0c, KEY_MUTE}, /* MUTE */ + + { 0x18, KEY_TV}, /* TV */ + { 0x0e, KEY_VIDEO}, /* AV */ + { 0x0b, KEY_AUDIO}, /* SV */ + { 0x0f, KEY_RADIO}, /* FM */ + + { 0x00, KEY_1}, + { 0x01, KEY_2}, + { 0x02, KEY_3}, + { 0x03, KEY_4}, + { 0x04, KEY_5}, + { 0x05, KEY_6}, + { 0x06, KEY_7}, + { 0x07, KEY_8}, + { 0x08, KEY_9}, + { 0x09, KEY_0}, + { 0x0a, KEY_INFO}, /* OSD */ + { 0x1c, KEY_BACKSPACE}, /* LAST */ + + { 0x0d, KEY_PLAY}, /* PLAY */ + { 0x1e, KEY_CAMERA}, /* SNAPSHOT */ + { 0x1a, KEY_RECORD}, /* RECORD */ + { 0x17, KEY_STOP}, /* STOP */ + + { 0x1f, KEY_UP}, /* UP */ + { 0x44, KEY_DOWN}, /* DOWN */ + { 0x46, KEY_TAB}, /* BACK */ + { 0x4a, KEY_ZOOM}, /* FULLSECREEN */ + + { 0x10, KEY_VOLUMEUP}, /* VOLUMEUP */ + { 0x11, KEY_VOLUMEDOWN}, /* VOLUMEDOWN */ + { 0x12, KEY_CHANNELUP}, /* CHANNELUP */ + { 0x13, KEY_CHANNELDOWN}, /* CHANNELDOWN */ + { 0x15, KEY_ENTER}, /* OK */ +}; + +static struct rc_map_list gadmei_rm008z_map = { + .map = { + .scan = gadmei_rm008z, + .size = ARRAY_SIZE(gadmei_rm008z), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_GADMEI_RM008Z, + } +}; + +static int __init init_rc_map_gadmei_rm008z(void) +{ + return rc_map_register(&gadmei_rm008z_map); +} + +static void __exit exit_rc_map_gadmei_rm008z(void) +{ + rc_map_unregister(&gadmei_rm008z_map); +} + +module_init(init_rc_map_gadmei_rm008z) +module_exit(exit_rc_map_gadmei_rm008z) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,84 @@ +/* genius-tvgo-a11mce.h - Keytable for genius_tvgo_a11mce Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Remote control for the Genius TVGO A11MCE + * Adrian Pardini + */ + +static struct rc_map_table genius_tvgo_a11mce[] = { + /* Keys 0 to 9 */ + { 0x48, KEY_0 }, + { 0x09, KEY_1 }, + { 0x1d, KEY_2 }, + { 0x1f, KEY_3 }, + { 0x19, KEY_4 }, + { 0x1b, KEY_5 }, + { 0x11, KEY_6 }, + { 0x17, KEY_7 }, + { 0x12, KEY_8 }, + { 0x16, KEY_9 }, + + { 0x54, KEY_RECORD }, /* recording */ + { 0x06, KEY_MUTE }, /* mute */ + { 0x10, KEY_POWER }, + { 0x40, KEY_LAST }, /* recall */ + { 0x4c, KEY_CHANNELUP }, /* channel / program + */ + { 0x00, KEY_CHANNELDOWN }, /* channel / program - */ + { 0x0d, KEY_VOLUMEUP }, + { 0x15, KEY_VOLUMEDOWN }, + { 0x4d, KEY_OK }, /* also labeled as Pause */ + { 0x1c, KEY_ZOOM }, /* full screen and Stop*/ + { 0x02, KEY_MODE }, /* AV Source or Rewind*/ + { 0x04, KEY_LIST }, /* -/-- */ + /* small arrows above numbers */ + { 0x1a, KEY_NEXT }, /* also Fast Forward */ + { 0x0e, KEY_PREVIOUS }, /* also Rewind */ + /* these are in a rather non standard layout and have + an alternate name written */ + { 0x1e, KEY_UP }, /* Video Setting */ + { 0x0a, KEY_DOWN }, /* Video Default */ + { 0x05, KEY_CAMERA }, /* Snapshot */ + { 0x0c, KEY_RIGHT }, /* Hide Panel */ + /* Four buttons without label */ + { 0x49, KEY_RED }, + { 0x0b, KEY_GREEN }, + { 0x13, KEY_YELLOW }, + { 0x50, KEY_BLUE }, +}; + +static struct rc_map_list genius_tvgo_a11mce_map = { + .map = { + .scan = genius_tvgo_a11mce, + .size = ARRAY_SIZE(genius_tvgo_a11mce), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_GENIUS_TVGO_A11MCE, + } +}; + +static int __init init_rc_map_genius_tvgo_a11mce(void) +{ + return rc_map_register(&genius_tvgo_a11mce_map); +} + +static void __exit exit_rc_map_genius_tvgo_a11mce(void) +{ + rc_map_unregister(&genius_tvgo_a11mce_map); +} + +module_init(init_rc_map_genius_tvgo_a11mce) +module_exit(exit_rc_map_genius_tvgo_a11mce) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-gotview7135.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-gotview7135.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-gotview7135.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-gotview7135.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,79 @@ +/* gotview7135.h - Keytable for gotview7135 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Mike Baikov */ + +static struct rc_map_table gotview7135[] = { + + { 0x11, KEY_POWER }, + { 0x35, KEY_TV }, + { 0x1b, KEY_0 }, + { 0x29, KEY_1 }, + { 0x19, KEY_2 }, + { 0x39, KEY_3 }, + { 0x1f, KEY_4 }, + { 0x2c, KEY_5 }, + { 0x21, KEY_6 }, + { 0x24, KEY_7 }, + { 0x18, KEY_8 }, + { 0x2b, KEY_9 }, + { 0x3b, KEY_AGAIN }, /* LOOP */ + { 0x06, KEY_AUDIO }, + { 0x31, KEY_PRINT }, /* PREVIEW */ + { 0x3e, KEY_VIDEO }, + { 0x10, KEY_CHANNELUP }, + { 0x20, KEY_CHANNELDOWN }, + { 0x0c, KEY_VOLUMEDOWN }, + { 0x28, KEY_VOLUMEUP }, + { 0x08, KEY_MUTE }, + { 0x26, KEY_SEARCH }, /* SCAN */ + { 0x3f, KEY_CAMERA }, /* SNAPSHOT */ + { 0x12, KEY_RECORD }, + { 0x32, KEY_STOP }, + { 0x3c, KEY_PLAY }, + { 0x1d, KEY_REWIND }, + { 0x2d, KEY_PAUSE }, + { 0x0d, KEY_FORWARD }, + { 0x05, KEY_ZOOM }, /*FULL*/ + + { 0x2a, KEY_F21 }, /* LIVE TIMESHIFT */ + { 0x0e, KEY_F22 }, /* MIN TIMESHIFT */ + { 0x1e, KEY_TIME }, /* TIMESHIFT */ + { 0x38, KEY_F24 }, /* NORMAL TIMESHIFT */ +}; + +static struct rc_map_list gotview7135_map = { + .map = { + .scan = gotview7135, + .size = ARRAY_SIZE(gotview7135), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_GOTVIEW7135, + } +}; + +static int __init init_rc_map_gotview7135(void) +{ + return rc_map_register(&gotview7135_map); +} + +static void __exit exit_rc_map_gotview7135(void) +{ + rc_map_unregister(&gotview7135_map); +} + +module_init(init_rc_map_gotview7135) +module_exit(exit_rc_map_gotview7135) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-hauppauge.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-hauppauge.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-hauppauge.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-hauppauge.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,241 @@ +/* rc-hauppauge.c - Keytable for Hauppauge Remote Controllers + * + * keymap imported from ir-keymaps.c + * + * This map currently contains the code for four different RCs: + * - New Hauppauge Gray; + * - Old Hauppauge Gray (with a golden screen for media keys); + * - Hauppauge Black; + * - DSR-0112 remote bundled with Haupauge MiniStick. + * + * Copyright (c) 2010-2011 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Hauppauge:the newer, gray remotes (seems there are multiple + * slightly different versions), shipped with cx88+ivtv cards. + * + * This table contains the complete RC5 code, instead of just the data part + */ + +static struct rc_map_table rc5_hauppauge_new[] = { + /* + * Remote Controller Hauppauge Gray found on modern devices + * Keycodes start with address = 0x1e + */ + + { 0x1e3b, KEY_SELECT }, /* GO / house symbol */ + { 0x1e3d, KEY_POWER2 }, /* system power (green button) */ + + { 0x1e1c, KEY_TV }, + { 0x1e18, KEY_VIDEO }, /* Videos */ + { 0x1e19, KEY_AUDIO }, /* Music */ + { 0x1e1a, KEY_CAMERA }, /* Pictures */ + + { 0x1e1b, KEY_EPG }, /* Guide */ + { 0x1e0c, KEY_RADIO }, + + { 0x1e14, KEY_UP }, + { 0x1e15, KEY_DOWN }, + { 0x1e16, KEY_LEFT }, + { 0x1e17, KEY_RIGHT }, + { 0x1e25, KEY_OK }, /* OK */ + + { 0x1e1f, KEY_EXIT }, /* back/exit */ + { 0x1e0d, KEY_MENU }, + + { 0x1e10, KEY_VOLUMEUP }, + { 0x1e11, KEY_VOLUMEDOWN }, + + { 0x1e12, KEY_PREVIOUS }, /* previous channel */ + { 0x1e0f, KEY_MUTE }, + + { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ + { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ + + { 0x1e37, KEY_RECORD }, /* recording */ + { 0x1e36, KEY_STOP }, + + { 0x1e32, KEY_REWIND }, /* backward << */ + { 0x1e35, KEY_PLAY }, + { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ + + { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ + { 0x1e30, KEY_PAUSE }, /* pause */ + { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ + + { 0x1e01, KEY_1 }, + { 0x1e02, KEY_2 }, + { 0x1e03, KEY_3 }, + + { 0x1e04, KEY_4 }, + { 0x1e05, KEY_5 }, + { 0x1e06, KEY_6 }, + + { 0x1e07, KEY_7 }, + { 0x1e08, KEY_8 }, + { 0x1e09, KEY_9 }, + + { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ + { 0x1e00, KEY_0 }, + { 0x1e0e, KEY_SUBTITLE }, /* also the Pound key (#) */ + + { 0x1e0b, KEY_RED }, /* red button */ + { 0x1e2e, KEY_GREEN }, /* green button */ + { 0x1e38, KEY_YELLOW }, /* yellow key */ + { 0x1e29, KEY_BLUE }, /* blue key */ + + /* + * Old Remote Controller Hauppauge Gray with a golden screen + * Keycodes start with address = 0x1f + */ + { 0x1f3d, KEY_POWER2 }, /* system power (green button) */ + { 0x1f3b, KEY_SELECT }, /* GO */ + + /* Keys 0 to 9 */ + { 0x1f00, KEY_0 }, + { 0x1f01, KEY_1 }, + { 0x1f02, KEY_2 }, + { 0x1f03, KEY_3 }, + { 0x1f04, KEY_4 }, + { 0x1f05, KEY_5 }, + { 0x1f06, KEY_6 }, + { 0x1f07, KEY_7 }, + { 0x1f08, KEY_8 }, + { 0x1f09, KEY_9 }, + + { 0x1f1f, KEY_EXIT }, /* back/exit */ + { 0x1f0d, KEY_MENU }, + + { 0x1f10, KEY_VOLUMEUP }, + { 0x1f11, KEY_VOLUMEDOWN }, + { 0x1f20, KEY_CHANNELUP }, /* channel / program + */ + { 0x1f21, KEY_CHANNELDOWN }, /* channel / program - */ + { 0x1f25, KEY_ENTER }, /* OK */ + + { 0x1f0b, KEY_RED }, /* red button */ + { 0x1f2e, KEY_GREEN }, /* green button */ + { 0x1f38, KEY_YELLOW }, /* yellow key */ + { 0x1f29, KEY_BLUE }, /* blue key */ + + { 0x1f0f, KEY_MUTE }, + { 0x1f0c, KEY_RADIO }, /* There's no indicator on this key */ + { 0x1f3c, KEY_ZOOM }, /* full */ + + { 0x1f32, KEY_REWIND }, /* backward << */ + { 0x1f35, KEY_PLAY }, + { 0x1f34, KEY_FASTFORWARD }, /* forward >> */ + + { 0x1f37, KEY_RECORD }, /* recording */ + { 0x1f36, KEY_STOP }, + { 0x1f30, KEY_PAUSE }, /* pause */ + + { 0x1f24, KEY_PREVIOUSSONG }, /* replay |< */ + { 0x1f1e, KEY_NEXTSONG }, /* skip >| */ + + /* + * Keycodes for DSR-0112 remote bundled with Haupauge MiniStick + * Keycodes start with address = 0x1d + */ + { 0x1d00, KEY_0 }, + { 0x1d01, KEY_1 }, + { 0x1d02, KEY_2 }, + { 0x1d03, KEY_3 }, + { 0x1d04, KEY_4 }, + { 0x1d05, KEY_5 }, + { 0x1d06, KEY_6 }, + { 0x1d07, KEY_7 }, + { 0x1d08, KEY_8 }, + { 0x1d09, KEY_9 }, + { 0x1d0a, KEY_TEXT }, + { 0x1d0d, KEY_MENU }, + { 0x1d0f, KEY_MUTE }, + { 0x1d10, KEY_VOLUMEUP }, + { 0x1d11, KEY_VOLUMEDOWN }, + { 0x1d12, KEY_PREVIOUS }, /* Prev.Ch .. ??? */ + { 0x1d14, KEY_UP }, + { 0x1d15, KEY_DOWN }, + { 0x1d16, KEY_LEFT }, + { 0x1d17, KEY_RIGHT }, + { 0x1d1c, KEY_TV }, + { 0x1d1e, KEY_NEXT }, /* >| */ + { 0x1d1f, KEY_EXIT }, + { 0x1d20, KEY_CHANNELUP }, + { 0x1d21, KEY_CHANNELDOWN }, + { 0x1d24, KEY_LAST }, /* <| */ + { 0x1d25, KEY_OK }, + { 0x1d30, KEY_PAUSE }, + { 0x1d32, KEY_REWIND }, + { 0x1d34, KEY_FASTFORWARD }, + { 0x1d35, KEY_PLAY }, + { 0x1d36, KEY_STOP }, + { 0x1d37, KEY_RECORD }, + { 0x1d3b, KEY_GOTO }, + { 0x1d3d, KEY_POWER }, + { 0x1d3f, KEY_HOME }, + + /* + * Keycodes for the old Black Remote Controller + * This one also uses RC-5 protocol + * Keycodes start with address = 0x00 + */ + { 0x001f, KEY_TV }, + { 0x0020, KEY_CHANNELUP }, + { 0x000c, KEY_RADIO }, + + { 0x0011, KEY_VOLUMEDOWN }, + { 0x002e, KEY_ZOOM }, /* full screen */ + { 0x0010, KEY_VOLUMEUP }, + + { 0x000d, KEY_MUTE }, + { 0x0021, KEY_CHANNELDOWN }, + { 0x0022, KEY_VIDEO }, /* source */ + + { 0x0001, KEY_1 }, + { 0x0002, KEY_2 }, + { 0x0003, KEY_3 }, + + { 0x0004, KEY_4 }, + { 0x0005, KEY_5 }, + { 0x0006, KEY_6 }, + + { 0x0007, KEY_7 }, + { 0x0008, KEY_8 }, + { 0x0009, KEY_9 }, + + { 0x001e, KEY_RED }, /* Reserved */ + { 0x0000, KEY_0 }, + { 0x0026, KEY_SLEEP }, /* Minimize */ +}; + +static struct rc_map_list rc5_hauppauge_new_map = { + .map = { + .scan = rc5_hauppauge_new, + .size = ARRAY_SIZE(rc5_hauppauge_new), + .rc_type = RC_TYPE_RC5, + .name = RC_MAP_HAUPPAUGE, + } +}; + +static int __init init_rc_map_rc5_hauppauge_new(void) +{ + return rc_map_register(&rc5_hauppauge_new_map); +} + +static void __exit exit_rc_map_rc5_hauppauge_new(void) +{ + rc_map_unregister(&rc5_hauppauge_new_map); +} + +module_init(init_rc_map_rc5_hauppauge_new) +module_exit(exit_rc_map_rc5_hauppauge_new) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-imon-mce.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-imon-mce.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-imon-mce.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-imon-mce.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,142 @@ +/* rc5-imon-mce.c - Keytable for Windows Media Center RC-6 remotes for use + * with the SoundGraph iMON/Antec Veris hardware IR decoder + * + * Copyright (c) 2010 by Jarod Wilson + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* mce-mode imon mce remote key table */ +static struct rc_map_table imon_mce[] = { + /* keys sorted mostly by frequency of use to optimize lookups */ + { 0x800ff415, KEY_REWIND }, + { 0x800ff414, KEY_FASTFORWARD }, + { 0x800ff41b, KEY_PREVIOUS }, + { 0x800ff41a, KEY_NEXT }, + + { 0x800ff416, KEY_PLAY }, + { 0x800ff418, KEY_PAUSE }, + { 0x800ff419, KEY_STOP }, + { 0x800ff417, KEY_RECORD }, + + { 0x02000052, KEY_UP }, + { 0x02000051, KEY_DOWN }, + { 0x02000050, KEY_LEFT }, + { 0x0200004f, KEY_RIGHT }, + + { 0x800ff41e, KEY_UP }, + { 0x800ff41f, KEY_DOWN }, + { 0x800ff420, KEY_LEFT }, + { 0x800ff421, KEY_RIGHT }, + + /* 0x800ff40b also KEY_NUMERIC_POUND on some receivers */ + { 0x800ff40b, KEY_ENTER }, + { 0x02000028, KEY_ENTER }, +/* the OK and Enter buttons decode to the same value on some remotes + { 0x02000028, KEY_OK }, */ + { 0x800ff422, KEY_OK }, + { 0x0200002a, KEY_EXIT }, + { 0x800ff423, KEY_EXIT }, + { 0x02000029, KEY_DELETE }, + /* 0x800ff40a also KEY_NUMERIC_STAR on some receivers */ + { 0x800ff40a, KEY_DELETE }, + + { 0x800ff40e, KEY_MUTE }, + { 0x800ff410, KEY_VOLUMEUP }, + { 0x800ff411, KEY_VOLUMEDOWN }, + { 0x800ff412, KEY_CHANNELUP }, + { 0x800ff413, KEY_CHANNELDOWN }, + + { 0x0200001e, KEY_NUMERIC_1 }, + { 0x0200001f, KEY_NUMERIC_2 }, + { 0x02000020, KEY_NUMERIC_3 }, + { 0x02000021, KEY_NUMERIC_4 }, + { 0x02000022, KEY_NUMERIC_5 }, + { 0x02000023, KEY_NUMERIC_6 }, + { 0x02000024, KEY_NUMERIC_7 }, + { 0x02000025, KEY_NUMERIC_8 }, + { 0x02000026, KEY_NUMERIC_9 }, + { 0x02000027, KEY_NUMERIC_0 }, + + { 0x800ff401, KEY_NUMERIC_1 }, + { 0x800ff402, KEY_NUMERIC_2 }, + { 0x800ff403, KEY_NUMERIC_3 }, + { 0x800ff404, KEY_NUMERIC_4 }, + { 0x800ff405, KEY_NUMERIC_5 }, + { 0x800ff406, KEY_NUMERIC_6 }, + { 0x800ff407, KEY_NUMERIC_7 }, + { 0x800ff408, KEY_NUMERIC_8 }, + { 0x800ff409, KEY_NUMERIC_9 }, + { 0x800ff400, KEY_NUMERIC_0 }, + + { 0x02200025, KEY_NUMERIC_STAR }, + { 0x02200020, KEY_NUMERIC_POUND }, + /* 0x800ff41d also KEY_BLUE on some receivers */ + { 0x800ff41d, KEY_NUMERIC_STAR }, + /* 0x800ff41c also KEY_PREVIOUS on some receivers */ + { 0x800ff41c, KEY_NUMERIC_POUND }, + + { 0x800ff446, KEY_TV }, + { 0x800ff447, KEY_AUDIO }, /* My Music */ + { 0x800ff448, KEY_PVR }, /* RecordedTV */ + { 0x800ff449, KEY_CAMERA }, + { 0x800ff44a, KEY_VIDEO }, + /* 0x800ff424 also KEY_MENU on some receivers */ + { 0x800ff424, KEY_DVD }, + /* 0x800ff425 also KEY_GREEN on some receivers */ + { 0x800ff425, KEY_TUNER }, /* LiveTV */ + { 0x800ff450, KEY_RADIO }, + + { 0x800ff44c, KEY_LANGUAGE }, + { 0x800ff427, KEY_ZOOM }, /* Aspect */ + + { 0x800ff45b, KEY_RED }, + { 0x800ff45c, KEY_GREEN }, + { 0x800ff45d, KEY_YELLOW }, + { 0x800ff45e, KEY_BLUE }, + + { 0x800ff466, KEY_RED }, + /* { 0x800ff425, KEY_GREEN }, */ + { 0x800ff468, KEY_YELLOW }, + /* { 0x800ff41d, KEY_BLUE }, */ + + { 0x800ff40f, KEY_INFO }, + { 0x800ff426, KEY_EPG }, /* Guide */ + { 0x800ff45a, KEY_SUBTITLE }, /* Caption/Teletext */ + { 0x800ff44d, KEY_TITLE }, + + { 0x800ff40c, KEY_POWER }, + { 0x800ff40d, KEY_MEDIA }, /* Windows MCE button */ + +}; + +static struct rc_map_list imon_mce_map = { + .map = { + .scan = imon_mce, + .size = ARRAY_SIZE(imon_mce), + /* its RC6, but w/a hardware decoder */ + .rc_type = RC_TYPE_RC6, + .name = RC_MAP_IMON_MCE, + } +}; + +static int __init init_rc_map_imon_mce(void) +{ + return rc_map_register(&imon_mce_map); +} + +static void __exit exit_rc_map_imon_mce(void) +{ + rc_map_unregister(&imon_mce_map); +} + +module_init(init_rc_map_imon_mce) +module_exit(exit_rc_map_imon_mce) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-imon-pad.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-imon-pad.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-imon-pad.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-imon-pad.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,156 @@ +/* rc5-imon-pad.c - Keytable for SoundGraph iMON PAD and Antec Veris + * RM-200 Remote Control + * + * Copyright (c) 2010 by Jarod Wilson + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * standard imon remote key table, which isn't really entirely + * "standard", as different receivers decode the same key on the + * same remote to different hex codes, and the silkscreened names + * vary a bit between the SoundGraph and Antec remotes... ugh. + */ +static struct rc_map_table imon_pad[] = { + /* keys sorted mostly by frequency of use to optimize lookups */ + { 0x2a8195b7, KEY_REWIND }, + { 0x298315b7, KEY_REWIND }, + { 0x2b8115b7, KEY_FASTFORWARD }, + { 0x2b8315b7, KEY_FASTFORWARD }, + { 0x2b9115b7, KEY_PREVIOUS }, + { 0x298195b7, KEY_NEXT }, + + { 0x2a8115b7, KEY_PLAY }, + { 0x2a8315b7, KEY_PLAY }, + { 0x2a9115b7, KEY_PAUSE }, + { 0x2b9715b7, KEY_STOP }, + { 0x298115b7, KEY_RECORD }, + + { 0x01008000, KEY_UP }, + { 0x01007f00, KEY_DOWN }, + { 0x01000080, KEY_LEFT }, + { 0x0100007f, KEY_RIGHT }, + + { 0x2aa515b7, KEY_UP }, + { 0x289515b7, KEY_DOWN }, + { 0x29a515b7, KEY_LEFT }, + { 0x2ba515b7, KEY_RIGHT }, + + { 0x0200002c, KEY_SPACE }, /* Select/Space */ + { 0x2a9315b7, KEY_SPACE }, /* Select/Space */ + { 0x02000028, KEY_ENTER }, + { 0x28a195b7, KEY_ENTER }, + { 0x288195b7, KEY_EXIT }, + { 0x02000029, KEY_ESC }, + { 0x2bb715b7, KEY_ESC }, + { 0x0200002a, KEY_BACKSPACE }, + { 0x28a115b7, KEY_BACKSPACE }, + + { 0x2b9595b7, KEY_MUTE }, + { 0x28a395b7, KEY_VOLUMEUP }, + { 0x28a595b7, KEY_VOLUMEDOWN }, + { 0x289395b7, KEY_CHANNELUP }, + { 0x288795b7, KEY_CHANNELDOWN }, + + { 0x0200001e, KEY_NUMERIC_1 }, + { 0x0200001f, KEY_NUMERIC_2 }, + { 0x02000020, KEY_NUMERIC_3 }, + { 0x02000021, KEY_NUMERIC_4 }, + { 0x02000022, KEY_NUMERIC_5 }, + { 0x02000023, KEY_NUMERIC_6 }, + { 0x02000024, KEY_NUMERIC_7 }, + { 0x02000025, KEY_NUMERIC_8 }, + { 0x02000026, KEY_NUMERIC_9 }, + { 0x02000027, KEY_NUMERIC_0 }, + + { 0x28b595b7, KEY_NUMERIC_1 }, + { 0x2bb195b7, KEY_NUMERIC_2 }, + { 0x28b195b7, KEY_NUMERIC_3 }, + { 0x2a8595b7, KEY_NUMERIC_4 }, + { 0x299595b7, KEY_NUMERIC_5 }, + { 0x2aa595b7, KEY_NUMERIC_6 }, + { 0x2b9395b7, KEY_NUMERIC_7 }, + { 0x2a8515b7, KEY_NUMERIC_8 }, + { 0x2aa115b7, KEY_NUMERIC_9 }, + { 0x2ba595b7, KEY_NUMERIC_0 }, + + { 0x02200025, KEY_NUMERIC_STAR }, + { 0x28b515b7, KEY_NUMERIC_STAR }, + { 0x02200020, KEY_NUMERIC_POUND }, + { 0x29a115b7, KEY_NUMERIC_POUND }, + + { 0x2b8515b7, KEY_VIDEO }, + { 0x299195b7, KEY_AUDIO }, + { 0x2ba115b7, KEY_IMAGES }, + { 0x28a515b7, KEY_TV }, + { 0x29a395b7, KEY_DVD }, + { 0x29a295b7, KEY_DVD }, + + /* the Menu key between DVD and Subtitle on the RM-200... */ + { 0x2ba385b7, KEY_MENU }, + { 0x2ba395b7, KEY_MENU }, + + { 0x288515b7, KEY_BOOKMARKS }, + { 0x2ab715b7, KEY_CAMERA }, /* Thumbnail */ + { 0x298595b7, KEY_SUBTITLE }, + { 0x2b8595b7, KEY_LANGUAGE }, + + { 0x29a595b7, KEY_ZOOM }, + { 0x2aa395b7, KEY_SCREEN }, /* FullScreen */ + + { 0x299115b7, KEY_KEYBOARD }, + { 0x299135b7, KEY_KEYBOARD }, + + { 0x01010000, BTN_LEFT }, + { 0x01020000, BTN_RIGHT }, + { 0x01010080, BTN_LEFT }, + { 0x01020080, BTN_RIGHT }, + { 0x688301b7, BTN_LEFT }, + { 0x688481b7, BTN_RIGHT }, + + { 0x2a9395b7, KEY_CYCLEWINDOWS }, /* TaskSwitcher */ + { 0x2b8395b7, KEY_TIME }, /* Timer */ + + { 0x289115b7, KEY_POWER }, + { 0x29b195b7, KEY_EJECTCD }, /* the one next to play */ + { 0x299395b7, KEY_EJECTCLOSECD }, /* eject (by TaskSw) */ + + { 0x02800000, KEY_CONTEXT_MENU }, /* Left Menu */ + { 0x2b8195b7, KEY_CONTEXT_MENU }, /* Left Menu*/ + { 0x02000065, KEY_COMPOSE }, /* RightMenu */ + { 0x28b715b7, KEY_COMPOSE }, /* RightMenu */ + { 0x2ab195b7, KEY_MEDIA }, /* Go or MultiMon */ + { 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */ +}; + +static struct rc_map_list imon_pad_map = { + .map = { + .scan = imon_pad, + .size = ARRAY_SIZE(imon_pad), + /* actual protocol details unknown, hardware decoder */ + .rc_type = RC_TYPE_OTHER, + .name = RC_MAP_IMON_PAD, + } +}; + +static int __init init_rc_map_imon_pad(void) +{ + return rc_map_register(&imon_pad_map); +} + +static void __exit exit_rc_map_imon_pad(void) +{ + rc_map_unregister(&imon_pad_map); +} + +module_init(init_rc_map_imon_pad) +module_exit(exit_rc_map_imon_pad) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-iodata-bctv7e.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-iodata-bctv7e.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-iodata-bctv7e.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-iodata-bctv7e.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* iodata-bctv7e.h - Keytable for iodata_bctv7e Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* IO-DATA BCTV7E Remote */ + +static struct rc_map_table iodata_bctv7e[] = { + { 0x40, KEY_TV }, + { 0x20, KEY_RADIO }, /* FM */ + { 0x60, KEY_EPG }, + { 0x00, KEY_POWER }, + + /* Keys 0 to 9 */ + { 0x44, KEY_0 }, /* 10 */ + { 0x50, KEY_1 }, + { 0x30, KEY_2 }, + { 0x70, KEY_3 }, + { 0x48, KEY_4 }, + { 0x28, KEY_5 }, + { 0x68, KEY_6 }, + { 0x58, KEY_7 }, + { 0x38, KEY_8 }, + { 0x78, KEY_9 }, + + { 0x10, KEY_L }, /* Live */ + { 0x08, KEY_TIME }, /* Time Shift */ + + { 0x18, KEY_PLAYPAUSE }, /* Play */ + + { 0x24, KEY_ENTER }, /* 11 */ + { 0x64, KEY_ESC }, /* 12 */ + { 0x04, KEY_M }, /* Multi */ + + { 0x54, KEY_VIDEO }, + { 0x34, KEY_CHANNELUP }, + { 0x74, KEY_VOLUMEUP }, + { 0x14, KEY_MUTE }, + + { 0x4c, KEY_VCR }, /* SVIDEO */ + { 0x2c, KEY_CHANNELDOWN }, + { 0x6c, KEY_VOLUMEDOWN }, + { 0x0c, KEY_ZOOM }, + + { 0x5c, KEY_PAUSE }, + { 0x3c, KEY_RED }, /* || (red) */ + { 0x7c, KEY_RECORD }, /* recording */ + { 0x1c, KEY_STOP }, + + { 0x41, KEY_REWIND }, /* backward << */ + { 0x21, KEY_PLAY }, + { 0x61, KEY_FASTFORWARD }, /* forward >> */ + { 0x01, KEY_NEXT }, /* skip >| */ +}; + +static struct rc_map_list iodata_bctv7e_map = { + .map = { + .scan = iodata_bctv7e, + .size = ARRAY_SIZE(iodata_bctv7e), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_IODATA_BCTV7E, + } +}; + +static int __init init_rc_map_iodata_bctv7e(void) +{ + return rc_map_register(&iodata_bctv7e_map); +} + +static void __exit exit_rc_map_iodata_bctv7e(void) +{ + rc_map_unregister(&iodata_bctv7e_map); +} + +module_init(init_rc_map_iodata_bctv7e) +module_exit(exit_rc_map_iodata_bctv7e) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kaiomy.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kaiomy.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kaiomy.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kaiomy.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,87 @@ +/* kaiomy.h - Keytable for kaiomy Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Kaiomy TVnPC U2 + Mauro Carvalho Chehab + */ + +static struct rc_map_table kaiomy[] = { + { 0x43, KEY_POWER2}, + { 0x01, KEY_LIST}, + { 0x0b, KEY_ZOOM}, + { 0x03, KEY_POWER}, + + { 0x04, KEY_1}, + { 0x08, KEY_2}, + { 0x02, KEY_3}, + + { 0x0f, KEY_4}, + { 0x05, KEY_5}, + { 0x06, KEY_6}, + + { 0x0c, KEY_7}, + { 0x0d, KEY_8}, + { 0x0a, KEY_9}, + + { 0x11, KEY_0}, + + { 0x09, KEY_CHANNELUP}, + { 0x07, KEY_CHANNELDOWN}, + + { 0x0e, KEY_VOLUMEUP}, + { 0x13, KEY_VOLUMEDOWN}, + + { 0x10, KEY_HOME}, + { 0x12, KEY_ENTER}, + + { 0x14, KEY_RECORD}, + { 0x15, KEY_STOP}, + { 0x16, KEY_PLAY}, + { 0x17, KEY_MUTE}, + + { 0x18, KEY_UP}, + { 0x19, KEY_DOWN}, + { 0x1a, KEY_LEFT}, + { 0x1b, KEY_RIGHT}, + + { 0x1c, KEY_RED}, + { 0x1d, KEY_GREEN}, + { 0x1e, KEY_YELLOW}, + { 0x1f, KEY_BLUE}, +}; + +static struct rc_map_list kaiomy_map = { + .map = { + .scan = kaiomy, + .size = ARRAY_SIZE(kaiomy), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_KAIOMY, + } +}; + +static int __init init_rc_map_kaiomy(void) +{ + return rc_map_register(&kaiomy_map); +} + +static void __exit exit_rc_map_kaiomy(void) +{ + rc_map_unregister(&kaiomy_map); +} + +module_init(init_rc_map_kaiomy) +module_exit(exit_rc_map_kaiomy) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kworld-315u.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kworld-315u.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kworld-315u.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kworld-315u.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* kworld-315u.h - Keytable for kworld_315u Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Kworld 315U + */ + +static struct rc_map_table kworld_315u[] = { + { 0x6143, KEY_POWER }, + { 0x6101, KEY_VIDEO }, /* source */ + { 0x610b, KEY_ZOOM }, + { 0x6103, KEY_POWER2 }, /* shutdown */ + + { 0x6104, KEY_1 }, + { 0x6108, KEY_2 }, + { 0x6102, KEY_3 }, + { 0x6109, KEY_CHANNELUP }, + + { 0x610f, KEY_4 }, + { 0x6105, KEY_5 }, + { 0x6106, KEY_6 }, + { 0x6107, KEY_CHANNELDOWN }, + + { 0x610c, KEY_7 }, + { 0x610d, KEY_8 }, + { 0x610a, KEY_9 }, + { 0x610e, KEY_VOLUMEUP }, + + { 0x6110, KEY_LAST }, + { 0x6111, KEY_0 }, + { 0x6112, KEY_ENTER }, + { 0x6113, KEY_VOLUMEDOWN }, + + { 0x6114, KEY_RECORD }, + { 0x6115, KEY_STOP }, + { 0x6116, KEY_PLAY }, + { 0x6117, KEY_MUTE }, + + { 0x6118, KEY_UP }, + { 0x6119, KEY_DOWN }, + { 0x611a, KEY_LEFT }, + { 0x611b, KEY_RIGHT }, + + { 0x611c, KEY_RED }, + { 0x611d, KEY_GREEN }, + { 0x611e, KEY_YELLOW }, + { 0x611f, KEY_BLUE }, +}; + +static struct rc_map_list kworld_315u_map = { + .map = { + .scan = kworld_315u, + .size = ARRAY_SIZE(kworld_315u), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_KWORLD_315U, + } +}; + +static int __init init_rc_map_kworld_315u(void) +{ + return rc_map_register(&kworld_315u_map); +} + +static void __exit exit_rc_map_kworld_315u(void) +{ + rc_map_unregister(&kworld_315u_map); +} + +module_init(init_rc_map_kworld_315u) +module_exit(exit_rc_map_kworld_315u) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,99 @@ +/* kworld-plus-tv-analog.h - Keytable for kworld_plus_tv_analog Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Kworld Plus TV Analog Lite PCI IR + Mauro Carvalho Chehab + */ + +static struct rc_map_table kworld_plus_tv_analog[] = { + { 0x0c, KEY_MEDIA }, /* Kworld key */ + { 0x16, KEY_CLOSECD }, /* -> ) */ + { 0x1d, KEY_POWER2 }, + + { 0x00, KEY_1 }, + { 0x01, KEY_2 }, + { 0x02, KEY_3 }, /* Two keys have the same code: 3 and left */ + { 0x03, KEY_4 }, /* Two keys have the same code: 3 and right */ + { 0x04, KEY_5 }, + { 0x05, KEY_6 }, + { 0x06, KEY_7 }, + { 0x07, KEY_8 }, + { 0x08, KEY_9 }, + { 0x0a, KEY_0 }, + + { 0x09, KEY_AGAIN }, + { 0x14, KEY_MUTE }, + + { 0x20, KEY_UP }, + { 0x21, KEY_DOWN }, + { 0x0b, KEY_ENTER }, + + { 0x10, KEY_CHANNELUP }, + { 0x11, KEY_CHANNELDOWN }, + + /* Couldn't map key left/key right since those + conflict with '3' and '4' scancodes + I dunno what the original driver does + */ + + { 0x13, KEY_VOLUMEUP }, + { 0x12, KEY_VOLUMEDOWN }, + + /* The lower part of the IR + There are several duplicated keycodes there. + Most of them conflict with digits. + Add mappings just to the unused scancodes. + Somehow, the original driver has a way to know, + but this doesn't seem to be on some GPIO. + Also, it is not related to the time between keyup + and keydown. + */ + { 0x19, KEY_TIME}, /* Timeshift */ + { 0x1a, KEY_STOP}, + { 0x1b, KEY_RECORD}, + + { 0x22, KEY_TEXT}, + + { 0x15, KEY_AUDIO}, /* ((*)) */ + { 0x0f, KEY_ZOOM}, + { 0x1c, KEY_CAMERA}, /* snapshot */ + + { 0x18, KEY_RED}, /* B */ + { 0x23, KEY_GREEN}, /* C */ +}; + +static struct rc_map_list kworld_plus_tv_analog_map = { + .map = { + .scan = kworld_plus_tv_analog, + .size = ARRAY_SIZE(kworld_plus_tv_analog), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_KWORLD_PLUS_TV_ANALOG, + } +}; + +static int __init init_rc_map_kworld_plus_tv_analog(void) +{ + return rc_map_register(&kworld_plus_tv_analog_map); +} + +static void __exit exit_rc_map_kworld_plus_tv_analog(void) +{ + rc_map_unregister(&kworld_plus_tv_analog_map); +} + +module_init(init_rc_map_kworld_plus_tv_analog) +module_exit(exit_rc_map_kworld_plus_tv_analog) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * LeadTek Y04G0051 remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table leadtek_y04g0051[] = { + { 0x0300, KEY_POWER2 }, + { 0x0303, KEY_SCREEN }, + { 0x0304, KEY_RIGHT }, + { 0x0305, KEY_1 }, + { 0x0306, KEY_2 }, + { 0x0307, KEY_3 }, + { 0x0308, KEY_LEFT }, + { 0x0309, KEY_4 }, + { 0x030a, KEY_5 }, + { 0x030b, KEY_6 }, + { 0x030c, KEY_UP }, + { 0x030d, KEY_7 }, + { 0x030e, KEY_8 }, + { 0x030f, KEY_9 }, + { 0x0310, KEY_DOWN }, + { 0x0311, KEY_AGAIN }, + { 0x0312, KEY_0 }, + { 0x0313, KEY_OK }, /* 1st ok */ + { 0x0314, KEY_MUTE }, + { 0x0316, KEY_OK }, /* 2nd ok */ + { 0x031e, KEY_VIDEO }, /* 2nd video */ + { 0x031b, KEY_AUDIO }, + { 0x031f, KEY_TEXT }, + { 0x0340, KEY_SLEEP }, + { 0x0341, KEY_DOT }, + { 0x0342, KEY_REWIND }, + { 0x0343, KEY_PLAY }, + { 0x0344, KEY_FASTFORWARD }, + { 0x0345, KEY_TIME }, + { 0x0346, KEY_STOP }, /* 2nd stop */ + { 0x0347, KEY_RECORD }, + { 0x0348, KEY_CAMERA }, + { 0x0349, KEY_ESC }, + { 0x034a, KEY_NEW }, + { 0x034b, KEY_RED }, + { 0x034c, KEY_GREEN }, + { 0x034d, KEY_YELLOW }, + { 0x034e, KEY_BLUE }, + { 0x034f, KEY_MENU }, + { 0x0350, KEY_STOP }, /* 1st stop */ + { 0x0351, KEY_CHANNEL }, + { 0x0352, KEY_VIDEO }, /* 1st video */ + { 0x0353, KEY_EPG }, + { 0x0354, KEY_PREVIOUS }, + { 0x0355, KEY_NEXT }, + { 0x0356, KEY_TV }, + { 0x035a, KEY_VOLUMEDOWN }, + { 0x035b, KEY_CHANNELUP }, + { 0x035e, KEY_VOLUMEUP }, + { 0x035f, KEY_CHANNELDOWN }, +}; + +static struct rc_map_list leadtek_y04g0051_map = { + .map = { + .scan = leadtek_y04g0051, + .size = ARRAY_SIZE(leadtek_y04g0051), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_LEADTEK_Y04G0051, + } +}; + +static int __init init_rc_map_leadtek_y04g0051(void) +{ + return rc_map_register(&leadtek_y04g0051_map); +} + +static void __exit exit_rc_map_leadtek_y04g0051(void) +{ + rc_map_unregister(&leadtek_y04g0051_map); +} + +module_init(init_rc_map_leadtek_y04g0051) +module_exit(exit_rc_map_leadtek_y04g0051) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-lirc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-lirc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-lirc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-lirc.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass + * all raw IR data to the lirc userspace decoder. + * + * Copyright (c) 2010 by Jarod Wilson + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table lirc[] = { + { }, +}; + +static struct rc_map_list lirc_map = { + .map = { + .scan = lirc, + .size = ARRAY_SIZE(lirc), + .rc_type = RC_TYPE_LIRC, + .name = RC_MAP_LIRC, + } +}; + +static int __init init_rc_map_lirc(void) +{ + return rc_map_register(&lirc_map); +} + +static void __exit exit_rc_map_lirc(void) +{ + rc_map_unregister(&lirc_map); +} + +module_init(init_rc_map_lirc) +module_exit(exit_rc_map_lirc) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-lme2510.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-lme2510.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-lme2510.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-lme2510.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,110 @@ +/* LME2510 remote control + * + * + * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.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, or + * (at your option) any later version. + */ + +#include + + +static struct rc_map_table lme2510_rc[] = { + /* Type 1 - 26 buttons */ + { 0x10ed45, KEY_0 }, + { 0x10ed5f, KEY_1 }, + { 0x10ed50, KEY_2 }, + { 0x10ed5d, KEY_3 }, + { 0x10ed41, KEY_4 }, + { 0x10ed0a, KEY_5 }, + { 0x10ed42, KEY_6 }, + { 0x10ed47, KEY_7 }, + { 0x10ed49, KEY_8 }, + { 0x10ed05, KEY_9 }, + { 0x10ed43, KEY_POWER }, + { 0x10ed46, KEY_SUBTITLE }, + { 0x10ed06, KEY_PAUSE }, + { 0x10ed03, KEY_MEDIA_REPEAT}, + { 0x10ed02, KEY_PAUSE }, + { 0x10ed5e, KEY_VOLUMEUP }, + { 0x10ed5c, KEY_VOLUMEDOWN }, + { 0x10ed09, KEY_CHANNELUP }, + { 0x10ed1a, KEY_CHANNELDOWN }, + { 0x10ed1e, KEY_PLAY }, + { 0x10ed1b, KEY_ZOOM }, + { 0x10ed59, KEY_MUTE }, + { 0x10ed5a, KEY_TV }, + { 0x10ed18, KEY_RECORD }, + { 0x10ed07, KEY_EPG }, + { 0x10ed01, KEY_STOP }, + /* Type 2 - 20 buttons */ + { 0xbf15, KEY_0 }, + { 0xbf08, KEY_1 }, + { 0xbf09, KEY_2 }, + { 0xbf0a, KEY_3 }, + { 0xbf0c, KEY_4 }, + { 0xbf0d, KEY_5 }, + { 0xbf0e, KEY_6 }, + { 0xbf10, KEY_7 }, + { 0xbf11, KEY_8 }, + { 0xbf12, KEY_9 }, + { 0xbf00, KEY_POWER }, + { 0xbf04, KEY_MEDIA_REPEAT}, /* Recall */ + { 0xbf1a, KEY_PAUSE }, /* Timeshift */ + { 0xbf02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0xbf06, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ + { 0xbf01, KEY_CHANNELUP }, + { 0xbf05, KEY_CHANNELDOWN }, + { 0xbf14, KEY_ZOOM }, + { 0xbf18, KEY_RECORD }, + { 0xbf16, KEY_STOP }, + /* Type 3 - 20 buttons */ + { 0x1c, KEY_0 }, + { 0x07, KEY_1 }, + { 0x15, KEY_2 }, + { 0x09, KEY_3 }, + { 0x16, KEY_4 }, + { 0x19, KEY_5 }, + { 0x0d, KEY_6 }, + { 0x0c, KEY_7 }, + { 0x18, KEY_8 }, + { 0x5e, KEY_9 }, + { 0x45, KEY_POWER }, + { 0x44, KEY_MEDIA_REPEAT}, /* Recall */ + { 0x4a, KEY_PAUSE }, /* Timeshift */ + { 0x47, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0x43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ + { 0x46, KEY_CHANNELUP }, + { 0x40, KEY_CHANNELDOWN }, + { 0x08, KEY_ZOOM }, + { 0x42, KEY_RECORD }, + { 0x5a, KEY_STOP }, +}; + +static struct rc_map_list lme2510_map = { + .map = { + .scan = lme2510_rc, + .size = ARRAY_SIZE(lme2510_rc), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_LME2510, + } +}; + +static int __init init_rc_lme2510_map(void) +{ + return rc_map_register(&lme2510_map); +} + +static void __exit exit_rc_lme2510_map(void) +{ + rc_map_unregister(&lme2510_map); +} + +module_init(init_rc_lme2510_map) +module_exit(exit_rc_lme2510_map) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-manli.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-manli.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-manli.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-manli.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,134 @@ +/* manli.h - Keytable for manli Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Michael Tokarev + keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at + least, and probably other cards too. + The "ascii-art picture" below (in comments, first row + is the keycode in hex, and subsequent row(s) shows + the button labels (several variants when appropriate) + helps to descide which keycodes to assign to the buttons. + */ + +static struct rc_map_table manli[] = { + + /* 0x1c 0x12 * + * FUNCTION POWER * + * FM (|) * + * */ + { 0x1c, KEY_RADIO }, /*XXX*/ + { 0x12, KEY_POWER }, + + /* 0x01 0x02 0x03 * + * 1 2 3 * + * * + * 0x04 0x05 0x06 * + * 4 5 6 * + * * + * 0x07 0x08 0x09 * + * 7 8 9 * + * */ + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + + /* 0x0a 0x00 0x17 * + * RECALL 0 +100 * + * PLUS * + * */ + { 0x0a, KEY_AGAIN }, /*XXX KEY_REWIND? */ + { 0x00, KEY_0 }, + { 0x17, KEY_DIGITS }, /*XXX*/ + + /* 0x14 0x10 * + * MENU INFO * + * OSD */ + { 0x14, KEY_MENU }, + { 0x10, KEY_INFO }, + + /* 0x0b * + * Up * + * * + * 0x18 0x16 0x0c * + * Left Ok Right * + * * + * 0x015 * + * Down * + * */ + { 0x0b, KEY_UP }, + { 0x18, KEY_LEFT }, + { 0x16, KEY_OK }, /*XXX KEY_SELECT? KEY_ENTER? */ + { 0x0c, KEY_RIGHT }, + { 0x15, KEY_DOWN }, + + /* 0x11 0x0d * + * TV/AV MODE * + * SOURCE STEREO * + * */ + { 0x11, KEY_TV }, /*XXX*/ + { 0x0d, KEY_MODE }, /*XXX there's no KEY_STEREO */ + + /* 0x0f 0x1b 0x1a * + * AUDIO Vol+ Chan+ * + * TIMESHIFT??? * + * * + * 0x0e 0x1f 0x1e * + * SLEEP Vol- Chan- * + * */ + { 0x0f, KEY_AUDIO }, + { 0x1b, KEY_VOLUMEUP }, + { 0x1a, KEY_CHANNELUP }, + { 0x0e, KEY_TIME }, + { 0x1f, KEY_VOLUMEDOWN }, + { 0x1e, KEY_CHANNELDOWN }, + + /* 0x13 0x19 * + * MUTE SNAPSHOT* + * */ + { 0x13, KEY_MUTE }, + { 0x19, KEY_CAMERA }, + + /* 0x1d unused ? */ +}; + +static struct rc_map_list manli_map = { + .map = { + .scan = manli, + .size = ARRAY_SIZE(manli), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_MANLI, + } +}; + +static int __init init_rc_map_manli(void) +{ + return rc_map_register(&manli_map); +} + +static void __exit exit_rc_map_manli(void) +{ + rc_map_unregister(&manli_map); +} + +module_init(init_rc_map_manli) +module_exit(exit_rc_map_manli) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-digivox-ii.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-digivox-ii.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-digivox-ii.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-digivox-ii.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,67 @@ +/* + * MSI DIGIVOX mini II remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table msi_digivox_ii[] = { + { 0x0002, KEY_2 }, + { 0x0003, KEY_UP }, /* up */ + { 0x0004, KEY_3 }, + { 0x0005, KEY_CHANNELDOWN }, + { 0x0008, KEY_5 }, + { 0x0009, KEY_0 }, + { 0x000b, KEY_8 }, + { 0x000d, KEY_DOWN }, /* down */ + { 0x0010, KEY_9 }, + { 0x0011, KEY_7 }, + { 0x0014, KEY_VOLUMEUP }, + { 0x0015, KEY_CHANNELUP }, + { 0x0016, KEY_OK }, + { 0x0017, KEY_POWER2 }, + { 0x001a, KEY_1 }, + { 0x001c, KEY_4 }, + { 0x001d, KEY_6 }, + { 0x001f, KEY_VOLUMEDOWN }, +}; + +static struct rc_map_list msi_digivox_ii_map = { + .map = { + .scan = msi_digivox_ii, + .size = ARRAY_SIZE(msi_digivox_ii), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_MSI_DIGIVOX_II, + } +}; + +static int __init init_rc_map_msi_digivox_ii(void) +{ + return rc_map_register(&msi_digivox_ii_map); +} + +static void __exit exit_rc_map_msi_digivox_ii(void) +{ + rc_map_unregister(&msi_digivox_ii_map); +} + +module_init(init_rc_map_msi_digivox_ii) +module_exit(exit_rc_map_msi_digivox_ii) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-digivox-iii.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-digivox-iii.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-digivox-iii.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-digivox-iii.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * MSI DIGIVOX mini III remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* MSI DIGIVOX mini III */ +/* Uses NEC extended 0x61d6. */ +/* This remote seems to be same as rc-kworld-315u.c. Anyhow, add new remote + since rc-kworld-315u.c lacks NEC extended address byte. */ +static struct rc_map_table msi_digivox_iii[] = { + { 0x61d601, KEY_VIDEO }, /* Source */ + { 0x61d602, KEY_3 }, + { 0x61d603, KEY_POWER }, /* ShutDown */ + { 0x61d604, KEY_1 }, + { 0x61d605, KEY_5 }, + { 0x61d606, KEY_6 }, + { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ + { 0x61d608, KEY_2 }, + { 0x61d609, KEY_CHANNELUP }, /* CH+ */ + { 0x61d60a, KEY_9 }, + { 0x61d60b, KEY_ZOOM }, /* Zoom */ + { 0x61d60c, KEY_7 }, + { 0x61d60d, KEY_8 }, + { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ + { 0x61d60f, KEY_4 }, + { 0x61d610, KEY_ESC }, /* [back up arrow] */ + { 0x61d611, KEY_0 }, + { 0x61d612, KEY_OK }, /* [enter arrow] */ + { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ + { 0x61d614, KEY_RECORD }, /* Rec */ + { 0x61d615, KEY_STOP }, /* Stop */ + { 0x61d616, KEY_PLAY }, /* Play */ + { 0x61d617, KEY_MUTE }, /* Mute */ + { 0x61d618, KEY_UP }, + { 0x61d619, KEY_DOWN }, + { 0x61d61a, KEY_LEFT }, + { 0x61d61b, KEY_RIGHT }, + { 0x61d61c, KEY_RED }, + { 0x61d61d, KEY_GREEN }, + { 0x61d61e, KEY_YELLOW }, + { 0x61d61f, KEY_BLUE }, + { 0x61d643, KEY_POWER2 }, /* [red power button] */ +}; + +static struct rc_map_list msi_digivox_iii_map = { + .map = { + .scan = msi_digivox_iii, + .size = ARRAY_SIZE(msi_digivox_iii), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_MSI_DIGIVOX_III, + } +}; + +static int __init init_rc_map_msi_digivox_iii(void) +{ + return rc_map_register(&msi_digivox_iii_map); +} + +static void __exit exit_rc_map_msi_digivox_iii(void) +{ + rc_map_unregister(&msi_digivox_iii_map); +} + +module_init(init_rc_map_msi_digivox_iii) +module_exit(exit_rc_map_msi_digivox_iii) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* msi-tvanywhere.h - Keytable for msi_tvanywhere Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* MSI TV@nywhere MASTER remote */ + +static struct rc_map_table msi_tvanywhere[] = { + /* Keys 0 to 9 */ + { 0x00, KEY_0 }, + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + + { 0x0c, KEY_MUTE }, + { 0x0f, KEY_SCREEN }, /* Full Screen */ + { 0x10, KEY_FN }, /* Function */ + { 0x11, KEY_TIME }, /* Time shift */ + { 0x12, KEY_POWER }, + { 0x13, KEY_MEDIA }, /* MTS */ + { 0x14, KEY_SLOW }, + { 0x16, KEY_REWIND }, /* backward << */ + { 0x17, KEY_ENTER }, /* Return */ + { 0x18, KEY_FASTFORWARD }, /* forward >> */ + { 0x1a, KEY_CHANNELUP }, + { 0x1b, KEY_VOLUMEUP }, + { 0x1e, KEY_CHANNELDOWN }, + { 0x1f, KEY_VOLUMEDOWN }, +}; + +static struct rc_map_list msi_tvanywhere_map = { + .map = { + .scan = msi_tvanywhere, + .size = ARRAY_SIZE(msi_tvanywhere), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_MSI_TVANYWHERE, + } +}; + +static int __init init_rc_map_msi_tvanywhere(void) +{ + return rc_map_register(&msi_tvanywhere_map); +} + +static void __exit exit_rc_map_msi_tvanywhere(void) +{ + rc_map_unregister(&msi_tvanywhere_map); +} + +module_init(init_rc_map_msi_tvanywhere) +module_exit(exit_rc_map_msi_tvanywhere) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,123 @@ +/* msi-tvanywhere-plus.h - Keytable for msi_tvanywhere_plus Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card + is marked "KS003". The controller is I2C at address 0x30, but does not seem + to respond to probes until a read is performed from a valid device. + I don't know why... + + Note: This remote may be of similar or identical design to the + Pixelview remote (?). The raw codes and duplicate button codes + appear to be the same. + + Henry Wong + Some changes to formatting and keycodes by Mark Schultz +*/ + +static struct rc_map_table msi_tvanywhere_plus[] = { + +/* ---- Remote Button Layout ---- + + POWER SOURCE SCAN MUTE + TV/FM 1 2 3 + |> 4 5 6 + <| 7 8 9 + ^^UP 0 + RECALL + vvDN RECORD STOP PLAY + + MINIMIZE ZOOM + + CH+ + VOL- VOL+ + CH- + + SNAPSHOT MTS + + << FUNC >> RESET +*/ + + { 0x01, KEY_1 }, /* 1 */ + { 0x0b, KEY_2 }, /* 2 */ + { 0x1b, KEY_3 }, /* 3 */ + { 0x05, KEY_4 }, /* 4 */ + { 0x09, KEY_5 }, /* 5 */ + { 0x15, KEY_6 }, /* 6 */ + { 0x06, KEY_7 }, /* 7 */ + { 0x0a, KEY_8 }, /* 8 */ + { 0x12, KEY_9 }, /* 9 */ + { 0x02, KEY_0 }, /* 0 */ + { 0x10, KEY_KPPLUS }, /* + */ + { 0x13, KEY_AGAIN }, /* Recall */ + + { 0x1e, KEY_POWER }, /* Power */ + { 0x07, KEY_VIDEO }, /* Source */ + { 0x1c, KEY_SEARCH }, /* Scan */ + { 0x18, KEY_MUTE }, /* Mute */ + + { 0x03, KEY_RADIO }, /* TV/FM */ + /* The next four keys are duplicates that appear to send the + same IR code as Ch+, Ch-, >>, and << . The raw code assigned + to them is the actual code + 0x20 - they will never be + detected as such unless some way is discovered to distinguish + these buttons from those that have the same code. */ + { 0x3f, KEY_RIGHT }, /* |> and Ch+ */ + { 0x37, KEY_LEFT }, /* <| and Ch- */ + { 0x2c, KEY_UP }, /* ^^Up and >> */ + { 0x24, KEY_DOWN }, /* vvDn and << */ + + { 0x00, KEY_RECORD }, /* Record */ + { 0x08, KEY_STOP }, /* Stop */ + { 0x11, KEY_PLAY }, /* Play */ + + { 0x0f, KEY_CLOSE }, /* Minimize */ + { 0x19, KEY_ZOOM }, /* Zoom */ + { 0x1a, KEY_CAMERA }, /* Snapshot */ + { 0x0d, KEY_LANGUAGE }, /* MTS */ + + { 0x14, KEY_VOLUMEDOWN }, /* Vol- */ + { 0x16, KEY_VOLUMEUP }, /* Vol+ */ + { 0x17, KEY_CHANNELDOWN }, /* Ch- */ + { 0x1f, KEY_CHANNELUP }, /* Ch+ */ + + { 0x04, KEY_REWIND }, /* << */ + { 0x0e, KEY_MENU }, /* Function */ + { 0x0c, KEY_FASTFORWARD }, /* >> */ + { 0x1d, KEY_RESTART }, /* Reset */ +}; + +static struct rc_map_list msi_tvanywhere_plus_map = { + .map = { + .scan = msi_tvanywhere_plus, + .size = ARRAY_SIZE(msi_tvanywhere_plus), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_MSI_TVANYWHERE_PLUS, + } +}; + +static int __init init_rc_map_msi_tvanywhere_plus(void) +{ + return rc_map_register(&msi_tvanywhere_plus_map); +} + +static void __exit exit_rc_map_msi_tvanywhere_plus(void) +{ + rc_map_unregister(&msi_tvanywhere_plus_map); +} + +module_init(init_rc_map_msi_tvanywhere_plus) +module_exit(exit_rc_map_msi_tvanywhere_plus) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-nebula.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-nebula.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-nebula.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-nebula.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,96 @@ +/* nebula.h - Keytable for nebula Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table nebula[] = { + { 0x00, KEY_0 }, + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + { 0x0a, KEY_TV }, + { 0x0b, KEY_AUX }, + { 0x0c, KEY_DVD }, + { 0x0d, KEY_POWER }, + { 0x0e, KEY_CAMERA }, /* labelled 'Picture' */ + { 0x0f, KEY_AUDIO }, + { 0x10, KEY_INFO }, + { 0x11, KEY_F13 }, /* 16:9 */ + { 0x12, KEY_F14 }, /* 14:9 */ + { 0x13, KEY_EPG }, + { 0x14, KEY_EXIT }, + { 0x15, KEY_MENU }, + { 0x16, KEY_UP }, + { 0x17, KEY_DOWN }, + { 0x18, KEY_LEFT }, + { 0x19, KEY_RIGHT }, + { 0x1a, KEY_ENTER }, + { 0x1b, KEY_CHANNELUP }, + { 0x1c, KEY_CHANNELDOWN }, + { 0x1d, KEY_VOLUMEUP }, + { 0x1e, KEY_VOLUMEDOWN }, + { 0x1f, KEY_RED }, + { 0x20, KEY_GREEN }, + { 0x21, KEY_YELLOW }, + { 0x22, KEY_BLUE }, + { 0x23, KEY_SUBTITLE }, + { 0x24, KEY_F15 }, /* AD */ + { 0x25, KEY_TEXT }, + { 0x26, KEY_MUTE }, + { 0x27, KEY_REWIND }, + { 0x28, KEY_STOP }, + { 0x29, KEY_PLAY }, + { 0x2a, KEY_FASTFORWARD }, + { 0x2b, KEY_F16 }, /* chapter */ + { 0x2c, KEY_PAUSE }, + { 0x2d, KEY_PLAY }, + { 0x2e, KEY_RECORD }, + { 0x2f, KEY_F17 }, /* picture in picture */ + { 0x30, KEY_KPPLUS }, /* zoom in */ + { 0x31, KEY_KPMINUS }, /* zoom out */ + { 0x32, KEY_F18 }, /* capture */ + { 0x33, KEY_F19 }, /* web */ + { 0x34, KEY_EMAIL }, + { 0x35, KEY_PHONE }, + { 0x36, KEY_PC }, +}; + +static struct rc_map_list nebula_map = { + .map = { + .scan = nebula, + .size = ARRAY_SIZE(nebula), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_NEBULA, + } +}; + +static int __init init_rc_map_nebula(void) +{ + return rc_map_register(&nebula_map); +} + +static void __exit exit_rc_map_nebula(void) +{ + rc_map_unregister(&nebula_map); +} + +module_init(init_rc_map_nebula) +module_exit(exit_rc_map_nebula) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,105 @@ +/* nec-terratec-cinergy-xs.h - Keytable for nec_terratec_cinergy_xs Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Terratec Cinergy Hybrid T USB XS FM + Mauro Carvalho Chehab + */ + +static struct rc_map_table nec_terratec_cinergy_xs[] = { + { 0x1441, KEY_HOME}, + { 0x1401, KEY_POWER2}, + + { 0x1442, KEY_MENU}, /* DVD menu */ + { 0x1443, KEY_SUBTITLE}, + { 0x1444, KEY_TEXT}, /* Teletext */ + { 0x1445, KEY_DELETE}, + + { 0x1402, KEY_1}, + { 0x1403, KEY_2}, + { 0x1404, KEY_3}, + { 0x1405, KEY_4}, + { 0x1406, KEY_5}, + { 0x1407, KEY_6}, + { 0x1408, KEY_7}, + { 0x1409, KEY_8}, + { 0x140a, KEY_9}, + { 0x140c, KEY_0}, + + { 0x140b, KEY_TUNER}, /* AV */ + { 0x140d, KEY_MODE}, /* A.B */ + + { 0x1446, KEY_TV}, + { 0x1447, KEY_DVD}, + { 0x1449, KEY_VIDEO}, + { 0x144a, KEY_RADIO}, /* Music */ + { 0x144b, KEY_CAMERA}, /* PIC */ + + { 0x1410, KEY_UP}, + { 0x1411, KEY_LEFT}, + { 0x1412, KEY_OK}, + { 0x1413, KEY_RIGHT}, + { 0x1414, KEY_DOWN}, + + { 0x140f, KEY_EPG}, + { 0x1416, KEY_INFO}, + { 0x144d, KEY_BACKSPACE}, + + { 0x141c, KEY_VOLUMEUP}, + { 0x141e, KEY_VOLUMEDOWN}, + + { 0x144c, KEY_PLAY}, + { 0x141d, KEY_MUTE}, + + { 0x141b, KEY_CHANNELUP}, + { 0x141f, KEY_CHANNELDOWN}, + + { 0x1417, KEY_RED}, + { 0x1418, KEY_GREEN}, + { 0x1419, KEY_YELLOW}, + { 0x141a, KEY_BLUE}, + + { 0x1458, KEY_RECORD}, + { 0x1448, KEY_STOP}, + { 0x1440, KEY_PAUSE}, + + { 0x1454, KEY_LAST}, + { 0x144e, KEY_REWIND}, + { 0x144f, KEY_FASTFORWARD}, + { 0x145c, KEY_NEXT}, +}; + +static struct rc_map_list nec_terratec_cinergy_xs_map = { + .map = { + .scan = nec_terratec_cinergy_xs, + .size = ARRAY_SIZE(nec_terratec_cinergy_xs), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_NEC_TERRATEC_CINERGY_XS, + } +}; + +static int __init init_rc_map_nec_terratec_cinergy_xs(void) +{ + return rc_map_register(&nec_terratec_cinergy_xs_map); +} + +static void __exit exit_rc_map_nec_terratec_cinergy_xs(void) +{ + rc_map_unregister(&nec_terratec_cinergy_xs_map); +} + +module_init(init_rc_map_nec_terratec_cinergy_xs) +module_exit(exit_rc_map_nec_terratec_cinergy_xs) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-norwood.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-norwood.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-norwood.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-norwood.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* norwood.h - Keytable for norwood Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Norwood Micro (non-Pro) TV Tuner + By Peter Naulls + Key comments are the functions given in the manual */ + +static struct rc_map_table norwood[] = { + /* Keys 0 to 9 */ + { 0x20, KEY_0 }, + { 0x21, KEY_1 }, + { 0x22, KEY_2 }, + { 0x23, KEY_3 }, + { 0x24, KEY_4 }, + { 0x25, KEY_5 }, + { 0x26, KEY_6 }, + { 0x27, KEY_7 }, + { 0x28, KEY_8 }, + { 0x29, KEY_9 }, + + { 0x78, KEY_VIDEO }, /* Video Source */ + { 0x2c, KEY_EXIT }, /* Open/Close software */ + { 0x2a, KEY_SELECT }, /* 2 Digit Select */ + { 0x69, KEY_AGAIN }, /* Recall */ + + { 0x32, KEY_BRIGHTNESSUP }, /* Brightness increase */ + { 0x33, KEY_BRIGHTNESSDOWN }, /* Brightness decrease */ + { 0x6b, KEY_KPPLUS }, /* (not named >>>>>) */ + { 0x6c, KEY_KPMINUS }, /* (not named <<<<<) */ + + { 0x2d, KEY_MUTE }, /* Mute */ + { 0x30, KEY_VOLUMEUP }, /* Volume up */ + { 0x31, KEY_VOLUMEDOWN }, /* Volume down */ + { 0x60, KEY_CHANNELUP }, /* Channel up */ + { 0x61, KEY_CHANNELDOWN }, /* Channel down */ + + { 0x3f, KEY_RECORD }, /* Record */ + { 0x37, KEY_PLAY }, /* Play */ + { 0x36, KEY_PAUSE }, /* Pause */ + { 0x2b, KEY_STOP }, /* Stop */ + { 0x67, KEY_FASTFORWARD }, /* Forward */ + { 0x66, KEY_REWIND }, /* Rewind */ + { 0x3e, KEY_SEARCH }, /* Auto Scan */ + { 0x2e, KEY_CAMERA }, /* Capture Video */ + { 0x6d, KEY_MENU }, /* Show/Hide Control */ + { 0x2f, KEY_ZOOM }, /* Full Screen */ + { 0x34, KEY_RADIO }, /* FM */ + { 0x65, KEY_POWER }, /* Computer power */ +}; + +static struct rc_map_list norwood_map = { + .map = { + .scan = norwood, + .size = ARRAY_SIZE(norwood), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_NORWOOD, + } +}; + +static int __init init_rc_map_norwood(void) +{ + return rc_map_register(&norwood_map); +} + +static void __exit exit_rc_map_norwood(void) +{ + rc_map_unregister(&norwood_map); +} + +module_init(init_rc_map_norwood) +module_exit(exit_rc_map_norwood) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-npgtech.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-npgtech.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-npgtech.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-npgtech.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,80 @@ +/* npgtech.h - Keytable for npgtech Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table npgtech[] = { + { 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */ + { 0x2a, KEY_FRONT }, + + { 0x3e, KEY_1 }, + { 0x02, KEY_2 }, + { 0x06, KEY_3 }, + { 0x0a, KEY_4 }, + { 0x0e, KEY_5 }, + { 0x12, KEY_6 }, + { 0x16, KEY_7 }, + { 0x1a, KEY_8 }, + { 0x1e, KEY_9 }, + { 0x3a, KEY_0 }, + { 0x22, KEY_NUMLOCK }, /* -/-- */ + { 0x20, KEY_REFRESH }, + + { 0x03, KEY_BRIGHTNESSDOWN }, + { 0x28, KEY_AUDIO }, + { 0x3c, KEY_CHANNELUP }, + { 0x3f, KEY_VOLUMEDOWN }, + { 0x2e, KEY_MUTE }, + { 0x3b, KEY_VOLUMEUP }, + { 0x00, KEY_CHANNELDOWN }, + { 0x07, KEY_BRIGHTNESSUP }, + { 0x2c, KEY_TEXT }, + + { 0x37, KEY_RECORD }, + { 0x17, KEY_PLAY }, + { 0x13, KEY_PAUSE }, + { 0x26, KEY_STOP }, + { 0x18, KEY_FASTFORWARD }, + { 0x14, KEY_REWIND }, + { 0x33, KEY_ZOOM }, + { 0x32, KEY_KEYBOARD }, + { 0x30, KEY_GOTO }, /* Pointing arrow */ + { 0x36, KEY_MACRO }, /* Maximize/Minimize (yellow) */ + { 0x0b, KEY_RADIO }, + { 0x10, KEY_POWER }, + +}; + +static struct rc_map_list npgtech_map = { + .map = { + .scan = npgtech, + .size = ARRAY_SIZE(npgtech), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_NPGTECH, + } +}; + +static int __init init_rc_map_npgtech(void) +{ + return rc_map_register(&npgtech_map); +} + +static void __exit exit_rc_map_npgtech(void) +{ + rc_map_unregister(&npgtech_map); +} + +module_init(init_rc_map_npgtech) +module_exit(exit_rc_map_npgtech) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pctv-sedna.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pctv-sedna.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pctv-sedna.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pctv-sedna.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,80 @@ +/* pctv-sedna.h - Keytable for pctv_sedna Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Mapping for the 28 key remote control as seen at + http://www.sednacomputer.com/photo/cardbus-tv.jpg + Pavel Mihaylov + Also for the remote bundled with Kozumi KTV-01C card */ + +static struct rc_map_table pctv_sedna[] = { + { 0x00, KEY_0 }, + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + + { 0x0a, KEY_AGAIN }, /* Recall */ + { 0x0b, KEY_CHANNELUP }, + { 0x0c, KEY_VOLUMEUP }, + { 0x0d, KEY_MODE }, /* Stereo */ + { 0x0e, KEY_STOP }, + { 0x0f, KEY_PREVIOUSSONG }, + { 0x10, KEY_ZOOM }, + { 0x11, KEY_VIDEO }, /* Source */ + { 0x12, KEY_POWER }, + { 0x13, KEY_MUTE }, + { 0x15, KEY_CHANNELDOWN }, + { 0x18, KEY_VOLUMEDOWN }, + { 0x19, KEY_CAMERA }, /* Snapshot */ + { 0x1a, KEY_NEXTSONG }, + { 0x1b, KEY_TIME }, /* Time Shift */ + { 0x1c, KEY_RADIO }, /* FM Radio */ + { 0x1d, KEY_RECORD }, + { 0x1e, KEY_PAUSE }, + /* additional codes for Kozumi's remote */ + { 0x14, KEY_INFO }, /* OSD */ + { 0x16, KEY_OK }, /* OK */ + { 0x17, KEY_DIGITS }, /* Plus */ + { 0x1f, KEY_PLAY }, /* Play */ +}; + +static struct rc_map_list pctv_sedna_map = { + .map = { + .scan = pctv_sedna, + .size = ARRAY_SIZE(pctv_sedna), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PCTV_SEDNA, + } +}; + +static int __init init_rc_map_pctv_sedna(void) +{ + return rc_map_register(&pctv_sedna_map); +} + +static void __exit exit_rc_map_pctv_sedna(void) +{ + rc_map_unregister(&pctv_sedna_map); +} + +module_init(init_rc_map_pctv_sedna) +module_exit(exit_rc_map_pctv_sedna) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-color.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-color.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-color.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-color.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,94 @@ +/* pinnacle-color.h - Keytable for pinnacle_color Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table pinnacle_color[] = { + { 0x59, KEY_MUTE }, + { 0x4a, KEY_POWER }, + + { 0x18, KEY_TEXT }, + { 0x26, KEY_TV }, + { 0x3d, KEY_PRINT }, + + { 0x48, KEY_RED }, + { 0x04, KEY_GREEN }, + { 0x11, KEY_YELLOW }, + { 0x00, KEY_BLUE }, + + { 0x2d, KEY_VOLUMEUP }, + { 0x1e, KEY_VOLUMEDOWN }, + + { 0x49, KEY_MENU }, + + { 0x16, KEY_CHANNELUP }, + { 0x17, KEY_CHANNELDOWN }, + + { 0x20, KEY_UP }, + { 0x21, KEY_DOWN }, + { 0x22, KEY_LEFT }, + { 0x23, KEY_RIGHT }, + { 0x0d, KEY_SELECT }, + + { 0x08, KEY_BACK }, + { 0x07, KEY_REFRESH }, + + { 0x2f, KEY_ZOOM }, + { 0x29, KEY_RECORD }, + + { 0x4b, KEY_PAUSE }, + { 0x4d, KEY_REWIND }, + { 0x2e, KEY_PLAY }, + { 0x4e, KEY_FORWARD }, + { 0x53, KEY_PREVIOUS }, + { 0x4c, KEY_STOP }, + { 0x54, KEY_NEXT }, + + { 0x69, KEY_0 }, + { 0x6a, KEY_1 }, + { 0x6b, KEY_2 }, + { 0x6c, KEY_3 }, + { 0x6d, KEY_4 }, + { 0x6e, KEY_5 }, + { 0x6f, KEY_6 }, + { 0x70, KEY_7 }, + { 0x71, KEY_8 }, + { 0x72, KEY_9 }, + + { 0x74, KEY_CHANNEL }, + { 0x0a, KEY_BACKSPACE }, +}; + +static struct rc_map_list pinnacle_color_map = { + .map = { + .scan = pinnacle_color, + .size = ARRAY_SIZE(pinnacle_color), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PINNACLE_COLOR, + } +}; + +static int __init init_rc_map_pinnacle_color(void) +{ + return rc_map_register(&pinnacle_color_map); +} + +static void __exit exit_rc_map_pinnacle_color(void) +{ + rc_map_unregister(&pinnacle_color_map); +} + +module_init(init_rc_map_pinnacle_color) +module_exit(exit_rc_map_pinnacle_color) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-grey.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-grey.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-grey.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-grey.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,89 @@ +/* pinnacle-grey.h - Keytable for pinnacle_grey Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table pinnacle_grey[] = { + { 0x3a, KEY_0 }, + { 0x31, KEY_1 }, + { 0x32, KEY_2 }, + { 0x33, KEY_3 }, + { 0x34, KEY_4 }, + { 0x35, KEY_5 }, + { 0x36, KEY_6 }, + { 0x37, KEY_7 }, + { 0x38, KEY_8 }, + { 0x39, KEY_9 }, + + { 0x2f, KEY_POWER }, + + { 0x2e, KEY_P }, + { 0x1f, KEY_L }, + { 0x2b, KEY_I }, + + { 0x2d, KEY_SCREEN }, + { 0x1e, KEY_ZOOM }, + { 0x1b, KEY_VOLUMEUP }, + { 0x0f, KEY_VOLUMEDOWN }, + { 0x17, KEY_CHANNELUP }, + { 0x1c, KEY_CHANNELDOWN }, + { 0x25, KEY_INFO }, + + { 0x3c, KEY_MUTE }, + + { 0x3d, KEY_LEFT }, + { 0x3b, KEY_RIGHT }, + + { 0x3f, KEY_UP }, + { 0x3e, KEY_DOWN }, + { 0x1a, KEY_ENTER }, + + { 0x1d, KEY_MENU }, + { 0x19, KEY_AGAIN }, + { 0x16, KEY_PREVIOUSSONG }, + { 0x13, KEY_NEXTSONG }, + { 0x15, KEY_PAUSE }, + { 0x0e, KEY_REWIND }, + { 0x0d, KEY_PLAY }, + { 0x0b, KEY_STOP }, + { 0x07, KEY_FORWARD }, + { 0x27, KEY_RECORD }, + { 0x26, KEY_TUNER }, + { 0x29, KEY_TEXT }, + { 0x2a, KEY_MEDIA }, + { 0x18, KEY_EPG }, +}; + +static struct rc_map_list pinnacle_grey_map = { + .map = { + .scan = pinnacle_grey, + .size = ARRAY_SIZE(pinnacle_grey), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PINNACLE_GREY, + } +}; + +static int __init init_rc_map_pinnacle_grey(void) +{ + return rc_map_register(&pinnacle_grey_map); +} + +static void __exit exit_rc_map_pinnacle_grey(void) +{ + rc_map_unregister(&pinnacle_grey_map); +} + +module_init(init_rc_map_pinnacle_grey) +module_exit(exit_rc_map_pinnacle_grey) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,73 @@ +/* pinnacle-pctv-hd.h - Keytable for pinnacle_pctv_hd Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Pinnacle PCTV HD 800i mini remote */ + +static struct rc_map_table pinnacle_pctv_hd[] = { + + { 0x0f, KEY_1 }, + { 0x15, KEY_2 }, + { 0x10, KEY_3 }, + { 0x18, KEY_4 }, + { 0x1b, KEY_5 }, + { 0x1e, KEY_6 }, + { 0x11, KEY_7 }, + { 0x21, KEY_8 }, + { 0x12, KEY_9 }, + { 0x27, KEY_0 }, + + { 0x24, KEY_ZOOM }, + { 0x2a, KEY_SUBTITLE }, + + { 0x00, KEY_MUTE }, + { 0x01, KEY_ENTER }, /* Pinnacle Logo */ + { 0x39, KEY_POWER }, + + { 0x03, KEY_VOLUMEUP }, + { 0x09, KEY_VOLUMEDOWN }, + { 0x06, KEY_CHANNELUP }, + { 0x0c, KEY_CHANNELDOWN }, + + { 0x2d, KEY_REWIND }, + { 0x30, KEY_PLAYPAUSE }, + { 0x33, KEY_FASTFORWARD }, + { 0x3c, KEY_STOP }, + { 0x36, KEY_RECORD }, + { 0x3f, KEY_EPG }, /* Labeled "?" */ +}; + +static struct rc_map_list pinnacle_pctv_hd_map = { + .map = { + .scan = pinnacle_pctv_hd, + .size = ARRAY_SIZE(pinnacle_pctv_hd), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PINNACLE_PCTV_HD, + } +}; + +static int __init init_rc_map_pinnacle_pctv_hd(void) +{ + return rc_map_register(&pinnacle_pctv_hd_map); +} + +static void __exit exit_rc_map_pinnacle_pctv_hd(void) +{ + rc_map_unregister(&pinnacle_pctv_hd_map); +} + +module_init(init_rc_map_pinnacle_pctv_hd) +module_exit(exit_rc_map_pinnacle_pctv_hd) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-002t.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-002t.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-002t.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-002t.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,77 @@ +/* rc-pixelview-mk12.h - Keytable for pixelview Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Keytable for 002-T IR remote provided together with Pixelview + * SBTVD Hybrid Remote Controller. Uses NEC extended format. + */ +static struct rc_map_table pixelview_002t[] = { + { 0x866b13, KEY_MUTE }, + { 0x866b12, KEY_POWER2 }, /* power */ + + { 0x866b01, KEY_1 }, + { 0x866b02, KEY_2 }, + { 0x866b03, KEY_3 }, + { 0x866b04, KEY_4 }, + { 0x866b05, KEY_5 }, + { 0x866b06, KEY_6 }, + { 0x866b07, KEY_7 }, + { 0x866b08, KEY_8 }, + { 0x866b09, KEY_9 }, + { 0x866b00, KEY_0 }, + + { 0x866b0d, KEY_CHANNELUP }, + { 0x866b19, KEY_CHANNELDOWN }, + { 0x866b10, KEY_VOLUMEUP }, /* vol + */ + { 0x866b0c, KEY_VOLUMEDOWN }, /* vol - */ + + { 0x866b0a, KEY_CAMERA }, /* snapshot */ + { 0x866b0b, KEY_ZOOM }, /* zoom */ + + { 0x866b1b, KEY_BACKSPACE }, + { 0x866b15, KEY_ENTER }, + + { 0x866b1d, KEY_UP }, + { 0x866b1e, KEY_DOWN }, + { 0x866b0e, KEY_LEFT }, + { 0x866b0f, KEY_RIGHT }, + + { 0x866b18, KEY_RECORD }, + { 0x866b1a, KEY_STOP }, +}; + +static struct rc_map_list pixelview_map = { + .map = { + .scan = pixelview_002t, + .size = ARRAY_SIZE(pixelview_002t), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_PIXELVIEW_002T, + } +}; + +static int __init init_rc_map_pixelview(void) +{ + return rc_map_register(&pixelview_map); +} + +static void __exit exit_rc_map_pixelview(void) +{ + rc_map_unregister(&pixelview_map); +} + +module_init(init_rc_map_pixelview) +module_exit(exit_rc_map_pixelview) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* pixelview.h - Keytable for pixelview Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table pixelview[] = { + + { 0x1e, KEY_POWER }, /* power */ + { 0x07, KEY_VIDEO }, /* source */ + { 0x1c, KEY_SEARCH }, /* scan */ + + + { 0x03, KEY_TUNER }, /* TV/FM */ + + { 0x00, KEY_RECORD }, + { 0x08, KEY_STOP }, + { 0x11, KEY_PLAY }, + + { 0x1a, KEY_PLAYPAUSE }, /* freeze */ + { 0x19, KEY_ZOOM }, /* zoom */ + { 0x0f, KEY_TEXT }, /* min */ + + { 0x01, KEY_1 }, + { 0x0b, KEY_2 }, + { 0x1b, KEY_3 }, + { 0x05, KEY_4 }, + { 0x09, KEY_5 }, + { 0x15, KEY_6 }, + { 0x06, KEY_7 }, + { 0x0a, KEY_8 }, + { 0x12, KEY_9 }, + { 0x02, KEY_0 }, + { 0x10, KEY_LAST }, /* +100 */ + { 0x13, KEY_LIST }, /* recall */ + + { 0x1f, KEY_CHANNELUP }, /* chn down */ + { 0x17, KEY_CHANNELDOWN }, /* chn up */ + { 0x16, KEY_VOLUMEUP }, /* vol down */ + { 0x14, KEY_VOLUMEDOWN }, /* vol up */ + + { 0x04, KEY_KPMINUS }, /* <<< */ + { 0x0e, KEY_SETUP }, /* function */ + { 0x0c, KEY_KPPLUS }, /* >>> */ + + { 0x0d, KEY_GOTO }, /* mts */ + { 0x1d, KEY_REFRESH }, /* reset */ + { 0x18, KEY_MUTE }, /* mute/unmute */ +}; + +static struct rc_map_list pixelview_map = { + .map = { + .scan = pixelview, + .size = ARRAY_SIZE(pixelview), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PIXELVIEW, + } +}; + +static int __init init_rc_map_pixelview(void) +{ + return rc_map_register(&pixelview_map); +} + +static void __exit exit_rc_map_pixelview(void) +{ + rc_map_unregister(&pixelview_map); +} + +module_init(init_rc_map_pixelview) +module_exit(exit_rc_map_pixelview) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-mk12.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-mk12.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-mk12.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-mk12.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* rc-pixelview-mk12.h - Keytable for pixelview Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Keytable for MK-F12 IR remote provided together with Pixelview + * Ultra Pro Remote Controller. Uses NEC extended format. + */ +static struct rc_map_table pixelview_mk12[] = { + { 0x866b03, KEY_TUNER }, /* Timeshift */ + { 0x866b1e, KEY_POWER2 }, /* power */ + + { 0x866b01, KEY_1 }, + { 0x866b0b, KEY_2 }, + { 0x866b1b, KEY_3 }, + { 0x866b05, KEY_4 }, + { 0x866b09, KEY_5 }, + { 0x866b15, KEY_6 }, + { 0x866b06, KEY_7 }, + { 0x866b0a, KEY_8 }, + { 0x866b12, KEY_9 }, + { 0x866b02, KEY_0 }, + + { 0x866b13, KEY_AGAIN }, /* loop */ + { 0x866b10, KEY_DIGITS }, /* +100 */ + + { 0x866b00, KEY_VIDEO }, /* source */ + { 0x866b18, KEY_MUTE }, /* mute */ + { 0x866b19, KEY_CAMERA }, /* snapshot */ + { 0x866b1a, KEY_SEARCH }, /* scan */ + + { 0x866b16, KEY_CHANNELUP }, /* chn + */ + { 0x866b14, KEY_CHANNELDOWN }, /* chn - */ + { 0x866b1f, KEY_VOLUMEUP }, /* vol + */ + { 0x866b17, KEY_VOLUMEDOWN }, /* vol - */ + { 0x866b1c, KEY_ZOOM }, /* zoom */ + + { 0x866b04, KEY_REWIND }, + { 0x866b0e, KEY_RECORD }, + { 0x866b0c, KEY_FORWARD }, + + { 0x866b1d, KEY_STOP }, + { 0x866b08, KEY_PLAY }, + { 0x866b0f, KEY_PAUSE }, + + { 0x866b0d, KEY_TV }, + { 0x866b07, KEY_RADIO }, /* FM */ +}; + +static struct rc_map_list pixelview_map = { + .map = { + .scan = pixelview_mk12, + .size = ARRAY_SIZE(pixelview_mk12), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_PIXELVIEW_MK12, + } +}; + +static int __init init_rc_map_pixelview(void) +{ + return rc_map_register(&pixelview_map); +} + +static void __exit exit_rc_map_pixelview(void) +{ + rc_map_unregister(&pixelview_map); +} + +module_init(init_rc_map_pixelview) +module_exit(exit_rc_map_pixelview) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-new.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-new.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-new.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pixelview-new.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,83 @@ +/* pixelview-new.h - Keytable for pixelview_new Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + Mauro Carvalho Chehab + present on PV MPEG 8000GT + */ + +static struct rc_map_table pixelview_new[] = { + { 0x3c, KEY_TIME }, /* Timeshift */ + { 0x12, KEY_POWER }, + + { 0x3d, KEY_1 }, + { 0x38, KEY_2 }, + { 0x18, KEY_3 }, + { 0x35, KEY_4 }, + { 0x39, KEY_5 }, + { 0x15, KEY_6 }, + { 0x36, KEY_7 }, + { 0x3a, KEY_8 }, + { 0x1e, KEY_9 }, + { 0x3e, KEY_0 }, + + { 0x1c, KEY_AGAIN }, /* LOOP */ + { 0x3f, KEY_VIDEO }, /* Source */ + { 0x1f, KEY_LAST }, /* +100 */ + { 0x1b, KEY_MUTE }, + + { 0x17, KEY_CHANNELDOWN }, + { 0x16, KEY_CHANNELUP }, + { 0x10, KEY_VOLUMEUP }, + { 0x14, KEY_VOLUMEDOWN }, + { 0x13, KEY_ZOOM }, + + { 0x19, KEY_CAMERA }, /* SNAPSHOT */ + { 0x1a, KEY_SEARCH }, /* scan */ + + { 0x37, KEY_REWIND }, /* << */ + { 0x32, KEY_RECORD }, /* o (red) */ + { 0x33, KEY_FORWARD }, /* >> */ + { 0x11, KEY_STOP }, /* square */ + { 0x3b, KEY_PLAY }, /* > */ + { 0x30, KEY_PLAYPAUSE }, /* || */ + + { 0x31, KEY_TV }, + { 0x34, KEY_RADIO }, +}; + +static struct rc_map_list pixelview_new_map = { + .map = { + .scan = pixelview_new, + .size = ARRAY_SIZE(pixelview_new), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PIXELVIEW_NEW, + } +}; + +static int __init init_rc_map_pixelview_new(void) +{ + return rc_map_register(&pixelview_new_map); +} + +static void __exit exit_rc_map_pixelview_new(void) +{ + rc_map_unregister(&pixelview_new_map); +} + +module_init(init_rc_map_pixelview_new) +module_exit(exit_rc_map_pixelview_new) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-powercolor-real-angel.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-powercolor-real-angel.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-powercolor-real-angel.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-powercolor-real-angel.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,81 @@ +/* powercolor-real-angel.h - Keytable for powercolor_real_angel Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Remote control for Powercolor Real Angel 330 + * Daniel Fraga + */ + +static struct rc_map_table powercolor_real_angel[] = { + { 0x38, KEY_SWITCHVIDEOMODE }, /* switch inputs */ + { 0x0c, KEY_MEDIA }, /* Turn ON/OFF App */ + { 0x00, KEY_0 }, + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + { 0x0a, KEY_DIGITS }, /* single, double, tripple digit */ + { 0x29, KEY_PREVIOUS }, /* previous channel */ + { 0x12, KEY_BRIGHTNESSUP }, + { 0x13, KEY_BRIGHTNESSDOWN }, + { 0x2b, KEY_MODE }, /* stereo/mono */ + { 0x2c, KEY_TEXT }, /* teletext */ + { 0x20, KEY_CHANNELUP }, /* channel up */ + { 0x21, KEY_CHANNELDOWN }, /* channel down */ + { 0x10, KEY_VOLUMEUP }, /* volume up */ + { 0x11, KEY_VOLUMEDOWN }, /* volume down */ + { 0x0d, KEY_MUTE }, + { 0x1f, KEY_RECORD }, + { 0x17, KEY_PLAY }, + { 0x16, KEY_PAUSE }, + { 0x0b, KEY_STOP }, + { 0x27, KEY_FASTFORWARD }, + { 0x26, KEY_REWIND }, + { 0x1e, KEY_SEARCH }, /* autoscan */ + { 0x0e, KEY_CAMERA }, /* snapshot */ + { 0x2d, KEY_SETUP }, + { 0x0f, KEY_SCREEN }, /* full screen */ + { 0x14, KEY_RADIO }, /* FM radio */ + { 0x25, KEY_POWER }, /* power */ +}; + +static struct rc_map_list powercolor_real_angel_map = { + .map = { + .scan = powercolor_real_angel, + .size = ARRAY_SIZE(powercolor_real_angel), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_POWERCOLOR_REAL_ANGEL, + } +}; + +static int __init init_rc_map_powercolor_real_angel(void) +{ + return rc_map_register(&powercolor_real_angel_map); +} + +static void __exit exit_rc_map_powercolor_real_angel(void) +{ + rc_map_unregister(&powercolor_real_angel_map); +} + +module_init(init_rc_map_powercolor_real_angel) +module_exit(exit_rc_map_powercolor_real_angel) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-proteus-2309.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-proteus-2309.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-proteus-2309.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-proteus-2309.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,69 @@ +/* proteus-2309.h - Keytable for proteus_2309 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Michal Majchrowicz */ + +static struct rc_map_table proteus_2309[] = { + /* numeric */ + { 0x00, KEY_0 }, + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + + { 0x5c, KEY_POWER }, /* power */ + { 0x20, KEY_ZOOM }, /* full screen */ + { 0x0f, KEY_BACKSPACE }, /* recall */ + { 0x1b, KEY_ENTER }, /* mute */ + { 0x41, KEY_RECORD }, /* record */ + { 0x43, KEY_STOP }, /* stop */ + { 0x16, KEY_S }, + { 0x1a, KEY_POWER2 }, /* off */ + { 0x2e, KEY_RED }, + { 0x1f, KEY_CHANNELDOWN }, /* channel - */ + { 0x1c, KEY_CHANNELUP }, /* channel + */ + { 0x10, KEY_VOLUMEDOWN }, /* volume - */ + { 0x1e, KEY_VOLUMEUP }, /* volume + */ + { 0x14, KEY_F1 }, +}; + +static struct rc_map_list proteus_2309_map = { + .map = { + .scan = proteus_2309, + .size = ARRAY_SIZE(proteus_2309), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PROTEUS_2309, + } +}; + +static int __init init_rc_map_proteus_2309(void) +{ + return rc_map_register(&proteus_2309_map); +} + +static void __exit exit_rc_map_proteus_2309(void) +{ + rc_map_unregister(&proteus_2309_map); +} + +module_init(init_rc_map_proteus_2309) +module_exit(exit_rc_map_proteus_2309) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-purpletv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-purpletv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-purpletv.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-purpletv.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,81 @@ +/* purpletv.h - Keytable for purpletv Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table purpletv[] = { + { 0x03, KEY_POWER }, + { 0x6f, KEY_MUTE }, + { 0x10, KEY_BACKSPACE }, /* Recall */ + + { 0x11, KEY_0 }, + { 0x04, KEY_1 }, + { 0x05, KEY_2 }, + { 0x06, KEY_3 }, + { 0x08, KEY_4 }, + { 0x09, KEY_5 }, + { 0x0a, KEY_6 }, + { 0x0c, KEY_7 }, + { 0x0d, KEY_8 }, + { 0x0e, KEY_9 }, + { 0x12, KEY_DOT }, /* 100+ */ + + { 0x07, KEY_VOLUMEUP }, + { 0x0b, KEY_VOLUMEDOWN }, + { 0x1a, KEY_KPPLUS }, + { 0x18, KEY_KPMINUS }, + { 0x15, KEY_UP }, + { 0x1d, KEY_DOWN }, + { 0x0f, KEY_CHANNELUP }, + { 0x13, KEY_CHANNELDOWN }, + { 0x48, KEY_ZOOM }, + + { 0x1b, KEY_VIDEO }, /* Video source */ + { 0x1f, KEY_CAMERA }, /* Snapshot */ + { 0x49, KEY_LANGUAGE }, /* MTS Select */ + { 0x19, KEY_SEARCH }, /* Auto Scan */ + + { 0x4b, KEY_RECORD }, + { 0x46, KEY_PLAY }, + { 0x45, KEY_PAUSE }, /* Pause */ + { 0x44, KEY_STOP }, + { 0x43, KEY_TIME }, /* Time Shift */ + { 0x17, KEY_CHANNEL }, /* SURF CH */ + { 0x40, KEY_FORWARD }, /* Forward ? */ + { 0x42, KEY_REWIND }, /* Backward ? */ + +}; + +static struct rc_map_list purpletv_map = { + .map = { + .scan = purpletv, + .size = ARRAY_SIZE(purpletv), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PURPLETV, + } +}; + +static int __init init_rc_map_purpletv(void) +{ + return rc_map_register(&purpletv_map); +} + +static void __exit exit_rc_map_purpletv(void) +{ + rc_map_unregister(&purpletv_map); +} + +module_init(init_rc_map_purpletv) +module_exit(exit_rc_map_purpletv) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pv951.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pv951.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pv951.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-pv951.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* pv951.h - Keytable for pv951 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Mark Phalan */ + +static struct rc_map_table pv951[] = { + { 0x00, KEY_0 }, + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + + { 0x12, KEY_POWER }, + { 0x10, KEY_MUTE }, + { 0x1f, KEY_VOLUMEDOWN }, + { 0x1b, KEY_VOLUMEUP }, + { 0x1a, KEY_CHANNELUP }, + { 0x1e, KEY_CHANNELDOWN }, + { 0x0e, KEY_PAGEUP }, + { 0x1d, KEY_PAGEDOWN }, + { 0x13, KEY_SOUND }, + + { 0x18, KEY_KPPLUSMINUS }, /* CH +/- */ + { 0x16, KEY_SUBTITLE }, /* CC */ + { 0x0d, KEY_TEXT }, /* TTX */ + { 0x0b, KEY_TV }, /* AIR/CBL */ + { 0x11, KEY_PC }, /* PC/TV */ + { 0x17, KEY_OK }, /* CH RTN */ + { 0x19, KEY_MODE }, /* FUNC */ + { 0x0c, KEY_SEARCH }, /* AUTOSCAN */ + + /* Not sure what to do with these ones! */ + { 0x0f, KEY_VIDEO }, /* SOURCE */ + { 0x0a, KEY_KPPLUS }, /* +100 */ + { 0x14, KEY_EQUAL }, /* SYNC */ + { 0x1c, KEY_TV }, /* PC/TV */ +}; + +static struct rc_map_list pv951_map = { + .map = { + .scan = pv951, + .size = ARRAY_SIZE(pv951), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PV951, + } +}; + +static int __init init_rc_map_pv951(void) +{ + return rc_map_register(&pv951_map); +} + +static void __exit exit_rc_map_pv951(void) +{ + rc_map_unregister(&pv951_map); +} + +module_init(init_rc_map_pv951) +module_exit(exit_rc_map_pv951) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-rc6-mce.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-rc6-mce.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-rc6-mce.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-rc6-mce.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,119 @@ +/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use + * with the Media Center Edition eHome Infrared Transceiver. + * + * Copyright (c) 2010 by Jarod Wilson + * + * See http://mediacenterguides.com/book/export/html/31 for details on + * key mappings. + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table rc6_mce[] = { + + { 0x800f0400, KEY_NUMERIC_0 }, + { 0x800f0401, KEY_NUMERIC_1 }, + { 0x800f0402, KEY_NUMERIC_2 }, + { 0x800f0403, KEY_NUMERIC_3 }, + { 0x800f0404, KEY_NUMERIC_4 }, + { 0x800f0405, KEY_NUMERIC_5 }, + { 0x800f0406, KEY_NUMERIC_6 }, + { 0x800f0407, KEY_NUMERIC_7 }, + { 0x800f0408, KEY_NUMERIC_8 }, + { 0x800f0409, KEY_NUMERIC_9 }, + + { 0x800f040a, KEY_DELETE }, + { 0x800f040b, KEY_ENTER }, + { 0x800f040c, KEY_POWER }, /* PC Power */ + { 0x800f040d, KEY_MEDIA }, /* Windows MCE button */ + { 0x800f040e, KEY_MUTE }, + { 0x800f040f, KEY_INFO }, + + { 0x800f0410, KEY_VOLUMEUP }, + { 0x800f0411, KEY_VOLUMEDOWN }, + { 0x800f0412, KEY_CHANNELUP }, + { 0x800f0413, KEY_CHANNELDOWN }, + + { 0x800f0414, KEY_FASTFORWARD }, + { 0x800f0415, KEY_REWIND }, + { 0x800f0416, KEY_PLAY }, + { 0x800f0417, KEY_RECORD }, + { 0x800f0418, KEY_PAUSE }, + { 0x800f046e, KEY_PLAYPAUSE }, + { 0x800f0419, KEY_STOP }, + { 0x800f041a, KEY_NEXT }, + { 0x800f041b, KEY_PREVIOUS }, + { 0x800f041c, KEY_NUMERIC_POUND }, + { 0x800f041d, KEY_NUMERIC_STAR }, + + { 0x800f041e, KEY_UP }, + { 0x800f041f, KEY_DOWN }, + { 0x800f0420, KEY_LEFT }, + { 0x800f0421, KEY_RIGHT }, + + { 0x800f0422, KEY_OK }, + { 0x800f0423, KEY_EXIT }, + { 0x800f0424, KEY_DVD }, + { 0x800f0425, KEY_TUNER }, /* LiveTV */ + { 0x800f0426, KEY_EPG }, /* Guide */ + { 0x800f0427, KEY_ZOOM }, /* Aspect */ + + { 0x800f0432, KEY_MODE }, /* Visualization */ + { 0x800f0433, KEY_PRESENTATION }, /* Slide Show */ + { 0x800f0434, KEY_EJECTCD }, + { 0x800f043a, KEY_BRIGHTNESSUP }, + + { 0x800f0446, KEY_TV }, + { 0x800f0447, KEY_AUDIO }, /* My Music */ + { 0x800f0448, KEY_PVR }, /* RecordedTV */ + { 0x800f0449, KEY_CAMERA }, + { 0x800f044a, KEY_VIDEO }, + { 0x800f044c, KEY_LANGUAGE }, + { 0x800f044d, KEY_TITLE }, + { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */ + + { 0x800f0450, KEY_RADIO }, + + { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */ + { 0x800f045b, KEY_RED }, + { 0x800f045c, KEY_GREEN }, + { 0x800f045d, KEY_YELLOW }, + { 0x800f045e, KEY_BLUE }, + + { 0x800f0465, KEY_POWER2 }, /* TV Power */ + { 0x800f046e, KEY_PLAYPAUSE }, + { 0x800f046f, KEY_PLAYER }, /* Start media application (NEW) */ + + { 0x800f0480, KEY_BRIGHTNESSDOWN }, + { 0x800f0481, KEY_PLAYPAUSE }, +}; + +static struct rc_map_list rc6_mce_map = { + .map = { + .scan = rc6_mce, + .size = ARRAY_SIZE(rc6_mce), + .rc_type = RC_TYPE_RC6, + .name = RC_MAP_RC6_MCE, + } +}; + +static int __init init_rc_map_rc6_mce(void) +{ + return rc_map_register(&rc6_mce_map); +} + +static void __exit exit_rc_map_rc6_mce(void) +{ + rc_map_unregister(&rc6_mce_map); +} + +module_init(init_rc_map_rc6_mce) +module_exit(exit_rc_map_rc6_mce) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,78 @@ +/* real-audio-220-32-keys.h - Keytable for real_audio_220_32_keys Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Zogis Real Audio 220 - 32 keys IR */ + +static struct rc_map_table real_audio_220_32_keys[] = { + { 0x1c, KEY_RADIO}, + { 0x12, KEY_POWER2}, + + { 0x01, KEY_1}, + { 0x02, KEY_2}, + { 0x03, KEY_3}, + { 0x04, KEY_4}, + { 0x05, KEY_5}, + { 0x06, KEY_6}, + { 0x07, KEY_7}, + { 0x08, KEY_8}, + { 0x09, KEY_9}, + { 0x00, KEY_0}, + + { 0x0c, KEY_VOLUMEUP}, + { 0x18, KEY_VOLUMEDOWN}, + { 0x0b, KEY_CHANNELUP}, + { 0x15, KEY_CHANNELDOWN}, + { 0x16, KEY_ENTER}, + + { 0x11, KEY_VIDEO}, /* Source */ + { 0x0d, KEY_AUDIO}, /* stereo */ + + { 0x0f, KEY_PREVIOUS}, /* Prev */ + { 0x1b, KEY_TIME}, /* Timeshift */ + { 0x1a, KEY_NEXT}, /* Next */ + + { 0x0e, KEY_STOP}, + { 0x1f, KEY_PLAY}, + { 0x1e, KEY_PLAYPAUSE}, /* Pause */ + + { 0x1d, KEY_RECORD}, + { 0x13, KEY_MUTE}, + { 0x19, KEY_CAMERA}, /* Snapshot */ + +}; + +static struct rc_map_list real_audio_220_32_keys_map = { + .map = { + .scan = real_audio_220_32_keys, + .size = ARRAY_SIZE(real_audio_220_32_keys), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_REAL_AUDIO_220_32_KEYS, + } +}; + +static int __init init_rc_map_real_audio_220_32_keys(void) +{ + return rc_map_register(&real_audio_220_32_keys_map); +} + +static void __exit exit_rc_map_real_audio_220_32_keys(void) +{ + rc_map_unregister(&real_audio_220_32_keys_map); +} + +module_init(init_rc_map_real_audio_220_32_keys) +module_exit(exit_rc_map_real_audio_220_32_keys) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-streamzap.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-streamzap.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-streamzap.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-streamzap.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* rc-streamzap.c - Keytable for Streamzap PC Remote, for use + * with the Streamzap PC Remote IR Receiver. + * + * Copyright (c) 2010 by Jarod Wilson + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table streamzap[] = { +/* + * The Streamzap remote is almost, but not quite, RC-5, as it has an extra + * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently, + * an additional RC-5-sz decoder is being deployed to support it, but it + * may be possible to merge it back with the standard RC-5 decoder. + */ + { 0x28c0, KEY_NUMERIC_0 }, + { 0x28c1, KEY_NUMERIC_1 }, + { 0x28c2, KEY_NUMERIC_2 }, + { 0x28c3, KEY_NUMERIC_3 }, + { 0x28c4, KEY_NUMERIC_4 }, + { 0x28c5, KEY_NUMERIC_5 }, + { 0x28c6, KEY_NUMERIC_6 }, + { 0x28c7, KEY_NUMERIC_7 }, + { 0x28c8, KEY_NUMERIC_8 }, + { 0x28c9, KEY_NUMERIC_9 }, + { 0x28ca, KEY_POWER }, + { 0x28cb, KEY_MUTE }, + { 0x28cc, KEY_CHANNELUP }, + { 0x28cd, KEY_VOLUMEUP }, + { 0x28ce, KEY_CHANNELDOWN }, + { 0x28cf, KEY_VOLUMEDOWN }, + { 0x28d0, KEY_UP }, + { 0x28d1, KEY_LEFT }, + { 0x28d2, KEY_OK }, + { 0x28d3, KEY_RIGHT }, + { 0x28d4, KEY_DOWN }, + { 0x28d5, KEY_MENU }, + { 0x28d6, KEY_EXIT }, + { 0x28d7, KEY_PLAY }, + { 0x28d8, KEY_PAUSE }, + { 0x28d9, KEY_STOP }, + { 0x28da, KEY_BACK }, + { 0x28db, KEY_FORWARD }, + { 0x28dc, KEY_RECORD }, + { 0x28dd, KEY_REWIND }, + { 0x28de, KEY_FASTFORWARD }, + { 0x28e0, KEY_RED }, + { 0x28e1, KEY_GREEN }, + { 0x28e2, KEY_YELLOW }, + { 0x28e3, KEY_BLUE }, + +}; + +static struct rc_map_list streamzap_map = { + .map = { + .scan = streamzap, + .size = ARRAY_SIZE(streamzap), + .rc_type = RC_TYPE_RC5_SZ, + .name = RC_MAP_STREAMZAP, + } +}; + +static int __init init_rc_map_streamzap(void) +{ + return rc_map_register(&streamzap_map); +} + +static void __exit exit_rc_map_streamzap(void) +{ + rc_map_unregister(&streamzap_map); +} + +module_init(init_rc_map_streamzap) +module_exit(exit_rc_map_streamzap) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tbs-nec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tbs-nec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tbs-nec.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tbs-nec.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,75 @@ +/* tbs-nec.h - Keytable for tbs_nec Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table tbs_nec[] = { + { 0x84, KEY_POWER2}, /* power */ + { 0x94, KEY_MUTE}, /* mute */ + { 0x87, KEY_1}, + { 0x86, KEY_2}, + { 0x85, KEY_3}, + { 0x8b, KEY_4}, + { 0x8a, KEY_5}, + { 0x89, KEY_6}, + { 0x8f, KEY_7}, + { 0x8e, KEY_8}, + { 0x8d, KEY_9}, + { 0x92, KEY_0}, + { 0xc0, KEY_10CHANNELSUP}, /* 10+ */ + { 0xd0, KEY_10CHANNELSDOWN}, /* 10- */ + { 0x96, KEY_CHANNELUP}, /* ch+ */ + { 0x91, KEY_CHANNELDOWN}, /* ch- */ + { 0x93, KEY_VOLUMEUP}, /* vol+ */ + { 0x8c, KEY_VOLUMEDOWN}, /* vol- */ + { 0x83, KEY_RECORD}, /* rec */ + { 0x98, KEY_PAUSE}, /* pause, yellow */ + { 0x99, KEY_OK}, /* ok */ + { 0x9a, KEY_CAMERA}, /* snapshot */ + { 0x81, KEY_UP}, + { 0x90, KEY_LEFT}, + { 0x82, KEY_RIGHT}, + { 0x88, KEY_DOWN}, + { 0x95, KEY_FAVORITES}, /* blue */ + { 0x97, KEY_SUBTITLE}, /* green */ + { 0x9d, KEY_ZOOM}, + { 0x9f, KEY_EXIT}, + { 0x9e, KEY_MENU}, + { 0x9c, KEY_EPG}, + { 0x80, KEY_PREVIOUS}, /* red */ + { 0x9b, KEY_MODE}, +}; + +static struct rc_map_list tbs_nec_map = { + .map = { + .scan = tbs_nec, + .size = ARRAY_SIZE(tbs_nec), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TBS_NEC, + } +}; + +static int __init init_rc_map_tbs_nec(void) +{ + return rc_map_register(&tbs_nec_map); +} + +static void __exit exit_rc_map_tbs_nec(void) +{ + rc_map_unregister(&tbs_nec_map); +} + +module_init(init_rc_map_tbs_nec) +module_exit(exit_rc_map_tbs_nec) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-technisat-usb2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-technisat-usb2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-technisat-usb2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-technisat-usb2.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,93 @@ +/* rc-technisat-usb2.c - Keytable for SkyStar HD USB + * + * Copyright (C) 2010 Patrick Boettcher, + * Kernel Labs Inc. PO Box 745, St James, NY 11780 + * + * Development was sponsored by Technisat Digital UK Limited, whose + * registered office is Witan Gate House 500 - 600 Witan Gate West, + * Milton Keynes, MK9 1SH + * + * 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, or (at your option) any later version. + * + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND + * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. NEITHER THE COPYRIGHT HOLDER + * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the + * GNU General Public License for more details. + */ + +#include + +static struct rc_map_table technisat_usb2[] = { + {0x0a0c, KEY_POWER}, + {0x0a01, KEY_1}, + {0x0a02, KEY_2}, + {0x0a03, KEY_3}, + {0x0a0d, KEY_MUTE}, + {0x0a04, KEY_4}, + {0x0a05, KEY_5}, + {0x0a06, KEY_6}, + {0x0a38, KEY_VIDEO}, /* EXT */ + {0x0a07, KEY_7}, + {0x0a08, KEY_8}, + {0x0a09, KEY_9}, + {0x0a00, KEY_0}, + {0x0a4f, KEY_INFO}, + {0x0a20, KEY_CHANNELUP}, + {0x0a52, KEY_MENU}, + {0x0a11, KEY_VOLUMEUP}, + {0x0a57, KEY_OK}, + {0x0a10, KEY_VOLUMEDOWN}, + {0x0a2f, KEY_EPG}, + {0x0a21, KEY_CHANNELDOWN}, + {0x0a22, KEY_REFRESH}, + {0x0a3c, KEY_TEXT}, + {0x0a76, KEY_ENTER}, /* HOOK */ + {0x0a0f, KEY_HELP}, + {0x0a6b, KEY_RED}, + {0x0a6c, KEY_GREEN}, + {0x0a6d, KEY_YELLOW}, + {0x0a6e, KEY_BLUE}, + {0x0a29, KEY_STOP}, + {0x0a23, KEY_LANGUAGE}, + {0x0a53, KEY_TV}, + {0x0a0a, KEY_PROGRAM}, +}; + +static struct rc_map_list technisat_usb2_map = { + .map = { + .scan = technisat_usb2, + .size = ARRAY_SIZE(technisat_usb2), + .rc_type = RC_TYPE_RC5, + .name = RC_MAP_TECHNISAT_USB2, + } +}; + +static int __init init_rc_map(void) +{ + return rc_map_register(&technisat_usb2_map); +} + +static void __exit exit_rc_map(void) +{ + rc_map_unregister(&technisat_usb2_map); +} + +module_init(init_rc_map) +module_exit(exit_rc_map) + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,92 @@ +/* terratec-cinergy-xs.h - Keytable for terratec_cinergy_xs Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Terratec Cinergy Hybrid T USB XS + Devin Heitmueller + */ + +static struct rc_map_table terratec_cinergy_xs[] = { + { 0x41, KEY_HOME}, + { 0x01, KEY_POWER}, + { 0x42, KEY_MENU}, + { 0x02, KEY_1}, + { 0x03, KEY_2}, + { 0x04, KEY_3}, + { 0x43, KEY_SUBTITLE}, + { 0x05, KEY_4}, + { 0x06, KEY_5}, + { 0x07, KEY_6}, + { 0x44, KEY_TEXT}, + { 0x08, KEY_7}, + { 0x09, KEY_8}, + { 0x0a, KEY_9}, + { 0x45, KEY_DELETE}, + { 0x0b, KEY_TUNER}, + { 0x0c, KEY_0}, + { 0x0d, KEY_MODE}, + { 0x46, KEY_TV}, + { 0x47, KEY_DVD}, + { 0x49, KEY_VIDEO}, + { 0x4b, KEY_AUX}, + { 0x10, KEY_UP}, + { 0x11, KEY_LEFT}, + { 0x12, KEY_OK}, + { 0x13, KEY_RIGHT}, + { 0x14, KEY_DOWN}, + { 0x0f, KEY_EPG}, + { 0x16, KEY_INFO}, + { 0x4d, KEY_BACKSPACE}, + { 0x1c, KEY_VOLUMEUP}, + { 0x4c, KEY_PLAY}, + { 0x1b, KEY_CHANNELUP}, + { 0x1e, KEY_VOLUMEDOWN}, + { 0x1d, KEY_MUTE}, + { 0x1f, KEY_CHANNELDOWN}, + { 0x17, KEY_RED}, + { 0x18, KEY_GREEN}, + { 0x19, KEY_YELLOW}, + { 0x1a, KEY_BLUE}, + { 0x58, KEY_RECORD}, + { 0x48, KEY_STOP}, + { 0x40, KEY_PAUSE}, + { 0x54, KEY_LAST}, + { 0x4e, KEY_REWIND}, + { 0x4f, KEY_FASTFORWARD}, + { 0x5c, KEY_NEXT}, +}; + +static struct rc_map_list terratec_cinergy_xs_map = { + .map = { + .scan = terratec_cinergy_xs, + .size = ARRAY_SIZE(terratec_cinergy_xs), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TERRATEC_CINERGY_XS, + } +}; + +static int __init init_rc_map_terratec_cinergy_xs(void) +{ + return rc_map_register(&terratec_cinergy_xs_map); +} + +static void __exit exit_rc_map_terratec_cinergy_xs(void) +{ + rc_map_unregister(&terratec_cinergy_xs_map); +} + +module_init(init_rc_map_terratec_cinergy_xs) +module_exit(exit_rc_map_terratec_cinergy_xs) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-slim-2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-slim-2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-slim-2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-slim-2.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,72 @@ +/* + * TerraTec remote controller keytable + * + * Copyright (C) 2011 Martin Groszhauser + * Copyright (C) 2011 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* + * TerraTec slim remote, 6 rows, 3 columns. + * Keytable from Martin Groszhauser + */ +static struct rc_map_table terratec_slim_2[] = { + { 0x8001, KEY_MUTE }, /* MUTE */ + { 0x8002, KEY_VOLUMEDOWN }, + { 0x8003, KEY_CHANNELDOWN }, + { 0x8004, KEY_1 }, + { 0x8005, KEY_2 }, + { 0x8006, KEY_3 }, + { 0x8007, KEY_4 }, + { 0x8008, KEY_5 }, + { 0x8009, KEY_6 }, + { 0x800a, KEY_7 }, + { 0x800c, KEY_ZOOM }, /* [fullscreen] */ + { 0x800d, KEY_0 }, + { 0x800e, KEY_AGAIN }, /* [two arrows forming a circle] */ + { 0x8012, KEY_POWER2 }, /* [red power button] */ + { 0x801a, KEY_VOLUMEUP }, + { 0x801b, KEY_8 }, + { 0x801e, KEY_CHANNELUP }, + { 0x801f, KEY_9 }, +}; + +static struct rc_map_list terratec_slim_2_map = { + .map = { + .scan = terratec_slim_2, + .size = ARRAY_SIZE(terratec_slim_2), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_TERRATEC_SLIM_2, + } +}; + +static int __init init_rc_map_terratec_slim_2(void) +{ + return rc_map_register(&terratec_slim_2_map); +} + +static void __exit exit_rc_map_terratec_slim_2(void) +{ + rc_map_unregister(&terratec_slim_2_map); +} + +module_init(init_rc_map_terratec_slim_2) +module_exit(exit_rc_map_terratec_slim_2) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-slim.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-slim.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-slim.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-terratec-slim.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * TerraTec remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* TerraTec slim remote, 7 rows, 4 columns. */ +/* Uses NEC extended 0x02bd. */ +static struct rc_map_table terratec_slim[] = { + { 0x02bd00, KEY_1 }, + { 0x02bd01, KEY_2 }, + { 0x02bd02, KEY_3 }, + { 0x02bd03, KEY_4 }, + { 0x02bd04, KEY_5 }, + { 0x02bd05, KEY_6 }, + { 0x02bd06, KEY_7 }, + { 0x02bd07, KEY_8 }, + { 0x02bd08, KEY_9 }, + { 0x02bd09, KEY_0 }, + { 0x02bd0a, KEY_MUTE }, + { 0x02bd0b, KEY_NEW }, /* symbol: PIP */ + { 0x02bd0e, KEY_VOLUMEDOWN }, + { 0x02bd0f, KEY_PLAYPAUSE }, + { 0x02bd10, KEY_RIGHT }, + { 0x02bd11, KEY_LEFT }, + { 0x02bd12, KEY_UP }, + { 0x02bd13, KEY_DOWN }, + { 0x02bd15, KEY_OK }, + { 0x02bd16, KEY_STOP }, + { 0x02bd17, KEY_CAMERA }, /* snapshot */ + { 0x02bd18, KEY_CHANNELUP }, + { 0x02bd19, KEY_RECORD }, + { 0x02bd1a, KEY_CHANNELDOWN }, + { 0x02bd1c, KEY_ESC }, + { 0x02bd1f, KEY_VOLUMEUP }, + { 0x02bd44, KEY_EPG }, + { 0x02bd45, KEY_POWER2 }, /* [red power button] */ +}; + +static struct rc_map_list terratec_slim_map = { + .map = { + .scan = terratec_slim, + .size = ARRAY_SIZE(terratec_slim), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_TERRATEC_SLIM, + } +}; + +static int __init init_rc_map_terratec_slim(void) +{ + return rc_map_register(&terratec_slim_map); +} + +static void __exit exit_rc_map_terratec_slim(void) +{ + rc_map_unregister(&terratec_slim_map); +} + +module_init(init_rc_map_terratec_slim) +module_exit(exit_rc_map_terratec_slim) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tevii-nec.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tevii-nec.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tevii-nec.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tevii-nec.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,88 @@ +/* tevii-nec.h - Keytable for tevii_nec Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table tevii_nec[] = { + { 0x0a, KEY_POWER2}, + { 0x0c, KEY_MUTE}, + { 0x11, KEY_1}, + { 0x12, KEY_2}, + { 0x13, KEY_3}, + { 0x14, KEY_4}, + { 0x15, KEY_5}, + { 0x16, KEY_6}, + { 0x17, KEY_7}, + { 0x18, KEY_8}, + { 0x19, KEY_9}, + { 0x10, KEY_0}, + { 0x1c, KEY_MENU}, + { 0x0f, KEY_VOLUMEDOWN}, + { 0x1a, KEY_LAST}, + { 0x0e, KEY_OPEN}, + { 0x04, KEY_RECORD}, + { 0x09, KEY_VOLUMEUP}, + { 0x08, KEY_CHANNELUP}, + { 0x07, KEY_PVR}, + { 0x0b, KEY_TIME}, + { 0x02, KEY_RIGHT}, + { 0x03, KEY_LEFT}, + { 0x00, KEY_UP}, + { 0x1f, KEY_OK}, + { 0x01, KEY_DOWN}, + { 0x05, KEY_TUNER}, + { 0x06, KEY_CHANNELDOWN}, + { 0x40, KEY_PLAYPAUSE}, + { 0x1e, KEY_REWIND}, + { 0x1b, KEY_FAVORITES}, + { 0x1d, KEY_BACK}, + { 0x4d, KEY_FASTFORWARD}, + { 0x44, KEY_EPG}, + { 0x4c, KEY_INFO}, + { 0x41, KEY_AB}, + { 0x43, KEY_AUDIO}, + { 0x45, KEY_SUBTITLE}, + { 0x4a, KEY_LIST}, + { 0x46, KEY_F1}, + { 0x47, KEY_F2}, + { 0x5e, KEY_F3}, + { 0x5c, KEY_F4}, + { 0x52, KEY_F5}, + { 0x5a, KEY_F6}, + { 0x56, KEY_MODE}, + { 0x58, KEY_SWITCHVIDEOMODE}, +}; + +static struct rc_map_list tevii_nec_map = { + .map = { + .scan = tevii_nec, + .size = ARRAY_SIZE(tevii_nec), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TEVII_NEC, + } +}; + +static int __init init_rc_map_tevii_nec(void) +{ + return rc_map_register(&tevii_nec_map); +} + +static void __exit exit_rc_map_tevii_nec(void) +{ + rc_map_unregister(&tevii_nec_map); +} + +module_init(init_rc_map_tevii_nec) +module_exit(exit_rc_map_tevii_nec) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tivo.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tivo.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tivo.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tivo.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* rc-tivo.c - Keytable for TiVo remotes + * + * Copyright (c) 2011 by Jarod Wilson + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* + * Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle, + * which also ships with a TiVo-branded IR transceiver, supported by the mceusb + * driver. Note that the remote uses an NEC-ish protocol, but instead of having + * a command/not_command pair, it has a vendor ID of 0xa10c, but some keys, the + * NEC extended checksums do pass, so the table presently has the intended + * values and the checksum-passed versions for those keys. + */ +static struct rc_map_table tivo[] = { + { 0xa10c900f, KEY_MEDIA }, /* TiVo Button */ + { 0xa10c0807, KEY_POWER2 }, /* TV Power */ + { 0xa10c8807, KEY_TV }, /* Live TV/Swap */ + { 0xa10c2c03, KEY_VIDEO_NEXT }, /* TV Input */ + { 0xa10cc807, KEY_INFO }, + { 0xa10cfa05, KEY_CYCLEWINDOWS }, /* Window */ + { 0x0085305f, KEY_CYCLEWINDOWS }, + { 0xa10c6c03, KEY_EPG }, /* Guide */ + + { 0xa10c2807, KEY_UP }, + { 0xa10c6807, KEY_DOWN }, + { 0xa10ce807, KEY_LEFT }, + { 0xa10ca807, KEY_RIGHT }, + + { 0xa10c1807, KEY_SCROLLDOWN }, /* Red Thumbs Down */ + { 0xa10c9807, KEY_SELECT }, + { 0xa10c5807, KEY_SCROLLUP }, /* Green Thumbs Up */ + + { 0xa10c3807, KEY_VOLUMEUP }, + { 0xa10cb807, KEY_VOLUMEDOWN }, + { 0xa10cd807, KEY_MUTE }, + { 0xa10c040b, KEY_RECORD }, + { 0xa10c7807, KEY_CHANNELUP }, + { 0xa10cf807, KEY_CHANNELDOWN }, + { 0x0085301f, KEY_CHANNELDOWN }, + + { 0xa10c840b, KEY_PLAY }, + { 0xa10cc40b, KEY_PAUSE }, + { 0xa10ca40b, KEY_SLOW }, + { 0xa10c440b, KEY_REWIND }, + { 0xa10c240b, KEY_FASTFORWARD }, + { 0xa10c640b, KEY_PREVIOUS }, + { 0xa10ce40b, KEY_NEXT }, /* ->| */ + + { 0xa10c220d, KEY_ZOOM }, /* Aspect */ + { 0xa10c120d, KEY_STOP }, + { 0xa10c520d, KEY_DVD }, /* DVD Menu */ + + { 0xa10c140b, KEY_NUMERIC_1 }, + { 0xa10c940b, KEY_NUMERIC_2 }, + { 0xa10c540b, KEY_NUMERIC_3 }, + { 0xa10cd40b, KEY_NUMERIC_4 }, + { 0xa10c340b, KEY_NUMERIC_5 }, + { 0xa10cb40b, KEY_NUMERIC_6 }, + { 0xa10c740b, KEY_NUMERIC_7 }, + { 0xa10cf40b, KEY_NUMERIC_8 }, + { 0x0085302f, KEY_NUMERIC_8 }, + { 0xa10c0c03, KEY_NUMERIC_9 }, + { 0xa10c8c03, KEY_NUMERIC_0 }, + { 0xa10ccc03, KEY_ENTER }, + { 0xa10c4c03, KEY_CLEAR }, +}; + +static struct rc_map_list tivo_map = { + .map = { + .scan = tivo, + .size = ARRAY_SIZE(tivo), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_TIVO, + } +}; + +static int __init init_rc_map_tivo(void) +{ + return rc_map_register(&tivo_map); +} + +static void __exit exit_rc_map_tivo(void) +{ + rc_map_unregister(&tivo_map); +} + +module_init(init_rc_map_tivo) +module_exit(exit_rc_map_tivo) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-total-media-in-hand.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-total-media-in-hand.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-total-media-in-hand.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-total-media-in-hand.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Total Media In Hand remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* Uses NEC extended 0x02bd */ +static struct rc_map_table total_media_in_hand[] = { + { 0x02bd00, KEY_1 }, + { 0x02bd01, KEY_2 }, + { 0x02bd02, KEY_3 }, + { 0x02bd03, KEY_4 }, + { 0x02bd04, KEY_5 }, + { 0x02bd05, KEY_6 }, + { 0x02bd06, KEY_7 }, + { 0x02bd07, KEY_8 }, + { 0x02bd08, KEY_9 }, + { 0x02bd09, KEY_0 }, + { 0x02bd0a, KEY_MUTE }, + { 0x02bd0b, KEY_CYCLEWINDOWS }, /* yellow, [min / max] */ + { 0x02bd0c, KEY_VIDEO }, /* TV / AV */ + { 0x02bd0e, KEY_VOLUMEDOWN }, + { 0x02bd0f, KEY_TIME }, /* TimeShift */ + { 0x02bd10, KEY_RIGHT }, /* right arrow */ + { 0x02bd11, KEY_LEFT }, /* left arrow */ + { 0x02bd12, KEY_UP }, /* up arrow */ + { 0x02bd13, KEY_DOWN }, /* down arrow */ + { 0x02bd14, KEY_POWER2 }, /* [red] */ + { 0x02bd15, KEY_OK }, /* OK */ + { 0x02bd16, KEY_STOP }, + { 0x02bd17, KEY_CAMERA }, /* Snapshot */ + { 0x02bd18, KEY_CHANNELUP }, + { 0x02bd19, KEY_RECORD }, + { 0x02bd1a, KEY_CHANNELDOWN }, + { 0x02bd1c, KEY_ESC }, /* Esc */ + { 0x02bd1e, KEY_PLAY }, + { 0x02bd1f, KEY_VOLUMEUP }, + { 0x02bd40, KEY_PAUSE }, + { 0x02bd41, KEY_FASTFORWARD }, /* FF >> */ + { 0x02bd42, KEY_REWIND }, /* FR << */ + { 0x02bd43, KEY_ZOOM }, /* [window + mouse pointer] */ + { 0x02bd44, KEY_SHUFFLE }, /* Shuffle */ + { 0x02bd45, KEY_INFO }, /* [red (I)] */ +}; + +static struct rc_map_list total_media_in_hand_map = { + .map = { + .scan = total_media_in_hand, + .size = ARRAY_SIZE(total_media_in_hand), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_TOTAL_MEDIA_IN_HAND, + } +}; + +static int __init init_rc_map_total_media_in_hand(void) +{ + return rc_map_register(&total_media_in_hand_map); +} + +static void __exit exit_rc_map_total_media_in_hand(void) +{ + rc_map_unregister(&total_media_in_hand_map); +} + +module_init(init_rc_map_total_media_in_hand) +module_exit(exit_rc_map_total_media_in_hand) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-trekstor.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-trekstor.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-trekstor.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-trekstor.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * TrekStor remote controller keytable + * + * Copyright (C) 2010 Antti Palosaari + * + * 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, or + * (at your option) any later version. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* TrekStor DVB-T USB Stick remote controller. */ +/* Imported from af9015.h. + Initial keytable was from Marc Schneider */ +static struct rc_map_table trekstor[] = { + { 0x0084, KEY_0 }, + { 0x0085, KEY_MUTE }, /* Mute */ + { 0x0086, KEY_HOMEPAGE }, /* Home */ + { 0x0087, KEY_UP }, /* Up */ + { 0x0088, KEY_OK }, /* OK */ + { 0x0089, KEY_RIGHT }, /* Right */ + { 0x008a, KEY_FASTFORWARD }, /* Fast forward */ + { 0x008b, KEY_VOLUMEUP }, /* Volume + */ + { 0x008c, KEY_DOWN }, /* Down */ + { 0x008d, KEY_PLAY }, /* Play/Pause */ + { 0x008e, KEY_STOP }, /* Stop */ + { 0x008f, KEY_EPG }, /* Info/EPG */ + { 0x0090, KEY_7 }, + { 0x0091, KEY_4 }, + { 0x0092, KEY_1 }, + { 0x0093, KEY_CHANNELDOWN }, /* Channel - */ + { 0x0094, KEY_8 }, + { 0x0095, KEY_5 }, + { 0x0096, KEY_2 }, + { 0x0097, KEY_CHANNELUP }, /* Channel + */ + { 0x0098, KEY_9 }, + { 0x0099, KEY_6 }, + { 0x009a, KEY_3 }, + { 0x009b, KEY_VOLUMEDOWN }, /* Volume - */ + { 0x009c, KEY_TV }, /* TV */ + { 0x009d, KEY_RECORD }, /* Record */ + { 0x009e, KEY_REWIND }, /* Rewind */ + { 0x009f, KEY_LEFT }, /* Left */ +}; + +static struct rc_map_list trekstor_map = { + .map = { + .scan = trekstor, + .size = ARRAY_SIZE(trekstor), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_TREKSTOR, + } +}; + +static int __init init_rc_map_trekstor(void) +{ + return rc_map_register(&trekstor_map); +} + +static void __exit exit_rc_map_trekstor(void) +{ + rc_map_unregister(&trekstor_map); +} + +module_init(init_rc_map_trekstor) +module_exit(exit_rc_map_trekstor) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tt-1500.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tt-1500.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tt-1500.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-tt-1500.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* tt-1500.h - Keytable for tt_1500 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* for the Technotrend 1500 bundled remotes (grey and black): */ + +static struct rc_map_table tt_1500[] = { + { 0x1501, KEY_POWER }, + { 0x1502, KEY_SHUFFLE }, /* ? double-arrow key */ + { 0x1503, KEY_1 }, + { 0x1504, KEY_2 }, + { 0x1505, KEY_3 }, + { 0x1506, KEY_4 }, + { 0x1507, KEY_5 }, + { 0x1508, KEY_6 }, + { 0x1509, KEY_7 }, + { 0x150a, KEY_8 }, + { 0x150b, KEY_9 }, + { 0x150c, KEY_0 }, + { 0x150d, KEY_UP }, + { 0x150e, KEY_LEFT }, + { 0x150f, KEY_OK }, + { 0x1510, KEY_RIGHT }, + { 0x1511, KEY_DOWN }, + { 0x1512, KEY_INFO }, + { 0x1513, KEY_EXIT }, + { 0x1514, KEY_RED }, + { 0x1515, KEY_GREEN }, + { 0x1516, KEY_YELLOW }, + { 0x1517, KEY_BLUE }, + { 0x1518, KEY_MUTE }, + { 0x1519, KEY_TEXT }, + { 0x151a, KEY_MODE }, /* ? TV/Radio */ + { 0x1521, KEY_OPTION }, + { 0x1522, KEY_EPG }, + { 0x1523, KEY_CHANNELUP }, + { 0x1524, KEY_CHANNELDOWN }, + { 0x1525, KEY_VOLUMEUP }, + { 0x1526, KEY_VOLUMEDOWN }, + { 0x1527, KEY_SETUP }, + { 0x153a, KEY_RECORD }, /* these keys are only in the black remote */ + { 0x153b, KEY_PLAY }, + { 0x153c, KEY_STOP }, + { 0x153d, KEY_REWIND }, + { 0x153e, KEY_PAUSE }, + { 0x153f, KEY_FORWARD }, +}; + +static struct rc_map_list tt_1500_map = { + .map = { + .scan = tt_1500, + .size = ARRAY_SIZE(tt_1500), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TT_1500, + } +}; + +static int __init init_rc_map_tt_1500(void) +{ + return rc_map_register(&tt_1500_map); +} + +static void __exit exit_rc_map_tt_1500(void) +{ + rc_map_unregister(&tt_1500_map); +} + +module_init(init_rc_map_tt_1500) +module_exit(exit_rc_map_tt_1500) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-twinhan1027.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-twinhan1027.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-twinhan1027.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-twinhan1027.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,87 @@ +#include + +static struct rc_map_table twinhan_vp1027[] = { + { 0x16, KEY_POWER2 }, + { 0x17, KEY_FAVORITES }, + { 0x0f, KEY_TEXT }, + { 0x48, KEY_INFO}, + { 0x1c, KEY_EPG }, + { 0x04, KEY_LIST }, + + { 0x03, KEY_1 }, + { 0x01, KEY_2 }, + { 0x06, KEY_3 }, + { 0x09, KEY_4 }, + { 0x1d, KEY_5 }, + { 0x1f, KEY_6 }, + { 0x0d, KEY_7 }, + { 0x19, KEY_8 }, + { 0x1b, KEY_9 }, + { 0x15, KEY_0 }, + + { 0x0c, KEY_CANCEL }, + { 0x4a, KEY_CLEAR }, + { 0x13, KEY_BACKSPACE }, + { 0x00, KEY_TAB }, + + { 0x4b, KEY_UP }, + { 0x51, KEY_DOWN }, + { 0x4e, KEY_LEFT }, + { 0x52, KEY_RIGHT }, + { 0x4f, KEY_ENTER }, + + { 0x1e, KEY_VOLUMEUP }, + { 0x0a, KEY_VOLUMEDOWN }, + { 0x02, KEY_CHANNELDOWN }, + { 0x05, KEY_CHANNELUP }, + { 0x11, KEY_RECORD }, + + { 0x14, KEY_PLAY }, + { 0x4c, KEY_PAUSE }, + { 0x1a, KEY_STOP }, + { 0x40, KEY_REWIND }, + { 0x12, KEY_FASTFORWARD }, + { 0x41, KEY_PREVIOUSSONG }, + { 0x42, KEY_NEXTSONG }, + { 0x54, KEY_SAVE }, + { 0x50, KEY_LANGUAGE }, + { 0x47, KEY_MEDIA }, + { 0x4d, KEY_SCREEN }, + { 0x43, KEY_SUBTITLE }, + { 0x10, KEY_MUTE }, + { 0x49, KEY_AUDIO }, + { 0x07, KEY_SLEEP }, + { 0x08, KEY_VIDEO }, + { 0x0e, KEY_AGAIN }, + { 0x45, KEY_EQUAL }, + { 0x46, KEY_MINUS }, + { 0x18, KEY_RED }, + { 0x53, KEY_GREEN }, + { 0x5e, KEY_YELLOW }, + { 0x5f, KEY_BLUE }, +}; + +static struct rc_map_list twinhan_vp1027_map = { + .map = { + .scan = twinhan_vp1027, + .size = ARRAY_SIZE(twinhan_vp1027), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TWINHAN_VP1027_DVBS, + } +}; + +static int __init init_rc_map_twinhan_vp1027(void) +{ + return rc_map_register(&twinhan_vp1027_map); +} + +static void __exit exit_rc_map_twinhan_vp1027(void) +{ + rc_map_unregister(&twinhan_vp1027_map); +} + +module_init(init_rc_map_twinhan_vp1027) +module_exit(exit_rc_map_twinhan_vp1027) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sergey Ivanov <123kash@gmail.com>"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-m1f.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-m1f.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-m1f.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-m1f.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,92 @@ +/* videomate-m1f.h - Keytable for videomate_m1f Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Pavel Osnova + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table videomate_m1f[] = { + { 0x01, KEY_POWER }, + { 0x31, KEY_TUNER }, + { 0x33, KEY_VIDEO }, + { 0x2f, KEY_RADIO }, + { 0x30, KEY_CAMERA }, + { 0x2d, KEY_NEW }, /* TV record button */ + { 0x17, KEY_CYCLEWINDOWS }, + { 0x2c, KEY_ANGLE }, + { 0x2b, KEY_LANGUAGE }, + { 0x32, KEY_SEARCH }, /* '...' button */ + { 0x11, KEY_UP }, + { 0x13, KEY_LEFT }, + { 0x15, KEY_OK }, + { 0x14, KEY_RIGHT }, + { 0x12, KEY_DOWN }, + { 0x16, KEY_BACKSPACE }, + { 0x02, KEY_ZOOM }, /* WIN key */ + { 0x04, KEY_INFO }, + { 0x05, KEY_VOLUMEUP }, + { 0x03, KEY_MUTE }, + { 0x07, KEY_CHANNELUP }, + { 0x06, KEY_VOLUMEDOWN }, + { 0x08, KEY_CHANNELDOWN }, + { 0x0c, KEY_RECORD }, + { 0x0e, KEY_STOP }, + { 0x0a, KEY_BACK }, + { 0x0b, KEY_PLAY }, + { 0x09, KEY_FORWARD }, + { 0x10, KEY_PREVIOUS }, + { 0x0d, KEY_PAUSE }, + { 0x0f, KEY_NEXT }, + { 0x1e, KEY_1 }, + { 0x1f, KEY_2 }, + { 0x20, KEY_3 }, + { 0x21, KEY_4 }, + { 0x22, KEY_5 }, + { 0x23, KEY_6 }, + { 0x24, KEY_7 }, + { 0x25, KEY_8 }, + { 0x26, KEY_9 }, + { 0x2a, KEY_NUMERIC_STAR }, /* * key */ + { 0x1d, KEY_0 }, + { 0x29, KEY_SUBTITLE }, /* # key */ + { 0x27, KEY_CLEAR }, + { 0x34, KEY_SCREEN }, + { 0x28, KEY_ENTER }, + { 0x19, KEY_RED }, + { 0x1a, KEY_GREEN }, + { 0x1b, KEY_YELLOW }, + { 0x1c, KEY_BLUE }, + { 0x18, KEY_TEXT }, +}; + +static struct rc_map_list videomate_m1f_map = { + .map = { + .scan = videomate_m1f, + .size = ARRAY_SIZE(videomate_m1f), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_VIDEOMATE_M1F, + } +}; + +static int __init init_rc_map_videomate_m1f(void) +{ + return rc_map_register(&videomate_m1f_map); +} + +static void __exit exit_rc_map_videomate_m1f(void) +{ + rc_map_unregister(&videomate_m1f_map); +} + +module_init(init_rc_map_videomate_m1f) +module_exit(exit_rc_map_videomate_m1f) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pavel Osnova "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-s350.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-s350.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-s350.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-s350.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,85 @@ +/* videomate-s350.h - Keytable for videomate_s350 Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table videomate_s350[] = { + { 0x00, KEY_TV}, + { 0x01, KEY_DVD}, + { 0x04, KEY_RECORD}, + { 0x05, KEY_VIDEO}, /* TV/Video */ + { 0x07, KEY_STOP}, + { 0x08, KEY_PLAYPAUSE}, + { 0x0a, KEY_REWIND}, + { 0x0f, KEY_FASTFORWARD}, + { 0x10, KEY_CHANNELUP}, + { 0x12, KEY_VOLUMEUP}, + { 0x13, KEY_CHANNELDOWN}, + { 0x14, KEY_MUTE}, + { 0x15, KEY_VOLUMEDOWN}, + { 0x16, KEY_1}, + { 0x17, KEY_2}, + { 0x18, KEY_3}, + { 0x19, KEY_4}, + { 0x1a, KEY_5}, + { 0x1b, KEY_6}, + { 0x1c, KEY_7}, + { 0x1d, KEY_8}, + { 0x1e, KEY_9}, + { 0x1f, KEY_0}, + { 0x21, KEY_SLEEP}, + { 0x24, KEY_ZOOM}, + { 0x25, KEY_LAST}, /* Recall */ + { 0x26, KEY_SUBTITLE}, /* CC */ + { 0x27, KEY_LANGUAGE}, /* MTS */ + { 0x29, KEY_CHANNEL}, /* SURF */ + { 0x2b, KEY_A}, + { 0x2c, KEY_B}, + { 0x2f, KEY_CAMERA}, /* Snapshot */ + { 0x23, KEY_RADIO}, + { 0x02, KEY_PREVIOUSSONG}, + { 0x06, KEY_NEXTSONG}, + { 0x03, KEY_EPG}, + { 0x09, KEY_SETUP}, + { 0x22, KEY_BACKSPACE}, + { 0x0c, KEY_UP}, + { 0x0e, KEY_DOWN}, + { 0x0b, KEY_LEFT}, + { 0x0d, KEY_RIGHT}, + { 0x11, KEY_ENTER}, + { 0x20, KEY_TEXT}, +}; + +static struct rc_map_list videomate_s350_map = { + .map = { + .scan = videomate_s350, + .size = ARRAY_SIZE(videomate_s350), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_VIDEOMATE_S350, + } +}; + +static int __init init_rc_map_videomate_s350(void) +{ + return rc_map_register(&videomate_s350_map); +} + +static void __exit exit_rc_map_videomate_s350(void) +{ + rc_map_unregister(&videomate_s350_map); +} + +module_init(init_rc_map_videomate_s350) +module_exit(exit_rc_map_videomate_s350) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,87 @@ +/* videomate-tv-pvr.h - Keytable for videomate_tv_pvr Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +static struct rc_map_table videomate_tv_pvr[] = { + { 0x14, KEY_MUTE }, + { 0x24, KEY_ZOOM }, + + { 0x01, KEY_DVD }, + { 0x23, KEY_RADIO }, + { 0x00, KEY_TV }, + + { 0x0a, KEY_REWIND }, + { 0x08, KEY_PLAYPAUSE }, + { 0x0f, KEY_FORWARD }, + + { 0x02, KEY_PREVIOUS }, + { 0x07, KEY_STOP }, + { 0x06, KEY_NEXT }, + + { 0x0c, KEY_UP }, + { 0x0e, KEY_DOWN }, + { 0x0b, KEY_LEFT }, + { 0x0d, KEY_RIGHT }, + { 0x11, KEY_OK }, + + { 0x03, KEY_MENU }, + { 0x09, KEY_SETUP }, + { 0x05, KEY_VIDEO }, + { 0x22, KEY_CHANNEL }, + + { 0x12, KEY_VOLUMEUP }, + { 0x15, KEY_VOLUMEDOWN }, + { 0x10, KEY_CHANNELUP }, + { 0x13, KEY_CHANNELDOWN }, + + { 0x04, KEY_RECORD }, + + { 0x16, KEY_1 }, + { 0x17, KEY_2 }, + { 0x18, KEY_3 }, + { 0x19, KEY_4 }, + { 0x1a, KEY_5 }, + { 0x1b, KEY_6 }, + { 0x1c, KEY_7 }, + { 0x1d, KEY_8 }, + { 0x1e, KEY_9 }, + { 0x1f, KEY_0 }, + + { 0x20, KEY_LANGUAGE }, + { 0x21, KEY_SLEEP }, +}; + +static struct rc_map_list videomate_tv_pvr_map = { + .map = { + .scan = videomate_tv_pvr, + .size = ARRAY_SIZE(videomate_tv_pvr), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_VIDEOMATE_TV_PVR, + } +}; + +static int __init init_rc_map_videomate_tv_pvr(void) +{ + return rc_map_register(&videomate_tv_pvr_map); +} + +static void __exit exit_rc_map_videomate_tv_pvr(void) +{ + rc_map_unregister(&videomate_tv_pvr_map); +} + +module_init(init_rc_map_videomate_tv_pvr) +module_exit(exit_rc_map_videomate_tv_pvr) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-winfast.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-winfast.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-winfast.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-winfast.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,102 @@ +/* winfast.h - Keytable for winfast Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */ + +static struct rc_map_table winfast[] = { + /* Keys 0 to 9 */ + { 0x12, KEY_0 }, + { 0x05, KEY_1 }, + { 0x06, KEY_2 }, + { 0x07, KEY_3 }, + { 0x09, KEY_4 }, + { 0x0a, KEY_5 }, + { 0x0b, KEY_6 }, + { 0x0d, KEY_7 }, + { 0x0e, KEY_8 }, + { 0x0f, KEY_9 }, + + { 0x00, KEY_POWER2 }, + { 0x1b, KEY_AUDIO }, /* Audio Source */ + { 0x02, KEY_TUNER }, /* TV/FM, not on Y0400052 */ + { 0x1e, KEY_VIDEO }, /* Video Source */ + { 0x16, KEY_INFO }, /* Display information */ + { 0x04, KEY_RIGHT }, + { 0x08, KEY_LEFT }, + { 0x0c, KEY_UP }, + { 0x10, KEY_DOWN }, + { 0x03, KEY_ZOOM }, /* fullscreen */ + { 0x1f, KEY_TEXT }, /* closed caption/teletext */ + { 0x20, KEY_SLEEP }, + { 0x29, KEY_CLEAR }, /* boss key */ + { 0x14, KEY_MUTE }, + { 0x2b, KEY_RED }, + { 0x2c, KEY_GREEN }, + { 0x2d, KEY_YELLOW }, + { 0x2e, KEY_BLUE }, + { 0x18, KEY_KPPLUS }, /* fine tune + , not on Y040052 */ + { 0x19, KEY_KPMINUS }, /* fine tune - , not on Y040052 */ + { 0x2a, KEY_TV2 }, /* PIP (Picture in picture */ + { 0x21, KEY_DOT }, + { 0x13, KEY_ENTER }, + { 0x11, KEY_LAST }, /* Recall (last channel */ + { 0x22, KEY_PREVIOUS }, + { 0x23, KEY_PLAYPAUSE }, + { 0x24, KEY_NEXT }, + { 0x25, KEY_TIME }, /* Time Shifting */ + { 0x26, KEY_STOP }, + { 0x27, KEY_RECORD }, + { 0x28, KEY_CAMERA }, /* Screenshot */ + { 0x2f, KEY_MENU }, + { 0x30, KEY_CANCEL }, + { 0x31, KEY_CHANNEL }, /* Channel Surf */ + { 0x32, KEY_SUBTITLE }, + { 0x33, KEY_LANGUAGE }, + { 0x34, KEY_REWIND }, + { 0x35, KEY_FASTFORWARD }, + { 0x36, KEY_TV }, + { 0x37, KEY_RADIO }, /* FM */ + { 0x38, KEY_DVD }, + + { 0x1a, KEY_MODE}, /* change to MCE mode on Y04G0051 */ + { 0x3e, KEY_VOLUMEUP }, /* MCE +VOL, on Y04G0033 */ + { 0x3a, KEY_VOLUMEDOWN }, /* MCE -VOL, on Y04G0033 */ + { 0x3b, KEY_CHANNELUP }, /* MCE +CH, on Y04G0033 */ + { 0x3f, KEY_CHANNELDOWN } /* MCE -CH, on Y04G0033 */ +}; + +static struct rc_map_list winfast_map = { + .map = { + .scan = winfast, + .size = ARRAY_SIZE(winfast), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_WINFAST, + } +}; + +static int __init init_rc_map_winfast(void) +{ + return rc_map_register(&winfast_map); +} + +static void __exit exit_rc_map_winfast(void) +{ + rc_map_unregister(&winfast_map); +} + +module_init(init_rc_map_winfast) +module_exit(exit_rc_map_winfast) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,82 @@ +/* winfast-usbii-deluxe.h - Keytable for winfast_usbii_deluxe Remote Controller + * + * keymap imported from ir-keymaps.c + * + * Copyright (c) 2010 by Mauro Carvalho Chehab + * + * 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, or + * (at your option) any later version. + */ + +#include + +/* Leadtek Winfast TV USB II Deluxe remote + Magnus Alm + */ + +static struct rc_map_table winfast_usbii_deluxe[] = { + { 0x62, KEY_0}, + { 0x75, KEY_1}, + { 0x76, KEY_2}, + { 0x77, KEY_3}, + { 0x79, KEY_4}, + { 0x7a, KEY_5}, + { 0x7b, KEY_6}, + { 0x7d, KEY_7}, + { 0x7e, KEY_8}, + { 0x7f, KEY_9}, + + { 0x38, KEY_CAMERA}, /* SNAPSHOT */ + { 0x37, KEY_RECORD}, /* RECORD */ + { 0x35, KEY_TIME}, /* TIMESHIFT */ + + { 0x74, KEY_VOLUMEUP}, /* VOLUMEUP */ + { 0x78, KEY_VOLUMEDOWN}, /* VOLUMEDOWN */ + { 0x64, KEY_MUTE}, /* MUTE */ + + { 0x21, KEY_CHANNEL}, /* SURF */ + { 0x7c, KEY_CHANNELUP}, /* CHANNELUP */ + { 0x60, KEY_CHANNELDOWN}, /* CHANNELDOWN */ + { 0x61, KEY_LAST}, /* LAST CHANNEL (RECALL) */ + + { 0x72, KEY_VIDEO}, /* INPUT MODES (TV/FM) */ + + { 0x70, KEY_POWER2}, /* TV ON/OFF */ + + { 0x39, KEY_CYCLEWINDOWS}, /* MINIMIZE (BOSS) */ + { 0x3a, KEY_NEW}, /* PIP */ + { 0x73, KEY_ZOOM}, /* FULLSECREEN */ + + { 0x66, KEY_INFO}, /* OSD (DISPLAY) */ + + { 0x31, KEY_DOT}, /* '.' */ + { 0x63, KEY_ENTER}, /* ENTER */ + +}; + +static struct rc_map_list winfast_usbii_deluxe_map = { + .map = { + .scan = winfast_usbii_deluxe, + .size = ARRAY_SIZE(winfast_usbii_deluxe), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_WINFAST_USBII_DELUXE, + } +}; + +static int __init init_rc_map_winfast_usbii_deluxe(void) +{ + return rc_map_register(&winfast_usbii_deluxe_map); +} + +static void __exit exit_rc_map_winfast_usbii_deluxe(void) +{ + rc_map_unregister(&winfast_usbii_deluxe_map); +} + +module_init(init_rc_map_winfast_usbii_deluxe) +module_exit(exit_rc_map_winfast_usbii_deluxe) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/lirc_dev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/lirc_dev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/lirc_dev.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/lirc_dev.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,816 @@ +/* + * LIRC base driver + * + * by Artur Lipowski + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int debug; + +#define IRCTL_DEV_NAME "BaseRemoteCtl" +#define NOPLUG -1 +#define LOGHEAD "lirc_dev (%s[%d]): " + +static dev_t lirc_base_dev; + +struct irctl { + struct lirc_driver d; + int attached; + int open; + + struct mutex irctl_lock; + struct lirc_buffer *buf; + unsigned int chunk_size; + + struct task_struct *task; + long jiffies_to_wait; +}; + +static DEFINE_MUTEX(lirc_dev_lock); + +static struct irctl *irctls[MAX_IRCTL_DEVICES]; +static struct cdev cdevs[MAX_IRCTL_DEVICES]; + +/* Only used for sysfs but defined to void otherwise */ +static struct class *lirc_class; + +/* helper function + * initializes the irctl structure + */ +static void lirc_irctl_init(struct irctl *ir) +{ + mutex_init(&ir->irctl_lock); + ir->d.minor = NOPLUG; +} + +static void lirc_irctl_cleanup(struct irctl *ir) +{ + dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); + + device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); + + if (ir->buf != ir->d.rbuf) { + lirc_buffer_free(ir->buf); + kfree(ir->buf); + } + ir->buf = NULL; +} + +/* helper function + * reads key codes from driver and puts them into buffer + * returns 0 on success + */ +static int lirc_add_to_buf(struct irctl *ir) +{ + if (ir->d.add_to_buf) { + int res = -ENODATA; + int got_data = 0; + + /* + * service the device as long as it is returning + * data and we have space + */ +get_data: + res = ir->d.add_to_buf(ir->d.data, ir->buf); + if (res == 0) { + got_data++; + goto get_data; + } + + if (res == -ENODEV) + kthread_stop(ir->task); + + return got_data ? 0 : res; + } + + return 0; +} + +/* main function of the polling thread + */ +static int lirc_thread(void *irctl) +{ + struct irctl *ir = irctl; + + dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n", + ir->d.name, ir->d.minor); + + do { + if (ir->open) { + if (ir->jiffies_to_wait) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(ir->jiffies_to_wait); + } + if (kthread_should_stop()) + break; + if (!lirc_add_to_buf(ir)) + wake_up_interruptible(&ir->buf->wait_poll); + } else { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + } while (!kthread_should_stop()); + + dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n", + ir->d.name, ir->d.minor); + + return 0; +} + + +static struct file_operations lirc_dev_fops = { + .owner = THIS_MODULE, + .read = lirc_dev_fop_read, + .write = lirc_dev_fop_write, + .poll = lirc_dev_fop_poll, + .unlocked_ioctl = lirc_dev_fop_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = lirc_dev_fop_ioctl, +#endif + .open = lirc_dev_fop_open, + .release = lirc_dev_fop_close, + .llseek = noop_llseek, +}; + +static int lirc_cdev_add(struct irctl *ir) +{ + int retval; + struct lirc_driver *d = &ir->d; + struct cdev *cdev = &cdevs[d->minor]; + + if (d->fops) { + cdev_init(cdev, d->fops); + cdev->owner = d->owner; + } else { + cdev_init(cdev, &lirc_dev_fops); + cdev->owner = THIS_MODULE; + } + retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); + if (retval) + return retval; + + retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); + if (retval) + kobject_put(&cdev->kobj); + + return retval; +} + +int lirc_register_driver(struct lirc_driver *d) +{ + struct irctl *ir; + int minor; + int bytes_in_key; + unsigned int chunk_size; + unsigned int buffer_size; + int err; + + if (!d) { + printk(KERN_ERR "lirc_dev: lirc_register_driver: " + "driver pointer must be not NULL!\n"); + err = -EBADRQC; + goto out; + } + + if (!d->dev) { + printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__); + err = -EINVAL; + goto out; + } + + if (MAX_IRCTL_DEVICES <= d->minor) { + dev_err(d->dev, "lirc_dev: lirc_register_driver: " + "\"minor\" must be between 0 and %d (%d)!\n", + MAX_IRCTL_DEVICES-1, d->minor); + err = -EBADRQC; + goto out; + } + + if (1 > d->code_length || (BUFLEN * 8) < d->code_length) { + dev_err(d->dev, "lirc_dev: lirc_register_driver: " + "code length in bits for minor (%d) " + "must be less than %d!\n", + d->minor, BUFLEN * 8); + err = -EBADRQC; + goto out; + } + + dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n", + d->sample_rate); + if (d->sample_rate) { + if (2 > d->sample_rate || HZ < d->sample_rate) { + dev_err(d->dev, "lirc_dev: lirc_register_driver: " + "sample_rate must be between 2 and %d!\n", HZ); + err = -EBADRQC; + goto out; + } + if (!d->add_to_buf) { + dev_err(d->dev, "lirc_dev: lirc_register_driver: " + "add_to_buf cannot be NULL when " + "sample_rate is set\n"); + err = -EBADRQC; + goto out; + } + } else if (!(d->fops && d->fops->read) && !d->rbuf) { + dev_err(d->dev, "lirc_dev: lirc_register_driver: " + "fops->read and rbuf cannot all be NULL!\n"); + err = -EBADRQC; + goto out; + } else if (!d->rbuf) { + if (!(d->fops && d->fops->read && d->fops->poll && + d->fops->unlocked_ioctl)) { + dev_err(d->dev, "lirc_dev: lirc_register_driver: " + "neither read, poll nor unlocked_ioctl can be NULL!\n"); + err = -EBADRQC; + goto out; + } + } + + mutex_lock(&lirc_dev_lock); + + minor = d->minor; + + if (minor < 0) { + /* find first free slot for driver */ + for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) + if (!irctls[minor]) + break; + if (MAX_IRCTL_DEVICES == minor) { + dev_err(d->dev, "lirc_dev: lirc_register_driver: " + "no free slots for drivers!\n"); + err = -ENOMEM; + goto out_lock; + } + } else if (irctls[minor]) { + dev_err(d->dev, "lirc_dev: lirc_register_driver: " + "minor (%d) just registered!\n", minor); + err = -EBUSY; + goto out_lock; + } + + ir = kzalloc(sizeof(struct irctl), GFP_KERNEL); + if (!ir) { + err = -ENOMEM; + goto out_lock; + } + lirc_irctl_init(ir); + irctls[minor] = ir; + d->minor = minor; + + if (d->sample_rate) { + ir->jiffies_to_wait = HZ / d->sample_rate; + } else { + /* it means - wait for external event in task queue */ + ir->jiffies_to_wait = 0; + } + + /* some safety check 8-) */ + d->name[sizeof(d->name)-1] = '\0'; + + bytes_in_key = BITS_TO_LONGS(d->code_length) + + (d->code_length % 8 ? 1 : 0); + buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; + chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; + + if (d->rbuf) { + ir->buf = d->rbuf; + } else { + ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); + if (!ir->buf) { + err = -ENOMEM; + goto out_lock; + } + err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); + if (err) { + kfree(ir->buf); + goto out_lock; + } + } + ir->chunk_size = ir->buf->chunk_size; + + if (d->features == 0) + d->features = LIRC_CAN_REC_LIRCCODE; + + ir->d = *d; + + device_create(lirc_class, ir->d.dev, + MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL, + "lirc%u", ir->d.minor); + + if (d->sample_rate) { + /* try to fire up polling thread */ + ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev"); + if (IS_ERR(ir->task)) { + dev_err(d->dev, "lirc_dev: lirc_register_driver: " + "cannot run poll thread for minor = %d\n", + d->minor); + err = -ECHILD; + goto out_sysfs; + } + } + + err = lirc_cdev_add(ir); + if (err) + goto out_sysfs; + + ir->attached = 1; + mutex_unlock(&lirc_dev_lock); + + dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", + ir->d.name, ir->d.minor); + return minor; + +out_sysfs: + device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); +out_lock: + mutex_unlock(&lirc_dev_lock); +out: + return err; +} +EXPORT_SYMBOL(lirc_register_driver); + +int lirc_unregister_driver(int minor) +{ + struct irctl *ir; + struct cdev *cdev; + + if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { + printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between " + "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1); + return -EBADRQC; + } + + ir = irctls[minor]; + if (!ir) { + printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct " + "for minor %d!\n", __func__, minor); + return -ENOENT; + } + + cdev = &cdevs[minor]; + + mutex_lock(&lirc_dev_lock); + + if (ir->d.minor != minor) { + printk(KERN_ERR "lirc_dev: %s: minor (%d) device not " + "registered!\n", __func__, minor); + mutex_unlock(&lirc_dev_lock); + return -ENOENT; + } + + /* end up polling thread */ + if (ir->task) + kthread_stop(ir->task); + + dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", + ir->d.name, ir->d.minor); + + ir->attached = 0; + if (ir->open) { + dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", + ir->d.name, ir->d.minor); + wake_up_interruptible(&ir->buf->wait_poll); + mutex_lock(&ir->irctl_lock); + ir->d.set_use_dec(ir->d.data); + module_put(cdev->owner); + mutex_unlock(&ir->irctl_lock); + } else { + lirc_irctl_cleanup(ir); + cdev_del(cdev); + kfree(ir); + irctls[minor] = NULL; + } + + mutex_unlock(&lirc_dev_lock); + + return 0; +} +EXPORT_SYMBOL(lirc_unregister_driver); + +int lirc_dev_fop_open(struct inode *inode, struct file *file) +{ + struct irctl *ir; + struct cdev *cdev; + int retval = 0; + + if (iminor(inode) >= MAX_IRCTL_DEVICES) { + printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n", + iminor(inode)); + return -ENODEV; + } + + if (mutex_lock_interruptible(&lirc_dev_lock)) + return -ERESTARTSYS; + + ir = irctls[iminor(inode)]; + if (!ir) { + retval = -ENODEV; + goto error; + } + + dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); + + if (ir->d.minor == NOPLUG) { + retval = -ENODEV; + goto error; + } + + if (ir->open) { + retval = -EBUSY; + goto error; + } + + cdev = &cdevs[iminor(inode)]; + if (try_module_get(cdev->owner)) { + ir->open++; + retval = ir->d.set_use_inc(ir->d.data); + + if (retval) { + module_put(cdev->owner); + ir->open--; + } else { + lirc_buffer_clear(ir->buf); + } + if (ir->task) + wake_up_process(ir->task); + } + +error: + if (ir) + dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n", + ir->d.name, ir->d.minor, retval); + + mutex_unlock(&lirc_dev_lock); + + nonseekable_open(inode, file); + + return retval; +} +EXPORT_SYMBOL(lirc_dev_fop_open); + +int lirc_dev_fop_close(struct inode *inode, struct file *file) +{ + struct irctl *ir = irctls[iminor(inode)]; + struct cdev *cdev = &cdevs[iminor(inode)]; + + if (!ir) { + printk(KERN_ERR "%s: called with invalid irctl\n", __func__); + return -EINVAL; + } + + dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); + + WARN_ON(mutex_lock_killable(&lirc_dev_lock)); + + ir->open--; + if (ir->attached) { + ir->d.set_use_dec(ir->d.data); + module_put(cdev->owner); + } else { + lirc_irctl_cleanup(ir); + cdev_del(cdev); + irctls[ir->d.minor] = NULL; + kfree(ir); + } + + mutex_unlock(&lirc_dev_lock); + + return 0; +} +EXPORT_SYMBOL(lirc_dev_fop_close); + +unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) +{ + struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; + unsigned int ret; + + if (!ir) { + printk(KERN_ERR "%s: called with invalid irctl\n", __func__); + return POLLERR; + } + + dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); + + if (!ir->attached) + return POLLERR; + + poll_wait(file, &ir->buf->wait_poll, wait); + + if (ir->buf) + if (lirc_buffer_empty(ir->buf)) + ret = 0; + else + ret = POLLIN | POLLRDNORM; + else + ret = POLLERR; + + dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n", + ir->d.name, ir->d.minor, ret); + + return ret; +} +EXPORT_SYMBOL(lirc_dev_fop_poll); + +long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + __u32 mode; + int result = 0; + struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; + + if (!ir) { + printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__); + return -ENODEV; + } + + dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", + ir->d.name, ir->d.minor, cmd); + + if (ir->d.minor == NOPLUG || !ir->attached) { + dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", + ir->d.name, ir->d.minor); + return -ENODEV; + } + + mutex_lock(&ir->irctl_lock); + + switch (cmd) { + case LIRC_GET_FEATURES: + result = put_user(ir->d.features, (__u32 *)arg); + break; + case LIRC_GET_REC_MODE: + if (!(ir->d.features & LIRC_CAN_REC_MASK)) { + result = -ENOSYS; + break; + } + + result = put_user(LIRC_REC2MODE + (ir->d.features & LIRC_CAN_REC_MASK), + (__u32 *)arg); + break; + case LIRC_SET_REC_MODE: + if (!(ir->d.features & LIRC_CAN_REC_MASK)) { + result = -ENOSYS; + break; + } + + result = get_user(mode, (__u32 *)arg); + if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) + result = -EINVAL; + /* + * FIXME: We should actually set the mode somehow but + * for now, lirc_serial doesn't support mode changing either + */ + break; + case LIRC_GET_LENGTH: + result = put_user(ir->d.code_length, (__u32 *)arg); + break; + case LIRC_GET_MIN_TIMEOUT: + if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || + ir->d.min_timeout == 0) { + result = -ENOSYS; + break; + } + + result = put_user(ir->d.min_timeout, (__u32 *)arg); + break; + case LIRC_GET_MAX_TIMEOUT: + if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || + ir->d.max_timeout == 0) { + result = -ENOSYS; + break; + } + + result = put_user(ir->d.max_timeout, (__u32 *)arg); + break; + default: + result = -EINVAL; + } + + dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n", + ir->d.name, ir->d.minor, result); + + mutex_unlock(&ir->irctl_lock); + + return result; +} +EXPORT_SYMBOL(lirc_dev_fop_ioctl); + +ssize_t lirc_dev_fop_read(struct file *file, + char __user *buffer, + size_t length, + loff_t *ppos) +{ + struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; + unsigned char *buf; + int ret = 0, written = 0; + DECLARE_WAITQUEUE(wait, current); + + if (!ir) { + printk(KERN_ERR "%s: called with invalid irctl\n", __func__); + return -ENODEV; + } + + dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); + + buf = kzalloc(ir->chunk_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (mutex_lock_interruptible(&ir->irctl_lock)) { + ret = -ERESTARTSYS; + goto out_unlocked; + } + if (!ir->attached) { + ret = -ENODEV; + goto out_locked; + } + + if (length % ir->chunk_size) { + ret = -EINVAL; + goto out_locked; + } + + /* + * we add ourselves to the task queue before buffer check + * to avoid losing scan code (in case when queue is awaken somewhere + * between while condition checking and scheduling) + */ + add_wait_queue(&ir->buf->wait_poll, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + /* + * while we didn't provide 'length' bytes, device is opened in blocking + * mode and 'copy_to_user' is happy, wait for data. + */ + while (written < length && ret == 0) { + if (lirc_buffer_empty(ir->buf)) { + /* According to the read(2) man page, 'written' can be + * returned as less than 'length', instead of blocking + * again, returning -EWOULDBLOCK, or returning + * -ERESTARTSYS */ + if (written) + break; + if (file->f_flags & O_NONBLOCK) { + ret = -EWOULDBLOCK; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + mutex_unlock(&ir->irctl_lock); + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + + if (mutex_lock_interruptible(&ir->irctl_lock)) { + ret = -ERESTARTSYS; + remove_wait_queue(&ir->buf->wait_poll, &wait); + set_current_state(TASK_RUNNING); + goto out_unlocked; + } + + if (!ir->attached) { + ret = -ENODEV; + break; + } + } else { + lirc_buffer_read(ir->buf, buf); + ret = copy_to_user((void *)buffer+written, buf, + ir->buf->chunk_size); + if (!ret) + written += ir->buf->chunk_size; + else + ret = -EFAULT; + } + } + + remove_wait_queue(&ir->buf->wait_poll, &wait); + set_current_state(TASK_RUNNING); + +out_locked: + mutex_unlock(&ir->irctl_lock); + +out_unlocked: + kfree(buf); + dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", + ir->d.name, ir->d.minor, ret ? "" : "", ret); + + return ret ? ret : written; +} +EXPORT_SYMBOL(lirc_dev_fop_read); + +void *lirc_get_pdata(struct file *file) +{ + void *data = NULL; + + if (file && file->f_dentry && file->f_dentry->d_inode && + file->f_dentry->d_inode->i_rdev) { + struct irctl *ir; + ir = irctls[iminor(file->f_dentry->d_inode)]; + data = ir->d.data; + } + + return data; +} +EXPORT_SYMBOL(lirc_get_pdata); + + +ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer, + size_t length, loff_t *ppos) +{ + struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; + + if (!ir) { + printk(KERN_ERR "%s: called with invalid irctl\n", __func__); + return -ENODEV; + } + + dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); + + if (!ir->attached) + return -ENODEV; + + return -EINVAL; +} +EXPORT_SYMBOL(lirc_dev_fop_write); + + +static int __init lirc_dev_init(void) +{ + int retval; + + lirc_class = class_create(THIS_MODULE, "lirc"); + if (IS_ERR(lirc_class)) { + retval = PTR_ERR(lirc_class); + printk(KERN_ERR "lirc_dev: class_create failed\n"); + goto error; + } + + retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES, + IRCTL_DEV_NAME); + if (retval) { + class_destroy(lirc_class); + printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n"); + goto error; + } + + + printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, " + "major %d \n", MAJOR(lirc_base_dev)); + +error: + return retval; +} + + + +static void __exit lirc_dev_exit(void) +{ + class_destroy(lirc_class); + unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES); + printk(KERN_INFO "lirc_dev: module unloaded\n"); +} + +module_init(lirc_dev_init); +module_exit(lirc_dev_exit); + +MODULE_DESCRIPTION("LIRC base driver module"); +MODULE_AUTHOR("Artur Lipowski"); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,25 @@ +rc-core-objs := rc-main.o ir-raw.o + +obj-y += keymaps/ + +obj-$(CONFIG_RC_CORE) += rc-core.o +obj-$(CONFIG_LIRC) += lirc_dev.o +obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o +obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o +obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o +obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o +obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o +obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o +obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o + +# stand-alone IR receivers/transmitters +obj-$(CONFIG_IR_IMON) += imon.o +obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o +obj-$(CONFIG_IR_MCEUSB) += mceusb.o +obj-$(CONFIG_IR_FINTEK) += fintek-cir.o +obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o +obj-$(CONFIG_IR_ENE) += ene_ir.o +obj-$(CONFIG_IR_REDRAT3) += redrat3.o +obj-$(CONFIG_IR_STREAMZAP) += streamzap.o +obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o +obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/mceusb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/mceusb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/mceusb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/mceusb.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1330 @@ +/* + * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers + * + * Copyright (c) 2010 by Jarod Wilson + * + * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan + * Conti, Martin Blatter and Daniel Melander, the latter of which was + * in turn also based on the lirc_atiusb driver by Paul Miller. The + * two mce drivers were merged into one by Jarod Wilson, with transmit + * support for the 1st-gen device added primarily by Patrick Calhoun, + * with a bit of tweaks by Jarod. Debugging improvements and proper + * support for what appears to be 3rd-gen hardware added by Jarod. + * Initial port from lirc driver to ir-core drivery by Jarod, based + * partially on a port to an earlier proposed IR infrastructure by + * Jon Smirl, which included enhancements and simplifications to the + * incoming IR buffer parsing routines. + * + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "1.91" +#define DRIVER_AUTHOR "Jarod Wilson " +#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ + "device driver" +#define DRIVER_NAME "mceusb" + +#define USB_BUFLEN 32 /* USB reception buffer length */ +#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ +#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ + +/* MCE constants */ +#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ +#define MCE_TIME_UNIT 50 /* Approx 50us resolution */ +#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ +#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ +#define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ +#define MCE_IRDATA_TRAILER 0x80 /* End of IR data */ +#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ +#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ +#define MCE_DEFAULT_TX_MASK 0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */ +#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */ +#define MCE_PULSE_MASK 0x7f /* Pulse mask */ +#define MCE_MAX_PULSE_LENGTH 0x7f /* Longest transmittable pulse symbol */ + +#define MCE_HW_CMD_HEADER 0xff /* MCE hardware command header */ +#define MCE_COMMAND_HEADER 0x9f /* MCE command header */ +#define MCE_COMMAND_MASK 0xe0 /* Mask out command bits */ +#define MCE_COMMAND_NULL 0x00 /* These show up various places... */ +/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER, + * then we're looking at a raw IR data sample */ +#define MCE_COMMAND_IRDATA 0x80 +#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ + +/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */ +#define MCE_CMD_SIG_END 0x01 /* End of signal */ +#define MCE_CMD_PING 0x03 /* Ping device */ +#define MCE_CMD_UNKNOWN 0x04 /* Unknown */ +#define MCE_CMD_UNKNOWN2 0x05 /* Unknown */ +#define MCE_CMD_S_CARRIER 0x06 /* Set TX carrier frequency */ +#define MCE_CMD_G_CARRIER 0x07 /* Get TX carrier frequency */ +#define MCE_CMD_S_TXMASK 0x08 /* Set TX port bitmask */ +#define MCE_CMD_UNKNOWN3 0x09 /* Unknown */ +#define MCE_CMD_UNKNOWN4 0x0a /* Unknown */ +#define MCE_CMD_G_REVISION 0x0b /* Get hw/sw revision */ +#define MCE_CMD_S_TIMEOUT 0x0c /* Set RX timeout value */ +#define MCE_CMD_G_TIMEOUT 0x0d /* Get RX timeout value */ +#define MCE_CMD_UNKNOWN5 0x0e /* Unknown */ +#define MCE_CMD_UNKNOWN6 0x0f /* Unknown */ +#define MCE_CMD_G_RXPORTSTS 0x11 /* Get RX port status */ +#define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */ +#define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */ +#define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */ +#define MCE_RSP_PULSE_COUNT 0x15 /* RX pulse count (only if learning) */ +#define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */ +#define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */ +#define MCE_CMD_UNKNOWN7 0x18 /* Unknown */ +#define MCE_CMD_UNKNOWN8 0x19 /* Unknown */ +#define MCE_CMD_UNKNOWN9 0x1b /* Unknown */ +#define MCE_CMD_DEVICE_RESET 0xaa /* Reset the hardware */ +#define MCE_RSP_CMD_INVALID 0xfe /* Invalid command issued */ + + +/* module parameters */ +#ifdef CONFIG_USB_DEBUG +static int debug = 1; +#else +static int debug; +#endif + +/* general constants */ +#define SEND_FLAG_IN_PROGRESS 1 +#define SEND_FLAG_COMPLETE 2 +#define RECV_FLAG_IN_PROGRESS 3 +#define RECV_FLAG_COMPLETE 4 + +#define MCEUSB_RX 1 +#define MCEUSB_TX 2 + +#define VENDOR_PHILIPS 0x0471 +#define VENDOR_SMK 0x0609 +#define VENDOR_TATUNG 0x1460 +#define VENDOR_GATEWAY 0x107b +#define VENDOR_SHUTTLE 0x1308 +#define VENDOR_SHUTTLE2 0x051c +#define VENDOR_MITSUMI 0x03ee +#define VENDOR_TOPSEED 0x1784 +#define VENDOR_RICAVISION 0x179d +#define VENDOR_ITRON 0x195d +#define VENDOR_FIC 0x1509 +#define VENDOR_LG 0x043e +#define VENDOR_MICROSOFT 0x045e +#define VENDOR_FORMOSA 0x147a +#define VENDOR_FINTEK 0x1934 +#define VENDOR_PINNACLE 0x2304 +#define VENDOR_ECS 0x1019 +#define VENDOR_WISTRON 0x0fb8 +#define VENDOR_COMPRO 0x185b +#define VENDOR_NORTHSTAR 0x04eb +#define VENDOR_REALTEK 0x0bda +#define VENDOR_TIVO 0x105a +#define VENDOR_CONEXANT 0x0572 + +enum mceusb_model_type { + MCE_GEN2 = 0, /* Most boards */ + MCE_GEN1, + MCE_GEN3, + MCE_GEN2_TX_INV, + POLARIS_EVK, + CX_HYBRID_TV, + MULTIFUNCTION, + TIVO_KIT, + MCE_GEN2_NO_TX, +}; + +struct mceusb_model { + u32 mce_gen1:1; + u32 mce_gen2:1; + u32 mce_gen3:1; + u32 tx_mask_normal:1; + u32 no_tx:1; + + int ir_intfnum; + + const char *rc_map; /* Allow specify a per-board map */ + const char *name; /* per-board name */ +}; + +static const struct mceusb_model mceusb_model[] = { + [MCE_GEN1] = { + .mce_gen1 = 1, + .tx_mask_normal = 1, + }, + [MCE_GEN2] = { + .mce_gen2 = 1, + }, + [MCE_GEN2_NO_TX] = { + .mce_gen2 = 1, + .no_tx = 1, + }, + [MCE_GEN2_TX_INV] = { + .mce_gen2 = 1, + .tx_mask_normal = 1, + }, + [MCE_GEN3] = { + .mce_gen3 = 1, + .tx_mask_normal = 1, + }, + [POLARIS_EVK] = { + /* + * In fact, the EVK is shipped without + * remotes, but we should have something handy, + * to allow testing it + */ + .rc_map = RC_MAP_HAUPPAUGE, + .name = "Conexant Hybrid TV (cx231xx) MCE IR", + }, + [CX_HYBRID_TV] = { + .no_tx = 1, /* tx isn't wired up at all */ + .name = "Conexant Hybrid TV (cx231xx) MCE IR", + }, + [MULTIFUNCTION] = { + .mce_gen2 = 1, + .ir_intfnum = 2, + }, + [TIVO_KIT] = { + .mce_gen2 = 1, + .rc_map = RC_MAP_TIVO, + }, +}; + +static struct usb_device_id mceusb_dev_table[] = { + /* Original Microsoft MCE IR Transceiver (often HP-branded) */ + { USB_DEVICE(VENDOR_MICROSOFT, 0x006d), + .driver_info = MCE_GEN1 }, + /* Philips Infrared Transceiver - Sahara branded */ + { USB_DEVICE(VENDOR_PHILIPS, 0x0608) }, + /* Philips Infrared Transceiver - HP branded */ + { USB_DEVICE(VENDOR_PHILIPS, 0x060c), + .driver_info = MCE_GEN2_TX_INV }, + /* Philips SRM5100 */ + { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, + /* Philips Infrared Transceiver - Omaura */ + { USB_DEVICE(VENDOR_PHILIPS, 0x060f) }, + /* Philips Infrared Transceiver - Spinel plus */ + { USB_DEVICE(VENDOR_PHILIPS, 0x0613) }, + /* Philips eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_PHILIPS, 0x0815) }, + /* Philips/Spinel plus IR transceiver for ASUS */ + { USB_DEVICE(VENDOR_PHILIPS, 0x206c) }, + /* Philips/Spinel plus IR transceiver for ASUS */ + { USB_DEVICE(VENDOR_PHILIPS, 0x2088) }, + /* Philips IR transceiver (Dell branded) */ + { USB_DEVICE(VENDOR_PHILIPS, 0x2093) }, + /* Realtek MCE IR Receiver and card reader */ + { USB_DEVICE(VENDOR_REALTEK, 0x0161), + .driver_info = MULTIFUNCTION }, + /* SMK/Toshiba G83C0004D410 */ + { USB_DEVICE(VENDOR_SMK, 0x031d), + .driver_info = MCE_GEN2_TX_INV }, + /* SMK eHome Infrared Transceiver (Sony VAIO) */ + { USB_DEVICE(VENDOR_SMK, 0x0322), + .driver_info = MCE_GEN2_TX_INV }, + /* bundled with Hauppauge PVR-150 */ + { USB_DEVICE(VENDOR_SMK, 0x0334), + .driver_info = MCE_GEN2_TX_INV }, + /* SMK eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_SMK, 0x0338) }, + /* Tatung eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, + /* Shuttle eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) }, + /* Shuttle eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) }, + /* Gateway eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_GATEWAY, 0x3009) }, + /* Mitsumi */ + { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, + /* Topseed eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x0001), + .driver_info = MCE_GEN2_TX_INV }, + /* Topseed HP eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x0006), + .driver_info = MCE_GEN2_TX_INV }, + /* Topseed eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x0007), + .driver_info = MCE_GEN2_TX_INV }, + /* Topseed eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x0008), + .driver_info = MCE_GEN3 }, + /* Topseed eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x000a), + .driver_info = MCE_GEN2_TX_INV }, + /* Topseed eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x0011), + .driver_info = MCE_GEN3 }, + /* Ricavision internal Infrared Transceiver */ + { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, + /* Itron ione Libra Q-11 */ + { USB_DEVICE(VENDOR_ITRON, 0x7002) }, + /* FIC eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_FIC, 0x9242) }, + /* LG eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_LG, 0x9803) }, + /* Microsoft MCE Infrared Transceiver */ + { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) }, + /* Formosa eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe015) }, + /* Formosa21 / eHome Infrared Receiver */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe016) }, + /* Formosa aim / Trust MCE Infrared Receiver */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe017), + .driver_info = MCE_GEN2_NO_TX }, + /* Formosa Industrial Computing / Beanbag Emulation Device */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe018) }, + /* Formosa21 / eHome Infrared Receiver */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) }, + /* Formosa Industrial Computing AIM IR605/A */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, + /* Formosa Industrial Computing */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, + /* Fintek eHome Infrared Transceiver (HP branded) */ + { USB_DEVICE(VENDOR_FINTEK, 0x5168) }, + /* Fintek eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, + /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ + { USB_DEVICE(VENDOR_FINTEK, 0x0702) }, + /* Pinnacle Remote Kit */ + { USB_DEVICE(VENDOR_PINNACLE, 0x0225), + .driver_info = MCE_GEN3 }, + /* Elitegroup Computer Systems IR */ + { USB_DEVICE(VENDOR_ECS, 0x0f38) }, + /* Wistron Corp. eHome Infrared Receiver */ + { USB_DEVICE(VENDOR_WISTRON, 0x0002) }, + /* Compro K100 */ + { USB_DEVICE(VENDOR_COMPRO, 0x3020) }, + /* Compro K100 v2 */ + { USB_DEVICE(VENDOR_COMPRO, 0x3082) }, + /* Northstar Systems, Inc. eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, + /* TiVo PC IR Receiver */ + { USB_DEVICE(VENDOR_TIVO, 0x2000), + .driver_info = TIVO_KIT }, + /* Conexant Hybrid TV "Shelby" Polaris SDK */ + { USB_DEVICE(VENDOR_CONEXANT, 0x58a1), + .driver_info = POLARIS_EVK }, + /* Conexant Hybrid TV RDU253S Polaris */ + { USB_DEVICE(VENDOR_CONEXANT, 0x58a5), + .driver_info = CX_HYBRID_TV }, + /* Terminating entry */ + { } +}; + +/* data structure for each usb transceiver */ +struct mceusb_dev { + /* ir-core bits */ + struct rc_dev *rc; + + /* optional features we can enable */ + bool carrier_report_enabled; + bool learning_enabled; + + /* core device bits */ + struct device *dev; + + /* usb */ + struct usb_device *usbdev; + struct urb *urb_in; + struct usb_endpoint_descriptor *usb_ep_in; + struct usb_endpoint_descriptor *usb_ep_out; + + /* buffers and dma */ + unsigned char *buf_in; + unsigned int len_in; + dma_addr_t dma_in; + dma_addr_t dma_out; + + enum { + CMD_HEADER = 0, + SUBCMD, + CMD_DATA, + PARSE_IRDATA, + } parser_state; + + u8 cmd, rem; /* Remaining IR data bytes in packet */ + + struct { + u32 connected:1; + u32 tx_mask_normal:1; + u32 microsoft_gen1:1; + u32 no_tx:1; + } flags; + + /* transmit support */ + int send_flags; + u32 carrier; + unsigned char tx_mask; + + char name[128]; + char phys[64]; + enum mceusb_model_type model; +}; + +/* + * MCE Device Command Strings + * Device command responses vary from device to device... + * - DEVICE_RESET resets the hardware to its default state + * - GET_REVISION fetches the hardware/software revision, common + * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42 + * - GET_CARRIER_FREQ gets the carrier mode and frequency of the + * device, with replies in the form of 9f 06 MM FF, where MM is 0-3, + * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is + * ((clk / frequency) - 1) + * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us, + * response in the form of 9f 0c msb lsb + * - GET_TX_BITMASK fetches the transmitter bitmask, replies in + * the form of 9f 08 bm, where bm is the bitmask + * - GET_RX_SENSOR fetches the RX sensor setting -- long-range + * general use one or short-range learning one, in the form of + * 9f 14 ss, where ss is either 01 for long-range or 02 for short + * - SET_CARRIER_FREQ sets a new carrier mode and frequency + * - SET_TX_BITMASK sets the transmitter bitmask + * - SET_RX_TIMEOUT sets the receiver timeout + * - SET_RX_SENSOR sets which receiver sensor to use + */ +static char DEVICE_RESET[] = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER, + MCE_CMD_DEVICE_RESET}; +static char GET_REVISION[] = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION}; +static char GET_UNKNOWN[] = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7}; +static char GET_UNKNOWN2[] = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2}; +static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER}; +static char GET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT}; +static char GET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK}; +static char GET_RX_SENSOR[] = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR}; +/* sub in desired values in lower byte or bytes for full command */ +/* FIXME: make use of these for transmit. +static char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, + MCE_CMD_S_CARRIER, 0x00, 0x00}; +static char SET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00}; +static char SET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, + MCE_CMD_S_TIMEOUT, 0x00, 0x00}; +static char SET_RX_SENSOR[] = {MCE_COMMAND_HEADER, + MCE_CMD_S_RXSENSOR, 0x00}; +*/ + +static int mceusb_cmdsize(u8 cmd, u8 subcmd) +{ + int datasize = 0; + + switch (cmd) { + case MCE_COMMAND_NULL: + if (subcmd == MCE_HW_CMD_HEADER) + datasize = 1; + break; + case MCE_HW_CMD_HEADER: + switch (subcmd) { + case MCE_CMD_G_REVISION: + datasize = 2; + break; + } + case MCE_COMMAND_HEADER: + switch (subcmd) { + case MCE_CMD_UNKNOWN: + case MCE_CMD_S_CARRIER: + case MCE_CMD_S_TIMEOUT: + case MCE_RSP_PULSE_COUNT: + datasize = 2; + break; + case MCE_CMD_SIG_END: + case MCE_CMD_S_TXMASK: + case MCE_CMD_S_RXSENSOR: + datasize = 1; + break; + } + } + return datasize; +} + +static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, + int offset, int len, bool out) +{ + char codes[USB_BUFLEN * 3 + 1]; + char inout[9]; + u8 cmd, subcmd, data1, data2; + struct device *dev = ir->dev; + int i, start, skip = 0; + + if (!debug) + return; + + /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ + if (ir->flags.microsoft_gen1 && !out && !offset) + skip = 2; + + if (len <= skip) + return; + + for (i = 0; i < len && i < USB_BUFLEN; i++) + snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff); + + dev_info(dev, "%sx data: %s(length=%d)\n", + (out ? "t" : "r"), codes, len); + + if (out) + strcpy(inout, "Request\0"); + else + strcpy(inout, "Got\0"); + + start = offset + skip; + cmd = buf[start] & 0xff; + subcmd = buf[start + 1] & 0xff; + data1 = buf[start + 2] & 0xff; + data2 = buf[start + 3] & 0xff; + + switch (cmd) { + case MCE_COMMAND_NULL: + if ((subcmd == MCE_HW_CMD_HEADER) && + (data1 == MCE_CMD_DEVICE_RESET)) + dev_info(dev, "Device reset requested\n"); + else + dev_info(dev, "Unknown command 0x%02x 0x%02x\n", + cmd, subcmd); + break; + case MCE_HW_CMD_HEADER: + switch (subcmd) { + case MCE_CMD_G_REVISION: + if (len == 2) + dev_info(dev, "Get hw/sw rev?\n"); + else + dev_info(dev, "hw/sw rev 0x%02x 0x%02x " + "0x%02x 0x%02x\n", data1, data2, + buf[start + 4], buf[start + 5]); + break; + case MCE_CMD_DEVICE_RESET: + dev_info(dev, "Device reset requested\n"); + break; + case MCE_RSP_CMD_INVALID: + dev_info(dev, "Previous command not supported\n"); + break; + case MCE_CMD_UNKNOWN7: + case MCE_CMD_UNKNOWN9: + default: + dev_info(dev, "Unknown command 0x%02x 0x%02x\n", + cmd, subcmd); + break; + } + break; + case MCE_COMMAND_HEADER: + switch (subcmd) { + case MCE_CMD_SIG_END: + dev_info(dev, "End of signal\n"); + break; + case MCE_CMD_PING: + dev_info(dev, "Ping\n"); + break; + case MCE_CMD_UNKNOWN: + dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", + data1, data2); + break; + case MCE_CMD_S_CARRIER: + dev_info(dev, "%s carrier mode and freq of " + "0x%02x 0x%02x\n", inout, data1, data2); + break; + case MCE_CMD_G_CARRIER: + dev_info(dev, "Get carrier mode and freq\n"); + break; + case MCE_CMD_S_TXMASK: + dev_info(dev, "%s transmit blaster mask of 0x%02x\n", + inout, data1); + break; + case MCE_CMD_S_TIMEOUT: + /* value is in units of 50us, so x*50/100 or x/2 ms */ + dev_info(dev, "%s receive timeout of %d ms\n", + inout, ((data1 << 8) | data2) / 2); + break; + case MCE_CMD_G_TIMEOUT: + dev_info(dev, "Get receive timeout\n"); + break; + case MCE_CMD_G_TXMASK: + dev_info(dev, "Get transmit blaster mask\n"); + break; + case MCE_CMD_S_RXSENSOR: + dev_info(dev, "%s %s-range receive sensor in use\n", + inout, data1 == 0x02 ? "short" : "long"); + break; + case MCE_CMD_G_RXSENSOR: + /* aka MCE_RSP_PULSE_COUNT */ + if (out) + dev_info(dev, "Get receive sensor\n"); + else if (ir->learning_enabled) + dev_info(dev, "RX pulse count: %d\n", + ((data1 << 8) | data2)); + break; + case MCE_RSP_CMD_INVALID: + dev_info(dev, "Error! Hardware is likely wedged...\n"); + break; + case MCE_CMD_UNKNOWN2: + case MCE_CMD_UNKNOWN3: + case MCE_CMD_UNKNOWN5: + default: + dev_info(dev, "Unknown command 0x%02x 0x%02x\n", + cmd, subcmd); + break; + } + break; + default: + break; + } + + if (cmd == MCE_IRDATA_TRAILER) + dev_info(dev, "End of raw IR data\n"); + else if ((cmd != MCE_COMMAND_HEADER) && + ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA)) + dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem); +} + +static void mce_async_callback(struct urb *urb, struct pt_regs *regs) +{ + struct mceusb_dev *ir; + int len; + + if (!urb) + return; + + ir = urb->context; + if (ir) { + len = urb->actual_length; + + dev_dbg(ir->dev, "callback called (status=%d len=%d)\n", + urb->status, len); + + mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true); + } + +} + +/* request incoming or send outgoing usb packet - used to initialize remote */ +static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, + int size, int urb_type) +{ + int res, pipe; + struct urb *async_urb; + struct device *dev = ir->dev; + unsigned char *async_buf; + + if (urb_type == MCEUSB_TX) { + async_urb = usb_alloc_urb(0, GFP_KERNEL); + if (unlikely(!async_urb)) { + dev_err(dev, "Error, couldn't allocate urb!\n"); + return; + } + + async_buf = kzalloc(size, GFP_KERNEL); + if (!async_buf) { + dev_err(dev, "Error, couldn't allocate buf!\n"); + usb_free_urb(async_urb); + return; + } + + /* outbound data */ + pipe = usb_sndintpipe(ir->usbdev, + ir->usb_ep_out->bEndpointAddress); + usb_fill_int_urb(async_urb, ir->usbdev, pipe, + async_buf, size, (usb_complete_t)mce_async_callback, + ir, ir->usb_ep_out->bInterval); + memcpy(async_buf, data, size); + + } else if (urb_type == MCEUSB_RX) { + /* standard request */ + async_urb = ir->urb_in; + ir->send_flags = RECV_FLAG_IN_PROGRESS; + + } else { + dev_err(dev, "Error! Unknown urb type %d\n", urb_type); + return; + } + + dev_dbg(dev, "receive request called (size=%#x)\n", size); + + async_urb->transfer_buffer_length = size; + async_urb->dev = ir->usbdev; + + res = usb_submit_urb(async_urb, GFP_ATOMIC); + if (res) { + dev_dbg(dev, "receive request FAILED! (res=%d)\n", res); + return; + } + dev_dbg(dev, "receive request complete (res=%d)\n", res); +} + +static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) +{ + mce_request_packet(ir, data, size, MCEUSB_TX); +} + +static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) +{ + mce_request_packet(ir, data, size, MCEUSB_RX); +} + +/* Send data out the IR blaster port(s) */ +static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) +{ + struct mceusb_dev *ir = dev->priv; + int i, ret = 0; + int cmdcount = 0; + unsigned char *cmdbuf; /* MCE command buffer */ + long signal_duration = 0; /* Singnal length in us */ + struct timeval start_time, end_time; + + do_gettimeofday(&start_time); + + cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL); + if (!cmdbuf) + return -ENOMEM; + + /* MCE tx init header */ + cmdbuf[cmdcount++] = MCE_COMMAND_HEADER; + cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK; + cmdbuf[cmdcount++] = ir->tx_mask; + + /* Generate mce packet data */ + for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { + signal_duration += txbuf[i]; + txbuf[i] = txbuf[i] / MCE_TIME_UNIT; + + do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ + + /* Insert mce packet header every 4th entry */ + if ((cmdcount < MCE_CMDBUF_SIZE) && + (cmdcount - MCE_TX_HEADER_LENGTH) % + MCE_CODE_LENGTH == 0) + cmdbuf[cmdcount++] = MCE_IRDATA_HEADER; + + /* Insert mce packet data */ + if (cmdcount < MCE_CMDBUF_SIZE) + cmdbuf[cmdcount++] = + (txbuf[i] < MCE_PULSE_BIT ? + txbuf[i] : MCE_MAX_PULSE_LENGTH) | + (i & 1 ? 0x00 : MCE_PULSE_BIT); + else { + ret = -EINVAL; + goto out; + } + + } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) && + (txbuf[i] -= MCE_MAX_PULSE_LENGTH)); + } + + /* Fix packet length in last header */ + cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] = + MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) % + MCE_CODE_LENGTH - 1; + + /* Check if we have room for the empty packet at the end */ + if (cmdcount >= MCE_CMDBUF_SIZE) { + ret = -EINVAL; + goto out; + } + + /* All mce commands end with an empty packet (0x80) */ + cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER; + + /* Transmit the command to the mce device */ + mce_async_out(ir, cmdbuf, cmdcount); + + /* + * The lircd gap calculation expects the write function to + * wait the time it takes for the ircommand to be sent before + * it returns. + */ + do_gettimeofday(&end_time); + signal_duration -= (end_time.tv_usec - start_time.tv_usec) + + (end_time.tv_sec - start_time.tv_sec) * 1000000; + + /* delay with the closest number of ticks */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(signal_duration)); + +out: + kfree(cmdbuf); + return ret ? ret : count; +} + +/* Sets active IR outputs -- mce devices typically have two */ +static int mceusb_set_tx_mask(struct rc_dev *dev, u32 mask) +{ + struct mceusb_dev *ir = dev->priv; + + if (ir->flags.tx_mask_normal) + ir->tx_mask = mask; + else + ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ? + mask ^ MCE_DEFAULT_TX_MASK : mask) << 1; + + return 0; +} + +/* Sets the send carrier frequency and mode */ +static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + struct mceusb_dev *ir = dev->priv; + int clk = 10000000; + int prescaler = 0, divisor = 0; + unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER, + MCE_CMD_S_CARRIER, 0x00, 0x00 }; + + /* Carrier has changed */ + if (ir->carrier != carrier) { + + if (carrier == 0) { + ir->carrier = carrier; + cmdbuf[2] = MCE_CMD_SIG_END; + cmdbuf[3] = MCE_IRDATA_TRAILER; + dev_dbg(ir->dev, "%s: disabling carrier " + "modulation\n", __func__); + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + return carrier; + } + + for (prescaler = 0; prescaler < 4; ++prescaler) { + divisor = (clk >> (2 * prescaler)) / carrier; + if (divisor <= 0xff) { + ir->carrier = carrier; + cmdbuf[2] = prescaler; + cmdbuf[3] = divisor; + dev_dbg(ir->dev, "%s: requesting %u HZ " + "carrier\n", __func__, carrier); + + /* Transmit new carrier to mce device */ + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + return carrier; + } + } + + return -EINVAL; + + } + + return carrier; +} + +/* + * We don't do anything but print debug spew for many of the command bits + * we receive from the hardware, but some of them are useful information + * we want to store so that we can use them. + */ +static void mceusb_handle_command(struct mceusb_dev *ir, int index) +{ + u8 hi = ir->buf_in[index + 1] & 0xff; + u8 lo = ir->buf_in[index + 2] & 0xff; + + switch (ir->buf_in[index]) { + /* 2-byte return value commands */ + case MCE_CMD_S_TIMEOUT: + ir->rc->timeout = US_TO_NS((hi << 8 | lo) / 2); + break; + + /* 1-byte return value commands */ + case MCE_CMD_S_TXMASK: + ir->tx_mask = hi; + break; + case MCE_CMD_S_RXSENSOR: + ir->learning_enabled = (hi == 0x02); + break; + default: + break; + } +} + +static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) +{ + DEFINE_IR_RAW_EVENT(rawir); + int i = 0; + + /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ + if (ir->flags.microsoft_gen1) + i = 2; + + /* if there's no data, just return now */ + if (buf_len <= i) + return; + + for (; i < buf_len; i++) { + switch (ir->parser_state) { + case SUBCMD: + ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]); + mceusb_dev_printdata(ir, ir->buf_in, i - 1, + ir->rem + 2, false); + mceusb_handle_command(ir, i); + ir->parser_state = CMD_DATA; + break; + case PARSE_IRDATA: + ir->rem--; + init_ir_raw_event(&rawir); + rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); + rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) + * US_TO_NS(MCE_TIME_UNIT); + + dev_dbg(ir->dev, "Storing %s with duration %d\n", + rawir.pulse ? "pulse" : "space", + rawir.duration); + + ir_raw_event_store_with_filter(ir->rc, &rawir); + break; + case CMD_DATA: + ir->rem--; + break; + case CMD_HEADER: + /* decode mce packets of the form (84),AA,BB,CC,DD */ + /* IR data packets can span USB messages - rem */ + ir->cmd = ir->buf_in[i]; + if ((ir->cmd == MCE_COMMAND_HEADER) || + ((ir->cmd & MCE_COMMAND_MASK) != + MCE_COMMAND_IRDATA)) { + ir->parser_state = SUBCMD; + continue; + } + ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK); + mceusb_dev_printdata(ir, ir->buf_in, + i, ir->rem + 1, false); + if (ir->rem) + ir->parser_state = PARSE_IRDATA; + else + ir_raw_event_reset(ir->rc); + break; + } + + if (ir->parser_state != CMD_HEADER && !ir->rem) + ir->parser_state = CMD_HEADER; + } + dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n"); + ir_raw_event_handle(ir->rc); +} + +static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) +{ + struct mceusb_dev *ir; + int buf_len; + + if (!urb) + return; + + ir = urb->context; + if (!ir) { + usb_unlink_urb(urb); + return; + } + + buf_len = urb->actual_length; + + if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { + ir->send_flags = SEND_FLAG_COMPLETE; + dev_dbg(ir->dev, "setup answer received %d bytes\n", + buf_len); + } + + switch (urb->status) { + /* success */ + case 0: + mceusb_process_ir_data(ir, buf_len); + break; + + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + usb_unlink_urb(urb); + return; + + case -EPIPE: + default: + dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status); + break; + } + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static void mceusb_gen1_init(struct mceusb_dev *ir) +{ + int ret; + int maxp = ir->len_in; + struct device *dev = ir->dev; + char *data; + + data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL); + if (!data) { + dev_err(dev, "%s: memory allocation failed!\n", __func__); + return; + } + + /* + * This is a strange one. Windows issues a set address to the device + * on the receive control pipe and expect a certain value pair back + */ + ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), + USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, + data, USB_CTRL_MSG_SZ, HZ * 3); + dev_dbg(dev, "%s - ret = %d\n", __func__, ret); + dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", + __func__, data[0], data[1]); + + /* set feature: bit rate 38400 bps */ + ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), + USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, + 0xc04e, 0x0000, NULL, 0, HZ * 3); + + dev_dbg(dev, "%s - ret = %d\n", __func__, ret); + + /* bRequest 4: set char length to 8 bits */ + ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), + 4, USB_TYPE_VENDOR, + 0x0808, 0x0000, NULL, 0, HZ * 3); + dev_dbg(dev, "%s - retB = %d\n", __func__, ret); + + /* bRequest 2: set handshaking to use DTR/DSR */ + ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), + 2, USB_TYPE_VENDOR, + 0x0000, 0x0100, NULL, 0, HZ * 3); + dev_dbg(dev, "%s - retC = %d\n", __func__, ret); + + /* device reset */ + mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); + mce_sync_in(ir, NULL, maxp); + + /* get hw/sw revision? */ + mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); + mce_sync_in(ir, NULL, maxp); + + kfree(data); +}; + +static void mceusb_gen2_init(struct mceusb_dev *ir) +{ + int maxp = ir->len_in; + + /* device reset */ + mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); + mce_sync_in(ir, NULL, maxp); + + /* get hw/sw revision? */ + mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); + mce_sync_in(ir, NULL, maxp); + + /* unknown what the next two actually return... */ + mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); + mce_sync_in(ir, NULL, maxp); + mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); + mce_sync_in(ir, NULL, maxp); +} + +static void mceusb_get_parameters(struct mceusb_dev *ir) +{ + int maxp = ir->len_in; + + /* get the carrier and frequency */ + mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); + mce_sync_in(ir, NULL, maxp); + + if (!ir->flags.no_tx) { + /* get the transmitter bitmask */ + mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); + mce_sync_in(ir, NULL, maxp); + } + + /* get receiver timeout value */ + mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); + mce_sync_in(ir, NULL, maxp); + + /* get receiver sensor setting */ + mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); + mce_sync_in(ir, NULL, maxp); +} + +static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) +{ + struct device *dev = ir->dev; + struct rc_dev *rc; + int ret; + + rc = rc_allocate_device(); + if (!rc) { + dev_err(dev, "remote dev allocation failed\n"); + goto out; + } + + snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)", + mceusb_model[ir->model].name ? + mceusb_model[ir->model].name : + "Media Center Ed. eHome Infrared Remote Transceiver", + le16_to_cpu(ir->usbdev->descriptor.idVendor), + le16_to_cpu(ir->usbdev->descriptor.idProduct)); + + usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys)); + + rc->input_name = ir->name; + rc->input_phys = ir->phys; + usb_to_input_id(ir->usbdev, &rc->input_id); + rc->dev.parent = dev; + rc->priv = ir; + rc->driver_type = RC_DRIVER_IR_RAW; + rc->allowed_protos = RC_TYPE_ALL; + rc->timeout = US_TO_NS(1000); + if (!ir->flags.no_tx) { + rc->s_tx_mask = mceusb_set_tx_mask; + rc->s_tx_carrier = mceusb_set_tx_carrier; + rc->tx_ir = mceusb_tx_ir; + } + rc->driver_name = DRIVER_NAME; + rc->map_name = mceusb_model[ir->model].rc_map ? + mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE; + + ret = rc_register_device(rc); + if (ret < 0) { + dev_err(dev, "remote dev registration failed\n"); + goto out; + } + + return rc; + +out: + rc_free_device(rc); + return NULL; +} + +static int __devinit mceusb_dev_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *idesc; + struct usb_endpoint_descriptor *ep = NULL; + struct usb_endpoint_descriptor *ep_in = NULL; + struct usb_endpoint_descriptor *ep_out = NULL; + struct mceusb_dev *ir = NULL; + int pipe, maxp, i; + char buf[63], name[128] = ""; + enum mceusb_model_type model = id->driver_info; + bool is_gen3; + bool is_microsoft_gen1; + bool tx_mask_normal; + int ir_intfnum; + + dev_dbg(&intf->dev, "%s called\n", __func__); + + idesc = intf->cur_altsetting; + + is_gen3 = mceusb_model[model].mce_gen3; + is_microsoft_gen1 = mceusb_model[model].mce_gen1; + tx_mask_normal = mceusb_model[model].tx_mask_normal; + ir_intfnum = mceusb_model[model].ir_intfnum; + + /* There are multi-function devices with non-IR interfaces */ + if (idesc->desc.bInterfaceNumber != ir_intfnum) + return -ENODEV; + + /* step through the endpoints to find first bulk in and out endpoint */ + for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { + ep = &idesc->endpoint[i].desc; + + if ((ep_in == NULL) + && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN) + && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK) + || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT))) { + + ep_in = ep; + ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; + ep_in->bInterval = 1; + dev_dbg(&intf->dev, "acceptable inbound endpoint " + "found\n"); + } + + if ((ep_out == NULL) + && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_OUT) + && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK) + || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT))) { + + ep_out = ep; + ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; + ep_out->bInterval = 1; + dev_dbg(&intf->dev, "acceptable outbound endpoint " + "found\n"); + } + } + if (ep_in == NULL) { + dev_dbg(&intf->dev, "inbound and/or endpoint not found\n"); + return -ENODEV; + } + + pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL); + if (!ir) + goto mem_alloc_fail; + + ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in); + if (!ir->buf_in) + goto buf_in_alloc_fail; + + ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); + if (!ir->urb_in) + goto urb_in_alloc_fail; + + ir->usbdev = dev; + ir->dev = &intf->dev; + ir->len_in = maxp; + ir->flags.microsoft_gen1 = is_microsoft_gen1; + ir->flags.tx_mask_normal = tx_mask_normal; + ir->flags.no_tx = mceusb_model[model].no_tx; + ir->model = model; + + /* Saving usb interface data for use by the transmitter routine */ + ir->usb_ep_in = ep_in; + ir->usb_ep_out = ep_out; + + if (dev->descriptor.iManufacturer + && usb_string(dev, dev->descriptor.iManufacturer, + buf, sizeof(buf)) > 0) + strlcpy(name, buf, sizeof(name)); + if (dev->descriptor.iProduct + && usb_string(dev, dev->descriptor.iProduct, + buf, sizeof(buf)) > 0) + snprintf(name + strlen(name), sizeof(name) - strlen(name), + " %s", buf); + + ir->rc = mceusb_init_rc_dev(ir); + if (!ir->rc) + goto rc_dev_fail; + + /* flush buffers on the device */ + mce_sync_in(ir, NULL, maxp); + mce_sync_in(ir, NULL, maxp); + + /* wire up inbound data handler */ + usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, + maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); + ir->urb_in->transfer_dma = ir->dma_in; + ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* initialize device */ + if (ir->flags.microsoft_gen1) + mceusb_gen1_init(ir); + else if (!is_gen3) + mceusb_gen2_init(ir); + + mceusb_get_parameters(ir); + + if (!ir->flags.no_tx) + mceusb_set_tx_mask(ir->rc, MCE_DEFAULT_TX_MASK); + + usb_set_intfdata(intf, ir); + + dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name, + dev->bus->busnum, dev->devnum); + + return 0; + + /* Error-handling path */ +rc_dev_fail: + usb_free_urb(ir->urb_in); +urb_in_alloc_fail: + usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in); +buf_in_alloc_fail: + kfree(ir); +mem_alloc_fail: + dev_err(&intf->dev, "%s: device setup failed!\n", __func__); + + return -ENOMEM; +} + + +static void __devexit mceusb_dev_disconnect(struct usb_interface *intf) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct mceusb_dev *ir = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + if (!ir) + return; + + ir->usbdev = NULL; + rc_unregister_device(ir->rc); + usb_kill_urb(ir->urb_in); + usb_free_urb(ir->urb_in); + usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); + + kfree(ir); +} + +static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct mceusb_dev *ir = usb_get_intfdata(intf); + dev_info(ir->dev, "suspend\n"); + usb_kill_urb(ir->urb_in); + return 0; +} + +static int mceusb_dev_resume(struct usb_interface *intf) +{ + struct mceusb_dev *ir = usb_get_intfdata(intf); + dev_info(ir->dev, "resume\n"); + if (usb_submit_urb(ir->urb_in, GFP_ATOMIC)) + return -EIO; + return 0; +} + +static struct usb_driver mceusb_dev_driver = { + .name = DRIVER_NAME, + .probe = mceusb_dev_probe, + .disconnect = mceusb_dev_disconnect, + .suspend = mceusb_dev_suspend, + .resume = mceusb_dev_resume, + .reset_resume = mceusb_dev_resume, + .id_table = mceusb_dev_table +}; + +static int __init mceusb_dev_init(void) +{ + int ret; + + ret = usb_register(&mceusb_dev_driver); + if (ret < 0) + printk(KERN_ERR DRIVER_NAME + ": usb register failed, result = %d\n", ret); + + return ret; +} + +static void __exit mceusb_dev_exit(void) +{ + usb_deregister(&mceusb_dev_driver); +} + +module_init(mceusb_dev_init); +module_exit(mceusb_dev_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, mceusb_dev_table); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/nuvoton-cir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/nuvoton-cir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/nuvoton-cir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/nuvoton-cir.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1274 @@ +/* + * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR + * + * Copyright (C) 2010 Jarod Wilson + * Copyright (C) 2009 Nuvoton PS Team + * + * Special thanks to Nuvoton for providing hardware, spec sheets and + * sample code upon which portions of this driver are based. Indirect + * thanks also to Maxim Levitsky, whose ene_ir driver this driver is + * modeled after. + * + * 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, or (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nuvoton-cir.h" + +/* write val to config reg */ +static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg) +{ + outb(reg, nvt->cr_efir); + outb(val, nvt->cr_efdr); +} + +/* read val from config reg */ +static inline u8 nvt_cr_read(struct nvt_dev *nvt, u8 reg) +{ + outb(reg, nvt->cr_efir); + return inb(nvt->cr_efdr); +} + +/* update config register bit without changing other bits */ +static inline void nvt_set_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg) +{ + u8 tmp = nvt_cr_read(nvt, reg) | val; + nvt_cr_write(nvt, tmp, reg); +} + +/* clear config register bit without changing other bits */ +static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg) +{ + u8 tmp = nvt_cr_read(nvt, reg) & ~val; + nvt_cr_write(nvt, tmp, reg); +} + +/* enter extended function mode */ +static inline void nvt_efm_enable(struct nvt_dev *nvt) +{ + /* Enabling Extended Function Mode explicitly requires writing 2x */ + outb(EFER_EFM_ENABLE, nvt->cr_efir); + outb(EFER_EFM_ENABLE, nvt->cr_efir); +} + +/* exit extended function mode */ +static inline void nvt_efm_disable(struct nvt_dev *nvt) +{ + outb(EFER_EFM_DISABLE, nvt->cr_efir); +} + +/* + * When you want to address a specific logical device, write its logical + * device number to CR_LOGICAL_DEV_SEL, then enable/disable by writing + * 0x1/0x0 respectively to CR_LOGICAL_DEV_EN. + */ +static inline void nvt_select_logical_dev(struct nvt_dev *nvt, u8 ldev) +{ + outb(CR_LOGICAL_DEV_SEL, nvt->cr_efir); + outb(ldev, nvt->cr_efdr); +} + +/* write val to cir config register */ +static inline void nvt_cir_reg_write(struct nvt_dev *nvt, u8 val, u8 offset) +{ + outb(val, nvt->cir_addr + offset); +} + +/* read val from cir config register */ +static u8 nvt_cir_reg_read(struct nvt_dev *nvt, u8 offset) +{ + u8 val; + + val = inb(nvt->cir_addr + offset); + + return val; +} + +/* write val to cir wake register */ +static inline void nvt_cir_wake_reg_write(struct nvt_dev *nvt, + u8 val, u8 offset) +{ + outb(val, nvt->cir_wake_addr + offset); +} + +/* read val from cir wake config register */ +static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset) +{ + u8 val; + + val = inb(nvt->cir_wake_addr + offset); + + return val; +} + +#define pr_reg(text, ...) \ + printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__) + +/* dump current cir register contents */ +static void cir_dump_regs(struct nvt_dev *nvt) +{ + nvt_efm_enable(nvt); + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); + + pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME); + pr_reg(" * CR CIR ACTIVE : 0x%x\n", + nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); + pr_reg(" * CR CIR BASE ADDR: 0x%x\n", + (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | + nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO)); + pr_reg(" * CR CIR IRQ NUM: 0x%x\n", + nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); + + nvt_efm_disable(nvt); + + pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME); + pr_reg(" * IRCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON)); + pr_reg(" * IRSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS)); + pr_reg(" * IREN: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN)); + pr_reg(" * RXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT)); + pr_reg(" * CP: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CP)); + pr_reg(" * CC: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CC)); + pr_reg(" * SLCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH)); + pr_reg(" * SLCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL)); + pr_reg(" * FIFOCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON)); + pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS)); + pr_reg(" * SRXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO)); + pr_reg(" * TXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT)); + pr_reg(" * STXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO)); + pr_reg(" * FCCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH)); + pr_reg(" * FCCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL)); + pr_reg(" * IRFSM: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM)); +} + +/* dump current cir wake register contents */ +static void cir_wake_dump_regs(struct nvt_dev *nvt) +{ + u8 i, fifo_len; + + nvt_efm_enable(nvt); + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); + + pr_reg("%s: Dump CIR WAKE logical device registers:\n", + NVT_DRIVER_NAME); + pr_reg(" * CR CIR WAKE ACTIVE : 0x%x\n", + nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); + pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n", + (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | + nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO)); + pr_reg(" * CR CIR WAKE IRQ NUM: 0x%x\n", + nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); + + nvt_efm_disable(nvt); + + pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME); + pr_reg(" * IRCON: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON)); + pr_reg(" * IRSTS: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS)); + pr_reg(" * IREN: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN)); + pr_reg(" * FIFO CMP DEEP: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP)); + pr_reg(" * FIFO CMP TOL: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL)); + pr_reg(" * FIFO COUNT: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT)); + pr_reg(" * SLCH: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH)); + pr_reg(" * SLCL: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL)); + pr_reg(" * FIFOCON: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON)); + pr_reg(" * SRXFSTS: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS)); + pr_reg(" * SAMPLE RX FIFO: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO)); + pr_reg(" * WR FIFO DATA: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA)); + pr_reg(" * RD FIFO ONLY: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); + pr_reg(" * RD FIFO ONLY IDX: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)); + pr_reg(" * FIFO IGNORE: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE)); + pr_reg(" * IRFSM: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM)); + + fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT); + pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len); + pr_reg("* Contents = "); + for (i = 0; i < fifo_len; i++) + printk(KERN_CONT "%02x ", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); + printk(KERN_CONT "\n"); +} + +/* detect hardware features */ +static int nvt_hw_detect(struct nvt_dev *nvt) +{ + unsigned long flags; + u8 chip_major, chip_minor; + int ret = 0; + char chip_id[12]; + bool chip_unknown = false; + + nvt_efm_enable(nvt); + + /* Check if we're wired for the alternate EFER setup */ + chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); + if (chip_major == 0xff) { + nvt->cr_efir = CR_EFIR2; + nvt->cr_efdr = CR_EFDR2; + nvt_efm_enable(nvt); + chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); + } + + chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO); + + /* these are the known working chip revisions... */ + switch (chip_major) { + case CHIP_ID_HIGH_667: + strcpy(chip_id, "w83667hg\0"); + if (chip_minor != CHIP_ID_LOW_667) + chip_unknown = true; + break; + case CHIP_ID_HIGH_677B: + strcpy(chip_id, "w83677hg\0"); + if (chip_minor != CHIP_ID_LOW_677B2 && + chip_minor != CHIP_ID_LOW_677B3) + chip_unknown = true; + break; + case CHIP_ID_HIGH_677C: + strcpy(chip_id, "w83677hg-c\0"); + if (chip_minor != CHIP_ID_LOW_677C) + chip_unknown = true; + break; + default: + strcpy(chip_id, "w836x7hg\0"); + chip_unknown = true; + break; + } + + /* warn, but still let the driver load, if we don't know this chip */ + if (chip_unknown) + nvt_pr(KERN_WARNING, "%s: unknown chip, id: 0x%02x 0x%02x, " + "it may not work...", chip_id, chip_major, chip_minor); + else + nvt_dbg("%s: chip id: 0x%02x 0x%02x", + chip_id, chip_major, chip_minor); + + nvt_efm_disable(nvt); + + spin_lock_irqsave(&nvt->nvt_lock, flags); + nvt->chip_major = chip_major; + nvt->chip_minor = chip_minor; + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + return ret; +} + +static void nvt_cir_ldev_init(struct nvt_dev *nvt) +{ + u8 val, psreg, psmask, psval; + + if (nvt->chip_major == CHIP_ID_HIGH_667) { + psreg = CR_MULTIFUNC_PIN_SEL; + psmask = MULTIFUNC_PIN_SEL_MASK; + psval = MULTIFUNC_ENABLE_CIR | MULTIFUNC_ENABLE_CIRWB; + } else { + psreg = CR_OUTPUT_PIN_SEL; + psmask = OUTPUT_PIN_SEL_MASK; + psval = OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB; + } + + /* output pin selection: enable CIR, with WB sensor enabled */ + val = nvt_cr_read(nvt, psreg); + val &= psmask; + val |= psval; + nvt_cr_write(nvt, val, psreg); + + /* Select CIR logical device and enable */ + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); + nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); + + nvt_cr_write(nvt, nvt->cir_addr >> 8, CR_CIR_BASE_ADDR_HI); + nvt_cr_write(nvt, nvt->cir_addr & 0xff, CR_CIR_BASE_ADDR_LO); + + nvt_cr_write(nvt, nvt->cir_irq, CR_CIR_IRQ_RSRC); + + nvt_dbg("CIR initialized, base io port address: 0x%lx, irq: %d", + nvt->cir_addr, nvt->cir_irq); +} + +static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt) +{ + /* Select ACPI logical device, enable it and CIR Wake */ + nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI); + nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); + + /* Enable CIR Wake via PSOUT# (Pin60) */ + nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE); + + /* enable cir interrupt of mouse/keyboard IRQ event */ + nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS); + + /* enable pme interrupt of cir wakeup event */ + nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2); + + /* Select CIR Wake logical device and enable */ + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); + nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); + + nvt_cr_write(nvt, nvt->cir_wake_addr >> 8, CR_CIR_BASE_ADDR_HI); + nvt_cr_write(nvt, nvt->cir_wake_addr & 0xff, CR_CIR_BASE_ADDR_LO); + + nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC); + + nvt_dbg("CIR Wake initialized, base io port address: 0x%lx, irq: %d", + nvt->cir_wake_addr, nvt->cir_wake_irq); +} + +/* clear out the hardware's cir rx fifo */ +static void nvt_clear_cir_fifo(struct nvt_dev *nvt) +{ + u8 val; + + val = nvt_cir_reg_read(nvt, CIR_FIFOCON); + nvt_cir_reg_write(nvt, val | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); +} + +/* clear out the hardware's cir wake rx fifo */ +static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt) +{ + u8 val; + + val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON); + nvt_cir_wake_reg_write(nvt, val | CIR_WAKE_FIFOCON_RXFIFOCLR, + CIR_WAKE_FIFOCON); +} + +/* clear out the hardware's cir tx fifo */ +static void nvt_clear_tx_fifo(struct nvt_dev *nvt) +{ + u8 val; + + val = nvt_cir_reg_read(nvt, CIR_FIFOCON); + nvt_cir_reg_write(nvt, val | CIR_FIFOCON_TXFIFOCLR, CIR_FIFOCON); +} + +/* enable RX Trigger Level Reach and Packet End interrupts */ +static void nvt_set_cir_iren(struct nvt_dev *nvt) +{ + u8 iren; + + iren = CIR_IREN_RTR | CIR_IREN_PE; + nvt_cir_reg_write(nvt, iren, CIR_IREN); +} + +static void nvt_cir_regs_init(struct nvt_dev *nvt) +{ + /* set sample limit count (PE interrupt raised when reached) */ + nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH); + nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL); + + /* set fifo irq trigger levels */ + nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV | + CIR_FIFOCON_RX_TRIGGER_LEV, CIR_FIFOCON); + + /* + * Enable TX and RX, specify carrier on = low, off = high, and set + * sample period (currently 50us) + */ + nvt_cir_reg_write(nvt, + CIR_IRCON_TXEN | CIR_IRCON_RXEN | + CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, + CIR_IRCON); + + /* clear hardware rx and tx fifos */ + nvt_clear_cir_fifo(nvt); + nvt_clear_tx_fifo(nvt); + + /* clear any and all stray interrupts */ + nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); + + /* and finally, enable interrupts */ + nvt_set_cir_iren(nvt); +} + +static void nvt_cir_wake_regs_init(struct nvt_dev *nvt) +{ + /* set number of bytes needed for wake from s3 (default 65) */ + nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_CMP_BYTES, + CIR_WAKE_FIFO_CMP_DEEP); + + /* set tolerance/variance allowed per byte during wake compare */ + nvt_cir_wake_reg_write(nvt, CIR_WAKE_CMP_TOLERANCE, + CIR_WAKE_FIFO_CMP_TOL); + + /* set sample limit count (PE interrupt raised when reached) */ + nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH); + nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL); + + /* set cir wake fifo rx trigger level (currently 67) */ + nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFOCON_RX_TRIGGER_LEV, + CIR_WAKE_FIFOCON); + + /* + * Enable TX and RX, specific carrier on = low, off = high, and set + * sample period (currently 50us) + */ + nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | + CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | + CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, + CIR_WAKE_IRCON); + + /* clear cir wake rx fifo */ + nvt_clear_cir_wake_fifo(nvt); + + /* clear any and all stray interrupts */ + nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); +} + +static void nvt_enable_wake(struct nvt_dev *nvt) +{ + nvt_efm_enable(nvt); + + nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI); + nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE); + nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS); + nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2); + + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); + nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); + + nvt_efm_disable(nvt); + + nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | + CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | + CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, + CIR_WAKE_IRCON); + nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); + nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); +} + +/* rx carrier detect only works in learning mode, must be called w/nvt_lock */ +static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) +{ + u32 count, carrier, duration = 0; + int i; + + count = nvt_cir_reg_read(nvt, CIR_FCCL) | + nvt_cir_reg_read(nvt, CIR_FCCH) << 8; + + for (i = 0; i < nvt->pkts; i++) { + if (nvt->buf[i] & BUF_PULSE_BIT) + duration += nvt->buf[i] & BUF_LEN_MASK; + } + + duration *= SAMPLE_PERIOD; + + if (!count || !duration) { + nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)", + count, duration); + return 0; + } + + carrier = MS_TO_NS(count) / duration; + + if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER)) + nvt_dbg("WTF? Carrier frequency out of range!"); + + nvt_dbg("Carrier frequency: %u (count %u, duration %u)", + carrier, count, duration); + + return carrier; +} + +/* + * set carrier frequency + * + * set carrier on 2 registers: CP & CC + * always set CP as 0x81 + * set CC by SPEC, CC = 3MHz/carrier - 1 + */ +static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + struct nvt_dev *nvt = dev->priv; + u16 val; + + nvt_cir_reg_write(nvt, 1, CIR_CP); + val = 3000000 / (carrier) - 1; + nvt_cir_reg_write(nvt, val & 0xff, CIR_CC); + + nvt_dbg("cp: 0x%x cc: 0x%x\n", + nvt_cir_reg_read(nvt, CIR_CP), nvt_cir_reg_read(nvt, CIR_CC)); + + return 0; +} + +/* + * nvt_tx_ir + * + * 1) clean TX fifo first (handled by AP) + * 2) copy data from user space + * 3) disable RX interrupts, enable TX interrupts: TTR & TFU + * 4) send 9 packets to TX FIFO to open TTR + * in interrupt_handler: + * 5) send all data out + * go back to write(): + * 6) disable TX interrupts, re-enable RX interupts + * + * The key problem of this function is user space data may larger than + * driver's data buf length. So nvt_tx_ir() will only copy TX_BUF_LEN data to + * buf, and keep current copied data buf num in cur_buf_num. But driver's buf + * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to + * set TXFCONT as 0xff, until buf_count less than 0xff. + */ +static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) +{ + struct nvt_dev *nvt = dev->priv; + unsigned long flags; + unsigned int i; + u8 iren; + int ret; + + spin_lock_irqsave(&nvt->tx.lock, flags); + + ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n); + nvt->tx.buf_count = (ret * sizeof(unsigned)); + + memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count); + + nvt->tx.cur_buf_num = 0; + + /* save currently enabled interrupts */ + iren = nvt_cir_reg_read(nvt, CIR_IREN); + + /* now disable all interrupts, save TFU & TTR */ + nvt_cir_reg_write(nvt, CIR_IREN_TFU | CIR_IREN_TTR, CIR_IREN); + + nvt->tx.tx_state = ST_TX_REPLY; + + nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV_8 | + CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); + + /* trigger TTR interrupt by writing out ones, (yes, it's ugly) */ + for (i = 0; i < 9; i++) + nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO); + + spin_unlock_irqrestore(&nvt->tx.lock, flags); + + wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST); + + spin_lock_irqsave(&nvt->tx.lock, flags); + nvt->tx.tx_state = ST_TX_NONE; + spin_unlock_irqrestore(&nvt->tx.lock, flags); + + /* restore enabled interrupts to prior state */ + nvt_cir_reg_write(nvt, iren, CIR_IREN); + + return ret; +} + +/* dump contents of the last rx buffer we got from the hw rx fifo */ +static void nvt_dump_rx_buf(struct nvt_dev *nvt) +{ + int i; + + printk(KERN_DEBUG "%s (len %d): ", __func__, nvt->pkts); + for (i = 0; (i < nvt->pkts) && (i < RX_BUF_LEN); i++) + printk(KERN_CONT "0x%02x ", nvt->buf[i]); + printk(KERN_CONT "\n"); +} + +/* + * Process raw data in rx driver buffer, store it in raw IR event kfifo, + * trigger decode when appropriate. + * + * We get IR data samples one byte at a time. If the msb is set, its a pulse, + * otherwise its a space. The lower 7 bits are the count of SAMPLE_PERIOD + * (default 50us) intervals for that pulse/space. A discrete signal is + * followed by a series of 0x7f packets, then either 0x7 or 0x80 + * to signal more IR coming (repeats) or end of IR, respectively. We store + * sample data in the raw event kfifo until we see 0x7 (except f) + * or 0x80, at which time, we trigger a decode operation. + */ +static void nvt_process_rx_ir_data(struct nvt_dev *nvt) +{ + DEFINE_IR_RAW_EVENT(rawir); + unsigned int count; + u32 carrier; + u8 sample; + int i; + + nvt_dbg_verbose("%s firing", __func__); + + if (debug) + nvt_dump_rx_buf(nvt); + + if (nvt->carrier_detect_enabled) + carrier = nvt_rx_carrier_detect(nvt); + + count = nvt->pkts; + nvt_dbg_verbose("Processing buffer of len %d", count); + + init_ir_raw_event(&rawir); + + for (i = 0; i < count; i++) { + nvt->pkts--; + sample = nvt->buf[i]; + + rawir.pulse = ((sample & BUF_PULSE_BIT) != 0); + rawir.duration = US_TO_NS((sample & BUF_LEN_MASK) + * SAMPLE_PERIOD); + + if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) { + if (nvt->rawir.pulse == rawir.pulse) + nvt->rawir.duration += rawir.duration; + else { + nvt->rawir.duration = rawir.duration; + nvt->rawir.pulse = rawir.pulse; + } + continue; + } + + rawir.duration += nvt->rawir.duration; + + init_ir_raw_event(&nvt->rawir); + nvt->rawir.duration = 0; + nvt->rawir.pulse = rawir.pulse; + + if (sample == BUF_PULSE_BIT) + rawir.pulse = false; + + if (rawir.duration) { + nvt_dbg("Storing %s with duration %d", + rawir.pulse ? "pulse" : "space", + rawir.duration); + + ir_raw_event_store_with_filter(nvt->rdev, &rawir); + } + + /* + * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE + * indicates end of IR signal, but new data incoming. In both + * cases, it means we're ready to call ir_raw_event_handle + */ + if ((sample == BUF_PULSE_BIT) && nvt->pkts) { + nvt_dbg("Calling ir_raw_event_handle (signal end)\n"); + ir_raw_event_handle(nvt->rdev); + } + } + + nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n"); + ir_raw_event_handle(nvt->rdev); + + if (nvt->pkts) { + nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts); + nvt->pkts = 0; + } + + nvt_dbg_verbose("%s done", __func__); +} + +static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt) +{ + nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!"); + + nvt->pkts = 0; + nvt_clear_cir_fifo(nvt); + ir_raw_event_reset(nvt->rdev); +} + +/* copy data from hardware rx fifo into driver buffer */ +static void nvt_get_rx_ir_data(struct nvt_dev *nvt) +{ + unsigned long flags; + u8 fifocount, val; + unsigned int b_idx; + bool overrun = false; + int i; + + /* Get count of how many bytes to read from RX FIFO */ + fifocount = nvt_cir_reg_read(nvt, CIR_RXFCONT); + /* if we get 0xff, probably means the logical dev is disabled */ + if (fifocount == 0xff) + return; + /* watch out for a fifo overrun condition */ + else if (fifocount > RX_BUF_LEN) { + overrun = true; + fifocount = RX_BUF_LEN; + } + + nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount); + + spin_lock_irqsave(&nvt->nvt_lock, flags); + + b_idx = nvt->pkts; + + /* This should never happen, but lets check anyway... */ + if (b_idx + fifocount > RX_BUF_LEN) { + nvt_process_rx_ir_data(nvt); + b_idx = 0; + } + + /* Read fifocount bytes from CIR Sample RX FIFO register */ + for (i = 0; i < fifocount; i++) { + val = nvt_cir_reg_read(nvt, CIR_SRXFIFO); + nvt->buf[b_idx + i] = val; + } + + nvt->pkts += fifocount; + nvt_dbg("%s: pkts now %d", __func__, nvt->pkts); + + nvt_process_rx_ir_data(nvt); + + if (overrun) + nvt_handle_rx_fifo_overrun(nvt); + + spin_unlock_irqrestore(&nvt->nvt_lock, flags); +} + +static void nvt_cir_log_irqs(u8 status, u8 iren) +{ + nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s", + status, iren, + status & CIR_IRSTS_RDR ? " RDR" : "", + status & CIR_IRSTS_RTR ? " RTR" : "", + status & CIR_IRSTS_PE ? " PE" : "", + status & CIR_IRSTS_RFO ? " RFO" : "", + status & CIR_IRSTS_TE ? " TE" : "", + status & CIR_IRSTS_TTR ? " TTR" : "", + status & CIR_IRSTS_TFU ? " TFU" : "", + status & CIR_IRSTS_GH ? " GH" : "", + status & ~(CIR_IRSTS_RDR | CIR_IRSTS_RTR | CIR_IRSTS_PE | + CIR_IRSTS_RFO | CIR_IRSTS_TE | CIR_IRSTS_TTR | + CIR_IRSTS_TFU | CIR_IRSTS_GH) ? " ?" : ""); +} + +static bool nvt_cir_tx_inactive(struct nvt_dev *nvt) +{ + unsigned long flags; + bool tx_inactive; + u8 tx_state; + + spin_lock_irqsave(&nvt->tx.lock, flags); + tx_state = nvt->tx.tx_state; + spin_unlock_irqrestore(&nvt->tx.lock, flags); + + tx_inactive = (tx_state == ST_TX_NONE); + + return tx_inactive; +} + +/* interrupt service routine for incoming and outgoing CIR data */ +static irqreturn_t nvt_cir_isr(int irq, void *data) +{ + struct nvt_dev *nvt = data; + u8 status, iren, cur_state; + unsigned long flags; + + nvt_dbg_verbose("%s firing", __func__); + + nvt_efm_enable(nvt); + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); + nvt_efm_disable(nvt); + + /* + * Get IR Status register contents. Write 1 to ack/clear + * + * bit: reg name - description + * 7: CIR_IRSTS_RDR - RX Data Ready + * 6: CIR_IRSTS_RTR - RX FIFO Trigger Level Reach + * 5: CIR_IRSTS_PE - Packet End + * 4: CIR_IRSTS_RFO - RX FIFO Overrun (RDR will also be set) + * 3: CIR_IRSTS_TE - TX FIFO Empty + * 2: CIR_IRSTS_TTR - TX FIFO Trigger Level Reach + * 1: CIR_IRSTS_TFU - TX FIFO Underrun + * 0: CIR_IRSTS_GH - Min Length Detected + */ + status = nvt_cir_reg_read(nvt, CIR_IRSTS); + if (!status) { + nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__); + nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); + return IRQ_RETVAL(IRQ_NONE); + } + + /* ack/clear all irq flags we've got */ + nvt_cir_reg_write(nvt, status, CIR_IRSTS); + nvt_cir_reg_write(nvt, 0, CIR_IRSTS); + + /* Interrupt may be shared with CIR Wake, bail if CIR not enabled */ + iren = nvt_cir_reg_read(nvt, CIR_IREN); + if (!iren) { + nvt_dbg_verbose("%s exiting, CIR not enabled", __func__); + return IRQ_RETVAL(IRQ_NONE); + } + + if (debug) + nvt_cir_log_irqs(status, iren); + + if (status & CIR_IRSTS_RTR) { + /* FIXME: add code for study/learn mode */ + /* We only do rx if not tx'ing */ + if (nvt_cir_tx_inactive(nvt)) + nvt_get_rx_ir_data(nvt); + } + + if (status & CIR_IRSTS_PE) { + if (nvt_cir_tx_inactive(nvt)) + nvt_get_rx_ir_data(nvt); + + spin_lock_irqsave(&nvt->nvt_lock, flags); + + cur_state = nvt->study_state; + + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + if (cur_state == ST_STUDY_NONE) + nvt_clear_cir_fifo(nvt); + } + + if (status & CIR_IRSTS_TE) + nvt_clear_tx_fifo(nvt); + + if (status & CIR_IRSTS_TTR) { + unsigned int pos, count; + u8 tmp; + + spin_lock_irqsave(&nvt->tx.lock, flags); + + pos = nvt->tx.cur_buf_num; + count = nvt->tx.buf_count; + + /* Write data into the hardware tx fifo while pos < count */ + if (pos < count) { + nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO); + nvt->tx.cur_buf_num++; + /* Disable TX FIFO Trigger Level Reach (TTR) interrupt */ + } else { + tmp = nvt_cir_reg_read(nvt, CIR_IREN); + nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN); + } + + spin_unlock_irqrestore(&nvt->tx.lock, flags); + + } + + if (status & CIR_IRSTS_TFU) { + spin_lock_irqsave(&nvt->tx.lock, flags); + if (nvt->tx.tx_state == ST_TX_REPLY) { + nvt->tx.tx_state = ST_TX_REQUEST; + wake_up(&nvt->tx.queue); + } + spin_unlock_irqrestore(&nvt->tx.lock, flags); + } + + nvt_dbg_verbose("%s done", __func__); + return IRQ_RETVAL(IRQ_HANDLED); +} + +/* Interrupt service routine for CIR Wake */ +static irqreturn_t nvt_cir_wake_isr(int irq, void *data) +{ + u8 status, iren, val; + struct nvt_dev *nvt = data; + unsigned long flags; + + nvt_dbg_wake("%s firing", __func__); + + status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS); + if (!status) + return IRQ_RETVAL(IRQ_NONE); + + if (status & CIR_WAKE_IRSTS_IR_PENDING) + nvt_clear_cir_wake_fifo(nvt); + + nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS); + nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS); + + /* Interrupt may be shared with CIR, bail if Wake not enabled */ + iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN); + if (!iren) { + nvt_dbg_wake("%s exiting, wake not enabled", __func__); + return IRQ_RETVAL(IRQ_HANDLED); + } + + if ((status & CIR_WAKE_IRSTS_PE) && + (nvt->wake_state == ST_WAKE_START)) { + while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) { + val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); + nvt_dbg("setting wake up key: 0x%x", val); + } + + nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); + spin_lock_irqsave(&nvt->nvt_lock, flags); + nvt->wake_state = ST_WAKE_FINISH; + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + } + + nvt_dbg_wake("%s done", __func__); + return IRQ_RETVAL(IRQ_HANDLED); +} + +static void nvt_enable_cir(struct nvt_dev *nvt) +{ + /* set function enable flags */ + nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | + CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, + CIR_IRCON); + + nvt_efm_enable(nvt); + + /* enable the CIR logical device */ + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); + nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); + + nvt_efm_disable(nvt); + + /* clear all pending interrupts */ + nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); + + /* enable interrupts */ + nvt_set_cir_iren(nvt); +} + +static void nvt_disable_cir(struct nvt_dev *nvt) +{ + /* disable CIR interrupts */ + nvt_cir_reg_write(nvt, 0, CIR_IREN); + + /* clear any and all pending interrupts */ + nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); + + /* clear all function enable flags */ + nvt_cir_reg_write(nvt, 0, CIR_IRCON); + + /* clear hardware rx and tx fifos */ + nvt_clear_cir_fifo(nvt); + nvt_clear_tx_fifo(nvt); + + nvt_efm_enable(nvt); + + /* disable the CIR logical device */ + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); + nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN); + + nvt_efm_disable(nvt); +} + +static int nvt_open(struct rc_dev *dev) +{ + struct nvt_dev *nvt = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&nvt->nvt_lock, flags); + nvt->in_use = true; + nvt_enable_cir(nvt); + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + return 0; +} + +static void nvt_close(struct rc_dev *dev) +{ + struct nvt_dev *nvt = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&nvt->nvt_lock, flags); + nvt->in_use = false; + nvt_disable_cir(nvt); + spin_unlock_irqrestore(&nvt->nvt_lock, flags); +} + +/* Allocate memory, probe hardware, and initialize everything */ +static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) +{ + struct nvt_dev *nvt; + struct rc_dev *rdev; + int ret = -ENOMEM; + + nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL); + if (!nvt) + return ret; + + /* input device for IR remote (and tx) */ + rdev = rc_allocate_device(); + if (!rdev) + goto failure; + + ret = -ENODEV; + /* validate pnp resources */ + if (!pnp_port_valid(pdev, 0) || + pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) { + dev_err(&pdev->dev, "IR PNP Port not valid!\n"); + goto failure; + } + + if (!pnp_irq_valid(pdev, 0)) { + dev_err(&pdev->dev, "PNP IRQ not valid!\n"); + goto failure; + } + + if (!pnp_port_valid(pdev, 1) || + pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) { + dev_err(&pdev->dev, "Wake PNP Port not valid!\n"); + goto failure; + } + + nvt->cir_addr = pnp_port_start(pdev, 0); + nvt->cir_irq = pnp_irq(pdev, 0); + + nvt->cir_wake_addr = pnp_port_start(pdev, 1); + /* irq is always shared between cir and cir wake */ + nvt->cir_wake_irq = nvt->cir_irq; + + nvt->cr_efir = CR_EFIR; + nvt->cr_efdr = CR_EFDR; + + spin_lock_init(&nvt->nvt_lock); + spin_lock_init(&nvt->tx.lock); + init_ir_raw_event(&nvt->rawir); + + ret = -EBUSY; + /* now claim resources */ + if (!request_region(nvt->cir_addr, + CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) + goto failure; + + if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED, + NVT_DRIVER_NAME, (void *)nvt)) + goto failure; + + if (!request_region(nvt->cir_wake_addr, + CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) + goto failure; + + if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED, + NVT_DRIVER_NAME, (void *)nvt)) + goto failure; + + pnp_set_drvdata(pdev, nvt); + nvt->pdev = pdev; + + init_waitqueue_head(&nvt->tx.queue); + + ret = nvt_hw_detect(nvt); + if (ret) + goto failure; + + /* Initialize CIR & CIR Wake Logical Devices */ + nvt_efm_enable(nvt); + nvt_cir_ldev_init(nvt); + nvt_cir_wake_ldev_init(nvt); + nvt_efm_disable(nvt); + + /* Initialize CIR & CIR Wake Config Registers */ + nvt_cir_regs_init(nvt); + nvt_cir_wake_regs_init(nvt); + + /* Set up the rc device */ + rdev->priv = nvt; + rdev->driver_type = RC_DRIVER_IR_RAW; + rdev->allowed_protos = RC_TYPE_ALL; + rdev->open = nvt_open; + rdev->close = nvt_close; + rdev->tx_ir = nvt_tx_ir; + rdev->s_tx_carrier = nvt_set_tx_carrier; + rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; + rdev->input_phys = "nuvoton/cir0"; + rdev->input_id.bustype = BUS_HOST; + rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2; + rdev->input_id.product = nvt->chip_major; + rdev->input_id.version = nvt->chip_minor; + rdev->dev.parent = &pdev->dev; + rdev->driver_name = NVT_DRIVER_NAME; + rdev->map_name = RC_MAP_RC6_MCE; + rdev->timeout = US_TO_NS(1000); + /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */ + rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD); +#if 0 + rdev->min_timeout = XYZ; + rdev->max_timeout = XYZ; + /* tx bits */ + rdev->tx_resolution = XYZ; +#endif + + ret = rc_register_device(rdev); + if (ret) + goto failure; + + device_init_wakeup(&pdev->dev, true); + nvt->rdev = rdev; + nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n"); + if (debug) { + cir_dump_regs(nvt); + cir_wake_dump_regs(nvt); + } + + return 0; + +failure: + if (nvt->cir_irq) + free_irq(nvt->cir_irq, nvt); + if (nvt->cir_addr) + release_region(nvt->cir_addr, CIR_IOREG_LENGTH); + + if (nvt->cir_wake_irq) + free_irq(nvt->cir_wake_irq, nvt); + if (nvt->cir_wake_addr) + release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); + + rc_free_device(rdev); + kfree(nvt); + + return ret; +} + +static void __devexit nvt_remove(struct pnp_dev *pdev) +{ + struct nvt_dev *nvt = pnp_get_drvdata(pdev); + unsigned long flags; + + spin_lock_irqsave(&nvt->nvt_lock, flags); + /* disable CIR */ + nvt_cir_reg_write(nvt, 0, CIR_IREN); + nvt_disable_cir(nvt); + /* enable CIR Wake (for IR power-on) */ + nvt_enable_wake(nvt); + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + /* free resources */ + free_irq(nvt->cir_irq, nvt); + free_irq(nvt->cir_wake_irq, nvt); + release_region(nvt->cir_addr, CIR_IOREG_LENGTH); + release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); + + rc_unregister_device(nvt->rdev); + + kfree(nvt); +} + +static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) +{ + struct nvt_dev *nvt = pnp_get_drvdata(pdev); + unsigned long flags; + + nvt_dbg("%s called", __func__); + + /* zero out misc state tracking */ + spin_lock_irqsave(&nvt->nvt_lock, flags); + nvt->study_state = ST_STUDY_NONE; + nvt->wake_state = ST_WAKE_NONE; + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + spin_lock_irqsave(&nvt->tx.lock, flags); + nvt->tx.tx_state = ST_TX_NONE; + spin_unlock_irqrestore(&nvt->tx.lock, flags); + + /* disable all CIR interrupts */ + nvt_cir_reg_write(nvt, 0, CIR_IREN); + + nvt_efm_enable(nvt); + + /* disable cir logical dev */ + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); + nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN); + + nvt_efm_disable(nvt); + + /* make sure wake is enabled */ + nvt_enable_wake(nvt); + + return 0; +} + +static int nvt_resume(struct pnp_dev *pdev) +{ + int ret = 0; + struct nvt_dev *nvt = pnp_get_drvdata(pdev); + + nvt_dbg("%s called", __func__); + + /* open interrupt */ + nvt_set_cir_iren(nvt); + + /* Enable CIR logical device */ + nvt_efm_enable(nvt); + nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); + nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); + + nvt_efm_disable(nvt); + + nvt_cir_regs_init(nvt); + nvt_cir_wake_regs_init(nvt); + + return ret; +} + +static void nvt_shutdown(struct pnp_dev *pdev) +{ + struct nvt_dev *nvt = pnp_get_drvdata(pdev); + nvt_enable_wake(nvt); +} + +static const struct pnp_device_id nvt_ids[] = { + { "WEC0530", 0 }, /* CIR */ + { "NTN0530", 0 }, /* CIR for new chip's pnp id*/ + { "", 0 }, +}; + +static struct pnp_driver nvt_driver = { + .name = NVT_DRIVER_NAME, + .id_table = nvt_ids, + .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, + .probe = nvt_probe, + .remove = __devexit_p(nvt_remove), + .suspend = nvt_suspend, + .resume = nvt_resume, + .shutdown = nvt_shutdown, +}; + +int nvt_init(void) +{ + return pnp_register_driver(&nvt_driver); +} + +void nvt_exit(void) +{ + pnp_unregister_driver(&nvt_driver); +} + +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging output"); + +MODULE_DEVICE_TABLE(pnp, nvt_ids); +MODULE_DESCRIPTION("Nuvoton W83667HG-A & W83677HG-I CIR driver"); + +MODULE_AUTHOR("Jarod Wilson "); +MODULE_LICENSE("GPL"); + +module_init(nvt_init); +module_exit(nvt_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/nuvoton-cir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/nuvoton-cir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/nuvoton-cir.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/nuvoton-cir.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,421 @@ +/* + * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR + * + * Copyright (C) 2010 Jarod Wilson + * Copyright (C) 2009 Nuvoton PS Team + * + * Special thanks to Nuvoton for providing hardware, spec sheets and + * sample code upon which portions of this driver are based. Indirect + * thanks also to Maxim Levitsky, whose ene_ir driver this driver is + * modeled after. + * + * 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, or (at your option) any later version. + * + * 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 +#include + +/* platform driver name to register */ +#define NVT_DRIVER_NAME "nuvoton-cir" + +/* debugging module parameter */ +static int debug; + + +#define nvt_pr(level, text, ...) \ + printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) + +#define nvt_dbg(text, ...) \ + if (debug) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) + +#define nvt_dbg_verbose(text, ...) \ + if (debug > 1) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) + +#define nvt_dbg_wake(text, ...) \ + if (debug > 2) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) + + +/* + * Original lirc driver said min value of 76, and recommended value of 256 + * for the buffer length, but then used 2048. Never mind that the size of the + * RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm + * not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes), + * and I don't have TX-capable hardware to test/debug on... + */ +#define TX_BUF_LEN 256 +#define RX_BUF_LEN 32 + +struct nvt_dev { + struct pnp_dev *pdev; + struct rc_dev *rdev; + struct ir_raw_event rawir; + + spinlock_t nvt_lock; + bool in_use; + + /* for rx */ + u8 buf[RX_BUF_LEN]; + unsigned int pkts; + + struct { + spinlock_t lock; + u8 buf[TX_BUF_LEN]; + unsigned int buf_count; + unsigned int cur_buf_num; + wait_queue_head_t queue; + u8 tx_state; + } tx; + + /* EFER Config register index/data pair */ + u8 cr_efir; + u8 cr_efdr; + + /* hardware I/O settings */ + unsigned long cir_addr; + unsigned long cir_wake_addr; + int cir_irq; + int cir_wake_irq; + + /* hardware id */ + u8 chip_major; + u8 chip_minor; + + /* hardware features */ + bool hw_learning_capable; + bool hw_tx_capable; + + /* rx settings */ + bool learning_enabled; + bool carrier_detect_enabled; + + /* track cir wake state */ + u8 wake_state; + /* for study */ + u8 study_state; + /* carrier period = 1 / frequency */ + u32 carrier; +}; + +/* study states */ +#define ST_STUDY_NONE 0x0 +#define ST_STUDY_START 0x1 +#define ST_STUDY_CARRIER 0x2 +#define ST_STUDY_ALL_RECV 0x4 + +/* wake states */ +#define ST_WAKE_NONE 0x0 +#define ST_WAKE_START 0x1 +#define ST_WAKE_FINISH 0x2 + +/* receive states */ +#define ST_RX_WAIT_7F 0x1 +#define ST_RX_WAIT_HEAD 0x2 +#define ST_RX_WAIT_SILENT_END 0x4 + +/* send states */ +#define ST_TX_NONE 0x0 +#define ST_TX_REQUEST 0x2 +#define ST_TX_REPLY 0x4 + +/* buffer packet constants */ +#define BUF_PULSE_BIT 0x80 +#define BUF_LEN_MASK 0x7f +#define BUF_REPEAT_BYTE 0x70 +#define BUF_REPEAT_MASK 0xf0 + +/* CIR settings */ + +/* total length of CIR and CIR WAKE */ +#define CIR_IOREG_LENGTH 0x0f + +/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL (0x7d0 = 2000) */ +#define CIR_RX_LIMIT_COUNT 0x7d0 + +/* CIR Regs */ +#define CIR_IRCON 0x00 +#define CIR_IRSTS 0x01 +#define CIR_IREN 0x02 +#define CIR_RXFCONT 0x03 +#define CIR_CP 0x04 +#define CIR_CC 0x05 +#define CIR_SLCH 0x06 +#define CIR_SLCL 0x07 +#define CIR_FIFOCON 0x08 +#define CIR_IRFIFOSTS 0x09 +#define CIR_SRXFIFO 0x0a +#define CIR_TXFCONT 0x0b +#define CIR_STXFIFO 0x0c +#define CIR_FCCH 0x0d +#define CIR_FCCL 0x0e +#define CIR_IRFSM 0x0f + +/* CIR IRCON settings */ +#define CIR_IRCON_RECV 0x80 +#define CIR_IRCON_WIREN 0x40 +#define CIR_IRCON_TXEN 0x20 +#define CIR_IRCON_RXEN 0x10 +#define CIR_IRCON_WRXINV 0x08 +#define CIR_IRCON_RXINV 0x04 + +#define CIR_IRCON_SAMPLE_PERIOD_SEL_1 0x00 +#define CIR_IRCON_SAMPLE_PERIOD_SEL_25 0x01 +#define CIR_IRCON_SAMPLE_PERIOD_SEL_50 0x02 +#define CIR_IRCON_SAMPLE_PERIOD_SEL_100 0x03 + +/* FIXME: make this a runtime option */ +/* select sample period as 50us */ +#define CIR_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50 + +/* CIR IRSTS settings */ +#define CIR_IRSTS_RDR 0x80 +#define CIR_IRSTS_RTR 0x40 +#define CIR_IRSTS_PE 0x20 +#define CIR_IRSTS_RFO 0x10 +#define CIR_IRSTS_TE 0x08 +#define CIR_IRSTS_TTR 0x04 +#define CIR_IRSTS_TFU 0x02 +#define CIR_IRSTS_GH 0x01 + +/* CIR IREN settings */ +#define CIR_IREN_RDR 0x80 +#define CIR_IREN_RTR 0x40 +#define CIR_IREN_PE 0x20 +#define CIR_IREN_RFO 0x10 +#define CIR_IREN_TE 0x08 +#define CIR_IREN_TTR 0x04 +#define CIR_IREN_TFU 0x02 +#define CIR_IREN_GH 0x01 + +/* CIR FIFOCON settings */ +#define CIR_FIFOCON_TXFIFOCLR 0x80 + +#define CIR_FIFOCON_TX_TRIGGER_LEV_31 0x00 +#define CIR_FIFOCON_TX_TRIGGER_LEV_24 0x10 +#define CIR_FIFOCON_TX_TRIGGER_LEV_16 0x20 +#define CIR_FIFOCON_TX_TRIGGER_LEV_8 0x30 + +/* FIXME: make this a runtime option */ +/* select TX trigger level as 16 */ +#define CIR_FIFOCON_TX_TRIGGER_LEV CIR_FIFOCON_TX_TRIGGER_LEV_16 + +#define CIR_FIFOCON_RXFIFOCLR 0x08 + +#define CIR_FIFOCON_RX_TRIGGER_LEV_1 0x00 +#define CIR_FIFOCON_RX_TRIGGER_LEV_8 0x01 +#define CIR_FIFOCON_RX_TRIGGER_LEV_16 0x02 +#define CIR_FIFOCON_RX_TRIGGER_LEV_24 0x03 + +/* FIXME: make this a runtime option */ +/* select RX trigger level as 24 */ +#define CIR_FIFOCON_RX_TRIGGER_LEV CIR_FIFOCON_RX_TRIGGER_LEV_24 + +/* CIR IRFIFOSTS settings */ +#define CIR_IRFIFOSTS_IR_PENDING 0x80 +#define CIR_IRFIFOSTS_RX_GS 0x40 +#define CIR_IRFIFOSTS_RX_FTA 0x20 +#define CIR_IRFIFOSTS_RX_EMPTY 0x10 +#define CIR_IRFIFOSTS_RX_FULL 0x08 +#define CIR_IRFIFOSTS_TX_FTA 0x04 +#define CIR_IRFIFOSTS_TX_EMPTY 0x02 +#define CIR_IRFIFOSTS_TX_FULL 0x01 + + +/* CIR WAKE UP Regs */ +#define CIR_WAKE_IRCON 0x00 +#define CIR_WAKE_IRSTS 0x01 +#define CIR_WAKE_IREN 0x02 +#define CIR_WAKE_FIFO_CMP_DEEP 0x03 +#define CIR_WAKE_FIFO_CMP_TOL 0x04 +#define CIR_WAKE_FIFO_COUNT 0x05 +#define CIR_WAKE_SLCH 0x06 +#define CIR_WAKE_SLCL 0x07 +#define CIR_WAKE_FIFOCON 0x08 +#define CIR_WAKE_SRXFSTS 0x09 +#define CIR_WAKE_SAMPLE_RX_FIFO 0x0a +#define CIR_WAKE_WR_FIFO_DATA 0x0b +#define CIR_WAKE_RD_FIFO_ONLY 0x0c +#define CIR_WAKE_RD_FIFO_ONLY_IDX 0x0d +#define CIR_WAKE_FIFO_IGNORE 0x0e +#define CIR_WAKE_IRFSM 0x0f + +/* CIR WAKE UP IRCON settings */ +#define CIR_WAKE_IRCON_DEC_RST 0x80 +#define CIR_WAKE_IRCON_MODE1 0x40 +#define CIR_WAKE_IRCON_MODE0 0x20 +#define CIR_WAKE_IRCON_RXEN 0x10 +#define CIR_WAKE_IRCON_R 0x08 +#define CIR_WAKE_IRCON_RXINV 0x04 + +/* FIXME/jarod: make this a runtime option */ +/* select a same sample period like cir register */ +#define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50 + +/* CIR WAKE IRSTS Bits */ +#define CIR_WAKE_IRSTS_RDR 0x80 +#define CIR_WAKE_IRSTS_RTR 0x40 +#define CIR_WAKE_IRSTS_PE 0x20 +#define CIR_WAKE_IRSTS_RFO 0x10 +#define CIR_WAKE_IRSTS_GH 0x08 +#define CIR_WAKE_IRSTS_IR_PENDING 0x01 + +/* CIR WAKE UP IREN Bits */ +#define CIR_WAKE_IREN_RDR 0x80 +#define CIR_WAKE_IREN_RTR 0x40 +#define CIR_WAKE_IREN_PE 0x20 +#define CIR_WAKE_IREN_RFO 0x10 +#define CIR_WAKE_IREN_TE 0x08 +#define CIR_WAKE_IREN_TTR 0x04 +#define CIR_WAKE_IREN_TFU 0x02 +#define CIR_WAKE_IREN_GH 0x01 + +/* CIR WAKE FIFOCON settings */ +#define CIR_WAKE_FIFOCON_RXFIFOCLR 0x08 + +#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 0x00 +#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_66 0x01 +#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_65 0x02 +#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_64 0x03 + +/* FIXME: make this a runtime option */ +/* select WAKE UP RX trigger level as 67 */ +#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 + +/* CIR WAKE SRXFSTS settings */ +#define CIR_WAKE_IRFIFOSTS_RX_GS 0x80 +#define CIR_WAKE_IRFIFOSTS_RX_FTA 0x40 +#define CIR_WAKE_IRFIFOSTS_RX_EMPTY 0x20 +#define CIR_WAKE_IRFIFOSTS_RX_FULL 0x10 + +/* + * The CIR Wake FIFO buffer is 67 bytes long, but the stock remote wakes + * the system comparing only 65 bytes (fails with this set to 67) + */ +#define CIR_WAKE_FIFO_CMP_BYTES 65 +/* CIR Wake byte comparison tolerance */ +#define CIR_WAKE_CMP_TOLERANCE 5 + +/* + * Extended Function Enable Registers: + * Extended Function Index Register + * Extended Function Data Register + */ +#define CR_EFIR 0x2e +#define CR_EFDR 0x2f + +/* Possible alternate EFER values, depends on how the chip is wired */ +#define CR_EFIR2 0x4e +#define CR_EFDR2 0x4f + +/* Extended Function Mode enable/disable magic values */ +#define EFER_EFM_ENABLE 0x87 +#define EFER_EFM_DISABLE 0xaa + +/* Chip IDs found in CR_CHIP_ID_{HI,LO} */ +#define CHIP_ID_HIGH_667 0xa5 +#define CHIP_ID_HIGH_677B 0xb4 +#define CHIP_ID_HIGH_677C 0xc3 +#define CHIP_ID_LOW_667 0x13 +#define CHIP_ID_LOW_677B2 0x72 +#define CHIP_ID_LOW_677B3 0x73 +#define CHIP_ID_LOW_677C 0x33 + +/* Config regs we need to care about */ +#define CR_SOFTWARE_RESET 0x02 +#define CR_LOGICAL_DEV_SEL 0x07 +#define CR_CHIP_ID_HI 0x20 +#define CR_CHIP_ID_LO 0x21 +#define CR_DEV_POWER_DOWN 0x22 /* bit 2 is CIR power, default power on */ +#define CR_OUTPUT_PIN_SEL 0x27 +#define CR_MULTIFUNC_PIN_SEL 0x2c +#define CR_LOGICAL_DEV_EN 0x30 /* valid for all logical devices */ +/* next three regs valid for both the CIR and CIR_WAKE logical devices */ +#define CR_CIR_BASE_ADDR_HI 0x60 +#define CR_CIR_BASE_ADDR_LO 0x61 +#define CR_CIR_IRQ_RSRC 0x70 +/* next three regs valid only for ACPI logical dev */ +#define CR_ACPI_CIR_WAKE 0xe0 +#define CR_ACPI_IRQ_EVENTS 0xf6 +#define CR_ACPI_IRQ_EVENTS2 0xf7 + +/* Logical devices that we need to care about */ +#define LOGICAL_DEV_LPT 0x01 +#define LOGICAL_DEV_CIR 0x06 +#define LOGICAL_DEV_ACPI 0x0a +#define LOGICAL_DEV_CIR_WAKE 0x0e + +#define LOGICAL_DEV_DISABLE 0x00 +#define LOGICAL_DEV_ENABLE 0x01 + +#define CIR_WAKE_ENABLE_BIT 0x08 +#define CIR_INTR_MOUSE_IRQ_BIT 0x80 +#define PME_INTR_CIR_PASS_BIT 0x08 + +/* w83677hg CIR pin config */ +#define OUTPUT_PIN_SEL_MASK 0xbc +#define OUTPUT_ENABLE_CIR 0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */ +#define OUTPUT_ENABLE_CIRWB 0x40 /* enable wide-band sensor */ + +/* w83667hg CIR pin config */ +#define MULTIFUNC_PIN_SEL_MASK 0x1f +#define MULTIFUNC_ENABLE_CIR 0x80 /* Pin75=CIRRX, Pin76=CIRTX1 */ +#define MULTIFUNC_ENABLE_CIRWB 0x20 /* enable wide-band sensor */ + +/* MCE CIR signal length, related on sample period */ + +/* MCE CIR controller signal length: about 43ms + * 43ms / 50us (sample period) * 0.85 (inaccuracy) + */ +#define CONTROLLER_BUF_LEN_MIN 830 + +/* MCE CIR keyboard signal length: about 26ms + * 26ms / 50us (sample period) * 0.85 (inaccuracy) + */ +#define KEYBOARD_BUF_LEN_MAX 650 +#define KEYBOARD_BUF_LEN_MIN 610 + +/* MCE CIR mouse signal length: about 24ms + * 24ms / 50us (sample period) * 0.85 (inaccuracy) + */ +#define MOUSE_BUF_LEN_MIN 565 + +#define CIR_SAMPLE_PERIOD 50 +#define CIR_SAMPLE_LOW_INACCURACY 0.85 + +/* MAX silence time that driver will sent to lirc */ +#define MAX_SILENCE_TIME 60000 + +#if CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_100 +#define SAMPLE_PERIOD 100 + +#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_50 +#define SAMPLE_PERIOD 50 + +#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_25 +#define SAMPLE_PERIOD 25 + +#else +#define SAMPLE_PERIOD 1 +#endif + +/* as VISTA MCE definition, valid carrier value */ +#define MAX_CARRIER 60000 +#define MIN_CARRIER 30000 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-core-priv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-core-priv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-core-priv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-core-priv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,193 @@ +/* + * Remote Controller core raw events header + * + * Copyright (C) 2010 by Mauro Carvalho Chehab + * + * 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 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. + */ + +#ifndef _RC_CORE_PRIV +#define _RC_CORE_PRIV + +#include +#include +#include + +struct ir_raw_handler { + struct list_head list; + + u64 protocols; /* which are handled by this handler */ + int (*decode)(struct rc_dev *dev, struct ir_raw_event event); + + /* These two should only be used by the lirc decoder */ + int (*raw_register)(struct rc_dev *dev); + int (*raw_unregister)(struct rc_dev *dev); +}; + +struct ir_raw_event_ctrl { + struct list_head list; /* to keep track of raw clients */ + struct task_struct *thread; + spinlock_t lock; + struct kfifo kfifo; /* fifo for the pulse/space durations */ + ktime_t last_event; /* when last event occurred */ + enum raw_event_type last_type; /* last event type */ + struct rc_dev *dev; /* pointer to the parent rc_dev */ + u64 enabled_protocols; /* enabled raw protocol decoders */ + + /* raw decoder state follows */ + struct ir_raw_event prev_ev; + struct ir_raw_event this_ev; + struct nec_dec { + int state; + unsigned count; + u32 bits; + bool is_nec_x; + bool necx_repeat; + } nec; + struct rc5_dec { + int state; + u32 bits; + unsigned count; + unsigned wanted_bits; + } rc5; + struct rc6_dec { + int state; + u8 header; + u32 body; + bool toggle; + unsigned count; + unsigned wanted_bits; + } rc6; + struct sony_dec { + int state; + u32 bits; + unsigned count; + } sony; + struct jvc_dec { + int state; + u16 bits; + u16 old_bits; + unsigned count; + bool first; + bool toggle; + } jvc; + struct rc5_sz_dec { + int state; + u32 bits; + unsigned count; + unsigned wanted_bits; + } rc5_sz; + struct lirc_codec { + struct rc_dev *dev; + struct lirc_driver *drv; + int carrier_low; + + ktime_t gap_start; + u64 gap_duration; + bool gap; + bool send_timeout_reports; + + } lirc; +}; + +/* macros for IR decoders */ +static inline bool geq_margin(unsigned d1, unsigned d2, unsigned margin) +{ + return d1 > (d2 - margin); +} + +static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin) +{ + return ((d1 > (d2 - margin)) && (d1 < (d2 + margin))); +} + +static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y) +{ + return x->pulse != y->pulse; +} + +static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration) +{ + if (duration > ev->duration) + ev->duration = 0; + else + ev->duration -= duration; +} + +/* Returns true if event is normal pulse/space event */ +static inline bool is_timing_event(struct ir_raw_event ev) +{ + return !ev.carrier_report && !ev.reset; +} + +#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000) +#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space") + +/* + * Routines from rc-raw.c to be used internally and by decoders + */ +u64 ir_raw_get_allowed_protocols(void); +int ir_raw_event_register(struct rc_dev *dev); +void ir_raw_event_unregister(struct rc_dev *dev); +int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); +void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler); +void ir_raw_init(void); + +/* + * Decoder initialization code + * + * Those load logic are called during ir-core init, and automatically + * loads the compiled decoders for their usage with IR raw events + */ + +/* from ir-nec-decoder.c */ +#ifdef CONFIG_IR_NEC_DECODER_MODULE +#define load_nec_decode() request_module("ir-nec-decoder") +#else +#define load_nec_decode() 0 +#endif + +/* from ir-rc5-decoder.c */ +#ifdef CONFIG_IR_RC5_DECODER_MODULE +#define load_rc5_decode() request_module("ir-rc5-decoder") +#else +#define load_rc5_decode() 0 +#endif + +/* from ir-rc6-decoder.c */ +#ifdef CONFIG_IR_RC6_DECODER_MODULE +#define load_rc6_decode() request_module("ir-rc6-decoder") +#else +#define load_rc6_decode() 0 +#endif + +/* from ir-jvc-decoder.c */ +#ifdef CONFIG_IR_JVC_DECODER_MODULE +#define load_jvc_decode() request_module("ir-jvc-decoder") +#else +#define load_jvc_decode() 0 +#endif + +/* from ir-sony-decoder.c */ +#ifdef CONFIG_IR_SONY_DECODER_MODULE +#define load_sony_decode() request_module("ir-sony-decoder") +#else +#define load_sony_decode() 0 +#endif + +/* from ir-lirc-codec.c */ +#ifdef CONFIG_IR_LIRC_CODEC_MODULE +#define load_lirc_codec() request_module("ir-lirc-codec") +#else +#define load_lirc_codec() 0 +#endif + + +#endif /* _RC_CORE_PRIV */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-loopback.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-loopback.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-loopback.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-loopback.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,259 @@ +/* + * Loopback driver for rc-core, + * + * Copyright (c) 2010 David Härdeman + * + * This driver receives TX data and passes it back as RX data, + * which is useful for (scripted) debugging of rc-core without + * having to use actual hardware. + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include + +#define DRIVER_NAME "rc-loopback" +#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x) +#define RXMASK_REGULAR 0x1 +#define RXMASK_LEARNING 0x2 + +static bool debug; + +struct loopback_dev { + struct rc_dev *dev; + u32 txmask; + u32 txcarrier; + u32 txduty; + bool idle; + bool learning; + bool carrierreport; + u32 rxcarriermin; + u32 rxcarriermax; +}; + +static struct loopback_dev loopdev; + +static int loop_set_tx_mask(struct rc_dev *dev, u32 mask) +{ + struct loopback_dev *lodev = dev->priv; + + if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) { + dprintk("invalid tx mask: %u\n", mask); + return -EINVAL; + } + + dprintk("setting tx mask: %u\n", mask); + lodev->txmask = mask; + return 0; +} + +static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + struct loopback_dev *lodev = dev->priv; + + dprintk("setting tx carrier: %u\n", carrier); + lodev->txcarrier = carrier; + return 0; +} + +static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle) +{ + struct loopback_dev *lodev = dev->priv; + + if (duty_cycle < 1 || duty_cycle > 99) { + dprintk("invalid duty cycle: %u\n", duty_cycle); + return -EINVAL; + } + + dprintk("setting duty cycle: %u\n", duty_cycle); + lodev->txduty = duty_cycle; + return 0; +} + +static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max) +{ + struct loopback_dev *lodev = dev->priv; + + if (min < 1 || min > max) { + dprintk("invalid rx carrier range %u to %u\n", min, max); + return -EINVAL; + } + + dprintk("setting rx carrier range %u to %u\n", min, max); + lodev->rxcarriermin = min; + lodev->rxcarriermax = max; + return 0; +} + +static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) +{ + struct loopback_dev *lodev = dev->priv; + u32 rxmask; + unsigned total_duration = 0; + unsigned i; + DEFINE_IR_RAW_EVENT(rawir); + + for (i = 0; i < count; i++) + total_duration += abs(txbuf[i]); + + if (total_duration == 0) { + dprintk("invalid tx data, total duration zero\n"); + return -EINVAL; + } + + if (lodev->txcarrier < lodev->rxcarriermin || + lodev->txcarrier > lodev->rxcarriermax) { + dprintk("ignoring tx, carrier out of range\n"); + goto out; + } + + if (lodev->learning) + rxmask = RXMASK_LEARNING; + else + rxmask = RXMASK_REGULAR; + + if (!(rxmask & lodev->txmask)) { + dprintk("ignoring tx, rx mask mismatch\n"); + goto out; + } + + for (i = 0; i < count; i++) { + rawir.pulse = i % 2 ? false : true; + rawir.duration = txbuf[i] * 1000; + if (rawir.duration) + ir_raw_event_store_with_filter(dev, &rawir); + } + + /* Fake a silence long enough to cause us to go idle */ + rawir.pulse = false; + rawir.duration = dev->timeout; + ir_raw_event_store_with_filter(dev, &rawir); + + ir_raw_event_handle(dev); + +out: + /* Lirc expects this function to take as long as the total duration */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(total_duration)); + return count; +} + +static void loop_set_idle(struct rc_dev *dev, bool enable) +{ + struct loopback_dev *lodev = dev->priv; + + if (lodev->idle != enable) { + dprintk("%sing idle mode\n", enable ? "enter" : "exit"); + lodev->idle = enable; + } +} + +static int loop_set_learning_mode(struct rc_dev *dev, int enable) +{ + struct loopback_dev *lodev = dev->priv; + + if (lodev->learning != enable) { + dprintk("%sing learning mode\n", enable ? "enter" : "exit"); + lodev->learning = !!enable; + } + + return 0; +} + +static int loop_set_carrier_report(struct rc_dev *dev, int enable) +{ + struct loopback_dev *lodev = dev->priv; + + if (lodev->carrierreport != enable) { + dprintk("%sabling carrier reports\n", enable ? "en" : "dis"); + lodev->carrierreport = !!enable; + } + + return 0; +} + +static int __init loop_init(void) +{ + struct rc_dev *rc; + int ret; + + rc = rc_allocate_device(); + if (!rc) { + printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n"); + return -ENOMEM; + } + + rc->input_name = "rc-core loopback device"; + rc->input_phys = "rc-core/virtual"; + rc->input_id.bustype = BUS_VIRTUAL; + rc->input_id.version = 1; + rc->driver_name = DRIVER_NAME; + rc->map_name = RC_MAP_EMPTY; + rc->priv = &loopdev; + rc->driver_type = RC_DRIVER_IR_RAW; + rc->allowed_protos = RC_TYPE_ALL; + rc->timeout = 100 * 1000 * 1000; /* 100 ms */ + rc->min_timeout = 1; + rc->max_timeout = UINT_MAX; + rc->rx_resolution = 1000; + rc->tx_resolution = 1000; + rc->s_tx_mask = loop_set_tx_mask; + rc->s_tx_carrier = loop_set_tx_carrier; + rc->s_tx_duty_cycle = loop_set_tx_duty_cycle; + rc->s_rx_carrier_range = loop_set_rx_carrier_range; + rc->tx_ir = loop_tx_ir; + rc->s_idle = loop_set_idle; + rc->s_learning_mode = loop_set_learning_mode; + rc->s_carrier_report = loop_set_carrier_report; + rc->priv = &loopdev; + + loopdev.txmask = RXMASK_REGULAR; + loopdev.txcarrier = 36000; + loopdev.txduty = 50; + loopdev.rxcarriermin = 1; + loopdev.rxcarriermax = ~0; + loopdev.idle = true; + loopdev.learning = false; + loopdev.carrierreport = false; + + ret = rc_register_device(rc); + if (ret < 0) { + printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n"); + rc_free_device(rc); + return ret; + } + + loopdev.dev = rc; + return 0; +} + +static void __exit loop_exit(void) +{ + rc_unregister_device(loopdev.dev); +} + +module_init(loop_init); +module_exit(loop_exit); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debug messages"); + +MODULE_DESCRIPTION("Loopback device for rc-core debugging"); +MODULE_AUTHOR("David Härdeman "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-main.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-main.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-main.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/rc-main.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1186 @@ +/* rc-main.c - Remote Controller core module + * + * Copyright (C) 2009-2010 by Mauro Carvalho Chehab + * + * 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 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. + */ + +#include +#include +#include +#include +#include +#include +#include "rc-core-priv.h" + +/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ +#define IR_TAB_MIN_SIZE 256 +#define IR_TAB_MAX_SIZE 8192 + +/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */ +#define IR_KEYPRESS_TIMEOUT 250 + +/* Used to keep track of known keymaps */ +static LIST_HEAD(rc_map_list); +static DEFINE_SPINLOCK(rc_map_lock); + +static struct rc_map_list *seek_rc_map(const char *name) +{ + struct rc_map_list *map = NULL; + + spin_lock(&rc_map_lock); + list_for_each_entry(map, &rc_map_list, list) { + if (!strcmp(name, map->map.name)) { + spin_unlock(&rc_map_lock); + return map; + } + } + spin_unlock(&rc_map_lock); + + return NULL; +} + +struct rc_map *rc_map_get(const char *name) +{ + + struct rc_map_list *map; + + map = seek_rc_map(name); +#ifdef MODULE + if (!map) { + int rc = request_module(name); + if (rc < 0) { + printk(KERN_ERR "Couldn't load IR keymap %s\n", name); + return NULL; + } + msleep(20); /* Give some time for IR to register */ + + map = seek_rc_map(name); + } +#endif + if (!map) { + printk(KERN_ERR "IR keymap %s not found\n", name); + return NULL; + } + + printk(KERN_INFO "Registered IR keymap %s\n", map->map.name); + + return &map->map; +} +EXPORT_SYMBOL_GPL(rc_map_get); + +int rc_map_register(struct rc_map_list *map) +{ + spin_lock(&rc_map_lock); + list_add_tail(&map->list, &rc_map_list); + spin_unlock(&rc_map_lock); + return 0; +} +EXPORT_SYMBOL_GPL(rc_map_register); + +void rc_map_unregister(struct rc_map_list *map) +{ + spin_lock(&rc_map_lock); + list_del(&map->list); + spin_unlock(&rc_map_lock); +} +EXPORT_SYMBOL_GPL(rc_map_unregister); + + +static struct rc_map_table empty[] = { + { 0x2a, KEY_COFFEE }, +}; + +static struct rc_map_list empty_map = { + .map = { + .scan = empty, + .size = ARRAY_SIZE(empty), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_EMPTY, + } +}; + +/** + * ir_create_table() - initializes a scancode table + * @rc_map: the rc_map to initialize + * @name: name to assign to the table + * @rc_type: ir type to assign to the new table + * @size: initial size of the table + * @return: zero on success or a negative error code + * + * This routine will initialize the rc_map and will allocate + * memory to hold at least the specified number of elements. + */ +static int ir_create_table(struct rc_map *rc_map, + const char *name, u64 rc_type, size_t size) +{ + rc_map->name = name; + rc_map->rc_type = rc_type; + rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table)); + rc_map->size = rc_map->alloc / sizeof(struct rc_map_table); + rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL); + if (!rc_map->scan) + return -ENOMEM; + + IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n", + rc_map->size, rc_map->alloc); + return 0; +} + +/** + * ir_free_table() - frees memory allocated by a scancode table + * @rc_map: the table whose mappings need to be freed + * + * This routine will free memory alloctaed for key mappings used by given + * scancode table. + */ +static void ir_free_table(struct rc_map *rc_map) +{ + rc_map->size = 0; + kfree(rc_map->scan); + rc_map->scan = NULL; +} + +/** + * ir_resize_table() - resizes a scancode table if necessary + * @rc_map: the rc_map to resize + * @gfp_flags: gfp flags to use when allocating memory + * @return: zero on success or a negative error code + * + * This routine will shrink the rc_map if it has lots of + * unused entries and grow it if it is full. + */ +static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags) +{ + unsigned int oldalloc = rc_map->alloc; + unsigned int newalloc = oldalloc; + struct rc_map_table *oldscan = rc_map->scan; + struct rc_map_table *newscan; + + if (rc_map->size == rc_map->len) { + /* All entries in use -> grow keytable */ + if (rc_map->alloc >= IR_TAB_MAX_SIZE) + return -ENOMEM; + + newalloc *= 2; + IR_dprintk(1, "Growing table to %u bytes\n", newalloc); + } + + if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) { + /* Less than 1/3 of entries in use -> shrink keytable */ + newalloc /= 2; + IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc); + } + + if (newalloc == oldalloc) + return 0; + + newscan = kmalloc(newalloc, gfp_flags); + if (!newscan) { + IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc); + return -ENOMEM; + } + + memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table)); + rc_map->scan = newscan; + rc_map->alloc = newalloc; + rc_map->size = rc_map->alloc / sizeof(struct rc_map_table); + kfree(oldscan); + return 0; +} + +/** + * ir_update_mapping() - set a keycode in the scancode->keycode table + * @dev: the struct rc_dev device descriptor + * @rc_map: scancode table to be adjusted + * @index: index of the mapping that needs to be updated + * @keycode: the desired keycode + * @return: previous keycode assigned to the mapping + * + * This routine is used to update scancode->keycode mapping at given + * position. + */ +static unsigned int ir_update_mapping(struct rc_dev *dev, + struct rc_map *rc_map, + unsigned int index, + unsigned int new_keycode) +{ + int old_keycode = rc_map->scan[index].keycode; + int i; + + /* Did the user wish to remove the mapping? */ + if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) { + IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", + index, rc_map->scan[index].scancode); + rc_map->len--; + memmove(&rc_map->scan[index], &rc_map->scan[index+ 1], + (rc_map->len - index) * sizeof(struct rc_map_table)); + } else { + IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n", + index, + old_keycode == KEY_RESERVED ? "New" : "Replacing", + rc_map->scan[index].scancode, new_keycode); + rc_map->scan[index].keycode = new_keycode; + __set_bit(new_keycode, dev->input_dev->keybit); + } + + if (old_keycode != KEY_RESERVED) { + /* A previous mapping was updated... */ + __clear_bit(old_keycode, dev->input_dev->keybit); + /* ... but another scancode might use the same keycode */ + for (i = 0; i < rc_map->len; i++) { + if (rc_map->scan[i].keycode == old_keycode) { + __set_bit(old_keycode, dev->input_dev->keybit); + break; + } + } + + /* Possibly shrink the keytable, failure is not a problem */ + ir_resize_table(rc_map, GFP_ATOMIC); + } + + return old_keycode; +} + +/** + * ir_establish_scancode() - set a keycode in the scancode->keycode table + * @dev: the struct rc_dev device descriptor + * @rc_map: scancode table to be searched + * @scancode: the desired scancode + * @resize: controls whether we allowed to resize the table to + * accommodate not yet present scancodes + * @return: index of the mapping containing scancode in question + * or -1U in case of failure. + * + * This routine is used to locate given scancode in rc_map. + * If scancode is not yet present the routine will allocate a new slot + * for it. + */ +static unsigned int ir_establish_scancode(struct rc_dev *dev, + struct rc_map *rc_map, + unsigned int scancode, + bool resize) +{ + unsigned int i; + + /* + * Unfortunately, some hardware-based IR decoders don't provide + * all bits for the complete IR code. In general, they provide only + * the command part of the IR code. Yet, as it is possible to replace + * the provided IR with another one, it is needed to allow loading + * IR tables from other remotes. So, we support specifying a mask to + * indicate the valid bits of the scancodes. + */ + if (dev->scanmask) + scancode &= dev->scanmask; + + /* First check if we already have a mapping for this ir command */ + for (i = 0; i < rc_map->len; i++) { + if (rc_map->scan[i].scancode == scancode) + return i; + + /* Keytable is sorted from lowest to highest scancode */ + if (rc_map->scan[i].scancode >= scancode) + break; + } + + /* No previous mapping found, we might need to grow the table */ + if (rc_map->size == rc_map->len) { + if (!resize || ir_resize_table(rc_map, GFP_ATOMIC)) + return -1U; + } + + /* i is the proper index to insert our new keycode */ + if (i < rc_map->len) + memmove(&rc_map->scan[i + 1], &rc_map->scan[i], + (rc_map->len - i) * sizeof(struct rc_map_table)); + rc_map->scan[i].scancode = scancode; + rc_map->scan[i].keycode = KEY_RESERVED; + rc_map->len++; + + return i; +} + +/** + * ir_setkeycode() - set a keycode in the scancode->keycode table + * @idev: the struct input_dev device descriptor + * @scancode: the desired scancode + * @keycode: result + * @return: -EINVAL if the keycode could not be inserted, otherwise zero. + * + * This routine is used to handle evdev EVIOCSKEY ioctl. + */ +static int ir_setkeycode(struct input_dev *idev, + const struct input_keymap_entry *ke, + unsigned int *old_keycode) +{ + struct rc_dev *rdev = input_get_drvdata(idev); + struct rc_map *rc_map = &rdev->rc_map; + unsigned int index; + unsigned int scancode; + int retval = 0; + unsigned long flags; + + spin_lock_irqsave(&rc_map->lock, flags); + + if (ke->flags & INPUT_KEYMAP_BY_INDEX) { + index = ke->index; + if (index >= rc_map->len) { + retval = -EINVAL; + goto out; + } + } else { + retval = input_scancode_to_scalar(ke, &scancode); + if (retval) + goto out; + + index = ir_establish_scancode(rdev, rc_map, scancode, true); + if (index >= rc_map->len) { + retval = -ENOMEM; + goto out; + } + } + + *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode); + +out: + spin_unlock_irqrestore(&rc_map->lock, flags); + return retval; +} + +/** + * ir_setkeytable() - sets several entries in the scancode->keycode table + * @dev: the struct rc_dev device descriptor + * @to: the struct rc_map to copy entries to + * @from: the struct rc_map to copy entries from + * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero. + * + * This routine is used to handle table initialization. + */ +static int ir_setkeytable(struct rc_dev *dev, + const struct rc_map *from) +{ + struct rc_map *rc_map = &dev->rc_map; + unsigned int i, index; + int rc; + + rc = ir_create_table(rc_map, from->name, + from->rc_type, from->size); + if (rc) + return rc; + + IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n", + rc_map->size, rc_map->alloc); + + for (i = 0; i < from->size; i++) { + index = ir_establish_scancode(dev, rc_map, + from->scan[i].scancode, false); + if (index >= rc_map->len) { + rc = -ENOMEM; + break; + } + + ir_update_mapping(dev, rc_map, index, + from->scan[i].keycode); + } + + if (rc) + ir_free_table(rc_map); + + return rc; +} + +/** + * ir_lookup_by_scancode() - locate mapping by scancode + * @rc_map: the struct rc_map to search + * @scancode: scancode to look for in the table + * @return: index in the table, -1U if not found + * + * This routine performs binary search in RC keykeymap table for + * given scancode. + */ +static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map, + unsigned int scancode) +{ + int start = 0; + int end = rc_map->len - 1; + int mid; + + while (start <= end) { + mid = (start + end) / 2; + if (rc_map->scan[mid].scancode < scancode) + start = mid + 1; + else if (rc_map->scan[mid].scancode > scancode) + end = mid - 1; + else + return mid; + } + + return -1U; +} + +/** + * ir_getkeycode() - get a keycode from the scancode->keycode table + * @idev: the struct input_dev device descriptor + * @scancode: the desired scancode + * @keycode: used to return the keycode, if found, or KEY_RESERVED + * @return: always returns zero. + * + * This routine is used to handle evdev EVIOCGKEY ioctl. + */ +static int ir_getkeycode(struct input_dev *idev, + struct input_keymap_entry *ke) +{ + struct rc_dev *rdev = input_get_drvdata(idev); + struct rc_map *rc_map = &rdev->rc_map; + struct rc_map_table *entry; + unsigned long flags; + unsigned int index; + unsigned int scancode; + int retval; + + spin_lock_irqsave(&rc_map->lock, flags); + + if (ke->flags & INPUT_KEYMAP_BY_INDEX) { + index = ke->index; + } else { + retval = input_scancode_to_scalar(ke, &scancode); + if (retval) + goto out; + + index = ir_lookup_by_scancode(rc_map, scancode); + } + + if (index < rc_map->len) { + entry = &rc_map->scan[index]; + + ke->index = index; + ke->keycode = entry->keycode; + ke->len = sizeof(entry->scancode); + memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode)); + + } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) { + /* + * We do not really know the valid range of scancodes + * so let's respond with KEY_RESERVED to anything we + * do not have mapping for [yet]. + */ + ke->index = index; + ke->keycode = KEY_RESERVED; + } else { + retval = -EINVAL; + goto out; + } + + retval = 0; + +out: + spin_unlock_irqrestore(&rc_map->lock, flags); + return retval; +} + +/** + * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode + * @dev: the struct rc_dev descriptor of the device + * @scancode: the scancode to look for + * @return: the corresponding keycode, or KEY_RESERVED + * + * This routine is used by drivers which need to convert a scancode to a + * keycode. Normally it should not be used since drivers should have no + * interest in keycodes. + */ +u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode) +{ + struct rc_map *rc_map = &dev->rc_map; + unsigned int keycode; + unsigned int index; + unsigned long flags; + + spin_lock_irqsave(&rc_map->lock, flags); + + index = ir_lookup_by_scancode(rc_map, scancode); + keycode = index < rc_map->len ? + rc_map->scan[index].keycode : KEY_RESERVED; + + spin_unlock_irqrestore(&rc_map->lock, flags); + + if (keycode != KEY_RESERVED) + IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n", + dev->input_name, scancode, keycode); + + return keycode; +} +EXPORT_SYMBOL_GPL(rc_g_keycode_from_table); + +/** + * ir_do_keyup() - internal function to signal the release of a keypress + * @dev: the struct rc_dev descriptor of the device + * + * This function is used internally to release a keypress, it must be + * called with keylock held. + */ +static void ir_do_keyup(struct rc_dev *dev) +{ + if (!dev->keypressed) + return; + + IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); + input_report_key(dev->input_dev, dev->last_keycode, 0); + input_sync(dev->input_dev); + dev->keypressed = false; +} + +/** + * rc_keyup() - signals the release of a keypress + * @dev: the struct rc_dev descriptor of the device + * + * This routine is used to signal that a key has been released on the + * remote control. + */ +void rc_keyup(struct rc_dev *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->keylock, flags); + ir_do_keyup(dev); + spin_unlock_irqrestore(&dev->keylock, flags); +} +EXPORT_SYMBOL_GPL(rc_keyup); + +/** + * ir_timer_keyup() - generates a keyup event after a timeout + * @cookie: a pointer to the struct rc_dev for the device + * + * This routine will generate a keyup event some time after a keydown event + * is generated when no further activity has been detected. + */ +static void ir_timer_keyup(unsigned long cookie) +{ + struct rc_dev *dev = (struct rc_dev *)cookie; + unsigned long flags; + + /* + * ir->keyup_jiffies is used to prevent a race condition if a + * hardware interrupt occurs at this point and the keyup timer + * event is moved further into the future as a result. + * + * The timer will then be reactivated and this function called + * again in the future. We need to exit gracefully in that case + * to allow the input subsystem to do its auto-repeat magic or + * a keyup event might follow immediately after the keydown. + */ + spin_lock_irqsave(&dev->keylock, flags); + if (time_is_before_eq_jiffies(dev->keyup_jiffies)) + ir_do_keyup(dev); + spin_unlock_irqrestore(&dev->keylock, flags); +} + +/** + * rc_repeat() - signals that a key is still pressed + * @dev: the struct rc_dev descriptor of the device + * + * This routine is used by IR decoders when a repeat message which does + * not include the necessary bits to reproduce the scancode has been + * received. + */ +void rc_repeat(struct rc_dev *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->keylock, flags); + + input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); + + if (!dev->keypressed) + goto out; + + dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); + mod_timer(&dev->timer_keyup, dev->keyup_jiffies); + +out: + spin_unlock_irqrestore(&dev->keylock, flags); +} +EXPORT_SYMBOL_GPL(rc_repeat); + +/** + * ir_do_keydown() - internal function to process a keypress + * @dev: the struct rc_dev descriptor of the device + * @scancode: the scancode of the keypress + * @keycode: the keycode of the keypress + * @toggle: the toggle value of the keypress + * + * This function is used internally to register a keypress, it must be + * called with keylock held. + */ +static void ir_do_keydown(struct rc_dev *dev, int scancode, + u32 keycode, u8 toggle) +{ + input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); + + /* Repeat event? */ + if (dev->keypressed && + dev->last_scancode == scancode && + dev->last_toggle == toggle) + return; + + /* Release old keypress */ + ir_do_keyup(dev); + + dev->last_scancode = scancode; + dev->last_toggle = toggle; + dev->last_keycode = keycode; + + if (keycode == KEY_RESERVED) + return; + + /* Register a keypress */ + dev->keypressed = true; + IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n", + dev->input_name, keycode, scancode); + input_report_key(dev->input_dev, dev->last_keycode, 1); + input_sync(dev->input_dev); +} + +/** + * rc_keydown() - generates input event for a key press + * @dev: the struct rc_dev descriptor of the device + * @scancode: the scancode that we're seeking + * @toggle: the toggle value (protocol dependent, if the protocol doesn't + * support toggle values, this should be set to zero) + * + * This routine is used to signal that a key has been pressed on the + * remote control. + */ +void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle) +{ + unsigned long flags; + u32 keycode = rc_g_keycode_from_table(dev, scancode); + + spin_lock_irqsave(&dev->keylock, flags); + ir_do_keydown(dev, scancode, keycode, toggle); + + if (dev->keypressed) { + dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); + mod_timer(&dev->timer_keyup, dev->keyup_jiffies); + } + spin_unlock_irqrestore(&dev->keylock, flags); +} +EXPORT_SYMBOL_GPL(rc_keydown); + +/** + * rc_keydown_notimeout() - generates input event for a key press without + * an automatic keyup event at a later time + * @dev: the struct rc_dev descriptor of the device + * @scancode: the scancode that we're seeking + * @toggle: the toggle value (protocol dependent, if the protocol doesn't + * support toggle values, this should be set to zero) + * + * This routine is used to signal that a key has been pressed on the + * remote control. The driver must manually call rc_keyup() at a later stage. + */ +void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle) +{ + unsigned long flags; + u32 keycode = rc_g_keycode_from_table(dev, scancode); + + spin_lock_irqsave(&dev->keylock, flags); + ir_do_keydown(dev, scancode, keycode, toggle); + spin_unlock_irqrestore(&dev->keylock, flags); +} +EXPORT_SYMBOL_GPL(rc_keydown_notimeout); + +static int ir_open(struct input_dev *idev) +{ + struct rc_dev *rdev = input_get_drvdata(idev); + + return rdev->open(rdev); +} + +static void ir_close(struct input_dev *idev) +{ + struct rc_dev *rdev = input_get_drvdata(idev); + + if (rdev) + rdev->close(rdev); +} + +/* class for /sys/class/rc */ +static char *ir_devnode(struct device *dev, mode_t *mode) +{ + return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev)); +} + +static struct class ir_input_class = { + .name = "rc", + .devnode = ir_devnode, +}; + +static struct { + u64 type; + char *name; +} proto_names[] = { + { RC_TYPE_UNKNOWN, "unknown" }, + { RC_TYPE_RC5, "rc-5" }, + { RC_TYPE_NEC, "nec" }, + { RC_TYPE_RC6, "rc-6" }, + { RC_TYPE_JVC, "jvc" }, + { RC_TYPE_SONY, "sony" }, + { RC_TYPE_RC5_SZ, "rc-5-sz" }, + { RC_TYPE_LIRC, "lirc" }, + { RC_TYPE_OTHER, "other" }, +}; + +#define PROTO_NONE "none" + +/** + * show_protocols() - shows the current IR protocol(s) + * @device: the device descriptor + * @mattr: the device attribute struct (unused) + * @buf: a pointer to the output buffer + * + * This routine is a callback routine for input read the IR protocol type(s). + * it is trigged by reading /sys/class/rc/rc?/protocols. + * It returns the protocol names of supported protocols. + * Enabled protocols are printed in brackets. + * + * dev->lock is taken to guard against races between device + * registration, store_protocols and show_protocols. + */ +static ssize_t show_protocols(struct device *device, + struct device_attribute *mattr, char *buf) +{ + struct rc_dev *dev = to_rc_dev(device); + u64 allowed, enabled; + char *tmp = buf; + int i; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + mutex_lock(&dev->lock); + + if (dev->driver_type == RC_DRIVER_SCANCODE) { + enabled = dev->rc_map.rc_type; + allowed = dev->allowed_protos; + } else { + enabled = dev->raw->enabled_protocols; + allowed = ir_raw_get_allowed_protocols(); + } + + IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", + (long long)allowed, + (long long)enabled); + + for (i = 0; i < ARRAY_SIZE(proto_names); i++) { + if (allowed & enabled & proto_names[i].type) + tmp += sprintf(tmp, "[%s] ", proto_names[i].name); + else if (allowed & proto_names[i].type) + tmp += sprintf(tmp, "%s ", proto_names[i].name); + } + + if (tmp != buf) + tmp--; + *tmp = '\n'; + + mutex_unlock(&dev->lock); + + return tmp + 1 - buf; +} + +/** + * store_protocols() - changes the current IR protocol(s) + * @device: the device descriptor + * @mattr: the device attribute struct (unused) + * @buf: a pointer to the input buffer + * @len: length of the input buffer + * + * This routine is for changing the IR protocol type. + * It is trigged by writing to /sys/class/rc/rc?/protocols. + * Writing "+proto" will add a protocol to the list of enabled protocols. + * Writing "-proto" will remove a protocol from the list of enabled protocols. + * Writing "proto" will enable only "proto". + * Writing "none" will disable all protocols. + * Returns -EINVAL if an invalid protocol combination or unknown protocol name + * is used, otherwise @len. + * + * dev->lock is taken to guard against races between device + * registration, store_protocols and show_protocols. + */ +static ssize_t store_protocols(struct device *device, + struct device_attribute *mattr, + const char *data, + size_t len) +{ + struct rc_dev *dev = to_rc_dev(device); + bool enable, disable; + const char *tmp; + u64 type; + u64 mask; + int rc, i, count = 0; + unsigned long flags; + ssize_t ret; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + mutex_lock(&dev->lock); + + if (dev->driver_type == RC_DRIVER_SCANCODE) + type = dev->rc_map.rc_type; + else if (dev->raw) + type = dev->raw->enabled_protocols; + else { + IR_dprintk(1, "Protocol switching not supported\n"); + ret = -EINVAL; + goto out; + } + + while ((tmp = strsep((char **) &data, " \n")) != NULL) { + if (!*tmp) + break; + + if (*tmp == '+') { + enable = true; + disable = false; + tmp++; + } else if (*tmp == '-') { + enable = false; + disable = true; + tmp++; + } else { + enable = false; + disable = false; + } + + if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) { + tmp += sizeof(PROTO_NONE); + mask = 0; + count++; + } else { + for (i = 0; i < ARRAY_SIZE(proto_names); i++) { + if (!strcasecmp(tmp, proto_names[i].name)) { + tmp += strlen(proto_names[i].name); + mask = proto_names[i].type; + break; + } + } + if (i == ARRAY_SIZE(proto_names)) { + IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); + ret = -EINVAL; + goto out; + } + count++; + } + + if (enable) + type |= mask; + else if (disable) + type &= ~mask; + else + type = mask; + } + + if (!count) { + IR_dprintk(1, "Protocol not specified\n"); + ret = -EINVAL; + goto out; + } + + if (dev->change_protocol) { + rc = dev->change_protocol(dev, type); + if (rc < 0) { + IR_dprintk(1, "Error setting protocols to 0x%llx\n", + (long long)type); + ret = -EINVAL; + goto out; + } + } + + if (dev->driver_type == RC_DRIVER_SCANCODE) { + spin_lock_irqsave(&dev->rc_map.lock, flags); + dev->rc_map.rc_type = type; + spin_unlock_irqrestore(&dev->rc_map.lock, flags); + } else { + dev->raw->enabled_protocols = type; + } + + IR_dprintk(1, "Current protocol(s): 0x%llx\n", + (long long)type); + + ret = len; + +out: + mutex_unlock(&dev->lock); + return ret; +} + +static void rc_dev_release(struct device *device) +{ + struct rc_dev *dev = to_rc_dev(device); + + kfree(dev); + module_put(THIS_MODULE); +} + +#define ADD_HOTPLUG_VAR(fmt, val...) \ + do { \ + int err = add_uevent_var(env, fmt, val); \ + if (err) \ + return err; \ + } while (0) + +static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) +{ + struct rc_dev *dev = to_rc_dev(device); + + if (dev->rc_map.name) + ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); + if (dev->driver_name) + ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name); + + return 0; +} + +/* + * Static device attribute struct with the sysfs attributes for IR's + */ +static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, + show_protocols, store_protocols); + +static struct attribute *rc_dev_attrs[] = { + &dev_attr_protocols.attr, + NULL, +}; + +static struct attribute_group rc_dev_attr_grp = { + .attrs = rc_dev_attrs, +}; + +static const struct attribute_group *rc_dev_attr_groups[] = { + &rc_dev_attr_grp, + NULL +}; + +static struct device_type rc_dev_type = { + .groups = rc_dev_attr_groups, + .release = rc_dev_release, + .uevent = rc_dev_uevent, +}; + +struct rc_dev *rc_allocate_device(void) +{ + struct rc_dev *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->input_dev = input_allocate_device(); + if (!dev->input_dev) { + kfree(dev); + return NULL; + } + + dev->input_dev->getkeycode = ir_getkeycode; + dev->input_dev->setkeycode = ir_setkeycode; + input_set_drvdata(dev->input_dev, dev); + + spin_lock_init(&dev->rc_map.lock); + spin_lock_init(&dev->keylock); + mutex_init(&dev->lock); + setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev); + + dev->dev.type = &rc_dev_type; + dev->dev.class = &ir_input_class; + device_initialize(&dev->dev); + + __module_get(THIS_MODULE); + return dev; +} +EXPORT_SYMBOL_GPL(rc_allocate_device); + +void rc_free_device(struct rc_dev *dev) +{ + if (dev) { + input_free_device(dev->input_dev); + put_device(&dev->dev); + } +} +EXPORT_SYMBOL_GPL(rc_free_device); + +int rc_register_device(struct rc_dev *dev) +{ + static atomic_t devno = ATOMIC_INIT(0); + struct rc_map *rc_map; + const char *path; + int rc; + + if (!dev || !dev->map_name) + return -EINVAL; + + rc_map = rc_map_get(dev->map_name); + if (!rc_map) + rc_map = rc_map_get(RC_MAP_EMPTY); + if (!rc_map || !rc_map->scan || rc_map->size == 0) + return -EINVAL; + + set_bit(EV_KEY, dev->input_dev->evbit); + set_bit(EV_REP, dev->input_dev->evbit); + set_bit(EV_MSC, dev->input_dev->evbit); + set_bit(MSC_SCAN, dev->input_dev->mscbit); + if (dev->open) + dev->input_dev->open = ir_open; + if (dev->close) + dev->input_dev->close = ir_close; + + /* + * Take the lock here, as the device sysfs node will appear + * when device_add() is called, which may trigger an ir-keytable udev + * rule, which will in turn call show_protocols and access either + * dev->rc_map.rc_type or dev->raw->enabled_protocols before it has + * been initialized. + */ + mutex_lock(&dev->lock); + + dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1); + dev_set_name(&dev->dev, "rc%ld", dev->devno); + dev_set_drvdata(&dev->dev, dev); + rc = device_add(&dev->dev); + if (rc) + goto out_unlock; + + rc = ir_setkeytable(dev, rc_map); + if (rc) + goto out_dev; + + dev->input_dev->dev.parent = &dev->dev; + memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id)); + dev->input_dev->phys = dev->input_phys; + dev->input_dev->name = dev->input_name; + rc = input_register_device(dev->input_dev); + if (rc) + goto out_table; + + /* + * Default delay of 250ms is too short for some protocols, especially + * since the timeout is currently set to 250ms. Increase it to 500ms, + * to avoid wrong repetition of the keycodes. Note that this must be + * set after the call to input_register_device(). + */ + dev->input_dev->rep[REP_DELAY] = 500; + + /* + * As a repeat event on protocols like RC-5 and NEC take as long as + * 110/114ms, using 33ms as a repeat period is not the right thing + * to do. + */ + dev->input_dev->rep[REP_PERIOD] = 125; + + path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); + printk(KERN_INFO "%s: %s as %s\n", + dev_name(&dev->dev), + dev->input_name ? dev->input_name : "Unspecified device", + path ? path : "N/A"); + kfree(path); + + if (dev->driver_type == RC_DRIVER_IR_RAW) { + rc = ir_raw_event_register(dev); + if (rc < 0) + goto out_input; + } + + if (dev->change_protocol) { + rc = dev->change_protocol(dev, rc_map->rc_type); + if (rc < 0) + goto out_raw; + } + + mutex_unlock(&dev->lock); + + IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n", + dev->devno, + dev->driver_name ? dev->driver_name : "unknown", + rc_map->name ? rc_map->name : "unknown", + dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked"); + + return 0; + +out_raw: + if (dev->driver_type == RC_DRIVER_IR_RAW) + ir_raw_event_unregister(dev); +out_input: + input_unregister_device(dev->input_dev); + dev->input_dev = NULL; +out_table: + ir_free_table(&dev->rc_map); +out_dev: + device_del(&dev->dev); +out_unlock: + mutex_unlock(&dev->lock); + return rc; +} +EXPORT_SYMBOL_GPL(rc_register_device); + +void rc_unregister_device(struct rc_dev *dev) +{ + if (!dev) + return; + + del_timer_sync(&dev->timer_keyup); + + if (dev->driver_type == RC_DRIVER_IR_RAW) + ir_raw_event_unregister(dev); + + input_unregister_device(dev->input_dev); + dev->input_dev = NULL; + + ir_free_table(&dev->rc_map); + IR_dprintk(1, "Freed keycode table\n"); + + device_unregister(&dev->dev); +} +EXPORT_SYMBOL_GPL(rc_unregister_device); + +/* + * Init/exit code for the module. Basically, creates/removes /sys/class/rc + */ + +static int __init rc_core_init(void) +{ + int rc = class_register(&ir_input_class); + if (rc) { + printk(KERN_ERR "rc_core: unable to register rc class\n"); + return rc; + } + + /* Initialize/load the decoders/keymap code that will be used */ + ir_raw_init(); + rc_map_register(&empty_map); + + return 0; +} + +static void __exit rc_core_exit(void) +{ + class_unregister(&ir_input_class); + rc_map_unregister(&empty_map); +} + +module_init(rc_core_init); +module_exit(rc_core_exit); + +int rc_core_debug; /* ir_debug level (0,1,2) */ +EXPORT_SYMBOL_GPL(rc_core_debug); +module_param_named(debug, rc_core_debug, int, 0644); + +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/redrat3.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/redrat3.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/redrat3.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/redrat3.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1344 @@ +/* + * USB RedRat3 IR Transceiver rc-core driver + * + * Copyright (c) 2011 by Jarod Wilson + * based heavily on the work of Stephen Cox, with additional + * help from RedRat Ltd. + * + * This driver began life based an an old version of the first-generation + * lirc_mceusb driver from the lirc 0.7.2 distribution. It was then + * significantly rewritten by Stephen Cox with the aid of RedRat Ltd's + * Chris Dodge. + * + * The driver was then ported to rc-core and significantly rewritten again, + * by Jarod, using the in-kernel mceusb driver as a guide, after an initial + * port effort was started by Stephen. + * + * TODO LIST: + * - fix lirc not showing repeats properly + * -- + * + * The RedRat3 is a USB transceiver with both send & receive, + * with 2 separate sensors available for receive to enable + * both good long range reception for general use, and good + * short range reception when required for learning a signal. + * + * http://www.redrat.co.uk/ + * + * It uses its own little protocol to communicate, the required + * parts of which are embedded within this driver. + * -- + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include + +/* Driver Information */ +#define DRIVER_VERSION "0.70" +#define DRIVER_AUTHOR "Jarod Wilson " +#define DRIVER_AUTHOR2 "The Dweller, Stephen Cox" +#define DRIVER_DESC "RedRat3 USB IR Transceiver Driver" +#define DRIVER_NAME "redrat3" + +/* module parameters */ +#ifdef CONFIG_USB_DEBUG +static int debug = 1; +#else +static int debug; +#endif + +#define RR3_DEBUG_STANDARD 0x1 +#define RR3_DEBUG_FUNCTION_TRACE 0x2 + +#define rr3_dbg(dev, fmt, ...) \ + do { \ + if (debug & RR3_DEBUG_STANDARD) \ + dev_info(dev, fmt, ## __VA_ARGS__); \ + } while (0) + +#define rr3_ftr(dev, fmt, ...) \ + do { \ + if (debug & RR3_DEBUG_FUNCTION_TRACE) \ + dev_info(dev, fmt, ## __VA_ARGS__); \ + } while (0) + +/* bulk data transfer types */ +#define RR3_ERROR 0x01 +#define RR3_MOD_SIGNAL_IN 0x20 +#define RR3_MOD_SIGNAL_OUT 0x21 + +/* Get the RR firmware version */ +#define RR3_FW_VERSION 0xb1 +#define RR3_FW_VERSION_LEN 64 +/* Send encoded signal bulk-sent earlier*/ +#define RR3_TX_SEND_SIGNAL 0xb3 +#define RR3_SET_IR_PARAM 0xb7 +#define RR3_GET_IR_PARAM 0xb8 +/* Blink the red LED on the device */ +#define RR3_BLINK_LED 0xb9 +/* Read serial number of device */ +#define RR3_READ_SER_NO 0xba +#define RR3_SER_NO_LEN 4 +/* Start capture with the RC receiver */ +#define RR3_RC_DET_ENABLE 0xbb +/* Stop capture with the RC receiver */ +#define RR3_RC_DET_DISABLE 0xbc +/* Return the status of RC detector capture */ +#define RR3_RC_DET_STATUS 0xbd +/* Reset redrat */ +#define RR3_RESET 0xa0 + +/* Max number of lengths in the signal. */ +#define RR3_IR_IO_MAX_LENGTHS 0x01 +/* Periods to measure mod. freq. */ +#define RR3_IR_IO_PERIODS_MF 0x02 +/* Size of memory for main signal data */ +#define RR3_IR_IO_SIG_MEM_SIZE 0x03 +/* Delta value when measuring lengths */ +#define RR3_IR_IO_LENGTH_FUZZ 0x04 +/* Timeout for end of signal detection */ +#define RR3_IR_IO_SIG_TIMEOUT 0x05 +/* Minumum value for pause recognition. */ +#define RR3_IR_IO_MIN_PAUSE 0x06 + +/* Clock freq. of EZ-USB chip */ +#define RR3_CLK 24000000 +/* Clock periods per timer count */ +#define RR3_CLK_PER_COUNT 12 +/* (RR3_CLK / RR3_CLK_PER_COUNT) */ +#define RR3_CLK_CONV_FACTOR 2000000 +/* USB bulk-in IR data endpoint address */ +#define RR3_BULK_IN_EP_ADDR 0x82 + +/* Raw Modulated signal data value offsets */ +#define RR3_PAUSE_OFFSET 0 +#define RR3_FREQ_COUNT_OFFSET 4 +#define RR3_NUM_PERIOD_OFFSET 6 +#define RR3_MAX_LENGTHS_OFFSET 8 +#define RR3_NUM_LENGTHS_OFFSET 9 +#define RR3_MAX_SIGS_OFFSET 10 +#define RR3_NUM_SIGS_OFFSET 12 +#define RR3_REPEATS_OFFSET 14 + +/* Size of the fixed-length portion of the signal */ +#define RR3_HEADER_LENGTH 15 +#define RR3_DRIVER_MAXLENS 128 +#define RR3_MAX_SIG_SIZE 512 +#define RR3_MAX_BUF_SIZE \ + ((2 * RR3_HEADER_LENGTH) + RR3_DRIVER_MAXLENS + RR3_MAX_SIG_SIZE) +#define RR3_TIME_UNIT 50 +#define RR3_END_OF_SIGNAL 0x7f +#define RR3_TX_HEADER_OFFSET 4 +#define RR3_TX_TRAILER_LEN 2 +#define RR3_RX_MIN_TIMEOUT 5 +#define RR3_RX_MAX_TIMEOUT 2000 + +/* The 8051's CPUCS Register address */ +#define RR3_CPUCS_REG_ADDR 0x7f92 + +#define USB_RR3USB_VENDOR_ID 0x112a +#define USB_RR3USB_PRODUCT_ID 0x0001 +#define USB_RR3IIUSB_PRODUCT_ID 0x0005 + +/* table of devices that work with this driver */ +static struct usb_device_id redrat3_dev_table[] = { + /* Original version of the RedRat3 */ + {USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3USB_PRODUCT_ID)}, + /* Second Version/release of the RedRat3 - RetRat3-II */ + {USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3IIUSB_PRODUCT_ID)}, + {} /* Terminating entry */ +}; + +/* Structure to hold all of our device specific stuff */ +struct redrat3_dev { + /* core device bits */ + struct rc_dev *rc; + struct device *dev; + + /* save off the usb device pointer */ + struct usb_device *udev; + + /* the receive endpoint */ + struct usb_endpoint_descriptor *ep_in; + /* the buffer to receive data */ + unsigned char *bulk_in_buf; + /* urb used to read ir data */ + struct urb *read_urb; + + /* the send endpoint */ + struct usb_endpoint_descriptor *ep_out; + /* the buffer to send data */ + unsigned char *bulk_out_buf; + /* the urb used to send data */ + struct urb *write_urb; + + /* usb dma */ + dma_addr_t dma_in; + dma_addr_t dma_out; + + /* true if write urb is busy */ + bool write_busy; + /* wait for the write to finish */ + struct completion write_finished; + + /* locks this structure */ + struct mutex lock; + + /* rx signal timeout timer */ + struct timer_list rx_timeout; + + /* Is the device currently receiving? */ + bool recv_in_progress; + /* is the detector enabled*/ + bool det_enabled; + /* Is the device currently transmitting?*/ + bool transmitting; + + /* store for current packet */ + char pbuf[RR3_MAX_BUF_SIZE]; + u16 pktlen; + u16 pkttype; + u16 bytes_read; + /* indicate whether we are going to reprocess + * the USB callback with a bigger buffer */ + int buftoosmall; + char *datap; + + u32 carrier; + + char name[128]; + char phys[64]; +}; + +/* All incoming data buffers adhere to a very specific data format */ +struct redrat3_signal_header { + u16 length; /* Length of data being transferred */ + u16 transfer_type; /* Type of data transferred */ + u32 pause; /* Pause between main and repeat signals */ + u16 mod_freq_count; /* Value of timer on mod. freq. measurement */ + u16 no_periods; /* No. of periods over which mod. freq. is measured */ + u8 max_lengths; /* Max no. of lengths (i.e. size of array) */ + u8 no_lengths; /* Actual no. of elements in lengths array */ + u16 max_sig_size; /* Max no. of values in signal data array */ + u16 sig_size; /* Acuto no. of values in signal data array */ + u8 no_repeats; /* No. of repeats of repeat signal section */ + /* Here forward is the lengths and signal data */ +}; + +static void redrat3_dump_signal_header(struct redrat3_signal_header *header) +{ + pr_info("%s:\n", __func__); + pr_info(" * length: %u, transfer_type: 0x%02x\n", + header->length, header->transfer_type); + pr_info(" * pause: %u, freq_count: %u, no_periods: %u\n", + header->pause, header->mod_freq_count, header->no_periods); + pr_info(" * lengths: %u (max: %u)\n", + header->no_lengths, header->max_lengths); + pr_info(" * sig_size: %u (max: %u)\n", + header->sig_size, header->max_sig_size); + pr_info(" * repeats: %u\n", header->no_repeats); +} + +static void redrat3_dump_signal_data(char *buffer, u16 len) +{ + int offset, i; + char *data_vals; + + pr_info("%s:", __func__); + + offset = RR3_TX_HEADER_OFFSET + RR3_HEADER_LENGTH + + (RR3_DRIVER_MAXLENS * sizeof(u16)); + + /* read RR3_DRIVER_MAXLENS from ctrl msg */ + data_vals = buffer + offset; + + for (i = 0; i < len; i++) { + if (i % 10 == 0) + pr_cont("\n * "); + pr_cont("%02x ", *data_vals++); + } + + pr_cont("\n"); +} + +/* + * redrat3_issue_async + * + * Issues an async read to the ir data in port.. + * sets the callback to be redrat3_handle_async + */ +static void redrat3_issue_async(struct redrat3_dev *rr3) +{ + int res; + + rr3_ftr(rr3->dev, "Entering %s\n", __func__); + + if (!rr3->det_enabled) { + dev_warn(rr3->dev, "not issuing async read, " + "detector not enabled\n"); + return; + } + + memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize); + res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC); + if (res) + rr3_dbg(rr3->dev, "%s: receive request FAILED! " + "(res %d, len %d)\n", __func__, res, + rr3->read_urb->transfer_buffer_length); +} + +static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) +{ + if (!rr3->transmitting && (code != 0x40)) + dev_info(rr3->dev, "fw error code 0x%02x: ", code); + + switch (code) { + case 0x00: + pr_cont("No Error\n"); + break; + + /* Codes 0x20 through 0x2f are IR Firmware Errors */ + case 0x20: + pr_cont("Initial signal pulse not long enough " + "to measure carrier frequency\n"); + break; + case 0x21: + pr_cont("Not enough length values allocated for signal\n"); + break; + case 0x22: + pr_cont("Not enough memory allocated for signal data\n"); + break; + case 0x23: + pr_cont("Too many signal repeats\n"); + break; + case 0x28: + pr_cont("Insufficient memory available for IR signal " + "data memory allocation\n"); + break; + case 0x29: + pr_cont("Insufficient memory available " + "for IrDa signal data memory allocation\n"); + break; + + /* Codes 0x30 through 0x3f are USB Firmware Errors */ + case 0x30: + pr_cont("Insufficient memory available for bulk " + "transfer structure\n"); + break; + + /* + * Other error codes... These are primarily errors that can occur in + * the control messages sent to the redrat + */ + case 0x40: + if (!rr3->transmitting) + pr_cont("Signal capture has been terminated\n"); + break; + case 0x41: + pr_cont("Attempt to set/get and unknown signal I/O " + "algorithm parameter\n"); + break; + case 0x42: + pr_cont("Signal capture already started\n"); + break; + + default: + pr_cont("Unknown Error\n"); + break; + } +} + +static u32 redrat3_val_to_mod_freq(struct redrat3_signal_header *ph) +{ + u32 mod_freq = 0; + + if (ph->mod_freq_count != 0) + mod_freq = (RR3_CLK * ph->no_periods) / + (ph->mod_freq_count * RR3_CLK_PER_COUNT); + + return mod_freq; +} + +/* this function scales down the figures for the same result... */ +static u32 redrat3_len_to_us(u32 length) +{ + u32 biglen = length * 1000; + u32 divisor = (RR3_CLK_CONV_FACTOR) / 1000; + u32 result = (u32) (biglen / divisor); + + /* don't allow zero lengths to go back, breaks lirc */ + return result ? result : 1; +} + +/* + * convert us back into redrat3 lengths + * + * length * 1000 length * 1000000 + * ------------- = ---------------- = micro + * rr3clk / 1000 rr3clk + + * 6 * 2 4 * 3 micro * rr3clk micro * rr3clk / 1000 + * ----- = 4 ----- = 6 -------------- = len --------------------- + * 3 2 1000000 1000 + */ +static u32 redrat3_us_to_len(u32 microsec) +{ + u32 result; + u32 divisor; + + microsec &= IR_MAX_DURATION; + divisor = (RR3_CLK_CONV_FACTOR / 1000); + result = (u32)(microsec * divisor) / 1000; + + /* don't allow zero lengths to go back, breaks lirc */ + return result ? result : 1; + +} + +/* timer callback to send long trailing space on receive timeout */ +static void redrat3_rx_timeout(unsigned long data) +{ + struct redrat3_dev *rr3 = (struct redrat3_dev *)data; + DEFINE_IR_RAW_EVENT(rawir); + + rawir.pulse = false; + rawir.duration = rr3->rc->timeout; + rr3_dbg(rr3->dev, "storing trailing space with duration %d\n", + rawir.duration); + ir_raw_event_store_with_filter(rr3->rc, &rawir); + + rr3_dbg(rr3->dev, "calling ir_raw_event_handle\n"); + ir_raw_event_handle(rr3->rc); + + rr3_dbg(rr3->dev, "calling ir_raw_event_reset\n"); + ir_raw_event_reset(rr3->rc); +} + +static void redrat3_process_ir_data(struct redrat3_dev *rr3) +{ + DEFINE_IR_RAW_EVENT(rawir); + struct redrat3_signal_header header; + struct device *dev; + int i; + unsigned long delay; + u32 mod_freq, single_len; + u16 *len_vals; + u8 *data_vals; + u32 tmp32; + u16 tmp16; + char *sig_data; + + if (!rr3) { + pr_err("%s called with no context!\n", __func__); + return; + } + + rr3_ftr(rr3->dev, "Entered %s\n", __func__); + + dev = rr3->dev; + sig_data = rr3->pbuf; + + header.length = rr3->pktlen; + header.transfer_type = rr3->pkttype; + + /* Sanity check */ + if (!(header.length >= RR3_HEADER_LENGTH)) + dev_warn(dev, "read returned less than rr3 header len\n"); + + delay = usecs_to_jiffies(rr3->rc->timeout / 1000); + mod_timer(&rr3->rx_timeout, jiffies + delay); + + memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32)); + header.pause = be32_to_cpu(tmp32); + + memcpy(&tmp16, sig_data + RR3_FREQ_COUNT_OFFSET, sizeof(tmp16)); + header.mod_freq_count = be16_to_cpu(tmp16); + + memcpy(&tmp16, sig_data + RR3_NUM_PERIOD_OFFSET, sizeof(tmp16)); + header.no_periods = be16_to_cpu(tmp16); + + header.max_lengths = sig_data[RR3_MAX_LENGTHS_OFFSET]; + header.no_lengths = sig_data[RR3_NUM_LENGTHS_OFFSET]; + + memcpy(&tmp16, sig_data + RR3_MAX_SIGS_OFFSET, sizeof(tmp16)); + header.max_sig_size = be16_to_cpu(tmp16); + + memcpy(&tmp16, sig_data + RR3_NUM_SIGS_OFFSET, sizeof(tmp16)); + header.sig_size = be16_to_cpu(tmp16); + + header.no_repeats= sig_data[RR3_REPEATS_OFFSET]; + + if (debug) { + redrat3_dump_signal_header(&header); + redrat3_dump_signal_data(sig_data, header.sig_size); + } + + mod_freq = redrat3_val_to_mod_freq(&header); + rr3_dbg(dev, "Got mod_freq of %u\n", mod_freq); + + /* Here we pull out the 'length' values from the signal */ + len_vals = (u16 *)(sig_data + RR3_HEADER_LENGTH); + + data_vals = sig_data + RR3_HEADER_LENGTH + + (header.max_lengths * sizeof(u16)); + + /* process each rr3 encoded byte into an int */ + for (i = 0; i < header.sig_size; i++) { + u16 val = len_vals[data_vals[i]]; + single_len = redrat3_len_to_us((u32)be16_to_cpu(val)); + + /* cap the value to IR_MAX_DURATION */ + single_len &= IR_MAX_DURATION; + + /* we should always get pulse/space/pulse/space samples */ + if (i % 2) + rawir.pulse = false; + else + rawir.pulse = true; + + rawir.duration = US_TO_NS(single_len); + rr3_dbg(dev, "storing %s with duration %d (i: %d)\n", + rawir.pulse ? "pulse" : "space", rawir.duration, i); + ir_raw_event_store_with_filter(rr3->rc, &rawir); + } + + /* add a trailing space, if need be */ + if (i % 2) { + rawir.pulse = false; + /* this duration is made up, and may not be ideal... */ + rawir.duration = rr3->rc->timeout / 2; + rr3_dbg(dev, "storing trailing space with duration %d\n", + rawir.duration); + ir_raw_event_store_with_filter(rr3->rc, &rawir); + } + + rr3_dbg(dev, "calling ir_raw_event_handle\n"); + ir_raw_event_handle(rr3->rc); + + return; +} + +/* Util fn to send rr3 cmds */ +static u8 redrat3_send_cmd(int cmd, struct redrat3_dev *rr3) +{ + struct usb_device *udev; + u8 *data; + int res; + + data = kzalloc(sizeof(u8), GFP_KERNEL); + if (!data) + return -ENOMEM; + + udev = rr3->udev; + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), cmd, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0000, 0x0000, data, sizeof(u8), HZ * 10); + + if (res < 0) { + dev_err(rr3->dev, "%s: Error sending rr3 cmd res %d, data %d", + __func__, res, *data); + res = -EIO; + } else + res = (u8)data[0]; + + kfree(data); + + return res; +} + +/* Enables the long range detector and starts async receive */ +static int redrat3_enable_detector(struct redrat3_dev *rr3) +{ + struct device *dev = rr3->dev; + u8 ret; + + rr3_ftr(dev, "Entering %s\n", __func__); + + ret = redrat3_send_cmd(RR3_RC_DET_ENABLE, rr3); + if (ret != 0) + dev_dbg(dev, "%s: unexpected ret of %d\n", + __func__, ret); + + ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3); + if (ret != 1) { + dev_err(dev, "%s: detector status: %d, should be 1\n", + __func__, ret); + return -EIO; + } + + rr3->det_enabled = true; + redrat3_issue_async(rr3); + + return 0; +} + +/* Disables the rr3 long range detector */ +static void redrat3_disable_detector(struct redrat3_dev *rr3) +{ + struct device *dev = rr3->dev; + u8 ret; + + rr3_ftr(dev, "Entering %s\n", __func__); + + ret = redrat3_send_cmd(RR3_RC_DET_DISABLE, rr3); + if (ret != 0) + dev_err(dev, "%s: failure!\n", __func__); + + ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3); + if (ret != 0) + dev_warn(dev, "%s: detector status: %d, should be 0\n", + __func__, ret); + + rr3->det_enabled = false; +} + +static inline void redrat3_delete(struct redrat3_dev *rr3, + struct usb_device *udev) +{ + rr3_ftr(rr3->dev, "%s cleaning up\n", __func__); + usb_kill_urb(rr3->read_urb); + usb_kill_urb(rr3->write_urb); + + usb_free_urb(rr3->read_urb); + usb_free_urb(rr3->write_urb); + + usb_free_coherent(udev, rr3->ep_in->wMaxPacketSize, + rr3->bulk_in_buf, rr3->dma_in); + usb_free_coherent(udev, rr3->ep_out->wMaxPacketSize, + rr3->bulk_out_buf, rr3->dma_out); + + kfree(rr3); +} + +static u32 redrat3_get_timeout(struct device *dev, + struct rc_dev *rc, struct usb_device *udev) +{ + u32 *tmp; + u32 timeout = MS_TO_NS(150); /* a sane default, if things go haywire */ + int len, ret, pipe; + + len = sizeof(*tmp); + tmp = kzalloc(len, GFP_KERNEL); + if (!tmp) { + dev_warn(dev, "Memory allocation faillure\n"); + return timeout; + } + + pipe = usb_rcvctrlpipe(udev, 0); + ret = usb_control_msg(udev, pipe, RR3_GET_IR_PARAM, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5); + if (ret != len) { + dev_warn(dev, "Failed to read timeout from hardware\n"); + return timeout; + } + + timeout = US_TO_NS(redrat3_len_to_us(be32_to_cpu(*tmp))); + if (timeout < rc->min_timeout) + timeout = rc->min_timeout; + else if (timeout > rc->max_timeout) + timeout = rc->max_timeout; + + rr3_dbg(dev, "Got timeout of %d ms\n", timeout / (1000 * 1000)); + return timeout; +} + +static void redrat3_reset(struct redrat3_dev *rr3) +{ + struct usb_device *udev = rr3->udev; + struct device *dev = rr3->dev; + int rc, rxpipe, txpipe; + u8 *val; + int len = sizeof(u8); + + rr3_ftr(dev, "Entering %s\n", __func__); + + rxpipe = usb_rcvctrlpipe(udev, 0); + txpipe = usb_sndctrlpipe(udev, 0); + + val = kzalloc(len, GFP_KERNEL); + if (!val) { + dev_err(dev, "Memory allocation failure\n"); + return; + } + + *val = 0x01; + rc = usb_control_msg(udev, rxpipe, RR3_RESET, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + RR3_CPUCS_REG_ADDR, 0, val, len, HZ * 25); + rr3_dbg(dev, "reset returned 0x%02x\n", rc); + + *val = 5; + rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + RR3_IR_IO_LENGTH_FUZZ, 0, val, len, HZ * 25); + rr3_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc); + + *val = RR3_DRIVER_MAXLENS; + rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + RR3_IR_IO_MAX_LENGTHS, 0, val, len, HZ * 25); + rr3_dbg(dev, "set ir parm max lens %d rc 0x%02x\n", *val, rc); + + kfree(val); +} + +static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) +{ + int rc = 0; + char *buffer; + + rr3_ftr(rr3->dev, "Entering %s\n", __func__); + + buffer = kzalloc(sizeof(char) * (RR3_FW_VERSION_LEN + 1), GFP_KERNEL); + if (!buffer) { + dev_err(rr3->dev, "Memory allocation failure\n"); + return; + } + + rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0), + RR3_FW_VERSION, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0, 0, buffer, RR3_FW_VERSION_LEN, HZ * 5); + + if (rc >= 0) + dev_info(rr3->dev, "Firmware rev: %s", buffer); + else + dev_err(rr3->dev, "Problem fetching firmware ID\n"); + + kfree(buffer); + rr3_ftr(rr3->dev, "Exiting %s\n", __func__); +} + +static void redrat3_read_packet_start(struct redrat3_dev *rr3, int len) +{ + u16 tx_error; + u16 hdrlen; + + rr3_ftr(rr3->dev, "Entering %s\n", __func__); + + /* grab the Length and type of transfer */ + memcpy(&(rr3->pktlen), (unsigned char *) rr3->bulk_in_buf, + sizeof(rr3->pktlen)); + memcpy(&(rr3->pkttype), ((unsigned char *) rr3->bulk_in_buf + + sizeof(rr3->pktlen)), + sizeof(rr3->pkttype)); + + /*data needs conversion to know what its real values are*/ + rr3->pktlen = be16_to_cpu(rr3->pktlen); + rr3->pkttype = be16_to_cpu(rr3->pkttype); + + switch (rr3->pkttype) { + case RR3_ERROR: + memcpy(&tx_error, ((unsigned char *)rr3->bulk_in_buf + + (sizeof(rr3->pktlen) + sizeof(rr3->pkttype))), + sizeof(tx_error)); + tx_error = be16_to_cpu(tx_error); + redrat3_dump_fw_error(rr3, tx_error); + break; + + case RR3_MOD_SIGNAL_IN: + hdrlen = sizeof(rr3->pktlen) + sizeof(rr3->pkttype); + rr3->bytes_read = len; + rr3->bytes_read -= hdrlen; + rr3->datap = &(rr3->pbuf[0]); + + memcpy(rr3->datap, ((unsigned char *)rr3->bulk_in_buf + hdrlen), + rr3->bytes_read); + rr3->datap += rr3->bytes_read; + rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", + rr3->bytes_read, rr3->pktlen); + break; + + default: + rr3_dbg(rr3->dev, "ignoring packet with type 0x%02x, " + "len of %d, 0x%02x\n", rr3->pkttype, len, rr3->pktlen); + break; + } +} + +static void redrat3_read_packet_continue(struct redrat3_dev *rr3, int len) +{ + + rr3_ftr(rr3->dev, "Entering %s\n", __func__); + + memcpy(rr3->datap, (unsigned char *)rr3->bulk_in_buf, len); + rr3->datap += len; + + rr3->bytes_read += len; + rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", + rr3->bytes_read, rr3->pktlen); +} + +/* gather IR data from incoming urb, process it when we have enough */ +static int redrat3_get_ir_data(struct redrat3_dev *rr3, int len) +{ + struct device *dev = rr3->dev; + int ret = 0; + + rr3_ftr(dev, "Entering %s\n", __func__); + + if (rr3->pktlen > RR3_MAX_BUF_SIZE) { + dev_err(rr3->dev, "error: packet larger than buffer\n"); + ret = -EINVAL; + goto out; + } + + if ((rr3->bytes_read == 0) && + (len >= (sizeof(rr3->pkttype) + sizeof(rr3->pktlen)))) { + redrat3_read_packet_start(rr3, len); + } else if (rr3->bytes_read != 0) { + redrat3_read_packet_continue(rr3, len); + } else if (rr3->bytes_read == 0) { + dev_err(dev, "error: no packet data read\n"); + ret = -ENODATA; + goto out; + } + + if (rr3->bytes_read > rr3->pktlen) { + dev_err(dev, "bytes_read (%d) greater than pktlen (%d)\n", + rr3->bytes_read, rr3->pktlen); + ret = -EINVAL; + goto out; + } else if (rr3->bytes_read < rr3->pktlen) + /* we're still accumulating data */ + return 0; + + /* if we get here, we've got IR data to decode */ + if (rr3->pkttype == RR3_MOD_SIGNAL_IN) + redrat3_process_ir_data(rr3); + else + rr3_dbg(dev, "discarding non-signal data packet " + "(type 0x%02x)\n", rr3->pkttype); + +out: + rr3->bytes_read = 0; + rr3->pktlen = 0; + rr3->pkttype = 0; + return ret; +} + +/* callback function from USB when async USB request has completed */ +static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) +{ + struct redrat3_dev *rr3; + + if (!urb) + return; + + rr3 = urb->context; + if (!rr3) { + pr_err("%s called with invalid context!\n", __func__); + usb_unlink_urb(urb); + return; + } + + rr3_ftr(rr3->dev, "Entering %s\n", __func__); + + if (!rr3->det_enabled) { + rr3_dbg(rr3->dev, "received a read callback but detector " + "disabled - ignoring\n"); + return; + } + + switch (urb->status) { + case 0: + redrat3_get_ir_data(rr3, urb->actual_length); + break; + + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + usb_unlink_urb(urb); + return; + + case -EPIPE: + default: + dev_warn(rr3->dev, "Error: urb status = %d\n", urb->status); + rr3->bytes_read = 0; + rr3->pktlen = 0; + rr3->pkttype = 0; + break; + } + + if (!rr3->transmitting) + redrat3_issue_async(rr3); + else + rr3_dbg(rr3->dev, "IR transmit in progress\n"); +} + +static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +{ + struct redrat3_dev *rr3; + int len; + + if (!urb) + return; + + rr3 = urb->context; + if (rr3) { + len = urb->actual_length; + rr3_ftr(rr3->dev, "%s: called (status=%d len=%d)\n", + __func__, urb->status, len); + } +} + +static u16 mod_freq_to_val(unsigned int mod_freq) +{ + int mult = 6000000; + + /* Clk used in mod. freq. generation is CLK24/4. */ + return (u16)(65536 - (mult / mod_freq)); +} + +static int redrat3_set_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + struct redrat3_dev *rr3 = dev->priv; + + rr3->carrier = carrier; + + return carrier; +} + +static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n) +{ + struct redrat3_dev *rr3 = rcdev->priv; + struct device *dev = rr3->dev; + struct redrat3_signal_header header; + int i, j, count, ret, ret_len, offset; + int lencheck, cur_sample_len, pipe; + char *buffer = NULL, *sigdata = NULL; + int *sample_lens = NULL; + u32 tmpi; + u16 tmps; + u8 *datap; + u8 curlencheck = 0; + u16 *lengths_ptr; + int sendbuf_len; + + rr3_ftr(dev, "Entering %s\n", __func__); + + if (rr3->transmitting) { + dev_warn(dev, "%s: transmitter already in use\n", __func__); + return -EAGAIN; + } + + count = n / sizeof(int); + if (count > (RR3_DRIVER_MAXLENS * 2)) + return -EINVAL; + + rr3->transmitting = true; + + redrat3_disable_detector(rr3); + + if (rr3->det_enabled) { + dev_err(dev, "%s: cannot tx while rx is enabled\n", __func__); + ret = -EIO; + goto out; + } + + sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL); + if (!sample_lens) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < count; i++) { + for (lencheck = 0; lencheck < curlencheck; lencheck++) { + cur_sample_len = redrat3_us_to_len(txbuf[i]); + if (sample_lens[lencheck] == cur_sample_len) + break; + } + if (lencheck == curlencheck) { + cur_sample_len = redrat3_us_to_len(txbuf[i]); + rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n", + i, txbuf[i], curlencheck, cur_sample_len); + if (curlencheck < 255) { + /* now convert the value to a proper + * rr3 value.. */ + sample_lens[curlencheck] = cur_sample_len; + curlencheck++; + } else { + dev_err(dev, "signal too long\n"); + ret = -EINVAL; + goto out; + } + } + } + + sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL); + if (!sigdata) { + ret = -ENOMEM; + goto out; + } + + sigdata[count] = RR3_END_OF_SIGNAL; + sigdata[count + 1] = RR3_END_OF_SIGNAL; + for (i = 0; i < count; i++) { + for (j = 0; j < curlencheck; j++) { + if (sample_lens[j] == redrat3_us_to_len(txbuf[i])) + sigdata[i] = j; + } + } + + offset = RR3_TX_HEADER_OFFSET; + sendbuf_len = RR3_HEADER_LENGTH + (sizeof(u16) * RR3_DRIVER_MAXLENS) + + count + RR3_TX_TRAILER_LEN + offset; + + buffer = kzalloc(sendbuf_len, GFP_KERNEL); + if (!buffer) { + ret = -ENOMEM; + goto out; + } + + /* fill in our packet header */ + header.length = sendbuf_len - offset; + header.transfer_type = RR3_MOD_SIGNAL_OUT; + header.pause = redrat3_len_to_us(100); + header.mod_freq_count = mod_freq_to_val(rr3->carrier); + header.no_periods = 0; /* n/a to transmit */ + header.max_lengths = RR3_DRIVER_MAXLENS; + header.no_lengths = curlencheck; + header.max_sig_size = RR3_MAX_SIG_SIZE; + header.sig_size = count + RR3_TX_TRAILER_LEN; + /* we currently rely on repeat handling in the IR encoding source */ + header.no_repeats = 0; + + tmps = cpu_to_be16(header.length); + memcpy(buffer, &tmps, 2); + + tmps = cpu_to_be16(header.transfer_type); + memcpy(buffer + 2, &tmps, 2); + + tmpi = cpu_to_be32(header.pause); + memcpy(buffer + offset, &tmpi, sizeof(tmpi)); + + tmps = cpu_to_be16(header.mod_freq_count); + memcpy(buffer + offset + RR3_FREQ_COUNT_OFFSET, &tmps, 2); + + buffer[offset + RR3_NUM_LENGTHS_OFFSET] = header.no_lengths; + + tmps = cpu_to_be16(header.sig_size); + memcpy(buffer + offset + RR3_NUM_SIGS_OFFSET, &tmps, 2); + + buffer[offset + RR3_REPEATS_OFFSET] = header.no_repeats; + + lengths_ptr = (u16 *)(buffer + offset + RR3_HEADER_LENGTH); + for (i = 0; i < curlencheck; ++i) + lengths_ptr[i] = cpu_to_be16(sample_lens[i]); + + datap = (u8 *)(buffer + offset + RR3_HEADER_LENGTH + + (sizeof(u16) * RR3_DRIVER_MAXLENS)); + memcpy(datap, sigdata, (count + RR3_TX_TRAILER_LEN)); + + if (debug) { + redrat3_dump_signal_header(&header); + redrat3_dump_signal_data(buffer, header.sig_size); + } + + pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress); + tmps = usb_bulk_msg(rr3->udev, pipe, buffer, + sendbuf_len, &ret_len, 10 * HZ); + rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, tmps); + + /* now tell the hardware to transmit what we sent it */ + pipe = usb_rcvctrlpipe(rr3->udev, 0); + ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0, 0, buffer, 2, HZ * 10); + + if (ret < 0) + dev_err(dev, "Error: control msg send failed, rc %d\n", ret); + else + ret = n; + +out: + kfree(sample_lens); + kfree(buffer); + kfree(sigdata); + + rr3->transmitting = false; + + redrat3_enable_detector(rr3); + + return ret; +} + +static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) +{ + struct device *dev = rr3->dev; + struct rc_dev *rc; + int ret = -ENODEV; + u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct); + + rc = rc_allocate_device(); + if (!rc) { + dev_err(dev, "remote input dev allocation failed\n"); + goto out; + } + + snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s " + "Infrared Remote Transceiver (%04x:%04x)", + prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "", + le16_to_cpu(rr3->udev->descriptor.idVendor), prod); + + usb_make_path(rr3->udev, rr3->phys, sizeof(rr3->phys)); + + rc->input_name = rr3->name; + rc->input_phys = rr3->phys; + usb_to_input_id(rr3->udev, &rc->input_id); + rc->dev.parent = dev; + rc->priv = rr3; + rc->driver_type = RC_DRIVER_IR_RAW; + rc->allowed_protos = RC_TYPE_ALL; + rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT); + rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT); + rc->timeout = redrat3_get_timeout(dev, rc, rr3->udev); + rc->tx_ir = redrat3_transmit_ir; + rc->s_tx_carrier = redrat3_set_tx_carrier; + rc->driver_name = DRIVER_NAME; + rc->map_name = RC_MAP_HAUPPAUGE; + + ret = rc_register_device(rc); + if (ret < 0) { + dev_err(dev, "remote dev registration failed\n"); + goto out; + } + + return rc; + +out: + rc_free_device(rc); + return NULL; +} + +static int __devinit redrat3_dev_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct device *dev = &intf->dev; + struct usb_host_interface *uhi; + struct redrat3_dev *rr3; + struct usb_endpoint_descriptor *ep; + struct usb_endpoint_descriptor *ep_in = NULL; + struct usb_endpoint_descriptor *ep_out = NULL; + u8 addr, attrs; + int pipe, i; + int retval = -ENOMEM; + + rr3_ftr(dev, "%s called\n", __func__); + + uhi = intf->cur_altsetting; + + /* find our bulk-in and bulk-out endpoints */ + for (i = 0; i < uhi->desc.bNumEndpoints; ++i) { + ep = &uhi->endpoint[i].desc; + addr = ep->bEndpointAddress; + attrs = ep->bmAttributes; + + if ((ep_in == NULL) && + ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && + ((attrs & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK)) { + rr3_dbg(dev, "found bulk-in endpoint at 0x%02x\n", + ep->bEndpointAddress); + /* data comes in on 0x82, 0x81 is for other data... */ + if (ep->bEndpointAddress == RR3_BULK_IN_EP_ADDR) + ep_in = ep; + } + + if ((ep_out == NULL) && + ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && + ((attrs & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK)) { + rr3_dbg(dev, "found bulk-out endpoint at 0x%02x\n", + ep->bEndpointAddress); + ep_out = ep; + } + } + + if (!ep_in || !ep_out) { + dev_err(dev, "Couldn't find both in and out endpoints\n"); + retval = -ENODEV; + goto no_endpoints; + } + + /* allocate memory for our device state and initialize it */ + rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL); + if (rr3 == NULL) { + dev_err(dev, "Memory allocation failure\n"); + goto no_endpoints; + } + + rr3->dev = &intf->dev; + + /* set up bulk-in endpoint */ + rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->read_urb) { + dev_err(dev, "Read urb allocation failure\n"); + goto error; + } + + rr3->ep_in = ep_in; + rr3->bulk_in_buf = usb_alloc_coherent(udev, ep_in->wMaxPacketSize, + GFP_ATOMIC, &rr3->dma_in); + if (!rr3->bulk_in_buf) { + dev_err(dev, "Read buffer allocation failure\n"); + goto error; + } + + pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress); + usb_fill_bulk_urb(rr3->read_urb, udev, pipe, + rr3->bulk_in_buf, ep_in->wMaxPacketSize, + (usb_complete_t)redrat3_handle_async, rr3); + + /* set up bulk-out endpoint*/ + rr3->write_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->write_urb) { + dev_err(dev, "Write urb allocation failure\n"); + goto error; + } + + rr3->ep_out = ep_out; + rr3->bulk_out_buf = usb_alloc_coherent(udev, ep_out->wMaxPacketSize, + GFP_ATOMIC, &rr3->dma_out); + if (!rr3->bulk_out_buf) { + dev_err(dev, "Write buffer allocation failure\n"); + goto error; + } + + pipe = usb_sndbulkpipe(udev, ep_out->bEndpointAddress); + usb_fill_bulk_urb(rr3->write_urb, udev, pipe, + rr3->bulk_out_buf, ep_out->wMaxPacketSize, + (usb_complete_t)redrat3_write_bulk_callback, rr3); + + mutex_init(&rr3->lock); + rr3->udev = udev; + + redrat3_reset(rr3); + redrat3_get_firmware_rev(rr3); + + /* might be all we need to do? */ + retval = redrat3_enable_detector(rr3); + if (retval < 0) + goto error; + + /* default.. will get overridden by any sends with a freq defined */ + rr3->carrier = 38000; + + rr3->rc = redrat3_init_rc_dev(rr3); + if (!rr3->rc) + goto error; + + setup_timer(&rr3->rx_timeout, redrat3_rx_timeout, (unsigned long)rr3); + + /* we can register the device now, as it is ready */ + usb_set_intfdata(intf, rr3); + + rr3_ftr(dev, "Exiting %s\n", __func__); + return 0; + +error: + redrat3_delete(rr3, rr3->udev); + +no_endpoints: + dev_err(dev, "%s: retval = %x", __func__, retval); + + return retval; +} + +static void __devexit redrat3_dev_disconnect(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct redrat3_dev *rr3 = usb_get_intfdata(intf); + + rr3_ftr(&intf->dev, "Entering %s\n", __func__); + + if (!rr3) + return; + + redrat3_disable_detector(rr3); + + usb_set_intfdata(intf, NULL); + rc_unregister_device(rr3->rc); + redrat3_delete(rr3, udev); + + rr3_ftr(&intf->dev, "RedRat3 IR Transceiver now disconnected\n"); +} + +static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct redrat3_dev *rr3 = usb_get_intfdata(intf); + rr3_ftr(rr3->dev, "suspend\n"); + usb_kill_urb(rr3->read_urb); + return 0; +} + +static int redrat3_dev_resume(struct usb_interface *intf) +{ + struct redrat3_dev *rr3 = usb_get_intfdata(intf); + rr3_ftr(rr3->dev, "resume\n"); + if (usb_submit_urb(rr3->read_urb, GFP_ATOMIC)) + return -EIO; + return 0; +} + +static struct usb_driver redrat3_dev_driver = { + .name = DRIVER_NAME, + .probe = redrat3_dev_probe, + .disconnect = redrat3_dev_disconnect, + .suspend = redrat3_dev_suspend, + .resume = redrat3_dev_resume, + .reset_resume = redrat3_dev_resume, + .id_table = redrat3_dev_table +}; + +static int __init redrat3_dev_init(void) +{ + int ret; + + ret = usb_register(&redrat3_dev_driver); + if (ret < 0) + pr_err(DRIVER_NAME + ": usb register failed, result = %d\n", ret); + + return ret; +} + +static void __exit redrat3_dev_exit(void) +{ + usb_deregister(&redrat3_dev_driver); +} + +module_init(redrat3_dev_init); +module_exit(redrat3_dev_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_AUTHOR(DRIVER_AUTHOR2); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, redrat3_dev_table); + +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable module debug spew. 0 = no debugging (default) " + "0x1 = standard debug messages, 0x2 = function tracing debug. " + "Flag bits are addative (i.e., 0x3 for both debug types)."); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/streamzap.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/streamzap.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/streamzap.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/streamzap.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,559 @@ +/* + * Streamzap Remote Control driver + * + * Copyright (c) 2005 Christoph Bartelmus + * Copyright (c) 2010 Jarod Wilson + * + * This driver was based on the work of Greg Wickham and Adrian + * Dewhurst. It was substantially rewritten to support correct signal + * gaps and now maintains a delay buffer, which is used to present + * consistent timing behaviour to user space applications. Without the + * delay buffer an ugly hack would be required in lircd, which can + * cause sluggish signal decoding in certain situations. + * + * Ported to in-kernel ir-core interface by Jarod Wilson + * + * This driver is based on the USB skeleton driver packaged with the + * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "1.61" +#define DRIVER_NAME "streamzap" +#define DRIVER_DESC "Streamzap Remote Control driver" + +#ifdef CONFIG_USB_DEBUG +static int debug = 1; +#else +static int debug; +#endif + +#define USB_STREAMZAP_VENDOR_ID 0x0e9c +#define USB_STREAMZAP_PRODUCT_ID 0x0000 + +/* table of devices that work with this driver */ +static struct usb_device_id streamzap_table[] = { + /* Streamzap Remote Control */ + { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) }, + /* Terminating entry */ + { } +}; + +MODULE_DEVICE_TABLE(usb, streamzap_table); + +#define SZ_PULSE_MASK 0xf0 +#define SZ_SPACE_MASK 0x0f +#define SZ_TIMEOUT 0xff +#define SZ_RESOLUTION 256 + +/* number of samples buffered */ +#define SZ_BUF_LEN 128 + +/* from ir-rc5-sz-decoder.c */ +#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE +#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder") +#else +#define load_rc5_sz_decode() {} +#endif + +enum StreamzapDecoderState { + PulseSpace, + FullPulse, + FullSpace, + IgnorePulse +}; + +/* structure to hold our device specific stuff */ +struct streamzap_ir { + /* ir-core */ + struct rc_dev *rdev; + + /* core device info */ + struct device *dev; + + /* usb */ + struct usb_device *usbdev; + struct usb_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct urb *urb_in; + + /* buffer & dma */ + unsigned char *buf_in; + dma_addr_t dma_in; + unsigned int buf_in_len; + + /* track what state we're in */ + enum StreamzapDecoderState decoder_state; + /* tracks whether we are currently receiving some signal */ + bool idle; + /* sum of signal lengths received since signal start */ + unsigned long sum; + /* start time of signal; necessary for gap tracking */ + struct timeval signal_last; + struct timeval signal_start; + bool timeout_enabled; + + char name[128]; + char phys[64]; +}; + + +/* local function prototypes */ +static int streamzap_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void streamzap_disconnect(struct usb_interface *interface); +static void streamzap_callback(struct urb *urb); +static int streamzap_suspend(struct usb_interface *intf, pm_message_t message); +static int streamzap_resume(struct usb_interface *intf); + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver streamzap_driver = { + .name = DRIVER_NAME, + .probe = streamzap_probe, + .disconnect = streamzap_disconnect, + .suspend = streamzap_suspend, + .resume = streamzap_resume, + .id_table = streamzap_table, +}; + +static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir) +{ + dev_dbg(sz->dev, "Storing %s with duration %u us\n", + (rawir.pulse ? "pulse" : "space"), rawir.duration); + ir_raw_event_store_with_filter(sz->rdev, &rawir); +} + +static void sz_push_full_pulse(struct streamzap_ir *sz, + unsigned char value) +{ + DEFINE_IR_RAW_EVENT(rawir); + + if (sz->idle) { + long deltv; + + sz->signal_last = sz->signal_start; + do_gettimeofday(&sz->signal_start); + + deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec; + rawir.pulse = false; + if (deltv > 15) { + /* really long time */ + rawir.duration = IR_MAX_DURATION; + } else { + rawir.duration = (int)(deltv * 1000000 + + sz->signal_start.tv_usec - + sz->signal_last.tv_usec); + rawir.duration -= sz->sum; + rawir.duration = US_TO_NS(rawir.duration); + rawir.duration &= IR_MAX_DURATION; + } + sz_push(sz, rawir); + + sz->idle = false; + sz->sum = 0; + } + + rawir.pulse = true; + rawir.duration = ((int) value) * SZ_RESOLUTION; + rawir.duration += SZ_RESOLUTION / 2; + sz->sum += rawir.duration; + rawir.duration = US_TO_NS(rawir.duration); + rawir.duration &= IR_MAX_DURATION; + sz_push(sz, rawir); +} + +static void sz_push_half_pulse(struct streamzap_ir *sz, + unsigned char value) +{ + sz_push_full_pulse(sz, (value & SZ_PULSE_MASK) >> 4); +} + +static void sz_push_full_space(struct streamzap_ir *sz, + unsigned char value) +{ + DEFINE_IR_RAW_EVENT(rawir); + + rawir.pulse = false; + rawir.duration = ((int) value) * SZ_RESOLUTION; + rawir.duration += SZ_RESOLUTION / 2; + sz->sum += rawir.duration; + rawir.duration = US_TO_NS(rawir.duration); + sz_push(sz, rawir); +} + +static void sz_push_half_space(struct streamzap_ir *sz, + unsigned long value) +{ + sz_push_full_space(sz, value & SZ_SPACE_MASK); +} + +/** + * streamzap_callback - usb IRQ handler callback + * + * This procedure is invoked on reception of data from + * the usb remote. + */ +static void streamzap_callback(struct urb *urb) +{ + struct streamzap_ir *sz; + unsigned int i; + int len; + + if (!urb) + return; + + sz = urb->context; + len = urb->actual_length; + + switch (urb->status) { + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* + * this urb is terminated, clean up. + * sz might already be invalid at this point + */ + dev_err(sz->dev, "urb terminated, status: %d\n", urb->status); + return; + default: + break; + } + + dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); + for (i = 0; i < len; i++) { + dev_dbg(sz->dev, "sz->buf_in[%d]: %x\n", + i, (unsigned char)sz->buf_in[i]); + switch (sz->decoder_state) { + case PulseSpace: + if ((sz->buf_in[i] & SZ_PULSE_MASK) == + SZ_PULSE_MASK) { + sz->decoder_state = FullPulse; + continue; + } else if ((sz->buf_in[i] & SZ_SPACE_MASK) + == SZ_SPACE_MASK) { + sz_push_half_pulse(sz, sz->buf_in[i]); + sz->decoder_state = FullSpace; + continue; + } else { + sz_push_half_pulse(sz, sz->buf_in[i]); + sz_push_half_space(sz, sz->buf_in[i]); + } + break; + case FullPulse: + sz_push_full_pulse(sz, sz->buf_in[i]); + sz->decoder_state = IgnorePulse; + break; + case FullSpace: + if (sz->buf_in[i] == SZ_TIMEOUT) { + DEFINE_IR_RAW_EVENT(rawir); + + rawir.pulse = false; + rawir.duration = sz->rdev->timeout; + sz->idle = true; + if (sz->timeout_enabled) + sz_push(sz, rawir); + ir_raw_event_handle(sz->rdev); + ir_raw_event_reset(sz->rdev); + } else { + sz_push_full_space(sz, sz->buf_in[i]); + } + sz->decoder_state = PulseSpace; + break; + case IgnorePulse: + if ((sz->buf_in[i] & SZ_SPACE_MASK) == + SZ_SPACE_MASK) { + sz->decoder_state = FullSpace; + continue; + } + sz_push_half_space(sz, sz->buf_in[i]); + sz->decoder_state = PulseSpace; + break; + } + } + + ir_raw_event_handle(sz->rdev); + usb_submit_urb(urb, GFP_ATOMIC); + + return; +} + +static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) +{ + struct rc_dev *rdev; + struct device *dev = sz->dev; + int ret; + + rdev = rc_allocate_device(); + if (!rdev) { + dev_err(dev, "remote dev allocation failed\n"); + goto out; + } + + snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared " + "Receiver (%04x:%04x)", + le16_to_cpu(sz->usbdev->descriptor.idVendor), + le16_to_cpu(sz->usbdev->descriptor.idProduct)); + usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys)); + strlcat(sz->phys, "/input0", sizeof(sz->phys)); + + rdev->input_name = sz->name; + rdev->input_phys = sz->phys; + usb_to_input_id(sz->usbdev, &rdev->input_id); + rdev->dev.parent = dev; + rdev->priv = sz; + rdev->driver_type = RC_DRIVER_IR_RAW; + rdev->allowed_protos = RC_TYPE_ALL; + rdev->driver_name = DRIVER_NAME; + rdev->map_name = RC_MAP_STREAMZAP; + + ret = rc_register_device(rdev); + if (ret < 0) { + dev_err(dev, "remote input device register failed\n"); + goto out; + } + + return rdev; + +out: + rc_free_device(rdev); + return NULL; +} + +/** + * streamzap_probe + * + * Called by usb-core to associated with a candidate device + * On any failure the return value is the ERROR + * On success return 0 + */ +static int __devinit streamzap_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *usbdev = interface_to_usbdev(intf); + struct usb_host_interface *iface_host; + struct streamzap_ir *sz = NULL; + char buf[63], name[128] = ""; + int retval = -ENOMEM; + int pipe, maxp; + + /* Allocate space for device driver specific data */ + sz = kzalloc(sizeof(struct streamzap_ir), GFP_KERNEL); + if (!sz) + return -ENOMEM; + + sz->usbdev = usbdev; + sz->interface = intf; + + /* Check to ensure endpoint information matches requirements */ + iface_host = intf->cur_altsetting; + + if (iface_host->desc.bNumEndpoints != 1) { + dev_err(&intf->dev, "%s: Unexpected desc.bNumEndpoints (%d)\n", + __func__, iface_host->desc.bNumEndpoints); + retval = -ENODEV; + goto free_sz; + } + + sz->endpoint = &(iface_host->endpoint[0].desc); + if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + != USB_DIR_IN) { + dev_err(&intf->dev, "%s: endpoint doesn't match input device " + "02%02x\n", __func__, sz->endpoint->bEndpointAddress); + retval = -ENODEV; + goto free_sz; + } + + if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + != USB_ENDPOINT_XFER_INT) { + dev_err(&intf->dev, "%s: endpoint attributes don't match xfer " + "02%02x\n", __func__, sz->endpoint->bmAttributes); + retval = -ENODEV; + goto free_sz; + } + + pipe = usb_rcvintpipe(usbdev, sz->endpoint->bEndpointAddress); + maxp = usb_maxpacket(usbdev, pipe, usb_pipeout(pipe)); + + if (maxp == 0) { + dev_err(&intf->dev, "%s: endpoint Max Packet Size is 0!?!\n", + __func__); + retval = -ENODEV; + goto free_sz; + } + + /* Allocate the USB buffer and IRQ URB */ + sz->buf_in = usb_alloc_coherent(usbdev, maxp, GFP_ATOMIC, &sz->dma_in); + if (!sz->buf_in) + goto free_sz; + + sz->urb_in = usb_alloc_urb(0, GFP_KERNEL); + if (!sz->urb_in) + goto free_buf_in; + + sz->dev = &intf->dev; + sz->buf_in_len = maxp; + + if (usbdev->descriptor.iManufacturer + && usb_string(usbdev, usbdev->descriptor.iManufacturer, + buf, sizeof(buf)) > 0) + strlcpy(name, buf, sizeof(name)); + + if (usbdev->descriptor.iProduct + && usb_string(usbdev, usbdev->descriptor.iProduct, + buf, sizeof(buf)) > 0) + snprintf(name + strlen(name), sizeof(name) - strlen(name), + " %s", buf); + + sz->rdev = streamzap_init_rc_dev(sz); + if (!sz->rdev) + goto rc_dev_fail; + + sz->idle = true; + sz->decoder_state = PulseSpace; + /* FIXME: don't yet have a way to set this */ + sz->timeout_enabled = true; + sz->rdev->timeout = ((US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION) & + IR_MAX_DURATION) | 0x03000000); + #if 0 + /* not yet supported, depends on patches from maxim */ + /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */ + sz->min_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION); + sz->max_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION); + #endif + + do_gettimeofday(&sz->signal_start); + + /* Complete final initialisations */ + usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in, + maxp, (usb_complete_t)streamzap_callback, + sz, sz->endpoint->bInterval); + sz->urb_in->transfer_dma = sz->dma_in; + sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + usb_set_intfdata(intf, sz); + + if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) + dev_err(sz->dev, "urb submit failed\n"); + + dev_info(sz->dev, "Registered %s on usb%d:%d\n", name, + usbdev->bus->busnum, usbdev->devnum); + + /* Load the streamzap not-quite-rc5 decoder too */ + load_rc5_sz_decode(); + + return 0; + +rc_dev_fail: + usb_free_urb(sz->urb_in); +free_buf_in: + usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in); +free_sz: + kfree(sz); + + return retval; +} + +/** + * streamzap_disconnect + * + * Called by the usb core when the device is removed from the system. + * + * This routine guarantees that the driver will not submit any more urbs + * by clearing dev->usbdev. It is also supposed to terminate any currently + * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(), + * does not provide any way to do this. + */ +static void streamzap_disconnect(struct usb_interface *interface) +{ + struct streamzap_ir *sz = usb_get_intfdata(interface); + struct usb_device *usbdev = interface_to_usbdev(interface); + + usb_set_intfdata(interface, NULL); + + if (!sz) + return; + + sz->usbdev = NULL; + rc_unregister_device(sz->rdev); + usb_kill_urb(sz->urb_in); + usb_free_urb(sz->urb_in); + usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in); + + kfree(sz); +} + +static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct streamzap_ir *sz = usb_get_intfdata(intf); + + usb_kill_urb(sz->urb_in); + + return 0; +} + +static int streamzap_resume(struct usb_interface *intf) +{ + struct streamzap_ir *sz = usb_get_intfdata(intf); + + if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { + dev_err(sz->dev, "Error sumbiting urb\n"); + return -EIO; + } + + return 0; +} + +/** + * streamzap_init + */ +static int __init streamzap_init(void) +{ + int ret; + + /* register this driver with the USB subsystem */ + ret = usb_register(&streamzap_driver); + if (ret < 0) + printk(KERN_ERR DRIVER_NAME ": usb register failed, " + "result = %d\n", ret); + + return ret; +} + +/** + * streamzap_exit + */ +static void __exit streamzap_exit(void) +{ + usb_deregister(&streamzap_driver); +} + + +module_init(streamzap_init); +module_exit(streamzap_exit); + +MODULE_AUTHOR("Jarod Wilson "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/winbond-cir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/winbond-cir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/winbond-cir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/rc/winbond-cir.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1179 @@ +/* + * winbond-cir.c - Driver for the Consumer IR functionality of Winbond + * SuperI/O chips. + * + * Currently supports the Winbond WPCD376i chip (PNP id WEC1022), but + * could probably support others (Winbond WEC102X, NatSemi, etc) + * with minor modifications. + * + * Original Author: David Härdeman + * Copyright (C) 2009 - 2011 David Härdeman + * + * Dedicated to my daughter Matilda, without whose loving attention this + * driver would have been finished in half the time and with a fraction + * of the bugs. + * + * Written using: + * o Winbond WPCD376I datasheet helpfully provided by Jesse Barnes at Intel + * o NatSemi PC87338/PC97338 datasheet (for the serial port stuff) + * o DSDT dumps + * + * Supported features: + * o IR Receive + * o IR Transmit + * o Wake-On-CIR functionality + * + * To do: + * o Learning + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "winbond-cir" + +/* CEIR Wake-Up Registers, relative to data->wbase */ +#define WBCIR_REG_WCEIR_CTL 0x03 /* CEIR Receiver Control */ +#define WBCIR_REG_WCEIR_STS 0x04 /* CEIR Receiver Status */ +#define WBCIR_REG_WCEIR_EV_EN 0x05 /* CEIR Receiver Event Enable */ +#define WBCIR_REG_WCEIR_CNTL 0x06 /* CEIR Receiver Counter Low */ +#define WBCIR_REG_WCEIR_CNTH 0x07 /* CEIR Receiver Counter High */ +#define WBCIR_REG_WCEIR_INDEX 0x08 /* CEIR Receiver Index */ +#define WBCIR_REG_WCEIR_DATA 0x09 /* CEIR Receiver Data */ +#define WBCIR_REG_WCEIR_CSL 0x0A /* CEIR Re. Compare Strlen */ +#define WBCIR_REG_WCEIR_CFG1 0x0B /* CEIR Re. Configuration 1 */ +#define WBCIR_REG_WCEIR_CFG2 0x0C /* CEIR Re. Configuration 2 */ + +/* CEIR Enhanced Functionality Registers, relative to data->ebase */ +#define WBCIR_REG_ECEIR_CTS 0x00 /* Enhanced IR Control Status */ +#define WBCIR_REG_ECEIR_CCTL 0x01 /* Infrared Counter Control */ +#define WBCIR_REG_ECEIR_CNT_LO 0x02 /* Infrared Counter LSB */ +#define WBCIR_REG_ECEIR_CNT_HI 0x03 /* Infrared Counter MSB */ +#define WBCIR_REG_ECEIR_IREM 0x04 /* Infrared Emitter Status */ + +/* SP3 Banked Registers, relative to data->sbase */ +#define WBCIR_REG_SP3_BSR 0x03 /* Bank Select, all banks */ + /* Bank 0 */ +#define WBCIR_REG_SP3_RXDATA 0x00 /* FIFO RX data (r) */ +#define WBCIR_REG_SP3_TXDATA 0x00 /* FIFO TX data (w) */ +#define WBCIR_REG_SP3_IER 0x01 /* Interrupt Enable */ +#define WBCIR_REG_SP3_EIR 0x02 /* Event Identification (r) */ +#define WBCIR_REG_SP3_FCR 0x02 /* FIFO Control (w) */ +#define WBCIR_REG_SP3_MCR 0x04 /* Mode Control */ +#define WBCIR_REG_SP3_LSR 0x05 /* Link Status */ +#define WBCIR_REG_SP3_MSR 0x06 /* Modem Status */ +#define WBCIR_REG_SP3_ASCR 0x07 /* Aux Status and Control */ + /* Bank 2 */ +#define WBCIR_REG_SP3_BGDL 0x00 /* Baud Divisor LSB */ +#define WBCIR_REG_SP3_BGDH 0x01 /* Baud Divisor MSB */ +#define WBCIR_REG_SP3_EXCR1 0x02 /* Extended Control 1 */ +#define WBCIR_REG_SP3_EXCR2 0x04 /* Extended Control 2 */ +#define WBCIR_REG_SP3_TXFLV 0x06 /* TX FIFO Level */ +#define WBCIR_REG_SP3_RXFLV 0x07 /* RX FIFO Level */ + /* Bank 3 */ +#define WBCIR_REG_SP3_MRID 0x00 /* Module Identification */ +#define WBCIR_REG_SP3_SH_LCR 0x01 /* LCR Shadow */ +#define WBCIR_REG_SP3_SH_FCR 0x02 /* FCR Shadow */ + /* Bank 4 */ +#define WBCIR_REG_SP3_IRCR1 0x02 /* Infrared Control 1 */ + /* Bank 5 */ +#define WBCIR_REG_SP3_IRCR2 0x04 /* Infrared Control 2 */ + /* Bank 6 */ +#define WBCIR_REG_SP3_IRCR3 0x00 /* Infrared Control 3 */ +#define WBCIR_REG_SP3_SIR_PW 0x02 /* SIR Pulse Width */ + /* Bank 7 */ +#define WBCIR_REG_SP3_IRRXDC 0x00 /* IR RX Demod Control */ +#define WBCIR_REG_SP3_IRTXMC 0x01 /* IR TX Mod Control */ +#define WBCIR_REG_SP3_RCCFG 0x02 /* CEIR Config */ +#define WBCIR_REG_SP3_IRCFG1 0x04 /* Infrared Config 1 */ +#define WBCIR_REG_SP3_IRCFG4 0x07 /* Infrared Config 4 */ + +/* + * Magic values follow + */ + +/* No interrupts for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ +#define WBCIR_IRQ_NONE 0x00 +/* RX data bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ +#define WBCIR_IRQ_RX 0x01 +/* TX data low bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ +#define WBCIR_IRQ_TX_LOW 0x02 +/* Over/Under-flow bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ +#define WBCIR_IRQ_ERR 0x04 +/* TX data empty bit for WBCEIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */ +#define WBCIR_IRQ_TX_EMPTY 0x20 +/* Led enable/disable bit for WBCIR_REG_ECEIR_CTS */ +#define WBCIR_LED_ENABLE 0x80 +/* RX data available bit for WBCIR_REG_SP3_LSR */ +#define WBCIR_RX_AVAIL 0x01 +/* RX data overrun error bit for WBCIR_REG_SP3_LSR */ +#define WBCIR_RX_OVERRUN 0x02 +/* TX End-Of-Transmission bit for WBCIR_REG_SP3_ASCR */ +#define WBCIR_TX_EOT 0x04 +/* RX disable bit for WBCIR_REG_SP3_ASCR */ +#define WBCIR_RX_DISABLE 0x20 +/* TX data underrun error bit for WBCIR_REG_SP3_ASCR */ +#define WBCIR_TX_UNDERRUN 0x40 +/* Extended mode enable bit for WBCIR_REG_SP3_EXCR1 */ +#define WBCIR_EXT_ENABLE 0x01 +/* Select compare register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */ +#define WBCIR_REGSEL_COMPARE 0x10 +/* Select mask register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */ +#define WBCIR_REGSEL_MASK 0x20 +/* Starting address of selected register in WBCIR_REG_WCEIR_INDEX */ +#define WBCIR_REG_ADDR0 0x00 + +/* Valid banks for the SP3 UART */ +enum wbcir_bank { + WBCIR_BANK_0 = 0x00, + WBCIR_BANK_1 = 0x80, + WBCIR_BANK_2 = 0xE0, + WBCIR_BANK_3 = 0xE4, + WBCIR_BANK_4 = 0xE8, + WBCIR_BANK_5 = 0xEC, + WBCIR_BANK_6 = 0xF0, + WBCIR_BANK_7 = 0xF4, +}; + +/* Supported power-on IR Protocols */ +enum wbcir_protocol { + IR_PROTOCOL_RC5 = 0x0, + IR_PROTOCOL_NEC = 0x1, + IR_PROTOCOL_RC6 = 0x2, +}; + +/* Possible states for IR reception */ +enum wbcir_rxstate { + WBCIR_RXSTATE_INACTIVE = 0, + WBCIR_RXSTATE_ACTIVE, + WBCIR_RXSTATE_ERROR +}; + +/* Possible states for IR transmission */ +enum wbcir_txstate { + WBCIR_TXSTATE_INACTIVE = 0, + WBCIR_TXSTATE_ACTIVE, + WBCIR_TXSTATE_DONE, + WBCIR_TXSTATE_ERROR +}; + +/* Misc */ +#define WBCIR_NAME "Winbond CIR" +#define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */ +#define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */ +#define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */ +#define WAKEUP_IOMEM_LEN 0x10 /* Wake-Up I/O Reg Len */ +#define EHFUNC_IOMEM_LEN 0x10 /* Enhanced Func I/O Reg Len */ +#define SP_IOMEM_LEN 0x08 /* Serial Port 3 (IR) Reg Len */ + +/* Per-device data */ +struct wbcir_data { + spinlock_t spinlock; + struct rc_dev *dev; + struct led_classdev led; + + unsigned long wbase; /* Wake-Up Baseaddr */ + unsigned long ebase; /* Enhanced Func. Baseaddr */ + unsigned long sbase; /* Serial Port Baseaddr */ + unsigned int irq; /* Serial Port IRQ */ + u8 irqmask; + + /* RX state */ + enum wbcir_rxstate rxstate; + struct led_trigger *rxtrigger; + struct ir_raw_event rxev; + + /* TX state */ + enum wbcir_txstate txstate; + struct led_trigger *txtrigger; + u32 txlen; + u32 txoff; + u32 *txbuf; + wait_queue_head_t txwaitq; + u8 txmask; + u32 txcarrier; +}; + +static enum wbcir_protocol protocol = IR_PROTOCOL_RC6; +module_param(protocol, uint, 0444); +MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command " + "(0 = RC5, 1 = NEC, 2 = RC6A, default)"); + +static int invert; /* default = 0 */ +module_param(invert, bool, 0444); +MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver"); + +static int txandrx; /* default = 0 */ +module_param(txandrx, bool, 0444); +MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX"); + +static unsigned int wake_sc = 0x800F040C; +module_param(wake_sc, uint, 0644); +MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command"); + +static unsigned int wake_rc6mode = 6; +module_param(wake_rc6mode, uint, 0644); +MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command " + "(0 = 0, 6 = 6A, default)"); + + + +/***************************************************************************** + * + * UTILITY FUNCTIONS + * + *****************************************************************************/ + +/* Caller needs to hold wbcir_lock */ +static void +wbcir_set_bits(unsigned long addr, u8 bits, u8 mask) +{ + u8 val; + + val = inb(addr); + val = ((val & ~mask) | (bits & mask)); + outb(val, addr); +} + +/* Selects the register bank for the serial port */ +static inline void +wbcir_select_bank(struct wbcir_data *data, enum wbcir_bank bank) +{ + outb(bank, data->sbase + WBCIR_REG_SP3_BSR); +} + +static inline void +wbcir_set_irqmask(struct wbcir_data *data, u8 irqmask) +{ + if (data->irqmask == irqmask) + return; + + wbcir_select_bank(data, WBCIR_BANK_0); + outb(irqmask, data->sbase + WBCIR_REG_SP3_IER); + data->irqmask = irqmask; +} + +static enum led_brightness +wbcir_led_brightness_get(struct led_classdev *led_cdev) +{ + struct wbcir_data *data = container_of(led_cdev, + struct wbcir_data, + led); + + if (inb(data->ebase + WBCIR_REG_ECEIR_CTS) & WBCIR_LED_ENABLE) + return LED_FULL; + else + return LED_OFF; +} + +static void +wbcir_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct wbcir_data *data = container_of(led_cdev, + struct wbcir_data, + led); + + wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CTS, + brightness == LED_OFF ? 0x00 : WBCIR_LED_ENABLE, + WBCIR_LED_ENABLE); +} + +/* Manchester encodes bits to RC6 message cells (see wbcir_shutdown) */ +static u8 +wbcir_to_rc6cells(u8 val) +{ + u8 coded = 0x00; + int i; + + val &= 0x0F; + for (i = 0; i < 4; i++) { + if (val & 0x01) + coded |= 0x02 << (i * 2); + else + coded |= 0x01 << (i * 2); + val >>= 1; + } + + return coded; +} + +/***************************************************************************** + * + * INTERRUPT FUNCTIONS + * + *****************************************************************************/ + +static void +wbcir_idle_rx(struct rc_dev *dev, bool idle) +{ + struct wbcir_data *data = dev->priv; + + if (!idle && data->rxstate == WBCIR_RXSTATE_INACTIVE) { + data->rxstate = WBCIR_RXSTATE_ACTIVE; + led_trigger_event(data->rxtrigger, LED_FULL); + } + + if (idle && data->rxstate != WBCIR_RXSTATE_INACTIVE) + /* Tell hardware to go idle by setting RXINACTIVE */ + outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR); +} + +static void +wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device) +{ + u8 irdata; + DEFINE_IR_RAW_EVENT(rawir); + + /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */ + while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) { + irdata = inb(data->sbase + WBCIR_REG_SP3_RXDATA); + if (data->rxstate == WBCIR_RXSTATE_ERROR) + continue; + rawir.pulse = irdata & 0x80 ? false : true; + rawir.duration = US_TO_NS((irdata & 0x7F) * 10); + ir_raw_event_store_with_filter(data->dev, &rawir); + } + + /* Check if we should go idle */ + if (data->dev->idle) { + led_trigger_event(data->rxtrigger, LED_OFF); + data->rxstate = WBCIR_RXSTATE_INACTIVE; + } + + ir_raw_event_handle(data->dev); +} + +static void +wbcir_irq_tx(struct wbcir_data *data) +{ + unsigned int space; + unsigned int used; + u8 bytes[16]; + u8 byte; + + if (!data->txbuf) + return; + + switch (data->txstate) { + case WBCIR_TXSTATE_INACTIVE: + /* TX FIFO empty */ + space = 16; + led_trigger_event(data->txtrigger, LED_FULL); + break; + case WBCIR_TXSTATE_ACTIVE: + /* TX FIFO low (3 bytes or less) */ + space = 13; + break; + case WBCIR_TXSTATE_ERROR: + space = 0; + break; + default: + return; + } + + /* + * TX data is run-length coded in bytes: YXXXXXXX + * Y = space (1) or pulse (0) + * X = duration, encoded as (X + 1) * 10us (i.e 10 to 1280 us) + */ + for (used = 0; used < space && data->txoff != data->txlen; used++) { + if (data->txbuf[data->txoff] == 0) { + data->txoff++; + continue; + } + byte = min((u32)0x80, data->txbuf[data->txoff]); + data->txbuf[data->txoff] -= byte; + byte--; + byte |= (data->txoff % 2 ? 0x80 : 0x00); /* pulse/space */ + bytes[used] = byte; + } + + while (data->txbuf[data->txoff] == 0 && data->txoff != data->txlen) + data->txoff++; + + if (used == 0) { + /* Finished */ + if (data->txstate == WBCIR_TXSTATE_ERROR) + /* Clear TX underrun bit */ + outb(WBCIR_TX_UNDERRUN, data->sbase + WBCIR_REG_SP3_ASCR); + else + data->txstate = WBCIR_TXSTATE_DONE; + wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR); + led_trigger_event(data->txtrigger, LED_OFF); + wake_up(&data->txwaitq); + } else if (data->txoff == data->txlen) { + /* At the end of transmission, tell the hw before last byte */ + outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1); + outb(WBCIR_TX_EOT, data->sbase + WBCIR_REG_SP3_ASCR); + outb(bytes[used - 1], data->sbase + WBCIR_REG_SP3_TXDATA); + wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR | + WBCIR_IRQ_TX_EMPTY); + } else { + /* More data to follow... */ + outsb(data->sbase + WBCIR_REG_SP3_RXDATA, bytes, used); + if (data->txstate == WBCIR_TXSTATE_INACTIVE) { + wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR | + WBCIR_IRQ_TX_LOW); + data->txstate = WBCIR_TXSTATE_ACTIVE; + } + } +} + +static irqreturn_t +wbcir_irq_handler(int irqno, void *cookie) +{ + struct pnp_dev *device = cookie; + struct wbcir_data *data = pnp_get_drvdata(device); + unsigned long flags; + u8 status; + + spin_lock_irqsave(&data->spinlock, flags); + wbcir_select_bank(data, WBCIR_BANK_0); + status = inb(data->sbase + WBCIR_REG_SP3_EIR); + status &= data->irqmask; + + if (!status) { + spin_unlock_irqrestore(&data->spinlock, flags); + return IRQ_NONE; + } + + if (status & WBCIR_IRQ_ERR) { + /* RX overflow? (read clears bit) */ + if (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_OVERRUN) { + data->rxstate = WBCIR_RXSTATE_ERROR; + ir_raw_event_reset(data->dev); + } + + /* TX underflow? */ + if (inb(data->sbase + WBCIR_REG_SP3_ASCR) & WBCIR_TX_UNDERRUN) + data->txstate = WBCIR_TXSTATE_ERROR; + } + + if (status & WBCIR_IRQ_RX) + wbcir_irq_rx(data, device); + + if (status & (WBCIR_IRQ_TX_LOW | WBCIR_IRQ_TX_EMPTY)) + wbcir_irq_tx(data); + + spin_unlock_irqrestore(&data->spinlock, flags); + return IRQ_HANDLED; +} + +/***************************************************************************** + * + * RC-CORE INTERFACE FUNCTIONS + * + *****************************************************************************/ + +static int +wbcir_txcarrier(struct rc_dev *dev, u32 carrier) +{ + struct wbcir_data *data = dev->priv; + unsigned long flags; + u8 val; + u32 freq; + + freq = DIV_ROUND_CLOSEST(carrier, 1000); + if (freq < 30 || freq > 60) + return -EINVAL; + + switch (freq) { + case 58: + case 59: + case 60: + val = freq - 58; + freq *= 1000; + break; + case 57: + val = freq - 27; + freq = 56900; + break; + default: + val = freq - 27; + freq *= 1000; + break; + } + + spin_lock_irqsave(&data->spinlock, flags); + if (data->txstate != WBCIR_TXSTATE_INACTIVE) { + spin_unlock_irqrestore(&data->spinlock, flags); + return -EBUSY; + } + + if (data->txcarrier != freq) { + wbcir_select_bank(data, WBCIR_BANK_7); + wbcir_set_bits(data->sbase + WBCIR_REG_SP3_IRTXMC, val, 0x1F); + data->txcarrier = freq; + } + + spin_unlock_irqrestore(&data->spinlock, flags); + return 0; +} + +static int +wbcir_txmask(struct rc_dev *dev, u32 mask) +{ + struct wbcir_data *data = dev->priv; + unsigned long flags; + u8 val; + + /* Four outputs, only one output can be enabled at a time */ + switch (mask) { + case 0x1: + val = 0x0; + break; + case 0x2: + val = 0x1; + break; + case 0x4: + val = 0x2; + break; + case 0x8: + val = 0x3; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&data->spinlock, flags); + if (data->txstate != WBCIR_TXSTATE_INACTIVE) { + spin_unlock_irqrestore(&data->spinlock, flags); + return -EBUSY; + } + + if (data->txmask != mask) { + wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CTS, val, 0x0c); + data->txmask = mask; + } + + spin_unlock_irqrestore(&data->spinlock, flags); + return 0; +} + +static int +wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count) +{ + struct wbcir_data *data = dev->priv; + unsigned i; + unsigned long flags; + + /* Not sure if this is possible, but better safe than sorry */ + spin_lock_irqsave(&data->spinlock, flags); + if (data->txstate != WBCIR_TXSTATE_INACTIVE) { + spin_unlock_irqrestore(&data->spinlock, flags); + return -EBUSY; + } + + /* Convert values to multiples of 10us */ + for (i = 0; i < count; i++) + buf[i] = DIV_ROUND_CLOSEST(buf[i], 10); + + /* Fill the TX fifo once, the irq handler will do the rest */ + data->txbuf = buf; + data->txlen = count; + data->txoff = 0; + wbcir_irq_tx(data); + + /* Wait for the TX to complete */ + while (data->txstate == WBCIR_TXSTATE_ACTIVE) { + spin_unlock_irqrestore(&data->spinlock, flags); + wait_event(data->txwaitq, data->txstate != WBCIR_TXSTATE_ACTIVE); + spin_lock_irqsave(&data->spinlock, flags); + } + + /* We're done */ + if (data->txstate == WBCIR_TXSTATE_ERROR) + count = -EAGAIN; + data->txstate = WBCIR_TXSTATE_INACTIVE; + data->txbuf = NULL; + spin_unlock_irqrestore(&data->spinlock, flags); + + return count; +} + +/***************************************************************************** + * + * SETUP/INIT/SUSPEND/RESUME FUNCTIONS + * + *****************************************************************************/ + +static void +wbcir_shutdown(struct pnp_dev *device) +{ + struct device *dev = &device->dev; + struct wbcir_data *data = pnp_get_drvdata(device); + bool do_wake = true; + u8 match[11]; + u8 mask[11]; + u8 rc6_csl = 0; + int i; + + memset(match, 0, sizeof(match)); + memset(mask, 0, sizeof(mask)); + + if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) { + do_wake = false; + goto finish; + } + + switch (protocol) { + case IR_PROTOCOL_RC5: + if (wake_sc > 0xFFF) { + do_wake = false; + dev_err(dev, "RC5 - Invalid wake scancode\n"); + break; + } + + /* Mask = 13 bits, ex toggle */ + mask[0] = 0xFF; + mask[1] = 0x17; + + match[0] = (wake_sc & 0x003F); /* 6 command bits */ + match[0] |= (wake_sc & 0x0180) >> 1; /* 2 address bits */ + match[1] = (wake_sc & 0x0E00) >> 9; /* 3 address bits */ + if (!(wake_sc & 0x0040)) /* 2nd start bit */ + match[1] |= 0x10; + + break; + + case IR_PROTOCOL_NEC: + if (wake_sc > 0xFFFFFF) { + do_wake = false; + dev_err(dev, "NEC - Invalid wake scancode\n"); + break; + } + + mask[0] = mask[1] = mask[2] = mask[3] = 0xFF; + + match[1] = bitrev8((wake_sc & 0xFF)); + match[0] = ~match[1]; + + match[3] = bitrev8((wake_sc & 0xFF00) >> 8); + if (wake_sc > 0xFFFF) + match[2] = bitrev8((wake_sc & 0xFF0000) >> 16); + else + match[2] = ~match[3]; + + break; + + case IR_PROTOCOL_RC6: + + if (wake_rc6mode == 0) { + if (wake_sc > 0xFFFF) { + do_wake = false; + dev_err(dev, "RC6 - Invalid wake scancode\n"); + break; + } + + /* Command */ + match[0] = wbcir_to_rc6cells(wake_sc >> 0); + mask[0] = 0xFF; + match[1] = wbcir_to_rc6cells(wake_sc >> 4); + mask[1] = 0xFF; + + /* Address */ + match[2] = wbcir_to_rc6cells(wake_sc >> 8); + mask[2] = 0xFF; + match[3] = wbcir_to_rc6cells(wake_sc >> 12); + mask[3] = 0xFF; + + /* Header */ + match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */ + mask[4] = 0xF0; + match[5] = 0x09; /* start bit = 1, mode2 = 0 */ + mask[5] = 0x0F; + + rc6_csl = 44; + + } else if (wake_rc6mode == 6) { + i = 0; + + /* Command */ + match[i] = wbcir_to_rc6cells(wake_sc >> 0); + mask[i++] = 0xFF; + match[i] = wbcir_to_rc6cells(wake_sc >> 4); + mask[i++] = 0xFF; + + /* Address + Toggle */ + match[i] = wbcir_to_rc6cells(wake_sc >> 8); + mask[i++] = 0xFF; + match[i] = wbcir_to_rc6cells(wake_sc >> 12); + mask[i++] = 0x3F; + + /* Customer bits 7 - 0 */ + match[i] = wbcir_to_rc6cells(wake_sc >> 16); + mask[i++] = 0xFF; + match[i] = wbcir_to_rc6cells(wake_sc >> 20); + mask[i++] = 0xFF; + + if (wake_sc & 0x80000000) { + /* Customer range bit and bits 15 - 8 */ + match[i] = wbcir_to_rc6cells(wake_sc >> 24); + mask[i++] = 0xFF; + match[i] = wbcir_to_rc6cells(wake_sc >> 28); + mask[i++] = 0xFF; + rc6_csl = 76; + } else if (wake_sc <= 0x007FFFFF) { + rc6_csl = 60; + } else { + do_wake = false; + dev_err(dev, "RC6 - Invalid wake scancode\n"); + break; + } + + /* Header */ + match[i] = 0x93; /* mode1 = mode0 = 1, submode = 0 */ + mask[i++] = 0xFF; + match[i] = 0x0A; /* start bit = 1, mode2 = 1 */ + mask[i++] = 0x0F; + + } else { + do_wake = false; + dev_err(dev, "RC6 - Invalid wake mode\n"); + } + + break; + + default: + do_wake = false; + break; + } + +finish: + if (do_wake) { + /* Set compare and compare mask */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX, + WBCIR_REGSEL_COMPARE | WBCIR_REG_ADDR0, + 0x3F); + outsb(data->wbase + WBCIR_REG_WCEIR_DATA, match, 11); + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX, + WBCIR_REGSEL_MASK | WBCIR_REG_ADDR0, + 0x3F); + outsb(data->wbase + WBCIR_REG_WCEIR_DATA, mask, 11); + + /* RC6 Compare String Len */ + outb(rc6_csl, data->wbase + WBCIR_REG_WCEIR_CSL); + + /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); + + /* Clear BUFF_EN, Clear END_EN, Set MATCH_EN */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x01, 0x07); + + /* Set CEIR_EN */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x01, 0x01); + + } else { + /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); + + /* Clear CEIR_EN */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01); + } + + /* + * ACPI will set the HW disable bit for SP3 which means that the + * output signals are left in an undefined state which may cause + * spurious interrupts which we need to ignore until the hardware + * is reinitialized. + */ + wbcir_set_irqmask(data, WBCIR_IRQ_NONE); + disable_irq(data->irq); + + /* Disable LED */ + led_trigger_event(data->rxtrigger, LED_OFF); + led_trigger_event(data->txtrigger, LED_OFF); +} + +static int +wbcir_suspend(struct pnp_dev *device, pm_message_t state) +{ + wbcir_shutdown(device); + return 0; +} + +static void +wbcir_init_hw(struct wbcir_data *data) +{ + u8 tmp; + + /* Disable interrupts */ + wbcir_set_irqmask(data, WBCIR_IRQ_NONE); + + /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */ + tmp = protocol << 4; + if (invert) + tmp |= 0x08; + outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL); + + /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); + + /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); + + /* Set RC5 cell time to correspond to 36 kHz */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CFG1, 0x4A, 0x7F); + + /* Set IRTX_INV */ + if (invert) + outb(0x04, data->ebase + WBCIR_REG_ECEIR_CCTL); + else + outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL); + + /* + * Clear IR LED, set SP3 clock to 24Mhz, set TX mask to IRTX1, + * set SP3_IRRX_SW to binary 01, helpfully not documented + */ + outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS); + data->txmask = 0x1; + + /* Enable extended mode */ + wbcir_select_bank(data, WBCIR_BANK_2); + outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1); + + /* + * Configure baud generator, IR data will be sampled at + * a bitrate of: (24Mhz * prescaler) / (divisor * 16). + * + * The ECIR registers include a flag to change the + * 24Mhz clock freq to 48Mhz. + * + * It's not documented in the specs, but fifo levels + * other than 16 seems to be unsupported. + */ + + /* prescaler 1.0, tx/rx fifo lvl 16 */ + outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2); + + /* Set baud divisor to sample every 10 us */ + outb(0x0F, data->sbase + WBCIR_REG_SP3_BGDL); + outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH); + + /* Set CEIR mode */ + wbcir_select_bank(data, WBCIR_BANK_0); + outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR); + inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */ + inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */ + + /* Disable RX demod, enable run-length enc/dec, set freq span */ + wbcir_select_bank(data, WBCIR_BANK_7); + outb(0x90, data->sbase + WBCIR_REG_SP3_RCCFG); + + /* Disable timer */ + wbcir_select_bank(data, WBCIR_BANK_4); + outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1); + + /* Disable MSR interrupt, clear AUX_IRX, mask RX during TX? */ + wbcir_select_bank(data, WBCIR_BANK_5); + outb(txandrx ? 0x03 : 0x02, data->sbase + WBCIR_REG_SP3_IRCR2); + + /* Disable CRC */ + wbcir_select_bank(data, WBCIR_BANK_6); + outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3); + + /* Set RX demodulation freq, not really used */ + wbcir_select_bank(data, WBCIR_BANK_7); + outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC); + + /* Set TX modulation, 36kHz, 7us pulse width */ + outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC); + data->txcarrier = 36000; + + /* Set invert and pin direction */ + if (invert) + outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4); + else + outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4); + + /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */ + wbcir_select_bank(data, WBCIR_BANK_0); + outb(0x97, data->sbase + WBCIR_REG_SP3_FCR); + + /* Clear AUX status bits */ + outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR); + + /* Clear RX state */ + data->rxstate = WBCIR_RXSTATE_INACTIVE; + data->rxev.duration = 0; + ir_raw_event_reset(data->dev); + ir_raw_event_handle(data->dev); + + /* + * Check TX state, if we did a suspend/resume cycle while TX was + * active, we will have a process waiting in txwaitq. + */ + if (data->txstate == WBCIR_TXSTATE_ACTIVE) { + data->txstate = WBCIR_TXSTATE_ERROR; + wake_up(&data->txwaitq); + } + + /* Enable interrupts */ + wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR); +} + +static int +wbcir_resume(struct pnp_dev *device) +{ + struct wbcir_data *data = pnp_get_drvdata(device); + + wbcir_init_hw(data); + enable_irq(data->irq); + + return 0; +} + +static int __devinit +wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) +{ + struct device *dev = &device->dev; + struct wbcir_data *data; + int err; + + if (!(pnp_port_len(device, 0) == EHFUNC_IOMEM_LEN && + pnp_port_len(device, 1) == WAKEUP_IOMEM_LEN && + pnp_port_len(device, 2) == SP_IOMEM_LEN)) { + dev_err(dev, "Invalid resources\n"); + return -ENODEV; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + pnp_set_drvdata(device, data); + + spin_lock_init(&data->spinlock); + init_waitqueue_head(&data->txwaitq); + data->ebase = pnp_port_start(device, 0); + data->wbase = pnp_port_start(device, 1); + data->sbase = pnp_port_start(device, 2); + data->irq = pnp_irq(device, 0); + + if (data->wbase == 0 || data->ebase == 0 || + data->sbase == 0 || data->irq == 0) { + err = -ENODEV; + dev_err(dev, "Invalid resources\n"); + goto exit_free_data; + } + + dev_dbg(&device->dev, "Found device " + "(w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n", + data->wbase, data->ebase, data->sbase, data->irq); + + if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) { + dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", + data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1); + err = -EBUSY; + goto exit_free_data; + } + + if (!request_region(data->ebase, EHFUNC_IOMEM_LEN, DRVNAME)) { + dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", + data->ebase, data->ebase + EHFUNC_IOMEM_LEN - 1); + err = -EBUSY; + goto exit_release_wbase; + } + + if (!request_region(data->sbase, SP_IOMEM_LEN, DRVNAME)) { + dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", + data->sbase, data->sbase + SP_IOMEM_LEN - 1); + err = -EBUSY; + goto exit_release_ebase; + } + + err = request_irq(data->irq, wbcir_irq_handler, + IRQF_DISABLED, DRVNAME, device); + if (err) { + dev_err(dev, "Failed to claim IRQ %u\n", data->irq); + err = -EBUSY; + goto exit_release_sbase; + } + + led_trigger_register_simple("cir-tx", &data->txtrigger); + if (!data->txtrigger) { + err = -ENOMEM; + goto exit_free_irq; + } + + led_trigger_register_simple("cir-rx", &data->rxtrigger); + if (!data->rxtrigger) { + err = -ENOMEM; + goto exit_unregister_txtrigger; + } + + data->led.name = "cir::activity"; + data->led.default_trigger = "cir-rx"; + data->led.brightness_set = wbcir_led_brightness_set; + data->led.brightness_get = wbcir_led_brightness_get; + err = led_classdev_register(&device->dev, &data->led); + if (err) + goto exit_unregister_rxtrigger; + + data->dev = rc_allocate_device(); + if (!data->dev) { + err = -ENOMEM; + goto exit_unregister_led; + } + + data->dev->driver_name = WBCIR_NAME; + data->dev->input_name = WBCIR_NAME; + data->dev->input_phys = "wbcir/cir0"; + data->dev->input_id.bustype = BUS_HOST; + data->dev->input_id.vendor = PCI_VENDOR_ID_WINBOND; + data->dev->input_id.product = WBCIR_ID_FAMILY; + data->dev->input_id.version = WBCIR_ID_CHIP; + data->dev->map_name = RC_MAP_RC6_MCE; + data->dev->s_idle = wbcir_idle_rx; + data->dev->s_tx_mask = wbcir_txmask; + data->dev->s_tx_carrier = wbcir_txcarrier; + data->dev->tx_ir = wbcir_tx; + data->dev->priv = data; + data->dev->dev.parent = &device->dev; + + err = rc_register_device(data->dev); + if (err) + goto exit_free_rc; + + device_init_wakeup(&device->dev, 1); + + wbcir_init_hw(data); + + return 0; + +exit_free_rc: + rc_free_device(data->dev); +exit_unregister_led: + led_classdev_unregister(&data->led); +exit_unregister_rxtrigger: + led_trigger_unregister_simple(data->rxtrigger); +exit_unregister_txtrigger: + led_trigger_unregister_simple(data->txtrigger); +exit_free_irq: + free_irq(data->irq, device); +exit_release_sbase: + release_region(data->sbase, SP_IOMEM_LEN); +exit_release_ebase: + release_region(data->ebase, EHFUNC_IOMEM_LEN); +exit_release_wbase: + release_region(data->wbase, WAKEUP_IOMEM_LEN); +exit_free_data: + kfree(data); + pnp_set_drvdata(device, NULL); +exit: + return err; +} + +static void __devexit +wbcir_remove(struct pnp_dev *device) +{ + struct wbcir_data *data = pnp_get_drvdata(device); + + /* Disable interrupts */ + wbcir_set_irqmask(data, WBCIR_IRQ_NONE); + free_irq(data->irq, device); + + /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); + + /* Clear CEIR_EN */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01); + + /* Clear BUFF_EN, END_EN, MATCH_EN */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07); + + rc_unregister_device(data->dev); + + led_trigger_unregister_simple(data->rxtrigger); + led_trigger_unregister_simple(data->txtrigger); + led_classdev_unregister(&data->led); + + /* This is ok since &data->led isn't actually used */ + wbcir_led_brightness_set(&data->led, LED_OFF); + + release_region(data->wbase, WAKEUP_IOMEM_LEN); + release_region(data->ebase, EHFUNC_IOMEM_LEN); + release_region(data->sbase, SP_IOMEM_LEN); + + kfree(data); + + pnp_set_drvdata(device, NULL); +} + +static const struct pnp_device_id wbcir_ids[] = { + { "WEC1022", 0 }, + { "", 0 } +}; +MODULE_DEVICE_TABLE(pnp, wbcir_ids); + +static struct pnp_driver wbcir_driver = { + .name = WBCIR_NAME, + .id_table = wbcir_ids, + .probe = wbcir_probe, + .remove = __devexit_p(wbcir_remove), + .suspend = wbcir_suspend, + .resume = wbcir_resume, + .shutdown = wbcir_shutdown +}; + +static int __init +wbcir_init(void) +{ + int ret; + + switch (protocol) { + case IR_PROTOCOL_RC5: + case IR_PROTOCOL_NEC: + case IR_PROTOCOL_RC6: + break; + default: + printk(KERN_ERR DRVNAME ": Invalid power-on protocol\n"); + } + + ret = pnp_register_driver(&wbcir_driver); + if (ret) + printk(KERN_ERR DRVNAME ": Unable to register driver\n"); + + return ret; +} + +static void __exit +wbcir_exit(void) +{ + pnp_unregister_driver(&wbcir_driver); +} + +module_init(wbcir_init); +module_exit(wbcir_exit); + +MODULE_AUTHOR("David Härdeman "); +MODULE_DESCRIPTION("Winbond SuperI/O Consumer IR Driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7170.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7170.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7170.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7170.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,359 @@ +/* + * adv7170 - adv7170, adv7171 video encoder driver version 0.0.1 + * + * Copyright (C) 2002 Maxim Yevtyushkin + * + * Based on adv7176 driver by: + * + * Copyright (C) 1998 Dave Perks + * Copyright (C) 1999 Wolfgang Scherr + * Copyright (C) 2000 Serguei Miridonov + * - some corrections for Pinnacle Systems Inc. DC10plus card. + * + * Changes by Ronald Bultje + * - moved over to linux>=2.4.x i2c protocol (1/1/2003) + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver"); +MODULE_AUTHOR("Maxim Yevtyushkin"); +MODULE_LICENSE("GPL"); + + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +/* ----------------------------------------------------------------------- */ + +struct adv7170 { + struct v4l2_subdev sd; + unsigned char reg[128]; + + v4l2_std_id norm; + int input; +}; + +static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd) +{ + return container_of(sd, struct adv7170, sd); +} + +static char *inputs[] = { "pass_through", "play_back" }; + +/* ----------------------------------------------------------------------- */ + +static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct adv7170 *encoder = to_adv7170(sd); + + encoder->reg[reg] = value; + return i2c_smbus_write_byte_data(client, reg, value); +} + +static inline int adv7170_read(struct v4l2_subdev *sd, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_read_byte_data(client, reg); +} + +static int adv7170_write_block(struct v4l2_subdev *sd, + const u8 *data, unsigned int len) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct adv7170 *encoder = to_adv7170(sd); + int ret = -1; + u8 reg; + + /* the adv7170 has an autoincrement function, use it if + * the adapter understands raw I2C */ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /* do raw I2C, not smbus compatible */ + u8 block_data[32]; + int block_len; + + while (len >= 2) { + block_len = 0; + block_data[block_len++] = reg = data[0]; + do { + block_data[block_len++] = + encoder->reg[reg++] = data[1]; + len -= 2; + data += 2; + } while (len >= 2 && data[0] == reg && block_len < 32); + ret = i2c_master_send(client, block_data, block_len); + if (ret < 0) + break; + } + } else { + /* do some slow I2C emulation kind of thing */ + while (len >= 2) { + reg = *data++; + ret = adv7170_write(sd, reg, *data++); + if (ret < 0) + break; + len -= 2; + } + } + return ret; +} + +/* ----------------------------------------------------------------------- */ + +#define TR0MODE 0x4c +#define TR0RST 0x80 + +#define TR1CAPT 0x00 +#define TR1PLAY 0x00 + +static const unsigned char init_NTSC[] = { + 0x00, 0x10, /* MR0 */ + 0x01, 0x20, /* MR1 */ + 0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */ + 0x03, 0x80, /* MR3 */ + 0x04, 0x30, /* MR4 */ + 0x05, 0x00, /* Reserved */ + 0x06, 0x00, /* Reserved */ + 0x07, TR0MODE, /* TM0 */ + 0x08, TR1CAPT, /* TM1 */ + 0x09, 0x16, /* Fsc0 */ + 0x0a, 0x7c, /* Fsc1 */ + 0x0b, 0xf0, /* Fsc2 */ + 0x0c, 0x21, /* Fsc3 */ + 0x0d, 0x00, /* Subcarrier Phase */ + 0x0e, 0x00, /* Closed Capt. Ext 0 */ + 0x0f, 0x00, /* Closed Capt. Ext 1 */ + 0x10, 0x00, /* Closed Capt. 0 */ + 0x11, 0x00, /* Closed Capt. 1 */ + 0x12, 0x00, /* Pedestal Ctl 0 */ + 0x13, 0x00, /* Pedestal Ctl 1 */ + 0x14, 0x00, /* Pedestal Ctl 2 */ + 0x15, 0x00, /* Pedestal Ctl 3 */ + 0x16, 0x00, /* CGMS_WSS_0 */ + 0x17, 0x00, /* CGMS_WSS_1 */ + 0x18, 0x00, /* CGMS_WSS_2 */ + 0x19, 0x00, /* Teletext Ctl */ +}; + +static const unsigned char init_PAL[] = { + 0x00, 0x71, /* MR0 */ + 0x01, 0x20, /* MR1 */ + 0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */ + 0x03, 0x80, /* MR3 */ + 0x04, 0x30, /* MR4 */ + 0x05, 0x00, /* Reserved */ + 0x06, 0x00, /* Reserved */ + 0x07, TR0MODE, /* TM0 */ + 0x08, TR1CAPT, /* TM1 */ + 0x09, 0xcb, /* Fsc0 */ + 0x0a, 0x8a, /* Fsc1 */ + 0x0b, 0x09, /* Fsc2 */ + 0x0c, 0x2a, /* Fsc3 */ + 0x0d, 0x00, /* Subcarrier Phase */ + 0x0e, 0x00, /* Closed Capt. Ext 0 */ + 0x0f, 0x00, /* Closed Capt. Ext 1 */ + 0x10, 0x00, /* Closed Capt. 0 */ + 0x11, 0x00, /* Closed Capt. 1 */ + 0x12, 0x00, /* Pedestal Ctl 0 */ + 0x13, 0x00, /* Pedestal Ctl 1 */ + 0x14, 0x00, /* Pedestal Ctl 2 */ + 0x15, 0x00, /* Pedestal Ctl 3 */ + 0x16, 0x00, /* CGMS_WSS_0 */ + 0x17, 0x00, /* CGMS_WSS_1 */ + 0x18, 0x00, /* CGMS_WSS_2 */ + 0x19, 0x00, /* Teletext Ctl */ +}; + + +static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7170 *encoder = to_adv7170(sd); + + v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); + + if (std & V4L2_STD_NTSC) { + adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC)); + if (encoder->input == 0) + adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */ + adv7170_write(sd, 0x07, TR0MODE | TR0RST); + adv7170_write(sd, 0x07, TR0MODE); + } else if (std & V4L2_STD_PAL) { + adv7170_write_block(sd, init_PAL, sizeof(init_PAL)); + if (encoder->input == 0) + adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */ + adv7170_write(sd, 0x07, TR0MODE | TR0RST); + adv7170_write(sd, 0x07, TR0MODE); + } else { + v4l2_dbg(1, debug, sd, "illegal norm: %llx\n", + (unsigned long long)std); + return -EINVAL; + } + v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std); + encoder->norm = std; + return 0; +} + +static int adv7170_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct adv7170 *encoder = to_adv7170(sd); + + /* RJ: input = 0: input is from decoder + input = 1: input is from ZR36060 + input = 2: color bar */ + + v4l2_dbg(1, debug, sd, "set input from %s\n", + input == 0 ? "decoder" : "ZR36060"); + + switch (input) { + case 0: + adv7170_write(sd, 0x01, 0x20); + adv7170_write(sd, 0x08, TR1CAPT); /* TR1 */ + adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */ + adv7170_write(sd, 0x07, TR0MODE | TR0RST); + adv7170_write(sd, 0x07, TR0MODE); + /* udelay(10); */ + break; + + case 1: + adv7170_write(sd, 0x01, 0x00); + adv7170_write(sd, 0x08, TR1PLAY); /* TR1 */ + adv7170_write(sd, 0x02, 0x08); + adv7170_write(sd, 0x07, TR0MODE | TR0RST); + adv7170_write(sd, 0x07, TR0MODE); + /* udelay(10); */ + break; + + default: + v4l2_dbg(1, debug, sd, "illegal input: %d\n", input); + return -EINVAL; + } + v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]); + encoder->input = input; + return 0; +} + +static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7170, 0); +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops adv7170_core_ops = { + .g_chip_ident = adv7170_g_chip_ident, +}; + +static const struct v4l2_subdev_video_ops adv7170_video_ops = { + .s_std_output = adv7170_s_std_output, + .s_routing = adv7170_s_routing, +}; + +static const struct v4l2_subdev_ops adv7170_ops = { + .core = &adv7170_core_ops, + .video = &adv7170_video_ops, +}; + +/* ----------------------------------------------------------------------- */ + +static int adv7170_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adv7170 *encoder; + struct v4l2_subdev *sd; + int i; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL); + if (encoder == NULL) + return -ENOMEM; + sd = &encoder->sd; + v4l2_i2c_subdev_init(sd, client, &adv7170_ops); + encoder->norm = V4L2_STD_NTSC; + encoder->input = 0; + + i = adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC)); + if (i >= 0) { + i = adv7170_write(sd, 0x07, TR0MODE | TR0RST); + i = adv7170_write(sd, 0x07, TR0MODE); + i = adv7170_read(sd, 0x12); + v4l2_dbg(1, debug, sd, "revision %d\n", i & 1); + } + if (i < 0) + v4l2_dbg(1, debug, sd, "init error 0x%x\n", i); + return 0; +} + +static int adv7170_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_adv7170(sd)); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id adv7170_id[] = { + { "adv7170", 0 }, + { "adv7171", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adv7170_id); + +static struct i2c_driver adv7170_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv7170", + }, + .probe = adv7170_probe, + .remove = adv7170_remove, + .id_table = adv7170_id, +}; + +static __init int init_adv7170(void) +{ + return i2c_add_driver(&adv7170_driver); +} + +static __exit void exit_adv7170(void) +{ + i2c_del_driver(&adv7170_driver); +} + +module_init(init_adv7170); +module_exit(exit_adv7170); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7175.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7175.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7175.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7175.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,409 @@ +/* + * adv7175 - adv7175a video encoder driver version 0.0.3 + * + * Copyright (C) 1998 Dave Perks + * Copyright (C) 1999 Wolfgang Scherr + * Copyright (C) 2000 Serguei Miridonov + * - some corrections for Pinnacle Systems Inc. DC10plus card. + * + * Changes by Ronald Bultje + * - moved over to linux>=2.4.x i2c protocol (9/9/2002) + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver"); +MODULE_AUTHOR("Dave Perks"); +MODULE_LICENSE("GPL"); + +#define I2C_ADV7175 0xd4 +#define I2C_ADV7176 0x54 + + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +/* ----------------------------------------------------------------------- */ + +struct adv7175 { + struct v4l2_subdev sd; + v4l2_std_id norm; + int input; +}; + +static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd) +{ + return container_of(sd, struct adv7175, sd); +} + +static char *inputs[] = { "pass_through", "play_back", "color_bar" }; + +/* ----------------------------------------------------------------------- */ + +static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +static inline int adv7175_read(struct v4l2_subdev *sd, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_read_byte_data(client, reg); +} + +static int adv7175_write_block(struct v4l2_subdev *sd, + const u8 *data, unsigned int len) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = -1; + u8 reg; + + /* the adv7175 has an autoincrement function, use it if + * the adapter understands raw I2C */ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /* do raw I2C, not smbus compatible */ + u8 block_data[32]; + int block_len; + + while (len >= 2) { + block_len = 0; + block_data[block_len++] = reg = data[0]; + do { + block_data[block_len++] = data[1]; + reg++; + len -= 2; + data += 2; + } while (len >= 2 && data[0] == reg && block_len < 32); + ret = i2c_master_send(client, block_data, block_len); + if (ret < 0) + break; + } + } else { + /* do some slow I2C emulation kind of thing */ + while (len >= 2) { + reg = *data++; + ret = adv7175_write(sd, reg, *data++); + if (ret < 0) + break; + len -= 2; + } + } + + return ret; +} + +static void set_subcarrier_freq(struct v4l2_subdev *sd, int pass_through) +{ + /* for some reason pass_through NTSC needs + * a different sub-carrier freq to remain stable. */ + if (pass_through) + adv7175_write(sd, 0x02, 0x00); + else + adv7175_write(sd, 0x02, 0x55); + + adv7175_write(sd, 0x03, 0x55); + adv7175_write(sd, 0x04, 0x55); + adv7175_write(sd, 0x05, 0x25); +} + +/* ----------------------------------------------------------------------- */ +/* Output filter: S-Video Composite */ + +#define MR050 0x11 /* 0x09 */ +#define MR060 0x14 /* 0x0c */ + +/* ----------------------------------------------------------------------- */ + +#define TR0MODE 0x46 +#define TR0RST 0x80 + +#define TR1CAPT 0x80 +#define TR1PLAY 0x00 + +static const unsigned char init_common[] = { + + 0x00, MR050, /* MR0, PAL enabled */ + 0x01, 0x00, /* MR1 */ + 0x02, 0x0c, /* subc. freq. */ + 0x03, 0x8c, /* subc. freq. */ + 0x04, 0x79, /* subc. freq. */ + 0x05, 0x26, /* subc. freq. */ + 0x06, 0x40, /* subc. phase */ + + 0x07, TR0MODE, /* TR0, 16bit */ + 0x08, 0x21, /* */ + 0x09, 0x00, /* */ + 0x0a, 0x00, /* */ + 0x0b, 0x00, /* */ + 0x0c, TR1CAPT, /* TR1 */ + 0x0d, 0x4f, /* MR2 */ + 0x0e, 0x00, /* */ + 0x0f, 0x00, /* */ + 0x10, 0x00, /* */ + 0x11, 0x00, /* */ +}; + +static const unsigned char init_pal[] = { + 0x00, MR050, /* MR0, PAL enabled */ + 0x01, 0x00, /* MR1 */ + 0x02, 0x0c, /* subc. freq. */ + 0x03, 0x8c, /* subc. freq. */ + 0x04, 0x79, /* subc. freq. */ + 0x05, 0x26, /* subc. freq. */ + 0x06, 0x40, /* subc. phase */ +}; + +static const unsigned char init_ntsc[] = { + 0x00, MR060, /* MR0, NTSC enabled */ + 0x01, 0x00, /* MR1 */ + 0x02, 0x55, /* subc. freq. */ + 0x03, 0x55, /* subc. freq. */ + 0x04, 0x55, /* subc. freq. */ + 0x05, 0x25, /* subc. freq. */ + 0x06, 0x1a, /* subc. phase */ +}; + +static int adv7175_init(struct v4l2_subdev *sd, u32 val) +{ + /* This is just for testing!!! */ + adv7175_write_block(sd, init_common, sizeof(init_common)); + adv7175_write(sd, 0x07, TR0MODE | TR0RST); + adv7175_write(sd, 0x07, TR0MODE); + return 0; +} + +static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7175 *encoder = to_adv7175(sd); + + if (std & V4L2_STD_NTSC) { + adv7175_write_block(sd, init_ntsc, sizeof(init_ntsc)); + if (encoder->input == 0) + adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */ + adv7175_write(sd, 0x07, TR0MODE | TR0RST); + adv7175_write(sd, 0x07, TR0MODE); + } else if (std & V4L2_STD_PAL) { + adv7175_write_block(sd, init_pal, sizeof(init_pal)); + if (encoder->input == 0) + adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */ + adv7175_write(sd, 0x07, TR0MODE | TR0RST); + adv7175_write(sd, 0x07, TR0MODE); + } else if (std & V4L2_STD_SECAM) { + /* This is an attempt to convert + * SECAM->PAL (typically it does not work + * due to genlock: when decoder is in SECAM + * and encoder in in PAL the subcarrier can + * not be syncronized with horizontal + * quency) */ + adv7175_write_block(sd, init_pal, sizeof(init_pal)); + if (encoder->input == 0) + adv7175_write(sd, 0x0d, 0x49); /* Disable genlock */ + adv7175_write(sd, 0x07, TR0MODE | TR0RST); + adv7175_write(sd, 0x07, TR0MODE); + } else { + v4l2_dbg(1, debug, sd, "illegal norm: %llx\n", + (unsigned long long)std); + return -EINVAL; + } + v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std); + encoder->norm = std; + return 0; +} + +static int adv7175_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct adv7175 *encoder = to_adv7175(sd); + + /* RJ: input = 0: input is from decoder + input = 1: input is from ZR36060 + input = 2: color bar */ + + switch (input) { + case 0: + adv7175_write(sd, 0x01, 0x00); + + if (encoder->norm & V4L2_STD_NTSC) + set_subcarrier_freq(sd, 1); + + adv7175_write(sd, 0x0c, TR1CAPT); /* TR1 */ + if (encoder->norm & V4L2_STD_SECAM) + adv7175_write(sd, 0x0d, 0x49); /* Disable genlock */ + else + adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */ + adv7175_write(sd, 0x07, TR0MODE | TR0RST); + adv7175_write(sd, 0x07, TR0MODE); + /*udelay(10);*/ + break; + + case 1: + adv7175_write(sd, 0x01, 0x00); + + if (encoder->norm & V4L2_STD_NTSC) + set_subcarrier_freq(sd, 0); + + adv7175_write(sd, 0x0c, TR1PLAY); /* TR1 */ + adv7175_write(sd, 0x0d, 0x49); + adv7175_write(sd, 0x07, TR0MODE | TR0RST); + adv7175_write(sd, 0x07, TR0MODE); + /* udelay(10); */ + break; + + case 2: + adv7175_write(sd, 0x01, 0x80); + + if (encoder->norm & V4L2_STD_NTSC) + set_subcarrier_freq(sd, 0); + + adv7175_write(sd, 0x0d, 0x49); + adv7175_write(sd, 0x07, TR0MODE | TR0RST); + adv7175_write(sd, 0x07, TR0MODE); + /* udelay(10); */ + break; + + default: + v4l2_dbg(1, debug, sd, "illegal input: %d\n", input); + return -EINVAL; + } + v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]); + encoder->input = input; + return 0; +} + +static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0); +} + +static int adv7175_s_power(struct v4l2_subdev *sd, int on) +{ + if (on) + adv7175_write(sd, 0x01, 0x00); + else + adv7175_write(sd, 0x01, 0x78); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops adv7175_core_ops = { + .g_chip_ident = adv7175_g_chip_ident, + .init = adv7175_init, + .s_power = adv7175_s_power, +}; + +static const struct v4l2_subdev_video_ops adv7175_video_ops = { + .s_std_output = adv7175_s_std_output, + .s_routing = adv7175_s_routing, +}; + +static const struct v4l2_subdev_ops adv7175_ops = { + .core = &adv7175_core_ops, + .video = &adv7175_video_ops, +}; + +/* ----------------------------------------------------------------------- */ + +static int adv7175_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int i; + struct adv7175 *encoder; + struct v4l2_subdev *sd; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL); + if (encoder == NULL) + return -ENOMEM; + sd = &encoder->sd; + v4l2_i2c_subdev_init(sd, client, &adv7175_ops); + encoder->norm = V4L2_STD_NTSC; + encoder->input = 0; + + i = adv7175_write_block(sd, init_common, sizeof(init_common)); + if (i >= 0) { + i = adv7175_write(sd, 0x07, TR0MODE | TR0RST); + i = adv7175_write(sd, 0x07, TR0MODE); + i = adv7175_read(sd, 0x12); + v4l2_dbg(1, debug, sd, "revision %d\n", i & 1); + } + if (i < 0) + v4l2_dbg(1, debug, sd, "init error 0x%x\n", i); + return 0; +} + +static int adv7175_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_adv7175(sd)); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id adv7175_id[] = { + { "adv7175", 0 }, + { "adv7176", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adv7175_id); + +static struct i2c_driver adv7175_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv7175", + }, + .probe = adv7175_probe, + .remove = adv7175_remove, + .id_table = adv7175_id, +}; + +static __init int init_adv7175(void) +{ + return i2c_add_driver(&adv7175_driver); +} + +static __exit void exit_adv7175(void) +{ + i2c_del_driver(&adv7175_driver); +} + +module_init(init_adv7175); +module_exit(exit_adv7175); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7180.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7180.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7180.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7180.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,463 @@ +/* + * adv7180.c Analog Devices ADV7180 video decoder driver + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "adv7180" + +#define ADV7180_INPUT_CONTROL_REG 0x00 +#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00 +#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10 +#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20 +#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30 +#define ADV7180_INPUT_CONTROL_NTSC_J 0x40 +#define ADV7180_INPUT_CONTROL_NTSC_M 0x50 +#define ADV7180_INPUT_CONTROL_PAL60 0x60 +#define ADV7180_INPUT_CONTROL_NTSC_443 0x70 +#define ADV7180_INPUT_CONTROL_PAL_BG 0x80 +#define ADV7180_INPUT_CONTROL_PAL_N 0x90 +#define ADV7180_INPUT_CONTROL_PAL_M 0xa0 +#define ADV7180_INPUT_CONTROL_PAL_M_PED 0xb0 +#define ADV7180_INPUT_CONTROL_PAL_COMB_N 0xc0 +#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED 0xd0 +#define ADV7180_INPUT_CONTROL_PAL_SECAM 0xe0 +#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED 0xf0 + +#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG 0x04 +#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 + +#define ADV7180_AUTODETECT_ENABLE_REG 0x07 +#define ADV7180_AUTODETECT_DEFAULT 0x7f + +#define ADV7180_ADI_CTRL_REG 0x0e +#define ADV7180_ADI_CTRL_IRQ_SPACE 0x20 + +#define ADV7180_STATUS1_REG 0x10 +#define ADV7180_STATUS1_IN_LOCK 0x01 +#define ADV7180_STATUS1_AUTOD_MASK 0x70 +#define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00 +#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10 +#define ADV7180_STATUS1_AUTOD_PAL_M 0x20 +#define ADV7180_STATUS1_AUTOD_PAL_60 0x30 +#define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40 +#define ADV7180_STATUS1_AUTOD_SECAM 0x50 +#define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60 +#define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 + +#define ADV7180_IDENT_REG 0x11 +#define ADV7180_ID_7180 0x18 + +#define ADV7180_ICONF1_ADI 0x40 +#define ADV7180_ICONF1_ACTIVE_LOW 0x01 +#define ADV7180_ICONF1_PSYNC_ONLY 0x10 +#define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 + +#define ADV7180_IRQ1_LOCK 0x01 +#define ADV7180_IRQ1_UNLOCK 0x02 +#define ADV7180_ISR1_ADI 0x42 +#define ADV7180_ICR1_ADI 0x43 +#define ADV7180_IMR1_ADI 0x44 +#define ADV7180_IMR2_ADI 0x48 +#define ADV7180_IRQ3_AD_CHANGE 0x08 +#define ADV7180_ISR3_ADI 0x4A +#define ADV7180_ICR3_ADI 0x4B +#define ADV7180_IMR3_ADI 0x4C +#define ADV7180_IMR4_ADI 0x50 + +struct adv7180_state { + struct v4l2_subdev sd; + struct work_struct work; + struct mutex mutex; /* mutual excl. when accessing chip */ + int irq; + v4l2_std_id curr_norm; + bool autodetect; +}; + +static v4l2_std_id adv7180_std_to_v4l2(u8 status1) +{ + switch (status1 & ADV7180_STATUS1_AUTOD_MASK) { + case ADV7180_STATUS1_AUTOD_NTSM_M_J: + return V4L2_STD_NTSC; + case ADV7180_STATUS1_AUTOD_NTSC_4_43: + return V4L2_STD_NTSC_443; + case ADV7180_STATUS1_AUTOD_PAL_M: + return V4L2_STD_PAL_M; + case ADV7180_STATUS1_AUTOD_PAL_60: + return V4L2_STD_PAL_60; + case ADV7180_STATUS1_AUTOD_PAL_B_G: + return V4L2_STD_PAL; + case ADV7180_STATUS1_AUTOD_SECAM: + return V4L2_STD_SECAM; + case ADV7180_STATUS1_AUTOD_PAL_COMB: + return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; + case ADV7180_STATUS1_AUTOD_SECAM_525: + return V4L2_STD_SECAM; + default: + return V4L2_STD_UNKNOWN; + } +} + +static int v4l2_std_to_adv7180(v4l2_std_id std) +{ + if (std == V4L2_STD_PAL_60) + return ADV7180_INPUT_CONTROL_PAL60; + if (std == V4L2_STD_NTSC_443) + return ADV7180_INPUT_CONTROL_NTSC_443; + if (std == V4L2_STD_PAL_N) + return ADV7180_INPUT_CONTROL_PAL_N; + if (std == V4L2_STD_PAL_M) + return ADV7180_INPUT_CONTROL_PAL_M; + if (std == V4L2_STD_PAL_Nc) + return ADV7180_INPUT_CONTROL_PAL_COMB_N; + + if (std & V4L2_STD_PAL) + return ADV7180_INPUT_CONTROL_PAL_BG; + if (std & V4L2_STD_NTSC) + return ADV7180_INPUT_CONTROL_NTSC_M; + if (std & V4L2_STD_SECAM) + return ADV7180_INPUT_CONTROL_PAL_SECAM; + + return -EINVAL; +} + +static u32 adv7180_status_to_v4l2(u8 status1) +{ + if (!(status1 & ADV7180_STATUS1_IN_LOCK)) + return V4L2_IN_ST_NO_SIGNAL; + + return 0; +} + +static int __adv7180_status(struct i2c_client *client, u32 *status, + v4l2_std_id *std) +{ + int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG); + + if (status1 < 0) + return status1; + + if (status) + *status = adv7180_status_to_v4l2(status1); + if (std) + *std = adv7180_std_to_v4l2(status1); + + return 0; +} + +static inline struct adv7180_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct adv7180_state, sd); +} + +static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct adv7180_state *state = to_state(sd); + int err = mutex_lock_interruptible(&state->mutex); + if (err) + return err; + + /* when we are interrupt driven we know the state */ + if (!state->autodetect || state->irq > 0) + *std = state->curr_norm; + else + err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std); + + mutex_unlock(&state->mutex); + return err; +} + +static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + struct adv7180_state *state = to_state(sd); + int ret = mutex_lock_interruptible(&state->mutex); + if (ret) + return ret; + + ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL); + mutex_unlock(&state->mutex); + return ret; +} + +static int adv7180_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0); +} + +static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7180_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = mutex_lock_interruptible(&state->mutex); + if (ret) + return ret; + + /* all standards -> autodetect */ + if (std == V4L2_STD_ALL) { + ret = i2c_smbus_write_byte_data(client, + ADV7180_INPUT_CONTROL_REG, + ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM); + if (ret < 0) + goto out; + + __adv7180_status(client, NULL, &state->curr_norm); + state->autodetect = true; + } else { + ret = v4l2_std_to_adv7180(std); + if (ret < 0) + goto out; + + ret = i2c_smbus_write_byte_data(client, + ADV7180_INPUT_CONTROL_REG, ret); + if (ret < 0) + goto out; + + state->curr_norm = std; + state->autodetect = false; + } + ret = 0; +out: + mutex_unlock(&state->mutex); + return ret; +} + +static const struct v4l2_subdev_video_ops adv7180_video_ops = { + .querystd = adv7180_querystd, + .g_input_status = adv7180_g_input_status, +}; + +static const struct v4l2_subdev_core_ops adv7180_core_ops = { + .g_chip_ident = adv7180_g_chip_ident, + .s_std = adv7180_s_std, +}; + +static const struct v4l2_subdev_ops adv7180_ops = { + .core = &adv7180_core_ops, + .video = &adv7180_video_ops, +}; + +static void adv7180_work(struct work_struct *work) +{ + struct adv7180_state *state = container_of(work, struct adv7180_state, + work); + struct i2c_client *client = v4l2_get_subdevdata(&state->sd); + u8 isr3; + + mutex_lock(&state->mutex); + i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, + ADV7180_ADI_CTRL_IRQ_SPACE); + isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI); + /* clear */ + i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3); + i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0); + + if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect) + __adv7180_status(client, NULL, &state->curr_norm); + mutex_unlock(&state->mutex); + + enable_irq(state->irq); +} + +static irqreturn_t adv7180_irq(int irq, void *devid) +{ + struct adv7180_state *state = devid; + + schedule_work(&state->work); + + disable_irq_nosync(state->irq); + + return IRQ_HANDLED; +} + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static __devinit int adv7180_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adv7180_state *state; + struct v4l2_subdev *sd; + int ret; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL); + if (state == NULL) { + ret = -ENOMEM; + goto err; + } + + state->irq = client->irq; + INIT_WORK(&state->work, adv7180_work); + mutex_init(&state->mutex); + state->autodetect = true; + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &adv7180_ops); + + /* Initialize adv7180 */ + /* Enable autodetection */ + ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG, + ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM); + if (ret < 0) + goto err_unreg_subdev; + + ret = i2c_smbus_write_byte_data(client, ADV7180_AUTODETECT_ENABLE_REG, + ADV7180_AUTODETECT_DEFAULT); + if (ret < 0) + goto err_unreg_subdev; + + /* ITU-R BT.656-4 compatible */ + ret = i2c_smbus_write_byte_data(client, + ADV7180_EXTENDED_OUTPUT_CONTROL_REG, + ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); + if (ret < 0) + goto err_unreg_subdev; + + /* read current norm */ + __adv7180_status(client, NULL, &state->curr_norm); + + /* register for interrupts */ + if (state->irq > 0) { + ret = request_irq(state->irq, adv7180_irq, 0, DRIVER_NAME, + state); + if (ret) + goto err_unreg_subdev; + + ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, + ADV7180_ADI_CTRL_IRQ_SPACE); + if (ret < 0) + goto err_unreg_subdev; + + /* config the Interrupt pin to be active low */ + ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI, + ADV7180_ICONF1_ACTIVE_LOW | ADV7180_ICONF1_PSYNC_ONLY); + if (ret < 0) + goto err_unreg_subdev; + + ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0); + if (ret < 0) + goto err_unreg_subdev; + + ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0); + if (ret < 0) + goto err_unreg_subdev; + + /* enable AD change interrupts interrupts */ + ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI, + ADV7180_IRQ3_AD_CHANGE); + if (ret < 0) + goto err_unreg_subdev; + + ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0); + if (ret < 0) + goto err_unreg_subdev; + + ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, + 0); + if (ret < 0) + goto err_unreg_subdev; + } + + return 0; + +err_unreg_subdev: + mutex_destroy(&state->mutex); + v4l2_device_unregister_subdev(sd); + kfree(state); +err: + printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", ret); + return ret; +} + +static __devexit int adv7180_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct adv7180_state *state = to_state(sd); + + if (state->irq > 0) { + free_irq(client->irq, state); + if (cancel_work_sync(&state->work)) { + /* + * Work was pending, therefore we need to enable + * IRQ here to balance the disable_irq() done in the + * interrupt handler. + */ + enable_irq(state->irq); + } + } + + mutex_destroy(&state->mutex); + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); + return 0; +} + +static const struct i2c_device_id adv7180_id[] = { + {DRIVER_NAME, 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, adv7180_id); + +static struct i2c_driver adv7180_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, + .probe = adv7180_probe, + .remove = __devexit_p(adv7180_remove), + .id_table = adv7180_id, +}; + +static __init int adv7180_init(void) +{ + return i2c_add_driver(&adv7180_driver); +} + +static __exit void adv7180_exit(void) +{ + i2c_del_driver(&adv7180_driver); +} + +module_init(adv7180_init); +module_exit(adv7180_exit); + +MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); +MODULE_AUTHOR("Mocean Laboratories"); +MODULE_LICENSE("GPL v2"); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7343.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7343.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7343.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7343.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,489 @@ +/* + * adv7343 - ADV7343 Video Encoder Driver + * + * The encoder hardware does not support SECAM. + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "adv7343_regs.h" + +MODULE_DESCRIPTION("ADV7343 video encoder driver"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +struct adv7343_state { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + u8 reg00; + u8 reg01; + u8 reg02; + u8 reg35; + u8 reg80; + u8 reg82; + u32 output; + v4l2_std_id std; +}; + +static inline struct adv7343_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct adv7343_state, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd; +} + +static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +static const u8 adv7343_init_reg_val[] = { + ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT, + ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT, + + ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT, + ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT, + ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT, + ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT, + ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT, + ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT, + ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT, + + ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT, + ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT, + ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT, + ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT, + ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT, + ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT, + ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT, + ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT, + + ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT, + ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT, + ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT, +}; + +/* + * 2^32 + * FSC(reg) = FSC (HZ) * -------- + * 27000000 + */ +static const struct adv7343_std_info stdinfo[] = { + { + /* FSC(Hz) = 3,579,545.45 Hz */ + SD_STD_NTSC, 569408542, V4L2_STD_NTSC, + }, { + /* FSC(Hz) = 3,575,611.00 Hz */ + SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M, + }, { + /* FSC(Hz) = 3,582,056.00 */ + SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60, + }, +}; + +static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7343_state *state = to_state(sd); + struct adv7343_std_info *std_info; + int output_idx, num_std; + char *fsc_ptr; + u8 reg, val; + int err = 0; + int i = 0; + + output_idx = state->output; + + std_info = (struct adv7343_std_info *)stdinfo; + num_std = ARRAY_SIZE(stdinfo); + + for (i = 0; i < num_std; i++) { + if (std_info[i].stdid & std) + break; + } + + if (i == num_std) { + v4l2_dbg(1, debug, sd, + "Invalid std or std is not supported: %llx\n", + (unsigned long long)std); + return -EINVAL; + } + + /* Set the standard */ + val = state->reg80 & (~(SD_STD_MASK)); + val |= std_info[i].standard_val3; + err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); + if (err < 0) + goto setstd_exit; + + state->reg80 = val; + + /* Configure the input mode register */ + val = state->reg01 & (~((u8) INPUT_MODE_MASK)); + val |= SD_INPUT_MODE; + err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val); + if (err < 0) + goto setstd_exit; + + state->reg01 = val; + + /* Program the sub carrier frequency registers */ + fsc_ptr = (unsigned char *)&std_info[i].fsc_val; + reg = ADV7343_FSC_REG0; + for (i = 0; i < 4; i++, reg++, fsc_ptr++) { + err = adv7343_write(sd, reg, *fsc_ptr); + if (err < 0) + goto setstd_exit; + } + + val = state->reg80; + + /* Filter settings */ + if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443)) + val &= 0x03; + else if (std & ~V4L2_STD_SECAM) + val |= 0x04; + + err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); + if (err < 0) + goto setstd_exit; + + state->reg80 = val; + +setstd_exit: + if (err != 0) + v4l2_err(sd, "Error setting std, write failed\n"); + + return err; +} + +static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type) +{ + struct adv7343_state *state = to_state(sd); + unsigned char val; + int err = 0; + + if (output_type > ADV7343_SVIDEO_ID) { + v4l2_dbg(1, debug, sd, + "Invalid output type or output type not supported:%d\n", + output_type); + return -EINVAL; + } + + /* Enable Appropriate DAC */ + val = state->reg00 & 0x03; + + if (output_type == ADV7343_COMPOSITE_ID) + val |= ADV7343_COMPOSITE_POWER_VALUE; + else if (output_type == ADV7343_COMPONENT_ID) + val |= ADV7343_COMPONENT_POWER_VALUE; + else + val |= ADV7343_SVIDEO_POWER_VALUE; + + err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val); + if (err < 0) + goto setoutput_exit; + + state->reg00 = val; + + /* Enable YUV output */ + val = state->reg02 | YUV_OUTPUT_SELECT; + err = adv7343_write(sd, ADV7343_MODE_REG0, val); + if (err < 0) + goto setoutput_exit; + + state->reg02 = val; + + /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */ + val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI); + err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val); + if (err < 0) + goto setoutput_exit; + + state->reg82 = val; + + /* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to + * zero */ + val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI); + err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val); + if (err < 0) + goto setoutput_exit; + + state->reg35 = val; + +setoutput_exit: + if (err != 0) + v4l2_err(sd, "Error setting output, write failed\n"); + + return err; +} + +static int adv7343_log_status(struct v4l2_subdev *sd) +{ + struct adv7343_state *state = to_state(sd); + + v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std); + v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" : + ((state->output == 1) ? "Component" : "S-Video")); + return 0; +} + +static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, + ctrl->val); + + case V4L2_CID_HUE: + return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val); + + case V4L2_CID_GAIN: + return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val); + } + return -EINVAL; +} + +static int adv7343_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0); +} + +static const struct v4l2_ctrl_ops adv7343_ctrl_ops = { + .s_ctrl = adv7343_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops adv7343_core_ops = { + .log_status = adv7343_log_status, + .g_chip_ident = adv7343_g_chip_ident, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, +}; + +static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + + if (state->std == std) + return 0; + + err = adv7343_setstd(sd, std); + if (!err) + state->std = std; + + return err; +} + +static int adv7343_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + + if (state->output == output) + return 0; + + err = adv7343_setoutput(sd, output); + if (!err) + state->output = output; + + return err; +} + +static const struct v4l2_subdev_video_ops adv7343_video_ops = { + .s_std_output = adv7343_s_std_output, + .s_routing = adv7343_s_routing, +}; + +static const struct v4l2_subdev_ops adv7343_ops = { + .core = &adv7343_core_ops, + .video = &adv7343_video_ops, +}; + +static int adv7343_initialize(struct v4l2_subdev *sd) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) { + + err = adv7343_write(sd, adv7343_init_reg_val[i], + adv7343_init_reg_val[i+1]); + if (err) { + v4l2_err(sd, "Error initializing\n"); + return err; + } + } + + /* Configure for default video standard */ + err = adv7343_setoutput(sd, state->output); + if (err < 0) { + v4l2_err(sd, "Error setting output during init\n"); + return -EINVAL; + } + + err = adv7343_setstd(sd, state->std); + if (err < 0) { + v4l2_err(sd, "Error setting std during init\n"); + return -EINVAL; + } + + return err; +} + +static int adv7343_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adv7343_state *state; + int err; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + state->reg00 = 0x80; + state->reg01 = 0x00; + state->reg02 = 0x20; + state->reg35 = 0x00; + state->reg80 = ADV7343_SD_MODE_REG1_DEFAULT; + state->reg82 = ADV7343_SD_MODE_REG2_DEFAULT; + + state->output = ADV7343_COMPOSITE_ID; + state->std = V4L2_STD_NTSC; + + v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops); + + v4l2_ctrl_handler_init(&state->hdl, 2); + v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, + V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN, + ADV7343_BRIGHTNESS_MAX, 1, + ADV7343_BRIGHTNESS_DEF); + v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, + V4L2_CID_HUE, ADV7343_HUE_MIN, + ADV7343_HUE_MAX, 1, + ADV7343_HUE_DEF); + v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, + V4L2_CID_GAIN, ADV7343_GAIN_MIN, + ADV7343_GAIN_MAX, 1, + ADV7343_GAIN_DEF); + state->sd.ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + v4l2_ctrl_handler_setup(&state->hdl); + + err = adv7343_initialize(&state->sd); + if (err) { + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + } + return err; +} + +static int adv7343_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct adv7343_state *state = to_state(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + + return 0; +} + +static const struct i2c_device_id adv7343_id[] = { + {"adv7343", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, adv7343_id); + +static struct i2c_driver adv7343_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv7343", + }, + .probe = adv7343_probe, + .remove = adv7343_remove, + .id_table = adv7343_id, +}; + +static __init int init_adv7343(void) +{ + return i2c_add_driver(&adv7343_driver); +} + +static __exit void exit_adv7343(void) +{ + i2c_del_driver(&adv7343_driver); +} + +module_init(init_adv7343); +module_exit(exit_adv7343); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7343_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7343_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7343_regs.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/adv7343_regs.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,181 @@ +/* + * ADV7343 encoder related structure and register definitions + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef ADV7343_REG_H +#define ADV7343_REGS_H + +struct adv7343_std_info { + u32 standard_val3; + u32 fsc_val; + v4l2_std_id stdid; +}; + +/* Register offset macros */ +#define ADV7343_POWER_MODE_REG (0x00) +#define ADV7343_MODE_SELECT_REG (0x01) +#define ADV7343_MODE_REG0 (0x02) + +#define ADV7343_DAC2_OUTPUT_LEVEL (0x0b) + +#define ADV7343_SOFT_RESET (0x17) + +#define ADV7343_HD_MODE_REG1 (0x30) +#define ADV7343_HD_MODE_REG2 (0x31) +#define ADV7343_HD_MODE_REG3 (0x32) +#define ADV7343_HD_MODE_REG4 (0x33) +#define ADV7343_HD_MODE_REG5 (0x34) +#define ADV7343_HD_MODE_REG6 (0x35) + +#define ADV7343_HD_MODE_REG7 (0x39) + +#define ADV7343_SD_MODE_REG1 (0x80) +#define ADV7343_SD_MODE_REG2 (0x82) +#define ADV7343_SD_MODE_REG3 (0x83) +#define ADV7343_SD_MODE_REG4 (0x84) +#define ADV7343_SD_MODE_REG5 (0x86) +#define ADV7343_SD_MODE_REG6 (0x87) +#define ADV7343_SD_MODE_REG7 (0x88) +#define ADV7343_SD_MODE_REG8 (0x89) + +#define ADV7343_FSC_REG0 (0x8C) +#define ADV7343_FSC_REG1 (0x8D) +#define ADV7343_FSC_REG2 (0x8E) +#define ADV7343_FSC_REG3 (0x8F) + +#define ADV7343_SD_CGMS_WSS0 (0x99) + +#define ADV7343_SD_HUE_REG (0xA0) +#define ADV7343_SD_BRIGHTNESS_WSS (0xA1) + +/* Default values for the registers */ +#define ADV7343_POWER_MODE_REG_DEFAULT (0x10) +#define ADV7343_HD_MODE_REG1_DEFAULT (0x3C) /* Changed Default + 720p EAVSAV code*/ +#define ADV7343_HD_MODE_REG2_DEFAULT (0x01) /* Changed Pixel data + valid */ +#define ADV7343_HD_MODE_REG3_DEFAULT (0x00) /* Color delay 0 clks */ +#define ADV7343_HD_MODE_REG4_DEFAULT (0xE8) /* Changed */ +#define ADV7343_HD_MODE_REG5_DEFAULT (0x08) +#define ADV7343_HD_MODE_REG6_DEFAULT (0x00) +#define ADV7343_HD_MODE_REG7_DEFAULT (0x00) +#define ADV7343_SD_MODE_REG8_DEFAULT (0x00) +#define ADV7343_SOFT_RESET_DEFAULT (0x02) +#define ADV7343_COMPOSITE_POWER_VALUE (0x80) +#define ADV7343_COMPONENT_POWER_VALUE (0x1C) +#define ADV7343_SVIDEO_POWER_VALUE (0x60) +#define ADV7343_SD_HUE_REG_DEFAULT (127) +#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT (0x03) + +#define ADV7343_SD_CGMS_WSS0_DEFAULT (0x10) + +#define ADV7343_SD_MODE_REG1_DEFAULT (0x00) +#define ADV7343_SD_MODE_REG2_DEFAULT (0xC9) +#define ADV7343_SD_MODE_REG3_DEFAULT (0x10) +#define ADV7343_SD_MODE_REG4_DEFAULT (0x01) +#define ADV7343_SD_MODE_REG5_DEFAULT (0x02) +#define ADV7343_SD_MODE_REG6_DEFAULT (0x0C) +#define ADV7343_SD_MODE_REG7_DEFAULT (0x04) +#define ADV7343_SD_MODE_REG8_DEFAULT (0x00) + +/* Bit masks for Mode Select Register */ +#define INPUT_MODE_MASK (0x70) +#define SD_INPUT_MODE (0x00) +#define HD_720P_INPUT_MODE (0x10) +#define HD_1080I_INPUT_MODE (0x10) + +/* Bit masks for Mode Register 0 */ +#define TEST_PATTERN_BLACK_BAR_EN (0x04) +#define YUV_OUTPUT_SELECT (0x20) +#define RGB_OUTPUT_SELECT (0xDF) + +/* Bit masks for DAC output levels */ +#define DAC_OUTPUT_LEVEL_MASK (0xFF) + +/* Bit masks for soft reset register */ +#define SOFT_RESET (0x02) + +/* Bit masks for HD Mode Register 1 */ +#define OUTPUT_STD_MASK (0x03) +#define OUTPUT_STD_SHIFT (0) +#define OUTPUT_STD_EIA0_2 (0x00) +#define OUTPUT_STD_EIA0_1 (0x01) +#define OUTPUT_STD_FULL (0x02) +#define EMBEDDED_SYNC (0x04) +#define EXTERNAL_SYNC (0xFB) +#define STD_MODE_SHIFT (3) +#define STD_MODE_MASK (0x1F) +#define STD_MODE_720P (0x05) +#define STD_MODE_720P_25 (0x08) +#define STD_MODE_720P_30 (0x07) +#define STD_MODE_720P_50 (0x06) +#define STD_MODE_1080I (0x0D) +#define STD_MODE_1080I_25fps (0x0E) +#define STD_MODE_1080P_24 (0x12) +#define STD_MODE_1080P_25 (0x10) +#define STD_MODE_1080P_30 (0x0F) +#define STD_MODE_525P (0x00) +#define STD_MODE_625P (0x03) + +/* Bit masks for SD Mode Register 1 */ +#define SD_STD_MASK (0x03) +#define SD_STD_NTSC (0x00) +#define SD_STD_PAL_BDGHI (0x01) +#define SD_STD_PAL_M (0x02) +#define SD_STD_PAL_N (0x03) +#define SD_LUMA_FLTR_MASK (0x7) +#define SD_LUMA_FLTR_SHIFT (0x2) +#define SD_CHROMA_FLTR_MASK (0x7) +#define SD_CHROMA_FLTR_SHIFT (0x5) + +/* Bit masks for SD Mode Register 2 */ +#define SD_PBPR_SSAF_EN (0x01) +#define SD_PBPR_SSAF_DI (0xFE) +#define SD_DAC_1_DI (0xFD) +#define SD_DAC_2_DI (0xFB) +#define SD_PEDESTAL_EN (0x08) +#define SD_PEDESTAL_DI (0xF7) +#define SD_SQUARE_PIXEL_EN (0x10) +#define SD_SQUARE_PIXEL_DI (0xEF) +#define SD_PIXEL_DATA_VALID (0x40) +#define SD_ACTIVE_EDGE_EN (0x80) +#define SD_ACTIVE_EDGE_DI (0x7F) + +/* Bit masks for HD Mode Register 6 */ +#define HD_RGB_INPUT_EN (0x02) +#define HD_RGB_INPUT_DI (0xFD) +#define HD_PBPR_SYNC_EN (0x04) +#define HD_PBPR_SYNC_DI (0xFB) +#define HD_DAC_SWAP_EN (0x08) +#define HD_DAC_SWAP_DI (0xF7) +#define HD_GAMMA_CURVE_A (0xEF) +#define HD_GAMMA_CURVE_B (0x10) +#define HD_GAMMA_EN (0x20) +#define HD_GAMMA_DI (0xDF) +#define HD_ADPT_FLTR_MODEB (0x40) +#define HD_ADPT_FLTR_MODEA (0xBF) +#define HD_ADPT_FLTR_EN (0x80) +#define HD_ADPT_FLTR_DI (0x7F) + +#define ADV7343_BRIGHTNESS_MAX (127) +#define ADV7343_BRIGHTNESS_MIN (0) +#define ADV7343_BRIGHTNESS_DEF (3) +#define ADV7343_HUE_MAX (255) +#define ADV7343_HUE_MIN (0) +#define ADV7343_HUE_DEF (127) +#define ADV7343_GAIN_MAX (64) +#define ADV7343_GAIN_MIN (-64) +#define ADV7343_GAIN_DEF (0) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ak881x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ak881x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ak881x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ak881x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,369 @@ +/* + * Driver for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM) + * + * Copyright (C) 2010, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define AK881X_INTERFACE_MODE 0 +#define AK881X_VIDEO_PROCESS1 1 +#define AK881X_VIDEO_PROCESS2 2 +#define AK881X_VIDEO_PROCESS3 3 +#define AK881X_DAC_MODE 5 +#define AK881X_STATUS 0x24 +#define AK881X_DEVICE_ID 0x25 +#define AK881X_DEVICE_REVISION 0x26 + +struct ak881x { + struct v4l2_subdev subdev; + struct ak881x_pdata *pdata; + unsigned int lines; + int id; /* DEVICE_ID code V4L2_IDENT_AK881X code from v4l2-chip-ident.h */ + char revision; /* DEVICE_REVISION content */ +}; + +static int reg_read(struct i2c_client *client, const u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int reg_write(struct i2c_client *client, const u8 reg, + const u8 data) +{ + return i2c_smbus_write_byte_data(client, reg, data); +} + +static int reg_set(struct i2c_client *client, const u8 reg, + const u8 data, u8 mask) +{ + int ret = reg_read(client, reg); + if (ret < 0) + return ret; + return reg_write(client, reg, (ret & ~mask) | (data & mask)); +} + +static struct ak881x *to_ak881x(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct ak881x, subdev); +} + +static int ak881x_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ak881x *ak881x = to_ak881x(client); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = ak881x->id; + id->revision = ak881x->revision; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ak881x_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + reg->val = reg_read(client, reg->reg); + + if (reg->val > 0xffff) + return -EIO; + + return 0; +} + +static int ak881x_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x26) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + if (reg_write(client, reg->reg, reg->val) < 0) + return -EIO; + + return 0; +} +#endif + +static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ak881x *ak881x = to_ak881x(client); + + v4l_bound_align_image(&mf->width, 0, 720, 2, + &mf->height, 0, ak881x->lines, 1, 0); + mf->field = V4L2_FIELD_INTERLACED; + mf->code = V4L2_MBUS_FMT_YUYV8_2X8; + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + + return 0; +} + +static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + if (mf->field != V4L2_FIELD_INTERLACED || + mf->code != V4L2_MBUS_FMT_YUYV8_2X8) + return -EINVAL; + + return ak881x_try_g_mbus_fmt(sd, mf); +} + +static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index) + return -EINVAL; + + *code = V4L2_MBUS_FMT_YUYV8_2X8; + return 0; +} + +static int ak881x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ak881x *ak881x = to_ak881x(client); + + a->bounds.left = 0; + a->bounds.top = 0; + a->bounds.width = 720; + a->bounds.height = ak881x->lines; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ak881x *ak881x = to_ak881x(client); + u8 vp1; + + if (std == V4L2_STD_NTSC_443) { + vp1 = 3; + ak881x->lines = 480; + } else if (std == V4L2_STD_PAL_M) { + vp1 = 5; + ak881x->lines = 480; + } else if (std == V4L2_STD_PAL_60) { + vp1 = 7; + ak881x->lines = 480; + } else if (std && !(std & ~V4L2_STD_PAL)) { + vp1 = 0xf; + ak881x->lines = 576; + } else if (std && !(std & ~V4L2_STD_NTSC)) { + vp1 = 0; + ak881x->lines = 480; + } else { + /* No SECAM or PAL_N/Nc supported */ + return -EINVAL; + } + + reg_set(client, AK881X_VIDEO_PROCESS1, vp1, 0xf); + + return 0; +} + +static int ak881x_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ak881x *ak881x = to_ak881x(client); + + if (enable) { + u8 dac; + /* For colour-bar testing set bit 6 of AK881X_VIDEO_PROCESS1 */ + /* Default: composite output */ + if (ak881x->pdata->flags & AK881X_COMPONENT) + dac = 3; + else + dac = 4; + /* Turn on the DAC(s) */ + reg_write(client, AK881X_DAC_MODE, dac); + dev_dbg(&client->dev, "chip status 0x%x\n", + reg_read(client, AK881X_STATUS)); + } else { + /* ...and clear bit 6 of AK881X_VIDEO_PROCESS1 here */ + reg_write(client, AK881X_DAC_MODE, 0); + dev_dbg(&client->dev, "chip status 0x%x\n", + reg_read(client, AK881X_STATUS)); + } + + return 0; +} + +static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = { + .g_chip_ident = ak881x_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ak881x_g_register, + .s_register = ak881x_s_register, +#endif +}; + +static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = { + .s_mbus_fmt = ak881x_s_mbus_fmt, + .g_mbus_fmt = ak881x_try_g_mbus_fmt, + .try_mbus_fmt = ak881x_try_g_mbus_fmt, + .cropcap = ak881x_cropcap, + .enum_mbus_fmt = ak881x_enum_mbus_fmt, + .s_std_output = ak881x_s_std_output, + .s_stream = ak881x_s_stream, +}; + +static struct v4l2_subdev_ops ak881x_subdev_ops = { + .core = &ak881x_subdev_core_ops, + .video = &ak881x_subdev_video_ops, +}; + +static int ak881x_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct ak881x *ak881x; + u8 ifmode, data; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + ak881x = kzalloc(sizeof(struct ak881x), GFP_KERNEL); + if (!ak881x) + return -ENOMEM; + + v4l2_i2c_subdev_init(&ak881x->subdev, client, &ak881x_subdev_ops); + + data = reg_read(client, AK881X_DEVICE_ID); + + switch (data) { + case 0x13: + ak881x->id = V4L2_IDENT_AK8813; + break; + case 0x14: + ak881x->id = V4L2_IDENT_AK8814; + break; + default: + dev_err(&client->dev, + "No ak881x chip detected, register read %x\n", data); + kfree(ak881x); + return -ENODEV; + } + + ak881x->revision = reg_read(client, AK881X_DEVICE_REVISION); + ak881x->pdata = client->dev.platform_data; + + if (ak881x->pdata) { + if (ak881x->pdata->flags & AK881X_FIELD) + ifmode = 4; + else + ifmode = 0; + + switch (ak881x->pdata->flags & AK881X_IF_MODE_MASK) { + case AK881X_IF_MODE_BT656: + ifmode |= 1; + break; + case AK881X_IF_MODE_MASTER: + ifmode |= 2; + break; + case AK881X_IF_MODE_SLAVE: + default: + break; + } + + dev_dbg(&client->dev, "IF mode %x\n", ifmode); + + /* + * "Line Blanking No." seems to be the same as the number of + * "black" lines on, e.g., SuperH VOU, whose default value of 20 + * "incidentally" matches ak881x' default + */ + reg_write(client, AK881X_INTERFACE_MODE, ifmode | (20 << 3)); + } + + /* Hardware default: NTSC-M */ + ak881x->lines = 480; + + dev_info(&client->dev, "Detected an ak881x chip ID %x, revision %x\n", + data, ak881x->revision); + + return 0; +} + +static int ak881x_remove(struct i2c_client *client) +{ + struct ak881x *ak881x = to_ak881x(client); + + v4l2_device_unregister_subdev(&ak881x->subdev); + kfree(ak881x); + + return 0; +} + +static const struct i2c_device_id ak881x_id[] = { + { "ak8813", 0 }, + { "ak8814", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ak881x_id); + +static struct i2c_driver ak881x_i2c_driver = { + .driver = { + .name = "ak881x", + }, + .probe = ak881x_probe, + .remove = ak881x_remove, + .id_table = ak881x_id, +}; + +static int __init ak881x_module_init(void) +{ + return i2c_add_driver(&ak881x_i2c_driver); +} + +static void __exit ak881x_module_exit(void) +{ + i2c_del_driver(&ak881x_i2c_driver); +} + +module_init(ak881x_module_init); +module_exit(ak881x_module_exit); + +MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/arv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/arv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/arv.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/arv.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,881 @@ +/* + * Colour AR M64278(VGA) driver for Video4Linux + * + * Copyright (C) 2003 Takeo Takahashi + * + * 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, or (at your option) any later version. + * + * Some code is taken from AR driver sample program for M3T-M32700UT. + * + * AR driver sample (M32R SDK): + * Copyright (c) 2003 RENESAS TECHNOROGY CORPORATION + * AND RENESAS SOLUTIONS CORPORATION + * All Rights Reserved. + * + * 2003-09-01: Support w3cam by Takeo Takahashi + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if 0 +#define DEBUG(n, args...) printk(KERN_INFO args) +#define CHECK_LOST 1 +#else +#define DEBUG(n, args...) +#define CHECK_LOST 0 +#endif + +/* + * USE_INT is always 0, interrupt mode is not available + * on linux due to lack of speed + */ +#define USE_INT 0 /* Don't modify */ + +#define VERSION "0.04" + +#define ar_inl(addr) inl((unsigned long)(addr)) +#define ar_outl(val, addr) outl((unsigned long)(val), (unsigned long)(addr)) + +extern struct cpuinfo_m32r boot_cpu_data; + +/* + * CCD pixel size + * Note that M32700UT does not support CIF mode, but QVGA is + * supported by M32700UT hardware using VGA mode of AR LSI. + * + * Supported: VGA (Normal mode, Interlace mode) + * QVGA (Always Interlace mode of VGA) + * + */ +#define AR_WIDTH_VGA 640 +#define AR_HEIGHT_VGA 480 +#define AR_WIDTH_QVGA 320 +#define AR_HEIGHT_QVGA 240 +#define MIN_AR_WIDTH AR_WIDTH_QVGA +#define MIN_AR_HEIGHT AR_HEIGHT_QVGA +#define MAX_AR_WIDTH AR_WIDTH_VGA +#define MAX_AR_HEIGHT AR_HEIGHT_VGA + +/* bits & bytes per pixel */ +#define AR_BITS_PER_PIXEL 16 +#define AR_BYTES_PER_PIXEL (AR_BITS_PER_PIXEL / 8) + +/* line buffer size */ +#define AR_LINE_BYTES_VGA (AR_WIDTH_VGA * AR_BYTES_PER_PIXEL) +#define AR_LINE_BYTES_QVGA (AR_WIDTH_QVGA * AR_BYTES_PER_PIXEL) +#define MAX_AR_LINE_BYTES AR_LINE_BYTES_VGA + +/* frame size & type */ +#define AR_FRAME_BYTES_VGA \ + (AR_WIDTH_VGA * AR_HEIGHT_VGA * AR_BYTES_PER_PIXEL) +#define AR_FRAME_BYTES_QVGA \ + (AR_WIDTH_QVGA * AR_HEIGHT_QVGA * AR_BYTES_PER_PIXEL) +#define MAX_AR_FRAME_BYTES \ + (MAX_AR_WIDTH * MAX_AR_HEIGHT * AR_BYTES_PER_PIXEL) + +#define AR_MAX_FRAME 15 + +/* capture size */ +#define AR_SIZE_VGA 0 +#define AR_SIZE_QVGA 1 + +/* capture mode */ +#define AR_MODE_INTERLACE 0 +#define AR_MODE_NORMAL 1 + +struct ar { + struct v4l2_device v4l2_dev; + struct video_device vdev; + unsigned int start_capture; /* duaring capture in INT. mode. */ +#if USE_INT + unsigned char *line_buff; /* DMA line buffer */ +#endif + unsigned char *frame[MAX_AR_HEIGHT]; /* frame data */ + short size; /* capture size */ + short mode; /* capture mode */ + int width, height; + int frame_bytes, line_bytes; + wait_queue_head_t wait; + struct mutex lock; +}; + +static struct ar ardev; + +static int video_nr = -1; /* video device number (first free) */ +static unsigned char yuv[MAX_AR_FRAME_BYTES]; + +/* module parameters */ +/* default frequency */ +#define DEFAULT_FREQ 50 /* 50 or 75 (MHz) is available as BCLK */ +static int freq = DEFAULT_FREQ; /* BCLK: available 50 or 70 (MHz) */ +static int vga; /* default mode(0:QVGA mode, other:VGA mode) */ +static int vga_interlace; /* 0 is normal mode for, else interlace mode */ +module_param(freq, int, 0); +module_param(vga, int, 0); +module_param(vga_interlace, int, 0); + +static void wait_for_vsync(void) +{ + while (ar_inl(ARVCR0) & ARVCR0_VDS) /* wait for VSYNC */ + cpu_relax(); + while (!(ar_inl(ARVCR0) & ARVCR0_VDS)) /* wait for VSYNC */ + cpu_relax(); +} + +static void wait_acknowledge(void) +{ + int i; + + for (i = 0; i < 1000; i++) + cpu_relax(); + while (ar_inl(PLDI2CSTS) & PLDI2CSTS_NOACK) + cpu_relax(); +} + +/******************************************************************* + * I2C functions + *******************************************************************/ +static void iic(int n, unsigned long addr, unsigned long data1, unsigned long data2, + unsigned long data3) +{ + int i; + + /* Slave Address */ + ar_outl(addr, PLDI2CDATA); + wait_for_vsync(); + + /* Start */ + ar_outl(1, PLDI2CCND); + wait_acknowledge(); + + /* Transfer data 1 */ + ar_outl(data1, PLDI2CDATA); + wait_for_vsync(); + ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN); + wait_acknowledge(); + + /* Transfer data 2 */ + ar_outl(data2, PLDI2CDATA); + wait_for_vsync(); + ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN); + wait_acknowledge(); + + if (n == 3) { + /* Transfer data 3 */ + ar_outl(data3, PLDI2CDATA); + wait_for_vsync(); + ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN); + wait_acknowledge(); + } + + /* Stop */ + for (i = 0; i < 100; i++) + cpu_relax(); + ar_outl(2, PLDI2CCND); + ar_outl(2, PLDI2CCND); + + while (ar_inl(PLDI2CSTS) & PLDI2CSTS_BB) + cpu_relax(); +} + + +static void init_iic(void) +{ + DEBUG(1, "init_iic:\n"); + + /* + * ICU Setting (iic) + */ + /* I2C Setting */ + ar_outl(0x0, PLDI2CCR); /* I2CCR Disable */ + ar_outl(0x0300, PLDI2CMOD); /* I2CMOD ACK/8b-data/7b-addr/auto */ + ar_outl(0x1, PLDI2CACK); /* I2CACK ACK */ + + /* I2C CLK */ + /* 50MH-100k */ + if (freq == 75) + ar_outl(369, PLDI2CFREQ); /* BCLK = 75MHz */ + else if (freq == 50) + ar_outl(244, PLDI2CFREQ); /* BCLK = 50MHz */ + else + ar_outl(244, PLDI2CFREQ); /* default: BCLK = 50MHz */ + ar_outl(0x1, PLDI2CCR); /* I2CCR Enable */ +} + +/************************************************************************** + * + * Video4Linux Interface functions + * + **************************************************************************/ + +static inline void disable_dma(void) +{ + ar_outl(0x8000, M32R_DMAEN_PORTL); /* disable DMA0 */ +} + +static inline void enable_dma(void) +{ + ar_outl(0x8080, M32R_DMAEN_PORTL); /* enable DMA0 */ +} + +static inline void clear_dma_status(void) +{ + ar_outl(0x8000, M32R_DMAEDET_PORTL); /* clear status */ +} + +static void wait_for_vertical_sync(struct ar *ar, int exp_line) +{ +#if CHECK_LOST + int tmout = 10000; /* FIXME */ + int l; + + /* + * check HCOUNT because we cannot check vertical sync. + */ + for (; tmout >= 0; tmout--) { + l = ar_inl(ARVHCOUNT); + if (l == exp_line) + break; + } + if (tmout < 0) + v4l2_err(&ar->v4l2_dev, "lost %d -> %d\n", exp_line, l); +#else + while (ar_inl(ARVHCOUNT) != exp_line) + cpu_relax(); +#endif +} + +static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + struct ar *ar = video_drvdata(file); + long ret = ar->frame_bytes; /* return read bytes */ + unsigned long arvcr1 = 0; + unsigned long flags; + unsigned char *p; + int h, w; + unsigned char *py, *pu, *pv; +#if !USE_INT + int l; +#endif + + DEBUG(1, "ar_read()\n"); + + if (ar->size == AR_SIZE_QVGA) + arvcr1 |= ARVCR1_QVGA; + if (ar->mode == AR_MODE_NORMAL) + arvcr1 |= ARVCR1_NORMAL; + + mutex_lock(&ar->lock); + +#if USE_INT + local_irq_save(flags); + disable_dma(); + ar_outl(0xa1871300, M32R_DMA0CR0_PORTL); + ar_outl(0x01000000, M32R_DMA0CR1_PORTL); + + /* set AR FIFO address as source(BSEL5) */ + ar_outl(ARDATA32, M32R_DMA0CSA_PORTL); + ar_outl(ARDATA32, M32R_DMA0RSA_PORTL); + ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); /* destination addr. */ + ar_outl(ar->line_buff, M32R_DMA0RDA_PORTL); /* reload address */ + ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL); /* byte count (bytes) */ + ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL); /* reload count (bytes) */ + + /* + * Okay, kick AR LSI to invoke an interrupt + */ + ar->start_capture = 0; + ar_outl(arvcr1 | ARVCR1_HIEN, ARVCR1); + local_irq_restore(flags); + /* .... AR interrupts .... */ + interruptible_sleep_on(&ar->wait); + if (signal_pending(current)) { + printk(KERN_ERR "arv: interrupted while get frame data.\n"); + ret = -EINTR; + goto out_up; + } +#else /* ! USE_INT */ + /* polling */ + ar_outl(arvcr1, ARVCR1); + disable_dma(); + ar_outl(0x8000, M32R_DMAEDET_PORTL); + ar_outl(0xa0861300, M32R_DMA0CR0_PORTL); + ar_outl(0x01000000, M32R_DMA0CR1_PORTL); + ar_outl(ARDATA32, M32R_DMA0CSA_PORTL); + ar_outl(ARDATA32, M32R_DMA0RSA_PORTL); + ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL); + ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL); + + local_irq_save(flags); + while (ar_inl(ARVHCOUNT) != 0) /* wait for 0 */ + cpu_relax(); + if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) { + for (h = 0; h < ar->height; h++) { + wait_for_vertical_sync(ar, h); + if (h < (AR_HEIGHT_VGA/2)) + l = h << 1; + else + l = (((h - (AR_HEIGHT_VGA/2)) << 1) + 1); + ar_outl(virt_to_phys(ar->frame[l]), M32R_DMA0CDA_PORTL); + enable_dma(); + while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000)) + cpu_relax(); + disable_dma(); + clear_dma_status(); + ar_outl(0xa0861300, M32R_DMA0CR0_PORTL); + } + } else { + for (h = 0; h < ar->height; h++) { + wait_for_vertical_sync(ar, h); + ar_outl(virt_to_phys(ar->frame[h]), M32R_DMA0CDA_PORTL); + enable_dma(); + while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000)) + cpu_relax(); + disable_dma(); + clear_dma_status(); + ar_outl(0xa0861300, M32R_DMA0CR0_PORTL); + } + } + local_irq_restore(flags); +#endif /* ! USE_INT */ + + /* + * convert YUV422 to YUV422P + * +--------------------+ + * | Y0,Y1,... | + * | ..............Yn | + * +--------------------+ + * | U0,U1,........Un | + * +--------------------+ + * | V0,V1,........Vn | + * +--------------------+ + */ + py = yuv; + pu = py + (ar->frame_bytes / 2); + pv = pu + (ar->frame_bytes / 4); + for (h = 0; h < ar->height; h++) { + p = ar->frame[h]; + for (w = 0; w < ar->line_bytes; w += 4) { + *py++ = *p++; + *pu++ = *p++; + *py++ = *p++; + *pv++ = *p++; + } + } + if (copy_to_user(buf, yuv, ar->frame_bytes)) { + v4l2_err(&ar->v4l2_dev, "failed while copy_to_user yuv.\n"); + ret = -EFAULT; + goto out_up; + } + DEBUG(1, "ret = %d\n", ret); +out_up: + mutex_unlock(&ar->lock); + return ret; +} + +static int ar_querycap(struct file *file, void *priv, + struct v4l2_capability *vcap) +{ + struct ar *ar = video_drvdata(file); + + strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver)); + strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card)); + strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info)); + vcap->version = KERNEL_VERSION(0, 0, 4); + vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + return 0; +} + +static int ar_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + if (vin->index > 0) + return -EINVAL; + strlcpy(vin->name, "Camera", sizeof(vin->name)); + vin->type = V4L2_INPUT_TYPE_CAMERA; + vin->audioset = 0; + vin->tuner = 0; + vin->std = V4L2_STD_ALL; + vin->status = 0; + return 0; +} + +static int ar_g_input(struct file *file, void *fh, unsigned int *inp) +{ + *inp = 0; + return 0; +} + +static int ar_s_input(struct file *file, void *fh, unsigned int inp) +{ + return inp ? -EINVAL : 0; +} + +static int ar_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ar *ar = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + pix->width = ar->width; + pix->height = ar->height; + pix->pixelformat = V4L2_PIX_FMT_YUV422P; + pix->field = (ar->mode == AR_MODE_NORMAL) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED; + pix->bytesperline = ar->width; + pix->sizeimage = 2 * ar->width * ar->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + return 0; +} + +static int ar_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ar *ar = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + if (pix->height <= AR_HEIGHT_QVGA || pix->width <= AR_WIDTH_QVGA) { + pix->height = AR_HEIGHT_QVGA; + pix->width = AR_WIDTH_QVGA; + pix->field = V4L2_FIELD_INTERLACED; + } else { + pix->height = AR_HEIGHT_VGA; + pix->width = AR_WIDTH_VGA; + pix->field = vga_interlace ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; + } + pix->pixelformat = V4L2_PIX_FMT_YUV422P; + pix->bytesperline = ar->width; + pix->sizeimage = 2 * ar->width * ar->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + return 0; +} + +static int ar_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ar *ar = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + int ret = ar_try_fmt_vid_cap(file, fh, fmt); + + if (ret) + return ret; + mutex_lock(&ar->lock); + ar->width = pix->width; + ar->height = pix->height; + if (ar->width == AR_WIDTH_VGA) { + ar->size = AR_SIZE_VGA; + ar->frame_bytes = AR_FRAME_BYTES_VGA; + ar->line_bytes = AR_LINE_BYTES_VGA; + if (vga_interlace) + ar->mode = AR_MODE_INTERLACE; + else + ar->mode = AR_MODE_NORMAL; + } else { + ar->size = AR_SIZE_QVGA; + ar->frame_bytes = AR_FRAME_BYTES_QVGA; + ar->line_bytes = AR_LINE_BYTES_QVGA; + ar->mode = AR_MODE_INTERLACE; + } + /* Ok we figured out what to use from our wide choice */ + mutex_unlock(&ar->lock); + return 0; +} + +static int ar_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) +{ + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "YUV 4:2:2 Planar", V4L2_PIX_FMT_YUV422P, + { 0, 0, 0, 0 } + }, + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 0) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; +} + +#if USE_INT +/* + * Interrupt handler + */ +static void ar_interrupt(int irq, void *dev) +{ + struct ar *ar = dev; + unsigned int line_count; + unsigned int line_number; + unsigned int arvcr1; + + line_count = ar_inl(ARVHCOUNT); /* line number */ + if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) { + /* operations for interlace mode */ + if (line_count < (AR_HEIGHT_VGA / 2)) /* even line */ + line_number = (line_count << 1); + else /* odd line */ + line_number = + (((line_count - (AR_HEIGHT_VGA / 2)) << 1) + 1); + } else { + line_number = line_count; + } + + if (line_number == 0) { + /* + * It is an interrupt for line 0. + * we have to start capture. + */ + disable_dma(); +#if 0 + ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); /* needless? */ +#endif + memcpy(ar->frame[0], ar->line_buff, ar->line_bytes); +#if 0 + ar_outl(0xa1861300, M32R_DMA0CR0_PORTL); +#endif + enable_dma(); + ar->start_capture = 1; /* during capture */ + return; + } + + if (ar->start_capture == 1 && line_number <= (ar->height - 1)) { + disable_dma(); + memcpy(ar->frame[line_number], ar->line_buff, ar->line_bytes); + + /* + * if captured all line of a frame, disable AR interrupt + * and wake a process up. + */ + if (line_number == (ar->height - 1)) { /* end of line */ + + ar->start_capture = 0; + + /* disable AR interrupt request */ + arvcr1 = ar_inl(ARVCR1); + arvcr1 &= ~ARVCR1_HIEN; /* clear int. flag */ + ar_outl(arvcr1, ARVCR1); /* disable */ + wake_up_interruptible(&ar->wait); + } else { +#if 0 + ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); + ar_outl(0xa1861300, M32R_DMA0CR0_PORTL); +#endif + enable_dma(); + } + } +} +#endif + +/* + * ar_initialize() + * ar_initialize() is called by video_register_device() and + * initializes AR LSI and peripherals. + * + * -1 is returned in all failures. + * 0 is returned in success. + * + */ +static int ar_initialize(struct ar *ar) +{ + unsigned long cr = 0; + int i, found = 0; + + DEBUG(1, "ar_initialize:\n"); + + /* + * initialize AR LSI + */ + ar_outl(0, ARVCR0); /* assert reset of AR LSI */ + for (i = 0; i < 0x18; i++) /* wait for over 10 cycles @ 27MHz */ + cpu_relax(); + ar_outl(ARVCR0_RST, ARVCR0); /* negate reset of AR LSI (enable) */ + for (i = 0; i < 0x40d; i++) /* wait for over 420 cycles @ 27MHz */ + cpu_relax(); + + /* AR uses INT3 of CPU as interrupt pin. */ + ar_outl(ARINTSEL_INT3, ARINTSEL); + + if (ar->size == AR_SIZE_QVGA) + cr |= ARVCR1_QVGA; + if (ar->mode == AR_MODE_NORMAL) + cr |= ARVCR1_NORMAL; + ar_outl(cr, ARVCR1); + + /* + * Initialize IIC so that CPU can communicate with AR LSI, + * and send boot commands to AR LSI. + */ + init_iic(); + + for (i = 0; i < 0x100000; i++) { /* > 0xa1d10, 56ms */ + if ((ar_inl(ARVCR0) & ARVCR0_VDS)) { /* VSYNC */ + found = 1; + break; + } + } + + if (found == 0) + return -ENODEV; + + v4l2_info(&ar->v4l2_dev, "Initializing "); + + iic(2, 0x78, 0x11, 0x01, 0x00); /* start */ + iic(3, 0x78, 0x12, 0x00, 0x06); + iic(3, 0x78, 0x12, 0x12, 0x30); + iic(3, 0x78, 0x12, 0x15, 0x58); + iic(3, 0x78, 0x12, 0x17, 0x30); + printk(KERN_CONT "."); + iic(3, 0x78, 0x12, 0x1a, 0x97); + iic(3, 0x78, 0x12, 0x1b, 0xff); + iic(3, 0x78, 0x12, 0x1c, 0xff); + iic(3, 0x78, 0x12, 0x26, 0x10); + iic(3, 0x78, 0x12, 0x27, 0x00); + printk(KERN_CONT "."); + iic(2, 0x78, 0x34, 0x02, 0x00); + iic(2, 0x78, 0x7a, 0x10, 0x00); + iic(2, 0x78, 0x80, 0x39, 0x00); + iic(2, 0x78, 0x81, 0xe6, 0x00); + iic(2, 0x78, 0x8d, 0x00, 0x00); + printk(KERN_CONT "."); + iic(2, 0x78, 0x8e, 0x0c, 0x00); + iic(2, 0x78, 0x8f, 0x00, 0x00); +#if 0 + iic(2, 0x78, 0x90, 0x00, 0x00); /* AWB on=1 off=0 */ +#endif + iic(2, 0x78, 0x93, 0x01, 0x00); + iic(2, 0x78, 0x94, 0xcd, 0x00); + iic(2, 0x78, 0x95, 0x00, 0x00); + printk(KERN_CONT "."); + iic(2, 0x78, 0x96, 0xa0, 0x00); + iic(2, 0x78, 0x97, 0x00, 0x00); + iic(2, 0x78, 0x98, 0x60, 0x00); + iic(2, 0x78, 0x99, 0x01, 0x00); + iic(2, 0x78, 0x9a, 0x19, 0x00); + printk(KERN_CONT "."); + iic(2, 0x78, 0x9b, 0x02, 0x00); + iic(2, 0x78, 0x9c, 0xe8, 0x00); + iic(2, 0x78, 0x9d, 0x02, 0x00); + iic(2, 0x78, 0x9e, 0x2e, 0x00); + iic(2, 0x78, 0xb8, 0x78, 0x00); + iic(2, 0x78, 0xba, 0x05, 0x00); +#if 0 + iic(2, 0x78, 0x83, 0x8c, 0x00); /* brightness */ +#endif + printk(KERN_CONT "."); + + /* color correction */ + iic(3, 0x78, 0x49, 0x00, 0x95); /* a */ + iic(3, 0x78, 0x49, 0x01, 0x96); /* b */ + iic(3, 0x78, 0x49, 0x03, 0x85); /* c */ + iic(3, 0x78, 0x49, 0x04, 0x97); /* d */ + iic(3, 0x78, 0x49, 0x02, 0x7e); /* e(Lo) */ + iic(3, 0x78, 0x49, 0x05, 0xa4); /* f(Lo) */ + iic(3, 0x78, 0x49, 0x06, 0x04); /* e(Hi) */ + iic(3, 0x78, 0x49, 0x07, 0x04); /* e(Hi) */ + iic(2, 0x78, 0x48, 0x01, 0x00); /* on=1 off=0 */ + + printk(KERN_CONT "."); + iic(2, 0x78, 0x11, 0x00, 0x00); /* end */ + printk(KERN_CONT " done\n"); + return 0; +} + + +/**************************************************************************** + * + * Video4Linux Module functions + * + ****************************************************************************/ + +static const struct v4l2_file_operations ar_fops = { + .owner = THIS_MODULE, + .read = ar_read, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops ar_ioctl_ops = { + .vidioc_querycap = ar_querycap, + .vidioc_g_input = ar_g_input, + .vidioc_s_input = ar_s_input, + .vidioc_enum_input = ar_enum_input, + .vidioc_enum_fmt_vid_cap = ar_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = ar_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = ar_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = ar_try_fmt_vid_cap, +}; + +#define ALIGN4(x) ((((int)(x)) & 0x3) == 0) + +static int __init ar_init(void) +{ + struct ar *ar; + struct v4l2_device *v4l2_dev; + int ret; + int i; + + ar = &ardev; + v4l2_dev = &ar->v4l2_dev; + strlcpy(v4l2_dev->name, "arv", sizeof(v4l2_dev->name)); + v4l2_info(v4l2_dev, "Colour AR VGA driver %s\n", VERSION); + + ret = v4l2_device_register(NULL, v4l2_dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return ret; + } + ret = -EIO; + +#if USE_INT + /* allocate a DMA buffer for 1 line. */ + ar->line_buff = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL | GFP_DMA); + if (ar->line_buff == NULL || !ALIGN4(ar->line_buff)) { + v4l2_err(v4l2_dev, "buffer allocation failed for DMA.\n"); + ret = -ENOMEM; + goto out_end; + } +#endif + /* allocate buffers for a frame */ + for (i = 0; i < MAX_AR_HEIGHT; i++) { + ar->frame[i] = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL); + if (ar->frame[i] == NULL || !ALIGN4(ar->frame[i])) { + v4l2_err(v4l2_dev, "buffer allocation failed for frame.\n"); + ret = -ENOMEM; + goto out_line_buff; + } + } + + strlcpy(ar->vdev.name, "Colour AR VGA", sizeof(ar->vdev.name)); + ar->vdev.v4l2_dev = v4l2_dev; + ar->vdev.fops = &ar_fops; + ar->vdev.ioctl_ops = &ar_ioctl_ops; + ar->vdev.release = video_device_release_empty; + video_set_drvdata(&ar->vdev, ar); + + if (vga) { + ar->width = AR_WIDTH_VGA; + ar->height = AR_HEIGHT_VGA; + ar->size = AR_SIZE_VGA; + ar->frame_bytes = AR_FRAME_BYTES_VGA; + ar->line_bytes = AR_LINE_BYTES_VGA; + if (vga_interlace) + ar->mode = AR_MODE_INTERLACE; + else + ar->mode = AR_MODE_NORMAL; + } else { + ar->width = AR_WIDTH_QVGA; + ar->height = AR_HEIGHT_QVGA; + ar->size = AR_SIZE_QVGA; + ar->frame_bytes = AR_FRAME_BYTES_QVGA; + ar->line_bytes = AR_LINE_BYTES_QVGA; + ar->mode = AR_MODE_INTERLACE; + } + mutex_init(&ar->lock); + init_waitqueue_head(&ar->wait); + +#if USE_INT + if (request_irq(M32R_IRQ_INT3, ar_interrupt, 0, "arv", ar)) { + v4l2_err("request_irq(%d) failed.\n", M32R_IRQ_INT3); + ret = -EIO; + goto out_irq; + } +#endif + + if (ar_initialize(ar) != 0) { + v4l2_err(v4l2_dev, "M64278 not found.\n"); + ret = -ENODEV; + goto out_dev; + } + + /* + * ok, we can initialize h/w according to parameters, + * so register video device as a frame grabber type. + * device is named "video[0-64]". + * video_register_device() initializes h/w using ar_initialize(). + */ + if (video_register_device(&ar->vdev, VFL_TYPE_GRABBER, video_nr) != 0) { + /* return -1, -ENFILE(full) or others */ + v4l2_err(v4l2_dev, "register video (Colour AR) failed.\n"); + ret = -ENODEV; + goto out_dev; + } + + v4l2_info(v4l2_dev, "%s: Found M64278 VGA (IRQ %d, Freq %dMHz).\n", + video_device_node_name(&ar->vdev), M32R_IRQ_INT3, freq); + + return 0; + +out_dev: +#if USE_INT + free_irq(M32R_IRQ_INT3, ar); + +out_irq: +#endif + for (i = 0; i < MAX_AR_HEIGHT; i++) + kfree(ar->frame[i]); + +out_line_buff: +#if USE_INT + kfree(ar->line_buff); + +out_end: +#endif + v4l2_device_unregister(&ar->v4l2_dev); + return ret; +} + + +static int __init ar_init_module(void) +{ + freq = (boot_cpu_data.bus_clock / 1000000); + printk(KERN_INFO "arv: Bus clock %d\n", freq); + if (freq != 50 && freq != 75) + freq = DEFAULT_FREQ; + return ar_init(); +} + +static void __exit ar_cleanup_module(void) +{ + struct ar *ar; + int i; + + ar = &ardev; + video_unregister_device(&ar->vdev); +#if USE_INT + free_irq(M32R_IRQ_INT3, ar); +#endif + for (i = 0; i < MAX_AR_HEIGHT; i++) + kfree(ar->frame[i]); +#if USE_INT + kfree(ar->line_buff); +#endif + v4l2_device_unregister(&ar->v4l2_dev); +} + +module_init(ar_init_module); +module_exit(ar_cleanup_module); + +MODULE_AUTHOR("Takeo Takahashi "); +MODULE_DESCRIPTION("Colour AR M64278(VGA) for Video4Linux"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-cards.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,330 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "au0828.h" +#include "au0828-cards.h" +#include "au8522.h" +#include "media/tuner.h" +#include "media/v4l2-common.h" + +void hvr950q_cs5340_audio(void *priv, int enable) +{ + /* Because the HVR-950q shares an i2s bus between the cs5340 and the + au8522, we need to hold cs5340 in reset when using the au8522 */ + struct au0828_dev *dev = priv; + if (enable == 1) + au0828_set(dev, REG_000, 0x10); + else + au0828_clear(dev, REG_000, 0x10); +} + +struct au0828_board au0828_boards[] = { + [AU0828_BOARD_UNKNOWN] = { + .name = "Unknown board", + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [AU0828_BOARD_HAUPPAUGE_HVR850] = { + .name = "Hauppauge HVR850", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .i2c_clk_divider = AU0828_I2C_CLK_30KHZ, + .input = { + { + .type = AU0828_VMUX_TELEVISION, + .vmux = AU8522_COMPOSITE_CH4_SIF, + .amux = AU8522_AUDIO_SIF, + }, + { + .type = AU0828_VMUX_COMPOSITE, + .vmux = AU8522_COMPOSITE_CH1, + .amux = AU8522_AUDIO_NONE, + .audio_setup = hvr950q_cs5340_audio, + }, + { + .type = AU0828_VMUX_SVIDEO, + .vmux = AU8522_SVIDEO_CH13, + .amux = AU8522_AUDIO_NONE, + .audio_setup = hvr950q_cs5340_audio, + }, + }, + }, + [AU0828_BOARD_HAUPPAUGE_HVR950Q] = { + .name = "Hauppauge HVR950Q", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + /* The au0828 hardware i2c implementation does not properly + support the xc5000's i2c clock stretching. So we need to + lower the clock frequency enough where the 15us clock + stretch fits inside of a normal clock cycle, or else the + au0828 fails to set the STOP bit. A 30 KHz clock puts the + clock pulse width at 18us */ + .i2c_clk_divider = AU0828_I2C_CLK_30KHZ, + .input = { + { + .type = AU0828_VMUX_TELEVISION, + .vmux = AU8522_COMPOSITE_CH4_SIF, + .amux = AU8522_AUDIO_SIF, + }, + { + .type = AU0828_VMUX_COMPOSITE, + .vmux = AU8522_COMPOSITE_CH1, + .amux = AU8522_AUDIO_NONE, + .audio_setup = hvr950q_cs5340_audio, + }, + { + .type = AU0828_VMUX_SVIDEO, + .vmux = AU8522_SVIDEO_CH13, + .amux = AU8522_AUDIO_NONE, + .audio_setup = hvr950q_cs5340_audio, + }, + }, + }, + [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = { + .name = "Hauppauge HVR950Q rev xxF8", + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, + }, + [AU0828_BOARD_DVICO_FUSIONHDTV7] = { + .name = "DViCO FusionHDTV USB", + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, + }, + [AU0828_BOARD_HAUPPAUGE_WOODBURY] = { + .name = "Hauppauge Woodbury", + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, + }, +}; + +/* Tuner callback function for au0828 boards. Currently only needed + * for HVR1500Q, which has an xc5000 tuner. + */ +int au0828_tuner_callback(void *priv, int component, int command, int arg) +{ + struct au0828_dev *dev = priv; + + dprintk(1, "%s()\n", __func__); + + switch (dev->boardnr) { + case AU0828_BOARD_HAUPPAUGE_HVR850: + case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + case AU0828_BOARD_DVICO_FUSIONHDTV7: + if (command == 0) { + /* Tuner Reset Command from xc5000 */ + /* Drive the tuner into reset and out */ + au0828_clear(dev, REG_001, 2); + mdelay(10); + au0828_set(dev, REG_001, 2); + mdelay(10); + return 0; + } else { + printk(KERN_ERR + "%s(): Unknown command.\n", __func__); + return -EINVAL; + } + break; + } + + return 0; /* Should never be here */ +} + +static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); + dev->board.tuner_type = tv.tuner_type; + + /* Make sure we support the board model */ + switch (tv.model) { + case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */ + case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ + case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ + case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ + case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */ + case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */ + case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", __func__, tv.model); + break; + } + + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + __func__, tv.model); +} + +void au0828_card_setup(struct au0828_dev *dev) +{ + static u8 eeprom[256]; + struct tuner_setup tun_setup; + struct v4l2_subdev *sd; + unsigned int mode_mask = T_ANALOG_TV; + + dprintk(1, "%s()\n", __func__); + + memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board)); + + if (dev->i2c_rc == 0) { + dev->i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom)); + } + + switch (dev->boardnr) { + case AU0828_BOARD_HAUPPAUGE_HVR850: + case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + case AU0828_BOARD_HAUPPAUGE_WOODBURY: + if (dev->i2c_rc == 0) + hauppauge_eeprom(dev, eeprom+0xa0); + break; + } + + if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) { + /* Load the analog demodulator driver (note this would need to + be abstracted out if we ever need to support a different + demod) */ + sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "au8522", 0x8e >> 1, NULL); + if (sd == NULL) + printk(KERN_ERR "analog subdev registration failed\n"); + } + + /* Setup tuners */ + if (dev->board.tuner_type != TUNER_ABSENT) { + /* Load the tuner module, which does the attach */ + sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "tuner", dev->board.tuner_addr, NULL); + if (sd == NULL) + printk(KERN_ERR "tuner subdev registration fail\n"); + + tun_setup.mode_mask = mode_mask; + tun_setup.type = dev->board.tuner_type; + tun_setup.addr = dev->board.tuner_addr; + tun_setup.tuner_callback = au0828_tuner_callback; + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, + &tun_setup); + } +} + +/* + * The bridge has between 8 and 12 gpios. + * Regs 1 and 0 deal with output enables. + * Regs 3 and 2 deal with direction. + */ +void au0828_gpio_setup(struct au0828_dev *dev) +{ + dprintk(1, "%s()\n", __func__); + + switch (dev->boardnr) { + case AU0828_BOARD_HAUPPAUGE_HVR850: + case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + case AU0828_BOARD_HAUPPAUGE_WOODBURY: + /* GPIO's + * 4 - CS5340 + * 5 - AU8522 Demodulator + * 6 - eeprom W/P + * 7 - power supply + * 9 - XC5000 Tuner + */ + + /* Into reset */ + au0828_write(dev, REG_003, 0x02); + au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10); + au0828_write(dev, REG_001, 0x0); + au0828_write(dev, REG_000, 0x0); + msleep(100); + + /* Out of reset (leave the cs5340 in reset until needed) */ + au0828_write(dev, REG_003, 0x02); + au0828_write(dev, REG_001, 0x02); + au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10); + au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20); + + msleep(250); + break; + case AU0828_BOARD_DVICO_FUSIONHDTV7: + /* GPIO's + * 6 - ? + * 8 - AU8522 Demodulator + * 9 - XC5000 Tuner + */ + + /* Into reset */ + au0828_write(dev, REG_003, 0x02); + au0828_write(dev, REG_002, 0xa0); + au0828_write(dev, REG_001, 0x0); + au0828_write(dev, REG_000, 0x0); + msleep(100); + + /* Out of reset */ + au0828_write(dev, REG_003, 0x02); + au0828_write(dev, REG_002, 0xa0); + au0828_write(dev, REG_001, 0x02); + au0828_write(dev, REG_000, 0xa0); + msleep(250); + break; + } +} + +/* table of devices that work with this driver */ +struct usb_device_id au0828_usb_id_table[] = { + { USB_DEVICE(0x2040, 0x7200), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7240), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 }, + { USB_DEVICE(0x0fe9, 0xd620), + .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 }, + { USB_DEVICE(0x2040, 0x7210), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7217), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x721b), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x721e), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x721f), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7280), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x0fd9, 0x0008), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7201), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, + { USB_DEVICE(0x2040, 0x7211), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, + { USB_DEVICE(0x2040, 0x7281), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, + { USB_DEVICE(0x2040, 0x8200), + .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, + { }, +}; + +MODULE_DEVICE_TABLE(usb, au0828_usb_id_table); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-cards.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-cards.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-cards.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-cards.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define AU0828_BOARD_UNKNOWN 0 +#define AU0828_BOARD_HAUPPAUGE_HVR950Q 1 +#define AU0828_BOARD_HAUPPAUGE_HVR850 2 +#define AU0828_BOARD_DVICO_FUSIONHDTV7 3 +#define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL 4 +#define AU0828_BOARD_HAUPPAUGE_WOODBURY 5 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-core.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,294 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "au0828.h" + +/* + * 1 = General debug messages + * 2 = USB handling + * 4 = I2C related + * 8 = Bridge related + */ +int au0828_debug; +module_param_named(debug, au0828_debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); + +static unsigned int disable_usb_speed_check; +module_param(disable_usb_speed_check, int, 0444); +MODULE_PARM_DESC(disable_usb_speed_check, + "override min bandwidth requirement of 480M bps"); + +#define _AU0828_BULKPIPE 0x03 +#define _BULKPIPESIZE 0xffff + +static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, + u16 index, unsigned char *cp, u16 size); +static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, + u16 index, unsigned char *cp, u16 size); + +/* USB Direction */ +#define CMD_REQUEST_IN 0x00 +#define CMD_REQUEST_OUT 0x01 + +u32 au0828_readreg(struct au0828_dev *dev, u16 reg) +{ + recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1); + dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, dev->ctrlmsg[0]); + return dev->ctrlmsg[0]; +} + +u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val) +{ + dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val); + return send_control_msg(dev, CMD_REQUEST_OUT, val, reg, + dev->ctrlmsg, 0); +} + +static void cmd_msg_dump(struct au0828_dev *dev) +{ + int i; + + for (i = 0; i < sizeof(dev->ctrlmsg); i += 16) + dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + __func__, + dev->ctrlmsg[i+0], dev->ctrlmsg[i+1], + dev->ctrlmsg[i+2], dev->ctrlmsg[i+3], + dev->ctrlmsg[i+4], dev->ctrlmsg[i+5], + dev->ctrlmsg[i+6], dev->ctrlmsg[i+7], + dev->ctrlmsg[i+8], dev->ctrlmsg[i+9], + dev->ctrlmsg[i+10], dev->ctrlmsg[i+11], + dev->ctrlmsg[i+12], dev->ctrlmsg[i+13], + dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]); +} + +static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, + u16 index, unsigned char *cp, u16 size) +{ + int status = -ENODEV; + mutex_lock(&dev->mutex); + if (dev->usbdev) { + + /* cp must be memory that has been allocated by kmalloc */ + status = usb_control_msg(dev->usbdev, + usb_sndctrlpipe(dev->usbdev, 0), + request, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, + value, index, + cp, size, 1000); + + status = min(status, 0); + + if (status < 0) { + printk(KERN_ERR "%s() Failed sending control message, error %d.\n", + __func__, status); + } + + } + mutex_unlock(&dev->mutex); + return status; +} + +static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, + u16 index, unsigned char *cp, u16 size) +{ + int status = -ENODEV; + mutex_lock(&dev->mutex); + if (dev->usbdev) { + + memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg)); + + /* cp must be memory that has been allocated by kmalloc */ + status = usb_control_msg(dev->usbdev, + usb_rcvctrlpipe(dev->usbdev, 0), + request, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + cp, size, 1000); + + status = min(status, 0); + + if (status < 0) { + printk(KERN_ERR "%s() Failed receiving control message, error %d.\n", + __func__, status); + } else + cmd_msg_dump(dev); + } + mutex_unlock(&dev->mutex); + return status; +} + +static void au0828_usb_disconnect(struct usb_interface *interface) +{ + struct au0828_dev *dev = usb_get_intfdata(interface); + + dprintk(1, "%s()\n", __func__); + + /* Digital TV */ + au0828_dvb_unregister(dev); + + if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) + au0828_analog_unregister(dev); + + /* I2C */ + au0828_i2c_unregister(dev); + + v4l2_device_unregister(&dev->v4l2_dev); + + usb_set_intfdata(interface, NULL); + + mutex_lock(&dev->mutex); + dev->usbdev = NULL; + mutex_unlock(&dev->mutex); + + kfree(dev); + +} + +static int au0828_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + int ifnum, retval; + struct au0828_dev *dev; + struct usb_device *usbdev = interface_to_usbdev(interface); + + ifnum = interface->altsetting->desc.bInterfaceNumber; + + if (ifnum != 0) + return -ENODEV; + + dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__, + le16_to_cpu(usbdev->descriptor.idVendor), + le16_to_cpu(usbdev->descriptor.idProduct), + ifnum); + + /* + * Make sure we have 480 Mbps of bandwidth, otherwise things like + * video stream wouldn't likely work, since 12 Mbps is generally + * not enough even for most Digital TV streams. + */ + if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { + printk(KERN_ERR "au0828: Device initialization failed.\n"); + printk(KERN_ERR "au0828: Device must be connected to a " + "high-speed USB 2.0 port.\n"); + return -ENODEV; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + printk(KERN_ERR "%s() Unable to allocate memory\n", __func__); + return -ENOMEM; + } + + mutex_init(&dev->mutex); + mutex_init(&dev->dvb.lock); + dev->usbdev = usbdev; + dev->boardnr = id->driver_info; + + /* Create the v4l2_device */ + retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); + if (retval) { + printk(KERN_ERR "%s() v4l2_device_register failed\n", + __func__); + kfree(dev); + return -EIO; + } + + /* Power Up the bridge */ + au0828_write(dev, REG_600, 1 << 4); + + /* Bring up the GPIO's and supporting devices */ + au0828_gpio_setup(dev); + + /* I2C */ + au0828_i2c_register(dev); + + /* Setup */ + au0828_card_setup(dev); + + /* Analog TV */ + if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) + au0828_analog_register(dev, interface); + + /* Digital TV */ + au0828_dvb_register(dev); + + /* Store the pointer to the au0828_dev so it can be accessed in + au0828_usb_disconnect */ + usb_set_intfdata(interface, dev); + + printk(KERN_INFO "Registered device AU0828 [%s]\n", + dev->board.name == NULL ? "Unset" : dev->board.name); + + return 0; +} + +static struct usb_driver au0828_usb_driver = { + .name = DRIVER_NAME, + .probe = au0828_usb_probe, + .disconnect = au0828_usb_disconnect, + .id_table = au0828_usb_id_table, +}; + +static int __init au0828_init(void) +{ + int ret; + + if (au0828_debug & 1) + printk(KERN_INFO "%s() Debugging is enabled\n", __func__); + + if (au0828_debug & 2) + printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__); + + if (au0828_debug & 4) + printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__); + + if (au0828_debug & 8) + printk(KERN_INFO "%s() Bridge Debugging is enabled\n", + __func__); + + printk(KERN_INFO "au0828 driver loaded\n"); + + ret = usb_register(&au0828_usb_driver); + if (ret) + printk(KERN_ERR "usb_register failed, error = %d\n", ret); + + return ret; +} + +static void __exit au0828_exit(void) +{ + usb_deregister(&au0828_usb_driver); +} + +module_init(au0828_init); +module_exit(au0828_exit); + +MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); +MODULE_AUTHOR("Steven Toth "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-dvb.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,439 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "au0828.h" +#include "au8522.h" +#include "xc5000.h" +#include "mxl5007t.h" +#include "tda18271.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define _AU0828_BULKPIPE 0x83 +#define _BULKPIPESIZE 0xe522 + +static u8 hauppauge_hvr950q_led_states[] = { + 0x00, /* off */ + 0x02, /* yellow */ + 0x04, /* green */ +}; + +static struct au8522_led_config hauppauge_hvr950q_led_cfg = { + .gpio_output = 0x00e0, + .gpio_output_enable = 0x6006, + .gpio_output_disable = 0x0660, + + .gpio_leds = 0x00e2, + .led_states = hauppauge_hvr950q_led_states, + .num_led_states = sizeof(hauppauge_hvr950q_led_states), + + .vsb8_strong = 20 /* dB */ * 10, + .qam64_strong = 25 /* dB */ * 10, + .qam256_strong = 32 /* dB */ * 10, +}; + +static struct au8522_config hauppauge_hvr950q_config = { + .demod_address = 0x8e >> 1, + .status_mode = AU8522_DEMODLOCKING, + .qam_if = AU8522_IF_6MHZ, + .vsb_if = AU8522_IF_6MHZ, + .led_cfg = &hauppauge_hvr950q_led_cfg, +}; + +static struct au8522_config fusionhdtv7usb_config = { + .demod_address = 0x8e >> 1, + .status_mode = AU8522_DEMODLOCKING, + .qam_if = AU8522_IF_6MHZ, + .vsb_if = AU8522_IF_6MHZ, +}; + +static struct au8522_config hauppauge_woodbury_config = { + .demod_address = 0x8e >> 1, + .status_mode = AU8522_DEMODLOCKING, + .qam_if = AU8522_IF_4MHZ, + .vsb_if = AU8522_IF_3_25MHZ, +}; + +static struct xc5000_config hauppauge_hvr950q_tunerconfig = { + .i2c_address = 0x61, + .if_khz = 6000, +}; + +static struct mxl5007t_config mxl5007t_hvr950q_config = { + .xtal_freq_hz = MxL_XTAL_24_MHZ, + .if_freq_hz = MxL_IF_6_MHZ, +}; + +static struct tda18271_config hauppauge_woodbury_tunerconfig = { + .gate = TDA18271_GATE_DIGITAL, +}; + +/*-------------------------------------------------------------------*/ +static void urb_completion(struct urb *purb) +{ + struct au0828_dev *dev = purb->context; + int ptype = usb_pipetype(purb->pipe); + + dprintk(2, "%s()\n", __func__); + + if (!dev) + return; + + if (dev->urb_streaming == 0) + return; + + if (ptype != PIPE_BULK) { + printk(KERN_ERR "%s() Unsupported URB type %d\n", + __func__, ptype); + return; + } + + /* Feed the transport payload into the kernel demux */ + dvb_dmx_swfilter_packets(&dev->dvb.demux, + purb->transfer_buffer, purb->actual_length / 188); + + /* Clean the buffer before we requeue */ + memset(purb->transfer_buffer, 0, URB_BUFSIZE); + + /* Requeue URB */ + usb_submit_urb(purb, GFP_ATOMIC); +} + +static int stop_urb_transfer(struct au0828_dev *dev) +{ + int i; + + dprintk(2, "%s()\n", __func__); + + for (i = 0; i < URB_COUNT; i++) { + usb_kill_urb(dev->urbs[i]); + kfree(dev->urbs[i]->transfer_buffer); + usb_free_urb(dev->urbs[i]); + } + + dev->urb_streaming = 0; + + return 0; +} + +static int start_urb_transfer(struct au0828_dev *dev) +{ + struct urb *purb; + int i, ret = -ENOMEM; + + dprintk(2, "%s()\n", __func__); + + if (dev->urb_streaming) { + dprintk(2, "%s: bulk xfer already running!\n", __func__); + return 0; + } + + for (i = 0; i < URB_COUNT; i++) { + + dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->urbs[i]) + goto err; + + purb = dev->urbs[i]; + + purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL); + if (!purb->transfer_buffer) { + usb_free_urb(purb); + dev->urbs[i] = NULL; + goto err; + } + + purb->status = -EINPROGRESS; + usb_fill_bulk_urb(purb, + dev->usbdev, + usb_rcvbulkpipe(dev->usbdev, + _AU0828_BULKPIPE), + purb->transfer_buffer, + URB_BUFSIZE, + urb_completion, + dev); + + } + + for (i = 0; i < URB_COUNT; i++) { + ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC); + if (ret != 0) { + stop_urb_transfer(dev); + printk(KERN_ERR "%s: failed urb submission, " + "err = %d\n", __func__, ret); + return ret; + } + } + + dev->urb_streaming = 1; + ret = 0; + +err: + return ret; +} + +static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct au0828_dev *dev = (struct au0828_dev *) demux->priv; + struct au0828_dvb *dvb = &dev->dvb; + int ret = 0; + + dprintk(1, "%s()\n", __func__); + + if (!demux->dmx.frontend) + return -EINVAL; + + if (dvb) { + mutex_lock(&dvb->lock); + if (dvb->feeding++ == 0) { + /* Start transport */ + au0828_write(dev, 0x608, 0x90); + au0828_write(dev, 0x609, 0x72); + au0828_write(dev, 0x60a, 0x71); + au0828_write(dev, 0x60b, 0x01); + ret = start_urb_transfer(dev); + } + mutex_unlock(&dvb->lock); + } + + return ret; +} + +static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct au0828_dev *dev = (struct au0828_dev *) demux->priv; + struct au0828_dvb *dvb = &dev->dvb; + int ret = 0; + + dprintk(1, "%s()\n", __func__); + + if (dvb) { + mutex_lock(&dvb->lock); + if (--dvb->feeding == 0) { + /* Stop transport */ + au0828_write(dev, 0x608, 0x00); + au0828_write(dev, 0x609, 0x00); + au0828_write(dev, 0x60a, 0x00); + au0828_write(dev, 0x60b, 0x00); + ret = stop_urb_transfer(dev); + } + mutex_unlock(&dvb->lock); + } + + return ret; +} + +static int dvb_register(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + int result; + + dprintk(1, "%s()\n", __func__); + + /* register adapter */ + result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, + &dev->usbdev->dev, adapter_nr); + if (result < 0) { + printk(KERN_ERR "%s: dvb_register_adapter failed " + "(errno = %d)\n", DRIVER_NAME, result); + goto fail_adapter; + } + dvb->adapter.priv = dev; + + /* register frontend */ + result = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (result < 0) { + printk(KERN_ERR "%s: dvb_register_frontend failed " + "(errno = %d)\n", DRIVER_NAME, result); + goto fail_frontend; + } + + /* register demux stuff */ + dvb->demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + dvb->demux.priv = dev; + dvb->demux.filternum = 256; + dvb->demux.feednum = 256; + dvb->demux.start_feed = au0828_dvb_start_feed; + dvb->demux.stop_feed = au0828_dvb_stop_feed; + result = dvb_dmx_init(&dvb->demux); + if (result < 0) { + printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n", + DRIVER_NAME, result); + goto fail_dmx; + } + + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = &dvb->demux.dmx; + dvb->dmxdev.capabilities = 0; + result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); + if (result < 0) { + printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n", + DRIVER_NAME, result); + goto fail_dmxdev; + } + + dvb->fe_hw.source = DMX_FRONTEND_0; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_ERR "%s: add_frontend failed " + "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result); + goto fail_fe_hw; + } + + dvb->fe_mem.source = DMX_MEMORY_FE; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); + if (result < 0) { + printk(KERN_ERR "%s: add_frontend failed " + "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result); + goto fail_fe_mem; + } + + result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", + DRIVER_NAME, result); + goto fail_fe_conn; + } + + /* register network adapter */ + dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); + return 0; + +fail_fe_conn: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); +fail_fe_mem: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); +fail_fe_hw: + dvb_dmxdev_release(&dvb->dmxdev); +fail_dmxdev: + dvb_dmx_release(&dvb->demux); +fail_dmx: + dvb_unregister_frontend(dvb->frontend); +fail_frontend: + dvb_frontend_detach(dvb->frontend); + dvb_unregister_adapter(&dvb->adapter); +fail_adapter: + return result; +} + +void au0828_dvb_unregister(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + + dprintk(1, "%s()\n", __func__); + + if (dvb->frontend == NULL) + return; + + dvb_net_release(&dvb->net); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(&dvb->demux); + dvb_unregister_frontend(dvb->frontend); + dvb_frontend_detach(dvb->frontend); + dvb_unregister_adapter(&dvb->adapter); +} + +/* All the DVB attach calls go here, this function get's modified + * for each new card. No other function in this file needs + * to change. + */ +int au0828_dvb_register(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + int ret; + + dprintk(1, "%s()\n", __func__); + + /* init frontend */ + switch (dev->boardnr) { + case AU0828_BOARD_HAUPPAUGE_HVR850: + case AU0828_BOARD_HAUPPAUGE_HVR950Q: + dvb->frontend = dvb_attach(au8522_attach, + &hauppauge_hvr950q_config, + &dev->i2c_adap); + if (dvb->frontend != NULL) + dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, + &hauppauge_hvr950q_tunerconfig); + break; + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + dvb->frontend = dvb_attach(au8522_attach, + &hauppauge_hvr950q_config, + &dev->i2c_adap); + if (dvb->frontend != NULL) + dvb_attach(mxl5007t_attach, dvb->frontend, + &dev->i2c_adap, 0x60, + &mxl5007t_hvr950q_config); + break; + case AU0828_BOARD_HAUPPAUGE_WOODBURY: + dvb->frontend = dvb_attach(au8522_attach, + &hauppauge_woodbury_config, + &dev->i2c_adap); + if (dvb->frontend != NULL) + dvb_attach(tda18271_attach, dvb->frontend, + 0x60, &dev->i2c_adap, + &hauppauge_woodbury_tunerconfig); + break; + case AU0828_BOARD_DVICO_FUSIONHDTV7: + dvb->frontend = dvb_attach(au8522_attach, + &fusionhdtv7usb_config, + &dev->i2c_adap); + if (dvb->frontend != NULL) { + dvb_attach(xc5000_attach, dvb->frontend, + &dev->i2c_adap, + &hauppauge_hvr950q_tunerconfig); + } + break; + default: + printk(KERN_WARNING "The frontend of your DVB/ATSC card " + "isn't supported yet\n"); + break; + } + if (NULL == dvb->frontend) { + printk(KERN_ERR "%s() Frontend initialization failed\n", + __func__); + return -1; + } + /* define general-purpose callback pointer */ + dvb->frontend->callback = au0828_tuner_callback; + + /* register everything */ + ret = dvb_register(dev); + if (ret < 0) { + if (dvb->frontend->ops.release) + dvb->frontend->ops.release(dvb->frontend); + return ret; + } + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,302 @@ +/* + * Driver for the Auvitek AU0828 USB bridge + * + * Copyright (c) 2008 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +/* Analog */ +#include +#include +#include + +/* DVB */ +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" + +#include "au0828-reg.h" +#include "au0828-cards.h" + +#define DRIVER_NAME "au0828" +#define URB_COUNT 16 +#define URB_BUFSIZE (0xe522) + +/* Analog constants */ +#define NTSC_STD_W 720 +#define NTSC_STD_H 480 + +#define AU0828_INTERLACED_DEFAULT 1 +#define V4L2_CID_PRIVATE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0) + +/* Defination for AU0828 USB transfer */ +#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */ +#define AU0828_ISO_PACKETS_PER_URB 128 + +#define AU0828_MIN_BUF 4 +#define AU0828_DEF_BUF 8 + +#define AU0828_MAX_INPUT 4 + +/* au0828 resource types (used for res_get/res_lock etc */ +#define AU0828_RESOURCE_VIDEO 0x01 +#define AU0828_RESOURCE_VBI 0x02 + +enum au0828_itype { + AU0828_VMUX_UNDEFINED = 0, + AU0828_VMUX_COMPOSITE, + AU0828_VMUX_SVIDEO, + AU0828_VMUX_CABLE, + AU0828_VMUX_TELEVISION, + AU0828_VMUX_DVB, + AU0828_VMUX_DEBUG +}; + +struct au0828_input { + enum au0828_itype type; + unsigned int vmux; + unsigned int amux; + void (*audio_setup) (void *priv, int enable); +}; + +struct au0828_board { + char *name; + unsigned int tuner_type; + unsigned char tuner_addr; + unsigned char i2c_clk_divider; + struct au0828_input input[AU0828_MAX_INPUT]; + +}; + +struct au0828_dvb { + struct mutex lock; + struct dvb_adapter adapter; + struct dvb_frontend *frontend; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net net; + int feeding; +}; + +enum au0828_stream_state { + STREAM_OFF, + STREAM_INTERRUPT, + STREAM_ON +}; + +#define AUVI_INPUT(nr) (dev->board.input[nr]) + +/* device state */ +enum au0828_dev_state { + DEV_INITIALIZED = 0x01, + DEV_DISCONNECTED = 0x02, + DEV_MISCONFIGURED = 0x04 +}; + +struct au0828_fh { + struct au0828_dev *dev; + unsigned int resources; + + struct videobuf_queue vb_vidq; + struct videobuf_queue vb_vbiq; + enum v4l2_buf_type type; +}; + +struct au0828_usb_isoc_ctl { + /* max packet size of isoc transaction */ + int max_pkt_size; + + /* number of allocated urbs */ + int num_bufs; + + /* urb for isoc transfers */ + struct urb **urb; + + /* transfer buffers for isoc transfer */ + char **transfer_buffer; + + /* Last buffer command and region */ + u8 cmd; + int pos, size, pktsize; + + /* Last field: ODD or EVEN? */ + int field; + + /* Stores incomplete commands */ + u32 tmp_buf; + int tmp_buf_len; + + /* Stores already requested buffers */ + struct au0828_buffer *buf; + struct au0828_buffer *vbi_buf; + + /* Stores the number of received fields */ + int nfields; + + /* isoc urb callback */ + int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb); + +}; + +/* buffer for one video frame */ +struct au0828_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + struct list_head frame; + int top_field; + int receiving; +}; + +struct au0828_dmaqueue { + struct list_head active; + struct list_head queued; + + wait_queue_head_t wq; + + /* Counters to control buffer fill */ + int pos; +}; + +struct au0828_dev { + struct mutex mutex; + struct usb_device *usbdev; + int boardnr; + struct au0828_board board; + u8 ctrlmsg[64]; + + /* I2C */ + struct i2c_adapter i2c_adap; + struct i2c_algorithm i2c_algo; + struct i2c_client i2c_client; + u32 i2c_rc; + + /* Digital */ + struct au0828_dvb dvb; + + /* Analog */ + struct v4l2_device v4l2_dev; + int users; + unsigned int resources; /* resources in use */ + struct video_device *vdev; + struct video_device *vbi_dev; + struct timer_list vid_timeout; + int vid_timeout_running; + struct timer_list vbi_timeout; + int vbi_timeout_running; + int width; + int height; + int vbi_width; + int vbi_height; + u32 vbi_read; + u32 field_size; + u32 frame_size; + u32 bytesperline; + int type; + u8 ctrl_ainput; + __u8 isoc_in_endpointaddr; + u8 isoc_init_ok; + int greenscreen_detected; + unsigned int frame_count; + int ctrl_freq; + int input_type; + unsigned int ctrl_input; + enum au0828_dev_state dev_state; + enum au0828_stream_state stream_state; + wait_queue_head_t open; + + struct mutex lock; + + /* Isoc control struct */ + struct au0828_dmaqueue vidq; + struct au0828_dmaqueue vbiq; + struct au0828_usb_isoc_ctl isoc_ctl; + spinlock_t slock; + + /* usb transfer */ + int alt; /* alternate */ + int max_pkt_size; /* max packet size of isoc transaction */ + int num_alt; /* Number of alternative settings */ + unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ + struct urb *urb[AU0828_MAX_ISO_BUFS]; /* urb for isoc transfers */ + char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc + transfer */ + + /* USB / URB Related */ + int urb_streaming; + struct urb *urbs[URB_COUNT]; +}; + +/* ----------------------------------------------------------- */ +#define au0828_read(dev, reg) au0828_readreg(dev, reg) +#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value) +#define au0828_andor(dev, reg, mask, value) \ + au0828_writereg(dev, reg, \ + (au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask))) + +#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit)) +#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0) + +/* ----------------------------------------------------------- */ +/* au0828-core.c */ +extern u32 au0828_read(struct au0828_dev *dev, u16 reg); +extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val); +extern int au0828_debug; + +/* ----------------------------------------------------------- */ +/* au0828-cards.c */ +extern struct au0828_board au0828_boards[]; +extern struct usb_device_id au0828_usb_id_table[]; +extern void au0828_gpio_setup(struct au0828_dev *dev); +extern int au0828_tuner_callback(void *priv, int component, + int command, int arg); +extern void au0828_card_setup(struct au0828_dev *dev); + +/* ----------------------------------------------------------- */ +/* au0828-i2c.c */ +extern int au0828_i2c_register(struct au0828_dev *dev); +extern int au0828_i2c_unregister(struct au0828_dev *dev); + +/* ----------------------------------------------------------- */ +/* au0828-video.c */ +int au0828_analog_register(struct au0828_dev *dev, + struct usb_interface *interface); +int au0828_analog_stream_disable(struct au0828_dev *d); +void au0828_analog_unregister(struct au0828_dev *dev); + +/* ----------------------------------------------------------- */ +/* au0828-dvb.c */ +extern int au0828_dvb_register(struct au0828_dev *dev); +extern void au0828_dvb_unregister(struct au0828_dev *dev); + +/* au0828-vbi.c */ +extern struct videobuf_queue_ops au0828_vbi_qops; + +#define dprintk(level, fmt, arg...)\ + do { if (au0828_debug & level)\ + printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\ + } while (0) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-i2c.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,390 @@ +/* + * Driver for the Auvitek AU0828 USB bridge + * + * Copyright (c) 2008 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "au0828.h" + +#include + +static int i2c_scan; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); + +#define I2C_WAIT_DELAY 512 +#define I2C_WAIT_RETRY 64 + +static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, AU0828_I2C_STATUS_201) & + AU0828_I2C_STATUS_NO_WRITE_ACK ? 0 : 1; +} + +static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, AU0828_I2C_STATUS_201) & + AU0828_I2C_STATUS_NO_READ_ACK ? 0 : 1; +} + +static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_slave_did_read_ack(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, AU0828_I2C_STATUS_201) & + AU0828_I2C_STATUS_READ_DONE ? 0 : 1; +} + +static int i2c_wait_read_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_is_read_busy(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, AU0828_I2C_STATUS_201) & + AU0828_I2C_STATUS_WRITE_DONE ? 1 : 0; +} + +static int i2c_wait_write_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (i2c_is_write_done(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + return au0828_read(dev, AU0828_I2C_STATUS_201) & + AU0828_I2C_STATUS_BUSY ? 1 : 0; +} + +static int i2c_wait_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_is_busy(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +/* FIXME: Implement join handling correctly */ +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int joined_rlen) +{ + int i, strobe = 0; + struct au0828_dev *dev = i2c_adap->algo_data; + + dprintk(4, "%s()\n", __func__); + + au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01); + + /* Set the I2C clock */ + au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202, + dev->board.i2c_clk_divider); + + /* Hardware needs 8 bit addresses */ + au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1); + + dprintk(4, "SEND: %02x\n", msg->addr); + + /* Deal with i2c_scan */ + if (msg->len == 0) { + /* The analog tuner detection code makes use of the SMBUS_QUICK + message (which involves a zero length i2c write). To avoid + checking the status register when we didn't strobe out any + actual bytes to the bus, just do a read check. This is + consistent with how I saw i2c device checking done in the + USB trace of the Windows driver */ + au0828_write(dev, AU0828_I2C_TRIGGER_200, + AU0828_I2C_TRIGGER_READ); + + if (!i2c_wait_done(i2c_adap)) + return -EIO; + + if (i2c_wait_read_ack(i2c_adap)) + return -EIO; + + return 0; + } + + for (i = 0; i < msg->len;) { + + dprintk(4, " %02x\n", msg->buf[i]); + + au0828_write(dev, AU0828_I2C_WRITE_FIFO_205, msg->buf[i]); + + strobe++; + i++; + + if ((strobe >= 4) || (i >= msg->len)) { + + /* Strobe the byte into the bus */ + if (i < msg->len) + au0828_write(dev, AU0828_I2C_TRIGGER_200, + AU0828_I2C_TRIGGER_WRITE | + AU0828_I2C_TRIGGER_HOLD); + else + au0828_write(dev, AU0828_I2C_TRIGGER_200, + AU0828_I2C_TRIGGER_WRITE); + + /* Reset strobe trigger */ + strobe = 0; + + if (!i2c_wait_write_done(i2c_adap)) + return -EIO; + + } + + } + if (!i2c_wait_done(i2c_adap)) + return -EIO; + + dprintk(4, "\n"); + + return msg->len; +} + +/* FIXME: Implement join handling correctly */ +static int i2c_readbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int joined) +{ + struct au0828_dev *dev = i2c_adap->algo_data; + int i; + + dprintk(4, "%s()\n", __func__); + + au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01); + + /* Set the I2C clock */ + au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202, + dev->board.i2c_clk_divider); + + /* Hardware needs 8 bit addresses */ + au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1); + + dprintk(4, " RECV:\n"); + + /* Deal with i2c_scan */ + if (msg->len == 0) { + au0828_write(dev, AU0828_I2C_TRIGGER_200, + AU0828_I2C_TRIGGER_READ); + + if (i2c_wait_read_ack(i2c_adap)) + return -EIO; + return 0; + } + + for (i = 0; i < msg->len;) { + + i++; + + if (i < msg->len) + au0828_write(dev, AU0828_I2C_TRIGGER_200, + AU0828_I2C_TRIGGER_READ | + AU0828_I2C_TRIGGER_HOLD); + else + au0828_write(dev, AU0828_I2C_TRIGGER_200, + AU0828_I2C_TRIGGER_READ); + + if (!i2c_wait_read_done(i2c_adap)) + return -EIO; + + msg->buf[i-1] = au0828_read(dev, AU0828_I2C_READ_FIFO_209) & + 0xff; + + dprintk(4, " %02x\n", msg->buf[i-1]); + } + if (!i2c_wait_done(i2c_adap)) + return -EIO; + + dprintk(4, "\n"); + + return msg->len; +} + +static int i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + int i, retval = 0; + + dprintk(4, "%s(num = %d)\n", __func__, num); + + for (i = 0; i < num; i++) { + dprintk(4, "%s(num = %d) addr = 0x%02x len = 0x%x\n", + __func__, num, msgs[i].addr, msgs[i].len); + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = i2c_readbytes(i2c_adap, &msgs[i], 0); + } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && + msgs[i].addr == msgs[i + 1].addr) { + /* write then read from same address */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], + msgs[i + 1].len); + if (retval < 0) + goto err; + i++; + retval = i2c_readbytes(i2c_adap, &msgs[i], 1); + } else { + /* write */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); + } + if (retval < 0) + goto err; + } + return num; + +err: + return retval; +} + +static u32 au0828_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; +} + +static struct i2c_algorithm au0828_i2c_algo_template = { + .master_xfer = i2c_xfer, + .functionality = au0828_functionality, +}; + +/* ----------------------------------------------------------------------- */ + +static struct i2c_adapter au0828_i2c_adap_template = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .algo = &au0828_i2c_algo_template, +}; + +static struct i2c_client au0828_i2c_client_template = { + .name = "au0828 internal", +}; + +static char *i2c_devs[128] = { + [0x8e >> 1] = "au8522", + [0xa0 >> 1] = "eeprom", + [0xc2 >> 1] = "tuner/xc5000", +}; + +static void do_i2c_scan(char *name, struct i2c_client *c) +{ + unsigned char buf; + int i, rc; + + for (i = 0; i < 128; i++) { + c->addr = i; + rc = i2c_master_recv(c, &buf, 0); + if (rc < 0) + continue; + printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + } +} + +/* init + register i2c algo-bit adapter */ +int au0828_i2c_register(struct au0828_dev *dev) +{ + dprintk(1, "%s()\n", __func__); + + memcpy(&dev->i2c_adap, &au0828_i2c_adap_template, + sizeof(dev->i2c_adap)); + memcpy(&dev->i2c_algo, &au0828_i2c_algo_template, + sizeof(dev->i2c_algo)); + memcpy(&dev->i2c_client, &au0828_i2c_client_template, + sizeof(dev->i2c_client)); + + dev->i2c_adap.dev.parent = &dev->usbdev->dev; + + strlcpy(dev->i2c_adap.name, DRIVER_NAME, + sizeof(dev->i2c_adap.name)); + + dev->i2c_adap.algo = &dev->i2c_algo; + dev->i2c_adap.algo_data = dev; + i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); + i2c_add_adapter(&dev->i2c_adap); + + dev->i2c_client.adapter = &dev->i2c_adap; + + if (0 == dev->i2c_rc) { + printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME); + if (i2c_scan) + do_i2c_scan(DRIVER_NAME, &dev->i2c_client); + } else + printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME); + + return dev->i2c_rc; +} + +int au0828_i2c_unregister(struct au0828_dev *dev) +{ + i2c_del_adapter(&dev->i2c_adap); + return 0; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,65 @@ +/* + * Driver for the Auvitek USB bridge + * + * Copyright (c) 2008 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* We'll start to rename these registers once we have a better + * understanding of their meaning. + */ +#define REG_000 0x000 +#define REG_001 0x001 +#define REG_002 0x002 +#define REG_003 0x003 + +#define AU0828_SENSORCTRL_100 0x100 +#define AU0828_SENSORCTRL_VBI_103 0x103 + +/* I2C registers */ +#define AU0828_I2C_TRIGGER_200 0x200 +#define AU0828_I2C_STATUS_201 0x201 +#define AU0828_I2C_CLK_DIVIDER_202 0x202 +#define AU0828_I2C_DEST_ADDR_203 0x203 +#define AU0828_I2C_WRITE_FIFO_205 0x205 +#define AU0828_I2C_READ_FIFO_209 0x209 +#define AU0828_I2C_MULTIBYTE_MODE_2FF 0x2ff + +/* Audio registers */ +#define AU0828_AUDIOCTRL_50C 0x50C + +#define REG_600 0x600 + +/*********************************************************************/ +/* Here are constants for values associated with the above registers */ + +/* I2C Trigger (Reg 0x200) */ +#define AU0828_I2C_TRIGGER_WRITE 0x01 +#define AU0828_I2C_TRIGGER_READ 0x20 +#define AU0828_I2C_TRIGGER_HOLD 0x40 + +/* I2C Status (Reg 0x201) */ +#define AU0828_I2C_STATUS_READ_DONE 0x01 +#define AU0828_I2C_STATUS_NO_READ_ACK 0x02 +#define AU0828_I2C_STATUS_WRITE_DONE 0x04 +#define AU0828_I2C_STATUS_NO_WRITE_ACK 0x08 +#define AU0828_I2C_STATUS_BUSY 0x10 + +/* I2C Clock Divider (Reg 0x202) */ +#define AU0828_I2C_CLK_250KHZ 0x07 +#define AU0828_I2C_CLK_100KHZ 0x14 +#define AU0828_I2C_CLK_30KHZ 0x40 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-vbi.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,138 @@ +/* + au0828-vbi.c - VBI driver for au0828 + + Copyright (C) 2010 Devin Heitmueller + + This work was sponsored by GetWellNetwork Inc. + + 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, or + (at your option) any later version. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include "au0828.h" + +static unsigned int vbibufs = 5; +module_param(vbibufs, int, 0644); +MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); + +/* ------------------------------------------------------------------ */ + +static void +free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf) +{ + struct au0828_fh *fh = vq->priv_data; + struct au0828_dev *dev = fh->dev; + unsigned long flags = 0; + if (in_interrupt()) + BUG(); + + /* We used to wait for the buffer to finish here, but this didn't work + because, as we were keeping the state as VIDEOBUF_QUEUED, + videobuf_queue_cancel marked it as finished for us. + (Also, it could wedge forever if the hardware was misconfigured.) + + This should be safe; by the time we get here, the buffer isn't + queued anymore. If we ever start marking the buffers as + VIDEOBUF_ACTIVE, it won't be, though. + */ + spin_lock_irqsave(&dev->slock, flags); + if (dev->isoc_ctl.vbi_buf == buf) + dev->isoc_ctl.vbi_buf = NULL; + spin_unlock_irqrestore(&dev->slock, flags); + + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int +vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + struct au0828_fh *fh = q->priv_data; + struct au0828_dev *dev = fh->dev; + + *size = dev->vbi_width * dev->vbi_height * 2; + + if (0 == *count) + *count = vbibufs; + if (*count < 2) + *count = 2; + if (*count > 32) + *count = 32; + return 0; +} + +static int +vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct au0828_fh *fh = q->priv_data; + struct au0828_dev *dev = fh->dev; + struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); + int rc = 0; + + buf->vb.size = dev->vbi_width * dev->vbi_height * 2; + + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + buf->vb.width = dev->vbi_width; + buf->vb.height = dev->vbi_height; + buf->vb.field = field; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(q, &buf->vb, NULL); + if (rc < 0) + goto fail; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(q, buf); + return rc; +} + +static void +vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct au0828_buffer *buf = container_of(vb, + struct au0828_buffer, + vb); + struct au0828_fh *fh = vq->priv_data; + struct au0828_dev *dev = fh->dev; + struct au0828_dmaqueue *vbiq = &dev->vbiq; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vbiq->active); +} + +static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); + free_buffer(q, buf); +} + +struct videobuf_queue_ops au0828_vbi_qops = { + .buf_setup = vbi_setup, + .buf_prepare = vbi_prepare, + .buf_queue = vbi_queue, + .buf_release = vbi_release, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-video.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/au0828-video.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1998 @@ +/* + * Auvitek AU0828 USB Bridge (Analog video support) + * + * Copyright (C) 2009 Devin Heitmueller + * Copyright (C) 2005-2008 Auvitek International, Ltd. + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* Developer Notes: + * + * VBI support is not yet working + * The hardware scaler supported is unimplemented + * AC97 audio support is unimplemented (only i2s audio mode) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "au0828.h" +#include "au0828-reg.h" + +static DEFINE_MUTEX(au0828_sysfs_lock); + +#define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1) + +/* ------------------------------------------------------------------ + Videobuf operations + ------------------------------------------------------------------*/ + +static unsigned int isoc_debug; +module_param(isoc_debug, int, 0644); +MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); + +#define au0828_isocdbg(fmt, arg...) \ +do {\ + if (isoc_debug) { \ + printk(KERN_INFO "au0828 %s :"fmt, \ + __func__ , ##arg); \ + } \ + } while (0) + +static inline void print_err_status(struct au0828_dev *dev, + int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + au0828_isocdbg("URB status %d [%s].\n", status, errmsg); + } else { + au0828_isocdbg("URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + +static int check_dev(struct au0828_dev *dev) +{ + if (dev->dev_state & DEV_DISCONNECTED) { + printk(KERN_INFO "v4l2 ioctl: device not present\n"); + return -ENODEV; + } + + if (dev->dev_state & DEV_MISCONFIGURED) { + printk(KERN_INFO "v4l2 ioctl: device is misconfigured; " + "close and open it again\n"); + return -EIO; + } + return 0; +} + +/* + * IRQ callback, called by URB callback + */ +static void au0828_irq_callback(struct urb *urb) +{ + struct au0828_dmaqueue *dma_q = urb->context; + struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq); + unsigned long flags = 0; + int rc, i; + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + au0828_isocdbg("au0828_irq_callback called: status kill\n"); + return; + default: /* unknown error */ + au0828_isocdbg("urb completition error %d.\n", urb->status); + break; + } + + /* Copy data from URB */ + spin_lock_irqsave(&dev->slock, flags); + rc = dev->isoc_ctl.isoc_copy(dev, urb); + spin_unlock_irqrestore(&dev->slock, flags); + + /* Reset urb buffers */ + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + urb->status = 0; + + urb->status = usb_submit_urb(urb, GFP_ATOMIC); + if (urb->status) { + au0828_isocdbg("urb resubmit failed (error=%i)\n", + urb->status); + } +} + +/* + * Stop and Deallocate URBs + */ +void au0828_uninit_isoc(struct au0828_dev *dev) +{ + struct urb *urb; + int i; + + au0828_isocdbg("au0828: called au0828_uninit_isoc\n"); + + dev->isoc_ctl.nfields = -1; + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = dev->isoc_ctl.urb[i]; + if (urb) { + if (!irqs_disabled()) + usb_kill_urb(urb); + else + usb_unlink_urb(urb); + + if (dev->isoc_ctl.transfer_buffer[i]) { + usb_free_coherent(dev->usbdev, + urb->transfer_buffer_length, + dev->isoc_ctl.transfer_buffer[i], + urb->transfer_dma); + } + usb_free_urb(urb); + dev->isoc_ctl.urb[i] = NULL; + } + dev->isoc_ctl.transfer_buffer[i] = NULL; + } + + kfree(dev->isoc_ctl.urb); + kfree(dev->isoc_ctl.transfer_buffer); + + dev->isoc_ctl.urb = NULL; + dev->isoc_ctl.transfer_buffer = NULL; + dev->isoc_ctl.num_bufs = 0; +} + +/* + * Allocate URBs and start IRQ + */ +int au0828_init_isoc(struct au0828_dev *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb)) +{ + struct au0828_dmaqueue *dma_q = &dev->vidq; + int i; + int sb_size, pipe; + struct urb *urb; + int j, k; + int rc; + + au0828_isocdbg("au0828: called au0828_prepare_isoc\n"); + + /* De-allocates all pending stuff */ + au0828_uninit_isoc(dev); + + dev->isoc_ctl.isoc_copy = isoc_copy; + dev->isoc_ctl.num_bufs = num_bufs; + + dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + if (!dev->isoc_ctl.urb) { + au0828_isocdbg("cannot alloc memory for usb buffers\n"); + return -ENOMEM; + } + + dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, + GFP_KERNEL); + if (!dev->isoc_ctl.transfer_buffer) { + au0828_isocdbg("cannot allocate memory for usb transfer\n"); + kfree(dev->isoc_ctl.urb); + return -ENOMEM; + } + + dev->isoc_ctl.max_pkt_size = max_pkt_size; + dev->isoc_ctl.buf = NULL; + + sb_size = max_packets * dev->isoc_ctl.max_pkt_size; + + /* allocate urbs and transfer buffers */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = usb_alloc_urb(max_packets, GFP_KERNEL); + if (!urb) { + au0828_isocdbg("cannot alloc isoc_ctl.urb %i\n", i); + au0828_uninit_isoc(dev); + return -ENOMEM; + } + dev->isoc_ctl.urb[i] = urb; + + dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev, + sb_size, GFP_KERNEL, &urb->transfer_dma); + if (!dev->isoc_ctl.transfer_buffer[i]) { + printk("unable to allocate %i bytes for transfer" + " buffer %i%s\n", + sb_size, i, + in_interrupt() ? " while in int" : ""); + au0828_uninit_isoc(dev); + return -ENOMEM; + } + memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); + + pipe = usb_rcvisocpipe(dev->usbdev, + dev->isoc_in_endpointaddr), + + usb_fill_int_urb(urb, dev->usbdev, pipe, + dev->isoc_ctl.transfer_buffer[i], sb_size, + au0828_irq_callback, dma_q, 1); + + urb->number_of_packets = max_packets; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + + k = 0; + for (j = 0; j < max_packets; j++) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = + dev->isoc_ctl.max_pkt_size; + k += dev->isoc_ctl.max_pkt_size; + } + } + + init_waitqueue_head(&dma_q->wq); + + /* submit urbs and enables IRQ */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); + if (rc) { + au0828_isocdbg("submit of urb %i failed (error=%i)\n", + i, rc); + au0828_uninit_isoc(dev); + return rc; + } + } + + return 0; +} + +/* + * Announces that a buffer were filled and request the next + */ +static inline void buffer_filled(struct au0828_dev *dev, + struct au0828_dmaqueue *dma_q, + struct au0828_buffer *buf) +{ + /* Advice that buffer was filled */ + au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); + + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + + dev->isoc_ctl.buf = NULL; + + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); +} + +static inline void vbi_buffer_filled(struct au0828_dev *dev, + struct au0828_dmaqueue *dma_q, + struct au0828_buffer *buf) +{ + /* Advice that buffer was filled */ + au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); + + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + + dev->isoc_ctl.vbi_buf = NULL; + + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); +} + +/* + * Identify the buffer header type and properly handles + */ +static void au0828_copy_video(struct au0828_dev *dev, + struct au0828_dmaqueue *dma_q, + struct au0828_buffer *buf, + unsigned char *p, + unsigned char *outp, unsigned long len) +{ + void *fieldstart, *startwrite, *startread; + int linesdone, currlinedone, offset, lencopy, remain; + int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */ + + if (len == 0) + return; + + if (dma_q->pos + len > buf->vb.size) + len = buf->vb.size - dma_q->pos; + + startread = p; + remain = len; + + /* Interlaces frame */ + if (buf->top_field) + fieldstart = outp; + else + fieldstart = outp + bytesperline; + + linesdone = dma_q->pos / bytesperline; + currlinedone = dma_q->pos % bytesperline; + offset = linesdone * bytesperline * 2 + currlinedone; + startwrite = fieldstart + offset; + lencopy = bytesperline - currlinedone; + lencopy = lencopy > remain ? remain : lencopy; + + if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) { + au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n", + ((char *)startwrite + lencopy) - + ((char *)outp + buf->vb.size)); + remain = (char *)outp + buf->vb.size - (char *)startwrite; + lencopy = remain; + } + if (lencopy <= 0) + return; + memcpy(startwrite, startread, lencopy); + + remain -= lencopy; + + while (remain > 0) { + startwrite += lencopy + bytesperline; + startread += lencopy; + if (bytesperline > remain) + lencopy = remain; + else + lencopy = bytesperline; + + if ((char *)startwrite + lencopy > (char *)outp + + buf->vb.size) { + au0828_isocdbg("Overflow %zi bytes past buf end (2)\n", + ((char *)startwrite + lencopy) - + ((char *)outp + buf->vb.size)); + lencopy = remain = (char *)outp + buf->vb.size - + (char *)startwrite; + } + if (lencopy <= 0) + break; + + memcpy(startwrite, startread, lencopy); + + remain -= lencopy; + } + + if (offset > 1440) { + /* We have enough data to check for greenscreen */ + if (outp[0] < 0x60 && outp[1440] < 0x60) + dev->greenscreen_detected = 1; + } + + dma_q->pos += len; +} + +/* + * video-buf generic routine to get the next available buffer + */ +static inline void get_next_buf(struct au0828_dmaqueue *dma_q, + struct au0828_buffer **buf) +{ + struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq); + + if (list_empty(&dma_q->active)) { + au0828_isocdbg("No active queue to serve\n"); + dev->isoc_ctl.buf = NULL; + *buf = NULL; + return; + } + + /* Get the next buffer */ + *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue); + dev->isoc_ctl.buf = *buf; + + return; +} + +static void au0828_copy_vbi(struct au0828_dev *dev, + struct au0828_dmaqueue *dma_q, + struct au0828_buffer *buf, + unsigned char *p, + unsigned char *outp, unsigned long len) +{ + unsigned char *startwrite, *startread; + int bytesperline; + int i, j = 0; + + if (dev == NULL) { + au0828_isocdbg("dev is null\n"); + return; + } + + if (dma_q == NULL) { + au0828_isocdbg("dma_q is null\n"); + return; + } + if (buf == NULL) + return; + if (p == NULL) { + au0828_isocdbg("p is null\n"); + return; + } + if (outp == NULL) { + au0828_isocdbg("outp is null\n"); + return; + } + + bytesperline = dev->vbi_width; + + if (dma_q->pos + len > buf->vb.size) + len = buf->vb.size - dma_q->pos; + + startread = p; + startwrite = outp + (dma_q->pos / 2); + + /* Make sure the bottom field populates the second half of the frame */ + if (buf->top_field == 0) + startwrite += bytesperline * dev->vbi_height; + + for (i = 0; i < len; i += 2) + startwrite[j++] = startread[i+1]; + + dma_q->pos += len; +} + + +/* + * video-buf generic routine to get the next available VBI buffer + */ +static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q, + struct au0828_buffer **buf) +{ + struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq); + char *outp; + + if (list_empty(&dma_q->active)) { + au0828_isocdbg("No active queue to serve\n"); + dev->isoc_ctl.vbi_buf = NULL; + *buf = NULL; + return; + } + + /* Get the next buffer */ + *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue); + /* Cleans up buffer - Useful for testing for frame/URB loss */ + outp = videobuf_to_vmalloc(&(*buf)->vb); + memset(outp, 0x00, (*buf)->vb.size); + + dev->isoc_ctl.vbi_buf = *buf; + + return; +} + +/* + * Controls the isoc copy of each urb packet + */ +static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) +{ + struct au0828_buffer *buf; + struct au0828_buffer *vbi_buf; + struct au0828_dmaqueue *dma_q = urb->context; + struct au0828_dmaqueue *vbi_dma_q = &dev->vbiq; + unsigned char *outp = NULL; + unsigned char *vbioutp = NULL; + int i, len = 0, rc = 1; + unsigned char *p; + unsigned char fbyte; + unsigned int vbi_field_size; + unsigned int remain, lencopy; + + if (!dev) + return 0; + + if ((dev->dev_state & DEV_DISCONNECTED) || + (dev->dev_state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + buf = dev->isoc_ctl.buf; + if (buf != NULL) + outp = videobuf_to_vmalloc(&buf->vb); + + vbi_buf = dev->isoc_ctl.vbi_buf; + if (vbi_buf != NULL) + vbioutp = videobuf_to_vmalloc(&vbi_buf->vb); + + for (i = 0; i < urb->number_of_packets; i++) { + int status = urb->iso_frame_desc[i].status; + + if (status < 0) { + print_err_status(dev, i, status); + if (urb->iso_frame_desc[i].status != -EPROTO) + continue; + } + + if (urb->iso_frame_desc[i].actual_length <= 0) + continue; + + if (urb->iso_frame_desc[i].actual_length > + dev->max_pkt_size) { + au0828_isocdbg("packet bigger than packet size"); + continue; + } + + p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + fbyte = p[0]; + len = urb->iso_frame_desc[i].actual_length - 4; + p += 4; + + if (fbyte & 0x80) { + len -= 4; + p += 4; + au0828_isocdbg("Video frame %s\n", + (fbyte & 0x40) ? "odd" : "even"); + if (fbyte & 0x40) { + /* VBI */ + if (vbi_buf != NULL) + vbi_buffer_filled(dev, + vbi_dma_q, + vbi_buf); + vbi_get_next_buf(vbi_dma_q, &vbi_buf); + if (vbi_buf == NULL) + vbioutp = NULL; + else + vbioutp = videobuf_to_vmalloc( + &vbi_buf->vb); + + /* Video */ + if (buf != NULL) + buffer_filled(dev, dma_q, buf); + get_next_buf(dma_q, &buf); + if (buf == NULL) + outp = NULL; + else + outp = videobuf_to_vmalloc(&buf->vb); + + /* As long as isoc traffic is arriving, keep + resetting the timer */ + if (dev->vid_timeout_running) + mod_timer(&dev->vid_timeout, + jiffies + (HZ / 10)); + if (dev->vbi_timeout_running) + mod_timer(&dev->vbi_timeout, + jiffies + (HZ / 10)); + } + + if (buf != NULL) { + if (fbyte & 0x40) + buf->top_field = 1; + else + buf->top_field = 0; + } + + if (vbi_buf != NULL) { + if (fbyte & 0x40) + vbi_buf->top_field = 1; + else + vbi_buf->top_field = 0; + } + + dev->vbi_read = 0; + vbi_dma_q->pos = 0; + dma_q->pos = 0; + } + + vbi_field_size = dev->vbi_width * dev->vbi_height * 2; + if (dev->vbi_read < vbi_field_size) { + remain = vbi_field_size - dev->vbi_read; + if (len < remain) + lencopy = len; + else + lencopy = remain; + + if (vbi_buf != NULL) + au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p, + vbioutp, len); + + len -= lencopy; + p += lencopy; + dev->vbi_read += lencopy; + } + + if (dev->vbi_read >= vbi_field_size && buf != NULL) + au0828_copy_video(dev, dma_q, buf, p, outp, len); + } + return rc; +} + +static int +buffer_setup(struct videobuf_queue *vq, unsigned int *count, + unsigned int *size) +{ + struct au0828_fh *fh = vq->priv_data; + *size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3; + + if (0 == *count) + *count = AU0828_DEF_BUF; + + if (*count < AU0828_MIN_BUF) + *count = AU0828_MIN_BUF; + return 0; +} + +/* This is called *without* dev->slock held; please keep it that way */ +static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf) +{ + struct au0828_fh *fh = vq->priv_data; + struct au0828_dev *dev = fh->dev; + unsigned long flags = 0; + if (in_interrupt()) + BUG(); + + /* We used to wait for the buffer to finish here, but this didn't work + because, as we were keeping the state as VIDEOBUF_QUEUED, + videobuf_queue_cancel marked it as finished for us. + (Also, it could wedge forever if the hardware was misconfigured.) + + This should be safe; by the time we get here, the buffer isn't + queued anymore. If we ever start marking the buffers as + VIDEOBUF_ACTIVE, it won't be, though. + */ + spin_lock_irqsave(&dev->slock, flags); + if (dev->isoc_ctl.buf == buf) + dev->isoc_ctl.buf = NULL; + spin_unlock_irqrestore(&dev->slock, flags); + + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int +buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct au0828_fh *fh = vq->priv_data; + struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); + struct au0828_dev *dev = fh->dev; + int rc = 0, urb_init = 0; + + buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3; + + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + buf->vb.width = dev->width; + buf->vb.height = dev->height; + buf->vb.field = field; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc < 0) { + printk(KERN_INFO "videobuf_iolock failed\n"); + goto fail; + } + } + + if (!dev->isoc_ctl.num_bufs) + urb_init = 1; + + if (urb_init) { + rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB, + AU0828_MAX_ISO_BUFS, dev->max_pkt_size, + au0828_isoc_copy); + if (rc < 0) { + printk(KERN_INFO "au0828_init_isoc failed\n"); + goto fail; + } + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(vq, buf); + return rc; +} + +static void +buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct au0828_buffer *buf = container_of(vb, + struct au0828_buffer, + vb); + struct au0828_fh *fh = vq->priv_data; + struct au0828_dev *dev = fh->dev; + struct au0828_dmaqueue *vidq = &dev->vidq; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vidq->active); +} + +static void buffer_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct au0828_buffer *buf = container_of(vb, + struct au0828_buffer, + vb); + + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops au0828_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/* ------------------------------------------------------------------ + V4L2 interface + ------------------------------------------------------------------*/ + +static int au0828_i2s_init(struct au0828_dev *dev) +{ + /* Enable i2s mode */ + au0828_writereg(dev, AU0828_AUDIOCTRL_50C, 0x01); + return 0; +} + +/* + * Auvitek au0828 analog stream enable + * Please set interface0 to AS5 before enable the stream + */ +int au0828_analog_stream_enable(struct au0828_dev *d) +{ + dprintk(1, "au0828_analog_stream_enable called\n"); + au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00); + au0828_writereg(d, 0x106, 0x00); + /* set x position */ + au0828_writereg(d, 0x110, 0x00); + au0828_writereg(d, 0x111, 0x00); + au0828_writereg(d, 0x114, 0xa0); + au0828_writereg(d, 0x115, 0x05); + /* set y position */ + au0828_writereg(d, 0x112, 0x00); + au0828_writereg(d, 0x113, 0x00); + au0828_writereg(d, 0x116, 0xf2); + au0828_writereg(d, 0x117, 0x00); + au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3); + + return 0; +} + +int au0828_analog_stream_disable(struct au0828_dev *d) +{ + dprintk(1, "au0828_analog_stream_disable called\n"); + au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0); + return 0; +} + +void au0828_analog_stream_reset(struct au0828_dev *dev) +{ + dprintk(1, "au0828_analog_stream_reset called\n"); + au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0); + mdelay(30); + au0828_writereg(dev, AU0828_SENSORCTRL_100, 0xb3); +} + +/* + * Some operations needs to stop current streaming + */ +static int au0828_stream_interrupt(struct au0828_dev *dev) +{ + int ret = 0; + + dev->stream_state = STREAM_INTERRUPT; + if (dev->dev_state == DEV_DISCONNECTED) + return -ENODEV; + else if (ret) { + dev->dev_state = DEV_MISCONFIGURED; + dprintk(1, "%s device is misconfigured!\n", __func__); + return ret; + } + return 0; +} + +/* + * au0828_release_resources + * unregister v4l2 devices + */ +void au0828_analog_unregister(struct au0828_dev *dev) +{ + dprintk(1, "au0828_release_resources called\n"); + mutex_lock(&au0828_sysfs_lock); + + if (dev->vdev) + video_unregister_device(dev->vdev); + if (dev->vbi_dev) + video_unregister_device(dev->vbi_dev); + + mutex_unlock(&au0828_sysfs_lock); +} + + +/* Usage lock check functions */ +static int res_get(struct au0828_fh *fh, unsigned int bit) +{ + struct au0828_dev *dev = fh->dev; + + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + mutex_lock(&dev->lock); + if (dev->resources & bit) { + /* no, someone else uses it */ + mutex_unlock(&dev->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->resources |= bit; + dprintk(1, "res: get %d\n", bit); + mutex_unlock(&dev->lock); + return 1; +} + +static int res_check(struct au0828_fh *fh, unsigned int bit) +{ + return fh->resources & bit; +} + +static int res_locked(struct au0828_dev *dev, unsigned int bit) +{ + return dev->resources & bit; +} + +static void res_free(struct au0828_fh *fh, unsigned int bits) +{ + struct au0828_dev *dev = fh->dev; + + BUG_ON((fh->resources & bits) != bits); + + mutex_lock(&dev->lock); + fh->resources &= ~bits; + dev->resources &= ~bits; + dprintk(1, "res: put %d\n", bits); + mutex_unlock(&dev->lock); +} + +static int get_ressource(struct au0828_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return AU0828_RESOURCE_VIDEO; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return AU0828_RESOURCE_VBI; + default: + BUG(); + return 0; + } +} + +/* This function ensures that video frames continue to be delivered even if + the ITU-656 input isn't receiving any data (thereby preventing applications + such as tvtime from hanging) */ +void au0828_vid_buffer_timeout(unsigned long data) +{ + struct au0828_dev *dev = (struct au0828_dev *) data; + struct au0828_dmaqueue *dma_q = &dev->vidq; + struct au0828_buffer *buf; + unsigned char *vid_data; + unsigned long flags = 0; + + spin_lock_irqsave(&dev->slock, flags); + + buf = dev->isoc_ctl.buf; + if (buf != NULL) { + vid_data = videobuf_to_vmalloc(&buf->vb); + memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */ + buffer_filled(dev, dma_q, buf); + } + get_next_buf(dma_q, &buf); + + if (dev->vid_timeout_running == 1) + mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); + + spin_unlock_irqrestore(&dev->slock, flags); +} + +void au0828_vbi_buffer_timeout(unsigned long data) +{ + struct au0828_dev *dev = (struct au0828_dev *) data; + struct au0828_dmaqueue *dma_q = &dev->vbiq; + struct au0828_buffer *buf; + unsigned char *vbi_data; + unsigned long flags = 0; + + spin_lock_irqsave(&dev->slock, flags); + + buf = dev->isoc_ctl.vbi_buf; + if (buf != NULL) { + vbi_data = videobuf_to_vmalloc(&buf->vb); + memset(vbi_data, 0x00, buf->vb.size); + vbi_buffer_filled(dev, dma_q, buf); + } + vbi_get_next_buf(dma_q, &buf); + + if (dev->vbi_timeout_running == 1) + mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); + spin_unlock_irqrestore(&dev->slock, flags); +} + + +static int au0828_v4l2_open(struct file *filp) +{ + int ret = 0; + struct video_device *vdev = video_devdata(filp); + struct au0828_dev *dev = video_drvdata(filp); + struct au0828_fh *fh; + int type; + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + default: + return -EINVAL; + } + + fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL); + if (NULL == fh) { + dprintk(1, "Failed allocate au0828_fh struct!\n"); + return -ENOMEM; + } + + fh->type = type; + fh->dev = dev; + filp->private_data = fh; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { + /* set au0828 interface0 to AS5 here again */ + ret = usb_set_interface(dev->usbdev, 0, 5); + if (ret < 0) { + printk(KERN_INFO "Au0828 can't set alternate to 5!\n"); + return -EBUSY; + } + dev->width = NTSC_STD_W; + dev->height = NTSC_STD_H; + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->width * dev->height; + dev->bytesperline = dev->width * 2; + + au0828_analog_stream_enable(dev); + au0828_analog_stream_reset(dev); + + /* If we were doing ac97 instead of i2s, it would go here...*/ + au0828_i2s_init(dev); + + dev->stream_state = STREAM_OFF; + dev->dev_state |= DEV_INITIALIZED; + } + + dev->users++; + + videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops, + NULL, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct au0828_buffer), fh, NULL); + + /* VBI Setup */ + dev->vbi_width = 720; + dev->vbi_height = 1; + videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops, + NULL, &dev->slock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, + sizeof(struct au0828_buffer), fh, NULL); + + return ret; +} + +static int au0828_v4l2_close(struct file *filp) +{ + int ret; + struct au0828_fh *fh = filp->private_data; + struct au0828_dev *dev = fh->dev; + + if (res_check(fh, AU0828_RESOURCE_VIDEO)) { + /* Cancel timeout thread in case they didn't call streamoff */ + dev->vid_timeout_running = 0; + del_timer_sync(&dev->vid_timeout); + + videobuf_stop(&fh->vb_vidq); + res_free(fh, AU0828_RESOURCE_VIDEO); + } + + if (res_check(fh, AU0828_RESOURCE_VBI)) { + /* Cancel timeout thread in case they didn't call streamoff */ + dev->vbi_timeout_running = 0; + del_timer_sync(&dev->vbi_timeout); + + videobuf_stop(&fh->vb_vbiq); + res_free(fh, AU0828_RESOURCE_VBI); + } + + if (dev->users == 1) { + if (dev->dev_state & DEV_DISCONNECTED) { + au0828_analog_unregister(dev); + kfree(dev); + return 0; + } + + au0828_analog_stream_disable(dev); + + au0828_uninit_isoc(dev); + + /* Save some power by putting tuner to sleep */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); + + /* When close the device, set the usb intf0 into alt0 to free + USB bandwidth */ + ret = usb_set_interface(dev->usbdev, 0, 0); + if (ret < 0) + printk(KERN_INFO "Au0828 can't set alternate to 0!\n"); + } + + videobuf_mmap_free(&fh->vb_vidq); + videobuf_mmap_free(&fh->vb_vbiq); + kfree(fh); + dev->users--; + wake_up_interruptible_nr(&dev->open, 1); + return 0; +} + +static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf, + size_t count, loff_t *pos) +{ + struct au0828_fh *fh = filp->private_data; + struct au0828_dev *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (res_locked(dev, AU0828_RESOURCE_VIDEO)) + return -EBUSY; + + return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, + filp->f_flags & O_NONBLOCK); + } + + if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (!res_get(fh, AU0828_RESOURCE_VBI)) + return -EBUSY; + + if (dev->vbi_timeout_running == 0) { + /* Handle case where caller tries to read without + calling streamon first */ + dev->vbi_timeout_running = 1; + mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); + } + + return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, + filp->f_flags & O_NONBLOCK); + } + + return 0; +} + +static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait) +{ + struct au0828_fh *fh = filp->private_data; + struct au0828_dev *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (!res_get(fh, AU0828_RESOURCE_VIDEO)) + return POLLERR; + return videobuf_poll_stream(filp, &fh->vb_vidq, wait); + } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (!res_get(fh, AU0828_RESOURCE_VBI)) + return POLLERR; + return videobuf_poll_stream(filp, &fh->vb_vbiq, wait); + } else { + return POLLERR; + } +} + +static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct au0828_fh *fh = filp->private_data; + struct au0828_dev *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); + else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma); + + return rc; +} + +static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, + struct v4l2_format *format) +{ + int ret; + int width = format->fmt.pix.width; + int height = format->fmt.pix.height; + + if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + /* If they are demanding a format other than the one we support, + bail out (tvtime asks for UYVY and then retries with YUYV) */ + if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY) + return -EINVAL; + + /* format->fmt.pix.width only support 720 and height 480 */ + if (width != 720) + width = 720; + if (height != 480) + height = 480; + + format->fmt.pix.width = width; + format->fmt.pix.height = height; + format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; + format->fmt.pix.bytesperline = width * 2; + format->fmt.pix.sizeimage = width * height * 2; + format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + format->fmt.pix.field = V4L2_FIELD_INTERLACED; + + if (cmd == VIDIOC_TRY_FMT) + return 0; + + /* maybe set new image format, driver current only support 720*480 */ + dev->width = width; + dev->height = height; + dev->frame_size = width * height * 2; + dev->field_size = width * height; + dev->bytesperline = width * 2; + + if (dev->stream_state == STREAM_ON) { + dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n"); + ret = au0828_stream_interrupt(dev); + if (ret != 0) { + dprintk(1, "error interrupting video stream!\n"); + return ret; + } + } + + /* set au0828 interface0 to AS5 here again */ + ret = usb_set_interface(dev->usbdev, 0, 5); + if (ret < 0) { + printk(KERN_INFO "Au0828 can't set alt setting to 5!\n"); + return -EBUSY; + } + + au0828_analog_stream_enable(dev); + + return 0; +} + + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc); + if (qc->type) + return 0; + else + return -EINVAL; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + strlcpy(cap->driver, "au0828", sizeof(cap->driver)); + strlcpy(cap->card, dev->board.name, sizeof(cap->card)); + strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); + + cap->version = AU0828_VERSION_CODE; + + /*set the device capabilities */ + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(f->description, "Packed YUV2"); + + f->flags = 0; + f->pixelformat = V4L2_PIX_FMT_UYVY; + + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; + f->fmt.pix.bytesperline = dev->bytesperline; + f->fmt.pix.sizeimage = dev->frame_size; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */ + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + return au0828_set_format(dev, VIDIOC_TRY_FMT, f); +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + + if (videobuf_queue_is_busy(&fh->vb_vidq)) { + printk(KERN_INFO "%s queue busy\n", __func__); + rc = -EBUSY; + goto out; + } + + rc = au0828_set_format(dev, VIDIOC_S_FMT, f); +out: + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + /* FIXME: when we support something other than NTSC, we are going to + have to make the au0828 bridge adjust the size of its capture + buffer, which is currently hardcoded at 720x480 */ + + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm); + return 0; +} + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + unsigned int tmp; + + static const char *inames[] = { + [AU0828_VMUX_UNDEFINED] = "Undefined", + [AU0828_VMUX_COMPOSITE] = "Composite", + [AU0828_VMUX_SVIDEO] = "S-Video", + [AU0828_VMUX_CABLE] = "Cable TV", + [AU0828_VMUX_TELEVISION] = "Television", + [AU0828_VMUX_DVB] = "DVB", + [AU0828_VMUX_DEBUG] = "tv debug" + }; + + tmp = input->index; + + if (tmp >= AU0828_MAX_INPUT) + return -EINVAL; + if (AUVI_INPUT(tmp).type == 0) + return -EINVAL; + + input->index = tmp; + strcpy(input->name, inames[AUVI_INPUT(tmp).type]); + if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) || + (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE)) + input->type |= V4L2_INPUT_TYPE_TUNER; + else + input->type |= V4L2_INPUT_TYPE_CAMERA; + + input->std = dev->vdev->tvnorms; + + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + *i = dev->ctrl_input; + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int index) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + int i; + + dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__, + index); + if (index >= AU0828_MAX_INPUT) + return -EINVAL; + if (AUVI_INPUT(index).type == 0) + return -EINVAL; + dev->ctrl_input = index; + + switch (AUVI_INPUT(index).type) { + case AU0828_VMUX_SVIDEO: + dev->input_type = AU0828_VMUX_SVIDEO; + break; + case AU0828_VMUX_COMPOSITE: + dev->input_type = AU0828_VMUX_COMPOSITE; + break; + case AU0828_VMUX_TELEVISION: + dev->input_type = AU0828_VMUX_TELEVISION; + break; + default: + dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n", + AUVI_INPUT(index).type); + break; + } + + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, + AUVI_INPUT(index).vmux, 0, 0); + + for (i = 0; i < AU0828_MAX_INPUT; i++) { + int enable = 0; + if (AUVI_INPUT(i).audio_setup == NULL) + continue; + + if (i == index) + enable = 1; + else + enable = 0; + if (enable) { + (AUVI_INPUT(i).audio_setup)(dev, enable); + } else { + /* Make sure we leave it turned on if some + other input is routed to this callback */ + if ((AUVI_INPUT(i).audio_setup) != + ((AUVI_INPUT(index).audio_setup))) { + (AUVI_INPUT(i).audio_setup)(dev, enable); + } + } + } + + v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, + AUVI_INPUT(index).amux, 0, 0); + return 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + unsigned int index = a->index; + + if (a->index > 1) + return -EINVAL; + + index = dev->ctrl_ainput; + if (index == 0) + strcpy(a->name, "Television"); + else + strcpy(a->name, "Line in"); + + a->capability = V4L2_AUDCAP_STEREO; + a->index = index; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + if (a->index != dev->ctrl_ainput) + return -EINVAL; + return 0; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); + return 0; + +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl); + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + if (t->index != 0) + return -EINVAL; + + strcpy(t->name, "Auvitek tuner"); + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + if (t->index != 0) + return -EINVAL; + + t->type = V4L2_TUNER_ANALOG_TV; + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); + dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal, + t->afc); + return 0; + +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + freq->type = V4L2_TUNER_ANALOG_TV; + freq->frequency = dev->ctrl_freq; + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + if (freq->tuner != 0) + return -EINVAL; + if (freq->type != V4L2_TUNER_ANALOG_TV) + return -EINVAL; + + dev->ctrl_freq = freq->frequency; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq); + + au0828_analog_stream_reset(dev); + + return 0; +} + + +/* RAW VBI ioctls */ + +static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *format) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + format->fmt.vbi.samples_per_line = dev->vbi_width; + format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + format->fmt.vbi.offset = 0; + format->fmt.vbi.flags = 0; + format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; + + format->fmt.vbi.count[0] = dev->vbi_height; + format->fmt.vbi.count[1] = dev->vbi_height; + format->fmt.vbi.start[0] = 21; + format->fmt.vbi.start[1] = 284; + + return 0; +} + +static int vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + + if (v4l2_chip_match_host(&chip->match)) { + chip->ident = V4L2_IDENT_AU0828; + return 0; + } + + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip); + if (chip->ident == V4L2_IDENT_NONE) + return -EINVAL; + + return 0; +} + +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cc) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + cc->bounds.left = 0; + cc->bounds.top = 0; + cc->bounds.width = dev->width; + cc->bounds.height = dev->height; + + cc->defrect = cc->bounds; + + cc->pixelaspect.numerator = 54; + cc->pixelaspect.denominator = 59; + + return 0; +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + int rc = -EINVAL; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (unlikely(type != fh->type)) + return -EINVAL; + + dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n", + fh, type, fh->resources, dev->resources); + + if (unlikely(!res_get(fh, get_ressource(fh)))) + return -EBUSY; + + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + au0828_analog_stream_enable(dev); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); + } + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + rc = videobuf_streamon(&fh->vb_vidq); + dev->vid_timeout_running = 1; + mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); + } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + rc = videobuf_streamon(&fh->vb_vbiq); + dev->vbi_timeout_running = 1; + mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); + } + + return rc; +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + int rc; + int i; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) + return -EINVAL; + if (type != fh->type) + return -EINVAL; + + dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n", + fh, type, fh->resources, dev->resources); + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev->vid_timeout_running = 0; + del_timer_sync(&dev->vid_timeout); + + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); + rc = au0828_stream_interrupt(dev); + if (rc != 0) + return rc; + + for (i = 0; i < AU0828_MAX_INPUT; i++) { + if (AUVI_INPUT(i).audio_setup == NULL) + continue; + (AUVI_INPUT(i).audio_setup)(dev, 0); + } + + videobuf_streamoff(&fh->vb_vidq); + res_free(fh, AU0828_RESOURCE_VIDEO); + } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + dev->vbi_timeout_running = 0; + del_timer_sync(&dev->vbi_timeout); + + videobuf_streamoff(&fh->vb_vbiq); + res_free(fh, AU0828_RESOURCE_VBI); + } + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + switch (reg->match.type) { + case V4L2_CHIP_MATCH_I2C_DRIVER: + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); + return 0; + default: + return -EINVAL; + } +} + +static int vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + switch (reg->match.type) { + case V4L2_CHIP_MATCH_I2C_DRIVER: + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); + return 0; + default: + return -EINVAL; + } + return 0; +} +#endif + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + rc = videobuf_reqbufs(&fh->vb_vidq, rb); + else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + rc = videobuf_reqbufs(&fh->vb_vbiq, rb); + + return rc; +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + rc = videobuf_querybuf(&fh->vb_vidq, b); + else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + rc = videobuf_querybuf(&fh->vb_vbiq, b); + + return rc; +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + rc = videobuf_qbuf(&fh->vb_vidq, b); + else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + rc = videobuf_qbuf(&fh->vb_vbiq, b); + + return rc; +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + /* Workaround for a bug in the au0828 hardware design that sometimes + results in the colorspace being inverted */ + if (dev->greenscreen_detected == 1) { + dprintk(1, "Detected green frame. Resetting stream...\n"); + au0828_analog_stream_reset(dev); + dev->greenscreen_detected = 0; + } + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); + else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK); + + return rc; +} + +static struct v4l2_file_operations au0828_v4l_fops = { + .owner = THIS_MODULE, + .open = au0828_v4l2_open, + .release = au0828_v4l2_close, + .read = au0828_v4l2_read, + .poll = au0828_v4l2_poll, + .mmap = au0828_v4l2_mmap, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_cropcap = vidioc_cropcap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif + .vidioc_g_chip_ident = vidioc_g_chip_ident, +}; + +static const struct video_device au0828_video_template = { + .fops = &au0828_v4l_fops, + .release = video_device_release, + .ioctl_ops = &video_ioctl_ops, + .tvnorms = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, +}; + +/**************************************************************************/ + +int au0828_analog_register(struct au0828_dev *dev, + struct usb_interface *interface) +{ + int retval = -ENOMEM; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int i; + + dprintk(1, "au0828_analog_register called!\n"); + + /* set au0828 usb interface0 to as5 */ + retval = usb_set_interface(dev->usbdev, + interface->cur_altsetting->desc.bInterfaceNumber, 5); + if (retval != 0) { + printk(KERN_INFO "Failure setting usb interface0 to as5\n"); + return retval; + } + + /* Figure out which endpoint has the isoc interface */ + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + endpoint = &iface_desc->endpoint[i].desc; + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_ISOC)) { + + /* we find our isoc in endpoint */ + u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize); + dev->max_pkt_size = (tmp & 0x07ff) * + (((tmp & 0x1800) >> 11) + 1); + dev->isoc_in_endpointaddr = endpoint->bEndpointAddress; + } + } + if (!(dev->isoc_in_endpointaddr)) { + printk(KERN_INFO "Could not locate isoc endpoint\n"); + kfree(dev); + return -ENODEV; + } + + init_waitqueue_head(&dev->open); + spin_lock_init(&dev->slock); + mutex_init(&dev->lock); + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + INIT_LIST_HEAD(&dev->vbiq.active); + INIT_LIST_HEAD(&dev->vbiq.queued); + + dev->vid_timeout.function = au0828_vid_buffer_timeout; + dev->vid_timeout.data = (unsigned long) dev; + init_timer(&dev->vid_timeout); + + dev->vbi_timeout.function = au0828_vbi_buffer_timeout; + dev->vbi_timeout.data = (unsigned long) dev; + init_timer(&dev->vbi_timeout); + + dev->width = NTSC_STD_W; + dev->height = NTSC_STD_H; + dev->field_size = dev->width * dev->height; + dev->frame_size = dev->field_size << 1; + dev->bytesperline = dev->width << 1; + dev->ctrl_ainput = 0; + + /* allocate and fill v4l2 video struct */ + dev->vdev = video_device_alloc(); + if (NULL == dev->vdev) { + dprintk(1, "Can't allocate video_device.\n"); + return -ENOMEM; + } + + /* allocate the VBI struct */ + dev->vbi_dev = video_device_alloc(); + if (NULL == dev->vbi_dev) { + dprintk(1, "Can't allocate vbi_device.\n"); + kfree(dev->vdev); + return -ENOMEM; + } + + /* Fill the video capture device struct */ + *dev->vdev = au0828_video_template; + dev->vdev->parent = &dev->usbdev->dev; + strcpy(dev->vdev->name, "au0828a video"); + + /* Setup the VBI device */ + *dev->vbi_dev = au0828_video_template; + dev->vbi_dev->parent = &dev->usbdev->dev; + strcpy(dev->vbi_dev->name, "au0828a vbi"); + + /* Register the v4l2 device */ + video_set_drvdata(dev->vdev, dev); + retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1); + if (retval != 0) { + dprintk(1, "unable to register video device (error = %d).\n", + retval); + video_device_release(dev->vdev); + return -ENODEV; + } + + /* Register the vbi device */ + video_set_drvdata(dev->vbi_dev, dev); + retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1); + if (retval != 0) { + dprintk(1, "unable to register vbi device (error = %d).\n", + retval); + video_device_release(dev->vbi_dev); + video_device_release(dev->vdev); + return -ENODEV; + } + + dprintk(1, "%s completed!\n", __func__); + + return 0; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,16 @@ + +config VIDEO_AU0828 + tristate "Auvitek AU0828 support" + depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 + select I2C_ALGOBIT + select VIDEO_TVEEPROM + select VIDEOBUF_VMALLOC + select DVB_AU8522 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + ---help--- + This is a video4linux driver for Auvitek's USB device. + + To compile this driver as a module, choose M here: the + module will be called au0828 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/au0828/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,9 @@ +au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o + +obj-$(CONFIG_VIDEO_AU0828) += au0828.o + +EXTRA_CFLAGS += -Idrivers/media/common/tuners +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + +EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt819.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt819.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt819.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt819.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,528 @@ +/* + * bt819 - BT819A VideoStream Decoder (Rockwell Part) + * + * Copyright (C) 1999 Mike Bernson + * Copyright (C) 1998 Dave Perks + * + * Modifications for LML33/DC10plus unified driver + * Copyright (C) 2000 Serguei Miridonov + * + * Changes by Ronald Bultje + * - moved over to linux>=2.4.x i2c protocol (9/9/2002) + * + * This code was modify/ported from the saa7111 driver written + * by Dave Perks. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Brooktree-819 video decoder driver"); +MODULE_AUTHOR("Mike Bernson & Dave Perks"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + + +/* ----------------------------------------------------------------------- */ + +struct bt819 { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + unsigned char reg[32]; + + v4l2_std_id norm; + int ident; + int input; + int enable; +}; + +static inline struct bt819 *to_bt819(struct v4l2_subdev *sd) +{ + return container_of(sd, struct bt819, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct bt819, hdl)->sd; +} + +struct timing { + int hactive; + int hdelay; + int vactive; + int vdelay; + int hscale; + int vscale; +}; + +/* for values, see the bt819 datasheet */ +static struct timing timing_data[] = { + {864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000}, + {858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000}, +}; + +/* ----------------------------------------------------------------------- */ + +static inline int bt819_write(struct bt819 *decoder, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); + + decoder->reg[reg] = value; + return i2c_smbus_write_byte_data(client, reg, value); +} + +static inline int bt819_setbit(struct bt819 *decoder, u8 reg, u8 bit, u8 value) +{ + return bt819_write(decoder, reg, + (decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0)); +} + +static int bt819_write_block(struct bt819 *decoder, const u8 *data, unsigned int len) +{ + struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); + int ret = -1; + u8 reg; + + /* the bt819 has an autoincrement function, use it if + * the adapter understands raw I2C */ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /* do raw I2C, not smbus compatible */ + u8 block_data[32]; + int block_len; + + while (len >= 2) { + block_len = 0; + block_data[block_len++] = reg = data[0]; + do { + block_data[block_len++] = + decoder->reg[reg++] = data[1]; + len -= 2; + data += 2; + } while (len >= 2 && data[0] == reg && block_len < 32); + ret = i2c_master_send(client, block_data, block_len); + if (ret < 0) + break; + } + } else { + /* do some slow I2C emulation kind of thing */ + while (len >= 2) { + reg = *data++; + ret = bt819_write(decoder, reg, *data++); + if (ret < 0) + break; + len -= 2; + } + } + + return ret; +} + +static inline int bt819_read(struct bt819 *decoder, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd); + + return i2c_smbus_read_byte_data(client, reg); +} + +static int bt819_init(struct v4l2_subdev *sd) +{ + static unsigned char init[] = { + /*0x1f, 0x00,*/ /* Reset */ + 0x01, 0x59, /* 0x01 input format */ + 0x02, 0x00, /* 0x02 temporal decimation */ + 0x03, 0x12, /* 0x03 Cropping msb */ + 0x04, 0x16, /* 0x04 Vertical Delay, lsb */ + 0x05, 0xe0, /* 0x05 Vertical Active lsb */ + 0x06, 0x80, /* 0x06 Horizontal Delay lsb */ + 0x07, 0xd0, /* 0x07 Horizontal Active lsb */ + 0x08, 0x00, /* 0x08 Horizontal Scaling msb */ + 0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */ + 0x0a, 0x00, /* 0x0a Brightness control */ + 0x0b, 0x30, /* 0x0b Miscellaneous control */ + 0x0c, 0xd8, /* 0x0c Luma Gain lsb */ + 0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */ + 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */ + 0x0f, 0x00, /* 0x0f Hue control */ + 0x12, 0x04, /* 0x12 Output Format */ + 0x13, 0x20, /* 0x13 Vertial Scaling msb 0x00 + chroma comb OFF, line drop scaling, interlace scaling + BUG? Why does turning the chroma comb on fuck up color? + Bug in the bt819 stepping on my board? + */ + 0x14, 0x00, /* 0x14 Vertial Scaling lsb */ + 0x16, 0x07, /* 0x16 Video Timing Polarity + ACTIVE=active low + FIELD: high=odd, + vreset=active high, + hreset=active high */ + 0x18, 0x68, /* 0x18 AGC Delay */ + 0x19, 0x5d, /* 0x19 Burst Gate Delay */ + 0x1a, 0x80, /* 0x1a ADC Interface */ + }; + + struct bt819 *decoder = to_bt819(sd); + struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0]; + + init[0x03 * 2 - 1] = + (((timing->vdelay >> 8) & 0x03) << 6) | + (((timing->vactive >> 8) & 0x03) << 4) | + (((timing->hdelay >> 8) & 0x03) << 2) | + ((timing->hactive >> 8) & 0x03); + init[0x04 * 2 - 1] = timing->vdelay & 0xff; + init[0x05 * 2 - 1] = timing->vactive & 0xff; + init[0x06 * 2 - 1] = timing->hdelay & 0xff; + init[0x07 * 2 - 1] = timing->hactive & 0xff; + init[0x08 * 2 - 1] = timing->hscale >> 8; + init[0x09 * 2 - 1] = timing->hscale & 0xff; + /* 0x15 in array is address 0x19 */ + init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93; /* Chroma burst delay */ + /* reset */ + bt819_write(decoder, 0x1f, 0x00); + mdelay(1); + + /* init */ + return bt819_write_block(decoder, init, sizeof(init)); +} + +/* ----------------------------------------------------------------------- */ + +static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) +{ + struct bt819 *decoder = to_bt819(sd); + int status = bt819_read(decoder, 0x00); + int res = V4L2_IN_ST_NO_SIGNAL; + v4l2_std_id std; + + if ((status & 0x80)) + res = 0; + + if ((status & 0x10)) + std = V4L2_STD_PAL; + else + std = V4L2_STD_NTSC; + if (pstd) + *pstd = std; + if (pstatus) + *pstatus = status; + + v4l2_dbg(1, debug, sd, "get status %x\n", status); + return 0; +} + +static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + return bt819_status(sd, NULL, std); +} + +static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + return bt819_status(sd, status, NULL); +} + +static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct bt819 *decoder = to_bt819(sd); + struct timing *timing = NULL; + + v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); + + if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL) + v4l2_err(sd, "no notify found!\n"); + + if (std & V4L2_STD_NTSC) { + v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL); + bt819_setbit(decoder, 0x01, 0, 1); + bt819_setbit(decoder, 0x01, 1, 0); + bt819_setbit(decoder, 0x01, 5, 0); + bt819_write(decoder, 0x18, 0x68); + bt819_write(decoder, 0x19, 0x5d); + /* bt819_setbit(decoder, 0x1a, 5, 1); */ + timing = &timing_data[1]; + } else if (std & V4L2_STD_PAL) { + v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL); + bt819_setbit(decoder, 0x01, 0, 1); + bt819_setbit(decoder, 0x01, 1, 1); + bt819_setbit(decoder, 0x01, 5, 1); + bt819_write(decoder, 0x18, 0x7f); + bt819_write(decoder, 0x19, 0x72); + /* bt819_setbit(decoder, 0x1a, 5, 0); */ + timing = &timing_data[0]; + } else { + v4l2_dbg(1, debug, sd, "unsupported norm %llx\n", + (unsigned long long)std); + return -EINVAL; + } + bt819_write(decoder, 0x03, + (((timing->vdelay >> 8) & 0x03) << 6) | + (((timing->vactive >> 8) & 0x03) << 4) | + (((timing->hdelay >> 8) & 0x03) << 2) | + ((timing->hactive >> 8) & 0x03)); + bt819_write(decoder, 0x04, timing->vdelay & 0xff); + bt819_write(decoder, 0x05, timing->vactive & 0xff); + bt819_write(decoder, 0x06, timing->hdelay & 0xff); + bt819_write(decoder, 0x07, timing->hactive & 0xff); + bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff); + bt819_write(decoder, 0x09, timing->hscale & 0xff); + decoder->norm = std; + v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL); + return 0; +} + +static int bt819_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct bt819 *decoder = to_bt819(sd); + + v4l2_dbg(1, debug, sd, "set input %x\n", input); + + if (input > 7) + return -EINVAL; + + if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL) + v4l2_err(sd, "no notify found!\n"); + + if (decoder->input != input) { + v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL); + decoder->input = input; + /* select mode */ + if (decoder->input == 0) { + bt819_setbit(decoder, 0x0b, 6, 0); + bt819_setbit(decoder, 0x1a, 1, 1); + } else { + bt819_setbit(decoder, 0x0b, 6, 1); + bt819_setbit(decoder, 0x1a, 1, 0); + } + v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL); + } + return 0; +} + +static int bt819_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct bt819 *decoder = to_bt819(sd); + + v4l2_dbg(1, debug, sd, "enable output %x\n", enable); + + if (decoder->enable != enable) { + decoder->enable = enable; + bt819_setbit(decoder, 0x16, 7, !enable); + } + return 0; +} + +static int bt819_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct bt819 *decoder = to_bt819(sd); + int temp; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + bt819_write(decoder, 0x0a, ctrl->val); + break; + + case V4L2_CID_CONTRAST: + bt819_write(decoder, 0x0c, ctrl->val & 0xff); + bt819_setbit(decoder, 0x0b, 2, ((ctrl->val >> 8) & 0x01)); + break; + + case V4L2_CID_SATURATION: + bt819_write(decoder, 0x0d, (ctrl->val >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 1, ((ctrl->val >> 15) & 0x01)); + + /* Ratio between U gain and V gain must stay the same as + the ratio between the default U and V gain values. */ + temp = (ctrl->val * 180) / 254; + bt819_write(decoder, 0x0e, (temp >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01); + break; + + case V4L2_CID_HUE: + bt819_write(decoder, 0x0f, ctrl->val); + break; + + default: + return -EINVAL; + } + return 0; +} + +static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct bt819 *decoder = to_bt819(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0); +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_ctrl_ops bt819_ctrl_ops = { + .s_ctrl = bt819_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops bt819_core_ops = { + .g_chip_ident = bt819_g_chip_ident, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, + .s_std = bt819_s_std, +}; + +static const struct v4l2_subdev_video_ops bt819_video_ops = { + .s_routing = bt819_s_routing, + .s_stream = bt819_s_stream, + .querystd = bt819_querystd, + .g_input_status = bt819_g_input_status, +}; + +static const struct v4l2_subdev_ops bt819_ops = { + .core = &bt819_core_ops, + .video = &bt819_video_ops, +}; + +/* ----------------------------------------------------------------------- */ + +static int bt819_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int i, ver; + struct bt819 *decoder; + struct v4l2_subdev *sd; + const char *name; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL); + if (decoder == NULL) + return -ENOMEM; + sd = &decoder->sd; + v4l2_i2c_subdev_init(sd, client, &bt819_ops); + + ver = bt819_read(decoder, 0x17); + switch (ver & 0xf0) { + case 0x70: + name = "bt819a"; + decoder->ident = V4L2_IDENT_BT819A; + break; + case 0x60: + name = "bt817a"; + decoder->ident = V4L2_IDENT_BT817A; + break; + case 0x20: + name = "bt815a"; + decoder->ident = V4L2_IDENT_BT815A; + break; + default: + v4l2_dbg(1, debug, sd, + "unknown chip version 0x%02x\n", ver); + return -ENODEV; + } + + v4l_info(client, "%s found @ 0x%x (%s)\n", name, + client->addr << 1, client->adapter->name); + + decoder->norm = V4L2_STD_NTSC; + decoder->input = 0; + decoder->enable = 1; + + i = bt819_init(sd); + if (i < 0) + v4l2_dbg(1, debug, sd, "init status %d\n", i); + + v4l2_ctrl_handler_init(&decoder->hdl, 4); + v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); + v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, + V4L2_CID_CONTRAST, 0, 511, 1, 0xd8); + v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, + V4L2_CID_SATURATION, 0, 511, 1, 0xfe); + v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + sd->ctrl_handler = &decoder->hdl; + if (decoder->hdl.error) { + int err = decoder->hdl.error; + + v4l2_ctrl_handler_free(&decoder->hdl); + kfree(decoder); + return err; + } + v4l2_ctrl_handler_setup(&decoder->hdl); + return 0; +} + +static int bt819_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct bt819 *decoder = to_bt819(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&decoder->hdl); + kfree(decoder); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id bt819_id[] = { + { "bt819a", 0 }, + { "bt817a", 0 }, + { "bt815a", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bt819_id); + +static struct i2c_driver bt819_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "bt819", + }, + .probe = bt819_probe, + .remove = bt819_remove, + .id_table = bt819_id, +}; + +static __init int init_bt819(void) +{ + return i2c_add_driver(&bt819_driver); +} + +static __exit void exit_bt819(void) +{ + i2c_del_driver(&bt819_driver); +} + +module_init(init_bt819); +module_exit(exit_bt819); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt856.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt856.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt856.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt856.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,284 @@ +/* + * bt856 - BT856A Digital Video Encoder (Rockwell Part) + * + * Copyright (C) 1999 Mike Bernson + * Copyright (C) 1998 Dave Perks + * + * Modifications for LML33/DC10plus unified driver + * Copyright (C) 2000 Serguei Miridonov + * + * This code was modify/ported from the saa7111 driver written + * by Dave Perks. + * + * Changes by Ronald Bultje + * - moved over to linux>=2.4.x i2c protocol (9/9/2002) + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Brooktree-856A video encoder driver"); +MODULE_AUTHOR("Mike Bernson & Dave Perks"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + + +/* ----------------------------------------------------------------------- */ + +#define BT856_REG_OFFSET 0xDA +#define BT856_NR_REG 6 + +struct bt856 { + struct v4l2_subdev sd; + unsigned char reg[BT856_NR_REG]; + + v4l2_std_id norm; +}; + +static inline struct bt856 *to_bt856(struct v4l2_subdev *sd) +{ + return container_of(sd, struct bt856, sd); +} + +/* ----------------------------------------------------------------------- */ + +static inline int bt856_write(struct bt856 *encoder, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd); + + encoder->reg[reg - BT856_REG_OFFSET] = value; + return i2c_smbus_write_byte_data(client, reg, value); +} + +static inline int bt856_setbit(struct bt856 *encoder, u8 reg, u8 bit, u8 value) +{ + return bt856_write(encoder, reg, + (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) | + (value ? (1 << bit) : 0)); +} + +static void bt856_dump(struct bt856 *encoder) +{ + int i; + + v4l2_info(&encoder->sd, "register dump:\n"); + for (i = 0; i < BT856_NR_REG; i += 2) + printk(KERN_CONT " %02x", encoder->reg[i]); + printk(KERN_CONT "\n"); +} + +/* ----------------------------------------------------------------------- */ + +static int bt856_init(struct v4l2_subdev *sd, u32 arg) +{ + struct bt856 *encoder = to_bt856(sd); + + /* This is just for testing!!! */ + v4l2_dbg(1, debug, sd, "init\n"); + bt856_write(encoder, 0xdc, 0x18); + bt856_write(encoder, 0xda, 0); + bt856_write(encoder, 0xde, 0); + + bt856_setbit(encoder, 0xdc, 3, 1); + /*bt856_setbit(encoder, 0xdc, 6, 0);*/ + bt856_setbit(encoder, 0xdc, 4, 1); + + if (encoder->norm & V4L2_STD_NTSC) + bt856_setbit(encoder, 0xdc, 2, 0); + else + bt856_setbit(encoder, 0xdc, 2, 1); + + bt856_setbit(encoder, 0xdc, 1, 1); + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + if (debug != 0) + bt856_dump(encoder); + return 0; +} + +static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct bt856 *encoder = to_bt856(sd); + + v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); + + if (std & V4L2_STD_NTSC) { + bt856_setbit(encoder, 0xdc, 2, 0); + } else if (std & V4L2_STD_PAL) { + bt856_setbit(encoder, 0xdc, 2, 1); + bt856_setbit(encoder, 0xda, 0, 0); + /*bt856_setbit(encoder, 0xda, 0, 1);*/ + } else { + return -EINVAL; + } + encoder->norm = std; + if (debug != 0) + bt856_dump(encoder); + return 0; +} + +static int bt856_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct bt856 *encoder = to_bt856(sd); + + v4l2_dbg(1, debug, sd, "set input %d\n", input); + + /* We only have video bus. + * input= 0: input is from bt819 + * input= 1: input is from ZR36060 */ + switch (input) { + case 0: + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + bt856_setbit(encoder, 0xdc, 3, 1); + bt856_setbit(encoder, 0xdc, 6, 0); + break; + case 1: + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + bt856_setbit(encoder, 0xdc, 3, 1); + bt856_setbit(encoder, 0xdc, 6, 1); + break; + case 2: /* Color bar */ + bt856_setbit(encoder, 0xdc, 3, 0); + bt856_setbit(encoder, 0xde, 4, 1); + break; + default: + return -EINVAL; + } + + if (debug != 0) + bt856_dump(encoder); + return 0; +} + +static int bt856_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT856, 0); +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops bt856_core_ops = { + .g_chip_ident = bt856_g_chip_ident, + .init = bt856_init, +}; + +static const struct v4l2_subdev_video_ops bt856_video_ops = { + .s_std_output = bt856_s_std_output, + .s_routing = bt856_s_routing, +}; + +static const struct v4l2_subdev_ops bt856_ops = { + .core = &bt856_core_ops, + .video = &bt856_video_ops, +}; + +/* ----------------------------------------------------------------------- */ + +static int bt856_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct bt856 *encoder; + struct v4l2_subdev *sd; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL); + if (encoder == NULL) + return -ENOMEM; + sd = &encoder->sd; + v4l2_i2c_subdev_init(sd, client, &bt856_ops); + encoder->norm = V4L2_STD_NTSC; + + bt856_write(encoder, 0xdc, 0x18); + bt856_write(encoder, 0xda, 0); + bt856_write(encoder, 0xde, 0); + + bt856_setbit(encoder, 0xdc, 3, 1); + /*bt856_setbit(encoder, 0xdc, 6, 0);*/ + bt856_setbit(encoder, 0xdc, 4, 1); + + if (encoder->norm & V4L2_STD_NTSC) + bt856_setbit(encoder, 0xdc, 2, 0); + else + bt856_setbit(encoder, 0xdc, 2, 1); + + bt856_setbit(encoder, 0xdc, 1, 1); + bt856_setbit(encoder, 0xde, 4, 0); + bt856_setbit(encoder, 0xde, 3, 1); + + if (debug != 0) + bt856_dump(encoder); + return 0; +} + +static int bt856_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_bt856(sd)); + return 0; +} + +static const struct i2c_device_id bt856_id[] = { + { "bt856", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bt856_id); + +static struct i2c_driver bt856_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "bt856", + }, + .probe = bt856_probe, + .remove = bt856_remove, + .id_table = bt856_id, +}; + +static __init int init_bt856(void) +{ + return i2c_add_driver(&bt856_driver); +} + +static __exit void exit_bt856(void) +{ + i2c_del_driver(&bt856_driver); +} + +module_init(init_bt856); +module_exit(exit_bt856); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt866.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt866.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt866.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt866.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,254 @@ +/* + bt866 - BT866 Digital Video Encoder (Rockwell Part) + + Copyright (C) 1999 Mike Bernson + Copyright (C) 1998 Dave Perks + + Modifications for LML33/DC10plus unified driver + Copyright (C) 2000 Serguei Miridonov + + This code was modify/ported from the saa7111 driver written + by Dave Perks. + + This code was adapted for the bt866 by Christer Weinigel and ported + to 2.6 by Martin Samuelsson. + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Brooktree-866 video encoder driver"); +MODULE_AUTHOR("Mike Bernson & Dave Perks"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + + +/* ----------------------------------------------------------------------- */ + +struct bt866 { + struct v4l2_subdev sd; + u8 reg[256]; +}; + +static inline struct bt866 *to_bt866(struct v4l2_subdev *sd) +{ + return container_of(sd, struct bt866, sd); +} + +static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data) +{ + struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd); + u8 buffer[2]; + int err; + + buffer[0] = subaddr; + buffer[1] = data; + + encoder->reg[subaddr] = data; + + v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data); + + for (err = 0; err < 3;) { + if (i2c_master_send(client, buffer, 2) == 2) + break; + err++; + v4l_warn(client, "error #%d writing to 0x%02x\n", + err, subaddr); + schedule_timeout_interruptible(msecs_to_jiffies(100)); + } + if (err == 3) { + v4l_warn(client, "giving up\n"); + return -1; + } + + return 0; +} + +static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) +{ + v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std); + + /* Only PAL supported by this driver at the moment! */ + if (!(std & V4L2_STD_NTSC)) + return -EINVAL; + return 0; +} + +static int bt866_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + static const __u8 init[] = { + 0xc8, 0xcc, /* CRSCALE */ + 0xca, 0x91, /* CBSCALE */ + 0xcc, 0x24, /* YC16 | OSDNUM */ + 0xda, 0x00, /* */ + 0xdc, 0x24, /* SETMODE | PAL */ + 0xde, 0x02, /* EACTIVE */ + + /* overlay colors */ + 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */ + 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */ + 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */ + 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */ + 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */ + 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */ + 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */ + 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */ + + 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */ + 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */ + 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */ + 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */ + 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */ + 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */ + 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */ + 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */ + }; + struct bt866 *encoder = to_bt866(sd); + u8 val; + int i; + + for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2) + bt866_write(encoder, init[i], init[i+1]); + + val = encoder->reg[0xdc]; + + if (input == 0) + val |= 0x40; /* CBSWAP */ + else + val &= ~0x40; /* !CBSWAP */ + + bt866_write(encoder, 0xdc, val); + + val = encoder->reg[0xcc]; + if (input == 2) + val |= 0x01; /* OSDBAR */ + else + val &= ~0x01; /* !OSDBAR */ + bt866_write(encoder, 0xcc, val); + + v4l2_dbg(1, debug, sd, "set input %d\n", input); + + switch (input) { + case 0: + case 1: + case 2: + break; + default: + return -EINVAL; + } + return 0; +} + +#if 0 +/* Code to setup square pixels, might be of some use in the future, + but is currently unused. */ + val = encoder->reg[0xdc]; + if (*iarg) + val |= 1; /* SQUARE */ + else + val &= ~1; /* !SQUARE */ + bt866_write(client, 0xdc, val); +#endif + +static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0); +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops bt866_core_ops = { + .g_chip_ident = bt866_g_chip_ident, +}; + +static const struct v4l2_subdev_video_ops bt866_video_ops = { + .s_std_output = bt866_s_std_output, + .s_routing = bt866_s_routing, +}; + +static const struct v4l2_subdev_ops bt866_ops = { + .core = &bt866_core_ops, + .video = &bt866_video_ops, +}; + +static int bt866_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct bt866 *encoder; + struct v4l2_subdev *sd; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + encoder = kzalloc(sizeof(*encoder), GFP_KERNEL); + if (encoder == NULL) + return -ENOMEM; + sd = &encoder->sd; + v4l2_i2c_subdev_init(sd, client, &bt866_ops); + return 0; +} + +static int bt866_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_bt866(sd)); + return 0; +} + +static const struct i2c_device_id bt866_id[] = { + { "bt866", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bt866_id); + +static struct i2c_driver bt866_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "bt866", + }, + .probe = bt866_probe, + .remove = bt866_remove, + .id_table = bt866_id, +}; + +static __init int init_bt866(void) +{ + return i2c_add_driver(&bt866_driver); +} + +static __exit void exit_bt866(void) +{ + i2c_del_driver(&bt866_driver); +} + +module_init(init_bt866); +module_exit(exit_bt866); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bt848.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bt848.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bt848.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bt848.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,366 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BT848_H_ +#define _BT848_H_ + +#ifndef PCI_VENDOR_ID_BROOKTREE +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#endif +#ifndef PCI_DEVICE_ID_BT848 +#define PCI_DEVICE_ID_BT848 0x350 +#endif +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 +#endif +#ifndef PCI_DEVICE_ID_BT878 +#define PCI_DEVICE_ID_BT878 0x36e +#endif +#ifndef PCI_DEVICE_ID_BT879 +#define PCI_DEVICE_ID_BT879 0x36f +#endif + + +/* Brooktree 848 registers */ + +#define BT848_DSTATUS 0x000 +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_PLOCK (1<<2) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + +#define BT848_IFORM 0x004 +#define BT848_IFORM_HACTIVE (1<<7) +#define BT848_IFORM_MUXSEL (3<<5) +#define BT848_IFORM_MUX0 (2<<5) +#define BT848_IFORM_MUX1 (3<<5) +#define BT848_IFORM_MUX2 (1<<5) +#define BT848_IFORM_XTSEL (3<<3) +#define BT848_IFORM_XT0 (1<<3) +#define BT848_IFORM_XT1 (2<<3) +#define BT848_IFORM_XTAUTO (3<<3) +#define BT848_IFORM_XTBOTH (3<<3) +#define BT848_IFORM_NTSC 1 +#define BT848_IFORM_NTSC_J 2 +#define BT848_IFORM_PAL_BDGHI 3 +#define BT848_IFORM_PAL_M 4 +#define BT848_IFORM_PAL_N 5 +#define BT848_IFORM_SECAM 6 +#define BT848_IFORM_PAL_NC 7 +#define BT848_IFORM_AUTO 0 +#define BT848_IFORM_NORM 7 + +#define BT848_TDEC 0x008 +#define BT848_TDEC_DEC_FIELD (1<<7) +#define BT848_TDEC_FLDALIGN (1<<6) +#define BT848_TDEC_DEC_RAT (0x1f) + +#define BT848_E_CROP 0x00C +#define BT848_O_CROP 0x08C + +#define BT848_E_VDELAY_LO 0x010 +#define BT848_O_VDELAY_LO 0x090 + +#define BT848_E_VACTIVE_LO 0x014 +#define BT848_O_VACTIVE_LO 0x094 + +#define BT848_E_HDELAY_LO 0x018 +#define BT848_O_HDELAY_LO 0x098 + +#define BT848_E_HACTIVE_LO 0x01C +#define BT848_O_HACTIVE_LO 0x09C + +#define BT848_E_HSCALE_HI 0x020 +#define BT848_O_HSCALE_HI 0x0A0 + +#define BT848_E_HSCALE_LO 0x024 +#define BT848_O_HSCALE_LO 0x0A4 + +#define BT848_BRIGHT 0x028 + +#define BT848_E_CONTROL 0x02C +#define BT848_O_CONTROL 0x0AC +#define BT848_CONTROL_LNOTCH (1<<7) +#define BT848_CONTROL_COMP (1<<6) +#define BT848_CONTROL_LDEC (1<<5) +#define BT848_CONTROL_CBSENSE (1<<4) +#define BT848_CONTROL_CON_MSB (1<<2) +#define BT848_CONTROL_SAT_U_MSB (1<<1) +#define BT848_CONTROL_SAT_V_MSB (1<<0) + +#define BT848_CONTRAST_LO 0x030 +#define BT848_SAT_U_LO 0x034 +#define BT848_SAT_V_LO 0x038 +#define BT848_HUE 0x03C + +#define BT848_E_SCLOOP 0x040 +#define BT848_O_SCLOOP 0x0C0 +#define BT848_SCLOOP_CAGC (1<<6) +#define BT848_SCLOOP_CKILL (1<<5) +#define BT848_SCLOOP_HFILT_AUTO (0<<3) +#define BT848_SCLOOP_HFILT_CIF (1<<3) +#define BT848_SCLOOP_HFILT_QCIF (2<<3) +#define BT848_SCLOOP_HFILT_ICON (3<<3) + +#define BT848_SCLOOP_PEAK (1<<7) +#define BT848_SCLOOP_HFILT_MINP (1<<3) +#define BT848_SCLOOP_HFILT_MEDP (2<<3) +#define BT848_SCLOOP_HFILT_MAXP (3<<3) + + +#define BT848_OFORM 0x048 +#define BT848_OFORM_RANGE (1<<7) +#define BT848_OFORM_CORE0 (0<<5) +#define BT848_OFORM_CORE8 (1<<5) +#define BT848_OFORM_CORE16 (2<<5) +#define BT848_OFORM_CORE32 (3<<5) + +#define BT848_E_VSCALE_HI 0x04C +#define BT848_O_VSCALE_HI 0x0CC +#define BT848_VSCALE_YCOMB (1<<7) +#define BT848_VSCALE_COMB (1<<6) +#define BT848_VSCALE_INT (1<<5) +#define BT848_VSCALE_HI 15 + +#define BT848_E_VSCALE_LO 0x050 +#define BT848_O_VSCALE_LO 0x0D0 +#define BT848_TEST 0x054 +#define BT848_ADELAY 0x060 +#define BT848_BDELAY 0x064 + +#define BT848_ADC 0x068 +#define BT848_ADC_RESERVED (2<<6) +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + +#define BT848_WC_UP 0x044 +#define BT848_WC_DOWN 0x078 + +#define BT848_E_VTC 0x06C +#define BT848_O_VTC 0x0EC +#define BT848_VTC_HSFMT (1<<7) +#define BT848_VTC_VFILT_2TAP 0 +#define BT848_VTC_VFILT_3TAP 1 +#define BT848_VTC_VFILT_4TAP 2 +#define BT848_VTC_VFILT_5TAP 3 + +#define BT848_SRESET 0x07C + +#define BT848_COLOR_FMT 0x0D4 +#define BT848_COLOR_FMT_O_RGB32 (0<<4) +#define BT848_COLOR_FMT_O_RGB24 (1<<4) +#define BT848_COLOR_FMT_O_RGB16 (2<<4) +#define BT848_COLOR_FMT_O_RGB15 (3<<4) +#define BT848_COLOR_FMT_O_YUY2 (4<<4) +#define BT848_COLOR_FMT_O_BtYUV (5<<4) +#define BT848_COLOR_FMT_O_Y8 (6<<4) +#define BT848_COLOR_FMT_O_RGB8 (7<<4) +#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) +#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) +#define BT848_COLOR_FMT_O_RAW (14<<4) +#define BT848_COLOR_FMT_E_RGB32 0 +#define BT848_COLOR_FMT_E_RGB24 1 +#define BT848_COLOR_FMT_E_RGB16 2 +#define BT848_COLOR_FMT_E_RGB15 3 +#define BT848_COLOR_FMT_E_YUY2 4 +#define BT848_COLOR_FMT_E_BtYUV 5 +#define BT848_COLOR_FMT_E_Y8 6 +#define BT848_COLOR_FMT_E_RGB8 7 +#define BT848_COLOR_FMT_E_YCrCb422 8 +#define BT848_COLOR_FMT_E_YCrCb411 9 +#define BT848_COLOR_FMT_E_RAW 14 + +#define BT848_COLOR_FMT_RGB32 0x00 +#define BT848_COLOR_FMT_RGB24 0x11 +#define BT848_COLOR_FMT_RGB16 0x22 +#define BT848_COLOR_FMT_RGB15 0x33 +#define BT848_COLOR_FMT_YUY2 0x44 +#define BT848_COLOR_FMT_BtYUV 0x55 +#define BT848_COLOR_FMT_Y8 0x66 +#define BT848_COLOR_FMT_RGB8 0x77 +#define BT848_COLOR_FMT_YCrCb422 0x88 +#define BT848_COLOR_FMT_YCrCb411 0x99 +#define BT848_COLOR_FMT_RAW 0xee + +#define BT848_VTOTAL_LO 0xB0 +#define BT848_VTOTAL_HI 0xB4 + +#define BT848_COLOR_CTL 0x0D8 +#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) +#define BT848_COLOR_CTL_COLOR_BARS (1<<6) +#define BT848_COLOR_CTL_RGB_DED (1<<5) +#define BT848_COLOR_CTL_GAMMA (1<<4) +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + +#define BT848_CAP_CTL 0x0DC +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) +#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define BT848_VBI_PACK_SIZE 0x0E0 + +#define BT848_VBI_PACK_DEL 0x0E4 +#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc +#define BT848_VBI_PACK_DEL_EXT_FRAME 2 +#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 + + +#define BT848_INT_STAT 0x100 +#define BT848_INT_MASK 0x104 + +#define BT848_INT_ETBF (1<<23) + +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + + +#define BT848_GPIO_DMA_CTL 0x10C +#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) +#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) +#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) +#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) +#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) +#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) +#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) +#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) +#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) +#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) +#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) +#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) +#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) + +#define BT848_I2C 0x110 +#define BT878_I2C_MODE (1<<7) +#define BT878_I2C_RATE (1<<6) +#define BT878_I2C_NOSTOP (1<<5) +#define BT878_I2C_NOSTART (1<<4) +#define BT848_I2C_DIV (0xf<<4) +#define BT848_I2C_SYNC (1<<3) +#define BT848_I2C_W3B (1<<2) +#define BT848_I2C_SCL (1<<1) +#define BT848_I2C_SDA (1<<0) + +#define BT848_RISC_STRT_ADD 0x114 +#define BT848_GPIO_OUT_EN 0x118 +#define BT848_GPIO_REG_INP 0x11C +#define BT848_RISC_COUNT 0x120 +#define BT848_GPIO_DATA 0x200 + + +/* Bt848 RISC commands */ + +/* only for the SYNC RISC command */ +#define BT848_FIFO_STATUS_FM1 0x06 +#define BT848_FIFO_STATUS_FM3 0x0e +#define BT848_FIFO_STATUS_SOL 0x02 +#define BT848_FIFO_STATUS_EOL4 0x01 +#define BT848_FIFO_STATUS_EOL3 0x0d +#define BT848_FIFO_STATUS_EOL2 0x09 +#define BT848_FIFO_STATUS_EOL1 0x05 +#define BT848_FIFO_STATUS_VRE 0x04 +#define BT848_FIFO_STATUS_VRO 0x0c +#define BT848_FIFO_STATUS_PXV 0x00 + +#define BT848_RISC_RESYNC (1<<15) + +/* WRITE and SKIP */ +/* disable which bytes of each DWORD */ +#define BT848_RISC_BYTE0 (1U<<12) +#define BT848_RISC_BYTE1 (1U<<13) +#define BT848_RISC_BYTE2 (1U<<14) +#define BT848_RISC_BYTE3 (1U<<15) +#define BT848_RISC_BYTE_ALL (0x0fU<<12) +#define BT848_RISC_BYTE_NONE 0 +/* cause RISCI */ +#define BT848_RISC_IRQ (1U<<24) +/* RISC command is last one in this line */ +#define BT848_RISC_EOL (1U<<26) +/* RISC command is first one in this line */ +#define BT848_RISC_SOL (1U<<27) + +#define BT848_RISC_WRITE (0x01U<<28) +#define BT848_RISC_SKIP (0x02U<<28) +#define BT848_RISC_WRITEC (0x05U<<28) +#define BT848_RISC_JUMP (0x07U<<28) +#define BT848_RISC_SYNC (0x08U<<28) + +#define BT848_RISC_WRITE123 (0x09U<<28) +#define BT848_RISC_SKIP123 (0x0aU<<28) +#define BT848_RISC_WRITE1S23 (0x0bU<<28) + + +/* Bt848A and higher only !! */ +#define BT848_TGLB 0x080 +#define BT848_TGCTRL 0x084 +#define BT848_FCAP 0x0E8 +#define BT848_PLL_F_LO 0x0F0 +#define BT848_PLL_F_HI 0x0F4 + +#define BT848_PLL_XCI 0x0F8 +#define BT848_PLL_X (1<<7) +#define BT848_PLL_C (1<<6) + +#define BT848_DVSIF 0x0FC + +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_EN_TBFX 0x02 +#define BT878_EN_VSFX 0x04 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-audio-hook.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-audio-hook.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-audio-hook.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-audio-hook.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,382 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +#include "bttv-audio-hook.h" + +#include + +/* ----------------------------------------------------------------------- */ +/* winview */ + +void winview_volume(struct bttv *btv, __u16 volume) +{ + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + int bits_out, loops, vol, data; + + /* 32 levels logarithmic */ + vol = 32 - ((volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; + data = gpio_read(); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<audmode & V4L2_TUNER_MODE_LANG1) + con = 0x000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x300; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x200; +/* if (t->audmode & V4L2_TUNER_MODE_MONO) + * con = 0x100; */ + gpio_bits(0x300, con); + } else { + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val, con; + + if (btv->radio_user) + return; + + val = gpio_read(); + if (set) { + con = 0x000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) { + if (t->audmode & V4L2_TUNER_MODE_LANG1) { + /* LANG1 + LANG2 */ + con = 0x100; + } + else { + /* LANG2 */ + con = 0x300; + } + } + if (con != (val & 0x300)) { + gpio_bits(0x300, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"gvbctv5pci"); + } + } else { + switch (val & 0x70) { + case 0x10: + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + case 0x30: + t->rxsubchans = V4L2_TUNER_SUB_LANG2; + break; + case 0x50: + t->rxsubchans = V4L2_TUNER_SUB_LANG1; + break; + case 0x60: + t->rxsubchans = V4L2_TUNER_SUB_STEREO; + break; + case 0x70: + t->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + default: + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + } + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Mario Medina Nussbaum + * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, + * 0xdde enables mono and 0xccd enables sap + * + * Petr Vandrovec + * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select + * input/output sound connection, so both must be set for output mode. + * + * Looks like it's needed only for the "tvphone", the "tvphone 98" + * handles this with a tda9840 + * + */ + +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x02; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + val = 0x01; + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1; + return; + } +} + + +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x01; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ + val = 0x02; + btaor(val, ~0x03, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + return; + } +} + +/* Lifetec 9415 handling */ + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (gpio_read() & 0x4000) { + t->audmode = V4L2_TUNER_MODE_MONO; + return; + } + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ + val = 0x0080; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ + val = 0x0880; + if ((t->audmode & V4L2_TUNER_MODE_LANG1) || + (t->audmode & V4L2_TUNER_MODE_MONO)) + val = 0; + gpio_bits(0x0880, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"lt9415"); + } else { + /* autodetect doesn't work with this card :-( */ + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + return; + } +} + +/* TDA9821 on TerraTV+ Bt848, Bt878 */ +void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int con = 0; + + if (set) { + gpio_inout(0x180000,0x180000); + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x080000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x180000; + gpio_bits(0x180000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"terratv"); + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + + +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned long val = 0; + + if (set) { + /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ + if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ + val = 0x420000; + if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ + val = 0x420000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x410000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ + val = 0x020000; + if (val) { + gpio_bits(0x430000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"winfast2000"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM + * revision 9B has on-board TDA9874A sound decoder). + * + * Note: There are card variants without tda9874a. Forcing the "stereo sound route" + * will mute this cards. + */ +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val = 0; + + if (btv->radio_user) + return; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { + val = 0x01; + } + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { + val = 0x02; + } + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"pvbt878p9b"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for FlyVideo 2000S (with tda9874 decoder) + * based on pvbt878p9b_audio() - this is not tested, please fix!!! + */ +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val = 0xffff; + + if (btv->radio_user) + return; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { + val = 0x0000; + } + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ + } + if (val != 0xffff) { + gpio_bits(0x1800, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"fv2000s"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * sound control for Canopus WinDVR PCI + * Masaki Suzuki + */ +void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned long val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) + val = 0x040000; + if (t->audmode & V4L2_TUNER_MODE_LANG1) + val = 0; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + val = 0x100000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + val = 0; + if (val) { + gpio_bits(0x140000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"windvr"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * sound control for AD-TVK503 + * Hiroshi Takekawa + */ +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int con = 0xffffff; + + /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ + + if (set) { + /* btor(***, BT848_GPIO_OUT_EN); */ + if (t->audmode & V4L2_TUNER_MODE_LANG1) + con = 0x00000000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x00180000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x00000000; + if (t->audmode & V4L2_TUNER_MODE_MONO) + con = 0x00060000; + if (con != 0xffffff) { + gpio_bits(0x1e0000,con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "adtvk503"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-audio-hook.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-audio-hook.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-audio-hook.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-audio-hook.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +#include "bttvp.h" + +void winview_volume (struct bttv *btv, __u16 volume); + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void terratv_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-cards.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,4919 @@ +/* + + bttv-cards.c + + this file has configuration informations - card-specific stuff + like the big tvcards array for the most part + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2001 Gerd Knorr + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bttvp.h" +#include +#include +#include "bttv-audio-hook.h" + +/* fwd decl */ +static void boot_msp34xx(struct bttv *btv, int pin); +static void hauppauge_eeprom(struct bttv *btv); +static void avermedia_eeprom(struct bttv *btv); +static void osprey_eeprom(struct bttv *btv, const u8 ee[256]); +static void modtec_eeprom(struct bttv *btv); +static void init_PXC200(struct bttv *btv); +static void init_RTV24(struct bttv *btv); + +static void rv605_muxsel(struct bttv *btv, unsigned int input); +static void eagle_muxsel(struct bttv *btv, unsigned int input); +static void xguard_muxsel(struct bttv *btv, unsigned int input); +static void ivc120_muxsel(struct bttv *btv, unsigned int input); +static void gvc1100_muxsel(struct bttv *btv, unsigned int input); + +static void PXC200_muxsel(struct bttv *btv, unsigned int input); + +static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input); +static void picolo_tetra_init(struct bttv *btv); + +static void tibetCS16_muxsel(struct bttv *btv, unsigned int input); +static void tibetCS16_init(struct bttv *btv); + +static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input); +static void kodicom4400r_init(struct bttv *btv); + +static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input); +static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input); + +static void geovision_muxsel(struct bttv *btv, unsigned int input); + +static void phytec_muxsel(struct bttv *btv, unsigned int input); + +static void gv800s_muxsel(struct bttv *btv, unsigned int input); +static void gv800s_init(struct bttv *btv); + +static int terratec_active_radio_upgrade(struct bttv *btv); +static int tea5757_read(struct bttv *btv); +static int tea5757_write(struct bttv *btv, int value); +static void identify_by_eeprom(struct bttv *btv, + unsigned char eeprom_data[256]); +static int __devinit pvr_boot(struct bttv *btv); + +/* config variables */ +static unsigned int triton1; +static unsigned int vsfx; +static unsigned int latency = UNSET; +int no_overlay=-1; + +static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int audiodev[BTTV_MAX]; +static unsigned int saa6588[BTTV_MAX]; +static struct bttv *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL }; +static unsigned int autoload = UNSET; +static unsigned int gpiomask = UNSET; +static unsigned int audioall = UNSET; +static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET }; + +/* insmod options */ +module_param(triton1, int, 0444); +module_param(vsfx, int, 0444); +module_param(no_overlay, int, 0444); +module_param(latency, int, 0444); +module_param(gpiomask, int, 0444); +module_param(audioall, int, 0444); +module_param(autoload, int, 0444); + +module_param_array(card, int, NULL, 0444); +module_param_array(pll, int, NULL, 0444); +module_param_array(tuner, int, NULL, 0444); +module_param_array(svhs, int, NULL, 0444); +module_param_array(remote, int, NULL, 0444); +module_param_array(audiodev, int, NULL, 0444); +module_param_array(audiomux, int, NULL, 0444); + +MODULE_PARM_DESC(triton1,"set ETBF pci config bit " + "[enable bug compatibility for triton1 + others]"); +MODULE_PARM_DESC(vsfx,"set VSFX pci config bit " + "[yet another chipset flaw workaround]"); +MODULE_PARM_DESC(latency,"pci latency timer"); +MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list"); +MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)"); +MODULE_PARM_DESC(tuner,"specify installed tuner type"); +MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore"); +MODULE_PARM_DESC(audiodev, "specify audio device:\n" + "\t\t-1 = no audio\n" + "\t\t 0 = autodetect (default)\n" + "\t\t 1 = msp3400\n" + "\t\t 2 = tda7432\n" + "\t\t 3 = tvaudio"); +MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition."); +MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" + " [some VIA/SIS chipsets are known to have problem with overlay]"); + +/* ----------------------------------------------------------------------- */ +/* list of card IDs for bt878+ cards */ + +static struct CARD { + unsigned id; + int cardnr; + char *name; +} cards[] __devinitdata = { + { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV" }, + { 0x39000070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV-D" }, + { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" }, + { 0xff000070, BTTV_BOARD_OSPREY1x0, "Osprey-100" }, + { 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" }, + { 0xff020070, BTTV_BOARD_OSPREY500, "Osprey-500" }, + { 0xff030070, BTTV_BOARD_OSPREY2000, "Osprey-2000" }, + { 0xff040070, BTTV_BOARD_OSPREY540, "Osprey-540" }, + { 0xff070070, BTTV_BOARD_OSPREY440, "Osprey-440" }, + + { 0x00011002, BTTV_BOARD_ATI_TVWONDER, "ATI TV Wonder" }, + { 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" }, + + { 0x6606107d, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x6607107d, BTTV_BOARD_WINFASTVC100, "Leadtek WinFast VC 100" }, + { 0x6609107d, BTTV_BOARD_WINFAST2000, "Leadtek TV 2000 XP" }, + { 0x263610b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, + { 0x264510b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, + { 0x402010fc, BTTV_BOARD_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" }, + { 0x405010fc, BTTV_BOARD_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" }, + { 0x407010fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, + { 0xd01810fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, + + { 0x001211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" }, + /* some cards ship with byteswapped IDs ... */ + { 0x1200bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" }, + { 0xff00bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" }, + /* this seems to happen as well ... */ + { 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" }, + + { 0x3000121a, BTTV_BOARD_VOODOOTV_200, "3Dfx VoodooTV 200" }, + { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM" }, + { 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" }, + + { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" }, + { 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" }, + { 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" }, + { 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" }, + { 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" }, + { 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" }, + { 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" }, + + { 0x00011461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00021461, BTTV_BOARD_AVERMEDIA98, "AVermedia TVCapture 98" }, + { 0x00031461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00041461, BTTV_BOARD_AVERMEDIA98, "AVerMedia TVCapture 98" }, + { 0x03001461, BTTV_BOARD_AVERMEDIA98, "VDOMATE TV TUNER CARD" }, + + { 0x1117153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" }, + { 0x1118153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" }, + { 0x1119153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL I)" }, + { 0x111a153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL I)" }, + + { 0x1123153b, BTTV_BOARD_TERRATVRADIO, "Terratec TV Radio+" }, + { 0x1127153b, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.05)" }, + /* clashes with FlyVideo + *{ 0x18521852, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.10)" }, */ + { 0x1134153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (LR102)" }, + { 0x1135153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */ + { 0x5018153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue" }, /* ?? */ + { 0xff3b153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */ + + { 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, + { 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, + { 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, + { 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, + { 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, + + { 0x1430aa00, BTTV_BOARD_PV143, "Provideo PV143A" }, + { 0x1431aa00, BTTV_BOARD_PV143, "Provideo PV143B" }, + { 0x1432aa00, BTTV_BOARD_PV143, "Provideo PV143C" }, + { 0x1433aa00, BTTV_BOARD_PV143, "Provideo PV143D" }, + { 0x1433aa03, BTTV_BOARD_PV143, "Security Eyes" }, + + { 0x1460aa00, BTTV_BOARD_PV150, "Provideo PV150A-1" }, + { 0x1461aa01, BTTV_BOARD_PV150, "Provideo PV150A-2" }, + { 0x1462aa02, BTTV_BOARD_PV150, "Provideo PV150A-3" }, + { 0x1463aa03, BTTV_BOARD_PV150, "Provideo PV150A-4" }, + + { 0x1464aa04, BTTV_BOARD_PV150, "Provideo PV150B-1" }, + { 0x1465aa05, BTTV_BOARD_PV150, "Provideo PV150B-2" }, + { 0x1466aa06, BTTV_BOARD_PV150, "Provideo PV150B-3" }, + { 0x1467aa07, BTTV_BOARD_PV150, "Provideo PV150B-4" }, + + { 0xa132ff00, BTTV_BOARD_IVC100, "IVC-100" }, + { 0xa1550000, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550001, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550002, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550003, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550100, BTTV_BOARD_IVC200, "IVC-200G" }, + { 0xa1550101, BTTV_BOARD_IVC200, "IVC-200G" }, + { 0xa1550102, BTTV_BOARD_IVC200, "IVC-200G" }, + { 0xa1550103, BTTV_BOARD_IVC200, "IVC-200G" }, + { 0xa1550800, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550801, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550802, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550803, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa182ff00, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff01, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff02, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff03, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff04, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff05, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff06, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff07, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff08, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff09, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0a, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0b, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0c, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0d, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0e, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0f, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xf0500000, BTTV_BOARD_IVCE8784, "IVCE-8784" }, + { 0xf0500001, BTTV_BOARD_IVCE8784, "IVCE-8784" }, + { 0xf0500002, BTTV_BOARD_IVCE8784, "IVCE-8784" }, + { 0xf0500003, BTTV_BOARD_IVCE8784, "IVCE-8784" }, + + { 0x41424344, BTTV_BOARD_GRANDTEC, "GrandTec Multi Capture" }, + { 0x01020304, BTTV_BOARD_XGUARD, "Grandtec Grand X-Guard" }, + + { 0x18501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, + { 0xa0501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, + { 0x18511851, BTTV_BOARD_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" }, + { 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" }, + { 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" }, + { 0x18501f7f, BTTV_BOARD_FLYVIDEO_98, "Lifeview Flyvideo 98" }, + + { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" }, + { 0x010114c7, BTTV_BOARD_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" }, + + { 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" }, + { 0x217d6606, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0xfff6f6ff, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x03116000, BTTV_BOARD_SENSORAY311, "Sensoray 311" }, + { 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" }, + { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" }, + { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" }, + { 0x146caa0c, BTTV_BOARD_PV951, "ituner spectra8" }, + { 0x200a1295, BTTV_BOARD_PXC200, "ImageNation PXC200A" }, + + { 0x40111554, BTTV_BOARD_PV_BT878P_9B, "Prolink Pixelview PV-BT" }, + { 0x17de0a01, BTTV_BOARD_KWORLD, "Mecer TV/FM/Video Tuner" }, + + { 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" }, + { 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" }, + { 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" }, + { 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" }, + + { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" }, + + { 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" }, + { 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" }, + + /* likely broken, vendor id doesn't match the other magic views ... + * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ + + /* Duplicate PCI ID, reconfigure for this board during the eeprom read. + * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */ + + { 0x109e036e, BTTV_BOARD_CONCEPTRONIC_CTVFMI2, "Conceptronic CTVFMi v2"}, + + /* DVB cards (using pci function .1 for mpeg data xfer) */ + { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" }, + { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, + { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"}, + { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, + { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" }, + { 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, + { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, + { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, + { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, + { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, + { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, + { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "}, + { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" }, + { 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" }, + { 0x18011000, BTTV_BOARD_ENLTV_FM_2, "Encore ENL TV-FM-2" }, + { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" }, + { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, + { 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, + { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, + + { 0x15401830, BTTV_BOARD_PV183, "Provideo PV183-1" }, + { 0x15401831, BTTV_BOARD_PV183, "Provideo PV183-2" }, + { 0x15401832, BTTV_BOARD_PV183, "Provideo PV183-3" }, + { 0x15401833, BTTV_BOARD_PV183, "Provideo PV183-4" }, + { 0x15401834, BTTV_BOARD_PV183, "Provideo PV183-5" }, + { 0x15401835, BTTV_BOARD_PV183, "Provideo PV183-6" }, + { 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" }, + { 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" }, + + { 0, -1, NULL } +}; + +/* ----------------------------------------------------------------------- */ +/* array with description for bt848 / bt878 tv/grabber cards */ + +struct tvcard bttv_tvcards[] = { + /* ---- card 0x00 ---------------------------------- */ + [BTTV_BOARD_UNKNOWN] = { + .name = " *** UNKNOWN/GENERIC *** ", + .video_inputs = 4, + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MIRO] = { + .name = "MIRO PCTV", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 10, + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_HAUPPAUGE] = { + .name = "Hauppauge (bt848)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_STB] = { + .name = "STB, Gateway P/N 6000699 (bt848)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 4, 0, 2, 3 }, + .gpiomute = 1, + .no_msp34xx = 1, + .needs_tvaudio = 1, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + + /* ---- card 0x04 ---------------------------------- */ + [BTTV_BOARD_INTEL] = { + .name = "Intel Create and Share PCI/ Smart Video Recorder III", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 2, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0 }, + .needs_tvaudio = 0, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_DIAMOND] = { + .name = "Diamond DTV2000", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 3, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0, 1, 0, 1 }, + .gpiomute = 3, + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_AVERMEDIA] = { + .name = "AVerMedia TVPhone", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 3, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomask = 0x0f, + .gpiomux = { 0x0c, 0x04, 0x08, 0x04 }, + /* 0x04 for some cards ?? */ + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= avermedia_tvphone_audio, + .has_remote = 1, + }, + [BTTV_BOARD_MATRIX_VISION] = { + .name = "MATRIX-Vision MV-Delta", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0, 0), + .gpiomux = { 0 }, + .needs_tvaudio = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x08 ---------------------------------- */ + [BTTV_BOARD_FLYVIDEO] = { + .name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xc00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0xc00, 0x800, 0x400 }, + .gpiomute = 0xc00, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TURBOTV] = { + .name = "IMS/IXmicro TurboTV", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 3, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 1, 2, 3 }, + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_HAUPPAUGE878] = { + .name = "Hauppauge (bt878)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x0f, /* old: 7 */ + .muxsel = MUXSEL(2, 0, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MIROPRO] = { + .name = "MIRO PCTV pro", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3014f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20001,0x10001, 0, 0 }, + .gpiomute = 10, + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x0c ---------------------------------- */ + [BTTV_BOARD_ADSTECH_TV] = { + .name = "ADS Technologies Channel Surfer TV (bt848)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 13, 14, 11, 7 }, + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_AVERMEDIA98] = { + .name = "AVerMedia TVCapture 98", + .video_inputs = 3, + /* .audio_inputs= 4, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 13, 14, 11, 7 }, + .needs_tvaudio = 1, + .msp34xx_alt = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= avermedia_tv_stereo_audio, + .no_gpioirq = 1, + }, + [BTTV_BOARD_VHX] = { + .name = "Aimslab Video Highway Xtreme (VHX)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 2, 1, 3 }, /* old: {0, 1, 2, 3, 4} */ + .gpiomute = 4, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ZOLTRIX] = { + .name = "Zoltrix TV-Max", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 1, 0 }, + .gpiomute = 10, + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x10 ---------------------------------- */ + [BTTV_BOARD_PIXVIEWPLAYTV] = { + .name = "Prolink Pixelview PlayTV (bt878)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x01fe00, + .muxsel = MUXSEL(2, 3, 1, 1), + /* 2003-10-20 by "Anton A. Arapov" */ + .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 }, + .gpiomute = 0x002000, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_WINVIEW_601] = { + .name = "Leadtek WinView 601", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x8300f8, + .muxsel = MUXSEL(2, 3, 1, 1, 0), + .gpiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 }, + .gpiomute = 0xcfa007, + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .volume_gpio = winview_volume, + .has_radio = 1, + }, + [BTTV_BOARD_AVEC_INTERCAP] = { + .name = "AVEC Intercapture", + .video_inputs = 3, + /* .audio_inputs= 2, */ + .svhs = 2, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 0, 0, 0 }, + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_LIFE_FLYKIT] = { + .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 0x8dff00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0 }, + .no_msp34xx = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x14 ---------------------------------- */ + [BTTV_BOARD_CEI_RAFFLES] = { + .name = "CEI Raffles Card", + .video_inputs = 3, + /* .audio_inputs= 3, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 1), + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_CONFERENCETV] = { + .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50", + .video_inputs = 4, + /* .audio_inputs= 2, tuner, line in */ + .svhs = 2, + .gpiomask = 0x1800, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_PHOEBE_TVMAS] = { + .name = "Askey CPH050/ Phoebe Tv Master + FM", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xc00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 0x800, 0x400 }, + .gpiomute = 0xc00, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MODTEC_205] = { + .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .has_dig_in = 1, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 0), /* input 2 is digital */ + /* .digital_mode= DIGITAL_MODE_CAMERA, */ + .gpiomux = { 0, 0, 0, 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ALPS_TSBB5_PAL_I, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x18 ---------------------------------- */ + [BTTV_BOARD_MAGICTVIEW061] = { + .name = "Askey CPH05X/06X (bt878) [many vendors]", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xe00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = {0x400, 0x400, 0x400, 0x400 }, + .gpiomute = 0xc00, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + }, + [BTTV_BOARD_VOBIS_BOOSTAR] = { + .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x1f0fff, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20000, 0x30000, 0x10000, 0 }, + .gpiomute = 0x40000, + .needs_tvaudio = 0, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= terratv_audio, + }, + [BTTV_BOARD_HAUPPAUG_WCAM] = { + .name = "Hauppauge WinCam newer (bt878)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 7, + .muxsel = MUXSEL(2, 0, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .needs_tvaudio = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MAXI] = { + .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50", + .video_inputs = 4, + /* .audio_inputs= 2, */ + .svhs = 2, + .gpiomask = 0x1800, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_SECAM, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x1c ---------------------------------- */ + [BTTV_BOARD_TERRATV] = { + .name = "Terratec TerraTV+ Version 1.1 (bt878)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x1f0fff, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20000, 0x30000, 0x10000, 0x00000 }, + .gpiomute = 0x40000, + .needs_tvaudio = 0, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= terratv_audio, + /* GPIO wiring: + External 20 pin connector (for Active Radio Upgrade board) + gpio00: i2c-sda + gpio01: i2c-scl + gpio02: om5610-data + gpio03: om5610-clk + gpio04: om5610-wre + gpio05: om5610-stereo + gpio06: rds6588-davn + gpio07: Pin 7 n.c. + gpio08: nIOW + gpio09+10: nIOR, nSEL ?? (bt878) + gpio09: nIOR (bt848) + gpio10: nSEL (bt848) + Sound Routing: + gpio16: u2-A0 (1st 4052bt) + gpio17: u2-A1 + gpio18: u2-nEN + gpio19: u4-A0 (2nd 4052) + gpio20: u4-A1 + u4-nEN - GND + Btspy: + 00000 : Cdrom (internal audio input) + 10000 : ext. Video audio input + 20000 : TV Mono + a0000 : TV Mono/2 + 1a0000 : TV Stereo + 30000 : Radio + 40000 : Mute + */ + + }, + [BTTV_BOARD_PXC200] = { + /* Jannik Fritsch */ + .name = "Imagenation PXC200", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 1, /* was: 4 */ + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0, 0), + .gpiomux = { 0 }, + .needs_tvaudio = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel_hook = PXC200_muxsel, + + }, + [BTTV_BOARD_FLYVIDEO_98] = { + .name = "Lifeview FlyVideo 98 LR50", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x1800, /* 0x8dfe00 */ + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x0800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_IPROTV] = { + .name = "Formac iProTV, Formac ProTV I (bt848)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 1, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 0, 0, 0 }, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x20 ---------------------------------- */ + [BTTV_BOARD_INTEL_C_S_PCI] = { + .name = "Intel Create and Share PCI/ Smart Video Recorder III", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 2, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0 }, + .needs_tvaudio = 0, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TERRATVALUE] = { + .name = "Terratec TerraTValue Version Bt878", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xffff00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x500, 0, 0x300, 0x900 }, + .gpiomute = 0x900, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_WINFAST2000] = { + .name = "Leadtek WinFast 2000/ WinFast 2000 XP", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + /* TV, CVid, SVid, CVid over SVid connector */ + .muxsel = MUXSEL(2, 3, 1, 1, 0), + /* Alexander Varakin [stereo version] */ + .gpiomask = 0xb33000, + .gpiomux = { 0x122000,0x1000,0x0000,0x620000 }, + .gpiomute = 0x800000, + /* Audio Routing for "WinFast 2000 XP" (no tv stereo !) + gpio23 -- hef4052:nEnable (0x800000) + gpio12 -- hef4052:A1 + gpio13 -- hef4052:A0 + 0x0000: external audio + 0x1000: FM + 0x2000: TV + 0x3000: n.c. + Note: There exists another variant "Winfast 2000" with tv stereo !? + Note: eeprom only contains FF and pci subsystem id 107d:6606 + */ + .needs_tvaudio = 0, + .pll = PLL_28, + .has_radio = 1, + .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */ + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= winfast2000_audio, + .has_remote = 1, + }, + [BTTV_BOARD_CHRONOS_VS2] = { + .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II", + .video_inputs = 4, + /* .audio_inputs= 3, */ + .svhs = 2, + .gpiomask = 0x1800, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x24 ---------------------------------- */ + [BTTV_BOARD_TYPHOON_TVIEW] = { + .name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner", + .video_inputs = 4, + /* .audio_inputs= 3, */ + .svhs = 2, + .gpiomask = 0x1800, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + }, + [BTTV_BOARD_PXELVWPLTVPRO] = { + .name = "Prolink PixelView PlayTV pro", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xff, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x21, 0x20, 0x24, 0x2c }, + .gpiomute = 0x29, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MAGICTVIEW063] = { + .name = "Askey CPH06X TView99", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x551e00, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0x551400, 0x551200, 0, 0 }, + .gpiomute = 0x551c00, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + }, + [BTTV_BOARD_PINNACLE] = { + .name = "Pinnacle PCTV Studio/Rave", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x03000F, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0xd0001, 0, 0 }, + .gpiomute = 1, + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x28 ---------------------------------- */ + [BTTV_BOARD_STB2] = { + .name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 4, 0, 2, 3 }, + .gpiomute = 1, + .no_msp34xx = 1, + .needs_tvaudio = 1, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + [BTTV_BOARD_AVPHONE98] = { + .name = "AVerMedia TVPhone 98", + .video_inputs = 3, + /* .audio_inputs= 4, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 13, 4, 11, 7 }, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + .audio_mode_gpio= avermedia_tvphone_audio, + }, + [BTTV_BOARD_PV951] = { + .name = "ProVideo PV951", /* pic16c54 */ + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 0, 0}, + .needs_tvaudio = 1, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ONAIR_TV] = { + .name = "Little OnAir TV", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xe00b, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 }, + .gpiomute = 0xff3ffc, + .no_msp34xx = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x2c ---------------------------------- */ + [BTTV_BOARD_SIGMA_TVII_FM] = { + .name = "Sigma TVII-FM", + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 3, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 1, 0, 2 }, + .gpiomute = 3, + .no_msp34xx = 1, + .pll = PLL_NONE, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MATRIX_VISION2] = { + .name = "MATRIX-Vision MV-Delta 2", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0, 0), + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ZOLTRIX_GENIE] = { + .name = "Zoltrix Genie TV/FM", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xbcf03f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0 }, + .gpiomute = 0xbcb03f, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4039FR5_NTSC, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TERRATVRADIO] = { + .name = "Terratec TV/Radio+", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x70000, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20000, 0x30000, 0x10000, 0 }, + .gpiomute = 0x40000, + .needs_tvaudio = 1, + .no_msp34xx = 1, + .pll = PLL_35, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + }, + + /* ---- card 0x30 ---------------------------------- */ + [BTTV_BOARD_DYNALINK] = { + .name = "Askey CPH03x/ Dynalink Magic TView", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = {2,0,0,0 }, + .gpiomute = 1, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_GVBCTV3PCI] = { + .name = "IODATA GV-BCTV3/PCI", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x010f00, + .muxsel = MUXSEL(2, 3, 0, 0), + .gpiomux = {0x10000, 0, 0x10000, 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ALPS_TSHC6_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= gvbctv3pci_audio, + }, + [BTTV_BOARD_PXELVWPLTVPAK] = { + .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 3, + .has_dig_in = 1, + .gpiomask = 0xAA0000, + .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */ + /* .digital_mode= DIGITAL_MODE_CAMERA, */ + .gpiomux = { 0x20000, 0, 0x80000, 0x80000 }, + .gpiomute = 0xa8000, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + /* GPIO wiring: (different from Rev.4C !) + GPIO17: U4.A0 (first hef4052bt) + GPIO19: U4.A1 + GPIO20: U5.A1 (second hef4052bt) + GPIO21: U4.nEN + GPIO22: BT832 Reset Line + GPIO23: A5,A0, U5,nEN + Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22 + */ + }, + [BTTV_BOARD_EAGLE] = { + .name = "Eagle Wireless Capricorn2 (bt878A)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 0, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .pll = PLL_28, + .tuner_type = UNSET /* TUNER_ALPS_TMDH2_NTSC */, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x34 ---------------------------------- */ + [BTTV_BOARD_PINNACLEPRO] = { + /* David Härdeman */ + .name = "Pinnacle PCTV Studio Pro", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 0x03000F, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 0xd0001, 0, 0 }, + .gpiomute = 10, + /* sound path (5 sources): + MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable) + 0= ext. Audio IN + 1= from MUX2 + 2= Mono TV sound from Tuner + 3= not connected + MUX2 (mask 0x30000): + 0,2,3= from MSP34xx + 1= FM stereo Radio from Tuner */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TVIEW_RDS_FM] = { + /* Claas Langbehn , + Sven Grothklags */ + .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS", + .video_inputs = 4, + /* .audio_inputs= 3, */ + .svhs = 2, + .gpiomask = 0x1c, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 0x10, 8 }, + .gpiomute = 4, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + }, + [BTTV_BOARD_LIFETEC_9415] = { + /* Tim Röstermundt + in de.comp.os.unix.linux.hardware: + options bttv card=0 pll=1 radio=1 gpiomask=0x18e0 + gpiomux =0x44c71f,0x44d71f,0,0x44d71f,0x44dfff + options tuner type=5 */ + .name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x18e0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x0000,0x0800,0x1000,0x1000 }, + .gpiomute = 0x18e0, + /* For cards with tda9820/tda9821: + 0x0000: Tuner normal stereo + 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) + 0x0880: Tuner A2 stereo */ + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_BESTBUY_EASYTV] = { + /* Miguel Angel Alvarez + old Easy TV BT848 version (model CPH031) */ + .name = "Askey CPH031/ BESTBUY Easy TV", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xF, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 10, + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x38 ---------------------------------- */ + [BTTV_BOARD_FLYVIDEO_98FM] = { + /* Gordon Heydon */ + [BTTV_BOARD_GRANDTEC] = { + .name = "GrandTec 'Grand Video Capture' (Bt848)", + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .gpiomask = 0, + .muxsel = MUXSEL(3, 1), + .gpiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_35, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ASKEY_CPH060] = { + /* Daniel Herrington */ + .name = "Askey CPH060/ Phoebe TV Master Only (No FM)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xe00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x400, 0x400, 0x400, 0x400 }, + .gpiomute = 0x800, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4036FY5_NTSC, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ASKEY_CPH03X] = { + /* Matti Mottus */ + .name = "Askey CPH03x TV Capturer", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x03000F, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 1, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + }, + + /* ---- card 0x3c ---------------------------------- */ + [BTTV_BOARD_MM100PCTV] = { + /* Philip Blundell */ + .name = "Modular Technology MM100PCTV", + .video_inputs = 2, + /* .audio_inputs= 2, */ + .svhs = NO_SVHS, + .gpiomask = 11, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0, 0, 1 }, + .gpiomute = 8, + .pll = PLL_35, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_GMV1] = { + /* Adrian Cox + new Easy TV BT878 version (model CPH061) + special thanks to Informatica Mieres for providing the card */ + .name = "Askey CPH061/ BESTBUY Easy TV (bt878)", + .video_inputs = 3, + /* .audio_inputs= 2, */ + .svhs = 2, + .gpiomask = 0xFF, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 1, 0, 4, 4 }, + .gpiomute = 9, + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ATI_TVWONDER] = { + /* Lukas Gebauer */ + .name = "ATI TV-Wonder", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xf03f, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0xbffe, 0, 0xbfff, 0 }, + .gpiomute = 0xbffe, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x40 ---------------------------------- */ + [BTTV_BOARD_ATI_TVWONDERVE] = { + /* Lukas Gebauer */ + .name = "ATI TV-Wonder VE", + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 1, + .muxsel = MUXSEL(2, 3, 0, 1), + .gpiomux = { 0, 0, 1, 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_FLYVIDEO2000] = { + /* DeeJay */ + .name = "IODATA GV-BCTV4/PCI", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x010f00, + .muxsel = MUXSEL(2, 3, 0, 0), + .gpiomux = {0x10000, 0, 0x10000, 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= gvbctv3pci_audio, + }, + + /* ---- card 0x44 ---------------------------------- */ + [BTTV_BOARD_VOODOOTV_FM] = { + .name = "3Dfx VoodooTV FM (Euro)", + /* try "insmod msp3400 simple=0" if you have + * sound problems with this card. */ + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 0x4f8a00, + /* 0x100000: 1=MSP enabled (0=disable again) + * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ + .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, + .gpiomute = 0x947fff, + /* tvtuner, radio, external,internal, mute, stereo + * tuner, Composit, SVid, Composit-on-Svid-adapter */ + .muxsel = MUXSEL(2, 3, 0, 1), + .tuner_type = TUNER_MT2032, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + [BTTV_BOARD_VOODOOTV_200] = { + .name = "VoodooTV 200 (USA)", + /* try "insmod msp3400 simple=0" if you have + * sound problems with this card. */ + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 0x4f8a00, + /* 0x100000: 1=MSP enabled (0=disable again) + * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ + .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, + .gpiomute = 0x947fff, + /* tvtuner, radio, external,internal, mute, stereo + * tuner, Composit, SVid, Composit-on-Svid-adapter */ + .muxsel = MUXSEL(2, 3, 0, 1), + .tuner_type = TUNER_MT2032, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + [BTTV_BOARD_AIMMS] = { + /* Philip Blundell */ + .name = "Active Imaging AIMMS", + .video_inputs = 1, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .muxsel = MUXSEL(2), + .gpiomask = 0 + }, + [BTTV_BOARD_PV_BT878P_PLUS] = { + /* Tomasz Pyra */ + .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)", + .video_inputs = 3, + /* .audio_inputs= 4, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 11, 7 }, /* TV and Radio with same GPIO ! */ + .gpiomute = 13, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_LG_PAL_I_FM, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + /* GPIO wiring: + GPIO0: U4.A0 (hef4052bt) + GPIO1: U4.A1 + GPIO2: U4.A1 (second hef4052bt) + GPIO3: U4.nEN, U5.A0, A5.nEN + GPIO8-15: vrd866b ? + */ + }, + [BTTV_BOARD_FLYVIDEO98EZ] = { + .name = "Lifeview FlyVideo 98EZ (capture only) LR51", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 2, + /* AV1, AV2, SVHS, CVid adapter on SVHS */ + .muxsel = MUXSEL(2, 3, 1, 1), + .pll = PLL_28, + .no_msp34xx = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x48 ---------------------------------- */ + [BTTV_BOARD_PV_BT878P_9B] = { + /* Dariusz Kowalewski */ + .name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x01, 0x00, 0x03, 0x03 }, + .gpiomute = 0x09, + .needs_tvaudio = 1, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */ + .has_radio = 1, /* Note: not all cards have radio */ + .has_remote = 1, + /* GPIO wiring: + GPIO0: A0 hef4052 + GPIO1: A1 hef4052 + GPIO3: nEN hef4052 + GPIO8-15: vrd866b + GPIO20,22,23: R30,R29,R28 + */ + }, + [BTTV_BOARD_SENSORAY311] = { + /* Clay Kunz */ + /* you must jumper JP5 for the card to work */ + .name = "Sensoray 311", + .video_inputs = 5, + /* .audio_inputs= 0, */ + .svhs = 4, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0, 0), + .gpiomux = { 0 }, + .needs_tvaudio = 0, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_RV605] = { + /* Miguel Freitas */ + .name = "RemoteVision MX (RV605)", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x00, + .gpiomask2 = 0x07ff, + .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), + .no_msp34xx = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel_hook = rv605_muxsel, + }, + [BTTV_BOARD_POWERCLR_MTV878] = { + .name = "Powercolor MTV878/ MTV878R/ MTV878F", + .video_inputs = 3, + /* .audio_inputs= 2, */ + .svhs = 2, + .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */ + .muxsel = MUXSEL(2, 1, 1), + .gpiomux = { 0, 1, 2, 2 }, + .gpiomute = 4, + .needs_tvaudio = 0, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + + /* ---- card 0x4c ---------------------------------- */ + [BTTV_BOARD_WINDVR] = { + /* Masaki Suzuki */ + .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x140007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= windvr_audio, + }, + [BTTV_BOARD_GRANDTEC_MULTI] = { + .name = "GrandTec Multi Capture Card (Bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_KWORLD] = { + .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF", + .video_inputs = 4, + /* .audio_inputs= 3, */ + .svhs = 2, + .gpiomask = 7, + /* Tuner, SVid, SVHS, SVid to SVHS connector */ + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 4, 4 },/* Yes, this tuner uses the same audio output for TV and FM radio! + * This card lacks external Audio In, so we mute it on Ext. & Int. + * The PCB can take a sbx1637/sbx1673, wiring unknown. + * This card lacks PCI subsystem ID, sigh. + * gpiomux =1: lower volume, 2+3: mute + * btwincap uses 0x80000/0x80003 + */ + .gpiomute = 4, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and + radio signal strength indicators work fine. */ + .has_radio = 1, + /* GPIO Info: + GPIO0,1: HEF4052 A0,A1 + GPIO2: HEF4052 nENABLE + GPIO3-7: n.c. + GPIO8-13: IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card] + GPIO14,15: ?? + GPIO16-21: n.c. + GPIO22,23: ?? + ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/ + }, + [BTTV_BOARD_DSP_TCVIDEO] = { + /* Arthur Tetzlaff-Deas, DSP Design Ltd */ + .name = "DSP Design TCVIDEO", + .video_inputs = 4, + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 1, 0), + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x50 ---------------------------------- */ + [BTTV_BOARD_HAUPPAUGEPVR] = { + .name = "Hauppauge WinTV PVR", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 0, 1, 1), + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + + .gpiomask = 7, + .gpiomux = {7}, + }, + [BTTV_BOARD_GVBCTV5PCI] = { + .name = "IODATA GV-BCTV5/PCI", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x0f0f80, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = {0x030000, 0x010000, 0, 0 }, + .gpiomute = 0x020000, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= gvbctv5pci_audio, + .has_radio = 1, + }, + [BTTV_BOARD_OSPREY1x0] = { + .name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */ + .video_inputs = 4, /* id-inputs-clock */ + /* .audio_inputs= 0, */ + .svhs = 3, + .muxsel = MUXSEL(3, 2, 0, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY1x0_848] = { + .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */ + .video_inputs = 3, + /* .audio_inputs= 0, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + + /* ---- card 0x54 ---------------------------------- */ + [BTTV_BOARD_OSPREY101_848] = { + .name = "Osprey 101 (848)", /* 0x05-40C0-C1 */ + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .muxsel = MUXSEL(3, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY1x1] = { + .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */ + .video_inputs = 1, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(0), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY1x1_SVID] = { + .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */ + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .muxsel = MUXSEL(0, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY2xx] = { + .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */ + .video_inputs = 1, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(0), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + + /* ---- card 0x58 ---------------------------------- */ + [BTTV_BOARD_OSPREY2x0_SVID] = { + .name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */ + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = 1, + .muxsel = MUXSEL(0, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY2x0] = { + .name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */ + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = 1, + .muxsel = MUXSEL(2, 3), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY500] = { + .name = "Osprey 500", /* 500 */ + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = 1, + .muxsel = MUXSEL(2, 3), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY540] = { + .name = "Osprey 540", /* 540 */ + .video_inputs = 4, + /* .audio_inputs= 1, */ + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + + /* ---- card 0x5C ---------------------------------- */ + [BTTV_BOARD_OSPREY2000] = { + .name = "Osprey 2000", /* 2000 */ + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = 1, + .muxsel = MUXSEL(2, 3), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */ + }, + [BTTV_BOARD_IDS_EAGLE] = { + /* M G Berberich */ + .name = "IDS Eagle", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 2, 2, 2), + .muxsel_hook = eagle_muxsel, + .no_msp34xx = 1, + .pll = PLL_28, + }, + [BTTV_BOARD_PINNACLESAT] = { + .name = "Pinnacle PCTV Sat", + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel = MUXSEL(3, 1), + .pll = PLL_28, + .no_gpioirq = 1, + .has_dvb = 1, + }, + [BTTV_BOARD_FORMAC_PROTV] = { + .name = "Formac ProTV II (bt878)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 2, + /* TV, Comp1, Composite over SVID con, SVID */ + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 2, 0, 0 }, + .pll = PLL_28, + .has_radio = 1, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + /* sound routing: + GPIO=0x00,0x01,0x03: mute (?) + 0x02: both TV and radio (tuner: FM1216/I) + The card has onboard audio connectors labeled "cdrom" and "board", + not soldered here, though unknown wiring. + Card lacks: external audio in, pci subsystem id. + */ + }, + + /* ---- card 0x60 ---------------------------------- */ + [BTTV_BOARD_MACHTV] = { + .name = "MachTV", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 3}, + .gpiomute = 4, + .needs_tvaudio = 1, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + }, + [BTTV_BOARD_EURESYS_PICOLO] = { + .name = "Euresys Picolo", + .video_inputs = 3, + /* .audio_inputs= 0, */ + .svhs = 2, + .gpiomask = 0, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel = MUXSEL(2, 0, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_PV150] = { + /* Luc Van Hoeylandt */ + .name = "ProVideo PV150", /* 0x4f */ + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3), + .gpiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_AD_TVK503] = { + /* Hiroshi Takekawa */ + /* This card lacks subsystem ID */ + .name = "AD-TVK503", /* 0x63 */ + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x001e8007, + .muxsel = MUXSEL(2, 3, 1, 0), + /* Tuner, Radio, external, internal, off, on */ + .gpiomux = { 0x08, 0x0f, 0x0a, 0x08 }, + .gpiomute = 0x0f, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= adtvk503_audio, + }, + + /* ---- card 0x64 ---------------------------------- */ + [BTTV_BOARD_HERCULES_SM_TV] = { + .name = "Hercules Smart TV Stereo", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x00, + .muxsel = MUXSEL(2, 3, 1, 1), + .needs_tvaudio = 1, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + /* Notes: + - card lacks subsystem ID + - stereo variant w/ daughter board with tda9874a @0xb0 + - Audio Routing: + always from tda9874 independent of GPIO (?) + external line in: unknown + - Other chips: em78p156elp @ 0x96 (probably IR remote control) + hef4053 (instead 4052) for unknown function + */ + }, + [BTTV_BOARD_PACETV] = { + .name = "Pace TV & Radio Card", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + /* Tuner, CVid, SVid, CVid over SVid connector */ + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomask = 0, + .no_tda7432 = 1, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + .pll = PLL_28, + /* Bt878, Bt832, FI1246 tuner; no pci subsystem id + only internal line out: (4pin header) RGGL + Radio must be decoded by msp3410d (not routed through)*/ + /* + .digital_mode = DIGITAL_MODE_CAMERA, todo! + */ + }, + [BTTV_BOARD_IVC200] = { + /* Chris Willing */ + .name = "IVC-200", + .video_inputs = 1, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0xdf, + .muxsel = MUXSEL(2), + .pll = PLL_28, + }, + [BTTV_BOARD_IVCE8784] = { + .name = "IVCE-8784", + .video_inputs = 1, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0xdf, + .muxsel = MUXSEL(2), + .pll = PLL_28, + }, + [BTTV_BOARD_XGUARD] = { + .name = "Grand X-Guard / Trust 814PCI", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .gpiomask2 = 0xff, + .muxsel = MUXSEL(2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0), + .muxsel_hook = xguard_muxsel, + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + }, + + /* ---- card 0x68 ---------------------------------- */ + [BTTV_BOARD_NEBULA_DIGITV] = { + .name = "Nebula Electronics DigiTV", + .video_inputs = 1, + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 1, 0), + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .has_dvb = 1, + .has_remote = 1, + .gpiomask = 0x1b, + .no_gpioirq = 1, + }, + [BTTV_BOARD_PV143] = { + /* Jorge Boncompte - DTI2 */ + .name = "ProVideo PV143", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD009X1_VD011_MINIDIN] = { + /* M.Klahr@phytec.de */ + .name = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD009X1_VD011_COMBI] = { + .name = "PHYTEC VD-009-X1 VD-011 Combi (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x6c ---------------------------------- */ + [BTTV_BOARD_VD009_MINIDIN] = { + .name = "PHYTEC VD-009 MiniDIN (bt878)", + .video_inputs = 10, + /* .audio_inputs= 0, */ + .svhs = 9, + .gpiomask = 0x00, + .gpiomask2 = 0x03, /* used for external vodeo mux */ + .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 0), + .muxsel_hook = phytec_muxsel, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD009_COMBI] = { + .name = "PHYTEC VD-009 Combi (bt878)", + .video_inputs = 10, + /* .audio_inputs= 0, */ + .svhs = 9, + .gpiomask = 0x00, + .gpiomask2 = 0x03, /* used for external vodeo mux */ + .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 1), + .muxsel_hook = phytec_muxsel, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_IVC100] = { + .name = "IVC-100", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0xdf, + .muxsel = MUXSEL(2, 3, 1, 0), + .pll = PLL_28, + }, + [BTTV_BOARD_IVC120] = { + /* IVC-120G - Alan Garfield */ + .name = "IVC-120G", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, /* card has no svhs */ + .needs_tvaudio = 0, + .no_msp34xx = 1, + .no_tda7432 = 1, + .gpiomask = 0x00, + .muxsel = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + .muxsel_hook = ivc120_muxsel, + .pll = PLL_28, + }, + + /* ---- card 0x70 ---------------------------------- */ + [BTTV_BOARD_PC_HDTV] = { + .name = "pcHDTV HD-2000 TV", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = TUNER_PHILIPS_FCV1236D, + .tuner_addr = ADDR_UNSET, + .has_dvb = 1, + }, + [BTTV_BOARD_TWINHAN_DST] = { + .name = "Twinhan DST + clones", + .no_msp34xx = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_video = 1, + .has_dvb = 1, + }, + [BTTV_BOARD_WINFASTVC100] = { + .name = "Winfast VC100", + .video_inputs = 3, + /* .audio_inputs= 0, */ + .svhs = 1, + /* Vid In, SVid In, Vid over SVid in connector */ + .muxsel = MUXSEL(3, 1, 1, 3), + .no_msp34xx = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + }, + [BTTV_BOARD_TEV560] = { + .name = "Teppro TEV-560/InterVision IV-560", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 3, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 1, 1, 1 }, + .needs_tvaudio = 1, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .pll = PLL_35, + }, + + /* ---- card 0x74 ---------------------------------- */ + [BTTV_BOARD_SIMUS_GVC1100] = { + .name = "SIMUS GVC1100", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .muxsel = MUXSEL(2, 2, 2, 2), + .gpiomask = 0x3F, + .muxsel_hook = gvc1100_muxsel, + }, + [BTTV_BOARD_NGSTV_PLUS] = { + /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */ + .name = "NGS NGSTV+", + .video_inputs = 3, + .svhs = 2, + .gpiomask = 0x008007, + .muxsel = MUXSEL(2, 3, 0, 0), + .gpiomux = { 0, 0, 0, 0 }, + .gpiomute = 0x000003, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + }, + [BTTV_BOARD_LMLBT4] = { + /* http://linuxmedialabs.com */ + .name = "LMLBT4", + .video_inputs = 4, /* IN1,IN2,IN3,IN4 */ + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 1, 0), + .no_msp34xx = 1, + .no_tda7432 = 1, + .needs_tvaudio = 0, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TEKRAM_M205] = { + /* Helmroos Harri */ + .name = "Tekram M205 PRO", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .svhs = 2, + .needs_tvaudio = 0, + .gpiomask = 0x68, + .muxsel = MUXSEL(2, 3, 1), + .gpiomux = { 0x68, 0x68, 0x61, 0x61 }, + .pll = PLL_28, + }, + + /* ---- card 0x78 ---------------------------------- */ + [BTTV_BOARD_CONTVFMI] = { + /* Javier Cendan Ares */ + /* bt878 TV + FM without subsystem ID */ + .name = "Conceptronic CONTVFMi", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x008007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 2 }, + .gpiomute = 3, + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + .has_radio = 1, + }, + [BTTV_BOARD_PICOLO_TETRA_CHIP] = { + /*Eric DEBIEF */ + /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controlled*/ + /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the following declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/ + /*0x79 in bttv.h*/ + .name = "Euresys Picolo Tetra", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/ + .no_msp34xx = 1, + .no_tda7432 = 1, + /*878A input is always MUX0, see above.*/ + .muxsel = MUXSEL(2, 2, 2, 2), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .pll = PLL_28, + .needs_tvaudio = 0, + .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_SPIRIT_TV] = { + /* Spirit TV Tuner from http://spiritmodems.com.au */ + /* Stafford Goodsell */ + .name = "Spirit TV Tuner", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x0000000f, + .muxsel = MUXSEL(2, 1, 1), + .gpiomux = { 0x02, 0x00, 0x00, 0x00 }, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + }, + [BTTV_BOARD_AVDVBT_771] = { + /* Wolfram Joost */ + .name = "AVerMedia AVerTV DVB-T 771", + .video_inputs = 2, + .svhs = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel = MUXSEL(3, 3), + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .has_dvb = 1, + .no_gpioirq = 1, + .has_remote = 1, + }, + /* ---- card 0x7c ---------------------------------- */ + [BTTV_BOARD_AVDVBT_761] = { + /* Matt Jesson */ + /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */ + .name = "AverMedia AverTV DVB-T 761", + .video_inputs = 2, + .svhs = 1, + .muxsel = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */ + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .has_dvb = 1, + .no_gpioirq = 1, + .has_remote = 1, + }, + [BTTV_BOARD_MATRIX_VISIONSQ] = { + /* andre.schwarz@matrix-vision.de */ + .name = "MATRIX Vision Sigma-SQ", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x0, + .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3), + .muxsel_hook = sigmaSQ_muxsel, + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MATRIX_VISIONSLC] = { + /* andre.schwarz@matrix-vision.de */ + .name = "MATRIX Vision Sigma-SLC", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x0, + .muxsel = MUXSEL(2, 2, 2, 2), + .muxsel_hook = sigmaSLC_muxsel, + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + /* BTTV_BOARD_APAC_VIEWCOMP */ + [BTTV_BOARD_APAC_VIEWCOMP] = { + /* Attila Kondoros */ + /* bt878 TV + FM 0x00000000 subsystem ID */ + .name = "APAC Viewcomp 878(AMAX)", + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 0xFF, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 10, + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */ + .has_radio = 1, /* not every card has radio */ + }, + + /* ---- card 0x80 ---------------------------------- */ + [BTTV_BOARD_DVICO_DVBT_LITE] = { + /* Chris Pascoe */ + .name = "DViCO FusionHDTV DVB-T Lite", + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .no_video = 1, + .has_dvb = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VGEAR_MYVCD] = { + /* Steven */ + .name = "V-Gear MyVCD", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3f, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = {0x31, 0x31, 0x31, 0x31 }, + .gpiomute = 0x31, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .tuner_addr = ADDR_UNSET, + .has_radio = 0, + }, + [BTTV_BOARD_SUPER_TV] = { + /* Rick C */ + .name = "Super TV Tuner", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .gpiomask = 0x008007, + .gpiomux = { 0, 0x000001,0,0 }, + .needs_tvaudio = 1, + .has_radio = 1, + }, + [BTTV_BOARD_TIBET_CS16] = { + /* Chris Fanning */ + .name = "Tibet Systems 'Progress DVR' CS16", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel_hook = tibetCS16_muxsel, + }, + [BTTV_BOARD_KODICOM_4400R] = { + /* Bill Brack */ + /* + * Note that, because of the card's wiring, the "master" + * BT878A chip (i.e. the one which controls the analog switch + * and must use this card type) is the 2nd one detected. The + * other 3 chips should use card type 0x85, whose description + * follows this one. There is a EEPROM on the card (which is + * connected to the I2C of one of those other chips), but is + * not currently handled. There is also a facility for a + * "monitor", which is also not currently implemented. + */ + .name = "Kodicom 4400R (master)", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + /* GPIO bits 0-9 used for analog switch: + * 00 - 03: camera selector + * 04 - 06: channel (controller) selector + * 07: data (1->on, 0->off) + * 08: strobe + * 09: reset + * bit 16 is input from sync separator for the channel + */ + .gpiomask = 0x0003ff, + .no_gpioirq = 1, + .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel_hook = kodicom4400r_muxsel, + }, + [BTTV_BOARD_KODICOM_4400R_SL] = { + /* Bill Brack */ + /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the + * one which controls the analog switch, and must use the card type) + * is the 2nd one detected. The other 3 chips should use this card + * type + */ + .name = "Kodicom 4400R (slave)", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0x010000, + .no_gpioirq = 1, + .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel_hook = kodicom4400r_muxsel, + }, + /* ---- card 0x86---------------------------------- */ + [BTTV_BOARD_ADLINK_RTV24] = { + /* Michael Henson */ + /* Adlink RTV24 with special unlock codes */ + .name = "Adlink RTV24", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + }, + /* ---- card 0x87---------------------------------- */ + [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = { + /* Michael Krufky */ + .name = "DViCO FusionHDTV 5 Lite", + .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */ + .tuner_addr = ADDR_UNSET, + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1), + .gpiomask = 0x00e00007, + .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, + .gpiomute = 0x00c00007, + .no_msp34xx = 1, + .no_tda7432 = 1, + .has_dvb = 1, + }, + /* ---- card 0x88---------------------------------- */ + [BTTV_BOARD_ACORP_Y878F] = { + /* Mauro Carvalho Chehab */ + .name = "Acorp Y878F", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x01fe00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 }, + .gpiomute = 0x002000, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_YMEC_TVF66T5_B_DFF, + .tuner_addr = 0xc1 >>1, + .has_radio = 1, + }, + /* ---- card 0x89 ---------------------------------- */ + [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = { + .name = "Conceptronic CTVFMi v2", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x001c0007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 2 }, + .gpiomute = 3, + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_TENA_9533_DI, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + .has_radio = 1, + }, + /* ---- card 0x8a ---------------------------------- */ + [BTTV_BOARD_PV_BT878P_2E] = { + .name = "Prolink Pixelview PV-BT878P+ (Rev.2E)", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 3, + .has_dig_in = 1, + .gpiomask = 0x01fe00, + .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */ + /* .digital_mode= DIGITAL_MODE_CAMERA, */ + .gpiomux = { 0x00400, 0x10400, 0x04400, 0x80000 }, + .gpiomute = 0x12400, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_LG_PAL_FM, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + }, + /* ---- card 0x8b ---------------------------------- */ + [BTTV_BOARD_PV_M4900] = { + /* Sérgio Fortier */ + .name = "Prolink PixelView PlayTV MPEG2 PV-M4900", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x21, 0x20, 0x24, 0x2c }, + .gpiomute = 0x29, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_YMEC_TVF_5533MF, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + .has_remote = 1, + }, + /* ---- card 0x8c ---------------------------------- */ + /* Has four Bt878 chips behind a PCI bridge, each chip has: + one external BNC composite input (mux 2) + three internal composite inputs (unknown muxes) + an 18-bit stereo A/D (CS5331A), which has: + one external stereo unblanced (RCA) audio connection + one (or 3?) internal stereo balanced (XLR) audio connection + input is selected via gpio to a 14052B mux + (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300) + gain is controlled via an X9221A chip on the I2C bus @0x28 + sample rate is controlled via gpio to an MK1413S + (mask=0x3, 32kHz=0x0, 44.1kHz=0x1, 48kHz=0x2, ??=0x3) + There is neither a tuner nor an svideo input. */ + [BTTV_BOARD_OSPREY440] = { + .name = "Osprey 440", + .video_inputs = 4, + /* .audio_inputs= 2, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 0, 1), /* 3,0,1 are guesses */ + .gpiomask = 0x303, + .gpiomute = 0x000, /* int + 32kHz */ + .gpiomux = { 0, 0, 0x000, 0x100}, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + /* ---- card 0x8d ---------------------------------- */ + [BTTV_BOARD_ASOUND_SKYEYE] = { + .name = "Asound Skyeye PCTV", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 1, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + }, + /* ---- card 0x8e ---------------------------------- */ + [BTTV_BOARD_SABRENT_TVFM] = { + .name = "Sabrent TV-FM (bttv version)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x108007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 100000, 100002, 100002, 100000 }, + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .tuner_type = TUNER_TNF_5335MF, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + }, + /* ---- card 0x8f ---------------------------------- */ + [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = { + .name = "Hauppauge ImpactVCB (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x0f, /* old: 7 */ + .muxsel = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */ + .no_msp34xx = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MACHTV_MAGICTV] = { + /* Julian Calaby + * Slightly different from original MachTV definition (0x60) + + * FIXME: RegSpy says gpiomask should be "0x001c800f", but it + * stuffs up remote chip. Bug is a pin on the jaecs is not set + * properly (methinks) causing no keyup bits being set */ + + .name = "MagicTV", /* rebranded MachTV */ + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .tuner_type = TUNER_TEMIC_4009FR5_PAL, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + .has_remote = 1, + }, + [BTTV_BOARD_SSAI_SECURITY] = { + .name = "SSAI Security Video Interface", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(0, 1, 2, 3), + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_SSAI_ULTRASOUND] = { + .name = "SSAI Ultrasound Video Interface", + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .muxsel = MUXSEL(2, 0, 1, 3), + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + /* ---- card 0x94---------------------------------- */ + [BTTV_BOARD_DVICO_FUSIONHDTV_2] = { + .name = "DViCO FusionHDTV 2", + .tuner_type = TUNER_PHILIPS_FCV1236D, + .tuner_addr = ADDR_UNSET, + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1), + .gpiomask = 0x00e00007, + .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, + .gpiomute = 0x00c00007, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + /* ---- card 0x95---------------------------------- */ + [BTTV_BOARD_TYPHOON_TVTUNERPCI] = { + .name = "Typhoon TV-Tuner PCI (50684)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3014f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20001,0x10001, 0, 0 }, + .gpiomute = 10, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_GEOVISION_GV600] = { + /* emhn@usb.ve */ + .name = "Geovision GV-600", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x0, + .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), + .muxsel_hook = geovision_muxsel, + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_KOZUMI_KTV_01C] = { + /* Mauro Lacy + * Based on MagicTV and Conceptronic CONTVFMi */ + + .name = "Kozumi KTV-01C", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x008007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 2 }, /* CONTVFMi */ + .gpiomute = 3, /* CONTVFMi */ + .needs_tvaudio = 0, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */ + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + .has_remote = 1, + }, + [BTTV_BOARD_ENLTV_FM_2] = { + /* Encore TV Tuner Pro ENL TV-FM-2 + Mauro Carvalho Chehab IR disabled + bit 18/17 = 00 -> mute + 01 -> enable external audio input + 10 -> internal audio input (mono?) + 11 -> internal audio input + */ + .gpiomask = 0x060040, + .muxsel = MUXSEL(2, 3, 3), + .gpiomux = { 0x60000, 0x60000, 0x20000, 0x20000 }, + .gpiomute = 0, + .tuner_type = TUNER_TCL_MF02GIP_5N, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + .has_remote = 1, + }, + [BTTV_BOARD_VD012] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012 (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x00, + .muxsel = MUXSEL(0, 2, 3, 1), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD012_X1] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012-X1 (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = MUXSEL(2, 3, 1), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD012_X2] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012-X2 (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = MUXSEL(3, 2, 1), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .needs_tvaudio = 0, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_GEOVISION_GV800S] = { + /* Bruno Christo + * + * GeoVision GV-800(S) has 4 Conexant Fusion 878A: + * 1 audio input per BT878A = 4 audio inputs + * 4 video inputs per BT878A = 16 video inputs + * This is the first BT878A chip of the GV-800(S). It's the + * "master" chip and it controls the video inputs through an + * analog multiplexer (a CD22M3494) via some GPIO pins. The + * slaves should use card type 0x9e (following this one). + * There is a EEPROM on the card which is currently not handled. + * The audio input is not working yet. + */ + .name = "Geovision GV-800(S) (master)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0xf107f, + .no_gpioirq = 1, + .muxsel = MUXSEL(2, 2, 2, 2), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel_hook = gv800s_muxsel, + }, + [BTTV_BOARD_GEOVISION_GV800S_SL] = { + /* Bruno Christo + * + * GeoVision GV-800(S) has 4 Conexant Fusion 878A: + * 1 audio input per BT878A = 4 audio inputs + * 4 video inputs per BT878A = 16 video inputs + * The 3 other BT878A chips are "slave" chips of the GV-800(S) + * and should use this card type. + * The audio input is not working yet. + */ + .name = "Geovision GV-800(S) (slave)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0x00, + .no_gpioirq = 1, + .muxsel = MUXSEL(2, 2, 2, 2), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel_hook = gv800s_muxsel, + }, + [BTTV_BOARD_PV183] = { + .name = "ProVideo PV183", /* 0x9f */ + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3), + .gpiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, +}; + +static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); + +/* ----------------------------------------------------------------------- */ + +static unsigned char eeprom_data[256]; + +/* + * identify card + */ +void __devinit bttv_idcard(struct bttv *btv) +{ + unsigned int gpiobits; + int i,type; + unsigned short tmp; + + /* read PCI subsystem ID */ + pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_ID, &tmp); + btv->cardid = tmp << 16; + pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_VENDOR_ID, &tmp); + btv->cardid |= tmp; + + if (0 != btv->cardid && 0xffffffff != btv->cardid) { + /* look for the card */ + for (type = -1, i = 0; cards[i].id != 0; i++) + if (cards[i].id == btv->cardid) + type = i; + + if (type != -1) { + /* found it */ + printk(KERN_INFO "bttv%d: detected: %s [card=%d], " + "PCI subsystem ID is %04x:%04x\n", + btv->c.nr,cards[type].name,cards[type].cardnr, + btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); + btv->c.type = cards[type].cardnr; + } else { + /* 404 */ + printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n", + btv->c.nr, btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); + printk(KERN_DEBUG "please mail id, board name and " + "the correct card= insmod option to linux-media@vger.kernel.org\n"); + } + } + + /* let the user override the autodetected type */ + if (card[btv->c.nr] < bttv_num_tvcards) + btv->c.type=card[btv->c.nr]; + + /* print which card config we are using */ + printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->c.nr, + bttv_tvcards[btv->c.type].name, btv->c.type, + card[btv->c.nr] < bttv_num_tvcards + ? "insmod option" : "autodetected"); + + /* overwrite gpio stuff ?? */ + if (UNSET == audioall && UNSET == audiomux[0]) + return; + + if (UNSET != audiomux[0]) { + gpiobits = 0; + for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { + bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; + gpiobits |= audiomux[i]; + } + } else { + gpiobits = audioall; + for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { + bttv_tvcards[btv->c.type].gpiomux[i] = audioall; + } + } + bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; + printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", + btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); + for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { + printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); + } + printk("\n"); +} + +/* + * (most) board specific initialisations goes here + */ + +/* Some Modular Technology cards have an eeprom, but no subsystem ID */ +static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) +{ + int type = -1; + + if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13)) + type = BTTV_BOARD_MODTEC_205; + else if (0 == strncmp(eeprom_data+20,"Picolo",7)) + type = BTTV_BOARD_EURESYS_PICOLO; + else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0) + type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */ + + if (-1 != type) { + btv->c.type = type; + printk("bttv%d: detected by eeprom: %s [card=%d]\n", + btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type); + } +} + +static void flyvideo_gpio(struct bttv *btv) +{ + int gpio, has_remote, has_radio, is_capture_only; + int is_lr90, has_tda9820_tda9821; + int tuner_type = UNSET, ttype; + + gpio_inout(0xffffff, 0); + udelay(8); /* without this we would see the 0x1800 mask */ + gpio = gpio_read(); + /* FIXME: must restore OUR_EN ??? */ + + /* all cards provide GPIO info, some have an additional eeprom + * LR50: GPIO coding can be found lower right CP1 .. CP9 + * CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1. + * GPIO14-12: n.c. + * LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878) + + * lowest 3 bytes are remote control codes (no handshake needed) + * xxxFFF: No remote control chip soldered + * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered + * Note: Some bits are Audio_Mask ! + */ + ttype = (gpio & 0x0f0000) >> 16; + switch (ttype) { + case 0x0: + tuner_type = 2; /* NTSC, e.g. TPI8NSR11P */ + break; + case 0x2: + tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */ + break; + case 0x4: + tuner_type = 5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ + break; + case 0x6: + tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */ + break; + case 0xC: + tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ + break; + default: + printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr); + break; + } + + has_remote = gpio & 0x800000; + has_radio = gpio & 0x400000; + /* unknown 0x200000; + * unknown2 0x100000; */ + is_capture_only = !(gpio & 0x008000); /* GPIO15 */ + has_tda9820_tda9821 = !(gpio & 0x004000); + is_lr90 = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */ + /* + * gpio & 0x001000 output bit for audio routing */ + + if (is_capture_only) + tuner_type = TUNER_ABSENT; /* No tuner present */ + + printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", + btv->c.nr, has_radio ? "yes" : "no ", + has_remote ? "yes" : "no ", tuner_type, gpio); + printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", + btv->c.nr, is_lr90 ? "yes" : "no ", + has_tda9820_tda9821 ? "yes" : "no ", + is_capture_only ? "yes" : "no "); + + if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */ + btv->tuner_type = tuner_type; + btv->has_radio = has_radio; + + /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 + * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 + * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ + if (has_tda9820_tda9821) + btv->audio_mode_gpio = lt9415_audio; + /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ +} + +static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, + 14,2,17,1, 4,1,4,3, 1,2,16,1, 4,4,4,4 }; +static int miro_fmtuner[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, + 1,1,1,1, 1,1,1,0, 0,0,0,0, 0,1,0,0 }; + +static void miro_pinnacle_gpio(struct bttv *btv) +{ + int id,msp,gpio; + char *info; + + gpio_inout(0xffffff, 0); + gpio = gpio_read(); + id = ((gpio>>10) & 63) -1; + msp = bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx"); + if (id < 32) { + btv->tuner_type = miro_tunermap[id]; + if (0 == (gpio & 0x20)) { + btv->has_radio = 1; + if (!miro_fmtuner[id]) { + btv->has_matchbox = 1; + btv->mbox_we = (1<<6); + btv->mbox_most = (1<<7); + btv->mbox_clk = (1<<8); + btv->mbox_data = (1<<9); + btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9); + } + } else { + btv->has_radio = 0; + } + if (-1 != msp) { + if (btv->c.type == BTTV_BOARD_MIRO) + btv->c.type = BTTV_BOARD_MIROPRO; + if (btv->c.type == BTTV_BOARD_PINNACLE) + btv->c.type = BTTV_BOARD_PINNACLEPRO; + } + printk(KERN_INFO + "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", + btv->c.nr, id+1, btv->tuner_type, + !btv->has_radio ? "no" : + (btv->has_matchbox ? "matchbox" : "fmtuner"), + (-1 == msp) ? "no" : "yes"); + } else { + /* new cards with microtune tuner */ + id = 63 - id; + btv->has_radio = 0; + switch (id) { + case 1: + info = "PAL / mono"; + btv->tda9887_conf = TDA9887_INTERCARRIER; + break; + case 2: + info = "PAL+SECAM / stereo"; + btv->has_radio = 1; + btv->tda9887_conf = TDA9887_QSS; + break; + case 3: + info = "NTSC / stereo"; + btv->has_radio = 1; + btv->tda9887_conf = TDA9887_QSS; + break; + case 4: + info = "PAL+SECAM / mono"; + btv->tda9887_conf = TDA9887_QSS; + break; + case 5: + info = "NTSC / mono"; + btv->tda9887_conf = TDA9887_INTERCARRIER; + break; + case 6: + info = "NTSC / stereo"; + btv->tda9887_conf = TDA9887_INTERCARRIER; + break; + case 7: + info = "PAL / stereo"; + btv->tda9887_conf = TDA9887_INTERCARRIER; + break; + default: + info = "oops: unknown card"; + break; + } + if (-1 != msp) + btv->c.type = BTTV_BOARD_PINNACLEPRO; + printk(KERN_INFO + "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", + btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); + btv->tuner_type = TUNER_MT2032; + } +} + +/* GPIO21 L: Buffer aktiv, H: Buffer inaktiv */ +#define LM1882_SYNC_DRIVE 0x200000L + +static void init_ids_eagle(struct bttv *btv) +{ + gpio_inout(0xffffff,0xFFFF37); + gpio_write(0x200020); + + /* flash strobe inverter ?! */ + gpio_write(0x200024); + + /* switch sync drive off */ + gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); + + /* set BT848 muxel to 2 */ + btaor((2)<<5, ~(2<<5), BT848_IFORM); +} + +/* Muxsel helper for the IDS Eagle. + * the eagles does not use the standard muxsel-bits but + * has its own multiplexer */ +static void eagle_muxsel(struct bttv *btv, unsigned int input) +{ + gpio_bits(3, input & 3); + + /* composite */ + /* set chroma ADC to sleep */ + btor(BT848_ADC_C_SLEEP, BT848_ADC); + /* set to composite video */ + btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); + btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); + + /* switch sync drive off */ + gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); +} + +static void gvc1100_muxsel(struct bttv *btv, unsigned int input) +{ + static const int masks[] = {0x30, 0x01, 0x12, 0x23}; + gpio_write(masks[input%4]); +} + +/* LMLBT4x initialization - to allow access to GPIO bits for sensors input and + alarms output + + GPIObit | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + assignment | TI | O3|INx| O2| O1|IN4|IN3|IN2|IN1| | | + + IN - sensor inputs, INx - sensor inputs and TI XORed together + O1,O2,O3 - alarm outputs (relays) + + OUT ENABLE 1 1 0 . 1 1 0 0 . 0 0 0 0 = 0x6C0 + +*/ + +static void init_lmlbt4x(struct bttv *btv) +{ + printk(KERN_DEBUG "LMLBT4x init\n"); + btwrite(0x000000, BT848_GPIO_REG_INP); + gpio_inout(0xffffff, 0x0006C0); + gpio_write(0x000000); +} + +static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 8; + gpio_inout( 0xf, 0xf ); + gpio_bits( 0xf, inmux ); +} + +static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 4; + gpio_inout( 3<<9, 3<<9 ); + gpio_bits( 3<<9, inmux<<9 ); +} + +static void geovision_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 16; + gpio_inout(0xf, 0xf); + gpio_bits(0xf, inmux); +} + +/* ----------------------------------------------------------------------- */ + +static void bttv_reset_audio(struct bttv *btv) +{ + /* + * BT878A has a audio-reset register. + * 1. This register is an audio reset function but it is in + * function-0 (video capture) address space. + * 2. It is enough to do this once per power-up of the card. + * 3. There is a typo in the Conexant doc -- it is not at + * 0x5B, but at 0x058. (B is an odd-number, obviously a typo!). + * --//Shrikumar 030609 + */ + if (btv->id != 878) + return; + + if (bttv_debug) + printk("bttv%d: BT878A ARESET\n",btv->c.nr); + btwrite((1<<7), 0x058); + udelay(10); + btwrite( 0, 0x058); +} + +/* initialization part one -- before registering i2c bus */ +void __devinit bttv_init_card1(struct bttv *btv) +{ + switch (btv->c.type) { + case BTTV_BOARD_HAUPPAUGE: + case BTTV_BOARD_HAUPPAUGE878: + boot_msp34xx(btv,5); + break; + case BTTV_BOARD_VOODOOTV_200: + case BTTV_BOARD_VOODOOTV_FM: + boot_msp34xx(btv,20); + break; + case BTTV_BOARD_AVERMEDIA98: + boot_msp34xx(btv,11); + break; + case BTTV_BOARD_HAUPPAUGEPVR: + pvr_boot(btv); + break; + case BTTV_BOARD_TWINHAN_DST: + case BTTV_BOARD_AVDVBT_771: + case BTTV_BOARD_PINNACLESAT: + btv->use_i2c_hw = 1; + break; + case BTTV_BOARD_ADLINK_RTV24: + init_RTV24( btv ); + break; + + } + if (!bttv_tvcards[btv->c.type].has_dvb) + bttv_reset_audio(btv); +} + +/* initialization part two -- after registering i2c bus */ +void __devinit bttv_init_card2(struct bttv *btv) +{ + btv->tuner_type = UNSET; + + if (BTTV_BOARD_UNKNOWN == btv->c.type) { + bttv_readee(btv,eeprom_data,0xa0); + identify_by_eeprom(btv,eeprom_data); + } + + switch (btv->c.type) { + case BTTV_BOARD_MIRO: + case BTTV_BOARD_MIROPRO: + case BTTV_BOARD_PINNACLE: + case BTTV_BOARD_PINNACLEPRO: + /* miro/pinnacle */ + miro_pinnacle_gpio(btv); + break; + case BTTV_BOARD_FLYVIDEO_98: + case BTTV_BOARD_MAXI: + case BTTV_BOARD_LIFE_FLYKIT: + case BTTV_BOARD_FLYVIDEO: + case BTTV_BOARD_TYPHOON_TVIEW: + case BTTV_BOARD_CHRONOS_VS2: + case BTTV_BOARD_FLYVIDEO_98FM: + case BTTV_BOARD_FLYVIDEO2000: + case BTTV_BOARD_FLYVIDEO98EZ: + case BTTV_BOARD_CONFERENCETV: + case BTTV_BOARD_LIFETEC_9415: + flyvideo_gpio(btv); + break; + case BTTV_BOARD_HAUPPAUGE: + case BTTV_BOARD_HAUPPAUGE878: + case BTTV_BOARD_HAUPPAUGEPVR: + /* pick up some config infos from the eeprom */ + bttv_readee(btv,eeprom_data,0xa0); + hauppauge_eeprom(btv); + break; + case BTTV_BOARD_AVERMEDIA98: + case BTTV_BOARD_AVPHONE98: + bttv_readee(btv,eeprom_data,0xa0); + avermedia_eeprom(btv); + break; + case BTTV_BOARD_PXC200: + init_PXC200(btv); + break; + case BTTV_BOARD_PICOLO_TETRA_CHIP: + picolo_tetra_init(btv); + break; + case BTTV_BOARD_VHX: + btv->has_radio = 1; + btv->has_matchbox = 1; + btv->mbox_we = 0x20; + btv->mbox_most = 0; + btv->mbox_clk = 0x08; + btv->mbox_data = 0x10; + btv->mbox_mask = 0x38; + break; + case BTTV_BOARD_VOBIS_BOOSTAR: + case BTTV_BOARD_TERRATV: + terratec_active_radio_upgrade(btv); + break; + case BTTV_BOARD_MAGICTVIEW061: + if (btv->cardid == 0x3002144f) { + btv->has_radio=1; + printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr); + } + break; + case BTTV_BOARD_STB2: + if (btv->cardid == 0x3060121a) { + /* Fix up entry for 3DFX VoodooTV 100, + which is an OEM STB card variant. */ + btv->has_radio=0; + btv->tuner_type=TUNER_TEMIC_NTSC; + } + break; + case BTTV_BOARD_OSPREY1x0: + case BTTV_BOARD_OSPREY1x0_848: + case BTTV_BOARD_OSPREY101_848: + case BTTV_BOARD_OSPREY1x1: + case BTTV_BOARD_OSPREY1x1_SVID: + case BTTV_BOARD_OSPREY2xx: + case BTTV_BOARD_OSPREY2x0_SVID: + case BTTV_BOARD_OSPREY2x0: + case BTTV_BOARD_OSPREY440: + case BTTV_BOARD_OSPREY500: + case BTTV_BOARD_OSPREY540: + case BTTV_BOARD_OSPREY2000: + bttv_readee(btv,eeprom_data,0xa0); + osprey_eeprom(btv, eeprom_data); + break; + case BTTV_BOARD_IDS_EAGLE: + init_ids_eagle(btv); + break; + case BTTV_BOARD_MODTEC_205: + bttv_readee(btv,eeprom_data,0xa0); + modtec_eeprom(btv); + break; + case BTTV_BOARD_LMLBT4: + init_lmlbt4x(btv); + break; + case BTTV_BOARD_TIBET_CS16: + tibetCS16_init(btv); + break; + case BTTV_BOARD_KODICOM_4400R: + kodicom4400r_init(btv); + break; + case BTTV_BOARD_GEOVISION_GV800S: + gv800s_init(btv); + break; + } + + /* pll configuration */ + if (!(btv->id==848 && btv->revision==0x11)) { + /* defaults from card list */ + if (PLL_28 == bttv_tvcards[btv->c.type].pll) { + btv->pll.pll_ifreq=28636363; + btv->pll.pll_crystal=BT848_IFORM_XT0; + } + if (PLL_35 == bttv_tvcards[btv->c.type].pll) { + btv->pll.pll_ifreq=35468950; + btv->pll.pll_crystal=BT848_IFORM_XT1; + } + /* insmod options can override */ + switch (pll[btv->c.nr]) { + case 0: /* none */ + btv->pll.pll_crystal = 0; + btv->pll.pll_ifreq = 0; + btv->pll.pll_ofreq = 0; + break; + case 1: /* 28 MHz */ + case 28: + btv->pll.pll_ifreq = 28636363; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal = BT848_IFORM_XT0; + break; + case 2: /* 35 MHz */ + case 35: + btv->pll.pll_ifreq = 35468950; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal = BT848_IFORM_XT1; + break; + } + } + btv->pll.pll_current = -1; + + /* tuner configuration (from card list / autodetect / insmod option) */ + if (UNSET != bttv_tvcards[btv->c.type].tuner_type) + if (UNSET == btv->tuner_type) + btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; + if (UNSET != tuner[btv->c.nr]) + btv->tuner_type = tuner[btv->c.nr]; + + if (btv->tuner_type == TUNER_ABSENT) + printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr); + else if(btv->tuner_type == UNSET) + printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr); + else + printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr, + btv->tuner_type); + + if (autoload != UNSET) { + printk(KERN_WARNING "bttv%d: the autoload option is obsolete.\n", btv->c.nr); + printk(KERN_WARNING "bttv%d: use option msp3400, tda7432 or tvaudio to\n", btv->c.nr); + printk(KERN_WARNING "bttv%d: override which audio module should be used.\n", btv->c.nr); + } + + if (UNSET == btv->tuner_type) + btv->tuner_type = TUNER_ABSENT; + + btv->dig = bttv_tvcards[btv->c.type].has_dig_in ? + bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET; + btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ? + UNSET : bttv_tvcards[btv->c.type].svhs; + if (svhs[btv->c.nr] != UNSET) + btv->svhs = svhs[btv->c.nr]; + if (remote[btv->c.nr] != UNSET) + btv->has_remote = remote[btv->c.nr]; + + if (bttv_tvcards[btv->c.type].has_radio) + btv->has_radio = 1; + if (bttv_tvcards[btv->c.type].has_remote) + btv->has_remote = 1; + if (!bttv_tvcards[btv->c.type].no_gpioirq) + btv->gpioirq = 1; + if (bttv_tvcards[btv->c.type].volume_gpio) + btv->volume_gpio = bttv_tvcards[btv->c.type].volume_gpio; + if (bttv_tvcards[btv->c.type].audio_mode_gpio) + btv->audio_mode_gpio = bttv_tvcards[btv->c.type].audio_mode_gpio; + + if (btv->tuner_type == TUNER_ABSENT) + return; /* no tuner or related drivers to load */ + + if (btv->has_saa6588 || saa6588[btv->c.nr]) { + /* Probe for RDS receiver chip */ + static const unsigned short addrs[] = { + 0x20 >> 1, + 0x22 >> 1, + I2C_CLIENT_END + }; + struct v4l2_subdev *sd; + + sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "saa6588", 0, addrs); + btv->has_saa6588 = (sd != NULL); + } + + /* try to detect audio/fader chips */ + + /* First check if the user specified the audio chip via a module + option. */ + + switch (audiodev[btv->c.nr]) { + case -1: + return; /* do not load any audio module */ + + case 0: /* autodetect */ + break; + + case 1: { + /* The user specified that we should probe for msp3400 */ + static const unsigned short addrs[] = { + I2C_ADDR_MSP3400 >> 1, + I2C_ADDR_MSP3400_ALT >> 1, + I2C_CLIENT_END + }; + + btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "msp3400", 0, addrs); + if (btv->sd_msp34xx) + return; + goto no_audio; + } + + case 2: { + /* The user specified that we should probe for tda7432 */ + static const unsigned short addrs[] = { + I2C_ADDR_TDA7432 >> 1, + I2C_CLIENT_END + }; + + if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tda7432", 0, addrs)) + return; + goto no_audio; + } + + case 3: { + /* The user specified that we should probe for tvaudio */ + btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); + if (btv->sd_tvaudio) + return; + goto no_audio; + } + + default: + printk(KERN_WARNING "bttv%d: unknown audiodev value!\n", + btv->c.nr); + return; + } + + /* There were no overrides, so now we try to discover this through the + card definition */ + + /* probe for msp3400 first: this driver can detect whether or not + it really is a msp3400, so it will return NULL when the device + found is really something else (e.g. a tea6300). */ + if (!bttv_tvcards[btv->c.type].no_msp34xx) { + btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "msp3400", + 0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1)); + } else if (bttv_tvcards[btv->c.type].msp34xx_alt) { + btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "msp3400", + 0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1)); + } + + /* If we found a msp34xx, then we're done. */ + if (btv->sd_msp34xx) + return; + + /* it might also be a tda7432. */ + if (!bttv_tvcards[btv->c.type].no_tda7432) { + static const unsigned short addrs[] = { + I2C_ADDR_TDA7432 >> 1, + I2C_CLIENT_END + }; + + if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tda7432", 0, addrs)) + return; + } + + /* Now see if we can find one of the tvaudio devices. */ + btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); + if (btv->sd_tvaudio) + return; + +no_audio: + printk(KERN_WARNING "bttv%d: audio absent, no audio device found!\n", + btv->c.nr); +} + + +/* initialize the tuner */ +void __devinit bttv_init_tuner(struct bttv *btv) +{ + int addr = ADDR_UNSET; + + if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr) + addr = bttv_tvcards[btv->c.type].tuner_addr; + + if (btv->tuner_type != TUNER_ABSENT) { + struct tuner_setup tun_setup; + + /* Load tuner module before issuing tuner config call! */ + if (bttv_tvcards[btv->c.type].has_radio) + v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); + v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); + + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = btv->tuner_type; + tun_setup.addr = addr; + + if (bttv_tvcards[btv->c.type].has_radio) + tun_setup.mode_mask |= T_RADIO; + + bttv_call_all(btv, tuner, s_type_addr, &tun_setup); + } + + if (btv->tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &btv->tda9887_conf; + + bttv_call_all(btv, tuner, s_config, &tda9887_cfg); + } +} + +/* ----------------------------------------------------------------------- */ + +static void modtec_eeprom(struct bttv *btv) +{ + if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) { + btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I; + printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr,&eeprom_data[0x1e]); + } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) { + btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I; + printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr,&eeprom_data[0x1e]); + } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) { + btv->tuner_type=TUNER_PHILIPS_NTSC; + printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr,&eeprom_data[0x1e]); + } else { + printk("bttv%d: Modtec: Unknown TunerString: %s\n", + btv->c.nr,&eeprom_data[0x1e]); + } +} + +static void __devinit hauppauge_eeprom(struct bttv *btv) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); + btv->tuner_type = tv.tuner_type; + btv->has_radio = tv.has_radio; + + printk("bttv%d: Hauppauge eeprom indicates model#%d\n", + btv->c.nr, tv.model); + + /* + * Some of the 878 boards have duplicate PCI IDs. Switch the board + * type based on model #. + */ + if(tv.model == 64900) { + printk("bttv%d: Switching board type from %s to %s\n", + btv->c.nr, + bttv_tvcards[btv->c.type].name, + bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name); + btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB; + } +} + +static int terratec_active_radio_upgrade(struct bttv *btv) +{ + int freq; + + btv->has_radio = 1; + btv->has_matchbox = 1; + btv->mbox_we = 0x10; + btv->mbox_most = 0x20; + btv->mbox_clk = 0x08; + btv->mbox_data = 0x04; + btv->mbox_mask = 0x3c; + + btv->mbox_iow = 1 << 8; + btv->mbox_ior = 1 << 9; + btv->mbox_csel = 1 << 10; + + freq=88000/62.5; + tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */ + if (0x1ed8 == tea5757_read(btv)) { + printk("bttv%d: Terratec Active Radio Upgrade found.\n", + btv->c.nr); + btv->has_radio = 1; + btv->has_saa6588 = 1; + btv->has_matchbox = 1; + } else { + btv->has_radio = 0; + btv->has_matchbox = 0; + } + return 0; +} + + +/* ----------------------------------------------------------------------- */ + +/* + * minimal bootstrap for the WinTV/PVR -- upload altera firmware. + * + * The hcwamc.rbf firmware file is on the Hauppauge driver CD. Have + * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be + * unpacked with unzip). + */ +#define PVR_GPIO_DELAY 10 + +#define BTTV_ALT_DATA 0x000001 +#define BTTV_ALT_DCLK 0x100000 +#define BTTV_ALT_NCONFIG 0x800000 + +static int __devinit pvr_altera_load(struct bttv *btv, const u8 *micro, + u32 microlen) +{ + u32 n; + u8 bits; + int i; + + gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG); + gpio_write(0); + udelay(PVR_GPIO_DELAY); + + gpio_write(BTTV_ALT_NCONFIG); + udelay(PVR_GPIO_DELAY); + + for (n = 0; n < microlen; n++) { + bits = micro[n]; + for (i = 0 ; i < 8 ; i++) { + gpio_bits(BTTV_ALT_DCLK,0); + if (bits & 0x01) + gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); + else + gpio_bits(BTTV_ALT_DATA,0); + gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); + bits >>= 1; + } + } + gpio_bits(BTTV_ALT_DCLK,0); + udelay(PVR_GPIO_DELAY); + + /* begin Altera init loop (Not necessary,but doesn't hurt) */ + for (i = 0 ; i < 30 ; i++) { + gpio_bits(BTTV_ALT_DCLK,0); + gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); + } + gpio_bits(BTTV_ALT_DCLK,0); + return 0; +} + +static int __devinit pvr_boot(struct bttv *btv) +{ + const struct firmware *fw_entry; + int rc; + + rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev); + if (rc != 0) { + printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n", + btv->c.nr); + return rc; + } + rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size); + printk(KERN_INFO "bttv%d: altera firmware upload %s\n", + btv->c.nr, (rc < 0) ? "failed" : "ok"); + release_firmware(fw_entry); + return rc; +} + +/* ----------------------------------------------------------------------- */ +/* some osprey specific stuff */ + +static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) +{ + int i; + u32 serial = 0; + int cardid = -1; + + /* This code will nevery actually get called in this case.... */ + if (btv->c.type == BTTV_BOARD_UNKNOWN) { + /* this might be an antique... check for MMAC label in eeprom */ + if (!strncmp(ee, "MMAC", 4)) { + u8 checksum = 0; + for (i = 0; i < 21; i++) + checksum += ee[i]; + if (checksum != ee[21]) + return; + cardid = BTTV_BOARD_OSPREY1x0_848; + for (i = 12; i < 21; i++) + serial *= 10, serial += ee[i] - '0'; + } + } else { + unsigned short type; + + for (i = 4*16; i < 8*16; i += 16) { + u16 checksum = ip_compute_csum(ee + i, 16); + + if ((checksum&0xff) + (checksum>>8) == 0xff) + break; + } + if (i >= 8*16) + return; + ee += i; + + /* found a valid descriptor */ + type = get_unaligned_be16((__be16 *)(ee+4)); + + switch(type) { + /* 848 based */ + case 0x0004: + cardid = BTTV_BOARD_OSPREY1x0_848; + break; + case 0x0005: + cardid = BTTV_BOARD_OSPREY101_848; + break; + + /* 878 based */ + case 0x0012: + case 0x0013: + cardid = BTTV_BOARD_OSPREY1x0; + break; + case 0x0014: + case 0x0015: + cardid = BTTV_BOARD_OSPREY1x1; + break; + case 0x0016: + case 0x0017: + case 0x0020: + cardid = BTTV_BOARD_OSPREY1x1_SVID; + break; + case 0x0018: + case 0x0019: + case 0x001E: + case 0x001F: + cardid = BTTV_BOARD_OSPREY2xx; + break; + case 0x001A: + case 0x001B: + cardid = BTTV_BOARD_OSPREY2x0_SVID; + break; + case 0x0040: + cardid = BTTV_BOARD_OSPREY500; + break; + case 0x0050: + case 0x0056: + cardid = BTTV_BOARD_OSPREY540; + /* bttv_osprey_540_init(btv); */ + break; + case 0x0060: + case 0x0070: + case 0x00A0: + cardid = BTTV_BOARD_OSPREY2x0; + /* enable output on select control lines */ + gpio_inout(0xffffff,0x000303); + break; + case 0x00D8: + cardid = BTTV_BOARD_OSPREY440; + break; + default: + /* unknown...leave generic, but get serial # */ + printk(KERN_INFO "bttv%d: " + "osprey eeprom: unknown card type 0x%04x\n", + btv->c.nr, type); + break; + } + serial = get_unaligned_be32((__be32 *)(ee+6)); + } + + printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n", + btv->c.nr, cardid, + cardid>0 ? bttv_tvcards[cardid].name : "Unknown", serial); + + if (cardid<0 || btv->c.type == cardid) + return; + + /* card type isn't set correctly */ + if (card[btv->c.nr] < bttv_num_tvcards) { + printk(KERN_WARNING "bttv%d: osprey eeprom: " + "Not overriding user specified card type\n", btv->c.nr); + } else { + printk(KERN_INFO "bttv%d: osprey eeprom: " + "Changing card type from %d to %d\n", btv->c.nr, + btv->c.type, cardid); + btv->c.type = cardid; + } +} + +/* ----------------------------------------------------------------------- */ +/* AVermedia specific stuff, from bktr_card.c */ + +static int tuner_0_table[] = { + TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL /* PAL-BG*/, + TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL /* PAL-I*/, + TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, + TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, + TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL, + TUNER_PHILIPS_FM1216ME_MK3 }; + +static int tuner_1_table[] = { + TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, + TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, + TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, + TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */ + TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL}; + +static void __devinit avermedia_eeprom(struct bttv *btv) +{ + int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0; + + tuner_make = (eeprom_data[0x41] & 0x7); + tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3; + tuner_format = (eeprom_data[0x42] & 0xf0) >> 4; + btv->has_remote = (eeprom_data[0x42] & 0x01); + + if (tuner_make == 0 || tuner_make == 2) + if (tuner_format <= 0x0a) + tuner_type = tuner_0_table[tuner_format]; + if (tuner_make == 1) + if (tuner_format <= 9) + tuner_type = tuner_1_table[tuner_format]; + + if (tuner_make == 4) + if (tuner_format == 0x09) + tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ + + printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=", + btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]); + if (tuner_type) { + btv->tuner_type = tuner_type; + printk(KERN_CONT "%d", tuner_type); + } else + printk(KERN_CONT "Unknown type"); + printk(KERN_CONT " radio:%s remote control:%s\n", + tuner_tv_fm ? "yes" : "no", + btv->has_remote ? "yes" : "no"); +} + +/* + * For Voodoo TV/FM and Voodoo 200. These cards' tuners use a TDA9880 + * analog demod, which is not I2C controlled like the newer and more common + * TDA9887 series. Instead is has two tri-state input pins, S0 and S1, + * that control the IF for the video and audio. Apparently, bttv GPIO + * 0x10000 is connected to S0. S0 low selects a 38.9 MHz VIF for B/G/D/K/I + * (i.e., PAL) while high selects 45.75 MHz for M/N (i.e., NTSC). + */ +u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits) +{ + + if (btv->audio == TVAUDIO_INPUT_TUNER) { + if (bttv_tvnorms[btv->tvnorm].v4l2_id & V4L2_STD_MN) + gpiobits |= 0x10000; + else + gpiobits &= ~0x10000; + } + + gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpiobits); + return gpiobits; +} + + +/* + * reset/enable the MSP on some Hauppauge cards + * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! + * + * Hauppauge: pin 5 + * Voodoo: pin 20 + */ +static void __devinit boot_msp34xx(struct bttv *btv, int pin) +{ + int mask = (1 << pin); + + gpio_inout(mask,mask); + gpio_bits(mask,0); + mdelay(2); + udelay(500); + gpio_bits(mask,mask); + + if (bttv_gpio) + bttv_gpio_tracking(btv,"msp34xx"); + if (bttv_verbose) + printk(KERN_INFO "bttv%d: Hauppauge/Voodoo msp34xx: reset line " + "init [%d]\n", btv->c.nr, pin); +} + +/* ----------------------------------------------------------------------- */ +/* Imagenation L-Model PXC200 Framegrabber */ +/* This is basically the same procedure as + * used by Alessandro Rubini in his pxc200 + * driver, but using BTTV functions */ + +static void __devinit init_PXC200(struct bttv *btv) +{ + static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x00 }; + unsigned int i; + int tmp; + u32 val; + + /* Initialise GPIO-connevted stuff */ + gpio_inout(0xffffff, (1<<13)); + gpio_write(0); + udelay(3); + gpio_write(1<<13); + /* GPIO inputs are pulled up, so no need to drive + * reset pin any longer */ + gpio_bits(0xffffff, 0); + if (bttv_gpio) + bttv_gpio_tracking(btv,"pxc200"); + + /* we could/should try and reset/control the AD pots? but + right now we simply turned off the crushing. Without + this the AGC drifts drifts + remember the EN is reverse logic --> + setting BT848_ADC_AGC_EN disable the AGC + tboult@eecs.lehigh.edu + */ + + btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); + + /* Initialise MAX517 DAC */ + printk(KERN_INFO "Setting DAC reference voltage level ...\n"); + bttv_I2CWrite(btv,0x5E,0,0x80,1); + + /* Initialise 12C508 PIC */ + /* The I2CWrite and I2CRead commmands are actually to the + * same chips - but the R/W bit is included in the address + * argument so the numbers are different */ + + + printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); + + /* First of all, enable the clock line. This is used in the PXC200-F */ + val = btread(BT848_GPIO_DMA_CTL); + val |= BT848_GPIO_DMA_CTL_GPCLKMODE; + btwrite(val, BT848_GPIO_DMA_CTL); + + /* Then, push to 0 the reset pin long enough to reset the * + * device same as above for the reset line, but not the same + * value sent to the GPIO-connected stuff + * which one is the good one? */ + gpio_inout(0xffffff,(1<<2)); + gpio_write(0); + udelay(10); + gpio_write(1<<2); + + for (i = 0; i < ARRAY_SIZE(vals); i++) { + tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1); + if (tmp != -1) { + printk(KERN_INFO + "I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n", + vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL)); + } + } + + printk(KERN_INFO "PXC200 Initialised.\n"); +} + + + +/* ----------------------------------------------------------------------- */ +/* + * The Adlink RTV-24 (aka Angelo) has some special initialisation to unlock + * it. This apparently involves the following procedure for each 878 chip: + * + * 1) write 0x00C3FEFF to the GPIO_OUT_EN register + * + * 2) write to GPIO_DATA + * - 0x0E + * - sleep 1ms + * - 0x10 + 0x0E + * - sleep 10ms + * - 0x0E + * read from GPIO_DATA into buf (uint_32) + * - if ( data>>18 & 0x01 != 0) || ( buf>>19 & 0x01 != 1 ) + * error. ERROR_CPLD_Check_Failed stop. + * + * 3) write to GPIO_DATA + * - write 0x4400 + 0x0E + * - sleep 10ms + * - write 0x4410 + 0x0E + * - sleep 1ms + * - write 0x0E + * read from GPIO_DATA into buf (uint_32) + * - if ( buf>>18 & 0x01 ) || ( buf>>19 & 0x01 != 0 ) + * error. ERROR_CPLD_Check_Failed. + */ +/* ----------------------------------------------------------------------- */ +static void +init_RTV24 (struct bttv *btv) +{ + uint32_t dataRead = 0; + long watchdog_value = 0x0E; + + printk (KERN_INFO + "bttv%d: Adlink RTV-24 initialisation in progress ...\n", + btv->c.nr); + + btwrite (0x00c3feff, BT848_GPIO_OUT_EN); + + btwrite (0 + watchdog_value, BT848_GPIO_DATA); + msleep (1); + btwrite (0x10 + watchdog_value, BT848_GPIO_DATA); + msleep (10); + btwrite (0 + watchdog_value, BT848_GPIO_DATA); + + dataRead = btread (BT848_GPIO_DATA); + + if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) { + printk (KERN_INFO + "bttv%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n", + btv->c.nr, dataRead); + } + + btwrite (0x4400 + watchdog_value, BT848_GPIO_DATA); + msleep (10); + btwrite (0x4410 + watchdog_value, BT848_GPIO_DATA); + msleep (1); + btwrite (watchdog_value, BT848_GPIO_DATA); + msleep (1); + dataRead = btread (BT848_GPIO_DATA); + + if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) { + printk (KERN_INFO + "bttv%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n", + btv->c.nr, dataRead); + + return; + } + + printk (KERN_INFO + "bttv%d: Adlink RTV-24 initialisation complete.\n", btv->c.nr); +} + + + +/* ----------------------------------------------------------------------- */ +/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */ +/* + * Copyright (c) 1999 Csaba Halasz + * This code is placed under the terms of the GNU General Public License + * + * Brutally hacked by Dan Sheridan djs52 8/3/00 + */ + +static void bus_low(struct bttv *btv, int bit) +{ + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + } + + gpio_bits(bit,0); + udelay(5); + + if (btv->mbox_ior) { + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); + udelay(5); + } +} + +static void bus_high(struct bttv *btv, int bit) +{ + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + } + + gpio_bits(bit,bit); + udelay(5); + + if (btv->mbox_ior) { + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); + udelay(5); + } +} + +static int bus_in(struct bttv *btv, int bit) +{ + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); + udelay(5); + } + return gpio_read() & (bit); +} + +/* TEA5757 register bits */ +#define TEA_FREQ 0:14 +#define TEA_BUFFER 15:15 + +#define TEA_SIGNAL_STRENGTH 16:17 + +#define TEA_PORT1 18:18 +#define TEA_PORT0 19:19 + +#define TEA_BAND 20:21 +#define TEA_BAND_FM 0 +#define TEA_BAND_MW 1 +#define TEA_BAND_LW 2 +#define TEA_BAND_SW 3 + +#define TEA_MONO 22:22 +#define TEA_ALLOW_STEREO 0 +#define TEA_FORCE_MONO 1 + +#define TEA_SEARCH_DIRECTION 23:23 +#define TEA_SEARCH_DOWN 0 +#define TEA_SEARCH_UP 1 + +#define TEA_STATUS 24:24 +#define TEA_STATUS_TUNED 0 +#define TEA_STATUS_SEARCHING 1 + +/* Low-level stuff */ +static int tea5757_read(struct bttv *btv) +{ + unsigned long timeout; + int value = 0; + int i; + + /* better safe than sorry */ + gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we); + + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + } + + if (bttv_gpio) + bttv_gpio_tracking(btv,"tea5757 read"); + + bus_low(btv,btv->mbox_we); + bus_low(btv,btv->mbox_clk); + + udelay(10); + timeout= jiffies + msecs_to_jiffies(1000); + + /* wait for DATA line to go low; error if it doesn't */ + while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) + schedule(); + if (bus_in(btv,btv->mbox_data)) { + printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->c.nr); + return -1; + } + + dprintk("bttv%d: tea5757:",btv->c.nr); + for (i = 0; i < 24; i++) { + udelay(5); + bus_high(btv,btv->mbox_clk); + udelay(5); + dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-'); + bus_low(btv,btv->mbox_clk); + value <<= 1; + value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */ + dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M'); + } + dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->c.nr, value); + return value; +} + +static int tea5757_write(struct bttv *btv, int value) +{ + int i; + int reg = value; + + gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data); + + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + } + if (bttv_gpio) + bttv_gpio_tracking(btv,"tea5757 write"); + + dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); + bus_low(btv,btv->mbox_clk); + bus_high(btv,btv->mbox_we); + for (i = 0; i < 25; i++) { + if (reg & 0x1000000) + bus_high(btv,btv->mbox_data); + else + bus_low(btv,btv->mbox_data); + reg <<= 1; + bus_high(btv,btv->mbox_clk); + udelay(10); + bus_low(btv,btv->mbox_clk); + udelay(10); + } + bus_low(btv,btv->mbox_we); /* unmute !!! */ + return 0; +} + +void tea5757_set_freq(struct bttv *btv, unsigned short freq) +{ + dprintk("tea5757_set_freq %d\n",freq); + tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ +} + +/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] + * + * This is needed because rv605 don't use a normal multiplex, but a crosspoint + * switch instead (CD22M3494E). This IC can have multiple active connections + * between Xn (input) and Yn (output) pins. We need to clear any existing + * connection prior to establish a new one, pulsing the STROBE pin. + * + * The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin. + * GPIO pins are wired as: + * GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroller) + * GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroller) + * GPIO[7] - DATA (xpoint) - P1[7] (microcontroller) + * GPIO[8] - - P3[5] (microcontroller) + * GPIO[9] - RESET (xpoint) - P3[6] (microcontroller) + * GPIO[10] - STROBE (xpoint) - P3[7] (microcontroller) + * GPINTR - - P3[4] (microcontroller) + * + * The microcontroller is a 80C32 like. It should be possible to change xpoint + * configuration either directly (as we are doing) or using the microcontroller + * which is also wired to I2C interface. I have no further info on the + * microcontroller features, one would need to disassembly the firmware. + * note: the vendor refused to give any information on this product, all + * that stuff was found using a multimeter! :) + */ +static void rv605_muxsel(struct bttv *btv, unsigned int input) +{ + static const u8 muxgpio[] = { 0x3, 0x1, 0x2, 0x4, 0xf, 0x7, 0xe, 0x0, + 0xd, 0xb, 0xc, 0x6, 0x9, 0x5, 0x8, 0xa }; + + gpio_bits(0x07f, muxgpio[input]); + + /* reset all conections */ + gpio_bits(0x200,0x200); + mdelay(1); + gpio_bits(0x200,0x000); + mdelay(1); + + /* create a new connection */ + gpio_bits(0x480,0x480); + mdelay(1); + gpio_bits(0x480,0x080); + mdelay(1); +} + +/* Tibet Systems 'Progress DVR' CS16 muxsel helper [Chris Fanning] + * + * The CS16 (available on eBay cheap) is a PCI board with four Fusion + * 878A chips, a PCI bridge, an Atmel microcontroller, four sync separator + * chips, ten eight input analog multiplexors, a not chip and a few + * other components. + * + * 16 inputs on a secondary bracket are provided and can be selected + * from each of the four capture chips. Two of the eight input + * multiplexors are used to select from any of the 16 input signals. + * + * Unsupported hardware capabilities: + * . A video output monitor on the secondary bracket can be selected from + * one of the 878A chips. + * . Another passthrough but I haven't spent any time investigating it. + * . Digital I/O (logic level connected to GPIO) is available from an + * onboard header. + * + * The on chip input mux should always be set to 2. + * GPIO[16:19] - Video input selection + * GPIO[0:3] - Video output monitor select (only available from one 878A) + * GPIO[?:?] - Digital I/O. + * + * There is an ATMEL microcontroller with an 8031 core on board. I have not + * determined what function (if any) it provides. With the microcontroller + * and sync separator chips a guess is that it might have to do with video + * switching and maybe some digital I/O. + */ +static void tibetCS16_muxsel(struct bttv *btv, unsigned int input) +{ + /* video mux */ + gpio_bits(0x0f0000, input << 16); +} + +static void tibetCS16_init(struct bttv *btv) +{ + /* enable gpio bits, mask obtained via btSpy */ + gpio_inout(0xffffff, 0x0f7fff); + gpio_write(0x0f7fff); +} + +/* + * The following routines for the Kodicom-4400r get a little mind-twisting. + * There is a "master" controller and three "slave" controllers, together + * an analog switch which connects any of 16 cameras to any of the BT87A's. + * The analog switch is controlled by the "master", but the detection order + * of the four BT878A chips is in an order which I just don't understand. + * The "master" is actually the second controller to be detected. The + * logic on the board uses logical numbers for the 4 controllers, but + * those numbers are different from the detection sequence. When working + * with the analog switch, we need to "map" from the detection sequence + * over to the board's logical controller number. This mapping sequence + * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical + * unit 3, the second (which is the master) is logical unit 0, etc. + * We need to maintain the status of the analog switch (which of the 16 + * cameras is connected to which of the 4 controllers). Rather than + * add to the bttv structure for this, we use the data reserved for + * the mbox (unused for this card type). + */ + +/* + * First a routine to set the analog switch, which controls which camera + * is routed to which controller. The switch comprises an X-address + * (gpio bits 0-3, representing the camera, ranging from 0-15), and a + * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3). + * A data value (gpio bit 7) of '1' enables the switch, and '0' disables + * the switch. A STROBE bit (gpio bit 8) latches the data value into the + * specified address. The idea is to set the address and data, then bring + * STROBE high, and finally bring STROBE back to low. + */ +static void kodicom4400r_write(struct bttv *btv, + unsigned char xaddr, + unsigned char yaddr, + unsigned char data) { + unsigned int udata; + + udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf); + gpio_bits(0x1ff, udata); /* write ADDR and DAT */ + gpio_bits(0x1ff, udata | (1 << 8)); /* strobe high */ + gpio_bits(0x1ff, udata); /* strobe low */ +} + +/* + * Next the mux select. Both the "master" and "slave" 'cards' (controllers) + * use this routine. The routine finds the "master" for the card, maps + * the controller number from the detected position over to the logical + * number, writes the appropriate data to the analog switch, and housekeeps + * the local copy of the switch information. The parameter 'input' is the + * requested camera number (0 - 15). + */ +static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input) +{ + char *sw_status; + int xaddr, yaddr; + struct bttv *mctlr; + static unsigned char map[4] = {3, 0, 2, 1}; + + mctlr = master[btv->c.nr]; + if (mctlr == NULL) { /* ignore if master not yet detected */ + return; + } + yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */ + yaddr = map[yaddr]; + sw_status = (char *)(&mctlr->mbox_we); + xaddr = input & 0xf; + /* Check if the controller/camera pair has changed, else ignore */ + if (sw_status[yaddr] != xaddr) + { + /* "open" the old switch, "close" the new one, save the new */ + kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0); + sw_status[yaddr] = xaddr; + kodicom4400r_write(mctlr, xaddr, yaddr, 1); + } +} + +/* + * During initialisation, we need to reset the analog switch. We + * also preset the switch to map the 4 connectors on the card to the + * *user's* (see above description of kodicom4400r_muxsel) channels + * 0 through 3 + */ +static void kodicom4400r_init(struct bttv *btv) +{ + char *sw_status = (char *)(&btv->mbox_we); + int ix; + + gpio_inout(0x0003ff, 0x0003ff); + gpio_write(1 << 9); /* reset MUX */ + gpio_write(0); + /* Preset camera 0 to the 4 controllers */ + for (ix = 0; ix < 4; ix++) { + sw_status[ix] = ix; + kodicom4400r_write(btv, ix, ix, 1); + } + /* + * Since this is the "master", we need to set up the + * other three controller chips' pointers to this structure + * for later use in the muxsel routine. + */ + if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3)) + return; + master[btv->c.nr-1] = btv; + master[btv->c.nr] = btv; + master[btv->c.nr+1] = btv; + master[btv->c.nr+2] = btv; +} + +/* The Grandtec X-Guard framegrabber card uses two Dual 4-channel + * video multiplexers to provide up to 16 video inputs. These + * multiplexers are controlled by the lower 8 GPIO pins of the + * bt878. The multiplexers probably Pericom PI5V331Q or similar. + + * xxx0 is pin xxx of multiplexer U5, + * yyy1 is pin yyy of multiplexer U2 + */ +#define ENA0 0x01 +#define ENB0 0x02 +#define ENA1 0x04 +#define ENB1 0x08 + +#define IN10 0x10 +#define IN00 0x20 +#define IN11 0x40 +#define IN01 0x80 + +static void xguard_muxsel(struct bttv *btv, unsigned int input) +{ + static const int masks[] = { + ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10, + ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10, + ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11, + ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11, + }; + gpio_write(masks[input%16]); +} +static void picolo_tetra_init(struct bttv *btv) +{ + /*This is the video input redirection fonctionality : I DID NOT USED IT. */ + btwrite (0x08<<16,BT848_GPIO_DATA);/*GPIO[19] [==> 4053 B+C] set to 1 */ + btwrite (0x04<<16,BT848_GPIO_DATA);/*GPIO[18] [==> 4053 A] set to 1*/ +} +static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) +{ + + dprintk (KERN_DEBUG "bttv%d : picolo_tetra_muxsel => input = %d\n",btv->c.nr,input); + /*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/ + /*GPIO[20]&GPIO[21] used to choose the right input*/ + btwrite (input<<20,BT848_GPIO_DATA); + +} + +/* + * ivc120_muxsel [Added by Alan Garfield ] + * + * The IVC120G security card has 4 i2c controlled TDA8540 matrix + * swichers to provide 16 channels to MUX0. The TDA8540's have + * 4 independent outputs and as such the IVC120G also has the + * optional "Monitor Out" bus. This allows the card to be looking + * at one input while the monitor is looking at another. + * + * Since I've couldn't be bothered figuring out how to add an + * independent muxsel for the monitor bus, I've just set it to + * whatever the card is looking at. + * + * OUT0 of the TDA8540's is connected to MUX0 (0x03) + * OUT1 of the TDA8540's is connected to "Monitor Out" (0x0C) + * + * TDA8540_ALT3 IN0-3 = Channel 13 - 16 (0x03) + * TDA8540_ALT4 IN0-3 = Channel 1 - 4 (0x03) + * TDA8540_ALT5 IN0-3 = Channel 5 - 8 (0x03) + * TDA8540_ALT6 IN0-3 = Channel 9 - 12 (0x03) + * + */ + +/* All 7 possible sub-ids for the TDA8540 Matrix Switcher */ +#define I2C_TDA8540 0x90 +#define I2C_TDA8540_ALT1 0x92 +#define I2C_TDA8540_ALT2 0x94 +#define I2C_TDA8540_ALT3 0x96 +#define I2C_TDA8540_ALT4 0x98 +#define I2C_TDA8540_ALT5 0x9a +#define I2C_TDA8540_ALT6 0x9c + +static void ivc120_muxsel(struct bttv *btv, unsigned int input) +{ + /* Simple maths */ + int key = input % 4; + int matrix = input / 4; + + dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", + btv->c.nr, input, matrix, key); + + /* Handles the input selection on the TDA8540's */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00, + ((matrix == 3) ? (key | key << 2) : 0x00), 1); + bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00, + ((matrix == 0) ? (key | key << 2) : 0x00), 1); + bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x00, + ((matrix == 1) ? (key | key << 2) : 0x00), 1); + bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00, + ((matrix == 2) ? (key | key << 2) : 0x00), 1); + + /* Handles the output enables on the TDA8540's */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02, + ((matrix == 3) ? 0x03 : 0x00), 1); /* 13 - 16 */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02, + ((matrix == 0) ? 0x03 : 0x00), 1); /* 1-4 */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02, + ((matrix == 1) ? 0x03 : 0x00), 1); /* 5-8 */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02, + ((matrix == 2) ? 0x03 : 0x00), 1); /* 9-12 */ + + /* 878's MUX0 is already selected for input via muxsel values */ +} + + +/* PXC200 muxsel helper + * luke@syseng.anu.edu.au + * another transplant + * from Alessandro Rubini (rubini@linux.it) + * + * There are 4 kinds of cards: + * PXC200L which is bt848 + * PXC200F which is bt848 with PIC controlling mux + * PXC200AL which is bt878 + * PXC200AF which is bt878 with PIC controlling mux + */ +#define PX_CFG_PXC200F 0x01 +#define PX_FLAG_PXC200A 0x00001000 /* a pxc200A is bt-878 based */ +#define PX_I2C_PIC 0x0f +#define PX_PXC200A_CARDID 0x200a1295 +#define PX_I2C_CMD_CFG 0x00 + +static void PXC200_muxsel(struct bttv *btv, unsigned int input) +{ + int rc; + long mux; + int bitmask; + unsigned char buf[2]; + + /* Read PIC config to determine if this is a PXC200F */ + /* PX_I2C_CMD_CFG*/ + buf[0]=0; + buf[1]=0; + rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1); + if (rc) { + printk(KERN_DEBUG "bttv%d: PXC200_muxsel: pic cfg write failed:%d\n", btv->c.nr,rc); + /* not PXC ? do nothing */ + return; + } + + rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL); + if (!(rc & PX_CFG_PXC200F)) { + printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc); + return; + } + + + /* The multiplexer in the 200F is handled by the GPIO port */ + /* get correct mapping between inputs */ + /* mux = bttv_tvcards[btv->type].muxsel[input] & 3; */ + /* ** not needed!? */ + mux = input; + + /* make sure output pins are enabled */ + /* bitmask=0x30f; */ + bitmask=0x302; + /* check whether we have a PXC200A */ + if (btv->cardid == PX_PXC200A_CARDID) { + bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */ + bitmask |= 7<<4; /* the DAC */ + } + btwrite(bitmask, BT848_GPIO_OUT_EN); + + bitmask = btread(BT848_GPIO_DATA); + if (btv->cardid == PX_PXC200A_CARDID) + bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7); + else /* older device */ + bitmask = (bitmask & ~0x300) | ((mux & 3) << 8); + btwrite(bitmask,BT848_GPIO_DATA); + + /* + * Was "to be safe, set the bt848 to input 0" + * Actually, since it's ok at load time, better not messing + * with these bits (on PXC200AF you need to set mux 2 here) + * + * needed because bttv-driver sets mux before calling this function + */ + if (btv->cardid == PX_PXC200A_CARDID) + btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM); + else /* older device */ + btand(~BT848_IFORM_MUXSEL,BT848_IFORM); + + printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux); +} + +static void phytec_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int mux = input % 4; + + if (input == btv->svhs) + mux = 0; + + gpio_bits(0x3, mux); +} + +/* + * GeoVision GV-800(S) functions + * Bruno Christo +*/ + +/* This is a function to control the analog switch, which determines which + * camera is routed to which controller. The switch comprises an X-address + * (gpio bits 0-3, representing the camera, ranging from 0-15), and a + * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3). + * A data value (gpio bit 18) of '1' enables the switch, and '0' disables + * the switch. A STROBE bit (gpio bit 17) latches the data value into the + * specified address. There is also a chip select (gpio bit 16). + * The idea is to set the address and chip select together, bring + * STROBE high, write the data, and finally bring STROBE back to low. + */ +static void gv800s_write(struct bttv *btv, + unsigned char xaddr, + unsigned char yaddr, + unsigned char data) { + /* On the "master" 878A: + * GPIO bits 0-9 are used for the analog switch: + * 00 - 03: camera selector + * 04 - 06: 878A (controller) selector + * 16: cselect + * 17: strobe + * 18: data (1->on, 0->off) + * 19: reset + */ + const u32 ADDRESS = ((xaddr&0xf) | (yaddr&3)<<4); + const u32 CSELECT = 1<<16; + const u32 STROBE = 1<<17; + const u32 DATA = data<<18; + + gpio_bits(0x1007f, ADDRESS | CSELECT); /* write ADDRESS and CSELECT */ + gpio_bits(0x20000, STROBE); /* STROBE high */ + gpio_bits(0x40000, DATA); /* write DATA */ + gpio_bits(0x20000, ~STROBE); /* STROBE low */ +} + +/* + * GeoVision GV-800(S) muxsel + * + * Each of the 4 cards (controllers) use this function. + * The controller using this function selects the input through the GPIO pins + * of the "master" card. A pointer to this card is stored in master[btv->c.nr]. + * + * The parameter 'input' is the requested camera number (0-4) on the controller. + * The map array has the address of each input. Note that the addresses in the + * array are in the sequence the original GeoVision driver uses, that is, set + * every controller to input 0, then to input 1, 2, 3, repeat. This means that + * the physical "camera 1" connector corresponds to controller 0 input 0, + * "camera 2" corresponds to controller 1 input 0, and so on. + * + * After getting the input address, the function then writes the appropriate + * data to the analog switch, and housekeeps the local copy of the switch + * information. + */ +static void gv800s_muxsel(struct bttv *btv, unsigned int input) +{ + struct bttv *mctlr; + char *sw_status; + int xaddr, yaddr; + static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 }, + { 0x1, 0x5, 0xb, 0x7 }, + { 0x2, 0x8, 0xc, 0xe }, + { 0x3, 0x9, 0xd, 0xf } }; + input = input%4; + mctlr = master[btv->c.nr]; + if (mctlr == NULL) { + /* do nothing until the "master" is detected */ + return; + } + yaddr = (btv->c.nr - mctlr->c.nr) & 3; + sw_status = (char *)(&mctlr->mbox_we); + xaddr = map[yaddr][input] & 0xf; + + /* Check if the controller/camera pair has changed, ignore otherwise */ + if (sw_status[yaddr] != xaddr) { + /* disable the old switch, enable the new one and save status */ + gv800s_write(mctlr, sw_status[yaddr], yaddr, 0); + sw_status[yaddr] = xaddr; + gv800s_write(mctlr, xaddr, yaddr, 1); + } +} + +/* GeoVision GV-800(S) "master" chip init */ +static void gv800s_init(struct bttv *btv) +{ + char *sw_status = (char *)(&btv->mbox_we); + int ix; + + gpio_inout(0xf107f, 0xf107f); + gpio_write(1<<19); /* reset the analog MUX */ + gpio_write(0); + + /* Preset camera 0 to the 4 controllers */ + for (ix = 0; ix < 4; ix++) { + sw_status[ix] = ix; + gv800s_write(btv, ix, ix, 1); + } + + /* Inputs on the "master" controller need this brightness fix */ + bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1); + + if (btv->c.nr > BTTV_MAX-4) + return; + /* + * Store the "master" controller pointer in the master + * array for later use in the muxsel function. + */ + master[btv->c.nr] = btv; + master[btv->c.nr+1] = btv; + master[btv->c.nr+2] = btv; + master[btv->c.nr+3] = btv; +} + +/* ----------------------------------------------------------------------- */ +/* motherboard chipset specific stuff */ + +void __init bttv_check_chipset(void) +{ + int pcipci_fail = 0; + struct pci_dev *dev = NULL; + + if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) /* should check if target is AGP */ + pcipci_fail = 1; + if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF)) + triton1 = 1; + if (pci_pci_problems & PCIPCI_VSFX) + vsfx = 1; +#ifdef PCIPCI_ALIMAGIK + if (pci_pci_problems & PCIPCI_ALIMAGIK) + latency = 0x0A; +#endif + + + /* print warnings about any quirks found */ + if (triton1) + printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n"); + if (vsfx) + printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n"); + if (pcipci_fail) { + printk(KERN_INFO "bttv: bttv and your chipset may not work " + "together.\n"); + if (!no_overlay) { + printk(KERN_INFO "bttv: overlay will be disabled.\n"); + no_overlay = 1; + } else { + printk(KERN_INFO "bttv: overlay forced. Use this " + "option at your own risk.\n"); + } + } + if (UNSET != latency) + printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency); + while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82441, dev))) { + unsigned char b; + pci_read_config_byte(dev, 0x53, &b); + if (bttv_debug) + printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, " + "bufcon=0x%02x\n",b); + } +} + +int __devinit bttv_handle_chipset(struct bttv *btv) +{ + unsigned char command; + + if (!triton1 && !vsfx && UNSET == latency) + return 0; + + if (bttv_verbose) { + if (triton1) + printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->c.nr); + if (vsfx && btv->id >= 878) + printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->c.nr); + if (UNSET != latency) + printk(KERN_INFO "bttv%d: setting pci timer to %d\n", + btv->c.nr,latency); + } + + if (btv->id < 878) { + /* bt848 (mis)uses a bit in the irq mask for etbf */ + if (triton1) + btv->triton1 = BT848_INT_ETBF; + } else { + /* bt878 has a bit in the pci config space for it */ + pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command); + if (triton1) + command |= BT878_EN_TBFX; + if (vsfx) + command |= BT878_EN_VSFX; + pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command); + } + if (UNSET != latency) + pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency); + return 0; +} + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-driver.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-driver.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,4632 @@ +/* + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler + & Marcus Metzler + (c) 1999-2002 Gerd Knorr + + some v4l2 code lines are taken from Justin's bttv2 driver which is + (c) 2000 Justin Schoeman + + V4L1 removal from: + (c) 2005-2006 Nickolay V. Shmyrev + + Fixes to be fully V4L2 compliant by + (c) 2006 Mauro Carvalho Chehab + + Cropping and overscan support + Copyright (C) 2005, 2006 Michael H. Schimek + Sponsored by OPQ Systems AB + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bttvp.h" +#include +#include +#include +#include + +#include + +#include +#include + +#include + + +unsigned int bttv_num; /* number of Bt848s in use */ +struct bttv *bttvs[BTTV_MAX]; + +unsigned int bttv_debug; +unsigned int bttv_verbose = 1; +unsigned int bttv_gpio; + +/* config variables */ +#ifdef __BIG_ENDIAN +static unsigned int bigendian=1; +#else +static unsigned int bigendian; +#endif +static unsigned int radio[BTTV_MAX]; +static unsigned int irq_debug; +static unsigned int gbuffers = 8; +static unsigned int gbufsize = 0x208000; +static unsigned int reset_crop = 1; + +static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; +static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; +static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; +static int debug_latency; +static int disable_ir; + +static unsigned int fdsr; + +/* options */ +static unsigned int combfilter; +static unsigned int lumafilter; +static unsigned int automute = 1; +static unsigned int chroma_agc; +static unsigned int adc_crush = 1; +static unsigned int whitecrush_upper = 0xCF; +static unsigned int whitecrush_lower = 0x7F; +static unsigned int vcr_hack; +static unsigned int irq_iswitch; +static unsigned int uv_ratio = 50; +static unsigned int full_luma_range; +static unsigned int coring; + +/* API features (turn on/off stuff for testing) */ +static unsigned int v4l2 = 1; + +/* insmod args */ +module_param(bttv_verbose, int, 0644); +module_param(bttv_gpio, int, 0644); +module_param(bttv_debug, int, 0644); +module_param(irq_debug, int, 0644); +module_param(debug_latency, int, 0644); +module_param(disable_ir, int, 0444); + +module_param(fdsr, int, 0444); +module_param(gbuffers, int, 0444); +module_param(gbufsize, int, 0444); +module_param(reset_crop, int, 0444); + +module_param(v4l2, int, 0644); +module_param(bigendian, int, 0644); +module_param(irq_iswitch, int, 0644); +module_param(combfilter, int, 0444); +module_param(lumafilter, int, 0444); +module_param(automute, int, 0444); +module_param(chroma_agc, int, 0444); +module_param(adc_crush, int, 0444); +module_param(whitecrush_upper, int, 0444); +module_param(whitecrush_lower, int, 0444); +module_param(vcr_hack, int, 0444); +module_param(uv_ratio, int, 0444); +module_param(full_luma_range, int, 0444); +module_param(coring, int, 0444); + +module_param_array(radio, int, NULL, 0444); +module_param_array(video_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); + +MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)"); +MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian"); +MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)"); +MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)"); +MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)"); +MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)"); +MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); +MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8"); +MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000"); +MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default " + "is 1 (yes) for compatibility with older applications"); +MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)"); +MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)"); +MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)"); +MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207"); +MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127"); +MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); +MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler"); +MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50"); +MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)"); +MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)"); +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); + +MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); +MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); +MODULE_LICENSE("GPL"); + +/* ----------------------------------------------------------------------- */ +/* sysfs */ + +static ssize_t show_card(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct video_device *vfd = container_of(cd, struct video_device, dev); + struct bttv *btv = video_get_drvdata(vfd); + return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); +} +static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); + +/* ----------------------------------------------------------------------- */ +/* dvb auto-load setup */ +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + request_module("dvb-bt8xx"); +} + +static void request_modules(struct bttv *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); +} + +static void flush_request_modules(struct bttv *dev) +{ + flush_work_sync(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#define flush_request_modules(dev) +#endif /* CONFIG_MODULES */ + + +/* ----------------------------------------------------------------------- */ +/* static data */ + +/* special timing tables from conexant... */ +static u8 SRAM_Table[][60] = +{ + /* PAL digital input over GPIO[7:0] */ + { + 45, // 45 bytes following + 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16, + 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00, + 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00, + 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37, + 0x37,0x00,0xAF,0x21,0x00 + }, + /* NTSC digital input over GPIO[7:0] */ + { + 51, // 51 bytes following + 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06, + 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00, + 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07, + 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6, + 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21, + 0x00, + }, + // TGB_NTSC392 // quartzsight + // This table has been modified to be used for Fusion Rev D + { + 0x2A, // size of table = 42 + 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24, + 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10, + 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00, + 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3, + 0x20, 0x00 + } +}; + +/* minhdelayx1 first video pixel we can capture on a line and + hdelayx1 start of active video, both relative to rising edge of + /HRESET pulse (0H) in 1 / fCLKx1. + swidth width of active video and + totalwidth total line width, both in 1 / fCLKx1. + sqwidth total line width in square pixels. + vdelay start of active video in 2 * field lines relative to + trailing edge of /VRESET pulse (VDELAY register). + sheight height of active video in 2 * field lines. + videostart0 ITU-R frame line number of the line corresponding + to vdelay in the first field. */ +#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \ + vdelay, sheight, videostart0) \ + .cropcap.bounds.left = minhdelayx1, \ + /* * 2 because vertically we count field lines times two, */ \ + /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \ + .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \ + /* 4 is a safety margin at the end of the line. */ \ + .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \ + .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \ + .cropcap.defrect.left = hdelayx1, \ + .cropcap.defrect.top = (videostart0) * 2, \ + .cropcap.defrect.width = swidth, \ + .cropcap.defrect.height = sheight, \ + .cropcap.pixelaspect.numerator = totalwidth, \ + .cropcap.pixelaspect.denominator = sqwidth, + +const struct bttv_tvnorm bttv_tvnorms[] = { + /* PAL-BDGHI */ + /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ + /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */ + { + .v4l2_id = V4L2_STD_PAL, + .name = "PAL", + .Fsc = 35468950, + .swidth = 924, + .sheight = 576, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0x72, + .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), + .scaledtwidth = 1135, + .hdelayx1 = 186, + .hactivex1 = 924, + .vdelay = 0x20, + .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */ + .sram = 0, + /* ITU-R frame line number of the first VBI line + we can capture, of the first and second field. + The last line is determined by cropcap.bounds. */ + .vbistart = { 7, 320 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 186, + /* Should be (768 * 1135 + 944 / 2) / 944. + cropcap.defrect is used for image width + checks, so we keep the old value 924. */ + /* swidth */ 924, + /* totalwidth */ 1135, + /* sqwidth */ 944, + /* vdelay */ 0x20, + /* sheight */ 576, + /* videostart0 */ 23) + /* bt878 (and bt848?) can capture another + line below active video. */ + .cropcap.bounds.height = (576 + 2) + 0x20 - 2, + },{ + .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, + .name = "NTSC", + .Fsc = 28636363, + .swidth = 768, + .sheight = 480, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0), + .scaledtwidth = 910, + .hdelayx1 = 128, + .hactivex1 = 910, + .vdelay = 0x1a, + .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */ + .sram = 1, + .vbistart = { 10, 273 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 128, + /* Should be (640 * 910 + 780 / 2) / 780? */ + /* swidth */ 768, + /* totalwidth */ 910, + /* sqwidth */ 780, + /* vdelay */ 0x1a, + /* sheight */ 480, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_SECAM, + .name = "SECAM", + .Fsc = 35468950, + .swidth = 924, + .sheight = 576, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0xb0, + .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1), + .scaledtwidth = 1135, + .hdelayx1 = 186, + .hactivex1 = 922, + .vdelay = 0x20, + .vbipack = 255, + .sram = 0, /* like PAL, correct? */ + .vbistart = { 7, 320 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 186, + /* swidth */ 924, + /* totalwidth */ 1135, + /* sqwidth */ 944, + /* vdelay */ 0x20, + /* sheight */ 576, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_PAL_Nc, + .name = "PAL-Nc", + .Fsc = 28636363, + .swidth = 640, + .sheight = 576, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), + .scaledtwidth = 780, + .hdelayx1 = 130, + .hactivex1 = 734, + .vdelay = 0x1a, + .vbipack = 144, + .sram = -1, + .vbistart = { 7, 320 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 130, + /* swidth */ (640 * 910 + 780 / 2) / 780, + /* totalwidth */ 910, + /* sqwidth */ 780, + /* vdelay */ 0x1a, + /* sheight */ 576, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_PAL_M, + .name = "PAL-M", + .Fsc = 28636363, + .swidth = 640, + .sheight = 480, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0), + .scaledtwidth = 780, + .hdelayx1 = 135, + .hactivex1 = 754, + .vdelay = 0x1a, + .vbipack = 144, + .sram = -1, + .vbistart = { 10, 273 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 135, + /* swidth */ (640 * 910 + 780 / 2) / 780, + /* totalwidth */ 910, + /* sqwidth */ 780, + /* vdelay */ 0x1a, + /* sheight */ 480, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_PAL_N, + .name = "PAL-N", + .Fsc = 35468950, + .swidth = 768, + .sheight = 576, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0x72, + .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1), + .scaledtwidth = 944, + .hdelayx1 = 186, + .hactivex1 = 922, + .vdelay = 0x20, + .vbipack = 144, + .sram = -1, + .vbistart = { 7, 320 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 186, + /* swidth */ (768 * 1135 + 944 / 2) / 944, + /* totalwidth */ 1135, + /* sqwidth */ 944, + /* vdelay */ 0x20, + /* sheight */ 576, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_NTSC_M_JP, + .name = "NTSC-JP", + .Fsc = 28636363, + .swidth = 640, + .sheight = 480, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), + .scaledtwidth = 780, + .hdelayx1 = 135, + .hactivex1 = 754, + .vdelay = 0x16, + .vbipack = 144, + .sram = -1, + .vbistart = { 10, 273 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 135, + /* swidth */ (640 * 910 + 780 / 2) / 780, + /* totalwidth */ 910, + /* sqwidth */ 780, + /* vdelay */ 0x16, + /* sheight */ 480, + /* videostart0 */ 23) + },{ + /* that one hopefully works with the strange timing + * which video recorders produce when playing a NTSC + * tape on a PAL TV ... */ + .v4l2_id = V4L2_STD_PAL_60, + .name = "PAL-60", + .Fsc = 35468950, + .swidth = 924, + .sheight = 480, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0x72, + .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), + .scaledtwidth = 1135, + .hdelayx1 = 186, + .hactivex1 = 924, + .vdelay = 0x1a, + .vbipack = 255, + .vtotal = 524, + .sram = -1, + .vbistart = { 10, 273 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 186, + /* swidth */ 924, + /* totalwidth */ 1135, + /* sqwidth */ 944, + /* vdelay */ 0x1a, + /* sheight */ 480, + /* videostart0 */ 23) + } +}; +static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); + +/* ----------------------------------------------------------------------- */ +/* bttv format list + packed pixel formats must come first */ +static const struct bttv_format formats[] = { + { + .name = "8 bpp, gray", + .fourcc = V4L2_PIX_FMT_GREY, + .btformat = BT848_COLOR_FMT_Y8, + .depth = 8, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "8 bpp, dithered color", + .fourcc = V4L2_PIX_FMT_HI240, + .btformat = BT848_COLOR_FMT_RGB8, + .depth = 8, + .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, + },{ + .name = "15 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB555, + .btformat = BT848_COLOR_FMT_RGB15, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "15 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB555X, + .btformat = BT848_COLOR_FMT_RGB15, + .btswap = 0x03, /* byteswap */ + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "16 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB565, + .btformat = BT848_COLOR_FMT_RGB16, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "16 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB565X, + .btformat = BT848_COLOR_FMT_RGB16, + .btswap = 0x03, /* byteswap */ + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "24 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR24, + .btformat = BT848_COLOR_FMT_RGB24, + .depth = 24, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "32 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR32, + .btformat = BT848_COLOR_FMT_RGB32, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "32 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB32, + .btformat = BT848_COLOR_FMT_RGB32, + .btswap = 0x0f, /* byte+word swap */ + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .btformat = BT848_COLOR_FMT_YUY2, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .btformat = BT848_COLOR_FMT_YUY2, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .btformat = BT848_COLOR_FMT_YUY2, + .btswap = 0x03, /* byteswap */ + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "4:2:2, planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YUV422P, + .btformat = BT848_COLOR_FMT_YCrCb422, + .depth = 16, + .flags = FORMAT_FLAGS_PLANAR, + .hshift = 1, + .vshift = 0, + },{ + .name = "4:2:0, planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YUV420, + .btformat = BT848_COLOR_FMT_YCrCb422, + .depth = 12, + .flags = FORMAT_FLAGS_PLANAR, + .hshift = 1, + .vshift = 1, + },{ + .name = "4:2:0, planar, Y-Cr-Cb", + .fourcc = V4L2_PIX_FMT_YVU420, + .btformat = BT848_COLOR_FMT_YCrCb422, + .depth = 12, + .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb, + .hshift = 1, + .vshift = 1, + },{ + .name = "4:1:1, planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YUV411P, + .btformat = BT848_COLOR_FMT_YCrCb411, + .depth = 12, + .flags = FORMAT_FLAGS_PLANAR, + .hshift = 2, + .vshift = 0, + },{ + .name = "4:1:0, planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YUV410, + .btformat = BT848_COLOR_FMT_YCrCb411, + .depth = 9, + .flags = FORMAT_FLAGS_PLANAR, + .hshift = 2, + .vshift = 2, + },{ + .name = "4:1:0, planar, Y-Cr-Cb", + .fourcc = V4L2_PIX_FMT_YVU410, + .btformat = BT848_COLOR_FMT_YCrCb411, + .depth = 9, + .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb, + .hshift = 2, + .vshift = 2, + },{ + .name = "raw scanlines", + .fourcc = -1, + .btformat = BT848_COLOR_FMT_RAW, + .depth = 8, + .flags = FORMAT_FLAGS_RAW, + } +}; +static const unsigned int FORMATS = ARRAY_SIZE(formats); + +/* ----------------------------------------------------------------------- */ + +#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1) +#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2) +#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4) +#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5) +#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6) +#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7) +#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8) +#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9) +#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10) +#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11) + +static const struct v4l2_queryctrl no_ctl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; +static const struct v4l2_queryctrl bttv_ctls[] = { + /* --- video --- */ + { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0, + .maximum = 65535, + .step = 256, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 65535, + .step = 128, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 65535, + .step = 128, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 65535, + .step = 256, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + /* --- audio --- */ + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 65535, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_BALANCE, + .name = "Balance", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_BASS, + .name = "Bass", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_TREBLE, + .name = "Treble", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + /* --- private --- */ + { + .id = V4L2_CID_PRIVATE_CHROMA_AGC, + .name = "chroma agc", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_COMBFILTER, + .name = "combfilter", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_AUTOMUTE, + .name = "automute", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_LUMAFILTER, + .name = "luma decimation filter", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_AGC_CRUSH, + .name = "agc crush", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_VCR_HACK, + .name = "vcr hack", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER, + .name = "whitecrush upper", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0xCF, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER, + .name = "whitecrush lower", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x7F, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_UV_RATIO, + .name = "uv ratio", + .minimum = 0, + .maximum = 100, + .step = 1, + .default_value = 50, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, + .name = "full luma range", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_CORING, + .name = "coring", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + } + + + +}; + +static const struct v4l2_queryctrl *ctrl_by_id(int id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++) + if (bttv_ctls[i].id == id) + return bttv_ctls+i; + + return NULL; +} + +/* ----------------------------------------------------------------------- */ +/* resource management */ + +/* + RESOURCE_ allocated by freed by + + VIDEO_READ bttv_read 1) bttv_read 2) + + VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF + VIDIOC_QBUF 1) bttv_release + VIDIOCMCAPTURE 1) + + OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off + VIDIOC_OVERLAY on VIDIOC_OVERLAY off + 3) bttv_release + + VBI VIDIOC_STREAMON VIDIOC_STREAMOFF + VIDIOC_QBUF 1) bttv_release + bttv_read, bttv_poll 1) 4) + + 1) The resource must be allocated when we enter buffer prepare functions + and remain allocated while buffers are in the DMA queue. + 2) This is a single frame read. + 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when + RESOURCE_OVERLAY is allocated. + 4) This is a continuous read, implies VIDIOC_STREAMON. + + Note this driver permits video input and standard changes regardless if + resources are allocated. +*/ + +#define VBI_RESOURCES (RESOURCE_VBI) +#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \ + RESOURCE_VIDEO_STREAM | \ + RESOURCE_OVERLAY) + +static +int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) +{ + int xbits; /* mutual exclusive resources */ + + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + xbits = bit; + if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM)) + xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM; + + /* is it free? */ + if (btv->resources & xbits) { + /* no, someone else uses it */ + goto fail; + } + + if ((bit & VIDEO_RESOURCES) + && 0 == (btv->resources & VIDEO_RESOURCES)) { + /* Do crop - use current, don't - use default parameters. */ + __s32 top = btv->crop[!!fh->do_crop].rect.top; + + if (btv->vbi_end > top) + goto fail; + + /* We cannot capture the same line as video and VBI data. + Claim scan lines crop[].rect.top to bottom. */ + btv->crop_start = top; + } else if (bit & VBI_RESOURCES) { + __s32 end = fh->vbi_fmt.end; + + if (end > btv->crop_start) + goto fail; + + /* Claim scan lines above fh->vbi_fmt.end. */ + btv->vbi_end = end; + } + + /* it's free, grab it */ + fh->resources |= bit; + btv->resources |= bit; + return 1; + + fail: + return 0; +} + +static +int check_btres(struct bttv_fh *fh, int bit) +{ + return (fh->resources & bit); +} + +static +int locked_btres(struct bttv *btv, int bit) +{ + return (btv->resources & bit); +} + +/* Call with btv->lock down. */ +static void +disclaim_vbi_lines(struct bttv *btv) +{ + btv->vbi_end = 0; +} + +/* Call with btv->lock down. */ +static void +disclaim_video_lines(struct bttv *btv) +{ + const struct bttv_tvnorm *tvnorm; + u8 crop; + + tvnorm = &bttv_tvnorms[btv->tvnorm]; + btv->crop_start = tvnorm->cropcap.bounds.top + + tvnorm->cropcap.bounds.height; + + /* VBI capturing ends at VDELAY, start of video capturing, no + matter how many lines the VBI RISC program expects. When video + capturing is off, it shall no longer "preempt" VBI capturing, + so we set VDELAY to maximum. */ + crop = btread(BT848_E_CROP) | 0xc0; + btwrite(crop, BT848_E_CROP); + btwrite(0xfe, BT848_E_VDELAY_LO); + btwrite(crop, BT848_O_CROP); + btwrite(0xfe, BT848_O_VDELAY_LO); +} + +static +void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) +{ + if ((fh->resources & bits) != bits) { + /* trying to free ressources not allocated by us ... */ + printk("bttv: BUG! (btres)\n"); + } + fh->resources &= ~bits; + btv->resources &= ~bits; + + bits = btv->resources; + + if (0 == (bits & VIDEO_RESOURCES)) + disclaim_video_lines(btv); + + if (0 == (bits & VBI_RESOURCES)) + disclaim_vbi_lines(btv); +} + +/* ----------------------------------------------------------------------- */ +/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */ + +/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C + PLL_X = Reference pre-divider (0=1, 1=2) + PLL_C = Post divider (0=6, 1=4) + PLL_I = Integer input + PLL_F = Fractional input + + F_input = 28.636363 MHz: + PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0 +*/ + +static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout) +{ + unsigned char fl, fh, fi; + + /* prevent overflows */ + fin/=4; + fout/=4; + + fout*=12; + fi=fout/fin; + + fout=(fout%fin)*256; + fh=fout/fin; + + fout=(fout%fin)*256; + fl=fout/fin; + + btwrite(fl, BT848_PLL_F_LO); + btwrite(fh, BT848_PLL_F_HI); + btwrite(fi|BT848_PLL_X, BT848_PLL_XCI); +} + +static void set_pll(struct bttv *btv) +{ + int i; + + if (!btv->pll.pll_crystal) + return; + + if (btv->pll.pll_ofreq == btv->pll.pll_current) { + dprintk("bttv%d: PLL: no change required\n",btv->c.nr); + return; + } + + if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) { + /* no PLL needed */ + if (btv->pll.pll_current == 0) + return; + bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n", + btv->c.nr,btv->pll.pll_ifreq); + btwrite(0x00,BT848_TGCTRL); + btwrite(0x00,BT848_PLL_XCI); + btv->pll.pll_current = 0; + return; + } + + bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr, + btv->pll.pll_ifreq, btv->pll.pll_ofreq); + set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); + + for (i=0; i<10; i++) { + /* Let other people run while the PLL stabilizes */ + bttv_printk("."); + msleep(10); + + if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) { + btwrite(0,BT848_DSTATUS); + } else { + btwrite(0x08,BT848_TGCTRL); + btv->pll.pll_current = btv->pll.pll_ofreq; + bttv_printk(" ok\n"); + return; + } + } + btv->pll.pll_current = -1; + bttv_printk("failed\n"); + return; +} + +/* used to switch between the bt848's analog/digital video capture modes */ +static void bt848A_set_timing(struct bttv *btv) +{ + int i, len; + int table_idx = bttv_tvnorms[btv->tvnorm].sram; + int fsc = bttv_tvnorms[btv->tvnorm].Fsc; + + if (btv->input == btv->dig) { + dprintk("bttv%d: load digital timing table (table_idx=%d)\n", + btv->c.nr,table_idx); + + /* timing change...reset timing generator address */ + btwrite(0x00, BT848_TGCTRL); + btwrite(0x02, BT848_TGCTRL); + btwrite(0x00, BT848_TGCTRL); + + len=SRAM_Table[table_idx][0]; + for(i = 1; i <= len; i++) + btwrite(SRAM_Table[table_idx][i],BT848_TGLB); + btv->pll.pll_ofreq = 27000000; + + set_pll(btv); + btwrite(0x11, BT848_TGCTRL); + btwrite(0x41, BT848_DVSIF); + } else { + btv->pll.pll_ofreq = fsc; + set_pll(btv); + btwrite(0x0, BT848_DVSIF); + } +} + +/* ----------------------------------------------------------------------- */ + +static void bt848_bright(struct bttv *btv, int bright) +{ + int value; + + // printk("bttv: set bright: %d\n",bright); // DEBUG + btv->bright = bright; + + /* We want -128 to 127 we get 0-65535 */ + value = (bright >> 8) - 128; + btwrite(value & 0xff, BT848_BRIGHT); +} + +static void bt848_hue(struct bttv *btv, int hue) +{ + int value; + + btv->hue = hue; + + /* -128 to 127 */ + value = (hue >> 8) - 128; + btwrite(value & 0xff, BT848_HUE); +} + +static void bt848_contrast(struct bttv *btv, int cont) +{ + int value,hibit; + + btv->contrast = cont; + + /* 0-511 */ + value = (cont >> 7); + hibit = (value >> 6) & 4; + btwrite(value & 0xff, BT848_CONTRAST_LO); + btaor(hibit, ~4, BT848_E_CONTROL); + btaor(hibit, ~4, BT848_O_CONTROL); +} + +static void bt848_sat(struct bttv *btv, int color) +{ + int val_u,val_v,hibits; + + btv->saturation = color; + + /* 0-511 for the color */ + val_u = ((color * btv->opt_uv_ratio) / 50) >> 7; + val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254; + hibits = (val_u >> 7) & 2; + hibits |= (val_v >> 8) & 1; + btwrite(val_u & 0xff, BT848_SAT_U_LO); + btwrite(val_v & 0xff, BT848_SAT_V_LO); + btaor(hibits, ~3, BT848_E_CONTROL); + btaor(hibits, ~3, BT848_O_CONTROL); +} + +/* ----------------------------------------------------------------------- */ + +static int +video_mux(struct bttv *btv, unsigned int input) +{ + int mux,mask2; + + if (input >= bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; + + /* needed by RemoteVideo MX */ + mask2 = bttv_tvcards[btv->c.type].gpiomask2; + if (mask2) + gpio_inout(mask2,mask2); + + if (input == btv->svhs) { + btor(BT848_CONTROL_COMP, BT848_E_CONTROL); + btor(BT848_CONTROL_COMP, BT848_O_CONTROL); + } else { + btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); + btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); + } + mux = bttv_muxsel(btv, input); + btaor(mux<<5, ~(3<<5), BT848_IFORM); + dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n", + btv->c.nr,input,mux); + + /* card specific hook */ + if(bttv_tvcards[btv->c.type].muxsel_hook) + bttv_tvcards[btv->c.type].muxsel_hook (btv, input); + return 0; +} + +static char *audio_modes[] = { + "audio: tuner", "audio: radio", "audio: extern", + "audio: intern", "audio: mute" +}; + +static int +audio_mux(struct bttv *btv, int input, int mute) +{ + int gpio_val, signal; + struct v4l2_control ctrl; + + gpio_inout(bttv_tvcards[btv->c.type].gpiomask, + bttv_tvcards[btv->c.type].gpiomask); + signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC; + + btv->mute = mute; + btv->audio = input; + + /* automute */ + mute = mute || (btv->opt_automute && !signal && !btv->radio_user); + + if (mute) + gpio_val = bttv_tvcards[btv->c.type].gpiomute; + else + gpio_val = bttv_tvcards[btv->c.type].gpiomux[input]; + + switch (btv->c.type) { + case BTTV_BOARD_VOODOOTV_FM: + case BTTV_BOARD_VOODOOTV_200: + gpio_val = bttv_tda9880_setnorm(btv, gpio_val); + break; + + default: + gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val); + } + + if (bttv_gpio) + bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]); + if (in_interrupt()) + return 0; + + ctrl.id = V4L2_CID_AUDIO_MUTE; + ctrl.value = btv->mute; + bttv_call_all(btv, core, s_ctrl, &ctrl); + if (btv->sd_msp34xx) { + u32 in; + + /* Note: the inputs tuner/radio/extern/intern are translated + to msp routings. This assumes common behavior for all msp3400 + based TV cards. When this assumption fails, then the + specific MSP routing must be added to the card table. + For now this is sufficient. */ + switch (input) { + case TVAUDIO_INPUT_RADIO: + in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); + break; + case TVAUDIO_INPUT_EXTERN: + in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); + break; + case TVAUDIO_INPUT_INTERN: + /* Yes, this is the same input as for RADIO. I doubt + if this is ever used. The only board with an INTERN + input is the BTTV_BOARD_AVERMEDIA98. I wonder how + that was tested. My guess is that the whole INTERN + input does not work. */ + in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); + break; + case TVAUDIO_INPUT_TUNER: + default: + /* This is the only card that uses TUNER2, and afaik, + is the only difference between the VOODOOTV_FM + and VOODOOTV_200 */ + if (btv->c.type == BTTV_BOARD_VOODOOTV_200) + in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \ + MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER); + else + in = MSP_INPUT_DEFAULT; + break; + } + v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing, + in, MSP_OUTPUT_DEFAULT, 0); + } + if (btv->sd_tvaudio) { + v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, + input, 0, 0); + } + return 0; +} + +static inline int +audio_mute(struct bttv *btv, int mute) +{ + return audio_mux(btv, btv->audio, mute); +} + +static inline int +audio_input(struct bttv *btv, int input) +{ + return audio_mux(btv, input, btv->mute); +} + +static void +bttv_crop_calc_limits(struct bttv_crop *c) +{ + /* Scale factor min. 1:1, max. 16:1. Min. image size + 48 x 32. Scaled width must be a multiple of 4. */ + + if (1) { + /* For bug compatibility with VIDIOCGCAP and image + size checks in earlier driver versions. */ + c->min_scaled_width = 48; + c->min_scaled_height = 32; + } else { + c->min_scaled_width = + (max(48, c->rect.width >> 4) + 3) & ~3; + c->min_scaled_height = + max(32, c->rect.height >> 4); + } + + c->max_scaled_width = c->rect.width & ~3; + c->max_scaled_height = c->rect.height; +} + +static void +bttv_crop_reset(struct bttv_crop *c, unsigned int norm) +{ + c->rect = bttv_tvnorms[norm].cropcap.defrect; + bttv_crop_calc_limits(c); +} + +/* Call with btv->lock down. */ +static int +set_tvnorm(struct bttv *btv, unsigned int norm) +{ + const struct bttv_tvnorm *tvnorm; + v4l2_std_id id; + + BUG_ON(norm >= BTTV_TVNORMS); + BUG_ON(btv->tvnorm >= BTTV_TVNORMS); + + tvnorm = &bttv_tvnorms[norm]; + + if (memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap, + sizeof (tvnorm->cropcap))) { + bttv_crop_reset(&btv->crop[0], norm); + btv->crop[1] = btv->crop[0]; /* current = default */ + + if (0 == (btv->resources & VIDEO_RESOURCES)) { + btv->crop_start = tvnorm->cropcap.bounds.top + + tvnorm->cropcap.bounds.height; + } + } + + btv->tvnorm = norm; + + btwrite(tvnorm->adelay, BT848_ADELAY); + btwrite(tvnorm->bdelay, BT848_BDELAY); + btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), + BT848_IFORM); + btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE); + btwrite(1, BT848_VBI_PACK_DEL); + bt848A_set_timing(btv); + + switch (btv->c.type) { + case BTTV_BOARD_VOODOOTV_FM: + case BTTV_BOARD_VOODOOTV_200: + bttv_tda9880_setnorm(btv, gpio_read()); + break; + } + id = tvnorm->v4l2_id; + bttv_call_all(btv, core, s_std, id); + + return 0; +} + +/* Call with btv->lock down. */ +static void +set_input(struct bttv *btv, unsigned int input, unsigned int norm) +{ + unsigned long flags; + + btv->input = input; + if (irq_iswitch) { + spin_lock_irqsave(&btv->s_lock,flags); + if (btv->curr.frame_irq) { + /* active capture -> delayed input switch */ + btv->new_input = input; + } else { + video_mux(btv,input); + } + spin_unlock_irqrestore(&btv->s_lock,flags); + } else { + video_mux(btv,input); + } + audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ? + TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN); + set_tvnorm(btv, norm); +} + +static void init_irqreg(struct bttv *btv) +{ + /* clear status */ + btwrite(0xfffffUL, BT848_INT_STAT); + + if (bttv_tvcards[btv->c.type].no_video) { + /* i2c only */ + btwrite(BT848_INT_I2CDONE, + BT848_INT_MASK); + } else { + /* full video */ + btwrite((btv->triton1) | + (btv->gpioirq ? BT848_INT_GPINT : 0) | + BT848_INT_SCERR | + (fdsr ? BT848_INT_FDSR : 0) | + BT848_INT_RISCI | BT848_INT_OCERR | + BT848_INT_FMTCHG|BT848_INT_HLOCK| + BT848_INT_I2CDONE, + BT848_INT_MASK); + } +} + +static void init_bt848(struct bttv *btv) +{ + int val; + + if (bttv_tvcards[btv->c.type].no_video) { + /* very basic init only */ + init_irqreg(btv); + return; + } + + btwrite(0x00, BT848_CAP_CTL); + btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); + btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM); + + /* set planar and packed mode trigger points and */ + /* set rising edge of inverted GPINTR pin as irq trigger */ + btwrite(BT848_GPIO_DMA_CTL_PKTP_32| + BT848_GPIO_DMA_CTL_PLTP1_16| + BT848_GPIO_DMA_CTL_PLTP23_16| + BT848_GPIO_DMA_CTL_GPINTC| + BT848_GPIO_DMA_CTL_GPINTI, + BT848_GPIO_DMA_CTL); + + val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; + btwrite(val, BT848_E_SCLOOP); + btwrite(val, BT848_O_SCLOOP); + + btwrite(0x20, BT848_E_VSCALE_HI); + btwrite(0x20, BT848_O_VSCALE_HI); + btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + BT848_ADC); + + btwrite(whitecrush_upper, BT848_WC_UP); + btwrite(whitecrush_lower, BT848_WC_DOWN); + + if (btv->opt_lumafilter) { + btwrite(0, BT848_E_CONTROL); + btwrite(0, BT848_O_CONTROL); + } else { + btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); + } + + bt848_bright(btv, btv->bright); + bt848_hue(btv, btv->hue); + bt848_contrast(btv, btv->contrast); + bt848_sat(btv, btv->saturation); + + /* interrupt */ + init_irqreg(btv); +} + +static void bttv_reinit_bt848(struct bttv *btv) +{ + unsigned long flags; + + if (bttv_verbose) + printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr); + spin_lock_irqsave(&btv->s_lock,flags); + btv->errors=0; + bttv_set_dma(btv,0); + spin_unlock_irqrestore(&btv->s_lock,flags); + + init_bt848(btv); + btv->pll.pll_current = -1; + set_input(btv, btv->input, btv->tvnorm); +} + +static int bttv_g_ctrl(struct file *file, void *priv, + struct v4l2_control *c) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = btv->bright; + break; + case V4L2_CID_HUE: + c->value = btv->hue; + break; + case V4L2_CID_CONTRAST: + c->value = btv->contrast; + break; + case V4L2_CID_SATURATION: + c->value = btv->saturation; + break; + + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + bttv_call_all(btv, core, g_ctrl, c); + break; + + case V4L2_CID_PRIVATE_CHROMA_AGC: + c->value = btv->opt_chroma_agc; + break; + case V4L2_CID_PRIVATE_COMBFILTER: + c->value = btv->opt_combfilter; + break; + case V4L2_CID_PRIVATE_LUMAFILTER: + c->value = btv->opt_lumafilter; + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + c->value = btv->opt_automute; + break; + case V4L2_CID_PRIVATE_AGC_CRUSH: + c->value = btv->opt_adc_crush; + break; + case V4L2_CID_PRIVATE_VCR_HACK: + c->value = btv->opt_vcr_hack; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + c->value = btv->opt_whitecrush_upper; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + c->value = btv->opt_whitecrush_lower; + break; + case V4L2_CID_PRIVATE_UV_RATIO: + c->value = btv->opt_uv_ratio; + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + c->value = btv->opt_full_luma_range; + break; + case V4L2_CID_PRIVATE_CORING: + c->value = btv->opt_coring; + break; + default: + return -EINVAL; + } + return 0; +} + +static int bttv_s_ctrl(struct file *file, void *f, + struct v4l2_control *c) +{ + int err; + int val; + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (0 != err) + return err; + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + bt848_bright(btv, c->value); + break; + case V4L2_CID_HUE: + bt848_hue(btv, c->value); + break; + case V4L2_CID_CONTRAST: + bt848_contrast(btv, c->value); + break; + case V4L2_CID_SATURATION: + bt848_sat(btv, c->value); + break; + case V4L2_CID_AUDIO_MUTE: + audio_mute(btv, c->value); + /* fall through */ + case V4L2_CID_AUDIO_VOLUME: + if (btv->volume_gpio) + btv->volume_gpio(btv, c->value); + + bttv_call_all(btv, core, s_ctrl, c); + break; + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + bttv_call_all(btv, core, s_ctrl, c); + break; + + case V4L2_CID_PRIVATE_CHROMA_AGC: + btv->opt_chroma_agc = c->value; + val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; + btwrite(val, BT848_E_SCLOOP); + btwrite(val, BT848_O_SCLOOP); + break; + case V4L2_CID_PRIVATE_COMBFILTER: + btv->opt_combfilter = c->value; + break; + case V4L2_CID_PRIVATE_LUMAFILTER: + btv->opt_lumafilter = c->value; + if (btv->opt_lumafilter) { + btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); + btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); + } else { + btor(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btor(BT848_CONTROL_LDEC, BT848_O_CONTROL); + } + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + btv->opt_automute = c->value; + break; + case V4L2_CID_PRIVATE_AGC_CRUSH: + btv->opt_adc_crush = c->value; + btwrite(BT848_ADC_RESERVED | + (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + BT848_ADC); + break; + case V4L2_CID_PRIVATE_VCR_HACK: + btv->opt_vcr_hack = c->value; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + btv->opt_whitecrush_upper = c->value; + btwrite(c->value, BT848_WC_UP); + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + btv->opt_whitecrush_lower = c->value; + btwrite(c->value, BT848_WC_DOWN); + break; + case V4L2_CID_PRIVATE_UV_RATIO: + btv->opt_uv_ratio = c->value; + bt848_sat(btv, btv->saturation); + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + btv->opt_full_luma_range = c->value; + btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); + break; + case V4L2_CID_PRIVATE_CORING: + btv->opt_coring = c->value; + btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); + break; + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +void bttv_gpio_tracking(struct bttv *btv, char *comment) +{ + unsigned int outbits, data; + outbits = btread(BT848_GPIO_OUT_EN); + data = btread(BT848_GPIO_DATA); + printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", + btv->c.nr,outbits,data & outbits, data & ~outbits, comment); +} + +static void bttv_field_count(struct bttv *btv) +{ + int need_count = 0; + + if (btv->users) + need_count++; + + if (need_count) { + /* start field counter */ + btor(BT848_INT_VSYNC,BT848_INT_MASK); + } else { + /* stop field counter */ + btand(~BT848_INT_VSYNC,BT848_INT_MASK); + btv->field_count = 0; + } +} + +static const struct bttv_format* +format_by_fourcc(int fourcc) +{ + unsigned int i; + + for (i = 0; i < FORMATS; i++) { + if (-1 == formats[i].fourcc) + continue; + if (formats[i].fourcc == fourcc) + return formats+i; + } + return NULL; +} + +/* ----------------------------------------------------------------------- */ +/* misc helpers */ + +static int +bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, + struct bttv_buffer *new) +{ + struct bttv_buffer *old; + unsigned long flags; + int retval = 0; + + dprintk("switch_overlay: enter [new=%p]\n",new); + if (new) + new->vb.state = VIDEOBUF_DONE; + spin_lock_irqsave(&btv->s_lock,flags); + old = btv->screen; + btv->screen = new; + btv->loop_irq |= 1; + bttv_set_dma(btv, 0x03); + spin_unlock_irqrestore(&btv->s_lock,flags); + if (NULL != old) { + dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state); + bttv_dma_free(&fh->cap,btv, old); + kfree(old); + } + if (NULL == new) + free_btres_lock(btv,fh,RESOURCE_OVERLAY); + dprintk("switch_overlay: done\n"); + return retval; +} + +/* ----------------------------------------------------------------------- */ +/* video4linux (1) interface */ + +static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, + struct bttv_buffer *buf, + const struct bttv_format *fmt, + unsigned int width, unsigned int height, + enum v4l2_field field) +{ + struct bttv_fh *fh = q->priv_data; + int redo_dma_risc = 0; + struct bttv_crop c; + int norm; + int rc; + + /* check settings */ + if (NULL == fmt) + return -EINVAL; + if (fmt->btformat == BT848_COLOR_FMT_RAW) { + width = RAW_BPL; + height = RAW_LINES*2; + if (width*height > buf->vb.bsize) + return -EINVAL; + buf->vb.size = buf->vb.bsize; + + /* Make sure tvnorm and vbi_end remain consistent + until we're done. */ + + norm = btv->tvnorm; + + /* In this mode capturing always starts at defrect.top + (default VDELAY), ignoring cropping parameters. */ + if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) { + return -EINVAL; + } + + c.rect = bttv_tvnorms[norm].cropcap.defrect; + } else { + norm = btv->tvnorm; + c = btv->crop[!!fh->do_crop]; + + if (width < c.min_scaled_width || + width > c.max_scaled_width || + height < c.min_scaled_height) + return -EINVAL; + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + /* btv->crop counts frame lines. Max. scale + factor is 16:1 for frames, 8:1 for fields. */ + if (height * 2 > c.max_scaled_height) + return -EINVAL; + break; + + default: + if (height > c.max_scaled_height) + return -EINVAL; + break; + } + + buf->vb.size = (width * height * fmt->depth) >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + } + + /* alloc + fill struct bttv_buffer (if changed) */ + if (buf->vb.width != width || buf->vb.height != height || + buf->vb.field != field || + buf->tvnorm != norm || buf->fmt != fmt || + buf->crop.top != c.rect.top || + buf->crop.left != c.rect.left || + buf->crop.width != c.rect.width || + buf->crop.height != c.rect.height) { + buf->vb.width = width; + buf->vb.height = height; + buf->vb.field = field; + buf->tvnorm = norm; + buf->fmt = fmt; + buf->crop = c.rect; + redo_dma_risc = 1; + } + + /* alloc risc memory */ + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + redo_dma_risc = 1; + if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf))) + goto fail; + } + + if (redo_dma_risc) + if (0 != (rc = bttv_buffer_risc(btv,buf))) + goto fail; + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + bttv_dma_free(q,btv,buf); + return rc; +} + +static int +buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + struct bttv_fh *fh = q->priv_data; + + *size = fh->fmt->depth*fh->width*fh->height >> 3; + if (0 == *count) + *count = gbuffers; + if (*size * *count > gbuffers * gbufsize) + *count = (gbuffers * gbufsize) / *size; + return 0; +} + +static int +buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + struct bttv_fh *fh = q->priv_data; + + return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt, + fh->width, fh->height, field); +} + +static void +buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue,&btv->capture); + if (!btv->curr.frame_irq) { + btv->loop_irq |= 1; + bttv_set_dma(btv, 0x03); + } +} + +static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + struct bttv_fh *fh = q->priv_data; + + bttv_dma_free(q,fh->btv,buf); +} + +static struct videobuf_queue_ops bttv_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + unsigned int i; + int err; + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (err) + goto err; + + for (i = 0; i < BTTV_TVNORMS; i++) + if (*id & bttv_tvnorms[i].v4l2_id) + break; + if (i == BTTV_TVNORMS) { + err = -EINVAL; + goto err; + } + + set_tvnorm(btv, i); + +err: + + return err; +} + +static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) + *id = V4L2_STD_625_50; + else + *id = V4L2_STD_525_60; + return 0; +} + +static int bttv_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int rc = 0; + + if (i->index >= bttv_tvcards[btv->c.type].video_inputs) { + rc = -EINVAL; + goto err; + } + + i->type = V4L2_INPUT_TYPE_CAMERA; + i->audioset = 1; + + if (btv->tuner_type != TUNER_ABSENT && i->index == 0) { + sprintf(i->name, "Television"); + i->type = V4L2_INPUT_TYPE_TUNER; + i->tuner = 0; + } else if (i->index == btv->svhs) { + sprintf(i->name, "S-Video"); + } else { + sprintf(i->name, "Composite%d", i->index); + } + + if (i->index == btv->input) { + __u32 dstatus = btread(BT848_DSTATUS); + if (0 == (dstatus & BT848_DSTATUS_PRES)) + i->status |= V4L2_IN_ST_NO_SIGNAL; + if (0 == (dstatus & BT848_DSTATUS_HLOC)) + i->status |= V4L2_IN_ST_NO_H_LOCK; + } + + i->std = BTTV_NORMS; + +err: + + return rc; +} + +static int bttv_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + *i = btv->input; + + return 0; +} + +static int bttv_s_input(struct file *file, void *priv, unsigned int i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + int err; + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (unlikely(err)) + goto err; + + if (i > bttv_tvcards[btv->c.type].video_inputs) { + err = -EINVAL; + goto err; + } + + set_input(btv, i, btv->tvnorm); + +err: + return 0; +} + +static int bttv_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; + + if (unlikely(0 != t->index)) + return -EINVAL; + + if (unlikely(btv->tuner_type == TUNER_ABSENT)) { + err = -EINVAL; + goto err; + } + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (unlikely(err)) + goto err; + + bttv_call_all(btv, tuner, s_tuner, t); + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 1); + +err: + + return 0; +} + +static int bttv_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = btv->freq; + + return 0; +} + +static int bttv_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; + + if (unlikely(f->tuner != 0)) + return -EINVAL; + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (unlikely(err)) + goto err; + + if (unlikely(f->type != (btv->radio_user + ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) { + err = -EINVAL; + goto err; + } + btv->freq = f->frequency; + bttv_call_all(btv, tuner, s_frequency, f); + if (btv->has_matchbox && btv->radio_user) + tea5757_set_freq(btv, btv->freq); +err: + + return 0; +} + +static int bttv_log_status(struct file *file, void *f) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); + bttv_call_all(btv, core, log_status); + printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int bttv_g_register(struct file *file, void *f, + struct v4l2_dbg_register *reg) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + reg->val = btread(reg->reg); + reg->size = 1; + + return 0; +} + +static int bttv_s_register(struct file *file, void *f, + struct v4l2_dbg_register *reg) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + btwrite(reg->val, reg->reg); + + return 0; +} +#endif + +/* Given cropping boundaries b and the scaled width and height of a + single field or frame, which must not exceed hardware limits, this + function adjusts the cropping parameters c. */ +static void +bttv_crop_adjust (struct bttv_crop * c, + const struct v4l2_rect * b, + __s32 width, + __s32 height, + enum v4l2_field field) +{ + __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field); + __s32 max_left; + __s32 max_top; + + if (width < c->min_scaled_width) { + /* Max. hor. scale factor 16:1. */ + c->rect.width = width * 16; + } else if (width > c->max_scaled_width) { + /* Min. hor. scale factor 1:1. */ + c->rect.width = width; + + max_left = b->left + b->width - width; + max_left = min(max_left, (__s32) MAX_HDELAY); + if (c->rect.left > max_left) + c->rect.left = max_left; + } + + if (height < c->min_scaled_height) { + /* Max. vert. scale factor 16:1, single fields 8:1. */ + c->rect.height = height * 16; + } else if (frame_height > c->max_scaled_height) { + /* Min. vert. scale factor 1:1. + Top and height count field lines times two. */ + c->rect.height = (frame_height + 1) & ~1; + + max_top = b->top + b->height - c->rect.height; + if (c->rect.top > max_top) + c->rect.top = max_top; + } + + bttv_crop_calc_limits(c); +} + +/* Returns an error if scaling to a frame or single field with the given + width and height is not possible with the current cropping parameters + and width aligned according to width_mask. If adjust_size is TRUE the + function may adjust the width and/or height instead, rounding width + to (width + width_bias) & width_mask. If adjust_crop is TRUE it may + also adjust the current cropping parameters to get closer to the + desired image size. */ +static int +limit_scaled_size_lock (struct bttv_fh * fh, + __s32 * width, + __s32 * height, + enum v4l2_field field, + unsigned int width_mask, + unsigned int width_bias, + int adjust_size, + int adjust_crop) +{ + struct bttv *btv = fh->btv; + const struct v4l2_rect *b; + struct bttv_crop *c; + __s32 min_width; + __s32 min_height; + __s32 max_width; + __s32 max_height; + int rc; + + BUG_ON((int) width_mask >= 0 || + width_bias >= (unsigned int) -width_mask); + + /* Make sure tvnorm, vbi_end and the current cropping parameters + remain consistent until we're done. */ + + b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; + + /* Do crop - use current, don't - use default parameters. */ + c = &btv->crop[!!fh->do_crop]; + + if (fh->do_crop + && adjust_size + && adjust_crop + && !locked_btres(btv, VIDEO_RESOURCES)) { + min_width = 48; + min_height = 32; + + /* We cannot scale up. When the scaled image is larger + than crop.rect we adjust the crop.rect as required + by the V4L2 spec, hence cropcap.bounds are our limit. */ + max_width = min(b->width, (__s32) MAX_HACTIVE); + max_height = b->height; + + /* We cannot capture the same line as video and VBI data. + Note btv->vbi_end is really a minimum, see + bttv_vbi_try_fmt(). */ + if (btv->vbi_end > b->top) { + max_height -= btv->vbi_end - b->top; + rc = -EBUSY; + if (min_height > max_height) + goto fail; + } + } else { + rc = -EBUSY; + if (btv->vbi_end > c->rect.top) + goto fail; + + min_width = c->min_scaled_width; + min_height = c->min_scaled_height; + max_width = c->max_scaled_width; + max_height = c->max_scaled_height; + + adjust_crop = 0; + } + + min_width = (min_width - width_mask - 1) & width_mask; + max_width = max_width & width_mask; + + /* Max. scale factor is 16:1 for frames, 8:1 for fields. */ + min_height = min_height; + /* Min. scale factor is 1:1. */ + max_height >>= !V4L2_FIELD_HAS_BOTH(field); + + if (adjust_size) { + *width = clamp(*width, min_width, max_width); + *height = clamp(*height, min_height, max_height); + + /* Round after clamping to avoid overflow. */ + *width = (*width + width_bias) & width_mask; + + if (adjust_crop) { + bttv_crop_adjust(c, b, *width, *height, field); + + if (btv->vbi_end > c->rect.top) { + /* Move the crop window out of the way. */ + c->rect.top = btv->vbi_end; + } + } + } else { + rc = -EINVAL; + if (*width < min_width || + *height < min_height || + *width > max_width || + *height > max_height || + 0 != (*width & ~width_mask)) + goto fail; + } + + rc = 0; /* success */ + + fail: + + return rc; +} + +/* Returns an error if the given overlay window dimensions are not + possible with the current cropping parameters. If adjust_size is + TRUE the function may adjust the window width and/or height + instead, however it always rounds the horizontal position and + width as btcx_align() does. If adjust_crop is TRUE the function + may also adjust the current cropping parameters to get closer + to the desired window size. */ +static int +verify_window_lock (struct bttv_fh * fh, + struct v4l2_window * win, + int adjust_size, + int adjust_crop) +{ + enum v4l2_field field; + unsigned int width_mask; + int rc; + + if (win->w.width < 48 || win->w.height < 32) + return -EINVAL; + if (win->clipcount > 2048) + return -EINVAL; + + field = win->field; + + if (V4L2_FIELD_ANY == field) { + __s32 height2; + + height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1; + field = (win->w.height > height2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + /* 4-byte alignment. */ + if (NULL == fh->ovfmt) + return -EINVAL; + width_mask = ~0; + switch (fh->ovfmt->depth) { + case 8: + case 24: + width_mask = ~3; + break; + case 16: + width_mask = ~1; + break; + case 32: + break; + default: + BUG(); + } + + win->w.width -= win->w.left & ~width_mask; + win->w.left = (win->w.left - width_mask - 1) & width_mask; + + rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height, + field, width_mask, + /* width_bias: round down */ 0, + adjust_size, adjust_crop); + if (0 != rc) + return rc; + + win->field = field; + return 0; +} + +static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, + struct v4l2_window *win, int fixup) +{ + struct v4l2_clip *clips = NULL; + int n,size,retval = 0; + + if (NULL == fh->ovfmt) + return -EINVAL; + if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + retval = verify_window_lock(fh, win, + /* adjust_size */ fixup, + /* adjust_crop */ fixup); + if (0 != retval) + return retval; + + /* copy clips -- luckily v4l1 + v4l2 are binary + compatible here ...*/ + n = win->clipcount; + size = sizeof(*clips)*(n+4); + clips = kmalloc(size,GFP_KERNEL); + if (NULL == clips) + return -ENOMEM; + if (n > 0) { + if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) { + kfree(clips); + return -EFAULT; + } + } + + /* clip against screen */ + if (NULL != btv->fbuf.base) + n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height, + &win->w, clips, n); + btcx_sort_clips(clips,n); + + /* 4-byte alignments */ + switch (fh->ovfmt->depth) { + case 8: + case 24: + btcx_align(&win->w, clips, n, 3); + break; + case 16: + btcx_align(&win->w, clips, n, 1); + break; + case 32: + /* no alignment fixups needed */ + break; + default: + BUG(); + } + + kfree(fh->ov.clips); + fh->ov.clips = clips; + fh->ov.nclips = n; + + fh->ov.w = win->w; + fh->ov.field = win->field; + fh->ov.setup_ok = 1; + + btv->init.ov.w.width = win->w.width; + btv->init.ov.w.height = win->w.height; + btv->init.ov.field = win->field; + + /* update overlay if needed */ + retval = 0; + if (check_btres(fh, RESOURCE_OVERLAY)) { + struct bttv_buffer *new; + + new = videobuf_sg_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + retval = bttv_switch_overlay(btv,fh,new); + } + return retval; +} + +/* ----------------------------------------------------------------------- */ + +static struct videobuf_queue* bttv_queue(struct bttv_fh *fh) +{ + struct videobuf_queue* q = NULL; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + q = &fh->cap; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + q = &fh->vbi; + break; + default: + BUG(); + } + return q; +} + +static int bttv_resource(struct bttv_fh *fh) +{ + int res = 0; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + res = RESOURCE_VIDEO_STREAM; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + res = RESOURCE_VBI; + break; + default: + BUG(); + } + return res; +} + +static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type) +{ + struct videobuf_queue *q = bttv_queue(fh); + int res = bttv_resource(fh); + + if (check_btres(fh,res)) + return -EBUSY; + if (videobuf_queue_is_busy(q)) + return -EBUSY; + fh->type = type; + return 0; +} + +static void +pix_format_set_size (struct v4l2_pix_format * f, + const struct bttv_format * fmt, + unsigned int width, + unsigned int height) +{ + f->width = width; + f->height = height; + + if (fmt->flags & FORMAT_FLAGS_PLANAR) { + f->bytesperline = width; /* Y plane */ + f->sizeimage = (width * height * fmt->depth) >> 3; + } else { + f->bytesperline = (width * fmt->depth) >> 3; + f->sizeimage = height * f->bytesperline; + } +} + +static int bttv_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + + pix_format_set_size(&f->fmt.pix, fh->fmt, + fh->width, fh->height); + f->fmt.pix.field = fh->cap.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + + return 0; +} + +static int bttv_g_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + + f->fmt.win.w = fh->ov.w; + f->fmt.win.field = fh->ov.field; + + return 0; +} + +static int bttv_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + const struct bttv_format *fmt; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + enum v4l2_field field; + __s32 width, height; + int rc; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + + if (V4L2_FIELD_ANY == field) { + __s32 height2; + + height2 = btv->crop[!!fh->do_crop].rect.height >> 1; + field = (f->fmt.pix.height > height2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + + if (V4L2_FIELD_SEQ_BT == field) + field = V4L2_FIELD_SEQ_TB; + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + case V4L2_FIELD_INTERLACED: + break; + case V4L2_FIELD_SEQ_TB: + if (fmt->flags & FORMAT_FLAGS_PLANAR) + return -EINVAL; + break; + default: + return -EINVAL; + } + + width = f->fmt.pix.width; + height = f->fmt.pix.height; + + rc = limit_scaled_size_lock(fh, &width, &height, field, + /* width_mask: 4 pixels */ ~3, + /* width_bias: nearest */ 2, + /* adjust_size */ 1, + /* adjust_crop */ 0); + if (0 != rc) + return rc; + + /* update data for the application */ + f->fmt.pix.field = field; + pix_format_set_size(&f->fmt.pix, fmt, width, height); + + return 0; +} + +static int bttv_try_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + + return verify_window_lock(fh, &f->fmt.win, + /* adjust_size */ 1, + /* adjust_crop */ 0); +} + +static int bttv_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int retval; + const struct bttv_format *fmt; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + __s32 width, height; + enum v4l2_field field; + + retval = bttv_switch_type(fh, f->type); + if (0 != retval) + return retval; + + retval = bttv_try_fmt_vid_cap(file, priv, f); + if (0 != retval) + return retval; + + width = f->fmt.pix.width; + height = f->fmt.pix.height; + field = f->fmt.pix.field; + + retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field, + /* width_mask: 4 pixels */ ~3, + /* width_bias: nearest */ 2, + /* adjust_size */ 1, + /* adjust_crop */ 1); + if (0 != retval) + return retval; + + f->fmt.pix.field = field; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + + /* update our state informations */ + fh->fmt = fmt; + fh->cap.field = f->fmt.pix.field; + fh->cap.last = V4L2_FIELD_NONE; + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + btv->init.fmt = fmt; + btv->init.width = f->fmt.pix.width; + btv->init.height = f->fmt.pix.height; + + return 0; +} + +static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + + return setup_window_lock(fh, btv, &f->fmt.win, 1); +} + +static int bttv_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (0 == v4l2) + return -EINVAL; + + strlcpy(cap->driver, "bttv", sizeof(cap->driver)); + strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "PCI:%s", pci_name(btv->c.pci)); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (no_overlay <= 0) + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + + /* + * No need to lock here: those vars are initialized during board + * probe and remains untouched during the rest of the driver lifecycle + */ + if (btv->has_saa6588) + cap->capabilities |= V4L2_CAP_RDS_CAPTURE; + if (btv->tuner_type != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} + +static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) +{ + int index = -1, i; + + for (i = 0; i < FORMATS; i++) { + if (formats[i].fourcc != -1) + index++; + if ((unsigned int)index == f->index) + break; + } + if (FORMATS == i) + return -EINVAL; + + f->pixelformat = formats[i].fourcc; + strlcpy(f->description, formats[i].name, sizeof(f->description)); + + return i; +} + +static int bttv_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int rc = bttv_enum_fmt_cap_ovr(f); + + if (rc < 0) + return rc; + + return 0; +} + +static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int rc; + + if (no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + + rc = bttv_enum_fmt_cap_ovr(f); + + if (rc < 0) + return rc; + + if (!(formats[rc].flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + + return 0; +} + +static int bttv_g_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + *fb = btv->fbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + if (fh->ovfmt) + fb->fmt.pixelformat = fh->ovfmt->fourcc; + return 0; +} + +static int bttv_overlay(struct file *file, void *f, unsigned int on) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + struct bttv_buffer *new; + int retval = 0; + + if (on) { + /* verify args */ + if (unlikely(!btv->fbuf.base)) { + return -EINVAL; + } + if (unlikely(!fh->ov.setup_ok)) { + dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr); + retval = -EINVAL; + } + if (retval) + return retval; + } + + if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY)) + return -EBUSY; + + if (on) { + fh->ov.tvnorm = btv->tvnorm; + new = videobuf_sg_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + } else { + new = NULL; + } + + /* switch over */ + retval = bttv_switch_overlay(btv, fh, new); + return retval; +} + +static int bttv_s_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct bttv_format *fmt; + int retval; + + if (!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; + if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + + retval = -EINVAL; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + __s32 width = fb->fmt.width; + __s32 height = fb->fmt.height; + + retval = limit_scaled_size_lock(fh, &width, &height, + V4L2_FIELD_INTERLACED, + /* width_mask */ ~3, + /* width_bias */ 2, + /* adjust_size */ 0, + /* adjust_crop */ 0); + if (0 != retval) + return retval; + } + + /* ok, accept it */ + btv->fbuf.base = fb->base; + btv->fbuf.fmt.width = fb->fmt.width; + btv->fbuf.fmt.height = fb->fmt.height; + if (0 != fb->fmt.bytesperline) + btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; + else + btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; + + retval = 0; + fh->ovfmt = fmt; + btv->init.ovfmt = fmt; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + fh->ov.w.left = 0; + fh->ov.w.top = 0; + fh->ov.w.width = fb->fmt.width; + fh->ov.w.height = fb->fmt.height; + btv->init.ov.w.width = fb->fmt.width; + btv->init.ov.w.height = fb->fmt.height; + kfree(fh->ov.clips); + fh->ov.clips = NULL; + fh->ov.nclips = 0; + + if (check_btres(fh, RESOURCE_OVERLAY)) { + struct bttv_buffer *new; + + new = videobuf_sg_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + retval = bttv_switch_overlay(btv, fh, new); + } + } + return retval; +} + +static int bttv_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct bttv_fh *fh = priv; + return videobuf_reqbufs(bttv_queue(fh), p); +} + +static int bttv_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + return videobuf_querybuf(bttv_queue(fh), b); +} + +static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int res = bttv_resource(fh); + + if (!check_alloc_btres_lock(btv, fh, res)) + return -EBUSY; + + return videobuf_qbuf(bttv_queue(fh), b); +} + +static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + return videobuf_dqbuf(bttv_queue(fh), b, + file->f_flags & O_NONBLOCK); +} + +static int bttv_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int res = bttv_resource(fh); + + if (!check_alloc_btres_lock(btv, fh, res)) + return -EBUSY; + return videobuf_streamon(bttv_queue(fh)); +} + + +static int bttv_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int retval; + int res = bttv_resource(fh); + + + retval = videobuf_streamoff(bttv_queue(fh)); + if (retval < 0) + return retval; + free_btres_lock(btv, fh, res); + return 0; +} + +static int bttv_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + const struct v4l2_queryctrl *ctrl; + + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; + + if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) + *c = no_ctl; + else { + ctrl = ctrl_by_id(c->id); + + *c = (NULL != ctrl) ? *ctrl : no_ctl; + } + + return 0; +} + +static int bttv_g_parm(struct file *file, void *f, + struct v4l2_streamparm *parm) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id, + &parm->parm.capture.timeperframe); + + return 0; +} + +static int bttv_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (btv->tuner_type == TUNER_ABSENT) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + t->rxsubchans = V4L2_TUNER_SUB_MONO; + bttv_call_all(btv, tuner, g_tuner, t); + strcpy(t->name, "Television"); + t->capability = V4L2_TUNER_CAP_NORM; + t->type = V4L2_TUNER_ANALOG_TV; + if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) + t->signal = 0xffff; + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 0); + + return 0; +} + +static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + *p = v4l2_prio_max(&btv->prio); + + return 0; +} + +static int bttv_s_priority(struct file *file, void *f, + enum v4l2_priority prio) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + int rc; + + rc = v4l2_prio_change(&btv->prio, &fh->prio, prio); + + return rc; +} + +static int bttv_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + + *cap = bttv_tvnorms[btv->tvnorm].cropcap; + + return 0; +} + +static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + + /* No fh->do_crop = 1; because btv->crop[1] may be + inconsistent with fh->width or fh->height and apps + do not expect a change here. */ + + crop->c = btv->crop[!!fh->do_crop].rect; + + return 0; +} + +static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct v4l2_rect *b; + int retval; + struct bttv_crop c; + __s32 b_left; + __s32 b_top; + __s32 b_right; + __s32 b_bottom; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + + /* Make sure tvnorm, vbi_end and the current cropping + parameters remain consistent until we're done. Note + read() may change vbi_end in check_alloc_btres_lock(). */ + retval = v4l2_prio_check(&btv->prio, fh->prio); + if (0 != retval) { + return retval; + } + + retval = -EBUSY; + + if (locked_btres(fh->btv, VIDEO_RESOURCES)) { + return retval; + } + + b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; + + b_left = b->left; + b_right = b_left + b->width; + b_bottom = b->top + b->height; + + b_top = max(b->top, btv->vbi_end); + if (b_top + 32 >= b_bottom) { + return retval; + } + + /* Min. scaled size 48 x 32. */ + c.rect.left = clamp(crop->c.left, b_left, b_right - 48); + c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); + + c.rect.width = clamp(crop->c.width, + 48, b_right - c.rect.left); + + c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); + /* Top and height must be a multiple of two. */ + c.rect.top = (c.rect.top + 1) & ~1; + + c.rect.height = clamp(crop->c.height, + 32, b_bottom - c.rect.top); + c.rect.height = (c.rect.height + 1) & ~1; + + bttv_crop_calc_limits(&c); + + btv->crop[1] = c; + + fh->do_crop = 1; + + if (fh->width < c.min_scaled_width) { + fh->width = c.min_scaled_width; + btv->init.width = c.min_scaled_width; + } else if (fh->width > c.max_scaled_width) { + fh->width = c.max_scaled_width; + btv->init.width = c.max_scaled_width; + } + + if (fh->height < c.min_scaled_height) { + fh->height = c.min_scaled_height; + btv->init.height = c.min_scaled_height; + } else if (fh->height > c.max_scaled_height) { + fh->height = c.max_scaled_height; + btv->init.height = c.max_scaled_height; + } + + return 0; +} + +static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + strcpy(a->name, "audio"); + return 0; +} + +static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + return 0; +} + +static ssize_t bttv_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct bttv_fh *fh = file->private_data; + int retval = 0; + + if (fh->btv->errors) + bttv_reinit_bt848(fh->btv); + dprintk("bttv%d: read count=%d type=%s\n", + fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]); + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) { + /* VIDEO_READ in use by another fh, + or VIDEO_STREAM by any fh. */ + return -EBUSY; + } + retval = videobuf_read_one(&fh->cap, data, count, ppos, + file->f_flags & O_NONBLOCK); + free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI)) + return -EBUSY; + retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1, + file->f_flags & O_NONBLOCK); + break; + default: + BUG(); + } + return retval; +} + +static unsigned int bttv_poll(struct file *file, poll_table *wait) +{ + struct bttv_fh *fh = file->private_data; + struct bttv_buffer *buf; + enum v4l2_field field; + unsigned int rc = POLLERR; + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI)) + return POLLERR; + return videobuf_poll_stream(file, &fh->vbi, wait); + } + + if (check_btres(fh,RESOURCE_VIDEO_STREAM)) { + /* streaming capture */ + if (list_empty(&fh->cap.stream)) + goto err; + buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream); + } else { + /* read() capture */ + if (NULL == fh->cap.read_buf) { + /* need to capture a new frame */ + if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) + goto err; + fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize); + if (NULL == fh->cap.read_buf) + goto err; + fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR; + field = videobuf_next_field(&fh->cap); + if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) { + kfree (fh->cap.read_buf); + fh->cap.read_buf = NULL; + goto err; + } + fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); + fh->cap.read_off = 0; + } + buf = (struct bttv_buffer*)fh->cap.read_buf; + } + + poll_wait(file, &buf->vb.done, wait); + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) + rc = POLLIN|POLLRDNORM; + else + rc = 0; +err: + return rc; +} + +static int bttv_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct bttv *btv = video_drvdata(file); + struct bttv_fh *fh; + enum v4l2_buf_type type = 0; + + dprintk(KERN_DEBUG "bttv: open dev=%s\n", video_device_node_name(vdev)); + + if (vdev->vfl_type == VFL_TYPE_GRABBER) { + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } else if (vdev->vfl_type == VFL_TYPE_VBI) { + type = V4L2_BUF_TYPE_VBI_CAPTURE; + } else { + WARN_ON(1); + return -ENODEV; + } + + dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", + btv->c.nr,v4l2_type_names[type]); + + /* allocate per filehandle data */ + fh = kmalloc(sizeof(*fh), GFP_KERNEL); + if (unlikely(!fh)) + return -ENOMEM; + file->private_data = fh; + + *fh = btv->init; + + fh->type = type; + fh->ov.setup_ok = 0; + + v4l2_prio_open(&btv->prio, &fh->prio); + + videobuf_queue_sg_init(&fh->cap, &bttv_video_qops, + &btv->c.pci->dev, &btv->s_lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct bttv_buffer), + fh, &btv->lock); + videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops, + &btv->c.pci->dev, &btv->s_lock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, + sizeof(struct bttv_buffer), + fh, &btv->lock); + set_tvnorm(btv,btv->tvnorm); + set_input(btv, btv->input, btv->tvnorm); + + btv->users++; + + /* The V4L2 spec requires one global set of cropping parameters + which only change on request. These are stored in btv->crop[1]. + However for compatibility with V4L apps and cropping unaware + V4L2 apps we now reset the cropping parameters as seen through + this fh, which is to say VIDIOC_G_CROP and scaling limit checks + will use btv->crop[0], the default cropping parameters for the + current video standard, and VIDIOC_S_FMT will not implicitely + change the cropping parameters until VIDIOC_S_CROP has been + called. */ + fh->do_crop = !reset_crop; /* module parameter */ + + /* Likewise there should be one global set of VBI capture + parameters, but for compatibility with V4L apps and earlier + driver versions each fh has its own parameters. */ + bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm); + + bttv_field_count(btv); + return 0; +} + +static int bttv_release(struct file *file) +{ + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; + + /* turn off overlay */ + if (check_btres(fh, RESOURCE_OVERLAY)) + bttv_switch_overlay(btv,fh,NULL); + + /* stop video capture */ + if (check_btres(fh, RESOURCE_VIDEO_STREAM)) { + videobuf_streamoff(&fh->cap); + free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM); + } + if (fh->cap.read_buf) { + buffer_release(&fh->cap,fh->cap.read_buf); + kfree(fh->cap.read_buf); + } + if (check_btres(fh, RESOURCE_VIDEO_READ)) { + free_btres_lock(btv, fh, RESOURCE_VIDEO_READ); + } + + /* stop vbi capture */ + if (check_btres(fh, RESOURCE_VBI)) { + videobuf_stop(&fh->vbi); + free_btres_lock(btv,fh,RESOURCE_VBI); + } + + /* free stuff */ + + videobuf_mmap_free(&fh->cap); + videobuf_mmap_free(&fh->vbi); + v4l2_prio_close(&btv->prio, fh->prio); + file->private_data = NULL; + kfree(fh); + + btv->users--; + bttv_field_count(btv); + + if (!btv->users) + audio_mute(btv, 1); + + return 0; +} + +static int +bttv_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct bttv_fh *fh = file->private_data; + + dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n", + fh->btv->c.nr, v4l2_type_names[fh->type], + vma->vm_start, vma->vm_end - vma->vm_start); + return videobuf_mmap_mapper(bttv_queue(fh),vma); +} + +static const struct v4l2_file_operations bttv_fops = +{ + .owner = THIS_MODULE, + .open = bttv_open, + .release = bttv_release, + .unlocked_ioctl = video_ioctl2, + .read = bttv_read, + .mmap = bttv_mmap, + .poll = bttv_poll, +}; + +static const struct v4l2_ioctl_ops bttv_ioctl_ops = { + .vidioc_querycap = bttv_querycap, + .vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = bttv_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = bttv_s_fmt_vid_cap, + .vidioc_enum_fmt_vid_overlay = bttv_enum_fmt_vid_overlay, + .vidioc_g_fmt_vid_overlay = bttv_g_fmt_vid_overlay, + .vidioc_try_fmt_vid_overlay = bttv_try_fmt_vid_overlay, + .vidioc_s_fmt_vid_overlay = bttv_s_fmt_vid_overlay, + .vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap, + .vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap, + .vidioc_g_audio = bttv_g_audio, + .vidioc_s_audio = bttv_s_audio, + .vidioc_cropcap = bttv_cropcap, + .vidioc_reqbufs = bttv_reqbufs, + .vidioc_querybuf = bttv_querybuf, + .vidioc_qbuf = bttv_qbuf, + .vidioc_dqbuf = bttv_dqbuf, + .vidioc_s_std = bttv_s_std, + .vidioc_enum_input = bttv_enum_input, + .vidioc_g_input = bttv_g_input, + .vidioc_s_input = bttv_s_input, + .vidioc_queryctrl = bttv_queryctrl, + .vidioc_g_ctrl = bttv_g_ctrl, + .vidioc_s_ctrl = bttv_s_ctrl, + .vidioc_streamon = bttv_streamon, + .vidioc_streamoff = bttv_streamoff, + .vidioc_g_tuner = bttv_g_tuner, + .vidioc_s_tuner = bttv_s_tuner, + .vidioc_g_crop = bttv_g_crop, + .vidioc_s_crop = bttv_s_crop, + .vidioc_g_fbuf = bttv_g_fbuf, + .vidioc_s_fbuf = bttv_s_fbuf, + .vidioc_overlay = bttv_overlay, + .vidioc_g_priority = bttv_g_priority, + .vidioc_s_priority = bttv_s_priority, + .vidioc_g_parm = bttv_g_parm, + .vidioc_g_frequency = bttv_g_frequency, + .vidioc_s_frequency = bttv_s_frequency, + .vidioc_log_status = bttv_log_status, + .vidioc_querystd = bttv_querystd, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = bttv_g_register, + .vidioc_s_register = bttv_s_register, +#endif +}; + +static struct video_device bttv_video_template = { + .fops = &bttv_fops, + .ioctl_ops = &bttv_ioctl_ops, + .tvnorms = BTTV_NORMS, + .current_norm = V4L2_STD_PAL, +}; + +/* ----------------------------------------------------------------------- */ +/* radio interface */ + +static int radio_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct bttv *btv = video_drvdata(file); + struct bttv_fh *fh; + + dprintk("bttv: open dev=%s\n", video_device_node_name(vdev)); + + dprintk("bttv%d: open called (radio)\n",btv->c.nr); + + /* allocate per filehandle data */ + fh = kmalloc(sizeof(*fh), GFP_KERNEL); + if (unlikely(!fh)) + return -ENOMEM; + file->private_data = fh; + *fh = btv->init; + + v4l2_prio_open(&btv->prio, &fh->prio); + + btv->radio_user++; + + bttv_call_all(btv, tuner, s_radio); + audio_input(btv,TVAUDIO_INPUT_RADIO); + + return 0; +} + +static int radio_release(struct file *file) +{ + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; + struct saa6588_command cmd; + + v4l2_prio_close(&btv->prio, fh->prio); + file->private_data = NULL; + kfree(fh); + + btv->radio_user--; + + bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd); + + return 0; +} + +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + strcpy(cap->driver, "bttv"); + strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + + return 0; +} + +static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (btv->tuner_type == TUNER_ABSENT) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + bttv_call_all(btv, tuner, g_tuner, t); + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 0); + + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + strcpy(a->name, "Radio"); + + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (0 != t->index) + return -EINVAL; + + bttv_call_all(btv, tuner, g_tuner, t); + return 0; +} + +static int radio_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + return 0; +} + +static int radio_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (unlikely(i)) + return -EINVAL; + + return 0; +} + +static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctl; + + return 0; +} + +static int radio_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static ssize_t radio_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; + struct saa6588_command cmd; + cmd.block_count = count/3; + cmd.buffer = data; + cmd.instance = file; + cmd.result = -ENODEV; + + bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd); + + return cmd.result; +} + +static unsigned int radio_poll(struct file *file, poll_table *wait) +{ + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; + struct saa6588_command cmd; + cmd.instance = file; + cmd.event_list = wait; + cmd.result = -ENODEV; + bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd); + + return cmd.result; +} + +static const struct v4l2_file_operations radio_fops = +{ + .owner = THIS_MODULE, + .open = radio_open, + .read = radio_read, + .release = radio_release, + .unlocked_ioctl = video_ioctl2, + .poll = radio_poll, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_s_std = radio_s_std, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_input = radio_g_input, + .vidioc_g_ctrl = bttv_g_ctrl, + .vidioc_s_ctrl = bttv_s_ctrl, + .vidioc_g_frequency = bttv_g_frequency, + .vidioc_s_frequency = bttv_s_frequency, +}; + +static struct video_device radio_template = { + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, +}; + +/* ----------------------------------------------------------------------- */ +/* some debug code */ + +static int bttv_risc_decode(u32 risc) +{ + static char *instr[16] = { + [ BT848_RISC_WRITE >> 28 ] = "write", + [ BT848_RISC_SKIP >> 28 ] = "skip", + [ BT848_RISC_WRITEC >> 28 ] = "writec", + [ BT848_RISC_JUMP >> 28 ] = "jump", + [ BT848_RISC_SYNC >> 28 ] = "sync", + [ BT848_RISC_WRITE123 >> 28 ] = "write123", + [ BT848_RISC_SKIP123 >> 28 ] = "skip123", + [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23", + }; + static int incr[16] = { + [ BT848_RISC_WRITE >> 28 ] = 2, + [ BT848_RISC_JUMP >> 28 ] = 2, + [ BT848_RISC_SYNC >> 28 ] = 2, + [ BT848_RISC_WRITE123 >> 28 ] = 5, + [ BT848_RISC_SKIP123 >> 28 ] = 2, + [ BT848_RISC_WRITE1S23 >> 28 ] = 3, + }; + static char *bits[] = { + "be0", "be1", "be2", "be3/resync", + "set0", "set1", "set2", "set3", + "clr0", "clr1", "clr2", "clr3", + "irq", "res", "eol", "sol", + }; + int i; + + printk("0x%08x [ %s", risc, + instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + if (risc & (1 << (i + 12))) + printk(" %s",bits[i]); + printk(" count=%d ]\n", risc & 0xfff); + return incr[risc >> 28] ? incr[risc >> 28] : 1; +} + +static void bttv_risc_disasm(struct bttv *btv, + struct btcx_riscmem *risc) +{ + unsigned int i,j,n; + + printk("%s: risc disasm: %p [dma=0x%08lx]\n", + btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma); + for (i = 0; i < (risc->size >> 2); i += n) { + printk("%s: 0x%lx: ", btv->c.v4l2_dev.name, + (unsigned long)(risc->dma + (i<<2))); + n = bttv_risc_decode(le32_to_cpu(risc->cpu[i])); + for (j = 1; j < n; j++) + printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n", + btv->c.v4l2_dev.name, (unsigned long)(risc->dma + ((i+j)<<2)), + risc->cpu[i+j], j); + if (0 == risc->cpu[i]) + break; + } +} + +static void bttv_print_riscaddr(struct bttv *btv) +{ + printk(" main: %08Lx\n", + (unsigned long long)btv->main.dma); + printk(" vbi : o=%08Lx e=%08Lx\n", + btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, + btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); + printk(" cap : o=%08Lx e=%08Lx\n", + btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, + btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); + printk(" scr : o=%08Lx e=%08Lx\n", + btv->screen ? (unsigned long long)btv->screen->top.dma : 0, + btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); + bttv_risc_disasm(btv, &btv->main); +} + +/* ----------------------------------------------------------------------- */ +/* irq handler */ + +static char *irq_name[] = { + "FMTCHG", // format change detected (525 vs. 625) + "VSYNC", // vertical sync (new field) + "HSYNC", // horizontal sync + "OFLOW", // chroma/luma AGC overflow + "HLOCK", // horizontal lock changed + "VPRES", // video presence changed + "6", "7", + "I2CDONE", // hw irc operation finished + "GPINT", // gpio port triggered irq + "10", + "RISCI", // risc instruction triggered irq + "FBUS", // pixel data fifo dropped data (high pci bus latencies) + "FTRGT", // pixel data fifo overrun + "FDSR", // fifo data stream resyncronisation + "PPERR", // parity error (data transfer) + "RIPERR", // parity error (read risc instructions) + "PABORT", // pci abort + "OCERR", // risc instruction error + "SCERR", // syncronisation error +}; + +static void bttv_print_irqbits(u32 print, u32 mark) +{ + unsigned int i; + + printk("bits:"); + for (i = 0; i < ARRAY_SIZE(irq_name); i++) { + if (print & (1 << i)) + printk(" %s",irq_name[i]); + if (mark & (1 << i)) + printk("*"); + } +} + +static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc) +{ + printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", + btv->c.nr, + (unsigned long)btv->main.dma, + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]), + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]), + (unsigned long)rc); + + if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) { + printk("bttv%d: Oh, there (temporarely?) is no input signal. " + "Ok, then this is harmless, don't worry ;)\n", + btv->c.nr); + return; + } + printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n", + btv->c.nr); + printk("bttv%d: Lets try to catch the culpit red-handed ...\n", + btv->c.nr); + dump_stack(); +} + +static int +bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set) +{ + struct bttv_buffer *item; + + memset(set,0,sizeof(*set)); + + /* capture request ? */ + if (!list_empty(&btv->capture)) { + set->frame_irq = 1; + item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); + if (V4L2_FIELD_HAS_TOP(item->vb.field)) + set->top = item; + if (V4L2_FIELD_HAS_BOTTOM(item->vb.field)) + set->bottom = item; + + /* capture request for other field ? */ + if (!V4L2_FIELD_HAS_BOTH(item->vb.field) && + (item->vb.queue.next != &btv->capture)) { + item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue); + /* Mike Isely - Only check + * and set up the bottom field in the logic + * below. Don't ever do the top field. This + * of course means that if we set up the + * bottom field in the above code that we'll + * actually skip a field. But that's OK. + * Having processed only a single buffer this + * time, then the next time around the first + * available buffer should be for a top field. + * That will then cause us here to set up a + * top then a bottom field in the normal way. + * The alternative to this understanding is + * that we set up the second available buffer + * as a top field, but that's out of order + * since this driver always processes the top + * field first - the effect will be the two + * buffers being returned in the wrong order, + * with the second buffer also being delayed + * by one field time (owing to the fifo nature + * of videobuf). Worse still, we'll be stuck + * doing fields out of order now every time + * until something else causes a field to be + * dropped. By effectively forcing a field to + * drop this way then we always get back into + * sync within a single frame time. (Out of + * order fields can screw up deinterlacing + * algorithms.) */ + if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) { + if (NULL == set->bottom && + V4L2_FIELD_BOTTOM == item->vb.field) { + set->bottom = item; + } + if (NULL != set->top && NULL != set->bottom) + set->top_irq = 2; + } + } + } + + /* screen overlay ? */ + if (NULL != btv->screen) { + if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) { + if (NULL == set->top && NULL == set->bottom) { + set->top = btv->screen; + set->bottom = btv->screen; + } + } else { + if (V4L2_FIELD_TOP == btv->screen->vb.field && + NULL == set->top) { + set->top = btv->screen; + } + if (V4L2_FIELD_BOTTOM == btv->screen->vb.field && + NULL == set->bottom) { + set->bottom = btv->screen; + } + } + } + + dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n", + btv->c.nr,set->top, set->bottom, + btv->screen,set->frame_irq,set->top_irq); + return 0; +} + +static void +bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, + struct bttv_buffer_set *curr, unsigned int state) +{ + struct timeval ts; + + do_gettimeofday(&ts); + + if (wakeup->top == wakeup->bottom) { + if (NULL != wakeup->top && curr->top != wakeup->top) { + if (irq_debug > 1) + printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top); + wakeup->top->vb.ts = ts; + wakeup->top->vb.field_count = btv->field_count; + wakeup->top->vb.state = state; + wake_up(&wakeup->top->vb.done); + } + } else { + if (NULL != wakeup->top && curr->top != wakeup->top) { + if (irq_debug > 1) + printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top); + wakeup->top->vb.ts = ts; + wakeup->top->vb.field_count = btv->field_count; + wakeup->top->vb.state = state; + wake_up(&wakeup->top->vb.done); + } + if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) { + if (irq_debug > 1) + printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom); + wakeup->bottom->vb.ts = ts; + wakeup->bottom->vb.field_count = btv->field_count; + wakeup->bottom->vb.state = state; + wake_up(&wakeup->bottom->vb.done); + } + } +} + +static void +bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup, + unsigned int state) +{ + struct timeval ts; + + if (NULL == wakeup) + return; + + do_gettimeofday(&ts); + wakeup->vb.ts = ts; + wakeup->vb.field_count = btv->field_count; + wakeup->vb.state = state; + wake_up(&wakeup->vb.done); +} + +static void bttv_irq_timeout(unsigned long data) +{ + struct bttv *btv = (struct bttv *)data; + struct bttv_buffer_set old,new; + struct bttv_buffer *ovbi; + struct bttv_buffer *item; + unsigned long flags; + + if (bttv_verbose) { + printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ", + btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total, + btread(BT848_RISC_COUNT)); + bttv_print_irqbits(btread(BT848_INT_STAT),0); + printk("\n"); + } + + spin_lock_irqsave(&btv->s_lock,flags); + + /* deactivate stuff */ + memset(&new,0,sizeof(new)); + old = btv->curr; + ovbi = btv->cvbi; + btv->curr = new; + btv->cvbi = NULL; + btv->loop_irq = 0; + bttv_buffer_activate_video(btv, &new); + bttv_buffer_activate_vbi(btv, NULL); + bttv_set_dma(btv, 0); + + /* wake up */ + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR); + bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR); + + /* cancel all outstanding capture / vbi requests */ + while (!list_empty(&btv->capture)) { + item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); + list_del(&item->vb.queue); + item->vb.state = VIDEOBUF_ERROR; + wake_up(&item->vb.done); + } + while (!list_empty(&btv->vcapture)) { + item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); + list_del(&item->vb.queue); + item->vb.state = VIDEOBUF_ERROR; + wake_up(&item->vb.done); + } + + btv->errors++; + spin_unlock_irqrestore(&btv->s_lock,flags); +} + +static void +bttv_irq_wakeup_top(struct bttv *btv) +{ + struct bttv_buffer *wakeup = btv->curr.top; + + if (NULL == wakeup) + return; + + spin_lock(&btv->s_lock); + btv->curr.top_irq = 0; + btv->curr.top = NULL; + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); + + do_gettimeofday(&wakeup->vb.ts); + wakeup->vb.field_count = btv->field_count; + wakeup->vb.state = VIDEOBUF_DONE; + wake_up(&wakeup->vb.done); + spin_unlock(&btv->s_lock); +} + +static inline int is_active(struct btcx_riscmem *risc, u32 rc) +{ + if (rc < risc->dma) + return 0; + if (rc > risc->dma + risc->size) + return 0; + return 1; +} + +static void +bttv_irq_switch_video(struct bttv *btv) +{ + struct bttv_buffer_set new; + struct bttv_buffer_set old; + dma_addr_t rc; + + spin_lock(&btv->s_lock); + + /* new buffer set */ + bttv_irq_next_video(btv, &new); + rc = btread(BT848_RISC_COUNT); + if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) || + (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) { + btv->framedrop++; + if (debug_latency) + bttv_irq_debug_low_latency(btv, rc); + spin_unlock(&btv->s_lock); + return; + } + + /* switch over */ + old = btv->curr; + btv->curr = new; + btv->loop_irq &= ~1; + bttv_buffer_activate_video(btv, &new); + bttv_set_dma(btv, 0); + + /* switch input */ + if (UNSET != btv->new_input) { + video_mux(btv,btv->new_input); + btv->new_input = UNSET; + } + + /* wake up finished buffers */ + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE); + spin_unlock(&btv->s_lock); +} + +static void +bttv_irq_switch_vbi(struct bttv *btv) +{ + struct bttv_buffer *new = NULL; + struct bttv_buffer *old; + u32 rc; + + spin_lock(&btv->s_lock); + + if (!list_empty(&btv->vcapture)) + new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); + old = btv->cvbi; + + rc = btread(BT848_RISC_COUNT); + if (NULL != old && (is_active(&old->top, rc) || + is_active(&old->bottom, rc))) { + btv->framedrop++; + if (debug_latency) + bttv_irq_debug_low_latency(btv, rc); + spin_unlock(&btv->s_lock); + return; + } + + /* switch */ + btv->cvbi = new; + btv->loop_irq &= ~4; + bttv_buffer_activate_vbi(btv, new); + bttv_set_dma(btv, 0); + + bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE); + spin_unlock(&btv->s_lock); +} + +static irqreturn_t bttv_irq(int irq, void *dev_id) +{ + u32 stat,astat; + u32 dstat; + int count; + struct bttv *btv; + int handled = 0; + + btv=(struct bttv *)dev_id; + + count=0; + while (1) { + /* get/clear interrupt status bits */ + stat=btread(BT848_INT_STAT); + astat=stat&btread(BT848_INT_MASK); + if (!astat) + break; + handled = 1; + btwrite(stat,BT848_INT_STAT); + + /* get device status bits */ + dstat=btread(BT848_DSTATUS); + + if (irq_debug) { + printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d " + "riscs=%x, riscc=%08x, ", + btv->c.nr, count, btv->field_count, + stat>>28, btread(BT848_RISC_COUNT)); + bttv_print_irqbits(stat,astat); + if (stat & BT848_INT_HLOCK) + printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC) + ? "yes" : "no"); + if (stat & BT848_INT_VPRES) + printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES) + ? "yes" : "no"); + if (stat & BT848_INT_FMTCHG) + printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML) + ? "625" : "525"); + printk("\n"); + } + + if (astat&BT848_INT_VSYNC) + btv->field_count++; + + if ((astat & BT848_INT_GPINT) && btv->remote) { + bttv_input_irq(btv); + } + + if (astat & BT848_INT_I2CDONE) { + btv->i2c_done = stat; + wake_up(&btv->i2c_queue); + } + + if ((astat & BT848_INT_RISCI) && (stat & (4<<28))) + bttv_irq_switch_vbi(btv); + + if ((astat & BT848_INT_RISCI) && (stat & (2<<28))) + bttv_irq_wakeup_top(btv); + + if ((astat & BT848_INT_RISCI) && (stat & (1<<28))) + bttv_irq_switch_video(btv); + + if ((astat & BT848_INT_HLOCK) && btv->opt_automute) + audio_mute(btv, btv->mute); /* trigger automute */ + + if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) { + printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr, + (astat & BT848_INT_SCERR) ? "SCERR" : "", + (astat & BT848_INT_OCERR) ? "OCERR" : "", + btread(BT848_RISC_COUNT)); + bttv_print_irqbits(stat,astat); + printk("\n"); + if (bttv_debug) + bttv_print_riscaddr(btv); + } + if (fdsr && astat & BT848_INT_FDSR) { + printk(KERN_INFO "bttv%d: FDSR @ %08x\n", + btv->c.nr,btread(BT848_RISC_COUNT)); + if (bttv_debug) + bttv_print_riscaddr(btv); + } + + count++; + if (count > 4) { + + if (count > 8 || !(astat & BT848_INT_GPINT)) { + btwrite(0, BT848_INT_MASK); + + printk(KERN_ERR + "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr); + } else { + printk(KERN_ERR + "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr); + + btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT), + BT848_INT_MASK); + }; + + bttv_print_irqbits(stat,astat); + + printk("]\n"); + } + } + btv->irq_total++; + if (handled) + btv->irq_me++; + return IRQ_RETVAL(handled); +} + + +/* ----------------------------------------------------------------------- */ +/* initialitation */ + +static struct video_device *vdev_init(struct bttv *btv, + const struct video_device *template, + const char *type_name) +{ + struct video_device *vfd; + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->v4l2_dev = &btv->c.v4l2_dev; + vfd->release = video_device_release; + vfd->debug = bttv_debug; + video_set_drvdata(vfd, btv); + snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", + btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", + type_name, bttv_tvcards[btv->c.type].name); + return vfd; +} + +static void bttv_unregister_video(struct bttv *btv) +{ + if (btv->video_dev) { + if (video_is_registered(btv->video_dev)) + video_unregister_device(btv->video_dev); + else + video_device_release(btv->video_dev); + btv->video_dev = NULL; + } + if (btv->vbi_dev) { + if (video_is_registered(btv->vbi_dev)) + video_unregister_device(btv->vbi_dev); + else + video_device_release(btv->vbi_dev); + btv->vbi_dev = NULL; + } + if (btv->radio_dev) { + if (video_is_registered(btv->radio_dev)) + video_unregister_device(btv->radio_dev); + else + video_device_release(btv->radio_dev); + btv->radio_dev = NULL; + } +} + +/* register video4linux devices */ +static int __devinit bttv_register_video(struct bttv *btv) +{ + if (no_overlay > 0) + printk("bttv: Overlay support disabled.\n"); + + /* video */ + btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); + + if (NULL == btv->video_dev) + goto err; + if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, + video_nr[btv->c.nr]) < 0) + goto err; + printk(KERN_INFO "bttv%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->video_dev)); + if (device_create_file(&btv->video_dev->dev, + &dev_attr_card)<0) { + printk(KERN_ERR "bttv%d: device_create_file 'card' " + "failed\n", btv->c.nr); + goto err; + } + + /* vbi */ + btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi"); + + if (NULL == btv->vbi_dev) + goto err; + if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, + vbi_nr[btv->c.nr]) < 0) + goto err; + printk(KERN_INFO "bttv%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->vbi_dev)); + + if (!btv->has_radio) + return 0; + /* radio */ + btv->radio_dev = vdev_init(btv, &radio_template, "radio"); + if (NULL == btv->radio_dev) + goto err; + if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, + radio_nr[btv->c.nr]) < 0) + goto err; + printk(KERN_INFO "bttv%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->radio_dev)); + + /* all done */ + return 0; + + err: + bttv_unregister_video(btv); + return -1; +} + + +/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ +/* response on cards with no firmware is not enabled by OF */ +static void pci_set_command(struct pci_dev *dev) +{ +#if defined(__powerpc__) + unsigned int cmd; + + pci_read_config_dword(dev, PCI_COMMAND, &cmd); + cmd = (cmd | PCI_COMMAND_MEMORY ); + pci_write_config_dword(dev, PCI_COMMAND, cmd); +#endif +} + +static int __devinit bttv_probe(struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + int result; + unsigned char lat; + struct bttv *btv; + + if (bttv_num == BTTV_MAX) + return -ENOMEM; + printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); + bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL); + if (btv == NULL) { + printk(KERN_ERR "bttv: out of memory.\n"); + return -ENOMEM; + } + btv->c.nr = bttv_num; + snprintf(btv->c.v4l2_dev.name, sizeof(btv->c.v4l2_dev.name), + "bttv%d", btv->c.nr); + + /* initialize structs / fill in defaults */ + mutex_init(&btv->lock); + spin_lock_init(&btv->s_lock); + spin_lock_init(&btv->gpio_lock); + init_waitqueue_head(&btv->i2c_queue); + INIT_LIST_HEAD(&btv->c.subs); + INIT_LIST_HEAD(&btv->capture); + INIT_LIST_HEAD(&btv->vcapture); + v4l2_prio_init(&btv->prio); + + init_timer(&btv->timeout); + btv->timeout.function = bttv_irq_timeout; + btv->timeout.data = (unsigned long)btv; + + btv->i2c_rc = -1; + btv->tuner_type = UNSET; + btv->new_input = UNSET; + btv->has_radio=radio[btv->c.nr]; + + /* pci stuff (init, get irq/mmio, ... */ + btv->c.pci = dev; + btv->id = dev->device; + if (pci_enable_device(dev)) { + printk(KERN_WARNING "bttv%d: Can't enable device.\n", + btv->c.nr); + return -EIO; + } + if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { + printk(KERN_WARNING "bttv%d: No suitable DMA available.\n", + btv->c.nr); + return -EIO; + } + if (!request_mem_region(pci_resource_start(dev,0), + pci_resource_len(dev,0), + btv->c.v4l2_dev.name)) { + printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n", + btv->c.nr, + (unsigned long long)pci_resource_start(dev,0)); + return -EBUSY; + } + pci_set_master(dev); + pci_set_command(dev); + + result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev); + if (result < 0) { + printk(KERN_WARNING "bttv%d: v4l2_device_register() failed\n", btv->c.nr); + goto fail0; + } + + btv->revision = dev->revision; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ", + bttv_num,btv->id, btv->revision, pci_name(dev)); + printk("irq: %d, latency: %d, mmio: 0x%llx\n", + btv->c.pci->irq, lat, + (unsigned long long)pci_resource_start(dev,0)); + schedule(); + + btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000); + if (NULL == btv->bt848_mmio) { + printk("bttv%d: ioremap() failed\n", btv->c.nr); + result = -EIO; + goto fail1; + } + + /* identify card */ + bttv_idcard(btv); + + /* disable irqs, register irq handler */ + btwrite(0, BT848_INT_MASK); + result = request_irq(btv->c.pci->irq, bttv_irq, + IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv); + if (result < 0) { + printk(KERN_ERR "bttv%d: can't get IRQ %d\n", + bttv_num,btv->c.pci->irq); + goto fail1; + } + + if (0 != bttv_handle_chipset(btv)) { + result = -EIO; + goto fail2; + } + + /* init options from insmod args */ + btv->opt_combfilter = combfilter; + btv->opt_lumafilter = lumafilter; + btv->opt_automute = automute; + btv->opt_chroma_agc = chroma_agc; + btv->opt_adc_crush = adc_crush; + btv->opt_vcr_hack = vcr_hack; + btv->opt_whitecrush_upper = whitecrush_upper; + btv->opt_whitecrush_lower = whitecrush_lower; + btv->opt_uv_ratio = uv_ratio; + btv->opt_full_luma_range = full_luma_range; + btv->opt_coring = coring; + + /* fill struct bttv with some useful defaults */ + btv->init.btv = btv; + btv->init.ov.w.width = 320; + btv->init.ov.w.height = 240; + btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + btv->init.width = 320; + btv->init.height = 240; + btv->input = 0; + + /* initialize hardware */ + if (bttv_gpio) + bttv_gpio_tracking(btv,"pre-init"); + + bttv_risc_init_main(btv); + init_bt848(btv); + + /* gpio */ + btwrite(0x00, BT848_GPIO_REG_INP); + btwrite(0x00, BT848_GPIO_OUT_EN); + if (bttv_verbose) + bttv_gpio_tracking(btv,"init"); + + /* needs to be done before i2c is registered */ + bttv_init_card1(btv); + + /* register i2c + gpio */ + init_bttv_i2c(btv); + + /* some card-specific stuff (needs working i2c) */ + bttv_init_card2(btv); + bttv_init_tuner(btv); + init_irqreg(btv); + + /* register video4linux + input */ + if (!bttv_tvcards[btv->c.type].no_video) { + bttv_register_video(btv); + bt848_bright(btv,32768); + bt848_contrast(btv,32768); + bt848_hue(btv,32768); + bt848_sat(btv,32768); + audio_mute(btv, 1); + set_input(btv, 0, btv->tvnorm); + bttv_crop_reset(&btv->crop[0], btv->tvnorm); + btv->crop[1] = btv->crop[0]; /* current = default */ + disclaim_vbi_lines(btv); + disclaim_video_lines(btv); + } + + /* add subdevices and autoload dvb-bt8xx if needed */ + if (bttv_tvcards[btv->c.type].has_dvb) { + bttv_sub_add_device(&btv->c, "dvb"); + request_modules(btv); + } + + if (!disable_ir) { + init_bttv_i2c_ir(btv); + bttv_input_init(btv); + } + + /* everything is fine */ + bttv_num++; + return 0; + +fail2: + free_irq(btv->c.pci->irq,btv); + +fail1: + v4l2_device_unregister(&btv->c.v4l2_dev); + +fail0: + if (btv->bt848_mmio) + iounmap(btv->bt848_mmio); + release_mem_region(pci_resource_start(btv->c.pci,0), + pci_resource_len(btv->c.pci,0)); + return result; +} + +static void __devexit bttv_remove(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct bttv *btv = to_bttv(v4l2_dev); + + if (bttv_verbose) + printk("bttv%d: unloading\n",btv->c.nr); + + if (bttv_tvcards[btv->c.type].has_dvb) + flush_request_modules(btv); + + /* shutdown everything (DMA+IRQs) */ + btand(~15, BT848_GPIO_DMA_CTL); + btwrite(0, BT848_INT_MASK); + btwrite(~0x0, BT848_INT_STAT); + btwrite(0x0, BT848_GPIO_OUT_EN); + if (bttv_gpio) + bttv_gpio_tracking(btv,"cleanup"); + + /* tell gpio modules we are leaving ... */ + btv->shutdown=1; + bttv_input_fini(btv); + bttv_sub_del_devices(&btv->c); + + /* unregister i2c_bus + input */ + fini_bttv_i2c(btv); + + /* unregister video4linux */ + bttv_unregister_video(btv); + + /* free allocated memory */ + btcx_riscmem_free(btv->c.pci,&btv->main); + + /* free ressources */ + free_irq(btv->c.pci->irq,btv); + iounmap(btv->bt848_mmio); + release_mem_region(pci_resource_start(btv->c.pci,0), + pci_resource_len(btv->c.pci,0)); + + v4l2_device_unregister(&btv->c.v4l2_dev); + bttvs[btv->c.nr] = NULL; + kfree(btv); + + return; +} + +#ifdef CONFIG_PM +static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct bttv *btv = to_bttv(v4l2_dev); + struct bttv_buffer_set idle; + unsigned long flags; + + dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event); + + /* stop dma + irqs */ + spin_lock_irqsave(&btv->s_lock,flags); + memset(&idle, 0, sizeof(idle)); + btv->state.video = btv->curr; + btv->state.vbi = btv->cvbi; + btv->state.loop_irq = btv->loop_irq; + btv->curr = idle; + btv->loop_irq = 0; + bttv_buffer_activate_video(btv, &idle); + bttv_buffer_activate_vbi(btv, NULL); + bttv_set_dma(btv, 0); + btwrite(0, BT848_INT_MASK); + spin_unlock_irqrestore(&btv->s_lock,flags); + + /* save bt878 state */ + btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN); + btv->state.gpio_data = gpio_read(); + + /* save pci state */ + pci_save_state(pci_dev); + if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { + pci_disable_device(pci_dev); + btv->state.disabled = 1; + } + return 0; +} + +static int bttv_resume(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct bttv *btv = to_bttv(v4l2_dev); + unsigned long flags; + int err; + + dprintk("bttv%d: resume\n", btv->c.nr); + + /* restore pci state */ + if (btv->state.disabled) { + err=pci_enable_device(pci_dev); + if (err) { + printk(KERN_WARNING "bttv%d: Can't enable device.\n", + btv->c.nr); + return err; + } + btv->state.disabled = 0; + } + err=pci_set_power_state(pci_dev, PCI_D0); + if (err) { + pci_disable_device(pci_dev); + printk(KERN_WARNING "bttv%d: Can't enable device.\n", + btv->c.nr); + btv->state.disabled = 1; + return err; + } + + pci_restore_state(pci_dev); + + /* restore bt878 state */ + bttv_reinit_bt848(btv); + gpio_inout(0xffffff, btv->state.gpio_enable); + gpio_write(btv->state.gpio_data); + + /* restart dma */ + spin_lock_irqsave(&btv->s_lock,flags); + btv->curr = btv->state.video; + btv->cvbi = btv->state.vbi; + btv->loop_irq = btv->state.loop_irq; + bttv_buffer_activate_video(btv, &btv->curr); + bttv_buffer_activate_vbi(btv, btv->cvbi); + bttv_set_dma(btv, 0); + spin_unlock_irqrestore(&btv->s_lock,flags); + return 0; +} +#endif + +static struct pci_device_id bttv_pci_tbl[] = { + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0}, + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); + +static struct pci_driver bttv_pci_driver = { + .name = "bttv", + .id_table = bttv_pci_tbl, + .probe = bttv_probe, + .remove = __devexit_p(bttv_remove), +#ifdef CONFIG_PM + .suspend = bttv_suspend, + .resume = bttv_resume, +#endif +}; + +static int __init bttv_init_module(void) +{ + int ret; + + bttv_num = 0; + + printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", + (BTTV_VERSION_CODE >> 16) & 0xff, + (BTTV_VERSION_CODE >> 8) & 0xff, + BTTV_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) + gbuffers = 2; + if (gbufsize > BTTV_MAX_FBUF) + gbufsize = BTTV_MAX_FBUF; + gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; + if (bttv_verbose) + printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n", + gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT); + + bttv_check_chipset(); + + ret = bus_register(&bttv_sub_bus_type); + if (ret < 0) { + printk(KERN_WARNING "bttv: bus_register error: %d\n", ret); + return ret; + } + ret = pci_register_driver(&bttv_pci_driver); + if (ret < 0) + bus_unregister(&bttv_sub_bus_type); + + return ret; +} + +static void __exit bttv_cleanup_module(void) +{ + pci_unregister_driver(&bttv_pci_driver); + bus_unregister(&bttv_sub_bus_type); +} + +module_init(bttv_init_module); +module_exit(bttv_cleanup_module); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-gpio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-gpio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-gpio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-gpio.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,187 @@ +/* + + bttv-gpio.c -- gpio sub drivers + + sysfs-based sub driver interface for bttv + mainly intended for gpio access + + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2003 Gerd Knorr + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "bttvp.h" + +/* ----------------------------------------------------------------------- */ +/* internal: the bttv "bus" */ + +static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv) +{ + struct bttv_sub_driver *sub = to_bttv_sub_drv(drv); + int len = strlen(sub->wanted); + + if (0 == strncmp(dev_name(dev), sub->wanted, len)) + return 1; + return 0; +} + +static int bttv_sub_probe(struct device *dev) +{ + struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); + struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); + + return sub->probe ? sub->probe(sdev) : -ENODEV; +} + +static int bttv_sub_remove(struct device *dev) +{ + struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); + struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); + + if (sub->remove) + sub->remove(sdev); + return 0; +} + +struct bus_type bttv_sub_bus_type = { + .name = "bttv-sub", + .match = &bttv_sub_bus_match, + .probe = bttv_sub_probe, + .remove = bttv_sub_remove, +}; + +static void release_sub_device(struct device *dev) +{ + struct bttv_sub_device *sub = to_bttv_sub_dev(dev); + kfree(sub); +} + +int bttv_sub_add_device(struct bttv_core *core, char *name) +{ + struct bttv_sub_device *sub; + int err; + + sub = kzalloc(sizeof(*sub),GFP_KERNEL); + if (NULL == sub) + return -ENOMEM; + + sub->core = core; + sub->dev.parent = &core->pci->dev; + sub->dev.bus = &bttv_sub_bus_type; + sub->dev.release = release_sub_device; + dev_set_name(&sub->dev, "%s%d", name, core->nr); + + err = device_register(&sub->dev); + if (0 != err) { + kfree(sub); + return err; + } + printk("bttv%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); + list_add_tail(&sub->list,&core->subs); + return 0; +} + +int bttv_sub_del_devices(struct bttv_core *core) +{ + struct bttv_sub_device *sub, *save; + + list_for_each_entry_safe(sub, save, &core->subs, list) { + list_del(&sub->list); + device_unregister(&sub->dev); + } + return 0; +} + +/* ----------------------------------------------------------------------- */ +/* external: sub-driver register/unregister */ + +int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted) +{ + sub->drv.bus = &bttv_sub_bus_type; + snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted); + return driver_register(&sub->drv); +} +EXPORT_SYMBOL(bttv_sub_register); + +int bttv_sub_unregister(struct bttv_sub_driver *sub) +{ + driver_unregister(&sub->drv); + return 0; +} +EXPORT_SYMBOL(bttv_sub_unregister); + +/* ----------------------------------------------------------------------- */ +/* external: gpio access functions */ + +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) +{ + struct bttv *btv = container_of(core, struct bttv, c); + unsigned long flags; + u32 data; + + spin_lock_irqsave(&btv->gpio_lock,flags); + data = btread(BT848_GPIO_OUT_EN); + data = data & ~mask; + data = data | (mask & outbits); + btwrite(data,BT848_GPIO_OUT_EN); + spin_unlock_irqrestore(&btv->gpio_lock,flags); +} + +u32 bttv_gpio_read(struct bttv_core *core) +{ + struct bttv *btv = container_of(core, struct bttv, c); + u32 value; + + value = btread(BT848_GPIO_DATA); + return value; +} + +void bttv_gpio_write(struct bttv_core *core, u32 value) +{ + struct bttv *btv = container_of(core, struct bttv, c); + + btwrite(value,BT848_GPIO_DATA); +} + +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) +{ + struct bttv *btv = container_of(core, struct bttv, c); + unsigned long flags; + u32 data; + + spin_lock_irqsave(&btv->gpio_lock,flags); + data = btread(BT848_GPIO_DATA); + data = data & ~mask; + data = data | (mask & bits); + btwrite(data,BT848_GPIO_DATA); + spin_unlock_irqrestore(&btv->gpio_lock,flags); +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,376 @@ +/* + * + * bttv - Bt848 frame grabber driver + * + * card ID's and external interfaces of the bttv driver + * basically stuff needed by other drivers (i2c, lirc, ...) + * and is supported not to change much over time. + * + * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + * (c) 1999,2000 Gerd Knorr + * + */ + +#ifndef _BTTV_H_ +#define _BTTV_H_ + +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------- */ +/* exported by bttv-cards.c */ + +#define BTTV_BOARD_UNKNOWN 0x00 +#define BTTV_BOARD_MIRO 0x01 +#define BTTV_BOARD_HAUPPAUGE 0x02 +#define BTTV_BOARD_STB 0x03 +#define BTTV_BOARD_INTEL 0x04 +#define BTTV_BOARD_DIAMOND 0x05 +#define BTTV_BOARD_AVERMEDIA 0x06 +#define BTTV_BOARD_MATRIX_VISION 0x07 +#define BTTV_BOARD_FLYVIDEO 0x08 +#define BTTV_BOARD_TURBOTV 0x09 +#define BTTV_BOARD_HAUPPAUGE878 0x0a +#define BTTV_BOARD_MIROPRO 0x0b +#define BTTV_BOARD_ADSTECH_TV 0x0c +#define BTTV_BOARD_AVERMEDIA98 0x0d +#define BTTV_BOARD_VHX 0x0e +#define BTTV_BOARD_ZOLTRIX 0x0f +#define BTTV_BOARD_PIXVIEWPLAYTV 0x10 +#define BTTV_BOARD_WINVIEW_601 0x11 +#define BTTV_BOARD_AVEC_INTERCAP 0x12 +#define BTTV_BOARD_LIFE_FLYKIT 0x13 +#define BTTV_BOARD_CEI_RAFFLES 0x14 +#define BTTV_BOARD_CONFERENCETV 0x15 +#define BTTV_BOARD_PHOEBE_TVMAS 0x16 +#define BTTV_BOARD_MODTEC_205 0x17 +#define BTTV_BOARD_MAGICTVIEW061 0x18 +#define BTTV_BOARD_VOBIS_BOOSTAR 0x19 +#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a +#define BTTV_BOARD_MAXI 0x1b +#define BTTV_BOARD_TERRATV 0x1c +#define BTTV_BOARD_PXC200 0x1d +#define BTTV_BOARD_FLYVIDEO_98 0x1e +#define BTTV_BOARD_IPROTV 0x1f +#define BTTV_BOARD_INTEL_C_S_PCI 0x20 +#define BTTV_BOARD_TERRATVALUE 0x21 +#define BTTV_BOARD_WINFAST2000 0x22 +#define BTTV_BOARD_CHRONOS_VS2 0x23 +#define BTTV_BOARD_TYPHOON_TVIEW 0x24 +#define BTTV_BOARD_PXELVWPLTVPRO 0x25 +#define BTTV_BOARD_MAGICTVIEW063 0x26 +#define BTTV_BOARD_PINNACLE 0x27 +#define BTTV_BOARD_STB2 0x28 +#define BTTV_BOARD_AVPHONE98 0x29 +#define BTTV_BOARD_PV951 0x2a +#define BTTV_BOARD_ONAIR_TV 0x2b +#define BTTV_BOARD_SIGMA_TVII_FM 0x2c +#define BTTV_BOARD_MATRIX_VISION2 0x2d +#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e +#define BTTV_BOARD_TERRATVRADIO 0x2f +#define BTTV_BOARD_DYNALINK 0x30 +#define BTTV_BOARD_GVBCTV3PCI 0x31 +#define BTTV_BOARD_PXELVWPLTVPAK 0x32 +#define BTTV_BOARD_EAGLE 0x33 +#define BTTV_BOARD_PINNACLEPRO 0x34 +#define BTTV_BOARD_TVIEW_RDS_FM 0x35 +#define BTTV_BOARD_LIFETEC_9415 0x36 +#define BTTV_BOARD_BESTBUY_EASYTV 0x37 +#define BTTV_BOARD_FLYVIDEO_98FM 0x38 +#define BTTV_BOARD_GRANDTEC 0x39 +#define BTTV_BOARD_ASKEY_CPH060 0x3a +#define BTTV_BOARD_ASKEY_CPH03X 0x3b +#define BTTV_BOARD_MM100PCTV 0x3c +#define BTTV_BOARD_GMV1 0x3d +#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e +#define BTTV_BOARD_ATI_TVWONDER 0x3f +#define BTTV_BOARD_ATI_TVWONDERVE 0x40 +#define BTTV_BOARD_FLYVIDEO2000 0x41 +#define BTTV_BOARD_TERRATVALUER 0x42 +#define BTTV_BOARD_GVBCTV4PCI 0x43 +#define BTTV_BOARD_VOODOOTV_FM 0x44 +#define BTTV_BOARD_AIMMS 0x45 +#define BTTV_BOARD_PV_BT878P_PLUS 0x46 +#define BTTV_BOARD_FLYVIDEO98EZ 0x47 +#define BTTV_BOARD_PV_BT878P_9B 0x48 +#define BTTV_BOARD_SENSORAY311 0x49 +#define BTTV_BOARD_RV605 0x4a +#define BTTV_BOARD_POWERCLR_MTV878 0x4b +#define BTTV_BOARD_WINDVR 0x4c +#define BTTV_BOARD_GRANDTEC_MULTI 0x4d +#define BTTV_BOARD_KWORLD 0x4e +#define BTTV_BOARD_DSP_TCVIDEO 0x4f +#define BTTV_BOARD_HAUPPAUGEPVR 0x50 +#define BTTV_BOARD_GVBCTV5PCI 0x51 +#define BTTV_BOARD_OSPREY1x0 0x52 +#define BTTV_BOARD_OSPREY1x0_848 0x53 +#define BTTV_BOARD_OSPREY101_848 0x54 +#define BTTV_BOARD_OSPREY1x1 0x55 +#define BTTV_BOARD_OSPREY1x1_SVID 0x56 +#define BTTV_BOARD_OSPREY2xx 0x57 +#define BTTV_BOARD_OSPREY2x0_SVID 0x58 +#define BTTV_BOARD_OSPREY2x0 0x59 +#define BTTV_BOARD_OSPREY500 0x5a +#define BTTV_BOARD_OSPREY540 0x5b +#define BTTV_BOARD_OSPREY2000 0x5c +#define BTTV_BOARD_IDS_EAGLE 0x5d +#define BTTV_BOARD_PINNACLESAT 0x5e +#define BTTV_BOARD_FORMAC_PROTV 0x5f +#define BTTV_BOARD_MACHTV 0x60 +#define BTTV_BOARD_EURESYS_PICOLO 0x61 +#define BTTV_BOARD_PV150 0x62 +#define BTTV_BOARD_AD_TVK503 0x63 +#define BTTV_BOARD_HERCULES_SM_TV 0x64 +#define BTTV_BOARD_PACETV 0x65 +#define BTTV_BOARD_IVC200 0x66 +#define BTTV_BOARD_XGUARD 0x67 +#define BTTV_BOARD_NEBULA_DIGITV 0x68 +#define BTTV_BOARD_PV143 0x69 +#define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a +#define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b +#define BTTV_BOARD_VD009_MINIDIN 0x6c +#define BTTV_BOARD_VD009_COMBI 0x6d +#define BTTV_BOARD_IVC100 0x6e +#define BTTV_BOARD_IVC120 0x6f +#define BTTV_BOARD_PC_HDTV 0x70 +#define BTTV_BOARD_TWINHAN_DST 0x71 +#define BTTV_BOARD_WINFASTVC100 0x72 +#define BTTV_BOARD_TEV560 0x73 +#define BTTV_BOARD_SIMUS_GVC1100 0x74 +#define BTTV_BOARD_NGSTV_PLUS 0x75 +#define BTTV_BOARD_LMLBT4 0x76 +#define BTTV_BOARD_TEKRAM_M205 0x77 +#define BTTV_BOARD_CONTVFMI 0x78 +#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 +#define BTTV_BOARD_SPIRIT_TV 0x7a +#define BTTV_BOARD_AVDVBT_771 0x7b +#define BTTV_BOARD_AVDVBT_761 0x7c +#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d +#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e +#define BTTV_BOARD_APAC_VIEWCOMP 0x7f +#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 +#define BTTV_BOARD_VGEAR_MYVCD 0x81 +#define BTTV_BOARD_SUPER_TV 0x82 +#define BTTV_BOARD_TIBET_CS16 0x83 +#define BTTV_BOARD_KODICOM_4400R 0x84 +#define BTTV_BOARD_KODICOM_4400R_SL 0x85 +#define BTTV_BOARD_ADLINK_RTV24 0x86 +#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 +#define BTTV_BOARD_ACORP_Y878F 0x88 +#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 +#define BTTV_BOARD_PV_BT878P_2E 0x8a +#define BTTV_BOARD_PV_M4900 0x8b +#define BTTV_BOARD_OSPREY440 0x8c +#define BTTV_BOARD_ASOUND_SKYEYE 0x8d +#define BTTV_BOARD_SABRENT_TVFM 0x8e +#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f +#define BTTV_BOARD_MACHTV_MAGICTV 0x90 +#define BTTV_BOARD_SSAI_SECURITY 0x91 +#define BTTV_BOARD_SSAI_ULTRASOUND 0x92 +#define BTTV_BOARD_VOODOOTV_200 0x93 +#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 +#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 +#define BTTV_BOARD_GEOVISION_GV600 0x96 +#define BTTV_BOARD_KOZUMI_KTV_01C 0x97 +#define BTTV_BOARD_ENLTV_FM_2 0x98 +#define BTTV_BOARD_VD012 0x99 +#define BTTV_BOARD_VD012_X1 0x9a +#define BTTV_BOARD_VD012_X2 0x9b +#define BTTV_BOARD_IVCE8784 0x9c +#define BTTV_BOARD_GEOVISION_GV800S 0x9d +#define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e +#define BTTV_BOARD_PV183 0x9f + + +/* more card-specific defines */ +#define PT2254_L_CHANNEL 0x10 +#define PT2254_R_CHANNEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#define PT2254_DBS_IN_10 0x20000 +#define WINVIEW_PT2254_CLK 0x40 +#define WINVIEW_PT2254_DATA 0x20 +#define WINVIEW_PT2254_STROBE 0x80 + +struct bttv_core { + /* device structs */ + struct v4l2_device v4l2_dev; + struct pci_dev *pci; + struct i2c_adapter i2c_adap; + struct list_head subs; /* struct bttv_sub_device */ + + /* device config */ + unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ + unsigned int type; /* card type (pointer into tvcards[]) */ +}; + +struct bttv; + +struct tvcard { + char *name; + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); + + /* MUX bits for each input, two bits per input starting with the LSB */ + u32 muxsel; /* Use MUXSEL() to set */ + + u32 gpiomask; + u32 gpiomux[4]; /* Tuner, Radio, external, internal */ + u32 gpiomute; /* GPIO mute setting */ + u32 gpiomask2; /* GPIO MUX mask */ + + unsigned int tuner_type; + u8 tuner_addr; + u8 video_inputs; /* Number of inputs */ + unsigned int svhs:4; /* Which input is s-video */ +#define NO_SVHS 15 + unsigned int pll:2; +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 + + /* i2c audio flags */ + unsigned int no_msp34xx:1; + unsigned int no_tda7432:1; + unsigned int needs_tvaudio:1; + unsigned int msp34xx_alt:1; + /* Note: currently no card definition needs to mark the presence + of a RDS saa6588 chip. If this is ever needed, then add a new + 'has_saa6588' bit here. */ + + unsigned int no_video:1; /* video pci function is unused */ + unsigned int has_dvb:1; + unsigned int has_remote:1; + unsigned int has_radio:1; + unsigned int has_dig_in:1; /* Has digital input (always last input) */ + unsigned int no_gpioirq:1; +}; + +extern struct tvcard bttv_tvcards[]; + +/* + * This bit of cpp voodoo is used to create a macro with a variable number of + * arguments (1 to 16). It will pack each argument into a word two bits at a + * time. It can't be a function because it needs to be compile time constant to + * initialize structures. Since each argument must fit in two bits, it's ok + * that they are changed to octal. One should not use hex number, macros, or + * anything else with this macro. Just use plain integers from 0 to 3. + */ +#define _MUXSELf(a) 0##a << 30 +#define _MUXSELe(a, b...) 0##a << 28 | _MUXSELf(b) +#define _MUXSELd(a, b...) 0##a << 26 | _MUXSELe(b) +#define _MUXSELc(a, b...) 0##a << 24 | _MUXSELd(b) +#define _MUXSELb(a, b...) 0##a << 22 | _MUXSELc(b) +#define _MUXSELa(a, b...) 0##a << 20 | _MUXSELb(b) +#define _MUXSEL9(a, b...) 0##a << 18 | _MUXSELa(b) +#define _MUXSEL8(a, b...) 0##a << 16 | _MUXSEL9(b) +#define _MUXSEL7(a, b...) 0##a << 14 | _MUXSEL8(b) +#define _MUXSEL6(a, b...) 0##a << 12 | _MUXSEL7(b) +#define _MUXSEL5(a, b...) 0##a << 10 | _MUXSEL6(b) +#define _MUXSEL4(a, b...) 0##a << 8 | _MUXSEL5(b) +#define _MUXSEL3(a, b...) 0##a << 6 | _MUXSEL4(b) +#define _MUXSEL2(a, b...) 0##a << 4 | _MUXSEL3(b) +#define _MUXSEL1(a, b...) 0##a << 2 | _MUXSEL2(b) +#define MUXSEL(a, b...) (a | _MUXSEL1(b)) + +/* identification / initialization of the card */ +extern void bttv_idcard(struct bttv *btv); +extern void bttv_init_card1(struct bttv *btv); +extern void bttv_init_card2(struct bttv *btv); +extern void bttv_init_tuner(struct bttv *btv); + +/* card-specific funtions */ +extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); +extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits); + +/* extra tweaks for some chipsets */ +extern void bttv_check_chipset(void); +extern int bttv_handle_chipset(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* exported by bttv-if.c */ + +/* this obsolete -- please use the sysfs-based + interface below for new code */ + +extern struct pci_dev* bttv_get_pcidev(unsigned int card); + +/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: + data | (current_GPOE_value & ~mask) + returns negative value if error occurred +*/ +extern int bttv_gpio_enable(unsigned int card, + unsigned long mask, unsigned long data); + +/* fills data with GPDATA register contents + returns negative value if error occurred +*/ +extern int bttv_read_gpio(unsigned int card, unsigned long *data); + +/* sets GPDATA register to new value: + (data & mask) | (current_GPDATA_value & ~mask) + returns negative value if error occurred +*/ +extern int bttv_write_gpio(unsigned int card, + unsigned long mask, unsigned long data); + + + + +/* ---------------------------------------------------------- */ +/* sysfs/driver-moded based gpio access interface */ + +struct bttv_sub_device { + struct device dev; + struct bttv_core *core; + struct list_head list; +}; +#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) + +struct bttv_sub_driver { + struct device_driver drv; + char wanted[20]; + int (*probe)(struct bttv_sub_device *sub); + void (*remove)(struct bttv_sub_device *sub); +}; +#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) + +int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); +int bttv_sub_unregister(struct bttv_sub_driver *drv); + +/* gpio access functions */ +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); +u32 bttv_gpio_read(struct bttv_core *core); +void bttv_gpio_write(struct bttv_core *core, u32 value); +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); + +#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) +#define gpio_read() bttv_gpio_read(&btv->c) +#define gpio_write(value) bttv_gpio_write(&btv->c, value) +#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) + + +/* ---------------------------------------------------------- */ +/* i2c */ + +#define bttv_call_all(btv, o, f, args...) \ + v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args) + +extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); +extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both); +extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); + +extern int bttv_input_init(struct bttv *dev); +extern void bttv_input_fini(struct bttv *dev); +extern void bttv_input_irq(struct bttv *dev); + +#endif /* _BTTV_H_ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,391 @@ +/* + + bttv-i2c.c -- all the i2c code is here + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2003 Gerd Knorr + + (c) 2005 Mauro Carvalho Chehab + - Multituner support and i2c address binding + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include + +#include "bttvp.h" +#include +#include +#include + +static int i2c_debug; +static int i2c_hw; +static int i2c_scan; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "configure i2c debug level"); +module_param(i2c_hw, int, 0444); +MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, " + "instead of software bitbang"); +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); + +static unsigned int i2c_udelay = 5; +module_param(i2c_udelay, int, 0444); +MODULE_PARM_DESC(i2c_udelay,"soft i2c delay at insmod time, in usecs " + "(should be 5 or higher). Lower value means higher bus speed."); + +/* ----------------------------------------------------------------------- */ +/* I2C functions - bitbanging adapter (software i2c) */ + +static void bttv_bit_setscl(void *data, int state) +{ + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x02; + else + btv->i2c_state &= ~0x02; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); +} + +static void bttv_bit_setsda(void *data, int state) +{ + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x01; + else + btv->i2c_state &= ~0x01; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); +} + +static int bttv_bit_getscl(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x02 ? 1 : 0; + return state; +} + +static int bttv_bit_getsda(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x01; + return state; +} + +static struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = { + .setsda = bttv_bit_setsda, + .setscl = bttv_bit_setscl, + .getsda = bttv_bit_getsda, + .getscl = bttv_bit_getscl, + .udelay = 16, + .timeout = 200, +}; + +/* ----------------------------------------------------------------------- */ +/* I2C functions - hardware i2c */ + +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static int +bttv_i2c_wait_done(struct bttv *btv) +{ + int rc = 0; + + /* timeout */ + if (wait_event_interruptible_timeout(btv->i2c_queue, + btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS) + rc = -EIO; + + if (btv->i2c_done & BT848_INT_RACK) + rc = 1; + btv->i2c_done = 0; + return rc; +} + +#define I2C_HW (BT878_I2C_MODE | BT848_I2C_SYNC |\ + BT848_I2C_SCL | BT848_I2C_SDA) + +static int +bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) +{ + u32 xmit; + int retval,cnt; + + /* sanity checks */ + if (0 == msg->len) + return -EINVAL; + + /* start, address + first byte */ + xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW; + if (msg->len > 1 || !last) + xmit |= BT878_I2C_NOSTOP; + btwrite(xmit, BT848_I2C); + retval = bttv_i2c_wait_done(btv); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" addr << 1, msg->buf[0]); + if (!(xmit & BT878_I2C_NOSTOP)) + printk(" >\n"); + } + + for (cnt = 1; cnt < msg->len; cnt++ ) { + /* following bytes */ + xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART; + if (cnt < msg->len-1 || !last) + xmit |= BT878_I2C_NOSTOP; + btwrite(xmit, BT848_I2C); + retval = bttv_i2c_wait_done(btv); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" %02x", msg->buf[cnt]); + if (!(xmit & BT878_I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + if (i2c_debug) + printk(" ERR: %d\n",retval); + return retval; +} + +static int +bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) +{ + u32 xmit; + u32 cnt; + int retval; + + for(cnt = 0; cnt < msg->len; cnt++) { + xmit = (msg->addr << 25) | (1 << 24) | I2C_HW; + if (cnt < msg->len-1) + xmit |= BT848_I2C_W3B; + if (cnt < msg->len-1 || !last) + xmit |= BT878_I2C_NOSTOP; + if (cnt) + xmit |= BT878_I2C_NOSTART; + btwrite(xmit, BT848_I2C); + retval = bttv_i2c_wait_done(btv); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff; + if (i2c_debug) { + if (!(xmit & BT878_I2C_NOSTART)) + printk(" addr << 1) +1); + printk(" =%02x", msg->buf[cnt]); + if (!(xmit & BT878_I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + if (i2c_debug) + printk(" ERR: %d\n",retval); + return retval; +} + +static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap); + struct bttv *btv = to_bttv(v4l2_dev); + int retval = 0; + int i; + + if (i2c_debug) + printk("bt-i2c:"); + btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); + for (i = 0 ; i < num; i++) { + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } else { + /* write */ + retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } + } + return num; + + err: + return retval; +} + +static const struct i2c_algorithm bttv_algo = { + .master_xfer = bttv_i2c_xfer, + .functionality = functionality, +}; + +/* ----------------------------------------------------------------------- */ +/* I2C functions - common stuff */ + +/* read I2C */ +int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) +{ + unsigned char buffer = 0; + + if (0 != btv->i2c_rc) + return -1; + if (bttv_verbose && NULL != probe_for) + printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", + btv->c.nr,probe_for,addr); + btv->i2c_client.addr = addr >> 1; + if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { + if (NULL != probe_for) { + if (bttv_verbose) + printk("not found\n"); + } else + printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", + btv->c.nr,addr); + return -1; + } + if (bttv_verbose && NULL != probe_for) + printk("found\n"); + return buffer; +} + +/* write I2C */ +int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both) +{ + unsigned char buffer[2]; + int bytes = both ? 2 : 1; + + if (0 != btv->i2c_rc) + return -1; + btv->i2c_client.addr = addr >> 1; + buffer[0] = b1; + buffer[1] = b2; + if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) + return -1; + return 0; +} + +/* read EEPROM content */ +void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) +{ + memset(eedata, 0, 256); + if (0 != btv->i2c_rc) + return; + btv->i2c_client.addr = addr >> 1; + tveeprom_read(&btv->i2c_client, eedata, 256); +} + +static char *i2c_devs[128] = { + [ 0x1c >> 1 ] = "lgdt330x", + [ 0x30 >> 1 ] = "IR (hauppauge)", + [ 0x80 >> 1 ] = "msp34xx", + [ 0x86 >> 1 ] = "tda9887", + [ 0xa0 >> 1 ] = "eeprom", + [ 0xc0 >> 1 ] = "tuner (analog)", + [ 0xc2 >> 1 ] = "tuner (analog)", +}; + +static void do_i2c_scan(char *name, struct i2c_client *c) +{ + unsigned char buf; + int i,rc; + + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { + c->addr = i; + rc = i2c_master_recv(c,&buf,0); + if (rc < 0) + continue; + printk("%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + } +} + +/* init + register i2c algo-bit adapter */ +int __devinit init_bttv_i2c(struct bttv *btv) +{ + strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE); + + if (i2c_hw) + btv->use_i2c_hw = 1; + if (btv->use_i2c_hw) { + /* bt878 */ + strlcpy(btv->c.i2c_adap.name, "bt878", + sizeof(btv->c.i2c_adap.name)); + btv->c.i2c_adap.algo = &bttv_algo; + } else { + /* bt848 */ + /* Prevents usage of invalid delay values */ + if (i2c_udelay<5) + i2c_udelay=5; + + strlcpy(btv->c.i2c_adap.name, "bttv", + sizeof(btv->c.i2c_adap.name)); + memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template, + sizeof(bttv_i2c_algo_bit_template)); + btv->i2c_algo.udelay = i2c_udelay; + btv->i2c_algo.data = btv; + btv->c.i2c_adap.algo_data = &btv->i2c_algo; + } + btv->c.i2c_adap.owner = THIS_MODULE; + + btv->c.i2c_adap.dev.parent = &btv->c.pci->dev; + snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name), + "bt%d #%d [%s]", btv->id, btv->c.nr, + btv->use_i2c_hw ? "hw" : "sw"); + + i2c_set_adapdata(&btv->c.i2c_adap, &btv->c.v4l2_dev); + btv->i2c_client.adapter = &btv->c.i2c_adap; + + + if (btv->use_i2c_hw) { + btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap); + } else { + bttv_bit_setscl(btv,1); + bttv_bit_setsda(btv,1); + btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap); + } + if (0 == btv->i2c_rc && i2c_scan) + do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client); + + return btv->i2c_rc; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-if.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-if.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-if.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-if.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,121 @@ +/* + + bttv-if.c -- old gpio interface to other kernel modules + don't use in new code, will go away in 2.7 + have a look at bttv-gpio.c instead. + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2003 Gerd Knorr + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include + +#include "bttvp.h" + +EXPORT_SYMBOL(bttv_get_pcidev); +EXPORT_SYMBOL(bttv_gpio_enable); +EXPORT_SYMBOL(bttv_read_gpio); +EXPORT_SYMBOL(bttv_write_gpio); + +/* ----------------------------------------------------------------------- */ +/* Exported functions - for other modules which want to access the */ +/* gpio ports (IR for example) */ +/* see bttv.h for comments */ + +struct pci_dev* bttv_get_pcidev(unsigned int card) +{ + if (card >= bttv_num) + return NULL; + if (!bttvs[card]) + return NULL; + + return bttvs[card]->c.pci; +} + + +int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = bttvs[card]; + if (!btv) + return -ENODEV; + + gpio_inout(mask,data); + if (bttv_gpio) + bttv_gpio_tracking(btv,"extern enable"); + return 0; +} + +int bttv_read_gpio(unsigned int card, unsigned long *data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = bttvs[card]; + if (!btv) + return -ENODEV; + + if(btv->shutdown) { + return -ENODEV; + } + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because we set direct input on init */ + *data = gpio_read(); + return 0; +} + +int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = bttvs[card]; + if (!btv) + return -ENODEV; + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because direct input is set on init */ + gpio_bits(mask,data); + if (bttv_gpio) + bttv_gpio_tracking(btv,"extern write"); + return 0; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-input.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-input.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,588 @@ +/* + * + * Copyright (c) 2003 Gerd Knorr + * Copyright (c) 2003 Pavel Machek + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "bttvp.h" + + +static int ir_debug; +module_param(ir_debug, int, 0644); + +static int ir_rc5_remote_gap = 885; +module_param(ir_rc5_remote_gap, int, 0644); + +#undef dprintk +#define dprintk(arg...) do { \ + if (ir_debug >= 1) \ + printk(arg); \ +} while (0) + +#define DEVNAME "bttv-input" + +#define MODULE_NAME "bttv" + +/* ---------------------------------------------------------------------- */ + +static void ir_handle_key(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + u32 gpio,data; + + /* read gpio value */ + gpio = bttv_gpio_read(&btv->c); + if (ir->polling) { + if (ir->last_gpio == gpio) + return; + ir->last_gpio = gpio; + } + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n", + gpio, data, + ir->polling ? "poll" : "irq", + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); + + if ((ir->mask_keydown && (gpio & ir->mask_keydown)) || + (ir->mask_keyup && !(gpio & ir->mask_keyup))) { + rc_keydown_notimeout(ir->dev, data, 0); + } else { + /* HACK: Probably, ir->mask_keydown is missing + for this board */ + if (btv->c.type == BTTV_BOARD_WINFAST2000) + rc_keydown_notimeout(ir->dev, data, 0); + + rc_keyup(ir->dev); + } +} + +static void ir_enltv_handle_key(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + u32 gpio, data, keyup; + + /* read gpio value */ + gpio = bttv_gpio_read(&btv->c); + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + + /* Check if it is keyup */ + keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; + + if ((ir->last_gpio & 0x7f) != data) { + dprintk(KERN_INFO DEVNAME ": gpio=0x%x code=%d | %s\n", + gpio, data, + (gpio & ir->mask_keyup) ? " up" : "up/down"); + + rc_keydown_notimeout(ir->dev, data, 0); + if (keyup) + rc_keyup(ir->dev); + } else { + if ((ir->last_gpio & 1 << 31) == keyup) + return; + + dprintk(KERN_INFO DEVNAME ":(cnt) gpio=0x%x code=%d | %s\n", + gpio, data, + (gpio & ir->mask_keyup) ? " up" : "down"); + + if (keyup) + rc_keyup(ir->dev); + else + rc_keydown_notimeout(ir->dev, data, 0); + } + + ir->last_gpio = data | keyup; +} + +static int bttv_rc5_irq(struct bttv *btv); + +void bttv_input_irq(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + + if (ir->rc5_gpio) + bttv_rc5_irq(btv); + else if (!ir->polling) + ir_handle_key(btv); +} + +static void bttv_input_timer(unsigned long data) +{ + struct bttv *btv = (struct bttv*)data; + struct bttv_ir *ir = btv->remote; + + if (btv->c.type == BTTV_BOARD_ENLTV_FM_2) + ir_enltv_handle_key(btv); + else + ir_handle_key(btv); + mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); +} + +/* + * FIXME: Nebula digi uses the legacy way to decode RC5, instead of relying + * on the rc-core way. As we need to be sure that both IRQ transitions are + * properly triggered, Better to touch it only with this hardware for + * testing. + */ + +#define RC5_START(x) (((x) >> 12) & 3) +#define RC5_TOGGLE(x) (((x) >> 11) & 1) +#define RC5_ADDR(x) (((x) >> 6) & 31) +#define RC5_INSTR(x) ((x) & 63) + +/* decode raw bit pattern to RC5 code */ +static u32 bttv_rc5_decode(unsigned int code) +{ + unsigned int org_code = code; + unsigned int pair; + unsigned int rc5 = 0; + int i; + + for (i = 0; i < 14; ++i) { + pair = code & 0x3; + code >>= 2; + + rc5 <<= 1; + switch (pair) { + case 0: + case 2: + break; + case 1: + rc5 |= 1; + break; + case 3: + dprintk(KERN_INFO DEVNAME ":rc5_decode(%x) bad code\n", + org_code); + return 0; + } + } + dprintk(KERN_INFO DEVNAME ":" + "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " + "instr=%x\n", rc5, org_code, RC5_START(rc5), + RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); + return rc5; +} + +static void bttv_rc5_timer_end(unsigned long data) +{ + struct bttv_ir *ir = (struct bttv_ir *)data; + struct timeval tv; + u32 gap; + u32 rc5 = 0; + + /* get time */ + do_gettimeofday(&tv); + + /* avoid overflow with gap >1s */ + if (tv.tv_sec - ir->base_time.tv_sec > 1) { + gap = 200000; + } else { + gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + + tv.tv_usec - ir->base_time.tv_usec; + } + + /* signal we're ready to start a new code */ + ir->active = false; + + /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */ + if (gap < 28000) { + dprintk(KERN_INFO DEVNAME ": spurious timer_end\n"); + return; + } + + if (ir->last_bit < 20) { + /* ignore spurious codes (caused by light/other remotes) */ + dprintk(KERN_INFO DEVNAME ": short code: %x\n", ir->code); + } else { + ir->code = (ir->code << ir->shift_by) | 1; + rc5 = bttv_rc5_decode(ir->code); + + /* two start bits? */ + if (RC5_START(rc5) != ir->start) { + printk(KERN_INFO DEVNAME ":" + " rc5 start bits invalid: %u\n", RC5_START(rc5)); + + /* right address? */ + } else if (RC5_ADDR(rc5) == ir->addr) { + u32 toggle = RC5_TOGGLE(rc5); + u32 instr = RC5_INSTR(rc5); + + /* Good code */ + rc_keydown(ir->dev, instr, toggle); + dprintk(KERN_INFO DEVNAME ":" + " instruction %x, toggle %x\n", + instr, toggle); + } + } +} + +static int bttv_rc5_irq(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + struct timeval tv; + u32 gpio; + u32 gap; + unsigned long current_jiffies; + + /* read gpio port */ + gpio = bttv_gpio_read(&btv->c); + + /* get time of bit */ + current_jiffies = jiffies; + do_gettimeofday(&tv); + + /* avoid overflow with gap >1s */ + if (tv.tv_sec - ir->base_time.tv_sec > 1) { + gap = 200000; + } else { + gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + + tv.tv_usec - ir->base_time.tv_usec; + } + + dprintk(KERN_INFO DEVNAME ": RC5 IRQ: gap %d us for %s\n", + gap, (gpio & 0x20) ? "mark" : "space"); + + /* remote IRQ? */ + if (!(gpio & 0x20)) + return 0; + + /* active code => add bit */ + if (ir->active) { + /* only if in the code (otherwise spurious IRQ or timer + late) */ + if (ir->last_bit < 28) { + ir->last_bit = (gap - ir_rc5_remote_gap / 2) / + ir_rc5_remote_gap; + ir->code |= 1 << ir->last_bit; + } + /* starting new code */ + } else { + ir->active = true; + ir->code = 0; + ir->base_time = tv; + ir->last_bit = 0; + + mod_timer(&ir->timer, current_jiffies + msecs_to_jiffies(30)); + } + + /* toggle GPIO pin 4 to reset the irq */ + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + bttv_gpio_write(&btv->c, gpio | (1 << 4)); + return 1; +} + +/* ---------------------------------------------------------------------- */ + +static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir) +{ + if (ir->polling) { + setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv); + ir->timer.expires = jiffies + msecs_to_jiffies(1000); + add_timer(&ir->timer); + } else if (ir->rc5_gpio) { + /* set timer_end for code completion */ + setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir); + ir->shift_by = 1; + ir->start = 3; + ir->addr = 0x0; + ir->rc5_remote_gap = ir_rc5_remote_gap; + } +} + +static void bttv_ir_stop(struct bttv *btv) +{ + if (btv->remote->polling) + del_timer_sync(&btv->remote->timer); + + if (btv->remote->rc5_gpio) { + u32 gpio; + + del_timer_sync(&btv->remote->timer); + + gpio = bttv_gpio_read(&btv->c); + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + } +} + +/* + * Get_key functions used by I2C remotes + */ + +static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b; + + /* poll IR chip */ + if (1 != i2c_master_recv(ir->c, &b, 1)) { + dprintk(KERN_INFO DEVNAME ": read error\n"); + return -EIO; + } + + /* ignore 0xaa */ + if (b==0xaa) + return 0; + dprintk(KERN_INFO DEVNAME ": key %02x\n", b); + + /* + * NOTE: + * lirc_i2c maps the pv951 code as: + * addr = 0x61D6 + * cmd = bit_reverse (b) + * So, it seems that this device uses NEC extended + * I decided to not fix the table, due to two reasons: + * 1) Without the actual device, this is only a guess; + * 2) As the addr is not reported via I2C, nor can be changed, + * the device is bound to the vendor-provided RC. + */ + + *ir_key = b; + *ir_raw = b; + return 1; +} + +/* Instantiate the I2C IR receiver device, if present */ +void __devinit init_bttv_i2c_ir(struct bttv *btv) +{ + const unsigned short addr_list[] = { + 0x1a, 0x18, 0x64, 0x30, 0x71, + I2C_CLIENT_END + }; + struct i2c_board_info info; + + if (0 != btv->i2c_rc) + return; + + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&btv->init_data, 0, sizeof(btv->init_data)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + + switch (btv->c.type) { + case BTTV_BOARD_PV951: + btv->init_data.name = "PV951"; + btv->init_data.get_key = get_key_pv951; + btv->init_data.ir_codes = RC_MAP_PV951; + info.addr = 0x4b; + break; + default: + /* + * The external IR receiver is at i2c address 0x34 (0x35 for + * reads). Future Hauppauge cards will have an internal + * receiver at 0x30 (0x31 for reads). In theory, both can be + * fitted, and Hauppauge suggest an external overrides an + * internal. + * That's why we probe 0x1a (~0x34) first. CB + */ + + i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); + return; + } + + if (btv->init_data.name) + info.platform_data = &btv->init_data; + i2c_new_device(&btv->c.i2c_adap, &info); + + return; +} + +int __devexit fini_bttv_i2c(struct bttv *btv) +{ + if (0 != btv->i2c_rc) + return 0; + + return i2c_del_adapter(&btv->c.i2c_adap); +} + +int bttv_input_init(struct bttv *btv) +{ + struct bttv_ir *ir; + char *ir_codes = NULL; + struct rc_dev *rc; + int err = -ENOMEM; + + if (!btv->has_remote) + return -ENODEV; + + ir = kzalloc(sizeof(*ir),GFP_KERNEL); + rc = rc_allocate_device(); + if (!ir || !rc) + goto err_out_free; + + /* detect & configure */ + switch (btv->c.type) { + case BTTV_BOARD_AVERMEDIA: + case BTTV_BOARD_AVPHONE98: + case BTTV_BOARD_AVERMEDIA98: + ir_codes = RC_MAP_AVERMEDIA; + ir->mask_keycode = 0xf88000; + ir->mask_keydown = 0x010000; + ir->polling = 50; // ms + break; + + case BTTV_BOARD_AVDVBT_761: + case BTTV_BOARD_AVDVBT_771: + ir_codes = RC_MAP_AVERMEDIA_DVBT; + ir->mask_keycode = 0x0f00c0; + ir->mask_keydown = 0x000020; + ir->polling = 50; // ms + break; + + case BTTV_BOARD_PXELVWPLTVPAK: + ir_codes = RC_MAP_PIXELVIEW; + ir->mask_keycode = 0x003e00; + ir->mask_keyup = 0x010000; + ir->polling = 50; // ms + break; + case BTTV_BOARD_PV_M4900: + case BTTV_BOARD_PV_BT878P_9B: + case BTTV_BOARD_PV_BT878P_PLUS: + ir_codes = RC_MAP_PIXELVIEW; + ir->mask_keycode = 0x001f00; + ir->mask_keyup = 0x008000; + ir->polling = 50; // ms + break; + + case BTTV_BOARD_WINFAST2000: + ir_codes = RC_MAP_WINFAST; + ir->mask_keycode = 0x1f8; + break; + case BTTV_BOARD_MAGICTVIEW061: + case BTTV_BOARD_MAGICTVIEW063: + ir_codes = RC_MAP_WINFAST; + ir->mask_keycode = 0x0008e000; + ir->mask_keydown = 0x00200000; + break; + case BTTV_BOARD_APAC_VIEWCOMP: + ir_codes = RC_MAP_APAC_VIEWCOMP; + ir->mask_keycode = 0x001f00; + ir->mask_keyup = 0x008000; + ir->polling = 50; // ms + break; + case BTTV_BOARD_ASKEY_CPH03X: + case BTTV_BOARD_CONCEPTRONIC_CTVFMI2: + case BTTV_BOARD_CONTVFMI: + ir_codes = RC_MAP_PIXELVIEW; + ir->mask_keycode = 0x001F00; + ir->mask_keyup = 0x006000; + ir->polling = 50; // ms + break; + case BTTV_BOARD_NEBULA_DIGITV: + ir_codes = RC_MAP_NEBULA; + ir->rc5_gpio = true; + break; + case BTTV_BOARD_MACHTV_MAGICTV: + ir_codes = RC_MAP_APAC_VIEWCOMP; + ir->mask_keycode = 0x001F00; + ir->mask_keyup = 0x004000; + ir->polling = 50; /* ms */ + break; + case BTTV_BOARD_KOZUMI_KTV_01C: + ir_codes = RC_MAP_PCTV_SEDNA; + ir->mask_keycode = 0x001f00; + ir->mask_keyup = 0x006000; + ir->polling = 50; /* ms */ + break; + case BTTV_BOARD_ENLTV_FM_2: + ir_codes = RC_MAP_ENCORE_ENLTV2; + ir->mask_keycode = 0x00fd00; + ir->mask_keyup = 0x000080; + ir->polling = 1; /* ms */ + ir->last_gpio = ir_extract_bits(bttv_gpio_read(&btv->c), + ir->mask_keycode); + break; + } + if (NULL == ir_codes) { + dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type); + err = -ENODEV; + goto err_out_free; + } + + if (ir->rc5_gpio) { + u32 gpio; + /* enable remote irq */ + bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4); + gpio = bttv_gpio_read(&btv->c); + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + bttv_gpio_write(&btv->c, gpio | (1 << 4)); + } else { + /* init hardware-specific stuff */ + bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0); + } + + /* init input device */ + ir->dev = rc; + + snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", + btv->c.type); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", + pci_name(btv->c.pci)); + + rc->input_name = ir->name; + rc->input_phys = ir->phys; + rc->input_id.bustype = BUS_PCI; + rc->input_id.version = 1; + if (btv->c.pci->subsystem_vendor) { + rc->input_id.vendor = btv->c.pci->subsystem_vendor; + rc->input_id.product = btv->c.pci->subsystem_device; + } else { + rc->input_id.vendor = btv->c.pci->vendor; + rc->input_id.product = btv->c.pci->device; + } + rc->dev.parent = &btv->c.pci->dev; + rc->map_name = ir_codes; + rc->driver_name = MODULE_NAME; + + btv->remote = ir; + bttv_ir_start(btv, ir); + + /* all done */ + err = rc_register_device(rc); + if (err) + goto err_out_stop; + + return 0; + + err_out_stop: + bttv_ir_stop(btv); + btv->remote = NULL; + err_out_free: + rc_free_device(rc); + kfree(ir); + return err; +} + +void bttv_input_fini(struct bttv *btv) +{ + if (btv->remote == NULL) + return; + + bttv_ir_stop(btv); + rc_unregister_device(btv->remote->dev); + kfree(btv->remote); + btv->remote = NULL; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttvp.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttvp.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttvp.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttvp.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,525 @@ +/* + + bttv - Bt848 frame grabber driver + + bttv's *private* header file -- nobody other than bttv itself + should ever include this file. + + (c) 2000-2002 Gerd Knorr + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BTTVP_H_ +#define _BTTVP_H_ + +#include +#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,18) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bt848.h" +#include "bttv.h" +#include "btcx-risc.h" + +#ifdef __KERNEL__ + +#define FORMAT_FLAGS_DITHER 0x01 +#define FORMAT_FLAGS_PACKED 0x02 +#define FORMAT_FLAGS_PLANAR 0x04 +#define FORMAT_FLAGS_RAW 0x08 +#define FORMAT_FLAGS_CrCb 0x10 + +#define RISC_SLOT_O_VBI 4 +#define RISC_SLOT_O_FIELD 6 +#define RISC_SLOT_E_VBI 10 +#define RISC_SLOT_E_FIELD 12 +#define RISC_SLOT_LOOP 14 + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO_STREAM 2 +#define RESOURCE_VBI 4 +#define RESOURCE_VIDEO_READ 8 + +#define RAW_LINES 640 +#define RAW_BPL 1024 + +#define UNSET (-1U) + +/* Min. value in VDELAY register. */ +#define MIN_VDELAY 2 +/* Even to get Cb first, odd for Cr. */ +#define MAX_HDELAY (0x3FF & -2) +/* Limits scaled width, which must be a multiple of 4. */ +#define MAX_HACTIVE (0x3FF & -4) + +#define BTTV_NORMS (\ + V4L2_STD_PAL | V4L2_STD_PAL_N | \ + V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ + V4L2_STD_NTSC | V4L2_STD_PAL_M | \ + V4L2_STD_PAL_60) +/* ---------------------------------------------------------- */ + +struct bttv_tvnorm { + int v4l2_id; + char *name; + u32 Fsc; + u16 swidth, sheight; /* scaled standard width, height */ + u16 totalwidth; + u8 adelay, bdelay, iform; + u32 scaledtwidth; + u16 hdelayx1, hactivex1; + u16 vdelay; + u8 vbipack; + u16 vtotal; + int sram; + /* ITU-R frame line number of the first VBI line we can + capture, of the first and second field. The last possible line + is determined by cropcap.bounds. */ + u16 vbistart[2]; + /* Horizontally this counts fCLKx1 samples following the leading + edge of the horizontal sync pulse, vertically ITU-R frame line + numbers of the first field times two (2, 4, 6, ... 524 or 624). */ + struct v4l2_cropcap cropcap; +}; +extern const struct bttv_tvnorm bttv_tvnorms[]; + +struct bttv_format { + char *name; + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift,vshift; /* for planar modes */ +}; + +struct bttv_ir { + struct rc_dev *dev; + struct timer_list timer; + + char name[32]; + char phys[32]; + + /* Usual gpio signalling */ + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; + u32 polling; + u32 last_gpio; + int shift_by; + int start; // What should RC5_START() be + int addr; // What RC5_ADDR() should be. + int rc5_remote_gap; + + /* RC5 gpio */ + bool rc5_gpio; /* Is RC5 legacy GPIO enabled? */ + u32 last_bit; /* last raw bit seen */ + u32 code; /* raw code under construction */ + struct timeval base_time; /* time of last seen code */ + bool active; /* building raw code */ +}; + + +/* ---------------------------------------------------------- */ + +struct bttv_geometry { + u8 vtc,crop,comb; + u16 width,hscale,hdelay; + u16 sheight,vscale,vdelay,vtotal; +}; + +struct bttv_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* bttv specific */ + const struct bttv_format *fmt; + unsigned int tvnorm; + int btformat; + int btswap; + struct bttv_geometry geo; + struct btcx_riscmem top; + struct btcx_riscmem bottom; + struct v4l2_rect crop; + unsigned int vbi_skip[2]; + unsigned int vbi_count[2]; +}; + +struct bttv_buffer_set { + struct bttv_buffer *top; /* top field buffer */ + struct bttv_buffer *bottom; /* bottom field buffer */ + unsigned int top_irq; + unsigned int frame_irq; +}; + +struct bttv_overlay { + unsigned int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct bttv_vbi_fmt { + struct v4l2_vbi_format fmt; + + /* fmt.start[] and count[] refer to this video standard. */ + const struct bttv_tvnorm *tvnorm; + + /* Earliest possible start of video capturing with this + v4l2_vbi_format, in struct bttv_crop.rect units. */ + __s32 end; +}; + +/* bttv-vbi.c */ +void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm); + +struct bttv_crop { + /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */ + struct v4l2_rect rect; + + /* Scaled image size limits with this crop rect. Divide + max_height, but not min_height, by two when capturing + single fields. See also bttv_crop_reset() and + bttv_crop_adjust() in bttv-driver.c. */ + __s32 min_scaled_width; + __s32 min_scaled_height; + __s32 max_scaled_width; + __s32 max_scaled_height; +}; + +struct bttv_fh { + struct bttv *btv; + int resources; +#ifdef VIDIOC_G_PRIORITY + enum v4l2_priority prio; +#endif + enum v4l2_buf_type type; + + /* video capture */ + struct videobuf_queue cap; + const struct bttv_format *fmt; + int width; + int height; + + /* video overlay */ + const struct bttv_format *ovfmt; + struct bttv_overlay ov; + + /* Application called VIDIOC_S_CROP. */ + int do_crop; + + /* vbi capture */ + struct videobuf_queue vbi; + /* Current VBI capture window as seen through this fh (cannot + be global for compatibility with earlier drivers). Protected + by struct bttv.lock and struct bttv_fh.vbi.lock. */ + struct bttv_vbi_fmt vbi_fmt; +}; + +/* ---------------------------------------------------------- */ +/* bttv-risc.c */ + +/* risc code generators - capture */ +int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int offset, unsigned int bpl, + unsigned int pitch, unsigned int skip_lines, + unsigned int store_lines); + +/* control dma register + risc main loop */ +void bttv_set_dma(struct bttv *btv, int override); +int bttv_risc_init_main(struct bttv *btv); +int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, + int irqflags); + +/* capture buffer handling */ +int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); +int bttv_buffer_activate_video(struct bttv *btv, + struct bttv_buffer_set *set); +int bttv_buffer_activate_vbi(struct bttv *btv, + struct bttv_buffer *vbi); +void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, + struct bttv_buffer *buf); + +/* overlay handling */ +int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, + const struct bttv_format *fmt, + struct bttv_buffer *buf); + + +/* ---------------------------------------------------------- */ +/* bttv-vbi.c */ + +int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); +int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); +int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); + +extern struct videobuf_queue_ops bttv_vbi_qops; + +/* ---------------------------------------------------------- */ +/* bttv-gpio.c */ + +extern struct bus_type bttv_sub_bus_type; +int bttv_sub_add_device(struct bttv_core *core, char *name); +int bttv_sub_del_devices(struct bttv_core *core); + +/* ---------------------------------------------------------- */ +/* bttv-cards.c */ + +extern int no_overlay; + +/* ---------------------------------------------------------- */ +/* bttv-input.c */ + +extern void init_bttv_i2c_ir(struct bttv *btv); +extern int fini_bttv_i2c(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* bttv-driver.c */ + +/* insmod options */ +extern unsigned int bttv_verbose; +extern unsigned int bttv_debug; +extern unsigned int bttv_gpio; +extern void bttv_gpio_tracking(struct bttv *btv, char *comment); +extern int init_bttv_i2c(struct bttv *btv); + +#define bttv_printk if (bttv_verbose) printk +#define dprintk if (bttv_debug >= 1) printk +#define d2printk if (bttv_debug >= 2) printk + +#define BTTV_MAX_FBUF 0x208000 +#define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ +#define BTTV_FREE_IDLE msecs_to_jiffies(1000) /* one second */ + + +struct bttv_pll_info { + unsigned int pll_ifreq; /* PLL input frequency */ + unsigned int pll_ofreq; /* PLL output frequency */ + unsigned int pll_crystal; /* Crystal used for input */ + unsigned int pll_current; /* Currently programmed ofreq */ +}; + +/* for gpio-connected remote control */ +struct bttv_input { + struct input_dev *dev; + char name[32]; + char phys[32]; + u32 mask_keycode; + u32 mask_keydown; +}; + +struct bttv_suspend_state { + u32 gpio_enable; + u32 gpio_data; + int disabled; + int loop_irq; + struct bttv_buffer_set video; + struct bttv_buffer *vbi; +}; + +struct bttv { + struct bttv_core c; + + /* pci device config */ + unsigned short id; + unsigned char revision; + unsigned char __iomem *bt848_mmio; /* pointer to mmio */ + + /* card configuration info */ + unsigned int cardid; /* pci subsystem id (bt878 based ones) */ + unsigned int tuner_type; /* tuner chip type */ + unsigned int tda9887_conf; + unsigned int svhs, dig; + unsigned int has_saa6588:1; + struct bttv_pll_info pll; + int triton1; + int gpioirq; + + int use_i2c_hw; + + /* old gpio interface */ + int shutdown; + + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); + + /* new gpio interface */ + spinlock_t gpio_lock; + + /* i2c layer */ + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_rc; + int i2c_done; + wait_queue_head_t i2c_queue; + struct v4l2_subdev *sd_msp34xx; + struct v4l2_subdev *sd_tvaudio; + + /* video4linux (1) */ + struct video_device *video_dev; + struct video_device *radio_dev; + struct video_device *vbi_dev; + + /* infrared remote */ + int has_remote; + struct bttv_ir *remote; + + /* I2C remote data */ + struct IR_i2c_init_data init_data; + + /* locking */ + spinlock_t s_lock; + struct mutex lock; + int resources; +#ifdef VIDIOC_G_PRIORITY + struct v4l2_prio_state prio; +#endif + + /* video state */ + unsigned int input; + unsigned int audio; + unsigned int mute; + unsigned long freq; + unsigned int tvnorm; + int hue, contrast, bright, saturation; + struct v4l2_framebuffer fbuf; + unsigned int field_count; + + /* various options */ + int opt_combfilter; + int opt_lumafilter; + int opt_automute; + int opt_chroma_agc; + int opt_adc_crush; + int opt_vcr_hack; + int opt_whitecrush_upper; + int opt_whitecrush_lower; + int opt_uv_ratio; + int opt_full_luma_range; + int opt_coring; + + /* radio data/state */ + int has_radio; + int radio_user; + + /* miro/pinnacle + Aimslab VHX + philips matchbox (tea5757 radio tuner) support */ + int has_matchbox; + int mbox_we; + int mbox_data; + int mbox_clk; + int mbox_most; + int mbox_mask; + + /* ISA stuff (Terratec Active Radio Upgrade) */ + int mbox_ior; + int mbox_iow; + int mbox_csel; + + /* risc memory management data + - must acquire s_lock before changing these + - only the irq handler is supported to touch top + bottom + vcurr */ + struct btcx_riscmem main; + struct bttv_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + struct list_head vcapture; /* vbi capture queue */ + struct bttv_buffer_set curr; /* active buffers */ + struct bttv_buffer *cvbi; /* active vbi buffer */ + int loop_irq; + int new_input; + + unsigned long cap_ctl; + unsigned long dma_on; + struct timer_list timeout; + struct bttv_suspend_state state; + + /* stats */ + unsigned int errors; + unsigned int framedrop; + unsigned int irq_total; + unsigned int irq_me; + + unsigned int users; + struct bttv_fh init; + + /* used to make dvb-bt8xx autoloadable */ + struct work_struct request_module_wk; + + /* Default (0) and current (1) video capturing and overlay + cropping parameters in bttv_tvnorm.cropcap units. Protected + by bttv.lock. */ + struct bttv_crop crop[2]; + + /* Earliest possible start of video capturing in + bttv_tvnorm.cropcap line units. Set by check_alloc_btres() + and free_btres(). Protected by bttv.lock. */ + __s32 vbi_end; + + /* Latest possible end of VBI capturing (= crop[x].rect.top when + VIDEO_RESOURCES are locked). Set by check_alloc_btres() + and free_btres(). Protected by bttv.lock. */ + __s32 crop_start; +}; + +static inline struct bttv *to_bttv(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct bttv, c.v4l2_dev); +} + +/* our devices */ +#define BTTV_MAX 32 +extern unsigned int bttv_num; +extern struct bttv *bttvs[BTTV_MAX]; + +static inline unsigned int bttv_muxsel(const struct bttv *btv, + unsigned int input) +{ + return (bttv_tvcards[btv->c.type].muxsel >> (input * 2)) & 3; +} + +#endif + +#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) +#define btread(adr) readl(btv->bt848_mmio+(adr)) + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#endif /* _BTTVP_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-risc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-risc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-risc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-risc.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,910 @@ +/* + + bttv-risc.c -- interfaces to other kernel modules + + bttv risc code handling + - memory management + - generation + + (c) 2000-2003 Gerd Knorr + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttvp.h" + +#define VCR_HACK_LINES 4 + +/* ---------------------------------------------------------- */ +/* risc code generators */ + +int +bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int offset, unsigned int bpl, + unsigned int padding, unsigned int skip_lines, + unsigned int store_lines) +{ + u32 instructions,line,todo; + struct scatterlist *sg; + __le32 *rp; + int rc; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + sync + jump (all 2 dwords). padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + instructions = skip_lines * 4; + instructions += (1 + ((bpl + padding) * store_lines) + / PAGE_SIZE + store_lines) * 8; + instructions += 2 * 8; + if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0) + return rc; + + /* sync instruction */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(rp++) = cpu_to_le32(0); + + while (skip_lines-- > 0) { + *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL | + BT848_RISC_EOL | bpl); + } + + /* scan lines */ + sg = sglist; + for (line = 0; line < store_lines; line++) { + if ((btv->opt_vcr_hack) && + (line >= (store_lines - VCR_HACK_LINES))) + continue; + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + if (bpl <= sg_dma_len(sg)-offset) { + /* fits into current chunk */ + *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + BT848_RISC_EOL|bpl); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + offset+=bpl; + } else { + /* scanline needs to be splitted */ + todo = bpl; + *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + (sg_dma_len(sg)-offset)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + todo -= (sg_dma_len(sg)-offset); + offset = 0; + sg++; + while (todo > sg_dma_len(sg)) { + *(rp++)=cpu_to_le32(BT848_RISC_WRITE| + sg_dma_len(sg)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + todo -= sg_dma_len(sg); + sg++; + } + *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL| + todo); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + offset += todo; + } + offset += padding; + } + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + +static int +bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int yoffset, unsigned int ybpl, + unsigned int ypadding, unsigned int ylines, + unsigned int uoffset, unsigned int voffset, + unsigned int hshift, unsigned int vshift, + unsigned int cpadding) +{ + unsigned int instructions,line,todo,ylen,chroma; + __le32 *rp; + u32 ri; + struct scatterlist *ysg; + struct scatterlist *usg; + struct scatterlist *vsg; + int topfield = (0 == yoffset); + int rc; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line (5 dwords) + plus sync + jump (2 dwords) */ + instructions = ((3 + (ybpl + ypadding) * ylines * 2) + / PAGE_SIZE) + ylines; + instructions += 2; + if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0) + return rc; + + /* sync instruction */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); + *(rp++) = cpu_to_le32(0); + + /* scan lines */ + ysg = sglist; + usg = sglist; + vsg = sglist; + for (line = 0; line < ylines; line++) { + if ((btv->opt_vcr_hack) && + (line >= (ylines - VCR_HACK_LINES))) + continue; + switch (vshift) { + case 0: + chroma = 1; + break; + case 1: + if (topfield) + chroma = ((line & 1) == 0); + else + chroma = ((line & 1) == 1); + break; + case 2: + if (topfield) + chroma = ((line & 3) == 0); + else + chroma = ((line & 3) == 2); + break; + default: + chroma = 0; + break; + } + + for (todo = ybpl; todo > 0; todo -= ylen) { + /* go to next sg entry if needed */ + while (yoffset && yoffset >= sg_dma_len(ysg)) { + yoffset -= sg_dma_len(ysg); + ysg++; + } + while (uoffset && uoffset >= sg_dma_len(usg)) { + uoffset -= sg_dma_len(usg); + usg++; + } + while (voffset && voffset >= sg_dma_len(vsg)) { + voffset -= sg_dma_len(vsg); + vsg++; + } + + /* calculate max number of bytes we can write */ + ylen = todo; + if (yoffset + ylen > sg_dma_len(ysg)) + ylen = sg_dma_len(ysg) - yoffset; + if (chroma) { + if (uoffset + (ylen>>hshift) > sg_dma_len(usg)) + ylen = (sg_dma_len(usg) - uoffset) << hshift; + if (voffset + (ylen>>hshift) > sg_dma_len(vsg)) + ylen = (sg_dma_len(vsg) - voffset) << hshift; + ri = BT848_RISC_WRITE123; + } else { + ri = BT848_RISC_WRITE1S23; + } + if (ybpl == todo) + ri |= BT848_RISC_SOL; + if (ylen == todo) + ri |= BT848_RISC_EOL; + + /* write risc instruction */ + *(rp++)=cpu_to_le32(ri | ylen); + *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) | + (ylen >> hshift)); + *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset); + yoffset += ylen; + if (chroma) { + *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset); + uoffset += ylen >> hshift; + *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset); + voffset += ylen >> hshift; + } + } + yoffset += ypadding; + if (chroma) { + uoffset += cpadding; + voffset += cpadding; + } + } + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + +static int +bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, + const struct bttv_format *fmt, struct bttv_overlay *ov, + int skip_even, int skip_odd) +{ + int dwords, rc, line, maxy, start, end; + unsigned skip, nskips; + struct btcx_skiplist *skips; + __le32 *rp; + u32 ri,ra; + u32 addr; + + /* skip list for window clipping */ + if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL))) + return -ENOMEM; + + /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions + + sync + jump (all 2 dwords) */ + dwords = (3 * ov->nclips + 2) * + ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height); + dwords += 4; + if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) { + kfree(skips); + return rc; + } + + /* sync instruction */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(rp++) = cpu_to_le32(0); + + addr = (unsigned long)btv->fbuf.base; + addr += btv->fbuf.fmt.bytesperline * ov->w.top; + addr += (fmt->depth >> 3) * ov->w.left; + + /* scan lines */ + for (maxy = -1, line = 0; line < ov->w.height; + line++, addr += btv->fbuf.fmt.bytesperline) { + if ((btv->opt_vcr_hack) && + (line >= (ov->w.height - VCR_HACK_LINES))) + continue; + if ((line%2) == 0 && skip_even) + continue; + if ((line%2) == 1 && skip_odd) + continue; + + /* calculate clipping */ + if (line > maxy) + btcx_calc_skips(line, ov->w.width, &maxy, + skips, &nskips, ov->clips, ov->nclips); + + /* write out risc code */ + for (start = 0, skip = 0; start < ov->w.width; start = end) { + if (skip >= nskips) { + ri = BT848_RISC_WRITE; + end = ov->w.width; + } else if (start < skips[skip].start) { + ri = BT848_RISC_WRITE; + end = skips[skip].start; + } else { + ri = BT848_RISC_SKIP; + end = skips[skip].end; + skip++; + } + if (BT848_RISC_WRITE == ri) + ra = addr + (fmt->depth>>3)*start; + else + ra = 0; + + if (0 == start) + ri |= BT848_RISC_SOL; + if (ov->w.width == end) + ri |= BT848_RISC_EOL; + ri |= (fmt->depth>>3) * (end-start); + + *(rp++)=cpu_to_le32(ri); + if (0 != ra) + *(rp++)=cpu_to_le32(ra); + } + } + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + kfree(skips); + return 0; +} + +/* ---------------------------------------------------------- */ + +static void +bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo, + int width, int height, int interleaved, + const struct bttv_tvnorm *tvnorm) +{ + u32 xsf, sr; + int vdelay; + + int swidth = tvnorm->swidth; + int totalwidth = tvnorm->totalwidth; + int scaledtwidth = tvnorm->scaledtwidth; + + if (btv->input == btv->dig) { + swidth = 720; + totalwidth = 858; + scaledtwidth = 858; + } + + vdelay = tvnorm->vdelay; + + xsf = (width*scaledtwidth)/swidth; + geo->hscale = ((totalwidth*4096UL)/xsf-4096); + geo->hdelay = tvnorm->hdelayx1; + geo->hdelay = (geo->hdelay*width)/swidth; + geo->hdelay &= 0x3fe; + sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512; + geo->vscale = (0x10000UL-sr) & 0x1fff; + geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) | + ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0); + geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0; + geo->vdelay = vdelay; + geo->width = width; + geo->sheight = tvnorm->sheight; + geo->vtotal = tvnorm->vtotal; + + if (btv->opt_combfilter) { + geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); + geo->comb = (width < 769) ? 1 : 0; + } else { + geo->vtc = 0; + geo->comb = 0; + } +} + +static void +bttv_calc_geo (struct bttv * btv, + struct bttv_geometry * geo, + unsigned int width, + unsigned int height, + int both_fields, + const struct bttv_tvnorm * tvnorm, + const struct v4l2_rect * crop) +{ + unsigned int c_width; + unsigned int c_height; + u32 sr; + + if ((crop->left == tvnorm->cropcap.defrect.left + && crop->top == tvnorm->cropcap.defrect.top + && crop->width == tvnorm->cropcap.defrect.width + && crop->height == tvnorm->cropcap.defrect.height + && width <= tvnorm->swidth /* see PAL-Nc et al */) + || btv->input == btv->dig) { + bttv_calc_geo_old(btv, geo, width, height, + both_fields, tvnorm); + return; + } + + /* For bug compatibility the image size checks permit scale + factors > 16. See bttv_crop_calc_limits(). */ + c_width = min((unsigned int) crop->width, width * 16); + c_height = min((unsigned int) crop->height, height * 16); + + geo->width = width; + geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096; + /* Even to store Cb first, odd for Cr. */ + geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1; + + geo->sheight = c_height; + geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY; + sr = c_height >> !both_fields; + sr = (sr * 512U + (height >> 1)) / height - 512; + geo->vscale = (0x10000UL - sr) & 0x1fff; + geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0; + geo->vtotal = tvnorm->vtotal; + + geo->crop = (((geo->width >> 8) & 0x03) | + ((geo->hdelay >> 6) & 0x0c) | + ((geo->sheight >> 4) & 0x30) | + ((geo->vdelay >> 2) & 0xc0)); + + if (btv->opt_combfilter) { + geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); + geo->comb = (width < 769) ? 1 : 0; + } else { + geo->vtc = 0; + geo->comb = 0; + } +} + +static void +bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd) +{ + int off = odd ? 0x80 : 0x00; + + if (geo->comb) + btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); + else + btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); + + btwrite(geo->vtc, BT848_E_VTC+off); + btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off); + btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off); + btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); + btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off); + btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off); + btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off); + btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off); + btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off); + btwrite(geo->crop, BT848_E_CROP+off); + btwrite(geo->vtotal>>8, BT848_VTOTAL_HI); + btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO); +} + +/* ---------------------------------------------------------- */ +/* risc group / risc main loop / dma management */ + +void +bttv_set_dma(struct bttv *btv, int override) +{ + unsigned long cmd; + int capctl; + + btv->cap_ctl = 0; + if (NULL != btv->curr.top) btv->cap_ctl |= 0x02; + if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01; + if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c; + + capctl = 0; + capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */ + capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */ + capctl |= override; + + d2printk(KERN_DEBUG + "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n", + btv->c.nr,capctl,btv->loop_irq, + btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, + btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, + btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0, + btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); + + cmd = BT848_RISC_JUMP; + if (btv->loop_irq) { + cmd |= BT848_RISC_IRQ; + cmd |= (btv->loop_irq & 0x0f) << 16; + cmd |= (~btv->loop_irq & 0x0f) << 20; + } + if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) { + mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT); + } else { + del_timer(&btv->timeout); + } + btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd); + + btaor(capctl, ~0x0f, BT848_CAP_CTL); + if (capctl) { + if (btv->dma_on) + return; + btwrite(btv->main.dma, BT848_RISC_STRT_ADD); + btor(3, BT848_GPIO_DMA_CTL); + btv->dma_on = 1; + } else { + if (!btv->dma_on) + return; + btand(~3, BT848_GPIO_DMA_CTL); + btv->dma_on = 0; + } + return; +} + +int +bttv_risc_init_main(struct bttv *btv) +{ + int rc; + + if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0) + return rc; + dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n", + btv->c.nr,(unsigned long long)btv->main.dma); + + btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | + BT848_FIFO_STATUS_VRE); + btv->main.cpu[1] = cpu_to_le32(0); + btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2)); + + /* top field */ + btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2)); + btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2)); + + btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | + BT848_FIFO_STATUS_VRO); + btv->main.cpu[9] = cpu_to_le32(0); + + /* bottom field */ + btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2)); + btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2)); + + /* jump back to top field */ + btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2)); + + return 0; +} + +int +bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, + int irqflags) +{ + unsigned long cmd; + unsigned long next = btv->main.dma + ((slot+2) << 2); + + if (NULL == risc) { + d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n", + btv->c.nr,risc,slot); + btv->main.cpu[slot+1] = cpu_to_le32(next); + } else { + d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n", + btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags); + cmd = BT848_RISC_JUMP; + if (irqflags) { + cmd |= BT848_RISC_IRQ; + cmd |= (irqflags & 0x0f) << 16; + cmd |= (~irqflags & 0x0f) << 20; + } + risc->jmp[0] = cpu_to_le32(cmd); + risc->jmp[1] = cpu_to_le32(next); + btv->main.cpu[slot+1] = cpu_to_le32(risc->dma); + } + return 0; +} + +void +bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf) +{ + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + + BUG_ON(in_interrupt()); + videobuf_waiton(q, &buf->vb, 0, 0); + videobuf_dma_unmap(q->dev, dma); + videobuf_dma_free(dma); + btcx_riscmem_free(btv->c.pci,&buf->bottom); + btcx_riscmem_free(btv->c.pci,&buf->top); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +int +bttv_buffer_activate_vbi(struct bttv *btv, + struct bttv_buffer *vbi) +{ + struct btcx_riscmem *top; + struct btcx_riscmem *bottom; + int top_irq_flags; + int bottom_irq_flags; + + top = NULL; + bottom = NULL; + top_irq_flags = 0; + bottom_irq_flags = 0; + + if (vbi) { + unsigned int crop, vdelay; + + vbi->vb.state = VIDEOBUF_ACTIVE; + list_del(&vbi->vb.queue); + + /* VDELAY is start of video, end of VBI capturing. */ + crop = btread(BT848_E_CROP); + vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2); + + if (vbi->geo.vdelay > vdelay) { + vdelay = vbi->geo.vdelay & 0xfe; + crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0); + + btwrite(vdelay, BT848_E_VDELAY_LO); + btwrite(crop, BT848_E_CROP); + btwrite(vdelay, BT848_O_VDELAY_LO); + btwrite(crop, BT848_O_CROP); + } + + if (vbi->vbi_count[0] > 0) { + top = &vbi->top; + top_irq_flags = 4; + } + + if (vbi->vbi_count[1] > 0) { + top_irq_flags = 0; + bottom = &vbi->bottom; + bottom_irq_flags = 4; + } + } + + bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags); + bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags); + + return 0; +} + +int +bttv_buffer_activate_video(struct bttv *btv, + struct bttv_buffer_set *set) +{ + /* video capture */ + if (NULL != set->top && NULL != set->bottom) { + if (set->top == set->bottom) { + set->top->vb.state = VIDEOBUF_ACTIVE; + if (set->top->vb.queue.next) + list_del(&set->top->vb.queue); + } else { + set->top->vb.state = VIDEOBUF_ACTIVE; + set->bottom->vb.state = VIDEOBUF_ACTIVE; + if (set->top->vb.queue.next) + list_del(&set->top->vb.queue); + if (set->bottom->vb.queue.next) + list_del(&set->bottom->vb.queue); + } + bttv_apply_geo(btv, &set->top->geo, 1); + bttv_apply_geo(btv, &set->bottom->geo,0); + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, + set->top_irq); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, + set->frame_irq); + btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f), + ~0xff, BT848_COLOR_FMT); + btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), + ~0x0f, BT848_COLOR_CTL); + } else if (NULL != set->top) { + set->top->vb.state = VIDEOBUF_ACTIVE; + if (set->top->vb.queue.next) + list_del(&set->top->vb.queue); + bttv_apply_geo(btv, &set->top->geo,1); + bttv_apply_geo(btv, &set->top->geo,0); + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, + set->frame_irq); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); + btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); + btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); + } else if (NULL != set->bottom) { + set->bottom->vb.state = VIDEOBUF_ACTIVE; + if (set->bottom->vb.queue.next) + list_del(&set->bottom->vb.queue); + bttv_apply_geo(btv, &set->bottom->geo,1); + bttv_apply_geo(btv, &set->bottom->geo,0); + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, + set->frame_irq); + btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT); + btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); + } else { + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); + } + return 0; +} + +/* ---------------------------------------------------------- */ + +/* calculate geometry, build risc code */ +int +bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) +{ + const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + + dprintk(KERN_DEBUG + "bttv%d: buffer field: %s format: %s size: %dx%d\n", + btv->c.nr, v4l2_field_names[buf->vb.field], + buf->fmt->name, buf->vb.width, buf->vb.height); + + /* packed pixel modes */ + if (buf->fmt->flags & FORMAT_FLAGS_PACKED) { + int bpl = (buf->fmt->depth >> 3) * buf->vb.width; + int bpf = bpl * (buf->vb.height >> 1); + + bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height, + V4L2_FIELD_HAS_BOTH(buf->vb.field), + tvnorm,&buf->crop); + + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + bttv_risc_packed(btv,&buf->top,dma->sglist, + /* offset */ 0,bpl, + /* padding */ 0,/* skip_lines */ 0, + buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + bttv_risc_packed(btv,&buf->bottom,dma->sglist, + 0,bpl,0,0,buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + bttv_risc_packed(btv,&buf->top,dma->sglist, + 0,bpl,bpl,0,buf->vb.height >> 1); + bttv_risc_packed(btv,&buf->bottom,dma->sglist, + bpl,bpl,bpl,0,buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + bttv_risc_packed(btv,&buf->top,dma->sglist, + 0,bpl,0,0,buf->vb.height >> 1); + bttv_risc_packed(btv,&buf->bottom,dma->sglist, + bpf,bpl,0,0,buf->vb.height >> 1); + break; + default: + BUG(); + } + } + + /* planar modes */ + if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) { + int uoffset, voffset; + int ypadding, cpadding, lines; + + /* calculate chroma offsets */ + uoffset = buf->vb.width * buf->vb.height; + voffset = buf->vb.width * buf->vb.height; + if (buf->fmt->flags & FORMAT_FLAGS_CrCb) { + /* Y-Cr-Cb plane order */ + uoffset >>= buf->fmt->hshift; + uoffset >>= buf->fmt->vshift; + uoffset += voffset; + } else { + /* Y-Cb-Cr plane order */ + voffset >>= buf->fmt->hshift; + voffset >>= buf->fmt->vshift; + voffset += uoffset; + } + + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,/* both_fields */ 0, + tvnorm,&buf->crop); + bttv_risc_planar(btv, &buf->top, dma->sglist, + 0,buf->vb.width,0,buf->vb.height, + uoffset,voffset,buf->fmt->hshift, + buf->fmt->vshift,0); + break; + case V4L2_FIELD_BOTTOM: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,0, + tvnorm,&buf->crop); + bttv_risc_planar(btv, &buf->bottom, dma->sglist, + 0,buf->vb.width,0,buf->vb.height, + uoffset,voffset,buf->fmt->hshift, + buf->fmt->vshift,0); + break; + case V4L2_FIELD_INTERLACED: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,1, + tvnorm,&buf->crop); + lines = buf->vb.height >> 1; + ypadding = buf->vb.width; + cpadding = buf->vb.width >> buf->fmt->hshift; + bttv_risc_planar(btv,&buf->top, + dma->sglist, + 0,buf->vb.width,ypadding,lines, + uoffset,voffset, + buf->fmt->hshift, + buf->fmt->vshift, + cpadding); + bttv_risc_planar(btv,&buf->bottom, + dma->sglist, + ypadding,buf->vb.width,ypadding,lines, + uoffset+cpadding, + voffset+cpadding, + buf->fmt->hshift, + buf->fmt->vshift, + cpadding); + break; + case V4L2_FIELD_SEQ_TB: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,1, + tvnorm,&buf->crop); + lines = buf->vb.height >> 1; + ypadding = buf->vb.width; + cpadding = buf->vb.width >> buf->fmt->hshift; + bttv_risc_planar(btv,&buf->top, + dma->sglist, + 0,buf->vb.width,0,lines, + uoffset >> 1, + voffset >> 1, + buf->fmt->hshift, + buf->fmt->vshift, + 0); + bttv_risc_planar(btv,&buf->bottom, + dma->sglist, + lines * ypadding,buf->vb.width,0,lines, + lines * ypadding + (uoffset >> 1), + lines * ypadding + (voffset >> 1), + buf->fmt->hshift, + buf->fmt->vshift, + 0); + break; + default: + BUG(); + } + } + + /* raw data */ + if (buf->fmt->flags & FORMAT_FLAGS_RAW) { + /* build risc code */ + buf->vb.field = V4L2_FIELD_SEQ_TB; + bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, + 1,tvnorm,&buf->crop); + bttv_risc_packed(btv, &buf->top, dma->sglist, + /* offset */ 0, RAW_BPL, /* padding */ 0, + /* skip_lines */ 0, RAW_LINES); + bttv_risc_packed(btv, &buf->bottom, dma->sglist, + buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); + } + + /* copy format info */ + buf->btformat = buf->fmt->btformat; + buf->btswap = buf->fmt->btswap; + return 0; +} + +/* ---------------------------------------------------------- */ + +/* calculate geometry, build risc code */ +int +bttv_overlay_risc(struct bttv *btv, + struct bttv_overlay *ov, + const struct bttv_format *fmt, + struct bttv_buffer *buf) +{ + /* check interleave, bottom+top fields */ + dprintk(KERN_DEBUG + "bttv%d: overlay fields: %s format: %s size: %dx%d\n", + btv->c.nr, v4l2_field_names[buf->vb.field], + fmt->name,ov->w.width,ov->w.height); + + /* calculate geometry */ + bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, + V4L2_FIELD_HAS_BOTH(ov->field), + &bttv_tvnorms[ov->tvnorm],&buf->crop); + + /* build risc code */ + switch (ov->field) { + case V4L2_FIELD_TOP: + bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0); + break; + case V4L2_FIELD_BOTTOM: + bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0); + break; + case V4L2_FIELD_INTERLACED: + bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1); + bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0); + break; + default: + BUG(); + } + + /* copy format info */ + buf->btformat = fmt->btformat; + buf->btswap = fmt->btswap; + buf->vb.field = ov->field; + return 0; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/bttv-vbi.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,454 @@ +/* + + bttv - Bt848 frame grabber driver + vbi interface + + (c) 2002 Gerd Knorr + + Copyright (C) 2005, 2006 Michael H. Schimek + Sponsored by OPQ Systems AB + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "bttvp.h" + +/* Offset from line sync pulse leading edge (0H) to start of VBI capture, + in fCLKx2 pixels. According to the datasheet, VBI capture starts + VBI_HDELAY fCLKx1 pixels from the tailing edgeof /HRESET, and /HRESET + is 64 fCLKx1 pixels wide. VBI_HDELAY is set to 0, so this should be + (64 + 0) * 2 = 128 fCLKx2 pixels. But it's not! The datasheet is + Just Plain Wrong. The real value appears to be different for + different revisions of the bt8x8 chips, and to be affected by the + horizontal scaling factor. Experimentally, the value is measured + to be about 244. */ +#define VBI_OFFSET 244 + +/* 2048 for compatibility with earlier driver versions. The driver + really stores 1024 + tvnorm->vbipack * 4 samples per line in the + buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI + is 0x1FF DWORDs) and VBI read()s store a frame counter in the last + four bytes of the VBI image. */ +#define VBI_BPL 2048 + +/* Compatibility. */ +#define VBI_DEFLINES 16 + +static unsigned int vbibufs = 4; +static unsigned int vbi_debug; + +module_param(vbibufs, int, 0444); +module_param(vbi_debug, int, 0644); +MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4"); +MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)"); + +#ifdef dprintk +# undef dprintk +#endif +#define dprintk(fmt, arg...) if (vbi_debug) \ + printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg) + +#define IMAGE_SIZE(fmt) \ + (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line) + +/* ----------------------------------------------------------------------- */ +/* vbi risc code + mm */ + +static int vbi_buffer_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + + if (0 == *count) + *count = vbibufs; + + *size = IMAGE_SIZE(&fh->vbi_fmt.fmt); + + dprintk("setup: samples=%u start=%d,%d count=%u,%u\n", + fh->vbi_fmt.fmt.samples_per_line, + fh->vbi_fmt.fmt.start[0], + fh->vbi_fmt.fmt.start[1], + fh->vbi_fmt.fmt.count[0], + fh->vbi_fmt.fmt.count[1]); + + return 0; +} + +static int vbi_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + const struct bttv_tvnorm *tvnorm; + unsigned int skip_lines0, skip_lines1, min_vdelay; + int redo_dma_risc; + int rc; + + buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt); + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + tvnorm = fh->vbi_fmt.tvnorm; + + /* There's no VBI_VDELAY register, RISC must skip the lines + we don't want. With default parameters we skip zero lines + as earlier driver versions did. The driver permits video + standard changes while capturing, so we use vbi_fmt.tvnorm + instead of btv->tvnorm to skip zero lines after video + standard changes as well. */ + + skip_lines0 = 0; + skip_lines1 = 0; + + if (fh->vbi_fmt.fmt.count[0] > 0) + skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0] + - tvnorm->vbistart[0])); + if (fh->vbi_fmt.fmt.count[1] > 0) + skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1] + - tvnorm->vbistart[1])); + + redo_dma_risc = 0; + + if (buf->vbi_skip[0] != skip_lines0 || + buf->vbi_skip[1] != skip_lines1 || + buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] || + buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) { + buf->vbi_skip[0] = skip_lines0; + buf->vbi_skip[1] = skip_lines1; + buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0]; + buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1]; + redo_dma_risc = 1; + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + redo_dma_risc = 1; + if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) + goto fail; + } + + if (redo_dma_risc) { + unsigned int bpl, padding, offset; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + + bpl = 2044; /* max. vbipack */ + padding = VBI_BPL - bpl; + + if (fh->vbi_fmt.fmt.count[0] > 0) { + rc = bttv_risc_packed(btv, &buf->top, + dma->sglist, + /* offset */ 0, bpl, + padding, skip_lines0, + fh->vbi_fmt.fmt.count[0]); + if (0 != rc) + goto fail; + } + + if (fh->vbi_fmt.fmt.count[1] > 0) { + offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL; + + rc = bttv_risc_packed(btv, &buf->bottom, + dma->sglist, + offset, bpl, + padding, skip_lines1, + fh->vbi_fmt.fmt.count[1]); + if (0 != rc) + goto fail; + } + } + + /* VBI capturing ends at VDELAY, start of video capturing, + no matter where the RISC program ends. VDELAY minimum is 2, + bounds.top is the corresponding first field line number + times two. VDELAY counts half field lines. */ + min_vdelay = MIN_VDELAY; + if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top) + min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top; + + /* For bttv_buffer_activate_vbi(). */ + buf->geo.vdelay = min_vdelay; + + buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.field = field; + dprintk("buf prepare %p: top=%p bottom=%p field=%s\n", + vb, &buf->top, &buf->bottom, + v4l2_field_names[buf->vb.field]); + return 0; + + fail: + bttv_dma_free(q,btv,buf); + return rc; +} + +static void +vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + + dprintk("queue %p\n",vb); + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue,&btv->vcapture); + if (NULL == btv->cvbi) { + fh->btv->loop_irq |= 4; + bttv_set_dma(btv,0x0c); + } +} + +static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + + dprintk("free %p\n",vb); + bttv_dma_free(q,fh->btv,buf); +} + +struct videobuf_queue_ops bttv_vbi_qops = { + .buf_setup = vbi_buffer_setup, + .buf_prepare = vbi_buffer_prepare, + .buf_queue = vbi_buffer_queue, + .buf_release = vbi_buffer_release, +}; + +/* ----------------------------------------------------------------------- */ + +static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, + __s32 crop_start) +{ + __s32 min_start, max_start, max_end, f2_offset; + unsigned int i; + + /* For compatibility with earlier driver versions we must pretend + the VBI and video capture window may overlap. In reality RISC + magic aborts VBI capturing at the first line of video capturing, + leaving the rest of the buffer unchanged, usually all zero. + VBI capturing must always start before video capturing. >> 1 + because cropping counts field lines times two. */ + min_start = tvnorm->vbistart[0]; + max_start = (crop_start >> 1) - 1; + max_end = (tvnorm->cropcap.bounds.top + + tvnorm->cropcap.bounds.height) >> 1; + + if (min_start > max_start) + return -EBUSY; + + BUG_ON(max_start >= max_end); + + f->sampling_rate = tvnorm->Fsc; + f->samples_per_line = VBI_BPL; + f->sample_format = V4L2_PIX_FMT_GREY; + f->offset = VBI_OFFSET; + + f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0]; + + for (i = 0; i < 2; ++i) { + if (0 == f->count[i]) { + /* No data from this field. We leave f->start[i] + alone because VIDIOCSVBIFMT is w/o and EINVALs + when a driver does not support exactly the + requested parameters. */ + } else { + s64 start, count; + + start = clamp(f->start[i], min_start, max_start); + /* s64 to prevent overflow. */ + count = (s64) f->start[i] + f->count[i] - start; + f->start[i] = start; + f->count[i] = clamp(count, (s64) 1, + max_end - start); + } + + min_start += f2_offset; + max_start += f2_offset; + max_end += f2_offset; + } + + if (0 == (f->count[0] | f->count[1])) { + /* As in earlier driver versions. */ + f->start[0] = tvnorm->vbistart[0]; + f->start[1] = tvnorm->vbistart[1]; + f->count[0] = 1; + f->count[1] = 1; + } + + f->flags = 0; + + f->reserved[0] = 0; + f->reserved[1] = 0; + + return 0; +} + +int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct bttv_tvnorm *tvnorm; + __s32 crop_start; + + mutex_lock(&btv->lock); + + tvnorm = &bttv_tvnorms[btv->tvnorm]; + crop_start = btv->crop_start; + + mutex_unlock(&btv->lock); + + return try_fmt(&frt->fmt.vbi, tvnorm, crop_start); +} + + +int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct bttv_tvnorm *tvnorm; + __s32 start1, end; + int rc; + + mutex_lock(&btv->lock); + + rc = -EBUSY; + if (fh->resources & RESOURCE_VBI) + goto fail; + + tvnorm = &bttv_tvnorms[btv->tvnorm]; + + rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start); + if (0 != rc) + goto fail; + + start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] + + tvnorm->vbistart[0]; + + /* First possible line of video capturing. Should be + max(f->start[0] + f->count[0], start1 + f->count[1]) * 2 + when capturing both fields. But for compatibility we must + pretend the VBI and video capture window may overlap, + so end = start + 1, the lowest possible value, times two + because vbi_fmt.end counts field lines times two. */ + end = max(frt->fmt.vbi.start[0], start1) * 2 + 2; + + mutex_lock(&fh->vbi.vb_lock); + + fh->vbi_fmt.fmt = frt->fmt.vbi; + fh->vbi_fmt.tvnorm = tvnorm; + fh->vbi_fmt.end = end; + + mutex_unlock(&fh->vbi.vb_lock); + + rc = 0; + + fail: + mutex_unlock(&btv->lock); + + return rc; +} + + +int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +{ + struct bttv_fh *fh = f; + const struct bttv_tvnorm *tvnorm; + + frt->fmt.vbi = fh->vbi_fmt.fmt; + + tvnorm = &bttv_tvnorms[fh->btv->tvnorm]; + + if (tvnorm != fh->vbi_fmt.tvnorm) { + __s32 max_end; + unsigned int i; + + /* As in vbi_buffer_prepare() this imitates the + behaviour of earlier driver versions after video + standard changes, with default parameters anyway. */ + + max_end = (tvnorm->cropcap.bounds.top + + tvnorm->cropcap.bounds.height) >> 1; + + frt->fmt.vbi.sampling_rate = tvnorm->Fsc; + + for (i = 0; i < 2; ++i) { + __s32 new_start; + + new_start = frt->fmt.vbi.start[i] + + tvnorm->vbistart[i] + - fh->vbi_fmt.tvnorm->vbistart[i]; + + frt->fmt.vbi.start[i] = min(new_start, max_end - 1); + frt->fmt.vbi.count[i] = + min((__s32) frt->fmt.vbi.count[i], + max_end - frt->fmt.vbi.start[i]); + + max_end += tvnorm->vbistart[1] + - tvnorm->vbistart[0]; + } + } + return 0; +} + +void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm) +{ + const struct bttv_tvnorm *tvnorm; + unsigned int real_samples_per_line; + unsigned int real_count; + + tvnorm = &bttv_tvnorms[norm]; + + f->fmt.sampling_rate = tvnorm->Fsc; + f->fmt.samples_per_line = VBI_BPL; + f->fmt.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.offset = VBI_OFFSET; + f->fmt.start[0] = tvnorm->vbistart[0]; + f->fmt.start[1] = tvnorm->vbistart[1]; + f->fmt.count[0] = VBI_DEFLINES; + f->fmt.count[1] = VBI_DEFLINES; + f->fmt.flags = 0; + f->fmt.reserved[0] = 0; + f->fmt.reserved[1] = 0; + + /* For compatibility the buffer size must be 2 * VBI_DEFLINES * + VBI_BPL regardless of the current video standard. */ + real_samples_per_line = 1024 + tvnorm->vbipack * 4; + real_count = ((tvnorm->cropcap.defrect.top >> 1) + - tvnorm->vbistart[0]); + + BUG_ON(real_samples_per_line > VBI_BPL); + BUG_ON(real_count > VBI_DEFLINES); + + f->tvnorm = tvnorm; + + /* See bttv_vbi_fmt_set(). */ + f->end = tvnorm->vbistart[0] * 2 + 2; +} + +/* ----------------------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,27 @@ +config VIDEO_BT848 + tristate "BT848 Video For Linux" + depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 + select I2C_ALGOBIT + select VIDEO_BTCX + select VIDEOBUF_DMA_SG + depends on RC_CORE + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO + ---help--- + Support for BT848 based frame grabber/overlay boards. This includes + the Miro, Hauppauge and STB boards. Please read the material in + for more information. + + To compile this driver as a module, choose M here: the + module will be called bttv. + +config VIDEO_BT848_DVB + bool "DVB/ATSC Support for bt878 based TV cards" + depends on VIDEO_BT848 && DVB_CORE + select DVB_BT8XX + ---help--- + This adds support for DVB/ATSC cards based on the BT878 chip. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bt8xx/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,13 @@ +# +# Makefile for the video capture/playback device drivers. +# + +bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ + bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ + bttv-input.o bttv-audio-hook.o + +obj-$(CONFIG_VIDEO_BT848) += bttv.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/btcx-risc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/btcx-risc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/btcx-risc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/btcx-risc.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,260 @@ +/* + + btcx-risc.c + + bt848/bt878/cx2388x risc code generator. + + (c) 2000-03 Gerd Knorr [SuSE Labs] + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "btcx-risc.h" + +MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers"); +MODULE_AUTHOR("Gerd Knorr"); +MODULE_LICENSE("GPL"); + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)"); + +/* ---------------------------------------------------------- */ +/* allocate/free risc memory */ + +static int memcnt; + +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc) +{ + if (NULL == risc->cpu) + return; + if (debug) { + memcnt--; + printk("btcx: riscmem free [%d] dma=%lx\n", + memcnt, (unsigned long)risc->dma); + } + pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); + memset(risc,0,sizeof(*risc)); +} + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size) +{ + __le32 *cpu; + dma_addr_t dma = 0; + + if (NULL != risc->cpu && risc->size < size) + btcx_riscmem_free(pci,risc); + if (NULL == risc->cpu) { + cpu = pci_alloc_consistent(pci, size, &dma); + if (NULL == cpu) + return -ENOMEM; + risc->cpu = cpu; + risc->dma = dma; + risc->size = size; + if (debug) { + memcnt++; + printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", + memcnt, (unsigned long)dma, cpu, size); + } + } + memset(risc->cpu,0,risc->size); + return 0; +} + +/* ---------------------------------------------------------- */ +/* screen overlay helpers */ + +int +btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n) +{ + if (win->left < 0) { + /* left */ + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = -win->left; + clips[n].c.height = win->height; + n++; + } + if (win->left + win->width > swidth) { + /* right */ + clips[n].c.left = swidth - win->left; + clips[n].c.top = 0; + clips[n].c.width = win->width - clips[n].c.left; + clips[n].c.height = win->height; + n++; + } + if (win->top < 0) { + /* top */ + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = win->width; + clips[n].c.height = -win->top; + n++; + } + if (win->top + win->height > sheight) { + /* bottom */ + clips[n].c.left = 0; + clips[n].c.top = sheight - win->top; + clips[n].c.width = win->width; + clips[n].c.height = win->height - clips[n].c.top; + n++; + } + return n; +} + +int +btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask) +{ + s32 nx,nw,dx; + unsigned int i; + + /* fixup window */ + nx = (win->left + mask) & ~mask; + nw = (win->width) & ~mask; + if (nx + nw > win->left + win->width) + nw -= mask+1; + dx = nx - win->left; + win->left = nx; + win->width = nw; + if (debug) + printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n", + win->width, win->height, win->left, win->top, dx); + + /* fixup clips */ + for (i = 0; i < n; i++) { + nx = (clips[i].c.left-dx) & ~mask; + nw = (clips[i].c.width) & ~mask; + if (nx + nw < clips[i].c.left-dx + clips[i].c.width) + nw += mask+1; + clips[i].c.left = nx; + clips[i].c.width = nw; + if (debug) + printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n", + clips[i].c.width, clips[i].c.height, + clips[i].c.left, clips[i].c.top); + } + return 0; +} + +void +btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) +{ + struct v4l2_clip swap; + int i,j,n; + + if (nclips < 2) + return; + for (i = nclips-2; i >= 0; i--) { + for (n = 0, j = 0; j <= i; j++) { + if (clips[j].c.left > clips[j+1].c.left) { + swap = clips[j]; + clips[j] = clips[j+1]; + clips[j+1] = swap; + n++; + } + } + if (0 == n) + break; + } +} + +void +btcx_calc_skips(int line, int width, int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips) +{ + unsigned int clip,skip; + int end, maxline; + + skip=0; + maxline = 9999; + for (clip = 0; clip < nclips; clip++) { + + /* sanity checks */ + if (clips[clip].c.left + clips[clip].c.width <= 0) + continue; + if (clips[clip].c.left > (signed)width) + break; + + /* vertical range */ + if (line > clips[clip].c.top+clips[clip].c.height-1) + continue; + if (line < clips[clip].c.top) { + if (maxline > clips[clip].c.top-1) + maxline = clips[clip].c.top-1; + continue; + } + if (maxline > clips[clip].c.top+clips[clip].c.height-1) + maxline = clips[clip].c.top+clips[clip].c.height-1; + + /* horizontal range */ + if (0 == skip || clips[clip].c.left > skips[skip-1].end) { + /* new one */ + skips[skip].start = clips[clip].c.left; + if (skips[skip].start < 0) + skips[skip].start = 0; + skips[skip].end = clips[clip].c.left + clips[clip].c.width; + if (skips[skip].end > width) + skips[skip].end = width; + skip++; + } else { + /* overlaps -- expand last one */ + end = clips[clip].c.left + clips[clip].c.width; + if (skips[skip-1].end < end) + skips[skip-1].end = end; + if (skips[skip-1].end > width) + skips[skip-1].end = width; + } + } + *nskips = skip; + *maxy = maxline; + + if (debug) { + printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline); + for (skip = 0; skip < *nskips; skip++) { + printk(" %d-%d",skips[skip].start,skips[skip].end); + } + printk("\n"); + } +} + +/* ---------------------------------------------------------- */ + +EXPORT_SYMBOL(btcx_riscmem_alloc); +EXPORT_SYMBOL(btcx_riscmem_free); + +EXPORT_SYMBOL(btcx_screen_clips); +EXPORT_SYMBOL(btcx_align); +EXPORT_SYMBOL(btcx_sort_clips); +EXPORT_SYMBOL(btcx_calc_skips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/btcx-risc.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/btcx-risc.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/btcx-risc.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/btcx-risc.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + */ +struct btcx_riscmem { + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bw-qcam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bw-qcam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bw-qcam.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/bw-qcam.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1094 @@ +/* + * QuickCam Driver For Video4Linux. + * + * Video4Linux conversion work by Alan Cox. + * Parport compatibility by Phil Blundell. + * Busy loop avoidance by Mark Cooke. + * + * Module parameters: + * + * maxpoll=<1 - 5000> + * + * When polling the QuickCam for a response, busy-wait for a + * maximum of this many loops. The default of 250 gives little + * impact on interactive response. + * + * NOTE: If this parameter is set too high, the processor + * will busy wait until this loop times out, and then + * slowly poll for a further 5 seconds before failing + * the transaction. You have been warned. + * + * yieldlines=<1 - 250> + * + * When acquiring a frame from the camera, the data gathering + * loop will yield back to the scheduler after completing + * this many lines. The default of 4 provides a trade-off + * between increased frame acquisition time and impact on + * interactive response. + */ + +/* qcam-lib.c -- Library for programming with the Connectix QuickCam. + * See the included documentation for usage instructions and details + * of the protocol involved. */ + + +/* Version 0.5, August 4, 1996 */ +/* Version 0.7, August 27, 1996 */ +/* Version 0.9, November 17, 1996 */ + + +/****************************************************************** + +Copyright (C) 1996 by Scott Laird + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* One from column A... */ +#define QC_NOTSET 0 +#define QC_UNIDIR 1 +#define QC_BIDIR 2 +#define QC_SERIAL 3 + +/* ... and one from column B */ +#define QC_ANY 0x00 +#define QC_FORCE_UNIDIR 0x10 +#define QC_FORCE_BIDIR 0x20 +#define QC_FORCE_SERIAL 0x30 +/* in the port_mode member */ + +#define QC_MODE_MASK 0x07 +#define QC_FORCE_MASK 0x70 + +#define MAX_HEIGHT 243 +#define MAX_WIDTH 336 + +/* Bit fields for status flags */ +#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ + +struct qcam { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct pardevice *pdev; + struct parport *pport; + struct mutex lock; + int width, height; + int bpp; + int mode; + int contrast, brightness, whitebal; + int port_mode; + int transfer_scale; + int top, left; + int status; + unsigned int saved_bits; + unsigned long in_use; +}; + +static unsigned int maxpoll = 250; /* Maximum busy-loop count for qcam I/O */ +static unsigned int yieldlines = 4; /* Yield after this many during capture */ +static int video_nr = -1; +static unsigned int force_init; /* Whether to probe aggressively */ + +module_param(maxpoll, int, 0); +module_param(yieldlines, int, 0); +module_param(video_nr, int, 0); + +/* Set force_init=1 to avoid detection by polling status register and + * immediately attempt to initialize qcam */ +module_param(force_init, int, 0); + +#define MAX_CAMS 4 +static struct qcam *qcams[MAX_CAMS]; +static unsigned int num_cams; + +static inline int read_lpstatus(struct qcam *q) +{ + return parport_read_status(q->pport); +} + +static inline int read_lpdata(struct qcam *q) +{ + return parport_read_data(q->pport); +} + +static inline void write_lpdata(struct qcam *q, int d) +{ + parport_write_data(q->pport, d); +} + +static void write_lpcontrol(struct qcam *q, int d) +{ + if (d & 0x20) { + /* Set bidirectional mode to reverse (data in) */ + parport_data_reverse(q->pport); + } else { + /* Set bidirectional mode to forward (data out) */ + parport_data_forward(q->pport); + } + + /* Now issue the regular port command, but strip out the + * direction flag */ + d &= ~0x20; + parport_write_control(q->pport, d); +} + + +/* qc_waithand busy-waits for a handshake signal from the QuickCam. + * Almost all communication with the camera requires handshaking. */ + +static int qc_waithand(struct qcam *q, int val) +{ + int status; + int runs = 0; + + if (val) { + while (!((status = read_lpstatus(q)) & 8)) { + /* 1000 is enough spins on the I/O for all normal + cases, at that point we start to poll slowly + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ + + if (runs++ > maxpoll) + msleep_interruptible(5); + if (runs > (maxpoll + 1000)) /* 5 seconds */ + return -1; + } + } else { + while (((status = read_lpstatus(q)) & 8)) { + /* 1000 is enough spins on the I/O for all normal + cases, at that point we start to poll slowly + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ + + if (runs++ > maxpoll) + msleep_interruptible(5); + if (runs++ > (maxpoll + 1000)) /* 5 seconds */ + return -1; + } + } + + return status; +} + +/* Waithand2 is used when the qcam is in bidirectional mode, and the + * handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1 + * (bit 3 of status register). It also returns the last value read, + * since this data is useful. */ + +static unsigned int qc_waithand2(struct qcam *q, int val) +{ + unsigned int status; + int runs = 0; + + do { + status = read_lpdata(q); + /* 1000 is enough spins on the I/O for all normal + cases, at that point we start to poll slowly + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ + + if (runs++ > maxpoll) + msleep_interruptible(5); + if (runs++ > (maxpoll + 1000)) /* 5 seconds */ + return 0; + } while ((status & 1) != val); + + return status; +} + +/* qc_command is probably a bit of a misnomer -- it's used to send + * bytes *to* the camera. Generally, these bytes are either commands + * or arguments to commands, so the name fits, but it still bugs me a + * bit. See the documentation for a list of commands. */ + +static int qc_command(struct qcam *q, int command) +{ + int n1, n2; + int cmd; + + write_lpdata(q, command); + write_lpcontrol(q, 6); + + n1 = qc_waithand(q, 1); + + write_lpcontrol(q, 0xe); + n2 = qc_waithand(q, 0); + + cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); + return cmd; +} + +static int qc_readparam(struct qcam *q) +{ + int n1, n2; + int cmd; + + write_lpcontrol(q, 6); + n1 = qc_waithand(q, 1); + + write_lpcontrol(q, 0xe); + n2 = qc_waithand(q, 0); + + cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); + return cmd; +} + + +/* Try to detect a QuickCam. It appears to flash the upper 4 bits of + the status register at 5-10 Hz. This is only used in the autoprobe + code. Be aware that this isn't the way Connectix detects the + camera (they send a reset and try to handshake), but this should be + almost completely safe, while their method screws up my printer if + I plug it in before the camera. */ + +static int qc_detect(struct qcam *q) +{ + int reg, lastreg; + int count = 0; + int i; + + if (force_init) + return 1; + + lastreg = reg = read_lpstatus(q) & 0xf0; + + for (i = 0; i < 500; i++) { + reg = read_lpstatus(q) & 0xf0; + if (reg != lastreg) + count++; + lastreg = reg; + mdelay(2); + } + + +#if 0 + /* Force camera detection during testing. Sometimes the camera + won't be flashing these bits. Possibly unloading the module + in the middle of a grab? Or some timeout condition? + I've seen this parameter as low as 19 on my 450Mhz box - mpc */ + printk(KERN_DEBUG "Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count); + return 1; +#endif + + /* Be (even more) liberal in what you accept... */ + + if (count > 20 && count < 400) { + return 1; /* found */ + } else { + printk(KERN_ERR "No Quickcam found on port %s\n", + q->pport->name); + printk(KERN_DEBUG "Quickcam detection counter: %u\n", count); + return 0; /* not found */ + } +} + +/* Decide which scan mode to use. There's no real requirement that + * the scanmode match the resolution in q->height and q-> width -- the + * camera takes the picture at the resolution specified in the + * "scanmode" and then returns the image at the resolution specified + * with the resolution commands. If the scan is bigger than the + * requested resolution, the upper-left hand corner of the scan is + * returned. If the scan is smaller, then the rest of the image + * returned contains garbage. */ + +static int qc_setscanmode(struct qcam *q) +{ + int old_mode = q->mode; + + switch (q->transfer_scale) { + case 1: + q->mode = 0; + break; + case 2: + q->mode = 4; + break; + case 4: + q->mode = 8; + break; + } + + switch (q->bpp) { + case 4: + break; + case 6: + q->mode += 2; + break; + } + + switch (q->port_mode & QC_MODE_MASK) { + case QC_BIDIR: + q->mode += 1; + break; + case QC_NOTSET: + case QC_UNIDIR: + break; + } + + if (q->mode != old_mode) + q->status |= QC_PARAM_CHANGE; + + return 0; +} + + +/* Reset the QuickCam. This uses the same sequence the Windows + * QuickPic program uses. Someone with a bi-directional port should + * check that bi-directional mode is detected right, and then + * implement bi-directional mode in qc_readbyte(). */ + +static void qc_reset(struct qcam *q) +{ + switch (q->port_mode & QC_FORCE_MASK) { + case QC_FORCE_UNIDIR: + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; + break; + + case QC_FORCE_BIDIR: + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; + break; + + case QC_ANY: + write_lpcontrol(q, 0x20); + write_lpdata(q, 0x75); + + if (read_lpdata(q) != 0x75) + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; + else + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; + break; + } + + write_lpcontrol(q, 0xb); + udelay(250); + write_lpcontrol(q, 0xe); + qc_setscanmode(q); /* in case port_mode changed */ +} + + + +/* Reset the QuickCam and program for brightness, contrast, + * white-balance, and resolution. */ + +static void qc_set(struct qcam *q) +{ + int val; + int val2; + + qc_reset(q); + + /* Set the brightness. Yes, this is repetitive, but it works. + * Shorter versions seem to fail subtly. Feel free to try :-). */ + /* I think the problem was in qc_command, not here -- bls */ + + qc_command(q, 0xb); + qc_command(q, q->brightness); + + val = q->height / q->transfer_scale; + qc_command(q, 0x11); + qc_command(q, val); + if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) { + /* The normal "transfers per line" calculation doesn't seem to work + as expected here (and yet it works fine in qc_scan). No idea + why this case is the odd man out. Fortunately, Laird's original + working version gives me a good way to guess at working values. + -- bls */ + val = q->width; + val2 = q->transfer_scale * 4; + } else { + val = q->width * q->bpp; + val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * + q->transfer_scale; + } + val = DIV_ROUND_UP(val, val2); + qc_command(q, 0x13); + qc_command(q, val); + + /* Setting top and left -- bls */ + qc_command(q, 0xd); + qc_command(q, q->top); + qc_command(q, 0xf); + qc_command(q, q->left / 2); + + qc_command(q, 0x19); + qc_command(q, q->contrast); + qc_command(q, 0x1f); + qc_command(q, q->whitebal); + + /* Clear flag that we must update the grabbing parameters on the camera + before we grab the next frame */ + q->status &= (~QC_PARAM_CHANGE); +} + +/* Qc_readbytes reads some bytes from the QC and puts them in + the supplied buffer. It returns the number of bytes read, + or -1 on error. */ + +static inline int qc_readbytes(struct qcam *q, char buffer[]) +{ + int ret = 1; + unsigned int hi, lo; + unsigned int hi2, lo2; + static int state; + + if (buffer == NULL) { + state = 0; + return 0; + } + + switch (q->port_mode & QC_MODE_MASK) { + case QC_BIDIR: /* Bi-directional Port */ + write_lpcontrol(q, 0x26); + lo = (qc_waithand2(q, 1) >> 1); + hi = (read_lpstatus(q) >> 3) & 0x1f; + write_lpcontrol(q, 0x2e); + lo2 = (qc_waithand2(q, 0) >> 1); + hi2 = (read_lpstatus(q) >> 3) & 0x1f; + switch (q->bpp) { + case 4: + buffer[0] = lo & 0xf; + buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3); + buffer[2] = (hi & 0x1e) >> 1; + buffer[3] = lo2 & 0xf; + buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3); + buffer[5] = (hi2 & 0x1e) >> 1; + ret = 6; + break; + case 6: + buffer[0] = lo & 0x3f; + buffer[1] = ((lo & 0x40) >> 6) | (hi << 1); + buffer[2] = lo2 & 0x3f; + buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1); + ret = 4; + break; + } + break; + + case QC_UNIDIR: /* Unidirectional Port */ + write_lpcontrol(q, 6); + lo = (qc_waithand(q, 1) & 0xf0) >> 4; + write_lpcontrol(q, 0xe); + hi = (qc_waithand(q, 0) & 0xf0) >> 4; + + switch (q->bpp) { + case 4: + buffer[0] = lo; + buffer[1] = hi; + ret = 2; + break; + case 6: + switch (state) { + case 0: + buffer[0] = (lo << 2) | ((hi & 0xc) >> 2); + q->saved_bits = (hi & 3) << 4; + state = 1; + ret = 1; + break; + case 1: + buffer[0] = lo | q->saved_bits; + q->saved_bits = hi << 2; + state = 2; + ret = 1; + break; + case 2: + buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits; + buffer[1] = ((lo & 3) << 4) | hi; + state = 0; + ret = 2; + break; + } + break; + } + break; + } + return ret; +} + +/* requests a scan from the camera. It sends the correct instructions + * to the camera and then reads back the correct number of bytes. In + * previous versions of this routine the return structure contained + * the raw output from the camera, and there was a 'qc_convertscan' + * function that converted that to a useful format. In version 0.3 I + * rolled qc_convertscan into qc_scan and now I only return the + * converted scan. The format is just an one-dimensional array of + * characters, one for each pixel, with 0=black up to n=white, where + * n=2^(bit depth)-1. Ask me for more details if you don't understand + * this. */ + +static long qc_capture(struct qcam *q, char __user *buf, unsigned long len) +{ + int i, j, k, yield; + int bytes; + int linestotrans, transperline; + int divisor; + int pixels_per_line; + int pixels_read = 0; + int got = 0; + char buffer[6]; + int shift = 8 - q->bpp; + char invert; + + if (q->mode == -1) + return -ENXIO; + + qc_command(q, 0x7); + qc_command(q, q->mode); + + if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { + write_lpcontrol(q, 0x2e); /* turn port around */ + write_lpcontrol(q, 0x26); + qc_waithand(q, 1); + write_lpcontrol(q, 0x2e); + qc_waithand(q, 0); + } + + /* strange -- should be 15:63 below, but 4bpp is odd */ + invert = (q->bpp == 4) ? 16 : 63; + + linestotrans = q->height / q->transfer_scale; + pixels_per_line = q->width / q->transfer_scale; + transperline = q->width * q->bpp; + divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * + q->transfer_scale; + transperline = DIV_ROUND_UP(transperline, divisor); + + for (i = 0, yield = yieldlines; i < linestotrans; i++) { + for (pixels_read = j = 0; j < transperline; j++) { + bytes = qc_readbytes(q, buffer); + for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) { + int o; + if (buffer[k] == 0 && invert == 16) { + /* 4bpp is odd (again) -- inverter is 16, not 15, but output + must be 0-15 -- bls */ + buffer[k] = 16; + } + o = i * pixels_per_line + pixels_read + k; + if (o < len) { + got++; + put_user((invert - buffer[k]) << shift, buf + o); + } + } + pixels_read += bytes; + } + qc_readbytes(q, NULL); /* reset state machine */ + + /* Grabbing an entire frame from the quickcam is a lengthy + process. We don't (usually) want to busy-block the + processor for the entire frame. yieldlines is a module + parameter. If we yield every line, the minimum frame + time will be 240 / 200 = 1.2 seconds. The compile-time + default is to yield every 4 lines. */ + if (i >= yield) { + msleep_interruptible(5); + yield = i + yieldlines; + } + } + + if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { + write_lpcontrol(q, 2); + write_lpcontrol(q, 6); + udelay(3); + write_lpcontrol(q, 0xe); + } + if (got < len) + return got; + return len; +} + +/* + * Video4linux interfacing + */ + +static int qcam_querycap(struct file *file, void *priv, + struct v4l2_capability *vcap) +{ + struct qcam *qcam = video_drvdata(file); + + strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); + strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card)); + strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); + vcap->version = KERNEL_VERSION(0, 0, 2); + vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + return 0; +} + +static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + if (vin->index > 0) + return -EINVAL; + strlcpy(vin->name, "Camera", sizeof(vin->name)); + vin->type = V4L2_INPUT_TYPE_CAMERA; + vin->audioset = 0; + vin->tuner = 0; + vin->std = 0; + vin->status = 0; + return 0; +} + +static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) +{ + *inp = 0; + return 0; +} + +static int qcam_s_input(struct file *file, void *fh, unsigned int inp) +{ + return (inp > 0) ? -EINVAL : 0; +} + +static int qcam_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180); + case V4L2_CID_CONTRAST: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192); + case V4L2_CID_GAMMA: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105); + } + return -EINVAL; +} + +static int qcam_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = qcam->brightness; + break; + case V4L2_CID_CONTRAST: + ctrl->value = qcam->contrast; + break; + case V4L2_CID_GAMMA: + ctrl->value = qcam->whitebal; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int qcam_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + mutex_lock(&qcam->lock); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + qcam->brightness = ctrl->value; + break; + case V4L2_CID_CONTRAST: + qcam->contrast = ctrl->value; + break; + case V4L2_CID_GAMMA: + qcam->whitebal = ctrl->value; + break; + default: + ret = -EINVAL; + break; + } + if (ret == 0) { + qc_setscanmode(qcam); + qcam->status |= QC_PARAM_CHANGE; + } + mutex_unlock(&qcam->lock); + return ret; +} + +static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + pix->width = qcam->width / qcam->transfer_scale; + pix->height = qcam->height / qcam->transfer_scale; + pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = qcam->width; + pix->sizeimage = qcam->width * qcam->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + if (pix->height <= 60 || pix->width <= 80) { + pix->height = 60; + pix->width = 80; + } else if (pix->height <= 120 || pix->width <= 160) { + pix->height = 120; + pix->width = 160; + } else { + pix->height = 240; + pix->width = 320; + } + if (pix->pixelformat != V4L2_PIX_FMT_Y4 && + pix->pixelformat != V4L2_PIX_FMT_Y6) + pix->pixelformat = V4L2_PIX_FMT_Y4; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = pix->width; + pix->sizeimage = pix->width * pix->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + int ret = qcam_try_fmt_vid_cap(file, fh, fmt); + + if (ret) + return ret; + qcam->width = 320; + qcam->height = 240; + if (pix->height == 60) + qcam->transfer_scale = 4; + else if (pix->height == 120) + qcam->transfer_scale = 2; + else + qcam->transfer_scale = 1; + if (pix->pixelformat == V4L2_PIX_FMT_Y6) + qcam->bpp = 6; + else + qcam->bpp = 4; + + mutex_lock(&qcam->lock); + qc_setscanmode(qcam); + /* We must update the camera before we grab. We could + just have changed the grab size */ + qcam->status |= QC_PARAM_CHANGE; + mutex_unlock(&qcam->lock); + return 0; +} + +static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) +{ + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "4-Bit Monochrome", V4L2_PIX_FMT_Y4, + { 0, 0, 0, 0 } + }, + { 0, 0, 0, + "6-Bit Monochrome", V4L2_PIX_FMT_Y6, + { 0, 0, 0, 0 } + }, + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 1) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; +} + +static ssize_t qcam_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct qcam *qcam = video_drvdata(file); + int len; + parport_claim_or_block(qcam->pdev); + + mutex_lock(&qcam->lock); + + qc_reset(qcam); + + /* Update the camera parameters if we need to */ + if (qcam->status & QC_PARAM_CHANGE) + qc_set(qcam); + + len = qc_capture(qcam, buf, count); + + mutex_unlock(&qcam->lock); + + parport_release(qcam->pdev); + return len; +} + +static const struct v4l2_file_operations qcam_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .read = qcam_read, +}; + +static const struct v4l2_ioctl_ops qcam_ioctl_ops = { + .vidioc_querycap = qcam_querycap, + .vidioc_g_input = qcam_g_input, + .vidioc_s_input = qcam_s_input, + .vidioc_enum_input = qcam_enum_input, + .vidioc_queryctrl = qcam_queryctrl, + .vidioc_g_ctrl = qcam_g_ctrl, + .vidioc_s_ctrl = qcam_s_ctrl, + .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, +}; + +/* Initialize the QuickCam driver control structure. This is where + * defaults are set for people who don't have a config file.*/ + +static struct qcam *qcam_init(struct parport *port) +{ + struct qcam *qcam; + struct v4l2_device *v4l2_dev; + + qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL); + if (qcam == NULL) + return NULL; + + v4l2_dev = &qcam->v4l2_dev; + strlcpy(v4l2_dev->name, "bw-qcam", sizeof(v4l2_dev->name)); + + if (v4l2_device_register(NULL, v4l2_dev) < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return NULL; + } + + qcam->pport = port; + qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, + NULL, 0, NULL); + if (qcam->pdev == NULL) { + v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); + kfree(qcam); + return NULL; + } + + strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name)); + qcam->vdev.v4l2_dev = v4l2_dev; + qcam->vdev.fops = &qcam_fops; + qcam->vdev.ioctl_ops = &qcam_ioctl_ops; + qcam->vdev.release = video_device_release_empty; + video_set_drvdata(&qcam->vdev, qcam); + + mutex_init(&qcam->lock); + + qcam->port_mode = (QC_ANY | QC_NOTSET); + qcam->width = 320; + qcam->height = 240; + qcam->bpp = 4; + qcam->transfer_scale = 2; + qcam->contrast = 192; + qcam->brightness = 180; + qcam->whitebal = 105; + qcam->top = 1; + qcam->left = 14; + qcam->mode = -1; + qcam->status = QC_PARAM_CHANGE; + return qcam; +} + +static int qc_calibrate(struct qcam *q) +{ + /* + * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 + * The white balance is an individual value for each + * quickcam. + */ + + int value; + int count = 0; + + qc_command(q, 27); /* AutoAdjustOffset */ + qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ + + /* GetOffset (33) will read 255 until autocalibration */ + /* is finished. After that, a value of 1-254 will be */ + /* returned. */ + + do { + qc_command(q, 33); + value = qc_readparam(q); + mdelay(1); + schedule(); + count++; + } while (value == 0xff && count < 2048); + + q->whitebal = value; + return value; +} + +static int init_bwqcam(struct parport *port) +{ + struct qcam *qcam; + + if (num_cams == MAX_CAMS) { + printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); + return -ENOSPC; + } + + qcam = qcam_init(port); + if (qcam == NULL) + return -ENODEV; + + parport_claim_or_block(qcam->pdev); + + qc_reset(qcam); + + if (qc_detect(qcam) == 0) { + parport_release(qcam->pdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + qc_calibrate(qcam); + + parport_release(qcam->pdev); + + v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name); + + if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + + qcams[num_cams++] = qcam; + + return 0; +} + +static void close_bwqcam(struct qcam *qcam) +{ + video_unregister_device(&qcam->vdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); +} + +/* The parport parameter controls which parports will be scanned. + * Scanning all parports causes some printers to print a garbage page. + * -- March 14, 1999 Billy Donahue */ +#ifdef MODULE +static char *parport[MAX_CAMS] = { NULL, }; +module_param_array(parport, charp, NULL, 0); +#endif + +static int accept_bwqcam(struct parport *port) +{ +#ifdef MODULE + int n; + + if (parport[0] && strncmp(parport[0], "auto", 4) != 0) { + /* user gave parport parameters */ + for (n = 0; n < MAX_CAMS && parport[n]; n++) { + char *ep; + unsigned long r; + r = simple_strtoul(parport[n], &ep, 0); + if (ep == parport[n]) { + printk(KERN_ERR + "bw-qcam: bad port specifier \"%s\"\n", + parport[n]); + continue; + } + if (r == port->number) + return 1; + } + return 0; + } +#endif + return 1; +} + +static void bwqcam_attach(struct parport *port) +{ + if (accept_bwqcam(port)) + init_bwqcam(port); +} + +static void bwqcam_detach(struct parport *port) +{ + int i; + for (i = 0; i < num_cams; i++) { + struct qcam *qcam = qcams[i]; + if (qcam && qcam->pdev->port == port) { + qcams[i] = NULL; + close_bwqcam(qcam); + } + } +} + +static struct parport_driver bwqcam_driver = { + .name = "bw-qcam", + .attach = bwqcam_attach, + .detach = bwqcam_detach, +}; + +static void __exit exit_bw_qcams(void) +{ + parport_unregister_driver(&bwqcam_driver); +} + +static int __init init_bw_qcams(void) +{ +#ifdef MODULE + /* Do some sanity checks on the module parameters. */ + if (maxpoll > 5000) { + printk(KERN_INFO "Connectix Quickcam max-poll was above 5000. Using 5000.\n"); + maxpoll = 5000; + } + + if (yieldlines < 1) { + printk(KERN_INFO "Connectix Quickcam yieldlines was less than 1. Using 1.\n"); + yieldlines = 1; + } +#endif + return parport_register_driver(&bwqcam_driver); +} + +module_init(init_bw_qcams); +module_exit(exit_bw_qcams); + +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2493 @@ +/**************************************************************************** + * + * Filename: cpia2_core.c + * + * Copyright 2001, STMicrolectronics, Inc. + * Contact: steve.miller@st.com + * + * Description: + * This is a USB driver for CPia2 based video cameras. + * The infrastructure of this driver is based on the cpia usb driver by + * Jochen Scharrlach and Johannes Erdfeldt. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Stripped of 2.4 stuff ready for main kernel submit by + * Alan Cox + * + ****************************************************************************/ + +#include "cpia2.h" + +#include +#include +#include +#include + +/* #define _CPIA2_DEBUG_ */ + +#ifdef _CPIA2_DEBUG_ + +static const char *block_name[] = { + "System", + "VC", + "VP", + "IDATA" +}; +#endif + +static unsigned int debugs_on; /* default 0 - DEBUG_REG */ + + +/****************************************************************************** + * + * Forward Declarations + * + *****************************************************************************/ +static int apply_vp_patch(struct camera_data *cam); +static int set_default_user_mode(struct camera_data *cam); +static int set_vw_size(struct camera_data *cam, int size); +static int configure_sensor(struct camera_data *cam, + int reqwidth, int reqheight); +static int config_sensor_410(struct camera_data *cam, + int reqwidth, int reqheight); +static int config_sensor_500(struct camera_data *cam, + int reqwidth, int reqheight); +static int set_all_properties(struct camera_data *cam); +static void get_color_params(struct camera_data *cam); +static void wake_system(struct camera_data *cam); +static void set_lowlight_boost(struct camera_data *cam); +static void reset_camera_struct(struct camera_data *cam); +static int cpia2_set_high_power(struct camera_data *cam); + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long kva, ret; + + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + ret = __pa(kva); + return ret; +} + +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + /* Round it off to PAGE_SIZE */ + size = PAGE_ALIGN(size); + + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + + while ((long)size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr; + + if (!mem) + return; + + size = PAGE_ALIGN(size); + + adr = (unsigned long) mem; + while ((long)size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} + +/****************************************************************************** + * + * cpia2_do_command + * + * Send an arbitrary command to the camera. For commands that read from + * the camera, copy the buffers into the proper param structures. + *****************************************************************************/ +int cpia2_do_command(struct camera_data *cam, + u32 command, u8 direction, u8 param) +{ + int retval = 0; + struct cpia2_command cmd; + unsigned int device = cam->params.pnp_id.device_type; + + cmd.command = command; + cmd.reg_count = 2; /* default */ + cmd.direction = direction; + + /*** + * Set up the command. + ***/ + switch (command) { + case CPIA2_CMD_GET_VERSION: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.start = CPIA2_SYSTEM_DEVICE_HI; + break; + case CPIA2_CMD_GET_PNP_ID: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 8; + cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI; + break; + case CPIA2_CMD_GET_ASIC_TYPE: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.start = CPIA2_VC_ASIC_ID; + break; + case CPIA2_CMD_GET_SENSOR: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.start = CPIA2_VP_SENSOR_FLAGS; + break; + case CPIA2_CMD_GET_VP_DEVICE: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.start = CPIA2_VP_DEVICEH; + break; + case CPIA2_CMD_SET_VP_BRIGHTNESS: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_BRIGHTNESS: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP4_EXPOSURE_TARGET; + else + cmd.start = CPIA2_VP5_EXPOSURE_TARGET; + break; + case CPIA2_CMD_SET_CONTRAST: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_CONTRAST: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_YRANGE; + break; + case CPIA2_CMD_SET_VP_SATURATION: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_SATURATION: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP_SATURATION; + else + cmd.start = CPIA2_VP5_MCUVSATURATION; + break; + case CPIA2_CMD_SET_VP_GPIO_DATA: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_GPIO_DATA: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_GPIO_DATA; + break; + case CPIA2_CMD_SET_VP_GPIO_DIRECTION: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_GPIO_DIRECTION: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_GPIO_DIRECTION; + break; + case CPIA2_CMD_SET_VC_MP_GPIO_DATA: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VC_MP_GPIO_DATA: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_MP_DATA; + break; + case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_MP_DIR; + break; + case CPIA2_CMD_ENABLE_PACKET_CTRL: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL; + cmd.reg_count = 1; + cmd.buffer.block_data[0] = param; + break; + case CPIA2_CMD_SET_FLICKER_MODES: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_FLICKER_MODES: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_FLICKER_MODES; + break; + case CPIA2_CMD_RESET_FIFO: /* clear fifo and enable stream block */ + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.reg_count = 2; + cmd.start = 0; + cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL; + cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC | + CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT; + cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL; + cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC | + CPIA2_VC_ST_CTRL_DST_USB | + CPIA2_VC_ST_CTRL_EOF_DETECT | + CPIA2_VC_ST_CTRL_FIFO_ENABLE; + break; + case CPIA2_CMD_SET_HI_POWER: + cmd.req_mode = + CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM; + cmd.reg_count = 2; + cmd.buffer.registers[0].index = + CPIA2_SYSTEM_SYSTEM_CONTROL; + cmd.buffer.registers[1].index = + CPIA2_SYSTEM_SYSTEM_CONTROL; + cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR; + cmd.buffer.registers[1].value = + CPIA2_SYSTEM_CONTROL_HIGH_POWER; + break; + case CPIA2_CMD_SET_LOW_POWER: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 1; + cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; + cmd.buffer.block_data[0] = 0; + break; + case CPIA2_CMD_CLEAR_V2W_ERR: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 1; + cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; + cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR; + break; + case CPIA2_CMD_SET_USER_MODE: /* Then fall through */ + cmd.buffer.block_data[0] = param; + case CPIA2_CMD_GET_USER_MODE: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP4_USER_MODE; + else + cmd.start = CPIA2_VP5_USER_MODE; + break; + case CPIA2_CMD_FRAMERATE_REQ: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP4_FRAMERATE_REQUEST; + else + cmd.start = CPIA2_VP5_FRAMERATE_REQUEST; + cmd.buffer.block_data[0] = param; + break; + case CPIA2_CMD_SET_WAKEUP: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_WAKEUP: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_WAKEUP; + break; + case CPIA2_CMD_SET_PW_CONTROL: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_PW_CONTROL: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_PW_CTRL; + break; + case CPIA2_CMD_GET_VP_SYSTEM_STATE: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_SYSTEMSTATE; + break; + case CPIA2_CMD_SET_SYSTEM_CTRL: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_SYSTEM_CTRL: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 1; + cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; + break; + case CPIA2_CMD_SET_VP_SYSTEM_CTRL: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_SYSTEM_CTRL: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_SYSTEMCTRL; + break; + case CPIA2_CMD_SET_VP_EXP_MODES: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_EXP_MODES: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_EXPOSURE_MODES; + break; + case CPIA2_CMD_SET_DEVICE_CONFIG: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_DEVICE_CONFIG: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_DEVICE_CONFIG; + break; + case CPIA2_CMD_SET_SERIAL_ADDR: + cmd.buffer.block_data[0] = param; + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 1; + cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR; + break; + case CPIA2_CMD_SET_SENSOR_CR1: + cmd.buffer.block_data[0] = param; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_SENSOR_CR1; + break; + case CPIA2_CMD_SET_VC_CONTROL: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VC_CONTROL: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_VC_CTRL; + break; + case CPIA2_CMD_SET_TARGET_KB: + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB; + cmd.buffer.registers[0].value = param; + break; + case CPIA2_CMD_SET_DEF_JPEG_OPT: + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.reg_count = 4; + cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT; + cmd.buffer.registers[0].value = + CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE; + cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE; + cmd.buffer.registers[1].value = 20; + cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD; + cmd.buffer.registers[2].value = 2; + cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT; + cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT; + break; + case CPIA2_CMD_REHASH_VP4: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_REHASH_VALUES; + cmd.buffer.block_data[0] = param; + break; + case CPIA2_CMD_SET_USER_EFFECTS: /* Note: Be careful with this as + this register can also affect + flicker modes */ + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_USER_EFFECTS: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP4_USER_EFFECTS; + else + cmd.start = CPIA2_VP5_USER_EFFECTS; + break; + default: + LOG("DoCommand received invalid command\n"); + return -EINVAL; + } + + retval = cpia2_send_command(cam, &cmd); + if (retval) { + return retval; + } + + /*** + * Now copy any results from a read into the appropriate param struct. + ***/ + switch (command) { + case CPIA2_CMD_GET_VERSION: + cam->params.version.firmware_revision_hi = + cmd.buffer.block_data[0]; + cam->params.version.firmware_revision_lo = + cmd.buffer.block_data[1]; + break; + case CPIA2_CMD_GET_PNP_ID: + cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) | + cmd.buffer.block_data[1]; + cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) | + cmd.buffer.block_data[3]; + cam->params.pnp_id.device_revision = + (cmd.buffer.block_data[4] << 8) | + cmd.buffer.block_data[5]; + if (cam->params.pnp_id.vendor == 0x553) { + if (cam->params.pnp_id.product == 0x100) { + cam->params.pnp_id.device_type = DEVICE_STV_672; + } else if (cam->params.pnp_id.product == 0x140 || + cam->params.pnp_id.product == 0x151) { + cam->params.pnp_id.device_type = DEVICE_STV_676; + } + } + break; + case CPIA2_CMD_GET_ASIC_TYPE: + cam->params.version.asic_id = cmd.buffer.block_data[0]; + cam->params.version.asic_rev = cmd.buffer.block_data[1]; + break; + case CPIA2_CMD_GET_SENSOR: + cam->params.version.sensor_flags = cmd.buffer.block_data[0]; + cam->params.version.sensor_rev = cmd.buffer.block_data[1]; + break; + case CPIA2_CMD_GET_VP_DEVICE: + cam->params.version.vp_device_hi = cmd.buffer.block_data[0]; + cam->params.version.vp_device_lo = cmd.buffer.block_data[1]; + break; + case CPIA2_CMD_GET_VP_BRIGHTNESS: + cam->params.color_params.brightness = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_CONTRAST: + cam->params.color_params.contrast = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_SATURATION: + cam->params.color_params.saturation = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_GPIO_DATA: + cam->params.vp_params.gpio_data = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_GPIO_DIRECTION: + cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION: + cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VC_MP_GPIO_DATA: + cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_FLICKER_MODES: + cam->params.flicker_control.cam_register = + cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_WAKEUP: + cam->params.vc_params.wakeup = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_PW_CONTROL: + cam->params.vc_params.pw_control = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_SYSTEM_CTRL: + cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_SYSTEM_STATE: + cam->params.vp_params.system_state = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_SYSTEM_CTRL: + cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_EXP_MODES: + cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_DEVICE_CONFIG: + cam->params.vp_params.device_config = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VC_CONTROL: + cam->params.vc_params.vc_control = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_USER_MODE: + cam->params.vp_params.video_mode = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_USER_EFFECTS: + cam->params.vp_params.user_effects = cmd.buffer.block_data[0]; + break; + default: + break; + } + return retval; +} + +/****************************************************************************** + * + * cpia2_send_command + * + *****************************************************************************/ + +#define DIR(cmd) ((cmd->direction == TRANSFER_WRITE) ? "Write" : "Read") +#define BINDEX(cmd) (cmd->req_mode & 0x03) + +int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd) +{ + u8 count; + u8 start; + u8 *buffer; + int retval; + + switch (cmd->req_mode & 0x0c) { + case CAMERAACCESS_TYPE_RANDOM: + count = cmd->reg_count * sizeof(struct cpia2_register); + start = 0; + buffer = (u8 *) & cmd->buffer; + if (debugs_on & DEBUG_REG) + DBG("%s Random: Register block %s\n", DIR(cmd), + block_name[BINDEX(cmd)]); + break; + case CAMERAACCESS_TYPE_BLOCK: + count = cmd->reg_count; + start = cmd->start; + buffer = cmd->buffer.block_data; + if (debugs_on & DEBUG_REG) + DBG("%s Block: Register block %s\n", DIR(cmd), + block_name[BINDEX(cmd)]); + break; + case CAMERAACCESS_TYPE_MASK: + count = cmd->reg_count * sizeof(struct cpia2_reg_mask); + start = 0; + buffer = (u8 *) & cmd->buffer; + if (debugs_on & DEBUG_REG) + DBG("%s Mask: Register block %s\n", DIR(cmd), + block_name[BINDEX(cmd)]); + break; + case CAMERAACCESS_TYPE_REPEAT: /* For patch blocks only */ + count = cmd->reg_count; + start = cmd->start; + buffer = cmd->buffer.block_data; + if (debugs_on & DEBUG_REG) + DBG("%s Repeat: Register block %s\n", DIR(cmd), + block_name[BINDEX(cmd)]); + break; + default: + LOG("%s: invalid request mode\n",__func__); + return -EINVAL; + } + + retval = cpia2_usb_transfer_cmd(cam, + buffer, + cmd->req_mode, + start, count, cmd->direction); +#ifdef _CPIA2_DEBUG_ + if (debugs_on & DEBUG_REG) { + int i; + for (i = 0; i < cmd->reg_count; i++) { + if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK) + KINFO("%s Block: [0x%02X] = 0x%02X\n", + DIR(cmd), start + i, buffer[i]); + if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM) + KINFO("%s Random: [0x%02X] = 0x%02X\n", + DIR(cmd), cmd->buffer.registers[i].index, + cmd->buffer.registers[i].value); + } + } +#endif + + return retval; +}; + +/************* + * Functions to implement camera functionality + *************/ +/****************************************************************************** + * + * cpia2_get_version_info + * + *****************************************************************************/ +static void cpia2_get_version_info(struct camera_data *cam) +{ + cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0); +} + +/****************************************************************************** + * + * cpia2_reset_camera + * + * Called at least during the open process, sets up initial params. + *****************************************************************************/ +int cpia2_reset_camera(struct camera_data *cam) +{ + u8 tmp_reg; + int retval = 0; + int i; + struct cpia2_command cmd; + + /*** + * VC setup + ***/ + retval = configure_sensor(cam, + cam->params.roi.width, + cam->params.roi.height); + if (retval < 0) { + ERR("Couldn't configure sensor, error=%d\n", retval); + return retval; + } + + /* Clear FIFO and route/enable stream block */ + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.direction = TRANSFER_WRITE; + cmd.reg_count = 2; + cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL; + cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC | + CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT; + cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL; + cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC | + CPIA2_VC_ST_CTRL_DST_USB | + CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE; + + cpia2_send_command(cam, &cmd); + + cpia2_set_high_power(cam); + + if (cam->params.pnp_id.device_type == DEVICE_STV_672) { + /* Enable button notification */ + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM; + cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL; + cmd.buffer.registers[0].value = + CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX; + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + } + + schedule_timeout_interruptible(msecs_to_jiffies(100)); + + if (cam->params.pnp_id.device_type == DEVICE_STV_672) + retval = apply_vp_patch(cam); + + /* wait for vp to go to sleep */ + schedule_timeout_interruptible(msecs_to_jiffies(100)); + + /*** + * If this is a 676, apply VP5 fixes before we start streaming + ***/ + if (cam->params.pnp_id.device_type == DEVICE_STV_676) { + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; + + /* The following writes improve the picture */ + cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL; + cmd.buffer.registers[0].value = 0; /* reduce from the default + * rec 601 pedestal of 16 */ + cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE; + cmd.buffer.registers[1].value = 0x92; /* increase from 100% to + * (256/256 - 31) to fill + * available range */ + cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING; + cmd.buffer.registers[2].value = 0xFF; /* Increase from the + * default rec 601 ceiling + * of 240 */ + cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION; + cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec + * 601 100% level (128) + * to 145-192 */ + cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP; + cmd.buffer.registers[4].value = 0x80; /* Inhibit the + * anti-flicker */ + + /* The following 4 writes are a fix to allow QVGA to work at 30 fps */ + cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H; + cmd.buffer.registers[5].value = 0x01; + cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L; + cmd.buffer.registers[6].value = 0xE3; + cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA; + cmd.buffer.registers[7].value = 0x02; + cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA; + cmd.buffer.registers[8].value = 0xFC; + + cmd.direction = TRANSFER_WRITE; + cmd.reg_count = 9; + + cpia2_send_command(cam, &cmd); + } + + /* Activate all settings and start the data stream */ + /* Set user mode */ + set_default_user_mode(cam); + + /* Give VP time to wake up */ + schedule_timeout_interruptible(msecs_to_jiffies(100)); + + set_all_properties(cam); + + cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0); + DBG("After SetAllProperties(cam), user mode is 0x%0X\n", + cam->params.vp_params.video_mode); + + /*** + * Set audio regulator off. This and the code to set the compresison + * state are too complex to form a CPIA2_CMD_, and seem to be somewhat + * intertwined. This stuff came straight from the windows driver. + ***/ + /* Turn AutoExposure off in VP and enable the serial bridge to the sensor */ + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0); + tmp_reg = cam->params.vp_params.system_ctrl; + cmd.buffer.registers[0].value = tmp_reg & + (tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF)); + + cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0); + cmd.buffer.registers[1].value = cam->params.vp_params.device_config | + CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE; + cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL; + cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG; + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; + cmd.reg_count = 2; + cmd.direction = TRANSFER_WRITE; + cmd.start = 0; + cpia2_send_command(cam, &cmd); + + /* Set the correct I2C address in the CPiA-2 system register */ + cpia2_do_command(cam, + CPIA2_CMD_SET_SERIAL_ADDR, + TRANSFER_WRITE, + CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR); + + /* Now have sensor access - set bit to turn the audio regulator off */ + cpia2_do_command(cam, + CPIA2_CMD_SET_SENSOR_CR1, + TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR); + + /* Set the correct I2C address in the CPiA-2 system register */ + if (cam->params.pnp_id.device_type == DEVICE_STV_672) + cpia2_do_command(cam, + CPIA2_CMD_SET_SERIAL_ADDR, + TRANSFER_WRITE, + CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88 + else + cpia2_do_command(cam, + CPIA2_CMD_SET_SERIAL_ADDR, + TRANSFER_WRITE, + CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a + + /* increase signal drive strength */ + if (cam->params.pnp_id.device_type == DEVICE_STV_676) + cpia2_do_command(cam, + CPIA2_CMD_SET_VP_EXP_MODES, + TRANSFER_WRITE, + CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP); + + /* Start autoexposure */ + cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0); + cmd.buffer.registers[0].value = cam->params.vp_params.device_config & + (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF); + + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0); + cmd.buffer.registers[1].value = + cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL; + + cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG; + cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL; + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; + cmd.reg_count = 2; + cmd.direction = TRANSFER_WRITE; + + cpia2_send_command(cam, &cmd); + + /* Set compression state */ + cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0); + if (cam->params.compression.inhibit_htables) { + tmp_reg = cam->params.vc_params.vc_control | + CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES; + } else { + tmp_reg = cam->params.vc_params.vc_control & + ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES; + } + cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg); + + /* Set target size (kb) on vc */ + cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB, + TRANSFER_WRITE, cam->params.vc_params.target_kb); + + /* Wiggle VC Reset */ + /*** + * First read and wait a bit. + ***/ + for (i = 0; i < 50; i++) { + cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL, + TRANSFER_READ, 0); + } + + tmp_reg = cam->params.vc_params.pw_control; + tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N; + + cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg); + + tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N; + cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg); + + cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0); + + cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0); + DBG("After VC RESET, user mode is 0x%0X\n", + cam->params.vp_params.video_mode); + + return retval; +} + +/****************************************************************************** + * + * cpia2_set_high_power + * + *****************************************************************************/ +static int cpia2_set_high_power(struct camera_data *cam) +{ + int i; + for (i = 0; i <= 50; i++) { + /* Read system status */ + cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0); + + /* If there is an error, clear it */ + if(cam->params.camera_state.system_ctrl & + CPIA2_SYSTEM_CONTROL_V2W_ERR) + cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR, + TRANSFER_WRITE, 0); + + /* Try to set high power mode */ + cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, + TRANSFER_WRITE, 1); + + /* Try to read something in VP to check if everything is awake */ + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE, + TRANSFER_READ, 0); + if (cam->params.vp_params.system_state & + CPIA2_VP_SYSTEMSTATE_HK_ALIVE) { + break; + } else if (i == 50) { + cam->params.camera_state.power_mode = LO_POWER_MODE; + ERR("Camera did not wake up\n"); + return -EIO; + } + } + + DBG("System now in high power state\n"); + cam->params.camera_state.power_mode = HI_POWER_MODE; + return 0; +} + +/****************************************************************************** + * + * cpia2_set_low_power + * + *****************************************************************************/ +int cpia2_set_low_power(struct camera_data *cam) +{ + cam->params.camera_state.power_mode = LO_POWER_MODE; + cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0); + return 0; +} + +/****************************************************************************** + * + * apply_vp_patch + * + *****************************************************************************/ +static int cpia2_send_onebyte_command(struct camera_data *cam, + struct cpia2_command *cmd, + u8 start, u8 datum) +{ + cmd->buffer.block_data[0] = datum; + cmd->start = start; + cmd->reg_count = 1; + return cpia2_send_command(cam, cmd); +} + +static int apply_vp_patch(struct camera_data *cam) +{ + const struct firmware *fw; + const char fw_name[] = "cpia2/stv0672_vp4.bin"; + int i, ret; + struct cpia2_command cmd; + + ret = request_firmware(&fw, fw_name, &cam->dev->dev); + if (ret) { + printk(KERN_ERR "cpia2: failed to load VP patch \"%s\"\n", + fw_name); + return ret; + } + + cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP; + cmd.direction = TRANSFER_WRITE; + + /* First send the start address... */ + cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */ + cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */ + + /* ... followed by the data payload */ + for (i = 2; i < fw->size; i += 64) { + cmd.start = 0x0C; /* Data */ + cmd.reg_count = min_t(int, 64, fw->size - i); + memcpy(cmd.buffer.block_data, &fw->data[i], cmd.reg_count); + cpia2_send_command(cam, &cmd); + } + + /* Next send the start address... */ + cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */ + cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */ + + /* ... followed by the 'goto' command */ + cpia2_send_onebyte_command(cam, &cmd, 0x0D, 1); + + release_firmware(fw); + return 0; +} + +/****************************************************************************** + * + * set_default_user_mode + * + *****************************************************************************/ +static int set_default_user_mode(struct camera_data *cam) +{ + unsigned char user_mode; + unsigned char frame_rate; + int width = cam->params.roi.width; + int height = cam->params.roi.height; + + switch (cam->params.version.sensor_flags) { + case CPIA2_VP_SENSOR_FLAGS_404: + case CPIA2_VP_SENSOR_FLAGS_407: + case CPIA2_VP_SENSOR_FLAGS_409: + case CPIA2_VP_SENSOR_FLAGS_410: + if ((width > STV_IMAGE_QCIF_COLS) + || (height > STV_IMAGE_QCIF_ROWS)) { + user_mode = CPIA2_VP_USER_MODE_CIF; + } else { + user_mode = CPIA2_VP_USER_MODE_QCIFDS; + } + frame_rate = CPIA2_VP_FRAMERATE_30; + break; + case CPIA2_VP_SENSOR_FLAGS_500: + if ((width > STV_IMAGE_CIF_COLS) + || (height > STV_IMAGE_CIF_ROWS)) { + user_mode = CPIA2_VP_USER_MODE_VGA; + } else { + user_mode = CPIA2_VP_USER_MODE_QVGADS; + } + if (cam->params.pnp_id.device_type == DEVICE_STV_672) + frame_rate = CPIA2_VP_FRAMERATE_15; + else + frame_rate = CPIA2_VP_FRAMERATE_30; + break; + default: + LOG("%s: Invalid sensor flag value 0x%0X\n",__func__, + cam->params.version.sensor_flags); + return -EINVAL; + } + + DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n", + cam->params.version.sensor_flags, user_mode, frame_rate); + cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE, + user_mode); + if(cam->params.vp_params.frame_rate > 0 && + frame_rate > cam->params.vp_params.frame_rate) + frame_rate = cam->params.vp_params.frame_rate; + + cpia2_set_fps(cam, frame_rate); + +// if (cam->params.pnp_id.device_type == DEVICE_STV_676) +// cpia2_do_command(cam, +// CPIA2_CMD_SET_VP_SYSTEM_CTRL, +// TRANSFER_WRITE, +// CPIA2_VP_SYSTEMCTRL_HK_CONTROL | +// CPIA2_VP_SYSTEMCTRL_POWER_CONTROL); + + return 0; +} + +/****************************************************************************** + * + * cpia2_match_video_size + * + * return the best match, where 'best' is as always + * the largest that is not bigger than what is requested. + *****************************************************************************/ +int cpia2_match_video_size(int width, int height) +{ + if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS) + return VIDEOSIZE_VGA; + + if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS) + return VIDEOSIZE_CIF; + + if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS) + return VIDEOSIZE_QVGA; + + if (width >= 288 && height >= 216) + return VIDEOSIZE_288_216; + + if (width >= 256 && height >= 192) + return VIDEOSIZE_256_192; + + if (width >= 224 && height >= 168) + return VIDEOSIZE_224_168; + + if (width >= 192 && height >= 144) + return VIDEOSIZE_192_144; + + if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS) + return VIDEOSIZE_QCIF; + + return -1; +} + +/****************************************************************************** + * + * SetVideoSize + * + *****************************************************************************/ +static int set_vw_size(struct camera_data *cam, int size) +{ + int retval = 0; + + cam->params.vp_params.video_size = size; + + switch (size) { + case VIDEOSIZE_VGA: + DBG("Setting size to VGA\n"); + cam->params.roi.width = STV_IMAGE_VGA_COLS; + cam->params.roi.height = STV_IMAGE_VGA_ROWS; + cam->width = STV_IMAGE_VGA_COLS; + cam->height = STV_IMAGE_VGA_ROWS; + break; + case VIDEOSIZE_CIF: + DBG("Setting size to CIF\n"); + cam->params.roi.width = STV_IMAGE_CIF_COLS; + cam->params.roi.height = STV_IMAGE_CIF_ROWS; + cam->width = STV_IMAGE_CIF_COLS; + cam->height = STV_IMAGE_CIF_ROWS; + break; + case VIDEOSIZE_QVGA: + DBG("Setting size to QVGA\n"); + cam->params.roi.width = STV_IMAGE_QVGA_COLS; + cam->params.roi.height = STV_IMAGE_QVGA_ROWS; + cam->width = STV_IMAGE_QVGA_COLS; + cam->height = STV_IMAGE_QVGA_ROWS; + break; + case VIDEOSIZE_288_216: + cam->params.roi.width = 288; + cam->params.roi.height = 216; + cam->width = 288; + cam->height = 216; + break; + case VIDEOSIZE_256_192: + cam->width = 256; + cam->height = 192; + cam->params.roi.width = 256; + cam->params.roi.height = 192; + break; + case VIDEOSIZE_224_168: + cam->width = 224; + cam->height = 168; + cam->params.roi.width = 224; + cam->params.roi.height = 168; + break; + case VIDEOSIZE_192_144: + cam->width = 192; + cam->height = 144; + cam->params.roi.width = 192; + cam->params.roi.height = 144; + break; + case VIDEOSIZE_QCIF: + DBG("Setting size to QCIF\n"); + cam->params.roi.width = STV_IMAGE_QCIF_COLS; + cam->params.roi.height = STV_IMAGE_QCIF_ROWS; + cam->width = STV_IMAGE_QCIF_COLS; + cam->height = STV_IMAGE_QCIF_ROWS; + break; + default: + retval = -EINVAL; + } + return retval; +} + +/****************************************************************************** + * + * configure_sensor + * + *****************************************************************************/ +static int configure_sensor(struct camera_data *cam, + int req_width, int req_height) +{ + int retval; + + switch (cam->params.version.sensor_flags) { + case CPIA2_VP_SENSOR_FLAGS_404: + case CPIA2_VP_SENSOR_FLAGS_407: + case CPIA2_VP_SENSOR_FLAGS_409: + case CPIA2_VP_SENSOR_FLAGS_410: + retval = config_sensor_410(cam, req_width, req_height); + break; + case CPIA2_VP_SENSOR_FLAGS_500: + retval = config_sensor_500(cam, req_width, req_height); + break; + default: + return -EINVAL; + } + + return retval; +} + +/****************************************************************************** + * + * config_sensor_410 + * + *****************************************************************************/ +static int config_sensor_410(struct camera_data *cam, + int req_width, int req_height) +{ + struct cpia2_command cmd; + int i = 0; + int image_size; + int image_type; + int width = req_width; + int height = req_height; + + /*** + * Make sure size doesn't exceed CIF. + ***/ + if (width > STV_IMAGE_CIF_COLS) + width = STV_IMAGE_CIF_COLS; + if (height > STV_IMAGE_CIF_ROWS) + height = STV_IMAGE_CIF_ROWS; + + image_size = cpia2_match_video_size(width, height); + + DBG("Config 410: width = %d, height = %d\n", width, height); + DBG("Image size returned is %d\n", image_size); + if (image_size >= 0) { + set_vw_size(cam, image_size); + width = cam->params.roi.width; + height = cam->params.roi.height; + + DBG("After set_vw_size(), width = %d, height = %d\n", + width, height); + if (width <= 176 && height <= 144) { + DBG("image type = VIDEOSIZE_QCIF\n"); + image_type = VIDEOSIZE_QCIF; + } + else if (width <= 320 && height <= 240) { + DBG("image type = VIDEOSIZE_QVGA\n"); + image_type = VIDEOSIZE_QVGA; + } + else { + DBG("image type = VIDEOSIZE_CIF\n"); + image_type = VIDEOSIZE_CIF; + } + } else { + ERR("ConfigSensor410 failed\n"); + return -EINVAL; + } + + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.direction = TRANSFER_WRITE; + + /* VC Format */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT; + if (image_type == VIDEOSIZE_CIF) { + cmd.buffer.registers[i++].value = + (u8) (CPIA2_VC_VC_FORMAT_UFIRST | + CPIA2_VC_VC_FORMAT_SHORTLINE); + } else { + cmd.buffer.registers[i++].value = + (u8) CPIA2_VC_VC_FORMAT_UFIRST; + } + + /* VC Clocks */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS; + if (image_type == VIDEOSIZE_QCIF) { + if (cam->params.pnp_id.device_type == DEVICE_STV_672) { + cmd.buffer.registers[i++].value= + (u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 | + CPIA2_VC_VC_672_CLOCKS_SCALING | + CPIA2_VC_VC_CLOCKS_LOGDIV2); + DBG("VC_Clocks (0xc4) should be B\n"); + } + else { + cmd.buffer.registers[i++].value= + (u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 | + CPIA2_VC_VC_CLOCKS_LOGDIV2); + } + } else { + if (cam->params.pnp_id.device_type == DEVICE_STV_672) { + cmd.buffer.registers[i++].value = + (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 | + CPIA2_VC_VC_CLOCKS_LOGDIV0); + } + else { + cmd.buffer.registers[i++].value = + (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 | + CPIA2_VC_VC_676_CLOCKS_SCALING | + CPIA2_VC_VC_CLOCKS_LOGDIV0); + } + } + DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value); + + /* Input reqWidth from VC */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = + (u8) (STV_IMAGE_QCIF_COLS / 4); + else + cmd.buffer.registers[i++].value = + (u8) (STV_IMAGE_CIF_COLS / 4); + + /* Timings */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 0; + else + cmd.buffer.registers[i++].value = (u8) 1; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 208; + else + cmd.buffer.registers[i++].value = (u8) 160; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 0; + else + cmd.buffer.registers[i++].value = (u8) 1; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 160; + else + cmd.buffer.registers[i++].value = (u8) 64; + + /* Output Image Size */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE; + cmd.buffer.registers[i++].value = cam->params.roi.width / 4; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE; + cmd.buffer.registers[i++].value = cam->params.roi.height / 4; + + /* Cropping */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2); + else + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2); + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2); + else + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2); + + /* Scaling registers (defaults) */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN; + cmd.buffer.registers[i++].value = (u8) 31; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN; + cmd.buffer.registers[i++].value = (u8) 31; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT; + cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */ + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT; + cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */ + + cmd.reg_count = i; + + cpia2_send_command(cam, &cmd); + + return i; +} + + +/****************************************************************************** + * + * config_sensor_500(cam) + * + *****************************************************************************/ +static int config_sensor_500(struct camera_data *cam, + int req_width, int req_height) +{ + struct cpia2_command cmd; + int i = 0; + int image_size = VIDEOSIZE_CIF; + int image_type = VIDEOSIZE_VGA; + int width = req_width; + int height = req_height; + unsigned int device = cam->params.pnp_id.device_type; + + image_size = cpia2_match_video_size(width, height); + + if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS) + image_type = VIDEOSIZE_VGA; + else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS) + image_type = VIDEOSIZE_CIF; + else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS) + image_type = VIDEOSIZE_QVGA; + else + image_type = VIDEOSIZE_QCIF; + + if (image_size >= 0) { + set_vw_size(cam, image_size); + width = cam->params.roi.width; + height = cam->params.roi.height; + } else { + ERR("ConfigSensor500 failed\n"); + return -EINVAL; + } + + DBG("image_size = %d, width = %d, height = %d, type = %d\n", + image_size, width, height, image_type); + + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.direction = TRANSFER_WRITE; + i = 0; + + /* VC Format */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT; + cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING; + i++; + + /* VC Clocks */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS; + if (device == DEVICE_STV_672) { + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i].value = + (u8)CPIA2_VC_VC_CLOCKS_LOGDIV1; + else + cmd.buffer.registers[i].value = + (u8)(CPIA2_VC_VC_672_CLOCKS_SCALING | + CPIA2_VC_VC_CLOCKS_LOGDIV3); + } else { + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i].value = + (u8)CPIA2_VC_VC_CLOCKS_LOGDIV0; + else + cmd.buffer.registers[i].value = + (u8)(CPIA2_VC_VC_676_CLOCKS_SCALING | + CPIA2_VC_VC_CLOCKS_LOGDIV2); + } + i++; + + DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value); + + /* Input width from VP */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i].value = + (u8) (STV_IMAGE_VGA_COLS / 4); + else + cmd.buffer.registers[i].value = + (u8) (STV_IMAGE_QVGA_COLS / 4); + i++; + DBG("Input width = %d\n", cmd.buffer.registers[i-1].value); + + /* Timings */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = (u8) 2; + else + cmd.buffer.registers[i++].value = (u8) 1; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = (u8) 250; + else if (image_type == VIDEOSIZE_QVGA) + cmd.buffer.registers[i++].value = (u8) 125; + else + cmd.buffer.registers[i++].value = (u8) 160; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = (u8) 2; + else + cmd.buffer.registers[i++].value = (u8) 1; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = (u8) 12; + else if (image_type == VIDEOSIZE_QVGA) + cmd.buffer.registers[i++].value = (u8) 64; + else + cmd.buffer.registers[i++].value = (u8) 6; + + /* Output Image Size */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS / 4; + else + cmd.buffer.registers[i++].value = width / 4; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS / 4; + else + cmd.buffer.registers[i++].value = height / 4; + + /* Cropping */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2); + else if (image_type == VIDEOSIZE_QVGA) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2); + else if (image_type == VIDEOSIZE_CIF) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2); + else /*if (image_type == VIDEOSIZE_QCIF)*/ + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2); + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2); + else if (image_type == VIDEOSIZE_QVGA) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2); + else if (image_type == VIDEOSIZE_CIF) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2); + else /*if (image_type == VIDEOSIZE_QCIF)*/ + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2); + + /* Scaling registers (defaults) */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 36; + else + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 32; + else + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 26; + else + cmd.buffer.registers[i++].value = (u8) 31; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 21; + else + cmd.buffer.registers[i++].value = (u8) 31; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 0x2B; /* 2/11 */ + else + cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */ + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 0x13; /* 1/3 */ + else + cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */ + + cmd.reg_count = i; + + cpia2_send_command(cam, &cmd); + + return i; +} + + +/****************************************************************************** + * + * setallproperties + * + * This sets all user changeable properties to the values in cam->params. + *****************************************************************************/ +static int set_all_properties(struct camera_data *cam) +{ + /** + * Don't set target_kb here, it will be set later. + * framerate and user_mode were already set (set_default_user_mode). + **/ + + cpia2_set_color_params(cam); + + cpia2_usb_change_streaming_alternate(cam, + cam->params.camera_state.stream_mode); + + cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, + cam->params.vp_params.user_effects); + + cpia2_set_flicker_mode(cam, + cam->params.flicker_control.flicker_mode_req); + + cpia2_do_command(cam, + CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, + TRANSFER_WRITE, cam->params.vp_params.gpio_direction); + cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE, + cam->params.vp_params.gpio_data); + + wake_system(cam); + + set_lowlight_boost(cam); + + return 0; +} + +/****************************************************************************** + * + * cpia2_save_camera_state + * + *****************************************************************************/ +void cpia2_save_camera_state(struct camera_data *cam) +{ + get_color_params(cam); + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ, + 0); + cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0); + /* Don't get framerate or target_kb. Trust the values we already have */ +} + +/****************************************************************************** + * + * get_color_params + * + *****************************************************************************/ +static void get_color_params(struct camera_data *cam) +{ + cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, TRANSFER_READ, 0); +} + +/****************************************************************************** + * + * cpia2_set_color_params + * + *****************************************************************************/ +void cpia2_set_color_params(struct camera_data *cam) +{ + DBG("Setting color params\n"); + cpia2_set_brightness(cam, cam->params.color_params.brightness); + cpia2_set_contrast(cam, cam->params.color_params.contrast); + cpia2_set_saturation(cam, cam->params.color_params.saturation); +} + +/****************************************************************************** + * + * cpia2_set_flicker_mode + * + *****************************************************************************/ +int cpia2_set_flicker_mode(struct camera_data *cam, int mode) +{ + unsigned char cam_reg; + int err = 0; + + if(cam->params.pnp_id.device_type != DEVICE_STV_672) + return -EINVAL; + + /* Set the appropriate bits in FLICKER_MODES, preserving the rest */ + if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, + TRANSFER_READ, 0))) + return err; + cam_reg = cam->params.flicker_control.cam_register; + + switch(mode) { + case NEVER_FLICKER: + cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; + cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ; + break; + case FLICKER_60: + cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; + cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ; + break; + case FLICKER_50: + cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; + cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ; + break; + default: + return -EINVAL; + } + + if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES, + TRANSFER_WRITE, cam_reg))) + return err; + + /* Set the appropriate bits in EXP_MODES, preserving the rest */ + if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES, + TRANSFER_READ, 0))) + return err; + cam_reg = cam->params.vp_params.exposure_modes; + + if (mode == NEVER_FLICKER) { + cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER; + } else { + cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER; + } + + if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES, + TRANSFER_WRITE, cam_reg))) + return err; + + if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, + TRANSFER_WRITE, 1))) + return err; + + switch(mode) { + case NEVER_FLICKER: + cam->params.flicker_control.flicker_mode_req = mode; + break; + case FLICKER_60: + cam->params.flicker_control.flicker_mode_req = mode; + cam->params.flicker_control.mains_frequency = 60; + break; + case FLICKER_50: + cam->params.flicker_control.flicker_mode_req = mode; + cam->params.flicker_control.mains_frequency = 50; + break; + default: + err = -EINVAL; + } + + return err; +} + +/****************************************************************************** + * + * cpia2_set_property_flip + * + *****************************************************************************/ +void cpia2_set_property_flip(struct camera_data *cam, int prop_val) +{ + unsigned char cam_reg; + + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); + cam_reg = cam->params.vp_params.user_effects; + + if (prop_val) + { + cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP; + } + else + { + cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP; + } + cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, + cam_reg); +} + +/****************************************************************************** + * + * cpia2_set_property_mirror + * + *****************************************************************************/ +void cpia2_set_property_mirror(struct camera_data *cam, int prop_val) +{ + unsigned char cam_reg; + + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); + cam_reg = cam->params.vp_params.user_effects; + + if (prop_val) + { + cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR; + } + else + { + cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR; + } + cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, + cam_reg); +} + +/****************************************************************************** + * + * set_target_kb + * + * The new Target KB is set in cam->params.vc_params.target_kb and + * activates on reset. + *****************************************************************************/ + +int cpia2_set_target_kb(struct camera_data *cam, unsigned char value) +{ + DBG("Requested target_kb = %d\n", value); + if (value != cam->params.vc_params.target_kb) { + + cpia2_usb_stream_pause(cam); + + /* reset camera for new target_kb */ + cam->params.vc_params.target_kb = value; + cpia2_reset_camera(cam); + + cpia2_usb_stream_resume(cam); + } + + return 0; +} + +/****************************************************************************** + * + * cpia2_set_gpio + * + *****************************************************************************/ +int cpia2_set_gpio(struct camera_data *cam, unsigned char setting) +{ + int ret; + + /* Set the microport direction (register 0x90, should be defined + * already) to 1 (user output), and set the microport data (0x91) to + * the value in the ioctl argument. + */ + + ret = cpia2_do_command(cam, + CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, + CPIA2_VC_MP_DIR_OUTPUT, + 255); + if (ret < 0) + return ret; + cam->params.vp_params.gpio_direction = 255; + + ret = cpia2_do_command(cam, + CPIA2_CMD_SET_VC_MP_GPIO_DATA, + CPIA2_VC_MP_DIR_OUTPUT, + setting); + if (ret < 0) + return ret; + cam->params.vp_params.gpio_data = setting; + + return 0; +} + +/****************************************************************************** + * + * cpia2_set_fps + * + *****************************************************************************/ +int cpia2_set_fps(struct camera_data *cam, int framerate) +{ + int retval; + + switch(framerate) { + case CPIA2_VP_FRAMERATE_30: + case CPIA2_VP_FRAMERATE_25: + if(cam->params.pnp_id.device_type == DEVICE_STV_672 && + cam->params.version.sensor_flags == + CPIA2_VP_SENSOR_FLAGS_500) { + return -EINVAL; + } + /* Fall through */ + case CPIA2_VP_FRAMERATE_15: + case CPIA2_VP_FRAMERATE_12_5: + case CPIA2_VP_FRAMERATE_7_5: + case CPIA2_VP_FRAMERATE_6_25: + break; + default: + return -EINVAL; + } + + if (cam->params.pnp_id.device_type == DEVICE_STV_672 && + framerate == CPIA2_VP_FRAMERATE_15) + framerate = 0; /* Work around bug in VP4 */ + + retval = cpia2_do_command(cam, + CPIA2_CMD_FRAMERATE_REQ, + TRANSFER_WRITE, + framerate); + + if(retval == 0) + cam->params.vp_params.frame_rate = framerate; + + return retval; +} + +/****************************************************************************** + * + * cpia2_set_brightness + * + *****************************************************************************/ +void cpia2_set_brightness(struct camera_data *cam, unsigned char value) +{ + /*** + * Don't let the register be set to zero - bug in VP4 - flash of full + * brightness + ***/ + if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0) + value++; + DBG("Setting brightness to %d (0x%0x)\n", value, value); + cpia2_do_command(cam,CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE,value); +} + +/****************************************************************************** + * + * cpia2_set_contrast + * + *****************************************************************************/ +void cpia2_set_contrast(struct camera_data *cam, unsigned char value) +{ + DBG("Setting contrast to %d (0x%0x)\n", value, value); + cam->params.color_params.contrast = value; + cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value); +} + +/****************************************************************************** + * + * cpia2_set_saturation + * + *****************************************************************************/ +void cpia2_set_saturation(struct camera_data *cam, unsigned char value) +{ + DBG("Setting saturation to %d (0x%0x)\n", value, value); + cam->params.color_params.saturation = value; + cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value); +} + +/****************************************************************************** + * + * wake_system + * + *****************************************************************************/ +static void wake_system(struct camera_data *cam) +{ + cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0); +} + +/****************************************************************************** + * + * set_lowlight_boost + * + * Valid for STV500 sensor only + *****************************************************************************/ +static void set_lowlight_boost(struct camera_data *cam) +{ + struct cpia2_command cmd; + + if (cam->params.pnp_id.device_type != DEVICE_STV_672 || + cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500) + return; + + cmd.direction = TRANSFER_WRITE; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 3; + cmd.start = CPIA2_VP_RAM_ADDR_H; + + cmd.buffer.block_data[0] = 0; /* High byte of address to write to */ + cmd.buffer.block_data[1] = 0x59; /* Low byte of address to write to */ + cmd.buffer.block_data[2] = 0; /* High byte of data to write */ + + cpia2_send_command(cam, &cmd); + + if (cam->params.vp_params.lowlight_boost) { + cmd.buffer.block_data[0] = 0x02; /* Low byte data to write */ + } else { + cmd.buffer.block_data[0] = 0x06; + } + cmd.start = CPIA2_VP_RAM_DATA; + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + + /* Rehash the VP4 values */ + cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1); +} + +/****************************************************************************** + * + * cpia2_set_format + * + * Assumes that new size is already set in param struct. + *****************************************************************************/ +void cpia2_set_format(struct camera_data *cam) +{ + cam->flush = true; + + cpia2_usb_stream_pause(cam); + + /* reset camera to new size */ + cpia2_set_low_power(cam); + cpia2_reset_camera(cam); + cam->flush = false; + + cpia2_dbg_dump_registers(cam); + + cpia2_usb_stream_resume(cam); +} + +/****************************************************************************** + * + * cpia2_dbg_dump_registers + * + *****************************************************************************/ +void cpia2_dbg_dump_registers(struct camera_data *cam) +{ +#ifdef _CPIA2_DEBUG_ + struct cpia2_command cmd; + + if (!(debugs_on & DEBUG_DUMP_REGS)) + return; + + cmd.direction = TRANSFER_READ; + + /* Start with bank 0 (SYSTEM) */ + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 3; + cmd.start = 0; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "System Device Hi = 0x%X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "System Device Lo = 0x%X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "System_system control = 0x%X\n", + cmd.buffer.block_data[2]); + + /* Bank 1 (VC) */ + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 4; + cmd.start = 0x80; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "ASIC_ID = 0x%X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "ASIC_REV = 0x%X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "PW_CONTRL = 0x%X\n", + cmd.buffer.block_data[2]); + printk(KERN_DEBUG "WAKEUP = 0x%X\n", + cmd.buffer.block_data[3]); + + cmd.start = 0xA0; /* ST_CTRL */ + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "Stream ctrl = 0x%X\n", + cmd.buffer.block_data[0]); + + cmd.start = 0xA4; /* Stream status */ + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "Stream status = 0x%X\n", + cmd.buffer.block_data[0]); + + cmd.start = 0xA8; /* USB status */ + cmd.reg_count = 3; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "USB_CTRL = 0x%X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "USB_STRM = 0x%X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "USB_STATUS = 0x%X\n", + cmd.buffer.block_data[2]); + + cmd.start = 0xAF; /* USB settings */ + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "USB settings = 0x%X\n", + cmd.buffer.block_data[0]); + + cmd.start = 0xC0; /* VC stuff */ + cmd.reg_count = 26; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VC Control = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VC Format = 0x%0X\n", + cmd.buffer.block_data[3]); + printk(KERN_DEBUG "VC Clocks = 0x%0X\n", + cmd.buffer.block_data[4]); + printk(KERN_DEBUG "VC IHSize = 0x%0X\n", + cmd.buffer.block_data[5]); + printk(KERN_DEBUG "VC Xlim Hi = 0x%0X\n", + cmd.buffer.block_data[6]); + printk(KERN_DEBUG "VC XLim Lo = 0x%0X\n", + cmd.buffer.block_data[7]); + printk(KERN_DEBUG "VC YLim Hi = 0x%0X\n", + cmd.buffer.block_data[8]); + printk(KERN_DEBUG "VC YLim Lo = 0x%0X\n", + cmd.buffer.block_data[9]); + printk(KERN_DEBUG "VC OHSize = 0x%0X\n", + cmd.buffer.block_data[10]); + printk(KERN_DEBUG "VC OVSize = 0x%0X\n", + cmd.buffer.block_data[11]); + printk(KERN_DEBUG "VC HCrop = 0x%0X\n", + cmd.buffer.block_data[12]); + printk(KERN_DEBUG "VC VCrop = 0x%0X\n", + cmd.buffer.block_data[13]); + printk(KERN_DEBUG "VC HPhase = 0x%0X\n", + cmd.buffer.block_data[14]); + printk(KERN_DEBUG "VC VPhase = 0x%0X\n", + cmd.buffer.block_data[15]); + printk(KERN_DEBUG "VC HIspan = 0x%0X\n", + cmd.buffer.block_data[16]); + printk(KERN_DEBUG "VC VIspan = 0x%0X\n", + cmd.buffer.block_data[17]); + printk(KERN_DEBUG "VC HiCrop = 0x%0X\n", + cmd.buffer.block_data[18]); + printk(KERN_DEBUG "VC ViCrop = 0x%0X\n", + cmd.buffer.block_data[19]); + printk(KERN_DEBUG "VC HiFract = 0x%0X\n", + cmd.buffer.block_data[20]); + printk(KERN_DEBUG "VC ViFract = 0x%0X\n", + cmd.buffer.block_data[21]); + printk(KERN_DEBUG "VC JPeg Opt = 0x%0X\n", + cmd.buffer.block_data[22]); + printk(KERN_DEBUG "VC Creep Per = 0x%0X\n", + cmd.buffer.block_data[23]); + printk(KERN_DEBUG "VC User Sq. = 0x%0X\n", + cmd.buffer.block_data[24]); + printk(KERN_DEBUG "VC Target KB = 0x%0X\n", + cmd.buffer.block_data[25]); + + /*** VP ***/ + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 14; + cmd.start = 0; + cpia2_send_command(cam, &cmd); + + printk(KERN_DEBUG "VP Dev Hi = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VP Dev Lo = 0x%0X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "VP Sys State = 0x%0X\n", + cmd.buffer.block_data[2]); + printk(KERN_DEBUG "VP Sys Ctrl = 0x%0X\n", + cmd.buffer.block_data[3]); + printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n", + cmd.buffer.block_data[5]); + printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n", + cmd.buffer.block_data[6]); + printk(KERN_DEBUG "VP Dev Config = 0x%0X\n", + cmd.buffer.block_data[7]); + printk(KERN_DEBUG "VP GPIO_DIR = 0x%0X\n", + cmd.buffer.block_data[8]); + printk(KERN_DEBUG "VP GPIO_DATA = 0x%0X\n", + cmd.buffer.block_data[9]); + printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n", + cmd.buffer.block_data[10]); + printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n", + cmd.buffer.block_data[11]); + printk(KERN_DEBUG "VP RAM Data = 0x%0X\n", + cmd.buffer.block_data[12]); + printk(KERN_DEBUG "Do Call = 0x%0X\n", + cmd.buffer.block_data[13]); + + if (cam->params.pnp_id.device_type == DEVICE_STV_672) { + cmd.reg_count = 9; + cmd.start = 0x0E; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n", + cmd.buffer.block_data[2]); + printk(KERN_DEBUG "VP Framerate = 0x%0X\n", + cmd.buffer.block_data[3]); + printk(KERN_DEBUG "VP UserEffect = 0x%0X\n", + cmd.buffer.block_data[4]); + printk(KERN_DEBUG "VP White Bal = 0x%0X\n", + cmd.buffer.block_data[5]); + printk(KERN_DEBUG "VP WB thresh = 0x%0X\n", + cmd.buffer.block_data[6]); + printk(KERN_DEBUG "VP Exp Modes = 0x%0X\n", + cmd.buffer.block_data[7]); + printk(KERN_DEBUG "VP Exp Target = 0x%0X\n", + cmd.buffer.block_data[8]); + + cmd.reg_count = 1; + cmd.start = 0x1B; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n", + cmd.buffer.block_data[0]); + } else { + cmd.reg_count = 8 ; + cmd.start = 0x0E; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n", + cmd.buffer.block_data[5]); + printk(KERN_DEBUG "VP Framerate = 0x%0X\n", + cmd.buffer.block_data[6]); + printk(KERN_DEBUG "VP UserEffect = 0x%0X\n", + cmd.buffer.block_data[7]); + + cmd.reg_count = 1; + cmd.start = CPIA2_VP5_EXPOSURE_TARGET; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n", + cmd.buffer.block_data[0]); + + cmd.reg_count = 4; + cmd.start = 0x3A; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP5 MY Black = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n", + cmd.buffer.block_data[2]); + printk(KERN_DEBUG "VP5 MCUV Sat = 0x%0X\n", + cmd.buffer.block_data[3]); + } +#endif +} + +/****************************************************************************** + * + * reset_camera_struct + * + * Sets all values to the defaults + *****************************************************************************/ +static void reset_camera_struct(struct camera_data *cam) +{ + /*** + * The following parameter values are the defaults from the register map. + ***/ + cam->params.color_params.brightness = DEFAULT_BRIGHTNESS; + cam->params.color_params.contrast = DEFAULT_CONTRAST; + cam->params.color_params.saturation = DEFAULT_SATURATION; + cam->params.vp_params.lowlight_boost = 0; + + /* FlickerModes */ + cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER; + cam->params.flicker_control.mains_frequency = 60; + + /* jpeg params */ + cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT; + cam->params.compression.creep_period = 2; + cam->params.compression.user_squeeze = 20; + cam->params.compression.inhibit_htables = false; + + /* gpio params */ + cam->params.vp_params.gpio_direction = 0; /* write, the default safe mode */ + cam->params.vp_params.gpio_data = 0; + + /* Target kb params */ + cam->params.vc_params.target_kb = DEFAULT_TARGET_KB; + + /*** + * Set Sensor FPS as fast as possible. + ***/ + if(cam->params.pnp_id.device_type == DEVICE_STV_672) { + if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) + cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15; + else + cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30; + } else { + cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30; + } + + /*** + * Set default video mode as large as possible : + * for vga sensor set to vga, for cif sensor set to CIF. + ***/ + if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) { + cam->sensor_type = CPIA2_SENSOR_500; + cam->video_size = VIDEOSIZE_VGA; + cam->params.roi.width = STV_IMAGE_VGA_COLS; + cam->params.roi.height = STV_IMAGE_VGA_ROWS; + } else { + cam->sensor_type = CPIA2_SENSOR_410; + cam->video_size = VIDEOSIZE_CIF; + cam->params.roi.width = STV_IMAGE_CIF_COLS; + cam->params.roi.height = STV_IMAGE_CIF_ROWS; + } + + cam->width = cam->params.roi.width; + cam->height = cam->params.roi.height; +} + +/****************************************************************************** + * + * cpia2_init_camera_struct + * + * Initializes camera struct, does not call reset to fill in defaults. + *****************************************************************************/ +struct camera_data *cpia2_init_camera_struct(void) +{ + struct camera_data *cam; + + cam = kzalloc(sizeof(*cam), GFP_KERNEL); + + if (!cam) { + ERR("couldn't kmalloc cpia2 struct\n"); + return NULL; + } + + + cam->present = 1; + mutex_init(&cam->v4l2_lock); + init_waitqueue_head(&cam->wq_stream); + + return cam; +} + +/****************************************************************************** + * + * cpia2_init_camera + * + * Initializes camera. + *****************************************************************************/ +int cpia2_init_camera(struct camera_data *cam) +{ + DBG("Start\n"); + + cam->mmapped = false; + + /* Get sensor and asic types before reset. */ + cpia2_set_high_power(cam); + cpia2_get_version_info(cam); + if (cam->params.version.asic_id != CPIA2_ASIC_672) { + ERR("Device IO error (asicID has incorrect value of 0x%X\n", + cam->params.version.asic_id); + return -ENODEV; + } + + /* Set GPIO direction and data to a safe state. */ + cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, + TRANSFER_WRITE, 0); + cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, + TRANSFER_WRITE, 0); + + /* resetting struct requires version info for sensor and asic types */ + reset_camera_struct(cam); + + cpia2_set_low_power(cam); + + DBG("End\n"); + + return 0; +} + +/****************************************************************************** + * + * cpia2_allocate_buffers + * + *****************************************************************************/ +int cpia2_allocate_buffers(struct camera_data *cam) +{ + int i; + + if(!cam->buffers) { + u32 size = cam->num_frames*sizeof(struct framebuf); + cam->buffers = kmalloc(size, GFP_KERNEL); + if(!cam->buffers) { + ERR("couldn't kmalloc frame buffer structures\n"); + return -ENOMEM; + } + } + + if(!cam->frame_buffer) { + cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames); + if (!cam->frame_buffer) { + ERR("couldn't vmalloc frame buffer data area\n"); + kfree(cam->buffers); + cam->buffers = NULL; + return -ENOMEM; + } + } + + for(i=0; inum_frames-1; ++i) { + cam->buffers[i].next = &cam->buffers[i+1]; + cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size; + cam->buffers[i].status = FRAME_EMPTY; + cam->buffers[i].length = 0; + cam->buffers[i].max_length = 0; + cam->buffers[i].num = i; + } + cam->buffers[i].next = cam->buffers; + cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size; + cam->buffers[i].status = FRAME_EMPTY; + cam->buffers[i].length = 0; + cam->buffers[i].max_length = 0; + cam->buffers[i].num = i; + cam->curbuff = cam->buffers; + cam->workbuff = cam->curbuff->next; + DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff, + cam->workbuff); + return 0; +} + +/****************************************************************************** + * + * cpia2_free_buffers + * + *****************************************************************************/ +void cpia2_free_buffers(struct camera_data *cam) +{ + if(cam->buffers) { + kfree(cam->buffers); + cam->buffers = NULL; + } + if(cam->frame_buffer) { + rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames); + cam->frame_buffer = NULL; + } +} + +/****************************************************************************** + * + * cpia2_read + * + *****************************************************************************/ +long cpia2_read(struct camera_data *cam, + char __user *buf, unsigned long count, int noblock) +{ + struct framebuf *frame; + + if (!count) + return 0; + + if (!buf) { + ERR("%s: buffer NULL\n",__func__); + return -EINVAL; + } + + if (!cam) { + ERR("%s: Internal error, camera_data NULL!\n",__func__); + return -EINVAL; + } + + if (!cam->present) { + LOG("%s: camera removed\n",__func__); + return 0; /* EOF */ + } + + if (!cam->streaming) { + /* Start streaming */ + cpia2_usb_stream_start(cam, + cam->params.camera_state.stream_mode); + } + + /* Copy cam->curbuff in case it changes while we're processing */ + frame = cam->curbuff; + if (noblock && frame->status != FRAME_READY) { + return -EAGAIN; + } + + if (frame->status != FRAME_READY) { + mutex_unlock(&cam->v4l2_lock); + wait_event_interruptible(cam->wq_stream, + !cam->present || + (frame = cam->curbuff)->status == FRAME_READY); + mutex_lock(&cam->v4l2_lock); + if (signal_pending(current)) + return -ERESTARTSYS; + if (!cam->present) + return 0; + } + + /* copy data to user space */ + if (frame->length > count) + return -EFAULT; + if (copy_to_user(buf, frame->data, frame->length)) + return -EFAULT; + + count = frame->length; + + frame->status = FRAME_EMPTY; + + return count; +} + +/****************************************************************************** + * + * cpia2_poll + * + *****************************************************************************/ +unsigned int cpia2_poll(struct camera_data *cam, struct file *filp, + poll_table *wait) +{ + unsigned int status=0; + + if (!cam) { + ERR("%s: Internal error, camera_data not found!\n",__func__); + return POLLERR; + } + + if (!cam->present) + return POLLHUP; + + if(!cam->streaming) { + /* Start streaming */ + cpia2_usb_stream_start(cam, + cam->params.camera_state.stream_mode); + } + + poll_wait(filp, &cam->wq_stream, wait); + + if(!cam->present) + status = POLLHUP; + else if(cam->curbuff->status == FRAME_READY) + status = POLLIN | POLLRDNORM; + + return status; +} + +/****************************************************************************** + * + * cpia2_remap_buffer + * + *****************************************************************************/ +int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma) +{ + const char *adr = (const char *)vma->vm_start; + unsigned long size = vma->vm_end-vma->vm_start; + unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long start = (unsigned long) adr; + unsigned long page, pos; + + if (!cam) + return -ENODEV; + + DBG("mmap offset:%ld size:%ld\n", start_offset, size); + + if (!cam->present) + return -ENODEV; + + if (size > cam->frame_size*cam->num_frames || + (start_offset % cam->frame_size) != 0 || + (start_offset+size > cam->frame_size*cam->num_frames)) + return -EINVAL; + + pos = ((unsigned long) (cam->frame_buffer)) + start_offset; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + cam->mmapped = true; + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2dev.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2dev.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2dev.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2dev.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,50 @@ +/**************************************************************************** + * + * Filename: cpia2dev.h + * + * Copyright 2001, STMicrolectronics, Inc. + * + * Contact: steve.miller@st.com + * + * Description: + * This file provides definitions for applications wanting to use the + * cpia2 driver beyond the generic v4l capabilities. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************************/ + +#ifndef CPIA2_DEV_HEADER +#define CPIA2_DEV_HEADER + +#include + +/*** + * The following defines are ioctl numbers based on video4linux private ioctls, + * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int + * args + */ +#define CPIA2_IOC_SET_GPIO _IOW('v', BASE_VIDIOC_PRIVATE + 17, __u32) + +/* V4L2 driver specific controls */ +#define CPIA2_CID_TARGET_KB (V4L2_CID_PRIVATE_BASE+0) +#define CPIA2_CID_GPIO (V4L2_CID_PRIVATE_BASE+1) +#define CPIA2_CID_FLICKER_MODE (V4L2_CID_PRIVATE_BASE+2) +#define CPIA2_CID_FRAMERATE (V4L2_CID_PRIVATE_BASE+3) +#define CPIA2_CID_USB_ALT (V4L2_CID_PRIVATE_BASE+4) +#define CPIA2_CID_LIGHTS (V4L2_CID_PRIVATE_BASE+5) +#define CPIA2_CID_RESET_CAMERA (V4L2_CID_PRIVATE_BASE+6) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,494 @@ +/**************************************************************************** + * + * Filename: cpia2.h + * + * Copyright 2001, STMicrolectronics, Inc. + * + * Contact: steve.miller@st.com + * + * Description: + * This is a USB driver for CPiA2 based video cameras. + * + * This driver is modelled on the cpia usb driver by + * Jochen Scharrlach and Johannes Erdfeldt. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************************/ + +#ifndef __CPIA2_H__ +#define __CPIA2_H__ + +#include +#include +#include +#include +#include + +#include "cpia2dev.h" +#include "cpia2_registers.h" + +/* define for verbose debug output */ +//#define _CPIA2_DEBUG_ + +#define CPIA2_MAJ_VER 3 +#define CPIA2_MIN_VER 0 +#define CPIA2_PATCH_VER 0 + +/*** + * Image defines + ***/ + +/* Misc constants */ +#define ALLOW_CORRUPT 0 /* Causes collater to discard checksum */ + +/* USB Transfer mode */ +#define XFER_ISOC 0 +#define XFER_BULK 1 + +/* USB Alternates */ +#define USBIF_CMDONLY 0 +#define USBIF_BULK 1 +#define USBIF_ISO_1 2 /* 128 bytes/ms */ +#define USBIF_ISO_2 3 /* 384 bytes/ms */ +#define USBIF_ISO_3 4 /* 640 bytes/ms */ +#define USBIF_ISO_4 5 /* 768 bytes/ms */ +#define USBIF_ISO_5 6 /* 896 bytes/ms */ +#define USBIF_ISO_6 7 /* 1023 bytes/ms */ + +/* Flicker Modes */ +#define NEVER_FLICKER 0 +#define ANTI_FLICKER_ON 1 +#define FLICKER_60 60 +#define FLICKER_50 50 + +/* Debug flags */ +#define DEBUG_NONE 0 +#define DEBUG_REG 0x00000001 +#define DEBUG_DUMP_PATCH 0x00000002 +#define DEBUG_DUMP_REGS 0x00000004 + +/*** + * Video frame sizes + ***/ +enum { + VIDEOSIZE_VGA = 0, /* 640x480 */ + VIDEOSIZE_CIF, /* 352x288 */ + VIDEOSIZE_QVGA, /* 320x240 */ + VIDEOSIZE_QCIF, /* 176x144 */ + VIDEOSIZE_288_216, + VIDEOSIZE_256_192, + VIDEOSIZE_224_168, + VIDEOSIZE_192_144, +}; + +#define STV_IMAGE_CIF_ROWS 288 +#define STV_IMAGE_CIF_COLS 352 + +#define STV_IMAGE_QCIF_ROWS 144 +#define STV_IMAGE_QCIF_COLS 176 + +#define STV_IMAGE_VGA_ROWS 480 +#define STV_IMAGE_VGA_COLS 640 + +#define STV_IMAGE_QVGA_ROWS 240 +#define STV_IMAGE_QVGA_COLS 320 + +#define JPEG_MARKER_COM (1<<6) /* Comment segment */ + +/*** + * Enums + ***/ +/* Sensor types available with cpia2 asics */ +enum sensors { + CPIA2_SENSOR_410, + CPIA2_SENSOR_500 +}; + +/* Asic types available in the CPiA2 architecture */ +#define CPIA2_ASIC_672 0x67 + +/* Device types (stv672, stv676, etc) */ +#define DEVICE_STV_672 0x0001 +#define DEVICE_STV_676 0x0002 + +enum frame_status { + FRAME_EMPTY, + FRAME_READING, /* In the process of being grabbed into */ + FRAME_READY, /* Ready to be read */ + FRAME_ERROR, +}; + +/*** + * Register access (for USB request byte) + ***/ +enum { + CAMERAACCESS_SYSTEM = 0, + CAMERAACCESS_VC, + CAMERAACCESS_VP, + CAMERAACCESS_IDATA +}; + +#define CAMERAACCESS_TYPE_BLOCK 0x00 +#define CAMERAACCESS_TYPE_RANDOM 0x04 +#define CAMERAACCESS_TYPE_MASK 0x08 +#define CAMERAACCESS_TYPE_REPEAT 0x0C + +#define TRANSFER_READ 0 +#define TRANSFER_WRITE 1 + +#define DEFAULT_ALT USBIF_ISO_6 +#define DEFAULT_BRIGHTNESS 0x46 +#define DEFAULT_CONTRAST 0x93 +#define DEFAULT_SATURATION 0x7f +#define DEFAULT_TARGET_KB 0x30 + +/* Power state */ +#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER +#define LO_POWER_MODE CPIA2_SYSTEM_CONTROL_LOW_POWER + + +/******** + * Commands + *******/ +enum { + CPIA2_CMD_NONE = 0, + CPIA2_CMD_GET_VERSION, + CPIA2_CMD_GET_PNP_ID, + CPIA2_CMD_GET_ASIC_TYPE, + CPIA2_CMD_GET_SENSOR, + CPIA2_CMD_GET_VP_DEVICE, + CPIA2_CMD_GET_VP_BRIGHTNESS, + CPIA2_CMD_SET_VP_BRIGHTNESS, + CPIA2_CMD_GET_CONTRAST, + CPIA2_CMD_SET_CONTRAST, + CPIA2_CMD_GET_VP_SATURATION, + CPIA2_CMD_SET_VP_SATURATION, + CPIA2_CMD_GET_VP_GPIO_DIRECTION, + CPIA2_CMD_SET_VP_GPIO_DIRECTION, + CPIA2_CMD_GET_VP_GPIO_DATA, + CPIA2_CMD_SET_VP_GPIO_DATA, + CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, + CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, + CPIA2_CMD_GET_VC_MP_GPIO_DATA, + CPIA2_CMD_SET_VC_MP_GPIO_DATA, + CPIA2_CMD_ENABLE_PACKET_CTRL, + CPIA2_CMD_GET_FLICKER_MODES, + CPIA2_CMD_SET_FLICKER_MODES, + CPIA2_CMD_RESET_FIFO, /* clear fifo and enable stream block */ + CPIA2_CMD_SET_HI_POWER, + CPIA2_CMD_SET_LOW_POWER, + CPIA2_CMD_CLEAR_V2W_ERR, + CPIA2_CMD_SET_USER_MODE, + CPIA2_CMD_GET_USER_MODE, + CPIA2_CMD_FRAMERATE_REQ, + CPIA2_CMD_SET_COMPRESSION_STATE, + CPIA2_CMD_GET_WAKEUP, + CPIA2_CMD_SET_WAKEUP, + CPIA2_CMD_GET_PW_CONTROL, + CPIA2_CMD_SET_PW_CONTROL, + CPIA2_CMD_GET_SYSTEM_CTRL, + CPIA2_CMD_SET_SYSTEM_CTRL, + CPIA2_CMD_GET_VP_SYSTEM_STATE, + CPIA2_CMD_GET_VP_SYSTEM_CTRL, + CPIA2_CMD_SET_VP_SYSTEM_CTRL, + CPIA2_CMD_GET_VP_EXP_MODES, + CPIA2_CMD_SET_VP_EXP_MODES, + CPIA2_CMD_GET_DEVICE_CONFIG, + CPIA2_CMD_SET_DEVICE_CONFIG, + CPIA2_CMD_SET_SERIAL_ADDR, + CPIA2_CMD_SET_SENSOR_CR1, + CPIA2_CMD_GET_VC_CONTROL, + CPIA2_CMD_SET_VC_CONTROL, + CPIA2_CMD_SET_TARGET_KB, + CPIA2_CMD_SET_DEF_JPEG_OPT, + CPIA2_CMD_REHASH_VP4, + CPIA2_CMD_GET_USER_EFFECTS, + CPIA2_CMD_SET_USER_EFFECTS +}; + +enum user_cmd { + COMMAND_NONE = 0x00000001, + COMMAND_SET_FPS = 0x00000002, + COMMAND_SET_COLOR_PARAMS = 0x00000004, + COMMAND_GET_COLOR_PARAMS = 0x00000008, + COMMAND_SET_FORMAT = 0x00000010, /* size, etc */ + COMMAND_SET_FLICKER = 0x00000020 +}; + +/*** + * Some defines specific to the 676 chip + ***/ +#define CAMACC_CIF 0x01 +#define CAMACC_VGA 0x02 +#define CAMACC_QCIF 0x04 +#define CAMACC_QVGA 0x08 + + +struct cpia2_register { + u8 index; + u8 value; +}; + +struct cpia2_reg_mask { + u8 index; + u8 and_mask; + u8 or_mask; + u8 fill; +}; + +struct cpia2_command { + u32 command; + u8 req_mode; /* (Block or random) | registerBank */ + u8 reg_count; + u8 direction; + u8 start; + union reg_types { + struct cpia2_register registers[32]; + struct cpia2_reg_mask masks[16]; + u8 block_data[64]; + u8 *patch_data; /* points to function defined block */ + } buffer; +}; + +struct camera_params { + struct { + u8 firmware_revision_hi; /* For system register set (bank 0) */ + u8 firmware_revision_lo; + u8 asic_id; /* Video Compressor set (bank 1) */ + u8 asic_rev; + u8 vp_device_hi; /* Video Processor set (bank 2) */ + u8 vp_device_lo; + u8 sensor_flags; + u8 sensor_rev; + } version; + + struct { + u32 device_type; /* enumerated from vendor/product ids. + * Currently, either STV_672 or STV_676 */ + u16 vendor; + u16 product; + u16 device_revision; + } pnp_id; + + struct { + u8 brightness; /* CPIA2_VP_EXPOSURE_TARGET */ + u8 contrast; /* Note: this is CPIA2_VP_YRANGE */ + u8 saturation; /* CPIA2_VP_SATURATION */ + } color_params; + + struct { + u8 cam_register; + u8 flicker_mode_req; /* 1 if flicker on, else never flicker */ + int mains_frequency; + } flicker_control; + + struct { + u8 jpeg_options; + u8 creep_period; + u8 user_squeeze; + u8 inhibit_htables; + } compression; + + struct { + u8 ohsize; /* output image size */ + u8 ovsize; + u8 hcrop; /* cropping start_pos/4 */ + u8 vcrop; + u8 hphase; /* scaling registers */ + u8 vphase; + u8 hispan; + u8 vispan; + u8 hicrop; + u8 vicrop; + u8 hifraction; + u8 vifraction; + } image_size; + + struct { + int width; /* actual window width */ + int height; /* actual window height */ + } roi; + + struct { + u8 video_mode; + u8 frame_rate; + u8 video_size; /* Not a register, just a convenience for cropped sizes */ + u8 gpio_direction; + u8 gpio_data; + u8 system_ctrl; + u8 system_state; + u8 lowlight_boost; /* Bool: 0 = off, 1 = on */ + u8 device_config; + u8 exposure_modes; + u8 user_effects; + } vp_params; + + struct { + u8 pw_control; + u8 wakeup; + u8 vc_control; + u8 vc_mp_direction; + u8 vc_mp_data; + u8 target_kb; + } vc_params; + + struct { + u8 power_mode; + u8 system_ctrl; + u8 stream_mode; /* This is the current alternate for usb drivers */ + u8 allow_corrupt; + } camera_state; +}; + +#define NUM_SBUF 2 + +struct cpia2_sbuf { + char *data; + struct urb *urb; +}; + +struct framebuf { + struct timeval timestamp; + unsigned long seq; + int num; + int length; + int max_length; + volatile enum frame_status status; + u8 *data; + struct framebuf *next; +}; + +struct cpia2_fh { + enum v4l2_priority prio; + u8 mmapped; +}; + +struct camera_data { + /* locks */ + struct mutex v4l2_lock; /* serialize file operations */ + struct v4l2_prio_state prio; + + /* camera status */ + volatile int present; /* Is the camera still present? */ + int open_count; /* # of process that have camera open */ + int first_image_seen; + u8 mains_freq; /* for flicker control */ + enum sensors sensor_type; + u8 flush; + u8 mmapped; + int streaming; /* 0 = no, 1 = yes */ + int xfer_mode; /* XFER_BULK or XFER_ISOC */ + struct camera_params params; /* camera settings */ + + /* v4l */ + int video_size; /* VIDEO_SIZE_ */ + struct video_device *vdev; /* v4l videodev */ + u32 width; + u32 height; /* Its size */ + __u32 pixelformat; /* Format fourcc */ + + /* USB */ + struct usb_device *dev; + unsigned char iface; + unsigned int cur_alt; + unsigned int old_alt; + struct cpia2_sbuf sbuf[NUM_SBUF]; /* Double buffering */ + + wait_queue_head_t wq_stream; + + /* Buffering */ + u32 frame_size; + int num_frames; + unsigned long frame_count; + u8 *frame_buffer; /* frame buffer data */ + struct framebuf *buffers; + struct framebuf * volatile curbuff; + struct framebuf *workbuff; + + /* MJPEG Extension */ + int APPn; /* Number of APP segment to be written, must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ +}; + +/* v4l */ +int cpia2_register_camera(struct camera_data *cam); +void cpia2_unregister_camera(struct camera_data *cam); + +/* core */ +int cpia2_reset_camera(struct camera_data *cam); +int cpia2_set_low_power(struct camera_data *cam); +void cpia2_dbg_dump_registers(struct camera_data *cam); +int cpia2_match_video_size(int width, int height); +void cpia2_set_camera_state(struct camera_data *cam); +void cpia2_save_camera_state(struct camera_data *cam); +void cpia2_set_color_params(struct camera_data *cam); +void cpia2_set_brightness(struct camera_data *cam, unsigned char value); +void cpia2_set_contrast(struct camera_data *cam, unsigned char value); +void cpia2_set_saturation(struct camera_data *cam, unsigned char value); +int cpia2_set_flicker_mode(struct camera_data *cam, int mode); +void cpia2_set_format(struct camera_data *cam); +int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd); +int cpia2_do_command(struct camera_data *cam, + unsigned int command, + unsigned char direction, unsigned char param); +struct camera_data *cpia2_init_camera_struct(void); +int cpia2_init_camera(struct camera_data *cam); +int cpia2_allocate_buffers(struct camera_data *cam); +void cpia2_free_buffers(struct camera_data *cam); +long cpia2_read(struct camera_data *cam, + char __user *buf, unsigned long count, int noblock); +unsigned int cpia2_poll(struct camera_data *cam, + struct file *filp, poll_table *wait); +int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma); +void cpia2_set_property_flip(struct camera_data *cam, int prop_val); +void cpia2_set_property_mirror(struct camera_data *cam, int prop_val); +int cpia2_set_target_kb(struct camera_data *cam, unsigned char value); +int cpia2_set_gpio(struct camera_data *cam, unsigned char setting); +int cpia2_set_fps(struct camera_data *cam, int framerate); + +/* usb */ +int cpia2_usb_init(void); +void cpia2_usb_cleanup(void); +int cpia2_usb_transfer_cmd(struct camera_data *cam, void *registers, + u8 request, u8 start, u8 count, u8 direction); +int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate); +int cpia2_usb_stream_stop(struct camera_data *cam); +int cpia2_usb_stream_pause(struct camera_data *cam); +int cpia2_usb_stream_resume(struct camera_data *cam); +int cpia2_usb_change_streaming_alternate(struct camera_data *cam, + unsigned int alt); + + +/* ----------------------- debug functions ---------------------- */ +#ifdef _CPIA2_DEBUG_ +#define ALOG(lev, fmt, args...) printk(lev "%s:%d %s(): " fmt, __FILE__, __LINE__, __func__, ## args) +#define LOG(fmt, args...) ALOG(KERN_INFO, fmt, ## args) +#define ERR(fmt, args...) ALOG(KERN_ERR, fmt, ## args) +#define DBG(fmt, args...) ALOG(KERN_DEBUG, fmt, ## args) +#else +#define ALOG(fmt,args...) printk(fmt,##args) +#define LOG(fmt,args...) ALOG(KERN_INFO "cpia2: "fmt,##args) +#define ERR(fmt,args...) ALOG(KERN_ERR "cpia2: "fmt,##args) +#define DBG(fmn,args...) do {} while(0) +#endif +/* No function or lineno, for shorter lines */ +#define KINFO(fmt, args...) printk(KERN_INFO fmt,##args) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_registers.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_registers.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_registers.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_registers.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,476 @@ +/**************************************************************************** + * + * Filename: cpia2registers.h + * + * Copyright 2001, STMicrolectronics, Inc. + * + * Description: + * Definitions for the CPia2 register set + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************************/ + +#ifndef CPIA2_REGISTER_HEADER +#define CPIA2_REGISTER_HEADER + +/*** + * System register set (Bank 0) + ***/ +#define CPIA2_SYSTEM_DEVICE_HI 0x00 +#define CPIA2_SYSTEM_DEVICE_LO 0x01 + +#define CPIA2_SYSTEM_SYSTEM_CONTROL 0x02 +#define CPIA2_SYSTEM_CONTROL_LOW_POWER 0x00 +#define CPIA2_SYSTEM_CONTROL_HIGH_POWER 0x01 +#define CPIA2_SYSTEM_CONTROL_SUSPEND 0x02 +#define CPIA2_SYSTEM_CONTROL_V2W_ERR 0x10 +#define CPIA2_SYSTEM_CONTROL_RB_ERR 0x10 +#define CPIA2_SYSTEM_CONTROL_CLEAR_ERR 0x80 + +#define CPIA2_SYSTEM_INT_PACKET_CTRL 0x04 +#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX 0x01 +#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_EOF 0x02 +#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_INT1 0x04 + +#define CPIA2_SYSTEM_CACHE_CTRL 0x05 +#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_RESET 0x01 +#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_FLUSH 0x02 + +#define CPIA2_SYSTEM_SERIAL_CTRL 0x06 +#define CPIA2_SYSTEM_SERIAL_CTRL_NULL_CMD 0x00 +#define CPIA2_SYSTEM_SERIAL_CTRL_START_CMD 0x01 +#define CPIA2_SYSTEM_SERIAL_CTRL_STOP_CMD 0x02 +#define CPIA2_SYSTEM_SERIAL_CTRL_WRITE_CMD 0x03 +#define CPIA2_SYSTEM_SERIAL_CTRL_READ_ACK_CMD 0x04 +#define CPIA2_SYSTEM_SERIAL_CTRL_READ_NACK_CMD 0x05 + +#define CPIA2_SYSTEM_SERIAL_DATA 0x07 + +#define CPIA2_SYSTEM_VP_SERIAL_ADDR 0x08 + +/*** + * I2C addresses for various devices in CPiA2 + ***/ +#define CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR 0x20 +#define CPIA2_SYSTEM_VP_SERIAL_ADDR_VP 0x88 +#define CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP 0x8A + +#define CPIA2_SYSTEM_SPARE_REG1 0x09 +#define CPIA2_SYSTEM_SPARE_REG2 0x0A +#define CPIA2_SYSTEM_SPARE_REG3 0x0B + +#define CPIA2_SYSTEM_MC_PORT_0 0x0C +#define CPIA2_SYSTEM_MC_PORT_1 0x0D +#define CPIA2_SYSTEM_MC_PORT_2 0x0E +#define CPIA2_SYSTEM_MC_PORT_3 0x0F + +#define CPIA2_SYSTEM_STATUS_PKT 0x20 +#define CPIA2_SYSTEM_STATUS_PKT_END 0x27 + +#define CPIA2_SYSTEM_DESCRIP_VID_HI 0x30 +#define CPIA2_SYSTEM_DESCRIP_VID_LO 0x31 +#define CPIA2_SYSTEM_DESCRIP_PID_HI 0x32 +#define CPIA2_SYSTEM_DESCRIP_PID_LO 0x33 + +#define CPIA2_SYSTEM_FW_VERSION_HI 0x34 +#define CPIA2_SYSTEM_FW_VERSION_LO 0x35 + +#define CPIA2_SYSTEM_CACHE_START_INDEX 0x80 +#define CPIA2_SYSTEM_CACHE_MAX_WRITES 0x10 + +/*** + * VC register set (Bank 1) + ***/ +#define CPIA2_VC_ASIC_ID 0x80 + +#define CPIA2_VC_ASIC_REV 0x81 + +#define CPIA2_VC_PW_CTRL 0x82 +#define CPIA2_VC_PW_CTRL_COLDSTART 0x01 +#define CPIA2_VC_PW_CTRL_CP_CLK_EN 0x02 +#define CPIA2_VC_PW_CTRL_VP_RESET_N 0x04 +#define CPIA2_VC_PW_CTRL_VC_CLK_EN 0x08 +#define CPIA2_VC_PW_CTRL_VC_RESET_N 0x10 +#define CPIA2_VC_PW_CTRL_GOTO_SUSPEND 0x20 +#define CPIA2_VC_PW_CTRL_UDC_SUSPEND 0x40 +#define CPIA2_VC_PW_CTRL_PWR_DOWN 0x80 + +#define CPIA2_VC_WAKEUP 0x83 +#define CPIA2_VC_WAKEUP_SW_ENABLE 0x01 +#define CPIA2_VC_WAKEUP_XX_ENABLE 0x02 +#define CPIA2_VC_WAKEUP_SW_ATWAKEUP 0x04 +#define CPIA2_VC_WAKEUP_XX_ATWAKEUP 0x08 + +#define CPIA2_VC_CLOCK_CTRL 0x84 +#define CPIA2_VC_CLOCK_CTRL_TESTUP72 0x01 + +#define CPIA2_VC_INT_ENABLE 0x88 +#define CPIA2_VC_INT_ENABLE_XX_IE 0x01 +#define CPIA2_VC_INT_ENABLE_SW_IE 0x02 +#define CPIA2_VC_INT_ENABLE_VC_IE 0x04 +#define CPIA2_VC_INT_ENABLE_USBDATA_IE 0x08 +#define CPIA2_VC_INT_ENABLE_USBSETUP_IE 0x10 +#define CPIA2_VC_INT_ENABLE_USBCFG_IE 0x20 + +#define CPIA2_VC_INT_FLAG 0x89 +#define CPIA2_VC_INT_ENABLE_XX_FLAG 0x01 +#define CPIA2_VC_INT_ENABLE_SW_FLAG 0x02 +#define CPIA2_VC_INT_ENABLE_VC_FLAG 0x04 +#define CPIA2_VC_INT_ENABLE_USBDATA_FLAG 0x08 +#define CPIA2_VC_INT_ENABLE_USBSETUP_FLAG 0x10 +#define CPIA2_VC_INT_ENABLE_USBCFG_FLAG 0x20 +#define CPIA2_VC_INT_ENABLE_SET_RESET_BIT 0x80 + +#define CPIA2_VC_INT_STATE 0x8A +#define CPIA2_VC_INT_STATE_XX_STATE 0x01 +#define CPIA2_VC_INT_STATE_SW_STATE 0x02 + +#define CPIA2_VC_MP_DIR 0x90 +#define CPIA2_VC_MP_DIR_INPUT 0x00 +#define CPIA2_VC_MP_DIR_OUTPUT 0x01 + +#define CPIA2_VC_MP_DATA 0x91 + +#define CPIA2_VC_DP_CTRL 0x98 +#define CPIA2_VC_DP_CTRL_MODE_0 0x00 +#define CPIA2_VC_DP_CTRL_MODE_A 0x01 +#define CPIA2_VC_DP_CTRL_MODE_B 0x02 +#define CPIA2_VC_DP_CTRL_MODE_C 0x03 +#define CPIA2_VC_DP_CTRL_FAKE_FST 0x04 + +#define CPIA2_VC_AD_CTRL 0x99 +#define CPIA2_VC_AD_CTRL_SRC_0 0x00 +#define CPIA2_VC_AD_CTRL_SRC_DIGI_A 0x01 +#define CPIA2_VC_AD_CTRL_SRC_REG 0x02 +#define CPIA2_VC_AD_CTRL_DST_USB 0x00 +#define CPIA2_VC_AD_CTRL_DST_REG 0x04 + +#define CPIA2_VC_AD_TEST_IN 0x9B + +#define CPIA2_VC_AD_TEST_OUT 0x9C + +#define CPIA2_VC_AD_STATUS 0x9D +#define CPIA2_VC_AD_STATUS_EMPTY 0x01 +#define CPIA2_VC_AD_STATUS_FULL 0x02 + +#define CPIA2_VC_DP_DATA 0x9E + +#define CPIA2_VC_ST_CTRL 0xA0 +#define CPIA2_VC_ST_CTRL_SRC_VC 0x00 +#define CPIA2_VC_ST_CTRL_SRC_DP 0x01 +#define CPIA2_VC_ST_CTRL_SRC_REG 0x02 + +#define CPIA2_VC_ST_CTRL_RAW_SELECT 0x04 + +#define CPIA2_VC_ST_CTRL_DST_USB 0x00 +#define CPIA2_VC_ST_CTRL_DST_DP 0x08 +#define CPIA2_VC_ST_CTRL_DST_REG 0x10 + +#define CPIA2_VC_ST_CTRL_FIFO_ENABLE 0x20 +#define CPIA2_VC_ST_CTRL_EOF_DETECT 0x40 + +#define CPIA2_VC_ST_TEST 0xA1 +#define CPIA2_VC_ST_TEST_MODE_MANUAL 0x00 +#define CPIA2_VC_ST_TEST_MODE_INCREMENT 0x02 + +#define CPIA2_VC_ST_TEST_AUTO_FILL 0x08 + +#define CPIA2_VC_ST_TEST_REPEAT_FIFO 0x10 + +#define CPIA2_VC_ST_TEST_IN 0xA2 + +#define CPIA2_VC_ST_TEST_OUT 0xA3 + +#define CPIA2_VC_ST_STATUS 0xA4 +#define CPIA2_VC_ST_STATUS_EMPTY 0x01 +#define CPIA2_VC_ST_STATUS_FULL 0x02 + +#define CPIA2_VC_ST_FRAME_DETECT_1 0xA5 + +#define CPIA2_VC_ST_FRAME_DETECT_2 0xA6 + +#define CPIA2_VC_USB_CTRL 0xA8 +#define CPIA2_VC_USB_CTRL_CMD_STALLED 0x01 +#define CPIA2_VC_USB_CTRL_CMD_READY 0x02 +#define CPIA2_VC_USB_CTRL_CMD_STATUS 0x04 +#define CPIA2_VC_USB_CTRL_CMD_STATUS_DIR 0x08 +#define CPIA2_VC_USB_CTRL_CMD_NO_CLASH 0x10 +#define CPIA2_VC_USB_CTRL_CMD_MICRO_ACCESS 0x80 + +#define CPIA2_VC_USB_STRM 0xA9 +#define CPIA2_VC_USB_STRM_ISO_ENABLE 0x01 +#define CPIA2_VC_USB_STRM_BLK_ENABLE 0x02 +#define CPIA2_VC_USB_STRM_INT_ENABLE 0x04 +#define CPIA2_VC_USB_STRM_AUD_ENABLE 0x08 + +#define CPIA2_VC_USB_STATUS 0xAA +#define CPIA2_VC_USB_STATUS_CMD_IN_PROGRESS 0x01 +#define CPIA2_VC_USB_STATUS_CMD_STATUS_STALL 0x02 +#define CPIA2_VC_USB_STATUS_CMD_HANDSHAKE 0x04 +#define CPIA2_VC_USB_STATUS_CMD_OVERRIDE 0x08 +#define CPIA2_VC_USB_STATUS_CMD_FIFO_BUSY 0x10 +#define CPIA2_VC_USB_STATUS_BULK_REPEAT_TXN 0x20 +#define CPIA2_VC_USB_STATUS_CONFIG_DONE 0x40 +#define CPIA2_VC_USB_STATUS_USB_SUSPEND 0x80 + +#define CPIA2_VC_USB_CMDW 0xAB + +#define CPIA2_VC_USB_DATARW 0xAC + +#define CPIA2_VC_USB_INFO 0xAD + +#define CPIA2_VC_USB_CONFIG 0xAE + +#define CPIA2_VC_USB_SETTINGS 0xAF +#define CPIA2_VC_USB_SETTINGS_CONFIG_MASK 0x03 +#define CPIA2_VC_USB_SETTINGS_INTERFACE_MASK 0x0C +#define CPIA2_VC_USB_SETTINGS_ALTERNATE_MASK 0x70 + +#define CPIA2_VC_USB_ISOLIM 0xB0 + +#define CPIA2_VC_USB_ISOFAILS 0xB1 + +#define CPIA2_VC_USB_ISOMAXPKTHI 0xB2 + +#define CPIA2_VC_USB_ISOMAXPKTLO 0xB3 + +#define CPIA2_VC_V2W_CTRL 0xB8 +#define CPIA2_VC_V2W_SELECT 0x01 + +#define CPIA2_VC_V2W_SCL 0xB9 + +#define CPIA2_VC_V2W_SDA 0xBA + +#define CPIA2_VC_VC_CTRL 0xC0 +#define CPIA2_VC_VC_CTRL_RUN 0x01 +#define CPIA2_VC_VC_CTRL_SINGLESHOT 0x02 +#define CPIA2_VC_VC_CTRL_IDLING 0x04 +#define CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES 0x10 +#define CPIA2_VC_VC_CTRL_INHIBIT_Q_TABLES 0x20 +#define CPIA2_VC_VC_CTRL_INHIBIT_PRIVATE 0x40 + +#define CPIA2_VC_VC_RESTART_IVAL_HI 0xC1 + +#define CPIA2_VC_VC_RESTART_IVAL_LO 0xC2 + +#define CPIA2_VC_VC_FORMAT 0xC3 +#define CPIA2_VC_VC_FORMAT_UFIRST 0x01 +#define CPIA2_VC_VC_FORMAT_MONO 0x02 +#define CPIA2_VC_VC_FORMAT_DECIMATING 0x04 +#define CPIA2_VC_VC_FORMAT_SHORTLINE 0x08 +#define CPIA2_VC_VC_FORMAT_SELFTEST 0x10 + +#define CPIA2_VC_VC_CLOCKS 0xC4 +#define CPIA2_VC_VC_CLOCKS_CLKDIV_MASK 0x03 +#define CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 0x04 +#define CPIA2_VC_VC_672_CLOCKS_SCALING 0x08 +#define CPIA2_VC_VC_CLOCKS_LOGDIV0 0x00 +#define CPIA2_VC_VC_CLOCKS_LOGDIV1 0x01 +#define CPIA2_VC_VC_CLOCKS_LOGDIV2 0x02 +#define CPIA2_VC_VC_CLOCKS_LOGDIV3 0x03 +#define CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 0x08 +#define CPIA2_VC_VC_676_CLOCKS_SCALING 0x10 + +#define CPIA2_VC_VC_IHSIZE_LO 0xC5 + +#define CPIA2_VC_VC_XLIM_HI 0xC6 + +#define CPIA2_VC_VC_XLIM_LO 0xC7 + +#define CPIA2_VC_VC_YLIM_HI 0xC8 + +#define CPIA2_VC_VC_YLIM_LO 0xC9 + +#define CPIA2_VC_VC_OHSIZE 0xCA + +#define CPIA2_VC_VC_OVSIZE 0xCB + +#define CPIA2_VC_VC_HCROP 0xCC + +#define CPIA2_VC_VC_VCROP 0xCD + +#define CPIA2_VC_VC_HPHASE 0xCE + +#define CPIA2_VC_VC_VPHASE 0xCF + +#define CPIA2_VC_VC_HISPAN 0xD0 + +#define CPIA2_VC_VC_VISPAN 0xD1 + +#define CPIA2_VC_VC_HICROP 0xD2 + +#define CPIA2_VC_VC_VICROP 0xD3 + +#define CPIA2_VC_VC_HFRACT 0xD4 +#define CPIA2_VC_VC_HFRACT_DEN_MASK 0x0F +#define CPIA2_VC_VC_HFRACT_NUM_MASK 0xF0 + +#define CPIA2_VC_VC_VFRACT 0xD5 +#define CPIA2_VC_VC_VFRACT_DEN_MASK 0x0F +#define CPIA2_VC_VC_VFRACT_NUM_MASK 0xF0 + +#define CPIA2_VC_VC_JPEG_OPT 0xD6 +#define CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE 0x01 +#define CPIA2_VC_VC_JPEG_OPT_NO_DC_AUTO_SQUEEZE 0x02 +#define CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE 0x04 +#define CPIA2_VC_VC_JPEG_OPT_DEFAULT (CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE|\ + CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE) + + +#define CPIA2_VC_VC_CREEP_PERIOD 0xD7 +#define CPIA2_VC_VC_USER_SQUEEZE 0xD8 +#define CPIA2_VC_VC_TARGET_KB 0xD9 + +#define CPIA2_VC_VC_AUTO_SQUEEZE 0xE6 + + +/*** + * VP register set (Bank 2) + ***/ +#define CPIA2_VP_DEVICEH 0 +#define CPIA2_VP_DEVICEL 1 + +#define CPIA2_VP_SYSTEMSTATE 0x02 +#define CPIA2_VP_SYSTEMSTATE_HK_ALIVE 0x01 + +#define CPIA2_VP_SYSTEMCTRL 0x03 +#define CPIA2_VP_SYSTEMCTRL_REQ_CLEAR_ERROR 0x80 +#define CPIA2_VP_SYSTEMCTRL_POWER_DOWN_PLL 0x20 +#define CPIA2_VP_SYSTEMCTRL_REQ_SUSPEND_STATE 0x10 +#define CPIA2_VP_SYSTEMCTRL_REQ_SERIAL_WAKEUP 0x08 +#define CPIA2_VP_SYSTEMCTRL_REQ_AUTOLOAD 0x04 +#define CPIA2_VP_SYSTEMCTRL_HK_CONTROL 0x02 +#define CPIA2_VP_SYSTEMCTRL_POWER_CONTROL 0x01 + +#define CPIA2_VP_SENSOR_FLAGS 0x05 +#define CPIA2_VP_SENSOR_FLAGS_404 0x01 +#define CPIA2_VP_SENSOR_FLAGS_407 0x02 +#define CPIA2_VP_SENSOR_FLAGS_409 0x04 +#define CPIA2_VP_SENSOR_FLAGS_410 0x08 +#define CPIA2_VP_SENSOR_FLAGS_500 0x10 + +#define CPIA2_VP_SENSOR_REV 0x06 + +#define CPIA2_VP_DEVICE_CONFIG 0x07 +#define CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE 0x01 + +#define CPIA2_VP_GPIO_DIRECTION 0x08 +#define CPIA2_VP_GPIO_READ 0xFF +#define CPIA2_VP_GPIO_WRITE 0x00 + +#define CPIA2_VP_GPIO_DATA 0x09 + +#define CPIA2_VP_RAM_ADDR_H 0x0A +#define CPIA2_VP_RAM_ADDR_L 0x0B +#define CPIA2_VP_RAM_DATA 0x0C + +#define CPIA2_VP_PATCH_REV 0x0F + +#define CPIA2_VP4_USER_MODE 0x10 +#define CPIA2_VP5_USER_MODE 0x13 +#define CPIA2_VP_USER_MODE_CIF 0x01 +#define CPIA2_VP_USER_MODE_QCIFDS 0x02 +#define CPIA2_VP_USER_MODE_QCIFPTC 0x04 +#define CPIA2_VP_USER_MODE_QVGADS 0x08 +#define CPIA2_VP_USER_MODE_QVGAPTC 0x10 +#define CPIA2_VP_USER_MODE_VGA 0x20 + +#define CPIA2_VP4_FRAMERATE_REQUEST 0x11 +#define CPIA2_VP5_FRAMERATE_REQUEST 0x14 +#define CPIA2_VP_FRAMERATE_60 0x80 +#define CPIA2_VP_FRAMERATE_50 0x40 +#define CPIA2_VP_FRAMERATE_30 0x20 +#define CPIA2_VP_FRAMERATE_25 0x10 +#define CPIA2_VP_FRAMERATE_15 0x08 +#define CPIA2_VP_FRAMERATE_12_5 0x04 +#define CPIA2_VP_FRAMERATE_7_5 0x02 +#define CPIA2_VP_FRAMERATE_6_25 0x01 + +#define CPIA2_VP4_USER_EFFECTS 0x12 +#define CPIA2_VP5_USER_EFFECTS 0x15 +#define CPIA2_VP_USER_EFFECTS_COLBARS 0x01 +#define CPIA2_VP_USER_EFFECTS_COLBARS_GRAD 0x02 +#define CPIA2_VP_USER_EFFECTS_MIRROR 0x04 +#define CPIA2_VP_USER_EFFECTS_FLIP 0x40 // VP5 only + +/* NOTE: CPIA2_VP_EXPOSURE_MODES shares the same register as VP5 User + * Effects */ +#define CPIA2_VP_EXPOSURE_MODES 0x15 +#define CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER 0x20 +#define CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP 0x10 + +#define CPIA2_VP4_EXPOSURE_TARGET 0x16 // VP4 +#define CPIA2_VP5_EXPOSURE_TARGET 0x20 // VP5 + +#define CPIA2_VP_FLICKER_MODES 0x1B +#define CPIA2_VP_FLICKER_MODES_50HZ 0x80 +#define CPIA2_VP_FLICKER_MODES_CUSTOM_FLT_FFREQ 0x40 +#define CPIA2_VP_FLICKER_MODES_NEVER_FLICKER 0x20 +#define CPIA2_VP_FLICKER_MODES_INHIBIT_RUB 0x10 +#define CPIA2_VP_FLICKER_MODES_ADJUST_LINE_FREQ 0x08 +#define CPIA2_VP_FLICKER_MODES_CUSTOM_INT_FFREQ 0x04 + +#define CPIA2_VP_UMISC 0x1D +#define CPIA2_VP_UMISC_FORCE_MONO 0x80 +#define CPIA2_VP_UMISC_FORCE_ID_MASK 0x40 +#define CPIA2_VP_UMISC_INHIBIT_AUTO_FGS 0x20 +#define CPIA2_VP_UMISC_INHIBIT_AUTO_DIMS 0x08 +#define CPIA2_VP_UMISC_OPT_FOR_SENSOR_DS 0x04 +#define CPIA2_VP_UMISC_INHIBIT_AUTO_MODE_INT 0x02 + +#define CPIA2_VP5_ANTIFLKRSETUP 0x22 //34 + +#define CPIA2_VP_INTERPOLATION 0x24 +#define CPIA2_VP_INTERPOLATION_EVEN_FIRST 0x40 +#define CPIA2_VP_INTERPOLATION_HJOG 0x20 +#define CPIA2_VP_INTERPOLATION_VJOG 0x10 + +#define CPIA2_VP_GAMMA 0x25 +#define CPIA2_VP_DEFAULT_GAMMA 0x10 + +#define CPIA2_VP_YRANGE 0x26 + +#define CPIA2_VP_SATURATION 0x27 + +#define CPIA2_VP5_MYBLACK_LEVEL 0x3A //58 +#define CPIA2_VP5_MCYRANGE 0x3B //59 +#define CPIA2_VP5_MYCEILING 0x3C //60 +#define CPIA2_VP5_MCUVSATURATION 0x3D //61 + + +#define CPIA2_VP_REHASH_VALUES 0x60 + + +/*** + * Common sensor registers + ***/ +#define CPIA2_SENSOR_DEVICE_H 0x00 +#define CPIA2_SENSOR_DEVICE_L 0x01 + +#define CPIA2_SENSOR_DATA_FORMAT 0x16 +#define CPIA2_SENSOR_DATA_FORMAT_HMIRROR 0x08 +#define CPIA2_SENSOR_DATA_FORMAT_VMIRROR 0x10 + +#define CPIA2_SENSOR_CR1 0x76 +#define CPIA2_SENSOR_CR1_STAND_BY 0x01 +#define CPIA2_SENSOR_CR1_DOWN_RAMP_GEN 0x02 +#define CPIA2_SENSOR_CR1_DOWN_COLUMN_ADC 0x04 +#define CPIA2_SENSOR_CR1_DOWN_CAB_REGULATOR 0x08 +#define CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR 0x10 +#define CPIA2_SENSOR_CR1_DOWN_VRT_AMP 0x20 +#define CPIA2_SENSOR_CR1_DOWN_BAND_GAP 0x40 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_usb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_usb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_usb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_usb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,914 @@ +/**************************************************************************** + * + * Filename: cpia2_usb.c + * + * Copyright 2001, STMicrolectronics, Inc. + * Contact: steve.miller@st.com + * + * Description: + * This is a USB driver for CPia2 based video cameras. + * The infrastructure of this driver is based on the cpia usb driver by + * Jochen Scharrlach and Johannes Erdfeldt. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Stripped of 2.4 stuff ready for main kernel submit by + * Alan Cox + ****************************************************************************/ + +#include +#include +#include + +#include "cpia2.h" + +static int frame_sizes[] = { + 0, // USBIF_CMDONLY + 0, // USBIF_BULK + 128, // USBIF_ISO_1 + 384, // USBIF_ISO_2 + 640, // USBIF_ISO_3 + 768, // USBIF_ISO_4 + 896, // USBIF_ISO_5 + 1023, // USBIF_ISO_6 +}; + +#define FRAMES_PER_DESC 10 +#define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt] + +static void process_frame(struct camera_data *cam); +static void cpia2_usb_complete(struct urb *urb); +static int cpia2_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id); +static void cpia2_usb_disconnect(struct usb_interface *intf); + +static void free_sbufs(struct camera_data *cam); +static void add_APPn(struct camera_data *cam); +static void add_COM(struct camera_data *cam); +static int submit_urbs(struct camera_data *cam); +static int set_alternate(struct camera_data *cam, unsigned int alt); +static int configure_transfer_mode(struct camera_data *cam, unsigned int alt); + +static struct usb_device_id cpia2_id_table[] = { + {USB_DEVICE(0x0553, 0x0100)}, + {USB_DEVICE(0x0553, 0x0140)}, + {USB_DEVICE(0x0553, 0x0151)}, /* STV0676 */ + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, cpia2_id_table); + +static struct usb_driver cpia2_driver = { + .name = "cpia2", + .probe = cpia2_usb_probe, + .disconnect = cpia2_usb_disconnect, + .id_table = cpia2_id_table +}; + + +/****************************************************************************** + * + * process_frame + * + *****************************************************************************/ +static void process_frame(struct camera_data *cam) +{ + static int frame_count; + + unsigned char *inbuff = cam->workbuff->data; + + DBG("Processing frame #%d, current:%d\n", + cam->workbuff->num, cam->curbuff->num); + + if(cam->workbuff->length > cam->workbuff->max_length) + cam->workbuff->max_length = cam->workbuff->length; + + if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) { + frame_count++; + } else { + cam->workbuff->status = FRAME_ERROR; + DBG("Start of frame not found\n"); + return; + } + + /*** + * Now the output buffer should have a JPEG image in it. + ***/ + if(!cam->first_image_seen) { + /* Always skip the first image after streaming + * starts. It is almost certainly corrupt. */ + cam->first_image_seen = 1; + cam->workbuff->status = FRAME_EMPTY; + return; + } + if (cam->workbuff->length > 3) { + if(cam->mmapped && + cam->workbuff->length < cam->workbuff->max_length) { + /* No junk in the buffers */ + memset(cam->workbuff->data+cam->workbuff->length, + 0, cam->workbuff->max_length- + cam->workbuff->length); + } + cam->workbuff->max_length = cam->workbuff->length; + cam->workbuff->status = FRAME_READY; + + if(!cam->mmapped && cam->num_frames > 2) { + /* During normal reading, the most recent + * frame will be read. If the current frame + * hasn't started reading yet, it will never + * be read, so mark it empty. If the buffer is + * mmapped, or we have few buffers, we need to + * wait for the user to free the buffer. + * + * NOTE: This is not entirely foolproof with 3 + * buffers, but it would take an EXTREMELY + * overloaded system to cause problems (possible + * image data corruption). Basically, it would + * need to take more time to execute cpia2_read + * than it would for the camera to send + * cam->num_frames-2 frames before problems + * could occur. + */ + cam->curbuff->status = FRAME_EMPTY; + } + cam->curbuff = cam->workbuff; + cam->workbuff = cam->workbuff->next; + DBG("Changed buffers, work:%d, current:%d\n", + cam->workbuff->num, cam->curbuff->num); + return; + } else { + DBG("Not enough data for an image.\n"); + } + + cam->workbuff->status = FRAME_ERROR; + return; +} + +/****************************************************************************** + * + * add_APPn + * + * Adds a user specified APPn record + *****************************************************************************/ +static void add_APPn(struct camera_data *cam) +{ + if(cam->APP_len > 0) { + cam->workbuff->data[cam->workbuff->length++] = 0xFF; + cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn; + cam->workbuff->data[cam->workbuff->length++] = 0; + cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2; + memcpy(cam->workbuff->data+cam->workbuff->length, + cam->APP_data, cam->APP_len); + cam->workbuff->length += cam->APP_len; + } +} + +/****************************************************************************** + * + * add_COM + * + * Adds a user specified COM record + *****************************************************************************/ +static void add_COM(struct camera_data *cam) +{ + if(cam->COM_len > 0) { + cam->workbuff->data[cam->workbuff->length++] = 0xFF; + cam->workbuff->data[cam->workbuff->length++] = 0xFE; + cam->workbuff->data[cam->workbuff->length++] = 0; + cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2; + memcpy(cam->workbuff->data+cam->workbuff->length, + cam->COM_data, cam->COM_len); + cam->workbuff->length += cam->COM_len; + } +} + +/****************************************************************************** + * + * cpia2_usb_complete + * + * callback when incoming packet is received + *****************************************************************************/ +static void cpia2_usb_complete(struct urb *urb) +{ + int i; + unsigned char *cdata; + static int frame_ready = false; + struct camera_data *cam = (struct camera_data *) urb->context; + + if (urb->status!=0) { + if (!(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) + { + DBG("urb->status = %d!\n", urb->status); + } + DBG("Stopping streaming\n"); + return; + } + + if (!cam->streaming || !cam->present || cam->open_count == 0) { + LOG("Will now stop the streaming: streaming = %d, " + "present=%d, open_count=%d\n", + cam->streaming, cam->present, cam->open_count); + return; + } + + /*** + * Packet collater + ***/ + //DBG("Collating %d packets\n", urb->number_of_packets); + for (i = 0; i < urb->number_of_packets; i++) { + u16 checksum, iso_checksum; + int j; + int n = urb->iso_frame_desc[i].actual_length; + int st = urb->iso_frame_desc[i].status; + + if(cam->workbuff->status == FRAME_READY) { + struct framebuf *ptr; + /* Try to find an available buffer */ + DBG("workbuff full, searching\n"); + for (ptr = cam->workbuff->next; + ptr != cam->workbuff; + ptr = ptr->next) + { + if (ptr->status == FRAME_EMPTY) { + ptr->status = FRAME_READING; + ptr->length = 0; + break; + } + } + if (ptr == cam->workbuff) + break; /* No READING or EMPTY buffers left */ + + cam->workbuff = ptr; + } + + if (cam->workbuff->status == FRAME_EMPTY || + cam->workbuff->status == FRAME_ERROR) { + cam->workbuff->status = FRAME_READING; + cam->workbuff->length = 0; + } + + //DBG(" Packet %d length = %d, status = %d\n", i, n, st); + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (st) { + LOG("cpia2 data error: [%d] len=%d, status = %d\n", + i, n, st); + if(!ALLOW_CORRUPT) + cam->workbuff->status = FRAME_ERROR; + continue; + } + + if(n<=2) + continue; + + checksum = 0; + for(j=0; jworkbuff->status = FRAME_ERROR; + continue; + } + } + n -= 2; + + if(cam->workbuff->status != FRAME_READING) { + if((0xFF == cdata[0] && 0xD8 == cdata[1]) || + (0xD8 == cdata[0] && 0xFF == cdata[1] && + 0 != cdata[2])) { + /* frame is skipped, but increment total + * frame count anyway */ + cam->frame_count++; + } + DBG("workbuff not reading, status=%d\n", + cam->workbuff->status); + continue; + } + + if (cam->frame_size < cam->workbuff->length + n) { + ERR("buffer overflow! length: %d, n: %d\n", + cam->workbuff->length, n); + cam->workbuff->status = FRAME_ERROR; + if(cam->workbuff->length > cam->workbuff->max_length) + cam->workbuff->max_length = + cam->workbuff->length; + continue; + } + + if (cam->workbuff->length == 0) { + int data_offset; + if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) { + data_offset = 1; + } else if((0xFF == cdata[0]) && (0xD8 == cdata[1]) + && (0xFF == cdata[2])) { + data_offset = 2; + } else { + DBG("Ignoring packet, not beginning!\n"); + continue; + } + DBG("Start of frame pattern found\n"); + do_gettimeofday(&cam->workbuff->timestamp); + cam->workbuff->seq = cam->frame_count++; + cam->workbuff->data[0] = 0xFF; + cam->workbuff->data[1] = 0xD8; + cam->workbuff->length = 2; + add_APPn(cam); + add_COM(cam); + memcpy(cam->workbuff->data+cam->workbuff->length, + cdata+data_offset, n-data_offset); + cam->workbuff->length += n-data_offset; + } else if (cam->workbuff->length > 0) { + memcpy(cam->workbuff->data + cam->workbuff->length, + cdata, n); + cam->workbuff->length += n; + } + + if ((cam->workbuff->length >= 3) && + (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) && + (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) && + (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) { + frame_ready = true; + cam->workbuff->data[cam->workbuff->length - 1] = 0; + cam->workbuff->length -= 1; + } else if ((cam->workbuff->length >= 2) && + (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) && + (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) { + frame_ready = true; + } + + if (frame_ready) { + DBG("Workbuff image size = %d\n",cam->workbuff->length); + process_frame(cam); + + frame_ready = false; + + if (waitqueue_active(&cam->wq_stream)) + wake_up_interruptible(&cam->wq_stream); + } + } + + if(cam->streaming) { + /* resubmit */ + urb->dev = cam->dev; + if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) + ERR("%s: usb_submit_urb ret %d!\n", __func__, i); + } +} + +/****************************************************************************** + * + * configure_transfer_mode + * + *****************************************************************************/ +static int configure_transfer_mode(struct camera_data *cam, unsigned int alt) +{ + static unsigned char iso_regs[8][4] = { + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0xB9, 0x00, 0x00, 0x7E}, + {0xB9, 0x00, 0x01, 0x7E}, + {0xB9, 0x00, 0x02, 0x7E}, + {0xB9, 0x00, 0x02, 0xFE}, + {0xB9, 0x00, 0x03, 0x7E}, + {0xB9, 0x00, 0x03, 0xFD} + }; + struct cpia2_command cmd; + unsigned char reg; + + if(!cam->present) + return -ENODEV; + + /*** + * Write the isoc registers according to the alternate selected + ***/ + cmd.direction = TRANSFER_WRITE; + cmd.buffer.block_data[0] = iso_regs[alt][0]; + cmd.buffer.block_data[1] = iso_regs[alt][1]; + cmd.buffer.block_data[2] = iso_regs[alt][2]; + cmd.buffer.block_data[3] = iso_regs[alt][3]; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.start = CPIA2_VC_USB_ISOLIM; + cmd.reg_count = 4; + cpia2_send_command(cam, &cmd); + + /*** + * Enable relevant streams before starting polling. + * First read USB Stream Config Register. + ***/ + cmd.direction = TRANSFER_READ; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.start = CPIA2_VC_USB_STRM; + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + reg = cmd.buffer.block_data[0]; + + /* Clear iso, bulk, and int */ + reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE | + CPIA2_VC_USB_STRM_ISO_ENABLE | + CPIA2_VC_USB_STRM_INT_ENABLE); + + if (alt == USBIF_BULK) { + DBG("Enabling bulk xfer\n"); + reg |= CPIA2_VC_USB_STRM_BLK_ENABLE; /* Enable Bulk */ + cam->xfer_mode = XFER_BULK; + } else if (alt >= USBIF_ISO_1) { + DBG("Enabling ISOC xfer\n"); + reg |= CPIA2_VC_USB_STRM_ISO_ENABLE; + cam->xfer_mode = XFER_ISOC; + } + + cmd.buffer.block_data[0] = reg; + cmd.direction = TRANSFER_WRITE; + cmd.start = CPIA2_VC_USB_STRM; + cmd.reg_count = 1; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cpia2_send_command(cam, &cmd); + + return 0; +} + +/****************************************************************************** + * + * cpia2_usb_change_streaming_alternate + * + *****************************************************************************/ +int cpia2_usb_change_streaming_alternate(struct camera_data *cam, + unsigned int alt) +{ + int ret = 0; + + if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6) + return -EINVAL; + + if(alt == cam->params.camera_state.stream_mode) + return 0; + + cpia2_usb_stream_pause(cam); + + configure_transfer_mode(cam, alt); + + cam->params.camera_state.stream_mode = alt; + + /* Reset the camera to prevent image quality degradation */ + cpia2_reset_camera(cam); + + cpia2_usb_stream_resume(cam); + + return ret; +} + +/****************************************************************************** + * + * set_alternate + * + *****************************************************************************/ +static int set_alternate(struct camera_data *cam, unsigned int alt) +{ + int ret = 0; + + if(alt == cam->cur_alt) + return 0; + + if (cam->cur_alt != USBIF_CMDONLY) { + DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY); + ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY); + if (ret != 0) + return ret; + } + if (alt != USBIF_CMDONLY) { + DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt); + ret = usb_set_interface(cam->dev, cam->iface, alt); + if (ret != 0) + return ret; + } + + cam->old_alt = cam->cur_alt; + cam->cur_alt = alt; + + return ret; +} + +/****************************************************************************** + * + * free_sbufs + * + * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL + * are assumed to be allocated. Non-NULL .urb members are also assumed to be + * submitted (and must therefore be killed before they are freed). + *****************************************************************************/ +static void free_sbufs(struct camera_data *cam) +{ + int i; + + for (i = 0; i < NUM_SBUF; i++) { + if(cam->sbuf[i].urb) { + usb_kill_urb(cam->sbuf[i].urb); + usb_free_urb(cam->sbuf[i].urb); + cam->sbuf[i].urb = NULL; + } + if(cam->sbuf[i].data) { + kfree(cam->sbuf[i].data); + cam->sbuf[i].data = NULL; + } + } +} + +/******* +* Convenience functions +*******/ +/**************************************************************************** + * + * write_packet + * + ***************************************************************************/ +static int write_packet(struct usb_device *udev, + u8 request, u8 * registers, u16 start, size_t size) +{ + if (!registers || size <= 0) + return -EINVAL; + + return usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + start, /* value */ + 0, /* index */ + registers, /* buffer */ + size, + HZ); +} + +/**************************************************************************** + * + * read_packet + * + ***************************************************************************/ +static int read_packet(struct usb_device *udev, + u8 request, u8 * registers, u16 start, size_t size) +{ + if (!registers || size <= 0) + return -EINVAL; + + return usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + request, + USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE, + start, /* value */ + 0, /* index */ + registers, /* buffer */ + size, + HZ); +} + +/****************************************************************************** + * + * cpia2_usb_transfer_cmd + * + *****************************************************************************/ +int cpia2_usb_transfer_cmd(struct camera_data *cam, + void *registers, + u8 request, u8 start, u8 count, u8 direction) +{ + int err = 0; + struct usb_device *udev = cam->dev; + + if (!udev) { + ERR("%s: Internal driver error: udev is NULL\n", __func__); + return -EINVAL; + } + + if (!registers) { + ERR("%s: Internal driver error: register array is NULL\n", __func__); + return -EINVAL; + } + + if (direction == TRANSFER_READ) { + err = read_packet(udev, request, (u8 *)registers, start, count); + if (err > 0) + err = 0; + } else if (direction == TRANSFER_WRITE) { + err =write_packet(udev, request, (u8 *)registers, start, count); + if (err < 0) { + LOG("Control message failed, err val = %d\n", err); + LOG("Message: request = 0x%0X, start = 0x%0X\n", + request, start); + LOG("Message: count = %d, register[0] = 0x%0X\n", + count, ((unsigned char *) registers)[0]); + } else + err=0; + } else { + LOG("Unexpected first byte of direction: %d\n", + direction); + return -EINVAL; + } + + if(err != 0) + LOG("Unexpected error: %d\n", err); + return err; +} + + +/****************************************************************************** + * + * submit_urbs + * + *****************************************************************************/ +static int submit_urbs(struct camera_data *cam) +{ + struct urb *urb; + int fx, err, i, j; + + for(i=0; isbuf[i].data) + continue; + cam->sbuf[i].data = + kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!cam->sbuf[i].data) { + while (--i >= 0) { + kfree(cam->sbuf[i].data); + cam->sbuf[i].data = NULL; + } + return -ENOMEM; + } + } + + /* We double buffer the Isoc lists, and also know the polling + * interval is every frame (1 == (1 << (bInterval -1))). + */ + for(i=0; isbuf[i].urb) { + continue; + } + urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); + if (!urb) { + ERR("%s: usb_alloc_urb error!\n", __func__); + for (j = 0; j < i; j++) + usb_free_urb(cam->sbuf[j].urb); + return -ENOMEM; + } + + cam->sbuf[i].urb = urb; + urb->dev = cam->dev; + urb->context = cam; + urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = cam->sbuf[i].data; + urb->complete = cpia2_usb_complete; + urb->number_of_packets = FRAMES_PER_DESC; + urb->interval = 1; + urb->transfer_buffer_length = + FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = + FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + } + + + /* Queue the ISO urbs, and resubmit in the completion handler */ + for(i=0; isbuf[i].urb, GFP_KERNEL); + if (err) { + ERR("usb_submit_urb[%d]() = %d\n", i, err); + return err; + } + } + + return 0; +} + +/****************************************************************************** + * + * cpia2_usb_stream_start + * + *****************************************************************************/ +int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate) +{ + int ret; + int old_alt; + + if(cam->streaming) + return 0; + + if (cam->flush) { + int i; + DBG("Flushing buffers\n"); + for(i=0; inum_frames; ++i) { + cam->buffers[i].status = FRAME_EMPTY; + cam->buffers[i].length = 0; + } + cam->curbuff = &cam->buffers[0]; + cam->workbuff = cam->curbuff->next; + cam->flush = false; + } + + old_alt = cam->params.camera_state.stream_mode; + cam->params.camera_state.stream_mode = 0; + ret = cpia2_usb_change_streaming_alternate(cam, alternate); + if (ret < 0) { + int ret2; + ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret); + cam->params.camera_state.stream_mode = old_alt; + ret2 = set_alternate(cam, USBIF_CMDONLY); + if (ret2 < 0) { + ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already " + "failed. Then tried to call " + "set_alternate(USBIF_CMDONLY) = %d.\n", + alternate, ret, ret2); + } + } else { + cam->frame_count = 0; + cam->streaming = 1; + ret = cpia2_usb_stream_resume(cam); + } + return ret; +} + +/****************************************************************************** + * + * cpia2_usb_stream_pause + * + *****************************************************************************/ +int cpia2_usb_stream_pause(struct camera_data *cam) +{ + int ret = 0; + if(cam->streaming) { + ret = set_alternate(cam, USBIF_CMDONLY); + free_sbufs(cam); + } + return ret; +} + +/****************************************************************************** + * + * cpia2_usb_stream_resume + * + *****************************************************************************/ +int cpia2_usb_stream_resume(struct camera_data *cam) +{ + int ret = 0; + if(cam->streaming) { + cam->first_image_seen = 0; + ret = set_alternate(cam, cam->params.camera_state.stream_mode); + if(ret == 0) { + ret = submit_urbs(cam); + } + } + return ret; +} + +/****************************************************************************** + * + * cpia2_usb_stream_stop + * + *****************************************************************************/ +int cpia2_usb_stream_stop(struct camera_data *cam) +{ + int ret; + ret = cpia2_usb_stream_pause(cam); + cam->streaming = 0; + configure_transfer_mode(cam, 0); + return ret; +} + +/****************************************************************************** + * + * cpia2_usb_probe + * + * Probe and initialize. + *****************************************************************************/ +static int cpia2_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_interface_descriptor *interface; + struct camera_data *cam; + int ret; + + /* A multi-config CPiA2 camera? */ + if (udev->descriptor.bNumConfigurations != 1) + return -ENODEV; + interface = &intf->cur_altsetting->desc; + + /* If we get to this point, we found a CPiA2 camera */ + LOG("CPiA2 USB camera found\n"); + + if((cam = cpia2_init_camera_struct()) == NULL) + return -ENOMEM; + + cam->dev = udev; + cam->iface = interface->bInterfaceNumber; + + ret = set_alternate(cam, USBIF_CMDONLY); + if (ret < 0) { + ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret); + kfree(cam); + return ret; + } + + if ((ret = cpia2_register_camera(cam)) < 0) { + ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret); + kfree(cam); + return ret; + } + + + if((ret = cpia2_init_camera(cam)) < 0) { + ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret); + cpia2_unregister_camera(cam); + kfree(cam); + return ret; + } + LOG(" CPiA Version: %d.%02d (%d.%d)\n", + cam->params.version.firmware_revision_hi, + cam->params.version.firmware_revision_lo, + cam->params.version.asic_id, + cam->params.version.asic_rev); + LOG(" CPiA PnP-ID: %04x:%04x:%04x\n", + cam->params.pnp_id.vendor, + cam->params.pnp_id.product, + cam->params.pnp_id.device_revision); + LOG(" SensorID: %d.(version %d)\n", + cam->params.version.sensor_flags, + cam->params.version.sensor_rev); + + usb_set_intfdata(intf, cam); + + return 0; +} + +/****************************************************************************** + * + * cpia2_disconnect + * + *****************************************************************************/ +static void cpia2_usb_disconnect(struct usb_interface *intf) +{ + struct camera_data *cam = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + cam->present = 0; + + DBG("Stopping stream\n"); + cpia2_usb_stream_stop(cam); + + DBG("Unregistering camera\n"); + cpia2_unregister_camera(cam); + + if(cam->buffers) { + DBG("Wakeup waiting processes\n"); + cam->curbuff->status = FRAME_READY; + cam->curbuff->length = 0; + if (waitqueue_active(&cam->wq_stream)) + wake_up_interruptible(&cam->wq_stream); + } + + DBG("Releasing interface\n"); + usb_driver_release_interface(&cpia2_driver, intf); + + if (cam->open_count == 0) { + DBG("Freeing camera structure\n"); + kfree(cam); + } + + LOG("CPiA2 camera disconnected.\n"); +} + + +/****************************************************************************** + * + * usb_cpia2_init + * + *****************************************************************************/ +int cpia2_usb_init(void) +{ + return usb_register(&cpia2_driver); +} + +/****************************************************************************** + * + * usb_cpia_cleanup + * + *****************************************************************************/ +void cpia2_usb_cleanup(void) +{ + schedule_timeout(2 * HZ); + usb_deregister(&cpia2_driver); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_v4l.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_v4l.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_v4l.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/cpia2_v4l.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1582 @@ +/**************************************************************************** + * + * Filename: cpia2_v4l.c + * + * Copyright 2001, STMicrolectronics, Inc. + * Contact: steve.miller@st.com + * Copyright 2001,2005, Scott J. Bertin + * + * Description: + * This is a USB driver for CPia2 based video cameras. + * The infrastructure of this driver is based on the cpia usb driver by + * Jochen Scharrlach and Johannes Erdfeldt. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Stripped of 2.4 stuff ready for main kernel submit by + * Alan Cox + ****************************************************************************/ + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpia2.h" +#include "cpia2dev.h" + +static int video_nr = -1; +module_param(video_nr, int, 0); +MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); + +static int buffer_size = 68*1024; +module_param(buffer_size, int, 0); +MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); + +static int num_buffers = 3; +module_param(num_buffers, int, 0); +MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" + __stringify(VIDEO_MAX_FRAME) ", default 3)"); + +static int alternate = DEFAULT_ALT; +module_param(alternate, int, 0); +MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-" + __stringify(USBIF_ISO_6) ", default " + __stringify(DEFAULT_ALT) ")"); + +static int flicker_freq = 60; +module_param(flicker_freq, int, 0); +MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" __stringify(50) "or" + __stringify(60) ", default " + __stringify(60) ")"); + +static int flicker_mode = NEVER_FLICKER; +module_param(flicker_mode, int, 0); +MODULE_PARM_DESC(flicker_mode, + "Flicker supression (" __stringify(NEVER_FLICKER) "or" + __stringify(ANTI_FLICKER_ON) ", default " + __stringify(NEVER_FLICKER) ")"); + +MODULE_AUTHOR("Steve Miller (STMicroelectronics) "); +MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); +MODULE_SUPPORTED_DEVICE("video"); +MODULE_LICENSE("GPL"); + +#define ABOUT "V4L-Driver for Vision CPiA2 based cameras" + +struct control_menu_info { + int value; + char name[32]; +}; + +static struct control_menu_info framerate_controls[] = +{ + { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" }, + { CPIA2_VP_FRAMERATE_7_5, "7.5 fps" }, + { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" }, + { CPIA2_VP_FRAMERATE_15, "15 fps" }, + { CPIA2_VP_FRAMERATE_25, "25 fps" }, + { CPIA2_VP_FRAMERATE_30, "30 fps" }, +}; +#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls)) + +static struct control_menu_info flicker_controls[] = +{ + { NEVER_FLICKER, "Off" }, + { FLICKER_50, "50 Hz" }, + { FLICKER_60, "60 Hz" }, +}; +#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls)) + +static struct control_menu_info lights_controls[] = +{ + { 0, "Off" }, + { 64, "Top" }, + { 128, "Bottom" }, + { 192, "Both" }, +}; +#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls)) +#define GPIO_LIGHTS_MASK 192 + +static struct v4l2_queryctrl controls[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = DEFAULT_BRIGHTNESS, + }, + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = DEFAULT_CONTRAST, + }, + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = DEFAULT_SATURATION, + }, + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = CPIA2_CID_TARGET_KB, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Target KB", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = DEFAULT_TARGET_KB, + }, + { + .id = CPIA2_CID_GPIO, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "GPIO", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0, + }, + { + .id = CPIA2_CID_FLICKER_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flicker Reduction", + .minimum = 0, + .maximum = NUM_FLICKER_CONTROLS-1, + .step = 1, + .default_value = 0, + }, + { + .id = CPIA2_CID_FRAMERATE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Framerate", + .minimum = 0, + .maximum = NUM_FRAMERATE_CONTROLS-1, + .step = 1, + .default_value = NUM_FRAMERATE_CONTROLS-1, + }, + { + .id = CPIA2_CID_USB_ALT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "USB Alternate", + .minimum = USBIF_ISO_1, + .maximum = USBIF_ISO_6, + .step = 1, + .default_value = DEFAULT_ALT, + }, + { + .id = CPIA2_CID_LIGHTS, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Lights", + .minimum = 0, + .maximum = NUM_LIGHTS_CONTROLS-1, + .step = 1, + .default_value = 0, + }, + { + .id = CPIA2_CID_RESET_CAMERA, + .type = V4L2_CTRL_TYPE_BUTTON, + .name = "Reset Camera", + .minimum = 0, + .maximum = 0, + .step = 0, + .default_value = 0, + }, +}; +#define NUM_CONTROLS (ARRAY_SIZE(controls)) + + +/****************************************************************************** + * + * cpia2_open + * + *****************************************************************************/ +static int cpia2_open(struct file *file) +{ + struct camera_data *cam = video_drvdata(file); + struct cpia2_fh *fh; + + if (!cam) { + ERR("Internal error, camera_data not found!\n"); + return -ENODEV; + } + + if (!cam->present) + return -ENODEV; + + if (cam->open_count == 0) { + if (cpia2_allocate_buffers(cam)) + return -ENOMEM; + + /* reset the camera */ + if (cpia2_reset_camera(cam) < 0) + return -EIO; + + cam->APP_len = 0; + cam->COM_len = 0; + } + + fh = kmalloc(sizeof(*fh), GFP_KERNEL); + if (!fh) + return -ENOMEM; + file->private_data = fh; + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&cam->prio, &fh->prio); + fh->mmapped = 0; + + ++cam->open_count; + + cpia2_dbg_dump_registers(cam); + return 0; +} + +/****************************************************************************** + * + * cpia2_close + * + *****************************************************************************/ +static int cpia2_close(struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct camera_data *cam = video_get_drvdata(dev); + struct cpia2_fh *fh = file->private_data; + + if (cam->present && + (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) { + cpia2_usb_stream_stop(cam); + + if (cam->open_count == 1) { + /* save camera state for later open */ + cpia2_save_camera_state(cam); + + cpia2_set_low_power(cam); + cpia2_free_buffers(cam); + } + } + + if (fh->mmapped) + cam->mmapped = 0; + v4l2_prio_close(&cam->prio, fh->prio); + file->private_data = NULL; + kfree(fh); + + if (--cam->open_count == 0) { + cpia2_free_buffers(cam); + if (!cam->present) { + video_unregister_device(dev); + kfree(cam); + return 0; + } + } + + return 0; +} + +/****************************************************************************** + * + * cpia2_v4l_read + * + *****************************************************************************/ +static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, + loff_t *off) +{ + struct camera_data *cam = video_drvdata(file); + int noblock = file->f_flags&O_NONBLOCK; + + struct cpia2_fh *fh = file->private_data; + + if(!cam) + return -EINVAL; + + /* Priority check */ + if(fh->prio != V4L2_PRIORITY_RECORD) { + return -EBUSY; + } + + return cpia2_read(cam, buf, count, noblock); +} + + +/****************************************************************************** + * + * cpia2_v4l_poll + * + *****************************************************************************/ +static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct camera_data *cam = video_drvdata(filp); + struct cpia2_fh *fh = filp->private_data; + + if(!cam) + return POLLERR; + + /* Priority check */ + if(fh->prio != V4L2_PRIORITY_RECORD) { + return POLLERR; + } + + return cpia2_poll(cam, filp, wait); +} + + +static int sync(struct camera_data *cam, int frame_nr) +{ + struct framebuf *frame = &cam->buffers[frame_nr]; + + while (1) { + if (frame->status == FRAME_READY) + return 0; + + if (!cam->streaming) { + frame->status = FRAME_READY; + frame->length = 0; + return 0; + } + + mutex_unlock(&cam->v4l2_lock); + wait_event_interruptible(cam->wq_stream, + !cam->streaming || + frame->status == FRAME_READY); + mutex_lock(&cam->v4l2_lock); + if (signal_pending(current)) + return -ERESTARTSYS; + if(!cam->present) + return -ENOTTY; + } +} + +/****************************************************************************** + * + * ioctl_set_gpio + * + *****************************************************************************/ + +static long cpia2_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) +{ + struct camera_data *cam = video_drvdata(file); + __u32 gpio_val; + + if (cmd != CPIA2_CID_GPIO) + return -EINVAL; + + gpio_val = *(__u32*) arg; + + if (gpio_val &~ 0xFFU) + return -EINVAL; + + return cpia2_set_gpio(cam, (unsigned char)gpio_val); +} + +/****************************************************************************** + * + * ioctl_querycap + * + * V4L2 device capabilities + * + *****************************************************************************/ + +static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc) +{ + struct camera_data *cam = video_drvdata(file); + + strcpy(vc->driver, "cpia2"); + + if (cam->params.pnp_id.product == 0x151) + strcpy(vc->card, "QX5 Microscope"); + else + strcpy(vc->card, "CPiA2 Camera"); + switch (cam->params.pnp_id.device_type) { + case DEVICE_STV_672: + strcat(vc->card, " (672/"); + break; + case DEVICE_STV_676: + strcat(vc->card, " (676/"); + break; + default: + strcat(vc->card, " (XXX/"); + break; + } + switch (cam->params.version.sensor_flags) { + case CPIA2_VP_SENSOR_FLAGS_404: + strcat(vc->card, "404)"); + break; + case CPIA2_VP_SENSOR_FLAGS_407: + strcat(vc->card, "407)"); + break; + case CPIA2_VP_SENSOR_FLAGS_409: + strcat(vc->card, "409)"); + break; + case CPIA2_VP_SENSOR_FLAGS_410: + strcat(vc->card, "410)"); + break; + case CPIA2_VP_SENSOR_FLAGS_500: + strcat(vc->card, "500)"); + break; + default: + strcat(vc->card, "XXX)"); + break; + } + + if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) + memset(vc->bus_info,0, sizeof(vc->bus_info)); + + vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER, + CPIA2_PATCH_VER); + + vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + + return 0; +} + +/****************************************************************************** + * + * ioctl_input + * + * V4L2 input get/set/enumerate + * + *****************************************************************************/ + +static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + if (i->index) + return -EINVAL; + strcpy(i->name, "Camera"); + i->type = V4L2_INPUT_TYPE_CAMERA; + return 0; +} + +static int cpia2_g_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int cpia2_s_input(struct file *file, void *fh, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +/****************************************************************************** + * + * ioctl_enum_fmt + * + * V4L2 format enumerate + * + *****************************************************************************/ + +static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + int index = f->index; + + if (index < 0 || index > 1) + return -EINVAL; + + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->flags = V4L2_FMT_FLAG_COMPRESSED; + switch(index) { + case 0: + strcpy(f->description, "MJPEG"); + f->pixelformat = V4L2_PIX_FMT_MJPEG; + break; + case 1: + strcpy(f->description, "JPEG"); + f->pixelformat = V4L2_PIX_FMT_JPEG; + break; + default: + return -EINVAL; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_try_fmt + * + * V4L2 format try + * + *****************************************************************************/ + +static int cpia2_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct camera_data *cam = video_drvdata(file); + + if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && + f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) + return -EINVAL; + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = cam->frame_size; + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + f->fmt.pix.priv = 0; + + switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { + case VIDEOSIZE_VGA: + f->fmt.pix.width = 640; + f->fmt.pix.height = 480; + break; + case VIDEOSIZE_CIF: + f->fmt.pix.width = 352; + f->fmt.pix.height = 288; + break; + case VIDEOSIZE_QVGA: + f->fmt.pix.width = 320; + f->fmt.pix.height = 240; + break; + case VIDEOSIZE_288_216: + f->fmt.pix.width = 288; + f->fmt.pix.height = 216; + break; + case VIDEOSIZE_256_192: + f->fmt.pix.width = 256; + f->fmt.pix.height = 192; + break; + case VIDEOSIZE_224_168: + f->fmt.pix.width = 224; + f->fmt.pix.height = 168; + break; + case VIDEOSIZE_192_144: + f->fmt.pix.width = 192; + f->fmt.pix.height = 144; + break; + case VIDEOSIZE_QCIF: + default: + f->fmt.pix.width = 176; + f->fmt.pix.height = 144; + break; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_set_fmt + * + * V4L2 format set + * + *****************************************************************************/ + +static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh, + struct v4l2_format *f) +{ + struct camera_data *cam = video_drvdata(file); + struct cpia2_fh *fh = _fh; + int err, frame; + + err = v4l2_prio_check(&cam->prio, fh->prio); + if (err) + return err; + err = cpia2_try_fmt_vid_cap(file, _fh, f); + if(err != 0) + return err; + + /* Ensure that only this process can change the format. */ + err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); + if(err != 0) { + return err; + } + + cam->pixelformat = f->fmt.pix.pixelformat; + + /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle + * the missing Huffman table properly. */ + cam->params.compression.inhibit_htables = 0; + /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ + + /* we set the video window to something smaller or equal to what + * is requested by the user??? + */ + DBG("Requested width = %d, height = %d\n", + f->fmt.pix.width, f->fmt.pix.height); + if (f->fmt.pix.width != cam->width || + f->fmt.pix.height != cam->height) { + cam->width = f->fmt.pix.width; + cam->height = f->fmt.pix.height; + cam->params.roi.width = f->fmt.pix.width; + cam->params.roi.height = f->fmt.pix.height; + cpia2_set_format(cam); + } + + for (frame = 0; frame < cam->num_frames; ++frame) { + if (cam->buffers[frame].status == FRAME_READING) + if ((err = sync(cam, frame)) < 0) + return err; + + cam->buffers[frame].status = FRAME_EMPTY; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_get_fmt + * + * V4L2 format get + * + *****************************************************************************/ + +static int cpia2_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct camera_data *cam = video_drvdata(file); + + f->fmt.pix.width = cam->width; + f->fmt.pix.height = cam->height; + f->fmt.pix.pixelformat = cam->pixelformat; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = cam->frame_size; + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + f->fmt.pix.priv = 0; + + return 0; +} + +/****************************************************************************** + * + * ioctl_cropcap + * + * V4L2 query cropping capabilities + * NOTE: cropping is currently disabled + * + *****************************************************************************/ + +static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c) +{ + struct camera_data *cam = video_drvdata(file); + + if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + c->bounds.left = 0; + c->bounds.top = 0; + c->bounds.width = cam->width; + c->bounds.height = cam->height; + c->defrect.left = 0; + c->defrect.top = 0; + c->defrect.width = cam->width; + c->defrect.height = cam->height; + c->pixelaspect.numerator = 1; + c->pixelaspect.denominator = 1; + + return 0; +} + +/****************************************************************************** + * + * ioctl_queryctrl + * + * V4L2 query possible control variables + * + *****************************************************************************/ + +static int cpia2_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) +{ + struct camera_data *cam = video_drvdata(file); + int i; + + for(i=0; iid == controls[i].id) { + memcpy(c, controls+i, sizeof(*c)); + break; + } + } + + if(i == NUM_CONTROLS) + return -EINVAL; + + /* Some devices have additional limitations */ + switch(c->id) { + case V4L2_CID_BRIGHTNESS: + /*** + * Don't let the register be set to zero - bug in VP4 + * flash of full brightness + ***/ + if (cam->params.pnp_id.device_type == DEVICE_STV_672) + c->minimum = 1; + break; + case V4L2_CID_VFLIP: + // VP5 Only + if(cam->params.pnp_id.device_type == DEVICE_STV_672) + c->flags |= V4L2_CTRL_FLAG_DISABLED; + break; + case CPIA2_CID_FRAMERATE: + if(cam->params.pnp_id.device_type == DEVICE_STV_672 && + cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ + // Maximum 15fps + for(i=0; imaximum; ++i) { + if(framerate_controls[i].value == + CPIA2_VP_FRAMERATE_15) { + c->maximum = i; + c->default_value = i; + } + } + } + break; + case CPIA2_CID_FLICKER_MODE: + // Flicker control only valid for 672. + if(cam->params.pnp_id.device_type != DEVICE_STV_672) + c->flags |= V4L2_CTRL_FLAG_DISABLED; + break; + case CPIA2_CID_LIGHTS: + // Light control only valid for the QX5 Microscope. + if(cam->params.pnp_id.product != 0x151) + c->flags |= V4L2_CTRL_FLAG_DISABLED; + break; + default: + break; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_querymenu + * + * V4L2 query possible control variables + * + *****************************************************************************/ + +static int cpia2_querymenu(struct file *file, void *fh, struct v4l2_querymenu *m) +{ + struct camera_data *cam = video_drvdata(file); + + switch(m->id) { + case CPIA2_CID_FLICKER_MODE: + if (m->index >= NUM_FLICKER_CONTROLS) + return -EINVAL; + + strcpy(m->name, flicker_controls[m->index].name); + break; + case CPIA2_CID_FRAMERATE: + { + int maximum = NUM_FRAMERATE_CONTROLS - 1; + if(cam->params.pnp_id.device_type == DEVICE_STV_672 && + cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ + // Maximum 15fps + int i; + for(i=0; iindex > maximum) + return -EINVAL; + + strcpy(m->name, framerate_controls[m->index].name); + break; + } + case CPIA2_CID_LIGHTS: + if (m->index >= NUM_LIGHTS_CONTROLS) + return -EINVAL; + + strcpy(m->name, lights_controls[m->index].name); + break; + default: + return -EINVAL; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_g_ctrl + * + * V4L2 get the value of a control variable + * + *****************************************************************************/ + +static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + struct camera_data *cam = video_drvdata(file); + + switch(c->id) { + case V4L2_CID_BRIGHTNESS: + cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, + TRANSFER_READ, 0); + c->value = cam->params.color_params.brightness; + break; + case V4L2_CID_CONTRAST: + cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, + TRANSFER_READ, 0); + c->value = cam->params.color_params.contrast; + break; + case V4L2_CID_SATURATION: + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, + TRANSFER_READ, 0); + c->value = cam->params.color_params.saturation; + break; + case V4L2_CID_HFLIP: + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, + TRANSFER_READ, 0); + c->value = (cam->params.vp_params.user_effects & + CPIA2_VP_USER_EFFECTS_MIRROR) != 0; + break; + case V4L2_CID_VFLIP: + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, + TRANSFER_READ, 0); + c->value = (cam->params.vp_params.user_effects & + CPIA2_VP_USER_EFFECTS_FLIP) != 0; + break; + case CPIA2_CID_TARGET_KB: + c->value = cam->params.vc_params.target_kb; + break; + case CPIA2_CID_GPIO: + cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, + TRANSFER_READ, 0); + c->value = cam->params.vp_params.gpio_data; + break; + case CPIA2_CID_FLICKER_MODE: + { + int i, mode; + cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, + TRANSFER_READ, 0); + if(cam->params.flicker_control.cam_register & + CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) { + mode = NEVER_FLICKER; + } else { + if(cam->params.flicker_control.cam_register & + CPIA2_VP_FLICKER_MODES_50HZ) { + mode = FLICKER_50; + } else { + mode = FLICKER_60; + } + } + for(i=0; ivalue = i; + break; + } + } + if(i == NUM_FLICKER_CONTROLS) + return -EINVAL; + break; + } + case CPIA2_CID_FRAMERATE: + { + int maximum = NUM_FRAMERATE_CONTROLS - 1; + int i; + for(i=0; i<= maximum; i++) { + if(cam->params.vp_params.frame_rate == + framerate_controls[i].value) + break; + } + if(i > maximum) + return -EINVAL; + c->value = i; + break; + } + case CPIA2_CID_USB_ALT: + c->value = cam->params.camera_state.stream_mode; + break; + case CPIA2_CID_LIGHTS: + { + int i; + cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, + TRANSFER_READ, 0); + for(i=0; iparams.vp_params.gpio_data&GPIO_LIGHTS_MASK) == + lights_controls[i].value) { + break; + } + } + if(i == NUM_LIGHTS_CONTROLS) + return -EINVAL; + c->value = i; + break; + } + case CPIA2_CID_RESET_CAMERA: + return -EINVAL; + default: + return -EINVAL; + } + + DBG("Get control id:%d, value:%d\n", c->id, c->value); + + return 0; +} + +/****************************************************************************** + * + * ioctl_s_ctrl + * + * V4L2 set the value of a control variable + * + *****************************************************************************/ + +static int cpia2_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + struct camera_data *cam = video_drvdata(file); + int i; + int retval = 0; + + DBG("Set control id:%d, value:%d\n", c->id, c->value); + + /* Check that the value is in range */ + for(i=0; iid == controls[i].id) { + if(c->value < controls[i].minimum || + c->value > controls[i].maximum) { + return -EINVAL; + } + break; + } + } + if(i == NUM_CONTROLS) + return -EINVAL; + + switch(c->id) { + case V4L2_CID_BRIGHTNESS: + cpia2_set_brightness(cam, c->value); + break; + case V4L2_CID_CONTRAST: + cpia2_set_contrast(cam, c->value); + break; + case V4L2_CID_SATURATION: + cpia2_set_saturation(cam, c->value); + break; + case V4L2_CID_HFLIP: + cpia2_set_property_mirror(cam, c->value); + break; + case V4L2_CID_VFLIP: + cpia2_set_property_flip(cam, c->value); + break; + case CPIA2_CID_TARGET_KB: + retval = cpia2_set_target_kb(cam, c->value); + break; + case CPIA2_CID_GPIO: + retval = cpia2_set_gpio(cam, c->value); + break; + case CPIA2_CID_FLICKER_MODE: + retval = cpia2_set_flicker_mode(cam, + flicker_controls[c->value].value); + break; + case CPIA2_CID_FRAMERATE: + retval = cpia2_set_fps(cam, framerate_controls[c->value].value); + break; + case CPIA2_CID_USB_ALT: + retval = cpia2_usb_change_streaming_alternate(cam, c->value); + break; + case CPIA2_CID_LIGHTS: + retval = cpia2_set_gpio(cam, lights_controls[c->value].value); + break; + case CPIA2_CID_RESET_CAMERA: + cpia2_usb_stream_pause(cam); + cpia2_reset_camera(cam); + cpia2_usb_stream_resume(cam); + break; + default: + retval = -EINVAL; + } + + return retval; +} + +/****************************************************************************** + * + * ioctl_g_jpegcomp + * + * V4L2 get the JPEG compression parameters + * + *****************************************************************************/ + +static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) +{ + struct camera_data *cam = video_drvdata(file); + + memset(parms, 0, sizeof(*parms)); + + parms->quality = 80; // TODO: Can this be made meaningful? + + parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; + if(!cam->params.compression.inhibit_htables) { + parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; + } + + parms->APPn = cam->APPn; + parms->APP_len = cam->APP_len; + if(cam->APP_len > 0) { + memcpy(parms->APP_data, cam->APP_data, cam->APP_len); + parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; + } + + parms->COM_len = cam->COM_len; + if(cam->COM_len > 0) { + memcpy(parms->COM_data, cam->COM_data, cam->COM_len); + parms->jpeg_markers |= JPEG_MARKER_COM; + } + + DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", + parms->APP_len, parms->COM_len); + + return 0; +} + +/****************************************************************************** + * + * ioctl_s_jpegcomp + * + * V4L2 set the JPEG compression parameters + * NOTE: quality and some jpeg_markers are ignored. + * + *****************************************************************************/ + +static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) +{ + struct camera_data *cam = video_drvdata(file); + + DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", + parms->APP_len, parms->COM_len); + + cam->params.compression.inhibit_htables = + !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); + + if(parms->APP_len != 0) { + if(parms->APP_len > 0 && + parms->APP_len <= sizeof(cam->APP_data) && + parms->APPn >= 0 && parms->APPn <= 15) { + cam->APPn = parms->APPn; + cam->APP_len = parms->APP_len; + memcpy(cam->APP_data, parms->APP_data, parms->APP_len); + } else { + LOG("Bad APPn Params n=%d len=%d\n", + parms->APPn, parms->APP_len); + return -EINVAL; + } + } else { + cam->APP_len = 0; + } + + if(parms->COM_len != 0) { + if(parms->COM_len > 0 && + parms->COM_len <= sizeof(cam->COM_data)) { + cam->COM_len = parms->COM_len; + memcpy(cam->COM_data, parms->COM_data, parms->COM_len); + } else { + LOG("Bad COM_len=%d\n", parms->COM_len); + return -EINVAL; + } + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_reqbufs + * + * V4L2 Initiate memory mapping. + * NOTE: The user's request is ignored. For now the buffers are fixed. + * + *****************************************************************************/ + +static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) +{ + struct camera_data *cam = video_drvdata(file); + + if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + req->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); + req->count = cam->num_frames; + memset(&req->reserved, 0, sizeof(req->reserved)); + + return 0; +} + +/****************************************************************************** + * + * ioctl_querybuf + * + * V4L2 Query memory buffer status. + * + *****************************************************************************/ + +static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + struct camera_data *cam = video_drvdata(file); + + if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + buf->index > cam->num_frames) + return -EINVAL; + + buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; + buf->length = cam->frame_size; + + buf->memory = V4L2_MEMORY_MMAP; + + if(cam->mmapped) + buf->flags = V4L2_BUF_FLAG_MAPPED; + else + buf->flags = 0; + + switch (cam->buffers[buf->index].status) { + case FRAME_EMPTY: + case FRAME_ERROR: + case FRAME_READING: + buf->bytesused = 0; + buf->flags = V4L2_BUF_FLAG_QUEUED; + break; + case FRAME_READY: + buf->bytesused = cam->buffers[buf->index].length; + buf->timestamp = cam->buffers[buf->index].timestamp; + buf->sequence = cam->buffers[buf->index].seq; + buf->flags = V4L2_BUF_FLAG_DONE; + break; + } + + DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", + buf->index, buf->m.offset, buf->flags, buf->sequence, + buf->bytesused); + + return 0; +} + +/****************************************************************************** + * + * ioctl_qbuf + * + * V4L2 User is freeing buffer + * + *****************************************************************************/ + +static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + struct camera_data *cam = video_drvdata(file); + + if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + buf->memory != V4L2_MEMORY_MMAP || + buf->index > cam->num_frames) + return -EINVAL; + + DBG("QBUF #%d\n", buf->index); + + if(cam->buffers[buf->index].status == FRAME_READY) + cam->buffers[buf->index].status = FRAME_EMPTY; + + return 0; +} + +/****************************************************************************** + * + * find_earliest_filled_buffer + * + * Helper for ioctl_dqbuf. Find the next ready buffer. + * + *****************************************************************************/ + +static int find_earliest_filled_buffer(struct camera_data *cam) +{ + int i; + int found = -1; + for (i=0; inum_frames; i++) { + if(cam->buffers[i].status == FRAME_READY) { + if(found < 0) { + found = i; + } else { + /* find which buffer is earlier */ + struct timeval *tv1, *tv2; + tv1 = &cam->buffers[i].timestamp; + tv2 = &cam->buffers[found].timestamp; + if(tv1->tv_sec < tv2->tv_sec || + (tv1->tv_sec == tv2->tv_sec && + tv1->tv_usec < tv2->tv_usec)) + found = i; + } + } + } + return found; +} + +/****************************************************************************** + * + * ioctl_dqbuf + * + * V4L2 User is asking for a filled buffer. + * + *****************************************************************************/ + +static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + struct camera_data *cam = video_drvdata(file); + int frame; + + if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + buf->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + frame = find_earliest_filled_buffer(cam); + + if(frame < 0 && file->f_flags&O_NONBLOCK) + return -EAGAIN; + + if(frame < 0) { + /* Wait for a frame to become available */ + struct framebuf *cb=cam->curbuff; + mutex_unlock(&cam->v4l2_lock); + wait_event_interruptible(cam->wq_stream, + !cam->present || + (cb=cam->curbuff)->status == FRAME_READY); + mutex_lock(&cam->v4l2_lock); + if (signal_pending(current)) + return -ERESTARTSYS; + if(!cam->present) + return -ENOTTY; + frame = cb->num; + } + + + buf->index = frame; + buf->bytesused = cam->buffers[buf->index].length; + buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; + buf->field = V4L2_FIELD_NONE; + buf->timestamp = cam->buffers[buf->index].timestamp; + buf->sequence = cam->buffers[buf->index].seq; + buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; + buf->length = cam->frame_size; + buf->input = 0; + buf->reserved = 0; + memset(&buf->timecode, 0, sizeof(buf->timecode)); + + DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, + cam->buffers[buf->index].status, buf->sequence, buf->bytesused); + + return 0; +} + +static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p) +{ + struct cpia2_fh *fh = _fh; + + *p = fh->prio; + return 0; +} + +static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio) +{ + struct camera_data *cam = video_drvdata(file); + struct cpia2_fh *fh = _fh; + + if (cam->streaming && prio != fh->prio && + fh->prio == V4L2_PRIORITY_RECORD) + /* Can't drop record priority while streaming */ + return -EBUSY; + + if (prio == V4L2_PRIORITY_RECORD && prio != fh->prio && + v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) + /* Only one program can record at a time */ + return -EBUSY; + return v4l2_prio_change(&cam->prio, &fh->prio, prio); +} + +static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct camera_data *cam = video_drvdata(file); + + DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); + if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (!cam->streaming) + return cpia2_usb_stream_start(cam, + cam->params.camera_state.stream_mode); + return -EINVAL; +} + +static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct camera_data *cam = video_drvdata(file); + + DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); + if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (cam->streaming) + return cpia2_usb_stream_stop(cam); + return -EINVAL; +} + +/****************************************************************************** + * + * cpia2_mmap + * + *****************************************************************************/ +static int cpia2_mmap(struct file *file, struct vm_area_struct *area) +{ + struct camera_data *cam = video_drvdata(file); + int retval; + + /* Priority check */ + struct cpia2_fh *fh = file->private_data; + if(fh->prio != V4L2_PRIORITY_RECORD) { + return -EBUSY; + } + + retval = cpia2_remap_buffer(cam, area); + + if(!retval) + fh->mmapped = 1; + return retval; +} + +/****************************************************************************** + * + * reset_camera_struct_v4l + * + * Sets all values to the defaults + *****************************************************************************/ +static void reset_camera_struct_v4l(struct camera_data *cam) +{ + cam->width = cam->params.roi.width; + cam->height = cam->params.roi.height; + + cam->frame_size = buffer_size; + cam->num_frames = num_buffers; + + /* FlickerModes */ + cam->params.flicker_control.flicker_mode_req = flicker_mode; + cam->params.flicker_control.mains_frequency = flicker_freq; + + /* streamMode */ + cam->params.camera_state.stream_mode = alternate; + + cam->pixelformat = V4L2_PIX_FMT_JPEG; + v4l2_prio_init(&cam->prio); +} + +static const struct v4l2_ioctl_ops cpia2_ioctl_ops = { + .vidioc_querycap = cpia2_querycap, + .vidioc_enum_input = cpia2_enum_input, + .vidioc_g_input = cpia2_g_input, + .vidioc_s_input = cpia2_s_input, + .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap, + .vidioc_queryctrl = cpia2_queryctrl, + .vidioc_querymenu = cpia2_querymenu, + .vidioc_g_ctrl = cpia2_g_ctrl, + .vidioc_s_ctrl = cpia2_s_ctrl, + .vidioc_g_jpegcomp = cpia2_g_jpegcomp, + .vidioc_s_jpegcomp = cpia2_s_jpegcomp, + .vidioc_cropcap = cpia2_cropcap, + .vidioc_reqbufs = cpia2_reqbufs, + .vidioc_querybuf = cpia2_querybuf, + .vidioc_qbuf = cpia2_qbuf, + .vidioc_dqbuf = cpia2_dqbuf, + .vidioc_streamon = cpia2_streamon, + .vidioc_streamoff = cpia2_streamoff, + .vidioc_g_priority = cpia2_g_priority, + .vidioc_s_priority = cpia2_s_priority, + .vidioc_default = cpia2_default, +}; + +/*** + * The v4l video device structure initialized for this device + ***/ +static const struct v4l2_file_operations cpia2_fops = { + .owner = THIS_MODULE, + .open = cpia2_open, + .release = cpia2_close, + .read = cpia2_v4l_read, + .poll = cpia2_v4l_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = cpia2_mmap, +}; + +static struct video_device cpia2_template = { + /* I could not find any place for the old .initialize initializer?? */ + .name = "CPiA2 Camera", + .fops = &cpia2_fops, + .ioctl_ops = &cpia2_ioctl_ops, + .release = video_device_release, +}; + +/****************************************************************************** + * + * cpia2_register_camera + * + *****************************************************************************/ +int cpia2_register_camera(struct camera_data *cam) +{ + cam->vdev = video_device_alloc(); + if(!cam->vdev) + return -ENOMEM; + + memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template)); + video_set_drvdata(cam->vdev, cam); + cam->vdev->lock = &cam->v4l2_lock; + + reset_camera_struct_v4l(cam); + + /* register v4l device */ + if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { + ERR("video_register_device failed\n"); + video_device_release(cam->vdev); + return -ENODEV; + } + + return 0; +} + +/****************************************************************************** + * + * cpia2_unregister_camera + * + *****************************************************************************/ +void cpia2_unregister_camera(struct camera_data *cam) +{ + if (!cam->open_count) { + video_unregister_device(cam->vdev); + } else { + LOG("%s removed while open, deferring " + "video_unregister_device\n", + video_device_node_name(cam->vdev)); + } +} + +/****************************************************************************** + * + * check_parameters + * + * Make sure that all user-supplied parameters are sensible + *****************************************************************************/ +static void __init check_parameters(void) +{ + if(buffer_size < PAGE_SIZE) { + buffer_size = PAGE_SIZE; + LOG("buffer_size too small, setting to %d\n", buffer_size); + } else if(buffer_size > 1024*1024) { + /* arbitrary upper limiit */ + buffer_size = 1024*1024; + LOG("buffer_size ridiculously large, setting to %d\n", + buffer_size); + } else { + buffer_size += PAGE_SIZE-1; + buffer_size &= ~(PAGE_SIZE-1); + } + + if(num_buffers < 1) { + num_buffers = 1; + LOG("num_buffers too small, setting to %d\n", num_buffers); + } else if(num_buffers > VIDEO_MAX_FRAME) { + num_buffers = VIDEO_MAX_FRAME; + LOG("num_buffers too large, setting to %d\n", num_buffers); + } + + if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { + alternate = DEFAULT_ALT; + LOG("alternate specified is invalid, using %d\n", alternate); + } + + if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) { + flicker_mode = NEVER_FLICKER; + LOG("Flicker mode specified is invalid, using %d\n", + flicker_mode); + } + + if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) { + flicker_freq = FLICKER_60; + LOG("Flicker mode specified is invalid, using %d\n", + flicker_freq); + } + + if(video_nr < -1 || video_nr > 64) { + video_nr = -1; + LOG("invalid video_nr specified, must be -1 to 64\n"); + } + + DBG("Using %d buffers, each %d bytes, alternate=%d\n", + num_buffers, buffer_size, alternate); +} + +/************ Module Stuff ***************/ + + +/****************************************************************************** + * + * cpia2_init/module_init + * + *****************************************************************************/ +static int __init cpia2_init(void) +{ + LOG("%s v%d.%d.%d\n", + ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); + check_parameters(); + cpia2_usb_init(); + return 0; +} + + +/****************************************************************************** + * + * cpia2_exit/module_exit + * + *****************************************************************************/ +static void __exit cpia2_exit(void) +{ + cpia2_usb_cleanup(); + schedule_timeout(2 * HZ); +} + +module_init(cpia2_init); +module_exit(cpia2_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,9 @@ +config VIDEO_CPIA2 + tristate "CPiA2 Video For Linux" + depends on VIDEO_DEV && USB && VIDEO_V4L2 + ---help--- + This is the video4linux driver for cameras based on Vision's CPiA2 + (Colour Processor Interface ASIC), such as the Digital Blue QX5 + Microscope. If you have one of these cameras, say Y here + + This driver is also available as a module (cpia2). diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cpia2/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3 @@ +cpia2-objs := cpia2_v4l.o cpia2_usb.o cpia2_core.o + +obj-$(CONFIG_VIDEO_CPIA2) += cpia2.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/c-qcam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/c-qcam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/c-qcam.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/c-qcam.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,891 @@ +/* + * Video4Linux Colour QuickCam driver + * Copyright 1997-2000 Philip Blundell + * + * Module parameters: + * + * parport=auto -- probe all parports (default) + * parport=0 -- parport0 becomes qcam1 + * parport=2,0,1 -- parports 2,0,1 are tried in that order + * + * probe=0 -- do no probing, assume camera is present + * probe=1 -- use IEEE-1284 autoprobe data only (default) + * probe=2 -- probe aggressively for cameras + * + * force_rgb=1 -- force data format to RGB (default is BGR) + * + * The parport parameter controls which parports will be scanned. + * Scanning all parports causes some printers to print a garbage page. + * -- March 14, 1999 Billy Donahue + * + * Fixed data format to BGR, added force_rgb parameter. Added missing + * parport_unregister_driver() on module removal. + * -- May 28, 2000 Claudio Matsuoka + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct qcam { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct pardevice *pdev; + struct parport *pport; + int width, height; + int ccd_width, ccd_height; + int mode; + int contrast, brightness, whitebal; + int top, left; + unsigned int bidirectional; + struct mutex lock; +}; + +/* cameras maximum */ +#define MAX_CAMS 4 + +/* The three possible QuickCam modes */ +#define QC_MILLIONS 0x18 +#define QC_BILLIONS 0x10 +#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */ + +/* The three possible decimations */ +#define QC_DECIMATION_1 0 +#define QC_DECIMATION_2 2 +#define QC_DECIMATION_4 4 + +#define BANNER "Colour QuickCam for Video4Linux v0.06" + +static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; +static int probe = 2; +static int force_rgb; +static int video_nr = -1; + +/* FIXME: parport=auto would never have worked, surely? --RR */ +MODULE_PARM_DESC(parport, "parport= for port detection method\n" + "probe=<0|1|2> for camera detection method\n" + "force_rgb=<0|1> for RGB data format (default BGR)"); +module_param_array(parport, int, NULL, 0); +module_param(probe, int, 0); +module_param(force_rgb, bool, 0); +module_param(video_nr, int, 0); + +static struct qcam *qcams[MAX_CAMS]; +static unsigned int num_cams; + +static inline void qcam_set_ack(struct qcam *qcam, unsigned int i) +{ + /* note: the QC specs refer to the PCAck pin by voltage, not + software level. PC ports have builtin inverters. */ + parport_frob_control(qcam->pport, 8, i ? 8 : 0); +} + +static inline unsigned int qcam_ready1(struct qcam *qcam) +{ + return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0; +} + +static inline unsigned int qcam_ready2(struct qcam *qcam) +{ + return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0; +} + +static unsigned int qcam_await_ready1(struct qcam *qcam, int value) +{ + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; + unsigned long oldjiffies = jiffies; + unsigned int i; + + for (oldjiffies = jiffies; + time_before(jiffies, oldjiffies + msecs_to_jiffies(40));) + if (qcam_ready1(qcam) == value) + return 0; + + /* If the camera didn't respond within 1/25 second, poll slowly + for a while. */ + for (i = 0; i < 50; i++) { + if (qcam_ready1(qcam) == value) + return 0; + msleep_interruptible(100); + } + + /* Probably somebody pulled the plug out. Not much we can do. */ + v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value, + parport_read_status(qcam->pport), + parport_read_control(qcam->pport)); + return 1; +} + +static unsigned int qcam_await_ready2(struct qcam *qcam, int value) +{ + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; + unsigned long oldjiffies = jiffies; + unsigned int i; + + for (oldjiffies = jiffies; + time_before(jiffies, oldjiffies + msecs_to_jiffies(40));) + if (qcam_ready2(qcam) == value) + return 0; + + /* If the camera didn't respond within 1/25 second, poll slowly + for a while. */ + for (i = 0; i < 50; i++) { + if (qcam_ready2(qcam) == value) + return 0; + msleep_interruptible(100); + } + + /* Probably somebody pulled the plug out. Not much we can do. */ + v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value, + parport_read_status(qcam->pport), + parport_read_control(qcam->pport), + parport_read_data(qcam->pport)); + return 1; +} + +static int qcam_read_data(struct qcam *qcam) +{ + unsigned int idata; + + qcam_set_ack(qcam, 0); + if (qcam_await_ready1(qcam, 1)) + return -1; + idata = parport_read_status(qcam->pport) & 0xf0; + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) + return -1; + idata |= parport_read_status(qcam->pport) >> 4; + return idata; +} + +static int qcam_write_data(struct qcam *qcam, unsigned int data) +{ + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; + unsigned int idata; + + parport_write_data(qcam->pport, data); + idata = qcam_read_data(qcam); + if (data != idata) { + v4l2_warn(v4l2_dev, "sent %x but received %x\n", data, + idata); + return 1; + } + return 0; +} + +static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data) +{ + if (qcam_write_data(qcam, cmd)) + return -1; + if (qcam_write_data(qcam, data)) + return -1; + return 0; +} + +static inline int qcam_get(struct qcam *qcam, unsigned int cmd) +{ + if (qcam_write_data(qcam, cmd)) + return -1; + return qcam_read_data(qcam); +} + +static int qc_detect(struct qcam *qcam) +{ + unsigned int stat, ostat, i, count = 0; + + /* The probe routine below is not very reliable. The IEEE-1284 + probe takes precedence. */ + /* XXX Currently parport provides no way to distinguish between + "the IEEE probe was not done" and "the probe was done, but + no device was found". Fix this one day. */ + if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA + && qcam->pport->probe_info[0].model + && !strcmp(qcam->pdev->port->probe_info[0].model, + "Color QuickCam 2.0")) { + printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n"); + return 1; + } + + if (probe < 2) + return 0; + + parport_write_control(qcam->pport, 0xc); + + /* look for a heartbeat */ + ostat = stat = parport_read_status(qcam->pport); + for (i = 0; i < 250; i++) { + mdelay(1); + stat = parport_read_status(qcam->pport); + if (ostat != stat) { + if (++count >= 3) + return 1; + ostat = stat; + } + } + + /* Reset the camera and try again */ + parport_write_control(qcam->pport, 0xc); + parport_write_control(qcam->pport, 0x8); + mdelay(1); + parport_write_control(qcam->pport, 0xc); + mdelay(1); + count = 0; + + ostat = stat = parport_read_status(qcam->pport); + for (i = 0; i < 250; i++) { + mdelay(1); + stat = parport_read_status(qcam->pport); + if (ostat != stat) { + if (++count >= 3) + return 1; + ostat = stat; + } + } + + /* no (or flatline) camera, give up */ + return 0; +} + +static void qc_reset(struct qcam *qcam) +{ + parport_write_control(qcam->pport, 0xc); + parport_write_control(qcam->pport, 0x8); + mdelay(1); + parport_write_control(qcam->pport, 0xc); + mdelay(1); +} + +/* Reset the QuickCam and program for brightness, contrast, + * white-balance, and resolution. */ + +static void qc_setup(struct qcam *qcam) +{ + qc_reset(qcam); + + /* Set the brightness. */ + qcam_set(qcam, 11, qcam->brightness); + + /* Set the height and width. These refer to the actual + CCD area *before* applying the selected decimation. */ + qcam_set(qcam, 17, qcam->ccd_height); + qcam_set(qcam, 19, qcam->ccd_width / 2); + + /* Set top and left. */ + qcam_set(qcam, 0xd, qcam->top); + qcam_set(qcam, 0xf, qcam->left); + + /* Set contrast and white balance. */ + qcam_set(qcam, 0x19, qcam->contrast); + qcam_set(qcam, 0x1f, qcam->whitebal); + + /* Set the speed. */ + qcam_set(qcam, 45, 2); +} + +/* Read some bytes from the camera and put them in the buffer. + nbytes should be a multiple of 3, because bidirectional mode gives + us three bytes at a time. */ + +static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes) +{ + unsigned int bytes = 0; + + qcam_set_ack(qcam, 0); + if (qcam->bidirectional) { + /* It's a bidirectional port */ + while (bytes < nbytes) { + unsigned int lo1, hi1, lo2, hi2; + unsigned char r, g, b; + + if (qcam_await_ready2(qcam, 1)) + return bytes; + lo1 = parport_read_data(qcam->pport) >> 1; + hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(qcam, 1); + if (qcam_await_ready2(qcam, 0)) + return bytes; + lo2 = parport_read_data(qcam->pport) >> 1; + hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(qcam, 0); + r = lo1 | ((hi1 & 1) << 7); + g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1); + b = lo2 | ((hi2 & 1) << 7); + if (force_rgb) { + buf[bytes++] = r; + buf[bytes++] = g; + buf[bytes++] = b; + } else { + buf[bytes++] = b; + buf[bytes++] = g; + buf[bytes++] = r; + } + } + } else { + /* It's a unidirectional port */ + int i = 0, n = bytes; + unsigned char rgb[3]; + + while (bytes < nbytes) { + unsigned int hi, lo; + + if (qcam_await_ready1(qcam, 1)) + return bytes; + hi = (parport_read_status(qcam->pport) & 0xf0); + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) + return bytes; + lo = (parport_read_status(qcam->pport) & 0xf0); + qcam_set_ack(qcam, 0); + /* flip some bits */ + rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; + if (i >= 2) { +get_fragment: + if (force_rgb) { + buf[n++] = rgb[0]; + buf[n++] = rgb[1]; + buf[n++] = rgb[2]; + } else { + buf[n++] = rgb[2]; + buf[n++] = rgb[1]; + buf[n++] = rgb[0]; + } + } + } + if (i) { + i = 0; + goto get_fragment; + } + } + return bytes; +} + +#define BUFSZ 150 + +static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len) +{ + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; + unsigned lines, pixelsperline, bitsperxfer; + unsigned int is_bi_dir = qcam->bidirectional; + size_t wantlen, outptr = 0; + char tmpbuf[BUFSZ]; + + if (!access_ok(VERIFY_WRITE, buf, len)) + return -EFAULT; + + /* Wait for camera to become ready */ + for (;;) { + int i = qcam_get(qcam, 41); + + if (i == -1) { + qc_setup(qcam); + return -EIO; + } + if ((i & 0x80) == 0) + break; + schedule(); + } + + if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1)) + return -EIO; + + lines = qcam->height; + pixelsperline = qcam->width; + bitsperxfer = (is_bi_dir) ? 24 : 8; + + if (is_bi_dir) { + /* Turn the port around */ + parport_data_reverse(qcam->pport); + mdelay(3); + qcam_set_ack(qcam, 0); + if (qcam_await_ready1(qcam, 1)) { + qc_setup(qcam); + return -EIO; + } + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) { + qc_setup(qcam); + return -EIO; + } + } + + wantlen = lines * pixelsperline * 24 / 8; + + while (wantlen) { + size_t t, s; + + s = (wantlen > BUFSZ) ? BUFSZ : wantlen; + t = qcam_read_bytes(qcam, tmpbuf, s); + if (outptr < len) { + size_t sz = len - outptr; + + if (sz > t) + sz = t; + if (__copy_to_user(buf + outptr, tmpbuf, sz)) + break; + outptr += sz; + } + wantlen -= t; + if (t < s) + break; + cond_resched(); + } + + len = outptr; + + if (wantlen) { + v4l2_err(v4l2_dev, "short read.\n"); + if (is_bi_dir) + parport_data_forward(qcam->pport); + qc_setup(qcam); + return len; + } + + if (is_bi_dir) { + int l; + + do { + l = qcam_read_bytes(qcam, tmpbuf, 3); + cond_resched(); + } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); + if (force_rgb) { + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + v4l2_err(v4l2_dev, "bad EOF\n"); + } else { + if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) + v4l2_err(v4l2_dev, "bad EOF\n"); + } + qcam_set_ack(qcam, 0); + if (qcam_await_ready1(qcam, 1)) { + v4l2_err(v4l2_dev, "no ack after EOF\n"); + parport_data_forward(qcam->pport); + qc_setup(qcam); + return len; + } + parport_data_forward(qcam->pport); + mdelay(3); + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) { + v4l2_err(v4l2_dev, "no ack to port turnaround\n"); + qc_setup(qcam); + return len; + } + } else { + int l; + + do { + l = qcam_read_bytes(qcam, tmpbuf, 1); + cond_resched(); + } while (l && tmpbuf[0] == 0x7e); + l = qcam_read_bytes(qcam, tmpbuf + 1, 2); + if (force_rgb) { + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + v4l2_err(v4l2_dev, "bad EOF\n"); + } else { + if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) + v4l2_err(v4l2_dev, "bad EOF\n"); + } + } + + qcam_write_data(qcam, 0); + return len; +} + +/* + * Video4linux interfacing + */ + +static int qcam_querycap(struct file *file, void *priv, + struct v4l2_capability *vcap) +{ + struct qcam *qcam = video_drvdata(file); + + strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); + strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card)); + strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); + vcap->version = KERNEL_VERSION(0, 0, 3); + vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + return 0; +} + +static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + if (vin->index > 0) + return -EINVAL; + strlcpy(vin->name, "Camera", sizeof(vin->name)); + vin->type = V4L2_INPUT_TYPE_CAMERA; + vin->audioset = 0; + vin->tuner = 0; + vin->std = 0; + vin->status = 0; + return 0; +} + +static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) +{ + *inp = 0; + return 0; +} + +static int qcam_s_input(struct file *file, void *fh, unsigned int inp) +{ + return (inp > 0) ? -EINVAL : 0; +} + +static int qcam_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240); + case V4L2_CID_CONTRAST: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192); + case V4L2_CID_GAMMA: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); + } + return -EINVAL; +} + +static int qcam_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = qcam->brightness; + break; + case V4L2_CID_CONTRAST: + ctrl->value = qcam->contrast; + break; + case V4L2_CID_GAMMA: + ctrl->value = qcam->whitebal; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int qcam_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + mutex_lock(&qcam->lock); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + qcam->brightness = ctrl->value; + break; + case V4L2_CID_CONTRAST: + qcam->contrast = ctrl->value; + break; + case V4L2_CID_GAMMA: + qcam->whitebal = ctrl->value; + break; + default: + ret = -EINVAL; + break; + } + if (ret == 0) { + parport_claim_or_block(qcam->pdev); + qc_setup(qcam); + parport_release(qcam->pdev); + } + mutex_unlock(&qcam->lock); + return ret; +} + +static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + pix->width = qcam->width; + pix->height = qcam->height; + pix->pixelformat = V4L2_PIX_FMT_RGB24; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = 3 * qcam->width; + pix->sizeimage = 3 * qcam->width * qcam->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + if (pix->height < 60 || pix->width < 80) { + pix->height = 60; + pix->width = 80; + } else if (pix->height < 120 || pix->width < 160) { + pix->height = 120; + pix->width = 160; + } else { + pix->height = 240; + pix->width = 320; + } + pix->pixelformat = V4L2_PIX_FMT_RGB24; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = 3 * pix->width; + pix->sizeimage = 3 * pix->width * pix->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + int ret = qcam_try_fmt_vid_cap(file, fh, fmt); + + if (ret) + return ret; + switch (pix->height) { + case 60: + qcam->mode = QC_DECIMATION_4; + break; + case 120: + qcam->mode = QC_DECIMATION_2; + break; + default: + qcam->mode = QC_DECIMATION_1; + break; + } + + mutex_lock(&qcam->lock); + qcam->mode |= QC_MILLIONS; + qcam->height = pix->height; + qcam->width = pix->width; + parport_claim_or_block(qcam->pdev); + qc_setup(qcam); + parport_release(qcam->pdev); + mutex_unlock(&qcam->lock); + return 0; +} + +static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) +{ + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "RGB 8:8:8", V4L2_PIX_FMT_RGB24, + { 0, 0, 0, 0 } + }, + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 0) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; +} + +static ssize_t qcam_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct qcam *qcam = video_drvdata(file); + int len; + + mutex_lock(&qcam->lock); + parport_claim_or_block(qcam->pdev); + /* Probably should have a semaphore against multiple users */ + len = qc_capture(qcam, buf, count); + parport_release(qcam->pdev); + mutex_unlock(&qcam->lock); + return len; +} + +static const struct v4l2_file_operations qcam_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .read = qcam_read, +}; + +static const struct v4l2_ioctl_ops qcam_ioctl_ops = { + .vidioc_querycap = qcam_querycap, + .vidioc_g_input = qcam_g_input, + .vidioc_s_input = qcam_s_input, + .vidioc_enum_input = qcam_enum_input, + .vidioc_queryctrl = qcam_queryctrl, + .vidioc_g_ctrl = qcam_g_ctrl, + .vidioc_s_ctrl = qcam_s_ctrl, + .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, +}; + +/* Initialize the QuickCam driver control structure. */ + +static struct qcam *qcam_init(struct parport *port) +{ + struct qcam *qcam; + struct v4l2_device *v4l2_dev; + + qcam = kzalloc(sizeof(*qcam), GFP_KERNEL); + if (qcam == NULL) + return NULL; + + v4l2_dev = &qcam->v4l2_dev; + strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name)); + + if (v4l2_device_register(NULL, v4l2_dev) < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return NULL; + } + + qcam->pport = port; + qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL, + NULL, 0, NULL); + + qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; + + if (qcam->pdev == NULL) { + v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); + kfree(qcam); + return NULL; + } + + strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name)); + qcam->vdev.v4l2_dev = v4l2_dev; + qcam->vdev.fops = &qcam_fops; + qcam->vdev.ioctl_ops = &qcam_ioctl_ops; + qcam->vdev.release = video_device_release_empty; + video_set_drvdata(&qcam->vdev, qcam); + + mutex_init(&qcam->lock); + qcam->width = qcam->ccd_width = 320; + qcam->height = qcam->ccd_height = 240; + qcam->mode = QC_MILLIONS | QC_DECIMATION_1; + qcam->contrast = 192; + qcam->brightness = 240; + qcam->whitebal = 128; + qcam->top = 1; + qcam->left = 14; + return qcam; +} + +static int init_cqcam(struct parport *port) +{ + struct qcam *qcam; + struct v4l2_device *v4l2_dev; + + if (parport[0] != -1) { + /* The user gave specific instructions */ + int i, found = 0; + + for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) { + if (parport[0] == port->number) + found = 1; + } + if (!found) + return -ENODEV; + } + + if (num_cams == MAX_CAMS) + return -ENOSPC; + + qcam = qcam_init(port); + if (qcam == NULL) + return -ENODEV; + + v4l2_dev = &qcam->v4l2_dev; + + parport_claim_or_block(qcam->pdev); + + qc_reset(qcam); + + if (probe && qc_detect(qcam) == 0) { + parport_release(qcam->pdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + + qc_setup(qcam); + + parport_release(qcam->pdev); + + if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { + v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n", + qcam->pport->name); + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + + v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n", + video_device_node_name(&qcam->vdev), qcam->pport->name); + + qcams[num_cams++] = qcam; + + return 0; +} + +static void close_cqcam(struct qcam *qcam) +{ + video_unregister_device(&qcam->vdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); +} + +static void cq_attach(struct parport *port) +{ + init_cqcam(port); +} + +static void cq_detach(struct parport *port) +{ + /* Write this some day. */ +} + +static struct parport_driver cqcam_driver = { + .name = "cqcam", + .attach = cq_attach, + .detach = cq_detach, +}; + +static int __init cqcam_init(void) +{ + printk(KERN_INFO BANNER "\n"); + + return parport_register_driver(&cqcam_driver); +} + +static void __exit cqcam_cleanup(void) +{ + unsigned int i; + + for (i = 0; i < num_cams; i++) + close_cqcam(qcams[i]); + + parport_unregister_driver(&cqcam_driver); +} + +MODULE_AUTHOR("Philip Blundell "); +MODULE_DESCRIPTION(BANNER); +MODULE_LICENSE("GPL"); + +module_init(cqcam_init); +module_exit(cqcam_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs5345.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs5345.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs5345.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs5345.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,263 @@ +/* + * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static int debug; + +module_param(debug, bool, 0644); + +MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On"); + +struct cs5345_state { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; +}; + +static inline struct cs5345_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct cs5345_state, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct cs5345_state, hdl)->sd; +} + +/* ----------------------------------------------------------------------- */ + +static inline int cs5345_write(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +static inline int cs5345_read(struct v4l2_subdev *sd, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_read_byte_data(client, reg); +} + +static int cs5345_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + if ((input & 0xf) > 6) { + v4l2_err(sd, "Invalid input %d.\n", input); + return -EINVAL; + } + cs5345_write(sd, 0x09, input & 0xf); + cs5345_write(sd, 0x05, input & 0xf0); + return 0; +} + +static int cs5345_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + cs5345_write(sd, 0x04, ctrl->val ? 0x80 : 0); + return 0; + case V4L2_CID_AUDIO_VOLUME: + cs5345_write(sd, 0x07, ((u8)ctrl->val) & 0x3f); + cs5345_write(sd, 0x08, ((u8)ctrl->val) & 0x3f); + return 0; + } + return -EINVAL; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + reg->size = 1; + reg->val = cs5345_read(sd, reg->reg & 0x1f); + return 0; +} + +static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + cs5345_write(sd, reg->reg & 0x1f, reg->val & 0xff); + return 0; +} +#endif + +static int cs5345_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_CS5345, 0); +} + +static int cs5345_log_status(struct v4l2_subdev *sd) +{ + u8 v = cs5345_read(sd, 0x09) & 7; + u8 m = cs5345_read(sd, 0x04); + int vol = cs5345_read(sd, 0x08) & 0x3f; + + v4l2_info(sd, "Input: %d%s\n", v, + (m & 0x80) ? " (muted)" : ""); + if (vol >= 32) + vol = vol - 64; + v4l2_info(sd, "Volume: %d dB\n", vol); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_ctrl_ops cs5345_ctrl_ops = { + .s_ctrl = cs5345_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops cs5345_core_ops = { + .log_status = cs5345_log_status, + .g_chip_ident = cs5345_g_chip_ident, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = cs5345_g_register, + .s_register = cs5345_s_register, +#endif +}; + +static const struct v4l2_subdev_audio_ops cs5345_audio_ops = { + .s_routing = cs5345_s_routing, +}; + +static const struct v4l2_subdev_ops cs5345_ops = { + .core = &cs5345_core_ops, + .audio = &cs5345_audio_ops, +}; + +/* ----------------------------------------------------------------------- */ + +static int cs5345_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cs5345_state *state; + struct v4l2_subdev *sd; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kzalloc(sizeof(struct cs5345_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &cs5345_ops); + + v4l2_ctrl_handler_init(&state->hdl, 2); + v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, -24, 24, 1, 0); + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + /* set volume/mute */ + v4l2_ctrl_handler_setup(&state->hdl); + + cs5345_write(sd, 0x02, 0x00); + cs5345_write(sd, 0x04, 0x01); + cs5345_write(sd, 0x09, 0x01); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int cs5345_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct cs5345_state *state = to_state(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id cs5345_id[] = { + { "cs5345", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs5345_id); + +static struct i2c_driver cs5345_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "cs5345", + }, + .probe = cs5345_probe, + .remove = cs5345_remove, + .id_table = cs5345_id, +}; + +static __init int init_cs5345(void) +{ + return i2c_add_driver(&cs5345_driver); +} + +static __exit void exit_cs5345(void) +{ + i2c_del_driver(&cs5345_driver); +} + +module_init(init_cs5345); +module_exit(exit_cs5345); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs53l32a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs53l32a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs53l32a.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs53l32a.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,262 @@ +/* + * cs53l32a (Adaptec AVC-2010 and AVC-2410) i2c ivtv driver. + * Copyright (C) 2005 Martin Vaughan + * + * Audio source switching for Adaptec AVC-2410 added by Trev Jackson + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); +MODULE_AUTHOR("Martin Vaughan"); +MODULE_LICENSE("GPL"); + +static int debug; + +module_param(debug, bool, 0644); + +MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On"); + + +struct cs53l32a_state { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; +}; + +static inline struct cs53l32a_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct cs53l32a_state, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct cs53l32a_state, hdl)->sd; +} + +/* ----------------------------------------------------------------------- */ + +static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_read_byte_data(client, reg); +} + +static int cs53l32a_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + /* There are 2 physical inputs, but the second input can be + placed in two modes, the first mode bypasses the PGA (gain), + the second goes through the PGA. Hence there are three + possible inputs to choose from. */ + if (input > 2) { + v4l2_err(sd, "Invalid input %d.\n", input); + return -EINVAL; + } + cs53l32a_write(sd, 0x01, 0x01 + (input << 4)); + return 0; +} + +static int cs53l32a_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + cs53l32a_write(sd, 0x03, ctrl->val ? 0xf0 : 0x30); + return 0; + case V4L2_CID_AUDIO_VOLUME: + cs53l32a_write(sd, 0x04, (u8)ctrl->val); + cs53l32a_write(sd, 0x05, (u8)ctrl->val); + return 0; + } + return -EINVAL; +} + +static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, + chip, V4L2_IDENT_CS53l32A, 0); +} + +static int cs53l32a_log_status(struct v4l2_subdev *sd) +{ + struct cs53l32a_state *state = to_state(sd); + u8 v = cs53l32a_read(sd, 0x01); + + v4l2_info(sd, "Input: %d\n", (v >> 4) & 3); + v4l2_ctrl_handler_log_status(&state->hdl, sd->name); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_ctrl_ops cs53l32a_ctrl_ops = { + .s_ctrl = cs53l32a_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops cs53l32a_core_ops = { + .log_status = cs53l32a_log_status, + .g_chip_ident = cs53l32a_g_chip_ident, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, +}; + +static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = { + .s_routing = cs53l32a_s_routing, +}; + +static const struct v4l2_subdev_ops cs53l32a_ops = { + .core = &cs53l32a_core_ops, + .audio = &cs53l32a_audio_ops, +}; + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static int cs53l32a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cs53l32a_state *state; + struct v4l2_subdev *sd; + int i; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + if (!id) + strlcpy(client->name, "cs53l32a", sizeof(client->name)); + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kzalloc(sizeof(struct cs53l32a_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops); + + for (i = 1; i <= 7; i++) { + u8 v = cs53l32a_read(sd, i); + + v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v); + } + + v4l2_ctrl_handler_init(&state->hdl, 2); + v4l2_ctrl_new_std(&state->hdl, &cs53l32a_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, -96, 12, 1, 0); + v4l2_ctrl_new_std(&state->hdl, &cs53l32a_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + + /* Set cs53l32a internal register for Adaptec 2010/2410 setup */ + + cs53l32a_write(sd, 0x01, 0x21); + cs53l32a_write(sd, 0x02, 0x29); + cs53l32a_write(sd, 0x03, 0x30); + cs53l32a_write(sd, 0x04, 0x00); + cs53l32a_write(sd, 0x05, 0x00); + cs53l32a_write(sd, 0x06, 0x00); + cs53l32a_write(sd, 0x07, 0x00); + + /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */ + + for (i = 1; i <= 7; i++) { + u8 v = cs53l32a_read(sd, i); + + v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v); + } + return 0; +} + +static int cs53l32a_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct cs53l32a_state *state = to_state(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return 0; +} + +static const struct i2c_device_id cs53l32a_id[] = { + { "cs53l32a", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs53l32a_id); + +static struct i2c_driver cs53l32a_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "cs53l32a", + }, + .probe = cs53l32a_probe, + .remove = cs53l32a_remove, + .id_table = cs53l32a_id, +}; + +static __init int init_cs53l32a(void) +{ + return i2c_add_driver(&cs53l32a_driver); +} + +static __exit void exit_cs53l32a(void) +{ + i2c_del_driver(&cs53l32a_driver); +} + +module_init(init_cs53l32a); +module_exit(exit_cs53l32a); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs8420.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs8420.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs8420.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cs8420.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,50 @@ +/* cs8420.h - cs8420 initializations + Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ +#ifndef __CS8420_H__ +#define __CS8420_H__ + +/* Initialization Sequence */ + +static __u8 init8420[] = { + 1, 0x01, 2, 0x02, 3, 0x00, 4, 0x46, + 5, 0x24, 6, 0x84, 18, 0x18, 19, 0x13, +}; + +#define INIT8420LEN (sizeof(init8420)/2) + +static __u8 mode8420pro[] = { /* professional output mode */ + 32, 0xa1, 33, 0x00, 34, 0x00, 35, 0x00, + 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, + 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, + 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, + 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, + 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, +}; +#define MODE8420LEN (sizeof(mode8420pro)/2) + +static __u8 mode8420con[] = { /* consumer output mode */ + 32, 0x20, 33, 0x00, 34, 0x00, 35, 0x48, + 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, + 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, + 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, + 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, + 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * ALSA interface to cx18 PCM capture streams + * + * Copyright (C) 2009 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +struct snd_card; + +struct snd_cx18_card { + struct v4l2_device *v4l2_dev; + struct snd_card *sc; + unsigned int capture_transfer_done; + unsigned int hwptr_done_capture; + struct snd_pcm_substream *capture_pcm_substream; + spinlock_t slock; +}; + +extern int cx18_alsa_debug; + +/* + * File operations that manipulate the encoder or video or audio subdevices + * need to be serialized. Use the same lock we use for v4l2 file ops. + */ +static inline void snd_cx18_lock(struct snd_cx18_card *cxsc) +{ + struct cx18 *cx = to_cx18(cxsc->v4l2_dev); + mutex_lock(&cx->serialize_lock); +} + +static inline void snd_cx18_unlock(struct snd_cx18_card *cxsc) +{ + struct cx18 *cx = to_cx18(cxsc->v4l2_dev); + mutex_unlock(&cx->serialize_lock); +} + +#define CX18_ALSA_DBGFLG_WARN (1 << 0) +#define CX18_ALSA_DBGFLG_WARN (1 << 0) +#define CX18_ALSA_DBGFLG_INFO (1 << 1) + +#define CX18_ALSA_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & cx18_alsa_debug) \ + printk(KERN_INFO "%s-alsa: " type ": " fmt, \ + v4l2_dev->name , ## args); \ + } while (0) + +#define CX18_ALSA_DEBUG_WARN(fmt, args...) \ + CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_WARN, "warning", fmt , ## args) + +#define CX18_ALSA_DEBUG_INFO(fmt, args...) \ + CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_INFO, "info", fmt , ## args) + +#define CX18_ALSA_ERR(fmt, args...) \ + printk(KERN_ERR "%s-alsa: " fmt, v4l2_dev->name , ## args) + +#define CX18_ALSA_WARN(fmt, args...) \ + printk(KERN_WARNING "%s-alsa: " fmt, v4l2_dev->name , ## args) + +#define CX18_ALSA_INFO(fmt, args...) \ + printk(KERN_INFO "%s-alsa: " fmt, v4l2_dev->name , ## args) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-main.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-main.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-main.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-main.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,294 @@ +/* + * ALSA interface to cx18 PCM capture streams + * + * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Devin Heitmueller + * + * Portions of this work were sponsored by ONELAN Limited. + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "cx18-driver.h" +#include "cx18-version.h" +#include "cx18-alsa.h" +#include "cx18-alsa-mixer.h" +#include "cx18-alsa-pcm.h" + +int cx18_alsa_debug; + +#define CX18_DEBUG_ALSA_INFO(fmt, arg...) \ + do { \ + if (cx18_alsa_debug & 2) \ + printk(KERN_INFO "%s: " fmt, "cx18-alsa", ## arg); \ + } while (0); + +module_param_named(debug, cx18_alsa_debug, int, 0644); +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n"); + +MODULE_AUTHOR("Andy Walls"); +MODULE_DESCRIPTION("CX23418 ALSA Interface"); +MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); +MODULE_LICENSE("GPL"); + + +static inline +struct snd_cx18_card *to_snd_cx18_card(struct v4l2_device *v4l2_dev) +{ + return to_cx18(v4l2_dev)->alsa; +} + +static inline +struct snd_cx18_card *p_to_snd_cx18_card(struct v4l2_device **v4l2_dev) +{ + return container_of(v4l2_dev, struct snd_cx18_card, v4l2_dev); +} + +static void snd_cx18_card_free(struct snd_cx18_card *cxsc) +{ + if (cxsc == NULL) + return; + + if (cxsc->v4l2_dev != NULL) + to_cx18(cxsc->v4l2_dev)->alsa = NULL; + + /* FIXME - take any other stopping actions needed */ + + kfree(cxsc); +} + +static void snd_cx18_card_private_free(struct snd_card *sc) +{ + if (sc == NULL) + return; + snd_cx18_card_free(sc->private_data); + sc->private_data = NULL; + sc->private_free = NULL; +} + +static int snd_cx18_card_create(struct v4l2_device *v4l2_dev, + struct snd_card *sc, + struct snd_cx18_card **cxsc) +{ + *cxsc = kzalloc(sizeof(struct snd_cx18_card), GFP_KERNEL); + if (*cxsc == NULL) + return -ENOMEM; + + (*cxsc)->v4l2_dev = v4l2_dev; + (*cxsc)->sc = sc; + + sc->private_data = *cxsc; + sc->private_free = snd_cx18_card_private_free; + + return 0; +} + +static int snd_cx18_card_set_names(struct snd_cx18_card *cxsc) +{ + struct cx18 *cx = to_cx18(cxsc->v4l2_dev); + struct snd_card *sc = cxsc->sc; + + /* sc->driver is used by alsa-lib's configurator: simple, unique */ + strlcpy(sc->driver, "CX23418", sizeof(sc->driver)); + + /* sc->shortname is a symlink in /proc/asound: CX18-M -> cardN */ + snprintf(sc->shortname, sizeof(sc->shortname), "CX18-%d", + cx->instance); + + /* sc->longname is read from /proc/asound/cards */ + snprintf(sc->longname, sizeof(sc->longname), + "CX23418 #%d %s TV/FM Radio/Line-In Capture", + cx->instance, cx->card_name); + + return 0; +} + +static int snd_cx18_init(struct v4l2_device *v4l2_dev) +{ + struct cx18 *cx = to_cx18(v4l2_dev); + struct snd_card *sc = NULL; + struct snd_cx18_card *cxsc; + int ret; + + /* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */ + + /* (1) Check and increment the device index */ + /* This is a no-op for us. We'll use the cx->instance */ + + /* (2) Create a card instance */ + ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */ + SNDRV_DEFAULT_STR1, /* xid from end of shortname*/ + THIS_MODULE, 0, &sc); + if (ret) { + CX18_ALSA_ERR("%s: snd_card_create() failed with err %d\n", + __func__, ret); + goto err_exit; + } + + /* (3) Create a main component */ + ret = snd_cx18_card_create(v4l2_dev, sc, &cxsc); + if (ret) { + CX18_ALSA_ERR("%s: snd_cx18_card_create() failed with err %d\n", + __func__, ret); + goto err_exit_free; + } + + /* (4) Set the driver ID and name strings */ + snd_cx18_card_set_names(cxsc); + + + ret = snd_cx18_pcm_create(cxsc); + if (ret) { + CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n", + __func__, ret); + goto err_exit_free; + } + /* FIXME - proc files */ + + /* (7) Set the driver data and return 0 */ + /* We do this out of normal order for PCI drivers to avoid races */ + cx->alsa = cxsc; + + /* (6) Register the card instance */ + ret = snd_card_register(sc); + if (ret) { + cx->alsa = NULL; + CX18_ALSA_ERR("%s: snd_card_register() failed with err %d\n", + __func__, ret); + goto err_exit_free; + } + + return 0; + +err_exit_free: + if (sc != NULL) + snd_card_free(sc); + kfree(cxsc); +err_exit: + return ret; +} + +int cx18_alsa_load(struct cx18 *cx) +{ + struct v4l2_device *v4l2_dev = &cx->v4l2_dev; + struct cx18_stream *s; + + if (v4l2_dev == NULL) { + printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n", + __func__); + return 0; + } + + cx = to_cx18(v4l2_dev); + if (cx == NULL) { + printk(KERN_ERR "cx18-alsa cx is NULL\n"); + return 0; + } + + s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; + if (s->video_dev == NULL) { + CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - " + "skipping\n", __func__); + return 0; + } + + if (cx->alsa != NULL) { + CX18_ALSA_ERR("%s: struct snd_cx18_card * already exists\n", + __func__); + return 0; + } + + if (snd_cx18_init(v4l2_dev)) { + CX18_ALSA_ERR("%s: failed to create struct snd_cx18_card\n", + __func__); + } else { + CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance " + "\n", __func__); + } + return 0; +} + +static int __init cx18_alsa_init(void) +{ + printk(KERN_INFO "cx18-alsa: module loading...\n"); + cx18_ext_init = &cx18_alsa_load; + return 0; +} + +static void __exit snd_cx18_exit(struct snd_cx18_card *cxsc) +{ + struct cx18 *cx = to_cx18(cxsc->v4l2_dev); + + /* FIXME - pointer checks & shutdown cxsc */ + + snd_card_free(cxsc->sc); + cx->alsa = NULL; +} + +static int __exit cx18_alsa_exit_callback(struct device *dev, void *data) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + struct snd_cx18_card *cxsc; + + if (v4l2_dev == NULL) { + printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n", + __func__); + return 0; + } + + cxsc = to_snd_cx18_card(v4l2_dev); + if (cxsc == NULL) { + CX18_ALSA_WARN("%s: struct snd_cx18_card * is NULL\n", + __func__); + return 0; + } + + snd_cx18_exit(cxsc); + return 0; +} + +static void __exit cx18_alsa_exit(void) +{ + struct device_driver *drv; + int ret; + + printk(KERN_INFO "cx18-alsa: module unloading...\n"); + + drv = driver_find("cx18", &pci_bus_type); + ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback); + put_driver(drv); + + cx18_ext_init = NULL; + printk(KERN_INFO "cx18-alsa: module unload complete\n"); +} + +module_init(cx18_alsa_init); +module_exit(cx18_alsa_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-mixer.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-mixer.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-mixer.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-mixer.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * ALSA mixer controls for the + * ALSA interface to cx18 PCM capture streams + * + * Copyright (C) 2009 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "cx18-alsa.h" +#include "cx18-driver.h" + +/* + * Note the cx18-av-core volume scale is funny, due to the alignment of the + * scale with another chip's range: + * + * v4l2_control value /512 indicated dB actual dB reg 0x8d4 + * 0x0000 - 0x01ff 0 -119 -96 228 + * 0x0200 - 0x02ff 1 -118 -96 228 + * ... + * 0x2c00 - 0x2dff 22 -97 -96 228 + * 0x2e00 - 0x2fff 23 -96 -96 228 + * 0x3000 - 0x31ff 24 -95 -95 226 + * ... + * 0xee00 - 0xefff 119 0 0 36 + * ... + * 0xfe00 - 0xffff 127 +8 +8 20 + */ +static inline int dB_to_cx18_av_vol(int dB) +{ + if (dB < -96) + dB = -96; + else if (dB > 8) + dB = 8; + return (dB + 119) << 9; +} + +static inline int cx18_av_vol_to_dB(int v) +{ + if (v < (23 << 9)) + v = (23 << 9); + else if (v > (127 << 9)) + v = (127 << 9); + return (v >> 9) - 119; +} + +static int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + /* We're already translating values, just keep this control in dB */ + uinfo->value.integer.min = -96; + uinfo->value.integer.max = 8; + uinfo->value.integer.step = 1; + return 0; +} + +static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl) +{ + struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); + struct cx18 *cx = to_cx18(cxsc->v4l2_dev); + struct v4l2_control vctrl; + int ret; + + vctrl.id = V4L2_CID_AUDIO_VOLUME; + vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); + + snd_cx18_lock(cxsc); + ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl); + snd_cx18_unlock(cxsc); + + if (!ret) + uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value); + return ret; +} + +static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl) +{ + struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); + struct cx18 *cx = to_cx18(cxsc->v4l2_dev); + struct v4l2_control vctrl; + int ret; + + vctrl.id = V4L2_CID_AUDIO_VOLUME; + vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); + + snd_cx18_lock(cxsc); + + /* Fetch current state */ + ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl); + + if (ret || + (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { + + /* Set, if needed */ + vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); + ret = v4l2_subdev_call(cx->sd_av, core, s_ctrl, &vctrl); + if (!ret) + ret = 1; /* Indicate control was changed w/o error */ + } + snd_cx18_unlock(cxsc); + + return ret; +} + + +/* This is a bit of overkill, the slider is already in dB internally */ +static DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0); + +static struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog TV Capture Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = snd_cx18_mixer_tv_volume_info, + .get = snd_cx18_mixer_tv_volume_get, + .put = snd_cx18_mixer_tv_volume_put, + .tlv.p = snd_cx18_mixer_tv_vol_db_scale +}; + +/* FIXME - add mute switch and balance, bass, treble sliders: + V4L2_CID_AUDIO_MUTE + + V4L2_CID_AUDIO_BALANCE + + V4L2_CID_AUDIO_BASS + V4L2_CID_AUDIO_TREBLE +*/ + +/* FIXME - add stereo, lang1, lang2, mono menu */ +/* FIXME - add CS5345 I2S volume for HVR-1600 */ + +int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc) +{ + struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; + struct snd_card *sc = cxsc->sc; + int ret; + + strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername)); + + ret = snd_ctl_add(sc, snd_ctl_new1(snd_cx18_mixer_tv_vol, cxsc)); + if (ret) { + CX18_ALSA_WARN("%s: failed to add %s control, err %d\n", + __func__, snd_cx18_mixer_tv_vol.name, ret); + } + return ret; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-mixer.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-mixer.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-mixer.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-mixer.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * ALSA mixer controls for the + * ALSA interface to cx18 PCM capture streams + * + * Copyright (C) 2009 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-pcm.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-pcm.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-pcm.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-pcm.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,360 @@ +/* + * ALSA PCM device for the + * ALSA interface to cx18 PCM capture streams + * + * Copyright (C) 2009 Andy Walls + * Copyright (C) 2009 Devin Heitmueller + * + * Portions of this work were sponsored by ONELAN Limited. + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include + +#include + +#include +#include + +#include "cx18-driver.h" +#include "cx18-queue.h" +#include "cx18-streams.h" +#include "cx18-fileops.h" +#include "cx18-alsa.h" + +static unsigned int pcm_debug; +module_param(pcm_debug, int, 0644); +MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); + +#define dprintk(fmt, arg...) do { \ + if (pcm_debug) \ + printk(KERN_INFO "cx18-alsa-pcm %s: " fmt, \ + __func__, ##arg); \ + } while (0) + +static struct snd_pcm_hardware snd_cx18_hw_capture = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_48000, + + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ + .period_bytes_min = 64, /* 12544/2, */ + .period_bytes_max = 12544, + .periods_min = 2, + .periods_max = 98, /* 12544, */ +}; + +void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data, + size_t num_bytes) +{ + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + unsigned int oldptr; + unsigned int stride; + int period_elapsed = 0; + int length; + + dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc, + pcm_data, num_bytes); + + substream = cxsc->capture_pcm_substream; + if (substream == NULL) { + dprintk("substream was NULL\n"); + return; + } + + runtime = substream->runtime; + if (runtime == NULL) { + dprintk("runtime was NULL\n"); + return; + } + + stride = runtime->frame_bits >> 3; + if (stride == 0) { + dprintk("stride is zero\n"); + return; + } + + length = num_bytes / stride; + if (length == 0) { + dprintk("%s: length was zero\n", __func__); + return; + } + + if (runtime->dma_area == NULL) { + dprintk("dma area was NULL - ignoring\n"); + return; + } + + oldptr = cxsc->hwptr_done_capture; + if (oldptr + length >= runtime->buffer_size) { + unsigned int cnt = + runtime->buffer_size - oldptr; + memcpy(runtime->dma_area + oldptr * stride, pcm_data, + cnt * stride); + memcpy(runtime->dma_area, pcm_data + cnt * stride, + length * stride - cnt * stride); + } else { + memcpy(runtime->dma_area + oldptr * stride, pcm_data, + length * stride); + } + snd_pcm_stream_lock(substream); + + cxsc->hwptr_done_capture += length; + if (cxsc->hwptr_done_capture >= + runtime->buffer_size) + cxsc->hwptr_done_capture -= + runtime->buffer_size; + + cxsc->capture_transfer_done += length; + if (cxsc->capture_transfer_done >= + runtime->period_size) { + cxsc->capture_transfer_done -= + runtime->period_size; + period_elapsed = 1; + } + + snd_pcm_stream_unlock(substream); + + if (period_elapsed) + snd_pcm_period_elapsed(substream); +} + +static int snd_cx18_pcm_capture_open(struct snd_pcm_substream *substream) +{ + struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; + struct cx18 *cx = to_cx18(v4l2_dev); + struct cx18_stream *s; + struct cx18_open_id item; + int ret; + + /* Instruct the cx18 to start sending packets */ + snd_cx18_lock(cxsc); + s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; + + item.cx = cx; + item.type = s->type; + item.open_id = cx->open_id++; + + /* See if the stream is available */ + if (cx18_claim_stream(&item, item.type)) { + /* No, it's already in use */ + snd_cx18_unlock(cxsc); + return -EBUSY; + } + + if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || + test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { + /* We're already streaming. No additional action required */ + snd_cx18_unlock(cxsc); + return 0; + } + + + runtime->hw = snd_cx18_hw_capture; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + cxsc->capture_pcm_substream = substream; + runtime->private_data = cx; + + cx->pcm_announce_callback = cx18_alsa_announce_pcm_data; + + /* Not currently streaming, so start it up */ + set_bit(CX18_F_S_STREAMING, &s->s_flags); + ret = cx18_start_v4l2_encode_stream(s); + snd_cx18_unlock(cxsc); + + return 0; +} + +static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream) +{ + struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); + struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; + struct cx18 *cx = to_cx18(v4l2_dev); + struct cx18_stream *s; + int ret; + + /* Instruct the cx18 to stop sending packets */ + snd_cx18_lock(cxsc); + s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; + ret = cx18_stop_v4l2_encode_stream(s, 0); + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + + cx18_release_stream(s); + + cx->pcm_announce_callback = NULL; + snd_cx18_unlock(cxsc); + + return 0; +} + +static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); + int ret; + + snd_cx18_lock(cxsc); + ret = snd_pcm_lib_ioctl(substream, cmd, arg); + snd_cx18_unlock(cxsc); + return ret; +} + + +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + dprintk("Allocating vbuffer\n"); + if (runtime->dma_area) { + if (runtime->dma_bytes > size) + return 0; + + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc(size); + if (!runtime->dma_area) + return -ENOMEM; + + runtime->dma_bytes = size; + + return 0; +} + +static int snd_cx18_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int ret; + + dprintk("%s called\n", __func__); + + ret = snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(params)); + return 0; +} + +static int snd_cx18_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); + unsigned long flags; + + spin_lock_irqsave(&cxsc->slock, flags); + if (substream->runtime->dma_area) { + dprintk("freeing pcm capture region\n"); + vfree(substream->runtime->dma_area); + substream->runtime->dma_area = NULL; + } + spin_unlock_irqrestore(&cxsc->slock, flags); + + return 0; +} + +static int snd_cx18_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); + + cxsc->hwptr_done_capture = 0; + cxsc->capture_transfer_done = 0; + + return 0; +} + +static int snd_cx18_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + return 0; +} + +static +snd_pcm_uframes_t snd_cx18_pcm_pointer(struct snd_pcm_substream *substream) +{ + unsigned long flags; + snd_pcm_uframes_t hwptr_done; + struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); + + spin_lock_irqsave(&cxsc->slock, flags); + hwptr_done = cxsc->hwptr_done_capture; + spin_unlock_irqrestore(&cxsc->slock, flags); + + return hwptr_done; +} + +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + + return vmalloc_to_page(pageptr); +} + +static struct snd_pcm_ops snd_cx18_pcm_capture_ops = { + .open = snd_cx18_pcm_capture_open, + .close = snd_cx18_pcm_capture_close, + .ioctl = snd_cx18_pcm_ioctl, + .hw_params = snd_cx18_pcm_hw_params, + .hw_free = snd_cx18_pcm_hw_free, + .prepare = snd_cx18_pcm_prepare, + .trigger = snd_cx18_pcm_trigger, + .pointer = snd_cx18_pcm_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +int snd_cx18_pcm_create(struct snd_cx18_card *cxsc) +{ + struct snd_pcm *sp; + struct snd_card *sc = cxsc->sc; + struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; + struct cx18 *cx = to_cx18(v4l2_dev); + int ret; + + ret = snd_pcm_new(sc, "CX23418 PCM", + 0, /* PCM device 0, the only one for this card */ + 0, /* 0 playback substreams */ + 1, /* 1 capture substream */ + &sp); + if (ret) { + CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n", + __func__, ret); + goto err_exit; + } + + spin_lock_init(&cxsc->slock); + + snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE, + &snd_cx18_pcm_capture_ops); + sp->info_flags = 0; + sp->private_data = cxsc; + strlcpy(sp->name, cx->card_name, sizeof(sp->name)); + + return 0; + +err_exit: + return ret; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-pcm.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-pcm.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-pcm.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-alsa-pcm.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * ALSA PCM device for the + * ALSA interface to cx18 PCM capture streams + * + * Copyright (C) 2009 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +int __init snd_cx18_pcm_create(struct snd_cx18_card *cxsc); + +/* Used by cx18-mailbox to announce the PCM data to the module */ +void cx18_alsa_announce_pcm_data(struct snd_cx18_card *card, u8 *pcm_data, + size_t num_bytes); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-audio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-audio.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,92 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-cards.h" +#include "cx18-audio.h" + +#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AI1_MUX_MASK 0x30 +#define CX18_AI1_MUX_I2S1 0x00 +#define CX18_AI1_MUX_I2S2 0x10 +#define CX18_AI1_MUX_843_I2S 0x20 + +/* Selects the audio input and output according to the current + settings. */ +int cx18_audio_set_io(struct cx18 *cx) +{ + const struct cx18_card_audio_input *in; + u32 u, v; + int err; + + /* Determine which input to use */ + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) + in = &cx->card->radio_input; + else + in = &cx->card->audio_inputs[cx->audio_input]; + + /* handle muxer chips */ + v4l2_subdev_call(cx->sd_extmux, audio, s_routing, + (u32) in->muxer_input, 0, 0); + + err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl, + audio, s_routing, in->audio_input, 0, 0); + if (err) + return err; + + /* FIXME - this internal mux should be abstracted to a subdev */ + u = cx18_read_reg(cx, CX18_AUDIO_ENABLE); + v = u & ~CX18_AI1_MUX_MASK; + switch (in->audio_input) { + case CX18_AV_AUDIO_SERIAL1: + v |= CX18_AI1_MUX_I2S1; + break; + case CX18_AV_AUDIO_SERIAL2: + v |= CX18_AI1_MUX_I2S2; + break; + default: + v |= CX18_AI1_MUX_843_I2S; + break; + } + if (v == u) { + /* force a toggle of some AI1 MUX control bits */ + u &= ~CX18_AI1_MUX_MASK; + switch (in->audio_input) { + case CX18_AV_AUDIO_SERIAL1: + u |= CX18_AI1_MUX_843_I2S; + break; + case CX18_AV_AUDIO_SERIAL2: + u |= CX18_AI1_MUX_843_I2S; + break; + default: + u |= CX18_AI1_MUX_I2S1; + break; + } + cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE, + u, CX18_AI1_MUX_MASK); + } + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-audio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-audio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-audio.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-audio.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +int cx18_audio_set_io(struct cx18 *cx); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-audio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-audio.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,471 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-audio.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" + +static int set_audclk_freq(struct cx18 *cx, u32 freq) +{ + struct cx18_av_state *state = &cx->av_state; + + if (freq != 32000 && freq != 44100 && freq != 48000) + return -EINVAL; + + /* + * The PLL parameters are based on the external crystal frequency that + * would ideally be: + * + * NTSC Color subcarrier freq * 8 = + * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz + * + * The accidents of history and rationale that explain from where this + * combination of magic numbers originate can be found in: + * + * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in + * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80 + * + * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the + * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83 + * + * As Mike Bradley has rightly pointed out, it's not the exact crystal + * frequency that matters, only that all parts of the driver and + * firmware are using the same value (close to the ideal value). + * + * Since I have a strong suspicion that, if the firmware ever assumes a + * crystal value at all, it will assume 28.636360 MHz, the crystal + * freq used in calculations in this driver will be: + * + * xtal_freq = 28.636360 MHz + * + * an error of less than 0.13 ppm which is way, way better than any off + * the shelf crystal will have for accuracy anyway. + * + * Below I aim to run the PLLs' VCOs near 400 MHz to minimze error. + * + * Many thanks to Jeff Campbell and Mike Bradley for their extensive + * investigation, experimentation, testing, and suggested solutions of + * of audio/video sync problems with SVideo and CVBS captures. + */ + + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { + switch (freq) { + case 32000: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20 + */ + cx18_av_write4(cx, 0x108, 0x200d040f); + + /* VID_PLL Fraction = 0x2be2fe */ + /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ + cx18_av_write4(cx, 0x10c, 0x002be2fe); + + /* AUX_PLL Fraction = 0x176740c */ + /* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/ + cx18_av_write4(cx, 0x110, 0x0176740c); + + /* src3/4/6_ctl */ + /* 0x1.f77f = (4 * xtal/8*2/455) / 32000 */ + cx18_av_write4(cx, 0x900, 0x0801f77f); + cx18_av_write4(cx, 0x904, 0x0801f77f); + cx18_av_write4(cx, 0x90c, 0x0801f77f); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */ + cx18_av_write(cx, 0x127, 0x60); + + /* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11202fff); + + /* + * EN_AV_LOCK = 0 + * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = + * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa00d2ef8); + break; + + case 44100: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x18 + */ + cx18_av_write4(cx, 0x108, 0x180e040f); + + /* VID_PLL Fraction = 0x2be2fe */ + /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ + cx18_av_write4(cx, 0x10c, 0x002be2fe); + + /* AUX_PLL Fraction = 0x062a1f2 */ + /* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/ + cx18_av_write4(cx, 0x110, 0x0062a1f2); + + /* src3/4/6_ctl */ + /* 0x1.6d59 = (4 * xtal/8*2/455) / 44100 */ + cx18_av_write4(cx, 0x900, 0x08016d59); + cx18_av_write4(cx, 0x904, 0x08016d59); + cx18_av_write4(cx, 0x90c, 0x08016d59); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x18 */ + cx18_av_write(cx, 0x127, 0x58); + + /* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */ + cx18_av_write4(cx, 0x12c, 0x112092ff); + + /* + * EN_AV_LOCK = 0 + * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = + * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa01d4bf8); + break; + + case 48000: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x16 + */ + cx18_av_write4(cx, 0x108, 0x160e040f); + + /* VID_PLL Fraction = 0x2be2fe */ + /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ + cx18_av_write4(cx, 0x10c, 0x002be2fe); + + /* AUX_PLL Fraction = 0x05227ad */ + /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz p-pd*/ + cx18_av_write4(cx, 0x110, 0x005227ad); + + /* src3/4/6_ctl */ + /* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */ + cx18_av_write4(cx, 0x900, 0x08014faa); + cx18_av_write4(cx, 0x904, 0x08014faa); + cx18_av_write4(cx, 0x90c, 0x08014faa); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ + cx18_av_write(cx, 0x127, 0x56); + + /* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11205fff); + + /* + * EN_AV_LOCK = 0 + * VID_COUNT = 0x1193f8 = 143999.000 * 8 = + * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa01193f8); + break; + } + } else { + switch (freq) { + case 32000: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x30 + */ + cx18_av_write4(cx, 0x108, 0x300d040f); + + /* VID_PLL Fraction = 0x2be2fe */ + /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ + cx18_av_write4(cx, 0x10c, 0x002be2fe); + + /* AUX_PLL Fraction = 0x176740c */ + /* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/ + cx18_av_write4(cx, 0x110, 0x0176740c); + + /* src1_ctl */ + /* 0x1.0000 = 32000/32000 */ + cx18_av_write4(cx, 0x8f8, 0x08010000); + + /* src3/4/6_ctl */ + /* 0x2.0000 = 2 * (32000/32000) */ + cx18_av_write4(cx, 0x900, 0x08020000); + cx18_av_write4(cx, 0x904, 0x08020000); + cx18_av_write4(cx, 0x90c, 0x08020000); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */ + cx18_av_write(cx, 0x127, 0x70); + + /* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11201fff); + + /* + * EN_AV_LOCK = 0 + * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = + * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa00d2ef8); + break; + + case 44100: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x24 + */ + cx18_av_write4(cx, 0x108, 0x240e040f); + + /* VID_PLL Fraction = 0x2be2fe */ + /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ + cx18_av_write4(cx, 0x10c, 0x002be2fe); + + /* AUX_PLL Fraction = 0x062a1f2 */ + /* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/ + cx18_av_write4(cx, 0x110, 0x0062a1f2); + + /* src1_ctl */ + /* 0x1.60cd = 44100/32000 */ + cx18_av_write4(cx, 0x8f8, 0x080160cd); + + /* src3/4/6_ctl */ + /* 0x1.7385 = 2 * (32000/44100) */ + cx18_av_write4(cx, 0x900, 0x08017385); + cx18_av_write4(cx, 0x904, 0x08017385); + cx18_av_write4(cx, 0x90c, 0x08017385); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x24 */ + cx18_av_write(cx, 0x127, 0x64); + + /* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */ + cx18_av_write4(cx, 0x12c, 0x112061ff); + + /* + * EN_AV_LOCK = 0 + * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = + * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa01d4bf8); + break; + + case 48000: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20 + */ + cx18_av_write4(cx, 0x108, 0x200d040f); + + /* VID_PLL Fraction = 0x2be2fe */ + /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ + cx18_av_write4(cx, 0x10c, 0x002be2fe); + + /* AUX_PLL Fraction = 0x176740c */ + /* xtal * 0xd.bb3a060/0x20 = 48000 * 256: 393 MHz p-pd*/ + cx18_av_write4(cx, 0x110, 0x0176740c); + + /* src1_ctl */ + /* 0x1.8000 = 48000/32000 */ + cx18_av_write4(cx, 0x8f8, 0x08018000); + + /* src3/4/6_ctl */ + /* 0x1.5555 = 2 * (32000/48000) */ + cx18_av_write4(cx, 0x900, 0x08015555); + cx18_av_write4(cx, 0x904, 0x08015555); + cx18_av_write4(cx, 0x90c, 0x08015555); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */ + cx18_av_write(cx, 0x127, 0x60); + + /* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11203fff); + + /* + * EN_AV_LOCK = 0 + * VID_COUNT = 0x1193f8 = 143999.000 * 8 = + * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa01193f8); + break; + } + } + + state->audclk_freq = freq; + + return 0; +} + +void cx18_av_audio_set_path(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + u8 v; + + /* stop microcontroller */ + v = cx18_av_read(cx, 0x803) & ~0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + + /* assert soft reset */ + v = cx18_av_read(cx, 0x810) | 0x01; + cx18_av_write_expect(cx, 0x810, v, v, 0x0f); + + /* Mute everything to prevent the PFFT! */ + cx18_av_write(cx, 0x8d3, 0x1f); + + if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) { + /* Set Path1 to Serial Audio Input */ + cx18_av_write4(cx, 0x8d0, 0x01011012); + + /* The microcontroller should not be started for the + * non-tuner inputs: autodetection is specific for + * TV audio. */ + } else { + /* Set Path1 to Analog Demod Main Channel */ + cx18_av_write4(cx, 0x8d0, 0x1f063870); + } + + set_audclk_freq(cx, state->audclk_freq); + + /* deassert soft reset */ + v = cx18_av_read(cx, 0x810) & ~0x01; + cx18_av_write_expect(cx, 0x810, v, v, 0x0f); + + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { + /* When the microcontroller detects the + * audio format, it will unmute the lines */ + v = cx18_av_read(cx, 0x803) | 0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + } +} + +static void set_volume(struct cx18 *cx, int volume) +{ + /* First convert the volume to msp3400 values (0-127) */ + int vol = volume >> 9; + /* now scale it up to cx18_av values + * -114dB to -96dB maps to 0 + * this should be 19, but in my testing that was 4dB too loud */ + if (vol <= 23) + vol = 0; + else + vol -= 23; + + /* PATH1_VOLUME */ + cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); +} + +static void set_bass(struct cx18 *cx, int bass) +{ + /* PATH1_EQ_BASS_VOL */ + cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); +} + +static void set_treble(struct cx18 *cx, int treble) +{ + /* PATH1_EQ_TREBLE_VOL */ + cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); +} + +static void set_balance(struct cx18 *cx, int balance) +{ + int bal = balance >> 8; + if (bal > 0x80) { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f); + } else { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal); + } +} + +static void set_mute(struct cx18 *cx, int mute) +{ + struct cx18_av_state *state = &cx->av_state; + u8 v; + + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { + /* Must turn off microcontroller in order to mute sound. + * Not sure if this is the best method, but it does work. + * If the microcontroller is running, then it will undo any + * changes to the mute register. */ + v = cx18_av_read(cx, 0x803); + if (mute) { + /* disable microcontroller */ + v &= ~0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + cx18_av_write(cx, 0x8d3, 0x1f); + } else { + /* enable microcontroller */ + v |= 0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + } + } else { + /* SRC1_MUTE_EN */ + cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00); + } +} + +int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + struct cx18_av_state *state = &cx->av_state; + int retval; + u8 v; + + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { + v = cx18_av_read(cx, 0x803) & ~0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + cx18_av_write(cx, 0x8d3, 0x1f); + } + v = cx18_av_read(cx, 0x810) | 0x1; + cx18_av_write_expect(cx, 0x810, v, v, 0x0f); + + retval = set_audclk_freq(cx, freq); + + v = cx18_av_read(cx, 0x810) & ~0x1; + cx18_av_write_expect(cx, 0x810, v, v, 0x0f); + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { + v = cx18_av_read(cx, 0x803) | 0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + } + return retval; +} + +static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct cx18 *cx = v4l2_get_subdevdata(sd); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + set_volume(cx, ctrl->val); + break; + case V4L2_CID_AUDIO_BASS: + set_bass(cx, ctrl->val); + break; + case V4L2_CID_AUDIO_TREBLE: + set_treble(cx, ctrl->val); + break; + case V4L2_CID_AUDIO_BALANCE: + set_balance(cx, ctrl->val); + break; + case V4L2_CID_AUDIO_MUTE: + set_mute(cx, ctrl->val); + break; + default: + return -EINVAL; + } + return 0; +} + +const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = { + .s_ctrl = cx18_av_audio_s_ctrl, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1401 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-core.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-cards.h" + +int cx18_av_write(struct cx18 *cx, u16 addr, u8 value) +{ + u32 reg = 0xc40000 + (addr & ~3); + u32 mask = 0xff; + int shift = (addr & 3) * 8; + u32 x = cx18_read_reg(cx, reg); + + x = (x & ~(mask << shift)) | ((u32)value << shift); + cx18_write_reg(cx, x, reg); + return 0; +} + +int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask) +{ + u32 reg = 0xc40000 + (addr & ~3); + int shift = (addr & 3) * 8; + u32 x = cx18_read_reg(cx, reg); + + x = (x & ~((u32)0xff << shift)) | ((u32)value << shift); + cx18_write_reg_expect(cx, x, reg, + ((u32)eval << shift), ((u32)mask << shift)); + return 0; +} + +int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) +{ + cx18_write_reg(cx, value, 0xc40000 + addr); + return 0; +} + +int +cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, u32 mask) +{ + cx18_write_reg_expect(cx, value, 0xc40000 + addr, eval, mask); + return 0; +} + +int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value) +{ + cx18_write_reg_noretry(cx, value, 0xc40000 + addr); + return 0; +} + +u8 cx18_av_read(struct cx18 *cx, u16 addr) +{ + u32 x = cx18_read_reg(cx, 0xc40000 + (addr & ~3)); + int shift = (addr & 3) * 8; + + return (x >> shift) & 0xff; +} + +u32 cx18_av_read4(struct cx18 *cx, u16 addr) +{ + return cx18_read_reg(cx, 0xc40000 + addr); +} + +int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask, + u8 or_value) +{ + return cx18_av_write(cx, addr, + (cx18_av_read(cx, addr) & and_mask) | + or_value); +} + +int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, + u32 or_value) +{ + return cx18_av_write4(cx, addr, + (cx18_av_read4(cx, addr) & and_mask) | + or_value); +} + +static void cx18_av_init(struct cx18 *cx) +{ + /* + * The crystal freq used in calculations in this driver will be + * 28.636360 MHz. + * Aim to run the PLLs' VCOs near 400 MHz to minimze errors. + */ + + /* + * VDCLK Integer = 0x0f, Post Divider = 0x04 + * AIMCLK Integer = 0x0e, Post Divider = 0x16 + */ + cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f); + + /* VDCLK Fraction = 0x2be2fe */ + /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */ + cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe); + + /* AIMCLK Fraction = 0x05227ad */ + /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/ + cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ + cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56); +} + +static void cx18_av_initialize(struct v4l2_subdev *sd) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + struct cx18 *cx = v4l2_get_subdevdata(sd); + int default_volume; + u32 v; + + cx18_av_loadfw(cx); + /* Stop 8051 code execution */ + cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x03000000, + 0x03000000, 0x13000000); + + /* initallize the PLL by toggling sleep bit */ + v = cx18_av_read4(cx, CXADEC_HOST_REG1); + /* enable sleep mode - register appears to be read only... */ + cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v | 1, v, 0xfffe); + /* disable sleep mode */ + cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v & 0xfffe, + v & 0xfffe, 0xffff); + + /* initialize DLLs */ + v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100); + + v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100); + + /* set analog bias currents. Set Vreg to 1.20V. */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802); + + v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1; + /* enable TUNE_FIL_RST */ + cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, v, v, 0x03009F0F); + /* disable TUNE_FIL_RST */ + cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, + v & 0xFFFFFFFE, v & 0xFFFFFFFE, 0x03009F0F); + + /* enable 656 output */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00); + + /* video output drive strength */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2); + + /* reset video */ + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000); + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0); + + /* + * Disable Video Auto-config of the Analog Front End and Video PLL. + * + * Since we only use BT.656 pixel mode, which works for both 525 and 625 + * line systems, it's just easier for us to set registers + * 0x102 (CXADEC_CHIP_CTRL), 0x104-0x106 (CXADEC_AFE_CTRL), + * 0x108-0x109 (CXADEC_PLL_CTRL1), and 0x10c-0x10f (CXADEC_VID_PLL_FRAC) + * ourselves, than to run around cleaning up after the auto-config. + * + * (Note: my CX23418 chip doesn't seem to let the ACFG_DIS bit + * get set to 1, but OTOH, it doesn't seem to do AFE and VID PLL + * autoconfig either.) + * + * As a default, also turn off Dual mode for ADC2 and set ADC2 to CH3. + */ + cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000); + + /* Setup the Video and and Aux/Audio PLLs */ + cx18_av_init(cx); + + /* set video to auto-detect */ + /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ + /* set the comb notch = 1 */ + cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800); + + /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */ + /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */ + cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000); + + /* Set VGA_TRACK_RANGE to 0x20 */ + cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000); + + /* + * Initial VBI setup + * VIP-1.1, 10 bit mode, enable Raw, disable sliced, + * don't clamp raw samples when codes are in use, 1 byte user D-words, + * IDID0 has line #, RP code V bit transition on VBLANK, data during + * blanking intervals + */ + cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4013252e); + + /* Set the video input. + The setting in MODE_CTRL gets lost when we do the above setup */ + /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */ + /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */ + + /* + * Analog Front End (AFE) + * Default to luma on ch1/ADC1, chroma on ch2/ADC2, SIF on ch3/ADC2 + * bypass_ch[1-3] use filter + * droop_comp_ch[1-3] disable + * clamp_en_ch[1-3] disable + * aud_in_sel ADC2 + * luma_in_sel ADC1 + * chroma_in_sel ADC2 + * clamp_sel_ch[2-3] midcode + * clamp_sel_ch1 video decoder + * vga_sel_ch3 audio decoder + * vga_sel_ch[1-2] video decoder + * half_bw_ch[1-3] disable + * +12db_ch[1-3] disable + */ + cx18_av_and_or4(cx, CXADEC_AFE_CTRL, 0xFF000000, 0x00005D00); + +/* if(dwEnable && dw3DCombAvailable) { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */ +/* } else { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ +/* } */ + cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); + default_volume = cx18_av_read(cx, 0x8d4); + /* + * Enforce the legacy volume scale mapping limits to avoid + * -ERANGE errors when initializing the volume control + */ + if (default_volume > 228) { + /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ + default_volume = 228; + cx18_av_write(cx, 0x8d4, 228); + } else if (default_volume < 20) { + /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ + default_volume = 20; + cx18_av_write(cx, 0x8d4, 20); + } + default_volume = (((228 - default_volume) >> 1) + 23) << 9; + state->volume->cur.val = state->volume->default_value = default_volume; + v4l2_ctrl_handler_setup(&state->hdl); +} + +static int cx18_av_reset(struct v4l2_subdev *sd, u32 val) +{ + cx18_av_initialize(sd); + return 0; +} + +static int cx18_av_load_fw(struct v4l2_subdev *sd) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + + if (!state->is_initialized) { + /* initialize on first use */ + state->is_initialized = 1; + cx18_av_initialize(sd); + } + return 0; +} + +void cx18_av_std_setup(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_subdev *sd = &state->sd; + v4l2_std_id std = state->std; + + /* + * Video ADC crystal clock to pixel clock SRC decimation ratio + * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b + */ + const int src_decimation = 0x21f; + + int hblank, hactive, burst, vblank, vactive, sc; + int vblank656; + int luma_lpf, uv_lpf, comb; + u32 pll_int, pll_frac, pll_post; + + /* datasheet startup, step 8d */ + if (std & ~V4L2_STD_NTSC) + cx18_av_write(cx, 0x49f, 0x11); + else + cx18_av_write(cx, 0x49f, 0x14); + + /* + * Note: At the end of a field, there are 3 sets of half line duration + * (double horizontal rate) pulses: + * + * 5 (625) or 6 (525) half-lines to blank for the vertical retrace + * 5 (625) or 6 (525) vertical sync pulses of half line duration + * 5 (625) or 6 (525) half-lines of equalization pulses + */ + if (std & V4L2_STD_625_50) { + /* + * The following relationships of half line counts should hold: + * 625 = vblank656 + vactive + * 10 = vblank656 - vblank = vsync pulses + equalization pulses + * + * vblank656: half lines after line 625/mid-313 of blanked video + * vblank: half lines, after line 5/317, of blanked video + * vactive: half lines of active video + + * 5 half lines after the end of active video + * + * As far as I can tell: + * vblank656 starts counting from the falling edge of the first + * vsync pulse (start of line 1 or mid-313) + * vblank starts counting from the after the 5 vsync pulses and + * 5 or 4 equalization pulses (start of line 6 or 318) + * + * For 625 line systems the driver will extract VBI information + * from lines 6-23 and lines 318-335 (but the slicer can only + * handle 17 lines, not the 18 in the vblank region). + * In addition, we need vblank656 and vblank to be one whole + * line longer, to cover line 24 and 336, so the SAV/EAV RP + * codes get generated such that the encoder can actually + * extract line 23 & 335 (WSS). We'll lose 1 line in each field + * at the top of the screen. + * + * It appears the 5 half lines that happen after active + * video must be included in vactive (579 instead of 574), + * otherwise the colors get badly displayed in various regions + * of the screen. I guess the chroma comb filter gets confused + * without them (at least when a PVR-350 is the PAL source). + */ + vblank656 = 48; /* lines 1 - 24 & 313 - 336 */ + vblank = 38; /* lines 6 - 24 & 318 - 336 */ + vactive = 579; /* lines 24 - 313 & 337 - 626 */ + + /* + * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is + * is 864 pixels = 720 active + 144 blanking. ITU-R BT.601 + * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after + * the end of active video to start a horizontal line, so that + * leaves 132 pixels of hblank to ignore. + */ + hblank = 132; + hactive = 720; + + /* + * Burst gate delay (for 625 line systems) + * Hsync leading edge to color burst rise = 5.6 us + * Color burst width = 2.25 us + * Gate width = 4 pixel clocks + * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks + */ + burst = 93; + luma_lpf = 2; + if (std & V4L2_STD_PAL) { + uv_lpf = 1; + comb = 0x20; + /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ + sc = 688700; + } else if (std == V4L2_STD_PAL_Nc) { + uv_lpf = 1; + comb = 0x20; + /* sc = 3582056.25 * src_decimation/28636360 * 2^13 */ + sc = 556422; + } else { /* SECAM */ + uv_lpf = 0; + comb = 0; + /* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */ + /* sc = 4328130 * src_decimation/28636360 * 2^13 */ + sc = 672314; + } + } else { + /* + * The following relationships of half line counts should hold: + * 525 = prevsync + vblank656 + vactive + * 12 = vblank656 - vblank = vsync pulses + equalization pulses + * + * prevsync: 6 half-lines before the vsync pulses + * vblank656: half lines, after line 3/mid-266, of blanked video + * vblank: half lines, after line 9/272, of blanked video + * vactive: half lines of active video + * + * As far as I can tell: + * vblank656 starts counting from the falling edge of the first + * vsync pulse (start of line 4 or mid-266) + * vblank starts counting from the after the 6 vsync pulses and + * 6 or 5 equalization pulses (start of line 10 or 272) + * + * For 525 line systems the driver will extract VBI information + * from lines 10-21 and lines 273-284. + */ + vblank656 = 38; /* lines 4 - 22 & 266 - 284 */ + vblank = 26; /* lines 10 - 22 & 272 - 284 */ + vactive = 481; /* lines 23 - 263 & 285 - 525 */ + + /* + * For a 13.5 Mpps clock and 15,734.26 Hz line rate, a line is + * is 858 pixels = 720 active + 138 blanking. The Hsync leading + * edge should happen 1.2 us * 13.5 Mpps ~= 16 pixels after the + * end of active video, leaving 122 pixels of hblank to ignore + * before active video starts. + */ + hactive = 720; + hblank = 122; + luma_lpf = 1; + uv_lpf = 1; + + /* + * Burst gate delay (for 525 line systems) + * Hsync leading edge to color burst rise = 5.3 us + * Color burst width = 2.5 us + * Gate width = 4 pixel clocks + * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks + */ + if (std == V4L2_STD_PAL_60) { + burst = 90; + luma_lpf = 2; + comb = 0x20; + /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ + sc = 688700; + } else if (std == V4L2_STD_PAL_M) { + /* The 97 needs to be verified against PAL-M timings */ + burst = 97; + comb = 0x20; + /* sc = 3575611.49 * src_decimation/28636360 * 2^13 */ + sc = 555421; + } else { + burst = 90; + comb = 0x66; + /* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */ + sc = 556032; + } + } + + /* DEBUG: Displays configured PLL frequency */ + pll_int = cx18_av_read(cx, 0x108); + pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff; + pll_post = cx18_av_read(cx, 0x109); + CX18_DEBUG_INFO_DEV(sd, "PLL regs = int: %u, frac: %u, post: %u\n", + pll_int, pll_frac, pll_post); + + if (pll_post) { + int fsc, pll; + u64 tmp; + + pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25; + pll /= pll_post; + CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n", + pll / 1000000, pll % 1000000); + CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n", + pll / 8000000, (pll / 8) % 1000000); + + CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio " + "= %d.%03d\n", src_decimation / 256, + ((src_decimation % 256) * 1000) / 256); + + tmp = 28636360 * (u64) sc; + do_div(tmp, src_decimation); + fsc = tmp >> 13; + CX18_DEBUG_INFO_DEV(sd, + "Chroma sub-carrier initial freq = %d.%06d " + "MHz\n", fsc / 1000000, fsc % 1000000); + + CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, " + "vactive %i, vblank656 %i, src_dec %i, " + "burst 0x%02x, luma_lpf %i, uv_lpf %i, " + "comb 0x%02x, sc 0x%06x\n", + hblank, hactive, vblank, vactive, vblank656, + src_decimation, burst, luma_lpf, uv_lpf, + comb, sc); + } + + /* Sets horizontal blanking delay and active lines */ + cx18_av_write(cx, 0x470, hblank); + cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) | + (hactive << 4))); + cx18_av_write(cx, 0x472, hactive >> 4); + + /* Sets burst gate delay */ + cx18_av_write(cx, 0x473, burst); + + /* Sets vertical blanking delay and active duration */ + cx18_av_write(cx, 0x474, vblank); + cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) | + (vactive << 4))); + cx18_av_write(cx, 0x476, vactive >> 4); + cx18_av_write(cx, 0x477, vblank656); + + /* Sets src decimation rate */ + cx18_av_write(cx, 0x478, 0xff & src_decimation); + cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8)); + + /* Sets Luma and UV Low pass filters */ + cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); + + /* Enables comb filters */ + cx18_av_write(cx, 0x47b, comb); + + /* Sets SC Step*/ + cx18_av_write(cx, 0x47c, sc); + cx18_av_write(cx, 0x47d, 0xff & sc >> 8); + cx18_av_write(cx, 0x47e, 0xff & sc >> 16); + + if (std & V4L2_STD_625_50) { + state->slicer_line_delay = 1; + state->slicer_line_offset = (6 + state->slicer_line_delay - 2); + } else { + state->slicer_line_delay = 0; + state->slicer_line_offset = (10 + state->slicer_line_delay - 2); + } + cx18_av_write(cx, 0x47f, state->slicer_line_delay); +} + +static void input_change(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + v4l2_std_id std = state->std; + u8 v; + + /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ + cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); + cx18_av_and_or(cx, 0x401, ~0x60, 0); + cx18_av_and_or(cx, 0x401, ~0x60, 0x60); + + if (std & V4L2_STD_525_60) { + if (std == V4L2_STD_NTSC_M_JP) { + /* Japan uses EIAJ audio standard */ + cx18_av_write_expect(cx, 0x808, 0xf7, 0xf7, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x02, 0x02, 0x3f); + } else if (std == V4L2_STD_NTSC_M_KR) { + /* South Korea uses A2 audio standard */ + cx18_av_write_expect(cx, 0x808, 0xf8, 0xf8, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); + } else { + /* Others use the BTSC audio standard */ + cx18_av_write_expect(cx, 0x808, 0xf6, 0xf6, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x01, 0x01, 0x3f); + } + } else if (std & V4L2_STD_PAL) { + /* Follow tuner change procedure for PAL */ + cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); + } else if (std & V4L2_STD_SECAM) { + /* Select autodetect for SECAM */ + cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); + } + + v = cx18_av_read(cx, 0x803); + if (v & 0x10) { + /* restart audio decoder microcontroller */ + v &= ~0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + v |= 0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + } +} + +static int cx18_av_s_frequency(struct v4l2_subdev *sd, + struct v4l2_frequency *freq) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + input_change(cx); + return 0; +} + +static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, + enum cx18_av_audio_input aud_input) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_subdev *sd = &state->sd; + + enum analog_signal_type { + NONE, CVBS, Y, C, SIF, Pb, Pr + } ch[3] = {NONE, NONE, NONE}; + + u8 afe_mux_cfg; + u8 adc2_cfg; + u8 input_mode; + u32 afe_cfg; + int i; + + CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n", + vid_input, aud_input); + + if (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8) { + afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1); + ch[0] = CVBS; + input_mode = 0x0; + } else if (vid_input >= CX18_AV_COMPONENT_LUMA1) { + int luma = vid_input & 0xf000; + int r_chroma = vid_input & 0xf0000; + int b_chroma = vid_input & 0xf00000; + + if ((vid_input & ~0xfff000) || + luma < CX18_AV_COMPONENT_LUMA1 || + luma > CX18_AV_COMPONENT_LUMA8 || + r_chroma < CX18_AV_COMPONENT_R_CHROMA4 || + r_chroma > CX18_AV_COMPONENT_R_CHROMA6 || + b_chroma < CX18_AV_COMPONENT_B_CHROMA7 || + b_chroma > CX18_AV_COMPONENT_B_CHROMA8) { + CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n", + vid_input); + return -EINVAL; + } + afe_mux_cfg = (luma - CX18_AV_COMPONENT_LUMA1) >> 12; + ch[0] = Y; + afe_mux_cfg |= (r_chroma - CX18_AV_COMPONENT_R_CHROMA4) >> 12; + ch[1] = Pr; + afe_mux_cfg |= (b_chroma - CX18_AV_COMPONENT_B_CHROMA7) >> 14; + ch[2] = Pb; + input_mode = 0x6; + } else { + int luma = vid_input & 0xf0; + int chroma = vid_input & 0xf00; + + if ((vid_input & ~0xff0) || + luma < CX18_AV_SVIDEO_LUMA1 || + luma > CX18_AV_SVIDEO_LUMA8 || + chroma < CX18_AV_SVIDEO_CHROMA4 || + chroma > CX18_AV_SVIDEO_CHROMA8) { + CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n", + vid_input); + return -EINVAL; + } + afe_mux_cfg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4); + ch[0] = Y; + if (chroma >= CX18_AV_SVIDEO_CHROMA7) { + afe_mux_cfg &= 0x3f; + afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2; + ch[2] = C; + } else { + afe_mux_cfg &= 0xcf; + afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4; + ch[1] = C; + } + input_mode = 0x2; + } + + switch (aud_input) { + case CX18_AV_AUDIO_SERIAL1: + case CX18_AV_AUDIO_SERIAL2: + /* do nothing, use serial audio input */ + break; + case CX18_AV_AUDIO4: + afe_mux_cfg &= ~0x30; + ch[1] = SIF; + break; + case CX18_AV_AUDIO5: + afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x10; + ch[1] = SIF; + break; + case CX18_AV_AUDIO6: + afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x20; + ch[1] = SIF; + break; + case CX18_AV_AUDIO7: + afe_mux_cfg &= ~0xc0; + ch[2] = SIF; + break; + case CX18_AV_AUDIO8: + afe_mux_cfg = (afe_mux_cfg & ~0xc0) | 0x40; + ch[2] = SIF; + break; + + default: + CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n", + aud_input); + return -EINVAL; + } + + /* Set up analog front end multiplexers */ + cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7); + /* Set INPUT_MODE to Composite, S-Video, or Component */ + cx18_av_and_or(cx, 0x401, ~0x6, input_mode); + + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ + adc2_cfg = cx18_av_read(cx, 0x102); + if (ch[2] == NONE) + adc2_cfg &= ~0x2; /* No sig on CH3, set ADC2 to CH2 for input */ + else + adc2_cfg |= 0x2; /* Signal on CH3, set ADC2 to CH3 for input */ + + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ + if (ch[1] != NONE && ch[2] != NONE) + adc2_cfg |= 0x4; /* Set dual mode */ + else + adc2_cfg &= ~0x4; /* Clear dual mode */ + cx18_av_write_expect(cx, 0x102, adc2_cfg, adc2_cfg, 0x17); + + /* Configure the analog front end */ + afe_cfg = cx18_av_read4(cx, CXADEC_AFE_CTRL); + afe_cfg &= 0xff000000; + afe_cfg |= 0x00005000; /* CHROMA_IN, AUD_IN: ADC2; LUMA_IN: ADC1 */ + if (ch[1] != NONE && ch[2] != NONE) + afe_cfg |= 0x00000030; /* half_bw_ch[2-3] since in dual mode */ + + for (i = 0; i < 3; i++) { + switch (ch[i]) { + default: + case NONE: + /* CLAMP_SEL = Fixed to midcode clamp level */ + afe_cfg |= (0x00000200 << i); + break; + case CVBS: + case Y: + if (i > 0) + afe_cfg |= 0x00002000; /* LUMA_IN_SEL: ADC2 */ + break; + case C: + case Pb: + case Pr: + /* CLAMP_SEL = Fixed to midcode clamp level */ + afe_cfg |= (0x00000200 << i); + if (i == 0 && ch[i] == C) + afe_cfg &= ~0x00001000; /* CHROMA_IN_SEL ADC1 */ + break; + case SIF: + /* + * VGA_GAIN_SEL = Audio Decoder + * CLAMP_SEL = Fixed to midcode clamp level + */ + afe_cfg |= (0x00000240 << i); + if (i == 0) + afe_cfg &= ~0x00004000; /* AUD_IN_SEL ADC1 */ + break; + } + } + + cx18_av_write4(cx, CXADEC_AFE_CTRL, afe_cfg); + + state->vid_input = vid_input; + state->aud_input = aud_input; + cx18_av_audio_set_path(cx); + input_change(cx); + return 0; +} + +static int cx18_av_s_video_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + struct cx18 *cx = v4l2_get_subdevdata(sd); + return set_input(cx, input, state->aud_input); +} + +static int cx18_av_s_audio_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + struct cx18 *cx = v4l2_get_subdevdata(sd); + return set_input(cx, state->vid_input, input); +} + +static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + struct cx18 *cx = v4l2_get_subdevdata(sd); + u8 vpres; + u8 mode; + int val = 0; + + if (state->radio) + return 0; + + vpres = cx18_av_read(cx, 0x40e) & 0x20; + vt->signal = vpres ? 0xffff : 0x0; + + vt->capability |= + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + + mode = cx18_av_read(cx, 0x804); + + /* get rxsubchans and audmode */ + if ((mode & 0xf) == 1) + val |= V4L2_TUNER_SUB_STEREO; + else + val |= V4L2_TUNER_SUB_MONO; + + if (mode == 2 || mode == 4) + val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + + if (mode & 0x10) + val |= V4L2_TUNER_SUB_SAP; + + vt->rxsubchans = val; + vt->audmode = state->audmode; + return 0; +} + +static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + struct cx18 *cx = v4l2_get_subdevdata(sd); + u8 v; + + if (state->radio) + return 0; + + v = cx18_av_read(cx, 0x809); + v &= ~0xf; + + switch (vt->audmode) { + case V4L2_TUNER_MODE_MONO: + /* mono -> mono + stereo -> mono + bilingual -> lang1 */ + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + /* mono -> mono + stereo -> stereo + bilingual -> lang1 */ + v |= 0x4; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang1/lang2 */ + v |= 0x7; + break; + case V4L2_TUNER_MODE_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang2 */ + v |= 0x1; + break; + default: + return -EINVAL; + } + cx18_av_write_expect(cx, 0x809, v, v, 0xff); + state->audmode = vt->audmode; + return 0; +} + +static int cx18_av_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + struct cx18 *cx = v4l2_get_subdevdata(sd); + + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; + + if (state->radio == 0 && state->std == norm) + return 0; + + state->radio = 0; + state->std = norm; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { + pal_m = 1; + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { + fmt = 0x8; + } else { + /* Then, test against generic ones */ + if (state->std & V4L2_STD_NTSC) + fmt = 0x1; + else if (state->std & V4L2_STD_PAL) + fmt = 0x4; + else if (state->std & V4L2_STD_SECAM) + fmt = 0xc; + } + + CX18_DEBUG_INFO_DEV(sd, "changing video std to fmt %i\n", fmt); + + /* Follow step 9 of section 3.16 in the cx18_av datasheet. + Without this PAL may display a vertical ghosting effect. + This happens for example with the Yuan MPC622. */ + if (fmt >= 4 && fmt < 8) { + /* Set format to NTSC-M */ + cx18_av_and_or(cx, 0x400, ~0xf, 1); + /* Turn off LCOMB */ + cx18_av_and_or(cx, 0x47b, ~6, 0); + } + cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20); + cx18_av_and_or(cx, 0x403, ~0x3, pal_m); + cx18_av_std_setup(cx); + input_change(cx); + return 0; +} + +static int cx18_av_s_radio(struct v4l2_subdev *sd) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + state->radio = 1; + return 0; +} + +static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct cx18 *cx = v4l2_get_subdevdata(sd); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + cx18_av_write(cx, 0x414, ctrl->val - 128); + break; + + case V4L2_CID_CONTRAST: + cx18_av_write(cx, 0x415, ctrl->val << 1); + break; + + case V4L2_CID_SATURATION: + cx18_av_write(cx, 0x420, ctrl->val << 1); + cx18_av_write(cx, 0x421, ctrl->val << 1); + break; + + case V4L2_CID_HUE: + cx18_av_write(cx, 0x422, ctrl->val); + break; + + default: + return -EINVAL; + } + return 0; +} + +static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + struct cx18 *cx = v4l2_get_subdevdata(sd); + int HSC, VSC, Vsrc, Hsrc, filter, Vlines; + int is_50Hz = !(state->std & V4L2_STD_525_60); + + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; + + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + + Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; + Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; + + Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; + Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; + + /* + * This adjustment reflects the excess of vactive, set in + * cx18_av_std_setup(), above standard values: + * + * 480 + 1 for 60 Hz systems + * 576 + 3 for 50 Hz systems + */ + Vlines = fmt->height + (is_50Hz ? 3 : 1); + + /* + * Invalid height and width scaling requests are: + * 1. width less than 1/16 of the source width + * 2. width greater than the source width + * 3. height less than 1/8 of the source height + * 4. height greater than the source height + */ + if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || + (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n", + fmt->width, fmt->height); + return -ERANGE; + } + + HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); + VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC &= 0x1fff; + + if (fmt->width >= 385) + filter = 0; + else if (fmt->width > 192) + filter = 1; + else if (fmt->width > 96) + filter = 2; + else + filter = 3; + + CX18_DEBUG_INFO_DEV(sd, + "decoder set size %dx%d -> scale %ux%u\n", + fmt->width, fmt->height, HSC, VSC); + + /* HSCALE=HSC */ + cx18_av_write(cx, 0x418, HSC & 0xff); + cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); + cx18_av_write(cx, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx18_av_write(cx, 0x41c, VSC & 0xff); + cx18_av_write(cx, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx18_av_write(cx, 0x41e, 0x8 | filter); + return 0; +} + +static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + + CX18_DEBUG_INFO_DEV(sd, "%s output\n", enable ? "enable" : "disable"); + if (enable) { + cx18_av_write(cx, 0x115, 0x8c); + cx18_av_write(cx, 0x116, 0x07); + } else { + cx18_av_write(cx, 0x115, 0x00); + cx18_av_write(cx, 0x116, 0x00); + } + return 0; +} + +static void log_video_status(struct cx18 *cx) +{ + static const char *const fmt_strs[] = { + "0x0", + "NTSC-M", "NTSC-J", "NTSC-4.43", + "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", + "0x9", "0xA", "0xB", + "SECAM", + "0xD", "0xE", "0xF" + }; + + struct cx18_av_state *state = &cx->av_state; + struct v4l2_subdev *sd = &state->sd; + u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf; + u8 gen_stat1 = cx18_av_read(cx, 0x40d); + u8 gen_stat2 = cx18_av_read(cx, 0x40e); + int vid_input = state->vid_input; + + CX18_INFO_DEV(sd, "Video signal: %spresent\n", + (gen_stat2 & 0x20) ? "" : "not "); + CX18_INFO_DEV(sd, "Detected format: %s\n", + fmt_strs[gen_stat1 & 0xf]); + + CX18_INFO_DEV(sd, "Specified standard: %s\n", + vidfmt_sel ? fmt_strs[vidfmt_sel] + : "automatic detection"); + + if (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8) { + CX18_INFO_DEV(sd, "Specified video input: Composite %d\n", + vid_input - CX18_AV_COMPOSITE1 + 1); + } else { + CX18_INFO_DEV(sd, "Specified video input: " + "S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, + (vid_input & 0xf00) >> 8); + } + + CX18_INFO_DEV(sd, "Specified audioclock freq: %d Hz\n", + state->audclk_freq); +} + +static void log_audio_status(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_subdev *sd = &state->sd; + u8 download_ctl = cx18_av_read(cx, 0x803); + u8 mod_det_stat0 = cx18_av_read(cx, 0x804); + u8 mod_det_stat1 = cx18_av_read(cx, 0x805); + u8 audio_config = cx18_av_read(cx, 0x808); + u8 pref_mode = cx18_av_read(cx, 0x809); + u8 afc0 = cx18_av_read(cx, 0x80b); + u8 mute_ctl = cx18_av_read(cx, 0x8d3); + int aud_input = state->aud_input; + char *p; + + switch (mod_det_stat0) { + case 0x00: p = "mono"; break; + case 0x01: p = "stereo"; break; + case 0x02: p = "dual"; break; + case 0x04: p = "tri"; break; + case 0x10: p = "mono with SAP"; break; + case 0x11: p = "stereo with SAP"; break; + case 0x12: p = "dual with SAP"; break; + case 0x14: p = "tri with SAP"; break; + case 0xfe: p = "forced mode"; break; + default: p = "not defined"; break; + } + CX18_INFO_DEV(sd, "Detected audio mode: %s\n", p); + + switch (mod_det_stat1) { + case 0x00: p = "not defined"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; + case 0x0e: p = "IF FM Radio"; break; + case 0x0f: p = "BTSC"; break; + case 0x10: p = "detected chrominance"; break; + case 0xfd: p = "unknown audio standard"; break; + case 0xfe: p = "forced audio standard"; break; + case 0xff: p = "no detected audio standard"; break; + default: p = "not defined"; break; + } + CX18_INFO_DEV(sd, "Detected audio standard: %s\n", p); + CX18_INFO_DEV(sd, "Audio muted: %s\n", + (mute_ctl & 0x2) ? "yes" : "no"); + CX18_INFO_DEV(sd, "Audio microcontroller: %s\n", + (download_ctl & 0x10) ? "running" : "stopped"); + + switch (audio_config >> 4) { + case 0x00: p = "undefined"; break; + case 0x01: p = "BTSC"; break; + case 0x02: p = "EIAJ"; break; + case 0x03: p = "A2-M"; break; + case 0x04: p = "A2-BG"; break; + case 0x05: p = "A2-DK1"; break; + case 0x06: p = "A2-DK2"; break; + case 0x07: p = "A2-DK3"; break; + case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x09: p = "AM-L"; break; + case 0x0a: p = "NICAM-BG"; break; + case 0x0b: p = "NICAM-DK"; break; + case 0x0c: p = "NICAM-I"; break; + case 0x0d: p = "NICAM-L"; break; + case 0x0e: p = "FM radio"; break; + case 0x0f: p = "automatic detection"; break; + default: p = "undefined"; break; + } + CX18_INFO_DEV(sd, "Configured audio standard: %s\n", p); + + if ((audio_config >> 4) < 0xF) { + switch (audio_config & 0xF) { + case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; + case 0x01: p = "MONO2 (LANGUAGE B)"; break; + case 0x02: p = "MONO3 (STEREO forced MONO)"; break; + case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; + case 0x04: p = "STEREO"; break; + case 0x05: p = "DUAL1 (AC)"; break; + case 0x06: p = "DUAL2 (BC)"; break; + case 0x07: p = "DUAL3 (AB)"; break; + default: p = "undefined"; + } + CX18_INFO_DEV(sd, "Configured audio mode: %s\n", p); + } else { + switch (audio_config & 0xF) { + case 0x00: p = "BG"; break; + case 0x01: p = "DK1"; break; + case 0x02: p = "DK2"; break; + case 0x03: p = "DK3"; break; + case 0x04: p = "I"; break; + case 0x05: p = "L"; break; + case 0x06: p = "BTSC"; break; + case 0x07: p = "EIAJ"; break; + case 0x08: p = "A2-M"; break; + case 0x09: p = "FM Radio (4.5 MHz)"; break; + case 0x0a: p = "FM Radio (5.5 MHz)"; break; + case 0x0b: p = "S-Video"; break; + case 0x0f: p = "automatic standard and mode detection"; break; + default: p = "undefined"; break; + } + CX18_INFO_DEV(sd, "Configured audio system: %s\n", p); + } + + if (aud_input) + CX18_INFO_DEV(sd, "Specified audio input: Tuner (In%d)\n", + aud_input); + else + CX18_INFO_DEV(sd, "Specified audio input: External\n"); + + switch (pref_mode & 0xf) { + case 0: p = "mono/language A"; break; + case 1: p = "language B"; break; + case 2: p = "language C"; break; + case 3: p = "analog fallback"; break; + case 4: p = "stereo"; break; + case 5: p = "language AC"; break; + case 6: p = "language BC"; break; + case 7: p = "language AB"; break; + default: p = "undefined"; break; + } + CX18_INFO_DEV(sd, "Preferred audio mode: %s\n", p); + + if ((audio_config & 0xf) == 0xf) { + switch ((afc0 >> 3) & 0x1) { + case 0: p = "system DK"; break; + case 1: p = "system L"; break; + } + CX18_INFO_DEV(sd, "Selected 65 MHz format: %s\n", p); + + switch (afc0 & 0x7) { + case 0: p = "Chroma"; break; + case 1: p = "BTSC"; break; + case 2: p = "EIAJ"; break; + case 3: p = "A2-M"; break; + case 4: p = "autodetect"; break; + default: p = "undefined"; break; + } + CX18_INFO_DEV(sd, "Selected 45 MHz format: %s\n", p); + } +} + +static int cx18_av_log_status(struct v4l2_subdev *sd) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + log_video_status(cx); + log_audio_status(cx); + return 0; +} + +static inline int cx18_av_dbg_match(const struct v4l2_dbg_match *match) +{ + return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 1; +} + +static int cx18_av_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + + if (cx18_av_dbg_match(&chip->match)) { + chip->ident = state->id; + chip->revision = state->rev; + } + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cx18_av_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + + if (!cx18_av_dbg_match(®->match)) + return -EINVAL; + if ((reg->reg & 0x3) != 0) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + reg->size = 4; + reg->val = cx18_av_read4(cx, reg->reg & 0x00000ffc); + return 0; +} + +static int cx18_av_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + + if (!cx18_av_dbg_match(®->match)) + return -EINVAL; + if ((reg->reg & 0x3) != 0) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + cx18_av_write4(cx, reg->reg & 0x00000ffc, reg->val); + return 0; +} +#endif + +static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = { + .s_ctrl = cx18_av_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops cx18_av_general_ops = { + .g_chip_ident = cx18_av_g_chip_ident, + .log_status = cx18_av_log_status, + .load_fw = cx18_av_load_fw, + .reset = cx18_av_reset, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, + .s_std = cx18_av_s_std, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = cx18_av_g_register, + .s_register = cx18_av_s_register, +#endif +}; + +static const struct v4l2_subdev_tuner_ops cx18_av_tuner_ops = { + .s_radio = cx18_av_s_radio, + .s_frequency = cx18_av_s_frequency, + .g_tuner = cx18_av_g_tuner, + .s_tuner = cx18_av_s_tuner, +}; + +static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = { + .s_clock_freq = cx18_av_s_clock_freq, + .s_routing = cx18_av_s_audio_routing, +}; + +static const struct v4l2_subdev_video_ops cx18_av_video_ops = { + .s_routing = cx18_av_s_video_routing, + .s_stream = cx18_av_s_stream, + .s_mbus_fmt = cx18_av_s_mbus_fmt, +}; + +static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = { + .decode_vbi_line = cx18_av_decode_vbi_line, + .g_sliced_fmt = cx18_av_g_sliced_fmt, + .s_sliced_fmt = cx18_av_s_sliced_fmt, + .s_raw_fmt = cx18_av_s_raw_fmt, +}; + +static const struct v4l2_subdev_ops cx18_av_ops = { + .core = &cx18_av_general_ops, + .tuner = &cx18_av_tuner_ops, + .audio = &cx18_av_audio_ops, + .video = &cx18_av_video_ops, + .vbi = &cx18_av_vbi_ops, +}; + +int cx18_av_probe(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_subdev *sd; + int err; + + state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff; + state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO) + ? V4L2_IDENT_CX23418_843 : V4L2_IDENT_UNKNOWN; + + state->vid_input = CX18_AV_COMPOSITE7; + state->aud_input = CX18_AV_AUDIO8; + state->audclk_freq = 48000; + state->audmode = V4L2_TUNER_MODE_LANG1; + state->slicer_line_delay = 0; + state->slicer_line_offset = (10 + state->slicer_line_delay - 2); + + sd = &state->sd; + v4l2_subdev_init(sd, &cx18_av_ops); + v4l2_set_subdevdata(sd, cx); + snprintf(sd->name, sizeof(sd->name), + "%s %03x", cx->v4l2_dev.name, (state->rev >> 4)); + sd->grp_id = CX18_HW_418_AV; + v4l2_ctrl_handler_init(&state->hdl, 9); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, + V4L2_CID_CONTRAST, 0, 127, 1, 64); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, + V4L2_CID_SATURATION, 0, 127, 1, 64); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + + state->volume = v4l2_ctrl_new_std(&state->hdl, + &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, + 0, 65535, 65535 / 100, 0); + v4l2_ctrl_new_std(&state->hdl, + &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, + 0, 1, 1, 0); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, + V4L2_CID_AUDIO_BALANCE, + 0, 65535, 65535 / 100, 32768); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, + V4L2_CID_AUDIO_BASS, + 0, 65535, 65535 / 100, 32768); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, + V4L2_CID_AUDIO_TREBLE, + 0, 65535, 65535 / 100, 32768); + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + return err; + } + err = v4l2_device_register_subdev(&cx->v4l2_dev, sd); + if (err) + v4l2_ctrl_handler_free(&state->hdl); + else + cx18_av_init(cx); + return err; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-core.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-core.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,391 @@ +/* + * cx18 ADEC header + * + * Derived from cx25840-core.h + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef _CX18_AV_CORE_H_ +#define _CX18_AV_CORE_H_ + +#include +#include + +struct cx18; + +enum cx18_av_video_input { + /* Composite video inputs In1-In8 */ + CX18_AV_COMPOSITE1 = 1, + CX18_AV_COMPOSITE2, + CX18_AV_COMPOSITE3, + CX18_AV_COMPOSITE4, + CX18_AV_COMPOSITE5, + CX18_AV_COMPOSITE6, + CX18_AV_COMPOSITE7, + CX18_AV_COMPOSITE8, + + /* S-Video inputs consist of one luma input (In1-In8) ORed with one + chroma input (In5-In8) */ + CX18_AV_SVIDEO_LUMA1 = 0x10, + CX18_AV_SVIDEO_LUMA2 = 0x20, + CX18_AV_SVIDEO_LUMA3 = 0x30, + CX18_AV_SVIDEO_LUMA4 = 0x40, + CX18_AV_SVIDEO_LUMA5 = 0x50, + CX18_AV_SVIDEO_LUMA6 = 0x60, + CX18_AV_SVIDEO_LUMA7 = 0x70, + CX18_AV_SVIDEO_LUMA8 = 0x80, + CX18_AV_SVIDEO_CHROMA4 = 0x400, + CX18_AV_SVIDEO_CHROMA5 = 0x500, + CX18_AV_SVIDEO_CHROMA6 = 0x600, + CX18_AV_SVIDEO_CHROMA7 = 0x700, + CX18_AV_SVIDEO_CHROMA8 = 0x800, + + /* S-Video aliases for common luma/chroma combinations */ + CX18_AV_SVIDEO1 = 0x510, + CX18_AV_SVIDEO2 = 0x620, + CX18_AV_SVIDEO3 = 0x730, + CX18_AV_SVIDEO4 = 0x840, + + /* Component Video inputs consist of one luma input (In1-In8) ORed + with a red chroma (In4-In6) and blue chroma input (In7-In8) */ + CX18_AV_COMPONENT_LUMA1 = 0x1000, + CX18_AV_COMPONENT_LUMA2 = 0x2000, + CX18_AV_COMPONENT_LUMA3 = 0x3000, + CX18_AV_COMPONENT_LUMA4 = 0x4000, + CX18_AV_COMPONENT_LUMA5 = 0x5000, + CX18_AV_COMPONENT_LUMA6 = 0x6000, + CX18_AV_COMPONENT_LUMA7 = 0x7000, + CX18_AV_COMPONENT_LUMA8 = 0x8000, + CX18_AV_COMPONENT_R_CHROMA4 = 0x40000, + CX18_AV_COMPONENT_R_CHROMA5 = 0x50000, + CX18_AV_COMPONENT_R_CHROMA6 = 0x60000, + CX18_AV_COMPONENT_B_CHROMA7 = 0x700000, + CX18_AV_COMPONENT_B_CHROMA8 = 0x800000, + + /* Component Video aliases for common combinations */ + CX18_AV_COMPONENT1 = 0x861000, +}; + +enum cx18_av_audio_input { + /* Audio inputs: serial or In4-In8 */ + CX18_AV_AUDIO_SERIAL1, + CX18_AV_AUDIO_SERIAL2, + CX18_AV_AUDIO4 = 4, + CX18_AV_AUDIO5, + CX18_AV_AUDIO6, + CX18_AV_AUDIO7, + CX18_AV_AUDIO8, +}; + +struct cx18_av_state { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *volume; + int radio; + v4l2_std_id std; + enum cx18_av_video_input vid_input; + enum cx18_av_audio_input aud_input; + u32 audclk_freq; + int audmode; + u32 id; + u32 rev; + int is_initialized; + + /* + * The VBI slicer starts operating and counting lines, beginning at + * slicer line count of 1, at D lines after the deassertion of VRESET. + * This staring field line, S, is 6 (& 319) or 10 (& 273) for 625 or 525 + * line systems respectively. Sliced ancillary data captured on VBI + * slicer line M is inserted after the VBI slicer is done with line M, + * when VBI slicer line count is N = M+1. Thus when the VBI slicer + * reports a VBI slicer line number with ancillary data, the IDID0 byte + * indicates VBI slicer line N. The actual field line that the captured + * data comes from is + * + * L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2). + * + * L is the line in the field, not frame, from which the VBI data came. + * N is the line reported by the slicer in the ancillary data. + * D is the slicer_line_delay value programmed into register 0x47f. + * S is 6 for 625 line systems or 10 for 525 line systems + * (S+D-2) is the slicer_line_offset used to convert slicer reported + * line counts to actual field lines. + */ + int slicer_line_delay; + int slicer_line_offset; +}; + + +/* Registers */ +#define CXADEC_CHIP_TYPE_TIGER 0x837 +#define CXADEC_CHIP_TYPE_MAKO 0x843 + +#define CXADEC_HOST_REG1 0x000 +#define CXADEC_HOST_REG2 0x001 + +#define CXADEC_CHIP_CTRL 0x100 +#define CXADEC_AFE_CTRL 0x104 +#define CXADEC_PLL_CTRL1 0x108 +#define CXADEC_VID_PLL_FRAC 0x10C +#define CXADEC_AUX_PLL_FRAC 0x110 +#define CXADEC_PIN_CTRL1 0x114 +#define CXADEC_PIN_CTRL2 0x118 +#define CXADEC_PIN_CFG1 0x11C +#define CXADEC_PIN_CFG2 0x120 + +#define CXADEC_PIN_CFG3 0x124 +#define CXADEC_I2S_MCLK 0x127 + +#define CXADEC_AUD_LOCK1 0x128 +#define CXADEC_AUD_LOCK2 0x12C +#define CXADEC_POWER_CTRL 0x130 +#define CXADEC_AFE_DIAG_CTRL1 0x134 +#define CXADEC_AFE_DIAG_CTRL2 0x138 +#define CXADEC_AFE_DIAG_CTRL3 0x13C +#define CXADEC_PLL_DIAG_CTRL 0x140 +#define CXADEC_TEST_CTRL1 0x144 +#define CXADEC_TEST_CTRL2 0x148 +#define CXADEC_BIST_STAT 0x14C +#define CXADEC_DLL1_DIAG_CTRL 0x158 +#define CXADEC_DLL2_DIAG_CTRL 0x15C + +/* IR registers */ +#define CXADEC_IR_CTRL_REG 0x200 +#define CXADEC_IR_TXCLK_REG 0x204 +#define CXADEC_IR_RXCLK_REG 0x208 +#define CXADEC_IR_CDUTY_REG 0x20C +#define CXADEC_IR_STAT_REG 0x210 +#define CXADEC_IR_IRQEN_REG 0x214 +#define CXADEC_IR_FILTER_REG 0x218 +#define CXADEC_IR_FIFO_REG 0x21C + +/* Video Registers */ +#define CXADEC_MODE_CTRL 0x400 +#define CXADEC_OUT_CTRL1 0x404 +#define CXADEC_OUT_CTRL2 0x408 +#define CXADEC_GEN_STAT 0x40C +#define CXADEC_INT_STAT_MASK 0x410 +#define CXADEC_LUMA_CTRL 0x414 + +#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414 +#define CXADEC_CONTRAST_CTRL_BYTE 0x415 +#define CXADEC_LUMA_CTRL_BYTE_3 0x416 + +#define CXADEC_HSCALE_CTRL 0x418 +#define CXADEC_VSCALE_CTRL 0x41C + +#define CXADEC_CHROMA_CTRL 0x420 + +#define CXADEC_USAT_CTRL_BYTE 0x420 +#define CXADEC_VSAT_CTRL_BYTE 0x421 +#define CXADEC_HUE_CTRL_BYTE 0x422 + +#define CXADEC_VBI_LINE_CTRL1 0x424 +#define CXADEC_VBI_LINE_CTRL2 0x428 +#define CXADEC_VBI_LINE_CTRL3 0x42C +#define CXADEC_VBI_LINE_CTRL4 0x430 +#define CXADEC_VBI_LINE_CTRL5 0x434 +#define CXADEC_VBI_FC_CFG 0x438 +#define CXADEC_VBI_MISC_CFG1 0x43C +#define CXADEC_VBI_MISC_CFG2 0x440 +#define CXADEC_VBI_PAY1 0x444 +#define CXADEC_VBI_PAY2 0x448 +#define CXADEC_VBI_CUST1_CFG1 0x44C +#define CXADEC_VBI_CUST1_CFG2 0x450 +#define CXADEC_VBI_CUST1_CFG3 0x454 +#define CXADEC_VBI_CUST2_CFG1 0x458 +#define CXADEC_VBI_CUST2_CFG2 0x45C +#define CXADEC_VBI_CUST2_CFG3 0x460 +#define CXADEC_VBI_CUST3_CFG1 0x464 +#define CXADEC_VBI_CUST3_CFG2 0x468 +#define CXADEC_VBI_CUST3_CFG3 0x46C +#define CXADEC_HORIZ_TIM_CTRL 0x470 +#define CXADEC_VERT_TIM_CTRL 0x474 +#define CXADEC_SRC_COMB_CFG 0x478 +#define CXADEC_CHROMA_VBIOFF_CFG 0x47C +#define CXADEC_FIELD_COUNT 0x480 +#define CXADEC_MISC_TIM_CTRL 0x484 +#define CXADEC_DFE_CTRL1 0x488 +#define CXADEC_DFE_CTRL2 0x48C +#define CXADEC_DFE_CTRL3 0x490 +#define CXADEC_PLL_CTRL2 0x494 +#define CXADEC_HTL_CTRL 0x498 +#define CXADEC_COMB_CTRL 0x49C +#define CXADEC_CRUSH_CTRL 0x4A0 +#define CXADEC_SOFT_RST_CTRL 0x4A4 +#define CXADEC_MV_DT_CTRL2 0x4A8 +#define CXADEC_MV_DT_CTRL3 0x4AC +#define CXADEC_MISC_DIAG_CTRL 0x4B8 + +#define CXADEC_DL_CTL 0x800 +#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */ +#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */ +#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */ +#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */ + +#define CXADEC_STD_DET_STATUS 0x804 + +#define CXADEC_STD_DET_CTL 0x808 +#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */ +#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */ + +#define CXADEC_DW8051_INT 0x80C +#define CXADEC_GENERAL_CTL 0x810 +#define CXADEC_AAGC_CTL 0x814 +#define CXADEC_IF_SRC_CTL 0x818 +#define CXADEC_ANLOG_DEMOD_CTL 0x81C +#define CXADEC_ROT_FREQ_CTL 0x820 +#define CXADEC_FM1_CTL 0x824 +#define CXADEC_PDF_CTL 0x828 +#define CXADEC_DFT1_CTL1 0x82C +#define CXADEC_DFT1_CTL2 0x830 +#define CXADEC_DFT_STATUS 0x834 +#define CXADEC_DFT2_CTL1 0x838 +#define CXADEC_DFT2_CTL2 0x83C +#define CXADEC_DFT2_STATUS 0x840 +#define CXADEC_DFT3_CTL1 0x844 +#define CXADEC_DFT3_CTL2 0x848 +#define CXADEC_DFT3_STATUS 0x84C +#define CXADEC_DFT4_CTL1 0x850 +#define CXADEC_DFT4_CTL2 0x854 +#define CXADEC_DFT4_STATUS 0x858 +#define CXADEC_AM_MTS_DET 0x85C +#define CXADEC_ANALOG_MUX_CTL 0x860 +#define CXADEC_DIG_PLL_CTL1 0x864 +#define CXADEC_DIG_PLL_CTL2 0x868 +#define CXADEC_DIG_PLL_CTL3 0x86C +#define CXADEC_DIG_PLL_CTL4 0x870 +#define CXADEC_DIG_PLL_CTL5 0x874 +#define CXADEC_DEEMPH_GAIN_CTL 0x878 +#define CXADEC_DEEMPH_COEF1 0x87C +#define CXADEC_DEEMPH_COEF2 0x880 +#define CXADEC_DBX1_CTL1 0x884 +#define CXADEC_DBX1_CTL2 0x888 +#define CXADEC_DBX1_STATUS 0x88C +#define CXADEC_DBX2_CTL1 0x890 +#define CXADEC_DBX2_CTL2 0x894 +#define CXADEC_DBX2_STATUS 0x898 +#define CXADEC_AM_FM_DIFF 0x89C + +/* NICAM registers go here */ +#define CXADEC_NICAM_STATUS 0x8C8 +#define CXADEC_DEMATRIX_CTL 0x8CC + +#define CXADEC_PATH1_CTL1 0x8D0 +#define CXADEC_PATH1_VOL_CTL 0x8D4 +#define CXADEC_PATH1_EQ_CTL 0x8D8 +#define CXADEC_PATH1_SC_CTL 0x8DC + +#define CXADEC_PATH2_CTL1 0x8E0 +#define CXADEC_PATH2_VOL_CTL 0x8E4 +#define CXADEC_PATH2_EQ_CTL 0x8E8 +#define CXADEC_PATH2_SC_CTL 0x8EC + +#define CXADEC_SRC_CTL 0x8F0 +#define CXADEC_SRC_LF_COEF 0x8F4 +#define CXADEC_SRC1_CTL 0x8F8 +#define CXADEC_SRC2_CTL 0x8FC +#define CXADEC_SRC3_CTL 0x900 +#define CXADEC_SRC4_CTL 0x904 +#define CXADEC_SRC5_CTL 0x908 +#define CXADEC_SRC6_CTL 0x90C + +#define CXADEC_BASEBAND_OUT_SEL 0x910 +#define CXADEC_I2S_IN_CTL 0x914 +#define CXADEC_I2S_OUT_CTL 0x918 +#define CXADEC_AC97_CTL 0x91C +#define CXADEC_QAM_PDF 0x920 +#define CXADEC_QAM_CONST_DEC 0x924 +#define CXADEC_QAM_ROTATOR_FREQ 0x948 + +/* Bit definitions / settings used in Mako Audio */ +#define CXADEC_PREF_MODE_MONO_LANGA 0 +#define CXADEC_PREF_MODE_MONO_LANGB 1 +#define CXADEC_PREF_MODE_MONO_LANGC 2 +#define CXADEC_PREF_MODE_FALLBACK 3 +#define CXADEC_PREF_MODE_STEREO 4 +#define CXADEC_PREF_MODE_DUAL_LANG_AC 5 +#define CXADEC_PREF_MODE_DUAL_LANG_BC 6 +#define CXADEC_PREF_MODE_DUAL_LANG_AB 7 + + +#define CXADEC_DETECT_STEREO 1 +#define CXADEC_DETECT_DUAL 2 +#define CXADEC_DETECT_TRI 4 +#define CXADEC_DETECT_SAP 0x10 +#define CXADEC_DETECT_NO_SIGNAL 0xFF + +#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */ +#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */ +#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2 +#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3 +#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */ +#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */ +#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6 +#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7 +#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */ +#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */ +#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */ + +static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct cx18_av_state, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd; +} + +/* ----------------------------------------------------------------------- */ +/* cx18_av-core.c */ +int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); +int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); +int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value); +int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask); +int cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, + u32 mask); +u8 cx18_av_read(struct cx18 *cx, u16 addr); +u32 cx18_av_read4(struct cx18 *cx, u16 addr); +int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); +int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); +void cx18_av_std_setup(struct cx18 *cx); + +int cx18_av_probe(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-firmware.c */ +int cx18_av_loadfw(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-audio.c */ +int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq); +void cx18_av_audio_set_path(struct cx18 *cx); +extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops; + +/* ----------------------------------------------------------------------- */ +/* cx18_av-vbi.c */ +int cx18_av_decode_vbi_line(struct v4l2_subdev *sd, + struct v4l2_decode_vbi_line *vbi); +int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt); +int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); +int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-firmware.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,223 @@ +/* + * cx18 ADEC firmware functions + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" +#include "cx18-io.h" +#include + +#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AI1_MUX_MASK 0x30 +#define CX18_AI1_MUX_I2S1 0x00 +#define CX18_AI1_MUX_I2S2 0x10 +#define CX18_AI1_MUX_843_I2S 0x20 +#define CX18_AI1_MUX_INVALID 0x30 + +#define FWFILE "v4l-cx23418-dig.fw" + +static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw) +{ + struct v4l2_subdev *sd = &cx->av_state.sd; + int ret = 0; + const u8 *data; + u32 size; + int addr; + u32 expected, dl_control; + + /* Ensure we put the 8051 in reset and enable firmware upload mode */ + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + do { + dl_control &= 0x00ffffff; + dl_control |= 0x0f000000; + cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control); + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + } while ((dl_control & 0xff000000) != 0x0f000000); + + /* Read and auto increment until at address 0x0000 */ + while (dl_control & 0x3fff) + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + + data = fw->data; + size = fw->size; + for (addr = 0; addr < size; addr++) { + dl_control &= 0xffff3fff; /* ignore top 2 bits of address */ + expected = 0x0f000000 | ((u32)data[addr] << 16) | addr; + if (expected != dl_control) { + CX18_ERR_DEV(sd, "verification of %s firmware load " + "failed: expected %#010x got %#010x\n", + FWFILE, expected, dl_control); + ret = -EIO; + break; + } + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + } + if (ret == 0) + CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n", + FWFILE, size); + return ret; +} + +int cx18_av_loadfw(struct cx18 *cx) +{ + struct v4l2_subdev *sd = &cx->av_state.sd; + const struct firmware *fw = NULL; + u32 size; + u32 u, v; + const u8 *ptr; + int i; + int retries1 = 0; + + if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) { + CX18_ERR_DEV(sd, "unable to open firmware %s\n", FWFILE); + return -EINVAL; + } + + /* The firmware load often has byte errors, so allow for several + retries, both at byte level and at the firmware load level. */ + while (retries1 < 5) { + cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000, + 0x00008430, 0xffffffff); /* cx25843 */ + cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff); + + /* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */ + cx18_av_write4_expect(cx, 0x8100, 0x00010000, + 0x00008430, 0xffffffff); /* cx25843 */ + + /* Put the 8051 in reset and enable firmware upload */ + cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000); + + ptr = fw->data; + size = fw->size; + + for (i = 0; i < size; i++) { + u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16); + u32 value = 0; + int retries2; + int unrec_err = 0; + + for (retries2 = 0; retries2 < CX18_MAX_MMIO_WR_RETRIES; + retries2++) { + cx18_av_write4_noretry(cx, CXADEC_DL_CTL, + dl_control); + udelay(10); + value = cx18_av_read4(cx, CXADEC_DL_CTL); + if (value == dl_control) + break; + /* Check if we can correct the byte by changing + the address. We can only write the lower + address byte of the address. */ + if ((value & 0x3F00) != (dl_control & 0x3F00)) { + unrec_err = 1; + break; + } + } + if (unrec_err || retries2 >= CX18_MAX_MMIO_WR_RETRIES) + break; + } + if (i == size) + break; + retries1++; + } + if (retries1 >= 5) { + CX18_ERR_DEV(sd, "unable to load firmware %s\n", FWFILE); + release_firmware(fw); + return -EIO; + } + + cx18_av_write4_expect(cx, CXADEC_DL_CTL, + 0x03000000 | fw->size, 0x03000000, 0x13000000); + + CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size); + + if (cx18_av_verifyfw(cx, fw) == 0) + cx18_av_write4_expect(cx, CXADEC_DL_CTL, + 0x13000000 | fw->size, 0x13000000, 0x13000000); + + /* Output to the 416 */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000); + + /* Audio input control 1 set to Sony mode */ + /* Audio output input 2 is 0 for slave operation input */ + /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ + /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge + after WS transition for first bit of audio word. */ + cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0); + + /* Audio output control 1 is set to Sony mode */ + /* Audio output control 2 is set to 1 for master mode */ + /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ + /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge + after WS transition for first bit of audio word. */ + /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT + are generated) */ + cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0); + + /* set alt I2s master clock to /0x16 and enable alt divider i2s + passthrough */ + cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687); + + cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6, + 0x3F00FFFF); + /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */ + + /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */ + /* Register 0x09CC is defined by the Merlin firmware, and doesn't + have a name in the spec. */ + cx18_av_write4(cx, 0x09CC, 1); + + v = cx18_read_reg(cx, CX18_AUDIO_ENABLE); + /* If bit 11 is 1, clear bit 10 */ + if (v & 0x800) + cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE, + 0, 0x400); + + /* Toggle the AI1 MUX */ + v = cx18_read_reg(cx, CX18_AUDIO_ENABLE); + u = v & CX18_AI1_MUX_MASK; + v &= ~CX18_AI1_MUX_MASK; + if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) { + /* Switch to I2S1 */ + v |= CX18_AI1_MUX_I2S1; + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + /* Switch back to the A/V decoder core I2S output */ + v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S; + } else { + /* Switch to the A/V decoder core I2S output */ + v |= CX18_AI1_MUX_843_I2S; + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + /* Switch back to I2S1 or I2S2 */ + v = (v & ~CX18_AI1_MUX_MASK) | u; + } + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + + /* Enable WW auto audio standard detection */ + v = cx18_av_read4(cx, CXADEC_STD_DET_CTL); + v |= 0xFF; /* Auto by default */ + v |= 0x400; /* Stereo by default */ + v |= 0x14000000; + cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF); + + release_firmware(fw); + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-av-vbi.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,311 @@ +/* + * cx18 ADEC VBI functions + * + * Derived from cx25840-vbi.c + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#include "cx18-driver.h" + +/* + * For sliced VBI output, we set up to use VIP-1.1, 8-bit mode, + * NN counts 1 byte Dwords, an IDID with the VBI line # in it. + * Thus, according to the VIP-2 Spec, our VBI ancillary data lines + * (should!) look like: + * 4 byte EAV code: 0xff 0x00 0x00 0xRP + * unknown number of possible idle bytes + * 3 byte Anc data preamble: 0x00 0xff 0xff + * 1 byte data identifier: ne010iii (parity bits, 010, DID bits) + * 1 byte secondary data id: nessssss (parity bits, SDID bits) + * 1 byte data word count: necccccc (parity bits, NN Dword count) + * 2 byte Internal DID: VBI-line-# 0x80 + * NN data bytes + * 1 byte checksum + * Fill bytes needed to fil out to 4*NN bytes of payload + * + * The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, & + * in the vertical blanking interval are: + * 0xb0 (Task 0 VerticalBlank HorizontalBlank 0 0 0 0) + * 0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0) + * + * Since the V bit is only allowed to toggle in the EAV RP code, just + * before the first active region line and for active lines, they are: + * 0x90 (Task 0 0 HorizontalBlank 0 0 0 0) + * 0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0) + * + * The user application DID bytes we care about are: + * 0x91 (1 0 010 0 !ActiveLine AncDataPresent) + * 0x55 (0 1 010 2ndField !ActiveLine AncDataPresent) + * + */ +static const u8 sliced_vbi_did[2] = { 0x91, 0x55 }; + +struct vbi_anc_data { + /* u8 eav[4]; */ + /* u8 idle[]; Variable number of idle bytes */ + u8 preamble[3]; + u8 did; + u8 sdid; + u8 data_count; + u8 idid[2]; + u8 payload[1]; /* data_count of payload */ + /* u8 checksum; */ + /* u8 fill[]; Variable number of fill bytes */ +}; + +static int odd_parity(u8 c) +{ + c ^= (c >> 4); + c ^= (c >> 2); + c ^= (c >> 1); + + return c & 1; +} + +static int decode_vps(u8 *dst, u8 *p) +{ + static const u8 biphase_tbl[] = { + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, + 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, + 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, + 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, + 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, + 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, + 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + }; + + u8 c, err = 0; + int i; + + for (i = 0; i < 2 * 13; i += 2) { + err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; + c = (biphase_tbl[p[i + 1]] & 0xf) | + ((biphase_tbl[p[i]] & 0xf) << 4); + dst[i / 2] = c; + } + + return err & 0xf0; +} + +int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + struct cx18_av_state *state = &cx->av_state; + static const u16 lcr2vbi[] = { + 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ + 0, V4L2_SLICED_WSS_625, 0, /* 4 */ + V4L2_SLICED_CAPTION_525, /* 6 */ + 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ + 0, 0, 0, 0 + }; + int is_pal = !(state->std & V4L2_STD_525_60); + int i; + + memset(svbi, 0, sizeof(*svbi)); + /* we're done if raw VBI is active */ + if ((cx18_av_read(cx, 0x404) & 0x10) == 0) + return 0; + + if (is_pal) { + for (i = 7; i <= 23; i++) { + u8 v = cx18_av_read(cx, 0x424 + i - 7); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } else { + for (i = 10; i <= 21; i++) { + u8 v = cx18_av_read(cx, 0x424 + i - 10); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } + return 0; +} + +int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + struct cx18_av_state *state = &cx->av_state; + + /* Setup standard */ + cx18_av_std_setup(cx); + + /* VBI Offset */ + cx18_av_write(cx, 0x47f, state->slicer_line_delay); + cx18_av_write(cx, 0x404, 0x2e); + return 0; +} + +int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + struct cx18_av_state *state = &cx->av_state; + int is_pal = !(state->std & V4L2_STD_525_60); + int i, x; + u8 lcr[24]; + + for (x = 0; x <= 23; x++) + lcr[x] = 0x00; + + /* Setup standard */ + cx18_av_std_setup(cx); + + /* Sliced VBI */ + cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */ + cx18_av_write(cx, 0x406, 0x13); + cx18_av_write(cx, 0x47f, state->slicer_line_delay); + + /* Force impossible lines to 0 */ + if (is_pal) { + for (i = 0; i <= 6; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } else { + for (i = 0; i <= 9; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + + for (i = 22; i <= 23; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } + + /* Build register values for requested service lines */ + for (i = 7; i <= 23; i++) { + for (x = 0; x <= 1; x++) { + switch (svbi->service_lines[1-x][i]) { + case V4L2_SLICED_TELETEXT_B: + lcr[i] |= 1 << (4 * x); + break; + case V4L2_SLICED_WSS_625: + lcr[i] |= 4 << (4 * x); + break; + case V4L2_SLICED_CAPTION_525: + lcr[i] |= 6 << (4 * x); + break; + case V4L2_SLICED_VPS: + lcr[i] |= 9 << (4 * x); + break; + } + } + } + + if (is_pal) { + for (x = 1, i = 0x424; i <= 0x434; i++, x++) + cx18_av_write(cx, i, lcr[6 + x]); + } else { + for (x = 1, i = 0x424; i <= 0x430; i++, x++) + cx18_av_write(cx, i, lcr[9 + x]); + for (i = 0x431; i <= 0x434; i++) + cx18_av_write(cx, i, 0); + } + + cx18_av_write(cx, 0x43c, 0x16); + /* Should match vblank set in cx18_av_std_setup() */ + cx18_av_write(cx, 0x474, is_pal ? 38 : 26); + return 0; +} + +int cx18_av_decode_vbi_line(struct v4l2_subdev *sd, + struct v4l2_decode_vbi_line *vbi) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + struct cx18_av_state *state = &cx->av_state; + struct vbi_anc_data *anc = (struct vbi_anc_data *)vbi->p; + u8 *p; + int did, sdid, l, err = 0; + + /* + * Check for the ancillary data header for sliced VBI + */ + if (anc->preamble[0] || + anc->preamble[1] != 0xff || anc->preamble[2] != 0xff || + (anc->did != sliced_vbi_did[0] && + anc->did != sliced_vbi_did[1])) { + vbi->line = vbi->type = 0; + return 0; + } + + did = anc->did; + sdid = anc->sdid & 0xf; + l = anc->idid[0] & 0x3f; + l += state->slicer_line_offset; + p = anc->payload; + + /* Decode the SDID set by the slicer */ + switch (sdid) { + case 1: + sdid = V4L2_SLICED_TELETEXT_B; + break; + case 4: + sdid = V4L2_SLICED_WSS_625; + break; + case 6: + sdid = V4L2_SLICED_CAPTION_525; + err = !odd_parity(p[0]) || !odd_parity(p[1]); + break; + case 9: + sdid = V4L2_SLICED_VPS; + if (decode_vps(p, p) != 0) + err = 1; + break; + default: + sdid = 0; + err = 1; + break; + } + + vbi->type = err ? 0 : sdid; + vbi->line = err ? 0 : l; + vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]); + vbi->p = p; + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-cards.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,638 @@ +/* + * cx18 functions to query card hardware + * + * Derived from ivtv-cards.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-av-core.h" +#include "cx18-i2c.h" +#include + +#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM) + +/********************** card configuration *******************************/ + +/* usual i2c tuner addresses to probe */ +static struct cx18_card_tuner_i2c cx18_i2c_std = { + .radio = { I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, 0x60, I2C_CLIENT_END }, +}; + +/* + * usual i2c tuner addresses to probe with additional demod address for + * an NXP TDA8295 at 0x42 (N.B. it can possibly be at 0x4b or 0x4c too). + */ +static struct cx18_card_tuner_i2c cx18_i2c_nxp = { + .radio = { I2C_CLIENT_END }, + .demod = { 0x42, 0x43, I2C_CLIENT_END }, + .tv = { 0x61, 0x60, I2C_CLIENT_END }, +}; + +/* Please add new PCI IDs to: http://pci-ids.ucw.cz/ + This keeps the PCI ID database up to date. Note that the entries + must be added under vendor 0x4444 (Conexant) as subsystem IDs. + New vendor IDs should still be added to the vendor ID list. */ + +/* Hauppauge HVR-1600 cards */ + +/* Note: for Hauppauge cards the tveeprom information is used instead + of PCI IDs */ +static const struct cx18_card cx18_card_hvr1600_esmt = { + .type = CX18_CARD_HVR_1600_ESMT, + .name = "Hauppauge HVR-1600", + .comment = "Simultaneous Digital and Analog TV capture supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_muxer = CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | + CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL | + CX18_HW_Z8F0811_IR_HAUP, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, + { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, + { CX18_CARD_INPUT_LINE_IN1, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, + { CX18_CARD_INPUT_LINE_IN2, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, + .ddr = { + /* ESMT M13S128324A-5B memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x44220e82, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 0, + }, + .gpio_init.initial_value = 0x3001, + .gpio_init.direction = 0x3001, + .gpio_i2c_slave_reset = { + .active_lo_mask = 0x3001, + .msecs_asserted = 10, + .msecs_recovery = 40, + .ir_reset_mask = 0x0001, + }, + .i2c = &cx18_i2c_std, +}; + +static const struct cx18_card cx18_card_hvr1600_s5h1411 = { + .type = CX18_CARD_HVR_1600_S5H1411, + .name = "Hauppauge HVR-1600", + .comment = "Simultaneous Digital and Analog TV capture supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_muxer = CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | + CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL | + CX18_HW_Z8F0811_IR_HAUP, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, + { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, + { CX18_CARD_INPUT_LINE_IN1, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, + { CX18_CARD_INPUT_LINE_IN2, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, + .ddr = { + /* ESMT M13S128324A-5B memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x44220e82, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 0, + }, + .gpio_init.initial_value = 0x3801, + .gpio_init.direction = 0x3801, + .gpio_i2c_slave_reset = { + .active_lo_mask = 0x3801, + .msecs_asserted = 10, + .msecs_recovery = 40, + .ir_reset_mask = 0x0001, + }, + .i2c = &cx18_i2c_nxp, +}; + +static const struct cx18_card cx18_card_hvr1600_samsung = { + .type = CX18_CARD_HVR_1600_SAMSUNG, + .name = "Hauppauge HVR-1600 (Preproduction)", + .comment = "Simultaneous Digital and Analog TV capture supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_muxer = CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | + CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL | + CX18_HW_Z8F0811_IR_HAUP, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, + { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, + { CX18_CARD_INPUT_LINE_IN1, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, + { CX18_CARD_INPUT_LINE_IN2, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, + .ddr = { + /* Samsung K4D263238G-VC33 memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x23230b73, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 2, + }, + .gpio_init.initial_value = 0x3001, + .gpio_init.direction = 0x3001, + .gpio_i2c_slave_reset = { + .active_lo_mask = 0x3001, + .msecs_asserted = 10, + .msecs_recovery = 40, + .ir_reset_mask = 0x0001, + }, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Compro VideoMate H900: note that this card is analog only! */ + +static const struct cx18_card_pci_info cx18_pci_h900[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_h900 = { + .type = CX18_CARD_COMPRO_H900, + .name = "Compro VideoMate H900", + .comment = "Analog TV capture supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, + CX18_AV_AUDIO_SERIAL1, 0 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX18_AV_AUDIO_SERIAL1, 0 }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .ddr = { + /* EtronTech EM6A9160TS-5G memory */ + .chip_config = 0x50003, + .refresh = 0x753, + .timing1 = 0x24330e84, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 0, + }, + .xceive_pin = 15, + .pci_list = cx18_pci_h900, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan MPC718: not working at the moment! */ + +static const struct cx18_card_pci_info cx18_pci_mpc718[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_mpc718 = { + .type = CX18_CARD_YUAN_MPC718, + .name = "Yuan MPC718 MiniPCI DVB-T/Analog", + .comment = "Experimenters needed for device to work well.\n" + "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_muxer = CX18_HW_GPIO_MUX, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | + CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, + { CX18_CARD_INPUT_SVIDEO2, 2, + CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, + }, + .tuners = { + /* XC3028 tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + /* FIXME - the FM radio is just a guess and driver doesn't use SIF */ + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, + .ddr = { + /* Hynix HY5DU283222B DDR RAM */ + .chip_config = 0x303, + .refresh = 0x3bd, + .timing1 = 0x36320966, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 2, + }, + .gpio_init.initial_value = 0x1, + .gpio_init.direction = 0x3, + /* FIXME - these GPIO's are just guesses */ + .gpio_audio_input = { .mask = 0x3, + .tuner = 0x1, + .linein = 0x3, + .radio = 0x1 }, + .xceive_pin = 0, + .pci_list = cx18_pci_mpc718, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* GoTView PCI */ + +static const struct cx18_card_pci_info cx18_pci_gotview_dvd3[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_GOTVIEW, 0x3343 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_gotview_dvd3 = { + .type = CX18_CARD_GOTVIEW_PCI_DVD3, + .name = "GoTView PCI DVD3 Hybrid", + .comment = "Experimenters needed for device to work well.\n" + "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_muxer = CX18_HW_GPIO_MUX, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | + CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, + { CX18_CARD_INPUT_SVIDEO2, 2, + CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, + }, + .tuners = { + /* XC3028 tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + /* FIXME - the FM radio is just a guess and driver doesn't use SIF */ + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, + .ddr = { + /* Hynix HY5DU283222B DDR RAM */ + .chip_config = 0x303, + .refresh = 0x3bd, + .timing1 = 0x36320966, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 2, + }, + .gpio_init.initial_value = 0x1, + .gpio_init.direction = 0x3, + + .gpio_audio_input = { .mask = 0x3, + .tuner = 0x1, + .linein = 0x2, + .radio = 0x1 }, + .xceive_pin = 0, + .pci_list = cx18_pci_gotview_dvd3, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Conexant Raptor PAL/SECAM: note that this card is analog only! */ + +static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_cnxt_raptor_pal = { + .type = CX18_CARD_CNXT_RAPTOR_PAL, + .name = "Conexant Raptor PAL/SECAM", + .comment = "Analog TV capture supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_muxer = CX18_HW_GPIO_MUX, + .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, + { CX18_CARD_INPUT_SVIDEO2, 2, + CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, + }, + .tuners = { + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 }, + .ddr = { + /* MT 46V16M16 memory */ + .chip_config = 0x50306, + .refresh = 0x753, + .timing1 = 0x33220953, + .timing2 = 0x09, + .tune_lane = 0, + .initial_emrs = 0, + }, + .gpio_init.initial_value = 0x1002, + .gpio_init.direction = 0xf002, + .gpio_audio_input = { .mask = 0xf002, + .tuner = 0x1002, /* LED D1 Tuner AF */ + .linein = 0x2000, /* LED D2 Line In 1 */ + .radio = 0x4002 }, /* LED D3 Tuner AF */ + .pci_list = cx18_pci_cnxt_raptor_pal, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Toshiba Qosmio laptop internal DVB-T/Analog Hybrid Tuner */ + +static const struct cx18_card_pci_info cx18_pci_toshiba_qosmio_dvbt[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_TOSHIBA, 0x0110 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = { + .type = CX18_CARD_TOSHIBA_QOSMIO_DVBT, + .name = "Toshiba Qosmio DVB-T/Analog", + .comment = "Experimenters and photos needed for device to work well.\n" + "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE6 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .ddr = { + .chip_config = 0x202, + .refresh = 0x3bb, + .timing1 = 0x33320a63, + .timing2 = 0x0a, + .tune_lane = 0, + .initial_emrs = 0x42, + }, + .xceive_pin = 15, + .pci_list = cx18_pci_toshiba_qosmio_dvbt, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Leadtek WinFast PVR2100 */ + +static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100 */ + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_leadtek_pvr2100 = { + .type = CX18_CARD_LEADTEK_PVR2100, + .name = "Leadtek WinFast PVR2100", + .comment = "Experimenters and photos needed for device to work well.\n" + "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_muxer = CX18_HW_GPIO_MUX, + .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX | + CX18_HW_GPIO_RESET_CTRL, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 }, + { CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + }, + .tuners = { + /* XC2028 tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, + .ddr = { + /* Pointer to proper DDR config values provided by Terry Wu */ + .chip_config = 0x303, + .refresh = 0x3bb, + .timing1 = 0x24220e83, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 0x2, + }, + .gpio_init.initial_value = 0x6, + .gpio_init.direction = 0x7, + .gpio_audio_input = { .mask = 0x7, + .tuner = 0x6, .linein = 0x2, .radio = 0x2 }, + .xceive_pin = 1, + .pci_list = cx18_pci_leadtek_pvr2100, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Leadtek WinFast DVR3100 H */ + +static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */ + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_leadtek_dvr3100h = { + .type = CX18_CARD_LEADTEK_DVR3100H, + .name = "Leadtek WinFast DVR3100 H", + .comment = "Simultaneous DVB-T and Analog capture supported,\n" + "\texcept when capturing Analog from the antenna input.\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_muxer = CX18_HW_GPIO_MUX, + .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX | + CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, + { CX18_CARD_INPUT_SVIDEO1, 1, + CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 }, + { CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + }, + .tuners = { + /* XC3028 tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, + .ddr = { + /* Pointer to proper DDR config values provided by Terry Wu */ + .chip_config = 0x303, + .refresh = 0x3bb, + .timing1 = 0x24220e83, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 0x2, + }, + .gpio_init.initial_value = 0x6, + .gpio_init.direction = 0x7, + .gpio_audio_input = { .mask = 0x7, + .tuner = 0x6, .linein = 0x2, .radio = 0x2 }, + .xceive_pin = 1, + .pci_list = cx18_pci_leadtek_dvr3100h, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +static const struct cx18_card *cx18_card_list[] = { + &cx18_card_hvr1600_esmt, + &cx18_card_hvr1600_samsung, + &cx18_card_h900, + &cx18_card_mpc718, + &cx18_card_cnxt_raptor_pal, + &cx18_card_toshiba_qosmio_dvbt, + &cx18_card_leadtek_pvr2100, + &cx18_card_leadtek_dvr3100h, + &cx18_card_gotview_dvd3, + &cx18_card_hvr1600_s5h1411 +}; + +const struct cx18_card *cx18_get_card(u16 index) +{ + if (index >= ARRAY_SIZE(cx18_card_list)) + return NULL; + return cx18_card_list[index]; +} + +int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input) +{ + const struct cx18_card_video_input *card_input = + cx->card->video_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "S-Video 1", + "S-Video 2", + "Composite 1", + "Composite 2", + "Component 1" + }; + + if (index >= cx->nof_inputs) + return -EINVAL; + input->index = index; + strlcpy(input->name, input_strs[card_input->video_type - 1], + sizeof(input->name)); + input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ? + V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); + input->audioset = (1 << cx->nof_audio_inputs) - 1; + input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? + cx->tuner_std : V4L2_STD_ALL; + return 0; +} + +int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio) +{ + const struct cx18_card_audio_input *aud_input = + cx->card->audio_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "Line In 1", + "Line In 2" + }; + + memset(audio, 0, sizeof(*audio)); + if (index >= cx->nof_audio_inputs) + return -EINVAL; + strlcpy(audio->name, input_strs[aud_input->audio_type - 1], + sizeof(audio->name)); + audio->index = index; + audio->capability = V4L2_AUDCAP_STEREO; + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-cards.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-cards.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-cards.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-cards.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,157 @@ +/* + * cx18 functions to query card hardware + * + * Derived from ivtv-cards.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +/* hardware flags */ +#define CX18_HW_TUNER (1 << 0) +#define CX18_HW_TVEEPROM (1 << 1) +#define CX18_HW_CS5345 (1 << 2) +#define CX18_HW_DVB (1 << 3) +#define CX18_HW_418_AV (1 << 4) +#define CX18_HW_GPIO_MUX (1 << 5) +#define CX18_HW_GPIO_RESET_CTRL (1 << 6) +#define CX18_HW_Z8F0811_IR_TX_HAUP (1 << 7) +#define CX18_HW_Z8F0811_IR_RX_HAUP (1 << 8) +#define CX18_HW_Z8F0811_IR_HAUP (CX18_HW_Z8F0811_IR_RX_HAUP | \ + CX18_HW_Z8F0811_IR_TX_HAUP) + +#define CX18_HW_IR_ANY (CX18_HW_Z8F0811_IR_RX_HAUP | \ + CX18_HW_Z8F0811_IR_TX_HAUP) + +/* video inputs */ +#define CX18_CARD_INPUT_VID_TUNER 1 +#define CX18_CARD_INPUT_SVIDEO1 2 +#define CX18_CARD_INPUT_SVIDEO2 3 +#define CX18_CARD_INPUT_COMPOSITE1 4 +#define CX18_CARD_INPUT_COMPOSITE2 5 +#define CX18_CARD_INPUT_COMPONENT1 6 + +/* audio inputs */ +#define CX18_CARD_INPUT_AUD_TUNER 1 +#define CX18_CARD_INPUT_LINE_IN1 2 +#define CX18_CARD_INPUT_LINE_IN2 3 + +#define CX18_CARD_MAX_VIDEO_INPUTS 6 +#define CX18_CARD_MAX_AUDIO_INPUTS 3 +#define CX18_CARD_MAX_TUNERS 2 + +/* V4L2 capability aliases */ +#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \ + V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) + +struct cx18_card_video_input { + u8 video_type; /* video input type */ + u8 audio_index; /* index in cx18_card_audio_input array */ + u32 video_input; /* hardware video input */ +}; + +struct cx18_card_audio_input { + u8 audio_type; /* audio input type */ + u32 audio_input; /* hardware audio input */ + u16 muxer_input; /* hardware muxer input for boards with a + multiplexer chip */ +}; + +struct cx18_card_pci_info { + u16 device; + u16 subsystem_vendor; + u16 subsystem_device; +}; + +/* GPIO definitions */ + +/* The mask is the set of bits used by the operation */ + +struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */ + u32 direction; /* DIR setting. Leave to 0 if no init is needed */ + u32 initial_value; +}; + +struct cx18_gpio_i2c_slave_reset { + u32 active_lo_mask; /* GPIO outputs that reset i2c chips when low */ + u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */ + int msecs_asserted; /* time period reset must remain asserted */ + int msecs_recovery; /* time after deassert for chips to be ready */ + u32 ir_reset_mask; /* GPIO to reset the Zilog Z8F0811 IR contoller */ +}; + +struct cx18_gpio_audio_input { /* select tuner/line in input */ + u32 mask; /* leave to 0 if not supported */ + u32 tuner; + u32 linein; + u32 radio; +}; + +struct cx18_card_tuner { + v4l2_std_id std; /* standard for which the tuner is suitable */ + int tuner; /* tuner ID (from tuner.h) */ +}; + +struct cx18_card_tuner_i2c { + unsigned short radio[2];/* radio tuner i2c address to probe */ + unsigned short demod[3];/* demodulator i2c address to probe */ + unsigned short tv[4]; /* tv tuner i2c addresses to probe */ +}; + +struct cx18_ddr { /* DDR config data */ + u32 chip_config; + u32 refresh; + u32 timing1; + u32 timing2; + u32 tune_lane; + u32 initial_emrs; +}; + +/* for card information/parameters */ +struct cx18_card { + int type; + char *name; + char *comment; + u32 v4l2_capabilities; + u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only + 1 dev allowed currently) */ + u32 hw_muxer; /* hardware used to multiplex audio input */ + u32 hw_all; /* all hardware used by the board */ + struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS]; + struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS]; + struct cx18_card_audio_input radio_input; + + /* GPIO card-specific settings */ + u8 xceive_pin; /* XCeive tuner GPIO reset pin */ + struct cx18_gpio_init gpio_init; + struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset; + struct cx18_gpio_audio_input gpio_audio_input; + + struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS]; + struct cx18_card_tuner_i2c *i2c; + + struct cx18_ddr ddr; + + /* list of device and subsystem vendor/devices that + correspond to this card type. */ + const struct cx18_card_pci_info *pci_list; +}; + +int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input); +int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input); +const struct cx18_card *cx18_get_card(u16 index); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-controls.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-controls.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-controls.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-controls.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,131 @@ +/* + * cx18 ioctl control functions + * + * Derived from ivtv-controls.c + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 +#include + +#include "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-ioctl.h" +#include "cx18-audio.h" +#include "cx18-mailbox.h" +#include "cx18-controls.h" + +static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) +{ + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); + int type = cxhdl->stream_type->val; + + if (atomic_read(&cx->ana_capturing) > 0) + return -EBUSY; + + if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV || + !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS || + type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD || + type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) { + /* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */ + cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE; + CX18_DEBUG_INFO("disabled insertion of sliced VBI data into " + "the MPEG stream\n"); + return 0; + } + + /* Allocate sliced VBI buffers if needed. */ + if (cx->vbi.sliced_mpeg_data[0] == NULL) { + int i; + + for (i = 0; i < CX18_VBI_FRAMES; i++) { + cx->vbi.sliced_mpeg_data[i] = + kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL); + if (cx->vbi.sliced_mpeg_data[i] == NULL) { + while (--i >= 0) { + kfree(cx->vbi.sliced_mpeg_data[i]); + cx->vbi.sliced_mpeg_data[i] = NULL; + } + cx->vbi.insert_mpeg = + V4L2_MPEG_STREAM_VBI_FMT_NONE; + CX18_WARN("Unable to allocate buffers for " + "sliced VBI data insertion\n"); + return -ENOMEM; + } + } + } + + cx->vbi.insert_mpeg = fmt; + CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS," + "when sliced VBI is enabled\n"); + + /* + * If our current settings have no lines set for capture, store a valid, + * default set of service lines to capture, in our current settings. + */ + if (cx18_get_service_set(cx->vbi.sliced_in) == 0) { + if (cx->is_60hz) + cx->vbi.sliced_in->service_set = + V4L2_SLICED_CAPTION_525; + else + cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; + cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz); + } + return 0; +} + +static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) +{ + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); + int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_mbus_framefmt fmt; + + /* fix videodecoder resolution */ + fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); + fmt.height = cxhdl->height; + fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); + return 0; +} + +static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) +{ + static const u32 freqs[3] = { 44100, 48000, 32000 }; + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); + + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (idx < ARRAY_SIZE(freqs)) + cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); + return 0; +} + +static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) +{ + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); + + cx->dualwatch_stereo_mode = val; + return 0; +} + +struct cx2341x_handler_ops cx18_cxhdl_ops = { + .s_audio_mode = cx18_s_audio_mode, + .s_audio_sampling_freq = cx18_s_audio_sampling_freq, + .s_video_encoding = cx18_s_video_encoding, + .s_stream_vbi_fmt = cx18_s_stream_vbi_fmt, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-controls.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-controls.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-controls.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-controls.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * cx18 ioctl control functions + * + * Derived from ivtv-controls.h + * + * Copyright (C) 2007 Hans Verkuil + + * 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, or + * (at your option) any later version. + + * 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 + */ + +extern struct cx2341x_handler_ops cx18_cxhdl_ops; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-driver.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-driver.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1356 @@ +/* + * cx18 driver initialization and card probing + * + * Derived from ivtv-driver.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-version.h" +#include "cx18-cards.h" +#include "cx18-i2c.h" +#include "cx18-irq.h" +#include "cx18-gpio.h" +#include "cx18-firmware.h" +#include "cx18-queue.h" +#include "cx18-streams.h" +#include "cx18-av-core.h" +#include "cx18-scb.h" +#include "cx18-mailbox.h" +#include "cx18-ioctl.h" +#include "cx18-controls.h" +#include "tuner-xc2028.h" + +#include + +/* If you have already X v4l cards, then set this to X. This way + the device numbers stay matched. Example: you have a WinTV card + without radio and a Compro H900 with. Normally this would give a + video1 device together with a radio0 device for the Compro. By + setting this to 1 you ensure that radio0 is now also radio1. */ +int cx18_first_minor; + +/* Callback for registering extensions */ +int (*cx18_ext_init)(struct cx18 *); +EXPORT_SYMBOL(cx18_ext_init); + +/* add your revision and whatnot here */ +static struct pci_device_id cx18_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, cx18_pci_tbl); + +static atomic_t cx18_instance = ATOMIC_INIT(0); + +/* Parameter declarations */ +static int cardtype[CX18_MAX_CARDS]; +static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static unsigned cardtype_c = 1; +static unsigned tuner_c = 1; +static unsigned radio_c = 1; +static char pal[] = "--"; +static char secam[] = "--"; +static char ntsc[] = "-"; + +/* Buffers */ +static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS; +static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; +static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS; +static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS; +static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS; +static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; + +static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE; +static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE; +static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE; +static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE; +static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE; + +static int enc_ts_bufs = -1; +static int enc_mpg_bufs = -1; +static int enc_idx_bufs = CX18_MAX_FW_MDLS_PER_STREAM; +static int enc_yuv_bufs = -1; +static int enc_vbi_bufs = -1; +static int enc_pcm_bufs = -1; + + +static int cx18_pci_latency = 1; + +static int mmio_ndelay; +static int retry_mmio = 1; + +int cx18_debug; + +module_param_array(tuner, int, &tuner_c, 0644); +module_param_array(radio, bool, &radio_c, 0644); +module_param_array(cardtype, int, &cardtype_c, 0644); +module_param_string(pal, pal, sizeof(pal), 0644); +module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); +module_param_named(debug, cx18_debug, int, 0644); +module_param(mmio_ndelay, int, 0644); +module_param(retry_mmio, int, 0644); +module_param(cx18_pci_latency, int, 0644); +module_param(cx18_first_minor, int, 0644); + +module_param(enc_ts_buffers, int, 0644); +module_param(enc_mpg_buffers, int, 0644); +module_param(enc_idx_buffers, int, 0644); +module_param(enc_yuv_buffers, int, 0644); +module_param(enc_vbi_buffers, int, 0644); +module_param(enc_pcm_buffers, int, 0644); + +module_param(enc_ts_bufsize, int, 0644); +module_param(enc_mpg_bufsize, int, 0644); +module_param(enc_idx_bufsize, int, 0644); +module_param(enc_yuv_bufsize, int, 0644); +module_param(enc_pcm_bufsize, int, 0644); + +module_param(enc_ts_bufs, int, 0644); +module_param(enc_mpg_bufs, int, 0644); +module_param(enc_idx_bufs, int, 0644); +module_param(enc_yuv_bufs, int, 0644); +module_param(enc_vbi_bufs, int, 0644); +module_param(enc_pcm_bufs, int, 0644); + +MODULE_PARM_DESC(tuner, "Tuner type selection,\n" + "\t\t\tsee tuner.h for values"); +MODULE_PARM_DESC(radio, + "Enable or disable the radio. Use only if autodetection\n" + "\t\t\tfails. 0 = disable, 1 = enable"); +MODULE_PARM_DESC(cardtype, + "Only use this option if your card is not detected properly.\n" + "\t\tSpecify card type:\n" + "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n" + "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n" + "\t\t\t 3 = Compro VideoMate H900\n" + "\t\t\t 4 = Yuan MPC718\n" + "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" + "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n" + "\t\t\t 7 = Leadtek WinFast PVR2100\n" + "\t\t\t 8 = Leadtek WinFast DVR3100 H\n" + "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n" + "\t\t\t 10 = Hauppauge HVR 1600 (S5H1411)\n" + "\t\t\t 0 = Autodetect (default)\n" + "\t\t\t-1 = Ignore this card\n\t\t"); +MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); +MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); +MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n" + "\t\t\t 4/0x0004: mailbox\n" + "\t\t\t 8/0x0008: dma\n" + "\t\t\t 16/0x0010: ioctl\n" + "\t\t\t 32/0x0020: file\n" + "\t\t\t 64/0x0040: i2c\n" + "\t\t\t128/0x0080: irq\n" + "\t\t\t256/0x0100: high volume\n"); +MODULE_PARM_DESC(cx18_pci_latency, + "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" + "\t\t\tDefault: Yes"); +MODULE_PARM_DESC(retry_mmio, + "(Deprecated) MMIO writes are now always checked and retried\n" + "\t\t\tEffectively: 1 [Yes]"); +MODULE_PARM_DESC(mmio_ndelay, + "(Deprecated) MMIO accesses are now never purposely delayed\n" + "\t\t\tEffectively: 0 ns"); +MODULE_PARM_DESC(enc_ts_buffers, + "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS)); +MODULE_PARM_DESC(enc_ts_bufsize, + "Size of an encoder TS buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE)); +MODULE_PARM_DESC(enc_ts_bufs, + "Number of encoder TS buffers\n" + "\t\t\tDefault is computed from other enc_ts_* parameters"); +MODULE_PARM_DESC(enc_mpg_buffers, + "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); +MODULE_PARM_DESC(enc_mpg_bufsize, + "Size of an encoder MPG buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE)); +MODULE_PARM_DESC(enc_mpg_bufs, + "Number of encoder MPG buffers\n" + "\t\t\tDefault is computed from other enc_mpg_* parameters"); +MODULE_PARM_DESC(enc_idx_buffers, + "(Deprecated) Encoder IDX buffer memory (MB)\n" + "\t\t\tIgnored, except 0 disables IDX buffer allocations\n" + "\t\t\tDefault: 1 [Enabled]"); +MODULE_PARM_DESC(enc_idx_bufsize, + "Size of an encoder IDX buffer (kB)\n" + "\t\t\tAllowed values are multiples of 1.5 kB rounded up\n" + "\t\t\t(multiples of size required for 64 index entries)\n" + "\t\t\tDefault: 2"); +MODULE_PARM_DESC(enc_idx_bufs, + "Number of encoder IDX buffers\n" + "\t\t\tDefault: " __stringify(CX18_MAX_FW_MDLS_PER_STREAM)); +MODULE_PARM_DESC(enc_yuv_buffers, + "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); +MODULE_PARM_DESC(enc_yuv_bufsize, + "Size of an encoder YUV buffer (kB)\n" + "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n" + "\t\t\t(multiples of size required for 32 screen lines)\n" + "\t\t\tDefault: 102"); +MODULE_PARM_DESC(enc_yuv_bufs, + "Number of encoder YUV buffers\n" + "\t\t\tDefault is computed from other enc_yuv_* parameters"); +MODULE_PARM_DESC(enc_vbi_buffers, + "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); +MODULE_PARM_DESC(enc_vbi_bufs, + "Number of encoder VBI buffers\n" + "\t\t\tDefault is computed from enc_vbi_buffers"); +MODULE_PARM_DESC(enc_pcm_buffers, + "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); +MODULE_PARM_DESC(enc_pcm_bufsize, + "Size of an encoder PCM buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE)); +MODULE_PARM_DESC(enc_pcm_bufs, + "Number of encoder PCM buffers\n" + "\t\t\tDefault is computed from other enc_pcm_* parameters"); + +MODULE_PARM_DESC(cx18_first_minor, + "Set device node number assigned to first card"); + +MODULE_AUTHOR("Hans Verkuil"); +MODULE_DESCRIPTION("CX23418 driver"); +MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); +MODULE_LICENSE("GPL"); + + +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + struct cx18 *dev = container_of(work, struct cx18, request_module_wk); + + /* Make sure cx18-alsa module is loaded */ + request_module("cx18-alsa"); + + /* Initialize cx18-alsa for this instance of the cx18 device */ + if (cx18_ext_init != NULL) + cx18_ext_init(dev); +} + +static void request_modules(struct cx18 *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); +} + +static void flush_request_modules(struct cx18 *dev) +{ + flush_work_sync(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#define flush_request_modules(dev) +#endif /* CONFIG_MODULES */ + +/* Generic utility functions */ +int cx18_msleep_timeout(unsigned int msecs, int intr) +{ + long int timeout = msecs_to_jiffies(msecs); + int sig; + + do { + set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + sig = intr ? signal_pending(current) : 0; + } while (!sig && timeout); + return sig; +} + +/* Release ioremapped memory */ +static void cx18_iounmap(struct cx18 *cx) +{ + if (cx == NULL) + return; + + /* Release io memory */ + if (cx->enc_mem != NULL) { + CX18_DEBUG_INFO("releasing enc_mem\n"); + iounmap(cx->enc_mem); + cx->enc_mem = NULL; + } +} + +static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len) +{ + int i; + + CX18_INFO("eeprom dump:\n"); + for (i = 0; i < len; i++) { + if (0 == (i % 16)) + CX18_INFO("eeprom %02x:", i); + printk(KERN_CONT " %02x", eedata[i]); + if (15 == (i % 16)) + printk(KERN_CONT "\n"); + } +} + +/* Hauppauge card? get values from tveeprom */ +void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) +{ + struct i2c_client c; + u8 eedata[256]; + + memset(&c, 0, sizeof(c)); + strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name)); + c.adapter = &cx->i2c_adap[0]; + c.addr = 0xA0 >> 1; + + memset(tv, 0, sizeof(*tv)); + if (tveeprom_read(&c, eedata, sizeof(eedata))) + return; + + switch (cx->card->type) { + case CX18_CARD_HVR_1600_ESMT: + case CX18_CARD_HVR_1600_SAMSUNG: + case CX18_CARD_HVR_1600_S5H1411: + tveeprom_hauppauge_analog(&c, tv, eedata); + break; + case CX18_CARD_YUAN_MPC718: + case CX18_CARD_GOTVIEW_PCI_DVD3: + tv->model = 0x718; + cx18_eeprom_dump(cx, eedata, sizeof(eedata)); + CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n", + eedata[2], eedata[1], eedata[4], eedata[3]); + break; + default: + tv->model = 0xffffffff; + cx18_eeprom_dump(cx, eedata, sizeof(eedata)); + break; + } +} + +static void cx18_process_eeprom(struct cx18 *cx) +{ + struct tveeprom tv; + + cx18_read_eeprom(cx, &tv); + + /* Many thanks to Steven Toth from Hauppauge for providing the + model numbers */ + /* Note: the Samsung memory models cannot be reliably determined + from the model number. Use the cardtype module option if you + have one of these preproduction models. */ + switch (tv.model) { + case 74301: /* Retail models */ + case 74321: + case 74351: /* OEM models */ + case 74361: + /* Digital side is s5h1411/tda18271 */ + cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411); + break; + case 74021: /* Retail models */ + case 74031: + case 74041: + case 74141: + case 74541: /* OEM models */ + case 74551: + case 74591: + case 74651: + case 74691: + case 74751: + case 74891: + /* Digital side is s5h1409/mxl5005s */ + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + break; + case 0x718: + return; + case 0xffffffff: + CX18_INFO("Unknown EEPROM encoding\n"); + return; + case 0: + CX18_ERR("Invalid EEPROM\n"); + return; + default: + CX18_ERR("Unknown model %d, defaulting to original HVR-1600 " + "(cardtype=1)\n", tv.model); + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + break; + } + + cx->v4l2_cap = cx->card->v4l2_capabilities; + cx->card_name = cx->card->name; + cx->card_i2c = cx->card->i2c; + + CX18_INFO("Autodetected %s\n", cx->card_name); + + if (tv.tuner_type == TUNER_ABSENT) + CX18_ERR("tveeprom cannot autodetect tuner!\n"); + + if (cx->options.tuner == -1) + cx->options.tuner = tv.tuner_type; + if (cx->options.radio == -1) + cx->options.radio = (tv.has_radio != 0); + + if (cx->std != 0) + /* user specified tuner standard */ + return; + + /* autodetect tuner standard */ +#define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \ + V4L2_STD_MN | \ + V4L2_STD_PAL_I | \ + V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \ + V4L2_STD_DK) + if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL) + == TVEEPROM_TUNER_FORMAT_ALL) { + CX18_DEBUG_INFO("Worldwide tuner detected\n"); + cx->std = V4L2_STD_ALL; + } else if (tv.tuner_formats & V4L2_STD_PAL) { + CX18_DEBUG_INFO("PAL tuner detected\n"); + cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + } else if (tv.tuner_formats & V4L2_STD_NTSC) { + CX18_DEBUG_INFO("NTSC tuner detected\n"); + cx->std |= V4L2_STD_NTSC_M; + } else if (tv.tuner_formats & V4L2_STD_SECAM) { + CX18_DEBUG_INFO("SECAM tuner detected\n"); + cx->std |= V4L2_STD_SECAM_L; + } else { + CX18_INFO("No tuner detected, default to NTSC-M\n"); + cx->std |= V4L2_STD_NTSC_M; + } +} + +static v4l2_std_id cx18_parse_std(struct cx18 *cx) +{ + switch (pal[0]) { + case '6': + return V4L2_STD_PAL_60; + case 'b': + case 'B': + case 'g': + case 'G': + return V4L2_STD_PAL_BG; + case 'h': + case 'H': + return V4L2_STD_PAL_H; + case 'n': + case 'N': + if (pal[1] == 'c' || pal[1] == 'C') + return V4L2_STD_PAL_Nc; + return V4L2_STD_PAL_N; + case 'i': + case 'I': + return V4L2_STD_PAL_I; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_PAL_DK; + case 'M': + case 'm': + return V4L2_STD_PAL_M; + case '-': + break; + default: + CX18_WARN("pal= argument not recognised\n"); + return 0; + } + + switch (secam[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_SECAM_DK; + case 'l': + case 'L': + if (secam[1] == 'C' || secam[1] == 'c') + return V4L2_STD_SECAM_LC; + return V4L2_STD_SECAM_L; + case '-': + break; + default: + CX18_WARN("secam= argument not recognised\n"); + return 0; + } + + switch (ntsc[0]) { + case 'm': + case 'M': + return V4L2_STD_NTSC_M; + case 'j': + case 'J': + return V4L2_STD_NTSC_M_JP; + case 'k': + case 'K': + return V4L2_STD_NTSC_M_KR; + case '-': + break; + default: + CX18_WARN("ntsc= argument not recognised\n"); + return 0; + } + + /* no match found */ + return 0; +} + +static void cx18_process_options(struct cx18 *cx) +{ + int i, j; + + cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */ + + cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */ + + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */ + + /* Ensure stream_buffers & stream_buf_size are valid */ + for (i = 0; i < CX18_MAX_STREAMS; i++) { + if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */ + cx->options.megabytes[i] <= 0 || /* User said 0 MB total */ + cx->stream_buf_size[i] <= 0) { /* User said buf size 0 */ + cx->options.megabytes[i] = 0; + cx->stream_buffers[i] = 0; + cx->stream_buf_size[i] = 0; + continue; + } + /* + * YUV is a special case where the stream_buf_size needs to be + * an integral multiple of 33.75 kB (storage for 32 screens + * lines to maintain alignment in case of lost buffers). + * + * IDX is a special case where the stream_buf_size should be + * an integral multiple of 1.5 kB (storage for 64 index entries + * to maintain alignment in case of lost buffers). + * + */ + if (i == CX18_ENC_STREAM_TYPE_YUV) { + cx->stream_buf_size[i] *= 1024; + cx->stream_buf_size[i] -= + (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE); + + if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE) + cx->stream_buf_size[i] = + CX18_UNIT_ENC_YUV_BUFSIZE; + } else if (i == CX18_ENC_STREAM_TYPE_IDX) { + cx->stream_buf_size[i] *= 1024; + cx->stream_buf_size[i] -= + (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE); + + if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE) + cx->stream_buf_size[i] = + CX18_UNIT_ENC_IDX_BUFSIZE; + } + /* + * YUV and IDX are special cases where the stream_buf_size is + * now in bytes. + * VBI is a special case where the stream_buf_size is fixed + * and already in bytes + */ + if (i == CX18_ENC_STREAM_TYPE_VBI || + i == CX18_ENC_STREAM_TYPE_YUV || + i == CX18_ENC_STREAM_TYPE_IDX) { + if (cx->stream_buffers[i] < 0) { + cx->stream_buffers[i] = + cx->options.megabytes[i] * 1024 * 1024 + / cx->stream_buf_size[i]; + } else { + /* N.B. This might round down to 0 */ + cx->options.megabytes[i] = + cx->stream_buffers[i] + * cx->stream_buf_size[i]/(1024 * 1024); + } + } else { + /* All other streams have stream_buf_size in kB here */ + if (cx->stream_buffers[i] < 0) { + cx->stream_buffers[i] = + cx->options.megabytes[i] * 1024 + / cx->stream_buf_size[i]; + } else { + /* N.B. This might round down to 0 */ + cx->options.megabytes[i] = + cx->stream_buffers[i] + * cx->stream_buf_size[i] / 1024; + } + /* convert from kB to bytes */ + cx->stream_buf_size[i] *= 1024; + } + CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, " + "%d bytes\n", i, cx->options.megabytes[i], + cx->stream_buffers[i], cx->stream_buf_size[i]); + } + + cx->options.cardtype = cardtype[cx->instance]; + cx->options.tuner = tuner[cx->instance]; + cx->options.radio = radio[cx->instance]; + + cx->std = cx18_parse_std(cx); + if (cx->options.cardtype == -1) { + CX18_INFO("Ignore card\n"); + return; + } + cx->card = cx18_get_card(cx->options.cardtype - 1); + if (cx->card) + CX18_INFO("User specified %s card\n", cx->card->name); + else if (cx->options.cardtype != 0) + CX18_ERR("Unknown user specified type, trying to autodetect card\n"); + if (cx->card == NULL) { + if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + CX18_INFO("Autodetected Hauppauge card\n"); + } + } + if (cx->card == NULL) { + for (i = 0; (cx->card = cx18_get_card(i)); i++) { + if (cx->card->pci_list == NULL) + continue; + for (j = 0; cx->card->pci_list[j].device; j++) { + if (cx->pci_dev->device != + cx->card->pci_list[j].device) + continue; + if (cx->pci_dev->subsystem_vendor != + cx->card->pci_list[j].subsystem_vendor) + continue; + if (cx->pci_dev->subsystem_device != + cx->card->pci_list[j].subsystem_device) + continue; + CX18_INFO("Autodetected %s card\n", cx->card->name); + goto done; + } + } + } +done: + + if (cx->card == NULL) { + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", + cx->pci_dev->vendor, cx->pci_dev->device); + CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n", + cx->pci_dev->subsystem_vendor, + cx->pci_dev->subsystem_device); + CX18_ERR("Defaulting to %s card\n", cx->card->name); + CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); + CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); + CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n"); + } + cx->v4l2_cap = cx->card->v4l2_capabilities; + cx->card_name = cx->card->name; + cx->card_i2c = cx->card->i2c; +} + +static int __devinit cx18_create_in_workq(struct cx18 *cx) +{ + snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", + cx->v4l2_dev.name); + cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0); + if (cx->in_work_queue == NULL) { + CX18_ERR("Unable to create incoming mailbox handler thread\n"); + return -ENOMEM; + } + return 0; +} + +static void __devinit cx18_init_in_work_orders(struct cx18 *cx) +{ + int i; + for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { + cx->in_work_order[i].cx = cx; + cx->in_work_order[i].str = cx->epu_debug_str; + INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler); + } +} + +/* Precondition: the cx18 structure has been memset to 0. Only + the dev and instance fields have been filled in. + No assumptions on the card type may be made here (see cx18_init_struct2 + for that). + */ +static int __devinit cx18_init_struct1(struct cx18 *cx) +{ + int ret; + + cx->base_addr = pci_resource_start(cx->pci_dev, 0); + + mutex_init(&cx->serialize_lock); + mutex_init(&cx->gpio_lock); + mutex_init(&cx->epu2apu_mb_lock); + mutex_init(&cx->epu2cpu_mb_lock); + + ret = cx18_create_in_workq(cx); + if (ret) + return ret; + + cx18_init_in_work_orders(cx); + + /* start counting open_id at 1 */ + cx->open_id = 1; + + /* Initial settings */ + cx->cxhdl.port = CX2341X_PORT_MEMORY; + cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; + cx->cxhdl.ops = &cx18_cxhdl_ops; + cx->cxhdl.func = cx18_api_func; + cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; + ret = cx2341x_handler_init(&cx->cxhdl, 50); + if (ret) + return ret; + cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl; + + cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val; + cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val; + cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val | + (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) | + (cx->cxhdl.video_median_filter_type->cur.val << 2); + + init_waitqueue_head(&cx->cap_w); + init_waitqueue_head(&cx->mb_apu_waitq); + init_waitqueue_head(&cx->mb_cpu_waitq); + init_waitqueue_head(&cx->dma_waitq); + + /* VBI */ + cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; + cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; + + /* IVTV style VBI insertion into MPEG streams */ + INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list); + INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list); + INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list); + list_add(&cx->vbi.sliced_mpeg_buf.list, + &cx->vbi.sliced_mpeg_mdl.buf_list); + return 0; +} + +/* Second initialization part. Here the card type has been + autodetected. */ +static void __devinit cx18_init_struct2(struct cx18 *cx) +{ + int i; + + for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++) + if (cx->card->video_inputs[i].video_type == 0) + break; + cx->nof_inputs = i; + for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++) + if (cx->card->audio_inputs[i].audio_type == 0) + break; + cx->nof_audio_inputs = i; + + /* Find tuner input */ + for (i = 0; i < cx->nof_inputs; i++) { + if (cx->card->video_inputs[i].video_type == + CX18_CARD_INPUT_VID_TUNER) + break; + } + if (i == cx->nof_inputs) + i = 0; + cx->active_input = i; + cx->audio_input = cx->card->video_inputs[i].audio_index; +} + +static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + u16 cmd; + unsigned char pci_latency; + + CX18_DEBUG_INFO("Enabling pci device\n"); + + if (pci_enable_device(pci_dev)) { + CX18_ERR("Can't enable device %d!\n", cx->instance); + return -EIO; + } + if (pci_set_dma_mask(pci_dev, 0xffffffff)) { + CX18_ERR("No suitable DMA available, card %d\n", cx->instance); + return -EIO; + } + if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) { + CX18_ERR("Cannot request encoder memory region, card %d\n", + cx->instance); + return -EIO; + } + + /* Enable bus mastering and memory mapped IO for the CX23418 */ + pci_read_config_word(pci_dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_word(pci_dev, PCI_COMMAND, cmd); + + cx->card_rev = pci_dev->revision; + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); + + if (pci_latency < 64 && cx18_pci_latency) { + CX18_INFO("Unreasonably low latency timer, " + "setting to 64 (was %d)\n", pci_latency); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); + } + + CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, " + "irq: %d, latency: %d, memory: 0x%lx\n", + cx->pci_dev->device, cx->card_rev, pci_dev->bus->number, + PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), + cx->pci_dev->irq, pci_latency, (unsigned long)cx->base_addr); + + return 0; +} + +static void cx18_init_subdevs(struct cx18 *cx) +{ + u32 hw = cx->card->hw_all; + u32 device; + int i; + + for (i = 0, device = 1; i < 32; i++, device <<= 1) { + + if (!(device & hw)) + continue; + + switch (device) { + case CX18_HW_DVB: + case CX18_HW_TVEEPROM: + /* These subordinate devices do not use probing */ + cx->hw_flags |= device; + break; + case CX18_HW_418_AV: + /* The A/V decoder gets probed earlier to set PLLs */ + /* Just note that the card uses it (i.e. has analog) */ + cx->hw_flags |= device; + break; + case CX18_HW_GPIO_RESET_CTRL: + /* + * The Reset Controller gets probed and added to + * hw_flags earlier for i2c adapter/bus initialization + */ + break; + case CX18_HW_GPIO_MUX: + if (cx18_gpio_register(cx, device) == 0) + cx->hw_flags |= device; + break; + default: + if (cx18_i2c_register(cx, i) == 0) + cx->hw_flags |= device; + break; + } + } + + if (cx->hw_flags & CX18_HW_418_AV) + cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV); + + if (cx->card->hw_muxer != 0) + cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer); +} + +static int __devinit cx18_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + int retval = 0; + int i; + u32 devtype; + struct cx18 *cx; + + /* FIXME - module parameter arrays constrain max instances */ + i = atomic_inc_return(&cx18_instance) - 1; + if (i >= CX18_MAX_CARDS) { + printk(KERN_ERR "cx18: cannot manage card %d, driver has a " + "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1); + return -ENOMEM; + } + + cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); + if (cx == NULL) { + printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n", + i); + return -ENOMEM; + } + cx->pci_dev = pci_dev; + cx->instance = i; + + retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev); + if (retval) { + printk(KERN_ERR "cx18: v4l2_device_register of card %d failed" + "\n", cx->instance); + kfree(cx); + return retval; + } + snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d", + cx->instance); + CX18_INFO("Initializing card %d\n", cx->instance); + + cx18_process_options(cx); + if (cx->options.cardtype == -1) { + retval = -ENODEV; + goto err; + } + + retval = cx18_init_struct1(cx); + if (retval) + goto err; + + CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); + + /* PCI Device Setup */ + retval = cx18_setup_pci(cx, pci_dev, pci_id); + if (retval != 0) + goto free_workqueues; + + /* map io memory */ + CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", + cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); + cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, + CX18_MEM_SIZE); + if (!cx->enc_mem) { + CX18_ERR("ioremap failed. Can't get a window into CX23418 " + "memory and register space\n"); + CX18_ERR("Each capture card with a CX23418 needs 64 MB of " + "vmalloc address space for the window\n"); + CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); + CX18_ERR("Use the vmalloc= kernel command line option to set " + "VmallocTotal to a larger value\n"); + retval = -ENOMEM; + goto free_mem; + } + cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; + devtype = cx18_read_reg(cx, 0xC72028); + switch (devtype & 0xff000000) { + case 0xff000000: + CX18_INFO("cx23418 revision %08x (A)\n", devtype); + break; + case 0x01000000: + CX18_INFO("cx23418 revision %08x (B)\n", devtype); + break; + default: + CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); + break; + } + + cx18_init_power(cx, 1); + cx18_init_memory(cx); + + cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); + cx18_init_scb(cx); + + cx18_gpio_init(cx); + + /* Initialize integrated A/V decoder early to set PLLs, just in case */ + retval = cx18_av_probe(cx); + if (retval) { + CX18_ERR("Could not register A/V decoder subdevice\n"); + goto free_map; + } + + /* Initialize GPIO Reset Controller to do chip resets during i2c init */ + if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) { + if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0) + CX18_WARN("Could not register GPIO reset controller" + "subdevice; proceeding anyway.\n"); + else + cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL; + } + + /* active i2c */ + CX18_DEBUG_INFO("activating i2c...\n"); + retval = init_cx18_i2c(cx); + if (retval) { + CX18_ERR("Could not initialize i2c\n"); + goto free_map; + } + + if (cx->card->hw_all & CX18_HW_TVEEPROM) { + /* Based on the model number the cardtype may be changed. + The PCI IDs are not always reliable. */ + const struct cx18_card *orig_card = cx->card; + cx18_process_eeprom(cx); + + if (cx->card != orig_card) { + /* Changed the cardtype; re-reset the I2C chips */ + cx18_gpio_init(cx); + cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, + core, reset, (u32) CX18_GPIO_RESET_I2C); + } + } + if (cx->card->comment) + CX18_INFO("%s", cx->card->comment); + if (cx->card->v4l2_capabilities == 0) { + retval = -ENODEV; + goto free_i2c; + } + cx18_init_memory(cx); + cx18_init_scb(cx); + + /* Register IRQ */ + retval = request_irq(cx->pci_dev->irq, cx18_irq_handler, + IRQF_SHARED | IRQF_DISABLED, + cx->v4l2_dev.name, (void *)cx); + if (retval) { + CX18_ERR("Failed to register irq %d\n", retval); + goto free_i2c; + } + + if (cx->std == 0) + cx->std = V4L2_STD_NTSC_M; + + if (cx->options.tuner == -1) { + for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { + if ((cx->std & cx->card->tuners[i].std) == 0) + continue; + cx->options.tuner = cx->card->tuners[i].tuner; + break; + } + } + /* if no tuner was found, then pick the first tuner in the card list */ + if (cx->options.tuner == -1 && cx->card->tuners[0].std) { + cx->std = cx->card->tuners[0].std; + if (cx->std & V4L2_STD_PAL) + cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + else if (cx->std & V4L2_STD_NTSC) + cx->std = V4L2_STD_NTSC_M; + else if (cx->std & V4L2_STD_SECAM) + cx->std = V4L2_STD_SECAM_L; + cx->options.tuner = cx->card->tuners[0].tuner; + } + if (cx->options.radio == -1) + cx->options.radio = (cx->card->radio_input.audio_type != 0); + + /* The card is now fully identified, continue with card-specific + initialization. */ + cx18_init_struct2(cx); + + cx18_init_subdevs(cx); + + if (cx->std & V4L2_STD_525_60) + cx->is_60hz = 1; + else + cx->is_50hz = 1; + + cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz); + + if (cx->options.radio > 0) + cx->v4l2_cap |= V4L2_CAP_RADIO; + + if (cx->options.tuner > -1) { + struct tuner_setup setup; + + setup.addr = ADDR_UNSET; + setup.type = cx->options.tuner; + setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + setup.tuner_callback = (setup.type == TUNER_XC2028) ? + cx18_reset_tuner_gpio : NULL; + cx18_call_all(cx, tuner, s_type_addr, &setup); + if (setup.type == TUNER_XC2028) { + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + }; + struct v4l2_priv_tun_config cfg = { + .tuner = cx->options.tuner, + .priv = &ctrl, + }; + cx18_call_all(cx, tuner, s_config, &cfg); + } + } + + /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) + are not. */ + cx->tuner_std = cx->std; + if (cx->std == V4L2_STD_ALL) + cx->std = V4L2_STD_NTSC_M; + + retval = cx18_streams_setup(cx); + if (retval) { + CX18_ERR("Error %d setting up streams\n", retval); + goto free_irq; + } + retval = cx18_streams_register(cx); + if (retval) { + CX18_ERR("Error %d registering devices\n", retval); + goto free_streams; + } + + CX18_INFO("Initialized card: %s\n", cx->card_name); + + /* Load cx18 submodules (cx18-alsa) */ + request_modules(cx); + return 0; + +free_streams: + cx18_streams_cleanup(cx, 1); +free_irq: + free_irq(cx->pci_dev->irq, (void *)cx); +free_i2c: + exit_cx18_i2c(cx); +free_map: + cx18_iounmap(cx); +free_mem: + release_mem_region(cx->base_addr, CX18_MEM_SIZE); +free_workqueues: + destroy_workqueue(cx->in_work_queue); +err: + if (retval == 0) + retval = -ENODEV; + CX18_ERR("Error %d on initialization\n", retval); + + v4l2_device_unregister(&cx->v4l2_dev); + kfree(cx); + return retval; +} + +int cx18_init_on_first_open(struct cx18 *cx) +{ + int video_input; + int fw_retry_count = 3; + struct v4l2_frequency vf; + struct cx18_open_id fh; + v4l2_std_id std; + + fh.cx = cx; + + if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) + return -ENXIO; + + if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) + return 0; + + while (--fw_retry_count > 0) { + /* load firmware */ + if (cx18_firmware_init(cx) == 0) + break; + if (fw_retry_count > 1) + CX18_WARN("Retry loading firmware\n"); + } + + if (fw_retry_count == 0) { + set_bit(CX18_F_I_FAILED, &cx->i_flags); + return -ENXIO; + } + set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); + + /* + * Init the firmware twice to work around a silicon bug + * with the digital TS. + * + * The second firmware load requires us to normalize the APU state, + * or the audio for the first analog capture will be badly incorrect. + * + * I can't seem to call APU_RESETAI and have it succeed without the + * APU capturing audio, so we start and stop it here to do the reset + */ + + /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ + cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); + cx18_vapi(cx, CX18_APU_RESETAI, 0); + cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); + + fw_retry_count = 3; + while (--fw_retry_count > 0) { + /* load firmware */ + if (cx18_firmware_init(cx) == 0) + break; + if (fw_retry_count > 1) + CX18_WARN("Retry loading firmware\n"); + } + + if (fw_retry_count == 0) { + set_bit(CX18_F_I_FAILED, &cx->i_flags); + return -ENXIO; + } + + /* + * The second firmware load requires us to normalize the APU state, + * or the audio for the first analog capture will be badly incorrect. + * + * I can't seem to call APU_RESETAI and have it succeed without the + * APU capturing audio, so we start and stop it here to do the reset + */ + + /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ + cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); + cx18_vapi(cx, CX18_APU_RESETAI, 0); + cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); + + /* Init the A/V decoder, if it hasn't been already */ + v4l2_subdev_call(cx->sd_av, core, load_fw); + + vf.tuner = 0; + vf.type = V4L2_TUNER_ANALOG_TV; + vf.frequency = 6400; /* the tuner 'baseline' frequency */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (cx->std == V4L2_STD_NTSC_M_JP) + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + else if (cx->std & V4L2_STD_NTSC_M) + vf.frequency = 1076; /* ch. 4 67250*16/1000 */ + + video_input = cx->active_input; + cx->active_input++; /* Force update of input */ + cx18_s_input(NULL, &fh, video_input); + + /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code + in one place. */ + cx->std++; /* Force full standard initialization */ + std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std; + cx18_s_std(NULL, &fh, &std); + cx18_s_frequency(NULL, &fh, &vf); + return 0; +} + +static void cx18_cancel_in_work_orders(struct cx18 *cx) +{ + int i; + for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) + cancel_work_sync(&cx->in_work_order[i].work); +} + +static void cx18_cancel_out_work_orders(struct cx18 *cx) +{ + int i; + for (i = 0; i < CX18_MAX_STREAMS; i++) + if (&cx->streams[i].video_dev != NULL) + cancel_work_sync(&cx->streams[i].out_work_order); +} + +static void cx18_remove(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct cx18 *cx = to_cx18(v4l2_dev); + int i; + + CX18_DEBUG_INFO("Removing Card\n"); + + flush_request_modules(cx); + + /* Stop all captures */ + CX18_DEBUG_INFO("Stopping all streams\n"); + if (atomic_read(&cx->tot_capturing) > 0) + cx18_stop_all_captures(cx); + + /* Stop interrupts that cause incoming work to be queued */ + cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); + + /* Incoming work can cause outgoing work, so clean up incoming first */ + cx18_cancel_in_work_orders(cx); + cx18_cancel_out_work_orders(cx); + + /* Stop ack interrupts that may have been needed for work to finish */ + cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + cx18_halt_firmware(cx); + + destroy_workqueue(cx->in_work_queue); + + cx18_streams_cleanup(cx, 1); + + exit_cx18_i2c(cx); + + free_irq(cx->pci_dev->irq, (void *)cx); + + cx18_iounmap(cx); + + release_mem_region(cx->base_addr, CX18_MEM_SIZE); + + pci_disable_device(cx->pci_dev); + + if (cx->vbi.sliced_mpeg_data[0] != NULL) + for (i = 0; i < CX18_VBI_FRAMES; i++) + kfree(cx->vbi.sliced_mpeg_data[i]); + + v4l2_ctrl_handler_free(&cx->av_state.hdl); + + CX18_INFO("Removed %s\n", cx->card_name); + + v4l2_device_unregister(v4l2_dev); + kfree(cx); +} + + +/* define a pci_driver for card detection */ +static struct pci_driver cx18_pci_driver = { + .name = "cx18", + .id_table = cx18_pci_tbl, + .probe = cx18_probe, + .remove = cx18_remove, +}; + +static int __init module_start(void) +{ + printk(KERN_INFO "cx18: Start initialization, version %s\n", + CX18_VERSION); + + /* Validate parameters */ + if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) { + printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n", + CX18_MAX_CARDS - 1); + return -1; + } + + if (cx18_debug < 0 || cx18_debug > 511) { + cx18_debug = 0; + printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n"); + } + + if (pci_register_driver(&cx18_pci_driver)) { + printk(KERN_ERR "cx18: Error detecting PCI card\n"); + return -ENODEV; + } + printk(KERN_INFO "cx18: End initialization\n"); + return 0; +} + +static void __exit module_cleanup(void) +{ + pci_unregister_driver(&cx18_pci_driver); +} + +module_init(module_start); +module_exit(module_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-driver.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-driver.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-driver.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-driver.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,736 @@ +/* + * cx18 driver internal defines and structures + * + * Derived from ivtv-driver.h + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#ifndef CX18_DRIVER_H +#define CX18_DRIVER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cx18-mailbox.h" +#include "cx18-av-core.h" +#include "cx23418.h" + +/* DVB */ +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" + +/* Videobuf / YUV support */ +#include +#include + +#ifndef CONFIG_PCI +# error "This driver requires kernel PCI support." +#endif + +#define CX18_MEM_OFFSET 0x00000000 +#define CX18_MEM_SIZE 0x04000000 +#define CX18_REG_OFFSET 0x02000000 + +/* Maximum cx18 driver instances. */ +#define CX18_MAX_CARDS 32 + +/* Supported cards */ +#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */ +#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */ +#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */ +#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ +#define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */ +#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/ +#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */ +#define CX18_CARD_LEADTEK_DVR3100H 7 /* Leadtek WinFast DVR3100 H */ +#define CX18_CARD_GOTVIEW_PCI_DVD3 8 /* GoTView PCI DVD3 Hybrid */ +#define CX18_CARD_HVR_1600_S5H1411 9 /* Hauppauge HVR 1600 s5h1411/tda18271*/ +#define CX18_CARD_LAST 9 + +#define CX18_ENC_STREAM_TYPE_MPG 0 +#define CX18_ENC_STREAM_TYPE_TS 1 +#define CX18_ENC_STREAM_TYPE_YUV 2 +#define CX18_ENC_STREAM_TYPE_VBI 3 +#define CX18_ENC_STREAM_TYPE_PCM 4 +#define CX18_ENC_STREAM_TYPE_IDX 5 +#define CX18_ENC_STREAM_TYPE_RAD 6 +#define CX18_MAX_STREAMS 7 + +/* system vendor and device IDs */ +#define PCI_VENDOR_ID_CX 0x14f1 +#define PCI_DEVICE_ID_CX23418 0x5b7a + +/* subsystem vendor ID */ +#define CX18_PCI_ID_HAUPPAUGE 0x0070 +#define CX18_PCI_ID_COMPRO 0x185b +#define CX18_PCI_ID_YUAN 0x12ab +#define CX18_PCI_ID_CONEXANT 0x14f1 +#define CX18_PCI_ID_TOSHIBA 0x1179 +#define CX18_PCI_ID_LEADTEK 0x107D +#define CX18_PCI_ID_GOTVIEW 0x5854 + +/* ======================================================================== */ +/* ========================== START USER SETTABLE DMA VARIABLES =========== */ +/* ======================================================================== */ + +/* DMA Buffers, Default size in MB allocated */ +#define CX18_DEFAULT_ENC_TS_BUFFERS 1 +#define CX18_DEFAULT_ENC_MPG_BUFFERS 2 +#define CX18_DEFAULT_ENC_IDX_BUFFERS 1 +#define CX18_DEFAULT_ENC_YUV_BUFFERS 2 +#define CX18_DEFAULT_ENC_VBI_BUFFERS 1 +#define CX18_DEFAULT_ENC_PCM_BUFFERS 1 + +/* Maximum firmware DMA buffers per stream */ +#define CX18_MAX_FW_MDLS_PER_STREAM 63 + +/* YUV buffer sizes in bytes to ensure integer # of frames per buffer */ +#define CX18_UNIT_ENC_YUV_BUFSIZE (720 * 32 * 3 / 2) /* bytes */ +#define CX18_625_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 576/32) +#define CX18_525_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 480/32) + +/* IDX buffer size should be a multiple of the index entry size from the chip */ +struct cx18_enc_idx_entry { + __le32 length; + __le32 offset_low; + __le32 offset_high; + __le32 flags; + __le32 pts_low; + __le32 pts_high; +} __attribute__ ((packed)); +#define CX18_UNIT_ENC_IDX_BUFSIZE \ + (sizeof(struct cx18_enc_idx_entry) * V4L2_ENC_IDX_ENTRIES) + +/* DMA buffer, default size in kB allocated */ +#define CX18_DEFAULT_ENC_TS_BUFSIZE 32 +#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32 +#define CX18_DEFAULT_ENC_IDX_BUFSIZE (CX18_UNIT_ENC_IDX_BUFSIZE * 1 / 1024 + 1) +#define CX18_DEFAULT_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 3 / 1024 + 1) +#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4 + +/* i2c stuff */ +#define I2C_CLIENTS_MAX 16 + +/* debugging */ + +/* Flag to turn on high volume debugging */ +#define CX18_DBGFLG_WARN (1 << 0) +#define CX18_DBGFLG_INFO (1 << 1) +#define CX18_DBGFLG_API (1 << 2) +#define CX18_DBGFLG_DMA (1 << 3) +#define CX18_DBGFLG_IOCTL (1 << 4) +#define CX18_DBGFLG_FILE (1 << 5) +#define CX18_DBGFLG_I2C (1 << 6) +#define CX18_DBGFLG_IRQ (1 << 7) +/* Flag to turn on high volume debugging */ +#define CX18_DBGFLG_HIGHVOL (1 << 8) + +/* NOTE: extra space before comma in 'fmt , ## args' is required for + gcc-2.95, otherwise it won't compile. */ +#define CX18_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & cx18_debug) \ + v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \ + } while (0) +#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args) +#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args) +#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args) +#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args) +#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args) +#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args) +#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args) + +#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \ + do { \ + if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \ + v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \ + } while (0) +#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args) +#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args) +#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args) +#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args) +#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args) +#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args) +#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args) + +/* Standard kernel messages */ +#define CX18_ERR(fmt, args...) v4l2_err(&cx->v4l2_dev, fmt , ## args) +#define CX18_WARN(fmt, args...) v4l2_warn(&cx->v4l2_dev, fmt , ## args) +#define CX18_INFO(fmt, args...) v4l2_info(&cx->v4l2_dev, fmt , ## args) + +/* Messages for internal subdevs to use */ +#define CX18_DEBUG_DEV(x, dev, type, fmt, args...) \ + do { \ + if ((x) & cx18_debug) \ + v4l2_info(dev, " " type ": " fmt , ## args); \ + } while (0) +#define CX18_DEBUG_WARN_DEV(dev, fmt, args...) \ + CX18_DEBUG_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args) +#define CX18_DEBUG_INFO_DEV(dev, fmt, args...) \ + CX18_DEBUG_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args) +#define CX18_DEBUG_API_DEV(dev, fmt, args...) \ + CX18_DEBUG_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args) +#define CX18_DEBUG_DMA_DEV(dev, fmt, args...) \ + CX18_DEBUG_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args) +#define CX18_DEBUG_IOCTL_DEV(dev, fmt, args...) \ + CX18_DEBUG_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args) +#define CX18_DEBUG_FILE_DEV(dev, fmt, args...) \ + CX18_DEBUG_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args) +#define CX18_DEBUG_I2C_DEV(dev, fmt, args...) \ + CX18_DEBUG_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args) +#define CX18_DEBUG_IRQ_DEV(dev, fmt, args...) \ + CX18_DEBUG_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args) + +#define CX18_DEBUG_HIGH_VOL_DEV(x, dev, type, fmt, args...) \ + do { \ + if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \ + v4l2_info(dev, " " type ": " fmt , ## args); \ + } while (0) +#define CX18_DEBUG_HI_WARN_DEV(dev, fmt, args...) \ + CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args) +#define CX18_DEBUG_HI_INFO_DEV(dev, fmt, args...) \ + CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args) +#define CX18_DEBUG_HI_API_DEV(dev, fmt, args...) \ + CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args) +#define CX18_DEBUG_HI_DMA_DEV(dev, fmt, args...) \ + CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args) +#define CX18_DEBUG_HI_IOCTL_DEV(dev, fmt, args...) \ + CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args) +#define CX18_DEBUG_HI_FILE_DEV(dev, fmt, args...) \ + CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args) +#define CX18_DEBUG_HI_I2C_DEV(dev, fmt, args...) \ + CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args) +#define CX18_DEBUG_HI_IRQ_DEV(dev, fmt, args...) \ + CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args) + +#define CX18_ERR_DEV(dev, fmt, args...) v4l2_err(dev, fmt , ## args) +#define CX18_WARN_DEV(dev, fmt, args...) v4l2_warn(dev, fmt , ## args) +#define CX18_INFO_DEV(dev, fmt, args...) v4l2_info(dev, fmt , ## args) + +extern int cx18_debug; + +struct cx18_options { + int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */ + int cardtype; /* force card type on load */ + int tuner; /* set tuner on load */ + int radio; /* enable/disable radio */ +}; + +/* per-mdl bit flags */ +#define CX18_F_M_NEED_SWAP 0 /* mdl buffer data must be endianess swapped */ + +/* per-stream, s_flags */ +#define CX18_F_S_CLAIMED 3 /* this stream is claimed */ +#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ +#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ +#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */ +#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ +#define CX18_F_S_STOPPING 9 /* telling the fw to stop capturing */ + +/* per-cx18, i_flags */ +#define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */ +#define CX18_F_I_EOS 4 /* End of encoder stream */ +#define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */ +#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ +#define CX18_F_I_INITED 21 /* set after first open */ +#define CX18_F_I_FAILED 22 /* set if first open failed */ + +/* These are the VBI types as they appear in the embedded VBI private packets. */ +#define CX18_SLICED_TYPE_TELETEXT_B (1) +#define CX18_SLICED_TYPE_CAPTION_525 (4) +#define CX18_SLICED_TYPE_WSS_625 (5) +#define CX18_SLICED_TYPE_VPS (7) + +/** + * list_entry_is_past_end - check if a previous loop cursor is off list end + * @pos: the type * previously used as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Check if the entry's list_head is the head of the list, thus it's not a + * real entry but was the loop cursor that walked past the end + */ +#define list_entry_is_past_end(pos, head, member) \ + (&pos->member == (head)) + +struct cx18_buffer { + struct list_head list; + dma_addr_t dma_handle; + char *buf; + + u32 bytesused; + u32 readpos; +}; + +struct cx18_mdl { + struct list_head list; + u32 id; /* index into cx->scb->cpu_mdl[] of 1st cx18_mdl_ent */ + + unsigned int skipped; + unsigned long m_flags; + + struct list_head buf_list; + struct cx18_buffer *curr_buf; /* current buffer in list for reading */ + + u32 bytesused; + u32 readpos; +}; + +struct cx18_queue { + struct list_head list; + atomic_t depth; + u32 bytesused; + spinlock_t lock; +}; + +struct cx18_stream; /* forward reference */ + +struct cx18_dvb { + struct cx18_stream *stream; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + int enabled; + int feeding; + struct mutex feedlock; +}; + +struct cx18; /* forward reference */ +struct cx18_scb; /* forward reference */ + + +#define CX18_MAX_MDL_ACKS 2 +#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7) +/* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */ + +#define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1 +#define CX18_F_EWO_MB_STALE_WHILE_PROC 0x2 +#define CX18_F_EWO_MB_STALE \ + (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC) + +struct cx18_in_work_order { + struct work_struct work; + atomic_t pending; + struct cx18 *cx; + unsigned long flags; + int rpu; + struct cx18_mailbox mb; + struct cx18_mdl_ack mdl_ack[CX18_MAX_MDL_ACKS]; + char *str; +}; + +#define CX18_INVALID_TASK_HANDLE 0xffffffff + +struct cx18_stream { + /* These first five fields are always set, even if the stream + is not actually created. */ + struct video_device *video_dev; /* NULL when stream not created */ + struct cx18_dvb *dvb; /* DVB / Digital Transport */ + struct cx18 *cx; /* for ease of use */ + const char *name; /* name of the stream */ + int type; /* stream type */ + u32 handle; /* task handle */ + unsigned int mdl_base_idx; + + u32 id; + unsigned long s_flags; /* status flags, see above */ + int dma; /* can be PCI_DMA_TODEVICE, + PCI_DMA_FROMDEVICE or + PCI_DMA_NONE */ + wait_queue_head_t waitq; + + /* Buffers */ + struct list_head buf_pool; /* buffers not attached to an MDL */ + u32 buffers; /* total buffers owned by this stream */ + u32 buf_size; /* size in bytes of a single buffer */ + + /* MDL sizes - all stream MDLs are the same size */ + u32 bufs_per_mdl; + u32 mdl_size; /* total bytes in all buffers in a mdl */ + + /* MDL Queues */ + struct cx18_queue q_free; /* free - in rotation, not committed */ + struct cx18_queue q_busy; /* busy - in use by firmware */ + struct cx18_queue q_full; /* full - data for user apps */ + struct cx18_queue q_idle; /* idle - not in rotation */ + + struct work_struct out_work_order; + + /* Videobuf for YUV video */ + u32 pixelformat; + struct list_head vb_capture; /* video capture queue */ + spinlock_t vb_lock; + struct timer_list vb_timeout; + + struct videobuf_queue vbuf_q; + spinlock_t vbuf_q_lock; /* Protect vbuf_q */ + enum v4l2_buf_type vb_type; +}; + +struct cx18_videobuf_buffer { + /* Common video buffer sub-system struct */ + struct videobuf_buffer vb; + v4l2_std_id tvnorm; /* selected tv norm */ + u32 bytes_used; +}; + +struct cx18_open_id { + struct v4l2_fh fh; + u32 open_id; + int type; + struct cx18 *cx; + + struct videobuf_queue vbuf_q; + spinlock_t s_lock; /* Protect vbuf_q */ + enum v4l2_buf_type vb_type; +}; + +static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) +{ + return container_of(fh, struct cx18_open_id, fh); +} + +static inline struct cx18_open_id *file2id(struct file *file) +{ + return fh2id(file->private_data); +} + +/* forward declaration of struct defined in cx18-cards.h */ +struct cx18_card; + +/* + * A note about "sliced" VBI data as implemented in this driver: + * + * Currently we collect the sliced VBI in the form of Ancillary Data + * packets, inserted by the AV core decoder/digitizer/slicer in the + * horizontal blanking region of the VBI lines, in "raw" mode as far as + * the Encoder is concerned. We don't ever tell the Encoder itself + * to provide sliced VBI. (AV Core: sliced mode - Encoder: raw mode) + * + * We then process the ancillary data ourselves to send the sliced data + * to the user application directly or build up MPEG-2 private stream 1 + * packets to splice into (only!) MPEG-2 PS streams for the user app. + * + * (That's how ivtv essentially does it.) + * + * The Encoder should be able to extract certain sliced VBI data for + * us and provide it in a separate stream or splice it into any type of + * MPEG PS or TS stream, but this isn't implemented yet. + */ + +/* + * Number of "raw" VBI samples per horizontal line we tell the Encoder to + * grab from the decoder/digitizer/slicer output for raw or sliced VBI. + * It depends on the pixel clock and the horiz rate: + * + * (1/Fh)*(2*Fp) = Samples/line + * = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples + * + * Sliced VBI data is sent as ancillary data during horizontal blanking + * Raw VBI is sent as active video samples during vertcal blanking + * + * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line + * length of 720 pixels @ 4:2:2 sampling. Thus... + * + * For systems that use a 15.734 kHz horizontal rate, such as + * NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have: + * + * (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line = + * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples + * + * For systems that use a 15.625 kHz horizontal rate, such as + * PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have: + * + * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line = + * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples + */ +static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */ +static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */ +static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */ + +#define CX18_VBI_FRAMES 32 + +struct vbi_info { + /* Current state of v4l2 VBI settings for this device */ + struct v4l2_format in; + struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */ + u32 count; /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */ + u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */ + + u32 frame; /* Count of VBI buffers/frames received from Encoder */ + + /* + * Vars for creation and insertion of MPEG Private Stream 1 packets + * of sliced VBI data into an MPEG PS + */ + + /* Boolean: create and insert Private Stream 1 packets into the PS */ + int insert_mpeg; + + /* + * Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. + * Used in cx18-vbi.c only for collecting sliced data, and as a source + * during conversion of sliced VBI data into MPEG Priv Stream 1 packets. + * We don't need to save state here, but the array may have been a bit + * too big (2304 bytes) to alloc from the stack. + */ + struct v4l2_sliced_vbi_data sliced_data[36]; + + /* + * A ring buffer of driver-generated MPEG-2 PS + * Program Pack/Private Stream 1 packets for sliced VBI data insertion + * into the MPEG PS stream. + * + * In each sliced_mpeg_data[] buffer is: + * 16 byte MPEG-2 PS Program Pack Header + * 16 byte MPEG-2 Private Stream 1 PES Header + * 4 byte magic number: "itv0" or "ITV0" + * 4 byte first field line mask, if "itv0" + * 4 byte second field line mask, if "itv0" + * 36 lines, if "ITV0"; or <36 lines, if "itv0"; of sliced VBI data + * + * Each line in the payload is + * 1 byte line header derived from the SDID (WSS, CC, VPS, etc.) + * 42 bytes of line data + * + * That's a maximum 1552 bytes of payload in the Private Stream 1 packet + * which is the payload size a PVR-350 (CX23415) MPEG decoder will + * accept for VBI data. So, including the headers, it's a maximum 1584 + * bytes total. + */ +#define CX18_SLICED_MPEG_DATA_MAXSZ 1584 + /* copy_vbi_buf() needs 8 temp bytes on the end for the worst case */ +#define CX18_SLICED_MPEG_DATA_BUFSZ (CX18_SLICED_MPEG_DATA_MAXSZ+8) + u8 *sliced_mpeg_data[CX18_VBI_FRAMES]; + u32 sliced_mpeg_size[CX18_VBI_FRAMES]; + + /* Count of Program Pack/Program Stream 1 packets inserted into PS */ + u32 inserted_frame; + + /* + * A dummy driver stream transfer mdl & buffer with a copy of the next + * sliced_mpeg_data[] buffer for output to userland apps. + * Only used in cx18-fileops.c, but its state needs to persist at times. + */ + struct cx18_mdl sliced_mpeg_mdl; + struct cx18_buffer sliced_mpeg_buf; +}; + +/* Per cx23418, per I2C bus private algo callback data */ +struct cx18_i2c_algo_callback_data { + struct cx18 *cx; + int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */ +}; + +#define CX18_MAX_MMIO_WR_RETRIES 10 + +/* Struct to hold info about cx18 cards */ +struct cx18 { + int instance; + struct pci_dev *pci_dev; + struct v4l2_device v4l2_dev; + struct v4l2_subdev *sd_av; /* A/V decoder/digitizer sub-device */ + struct v4l2_subdev *sd_extmux; /* External multiplexer sub-dev */ + + const struct cx18_card *card; /* card information */ + const char *card_name; /* full name of the card */ + const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ + u8 is_50hz; + u8 is_60hz; + u8 nof_inputs; /* number of video inputs */ + u8 nof_audio_inputs; /* number of audio inputs */ + u32 v4l2_cap; /* V4L2 capabilities of card */ + u32 hw_flags; /* Hardware description of the board */ + unsigned int free_mdl_idx; + struct cx18_scb __iomem *scb; /* pointer to SCB */ + struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ + struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ + + struct cx18_av_state av_state; + + /* codec settings */ + struct cx2341x_handler cxhdl; + u32 filter_mode; + u32 temporal_strength; + u32 spatial_strength; + + /* dualwatch */ + unsigned long dualwatch_jiffies; + u32 dualwatch_stereo_mode; + + struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ + struct cx18_options options; /* User options */ + int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */ + int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ + struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ + struct snd_cx18_card *alsa; /* ALSA interface for PCM capture stream */ + void (*pcm_announce_callback)(struct snd_cx18_card *card, u8 *pcm_data, + size_t num_bytes); + + unsigned long i_flags; /* global cx18 flags */ + atomic_t ana_capturing; /* count number of active analog capture streams */ + atomic_t tot_capturing; /* total count number of active capture streams */ + int search_pack_header; + + int open_id; /* incremented each time an open occurs, used as + unique ID. Starts at 1, so 0 can be used as + uninitialized value in the stream->id. */ + + u32 base_addr; + + u8 card_rev; + void __iomem *enc_mem, *reg_mem; + + struct vbi_info vbi; + + u64 mpg_data_received; + u64 vbi_data_inserted; + + wait_queue_head_t mb_apu_waitq; + wait_queue_head_t mb_cpu_waitq; + wait_queue_head_t cap_w; + /* when the current DMA is finished this queue is woken up */ + wait_queue_head_t dma_waitq; + + u32 sw1_irq_mask; + u32 sw2_irq_mask; + u32 hw2_irq_mask; + + struct workqueue_struct *in_work_queue; + char in_workq_name[11]; /* "cx18-NN-in" */ + struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; + char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ + + /* i2c */ + struct i2c_adapter i2c_adap[2]; + struct i2c_algo_bit_data i2c_algo[2]; + struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; + + struct IR_i2c_init_data ir_i2c_init_data; + + /* gpio */ + u32 gpio_dir; + u32 gpio_val; + struct mutex gpio_lock; + struct v4l2_subdev sd_gpiomux; + struct v4l2_subdev sd_resetctrl; + + /* v4l2 and User settings */ + + /* codec settings */ + u32 audio_input; + u32 active_input; + v4l2_std_id std; + v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ + + /* Used for cx18-alsa module loading */ + struct work_struct request_module_wk; +}; + +static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct cx18, v4l2_dev); +} + +/* cx18 extensions to be loaded */ +extern int (*cx18_ext_init)(struct cx18 *); + +/* Globals */ +extern int cx18_first_minor; + +/*==============Prototypes==================*/ + +/* Return non-zero if a signal is pending */ +int cx18_msleep_timeout(unsigned int msecs, int intr); + +/* Read Hauppauge eeprom */ +struct tveeprom; /* forward reference */ +void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv); + +/* First-open initialization: load firmware, etc. */ +int cx18_init_on_first_open(struct cx18 *cx); + +/* Test if the current VBI mode is raw (1) or sliced (0) */ +static inline int cx18_raw_vbi(const struct cx18 *cx) +{ + return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE; +} + +/* Call the specified callback for all subdevs with a grp_id bit matching the + * mask in hw (if 0, then match them all). Ignore any errors. */ +#define cx18_call_hw(cx, hw, o, f, args...) \ + do { \ + struct v4l2_subdev *__sd; \ + __v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd, \ + !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ + } while (0) + +#define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args) + +/* Call the specified callback for all subdevs with a grp_id bit matching the + * mask in hw (if 0, then match them all). If the callback returns an error + * other than 0 or -ENOIOCTLCMD, then return with that error code. */ +#define cx18_call_hw_err(cx, hw, o, f, args...) \ +({ \ + struct v4l2_subdev *__sd; \ + __v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev, \ + __sd, !(hw) || (__sd->grp_id & (hw)), o, f, \ + ##args); \ +}) + +#define cx18_call_all_err(cx, o, f, args...) \ + cx18_call_hw_err(cx, 0, o, f , ##args) + +#endif /* CX18_DRIVER_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-dvb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,605 @@ +/* + * cx18 functions for DVB support + * + * Copyright (c) 2008 Steven Toth + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx18-version.h" +#include "cx18-dvb.h" +#include "cx18-io.h" +#include "cx18-queue.h" +#include "cx18-streams.h" +#include "cx18-cards.h" +#include "cx18-gpio.h" +#include "s5h1409.h" +#include "mxl5005s.h" +#include "s5h1411.h" +#include "tda18271.h" +#include "zl10353.h" + +#include +#include "mt352.h" +#include "mt352_priv.h" +#include "tuner-xc2028.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 +#define CX18_CLOCK_ENABLE2 0xc71024 +#define CX18_DMUX_CLK_MASK 0x0080 + +/* + * CX18_CARD_HVR_1600_ESMT + * CX18_CARD_HVR_1600_SAMSUNG + */ + +static struct mxl5005s_config hauppauge_hvr1600_tuner = { + .i2c_address = 0xC6 >> 1, + .if_freq = IF_FREQ_5380000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C_H, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .qam_gain = 0x02, + .AgcMasterByte = 0x00, +}; + +static struct s5h1409_config hauppauge_hvr1600_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .hvr1600_opt = S5H1409_HVR1600_OPTIMIZE +}; + +/* + * CX18_CARD_HVR_1600_S5H1411 + */ +static struct s5h1411_config hcw_s5h1411_config = { + .output_mode = S5H1411_SERIAL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .vsb_if = S5H1411_IF_44000, + .qam_if = S5H1411_IF_4000, + .inversion = S5H1411_INVERSION_ON, + .status_mode = S5H1411_DEMODLOCKING, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct tda18271_std_map hauppauge_tda18271_std_map = { + .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, + .if_lvl = 6, .rfagc_top = 0x37 }, + .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, + .if_lvl = 6, .rfagc_top = 0x37 }, +}; + +static struct tda18271_config hauppauge_tda18271_config = { + .std_map = &hauppauge_tda18271_std_map, + .gate = TDA18271_GATE_DIGITAL, + .output_opt = TDA18271_OUTPUT_LT_OFF, +}; + +/* + * CX18_CARD_LEADTEK_DVR3100H + */ +/* Information/confirmation of proper config values provided by Terry Wu */ +static struct zl10353_config leadtek_dvr3100h_demod = { + .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ + .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ + .parallel_ts = 1, /* Not a serial TS */ + .no_tuner = 1, /* XC3028 is not behind the gate */ + .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ +}; + +/* + * CX18_CARD_YUAN_MPC718 + */ +/* + * Due to + * + * 1. an absence of information on how to prgram the MT352 + * 2. the Linux mt352 module pushing MT352 initialzation off onto us here + * + * We have to use an init sequence that *you* must extract from the Windows + * driver (yuanrap.sys) and which we load as a firmware. + * + * If someone can provide me with a Zarlink MT352 (Intel CE6352?) Design Manual + * with chip programming details, then I can remove this annoyance. + */ +static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream, + const struct firmware **fw) +{ + struct cx18 *cx = stream->cx; + const char *fn = "dvb-cx18-mpc718-mt352.fw"; + int ret; + + ret = request_firmware(fw, fn, &cx->pci_dev->dev); + if (ret) + CX18_ERR("Unable to open firmware file %s\n", fn); + else { + size_t sz = (*fw)->size; + if (sz < 2 || sz > 64 || (sz % 2) != 0) { + CX18_ERR("Firmware %s has a bad size: %lu bytes\n", + fn, (unsigned long) sz); + ret = -EILSEQ; + release_firmware(*fw); + *fw = NULL; + } + } + + if (ret) { + CX18_ERR("The MPC718 board variant with the MT352 DVB-T" + "demodualtor will not work without it\n"); + CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware " + "mpc718' if you need the firmware\n"); + } + return ret; +} + +static int yuan_mpc718_mt352_init(struct dvb_frontend *fe) +{ + struct cx18_dvb *dvb = container_of(fe->dvb, + struct cx18_dvb, dvb_adapter); + struct cx18_stream *stream = dvb->stream; + const struct firmware *fw = NULL; + int ret; + int i; + u8 buf[3]; + + ret = yuan_mpc718_mt352_reqfw(stream, &fw); + if (ret) + return ret; + + /* Loop through all the register-value pairs in the firmware file */ + for (i = 0; i < fw->size; i += 2) { + buf[0] = fw->data[i]; + /* Intercept a few registers we want to set ourselves */ + switch (buf[0]) { + case TRL_NOMINAL_RATE_0: + /* Set our custom OFDM bandwidth in the case below */ + break; + case TRL_NOMINAL_RATE_1: + /* 6 MHz: 64/7 * 6/8 / 20.48 * 2^16 = 0x55b6.db6 */ + /* 7 MHz: 64/7 * 7/8 / 20.48 * 2^16 = 0x6400 */ + /* 8 MHz: 64/7 * 8/8 / 20.48 * 2^16 = 0x7249.249 */ + buf[1] = 0x72; + buf[2] = 0x49; + mt352_write(fe, buf, 3); + break; + case INPUT_FREQ_0: + /* Set our custom IF in the case below */ + break; + case INPUT_FREQ_1: + /* 4.56 MHz IF: (20.48 - 4.56)/20.48 * 2^14 = 0x31c0 */ + buf[1] = 0x31; + buf[2] = 0xc0; + mt352_write(fe, buf, 3); + break; + default: + /* Pass through the register-value pair from the fw */ + buf[1] = fw->data[i+1]; + mt352_write(fe, buf, 2); + break; + } + } + + buf[0] = (u8) TUNER_GO; + buf[1] = 0x01; /* Go */ + mt352_write(fe, buf, 2); + release_firmware(fw); + return 0; +} + +static struct mt352_config yuan_mpc718_mt352_demod = { + .demod_address = 0x1e >> 1, + .adc_clock = 20480, /* 20.480 MHz */ + .if2 = 4560, /* 4.560 MHz */ + .no_tuner = 1, /* XC3028 is not behind the gate */ + .demod_init = yuan_mpc718_mt352_init, +}; + +static struct zl10353_config yuan_mpc718_zl10353_demod = { + .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ + .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ + .parallel_ts = 1, /* Not a serial TS */ + .no_tuner = 1, /* XC3028 is not behind the gate */ + .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ +}; + +static struct zl10353_config gotview_dvd3_zl10353_demod = { + .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ + .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ + .parallel_ts = 1, /* Not a serial TS */ + .no_tuner = 1, /* XC3028 is not behind the gate */ + .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ +}; + +static int dvb_register(struct cx18_stream *stream); + +/* Kernel DVB framework calls this when the feed needs to start. + * The CX18 framework should enable the transport DMA handling + * and queue processing. + */ +static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx18_stream *stream = (struct cx18_stream *) demux->priv; + struct cx18 *cx; + int ret; + u32 v; + + if (!stream) + return -EINVAL; + + cx = stream->cx; + CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n", + feed->pid, feed->index); + + mutex_lock(&cx->serialize_lock); + ret = cx18_init_on_first_open(cx); + mutex_unlock(&cx->serialize_lock); + if (ret) { + CX18_ERR("Failed to initialize firmware starting DVB feed\n"); + return ret; + } + ret = -EINVAL; + + switch (cx->card->type) { + case CX18_CARD_HVR_1600_ESMT: + case CX18_CARD_HVR_1600_SAMSUNG: + case CX18_CARD_HVR_1600_S5H1411: + v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL); + v |= 0x00400000; /* Serial Mode */ + v |= 0x00002000; /* Data Length - Byte */ + v |= 0x00010000; /* Error - Polarity */ + v |= 0x00020000; /* Error - Passthru */ + v |= 0x000c0000; /* Error - Ignore */ + cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL); + break; + + case CX18_CARD_LEADTEK_DVR3100H: + case CX18_CARD_YUAN_MPC718: + case CX18_CARD_GOTVIEW_PCI_DVD3: + default: + /* Assumption - Parallel transport - Signalling + * undefined or default. + */ + break; + } + + if (!demux->dmx.frontend) + return -EINVAL; + + mutex_lock(&stream->dvb->feedlock); + if (stream->dvb->feeding++ == 0) { + CX18_DEBUG_INFO("Starting Transport DMA\n"); + mutex_lock(&cx->serialize_lock); + set_bit(CX18_F_S_STREAMING, &stream->s_flags); + ret = cx18_start_v4l2_encode_stream(stream); + if (ret < 0) { + CX18_DEBUG_INFO("Failed to start Transport DMA\n"); + stream->dvb->feeding--; + if (stream->dvb->feeding == 0) + clear_bit(CX18_F_S_STREAMING, &stream->s_flags); + } + mutex_unlock(&cx->serialize_lock); + } else + ret = 0; + mutex_unlock(&stream->dvb->feedlock); + + return ret; +} + +/* Kernel DVB framework calls this when the feed needs to stop. */ +static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx18_stream *stream = (struct cx18_stream *)demux->priv; + struct cx18 *cx; + int ret = -EINVAL; + + if (stream) { + cx = stream->cx; + CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n", + feed->pid, feed->index); + + mutex_lock(&stream->dvb->feedlock); + if (--stream->dvb->feeding == 0) { + CX18_DEBUG_INFO("Stopping Transport DMA\n"); + mutex_lock(&cx->serialize_lock); + ret = cx18_stop_v4l2_encode_stream(stream, 0); + mutex_unlock(&cx->serialize_lock); + } else + ret = 0; + mutex_unlock(&stream->dvb->feedlock); + } + + return ret; +} + +int cx18_dvb_register(struct cx18_stream *stream) +{ + struct cx18 *cx = stream->cx; + struct cx18_dvb *dvb = stream->dvb; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret; + + if (!dvb) + return -EINVAL; + + dvb->enabled = 0; + dvb->stream = stream; + + ret = dvb_register_adapter(&dvb->dvb_adapter, + CX18_DRIVER_NAME, + THIS_MODULE, &cx->pci_dev->dev, adapter_nr); + if (ret < 0) + goto err_out; + + dvb_adapter = &dvb->dvb_adapter; + + dvbdemux = &dvb->demux; + + dvbdemux->priv = (void *)stream; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = cx18_dvb_start_feed; + dvbdemux->stop_feed = cx18_dvb_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + + dvb->hw_frontend.source = DMX_FRONTEND_0; + dvb->mem_frontend.source = DMX_MEMORY_FE; + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = dmx; + + ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + ret = dmx->add_frontend(dmx, &dvb->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + ret = dmx->add_frontend(dmx, &dvb->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &dvb->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = dvb_register(stream); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); + + CX18_INFO("DVB Frontend registered\n"); + CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n", + stream->dvb->dvb_adapter.num, stream->name, + stream->buffers, stream->buf_size/1024, + (stream->buf_size * 100 / 1024) % 100); + + mutex_init(&dvb->feedlock); + dvb->enabled = 1; + return ret; + +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &dvb->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &dvb->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&dvb->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_out: + return ret; +} + +void cx18_dvb_unregister(struct cx18_stream *stream) +{ + struct cx18 *cx = stream->cx; + struct cx18_dvb *dvb = stream->dvb; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + + CX18_INFO("unregister DVB\n"); + + if (dvb == NULL || !dvb->enabled) + return; + + dvb_adapter = &dvb->dvb_adapter; + dvbdemux = &dvb->demux; + dmx = &dvbdemux->dmx; + + dmx->close(dmx); + dvb_net_release(&dvb->dvbnet); + dmx->remove_frontend(dmx, &dvb->mem_frontend); + dmx->remove_frontend(dmx, &dvb->hw_frontend); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_frontend(dvb->fe); + dvb_frontend_detach(dvb->fe); + dvb_unregister_adapter(dvb_adapter); +} + +/* All the DVB attach calls go here, this function get's modified + * for each new card. cx18_dvb_start_feed() will also need changes. + */ +static int dvb_register(struct cx18_stream *stream) +{ + struct cx18_dvb *dvb = stream->dvb; + struct cx18 *cx = stream->cx; + int ret = 0; + + switch (cx->card->type) { + case CX18_CARD_HVR_1600_ESMT: + case CX18_CARD_HVR_1600_SAMSUNG: + dvb->fe = dvb_attach(s5h1409_attach, + &hauppauge_hvr1600_config, + &cx->i2c_adap[0]); + if (dvb->fe != NULL) { + dvb_attach(mxl5005s_attach, dvb->fe, + &cx->i2c_adap[0], + &hauppauge_hvr1600_tuner); + ret = 0; + } + break; + case CX18_CARD_HVR_1600_S5H1411: + dvb->fe = dvb_attach(s5h1411_attach, + &hcw_s5h1411_config, + &cx->i2c_adap[0]); + if (dvb->fe != NULL) + dvb_attach(tda18271_attach, dvb->fe, + 0x60, &cx->i2c_adap[0], + &hauppauge_tda18271_config); + break; + case CX18_CARD_LEADTEK_DVR3100H: + dvb->fe = dvb_attach(zl10353_attach, + &leadtek_dvr3100h_demod, + &cx->i2c_adap[1]); + if (dvb->fe != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &cx->i2c_adap[1], + .i2c_addr = 0xc2 >> 1, + .ctrl = NULL, + }; + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_ZARLINK456, + .type = XC2028_AUTO, + }; + + fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctrl); + } + break; + case CX18_CARD_YUAN_MPC718: + /* + * TODO + * Apparently, these cards also could instead have a + * DiBcom demod supported by one of the db7000 drivers + */ + dvb->fe = dvb_attach(mt352_attach, + &yuan_mpc718_mt352_demod, + &cx->i2c_adap[1]); + if (dvb->fe == NULL) + dvb->fe = dvb_attach(zl10353_attach, + &yuan_mpc718_zl10353_demod, + &cx->i2c_adap[1]); + if (dvb->fe != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &cx->i2c_adap[1], + .i2c_addr = 0xc2 >> 1, + .ctrl = NULL, + }; + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_ZARLINK456, + .type = XC2028_AUTO, + }; + + fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctrl); + } + break; + case CX18_CARD_GOTVIEW_PCI_DVD3: + dvb->fe = dvb_attach(zl10353_attach, + &gotview_dvd3_zl10353_demod, + &cx->i2c_adap[1]); + if (dvb->fe != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &cx->i2c_adap[1], + .i2c_addr = 0xc2 >> 1, + .ctrl = NULL, + }; + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_ZARLINK456, + .type = XC2028_AUTO, + }; + + fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctrl); + } + break; + default: + /* No Digital Tv Support */ + break; + } + + if (dvb->fe == NULL) { + CX18_ERR("frontend initialization failed\n"); + return -1; + } + + dvb->fe->callback = cx18_reset_tuner_gpio; + + ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe); + if (ret < 0) { + if (dvb->fe->ops.release) + dvb->fe->ops.release(dvb->fe); + return ret; + } + + /* + * The firmware seems to enable the TS DMUX clock + * under various circumstances. However, since we know we + * might use it, let's just turn it on ourselves here. + */ + cx18_write_reg_expect(cx, + (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK, + CX18_CLOCK_ENABLE2, + CX18_DMUX_CLK_MASK, + (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK); + + return ret; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-dvb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-dvb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-dvb.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-dvb.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * cx18 functions for DVB support + * + * Copyright (c) 2008 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx18-driver.h" + +int cx18_dvb_register(struct cx18_stream *stream); +void cx18_dvb_unregister(struct cx18_stream *stream); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-fileops.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-fileops.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-fileops.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-fileops.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,896 @@ +/* + * cx18 file operation functions + * + * Derived from ivtv-fileops.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-fileops.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-vbi.h" +#include "cx18-audio.h" +#include "cx18-mailbox.h" +#include "cx18-scb.h" +#include "cx18-streams.h" +#include "cx18-controls.h" +#include "cx18-ioctl.h" +#include "cx18-cards.h" + +/* This function tries to claim the stream for a specific file descriptor. + If no one else is using this stream then the stream is claimed and + associated VBI and IDX streams are also automatically claimed. + Possible error returns: -EBUSY if someone else has claimed + the stream or 0 on success. */ +int cx18_claim_stream(struct cx18_open_id *id, int type) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[type]; + struct cx18_stream *s_assoc; + + /* Nothing should ever try to directly claim the IDX stream */ + if (type == CX18_ENC_STREAM_TYPE_IDX) { + CX18_WARN("MPEG Index stream cannot be claimed " + "directly, but something tried.\n"); + return -EINVAL; + } + + if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) { + /* someone already claimed this stream */ + if (s->id == id->open_id) { + /* yes, this file descriptor did. So that's OK. */ + return 0; + } + if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) { + /* VBI is handled already internally, now also assign + the file descriptor to this stream for external + reading of the stream. */ + s->id = id->open_id; + CX18_DEBUG_INFO("Start Read VBI\n"); + return 0; + } + /* someone else is using this stream already */ + CX18_DEBUG_INFO("Stream %d is busy\n", type); + return -EBUSY; + } + s->id = id->open_id; + + /* + * CX18_ENC_STREAM_TYPE_MPG needs to claim: + * CX18_ENC_STREAM_TYPE_VBI, if VBI insertion is on for sliced VBI, or + * CX18_ENC_STREAM_TYPE_IDX, if VBI insertion is off for sliced VBI + * (We don't yet fix up MPEG Index entries for our inserted packets). + * + * For all other streams we're done. + */ + if (type != CX18_ENC_STREAM_TYPE_MPG) + return 0; + + s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; + if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) + s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + else if (!cx18_stream_enabled(s_assoc)) + return 0; + + set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); + + /* mark that it is used internally */ + set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags); + return 0; +} +EXPORT_SYMBOL(cx18_claim_stream); + +/* This function releases a previously claimed stream. It will take into + account associated VBI streams. */ +void cx18_release_stream(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + struct cx18_stream *s_assoc; + + s->id = -1; + if (s->type == CX18_ENC_STREAM_TYPE_IDX) { + /* + * The IDX stream is only used internally, and can + * only be indirectly unclaimed by unclaiming the MPG stream. + */ + return; + } + + if (s->type == CX18_ENC_STREAM_TYPE_VBI && + test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { + /* this stream is still in use internally */ + return; + } + if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) { + CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name); + return; + } + + cx18_flush_queues(s); + + /* + * CX18_ENC_STREAM_TYPE_MPG needs to release the + * CX18_ENC_STREAM_TYPE_VBI and/or CX18_ENC_STREAM_TYPE_IDX streams. + * + * For all other streams we're done. + */ + if (s->type != CX18_ENC_STREAM_TYPE_MPG) + return; + + /* Unclaim the associated MPEG Index stream */ + s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; + if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { + clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); + cx18_flush_queues(s_assoc); + } + + /* Unclaim the associated VBI stream */ + s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { + if (s_assoc->id == -1) { + /* + * The VBI stream is not still claimed by a file + * descriptor, so completely unclaim it. + */ + clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); + cx18_flush_queues(s_assoc); + } + } +} +EXPORT_SYMBOL(cx18_release_stream); + +static void cx18_dualwatch(struct cx18 *cx) +{ + struct v4l2_tuner vt; + u32 new_stereo_mode; + const u32 dual = 0x0200; + + new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); + memset(&vt, 0, sizeof(vt)); + cx18_call_all(cx, tuner, g_tuner, &vt); + if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && + (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) + new_stereo_mode = dual; + + if (new_stereo_mode == cx->dualwatch_stereo_mode) + return; + + CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", + cx->dualwatch_stereo_mode, new_stereo_mode); + if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode)) + CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); +} + + +static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block, + int *err) +{ + struct cx18 *cx = s->cx; + struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + struct cx18_mdl *mdl; + DEFINE_WAIT(wait); + + *err = 0; + while (1) { + if (s->type == CX18_ENC_STREAM_TYPE_MPG) { + /* Process pending program updates and VBI data */ + if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { + cx->dualwatch_jiffies = jiffies; + cx18_dualwatch(cx); + } + if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { + while ((mdl = cx18_dequeue(s_vbi, + &s_vbi->q_full))) { + /* byteswap and process VBI data */ + cx18_process_vbi_data(cx, mdl, + s_vbi->type); + cx18_stream_put_mdl_fw(s_vbi, mdl); + } + } + mdl = &cx->vbi.sliced_mpeg_mdl; + if (mdl->readpos != mdl->bytesused) + return mdl; + } + + /* do we have new data? */ + mdl = cx18_dequeue(s, &s->q_full); + if (mdl) { + if (!test_and_clear_bit(CX18_F_M_NEED_SWAP, + &mdl->m_flags)) + return mdl; + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + /* byteswap MPG data */ + cx18_mdl_swap(mdl); + else { + /* byteswap and process VBI data */ + cx18_process_vbi_data(cx, mdl, s->type); + } + return mdl; + } + + /* return if end of stream */ + if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + CX18_DEBUG_INFO("EOS %s\n", s->name); + return NULL; + } + + /* return if file was opened with O_NONBLOCK */ + if (non_block) { + *err = -EAGAIN; + return NULL; + } + + /* wait for more data to arrive */ + prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); + /* New buffers might have become available before we were added + to the waitqueue */ + if (!atomic_read(&s->q_full.depth)) + schedule(); + finish_wait(&s->waitq, &wait); + if (signal_pending(current)) { + /* return if a signal was received */ + CX18_DEBUG_INFO("User stopped %s\n", s->name); + *err = -EINTR; + return NULL; + } + } +} + +static void cx18_setup_sliced_vbi_mdl(struct cx18 *cx) +{ + struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl; + struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf; + int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; + + buf->buf = cx->vbi.sliced_mpeg_data[idx]; + buf->bytesused = cx->vbi.sliced_mpeg_size[idx]; + buf->readpos = 0; + + mdl->curr_buf = NULL; + mdl->bytesused = cx->vbi.sliced_mpeg_size[idx]; + mdl->readpos = 0; +} + +static size_t cx18_copy_buf_to_user(struct cx18_stream *s, + struct cx18_buffer *buf, char __user *ubuf, size_t ucount, bool *stop) +{ + struct cx18 *cx = s->cx; + size_t len = buf->bytesused - buf->readpos; + + *stop = false; + if (len > ucount) + len = ucount; + if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && + !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) { + /* + * Try to find a good splice point in the PS, just before + * an MPEG-2 Program Pack start code, and provide only + * up to that point to the user, so it's easy to insert VBI data + * the next time around. + * + * This will not work for an MPEG-2 TS and has only been + * verified by analysis to work for an MPEG-2 PS. Helen Buus + * pointed out this works for the CX23416 MPEG-2 DVD compatible + * stream, and research indicates both the MPEG 2 SVCD and DVD + * stream types use an MPEG-2 PS container. + */ + /* + * An MPEG-2 Program Stream (PS) is a series of + * MPEG-2 Program Packs terminated by an + * MPEG Program End Code after the last Program Pack. + * A Program Pack may hold a PS System Header packet and any + * number of Program Elementary Stream (PES) Packets + */ + const char *start = buf->buf + buf->readpos; + const char *p = start + 1; + const u8 *q; + u8 ch = cx->search_pack_header ? 0xba : 0xe0; + int stuffing, i; + + while (start + len > p) { + /* Scan for a 0 to find a potential MPEG-2 start code */ + q = memchr(p, 0, start + len - p); + if (q == NULL) + break; + p = q + 1; + /* + * Keep looking if not a + * MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba + * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0 + */ + if ((char *)q + 15 >= buf->buf + buf->bytesused || + q[1] != 0 || q[2] != 1 || q[3] != ch) + continue; + + /* If expecting the primary video PES */ + if (!cx->search_pack_header) { + /* Continue if it couldn't be a PES packet */ + if ((q[6] & 0xc0) != 0x80) + continue; + /* Check if a PTS or PTS & DTS follow */ + if (((q[7] & 0xc0) == 0x80 && /* PTS only */ + (q[9] & 0xf0) == 0x20) || /* PTS only */ + ((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */ + (q[9] & 0xf0) == 0x30)) { /* DTS follows */ + /* Assume we found the video PES hdr */ + ch = 0xba; /* next want a Program Pack*/ + cx->search_pack_header = 1; + p = q + 9; /* Skip this video PES hdr */ + } + continue; + } + + /* We may have found a Program Pack start code */ + + /* Get the count of stuffing bytes & verify them */ + stuffing = q[13] & 7; + /* all stuffing bytes must be 0xff */ + for (i = 0; i < stuffing; i++) + if (q[14 + i] != 0xff) + break; + if (i == stuffing && /* right number of stuffing bytes*/ + (q[4] & 0xc4) == 0x44 && /* marker check */ + (q[12] & 3) == 3 && /* marker check */ + q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */ + q[15 + stuffing] == 0 && + q[16 + stuffing] == 1) { + /* We declare we actually found a Program Pack*/ + cx->search_pack_header = 0; /* expect vid PES */ + len = (char *)q - start; + cx18_setup_sliced_vbi_mdl(cx); + *stop = true; + break; + } + } + } + if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { + CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n", + len, s->name); + return -EFAULT; + } + buf->readpos += len; + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + buf != &cx->vbi.sliced_mpeg_buf) + cx->mpg_data_received += len; + return len; +} + +static size_t cx18_copy_mdl_to_user(struct cx18_stream *s, + struct cx18_mdl *mdl, char __user *ubuf, size_t ucount) +{ + size_t tot_written = 0; + int rc; + bool stop = false; + + if (mdl->curr_buf == NULL) + mdl->curr_buf = list_first_entry(&mdl->buf_list, + struct cx18_buffer, list); + + if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { + /* + * For some reason we've exhausted the buffers, but the MDL + * object still said some data was unread. + * Fix that and bail out. + */ + mdl->readpos = mdl->bytesused; + return 0; + } + + list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { + + if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) + continue; + + rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written, + ucount - tot_written, &stop); + if (rc < 0) + return rc; + mdl->readpos += rc; + tot_written += rc; + + if (stop || /* Forced stopping point for VBI insertion */ + tot_written >= ucount || /* Reader request statisfied */ + mdl->curr_buf->readpos < mdl->curr_buf->bytesused || + mdl->readpos >= mdl->bytesused) /* MDL buffers drained */ + break; + } + return tot_written; +} + +static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, + size_t tot_count, int non_block) +{ + struct cx18 *cx = s->cx; + size_t tot_written = 0; + int single_frame = 0; + + if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) { + /* shouldn't happen */ + CX18_DEBUG_WARN("Stream %s not initialized before read\n", + s->name); + return -EIO; + } + + /* Each VBI buffer is one frame, the v4l2 API says that for VBI the + frames should arrive one-by-one, so make sure we never output more + than one VBI frame at a time */ + if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx)) + single_frame = 1; + + for (;;) { + struct cx18_mdl *mdl; + int rc; + + mdl = cx18_get_mdl(s, non_block, &rc); + /* if there is no data available... */ + if (mdl == NULL) { + /* if we got data, then return that regardless */ + if (tot_written) + break; + /* EOS condition */ + if (rc == 0) { + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + clear_bit(CX18_F_S_APPL_IO, &s->s_flags); + cx18_release_stream(s); + } + /* set errno */ + return rc; + } + + rc = cx18_copy_mdl_to_user(s, mdl, ubuf + tot_written, + tot_count - tot_written); + + if (mdl != &cx->vbi.sliced_mpeg_mdl) { + if (mdl->readpos == mdl->bytesused) + cx18_stream_put_mdl_fw(s, mdl); + else + cx18_push(s, mdl, &s->q_full); + } else if (mdl->readpos == mdl->bytesused) { + int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; + + cx->vbi.sliced_mpeg_size[idx] = 0; + cx->vbi.inserted_frame++; + cx->vbi_data_inserted += mdl->bytesused; + } + if (rc < 0) + return rc; + tot_written += rc; + + if (tot_written == tot_count || single_frame) + break; + } + return tot_written; +} + +static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, + size_t count, loff_t *pos, int non_block) +{ + ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0; + struct cx18 *cx = s->cx; + + CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); + if (rc > 0) + pos += rc; + return rc; +} + +int cx18_start_capture(struct cx18_open_id *id) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + struct cx18_stream *s_vbi; + struct cx18_stream *s_idx; + + if (s->type == CX18_ENC_STREAM_TYPE_RAD) { + /* you cannot read from these stream types. */ + return -EPERM; + } + + /* Try to claim this stream. */ + if (cx18_claim_stream(id, s->type)) + return -EBUSY; + + /* If capture is already in progress, then we also have to + do nothing extra. */ + if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || + test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { + set_bit(CX18_F_S_APPL_IO, &s->s_flags); + return 0; + } + + /* Start associated VBI or IDX stream capture if required */ + s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; + if (s->type == CX18_ENC_STREAM_TYPE_MPG) { + /* + * The VBI and IDX streams should have been claimed + * automatically, if for internal use, when the MPG stream was + * claimed. We only need to start these streams capturing. + */ + if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) && + !test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { + if (cx18_start_v4l2_encode_stream(s_idx)) { + CX18_DEBUG_WARN("IDX capture start failed\n"); + clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); + goto start_failed; + } + CX18_DEBUG_INFO("IDX capture started\n"); + } + if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { + if (cx18_start_v4l2_encode_stream(s_vbi)) { + CX18_DEBUG_WARN("VBI capture start failed\n"); + clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); + goto start_failed; + } + CX18_DEBUG_INFO("VBI insertion started\n"); + } + } + + /* Tell the card to start capturing */ + if (!cx18_start_v4l2_encode_stream(s)) { + /* We're done */ + set_bit(CX18_F_S_APPL_IO, &s->s_flags); + /* Resume a possibly paused encoder */ + if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle); + return 0; + } + +start_failed: + CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); + + /* + * The associated VBI and IDX streams for internal use are released + * automatically when the MPG stream is released. We only need to stop + * the associated stream. + */ + if (s->type == CX18_ENC_STREAM_TYPE_MPG) { + /* Stop the IDX stream which is always for internal use */ + if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { + cx18_stop_v4l2_encode_stream(s_idx, 0); + clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); + } + /* Stop the VBI stream, if only running for internal use */ + if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && + !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { + cx18_stop_v4l2_encode_stream(s_vbi, 0); + clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); + } + } + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + cx18_release_stream(s); /* Also releases associated streams */ + return -EIO; +} + +ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos) +{ + struct cx18_open_id *id = file2id(filp); + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + int rc; + + CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); + + mutex_lock(&cx->serialize_lock); + rc = cx18_start_capture(id); + mutex_unlock(&cx->serialize_lock); + if (rc) + return rc; + + if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (id->type == CX18_ENC_STREAM_TYPE_YUV)) { + return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0, + filp->f_flags & O_NONBLOCK); + } + + return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); +} + +unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) +{ + struct cx18_open_id *id = file2id(filp); + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); + + /* Start a capture if there is none */ + if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + int rc; + + mutex_lock(&cx->serialize_lock); + rc = cx18_start_capture(id); + mutex_unlock(&cx->serialize_lock); + if (rc) { + CX18_DEBUG_INFO("Could not start capture for %s (%d)\n", + s->name, rc); + return POLLERR; + } + CX18_DEBUG_FILE("Encoder poll started capture\n"); + } + + if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (id->type == CX18_ENC_STREAM_TYPE_YUV)) { + int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait); + if (eof && videobuf_poll == POLLERR) + return POLLHUP; + else + return videobuf_poll; + } + + /* add stream's waitq to the poll list */ + CX18_DEBUG_HI_FILE("Encoder poll\n"); + poll_wait(filp, &s->waitq, wait); + + if (atomic_read(&s->q_full.depth)) + return POLLIN | POLLRDNORM; + if (eof) + return POLLHUP; + return 0; +} + +int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cx18_open_id *id = file->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); + + if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (id->type == CX18_ENC_STREAM_TYPE_YUV)) { + + /* Start a capture if there is none */ + if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + int rc; + + mutex_lock(&cx->serialize_lock); + rc = cx18_start_capture(id); + mutex_unlock(&cx->serialize_lock); + if (rc) { + CX18_DEBUG_INFO( + "Could not start capture for %s (%d)\n", + s->name, rc); + return -EINVAL; + } + CX18_DEBUG_FILE("Encoder mmap started capture\n"); + } + + return videobuf_mmap_mapper(&s->vbuf_q, vma); + } + + return -EINVAL; +} + +void cx18_vb_timeout(unsigned long data) +{ + struct cx18_stream *s = (struct cx18_stream *)data; + struct cx18_videobuf_buffer *buf; + unsigned long flags; + + /* Return all of the buffers in error state, so the vbi/vid inode + * can return from blocking. + */ + spin_lock_irqsave(&s->vb_lock, flags); + while (!list_empty(&s->vb_capture)) { + buf = list_entry(s->vb_capture.next, + struct cx18_videobuf_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + } + spin_unlock_irqrestore(&s->vb_lock, flags); +} + +void cx18_stop_capture(struct cx18_open_id *id, int gop_end) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; + + CX18_DEBUG_IOCTL("close() of %s\n", s->name); + + /* 'Unclaim' this stream */ + + /* Stop capturing */ + if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + CX18_DEBUG_INFO("close stopping capture\n"); + if (id->type == CX18_ENC_STREAM_TYPE_MPG) { + /* Stop internal use associated VBI and IDX streams */ + if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && + !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { + CX18_DEBUG_INFO("close stopping embedded VBI " + "capture\n"); + cx18_stop_v4l2_encode_stream(s_vbi, 0); + } + if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { + CX18_DEBUG_INFO("close stopping IDX capture\n"); + cx18_stop_v4l2_encode_stream(s_idx, 0); + } + } + if (id->type == CX18_ENC_STREAM_TYPE_VBI && + test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) + /* Also used internally, don't stop capturing */ + s->id = -1; + else + cx18_stop_v4l2_encode_stream(s, gop_end); + } + if (!gop_end) { + clear_bit(CX18_F_S_APPL_IO, &s->s_flags); + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + cx18_release_stream(s); + } +} + +int cx18_v4l2_close(struct file *filp) +{ + struct v4l2_fh *fh = filp->private_data; + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + CX18_DEBUG_IOCTL("close() of %s\n", s->name); + + v4l2_fh_del(fh); + v4l2_fh_exit(fh); + + /* Easy case first: this stream was never claimed by us */ + if (s->id != id->open_id) { + kfree(id); + return 0; + } + + /* 'Unclaim' this stream */ + + /* Stop radio */ + mutex_lock(&cx->serialize_lock); + if (id->type == CX18_ENC_STREAM_TYPE_RAD) { + /* Closing radio device, return to TV mode */ + cx18_mute(cx); + /* Mark that the radio is no longer in use */ + clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); + /* Switch tuner to TV */ + cx18_call_all(cx, core, s_std, cx->std); + /* Select correct audio input (i.e. TV tuner or Line in) */ + cx18_audio_set_io(cx); + if (atomic_read(&cx->ana_capturing) > 0) { + /* Undo video mute */ + cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, + (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) | + (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8))); + } + /* Done! Unmute and continue. */ + cx18_unmute(cx); + cx18_release_stream(s); + } else { + cx18_stop_capture(id, 0); + if (id->type == CX18_ENC_STREAM_TYPE_YUV) + videobuf_mmap_free(&id->vbuf_q); + } + kfree(id); + mutex_unlock(&cx->serialize_lock); + return 0; +} + +static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) +{ + struct cx18 *cx = s->cx; + struct cx18_open_id *item; + + CX18_DEBUG_FILE("open %s\n", s->name); + + /* Allocate memory */ + item = kzalloc(sizeof(struct cx18_open_id), GFP_KERNEL); + if (NULL == item) { + CX18_DEBUG_WARN("nomem on v4l2 open\n"); + return -ENOMEM; + } + v4l2_fh_init(&item->fh, s->video_dev); + + item->cx = cx; + item->type = s->type; + + item->open_id = cx->open_id++; + filp->private_data = &item->fh; + + if (item->type == CX18_ENC_STREAM_TYPE_RAD) { + /* Try to claim this stream */ + if (cx18_claim_stream(item, item->type)) { + /* No, it's already in use */ + v4l2_fh_exit(&item->fh); + kfree(item); + return -EBUSY; + } + + if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + if (atomic_read(&cx->ana_capturing) > 0) { + /* switching to radio while capture is + in progress is not polite */ + cx18_release_stream(s); + v4l2_fh_exit(&item->fh); + kfree(item); + return -EBUSY; + } + } + + /* Mark that the radio is being used. */ + set_bit(CX18_F_I_RADIO_USER, &cx->i_flags); + /* We have the radio */ + cx18_mute(cx); + /* Switch tuner to radio */ + cx18_call_all(cx, tuner, s_radio); + /* Select the correct audio input (i.e. radio tuner) */ + cx18_audio_set_io(cx); + /* Done! Unmute and continue. */ + cx18_unmute(cx); + } + v4l2_fh_add(&item->fh); + return 0; +} + +int cx18_v4l2_open(struct file *filp) +{ + int res; + struct video_device *video_dev = video_devdata(filp); + struct cx18_stream *s = video_get_drvdata(video_dev); + struct cx18 *cx = s->cx; + + mutex_lock(&cx->serialize_lock); + if (cx18_init_on_first_open(cx)) { + CX18_ERR("Failed to initialize on %s\n", + video_device_node_name(video_dev)); + mutex_unlock(&cx->serialize_lock); + return -ENXIO; + } + res = cx18_serialized_open(s, filp); + mutex_unlock(&cx->serialize_lock); + return res; +} + +void cx18_mute(struct cx18 *cx) +{ + u32 h; + if (atomic_read(&cx->ana_capturing)) { + h = cx18_find_handle(cx); + if (h != CX18_INVALID_TASK_HANDLE) + cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1); + else + CX18_ERR("Can't find valid task handle for mute\n"); + } + CX18_DEBUG_INFO("Mute\n"); +} + +void cx18_unmute(struct cx18 *cx) +{ + u32 h; + if (atomic_read(&cx->ana_capturing)) { + h = cx18_find_handle(cx); + if (h != CX18_INVALID_TASK_HANDLE) { + cx18_msleep_timeout(100, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12); + cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0); + } else + CX18_ERR("Can't find valid task handle for unmute\n"); + } + CX18_DEBUG_INFO("Unmute\n"); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-fileops.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-fileops.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-fileops.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-fileops.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * cx18 file operation functions + * + * Derived from ivtv-fileops.h + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +/* Testing/Debugging */ +int cx18_v4l2_open(struct file *filp); +ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos); +ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count, + loff_t *pos); +int cx18_v4l2_close(struct file *filp); +unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait); +int cx18_start_capture(struct cx18_open_id *id); +void cx18_stop_capture(struct cx18_open_id *id, int gop_end); +void cx18_mute(struct cx18 *cx); +void cx18_unmute(struct cx18 *cx); +int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma); +void cx18_vb_timeout(unsigned long data); + +/* Shared with cx18-alsa module */ +int cx18_claim_stream(struct cx18_open_id *id, int type); +void cx18_release_stream(struct cx18_stream *s); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-firmware.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,448 @@ +/* + * cx18 firmware functions + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-scb.h" +#include "cx18-irq.h" +#include "cx18-firmware.h" +#include "cx18-cards.h" +#include + +#define CX18_PROC_SOFT_RESET 0xc70010 +#define CX18_DDR_SOFT_RESET 0xc70014 +#define CX18_CLOCK_SELECT1 0xc71000 +#define CX18_CLOCK_SELECT2 0xc71004 +#define CX18_HALF_CLOCK_SELECT1 0xc71008 +#define CX18_HALF_CLOCK_SELECT2 0xc7100C +#define CX18_CLOCK_POLARITY1 0xc71010 +#define CX18_CLOCK_POLARITY2 0xc71014 +#define CX18_ADD_DELAY_ENABLE1 0xc71018 +#define CX18_ADD_DELAY_ENABLE2 0xc7101C +#define CX18_CLOCK_ENABLE1 0xc71020 +#define CX18_CLOCK_ENABLE2 0xc71024 + +#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 + +#define CX18_FAST_CLOCK_PLL_INT 0xc78000 +#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004 +#define CX18_FAST_CLOCK_PLL_POST 0xc78008 +#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C +#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010 + +#define CX18_SLOW_CLOCK_PLL_INT 0xc78014 +#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018 +#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C +#define CX18_MPEG_CLOCK_PLL_INT 0xc78040 +#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044 +#define CX18_MPEG_CLOCK_PLL_POST 0xc78048 +#define CX18_PLL_POWER_DOWN 0xc78088 +#define CX18_SW1_INT_STATUS 0xc73104 +#define CX18_SW1_INT_ENABLE_PCI 0xc7311C +#define CX18_SW2_INT_SET 0xc73140 +#define CX18_SW2_INT_STATUS 0xc73144 +#define CX18_ADEC_CONTROL 0xc78120 + +#define CX18_DDR_REQUEST_ENABLE 0xc80000 +#define CX18_DDR_CHIP_CONFIG 0xc80004 +#define CX18_DDR_REFRESH 0xc80008 +#define CX18_DDR_TIMING1 0xc8000C +#define CX18_DDR_TIMING2 0xc80010 +#define CX18_DDR_POWER_REG 0xc8001C + +#define CX18_DDR_TUNE_LANE 0xc80048 +#define CX18_DDR_INITIAL_EMRS 0xc80054 +#define CX18_DDR_MB_PER_ROW_7 0xc8009C +#define CX18_DDR_BASE_63_ADDR 0xc804FC + +#define CX18_WMB_CLIENT02 0xc90108 +#define CX18_WMB_CLIENT05 0xc90114 +#define CX18_WMB_CLIENT06 0xc90118 +#define CX18_WMB_CLIENT07 0xc9011C +#define CX18_WMB_CLIENT08 0xc90120 +#define CX18_WMB_CLIENT09 0xc90124 +#define CX18_WMB_CLIENT10 0xc90128 +#define CX18_WMB_CLIENT11 0xc9012C +#define CX18_WMB_CLIENT12 0xc90130 +#define CX18_WMB_CLIENT13 0xc90134 +#define CX18_WMB_CLIENT14 0xc90138 + +#define CX18_DSP0_INTERRUPT_MASK 0xd0004C + +#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ +#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ + +struct cx18_apu_rom_seghdr { + u32 sync1; + u32 sync2; + u32 addr; + u32 size; +}; + +static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) +{ + const struct firmware *fw = NULL; + int i, j; + unsigned size; + u32 __iomem *dst = (u32 __iomem *)mem; + const u32 *src; + + if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { + CX18_ERR("Unable to open firmware %s\n", fn); + CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); + return -ENOMEM; + } + + src = (const u32 *)fw->data; + + for (i = 0; i < fw->size; i += 4096) { + cx18_setup_page(cx, i); + for (j = i; j < fw->size && j < i + 4096; j += 4) { + /* no need for endianness conversion on the ppc */ + cx18_raw_writel(cx, *src, dst); + if (cx18_raw_readl(cx, dst) != *src) { + CX18_ERR("Mismatch at offset %x\n", i); + release_firmware(fw); + cx18_setup_page(cx, 0); + return -EIO; + } + dst++; + src++; + } + } + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) + CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); + size = fw->size; + release_firmware(fw); + cx18_setup_page(cx, SCB_OFFSET); + return size; +} + +static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, + u32 *entry_addr) +{ + const struct firmware *fw = NULL; + int i, j; + unsigned size; + const u32 *src; + struct cx18_apu_rom_seghdr seghdr; + const u8 *vers; + u32 offset = 0; + u32 apu_version = 0; + int sz; + + if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { + CX18_ERR("unable to open firmware %s\n", fn); + CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); + cx18_setup_page(cx, 0); + return -ENOMEM; + } + + *entry_addr = 0; + src = (const u32 *)fw->data; + vers = fw->data + sizeof(seghdr); + sz = fw->size; + + apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; + while (offset + sizeof(seghdr) < fw->size) { + /* TODO: byteswapping */ + memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); + offset += sizeof(seghdr); + if (seghdr.sync1 != APU_ROM_SYNC1 || + seghdr.sync2 != APU_ROM_SYNC2) { + offset += seghdr.size; + continue; + } + CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, + seghdr.addr + seghdr.size - 1); + if (*entry_addr == 0) + *entry_addr = seghdr.addr; + if (offset + seghdr.size > sz) + break; + for (i = 0; i < seghdr.size; i += 4096) { + cx18_setup_page(cx, seghdr.addr + i); + for (j = i; j < seghdr.size && j < i + 4096; j += 4) { + /* no need for endianness conversion on the ppc */ + cx18_raw_writel(cx, src[(offset + j) / 4], + dst + seghdr.addr + j); + if (cx18_raw_readl(cx, dst + seghdr.addr + j) + != src[(offset + j) / 4]) { + CX18_ERR("Mismatch at offset %x\n", + offset + j); + release_firmware(fw); + cx18_setup_page(cx, 0); + return -EIO; + } + } + } + offset += seghdr.size; + } + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) + CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", + fn, apu_version, fw->size); + size = fw->size; + release_firmware(fw); + cx18_setup_page(cx, 0); + return size; +} + +void cx18_halt_firmware(struct cx18 *cx) +{ + CX18_DEBUG_INFO("Preparing for firmware halt.\n"); + cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, + 0x0000000F, 0x000F000F); + cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL, + 0x00000002, 0x00020002); +} + +void cx18_init_power(struct cx18 *cx, int lowpwr) +{ + /* power-down Spare and AOM PLLs */ + /* power-up fast, slow and mpeg PLLs */ + cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN); + + /* ADEC out of sleep */ + cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL, + 0x00000000, 0x00020002); + + /* + * The PLL parameters are based on the external crystal frequency that + * would ideally be: + * + * NTSC Color subcarrier freq * 8 = + * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz + * + * The accidents of history and rationale that explain from where this + * combination of magic numbers originate can be found in: + * + * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in + * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80 + * + * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the + * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83 + * + * As Mike Bradley has rightly pointed out, it's not the exact crystal + * frequency that matters, only that all parts of the driver and + * firmware are using the same value (close to the ideal value). + * + * Since I have a strong suspicion that, if the firmware ever assumes a + * crystal value at all, it will assume 28.636360 MHz, the crystal + * freq used in calculations in this driver will be: + * + * xtal_freq = 28.636360 MHz + * + * an error of less than 0.13 ppm which is way, way better than any off + * the shelf crystal will have for accuracy anyway. + * + * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors. + * + * Many thanks to Jeff Campbell and Mike Bradley for their extensive + * investigation, experimentation, testing, and suggested solutions of + * of audio/video sync problems with SVideo and CVBS captures. + */ + + /* the fast clock is at 200/245 MHz */ + /* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/ + /* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/ + cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); + cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7, + CX18_FAST_CLOCK_PLL_FRAC); + + cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST); + cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE); + cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH); + + /* set slow clock to 125/120 MHz */ + /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */ + /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */ + cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT); + cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F, + CX18_SLOW_CLOCK_PLL_FRAC); + cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST); + + /* mpeg clock pll 54MHz */ + /* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */ + cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT); + cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC); + cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST); + + /* Defaults */ + /* APU = SC or SC/2 = 125/62.5 */ + /* EPU = SC = 125 */ + /* DDR = FC = 180 */ + /* ENC = SC = 125 */ + /* AI1 = SC = 125 */ + /* VIM2 = disabled */ + /* PCI = FC/2 = 90 */ + /* AI2 = disabled */ + /* DEMUX = disabled */ + /* AO = SC/2 = 62.5 */ + /* SER = 54MHz */ + /* VFC = disabled */ + /* USB = disabled */ + + if (lowpwr) { + cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1, + 0x00000020, 0xFFFFFFFF); + cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2, + 0x00000004, 0xFFFFFFFF); + } else { + /* This doesn't explicitly set every clock select */ + cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1, + 0x00000004, 0x00060006); + cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2, + 0x00000006, 0x00060006); + } + + cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1, + 0x00000002, 0xFFFFFFFF); + cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2, + 0x00000104, 0xFFFFFFFF); + cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1, + 0x00009026, 0xFFFFFFFF); + cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2, + 0x00003105, 0xFFFFFFFF); +} + +void cx18_init_memory(struct cx18 *cx) +{ + cx18_msleep_timeout(10, 0); + cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET, + 0x00000000, 0x00010001); + cx18_msleep_timeout(10, 0); + + cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG); + + cx18_msleep_timeout(10, 0); + + cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH); + cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1); + cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2); + + cx18_msleep_timeout(10, 0); + + /* Initialize DQS pad time */ + cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE); + cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS); + + cx18_msleep_timeout(10, 0); + + cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET, + 0x00000000, 0x00020002); + cx18_msleep_timeout(10, 0); + + /* use power-down mode when idle */ + cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG); + + cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN, + 0x00000001, 0x00010001); + + cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7); + cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR); + + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02); /* AO */ + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09); /* AI2 */ + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05); /* VIM1 */ + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06); /* AI1 */ + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07); /* 3D comb */ + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10); /* ME */ + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12); /* ENC */ + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13); /* PK */ + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11); /* RC */ + cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14); /* AVO */ +} + +int cx18_firmware_init(struct cx18 *cx) +{ + u32 fw_entry_addr; + int sz, retries; + u32 api_args[MAX_MB_ARGUMENTS]; + + /* Allow chip to control CLKRUN */ + cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK); + + /* Stop the firmware */ + cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, + 0x0000000F, 0x000F000F); + + cx18_msleep_timeout(1, 0); + + /* If the CPU is still running */ + if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) { + CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__); + return -EIO; + } + + cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); + cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx); + if (sz <= 0) + return sz; + + /* The SCB & IPC area *must* be correct before starting the firmwares */ + cx18_init_scb(cx); + + fw_entry_addr = 0; + sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx, + &fw_entry_addr); + if (sz <= 0) + return sz; + + /* Start the CPU. The CPU will take care of the APU for us. */ + cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET, + 0x00000000, 0x00080008); + + /* Wait up to 500 ms for the APU to come out of reset */ + for (retries = 0; + retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1; + retries++) + cx18_msleep_timeout(10, 0); + + cx18_msleep_timeout(200, 0); + + if (retries == 50 && + (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) { + CX18_ERR("Could not start the CPU\n"); + return -EIO; + } + + /* + * The CPU had once before set up to receive an interrupt for it's + * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an + * interrupt when it sends us an ack, but by the time we process it, + * that flag in the SW2 status register has been cleared by the CPU + * firmware. We'll prevent that not so useful condition from happening + * by clearing the CPU's interrupt enables for Ack IRQ's we want to + * process. + */ + cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + /* Try a benign command to see if the CPU is alive and well */ + sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0); + if (sz < 0) + return sz; + + /* initialize GPIO */ + cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-firmware.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-firmware.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-firmware.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * cx18 firmware functions + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +int cx18_firmware_init(struct cx18 *cx); +void cx18_halt_firmware(struct cx18 *cx); +void cx18_init_memory(struct cx18 *cx); +void cx18_init_power(struct cx18 *cx, int lowpwr); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-gpio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-gpio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-gpio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-gpio.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,347 @@ +/* + * cx18 gpio functions + * + * Derived from ivtv-gpio.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-cards.h" +#include "cx18-gpio.h" +#include "tuner-xc2028.h" + +/********************* GPIO stuffs *********************/ + +/* GPIO registers */ +#define CX18_REG_GPIO_IN 0xc72010 +#define CX18_REG_GPIO_OUT1 0xc78100 +#define CX18_REG_GPIO_DIR1 0xc78108 +#define CX18_REG_GPIO_OUT2 0xc78104 +#define CX18_REG_GPIO_DIR2 0xc7810c + +/* + * HVR-1600 GPIO pins, courtesy of Hauppauge: + * + * gpio0: zilog ir process reset pin + * gpio1: zilog programming pin (you should never use this) + * gpio12: cx24227 reset pin + * gpio13: cs5345 reset pin +*/ + +/* + * File scope utility functions + */ +static void gpio_write(struct cx18 *cx) +{ + u32 dir_lo = cx->gpio_dir & 0xffff; + u32 val_lo = cx->gpio_val & 0xffff; + u32 dir_hi = cx->gpio_dir >> 16; + u32 val_hi = cx->gpio_val >> 16; + + cx18_write_reg_expect(cx, dir_lo << 16, + CX18_REG_GPIO_DIR1, ~dir_lo, dir_lo); + cx18_write_reg_expect(cx, (dir_lo << 16) | val_lo, + CX18_REG_GPIO_OUT1, val_lo, dir_lo); + cx18_write_reg_expect(cx, dir_hi << 16, + CX18_REG_GPIO_DIR2, ~dir_hi, dir_hi); + cx18_write_reg_expect(cx, (dir_hi << 16) | val_hi, + CX18_REG_GPIO_OUT2, val_hi, dir_hi); +} + +static void gpio_update(struct cx18 *cx, u32 mask, u32 data) +{ + if (mask == 0) + return; + + mutex_lock(&cx->gpio_lock); + cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask); + gpio_write(cx); + mutex_unlock(&cx->gpio_lock); +} + +static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi, + unsigned int assert_msecs, + unsigned int recovery_msecs) +{ + u32 mask; + + mask = active_lo | active_hi; + if (mask == 0) + return; + + /* + * Assuming that active_hi and active_lo are a subsets of the bits in + * gpio_dir. Also assumes that active_lo and active_hi don't overlap + * in any bit position + */ + + /* Assert */ + gpio_update(cx, mask, ~active_lo); + schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs)); + + /* Deassert */ + gpio_update(cx, mask, ~active_hi); + schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs)); +} + +/* + * GPIO Multiplexer - logical device + */ +static int gpiomux_log_status(struct v4l2_subdev *sd) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + + mutex_lock(&cx->gpio_lock); + CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n", + cx->gpio_dir, cx->gpio_val); + mutex_unlock(&cx->gpio_lock); + return 0; +} + +static int gpiomux_s_radio(struct v4l2_subdev *sd) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + + /* + * FIXME - work out the cx->active/audio_input mess - this is + * intended to handle the switch to radio mode and set the + * audio routing, but we need to update the state in cx + */ + gpio_update(cx, cx->card->gpio_audio_input.mask, + cx->card->gpio_audio_input.radio); + return 0; +} + +static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + u32 data; + + switch (cx->card->audio_inputs[cx->audio_input].muxer_input) { + case 1: + data = cx->card->gpio_audio_input.linein; + break; + case 0: + data = cx->card->gpio_audio_input.tuner; + break; + default: + /* + * FIXME - work out the cx->active/audio_input mess - this is + * intended to handle the switch from radio mode and set the + * audio routing, but we need to update the state in cx + */ + data = cx->card->gpio_audio_input.tuner; + break; + } + gpio_update(cx, cx->card->gpio_audio_input.mask, data); + return 0; +} + +static int gpiomux_s_audio_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + u32 data; + + switch (input) { + case 0: + data = cx->card->gpio_audio_input.tuner; + break; + case 1: + data = cx->card->gpio_audio_input.linein; + break; + case 2: + data = cx->card->gpio_audio_input.radio; + break; + default: + return -EINVAL; + } + gpio_update(cx, cx->card->gpio_audio_input.mask, data); + return 0; +} + +static const struct v4l2_subdev_core_ops gpiomux_core_ops = { + .log_status = gpiomux_log_status, + .s_std = gpiomux_s_std, +}; + +static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = { + .s_radio = gpiomux_s_radio, +}; + +static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = { + .s_routing = gpiomux_s_audio_routing, +}; + +static const struct v4l2_subdev_ops gpiomux_ops = { + .core = &gpiomux_core_ops, + .tuner = &gpiomux_tuner_ops, + .audio = &gpiomux_audio_ops, +}; + +/* + * GPIO Reset Controller - logical device + */ +static int resetctrl_log_status(struct v4l2_subdev *sd) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + + mutex_lock(&cx->gpio_lock); + CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n", + cx->gpio_dir, cx->gpio_val); + mutex_unlock(&cx->gpio_lock); + return 0; +} + +static int resetctrl_reset(struct v4l2_subdev *sd, u32 val) +{ + struct cx18 *cx = v4l2_get_subdevdata(sd); + const struct cx18_gpio_i2c_slave_reset *p; + + p = &cx->card->gpio_i2c_slave_reset; + switch (val) { + case CX18_GPIO_RESET_I2C: + gpio_reset_seq(cx, p->active_lo_mask, p->active_hi_mask, + p->msecs_asserted, p->msecs_recovery); + break; + case CX18_GPIO_RESET_Z8F0811: + /* + * Assert timing for the Z8F0811 on HVR-1600 boards: + * 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to + * initiate + * 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock + * cycles (6,601,085 nanoseconds ~= 7 milliseconds) + * 3. DBG pin must be high before chip exits reset for normal + * operation. DBG is open drain and hopefully pulled high + * since we don't normally drive it (GPIO 1?) for the + * HVR-1600 + * 4. Z8F0811 won't exit reset until RESET is deasserted + * 5. Zilog comes out of reset, loads reset vector address and + * executes from there. Required recovery delay unknown. + */ + gpio_reset_seq(cx, p->ir_reset_mask, 0, + p->msecs_asserted, p->msecs_recovery); + break; + case CX18_GPIO_RESET_XC2028: + if (cx->card->tuners[0].tuner == TUNER_XC2028) + gpio_reset_seq(cx, (1 << cx->card->xceive_pin), 0, + 1, 1); + break; + } + return 0; +} + +static const struct v4l2_subdev_core_ops resetctrl_core_ops = { + .log_status = resetctrl_log_status, + .reset = resetctrl_reset, +}; + +static const struct v4l2_subdev_ops resetctrl_ops = { + .core = &resetctrl_core_ops, +}; + +/* + * External entry points + */ +void cx18_gpio_init(struct cx18 *cx) +{ + mutex_lock(&cx->gpio_lock); + cx->gpio_dir = cx->card->gpio_init.direction; + cx->gpio_val = cx->card->gpio_init.initial_value; + + if (cx->card->tuners[0].tuner == TUNER_XC2028) { + cx->gpio_dir |= 1 << cx->card->xceive_pin; + cx->gpio_val |= 1 << cx->card->xceive_pin; + } + + if (cx->gpio_dir == 0) { + mutex_unlock(&cx->gpio_lock); + return; + } + + CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n", + cx18_read_reg(cx, CX18_REG_GPIO_DIR1), + cx18_read_reg(cx, CX18_REG_GPIO_DIR2), + cx18_read_reg(cx, CX18_REG_GPIO_OUT1), + cx18_read_reg(cx, CX18_REG_GPIO_OUT2)); + + gpio_write(cx); + mutex_unlock(&cx->gpio_lock); +} + +int cx18_gpio_register(struct cx18 *cx, u32 hw) +{ + struct v4l2_subdev *sd; + const struct v4l2_subdev_ops *ops; + char *str; + + switch (hw) { + case CX18_HW_GPIO_MUX: + sd = &cx->sd_gpiomux; + ops = &gpiomux_ops; + str = "gpio-mux"; + break; + case CX18_HW_GPIO_RESET_CTRL: + sd = &cx->sd_resetctrl; + ops = &resetctrl_ops; + str = "gpio-reset-ctrl"; + break; + default: + return -EINVAL; + } + + v4l2_subdev_init(sd, ops); + v4l2_set_subdevdata(sd, cx); + snprintf(sd->name, sizeof(sd->name), "%s %s", cx->v4l2_dev.name, str); + sd->grp_id = hw; + return v4l2_device_register_subdev(&cx->v4l2_dev, sd); +} + +void cx18_reset_ir_gpio(void *data) +{ + struct cx18 *cx = to_cx18((struct v4l2_device *)data); + + if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0) + return; + + CX18_DEBUG_INFO("Resetting IR microcontroller\n"); + + v4l2_subdev_call(&cx->sd_resetctrl, + core, reset, CX18_GPIO_RESET_Z8F0811); +} +EXPORT_SYMBOL(cx18_reset_ir_gpio); +/* This symbol is exported for use by lirc_pvr150 for the IR-blaster */ + +/* Xceive tuner reset function */ +int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value) +{ + struct i2c_algo_bit_data *algo = dev; + struct cx18_i2c_algo_callback_data *cb_data = algo->data; + struct cx18 *cx = cb_data->cx; + + if (cmd != XC2028_TUNER_RESET || + cx->card->tuners[0].tuner != TUNER_XC2028) + return 0; + + CX18_DEBUG_INFO("Resetting XCeive tuner\n"); + return v4l2_subdev_call(&cx->sd_resetctrl, + core, reset, CX18_GPIO_RESET_XC2028); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-gpio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-gpio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-gpio.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-gpio.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * cx18 gpio functions + * + * Derived from ivtv-gpio.h + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +void cx18_gpio_init(struct cx18 *cx); +int cx18_gpio_register(struct cx18 *cx, u32 hw); + +enum cx18_gpio_reset_type { + CX18_GPIO_RESET_I2C = 0, + CX18_GPIO_RESET_Z8F0811 = 1, + CX18_GPIO_RESET_XC2028 = 2, +}; + +void cx18_reset_ir_gpio(void *data); +int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,330 @@ +/* + * cx18 I2C functions + * + * Derived from ivtv-i2c.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-cards.h" +#include "cx18-gpio.h" +#include "cx18-i2c.h" +#include "cx18-irq.h" + +#define CX18_REG_I2C_1_WR 0xf15000 +#define CX18_REG_I2C_1_RD 0xf15008 +#define CX18_REG_I2C_2_WR 0xf25100 +#define CX18_REG_I2C_2_RD 0xf25108 + +#define SETSCL_BIT 0x0001 +#define SETSDL_BIT 0x0002 +#define GETSCL_BIT 0x0004 +#define GETSDL_BIT 0x0008 + +#define CX18_CS5345_I2C_ADDR 0x4c +#define CX18_Z8F0811_IR_TX_I2C_ADDR 0x70 +#define CX18_Z8F0811_IR_RX_I2C_ADDR 0x71 + +/* This array should match the CX18_HW_ defines */ +static const u8 hw_addrs[] = { + 0, /* CX18_HW_TUNER */ + 0, /* CX18_HW_TVEEPROM */ + CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */ + 0, /* CX18_HW_DVB */ + 0, /* CX18_HW_418_AV */ + 0, /* CX18_HW_GPIO_MUX */ + 0, /* CX18_HW_GPIO_RESET_CTRL */ + CX18_Z8F0811_IR_TX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_TX_HAUP */ + CX18_Z8F0811_IR_RX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_RX_HAUP */ +}; + +/* This array should match the CX18_HW_ defines */ +/* This might well become a card-specific array */ +static const u8 hw_bus[] = { + 1, /* CX18_HW_TUNER */ + 0, /* CX18_HW_TVEEPROM */ + 0, /* CX18_HW_CS5345 */ + 0, /* CX18_HW_DVB */ + 0, /* CX18_HW_418_AV */ + 0, /* CX18_HW_GPIO_MUX */ + 0, /* CX18_HW_GPIO_RESET_CTRL */ + 0, /* CX18_HW_Z8F0811_IR_TX_HAUP */ + 0, /* CX18_HW_Z8F0811_IR_RX_HAUP */ +}; + +/* This array should match the CX18_HW_ defines */ +static const char * const hw_devicenames[] = { + "tuner", + "tveeprom", + "cs5345", + "cx23418_DTV", + "cx23418_AV", + "gpio_mux", + "gpio_reset_ctrl", + "ir_tx_z8f0811_haup", + "ir_rx_z8f0811_haup", +}; + +static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw, + const char *type, u8 addr) +{ + struct i2c_board_info info; + struct IR_i2c_init_data *init_data = &cx->ir_i2c_init_data; + unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, type, I2C_NAME_SIZE); + + /* Our default information for ir-kbd-i2c.c to use */ + switch (hw) { + case CX18_HW_Z8F0811_IR_RX_HAUP: + init_data->ir_codes = RC_MAP_HAUPPAUGE; + init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; + init_data->type = RC_TYPE_RC5; + init_data->name = cx->card_name; + info.platform_data = init_data; + break; + } + + return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? + -1 : 0; +} + +int cx18_i2c_register(struct cx18 *cx, unsigned idx) +{ + struct v4l2_subdev *sd; + int bus = hw_bus[idx]; + struct i2c_adapter *adap = &cx->i2c_adap[bus]; + const char *type = hw_devicenames[idx]; + u32 hw = 1 << idx; + + if (idx >= ARRAY_SIZE(hw_addrs)) + return -1; + + if (hw == CX18_HW_TUNER) { + /* special tuner group handling */ + sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, + adap, type, 0, cx->card_i2c->radio); + if (sd != NULL) + sd->grp_id = hw; + sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, + adap, type, 0, cx->card_i2c->demod); + if (sd != NULL) + sd->grp_id = hw; + sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, + adap, type, 0, cx->card_i2c->tv); + if (sd != NULL) + sd->grp_id = hw; + return sd != NULL ? 0 : -1; + } + + if (hw & CX18_HW_IR_ANY) + return cx18_i2c_new_ir(cx, adap, hw, type, hw_addrs[idx]); + + /* Is it not an I2C device or one we do not wish to register? */ + if (!hw_addrs[idx]) + return -1; + + /* It's an I2C device other than an analog tuner or IR chip */ + sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx], + NULL); + if (sd != NULL) + sd->grp_id = hw; + return sd != NULL ? 0 : -1; +} + +/* Find the first member of the subdev group id in hw */ +struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw) +{ + struct v4l2_subdev *result = NULL; + struct v4l2_subdev *sd; + + spin_lock(&cx->v4l2_dev.lock); + v4l2_device_for_each_subdev(sd, &cx->v4l2_dev) { + if (sd->grp_id == hw) { + result = sd; + break; + } + } + spin_unlock(&cx->v4l2_dev.lock); + return result; +} + +static void cx18_setscl(void *data, int state) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; + u32 r = cx18_read_reg(cx, addr); + + if (state) + cx18_write_reg(cx, r | SETSCL_BIT, addr); + else + cx18_write_reg(cx, r & ~SETSCL_BIT, addr); +} + +static void cx18_setsda(void *data, int state) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; + u32 r = cx18_read_reg(cx, addr); + + if (state) + cx18_write_reg(cx, r | SETSDL_BIT, addr); + else + cx18_write_reg(cx, r & ~SETSDL_BIT, addr); +} + +static int cx18_getscl(void *data) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; + + return cx18_read_reg(cx, addr) & GETSCL_BIT; +} + +static int cx18_getsda(void *data) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; + + return cx18_read_reg(cx, addr) & GETSDL_BIT; +} + +/* template for i2c-bit-algo */ +static struct i2c_adapter cx18_i2c_adap_template = { + .name = "cx18 i2c driver", + .algo = NULL, /* set by i2c-algo-bit */ + .algo_data = NULL, /* filled from template */ + .owner = THIS_MODULE, +}; + +#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */ +#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */ + +static struct i2c_algo_bit_data cx18_i2c_algo_template = { + .setsda = cx18_setsda, + .setscl = cx18_setscl, + .getsda = cx18_getsda, + .getscl = cx18_getscl, + .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/ + .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ +}; + +/* init + register i2c algo-bit adapter */ +int init_cx18_i2c(struct cx18 *cx) +{ + int i, err; + CX18_DEBUG_I2C("i2c init\n"); + + for (i = 0; i < 2; i++) { + /* Setup algorithm for adapter */ + memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template, + sizeof(struct i2c_algo_bit_data)); + cx->i2c_algo_cb_data[i].cx = cx; + cx->i2c_algo_cb_data[i].bus_index = i; + cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i]; + + /* Setup adapter */ + memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, + sizeof(struct i2c_adapter)); + cx->i2c_adap[i].algo_data = &cx->i2c_algo[i]; + sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name), + " #%d-%d", cx->instance, i); + i2c_set_adapdata(&cx->i2c_adap[i], &cx->v4l2_dev); + cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev; + } + + if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) { + /* Reset/Unreset I2C hardware block */ + /* Clock select 220MHz */ + cx18_write_reg_expect(cx, 0x10000000, 0xc71004, + 0x00000000, 0x10001000); + /* Clock Enable */ + cx18_write_reg_expect(cx, 0x10001000, 0xc71024, + 0x00001000, 0x10001000); + } + /* courtesy of Steven Toth */ + cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); + mdelay(10); + cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0); + mdelay(10); + cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); + mdelay(10); + + /* Set to edge-triggered intrs. */ + cx18_write_reg(cx, 0x00c00000, 0xc730c8); + /* Clear any stale intrs */ + cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS, + ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT); + + /* Hw I2C1 Clock Freq ~100kHz */ + cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR); + cx18_setscl(&cx->i2c_algo_cb_data[0], 1); + cx18_setsda(&cx->i2c_algo_cb_data[0], 1); + + /* Hw I2C2 Clock Freq ~100kHz */ + cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR); + cx18_setscl(&cx->i2c_algo_cb_data[1], 1); + cx18_setsda(&cx->i2c_algo_cb_data[1], 1); + + cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, + core, reset, (u32) CX18_GPIO_RESET_I2C); + + err = i2c_bit_add_bus(&cx->i2c_adap[0]); + if (err) + goto err; + err = i2c_bit_add_bus(&cx->i2c_adap[1]); + if (err) + goto err_del_bus_0; + return 0; + + err_del_bus_0: + i2c_del_adapter(&cx->i2c_adap[0]); + err: + return err; +} + +void exit_cx18_i2c(struct cx18 *cx) +{ + int i; + CX18_DEBUG_I2C("i2c exit\n"); + cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4, + CX18_REG_I2C_1_WR); + cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4, + CX18_REG_I2C_2_WR); + + for (i = 0; i < 2; i++) { + i2c_del_adapter(&cx->i2c_adap[i]); + } +} + +/* + Hauppauge HVR1600 should have: + 32 cx24227 + 98 unknown + a0 eeprom + c2 tuner + e? zilog ir + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-i2c.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-i2c.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * cx18 I2C functions + * + * Derived from ivtv-i2c.h + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +int cx18_i2c_register(struct cx18 *cx, unsigned idx); +struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw); + +/* init + register i2c algo-bit adapter */ +int init_cx18_i2c(struct cx18 *cx); +void exit_cx18_i2c(struct cx18 *cx); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-io.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-io.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-io.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-io.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,97 @@ +/* + * cx18 driver PCI memory mapped IO access routines + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-irq.h" + +void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count) +{ + u8 __iomem *dst = addr; + u16 val2 = val | (val << 8); + u32 val4 = val2 | (val2 << 16); + + /* Align writes on the CX23418's addresses */ + if ((count > 0) && ((unsigned long)dst & 1)) { + cx18_writeb(cx, (u8) val, dst); + count--; + dst++; + } + if ((count > 1) && ((unsigned long)dst & 2)) { + cx18_writew(cx, val2, dst); + count -= 2; + dst += 2; + } + while (count > 3) { + cx18_writel(cx, val4, dst); + count -= 4; + dst += 4; + } + if (count > 1) { + cx18_writew(cx, val2, dst); + count -= 2; + dst += 2; + } + if (count > 0) + cx18_writeb(cx, (u8) val, dst); +} + +void cx18_sw1_irq_enable(struct cx18 *cx, u32 val) +{ + cx18_write_reg_expect(cx, val, SW1_INT_STATUS, ~val, val); + cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | val; + cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI); +} + +void cx18_sw1_irq_disable(struct cx18 *cx, u32 val) +{ + cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) & ~val; + cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI); +} + +void cx18_sw2_irq_enable(struct cx18 *cx, u32 val) +{ + cx18_write_reg_expect(cx, val, SW2_INT_STATUS, ~val, val); + cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | val; + cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI); +} + +void cx18_sw2_irq_disable(struct cx18 *cx, u32 val) +{ + cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) & ~val; + cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI); +} + +void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val) +{ + u32 r; + r = cx18_read_reg(cx, SW2_INT_ENABLE_CPU); + cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_CPU); +} + +void cx18_setup_page(struct cx18 *cx, u32 addr) +{ + u32 val; + val = cx18_read_reg(cx, 0xD000F8); + val = (val & ~0x1f00) | ((addr >> 17) & 0x1f00); + cx18_write_reg(cx, val, 0xD000F8); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-ioctl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-ioctl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-ioctl.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-ioctl.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1217 @@ +/* + * cx18 ioctl system call + * + * Derived from ivtv-ioctl.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-version.h" +#include "cx18-mailbox.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-fileops.h" +#include "cx18-vbi.h" +#include "cx18-audio.h" +#include "cx18-video.h" +#include "cx18-streams.h" +#include "cx18-ioctl.h" +#include "cx18-gpio.h" +#include "cx18-controls.h" +#include "cx18-cards.h" +#include "cx18-av-core.h" +#include +#include + +u16 cx18_service2vbi(int type) +{ + switch (type) { + case V4L2_SLICED_TELETEXT_B: + return CX18_SLICED_TYPE_TELETEXT_B; + case V4L2_SLICED_CAPTION_525: + return CX18_SLICED_TYPE_CAPTION_525; + case V4L2_SLICED_WSS_625: + return CX18_SLICED_TYPE_WSS_625; + case V4L2_SLICED_VPS: + return CX18_SLICED_TYPE_VPS; + default: + return 0; + } +} + +/* Check if VBI services are allowed on the (field, line) for the video std */ +static int valid_service_line(int field, int line, int is_pal) +{ + return (is_pal && line >= 6 && + ((field == 0 && line <= 23) || (field == 1 && line <= 22))) || + (!is_pal && line >= 10 && line < 22); +} + +/* + * For a (field, line, std) and inbound potential set of services for that line, + * return the first valid service of those passed in the incoming set for that + * line in priority order: + * CC, VPS, or WSS over TELETEXT for well known lines + * TELETEXT, before VPS, before CC, before WSS, for other lines + */ +static u16 select_service_from_set(int field, int line, u16 set, int is_pal) +{ + u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); + int i; + + set = set & valid_set; + if (set == 0 || !valid_service_line(field, line, is_pal)) + return 0; + if (!is_pal) { + if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) + return V4L2_SLICED_CAPTION_525; + } else { + if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) + return V4L2_SLICED_VPS; + if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) + return V4L2_SLICED_WSS_625; + if (line == 23) + return 0; + } + for (i = 0; i < 32; i++) { + if ((1 << i) & set) + return 1 << i; + } + return 0; +} + +/* + * Expand the service_set of *fmt into valid service_lines for the std, + * and clear the passed in fmt->service_set + */ +void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + u16 set = fmt->service_set; + int f, l; + + fmt->service_set = 0; + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) + fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); + } +} + +/* + * Sanitize the service_lines in *fmt per the video std, and return 1 + * if any service_line is left as valid after santization + */ +static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + int f, l; + u16 set = 0; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); + set |= fmt->service_lines[f][l]; + } + } + return set != 0; +} + +/* Compute the service_set from the assumed valid service_lines of *fmt */ +u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) +{ + int f, l; + u16 set = 0; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) + set |= fmt->service_lines[f][l]; + } + return set; +} + +static int cx18_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + pixfmt->width = cx->cxhdl.width; + pixfmt->height = cx->cxhdl.height; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + pixfmt->priv = 0; + if (id->type == CX18_ENC_STREAM_TYPE_YUV) { + pixfmt->pixelformat = s->pixelformat; + /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) + UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ + if (s->pixelformat == V4L2_PIX_FMT_HM12) + pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; + else + pixfmt->sizeimage = pixfmt->height * 720 * 2; + pixfmt->bytesperline = 720; + } else { + pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; + pixfmt->sizeimage = 128 * 1024; + pixfmt->bytesperline = 0; + } + return 0; +} + +static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18 *cx = fh2id(fh)->cx; + struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; + + vbifmt->sampling_rate = 27000000; + vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */ + vbifmt->samples_per_line = vbi_active_samples - 4; + vbifmt->sample_format = V4L2_PIX_FMT_GREY; + vbifmt->start[0] = cx->vbi.start[0]; + vbifmt->start[1] = cx->vbi.start[1]; + vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count; + vbifmt->flags = 0; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + return 0; +} + +static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18 *cx = fh2id(fh)->cx; + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + + /* sane, V4L2 spec compliant, defaults */ + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); + vbifmt->service_set = 0; + + /* + * Fetch the configured service_lines and total service_set from the + * digitizer/slicer. Note, cx18_av_vbi() wipes the passed in + * fmt->fmt.sliced under valid calling conditions + */ + if (v4l2_subdev_call(cx->sd_av, vbi, g_sliced_fmt, &fmt->fmt.sliced)) + return -EINVAL; + + /* Ensure V4L2 spec compliant output */ + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + vbifmt->service_set = cx18_get_service_set(vbifmt); + return 0; +} + +static int cx18_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + int min_h = 2; + + w = min(w, 720); + w = max(w, 2); + if (id->type == CX18_ENC_STREAM_TYPE_YUV) { + /* YUV height must be a multiple of 32 */ + h &= ~0x1f; + min_h = 32; + } + h = min(h, cx->is_50hz ? 576 : 480); + h = max(h, min_h); + + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + return 0; +} + +static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + return cx18_g_fmt_vbi_cap(file, fh, fmt); +} + +static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18 *cx = fh2id(fh)->cx; + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + + /* If given a service set, expand it validly & clear passed in set */ + if (vbifmt->service_set) + cx18_expand_service_set(vbifmt, cx->is_50hz); + /* Sanitize the service_lines, and compute the new set if any valid */ + if (check_service_set(vbifmt, cx->is_50hz)) + vbifmt->service_set = cx18_get_service_set(vbifmt); + return 0; +} + +static int cx18_s_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + struct v4l2_mbus_framefmt mbus_fmt; + struct cx18_stream *s = &cx->streams[id->type]; + int ret; + int w, h; + + ret = cx18_try_fmt_vid_cap(file, fh, fmt); + if (ret) + return ret; + w = fmt->fmt.pix.width; + h = fmt->fmt.pix.height; + + if (cx->cxhdl.width == w && cx->cxhdl.height == h && + s->pixelformat == fmt->fmt.pix.pixelformat) + return 0; + + if (atomic_read(&cx->ana_capturing) > 0) + return -EBUSY; + + s->pixelformat = fmt->fmt.pix.pixelformat; + + mbus_fmt.width = cx->cxhdl.width = w; + mbus_fmt.height = cx->cxhdl.height = h; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); + return cx18_g_fmt_vid_cap(file, fh, fmt); +} + +static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + int ret; + + /* + * Changing the Encoder's Raw VBI parameters won't have any effect + * if any analog capture is ongoing + */ + if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) + return -EBUSY; + + /* + * Set the digitizer registers for raw active VBI. + * Note cx18_av_vbi_wipes out a lot of the passed in fmt under valid + * calling conditions + */ + ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi); + if (ret) + return ret; + + /* Store our new v4l2 (non-)sliced VBI state */ + cx->vbi.sliced_in->service_set = 0; + cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; + + return cx18_g_fmt_vbi_cap(file, fh, fmt); +} + +static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + int ret; + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + + cx18_try_fmt_sliced_vbi_cap(file, fh, fmt); + + /* + * Changing the Encoder's Raw VBI parameters won't have any effect + * if any analog capture is ongoing + */ + if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) + return -EBUSY; + + /* + * Set the service_lines requested in the digitizer/slicer registers. + * Note, cx18_av_vbi() wipes some "impossible" service lines in the + * passed in fmt->fmt.sliced under valid calling conditions + */ + ret = v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &fmt->fmt.sliced); + if (ret) + return ret; + /* Store our current v4l2 sliced VBI settings */ + cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); + return 0; +} + +static int cx18_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) +{ + struct cx18 *cx = fh2id(fh)->cx; + int err = 0; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + switch (chip->match.type) { + case V4L2_CHIP_MATCH_HOST: + switch (chip->match.addr) { + case 0: + chip->ident = V4L2_IDENT_CX23418; + chip->revision = cx18_read_reg(cx, 0xC72028); + break; + case 1: + /* + * The A/V decoder is always present, but in the rare + * case that the card doesn't have analog, we don't + * use it. We find it w/o using the cx->sd_av pointer + */ + cx18_call_hw(cx, CX18_HW_418_AV, + core, g_chip_ident, chip); + break; + default: + /* + * Could return ident = V4L2_IDENT_UNKNOWN if we had + * other host chips at higher addresses, but we don't + */ + err = -EINVAL; /* per V4L2 spec */ + break; + } + break; + case V4L2_CHIP_MATCH_I2C_DRIVER: + /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */ + cx18_call_all(cx, core, g_chip_ident, chip); + break; + case V4L2_CHIP_MATCH_I2C_ADDR: + /* + * We could return V4L2_IDENT_UNKNOWN, but we don't do the work + * to look if a chip is at the address with no driver. That's a + * dangerous thing to do with EEPROMs anyway. + */ + cx18_call_all(cx, core, g_chip_ident, chip); + break; + default: + err = -EINVAL; + break; + } + return err; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct v4l2_dbg_register *regs = arg; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) + return -EINVAL; + + regs->size = 4; + if (cmd == VIDIOC_DBG_S_REGISTER) + cx18_write_enc(cx, regs->val, regs->reg); + else + regs->val = cx18_read_enc(cx, regs->reg); + return 0; +} + +static int cx18_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + struct cx18 *cx = fh2id(fh)->cx; + + if (v4l2_chip_match_host(®->match)) + return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); + /* FIXME - errors shouldn't be ignored */ + cx18_call_all(cx, core, g_register, reg); + return 0; +} + +static int cx18_s_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + struct cx18 *cx = fh2id(fh)->cx; + + if (v4l2_chip_match_host(®->match)) + return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); + /* FIXME - errors shouldn't be ignored */ + cx18_call_all(cx, core, s_register, reg); + return 0; +} +#endif + +static int cx18_querycap(struct file *file, void *fh, + struct v4l2_capability *vcap) +{ + struct cx18 *cx = fh2id(fh)->cx; + + strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); + snprintf(vcap->bus_info, sizeof(vcap->bus_info), + "PCI:%s", pci_name(cx->pci_dev)); + vcap->version = CX18_DRIVER_VERSION; /* version */ + vcap->capabilities = cx->v4l2_cap; /* capabilities */ + return 0; +} + +static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct cx18 *cx = fh2id(fh)->cx; + + return cx18_get_audio_input(cx, vin->index, vin); +} + +static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct cx18 *cx = fh2id(fh)->cx; + + vin->index = cx->audio_input; + return cx18_get_audio_input(cx, vin->index, vin); +} + +static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) +{ + struct cx18 *cx = fh2id(fh)->cx; + + if (vout->index >= cx->nof_audio_inputs) + return -EINVAL; + cx->audio_input = vout->index; + cx18_audio_set_io(cx); + return 0; +} + +static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + struct cx18 *cx = fh2id(fh)->cx; + + /* set it to defaults from our table */ + return cx18_get_input(cx, vin->index, vin); +} + +static int cx18_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cropcap) +{ + struct cx18 *cx = fh2id(fh)->cx; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + cropcap->bounds.height = cx->is_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; + cropcap->defrect = cropcap->bounds; + return 0; +} + +static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n"); + return -EINVAL; +} + +static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct cx18 *cx = fh2id(fh)->cx; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n"); + return -EINVAL; +} + +static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *fmt) +{ + static const struct v4l2_fmtdesc formats[] = { + { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, + "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } + }, + { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } + }, + { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, + "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 } + }, + }; + + if (fmt->index > ARRAY_SIZE(formats) - 1) + return -EINVAL; + *fmt = formats[fmt->index]; + return 0; +} + +static int cx18_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct cx18 *cx = fh2id(fh)->cx; + + *i = cx->active_input; + return 0; +} + +int cx18_s_input(struct file *file, void *fh, unsigned int inp) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + + if (inp >= cx->nof_inputs) + return -EINVAL; + + if (inp == cx->active_input) { + CX18_DEBUG_INFO("Input unchanged\n"); + return 0; + } + + CX18_DEBUG_INFO("Changing input from %d to %d\n", + cx->active_input, inp); + + cx->active_input = inp; + /* Set the audio input to whatever is appropriate for the input type. */ + cx->audio_input = cx->card->video_inputs[inp].audio_index; + + /* prevent others from messing with the streams until + we're finished changing inputs. */ + cx18_mute(cx); + cx18_video_set_io(cx); + cx18_audio_set_io(cx); + cx18_unmute(cx); + return 0; +} + +static int cx18_g_frequency(struct file *file, void *fh, + struct v4l2_frequency *vf) +{ + struct cx18 *cx = fh2id(fh)->cx; + + if (vf->tuner != 0) + return -EINVAL; + + cx18_call_all(cx, tuner, g_frequency, vf); + return 0; +} + +int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + + if (vf->tuner != 0) + return -EINVAL; + + cx18_mute(cx); + CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); + cx18_call_all(cx, tuner, s_frequency, vf); + cx18_unmute(cx); + return 0; +} + +static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct cx18 *cx = fh2id(fh)->cx; + + *std = cx->std; + return 0; +} + +int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + + if ((*std & V4L2_STD_ALL) == 0) + return -EINVAL; + + if (*std == cx->std) + return 0; + + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || + atomic_read(&cx->ana_capturing) > 0) { + /* Switching standard would turn off the radio or mess + with already running streams, prevent that by + returning EBUSY. */ + return -EBUSY; + } + + cx->std = *std; + cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + cx->is_50hz = !cx->is_60hz; + cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz); + cx->cxhdl.width = 720; + cx->cxhdl.height = cx->is_50hz ? 576 : 480; + cx->vbi.count = cx->is_50hz ? 18 : 12; + cx->vbi.start[0] = cx->is_50hz ? 6 : 10; + cx->vbi.start[1] = cx->is_50hz ? 318 : 273; + CX18_DEBUG_INFO("Switching standard to %llx.\n", + (unsigned long long) cx->std); + + /* Tuner */ + cx18_call_all(cx, core, s_std, cx->std); + return 0; +} + +static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + + if (vt->index != 0) + return -EINVAL; + + cx18_call_all(cx, tuner, s_tuner, vt); + return 0; +} + +static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct cx18 *cx = fh2id(fh)->cx; + + if (vt->index != 0) + return -EINVAL; + + cx18_call_all(cx, tuner, g_tuner, vt); + + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_RADIO; + } else { + strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_ANALOG_TV; + } + + return 0; +} + +static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_sliced_vbi_cap *cap) +{ + struct cx18 *cx = fh2id(fh)->cx; + int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; + int f, l; + + if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + + cap->service_set = 0; + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + if (valid_service_line(f, l, cx->is_50hz)) { + /* + * We can find all v4l2 supported vbi services + * for the standard, on a valid line for the std + */ + cap->service_lines[f][l] = set; + cap->service_set |= set; + } else + cap->service_lines[f][l] = 0; + } + } + for (f = 0; f < 3; f++) + cap->reserved[f] = 0; + return 0; +} + +static int _cx18_process_idx_data(struct cx18_buffer *buf, + struct v4l2_enc_idx *idx) +{ + int consumed, remaining; + struct v4l2_enc_idx_entry *e_idx; + struct cx18_enc_idx_entry *e_buf; + + /* Frame type lookup: 1=I, 2=P, 4=B */ + const int mapping[8] = { + -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, + -1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1 + }; + + /* + * Assumption here is that a buf holds an integral number of + * struct cx18_enc_idx_entry objects and is properly aligned. + * This is enforced by the module options on IDX buffer sizes. + */ + remaining = buf->bytesused - buf->readpos; + consumed = 0; + e_idx = &idx->entry[idx->entries]; + e_buf = (struct cx18_enc_idx_entry *) &buf->buf[buf->readpos]; + + while (remaining >= sizeof(struct cx18_enc_idx_entry) && + idx->entries < V4L2_ENC_IDX_ENTRIES) { + + e_idx->offset = (((u64) le32_to_cpu(e_buf->offset_high)) << 32) + | le32_to_cpu(e_buf->offset_low); + + e_idx->pts = (((u64) (le32_to_cpu(e_buf->pts_high) & 1)) << 32) + | le32_to_cpu(e_buf->pts_low); + + e_idx->length = le32_to_cpu(e_buf->length); + + e_idx->flags = mapping[le32_to_cpu(e_buf->flags) & 0x7]; + + e_idx->reserved[0] = 0; + e_idx->reserved[1] = 0; + + idx->entries++; + e_idx = &idx->entry[idx->entries]; + e_buf++; + + remaining -= sizeof(struct cx18_enc_idx_entry); + consumed += sizeof(struct cx18_enc_idx_entry); + } + + /* Swallow any partial entries at the end, if there are any */ + if (remaining > 0 && remaining < sizeof(struct cx18_enc_idx_entry)) + consumed += remaining; + + buf->readpos += consumed; + return consumed; +} + +static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl, + struct v4l2_enc_idx *idx) +{ + if (s->type != CX18_ENC_STREAM_TYPE_IDX) + return -EINVAL; + + if (mdl->curr_buf == NULL) + mdl->curr_buf = list_first_entry(&mdl->buf_list, + struct cx18_buffer, list); + + if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { + /* + * For some reason we've exhausted the buffers, but the MDL + * object still said some data was unread. + * Fix that and bail out. + */ + mdl->readpos = mdl->bytesused; + return 0; + } + + list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { + + /* Skip any empty buffers in the MDL */ + if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) + continue; + + mdl->readpos += _cx18_process_idx_data(mdl->curr_buf, idx); + + /* exit when MDL drained or request satisfied */ + if (idx->entries >= V4L2_ENC_IDX_ENTRIES || + mdl->curr_buf->readpos < mdl->curr_buf->bytesused || + mdl->readpos >= mdl->bytesused) + break; + } + return 0; +} + +static int cx18_g_enc_index(struct file *file, void *fh, + struct v4l2_enc_idx *idx) +{ + struct cx18 *cx = fh2id(fh)->cx; + struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; + s32 tmp; + struct cx18_mdl *mdl; + + if (!cx18_stream_enabled(s)) /* Module options inhibited IDX stream */ + return -EINVAL; + + /* Compute the best case number of entries we can buffer */ + tmp = s->buffers - + s->bufs_per_mdl * CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN; + if (tmp <= 0) + tmp = 1; + tmp = tmp * s->buf_size / sizeof(struct cx18_enc_idx_entry); + + /* Fill out the header of the return structure */ + idx->entries = 0; + idx->entries_cap = tmp; + memset(idx->reserved, 0, sizeof(idx->reserved)); + + /* Pull IDX MDLs and buffers from q_full and populate the entries */ + do { + mdl = cx18_dequeue(s, &s->q_full); + if (mdl == NULL) /* No more IDX data right now */ + break; + + /* Extract the Index entry data from the MDL and buffers */ + cx18_process_idx_data(s, mdl, idx); + if (mdl->readpos < mdl->bytesused) { + /* We finished with data remaining, push the MDL back */ + cx18_push(s, mdl, &s->q_full); + break; + } + + /* We drained this MDL, schedule it to go to the firmware */ + cx18_enqueue(s, mdl, &s->q_free); + + } while (idx->entries < V4L2_ENC_IDX_ENTRIES); + + /* Tell the work handler to send free IDX MDLs to the firmware */ + cx18_stream_load_fw_queue(s); + return 0; +} + +static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id) +{ + struct videobuf_queue *q = NULL; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + switch (s->vb_type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + q = &s->vbuf_q; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + break; + default: + break; + } + return q; +} + +static int cx18_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct cx18_open_id *id = file->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + /* Start the hardware only if we're the video device */ + if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) + return -EINVAL; + + if (id->type != CX18_ENC_STREAM_TYPE_YUV) + return -EINVAL; + + /* Establish a buffer timeout */ + mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); + + return videobuf_streamon(cx18_vb_queue(id)); +} + +static int cx18_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct cx18_open_id *id = file->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + /* Start the hardware only if we're the video device */ + if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) + return -EINVAL; + + if (id->type != CX18_ENC_STREAM_TYPE_YUV) + return -EINVAL; + + return videobuf_streamoff(cx18_vb_queue(id)); +} + +static int cx18_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct cx18_open_id *id = file->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) + return -EINVAL; + + return videobuf_reqbufs(cx18_vb_queue(id), rb); +} + +static int cx18_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct cx18_open_id *id = file->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) + return -EINVAL; + + return videobuf_querybuf(cx18_vb_queue(id), b); +} + +static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct cx18_open_id *id = file->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) + return -EINVAL; + + return videobuf_qbuf(cx18_vb_queue(id), b); +} + +static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct cx18_open_id *id = file->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) + return -EINVAL; + + return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK); +} + +static int cx18_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + u32 h; + + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + return cx18_start_capture(id); + + case V4L2_ENC_CMD_STOP: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + cx18_stop_capture(id, + enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); + break; + + case V4L2_ENC_CMD_PAUSE: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + if (!atomic_read(&cx->ana_capturing)) + return -EPERM; + if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + h = cx18_find_handle(cx); + if (h == CX18_INVALID_TASK_HANDLE) { + CX18_ERR("Can't find valid task handle for " + "V4L2_ENC_CMD_PAUSE\n"); + return -EBADFD; + } + cx18_mute(cx); + cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h); + break; + + case V4L2_ENC_CMD_RESUME: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; + if (!atomic_read(&cx->ana_capturing)) + return -EPERM; + if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + h = cx18_find_handle(cx); + if (h == CX18_INVALID_TASK_HANDLE) { + CX18_ERR("Can't find valid task handle for " + "V4L2_ENC_CMD_RESUME\n"); + return -EBADFD; + } + cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h); + cx18_unmute(cx); + break; + + default: + CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); + return -EINVAL; + } + return 0; +} + +static int cx18_try_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct cx18 *cx = fh2id(fh)->cx; + + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + break; + + case V4L2_ENC_CMD_STOP: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + break; + + case V4L2_ENC_CMD_PAUSE: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + break; + + case V4L2_ENC_CMD_RESUME: + CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; + break; + + default: + CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); + return -EINVAL; + } + return 0; +} + +static int cx18_log_status(struct file *file, void *fh) +{ + struct cx18 *cx = fh2id(fh)->cx; + struct v4l2_input vidin; + struct v4l2_audio audin; + int i; + + CX18_INFO("================= START STATUS CARD #%d " + "=================\n", cx->instance); + CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name); + if (cx->hw_flags & CX18_HW_TVEEPROM) { + struct tveeprom tv; + + cx18_read_eeprom(cx, &tv); + } + cx18_call_all(cx, core, log_status); + cx18_get_input(cx, cx->active_input, &vidin); + cx18_get_audio_input(cx, cx->audio_input, &audin); + CX18_INFO("Video Input: %s\n", vidin.name); + CX18_INFO("Audio Input: %s\n", audin.name); + mutex_lock(&cx->gpio_lock); + CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n", + cx->gpio_dir, cx->gpio_val); + mutex_unlock(&cx->gpio_lock); + CX18_INFO("Tuner: %s\n", + test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV"); + v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name); + CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); + for (i = 0; i < CX18_MAX_STREAMS; i++) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->video_dev == NULL || s->buffers == 0) + continue; + CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", + s->name, s->s_flags, + atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100 + / s->buffers, + (s->buffers * s->buf_size) / 1024, s->buffers); + } + CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", + (long long)cx->mpg_data_received, + (long long)cx->vbi_data_inserted); + CX18_INFO("================== END STATUS CARD #%d " + "==================\n", cx->instance); + return 0; +} + +static long cx18_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) +{ + struct cx18 *cx = fh2id(fh)->cx; + + switch (cmd) { + case VIDIOC_INT_RESET: { + u32 val = *(u32 *)arg; + + if ((val == 0) || (val & 0x01)) + cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset, + (u32) CX18_GPIO_RESET_Z8F0811); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct video_device *vfd = video_devdata(filp); + struct cx18_open_id *id = file2id(filp); + struct cx18 *cx = id->cx; + long res; + + mutex_lock(&cx->serialize_lock); + + if (cx18_debug & CX18_DBGFLG_IOCTL) + vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; + res = video_ioctl2(filp, cmd, arg); + vfd->debug = 0; + mutex_unlock(&cx->serialize_lock); + return res; +} + +static const struct v4l2_ioctl_ops cx18_ioctl_ops = { + .vidioc_querycap = cx18_querycap, + .vidioc_s_audio = cx18_s_audio, + .vidioc_g_audio = cx18_g_audio, + .vidioc_enumaudio = cx18_enumaudio, + .vidioc_enum_input = cx18_enum_input, + .vidioc_cropcap = cx18_cropcap, + .vidioc_s_crop = cx18_s_crop, + .vidioc_g_crop = cx18_g_crop, + .vidioc_g_input = cx18_g_input, + .vidioc_s_input = cx18_s_input, + .vidioc_g_frequency = cx18_g_frequency, + .vidioc_s_frequency = cx18_s_frequency, + .vidioc_s_tuner = cx18_s_tuner, + .vidioc_g_tuner = cx18_g_tuner, + .vidioc_g_enc_index = cx18_g_enc_index, + .vidioc_g_std = cx18_g_std, + .vidioc_s_std = cx18_s_std, + .vidioc_log_status = cx18_log_status, + .vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap, + .vidioc_encoder_cmd = cx18_encoder_cmd, + .vidioc_try_encoder_cmd = cx18_try_encoder_cmd, + .vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap, + .vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap, + .vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap, + .vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap, + .vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap, + .vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap, + .vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap, + .vidioc_g_chip_ident = cx18_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = cx18_g_register, + .vidioc_s_register = cx18_s_register, +#endif + .vidioc_default = cx18_default, + .vidioc_streamon = cx18_streamon, + .vidioc_streamoff = cx18_streamoff, + .vidioc_reqbufs = cx18_reqbufs, + .vidioc_querybuf = cx18_querybuf, + .vidioc_qbuf = cx18_qbuf, + .vidioc_dqbuf = cx18_dqbuf, +}; + +void cx18_set_funcs(struct video_device *vdev) +{ + vdev->ioctl_ops = &cx18_ioctl_ops; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-ioctl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-ioctl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-ioctl.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-ioctl.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * cx18 ioctl system call + * + * Derived from ivtv-ioctl.h + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +u16 cx18_service2vbi(int type); +void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); +u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); +void cx18_set_funcs(struct video_device *vdev); +int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); +int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int cx18_s_input(struct file *file, void *fh, unsigned int inp); +long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-io.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-io.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-io.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-io.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,191 @@ +/* + * cx18 driver PCI memory mapped IO access routines + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#ifndef CX18_IO_H +#define CX18_IO_H + +#include "cx18-driver.h" + +/* + * Readback and retry of MMIO access for reliability: + * The concept was suggested by Steve Toth . + * The implmentation is the fault of Andy Walls . + * + * *write* functions are implied to retry the mmio unless suffixed with _noretry + * *read* functions never retry the mmio (it never helps to do so) + */ + +/* Non byteswapping memory mapped IO */ +static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr) +{ + return __raw_readl(addr); +} + +static inline +void cx18_raw_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + __raw_writel(val, addr); +} + +static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { + cx18_raw_writel_noretry(cx, val, addr); + if (val == cx18_raw_readl(cx, addr)) + break; + } +} + +/* Normal memory mapped IO */ +static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr) +{ + return readl(addr); +} + +static inline +void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) +{ + writel(val, addr); +} + +static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { + cx18_writel_noretry(cx, val, addr); + if (val == cx18_readl(cx, addr)) + break; + } +} + +static inline +void cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr, + u32 eval, u32 mask) +{ + int i; + u32 r; + eval &= mask; + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { + cx18_writel_noretry(cx, val, addr); + r = cx18_readl(cx, addr); + if (r == 0xffffffff && eval != 0xffffffff) + continue; + if (eval == (r & mask)) + break; + } +} + +static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr) +{ + return readw(addr); +} + +static inline +void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr) +{ + writew(val, addr); +} + +static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { + cx18_writew_noretry(cx, val, addr); + if (val == cx18_readw(cx, addr)) + break; + } +} + +static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr) +{ + return readb(addr); +} + +static inline +void cx18_writeb_noretry(struct cx18 *cx, u8 val, void __iomem *addr) +{ + writeb(val, addr); +} + +static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr) +{ + int i; + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { + cx18_writeb_noretry(cx, val, addr); + if (val == cx18_readb(cx, addr)) + break; + } +} + +static inline +void cx18_memcpy_fromio(struct cx18 *cx, void *to, + const void __iomem *from, unsigned int len) +{ + memcpy_fromio(to, from, len); +} + +void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count); + + +/* Access "register" region of CX23418 memory mapped I/O */ +static inline void cx18_write_reg_noretry(struct cx18 *cx, u32 val, u32 reg) +{ + cx18_writel_noretry(cx, val, cx->reg_mem + reg); +} + +static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg) +{ + cx18_writel(cx, val, cx->reg_mem + reg); +} + +static inline void cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg, + u32 eval, u32 mask) +{ + cx18_writel_expect(cx, val, cx->reg_mem + reg, eval, mask); +} + +static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg) +{ + return cx18_readl(cx, cx->reg_mem + reg); +} + + +/* Access "encoder memory" region of CX23418 memory mapped I/O */ +static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr) +{ + cx18_writel(cx, val, cx->enc_mem + addr); +} + +static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr) +{ + return cx18_readl(cx, cx->enc_mem + addr); +} + +void cx18_sw1_irq_enable(struct cx18 *cx, u32 val); +void cx18_sw1_irq_disable(struct cx18 *cx, u32 val); +void cx18_sw2_irq_enable(struct cx18 *cx, u32 val); +void cx18_sw2_irq_disable(struct cx18 *cx, u32 val); +void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val); +void cx18_setup_page(struct cx18 *cx, u32 addr); + +#endif /* CX18_IO_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-irq.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-irq.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-irq.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-irq.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * cx18 interrupt handling + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-irq.h" +#include "cx18-mailbox.h" +#include "cx18-scb.h" + +static void xpu_ack(struct cx18 *cx, u32 sw2) +{ + if (sw2 & IRQ_CPU_TO_EPU_ACK) + wake_up(&cx->mb_cpu_waitq); + if (sw2 & IRQ_APU_TO_EPU_ACK) + wake_up(&cx->mb_apu_waitq); +} + +static void epu_cmd(struct cx18 *cx, u32 sw1) +{ + if (sw1 & IRQ_CPU_TO_EPU) + cx18_api_epu_cmd_irq(cx, CPU); + if (sw1 & IRQ_APU_TO_EPU) + cx18_api_epu_cmd_irq(cx, APU); +} + +irqreturn_t cx18_irq_handler(int irq, void *dev_id) +{ + struct cx18 *cx = (struct cx18 *)dev_id; + u32 sw1, sw2, hw2; + + sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & cx->sw1_irq_mask; + sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & cx->sw2_irq_mask; + hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & cx->hw2_irq_mask; + + if (sw1) + cx18_write_reg_expect(cx, sw1, SW1_INT_STATUS, ~sw1, sw1); + if (sw2) + cx18_write_reg_expect(cx, sw2, SW2_INT_STATUS, ~sw2, sw2); + if (hw2) + cx18_write_reg_expect(cx, hw2, HW2_INT_CLR_STATUS, ~hw2, hw2); + + if (sw1 || sw2 || hw2) + CX18_DEBUG_HI_IRQ("received interrupts " + "SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); + + /* + * SW1 responses have to happen first. The sending XPU times out the + * incoming mailboxes on us rather rapidly. + */ + if (sw1) + epu_cmd(cx, sw1); + + /* To do: interrupt-based I2C handling + if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) { + } + */ + + if (sw2) + xpu_ack(cx, sw2); + + return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-irq.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-irq.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-irq.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-irq.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * cx18 interrupt handling + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#define HW2_I2C1_INT (1 << 22) +#define HW2_I2C2_INT (1 << 23) +#define HW2_INT_CLR_STATUS 0xc730c4 +#define HW2_INT_MASK5_PCI 0xc730e4 +#define SW1_INT_SET 0xc73100 +#define SW1_INT_STATUS 0xc73104 +#define SW1_INT_ENABLE_PCI 0xc7311c +#define SW2_INT_SET 0xc73140 +#define SW2_INT_STATUS 0xc73144 +#define SW2_INT_ENABLE_CPU 0xc73158 +#define SW2_INT_ENABLE_PCI 0xc7315c + +irqreturn_t cx18_irq_handler(int irq, void *dev_id); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-mailbox.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-mailbox.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-mailbox.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-mailbox.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,869 @@ +/* + * cx18 mailbox functions + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + +#include "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-scb.h" +#include "cx18-irq.h" +#include "cx18-mailbox.h" +#include "cx18-queue.h" +#include "cx18-streams.h" +#include "cx18-alsa-pcm.h" /* FIXME make configurable */ + +static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" }; + +#define API_FAST (1 << 2) /* Short timeout */ +#define API_SLOW (1 << 3) /* Additional 300ms timeout */ + +struct cx18_api_info { + u32 cmd; + u8 flags; /* Flags, see above */ + u8 rpu; /* Processing unit */ + const char *name; /* The name of the command */ +}; + +#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x } + +static const struct cx18_api_info api_info[] = { + /* MPEG encoder API */ + API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), + API_ENTRY(CPU, CX18_EPU_DEBUG, 0), + API_ENTRY(CPU, CX18_CREATE_TASK, 0), + API_ENTRY(CPU, CX18_DESTROY_TASK, 0), + API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW), + API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW), + API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0), + API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0), + API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0), + API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0), + API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0), + API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0), + API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0), + API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW), + API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0), + API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0), + API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0), + API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0), + API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0), + API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0), + API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0), + API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), + API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), + API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), + API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM, 0), + API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), + API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), + API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), + API_ENTRY(APU, CX18_APU_START, 0), + API_ENTRY(APU, CX18_APU_STOP, 0), + API_ENTRY(APU, CX18_APU_RESETAI, 0), + API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0), + API_ENTRY(0, 0, 0), +}; + +static const struct cx18_api_info *find_api_info(u32 cmd) +{ + int i; + + for (i = 0; api_info[i].cmd; i++) + if (api_info[i].cmd == cmd) + return &api_info[i]; + return NULL; +} + +/* Call with buf of n*11+1 bytes */ +static char *u32arr2hex(u32 data[], int n, char *buf) +{ + char *p; + int i; + + for (i = 0, p = buf; i < n; i++, p += 11) { + /* kernel snprintf() appends '\0' always */ + snprintf(p, 12, " %#010x", data[i]); + } + *p = '\0'; + return buf; +} + +static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) +{ + char argstr[MAX_MB_ARGUMENTS*11+1]; + + if (!(cx18_debug & CX18_DBGFLG_API)) + return; + + CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s" + "\n", name, mb->request, mb->ack, mb->cmd, mb->error, + u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr)); +} + + +/* + * Functions that run in a work_queue work handling context + */ + +static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl) +{ + struct cx18_buffer *buf; + + if (s->dvb == NULL || !s->dvb->enabled || mdl->bytesused == 0) + return; + + /* We ignore mdl and buf readpos accounting here - it doesn't matter */ + + /* The likely case */ + if (list_is_singular(&mdl->buf_list)) { + buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, + list); + if (buf->bytesused) + dvb_dmx_swfilter(&s->dvb->demux, + buf->buf, buf->bytesused); + return; + } + + list_for_each_entry(buf, &mdl->buf_list, list) { + if (buf->bytesused == 0) + break; + dvb_dmx_swfilter(&s->dvb->demux, buf->buf, buf->bytesused); + } +} + +static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, + struct cx18_mdl *mdl) +{ + struct cx18_videobuf_buffer *vb_buf; + struct cx18_buffer *buf; + u8 *p; + u32 offset = 0; + int dispatch = 0; + + if (mdl->bytesused == 0) + return; + + /* Acquire a videobuf buffer, clone to and and release it */ + spin_lock(&s->vb_lock); + if (list_empty(&s->vb_capture)) + goto out; + + vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer, + vb.queue); + + p = videobuf_to_vmalloc(&vb_buf->vb); + if (!p) + goto out; + + offset = vb_buf->bytes_used; + list_for_each_entry(buf, &mdl->buf_list, list) { + if (buf->bytesused == 0) + break; + + if ((offset + buf->bytesused) <= vb_buf->vb.bsize) { + memcpy(p + offset, buf->buf, buf->bytesused); + offset += buf->bytesused; + vb_buf->bytes_used += buf->bytesused; + } + } + + /* If we've filled the buffer as per the callers res then dispatch it */ + if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) { + dispatch = 1; + vb_buf->bytes_used = 0; + } + + if (dispatch) { + vb_buf->vb.ts = ktime_to_timeval(ktime_get()); + list_del(&vb_buf->vb.queue); + vb_buf->vb.state = VIDEOBUF_DONE; + wake_up(&vb_buf->vb.done); + } + + mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); + +out: + spin_unlock(&s->vb_lock); +} + +static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s, + struct cx18_mdl *mdl) +{ + struct cx18_buffer *buf; + + if (mdl->bytesused == 0) + return; + + /* We ignore mdl and buf readpos accounting here - it doesn't matter */ + + /* The likely case */ + if (list_is_singular(&mdl->buf_list)) { + buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, + list); + if (buf->bytesused) + cx->pcm_announce_callback(cx->alsa, buf->buf, + buf->bytesused); + return; + } + + list_for_each_entry(buf, &mdl->buf_list, list) { + if (buf->bytesused == 0) + break; + cx->pcm_announce_callback(cx->alsa, buf->buf, buf->bytesused); + } +} + +static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) +{ + u32 handle, mdl_ack_count, id; + struct cx18_mailbox *mb; + struct cx18_mdl_ack *mdl_ack; + struct cx18_stream *s; + struct cx18_mdl *mdl; + int i; + + mb = &order->mb; + handle = mb->args[0]; + s = cx18_handle_to_stream(cx, handle); + + if (s == NULL) { + CX18_WARN("Got DMA done notification for unknown/inactive" + " handle %d, %s mailbox seq no %d\n", handle, + (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ? + "stale" : "good", mb->request); + return; + } + + mdl_ack_count = mb->args[2]; + mdl_ack = order->mdl_ack; + for (i = 0; i < mdl_ack_count; i++, mdl_ack++) { + id = mdl_ack->id; + /* + * Simple integrity check for processing a stale (and possibly + * inconsistent mailbox): make sure the MDL id is in the + * valid range for the stream. + * + * We go through the trouble of dealing with stale mailboxes + * because most of the time, the mailbox data is still valid and + * unchanged (and in practice the firmware ping-pongs the + * two mdl_ack buffers so mdl_acks are not stale). + * + * There are occasions when we get a half changed mailbox, + * which this check catches for a handle & id mismatch. If the + * handle and id do correspond, the worst case is that we + * completely lost the old MDL, but pick up the new MDL + * early (but the new mdl_ack is guaranteed to be good in this + * case as the firmware wouldn't point us to a new mdl_ack until + * it's filled in). + * + * cx18_queue_get_mdl() will detect the lost MDLs + * and send them back to q_free for fw rotation eventually. + */ + if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && + !(id >= s->mdl_base_idx && + id < (s->mdl_base_idx + s->buffers))) { + CX18_WARN("Fell behind! Ignoring stale mailbox with " + " inconsistent data. Lost MDL for mailbox " + "seq no %d\n", mb->request); + break; + } + mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used); + + CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id); + if (mdl == NULL) { + CX18_WARN("Could not find MDL %d for stream %s\n", + id, s->name); + continue; + } + + CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", + s->name, mdl->bytesused); + + if (s->type == CX18_ENC_STREAM_TYPE_TS) { + cx18_mdl_send_to_dvb(s, mdl); + cx18_enqueue(s, mdl, &s->q_free); + } else if (s->type == CX18_ENC_STREAM_TYPE_PCM) { + /* Pass the data to cx18-alsa */ + if (cx->pcm_announce_callback != NULL) { + cx18_mdl_send_to_alsa(cx, s, mdl); + cx18_enqueue(s, mdl, &s->q_free); + } else { + cx18_enqueue(s, mdl, &s->q_full); + } + } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) { + cx18_mdl_send_to_videobuf(s, mdl); + cx18_enqueue(s, mdl, &s->q_free); + } else { + cx18_enqueue(s, mdl, &s->q_full); + if (s->type == CX18_ENC_STREAM_TYPE_IDX) + cx18_stream_rotate_idx_mdls(cx); + } + } + /* Put as many MDLs as possible back into fw use */ + cx18_stream_load_fw_queue(s); + + wake_up(&cx->dma_waitq); + if (s->id != -1) + wake_up(&s->waitq); +} + +static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order) +{ + char *p; + char *str = order->str; + + CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str); + p = strchr(str, '.'); + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) + CX18_INFO("FW version: %s\n", p - 1); +} + +static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order) +{ + switch (order->rpu) { + case CPU: + { + switch (order->mb.cmd) { + case CX18_EPU_DMA_DONE: + epu_dma_done(cx, order); + break; + case CX18_EPU_DEBUG: + epu_debug(cx, order); + break; + default: + CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", + order->mb.cmd); + break; + } + break; + } + case APU: + CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", + order->mb.cmd); + break; + default: + break; + } +} + +static +void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order) +{ + atomic_set(&order->pending, 0); +} + +void cx18_in_work_handler(struct work_struct *work) +{ + struct cx18_in_work_order *order = + container_of(work, struct cx18_in_work_order, work); + struct cx18 *cx = order->cx; + epu_cmd(cx, order); + free_in_work_order(cx, order); +} + + +/* + * Functions that run in an interrupt handling context + */ + +static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order) +{ + struct cx18_mailbox __iomem *ack_mb; + u32 ack_irq, req; + + switch (order->rpu) { + case APU: + ack_irq = IRQ_EPU_TO_APU_ACK; + ack_mb = &cx->scb->apu2epu_mb; + break; + case CPU: + ack_irq = IRQ_EPU_TO_CPU_ACK; + ack_mb = &cx->scb->cpu2epu_mb; + break; + default: + CX18_WARN("Unhandled RPU (%d) for command %x ack\n", + order->rpu, order->mb.cmd); + return; + } + + req = order->mb.request; + /* Don't ack if the RPU has gotten impatient and timed us out */ + if (req != cx18_readl(cx, &ack_mb->request) || + req == cx18_readl(cx, &ack_mb->ack)) { + CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " + "incoming %s to EPU mailbox (sequence no. %u) " + "while processing\n", + rpu_str[order->rpu], rpu_str[order->rpu], req); + order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC; + return; + } + cx18_writel(cx, req, &ack_mb->ack); + cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq); + return; +} + +static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order) +{ + u32 handle, mdl_ack_offset, mdl_ack_count; + struct cx18_mailbox *mb; + + mb = &order->mb; + handle = mb->args[0]; + mdl_ack_offset = mb->args[1]; + mdl_ack_count = mb->args[2]; + + if (handle == CX18_INVALID_TASK_HANDLE || + mdl_ack_count == 0 || mdl_ack_count > CX18_MAX_MDL_ACKS) { + if ((order->flags & CX18_F_EWO_MB_STALE) == 0) + mb_ack_irq(cx, order); + return -1; + } + + cx18_memcpy_fromio(cx, order->mdl_ack, cx->enc_mem + mdl_ack_offset, + sizeof(struct cx18_mdl_ack) * mdl_ack_count); + + if ((order->flags & CX18_F_EWO_MB_STALE) == 0) + mb_ack_irq(cx, order); + return 1; +} + +static +int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order) +{ + u32 str_offset; + char *str = order->str; + + str[0] = '\0'; + str_offset = order->mb.args[1]; + if (str_offset) { + cx18_setup_page(cx, str_offset); + cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252); + str[252] = '\0'; + cx18_setup_page(cx, SCB_OFFSET); + } + + if ((order->flags & CX18_F_EWO_MB_STALE) == 0) + mb_ack_irq(cx, order); + + return str_offset ? 1 : 0; +} + +static inline +int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order) +{ + int ret = -1; + + switch (order->rpu) { + case CPU: + { + switch (order->mb.cmd) { + case CX18_EPU_DMA_DONE: + ret = epu_dma_done_irq(cx, order); + break; + case CX18_EPU_DEBUG: + ret = epu_debug_irq(cx, order); + break; + default: + CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", + order->mb.cmd); + break; + } + break; + } + case APU: + CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", + order->mb.cmd); + break; + default: + break; + } + return ret; +} + +static inline +struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx) +{ + int i; + struct cx18_in_work_order *order = NULL; + + for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { + /* + * We only need "pending" atomic to inspect its contents, + * and need not do a check and set because: + * 1. Any work handler thread only clears "pending" and only + * on one, particular work order at a time, per handler thread. + * 2. "pending" is only set here, and we're serialized because + * we're called in an IRQ handler context. + */ + if (atomic_read(&cx->in_work_order[i].pending) == 0) { + order = &cx->in_work_order[i]; + atomic_set(&order->pending, 1); + break; + } + } + return order; +} + +void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) +{ + struct cx18_mailbox __iomem *mb; + struct cx18_mailbox *order_mb; + struct cx18_in_work_order *order; + int submit; + + switch (rpu) { + case CPU: + mb = &cx->scb->cpu2epu_mb; + break; + case APU: + mb = &cx->scb->apu2epu_mb; + break; + default: + return; + } + + order = alloc_in_work_order_irq(cx); + if (order == NULL) { + CX18_WARN("Unable to find blank work order form to schedule " + "incoming mailbox command processing\n"); + return; + } + + order->flags = 0; + order->rpu = rpu; + order_mb = &order->mb; + + /* mb->cmd and mb->args[0] through mb->args[2] */ + cx18_memcpy_fromio(cx, &order_mb->cmd, &mb->cmd, 4 * sizeof(u32)); + /* mb->request and mb->ack. N.B. we want to read mb->ack last */ + cx18_memcpy_fromio(cx, &order_mb->request, &mb->request, + 2 * sizeof(u32)); + + if (order_mb->request == order_mb->ack) { + CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " + "incoming %s to EPU mailbox (sequence no. %u)" + "\n", + rpu_str[rpu], rpu_str[rpu], order_mb->request); + if (cx18_debug & CX18_DBGFLG_WARN) + dump_mb(cx, order_mb, "incoming"); + order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT; + } + + /* + * Individual EPU command processing is responsible for ack-ing + * a non-stale mailbox as soon as possible + */ + submit = epu_cmd_irq(cx, order); + if (submit > 0) { + queue_work(cx->in_work_queue, &order->work); + } +} + + +/* + * Functions called from a non-interrupt, non work_queue context + */ + +static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) +{ + const struct cx18_api_info *info = find_api_info(cmd); + u32 state, irq, req, ack, err; + struct cx18_mailbox __iomem *mb; + u32 __iomem *xpu_state; + wait_queue_head_t *waitq; + struct mutex *mb_lock; + unsigned long int t0, timeout, ret; + int i; + char argstr[MAX_MB_ARGUMENTS*11+1]; + DEFINE_WAIT(w); + + if (info == NULL) { + CX18_WARN("unknown cmd %x\n", cmd); + return -EINVAL; + } + + if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */ + if (cmd == CX18_CPU_DE_SET_MDL) { + if (cx18_debug & CX18_DBGFLG_HIGHVOL) + CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n", + info->name, cmd, + u32arr2hex(data, args, argstr)); + } else + CX18_DEBUG_API("%s\tcmd %#010x args%s\n", + info->name, cmd, + u32arr2hex(data, args, argstr)); + } + + switch (info->rpu) { + case APU: + waitq = &cx->mb_apu_waitq; + mb_lock = &cx->epu2apu_mb_lock; + irq = IRQ_EPU_TO_APU; + mb = &cx->scb->epu2apu_mb; + xpu_state = &cx->scb->apu_state; + break; + case CPU: + waitq = &cx->mb_cpu_waitq; + mb_lock = &cx->epu2cpu_mb_lock; + irq = IRQ_EPU_TO_CPU; + mb = &cx->scb->epu2cpu_mb; + xpu_state = &cx->scb->cpu_state; + break; + default: + CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); + return -EINVAL; + } + + mutex_lock(mb_lock); + /* + * Wait for an in-use mailbox to complete + * + * If the XPU is responding with Ack's, the mailbox shouldn't be in + * a busy state, since we serialize access to it on our end. + * + * If the wait for ack after sending a previous command was interrupted + * by a signal, we may get here and find a busy mailbox. After waiting, + * mark it "not busy" from our end, if the XPU hasn't ack'ed it still. + */ + state = cx18_readl(cx, xpu_state); + req = cx18_readl(cx, &mb->request); + timeout = msecs_to_jiffies(10); + ret = wait_event_timeout(*waitq, + (ack = cx18_readl(cx, &mb->ack)) == req, + timeout); + if (req != ack) { + /* waited long enough, make the mbox "not busy" from our end */ + cx18_writel(cx, req, &mb->ack); + CX18_ERR("mbox was found stuck busy when setting up for %s; " + "clearing busy and trying to proceed\n", info->name); + } else if (ret != timeout) + CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n", + jiffies_to_msecs(timeout-ret)); + + /* Build the outgoing mailbox */ + req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1; + + cx18_writel(cx, cmd, &mb->cmd); + for (i = 0; i < args; i++) + cx18_writel(cx, data[i], &mb->args[i]); + cx18_writel(cx, 0, &mb->error); + cx18_writel(cx, req, &mb->request); + cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ + + /* + * Notify the XPU and wait for it to send an Ack back + */ + timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20); + + CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", + irq, info->name); + + /* So we don't miss the wakeup, prepare to wait before notifying fw */ + prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE); + cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); + + t0 = jiffies; + ack = cx18_readl(cx, &mb->ack); + if (ack != req) { + schedule_timeout(timeout); + ret = jiffies - t0; + ack = cx18_readl(cx, &mb->ack); + } else { + ret = jiffies - t0; + } + + finish_wait(waitq, &w); + + if (req != ack) { + mutex_unlock(mb_lock); + if (ret >= timeout) { + /* Timed out */ + CX18_DEBUG_WARN("sending %s timed out waiting %d msecs " + "for RPU acknowledgement\n", + info->name, jiffies_to_msecs(ret)); + } else { + CX18_DEBUG_WARN("woken up before mailbox ack was ready " + "after submitting %s to RPU. only " + "waited %d msecs on req %u but awakened" + " with unmatched ack %u\n", + info->name, + jiffies_to_msecs(ret), + req, ack); + } + return -EINVAL; + } + + if (ret >= timeout) + CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment " + "sending %s; timed out waiting %d msecs\n", + info->name, jiffies_to_msecs(ret)); + else + CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", + jiffies_to_msecs(ret), info->name); + + /* Collect data returned by the XPU */ + for (i = 0; i < MAX_MB_ARGUMENTS; i++) + data[i] = cx18_readl(cx, &mb->args[i]); + err = cx18_readl(cx, &mb->error); + mutex_unlock(mb_lock); + + /* + * Wait for XPU to perform extra actions for the caller in some cases. + * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all MDLs + * back in a burst shortly thereafter + */ + if (info->flags & API_SLOW) + cx18_msleep_timeout(300, 0); + + if (err) + CX18_DEBUG_API("mailbox error %08x for command %s\n", err, + info->name); + return err ? -EIO : 0; +} + +int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) +{ + return cx18_api_call(cx, cmd, args, data); +} + +static int cx18_set_filter_param(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + u32 mode; + int ret; + + mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0); + ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 1, mode, cx->spatial_strength); + mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0); + ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 0, mode, cx->temporal_strength); + ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 2, cx->filter_mode >> 2, 0); + return ret; +} + +int cx18_api_func(void *priv, u32 cmd, int in, int out, + u32 data[CX2341X_MBOX_MAX_DATA]) +{ + struct cx18_stream *s = priv; + struct cx18 *cx = s->cx; + + switch (cmd) { + case CX2341X_ENC_SET_OUTPUT_PORT: + return 0; + case CX2341X_ENC_SET_FRAME_RATE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6, + s->handle, 0, 0, 0, 0, data[0]); + case CX2341X_ENC_SET_FRAME_SIZE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3, + s->handle, data[1], data[0]); + case CX2341X_ENC_SET_STREAM_TYPE: + return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_ASPECT_RATIO: + return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2, + s->handle, data[0]); + + case CX2341X_ENC_SET_GOP_PROPERTIES: + return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3, + s->handle, data[0], data[1]); + case CX2341X_ENC_SET_GOP_CLOSURE: + return 0; + case CX2341X_ENC_SET_AUDIO_PROPERTIES: + return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, + s->handle, data[0]); + case CX2341X_ENC_MUTE_AUDIO: + return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_BIT_RATE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5, + s->handle, data[0], data[1], data[2], data[3]); + case CX2341X_ENC_MUTE_VIDEO: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_FRAME_DROP_RATE: + return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2, + s->handle, data[0]); + case CX2341X_ENC_MISC: + return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4, + s->handle, data[0], data[1], data[2]); + case CX2341X_ENC_SET_DNR_FILTER_MODE: + cx->filter_mode = (data[0] & 3) | (data[1] << 2); + return cx18_set_filter_param(s); + case CX2341X_ENC_SET_DNR_FILTER_PROPS: + cx->spatial_strength = data[0]; + cx->temporal_strength = data[1]; + return cx18_set_filter_param(s); + case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: + return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3, + s->handle, data[0], data[1]); + case CX2341X_ENC_SET_CORING_LEVELS: + return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5, + s->handle, data[0], data[1], data[2], data[3]); + } + CX18_WARN("Unknown cmd %x\n", cmd); + return 0; +} + +int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], + u32 cmd, int args, ...) +{ + va_list ap; + int i; + + va_start(ap, args); + for (i = 0; i < args; i++) + data[i] = va_arg(ap, u32); + va_end(ap); + return cx18_api(cx, cmd, args, data); +} + +int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...) +{ + u32 data[MAX_MB_ARGUMENTS]; + va_list ap; + int i; + + if (cx == NULL) { + CX18_ERR("cx == NULL (cmd=%x)\n", cmd); + return 0; + } + if (args > MAX_MB_ARGUMENTS) { + CX18_ERR("args too big (cmd=%x)\n", cmd); + args = MAX_MB_ARGUMENTS; + } + va_start(ap, args); + for (i = 0; i < args; i++) + data[i] = va_arg(ap, u32); + va_end(ap); + return cx18_api(cx, cmd, args, data); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-mailbox.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-mailbox.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-mailbox.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-mailbox.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * cx18 mailbox functions + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#ifndef _CX18_MAILBOX_H_ +#define _CX18_MAILBOX_H_ + +/* mailbox max args */ +#define MAX_MB_ARGUMENTS 6 +/* compatibility, should be same as the define in cx2341x.h */ +#define CX2341X_MBOX_MAX_DATA 16 + +#define MB_RESERVED_HANDLE_0 0 +#define MB_RESERVED_HANDLE_1 0xFFFFFFFF + +#define APU 0 +#define CPU 1 +#define EPU 2 +#define HPU 3 + +struct cx18; + +/* + * This structure is used by CPU to provide completed MDL & buffers information. + * Its structure is dictated by the layout of the SCB, required by the + * firmware, but its definition needs to be here, instead of in cx18-scb.h, + * for mailbox work order scheduling + */ +struct cx18_mdl_ack { + u32 id; /* ID of a completed MDL */ + u32 data_used; /* Total data filled in the MDL with 'id' */ +}; + +/* The cx18_mailbox struct is the mailbox structure which is used for passing + messages between processors */ +struct cx18_mailbox { + /* The sender sets a handle in 'request' after he fills the command. The + 'request' should be different than 'ack'. The sender, also, generates + an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the + receiver. */ + u32 request; + /* The receiver detects a new command when 'req' is different than 'ack'. + He sets 'ack' to the same value as 'req' to clear the command. He, also, + generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU + is the receiver. */ + u32 ack; + u32 reserved[6]; + /* 'cmd' identifies the command. The list of these commands are in + cx23418.h */ + u32 cmd; + /* Each command can have up to 6 arguments */ + u32 args[MAX_MB_ARGUMENTS]; + /* The return code can be one of the codes in the file cx23418.h. If the + command is completed successfuly, the error will be ERR_SYS_SUCCESS. + If it is pending, the code is ERR_SYS_PENDING. If it failed, the error + code would indicate the task from which the error originated and will + be one of the errors in cx23418.h. In that case, the following + applies ((error & 0xff) != 0). + If the command is pending, the return will be passed in a MB from the + receiver to the sender. 'req' will be returned in args[0] */ + u32 error; +}; + +struct cx18_stream; + +int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); +int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, + int args, ...); +int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); +int cx18_api_func(void *priv, u32 cmd, int in, int out, + u32 data[CX2341X_MBOX_MAX_DATA]); + +void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu); + +void cx18_in_work_handler(struct work_struct *work); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-queue.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-queue.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-queue.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-queue.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,443 @@ +/* + * cx18 buffer queues + * + * Derived from ivtv-queue.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-queue.h" +#include "cx18-streams.h" +#include "cx18-scb.h" +#include "cx18-io.h" + +void cx18_buf_swap(struct cx18_buffer *buf) +{ + int i; + + for (i = 0; i < buf->bytesused; i += 4) + swab32s((u32 *)(buf->buf + i)); +} + +void _cx18_mdl_swap(struct cx18_mdl *mdl) +{ + struct cx18_buffer *buf; + + list_for_each_entry(buf, &mdl->buf_list, list) { + if (buf->bytesused == 0) + break; + cx18_buf_swap(buf); + } +} + +void cx18_queue_init(struct cx18_queue *q) +{ + INIT_LIST_HEAD(&q->list); + atomic_set(&q->depth, 0); + q->bytesused = 0; +} + +struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, + struct cx18_queue *q, int to_front) +{ + /* clear the mdl if it is not to be enqueued to the full queue */ + if (q != &s->q_full) { + mdl->bytesused = 0; + mdl->readpos = 0; + mdl->m_flags = 0; + mdl->skipped = 0; + mdl->curr_buf = NULL; + } + + /* q_busy is restricted to a max buffer count imposed by firmware */ + if (q == &s->q_busy && + atomic_read(&q->depth) >= CX18_MAX_FW_MDLS_PER_STREAM) + q = &s->q_free; + + spin_lock(&q->lock); + + if (to_front) + list_add(&mdl->list, &q->list); /* LIFO */ + else + list_add_tail(&mdl->list, &q->list); /* FIFO */ + q->bytesused += mdl->bytesused - mdl->readpos; + atomic_inc(&q->depth); + + spin_unlock(&q->lock); + return q; +} + +struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) +{ + struct cx18_mdl *mdl = NULL; + + spin_lock(&q->lock); + if (!list_empty(&q->list)) { + mdl = list_first_entry(&q->list, struct cx18_mdl, list); + list_del_init(&mdl->list); + q->bytesused -= mdl->bytesused - mdl->readpos; + mdl->skipped = 0; + atomic_dec(&q->depth); + } + spin_unlock(&q->lock); + return mdl; +} + +static void _cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s, + struct cx18_mdl *mdl) +{ + struct cx18_buffer *buf; + u32 buf_size = s->buf_size; + u32 bytesused = mdl->bytesused; + + list_for_each_entry(buf, &mdl->buf_list, list) { + buf->readpos = 0; + if (bytesused >= buf_size) { + buf->bytesused = buf_size; + bytesused -= buf_size; + } else { + buf->bytesused = bytesused; + bytesused = 0; + } + cx18_buf_sync_for_cpu(s, buf); + } +} + +static inline void cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s, + struct cx18_mdl *mdl) +{ + struct cx18_buffer *buf; + + if (list_is_singular(&mdl->buf_list)) { + buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, + list); + buf->bytesused = mdl->bytesused; + buf->readpos = 0; + cx18_buf_sync_for_cpu(s, buf); + } else { + _cx18_mdl_update_bufs_for_cpu(s, mdl); + } +} + +struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, + u32 bytesused) +{ + struct cx18 *cx = s->cx; + struct cx18_mdl *mdl; + struct cx18_mdl *tmp; + struct cx18_mdl *ret = NULL; + LIST_HEAD(sweep_up); + + /* + * We don't have to acquire multiple q locks here, because we are + * serialized by the single threaded work handler. + * MDLs from the firmware will thus remain in order as + * they are moved from q_busy to q_full or to the dvb ring buffer. + */ + spin_lock(&s->q_busy.lock); + list_for_each_entry_safe(mdl, tmp, &s->q_busy.list, list) { + /* + * We should find what the firmware told us is done, + * right at the front of the queue. If we don't, we likely have + * missed an mdl done message from the firmware. + * Once we skip an mdl repeatedly, relative to the size of + * q_busy, we have high confidence we've missed it. + */ + if (mdl->id != id) { + mdl->skipped++; + if (mdl->skipped >= atomic_read(&s->q_busy.depth)-1) { + /* mdl must have fallen out of rotation */ + CX18_WARN("Skipped %s, MDL %d, %d " + "times - it must have dropped out of " + "rotation\n", s->name, mdl->id, + mdl->skipped); + /* Sweep it up to put it back into rotation */ + list_move_tail(&mdl->list, &sweep_up); + atomic_dec(&s->q_busy.depth); + } + continue; + } + /* + * We pull the desired mdl off of the queue here. Something + * will have to put it back on a queue later. + */ + list_del_init(&mdl->list); + atomic_dec(&s->q_busy.depth); + ret = mdl; + break; + } + spin_unlock(&s->q_busy.lock); + + /* + * We found the mdl for which we were looking. Get it ready for + * the caller to put on q_full or in the dvb ring buffer. + */ + if (ret != NULL) { + ret->bytesused = bytesused; + ret->skipped = 0; + /* 0'ed readpos, m_flags & curr_buf when mdl went on q_busy */ + cx18_mdl_update_bufs_for_cpu(s, ret); + if (s->type != CX18_ENC_STREAM_TYPE_TS) + set_bit(CX18_F_M_NEED_SWAP, &ret->m_flags); + } + + /* Put any mdls the firmware is ignoring back into normal rotation */ + list_for_each_entry_safe(mdl, tmp, &sweep_up, list) { + list_del_init(&mdl->list); + cx18_enqueue(s, mdl, &s->q_free); + } + return ret; +} + +/* Move all mdls of a queue, while flushing the mdl */ +static void cx18_queue_flush(struct cx18_stream *s, + struct cx18_queue *q_src, struct cx18_queue *q_dst) +{ + struct cx18_mdl *mdl; + + /* It only makes sense to flush to q_free or q_idle */ + if (q_src == q_dst || q_dst == &s->q_full || q_dst == &s->q_busy) + return; + + spin_lock(&q_src->lock); + spin_lock(&q_dst->lock); + while (!list_empty(&q_src->list)) { + mdl = list_first_entry(&q_src->list, struct cx18_mdl, list); + list_move_tail(&mdl->list, &q_dst->list); + mdl->bytesused = 0; + mdl->readpos = 0; + mdl->m_flags = 0; + mdl->skipped = 0; + mdl->curr_buf = NULL; + atomic_inc(&q_dst->depth); + } + cx18_queue_init(q_src); + spin_unlock(&q_src->lock); + spin_unlock(&q_dst->lock); +} + +void cx18_flush_queues(struct cx18_stream *s) +{ + cx18_queue_flush(s, &s->q_busy, &s->q_free); + cx18_queue_flush(s, &s->q_full, &s->q_free); +} + +/* + * Note, s->buf_pool is not protected by a lock, + * the stream better not have *anything* going on when calling this + */ +void cx18_unload_queues(struct cx18_stream *s) +{ + struct cx18_queue *q_idle = &s->q_idle; + struct cx18_mdl *mdl; + struct cx18_buffer *buf; + + /* Move all MDLS to q_idle */ + cx18_queue_flush(s, &s->q_busy, q_idle); + cx18_queue_flush(s, &s->q_full, q_idle); + cx18_queue_flush(s, &s->q_free, q_idle); + + /* Reset MDL id's and move all buffers back to the stream's buf_pool */ + spin_lock(&q_idle->lock); + list_for_each_entry(mdl, &q_idle->list, list) { + while (!list_empty(&mdl->buf_list)) { + buf = list_first_entry(&mdl->buf_list, + struct cx18_buffer, list); + list_move_tail(&buf->list, &s->buf_pool); + buf->bytesused = 0; + buf->readpos = 0; + } + mdl->id = s->mdl_base_idx; /* reset id to a "safe" value */ + /* all other mdl fields were cleared by cx18_queue_flush() */ + } + spin_unlock(&q_idle->lock); +} + +/* + * Note, s->buf_pool is not protected by a lock, + * the stream better not have *anything* going on when calling this + */ +void cx18_load_queues(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + struct cx18_mdl *mdl; + struct cx18_buffer *buf; + int mdl_id; + int i; + u32 partial_buf_size; + + /* + * Attach buffers to MDLs, give the MDLs ids, and add MDLs to q_free + * Excess MDLs are left on q_idle + * Excess buffers are left in buf_pool and/or on an MDL in q_idle + */ + mdl_id = s->mdl_base_idx; + for (mdl = cx18_dequeue(s, &s->q_idle), i = s->bufs_per_mdl; + mdl != NULL && i == s->bufs_per_mdl; + mdl = cx18_dequeue(s, &s->q_idle)) { + + mdl->id = mdl_id; + + for (i = 0; i < s->bufs_per_mdl; i++) { + if (list_empty(&s->buf_pool)) + break; + + buf = list_first_entry(&s->buf_pool, struct cx18_buffer, + list); + list_move_tail(&buf->list, &mdl->buf_list); + + /* update the firmware's MDL array with this buffer */ + cx18_writel(cx, buf->dma_handle, + &cx->scb->cpu_mdl[mdl_id + i].paddr); + cx18_writel(cx, s->buf_size, + &cx->scb->cpu_mdl[mdl_id + i].length); + } + + if (i == s->bufs_per_mdl) { + /* + * The encoder doesn't honor s->mdl_size. So in the + * case of a non-integral number of buffers to meet + * mdl_size, we lie about the size of the last buffer + * in the MDL to get the encoder to really only send + * us mdl_size bytes per MDL transfer. + */ + partial_buf_size = s->mdl_size % s->buf_size; + if (partial_buf_size) { + cx18_writel(cx, partial_buf_size, + &cx->scb->cpu_mdl[mdl_id + i - 1].length); + } + cx18_enqueue(s, mdl, &s->q_free); + } else { + /* Not enough buffers for this MDL; we won't use it */ + cx18_push(s, mdl, &s->q_idle); + } + mdl_id += i; + } +} + +void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl) +{ + int dma = s->dma; + u32 buf_size = s->buf_size; + struct pci_dev *pci_dev = s->cx->pci_dev; + struct cx18_buffer *buf; + + list_for_each_entry(buf, &mdl->buf_list, list) + pci_dma_sync_single_for_device(pci_dev, buf->dma_handle, + buf_size, dma); +} + +int cx18_stream_alloc(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + int i; + + if (s->buffers == 0) + return 0; + + CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers " + "(%d.%02d kB total)\n", + s->name, s->buffers, s->buf_size, + s->buffers * s->buf_size / 1024, + (s->buffers * s->buf_size * 100 / 1024) % 100); + + if (((char __iomem *)&cx->scb->cpu_mdl[cx->free_mdl_idx + s->buffers] - + (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) { + unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE - + ((char __iomem *)cx->scb->cpu_mdl)); + + CX18_ERR("Too many buffers, cannot fit in SCB area\n"); + CX18_ERR("Max buffers = %zd\n", + bufsz / sizeof(struct cx18_mdl_ent)); + return -ENOMEM; + } + + s->mdl_base_idx = cx->free_mdl_idx; + + /* allocate stream buffers and MDLs */ + for (i = 0; i < s->buffers; i++) { + struct cx18_mdl *mdl; + struct cx18_buffer *buf; + + /* 1 MDL per buffer to handle the worst & also default case */ + mdl = kzalloc(sizeof(struct cx18_mdl), GFP_KERNEL|__GFP_NOWARN); + if (mdl == NULL) + break; + + buf = kzalloc(sizeof(struct cx18_buffer), + GFP_KERNEL|__GFP_NOWARN); + if (buf == NULL) { + kfree(mdl); + break; + } + + buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN); + if (buf->buf == NULL) { + kfree(mdl); + kfree(buf); + break; + } + + INIT_LIST_HEAD(&mdl->list); + INIT_LIST_HEAD(&mdl->buf_list); + mdl->id = s->mdl_base_idx; /* a somewhat safe value */ + cx18_enqueue(s, mdl, &s->q_idle); + + INIT_LIST_HEAD(&buf->list); + buf->dma_handle = pci_map_single(s->cx->pci_dev, + buf->buf, s->buf_size, s->dma); + cx18_buf_sync_for_cpu(s, buf); + list_add_tail(&buf->list, &s->buf_pool); + } + if (i == s->buffers) { + cx->free_mdl_idx += s->buffers; + return 0; + } + CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name); + cx18_stream_free(s); + return -ENOMEM; +} + +void cx18_stream_free(struct cx18_stream *s) +{ + struct cx18_mdl *mdl; + struct cx18_buffer *buf; + struct cx18 *cx = s->cx; + + CX18_DEBUG_INFO("Deallocating buffers for %s stream\n", s->name); + + /* move all buffers to buf_pool and all MDLs to q_idle */ + cx18_unload_queues(s); + + /* empty q_idle */ + while ((mdl = cx18_dequeue(s, &s->q_idle))) + kfree(mdl); + + /* empty buf_pool */ + while (!list_empty(&s->buf_pool)) { + buf = list_first_entry(&s->buf_pool, struct cx18_buffer, list); + list_del_init(&buf->list); + + pci_unmap_single(s->cx->pci_dev, buf->dma_handle, + s->buf_size, s->dma); + kfree(buf->buf); + kfree(buf); + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-queue.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-queue.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-queue.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-queue.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * cx18 buffer queues + * + * Derived from ivtv-queue.h + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#define CX18_DMA_UNMAPPED ((u32) -1) + +/* cx18_buffer utility functions */ + +static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + pci_dma_sync_single_for_cpu(s->cx->pci_dev, buf->dma_handle, + s->buf_size, s->dma); +} + +static inline void cx18_buf_sync_for_device(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + pci_dma_sync_single_for_device(s->cx->pci_dev, buf->dma_handle, + s->buf_size, s->dma); +} + +void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl); + +static inline void cx18_mdl_sync_for_device(struct cx18_stream *s, + struct cx18_mdl *mdl) +{ + if (list_is_singular(&mdl->buf_list)) + cx18_buf_sync_for_device(s, list_first_entry(&mdl->buf_list, + struct cx18_buffer, + list)); + else + _cx18_mdl_sync_for_device(s, mdl); +} + +void cx18_buf_swap(struct cx18_buffer *buf); +void _cx18_mdl_swap(struct cx18_mdl *mdl); + +static inline void cx18_mdl_swap(struct cx18_mdl *mdl) +{ + if (list_is_singular(&mdl->buf_list)) + cx18_buf_swap(list_first_entry(&mdl->buf_list, + struct cx18_buffer, list)); + else + _cx18_mdl_swap(mdl); +} + +/* cx18_queue utility functions */ +struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, + struct cx18_queue *q, int to_front); + +static inline +struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, + struct cx18_queue *q) +{ + return _cx18_enqueue(s, mdl, q, 0); /* FIFO */ +} + +static inline +struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_mdl *mdl, + struct cx18_queue *q) +{ + return _cx18_enqueue(s, mdl, q, 1); /* LIFO */ +} + +void cx18_queue_init(struct cx18_queue *q); +struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); +struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, + u32 bytesused); +void cx18_flush_queues(struct cx18_stream *s); + +/* queue MDL reconfiguration helpers */ +void cx18_unload_queues(struct cx18_stream *s); +void cx18_load_queues(struct cx18_stream *s); + +/* cx18_stream utility functions */ +int cx18_stream_alloc(struct cx18_stream *s); +void cx18_stream_free(struct cx18_stream *s); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-scb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-scb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-scb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-scb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,122 @@ +/* + * cx18 System Control Block initialization + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-scb.h" + +void cx18_init_scb(struct cx18 *cx) +{ + cx18_setup_page(cx, SCB_OFFSET); + cx18_memset_io(cx, cx->scb, 0, 0x10000); + + cx18_writel(cx, IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq); + cx18_writel(cx, IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack); + cx18_writel(cx, IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq); + cx18_writel(cx, IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack); + cx18_writel(cx, IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq); + cx18_writel(cx, IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack); + cx18_writel(cx, IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq); + cx18_writel(cx, IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack); + + cx18_writel(cx, IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq); + cx18_writel(cx, IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack); + cx18_writel(cx, IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq); + cx18_writel(cx, IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack); + cx18_writel(cx, IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq); + cx18_writel(cx, IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack); + cx18_writel(cx, IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq); + cx18_writel(cx, IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack); + + cx18_writel(cx, IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq); + cx18_writel(cx, IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack); + cx18_writel(cx, IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq); + cx18_writel(cx, IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack); + cx18_writel(cx, IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq); + cx18_writel(cx, IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack); + cx18_writel(cx, IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq); + cx18_writel(cx, IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack); + + cx18_writel(cx, IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq); + cx18_writel(cx, IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack); + cx18_writel(cx, IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq); + cx18_writel(cx, IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack); + cx18_writel(cx, IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq); + cx18_writel(cx, IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack); + cx18_writel(cx, IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq); + cx18_writel(cx, IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack); + + cx18_writel(cx, IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq); + cx18_writel(cx, IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack); + cx18_writel(cx, IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq); + cx18_writel(cx, IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack); + cx18_writel(cx, IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq); + cx18_writel(cx, IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack); + cx18_writel(cx, IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq); + cx18_writel(cx, IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack); + + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb), + &cx->scb->apu2cpu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb), + &cx->scb->hpu2cpu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb), + &cx->scb->ppu2cpu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb), + &cx->scb->epu2cpu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb), + &cx->scb->cpu2apu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb), + &cx->scb->hpu2apu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb), + &cx->scb->ppu2apu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb), + &cx->scb->epu2apu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb), + &cx->scb->cpu2hpu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb), + &cx->scb->apu2hpu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb), + &cx->scb->ppu2hpu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb), + &cx->scb->epu2hpu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb), + &cx->scb->cpu2ppu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb), + &cx->scb->apu2ppu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb), + &cx->scb->hpu2ppu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb), + &cx->scb->epu2ppu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb), + &cx->scb->cpu2epu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb), + &cx->scb->apu2epu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb), + &cx->scb->hpu2epu_mb_offset); + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb), + &cx->scb->ppu2epu_mb_offset); + + cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state), + &cx->scb->ipc_offset); + + cx18_writel(cx, 1, &cx->scb->epu_state); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-scb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-scb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-scb.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-scb.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,280 @@ +/* + * cx18 System Control Block initialization + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#ifndef CX18_SCB_H +#define CX18_SCB_H + +#include "cx18-mailbox.h" + +/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts + are in the SW1 register. */ + +#define IRQ_APU_TO_CPU 0x00000001 +#define IRQ_CPU_TO_APU_ACK 0x00000001 +#define IRQ_HPU_TO_CPU 0x00000002 +#define IRQ_CPU_TO_HPU_ACK 0x00000002 +#define IRQ_PPU_TO_CPU 0x00000004 +#define IRQ_CPU_TO_PPU_ACK 0x00000004 +#define IRQ_EPU_TO_CPU 0x00000008 +#define IRQ_CPU_TO_EPU_ACK 0x00000008 + +#define IRQ_CPU_TO_APU 0x00000010 +#define IRQ_APU_TO_CPU_ACK 0x00000010 +#define IRQ_HPU_TO_APU 0x00000020 +#define IRQ_APU_TO_HPU_ACK 0x00000020 +#define IRQ_PPU_TO_APU 0x00000040 +#define IRQ_APU_TO_PPU_ACK 0x00000040 +#define IRQ_EPU_TO_APU 0x00000080 +#define IRQ_APU_TO_EPU_ACK 0x00000080 + +#define IRQ_CPU_TO_HPU 0x00000100 +#define IRQ_HPU_TO_CPU_ACK 0x00000100 +#define IRQ_APU_TO_HPU 0x00000200 +#define IRQ_HPU_TO_APU_ACK 0x00000200 +#define IRQ_PPU_TO_HPU 0x00000400 +#define IRQ_HPU_TO_PPU_ACK 0x00000400 +#define IRQ_EPU_TO_HPU 0x00000800 +#define IRQ_HPU_TO_EPU_ACK 0x00000800 + +#define IRQ_CPU_TO_PPU 0x00001000 +#define IRQ_PPU_TO_CPU_ACK 0x00001000 +#define IRQ_APU_TO_PPU 0x00002000 +#define IRQ_PPU_TO_APU_ACK 0x00002000 +#define IRQ_HPU_TO_PPU 0x00004000 +#define IRQ_PPU_TO_HPU_ACK 0x00004000 +#define IRQ_EPU_TO_PPU 0x00008000 +#define IRQ_PPU_TO_EPU_ACK 0x00008000 + +#define IRQ_CPU_TO_EPU 0x00010000 +#define IRQ_EPU_TO_CPU_ACK 0x00010000 +#define IRQ_APU_TO_EPU 0x00020000 +#define IRQ_EPU_TO_APU_ACK 0x00020000 +#define IRQ_HPU_TO_EPU 0x00040000 +#define IRQ_EPU_TO_HPU_ACK 0x00040000 +#define IRQ_PPU_TO_EPU 0x00080000 +#define IRQ_EPU_TO_PPU_ACK 0x00080000 + +#define SCB_OFFSET 0xDC0000 + +/* If Firmware uses fixed memory map, it shall not allocate the area + between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */ +#define SCB_RESERVED_SIZE 0x10000 + + +/* This structure is used by EPU to provide memory descriptors in its memory */ +struct cx18_mdl_ent { + u32 paddr; /* Physical address of a buffer segment */ + u32 length; /* Length of the buffer segment */ +}; + +struct cx18_scb { + /* These fields form the System Control Block which is used at boot time + for localizing the IPC data as well as the code positions for all + processors. The offsets are from the start of this struct. */ + + /* Offset where to find the Inter-Processor Communication data */ + u32 ipc_offset; + u32 reserved01[7]; + /* Offset where to find the start of the CPU code */ + u32 cpu_code_offset; + u32 reserved02[3]; + /* Offset where to find the start of the APU code */ + u32 apu_code_offset; + u32 reserved03[3]; + /* Offset where to find the start of the HPU code */ + u32 hpu_code_offset; + u32 reserved04[3]; + /* Offset where to find the start of the PPU code */ + u32 ppu_code_offset; + u32 reserved05[3]; + + /* These fields form Inter-Processor Communication data which is used + by all processors to locate the information needed for communicating + with other processors */ + + /* Fields for CPU: */ + + /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */ + u32 cpu_state; + u32 reserved1[7]; + /* Offset to the mailbox used for sending commands from APU to CPU */ + u32 apu2cpu_mb_offset; + /* Value to write to register SW1 register set (0xC7003100) after the + command is ready */ + u32 apu2cpu_irq; + /* Value to write to register SW2 register set (0xC7003140) after the + command is cleared */ + u32 cpu2apu_irq_ack; + u32 reserved2[13]; + + u32 hpu2cpu_mb_offset; + u32 hpu2cpu_irq; + u32 cpu2hpu_irq_ack; + u32 reserved3[13]; + + u32 ppu2cpu_mb_offset; + u32 ppu2cpu_irq; + u32 cpu2ppu_irq_ack; + u32 reserved4[13]; + + u32 epu2cpu_mb_offset; + u32 epu2cpu_irq; + u32 cpu2epu_irq_ack; + u32 reserved5[13]; + u32 reserved6[8]; + + /* Fields for APU: */ + + u32 apu_state; + u32 reserved11[7]; + u32 cpu2apu_mb_offset; + u32 cpu2apu_irq; + u32 apu2cpu_irq_ack; + u32 reserved12[13]; + + u32 hpu2apu_mb_offset; + u32 hpu2apu_irq; + u32 apu2hpu_irq_ack; + u32 reserved13[13]; + + u32 ppu2apu_mb_offset; + u32 ppu2apu_irq; + u32 apu2ppu_irq_ack; + u32 reserved14[13]; + + u32 epu2apu_mb_offset; + u32 epu2apu_irq; + u32 apu2epu_irq_ack; + u32 reserved15[13]; + u32 reserved16[8]; + + /* Fields for HPU: */ + + u32 hpu_state; + u32 reserved21[7]; + u32 cpu2hpu_mb_offset; + u32 cpu2hpu_irq; + u32 hpu2cpu_irq_ack; + u32 reserved22[13]; + + u32 apu2hpu_mb_offset; + u32 apu2hpu_irq; + u32 hpu2apu_irq_ack; + u32 reserved23[13]; + + u32 ppu2hpu_mb_offset; + u32 ppu2hpu_irq; + u32 hpu2ppu_irq_ack; + u32 reserved24[13]; + + u32 epu2hpu_mb_offset; + u32 epu2hpu_irq; + u32 hpu2epu_irq_ack; + u32 reserved25[13]; + u32 reserved26[8]; + + /* Fields for PPU: */ + + u32 ppu_state; + u32 reserved31[7]; + u32 cpu2ppu_mb_offset; + u32 cpu2ppu_irq; + u32 ppu2cpu_irq_ack; + u32 reserved32[13]; + + u32 apu2ppu_mb_offset; + u32 apu2ppu_irq; + u32 ppu2apu_irq_ack; + u32 reserved33[13]; + + u32 hpu2ppu_mb_offset; + u32 hpu2ppu_irq; + u32 ppu2hpu_irq_ack; + u32 reserved34[13]; + + u32 epu2ppu_mb_offset; + u32 epu2ppu_irq; + u32 ppu2epu_irq_ack; + u32 reserved35[13]; + u32 reserved36[8]; + + /* Fields for EPU: */ + + u32 epu_state; + u32 reserved41[7]; + u32 cpu2epu_mb_offset; + u32 cpu2epu_irq; + u32 epu2cpu_irq_ack; + u32 reserved42[13]; + + u32 apu2epu_mb_offset; + u32 apu2epu_irq; + u32 epu2apu_irq_ack; + u32 reserved43[13]; + + u32 hpu2epu_mb_offset; + u32 hpu2epu_irq; + u32 epu2hpu_irq_ack; + u32 reserved44[13]; + + u32 ppu2epu_mb_offset; + u32 ppu2epu_irq; + u32 epu2ppu_irq_ack; + u32 reserved45[13]; + u32 reserved46[8]; + + u32 semaphores[8]; /* Semaphores */ + + u32 reserved50[32]; /* Reserved for future use */ + + struct cx18_mailbox apu2cpu_mb; + struct cx18_mailbox hpu2cpu_mb; + struct cx18_mailbox ppu2cpu_mb; + struct cx18_mailbox epu2cpu_mb; + + struct cx18_mailbox cpu2apu_mb; + struct cx18_mailbox hpu2apu_mb; + struct cx18_mailbox ppu2apu_mb; + struct cx18_mailbox epu2apu_mb; + + struct cx18_mailbox cpu2hpu_mb; + struct cx18_mailbox apu2hpu_mb; + struct cx18_mailbox ppu2hpu_mb; + struct cx18_mailbox epu2hpu_mb; + + struct cx18_mailbox cpu2ppu_mb; + struct cx18_mailbox apu2ppu_mb; + struct cx18_mailbox hpu2ppu_mb; + struct cx18_mailbox epu2ppu_mb; + + struct cx18_mailbox cpu2epu_mb; + struct cx18_mailbox apu2epu_mb; + struct cx18_mailbox hpu2epu_mb; + struct cx18_mailbox ppu2epu_mb; + + struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS]; + struct cx18_mdl_ent cpu_mdl[1]; +}; + +void cx18_init_scb(struct cx18 *cx); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-streams.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-streams.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-streams.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-streams.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1050 @@ +/* + * cx18 init/start/stop/exit stream functions + * + * Derived from ivtv-streams.c + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-io.h" +#include "cx18-fileops.h" +#include "cx18-mailbox.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-ioctl.h" +#include "cx18-streams.h" +#include "cx18-cards.h" +#include "cx18-scb.h" +#include "cx18-dvb.h" + +#define CX18_DSP0_INTERRUPT_MASK 0xd0004C + +static struct v4l2_file_operations cx18_v4l2_enc_fops = { + .owner = THIS_MODULE, + .read = cx18_v4l2_read, + .open = cx18_v4l2_open, + /* FIXME change to video_ioctl2 if serialization lock can be removed */ + .unlocked_ioctl = cx18_v4l2_ioctl, + .release = cx18_v4l2_close, + .poll = cx18_v4l2_enc_poll, + .mmap = cx18_v4l2_mmap, +}; + +/* offset from 0 to register ts v4l2 minors on */ +#define CX18_V4L2_ENC_TS_OFFSET 16 +/* offset from 0 to register pcm v4l2 minors on */ +#define CX18_V4L2_ENC_PCM_OFFSET 24 +/* offset from 0 to register yuv v4l2 minors on */ +#define CX18_V4L2_ENC_YUV_OFFSET 32 + +static struct { + const char *name; + int vfl_type; + int num_offset; + int dma; + enum v4l2_buf_type buf_type; +} cx18_stream_info[] = { + { /* CX18_ENC_STREAM_TYPE_MPG */ + "encoder MPEG", + VFL_TYPE_GRABBER, 0, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + }, + { /* CX18_ENC_STREAM_TYPE_TS */ + "TS", + VFL_TYPE_GRABBER, -1, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + }, + { /* CX18_ENC_STREAM_TYPE_YUV */ + "encoder YUV", + VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + }, + { /* CX18_ENC_STREAM_TYPE_VBI */ + "encoder VBI", + VFL_TYPE_VBI, 0, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE, + }, + { /* CX18_ENC_STREAM_TYPE_PCM */ + "encoder PCM audio", + VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE, + }, + { /* CX18_ENC_STREAM_TYPE_IDX */ + "encoder IDX", + VFL_TYPE_GRABBER, -1, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + }, + { /* CX18_ENC_STREAM_TYPE_RAD */ + "encoder radio", + VFL_TYPE_RADIO, 0, + PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE, + }, +}; + + +void cx18_dma_free(struct videobuf_queue *q, + struct cx18_stream *s, struct cx18_videobuf_buffer *buf) +{ + videobuf_waiton(q, &buf->vb, 0, 0); + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int cx18_prepare_buffer(struct videobuf_queue *q, + struct cx18_stream *s, + struct cx18_videobuf_buffer *buf, + u32 pixelformat, + unsigned int width, unsigned int height, + enum v4l2_field field) +{ + struct cx18 *cx = s->cx; + int rc = 0; + + /* check settings */ + buf->bytes_used = 0; + + if ((width < 48) || (height < 32)) + return -EINVAL; + + buf->vb.size = (width * height * 2); + if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) + return -EINVAL; + + /* alloc + fill struct (if changed) */ + if (buf->vb.width != width || buf->vb.height != height || + buf->vb.field != field || s->pixelformat != pixelformat || + buf->tvnorm != cx->std) { + + buf->vb.width = width; + buf->vb.height = height; + buf->vb.field = field; + buf->tvnorm = cx->std; + s->pixelformat = pixelformat; + + cx18_dma_free(q, s, buf); + } + + if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) + return -EINVAL; + + if (buf->vb.field == 0) + buf->vb.field = V4L2_FIELD_INTERLACED; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + buf->vb.width = width; + buf->vb.height = height; + buf->vb.field = field; + buf->tvnorm = cx->std; + s->pixelformat = pixelformat; + + rc = videobuf_iolock(q, &buf->vb, NULL); + if (rc != 0) + goto fail; + } + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + cx18_dma_free(q, s, buf); + return rc; + +} + +/* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576) + 1440 is a single line of 4:2:2 YUV at 720 luma samples wide +*/ +#define VB_MIN_BUFFERS 32 +#define VB_MIN_BUFSIZE 4147200 + +static int buffer_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct cx18_stream *s = q->priv_data; + struct cx18 *cx = s->cx; + + *size = 2 * cx->cxhdl.width * cx->cxhdl.height; + if (*count == 0) + *count = VB_MIN_BUFFERS; + + while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE) + (*count)--; + + q->field = V4L2_FIELD_INTERLACED; + q->last = V4L2_FIELD_INTERLACED; + + return 0; +} + +static int buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx18_videobuf_buffer *buf = + container_of(vb, struct cx18_videobuf_buffer, vb); + struct cx18_stream *s = q->priv_data; + struct cx18 *cx = s->cx; + + return cx18_prepare_buffer(q, s, buf, s->pixelformat, + cx->cxhdl.width, cx->cxhdl.height, field); +} + +static void buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct cx18_videobuf_buffer *buf = + container_of(vb, struct cx18_videobuf_buffer, vb); + struct cx18_stream *s = q->priv_data; + + cx18_dma_free(q, s, buf); +} + +static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx18_videobuf_buffer *buf = + container_of(vb, struct cx18_videobuf_buffer, vb); + struct cx18_stream *s = q->priv_data; + + buf->vb.state = VIDEOBUF_QUEUED; + + list_add_tail(&buf->vb.queue, &s->vb_capture); +} + +static struct videobuf_queue_ops cx18_videobuf_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +static void cx18_stream_init(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + struct video_device *video_dev = s->video_dev; + + /* we need to keep video_dev, so restore it afterwards */ + memset(s, 0, sizeof(*s)); + s->video_dev = video_dev; + + /* initialize cx18_stream fields */ + s->dvb = NULL; + s->cx = cx; + s->type = type; + s->name = cx18_stream_info[type].name; + s->handle = CX18_INVALID_TASK_HANDLE; + + s->dma = cx18_stream_info[type].dma; + s->buffers = cx->stream_buffers[type]; + s->buf_size = cx->stream_buf_size[type]; + INIT_LIST_HEAD(&s->buf_pool); + s->bufs_per_mdl = 1; + s->mdl_size = s->buf_size * s->bufs_per_mdl; + + init_waitqueue_head(&s->waitq); + s->id = -1; + spin_lock_init(&s->q_free.lock); + cx18_queue_init(&s->q_free); + spin_lock_init(&s->q_busy.lock); + cx18_queue_init(&s->q_busy); + spin_lock_init(&s->q_full.lock); + cx18_queue_init(&s->q_full); + spin_lock_init(&s->q_idle.lock); + cx18_queue_init(&s->q_idle); + + INIT_WORK(&s->out_work_order, cx18_out_work_handler); + + INIT_LIST_HEAD(&s->vb_capture); + s->vb_timeout.function = cx18_vb_timeout; + s->vb_timeout.data = (unsigned long)s; + init_timer(&s->vb_timeout); + spin_lock_init(&s->vb_lock); + if (type == CX18_ENC_STREAM_TYPE_YUV) { + spin_lock_init(&s->vbuf_q_lock); + + s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops, + &cx->pci_dev->dev, &s->vbuf_q_lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct cx18_videobuf_buffer), + s, &cx->serialize_lock); + + /* Assume the previous pixel default */ + s->pixelformat = V4L2_PIX_FMT_HM12; + } +} + +static int cx18_prep_dev(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + u32 cap = cx->v4l2_cap; + int num_offset = cx18_stream_info[type].num_offset; + int num = cx->instance + cx18_first_minor + num_offset; + + /* + * These five fields are always initialized. + * For analog capture related streams, if video_dev == NULL then the + * stream is not in use. + * For the TS stream, if dvb == NULL then the stream is not in use. + * In those cases no other fields but these four can be used. + */ + s->video_dev = NULL; + s->dvb = NULL; + s->cx = cx; + s->type = type; + s->name = cx18_stream_info[type].name; + + /* Check whether the radio is supported */ + if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO)) + return 0; + + /* Check whether VBI is supported */ + if (type == CX18_ENC_STREAM_TYPE_VBI && + !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) + return 0; + + /* User explicitly selected 0 buffers for these streams, so don't + create them. */ + if (cx18_stream_info[type].dma != PCI_DMA_NONE && + cx->stream_buffers[type] == 0) { + CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); + return 0; + } + + cx18_stream_init(cx, type); + + /* Allocate the cx18_dvb struct only for the TS on cards with DTV */ + if (type == CX18_ENC_STREAM_TYPE_TS) { + if (cx->card->hw_all & CX18_HW_DVB) { + s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL); + if (s->dvb == NULL) { + CX18_ERR("Couldn't allocate cx18_dvb structure" + " for %s\n", s->name); + return -ENOMEM; + } + } else { + /* Don't need buffers for the TS, if there is no DVB */ + s->buffers = 0; + } + } + + if (num_offset == -1) + return 0; + + /* allocate and initialize the v4l2 video device structure */ + s->video_dev = video_device_alloc(); + if (s->video_dev == NULL) { + CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", + s->name); + return -ENOMEM; + } + + snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s", + cx->v4l2_dev.name, s->name); + + s->video_dev->num = num; + s->video_dev->v4l2_dev = &cx->v4l2_dev; + s->video_dev->fops = &cx18_v4l2_enc_fops; + s->video_dev->release = video_device_release; + s->video_dev->tvnorms = V4L2_STD_ALL; + set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags); + cx18_set_funcs(s->video_dev); + return 0; +} + +/* Initialize v4l2 variables and register v4l2 devices */ +int cx18_streams_setup(struct cx18 *cx) +{ + int type, ret; + + /* Setup V4L2 Devices */ + for (type = 0; type < CX18_MAX_STREAMS; type++) { + /* Prepare device */ + ret = cx18_prep_dev(cx, type); + if (ret < 0) + break; + + /* Allocate Stream */ + ret = cx18_stream_alloc(&cx->streams[type]); + if (ret < 0) + break; + } + if (type == CX18_MAX_STREAMS) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + cx18_streams_cleanup(cx, 0); + return ret; +} + +static int cx18_reg_dev(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + int vfl_type = cx18_stream_info[type].vfl_type; + const char *name; + int num, ret; + + if (type == CX18_ENC_STREAM_TYPE_TS && s->dvb != NULL) { + ret = cx18_dvb_register(s); + if (ret < 0) { + CX18_ERR("DVB failed to register\n"); + return ret; + } + } + + if (s->video_dev == NULL) + return 0; + + num = s->video_dev->num; + /* card number + user defined offset + device offset */ + if (type != CX18_ENC_STREAM_TYPE_MPG) { + struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; + + if (s_mpg->video_dev) + num = s_mpg->video_dev->num + + cx18_stream_info[type].num_offset; + } + video_set_drvdata(s->video_dev, s); + + /* Register device. First try the desired minor, then any free one. */ + ret = video_register_device_no_warn(s->video_dev, vfl_type, num); + if (ret < 0) { + CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", + s->name, num); + video_device_release(s->video_dev); + s->video_dev = NULL; + return ret; + } + + name = video_device_node_name(s->video_dev); + + switch (vfl_type) { + case VFL_TYPE_GRABBER: + CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n", + name, s->name, cx->stream_buffers[type], + cx->stream_buf_size[type] / 1024, + (cx->stream_buf_size[type] * 100 / 1024) % 100); + break; + + case VFL_TYPE_RADIO: + CX18_INFO("Registered device %s for %s\n", name, s->name); + break; + + case VFL_TYPE_VBI: + if (cx->stream_buffers[type]) + CX18_INFO("Registered device %s for %s " + "(%d x %d bytes)\n", + name, s->name, cx->stream_buffers[type], + cx->stream_buf_size[type]); + else + CX18_INFO("Registered device %s for %s\n", + name, s->name); + break; + } + + return 0; +} + +/* Register v4l2 devices */ +int cx18_streams_register(struct cx18 *cx) +{ + int type; + int err; + int ret = 0; + + /* Register V4L2 devices */ + for (type = 0; type < CX18_MAX_STREAMS; type++) { + err = cx18_reg_dev(cx, type); + if (err && ret == 0) + ret = err; + } + + if (ret == 0) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + cx18_streams_cleanup(cx, 1); + return ret; +} + +/* Unregister v4l2 devices */ +void cx18_streams_cleanup(struct cx18 *cx, int unregister) +{ + struct video_device *vdev; + int type; + + /* Teardown all streams */ + for (type = 0; type < CX18_MAX_STREAMS; type++) { + + /* The TS has a cx18_dvb structure, not a video_device */ + if (type == CX18_ENC_STREAM_TYPE_TS) { + if (cx->streams[type].dvb != NULL) { + if (unregister) + cx18_dvb_unregister(&cx->streams[type]); + kfree(cx->streams[type].dvb); + cx->streams[type].dvb = NULL; + cx18_stream_free(&cx->streams[type]); + } + continue; + } + + /* No struct video_device, but can have buffers allocated */ + if (type == CX18_ENC_STREAM_TYPE_IDX) { + /* If the module params didn't inhibit IDX ... */ + if (cx->stream_buffers[type] != 0) { + cx->stream_buffers[type] = 0; + /* + * Before calling cx18_stream_free(), + * check if the IDX stream was actually set up. + * Needed, since the cx18_probe() error path + * exits through here as well as normal clean up + */ + if (cx->streams[type].buffers != 0) + cx18_stream_free(&cx->streams[type]); + } + continue; + } + + /* If struct video_device exists, can have buffers allocated */ + vdev = cx->streams[type].video_dev; + + cx->streams[type].video_dev = NULL; + if (vdev == NULL) + continue; + + if (type == CX18_ENC_STREAM_TYPE_YUV) + videobuf_mmap_free(&cx->streams[type].vbuf_q); + + cx18_stream_free(&cx->streams[type]); + + /* Unregister or release device */ + if (unregister) + video_unregister_device(vdev); + else + video_device_release(vdev); + } +} + +static void cx18_vbi_setup(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + int raw = cx18_raw_vbi(cx); + u32 data[CX2341X_MBOX_MAX_DATA]; + int lines; + + if (cx->is_60hz) { + cx->vbi.count = 12; + cx->vbi.start[0] = 10; + cx->vbi.start[1] = 273; + } else { /* PAL/SECAM */ + cx->vbi.count = 18; + cx->vbi.start[0] = 6; + cx->vbi.start[1] = 318; + } + + /* setup VBI registers */ + if (raw) + v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &cx->vbi.in.fmt.vbi); + else + v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &cx->vbi.in.fmt.sliced); + + /* + * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw + * VBI when the first analog capture channel starts, as once it starts + * (e.g. MPEG), we can't effect any change in the Encoder Raw VBI setup + * (i.e. for the VBI capture channels). We also send it for each + * analog capture channel anyway just to make sure we get the proper + * behavior + */ + if (raw) { + lines = cx->vbi.count * 2; + } else { + /* + * For 525/60 systems, according to the VIP 2 & BT.656 std: + * The EAV RP code's Field bit toggles on line 4, a few lines + * after the Vertcal Blank bit has already toggled. + * Tell the encoder to capture 21-4+1=18 lines per field, + * since we want lines 10 through 21. + * + * For 625/50 systems, according to the VIP 2 & BT.656 std: + * The EAV RP code's Field bit toggles on line 1, a few lines + * after the Vertcal Blank bit has already toggled. + * (We've actually set the digitizer so that the Field bit + * toggles on line 2.) Tell the encoder to capture 23-2+1=22 + * lines per field, since we want lines 6 through 23. + */ + lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2; + } + + data[0] = s->handle; + /* Lines per field */ + data[1] = (lines / 2) | ((lines / 2) << 16); + /* bytes per line */ + data[2] = (raw ? vbi_active_samples + : (cx->is_60hz ? vbi_hblank_samples_60Hz + : vbi_hblank_samples_50Hz)); + /* Every X number of frames a VBI interrupt arrives + (frames as in 25 or 30 fps) */ + data[3] = 1; + /* + * Set the SAV/EAV RP codes to look for as start/stop points + * when in VIP-1.1 mode + */ + if (raw) { + /* + * Start codes for beginning of "active" line in vertical blank + * 0x20 ( VerticalBlank ) + * 0x60 ( EvenField VerticalBlank ) + */ + data[4] = 0x20602060; + /* + * End codes for end of "active" raw lines and regular lines + * 0x30 ( VerticalBlank HorizontalBlank) + * 0x70 ( EvenField VerticalBlank HorizontalBlank) + * 0x90 (Task HorizontalBlank) + * 0xd0 (Task EvenField HorizontalBlank) + */ + data[5] = 0x307090d0; + } else { + /* + * End codes for active video, we want data in the hblank region + * 0xb0 (Task 0 VerticalBlank HorizontalBlank) + * 0xf0 (Task EvenField VerticalBlank HorizontalBlank) + * + * Since the V bit is only allowed to toggle in the EAV RP code, + * just before the first active region line, these two + * are problematic: + * 0x90 (Task HorizontalBlank) + * 0xd0 (Task EvenField HorizontalBlank) + * + * We have set the digitzer such that we don't have to worry + * about these problem codes. + */ + data[4] = 0xB0F0B0F0; + /* + * Start codes for beginning of active line in vertical blank + * 0xa0 (Task VerticalBlank ) + * 0xe0 (Task EvenField VerticalBlank ) + */ + data[5] = 0xA0E0A0E0; + } + + CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n", + data[0], data[1], data[2], data[3], data[4], data[5]); + + cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); +} + +void cx18_stream_rotate_idx_mdls(struct cx18 *cx) +{ + struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; + struct cx18_mdl *mdl; + + if (!cx18_stream_enabled(s)) + return; + + /* Return if the firmware is not running low on MDLs */ + if ((atomic_read(&s->q_free.depth) + atomic_read(&s->q_busy.depth)) >= + CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN) + return; + + /* Return if there are no MDLs to rotate back to the firmware */ + if (atomic_read(&s->q_full.depth) < 2) + return; + + /* + * Take the oldest IDX MDL still holding data, and discard its index + * entries by scheduling the MDL to go back to the firmware + */ + mdl = cx18_dequeue(s, &s->q_full); + if (mdl != NULL) + cx18_enqueue(s, mdl, &s->q_free); +} + +static +struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s, + struct cx18_mdl *mdl) +{ + struct cx18 *cx = s->cx; + struct cx18_queue *q; + + /* Don't give it to the firmware, if we're not running a capture */ + if (s->handle == CX18_INVALID_TASK_HANDLE || + test_bit(CX18_F_S_STOPPING, &s->s_flags) || + !test_bit(CX18_F_S_STREAMING, &s->s_flags)) + return cx18_enqueue(s, mdl, &s->q_free); + + q = cx18_enqueue(s, mdl, &s->q_busy); + if (q != &s->q_busy) + return q; /* The firmware has the max MDLs it can handle */ + + cx18_mdl_sync_for_device(s, mdl); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem, + s->bufs_per_mdl, mdl->id, s->mdl_size); + return q; +} + +static +void _cx18_stream_load_fw_queue(struct cx18_stream *s) +{ + struct cx18_queue *q; + struct cx18_mdl *mdl; + + if (atomic_read(&s->q_free.depth) == 0 || + atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM) + return; + + /* Move from q_free to q_busy notifying the firmware, until the limit */ + do { + mdl = cx18_dequeue(s, &s->q_free); + if (mdl == NULL) + break; + q = _cx18_stream_put_mdl_fw(s, mdl); + } while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM + && q == &s->q_busy); +} + +void cx18_out_work_handler(struct work_struct *work) +{ + struct cx18_stream *s = + container_of(work, struct cx18_stream, out_work_order); + + _cx18_stream_load_fw_queue(s); +} + +static void cx18_stream_configure_mdls(struct cx18_stream *s) +{ + cx18_unload_queues(s); + + switch (s->type) { + case CX18_ENC_STREAM_TYPE_YUV: + /* + * Height should be a multiple of 32 lines. + * Set the MDL size to the exact size needed for one frame. + * Use enough buffers per MDL to cover the MDL size + */ + if (s->pixelformat == V4L2_PIX_FMT_HM12) + s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; + else + s->mdl_size = 720 * s->cx->cxhdl.height * 2; + s->bufs_per_mdl = s->mdl_size / s->buf_size; + if (s->mdl_size % s->buf_size) + s->bufs_per_mdl++; + break; + case CX18_ENC_STREAM_TYPE_VBI: + s->bufs_per_mdl = 1; + if (cx18_raw_vbi(s->cx)) { + s->mdl_size = (s->cx->is_60hz ? 12 : 18) + * 2 * vbi_active_samples; + } else { + /* + * See comment in cx18_vbi_setup() below about the + * extra lines we capture in sliced VBI mode due to + * the lines on which EAV RP codes toggle. + */ + s->mdl_size = s->cx->is_60hz + ? (21 - 4 + 1) * 2 * vbi_hblank_samples_60Hz + : (23 - 2 + 1) * 2 * vbi_hblank_samples_50Hz; + } + break; + default: + s->bufs_per_mdl = 1; + s->mdl_size = s->buf_size * s->bufs_per_mdl; + break; + } + + cx18_load_queues(s); +} + +int cx18_start_v4l2_encode_stream(struct cx18_stream *s) +{ + u32 data[MAX_MB_ARGUMENTS]; + struct cx18 *cx = s->cx; + int captype = 0; + struct cx18_stream *s_idx; + + if (!cx18_stream_enabled(s)) + return -EINVAL; + + CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); + + switch (s->type) { + case CX18_ENC_STREAM_TYPE_MPG: + captype = CAPTURE_CHANNEL_TYPE_MPEG; + cx->mpg_data_received = cx->vbi_data_inserted = 0; + cx->dualwatch_jiffies = jiffies; + cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); + cx->search_pack_header = 0; + break; + + case CX18_ENC_STREAM_TYPE_IDX: + captype = CAPTURE_CHANNEL_TYPE_INDEX; + break; + case CX18_ENC_STREAM_TYPE_TS: + captype = CAPTURE_CHANNEL_TYPE_TS; + break; + case CX18_ENC_STREAM_TYPE_YUV: + captype = CAPTURE_CHANNEL_TYPE_YUV; + break; + case CX18_ENC_STREAM_TYPE_PCM: + captype = CAPTURE_CHANNEL_TYPE_PCM; + break; + case CX18_ENC_STREAM_TYPE_VBI: +#ifdef CX18_ENCODER_PARSES_SLICED + captype = cx18_raw_vbi(cx) ? + CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; +#else + /* + * Currently we set things up so that Sliced VBI from the + * digitizer is handled as Raw VBI by the encoder + */ + captype = CAPTURE_CHANNEL_TYPE_VBI; +#endif + cx->vbi.frame = 0; + cx->vbi.inserted_frame = 0; + memset(cx->vbi.sliced_mpeg_size, + 0, sizeof(cx->vbi.sliced_mpeg_size)); + break; + default: + return -EINVAL; + } + + /* Clear Streamoff flags in case left from last capture */ + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + + cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); + s->handle = data[0]; + cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); + + /* + * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and + * set up all the parameters, as it is not obvious which parameters the + * firmware shares across capture channel types and which it does not. + * + * Some of the cx18_vapi() calls below apply to only certain capture + * channel types. We're hoping there's no harm in calling most of them + * anyway, as long as the values are all consistent. Setting some + * shared parameters will have no effect once an analog capture channel + * has started streaming. + */ + if (captype != CAPTURE_CHANNEL_TYPE_TS) { + cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); + + /* + * Audio related reset according to + * Documentation/video4linux/cx2341x/fw-encoder-api.txt + */ + if (atomic_read(&cx->ana_capturing) == 0) + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, + s->handle, 12); + + /* + * Number of lines for Field 1 & Field 2 according to + * Documentation/video4linux/cx2341x/fw-encoder-api.txt + * Field 1 is 312 for 625 line systems in BT.656 + * Field 2 is 313 for 625 line systems in BT.656 + */ + cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, + s->handle, 312, 313); + + if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) + cx18_vbi_setup(s); + + /* + * Select to receive I, P, and B frame index entries, if the + * index stream is enabled. Otherwise disable index entry + * generation. + */ + s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; + cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2, + s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); + + /* Call out to the common CX2341x API setup for user controls */ + cx->cxhdl.priv = s; + cx2341x_handler_setup(&cx->cxhdl); + + /* + * When starting a capture and we're set for radio, + * ensure the video is muted, despite the user control. + */ + if (!cx->cxhdl.video_mute && + test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) + cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, + (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); + + /* Enable the Video Format Converter for UYVY 4:2:2 support, + * rather than the default HM12 Macroblovk 4:2:0 support. + */ + if (captype == CAPTURE_CHANNEL_TYPE_YUV) { + if (s->pixelformat == V4L2_PIX_FMT_UYVY) + cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, + s->handle, 1); + else + /* If in doubt, default to HM12 */ + cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, + s->handle, 0); + } + } + + if (atomic_read(&cx->tot_capturing) == 0) { + cx2341x_handler_set_busy(&cx->cxhdl, 1); + clear_bit(CX18_F_I_EOS, &cx->i_flags); + cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); + } + + cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, + (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, + (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); + + /* Init all the cpu_mdls for this stream */ + cx18_stream_configure_mdls(s); + _cx18_stream_load_fw_queue(s); + + /* begin_capture */ + if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { + CX18_DEBUG_WARN("Error starting capture!\n"); + /* Ensure we're really not capturing before releasing MDLs */ + set_bit(CX18_F_S_STOPPING, &s->s_flags); + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); + else + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + /* FIXME - CX18_F_S_STREAMOFF as well? */ + cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); + s->handle = CX18_INVALID_TASK_HANDLE; + clear_bit(CX18_F_S_STOPPING, &s->s_flags); + if (atomic_read(&cx->tot_capturing) == 0) { + set_bit(CX18_F_I_EOS, &cx->i_flags); + cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); + } + return -EINVAL; + } + + /* you're live! sit back and await interrupts :) */ + if (captype != CAPTURE_CHANNEL_TYPE_TS) + atomic_inc(&cx->ana_capturing); + atomic_inc(&cx->tot_capturing); + return 0; +} +EXPORT_SYMBOL(cx18_start_v4l2_encode_stream); + +void cx18_stop_all_captures(struct cx18 *cx) +{ + int i; + + for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) { + struct cx18_stream *s = &cx->streams[i]; + + if (!cx18_stream_enabled(s)) + continue; + if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) + cx18_stop_v4l2_encode_stream(s, 0); + } +} + +int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) +{ + struct cx18 *cx = s->cx; + unsigned long then; + + if (!cx18_stream_enabled(s)) + return -EINVAL; + + /* This function assumes that you are allowed to stop the capture + and that we are actually capturing */ + + CX18_DEBUG_INFO("Stop Capture\n"); + + if (atomic_read(&cx->tot_capturing) == 0) + return 0; + + set_bit(CX18_F_S_STOPPING, &s->s_flags); + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); + else + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); + + then = jiffies; + + if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) { + CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); + } + + if (s->type != CX18_ENC_STREAM_TYPE_TS) + atomic_dec(&cx->ana_capturing); + atomic_dec(&cx->tot_capturing); + + /* Clear capture and no-read bits */ + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + + /* Tell the CX23418 it can't use our buffers anymore */ + cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); + + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); + s->handle = CX18_INVALID_TASK_HANDLE; + clear_bit(CX18_F_S_STOPPING, &s->s_flags); + + if (atomic_read(&cx->tot_capturing) > 0) + return 0; + + cx2341x_handler_set_busy(&cx->cxhdl, 0); + cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); + wake_up(&s->waitq); + + return 0; +} +EXPORT_SYMBOL(cx18_stop_v4l2_encode_stream); + +u32 cx18_find_handle(struct cx18 *cx) +{ + int i; + + /* find first available handle to be used for global settings */ + for (i = 0; i < CX18_MAX_STREAMS; i++) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) + return s->handle; + } + return CX18_INVALID_TASK_HANDLE; +} + +struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle) +{ + int i; + struct cx18_stream *s; + + if (handle == CX18_INVALID_TASK_HANDLE) + return NULL; + + for (i = 0; i < CX18_MAX_STREAMS; i++) { + s = &cx->streams[i]; + if (s->handle != handle) + continue; + if (cx18_stream_enabled(s)) + return s; + } + return NULL; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-streams.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-streams.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-streams.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-streams.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,62 @@ +/* + * cx18 init/start/stop/exit stream functions + * + * Derived from ivtv-streams.h + * + * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +u32 cx18_find_handle(struct cx18 *cx); +struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle); +int cx18_streams_setup(struct cx18 *cx); +int cx18_streams_register(struct cx18 *cx); +void cx18_streams_cleanup(struct cx18 *cx, int unregister); + +#define CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN (3) +void cx18_stream_rotate_idx_mdls(struct cx18 *cx); + +static inline bool cx18_stream_enabled(struct cx18_stream *s) +{ + return s->video_dev || + (s->dvb && s->dvb->enabled) || + (s->type == CX18_ENC_STREAM_TYPE_IDX && + s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0); +} + +/* Related to submission of mdls to firmware */ +static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) +{ + schedule_work(&s->out_work_order); +} + +static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s, + struct cx18_mdl *mdl) +{ + /* Put mdl on q_free; the out work handler will move mdl(s) to q_busy */ + cx18_enqueue(s, mdl, &s->q_free); + cx18_stream_load_fw_queue(s); +} + +void cx18_out_work_handler(struct work_struct *work); + +/* Capture related */ +int cx18_start_v4l2_encode_stream(struct cx18_stream *s); +int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); + +void cx18_stop_all_captures(struct cx18 *cx); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-vbi.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,277 @@ +/* + * cx18 Vertical Blank Interval support functions + * + * Derived from ivtv-vbi.c + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-vbi.h" +#include "cx18-ioctl.h" +#include "cx18-queue.h" + +/* + * Raster Reference/Protection (RP) bytes, used in Start/End Active + * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start + * of VBI sample or VBI ancillary data regions in the digitial ratser line. + * + * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0 + */ +static const u8 raw_vbi_sav_rp[2] = { 0x20, 0x60 }; /* __V_, _FV_ */ +static const u8 sliced_vbi_eav_rp[2] = { 0xb0, 0xf0 }; /* T_VH, TFVH */ + +static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) +{ + int line = 0; + int i; + u32 linemask[2] = { 0, 0 }; + unsigned short size; + static const u8 mpeg_hdr_data[] = { + /* MPEG-2 Program Pack */ + 0x00, 0x00, 0x01, 0xba, /* Prog Pack start code */ + 0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */ + 0x01, 0xd1, 0xd3, /* Mux Rate, markers */ + 0xfa, 0xff, 0xff, /* Res, Suff cnt, Stuff */ + /* MPEG-2 Private Stream 1 PES Packet */ + 0x00, 0x00, 0x01, 0xbd, /* Priv Stream 1 start */ + 0x00, 0x1a, /* length */ + 0x84, 0x80, 0x07, /* flags, hdr data len */ + 0x21, 0x00, 0x5d, 0x63, 0xa7, /* PTS, markers */ + 0xff, 0xff /* stuffing */ + }; + const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ + int idx = cx->vbi.frame % CX18_VBI_FRAMES; + u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0]; + + for (i = 0; i < lines; i++) { + struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i; + int f, l; + + if (sdata->id == 0) + continue; + + l = sdata->line - 6; + f = sdata->field; + if (f) + l += 18; + if (l < 32) + linemask[0] |= (1 << l); + else + linemask[1] |= (1 << (l - 32)); + dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id); + memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42); + line++; + } + memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); + if (line == 36) { + /* All lines are used, so there is no space for the linemask + (the max size of the VBI data is 36 * 43 + 4 bytes). + So in this case we use the magic number 'ITV0'. */ + memcpy(dst + sd, "ITV0", 4); + memcpy(dst + sd + 4, dst + sd + 12, line * 43); + size = 4 + ((43 * line + 3) & ~3); + } else { + memcpy(dst + sd, "itv0", 4); + cpu_to_le32s(&linemask[0]); + cpu_to_le32s(&linemask[1]); + memcpy(dst + sd + 4, &linemask[0], 8); + size = 12 + ((43 * line + 3) & ~3); + } + dst[4+16] = (size + 10) >> 8; + dst[5+16] = (size + 10) & 0xff; + dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); + dst[10+16] = (pts_stamp >> 22) & 0xff; + dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); + dst[12+16] = (pts_stamp >> 7) & 0xff; + dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); + cx->vbi.sliced_mpeg_size[idx] = sd + size; +} + +/* Compress raw VBI format, removes leading SAV codes and surplus space + after the frame. Returns new compressed size. */ +/* FIXME - this function ignores the input size. */ +static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size) +{ + u32 line_size = vbi_active_samples; + u32 lines = cx->vbi.count * 2; + u8 *q = buf; + u8 *p; + int i; + + /* Skip the header */ + buf += hdr_size; + + for (i = 0; i < lines; i++) { + p = buf + i * line_size; + + /* Look for SAV code */ + if (p[0] != 0xff || p[1] || p[2] || + (p[3] != raw_vbi_sav_rp[0] && + p[3] != raw_vbi_sav_rp[1])) + break; + if (i == lines - 1) { + /* last line is hdr_size bytes short - extrapolate it */ + memcpy(q, p + 4, line_size - 4 - hdr_size); + q += line_size - 4 - hdr_size; + p += line_size - hdr_size - 1; + memset(q, (int) *p, hdr_size); + } else { + memcpy(q, p + 4, line_size - 4); + q += line_size - 4; + } + } + return lines * (line_size - 4); +} + +static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size, + const u32 hdr_size) +{ + struct v4l2_decode_vbi_line vbi; + int i; + u32 line = 0; + u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz + : vbi_hblank_samples_50Hz; + + /* find the first valid line */ + for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) { + if (buf[0] == 0xff && !buf[1] && !buf[2] && + (buf[3] == sliced_vbi_eav_rp[0] || + buf[3] == sliced_vbi_eav_rp[1])) + break; + } + + /* + * The last line is short by hdr_size bytes, but for the remaining + * checks against size, we pretend that it is not, by counting the + * header bytes we knowingly skipped + */ + size -= (i - hdr_size); + if (size < line_size) + return line; + + for (i = 0; i < size / line_size; i++) { + u8 *p = buf + i * line_size; + + /* Look for EAV code */ + if (p[0] != 0xff || p[1] || p[2] || + (p[3] != sliced_vbi_eav_rp[0] && + p[3] != sliced_vbi_eav_rp[1])) + continue; + vbi.p = p + 4; + v4l2_subdev_call(cx->sd_av, vbi, decode_vbi_line, &vbi); + if (vbi.type) { + cx->vbi.sliced_data[line].id = vbi.type; + cx->vbi.sliced_data[line].field = vbi.is_second_field; + cx->vbi.sliced_data[line].line = vbi.line; + memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42); + line++; + } + } + return line; +} + +static void _cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf) +{ + /* + * The CX23418 provides a 12 byte header in its raw VBI buffers to us: + * 0x3fffffff [4 bytes of something] [4 byte presentation time stamp] + */ + struct vbi_data_hdr { + __be32 magic; + __be32 unknown; + __be32 pts; + } *hdr = (struct vbi_data_hdr *) buf->buf; + + u8 *p = (u8 *) buf->buf; + u32 size = buf->bytesused; + u32 pts; + int lines; + + /* + * The CX23418 sends us data that is 32 bit little-endian swapped, + * but we want the raw VBI bytes in the order they were in the raster + * line. This has a side effect of making the header big endian + */ + cx18_buf_swap(buf); + + /* Raw VBI data */ + if (cx18_raw_vbi(cx)) { + + size = buf->bytesused = + compress_raw_buf(cx, p, size, sizeof(struct vbi_data_hdr)); + + /* + * Hack needed for compatibility with old VBI software. + * Write the frame # at the last 4 bytes of the frame + */ + p += size - 4; + memcpy(p, &cx->vbi.frame, 4); + cx->vbi.frame++; + return; + } + + /* Sliced VBI data with data insertion */ + + pts = (be32_to_cpu(hdr->magic) == 0x3fffffff) ? be32_to_cpu(hdr->pts) + : 0; + + lines = compress_sliced_buf(cx, p, size, sizeof(struct vbi_data_hdr)); + + /* always return at least one empty line */ + if (lines == 0) { + cx->vbi.sliced_data[0].id = 0; + cx->vbi.sliced_data[0].line = 0; + cx->vbi.sliced_data[0].field = 0; + lines = 1; + } + buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]); + memcpy(p, &cx->vbi.sliced_data[0], size); + + if (cx->vbi.insert_mpeg) + copy_vbi_data(cx, lines, pts); + cx->vbi.frame++; +} + +void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, + int streamtype) +{ + struct cx18_buffer *buf; + u32 orig_used; + + if (streamtype != CX18_ENC_STREAM_TYPE_VBI) + return; + + /* + * Big assumption here: + * Every buffer hooked to the MDL's buf_list is a complete VBI frame + * that ends at the end of the buffer. + * + * To assume anything else would make the code in this file + * more complex, or require extra memcpy()'s to make the + * buffers satisfy the above assumption. It's just simpler to set + * up the encoder buffer transfers to make the assumption true. + */ + list_for_each_entry(buf, &mdl->buf_list, list) { + orig_used = buf->bytesused; + if (orig_used == 0) + break; + _cx18_process_vbi_data(cx, buf); + mdl->bytesused -= (orig_used - buf->bytesused); + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-vbi.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-vbi.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-vbi.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-vbi.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * cx18 Vertical Blank Interval support functions + * + * Derived from ivtv-vbi.h + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, + int streamtype); +int cx18_used_line(struct cx18 *cx, int line, int field); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-version.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-version.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-version.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-version.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * cx18 driver version information + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#ifndef CX18_VERSION_H +#define CX18_VERSION_H + +#define CX18_DRIVER_NAME "cx18" +#define CX18_DRIVER_VERSION_MAJOR 1 +#define CX18_DRIVER_VERSION_MINOR 5 +#define CX18_DRIVER_VERSION_PATCHLEVEL 0 + +#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) +#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ + CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-video.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-video.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * cx18 video interface functions + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 "cx18-driver.h" +#include "cx18-video.h" +#include "cx18-cards.h" + +void cx18_video_set_io(struct cx18 *cx) +{ + int inp = cx->active_input; + + v4l2_subdev_call(cx->sd_av, video, s_routing, + cx->card->video_inputs[inp].video_input, 0, 0); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-video.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-video.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-video.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx18-video.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,22 @@ +/* + * cx18 video interface functions + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +void cx18_video_set_io(struct cx18 *cx); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx23418.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx23418.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx23418.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/cx23418.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,492 @@ +/* + * cx18 header containing common defines. + * + * Copyright (C) 2007 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#ifndef CX23418_H +#define CX23418_H + +#include + +#define MGR_CMD_MASK 0x40000000 +/* The MSB of the command code indicates that this is the completion of a + command */ +#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000) + +/* Description: This command creates a new instance of a certain task + IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is + the processor on which the task YYY will be created + OUT[0] - Task handle. This handle is passed along with commands to + dispatch to the right instance of the task + ReturnCode - One of the ERR_SYS_... */ +#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001) + +/* Description: This command destroys an instance of a task + IN[0] - Task handle. Hanlde of the task to destroy + ReturnCode - One of the ERR_SYS_... */ +#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002) + +/* All commands for CPU have the following mask set */ +#define CPU_CMD_MASK 0x20000000 +#define CPU_CMD_MASK_DEBUG (CPU_CMD_MASK | 0x00000000) +#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000) +#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000) +#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000) + +#define EPU_CMD_MASK 0x02000000 +#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000) +#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000) + +#define APU_CMD_MASK 0x10000000 +#define APU_CMD_MASK_ACK (APU_CMD_MASK | 0x80000000) + +#define CX18_APU_ENCODING_METHOD_MPEG (0 << 28) +#define CX18_APU_ENCODING_METHOD_AC3 (1 << 28) + +/* Description: Command APU to start audio + IN[0] - audio parameters (same as CX18_CPU_SET_AUDIO_PARAMETERS?) + IN[1] - caller buffer address, or 0 + ReturnCode - ??? */ +#define CX18_APU_START (APU_CMD_MASK | 0x01) + +/* Description: Command APU to stop audio + IN[0] - encoding method to stop + ReturnCode - ??? */ +#define CX18_APU_STOP (APU_CMD_MASK | 0x02) + +/* Description: Command APU to reset the AI + ReturnCode - ??? */ +#define CX18_APU_RESETAI (APU_CMD_MASK | 0x05) + +/* Description: This command indicates that a Memory Descriptor List has been + filled with the requested channel type + IN[0] - Task handle. Handle of the task + IN[1] - Offset of the MDL_ACK from the beginning of the local DDR. + IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1] + ReturnCode - One of the ERR_DE_... */ +#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001) + +/* Something interesting happened + IN[0] - A value to log + IN[1] - An offset of a string in the MiniMe memory; + 0/zero/NULL means "I have nothing to say" */ +#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003) + +/* Reads memory/registers (32-bit) + IN[0] - Address + OUT[1] - Value */ +#define CX18_CPU_DEBUG_PEEK32 (CPU_CMD_MASK_DEBUG | 0x0003) + +/* Description: This command starts streaming with the set channel type + IN[0] - Task handle. Handle of the task to start + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002) + +/* Description: This command stops streaming with the set channel type + IN[0] - Task handle. Handle of the task to stop + IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only) + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003) + +/* Description: This command pauses streaming with the set channel type + IN[0] - Task handle. Handle of the task to pause + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007) + +/* Description: This command resumes streaming with the set channel type + IN[0] - Task handle. Handle of the task to resume + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008) + +#define CAPTURE_CHANNEL_TYPE_NONE 0 +#define CAPTURE_CHANNEL_TYPE_MPEG 1 +#define CAPTURE_CHANNEL_TYPE_INDEX 2 +#define CAPTURE_CHANNEL_TYPE_YUV 3 +#define CAPTURE_CHANNEL_TYPE_PCM 4 +#define CAPTURE_CHANNEL_TYPE_VBI 5 +#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6 +#define CAPTURE_CHANNEL_TYPE_TS 7 +#define CAPTURE_CHANNEL_TYPE_MAX 15 + +/* Description: This command sets the channel type. This can only be done + when stopped. + IN[0] - Task handle. Handle of the task to start + IN[1] - Channel Type. See Below. + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1) + +/* Description: Set stream output type + IN[0] - task handle. Handle of the task to start + IN[1] - type + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012) + +/* Description: Set video input resolution and frame rate + IN[0] - task handle + IN[1] - reserved + IN[2] - reserved + IN[3] - reserved + IN[4] - reserved + IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004) + +/* Description: Set video frame rate + IN[0] - task handle. Handle of the task to start + IN[1] - video bit rate mode + IN[2] - video average rate + IN[3] - video peak rate + IN[4] - system mux rate + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005) + +/* Description: Set video output resolution + IN[0] - task handle + IN[1] - horizontal size + IN[2] - vertical size + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006) + +/* Description: This command set filter parameters + IN[0] - Task handle. Handle of the task + IN[1] - type, 0 - temporal, 1 - spatial, 2 - median + IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic + median: 0 = disable, 1 = horizontal, 2 = vertical, + 3 = horizontal/vertical, 4 = diagonal + IN[3] - strength, temporal 0 - 31, spatial 0 - 15 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009) + +/* Description: This command set spatial filter type + IN[0] - Task handle. + IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only, + 3 = 2D H/V separable, 4 = 2D symmetric non-separable + IN[2] - chroma type: 0 - disable, 1 = 1D horizontal + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C) + +/* Description: This command set coring levels for median filter + IN[0] - Task handle. + IN[1] - luma_high + IN[2] - luma_low + IN[3] - chroma_high + IN[4] - chroma_low + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E) + +/* Description: This command set the picture type mask for index file + IN[0] - Task handle (ignored by firmware) + IN[1] - 0 = disable index file output + 1 = output I picture + 2 = P picture + 4 = B picture + other = illegal */ +#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010) + +/* Description: Set audio parameters + IN[0] - task handle. Handle of the task to start + IN[1] - audio parameter + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011) + +/* Description: Set video mute + IN[0] - task handle. Handle of the task to start + IN[1] - bit31-24: muteYvalue + bit23-16: muteUvalue + bit15-8: muteVvalue + bit0: 1:mute, 0: unmute + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013) + +/* Description: Set audio mute + IN[0] - task handle. Handle of the task to start + IN[1] - mute/unmute + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014) + +/* Description: Set stream output type + IN[0] - task handle. Handle of the task to start + IN[1] - subType + SET_INITIAL_SCR 1 + SET_QUALITY_MODE 2 + SET_VIM_PROTECT_MODE 3 + SET_PTS_CORRECTION 4 + SET_USB_FLUSH_MODE 5 + SET_MERAQPAR_ENABLE 6 + SET_NAV_PACK_INSERTION 7 + SET_SCENE_CHANGE_ENABLE 8 + IN[2] - parameter 1 + IN[3] - parameter 2 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015) + +/* Description: Set raw VBI parameters + IN[0] - Task handle + IN[1] - No. of input lines per field: + bit[15:0]: field 1, + bit[31:16]: field 2 + IN[2] - No. of input bytes per line + IN[3] - No. of output frames per transfer + IN[4] - start code + IN[5] - stop code + ReturnCode */ +#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016) + +/* Description: Set capture line No. + IN[0] - task handle. Handle of the task to start + IN[1] - height1 + IN[2] - height2 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017) + +/* Description: Set copyright + IN[0] - task handle. Handle of the task to start + IN[1] - copyright + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018) + +/* Description: Set audio PID + IN[0] - task handle. Handle of the task to start + IN[1] - PID + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019) + +/* Description: Set video PID + IN[0] - task handle. Handle of the task to start + IN[1] - PID + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A) + +/* Description: Set Vertical Crop Line + IN[0] - task handle. Handle of the task to start + IN[1] - Line + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B) + +/* Description: Set COP structure + IN[0] - task handle. Handle of the task to start + IN[1] - M + IN[2] - N + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C) + +/* Description: Set Scene Change Detection + IN[0] - task handle. Handle of the task to start + IN[1] - scene change + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D) + +/* Description: Set Aspect Ratio + IN[0] - task handle. Handle of the task to start + IN[1] - AspectRatio + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E) + +/* Description: Set Skip Input Frame + IN[0] - task handle. Handle of the task to start + IN[1] - skip input frames + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F) + +/* Description: Set sliced VBI parameters - + Note This API will only apply to MPEG and Sliced VBI Channels + IN[0] - Task handle + IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext + IN[2] - start / stop line + bit[15:0] start line number + bit[31:16] stop line number + IN[3] - number of output frames per interrupt + IN[4] - VBI insertion mode + bit 0: output user data, 1 - enable + bit 1: output private stream, 1 - enable + bit 2: mux option, 0 - in GOP, 1 - in picture + bit[7:0] private stream ID + IN[5] - insertion period while mux option is in picture + ReturnCode - VBI data offset */ +#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020) + +/* Description: Set the user data place holder + IN[0] - type of data (0 for user) + IN[1] - Stuffing period + IN[2] - ID data size in word (less than 10) + IN[3] - Pointer to ID buffer */ +#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021) + + +/* Description: + In[0] Task Handle + return parameter: + Out[0] Reserved + Out[1] Video PTS bit[32:2] of last output video frame. + Out[2] Video PTS bit[ 1:0] of last output video frame. + Out[3] Hardware Video PTS counter bit[31:0], + these bits get incremented on every 90kHz clock tick. + Out[4] Hardware Video PTS counter bit32, + these bits get incremented on every 90kHz clock tick. + ReturnCode */ +#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) + +/* Description: Set VFC parameters + IN[0] - task handle + IN[1] - VFC enable flag, 1 - enable, 0 - disable +*/ +#define CX18_CPU_SET_VFC_PARAM (CPU_CMD_MASK_CAPTURE | 0x0023) + +/* Below is the list of commands related to the data exchange */ +#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) + +/* Description: This command provides the physical base address of the local + DDR as viewed by EPU + IN[0] - Physical offset where EPU has the local DDR mapped + ReturnCode - One of the ERR_DE_... */ +#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001) + +/* Description: This command provides the offsets in the device memory where + the 2 cx18_mdl_ack blocks reside + IN[0] - Task handle. Handle of the task to start + IN[1] - Offset of the first cx18_mdl_ack from the beginning of the + local DDR. + IN[2] - Offset of the second cx18_mdl_ack from the beginning of the + local DDR. + ReturnCode - One of the ERR_DE_... */ +#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002) + +/* Description: This command provides the offset to a Memory Descriptor List + IN[0] - Task handle. Handle of the task to start + IN[1] - Offset of the MDL from the beginning of the local DDR. + IN[2] - Number of cx18_mdl_ent structures in the array pointed to by IN[1] + IN[3] - Buffer ID + IN[4] - Total buffer length + ReturnCode - One of the ERR_DE_... */ +#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005) + +/* Description: This command requests return of all current Memory + Descriptor Lists to the driver + IN[0] - Task handle. Handle of the task to start + ReturnCode - One of the ERR_DE_... */ +#define CX18_CPU_DE_RELEASE_MDL (CPU_CMD_MASK_DE | 0x0006) + +/* Description: This command signals the cpu that the dat buffer has been + consumed and ready for re-use. + IN[0] - Task handle. Handle of the task + IN[1] - Offset of the data block from the beginning of the local DDR. + IN[2] - Number of bytes in the data block + ReturnCode - One of the ERR_DE_... */ +/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */ + +/* No Error / Success */ +#define CNXT_OK 0x000000 + +/* Received unknown command */ +#define CXERR_UNK_CMD 0x000001 + +/* First parameter in the command is invalid */ +#define CXERR_INVALID_PARAM1 0x000002 + +/* Second parameter in the command is invalid */ +#define CXERR_INVALID_PARAM2 0x000003 + +/* Device interface is not open/found */ +#define CXERR_DEV_NOT_FOUND 0x000004 + +/* Requested function is not implemented/available */ +#define CXERR_NOTSUPPORTED 0x000005 + +/* Invalid pointer is provided */ +#define CXERR_BADPTR 0x000006 + +/* Unable to allocate memory */ +#define CXERR_NOMEM 0x000007 + +/* Object/Link not found */ +#define CXERR_LINK 0x000008 + +/* Device busy, command cannot be executed */ +#define CXERR_BUSY 0x000009 + +/* File/device/handle is not open. */ +#define CXERR_NOT_OPEN 0x00000A + +/* Value is out of range */ +#define CXERR_OUTOFRANGE 0x00000B + +/* Buffer overflow */ +#define CXERR_OVERFLOW 0x00000C + +/* Version mismatch */ +#define CXERR_BADVER 0x00000D + +/* Operation timed out */ +#define CXERR_TIMEOUT 0x00000E + +/* Operation aborted */ +#define CXERR_ABORT 0x00000F + +/* Specified I2C device not found for read/write */ +#define CXERR_I2CDEV_NOTFOUND 0x000010 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_XFERERR 0x000011 + +/* Chanel changing component not ready */ +#define CXERR_CHANNELNOTREADY 0x000012 + +/* PPU (Presensation/Decoder) mail box is corrupted */ +#define CXERR_PPU_MB_CORRUPT 0x000013 + +/* CPU (Capture/Encoder) mail box is corrupted */ +#define CXERR_CPU_MB_CORRUPT 0x000014 + +/* APU (Audio) mail box is corrupted */ +#define CXERR_APU_MB_CORRUPT 0x000015 + +/* Unable to open file for reading */ +#define CXERR_FILE_OPEN_READ 0x000016 + +/* Unable to open file for writing */ +#define CXERR_FILE_OPEN_WRITE 0x000017 + +/* Unable to find the I2C section specified */ +#define CXERR_I2C_BADSECTION 0x000018 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_DATALOW 0x000019 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_CLOCKLOW 0x00001A + +/* No Interrupt received from HW (for I2C access) */ +#define CXERR_NO_HW_I2C_INTR 0x00001B + +/* RPU is not ready to accept commands! */ +#define CXERR_RPU_NOT_READY 0x00001C + +/* RPU is not ready to accept commands! */ +#define CXERR_RPU_NO_ACK 0x00001D + +/* The are no buffers ready. Try again soon! */ +#define CXERR_NODATA_AGAIN 0x00001E + +/* The stream is stopping. Function not allowed now! */ +#define CXERR_STOPPING_STATUS 0x00001F + +/* Trying to access hardware when the power is turned OFF */ +#define CXERR_DEVPOWER_OFF 0x000020 + +#endif /* CX23418_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,35 @@ +config VIDEO_CX18 + tristate "Conexant cx23418 MPEG encoder support" + depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL + select I2C_ALGOBIT + select VIDEOBUF_VMALLOC + depends on RC_CORE + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_CX2341X + select VIDEO_CS5345 + select DVB_S5H1409 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + select DVB_S5H1411 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE + ---help--- + This is a video4linux driver for Conexant cx23418 based + PCI combo video recorder devices. + + This is used in devices such as the Hauppauge HVR-1600 + cards. + + To compile this driver as a module, choose M here: the + module will be called cx18. + +config VIDEO_CX18_ALSA + tristate "Conexant 23418 DMA audio support" + depends on VIDEO_CX18 && SND && EXPERIMENTAL + select SND_PCM + ---help--- + This is a video4linux driver for direct (DMA) audio on + Conexant 23418 based TV cards using ALSA. + + To compile this driver as a module, choose M here: the + module will be called cx18-alsa. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx18/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,13 @@ +cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \ + cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \ + cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \ + cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \ + cx18-dvb.o cx18-io.o +cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o + +obj-$(CONFIG_VIDEO_CX18) += cx18.o +obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-417.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-417.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-417.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-417.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2192 @@ +/* + * + * Support for a cx23417 mpeg encoder via cx231xx host port. + * + * (c) 2004 Jelle Foks + * (c) 2004 Gerd Knorr + * (c) 2008 Steven Toth + * - CX23885/7/8 support + * + * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx231xx.h" +/*#include "cx23885-ioctl.h"*/ + +#define CX231xx_FIRM_IMAGE_SIZE 376836 +#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" + +/* for polaris ITVC */ +#define ITVC_WRITE_DIR 0x03FDFC00 +#define ITVC_READ_DIR 0x0001FC00 + +#define MCI_MEMORY_DATA_BYTE0 0x00 +#define MCI_MEMORY_DATA_BYTE1 0x08 +#define MCI_MEMORY_DATA_BYTE2 0x10 +#define MCI_MEMORY_DATA_BYTE3 0x18 + +#define MCI_MEMORY_ADDRESS_BYTE2 0x20 +#define MCI_MEMORY_ADDRESS_BYTE1 0x28 +#define MCI_MEMORY_ADDRESS_BYTE0 0x30 + +#define MCI_REGISTER_DATA_BYTE0 0x40 +#define MCI_REGISTER_DATA_BYTE1 0x48 +#define MCI_REGISTER_DATA_BYTE2 0x50 +#define MCI_REGISTER_DATA_BYTE3 0x58 + +#define MCI_REGISTER_ADDRESS_BYTE0 0x60 +#define MCI_REGISTER_ADDRESS_BYTE1 0x68 + +#define MCI_REGISTER_MODE 0x70 + +/* Read and write modes for polaris ITVC */ +#define MCI_MODE_REGISTER_READ 0x000 +#define MCI_MODE_REGISTER_WRITE 0x100 +#define MCI_MODE_MEMORY_READ 0x000 +#define MCI_MODE_MEMORY_WRITE 0x4000 + +static unsigned int mpegbufs = 8; +module_param(mpegbufs, int, 0644); +MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32"); +static unsigned int mpeglines = 128; +module_param(mpeglines, int, 0644); +MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32"); +static unsigned int mpeglinesize = 512; +module_param(mpeglinesize, int, 0644); +MODULE_PARM_DESC(mpeglinesize, + "number of bytes in each line of an MPEG buffer, range 512-1024"); + +static unsigned int v4l_debug = 1; +module_param(v4l_debug, int, 0644); +MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages"); +struct cx231xx_dmaqueue *dma_qq; +#define dprintk(level, fmt, arg...)\ + do { if (v4l_debug >= level) \ + printk(KERN_INFO "%s: " fmt, \ + (dev) ? dev->name : "cx231xx[?]", ## arg); \ + } while (0) + +static struct cx231xx_tvnorm cx231xx_tvnorms[] = { + { + .name = "NTSC-M", + .id = V4L2_STD_NTSC_M, + }, { + .name = "NTSC-JP", + .id = V4L2_STD_NTSC_M_JP, + }, { + .name = "PAL-BG", + .id = V4L2_STD_PAL_BG, + }, { + .name = "PAL-DK", + .id = V4L2_STD_PAL_DK, + }, { + .name = "PAL-I", + .id = V4L2_STD_PAL_I, + }, { + .name = "PAL-M", + .id = V4L2_STD_PAL_M, + }, { + .name = "PAL-N", + .id = V4L2_STD_PAL_N, + }, { + .name = "PAL-Nc", + .id = V4L2_STD_PAL_Nc, + }, { + .name = "PAL-60", + .id = V4L2_STD_PAL_60, + }, { + .name = "SECAM-L", + .id = V4L2_STD_SECAM_L, + }, { + .name = "SECAM-DK", + .id = V4L2_STD_SECAM_DK, + } +}; + +/* ------------------------------------------------------------------ */ +enum cx231xx_capture_type { + CX231xx_MPEG_CAPTURE, + CX231xx_RAW_CAPTURE, + CX231xx_RAW_PASSTHRU_CAPTURE +}; +enum cx231xx_capture_bits { + CX231xx_RAW_BITS_NONE = 0x00, + CX231xx_RAW_BITS_YUV_CAPTURE = 0x01, + CX231xx_RAW_BITS_PCM_CAPTURE = 0x02, + CX231xx_RAW_BITS_VBI_CAPTURE = 0x04, + CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08, + CX231xx_RAW_BITS_TO_HOST_CAPTURE = 0x10 +}; +enum cx231xx_capture_end { + CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */ + CX231xx_END_NOW, /* stop immediately, no irq */ +}; +enum cx231xx_framerate { + CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */ + CX231xx_FRAMERATE_PAL_25 /* PAL: 25fps */ +}; +enum cx231xx_stream_port { + CX231xx_OUTPUT_PORT_MEMORY, + CX231xx_OUTPUT_PORT_STREAMING, + CX231xx_OUTPUT_PORT_SERIAL +}; +enum cx231xx_data_xfer_status { + CX231xx_MORE_BUFFERS_FOLLOW, + CX231xx_LAST_BUFFER, +}; +enum cx231xx_picture_mask { + CX231xx_PICTURE_MASK_NONE, + CX231xx_PICTURE_MASK_I_FRAMES, + CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3, + CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7, +}; +enum cx231xx_vbi_mode_bits { + CX231xx_VBI_BITS_SLICED, + CX231xx_VBI_BITS_RAW, +}; +enum cx231xx_vbi_insertion_bits { + CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, + CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, + CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1, + CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, + CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, +}; +enum cx231xx_dma_unit { + CX231xx_DMA_BYTES, + CX231xx_DMA_FRAMES, +}; +enum cx231xx_dma_transfer_status_bits { + CX231xx_DMA_TRANSFER_BITS_DONE = 0x01, + CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04, + CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10, +}; +enum cx231xx_pause { + CX231xx_PAUSE_ENCODING, + CX231xx_RESUME_ENCODING, +}; +enum cx231xx_copyright { + CX231xx_COPYRIGHT_OFF, + CX231xx_COPYRIGHT_ON, +}; +enum cx231xx_notification_type { + CX231xx_NOTIFICATION_REFRESH, +}; +enum cx231xx_notification_status { + CX231xx_NOTIFICATION_OFF, + CX231xx_NOTIFICATION_ON, +}; +enum cx231xx_notification_mailbox { + CX231xx_NOTIFICATION_NO_MAILBOX = -1, +}; +enum cx231xx_field1_lines { + CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */ + CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */ + CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */ +}; +enum cx231xx_field2_lines { + CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */ + CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */ + CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */ +}; +enum cx231xx_custom_data_type { + CX231xx_CUSTOM_EXTENSION_USR_DATA, + CX231xx_CUSTOM_PRIVATE_PACKET, +}; +enum cx231xx_mute { + CX231xx_UNMUTE, + CX231xx_MUTE, +}; +enum cx231xx_mute_video_mask { + CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00, + CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000, + CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000, +}; +enum cx231xx_mute_video_shift { + CX231xx_MUTE_VIDEO_V_SHIFT = 8, + CX231xx_MUTE_VIDEO_U_SHIFT = 16, + CX231xx_MUTE_VIDEO_Y_SHIFT = 24, +}; + +/* defines below are from ivtv-driver.h */ +#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF + +/* Firmware API commands */ +#define IVTV_API_STD_TIMEOUT 500 + +/* Registers */ +/* IVTV_REG_OFFSET */ +#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) +#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) +#define IVTV_REG_SPU (0x9050) +#define IVTV_REG_HW_BLOCKS (0x9054) +#define IVTV_REG_VPU (0x9058) +#define IVTV_REG_APU (0xA064) + +/* + * Bit definitions for MC417_RWD and MC417_OEN registers + * + * bits 31-16 + *+-----------+ + *| Reserved | + *|+-----------+ + *| bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 + *|+-------+-------+-------+-------+-------+-------+-------+-------+ + *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0| + *|+-------+-------+-------+-------+-------+-------+-------+-------+ + *| bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 + *|+-------+-------+-------+-------+-------+-------+-------+-------+ + *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0| + *|+-------+-------+-------+-------+-------+-------+-------+-------+ + */ +#define MC417_MIWR 0x8000 +#define MC417_MIRD 0x4000 +#define MC417_MICS 0x2000 +#define MC417_MIRDY 0x1000 +#define MC417_MIADDR 0x0F00 +#define MC417_MIDATA 0x00FF + + +/* Bit definitions for MC417_CTL register **** + *bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0 + *+--------+-------------+--------+--------------+------------+ + *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN| + *+--------+-------------+--------+--------------+------------+ + */ +#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030) +#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006) +#define MC417_UART_GPIO_EN 0x00000001 + +/* Values for speed control */ +#define MC417_SPD_CTL_SLOW 0x1 +#define MC417_SPD_CTL_MEDIUM 0x0 +#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */ + +/* Values for GPIO select */ +#define MC417_GPIO_SEL_GPIO3 0x3 +#define MC417_GPIO_SEL_GPIO2 0x2 +#define MC417_GPIO_SEL_GPIO1 0x1 +#define MC417_GPIO_SEL_GPIO0 0x0 + + +#define CX23417_GPIO_MASK 0xFC0003FF +static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value) +{ + int status = 0; + u32 _gpio_direction = 0; + + _gpio_direction = _gpio_direction & CX23417_GPIO_MASK; + _gpio_direction = _gpio_direction|gpio_direction; + status = cx231xx_send_gpio_cmd(dev, _gpio_direction, + (u8 *)&value, 4, 0, 0); + return status; +} +static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue) +{ + int status = 0; + u32 _gpio_direction = 0; + + _gpio_direction = _gpio_direction & CX23417_GPIO_MASK; + _gpio_direction = _gpio_direction|gpio_direction; + + status = cx231xx_send_gpio_cmd(dev, _gpio_direction, + (u8 *)pValue, 4, 0, 1); + return status; +} + +static int waitForMciComplete(struct cx231xx *dev) +{ + u32 gpio; + u32 gpio_driection = 0; + u8 count = 0; + getITVCReg(dev, gpio_driection, &gpio); + + while (!(gpio&0x020000)) { + msleep(10); + + getITVCReg(dev, gpio_driection, &gpio); + + if (count++ > 100) { + dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio); + return -1; + } + } + return 0; +} + +static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value) +{ + u32 temp; + int status = 0; + + temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8); + temp = temp<<10; + status = setITVCReg(dev, ITVC_WRITE_DIR, temp); + if (status < 0) + return status; + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write data byte 1;*/ + temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write data byte 2;*/ + temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write data byte 3;*/ + temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write address byte 0;*/ + temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write address byte 1;*/ + temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*Write that the mode is write.*/ + temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE; + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + return waitForMciComplete(dev); +} + +static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value) +{ + /*write address byte 0;*/ + u32 temp; + u32 return_value = 0; + int ret = 0; + + temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8); + temp = temp << 10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp | ((0x05) << 10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write address byte 1;*/ + temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00); + temp = temp << 10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp | ((0x05) << 10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write that the mode is read;*/ + temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ; + temp = temp << 10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp | ((0x05) << 10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*wait for the MIRDY line to be asserted , + signalling that the read is done;*/ + ret = waitForMciComplete(dev); + + /*switch the DATA- GPIO to input mode;*/ + + /*Read data byte 0;*/ + temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10; + setITVCReg(dev, ITVC_READ_DIR, temp); + temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10); + setITVCReg(dev, ITVC_READ_DIR, temp); + getITVCReg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp & 0x03FC0000) >> 18); + setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); + + /* Read data byte 1;*/ + temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10; + setITVCReg(dev, ITVC_READ_DIR, temp); + temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10); + setITVCReg(dev, ITVC_READ_DIR, temp); + getITVCReg(dev, ITVC_READ_DIR, &temp); + + return_value |= ((temp & 0x03FC0000) >> 10); + setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); + + /*Read data byte 2;*/ + temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10; + setITVCReg(dev, ITVC_READ_DIR, temp); + temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10); + setITVCReg(dev, ITVC_READ_DIR, temp); + getITVCReg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp & 0x03FC0000) >> 2); + setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); + + /*Read data byte 3;*/ + temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10; + setITVCReg(dev, ITVC_READ_DIR, temp); + temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10); + setITVCReg(dev, ITVC_READ_DIR, temp); + getITVCReg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp & 0x03FC0000) << 6); + setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); + + *value = return_value; + + + return ret; +} + +static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value) +{ + /*write data byte 0;*/ + + u32 temp; + int ret = 0; + + temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8); + temp = temp << 10; + ret = setITVCReg(dev, ITVC_WRITE_DIR, temp); + if (ret < 0) + return ret; + temp = temp | ((0x05) << 10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write data byte 1;*/ + temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00); + temp = temp << 10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp | ((0x05) << 10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write data byte 2;*/ + temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write data byte 3;*/ + temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /* write address byte 2;*/ + temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE | + ((address & 0x003F0000)>>8); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /* write address byte 1;*/ + temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /* write address byte 0;*/ + temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*wait for MIRDY line;*/ + waitForMciComplete(dev); + + return 0; +} + +static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value) +{ + u32 temp = 0; + u32 return_value = 0; + int ret = 0; + + /*write address byte 2;*/ + temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ | + ((address & 0x003F0000)>>8); + temp = temp<<10; + ret = setITVCReg(dev, ITVC_WRITE_DIR, temp); + if (ret < 0) + return ret; + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write address byte 1*/ + temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*write address byte 0*/ + temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8); + temp = temp<<10; + setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp|((0x05)<<10); + setITVCReg(dev, ITVC_WRITE_DIR, temp); + + /*Wait for MIRDY line*/ + ret = waitForMciComplete(dev); + + + /*Read data byte 3;*/ + temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10; + setITVCReg(dev, ITVC_READ_DIR, temp); + temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10); + setITVCReg(dev, ITVC_READ_DIR, temp); + getITVCReg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp&0x03FC0000)<<6); + setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); + + /*Read data byte 2;*/ + temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10; + setITVCReg(dev, ITVC_READ_DIR, temp); + temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10); + setITVCReg(dev, ITVC_READ_DIR, temp); + getITVCReg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp&0x03FC0000)>>2); + setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); + + /* Read data byte 1;*/ + temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10; + setITVCReg(dev, ITVC_READ_DIR, temp); + temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10); + setITVCReg(dev, ITVC_READ_DIR, temp); + getITVCReg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp&0x03FC0000)>>10); + setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); + + /*Read data byte 0;*/ + temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10; + setITVCReg(dev, ITVC_READ_DIR, temp); + temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10); + setITVCReg(dev, ITVC_READ_DIR, temp); + getITVCReg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp&0x03FC0000)>>18); + setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); + + *value = return_value; + return ret; +} + +/* ------------------------------------------------------------------ */ + +/* MPEG encoder API */ +static char *cmd_to_str(int cmd) +{ + switch (cmd) { + case CX2341X_ENC_PING_FW: + return "PING_FW"; + case CX2341X_ENC_START_CAPTURE: + return "START_CAPTURE"; + case CX2341X_ENC_STOP_CAPTURE: + return "STOP_CAPTURE"; + case CX2341X_ENC_SET_AUDIO_ID: + return "SET_AUDIO_ID"; + case CX2341X_ENC_SET_VIDEO_ID: + return "SET_VIDEO_ID"; + case CX2341X_ENC_SET_PCR_ID: + return "SET_PCR_PID"; + case CX2341X_ENC_SET_FRAME_RATE: + return "SET_FRAME_RATE"; + case CX2341X_ENC_SET_FRAME_SIZE: + return "SET_FRAME_SIZE"; + case CX2341X_ENC_SET_BIT_RATE: + return "SET_BIT_RATE"; + case CX2341X_ENC_SET_GOP_PROPERTIES: + return "SET_GOP_PROPERTIES"; + case CX2341X_ENC_SET_ASPECT_RATIO: + return "SET_ASPECT_RATIO"; + case CX2341X_ENC_SET_DNR_FILTER_MODE: + return "SET_DNR_FILTER_PROPS"; + case CX2341X_ENC_SET_DNR_FILTER_PROPS: + return "SET_DNR_FILTER_PROPS"; + case CX2341X_ENC_SET_CORING_LEVELS: + return "SET_CORING_LEVELS"; + case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: + return "SET_SPATIAL_FILTER_TYPE"; + case CX2341X_ENC_SET_VBI_LINE: + return "SET_VBI_LINE"; + case CX2341X_ENC_SET_STREAM_TYPE: + return "SET_STREAM_TYPE"; + case CX2341X_ENC_SET_OUTPUT_PORT: + return "SET_OUTPUT_PORT"; + case CX2341X_ENC_SET_AUDIO_PROPERTIES: + return "SET_AUDIO_PROPERTIES"; + case CX2341X_ENC_HALT_FW: + return "HALT_FW"; + case CX2341X_ENC_GET_VERSION: + return "GET_VERSION"; + case CX2341X_ENC_SET_GOP_CLOSURE: + return "SET_GOP_CLOSURE"; + case CX2341X_ENC_GET_SEQ_END: + return "GET_SEQ_END"; + case CX2341X_ENC_SET_PGM_INDEX_INFO: + return "SET_PGM_INDEX_INFO"; + case CX2341X_ENC_SET_VBI_CONFIG: + return "SET_VBI_CONFIG"; + case CX2341X_ENC_SET_DMA_BLOCK_SIZE: + return "SET_DMA_BLOCK_SIZE"; + case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10: + return "GET_PREV_DMA_INFO_MB_10"; + case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9: + return "GET_PREV_DMA_INFO_MB_9"; + case CX2341X_ENC_SCHED_DMA_TO_HOST: + return "SCHED_DMA_TO_HOST"; + case CX2341X_ENC_INITIALIZE_INPUT: + return "INITIALIZE_INPUT"; + case CX2341X_ENC_SET_FRAME_DROP_RATE: + return "SET_FRAME_DROP_RATE"; + case CX2341X_ENC_PAUSE_ENCODER: + return "PAUSE_ENCODER"; + case CX2341X_ENC_REFRESH_INPUT: + return "REFRESH_INPUT"; + case CX2341X_ENC_SET_COPYRIGHT: + return "SET_COPYRIGHT"; + case CX2341X_ENC_SET_EVENT_NOTIFICATION: + return "SET_EVENT_NOTIFICATION"; + case CX2341X_ENC_SET_NUM_VSYNC_LINES: + return "SET_NUM_VSYNC_LINES"; + case CX2341X_ENC_SET_PLACEHOLDER: + return "SET_PLACEHOLDER"; + case CX2341X_ENC_MUTE_VIDEO: + return "MUTE_VIDEO"; + case CX2341X_ENC_MUTE_AUDIO: + return "MUTE_AUDIO"; + case CX2341X_ENC_MISC: + return "MISC"; + default: + return "UNKNOWN"; + } +} + +static int cx231xx_mbox_func(void *priv, + u32 command, + int in, + int out, + u32 data[CX2341X_MBOX_MAX_DATA]) +{ + struct cx231xx *dev = priv; + unsigned long timeout; + u32 value, flag, retval = 0; + int i; + + dprintk(3, "%s: command(0x%X) = %s\n", __func__, command, + cmd_to_str(command)); + + /* this may not be 100% safe if we can't read any memory location + without side effects */ + mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value); + if (value != 0x12345678) { + dprintk(3, + "Firmware and/or mailbox pointer not initialized " + "or corrupted, signature = 0x%x, cmd = %s\n", value, + cmd_to_str(command)); + return -1; + } + + /* This read looks at 32 bits, but flag is only 8 bits. + * Seems we also bail if CMD or TIMEOUT bytes are set??? + */ + mc417_memory_read(dev, dev->cx23417_mailbox, &flag); + if (flag) { + dprintk(3, "ERROR: Mailbox appears to be in use " + "(%x), cmd = %s\n", flag, cmd_to_str(command)); + return -1; + } + + flag |= 1; /* tell 'em we're working on it */ + mc417_memory_write(dev, dev->cx23417_mailbox, flag); + + /* write command + args + fill remaining with zeros */ + /* command code */ + mc417_memory_write(dev, dev->cx23417_mailbox + 1, command); + mc417_memory_write(dev, dev->cx23417_mailbox + 3, + IVTV_API_STD_TIMEOUT); /* timeout */ + for (i = 0; i < in; i++) { + mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]); + dprintk(3, "API Input %d = %d\n", i, data[i]); + } + for (; i < CX2341X_MBOX_MAX_DATA; i++) + mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0); + + flag |= 3; /* tell 'em we're done writing */ + mc417_memory_write(dev, dev->cx23417_mailbox, flag); + + /* wait for firmware to handle the API command */ + timeout = jiffies + msecs_to_jiffies(10); + for (;;) { + mc417_memory_read(dev, dev->cx23417_mailbox, &flag); + if (0 != (flag & 4)) + break; + if (time_after(jiffies, timeout)) { + dprintk(3, "ERROR: API Mailbox timeout\n"); + return -1; + } + udelay(10); + } + + /* read output values */ + for (i = 0; i < out; i++) { + mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i); + dprintk(3, "API Output %d = %d\n", i, data[i]); + } + + mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval); + dprintk(3, "API result = %d\n", retval); + + flag = 0; + mc417_memory_write(dev, dev->cx23417_mailbox, flag); + + return retval; +} + +/* We don't need to call the API often, so using just one + * mailbox will probably suffice + */ +static int cx231xx_api_cmd(struct cx231xx *dev, + u32 command, + u32 inputcnt, + u32 outputcnt, + ...) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + va_list vargs; + int i, err; + + dprintk(3, "%s() cmds = 0x%08x\n", __func__, command); + + va_start(vargs, outputcnt); + for (i = 0; i < inputcnt; i++) + data[i] = va_arg(vargs, int); + + err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data); + for (i = 0; i < outputcnt; i++) { + int *vptr = va_arg(vargs, int *); + *vptr = data[i]; + } + va_end(vargs); + + return err; +} + +static int cx231xx_find_mailbox(struct cx231xx *dev) +{ + u32 signature[4] = { + 0x12345678, 0x34567812, 0x56781234, 0x78123456 + }; + int signaturecnt = 0; + u32 value; + int i; + int ret = 0; + + dprintk(2, "%s()\n", __func__); + + for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/ + ret = mc417_memory_read(dev, i, &value); + if (ret < 0) + return ret; + if (value == signature[signaturecnt]) + signaturecnt++; + else + signaturecnt = 0; + if (4 == signaturecnt) { + dprintk(1, "Mailbox signature found at 0x%x\n", i+1); + return i+1; + } + } + dprintk(3, "Mailbox signature values not found!\n"); + return -1; +} + +static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value, + u32 *p_fw_image) +{ + + u32 temp = 0; + int i = 0; + + temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8); + temp = temp<<10; + *p_fw_image = temp; + p_fw_image++; + temp = temp|((0x05)<<10); + *p_fw_image = temp; + p_fw_image++; + + /*write data byte 1;*/ + temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00); + temp = temp<<10; + *p_fw_image = temp; + p_fw_image++; + temp = temp|((0x05)<<10); + *p_fw_image = temp; + p_fw_image++; + + /*write data byte 2;*/ + temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8); + temp = temp<<10; + *p_fw_image = temp; + p_fw_image++; + temp = temp|((0x05)<<10); + *p_fw_image = temp; + p_fw_image++; + + /*write data byte 3;*/ + temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16); + temp = temp<<10; + *p_fw_image = temp; + p_fw_image++; + temp = temp|((0x05)<<10); + *p_fw_image = temp; + p_fw_image++; + + /* write address byte 2;*/ + temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE | + ((address & 0x003F0000)>>8); + temp = temp<<10; + *p_fw_image = temp; + p_fw_image++; + temp = temp|((0x05)<<10); + *p_fw_image = temp; + p_fw_image++; + + /* write address byte 1;*/ + temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); + temp = temp<<10; + *p_fw_image = temp; + p_fw_image++; + temp = temp|((0x05)<<10); + *p_fw_image = temp; + p_fw_image++; + + /* write address byte 0;*/ + temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8); + temp = temp<<10; + *p_fw_image = temp; + p_fw_image++; + temp = temp|((0x05)<<10); + *p_fw_image = temp; + p_fw_image++; + + for (i = 0; i < 6; i++) { + *p_fw_image = 0xFFFFFFFF; + p_fw_image++; + } +} + + +static int cx231xx_load_firmware(struct cx231xx *dev) +{ + static const unsigned char magic[8] = { + 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa + }; + const struct firmware *firmware; + int i, retval = 0; + u32 value = 0; + u32 gpio_output = 0; + /*u32 checksum = 0;*/ + /*u32 *dataptr;*/ + u32 transfer_size = 0; + u32 fw_data = 0; + u32 address = 0; + /*u32 current_fw[800];*/ + u32 *p_current_fw, *p_fw; + u32 *p_fw_data; + int frame = 0; + u16 _buffer_size = 4096; + u8 *p_buffer; + + p_current_fw = vmalloc(1884180 * 4); + p_fw = p_current_fw; + if (p_current_fw == NULL) { + dprintk(2, "FAIL!!!\n"); + return -1; + } + + p_buffer = vmalloc(4096); + if (p_buffer == NULL) { + dprintk(2, "FAIL!!!\n"); + return -1; + } + + dprintk(2, "%s()\n", __func__); + + /* Save GPIO settings before reset of APU */ + retval |= mc417_memory_read(dev, 0x9020, &gpio_output); + retval |= mc417_memory_read(dev, 0x900C, &value); + + retval = mc417_register_write(dev, + IVTV_REG_VPU, 0xFFFFFFED); + retval |= mc417_register_write(dev, + IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); + retval |= mc417_register_write(dev, + IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800); + retval |= mc417_register_write(dev, + IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); + retval |= mc417_register_write(dev, + IVTV_REG_APU, 0); + + if (retval != 0) { + printk(KERN_ERR "%s: Error with mc417_register_write\n", + __func__); + return -1; + } + + retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME, + &dev->udev->dev); + + if (retval != 0) { + printk(KERN_ERR + "ERROR: Hotplug firmware request failed (%s).\n", + CX231xx_FIRM_IMAGE_NAME); + printk(KERN_ERR "Please fix your hotplug setup, the board will " + "not work without firmware loaded!\n"); + return -1; + } + + if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) { + printk(KERN_ERR "ERROR: Firmware size mismatch " + "(have %zd, expected %d)\n", + firmware->size, CX231xx_FIRM_IMAGE_SIZE); + release_firmware(firmware); + return -1; + } + + if (0 != memcmp(firmware->data, magic, 8)) { + printk(KERN_ERR + "ERROR: Firmware magic mismatch, wrong file?\n"); + release_firmware(firmware); + return -1; + } + + initGPIO(dev); + + /* transfer to the chip */ + dprintk(2, "Loading firmware to GPIO...\n"); + p_fw_data = (u32 *)firmware->data; + dprintk(2, "firmware->size=%zd\n", firmware->size); + for (transfer_size = 0; transfer_size < firmware->size; + transfer_size += 4) { + fw_data = *p_fw_data; + + mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw); + address = address + 1; + p_current_fw += 20; + p_fw_data += 1; + } + + /*download the firmware by ep5-out*/ + + for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size); + frame++) { + for (i = 0; i < _buffer_size; i++) { + *(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF); + i++; + *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8); + i++; + *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16); + i++; + *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24); + } + cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size); + } + + p_current_fw = p_fw; + vfree(p_current_fw); + p_current_fw = NULL; + uninitGPIO(dev); + release_firmware(firmware); + dprintk(1, "Firmware upload successful.\n"); + + retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS, + IVTV_CMD_HW_BLOCKS_RST); + if (retval < 0) { + printk(KERN_ERR "%s: Error with mc417_register_write\n", + __func__); + return retval; + } + /* F/W power up disturbs the GPIOs, restore state */ + retval |= mc417_register_write(dev, 0x9020, gpio_output); + retval |= mc417_register_write(dev, 0x900C, value); + + retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); + retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); + + if (retval < 0) { + printk(KERN_ERR "%s: Error with mc417_register_write\n", + __func__); + return retval; + } + return 0; +} + +static void cx231xx_417_check_encoder(struct cx231xx *dev) +{ + u32 status, seq; + + status = 0; + seq = 0; + cx231xx_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq); + dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq); +} + +static void cx231xx_codec_settings(struct cx231xx *dev) +{ + dprintk(1, "%s()\n", __func__); + + /* assign frame size */ + cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, + dev->ts1.height, dev->ts1.width); + + dev->mpeg_params.width = dev->ts1.width; + dev->mpeg_params.height = dev->ts1.height; + + cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params); + + cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); + cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); +} + +static int cx231xx_initialize_codec(struct cx231xx *dev) +{ + int version; + int retval; + u32 i, data[7]; + u32 val = 0; + + dprintk(1, "%s()\n", __func__); + cx231xx_disable656(dev); + retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ + if (retval < 0) { + dprintk(2, "%s() PING OK\n", __func__); + retval = cx231xx_load_firmware(dev); + if (retval < 0) { + printk(KERN_ERR "%s() f/w load failed\n", __func__); + return retval; + } + retval = cx231xx_find_mailbox(dev); + if (retval < 0) { + printk(KERN_ERR "%s() mailbox < 0, error\n", + __func__); + return -1; + } + dev->cx23417_mailbox = retval; + retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); + if (retval < 0) { + printk(KERN_ERR + "ERROR: cx23417 firmware ping failed!\n"); + return -1; + } + retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, + &version); + if (retval < 0) { + printk(KERN_ERR "ERROR: cx23417 firmware get encoder :" + "version failed!\n"); + return -1; + } + dprintk(1, "cx23417 firmware version is 0x%08x\n", version); + msleep(200); + } + + for (i = 0; i < 1; i++) { + retval = mc417_register_read(dev, 0x20f8, &val); + dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n", + val); + if (retval < 0) + return retval; + } + + cx231xx_enable656(dev); + /* stop mpeg capture */ + cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, + 3, 0, 1, 3, 4); + + cx231xx_codec_settings(dev); + msleep(60); + +/* cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, + CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115); + cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, + CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0); +*/ + /* Setup to capture VBI */ + data[0] = 0x0001BD00; + data[1] = 1; /* frames per interrupt */ + data[2] = 4; /* total bufs */ + data[3] = 0x91559155; /* start codes */ + data[4] = 0x206080C0; /* stop codes */ + data[5] = 6; /* lines */ + data[6] = 64; /* BPL */ +/* + cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1], + data[2], data[3], data[4], data[5], data[6]); + + for (i = 2; i <= 24; i++) { + int valid; + + valid = ((i >= 19) && (i <= 21)); + cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i, + valid, 0 , 0, 0); + cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, + i | 0x80000000, valid, 0, 0, 0); + } +*/ +/* cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE); + msleep(60); +*/ + /* initialize the video input */ + retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); + if (retval < 0) + return retval; + msleep(60); + + /* Enable VIP style pixel invalidation so we work with scaled mode */ + mc417_memory_write(dev, 2120, 0x00000080); + + /* start capturing to the host interface */ + retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, + CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE); + if (retval < 0) + return retval; + msleep(10); + + for (i = 0; i < 1; i++) { + mc417_register_read(dev, 0x20f8, &val); + dprintk(3, "***VIM Capture Lines =%d ***\n", val); + } + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int bb_buf_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct cx231xx_fh *fh = q->priv_data; + + fh->dev->ts1.ts_packet_size = mpeglinesize; + fh->dev->ts1.ts_packet_count = mpeglines; + + *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; + *count = mpegbufs; + + return 0; +} +static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) +{ + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx *dev = fh->dev; + unsigned long flags = 0; + + if (in_interrupt()) + BUG(); + + spin_lock_irqsave(&dev->video_mode.slock, flags); + if (dev->USE_ISO) { + if (dev->video_mode.isoc_ctl.buf == buf) + dev->video_mode.isoc_ctl.buf = NULL; + } else { + if (dev->video_mode.bulk_ctl.buf == buf) + dev->video_mode.bulk_ctl.buf = NULL; + } + spin_unlock_irqrestore(&dev->video_mode.slock, flags); + videobuf_waiton(vq, &buf->vb, 0, 0); + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb, + struct cx231xx_dmaqueue *dma_q) +{ + void *vbuf; + struct cx231xx_buffer *buf; + u32 tail_data = 0; + char *p_data; + + if (dma_q->mpeg_buffer_done == 0) { + if (list_empty(&dma_q->active)) + return; + + buf = list_entry(dma_q->active.next, + struct cx231xx_buffer, vb.queue); + dev->video_mode.isoc_ctl.buf = buf; + dma_q->mpeg_buffer_done = 1; + } + /* Fill buffer */ + buf = dev->video_mode.isoc_ctl.buf; + vbuf = videobuf_to_vmalloc(&buf->vb); + + if ((dma_q->mpeg_buffer_completed+len) < + mpeglines*mpeglinesize) { + if (dma_q->add_ps_package_head == + CX231XX_NEED_ADD_PS_PACKAGE_HEAD) { + memcpy(vbuf+dma_q->mpeg_buffer_completed, + dma_q->ps_head, 3); + dma_q->mpeg_buffer_completed = + dma_q->mpeg_buffer_completed + 3; + dma_q->add_ps_package_head = + CX231XX_NONEED_PS_PACKAGE_HEAD; + } + memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len); + dma_q->mpeg_buffer_completed = + dma_q->mpeg_buffer_completed + len; + } else { + dma_q->mpeg_buffer_done = 0; + + tail_data = + mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed; + memcpy(vbuf+dma_q->mpeg_buffer_completed, + data, tail_data); + + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + dma_q->mpeg_buffer_completed = 0; + + if (len - tail_data > 0) { + p_data = data + tail_data; + dma_q->left_data_count = len - tail_data; + memcpy(dma_q->p_left_data, + p_data, len - tail_data); + } + + } + + return; +} + +static void buffer_filled(char *data, int len, struct urb *urb, + struct cx231xx_dmaqueue *dma_q) +{ + void *vbuf; + struct cx231xx_buffer *buf; + + if (list_empty(&dma_q->active)) + return; + + + buf = list_entry(dma_q->active.next, + struct cx231xx_buffer, vb.queue); + + + /* Fill buffer */ + vbuf = videobuf_to_vmalloc(&buf->vb); + memcpy(vbuf, data, len); + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + + return; +} +static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) +{ + struct cx231xx_dmaqueue *dma_q = urb->context; + unsigned char *p_buffer; + u32 buffer_size = 0; + u32 i = 0; + + for (i = 0; i < urb->number_of_packets; i++) { + if (dma_q->left_data_count > 0) { + buffer_copy(dev, dma_q->p_left_data, + dma_q->left_data_count, urb, dma_q); + dma_q->mpeg_buffer_completed = dma_q->left_data_count; + dma_q->left_data_count = 0; + } + + p_buffer = urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + buffer_size = urb->iso_frame_desc[i].actual_length; + + if (buffer_size > 0) + buffer_copy(dev, p_buffer, buffer_size, urb, dma_q); + } + + return 0; +} +static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) +{ + + /*char *outp;*/ + /*struct cx231xx_buffer *buf;*/ + struct cx231xx_dmaqueue *dma_q = urb->context; + unsigned char *p_buffer, *buffer; + u32 buffer_size = 0; + + p_buffer = urb->transfer_buffer; + buffer_size = urb->actual_length; + + buffer = kmalloc(buffer_size, GFP_ATOMIC); + + memcpy(buffer, dma_q->ps_head, 3); + memcpy(buffer+3, p_buffer, buffer_size-3); + memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3); + + p_buffer = buffer; + buffer_filled(p_buffer, buffer_size, urb, dma_q); + + kfree(buffer); + return 0; +} + +static int bb_buf_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) +{ + struct cx231xx_fh *fh = q->priv_data; + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb); + struct cx231xx *dev = fh->dev; + int rc = 0, urb_init = 0; + int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; + + dma_qq = &dev->video_mode.vidq; + + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + buf->vb.width = fh->dev->ts1.ts_packet_size; + buf->vb.height = fh->dev->ts1.ts_packet_count; + buf->vb.size = size; + buf->vb.field = field; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(q, &buf->vb, NULL); + if (rc < 0) + goto fail; + } + + if (dev->USE_ISO) { + if (!dev->video_mode.isoc_ctl.num_bufs) + urb_init = 1; + } else { + if (!dev->video_mode.bulk_ctl.num_bufs) + urb_init = 1; + } + /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n", + urb_init, dev->video_mode.max_pkt_size);*/ + dev->mode_tv = 1; + + if (urb_init) { + rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); + rc = cx231xx_unmute_audio(dev); + if (dev->USE_ISO) { + cx231xx_set_alt_setting(dev, INDEX_TS1, 4); + rc = cx231xx_init_isoc(dev, mpeglines, + mpegbufs, + dev->ts1_mode.max_pkt_size, + cx231xx_isoc_copy); + } else { + cx231xx_set_alt_setting(dev, INDEX_TS1, 0); + rc = cx231xx_init_bulk(dev, mpeglines, + mpegbufs, + dev->ts1_mode.max_pkt_size, + cx231xx_bulk_copy); + } + if (rc < 0) + goto fail; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(q, buf); + return rc; +} + +static void bb_buf_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct cx231xx_fh *fh = q->priv_data; + + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb); + struct cx231xx *dev = fh->dev; + struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vidq->active); + +} + +static void bb_buf_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb); + /*struct cx231xx_fh *fh = q->priv_data;*/ + /*struct cx231xx *dev = (struct cx231xx *)fh->dev;*/ + + free_buffer(q, buf); +} + +static struct videobuf_queue_ops cx231xx_qops = { + .buf_setup = bb_buf_setup, + .buf_prepare = bb_buf_prepare, + .buf_queue = bb_buf_queue, + .buf_release = bb_buf_release, +}; + +/* ------------------------------------------------------------------ */ + +static const u32 *ctrl_classes[] = { + cx2341x_mpeg_ctrls, + NULL +}; + +static int cx231xx_queryctrl(struct cx231xx *dev, + struct v4l2_queryctrl *qctrl) +{ + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (qctrl->id == 0) + return -EINVAL; + + /* MPEG V4L2 controls */ + if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + + return 0; +} + +static int cx231xx_querymenu(struct cx231xx *dev, + struct v4l2_querymenu *qmenu) +{ + struct v4l2_queryctrl qctrl; + + qctrl.id = qmenu->id; + cx231xx_queryctrl(dev, &qctrl); + return v4l2_ctrl_query_menu(qmenu, &qctrl, + cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); +} + +static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + + *norm = dev->encodernorm.id; + return 0; +} +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++) + if (*id & cx231xx_tvnorms[i].id) + break; + if (i == ARRAY_SIZE(cx231xx_tvnorms)) + return -EINVAL; + dev->encodernorm = cx231xx_tvnorms[i]; + + if (dev->encodernorm.id & 0xb000) { + dprintk(3, "encodernorm set to NTSC\n"); + dev->norm = V4L2_STD_NTSC; + dev->ts1.height = 480; + dev->mpeg_params.is_50hz = 0; + } else { + dprintk(3, "encodernorm set to PAL\n"); + dev->norm = V4L2_STD_PAL_B; + dev->ts1.height = 576; + dev->mpeg_params.is_50hz = 1; + } + call_all(dev, core, s_std, dev->norm); + /* do mode control overrides */ + cx231xx_do_mode_ctrl_overrides(dev); + + dprintk(3, "exit vidioc_s_std() i=0x%x\n", i); + return 0; +} +static int vidioc_g_audio(struct file *file, void *fh, + struct v4l2_audio *a) +{ + struct v4l2_audio *vin = a; + + int ret = -EINVAL; + if (vin->index > 0) + return ret; + strncpy(vin->name, "VideoGrabber Audio", 14); + vin->capability = V4L2_AUDCAP_STEREO; +return 0; +} +static int vidioc_enumaudio(struct file *file, void *fh, + struct v4l2_audio *a) +{ + struct v4l2_audio *vin = a; + + int ret = -EINVAL; + + if (vin->index > 0) + return ret; + strncpy(vin->name, "VideoGrabber Audio", 14); + vin->capability = V4L2_AUDCAP_STEREO; + + +return 0; +} +static const char *iname[] = { + [CX231XX_VMUX_COMPOSITE1] = "Composite1", + [CX231XX_VMUX_SVIDEO] = "S-Video", + [CX231XX_VMUX_TELEVISION] = "Television", + [CX231XX_VMUX_CABLE] = "Cable TV", + [CX231XX_VMUX_DVB] = "DVB", + [CX231XX_VMUX_DEBUG] = "for debug only", +}; +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + struct cx231xx_input *input; + int n; + dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index); + + if (i->index >= 4) + return -EINVAL; + + + input = &cx231xx_boards[dev->model].input[i->index]; + + if (input->type == 0) + return -EINVAL; + + /* FIXME + * strcpy(i->name, input->name); */ + + n = i->index; + strcpy(i->name, iname[INPUT(n)->type]); + + if (input->type == CX231XX_VMUX_TELEVISION || + input->type == CX231XX_VMUX_CABLE) + i->type = V4L2_INPUT_TYPE_TUNER; + else + i->type = V4L2_INPUT_TYPE_CAMERA; + + + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + + dprintk(3, "enter vidioc_s_input() i=%d\n", i); + + mutex_lock(&dev->lock); + + video_mux(dev, i); + + mutex_unlock(&dev->lock); + + if (i >= 4) + return -EINVAL; + dev->input = i; + dprintk(3, "exit vidioc_s_input()\n"); + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + + + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_s_ctrl()\n"); + /* Update the A/V core */ + call_all(dev, core, s_ctrl, ctl); + dprintk(3, "exit vidioc_s_ctrl()\n"); + return 0; +} +static struct v4l2_capability pvr_capability = { + .driver = "cx231xx", + .card = "VideoGrabber", + .bus_info = "usb", + .version = 1, + .capabilities = (V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE), + .reserved = {0, 0, 0, 0} +}; +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + + + + memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + + if (f->index != 0) + return -EINVAL; + + strlcpy(f->description, "MPEG", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_MPEG; + + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_g_fmt_vid_cap()\n"); + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = + dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; + f->fmt.pix.colorspace = 0; + f->fmt.pix.width = dev->ts1.width; + f->fmt.pix.height = dev->ts1.height; + f->fmt.pix.field = fh->vidq.field; + dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", + dev->ts1.width, dev->ts1.height, fh->vidq.field); + dprintk(3, "exit vidioc_g_fmt_vid_cap()\n"); + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_try_fmt_vid_cap()\n"); + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = + dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; + f->fmt.pix.colorspace = 0; + dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", + dev->ts1.width, dev->ts1.height, fh->vidq.field); + dprintk(3, "exit vidioc_try_fmt_vid_cap()\n"); + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + + return 0; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct cx231xx_fh *fh = file->private_data; + + return videobuf_reqbufs(&fh->vidq, p); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx231xx_fh *fh = file->private_data; + + return videobuf_querybuf(&fh->vidq, p); +} + +static int vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx231xx_fh *fh = file->private_data; + + return videobuf_qbuf(&fh->vidq, p); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct cx231xx_fh *fh = priv; + + return videobuf_dqbuf(&fh->vidq, b, file->f_flags & O_NONBLOCK); +} + + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type i) +{ + struct cx231xx_fh *fh = file->private_data; + + struct cx231xx *dev = fh->dev; + int rc = 0; + dprintk(3, "enter vidioc_streamon()\n"); + cx231xx_set_alt_setting(dev, INDEX_TS1, 0); + rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); + if (dev->USE_ISO) + rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, + CX231XX_NUM_BUFS, + dev->video_mode.max_pkt_size, + cx231xx_isoc_copy); + else { + rc = cx231xx_init_bulk(dev, 320, + 5, + dev->ts1_mode.max_pkt_size, + cx231xx_bulk_copy); + } + dprintk(3, "exit vidioc_streamon()\n"); + return videobuf_streamon(&fh->vidq); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx231xx_fh *fh = file->private_data; + + return videobuf_streamoff(&fh->vidq); +} + +static int vidioc_g_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_g_ext_ctrls()\n"); + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + dprintk(3, "exit vidioc_g_ext_ctrls()\n"); + return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); +} + +static int vidioc_s_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + struct cx2341x_mpeg_params p; + int err; + dprintk(3, "enter vidioc_s_ext_ctrls()\n"); + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + p = dev->mpeg_params; + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); + if (err == 0) { + err = cx2341x_update(dev, cx231xx_mbox_func, + &dev->mpeg_params, &p); + dev->mpeg_params = p; + } + + return err; + + +return 0; +} + +static int vidioc_try_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + struct cx2341x_mpeg_params p; + int err; + dprintk(3, "enter vidioc_try_ext_ctrls()\n"); + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + p = dev->mpeg_params; + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); + dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err); + return err; +} + +static int vidioc_log_status(struct file *file, void *priv) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + char name[32 + 2]; + + snprintf(name, sizeof(name), "%s/2", dev->name); + dprintk(3, + "%s/2: ============ START LOG STATUS ============\n", + dev->name); + call_all(dev, core, log_status); + cx2341x_log_status(&dev->mpeg_params, name); + dprintk(3, + "%s/2: ============= END LOG STATUS =============\n", + dev->name); + return 0; +} + +static int vidioc_querymenu(struct file *file, void *priv, + struct v4l2_querymenu *a) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_querymenu()\n"); + dprintk(3, "exit vidioc_querymenu()\n"); + return cx231xx_querymenu(dev, a); +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_queryctrl()\n"); + dprintk(3, "exit vidioc_queryctrl()\n"); + return cx231xx_queryctrl(dev, c); +} + +static int mpeg_open(struct file *file) +{ + int minor = video_devdata(file)->minor; + struct cx231xx *h, *dev = NULL; + /*struct list_head *list;*/ + struct cx231xx_fh *fh; + /*u32 value = 0;*/ + + dprintk(2, "%s()\n", __func__); + + list_for_each_entry(h, &cx231xx_devlist, devlist) { + if (h->v4l_device->minor == minor) + dev = h; + } + + if (dev == NULL) + return -ENODEV; + + mutex_lock(&dev->lock); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) { + mutex_unlock(&dev->lock); + return -ENOMEM; + } + + file->private_data = fh; + fh->dev = dev; + + + videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops, + NULL, &dev->video_mode.slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, + sizeof(struct cx231xx_buffer), fh, NULL); +/* + videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops, + &dev->udev->dev, &dev->ts1.slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct cx231xx_buffer), + fh, NULL); +*/ + + + cx231xx_set_alt_setting(dev, INDEX_VANC, 1); + cx231xx_set_gpio_value(dev, 2, 0); + + cx231xx_initialize_codec(dev); + + mutex_unlock(&dev->lock); + cx231xx_start_TS1(dev); + + return 0; +} + +static int mpeg_release(struct file *file) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + + dprintk(3, "mpeg_release()! dev=0x%p\n", dev); + + if (!dev) { + dprintk(3, "abort!!!\n"); + return 0; + } + + mutex_lock(&dev->lock); + + cx231xx_stop_TS1(dev); + + /* do this before setting alternate! */ + if (dev->USE_ISO) + cx231xx_uninit_isoc(dev); + else + cx231xx_uninit_bulk(dev); + cx231xx_set_mode(dev, CX231XX_SUSPEND); + + cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + CX231xx_END_NOW, CX231xx_MPEG_CAPTURE, + CX231xx_RAW_BITS_NONE); + + /* FIXME: Review this crap */ + /* Shut device down on last close */ + if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { + if (atomic_dec_return(&dev->v4l_reader_count) == 0) { + /* stop mpeg capture */ + + msleep(500); + cx231xx_417_check_encoder(dev); + + } + } + + if (fh->vidq.streaming) + videobuf_streamoff(&fh->vidq); + if (fh->vidq.reading) + videobuf_read_stop(&fh->vidq); + + videobuf_mmap_free(&fh->vidq); + file->private_data = NULL; + kfree(fh); + mutex_unlock(&dev->lock); + return 0; +} + +static ssize_t mpeg_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + + + /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ + /* Start mpeg encoder on first read. */ + if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { + if (atomic_inc_return(&dev->v4l_reader_count) == 1) { + if (cx231xx_initialize_codec(dev) < 0) + return -EINVAL; + } + } + + return videobuf_read_stream(&fh->vidq, data, count, ppos, 0, + file->f_flags & O_NONBLOCK); +} + +static unsigned int mpeg_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct cx231xx_fh *fh = file->private_data; + /*struct cx231xx *dev = fh->dev;*/ + + /*dprintk(2, "%s\n", __func__);*/ + + return videobuf_poll_stream(file, &fh->vidq, wait); +} + +static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + + dprintk(2, "%s()\n", __func__); + + return videobuf_mmap_mapper(&fh->vidq, vma); +} + +static struct v4l2_file_operations mpeg_fops = { + .owner = THIS_MODULE, + .open = mpeg_open, + .release = mpeg_release, + .read = mpeg_read, + .poll = mpeg_poll, + .mmap = mpeg_mmap, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { + .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_enumaudio = vidioc_enumaudio, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, + .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, + .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, + .vidioc_log_status = vidioc_log_status, + .vidioc_querymenu = vidioc_querymenu, + .vidioc_queryctrl = vidioc_queryctrl, +/* .vidioc_g_chip_ident = cx231xx_g_chip_ident,*/ +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* .vidioc_g_register = cx231xx_g_register,*/ +/* .vidioc_s_register = cx231xx_s_register,*/ +#endif +}; + +static struct video_device cx231xx_mpeg_template = { + .name = "cx231xx", + .fops = &mpeg_fops, + .ioctl_ops = &mpeg_ioctl_ops, + .minor = -1, + .tvnorms = CX231xx_NORMS, + .current_norm = V4L2_STD_NTSC_M, +}; + +void cx231xx_417_unregister(struct cx231xx *dev) +{ + dprintk(1, "%s()\n", __func__); + dprintk(3, "%s()\n", __func__); + + if (dev->v4l_device) { + if (-1 != dev->v4l_device->minor) + video_unregister_device(dev->v4l_device); + else + video_device_release(dev->v4l_device); + dev->v4l_device = NULL; + } +} + +static struct video_device *cx231xx_video_dev_alloc( + struct cx231xx *dev, + struct usb_device *usbdev, + struct video_device *template, + char *type) +{ + struct video_device *vfd; + + dprintk(1, "%s()\n", __func__); + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->minor = -1; + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, + type, cx231xx_boards[dev->model].name); + + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->release = video_device_release; + + return vfd; + +} + +int cx231xx_417_register(struct cx231xx *dev) +{ + /* FIXME: Port1 hardcoded here */ + int err = -ENODEV; + struct cx231xx_tsport *tsport = &dev->ts1; + + dprintk(1, "%s()\n", __func__); + + /* Set default TV standard */ + dev->encodernorm = cx231xx_tvnorms[0]; + + if (dev->encodernorm.id & V4L2_STD_525_60) + tsport->height = 480; + else + tsport->height = 576; + + tsport->width = 720; + cx2341x_fill_defaults(&dev->mpeg_params); + dev->norm = V4L2_STD_NTSC; + + dev->mpeg_params.port = CX2341X_PORT_SERIAL; + + /* Allocate and initialize V4L video device */ + dev->v4l_device = cx231xx_video_dev_alloc(dev, + dev->udev, &cx231xx_mpeg_template, "mpeg"); + err = video_register_device(dev->v4l_device, + VFL_TYPE_GRABBER, -1); + if (err < 0) { + dprintk(3, "%s: can't register mpeg device\n", dev->name); + return err; + } + + dprintk(3, "%s: registered device video%d [mpeg]\n", + dev->name, dev->v4l_device->num); + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-audio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-audio.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,756 @@ +/* + * Conexant Cx231xx audio extension + * + * Copyright (C) 2008 + * Based on em28xx driver + * + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cx231xx.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); + +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_INFO "cx231xx-audio %s: " fmt, \ + __func__, ##arg); \ + } while (0) + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; + +static int cx231xx_isoc_audio_deinit(struct cx231xx *dev) +{ + int i; + + dprintk("Stopping isoc\n"); + + for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { + if (dev->adev.urb[i]) { + if (!irqs_disabled()) + usb_kill_urb(dev->adev.urb[i]); + else + usb_unlink_urb(dev->adev.urb[i]); + + usb_free_urb(dev->adev.urb[i]); + dev->adev.urb[i] = NULL; + + kfree(dev->adev.transfer_buffer[i]); + dev->adev.transfer_buffer[i] = NULL; + } + } + + return 0; +} + +static int cx231xx_bulk_audio_deinit(struct cx231xx *dev) +{ + int i; + + dprintk("Stopping bulk\n"); + + for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { + if (dev->adev.urb[i]) { + if (!irqs_disabled()) + usb_kill_urb(dev->adev.urb[i]); + else + usb_unlink_urb(dev->adev.urb[i]); + + usb_free_urb(dev->adev.urb[i]); + dev->adev.urb[i] = NULL; + + kfree(dev->adev.transfer_buffer[i]); + dev->adev.transfer_buffer[i] = NULL; + } + } + + return 0; +} + +static void cx231xx_audio_isocirq(struct urb *urb) +{ + struct cx231xx *dev = urb->context; + int i; + unsigned int oldptr; + int period_elapsed = 0; + int status; + unsigned char *cp; + unsigned int stride; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + dprintk("urb completition error %d.\n", urb->status); + break; + } + + if (atomic_read(&dev->stream_started) == 0) + return; + + if (dev->adev.capture_pcm_substream) { + substream = dev->adev.capture_pcm_substream; + runtime = substream->runtime; + stride = runtime->frame_bits >> 3; + + for (i = 0; i < urb->number_of_packets; i++) { + int length = urb->iso_frame_desc[i].actual_length / + stride; + cp = (unsigned char *)urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + + if (!length) + continue; + + oldptr = dev->adev.hwptr_done_capture; + if (oldptr + length >= runtime->buffer_size) { + unsigned int cnt; + + cnt = runtime->buffer_size - oldptr; + memcpy(runtime->dma_area + oldptr * stride, cp, + cnt * stride); + memcpy(runtime->dma_area, cp + cnt * stride, + length * stride - cnt * stride); + } else { + memcpy(runtime->dma_area + oldptr * stride, cp, + length * stride); + } + + snd_pcm_stream_lock(substream); + + dev->adev.hwptr_done_capture += length; + if (dev->adev.hwptr_done_capture >= + runtime->buffer_size) + dev->adev.hwptr_done_capture -= + runtime->buffer_size; + + dev->adev.capture_transfer_done += length; + if (dev->adev.capture_transfer_done >= + runtime->period_size) { + dev->adev.capture_transfer_done -= + runtime->period_size; + period_elapsed = 1; + } + snd_pcm_stream_unlock(substream); + } + if (period_elapsed) + snd_pcm_period_elapsed(substream); + } + urb->status = 0; + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { + cx231xx_errdev("resubmit of audio urb failed (error=%i)\n", + status); + } + return; +} + +static void cx231xx_audio_bulkirq(struct urb *urb) +{ + struct cx231xx *dev = urb->context; + unsigned int oldptr; + int period_elapsed = 0; + int status; + unsigned char *cp; + unsigned int stride; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + dprintk("urb completition error %d.\n", urb->status); + break; + } + + if (atomic_read(&dev->stream_started) == 0) + return; + + if (dev->adev.capture_pcm_substream) { + substream = dev->adev.capture_pcm_substream; + runtime = substream->runtime; + stride = runtime->frame_bits >> 3; + + if (1) { + int length = urb->actual_length / + stride; + cp = (unsigned char *)urb->transfer_buffer; + + oldptr = dev->adev.hwptr_done_capture; + if (oldptr + length >= runtime->buffer_size) { + unsigned int cnt; + + cnt = runtime->buffer_size - oldptr; + memcpy(runtime->dma_area + oldptr * stride, cp, + cnt * stride); + memcpy(runtime->dma_area, cp + cnt * stride, + length * stride - cnt * stride); + } else { + memcpy(runtime->dma_area + oldptr * stride, cp, + length * stride); + } + + snd_pcm_stream_lock(substream); + + dev->adev.hwptr_done_capture += length; + if (dev->adev.hwptr_done_capture >= + runtime->buffer_size) + dev->adev.hwptr_done_capture -= + runtime->buffer_size; + + dev->adev.capture_transfer_done += length; + if (dev->adev.capture_transfer_done >= + runtime->period_size) { + dev->adev.capture_transfer_done -= + runtime->period_size; + period_elapsed = 1; + } + snd_pcm_stream_unlock(substream); + } + if (period_elapsed) + snd_pcm_period_elapsed(substream); + } + urb->status = 0; + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { + cx231xx_errdev("resubmit of audio urb failed (error=%i)\n", + status); + } + return; +} + +static int cx231xx_init_audio_isoc(struct cx231xx *dev) +{ + int i, errCode; + int sb_size; + + cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__); + + sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; + + for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { + struct urb *urb; + int j, k; + + dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); + if (!dev->adev.transfer_buffer[i]) + return -ENOMEM; + + memset(dev->adev.transfer_buffer[i], 0x80, sb_size); + urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC); + if (!urb) { + cx231xx_errdev("usb_alloc_urb failed!\n"); + for (j = 0; j < i; j++) { + usb_free_urb(dev->adev.urb[j]); + kfree(dev->adev.transfer_buffer[j]); + } + return -ENOMEM; + } + + urb->dev = dev->udev; + urb->context = dev; + urb->pipe = usb_rcvisocpipe(dev->udev, + dev->adev.end_point_addr); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = dev->adev.transfer_buffer[i]; + urb->interval = 1; + urb->complete = cx231xx_audio_isocirq; + urb->number_of_packets = CX231XX_ISO_NUM_AUDIO_PACKETS; + urb->transfer_buffer_length = sb_size; + + for (j = k = 0; j < CX231XX_ISO_NUM_AUDIO_PACKETS; + j++, k += dev->adev.max_pkt_size) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = dev->adev.max_pkt_size; + } + dev->adev.urb[i] = urb; + } + + for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { + errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); + if (errCode < 0) { + cx231xx_isoc_audio_deinit(dev); + return errCode; + } + } + + return errCode; +} + +static int cx231xx_init_audio_bulk(struct cx231xx *dev) +{ + int i, errCode; + int sb_size; + + cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__); + + sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; + + for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { + struct urb *urb; + int j; + + dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); + if (!dev->adev.transfer_buffer[i]) + return -ENOMEM; + + memset(dev->adev.transfer_buffer[i], 0x80, sb_size); + urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); + if (!urb) { + cx231xx_errdev("usb_alloc_urb failed!\n"); + for (j = 0; j < i; j++) { + usb_free_urb(dev->adev.urb[j]); + kfree(dev->adev.transfer_buffer[j]); + } + return -ENOMEM; + } + + urb->dev = dev->udev; + urb->context = dev; + urb->pipe = usb_rcvbulkpipe(dev->udev, + dev->adev.end_point_addr); + urb->transfer_flags = 0; + urb->transfer_buffer = dev->adev.transfer_buffer[i]; + urb->complete = cx231xx_audio_bulkirq; + urb->transfer_buffer_length = sb_size; + + dev->adev.urb[i] = urb; + + } + + for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { + errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); + if (errCode < 0) { + cx231xx_bulk_audio_deinit(dev); + return errCode; + } + } + + return errCode; +} + +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + dprintk("Allocating vbuffer\n"); + if (runtime->dma_area) { + if (runtime->dma_bytes > size) + return 0; + + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc(size); + if (!runtime->dma_area) + return -ENOMEM; + + runtime->dma_bytes = size; + + return 0; +} + +static struct snd_pcm_hardware snd_cx231xx_hw_capture = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, + + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ + .period_bytes_min = 64, /* 12544/2, */ + .period_bytes_max = 12544, + .periods_min = 2, + .periods_max = 98, /* 12544, */ +}; + +static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream) +{ + struct cx231xx *dev = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret = 0; + + dprintk("opening device and trying to acquire exclusive lock\n"); + + if (!dev) { + cx231xx_errdev("BUG: cx231xx can't find device struct." + " Can't proceed with open\n"); + return -ENODEV; + } + + /* Sets volume, mute, etc */ + dev->mute = 0; + + /* set alternate setting for audio interface */ + /* 1 - 48000 samples per sec */ + mutex_lock(&dev->lock); + if (dev->USE_ISO) + ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1); + else + ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); + mutex_unlock(&dev->lock); + if (ret < 0) { + cx231xx_errdev("failed to set alternate setting !\n"); + + return ret; + } + + runtime->hw = snd_cx231xx_hw_capture; + + mutex_lock(&dev->lock); + /* inform hardware to start streaming */ + ret = cx231xx_capture_start(dev, 1, Audio); + + dev->adev.users++; + mutex_unlock(&dev->lock); + + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + dev->adev.capture_pcm_substream = substream; + runtime->private_data = dev; + + return 0; +} + +static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) +{ + int ret; + struct cx231xx *dev = snd_pcm_substream_chip(substream); + + dprintk("closing device\n"); + + /* inform hardware to stop streaming */ + mutex_lock(&dev->lock); + ret = cx231xx_capture_start(dev, 0, Audio); + + /* set alternate setting for audio interface */ + /* 1 - 48000 samples per sec */ + ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); + if (ret < 0) { + cx231xx_errdev("failed to set alternate setting !\n"); + + mutex_unlock(&dev->lock); + return ret; + } + + dev->mute = 1; + dev->adev.users--; + mutex_unlock(&dev->lock); + + if (dev->adev.users == 0 && dev->adev.shutdown == 1) { + dprintk("audio users: %d\n", dev->adev.users); + dprintk("disabling audio stream!\n"); + dev->adev.shutdown = 0; + dprintk("released lock\n"); + if (atomic_read(&dev->stream_started) > 0) { + atomic_set(&dev->stream_started, 0); + schedule_work(&dev->wq_trigger); + } + } + return 0; +} + +static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + unsigned int channels, rate, format; + int ret; + + dprintk("Setting capture parameters\n"); + + ret = snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + format = params_format(hw_params); + rate = params_rate(hw_params); + channels = params_channels(hw_params); + + /* TODO: set up cx231xx audio chip to deliver the correct audio format, + current default is 48000hz multiplexed => 96000hz mono + which shouldn't matter since analogue TV only supports mono */ + return 0; +} + +static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream) +{ + struct cx231xx *dev = snd_pcm_substream_chip(substream); + + dprintk("Stop capture, if needed\n"); + + if (atomic_read(&dev->stream_started) > 0) { + atomic_set(&dev->stream_started, 0); + schedule_work(&dev->wq_trigger); + } + + return 0; +} + +static int snd_cx231xx_prepare(struct snd_pcm_substream *substream) +{ + struct cx231xx *dev = snd_pcm_substream_chip(substream); + + dev->adev.hwptr_done_capture = 0; + dev->adev.capture_transfer_done = 0; + + return 0; +} + +static void audio_trigger(struct work_struct *work) +{ + struct cx231xx *dev = container_of(work, struct cx231xx, wq_trigger); + + if (atomic_read(&dev->stream_started)) { + dprintk("starting capture"); + if (is_fw_load(dev) == 0) + cx25840_call(dev, core, load_fw); + if (dev->USE_ISO) + cx231xx_init_audio_isoc(dev); + else + cx231xx_init_audio_bulk(dev); + } else { + dprintk("stopping capture"); + cx231xx_isoc_audio_deinit(dev); + } +} + +static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct cx231xx *dev = snd_pcm_substream_chip(substream); + int retval; + + spin_lock(&dev->adev.slock); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + atomic_set(&dev->stream_started, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + atomic_set(&dev->stream_started, 0); + break; + default: + retval = -EINVAL; + } + spin_unlock(&dev->adev.slock); + + schedule_work(&dev->wq_trigger); + + return 0; +} + +static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream + *substream) +{ + struct cx231xx *dev; + unsigned long flags; + snd_pcm_uframes_t hwptr_done; + + dev = snd_pcm_substream_chip(substream); + + spin_lock_irqsave(&dev->adev.slock, flags); + hwptr_done = dev->adev.hwptr_done_capture; + spin_unlock_irqrestore(&dev->adev.slock, flags); + + return hwptr_done; +} + +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + + return vmalloc_to_page(pageptr); +} + +static struct snd_pcm_ops snd_cx231xx_pcm_capture = { + .open = snd_cx231xx_capture_open, + .close = snd_cx231xx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cx231xx_hw_capture_params, + .hw_free = snd_cx231xx_hw_capture_free, + .prepare = snd_cx231xx_prepare, + .trigger = snd_cx231xx_capture_trigger, + .pointer = snd_cx231xx_capture_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +static int cx231xx_audio_init(struct cx231xx *dev) +{ + struct cx231xx_audio *adev = &dev->adev; + struct snd_pcm *pcm; + struct snd_card *card; + static int devnr; + int err; + struct usb_interface *uif; + int i, isoc_pipe = 0; + + if (dev->has_alsa_audio != 1) { + /* This device does not support the extension (in this case + the device is expecting the snd-usb-audio module or + doesn't have analog audio support at all) */ + return 0; + } + + cx231xx_info("cx231xx-audio.c: probing for cx231xx " + "non standard usbaudio\n"); + + err = snd_card_create(index[devnr], "Cx231xx Audio", THIS_MODULE, + 0, &card); + if (err < 0) + return err; + + spin_lock_init(&adev->slock); + err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm); + if (err < 0) { + snd_card_free(card); + return err; + } + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_cx231xx_pcm_capture); + pcm->info_flags = 0; + pcm->private_data = dev; + strcpy(pcm->name, "Conexant cx231xx Capture"); + snd_card_set_dev(card, &dev->udev->dev); + strcpy(card->driver, "Cx231xx-Audio"); + strcpy(card->shortname, "Cx231xx Audio"); + strcpy(card->longname, "Conexant cx231xx Audio"); + + INIT_WORK(&dev->wq_trigger, audio_trigger); + + err = snd_card_register(card); + if (err < 0) { + snd_card_free(card); + return err; + } + adev->sndcard = card; + adev->udev = dev->udev; + + /* compute alternate max packet sizes for Audio */ + uif = + dev->udev->actconfig->interface[dev->current_pcb_config. + hs_config_info[0].interface_info. + audio_index + 1]; + + adev->end_point_addr = + le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc. + bEndpointAddress); + + adev->num_alt = uif->num_altsetting; + cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", + adev->end_point_addr, adev->num_alt); + adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL); + + if (adev->alt_max_pkt_size == NULL) { + cx231xx_errdev("out of memory!\n"); + return -ENOMEM; + } + + for (i = 0; i < adev->num_alt; i++) { + u16 tmp = + le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc. + wMaxPacketSize); + adev->alt_max_pkt_size[i] = + (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); + cx231xx_info("Alternate setting %i, max size= %i\n", i, + adev->alt_max_pkt_size[i]); + } + + return 0; +} + +static int cx231xx_audio_fini(struct cx231xx *dev) +{ + if (dev == NULL) + return 0; + + if (dev->has_alsa_audio != 1) { + /* This device does not support the extension (in this case + the device is expecting the snd-usb-audio module or + doesn't have analog audio support at all) */ + return 0; + } + + if (dev->adev.sndcard) { + snd_card_free(dev->adev.sndcard); + kfree(dev->adev.alt_max_pkt_size); + dev->adev.sndcard = NULL; + } + + return 0; +} + +static struct cx231xx_ops audio_ops = { + .id = CX231XX_AUDIO, + .name = "Cx231xx Audio Extension", + .init = cx231xx_audio_init, + .fini = cx231xx_audio_fini, +}; + +static int __init cx231xx_alsa_register(void) +{ + return cx231xx_register_extension(&audio_ops); +} + +static void __exit cx231xx_alsa_unregister(void) +{ + cx231xx_unregister_extension(&audio_ops); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Srinivasa Deevi "); +MODULE_DESCRIPTION("Cx231xx Audio driver"); + +module_init(cx231xx_alsa_register); +module_exit(cx231xx_alsa_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-avcore.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-avcore.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-avcore.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-avcore.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,3123 @@ +/* + cx231xx_avcore.c - driver for Conexant Cx23100/101/102 + USB video capture devices + + Copyright (C) 2008 + + This program contains the specific code to control the avdecoder chip and + other related usb control functions for cx231xx based chipset. + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "cx231xx.h" +#include "cx231xx-dif.h" + +#define TUNER_MODE_FM_RADIO 0 +/****************************************************************************** + -: BLOCK ARRANGEMENT :- + I2S block ----------------------| + [I2S audio] | + | + Analog Front End --> Direct IF -|-> Cx25840 --> Audio + [video & audio] | [Audio] + | + |-> Cx25840 --> Video + [Video] + +*******************************************************************************/ +/****************************************************************************** + * VERVE REGISTER * + * * + ******************************************************************************/ +static int verve_write_byte(struct cx231xx *dev, u8 saddr, u8 data) +{ + return cx231xx_write_i2c_data(dev, VERVE_I2C_ADDRESS, + saddr, 1, data, 1); +} + +static int verve_read_byte(struct cx231xx *dev, u8 saddr, u8 *data) +{ + int status; + u32 temp = 0; + + status = cx231xx_read_i2c_data(dev, VERVE_I2C_ADDRESS, + saddr, 1, &temp, 1); + *data = (u8) temp; + return status; +} +void initGPIO(struct cx231xx *dev) +{ + u32 _gpio_direction = 0; + u32 value = 0; + u8 val = 0; + + _gpio_direction = _gpio_direction & 0xFC0003FF; + _gpio_direction = _gpio_direction | 0x03FDFC00; + cx231xx_send_gpio_cmd(dev, _gpio_direction, (u8 *)&value, 4, 0, 0); + + verve_read_byte(dev, 0x07, &val); + cx231xx_info(" verve_read_byte address0x07=0x%x\n", val); + verve_write_byte(dev, 0x07, 0xF4); + verve_read_byte(dev, 0x07, &val); + cx231xx_info(" verve_read_byte address0x07=0x%x\n", val); + + cx231xx_capture_start(dev, 1, 2); + + cx231xx_mode_register(dev, EP_MODE_SET, 0x0500FE00); + cx231xx_mode_register(dev, GBULK_BIT_EN, 0xFFFDFFFF); + +} +void uninitGPIO(struct cx231xx *dev) +{ + u8 value[4] = { 0, 0, 0, 0 }; + + cx231xx_capture_start(dev, 0, 2); + verve_write_byte(dev, 0x07, 0x14); + cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + 0x68, value, 4); +} + +/****************************************************************************** + * A F E - B L O C K C O N T R O L functions * + * [ANALOG FRONT END] * + ******************************************************************************/ +static int afe_write_byte(struct cx231xx *dev, u16 saddr, u8 data) +{ + return cx231xx_write_i2c_data(dev, AFE_DEVICE_ADDRESS, + saddr, 2, data, 1); +} + +static int afe_read_byte(struct cx231xx *dev, u16 saddr, u8 *data) +{ + int status; + u32 temp = 0; + + status = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS, + saddr, 2, &temp, 1); + *data = (u8) temp; + return status; +} + +int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count) +{ + int status = 0; + u8 temp = 0; + u8 afe_power_status = 0; + int i = 0; + + /* super block initialize */ + temp = (u8) (ref_count & 0xff); + status = afe_write_byte(dev, SUP_BLK_TUNE2, temp); + if (status < 0) + return status; + + status = afe_read_byte(dev, SUP_BLK_TUNE2, &afe_power_status); + if (status < 0) + return status; + + temp = (u8) ((ref_count & 0x300) >> 8); + temp |= 0x40; + status = afe_write_byte(dev, SUP_BLK_TUNE1, temp); + if (status < 0) + return status; + + status = afe_write_byte(dev, SUP_BLK_PLL2, 0x0f); + if (status < 0) + return status; + + /* enable pll */ + while (afe_power_status != 0x18) { + status = afe_write_byte(dev, SUP_BLK_PWRDN, 0x18); + if (status < 0) { + cx231xx_info( + ": Init Super Block failed in send cmd\n"); + break; + } + + status = afe_read_byte(dev, SUP_BLK_PWRDN, &afe_power_status); + afe_power_status &= 0xff; + if (status < 0) { + cx231xx_info( + ": Init Super Block failed in receive cmd\n"); + break; + } + i++; + if (i == 10) { + cx231xx_info( + ": Init Super Block force break in loop !!!!\n"); + status = -1; + break; + } + } + + if (status < 0) + return status; + + /* start tuning filter */ + status = afe_write_byte(dev, SUP_BLK_TUNE3, 0x40); + if (status < 0) + return status; + + msleep(5); + + /* exit tuning */ + status = afe_write_byte(dev, SUP_BLK_TUNE3, 0x00); + + return status; +} + +int cx231xx_afe_init_channels(struct cx231xx *dev) +{ + int status = 0; + + /* power up all 3 channels, clear pd_buffer */ + status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, 0x00); + status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, 0x00); + status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, 0x00); + + /* Enable quantizer calibration */ + status = afe_write_byte(dev, ADC_COM_QUANT, 0x02); + + /* channel initialize, force modulator (fb) reset */ + status = afe_write_byte(dev, ADC_FB_FRCRST_CH1, 0x17); + status = afe_write_byte(dev, ADC_FB_FRCRST_CH2, 0x17); + status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, 0x17); + + /* start quantilizer calibration */ + status = afe_write_byte(dev, ADC_CAL_ATEST_CH1, 0x10); + status = afe_write_byte(dev, ADC_CAL_ATEST_CH2, 0x10); + status = afe_write_byte(dev, ADC_CAL_ATEST_CH3, 0x10); + msleep(5); + + /* exit modulator (fb) reset */ + status = afe_write_byte(dev, ADC_FB_FRCRST_CH1, 0x07); + status = afe_write_byte(dev, ADC_FB_FRCRST_CH2, 0x07); + status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, 0x07); + + /* enable the pre_clamp in each channel for single-ended input */ + status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH1, 0xf0); + status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH2, 0xf0); + status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, 0xf0); + + /* use diode instead of resistor, so set term_en to 0, res_en to 0 */ + status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8, + ADC_QGAIN_RES_TRM_CH1, 3, 7, 0x00); + status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8, + ADC_QGAIN_RES_TRM_CH2, 3, 7, 0x00); + status = cx231xx_reg_mask_write(dev, AFE_DEVICE_ADDRESS, 8, + ADC_QGAIN_RES_TRM_CH3, 3, 7, 0x00); + + /* dynamic element matching off */ + status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH1, 0x03); + status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH2, 0x03); + status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, 0x03); + + return status; +} + +int cx231xx_afe_setup_AFE_for_baseband(struct cx231xx *dev) +{ + u8 c_value = 0; + int status = 0; + + status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH2, &c_value); + c_value &= (~(0x50)); + status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, c_value); + + return status; +} + +/* + The Analog Front End in Cx231xx has 3 channels. These + channels are used to share between different inputs + like tuner, s-video and composite inputs. + + channel 1 ----- pin 1 to pin4(in reg is 1-4) + channel 2 ----- pin 5 to pin8(in reg is 5-8) + channel 3 ----- pin 9 to pin 12(in reg is 9-11) +*/ +int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux) +{ + u8 ch1_setting = (u8) input_mux; + u8 ch2_setting = (u8) (input_mux >> 8); + u8 ch3_setting = (u8) (input_mux >> 16); + int status = 0; + u8 value = 0; + + if (ch1_setting != 0) { + status = afe_read_byte(dev, ADC_INPUT_CH1, &value); + value &= ~INPUT_SEL_MASK; + value |= (ch1_setting - 1) << 4; + value &= 0xff; + status = afe_write_byte(dev, ADC_INPUT_CH1, value); + } + + if (ch2_setting != 0) { + status = afe_read_byte(dev, ADC_INPUT_CH2, &value); + value &= ~INPUT_SEL_MASK; + value |= (ch2_setting - 1) << 4; + value &= 0xff; + status = afe_write_byte(dev, ADC_INPUT_CH2, value); + } + + /* For ch3_setting, the value to put in the register is + 7 less than the input number */ + if (ch3_setting != 0) { + status = afe_read_byte(dev, ADC_INPUT_CH3, &value); + value &= ~INPUT_SEL_MASK; + value |= (ch3_setting - 1) << 4; + value &= 0xff; + status = afe_write_byte(dev, ADC_INPUT_CH3, value); + } + + return status; +} + +int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode) +{ + int status = 0; + + /* + * FIXME: We need to implement the AFE code for LOW IF and for HI IF. + * Currently, only baseband works. + */ + + switch (mode) { + case AFE_MODE_LOW_IF: + cx231xx_Setup_AFE_for_LowIF(dev); + break; + case AFE_MODE_BASEBAND: + status = cx231xx_afe_setup_AFE_for_baseband(dev); + break; + case AFE_MODE_EU_HI_IF: + /* SetupAFEforEuHiIF(); */ + break; + case AFE_MODE_US_HI_IF: + /* SetupAFEforUsHiIF(); */ + break; + case AFE_MODE_JAPAN_HI_IF: + /* SetupAFEforJapanHiIF(); */ + break; + } + + if ((mode != dev->afe_mode) && + (dev->video_input == CX231XX_VMUX_TELEVISION)) + status = cx231xx_afe_adjust_ref_count(dev, + CX231XX_VMUX_TELEVISION); + + dev->afe_mode = mode; + + return status; +} + +int cx231xx_afe_update_power_control(struct cx231xx *dev, + enum AV_MODE avmode) +{ + u8 afe_power_status = 0; + int status = 0; + + switch (dev->model) { + case CX231XX_BOARD_CNXT_CARRAERA: + case CX231XX_BOARD_CNXT_RDE_250: + case CX231XX_BOARD_CNXT_SHELBY: + case CX231XX_BOARD_CNXT_RDU_250: + case CX231XX_BOARD_CNXT_RDE_253S: + case CX231XX_BOARD_CNXT_RDU_253S: + case CX231XX_BOARD_CNXT_VIDEO_GRABBER: + case CX231XX_BOARD_HAUPPAUGE_EXETER: + case CX231XX_BOARD_HAUPPAUGE_USBLIVE2: + case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: + if (avmode == POLARIS_AVMODE_ANALOGT_TV) { + while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | + FLD_PWRDN_ENABLE_PLL)) { + status = afe_write_byte(dev, SUP_BLK_PWRDN, + FLD_PWRDN_TUNING_BIAS | + FLD_PWRDN_ENABLE_PLL); + status |= afe_read_byte(dev, SUP_BLK_PWRDN, + &afe_power_status); + if (status < 0) + break; + } + + status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, + 0x00); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, + 0x00); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, + 0x00); + } else if (avmode == POLARIS_AVMODE_DIGITAL) { + status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, + 0x70); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, + 0x70); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, + 0x70); + + status |= afe_read_byte(dev, SUP_BLK_PWRDN, + &afe_power_status); + afe_power_status |= FLD_PWRDN_PD_BANDGAP | + FLD_PWRDN_PD_BIAS | + FLD_PWRDN_PD_TUNECK; + status |= afe_write_byte(dev, SUP_BLK_PWRDN, + afe_power_status); + } else if (avmode == POLARIS_AVMODE_ENXTERNAL_AV) { + while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | + FLD_PWRDN_ENABLE_PLL)) { + status = afe_write_byte(dev, SUP_BLK_PWRDN, + FLD_PWRDN_TUNING_BIAS | + FLD_PWRDN_ENABLE_PLL); + status |= afe_read_byte(dev, SUP_BLK_PWRDN, + &afe_power_status); + if (status < 0) + break; + } + + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, + 0x00); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, + 0x00); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, + 0x00); + } else { + cx231xx_info("Invalid AV mode input\n"); + status = -1; + } + break; + default: + if (avmode == POLARIS_AVMODE_ANALOGT_TV) { + while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | + FLD_PWRDN_ENABLE_PLL)) { + status = afe_write_byte(dev, SUP_BLK_PWRDN, + FLD_PWRDN_TUNING_BIAS | + FLD_PWRDN_ENABLE_PLL); + status |= afe_read_byte(dev, SUP_BLK_PWRDN, + &afe_power_status); + if (status < 0) + break; + } + + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, + 0x40); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, + 0x40); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, + 0x00); + } else if (avmode == POLARIS_AVMODE_DIGITAL) { + status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, + 0x70); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, + 0x70); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, + 0x70); + + status |= afe_read_byte(dev, SUP_BLK_PWRDN, + &afe_power_status); + afe_power_status |= FLD_PWRDN_PD_BANDGAP | + FLD_PWRDN_PD_BIAS | + FLD_PWRDN_PD_TUNECK; + status |= afe_write_byte(dev, SUP_BLK_PWRDN, + afe_power_status); + } else if (avmode == POLARIS_AVMODE_ENXTERNAL_AV) { + while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | + FLD_PWRDN_ENABLE_PLL)) { + status = afe_write_byte(dev, SUP_BLK_PWRDN, + FLD_PWRDN_TUNING_BIAS | + FLD_PWRDN_ENABLE_PLL); + status |= afe_read_byte(dev, SUP_BLK_PWRDN, + &afe_power_status); + if (status < 0) + break; + } + + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH1, + 0x00); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH2, + 0x00); + status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, + 0x40); + } else { + cx231xx_info("Invalid AV mode input\n"); + status = -1; + } + } /* switch */ + + return status; +} + +int cx231xx_afe_adjust_ref_count(struct cx231xx *dev, u32 video_input) +{ + u8 input_mode = 0; + u8 ntf_mode = 0; + int status = 0; + + dev->video_input = video_input; + + if (video_input == CX231XX_VMUX_TELEVISION) { + status = afe_read_byte(dev, ADC_INPUT_CH3, &input_mode); + status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, + &ntf_mode); + } else { + status = afe_read_byte(dev, ADC_INPUT_CH1, &input_mode); + status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH1, + &ntf_mode); + } + + input_mode = (ntf_mode & 0x3) | ((input_mode & 0x6) << 1); + + switch (input_mode) { + case SINGLE_ENDED: + dev->afe_ref_count = 0x23C; + break; + case LOW_IF: + dev->afe_ref_count = 0x24C; + break; + case EU_IF: + dev->afe_ref_count = 0x258; + break; + case US_IF: + dev->afe_ref_count = 0x260; + break; + default: + break; + } + + status = cx231xx_afe_init_super_block(dev, dev->afe_ref_count); + + return status; +} + +/****************************************************************************** + * V I D E O / A U D I O D E C O D E R C O N T R O L functions * + ******************************************************************************/ +static int vid_blk_write_byte(struct cx231xx *dev, u16 saddr, u8 data) +{ + return cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS, + saddr, 2, data, 1); +} + +static int vid_blk_read_byte(struct cx231xx *dev, u16 saddr, u8 *data) +{ + int status; + u32 temp = 0; + + status = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, + saddr, 2, &temp, 1); + *data = (u8) temp; + return status; +} + +static int vid_blk_write_word(struct cx231xx *dev, u16 saddr, u32 data) +{ + return cx231xx_write_i2c_data(dev, VID_BLK_I2C_ADDRESS, + saddr, 2, data, 4); +} + +static int vid_blk_read_word(struct cx231xx *dev, u16 saddr, u32 *data) +{ + return cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, + saddr, 2, data, 4); +} +int cx231xx_check_fw(struct cx231xx *dev) +{ + u8 temp = 0; + int status = 0; + status = vid_blk_read_byte(dev, DL_CTL_ADDRESS_LOW, &temp); + if (status < 0) + return status; + else + return temp; + +} + +int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input) +{ + int status = 0; + + switch (INPUT(input)->type) { + case CX231XX_VMUX_COMPOSITE1: + case CX231XX_VMUX_SVIDEO: + if ((dev->current_pcb_config.type == USB_BUS_POWER) && + (dev->power_mode != POLARIS_AVMODE_ENXTERNAL_AV)) { + /* External AV */ + status = cx231xx_set_power_mode(dev, + POLARIS_AVMODE_ENXTERNAL_AV); + if (status < 0) { + cx231xx_errdev("%s: set_power_mode : Failed to" + " set Power - errCode [%d]!\n", + __func__, status); + return status; + } + } + status = cx231xx_set_decoder_video_input(dev, + INPUT(input)->type, + INPUT(input)->vmux); + break; + case CX231XX_VMUX_TELEVISION: + case CX231XX_VMUX_CABLE: + if ((dev->current_pcb_config.type == USB_BUS_POWER) && + (dev->power_mode != POLARIS_AVMODE_ANALOGT_TV)) { + /* Tuner */ + status = cx231xx_set_power_mode(dev, + POLARIS_AVMODE_ANALOGT_TV); + if (status < 0) { + cx231xx_errdev("%s: set_power_mode:Failed" + " to set Power - errCode [%d]!\n", + __func__, status); + return status; + } + } + if (dev->tuner_type == TUNER_NXP_TDA18271) + status = cx231xx_set_decoder_video_input(dev, + CX231XX_VMUX_TELEVISION, + INPUT(input)->vmux); + else + status = cx231xx_set_decoder_video_input(dev, + CX231XX_VMUX_COMPOSITE1, + INPUT(input)->vmux); + + break; + default: + cx231xx_errdev("%s: set_power_mode : Unknown Input %d !\n", + __func__, INPUT(input)->type); + break; + } + + /* save the selection */ + dev->video_input = input; + + return status; +} + +int cx231xx_set_decoder_video_input(struct cx231xx *dev, + u8 pin_type, u8 input) +{ + int status = 0; + u32 value = 0; + + if (pin_type != dev->video_input) { + status = cx231xx_afe_adjust_ref_count(dev, pin_type); + if (status < 0) { + cx231xx_errdev("%s: adjust_ref_count :Failed to set" + "AFE input mux - errCode [%d]!\n", + __func__, status); + return status; + } + } + + /* call afe block to set video inputs */ + status = cx231xx_afe_set_input_mux(dev, input); + if (status < 0) { + cx231xx_errdev("%s: set_input_mux :Failed to set" + " AFE input mux - errCode [%d]!\n", + __func__, status); + return status; + } + + switch (pin_type) { + case CX231XX_VMUX_COMPOSITE1: + status = vid_blk_read_word(dev, AFE_CTRL, &value); + value |= (0 << 13) | (1 << 4); + value &= ~(1 << 5); + + /* set [24:23] [22:15] to 0 */ + value &= (~(0x1ff8000)); + /* set FUNC_MODE[24:23] = 2 IF_MOD[22:15] = 0 */ + value |= 0x1000000; + status = vid_blk_write_word(dev, AFE_CTRL, value); + + status = vid_blk_read_word(dev, OUT_CTRL1, &value); + value |= (1 << 7); + status = vid_blk_write_word(dev, OUT_CTRL1, value); + + /* Set output mode */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + OUT_CTRL1, + FLD_OUT_MODE, + dev->board.output_mode); + + /* Tell DIF object to go to baseband mode */ + status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND); + if (status < 0) { + cx231xx_errdev("%s: cx231xx_dif set to By pass" + " mode- errCode [%d]!\n", + __func__, status); + return status; + } + + /* Read the DFE_CTRL1 register */ + status = vid_blk_read_word(dev, DFE_CTRL1, &value); + + /* enable the VBI_GATE_EN */ + value |= FLD_VBI_GATE_EN; + + /* Enable the auto-VGA enable */ + value |= FLD_VGA_AUTO_EN; + + /* Write it back */ + status = vid_blk_write_word(dev, DFE_CTRL1, value); + + /* Disable auto config of registers */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + MODE_CTRL, FLD_ACFG_DIS, + cx231xx_set_field(FLD_ACFG_DIS, 1)); + + /* Set CVBS input mode */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + MODE_CTRL, FLD_INPUT_MODE, + cx231xx_set_field(FLD_INPUT_MODE, INPUT_MODE_CVBS_0)); + break; + case CX231XX_VMUX_SVIDEO: + /* Disable the use of DIF */ + + status = vid_blk_read_word(dev, AFE_CTRL, &value); + + /* set [24:23] [22:15] to 0 */ + value &= (~(0x1ff8000)); + /* set FUNC_MODE[24:23] = 2 + IF_MOD[22:15] = 0 DCR_BYP_CH2[4:4] = 1; */ + value |= 0x1000010; + status = vid_blk_write_word(dev, AFE_CTRL, value); + + /* Tell DIF object to go to baseband mode */ + status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND); + if (status < 0) { + cx231xx_errdev("%s: cx231xx_dif set to By pass" + " mode- errCode [%d]!\n", + __func__, status); + return status; + } + + /* Read the DFE_CTRL1 register */ + status = vid_blk_read_word(dev, DFE_CTRL1, &value); + + /* enable the VBI_GATE_EN */ + value |= FLD_VBI_GATE_EN; + + /* Enable the auto-VGA enable */ + value |= FLD_VGA_AUTO_EN; + + /* Write it back */ + status = vid_blk_write_word(dev, DFE_CTRL1, value); + + /* Disable auto config of registers */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + MODE_CTRL, FLD_ACFG_DIS, + cx231xx_set_field(FLD_ACFG_DIS, 1)); + + /* Set YC input mode */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + MODE_CTRL, + FLD_INPUT_MODE, + cx231xx_set_field(FLD_INPUT_MODE, INPUT_MODE_YC_1)); + + /* Chroma to ADC2 */ + status = vid_blk_read_word(dev, AFE_CTRL, &value); + value |= FLD_CHROMA_IN_SEL; /* set the chroma in select */ + + /* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8) + This sets them to use video + rather than audio. Only one of the two will be in use. */ + value &= ~(FLD_VGA_SEL_CH2 | FLD_VGA_SEL_CH3); + + status = vid_blk_write_word(dev, AFE_CTRL, value); + + status = cx231xx_afe_set_mode(dev, AFE_MODE_BASEBAND); + break; + case CX231XX_VMUX_TELEVISION: + case CX231XX_VMUX_CABLE: + default: + /* TODO: Test if this is also needed for xc2028/xc3028 */ + if (dev->board.tuner_type == TUNER_XC5000) { + /* Disable the use of DIF */ + + status = vid_blk_read_word(dev, AFE_CTRL, &value); + value |= (0 << 13) | (1 << 4); + value &= ~(1 << 5); + + /* set [24:23] [22:15] to 0 */ + value &= (~(0x1FF8000)); + /* set FUNC_MODE[24:23] = 2 IF_MOD[22:15] = 0 */ + value |= 0x1000000; + status = vid_blk_write_word(dev, AFE_CTRL, value); + + status = vid_blk_read_word(dev, OUT_CTRL1, &value); + value |= (1 << 7); + status = vid_blk_write_word(dev, OUT_CTRL1, value); + + /* Set output mode */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + OUT_CTRL1, FLD_OUT_MODE, + dev->board.output_mode); + + /* Tell DIF object to go to baseband mode */ + status = cx231xx_dif_set_standard(dev, + DIF_USE_BASEBAND); + if (status < 0) { + cx231xx_errdev("%s: cx231xx_dif set to By pass" + " mode- errCode [%d]!\n", + __func__, status); + return status; + } + + /* Read the DFE_CTRL1 register */ + status = vid_blk_read_word(dev, DFE_CTRL1, &value); + + /* enable the VBI_GATE_EN */ + value |= FLD_VBI_GATE_EN; + + /* Enable the auto-VGA enable */ + value |= FLD_VGA_AUTO_EN; + + /* Write it back */ + status = vid_blk_write_word(dev, DFE_CTRL1, value); + + /* Disable auto config of registers */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + MODE_CTRL, FLD_ACFG_DIS, + cx231xx_set_field(FLD_ACFG_DIS, 1)); + + /* Set CVBS input mode */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + MODE_CTRL, FLD_INPUT_MODE, + cx231xx_set_field(FLD_INPUT_MODE, + INPUT_MODE_CVBS_0)); + } else { + /* Enable the DIF for the tuner */ + + /* Reinitialize the DIF */ + status = cx231xx_dif_set_standard(dev, dev->norm); + if (status < 0) { + cx231xx_errdev("%s: cx231xx_dif set to By pass" + " mode- errCode [%d]!\n", + __func__, status); + return status; + } + + /* Make sure bypass is cleared */ + status = vid_blk_read_word(dev, DIF_MISC_CTRL, &value); + + /* Clear the bypass bit */ + value &= ~FLD_DIF_DIF_BYPASS; + + /* Enable the use of the DIF block */ + status = vid_blk_write_word(dev, DIF_MISC_CTRL, value); + + /* Read the DFE_CTRL1 register */ + status = vid_blk_read_word(dev, DFE_CTRL1, &value); + + /* Disable the VBI_GATE_EN */ + value &= ~FLD_VBI_GATE_EN; + + /* Enable the auto-VGA enable, AGC, and + set the skip count to 2 */ + value |= FLD_VGA_AUTO_EN | FLD_AGC_AUTO_EN | 0x00200000; + + /* Write it back */ + status = vid_blk_write_word(dev, DFE_CTRL1, value); + + /* Wait until AGC locks up */ + msleep(1); + + /* Disable the auto-VGA enable AGC */ + value &= ~(FLD_VGA_AUTO_EN); + + /* Write it back */ + status = vid_blk_write_word(dev, DFE_CTRL1, value); + + /* Enable Polaris B0 AGC output */ + status = vid_blk_read_word(dev, PIN_CTRL, &value); + value |= (FLD_OEF_AGC_RF) | + (FLD_OEF_AGC_IFVGA) | + (FLD_OEF_AGC_IF); + status = vid_blk_write_word(dev, PIN_CTRL, value); + + /* Set output mode */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + OUT_CTRL1, FLD_OUT_MODE, + dev->board.output_mode); + + /* Disable auto config of registers */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + MODE_CTRL, FLD_ACFG_DIS, + cx231xx_set_field(FLD_ACFG_DIS, 1)); + + /* Set CVBS input mode */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + MODE_CTRL, FLD_INPUT_MODE, + cx231xx_set_field(FLD_INPUT_MODE, + INPUT_MODE_CVBS_0)); + + /* Set some bits in AFE_CTRL so that channel 2 or 3 + * is ready to receive audio */ + /* Clear clamp for channels 2 and 3 (bit 16-17) */ + /* Clear droop comp (bit 19-20) */ + /* Set VGA_SEL (for audio control) (bit 7-8) */ + status = vid_blk_read_word(dev, AFE_CTRL, &value); + + /*Set Func mode:01-DIF 10-baseband 11-YUV*/ + value &= (~(FLD_FUNC_MODE)); + value |= 0x800000; + + value |= FLD_VGA_SEL_CH3 | FLD_VGA_SEL_CH2; + + status = vid_blk_write_word(dev, AFE_CTRL, value); + + if (dev->tuner_type == TUNER_NXP_TDA18271) { + status = vid_blk_read_word(dev, PIN_CTRL, + &value); + status = vid_blk_write_word(dev, PIN_CTRL, + (value & 0xFFFFFFEF)); + } + + break; + + } + break; + } + + /* Set raw VBI mode */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + OUT_CTRL1, FLD_VBIHACTRAW_EN, + cx231xx_set_field(FLD_VBIHACTRAW_EN, 1)); + + status = vid_blk_read_word(dev, OUT_CTRL1, &value); + if (value & 0x02) { + value |= (1 << 19); + status = vid_blk_write_word(dev, OUT_CTRL1, value); + } + + return status; +} + +void cx231xx_enable656(struct cx231xx *dev) +{ + u8 temp = 0; + int status; + /*enable TS1 data[0:7] as output to export 656*/ + + status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0xFF); + + /*enable TS1 clock as output to export 656*/ + + status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp); + temp = temp|0x04; + + status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp); + +} +EXPORT_SYMBOL_GPL(cx231xx_enable656); + +void cx231xx_disable656(struct cx231xx *dev) +{ + u8 temp = 0; + int status; + + + status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0x00); + + status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp); + temp = temp&0xFB; + + status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp); +} +EXPORT_SYMBOL_GPL(cx231xx_disable656); + +/* + * Handle any video-mode specific overrides that are different + * on a per video standards basis after touching the MODE_CTRL + * register which resets many values for autodetect + */ +int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev) +{ + int status = 0; + + cx231xx_info("do_mode_ctrl_overrides : 0x%x\n", + (unsigned int)dev->norm); + + /* Change the DFE_CTRL3 bp_percent to fix flagging */ + status = vid_blk_write_word(dev, DFE_CTRL3, 0xCD3F0280); + + if (dev->norm & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) { + cx231xx_info("do_mode_ctrl_overrides NTSC\n"); + + /* Move the close caption lines out of active video, + adjust the active video start point */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + VERT_TIM_CTRL, + FLD_VBLANK_CNT, 0x18); + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + VERT_TIM_CTRL, + FLD_VACTIVE_CNT, + 0x1E7000); + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + VERT_TIM_CTRL, + FLD_V656BLANK_CNT, + 0x1C000000); + + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + HORIZ_TIM_CTRL, + FLD_HBLANK_CNT, + cx231xx_set_field + (FLD_HBLANK_CNT, 0x79)); + + } else if (dev->norm & V4L2_STD_SECAM) { + cx231xx_info("do_mode_ctrl_overrides SECAM\n"); + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + VERT_TIM_CTRL, + FLD_VBLANK_CNT, 0x20); + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + VERT_TIM_CTRL, + FLD_VACTIVE_CNT, + cx231xx_set_field + (FLD_VACTIVE_CNT, + 0x244)); + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + VERT_TIM_CTRL, + FLD_V656BLANK_CNT, + cx231xx_set_field + (FLD_V656BLANK_CNT, + 0x24)); + /* Adjust the active video horizontal start point */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + HORIZ_TIM_CTRL, + FLD_HBLANK_CNT, + cx231xx_set_field + (FLD_HBLANK_CNT, 0x85)); + } else { + cx231xx_info("do_mode_ctrl_overrides PAL\n"); + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + VERT_TIM_CTRL, + FLD_VBLANK_CNT, 0x20); + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + VERT_TIM_CTRL, + FLD_VACTIVE_CNT, + cx231xx_set_field + (FLD_VACTIVE_CNT, + 0x244)); + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + VERT_TIM_CTRL, + FLD_V656BLANK_CNT, + cx231xx_set_field + (FLD_V656BLANK_CNT, + 0x24)); + /* Adjust the active video horizontal start point */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + HORIZ_TIM_CTRL, + FLD_HBLANK_CNT, + cx231xx_set_field + (FLD_HBLANK_CNT, 0x85)); + + } + + return status; +} + +int cx231xx_unmute_audio(struct cx231xx *dev) +{ + return vid_blk_write_byte(dev, PATH1_VOL_CTL, 0x24); +} +EXPORT_SYMBOL_GPL(cx231xx_unmute_audio); + +int stopAudioFirmware(struct cx231xx *dev) +{ + return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x03); +} + +int restartAudioFirmware(struct cx231xx *dev) +{ + return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x13); +} + +int cx231xx_set_audio_input(struct cx231xx *dev, u8 input) +{ + int status = 0; + enum AUDIO_INPUT ainput = AUDIO_INPUT_LINE; + + switch (INPUT(input)->amux) { + case CX231XX_AMUX_VIDEO: + ainput = AUDIO_INPUT_TUNER_TV; + break; + case CX231XX_AMUX_LINE_IN: + status = cx231xx_i2s_blk_set_audio_input(dev, input); + ainput = AUDIO_INPUT_LINE; + break; + default: + break; + } + + status = cx231xx_set_audio_decoder_input(dev, ainput); + + return status; +} + +int cx231xx_set_audio_decoder_input(struct cx231xx *dev, + enum AUDIO_INPUT audio_input) +{ + u32 dwval; + int status; + u8 gen_ctrl; + u32 value = 0; + + /* Put it in soft reset */ + status = vid_blk_read_byte(dev, GENERAL_CTL, &gen_ctrl); + gen_ctrl |= 1; + status = vid_blk_write_byte(dev, GENERAL_CTL, gen_ctrl); + + switch (audio_input) { + case AUDIO_INPUT_LINE: + /* setup AUD_IO control from Merlin paralle output */ + value = cx231xx_set_field(FLD_AUD_CHAN1_SRC, + AUD_CHAN_SRC_PARALLEL); + status = vid_blk_write_word(dev, AUD_IO_CTRL, value); + + /* setup input to Merlin, SRC2 connect to AC97 + bypass upsample-by-2, slave mode, sony mode, left justify + adr 091c, dat 01000000 */ + status = vid_blk_read_word(dev, AC97_CTL, &dwval); + + status = vid_blk_write_word(dev, AC97_CTL, + (dwval | FLD_AC97_UP2X_BYPASS)); + + /* select the parallel1 and SRC3 */ + status = vid_blk_write_word(dev, BAND_OUT_SEL, + cx231xx_set_field(FLD_SRC3_IN_SEL, 0x0) | + cx231xx_set_field(FLD_SRC3_CLK_SEL, 0x0) | + cx231xx_set_field(FLD_PARALLEL1_SRC_SEL, 0x0)); + + /* unmute all, AC97 in, independence mode + adr 08d0, data 0x00063073 */ + status = vid_blk_write_word(dev, DL_CTL, 0x3000001); + status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063073); + + /* set AVC maximum threshold, adr 08d4, dat ffff0024 */ + status = vid_blk_read_word(dev, PATH1_VOL_CTL, &dwval); + status = vid_blk_write_word(dev, PATH1_VOL_CTL, + (dwval | FLD_PATH1_AVC_THRESHOLD)); + + /* set SC maximum threshold, adr 08ec, dat ffffb3a3 */ + status = vid_blk_read_word(dev, PATH1_SC_CTL, &dwval); + status = vid_blk_write_word(dev, PATH1_SC_CTL, + (dwval | FLD_PATH1_SC_THRESHOLD)); + break; + + case AUDIO_INPUT_TUNER_TV: + default: + status = stopAudioFirmware(dev); + /* Setup SRC sources and clocks */ + status = vid_blk_write_word(dev, BAND_OUT_SEL, + cx231xx_set_field(FLD_SRC6_IN_SEL, 0x00) | + cx231xx_set_field(FLD_SRC6_CLK_SEL, 0x01) | + cx231xx_set_field(FLD_SRC5_IN_SEL, 0x00) | + cx231xx_set_field(FLD_SRC5_CLK_SEL, 0x02) | + cx231xx_set_field(FLD_SRC4_IN_SEL, 0x02) | + cx231xx_set_field(FLD_SRC4_CLK_SEL, 0x03) | + cx231xx_set_field(FLD_SRC3_IN_SEL, 0x00) | + cx231xx_set_field(FLD_SRC3_CLK_SEL, 0x00) | + cx231xx_set_field(FLD_BASEBAND_BYPASS_CTL, 0x00) | + cx231xx_set_field(FLD_AC97_SRC_SEL, 0x03) | + cx231xx_set_field(FLD_I2S_SRC_SEL, 0x00) | + cx231xx_set_field(FLD_PARALLEL2_SRC_SEL, 0x02) | + cx231xx_set_field(FLD_PARALLEL1_SRC_SEL, 0x01)); + + /* Setup the AUD_IO control */ + status = vid_blk_write_word(dev, AUD_IO_CTRL, + cx231xx_set_field(FLD_I2S_PORT_DIR, 0x00) | + cx231xx_set_field(FLD_I2S_OUT_SRC, 0x00) | + cx231xx_set_field(FLD_AUD_CHAN3_SRC, 0x00) | + cx231xx_set_field(FLD_AUD_CHAN2_SRC, 0x00) | + cx231xx_set_field(FLD_AUD_CHAN1_SRC, 0x03)); + + status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F063870); + + /* setAudioStandard(_audio_standard); */ + status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063870); + + status = restartAudioFirmware(dev); + + switch (dev->board.tuner_type) { + case TUNER_XC5000: + /* SIF passthrough at 28.6363 MHz sample rate */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + CHIP_CTRL, + FLD_SIF_EN, + cx231xx_set_field(FLD_SIF_EN, 1)); + break; + case TUNER_NXP_TDA18271: + /* Normal mode: SIF passthrough at 14.32 MHz */ + status = cx231xx_read_modify_write_i2c_dword(dev, + VID_BLK_I2C_ADDRESS, + CHIP_CTRL, + FLD_SIF_EN, + cx231xx_set_field(FLD_SIF_EN, 0)); + break; + default: + /* This is just a casual suggestion to people adding + new boards in case they use a tuner type we don't + currently know about */ + printk(KERN_INFO "Unknown tuner type configuring SIF"); + break; + } + break; + + case AUDIO_INPUT_TUNER_FM: + /* use SIF for FM radio + setupFM(); + setAudioStandard(_audio_standard); + */ + break; + + case AUDIO_INPUT_MUTE: + status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F011012); + break; + } + + /* Take it out of soft reset */ + status = vid_blk_read_byte(dev, GENERAL_CTL, &gen_ctrl); + gen_ctrl &= ~1; + status = vid_blk_write_byte(dev, GENERAL_CTL, gen_ctrl); + + return status; +} + +/****************************************************************************** + * C H I P Specific C O N T R O L functions * + ******************************************************************************/ +int cx231xx_init_ctrl_pin_status(struct cx231xx *dev) +{ + u32 value; + int status = 0; + + status = vid_blk_read_word(dev, PIN_CTRL, &value); + value |= (~dev->board.ctl_pin_status_mask); + status = vid_blk_write_word(dev, PIN_CTRL, value); + + return status; +} + +int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev, + u8 analog_or_digital) +{ + int status = 0; + + /* first set the direction to output */ + status = cx231xx_set_gpio_direction(dev, + dev->board. + agc_analog_digital_select_gpio, 1); + + /* 0 - demod ; 1 - Analog mode */ + status = cx231xx_set_gpio_value(dev, + dev->board.agc_analog_digital_select_gpio, + analog_or_digital); + + return status; +} + +int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3) +{ + u8 value[4] = { 0, 0, 0, 0 }; + int status = 0; + bool current_is_port_3; + + if (dev->board.dont_use_port_3) + is_port_3 = false; + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, + PWR_CTL_EN, value, 4); + if (status < 0) + return status; + + current_is_port_3 = value[0] & I2C_DEMOD_EN ? true : false; + + /* Just return, if already using the right port */ + if (current_is_port_3 == is_port_3) + return 0; + + if (is_port_3) + value[0] |= I2C_DEMOD_EN; + else + value[0] &= ~I2C_DEMOD_EN; + + cx231xx_info("Changing the i2c master port to %d\n", + is_port_3 ? 3 : 1); + + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + + return status; + +} +EXPORT_SYMBOL_GPL(cx231xx_enable_i2c_port_3); + +void update_HH_register_after_set_DIF(struct cx231xx *dev) +{ +/* + u8 status = 0; + u32 value = 0; + + vid_blk_write_word(dev, PIN_CTRL, 0xA0FFF82F); + vid_blk_write_word(dev, DIF_MISC_CTRL, 0x0A203F11); + vid_blk_write_word(dev, DIF_SRC_PHASE_INC, 0x1BEFBF06); + + status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); + vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390); + status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); +*/ +} + +void cx231xx_dump_HH_reg(struct cx231xx *dev) +{ + u8 status = 0; + u32 value = 0; + u16 i = 0; + + value = 0x45005390; + status = vid_blk_write_word(dev, 0x104, value); + + for (i = 0x100; i < 0x140; i++) { + status = vid_blk_read_word(dev, i, &value); + cx231xx_info("reg0x%x=0x%x\n", i, value); + i = i+3; + } + + for (i = 0x300; i < 0x400; i++) { + status = vid_blk_read_word(dev, i, &value); + cx231xx_info("reg0x%x=0x%x\n", i, value); + i = i+3; + } + + for (i = 0x400; i < 0x440; i++) { + status = vid_blk_read_word(dev, i, &value); + cx231xx_info("reg0x%x=0x%x\n", i, value); + i = i+3; + } + + status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); + cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); + vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390); + status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); + cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); +} + +void cx231xx_dump_SC_reg(struct cx231xx *dev) +{ + u8 value[4] = { 0, 0, 0, 0 }; + int status = 0; + cx231xx_info("cx231xx_dump_SC_reg!\n"); + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", BOARD_CFG_STAT, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS_MODE_REG, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_CFG_REG, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_LENGTH_REG, value[0], + value[1], value[2], value[3]); + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_CFG_REG, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_LENGTH_REG, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", EP_MODE_SET, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN1, value[0], + value[1], value[2], value[3]); + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN2, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN3, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK0, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK1, value[0], + value[1], value[2], value[3]); + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK2, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_GAIN, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_CAR_REG, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG1, value[0], + value[1], value[2], value[3]); + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG2, value[0], + value[1], value[2], value[3]); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, + value, 4); + cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, value[0], + value[1], value[2], value[3]); + + +} + +void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev) + +{ + u8 status = 0; + u8 value = 0; + + + + status = afe_read_byte(dev, ADC_STATUS2_CH3, &value); + value = (value & 0xFE)|0x01; + status = afe_write_byte(dev, ADC_STATUS2_CH3, value); + + status = afe_read_byte(dev, ADC_STATUS2_CH3, &value); + value = (value & 0xFE)|0x00; + status = afe_write_byte(dev, ADC_STATUS2_CH3, value); + + +/* + config colibri to lo-if mode + + FIXME: ntf_mode = 2'b00 by default. But set 0x1 would reduce + the diff IF input by half, + + for low-if agc defect +*/ + + status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, &value); + value = (value & 0xFC)|0x00; + status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, value); + + status = afe_read_byte(dev, ADC_INPUT_CH3, &value); + value = (value & 0xF9)|0x02; + status = afe_write_byte(dev, ADC_INPUT_CH3, value); + + status = afe_read_byte(dev, ADC_FB_FRCRST_CH3, &value); + value = (value & 0xFB)|0x04; + status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, value); + + status = afe_read_byte(dev, ADC_DCSERVO_DEM_CH3, &value); + value = (value & 0xFC)|0x03; + status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, value); + + status = afe_read_byte(dev, ADC_CTRL_DAC1_CH3, &value); + value = (value & 0xFB)|0x04; + status = afe_write_byte(dev, ADC_CTRL_DAC1_CH3, value); + + status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value); + value = (value & 0xF8)|0x06; + status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value); + + status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value); + value = (value & 0x8F)|0x40; + status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value); + + status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH3, &value); + value = (value & 0xDF)|0x20; + status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, value); +} + +void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq, + u8 spectral_invert, u32 mode) +{ + u32 colibri_carrier_offset = 0; + u8 status = 0; + u32 func_mode = 0x01; /* Device has a DIF if this function is called */ + u32 standard = 0; + u8 value[4] = { 0, 0, 0, 0 }; + + cx231xx_info("Enter cx231xx_set_Colibri_For_LowIF()\n"); + value[0] = (u8) 0x6F; + value[1] = (u8) 0x6F; + value[2] = (u8) 0x6F; + value[3] = (u8) 0x6F; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + + /*Set colibri for low IF*/ + status = cx231xx_afe_set_mode(dev, AFE_MODE_LOW_IF); + + /* Set C2HH for low IF operation.*/ + standard = dev->norm; + status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode, + func_mode, standard); + + /* Get colibri offsets.*/ + colibri_carrier_offset = cx231xx_Get_Colibri_CarrierOffset(mode, + standard); + + cx231xx_info("colibri_carrier_offset=%d, standard=0x%x\n", + colibri_carrier_offset, standard); + + /* Set the band Pass filter for DIF*/ + cx231xx_set_DIF_bandpass(dev, (if_freq+colibri_carrier_offset), + spectral_invert, mode); +} + +u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd) +{ + u32 colibri_carrier_offset = 0; + + if (mode == TUNER_MODE_FM_RADIO) { + colibri_carrier_offset = 1100000; + } else if (standerd & (V4L2_STD_MN | V4L2_STD_NTSC_M_JP)) { + colibri_carrier_offset = 4832000; /*4.83MHz */ + } else if (standerd & (V4L2_STD_PAL_B | V4L2_STD_PAL_G)) { + colibri_carrier_offset = 2700000; /*2.70MHz */ + } else if (standerd & (V4L2_STD_PAL_D | V4L2_STD_PAL_I + | V4L2_STD_SECAM)) { + colibri_carrier_offset = 2100000; /*2.10MHz */ + } + + return colibri_carrier_offset; +} + +void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq, + u8 spectral_invert, u32 mode) +{ + unsigned long pll_freq_word; + int status = 0; + u32 dif_misc_ctrl_value = 0; + u64 pll_freq_u64 = 0; + u32 i = 0; + + cx231xx_info("if_freq=%d;spectral_invert=0x%x;mode=0x%x\n", + if_freq, spectral_invert, mode); + + + if (mode == TUNER_MODE_FM_RADIO) { + pll_freq_word = 0x905A1CAC; + status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word); + + } else /*KSPROPERTY_TUNER_MODE_TV*/{ + /* Calculate the PLL frequency word based on the adjusted if_freq*/ + pll_freq_word = if_freq; + pll_freq_u64 = (u64)pll_freq_word << 28L; + do_div(pll_freq_u64, 50000000); + pll_freq_word = (u32)pll_freq_u64; + /*pll_freq_word = 0x3463497;*/ + status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word); + + if (spectral_invert) { + if_freq -= 400000; + /* Enable Spectral Invert*/ + status = vid_blk_read_word(dev, DIF_MISC_CTRL, + &dif_misc_ctrl_value); + dif_misc_ctrl_value = dif_misc_ctrl_value | 0x00200000; + status = vid_blk_write_word(dev, DIF_MISC_CTRL, + dif_misc_ctrl_value); + } else { + if_freq += 400000; + /* Disable Spectral Invert*/ + status = vid_blk_read_word(dev, DIF_MISC_CTRL, + &dif_misc_ctrl_value); + dif_misc_ctrl_value = dif_misc_ctrl_value & 0xFFDFFFFF; + status = vid_blk_write_word(dev, DIF_MISC_CTRL, + dif_misc_ctrl_value); + } + + if_freq = (if_freq/100000)*100000; + + if (if_freq < 3000000) + if_freq = 3000000; + + if (if_freq > 16000000) + if_freq = 16000000; + } + + cx231xx_info("Enter IF=%zd\n", + sizeof(Dif_set_array)/sizeof(struct dif_settings)); + for (i = 0; i < sizeof(Dif_set_array)/sizeof(struct dif_settings); i++) { + if (Dif_set_array[i].if_freq == if_freq) { + status = vid_blk_write_word(dev, + Dif_set_array[i].register_address, Dif_set_array[i].value); + } + } +} + +/****************************************************************************** + * D I F - B L O C K C O N T R O L functions * + ******************************************************************************/ +int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode, + u32 function_mode, u32 standard) +{ + int status = 0; + + + if (mode == V4L2_TUNER_RADIO) { + /* C2HH */ + /* lo if big signal */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1); + /* FUNC_MODE = DIF */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 23, 24, function_mode); + /* IF_MODE */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xFF); + /* no inv */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1); + } else if (standard != DIF_USE_BASEBAND) { + if (standard & V4L2_STD_MN) { + /* lo if big signal */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1); + /* FUNC_MODE = DIF */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 23, 24, + function_mode); + /* IF_MODE */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xb); + /* no inv */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1); + /* 0x124, AUD_CHAN1_SRC = 0x3 */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AUD_IO_CTRL, 0, 31, 0x00000003); + } else if ((standard == V4L2_STD_PAL_I) | + (standard & V4L2_STD_PAL_D) | + (standard & V4L2_STD_SECAM)) { + /* C2HH setup */ + /* lo if big signal */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1); + /* FUNC_MODE = DIF */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 23, 24, + function_mode); + /* IF_MODE */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xF); + /* no inv */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1); + } else { + /* default PAL BG */ + /* C2HH setup */ + /* lo if big signal */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 30, 31, 0x1); + /* FUNC_MODE = DIF */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 23, 24, + function_mode); + /* IF_MODE */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 15, 22, 0xE); + /* no inv */ + status = cx231xx_reg_mask_write(dev, + VID_BLK_I2C_ADDRESS, 32, + AFE_CTRL_C2HH_SRC_CTRL, 9, 9, 0x1); + } + } + + return status; +} + +int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard) +{ + int status = 0; + u32 dif_misc_ctrl_value = 0; + u32 func_mode = 0; + + cx231xx_info("%s: setStandard to %x\n", __func__, standard); + + status = vid_blk_read_word(dev, DIF_MISC_CTRL, &dif_misc_ctrl_value); + if (standard != DIF_USE_BASEBAND) + dev->norm = standard; + + switch (dev->model) { + case CX231XX_BOARD_CNXT_CARRAERA: + case CX231XX_BOARD_CNXT_RDE_250: + case CX231XX_BOARD_CNXT_SHELBY: + case CX231XX_BOARD_CNXT_RDU_250: + case CX231XX_BOARD_CNXT_VIDEO_GRABBER: + case CX231XX_BOARD_HAUPPAUGE_EXETER: + func_mode = 0x03; + break; + case CX231XX_BOARD_CNXT_RDE_253S: + case CX231XX_BOARD_CNXT_RDU_253S: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: + func_mode = 0x01; + break; + default: + func_mode = 0x01; + } + + status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode, + func_mode, standard); + + if (standard == DIF_USE_BASEBAND) { /* base band */ + /* There is a different SRC_PHASE_INC value + for baseband vs. DIF */ + status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, 0xDF7DF83); + status = vid_blk_read_word(dev, DIF_MISC_CTRL, + &dif_misc_ctrl_value); + dif_misc_ctrl_value |= FLD_DIF_DIF_BYPASS; + status = vid_blk_write_word(dev, DIF_MISC_CTRL, + dif_misc_ctrl_value); + } else if (standard & V4L2_STD_PAL_D) { + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL, 0, 31, 0x6503bc0c); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL1, 0, 31, 0xbd038c85); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL2, 0, 31, 0x1db4640a); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL3, 0, 31, 0x00008800); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_REF, 0, 31, 0x444C1380); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_IF, 0, 31, 0xDA302600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_INT, 0, 31, 0xDA261700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_RF, 0, 31, 0xDA262600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_INT_CURRENT, 0, 31, + 0x26001700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_RF_CURRENT, 0, 31, + 0x00002660); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VIDEO_AGC_CTRL, 0, 31, + 0x72500800); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VID_AUD_OVERRIDE, 0, 31, + 0x27000100); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AV_SEP_CTRL, 0, 31, 0x3F3934EA); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_COMP_FLT_CTRL, 0, 31, + 0x00000000); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_PHASE_INC, 0, 31, + 0x1befbf06); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_GAIN_CONTROL, 0, 31, + 0x000035e8); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_RPT_VARIANCE, 0, 31, 0x00000000); + /* Save the Spec Inversion value */ + dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; + dif_misc_ctrl_value |= 0x3a023F11; + } else if (standard & V4L2_STD_PAL_I) { + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL, 0, 31, 0x6503bc0c); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL1, 0, 31, 0xbd038c85); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL2, 0, 31, 0x1db4640a); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL3, 0, 31, 0x00008800); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_REF, 0, 31, 0x444C1380); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_IF, 0, 31, 0xDA302600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_INT, 0, 31, 0xDA261700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_RF, 0, 31, 0xDA262600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_INT_CURRENT, 0, 31, + 0x26001700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_RF_CURRENT, 0, 31, + 0x00002660); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VIDEO_AGC_CTRL, 0, 31, + 0x72500800); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VID_AUD_OVERRIDE, 0, 31, + 0x27000100); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AV_SEP_CTRL, 0, 31, 0x5F39A934); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_COMP_FLT_CTRL, 0, 31, + 0x00000000); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_PHASE_INC, 0, 31, + 0x1befbf06); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_GAIN_CONTROL, 0, 31, + 0x000035e8); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_RPT_VARIANCE, 0, 31, 0x00000000); + /* Save the Spec Inversion value */ + dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; + dif_misc_ctrl_value |= 0x3a033F11; + } else if (standard & V4L2_STD_PAL_M) { + /* improved Low Frequency Phase Noise */ + status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0xFF01FF0C); + status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xbd038c85); + status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1db4640a); + status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800); + status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C1380); + status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT, + 0x26001700); + status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT, + 0x00002660); + status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL, + 0x72500800); + status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE, + 0x27000100); + status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, 0x012c405d); + status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL, + 0x009f50c1); + status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, + 0x1befbf06); + status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL, + 0x000035e8); + status = vid_blk_write_word(dev, DIF_SOFT_RST_CTRL_REVB, + 0x00000000); + /* Save the Spec Inversion value */ + dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; + dif_misc_ctrl_value |= 0x3A0A3F10; + } else if (standard & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) { + /* improved Low Frequency Phase Noise */ + status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0xFF01FF0C); + status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xbd038c85); + status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1db4640a); + status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800); + status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C1380); + status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT, + 0x26001700); + status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT, + 0x00002660); + status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL, + 0x72500800); + status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE, + 0x27000100); + status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, + 0x012c405d); + status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL, + 0x009f50c1); + status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, + 0x1befbf06); + status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL, + 0x000035e8); + status = vid_blk_write_word(dev, DIF_SOFT_RST_CTRL_REVB, + 0x00000000); + /* Save the Spec Inversion value */ + dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; + dif_misc_ctrl_value = 0x3A093F10; + } else if (standard & + (V4L2_STD_SECAM_B | V4L2_STD_SECAM_D | V4L2_STD_SECAM_G | + V4L2_STD_SECAM_K | V4L2_STD_SECAM_K1)) { + + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL, 0, 31, 0x6503bc0c); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL1, 0, 31, 0xbd038c85); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL2, 0, 31, 0x1db4640a); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL3, 0, 31, 0x00008800); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_REF, 0, 31, 0x888C0380); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_IF, 0, 31, 0xe0262600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_INT, 0, 31, 0xc2171700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_RF, 0, 31, 0xc2262600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_INT_CURRENT, 0, 31, + 0x26001700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_RF_CURRENT, 0, 31, + 0x00002660); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VID_AUD_OVERRIDE, 0, 31, + 0x27000100); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AV_SEP_CTRL, 0, 31, 0x3F3530ec); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_COMP_FLT_CTRL, 0, 31, + 0x00000000); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_PHASE_INC, 0, 31, + 0x1befbf06); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_GAIN_CONTROL, 0, 31, + 0x000035e8); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_RPT_VARIANCE, 0, 31, 0x00000000); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VIDEO_AGC_CTRL, 0, 31, + 0xf4000000); + + /* Save the Spec Inversion value */ + dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; + dif_misc_ctrl_value |= 0x3a023F11; + } else if (standard & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) { + /* Is it SECAM_L1? */ + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL, 0, 31, 0x6503bc0c); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL1, 0, 31, 0xbd038c85); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL2, 0, 31, 0x1db4640a); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL3, 0, 31, 0x00008800); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_REF, 0, 31, 0x888C0380); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_IF, 0, 31, 0xe0262600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_INT, 0, 31, 0xc2171700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_RF, 0, 31, 0xc2262600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_INT_CURRENT, 0, 31, + 0x26001700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_RF_CURRENT, 0, 31, + 0x00002660); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VID_AUD_OVERRIDE, 0, 31, + 0x27000100); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AV_SEP_CTRL, 0, 31, 0x3F3530ec); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_COMP_FLT_CTRL, 0, 31, + 0x00000000); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_PHASE_INC, 0, 31, + 0x1befbf06); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_GAIN_CONTROL, 0, 31, + 0x000035e8); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_RPT_VARIANCE, 0, 31, 0x00000000); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VIDEO_AGC_CTRL, 0, 31, + 0xf2560000); + + /* Save the Spec Inversion value */ + dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; + dif_misc_ctrl_value |= 0x3a023F11; + + } else if (standard & V4L2_STD_NTSC_M) { + /* V4L2_STD_NTSC_M (75 IRE Setup) Or + V4L2_STD_NTSC_M_JP (Japan, 0 IRE Setup) */ + + /* For NTSC the centre frequency of video coming out of + sidewinder is around 7.1MHz or 3.6MHz depending on the + spectral inversion. so for a non spectrally inverted channel + the pll freq word is 0x03420c49 + */ + + status = vid_blk_write_word(dev, DIF_PLL_CTRL, 0x6503BC0C); + status = vid_blk_write_word(dev, DIF_PLL_CTRL1, 0xBD038C85); + status = vid_blk_write_word(dev, DIF_PLL_CTRL2, 0x1DB4640A); + status = vid_blk_write_word(dev, DIF_PLL_CTRL3, 0x00008800); + status = vid_blk_write_word(dev, DIF_AGC_IF_REF, 0x444C0380); + status = vid_blk_write_word(dev, DIF_AGC_IF_INT_CURRENT, + 0x26001700); + status = vid_blk_write_word(dev, DIF_AGC_RF_CURRENT, + 0x00002660); + status = vid_blk_write_word(dev, DIF_VIDEO_AGC_CTRL, + 0x04000800); + status = vid_blk_write_word(dev, DIF_VID_AUD_OVERRIDE, + 0x27000100); + status = vid_blk_write_word(dev, DIF_AV_SEP_CTRL, 0x01296e1f); + + status = vid_blk_write_word(dev, DIF_COMP_FLT_CTRL, + 0x009f50c1); + status = vid_blk_write_word(dev, DIF_SRC_PHASE_INC, + 0x1befbf06); + status = vid_blk_write_word(dev, DIF_SRC_GAIN_CONTROL, + 0x000035e8); + + status = vid_blk_write_word(dev, DIF_AGC_CTRL_IF, 0xC2262600); + status = vid_blk_write_word(dev, DIF_AGC_CTRL_INT, + 0xC2262600); + status = vid_blk_write_word(dev, DIF_AGC_CTRL_RF, 0xC2262600); + + /* Save the Spec Inversion value */ + dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; + dif_misc_ctrl_value |= 0x3a003F10; + } else { + /* default PAL BG */ + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL, 0, 31, 0x6503bc0c); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL1, 0, 31, 0xbd038c85); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL2, 0, 31, 0x1db4640a); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_PLL_CTRL3, 0, 31, 0x00008800); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_REF, 0, 31, 0x444C1380); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_IF, 0, 31, 0xDA302600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_INT, 0, 31, 0xDA261700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_CTRL_RF, 0, 31, 0xDA262600); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_IF_INT_CURRENT, 0, 31, + 0x26001700); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AGC_RF_CURRENT, 0, 31, + 0x00002660); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VIDEO_AGC_CTRL, 0, 31, + 0x72500800); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_VID_AUD_OVERRIDE, 0, 31, + 0x27000100); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_AV_SEP_CTRL, 0, 31, 0x3F3530EC); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_COMP_FLT_CTRL, 0, 31, + 0x00A653A8); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_PHASE_INC, 0, 31, + 0x1befbf06); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_SRC_GAIN_CONTROL, 0, 31, + 0x000035e8); + status = cx231xx_reg_mask_write(dev, VID_BLK_I2C_ADDRESS, 32, + DIF_RPT_VARIANCE, 0, 31, 0x00000000); + /* Save the Spec Inversion value */ + dif_misc_ctrl_value &= FLD_DIF_SPEC_INV; + dif_misc_ctrl_value |= 0x3a013F11; + } + + /* The AGC values should be the same for all standards, + AUD_SRC_SEL[19] should always be disabled */ + dif_misc_ctrl_value &= ~FLD_DIF_AUD_SRC_SEL; + + /* It is still possible to get Set Standard calls even when we + are in FM mode. + This is done to override the value for FM. */ + if (dev->active_mode == V4L2_TUNER_RADIO) + dif_misc_ctrl_value = 0x7a080000; + + /* Write the calculated value for misc ontrol register */ + status = vid_blk_write_word(dev, DIF_MISC_CTRL, dif_misc_ctrl_value); + + return status; +} + +int cx231xx_tuner_pre_channel_change(struct cx231xx *dev) +{ + int status = 0; + u32 dwval; + + /* Set the RF and IF k_agc values to 3 */ + status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval); + dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF); + dwval |= 0x33000000; + + status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval); + + return status; +} + +int cx231xx_tuner_post_channel_change(struct cx231xx *dev) +{ + int status = 0; + u32 dwval; + cx231xx_info("cx231xx_tuner_post_channel_change dev->tuner_type =0%d\n", + dev->tuner_type); + /* Set the RF and IF k_agc values to 4 for PAL/NTSC and 8 for + * SECAM L/B/D standards */ + status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval); + dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF); + + if (dev->norm & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_B | + V4L2_STD_SECAM_D)) { + if (dev->tuner_type == TUNER_NXP_TDA18271) { + dwval &= ~FLD_DIF_IF_REF; + dwval |= 0x88000300; + } else + dwval |= 0x88000000; + } else { + if (dev->tuner_type == TUNER_NXP_TDA18271) { + dwval &= ~FLD_DIF_IF_REF; + dwval |= 0xCC000300; + } else + dwval |= 0x44000000; + } + + status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval); + + return status; +} + +/****************************************************************************** + * I 2 S - B L O C K C O N T R O L functions * + ******************************************************************************/ +int cx231xx_i2s_blk_initialize(struct cx231xx *dev) +{ + int status = 0; + u32 value; + + status = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, + CH_PWR_CTRL1, 1, &value, 1); + /* enables clock to delta-sigma and decimation filter */ + value |= 0x80; + status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, + CH_PWR_CTRL1, 1, value, 1); + /* power up all channel */ + status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, + CH_PWR_CTRL2, 1, 0x00, 1); + + return status; +} + +int cx231xx_i2s_blk_update_power_control(struct cx231xx *dev, + enum AV_MODE avmode) +{ + int status = 0; + u32 value = 0; + + if (avmode != POLARIS_AVMODE_ENXTERNAL_AV) { + status = cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, + CH_PWR_CTRL2, 1, &value, 1); + value |= 0xfe; + status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, + CH_PWR_CTRL2, 1, value, 1); + } else { + status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, + CH_PWR_CTRL2, 1, 0x00, 1); + } + + return status; +} + +/* set i2s_blk for audio input types */ +int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input) +{ + int status = 0; + + switch (audio_input) { + case CX231XX_AMUX_LINE_IN: + status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, + CH_PWR_CTRL2, 1, 0x00, 1); + status = cx231xx_write_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, + CH_PWR_CTRL1, 1, 0x80, 1); + break; + case CX231XX_AMUX_VIDEO: + default: + break; + } + + dev->ctl_ainput = audio_input; + + return status; +} + +/****************************************************************************** + * P O W E R C O N T R O L functions * + ******************************************************************************/ +int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode) +{ + u8 value[4] = { 0, 0, 0, 0 }; + u32 tmp = 0; + int status = 0; + + if (dev->power_mode != mode) + dev->power_mode = mode; + else { + cx231xx_info(" setPowerMode::mode = %d, No Change req.\n", + mode); + return 0; + } + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value, + 4); + if (status < 0) + return status; + + tmp = *((u32 *) value); + + switch (mode) { + case POLARIS_AVMODE_ENXTERNAL_AV: + + tmp &= (~PWR_MODE_MASK); + + tmp |= PWR_AV_EN; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + + tmp |= PWR_ISO_EN; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = + cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN, + value, 4); + msleep(PWR_SLEEP_INTERVAL); + + tmp |= POLARIS_AVMODE_ENXTERNAL_AV; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + + /* reset state of xceive tuner */ + dev->xc_fw_load_done = 0; + break; + + case POLARIS_AVMODE_ANALOGT_TV: + + tmp |= PWR_DEMOD_EN; + tmp |= (I2C_DEMOD_EN); + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + + if (!(tmp & PWR_TUNER_EN)) { + tmp |= (PWR_TUNER_EN); + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + } + + if (!(tmp & PWR_AV_EN)) { + tmp |= PWR_AV_EN; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + } + if (!(tmp & PWR_ISO_EN)) { + tmp |= PWR_ISO_EN; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + } + + if (!(tmp & POLARIS_AVMODE_ANALOGT_TV)) { + tmp |= POLARIS_AVMODE_ANALOGT_TV; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + } + + if (dev->board.tuner_type != TUNER_ABSENT) { + /* Enable tuner */ + cx231xx_enable_i2c_port_3(dev, true); + + /* reset the Tuner */ + if (dev->board.tuner_gpio) + cx231xx_gpio_set(dev, dev->board.tuner_gpio); + + if (dev->cx231xx_reset_analog_tuner) + dev->cx231xx_reset_analog_tuner(dev); + } + + break; + + case POLARIS_AVMODE_DIGITAL: + if (!(tmp & PWR_TUNER_EN)) { + tmp |= (PWR_TUNER_EN); + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + } + if (!(tmp & PWR_AV_EN)) { + tmp |= PWR_AV_EN; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + } + if (!(tmp & PWR_ISO_EN)) { + tmp |= PWR_ISO_EN; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + } + + tmp &= (~PWR_AV_MODE); + tmp |= POLARIS_AVMODE_DIGITAL | I2C_DEMOD_EN; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + + if (!(tmp & PWR_DEMOD_EN)) { + tmp |= PWR_DEMOD_EN; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + } + + if (dev->board.tuner_type != TUNER_ABSENT) { + /* + * Enable tuner + * Hauppauge Exeter seems to need to do something different! + */ + if (dev->model == CX231XX_BOARD_HAUPPAUGE_EXETER) + cx231xx_enable_i2c_port_3(dev, false); + else + cx231xx_enable_i2c_port_3(dev, true); + + /* reset the Tuner */ + if (dev->board.tuner_gpio) + cx231xx_gpio_set(dev, dev->board.tuner_gpio); + + if (dev->cx231xx_reset_analog_tuner) + dev->cx231xx_reset_analog_tuner(dev); + } + break; + + default: + break; + } + + msleep(PWR_SLEEP_INTERVAL); + + /* For power saving, only enable Pwr_resetout_n + when digital TV is selected. */ + if (mode == POLARIS_AVMODE_DIGITAL) { + tmp |= PWR_RESETOUT_EN; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(PWR_SLEEP_INTERVAL); + } + + /* update power control for afe */ + status = cx231xx_afe_update_power_control(dev, mode); + + /* update power control for i2s_blk */ + status = cx231xx_i2s_blk_update_power_control(dev, mode); + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value, + 4); + + return status; +} + +int cx231xx_power_suspend(struct cx231xx *dev) +{ + u8 value[4] = { 0, 0, 0, 0 }; + u32 tmp = 0; + int status = 0; + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, + value, 4); + if (status > 0) + return status; + + tmp = *((u32 *) value); + tmp &= (~PWR_MODE_MASK); + + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN, + value, 4); + + return status; +} + +/****************************************************************************** + * S T R E A M C O N T R O L functions * + ******************************************************************************/ +int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask) +{ + u8 value[4] = { 0x0, 0x0, 0x0, 0x0 }; + u32 tmp = 0; + int status = 0; + + cx231xx_info("cx231xx_start_stream():: ep_mask = %x\n", ep_mask); + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET, + value, 4); + if (status < 0) + return status; + + tmp = *((u32 *) value); + tmp |= ep_mask; + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, EP_MODE_SET, + value, 4); + + return status; +} + +int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask) +{ + u8 value[4] = { 0x0, 0x0, 0x0, 0x0 }; + u32 tmp = 0; + int status = 0; + + cx231xx_info("cx231xx_stop_stream():: ep_mask = %x\n", ep_mask); + status = + cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET, value, 4); + if (status < 0) + return status; + + tmp = *((u32 *) value); + tmp &= (~ep_mask); + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, EP_MODE_SET, + value, 4); + + return status; +} + +int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type) +{ + int status = 0; + u32 value = 0; + u8 val[4] = { 0, 0, 0, 0 }; + + if (dev->udev->speed == USB_SPEED_HIGH) { + switch (media_type) { + case 81: /* audio */ + cx231xx_info("%s: Audio enter HANC\n", __func__); + status = + cx231xx_mode_register(dev, TS_MODE_REG, 0x9300); + break; + + case 2: /* vbi */ + cx231xx_info("%s: set vanc registers\n", __func__); + status = cx231xx_mode_register(dev, TS_MODE_REG, 0x300); + break; + + case 3: /* sliced cc */ + cx231xx_info("%s: set hanc registers\n", __func__); + status = + cx231xx_mode_register(dev, TS_MODE_REG, 0x1300); + break; + + case 0: /* video */ + cx231xx_info("%s: set video registers\n", __func__); + status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100); + break; + + case 4: /* ts1 */ + cx231xx_info("%s: set ts1 registers", __func__); + + if (dev->board.has_417) { + cx231xx_info(" MPEG\n"); + value &= 0xFFFFFFFC; + value |= 0x3; + + status = cx231xx_mode_register(dev, TS_MODE_REG, value); + + val[0] = 0x04; + val[1] = 0xA3; + val[2] = 0x3B; + val[3] = 0x00; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + TS1_CFG_REG, val, 4); + + val[0] = 0x00; + val[1] = 0x08; + val[2] = 0x00; + val[3] = 0x08; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + TS1_LENGTH_REG, val, 4); + + } else { + cx231xx_info(" BDA\n"); + status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101); + status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x010); + } + break; + + case 6: /* ts1 parallel mode */ + cx231xx_info("%s: set ts1 parallel mode registers\n", + __func__); + status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100); + status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400); + break; + } + } else { + status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101); + } + + return status; +} + +int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type) +{ + int rc = -1; + u32 ep_mask = -1; + struct pcb_config *pcb_config; + + /* get EP for media type */ + pcb_config = (struct pcb_config *)&dev->current_pcb_config; + + if (pcb_config->config_num == 1) { + switch (media_type) { + case 0: /* Video */ + ep_mask = ENABLE_EP4; /* ep4 [00:1000] */ + break; + case 1: /* Audio */ + ep_mask = ENABLE_EP3; /* ep3 [00:0100] */ + break; + case 2: /* Vbi */ + ep_mask = ENABLE_EP5; /* ep5 [01:0000] */ + break; + case 3: /* Sliced_cc */ + ep_mask = ENABLE_EP6; /* ep6 [10:0000] */ + break; + case 4: /* ts1 */ + case 6: /* ts1 parallel mode */ + ep_mask = ENABLE_EP1; /* ep1 [00:0001] */ + break; + case 5: /* ts2 */ + ep_mask = ENABLE_EP2; /* ep2 [00:0010] */ + break; + } + + } else if (pcb_config->config_num > 1) { + switch (media_type) { + case 0: /* Video */ + ep_mask = ENABLE_EP4; /* ep4 [00:1000] */ + break; + case 1: /* Audio */ + ep_mask = ENABLE_EP3; /* ep3 [00:0100] */ + break; + case 2: /* Vbi */ + ep_mask = ENABLE_EP5; /* ep5 [01:0000] */ + break; + case 3: /* Sliced_cc */ + ep_mask = ENABLE_EP6; /* ep6 [10:0000] */ + break; + case 4: /* ts1 */ + case 6: /* ts1 parallel mode */ + ep_mask = ENABLE_EP1; /* ep1 [00:0001] */ + break; + case 5: /* ts2 */ + ep_mask = ENABLE_EP2; /* ep2 [00:0010] */ + break; + } + + } + + if (start) { + rc = cx231xx_initialize_stream_xfer(dev, media_type); + + if (rc < 0) + return rc; + + /* enable video capture */ + if (ep_mask > 0) + rc = cx231xx_start_stream(dev, ep_mask); + } else { + /* disable video capture */ + if (ep_mask > 0) + rc = cx231xx_stop_stream(dev, ep_mask); + } + + if (dev->mode == CX231XX_ANALOG_MODE) + ;/* do any in Analog mode */ + else + ;/* do any in digital mode */ + + return rc; +} +EXPORT_SYMBOL_GPL(cx231xx_capture_start); + +/***************************************************************************** +* G P I O B I T control functions * +******************************************************************************/ +int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val) +{ + int status = 0; + + status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 0); + + return status; +} + +int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val) +{ + int status = 0; + + status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 1); + + return status; +} + +/* +* cx231xx_set_gpio_direction +* Sets the direction of the GPIO pin to input or output +* +* Parameters : +* pin_number : The GPIO Pin number to program the direction for +* from 0 to 31 +* pin_value : The Direction of the GPIO Pin under reference. +* 0 = Input direction +* 1 = Output direction +*/ +int cx231xx_set_gpio_direction(struct cx231xx *dev, + int pin_number, int pin_value) +{ + int status = 0; + u32 value = 0; + + /* Check for valid pin_number - if 32 , bail out */ + if (pin_number >= 32) + return -EINVAL; + + /* input */ + if (pin_value == 0) + value = dev->gpio_dir & (~(1 << pin_number)); /* clear */ + else + value = dev->gpio_dir | (1 << pin_number); + + status = cx231xx_set_gpio_bit(dev, value, (u8 *) &dev->gpio_val); + + /* cache the value for future */ + dev->gpio_dir = value; + + return status; +} + +/* +* cx231xx_set_gpio_value +* Sets the value of the GPIO pin to Logic high or low. The Pin under +* reference should ALREADY BE SET IN OUTPUT MODE !!!!!!!!! +* +* Parameters : +* pin_number : The GPIO Pin number to program the direction for +* pin_value : The value of the GPIO Pin under reference. +* 0 = set it to 0 +* 1 = set it to 1 +*/ +int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value) +{ + int status = 0; + u32 value = 0; + + /* Check for valid pin_number - if 0xFF , bail out */ + if (pin_number >= 32) + return -EINVAL; + + /* first do a sanity check - if the Pin is not output, make it output */ + if ((dev->gpio_dir & (1 << pin_number)) == 0x00) { + /* It was in input mode */ + value = dev->gpio_dir | (1 << pin_number); + dev->gpio_dir = value; + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, + (u8 *) &dev->gpio_val); + value = 0; + } + + if (pin_value == 0) + value = dev->gpio_val & (~(1 << pin_number)); + else + value = dev->gpio_val | (1 << pin_number); + + /* store the value */ + dev->gpio_val = value; + + /* toggle bit0 of GP_IO */ + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + return status; +} + +/***************************************************************************** +* G P I O I2C related functions * +******************************************************************************/ +int cx231xx_gpio_i2c_start(struct cx231xx *dev) +{ + int status = 0; + + /* set SCL to output 1 ; set SDA to output 1 */ + dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio; + dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; + dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; + dev->gpio_val |= 1 << dev->board.tuner_sda_gpio; + + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + if (status < 0) + return -EINVAL; + + /* set SCL to output 1; set SDA to output 0 */ + dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; + dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); + + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + if (status < 0) + return -EINVAL; + + /* set SCL to output 0; set SDA to output 0 */ + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); + + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + if (status < 0) + return -EINVAL; + + return status; +} + +int cx231xx_gpio_i2c_end(struct cx231xx *dev) +{ + int status = 0; + + /* set SCL to output 0; set SDA to output 0 */ + dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio; + dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; + + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); + + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + if (status < 0) + return -EINVAL; + + /* set SCL to output 1; set SDA to output 0 */ + dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; + dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); + + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + if (status < 0) + return -EINVAL; + + /* set SCL to input ,release SCL cable control + set SDA to input ,release SDA cable control */ + dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio); + dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); + + status = + cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + if (status < 0) + return -EINVAL; + + return status; +} + +int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data) +{ + int status = 0; + u8 i; + + /* set SCL to output ; set SDA to output */ + dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio; + dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; + + for (i = 0; i < 8; i++) { + if (((data << i) & 0x80) == 0) { + /* set SCL to output 0; set SDA to output 0 */ + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + + /* set SCL to output 1; set SDA to output 0 */ + dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + + /* set SCL to output 0; set SDA to output 0 */ + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + } else { + /* set SCL to output 0; set SDA to output 1 */ + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + dev->gpio_val |= 1 << dev->board.tuner_sda_gpio; + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + + /* set SCL to output 1; set SDA to output 1 */ + dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + + /* set SCL to output 0; set SDA to output 1 */ + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + } + } + return status; +} + +int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf) +{ + u8 value = 0; + int status = 0; + u32 gpio_logic_value = 0; + u8 i; + + /* read byte */ + for (i = 0; i < 8; i++) { /* send write I2c addr */ + + /* set SCL to output 0; set SDA to input */ + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + + /* set SCL to output 1; set SDA to input */ + dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + + /* get SDA data bit */ + gpio_logic_value = dev->gpio_val; + status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + if ((dev->gpio_val & (1 << dev->board.tuner_sda_gpio)) != 0) + value |= (1 << (8 - i - 1)); + + dev->gpio_val = gpio_logic_value; + } + + /* set SCL to output 0,finish the read latest SCL signal. + !!!set SDA to input, never to modify SDA direction at + the same times */ + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + /* store the value */ + *buf = value & 0xff; + + return status; +} + +int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev) +{ + int status = 0; + u32 gpio_logic_value = 0; + int nCnt = 10; + int nInit = nCnt; + + /* clock stretch; set SCL to input; set SDA to input; + get SCL value till SCL = 1 */ + dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); + dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio); + + gpio_logic_value = dev->gpio_val; + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + do { + msleep(2); + status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, + (u8 *)&dev->gpio_val); + nCnt--; + } while (((dev->gpio_val & + (1 << dev->board.tuner_scl_gpio)) == 0) && + (nCnt > 0)); + + if (nCnt == 0) + cx231xx_info("No ACK after %d msec -GPIO I2C failed!", + nInit * 10); + + /* + * readAck + * through clock stretch, slave has given a SCL signal, + * so the SDA data can be directly read. + */ + status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + if ((dev->gpio_val & 1 << dev->board.tuner_sda_gpio) == 0) { + dev->gpio_val = gpio_logic_value; + dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); + status = 0; + } else { + dev->gpio_val = gpio_logic_value; + dev->gpio_val |= (1 << dev->board.tuner_sda_gpio); + } + + /* read SDA end, set the SCL to output 0, after this operation, + SDA direction can be changed. */ + dev->gpio_val = gpio_logic_value; + dev->gpio_dir |= (1 << dev->board.tuner_scl_gpio); + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + return status; +} + +int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev) +{ + int status = 0; + + /* set SDA to ouput */ + dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + /* set SCL = 0 (output); set SDA = 0 (output) */ + dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + /* set SCL = 1 (output); set SDA = 0 (output) */ + dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + /* set SCL = 0 (output); set SDA = 0 (output) */ + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + /* set SDA to input,and then the slave will read data from SDA. */ + dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + return status; +} + +int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev) +{ + int status = 0; + + /* set scl to output ; set sda to input */ + dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio; + dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + /* set scl to output 0; set sda to input */ + dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + /* set scl to output 1; set sda to input */ + dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + + return status; +} + +/***************************************************************************** +* G P I O I2C related functions * +******************************************************************************/ +/* cx231xx_gpio_i2c_read + * Function to read data from gpio based I2C interface + */ +int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len) +{ + int status = 0; + int i = 0; + + /* get the lock */ + mutex_lock(&dev->gpio_i2c_lock); + + /* start */ + status = cx231xx_gpio_i2c_start(dev); + + /* write dev_addr */ + status = cx231xx_gpio_i2c_write_byte(dev, (dev_addr << 1) + 1); + + /* readAck */ + status = cx231xx_gpio_i2c_read_ack(dev); + + /* read data */ + for (i = 0; i < len; i++) { + /* read data */ + buf[i] = 0; + status = cx231xx_gpio_i2c_read_byte(dev, &buf[i]); + + if ((i + 1) != len) { + /* only do write ack if we more length */ + status = cx231xx_gpio_i2c_write_ack(dev); + } + } + + /* write NAK - inform reads are complete */ + status = cx231xx_gpio_i2c_write_nak(dev); + + /* write end */ + status = cx231xx_gpio_i2c_end(dev); + + /* release the lock */ + mutex_unlock(&dev->gpio_i2c_lock); + + return status; +} + +/* cx231xx_gpio_i2c_write + * Function to write data to gpio based I2C interface + */ +int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len) +{ + int status = 0; + int i = 0; + + /* get the lock */ + mutex_lock(&dev->gpio_i2c_lock); + + /* start */ + status = cx231xx_gpio_i2c_start(dev); + + /* write dev_addr */ + status = cx231xx_gpio_i2c_write_byte(dev, dev_addr << 1); + + /* read Ack */ + status = cx231xx_gpio_i2c_read_ack(dev); + + for (i = 0; i < len; i++) { + /* Write data */ + status = cx231xx_gpio_i2c_write_byte(dev, buf[i]); + + /* read Ack */ + status = cx231xx_gpio_i2c_read_ack(dev); + } + + /* write End */ + status = cx231xx_gpio_i2c_end(dev); + + /* release the lock */ + mutex_unlock(&dev->gpio_i2c_lock); + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-cards.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1406 @@ +/* + cx231xx-cards.c - driver for Conexant Cx23100/101/102 + USB video capture devices + + Copyright (C) 2008 + Based on em28xx driver + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "dvb-usb-ids.h" +#include "xc5000.h" +#include "tda18271.h" + +#include "cx231xx.h" + +static int tuner = -1; +module_param(tuner, int, 0444); +MODULE_PARM_DESC(tuner, "tuner type"); + +static int transfer_mode = 1; +module_param(transfer_mode, int, 0444); +MODULE_PARM_DESC(transfer_mode, "transfer mode (1-ISO or 0-BULK)"); + +static unsigned int disable_ir; +module_param(disable_ir, int, 0444); +MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); + +/* Bitmask marking allocated devices from 0 to CX231XX_MAXBOARDS */ +static unsigned long cx231xx_devused; + +/* + * Reset sequences for analog/digital modes + */ + +static struct cx231xx_reg_seq RDE250_XCV_TUNER[] = { + {0x03, 0x01, 10}, + {0x03, 0x00, 30}, + {0x03, 0x01, 10}, + {-1, -1, -1}, +}; + +/* + * Board definitions + */ +struct cx231xx_board cx231xx_boards[] = { + [CX231XX_BOARD_UNKNOWN] = { + .name = "Unknown CX231xx video grabber", + .tuner_type = TUNER_ABSENT, + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } + }, + }, + [CX231XX_BOARD_CNXT_CARRAERA] = { + .name = "Conexant Hybrid TV - CARRAERA", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .demod_i2c_master = 2, + .has_dvb = 1, + .demod_addr = 0x02, + .norm = V4L2_STD_PAL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } + }, + }, + [CX231XX_BOARD_CNXT_SHELBY] = { + .name = "Conexant Hybrid TV - SHELBY", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .demod_i2c_master = 2, + .has_dvb = 1, + .demod_addr = 0x32, + .norm = V4L2_STD_NTSC, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } + }, + }, + [CX231XX_BOARD_CNXT_RDE_253S] = { + .name = "Conexant Hybrid TV - RDE253S", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x1c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .demod_i2c_master = 2, + .has_dvb = 1, + .demod_addr = 0x02, + .norm = V4L2_STD_PAL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } + }, + }, + + [CX231XX_BOARD_CNXT_RDU_253S] = { + .name = "Conexant Hybrid TV - RDU253S", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x1c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .demod_i2c_master = 2, + .has_dvb = 1, + .demod_addr = 0x02, + .norm = V4L2_STD_PAL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } + }, + }, + [CX231XX_BOARD_CNXT_VIDEO_GRABBER] = { + .name = "Conexant VIDEO GRABBER", + .tuner_type = TUNER_ABSENT, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x1c, + .gpio_pin_status_mask = 0x4001000, + .norm = V4L2_STD_PAL, + .no_alt_vanc = 1, + .external_av = 1, + .has_417 = 1, + + .input = {{ + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } + }, + }, + [CX231XX_BOARD_CNXT_RDE_250] = { + .name = "Conexant Hybrid TV - rde 250", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .demod_i2c_master = 2, + .has_dvb = 1, + .demod_addr = 0x02, + .norm = V4L2_STD_PAL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + } + }, + }, + [CX231XX_BOARD_CNXT_RDU_250] = { + .name = "Conexant Hybrid TV - RDU 250", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .demod_i2c_master = 2, + .has_dvb = 1, + .demod_addr = 0x32, + .norm = V4L2_STD_NTSC, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + } + }, + }, + [CX231XX_BOARD_HAUPPAUGE_EXETER] = { + .name = "Hauppauge EXETER", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .demod_i2c_master = 2, + .has_dvb = 1, + .demod_addr = 0x0e, + .norm = V4L2_STD_NTSC, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_HAUPPAUGE_USBLIVE2] = { + .name = "Hauppauge USB Live 2", + .tuner_type = TUNER_ABSENT, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .norm = V4L2_STD_NTSC, + .no_alt_vanc = 1, + .external_av = 1, + .input = {{ + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_KWORLD_UB430_USB_HYBRID] = { + .name = "Kworld UB430 USB Hybrid", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x11, /* According with PV cxPolaris.inf file */ + .tuner_sif_gpio = -1, + .tuner_scl_gpio = -1, + .tuner_sda_gpio = -1, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 2, + .demod_i2c_master = 1, + .ir_i2c_master = 2, + .has_dvb = 1, + .demod_addr = 0x10, + .norm = V4L2_STD_PAL_M, + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = { + .name = "Pixelview PlayTV USB Hybrid", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x00, /* According with PV cxPolaris.inf file */ + .tuner_sif_gpio = -1, + .tuner_scl_gpio = -1, + .tuner_sda_gpio = -1, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 2, + .demod_i2c_master = 1, + .ir_i2c_master = 2, + .rc_map_name = RC_MAP_PIXELVIEW_002T, + .has_dvb = 1, + .demod_addr = 0x10, + .norm = V4L2_STD_PAL_M, + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_PV_XCAPTURE_USB] = { + .name = "Pixelview Xcapture USB", + .tuner_type = TUNER_ABSENT, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .norm = V4L2_STD_NTSC, + .no_alt_vanc = 1, + .external_av = 1, + .dont_use_port_3 = 1, + + .input = {{ + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } + }, + }, + + [CX231XX_BOARD_ICONBIT_U100] = { + .name = "Iconbit Analog Stick U100 FM", + .tuner_type = TUNER_ABSENT, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x1C, + .gpio_pin_status_mask = 0x4001000, + + .input = {{ + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL] = { + .name = "Hauppauge WinTV USB2 FM (PAL)", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .norm = V4L2_STD_PAL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC] = { + .name = "Hauppauge WinTV USB2 FM (NTSC)", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = 1, + .norm = V4L2_STD_NTSC, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, +}; +const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); + +/* table of devices that work with this driver */ +struct usb_device_id cx231xx_id_table[] = { + {USB_DEVICE(0x0572, 0x5A3C), + .driver_info = CX231XX_BOARD_UNKNOWN}, + {USB_DEVICE(0x0572, 0x58A2), + .driver_info = CX231XX_BOARD_CNXT_CARRAERA}, + {USB_DEVICE(0x0572, 0x58A1), + .driver_info = CX231XX_BOARD_CNXT_SHELBY}, + {USB_DEVICE(0x0572, 0x58A4), + .driver_info = CX231XX_BOARD_CNXT_RDE_253S}, + {USB_DEVICE(0x0572, 0x58A5), + .driver_info = CX231XX_BOARD_CNXT_RDU_253S}, + {USB_DEVICE(0x0572, 0x58A6), + .driver_info = CX231XX_BOARD_CNXT_VIDEO_GRABBER}, + {USB_DEVICE(0x0572, 0x589E), + .driver_info = CX231XX_BOARD_CNXT_RDE_250}, + {USB_DEVICE(0x0572, 0x58A0), + .driver_info = CX231XX_BOARD_CNXT_RDU_250}, + {USB_DEVICE(0x2040, 0xb110), + .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL}, + {USB_DEVICE(0x2040, 0xb111), + .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC}, + {USB_DEVICE(0x2040, 0xb120), + .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, + {USB_DEVICE(0x2040, 0xb140), + .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, + {USB_DEVICE(0x2040, 0xc200), + .driver_info = CX231XX_BOARD_HAUPPAUGE_USBLIVE2}, + {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000, 0x4001), + .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID}, + {USB_DEVICE(USB_VID_PIXELVIEW, 0x5014), + .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, + {USB_DEVICE(0x1b80, 0xe424), + .driver_info = CX231XX_BOARD_KWORLD_UB430_USB_HYBRID}, + {USB_DEVICE(0x1f4d, 0x0237), + .driver_info = CX231XX_BOARD_ICONBIT_U100}, + {}, +}; + +MODULE_DEVICE_TABLE(usb, cx231xx_id_table); + +/* cx231xx_tuner_callback + * will be used to reset XC5000 tuner using GPIO pin + */ + +int cx231xx_tuner_callback(void *ptr, int component, int command, int arg) +{ + int rc = 0; + struct cx231xx *dev = ptr; + + if (dev->tuner_type == TUNER_XC5000) { + if (command == XC5000_TUNER_RESET) { + cx231xx_info + ("Tuner CB: RESET: cmd %d : tuner type %d \n", + command, dev->tuner_type); + cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, + 1); + msleep(10); + cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, + 0); + msleep(330); + cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, + 1); + msleep(10); + } + } else if (dev->tuner_type == TUNER_NXP_TDA18271) { + switch (command) { + case TDA18271_CALLBACK_CMD_AGC_ENABLE: + if (dev->model == CX231XX_BOARD_PV_PLAYTV_USB_HYBRID) + rc = cx231xx_set_agc_analog_digital_mux_select(dev, arg); + break; + default: + rc = -EINVAL; + break; + } + } + return rc; +} +EXPORT_SYMBOL_GPL(cx231xx_tuner_callback); + +void cx231xx_reset_out(struct cx231xx *dev) +{ + cx231xx_set_gpio_value(dev, CX23417_RESET, 1); + msleep(200); + cx231xx_set_gpio_value(dev, CX23417_RESET, 0); + msleep(200); + cx231xx_set_gpio_value(dev, CX23417_RESET, 1); +} +void cx231xx_enable_OSC(struct cx231xx *dev) +{ + cx231xx_set_gpio_value(dev, CX23417_OSC_EN, 1); +} +void cx231xx_sleep_s5h1432(struct cx231xx *dev) +{ + cx231xx_set_gpio_value(dev, SLEEP_S5H1432, 0); +} + +static inline void cx231xx_set_model(struct cx231xx *dev) +{ + memcpy(&dev->board, &cx231xx_boards[dev->model], sizeof(dev->board)); +} + +/* Since cx231xx_pre_card_setup() requires a proper dev->model, + * this won't work for boards with generic PCI IDs + */ +void cx231xx_pre_card_setup(struct cx231xx *dev) +{ + + cx231xx_set_model(dev); + + cx231xx_info("Identified as %s (card=%d)\n", + dev->board.name, dev->model); + + /* set the direction for GPIO pins */ + if (dev->board.tuner_gpio) { + cx231xx_set_gpio_direction(dev, dev->board.tuner_gpio->bit, 1); + cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, 1); + } + if (dev->board.tuner_sif_gpio >= 0) + cx231xx_set_gpio_direction(dev, dev->board.tuner_sif_gpio, 1); + + /* request some modules if any required */ + + /* set the mode to Analog mode initially */ + cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); + + /* Unlock device */ + /* cx231xx_set_mode(dev, CX231XX_SUSPEND); */ + +} + +static void cx231xx_config_tuner(struct cx231xx *dev) +{ + struct tuner_setup tun_setup; + struct v4l2_frequency f; + + if (dev->tuner_type == TUNER_ABSENT) + return; + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + tun_setup.tuner_callback = cx231xx_tuner_callback; + + tuner_call(dev, tuner, s_type_addr, &tun_setup); + +#if 0 + if (tun_setup.type == TUNER_XC5000) { + static struct xc2028_ctrl ctrl = { + .fname = XC5000_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = 0; + }; + struct v4l2_priv_tun_config cfg = { + .tuner = dev->tuner_type, + .priv = &ctrl, + }; + tuner_call(dev, tuner, s_config, &cfg); + } +#endif + /* configure tuner */ + f.tuner = 0; + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = 9076; /* just a magic number */ + dev->ctl_freq = f.frequency; + call_all(dev, tuner, s_frequency, &f); + +} + +void cx231xx_card_setup(struct cx231xx *dev) +{ + + cx231xx_set_model(dev); + + dev->tuner_type = cx231xx_boards[dev->model].tuner_type; + if (cx231xx_boards[dev->model].tuner_addr) + dev->tuner_addr = cx231xx_boards[dev->model].tuner_addr; + + /* request some modules */ + if (dev->board.decoder == CX231XX_AVDECODER) { + dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_bus[0].i2c_adap, + "cx25840", 0x88 >> 1, NULL); + if (dev->sd_cx25840 == NULL) + cx231xx_info("cx25840 subdev registration failure\n"); + cx25840_call(dev, core, load_fw); + + } + + /* Initialize the tuner */ + if (dev->board.tuner_type != TUNER_ABSENT) { + dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, + "tuner", + dev->tuner_addr, NULL); + if (dev->sd_tuner == NULL) + cx231xx_info("tuner subdev registration failure\n"); + else + cx231xx_config_tuner(dev); + } +} + +/* + * cx231xx_config() + * inits registers with sane defaults + */ +int cx231xx_config(struct cx231xx *dev) +{ + /* TBD need to add cx231xx specific code */ + dev->mute = 1; /* maybe not the right place... */ + dev->volume = 0x1f; + + return 0; +} + +/* + * cx231xx_config_i2c() + * configure i2c attached devices + */ +void cx231xx_config_i2c(struct cx231xx *dev) +{ + /* u32 input = INPUT(dev->video_input)->vmux; */ + + call_all(dev, video, s_stream, 1); +} + +/* + * cx231xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +void cx231xx_release_resources(struct cx231xx *dev) +{ + cx231xx_release_analog_resources(dev); + + cx231xx_remove_from_devlist(dev); + + /* Release I2C buses */ + cx231xx_dev_uninit(dev); + + cx231xx_ir_exit(dev); + + usb_put_dev(dev->udev); + + /* Mark device as unused */ + cx231xx_devused &= ~(1 << dev->devno); +} + +/* + * cx231xx_init_dev() + * allocates and inits the device structs, registers i2c bus and v4l device + */ +static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev, + int minor) +{ + struct cx231xx *dev = *devhandle; + int retval = -ENOMEM; + int errCode; + unsigned int maxh, maxw; + + dev->udev = udev; + mutex_init(&dev->lock); + mutex_init(&dev->ctrl_urb_lock); + mutex_init(&dev->gpio_i2c_lock); + mutex_init(&dev->i2c_lock); + + spin_lock_init(&dev->video_mode.slock); + spin_lock_init(&dev->vbi_mode.slock); + spin_lock_init(&dev->sliced_cc_mode.slock); + + init_waitqueue_head(&dev->open); + init_waitqueue_head(&dev->wait_frame); + init_waitqueue_head(&dev->wait_stream); + + dev->cx231xx_read_ctrl_reg = cx231xx_read_ctrl_reg; + dev->cx231xx_write_ctrl_reg = cx231xx_write_ctrl_reg; + dev->cx231xx_send_usb_command = cx231xx_send_usb_command; + dev->cx231xx_gpio_i2c_read = cx231xx_gpio_i2c_read; + dev->cx231xx_gpio_i2c_write = cx231xx_gpio_i2c_write; + + /* Query cx231xx to find what pcb config it is related to */ + initialize_cx231xx(dev); + + /*To workaround error number=-71 on EP0 for VideoGrabber, + need set alt here.*/ + if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER || + dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) { + cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3); + cx231xx_set_alt_setting(dev, INDEX_VANC, 1); + } + /* Cx231xx pre card setup */ + cx231xx_pre_card_setup(dev); + + errCode = cx231xx_config(dev); + if (errCode) { + cx231xx_errdev("error configuring device\n"); + return -ENOMEM; + } + + /* set default norm */ + dev->norm = dev->board.norm; + + /* register i2c bus */ + errCode = cx231xx_dev_init(dev); + if (errCode < 0) { + cx231xx_dev_uninit(dev); + cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + + /* Do board specific init */ + cx231xx_card_setup(dev); + + /* configure the device */ + cx231xx_config_i2c(dev); + + maxw = norm_maxw(dev); + maxh = norm_maxh(dev); + + /* set default image size */ + dev->width = maxw; + dev->height = maxh; + dev->interlaced = 0; + dev->video_input = 0; + + errCode = cx231xx_config(dev); + if (errCode < 0) { + cx231xx_errdev("%s: cx231xx_config - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->video_mode.vidq.active); + INIT_LIST_HEAD(&dev->video_mode.vidq.queued); + + /* init vbi dma queues */ + INIT_LIST_HEAD(&dev->vbi_mode.vidq.active); + INIT_LIST_HEAD(&dev->vbi_mode.vidq.queued); + + /* Reset other chips required if they are tied up with GPIO pins */ + cx231xx_add_into_devlist(dev); + + if (dev->board.has_417) { + printk(KERN_INFO "attach 417 %d\n", dev->model); + if (cx231xx_417_register(dev) < 0) { + printk(KERN_ERR + "%s() Failed to register 417 on VID_B\n", + __func__); + } + } + + retval = cx231xx_register_analog_devices(dev); + if (retval < 0) { + cx231xx_release_resources(dev); + return retval; + } + + cx231xx_ir_init(dev); + + cx231xx_init_extension(dev); + + return 0; +} + +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + struct cx231xx *dev = container_of(work, + struct cx231xx, request_module_wk); + + if (dev->has_alsa_audio) + request_module("cx231xx-alsa"); + + if (dev->board.has_dvb) + request_module("cx231xx-dvb"); + +} + +static void request_modules(struct cx231xx *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); +} + +static void flush_request_modules(struct cx231xx *dev) +{ + flush_work_sync(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#define flush_request_modules(dev) +#endif /* CONFIG_MODULES */ + +/* + * cx231xx_usb_probe() + * checks for supported devices + */ +static int cx231xx_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev; + struct usb_interface *uif; + struct cx231xx *dev = NULL; + int retval = -ENODEV; + int nr = 0, ifnum; + int i, isoc_pipe = 0; + char *speed; + char descr[255] = ""; + struct usb_interface *lif = NULL; + struct usb_interface_assoc_descriptor *assoc_desc; + + udev = usb_get_dev(interface_to_usbdev(interface)); + ifnum = interface->altsetting[0].desc.bInterfaceNumber; + + /* + * Interface number 0 - IR interface (handled by mceusb driver) + * Interface number 1 - AV interface (handled by this driver) + */ + if (ifnum != 1) + return -ENODEV; + + /* Check to see next free device and mark as used */ + nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); + cx231xx_devused |= 1 << nr; + + if (nr >= CX231XX_MAXBOARDS) { + cx231xx_err(DRIVER_NAME + ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS); + cx231xx_devused &= ~(1 << nr); + return -ENOMEM; + } + + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + cx231xx_err(DRIVER_NAME ": out of memory!\n"); + cx231xx_devused &= ~(1 << nr); + return -ENOMEM; + } + + snprintf(dev->name, 29, "cx231xx #%d", nr); + dev->devno = nr; + dev->model = id->driver_info; + dev->video_mode.alt = -1; + + dev->interface_count++; + /* reset gpio dir and value */ + dev->gpio_dir = 0; + dev->gpio_val = 0; + dev->xc_fw_load_done = 0; + dev->has_alsa_audio = 1; + dev->power_mode = -1; + atomic_set(&dev->devlist_count, 0); + + /* 0 - vbi ; 1 -sliced cc mode */ + dev->vbi_or_sliced_cc_mode = 0; + + /* get maximum no.of IAD interfaces */ + assoc_desc = udev->actconfig->intf_assoc[0]; + dev->max_iad_interface_count = assoc_desc->bInterfaceCount; + + /* init CIR module TBD */ + + /* store the current interface */ + lif = interface; + + /*mode_tv: digital=1 or analog=0*/ + dev->mode_tv = 0; + + dev->USE_ISO = transfer_mode; + + switch (udev->speed) { + case USB_SPEED_LOW: + speed = "1.5"; + break; + case USB_SPEED_UNKNOWN: + case USB_SPEED_FULL: + speed = "12"; + break; + case USB_SPEED_HIGH: + speed = "480"; + break; + default: + speed = "unknown"; + } + + if (udev->manufacturer) + strlcpy(descr, udev->manufacturer, sizeof(descr)); + + if (udev->product) { + if (*descr) + strlcat(descr, " ", sizeof(descr)); + strlcat(descr, udev->product, sizeof(descr)); + } + if (*descr) + strlcat(descr, " ", sizeof(descr)); + + cx231xx_info("New device %s@ %s Mbps " + "(%04x:%04x) with %d interfaces\n", + descr, + speed, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + dev->max_iad_interface_count); + + /* store the interface 0 back */ + lif = udev->actconfig->interface[0]; + + /* increment interface count */ + dev->interface_count++; + + /* get device number */ + nr = dev->devno; + + assoc_desc = udev->actconfig->intf_assoc[0]; + if (assoc_desc->bFirstInterface != ifnum) { + cx231xx_err(DRIVER_NAME ": Not found " + "matching IAD interface\n"); + return -ENODEV; + } + + cx231xx_info("registering interface %d\n", ifnum); + + /* save our data pointer in this interface device */ + usb_set_intfdata(lif, dev); + + /* + * AV device initialization - only done at the last interface + */ + + /* Create v4l2 device */ + retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); + if (retval) { + cx231xx_errdev("v4l2_device_register failed\n"); + cx231xx_devused &= ~(1 << nr); + kfree(dev); + dev = NULL; + return -EIO; + } + /* allocate device struct */ + retval = cx231xx_init_dev(&dev, udev, nr); + if (retval) { + cx231xx_devused &= ~(1 << dev->devno); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); + dev = NULL; + usb_set_intfdata(lif, NULL); + + return retval; + } + + /* compute alternate max packet sizes for video */ + uif = udev->actconfig->interface[dev->current_pcb_config. + hs_config_info[0].interface_info.video_index + 1]; + + dev->video_mode.end_point_addr = le16_to_cpu(uif->altsetting[0]. + endpoint[isoc_pipe].desc.bEndpointAddress); + + dev->video_mode.num_alt = uif->num_altsetting; + cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", + dev->video_mode.end_point_addr, + dev->video_mode.num_alt); + dev->video_mode.alt_max_pkt_size = + kmalloc(32 * dev->video_mode.num_alt, GFP_KERNEL); + + if (dev->video_mode.alt_max_pkt_size == NULL) { + cx231xx_errdev("out of memory!\n"); + cx231xx_devused &= ~(1 << nr); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); + dev = NULL; + return -ENOMEM; + } + + for (i = 0; i < dev->video_mode.num_alt; i++) { + u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. + desc.wMaxPacketSize); + dev->video_mode.alt_max_pkt_size[i] = + (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); + cx231xx_info("Alternate setting %i, max size= %i\n", i, + dev->video_mode.alt_max_pkt_size[i]); + } + + /* compute alternate max packet sizes for vbi */ + uif = udev->actconfig->interface[dev->current_pcb_config. + hs_config_info[0].interface_info. + vanc_index + 1]; + + dev->vbi_mode.end_point_addr = + le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc. + bEndpointAddress); + + dev->vbi_mode.num_alt = uif->num_altsetting; + cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", + dev->vbi_mode.end_point_addr, + dev->vbi_mode.num_alt); + dev->vbi_mode.alt_max_pkt_size = + kmalloc(32 * dev->vbi_mode.num_alt, GFP_KERNEL); + + if (dev->vbi_mode.alt_max_pkt_size == NULL) { + cx231xx_errdev("out of memory!\n"); + cx231xx_devused &= ~(1 << nr); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); + dev = NULL; + return -ENOMEM; + } + + for (i = 0; i < dev->vbi_mode.num_alt; i++) { + u16 tmp = + le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. + desc.wMaxPacketSize); + dev->vbi_mode.alt_max_pkt_size[i] = + (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); + cx231xx_info("Alternate setting %i, max size= %i\n", i, + dev->vbi_mode.alt_max_pkt_size[i]); + } + + /* compute alternate max packet sizes for sliced CC */ + uif = udev->actconfig->interface[dev->current_pcb_config. + hs_config_info[0].interface_info. + hanc_index + 1]; + + dev->sliced_cc_mode.end_point_addr = + le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc. + bEndpointAddress); + + dev->sliced_cc_mode.num_alt = uif->num_altsetting; + cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", + dev->sliced_cc_mode.end_point_addr, + dev->sliced_cc_mode.num_alt); + dev->sliced_cc_mode.alt_max_pkt_size = + kmalloc(32 * dev->sliced_cc_mode.num_alt, GFP_KERNEL); + + if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) { + cx231xx_errdev("out of memory!\n"); + cx231xx_devused &= ~(1 << nr); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); + dev = NULL; + return -ENOMEM; + } + + for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) { + u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. + desc.wMaxPacketSize); + dev->sliced_cc_mode.alt_max_pkt_size[i] = + (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); + cx231xx_info("Alternate setting %i, max size= %i\n", i, + dev->sliced_cc_mode.alt_max_pkt_size[i]); + } + + if (dev->current_pcb_config.ts1_source != 0xff) { + /* compute alternate max packet sizes for TS1 */ + uif = udev->actconfig->interface[dev->current_pcb_config. + hs_config_info[0]. + interface_info. + ts1_index + 1]; + + dev->ts1_mode.end_point_addr = + le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe]. + desc.bEndpointAddress); + + dev->ts1_mode.num_alt = uif->num_altsetting; + cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", + dev->ts1_mode.end_point_addr, + dev->ts1_mode.num_alt); + dev->ts1_mode.alt_max_pkt_size = + kmalloc(32 * dev->ts1_mode.num_alt, GFP_KERNEL); + + if (dev->ts1_mode.alt_max_pkt_size == NULL) { + cx231xx_errdev("out of memory!\n"); + cx231xx_devused &= ~(1 << nr); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); + dev = NULL; + return -ENOMEM; + } + + for (i = 0; i < dev->ts1_mode.num_alt; i++) { + u16 tmp = le16_to_cpu(uif->altsetting[i]. + endpoint[isoc_pipe].desc. + wMaxPacketSize); + dev->ts1_mode.alt_max_pkt_size[i] = + (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); + cx231xx_info("Alternate setting %i, max size= %i\n", i, + dev->ts1_mode.alt_max_pkt_size[i]); + } + } + + if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) { + cx231xx_enable_OSC(dev); + cx231xx_reset_out(dev); + cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3); + } + + if (dev->model == CX231XX_BOARD_CNXT_RDE_253S) + cx231xx_sleep_s5h1432(dev); + + /* load other modules required */ + request_modules(dev); + + return 0; +} + +/* + * cx231xx_usb_disconnect() + * called when the device gets diconencted + * video device will be unregistered on v4l2_close in case it is still open + */ +static void cx231xx_usb_disconnect(struct usb_interface *interface) +{ + struct cx231xx *dev; + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + if (!dev) + return; + + if (!dev->udev) + return; + + flush_request_modules(dev); + + /* delete v4l2 device */ + v4l2_device_unregister(&dev->v4l2_dev); + + /* wait until all current v4l2 io is finished then deallocate + resources */ + mutex_lock(&dev->lock); + + wake_up_interruptible_all(&dev->open); + + if (dev->users) { + cx231xx_warn + ("device %s is open! Deregistration and memory " + "deallocation are deferred on close.\n", + video_device_node_name(dev->vdev)); + + dev->state |= DEV_MISCONFIGURED; + if (dev->USE_ISO) + cx231xx_uninit_isoc(dev); + else + cx231xx_uninit_bulk(dev); + dev->state |= DEV_DISCONNECTED; + wake_up_interruptible(&dev->wait_frame); + wake_up_interruptible(&dev->wait_stream); + } else { + dev->state |= DEV_DISCONNECTED; + cx231xx_release_resources(dev); + } + + cx231xx_close_extension(dev); + + mutex_unlock(&dev->lock); + + if (!dev->users) { + kfree(dev->video_mode.alt_max_pkt_size); + kfree(dev->vbi_mode.alt_max_pkt_size); + kfree(dev->sliced_cc_mode.alt_max_pkt_size); + kfree(dev->ts1_mode.alt_max_pkt_size); + kfree(dev); + dev = NULL; + } +} + +static struct usb_driver cx231xx_usb_driver = { + .name = "cx231xx", + .probe = cx231xx_usb_probe, + .disconnect = cx231xx_usb_disconnect, + .id_table = cx231xx_id_table, +}; + +static int __init cx231xx_module_init(void) +{ + int result; + + printk(KERN_INFO DRIVER_NAME " v4l2 driver loaded.\n"); + + /* register this driver with the USB subsystem */ + result = usb_register(&cx231xx_usb_driver); + if (result) + cx231xx_err(DRIVER_NAME + " usb_register failed. Error number %d.\n", result); + + return result; +} + +static void __exit cx231xx_module_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&cx231xx_usb_driver); +} + +module_init(cx231xx_module_init); +module_exit(cx231xx_module_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-conf-reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,495 @@ +/* + cx231xx_conf-reg.h - driver for Conexant Cx23100/101/102 USB + video capture devices + + Copyright (C) 2008 + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _POLARIS_REG_H_ +#define _POLARIS_REG_H_ + +#define BOARD_CFG_STAT 0x0 +#define TS_MODE_REG 0x4 +#define TS1_CFG_REG 0x8 +#define TS1_LENGTH_REG 0xc +#define TS2_CFG_REG 0x10 +#define TS2_LENGTH_REG 0x14 +#define EP_MODE_SET 0x18 +#define CIR_PWR_PTN1 0x1c +#define CIR_PWR_PTN2 0x20 +#define CIR_PWR_PTN3 0x24 +#define CIR_PWR_MASK0 0x28 +#define CIR_PWR_MASK1 0x2c +#define CIR_PWR_MASK2 0x30 +#define CIR_GAIN 0x34 +#define CIR_CAR_REG 0x38 +#define CIR_OT_CFG1 0x40 +#define CIR_OT_CFG2 0x44 +#define GBULK_BIT_EN 0x68 +#define PWR_CTL_EN 0x74 + +/* Polaris Endpoints capture mask for register EP_MODE_SET */ +#define ENABLE_EP1 0x01 /* Bit[0]=1 */ +#define ENABLE_EP2 0x02 /* Bit[1]=1 */ +#define ENABLE_EP3 0x04 /* Bit[2]=1 */ +#define ENABLE_EP4 0x08 /* Bit[3]=1 */ +#define ENABLE_EP5 0x10 /* Bit[4]=1 */ +#define ENABLE_EP6 0x20 /* Bit[5]=1 */ + +/* Bit definition for register PWR_CTL_EN */ +#define PWR_MODE_MASK 0x17f +#define PWR_AV_EN 0x08 /* bit3 */ +#define PWR_ISO_EN 0x40 /* bit6 */ +#define PWR_AV_MODE 0x30 /* bit4,5 */ +#define PWR_TUNER_EN 0x04 /* bit2 */ +#define PWR_DEMOD_EN 0x02 /* bit1 */ +#define I2C_DEMOD_EN 0x01 /* bit0 */ +#define PWR_RESETOUT_EN 0x100 /* bit8 */ + +enum AV_MODE{ + POLARIS_AVMODE_DEFAULT = 0, + POLARIS_AVMODE_DIGITAL = 0x10, + POLARIS_AVMODE_ANALOGT_TV = 0x20, + POLARIS_AVMODE_ENXTERNAL_AV = 0x30, + +}; + +/* Colibri Registers */ + +#define SINGLE_ENDED 0x0 +#define LOW_IF 0x4 +#define EU_IF 0x9 +#define US_IF 0xa + +#define SUP_BLK_TUNE1 0x00 +#define SUP_BLK_TUNE2 0x01 +#define SUP_BLK_TUNE3 0x02 +#define SUP_BLK_XTAL 0x03 +#define SUP_BLK_PLL1 0x04 +#define SUP_BLK_PLL2 0x05 +#define SUP_BLK_PLL3 0x06 +#define SUP_BLK_REF 0x07 +#define SUP_BLK_PWRDN 0x08 +#define SUP_BLK_TESTPAD 0x09 +#define ADC_COM_INT5_STAB_REF 0x0a +#define ADC_COM_QUANT 0x0b +#define ADC_COM_BIAS1 0x0c +#define ADC_COM_BIAS2 0x0d +#define ADC_COM_BIAS3 0x0e +#define TESTBUS_CTRL 0x12 + +#define FLD_PWRDN_TUNING_BIAS 0x10 +#define FLD_PWRDN_ENABLE_PLL 0x08 +#define FLD_PWRDN_PD_BANDGAP 0x04 +#define FLD_PWRDN_PD_BIAS 0x02 +#define FLD_PWRDN_PD_TUNECK 0x01 + + +#define ADC_STATUS_CH1 0x20 +#define ADC_STATUS_CH2 0x40 +#define ADC_STATUS_CH3 0x60 + +#define ADC_STATUS2_CH1 0x21 +#define ADC_STATUS2_CH2 0x41 +#define ADC_STATUS2_CH3 0x61 + +#define ADC_CAL_ATEST_CH1 0x22 +#define ADC_CAL_ATEST_CH2 0x42 +#define ADC_CAL_ATEST_CH3 0x62 + +#define ADC_PWRDN_CLAMP_CH1 0x23 +#define ADC_PWRDN_CLAMP_CH2 0x43 +#define ADC_PWRDN_CLAMP_CH3 0x63 + +#define ADC_CTRL_DAC23_CH1 0x24 +#define ADC_CTRL_DAC23_CH2 0x44 +#define ADC_CTRL_DAC23_CH3 0x64 + +#define ADC_CTRL_DAC1_CH1 0x25 +#define ADC_CTRL_DAC1_CH2 0x45 +#define ADC_CTRL_DAC1_CH3 0x65 + +#define ADC_DCSERVO_DEM_CH1 0x26 +#define ADC_DCSERVO_DEM_CH2 0x46 +#define ADC_DCSERVO_DEM_CH3 0x66 + +#define ADC_FB_FRCRST_CH1 0x27 +#define ADC_FB_FRCRST_CH2 0x47 +#define ADC_FB_FRCRST_CH3 0x67 + +#define ADC_INPUT_CH1 0x28 +#define ADC_INPUT_CH2 0x48 +#define ADC_INPUT_CH3 0x68 +#define INPUT_SEL_MASK 0x30 /* [5:4] in_sel */ + +#define ADC_NTF_PRECLMP_EN_CH1 0x29 +#define ADC_NTF_PRECLMP_EN_CH2 0x49 +#define ADC_NTF_PRECLMP_EN_CH3 0x69 + +#define ADC_QGAIN_RES_TRM_CH1 0x2a +#define ADC_QGAIN_RES_TRM_CH2 0x4a +#define ADC_QGAIN_RES_TRM_CH3 0x6a + +#define ADC_SOC_PRECLMP_TERM_CH1 0x2b +#define ADC_SOC_PRECLMP_TERM_CH2 0x4b +#define ADC_SOC_PRECLMP_TERM_CH3 0x6b + +#define TESTBUS_CTRL_CH1 0x32 +#define TESTBUS_CTRL_CH2 0x52 +#define TESTBUS_CTRL_CH3 0x72 + +/****************************************************************************** + * DIF registers * + ******************************************************************************/ +#define DIRECT_IF_REVB_BASE 0x00300 + +/*****************************************************************************/ +#define DIF_PLL_FREQ_WORD (DIRECT_IF_REVB_BASE + 0x00000000) +/*****************************************************************************/ +#define FLD_DIF_PLL_LOCK 0x80000000 +/* Reserved [30:29] */ +#define FLD_DIF_PLL_FREE_RUN 0x10000000 +#define FLD_DIF_PLL_FREQ 0x0fffffff + +/*****************************************************************************/ +#define DIF_PLL_CTRL (DIRECT_IF_REVB_BASE + 0x00000004) +/*****************************************************************************/ +#define FLD_DIF_KD_PD 0xff000000 +/* Reserved [23:20] */ +#define FLD_DIF_KDS_PD 0x000f0000 +#define FLD_DIF_KI_PD 0x0000ff00 +/* Reserved [7:4] */ +#define FLD_DIF_KIS_PD 0x0000000f + +/*****************************************************************************/ +#define DIF_PLL_CTRL1 (DIRECT_IF_REVB_BASE + 0x00000008) +/*****************************************************************************/ +#define FLD_DIF_KD_FD 0xff000000 +/* Reserved [23:20] */ +#define FLD_DIF_KDS_FD 0x000f0000 +#define FLD_DIF_KI_FD 0x0000ff00 +#define FLD_DIF_SIG_PROP_SZ 0x000000f0 +#define FLD_DIF_KIS_FD 0x0000000f + +/*****************************************************************************/ +#define DIF_PLL_CTRL2 (DIRECT_IF_REVB_BASE + 0x0000000c) +/*****************************************************************************/ +#define FLD_DIF_PLL_AGC_REF 0xfff00000 +#define FLD_DIF_PLL_AGC_KI 0x000f0000 +/* Reserved [15] */ +#define FLD_DIF_FREQ_LIMIT 0x00007000 +#define FLD_DIF_K_FD 0x00000f00 +#define FLD_DIF_DOWNSMPL_FD 0x000000ff + +/*****************************************************************************/ +#define DIF_PLL_CTRL3 (DIRECT_IF_REVB_BASE + 0x00000010) +/*****************************************************************************/ +/* Reserved [31:16] */ +#define FLD_DIF_PLL_AGC_EN 0x00008000 +/* Reserved [14:12] */ +#define FLD_DIF_PLL_MAN_GAIN 0x00000fff + +/*****************************************************************************/ +#define DIF_AGC_IF_REF (DIRECT_IF_REVB_BASE + 0x00000014) +/*****************************************************************************/ +#define FLD_DIF_K_AGC_RF 0xf0000000 +#define FLD_DIF_K_AGC_IF 0x0f000000 +#define FLD_DIF_K_AGC_INT 0x00f00000 +/* Reserved [19:12] */ +#define FLD_DIF_IF_REF 0x00000fff + +/*****************************************************************************/ +#define DIF_AGC_CTRL_IF (DIRECT_IF_REVB_BASE + 0x00000018) +/*****************************************************************************/ +#define FLD_DIF_IF_MAX 0xff000000 +#define FLD_DIF_IF_MIN 0x00ff0000 +#define FLD_DIF_IF_AGC 0x0000ffff + +/*****************************************************************************/ +#define DIF_AGC_CTRL_INT (DIRECT_IF_REVB_BASE + 0x0000001c) +/*****************************************************************************/ +#define FLD_DIF_INT_MAX 0xff000000 +#define FLD_DIF_INT_MIN 0x00ff0000 +#define FLD_DIF_INT_AGC 0x0000ffff + +/*****************************************************************************/ +#define DIF_AGC_CTRL_RF (DIRECT_IF_REVB_BASE + 0x00000020) +/*****************************************************************************/ +#define FLD_DIF_RF_MAX 0xff000000 +#define FLD_DIF_RF_MIN 0x00ff0000 +#define FLD_DIF_RF_AGC 0x0000ffff + +/*****************************************************************************/ +#define DIF_AGC_IF_INT_CURRENT (DIRECT_IF_REVB_BASE + 0x00000024) +/*****************************************************************************/ +#define FLD_DIF_IF_AGC_IN 0xffff0000 +#define FLD_DIF_INT_AGC_IN 0x0000ffff + +/*****************************************************************************/ +#define DIF_AGC_RF_CURRENT (DIRECT_IF_REVB_BASE + 0x00000028) +/*****************************************************************************/ +/* Reserved [31:16] */ +#define FLD_DIF_RF_AGC_IN 0x0000ffff + +/*****************************************************************************/ +#define DIF_VIDEO_AGC_CTRL (DIRECT_IF_REVB_BASE + 0x0000002c) +/*****************************************************************************/ +#define FLD_DIF_AFD 0xc0000000 +#define FLD_DIF_K_VID_AGC 0x30000000 +#define FLD_DIF_LINE_LENGTH 0x0fff0000 +#define FLD_DIF_AGC_GAIN 0x0000ffff + +/*****************************************************************************/ +#define DIF_VID_AUD_OVERRIDE (DIRECT_IF_REVB_BASE + 0x00000030) +/*****************************************************************************/ +#define FLD_DIF_AUDIO_AGC_OVERRIDE 0x80000000 +/* Reserved [30:30] */ +#define FLD_DIF_AUDIO_MAN_GAIN 0x3f000000 +/* Reserved [23:17] */ +#define FLD_DIF_VID_AGC_OVERRIDE 0x00010000 +#define FLD_DIF_VID_MAN_GAIN 0x0000ffff + +/*****************************************************************************/ +#define DIF_AV_SEP_CTRL (DIRECT_IF_REVB_BASE + 0x00000034) +/*****************************************************************************/ +#define FLD_DIF_LPF_FREQ 0xc0000000 +#define FLD_DIF_AV_PHASE_INC 0x3f000000 +#define FLD_DIF_AUDIO_FREQ 0x00ffffff + +/*****************************************************************************/ +#define DIF_COMP_FLT_CTRL (DIRECT_IF_REVB_BASE + 0x00000038) +/*****************************************************************************/ +/* Reserved [31:24] */ +#define FLD_DIF_IIR23_R2 0x00ff0000 +#define FLD_DIF_IIR23_R1 0x0000ff00 +#define FLD_DIF_IIR1_R1 0x000000ff + +/*****************************************************************************/ +#define DIF_MISC_CTRL (DIRECT_IF_REVB_BASE + 0x0000003c) +/*****************************************************************************/ +#define FLD_DIF_DIF_BYPASS 0x80000000 +#define FLD_DIF_FM_NYQ_GAIN 0x40000000 +#define FLD_DIF_RF_AGC_ENA 0x20000000 +#define FLD_DIF_INT_AGC_ENA 0x10000000 +#define FLD_DIF_IF_AGC_ENA 0x08000000 +#define FLD_DIF_FORCE_RF_IF_LOCK 0x04000000 +#define FLD_DIF_VIDEO_AGC_ENA 0x02000000 +#define FLD_DIF_RF_AGC_INV 0x01000000 +#define FLD_DIF_INT_AGC_INV 0x00800000 +#define FLD_DIF_IF_AGC_INV 0x00400000 +#define FLD_DIF_SPEC_INV 0x00200000 +#define FLD_DIF_AUD_FULL_BW 0x00100000 +#define FLD_DIF_AUD_SRC_SEL 0x00080000 +/* Reserved [18] */ +#define FLD_DIF_IF_FREQ 0x00030000 +/* Reserved [15:14] */ +#define FLD_DIF_TIP_OFFSET 0x00003f00 +/* Reserved [7:5] */ +#define FLD_DIF_DITHER_ENA 0x00000010 +/* Reserved [3:1] */ +#define FLD_DIF_RF_IF_LOCK 0x00000001 + +/*****************************************************************************/ +#define DIF_SRC_PHASE_INC (DIRECT_IF_REVB_BASE + 0x00000040) +/*****************************************************************************/ +/* Reserved [31:29] */ +#define FLD_DIF_PHASE_INC 0x1fffffff + +/*****************************************************************************/ +#define DIF_SRC_GAIN_CONTROL (DIRECT_IF_REVB_BASE + 0x00000044) +/*****************************************************************************/ +/* Reserved [31:16] */ +#define FLD_DIF_SRC_KI 0x0000ff00 +#define FLD_DIF_SRC_KD 0x000000ff + +/*****************************************************************************/ +#define DIF_BPF_COEFF01 (DIRECT_IF_REVB_BASE + 0x00000048) +/*****************************************************************************/ +/* Reserved [31:19] */ +#define FLD_DIF_BPF_COEFF_0 0x00070000 +/* Reserved [15:4] */ +#define FLD_DIF_BPF_COEFF_1 0x0000000f + +/*****************************************************************************/ +#define DIF_BPF_COEFF23 (DIRECT_IF_REVB_BASE + 0x0000004c) +/*****************************************************************************/ +/* Reserved [31:22] */ +#define FLD_DIF_BPF_COEFF_2 0x003f0000 +/* Reserved [15:7] */ +#define FLD_DIF_BPF_COEFF_3 0x0000007f + +/*****************************************************************************/ +#define DIF_BPF_COEFF45 (DIRECT_IF_REVB_BASE + 0x00000050) +/*****************************************************************************/ +/* Reserved [31:24] */ +#define FLD_DIF_BPF_COEFF_4 0x00ff0000 +/* Reserved [15:8] */ +#define FLD_DIF_BPF_COEFF_5 0x000000ff + +/*****************************************************************************/ +#define DIF_BPF_COEFF67 (DIRECT_IF_REVB_BASE + 0x00000054) +/*****************************************************************************/ +/* Reserved [31:25] */ +#define FLD_DIF_BPF_COEFF_6 0x01ff0000 +/* Reserved [15:9] */ +#define FLD_DIF_BPF_COEFF_7 0x000001ff + +/*****************************************************************************/ +#define DIF_BPF_COEFF89 (DIRECT_IF_REVB_BASE + 0x00000058) +/*****************************************************************************/ +/* Reserved [31:26] */ +#define FLD_DIF_BPF_COEFF_8 0x03ff0000 +/* Reserved [15:10] */ +#define FLD_DIF_BPF_COEFF_9 0x000003ff + +/*****************************************************************************/ +#define DIF_BPF_COEFF1011 (DIRECT_IF_REVB_BASE + 0x0000005c) +/*****************************************************************************/ +/* Reserved [31:27] */ +#define FLD_DIF_BPF_COEFF_10 0x07ff0000 +/* Reserved [15:11] */ +#define FLD_DIF_BPF_COEFF_11 0x000007ff + +/*****************************************************************************/ +#define DIF_BPF_COEFF1213 (DIRECT_IF_REVB_BASE + 0x00000060) +/*****************************************************************************/ +/* Reserved [31:27] */ +#define FLD_DIF_BPF_COEFF_12 0x07ff0000 +/* Reserved [15:12] */ +#define FLD_DIF_BPF_COEFF_13 0x00000fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF1415 (DIRECT_IF_REVB_BASE + 0x00000064) +/*****************************************************************************/ +/* Reserved [31:28] */ +#define FLD_DIF_BPF_COEFF_14 0x0fff0000 +/* Reserved [15:12] */ +#define FLD_DIF_BPF_COEFF_15 0x00000fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF1617 (DIRECT_IF_REVB_BASE + 0x00000068) +/*****************************************************************************/ +/* Reserved [31:29] */ +#define FLD_DIF_BPF_COEFF_16 0x1fff0000 +/* Reserved [15:13] */ +#define FLD_DIF_BPF_COEFF_17 0x00001fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF1819 (DIRECT_IF_REVB_BASE + 0x0000006c) +/*****************************************************************************/ +/* Reserved [31:29] */ +#define FLD_DIF_BPF_COEFF_18 0x1fff0000 +/* Reserved [15:13] */ +#define FLD_DIF_BPF_COEFF_19 0x00001fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF2021 (DIRECT_IF_REVB_BASE + 0x00000070) +/*****************************************************************************/ +/* Reserved [31:29] */ +#define FLD_DIF_BPF_COEFF_20 0x1fff0000 +/* Reserved [15:14] */ +#define FLD_DIF_BPF_COEFF_21 0x00003fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF2223 (DIRECT_IF_REVB_BASE + 0x00000074) +/*****************************************************************************/ +/* Reserved [31:30] */ +#define FLD_DIF_BPF_COEFF_22 0x3fff0000 +/* Reserved [15:14] */ +#define FLD_DIF_BPF_COEFF_23 0x00003fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF2425 (DIRECT_IF_REVB_BASE + 0x00000078) +/*****************************************************************************/ +/* Reserved [31:30] */ +#define FLD_DIF_BPF_COEFF_24 0x3fff0000 +/* Reserved [15:14] */ +#define FLD_DIF_BPF_COEFF_25 0x00003fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF2627 (DIRECT_IF_REVB_BASE + 0x0000007c) +/*****************************************************************************/ +/* Reserved [31:30] */ +#define FLD_DIF_BPF_COEFF_26 0x3fff0000 +/* Reserved [15:14] */ +#define FLD_DIF_BPF_COEFF_27 0x00003fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF2829 (DIRECT_IF_REVB_BASE + 0x00000080) +/*****************************************************************************/ +/* Reserved [31:30] */ +#define FLD_DIF_BPF_COEFF_28 0x3fff0000 +/* Reserved [15:14] */ +#define FLD_DIF_BPF_COEFF_29 0x00003fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF3031 (DIRECT_IF_REVB_BASE + 0x00000084) +/*****************************************************************************/ +/* Reserved [31:30] */ +#define FLD_DIF_BPF_COEFF_30 0x3fff0000 +/* Reserved [15:14] */ +#define FLD_DIF_BPF_COEFF_31 0x00003fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF3233 (DIRECT_IF_REVB_BASE + 0x00000088) +/*****************************************************************************/ +/* Reserved [31:30] */ +#define FLD_DIF_BPF_COEFF_32 0x3fff0000 +/* Reserved [15:14] */ +#define FLD_DIF_BPF_COEFF_33 0x00003fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF3435 (DIRECT_IF_REVB_BASE + 0x0000008c) +/*****************************************************************************/ +/* Reserved [31:30] */ +#define FLD_DIF_BPF_COEFF_34 0x3fff0000 +/* Reserved [15:14] */ +#define FLD_DIF_BPF_COEFF_35 0x00003fff + +/*****************************************************************************/ +#define DIF_BPF_COEFF36 (DIRECT_IF_REVB_BASE + 0x00000090) +/*****************************************************************************/ +/* Reserved [31:30] */ +#define FLD_DIF_BPF_COEFF_36 0x3fff0000 +/* Reserved [15:0] */ + +/*****************************************************************************/ +#define DIF_RPT_VARIANCE (DIRECT_IF_REVB_BASE + 0x00000094) +/*****************************************************************************/ +/* Reserved [31:20] */ +#define FLD_DIF_RPT_VARIANCE 0x000fffff + +/*****************************************************************************/ +#define DIF_SOFT_RST_CTRL_REVB (DIRECT_IF_REVB_BASE + 0x00000098) +/*****************************************************************************/ +/* Reserved [31:8] */ +#define FLD_DIF_DIF_SOFT_RST 0x00000080 +#define FLD_DIF_DIF_REG_RST_MSK 0x00000040 +#define FLD_DIF_AGC_RST_MSK 0x00000020 +#define FLD_DIF_CMP_RST_MSK 0x00000010 +#define FLD_DIF_AVS_RST_MSK 0x00000008 +#define FLD_DIF_NYQ_RST_MSK 0x00000004 +#define FLD_DIF_DIF_SRC_RST_MSK 0x00000002 +#define FLD_DIF_PLL_RST_MSK 0x00000001 + +/*****************************************************************************/ +#define DIF_PLL_FREQ_ERR (DIRECT_IF_REVB_BASE + 0x0000009c) +/*****************************************************************************/ +/* Reserved [31:25] */ +#define FLD_DIF_CTL_IP 0x01ffffff + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1739 @@ +/* + cx231xx-core.c - driver for Conexant Cx23100/101/102 + USB video capture devices + + Copyright (C) 2008 + Based on em28xx driver + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx231xx.h" +#include "cx231xx-reg.h" + +/* #define ENABLE_DEBUG_ISOC_FRAMES */ + +static unsigned int core_debug; +module_param(core_debug, int, 0644); +MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); + +#define cx231xx_coredbg(fmt, arg...) do {\ + if (core_debug) \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); } while (0) + +static unsigned int reg_debug; +module_param(reg_debug, int, 0644); +MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); + +static int alt = CX231XX_PINOUT; +module_param(alt, int, 0644); +MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); + +#define cx231xx_isocdbg(fmt, arg...) do {\ + if (core_debug) \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); } while (0) + +/***************************************************************** +* Device control list functions * +******************************************************************/ + +LIST_HEAD(cx231xx_devlist); +static DEFINE_MUTEX(cx231xx_devlist_mutex); + +/* + * cx231xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +void cx231xx_remove_from_devlist(struct cx231xx *dev) +{ + if (dev == NULL) + return; + if (dev->udev == NULL) + return; + + if (atomic_read(&dev->devlist_count) > 0) { + mutex_lock(&cx231xx_devlist_mutex); + list_del(&dev->devlist); + atomic_dec(&dev->devlist_count); + mutex_unlock(&cx231xx_devlist_mutex); + } +}; + +void cx231xx_add_into_devlist(struct cx231xx *dev) +{ + mutex_lock(&cx231xx_devlist_mutex); + list_add_tail(&dev->devlist, &cx231xx_devlist); + atomic_inc(&dev->devlist_count); + mutex_unlock(&cx231xx_devlist_mutex); +}; + +static LIST_HEAD(cx231xx_extension_devlist); + +int cx231xx_register_extension(struct cx231xx_ops *ops) +{ + struct cx231xx *dev = NULL; + + mutex_lock(&cx231xx_devlist_mutex); + list_add_tail(&ops->next, &cx231xx_extension_devlist); + list_for_each_entry(dev, &cx231xx_devlist, devlist) + ops->init(dev); + + printk(KERN_INFO DRIVER_NAME ": %s initialized\n", ops->name); + mutex_unlock(&cx231xx_devlist_mutex); + return 0; +} +EXPORT_SYMBOL(cx231xx_register_extension); + +void cx231xx_unregister_extension(struct cx231xx_ops *ops) +{ + struct cx231xx *dev = NULL; + + mutex_lock(&cx231xx_devlist_mutex); + list_for_each_entry(dev, &cx231xx_devlist, devlist) + ops->fini(dev); + + + printk(KERN_INFO DRIVER_NAME ": %s removed\n", ops->name); + list_del(&ops->next); + mutex_unlock(&cx231xx_devlist_mutex); +} +EXPORT_SYMBOL(cx231xx_unregister_extension); + +void cx231xx_init_extension(struct cx231xx *dev) +{ + struct cx231xx_ops *ops = NULL; + + mutex_lock(&cx231xx_devlist_mutex); + if (!list_empty(&cx231xx_extension_devlist)) { + list_for_each_entry(ops, &cx231xx_extension_devlist, next) { + if (ops->init) + ops->init(dev); + } + } + mutex_unlock(&cx231xx_devlist_mutex); +} + +void cx231xx_close_extension(struct cx231xx *dev) +{ + struct cx231xx_ops *ops = NULL; + + mutex_lock(&cx231xx_devlist_mutex); + if (!list_empty(&cx231xx_extension_devlist)) { + list_for_each_entry(ops, &cx231xx_extension_devlist, next) { + if (ops->fini) + ops->fini(dev); + } + } + mutex_unlock(&cx231xx_devlist_mutex); +} + +/**************************************************************** +* U S B related functions * +*****************************************************************/ +int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus, + struct cx231xx_i2c_xfer_data *req_data) +{ + int status = 0; + struct cx231xx *dev = i2c_bus->dev; + struct VENDOR_REQUEST_IN ven_req; + + u8 saddr_len = 0; + u8 _i2c_period = 0; + u8 _i2c_nostop = 0; + u8 _i2c_reserve = 0; + + /* Get the I2C period, nostop and reserve parameters */ + _i2c_period = i2c_bus->i2c_period; + _i2c_nostop = i2c_bus->i2c_nostop; + _i2c_reserve = i2c_bus->i2c_reserve; + + saddr_len = req_data->saddr_len; + + /* Set wValue */ + if (saddr_len == 1) /* need check saddr_len == 0 */ + ven_req.wValue = + req_data-> + dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 | + _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6; + else + ven_req.wValue = + req_data-> + dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 | + _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6; + + /* set channel number */ + if (req_data->direction & I2C_M_RD) { + /* channel number, for read,spec required channel_num +4 */ + ven_req.bRequest = i2c_bus->nr + 4; + } else + ven_req.bRequest = i2c_bus->nr; /* channel number, */ + + /* set index value */ + switch (saddr_len) { + case 0: + ven_req.wIndex = 0; /* need check */ + break; + case 1: + ven_req.wIndex = (req_data->saddr_dat & 0xff); + break; + case 2: + ven_req.wIndex = req_data->saddr_dat; + break; + } + + /* set wLength value */ + ven_req.wLength = req_data->buf_size; + + /* set bData value */ + ven_req.bData = 0; + + /* set the direction */ + if (req_data->direction) { + ven_req.direction = USB_DIR_IN; + memset(req_data->p_buffer, 0x00, ven_req.wLength); + } else + ven_req.direction = USB_DIR_OUT; + + /* set the buffer for read / write */ + ven_req.pBuff = req_data->p_buffer; + + + /* call common vendor command request */ + status = cx231xx_send_vendor_cmd(dev, &ven_req); + if (status < 0) { + cx231xx_info + ("UsbInterface::sendCommand, failed with status -%d\n", + status); + } + + return status; +} +EXPORT_SYMBOL_GPL(cx231xx_send_usb_command); + +/* + * Sends/Receives URB control messages, assuring to use a kalloced buffer + * for all operations (dev->urb_buf), to avoid using stacked buffers, as + * they aren't safe for usage with USB, due to DMA restrictions. + * Also implements the debug code for control URB's. + */ +static int __usb_control_msg(struct cx231xx *dev, unsigned int pipe, + __u8 request, __u8 requesttype, __u16 value, __u16 index, + void *data, __u16 size, int timeout) +{ + int rc, i; + + if (reg_debug) { + printk(KERN_DEBUG "%s: (pipe 0x%08x): " + "%s: %02x %02x %02x %02x %02x %02x %02x %02x ", + dev->name, + pipe, + (requesttype & USB_DIR_IN) ? "IN" : "OUT", + requesttype, + request, + value & 0xff, value >> 8, + index & 0xff, index >> 8, + size & 0xff, size >> 8); + if (!(requesttype & USB_DIR_IN)) { + printk(KERN_CONT ">>>"); + for (i = 0; i < size; i++) + printk(KERN_CONT " %02x", + ((unsigned char *)data)[i]); + } + } + + /* Do the real call to usb_control_msg */ + mutex_lock(&dev->ctrl_urb_lock); + if (!(requesttype & USB_DIR_IN) && size) + memcpy(dev->urb_buf, data, size); + rc = usb_control_msg(dev->udev, pipe, request, requesttype, value, + index, dev->urb_buf, size, timeout); + if ((requesttype & USB_DIR_IN) && size) + memcpy(data, dev->urb_buf, size); + mutex_unlock(&dev->ctrl_urb_lock); + + if (reg_debug) { + if (unlikely(rc < 0)) { + printk(KERN_CONT "FAILED!\n"); + return rc; + } + + if ((requesttype & USB_DIR_IN)) { + printk(KERN_CONT "<<<"); + for (i = 0; i < size; i++) + printk(KERN_CONT " %02x", + ((unsigned char *)data)[i]); + } + printk(KERN_CONT "\n"); + } + + return rc; +} + + +/* + * cx231xx_read_ctrl_reg() + * reads data from the usb device specifying bRequest and wValue + */ +int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, + char *buf, int len) +{ + u8 val = 0; + int ret; + int pipe = usb_rcvctrlpipe(dev->udev, 0); + + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + + if (len > URB_MAX_CTRL_SIZE) + return -EINVAL; + + switch (len) { + case 1: + val = ENABLE_ONE_BYTE; + break; + case 2: + val = ENABLE_TWE_BYTE; + break; + case 3: + val = ENABLE_THREE_BYTE; + break; + case 4: + val = ENABLE_FOUR_BYTE; + break; + default: + val = 0xFF; /* invalid option */ + } + + if (val == 0xFF) + return -EINVAL; + + ret = __usb_control_msg(dev, pipe, req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, reg, buf, len, HZ); + return ret; +} + +int cx231xx_send_vendor_cmd(struct cx231xx *dev, + struct VENDOR_REQUEST_IN *ven_req) +{ + int ret; + int pipe = 0; + int unsend_size = 0; + u8 *pdata; + + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + + if ((ven_req->wLength > URB_MAX_CTRL_SIZE)) + return -EINVAL; + + if (ven_req->direction) + pipe = usb_rcvctrlpipe(dev->udev, 0); + else + pipe = usb_sndctrlpipe(dev->udev, 0); + + /* + * If the cx23102 read more than 4 bytes with i2c bus, + * need chop to 4 byte per request + */ + if ((ven_req->wLength > 4) && ((ven_req->bRequest == 0x4) || + (ven_req->bRequest == 0x5) || + (ven_req->bRequest == 0x6))) { + unsend_size = 0; + pdata = ven_req->pBuff; + + + unsend_size = ven_req->wLength; + + /* the first package */ + ven_req->wValue = ven_req->wValue & 0xFFFB; + ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x2; + ret = __usb_control_msg(dev, pipe, ven_req->bRequest, + ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + ven_req->wValue, ven_req->wIndex, pdata, + 0x0004, HZ); + unsend_size = unsend_size - 4; + + /* the middle package */ + ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x42; + while (unsend_size - 4 > 0) { + pdata = pdata + 4; + ret = __usb_control_msg(dev, pipe, + ven_req->bRequest, + ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + ven_req->wValue, ven_req->wIndex, pdata, + 0x0004, HZ); + unsend_size = unsend_size - 4; + } + + /* the last package */ + ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x40; + pdata = pdata + 4; + ret = __usb_control_msg(dev, pipe, ven_req->bRequest, + ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + ven_req->wValue, ven_req->wIndex, pdata, + unsend_size, HZ); + } else { + ret = __usb_control_msg(dev, pipe, ven_req->bRequest, + ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + ven_req->wValue, ven_req->wIndex, + ven_req->pBuff, ven_req->wLength, HZ); + } + + return ret; +} + +/* + * cx231xx_write_ctrl_reg() + * sends data to the usb device, specifying bRequest + */ +int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, char *buf, + int len) +{ + u8 val = 0; + int ret; + int pipe = usb_sndctrlpipe(dev->udev, 0); + + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + + if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) + return -EINVAL; + + switch (len) { + case 1: + val = ENABLE_ONE_BYTE; + break; + case 2: + val = ENABLE_TWE_BYTE; + break; + case 3: + val = ENABLE_THREE_BYTE; + break; + case 4: + val = ENABLE_FOUR_BYTE; + break; + default: + val = 0xFF; /* invalid option */ + } + + if (val == 0xFF) + return -EINVAL; + + if (reg_debug) { + int byte; + + cx231xx_isocdbg("(pipe 0x%08x): " + "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", + pipe, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, val, reg & 0xff, + reg >> 8, len & 0xff, len >> 8); + + for (byte = 0; byte < len; byte++) + cx231xx_isocdbg(" %02x", (unsigned char)buf[byte]); + cx231xx_isocdbg("\n"); + } + + ret = __usb_control_msg(dev, pipe, req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, reg, buf, len, HZ); + + return ret; +} + +/**************************************************************** +* USB Alternate Setting functions * +*****************************************************************/ + +int cx231xx_set_video_alternate(struct cx231xx *dev) +{ + int errCode, prev_alt = dev->video_mode.alt; + unsigned int min_pkt_size = dev->width * 2 + 4; + u32 usb_interface_index = 0; + + /* When image size is bigger than a certain value, + the frame size should be increased, otherwise, only + green screen will be received. + */ + if (dev->width * 2 * dev->height > 720 * 240 * 2) + min_pkt_size *= 2; + + if (dev->width > 360) { + /* resolutions: 720,704,640 */ + dev->video_mode.alt = 3; + } else if (dev->width > 180) { + /* resolutions: 360,352,320,240 */ + dev->video_mode.alt = 2; + } else if (dev->width > 0) { + /* resolutions: 180,176,160,128,88 */ + dev->video_mode.alt = 1; + } else { + /* Change to alt0 BULK to release USB bandwidth */ + dev->video_mode.alt = 0; + } + + if (dev->USE_ISO == 0) + dev->video_mode.alt = 0; + + cx231xx_coredbg("dev->video_mode.alt= %d\n", dev->video_mode.alt); + + /* Get the correct video interface Index */ + usb_interface_index = + dev->current_pcb_config.hs_config_info[0].interface_info. + video_index + 1; + + if (dev->video_mode.alt != prev_alt) { + cx231xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", + min_pkt_size, dev->video_mode.alt); + + if (dev->video_mode.alt_max_pkt_size != NULL) + dev->video_mode.max_pkt_size = + dev->video_mode.alt_max_pkt_size[dev->video_mode.alt]; + cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", + dev->video_mode.alt, + dev->video_mode.max_pkt_size); + errCode = + usb_set_interface(dev->udev, usb_interface_index, + dev->video_mode.alt); + if (errCode < 0) { + cx231xx_errdev + ("cannot change alt number to %d (error=%i)\n", + dev->video_mode.alt, errCode); + return errCode; + } + } + return 0; +} + +int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt) +{ + int status = 0; + u32 usb_interface_index = 0; + u32 max_pkt_size = 0; + + switch (index) { + case INDEX_TS1: + usb_interface_index = + dev->current_pcb_config.hs_config_info[0].interface_info. + ts1_index + 1; + dev->ts1_mode.alt = alt; + if (dev->ts1_mode.alt_max_pkt_size != NULL) + max_pkt_size = dev->ts1_mode.max_pkt_size = + dev->ts1_mode.alt_max_pkt_size[dev->ts1_mode.alt]; + break; + case INDEX_TS2: + usb_interface_index = + dev->current_pcb_config.hs_config_info[0].interface_info. + ts2_index + 1; + break; + case INDEX_AUDIO: + usb_interface_index = + dev->current_pcb_config.hs_config_info[0].interface_info. + audio_index + 1; + dev->adev.alt = alt; + if (dev->adev.alt_max_pkt_size != NULL) + max_pkt_size = dev->adev.max_pkt_size = + dev->adev.alt_max_pkt_size[dev->adev.alt]; + break; + case INDEX_VIDEO: + usb_interface_index = + dev->current_pcb_config.hs_config_info[0].interface_info. + video_index + 1; + dev->video_mode.alt = alt; + if (dev->video_mode.alt_max_pkt_size != NULL) + max_pkt_size = dev->video_mode.max_pkt_size = + dev->video_mode.alt_max_pkt_size[dev->video_mode. + alt]; + break; + case INDEX_VANC: + if (dev->board.no_alt_vanc) + return 0; + usb_interface_index = + dev->current_pcb_config.hs_config_info[0].interface_info. + vanc_index + 1; + dev->vbi_mode.alt = alt; + if (dev->vbi_mode.alt_max_pkt_size != NULL) + max_pkt_size = dev->vbi_mode.max_pkt_size = + dev->vbi_mode.alt_max_pkt_size[dev->vbi_mode.alt]; + break; + case INDEX_HANC: + usb_interface_index = + dev->current_pcb_config.hs_config_info[0].interface_info. + hanc_index + 1; + dev->sliced_cc_mode.alt = alt; + if (dev->sliced_cc_mode.alt_max_pkt_size != NULL) + max_pkt_size = dev->sliced_cc_mode.max_pkt_size = + dev->sliced_cc_mode.alt_max_pkt_size[dev-> + sliced_cc_mode. + alt]; + break; + default: + break; + } + + if (alt > 0 && max_pkt_size == 0) { + cx231xx_errdev + ("can't change interface %d alt no. to %d: Max. Pkt size = 0\n", + usb_interface_index, alt); + /*To workaround error number=-71 on EP0 for videograbber, + need add following codes.*/ + if (dev->board.no_alt_vanc) + return -1; + } + + cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u," + "Interface = %d\n", alt, max_pkt_size, + usb_interface_index); + + if (usb_interface_index > 0) { + status = usb_set_interface(dev->udev, usb_interface_index, alt); + if (status < 0) { + cx231xx_errdev + ("can't change interface %d alt no. to %d (err=%i)\n", + usb_interface_index, alt, status); + return status; + } + } + + return status; +} +EXPORT_SYMBOL_GPL(cx231xx_set_alt_setting); + +int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio) +{ + int rc = 0; + + if (!gpio) + return rc; + + /* Send GPIO reset sequences specified at board entry */ + while (gpio->sleep >= 0) { + rc = cx231xx_set_gpio_value(dev, gpio->bit, gpio->val); + if (rc < 0) + return rc; + + if (gpio->sleep > 0) + msleep(gpio->sleep); + + gpio++; + } + return rc; +} + +int cx231xx_demod_reset(struct cx231xx *dev) +{ + + u8 status = 0; + u8 value[4] = { 0, 0, 0, 0 }; + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, + value, 4); + + cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, + value[0], value[1], value[2], value[3]); + + cx231xx_coredbg("Enter cx231xx_demod_reset()\n"); + + value[1] = (u8) 0x3; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(10); + + value[1] = (u8) 0x0; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(10); + + value[1] = (u8) 0x3; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + PWR_CTL_EN, value, 4); + msleep(10); + + + + status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, + value, 4); + + cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, + value[0], value[1], value[2], value[3]); + + return status; +} +EXPORT_SYMBOL_GPL(cx231xx_demod_reset); +int is_fw_load(struct cx231xx *dev) +{ + return cx231xx_check_fw(dev); +} +EXPORT_SYMBOL_GPL(is_fw_load); + +int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode) +{ + int errCode = 0; + + if (dev->mode == set_mode) + return 0; + + if (set_mode == CX231XX_SUSPEND) { + /* Set the chip in power saving mode */ + dev->mode = set_mode; + } + + /* Resource is locked */ + if (dev->mode != CX231XX_SUSPEND) + return -EINVAL; + + dev->mode = set_mode; + + if (dev->mode == CX231XX_DIGITAL_MODE)/* Set Digital power mode */ { + /* set AGC mode to Digital */ + switch (dev->model) { + case CX231XX_BOARD_CNXT_CARRAERA: + case CX231XX_BOARD_CNXT_RDE_250: + case CX231XX_BOARD_CNXT_SHELBY: + case CX231XX_BOARD_CNXT_RDU_250: + errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); + break; + case CX231XX_BOARD_CNXT_RDE_253S: + case CX231XX_BOARD_CNXT_RDU_253S: + errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1); + break; + case CX231XX_BOARD_HAUPPAUGE_EXETER: + errCode = cx231xx_set_power_mode(dev, + POLARIS_AVMODE_DIGITAL); + break; + default: + break; + } + } else/* Set Analog Power mode */ { + /* set AGC mode to Analog */ + switch (dev->model) { + case CX231XX_BOARD_CNXT_CARRAERA: + case CX231XX_BOARD_CNXT_RDE_250: + case CX231XX_BOARD_CNXT_SHELBY: + case CX231XX_BOARD_CNXT_RDU_250: + errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1); + break; + case CX231XX_BOARD_CNXT_RDE_253S: + case CX231XX_BOARD_CNXT_RDU_253S: + case CX231XX_BOARD_HAUPPAUGE_EXETER: + case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: + errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); + break; + default: + break; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(cx231xx_set_mode); + +int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size) +{ + int errCode = 0; + int actlen, ret = -ENOMEM; + u32 *buffer; + +buffer = kzalloc(4096, GFP_KERNEL); + if (buffer == NULL) { + cx231xx_info("out of mem\n"); + return -ENOMEM; + } + memcpy(&buffer[0], firmware, 4096); + + ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5), + buffer, 4096, &actlen, 2000); + + if (ret) + cx231xx_info("bulk message failed: %d (%d/%d)", ret, + size, actlen); + else { + errCode = actlen != size ? -1 : 0; + } +kfree(buffer); + return 0; +} + +/***************************************************************** +* URB Streaming functions * +******************************************************************/ + +/* + * IRQ callback, called by URB callback + */ +static void cx231xx_isoc_irq_callback(struct urb *urb) +{ + struct cx231xx_dmaqueue *dma_q = urb->context; + struct cx231xx_video_mode *vmode = + container_of(dma_q, struct cx231xx_video_mode, vidq); + struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode); + int rc, i; + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + cx231xx_isocdbg("urb completition error %d.\n", urb->status); + break; + } + + /* Copy data from URB */ + spin_lock(&dev->video_mode.slock); + rc = dev->video_mode.isoc_ctl.isoc_copy(dev, urb); + spin_unlock(&dev->video_mode.slock); + + /* Reset urb buffers */ + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + urb->status = 0; + + urb->status = usb_submit_urb(urb, GFP_ATOMIC); + if (urb->status) { + cx231xx_isocdbg("urb resubmit failed (error=%i)\n", + urb->status); + } +} +/***************************************************************** +* URB Streaming functions * +******************************************************************/ + +/* + * IRQ callback, called by URB callback + */ +static void cx231xx_bulk_irq_callback(struct urb *urb) +{ + struct cx231xx_dmaqueue *dma_q = urb->context; + struct cx231xx_video_mode *vmode = + container_of(dma_q, struct cx231xx_video_mode, vidq); + struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode); + int rc; + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + cx231xx_isocdbg("urb completition error %d.\n", urb->status); + break; + } + + /* Copy data from URB */ + spin_lock(&dev->video_mode.slock); + rc = dev->video_mode.bulk_ctl.bulk_copy(dev, urb); + spin_unlock(&dev->video_mode.slock); + + /* Reset urb buffers */ + urb->status = 0; + + urb->status = usb_submit_urb(urb, GFP_ATOMIC); + if (urb->status) { + cx231xx_isocdbg("urb resubmit failed (error=%i)\n", + urb->status); + } +} +/* + * Stop and Deallocate URBs + */ +void cx231xx_uninit_isoc(struct cx231xx *dev) +{ + struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; + struct urb *urb; + int i; + + cx231xx_isocdbg("cx231xx: called cx231xx_uninit_isoc\n"); + + dev->video_mode.isoc_ctl.nfields = -1; + for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) { + urb = dev->video_mode.isoc_ctl.urb[i]; + if (urb) { + if (!irqs_disabled()) + usb_kill_urb(urb); + else + usb_unlink_urb(urb); + + if (dev->video_mode.isoc_ctl.transfer_buffer[i]) { + usb_free_coherent(dev->udev, + urb->transfer_buffer_length, + dev->video_mode.isoc_ctl. + transfer_buffer[i], + urb->transfer_dma); + } + usb_free_urb(urb); + dev->video_mode.isoc_ctl.urb[i] = NULL; + } + dev->video_mode.isoc_ctl.transfer_buffer[i] = NULL; + } + + kfree(dev->video_mode.isoc_ctl.urb); + kfree(dev->video_mode.isoc_ctl.transfer_buffer); + kfree(dma_q->p_left_data); + + dev->video_mode.isoc_ctl.urb = NULL; + dev->video_mode.isoc_ctl.transfer_buffer = NULL; + dev->video_mode.isoc_ctl.num_bufs = 0; + dma_q->p_left_data = NULL; + + if (dev->mode_tv == 0) + cx231xx_capture_start(dev, 0, Raw_Video); + else + cx231xx_capture_start(dev, 0, TS1_serial_mode); + + +} +EXPORT_SYMBOL_GPL(cx231xx_uninit_isoc); + +/* + * Stop and Deallocate URBs + */ +void cx231xx_uninit_bulk(struct cx231xx *dev) +{ + struct urb *urb; + int i; + + cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n"); + + dev->video_mode.bulk_ctl.nfields = -1; + for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) { + urb = dev->video_mode.bulk_ctl.urb[i]; + if (urb) { + if (!irqs_disabled()) + usb_kill_urb(urb); + else + usb_unlink_urb(urb); + + if (dev->video_mode.bulk_ctl.transfer_buffer[i]) { + usb_free_coherent(dev->udev, + urb->transfer_buffer_length, + dev->video_mode.isoc_ctl. + transfer_buffer[i], + urb->transfer_dma); + } + usb_free_urb(urb); + dev->video_mode.bulk_ctl.urb[i] = NULL; + } + dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL; + } + + kfree(dev->video_mode.bulk_ctl.urb); + kfree(dev->video_mode.bulk_ctl.transfer_buffer); + + dev->video_mode.bulk_ctl.urb = NULL; + dev->video_mode.bulk_ctl.transfer_buffer = NULL; + dev->video_mode.bulk_ctl.num_bufs = 0; + + if (dev->mode_tv == 0) + cx231xx_capture_start(dev, 0, Raw_Video); + else + cx231xx_capture_start(dev, 0, TS1_serial_mode); + + +} +EXPORT_SYMBOL_GPL(cx231xx_uninit_bulk); + +/* + * Allocate URBs and start IRQ + */ +int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*isoc_copy) (struct cx231xx *dev, struct urb *urb)) +{ + struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; + int i; + int sb_size, pipe; + struct urb *urb; + int j, k; + int rc; + + /* De-allocates all pending stuff */ + cx231xx_uninit_isoc(dev); + + dma_q->p_left_data = kzalloc(4096, GFP_KERNEL); + if (dma_q->p_left_data == NULL) { + cx231xx_info("out of mem\n"); + return -ENOMEM; + } + + + + dev->video_mode.isoc_ctl.isoc_copy = isoc_copy; + dev->video_mode.isoc_ctl.num_bufs = num_bufs; + dma_q->pos = 0; + dma_q->is_partial_line = 0; + dma_q->last_sav = 0; + dma_q->current_field = -1; + dma_q->field1_done = 0; + dma_q->lines_per_field = dev->height / 2; + dma_q->bytes_left_in_line = dev->width << 1; + dma_q->lines_completed = 0; + dma_q->mpeg_buffer_done = 0; + dma_q->left_data_count = 0; + dma_q->mpeg_buffer_completed = 0; + dma_q->add_ps_package_head = CX231XX_NEED_ADD_PS_PACKAGE_HEAD; + dma_q->ps_head[0] = 0x00; + dma_q->ps_head[1] = 0x00; + dma_q->ps_head[2] = 0x01; + dma_q->ps_head[3] = 0xBA; + for (i = 0; i < 8; i++) + dma_q->partial_buf[i] = 0; + + dev->video_mode.isoc_ctl.urb = + kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + if (!dev->video_mode.isoc_ctl.urb) { + cx231xx_errdev("cannot alloc memory for usb buffers\n"); + return -ENOMEM; + } + + dev->video_mode.isoc_ctl.transfer_buffer = + kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + if (!dev->video_mode.isoc_ctl.transfer_buffer) { + cx231xx_errdev("cannot allocate memory for usbtransfer\n"); + kfree(dev->video_mode.isoc_ctl.urb); + return -ENOMEM; + } + + dev->video_mode.isoc_ctl.max_pkt_size = max_pkt_size; + dev->video_mode.isoc_ctl.buf = NULL; + + sb_size = max_packets * dev->video_mode.isoc_ctl.max_pkt_size; + + if (dev->mode_tv == 1) + dev->video_mode.end_point_addr = 0x81; + else + dev->video_mode.end_point_addr = 0x84; + + + /* allocate urbs and transfer buffers */ + for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) { + urb = usb_alloc_urb(max_packets, GFP_KERNEL); + if (!urb) { + cx231xx_err("cannot alloc isoc_ctl.urb %i\n", i); + cx231xx_uninit_isoc(dev); + return -ENOMEM; + } + dev->video_mode.isoc_ctl.urb[i] = urb; + + dev->video_mode.isoc_ctl.transfer_buffer[i] = + usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, + &urb->transfer_dma); + if (!dev->video_mode.isoc_ctl.transfer_buffer[i]) { + cx231xx_err("unable to allocate %i bytes for transfer" + " buffer %i%s\n", + sb_size, i, + in_interrupt() ? " while in int" : ""); + cx231xx_uninit_isoc(dev); + return -ENOMEM; + } + memset(dev->video_mode.isoc_ctl.transfer_buffer[i], 0, sb_size); + + pipe = + usb_rcvisocpipe(dev->udev, dev->video_mode.end_point_addr); + + usb_fill_int_urb(urb, dev->udev, pipe, + dev->video_mode.isoc_ctl.transfer_buffer[i], + sb_size, cx231xx_isoc_irq_callback, dma_q, 1); + + urb->number_of_packets = max_packets; + urb->transfer_flags = URB_ISO_ASAP; + + k = 0; + for (j = 0; j < max_packets; j++) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = + dev->video_mode.isoc_ctl.max_pkt_size; + k += dev->video_mode.isoc_ctl.max_pkt_size; + } + } + + init_waitqueue_head(&dma_q->wq); + + /* submit urbs and enables IRQ */ + for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->video_mode.isoc_ctl.urb[i], + GFP_ATOMIC); + if (rc) { + cx231xx_err("submit of urb %i failed (error=%i)\n", i, + rc); + cx231xx_uninit_isoc(dev); + return rc; + } + } + + if (dev->mode_tv == 0) + cx231xx_capture_start(dev, 1, Raw_Video); + else + cx231xx_capture_start(dev, 1, TS1_serial_mode); + + return 0; +} +EXPORT_SYMBOL_GPL(cx231xx_init_isoc); + +/* + * Allocate URBs and start IRQ + */ +int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*bulk_copy) (struct cx231xx *dev, struct urb *urb)) +{ + struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; + int i; + int sb_size, pipe; + struct urb *urb; + int rc; + + dev->video_input = dev->video_input > 2 ? 2 : dev->video_input; + + cx231xx_coredbg("Setting Video mux to %d\n", dev->video_input); + + video_mux(dev, dev->video_input); + + /* De-allocates all pending stuff */ + cx231xx_uninit_bulk(dev); + + dev->video_mode.bulk_ctl.bulk_copy = bulk_copy; + dev->video_mode.bulk_ctl.num_bufs = num_bufs; + dma_q->pos = 0; + dma_q->is_partial_line = 0; + dma_q->last_sav = 0; + dma_q->current_field = -1; + dma_q->field1_done = 0; + dma_q->lines_per_field = dev->height / 2; + dma_q->bytes_left_in_line = dev->width << 1; + dma_q->lines_completed = 0; + dma_q->mpeg_buffer_done = 0; + dma_q->left_data_count = 0; + dma_q->mpeg_buffer_completed = 0; + dma_q->ps_head[0] = 0x00; + dma_q->ps_head[1] = 0x00; + dma_q->ps_head[2] = 0x01; + dma_q->ps_head[3] = 0xBA; + for (i = 0; i < 8; i++) + dma_q->partial_buf[i] = 0; + + dev->video_mode.bulk_ctl.urb = + kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + if (!dev->video_mode.bulk_ctl.urb) { + cx231xx_errdev("cannot alloc memory for usb buffers\n"); + return -ENOMEM; + } + + dev->video_mode.bulk_ctl.transfer_buffer = + kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + if (!dev->video_mode.bulk_ctl.transfer_buffer) { + cx231xx_errdev("cannot allocate memory for usbtransfer\n"); + kfree(dev->video_mode.bulk_ctl.urb); + return -ENOMEM; + } + + dev->video_mode.bulk_ctl.max_pkt_size = max_pkt_size; + dev->video_mode.bulk_ctl.buf = NULL; + + sb_size = max_packets * dev->video_mode.bulk_ctl.max_pkt_size; + + if (dev->mode_tv == 1) + dev->video_mode.end_point_addr = 0x81; + else + dev->video_mode.end_point_addr = 0x84; + + + /* allocate urbs and transfer buffers */ + for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i); + cx231xx_uninit_bulk(dev); + return -ENOMEM; + } + dev->video_mode.bulk_ctl.urb[i] = urb; + urb->transfer_flags = 0; + + dev->video_mode.bulk_ctl.transfer_buffer[i] = + usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, + &urb->transfer_dma); + if (!dev->video_mode.bulk_ctl.transfer_buffer[i]) { + cx231xx_err("unable to allocate %i bytes for transfer" + " buffer %i%s\n", + sb_size, i, + in_interrupt() ? " while in int" : ""); + cx231xx_uninit_bulk(dev); + return -ENOMEM; + } + memset(dev->video_mode.bulk_ctl.transfer_buffer[i], 0, sb_size); + + pipe = usb_rcvbulkpipe(dev->udev, + dev->video_mode.end_point_addr); + usb_fill_bulk_urb(urb, dev->udev, pipe, + dev->video_mode.bulk_ctl.transfer_buffer[i], + sb_size, cx231xx_bulk_irq_callback, dma_q); + } + + init_waitqueue_head(&dma_q->wq); + + /* submit urbs and enables IRQ */ + for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->video_mode.bulk_ctl.urb[i], + GFP_ATOMIC); + if (rc) { + cx231xx_err("submit of urb %i failed (error=%i)\n", i, + rc); + cx231xx_uninit_bulk(dev); + return rc; + } + } + + if (dev->mode_tv == 0) + cx231xx_capture_start(dev, 1, Raw_Video); + else + cx231xx_capture_start(dev, 1, TS1_serial_mode); + + return 0; +} +EXPORT_SYMBOL_GPL(cx231xx_init_bulk); +void cx231xx_stop_TS1(struct cx231xx *dev) +{ + int status = 0; + u8 val[4] = { 0, 0, 0, 0 }; + + val[0] = 0x00; + val[1] = 0x03; + val[2] = 0x00; + val[3] = 0x00; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + TS_MODE_REG, val, 4); + + val[0] = 0x00; + val[1] = 0x70; + val[2] = 0x04; + val[3] = 0x00; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + TS1_CFG_REG, val, 4); +} +/* EXPORT_SYMBOL_GPL(cx231xx_stop_TS1); */ +void cx231xx_start_TS1(struct cx231xx *dev) +{ + int status = 0; + u8 val[4] = { 0, 0, 0, 0 }; + + val[0] = 0x03; + val[1] = 0x03; + val[2] = 0x00; + val[3] = 0x00; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + TS_MODE_REG, val, 4); + + val[0] = 0x04; + val[1] = 0xA3; + val[2] = 0x3B; + val[3] = 0x00; + status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, + TS1_CFG_REG, val, 4); +} +/* EXPORT_SYMBOL_GPL(cx231xx_start_TS1); */ +/***************************************************************** +* Device Init/UnInit functions * +******************************************************************/ +int cx231xx_dev_init(struct cx231xx *dev) +{ + int errCode = 0; + + /* Initialize I2C bus */ + + /* External Master 1 Bus */ + dev->i2c_bus[0].nr = 0; + dev->i2c_bus[0].dev = dev; + dev->i2c_bus[0].i2c_period = I2C_SPEED_100K; /* 100 KHz */ + dev->i2c_bus[0].i2c_nostop = 0; + dev->i2c_bus[0].i2c_reserve = 0; + + /* External Master 2 Bus */ + dev->i2c_bus[1].nr = 1; + dev->i2c_bus[1].dev = dev; + dev->i2c_bus[1].i2c_period = I2C_SPEED_100K; /* 100 KHz */ + dev->i2c_bus[1].i2c_nostop = 0; + dev->i2c_bus[1].i2c_reserve = 0; + + /* Internal Master 3 Bus */ + dev->i2c_bus[2].nr = 2; + dev->i2c_bus[2].dev = dev; + dev->i2c_bus[2].i2c_period = I2C_SPEED_100K; /* 100kHz */ + dev->i2c_bus[2].i2c_nostop = 0; + dev->i2c_bus[2].i2c_reserve = 0; + + /* register I2C buses */ + cx231xx_i2c_register(&dev->i2c_bus[0]); + cx231xx_i2c_register(&dev->i2c_bus[1]); + cx231xx_i2c_register(&dev->i2c_bus[2]); + + /* init hardware */ + /* Note : with out calling set power mode function, + afe can not be set up correctly */ + if (dev->board.external_av) { + errCode = cx231xx_set_power_mode(dev, + POLARIS_AVMODE_ENXTERNAL_AV); + if (errCode < 0) { + cx231xx_errdev + ("%s: Failed to set Power - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + } else { + errCode = cx231xx_set_power_mode(dev, + POLARIS_AVMODE_ANALOGT_TV); + if (errCode < 0) { + cx231xx_errdev + ("%s: Failed to set Power - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + } + + /* reset the Tuner, if it is a Xceive tuner */ + if ((dev->board.tuner_type == TUNER_XC5000) || + (dev->board.tuner_type == TUNER_XC2028)) + cx231xx_gpio_set(dev, dev->board.tuner_gpio); + + /* initialize Colibri block */ + errCode = cx231xx_afe_init_super_block(dev, 0x23c); + if (errCode < 0) { + cx231xx_errdev + ("%s: cx231xx_afe init super block - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + errCode = cx231xx_afe_init_channels(dev); + if (errCode < 0) { + cx231xx_errdev + ("%s: cx231xx_afe init channels - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + + /* Set DIF in By pass mode */ + errCode = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND); + if (errCode < 0) { + cx231xx_errdev + ("%s: cx231xx_dif set to By pass mode - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + + /* I2S block related functions */ + errCode = cx231xx_i2s_blk_initialize(dev); + if (errCode < 0) { + cx231xx_errdev + ("%s: cx231xx_i2s block initialize - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + + /* init control pins */ + errCode = cx231xx_init_ctrl_pin_status(dev); + if (errCode < 0) { + cx231xx_errdev("%s: cx231xx_init ctrl pins - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + + /* set AGC mode to Analog */ + switch (dev->model) { + case CX231XX_BOARD_CNXT_CARRAERA: + case CX231XX_BOARD_CNXT_RDE_250: + case CX231XX_BOARD_CNXT_SHELBY: + case CX231XX_BOARD_CNXT_RDU_250: + errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1); + break; + case CX231XX_BOARD_CNXT_RDE_253S: + case CX231XX_BOARD_CNXT_RDU_253S: + case CX231XX_BOARD_HAUPPAUGE_EXETER: + case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: + case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: + errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); + break; + default: + break; + } + if (errCode < 0) { + cx231xx_errdev + ("%s: cx231xx_AGC mode to Analog - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + + /* set all alternate settings to zero initially */ + cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0); + cx231xx_set_alt_setting(dev, INDEX_VANC, 0); + cx231xx_set_alt_setting(dev, INDEX_HANC, 0); + if (dev->board.has_dvb) + cx231xx_set_alt_setting(dev, INDEX_TS1, 0); + + /* set the I2C master port to 3 on channel 1 */ + errCode = cx231xx_enable_i2c_port_3(dev, true); + + return errCode; +} +EXPORT_SYMBOL_GPL(cx231xx_dev_init); + +void cx231xx_dev_uninit(struct cx231xx *dev) +{ + /* Un Initialize I2C bus */ + cx231xx_i2c_unregister(&dev->i2c_bus[2]); + cx231xx_i2c_unregister(&dev->i2c_bus[1]); + cx231xx_i2c_unregister(&dev->i2c_bus[0]); +} +EXPORT_SYMBOL_GPL(cx231xx_dev_uninit); + +/***************************************************************** +* G P I O related functions * +******************************************************************/ +int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val, + u8 len, u8 request, u8 direction) +{ + int status = 0; + struct VENDOR_REQUEST_IN ven_req; + + /* Set wValue */ + ven_req.wValue = (u16) (gpio_bit >> 16 & 0xffff); + + /* set request */ + if (!request) { + if (direction) + ven_req.bRequest = VRT_GET_GPIO; /* 0x8 gpio */ + else + ven_req.bRequest = VRT_SET_GPIO; /* 0x9 gpio */ + } else { + if (direction) + ven_req.bRequest = VRT_GET_GPIE; /* 0xa gpie */ + else + ven_req.bRequest = VRT_SET_GPIE; /* 0xb gpie */ + } + + /* set index value */ + ven_req.wIndex = (u16) (gpio_bit & 0xffff); + + /* set wLength value */ + ven_req.wLength = len; + + /* set bData value */ + ven_req.bData = 0; + + /* set the buffer for read / write */ + ven_req.pBuff = gpio_val; + + /* set the direction */ + if (direction) { + ven_req.direction = USB_DIR_IN; + memset(ven_req.pBuff, 0x00, ven_req.wLength); + } else + ven_req.direction = USB_DIR_OUT; + + + /* call common vendor command request */ + status = cx231xx_send_vendor_cmd(dev, &ven_req); + if (status < 0) { + cx231xx_info + ("UsbInterface::sendCommand, failed with status -%d\n", + status); + } + + return status; +} +EXPORT_SYMBOL_GPL(cx231xx_send_gpio_cmd); + +/***************************************************************** + * C O N T R O L - Register R E A D / W R I T E functions * + *****************************************************************/ +int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode) +{ + u8 value[4] = { 0x0, 0x0, 0x0, 0x0 }; + u32 tmp = 0; + int status = 0; + + status = + cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, address, value, 4); + if (status < 0) + return status; + + tmp = *((u32 *) value); + tmp |= mode; + + value[0] = (u8) tmp; + value[1] = (u8) (tmp >> 8); + value[2] = (u8) (tmp >> 16); + value[3] = (u8) (tmp >> 24); + + status = + cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, address, value, 4); + + return status; +} + +/***************************************************************** + * I 2 C Internal C O N T R O L functions * + *****************************************************************/ +int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr, + u8 saddr_len, u32 *data, u8 data_len, int master) +{ + int status = 0; + struct cx231xx_i2c_xfer_data req_data; + u8 value[64] = "0"; + + if (saddr_len == 0) + saddr = 0; + else if (saddr_len == 1) + saddr &= 0xff; + + /* prepare xfer_data struct */ + req_data.dev_addr = dev_addr >> 1; + req_data.direction = I2C_M_RD; + req_data.saddr_len = saddr_len; + req_data.saddr_dat = saddr; + req_data.buf_size = data_len; + req_data.p_buffer = (u8 *) value; + + /* usb send command */ + if (master == 0) + status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], + &req_data); + else if (master == 1) + status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1], + &req_data); + else if (master == 2) + status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2], + &req_data); + + if (status >= 0) { + /* Copy the data read back to main buffer */ + if (data_len == 1) + *data = value[0]; + else if (data_len == 4) + *data = + value[0] | value[1] << 8 | value[2] << 16 | value[3] + << 24; + else if (data_len > 4) + *data = value[saddr]; + } + + return status; +} + +int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr, + u8 saddr_len, u32 data, u8 data_len, int master) +{ + int status = 0; + u8 value[4] = { 0, 0, 0, 0 }; + struct cx231xx_i2c_xfer_data req_data; + + value[0] = (u8) data; + value[1] = (u8) (data >> 8); + value[2] = (u8) (data >> 16); + value[3] = (u8) (data >> 24); + + if (saddr_len == 0) + saddr = 0; + else if (saddr_len == 1) + saddr &= 0xff; + + /* prepare xfer_data struct */ + req_data.dev_addr = dev_addr >> 1; + req_data.direction = 0; + req_data.saddr_len = saddr_len; + req_data.saddr_dat = saddr; + req_data.buf_size = data_len; + req_data.p_buffer = value; + + /* usb send command */ + if (master == 0) + status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], + &req_data); + else if (master == 1) + status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1], + &req_data); + else if (master == 2) + status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2], + &req_data); + + return status; +} + +int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr, + u8 saddr_len, u32 *data, u8 data_len) +{ + int status = 0; + struct cx231xx_i2c_xfer_data req_data; + u8 value[4] = { 0, 0, 0, 0 }; + + if (saddr_len == 0) + saddr = 0; + else if (saddr_len == 1) + saddr &= 0xff; + + /* prepare xfer_data struct */ + req_data.dev_addr = dev_addr >> 1; + req_data.direction = I2C_M_RD; + req_data.saddr_len = saddr_len; + req_data.saddr_dat = saddr; + req_data.buf_size = data_len; + req_data.p_buffer = (u8 *) value; + + /* usb send command */ + status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], &req_data); + + if (status >= 0) { + /* Copy the data read back to main buffer */ + if (data_len == 1) + *data = value[0]; + else + *data = + value[0] | value[1] << 8 | value[2] << 16 | value[3] + << 24; + } + + return status; +} + +int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr, + u8 saddr_len, u32 data, u8 data_len) +{ + int status = 0; + u8 value[4] = { 0, 0, 0, 0 }; + struct cx231xx_i2c_xfer_data req_data; + + value[0] = (u8) data; + value[1] = (u8) (data >> 8); + value[2] = (u8) (data >> 16); + value[3] = (u8) (data >> 24); + + if (saddr_len == 0) + saddr = 0; + else if (saddr_len == 1) + saddr &= 0xff; + + /* prepare xfer_data struct */ + req_data.dev_addr = dev_addr >> 1; + req_data.direction = 0; + req_data.saddr_len = saddr_len; + req_data.saddr_dat = saddr; + req_data.buf_size = data_len; + req_data.p_buffer = value; + + /* usb send command */ + status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0], &req_data); + + return status; +} + +int cx231xx_reg_mask_write(struct cx231xx *dev, u8 dev_addr, u8 size, + u16 register_address, u8 bit_start, u8 bit_end, + u32 value) +{ + int status = 0; + u32 tmp; + u32 mask = 0; + int i; + + if (bit_start > (size - 1) || bit_end > (size - 1)) + return -1; + + if (size == 8) { + status = + cx231xx_read_i2c_data(dev, dev_addr, register_address, 2, + &tmp, 1); + } else { + status = + cx231xx_read_i2c_data(dev, dev_addr, register_address, 2, + &tmp, 4); + } + + if (status < 0) + return status; + + mask = 1 << bit_end; + for (i = bit_end; i > bit_start && i > 0; i--) + mask = mask + (1 << (i - 1)); + + value <<= bit_start; + + if (size == 8) { + tmp &= ~mask; + tmp |= value; + tmp &= 0xff; + status = + cx231xx_write_i2c_data(dev, dev_addr, register_address, 2, + tmp, 1); + } else { + tmp &= ~mask; + tmp |= value; + status = + cx231xx_write_i2c_data(dev, dev_addr, register_address, 2, + tmp, 4); + } + + return status; +} + +int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr, + u16 saddr, u32 mask, u32 value) +{ + u32 temp; + int status = 0; + + status = cx231xx_read_i2c_data(dev, dev_addr, saddr, 2, &temp, 4); + + if (status < 0) + return status; + + temp &= ~mask; + temp |= value; + + status = cx231xx_write_i2c_data(dev, dev_addr, saddr, 2, temp, 4); + + return status; +} + +u32 cx231xx_set_field(u32 field_mask, u32 data) +{ + u32 temp; + + for (temp = field_mask; (temp & 1) == 0; temp >>= 1) + data <<= 1; + + return data; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-dif.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-dif.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-dif.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-dif.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3178 @@ +/* + * cx231xx-dif.h - driver for Conexant Cx23100/101/102 USB video capture devices + * + * Copyright {C} 2009 + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CX231XX_DIF_H +#define _CX231XX_DIF_H + +#include "cx231xx-reg.h" + +struct dif_settings{ + u32 if_freq; + u32 register_address; + u32 value; +}; + +static struct dif_settings Dif_set_array[] = { + +/*case 3000000:*/ +/* BEGIN - DIF BPF register values from 30_quant.dat*/ +{3000000, DIF_BPF_COEFF01, 0x00000002}, +{3000000, DIF_BPF_COEFF23, 0x00080012}, +{3000000, DIF_BPF_COEFF45, 0x001e0024}, +{3000000, DIF_BPF_COEFF67, 0x001bfff8}, +{3000000, DIF_BPF_COEFF89, 0xffb4ff50}, +{3000000, DIF_BPF_COEFF1011, 0xfed8fe68}, +{3000000, DIF_BPF_COEFF1213, 0xfe24fe34}, +{3000000, DIF_BPF_COEFF1415, 0xfebaffc7}, +{3000000, DIF_BPF_COEFF1617, 0x014d031f}, +{3000000, DIF_BPF_COEFF1819, 0x04f0065d}, +{3000000, DIF_BPF_COEFF2021, 0x07010688}, +{3000000, DIF_BPF_COEFF2223, 0x04c901d6}, +{3000000, DIF_BPF_COEFF2425, 0xfe00f9d3}, +{3000000, DIF_BPF_COEFF2627, 0xf600f342}, +{3000000, DIF_BPF_COEFF2829, 0xf235f337}, +{3000000, DIF_BPF_COEFF3031, 0xf64efb22}, +{3000000, DIF_BPF_COEFF3233, 0x0105070f}, +{3000000, DIF_BPF_COEFF3435, 0x0c460fce}, +{3000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 30_quant.dat*/ + + +/*case 3100000:*/ +/* BEGIN - DIF BPF register values from 31_quant.dat*/ +{3100000, DIF_BPF_COEFF01, 0x00000001}, +{3100000, DIF_BPF_COEFF23, 0x00070012}, +{3100000, DIF_BPF_COEFF45, 0x00220032}, +{3100000, DIF_BPF_COEFF67, 0x00370026}, +{3100000, DIF_BPF_COEFF89, 0xfff0ff91}, +{3100000, DIF_BPF_COEFF1011, 0xff0efe7c}, +{3100000, DIF_BPF_COEFF1213, 0xfe01fdcc}, +{3100000, DIF_BPF_COEFF1415, 0xfe0afedb}, +{3100000, DIF_BPF_COEFF1617, 0x00440224}, +{3100000, DIF_BPF_COEFF1819, 0x0434060c}, +{3100000, DIF_BPF_COEFF2021, 0x0738074e}, +{3100000, DIF_BPF_COEFF2223, 0x06090361}, +{3100000, DIF_BPF_COEFF2425, 0xff99fb39}, +{3100000, DIF_BPF_COEFF2627, 0xf6fef3b6}, +{3100000, DIF_BPF_COEFF2829, 0xf21af2a5}, +{3100000, DIF_BPF_COEFF3031, 0xf573fa33}, +{3100000, DIF_BPF_COEFF3233, 0x0034067d}, +{3100000, DIF_BPF_COEFF3435, 0x0bfb0fb9}, +{3100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 31_quant.dat*/ + + +/*case 3200000:*/ +/* BEGIN - DIF BPF register values from 32_quant.dat*/ +{3200000, DIF_BPF_COEFF01, 0x00000000}, +{3200000, DIF_BPF_COEFF23, 0x0004000e}, +{3200000, DIF_BPF_COEFF45, 0x00200038}, +{3200000, DIF_BPF_COEFF67, 0x004c004f}, +{3200000, DIF_BPF_COEFF89, 0x002fffdf}, +{3200000, DIF_BPF_COEFF1011, 0xff5cfeb6}, +{3200000, DIF_BPF_COEFF1213, 0xfe0dfd92}, +{3200000, DIF_BPF_COEFF1415, 0xfd7ffe03}, +{3200000, DIF_BPF_COEFF1617, 0xff36010a}, +{3200000, DIF_BPF_COEFF1819, 0x03410575}, +{3200000, DIF_BPF_COEFF2021, 0x072607d2}, +{3200000, DIF_BPF_COEFF2223, 0x071804d5}, +{3200000, DIF_BPF_COEFF2425, 0x0134fcb7}, +{3200000, DIF_BPF_COEFF2627, 0xf81ff451}, +{3200000, DIF_BPF_COEFF2829, 0xf223f22e}, +{3200000, DIF_BPF_COEFF3031, 0xf4a7f94b}, +{3200000, DIF_BPF_COEFF3233, 0xff6405e8}, +{3200000, DIF_BPF_COEFF3435, 0x0bae0fa4}, +{3200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 32_quant.dat*/ + + +/*case 3300000:*/ +/* BEGIN - DIF BPF register values from 33_quant.dat*/ +{3300000, DIF_BPF_COEFF01, 0x0000ffff}, +{3300000, DIF_BPF_COEFF23, 0x00000008}, +{3300000, DIF_BPF_COEFF45, 0x001a0036}, +{3300000, DIF_BPF_COEFF67, 0x0056006d}, +{3300000, DIF_BPF_COEFF89, 0x00670030}, +{3300000, DIF_BPF_COEFF1011, 0xffbdff10}, +{3300000, DIF_BPF_COEFF1213, 0xfe46fd8d}, +{3300000, DIF_BPF_COEFF1415, 0xfd25fd4f}, +{3300000, DIF_BPF_COEFF1617, 0xfe35ffe0}, +{3300000, DIF_BPF_COEFF1819, 0x0224049f}, +{3300000, DIF_BPF_COEFF2021, 0x06c9080e}, +{3300000, DIF_BPF_COEFF2223, 0x07ef0627}, +{3300000, DIF_BPF_COEFF2425, 0x02c9fe45}, +{3300000, DIF_BPF_COEFF2627, 0xf961f513}, +{3300000, DIF_BPF_COEFF2829, 0xf250f1d2}, +{3300000, DIF_BPF_COEFF3031, 0xf3ecf869}, +{3300000, DIF_BPF_COEFF3233, 0xfe930552}, +{3300000, DIF_BPF_COEFF3435, 0x0b5f0f8f}, +{3300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 33_quant.dat*/ + + +/*case 3400000:*/ +/* BEGIN - DIF BPF register values from 34_quant.dat*/ +{3400000, DIF_BPF_COEFF01, 0xfffffffe}, +{3400000, DIF_BPF_COEFF23, 0xfffd0001}, +{3400000, DIF_BPF_COEFF45, 0x000f002c}, +{3400000, DIF_BPF_COEFF67, 0x0054007d}, +{3400000, DIF_BPF_COEFF89, 0x0093007c}, +{3400000, DIF_BPF_COEFF1011, 0x0024ff82}, +{3400000, DIF_BPF_COEFF1213, 0xfea6fdbb}, +{3400000, DIF_BPF_COEFF1415, 0xfd03fcca}, +{3400000, DIF_BPF_COEFF1617, 0xfd51feb9}, +{3400000, DIF_BPF_COEFF1819, 0x00eb0392}, +{3400000, DIF_BPF_COEFF2021, 0x06270802}, +{3400000, DIF_BPF_COEFF2223, 0x08880750}, +{3400000, DIF_BPF_COEFF2425, 0x044dffdb}, +{3400000, DIF_BPF_COEFF2627, 0xfabdf5f8}, +{3400000, DIF_BPF_COEFF2829, 0xf2a0f193}, +{3400000, DIF_BPF_COEFF3031, 0xf342f78f}, +{3400000, DIF_BPF_COEFF3233, 0xfdc404b9}, +{3400000, DIF_BPF_COEFF3435, 0x0b0e0f78}, +{3400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 34_quant.dat*/ + + +/*case 3500000:*/ +/* BEGIN - DIF BPF register values from 35_quant.dat*/ +{3500000, DIF_BPF_COEFF01, 0xfffffffd}, +{3500000, DIF_BPF_COEFF23, 0xfffafff9}, +{3500000, DIF_BPF_COEFF45, 0x0002001b}, +{3500000, DIF_BPF_COEFF67, 0x0046007d}, +{3500000, DIF_BPF_COEFF89, 0x00ad00ba}, +{3500000, DIF_BPF_COEFF1011, 0x00870000}, +{3500000, DIF_BPF_COEFF1213, 0xff26fe1a}, +{3500000, DIF_BPF_COEFF1415, 0xfd1bfc7e}, +{3500000, DIF_BPF_COEFF1617, 0xfc99fda4}, +{3500000, DIF_BPF_COEFF1819, 0xffa5025c}, +{3500000, DIF_BPF_COEFF2021, 0x054507ad}, +{3500000, DIF_BPF_COEFF2223, 0x08dd0847}, +{3500000, DIF_BPF_COEFF2425, 0x05b80172}, +{3500000, DIF_BPF_COEFF2627, 0xfc2ef6ff}, +{3500000, DIF_BPF_COEFF2829, 0xf313f170}, +{3500000, DIF_BPF_COEFF3031, 0xf2abf6bd}, +{3500000, DIF_BPF_COEFF3233, 0xfcf6041f}, +{3500000, DIF_BPF_COEFF3435, 0x0abc0f61}, +{3500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 35_quant.dat*/ + + +/*case 3600000:*/ +/* BEGIN - DIF BPF register values from 36_quant.dat*/ +{3600000, DIF_BPF_COEFF01, 0xfffffffd}, +{3600000, DIF_BPF_COEFF23, 0xfff8fff3}, +{3600000, DIF_BPF_COEFF45, 0xfff50006}, +{3600000, DIF_BPF_COEFF67, 0x002f006c}, +{3600000, DIF_BPF_COEFF89, 0x00b200e3}, +{3600000, DIF_BPF_COEFF1011, 0x00dc007e}, +{3600000, DIF_BPF_COEFF1213, 0xffb9fea0}, +{3600000, DIF_BPF_COEFF1415, 0xfd6bfc71}, +{3600000, DIF_BPF_COEFF1617, 0xfc17fcb1}, +{3600000, DIF_BPF_COEFF1819, 0xfe65010b}, +{3600000, DIF_BPF_COEFF2021, 0x042d0713}, +{3600000, DIF_BPF_COEFF2223, 0x08ec0906}, +{3600000, DIF_BPF_COEFF2425, 0x07020302}, +{3600000, DIF_BPF_COEFF2627, 0xfdaff823}, +{3600000, DIF_BPF_COEFF2829, 0xf3a7f16a}, +{3600000, DIF_BPF_COEFF3031, 0xf228f5f5}, +{3600000, DIF_BPF_COEFF3233, 0xfc2a0384}, +{3600000, DIF_BPF_COEFF3435, 0x0a670f4a}, +{3600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 36_quant.dat*/ + + +/*case 3700000:*/ +/* BEGIN - DIF BPF register values from 37_quant.dat*/ +{3700000, DIF_BPF_COEFF01, 0x0000fffd}, +{3700000, DIF_BPF_COEFF23, 0xfff7ffef}, +{3700000, DIF_BPF_COEFF45, 0xffe9fff1}, +{3700000, DIF_BPF_COEFF67, 0x0010004d}, +{3700000, DIF_BPF_COEFF89, 0x00a100f2}, +{3700000, DIF_BPF_COEFF1011, 0x011a00f0}, +{3700000, DIF_BPF_COEFF1213, 0x0053ff44}, +{3700000, DIF_BPF_COEFF1415, 0xfdedfca2}, +{3700000, DIF_BPF_COEFF1617, 0xfbd3fbef}, +{3700000, DIF_BPF_COEFF1819, 0xfd39ffae}, +{3700000, DIF_BPF_COEFF2021, 0x02ea0638}, +{3700000, DIF_BPF_COEFF2223, 0x08b50987}, +{3700000, DIF_BPF_COEFF2425, 0x08230483}, +{3700000, DIF_BPF_COEFF2627, 0xff39f960}, +{3700000, DIF_BPF_COEFF2829, 0xf45bf180}, +{3700000, DIF_BPF_COEFF3031, 0xf1b8f537}, +{3700000, DIF_BPF_COEFF3233, 0xfb6102e7}, +{3700000, DIF_BPF_COEFF3435, 0x0a110f32}, +{3700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 37_quant.dat*/ + + +/*case 3800000:*/ +/* BEGIN - DIF BPF register values from 38_quant.dat*/ +{3800000, DIF_BPF_COEFF01, 0x0000fffe}, +{3800000, DIF_BPF_COEFF23, 0xfff9ffee}, +{3800000, DIF_BPF_COEFF45, 0xffe1ffdd}, +{3800000, DIF_BPF_COEFF67, 0xfff00024}, +{3800000, DIF_BPF_COEFF89, 0x007c00e5}, +{3800000, DIF_BPF_COEFF1011, 0x013a014a}, +{3800000, DIF_BPF_COEFF1213, 0x00e6fff8}, +{3800000, DIF_BPF_COEFF1415, 0xfe98fd0f}, +{3800000, DIF_BPF_COEFF1617, 0xfbd3fb67}, +{3800000, DIF_BPF_COEFF1819, 0xfc32fe54}, +{3800000, DIF_BPF_COEFF2021, 0x01880525}, +{3800000, DIF_BPF_COEFF2223, 0x083909c7}, +{3800000, DIF_BPF_COEFF2425, 0x091505ee}, +{3800000, DIF_BPF_COEFF2627, 0x00c7fab3}, +{3800000, DIF_BPF_COEFF2829, 0xf52df1b4}, +{3800000, DIF_BPF_COEFF3031, 0xf15df484}, +{3800000, DIF_BPF_COEFF3233, 0xfa9b0249}, +{3800000, DIF_BPF_COEFF3435, 0x09ba0f19}, +{3800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 38_quant.dat*/ + + +/*case 3900000:*/ +/* BEGIN - DIF BPF register values from 39_quant.dat*/ +{3900000, DIF_BPF_COEFF01, 0x00000000}, +{3900000, DIF_BPF_COEFF23, 0xfffbfff0}, +{3900000, DIF_BPF_COEFF45, 0xffdeffcf}, +{3900000, DIF_BPF_COEFF67, 0xffd1fff6}, +{3900000, DIF_BPF_COEFF89, 0x004800be}, +{3900000, DIF_BPF_COEFF1011, 0x01390184}, +{3900000, DIF_BPF_COEFF1213, 0x016300ac}, +{3900000, DIF_BPF_COEFF1415, 0xff5efdb1}, +{3900000, DIF_BPF_COEFF1617, 0xfc17fb23}, +{3900000, DIF_BPF_COEFF1819, 0xfb5cfd0d}, +{3900000, DIF_BPF_COEFF2021, 0x001703e4}, +{3900000, DIF_BPF_COEFF2223, 0x077b09c4}, +{3900000, DIF_BPF_COEFF2425, 0x09d2073c}, +{3900000, DIF_BPF_COEFF2627, 0x0251fc18}, +{3900000, DIF_BPF_COEFF2829, 0xf61cf203}, +{3900000, DIF_BPF_COEFF3031, 0xf118f3dc}, +{3900000, DIF_BPF_COEFF3233, 0xf9d801aa}, +{3900000, DIF_BPF_COEFF3435, 0x09600eff}, +{3900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 39_quant.dat*/ + + +/*case 4000000:*/ +/* BEGIN - DIF BPF register values from 40_quant.dat*/ +{4000000, DIF_BPF_COEFF01, 0x00000001}, +{4000000, DIF_BPF_COEFF23, 0xfffefff4}, +{4000000, DIF_BPF_COEFF45, 0xffe1ffc8}, +{4000000, DIF_BPF_COEFF67, 0xffbaffca}, +{4000000, DIF_BPF_COEFF89, 0x000b0082}, +{4000000, DIF_BPF_COEFF1011, 0x01170198}, +{4000000, DIF_BPF_COEFF1213, 0x01c10152}, +{4000000, DIF_BPF_COEFF1415, 0x0030fe7b}, +{4000000, DIF_BPF_COEFF1617, 0xfc99fb24}, +{4000000, DIF_BPF_COEFF1819, 0xfac3fbe9}, +{4000000, DIF_BPF_COEFF2021, 0xfea5027f}, +{4000000, DIF_BPF_COEFF2223, 0x0683097f}, +{4000000, DIF_BPF_COEFF2425, 0x0a560867}, +{4000000, DIF_BPF_COEFF2627, 0x03d2fd89}, +{4000000, DIF_BPF_COEFF2829, 0xf723f26f}, +{4000000, DIF_BPF_COEFF3031, 0xf0e8f341}, +{4000000, DIF_BPF_COEFF3233, 0xf919010a}, +{4000000, DIF_BPF_COEFF3435, 0x09060ee5}, +{4000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 40_quant.dat*/ + + +/*case 4100000:*/ +/* BEGIN - DIF BPF register values from 41_quant.dat*/ +{4100000, DIF_BPF_COEFF01, 0x00010002}, +{4100000, DIF_BPF_COEFF23, 0x0002fffb}, +{4100000, DIF_BPF_COEFF45, 0xffe8ffca}, +{4100000, DIF_BPF_COEFF67, 0xffacffa4}, +{4100000, DIF_BPF_COEFF89, 0xffcd0036}, +{4100000, DIF_BPF_COEFF1011, 0x00d70184}, +{4100000, DIF_BPF_COEFF1213, 0x01f601dc}, +{4100000, DIF_BPF_COEFF1415, 0x00ffff60}, +{4100000, DIF_BPF_COEFF1617, 0xfd51fb6d}, +{4100000, DIF_BPF_COEFF1819, 0xfa6efaf5}, +{4100000, DIF_BPF_COEFF2021, 0xfd410103}, +{4100000, DIF_BPF_COEFF2223, 0x055708f9}, +{4100000, DIF_BPF_COEFF2425, 0x0a9e0969}, +{4100000, DIF_BPF_COEFF2627, 0x0543ff02}, +{4100000, DIF_BPF_COEFF2829, 0xf842f2f5}, +{4100000, DIF_BPF_COEFF3031, 0xf0cef2b2}, +{4100000, DIF_BPF_COEFF3233, 0xf85e006b}, +{4100000, DIF_BPF_COEFF3435, 0x08aa0ecb}, +{4100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 41_quant.dat*/ + + +/*case 4200000:*/ +/* BEGIN - DIF BPF register values from 42_quant.dat*/ +{4200000, DIF_BPF_COEFF01, 0x00010003}, +{4200000, DIF_BPF_COEFF23, 0x00050003}, +{4200000, DIF_BPF_COEFF45, 0xfff3ffd3}, +{4200000, DIF_BPF_COEFF67, 0xffaaff8b}, +{4200000, DIF_BPF_COEFF89, 0xff95ffe5}, +{4200000, DIF_BPF_COEFF1011, 0x0080014a}, +{4200000, DIF_BPF_COEFF1213, 0x01fe023f}, +{4200000, DIF_BPF_COEFF1415, 0x01ba0050}, +{4200000, DIF_BPF_COEFF1617, 0xfe35fbf8}, +{4200000, DIF_BPF_COEFF1819, 0xfa62fa3b}, +{4200000, DIF_BPF_COEFF2021, 0xfbf9ff7e}, +{4200000, DIF_BPF_COEFF2223, 0x04010836}, +{4200000, DIF_BPF_COEFF2425, 0x0aa90a3d}, +{4200000, DIF_BPF_COEFF2627, 0x069f007f}, +{4200000, DIF_BPF_COEFF2829, 0xf975f395}, +{4200000, DIF_BPF_COEFF3031, 0xf0cbf231}, +{4200000, DIF_BPF_COEFF3233, 0xf7a9ffcb}, +{4200000, DIF_BPF_COEFF3435, 0x084c0eaf}, +{4200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 42_quant.dat*/ + + +/*case 4300000:*/ +/* BEGIN - DIF BPF register values from 43_quant.dat*/ +{4300000, DIF_BPF_COEFF01, 0x00010003}, +{4300000, DIF_BPF_COEFF23, 0x0008000a}, +{4300000, DIF_BPF_COEFF45, 0x0000ffe4}, +{4300000, DIF_BPF_COEFF67, 0xffb4ff81}, +{4300000, DIF_BPF_COEFF89, 0xff6aff96}, +{4300000, DIF_BPF_COEFF1011, 0x001c00f0}, +{4300000, DIF_BPF_COEFF1213, 0x01d70271}, +{4300000, DIF_BPF_COEFF1415, 0x0254013b}, +{4300000, DIF_BPF_COEFF1617, 0xff36fcbd}, +{4300000, DIF_BPF_COEFF1819, 0xfa9ff9c5}, +{4300000, DIF_BPF_COEFF2021, 0xfadbfdfe}, +{4300000, DIF_BPF_COEFF2223, 0x028c073b}, +{4300000, DIF_BPF_COEFF2425, 0x0a750adf}, +{4300000, DIF_BPF_COEFF2627, 0x07e101fa}, +{4300000, DIF_BPF_COEFF2829, 0xfab8f44e}, +{4300000, DIF_BPF_COEFF3031, 0xf0ddf1be}, +{4300000, DIF_BPF_COEFF3233, 0xf6f9ff2b}, +{4300000, DIF_BPF_COEFF3435, 0x07ed0e94}, +{4300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 43_quant.dat*/ + + +/*case 4400000:*/ +/* BEGIN - DIF BPF register values from 44_quant.dat*/ +{4400000, DIF_BPF_COEFF01, 0x00000003}, +{4400000, DIF_BPF_COEFF23, 0x0009000f}, +{4400000, DIF_BPF_COEFF45, 0x000efff8}, +{4400000, DIF_BPF_COEFF67, 0xffc9ff87}, +{4400000, DIF_BPF_COEFF89, 0xff52ff54}, +{4400000, DIF_BPF_COEFF1011, 0xffb5007e}, +{4400000, DIF_BPF_COEFF1213, 0x01860270}, +{4400000, DIF_BPF_COEFF1415, 0x02c00210}, +{4400000, DIF_BPF_COEFF1617, 0x0044fdb2}, +{4400000, DIF_BPF_COEFF1819, 0xfb22f997}, +{4400000, DIF_BPF_COEFF2021, 0xf9f2fc90}, +{4400000, DIF_BPF_COEFF2223, 0x0102060f}, +{4400000, DIF_BPF_COEFF2425, 0x0a050b4c}, +{4400000, DIF_BPF_COEFF2627, 0x0902036e}, +{4400000, DIF_BPF_COEFF2829, 0xfc0af51e}, +{4400000, DIF_BPF_COEFF3031, 0xf106f15a}, +{4400000, DIF_BPF_COEFF3233, 0xf64efe8b}, +{4400000, DIF_BPF_COEFF3435, 0x078d0e77}, +{4400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 44_quant.dat*/ + + +/*case 4500000:*/ +/* BEGIN - DIF BPF register values from 45_quant.dat*/ +{4500000, DIF_BPF_COEFF01, 0x00000002}, +{4500000, DIF_BPF_COEFF23, 0x00080012}, +{4500000, DIF_BPF_COEFF45, 0x0019000e}, +{4500000, DIF_BPF_COEFF67, 0xffe5ff9e}, +{4500000, DIF_BPF_COEFF89, 0xff4fff25}, +{4500000, DIF_BPF_COEFF1011, 0xff560000}, +{4500000, DIF_BPF_COEFF1213, 0x0112023b}, +{4500000, DIF_BPF_COEFF1415, 0x02f702c0}, +{4500000, DIF_BPF_COEFF1617, 0x014dfec8}, +{4500000, DIF_BPF_COEFF1819, 0xfbe5f9b3}, +{4500000, DIF_BPF_COEFF2021, 0xf947fb41}, +{4500000, DIF_BPF_COEFF2223, 0xff7004b9}, +{4500000, DIF_BPF_COEFF2425, 0x095a0b81}, +{4500000, DIF_BPF_COEFF2627, 0x0a0004d8}, +{4500000, DIF_BPF_COEFF2829, 0xfd65f603}, +{4500000, DIF_BPF_COEFF3031, 0xf144f104}, +{4500000, DIF_BPF_COEFF3233, 0xf5aafdec}, +{4500000, DIF_BPF_COEFF3435, 0x072b0e5a}, +{4500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 45_quant.dat*/ + + +/*case 4600000:*/ +/* BEGIN - DIF BPF register values from 46_quant.dat*/ +{4600000, DIF_BPF_COEFF01, 0x00000001}, +{4600000, DIF_BPF_COEFF23, 0x00060012}, +{4600000, DIF_BPF_COEFF45, 0x00200022}, +{4600000, DIF_BPF_COEFF67, 0x0005ffc1}, +{4600000, DIF_BPF_COEFF89, 0xff61ff10}, +{4600000, DIF_BPF_COEFF1011, 0xff09ff82}, +{4600000, DIF_BPF_COEFF1213, 0x008601d7}, +{4600000, DIF_BPF_COEFF1415, 0x02f50340}, +{4600000, DIF_BPF_COEFF1617, 0x0241fff0}, +{4600000, DIF_BPF_COEFF1819, 0xfcddfa19}, +{4600000, DIF_BPF_COEFF2021, 0xf8e2fa1e}, +{4600000, DIF_BPF_COEFF2223, 0xfde30343}, +{4600000, DIF_BPF_COEFF2425, 0x08790b7f}, +{4600000, DIF_BPF_COEFF2627, 0x0ad50631}, +{4600000, DIF_BPF_COEFF2829, 0xfec7f6fc}, +{4600000, DIF_BPF_COEFF3031, 0xf198f0bd}, +{4600000, DIF_BPF_COEFF3233, 0xf50dfd4e}, +{4600000, DIF_BPF_COEFF3435, 0x06c90e3d}, +{4600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 46_quant.dat*/ + + +/*case 4700000:*/ +/* BEGIN - DIF BPF register values from 47_quant.dat*/ +{4700000, DIF_BPF_COEFF01, 0x0000ffff}, +{4700000, DIF_BPF_COEFF23, 0x0003000f}, +{4700000, DIF_BPF_COEFF45, 0x00220030}, +{4700000, DIF_BPF_COEFF67, 0x0025ffed}, +{4700000, DIF_BPF_COEFF89, 0xff87ff15}, +{4700000, DIF_BPF_COEFF1011, 0xfed6ff10}, +{4700000, DIF_BPF_COEFF1213, 0xffed014c}, +{4700000, DIF_BPF_COEFF1415, 0x02b90386}, +{4700000, DIF_BPF_COEFF1617, 0x03110119}, +{4700000, DIF_BPF_COEFF1819, 0xfdfefac4}, +{4700000, DIF_BPF_COEFF2021, 0xf8c6f92f}, +{4700000, DIF_BPF_COEFF2223, 0xfc6701b7}, +{4700000, DIF_BPF_COEFF2425, 0x07670b44}, +{4700000, DIF_BPF_COEFF2627, 0x0b7e0776}, +{4700000, DIF_BPF_COEFF2829, 0x002df807}, +{4700000, DIF_BPF_COEFF3031, 0xf200f086}, +{4700000, DIF_BPF_COEFF3233, 0xf477fcb1}, +{4700000, DIF_BPF_COEFF3435, 0x06650e1e}, +{4700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 47_quant.dat*/ + + +/*case 4800000:*/ +/* BEGIN - DIF BPF register values from 48_quant.dat*/ +{4800000, DIF_BPF_COEFF01, 0xfffffffe}, +{4800000, DIF_BPF_COEFF23, 0xffff0009}, +{4800000, DIF_BPF_COEFF45, 0x001e0038}, +{4800000, DIF_BPF_COEFF67, 0x003f001b}, +{4800000, DIF_BPF_COEFF89, 0xffbcff36}, +{4800000, DIF_BPF_COEFF1011, 0xfec2feb6}, +{4800000, DIF_BPF_COEFF1213, 0xff5600a5}, +{4800000, DIF_BPF_COEFF1415, 0x0248038d}, +{4800000, DIF_BPF_COEFF1617, 0x03b00232}, +{4800000, DIF_BPF_COEFF1819, 0xff39fbab}, +{4800000, DIF_BPF_COEFF2021, 0xf8f4f87f}, +{4800000, DIF_BPF_COEFF2223, 0xfb060020}, +{4800000, DIF_BPF_COEFF2425, 0x062a0ad2}, +{4800000, DIF_BPF_COEFF2627, 0x0bf908a3}, +{4800000, DIF_BPF_COEFF2829, 0x0192f922}, +{4800000, DIF_BPF_COEFF3031, 0xf27df05e}, +{4800000, DIF_BPF_COEFF3233, 0xf3e8fc14}, +{4800000, DIF_BPF_COEFF3435, 0x06000e00}, +{4800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 48_quant.dat*/ + + +/*case 4900000:*/ +/* BEGIN - DIF BPF register values from 49_quant.dat*/ +{4900000, DIF_BPF_COEFF01, 0xfffffffd}, +{4900000, DIF_BPF_COEFF23, 0xfffc0002}, +{4900000, DIF_BPF_COEFF45, 0x00160037}, +{4900000, DIF_BPF_COEFF67, 0x00510046}, +{4900000, DIF_BPF_COEFF89, 0xfff9ff6d}, +{4900000, DIF_BPF_COEFF1011, 0xfed0fe7c}, +{4900000, DIF_BPF_COEFF1213, 0xfecefff0}, +{4900000, DIF_BPF_COEFF1415, 0x01aa0356}, +{4900000, DIF_BPF_COEFF1617, 0x0413032b}, +{4900000, DIF_BPF_COEFF1819, 0x007ffcc5}, +{4900000, DIF_BPF_COEFF2021, 0xf96cf812}, +{4900000, DIF_BPF_COEFF2223, 0xf9cefe87}, +{4900000, DIF_BPF_COEFF2425, 0x04c90a2c}, +{4900000, DIF_BPF_COEFF2627, 0x0c4309b4}, +{4900000, DIF_BPF_COEFF2829, 0x02f3fa4a}, +{4900000, DIF_BPF_COEFF3031, 0xf30ef046}, +{4900000, DIF_BPF_COEFF3233, 0xf361fb7a}, +{4900000, DIF_BPF_COEFF3435, 0x059b0de0}, +{4900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 49_quant.dat*/ + + +/*case 5000000:*/ +/* BEGIN - DIF BPF register values from 50_quant.dat*/ +{5000000, DIF_BPF_COEFF01, 0xfffffffd}, +{5000000, DIF_BPF_COEFF23, 0xfff9fffa}, +{5000000, DIF_BPF_COEFF45, 0x000a002d}, +{5000000, DIF_BPF_COEFF67, 0x00570067}, +{5000000, DIF_BPF_COEFF89, 0x0037ffb5}, +{5000000, DIF_BPF_COEFF1011, 0xfefffe68}, +{5000000, DIF_BPF_COEFF1213, 0xfe62ff3d}, +{5000000, DIF_BPF_COEFF1415, 0x00ec02e3}, +{5000000, DIF_BPF_COEFF1617, 0x043503f6}, +{5000000, DIF_BPF_COEFF1819, 0x01befe05}, +{5000000, DIF_BPF_COEFF2021, 0xfa27f7ee}, +{5000000, DIF_BPF_COEFF2223, 0xf8c6fcf8}, +{5000000, DIF_BPF_COEFF2425, 0x034c0954}, +{5000000, DIF_BPF_COEFF2627, 0x0c5c0aa4}, +{5000000, DIF_BPF_COEFF2829, 0x044cfb7e}, +{5000000, DIF_BPF_COEFF3031, 0xf3b1f03f}, +{5000000, DIF_BPF_COEFF3233, 0xf2e2fae1}, +{5000000, DIF_BPF_COEFF3435, 0x05340dc0}, +{5000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 50_quant.dat*/ + + +/*case 5100000:*/ +/* BEGIN - DIF BPF register values from 51_quant.dat*/ +{5100000, DIF_BPF_COEFF01, 0x0000fffd}, +{5100000, DIF_BPF_COEFF23, 0xfff8fff4}, +{5100000, DIF_BPF_COEFF45, 0xfffd001e}, +{5100000, DIF_BPF_COEFF67, 0x0051007b}, +{5100000, DIF_BPF_COEFF89, 0x006e0006}, +{5100000, DIF_BPF_COEFF1011, 0xff48fe7c}, +{5100000, DIF_BPF_COEFF1213, 0xfe1bfe9a}, +{5100000, DIF_BPF_COEFF1415, 0x001d023e}, +{5100000, DIF_BPF_COEFF1617, 0x04130488}, +{5100000, DIF_BPF_COEFF1819, 0x02e6ff5b}, +{5100000, DIF_BPF_COEFF2021, 0xfb1ef812}, +{5100000, DIF_BPF_COEFF2223, 0xf7f7fb7f}, +{5100000, DIF_BPF_COEFF2425, 0x01bc084e}, +{5100000, DIF_BPF_COEFF2627, 0x0c430b72}, +{5100000, DIF_BPF_COEFF2829, 0x059afcba}, +{5100000, DIF_BPF_COEFF3031, 0xf467f046}, +{5100000, DIF_BPF_COEFF3233, 0xf26cfa4a}, +{5100000, DIF_BPF_COEFF3435, 0x04cd0da0}, +{5100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 51_quant.dat*/ + + +/*case 5200000:*/ +/* BEGIN - DIF BPF register values from 52_quant.dat*/ +{5200000, DIF_BPF_COEFF01, 0x0000fffe}, +{5200000, DIF_BPF_COEFF23, 0xfff8ffef}, +{5200000, DIF_BPF_COEFF45, 0xfff00009}, +{5200000, DIF_BPF_COEFF67, 0x003f007f}, +{5200000, DIF_BPF_COEFF89, 0x00980056}, +{5200000, DIF_BPF_COEFF1011, 0xffa5feb6}, +{5200000, DIF_BPF_COEFF1213, 0xfe00fe15}, +{5200000, DIF_BPF_COEFF1415, 0xff4b0170}, +{5200000, DIF_BPF_COEFF1617, 0x03b004d7}, +{5200000, DIF_BPF_COEFF1819, 0x03e800b9}, +{5200000, DIF_BPF_COEFF2021, 0xfc48f87f}, +{5200000, DIF_BPF_COEFF2223, 0xf768fa23}, +{5200000, DIF_BPF_COEFF2425, 0x0022071f}, +{5200000, DIF_BPF_COEFF2627, 0x0bf90c1b}, +{5200000, DIF_BPF_COEFF2829, 0x06dafdfd}, +{5200000, DIF_BPF_COEFF3031, 0xf52df05e}, +{5200000, DIF_BPF_COEFF3233, 0xf1fef9b5}, +{5200000, DIF_BPF_COEFF3435, 0x04640d7f}, +{5200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 52_quant.dat*/ + + +/*case 5300000:*/ +/* BEGIN - DIF BPF register values from 53_quant.dat*/ +{5300000, DIF_BPF_COEFF01, 0x0000ffff}, +{5300000, DIF_BPF_COEFF23, 0xfff9ffee}, +{5300000, DIF_BPF_COEFF45, 0xffe6fff3}, +{5300000, DIF_BPF_COEFF67, 0x00250072}, +{5300000, DIF_BPF_COEFF89, 0x00af009c}, +{5300000, DIF_BPF_COEFF1011, 0x000cff10}, +{5300000, DIF_BPF_COEFF1213, 0xfe13fdb8}, +{5300000, DIF_BPF_COEFF1415, 0xfe870089}, +{5300000, DIF_BPF_COEFF1617, 0x031104e1}, +{5300000, DIF_BPF_COEFF1819, 0x04b8020f}, +{5300000, DIF_BPF_COEFF2021, 0xfd98f92f}, +{5300000, DIF_BPF_COEFF2223, 0xf71df8f0}, +{5300000, DIF_BPF_COEFF2425, 0xfe8805ce}, +{5300000, DIF_BPF_COEFF2627, 0x0b7e0c9c}, +{5300000, DIF_BPF_COEFF2829, 0x0808ff44}, +{5300000, DIF_BPF_COEFF3031, 0xf603f086}, +{5300000, DIF_BPF_COEFF3233, 0xf19af922}, +{5300000, DIF_BPF_COEFF3435, 0x03fb0d5e}, +{5300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 53_quant.dat*/ + + +/*case 5400000:*/ +/* BEGIN - DIF BPF register values from 54_quant.dat*/ +{5400000, DIF_BPF_COEFF01, 0x00000001}, +{5400000, DIF_BPF_COEFF23, 0xfffcffef}, +{5400000, DIF_BPF_COEFF45, 0xffe0ffe0}, +{5400000, DIF_BPF_COEFF67, 0x00050056}, +{5400000, DIF_BPF_COEFF89, 0x00b000d1}, +{5400000, DIF_BPF_COEFF1011, 0x0071ff82}, +{5400000, DIF_BPF_COEFF1213, 0xfe53fd8c}, +{5400000, DIF_BPF_COEFF1415, 0xfddfff99}, +{5400000, DIF_BPF_COEFF1617, 0x024104a3}, +{5400000, DIF_BPF_COEFF1819, 0x054a034d}, +{5400000, DIF_BPF_COEFF2021, 0xff01fa1e}, +{5400000, DIF_BPF_COEFF2223, 0xf717f7ed}, +{5400000, DIF_BPF_COEFF2425, 0xfcf50461}, +{5400000, DIF_BPF_COEFF2627, 0x0ad50cf4}, +{5400000, DIF_BPF_COEFF2829, 0x0921008d}, +{5400000, DIF_BPF_COEFF3031, 0xf6e7f0bd}, +{5400000, DIF_BPF_COEFF3233, 0xf13ff891}, +{5400000, DIF_BPF_COEFF3435, 0x03920d3b}, +{5400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 54_quant.dat*/ + + +/*case 5500000:*/ +/* BEGIN - DIF BPF register values from 55_quant.dat*/ +{5500000, DIF_BPF_COEFF01, 0x00010002}, +{5500000, DIF_BPF_COEFF23, 0xfffffff3}, +{5500000, DIF_BPF_COEFF45, 0xffdeffd1}, +{5500000, DIF_BPF_COEFF67, 0xffe5002f}, +{5500000, DIF_BPF_COEFF89, 0x009c00ed}, +{5500000, DIF_BPF_COEFF1011, 0x00cb0000}, +{5500000, DIF_BPF_COEFF1213, 0xfebafd94}, +{5500000, DIF_BPF_COEFF1415, 0xfd61feb0}, +{5500000, DIF_BPF_COEFF1617, 0x014d0422}, +{5500000, DIF_BPF_COEFF1819, 0x05970464}, +{5500000, DIF_BPF_COEFF2021, 0x0074fb41}, +{5500000, DIF_BPF_COEFF2223, 0xf759f721}, +{5500000, DIF_BPF_COEFF2425, 0xfb7502de}, +{5500000, DIF_BPF_COEFF2627, 0x0a000d21}, +{5500000, DIF_BPF_COEFF2829, 0x0a2201d4}, +{5500000, DIF_BPF_COEFF3031, 0xf7d9f104}, +{5500000, DIF_BPF_COEFF3233, 0xf0edf804}, +{5500000, DIF_BPF_COEFF3435, 0x03280d19}, +{5500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 55_quant.dat*/ + + +/*case 5600000:*/ +/* BEGIN - DIF BPF register values from 56_quant.dat*/ +{5600000, DIF_BPF_COEFF01, 0x00010003}, +{5600000, DIF_BPF_COEFF23, 0x0003fffa}, +{5600000, DIF_BPF_COEFF45, 0xffe3ffc9}, +{5600000, DIF_BPF_COEFF67, 0xffc90002}, +{5600000, DIF_BPF_COEFF89, 0x007500ef}, +{5600000, DIF_BPF_COEFF1011, 0x010e007e}, +{5600000, DIF_BPF_COEFF1213, 0xff3dfdcf}, +{5600000, DIF_BPF_COEFF1415, 0xfd16fddd}, +{5600000, DIF_BPF_COEFF1617, 0x00440365}, +{5600000, DIF_BPF_COEFF1819, 0x059b0548}, +{5600000, DIF_BPF_COEFF2021, 0x01e3fc90}, +{5600000, DIF_BPF_COEFF2223, 0xf7dff691}, +{5600000, DIF_BPF_COEFF2425, 0xfa0f014d}, +{5600000, DIF_BPF_COEFF2627, 0x09020d23}, +{5600000, DIF_BPF_COEFF2829, 0x0b0a0318}, +{5600000, DIF_BPF_COEFF3031, 0xf8d7f15a}, +{5600000, DIF_BPF_COEFF3233, 0xf0a5f779}, +{5600000, DIF_BPF_COEFF3435, 0x02bd0cf6}, +{5600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 56_quant.dat*/ + + +/*case 5700000:*/ +/* BEGIN - DIF BPF register values from 57_quant.dat*/ +{5700000, DIF_BPF_COEFF01, 0x00010003}, +{5700000, DIF_BPF_COEFF23, 0x00060001}, +{5700000, DIF_BPF_COEFF45, 0xffecffc9}, +{5700000, DIF_BPF_COEFF67, 0xffb4ffd4}, +{5700000, DIF_BPF_COEFF89, 0x004000d5}, +{5700000, DIF_BPF_COEFF1011, 0x013600f0}, +{5700000, DIF_BPF_COEFF1213, 0xffd3fe39}, +{5700000, DIF_BPF_COEFF1415, 0xfd04fd31}, +{5700000, DIF_BPF_COEFF1617, 0xff360277}, +{5700000, DIF_BPF_COEFF1819, 0x055605ef}, +{5700000, DIF_BPF_COEFF2021, 0x033efdfe}, +{5700000, DIF_BPF_COEFF2223, 0xf8a5f642}, +{5700000, DIF_BPF_COEFF2425, 0xf8cbffb6}, +{5700000, DIF_BPF_COEFF2627, 0x07e10cfb}, +{5700000, DIF_BPF_COEFF2829, 0x0bd50456}, +{5700000, DIF_BPF_COEFF3031, 0xf9dff1be}, +{5700000, DIF_BPF_COEFF3233, 0xf067f6f2}, +{5700000, DIF_BPF_COEFF3435, 0x02520cd2}, +{5700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 57_quant.dat*/ + + +/*case 5800000:*/ +/* BEGIN - DIF BPF register values from 58_quant.dat*/ +{5800000, DIF_BPF_COEFF01, 0x00000003}, +{5800000, DIF_BPF_COEFF23, 0x00080009}, +{5800000, DIF_BPF_COEFF45, 0xfff8ffd2}, +{5800000, DIF_BPF_COEFF67, 0xffaaffac}, +{5800000, DIF_BPF_COEFF89, 0x000200a3}, +{5800000, DIF_BPF_COEFF1011, 0x013c014a}, +{5800000, DIF_BPF_COEFF1213, 0x006dfec9}, +{5800000, DIF_BPF_COEFF1415, 0xfd2bfcb7}, +{5800000, DIF_BPF_COEFF1617, 0xfe350165}, +{5800000, DIF_BPF_COEFF1819, 0x04cb0651}, +{5800000, DIF_BPF_COEFF2021, 0x0477ff7e}, +{5800000, DIF_BPF_COEFF2223, 0xf9a5f635}, +{5800000, DIF_BPF_COEFF2425, 0xf7b1fe20}, +{5800000, DIF_BPF_COEFF2627, 0x069f0ca8}, +{5800000, DIF_BPF_COEFF2829, 0x0c81058b}, +{5800000, DIF_BPF_COEFF3031, 0xfaf0f231}, +{5800000, DIF_BPF_COEFF3233, 0xf033f66d}, +{5800000, DIF_BPF_COEFF3435, 0x01e60cae}, +{5800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 58_quant.dat*/ + + +/*case 5900000:*/ +/* BEGIN - DIF BPF register values from 59_quant.dat*/ +{5900000, DIF_BPF_COEFF01, 0x00000002}, +{5900000, DIF_BPF_COEFF23, 0x0009000e}, +{5900000, DIF_BPF_COEFF45, 0x0005ffe1}, +{5900000, DIF_BPF_COEFF67, 0xffacff90}, +{5900000, DIF_BPF_COEFF89, 0xffc5005f}, +{5900000, DIF_BPF_COEFF1011, 0x01210184}, +{5900000, DIF_BPF_COEFF1213, 0x00fcff72}, +{5900000, DIF_BPF_COEFF1415, 0xfd8afc77}, +{5900000, DIF_BPF_COEFF1617, 0xfd51003f}, +{5900000, DIF_BPF_COEFF1819, 0x04020669}, +{5900000, DIF_BPF_COEFF2021, 0x05830103}, +{5900000, DIF_BPF_COEFF2223, 0xfad7f66b}, +{5900000, DIF_BPF_COEFF2425, 0xf6c8fc93}, +{5900000, DIF_BPF_COEFF2627, 0x05430c2b}, +{5900000, DIF_BPF_COEFF2829, 0x0d0d06b5}, +{5900000, DIF_BPF_COEFF3031, 0xfc08f2b2}, +{5900000, DIF_BPF_COEFF3233, 0xf00af5ec}, +{5900000, DIF_BPF_COEFF3435, 0x017b0c89}, +{5900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 59_quant.dat*/ + + +/*case 6000000:*/ +/* BEGIN - DIF BPF register values from 60_quant.dat*/ +{6000000, DIF_BPF_COEFF01, 0x00000001}, +{6000000, DIF_BPF_COEFF23, 0x00070012}, +{6000000, DIF_BPF_COEFF45, 0x0012fff5}, +{6000000, DIF_BPF_COEFF67, 0xffbaff82}, +{6000000, DIF_BPF_COEFF89, 0xff8e000f}, +{6000000, DIF_BPF_COEFF1011, 0x00e80198}, +{6000000, DIF_BPF_COEFF1213, 0x01750028}, +{6000000, DIF_BPF_COEFF1415, 0xfe18fc75}, +{6000000, DIF_BPF_COEFF1617, 0xfc99ff15}, +{6000000, DIF_BPF_COEFF1819, 0x03050636}, +{6000000, DIF_BPF_COEFF2021, 0x0656027f}, +{6000000, DIF_BPF_COEFF2223, 0xfc32f6e2}, +{6000000, DIF_BPF_COEFF2425, 0xf614fb17}, +{6000000, DIF_BPF_COEFF2627, 0x03d20b87}, +{6000000, DIF_BPF_COEFF2829, 0x0d7707d2}, +{6000000, DIF_BPF_COEFF3031, 0xfd26f341}, +{6000000, DIF_BPF_COEFF3233, 0xefeaf56f}, +{6000000, DIF_BPF_COEFF3435, 0x010f0c64}, +{6000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 60_quant.dat*/ + + +/*case 6100000:*/ +/* BEGIN - DIF BPF register values from 61_quant.dat*/ +{6100000, DIF_BPF_COEFF01, 0xffff0000}, +{6100000, DIF_BPF_COEFF23, 0x00050012}, +{6100000, DIF_BPF_COEFF45, 0x001c000b}, +{6100000, DIF_BPF_COEFF67, 0xffd1ff84}, +{6100000, DIF_BPF_COEFF89, 0xff66ffbe}, +{6100000, DIF_BPF_COEFF1011, 0x00960184}, +{6100000, DIF_BPF_COEFF1213, 0x01cd00da}, +{6100000, DIF_BPF_COEFF1415, 0xfeccfcb2}, +{6100000, DIF_BPF_COEFF1617, 0xfc17fdf9}, +{6100000, DIF_BPF_COEFF1819, 0x01e005bc}, +{6100000, DIF_BPF_COEFF2021, 0x06e703e4}, +{6100000, DIF_BPF_COEFF2223, 0xfdabf798}, +{6100000, DIF_BPF_COEFF2425, 0xf599f9b3}, +{6100000, DIF_BPF_COEFF2627, 0x02510abd}, +{6100000, DIF_BPF_COEFF2829, 0x0dbf08df}, +{6100000, DIF_BPF_COEFF3031, 0xfe48f3dc}, +{6100000, DIF_BPF_COEFF3233, 0xefd5f4f6}, +{6100000, DIF_BPF_COEFF3435, 0x00a20c3e}, +{6100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 61_quant.dat*/ + + +/*case 6200000:*/ +/* BEGIN - DIF BPF register values from 62_quant.dat*/ +{6200000, DIF_BPF_COEFF01, 0xfffffffe}, +{6200000, DIF_BPF_COEFF23, 0x0002000f}, +{6200000, DIF_BPF_COEFF45, 0x0021001f}, +{6200000, DIF_BPF_COEFF67, 0xfff0ff97}, +{6200000, DIF_BPF_COEFF89, 0xff50ff74}, +{6200000, DIF_BPF_COEFF1011, 0x0034014a}, +{6200000, DIF_BPF_COEFF1213, 0x01fa0179}, +{6200000, DIF_BPF_COEFF1415, 0xff97fd2a}, +{6200000, DIF_BPF_COEFF1617, 0xfbd3fcfa}, +{6200000, DIF_BPF_COEFF1819, 0x00a304fe}, +{6200000, DIF_BPF_COEFF2021, 0x07310525}, +{6200000, DIF_BPF_COEFF2223, 0xff37f886}, +{6200000, DIF_BPF_COEFF2425, 0xf55cf86e}, +{6200000, DIF_BPF_COEFF2627, 0x00c709d0}, +{6200000, DIF_BPF_COEFF2829, 0x0de209db}, +{6200000, DIF_BPF_COEFF3031, 0xff6df484}, +{6200000, DIF_BPF_COEFF3233, 0xefcbf481}, +{6200000, DIF_BPF_COEFF3435, 0x00360c18}, +{6200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 62_quant.dat*/ + + +/*case 6300000:*/ +/* BEGIN - DIF BPF register values from 63_quant.dat*/ +{6300000, DIF_BPF_COEFF01, 0xfffffffd}, +{6300000, DIF_BPF_COEFF23, 0xfffe000a}, +{6300000, DIF_BPF_COEFF45, 0x0021002f}, +{6300000, DIF_BPF_COEFF67, 0x0010ffb8}, +{6300000, DIF_BPF_COEFF89, 0xff50ff3b}, +{6300000, DIF_BPF_COEFF1011, 0xffcc00f0}, +{6300000, DIF_BPF_COEFF1213, 0x01fa01fa}, +{6300000, DIF_BPF_COEFF1415, 0x0069fdd4}, +{6300000, DIF_BPF_COEFF1617, 0xfbd3fc26}, +{6300000, DIF_BPF_COEFF1819, 0xff5d0407}, +{6300000, DIF_BPF_COEFF2021, 0x07310638}, +{6300000, DIF_BPF_COEFF2223, 0x00c9f9a8}, +{6300000, DIF_BPF_COEFF2425, 0xf55cf74e}, +{6300000, DIF_BPF_COEFF2627, 0xff3908c3}, +{6300000, DIF_BPF_COEFF2829, 0x0de20ac3}, +{6300000, DIF_BPF_COEFF3031, 0x0093f537}, +{6300000, DIF_BPF_COEFF3233, 0xefcbf410}, +{6300000, DIF_BPF_COEFF3435, 0xffca0bf2}, +{6300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 63_quant.dat*/ + + +/*case 6400000:*/ +/* BEGIN - DIF BPF register values from 64_quant.dat*/ +{6400000, DIF_BPF_COEFF01, 0xfffffffd}, +{6400000, DIF_BPF_COEFF23, 0xfffb0003}, +{6400000, DIF_BPF_COEFF45, 0x001c0037}, +{6400000, DIF_BPF_COEFF67, 0x002fffe2}, +{6400000, DIF_BPF_COEFF89, 0xff66ff17}, +{6400000, DIF_BPF_COEFF1011, 0xff6a007e}, +{6400000, DIF_BPF_COEFF1213, 0x01cd0251}, +{6400000, DIF_BPF_COEFF1415, 0x0134fea5}, +{6400000, DIF_BPF_COEFF1617, 0xfc17fb8b}, +{6400000, DIF_BPF_COEFF1819, 0xfe2002e0}, +{6400000, DIF_BPF_COEFF2021, 0x06e70713}, +{6400000, DIF_BPF_COEFF2223, 0x0255faf5}, +{6400000, DIF_BPF_COEFF2425, 0xf599f658}, +{6400000, DIF_BPF_COEFF2627, 0xfdaf0799}, +{6400000, DIF_BPF_COEFF2829, 0x0dbf0b96}, +{6400000, DIF_BPF_COEFF3031, 0x01b8f5f5}, +{6400000, DIF_BPF_COEFF3233, 0xefd5f3a3}, +{6400000, DIF_BPF_COEFF3435, 0xff5e0bca}, +{6400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 64_quant.dat*/ + + +/*case 6500000:*/ +/* BEGIN - DIF BPF register values from 65_quant.dat*/ +{6500000, DIF_BPF_COEFF01, 0x0000fffd}, +{6500000, DIF_BPF_COEFF23, 0xfff9fffb}, +{6500000, DIF_BPF_COEFF45, 0x00120037}, +{6500000, DIF_BPF_COEFF67, 0x00460010}, +{6500000, DIF_BPF_COEFF89, 0xff8eff0f}, +{6500000, DIF_BPF_COEFF1011, 0xff180000}, +{6500000, DIF_BPF_COEFF1213, 0x01750276}, +{6500000, DIF_BPF_COEFF1415, 0x01e8ff8d}, +{6500000, DIF_BPF_COEFF1617, 0xfc99fb31}, +{6500000, DIF_BPF_COEFF1819, 0xfcfb0198}, +{6500000, DIF_BPF_COEFF2021, 0x065607ad}, +{6500000, DIF_BPF_COEFF2223, 0x03cefc64}, +{6500000, DIF_BPF_COEFF2425, 0xf614f592}, +{6500000, DIF_BPF_COEFF2627, 0xfc2e0656}, +{6500000, DIF_BPF_COEFF2829, 0x0d770c52}, +{6500000, DIF_BPF_COEFF3031, 0x02daf6bd}, +{6500000, DIF_BPF_COEFF3233, 0xefeaf33b}, +{6500000, DIF_BPF_COEFF3435, 0xfef10ba3}, +{6500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 65_quant.dat*/ + + +/*case 6600000:*/ +/* BEGIN - DIF BPF register values from 66_quant.dat*/ +{6600000, DIF_BPF_COEFF01, 0x0000fffe}, +{6600000, DIF_BPF_COEFF23, 0xfff7fff5}, +{6600000, DIF_BPF_COEFF45, 0x0005002f}, +{6600000, DIF_BPF_COEFF67, 0x0054003c}, +{6600000, DIF_BPF_COEFF89, 0xffc5ff22}, +{6600000, DIF_BPF_COEFF1011, 0xfedfff82}, +{6600000, DIF_BPF_COEFF1213, 0x00fc0267}, +{6600000, DIF_BPF_COEFF1415, 0x0276007e}, +{6600000, DIF_BPF_COEFF1617, 0xfd51fb1c}, +{6600000, DIF_BPF_COEFF1819, 0xfbfe003e}, +{6600000, DIF_BPF_COEFF2021, 0x05830802}, +{6600000, DIF_BPF_COEFF2223, 0x0529fdec}, +{6600000, DIF_BPF_COEFF2425, 0xf6c8f4fe}, +{6600000, DIF_BPF_COEFF2627, 0xfabd04ff}, +{6600000, DIF_BPF_COEFF2829, 0x0d0d0cf6}, +{6600000, DIF_BPF_COEFF3031, 0x03f8f78f}, +{6600000, DIF_BPF_COEFF3233, 0xf00af2d7}, +{6600000, DIF_BPF_COEFF3435, 0xfe850b7b}, +{6600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 66_quant.dat*/ + + +/*case 6700000:*/ +/* BEGIN - DIF BPF register values from 67_quant.dat*/ +{6700000, DIF_BPF_COEFF01, 0x0000ffff}, +{6700000, DIF_BPF_COEFF23, 0xfff8fff0}, +{6700000, DIF_BPF_COEFF45, 0xfff80020}, +{6700000, DIF_BPF_COEFF67, 0x00560060}, +{6700000, DIF_BPF_COEFF89, 0x0002ff4e}, +{6700000, DIF_BPF_COEFF1011, 0xfec4ff10}, +{6700000, DIF_BPF_COEFF1213, 0x006d0225}, +{6700000, DIF_BPF_COEFF1415, 0x02d50166}, +{6700000, DIF_BPF_COEFF1617, 0xfe35fb4e}, +{6700000, DIF_BPF_COEFF1819, 0xfb35fee1}, +{6700000, DIF_BPF_COEFF2021, 0x0477080e}, +{6700000, DIF_BPF_COEFF2223, 0x065bff82}, +{6700000, DIF_BPF_COEFF2425, 0xf7b1f4a0}, +{6700000, DIF_BPF_COEFF2627, 0xf9610397}, +{6700000, DIF_BPF_COEFF2829, 0x0c810d80}, +{6700000, DIF_BPF_COEFF3031, 0x0510f869}, +{6700000, DIF_BPF_COEFF3233, 0xf033f278}, +{6700000, DIF_BPF_COEFF3435, 0xfe1a0b52}, +{6700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 67_quant.dat*/ + + +/*case 6800000:*/ +/* BEGIN - DIF BPF register values from 68_quant.dat*/ +{6800000, DIF_BPF_COEFF01, 0x00010000}, +{6800000, DIF_BPF_COEFF23, 0xfffaffee}, +{6800000, DIF_BPF_COEFF45, 0xffec000c}, +{6800000, DIF_BPF_COEFF67, 0x004c0078}, +{6800000, DIF_BPF_COEFF89, 0x0040ff8e}, +{6800000, DIF_BPF_COEFF1011, 0xfecafeb6}, +{6800000, DIF_BPF_COEFF1213, 0xffd301b6}, +{6800000, DIF_BPF_COEFF1415, 0x02fc0235}, +{6800000, DIF_BPF_COEFF1617, 0xff36fbc5}, +{6800000, DIF_BPF_COEFF1819, 0xfaaafd90}, +{6800000, DIF_BPF_COEFF2021, 0x033e07d2}, +{6800000, DIF_BPF_COEFF2223, 0x075b011b}, +{6800000, DIF_BPF_COEFF2425, 0xf8cbf47a}, +{6800000, DIF_BPF_COEFF2627, 0xf81f0224}, +{6800000, DIF_BPF_COEFF2829, 0x0bd50def}, +{6800000, DIF_BPF_COEFF3031, 0x0621f94b}, +{6800000, DIF_BPF_COEFF3233, 0xf067f21e}, +{6800000, DIF_BPF_COEFF3435, 0xfdae0b29}, +{6800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 68_quant.dat*/ + + +/*case 6900000:*/ +/* BEGIN - DIF BPF register values from 69_quant.dat*/ +{6900000, DIF_BPF_COEFF01, 0x00010001}, +{6900000, DIF_BPF_COEFF23, 0xfffdffef}, +{6900000, DIF_BPF_COEFF45, 0xffe3fff6}, +{6900000, DIF_BPF_COEFF67, 0x0037007f}, +{6900000, DIF_BPF_COEFF89, 0x0075ffdc}, +{6900000, DIF_BPF_COEFF1011, 0xfef2fe7c}, +{6900000, DIF_BPF_COEFF1213, 0xff3d0122}, +{6900000, DIF_BPF_COEFF1415, 0x02ea02dd}, +{6900000, DIF_BPF_COEFF1617, 0x0044fc79}, +{6900000, DIF_BPF_COEFF1819, 0xfa65fc5d}, +{6900000, DIF_BPF_COEFF2021, 0x01e3074e}, +{6900000, DIF_BPF_COEFF2223, 0x082102ad}, +{6900000, DIF_BPF_COEFF2425, 0xfa0ff48c}, +{6900000, DIF_BPF_COEFF2627, 0xf6fe00a9}, +{6900000, DIF_BPF_COEFF2829, 0x0b0a0e43}, +{6900000, DIF_BPF_COEFF3031, 0x0729fa33}, +{6900000, DIF_BPF_COEFF3233, 0xf0a5f1c9}, +{6900000, DIF_BPF_COEFF3435, 0xfd430b00}, +{6900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 69_quant.dat*/ + + +/*case 7000000:*/ +/* BEGIN - DIF BPF register values from 70_quant.dat*/ +{7000000, DIF_BPF_COEFF01, 0x00010002}, +{7000000, DIF_BPF_COEFF23, 0x0001fff3}, +{7000000, DIF_BPF_COEFF45, 0xffdeffe2}, +{7000000, DIF_BPF_COEFF67, 0x001b0076}, +{7000000, DIF_BPF_COEFF89, 0x009c002d}, +{7000000, DIF_BPF_COEFF1011, 0xff35fe68}, +{7000000, DIF_BPF_COEFF1213, 0xfeba0076}, +{7000000, DIF_BPF_COEFF1415, 0x029f0352}, +{7000000, DIF_BPF_COEFF1617, 0x014dfd60}, +{7000000, DIF_BPF_COEFF1819, 0xfa69fb53}, +{7000000, DIF_BPF_COEFF2021, 0x00740688}, +{7000000, DIF_BPF_COEFF2223, 0x08a7042d}, +{7000000, DIF_BPF_COEFF2425, 0xfb75f4d6}, +{7000000, DIF_BPF_COEFF2627, 0xf600ff2d}, +{7000000, DIF_BPF_COEFF2829, 0x0a220e7a}, +{7000000, DIF_BPF_COEFF3031, 0x0827fb22}, +{7000000, DIF_BPF_COEFF3233, 0xf0edf17a}, +{7000000, DIF_BPF_COEFF3435, 0xfcd80ad6}, +{7000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 70_quant.dat*/ + + +/*case 7100000:*/ +/* BEGIN - DIF BPF register values from 71_quant.dat*/ +{7100000, DIF_BPF_COEFF01, 0x00000003}, +{7100000, DIF_BPF_COEFF23, 0x0004fff9}, +{7100000, DIF_BPF_COEFF45, 0xffe0ffd2}, +{7100000, DIF_BPF_COEFF67, 0xfffb005e}, +{7100000, DIF_BPF_COEFF89, 0x00b0007a}, +{7100000, DIF_BPF_COEFF1011, 0xff8ffe7c}, +{7100000, DIF_BPF_COEFF1213, 0xfe53ffc1}, +{7100000, DIF_BPF_COEFF1415, 0x0221038c}, +{7100000, DIF_BPF_COEFF1617, 0x0241fe6e}, +{7100000, DIF_BPF_COEFF1819, 0xfab6fa80}, +{7100000, DIF_BPF_COEFF2021, 0xff010587}, +{7100000, DIF_BPF_COEFF2223, 0x08e90590}, +{7100000, DIF_BPF_COEFF2425, 0xfcf5f556}, +{7100000, DIF_BPF_COEFF2627, 0xf52bfdb3}, +{7100000, DIF_BPF_COEFF2829, 0x09210e95}, +{7100000, DIF_BPF_COEFF3031, 0x0919fc15}, +{7100000, DIF_BPF_COEFF3233, 0xf13ff12f}, +{7100000, DIF_BPF_COEFF3435, 0xfc6e0aab}, +{7100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 71_quant.dat*/ + + +/*case 7200000:*/ +/* BEGIN - DIF BPF register values from 72_quant.dat*/ +{7200000, DIF_BPF_COEFF01, 0x00000003}, +{7200000, DIF_BPF_COEFF23, 0x00070000}, +{7200000, DIF_BPF_COEFF45, 0xffe6ffc9}, +{7200000, DIF_BPF_COEFF67, 0xffdb0039}, +{7200000, DIF_BPF_COEFF89, 0x00af00b8}, +{7200000, DIF_BPF_COEFF1011, 0xfff4feb6}, +{7200000, DIF_BPF_COEFF1213, 0xfe13ff10}, +{7200000, DIF_BPF_COEFF1415, 0x01790388}, +{7200000, DIF_BPF_COEFF1617, 0x0311ff92}, +{7200000, DIF_BPF_COEFF1819, 0xfb48f9ed}, +{7200000, DIF_BPF_COEFF2021, 0xfd980453}, +{7200000, DIF_BPF_COEFF2223, 0x08e306cd}, +{7200000, DIF_BPF_COEFF2425, 0xfe88f60a}, +{7200000, DIF_BPF_COEFF2627, 0xf482fc40}, +{7200000, DIF_BPF_COEFF2829, 0x08080e93}, +{7200000, DIF_BPF_COEFF3031, 0x09fdfd0c}, +{7200000, DIF_BPF_COEFF3233, 0xf19af0ea}, +{7200000, DIF_BPF_COEFF3435, 0xfc050a81}, +{7200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 72_quant.dat*/ + + +/*case 7300000:*/ +/* BEGIN - DIF BPF register values from 73_quant.dat*/ +{7300000, DIF_BPF_COEFF01, 0x00000002}, +{7300000, DIF_BPF_COEFF23, 0x00080008}, +{7300000, DIF_BPF_COEFF45, 0xfff0ffc9}, +{7300000, DIF_BPF_COEFF67, 0xffc1000d}, +{7300000, DIF_BPF_COEFF89, 0x009800e2}, +{7300000, DIF_BPF_COEFF1011, 0x005bff10}, +{7300000, DIF_BPF_COEFF1213, 0xfe00fe74}, +{7300000, DIF_BPF_COEFF1415, 0x00b50345}, +{7300000, DIF_BPF_COEFF1617, 0x03b000bc}, +{7300000, DIF_BPF_COEFF1819, 0xfc18f9a1}, +{7300000, DIF_BPF_COEFF2021, 0xfc4802f9}, +{7300000, DIF_BPF_COEFF2223, 0x089807dc}, +{7300000, DIF_BPF_COEFF2425, 0x0022f6f0}, +{7300000, DIF_BPF_COEFF2627, 0xf407fada}, +{7300000, DIF_BPF_COEFF2829, 0x06da0e74}, +{7300000, DIF_BPF_COEFF3031, 0x0ad3fe06}, +{7300000, DIF_BPF_COEFF3233, 0xf1fef0ab}, +{7300000, DIF_BPF_COEFF3435, 0xfb9c0a55}, +{7300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 73_quant.dat*/ + + +/*case 7400000:*/ +/* BEGIN - DIF BPF register values from 74_quant.dat*/ +{7400000, DIF_BPF_COEFF01, 0x00000001}, +{7400000, DIF_BPF_COEFF23, 0x0008000e}, +{7400000, DIF_BPF_COEFF45, 0xfffdffd0}, +{7400000, DIF_BPF_COEFF67, 0xffafffdf}, +{7400000, DIF_BPF_COEFF89, 0x006e00f2}, +{7400000, DIF_BPF_COEFF1011, 0x00b8ff82}, +{7400000, DIF_BPF_COEFF1213, 0xfe1bfdf8}, +{7400000, DIF_BPF_COEFF1415, 0xffe302c8}, +{7400000, DIF_BPF_COEFF1617, 0x041301dc}, +{7400000, DIF_BPF_COEFF1819, 0xfd1af99e}, +{7400000, DIF_BPF_COEFF2021, 0xfb1e0183}, +{7400000, DIF_BPF_COEFF2223, 0x080908b5}, +{7400000, DIF_BPF_COEFF2425, 0x01bcf801}, +{7400000, DIF_BPF_COEFF2627, 0xf3bdf985}, +{7400000, DIF_BPF_COEFF2829, 0x059a0e38}, +{7400000, DIF_BPF_COEFF3031, 0x0b99ff03}, +{7400000, DIF_BPF_COEFF3233, 0xf26cf071}, +{7400000, DIF_BPF_COEFF3435, 0xfb330a2a}, +{7400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 74_quant.dat*/ + + +/*case 7500000:*/ +/* BEGIN - DIF BPF register values from 75_quant.dat*/ +{7500000, DIF_BPF_COEFF01, 0xffff0000}, +{7500000, DIF_BPF_COEFF23, 0x00070011}, +{7500000, DIF_BPF_COEFF45, 0x000affdf}, +{7500000, DIF_BPF_COEFF67, 0xffa9ffb5}, +{7500000, DIF_BPF_COEFF89, 0x003700e6}, +{7500000, DIF_BPF_COEFF1011, 0x01010000}, +{7500000, DIF_BPF_COEFF1213, 0xfe62fda8}, +{7500000, DIF_BPF_COEFF1415, 0xff140219}, +{7500000, DIF_BPF_COEFF1617, 0x043502e1}, +{7500000, DIF_BPF_COEFF1819, 0xfe42f9e6}, +{7500000, DIF_BPF_COEFF2021, 0xfa270000}, +{7500000, DIF_BPF_COEFF2223, 0x073a0953}, +{7500000, DIF_BPF_COEFF2425, 0x034cf939}, +{7500000, DIF_BPF_COEFF2627, 0xf3a4f845}, +{7500000, DIF_BPF_COEFF2829, 0x044c0de1}, +{7500000, DIF_BPF_COEFF3031, 0x0c4f0000}, +{7500000, DIF_BPF_COEFF3233, 0xf2e2f03c}, +{7500000, DIF_BPF_COEFF3435, 0xfacc09fe}, +{7500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 75_quant.dat*/ + + +/*case 7600000:*/ +/* BEGIN - DIF BPF register values from 76_quant.dat*/ +{7600000, DIF_BPF_COEFF01, 0xffffffff}, +{7600000, DIF_BPF_COEFF23, 0x00040012}, +{7600000, DIF_BPF_COEFF45, 0x0016fff3}, +{7600000, DIF_BPF_COEFF67, 0xffafff95}, +{7600000, DIF_BPF_COEFF89, 0xfff900c0}, +{7600000, DIF_BPF_COEFF1011, 0x0130007e}, +{7600000, DIF_BPF_COEFF1213, 0xfecefd89}, +{7600000, DIF_BPF_COEFF1415, 0xfe560146}, +{7600000, DIF_BPF_COEFF1617, 0x041303bc}, +{7600000, DIF_BPF_COEFF1819, 0xff81fa76}, +{7600000, DIF_BPF_COEFF2021, 0xf96cfe7d}, +{7600000, DIF_BPF_COEFF2223, 0x063209b1}, +{7600000, DIF_BPF_COEFF2425, 0x04c9fa93}, +{7600000, DIF_BPF_COEFF2627, 0xf3bdf71e}, +{7600000, DIF_BPF_COEFF2829, 0x02f30d6e}, +{7600000, DIF_BPF_COEFF3031, 0x0cf200fd}, +{7600000, DIF_BPF_COEFF3233, 0xf361f00e}, +{7600000, DIF_BPF_COEFF3435, 0xfa6509d1}, +{7600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 76_quant.dat*/ + + +/*case 7700000:*/ +/* BEGIN - DIF BPF register values from 77_quant.dat*/ +{7700000, DIF_BPF_COEFF01, 0xfffffffe}, +{7700000, DIF_BPF_COEFF23, 0x00010010}, +{7700000, DIF_BPF_COEFF45, 0x001e0008}, +{7700000, DIF_BPF_COEFF67, 0xffc1ff84}, +{7700000, DIF_BPF_COEFF89, 0xffbc0084}, +{7700000, DIF_BPF_COEFF1011, 0x013e00f0}, +{7700000, DIF_BPF_COEFF1213, 0xff56fd9f}, +{7700000, DIF_BPF_COEFF1415, 0xfdb8005c}, +{7700000, DIF_BPF_COEFF1617, 0x03b00460}, +{7700000, DIF_BPF_COEFF1819, 0x00c7fb45}, +{7700000, DIF_BPF_COEFF2021, 0xf8f4fd07}, +{7700000, DIF_BPF_COEFF2223, 0x04fa09ce}, +{7700000, DIF_BPF_COEFF2425, 0x062afc07}, +{7700000, DIF_BPF_COEFF2627, 0xf407f614}, +{7700000, DIF_BPF_COEFF2829, 0x01920ce0}, +{7700000, DIF_BPF_COEFF3031, 0x0d8301fa}, +{7700000, DIF_BPF_COEFF3233, 0xf3e8efe5}, +{7700000, DIF_BPF_COEFF3435, 0xfa0009a4}, +{7700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 77_quant.dat*/ + + +/*case 7800000:*/ +/* BEGIN - DIF BPF register values from 78_quant.dat*/ +{7800000, DIF_BPF_COEFF01, 0x0000fffd}, +{7800000, DIF_BPF_COEFF23, 0xfffd000b}, +{7800000, DIF_BPF_COEFF45, 0x0022001d}, +{7800000, DIF_BPF_COEFF67, 0xffdbff82}, +{7800000, DIF_BPF_COEFF89, 0xff870039}, +{7800000, DIF_BPF_COEFF1011, 0x012a014a}, +{7800000, DIF_BPF_COEFF1213, 0xffedfde7}, +{7800000, DIF_BPF_COEFF1415, 0xfd47ff6b}, +{7800000, DIF_BPF_COEFF1617, 0x031104c6}, +{7800000, DIF_BPF_COEFF1819, 0x0202fc4c}, +{7800000, DIF_BPF_COEFF2021, 0xf8c6fbad}, +{7800000, DIF_BPF_COEFF2223, 0x039909a7}, +{7800000, DIF_BPF_COEFF2425, 0x0767fd8e}, +{7800000, DIF_BPF_COEFF2627, 0xf482f52b}, +{7800000, DIF_BPF_COEFF2829, 0x002d0c39}, +{7800000, DIF_BPF_COEFF3031, 0x0e0002f4}, +{7800000, DIF_BPF_COEFF3233, 0xf477efc2}, +{7800000, DIF_BPF_COEFF3435, 0xf99b0977}, +{7800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 78_quant.dat*/ + + +/*case 7900000:*/ +/* BEGIN - DIF BPF register values from 79_quant.dat*/ +{7900000, DIF_BPF_COEFF01, 0x0000fffd}, +{7900000, DIF_BPF_COEFF23, 0xfffa0004}, +{7900000, DIF_BPF_COEFF45, 0x0020002d}, +{7900000, DIF_BPF_COEFF67, 0xfffbff91}, +{7900000, DIF_BPF_COEFF89, 0xff61ffe8}, +{7900000, DIF_BPF_COEFF1011, 0x00f70184}, +{7900000, DIF_BPF_COEFF1213, 0x0086fe5c}, +{7900000, DIF_BPF_COEFF1415, 0xfd0bfe85}, +{7900000, DIF_BPF_COEFF1617, 0x024104e5}, +{7900000, DIF_BPF_COEFF1819, 0x0323fd7d}, +{7900000, DIF_BPF_COEFF2021, 0xf8e2fa79}, +{7900000, DIF_BPF_COEFF2223, 0x021d093f}, +{7900000, DIF_BPF_COEFF2425, 0x0879ff22}, +{7900000, DIF_BPF_COEFF2627, 0xf52bf465}, +{7900000, DIF_BPF_COEFF2829, 0xfec70b79}, +{7900000, DIF_BPF_COEFF3031, 0x0e6803eb}, +{7900000, DIF_BPF_COEFF3233, 0xf50defa5}, +{7900000, DIF_BPF_COEFF3435, 0xf937094a}, +{7900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 79_quant.dat*/ + + +/*case 8000000:*/ +/* BEGIN - DIF BPF register values from 80_quant.dat*/ +{8000000, DIF_BPF_COEFF01, 0x0000fffe}, +{8000000, DIF_BPF_COEFF23, 0xfff8fffd}, +{8000000, DIF_BPF_COEFF45, 0x00190036}, +{8000000, DIF_BPF_COEFF67, 0x001bffaf}, +{8000000, DIF_BPF_COEFF89, 0xff4fff99}, +{8000000, DIF_BPF_COEFF1011, 0x00aa0198}, +{8000000, DIF_BPF_COEFF1213, 0x0112fef3}, +{8000000, DIF_BPF_COEFF1415, 0xfd09fdb9}, +{8000000, DIF_BPF_COEFF1617, 0x014d04be}, +{8000000, DIF_BPF_COEFF1819, 0x041bfecc}, +{8000000, DIF_BPF_COEFF2021, 0xf947f978}, +{8000000, DIF_BPF_COEFF2223, 0x00900897}, +{8000000, DIF_BPF_COEFF2425, 0x095a00b9}, +{8000000, DIF_BPF_COEFF2627, 0xf600f3c5}, +{8000000, DIF_BPF_COEFF2829, 0xfd650aa3}, +{8000000, DIF_BPF_COEFF3031, 0x0ebc04de}, +{8000000, DIF_BPF_COEFF3233, 0xf5aaef8e}, +{8000000, DIF_BPF_COEFF3435, 0xf8d5091c}, +{8000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 80_quant.dat*/ + + +/*case 8100000:*/ +/* BEGIN - DIF BPF register values from 81_quant.dat*/ +{8100000, DIF_BPF_COEFF01, 0x0000ffff}, +{8100000, DIF_BPF_COEFF23, 0xfff7fff6}, +{8100000, DIF_BPF_COEFF45, 0x000e0038}, +{8100000, DIF_BPF_COEFF67, 0x0037ffd7}, +{8100000, DIF_BPF_COEFF89, 0xff52ff56}, +{8100000, DIF_BPF_COEFF1011, 0x004b0184}, +{8100000, DIF_BPF_COEFF1213, 0x0186ffa1}, +{8100000, DIF_BPF_COEFF1415, 0xfd40fd16}, +{8100000, DIF_BPF_COEFF1617, 0x00440452}, +{8100000, DIF_BPF_COEFF1819, 0x04de0029}, +{8100000, DIF_BPF_COEFF2021, 0xf9f2f8b2}, +{8100000, DIF_BPF_COEFF2223, 0xfefe07b5}, +{8100000, DIF_BPF_COEFF2425, 0x0a05024d}, +{8100000, DIF_BPF_COEFF2627, 0xf6fef34d}, +{8100000, DIF_BPF_COEFF2829, 0xfc0a09b8}, +{8100000, DIF_BPF_COEFF3031, 0x0efa05cd}, +{8100000, DIF_BPF_COEFF3233, 0xf64eef7d}, +{8100000, DIF_BPF_COEFF3435, 0xf87308ed}, +{8100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 81_quant.dat*/ + + +/*case 8200000:*/ +/* BEGIN - DIF BPF register values from 82_quant.dat*/ +{8200000, DIF_BPF_COEFF01, 0x00010000}, +{8200000, DIF_BPF_COEFF23, 0xfff8fff0}, +{8200000, DIF_BPF_COEFF45, 0x00000031}, +{8200000, DIF_BPF_COEFF67, 0x004c0005}, +{8200000, DIF_BPF_COEFF89, 0xff6aff27}, +{8200000, DIF_BPF_COEFF1011, 0xffe4014a}, +{8200000, DIF_BPF_COEFF1213, 0x01d70057}, +{8200000, DIF_BPF_COEFF1415, 0xfdacfca6}, +{8200000, DIF_BPF_COEFF1617, 0xff3603a7}, +{8200000, DIF_BPF_COEFF1819, 0x05610184}, +{8200000, DIF_BPF_COEFF2021, 0xfadbf82e}, +{8200000, DIF_BPF_COEFF2223, 0xfd74069f}, +{8200000, DIF_BPF_COEFF2425, 0x0a7503d6}, +{8200000, DIF_BPF_COEFF2627, 0xf81ff2ff}, +{8200000, DIF_BPF_COEFF2829, 0xfab808b9}, +{8200000, DIF_BPF_COEFF3031, 0x0f2306b5}, +{8200000, DIF_BPF_COEFF3233, 0xf6f9ef72}, +{8200000, DIF_BPF_COEFF3435, 0xf81308bf}, +{8200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 82_quant.dat*/ + + +/*case 8300000:*/ +/* BEGIN - DIF BPF register values from 83_quant.dat*/ +{8300000, DIF_BPF_COEFF01, 0x00010001}, +{8300000, DIF_BPF_COEFF23, 0xfffbffee}, +{8300000, DIF_BPF_COEFF45, 0xfff30022}, +{8300000, DIF_BPF_COEFF67, 0x00560032}, +{8300000, DIF_BPF_COEFF89, 0xff95ff10}, +{8300000, DIF_BPF_COEFF1011, 0xff8000f0}, +{8300000, DIF_BPF_COEFF1213, 0x01fe0106}, +{8300000, DIF_BPF_COEFF1415, 0xfe46fc71}, +{8300000, DIF_BPF_COEFF1617, 0xfe3502c7}, +{8300000, DIF_BPF_COEFF1819, 0x059e02ce}, +{8300000, DIF_BPF_COEFF2021, 0xfbf9f7f2}, +{8300000, DIF_BPF_COEFF2223, 0xfbff055b}, +{8300000, DIF_BPF_COEFF2425, 0x0aa9054c}, +{8300000, DIF_BPF_COEFF2627, 0xf961f2db}, +{8300000, DIF_BPF_COEFF2829, 0xf97507aa}, +{8300000, DIF_BPF_COEFF3031, 0x0f350797}, +{8300000, DIF_BPF_COEFF3233, 0xf7a9ef6d}, +{8300000, DIF_BPF_COEFF3435, 0xf7b40890}, +{8300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 83_quant.dat*/ + + +/*case 8400000:*/ +/* BEGIN - DIF BPF register values from 84_quant.dat*/ +{8400000, DIF_BPF_COEFF01, 0x00010002}, +{8400000, DIF_BPF_COEFF23, 0xfffeffee}, +{8400000, DIF_BPF_COEFF45, 0xffe8000f}, +{8400000, DIF_BPF_COEFF67, 0x00540058}, +{8400000, DIF_BPF_COEFF89, 0xffcdff14}, +{8400000, DIF_BPF_COEFF1011, 0xff29007e}, +{8400000, DIF_BPF_COEFF1213, 0x01f6019e}, +{8400000, DIF_BPF_COEFF1415, 0xff01fc7c}, +{8400000, DIF_BPF_COEFF1617, 0xfd5101bf}, +{8400000, DIF_BPF_COEFF1819, 0x059203f6}, +{8400000, DIF_BPF_COEFF2021, 0xfd41f7fe}, +{8400000, DIF_BPF_COEFF2223, 0xfaa903f3}, +{8400000, DIF_BPF_COEFF2425, 0x0a9e06a9}, +{8400000, DIF_BPF_COEFF2627, 0xfabdf2e2}, +{8400000, DIF_BPF_COEFF2829, 0xf842068b}, +{8400000, DIF_BPF_COEFF3031, 0x0f320871}, +{8400000, DIF_BPF_COEFF3233, 0xf85eef6e}, +{8400000, DIF_BPF_COEFF3435, 0xf7560860}, +{8400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 84_quant.dat*/ + + +/*case 8500000:*/ +/* BEGIN - DIF BPF register values from 85_quant.dat*/ +{8500000, DIF_BPF_COEFF01, 0x00000003}, +{8500000, DIF_BPF_COEFF23, 0x0002fff2}, +{8500000, DIF_BPF_COEFF45, 0xffe1fff9}, +{8500000, DIF_BPF_COEFF67, 0x00460073}, +{8500000, DIF_BPF_COEFF89, 0x000bff34}, +{8500000, DIF_BPF_COEFF1011, 0xfee90000}, +{8500000, DIF_BPF_COEFF1213, 0x01c10215}, +{8500000, DIF_BPF_COEFF1415, 0xffd0fcc5}, +{8500000, DIF_BPF_COEFF1617, 0xfc99009d}, +{8500000, DIF_BPF_COEFF1819, 0x053d04f1}, +{8500000, DIF_BPF_COEFF2021, 0xfea5f853}, +{8500000, DIF_BPF_COEFF2223, 0xf97d0270}, +{8500000, DIF_BPF_COEFF2425, 0x0a5607e4}, +{8500000, DIF_BPF_COEFF2627, 0xfc2ef314}, +{8500000, DIF_BPF_COEFF2829, 0xf723055f}, +{8500000, DIF_BPF_COEFF3031, 0x0f180943}, +{8500000, DIF_BPF_COEFF3233, 0xf919ef75}, +{8500000, DIF_BPF_COEFF3435, 0xf6fa0830}, +{8500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 85_quant.dat*/ + + +/*case 8600000:*/ +/* BEGIN - DIF BPF register values from 86_quant.dat*/ +{8600000, DIF_BPF_COEFF01, 0x00000003}, +{8600000, DIF_BPF_COEFF23, 0x0005fff8}, +{8600000, DIF_BPF_COEFF45, 0xffdeffe4}, +{8600000, DIF_BPF_COEFF67, 0x002f007f}, +{8600000, DIF_BPF_COEFF89, 0x0048ff6b}, +{8600000, DIF_BPF_COEFF1011, 0xfec7ff82}, +{8600000, DIF_BPF_COEFF1213, 0x0163025f}, +{8600000, DIF_BPF_COEFF1415, 0x00a2fd47}, +{8600000, DIF_BPF_COEFF1617, 0xfc17ff73}, +{8600000, DIF_BPF_COEFF1819, 0x04a405b2}, +{8600000, DIF_BPF_COEFF2021, 0x0017f8ed}, +{8600000, DIF_BPF_COEFF2223, 0xf88500dc}, +{8600000, DIF_BPF_COEFF2425, 0x09d208f9}, +{8600000, DIF_BPF_COEFF2627, 0xfdaff370}, +{8600000, DIF_BPF_COEFF2829, 0xf61c0429}, +{8600000, DIF_BPF_COEFF3031, 0x0ee80a0b}, +{8600000, DIF_BPF_COEFF3233, 0xf9d8ef82}, +{8600000, DIF_BPF_COEFF3435, 0xf6a00800}, +{8600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 86_quant.dat*/ + + +/*case 8700000:*/ +/* BEGIN - DIF BPF register values from 87_quant.dat*/ +{8700000, DIF_BPF_COEFF01, 0x00000003}, +{8700000, DIF_BPF_COEFF23, 0x0007ffff}, +{8700000, DIF_BPF_COEFF45, 0xffe1ffd4}, +{8700000, DIF_BPF_COEFF67, 0x0010007a}, +{8700000, DIF_BPF_COEFF89, 0x007cffb2}, +{8700000, DIF_BPF_COEFF1011, 0xfec6ff10}, +{8700000, DIF_BPF_COEFF1213, 0x00e60277}, +{8700000, DIF_BPF_COEFF1415, 0x0168fdf9}, +{8700000, DIF_BPF_COEFF1617, 0xfbd3fe50}, +{8700000, DIF_BPF_COEFF1819, 0x03ce0631}, +{8700000, DIF_BPF_COEFF2021, 0x0188f9c8}, +{8700000, DIF_BPF_COEFF2223, 0xf7c7ff43}, +{8700000, DIF_BPF_COEFF2425, 0x091509e3}, +{8700000, DIF_BPF_COEFF2627, 0xff39f3f6}, +{8700000, DIF_BPF_COEFF2829, 0xf52d02ea}, +{8700000, DIF_BPF_COEFF3031, 0x0ea30ac9}, +{8700000, DIF_BPF_COEFF3233, 0xfa9bef95}, +{8700000, DIF_BPF_COEFF3435, 0xf64607d0}, +{8700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 87_quant.dat*/ + + +/*case 8800000:*/ +/* BEGIN - DIF BPF register values from 88_quant.dat*/ +{8800000, DIF_BPF_COEFF01, 0x00000002}, +{8800000, DIF_BPF_COEFF23, 0x00090007}, +{8800000, DIF_BPF_COEFF45, 0xffe9ffca}, +{8800000, DIF_BPF_COEFF67, 0xfff00065}, +{8800000, DIF_BPF_COEFF89, 0x00a10003}, +{8800000, DIF_BPF_COEFF1011, 0xfee6feb6}, +{8800000, DIF_BPF_COEFF1213, 0x0053025b}, +{8800000, DIF_BPF_COEFF1415, 0x0213fed0}, +{8800000, DIF_BPF_COEFF1617, 0xfbd3fd46}, +{8800000, DIF_BPF_COEFF1819, 0x02c70668}, +{8800000, DIF_BPF_COEFF2021, 0x02eafadb}, +{8800000, DIF_BPF_COEFF2223, 0xf74bfdae}, +{8800000, DIF_BPF_COEFF2425, 0x08230a9c}, +{8800000, DIF_BPF_COEFF2627, 0x00c7f4a3}, +{8800000, DIF_BPF_COEFF2829, 0xf45b01a6}, +{8800000, DIF_BPF_COEFF3031, 0x0e480b7c}, +{8800000, DIF_BPF_COEFF3233, 0xfb61efae}, +{8800000, DIF_BPF_COEFF3435, 0xf5ef079f}, +{8800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 88_quant.dat*/ + + +/*case 8900000:*/ +/* BEGIN - DIF BPF register values from 89_quant.dat*/ +{8900000, DIF_BPF_COEFF01, 0xffff0000}, +{8900000, DIF_BPF_COEFF23, 0x0008000d}, +{8900000, DIF_BPF_COEFF45, 0xfff5ffc8}, +{8900000, DIF_BPF_COEFF67, 0xffd10043}, +{8900000, DIF_BPF_COEFF89, 0x00b20053}, +{8900000, DIF_BPF_COEFF1011, 0xff24fe7c}, +{8900000, DIF_BPF_COEFF1213, 0xffb9020c}, +{8900000, DIF_BPF_COEFF1415, 0x0295ffbb}, +{8900000, DIF_BPF_COEFF1617, 0xfc17fc64}, +{8900000, DIF_BPF_COEFF1819, 0x019b0654}, +{8900000, DIF_BPF_COEFF2021, 0x042dfc1c}, +{8900000, DIF_BPF_COEFF2223, 0xf714fc2a}, +{8900000, DIF_BPF_COEFF2425, 0x07020b21}, +{8900000, DIF_BPF_COEFF2627, 0x0251f575}, +{8900000, DIF_BPF_COEFF2829, 0xf3a7005e}, +{8900000, DIF_BPF_COEFF3031, 0x0dd80c24}, +{8900000, DIF_BPF_COEFF3233, 0xfc2aefcd}, +{8900000, DIF_BPF_COEFF3435, 0xf599076e}, +{8900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 89_quant.dat*/ + + +/*case 9000000:*/ +/* BEGIN - DIF BPF register values from 90_quant.dat*/ +{9000000, DIF_BPF_COEFF01, 0xffffffff}, +{9000000, DIF_BPF_COEFF23, 0x00060011}, +{9000000, DIF_BPF_COEFF45, 0x0002ffcf}, +{9000000, DIF_BPF_COEFF67, 0xffba0018}, +{9000000, DIF_BPF_COEFF89, 0x00ad009a}, +{9000000, DIF_BPF_COEFF1011, 0xff79fe68}, +{9000000, DIF_BPF_COEFF1213, 0xff260192}, +{9000000, DIF_BPF_COEFF1415, 0x02e500ab}, +{9000000, DIF_BPF_COEFF1617, 0xfc99fbb6}, +{9000000, DIF_BPF_COEFF1819, 0x005b05f7}, +{9000000, DIF_BPF_COEFF2021, 0x0545fd81}, +{9000000, DIF_BPF_COEFF2223, 0xf723fabf}, +{9000000, DIF_BPF_COEFF2425, 0x05b80b70}, +{9000000, DIF_BPF_COEFF2627, 0x03d2f669}, +{9000000, DIF_BPF_COEFF2829, 0xf313ff15}, +{9000000, DIF_BPF_COEFF3031, 0x0d550cbf}, +{9000000, DIF_BPF_COEFF3233, 0xfcf6eff2}, +{9000000, DIF_BPF_COEFF3435, 0xf544073d}, +{9000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 90_quant.dat*/ + + +/*case 9100000:*/ +/* BEGIN - DIF BPF register values from 91_quant.dat*/ +{9100000, DIF_BPF_COEFF01, 0xfffffffe}, +{9100000, DIF_BPF_COEFF23, 0x00030012}, +{9100000, DIF_BPF_COEFF45, 0x000fffdd}, +{9100000, DIF_BPF_COEFF67, 0xffacffea}, +{9100000, DIF_BPF_COEFF89, 0x009300cf}, +{9100000, DIF_BPF_COEFF1011, 0xffdcfe7c}, +{9100000, DIF_BPF_COEFF1213, 0xfea600f7}, +{9100000, DIF_BPF_COEFF1415, 0x02fd0190}, +{9100000, DIF_BPF_COEFF1617, 0xfd51fb46}, +{9100000, DIF_BPF_COEFF1819, 0xff150554}, +{9100000, DIF_BPF_COEFF2021, 0x0627fefd}, +{9100000, DIF_BPF_COEFF2223, 0xf778f978}, +{9100000, DIF_BPF_COEFF2425, 0x044d0b87}, +{9100000, DIF_BPF_COEFF2627, 0x0543f77d}, +{9100000, DIF_BPF_COEFF2829, 0xf2a0fdcf}, +{9100000, DIF_BPF_COEFF3031, 0x0cbe0d4e}, +{9100000, DIF_BPF_COEFF3233, 0xfdc4f01d}, +{9100000, DIF_BPF_COEFF3435, 0xf4f2070b}, +{9100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 91_quant.dat*/ + + +/*case 9200000:*/ +/* BEGIN - DIF BPF register values from 92_quant.dat*/ +{9200000, DIF_BPF_COEFF01, 0x0000fffd}, +{9200000, DIF_BPF_COEFF23, 0x00000010}, +{9200000, DIF_BPF_COEFF45, 0x001afff0}, +{9200000, DIF_BPF_COEFF67, 0xffaaffbf}, +{9200000, DIF_BPF_COEFF89, 0x006700ed}, +{9200000, DIF_BPF_COEFF1011, 0x0043feb6}, +{9200000, DIF_BPF_COEFF1213, 0xfe460047}, +{9200000, DIF_BPF_COEFF1415, 0x02db0258}, +{9200000, DIF_BPF_COEFF1617, 0xfe35fb1b}, +{9200000, DIF_BPF_COEFF1819, 0xfddc0473}, +{9200000, DIF_BPF_COEFF2021, 0x06c90082}, +{9200000, DIF_BPF_COEFF2223, 0xf811f85e}, +{9200000, DIF_BPF_COEFF2425, 0x02c90b66}, +{9200000, DIF_BPF_COEFF2627, 0x069ff8ad}, +{9200000, DIF_BPF_COEFF2829, 0xf250fc8d}, +{9200000, DIF_BPF_COEFF3031, 0x0c140dcf}, +{9200000, DIF_BPF_COEFF3233, 0xfe93f04d}, +{9200000, DIF_BPF_COEFF3435, 0xf4a106d9}, +{9200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 92_quant.dat*/ + + +/*case 9300000:*/ +/* BEGIN - DIF BPF register values from 93_quant.dat*/ +{9300000, DIF_BPF_COEFF01, 0x0000fffd}, +{9300000, DIF_BPF_COEFF23, 0xfffc000c}, +{9300000, DIF_BPF_COEFF45, 0x00200006}, +{9300000, DIF_BPF_COEFF67, 0xffb4ff9c}, +{9300000, DIF_BPF_COEFF89, 0x002f00ef}, +{9300000, DIF_BPF_COEFF1011, 0x00a4ff10}, +{9300000, DIF_BPF_COEFF1213, 0xfe0dff92}, +{9300000, DIF_BPF_COEFF1415, 0x028102f7}, +{9300000, DIF_BPF_COEFF1617, 0xff36fb37}, +{9300000, DIF_BPF_COEFF1819, 0xfcbf035e}, +{9300000, DIF_BPF_COEFF2021, 0x07260202}, +{9300000, DIF_BPF_COEFF2223, 0xf8e8f778}, +{9300000, DIF_BPF_COEFF2425, 0x01340b0d}, +{9300000, DIF_BPF_COEFF2627, 0x07e1f9f4}, +{9300000, DIF_BPF_COEFF2829, 0xf223fb51}, +{9300000, DIF_BPF_COEFF3031, 0x0b590e42}, +{9300000, DIF_BPF_COEFF3233, 0xff64f083}, +{9300000, DIF_BPF_COEFF3435, 0xf45206a7}, +{9300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 93_quant.dat*/ + + +/*case 9400000:*/ +/* BEGIN - DIF BPF register values from 94_quant.dat*/ +{9400000, DIF_BPF_COEFF01, 0x0000fffd}, +{9400000, DIF_BPF_COEFF23, 0xfff90005}, +{9400000, DIF_BPF_COEFF45, 0x0022001a}, +{9400000, DIF_BPF_COEFF67, 0xffc9ff86}, +{9400000, DIF_BPF_COEFF89, 0xfff000d7}, +{9400000, DIF_BPF_COEFF1011, 0x00f2ff82}, +{9400000, DIF_BPF_COEFF1213, 0xfe01fee5}, +{9400000, DIF_BPF_COEFF1415, 0x01f60362}, +{9400000, DIF_BPF_COEFF1617, 0x0044fb99}, +{9400000, DIF_BPF_COEFF1819, 0xfbcc0222}, +{9400000, DIF_BPF_COEFF2021, 0x07380370}, +{9400000, DIF_BPF_COEFF2223, 0xf9f7f6cc}, +{9400000, DIF_BPF_COEFF2425, 0xff990a7e}, +{9400000, DIF_BPF_COEFF2627, 0x0902fb50}, +{9400000, DIF_BPF_COEFF2829, 0xf21afa1f}, +{9400000, DIF_BPF_COEFF3031, 0x0a8d0ea6}, +{9400000, DIF_BPF_COEFF3233, 0x0034f0bf}, +{9400000, DIF_BPF_COEFF3435, 0xf4050675}, +{9400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 94_quant.dat*/ + + +/*case 9500000:*/ +/* BEGIN - DIF BPF register values from 95_quant.dat*/ +{9500000, DIF_BPF_COEFF01, 0x0000fffe}, +{9500000, DIF_BPF_COEFF23, 0xfff8fffe}, +{9500000, DIF_BPF_COEFF45, 0x001e002b}, +{9500000, DIF_BPF_COEFF67, 0xffe5ff81}, +{9500000, DIF_BPF_COEFF89, 0xffb400a5}, +{9500000, DIF_BPF_COEFF1011, 0x01280000}, +{9500000, DIF_BPF_COEFF1213, 0xfe24fe50}, +{9500000, DIF_BPF_COEFF1415, 0x01460390}, +{9500000, DIF_BPF_COEFF1617, 0x014dfc3a}, +{9500000, DIF_BPF_COEFF1819, 0xfb1000ce}, +{9500000, DIF_BPF_COEFF2021, 0x070104bf}, +{9500000, DIF_BPF_COEFF2223, 0xfb37f65f}, +{9500000, DIF_BPF_COEFF2425, 0xfe0009bc}, +{9500000, DIF_BPF_COEFF2627, 0x0a00fcbb}, +{9500000, DIF_BPF_COEFF2829, 0xf235f8f8}, +{9500000, DIF_BPF_COEFF3031, 0x09b20efc}, +{9500000, DIF_BPF_COEFF3233, 0x0105f101}, +{9500000, DIF_BPF_COEFF3435, 0xf3ba0642}, +{9500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 95_quant.dat*/ + + +/*case 9600000:*/ +/* BEGIN - DIF BPF register values from 96_quant.dat*/ +{9600000, DIF_BPF_COEFF01, 0x0001ffff}, +{9600000, DIF_BPF_COEFF23, 0xfff8fff7}, +{9600000, DIF_BPF_COEFF45, 0x00150036}, +{9600000, DIF_BPF_COEFF67, 0x0005ff8c}, +{9600000, DIF_BPF_COEFF89, 0xff810061}, +{9600000, DIF_BPF_COEFF1011, 0x013d007e}, +{9600000, DIF_BPF_COEFF1213, 0xfe71fddf}, +{9600000, DIF_BPF_COEFF1415, 0x007c0380}, +{9600000, DIF_BPF_COEFF1617, 0x0241fd13}, +{9600000, DIF_BPF_COEFF1819, 0xfa94ff70}, +{9600000, DIF_BPF_COEFF2021, 0x068005e2}, +{9600000, DIF_BPF_COEFF2223, 0xfc9bf633}, +{9600000, DIF_BPF_COEFF2425, 0xfc7308ca}, +{9600000, DIF_BPF_COEFF2627, 0x0ad5fe30}, +{9600000, DIF_BPF_COEFF2829, 0xf274f7e0}, +{9600000, DIF_BPF_COEFF3031, 0x08c90f43}, +{9600000, DIF_BPF_COEFF3233, 0x01d4f147}, +{9600000, DIF_BPF_COEFF3435, 0xf371060f}, +{9600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 96_quant.dat*/ + + +/*case 9700000:*/ +/* BEGIN - DIF BPF register values from 97_quant.dat*/ +{9700000, DIF_BPF_COEFF01, 0x00010001}, +{9700000, DIF_BPF_COEFF23, 0xfff9fff1}, +{9700000, DIF_BPF_COEFF45, 0x00090038}, +{9700000, DIF_BPF_COEFF67, 0x0025ffa7}, +{9700000, DIF_BPF_COEFF89, 0xff5e0012}, +{9700000, DIF_BPF_COEFF1011, 0x013200f0}, +{9700000, DIF_BPF_COEFF1213, 0xfee3fd9b}, +{9700000, DIF_BPF_COEFF1415, 0xffaa0331}, +{9700000, DIF_BPF_COEFF1617, 0x0311fe15}, +{9700000, DIF_BPF_COEFF1819, 0xfa60fe18}, +{9700000, DIF_BPF_COEFF2021, 0x05bd06d1}, +{9700000, DIF_BPF_COEFF2223, 0xfe1bf64a}, +{9700000, DIF_BPF_COEFF2425, 0xfafa07ae}, +{9700000, DIF_BPF_COEFF2627, 0x0b7effab}, +{9700000, DIF_BPF_COEFF2829, 0xf2d5f6d7}, +{9700000, DIF_BPF_COEFF3031, 0x07d30f7a}, +{9700000, DIF_BPF_COEFF3233, 0x02a3f194}, +{9700000, DIF_BPF_COEFF3435, 0xf32905dc}, +{9700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 97_quant.dat*/ + + +/*case 9800000:*/ +/* BEGIN - DIF BPF register values from 98_quant.dat*/ +{9800000, DIF_BPF_COEFF01, 0x00010002}, +{9800000, DIF_BPF_COEFF23, 0xfffcffee}, +{9800000, DIF_BPF_COEFF45, 0xfffb0032}, +{9800000, DIF_BPF_COEFF67, 0x003fffcd}, +{9800000, DIF_BPF_COEFF89, 0xff4effc1}, +{9800000, DIF_BPF_COEFF1011, 0x0106014a}, +{9800000, DIF_BPF_COEFF1213, 0xff6efd8a}, +{9800000, DIF_BPF_COEFF1415, 0xfedd02aa}, +{9800000, DIF_BPF_COEFF1617, 0x03b0ff34}, +{9800000, DIF_BPF_COEFF1819, 0xfa74fcd7}, +{9800000, DIF_BPF_COEFF2021, 0x04bf0781}, +{9800000, DIF_BPF_COEFF2223, 0xffaaf6a3}, +{9800000, DIF_BPF_COEFF2425, 0xf99e066b}, +{9800000, DIF_BPF_COEFF2627, 0x0bf90128}, +{9800000, DIF_BPF_COEFF2829, 0xf359f5e1}, +{9800000, DIF_BPF_COEFF3031, 0x06d20fa2}, +{9800000, DIF_BPF_COEFF3233, 0x0370f1e5}, +{9800000, DIF_BPF_COEFF3435, 0xf2e405a8}, +{9800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 98_quant.dat*/ + + +/*case 9900000:*/ +/* BEGIN - DIF BPF register values from 99_quant.dat*/ +{9900000, DIF_BPF_COEFF01, 0x00000003}, +{9900000, DIF_BPF_COEFF23, 0xffffffee}, +{9900000, DIF_BPF_COEFF45, 0xffef0024}, +{9900000, DIF_BPF_COEFF67, 0x0051fffa}, +{9900000, DIF_BPF_COEFF89, 0xff54ff77}, +{9900000, DIF_BPF_COEFF1011, 0x00be0184}, +{9900000, DIF_BPF_COEFF1213, 0x0006fdad}, +{9900000, DIF_BPF_COEFF1415, 0xfe2701f3}, +{9900000, DIF_BPF_COEFF1617, 0x0413005e}, +{9900000, DIF_BPF_COEFF1819, 0xfad1fbba}, +{9900000, DIF_BPF_COEFF2021, 0x039007ee}, +{9900000, DIF_BPF_COEFF2223, 0x013bf73d}, +{9900000, DIF_BPF_COEFF2425, 0xf868050a}, +{9900000, DIF_BPF_COEFF2627, 0x0c4302a1}, +{9900000, DIF_BPF_COEFF2829, 0xf3fdf4fe}, +{9900000, DIF_BPF_COEFF3031, 0x05c70fba}, +{9900000, DIF_BPF_COEFF3233, 0x043bf23c}, +{9900000, DIF_BPF_COEFF3435, 0xf2a10575}, +{9900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 99_quant.dat*/ + + +/*case 10000000:*/ +/* BEGIN - DIF BPF register values from 100_quant.dat*/ +{10000000, DIF_BPF_COEFF01, 0x00000003}, +{10000000, DIF_BPF_COEFF23, 0x0003fff1}, +{10000000, DIF_BPF_COEFF45, 0xffe50011}, +{10000000, DIF_BPF_COEFF67, 0x00570027}, +{10000000, DIF_BPF_COEFF89, 0xff70ff3c}, +{10000000, DIF_BPF_COEFF1011, 0x00620198}, +{10000000, DIF_BPF_COEFF1213, 0x009efe01}, +{10000000, DIF_BPF_COEFF1415, 0xfd95011a}, +{10000000, DIF_BPF_COEFF1617, 0x04350183}, +{10000000, DIF_BPF_COEFF1819, 0xfb71fad0}, +{10000000, DIF_BPF_COEFF2021, 0x023c0812}, +{10000000, DIF_BPF_COEFF2223, 0x02c3f811}, +{10000000, DIF_BPF_COEFF2425, 0xf75e0390}, +{10000000, DIF_BPF_COEFF2627, 0x0c5c0411}, +{10000000, DIF_BPF_COEFF2829, 0xf4c1f432}, +{10000000, DIF_BPF_COEFF3031, 0x04b30fc1}, +{10000000, DIF_BPF_COEFF3233, 0x0503f297}, +{10000000, DIF_BPF_COEFF3435, 0xf2610541}, +{10000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 100_quant.dat*/ + + +/*case 10100000:*/ +/* BEGIN - DIF BPF register values from 101_quant.dat*/ +{10100000, DIF_BPF_COEFF01, 0x00000003}, +{10100000, DIF_BPF_COEFF23, 0x0006fff7}, +{10100000, DIF_BPF_COEFF45, 0xffdffffc}, +{10100000, DIF_BPF_COEFF67, 0x00510050}, +{10100000, DIF_BPF_COEFF89, 0xff9dff18}, +{10100000, DIF_BPF_COEFF1011, 0xfffc0184}, +{10100000, DIF_BPF_COEFF1213, 0x0128fe80}, +{10100000, DIF_BPF_COEFF1415, 0xfd32002e}, +{10100000, DIF_BPF_COEFF1617, 0x04130292}, +{10100000, DIF_BPF_COEFF1819, 0xfc4dfa21}, +{10100000, DIF_BPF_COEFF2021, 0x00d107ee}, +{10100000, DIF_BPF_COEFF2223, 0x0435f91c}, +{10100000, DIF_BPF_COEFF2425, 0xf6850205}, +{10100000, DIF_BPF_COEFF2627, 0x0c430573}, +{10100000, DIF_BPF_COEFF2829, 0xf5a1f37d}, +{10100000, DIF_BPF_COEFF3031, 0x03990fba}, +{10100000, DIF_BPF_COEFF3233, 0x05c7f2f8}, +{10100000, DIF_BPF_COEFF3435, 0xf222050d}, +{10100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 101_quant.dat*/ + + +/*case 10200000:*/ +/* BEGIN - DIF BPF register values from 102_quant.dat*/ +{10200000, DIF_BPF_COEFF01, 0x00000002}, +{10200000, DIF_BPF_COEFF23, 0x0008fffe}, +{10200000, DIF_BPF_COEFF45, 0xffdfffe7}, +{10200000, DIF_BPF_COEFF67, 0x003f006e}, +{10200000, DIF_BPF_COEFF89, 0xffd6ff0f}, +{10200000, DIF_BPF_COEFF1011, 0xff96014a}, +{10200000, DIF_BPF_COEFF1213, 0x0197ff1f}, +{10200000, DIF_BPF_COEFF1415, 0xfd05ff3e}, +{10200000, DIF_BPF_COEFF1617, 0x03b0037c}, +{10200000, DIF_BPF_COEFF1819, 0xfd59f9b7}, +{10200000, DIF_BPF_COEFF2021, 0xff5d0781}, +{10200000, DIF_BPF_COEFF2223, 0x0585fa56}, +{10200000, DIF_BPF_COEFF2425, 0xf5e4006f}, +{10200000, DIF_BPF_COEFF2627, 0x0bf906c4}, +{10200000, DIF_BPF_COEFF2829, 0xf69df2e0}, +{10200000, DIF_BPF_COEFF3031, 0x02790fa2}, +{10200000, DIF_BPF_COEFF3233, 0x0688f35d}, +{10200000, DIF_BPF_COEFF3435, 0xf1e604d8}, +{10200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 102_quant.dat*/ + + +/*case 10300000:*/ +/* BEGIN - DIF BPF register values from 103_quant.dat*/ +{10300000, DIF_BPF_COEFF01, 0xffff0001}, +{10300000, DIF_BPF_COEFF23, 0x00090005}, +{10300000, DIF_BPF_COEFF45, 0xffe4ffd6}, +{10300000, DIF_BPF_COEFF67, 0x0025007e}, +{10300000, DIF_BPF_COEFF89, 0x0014ff20}, +{10300000, DIF_BPF_COEFF1011, 0xff3c00f0}, +{10300000, DIF_BPF_COEFF1213, 0x01e1ffd0}, +{10300000, DIF_BPF_COEFF1415, 0xfd12fe5c}, +{10300000, DIF_BPF_COEFF1617, 0x03110433}, +{10300000, DIF_BPF_COEFF1819, 0xfe88f996}, +{10300000, DIF_BPF_COEFF2021, 0xfdf106d1}, +{10300000, DIF_BPF_COEFF2223, 0x06aafbb7}, +{10300000, DIF_BPF_COEFF2425, 0xf57efed8}, +{10300000, DIF_BPF_COEFF2627, 0x0b7e07ff}, +{10300000, DIF_BPF_COEFF2829, 0xf7b0f25e}, +{10300000, DIF_BPF_COEFF3031, 0x01560f7a}, +{10300000, DIF_BPF_COEFF3233, 0x0745f3c7}, +{10300000, DIF_BPF_COEFF3435, 0xf1ac04a4}, +{10300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 103_quant.dat*/ + + +/*case 10400000:*/ +/* BEGIN - DIF BPF register values from 104_quant.dat*/ +{10400000, DIF_BPF_COEFF01, 0xffffffff}, +{10400000, DIF_BPF_COEFF23, 0x0008000c}, +{10400000, DIF_BPF_COEFF45, 0xffedffcb}, +{10400000, DIF_BPF_COEFF67, 0x0005007d}, +{10400000, DIF_BPF_COEFF89, 0x0050ff4c}, +{10400000, DIF_BPF_COEFF1011, 0xfef6007e}, +{10400000, DIF_BPF_COEFF1213, 0x01ff0086}, +{10400000, DIF_BPF_COEFF1415, 0xfd58fd97}, +{10400000, DIF_BPF_COEFF1617, 0x024104ad}, +{10400000, DIF_BPF_COEFF1819, 0xffcaf9c0}, +{10400000, DIF_BPF_COEFF2021, 0xfc9905e2}, +{10400000, DIF_BPF_COEFF2223, 0x079afd35}, +{10400000, DIF_BPF_COEFF2425, 0xf555fd46}, +{10400000, DIF_BPF_COEFF2627, 0x0ad50920}, +{10400000, DIF_BPF_COEFF2829, 0xf8d9f1f6}, +{10400000, DIF_BPF_COEFF3031, 0x00310f43}, +{10400000, DIF_BPF_COEFF3233, 0x07fdf435}, +{10400000, DIF_BPF_COEFF3435, 0xf174046f}, +{10400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 104_quant.dat*/ + + +/*case 10500000:*/ +/* BEGIN - DIF BPF register values from 105_quant.dat*/ +{10500000, DIF_BPF_COEFF01, 0xfffffffe}, +{10500000, DIF_BPF_COEFF23, 0x00050011}, +{10500000, DIF_BPF_COEFF45, 0xfffaffc8}, +{10500000, DIF_BPF_COEFF67, 0xffe5006b}, +{10500000, DIF_BPF_COEFF89, 0x0082ff8c}, +{10500000, DIF_BPF_COEFF1011, 0xfecc0000}, +{10500000, DIF_BPF_COEFF1213, 0x01f00130}, +{10500000, DIF_BPF_COEFF1415, 0xfdd2fcfc}, +{10500000, DIF_BPF_COEFF1617, 0x014d04e3}, +{10500000, DIF_BPF_COEFF1819, 0x010efa32}, +{10500000, DIF_BPF_COEFF2021, 0xfb6404bf}, +{10500000, DIF_BPF_COEFF2223, 0x084efec5}, +{10500000, DIF_BPF_COEFF2425, 0xf569fbc2}, +{10500000, DIF_BPF_COEFF2627, 0x0a000a23}, +{10500000, DIF_BPF_COEFF2829, 0xfa15f1ab}, +{10500000, DIF_BPF_COEFF3031, 0xff0b0efc}, +{10500000, DIF_BPF_COEFF3233, 0x08b0f4a7}, +{10500000, DIF_BPF_COEFF3435, 0xf13f043a}, +{10500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 105_quant.dat*/ + + +/*case 10600000:*/ +/* BEGIN - DIF BPF register values from 106_quant.dat*/ +{10600000, DIF_BPF_COEFF01, 0x0000fffd}, +{10600000, DIF_BPF_COEFF23, 0x00020012}, +{10600000, DIF_BPF_COEFF45, 0x0007ffcd}, +{10600000, DIF_BPF_COEFF67, 0xffc9004c}, +{10600000, DIF_BPF_COEFF89, 0x00a4ffd9}, +{10600000, DIF_BPF_COEFF1011, 0xfec3ff82}, +{10600000, DIF_BPF_COEFF1213, 0x01b401c1}, +{10600000, DIF_BPF_COEFF1415, 0xfe76fc97}, +{10600000, DIF_BPF_COEFF1617, 0x004404d2}, +{10600000, DIF_BPF_COEFF1819, 0x0245fae8}, +{10600000, DIF_BPF_COEFF2021, 0xfa5f0370}, +{10600000, DIF_BPF_COEFF2223, 0x08c1005f}, +{10600000, DIF_BPF_COEFF2425, 0xf5bcfa52}, +{10600000, DIF_BPF_COEFF2627, 0x09020b04}, +{10600000, DIF_BPF_COEFF2829, 0xfb60f17b}, +{10600000, DIF_BPF_COEFF3031, 0xfde70ea6}, +{10600000, DIF_BPF_COEFF3233, 0x095df51e}, +{10600000, DIF_BPF_COEFF3435, 0xf10c0405}, +{10600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 106_quant.dat*/ + + +/*case 10700000:*/ +/* BEGIN - DIF BPF register values from 107_quant.dat*/ +{10700000, DIF_BPF_COEFF01, 0x0000fffd}, +{10700000, DIF_BPF_COEFF23, 0xffff0011}, +{10700000, DIF_BPF_COEFF45, 0x0014ffdb}, +{10700000, DIF_BPF_COEFF67, 0xffb40023}, +{10700000, DIF_BPF_COEFF89, 0x00b2002a}, +{10700000, DIF_BPF_COEFF1011, 0xfedbff10}, +{10700000, DIF_BPF_COEFF1213, 0x0150022d}, +{10700000, DIF_BPF_COEFF1415, 0xff38fc6f}, +{10700000, DIF_BPF_COEFF1617, 0xff36047b}, +{10700000, DIF_BPF_COEFF1819, 0x035efbda}, +{10700000, DIF_BPF_COEFF2021, 0xf9940202}, +{10700000, DIF_BPF_COEFF2223, 0x08ee01f5}, +{10700000, DIF_BPF_COEFF2425, 0xf649f8fe}, +{10700000, DIF_BPF_COEFF2627, 0x07e10bc2}, +{10700000, DIF_BPF_COEFF2829, 0xfcb6f169}, +{10700000, DIF_BPF_COEFF3031, 0xfcc60e42}, +{10700000, DIF_BPF_COEFF3233, 0x0a04f599}, +{10700000, DIF_BPF_COEFF3435, 0xf0db03d0}, +{10700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 107_quant.dat*/ + + +/*case 10800000:*/ +/* BEGIN - DIF BPF register values from 108_quant.dat*/ +{10800000, DIF_BPF_COEFF01, 0x0000fffd}, +{10800000, DIF_BPF_COEFF23, 0xfffb000d}, +{10800000, DIF_BPF_COEFF45, 0x001dffed}, +{10800000, DIF_BPF_COEFF67, 0xffaafff5}, +{10800000, DIF_BPF_COEFF89, 0x00aa0077}, +{10800000, DIF_BPF_COEFF1011, 0xff13feb6}, +{10800000, DIF_BPF_COEFF1213, 0x00ce026b}, +{10800000, DIF_BPF_COEFF1415, 0x000afc85}, +{10800000, DIF_BPF_COEFF1617, 0xfe3503e3}, +{10800000, DIF_BPF_COEFF1819, 0x044cfcfb}, +{10800000, DIF_BPF_COEFF2021, 0xf90c0082}, +{10800000, DIF_BPF_COEFF2223, 0x08d5037f}, +{10800000, DIF_BPF_COEFF2425, 0xf710f7cc}, +{10800000, DIF_BPF_COEFF2627, 0x069f0c59}, +{10800000, DIF_BPF_COEFF2829, 0xfe16f173}, +{10800000, DIF_BPF_COEFF3031, 0xfbaa0dcf}, +{10800000, DIF_BPF_COEFF3233, 0x0aa5f617}, +{10800000, DIF_BPF_COEFF3435, 0xf0ad039b}, +{10800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 108_quant.dat*/ + + +/*case 10900000:*/ +/* BEGIN - DIF BPF register values from 109_quant.dat*/ +{10900000, DIF_BPF_COEFF01, 0x0000fffe}, +{10900000, DIF_BPF_COEFF23, 0xfff90006}, +{10900000, DIF_BPF_COEFF45, 0x00210003}, +{10900000, DIF_BPF_COEFF67, 0xffacffc8}, +{10900000, DIF_BPF_COEFF89, 0x008e00b6}, +{10900000, DIF_BPF_COEFF1011, 0xff63fe7c}, +{10900000, DIF_BPF_COEFF1213, 0x003a0275}, +{10900000, DIF_BPF_COEFF1415, 0x00dafcda}, +{10900000, DIF_BPF_COEFF1617, 0xfd510313}, +{10900000, DIF_BPF_COEFF1819, 0x0501fe40}, +{10900000, DIF_BPF_COEFF2021, 0xf8cbfefd}, +{10900000, DIF_BPF_COEFF2223, 0x087604f0}, +{10900000, DIF_BPF_COEFF2425, 0xf80af6c2}, +{10900000, DIF_BPF_COEFF2627, 0x05430cc8}, +{10900000, DIF_BPF_COEFF2829, 0xff7af19a}, +{10900000, DIF_BPF_COEFF3031, 0xfa940d4e}, +{10900000, DIF_BPF_COEFF3233, 0x0b3ff699}, +{10900000, DIF_BPF_COEFF3435, 0xf0810365}, +{10900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 109_quant.dat*/ + + +/*case 11000000:*/ +/* BEGIN - DIF BPF register values from 110_quant.dat*/ +{11000000, DIF_BPF_COEFF01, 0x0001ffff}, +{11000000, DIF_BPF_COEFF23, 0xfff8ffff}, +{11000000, DIF_BPF_COEFF45, 0x00210018}, +{11000000, DIF_BPF_COEFF67, 0xffbaffa3}, +{11000000, DIF_BPF_COEFF89, 0x006000e1}, +{11000000, DIF_BPF_COEFF1011, 0xffc4fe68}, +{11000000, DIF_BPF_COEFF1213, 0xffa0024b}, +{11000000, DIF_BPF_COEFF1415, 0x019afd66}, +{11000000, DIF_BPF_COEFF1617, 0xfc990216}, +{11000000, DIF_BPF_COEFF1819, 0x0575ff99}, +{11000000, DIF_BPF_COEFF2021, 0xf8d4fd81}, +{11000000, DIF_BPF_COEFF2223, 0x07d40640}, +{11000000, DIF_BPF_COEFF2425, 0xf932f5e6}, +{11000000, DIF_BPF_COEFF2627, 0x03d20d0d}, +{11000000, DIF_BPF_COEFF2829, 0x00dff1de}, +{11000000, DIF_BPF_COEFF3031, 0xf9860cbf}, +{11000000, DIF_BPF_COEFF3233, 0x0bd1f71e}, +{11000000, DIF_BPF_COEFF3435, 0xf058032f}, +{11000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 110_quant.dat*/ + + +/*case 11100000:*/ +/* BEGIN - DIF BPF register values from 111_quant.dat*/ +{11100000, DIF_BPF_COEFF01, 0x00010000}, +{11100000, DIF_BPF_COEFF23, 0xfff8fff8}, +{11100000, DIF_BPF_COEFF45, 0x001b0029}, +{11100000, DIF_BPF_COEFF67, 0xffd1ff8a}, +{11100000, DIF_BPF_COEFF89, 0x002600f2}, +{11100000, DIF_BPF_COEFF1011, 0x002cfe7c}, +{11100000, DIF_BPF_COEFF1213, 0xff0f01f0}, +{11100000, DIF_BPF_COEFF1415, 0x023bfe20}, +{11100000, DIF_BPF_COEFF1617, 0xfc1700fa}, +{11100000, DIF_BPF_COEFF1819, 0x05a200f7}, +{11100000, DIF_BPF_COEFF2021, 0xf927fc1c}, +{11100000, DIF_BPF_COEFF2223, 0x06f40765}, +{11100000, DIF_BPF_COEFF2425, 0xfa82f53b}, +{11100000, DIF_BPF_COEFF2627, 0x02510d27}, +{11100000, DIF_BPF_COEFF2829, 0x0243f23d}, +{11100000, DIF_BPF_COEFF3031, 0xf8810c24}, +{11100000, DIF_BPF_COEFF3233, 0x0c5cf7a7}, +{11100000, DIF_BPF_COEFF3435, 0xf03102fa}, +{11100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 111_quant.dat*/ + + +/*case 11200000:*/ +/* BEGIN - DIF BPF register values from 112_quant.dat*/ +{11200000, DIF_BPF_COEFF01, 0x00010002}, +{11200000, DIF_BPF_COEFF23, 0xfffafff2}, +{11200000, DIF_BPF_COEFF45, 0x00110035}, +{11200000, DIF_BPF_COEFF67, 0xfff0ff81}, +{11200000, DIF_BPF_COEFF89, 0xffe700e7}, +{11200000, DIF_BPF_COEFF1011, 0x008ffeb6}, +{11200000, DIF_BPF_COEFF1213, 0xfe94016d}, +{11200000, DIF_BPF_COEFF1415, 0x02b0fefb}, +{11200000, DIF_BPF_COEFF1617, 0xfbd3ffd1}, +{11200000, DIF_BPF_COEFF1819, 0x05850249}, +{11200000, DIF_BPF_COEFF2021, 0xf9c1fadb}, +{11200000, DIF_BPF_COEFF2223, 0x05de0858}, +{11200000, DIF_BPF_COEFF2425, 0xfbf2f4c4}, +{11200000, DIF_BPF_COEFF2627, 0x00c70d17}, +{11200000, DIF_BPF_COEFF2829, 0x03a0f2b8}, +{11200000, DIF_BPF_COEFF3031, 0xf7870b7c}, +{11200000, DIF_BPF_COEFF3233, 0x0cdff833}, +{11200000, DIF_BPF_COEFF3435, 0xf00d02c4}, +{11200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 112_quant.dat*/ + + +/*case 11300000:*/ +/* BEGIN - DIF BPF register values from 113_quant.dat*/ +{11300000, DIF_BPF_COEFF01, 0x00000003}, +{11300000, DIF_BPF_COEFF23, 0xfffdffee}, +{11300000, DIF_BPF_COEFF45, 0x00040038}, +{11300000, DIF_BPF_COEFF67, 0x0010ff88}, +{11300000, DIF_BPF_COEFF89, 0xffac00c2}, +{11300000, DIF_BPF_COEFF1011, 0x00e2ff10}, +{11300000, DIF_BPF_COEFF1213, 0xfe3900cb}, +{11300000, DIF_BPF_COEFF1415, 0x02f1ffe9}, +{11300000, DIF_BPF_COEFF1617, 0xfbd3feaa}, +{11300000, DIF_BPF_COEFF1819, 0x05210381}, +{11300000, DIF_BPF_COEFF2021, 0xfa9cf9c8}, +{11300000, DIF_BPF_COEFF2223, 0x04990912}, +{11300000, DIF_BPF_COEFF2425, 0xfd7af484}, +{11300000, DIF_BPF_COEFF2627, 0xff390cdb}, +{11300000, DIF_BPF_COEFF2829, 0x04f4f34d}, +{11300000, DIF_BPF_COEFF3031, 0xf69a0ac9}, +{11300000, DIF_BPF_COEFF3233, 0x0d5af8c1}, +{11300000, DIF_BPF_COEFF3435, 0xefec028e}, +{11300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 113_quant.dat*/ + + +/*case 11400000:*/ +/* BEGIN - DIF BPF register values from 114_quant.dat*/ +{11400000, DIF_BPF_COEFF01, 0x00000003}, +{11400000, DIF_BPF_COEFF23, 0x0000ffee}, +{11400000, DIF_BPF_COEFF45, 0xfff60033}, +{11400000, DIF_BPF_COEFF67, 0x002fff9f}, +{11400000, DIF_BPF_COEFF89, 0xff7b0087}, +{11400000, DIF_BPF_COEFF1011, 0x011eff82}, +{11400000, DIF_BPF_COEFF1213, 0xfe080018}, +{11400000, DIF_BPF_COEFF1415, 0x02f900d8}, +{11400000, DIF_BPF_COEFF1617, 0xfc17fd96}, +{11400000, DIF_BPF_COEFF1819, 0x04790490}, +{11400000, DIF_BPF_COEFF2021, 0xfbadf8ed}, +{11400000, DIF_BPF_COEFF2223, 0x032f098e}, +{11400000, DIF_BPF_COEFF2425, 0xff10f47d}, +{11400000, DIF_BPF_COEFF2627, 0xfdaf0c75}, +{11400000, DIF_BPF_COEFF2829, 0x063cf3fc}, +{11400000, DIF_BPF_COEFF3031, 0xf5ba0a0b}, +{11400000, DIF_BPF_COEFF3233, 0x0dccf952}, +{11400000, DIF_BPF_COEFF3435, 0xefcd0258}, +{11400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 114_quant.dat*/ + + +/*case 11500000:*/ +/* BEGIN - DIF BPF register values from 115_quant.dat*/ +{11500000, DIF_BPF_COEFF01, 0x00000003}, +{11500000, DIF_BPF_COEFF23, 0x0004fff1}, +{11500000, DIF_BPF_COEFF45, 0xffea0026}, +{11500000, DIF_BPF_COEFF67, 0x0046ffc3}, +{11500000, DIF_BPF_COEFF89, 0xff5a003c}, +{11500000, DIF_BPF_COEFF1011, 0x013b0000}, +{11500000, DIF_BPF_COEFF1213, 0xfe04ff63}, +{11500000, DIF_BPF_COEFF1415, 0x02c801b8}, +{11500000, DIF_BPF_COEFF1617, 0xfc99fca6}, +{11500000, DIF_BPF_COEFF1819, 0x0397056a}, +{11500000, DIF_BPF_COEFF2021, 0xfcecf853}, +{11500000, DIF_BPF_COEFF2223, 0x01ad09c9}, +{11500000, DIF_BPF_COEFF2425, 0x00acf4ad}, +{11500000, DIF_BPF_COEFF2627, 0xfc2e0be7}, +{11500000, DIF_BPF_COEFF2829, 0x0773f4c2}, +{11500000, DIF_BPF_COEFF3031, 0xf4e90943}, +{11500000, DIF_BPF_COEFF3233, 0x0e35f9e6}, +{11500000, DIF_BPF_COEFF3435, 0xefb10221}, +{11500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 115_quant.dat*/ + + +/*case 11600000:*/ +/* BEGIN - DIF BPF register values from 116_quant.dat*/ +{11600000, DIF_BPF_COEFF01, 0x00000002}, +{11600000, DIF_BPF_COEFF23, 0x0007fff6}, +{11600000, DIF_BPF_COEFF45, 0xffe20014}, +{11600000, DIF_BPF_COEFF67, 0x0054ffee}, +{11600000, DIF_BPF_COEFF89, 0xff4effeb}, +{11600000, DIF_BPF_COEFF1011, 0x0137007e}, +{11600000, DIF_BPF_COEFF1213, 0xfe2efebb}, +{11600000, DIF_BPF_COEFF1415, 0x0260027a}, +{11600000, DIF_BPF_COEFF1617, 0xfd51fbe6}, +{11600000, DIF_BPF_COEFF1819, 0x02870605}, +{11600000, DIF_BPF_COEFF2021, 0xfe4af7fe}, +{11600000, DIF_BPF_COEFF2223, 0x001d09c1}, +{11600000, DIF_BPF_COEFF2425, 0x0243f515}, +{11600000, DIF_BPF_COEFF2627, 0xfabd0b32}, +{11600000, DIF_BPF_COEFF2829, 0x0897f59e}, +{11600000, DIF_BPF_COEFF3031, 0xf4280871}, +{11600000, DIF_BPF_COEFF3233, 0x0e95fa7c}, +{11600000, DIF_BPF_COEFF3435, 0xef9701eb}, +{11600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 116_quant.dat*/ + + +/*case 11700000:*/ +/* BEGIN - DIF BPF register values from 117_quant.dat*/ +{11700000, DIF_BPF_COEFF01, 0xffff0001}, +{11700000, DIF_BPF_COEFF23, 0x0008fffd}, +{11700000, DIF_BPF_COEFF45, 0xffdeffff}, +{11700000, DIF_BPF_COEFF67, 0x0056001d}, +{11700000, DIF_BPF_COEFF89, 0xff57ff9c}, +{11700000, DIF_BPF_COEFF1011, 0x011300f0}, +{11700000, DIF_BPF_COEFF1213, 0xfe82fe2e}, +{11700000, DIF_BPF_COEFF1415, 0x01ca0310}, +{11700000, DIF_BPF_COEFF1617, 0xfe35fb62}, +{11700000, DIF_BPF_COEFF1819, 0x0155065a}, +{11700000, DIF_BPF_COEFF2021, 0xffbaf7f2}, +{11700000, DIF_BPF_COEFF2223, 0xfe8c0977}, +{11700000, DIF_BPF_COEFF2425, 0x03cef5b2}, +{11700000, DIF_BPF_COEFF2627, 0xf9610a58}, +{11700000, DIF_BPF_COEFF2829, 0x09a5f68f}, +{11700000, DIF_BPF_COEFF3031, 0xf3790797}, +{11700000, DIF_BPF_COEFF3233, 0x0eebfb14}, +{11700000, DIF_BPF_COEFF3435, 0xef8001b5}, +{11700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 117_quant.dat*/ + + +/*case 11800000:*/ +/* BEGIN - DIF BPF register values from 118_quant.dat*/ +{11800000, DIF_BPF_COEFF01, 0xffff0000}, +{11800000, DIF_BPF_COEFF23, 0x00080004}, +{11800000, DIF_BPF_COEFF45, 0xffe0ffe9}, +{11800000, DIF_BPF_COEFF67, 0x004c0047}, +{11800000, DIF_BPF_COEFF89, 0xff75ff58}, +{11800000, DIF_BPF_COEFF1011, 0x00d1014a}, +{11800000, DIF_BPF_COEFF1213, 0xfef9fdc8}, +{11800000, DIF_BPF_COEFF1415, 0x0111036f}, +{11800000, DIF_BPF_COEFF1617, 0xff36fb21}, +{11800000, DIF_BPF_COEFF1819, 0x00120665}, +{11800000, DIF_BPF_COEFF2021, 0x012df82e}, +{11800000, DIF_BPF_COEFF2223, 0xfd0708ec}, +{11800000, DIF_BPF_COEFF2425, 0x0542f682}, +{11800000, DIF_BPF_COEFF2627, 0xf81f095c}, +{11800000, DIF_BPF_COEFF2829, 0x0a9af792}, +{11800000, DIF_BPF_COEFF3031, 0xf2db06b5}, +{11800000, DIF_BPF_COEFF3233, 0x0f38fbad}, +{11800000, DIF_BPF_COEFF3435, 0xef6c017e}, +{11800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 118_quant.dat*/ + + +/*case 11900000:*/ +/* BEGIN - DIF BPF register values from 119_quant.dat*/ +{11900000, DIF_BPF_COEFF01, 0xffffffff}, +{11900000, DIF_BPF_COEFF23, 0x0007000b}, +{11900000, DIF_BPF_COEFF45, 0xffe7ffd8}, +{11900000, DIF_BPF_COEFF67, 0x00370068}, +{11900000, DIF_BPF_COEFF89, 0xffa4ff28}, +{11900000, DIF_BPF_COEFF1011, 0x00790184}, +{11900000, DIF_BPF_COEFF1213, 0xff87fd91}, +{11900000, DIF_BPF_COEFF1415, 0x00430392}, +{11900000, DIF_BPF_COEFF1617, 0x0044fb26}, +{11900000, DIF_BPF_COEFF1819, 0xfece0626}, +{11900000, DIF_BPF_COEFF2021, 0x0294f8b2}, +{11900000, DIF_BPF_COEFF2223, 0xfb990825}, +{11900000, DIF_BPF_COEFF2425, 0x0698f77f}, +{11900000, DIF_BPF_COEFF2627, 0xf6fe0842}, +{11900000, DIF_BPF_COEFF2829, 0x0b73f8a7}, +{11900000, DIF_BPF_COEFF3031, 0xf25105cd}, +{11900000, DIF_BPF_COEFF3233, 0x0f7bfc48}, +{11900000, DIF_BPF_COEFF3435, 0xef5a0148}, +{11900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 119_quant.dat*/ + + +/*case 12000000:*/ +/* BEGIN - DIF BPF register values from 120_quant.dat*/ +{12000000, DIF_BPF_COEFF01, 0x0000fffe}, +{12000000, DIF_BPF_COEFF23, 0x00050010}, +{12000000, DIF_BPF_COEFF45, 0xfff2ffcc}, +{12000000, DIF_BPF_COEFF67, 0x001b007b}, +{12000000, DIF_BPF_COEFF89, 0xffdfff10}, +{12000000, DIF_BPF_COEFF1011, 0x00140198}, +{12000000, DIF_BPF_COEFF1213, 0x0020fd8e}, +{12000000, DIF_BPF_COEFF1415, 0xff710375}, +{12000000, DIF_BPF_COEFF1617, 0x014dfb73}, +{12000000, DIF_BPF_COEFF1819, 0xfd9a059f}, +{12000000, DIF_BPF_COEFF2021, 0x03e0f978}, +{12000000, DIF_BPF_COEFF2223, 0xfa4e0726}, +{12000000, DIF_BPF_COEFF2425, 0x07c8f8a7}, +{12000000, DIF_BPF_COEFF2627, 0xf600070c}, +{12000000, DIF_BPF_COEFF2829, 0x0c2ff9c9}, +{12000000, DIF_BPF_COEFF3031, 0xf1db04de}, +{12000000, DIF_BPF_COEFF3233, 0x0fb4fce5}, +{12000000, DIF_BPF_COEFF3435, 0xef4b0111}, +{12000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 120_quant.dat*/ + + +/*case 12100000:*/ +/* BEGIN - DIF BPF register values from 121_quant.dat*/ +{12100000, DIF_BPF_COEFF01, 0x0000fffd}, +{12100000, DIF_BPF_COEFF23, 0x00010012}, +{12100000, DIF_BPF_COEFF45, 0xffffffc8}, +{12100000, DIF_BPF_COEFF67, 0xfffb007e}, +{12100000, DIF_BPF_COEFF89, 0x001dff14}, +{12100000, DIF_BPF_COEFF1011, 0xffad0184}, +{12100000, DIF_BPF_COEFF1213, 0x00b7fdbe}, +{12100000, DIF_BPF_COEFF1415, 0xfea9031b}, +{12100000, DIF_BPF_COEFF1617, 0x0241fc01}, +{12100000, DIF_BPF_COEFF1819, 0xfc8504d6}, +{12100000, DIF_BPF_COEFF2021, 0x0504fa79}, +{12100000, DIF_BPF_COEFF2223, 0xf93005f6}, +{12100000, DIF_BPF_COEFF2425, 0x08caf9f2}, +{12100000, DIF_BPF_COEFF2627, 0xf52b05c0}, +{12100000, DIF_BPF_COEFF2829, 0x0ccbfaf9}, +{12100000, DIF_BPF_COEFF3031, 0xf17903eb}, +{12100000, DIF_BPF_COEFF3233, 0x0fe3fd83}, +{12100000, DIF_BPF_COEFF3435, 0xef3f00db}, +{12100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 121_quant.dat*/ + + +/*case 12200000:*/ +/* BEGIN - DIF BPF register values from 122_quant.dat*/ +{12200000, DIF_BPF_COEFF01, 0x0000fffd}, +{12200000, DIF_BPF_COEFF23, 0xfffe0011}, +{12200000, DIF_BPF_COEFF45, 0x000cffcc}, +{12200000, DIF_BPF_COEFF67, 0xffdb0071}, +{12200000, DIF_BPF_COEFF89, 0x0058ff32}, +{12200000, DIF_BPF_COEFF1011, 0xff4f014a}, +{12200000, DIF_BPF_COEFF1213, 0x013cfe1f}, +{12200000, DIF_BPF_COEFF1415, 0xfdfb028a}, +{12200000, DIF_BPF_COEFF1617, 0x0311fcc9}, +{12200000, DIF_BPF_COEFF1819, 0xfb9d03d6}, +{12200000, DIF_BPF_COEFF2021, 0x05f4fbad}, +{12200000, DIF_BPF_COEFF2223, 0xf848049d}, +{12200000, DIF_BPF_COEFF2425, 0x0999fb5b}, +{12200000, DIF_BPF_COEFF2627, 0xf4820461}, +{12200000, DIF_BPF_COEFF2829, 0x0d46fc32}, +{12200000, DIF_BPF_COEFF3031, 0xf12d02f4}, +{12200000, DIF_BPF_COEFF3233, 0x1007fe21}, +{12200000, DIF_BPF_COEFF3435, 0xef3600a4}, +{12200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 122_quant.dat*/ + + +/*case 12300000:*/ +/* BEGIN - DIF BPF register values from 123_quant.dat*/ +{12300000, DIF_BPF_COEFF01, 0x0000fffe}, +{12300000, DIF_BPF_COEFF23, 0xfffa000e}, +{12300000, DIF_BPF_COEFF45, 0x0017ffd9}, +{12300000, DIF_BPF_COEFF67, 0xffc10055}, +{12300000, DIF_BPF_COEFF89, 0x0088ff68}, +{12300000, DIF_BPF_COEFF1011, 0xff0400f0}, +{12300000, DIF_BPF_COEFF1213, 0x01a6fea7}, +{12300000, DIF_BPF_COEFF1415, 0xfd7501cc}, +{12300000, DIF_BPF_COEFF1617, 0x03b0fdc0}, +{12300000, DIF_BPF_COEFF1819, 0xfaef02a8}, +{12300000, DIF_BPF_COEFF2021, 0x06a7fd07}, +{12300000, DIF_BPF_COEFF2223, 0xf79d0326}, +{12300000, DIF_BPF_COEFF2425, 0x0a31fcda}, +{12300000, DIF_BPF_COEFF2627, 0xf40702f3}, +{12300000, DIF_BPF_COEFF2829, 0x0d9ffd72}, +{12300000, DIF_BPF_COEFF3031, 0xf0f601fa}, +{12300000, DIF_BPF_COEFF3233, 0x1021fec0}, +{12300000, DIF_BPF_COEFF3435, 0xef2f006d}, +{12300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 123_quant.dat*/ + + +/*case 12400000:*/ +/* BEGIN - DIF BPF register values from 124_quant.dat*/ +{12400000, DIF_BPF_COEFF01, 0x0001ffff}, +{12400000, DIF_BPF_COEFF23, 0xfff80007}, +{12400000, DIF_BPF_COEFF45, 0x001fffeb}, +{12400000, DIF_BPF_COEFF67, 0xffaf002d}, +{12400000, DIF_BPF_COEFF89, 0x00a8ffb0}, +{12400000, DIF_BPF_COEFF1011, 0xfed3007e}, +{12400000, DIF_BPF_COEFF1213, 0x01e9ff4c}, +{12400000, DIF_BPF_COEFF1415, 0xfd2000ee}, +{12400000, DIF_BPF_COEFF1617, 0x0413fed8}, +{12400000, DIF_BPF_COEFF1819, 0xfa82015c}, +{12400000, DIF_BPF_COEFF2021, 0x0715fe7d}, +{12400000, DIF_BPF_COEFF2223, 0xf7340198}, +{12400000, DIF_BPF_COEFF2425, 0x0a8dfe69}, +{12400000, DIF_BPF_COEFF2627, 0xf3bd017c}, +{12400000, DIF_BPF_COEFF2829, 0x0dd5feb8}, +{12400000, DIF_BPF_COEFF3031, 0xf0d500fd}, +{12400000, DIF_BPF_COEFF3233, 0x1031ff60}, +{12400000, DIF_BPF_COEFF3435, 0xef2b0037}, +{12400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 124_quant.dat*/ + + +/*case 12500000:*/ +/* BEGIN - DIF BPF register values from 125_quant.dat*/ +{12500000, DIF_BPF_COEFF01, 0x00010000}, +{12500000, DIF_BPF_COEFF23, 0xfff70000}, +{12500000, DIF_BPF_COEFF45, 0x00220000}, +{12500000, DIF_BPF_COEFF67, 0xffa90000}, +{12500000, DIF_BPF_COEFF89, 0x00b30000}, +{12500000, DIF_BPF_COEFF1011, 0xfec20000}, +{12500000, DIF_BPF_COEFF1213, 0x02000000}, +{12500000, DIF_BPF_COEFF1415, 0xfd030000}, +{12500000, DIF_BPF_COEFF1617, 0x04350000}, +{12500000, DIF_BPF_COEFF1819, 0xfa5e0000}, +{12500000, DIF_BPF_COEFF2021, 0x073b0000}, +{12500000, DIF_BPF_COEFF2223, 0xf7110000}, +{12500000, DIF_BPF_COEFF2425, 0x0aac0000}, +{12500000, DIF_BPF_COEFF2627, 0xf3a40000}, +{12500000, DIF_BPF_COEFF2829, 0x0de70000}, +{12500000, DIF_BPF_COEFF3031, 0xf0c90000}, +{12500000, DIF_BPF_COEFF3233, 0x10360000}, +{12500000, DIF_BPF_COEFF3435, 0xef290000}, +{12500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 125_quant.dat*/ + + +/*case 12600000:*/ +/* BEGIN - DIF BPF register values from 126_quant.dat*/ +{12600000, DIF_BPF_COEFF01, 0x00010001}, +{12600000, DIF_BPF_COEFF23, 0xfff8fff9}, +{12600000, DIF_BPF_COEFF45, 0x001f0015}, +{12600000, DIF_BPF_COEFF67, 0xffafffd3}, +{12600000, DIF_BPF_COEFF89, 0x00a80050}, +{12600000, DIF_BPF_COEFF1011, 0xfed3ff82}, +{12600000, DIF_BPF_COEFF1213, 0x01e900b4}, +{12600000, DIF_BPF_COEFF1415, 0xfd20ff12}, +{12600000, DIF_BPF_COEFF1617, 0x04130128}, +{12600000, DIF_BPF_COEFF1819, 0xfa82fea4}, +{12600000, DIF_BPF_COEFF2021, 0x07150183}, +{12600000, DIF_BPF_COEFF2223, 0xf734fe68}, +{12600000, DIF_BPF_COEFF2425, 0x0a8d0197}, +{12600000, DIF_BPF_COEFF2627, 0xf3bdfe84}, +{12600000, DIF_BPF_COEFF2829, 0x0dd50148}, +{12600000, DIF_BPF_COEFF3031, 0xf0d5ff03}, +{12600000, DIF_BPF_COEFF3233, 0x103100a0}, +{12600000, DIF_BPF_COEFF3435, 0xef2bffc9}, +{12600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 126_quant.dat*/ + + +/*case 12700000:*/ +/* BEGIN - DIF BPF register values from 127_quant.dat*/ +{12700000, DIF_BPF_COEFF01, 0x00000002}, +{12700000, DIF_BPF_COEFF23, 0xfffafff2}, +{12700000, DIF_BPF_COEFF45, 0x00170027}, +{12700000, DIF_BPF_COEFF67, 0xffc1ffab}, +{12700000, DIF_BPF_COEFF89, 0x00880098}, +{12700000, DIF_BPF_COEFF1011, 0xff04ff10}, +{12700000, DIF_BPF_COEFF1213, 0x01a60159}, +{12700000, DIF_BPF_COEFF1415, 0xfd75fe34}, +{12700000, DIF_BPF_COEFF1617, 0x03b00240}, +{12700000, DIF_BPF_COEFF1819, 0xfaeffd58}, +{12700000, DIF_BPF_COEFF2021, 0x06a702f9}, +{12700000, DIF_BPF_COEFF2223, 0xf79dfcda}, +{12700000, DIF_BPF_COEFF2425, 0x0a310326}, +{12700000, DIF_BPF_COEFF2627, 0xf407fd0d}, +{12700000, DIF_BPF_COEFF2829, 0x0d9f028e}, +{12700000, DIF_BPF_COEFF3031, 0xf0f6fe06}, +{12700000, DIF_BPF_COEFF3233, 0x10210140}, +{12700000, DIF_BPF_COEFF3435, 0xef2fff93}, +{12700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 127_quant.dat*/ + + +/*case 12800000:*/ +/* BEGIN - DIF BPF register values from 128_quant.dat*/ +{12800000, DIF_BPF_COEFF01, 0x00000003}, +{12800000, DIF_BPF_COEFF23, 0xfffeffef}, +{12800000, DIF_BPF_COEFF45, 0x000c0034}, +{12800000, DIF_BPF_COEFF67, 0xffdbff8f}, +{12800000, DIF_BPF_COEFF89, 0x005800ce}, +{12800000, DIF_BPF_COEFF1011, 0xff4ffeb6}, +{12800000, DIF_BPF_COEFF1213, 0x013c01e1}, +{12800000, DIF_BPF_COEFF1415, 0xfdfbfd76}, +{12800000, DIF_BPF_COEFF1617, 0x03110337}, +{12800000, DIF_BPF_COEFF1819, 0xfb9dfc2a}, +{12800000, DIF_BPF_COEFF2021, 0x05f40453}, +{12800000, DIF_BPF_COEFF2223, 0xf848fb63}, +{12800000, DIF_BPF_COEFF2425, 0x099904a5}, +{12800000, DIF_BPF_COEFF2627, 0xf482fb9f}, +{12800000, DIF_BPF_COEFF2829, 0x0d4603ce}, +{12800000, DIF_BPF_COEFF3031, 0xf12dfd0c}, +{12800000, DIF_BPF_COEFF3233, 0x100701df}, +{12800000, DIF_BPF_COEFF3435, 0xef36ff5c}, +{12800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 128_quant.dat*/ + + +/*case 12900000:*/ +/* BEGIN - DIF BPF register values from 129_quant.dat*/ +{12900000, DIF_BPF_COEFF01, 0x00000003}, +{12900000, DIF_BPF_COEFF23, 0x0001ffee}, +{12900000, DIF_BPF_COEFF45, 0xffff0038}, +{12900000, DIF_BPF_COEFF67, 0xfffbff82}, +{12900000, DIF_BPF_COEFF89, 0x001d00ec}, +{12900000, DIF_BPF_COEFF1011, 0xffadfe7c}, +{12900000, DIF_BPF_COEFF1213, 0x00b70242}, +{12900000, DIF_BPF_COEFF1415, 0xfea9fce5}, +{12900000, DIF_BPF_COEFF1617, 0x024103ff}, +{12900000, DIF_BPF_COEFF1819, 0xfc85fb2a}, +{12900000, DIF_BPF_COEFF2021, 0x05040587}, +{12900000, DIF_BPF_COEFF2223, 0xf930fa0a}, +{12900000, DIF_BPF_COEFF2425, 0x08ca060e}, +{12900000, DIF_BPF_COEFF2627, 0xf52bfa40}, +{12900000, DIF_BPF_COEFF2829, 0x0ccb0507}, +{12900000, DIF_BPF_COEFF3031, 0xf179fc15}, +{12900000, DIF_BPF_COEFF3233, 0x0fe3027d}, +{12900000, DIF_BPF_COEFF3435, 0xef3fff25}, +{12900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 129_quant.dat*/ + + +/*case 113000000:*/ +/* BEGIN - DIF BPF register values from 130_quant.dat*/ +{13000000, DIF_BPF_COEFF01, 0x00000002}, +{13000000, DIF_BPF_COEFF23, 0x0005fff0}, +{13000000, DIF_BPF_COEFF45, 0xfff20034}, +{13000000, DIF_BPF_COEFF67, 0x001bff85}, +{13000000, DIF_BPF_COEFF89, 0xffdf00f0}, +{13000000, DIF_BPF_COEFF1011, 0x0014fe68}, +{13000000, DIF_BPF_COEFF1213, 0x00200272}, +{13000000, DIF_BPF_COEFF1415, 0xff71fc8b}, +{13000000, DIF_BPF_COEFF1617, 0x014d048d}, +{13000000, DIF_BPF_COEFF1819, 0xfd9afa61}, +{13000000, DIF_BPF_COEFF2021, 0x03e00688}, +{13000000, DIF_BPF_COEFF2223, 0xfa4ef8da}, +{13000000, DIF_BPF_COEFF2425, 0x07c80759}, +{13000000, DIF_BPF_COEFF2627, 0xf600f8f4}, +{13000000, DIF_BPF_COEFF2829, 0x0c2f0637}, +{13000000, DIF_BPF_COEFF3031, 0xf1dbfb22}, +{13000000, DIF_BPF_COEFF3233, 0x0fb4031b}, +{13000000, DIF_BPF_COEFF3435, 0xef4bfeef}, +{13000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 130_quant.dat*/ + + +/*case 13100000:*/ +/* BEGIN - DIF BPF register values from 131_quant.dat*/ +{13100000, DIF_BPF_COEFF01, 0xffff0001}, +{13100000, DIF_BPF_COEFF23, 0x0007fff5}, +{13100000, DIF_BPF_COEFF45, 0xffe70028}, +{13100000, DIF_BPF_COEFF67, 0x0037ff98}, +{13100000, DIF_BPF_COEFF89, 0xffa400d8}, +{13100000, DIF_BPF_COEFF1011, 0x0079fe7c}, +{13100000, DIF_BPF_COEFF1213, 0xff87026f}, +{13100000, DIF_BPF_COEFF1415, 0x0043fc6e}, +{13100000, DIF_BPF_COEFF1617, 0x004404da}, +{13100000, DIF_BPF_COEFF1819, 0xfecef9da}, +{13100000, DIF_BPF_COEFF2021, 0x0294074e}, +{13100000, DIF_BPF_COEFF2223, 0xfb99f7db}, +{13100000, DIF_BPF_COEFF2425, 0x06980881}, +{13100000, DIF_BPF_COEFF2627, 0xf6fef7be}, +{13100000, DIF_BPF_COEFF2829, 0x0b730759}, +{13100000, DIF_BPF_COEFF3031, 0xf251fa33}, +{13100000, DIF_BPF_COEFF3233, 0x0f7b03b8}, +{13100000, DIF_BPF_COEFF3435, 0xef5afeb8}, +{13100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 131_quant.dat*/ + + +/*case 13200000:*/ +/* BEGIN - DIF BPF register values from 132_quant.dat*/ +{13200000, DIF_BPF_COEFF01, 0xffff0000}, +{13200000, DIF_BPF_COEFF23, 0x0008fffc}, +{13200000, DIF_BPF_COEFF45, 0xffe00017}, +{13200000, DIF_BPF_COEFF67, 0x004cffb9}, +{13200000, DIF_BPF_COEFF89, 0xff7500a8}, +{13200000, DIF_BPF_COEFF1011, 0x00d1feb6}, +{13200000, DIF_BPF_COEFF1213, 0xfef90238}, +{13200000, DIF_BPF_COEFF1415, 0x0111fc91}, +{13200000, DIF_BPF_COEFF1617, 0xff3604df}, +{13200000, DIF_BPF_COEFF1819, 0x0012f99b}, +{13200000, DIF_BPF_COEFF2021, 0x012d07d2}, +{13200000, DIF_BPF_COEFF2223, 0xfd07f714}, +{13200000, DIF_BPF_COEFF2425, 0x0542097e}, +{13200000, DIF_BPF_COEFF2627, 0xf81ff6a4}, +{13200000, DIF_BPF_COEFF2829, 0x0a9a086e}, +{13200000, DIF_BPF_COEFF3031, 0xf2dbf94b}, +{13200000, DIF_BPF_COEFF3233, 0x0f380453}, +{13200000, DIF_BPF_COEFF3435, 0xef6cfe82}, +{13200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 132_quant.dat*/ + + +/*case 13300000:*/ +/* BEGIN - DIF BPF register values from 133_quant.dat*/ +{13300000, DIF_BPF_COEFF01, 0xffffffff}, +{13300000, DIF_BPF_COEFF23, 0x00080003}, +{13300000, DIF_BPF_COEFF45, 0xffde0001}, +{13300000, DIF_BPF_COEFF67, 0x0056ffe3}, +{13300000, DIF_BPF_COEFF89, 0xff570064}, +{13300000, DIF_BPF_COEFF1011, 0x0113ff10}, +{13300000, DIF_BPF_COEFF1213, 0xfe8201d2}, +{13300000, DIF_BPF_COEFF1415, 0x01cafcf0}, +{13300000, DIF_BPF_COEFF1617, 0xfe35049e}, +{13300000, DIF_BPF_COEFF1819, 0x0155f9a6}, +{13300000, DIF_BPF_COEFF2021, 0xffba080e}, +{13300000, DIF_BPF_COEFF2223, 0xfe8cf689}, +{13300000, DIF_BPF_COEFF2425, 0x03ce0a4e}, +{13300000, DIF_BPF_COEFF2627, 0xf961f5a8}, +{13300000, DIF_BPF_COEFF2829, 0x09a50971}, +{13300000, DIF_BPF_COEFF3031, 0xf379f869}, +{13300000, DIF_BPF_COEFF3233, 0x0eeb04ec}, +{13300000, DIF_BPF_COEFF3435, 0xef80fe4b}, +{13300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 133_quant.dat*/ + + +/*case 13400000:*/ +/* BEGIN - DIF BPF register values from 134_quant.dat*/ +{13400000, DIF_BPF_COEFF01, 0x0000fffe}, +{13400000, DIF_BPF_COEFF23, 0x0007000a}, +{13400000, DIF_BPF_COEFF45, 0xffe2ffec}, +{13400000, DIF_BPF_COEFF67, 0x00540012}, +{13400000, DIF_BPF_COEFF89, 0xff4e0015}, +{13400000, DIF_BPF_COEFF1011, 0x0137ff82}, +{13400000, DIF_BPF_COEFF1213, 0xfe2e0145}, +{13400000, DIF_BPF_COEFF1415, 0x0260fd86}, +{13400000, DIF_BPF_COEFF1617, 0xfd51041a}, +{13400000, DIF_BPF_COEFF1819, 0x0287f9fb}, +{13400000, DIF_BPF_COEFF2021, 0xfe4a0802}, +{13400000, DIF_BPF_COEFF2223, 0x001df63f}, +{13400000, DIF_BPF_COEFF2425, 0x02430aeb}, +{13400000, DIF_BPF_COEFF2627, 0xfabdf4ce}, +{13400000, DIF_BPF_COEFF2829, 0x08970a62}, +{13400000, DIF_BPF_COEFF3031, 0xf428f78f}, +{13400000, DIF_BPF_COEFF3233, 0x0e950584}, +{13400000, DIF_BPF_COEFF3435, 0xef97fe15}, +{13400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 134_quant.dat*/ + + +/*case 13500000:*/ +/* BEGIN - DIF BPF register values from 135_quant.dat*/ +{13500000, DIF_BPF_COEFF01, 0x0000fffd}, +{13500000, DIF_BPF_COEFF23, 0x0004000f}, +{13500000, DIF_BPF_COEFF45, 0xffeaffda}, +{13500000, DIF_BPF_COEFF67, 0x0046003d}, +{13500000, DIF_BPF_COEFF89, 0xff5affc4}, +{13500000, DIF_BPF_COEFF1011, 0x013b0000}, +{13500000, DIF_BPF_COEFF1213, 0xfe04009d}, +{13500000, DIF_BPF_COEFF1415, 0x02c8fe48}, +{13500000, DIF_BPF_COEFF1617, 0xfc99035a}, +{13500000, DIF_BPF_COEFF1819, 0x0397fa96}, +{13500000, DIF_BPF_COEFF2021, 0xfcec07ad}, +{13500000, DIF_BPF_COEFF2223, 0x01adf637}, +{13500000, DIF_BPF_COEFF2425, 0x00ac0b53}, +{13500000, DIF_BPF_COEFF2627, 0xfc2ef419}, +{13500000, DIF_BPF_COEFF2829, 0x07730b3e}, +{13500000, DIF_BPF_COEFF3031, 0xf4e9f6bd}, +{13500000, DIF_BPF_COEFF3233, 0x0e35061a}, +{13500000, DIF_BPF_COEFF3435, 0xefb1fddf}, +{13500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 135_quant.dat*/ + + +/*case 13600000:*/ +/* BEGIN - DIF BPF register values from 136_quant.dat*/ +{13600000, DIF_BPF_COEFF01, 0x0000fffd}, +{13600000, DIF_BPF_COEFF23, 0x00000012}, +{13600000, DIF_BPF_COEFF45, 0xfff6ffcd}, +{13600000, DIF_BPF_COEFF67, 0x002f0061}, +{13600000, DIF_BPF_COEFF89, 0xff7bff79}, +{13600000, DIF_BPF_COEFF1011, 0x011e007e}, +{13600000, DIF_BPF_COEFF1213, 0xfe08ffe8}, +{13600000, DIF_BPF_COEFF1415, 0x02f9ff28}, +{13600000, DIF_BPF_COEFF1617, 0xfc17026a}, +{13600000, DIF_BPF_COEFF1819, 0x0479fb70}, +{13600000, DIF_BPF_COEFF2021, 0xfbad0713}, +{13600000, DIF_BPF_COEFF2223, 0x032ff672}, +{13600000, DIF_BPF_COEFF2425, 0xff100b83}, +{13600000, DIF_BPF_COEFF2627, 0xfdaff38b}, +{13600000, DIF_BPF_COEFF2829, 0x063c0c04}, +{13600000, DIF_BPF_COEFF3031, 0xf5baf5f5}, +{13600000, DIF_BPF_COEFF3233, 0x0dcc06ae}, +{13600000, DIF_BPF_COEFF3435, 0xefcdfda8}, +{13600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 136_quant.dat*/ + + +/*case 13700000:*/ +/* BEGIN - DIF BPF register values from 137_quant.dat*/ +{13700000, DIF_BPF_COEFF01, 0x0000fffd}, +{13700000, DIF_BPF_COEFF23, 0xfffd0012}, +{13700000, DIF_BPF_COEFF45, 0x0004ffc8}, +{13700000, DIF_BPF_COEFF67, 0x00100078}, +{13700000, DIF_BPF_COEFF89, 0xffacff3e}, +{13700000, DIF_BPF_COEFF1011, 0x00e200f0}, +{13700000, DIF_BPF_COEFF1213, 0xfe39ff35}, +{13700000, DIF_BPF_COEFF1415, 0x02f10017}, +{13700000, DIF_BPF_COEFF1617, 0xfbd30156}, +{13700000, DIF_BPF_COEFF1819, 0x0521fc7f}, +{13700000, DIF_BPF_COEFF2021, 0xfa9c0638}, +{13700000, DIF_BPF_COEFF2223, 0x0499f6ee}, +{13700000, DIF_BPF_COEFF2425, 0xfd7a0b7c}, +{13700000, DIF_BPF_COEFF2627, 0xff39f325}, +{13700000, DIF_BPF_COEFF2829, 0x04f40cb3}, +{13700000, DIF_BPF_COEFF3031, 0xf69af537}, +{13700000, DIF_BPF_COEFF3233, 0x0d5a073f}, +{13700000, DIF_BPF_COEFF3435, 0xefecfd72}, +{13700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 137_quant.dat*/ + + +/*case 13800000:*/ +/* BEGIN - DIF BPF register values from 138_quant.dat*/ +{13800000, DIF_BPF_COEFF01, 0x0001fffe}, +{13800000, DIF_BPF_COEFF23, 0xfffa000e}, +{13800000, DIF_BPF_COEFF45, 0x0011ffcb}, +{13800000, DIF_BPF_COEFF67, 0xfff0007f}, +{13800000, DIF_BPF_COEFF89, 0xffe7ff19}, +{13800000, DIF_BPF_COEFF1011, 0x008f014a}, +{13800000, DIF_BPF_COEFF1213, 0xfe94fe93}, +{13800000, DIF_BPF_COEFF1415, 0x02b00105}, +{13800000, DIF_BPF_COEFF1617, 0xfbd3002f}, +{13800000, DIF_BPF_COEFF1819, 0x0585fdb7}, +{13800000, DIF_BPF_COEFF2021, 0xf9c10525}, +{13800000, DIF_BPF_COEFF2223, 0x05def7a8}, +{13800000, DIF_BPF_COEFF2425, 0xfbf20b3c}, +{13800000, DIF_BPF_COEFF2627, 0x00c7f2e9}, +{13800000, DIF_BPF_COEFF2829, 0x03a00d48}, +{13800000, DIF_BPF_COEFF3031, 0xf787f484}, +{13800000, DIF_BPF_COEFF3233, 0x0cdf07cd}, +{13800000, DIF_BPF_COEFF3435, 0xf00dfd3c}, +{13800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 138_quant.dat*/ + + +/*case 13900000:*/ +/* BEGIN - DIF BPF register values from 139_quant.dat*/ +{13900000, DIF_BPF_COEFF01, 0x00010000}, +{13900000, DIF_BPF_COEFF23, 0xfff80008}, +{13900000, DIF_BPF_COEFF45, 0x001bffd7}, +{13900000, DIF_BPF_COEFF67, 0xffd10076}, +{13900000, DIF_BPF_COEFF89, 0x0026ff0e}, +{13900000, DIF_BPF_COEFF1011, 0x002c0184}, +{13900000, DIF_BPF_COEFF1213, 0xff0ffe10}, +{13900000, DIF_BPF_COEFF1415, 0x023b01e0}, +{13900000, DIF_BPF_COEFF1617, 0xfc17ff06}, +{13900000, DIF_BPF_COEFF1819, 0x05a2ff09}, +{13900000, DIF_BPF_COEFF2021, 0xf92703e4}, +{13900000, DIF_BPF_COEFF2223, 0x06f4f89b}, +{13900000, DIF_BPF_COEFF2425, 0xfa820ac5}, +{13900000, DIF_BPF_COEFF2627, 0x0251f2d9}, +{13900000, DIF_BPF_COEFF2829, 0x02430dc3}, +{13900000, DIF_BPF_COEFF3031, 0xf881f3dc}, +{13900000, DIF_BPF_COEFF3233, 0x0c5c0859}, +{13900000, DIF_BPF_COEFF3435, 0xf031fd06}, +{13900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 139_quant.dat*/ + + +/*case 14000000:*/ +/* BEGIN - DIF BPF register values from 140_quant.dat*/ +{14000000, DIF_BPF_COEFF01, 0x00010001}, +{14000000, DIF_BPF_COEFF23, 0xfff80001}, +{14000000, DIF_BPF_COEFF45, 0x0021ffe8}, +{14000000, DIF_BPF_COEFF67, 0xffba005d}, +{14000000, DIF_BPF_COEFF89, 0x0060ff1f}, +{14000000, DIF_BPF_COEFF1011, 0xffc40198}, +{14000000, DIF_BPF_COEFF1213, 0xffa0fdb5}, +{14000000, DIF_BPF_COEFF1415, 0x019a029a}, +{14000000, DIF_BPF_COEFF1617, 0xfc99fdea}, +{14000000, DIF_BPF_COEFF1819, 0x05750067}, +{14000000, DIF_BPF_COEFF2021, 0xf8d4027f}, +{14000000, DIF_BPF_COEFF2223, 0x07d4f9c0}, +{14000000, DIF_BPF_COEFF2425, 0xf9320a1a}, +{14000000, DIF_BPF_COEFF2627, 0x03d2f2f3}, +{14000000, DIF_BPF_COEFF2829, 0x00df0e22}, +{14000000, DIF_BPF_COEFF3031, 0xf986f341}, +{14000000, DIF_BPF_COEFF3233, 0x0bd108e2}, +{14000000, DIF_BPF_COEFF3435, 0xf058fcd1}, +{14000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 140_quant.dat*/ + + +/*case 14100000:*/ +/* BEGIN - DIF BPF register values from 141_quant.dat*/ +{14100000, DIF_BPF_COEFF01, 0x00000002}, +{14100000, DIF_BPF_COEFF23, 0xfff9fffa}, +{14100000, DIF_BPF_COEFF45, 0x0021fffd}, +{14100000, DIF_BPF_COEFF67, 0xffac0038}, +{14100000, DIF_BPF_COEFF89, 0x008eff4a}, +{14100000, DIF_BPF_COEFF1011, 0xff630184}, +{14100000, DIF_BPF_COEFF1213, 0x003afd8b}, +{14100000, DIF_BPF_COEFF1415, 0x00da0326}, +{14100000, DIF_BPF_COEFF1617, 0xfd51fced}, +{14100000, DIF_BPF_COEFF1819, 0x050101c0}, +{14100000, DIF_BPF_COEFF2021, 0xf8cb0103}, +{14100000, DIF_BPF_COEFF2223, 0x0876fb10}, +{14100000, DIF_BPF_COEFF2425, 0xf80a093e}, +{14100000, DIF_BPF_COEFF2627, 0x0543f338}, +{14100000, DIF_BPF_COEFF2829, 0xff7a0e66}, +{14100000, DIF_BPF_COEFF3031, 0xfa94f2b2}, +{14100000, DIF_BPF_COEFF3233, 0x0b3f0967}, +{14100000, DIF_BPF_COEFF3435, 0xf081fc9b}, +{14100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 141_quant.dat*/ + + +/*case 14200000:*/ +/* BEGIN - DIF BPF register values from 142_quant.dat*/ +{14200000, DIF_BPF_COEFF01, 0x00000003}, +{14200000, DIF_BPF_COEFF23, 0xfffbfff3}, +{14200000, DIF_BPF_COEFF45, 0x001d0013}, +{14200000, DIF_BPF_COEFF67, 0xffaa000b}, +{14200000, DIF_BPF_COEFF89, 0x00aaff89}, +{14200000, DIF_BPF_COEFF1011, 0xff13014a}, +{14200000, DIF_BPF_COEFF1213, 0x00cefd95}, +{14200000, DIF_BPF_COEFF1415, 0x000a037b}, +{14200000, DIF_BPF_COEFF1617, 0xfe35fc1d}, +{14200000, DIF_BPF_COEFF1819, 0x044c0305}, +{14200000, DIF_BPF_COEFF2021, 0xf90cff7e}, +{14200000, DIF_BPF_COEFF2223, 0x08d5fc81}, +{14200000, DIF_BPF_COEFF2425, 0xf7100834}, +{14200000, DIF_BPF_COEFF2627, 0x069ff3a7}, +{14200000, DIF_BPF_COEFF2829, 0xfe160e8d}, +{14200000, DIF_BPF_COEFF3031, 0xfbaaf231}, +{14200000, DIF_BPF_COEFF3233, 0x0aa509e9}, +{14200000, DIF_BPF_COEFF3435, 0xf0adfc65}, +{14200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 142_quant.dat*/ + + +/*case 14300000:*/ +/* BEGIN - DIF BPF register values from 143_quant.dat*/ +{14300000, DIF_BPF_COEFF01, 0x00000003}, +{14300000, DIF_BPF_COEFF23, 0xffffffef}, +{14300000, DIF_BPF_COEFF45, 0x00140025}, +{14300000, DIF_BPF_COEFF67, 0xffb4ffdd}, +{14300000, DIF_BPF_COEFF89, 0x00b2ffd6}, +{14300000, DIF_BPF_COEFF1011, 0xfedb00f0}, +{14300000, DIF_BPF_COEFF1213, 0x0150fdd3}, +{14300000, DIF_BPF_COEFF1415, 0xff380391}, +{14300000, DIF_BPF_COEFF1617, 0xff36fb85}, +{14300000, DIF_BPF_COEFF1819, 0x035e0426}, +{14300000, DIF_BPF_COEFF2021, 0xf994fdfe}, +{14300000, DIF_BPF_COEFF2223, 0x08eefe0b}, +{14300000, DIF_BPF_COEFF2425, 0xf6490702}, +{14300000, DIF_BPF_COEFF2627, 0x07e1f43e}, +{14300000, DIF_BPF_COEFF2829, 0xfcb60e97}, +{14300000, DIF_BPF_COEFF3031, 0xfcc6f1be}, +{14300000, DIF_BPF_COEFF3233, 0x0a040a67}, +{14300000, DIF_BPF_COEFF3435, 0xf0dbfc30}, +{14300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 143_quant.dat*/ + + +/*case 14400000:*/ +/* BEGIN - DIF BPF register values from 144_quant.dat*/ +{14400000, DIF_BPF_COEFF01, 0x00000003}, +{14400000, DIF_BPF_COEFF23, 0x0002ffee}, +{14400000, DIF_BPF_COEFF45, 0x00070033}, +{14400000, DIF_BPF_COEFF67, 0xffc9ffb4}, +{14400000, DIF_BPF_COEFF89, 0x00a40027}, +{14400000, DIF_BPF_COEFF1011, 0xfec3007e}, +{14400000, DIF_BPF_COEFF1213, 0x01b4fe3f}, +{14400000, DIF_BPF_COEFF1415, 0xfe760369}, +{14400000, DIF_BPF_COEFF1617, 0x0044fb2e}, +{14400000, DIF_BPF_COEFF1819, 0x02450518}, +{14400000, DIF_BPF_COEFF2021, 0xfa5ffc90}, +{14400000, DIF_BPF_COEFF2223, 0x08c1ffa1}, +{14400000, DIF_BPF_COEFF2425, 0xf5bc05ae}, +{14400000, DIF_BPF_COEFF2627, 0x0902f4fc}, +{14400000, DIF_BPF_COEFF2829, 0xfb600e85}, +{14400000, DIF_BPF_COEFF3031, 0xfde7f15a}, +{14400000, DIF_BPF_COEFF3233, 0x095d0ae2}, +{14400000, DIF_BPF_COEFF3435, 0xf10cfbfb}, +{14400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 144_quant.dat*/ + + +/*case 14500000:*/ +/* BEGIN - DIF BPF register values from 145_quant.dat*/ +{14500000, DIF_BPF_COEFF01, 0xffff0002}, +{14500000, DIF_BPF_COEFF23, 0x0005ffef}, +{14500000, DIF_BPF_COEFF45, 0xfffa0038}, +{14500000, DIF_BPF_COEFF67, 0xffe5ff95}, +{14500000, DIF_BPF_COEFF89, 0x00820074}, +{14500000, DIF_BPF_COEFF1011, 0xfecc0000}, +{14500000, DIF_BPF_COEFF1213, 0x01f0fed0}, +{14500000, DIF_BPF_COEFF1415, 0xfdd20304}, +{14500000, DIF_BPF_COEFF1617, 0x014dfb1d}, +{14500000, DIF_BPF_COEFF1819, 0x010e05ce}, +{14500000, DIF_BPF_COEFF2021, 0xfb64fb41}, +{14500000, DIF_BPF_COEFF2223, 0x084e013b}, +{14500000, DIF_BPF_COEFF2425, 0xf569043e}, +{14500000, DIF_BPF_COEFF2627, 0x0a00f5dd}, +{14500000, DIF_BPF_COEFF2829, 0xfa150e55}, +{14500000, DIF_BPF_COEFF3031, 0xff0bf104}, +{14500000, DIF_BPF_COEFF3233, 0x08b00b59}, +{14500000, DIF_BPF_COEFF3435, 0xf13ffbc6}, +{14500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 145_quant.dat*/ + + +/*case 14600000:*/ +/* BEGIN - DIF BPF register values from 146_quant.dat*/ +{14600000, DIF_BPF_COEFF01, 0xffff0001}, +{14600000, DIF_BPF_COEFF23, 0x0008fff4}, +{14600000, DIF_BPF_COEFF45, 0xffed0035}, +{14600000, DIF_BPF_COEFF67, 0x0005ff83}, +{14600000, DIF_BPF_COEFF89, 0x005000b4}, +{14600000, DIF_BPF_COEFF1011, 0xfef6ff82}, +{14600000, DIF_BPF_COEFF1213, 0x01ffff7a}, +{14600000, DIF_BPF_COEFF1415, 0xfd580269}, +{14600000, DIF_BPF_COEFF1617, 0x0241fb53}, +{14600000, DIF_BPF_COEFF1819, 0xffca0640}, +{14600000, DIF_BPF_COEFF2021, 0xfc99fa1e}, +{14600000, DIF_BPF_COEFF2223, 0x079a02cb}, +{14600000, DIF_BPF_COEFF2425, 0xf55502ba}, +{14600000, DIF_BPF_COEFF2627, 0x0ad5f6e0}, +{14600000, DIF_BPF_COEFF2829, 0xf8d90e0a}, +{14600000, DIF_BPF_COEFF3031, 0x0031f0bd}, +{14600000, DIF_BPF_COEFF3233, 0x07fd0bcb}, +{14600000, DIF_BPF_COEFF3435, 0xf174fb91}, +{14600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 146_quant.dat*/ + + +/*case 14700000:*/ +/* BEGIN - DIF BPF register values from 147_quant.dat*/ +{14700000, DIF_BPF_COEFF01, 0xffffffff}, +{14700000, DIF_BPF_COEFF23, 0x0009fffb}, +{14700000, DIF_BPF_COEFF45, 0xffe4002a}, +{14700000, DIF_BPF_COEFF67, 0x0025ff82}, +{14700000, DIF_BPF_COEFF89, 0x001400e0}, +{14700000, DIF_BPF_COEFF1011, 0xff3cff10}, +{14700000, DIF_BPF_COEFF1213, 0x01e10030}, +{14700000, DIF_BPF_COEFF1415, 0xfd1201a4}, +{14700000, DIF_BPF_COEFF1617, 0x0311fbcd}, +{14700000, DIF_BPF_COEFF1819, 0xfe88066a}, +{14700000, DIF_BPF_COEFF2021, 0xfdf1f92f}, +{14700000, DIF_BPF_COEFF2223, 0x06aa0449}, +{14700000, DIF_BPF_COEFF2425, 0xf57e0128}, +{14700000, DIF_BPF_COEFF2627, 0x0b7ef801}, +{14700000, DIF_BPF_COEFF2829, 0xf7b00da2}, +{14700000, DIF_BPF_COEFF3031, 0x0156f086}, +{14700000, DIF_BPF_COEFF3233, 0x07450c39}, +{14700000, DIF_BPF_COEFF3435, 0xf1acfb5c}, +{14700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 147_quant.dat*/ + + +/*case 14800000:*/ +/* BEGIN - DIF BPF register values from 148_quant.dat*/ +{14800000, DIF_BPF_COEFF01, 0x0000fffe}, +{14800000, DIF_BPF_COEFF23, 0x00080002}, +{14800000, DIF_BPF_COEFF45, 0xffdf0019}, +{14800000, DIF_BPF_COEFF67, 0x003fff92}, +{14800000, DIF_BPF_COEFF89, 0xffd600f1}, +{14800000, DIF_BPF_COEFF1011, 0xff96feb6}, +{14800000, DIF_BPF_COEFF1213, 0x019700e1}, +{14800000, DIF_BPF_COEFF1415, 0xfd0500c2}, +{14800000, DIF_BPF_COEFF1617, 0x03b0fc84}, +{14800000, DIF_BPF_COEFF1819, 0xfd590649}, +{14800000, DIF_BPF_COEFF2021, 0xff5df87f}, +{14800000, DIF_BPF_COEFF2223, 0x058505aa}, +{14800000, DIF_BPF_COEFF2425, 0xf5e4ff91}, +{14800000, DIF_BPF_COEFF2627, 0x0bf9f93c}, +{14800000, DIF_BPF_COEFF2829, 0xf69d0d20}, +{14800000, DIF_BPF_COEFF3031, 0x0279f05e}, +{14800000, DIF_BPF_COEFF3233, 0x06880ca3}, +{14800000, DIF_BPF_COEFF3435, 0xf1e6fb28}, +{14800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 148_quant.dat*/ + + +/*case 14900000:*/ +/* BEGIN - DIF BPF register values from 149_quant.dat*/ +{14900000, DIF_BPF_COEFF01, 0x0000fffd}, +{14900000, DIF_BPF_COEFF23, 0x00060009}, +{14900000, DIF_BPF_COEFF45, 0xffdf0004}, +{14900000, DIF_BPF_COEFF67, 0x0051ffb0}, +{14900000, DIF_BPF_COEFF89, 0xff9d00e8}, +{14900000, DIF_BPF_COEFF1011, 0xfffcfe7c}, +{14900000, DIF_BPF_COEFF1213, 0x01280180}, +{14900000, DIF_BPF_COEFF1415, 0xfd32ffd2}, +{14900000, DIF_BPF_COEFF1617, 0x0413fd6e}, +{14900000, DIF_BPF_COEFF1819, 0xfc4d05df}, +{14900000, DIF_BPF_COEFF2021, 0x00d1f812}, +{14900000, DIF_BPF_COEFF2223, 0x043506e4}, +{14900000, DIF_BPF_COEFF2425, 0xf685fdfb}, +{14900000, DIF_BPF_COEFF2627, 0x0c43fa8d}, +{14900000, DIF_BPF_COEFF2829, 0xf5a10c83}, +{14900000, DIF_BPF_COEFF3031, 0x0399f046}, +{14900000, DIF_BPF_COEFF3233, 0x05c70d08}, +{14900000, DIF_BPF_COEFF3435, 0xf222faf3}, +{14900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 149_quant.dat*/ + + +/*case 15000000:*/ +/* BEGIN - DIF BPF register values from 150_quant.dat*/ +{15000000, DIF_BPF_COEFF01, 0x0000fffd}, +{15000000, DIF_BPF_COEFF23, 0x0003000f}, +{15000000, DIF_BPF_COEFF45, 0xffe5ffef}, +{15000000, DIF_BPF_COEFF67, 0x0057ffd9}, +{15000000, DIF_BPF_COEFF89, 0xff7000c4}, +{15000000, DIF_BPF_COEFF1011, 0x0062fe68}, +{15000000, DIF_BPF_COEFF1213, 0x009e01ff}, +{15000000, DIF_BPF_COEFF1415, 0xfd95fee6}, +{15000000, DIF_BPF_COEFF1617, 0x0435fe7d}, +{15000000, DIF_BPF_COEFF1819, 0xfb710530}, +{15000000, DIF_BPF_COEFF2021, 0x023cf7ee}, +{15000000, DIF_BPF_COEFF2223, 0x02c307ef}, +{15000000, DIF_BPF_COEFF2425, 0xf75efc70}, +{15000000, DIF_BPF_COEFF2627, 0x0c5cfbef}, +{15000000, DIF_BPF_COEFF2829, 0xf4c10bce}, +{15000000, DIF_BPF_COEFF3031, 0x04b3f03f}, +{15000000, DIF_BPF_COEFF3233, 0x05030d69}, +{15000000, DIF_BPF_COEFF3435, 0xf261fabf}, +{15000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 150_quant.dat*/ + + +/*case 15100000:*/ +/* BEGIN - DIF BPF register values from 151_quant.dat*/ +{15100000, DIF_BPF_COEFF01, 0x0000fffd}, +{15100000, DIF_BPF_COEFF23, 0xffff0012}, +{15100000, DIF_BPF_COEFF45, 0xffefffdc}, +{15100000, DIF_BPF_COEFF67, 0x00510006}, +{15100000, DIF_BPF_COEFF89, 0xff540089}, +{15100000, DIF_BPF_COEFF1011, 0x00befe7c}, +{15100000, DIF_BPF_COEFF1213, 0x00060253}, +{15100000, DIF_BPF_COEFF1415, 0xfe27fe0d}, +{15100000, DIF_BPF_COEFF1617, 0x0413ffa2}, +{15100000, DIF_BPF_COEFF1819, 0xfad10446}, +{15100000, DIF_BPF_COEFF2021, 0x0390f812}, +{15100000, DIF_BPF_COEFF2223, 0x013b08c3}, +{15100000, DIF_BPF_COEFF2425, 0xf868faf6}, +{15100000, DIF_BPF_COEFF2627, 0x0c43fd5f}, +{15100000, DIF_BPF_COEFF2829, 0xf3fd0b02}, +{15100000, DIF_BPF_COEFF3031, 0x05c7f046}, +{15100000, DIF_BPF_COEFF3233, 0x043b0dc4}, +{15100000, DIF_BPF_COEFF3435, 0xf2a1fa8b}, +{15100000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 151_quant.dat*/ + + +/*case 15200000:*/ +/* BEGIN - DIF BPF register values from 152_quant.dat*/ +{15200000, DIF_BPF_COEFF01, 0x0001fffe}, +{15200000, DIF_BPF_COEFF23, 0xfffc0012}, +{15200000, DIF_BPF_COEFF45, 0xfffbffce}, +{15200000, DIF_BPF_COEFF67, 0x003f0033}, +{15200000, DIF_BPF_COEFF89, 0xff4e003f}, +{15200000, DIF_BPF_COEFF1011, 0x0106feb6}, +{15200000, DIF_BPF_COEFF1213, 0xff6e0276}, +{15200000, DIF_BPF_COEFF1415, 0xfeddfd56}, +{15200000, DIF_BPF_COEFF1617, 0x03b000cc}, +{15200000, DIF_BPF_COEFF1819, 0xfa740329}, +{15200000, DIF_BPF_COEFF2021, 0x04bff87f}, +{15200000, DIF_BPF_COEFF2223, 0xffaa095d}, +{15200000, DIF_BPF_COEFF2425, 0xf99ef995}, +{15200000, DIF_BPF_COEFF2627, 0x0bf9fed8}, +{15200000, DIF_BPF_COEFF2829, 0xf3590a1f}, +{15200000, DIF_BPF_COEFF3031, 0x06d2f05e}, +{15200000, DIF_BPF_COEFF3233, 0x03700e1b}, +{15200000, DIF_BPF_COEFF3435, 0xf2e4fa58}, +{15200000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 152_quant.dat*/ + + +/*case 115300000:*/ +/* BEGIN - DIF BPF register values from 153_quant.dat*/ +{15300000, DIF_BPF_COEFF01, 0x0001ffff}, +{15300000, DIF_BPF_COEFF23, 0xfff9000f}, +{15300000, DIF_BPF_COEFF45, 0x0009ffc8}, +{15300000, DIF_BPF_COEFF67, 0x00250059}, +{15300000, DIF_BPF_COEFF89, 0xff5effee}, +{15300000, DIF_BPF_COEFF1011, 0x0132ff10}, +{15300000, DIF_BPF_COEFF1213, 0xfee30265}, +{15300000, DIF_BPF_COEFF1415, 0xffaafccf}, +{15300000, DIF_BPF_COEFF1617, 0x031101eb}, +{15300000, DIF_BPF_COEFF1819, 0xfa6001e8}, +{15300000, DIF_BPF_COEFF2021, 0x05bdf92f}, +{15300000, DIF_BPF_COEFF2223, 0xfe1b09b6}, +{15300000, DIF_BPF_COEFF2425, 0xfafaf852}, +{15300000, DIF_BPF_COEFF2627, 0x0b7e0055}, +{15300000, DIF_BPF_COEFF2829, 0xf2d50929}, +{15300000, DIF_BPF_COEFF3031, 0x07d3f086}, +{15300000, DIF_BPF_COEFF3233, 0x02a30e6c}, +{15300000, DIF_BPF_COEFF3435, 0xf329fa24}, +{15300000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 153_quant.dat*/ + + +/*case 115400000:*/ +/* BEGIN - DIF BPF register values from 154_quant.dat*/ +{15400000, DIF_BPF_COEFF01, 0x00010001}, +{15400000, DIF_BPF_COEFF23, 0xfff80009}, +{15400000, DIF_BPF_COEFF45, 0x0015ffca}, +{15400000, DIF_BPF_COEFF67, 0x00050074}, +{15400000, DIF_BPF_COEFF89, 0xff81ff9f}, +{15400000, DIF_BPF_COEFF1011, 0x013dff82}, +{15400000, DIF_BPF_COEFF1213, 0xfe710221}, +{15400000, DIF_BPF_COEFF1415, 0x007cfc80}, +{15400000, DIF_BPF_COEFF1617, 0x024102ed}, +{15400000, DIF_BPF_COEFF1819, 0xfa940090}, +{15400000, DIF_BPF_COEFF2021, 0x0680fa1e}, +{15400000, DIF_BPF_COEFF2223, 0xfc9b09cd}, +{15400000, DIF_BPF_COEFF2425, 0xfc73f736}, +{15400000, DIF_BPF_COEFF2627, 0x0ad501d0}, +{15400000, DIF_BPF_COEFF2829, 0xf2740820}, +{15400000, DIF_BPF_COEFF3031, 0x08c9f0bd}, +{15400000, DIF_BPF_COEFF3233, 0x01d40eb9}, +{15400000, DIF_BPF_COEFF3435, 0xf371f9f1}, +{15400000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 154_quant.dat*/ + + +/*case 115500000:*/ +/* BEGIN - DIF BPF register values from 155_quant.dat*/ +{15500000, DIF_BPF_COEFF01, 0x00000002}, +{15500000, DIF_BPF_COEFF23, 0xfff80002}, +{15500000, DIF_BPF_COEFF45, 0x001effd5}, +{15500000, DIF_BPF_COEFF67, 0xffe5007f}, +{15500000, DIF_BPF_COEFF89, 0xffb4ff5b}, +{15500000, DIF_BPF_COEFF1011, 0x01280000}, +{15500000, DIF_BPF_COEFF1213, 0xfe2401b0}, +{15500000, DIF_BPF_COEFF1415, 0x0146fc70}, +{15500000, DIF_BPF_COEFF1617, 0x014d03c6}, +{15500000, DIF_BPF_COEFF1819, 0xfb10ff32}, +{15500000, DIF_BPF_COEFF2021, 0x0701fb41}, +{15500000, DIF_BPF_COEFF2223, 0xfb3709a1}, +{15500000, DIF_BPF_COEFF2425, 0xfe00f644}, +{15500000, DIF_BPF_COEFF2627, 0x0a000345}, +{15500000, DIF_BPF_COEFF2829, 0xf2350708}, +{15500000, DIF_BPF_COEFF3031, 0x09b2f104}, +{15500000, DIF_BPF_COEFF3233, 0x01050eff}, +{15500000, DIF_BPF_COEFF3435, 0xf3baf9be}, +{15500000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 155_quant.dat*/ + + +/*case 115600000:*/ +/* BEGIN - DIF BPF register values from 156_quant.dat*/ +{15600000, DIF_BPF_COEFF01, 0x00000003}, +{15600000, DIF_BPF_COEFF23, 0xfff9fffb}, +{15600000, DIF_BPF_COEFF45, 0x0022ffe6}, +{15600000, DIF_BPF_COEFF67, 0xffc9007a}, +{15600000, DIF_BPF_COEFF89, 0xfff0ff29}, +{15600000, DIF_BPF_COEFF1011, 0x00f2007e}, +{15600000, DIF_BPF_COEFF1213, 0xfe01011b}, +{15600000, DIF_BPF_COEFF1415, 0x01f6fc9e}, +{15600000, DIF_BPF_COEFF1617, 0x00440467}, +{15600000, DIF_BPF_COEFF1819, 0xfbccfdde}, +{15600000, DIF_BPF_COEFF2021, 0x0738fc90}, +{15600000, DIF_BPF_COEFF2223, 0xf9f70934}, +{15600000, DIF_BPF_COEFF2425, 0xff99f582}, +{15600000, DIF_BPF_COEFF2627, 0x090204b0}, +{15600000, DIF_BPF_COEFF2829, 0xf21a05e1}, +{15600000, DIF_BPF_COEFF3031, 0x0a8df15a}, +{15600000, DIF_BPF_COEFF3233, 0x00340f41}, +{15600000, DIF_BPF_COEFF3435, 0xf405f98b}, +{15600000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 156_quant.dat*/ + + +/*case 115700000:*/ +/* BEGIN - DIF BPF register values from 157_quant.dat*/ +{15700000, DIF_BPF_COEFF01, 0x00000003}, +{15700000, DIF_BPF_COEFF23, 0xfffcfff4}, +{15700000, DIF_BPF_COEFF45, 0x0020fffa}, +{15700000, DIF_BPF_COEFF67, 0xffb40064}, +{15700000, DIF_BPF_COEFF89, 0x002fff11}, +{15700000, DIF_BPF_COEFF1011, 0x00a400f0}, +{15700000, DIF_BPF_COEFF1213, 0xfe0d006e}, +{15700000, DIF_BPF_COEFF1415, 0x0281fd09}, +{15700000, DIF_BPF_COEFF1617, 0xff3604c9}, +{15700000, DIF_BPF_COEFF1819, 0xfcbffca2}, +{15700000, DIF_BPF_COEFF2021, 0x0726fdfe}, +{15700000, DIF_BPF_COEFF2223, 0xf8e80888}, +{15700000, DIF_BPF_COEFF2425, 0x0134f4f3}, +{15700000, DIF_BPF_COEFF2627, 0x07e1060c}, +{15700000, DIF_BPF_COEFF2829, 0xf22304af}, +{15700000, DIF_BPF_COEFF3031, 0x0b59f1be}, +{15700000, DIF_BPF_COEFF3233, 0xff640f7d}, +{15700000, DIF_BPF_COEFF3435, 0xf452f959}, +{15700000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 157_quant.dat*/ + + +/*case 115800000:*/ +/* BEGIN - DIF BPF register values from 158_quant.dat*/ +{15800000, DIF_BPF_COEFF01, 0x00000003}, +{15800000, DIF_BPF_COEFF23, 0x0000fff0}, +{15800000, DIF_BPF_COEFF45, 0x001a0010}, +{15800000, DIF_BPF_COEFF67, 0xffaa0041}, +{15800000, DIF_BPF_COEFF89, 0x0067ff13}, +{15800000, DIF_BPF_COEFF1011, 0x0043014a}, +{15800000, DIF_BPF_COEFF1213, 0xfe46ffb9}, +{15800000, DIF_BPF_COEFF1415, 0x02dbfda8}, +{15800000, DIF_BPF_COEFF1617, 0xfe3504e5}, +{15800000, DIF_BPF_COEFF1819, 0xfddcfb8d}, +{15800000, DIF_BPF_COEFF2021, 0x06c9ff7e}, +{15800000, DIF_BPF_COEFF2223, 0xf81107a2}, +{15800000, DIF_BPF_COEFF2425, 0x02c9f49a}, +{15800000, DIF_BPF_COEFF2627, 0x069f0753}, +{15800000, DIF_BPF_COEFF2829, 0xf2500373}, +{15800000, DIF_BPF_COEFF3031, 0x0c14f231}, +{15800000, DIF_BPF_COEFF3233, 0xfe930fb3}, +{15800000, DIF_BPF_COEFF3435, 0xf4a1f927}, +{15800000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 158_quant.dat*/ + + +/*case 115900000:*/ +/* BEGIN - DIF BPF register values from 159_quant.dat*/ +{15900000, DIF_BPF_COEFF01, 0xffff0002}, +{15900000, DIF_BPF_COEFF23, 0x0003ffee}, +{15900000, DIF_BPF_COEFF45, 0x000f0023}, +{15900000, DIF_BPF_COEFF67, 0xffac0016}, +{15900000, DIF_BPF_COEFF89, 0x0093ff31}, +{15900000, DIF_BPF_COEFF1011, 0xffdc0184}, +{15900000, DIF_BPF_COEFF1213, 0xfea6ff09}, +{15900000, DIF_BPF_COEFF1415, 0x02fdfe70}, +{15900000, DIF_BPF_COEFF1617, 0xfd5104ba}, +{15900000, DIF_BPF_COEFF1819, 0xff15faac}, +{15900000, DIF_BPF_COEFF2021, 0x06270103}, +{15900000, DIF_BPF_COEFF2223, 0xf7780688}, +{15900000, DIF_BPF_COEFF2425, 0x044df479}, +{15900000, DIF_BPF_COEFF2627, 0x05430883}, +{15900000, DIF_BPF_COEFF2829, 0xf2a00231}, +{15900000, DIF_BPF_COEFF3031, 0x0cbef2b2}, +{15900000, DIF_BPF_COEFF3233, 0xfdc40fe3}, +{15900000, DIF_BPF_COEFF3435, 0xf4f2f8f5}, +{15900000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 159_quant.dat*/ + + +/*case 116000000:*/ +/* BEGIN - DIF BPF register values from 160_quant.dat*/ +{16000000, DIF_BPF_COEFF01, 0xffff0001}, +{16000000, DIF_BPF_COEFF23, 0x0006ffef}, +{16000000, DIF_BPF_COEFF45, 0x00020031}, +{16000000, DIF_BPF_COEFF67, 0xffbaffe8}, +{16000000, DIF_BPF_COEFF89, 0x00adff66}, +{16000000, DIF_BPF_COEFF1011, 0xff790198}, +{16000000, DIF_BPF_COEFF1213, 0xff26fe6e}, +{16000000, DIF_BPF_COEFF1415, 0x02e5ff55}, +{16000000, DIF_BPF_COEFF1617, 0xfc99044a}, +{16000000, DIF_BPF_COEFF1819, 0x005bfa09}, +{16000000, DIF_BPF_COEFF2021, 0x0545027f}, +{16000000, DIF_BPF_COEFF2223, 0xf7230541}, +{16000000, DIF_BPF_COEFF2425, 0x05b8f490}, +{16000000, DIF_BPF_COEFF2627, 0x03d20997}, +{16000000, DIF_BPF_COEFF2829, 0xf31300eb}, +{16000000, DIF_BPF_COEFF3031, 0x0d55f341}, +{16000000, DIF_BPF_COEFF3233, 0xfcf6100e}, +{16000000, DIF_BPF_COEFF3435, 0xf544f8c3}, +{16000000, DIF_BPF_COEFF36, 0x110d0000}, +/* END - DIF BPF register values from 160_quant.dat*/ +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-dvb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,796 @@ +/* + DVB device driver for cx231xx + + Copyright (C) 2008 + Based on em28xx driver + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include "cx231xx.h" +#include +#include + +#include "xc5000.h" +#include "s5h1432.h" +#include "tda18271.h" +#include "s5h1411.h" +#include "lgdt3305.h" +#include "mb86a20s.h" + +MODULE_DESCRIPTION("driver for cx231xx based DVB cards"); +MODULE_AUTHOR("Srinivasa Deevi "); +MODULE_LICENSE("GPL"); + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages [dvb]"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk(level, fmt, arg...) do { \ +if (debug >= level) \ + printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ +} while (0) + +#define CX231XX_DVB_NUM_BUFS 5 +#define CX231XX_DVB_MAX_PACKETSIZE 564 +#define CX231XX_DVB_MAX_PACKETS 64 + +struct cx231xx_dvb { + struct dvb_frontend *frontend; + + /* feed count management */ + struct mutex lock; + int nfeeds; + + /* general boilerplate stuff */ + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net net; +}; + +static struct s5h1432_config dvico_s5h1432_config = { + .output_mode = S5H1432_SERIAL_OUTPUT, + .gpio = S5H1432_GPIO_ON, + .qam_if = S5H1432_IF_4000, + .vsb_if = S5H1432_IF_4000, + .inversion = S5H1432_INVERSION_OFF, + .status_mode = S5H1432_DEMODLOCKING, + .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = { + .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, + .dvbt_7 = { .if_freq = 4000, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, + .dvbt_8 = { .if_freq = 4000, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, +}; + +static struct tda18271_std_map mb86a20s_tda18271_config = { + .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, + .if_lvl = 7, .rfagc_top = 0x37, }, +}; + +static struct tda18271_config cnxt_rde253s_tunerconfig = { + .std_map = &cnxt_rde253s_tda18271_std_map, + .gate = TDA18271_GATE_ANALOG, +}; + +static struct s5h1411_config tda18271_s5h1411_config = { + .output_mode = S5H1411_SERIAL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .vsb_if = S5H1411_IF_3250, + .qam_if = S5H1411_IF_4000, + .inversion = S5H1411_INVERSION_ON, + .status_mode = S5H1411_DEMODLOCKING, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; +static struct s5h1411_config xc5000_s5h1411_config = { + .output_mode = S5H1411_SERIAL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .vsb_if = S5H1411_IF_3250, + .qam_if = S5H1411_IF_3250, + .inversion = S5H1411_INVERSION_OFF, + .status_mode = S5H1411_DEMODLOCKING, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct lgdt3305_config hcw_lgdt3305_config = { + .i2c_addr = 0x0e, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .deny_i2c_rptr = 1, + .spectral_inversion = 1, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, +}; + +static struct tda18271_std_map hauppauge_tda18271_std_map = { + .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x58, }, + .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x58, }, +}; + +static struct tda18271_config hcw_tda18271_config = { + .std_map = &hauppauge_tda18271_std_map, + .gate = TDA18271_GATE_DIGITAL, +}; + +static const struct mb86a20s_config pv_mb86a20s_config = { + .demod_address = 0x10, + .is_serial = true, +}; + +static struct tda18271_config pv_tda18271_config = { + .std_map = &mb86a20s_tda18271_config, + .gate = TDA18271_GATE_DIGITAL, + .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, +}; + +static inline void print_err_status(struct cx231xx *dev, int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + dprintk(1, "URB status %d [%s].\n", status, errmsg); + } else { + dprintk(1, "URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + +static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb) +{ + int i; + + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + for (i = 0; i < urb->number_of_packets; i++) { + int status = urb->iso_frame_desc[i].status; + + if (status < 0) { + print_err_status(dev, i, status); + if (urb->iso_frame_desc[i].status != -EPROTO) + continue; + } + + dvb_dmx_swfilter(&dev->dvb->demux, + urb->transfer_buffer + + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } + + return 0; +} + +static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb) +{ + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + /* Feed the transport payload into the kernel demux */ + dvb_dmx_swfilter(&dev->dvb->demux, + urb->transfer_buffer, urb->actual_length); + + return 0; +} + +static int start_streaming(struct cx231xx_dvb *dvb) +{ + int rc; + struct cx231xx *dev = dvb->adapter.priv; + + if (dev->USE_ISO) { + cx231xx_info("DVB transfer mode is ISO.\n"); + mutex_lock(&dev->i2c_lock); + cx231xx_enable_i2c_port_3(dev, false); + cx231xx_set_alt_setting(dev, INDEX_TS1, 4); + cx231xx_enable_i2c_port_3(dev, true); + mutex_unlock(&dev->i2c_lock); + rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); + if (rc < 0) + return rc; + dev->mode_tv = 1; + return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS, + CX231XX_DVB_NUM_BUFS, + dev->ts1_mode.max_pkt_size, + dvb_isoc_copy); + } else { + cx231xx_info("DVB transfer mode is BULK.\n"); + cx231xx_set_alt_setting(dev, INDEX_TS1, 0); + rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); + if (rc < 0) + return rc; + dev->mode_tv = 1; + return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS, + CX231XX_DVB_NUM_BUFS, + dev->ts1_mode.max_pkt_size, + dvb_bulk_copy); + } + +} + +static int stop_streaming(struct cx231xx_dvb *dvb) +{ + struct cx231xx *dev = dvb->adapter.priv; + + if (dev->USE_ISO) + cx231xx_uninit_isoc(dev); + else + cx231xx_uninit_bulk(dev); + + cx231xx_set_mode(dev, CX231XX_SUSPEND); + + return 0; +} + +static int start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx231xx_dvb *dvb = demux->priv; + int rc, ret; + + if (!demux->dmx.frontend) + return -EINVAL; + + mutex_lock(&dvb->lock); + dvb->nfeeds++; + rc = dvb->nfeeds; + + if (dvb->nfeeds == 1) { + ret = start_streaming(dvb); + if (ret < 0) + rc = ret; + } + + mutex_unlock(&dvb->lock); + return rc; +} + +static int stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx231xx_dvb *dvb = demux->priv; + int err = 0; + + mutex_lock(&dvb->lock); + dvb->nfeeds--; + + if (0 == dvb->nfeeds) + err = stop_streaming(dvb); + + mutex_unlock(&dvb->lock); + return err; +} + +/* ------------------------------------------------------------------ */ +static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct cx231xx *dev = fe->dvb->priv; + + if (acquire) + return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); + else + return cx231xx_set_mode(dev, CX231XX_SUSPEND); +} + +/* ------------------------------------------------------------------ */ + +static struct xc5000_config cnxt_rde250_tunerconfig = { + .i2c_address = 0x61, + .if_khz = 4000, +}; +static struct xc5000_config cnxt_rdu250_tunerconfig = { + .i2c_address = 0x61, + .if_khz = 3250, +}; + +/* ------------------------------------------------------------------ */ +#if 0 +static int attach_xc5000(u8 addr, struct cx231xx *dev) +{ + + struct dvb_frontend *fe; + struct xc5000_config cfg; + + memset(&cfg, 0, sizeof(cfg)); + cfg.i2c_adap = &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap; + cfg.i2c_addr = addr; + + if (!dev->dvb->frontend) { + printk(KERN_ERR "%s/2: dvb frontend not attached. " + "Can't attach xc5000\n", dev->name); + return -EINVAL; + } + + fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg); + if (!fe) { + printk(KERN_ERR "%s/2: xc5000 attach failed\n", dev->name); + dvb_frontend_detach(dev->dvb->frontend); + dev->dvb->frontend = NULL; + return -EINVAL; + } + + printk(KERN_INFO "%s/2: xc5000 attached\n", dev->name); + + return 0; +} +#endif + +int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) +{ + int status = 0; + + if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { + + struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; + + if (dops->set_analog_params != NULL) { + struct analog_parameters params; + + params.frequency = freq; + params.std = dev->norm; + params.mode = 0; /* 0- Air; 1 - cable */ + /*params.audmode = ; */ + + /* Set the analog parameters to set the frequency */ + dops->set_analog_params(dev->dvb->frontend, ¶ms); + } + + } + + return status; +} + +int cx231xx_reset_analog_tuner(struct cx231xx *dev) +{ + int status = 0; + + if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { + + struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; + + if (dops->init != NULL && !dev->xc_fw_load_done) { + + cx231xx_info("Reloading firmware for XC5000\n"); + status = dops->init(dev->dvb->frontend); + if (status == 0) { + dev->xc_fw_load_done = 1; + cx231xx_info + ("XC5000 firmware download completed\n"); + } else { + dev->xc_fw_load_done = 0; + cx231xx_info + ("XC5000 firmware download failed !!!\n"); + } + } + + } + + return status; +} + +/* ------------------------------------------------------------------ */ + +static int register_dvb(struct cx231xx_dvb *dvb, + struct module *module, + struct cx231xx *dev, struct device *device) +{ + int result; + + mutex_init(&dvb->lock); + + /* register adapter */ + result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, + adapter_nr); + if (result < 0) { + printk(KERN_WARNING + "%s: dvb_register_adapter failed (errno = %d)\n", + dev->name, result); + goto fail_adapter; + } + + /* Ensure all frontends negotiate bus access */ + dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; + + dvb->adapter.priv = dev; + + /* register frontend */ + result = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (result < 0) { + printk(KERN_WARNING + "%s: dvb_register_frontend failed (errno = %d)\n", + dev->name, result); + goto fail_frontend; + } + + /* register demux stuff */ + dvb->demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + dvb->demux.priv = dvb; + dvb->demux.filternum = 256; + dvb->demux.feednum = 256; + dvb->demux.start_feed = start_feed; + dvb->demux.stop_feed = stop_feed; + + result = dvb_dmx_init(&dvb->demux); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", + dev->name, result); + goto fail_dmx; + } + + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = &dvb->demux.dmx; + dvb->dmxdev.capabilities = 0; + result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", + dev->name, result); + goto fail_dmxdev; + } + + dvb->fe_hw.source = DMX_FRONTEND_0; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING + "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", + dev->name, result); + goto fail_fe_hw; + } + + dvb->fe_mem.source = DMX_MEMORY_FE; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); + if (result < 0) { + printk(KERN_WARNING + "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", + dev->name, result); + goto fail_fe_mem; + } + + result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING + "%s: connect_frontend failed (errno = %d)\n", dev->name, + result); + goto fail_fe_conn; + } + + /* register network adapter */ + dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); + return 0; + +fail_fe_conn: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); +fail_fe_mem: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); +fail_fe_hw: + dvb_dmxdev_release(&dvb->dmxdev); +fail_dmxdev: + dvb_dmx_release(&dvb->demux); +fail_dmx: + dvb_unregister_frontend(dvb->frontend); +fail_frontend: + dvb_frontend_detach(dvb->frontend); + dvb_unregister_adapter(&dvb->adapter); +fail_adapter: + return result; +} + +static void unregister_dvb(struct cx231xx_dvb *dvb) +{ + dvb_net_release(&dvb->net); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(&dvb->demux); + dvb_unregister_frontend(dvb->frontend); + dvb_frontend_detach(dvb->frontend); + dvb_unregister_adapter(&dvb->adapter); +} + +static int dvb_init(struct cx231xx *dev) +{ + int result = 0; + struct cx231xx_dvb *dvb; + + if (!dev->board.has_dvb) { + /* This device does not support the extension */ + return 0; + } + + dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL); + + if (dvb == NULL) { + printk(KERN_INFO "cx231xx_dvb: memory allocation failed\n"); + return -ENOMEM; + } + dev->dvb = dvb; + dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq; + dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner; + + mutex_lock(&dev->lock); + cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); + cx231xx_demod_reset(dev); + /* init frontend */ + switch (dev->model) { + case CX231XX_BOARD_CNXT_CARRAERA: + case CX231XX_BOARD_CNXT_RDE_250: + + dev->dvb->frontend = dvb_attach(s5h1432_attach, + &dvico_s5h1432_config, + &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); + + if (dev->dvb->frontend == NULL) { + printk(DRIVER_NAME + ": Failed to attach s5h1432 front end\n"); + result = -EINVAL; + goto out_free; + } + + /* define general-purpose callback pointer */ + dvb->frontend->callback = cx231xx_tuner_callback; + + if (!dvb_attach(xc5000_attach, dev->dvb->frontend, + &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, + &cnxt_rde250_tunerconfig)) { + result = -EINVAL; + goto out_free; + } + + break; + case CX231XX_BOARD_CNXT_SHELBY: + case CX231XX_BOARD_CNXT_RDU_250: + + dev->dvb->frontend = dvb_attach(s5h1411_attach, + &xc5000_s5h1411_config, + &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); + + if (dev->dvb->frontend == NULL) { + printk(DRIVER_NAME + ": Failed to attach s5h1411 front end\n"); + result = -EINVAL; + goto out_free; + } + + /* define general-purpose callback pointer */ + dvb->frontend->callback = cx231xx_tuner_callback; + + if (!dvb_attach(xc5000_attach, dev->dvb->frontend, + &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, + &cnxt_rdu250_tunerconfig)) { + result = -EINVAL; + goto out_free; + } + break; + case CX231XX_BOARD_CNXT_RDE_253S: + + dev->dvb->frontend = dvb_attach(s5h1432_attach, + &dvico_s5h1432_config, + &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); + + if (dev->dvb->frontend == NULL) { + printk(DRIVER_NAME + ": Failed to attach s5h1432 front end\n"); + result = -EINVAL; + goto out_free; + } + + /* define general-purpose callback pointer */ + dvb->frontend->callback = cx231xx_tuner_callback; + + if (!dvb_attach(tda18271_attach, dev->dvb->frontend, + 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, + &cnxt_rde253s_tunerconfig)) { + result = -EINVAL; + goto out_free; + } + break; + case CX231XX_BOARD_CNXT_RDU_253S: + + dev->dvb->frontend = dvb_attach(s5h1411_attach, + &tda18271_s5h1411_config, + &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); + + if (dev->dvb->frontend == NULL) { + printk(DRIVER_NAME + ": Failed to attach s5h1411 front end\n"); + result = -EINVAL; + goto out_free; + } + + /* define general-purpose callback pointer */ + dvb->frontend->callback = cx231xx_tuner_callback; + + if (!dvb_attach(tda18271_attach, dev->dvb->frontend, + 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, + &cnxt_rde253s_tunerconfig)) { + result = -EINVAL; + goto out_free; + } + break; + case CX231XX_BOARD_HAUPPAUGE_EXETER: + + printk(KERN_INFO "%s: looking for tuner / demod on i2c bus: %d\n", + __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap)); + + dev->dvb->frontend = dvb_attach(lgdt3305_attach, + &hcw_lgdt3305_config, + &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap); + + if (dev->dvb->frontend == NULL) { + printk(DRIVER_NAME + ": Failed to attach LG3305 front end\n"); + result = -EINVAL; + goto out_free; + } + + /* define general-purpose callback pointer */ + dvb->frontend->callback = cx231xx_tuner_callback; + + dvb_attach(tda18271_attach, dev->dvb->frontend, + 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, + &hcw_tda18271_config); + break; + + case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: + case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID: + + printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n", + __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap)); + + dev->dvb->frontend = dvb_attach(mb86a20s_attach, + &pv_mb86a20s_config, + &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); + + if (dev->dvb->frontend == NULL) { + printk(DRIVER_NAME + ": Failed to attach mb86a20s demod\n"); + result = -EINVAL; + goto out_free; + } + + /* define general-purpose callback pointer */ + dvb->frontend->callback = cx231xx_tuner_callback; + + dvb_attach(tda18271_attach, dev->dvb->frontend, + 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, + &pv_tda18271_config); + break; + + default: + printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" + " isn't supported yet\n", dev->name); + break; + } + if (NULL == dvb->frontend) { + printk(KERN_ERR + "%s/2: frontend initialization failed\n", dev->name); + result = -EINVAL; + goto out_free; + } + + /* register everything */ + result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); + + if (result < 0) + goto out_free; + + + printk(KERN_INFO "Successfully loaded cx231xx-dvb\n"); + +ret: + cx231xx_set_mode(dev, CX231XX_SUSPEND); + mutex_unlock(&dev->lock); + return result; + +out_free: + kfree(dvb); + dev->dvb = NULL; + goto ret; +} + +static int dvb_fini(struct cx231xx *dev) +{ + if (!dev->board.has_dvb) { + /* This device does not support the extension */ + return 0; + } + + if (dev->dvb) { + unregister_dvb(dev->dvb); + dev->dvb = NULL; + } + + return 0; +} + +static struct cx231xx_ops dvb_ops = { + .id = CX231XX_DVB, + .name = "Cx231xx dvb Extension", + .init = dvb_init, + .fini = dvb_fini, +}; + +static int __init cx231xx_dvb_register(void) +{ + return cx231xx_register_extension(&dvb_ops); +} + +static void __exit cx231xx_dvb_unregister(void) +{ + cx231xx_unregister_extension(&dvb_ops); +} + +module_init(cx231xx_dvb_register); +module_exit(cx231xx_dvb_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1015 @@ +/* + cx231xx.h - driver for Conexant Cx23100/101/102 USB video capture devices + + Copyright (C) 2008 + Based on em28xx driver + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CX231XX_H +#define _CX231XX_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "cx231xx-reg.h" +#include "cx231xx-pcb-cfg.h" +#include "cx231xx-conf-reg.h" + +#define DRIVER_NAME "cx231xx" +#define PWR_SLEEP_INTERVAL 5 + +/* I2C addresses for control block in Cx231xx */ +#define AFE_DEVICE_ADDRESS 0x60 +#define I2S_BLK_DEVICE_ADDRESS 0x98 +#define VID_BLK_I2C_ADDRESS 0x88 +#define VERVE_I2C_ADDRESS 0x40 +#define DIF_USE_BASEBAND 0xFFFFFFFF + +/* Boards supported by driver */ +#define CX231XX_BOARD_UNKNOWN 0 +#define CX231XX_BOARD_CNXT_CARRAERA 1 +#define CX231XX_BOARD_CNXT_SHELBY 2 +#define CX231XX_BOARD_CNXT_RDE_253S 3 +#define CX231XX_BOARD_CNXT_RDU_253S 4 +#define CX231XX_BOARD_CNXT_VIDEO_GRABBER 5 +#define CX231XX_BOARD_CNXT_RDE_250 6 +#define CX231XX_BOARD_CNXT_RDU_250 7 +#define CX231XX_BOARD_HAUPPAUGE_EXETER 8 +#define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9 +#define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10 +#define CX231XX_BOARD_PV_XCAPTURE_USB 11 +#define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12 +#define CX231XX_BOARD_ICONBIT_U100 13 +#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14 +#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15 + +/* Limits minimum and default number of buffers */ +#define CX231XX_MIN_BUF 4 +#define CX231XX_DEF_BUF 12 +#define CX231XX_DEF_VBI_BUF 6 + +#define VBI_LINE_COUNT 17 +#define VBI_LINE_LENGTH 1440 + +/*Limits the max URB message size */ +#define URB_MAX_CTRL_SIZE 80 + +/* Params for validated field */ +#define CX231XX_BOARD_NOT_VALIDATED 1 +#define CX231XX_BOARD_VALIDATED 0 + +/* maximum number of cx231xx boards */ +#define CX231XX_MAXBOARDS 8 + +/* maximum number of frames that can be queued */ +#define CX231XX_NUM_FRAMES 5 + +/* number of buffers for isoc transfers */ +#define CX231XX_NUM_BUFS 8 + +/* number of packets for each buffer + windows requests only 40 packets .. so we better do the same + this is what I found out for all alternate numbers there! + */ +#define CX231XX_NUM_PACKETS 40 + +/* default alternate; 0 means choose the best */ +#define CX231XX_PINOUT 0 + +#define CX231XX_INTERLACED_DEFAULT 1 + +/* time to wait when stopping the isoc transfer */ +#define CX231XX_URB_TIMEOUT \ + msecs_to_jiffies(CX231XX_NUM_BUFS * CX231XX_NUM_PACKETS) + +#define CX231xx_NORMS (\ + V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \ + V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ + V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ + V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) +#define CX231xx_VERSION_CODE KERNEL_VERSION(0, 0, 2) + +#define SLEEP_S5H1432 30 +#define CX23417_OSC_EN 8 +#define CX23417_RESET 9 + +struct cx23417_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 cxformat; +}; +enum cx231xx_mode { + CX231XX_SUSPEND, + CX231XX_ANALOG_MODE, + CX231XX_DIGITAL_MODE, +}; + +enum cx231xx_std_mode { + CX231XX_TV_AIR = 0, + CX231XX_TV_CABLE +}; + +enum cx231xx_stream_state { + STREAM_OFF, + STREAM_INTERRUPT, + STREAM_ON, +}; + +struct cx231xx; + +struct cx231xx_isoc_ctl { + /* max packet size of isoc transaction */ + int max_pkt_size; + + /* number of allocated urbs */ + int num_bufs; + + /* urb for isoc transfers */ + struct urb **urb; + + /* transfer buffers for isoc transfer */ + char **transfer_buffer; + + /* Last buffer command and region */ + u8 cmd; + int pos, size, pktsize; + + /* Last field: ODD or EVEN? */ + int field; + + /* Stores incomplete commands */ + u32 tmp_buf; + int tmp_buf_len; + + /* Stores already requested buffers */ + struct cx231xx_buffer *buf; + + /* Stores the number of received fields */ + int nfields; + + /* isoc urb callback */ + int (*isoc_copy) (struct cx231xx *dev, struct urb *urb); +}; + +struct cx231xx_bulk_ctl { + /* max packet size of bulk transaction */ + int max_pkt_size; + + /* number of allocated urbs */ + int num_bufs; + + /* urb for bulk transfers */ + struct urb **urb; + + /* transfer buffers for bulk transfer */ + char **transfer_buffer; + + /* Last buffer command and region */ + u8 cmd; + int pos, size, pktsize; + + /* Last field: ODD or EVEN? */ + int field; + + /* Stores incomplete commands */ + u32 tmp_buf; + int tmp_buf_len; + + /* Stores already requested buffers */ + struct cx231xx_buffer *buf; + + /* Stores the number of received fields */ + int nfields; + + /* bulk urb callback */ + int (*bulk_copy) (struct cx231xx *dev, struct urb *urb); +}; + +struct cx231xx_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int reg; +}; + +/* buffer for one video frame */ +struct cx231xx_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + struct list_head frame; + int top_field; + int receiving; +}; + +enum ps_package_head { + CX231XX_NEED_ADD_PS_PACKAGE_HEAD = 0, + CX231XX_NONEED_PS_PACKAGE_HEAD +}; + +struct cx231xx_dmaqueue { + struct list_head active; + struct list_head queued; + + wait_queue_head_t wq; + + /* Counters to control buffer fill */ + int pos; + u8 is_partial_line; + u8 partial_buf[8]; + u8 last_sav; + int current_field; + u32 bytes_left_in_line; + u32 lines_completed; + u8 field1_done; + u32 lines_per_field; + + /*Mpeg2 control buffer*/ + u8 *p_left_data; + u32 left_data_count; + u8 mpeg_buffer_done; + u32 mpeg_buffer_completed; + enum ps_package_head add_ps_package_head; + char ps_head[10]; +}; + +/* inputs */ + +#define MAX_CX231XX_INPUT 4 + +enum cx231xx_itype { + CX231XX_VMUX_COMPOSITE1 = 1, + CX231XX_VMUX_SVIDEO, + CX231XX_VMUX_TELEVISION, + CX231XX_VMUX_CABLE, + CX231XX_RADIO, + CX231XX_VMUX_DVB, + CX231XX_VMUX_DEBUG +}; + +enum cx231xx_v_input { + CX231XX_VIN_1_1 = 0x1, + CX231XX_VIN_2_1, + CX231XX_VIN_3_1, + CX231XX_VIN_4_1, + CX231XX_VIN_1_2 = 0x01, + CX231XX_VIN_2_2, + CX231XX_VIN_3_2, + CX231XX_VIN_1_3 = 0x1, + CX231XX_VIN_2_3, + CX231XX_VIN_3_3, +}; + +/* cx231xx has two audio inputs: tuner and line in */ +enum cx231xx_amux { + /* This is the only entry for cx231xx tuner input */ + CX231XX_AMUX_VIDEO, /* cx231xx tuner */ + CX231XX_AMUX_LINE_IN, /* Line In */ +}; + +struct cx231xx_reg_seq { + unsigned char bit; + unsigned char val; + int sleep; +}; + +struct cx231xx_input { + enum cx231xx_itype type; + unsigned int vmux; + enum cx231xx_amux amux; + struct cx231xx_reg_seq *gpio; +}; + +#define INPUT(nr) (&cx231xx_boards[dev->model].input[nr]) + +enum cx231xx_decoder { + CX231XX_NODECODER, + CX231XX_AVDECODER +}; + +enum CX231XX_I2C_MASTER_PORT { + I2C_0 = 0, + I2C_1 = 1, + I2C_2 = 2, + I2C_3 = 3 +}; + +struct cx231xx_board { + char *name; + int vchannels; + int tuner_type; + int tuner_addr; + v4l2_std_id norm; /* tv norm */ + + /* demod related */ + int demod_addr; + u8 demod_xfer_mode; /* 0 - Serial; 1 - parallel */ + + /* GPIO Pins */ + struct cx231xx_reg_seq *dvb_gpio; + struct cx231xx_reg_seq *suspend_gpio; + struct cx231xx_reg_seq *tuner_gpio; + /* Negative means don't use it */ + s8 tuner_sif_gpio; + s8 tuner_scl_gpio; + s8 tuner_sda_gpio; + + /* PIN ctrl */ + u32 ctl_pin_status_mask; + u8 agc_analog_digital_select_gpio; + u32 gpio_pin_status_mask; + + /* i2c masters */ + u8 tuner_i2c_master; + u8 demod_i2c_master; + u8 ir_i2c_master; + + /* for devices with I2C chips for IR */ + char *rc_map_name; + + unsigned int max_range_640_480:1; + unsigned int has_dvb:1; + unsigned int has_417:1; + unsigned int valid:1; + unsigned int no_alt_vanc:1; + unsigned int external_av:1; + unsigned int dont_use_port_3:1; + + unsigned char xclk, i2c_speed; + + enum cx231xx_decoder decoder; + int output_mode; + + struct cx231xx_input input[MAX_CX231XX_INPUT]; + struct cx231xx_input radio; + struct rc_map *ir_codes; +}; + +/* device states */ +enum cx231xx_dev_state { + DEV_INITIALIZED = 0x01, + DEV_DISCONNECTED = 0x02, + DEV_MISCONFIGURED = 0x04, +}; + +enum AFE_MODE { + AFE_MODE_LOW_IF, + AFE_MODE_BASEBAND, + AFE_MODE_EU_HI_IF, + AFE_MODE_US_HI_IF, + AFE_MODE_JAPAN_HI_IF +}; + +enum AUDIO_INPUT { + AUDIO_INPUT_MUTE, + AUDIO_INPUT_LINE, + AUDIO_INPUT_TUNER_TV, + AUDIO_INPUT_SPDIF, + AUDIO_INPUT_TUNER_FM +}; + +#define CX231XX_AUDIO_BUFS 5 +#define CX231XX_NUM_AUDIO_PACKETS 16 +#define CX231XX_ISO_NUM_AUDIO_PACKETS 64 + +/* cx231xx extensions */ +#define CX231XX_AUDIO 0x10 +#define CX231XX_DVB 0x20 + +struct cx231xx_audio { + char name[50]; + char *transfer_buffer[CX231XX_AUDIO_BUFS]; + struct urb *urb[CX231XX_AUDIO_BUFS]; + struct usb_device *udev; + unsigned int capture_transfer_done; + struct snd_pcm_substream *capture_pcm_substream; + + unsigned int hwptr_done_capture; + struct snd_card *sndcard; + + int users, shutdown; + /* locks */ + spinlock_t slock; + + int alt; /* alternate */ + int max_pkt_size; /* max packet size of isoc transaction */ + int num_alt; /* Number of alternative settings */ + unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ + u16 end_point_addr; +}; + +struct cx231xx; + +struct cx231xx_fh { + struct cx231xx *dev; + unsigned int stream_on:1; /* Locks streams */ + int radio; + + struct videobuf_queue vb_vidq; + + enum v4l2_buf_type type; + + + +/*following is copyed from cx23885.h*/ + u32 resources; + + /* video overlay */ + struct v4l2_window win; + struct v4l2_clip *clips; + unsigned int nclips; + + /* video capture */ + struct cx23417_fmt *fmt; + unsigned int width, height; + + /* vbi capture */ + struct videobuf_queue vidq; + struct videobuf_queue vbiq; + + /* MPEG Encoder specifics ONLY */ + + atomic_t v4l_reading; +}; + +/*****************************************************************/ +/* set/get i2c */ +/* 00--1Mb/s, 01-400kb/s, 10--100kb/s, 11--5Mb/s */ +#define I2C_SPEED_1M 0x0 +#define I2C_SPEED_400K 0x1 +#define I2C_SPEED_100K 0x2 +#define I2C_SPEED_5M 0x3 + +/* 0-- STOP transaction */ +#define I2C_STOP 0x0 +/* 1-- do not transmit STOP at end of transaction */ +#define I2C_NOSTOP 0x1 +/* 1--allow slave to insert clock wait states */ +#define I2C_SYNC 0x1 + +struct cx231xx_i2c { + struct cx231xx *dev; + + int nr; + + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + u32 i2c_rc; + + /* different settings for each bus */ + u8 i2c_period; + u8 i2c_nostop; + u8 i2c_reserve; +}; + +struct cx231xx_i2c_xfer_data { + u8 dev_addr; + u8 direction; /* 1 - IN, 0 - OUT */ + u8 saddr_len; /* sub address len */ + u16 saddr_dat; /* sub addr data */ + u8 buf_size; /* buffer size */ + u8 *p_buffer; /* pointer to the buffer */ +}; + +struct VENDOR_REQUEST_IN { + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; + u8 direction; + u8 bData; + u8 *pBuff; +}; + +struct cx231xx_tvnorm { + char *name; + v4l2_std_id id; + u32 cxiformat; + u32 cxoformat; +}; + +struct cx231xx_ctrl { + struct v4l2_queryctrl v; + u32 off; + u32 reg; + u32 mask; + u32 shift; +}; + +enum TRANSFER_TYPE { + Raw_Video = 0, + Audio, + Vbi, /* VANC */ + Sliced_cc, /* HANC */ + TS1_serial_mode, + TS2, + TS1_parallel_mode +} ; + +struct cx231xx_video_mode { + /* Isoc control struct */ + struct cx231xx_dmaqueue vidq; + struct cx231xx_isoc_ctl isoc_ctl; + struct cx231xx_bulk_ctl bulk_ctl; + /* locks */ + spinlock_t slock; + + /* usb transfer */ + int alt; /* alternate */ + int max_pkt_size; /* max packet size of isoc transaction */ + int num_alt; /* Number of alternative settings */ + unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ + u16 end_point_addr; +}; +/* +struct cx23885_dmaqueue { + struct list_head active; + struct list_head queued; + struct timer_list timeout; + struct btcx_riscmem stopper; + u32 count; +}; +*/ +struct cx231xx_tsport { + struct cx231xx *dev; + + int nr; + int sram_chno; + + struct videobuf_dvb_frontends frontends; + + /* dma queues */ + + u32 ts_packet_size; + u32 ts_packet_count; + + int width; + int height; + + /* locks */ + spinlock_t slock; + + /* registers */ + u32 reg_gpcnt; + u32 reg_gpcnt_ctl; + u32 reg_dma_ctl; + u32 reg_lngth; + u32 reg_hw_sop_ctrl; + u32 reg_gen_ctrl; + u32 reg_bd_pkt_status; + u32 reg_sop_status; + u32 reg_fifo_ovfl_stat; + u32 reg_vld_misc; + u32 reg_ts_clk_en; + u32 reg_ts_int_msk; + u32 reg_ts_int_stat; + u32 reg_src_sel; + + /* Default register vals */ + int pci_irqmask; + u32 dma_ctl_val; + u32 ts_int_msk_val; + u32 gen_ctrl_val; + u32 ts_clk_en_val; + u32 src_sel_val; + u32 vld_misc_val; + u32 hw_sop_ctrl_val; + + /* Allow a single tsport to have multiple frontends */ + u32 num_frontends; + void *port_priv; +}; + +/* main device struct */ +struct cx231xx { + /* generic device properties */ + char name[30]; /* name (including minor) of the device */ + int model; /* index in the device_data struct */ + int devno; /* marks the number of this device */ + + struct cx231xx_board board; + + /* For I2C IR support */ + struct IR_i2c_init_data init_data; + + unsigned int stream_on:1; /* Locks streams */ + unsigned int vbi_stream_on:1; /* Locks streams for VBI */ + unsigned int has_audio_class:1; + unsigned int has_alsa_audio:1; + + struct cx231xx_fmt *format; + + struct v4l2_device v4l2_dev; + struct v4l2_subdev *sd_cx25840; + struct v4l2_subdev *sd_tuner; + + struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ + atomic_t stream_started; /* stream should be running if true */ + + struct list_head devlist; + + int tuner_type; /* type of the tuner */ + int tuner_addr; /* tuner address */ + + /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ + struct cx231xx_i2c i2c_bus[3]; + unsigned int xc_fw_load_done:1; + /* locks */ + struct mutex gpio_i2c_lock; + struct mutex i2c_lock; + + /* video for linux */ + int users; /* user count for exclusive use */ + struct video_device *vdev; /* video for linux device struct */ + v4l2_std_id norm; /* selected tv norm */ + int ctl_freq; /* selected frequency */ + unsigned int ctl_ainput; /* selected audio input */ + int mute; + int volume; + + /* frame properties */ + int width; /* current frame width */ + int height; /* current frame height */ + int interlaced; /* 1=interlace fileds, 0=just top fileds */ + + struct cx231xx_audio adev; + + /* states */ + enum cx231xx_dev_state state; + + struct work_struct request_module_wk; + + /* locks */ + struct mutex lock; + struct mutex ctrl_urb_lock; /* protects urb_buf */ + struct list_head inqueue, outqueue; + wait_queue_head_t open, wait_frame, wait_stream; + struct video_device *vbi_dev; + struct video_device *radio_dev; + + unsigned char eedata[256]; + + struct cx231xx_video_mode video_mode; + struct cx231xx_video_mode vbi_mode; + struct cx231xx_video_mode sliced_cc_mode; + struct cx231xx_video_mode ts1_mode; + + atomic_t devlist_count; + + struct usb_device *udev; /* the usb device */ + char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ + + /* helper funcs that call usb_control_msg */ + int (*cx231xx_read_ctrl_reg) (struct cx231xx *dev, u8 req, u16 reg, + char *buf, int len); + int (*cx231xx_write_ctrl_reg) (struct cx231xx *dev, u8 req, u16 reg, + char *buf, int len); + int (*cx231xx_send_usb_command) (struct cx231xx_i2c *i2c_bus, + struct cx231xx_i2c_xfer_data *req_data); + int (*cx231xx_gpio_i2c_read) (struct cx231xx *dev, u8 dev_addr, + u8 *buf, u8 len); + int (*cx231xx_gpio_i2c_write) (struct cx231xx *dev, u8 dev_addr, + u8 *buf, u8 len); + + int (*cx231xx_set_analog_freq) (struct cx231xx *dev, u32 freq); + int (*cx231xx_reset_analog_tuner) (struct cx231xx *dev); + + enum cx231xx_mode mode; + + struct cx231xx_dvb *dvb; + + /* Cx231xx supported PCB config's */ + struct pcb_config current_pcb_config; + u8 current_scenario_idx; + u8 interface_count; + u8 max_iad_interface_count; + + /* GPIO related register direction and values */ + u32 gpio_dir; + u32 gpio_val; + + /* Power Modes */ + int power_mode; + + /* afe parameters */ + enum AFE_MODE afe_mode; + u32 afe_ref_count; + + /* video related parameters */ + u32 video_input; + u32 active_mode; + u8 vbi_or_sliced_cc_mode; /* 0 - vbi ; 1 - sliced cc mode */ + enum cx231xx_std_mode std_mode; /* 0 - Air; 1 - cable */ + + /*mode: digital=1 or analog=0*/ + u8 mode_tv; + + u8 USE_ISO; + struct cx231xx_tvnorm encodernorm; + struct cx231xx_tsport ts1, ts2; + struct cx2341x_mpeg_params mpeg_params; + struct video_device *v4l_device; + atomic_t v4l_reader_count; + u32 freq; + unsigned int input; + u32 cx23417_mailbox; + u32 __iomem *lmmio; + u8 __iomem *bmmio; +}; + +extern struct list_head cx231xx_devlist; + +#define cx25840_call(cx231xx, o, f, args...) \ + v4l2_subdev_call(cx231xx->sd_cx25840, o, f, ##args) +#define tuner_call(cx231xx, o, f, args...) \ + v4l2_subdev_call(cx231xx->sd_tuner, o, f, ##args) +#define call_all(dev, o, f, args...) \ + v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args) + +struct cx231xx_ops { + struct list_head next; + char *name; + int id; + int (*init) (struct cx231xx *); + int (*fini) (struct cx231xx *); +}; + +/* call back functions in dvb module */ +int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq); +int cx231xx_reset_analog_tuner(struct cx231xx *dev); + +/* Provided by cx231xx-i2c.c */ +void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c); +int cx231xx_i2c_register(struct cx231xx_i2c *bus); +int cx231xx_i2c_unregister(struct cx231xx_i2c *bus); + +/* Internal block control functions */ +int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr, + u8 saddr_len, u32 *data, u8 data_len, int master); +int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr, + u8 saddr_len, u32 data, u8 data_len, int master); +int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, + u16 saddr, u8 saddr_len, u32 *data, u8 data_len); +int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr, + u16 saddr, u8 saddr_len, u32 data, u8 data_len); +int cx231xx_reg_mask_write(struct cx231xx *dev, u8 dev_addr, u8 size, + u16 register_address, u8 bit_start, u8 bit_end, + u32 value); +int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr, + u16 saddr, u32 mask, u32 value); +u32 cx231xx_set_field(u32 field_mask, u32 data); + +/*verve r/w*/ +void initGPIO(struct cx231xx *dev); +void uninitGPIO(struct cx231xx *dev); +/* afe related functions */ +int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count); +int cx231xx_afe_init_channels(struct cx231xx *dev); +int cx231xx_afe_setup_AFE_for_baseband(struct cx231xx *dev); +int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux); +int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode); +int cx231xx_afe_update_power_control(struct cx231xx *dev, + enum AV_MODE avmode); +int cx231xx_afe_adjust_ref_count(struct cx231xx *dev, u32 video_input); + +/* i2s block related functions */ +int cx231xx_i2s_blk_initialize(struct cx231xx *dev); +int cx231xx_i2s_blk_update_power_control(struct cx231xx *dev, + enum AV_MODE avmode); +int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input); + +/* DIF related functions */ +int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode, + u32 function_mode, u32 standard); +void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq, + u8 spectral_invert, u32 mode); +u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd); +void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq, + u8 spectral_invert, u32 mode); +void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev); +void reset_s5h1432_demod(struct cx231xx *dev); +void cx231xx_dump_HH_reg(struct cx231xx *dev); +void update_HH_register_after_set_DIF(struct cx231xx *dev); +void cx231xx_dump_SC_reg(struct cx231xx *dev); + + + +int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard); +int cx231xx_tuner_pre_channel_change(struct cx231xx *dev); +int cx231xx_tuner_post_channel_change(struct cx231xx *dev); + +/* video parser functions */ +u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, + u32 *p_bytes_used); +u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf, + u32 *p_bytes_used); +int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 *p_buffer, u32 bytes_to_copy); +void cx231xx_reset_video_buffer(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q); +u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q); +u32 cx231xx_copy_video_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 *p_line, u32 length, int field_number); +u32 cx231xx_get_video_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 sav_eav, u8 *p_buffer, u32 buffer_size); +void cx231xx_swab(u16 *from, u16 *to, u16 len); + +/* Provided by cx231xx-core.c */ + +u32 cx231xx_request_buffers(struct cx231xx *dev, u32 count); +void cx231xx_queue_unusedframes(struct cx231xx *dev); +void cx231xx_release_buffers(struct cx231xx *dev); + +/* read from control pipe */ +int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, + char *buf, int len); + +/* write to control pipe */ +int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, + char *buf, int len); +int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode); + +int cx231xx_send_vendor_cmd(struct cx231xx *dev, + struct VENDOR_REQUEST_IN *ven_req); +int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus, + struct cx231xx_i2c_xfer_data *req_data); + +/* Gpio related functions */ +int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val, + u8 len, u8 request, u8 direction); +int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val); +int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val); +int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value); +int cx231xx_set_gpio_direction(struct cx231xx *dev, int pin_number, + int pin_value); + +int cx231xx_gpio_i2c_start(struct cx231xx *dev); +int cx231xx_gpio_i2c_end(struct cx231xx *dev); +int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data); +int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf); +int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev); +int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev); +int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev); + +int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len); +int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len); + +/* audio related functions */ +int cx231xx_set_audio_decoder_input(struct cx231xx *dev, + enum AUDIO_INPUT audio_input); + +int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type); +int cx231xx_set_video_alternate(struct cx231xx *dev); +int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt); +int is_fw_load(struct cx231xx *dev); +int cx231xx_check_fw(struct cx231xx *dev); +int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*isoc_copy) (struct cx231xx *dev, + struct urb *urb)); +int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*bulk_copy) (struct cx231xx *dev, + struct urb *urb)); +void cx231xx_stop_TS1(struct cx231xx *dev); +void cx231xx_start_TS1(struct cx231xx *dev); +void cx231xx_uninit_isoc(struct cx231xx *dev); +void cx231xx_uninit_bulk(struct cx231xx *dev); +int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode); +int cx231xx_unmute_audio(struct cx231xx *dev); +int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size); +void cx231xx_disable656(struct cx231xx *dev); +void cx231xx_enable656(struct cx231xx *dev); +int cx231xx_demod_reset(struct cx231xx *dev); +int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio); + +/* Device list functions */ +void cx231xx_release_resources(struct cx231xx *dev); +void cx231xx_release_analog_resources(struct cx231xx *dev); +int cx231xx_register_analog_devices(struct cx231xx *dev); +void cx231xx_remove_from_devlist(struct cx231xx *dev); +void cx231xx_add_into_devlist(struct cx231xx *dev); +void cx231xx_init_extension(struct cx231xx *dev); +void cx231xx_close_extension(struct cx231xx *dev); + +/* hardware init functions */ +int cx231xx_dev_init(struct cx231xx *dev); +void cx231xx_dev_uninit(struct cx231xx *dev); +void cx231xx_config_i2c(struct cx231xx *dev); +int cx231xx_config(struct cx231xx *dev); + +/* Stream control functions */ +int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask); +int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask); + +int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type); + +/* Power control functions */ +int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode); +int cx231xx_power_suspend(struct cx231xx *dev); + +/* chip specific control functions */ +int cx231xx_init_ctrl_pin_status(struct cx231xx *dev); +int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev, + u8 analog_or_digital); +int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3); + +/* video audio decoder related functions */ +void video_mux(struct cx231xx *dev, int index); +int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input); +int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input); +int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev); +int cx231xx_set_audio_input(struct cx231xx *dev, u8 input); + +/* Provided by cx231xx-video.c */ +int cx231xx_register_extension(struct cx231xx_ops *dev); +void cx231xx_unregister_extension(struct cx231xx_ops *dev); +void cx231xx_init_extension(struct cx231xx *dev); +void cx231xx_close_extension(struct cx231xx *dev); + +/* Provided by cx231xx-cards.c */ +extern void cx231xx_pre_card_setup(struct cx231xx *dev); +extern void cx231xx_card_setup(struct cx231xx *dev); +extern struct cx231xx_board cx231xx_boards[]; +extern struct usb_device_id cx231xx_id_table[]; +extern const unsigned int cx231xx_bcount; +int cx231xx_tuner_callback(void *ptr, int component, int command, int arg); + +/* cx23885-417.c */ +extern int cx231xx_417_register(struct cx231xx *dev); +extern void cx231xx_417_unregister(struct cx231xx *dev); + +/* cx23885-input.c */ + +#if defined(CONFIG_VIDEO_CX231XX_RC) +int cx231xx_ir_init(struct cx231xx *dev); +void cx231xx_ir_exit(struct cx231xx *dev); +#else +#define cx231xx_ir_init(dev) (0) +#define cx231xx_ir_exit(dev) (0) +#endif + + +/* printk macros */ + +#define cx231xx_err(fmt, arg...) do {\ + printk(KERN_ERR fmt , ##arg); } while (0) + +#define cx231xx_errdev(fmt, arg...) do {\ + printk(KERN_ERR "%s: "fmt,\ + dev->name , ##arg); } while (0) + +#define cx231xx_info(fmt, arg...) do {\ + printk(KERN_INFO "%s: "fmt,\ + dev->name , ##arg); } while (0) +#define cx231xx_warn(fmt, arg...) do {\ + printk(KERN_WARNING "%s: "fmt,\ + dev->name , ##arg); } while (0) + +static inline unsigned int norm_maxw(struct cx231xx *dev) +{ + if (dev->board.max_range_640_480) + return 640; + else + return 720; +} + +static inline unsigned int norm_maxh(struct cx231xx *dev) +{ + if (dev->board.max_range_640_480) + return 480; + else + return (dev->norm & V4L2_STD_625_50) ? 576 : 480; +} +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,536 @@ +/* + cx231xx-i2c.c - driver for Conexant Cx23100/101/102 USB video capture devices + + Copyright (C) 2008 + Based on em28xx driver + Based on Cx23885 driver + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "cx231xx.h" + +/* ----------------------------------------------------------- */ + +static unsigned int i2c_scan; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); + +static unsigned int i2c_debug; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + +#define dprintk1(lvl, fmt, args...) \ +do { \ + if (i2c_debug >= lvl) { \ + printk(fmt, ##args); \ + } \ +} while (0) + +#define dprintk2(lvl, fmt, args...) \ +do { \ + if (i2c_debug >= lvl) { \ + printk(KERN_DEBUG "%s at %s: " fmt, \ + dev->name, __func__ , ##args); \ + } \ +} while (0) + +static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus, + const struct i2c_msg *msg, int tuner_type) +{ + if (bus->nr != dev->board.tuner_i2c_master) + return false; + + if (msg->addr != dev->board.tuner_addr) + return false; + + if (dev->tuner_type != tuner_type) + return false; + + return true; +} + +/* + * cx231xx_i2c_send_bytes() + */ +int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg) +{ + struct cx231xx_i2c *bus = i2c_adap->algo_data; + struct cx231xx *dev = bus->dev; + struct cx231xx_i2c_xfer_data req_data; + int status = 0; + u16 size = 0; + u8 loop = 0; + u8 saddr_len = 1; + u8 *buf_ptr = NULL; + u16 saddr = 0; + u8 need_gpio = 0; + + if (is_tuner(dev, bus, msg, TUNER_XC5000)) { + size = msg->len; + + if (size == 2) { /* register write sub addr */ + /* Just writing sub address will cause problem + * to XC5000. So ignore the request */ + return 0; + } else if (size == 4) { /* register write with sub addr */ + if (msg->len >= 2) + saddr = msg->buf[0] << 8 | msg->buf[1]; + else if (msg->len == 1) + saddr = msg->buf[0]; + + switch (saddr) { + case 0x0000: /* start tuner calibration mode */ + need_gpio = 1; + /* FW Loading is done */ + dev->xc_fw_load_done = 1; + break; + case 0x000D: /* Set signal source */ + case 0x0001: /* Set TV standard - Video */ + case 0x0002: /* Set TV standard - Audio */ + case 0x0003: /* Set RF Frequency */ + need_gpio = 1; + break; + default: + if (dev->xc_fw_load_done) + need_gpio = 1; + break; + } + + if (need_gpio) { + dprintk1(1, + "GPIO WRITE: addr 0x%x, len %d, saddr 0x%x\n", + msg->addr, msg->len, saddr); + + return dev->cx231xx_gpio_i2c_write(dev, + msg->addr, + msg->buf, + msg->len); + } + } + + /* special case for Xc5000 tuner case */ + saddr_len = 1; + + /* adjust the length to correct length */ + size -= saddr_len; + buf_ptr = (u8 *) (msg->buf + 1); + + do { + /* prepare xfer_data struct */ + req_data.dev_addr = msg->addr; + req_data.direction = msg->flags; + req_data.saddr_len = saddr_len; + req_data.saddr_dat = msg->buf[0]; + req_data.buf_size = size > 16 ? 16 : size; + req_data.p_buffer = (u8 *) (buf_ptr + loop * 16); + + bus->i2c_nostop = (size > 16) ? 1 : 0; + bus->i2c_reserve = (loop == 0) ? 0 : 1; + + /* usb send command */ + status = dev->cx231xx_send_usb_command(bus, &req_data); + loop++; + + if (size >= 16) + size -= 16; + else + size = 0; + + } while (size > 0); + + bus->i2c_nostop = 0; + bus->i2c_reserve = 0; + + } else { /* regular case */ + + /* prepare xfer_data struct */ + req_data.dev_addr = msg->addr; + req_data.direction = msg->flags; + req_data.saddr_len = 0; + req_data.saddr_dat = 0; + req_data.buf_size = msg->len; + req_data.p_buffer = msg->buf; + + /* usb send command */ + status = dev->cx231xx_send_usb_command(bus, &req_data); + } + + return status < 0 ? status : 0; +} + +/* + * cx231xx_i2c_recv_bytes() + * read a byte from the i2c device + */ +static int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg) +{ + struct cx231xx_i2c *bus = i2c_adap->algo_data; + struct cx231xx *dev = bus->dev; + struct cx231xx_i2c_xfer_data req_data; + int status = 0; + u16 saddr = 0; + u8 need_gpio = 0; + + if (is_tuner(dev, bus, msg, TUNER_XC5000)) { + if (msg->len == 2) + saddr = msg->buf[0] << 8 | msg->buf[1]; + else if (msg->len == 1) + saddr = msg->buf[0]; + + if (dev->xc_fw_load_done) { + + switch (saddr) { + case 0x0009: /* BUSY check */ + dprintk1(1, + "GPIO R E A D: Special case BUSY check \n"); + /*Try read BUSY register, just set it to zero*/ + msg->buf[0] = 0; + if (msg->len == 2) + msg->buf[1] = 0; + return 0; + case 0x0004: /* read Lock status */ + need_gpio = 1; + break; + + } + + if (need_gpio) { + /* this is a special case to handle Xceive tuner + clock stretch issue with gpio based I2C */ + + dprintk1(1, + "GPIO R E A D: addr 0x%x, len %d, saddr 0x%x\n", + msg->addr, msg->len, + msg->buf[0] << 8 | msg->buf[1]); + + status = + dev->cx231xx_gpio_i2c_write(dev, msg->addr, + msg->buf, + msg->len); + status = + dev->cx231xx_gpio_i2c_read(dev, msg->addr, + msg->buf, + msg->len); + return status; + } + } + + /* prepare xfer_data struct */ + req_data.dev_addr = msg->addr; + req_data.direction = msg->flags; + req_data.saddr_len = msg->len; + req_data.saddr_dat = msg->buf[0] << 8 | msg->buf[1]; + req_data.buf_size = msg->len; + req_data.p_buffer = msg->buf; + + /* usb send command */ + status = dev->cx231xx_send_usb_command(bus, &req_data); + + } else { + + /* prepare xfer_data struct */ + req_data.dev_addr = msg->addr; + req_data.direction = msg->flags; + req_data.saddr_len = 0; + req_data.saddr_dat = 0; + req_data.buf_size = msg->len; + req_data.p_buffer = msg->buf; + + /* usb send command */ + status = dev->cx231xx_send_usb_command(bus, &req_data); + } + + return status < 0 ? status : 0; +} + +/* + * cx231xx_i2c_recv_bytes_with_saddr() + * read a byte from the i2c device + */ +static int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg1, + const struct i2c_msg *msg2) +{ + struct cx231xx_i2c *bus = i2c_adap->algo_data; + struct cx231xx *dev = bus->dev; + struct cx231xx_i2c_xfer_data req_data; + int status = 0; + u16 saddr = 0; + u8 need_gpio = 0; + + if (msg1->len == 2) + saddr = msg1->buf[0] << 8 | msg1->buf[1]; + else if (msg1->len == 1) + saddr = msg1->buf[0]; + + if (is_tuner(dev, bus, msg2, TUNER_XC5000)) { + if ((msg2->len < 16)) { + + dprintk1(1, + "i2c_read: addr 0x%x, len %d, saddr 0x%x, len %d\n", + msg2->addr, msg2->len, saddr, msg1->len); + + switch (saddr) { + case 0x0008: /* read FW load status */ + need_gpio = 1; + break; + case 0x0004: /* read Lock status */ + need_gpio = 1; + break; + } + + if (need_gpio) { + status = + dev->cx231xx_gpio_i2c_write(dev, msg1->addr, + msg1->buf, + msg1->len); + status = + dev->cx231xx_gpio_i2c_read(dev, msg2->addr, + msg2->buf, + msg2->len); + return status; + } + } + } + + /* prepare xfer_data struct */ + req_data.dev_addr = msg2->addr; + req_data.direction = msg2->flags; + req_data.saddr_len = msg1->len; + req_data.saddr_dat = saddr; + req_data.buf_size = msg2->len; + req_data.p_buffer = msg2->buf; + + /* usb send command */ + status = dev->cx231xx_send_usb_command(bus, &req_data); + + return status < 0 ? status : 0; +} + +/* + * cx231xx_i2c_check_for_device() + * check if there is a i2c_device at the supplied address + */ +static int cx231xx_i2c_check_for_device(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg) +{ + struct cx231xx_i2c *bus = i2c_adap->algo_data; + struct cx231xx *dev = bus->dev; + struct cx231xx_i2c_xfer_data req_data; + int status = 0; + + /* prepare xfer_data struct */ + req_data.dev_addr = msg->addr; + req_data.direction = msg->flags; + req_data.saddr_len = 0; + req_data.saddr_dat = 0; + req_data.buf_size = 0; + req_data.p_buffer = NULL; + + /* usb send command */ + status = dev->cx231xx_send_usb_command(bus, &req_data); + + return status < 0 ? status : 0; +} + +/* + * cx231xx_i2c_xfer() + * the main i2c transfer function + */ +static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct cx231xx_i2c *bus = i2c_adap->algo_data; + struct cx231xx *dev = bus->dev; + int addr, rc, i, byte; + + if (num <= 0) + return 0; + mutex_lock(&dev->i2c_lock); + for (i = 0; i < num; i++) { + + addr = msgs[i].addr >> 1; + + dprintk2(2, "%s %s addr=%x len=%d:", + (msgs[i].flags & I2C_M_RD) ? "read" : "write", + i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); + if (!msgs[i].len) { + /* no len: check only for device presence */ + rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]); + if (rc < 0) { + dprintk2(2, " no device\n"); + mutex_unlock(&dev->i2c_lock); + return rc; + } + + } else if (msgs[i].flags & I2C_M_RD) { + /* read bytes */ + rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]); + if (i2c_debug >= 2) { + for (byte = 0; byte < msgs[i].len; byte++) + printk(" %02x", msgs[i].buf[byte]); + } + } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && + msgs[i].addr == msgs[i + 1].addr + && (msgs[i].len <= 2) && (bus->nr < 3)) { + /* read bytes */ + rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap, + &msgs[i], + &msgs[i + 1]); + if (i2c_debug >= 2) { + for (byte = 0; byte < msgs[i].len; byte++) + printk(" %02x", msgs[i].buf[byte]); + } + i++; + } else { + /* write bytes */ + if (i2c_debug >= 2) { + for (byte = 0; byte < msgs[i].len; byte++) + printk(" %02x", msgs[i].buf[byte]); + } + rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]); + } + if (rc < 0) + goto err; + if (i2c_debug >= 2) + printk("\n"); + } + mutex_unlock(&dev->i2c_lock); + return num; +err: + dprintk2(2, " ERROR: %i\n", rc); + mutex_unlock(&dev->i2c_lock); + return rc; +} + +/* ----------------------------------------------------------- */ + +/* + * functionality() + */ +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; +} + +static struct i2c_algorithm cx231xx_algo = { + .master_xfer = cx231xx_i2c_xfer, + .functionality = functionality, +}; + +static struct i2c_adapter cx231xx_adap_template = { + .owner = THIS_MODULE, + .name = "cx231xx", + .algo = &cx231xx_algo, +}; + +static struct i2c_client cx231xx_client_template = { + .name = "cx231xx internal", +}; + +/* ----------------------------------------------------------- */ + +/* + * i2c_devs + * incomplete list of known devices + */ +static char *i2c_devs[128] = { + [0x60 >> 1] = "colibri", + [0x88 >> 1] = "hammerhead", + [0x8e >> 1] = "CIR", + [0x32 >> 1] = "GeminiIII", + [0x02 >> 1] = "Aquarius", + [0xa0 >> 1] = "eeprom", + [0xc0 >> 1] = "tuner", + [0xc2 >> 1] = "tuner", +}; + +/* + * cx231xx_do_i2c_scan() + * check i2c address range for devices + */ +void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c) +{ + unsigned char buf; + int i, rc; + + cx231xx_info(": Checking for I2C devices ..\n"); + for (i = 0; i < 128; i++) { + c->addr = i; + rc = i2c_master_recv(c, &buf, 0); + if (rc < 0) + continue; + cx231xx_info("%s: i2c scan: found device @ 0x%x [%s]\n", + dev->name, i << 1, + i2c_devs[i] ? i2c_devs[i] : "???"); + } + cx231xx_info(": Completed Checking for I2C devices.\n"); +} + +/* + * cx231xx_i2c_register() + * register i2c bus + */ +int cx231xx_i2c_register(struct cx231xx_i2c *bus) +{ + struct cx231xx *dev = bus->dev; + + BUG_ON(!dev->cx231xx_send_usb_command); + + memcpy(&bus->i2c_adap, &cx231xx_adap_template, sizeof(bus->i2c_adap)); + memcpy(&bus->i2c_algo, &cx231xx_algo, sizeof(bus->i2c_algo)); + memcpy(&bus->i2c_client, &cx231xx_client_template, + sizeof(bus->i2c_client)); + + bus->i2c_adap.dev.parent = &dev->udev->dev; + + strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + + bus->i2c_algo.data = bus; + bus->i2c_adap.algo_data = bus; + i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); + i2c_add_adapter(&bus->i2c_adap); + + bus->i2c_client.adapter = &bus->i2c_adap; + + if (0 == bus->i2c_rc) { + if (i2c_scan) + cx231xx_do_i2c_scan(dev, &bus->i2c_client); + } else + cx231xx_warn("%s: i2c bus %d register FAILED\n", + dev->name, bus->nr); + + return bus->i2c_rc; +} + +/* + * cx231xx_i2c_unregister() + * unregister i2c_bus + */ +int cx231xx_i2c_unregister(struct cx231xx_i2c *bus) +{ + i2c_del_adapter(&bus->i2c_adap); + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-input.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-input.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,112 @@ +/* + * cx231xx IR glue driver + * + * Copyright (C) 2010 Mauro Carvalho Chehab + * + * Polaris (cx231xx) has its support for IR's with a design close to MCE. + * however, a few designs are using an external I2C chip for IR, instead + * of using the one provided by the chip. + * This driver provides support for those extra devices + * + * 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 version 2. + * + * 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. + */ + +#include "cx231xx.h" +#include +#include + +#define MODULE_NAME "cx231xx-input" + +static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key, + u32 *ir_raw) +{ + u8 cmd, scancode; + + dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__); + + /* poll IR chip */ + if (1 != i2c_master_recv(ir->c, &cmd, 1)) + return -EIO; + + /* it seems that 0xFE indicates that a button is still hold + down, while 0xff indicates that no button is hold + down. 0xfe sequences are sometimes interrupted by 0xFF */ + + if (cmd == 0xff) + return 0; + + scancode = + ((cmd & 0x01) ? 0x80 : 0) | + ((cmd & 0x02) ? 0x40 : 0) | + ((cmd & 0x04) ? 0x20 : 0) | + ((cmd & 0x08) ? 0x10 : 0) | + ((cmd & 0x10) ? 0x08 : 0) | + ((cmd & 0x20) ? 0x04 : 0) | + ((cmd & 0x40) ? 0x02 : 0) | + ((cmd & 0x80) ? 0x01 : 0); + + dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n", + cmd, scancode); + + *ir_key = scancode; + *ir_raw = scancode; + return 1; +} + +int cx231xx_ir_init(struct cx231xx *dev) +{ + struct i2c_board_info info; + u8 ir_i2c_bus; + + dev_dbg(&dev->udev->dev, "%s\n", __func__); + + /* Only initialize if a rc keycode map is defined */ + if (!cx231xx_boards[dev->model].rc_map_name) + return -ENODEV; + + request_module("ir-kbd-i2c"); + + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&dev->init_data, 0, sizeof(dev->init_data)); + dev->init_data.rc_dev = rc_allocate_device(); + if (!dev->init_data.rc_dev) + return -ENOMEM; + + dev->init_data.name = cx231xx_boards[dev->model].name; + + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + info.platform_data = &dev->init_data; + + /* + * Board-dependent values + * + * For now, there's just one type of hardware design using + * an i2c device. + */ + dev->init_data.get_key = get_key_isdbt; + dev->init_data.ir_codes = cx231xx_boards[dev->model].rc_map_name; + /* The i2c micro-controller only outputs the cmd part of NEC protocol */ + dev->init_data.rc_dev->scanmask = 0xff; + dev->init_data.rc_dev->driver_name = "cx231xx"; + dev->init_data.type = RC_TYPE_NEC; + info.addr = 0x30; + + /* Load and bind ir-kbd-i2c */ + ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master; + dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n", + ir_i2c_bus, info.addr); + i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info); + + return 0; +} + +void cx231xx_ir_exit(struct cx231xx *dev) +{ +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,795 @@ +/* + cx231xx-pcb-config.c - driver for Conexant + Cx23100/101/102 USB video capture devices + + Copyright (C) 2008 + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx231xx.h" +#include "cx231xx-conf-reg.h" + +static unsigned int pcb_debug; +module_param(pcb_debug, int, 0644); +MODULE_PARM_DESC(pcb_debug, "enable pcb config debug messages [video]"); + +/******************************************************************************/ + +struct pcb_config cx231xx_Scenario[] = { + { + INDEX_SELFPOWER_DIGITAL_ONLY, /* index */ + USB_SELF_POWER, /* power_type */ + 0, /* speed , not decide yet */ + MOD_DIGITAL, /* mode */ + SOURCE_TS_BDA, /* ts1_source, digital tv only */ + NOT_SUPPORTED, /* ts2_source */ + NOT_SUPPORTED, /* analog source */ + + 0, /* digital_index */ + 0, /* analog index */ + 0, /* dif_index */ + 0, /* external_index */ + + 1, /* only one configuration */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + NOT_SUPPORTED, /* AUDIO */ + NOT_SUPPORTED, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + , + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + , + /* full-speed config */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + NOT_SUPPORTED, /* AUDIO */ + NOT_SUPPORTED, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + } + , + + { + INDEX_SELFPOWER_DUAL_DIGITAL, /* index */ + USB_SELF_POWER, /* power_type */ + 0, /* speed , not decide yet */ + MOD_DIGITAL, /* mode */ + SOURCE_TS_BDA, /* ts1_source, digital tv only */ + 0, /* ts2_source,need update from register */ + NOT_SUPPORTED, /* analog source */ + 0, /* digital_index */ + 0, /* analog index */ + 0, /* dif_index */ + 0, /* external_index */ + + 1, /* only one configuration */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + 2, /* TS2 index */ + NOT_SUPPORTED, /* AUDIO */ + NOT_SUPPORTED, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + , + /* full-speed */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + 2, /* TS2 index */ + NOT_SUPPORTED, /* AUDIO */ + NOT_SUPPORTED, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + } + , + + { + INDEX_SELFPOWER_ANALOG_ONLY, /* index */ + USB_SELF_POWER, /* power_type */ + 0, /* speed , not decide yet */ + MOD_ANALOG | MOD_DIF | MOD_EXTERNAL, /* mode ,analog tv only */ + NOT_SUPPORTED, /* ts1_source, NOT SUPPORT */ + NOT_SUPPORTED, /* ts2_source,NOT SUPPORT */ + 0, /* analog source, need update */ + + 0, /* digital_index */ + 0, /* analog index */ + 0, /* dif_index */ + 0, /* external_index */ + + 1, /* only one configuration */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + NOT_SUPPORTED, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + 1, /* AUDIO */ + 2, /* VIDEO */ + 3, /* VANC */ + 4, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + , + /* full-speed */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + NOT_SUPPORTED, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + 1, /* AUDIO */ + 2, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + } + , + + { + INDEX_SELFPOWER_DUAL, /* index */ + USB_SELF_POWER, /* power_type */ + 0, /* speed , not decide yet */ + /* mode ,analog tv and digital path */ + MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL, + 0, /* ts1_source,will update in register */ + NOT_SUPPORTED, /* ts2_source,NOT SUPPORT */ + 0, /* analog source need update */ + 0, /* digital_index */ + 0, /* analog index */ + 0, /* dif_index */ + 0, /* external_index */ + 1, /* only one configuration */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + 2, /* AUDIO */ + 3, /* VIDEO */ + 4, /* VANC */ + 5, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + , + /* full-speed */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + 2, /* AUDIO */ + 3, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + } + , + + { + INDEX_SELFPOWER_TRIPLE, /* index */ + USB_SELF_POWER, /* power_type */ + 0, /* speed , not decide yet */ + /* mode ,analog tv and digital path */ + MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL, + 0, /* ts1_source, update in register */ + 0, /* ts2_source,update in register */ + 0, /* analog source, need update */ + + 0, /* digital_index */ + 0, /* analog index */ + 0, /* dif_index */ + 0, /* external_index */ + 1, /* only one configuration */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + 2, /* TS2 index */ + 3, /* AUDIO */ + 4, /* VIDEO */ + 5, /* VANC */ + 6, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + , + /* full-speed */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + 2, /* TS2 index */ + 3, /* AUDIO */ + 4, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + } + , + + { + INDEX_SELFPOWER_COMPRESSOR, /* index */ + USB_SELF_POWER, /* power_type */ + 0, /* speed , not decide yet */ + /* mode ,analog tv AND DIGITAL path */ + MOD_ANALOG | MOD_DIF | MOD_DIGITAL | MOD_EXTERNAL, + NOT_SUPPORTED, /* ts1_source, disable */ + SOURCE_TS_BDA, /* ts2_source */ + 0, /* analog source,need update */ + 0, /* digital_index */ + 0, /* analog index */ + 0, /* dif_index */ + 0, /* external_index */ + 1, /* only one configuration */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + NOT_SUPPORTED, /* ts1 index */ + 1, /* TS2 index */ + 2, /* AUDIO */ + 3, /* VIDEO */ + 4, /* VANC */ + 5, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + , + /* full-speed */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + NOT_SUPPORTED, /* ts1 index */ + 1, /* TS2 index */ + 2, /* AUDIO */ + 3, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + } + , + + { + INDEX_BUSPOWER_DIGITAL_ONLY, /* index */ + USB_BUS_POWER, /* power_type */ + 0, /* speed , not decide yet */ + MOD_DIGITAL, /* mode ,analog tv AND DIGITAL path */ + SOURCE_TS_BDA, /* ts1_source, disable */ + NOT_SUPPORTED, /* ts2_source */ + NOT_SUPPORTED, /* analog source */ + + 0, /* digital_index */ + 0, /* analog index */ + 0, /* dif_index */ + 0, /* external_index */ + + 1, /* only one configuration */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index = 2 */ + 1, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + NOT_SUPPORTED, /* AUDIO */ + NOT_SUPPORTED, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + , + /* full-speed */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index = 2 */ + 1, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + NOT_SUPPORTED, /* AUDIO */ + NOT_SUPPORTED, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + } + , + { + INDEX_BUSPOWER_ANALOG_ONLY, /* index */ + USB_BUS_POWER, /* power_type */ + 0, /* speed , not decide yet */ + MOD_ANALOG, /* mode ,analog tv AND DIGITAL path */ + NOT_SUPPORTED, /* ts1_source, disable */ + NOT_SUPPORTED, /* ts2_source */ + SOURCE_ANALOG, /* analog source--analog */ + 0, /* digital_index */ + 0, /* analog index */ + 0, /* dif_index */ + 0, /* external_index */ + 1, /* only one configuration */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + NOT_SUPPORTED, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + 1, /* AUDIO */ + 2, /* VIDEO */ + 3, /* VANC */ + 4, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + , + { /* full-speed */ + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + NOT_SUPPORTED, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + 1, /* AUDIO */ + 2, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + } + , + { + INDEX_BUSPOWER_DIF_ONLY, /* index */ + USB_BUS_POWER, /* power_type */ + 0, /* speed , not decide yet */ + /* mode ,analog tv AND DIGITAL path */ + MOD_DIF | MOD_ANALOG | MOD_DIGITAL | MOD_EXTERNAL, + SOURCE_TS_BDA, /* ts1_source, disable */ + NOT_SUPPORTED, /* ts2_source */ + SOURCE_DIF | SOURCE_ANALOG | SOURCE_EXTERNAL, /* analog source, dif */ + 0, /* digital_index */ + 0, /* analog index */ + 0, /* dif_index */ + 0, /* external_index */ + 1, /* only one configuration */ + { + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + 2, /* AUDIO */ + 3, /* VIDEO */ + 4, /* VANC */ + 5, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + , + { /* full speed */ + { + 0, /* config index */ + { + 0, /* interrupt ep index */ + 1, /* ts1 index */ + NOT_SUPPORTED, /* TS2 index */ + 2, /* AUDIO */ + 3, /* VIDEO */ + NOT_SUPPORTED, /* VANC */ + NOT_SUPPORTED, /* HANC */ + NOT_SUPPORTED /* ir_index */ + } + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + , + {NOT_SUPPORTED, {NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED, NOT_SUPPORTED, NOT_SUPPORTED, + NOT_SUPPORTED} + } + } + } + , + +}; + +/*****************************************************************/ + +u32 initialize_cx231xx(struct cx231xx *dev) +{ + u32 config_info = 0; + struct pcb_config *p_pcb_info; + u8 usb_speed = 1; /* from register,1--HS, 0--FS */ + u8 data[4] = { 0, 0, 0, 0 }; + u32 ts1_source = 0; + u32 ts2_source = 0; + u32 analog_source = 0; + u8 _current_scenario_idx = 0xff; + + ts1_source = SOURCE_TS_BDA; + ts2_source = SOURCE_TS_BDA; + + /* read board config register to find out which + pcb config it is related to */ + cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4); + + config_info = *((u32 *) data); + usb_speed = (u8) (config_info & 0x1); + + /* Verify this device belongs to Bus power or Self power device */ + if (config_info & BUS_POWER) { /* bus-power */ + switch (config_info & BUSPOWER_MASK) { + case TS1_PORT | BUS_POWER: + cx231xx_Scenario[INDEX_BUSPOWER_DIGITAL_ONLY].speed = + usb_speed; + p_pcb_info = + &cx231xx_Scenario[INDEX_BUSPOWER_DIGITAL_ONLY]; + _current_scenario_idx = INDEX_BUSPOWER_DIGITAL_ONLY; + break; + case AVDEC_ENABLE | BUS_POWER: + cx231xx_Scenario[INDEX_BUSPOWER_ANALOG_ONLY].speed = + usb_speed; + p_pcb_info = + &cx231xx_Scenario[INDEX_BUSPOWER_ANALOG_ONLY]; + _current_scenario_idx = INDEX_BUSPOWER_ANALOG_ONLY; + break; + case AVDEC_ENABLE | BUS_POWER | TS1_PORT: + cx231xx_Scenario[INDEX_BUSPOWER_DIF_ONLY].speed = + usb_speed; + p_pcb_info = &cx231xx_Scenario[INDEX_BUSPOWER_DIF_ONLY]; + _current_scenario_idx = INDEX_BUSPOWER_DIF_ONLY; + break; + default: + cx231xx_info("bad config in buspower!!!!\n"); + cx231xx_info("config_info=%x\n", + (config_info & BUSPOWER_MASK)); + return 1; + } + } else { /* self-power */ + + switch (config_info & SELFPOWER_MASK) { + case TS1_PORT | SELF_POWER: + cx231xx_Scenario[INDEX_SELFPOWER_DIGITAL_ONLY].speed = + usb_speed; + p_pcb_info = + &cx231xx_Scenario[INDEX_SELFPOWER_DIGITAL_ONLY]; + _current_scenario_idx = INDEX_SELFPOWER_DIGITAL_ONLY; + break; + case TS1_TS2_PORT | SELF_POWER: + cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL].speed = + usb_speed; + cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL]. + ts2_source = ts2_source; + p_pcb_info = + &cx231xx_Scenario[INDEX_SELFPOWER_DUAL_DIGITAL]; + _current_scenario_idx = INDEX_SELFPOWER_DUAL_DIGITAL; + break; + case AVDEC_ENABLE | SELF_POWER: + cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY].speed = + usb_speed; + cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY]. + analog_source = analog_source; + p_pcb_info = + &cx231xx_Scenario[INDEX_SELFPOWER_ANALOG_ONLY]; + _current_scenario_idx = INDEX_SELFPOWER_ANALOG_ONLY; + break; + case AVDEC_ENABLE | TS1_PORT | SELF_POWER: + cx231xx_Scenario[INDEX_SELFPOWER_DUAL].speed = + usb_speed; + cx231xx_Scenario[INDEX_SELFPOWER_DUAL].ts1_source = + ts1_source; + cx231xx_Scenario[INDEX_SELFPOWER_DUAL].analog_source = + analog_source; + p_pcb_info = &cx231xx_Scenario[INDEX_SELFPOWER_DUAL]; + _current_scenario_idx = INDEX_SELFPOWER_DUAL; + break; + case AVDEC_ENABLE | TS1_TS2_PORT | SELF_POWER: + cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].speed = + usb_speed; + cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].ts1_source = + ts1_source; + cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].ts2_source = + ts2_source; + cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE].analog_source = + analog_source; + p_pcb_info = &cx231xx_Scenario[INDEX_SELFPOWER_TRIPLE]; + _current_scenario_idx = INDEX_SELFPOWER_TRIPLE; + break; + case AVDEC_ENABLE | TS1VIP_TS2_PORT | SELF_POWER: + cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR].speed = + usb_speed; + cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR]. + analog_source = analog_source; + p_pcb_info = + &cx231xx_Scenario[INDEX_SELFPOWER_COMPRESSOR]; + _current_scenario_idx = INDEX_SELFPOWER_COMPRESSOR; + break; + default: + cx231xx_info("bad senario!!!!!\n"); + cx231xx_info("config_info=%x\n", + (config_info & SELFPOWER_MASK)); + return 1; + } + } + + dev->current_scenario_idx = _current_scenario_idx; + + memcpy(&dev->current_pcb_config, p_pcb_info, + sizeof(struct pcb_config)); + + if (pcb_debug) { + cx231xx_info("SC(0x00) register = 0x%x\n", config_info); + cx231xx_info("scenario %d\n", + (dev->current_pcb_config.index) + 1); + cx231xx_info("type=%x\n", dev->current_pcb_config.type); + cx231xx_info("mode=%x\n", dev->current_pcb_config.mode); + cx231xx_info("speed=%x\n", dev->current_pcb_config.speed); + cx231xx_info("ts1_source=%x\n", + dev->current_pcb_config.ts1_source); + cx231xx_info("ts2_source=%x\n", + dev->current_pcb_config.ts2_source); + cx231xx_info("analog_source=%x\n", + dev->current_pcb_config.analog_source); + } + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-pcb-cfg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,231 @@ +/* + cx231xx-pcb-cfg.h - driver for Conexant + Cx23100/101/102 USB video capture devices + + Copyright (C) 2008 + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _PCB_CONFIG_H_ +#define _PCB_CONFIG_H_ + +#include +#include + +/*************************************************************************** + * Class Information * +***************************************************************************/ +#define CLASS_DEFAULT 0xFF + +enum VENDOR_REQUEST_TYPE { + /* Set/Get I2C */ + VRT_SET_I2C0 = 0x0, + VRT_SET_I2C1 = 0x1, + VRT_SET_I2C2 = 0x2, + VRT_GET_I2C0 = 0x4, + VRT_GET_I2C1 = 0x5, + VRT_GET_I2C2 = 0x6, + + /* Set/Get GPIO */ + VRT_SET_GPIO = 0x8, + VRT_GET_GPIO = 0x9, + + /* Set/Get GPIE */ + VRT_SET_GPIE = 0xA, + VRT_GET_GPIE = 0xB, + + /* Set/Get Register Control/Status */ + VRT_SET_REGISTER = 0xC, + VRT_GET_REGISTER = 0xD, + + /* Get Extended Compat ID Descriptor */ + VRT_GET_EXTCID_DESC = 0xFF, +}; + +enum BYTE_ENABLE_MASK { + ENABLE_ONE_BYTE = 0x1, + ENABLE_TWE_BYTE = 0x3, + ENABLE_THREE_BYTE = 0x7, + ENABLE_FOUR_BYTE = 0xF, +}; + +#define SPEED_MASK 0x1 +enum USB_SPEED{ + FULL_SPEED = 0x0, /* 0: full speed */ + HIGH_SPEED = 0x1 /* 1: high speed */ +}; + +enum _true_false{ + FALSE = 0, + TRUE = 1 +}; + +#define TS_MASK 0x6 +enum TS_PORT{ + NO_TS_PORT = 0x0, /* 2'b00: Neither port used. PCB not a Hybrid, + only offers Analog TV or Video */ + TS1_PORT = 0x4, /* 2'b10: TS1 Input (Hybrid mode : + Digital or External Analog/Compressed source) */ + TS1_TS2_PORT = 0x6, /* 2'b11: TS1 & TS2 Inputs + (Dual inputs from Digital and/or + External Analog/Compressed sources) */ + TS1_EXT_CLOCK = 0x6, /* 2'b11: TS1 & TS2 as selector + to external clock */ + TS1VIP_TS2_PORT = 0x2 /* 2'b01: TS1 used as 656/VIP Output, + TS2 Input (from Compressor) */ +}; + +#define EAVP_MASK 0x8 +enum EAV_PRESENT{ + NO_EXTERNAL_AV = 0x0, /* 0: No External A/V inputs + (no need for i2s blcok), + Analog Tuner must be present */ + EXTERNAL_AV = 0x8 /* 1: External A/V inputs + present (requires i2s blk) */ +}; + +#define ATM_MASK 0x30 +enum AT_MODE{ + DIF_TUNER = 0x30, /* 2'b11: IF Tuner (requires use of DIF) */ + BASEBAND_SOUND = 0x20, /* 2'b10: Baseband Composite & + Sound-IF Signals present */ + NO_TUNER = 0x10 /* 2'b0x: No Analog Tuner present */ +}; + +#define PWR_SEL_MASK 0x40 +enum POWE_TYPE{ + SELF_POWER = 0x0, /* 0: self power */ + BUS_POWER = 0x40 /* 1: bus power */ +}; + +enum USB_POWE_TYPE{ + USB_SELF_POWER = 0, + USB_BUS_POWER +}; + +#define BO_0_MASK 0x80 +enum AVDEC_STATUS{ + AVDEC_DISABLE = 0x0, /* 0: A/V Decoder Disabled */ + AVDEC_ENABLE = 0x80 /* 1: A/V Decoder Enabled */ +}; + +#define BO_1_MASK 0x100 + +#define BUSPOWER_MASK 0xC4 /* for Polaris spec 0.8 */ +#define SELFPOWER_MASK 0x86 + +/***************************************************************************/ +#define NOT_DECIDE_YET 0xFE +#define NOT_SUPPORTED 0xFF + +/*************************************************************************** + * for mod field use * +***************************************************************************/ +#define MOD_DIGITAL 0x1 +#define MOD_ANALOG 0x2 +#define MOD_DIF 0x4 +#define MOD_EXTERNAL 0x8 +#define CAP_ALL_MOD 0x0f + +/*************************************************************************** + * source define * +***************************************************************************/ +#define SOURCE_DIGITAL 0x1 +#define SOURCE_ANALOG 0x2 +#define SOURCE_DIF 0x4 +#define SOURCE_EXTERNAL 0x8 +#define SOURCE_TS_BDA 0x10 +#define SOURCE_TS_ENCODE 0x20 +#define SOURCE_TS_EXTERNAL 0x40 + +/*************************************************************************** + * interface information define * +***************************************************************************/ +struct INTERFACE_INFO { + u8 interrupt_index; + u8 ts1_index; + u8 ts2_index; + u8 audio_index; + u8 video_index; + u8 vanc_index; /* VBI */ + u8 hanc_index; /* Sliced CC */ + u8 ir_index; +}; + +enum INDEX_INTERFACE_INFO{ + INDEX_INTERRUPT = 0x0, + INDEX_TS1, + INDEX_TS2, + INDEX_AUDIO, + INDEX_VIDEO, + INDEX_VANC, + INDEX_HANC, + INDEX_IR, +}; + +/*************************************************************************** + * configuration information define * +***************************************************************************/ +struct CONFIG_INFO { + u8 config_index; + struct INTERFACE_INFO interface_info; +}; + +struct pcb_config { + u8 index; + u8 type; /* bus power or self power, + self power--0, bus_power--1 */ + u8 speed; /* usb speed, 2.0--1, 1.1--0 */ + u8 mode; /* digital , anlog, dif or external A/V */ + u32 ts1_source; /* three source -- BDA,External,encode */ + u32 ts2_source; + u32 analog_source; + u8 digital_index; /* bus-power used */ + u8 analog_index; /* bus-power used */ + u8 dif_index; /* bus-power used */ + u8 external_index; /* bus-power used */ + u8 config_num; /* current config num, 0,1,2, + for self-power, always 0 */ + struct CONFIG_INFO hs_config_info[3]; + struct CONFIG_INFO fs_config_info[3]; +}; + +enum INDEX_PCB_CONFIG{ + INDEX_SELFPOWER_DIGITAL_ONLY = 0x0, + INDEX_SELFPOWER_DUAL_DIGITAL, + INDEX_SELFPOWER_ANALOG_ONLY, + INDEX_SELFPOWER_DUAL, + INDEX_SELFPOWER_TRIPLE, + INDEX_SELFPOWER_COMPRESSOR, + INDEX_BUSPOWER_DIGITAL_ONLY, + INDEX_BUSPOWER_ANALOG_ONLY, + INDEX_BUSPOWER_DIF_ONLY, + INDEX_BUSPOWER_EXTERNAL_ONLY, + INDEX_BUSPOWER_EXTERNAL_ANALOG, + INDEX_BUSPOWER_EXTERNAL_DIF, + INDEX_BUSPOWER_EXTERNAL_DIGITAL, + INDEX_BUSPOWER_DIGITAL_ANALOG, + INDEX_BUSPOWER_DIGITAL_DIF, + INDEX_BUSPOWER_DIGITAL_ANALOG_EXTERNAL, + INDEX_BUSPOWER_DIGITAL_DIF_EXTERNAL, +}; + +/***************************************************************************/ +struct cx231xx; + +u32 initialize_cx231xx(struct cx231xx *p_dev); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1564 @@ +/* + cx231xx-reg.h - driver for Conexant Cx23100/101/102 + USB video capture devices + + Copyright (C) 2008 + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CX231XX_REG_H +#define _CX231XX_REG_H + +/***************************************************************************** + * VBI codes * +*****************************************************************************/ + +#define SAV_ACTIVE_VIDEO_FIELD1 0x80 +#define EAV_ACTIVE_VIDEO_FIELD1 0x90 + +#define SAV_ACTIVE_VIDEO_FIELD2 0xc0 +#define EAV_ACTIVE_VIDEO_FIELD2 0xd0 + +#define SAV_VBLANK_FIELD1 0xa0 +#define EAV_VBLANK_FIELD1 0xb0 + +#define SAV_VBLANK_FIELD2 0xe0 +#define EAV_VBLANK_FIELD2 0xf0 + +#define SAV_VBI_FIELD1 0x20 +#define EAV_VBI_FIELD1 0x30 + +#define SAV_VBI_FIELD2 0x60 +#define EAV_VBI_FIELD2 0x70 + +/*****************************************************************************/ +/* Audio ADC Registers */ +#define CH_PWR_CTRL1 0x0000000e +#define CH_PWR_CTRL2 0x0000000f +/*****************************************************************************/ + +#define HOST_REG1 0x000 +#define FLD_FORCE_CHIP_SEL 0x80 +#define FLD_AUTO_INC_DIS 0x20 +#define FLD_PREFETCH_EN 0x10 +/* Reserved [2:3] */ +#define FLD_DIGITAL_PWR_DN 0x02 +#define FLD_SLEEP 0x01 + +/*****************************************************************************/ +#define HOST_REG2 0x001 + +/*****************************************************************************/ +#define HOST_REG3 0x002 + +/*****************************************************************************/ +/* added for polaris */ +#define GPIO_PIN_CTL0 0x3 +#define GPIO_PIN_CTL1 0x4 +#define GPIO_PIN_CTL2 0x5 +#define GPIO_PIN_CTL3 0x6 +#define TS1_PIN_CTL0 0x7 +#define TS1_PIN_CTL1 0x8 +/*****************************************************************************/ + +#define FLD_CLK_IN_EN 0x80 +#define FLD_XTAL_CTRL 0x70 +#define FLD_BB_CLK_MODE 0x0C +#define FLD_REF_DIV_PLL 0x02 +#define FLD_REF_SEL_PLL1 0x01 + +/*****************************************************************************/ +#define CHIP_CTRL 0x100 +/* Reserved [27] */ +/* Reserved [31:21] */ +#define FLD_CHIP_ACFG_DIS 0x00100000 +/* Reserved [19] */ +#define FLD_DUAL_MODE_ADC2 0x00040000 +#define FLD_SIF_EN 0x00020000 +#define FLD_SOFT_RST 0x00010000 +#define FLD_DEVICE_ID 0x0000ffff + +/*****************************************************************************/ +#define AFE_CTRL 0x104 +#define AFE_CTRL_C2HH_SRC_CTRL 0x104 +#define FLD_DIF_OUT_SEL 0xc0000000 +#define FLD_AUX_PLL_CLK_ALT_SEL 0x3c000000 +#define FLD_UV_ORDER_MODE 0x02000000 +#define FLD_FUNC_MODE 0x01800000 +#define FLD_ROT1_PHASE_CTL 0x007f8000 +#define FLD_AUD_IN_SEL 0x00004000 +#define FLD_LUMA_IN_SEL 0x00002000 +#define FLD_CHROMA_IN_SEL 0x00001000 +/* reserve [11:10] */ +#define FLD_INV_SPEC_DIS 0x00000200 +#define FLD_VGA_SEL_CH3 0x00000100 +#define FLD_VGA_SEL_CH2 0x00000080 +#define FLD_VGA_SEL_CH1 0x00000040 +#define FLD_DCR_BYP_CH1 0x00000020 +#define FLD_DCR_BYP_CH2 0x00000010 +#define FLD_DCR_BYP_CH3 0x00000008 +#define FLD_EN_12DB_CH3 0x00000004 +#define FLD_EN_12DB_CH2 0x00000002 +#define FLD_EN_12DB_CH1 0x00000001 + +/* redefine in Cx231xx */ +/*****************************************************************************/ +#define DC_CTRL1 0x108 +/* reserve [31:30] */ +#define FLD_CLAMP_LVL_CH1 0x3fff8000 +#define FLD_CLAMP_LVL_CH2 0x00007fff +/*****************************************************************************/ + +/*****************************************************************************/ +#define DC_CTRL2 0x10c +/* reserve [31:28] */ +#define FLD_CLAMP_LVL_CH3 0x00fffe00 +#define FLD_CLAMP_WIND_LENTH 0x000001e0 +#define FLD_C2HH_SAT_MIN 0x0000001e +#define FLD_FLT_BYP_SEL 0x00000001 +/*****************************************************************************/ + +/*****************************************************************************/ +#define DC_CTRL3 0x110 +/* reserve [31:16] */ +#define FLD_ERR_GAIN_CTL 0x00070000 +#define FLD_LPF_MIN 0x0000ffff +/*****************************************************************************/ + +/*****************************************************************************/ +#define DC_CTRL4 0x114 +/* reserve [31:31] */ +#define FLD_INTG_CH1 0x7fffffff +/*****************************************************************************/ + +/*****************************************************************************/ +#define DC_CTRL5 0x118 +/* reserve [31:31] */ +#define FLD_INTG_CH2 0x7fffffff +/*****************************************************************************/ + +/*****************************************************************************/ +#define DC_CTRL6 0x11c +/* reserve [31:31] */ +#define FLD_INTG_CH3 0x7fffffff +/*****************************************************************************/ + +/*****************************************************************************/ +#define PIN_CTRL 0x120 +#define FLD_OEF_AGC_RF 0x00000001 +#define FLD_OEF_AGC_IFVGA 0x00000002 +#define FLD_OEF_AGC_IF 0x00000004 +#define FLD_REG_BO_PUD 0x80000000 +#define FLD_IR_IRQ_STAT 0x40000000 +#define FLD_AUD_IRQ_STAT 0x20000000 +#define FLD_VID_IRQ_STAT 0x10000000 +/* Reserved [27:26] */ +#define FLD_IRQ_N_OUT_EN 0x02000000 +#define FLD_IRQ_N_POLAR 0x01000000 +/* Reserved [23:6] */ +#define FLD_OE_AUX_PLL_CLK 0x00000020 +#define FLD_OE_I2S_BCLK 0x00000010 +#define FLD_OE_I2S_WCLK 0x00000008 +#define FLD_OE_AGC_IF 0x00000004 +#define FLD_OE_AGC_IFVGA 0x00000002 +#define FLD_OE_AGC_RF 0x00000001 + +/*****************************************************************************/ +#define AUD_IO_CTRL 0x124 +/* Reserved [31:8] */ +#define FLD_I2S_PORT_DIR 0x00000080 +#define FLD_I2S_OUT_SRC 0x00000040 +#define FLD_AUD_CHAN3_SRC 0x00000030 +#define FLD_AUD_CHAN2_SRC 0x0000000c +#define FLD_AUD_CHAN1_SRC 0x00000003 + +/*****************************************************************************/ +#define AUD_LOCK1 0x128 +#define FLD_AUD_LOCK_KI_SHIFT 0xc0000000 +#define FLD_AUD_LOCK_KD_SHIFT 0x30000000 +/* Reserved [27:25] */ +#define FLD_EN_AV_LOCK 0x01000000 +#define FLD_VID_COUNT 0x00ffffff + +/*****************************************************************************/ +#define AUD_LOCK2 0x12c +#define FLD_AUD_LOCK_KI_MULT 0xf0000000 +#define FLD_AUD_LOCK_KD_MULT 0x0F000000 +/* Reserved [23:22] */ +#define FLD_AUD_LOCK_FREQ_SHIFT 0x00300000 +#define FLD_AUD_COUNT 0x000fffff + +/*****************************************************************************/ +#define AFE_DIAG_CTRL1 0x134 +/* Reserved [31:16] */ +#define FLD_CUV_DLY_LENGTH 0x0000ff00 +#define FLD_YC_DLY_LENGTH 0x000000ff + +/*****************************************************************************/ +/* Poalris redefine */ +#define AFE_DIAG_CTRL3 0x138 +/* Reserved [31:26] */ +#define FLD_AUD_DUAL_FLAG_POL 0x02000000 +#define FLD_VID_DUAL_FLAG_POL 0x01000000 +/* Reserved [23:23] */ +#define FLD_COL_CLAMP_DIS_CH1 0x00400000 +#define FLD_COL_CLAMP_DIS_CH2 0x00200000 +#define FLD_COL_CLAMP_DIS_CH3 0x00100000 + +#define TEST_CTRL1 0x144 +/* Reserved [31:29] */ +#define FLD_LBIST_EN 0x10000000 +/* Reserved [27:10] */ +#define FLD_FI_BIST_INTR_R 0x0000200 +#define FLD_FI_BIST_INTR_L 0x0000100 +#define FLD_BIST_FAIL_AUD_PLL 0x0000080 +#define FLD_BIST_INTR_AUD_PLL 0x0000040 +#define FLD_BIST_FAIL_VID_PLL 0x0000020 +#define FLD_BIST_INTR_VID_PLL 0x0000010 +/* Reserved [3:1] */ +#define FLD_CIR_TEST_DIS 0x00000001 + +/*****************************************************************************/ +#define TEST_CTRL2 0x148 +#define FLD_TSXCLK_POL_CTL 0x80000000 +#define FLD_ISO_CTL_SEL 0x40000000 +#define FLD_ISO_CTL_EN 0x20000000 +#define FLD_BIST_DEBUGZ 0x10000000 +#define FLD_AUD_BIST_TEST_H 0x0f000000 +/* Reserved [23:22] */ +#define FLD_FLTRN_BIST_TEST_H 0x00020000 +#define FLD_VID_BIST_TEST_H 0x00010000 +/* Reserved [19:17] */ +#define FLD_BIST_TEST_H 0x00010000 +/* Reserved [15:13] */ +#define FLD_TAB_EN 0x00001000 +/* Reserved [11:0] */ + +/*****************************************************************************/ +#define BIST_STAT 0x14c +#define FLD_AUD_BIST_FAIL_H 0xfff00000 +#define FLD_FLTRN_BIST_FAIL_H 0x00180000 +#define FLD_VID_BIST_FAIL_H 0x00070000 +#define FLD_AUD_BIST_TST_DONE 0x0000fff0 +#define FLD_FLTRN_BIST_TST_DONE 0x00000008 +#define FLD_VID_BIST_TST_DONE 0x00000007 + +/*****************************************************************************/ +/* DirectIF registers definition have been moved to DIF_reg.h */ +/*****************************************************************************/ +#define MODE_CTRL 0x400 +#define FLD_AFD_PAL60_DIS 0x20000000 +#define FLD_AFD_FORCE_SECAM 0x10000000 +#define FLD_AFD_FORCE_PALNC 0x08000000 +#define FLD_AFD_FORCE_PAL 0x04000000 +#define FLD_AFD_PALM_SEL 0x03000000 +#define FLD_CKILL_MODE 0x00300000 +#define FLD_COMB_NOTCH_MODE 0x00c00000 /* bit[19:18] */ +#define FLD_CLR_LOCK_STAT 0x00020000 +#define FLD_FAST_LOCK_MD 0x00010000 +#define FLD_WCEN 0x00008000 +#define FLD_CAGCEN 0x00004000 +#define FLD_CKILLEN 0x00002000 +#define FLD_AUTO_SC_LOCK 0x00001000 +#define FLD_MAN_SC_FAST_LOCK 0x00000800 +#define FLD_INPUT_MODE 0x00000600 +#define FLD_AFD_ACQUIRE 0x00000100 +#define FLD_AFD_NTSC_SEL 0x00000080 +#define FLD_AFD_PAL_SEL 0x00000040 +#define FLD_ACFG_DIS 0x00000020 +#define FLD_SQ_PIXEL 0x00000010 +#define FLD_VID_FMT_SEL 0x0000000f + +/*****************************************************************************/ +#define OUT_CTRL1 0x404 +#define FLD_POLAR 0x7f000000 +/* Reserved [23] */ +#define FLD_RND_MODE 0x00600000 +#define FLD_VIPCLAMP_EN 0x00100000 +#define FLD_VIPBLANK_EN 0x00080000 +#define FLD_VIP_OPT_AL 0x00040000 +#define FLD_IDID0_SOURCE 0x00020000 +#define FLD_DCMODE 0x00010000 +#define FLD_CLK_GATING 0x0000c000 +#define FLD_CLK_INVERT 0x00002000 +#define FLD_HSFMT 0x00001000 +#define FLD_VALIDFMT 0x00000800 +#define FLD_ACTFMT 0x00000400 +#define FLD_SWAPRAW 0x00000200 +#define FLD_CLAMPRAW_EN 0x00000100 +#define FLD_BLUE_FIELD_EN 0x00000080 +#define FLD_BLUE_FIELD_ACT 0x00000040 +#define FLD_TASKBIT_VAL 0x00000020 +#define FLD_ANC_DATA_EN 0x00000010 +#define FLD_VBIHACTRAW_EN 0x00000008 +#define FLD_MODE10B 0x00000004 +#define FLD_OUT_MODE 0x00000003 + +/*****************************************************************************/ +#define OUT_CTRL2 0x408 +#define FLD_AUD_GRP 0xc0000000 +#define FLD_SAMPLE_RATE 0x30000000 +#define FLD_AUD_ANC_EN 0x08000000 +#define FLD_EN_C 0x04000000 +#define FLD_EN_B 0x02000000 +#define FLD_EN_A 0x01000000 +/* Reserved [23:20] */ +#define FLD_IDID1_LSB 0x000c0000 +#define FLD_IDID0_LSB 0x00030000 +#define FLD_IDID1_MSB 0x0000ff00 +#define FLD_IDID0_MSB 0x000000ff + +/*****************************************************************************/ +#define GEN_STAT 0x40c +#define FLD_VCR_DETECT 0x00800000 +#define FLD_SPECIAL_PLAY_N 0x00400000 +#define FLD_VPRES 0x00200000 +#define FLD_AGC_LOCK 0x00100000 +#define FLD_CSC_LOCK 0x00080000 +#define FLD_VLOCK 0x00040000 +#define FLD_SRC_LOCK 0x00020000 +#define FLD_HLOCK 0x00010000 +#define FLD_VSYNC_N 0x00008000 +#define FLD_SRC_FIFO_UFLOW 0x00004000 +#define FLD_SRC_FIFO_OFLOW 0x00002000 +#define FLD_FIELD 0x00001000 +#define FLD_AFD_FMT_STAT 0x00000f00 +#define FLD_MV_TYPE2_PAIR 0x00000080 +#define FLD_MV_T3CS 0x00000040 +#define FLD_MV_CS 0x00000020 +#define FLD_MV_PSP 0x00000010 +/* Reserved [3] */ +#define FLD_MV_CDAT 0x00000003 + +/*****************************************************************************/ +#define INT_STAT_MASK 0x410 +#define FLD_COMB_3D_FIFO_MSK 0x80000000 +#define FLD_WSS_DAT_AVAIL_MSK 0x40000000 +#define FLD_GS2_DAT_AVAIL_MSK 0x20000000 +#define FLD_GS1_DAT_AVAIL_MSK 0x10000000 +#define FLD_CC_DAT_AVAIL_MSK 0x08000000 +#define FLD_VPRES_CHANGE_MSK 0x04000000 +#define FLD_MV_CHANGE_MSK 0x02000000 +#define FLD_END_VBI_EVEN_MSK 0x01000000 +#define FLD_END_VBI_ODD_MSK 0x00800000 +#define FLD_FMT_CHANGE_MSK 0x00400000 +#define FLD_VSYNC_TRAIL_MSK 0x00200000 +#define FLD_HLOCK_CHANGE_MSK 0x00100000 +#define FLD_VLOCK_CHANGE_MSK 0x00080000 +#define FLD_CSC_LOCK_CHANGE_MSK 0x00040000 +#define FLD_SRC_FIFO_UFLOW_MSK 0x00020000 +#define FLD_SRC_FIFO_OFLOW_MSK 0x00010000 +#define FLD_COMB_3D_FIFO_STAT 0x00008000 +#define FLD_WSS_DAT_AVAIL_STAT 0x00004000 +#define FLD_GS2_DAT_AVAIL_STAT 0x00002000 +#define FLD_GS1_DAT_AVAIL_STAT 0x00001000 +#define FLD_CC_DAT_AVAIL_STAT 0x00000800 +#define FLD_VPRES_CHANGE_STAT 0x00000400 +#define FLD_MV_CHANGE_STAT 0x00000200 +#define FLD_END_VBI_EVEN_STAT 0x00000100 +#define FLD_END_VBI_ODD_STAT 0x00000080 +#define FLD_FMT_CHANGE_STAT 0x00000040 +#define FLD_VSYNC_TRAIL_STAT 0x00000020 +#define FLD_HLOCK_CHANGE_STAT 0x00000010 +#define FLD_VLOCK_CHANGE_STAT 0x00000008 +#define FLD_CSC_LOCK_CHANGE_STAT 0x00000004 +#define FLD_SRC_FIFO_UFLOW_STAT 0x00000002 +#define FLD_SRC_FIFO_OFLOW_STAT 0x00000001 + +/*****************************************************************************/ +#define LUMA_CTRL 0x414 +#define BRIGHTNESS_CTRL_BYTE 0x414 +#define CONTRAST_CTRL_BYTE 0x415 +#define LUMA_CTRL_BYTE_3 0x416 +#define FLD_LUMA_CORE_SEL 0x00c00000 +#define FLD_RANGE 0x00300000 +/* Reserved [19] */ +#define FLD_PEAK_EN 0x00040000 +#define FLD_PEAK_SEL 0x00030000 +#define FLD_CNTRST 0x0000ff00 +#define FLD_BRITE 0x000000ff + +/*****************************************************************************/ +#define HSCALE_CTRL 0x418 +#define FLD_HFILT 0x03000000 +#define FLD_HSCALE 0x00ffffff + +/*****************************************************************************/ +#define VSCALE_CTRL 0x41c +#define FLD_LINE_AVG_DIS 0x01000000 +/* Reserved [23:20] */ +#define FLD_VS_INTRLACE 0x00080000 +#define FLD_VFILT 0x00070000 +/* Reserved [15:13] */ +#define FLD_VSCALE 0x00001fff + +/*****************************************************************************/ +#define CHROMA_CTRL 0x420 +#define USAT_CTRL_BYTE 0x420 +#define VSAT_CTRL_BYTE 0x421 +#define HUE_CTRL_BYTE 0x422 +#define FLD_C_LPF_EN 0x20000000 +#define FLD_CHR_DELAY 0x1c000000 +#define FLD_C_CORE_SEL 0x03000000 +#define FLD_HUE 0x00ff0000 +#define FLD_VSAT 0x0000ff00 +#define FLD_USAT 0x000000ff + +/*****************************************************************************/ +#define VBI_LINE_CTRL1 0x424 +#define FLD_VBI_MD_LINE4 0xff000000 +#define FLD_VBI_MD_LINE3 0x00ff0000 +#define FLD_VBI_MD_LINE2 0x0000ff00 +#define FLD_VBI_MD_LINE1 0x000000ff + +/*****************************************************************************/ +#define VBI_LINE_CTRL2 0x428 +#define FLD_VBI_MD_LINE8 0xff000000 +#define FLD_VBI_MD_LINE7 0x00ff0000 +#define FLD_VBI_MD_LINE6 0x0000ff00 +#define FLD_VBI_MD_LINE5 0x000000ff + +/*****************************************************************************/ +#define VBI_LINE_CTRL3 0x42c +#define FLD_VBI_MD_LINE12 0xff000000 +#define FLD_VBI_MD_LINE11 0x00ff0000 +#define FLD_VBI_MD_LINE10 0x0000ff00 +#define FLD_VBI_MD_LINE9 0x000000ff + +/*****************************************************************************/ +#define VBI_LINE_CTRL4 0x430 +#define FLD_VBI_MD_LINE16 0xff000000 +#define FLD_VBI_MD_LINE15 0x00ff0000 +#define FLD_VBI_MD_LINE14 0x0000ff00 +#define FLD_VBI_MD_LINE13 0x000000ff + +/*****************************************************************************/ +#define VBI_LINE_CTRL5 0x434 +#define FLD_VBI_MD_LINE17 0x000000ff + +/*****************************************************************************/ +#define VBI_FC_CFG 0x438 +#define FLD_FC_ALT2 0xff000000 +#define FLD_FC_ALT1 0x00ff0000 +#define FLD_FC_ALT2_TYPE 0x0000f000 +#define FLD_FC_ALT1_TYPE 0x00000f00 +/* Reserved [7:1] */ +#define FLD_FC_SEARCH_MODE 0x00000001 + +/*****************************************************************************/ +#define VBI_MISC_CFG1 0x43c +#define FLD_TTX_PKTADRU 0xfff00000 +#define FLD_TTX_PKTADRL 0x000fff00 +/* Reserved [7:6] */ +#define FLD_MOJI_PACK_DIS 0x00000020 +#define FLD_VPS_DEC_DIS 0x00000010 +#define FLD_CRI_MARG_SCALE 0x0000000c +#define FLD_EDGE_RESYNC_EN 0x00000002 +#define FLD_ADAPT_SLICE_DIS 0x00000001 + +/*****************************************************************************/ +#define VBI_MISC_CFG2 0x440 +#define FLD_HAMMING_TYPE 0x0f000000 +/* Reserved [23:20] */ +#define FLD_WSS_FIFO_RST 0x00080000 +#define FLD_GS2_FIFO_RST 0x00040000 +#define FLD_GS1_FIFO_RST 0x00020000 +#define FLD_CC_FIFO_RST 0x00010000 +/* Reserved [15:12] */ +#define FLD_VBI3_SDID 0x00000f00 +#define FLD_VBI2_SDID 0x000000f0 +#define FLD_VBI1_SDID 0x0000000f + +/*****************************************************************************/ +#define VBI_PAY1 0x444 +#define FLD_GS1_FIFO_DAT 0xFF000000 +#define FLD_GS1_STAT 0x00FF0000 +#define FLD_CC_FIFO_DAT 0x0000FF00 +#define FLD_CC_STAT 0x000000FF + +/*****************************************************************************/ +#define VBI_PAY2 0x448 +#define FLD_WSS_FIFO_DAT 0xff000000 +#define FLD_WSS_STAT 0x00ff0000 +#define FLD_GS2_FIFO_DAT 0x0000ff00 +#define FLD_GS2_STAT 0x000000ff + +/*****************************************************************************/ +#define VBI_CUST1_CFG1 0x44c +/* Reserved [31] */ +#define FLD_VBI1_CRIWIN 0x7f000000 +#define FLD_VBI1_SLICE_DIST 0x00f00000 +#define FLD_VBI1_BITINC 0x000fff00 +#define FLD_VBI1_HDELAY 0x000000ff + +/*****************************************************************************/ +#define VBI_CUST1_CFG2 0x450 +#define FLD_VBI1_FC_LENGTH 0x1f000000 +#define FLD_VBI1_FRAME_CODE 0x00ffffff + +/*****************************************************************************/ +#define VBI_CUST1_CFG3 0x454 +#define FLD_VBI1_HAM_EN 0x80000000 +#define FLD_VBI1_FIFO_MODE 0x70000000 +#define FLD_VBI1_FORMAT_TYPE 0x0f000000 +#define FLD_VBI1_PAYLD_LENGTH 0x00ff0000 +#define FLD_VBI1_CRI_LENGTH 0x0000f000 +#define FLD_VBI1_CRI_MARGIN 0x00000f00 +#define FLD_VBI1_CRI_TIME 0x000000ff + +/*****************************************************************************/ +#define VBI_CUST2_CFG1 0x458 +/* Reserved [31] */ +#define FLD_VBI2_CRIWIN 0x7f000000 +#define FLD_VBI2_SLICE_DIST 0x00f00000 +#define FLD_VBI2_BITINC 0x000fff00 +#define FLD_VBI2_HDELAY 0x000000ff + +/*****************************************************************************/ +#define VBI_CUST2_CFG2 0x45c +#define FLD_VBI2_FC_LENGTH 0x1f000000 +#define FLD_VBI2_FRAME_CODE 0x00ffffff + +/*****************************************************************************/ +#define VBI_CUST2_CFG3 0x460 +#define FLD_VBI2_HAM_EN 0x80000000 +#define FLD_VBI2_FIFO_MODE 0x70000000 +#define FLD_VBI2_FORMAT_TYPE 0x0f000000 +#define FLD_VBI2_PAYLD_LENGTH 0x00ff0000 +#define FLD_VBI2_CRI_LENGTH 0x0000f000 +#define FLD_VBI2_CRI_MARGIN 0x00000f00 +#define FLD_VBI2_CRI_TIME 0x000000ff + +/*****************************************************************************/ +#define VBI_CUST3_CFG1 0x464 +/* Reserved [31] */ +#define FLD_VBI3_CRIWIN 0x7f000000 +#define FLD_VBI3_SLICE_DIST 0x00f00000 +#define FLD_VBI3_BITINC 0x000fff00 +#define FLD_VBI3_HDELAY 0x000000ff + +/*****************************************************************************/ +#define VBI_CUST3_CFG2 0x468 +#define FLD_VBI3_FC_LENGTH 0x1f000000 +#define FLD_VBI3_FRAME_CODE 0x00ffffff + +/*****************************************************************************/ +#define VBI_CUST3_CFG3 0x46c +#define FLD_VBI3_HAM_EN 0x80000000 +#define FLD_VBI3_FIFO_MODE 0x70000000 +#define FLD_VBI3_FORMAT_TYPE 0x0f000000 +#define FLD_VBI3_PAYLD_LENGTH 0x00ff0000 +#define FLD_VBI3_CRI_LENGTH 0x0000f000 +#define FLD_VBI3_CRI_MARGIN 0x00000f00 +#define FLD_VBI3_CRI_TIME 0x000000ff + +/*****************************************************************************/ +#define HORIZ_TIM_CTRL 0x470 +#define FLD_BGDEL_CNT 0xff000000 +/* Reserved [23:22] */ +#define FLD_HACTIVE_CNT 0x003ff000 +/* Reserved [11:10] */ +#define FLD_HBLANK_CNT 0x000003ff + +/*****************************************************************************/ +#define VERT_TIM_CTRL 0x474 +#define FLD_V656BLANK_CNT 0xff000000 +/* Reserved [23:22] */ +#define FLD_VACTIVE_CNT 0x003ff000 +/* Reserved [11:10] */ +#define FLD_VBLANK_CNT 0x000003ff + +/*****************************************************************************/ +#define SRC_COMB_CFG 0x478 +#define FLD_CCOMB_2LN_CHECK 0x80000000 +#define FLD_CCOMB_3LN_EN 0x40000000 +#define FLD_CCOMB_2LN_EN 0x20000000 +#define FLD_CCOMB_3D_EN 0x10000000 +/* Reserved [27] */ +#define FLD_LCOMB_3LN_EN 0x04000000 +#define FLD_LCOMB_2LN_EN 0x02000000 +#define FLD_LCOMB_3D_EN 0x01000000 +#define FLD_LUMA_LPF_SEL 0x00c00000 +#define FLD_UV_LPF_SEL 0x00300000 +#define FLD_BLEND_SLOPE 0x000f0000 +#define FLD_CCOMB_REDUCE_EN 0x00008000 +/* Reserved [14:10] */ +#define FLD_SRC_DECIM_RATIO 0x000003ff + +/*****************************************************************************/ +#define CHROMA_VBIOFF_CFG 0x47c +#define FLD_VBI_VOFFSET 0x1f000000 +/* Reserved [23:20] */ +#define FLD_SC_STEP 0x000fffff + +/*****************************************************************************/ +#define FIELD_COUNT 0x480 +#define FLD_FIELD_COUNT_FLD 0x000003ff + +/*****************************************************************************/ +#define MISC_TIM_CTRL 0x484 +#define FLD_DEBOUNCE_COUNT 0xc0000000 +#define FLD_VT_LINE_CNT_HYST 0x30000000 +/* Reserved [27] */ +#define FLD_AFD_STAT 0x07ff0000 +#define FLD_VPRES_VERT_EN 0x00008000 +/* Reserved [14:12] */ +#define FLD_HR32 0x00000800 +#define FLD_TDALGN 0x00000400 +#define FLD_TDFIELD 0x00000200 +/* Reserved [8:6] */ +#define FLD_TEMPDEC 0x0000003f + +/*****************************************************************************/ +#define DFE_CTRL1 0x488 +#define FLD_CLAMP_AUTO_EN 0x80000000 +#define FLD_AGC_AUTO_EN 0x40000000 +#define FLD_VGA_CRUSH_EN 0x20000000 +#define FLD_VGA_AUTO_EN 0x10000000 +#define FLD_VBI_GATE_EN 0x08000000 +#define FLD_CLAMP_LEVEL 0x07000000 +/* Reserved [23:22] */ +#define FLD_CLAMP_SKIP_CNT 0x00300000 +#define FLD_AGC_GAIN 0x000fff00 +/* Reserved [7:6] */ +#define FLD_VGA_GAIN 0x0000003f + +/*****************************************************************************/ +#define DFE_CTRL2 0x48c +#define FLD_VGA_ACQUIRE_RANGE 0x00ff0000 +#define FLD_VGA_TRACK_RANGE 0x0000ff00 +#define FLD_VGA_SYNC 0x000000ff + +/*****************************************************************************/ +#define DFE_CTRL3 0x490 +#define FLD_BP_PERCENT 0xff000000 +#define FLD_DFT_THRESHOLD 0x00ff0000 +/* Reserved [15:12] */ +#define FLD_SYNC_WIDTH_SEL 0x00000600 +#define FLD_BP_LOOP_GAIN 0x00000300 +#define FLD_SYNC_LOOP_GAIN 0x000000c0 +/* Reserved [5:4] */ +#define FLD_AGC_LOOP_GAIN 0x0000000c +#define FLD_DCC_LOOP_GAIN 0x00000003 + +/*****************************************************************************/ +#define PLL_CTRL 0x494 +#define FLD_PLL_KD 0xff000000 +#define FLD_PLL_KI 0x00ff0000 +#define FLD_PLL_MAX_OFFSET 0x0000ffff + +/*****************************************************************************/ +#define HTL_CTRL 0x498 +/* Reserved [31:24] */ +#define FLD_AUTO_LOCK_SPD 0x00080000 +#define FLD_MAN_FAST_LOCK 0x00040000 +#define FLD_HTL_15K_EN 0x00020000 +#define FLD_HTL_500K_EN 0x00010000 +#define FLD_HTL_KD 0x0000ff00 +#define FLD_HTL_KI 0x000000ff + +/*****************************************************************************/ +#define COMB_CTRL 0x49c +#define FLD_COMB_PHASE_LIMIT 0xff000000 +#define FLD_CCOMB_ERR_LIMIT 0x00ff0000 +#define FLD_LUMA_THRESHOLD 0x0000ff00 +#define FLD_LCOMB_ERR_LIMIT 0x000000ff + +/*****************************************************************************/ +#define CRUSH_CTRL 0x4a0 +#define FLD_WTW_EN 0x00400000 +#define FLD_CRUSH_FREQ 0x00200000 +#define FLD_MAJ_SEL_EN 0x00100000 +#define FLD_MAJ_SEL 0x000c0000 +/* Reserved [17:15] */ +#define FLD_SYNC_TIP_REDUCE 0x00007e00 +/* Reserved [8:6] */ +#define FLD_SYNC_TIP_INC 0x0000003f + +/*****************************************************************************/ +#define SOFT_RST_CTRL 0x4a4 +#define FLD_VD_SOFT_RST 0x00008000 +/* Reserved [14:12] */ +#define FLD_REG_RST_MSK 0x00000800 +#define FLD_VOF_RST_MSK 0x00000400 +#define FLD_MVDET_RST_MSK 0x00000200 +#define FLD_VBI_RST_MSK 0x00000100 +#define FLD_SCALE_RST_MSK 0x00000080 +#define FLD_CHROMA_RST_MSK 0x00000040 +#define FLD_LUMA_RST_MSK 0x00000020 +#define FLD_VTG_RST_MSK 0x00000010 +#define FLD_YCSEP_RST_MSK 0x00000008 +#define FLD_SRC_RST_MSK 0x00000004 +#define FLD_DFE_RST_MSK 0x00000002 +/* Reserved [0] */ + +/*****************************************************************************/ +#define MV_DT_CTRL1 0x4a8 +/* Reserved [31:29] */ +#define FLD_PSP_STOP_LINE 0x1f000000 +/* Reserved [23:21] */ +#define FLD_PSP_STRT_LINE 0x001f0000 +/* Reserved [15] */ +#define FLD_PSP_LLIMW 0x00007f00 +/* Reserved [7] */ +#define FLD_PSP_ULIMW 0x0000007f + +/*****************************************************************************/ +#define MV_DT_CTRL2 0x4aC +#define FLD_CS_STOPWIN 0xff000000 +#define FLD_CS_STRTWIN 0x00ff0000 +#define FLD_CS_WIDTH 0x0000ff00 +#define FLD_PSP_SPEC_VAL 0x000000ff + +/*****************************************************************************/ +#define MV_DT_CTRL3 0x4B0 +#define FLD_AUTO_RATE_DIS 0x80000000 +#define FLD_HLOCK_DIS 0x40000000 +#define FLD_SEL_FIELD_CNT 0x20000000 +#define FLD_CS_TYPE2_SEL 0x10000000 +#define FLD_CS_LINE_THRSH_SEL 0x08000000 +#define FLD_CS_ATHRESH_SEL 0x04000000 +#define FLD_PSP_SPEC_SEL 0x02000000 +#define FLD_PSP_LINES_SEL 0x01000000 +#define FLD_FIELD_CNT 0x00f00000 +#define FLD_CS_TYPE2_CNT 0x000fc000 +#define FLD_CS_LINE_CNT 0x00003f00 +#define FLD_CS_ATHRESH_LEV 0x000000ff + +/*****************************************************************************/ +#define CHIP_VERSION 0x4b4 +/* Cx231xx redefine */ +#define VERSION 0x4b4 +#define FLD_REV_ID 0x000000ff + +/*****************************************************************************/ +#define MISC_DIAG_CTRL 0x4b8 +/* Reserved [31:24] */ +#define FLD_SC_CONVERGE_THRESH 0x00ff0000 +#define FLD_CCOMB_ERR_LIMIT_3D 0x0000ff00 +#define FLD_LCOMB_ERR_LIMIT_3D 0x000000ff + +/*****************************************************************************/ +#define VBI_PASS_CTRL 0x4bc +#define FLD_VBI_PASS_MD 0x00200000 +#define FLD_VBI_SETUP_DIS 0x00100000 +#define FLD_PASS_LINE_CTRL 0x000fffff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define VCR_DET_CTRL 0x4c0 +#define FLD_EN_FIELD_PHASE_DET 0x80000000 +#define FLD_EN_HEAD_SW_DET 0x40000000 +#define FLD_FIELD_PHASE_LENGTH 0x01ff0000 +/* Reserved [29:25] */ +#define FLD_FIELD_PHASE_DELAY 0x0000ff00 +#define FLD_FIELD_PHASE_LIMIT 0x000000f0 +#define FLD_HEAD_SW_DET_LIMIT 0x0000000f + +/*****************************************************************************/ +#define DL_CTL 0x800 +#define DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */ +#define DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */ +#define DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */ +#define DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */ +/* Reserved [31:5] */ +#define FLD_START_8051 0x10000000 +#define FLD_DL_ENABLE 0x08000000 +#define FLD_DL_AUTO_INC 0x04000000 +#define FLD_DL_MAP 0x03000000 + +/*****************************************************************************/ +#define STD_DET_STATUS 0x804 +#define FLD_SPARE_STATUS1 0xff000000 +#define FLD_SPARE_STATUS0 0x00ff0000 +#define FLD_MOD_DET_STATUS1 0x0000ff00 +#define FLD_MOD_DET_STATUS0 0x000000ff + +/*****************************************************************************/ +#define AUD_BUILD_NUM 0x806 +#define AUD_VER_NUM 0x807 +#define STD_DET_CTL 0x808 +#define STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */ +#define STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */ +#define FLD_SPARE_CTL0 0xff000000 +#define FLD_DIS_DBX 0x00800000 +#define FLD_DIS_BTSC 0x00400000 +#define FLD_DIS_NICAM_A2 0x00200000 +#define FLD_VIDEO_PRESENT 0x00100000 +#define FLD_DW8051_VIDEO_FORMAT 0x000f0000 +#define FLD_PREF_DEC_MODE 0x0000ff00 +#define FLD_AUD_CONFIG 0x000000ff + +/*****************************************************************************/ +#define DW8051_INT 0x80c +#define FLD_VIDEO_PRESENT_CHANGE 0x80000000 +#define FLD_VIDEO_CHANGE 0x40000000 +#define FLD_RDS_READY 0x20000000 +#define FLD_AC97_INT 0x10000000 +#define FLD_NICAM_BIT_ERROR_TOO_HIGH 0x08000000 +#define FLD_NICAM_LOCK 0x04000000 +#define FLD_NICAM_UNLOCK 0x02000000 +#define FLD_DFT4_TH_CMP 0x01000000 +/* Reserved [23:22] */ +#define FLD_LOCK_IND_INT 0x00200000 +#define FLD_DFT3_TH_CMP 0x00100000 +#define FLD_DFT2_TH_CMP 0x00080000 +#define FLD_DFT1_TH_CMP 0x00040000 +#define FLD_FM2_DFT_TH_CMP 0x00020000 +#define FLD_FM1_DFT_TH_CMP 0x00010000 +#define FLD_VIDEO_PRESENT_EN 0x00008000 +#define FLD_VIDEO_CHANGE_EN 0x00004000 +#define FLD_RDS_READY_EN 0x00002000 +#define FLD_AC97_INT_EN 0x00001000 +#define FLD_NICAM_BIT_ERROR_TOO_HIGH_EN 0x00000800 +#define FLD_NICAM_LOCK_EN 0x00000400 +#define FLD_NICAM_UNLOCK_EN 0x00000200 +#define FLD_DFT4_TH_CMP_EN 0x00000100 +/* Reserved [7] */ +#define FLD_DW8051_INT6_CTL1 0x00000040 +#define FLD_DW8051_INT5_CTL1 0x00000020 +#define FLD_DW8051_INT4_CTL1 0x00000010 +#define FLD_DW8051_INT3_CTL1 0x00000008 +#define FLD_DW8051_INT2_CTL1 0x00000004 +#define FLD_DW8051_INT1_CTL1 0x00000002 +#define FLD_DW8051_INT0_CTL1 0x00000001 + +/*****************************************************************************/ +#define GENERAL_CTL 0x810 +#define FLD_RDS_INT 0x80000000 +#define FLD_NBER_INT 0x40000000 +#define FLD_NLL_INT 0x20000000 +#define FLD_IFL_INT 0x10000000 +#define FLD_FDL_INT 0x08000000 +#define FLD_AFC_INT 0x04000000 +#define FLD_AMC_INT 0x02000000 +#define FLD_AC97_INT_CTL 0x01000000 +#define FLD_RDS_INT_DIS 0x00800000 +#define FLD_NBER_INT_DIS 0x00400000 +#define FLD_NLL_INT_DIS 0x00200000 +#define FLD_IFL_INT_DIS 0x00100000 +#define FLD_FDL_INT_DIS 0x00080000 +#define FLD_FC_INT_DIS 0x00040000 +#define FLD_AMC_INT_DIS 0x00020000 +#define FLD_AC97_INT_DIS 0x00010000 +#define FLD_REV_NUM 0x0000ff00 +/* Reserved [7:5] */ +#define FLD_DBX_SOFT_RESET_REG 0x00000010 +#define FLD_AD_SOFT_RESET_REG 0x00000008 +#define FLD_SRC_SOFT_RESET_REG 0x00000004 +#define FLD_CDMOD_SOFT_RESET 0x00000002 +#define FLD_8051_SOFT_RESET 0x00000001 + +/*****************************************************************************/ +#define AAGC_CTL 0x814 +#define FLD_AFE_12DB_EN 0x80000000 +#define FLD_AAGC_DEFAULT_EN 0x40000000 +#define FLD_AAGC_DEFAULT 0x3f000000 +/* Reserved [23] */ +#define FLD_AAGC_GAIN 0x00600000 +#define FLD_AAGC_TH 0x001f0000 +/* Reserved [15:14] */ +#define FLD_AAGC_HYST2 0x00003f00 +/* Reserved [7:6] */ +#define FLD_AAGC_HYST1 0x0000003f + +/*****************************************************************************/ +#define IF_SRC_CTL 0x818 +#define FLD_DBX_BYPASS 0x80000000 +/* Reserved [30:25] */ +#define FLD_IF_SRC_MODE 0x01000000 +/* Reserved [23:18] */ +#define FLD_IF_SRC_PHASE_INC 0x0001ffff + +/*****************************************************************************/ +#define ANALOG_DEMOD_CTL 0x81c +#define FLD_ROT1_PHACC_PROG 0xffff0000 +/* Reserved [15] */ +#define FLD_FM1_DELAY_FIX 0x00007000 +#define FLD_PDF4_SHIFT 0x00000c00 +#define FLD_PDF3_SHIFT 0x00000300 +#define FLD_PDF2_SHIFT 0x000000c0 +#define FLD_PDF1_SHIFT 0x00000030 +#define FLD_FMBYPASS_MODE2 0x00000008 +#define FLD_FMBYPASS_MODE1 0x00000004 +#define FLD_NICAM_MODE 0x00000002 +#define FLD_BTSC_FMRADIO_MODE 0x00000001 + +/*****************************************************************************/ +#define ROT_FREQ_CTL 0x820 +#define FLD_ROT3_PHACC_PROG 0xffff0000 +#define FLD_ROT2_PHACC_PROG 0x0000ffff + +/*****************************************************************************/ +#define FM_CTL 0x824 +#define FLD_FM2_DC_FB_SHIFT 0xf0000000 +#define FLD_FM2_DC_INT_SHIFT 0x0f000000 +#define FLD_FM2_AFC_RESET 0x00800000 +#define FLD_FM2_DC_PASS_IN 0x00400000 +#define FLD_FM2_DAGC_SHIFT 0x00380000 +#define FLD_FM2_CORDIC_SHIFT 0x00070000 +#define FLD_FM1_DC_FB_SHIFT 0x0000f000 +#define FLD_FM1_DC_INT_SHIFT 0x00000f00 +#define FLD_FM1_AFC_RESET 0x00000080 +#define FLD_FM1_DC_PASS_IN 0x00000040 +#define FLD_FM1_DAGC_SHIFT 0x00000038 +#define FLD_FM1_CORDIC_SHIFT 0x00000007 + +/*****************************************************************************/ +#define LPF_PDF_CTL 0x828 +/* Reserved [31:30] */ +#define FLD_LPF32_SHIFT1 0x30000000 +#define FLD_LPF32_SHIFT2 0x0c000000 +#define FLD_LPF160_SHIFTA 0x03000000 +#define FLD_LPF160_SHIFTB 0x00c00000 +#define FLD_LPF160_SHIFTC 0x00300000 +#define FLD_LPF32_COEF_SEL2 0x000c0000 +#define FLD_LPF32_COEF_SEL1 0x00030000 +#define FLD_LPF160_COEF_SELC 0x0000c000 +#define FLD_LPF160_COEF_SELB 0x00003000 +#define FLD_LPF160_COEF_SELA 0x00000c00 +#define FLD_LPF160_IN_EN_REG 0x00000300 +#define FLD_PDF4_PDF_SEL 0x000000c0 +#define FLD_PDF3_PDF_SEL 0x00000030 +#define FLD_PDF2_PDF_SEL 0x0000000c +#define FLD_PDF1_PDF_SEL 0x00000003 + +/*****************************************************************************/ +#define DFT1_CTL1 0x82c +#define FLD_DFT1_DWELL 0xffff0000 +#define FLD_DFT1_FREQ 0x0000ffff + +/*****************************************************************************/ +#define DFT1_CTL2 0x830 +#define FLD_DFT1_THRESHOLD 0xffffff00 +#define FLD_DFT1_CMP_CTL 0x00000080 +#define FLD_DFT1_AVG 0x00000070 +/* Reserved [3:1] */ +#define FLD_DFT1_START 0x00000001 + +/*****************************************************************************/ +#define DFT1_STATUS 0x834 +#define FLD_DFT1_DONE 0x80000000 +#define FLD_DFT1_TH_CMP_STAT 0x40000000 +#define FLD_DFT1_RESULT 0x3fffffff + +/*****************************************************************************/ +#define DFT2_CTL1 0x838 +#define FLD_DFT2_DWELL 0xffff0000 +#define FLD_DFT2_FREQ 0x0000ffff + +/*****************************************************************************/ +#define DFT2_CTL2 0x83C +#define FLD_DFT2_THRESHOLD 0xffffff00 +#define FLD_DFT2_CMP_CTL 0x00000080 +#define FLD_DFT2_AVG 0x00000070 +/* Reserved [3:1] */ +#define FLD_DFT2_START 0x00000001 + +/*****************************************************************************/ +#define DFT2_STATUS 0x840 +#define FLD_DFT2_DONE 0x80000000 +#define FLD_DFT2_TH_CMP_STAT 0x40000000 +#define FLD_DFT2_RESULT 0x3fffffff + +/*****************************************************************************/ +#define DFT3_CTL1 0x844 +#define FLD_DFT3_DWELL 0xffff0000 +#define FLD_DFT3_FREQ 0x0000ffff + +/*****************************************************************************/ +#define DFT3_CTL2 0x848 +#define FLD_DFT3_THRESHOLD 0xffffff00 +#define FLD_DFT3_CMP_CTL 0x00000080 +#define FLD_DFT3_AVG 0x00000070 +/* Reserved [3:1] */ +#define FLD_DFT3_START 0x00000001 + +/*****************************************************************************/ +#define DFT3_STATUS 0x84c +#define FLD_DFT3_DONE 0x80000000 +#define FLD_DFT3_TH_CMP_STAT 0x40000000 +#define FLD_DFT3_RESULT 0x3fffffff + +/*****************************************************************************/ +#define DFT4_CTL1 0x850 +#define FLD_DFT4_DWELL 0xffff0000 +#define FLD_DFT4_FREQ 0x0000ffff + +/*****************************************************************************/ +#define DFT4_CTL2 0x854 +#define FLD_DFT4_THRESHOLD 0xffffff00 +#define FLD_DFT4_CMP_CTL 0x00000080 +#define FLD_DFT4_AVG 0x00000070 +/* Reserved [3:1] */ +#define FLD_DFT4_START 0x00000001 + +/*****************************************************************************/ +#define DFT4_STATUS 0x858 +#define FLD_DFT4_DONE 0x80000000 +#define FLD_DFT4_TH_CMP_STAT 0x40000000 +#define FLD_DFT4_RESULT 0x3fffffff + +/*****************************************************************************/ +#define AM_MTS_DET 0x85c +#define FLD_AM_MTS_MODE 0x80000000 +/* Reserved [30:26] */ +#define FLD_AM_SUB 0x02000000 +#define FLD_AM_GAIN_EN 0x01000000 +/* Reserved [23:16] */ +#define FLD_AMMTS_GAIN_SCALE 0x0000e000 +#define FLD_MTS_PDF_SHIFT 0x00001800 +#define FLD_AM_REG_GAIN 0x00000700 +#define FLD_AGC_REF 0x000000ff + +/*****************************************************************************/ +#define ANALOG_MUX_CTL 0x860 +/* Reserved [31:29] */ +#define FLD_MUX21_SEL 0x10000000 +#define FLD_MUX20_SEL 0x08000000 +#define FLD_MUX19_SEL 0x04000000 +#define FLD_MUX18_SEL 0x02000000 +#define FLD_MUX17_SEL 0x01000000 +#define FLD_MUX16_SEL 0x00800000 +#define FLD_MUX15_SEL 0x00400000 +#define FLD_MUX14_SEL 0x00300000 +#define FLD_MUX13_SEL 0x000C0000 +#define FLD_MUX12_SEL 0x00020000 +#define FLD_MUX11_SEL 0x00018000 +#define FLD_MUX10_SEL 0x00004000 +#define FLD_MUX9_SEL 0x00002000 +#define FLD_MUX8_SEL 0x00001000 +#define FLD_MUX7_SEL 0x00000800 +#define FLD_MUX6_SEL 0x00000600 +#define FLD_MUX5_SEL 0x00000100 +#define FLD_MUX4_SEL 0x000000c0 +#define FLD_MUX3_SEL 0x00000030 +#define FLD_MUX2_SEL 0x0000000c +#define FLD_MUX1_SEL 0x00000003 + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DPLL_CTRL1 0x864 +#define DIG_PLL_CTL1 0x864 + +#define FLD_PLL_STATUS 0x07000000 +#define FLD_BANDWIDTH_SELECT 0x00030000 +#define FLD_PLL_SHIFT_REG 0x00007000 +#define FLD_PHASE_SHIFT 0x000007ff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DPLL_CTRL2 0x868 +#define DIG_PLL_CTL2 0x868 +#define FLD_PLL_UNLOCK_THR 0xff000000 +#define FLD_PLL_LOCK_THR 0x00ff0000 +/* Reserved [15:8] */ +#define FLD_AM_PDF_SEL2 0x000000c0 +#define FLD_AM_PDF_SEL1 0x00000030 +#define FLD_DPLL_FSM_CTRL 0x0000000c +/* Reserved [1] */ +#define FLD_PLL_PILOT_DET 0x00000001 + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DPLL_CTRL3 0x86c +#define DIG_PLL_CTL3 0x86c +#define FLD_DISABLE_LOOP 0x01000000 +#define FLD_A1_DS1_SEL 0x000c0000 +#define FLD_A1_DS2_SEL 0x00030000 +#define FLD_A1_KI 0x0000ff00 +#define FLD_A1_KD 0x000000ff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DPLL_CTRL4 0x870 +#define DIG_PLL_CTL4 0x870 +#define FLD_A2_DS1_SEL 0x000c0000 +#define FLD_A2_DS2_SEL 0x00030000 +#define FLD_A2_KI 0x0000ff00 +#define FLD_A2_KD 0x000000ff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DPLL_CTRL5 0x874 +#define DIG_PLL_CTL5 0x874 +#define FLD_TRK_DS1_SEL 0x000c0000 +#define FLD_TRK_DS2_SEL 0x00030000 +#define FLD_TRK_KI 0x0000ff00 +#define FLD_TRK_KD 0x000000ff + +/*****************************************************************************/ +#define DEEMPH_GAIN_CTL 0x878 +#define FLD_DEEMPH2_GAIN 0xFFFF0000 +#define FLD_DEEMPH1_GAIN 0x0000FFFF + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DEEMPH_COEFF1 0x87c +#define DEEMPH_COEF1 0x87c +#define FLD_DEEMPH_B0 0xffff0000 +#define FLD_DEEMPH_A0 0x0000ffff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DEEMPH_COEFF2 0x880 +#define DEEMPH_COEF2 0x880 +#define FLD_DEEMPH_B1 0xFFFF0000 +#define FLD_DEEMPH_A1 0x0000FFFF + +/*****************************************************************************/ +#define DBX1_CTL1 0x884 +#define FLD_DBX1_WBE_GAIN 0xffff0000 +#define FLD_DBX1_IN_GAIN 0x0000ffff + +/*****************************************************************************/ +#define DBX1_CTL2 0x888 +#define FLD_DBX1_SE_BYPASS 0xffff0000 +#define FLD_DBX1_SE_GAIN 0x0000ffff + +/*****************************************************************************/ +#define DBX1_RMS_SE 0x88C +#define FLD_DBX1_RMS_WBE 0xffff0000 +#define FLD_DBX1_RMS_SE_FLD 0x0000ffff + +/*****************************************************************************/ +#define DBX2_CTL1 0x890 +#define FLD_DBX2_WBE_GAIN 0xffff0000 +#define FLD_DBX2_IN_GAIN 0x0000ffff + +/*****************************************************************************/ +#define DBX2_CTL2 0x894 +#define FLD_DBX2_SE_BYPASS 0xffff0000 +#define FLD_DBX2_SE_GAIN 0x0000ffff + +/*****************************************************************************/ +#define DBX2_RMS_SE 0x898 +#define FLD_DBX2_RMS_WBE 0xffff0000 +#define FLD_DBX2_RMS_SE_FLD 0x0000ffff + +/*****************************************************************************/ +#define AM_FM_DIFF 0x89c +/* Reserved [31] */ +#define FLD_FM_DIFF_OUT 0x7fff0000 +/* Reserved [15] */ +#define FLD_AM_DIFF_OUT 0x00007fff + +/*****************************************************************************/ +#define NICAM_FAW 0x8a0 +#define FLD_FAWDETWINEND 0xFc000000 +#define FLD_FAWDETWINSTR 0x03ff0000 +/* Reserved [15:12] */ +#define FLD_FAWDETTHRSHLD3 0x00000f00 +#define FLD_FAWDETTHRSHLD2 0x000000f0 +#define FLD_FAWDETTHRSHLD1 0x0000000f + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DEEMPH_GAIN 0x8a4 +#define NICAM_DEEMPHGAIN 0x8a4 +/* Reserved [31:18] */ +#define FLD_DEEMPHGAIN 0x0003ffff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DEEMPH_NUMER1 0x8a8 +#define NICAM_DEEMPHNUMER1 0x8a8 +/* Reserved [31:18] */ +#define FLD_DEEMPHNUMER1 0x0003ffff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DEEMPH_NUMER2 0x8ac +#define NICAM_DEEMPHNUMER2 0x8ac +/* Reserved [31:18] */ +#define FLD_DEEMPHNUMER2 0x0003ffff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DEEMPH_DENOM1 0x8b0 +#define NICAM_DEEMPHDENOM1 0x8b0 +/* Reserved [31:18] */ +#define FLD_DEEMPHDENOM1 0x0003ffff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define DEEMPH_DENOM2 0x8b4 +#define NICAM_DEEMPHDENOM2 0x8b4 +/* Reserved [31:18] */ +#define FLD_DEEMPHDENOM2 0x0003ffff + +/*****************************************************************************/ +#define NICAM_ERRLOG_CTL1 0x8B8 +/* Reserved [31:28] */ +#define FLD_ERRINTRPTTHSHLD1 0x0fff0000 +/* Reserved [15:12] */ +#define FLD_ERRLOGPERIOD 0x00000fff + +/*****************************************************************************/ +#define NICAM_ERRLOG_CTL2 0x8bc +/* Reserved [31:28] */ +#define FLD_ERRINTRPTTHSHLD3 0x0fff0000 +/* Reserved [15:12] */ +#define FLD_ERRINTRPTTHSHLD2 0x00000fff + +/*****************************************************************************/ +#define NICAM_ERRLOG_STS1 0x8c0 +/* Reserved [31:28] */ +#define FLD_ERRLOG2 0x0fff0000 +/* Reserved [15:12] */ +#define FLD_ERRLOG1 0x00000fff + +/*****************************************************************************/ +#define NICAM_ERRLOG_STS2 0x8c4 +/* Reserved [31:12] */ +#define FLD_ERRLOG3 0x00000fff + +/*****************************************************************************/ +#define NICAM_STATUS 0x8c8 +/* Reserved [31:20] */ +#define FLD_NICAM_CIB 0x000c0000 +#define FLD_NICAM_LOCK_STAT 0x00020000 +#define FLD_NICAM_MUTE 0x00010000 +#define FLD_NICAMADDIT_DATA 0x0000ffe0 +#define FLD_NICAMCNTRL 0x0000001f + +/*****************************************************************************/ +#define DEMATRIX_CTL 0x8cc +#define FLD_AC97_IN_SHIFT 0xf0000000 +#define FLD_I2S_IN_SHIFT 0x0f000000 +#define FLD_DEMATRIX_SEL_CTL 0x00ff0000 +/* Reserved [15:11] */ +#define FLD_DMTRX_BYPASS 0x00000400 +#define FLD_DEMATRIX_MODE 0x00000300 +/* Reserved [7:6] */ +#define FLD_PH_DBX_SEL 0x00000020 +#define FLD_PH_CH_SEL 0x00000010 +#define FLD_PHASE_FIX 0x0000000f + +/*****************************************************************************/ +#define PATH1_CTL1 0x8d0 +/* Reserved [31:29] */ +#define FLD_PATH1_MUTE_CTL 0x1f000000 +/* Reserved [23:22] */ +#define FLD_PATH1_AVC_CG 0x00300000 +#define FLD_PATH1_AVC_RT 0x000f0000 +#define FLD_PATH1_AVC_AT 0x0000f000 +#define FLD_PATH1_AVC_STEREO 0x00000800 +#define FLD_PATH1_AVC_CR 0x00000700 +#define FLD_PATH1_AVC_RMS_CON 0x000000f0 +#define FLD_PATH1_SEL_CTL 0x0000000f + +/*****************************************************************************/ +#define PATH1_VOL_CTL 0x8d4 +#define FLD_PATH1_AVC_THRESHOLD 0x7fff0000 +#define FLD_PATH1_BAL_LEFT 0x00008000 +#define FLD_PATH1_BAL_LEVEL 0x00007f00 +#define FLD_PATH1_VOLUME 0x000000ff + +/*****************************************************************************/ +#define PATH1_EQ_CTL 0x8d8 +/* Reserved [31:30] */ +#define FLD_PATH1_EQ_TREBLE_VOL 0x3f000000 +/* Reserved [23:22] */ +#define FLD_PATH1_EQ_MID_VOL 0x003f0000 +/* Reserved [15:14] */ +#define FLD_PATH1_EQ_BASS_VOL 0x00003f00 +/* Reserved [7:1] */ +#define FLD_PATH1_EQ_BAND_SEL 0x00000001 + +/*****************************************************************************/ +#define PATH1_SC_CTL 0x8dc +#define FLD_PATH1_SC_THRESHOLD 0x7fff0000 +#define FLD_PATH1_SC_RT 0x0000f000 +#define FLD_PATH1_SC_AT 0x00000f00 +#define FLD_PATH1_SC_STEREO 0x00000080 +#define FLD_PATH1_SC_CR 0x00000070 +#define FLD_PATH1_SC_RMS_CON 0x0000000f + +/*****************************************************************************/ +#define PATH2_CTL1 0x8e0 +/* Reserved [31:26] */ +#define FLD_PATH2_MUTE_CTL 0x03000000 +/* Reserved [23:22] */ +#define FLD_PATH2_AVC_CG 0x00300000 +#define FLD_PATH2_AVC_RT 0x000f0000 +#define FLD_PATH2_AVC_AT 0x0000f000 +#define FLD_PATH2_AVC_STEREO 0x00000800 +#define FLD_PATH2_AVC_CR 0x00000700 +#define FLD_PATH2_AVC_RMS_CON 0x000000f0 +#define FLD_PATH2_SEL_CTL 0x0000000f + +/*****************************************************************************/ +#define PATH2_VOL_CTL 0x8e4 +#define FLD_PATH2_AVC_THRESHOLD 0xffff0000 +#define FLD_PATH2_BAL_LEFT 0x00008000 +#define FLD_PATH2_BAL_LEVEL 0x00007f00 +#define FLD_PATH2_VOLUME 0x000000ff + +/*****************************************************************************/ +#define PATH2_EQ_CTL 0x8e8 +/* Reserved [31:30] */ +#define FLD_PATH2_EQ_TREBLE_VOL 0x3f000000 +/* Reserved [23:22] */ +#define FLD_PATH2_EQ_MID_VOL 0x003f0000 +/* Reserved [15:14] */ +#define FLD_PATH2_EQ_BASS_VOL 0x00003f00 +/* Reserved [7:1] */ +#define FLD_PATH2_EQ_BAND_SEL 0x00000001 + +/*****************************************************************************/ +#define PATH2_SC_CTL 0x8eC +#define FLD_PATH2_SC_THRESHOLD 0xffff0000 +#define FLD_PATH2_SC_RT 0x0000f000 +#define FLD_PATH2_SC_AT 0x00000f00 +#define FLD_PATH2_SC_STEREO 0x00000080 +#define FLD_PATH2_SC_CR 0x00000070 +#define FLD_PATH2_SC_RMS_CON 0x0000000f + +/*****************************************************************************/ +#define SRC_CTL 0x8f0 +#define FLD_SRC_STATUS 0xffffff00 +#define FLD_FIFO_LF_EN 0x000000fc +#define FLD_BYPASS_LI 0x00000002 +#define FLD_BYPASS_PF 0x00000001 + +/*****************************************************************************/ +#define SRC_LF_COEF 0x8f4 +#define FLD_LOOP_FILTER_COEF2 0xffff0000 +#define FLD_LOOP_FILTER_COEF1 0x0000ffff + +/*****************************************************************************/ +#define SRC1_CTL 0x8f8 +/* Reserved [31:28] */ +#define FLD_SRC1_FIFO_RD_TH 0x0f000000 +/* Reserved [23:18] */ +#define FLD_SRC1_PHASE_INC 0x0003ffff + +/*****************************************************************************/ +#define SRC2_CTL 0x8fc +/* Reserved [31:28] */ +#define FLD_SRC2_FIFO_RD_TH 0x0f000000 +/* Reserved [23:18] */ +#define FLD_SRC2_PHASE_INC 0x0003ffff + +/*****************************************************************************/ +#define SRC3_CTL 0x900 +/* Reserved [31:28] */ +#define FLD_SRC3_FIFO_RD_TH 0x0f000000 +/* Reserved [23:18] */ +#define FLD_SRC3_PHASE_INC 0x0003ffff + +/*****************************************************************************/ +#define SRC4_CTL 0x904 +/* Reserved [31:28] */ +#define FLD_SRC4_FIFO_RD_TH 0x0f000000 +/* Reserved [23:18] */ +#define FLD_SRC4_PHASE_INC 0x0003ffff + +/*****************************************************************************/ +#define SRC5_CTL 0x908 +/* Reserved [31:28] */ +#define FLD_SRC5_FIFO_RD_TH 0x0f000000 +/* Reserved [23:18] */ +#define FLD_SRC5_PHASE_INC 0x0003ffff + +/*****************************************************************************/ +#define SRC6_CTL 0x90c +/* Reserved [31:28] */ +#define FLD_SRC6_FIFO_RD_TH 0x0f000000 +/* Reserved [23:18] */ +#define FLD_SRC6_PHASE_INC 0x0003ffff + +/*****************************************************************************/ +#define BAND_OUT_SEL 0x910 +#define FLD_SRC6_IN_SEL 0xc0000000 +#define FLD_SRC6_CLK_SEL 0x30000000 +#define FLD_SRC5_IN_SEL 0x0c000000 +#define FLD_SRC5_CLK_SEL 0x03000000 +#define FLD_SRC4_IN_SEL 0x00c00000 +#define FLD_SRC4_CLK_SEL 0x00300000 +#define FLD_SRC3_IN_SEL 0x000c0000 +#define FLD_SRC3_CLK_SEL 0x00030000 +#define FLD_BASEBAND_BYPASS_CTL 0x0000ff00 +#define FLD_AC97_SRC_SEL 0x000000c0 +#define FLD_I2S_SRC_SEL 0x00000030 +#define FLD_PARALLEL2_SRC_SEL 0x0000000c +#define FLD_PARALLEL1_SRC_SEL 0x00000003 + +/*****************************************************************************/ +#define I2S_IN_CTL 0x914 +/* Reserved [31:11] */ +#define FLD_I2S_UP2X_BW20K 0x00000400 +#define FLD_I2S_UP2X_BYPASS 0x00000200 +#define FLD_I2S_IN_MASTER_MODE 0x00000100 +#define FLD_I2S_IN_SONY_MODE 0x00000080 +#define FLD_I2S_IN_RIGHT_JUST 0x00000040 +#define FLD_I2S_IN_WS_SEL 0x00000020 +#define FLD_I2S_IN_BCN_DEL 0x0000001f + +/*****************************************************************************/ +#define I2S_OUT_CTL 0x918 +/* Reserved [31:17] */ +#define FLD_I2S_OUT_SOFT_RESET_EN 0x00010000 +/* Reserved [15:9] */ +#define FLD_I2S_OUT_MASTER_MODE 0x00000100 +#define FLD_I2S_OUT_SONY_MODE 0x00000080 +#define FLD_I2S_OUT_RIGHT_JUST 0x00000040 +#define FLD_I2S_OUT_WS_SEL 0x00000020 +#define FLD_I2S_OUT_BCN_DEL 0x0000001f + +/*****************************************************************************/ +#define AC97_CTL 0x91c +/* Reserved [31:26] */ +#define FLD_AC97_UP2X_BW20K 0x02000000 +#define FLD_AC97_UP2X_BYPASS 0x01000000 +/* Reserved [23:17] */ +#define FLD_AC97_RST_ACL 0x00010000 +/* Reserved [15:9] */ +#define FLD_AC97_WAKE_UP_SYNC 0x00000100 +/* Reserved [7:1] */ +#define FLD_AC97_SHUTDOWN 0x00000001 + +/* Cx231xx redefine */ +#define QPSK_IAGC_CTL1 0x94c +#define QPSK_IAGC_CTL2 0x950 +#define QPSK_FEPR_FREQ 0x954 +#define QPSK_BTL_CTL1 0x958 +#define QPSK_BTL_CTL2 0x95c +#define QPSK_CTL_CTL1 0x960 +#define QPSK_CTL_CTL2 0x964 +#define QPSK_MF_FAGC_CTL 0x968 +#define QPSK_EQ_CTL 0x96c +#define QPSK_LOCK_CTL 0x970 + +/*****************************************************************************/ +#define FM1_DFT_CTL 0x9a8 +#define FLD_FM1_DFT_THRESHOLD 0xffff0000 +/* Reserved [15:8] */ +#define FLD_FM1_DFT_CMP_CTL 0x00000080 +#define FLD_FM1_DFT_AVG 0x00000070 +/* Reserved [3:1] */ +#define FLD_FM1_DFT_START 0x00000001 + +/*****************************************************************************/ +#define FM1_DFT_STATUS 0x9ac +#define FLD_FM1_DFT_DONE 0x80000000 +/* Reserved [30:19] */ +#define FLD_FM_DFT_TH_CMP 0x00040000 +#define FLD_FM1_DFT 0x0003ffff + +/*****************************************************************************/ +#define FM2_DFT_CTL 0x9b0 +#define FLD_FM2_DFT_THRESHOLD 0xffff0000 +/* Reserved [15:8] */ +#define FLD_FM2_DFT_CMP_CTL 0x00000080 +#define FLD_FM2_DFT_AVG 0x00000070 +/* Reserved [3:1] */ +#define FLD_FM2_DFT_START 0x00000001 + +/*****************************************************************************/ +#define FM2_DFT_STATUS 0x9b4 +#define FLD_FM2_DFT_DONE 0x80000000 +/* Reserved [30:19] */ +#define FLD_FM2_DFT_TH_CMP_STAT 0x00040000 +#define FLD_FM2_DFT 0x0003ffff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define AAGC_STATUS_REG 0x9b8 +#define AAGC_STATUS 0x9b8 +/* Reserved [31:27] */ +#define FLD_FM2_DAGC_OUT 0x07000000 +/* Reserved [23:19] */ +#define FLD_FM1_DAGC_OUT 0x00070000 +/* Reserved [15:6] */ +#define FLD_AFE_VGA_OUT 0x0000003f + +/*****************************************************************************/ +#define MTS_GAIN_STATUS 0x9bc +/* Reserved [31:14] */ +#define FLD_MTS_GAIN 0x00003fff + +#define RDS_OUT 0x9c0 +#define FLD_RDS_Q 0xffff0000 +#define FLD_RDS_I 0x0000ffff + +/*****************************************************************************/ +#define AUTOCONFIG_REG 0x9c4 +/* Reserved [31:4] */ +#define FLD_AUTOCONFIG_MODE 0x0000000f + +#define FM_AFC 0x9c8 +#define FLD_FM2_AFC 0xffff0000 +#define FLD_FM1_AFC 0x0000ffff + +/*****************************************************************************/ +/* Cx231xx redefine */ +#define NEW_SPARE 0x9cc +#define NEW_SPARE_REG 0x9cc + +/*****************************************************************************/ +#define DBX_ADJ 0x9d0 +/* Reserved [31:28] */ +#define FLD_DBX2_ADJ 0x0fff0000 +/* Reserved [15:12] */ +#define FLD_DBX1_ADJ 0x00000fff + +#define VID_FMT_AUTO 0 +#define VID_FMT_NTSC_M 1 +#define VID_FMT_NTSC_J 2 +#define VID_FMT_NTSC_443 3 +#define VID_FMT_PAL_BDGHI 4 +#define VID_FMT_PAL_M 5 +#define VID_FMT_PAL_N 6 +#define VID_FMT_PAL_NC 7 +#define VID_FMT_PAL_60 8 +#define VID_FMT_SECAM 12 +#define VID_FMT_SECAM_60 13 + +#define INPUT_MODE_CVBS_0 0 /* INPUT_MODE_VALUE(0) */ +#define INPUT_MODE_YC_1 1 /* INPUT_MODE_VALUE(1) */ +#define INPUT_MODE_YC2_2 2 /* INPUT_MODE_VALUE(2) */ +#define INPUT_MODE_YUV_3 3 /* INPUT_MODE_VALUE(3) */ + +#define LUMA_LPF_LOW_BANDPASS 0 /* 0.6Mhz LPF BW */ +#define LUMA_LPF_MEDIUM_BANDPASS 1 /* 1.0Mhz LPF BW */ +#define LUMA_LPF_HIGH_BANDPASS 2 /* 1.5Mhz LPF BW */ + +#define UV_LPF_LOW_BANDPASS 0 /* 0.6Mhz LPF BW */ +#define UV_LPF_MEDIUM_BANDPASS 1 /* 1.0Mhz LPF BW */ +#define UV_LPF_HIGH_BANDPASS 2 /* 1.5Mhz LPF BW */ + +#define TWO_TAP_FILT 0 +#define THREE_TAP_FILT 1 +#define FOUR_TAP_FILT 2 +#define FIVE_TAP_FILT 3 + +#define AUD_CHAN_SRC_PARALLEL 0 +#define AUD_CHAN_SRC_I2S_INPUT 1 +#define AUD_CHAN_SRC_FLATIRON 2 +#define AUD_CHAN_SRC_PARALLEL3 3 + +#define OUT_MODE_601 0 +#define OUT_MODE_656 1 +#define OUT_MODE_VIP11 2 +#define OUT_MODE_VIP20 3 + +#define PHASE_INC_49MHZ 0x0df22 +#define PHASE_INC_56MHZ 0x0fa5b +#define PHASE_INC_28MHZ 0x010000 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-vbi.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,714 @@ +/* + cx231xx_vbi.c - driver for Conexant Cx23100/101/102 USB video capture devices + + Copyright (C) 2008 + Based on cx88 driver + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "cx231xx.h" +#include "cx231xx-vbi.h" + +static inline void print_err_status(struct cx231xx *dev, int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + cx231xx_err(DRIVER_NAME "URB status %d [%s].\n", status, + errmsg); + } else { + cx231xx_err(DRIVER_NAME "URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + +/* + * Controls the isoc copy of each urb packet + */ +static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb) +{ + struct cx231xx_buffer *buf; + struct cx231xx_dmaqueue *dma_q = urb->context; + int rc = 1; + unsigned char *p_buffer; + u32 bytes_parsed = 0, buffer_size = 0; + u8 sav_eav = 0; + + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + buf = dev->vbi_mode.bulk_ctl.buf; + + /* get buffer pointer and length */ + p_buffer = urb->transfer_buffer; + buffer_size = urb->actual_length; + + if (buffer_size > 0) { + bytes_parsed = 0; + + if (dma_q->is_partial_line) { + /* Handle the case where we were working on a partial + line */ + sav_eav = dma_q->last_sav; + } else { + /* Check for a SAV/EAV overlapping the + buffer boundary */ + + sav_eav = cx231xx_find_boundary_SAV_EAV(p_buffer, + dma_q->partial_buf, + &bytes_parsed); + } + + sav_eav &= 0xF0; + /* Get the first line if we have some portion of an SAV/EAV from + the last buffer or a partial line */ + if (sav_eav) { + bytes_parsed += cx231xx_get_vbi_line(dev, dma_q, + sav_eav, /* SAV/EAV */ + p_buffer + bytes_parsed, /* p_buffer */ + buffer_size - bytes_parsed); /* buffer size */ + } + + /* Now parse data that is completely in this buffer */ + dma_q->is_partial_line = 0; + + while (bytes_parsed < buffer_size) { + u32 bytes_used = 0; + + sav_eav = cx231xx_find_next_SAV_EAV( + p_buffer + bytes_parsed, /* p_buffer */ + buffer_size - bytes_parsed, /* buffer size */ + &bytes_used); /* bytes used to get SAV/EAV */ + + bytes_parsed += bytes_used; + + sav_eav &= 0xF0; + if (sav_eav && (bytes_parsed < buffer_size)) { + bytes_parsed += cx231xx_get_vbi_line(dev, + dma_q, sav_eav, /* SAV/EAV */ + p_buffer+bytes_parsed, /* p_buffer */ + buffer_size-bytes_parsed);/*buf size*/ + } + } + + /* Save the last four bytes of the buffer so we can + check the buffer boundary condition next time */ + memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4); + bytes_parsed = 0; + } + + return rc; +} + +/* ------------------------------------------------------------------ + Vbi buf operations + ------------------------------------------------------------------*/ + +static int +vbi_buffer_setup(struct videobuf_queue *vq, unsigned int *count, + unsigned int *size) +{ + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx *dev = fh->dev; + u32 height = 0; + + height = ((dev->norm & V4L2_STD_625_50) ? + PAL_VBI_LINES : NTSC_VBI_LINES); + + *size = (dev->width * height * 2 * 2); + if (0 == *count) + *count = CX231XX_DEF_VBI_BUF; + + if (*count < CX231XX_MIN_BUF) + *count = CX231XX_MIN_BUF; + + return 0; +} + +/* This is called *without* dev->slock held; please keep it that way */ +static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) +{ + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx *dev = fh->dev; + unsigned long flags = 0; + if (in_interrupt()) + BUG(); + + /* We used to wait for the buffer to finish here, but this didn't work + because, as we were keeping the state as VIDEOBUF_QUEUED, + videobuf_queue_cancel marked it as finished for us. + (Also, it could wedge forever if the hardware was misconfigured.) + + This should be safe; by the time we get here, the buffer isn't + queued anymore. If we ever start marking the buffers as + VIDEOBUF_ACTIVE, it won't be, though. + */ + spin_lock_irqsave(&dev->vbi_mode.slock, flags); + if (dev->vbi_mode.bulk_ctl.buf == buf) + dev->vbi_mode.bulk_ctl.buf = NULL; + spin_unlock_irqrestore(&dev->vbi_mode.slock, flags); + + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int +vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb); + struct cx231xx *dev = fh->dev; + int rc = 0, urb_init = 0; + u32 height = 0; + + height = ((dev->norm & V4L2_STD_625_50) ? + PAL_VBI_LINES : NTSC_VBI_LINES); + buf->vb.size = ((dev->width << 1) * height * 2); + + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + buf->vb.width = dev->width; + buf->vb.height = height; + buf->vb.field = field; + buf->vb.field = V4L2_FIELD_SEQ_TB; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc < 0) + goto fail; + } + + if (!dev->vbi_mode.bulk_ctl.num_bufs) + urb_init = 1; + + if (urb_init) { + rc = cx231xx_init_vbi_isoc(dev, CX231XX_NUM_VBI_PACKETS, + CX231XX_NUM_VBI_BUFS, + dev->vbi_mode.alt_max_pkt_size[0], + cx231xx_isoc_vbi_copy); + if (rc < 0) + goto fail; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(vq, buf); + return rc; +} + +static void +vbi_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb); + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx *dev = fh->dev; + struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vidq->active); + +} + +static void vbi_buffer_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb); + + + free_buffer(vq, buf); +} + +struct videobuf_queue_ops cx231xx_vbi_qops = { + .buf_setup = vbi_buffer_setup, + .buf_prepare = vbi_buffer_prepare, + .buf_queue = vbi_buffer_queue, + .buf_release = vbi_buffer_release, +}; + +/* ------------------------------------------------------------------ + URB control + ------------------------------------------------------------------*/ + +/* + * IRQ callback, called by URB callback + */ +static void cx231xx_irq_vbi_callback(struct urb *urb) +{ + struct cx231xx_dmaqueue *dma_q = urb->context; + struct cx231xx_video_mode *vmode = + container_of(dma_q, struct cx231xx_video_mode, vidq); + struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode); + int rc; + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + cx231xx_err(DRIVER_NAME "urb completition error %d.\n", + urb->status); + break; + } + + /* Copy data from URB */ + spin_lock(&dev->vbi_mode.slock); + rc = dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb); + spin_unlock(&dev->vbi_mode.slock); + + /* Reset status */ + urb->status = 0; + + urb->status = usb_submit_urb(urb, GFP_ATOMIC); + if (urb->status) { + cx231xx_err(DRIVER_NAME "urb resubmit failed (error=%i)\n", + urb->status); + } +} + +/* + * Stop and Deallocate URBs + */ +void cx231xx_uninit_vbi_isoc(struct cx231xx *dev) +{ + struct urb *urb; + int i; + + cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_uninit_vbi_isoc\n"); + + dev->vbi_mode.bulk_ctl.nfields = -1; + for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { + urb = dev->vbi_mode.bulk_ctl.urb[i]; + if (urb) { + if (!irqs_disabled()) + usb_kill_urb(urb); + else + usb_unlink_urb(urb); + + if (dev->vbi_mode.bulk_ctl.transfer_buffer[i]) { + + kfree(dev->vbi_mode.bulk_ctl. + transfer_buffer[i]); + dev->vbi_mode.bulk_ctl.transfer_buffer[i] = + NULL; + } + usb_free_urb(urb); + dev->vbi_mode.bulk_ctl.urb[i] = NULL; + } + dev->vbi_mode.bulk_ctl.transfer_buffer[i] = NULL; + } + + kfree(dev->vbi_mode.bulk_ctl.urb); + kfree(dev->vbi_mode.bulk_ctl.transfer_buffer); + + dev->vbi_mode.bulk_ctl.urb = NULL; + dev->vbi_mode.bulk_ctl.transfer_buffer = NULL; + dev->vbi_mode.bulk_ctl.num_bufs = 0; + + cx231xx_capture_start(dev, 0, Vbi); +} +EXPORT_SYMBOL_GPL(cx231xx_uninit_vbi_isoc); + +/* + * Allocate URBs and start IRQ + */ +int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*bulk_copy) (struct cx231xx *dev, + struct urb *urb)) +{ + struct cx231xx_dmaqueue *dma_q = &dev->vbi_mode.vidq; + int i; + int sb_size, pipe; + struct urb *urb; + int rc; + + cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_prepare_isoc\n"); + + /* De-allocates all pending stuff */ + cx231xx_uninit_vbi_isoc(dev); + + /* clear if any halt */ + usb_clear_halt(dev->udev, + usb_rcvbulkpipe(dev->udev, + dev->vbi_mode.end_point_addr)); + + dev->vbi_mode.bulk_ctl.bulk_copy = bulk_copy; + dev->vbi_mode.bulk_ctl.num_bufs = num_bufs; + dma_q->pos = 0; + dma_q->is_partial_line = 0; + dma_q->last_sav = 0; + dma_q->current_field = -1; + dma_q->bytes_left_in_line = dev->width << 1; + dma_q->lines_per_field = ((dev->norm & V4L2_STD_625_50) ? + PAL_VBI_LINES : NTSC_VBI_LINES); + dma_q->lines_completed = 0; + for (i = 0; i < 8; i++) + dma_q->partial_buf[i] = 0; + + dev->vbi_mode.bulk_ctl.urb = kzalloc(sizeof(void *) * num_bufs, + GFP_KERNEL); + if (!dev->vbi_mode.bulk_ctl.urb) { + cx231xx_errdev("cannot alloc memory for usb buffers\n"); + return -ENOMEM; + } + + dev->vbi_mode.bulk_ctl.transfer_buffer = + kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + if (!dev->vbi_mode.bulk_ctl.transfer_buffer) { + cx231xx_errdev("cannot allocate memory for usbtransfer\n"); + kfree(dev->vbi_mode.bulk_ctl.urb); + return -ENOMEM; + } + + dev->vbi_mode.bulk_ctl.max_pkt_size = max_pkt_size; + dev->vbi_mode.bulk_ctl.buf = NULL; + + sb_size = max_packets * dev->vbi_mode.bulk_ctl.max_pkt_size; + + /* allocate urbs and transfer buffers */ + for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + cx231xx_err(DRIVER_NAME + ": cannot alloc bulk_ctl.urb %i\n", i); + cx231xx_uninit_vbi_isoc(dev); + return -ENOMEM; + } + dev->vbi_mode.bulk_ctl.urb[i] = urb; + urb->transfer_flags = 0; + + dev->vbi_mode.bulk_ctl.transfer_buffer[i] = + kzalloc(sb_size, GFP_KERNEL); + if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) { + cx231xx_err(DRIVER_NAME + ": unable to allocate %i bytes for transfer" + " buffer %i%s\n", sb_size, i, + in_interrupt() ? " while in int" : ""); + cx231xx_uninit_vbi_isoc(dev); + return -ENOMEM; + } + + pipe = usb_rcvbulkpipe(dev->udev, dev->vbi_mode.end_point_addr); + usb_fill_bulk_urb(urb, dev->udev, pipe, + dev->vbi_mode.bulk_ctl.transfer_buffer[i], + sb_size, cx231xx_irq_vbi_callback, dma_q); + } + + init_waitqueue_head(&dma_q->wq); + + /* submit urbs and enables IRQ */ + for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC); + if (rc) { + cx231xx_err(DRIVER_NAME + ": submit of urb %i failed (error=%i)\n", i, + rc); + cx231xx_uninit_vbi_isoc(dev); + return rc; + } + } + + cx231xx_capture_start(dev, 1, Vbi); + + return 0; +} +EXPORT_SYMBOL_GPL(cx231xx_init_vbi_isoc); + +u32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 sav_eav, u8 *p_buffer, u32 buffer_size) +{ + u32 bytes_copied = 0; + int current_field = -1; + + switch (sav_eav) { + + case SAV_VBI_FIELD1: + current_field = 1; + break; + + case SAV_VBI_FIELD2: + current_field = 2; + break; + default: + break; + } + + if (current_field < 0) + return bytes_copied; + + dma_q->last_sav = sav_eav; + + bytes_copied = + cx231xx_copy_vbi_line(dev, dma_q, p_buffer, buffer_size, + current_field); + + return bytes_copied; +} + +/* + * Announces that a buffer were filled and request the next + */ +static inline void vbi_buffer_filled(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q, + struct cx231xx_buffer *buf) +{ + /* Advice that buffer was filled */ + /* cx231xx_info(DRIVER_NAME "[%p/%d] wakeup\n", buf, buf->vb.i); */ + + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + + dev->vbi_mode.bulk_ctl.buf = NULL; + + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); +} + +u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 *p_line, u32 length, int field_number) +{ + u32 bytes_to_copy; + struct cx231xx_buffer *buf; + u32 _line_size = dev->width * 2; + + if (dma_q->current_field == -1) { + /* Just starting up */ + cx231xx_reset_vbi_buffer(dev, dma_q); + } + + if (dma_q->current_field != field_number) + dma_q->lines_completed = 0; + + /* get the buffer pointer */ + buf = dev->vbi_mode.bulk_ctl.buf; + + /* Remember the field number for next time */ + dma_q->current_field = field_number; + + bytes_to_copy = dma_q->bytes_left_in_line; + if (bytes_to_copy > length) + bytes_to_copy = length; + + if (dma_q->lines_completed >= dma_q->lines_per_field) { + dma_q->bytes_left_in_line -= bytes_to_copy; + dma_q->is_partial_line = + (dma_q->bytes_left_in_line == 0) ? 0 : 1; + return 0; + } + + dma_q->is_partial_line = 1; + + /* If we don't have a buffer, just return the number of bytes we would + have copied if we had a buffer. */ + if (!buf) { + dma_q->bytes_left_in_line -= bytes_to_copy; + dma_q->is_partial_line = + (dma_q->bytes_left_in_line == 0) ? 0 : 1; + return bytes_to_copy; + } + + /* copy the data to video buffer */ + cx231xx_do_vbi_copy(dev, dma_q, p_line, bytes_to_copy); + + dma_q->pos += bytes_to_copy; + dma_q->bytes_left_in_line -= bytes_to_copy; + + if (dma_q->bytes_left_in_line == 0) { + + dma_q->bytes_left_in_line = _line_size; + dma_q->lines_completed++; + dma_q->is_partial_line = 0; + + if (cx231xx_is_vbi_buffer_done(dev, dma_q) && buf) { + + vbi_buffer_filled(dev, dma_q, buf); + + dma_q->pos = 0; + dma_q->lines_completed = 0; + cx231xx_reset_vbi_buffer(dev, dma_q); + } + } + + return bytes_to_copy; +} + +/* + * video-buf generic routine to get the next available buffer + */ +static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q, + struct cx231xx_buffer **buf) +{ + struct cx231xx_video_mode *vmode = + container_of(dma_q, struct cx231xx_video_mode, vidq); + struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode); + char *outp; + + if (list_empty(&dma_q->active)) { + cx231xx_err(DRIVER_NAME ": No active queue to serve\n"); + dev->vbi_mode.bulk_ctl.buf = NULL; + *buf = NULL; + return; + } + + /* Get the next buffer */ + *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue); + + /* Cleans up buffer - Useful for testing for frame/URB loss */ + outp = videobuf_to_vmalloc(&(*buf)->vb); + memset(outp, 0, (*buf)->vb.size); + + dev->vbi_mode.bulk_ctl.buf = *buf; + + return; +} + +void cx231xx_reset_vbi_buffer(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q) +{ + struct cx231xx_buffer *buf; + + buf = dev->vbi_mode.bulk_ctl.buf; + + if (buf == NULL) { + /* first try to get the buffer */ + get_next_vbi_buf(dma_q, &buf); + + dma_q->pos = 0; + dma_q->current_field = -1; + } + + dma_q->bytes_left_in_line = dev->width << 1; + dma_q->lines_completed = 0; +} + +int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 *p_buffer, u32 bytes_to_copy) +{ + u8 *p_out_buffer = NULL; + u32 current_line_bytes_copied = 0; + struct cx231xx_buffer *buf; + u32 _line_size = dev->width << 1; + void *startwrite; + int offset, lencopy; + + buf = dev->vbi_mode.bulk_ctl.buf; + + if (buf == NULL) + return -EINVAL; + + p_out_buffer = videobuf_to_vmalloc(&buf->vb); + + if (dma_q->bytes_left_in_line != _line_size) { + current_line_bytes_copied = + _line_size - dma_q->bytes_left_in_line; + } + + offset = (dma_q->lines_completed * _line_size) + + current_line_bytes_copied; + + if (dma_q->current_field == 2) { + /* Populate the second half of the frame */ + offset += (dev->width * 2 * dma_q->lines_per_field); + } + + /* prepare destination address */ + startwrite = p_out_buffer + offset; + + lencopy = dma_q->bytes_left_in_line > bytes_to_copy ? + bytes_to_copy : dma_q->bytes_left_in_line; + + memcpy(startwrite, p_buffer, lencopy); + + return 0; +} + +u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q) +{ + u32 height = 0; + + height = ((dev->norm & V4L2_STD_625_50) ? + PAL_VBI_LINES : NTSC_VBI_LINES); + if (dma_q->lines_completed == height && dma_q->current_field == 2) + return 1; + else + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-vbi.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-vbi.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-vbi.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-vbi.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,65 @@ +/* + cx231xx_vbi.h - driver for Conexant Cx23100/101/102 USB video capture devices + + Copyright (C) 2008 + Based on cx88 driver + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CX231XX_VBI_H +#define _CX231XX_VBI_H + +extern struct videobuf_queue_ops cx231xx_vbi_qops; + +#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ +#define NTSC_VBI_END_LINE 21 +#define NTSC_VBI_LINES (NTSC_VBI_END_LINE-NTSC_VBI_START_LINE+1) + +#define PAL_VBI_START_LINE 6 +#define PAL_VBI_END_LINE 23 +#define PAL_VBI_LINES (PAL_VBI_END_LINE-PAL_VBI_START_LINE+1) + +#define VBI_STRIDE 1440 +#define VBI_SAMPLES_PER_LINE 1440 + +#define CX231XX_NUM_VBI_PACKETS 4 +#define CX231XX_NUM_VBI_BUFS 5 + +/* stream functions */ +int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*bulk_copy) (struct cx231xx *dev, + struct urb *urb)); + +void cx231xx_uninit_vbi_isoc(struct cx231xx *dev); + +/* vbi data copy functions */ +u32 cx231xx_get_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 sav_eav, u8 *p_buffer, u32 buffer_size); + +u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 *p_line, u32 length, int field_number); + +void cx231xx_reset_vbi_buffer(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q); + +int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 *p_buffer, u32 bytes_to_copy); + +u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-video.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/cx231xx-video.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2658 @@ +/* + cx231xx-video.c - driver for Conexant Cx23100/101/102 + USB video capture devices + + Copyright (C) 2008 + Based on em28xx driver + Based on cx23885 driver + Based on cx88 driver + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "cx231xx.h" +#include "cx231xx-vbi.h" + +#define CX231XX_VERSION_CODE KERNEL_VERSION(0, 0, 1) + +#define DRIVER_AUTHOR "Srinivasa Deevi " +#define DRIVER_DESC "Conexant cx231xx based USB video device driver" + +#define cx231xx_videodbg(fmt, arg...) do {\ + if (video_debug) \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); } while (0) + +static unsigned int isoc_debug; +module_param(isoc_debug, int, 0644); +MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); + +#define cx231xx_isocdbg(fmt, arg...) \ +do {\ + if (isoc_debug) { \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); \ + } \ + } while (0) + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; + +module_param_array(card, int, NULL, 0444); +module_param_array(video_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); + +MODULE_PARM_DESC(card, "card type"); +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); + +static unsigned int video_debug; +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); + +/* supported video standards */ +static struct cx231xx_fmt format[] = { + { + .name = "16bpp YUY2, 4:2:2, packed", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .reg = 0, + }, +}; + +/* supported controls */ +/* Common to all boards */ + +/* ------------------------------------------------------------------- */ + +static const struct v4l2_queryctrl no_ctl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; + +static struct cx231xx_ctrl cx231xx_ctls[] = { + /* --- video --- */ + { + .v = { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = LUMA_CTRL, + .mask = 0x00ff, + .shift = 0, + }, { + .v = { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = LUMA_CTRL, + .mask = 0xff00, + .shift = 8, + }, { + .v = { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = CHROMA_CTRL, + .mask = 0xff0000, + .shift = 16, + }, { + /* strictly, this only describes only U saturation. + * V saturation is handled specially through code. + */ + .v = { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = CHROMA_CTRL, + .mask = 0x00ff, + .shift = 0, + }, { + /* --- audio --- */ + .v = { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, + .reg = PATH1_CTL1, + .mask = (0x1f << 24), + .shift = 24, + }, { + .v = { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 0x3f, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .reg = PATH1_VOL_CTL, + .mask = 0xff, + .shift = 0, + } +}; +static const int CX231XX_CTLS = ARRAY_SIZE(cx231xx_ctls); + +static const u32 cx231xx_user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_AUDIO_VOLUME, +#if 0 + V4L2_CID_AUDIO_BALANCE, +#endif + V4L2_CID_AUDIO_MUTE, + 0 +}; + +static const u32 *ctrl_classes[] = { + cx231xx_user_ctrls, + NULL +}; + +/* ------------------------------------------------------------------ + Video buffer and parser functions + ------------------------------------------------------------------*/ + +/* + * Announces that a buffer were filled and request the next + */ +static inline void buffer_filled(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q, + struct cx231xx_buffer *buf) +{ + /* Advice that buffer was filled */ + cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + + if (dev->USE_ISO) + dev->video_mode.isoc_ctl.buf = NULL; + else + dev->video_mode.bulk_ctl.buf = NULL; + + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); +} + +static inline void print_err_status(struct cx231xx *dev, int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + cx231xx_isocdbg("URB status %d [%s].\n", status, errmsg); + } else { + cx231xx_isocdbg("URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + +/* + * video-buf generic routine to get the next available buffer + */ +static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q, + struct cx231xx_buffer **buf) +{ + struct cx231xx_video_mode *vmode = + container_of(dma_q, struct cx231xx_video_mode, vidq); + struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode); + + char *outp; + + if (list_empty(&dma_q->active)) { + cx231xx_isocdbg("No active queue to serve\n"); + if (dev->USE_ISO) + dev->video_mode.isoc_ctl.buf = NULL; + else + dev->video_mode.bulk_ctl.buf = NULL; + *buf = NULL; + return; + } + + /* Get the next buffer */ + *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue); + + /* Cleans up buffer - Useful for testing for frame/URB loss */ + outp = videobuf_to_vmalloc(&(*buf)->vb); + memset(outp, 0, (*buf)->vb.size); + + if (dev->USE_ISO) + dev->video_mode.isoc_ctl.buf = *buf; + else + dev->video_mode.bulk_ctl.buf = *buf; + + return; +} + +/* + * Controls the isoc copy of each urb packet + */ +static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) +{ + struct cx231xx_buffer *buf; + struct cx231xx_dmaqueue *dma_q = urb->context; + unsigned char *outp = NULL; + int i, rc = 1; + unsigned char *p_buffer; + u32 bytes_parsed = 0, buffer_size = 0; + u8 sav_eav = 0; + + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + buf = dev->video_mode.isoc_ctl.buf; + if (buf != NULL) + outp = videobuf_to_vmalloc(&buf->vb); + + for (i = 0; i < urb->number_of_packets; i++) { + int status = urb->iso_frame_desc[i].status; + + if (status < 0) { + print_err_status(dev, i, status); + if (urb->iso_frame_desc[i].status != -EPROTO) + continue; + } + + if (urb->iso_frame_desc[i].actual_length <= 0) { + /* cx231xx_isocdbg("packet %d is empty",i); - spammy */ + continue; + } + if (urb->iso_frame_desc[i].actual_length > + dev->video_mode.max_pkt_size) { + cx231xx_isocdbg("packet bigger than packet size"); + continue; + } + + /* get buffer pointer and length */ + p_buffer = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + buffer_size = urb->iso_frame_desc[i].actual_length; + bytes_parsed = 0; + + if (dma_q->is_partial_line) { + /* Handle the case of a partial line */ + sav_eav = dma_q->last_sav; + } else { + /* Check for a SAV/EAV overlapping + the buffer boundary */ + sav_eav = + cx231xx_find_boundary_SAV_EAV(p_buffer, + dma_q->partial_buf, + &bytes_parsed); + } + + sav_eav &= 0xF0; + /* Get the first line if we have some portion of an SAV/EAV from + the last buffer or a partial line */ + if (sav_eav) { + bytes_parsed += cx231xx_get_video_line(dev, dma_q, + sav_eav, /* SAV/EAV */ + p_buffer + bytes_parsed, /* p_buffer */ + buffer_size - bytes_parsed);/* buf size */ + } + + /* Now parse data that is completely in this buffer */ + /* dma_q->is_partial_line = 0; */ + + while (bytes_parsed < buffer_size) { + u32 bytes_used = 0; + + sav_eav = cx231xx_find_next_SAV_EAV( + p_buffer + bytes_parsed, /* p_buffer */ + buffer_size - bytes_parsed, /* buf size */ + &bytes_used);/* bytes used to get SAV/EAV */ + + bytes_parsed += bytes_used; + + sav_eav &= 0xF0; + if (sav_eav && (bytes_parsed < buffer_size)) { + bytes_parsed += cx231xx_get_video_line(dev, + dma_q, sav_eav, /* SAV/EAV */ + p_buffer + bytes_parsed,/* p_buffer */ + buffer_size - bytes_parsed);/*buf size*/ + } + } + + /* Save the last four bytes of the buffer so we can check the + buffer boundary condition next time */ + memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4); + bytes_parsed = 0; + + } + return rc; +} + +static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) +{ + struct cx231xx_buffer *buf; + struct cx231xx_dmaqueue *dma_q = urb->context; + unsigned char *outp = NULL; + int rc = 1; + unsigned char *p_buffer; + u32 bytes_parsed = 0, buffer_size = 0; + u8 sav_eav = 0; + + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + buf = dev->video_mode.bulk_ctl.buf; + if (buf != NULL) + outp = videobuf_to_vmalloc(&buf->vb); + + if (1) { + + /* get buffer pointer and length */ + p_buffer = urb->transfer_buffer; + buffer_size = urb->actual_length; + bytes_parsed = 0; + + if (dma_q->is_partial_line) { + /* Handle the case of a partial line */ + sav_eav = dma_q->last_sav; + } else { + /* Check for a SAV/EAV overlapping + the buffer boundary */ + sav_eav = + cx231xx_find_boundary_SAV_EAV(p_buffer, + dma_q->partial_buf, + &bytes_parsed); + } + + sav_eav &= 0xF0; + /* Get the first line if we have some portion of an SAV/EAV from + the last buffer or a partial line */ + if (sav_eav) { + bytes_parsed += cx231xx_get_video_line(dev, dma_q, + sav_eav, /* SAV/EAV */ + p_buffer + bytes_parsed, /* p_buffer */ + buffer_size - bytes_parsed);/* buf size */ + } + + /* Now parse data that is completely in this buffer */ + /* dma_q->is_partial_line = 0; */ + + while (bytes_parsed < buffer_size) { + u32 bytes_used = 0; + + sav_eav = cx231xx_find_next_SAV_EAV( + p_buffer + bytes_parsed, /* p_buffer */ + buffer_size - bytes_parsed, /* buf size */ + &bytes_used);/* bytes used to get SAV/EAV */ + + bytes_parsed += bytes_used; + + sav_eav &= 0xF0; + if (sav_eav && (bytes_parsed < buffer_size)) { + bytes_parsed += cx231xx_get_video_line(dev, + dma_q, sav_eav, /* SAV/EAV */ + p_buffer + bytes_parsed,/* p_buffer */ + buffer_size - bytes_parsed);/*buf size*/ + } + } + + /* Save the last four bytes of the buffer so we can check the + buffer boundary condition next time */ + memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4); + bytes_parsed = 0; + + } + return rc; +} + + +u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf, + u32 *p_bytes_used) +{ + u32 bytes_used; + u8 boundary_bytes[8]; + u8 sav_eav = 0; + + *p_bytes_used = 0; + + /* Create an array of the last 4 bytes of the last buffer and the first + 4 bytes of the current buffer. */ + + memcpy(boundary_bytes, partial_buf, 4); + memcpy(boundary_bytes + 4, p_buffer, 4); + + /* Check for the SAV/EAV in the boundary buffer */ + sav_eav = cx231xx_find_next_SAV_EAV((u8 *)&boundary_bytes, 8, + &bytes_used); + + if (sav_eav) { + /* found a boundary SAV/EAV. Updates the bytes used to reflect + only those used in the new buffer */ + *p_bytes_used = bytes_used - 4; + } + + return sav_eav; +} + +u8 cx231xx_find_next_SAV_EAV(u8 *p_buffer, u32 buffer_size, u32 *p_bytes_used) +{ + u32 i; + u8 sav_eav = 0; + + /* + * Don't search if the buffer size is less than 4. It causes a page + * fault since buffer_size - 4 evaluates to a large number in that + * case. + */ + if (buffer_size < 4) { + *p_bytes_used = buffer_size; + return 0; + } + + for (i = 0; i < (buffer_size - 3); i++) { + + if ((p_buffer[i] == 0xFF) && + (p_buffer[i + 1] == 0x00) && (p_buffer[i + 2] == 0x00)) { + + *p_bytes_used = i + 4; + sav_eav = p_buffer[i + 3]; + return sav_eav; + } + } + + *p_bytes_used = buffer_size; + return 0; +} + +u32 cx231xx_get_video_line(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q, u8 sav_eav, + u8 *p_buffer, u32 buffer_size) +{ + u32 bytes_copied = 0; + int current_field = -1; + + switch (sav_eav) { + case SAV_ACTIVE_VIDEO_FIELD1: + /* looking for skipped line which occurred in PAL 720x480 mode. + In this case, there will be no active data contained + between the SAV and EAV */ + if ((buffer_size > 3) && (p_buffer[0] == 0xFF) && + (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) && + ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) || + (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) || + (p_buffer[3] == EAV_VBLANK_FIELD1) || + (p_buffer[3] == EAV_VBLANK_FIELD2))) + return bytes_copied; + current_field = 1; + break; + + case SAV_ACTIVE_VIDEO_FIELD2: + /* looking for skipped line which occurred in PAL 720x480 mode. + In this case, there will be no active data contained between + the SAV and EAV */ + if ((buffer_size > 3) && (p_buffer[0] == 0xFF) && + (p_buffer[1] == 0x00) && (p_buffer[2] == 0x00) && + ((p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD1) || + (p_buffer[3] == EAV_ACTIVE_VIDEO_FIELD2) || + (p_buffer[3] == EAV_VBLANK_FIELD1) || + (p_buffer[3] == EAV_VBLANK_FIELD2))) + return bytes_copied; + current_field = 2; + break; + } + + dma_q->last_sav = sav_eav; + + bytes_copied = cx231xx_copy_video_line(dev, dma_q, p_buffer, + buffer_size, current_field); + + return bytes_copied; +} + +u32 cx231xx_copy_video_line(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q, u8 *p_line, + u32 length, int field_number) +{ + u32 bytes_to_copy; + struct cx231xx_buffer *buf; + u32 _line_size = dev->width * 2; + + if (dma_q->current_field != field_number) + cx231xx_reset_video_buffer(dev, dma_q); + + /* get the buffer pointer */ + if (dev->USE_ISO) + buf = dev->video_mode.isoc_ctl.buf; + else + buf = dev->video_mode.bulk_ctl.buf; + + /* Remember the field number for next time */ + dma_q->current_field = field_number; + + bytes_to_copy = dma_q->bytes_left_in_line; + if (bytes_to_copy > length) + bytes_to_copy = length; + + if (dma_q->lines_completed >= dma_q->lines_per_field) { + dma_q->bytes_left_in_line -= bytes_to_copy; + dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) ? + 0 : 1; + return 0; + } + + dma_q->is_partial_line = 1; + + /* If we don't have a buffer, just return the number of bytes we would + have copied if we had a buffer. */ + if (!buf) { + dma_q->bytes_left_in_line -= bytes_to_copy; + dma_q->is_partial_line = (dma_q->bytes_left_in_line == 0) + ? 0 : 1; + return bytes_to_copy; + } + + /* copy the data to video buffer */ + cx231xx_do_copy(dev, dma_q, p_line, bytes_to_copy); + + dma_q->pos += bytes_to_copy; + dma_q->bytes_left_in_line -= bytes_to_copy; + + if (dma_q->bytes_left_in_line == 0) { + dma_q->bytes_left_in_line = _line_size; + dma_q->lines_completed++; + dma_q->is_partial_line = 0; + + if (cx231xx_is_buffer_done(dev, dma_q) && buf) { + buffer_filled(dev, dma_q, buf); + + dma_q->pos = 0; + buf = NULL; + dma_q->lines_completed = 0; + } + } + + return bytes_to_copy; +} + +void cx231xx_reset_video_buffer(struct cx231xx *dev, + struct cx231xx_dmaqueue *dma_q) +{ + struct cx231xx_buffer *buf; + + /* handle the switch from field 1 to field 2 */ + if (dma_q->current_field == 1) { + if (dma_q->lines_completed >= dma_q->lines_per_field) + dma_q->field1_done = 1; + else + dma_q->field1_done = 0; + } + + if (dev->USE_ISO) + buf = dev->video_mode.isoc_ctl.buf; + else + buf = dev->video_mode.bulk_ctl.buf; + + if (buf == NULL) { + u8 *outp = NULL; + /* first try to get the buffer */ + get_next_buf(dma_q, &buf); + + if (buf) + outp = videobuf_to_vmalloc(&buf->vb); + + dma_q->pos = 0; + dma_q->field1_done = 0; + dma_q->current_field = -1; + } + + /* reset the counters */ + dma_q->bytes_left_in_line = dev->width << 1; + dma_q->lines_completed = 0; +} + +int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, + u8 *p_buffer, u32 bytes_to_copy) +{ + u8 *p_out_buffer = NULL; + u32 current_line_bytes_copied = 0; + struct cx231xx_buffer *buf; + u32 _line_size = dev->width << 1; + void *startwrite; + int offset, lencopy; + + if (dev->USE_ISO) + buf = dev->video_mode.isoc_ctl.buf; + else + buf = dev->video_mode.bulk_ctl.buf; + + if (buf == NULL) + return -1; + + p_out_buffer = videobuf_to_vmalloc(&buf->vb); + + current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line; + + /* Offset field 2 one line from the top of the buffer */ + offset = (dma_q->current_field == 1) ? 0 : _line_size; + + /* Offset for field 2 */ + startwrite = p_out_buffer + offset; + + /* lines already completed in the current field */ + startwrite += (dma_q->lines_completed * _line_size * 2); + + /* bytes already completed in the current line */ + startwrite += current_line_bytes_copied; + + lencopy = dma_q->bytes_left_in_line > bytes_to_copy ? + bytes_to_copy : dma_q->bytes_left_in_line; + + if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + buf->vb.size)) + return 0; + + /* The below copies the UYVY data straight into video buffer */ + cx231xx_swab((u16 *) p_buffer, (u16 *) startwrite, (u16) lencopy); + + return 0; +} + +void cx231xx_swab(u16 *from, u16 *to, u16 len) +{ + u16 i; + + if (len <= 0) + return; + + for (i = 0; i < len / 2; i++) + to[i] = (from[i] << 8) | (from[i] >> 8); +} + +u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q) +{ + u8 buffer_complete = 0; + + /* Dual field stream */ + buffer_complete = ((dma_q->current_field == 2) && + (dma_q->lines_completed >= dma_q->lines_per_field) && + dma_q->field1_done); + + return buffer_complete; +} + +/* ------------------------------------------------------------------ + Videobuf operations + ------------------------------------------------------------------*/ + +static int +buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) +{ + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx *dev = fh->dev; + + *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3; + if (0 == *count) + *count = CX231XX_DEF_BUF; + + if (*count < CX231XX_MIN_BUF) + *count = CX231XX_MIN_BUF; + + return 0; +} + +/* This is called *without* dev->slock held; please keep it that way */ +static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) +{ + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx *dev = fh->dev; + unsigned long flags = 0; + + if (in_interrupt()) + BUG(); + + /* We used to wait for the buffer to finish here, but this didn't work + because, as we were keeping the state as VIDEOBUF_QUEUED, + videobuf_queue_cancel marked it as finished for us. + (Also, it could wedge forever if the hardware was misconfigured.) + + This should be safe; by the time we get here, the buffer isn't + queued anymore. If we ever start marking the buffers as + VIDEOBUF_ACTIVE, it won't be, though. + */ + spin_lock_irqsave(&dev->video_mode.slock, flags); + if (dev->USE_ISO) { + if (dev->video_mode.isoc_ctl.buf == buf) + dev->video_mode.isoc_ctl.buf = NULL; + } else { + if (dev->video_mode.bulk_ctl.buf == buf) + dev->video_mode.bulk_ctl.buf = NULL; + } + spin_unlock_irqrestore(&dev->video_mode.slock, flags); + + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int +buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb); + struct cx231xx *dev = fh->dev; + int rc = 0, urb_init = 0; + + /* The only currently supported format is 16 bits/pixel */ + buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + + 7) >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + buf->vb.width = dev->width; + buf->vb.height = dev->height; + buf->vb.field = field; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc < 0) + goto fail; + } + + if (dev->USE_ISO) { + if (!dev->video_mode.isoc_ctl.num_bufs) + urb_init = 1; + } else { + if (!dev->video_mode.bulk_ctl.num_bufs) + urb_init = 1; + } + /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n", + urb_init, dev->video_mode.max_pkt_size);*/ + if (urb_init) { + dev->mode_tv = 0; + if (dev->USE_ISO) + rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, + CX231XX_NUM_BUFS, + dev->video_mode.max_pkt_size, + cx231xx_isoc_copy); + else + rc = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS, + CX231XX_NUM_BUFS, + dev->video_mode.max_pkt_size, + cx231xx_bulk_copy); + if (rc < 0) + goto fail; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(vq, buf); + return rc; +} + +static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb); + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx *dev = fh->dev; + struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vidq->active); + +} + +static void buffer_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb); + struct cx231xx_fh *fh = vq->priv_data; + struct cx231xx *dev = (struct cx231xx *)fh->dev; + + cx231xx_isocdbg("cx231xx: called buffer_release\n"); + + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops cx231xx_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/********************* v4l2 interface **************************************/ + +void video_mux(struct cx231xx *dev, int index) +{ + dev->video_input = index; + dev->ctl_ainput = INPUT(index)->amux; + + cx231xx_set_video_input_mux(dev, index); + + cx25840_call(dev, video, s_routing, INPUT(index)->vmux, 0, 0); + + cx231xx_set_audio_input(dev, dev->ctl_ainput); + + cx231xx_info("video_mux : %d\n", index); + + /* do mode control overrides if required */ + cx231xx_do_mode_ctrl_overrides(dev); +} + +/* Usage lock check functions */ +static int res_get(struct cx231xx_fh *fh) +{ + struct cx231xx *dev = fh->dev; + int rc = 0; + + /* This instance already has stream_on */ + if (fh->stream_on) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (dev->stream_on) + return -EBUSY; + dev->stream_on = 1; + } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (dev->vbi_stream_on) + return -EBUSY; + dev->vbi_stream_on = 1; + } else + return -EINVAL; + + fh->stream_on = 1; + + return rc; +} + +static int res_check(struct cx231xx_fh *fh) +{ + return fh->stream_on; +} + +static void res_free(struct cx231xx_fh *fh) +{ + struct cx231xx *dev = fh->dev; + + fh->stream_on = 0; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + dev->stream_on = 0; + if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + dev->vbi_stream_on = 0; +} + +static int check_dev(struct cx231xx *dev) +{ + if (dev->state & DEV_DISCONNECTED) { + cx231xx_errdev("v4l2 ioctl: device not present\n"); + return -ENODEV; + } + + if (dev->state & DEV_MISCONFIGURED) { + cx231xx_errdev("v4l2 ioctl: device is misconfigured; " + "close and open it again\n"); + return -EIO; + } + return 0; +} + +/* ------------------------------------------------------------------ + IOCTL vidioc handling + ------------------------------------------------------------------*/ + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.pixelformat = dev->format->fourcc; + f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + + return 0; +} + +static struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(format); i++) + if (format[i].fourcc == fourcc) + return &format[i]; + + return NULL; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + unsigned int width = f->fmt.pix.width; + unsigned int height = f->fmt.pix.height; + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + struct cx231xx_fmt *fmt; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmt) { + cx231xx_videodbg("Fourcc format (%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + /* width must even because of the YUYV format + height must be even because of interlacing */ + v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0); + + f->fmt.pix.width = width; + f->fmt.pix.height = height; + f->fmt.pix.pixelformat = fmt->fourcc; + f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + struct cx231xx_fmt *fmt; + struct v4l2_mbus_framefmt mbus_fmt; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + vidioc_try_fmt_vid_cap(file, priv, f); + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmt) + return -EINVAL; + + if (videobuf_queue_is_busy(&fh->vb_vidq)) { + cx231xx_errdev("%s queue busy\n", __func__); + return -EBUSY; + } + + if (dev->stream_on && !fh->stream_on) { + cx231xx_errdev("%s device in use by another fh\n", __func__); + return -EBUSY; + } + + /* set new image size */ + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + dev->format = fmt; + + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); + call_all(dev, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + + return rc; +} + +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + + *id = dev->norm; + return 0; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_format f; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm); + + dev->norm = *norm; + + /* Adjusts width/height, if needed */ + f.fmt.pix.width = dev->width; + f.fmt.pix.height = dev->height; + vidioc_try_fmt_vid_cap(file, priv, &f); + + call_all(dev, core, s_std, dev->norm); + + /* We need to reset basic properties in the decoder related to + resolution (since a standard change effects things like the number + of lines in VACT, etc) */ + v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED); + call_all(dev, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt); + + /* set new image size */ + dev->width = f.fmt.pix.width; + dev->height = f.fmt.pix.height; + + /* do mode control overrides */ + cx231xx_do_mode_ctrl_overrides(dev); + + return 0; +} + +static const char *iname[] = { + [CX231XX_VMUX_COMPOSITE1] = "Composite1", + [CX231XX_VMUX_SVIDEO] = "S-Video", + [CX231XX_VMUX_TELEVISION] = "Television", + [CX231XX_VMUX_CABLE] = "Cable TV", + [CX231XX_VMUX_DVB] = "DVB", + [CX231XX_VMUX_DEBUG] = "for debug only", +}; + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + unsigned int n; + + n = i->index; + if (n >= MAX_CX231XX_INPUT) + return -EINVAL; + if (0 == INPUT(n)->type) + return -EINVAL; + + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + + strcpy(i->name, iname[INPUT(n)->type]); + + if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) || + (CX231XX_VMUX_CABLE == INPUT(n)->type)) + i->type = V4L2_INPUT_TYPE_TUNER; + + i->std = dev->vdev->tvnorms; + + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + + *i = dev->video_input; + + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + dev->mode_tv = 0; + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (i >= MAX_CX231XX_INPUT) + return -EINVAL; + if (0 == INPUT(i)->type) + return -EINVAL; + + video_mux(dev, i); + + if (INPUT(i)->type == CX231XX_VMUX_TELEVISION || + INPUT(i)->type == CX231XX_VMUX_CABLE) { + /* There's a tuner, so reset the standard and put it on the + last known frequency (since it was probably powered down + until now */ + call_all(dev, core, s_std, dev->norm); + } + + return 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + + switch (a->index) { + case CX231XX_AMUX_VIDEO: + strcpy(a->name, "Television"); + break; + case CX231XX_AMUX_LINE_IN: + strcpy(a->name, "Line In"); + break; + default: + return -EINVAL; + } + + a->index = dev->ctl_ainput; + a->capability = V4L2_AUDCAP_STEREO; + + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int status = 0; + + /* Doesn't allow manual routing */ + if (a->index != dev->ctl_ainput) + return -EINVAL; + + dev->ctl_ainput = INPUT(a->index)->amux; + status = cx231xx_set_audio_input(dev, dev->ctl_ainput); + + return status; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int id = qc->id; + int i; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + qc->id = v4l2_ctrl_next(ctrl_classes, qc->id); + if (unlikely(qc->id == 0)) + return -EINVAL; + + memset(qc, 0, sizeof(*qc)); + + qc->id = id; + + if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1) + return -EINVAL; + + for (i = 0; i < CX231XX_CTLS; i++) + if (cx231xx_ctls[i].v.id == qc->id) + break; + + if (i == CX231XX_CTLS) { + *qc = no_ctl; + return 0; + } + *qc = cx231xx_ctls[i].v; + + call_all(dev, core, queryctrl, qc); + + if (qc->type) + return 0; + else + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + call_all(dev, core, g_ctrl, ctrl); + return rc; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + call_all(dev, core, s_ctrl, ctrl); + return rc; +} + +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Tuner"); + + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; + t->signal = 0xffff; /* LOCKED */ + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) + return -EINVAL; +#if 0 + call_all(dev, tuner, s_tuner, t); +#endif + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; + + call_all(dev, tuner, g_frequency, f); + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + u32 if_frequency = 5400000; + + cx231xx_info("Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n", + f->frequency, f->type); + /*cx231xx_info("f->type: 1-radio 2-analogTV 3-digitalTV\n");*/ + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != f->tuner) + return -EINVAL; + + if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) + return -EINVAL; + + /* set pre channel change settings in DIF first */ + rc = cx231xx_tuner_pre_channel_change(dev); + + dev->ctl_freq = f->frequency; + call_all(dev, tuner, s_frequency, f); + + /* set post channel change settings in DIF first */ + rc = cx231xx_tuner_post_channel_change(dev); + + if (dev->tuner_type == TUNER_NXP_TDA18271) { + if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443)) + if_frequency = 5400000; /*5.4MHz */ + else if (dev->norm & V4L2_STD_B) + if_frequency = 6000000; /*6.0MHz */ + else if (dev->norm & (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK)) + if_frequency = 6900000; /*6.9MHz */ + else if (dev->norm & V4L2_STD_GH) + if_frequency = 7100000; /*7.1MHz */ + else if (dev->norm & V4L2_STD_PAL_I) + if_frequency = 7250000; /*7.25MHz */ + else if (dev->norm & V4L2_STD_SECAM_L) + if_frequency = 6900000; /*6.9MHz */ + else if (dev->norm & V4L2_STD_SECAM_LC) + if_frequency = 1250000; /*1.25MHz */ + + cx231xx_info("if_frequency is set to %d\n", if_frequency); + cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1); + + update_HH_register_after_set_DIF(dev); + } + + cx231xx_info("Set New FREQUENCY to %d\n", f->frequency); + + return rc; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG + +/* + -R, --list-registers=type=, + chip=[,min=,max=] + dump registers from to [VIDIOC_DBG_G_REGISTER] + -r, --set-register=type=, + chip=,reg=,val= + set the register [VIDIOC_DBG_S_REGISTER] + + if type == host, then is the hosts chip ID (default 0) + if type == i2cdrv (default), then is the I2C driver name or ID + if type == i2caddr, then is the 7-bit I2C address +*/ + +static int vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int ret = 0; + u8 value[4] = { 0, 0, 0, 0 }; + u32 data = 0; + + switch (reg->match.type) { + case V4L2_CHIP_MATCH_HOST: + switch (reg->match.addr) { + case 0: /* Cx231xx - internal registers */ + ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, + (u16)reg->reg, value, 4); + reg->val = value[0] | value[1] << 8 | + value[2] << 16 | value[3] << 24; + break; + case 1: /* AFE - read byte */ + ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS, + (u16)reg->reg, 2, &data, 1); + reg->val = le32_to_cpu(data & 0xff); + break; + case 14: /* AFE - read dword */ + ret = cx231xx_read_i2c_data(dev, AFE_DEVICE_ADDRESS, + (u16)reg->reg, 2, &data, 4); + reg->val = le32_to_cpu(data); + break; + case 2: /* Video Block - read byte */ + ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, + (u16)reg->reg, 2, &data, 1); + reg->val = le32_to_cpu(data & 0xff); + break; + case 24: /* Video Block - read dword */ + ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS, + (u16)reg->reg, 2, &data, 4); + reg->val = le32_to_cpu(data); + break; + case 3: /* I2S block - read byte */ + ret = cx231xx_read_i2c_data(dev, + I2S_BLK_DEVICE_ADDRESS, + (u16)reg->reg, 1, + &data, 1); + reg->val = le32_to_cpu(data & 0xff); + break; + case 34: /* I2S Block - read dword */ + ret = + cx231xx_read_i2c_data(dev, I2S_BLK_DEVICE_ADDRESS, + (u16)reg->reg, 1, &data, 4); + reg->val = le32_to_cpu(data); + break; + } + return ret < 0 ? ret : 0; + + case V4L2_CHIP_MATCH_I2C_DRIVER: + call_all(dev, core, g_register, reg); + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR:/*for register debug*/ + switch (reg->match.addr) { + case 0: /* Cx231xx - internal registers */ + ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, + (u16)reg->reg, value, 4); + reg->val = value[0] | value[1] << 8 | + value[2] << 16 | value[3] << 24; + + break; + case 0x600:/* AFE - read byte */ + ret = cx231xx_read_i2c_master(dev, AFE_DEVICE_ADDRESS, + (u16)reg->reg, 2, + &data, 1 , 0); + reg->val = le32_to_cpu(data & 0xff); + break; + + case 0x880:/* Video Block - read byte */ + if (reg->reg < 0x0b) { + ret = cx231xx_read_i2c_master(dev, + VID_BLK_I2C_ADDRESS, + (u16)reg->reg, 2, + &data, 1 , 0); + reg->val = le32_to_cpu(data & 0xff); + } else { + ret = cx231xx_read_i2c_master(dev, + VID_BLK_I2C_ADDRESS, + (u16)reg->reg, 2, + &data, 4 , 0); + reg->val = le32_to_cpu(data); + } + break; + case 0x980: + ret = cx231xx_read_i2c_master(dev, + I2S_BLK_DEVICE_ADDRESS, + (u16)reg->reg, 1, + &data, 1 , 0); + reg->val = le32_to_cpu(data & 0xff); + break; + case 0x400: + ret = + cx231xx_read_i2c_master(dev, 0x40, + (u16)reg->reg, 1, + &data, 1 , 0); + reg->val = le32_to_cpu(data & 0xff); + break; + case 0xc01: + ret = + cx231xx_read_i2c_master(dev, 0xc0, + (u16)reg->reg, 2, + &data, 38, 1); + reg->val = le32_to_cpu(data); + break; + case 0x022: + ret = + cx231xx_read_i2c_master(dev, 0x02, + (u16)reg->reg, 1, + &data, 1, 2); + reg->val = le32_to_cpu(data & 0xff); + break; + case 0x322: + ret = cx231xx_read_i2c_master(dev, + 0x32, + (u16)reg->reg, 1, + &data, 4 , 2); + reg->val = le32_to_cpu(data); + break; + case 0x342: + ret = cx231xx_read_i2c_master(dev, + 0x34, + (u16)reg->reg, 1, + &data, 4 , 2); + reg->val = le32_to_cpu(data); + break; + + default: + cx231xx_info("no match device address!!\n"); + break; + } + return ret < 0 ? ret : 0; + /*return -EINVAL;*/ + default: + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + } + + call_all(dev, core, g_register, reg); + + return ret; +} + +static int vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int ret = 0; + __le64 buf; + u32 value; + u8 data[4] = { 0, 0, 0, 0 }; + + buf = cpu_to_le64(reg->val); + + switch (reg->match.type) { + case V4L2_CHIP_MATCH_HOST: + { + value = (u32) buf & 0xffffffff; + + switch (reg->match.addr) { + case 0: /* cx231xx internal registers */ + data[0] = (u8) value; + data[1] = (u8) (value >> 8); + data[2] = (u8) (value >> 16); + data[3] = (u8) (value >> 24); + ret = cx231xx_write_ctrl_reg(dev, + VRT_SET_REGISTER, + (u16)reg->reg, data, + 4); + break; + case 1: /* AFE - read byte */ + ret = cx231xx_write_i2c_data(dev, + AFE_DEVICE_ADDRESS, + (u16)reg->reg, 2, + value, 1); + break; + case 14: /* AFE - read dword */ + ret = cx231xx_write_i2c_data(dev, + AFE_DEVICE_ADDRESS, + (u16)reg->reg, 2, + value, 4); + break; + case 2: /* Video Block - read byte */ + ret = + cx231xx_write_i2c_data(dev, + VID_BLK_I2C_ADDRESS, + (u16)reg->reg, 2, + value, 1); + break; + case 24: /* Video Block - read dword */ + ret = + cx231xx_write_i2c_data(dev, + VID_BLK_I2C_ADDRESS, + (u16)reg->reg, 2, + value, 4); + break; + case 3: /* I2S block - read byte */ + ret = + cx231xx_write_i2c_data(dev, + I2S_BLK_DEVICE_ADDRESS, + (u16)reg->reg, 1, + value, 1); + break; + case 34: /* I2S block - read dword */ + ret = + cx231xx_write_i2c_data(dev, + I2S_BLK_DEVICE_ADDRESS, + (u16)reg->reg, 1, + value, 4); + break; + } + } + return ret < 0 ? ret : 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + { + value = (u32) buf & 0xffffffff; + + switch (reg->match.addr) { + case 0:/*cx231xx internal registers*/ + data[0] = (u8) value; + data[1] = (u8) (value >> 8); + data[2] = (u8) (value >> 16); + data[3] = (u8) (value >> 24); + ret = cx231xx_write_ctrl_reg(dev, + VRT_SET_REGISTER, + (u16)reg->reg, data, + 4); + break; + case 0x600:/* AFE - read byte */ + ret = cx231xx_write_i2c_master(dev, + AFE_DEVICE_ADDRESS, + (u16)reg->reg, 2, + value, 1 , 0); + break; + + case 0x880:/* Video Block - read byte */ + if (reg->reg < 0x0b) + cx231xx_write_i2c_master(dev, + VID_BLK_I2C_ADDRESS, + (u16)reg->reg, 2, + value, 1, 0); + else + cx231xx_write_i2c_master(dev, + VID_BLK_I2C_ADDRESS, + (u16)reg->reg, 2, + value, 4, 0); + break; + case 0x980: + ret = + cx231xx_write_i2c_master(dev, + I2S_BLK_DEVICE_ADDRESS, + (u16)reg->reg, 1, + value, 1, 0); + break; + case 0x400: + ret = + cx231xx_write_i2c_master(dev, + 0x40, + (u16)reg->reg, 1, + value, 1, 0); + break; + case 0xc01: + ret = + cx231xx_write_i2c_master(dev, + 0xc0, + (u16)reg->reg, 1, + value, 1, 1); + break; + + case 0x022: + ret = + cx231xx_write_i2c_master(dev, + 0x02, + (u16)reg->reg, 1, + value, 1, 2); + case 0x322: + ret = + cx231xx_write_i2c_master(dev, + 0x32, + (u16)reg->reg, 1, + value, 4, 2); + break; + + case 0x342: + ret = + cx231xx_write_i2c_master(dev, + 0x34, + (u16)reg->reg, 1, + value, 4, 2); + break; + default: + cx231xx_info("no match device address, " + "the value is %x\n", reg->match.addr); + break; + + } + + } + default: + break; + } + + call_all(dev, core, s_register, reg); + + return ret; +} +#endif + +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cc) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + cc->bounds.left = 0; + cc->bounds.top = 0; + cc->bounds.width = dev->width; + cc->bounds.height = dev->height; + cc->defrect = cc->bounds; + cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ + cc->pixelaspect.denominator = 59; + + return 0; +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + rc = res_get(fh); + + if (likely(rc >= 0)) + rc = videobuf_streamon(&fh->vb_vidq); + + call_all(dev, video, s_stream, 1); + + return rc; +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) + return -EINVAL; + if (type != fh->type) + return -EINVAL; + + cx25840_call(dev, video, s_stream, 0); + + videobuf_streamoff(&fh->vb_vidq); + res_free(fh); + + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + + strlcpy(cap->driver, "cx231xx", sizeof(cap->driver)); + strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + + cap->version = CX231XX_VERSION_CODE; + + cap->capabilities = V4L2_CAP_VBI_CAPTURE | +#if 0 + V4L2_CAP_SLICED_VBI_CAPTURE | +#endif + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + + if (dev->tuner_type != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; + + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(format))) + return -EINVAL; + + strlcpy(f->description, format[f->index].name, sizeof(f->description)); + f->pixelformat = format[f->index].fourcc; + + return 0; +} + +/* Sliced VBI ioctls */ +static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + f->fmt.sliced.service_set = 0; + + call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced); + + if (f->fmt.sliced.service_set == 0) + rc = -EINVAL; + + return rc; +} + +static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced); + + if (f->fmt.sliced.service_set == 0) + return -EINVAL; + + return 0; +} + +/* RAW VBI ioctls */ + +static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + f->fmt.vbi.sampling_rate = 6750000 * 4; + f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 0; + f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ? + PAL_VBI_START_LINE : NTSC_VBI_START_LINE; + f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ? + PAL_VBI_LINES : NTSC_VBI_LINES; + f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ? + PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263; + f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; + + return 0; + +} + +static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + + if (dev->vbi_stream_on && !fh->stream_on) { + cx231xx_errdev("%s device in use by another fh\n", __func__); + return -EBUSY; + } + + f->type = V4L2_BUF_TYPE_VBI_CAPTURE; + f->fmt.vbi.sampling_rate = 6750000 * 4; + f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 0; + f->fmt.vbi.flags = 0; + f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ? + PAL_VBI_START_LINE : NTSC_VBI_START_LINE; + f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ? + PAL_VBI_LINES : NTSC_VBI_LINES; + f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ? + PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263; + f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; + + return 0; + +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + return videobuf_reqbufs(&fh->vb_vidq, rb); +} + +static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + return videobuf_querybuf(&fh->vb_vidq, b); +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + return videobuf_qbuf(&fh->vb_vidq, b); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); +} + +/* ----------------------------------------------------------- */ +/* RADIO ESPECIFIC IOCTLS */ +/* ----------------------------------------------------------- */ + +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; + + strlcpy(cap->driver, "cx231xx", sizeof(cap->driver)); + strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + + cap->version = CX231XX_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; +} + +static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; + + if (unlikely(t->index > 0)) + return -EINVAL; + + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + call_all(dev, tuner, s_tuner, t); + + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + strcpy(a->name, "Radio"); + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; + + if (0 != t->index) + return -EINVAL; + + call_all(dev, tuner, s_tuner, t); + + return 0; +} + +static int radio_s_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input(struct file *file, void *fh, unsigned int i) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + int i; + + if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE) { + for (i = 0; i < CX231XX_CTLS; i++) { + if (cx231xx_ctls[i].v.id == c->id) + break; + } + if (i == CX231XX_CTLS) + return -EINVAL; + *c = cx231xx_ctls[i].v; + } else + *c = no_ctl; + return 0; +} + +/* + * cx231xx_v4l2_open() + * inits the device and starts isoc transfer + */ +static int cx231xx_v4l2_open(struct file *filp) +{ + int errCode = 0, radio = 0; + struct video_device *vdev = video_devdata(filp); + struct cx231xx *dev = video_drvdata(filp); + struct cx231xx_fh *fh; + enum v4l2_buf_type fh_type = 0; + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; + } + + cx231xx_videodbg("open dev=%s type=%s users=%d\n", + video_device_node_name(vdev), v4l2_type_names[fh_type], + dev->users); + +#if 0 + errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); + if (errCode < 0) { + cx231xx_errdev + ("Device locked on digital mode. Can't open analog\n"); + return -EBUSY; + } +#endif + + fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL); + if (!fh) { + cx231xx_errdev("cx231xx-video.c: Out of memory?!\n"); + return -ENOMEM; + } + fh->dev = dev; + fh->radio = radio; + fh->type = fh_type; + filp->private_data = fh; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { + dev->width = norm_maxw(dev); + dev->height = norm_maxh(dev); + + /* Power up in Analog TV mode */ + if (dev->board.external_av) + cx231xx_set_power_mode(dev, + POLARIS_AVMODE_ENXTERNAL_AV); + else + cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV); + +#if 0 + cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); +#endif + + /* set video alternate setting */ + cx231xx_set_video_alternate(dev); + + /* Needed, since GPIO might have disabled power of + some i2c device */ + cx231xx_config_i2c(dev); + + /* device needs to be initialized before isoc transfer */ + dev->video_input = dev->video_input > 2 ? 2 : dev->video_input; + + } + if (fh->radio) { + cx231xx_videodbg("video_open: setting radio device\n"); + + /* cx231xx_start_radio(dev); */ + + call_all(dev, tuner, s_radio); + } + + dev->users++; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops, + NULL, &dev->video_mode.slock, + fh->type, V4L2_FIELD_INTERLACED, + sizeof(struct cx231xx_buffer), + fh, &dev->lock); + if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + /* Set the required alternate setting VBI interface works in + Bulk mode only */ + cx231xx_set_alt_setting(dev, INDEX_VANC, 0); + + videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops, + NULL, &dev->vbi_mode.slock, + fh->type, V4L2_FIELD_SEQ_TB, + sizeof(struct cx231xx_buffer), + fh, &dev->lock); + } + + return errCode; +} + +/* + * cx231xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +void cx231xx_release_analog_resources(struct cx231xx *dev) +{ + + /*FIXME: I2C IR should be disconnected */ + + if (dev->radio_dev) { + if (video_is_registered(dev->radio_dev)) + video_unregister_device(dev->radio_dev); + else + video_device_release(dev->radio_dev); + dev->radio_dev = NULL; + } + if (dev->vbi_dev) { + cx231xx_info("V4L2 device %s deregistered\n", + video_device_node_name(dev->vbi_dev)); + if (video_is_registered(dev->vbi_dev)) + video_unregister_device(dev->vbi_dev); + else + video_device_release(dev->vbi_dev); + dev->vbi_dev = NULL; + } + if (dev->vdev) { + cx231xx_info("V4L2 device %s deregistered\n", + video_device_node_name(dev->vdev)); + + if (dev->board.has_417) + cx231xx_417_unregister(dev); + + if (video_is_registered(dev->vdev)) + video_unregister_device(dev->vdev); + else + video_device_release(dev->vdev); + dev->vdev = NULL; + } +} + +/* + * cx231xx_v4l2_close() + * stops streaming and deallocates all resources allocated by the v4l2 + * calls and ioctls + */ +static int cx231xx_v4l2_close(struct file *filp) +{ + struct cx231xx_fh *fh = filp->private_data; + struct cx231xx *dev = fh->dev; + + cx231xx_videodbg("users=%d\n", dev->users); + + cx231xx_videodbg("users=%d\n", dev->users); + if (res_check(fh)) + res_free(fh); + + /* + * To workaround error number=-71 on EP0 for VideoGrabber, + * need exclude following. + * FIXME: It is probably safe to remove most of these, as we're + * now avoiding the alternate setting for INDEX_VANC + */ + if (!dev->board.no_alt_vanc) + if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + videobuf_stop(&fh->vb_vidq); + videobuf_mmap_free(&fh->vb_vidq); + + /* the device is already disconnect, + free the remaining resources */ + if (dev->state & DEV_DISCONNECTED) { + if (atomic_read(&dev->devlist_count) > 0) { + cx231xx_release_resources(dev); + kfree(dev); + dev = NULL; + return 0; + } + return 0; + } + + /* do this before setting alternate! */ + cx231xx_uninit_vbi_isoc(dev); + + /* set alternate 0 */ + if (!dev->vbi_or_sliced_cc_mode) + cx231xx_set_alt_setting(dev, INDEX_VANC, 0); + else + cx231xx_set_alt_setting(dev, INDEX_HANC, 0); + + kfree(fh); + dev->users--; + wake_up_interruptible_nr(&dev->open, 1); + return 0; + } + + if (dev->users == 1) { + videobuf_stop(&fh->vb_vidq); + videobuf_mmap_free(&fh->vb_vidq); + + /* the device is already disconnect, + free the remaining resources */ + if (dev->state & DEV_DISCONNECTED) { + cx231xx_release_resources(dev); + kfree(dev); + dev = NULL; + return 0; + } + + /* Save some power by putting tuner to sleep */ + call_all(dev, core, s_power, 0); + + /* do this before setting alternate! */ + if (dev->USE_ISO) + cx231xx_uninit_isoc(dev); + else + cx231xx_uninit_bulk(dev); + cx231xx_set_mode(dev, CX231XX_SUSPEND); + + /* set alternate 0 */ + cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0); + } + kfree(fh); + dev->users--; + wake_up_interruptible_nr(&dev->open, 1); + return 0; +} + +/* + * cx231xx_v4l2_read() + * will allocate buffers when called for the first time + */ +static ssize_t +cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos) +{ + struct cx231xx_fh *fh = filp->private_data; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) { + rc = res_get(fh); + + if (unlikely(rc < 0)) + return rc; + + return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, + filp->f_flags & O_NONBLOCK); + } + return 0; +} + +/* + * cx231xx_v4l2_poll() + * will allocate buffers when called for the first time + */ +static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait) +{ + struct cx231xx_fh *fh = filp->private_data; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + rc = res_get(fh); + + if (unlikely(rc < 0)) + return POLLERR; + + if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) || + (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) + return videobuf_poll_stream(filp, &fh->vb_vidq, wait); + else + return POLLERR; +} + +/* + * cx231xx_v4l2_mmap() + */ +static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct cx231xx_fh *fh = filp->private_data; + struct cx231xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + rc = res_get(fh); + + if (unlikely(rc < 0)) + return rc; + + rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); + + cx231xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", + (unsigned long)vma->vm_start, + (unsigned long)vma->vm_end - + (unsigned long)vma->vm_start, rc); + + return rc; +} + +static const struct v4l2_file_operations cx231xx_v4l_fops = { + .owner = THIS_MODULE, + .open = cx231xx_v4l2_open, + .release = cx231xx_v4l2_close, + .read = cx231xx_v4l2_read, + .poll = cx231xx_v4l2_poll, + .mmap = cx231xx_v4l2_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + .vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = vidioc_try_fmt_vbi_cap, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_cropcap = vidioc_cropcap, + .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +static struct video_device cx231xx_vbi_template; + +static const struct video_device cx231xx_video_template = { + .fops = &cx231xx_v4l_fops, + .release = video_device_release, + .ioctl_ops = &video_ioctl_ops, + .tvnorms = V4L2_STD_ALL, + .current_norm = V4L2_STD_PAL, +}; + +static const struct v4l2_file_operations radio_fops = { + .owner = THIS_MODULE, + .open = cx231xx_v4l2_open, + .release = cx231xx_v4l2_close, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +static struct video_device cx231xx_radio_template = { + .name = "cx231xx-radio", + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, +}; + +/******************************** usb interface ******************************/ + +static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, + const struct video_device + *template, const char *type_name) +{ + struct video_device *vfd; + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + + *vfd = *template; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->release = video_device_release; + vfd->debug = video_debug; + vfd->lock = &dev->lock; + + snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); + + video_set_drvdata(vfd, dev); + return vfd; +} + +int cx231xx_register_analog_devices(struct cx231xx *dev) +{ + int ret; + + cx231xx_info("%s: v4l2 driver version %d.%d.%d\n", + dev->name, + (CX231XX_VERSION_CODE >> 16) & 0xff, + (CX231XX_VERSION_CODE >> 8) & 0xff, + CX231XX_VERSION_CODE & 0xff); + + /* set default norm */ + /*dev->norm = cx231xx_video_template.current_norm; */ + dev->width = norm_maxw(dev); + dev->height = norm_maxh(dev); + dev->interlaced = 0; + + /* Analog specific initialization */ + dev->format = &format[0]; + + /* Set the initial input */ + video_mux(dev, dev->video_input); + + /* Audio defaults */ + dev->mute = 1; + dev->volume = 0x1f; + + /* enable vbi capturing */ + /* write code here... */ + + /* allocate and fill video video_device struct */ + dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video"); + if (!dev->vdev) { + cx231xx_errdev("cannot allocate video_device.\n"); + return -ENODEV; + } + + /* register v4l2 video video_device */ + ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + video_nr[dev->devno]); + if (ret) { + cx231xx_errdev("unable to register video device (error=%i).\n", + ret); + return ret; + } + + cx231xx_info("%s/0: registered device %s [v4l2]\n", + dev->name, video_device_node_name(dev->vdev)); + + /* Initialize VBI template */ + memcpy(&cx231xx_vbi_template, &cx231xx_video_template, + sizeof(cx231xx_vbi_template)); + strcpy(cx231xx_vbi_template.name, "cx231xx-vbi"); + + /* Allocate and fill vbi video_device struct */ + dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi"); + + /* register v4l2 vbi video_device */ + ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->devno]); + if (ret < 0) { + cx231xx_errdev("unable to register vbi device\n"); + return ret; + } + + cx231xx_info("%s/0: registered device %s\n", + dev->name, video_device_node_name(dev->vbi_dev)); + + if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) { + dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template, + "radio"); + if (!dev->radio_dev) { + cx231xx_errdev("cannot allocate video_device.\n"); + return -ENODEV; + } + ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr[dev->devno]); + if (ret < 0) { + cx231xx_errdev("can't register radio device\n"); + return ret; + } + cx231xx_info("Registered radio device as %s\n", + video_device_node_name(dev->radio_dev)); + } + + cx231xx_info("V4L2 device registered as %s and %s\n", + video_device_node_name(dev->vdev), + video_device_node_name(dev->vbi_dev)); + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,51 @@ +config VIDEO_CX231XX + tristate "Conexant cx231xx USB video capture support" + depends on VIDEO_DEV && I2C + select VIDEO_TUNER + select VIDEO_TVEEPROM + depends on RC_CORE + select VIDEOBUF_VMALLOC + select VIDEO_CX25840 + select VIDEO_CX2341X + + ---help--- + This is a video4linux driver for Conexant 231xx USB based TV cards. + + To compile this driver as a module, choose M here: the + module will be called cx231xx + +config VIDEO_CX231XX_RC + bool "Conexant cx231xx Remote Controller additional support" + depends on RC_CORE + depends on VIDEO_CX231XX + default y + ---help--- + cx231xx hardware has a builtin RX/TX support. However, a few + designs opted to not use it, but, instead, some other hardware. + This module enables the usage of those other hardware, like the + ones used with ISDB-T boards. + + On most cases, all you need for IR is mceusb module. + +config VIDEO_CX231XX_ALSA + tristate "Conexant Cx231xx ALSA audio module" + depends on VIDEO_CX231XX && SND + select SND_PCM + + ---help--- + This is an ALSA driver for Cx231xx USB based TV cards. + + To compile this driver as a module, choose M here: the + module will be called cx231xx-alsa + +config VIDEO_CX231XX_DVB + tristate "DVB/ATSC Support for Cx231xx based TV cards" + depends on VIDEO_CX231XX && DVB_CORE + select VIDEOBUF_DVB + select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_NXP18271 if !DVB_FE_CUSTOMISE + select DVB_MB86A20S if !DVB_FE_CUSTOMISE + + ---help--- + This adds support for DVB cards based on the + Conexant cx231xx chips. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx231xx/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,16 @@ +cx231xx-y += cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o +cx231xx-y += cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o +cx231xx-$(CONFIG_VIDEO_CX231XX_RC) += cx231xx-input.o + +cx231xx-alsa-objs := cx231xx-audio.o + +obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o +obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o +obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-usb + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx2341x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx2341x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx2341x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx2341x.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1726 @@ +/* + * cx2341x - generic code for cx23415/6/8 based devices + * + * Copyright (C) 2006 Hans Verkuil + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_DESCRIPTION("cx23415/6/8 driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +/********************** COMMON CODE *********************/ + +/* definitions for audio properties bits 29-28 */ +#define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0 +#define CX2341X_AUDIO_ENCODING_METHOD_AC3 1 +#define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2 + +static const char *cx2341x_get_name(u32 id) +{ + switch (id) { + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + return "Spatial Filter Mode"; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + return "Spatial Filter"; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + return "Spatial Luma Filter Type"; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + return "Spatial Chroma Filter Type"; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + return "Temporal Filter Mode"; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + return "Temporal Filter"; + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + return "Median Filter Type"; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + return "Median Luma Filter Maximum"; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + return "Median Luma Filter Minimum"; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + return "Median Chroma Filter Maximum"; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + return "Median Chroma Filter Minimum"; + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + return "Insert Navigation Packets"; + } + return NULL; +} + +static const char **cx2341x_get_menu(u32 id) +{ + static const char *cx2341x_video_spatial_filter_mode_menu[] = { + "Manual", + "Auto", + NULL + }; + + static const char *cx2341x_video_luma_spatial_filter_type_menu[] = { + "Off", + "1D Horizontal", + "1D Vertical", + "2D H/V Separable", + "2D Symmetric non-separable", + NULL + }; + + static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = { + "Off", + "1D Horizontal", + NULL + }; + + static const char *cx2341x_video_temporal_filter_mode_menu[] = { + "Manual", + "Auto", + NULL + }; + + static const char *cx2341x_video_median_filter_type_menu[] = { + "Off", + "Horizontal", + "Vertical", + "Horizontal/Vertical", + "Diagonal", + NULL + }; + + switch (id) { + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + return cx2341x_video_spatial_filter_mode_menu; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + return cx2341x_video_luma_spatial_filter_type_menu; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + return cx2341x_video_chroma_spatial_filter_type_menu; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + return cx2341x_video_temporal_filter_mode_menu; + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + return cx2341x_video_median_filter_type_menu; + } + return NULL; +} + +static void cx2341x_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, + s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags) +{ + *name = cx2341x_get_name(id); + *flags = 0; + + switch (id) { + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + *type = V4L2_CTRL_TYPE_MENU; + *min = 0; + *step = 0; + break; + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + *type = V4L2_CTRL_TYPE_BOOLEAN; + *min = 0; + *max = *step = 1; + break; + default: + *type = V4L2_CTRL_TYPE_INTEGER; + break; + } + switch (id) { + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + *flags |= V4L2_CTRL_FLAG_UPDATE; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + *flags |= V4L2_CTRL_FLAG_SLIDER; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + *flags |= V4L2_CTRL_FLAG_READ_ONLY; + break; + } +} + + +/********************** OLD CODE *********************/ + +/* Must be sorted from low to high control ID! */ +const u32 cx2341x_mpeg_ctrls[] = { + V4L2_CID_MPEG_CLASS, + V4L2_CID_MPEG_STREAM_TYPE, + V4L2_CID_MPEG_STREAM_VBI_FMT, + V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, + V4L2_CID_MPEG_AUDIO_ENCODING, + V4L2_CID_MPEG_AUDIO_L2_BITRATE, + V4L2_CID_MPEG_AUDIO_MODE, + V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, + V4L2_CID_MPEG_AUDIO_EMPHASIS, + V4L2_CID_MPEG_AUDIO_CRC, + V4L2_CID_MPEG_AUDIO_MUTE, + V4L2_CID_MPEG_AUDIO_AC3_BITRATE, + V4L2_CID_MPEG_VIDEO_ENCODING, + V4L2_CID_MPEG_VIDEO_ASPECT, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_CID_MPEG_VIDEO_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, + V4L2_CID_MPEG_VIDEO_MUTE, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, + V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, + V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, + 0 +}; +EXPORT_SYMBOL(cx2341x_mpeg_ctrls); + +static const struct cx2341x_mpeg_params default_params = { + /* misc */ + .capabilities = 0, + .port = CX2341X_PORT_MEMORY, + .width = 720, + .height = 480, + .is_50hz = 0, + + /* stream */ + .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, + .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, + .stream_insert_nav_packets = 0, + + /* audio */ + .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, + .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K, + .audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K, + .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO, + .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, + .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, + .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, + .audio_mute = 0, + + /* video */ + .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, + .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3, + .video_b_frames = 2, + .video_gop_size = 12, + .video_gop_closure = 1, + .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .video_bitrate = 6000000, + .video_bitrate_peak = 8000000, + .video_temporal_decimation = 0, + .video_mute = 0, + .video_mute_yuv = 0x008080, /* YCbCr value for black */ + + /* encoding filters */ + .video_spatial_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + .video_spatial_filter = 0, + .video_luma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_chroma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_temporal_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + .video_temporal_filter = 8, + .video_median_filter_type = + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + .video_luma_median_filter_top = 255, + .video_luma_median_filter_bottom = 0, + .video_chroma_median_filter_top = 255, + .video_chroma_median_filter_bottom = 0, +}; +/* Map the control ID to the correct field in the cx2341x_mpeg_params + struct. Return -EINVAL if the ID is unknown, else return 0. */ +static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params, + struct v4l2_ext_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + ctrl->value = params->audio_sampling_freq; + break; + case V4L2_CID_MPEG_AUDIO_ENCODING: + ctrl->value = params->audio_encoding; + break; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + ctrl->value = params->audio_l2_bitrate; + break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + ctrl->value = params->audio_ac3_bitrate; + break; + case V4L2_CID_MPEG_AUDIO_MODE: + ctrl->value = params->audio_mode; + break; + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + ctrl->value = params->audio_mode_extension; + break; + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + ctrl->value = params->audio_emphasis; + break; + case V4L2_CID_MPEG_AUDIO_CRC: + ctrl->value = params->audio_crc; + break; + case V4L2_CID_MPEG_AUDIO_MUTE: + ctrl->value = params->audio_mute; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + ctrl->value = params->video_encoding; + break; + case V4L2_CID_MPEG_VIDEO_ASPECT: + ctrl->value = params->video_aspect; + break; + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + ctrl->value = params->video_b_frames; + break; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + ctrl->value = params->video_gop_size; + break; + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + ctrl->value = params->video_gop_closure; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + ctrl->value = params->video_bitrate_mode; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctrl->value = params->video_bitrate; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + ctrl->value = params->video_bitrate_peak; + break; + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: + ctrl->value = params->video_temporal_decimation; + break; + case V4L2_CID_MPEG_VIDEO_MUTE: + ctrl->value = params->video_mute; + break; + case V4L2_CID_MPEG_VIDEO_MUTE_YUV: + ctrl->value = params->video_mute_yuv; + break; + case V4L2_CID_MPEG_STREAM_TYPE: + ctrl->value = params->stream_type; + break; + case V4L2_CID_MPEG_STREAM_VBI_FMT: + ctrl->value = params->stream_vbi_fmt; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + ctrl->value = params->video_spatial_filter_mode; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + ctrl->value = params->video_spatial_filter; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + ctrl->value = params->video_luma_spatial_filter_type; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + ctrl->value = params->video_chroma_spatial_filter_type; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + ctrl->value = params->video_temporal_filter_mode; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + ctrl->value = params->video_temporal_filter; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + ctrl->value = params->video_median_filter_type; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + ctrl->value = params->video_luma_median_filter_top; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + ctrl->value = params->video_luma_median_filter_bottom; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + ctrl->value = params->video_chroma_median_filter_top; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + ctrl->value = params->video_chroma_median_filter_bottom; + break; + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + ctrl->value = params->stream_insert_nav_packets; + break; + default: + return -EINVAL; + } + return 0; +} + +/* Map the control ID to the correct field in the cx2341x_mpeg_params + struct. Return -EINVAL if the ID is unknown, else return 0. */ +static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, + struct v4l2_ext_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + if (busy) + return -EBUSY; + params->audio_sampling_freq = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_ENCODING: + if (busy) + return -EBUSY; + if (params->capabilities & CX2341X_CAP_HAS_AC3) + if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && + ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3) + return -ERANGE; + params->audio_encoding = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + if (busy) + return -EBUSY; + params->audio_l2_bitrate = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (busy) + return -EBUSY; + if (!(params->capabilities & CX2341X_CAP_HAS_AC3)) + return -EINVAL; + params->audio_ac3_bitrate = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_MODE: + params->audio_mode = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + params->audio_mode_extension = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + params->audio_emphasis = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_CRC: + params->audio_crc = ctrl->value; + break; + case V4L2_CID_MPEG_AUDIO_MUTE: + params->audio_mute = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_ASPECT: + params->video_aspect = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_B_FRAMES: { + int b = ctrl->value + 1; + int gop = params->video_gop_size; + params->video_b_frames = ctrl->value; + params->video_gop_size = b * ((gop + b - 1) / b); + /* Max GOP size = 34 */ + while (params->video_gop_size > 34) + params->video_gop_size -= b; + break; + } + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: { + int b = params->video_b_frames + 1; + int gop = ctrl->value; + params->video_gop_size = b * ((gop + b - 1) / b); + /* Max GOP size = 34 */ + while (params->video_gop_size > 34) + params->video_gop_size -= b; + ctrl->value = params->video_gop_size; + break; + } + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + params->video_gop_closure = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + if (busy) + return -EBUSY; + /* MPEG-1 only allows CBR */ + if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 && + ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + return -EINVAL; + params->video_bitrate_mode = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + if (busy) + return -EBUSY; + params->video_bitrate = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + if (busy) + return -EBUSY; + params->video_bitrate_peak = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: + params->video_temporal_decimation = ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_MUTE: + params->video_mute = (ctrl->value != 0); + break; + case V4L2_CID_MPEG_VIDEO_MUTE_YUV: + params->video_mute_yuv = ctrl->value; + break; + case V4L2_CID_MPEG_STREAM_TYPE: + if (busy) + return -EBUSY; + params->stream_type = ctrl->value; + params->video_encoding = + (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || + params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? + V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : + V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + /* MPEG-1 implies CBR */ + params->video_bitrate_mode = + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + break; + case V4L2_CID_MPEG_STREAM_VBI_FMT: + params->stream_vbi_fmt = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + params->video_spatial_filter_mode = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + params->video_spatial_filter = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + params->video_luma_spatial_filter_type = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + params->video_chroma_spatial_filter_type = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + params->video_temporal_filter_mode = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + params->video_temporal_filter = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + params->video_median_filter_type = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + params->video_luma_median_filter_top = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + params->video_luma_median_filter_bottom = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + params->video_chroma_median_filter_top = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + params->video_chroma_median_filter_bottom = ctrl->value; + break; + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + params->stream_insert_nav_packets = ctrl->value; + break; + default: + return -EINVAL; + } + return 0; +} + +static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, + s32 min, s32 max, s32 step, s32 def) +{ + const char *name; + + switch (qctrl->id) { + /* MPEG controls */ + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + cx2341x_ctrl_fill(qctrl->id, &name, &qctrl->type, + &min, &max, &step, &def, &qctrl->flags); + qctrl->minimum = min; + qctrl->maximum = max; + qctrl->step = step; + qctrl->default_value = def; + qctrl->reserved[0] = qctrl->reserved[1] = 0; + strlcpy(qctrl->name, name, sizeof(qctrl->name)); + return 0; + + default: + return v4l2_ctrl_query_fill(qctrl, min, max, step, def); + } +} + +int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, + struct v4l2_queryctrl *qctrl) +{ + int err; + + switch (qctrl->id) { + case V4L2_CID_MPEG_CLASS: + return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); + case V4L2_CID_MPEG_STREAM_TYPE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_TYPE_MPEG2_PS, + V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1, + V4L2_MPEG_STREAM_TYPE_MPEG2_PS); + + case V4L2_CID_MPEG_STREAM_VBI_FMT: + if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI) + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_VBI_FMT_NONE, + V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1, + V4L2_MPEG_STREAM_VBI_FMT_NONE); + return cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_VBI_FMT_NONE, + V4L2_MPEG_STREAM_VBI_FMT_NONE, 1, + default_params.stream_vbi_fmt); + + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); + + case V4L2_CID_MPEG_AUDIO_ENCODING: + if (params->capabilities & CX2341X_CAP_HAS_AC3) { + /* + * The state of L2 & AC3 bitrate controls can change + * when this control changes, but v4l2_ctrl_query_fill() + * already sets V4L2_CTRL_FLAG_UPDATE for + * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here. + */ + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + V4L2_MPEG_AUDIO_ENCODING_AC3, 1, + default_params.audio_encoding); + } + + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, + default_params.audio_encoding); + + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_L2_BITRATE_192K, + V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, + default_params.audio_l2_bitrate); + if (err) + return err; + if (params->capabilities & CX2341X_CAP_HAS_AC3 && + params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_AUDIO_MODE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_MODE_STEREO, + V4L2_MPEG_AUDIO_MODE_MONO, 1, + V4L2_MPEG_AUDIO_MODE_STEREO); + + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); + if (err == 0 && + params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return err; + + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_EMPHASIS_NONE, + V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1, + V4L2_MPEG_AUDIO_EMPHASIS_NONE); + + case V4L2_CID_MPEG_AUDIO_CRC: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_CRC_NONE, + V4L2_MPEG_AUDIO_CRC_CRC16, 1, + V4L2_MPEG_AUDIO_CRC_NONE); + + case V4L2_CID_MPEG_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); + + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_AC3_BITRATE_48K, + V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1, + default_params.audio_ac3_bitrate); + if (err) + return err; + if (params->capabilities & CX2341X_CAP_HAS_AC3) { + if (params->audio_encoding != + V4L2_MPEG_AUDIO_ENCODING_AC3) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + } else + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + + case V4L2_CID_MPEG_VIDEO_ENCODING: + /* this setting is read-only for the cx2341x since the + V4L2_CID_MPEG_STREAM_TYPE really determines the + MPEG-1/2 setting */ + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_ENCODING_MPEG_1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2); + if (err == 0) + qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + return err; + + case V4L2_CID_MPEG_VIDEO_ASPECT: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_ASPECT_1x1, + V4L2_MPEG_VIDEO_ASPECT_221x100, 1, + V4L2_MPEG_VIDEO_ASPECT_4x3); + + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2); + + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, + params->is_50hz ? 12 : 15); + + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); + + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); + if (err == 0 && + params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return err; + + case V4L2_CID_MPEG_VIDEO_BITRATE: + return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000); + + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); + if (err == 0 && + params->video_bitrate_mode == + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return err; + + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: + return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); + + case V4L2_CID_MPEG_VIDEO_MUTE: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); + + case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */ + return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080); + + /* CX23415/6 specific */ + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + return cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, + default_params.video_spatial_filter_mode); + + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, + default_params.video_spatial_filter); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, + 1, + default_params.video_luma_spatial_filter_type); + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + 1, + default_params.video_chroma_spatial_filter_type); + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + return cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, + default_params.video_temporal_filter_mode); + + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: + cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, + default_params.video_temporal_filter); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_temporal_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + return cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, + default_params.video_median_filter_type); + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_luma_median_filter_top); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_luma_median_filter_bottom); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_chroma_median_filter_top); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: + cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, + default_params.video_chroma_median_filter_bottom); + qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; + + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, + default_params.stream_insert_nav_packets); + + default: + return -EINVAL; + + } +} +EXPORT_SYMBOL(cx2341x_ctrl_query); + +const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) +{ + static const char * const mpeg_stream_type_without_ts[] = { + "MPEG-2 Program Stream", + "", + "MPEG-1 System Stream", + "MPEG-2 DVD-compatible Stream", + "MPEG-1 VCD-compatible Stream", + "MPEG-2 SVCD-compatible Stream", + NULL + }; + + static const char *mpeg_stream_type_with_ts[] = { + "MPEG-2 Program Stream", + "MPEG-2 Transport Stream", + "MPEG-1 System Stream", + "MPEG-2 DVD-compatible Stream", + "MPEG-1 VCD-compatible Stream", + "MPEG-2 SVCD-compatible Stream", + NULL + }; + + static const char *mpeg_audio_encoding_l2_ac3[] = { + "", + "MPEG-1/2 Layer II", + "", + "", + "AC-3", + NULL + }; + + switch (id) { + case V4L2_CID_MPEG_STREAM_TYPE: + return (p->capabilities & CX2341X_CAP_HAS_TS) ? + mpeg_stream_type_with_ts : mpeg_stream_type_without_ts; + case V4L2_CID_MPEG_AUDIO_ENCODING: + return (p->capabilities & CX2341X_CAP_HAS_AC3) ? + mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id); + case V4L2_CID_MPEG_AUDIO_L1_BITRATE: + case V4L2_CID_MPEG_AUDIO_L3_BITRATE: + return NULL; + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: + case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: + case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: + return cx2341x_get_menu(id); + default: + return v4l2_ctrl_get_menu(id); + } +} +EXPORT_SYMBOL(cx2341x_ctrl_get_menu); + +static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) +{ + params->audio_properties = + (params->audio_sampling_freq << 0) | + (params->audio_mode << 8) | + (params->audio_mode_extension << 10) | + (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) + ? 3 : params->audio_emphasis) << 12) | + (params->audio_crc << 14); + + if ((params->capabilities & CX2341X_CAP_HAS_AC3) && + params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) { + params->audio_properties |= + /* Not sure if this MPEG Layer II setting is required */ + ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | + (params->audio_ac3_bitrate << 4) | + (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); + } else { + /* Assuming MPEG Layer II */ + params->audio_properties |= + ((3 - params->audio_encoding) << 2) | + ((1 + params->audio_l2_bitrate) << 4); + } +} + +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, + struct v4l2_ext_controls *ctrls, unsigned int cmd) +{ + int err = 0; + int i; + + if (cmd == VIDIOC_G_EXT_CTRLS) { + for (i = 0; i < ctrls->count; i++) { + struct v4l2_ext_control *ctrl = ctrls->controls + i; + + err = cx2341x_get_ctrl(params, ctrl); + if (err) { + ctrls->error_idx = i; + break; + } + } + return err; + } + for (i = 0; i < ctrls->count; i++) { + struct v4l2_ext_control *ctrl = ctrls->controls + i; + struct v4l2_queryctrl qctrl; + const char * const *menu_items = NULL; + + qctrl.id = ctrl->id; + err = cx2341x_ctrl_query(params, &qctrl); + if (err) + break; + if (qctrl.type == V4L2_CTRL_TYPE_MENU) + menu_items = cx2341x_ctrl_get_menu(params, qctrl.id); + err = v4l2_ctrl_check(ctrl, &qctrl, menu_items); + if (err) + break; + err = cx2341x_set_ctrl(params, busy, ctrl); + if (err) + break; + } + if (err == 0 && + params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + params->video_bitrate_peak < params->video_bitrate) { + err = -ERANGE; + ctrls->error_idx = ctrls->count; + } + if (err) + ctrls->error_idx = i; + else + cx2341x_calc_audio_properties(params); + return err; +} +EXPORT_SYMBOL(cx2341x_ext_ctrls); + +void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) +{ + *p = default_params; + cx2341x_calc_audio_properties(p); +} +EXPORT_SYMBOL(cx2341x_fill_defaults); + +static int cx2341x_api(void *priv, cx2341x_mbox_func func, + u32 cmd, int args, ...) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + va_list vargs; + int i; + + va_start(vargs, args); + + for (i = 0; i < args; i++) + data[i] = va_arg(vargs, int); + va_end(vargs); + return func(priv, cmd, args, 0, data); +} + +#define NEQ(field) (old->field != new->field) + +int cx2341x_update(void *priv, cx2341x_mbox_func func, + const struct cx2341x_mpeg_params *old, + const struct cx2341x_mpeg_params *new) +{ + static int mpeg_stream_type[] = { + 0, /* MPEG-2 PS */ + 1, /* MPEG-2 TS */ + 2, /* MPEG-1 SS */ + 14, /* DVD */ + 11, /* VCD */ + 12, /* SVCD */ + }; + + int err = 0; + int force = (old == NULL); + u16 temporal = new->video_temporal_filter; + + cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); + + if (force || NEQ(is_50hz)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, + new->is_50hz); + if (err) return err; + } + + if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) { + u16 w = new->width; + u16 h = new->height; + + if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { + w /= 2; + h /= 2; + } + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, + h, w); + if (err) return err; + } + if (force || NEQ(stream_type)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, + mpeg_stream_type[new->stream_type]); + if (err) return err; + } + if (force || NEQ(video_aspect)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, + 1 + new->video_aspect); + if (err) return err; + } + if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2, + new->video_gop_size, new->video_b_frames + 1); + if (err) return err; + } + if (force || NEQ(video_gop_closure)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, + new->video_gop_closure); + if (err) return err; + } + if (force || NEQ(audio_properties)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, + 1, new->audio_properties); + if (err) return err; + } + if (force || NEQ(audio_mute)) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, + new->audio_mute); + if (err) return err; + } + if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) || + NEQ(video_bitrate_peak)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5, + new->video_bitrate_mode, new->video_bitrate, + new->video_bitrate_peak / 400, 0, 0); + if (err) return err; + } + if (force || NEQ(video_spatial_filter_mode) || + NEQ(video_temporal_filter_mode) || + NEQ(video_median_filter_type)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, + 2, new->video_spatial_filter_mode | + (new->video_temporal_filter_mode << 1), + new->video_median_filter_type); + if (err) return err; + } + if (force || NEQ(video_luma_median_filter_bottom) || + NEQ(video_luma_median_filter_top) || + NEQ(video_chroma_median_filter_bottom) || + NEQ(video_chroma_median_filter_top)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4, + new->video_luma_median_filter_bottom, + new->video_luma_median_filter_top, + new->video_chroma_median_filter_bottom, + new->video_chroma_median_filter_top); + if (err) return err; + } + if (force || NEQ(video_luma_spatial_filter_type) || + NEQ(video_chroma_spatial_filter_type)) { + err = cx2341x_api(priv, func, + CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, + 2, new->video_luma_spatial_filter_type, + new->video_chroma_spatial_filter_type); + if (err) return err; + } + if (force || NEQ(video_spatial_filter) || + old->video_temporal_filter != temporal) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, + 2, new->video_spatial_filter, temporal); + if (err) return err; + } + if (force || NEQ(video_temporal_decimation)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, + 1, new->video_temporal_decimation); + if (err) return err; + } + if (force || NEQ(video_mute) || + (new->video_mute && NEQ(video_mute_yuv))) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, + new->video_mute | (new->video_mute_yuv << 8)); + if (err) return err; + } + if (force || NEQ(stream_insert_nav_packets)) { + err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, + 7, new->stream_insert_nav_packets); + if (err) return err; + } + return 0; +} +EXPORT_SYMBOL(cx2341x_update); + +static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id) +{ + const char * const *menu = cx2341x_ctrl_get_menu(p, id); + struct v4l2_ext_control ctrl; + + if (menu == NULL) + goto invalid; + ctrl.id = id; + if (cx2341x_get_ctrl(p, &ctrl)) + goto invalid; + while (ctrl.value-- && *menu) menu++; + if (*menu == NULL) + goto invalid; + return *menu; + +invalid: + return ""; +} + +void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) +{ + int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + + /* Stream */ + printk(KERN_INFO "%s: Stream: %s", + prefix, + cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); + if (p->stream_insert_nav_packets) + printk(" (with navigation packets)"); + printk("\n"); + printk(KERN_INFO "%s: VBI Format: %s\n", + prefix, + cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); + + /* Video */ + printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n", + prefix, + p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), + p->is_50hz ? 25 : 30, + (p->video_mute) ? " (muted)" : ""); + printk(KERN_INFO "%s: Video: %s, %s, %s, %d", + prefix, + cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), + cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT), + cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), + p->video_bitrate); + if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + printk(", Peak %d", p->video_bitrate_peak); + printk("\n"); + printk(KERN_INFO + "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", + prefix, + p->video_gop_size, p->video_b_frames, + p->video_gop_closure ? "" : "No "); + if (p->video_temporal_decimation) + printk(KERN_INFO "%s: Video: Temporal Decimation %d\n", + prefix, p->video_temporal_decimation); + + /* Audio */ + printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", + prefix, + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), + cx2341x_menu_item(p, + p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3 + ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE + : V4L2_CID_MPEG_AUDIO_L2_BITRATE), + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), + p->audio_mute ? " (muted)" : ""); + if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + printk(", %s", cx2341x_menu_item(p, + V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); + printk(", %s, %s\n", + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS), + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); + + /* Encoding filters */ + printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n", + prefix, + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), + p->video_spatial_filter); + + printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", + prefix, + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), + p->video_temporal_filter); + printk(KERN_INFO + "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", + prefix, + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), + p->video_luma_median_filter_bottom, + p->video_luma_median_filter_top, + p->video_chroma_median_filter_bottom, + p->video_chroma_median_filter_top); +} +EXPORT_SYMBOL(cx2341x_log_status); + + + +/********************** NEW CODE *********************/ + +static inline struct cx2341x_handler *to_cxhdl(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct cx2341x_handler, hdl); +} + +static int cx2341x_hdl_api(struct cx2341x_handler *hdl, + u32 cmd, int args, ...) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + va_list vargs; + int i; + + va_start(vargs, args); + + for (i = 0; i < args; i++) + data[i] = va_arg(vargs, int); + va_end(vargs); + return hdl->func(hdl->priv, cmd, args, 0, data); +} + +/* ctrl->handler->lock is held, so it is safe to access cur.val */ +static inline int cx2341x_neq(struct v4l2_ctrl *ctrl) +{ + return ctrl && ctrl->val != ctrl->cur.val; +} + +static int cx2341x_try_ctrl(struct v4l2_ctrl *ctrl) +{ + struct cx2341x_handler *hdl = to_cxhdl(ctrl); + s32 val = ctrl->val; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_B_FRAMES: { + /* video gop cluster */ + int b = val + 1; + int gop = hdl->video_gop_size->val; + + gop = b * ((gop + b - 1) / b); + + /* Max GOP size = 34 */ + while (gop > 34) + gop -= b; + hdl->video_gop_size->val = gop; + break; + } + + case V4L2_CID_MPEG_STREAM_TYPE: + /* stream type cluster */ + hdl->video_encoding->val = + (hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || + hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? + V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : + V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + if (hdl->video_encoding->val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + /* MPEG-1 implies CBR */ + hdl->video_bitrate_mode->val = + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + /* peak bitrate shall be >= normal bitrate */ + if (hdl->video_bitrate_mode->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + hdl->video_bitrate_peak->val < hdl->video_bitrate->val) + hdl->video_bitrate_peak->val = hdl->video_bitrate->val; + break; + } + return 0; +} + +static int cx2341x_s_ctrl(struct v4l2_ctrl *ctrl) +{ + static const int mpeg_stream_type[] = { + 0, /* MPEG-2 PS */ + 1, /* MPEG-2 TS */ + 2, /* MPEG-1 SS */ + 14, /* DVD */ + 11, /* VCD */ + 12, /* SVCD */ + }; + struct cx2341x_handler *hdl = to_cxhdl(ctrl); + s32 val = ctrl->val; + u32 props; + int err; + + switch (ctrl->id) { + case V4L2_CID_MPEG_STREAM_VBI_FMT: + if (hdl->ops && hdl->ops->s_stream_vbi_fmt) + return hdl->ops->s_stream_vbi_fmt(hdl, val); + return 0; + + case V4L2_CID_MPEG_VIDEO_ASPECT: + return cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_ASPECT_RATIO, 1, val + 1); + + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_CLOSURE, 1, val); + + case V4L2_CID_MPEG_AUDIO_MUTE: + return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_AUDIO, 1, val); + + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: + return cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_FRAME_DROP_RATE, 1, val); + + case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: + return cx2341x_hdl_api(hdl, CX2341X_ENC_MISC, 2, 7, val); + + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + /* audio properties cluster */ + props = (hdl->audio_sampling_freq->val << 0) | + (hdl->audio_mode->val << 8) | + (hdl->audio_mode_extension->val << 10) | + (hdl->audio_crc->val << 14); + if (hdl->audio_emphasis->val == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) + props |= 3 << 12; + else + props |= hdl->audio_emphasis->val << 12; + + if (hdl->audio_encoding->val == V4L2_MPEG_AUDIO_ENCODING_AC3) { + props |= +#if 1 + /* Not sure if this MPEG Layer II setting is required */ + ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | +#endif + (hdl->audio_ac3_bitrate->val << 4) | + (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); + } else { + /* Assuming MPEG Layer II */ + props |= + ((3 - hdl->audio_encoding->val) << 2) | + ((1 + hdl->audio_l2_bitrate->val) << 4); + } + err = cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, props); + if (err) + return err; + + hdl->audio_properties = props; + if (hdl->audio_ac3_bitrate) { + int is_ac3 = hdl->audio_encoding->val == + V4L2_MPEG_AUDIO_ENCODING_AC3; + + v4l2_ctrl_activate(hdl->audio_ac3_bitrate, is_ac3); + v4l2_ctrl_activate(hdl->audio_l2_bitrate, !is_ac3); + } + v4l2_ctrl_activate(hdl->audio_mode_extension, + hdl->audio_mode->val == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO); + if (cx2341x_neq(hdl->audio_sampling_freq) && + hdl->ops && hdl->ops->s_audio_sampling_freq) + return hdl->ops->s_audio_sampling_freq(hdl, hdl->audio_sampling_freq->val); + if (cx2341x_neq(hdl->audio_mode) && + hdl->ops && hdl->ops->s_audio_mode) + return hdl->ops->s_audio_mode(hdl, hdl->audio_mode->val); + return 0; + + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + /* video gop cluster */ + return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_PROPERTIES, 2, + hdl->video_gop_size->val, + hdl->video_b_frames->val + 1); + + case V4L2_CID_MPEG_STREAM_TYPE: + /* stream type cluster */ + err = cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[val]); + if (err) + return err; + + err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_BIT_RATE, 5, + hdl->video_bitrate_mode->val, + hdl->video_bitrate->val, + hdl->video_bitrate_peak->val / 400, 0, 0); + if (err) + return err; + + v4l2_ctrl_activate(hdl->video_bitrate_mode, + hdl->video_encoding->val != V4L2_MPEG_VIDEO_ENCODING_MPEG_1); + v4l2_ctrl_activate(hdl->video_bitrate_peak, + hdl->video_bitrate_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); + if (cx2341x_neq(hdl->video_encoding) && + hdl->ops && hdl->ops->s_video_encoding) + return hdl->ops->s_video_encoding(hdl, hdl->video_encoding->val); + return 0; + + case V4L2_CID_MPEG_VIDEO_MUTE: + /* video mute cluster */ + return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_VIDEO, 1, + hdl->video_mute->val | + (hdl->video_mute_yuv->val << 8)); + + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: { + int active_filter; + + /* video filter mode */ + err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_MODE, 2, + hdl->video_spatial_filter_mode->val | + (hdl->video_temporal_filter_mode->val << 1), + hdl->video_median_filter_type->val); + if (err) + return err; + + active_filter = hdl->video_spatial_filter_mode->val != + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO; + v4l2_ctrl_activate(hdl->video_spatial_filter, active_filter); + v4l2_ctrl_activate(hdl->video_luma_spatial_filter_type, active_filter); + v4l2_ctrl_activate(hdl->video_chroma_spatial_filter_type, active_filter); + active_filter = hdl->video_temporal_filter_mode->val != + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO; + v4l2_ctrl_activate(hdl->video_temporal_filter, active_filter); + active_filter = hdl->video_median_filter_type->val != + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF; + v4l2_ctrl_activate(hdl->video_luma_median_filter_bottom, active_filter); + v4l2_ctrl_activate(hdl->video_luma_median_filter_top, active_filter); + v4l2_ctrl_activate(hdl->video_chroma_median_filter_bottom, active_filter); + v4l2_ctrl_activate(hdl->video_chroma_median_filter_top, active_filter); + return 0; + } + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: + /* video filter type cluster */ + return cx2341x_hdl_api(hdl, + CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, + hdl->video_luma_spatial_filter_type->val, + hdl->video_chroma_spatial_filter_type->val); + + case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: + /* video filter cluster */ + return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2, + hdl->video_spatial_filter->val, + hdl->video_temporal_filter->val); + + case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: + /* video median cluster */ + return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_CORING_LEVELS, 4, + hdl->video_luma_median_filter_bottom->val, + hdl->video_luma_median_filter_top->val, + hdl->video_chroma_median_filter_bottom->val, + hdl->video_chroma_median_filter_top->val); + } + return -EINVAL; +} + +static const struct v4l2_ctrl_ops cx2341x_ops = { + .try_ctrl = cx2341x_try_ctrl, + .s_ctrl = cx2341x_s_ctrl, +}; + +static struct v4l2_ctrl *cx2341x_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, + u32 id, s32 min, s32 max, s32 step, s32 def) +{ + struct v4l2_ctrl_config cfg; + + cx2341x_ctrl_fill(id, &cfg.name, &cfg.type, &min, &max, &step, &def, &cfg.flags); + cfg.ops = &cx2341x_ops; + cfg.id = id; + cfg.min = min; + cfg.max = max; + cfg.def = def; + if (cfg.type == V4L2_CTRL_TYPE_MENU) { + cfg.step = 0; + cfg.menu_skip_mask = step; + cfg.qmenu = cx2341x_get_menu(id); + } else { + cfg.step = step; + cfg.menu_skip_mask = 0; + } + return v4l2_ctrl_new_custom(hdl, &cfg, NULL); +} + +static struct v4l2_ctrl *cx2341x_ctrl_new_std(struct v4l2_ctrl_handler *hdl, + u32 id, s32 min, s32 max, s32 step, s32 def) +{ + return v4l2_ctrl_new_std(hdl, &cx2341x_ops, id, min, max, step, def); +} + +static struct v4l2_ctrl *cx2341x_ctrl_new_menu(struct v4l2_ctrl_handler *hdl, + u32 id, s32 max, s32 mask, s32 def) +{ + return v4l2_ctrl_new_std_menu(hdl, &cx2341x_ops, id, max, mask, def); +} + +int cx2341x_handler_init(struct cx2341x_handler *cxhdl, + unsigned nr_of_controls_hint) +{ + struct v4l2_ctrl_handler *hdl = &cxhdl->hdl; + u32 caps = cxhdl->capabilities; + int has_sliced_vbi = caps & CX2341X_CAP_HAS_SLICED_VBI; + int has_ac3 = caps & CX2341X_CAP_HAS_AC3; + int has_ts = caps & CX2341X_CAP_HAS_TS; + + cxhdl->width = 720; + cxhdl->height = 480; + + v4l2_ctrl_handler_init(hdl, nr_of_controls_hint); + + /* Add controls in ascending control ID order for fastest + insertion time. */ + cxhdl->stream_type = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_STREAM_TYPE, + V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, has_ts ? 0 : 2, + V4L2_MPEG_STREAM_TYPE_MPEG2_PS); + cxhdl->stream_vbi_fmt = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_STREAM_VBI_FMT, + V4L2_MPEG_STREAM_VBI_FMT_IVTV, has_sliced_vbi ? 0 : 2, + V4L2_MPEG_STREAM_VBI_FMT_NONE); + cxhdl->audio_sampling_freq = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 0, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); + cxhdl->audio_encoding = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_ENCODING, + V4L2_MPEG_AUDIO_ENCODING_AC3, has_ac3 ? ~0x12 : ~0x2, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2); + cxhdl->audio_l2_bitrate = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_L2_BITRATE, + V4L2_MPEG_AUDIO_L2_BITRATE_384K, 0x1ff, + V4L2_MPEG_AUDIO_L2_BITRATE_224K); + cxhdl->audio_mode = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_MODE, + V4L2_MPEG_AUDIO_MODE_MONO, 0, + V4L2_MPEG_AUDIO_MODE_STEREO); + cxhdl->audio_mode_extension = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 0, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); + cxhdl->audio_emphasis = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_EMPHASIS, + V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 0, + V4L2_MPEG_AUDIO_EMPHASIS_NONE); + cxhdl->audio_crc = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_CRC, + V4L2_MPEG_AUDIO_CRC_CRC16, 0, + V4L2_MPEG_AUDIO_CRC_NONE); + + cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_AUDIO_MUTE, 0, 1, 1, 0); + if (has_ac3) + cxhdl->audio_ac3_bitrate = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_AUDIO_AC3_BITRATE, + V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 0x03, + V4L2_MPEG_AUDIO_AC3_BITRATE_224K); + cxhdl->video_encoding = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_VIDEO_ENCODING, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 0, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2); + cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_VIDEO_ASPECT, + V4L2_MPEG_VIDEO_ASPECT_221x100, 0, + V4L2_MPEG_VIDEO_ASPECT_4x3); + cxhdl->video_b_frames = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 33, 1, 2); + cxhdl->video_gop_size = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + 1, 34, 1, cxhdl->is_50hz ? 12 : 15); + cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1); + cxhdl->video_bitrate_mode = cx2341x_ctrl_new_menu(hdl, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); + cxhdl->video_bitrate = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_BITRATE, + 0, 27000000, 1, 6000000); + cxhdl->video_bitrate_peak = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + 0, 27000000, 1, 8000000); + cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, 0, 255, 1, 0); + cxhdl->video_mute = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_MUTE, 0, 1, 1, 0); + cxhdl->video_mute_yuv = cx2341x_ctrl_new_std(hdl, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, 0, 0xffffff, 1, 0x008080); + + /* CX23415/6 specific */ + cxhdl->video_spatial_filter_mode = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 0, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); + cxhdl->video_spatial_filter = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, + 0, 15, 1, 0); + cxhdl->video_luma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, + 0, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR); + cxhdl->video_chroma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + 0, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR); + cxhdl->video_temporal_filter_mode = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, + 0, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); + cxhdl->video_temporal_filter = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, + 0, 31, 1, 8); + cxhdl->video_median_filter_type = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, + 0, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); + cxhdl->video_luma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, + 0, 255, 1, 0); + cxhdl->video_luma_median_filter_top = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, + 0, 255, 1, 255); + cxhdl->video_chroma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, + 0, 255, 1, 0); + cxhdl->video_chroma_median_filter_top = cx2341x_ctrl_new_custom(hdl, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, + 0, 255, 1, 255); + cx2341x_ctrl_new_custom(hdl, V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, + 0, 1, 1, 0); + + if (hdl->error) { + int err = hdl->error; + + v4l2_ctrl_handler_free(hdl); + return err; + } + + v4l2_ctrl_cluster(8, &cxhdl->audio_sampling_freq); + v4l2_ctrl_cluster(2, &cxhdl->video_b_frames); + v4l2_ctrl_cluster(5, &cxhdl->stream_type); + v4l2_ctrl_cluster(2, &cxhdl->video_mute); + v4l2_ctrl_cluster(3, &cxhdl->video_spatial_filter_mode); + v4l2_ctrl_cluster(2, &cxhdl->video_luma_spatial_filter_type); + v4l2_ctrl_cluster(2, &cxhdl->video_spatial_filter); + v4l2_ctrl_cluster(4, &cxhdl->video_luma_median_filter_top); + + return 0; +} +EXPORT_SYMBOL(cx2341x_handler_init); + +void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz) +{ + cxhdl->is_50hz = is_50hz; + cxhdl->video_gop_size->default_value = cxhdl->is_50hz ? 12 : 15; +} +EXPORT_SYMBOL(cx2341x_handler_set_50hz); + +int cx2341x_handler_setup(struct cx2341x_handler *cxhdl) +{ + int h = cxhdl->height; + int w = cxhdl->width; + int err; + + err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_OUTPUT_PORT, 2, cxhdl->port, 0); + if (err) + return err; + err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_RATE, 1, cxhdl->is_50hz); + if (err) + return err; + + if (v4l2_ctrl_g_ctrl(cxhdl->video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { + w /= 2; + h /= 2; + } + err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); + if (err) + return err; + return v4l2_ctrl_handler_setup(&cxhdl->hdl); +} +EXPORT_SYMBOL(cx2341x_handler_setup); + +void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy) +{ + v4l2_ctrl_grab(cxhdl->audio_sampling_freq, busy); + v4l2_ctrl_grab(cxhdl->audio_encoding, busy); + v4l2_ctrl_grab(cxhdl->audio_l2_bitrate, busy); + v4l2_ctrl_grab(cxhdl->audio_ac3_bitrate, busy); + v4l2_ctrl_grab(cxhdl->stream_vbi_fmt, busy); + v4l2_ctrl_grab(cxhdl->stream_type, busy); + v4l2_ctrl_grab(cxhdl->video_bitrate_mode, busy); + v4l2_ctrl_grab(cxhdl->video_bitrate, busy); + v4l2_ctrl_grab(cxhdl->video_bitrate_peak, busy); +} +EXPORT_SYMBOL(cx2341x_handler_set_busy); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/altera-ci.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/altera-ci.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/altera-ci.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/altera-ci.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,838 @@ +/* + * altera-ci.c + * + * CI driver in conjunction with NetUp Dual DVB-T/C RF CI card + * + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * currently cx23885 GPIO's used. + * GPIO-0 ~INT in + * GPIO-1 TMS out + * GPIO-2 ~reset chips out + * GPIO-3 to GPIO-10 data/addr for CA in/out + * GPIO-11 ~CS out + * GPIO-12 AD_RG out + * GPIO-13 ~WR out + * GPIO-14 ~RD out + * GPIO-15 ~RDY in + * GPIO-16 TCK out + * GPIO-17 TDO in + * GPIO-18 TDI out + */ +/* + * Bit definitions for MC417_RWD and MC417_OEN registers + * bits 31-16 + * +-----------+ + * | Reserved | + * +-----------+ + * bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | TDI | TDO | TCK | RDY# | #RD | #WR | AD_RG | #CS | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| + * +-------+-------+-------+-------+-------+-------+-------+-------+ + */ +#include +#include +#include +#include "altera-ci.h" +#include "dvb_ca_en50221.h" + +/* FPGA regs */ +#define NETUP_CI_INT_CTRL 0x00 +#define NETUP_CI_BUSCTRL2 0x01 +#define NETUP_CI_ADDR0 0x04 +#define NETUP_CI_ADDR1 0x05 +#define NETUP_CI_DATA 0x06 +#define NETUP_CI_BUSCTRL 0x07 +#define NETUP_CI_PID_ADDR0 0x08 +#define NETUP_CI_PID_ADDR1 0x09 +#define NETUP_CI_PID_DATA 0x0a +#define NETUP_CI_TSA_DIV 0x0c +#define NETUP_CI_TSB_DIV 0x0d +#define NETUP_CI_REVISION 0x0f + +/* const for ci op */ +#define NETUP_CI_FLG_CTL 1 +#define NETUP_CI_FLG_RD 1 +#define NETUP_CI_FLG_AD 1 + +static unsigned int ci_dbg; +module_param(ci_dbg, int, 0644); +MODULE_PARM_DESC(ci_dbg, "Enable CI debugging"); + +static unsigned int pid_dbg; +module_param(pid_dbg, int, 0644); +MODULE_PARM_DESC(pid_dbg, "Enable PID filtering debugging"); + +MODULE_DESCRIPTION("altera FPGA CI module"); +MODULE_AUTHOR("Igor M. Liplianin "); +MODULE_LICENSE("GPL"); + +#define ci_dbg_print(args...) \ + do { \ + if (ci_dbg) \ + printk(KERN_DEBUG args); \ + } while (0) + +#define pid_dbg_print(args...) \ + do { \ + if (pid_dbg) \ + printk(KERN_DEBUG args); \ + } while (0) + +struct altera_ci_state; +struct netup_hw_pid_filter; + +struct fpga_internal { + void *dev; + struct mutex fpga_mutex;/* two CI's on the same fpga */ + struct netup_hw_pid_filter *pid_filt[2]; + struct altera_ci_state *state[2]; + struct work_struct work; + int (*fpga_rw) (void *dev, int flag, int data, int rw); + int cis_used; + int filts_used; + int strt_wrk; +}; + +/* stores all private variables for communication with CI */ +struct altera_ci_state { + struct fpga_internal *internal; + struct dvb_ca_en50221 ca; + int status; + int nr; +}; + +/* stores all private variables for hardware pid filtering */ +struct netup_hw_pid_filter { + struct fpga_internal *internal; + struct dvb_demux *demux; + /* save old functions */ + int (*start_feed)(struct dvb_demux_feed *feed); + int (*stop_feed)(struct dvb_demux_feed *feed); + + int status; + int nr; +}; + +/* internal params node */ +struct fpga_inode { + /* pointer for internal params, one for each pair of CI's */ + struct fpga_internal *internal; + struct fpga_inode *next_inode; +}; + +/* first internal params */ +static struct fpga_inode *fpga_first_inode; + +/* find chip by dev */ +static struct fpga_inode *find_inode(void *dev) +{ + struct fpga_inode *temp_chip = fpga_first_inode; + + if (temp_chip == NULL) + return temp_chip; + + /* + Search for the last fpga CI chip or + find it by dev */ + while ((temp_chip != NULL) && + (temp_chip->internal->dev != dev)) + temp_chip = temp_chip->next_inode; + + return temp_chip; +} +/* check demux */ +static struct fpga_internal *check_filter(struct fpga_internal *temp_int, + void *demux_dev, int filt_nr) +{ + if (temp_int == NULL) + return NULL; + + if ((temp_int->pid_filt[filt_nr]) == NULL) + return NULL; + + if (temp_int->pid_filt[filt_nr]->demux == demux_dev) + return temp_int; + + return NULL; +} + +/* find chip by demux */ +static struct fpga_inode *find_dinode(void *demux_dev) +{ + struct fpga_inode *temp_chip = fpga_first_inode; + struct fpga_internal *temp_int; + + /* + * Search of the last fpga CI chip or + * find it by demux + */ + while (temp_chip != NULL) { + if (temp_chip->internal != NULL) { + temp_int = temp_chip->internal; + if (check_filter(temp_int, demux_dev, 0)) + break; + if (check_filter(temp_int, demux_dev, 1)) + break; + } + + temp_chip = temp_chip->next_inode; + } + + return temp_chip; +} + +/* deallocating chip */ +static void remove_inode(struct fpga_internal *internal) +{ + struct fpga_inode *prev_node = fpga_first_inode; + struct fpga_inode *del_node = find_inode(internal->dev); + + if (del_node != NULL) { + if (del_node == fpga_first_inode) { + fpga_first_inode = del_node->next_inode; + } else { + while (prev_node->next_inode != del_node) + prev_node = prev_node->next_inode; + + if (del_node->next_inode == NULL) + prev_node->next_inode = NULL; + else + prev_node->next_inode = + prev_node->next_inode->next_inode; + } + + kfree(del_node); + } +} + +/* allocating new chip */ +static struct fpga_inode *append_internal(struct fpga_internal *internal) +{ + struct fpga_inode *new_node = fpga_first_inode; + + if (new_node == NULL) { + new_node = kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); + fpga_first_inode = new_node; + } else { + while (new_node->next_inode != NULL) + new_node = new_node->next_inode; + + new_node->next_inode = + kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); + if (new_node->next_inode != NULL) + new_node = new_node->next_inode; + else + new_node = NULL; + } + + if (new_node != NULL) { + new_node->internal = internal; + new_node->next_inode = NULL; + } + + return new_node; +} + +static int netup_fpga_op_rw(struct fpga_internal *inter, int addr, + u8 val, u8 read) +{ + inter->fpga_rw(inter->dev, NETUP_CI_FLG_AD, addr, 0); + return inter->fpga_rw(inter->dev, 0, val, read); +} + +/* flag - mem/io, read - read/write */ +int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, + u8 flag, u8 read, int addr, u8 val) +{ + + struct altera_ci_state *state = en50221->data; + struct fpga_internal *inter = state->internal; + + u8 store; + int mem = 0; + + if (0 != slot) + return -EINVAL; + + mutex_lock(&inter->fpga_mutex); + + netup_fpga_op_rw(inter, NETUP_CI_ADDR0, ((addr << 1) & 0xfe), 0); + netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0); + store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); + + store &= 0x0f; + store |= ((state->nr << 7) | (flag << 6)); + + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0); + mem = netup_fpga_op_rw(inter, NETUP_CI_DATA, val, read); + + mutex_unlock(&inter->fpga_mutex); + + ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__, + (read) ? "read" : "write", addr, + (flag == NETUP_CI_FLG_CTL) ? "ctl" : "mem", + (read) ? mem : val); + + return mem; +} + +int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr) +{ + return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0); +} + +int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr, u8 data) +{ + return altera_ci_op_cam(en50221, slot, 0, 0, addr, data); +} + +int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) +{ + return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, + NETUP_CI_FLG_RD, addr, 0); +} + +int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, + u8 addr, u8 data) +{ + return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data); +} + +int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +{ + struct altera_ci_state *state = en50221->data; + struct fpga_internal *inter = state->internal; + /* reasonable timeout for CI reset is 10 seconds */ + unsigned long t_out = jiffies + msecs_to_jiffies(9999); + int ret; + + ci_dbg_print("%s\n", __func__); + + if (0 != slot) + return -EINVAL; + + mutex_lock(&inter->fpga_mutex); + + ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, + (ret & 0xcf) | (1 << (5 - state->nr)), 0); + + mutex_unlock(&inter->fpga_mutex); + + for (;;) { + mdelay(50); + + mutex_lock(&inter->fpga_mutex); + + ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, + 0, NETUP_CI_FLG_RD); + mutex_unlock(&inter->fpga_mutex); + + if ((ret & (1 << (5 - state->nr))) == 0) + break; + if (time_after(jiffies, t_out)) + break; + } + + + ci_dbg_print("%s: %d msecs\n", __func__, + jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out)); + + return 0; +} + +int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +{ + /* not implemented */ + return 0; +} + +int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) +{ + struct altera_ci_state *state = en50221->data; + struct fpga_internal *inter = state->internal; + int ret; + + ci_dbg_print("%s\n", __func__); + + if (0 != slot) + return -EINVAL; + + mutex_lock(&inter->fpga_mutex); + + ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, + (ret & 0x0f) | (1 << (3 - state->nr)), 0); + + mutex_unlock(&inter->fpga_mutex); + + return 0; +} + +/* work handler */ +static void netup_read_ci_status(struct work_struct *work) +{ + struct fpga_internal *inter = + container_of(work, struct fpga_internal, work); + int ret; + + ci_dbg_print("%s\n", __func__); + + mutex_lock(&inter->fpga_mutex); + /* ack' irq */ + ret = netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0, NETUP_CI_FLG_RD); + ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); + + mutex_unlock(&inter->fpga_mutex); + + if (inter->state[1] != NULL) { + inter->state[1]->status = + ((ret & 1) == 0 ? + DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY : 0); + ci_dbg_print("%s: setting CI[1] status = 0x%x\n", + __func__, inter->state[1]->status); + }; + + if (inter->state[0] != NULL) { + inter->state[0]->status = + ((ret & 2) == 0 ? + DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY : 0); + ci_dbg_print("%s: setting CI[0] status = 0x%x\n", + __func__, inter->state[0]->status); + }; +} + +/* CI irq handler */ +int altera_ci_irq(void *dev) +{ + struct fpga_inode *temp_int = NULL; + struct fpga_internal *inter = NULL; + + ci_dbg_print("%s\n", __func__); + + if (dev != NULL) { + temp_int = find_inode(dev); + if (temp_int != NULL) { + inter = temp_int->internal; + schedule_work(&inter->work); + } + } + + return 1; +} +EXPORT_SYMBOL(altera_ci_irq); + +int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, + int open) +{ + struct altera_ci_state *state = en50221->data; + + if (0 != slot) + return -EINVAL; + + return state->status; +} + +void altera_hw_filt_release(void *main_dev, int filt_nr) +{ + struct fpga_inode *temp_int = find_inode(main_dev); + struct netup_hw_pid_filter *pid_filt = NULL; + + ci_dbg_print("%s\n", __func__); + + if (temp_int != NULL) { + pid_filt = temp_int->internal->pid_filt[filt_nr - 1]; + /* stored old feed controls */ + pid_filt->demux->start_feed = pid_filt->start_feed; + pid_filt->demux->stop_feed = pid_filt->stop_feed; + + if (((--(temp_int->internal->filts_used)) <= 0) && + ((temp_int->internal->cis_used) <= 0)) { + + ci_dbg_print("%s: Actually removing\n", __func__); + + remove_inode(temp_int->internal); + kfree(pid_filt->internal); + } + + kfree(pid_filt); + + } + +} +EXPORT_SYMBOL(altera_hw_filt_release); + +void altera_ci_release(void *dev, int ci_nr) +{ + struct fpga_inode *temp_int = find_inode(dev); + struct altera_ci_state *state = NULL; + + ci_dbg_print("%s\n", __func__); + + if (temp_int != NULL) { + state = temp_int->internal->state[ci_nr - 1]; + altera_hw_filt_release(dev, ci_nr); + + + if (((temp_int->internal->filts_used) <= 0) && + ((--(temp_int->internal->cis_used)) <= 0)) { + + ci_dbg_print("%s: Actually removing\n", __func__); + + remove_inode(temp_int->internal); + kfree(state->internal); + } + + if (state != NULL) { + if (state->ca.data != NULL) + dvb_ca_en50221_release(&state->ca); + + kfree(state); + } + } + +} +EXPORT_SYMBOL(altera_ci_release); + +static void altera_pid_control(struct netup_hw_pid_filter *pid_filt, + u16 pid, int onoff) +{ + struct fpga_internal *inter = pid_filt->internal; + u8 store = 0; + + /* pid 0-0x1f always enabled, don't touch them */ + if ((pid == 0x2000) || (pid < 0x20)) + return; + + mutex_lock(&inter->fpga_mutex); + + netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, (pid >> 3) & 0xff, 0); + netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, + ((pid >> 11) & 0x03) | (pid_filt->nr << 2), 0); + + store = netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 0, NETUP_CI_FLG_RD); + + if (onoff)/* 0 - on, 1 - off */ + store |= (1 << (pid & 7)); + else + store &= ~(1 << (pid & 7)); + + netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0); + + mutex_unlock(&inter->fpga_mutex); + + pid_dbg_print("%s: (%d) set pid: %5d 0x%04x '%s'\n", __func__, + pid_filt->nr, pid, pid, onoff ? "off" : "on"); +} + +static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt, + int filt_nr, int onoff) +{ + struct fpga_internal *inter = pid_filt->internal; + u8 store = 0; + int i; + + pid_dbg_print("%s: pid_filt->nr[%d] now %s\n", __func__, pid_filt->nr, + onoff ? "off" : "on"); + + if (onoff)/* 0 - on, 1 - off */ + store = 0xff;/* ignore pid */ + else + store = 0;/* enable pid */ + + mutex_lock(&inter->fpga_mutex); + + for (i = 0; i < 1024; i++) { + netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, i & 0xff, 0); + + netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, + ((i >> 8) & 0x03) | (pid_filt->nr << 2), 0); + /* pid 0-0x1f always enabled */ + netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, + (i > 3 ? store : 0), 0); + } + + mutex_unlock(&inter->fpga_mutex); +} + +int altera_pid_feed_control(void *demux_dev, int filt_nr, + struct dvb_demux_feed *feed, int onoff) +{ + struct fpga_inode *temp_int = find_dinode(demux_dev); + struct fpga_internal *inter = temp_int->internal; + struct netup_hw_pid_filter *pid_filt = inter->pid_filt[filt_nr - 1]; + + altera_pid_control(pid_filt, feed->pid, onoff ? 0 : 1); + /* call old feed proc's */ + if (onoff) + pid_filt->start_feed(feed); + else + pid_filt->stop_feed(feed); + + if (feed->pid == 0x2000) + altera_toggle_fullts_streaming(pid_filt, filt_nr, + onoff ? 0 : 1); + + return 0; +} +EXPORT_SYMBOL(altera_pid_feed_control); + +int altera_ci_start_feed(struct dvb_demux_feed *feed, int num) +{ + altera_pid_feed_control(feed->demux, num, feed, 1); + + return 0; +} + +int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num) +{ + altera_pid_feed_control(feed->demux, num, feed, 0); + + return 0; +} + +int altera_ci_start_feed_1(struct dvb_demux_feed *feed) +{ + return altera_ci_start_feed(feed, 1); +} + +int altera_ci_stop_feed_1(struct dvb_demux_feed *feed) +{ + return altera_ci_stop_feed(feed, 1); +} + +int altera_ci_start_feed_2(struct dvb_demux_feed *feed) +{ + return altera_ci_start_feed(feed, 2); +} + +int altera_ci_stop_feed_2(struct dvb_demux_feed *feed) +{ + return altera_ci_stop_feed(feed, 2); +} + +int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) +{ + struct netup_hw_pid_filter *pid_filt = NULL; + struct fpga_inode *temp_int = find_inode(config->dev); + struct fpga_internal *inter = NULL; + int ret = 0; + + pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL); + + ci_dbg_print("%s\n", __func__); + + if (!pid_filt) { + ret = -ENOMEM; + goto err; + } + + if (temp_int != NULL) { + inter = temp_int->internal; + (inter->filts_used)++; + ci_dbg_print("%s: Find Internal Structure!\n", __func__); + } else { + inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); + if (!inter) { + ret = -ENOMEM; + goto err; + } + + temp_int = append_internal(inter); + inter->filts_used = 1; + inter->dev = config->dev; + inter->fpga_rw = config->fpga_rw; + mutex_init(&inter->fpga_mutex); + inter->strt_wrk = 1; + ci_dbg_print("%s: Create New Internal Structure!\n", __func__); + } + + ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__, + pid_filt, hw_filt_nr - 1); + inter->pid_filt[hw_filt_nr - 1] = pid_filt; + pid_filt->demux = config->demux; + pid_filt->internal = inter; + pid_filt->nr = hw_filt_nr - 1; + /* store old feed controls */ + pid_filt->start_feed = config->demux->start_feed; + pid_filt->stop_feed = config->demux->stop_feed; + /* replace with new feed controls */ + if (hw_filt_nr == 1) { + pid_filt->demux->start_feed = altera_ci_start_feed_1; + pid_filt->demux->stop_feed = altera_ci_stop_feed_1; + } else if (hw_filt_nr == 2) { + pid_filt->demux->start_feed = altera_ci_start_feed_2; + pid_filt->demux->stop_feed = altera_ci_stop_feed_2; + } + + altera_toggle_fullts_streaming(pid_filt, 0, 1); + + return 0; +err: + ci_dbg_print("%s: Can't init hardware filter: Error %d\n", + __func__, ret); + + kfree(pid_filt); + + return ret; +} +EXPORT_SYMBOL(altera_hw_filt_init); + +int altera_ci_init(struct altera_ci_config *config, int ci_nr) +{ + struct altera_ci_state *state; + struct fpga_inode *temp_int = find_inode(config->dev); + struct fpga_internal *inter = NULL; + int ret = 0; + u8 store = 0; + + state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL); + + ci_dbg_print("%s\n", __func__); + + if (!state) { + ret = -ENOMEM; + goto err; + } + + if (temp_int != NULL) { + inter = temp_int->internal; + (inter->cis_used)++; + ci_dbg_print("%s: Find Internal Structure!\n", __func__); + } else { + inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); + if (!inter) { + ret = -ENOMEM; + goto err; + } + + temp_int = append_internal(inter); + inter->cis_used = 1; + inter->dev = config->dev; + inter->fpga_rw = config->fpga_rw; + mutex_init(&inter->fpga_mutex); + inter->strt_wrk = 1; + ci_dbg_print("%s: Create New Internal Structure!\n", __func__); + } + + ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__, + state, ci_nr - 1); + inter->state[ci_nr - 1] = state; + state->internal = inter; + state->nr = ci_nr - 1; + + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = altera_ci_read_attribute_mem; + state->ca.write_attribute_mem = altera_ci_write_attribute_mem; + state->ca.read_cam_control = altera_ci_read_cam_ctl; + state->ca.write_cam_control = altera_ci_write_cam_ctl; + state->ca.slot_reset = altera_ci_slot_reset; + state->ca.slot_shutdown = altera_ci_slot_shutdown; + state->ca.slot_ts_enable = altera_ci_slot_ts_ctl; + state->ca.poll_slot_status = altera_poll_ci_slot_status; + state->ca.data = state; + + ret = dvb_ca_en50221_init(config->adapter, + &state->ca, + /* flags */ 0, + /* n_slots */ 1); + if (0 != ret) + goto err; + + altera_hw_filt_init(config, ci_nr); + + if (inter->strt_wrk) { + INIT_WORK(&inter->work, netup_read_ci_status); + inter->strt_wrk = 0; + } + + ci_dbg_print("%s: CI initialized!\n", __func__); + + mutex_lock(&inter->fpga_mutex); + + /* Enable div */ + netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0); + netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0); + + /* enable TS out */ + store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); + store |= (3 << 4); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); + + ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD); + /* enable irq */ + netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0); + + mutex_unlock(&inter->fpga_mutex); + + ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret); + + schedule_work(&inter->work); + + return 0; +err: + ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret); + + kfree(state); + + return ret; +} +EXPORT_SYMBOL(altera_ci_init); + +int altera_ci_tuner_reset(void *dev, int ci_nr) +{ + struct fpga_inode *temp_int = find_inode(dev); + struct fpga_internal *inter = NULL; + u8 store; + + ci_dbg_print("%s\n", __func__); + + if (temp_int == NULL) + return -1; + + if (temp_int->internal == NULL) + return -1; + + inter = temp_int->internal; + + mutex_lock(&inter->fpga_mutex); + + store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); + store &= ~(4 << (2 - ci_nr)); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); + msleep(100); + store |= (4 << (2 - ci_nr)); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); + + mutex_unlock(&inter->fpga_mutex); + + return 0; +} +EXPORT_SYMBOL(altera_ci_tuner_reset); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/altera-ci.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/altera-ci.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/altera-ci.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/altera-ci.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,100 @@ +/* + * altera-ci.c + * + * CI driver in conjunction with NetUp Dual DVB-T/C RF CI card + * + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __ALTERA_CI_H +#define __ALTERA_CI_H + +#define ALT_DATA 0x000000ff +#define ALT_TDI 0x00008000 +#define ALT_TDO 0x00004000 +#define ALT_TCK 0x00002000 +#define ALT_RDY 0x00001000 +#define ALT_RD 0x00000800 +#define ALT_WR 0x00000400 +#define ALT_AD_RG 0x00000200 +#define ALT_CS 0x00000100 + +struct altera_ci_config { + void *dev;/* main dev, for example cx23885_dev */ + void *adapter;/* for CI to connect to */ + struct dvb_demux *demux;/* for hardware PID filter to connect to */ + int (*fpga_rw) (void *dev, int ad_rg, int val, int rw); +}; + +#if defined(CONFIG_MEDIA_ALTERA_CI) || (defined(CONFIG_MEDIA_ALTERA_CI_MODULE) \ + && defined(MODULE)) + +extern int altera_ci_init(struct altera_ci_config *config, int ci_nr); +extern void altera_ci_release(void *dev, int ci_nr); +extern int altera_ci_irq(void *dev); +extern int altera_ci_tuner_reset(void *dev, int ci_nr); + +#else + +static inline int altera_ci_init(struct altera_ci_config *config, int ci_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline void altera_ci_release(void *dev, int ci_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline int altera_ci_irq(void *dev) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline int altera_ci_tuner_reset(void *dev, int ci_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +#endif +#if 0 +static inline int altera_hw_filt_init(struct altera_ci_config *config, + int hw_filt_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline void altera_hw_filt_release(void *dev, int filt_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline int altera_pid_feed_control(void *dev, int filt_nr, + struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +#endif /* CONFIG_MEDIA_ALTERA_CI */ + +#endif /* __ALTERA_CI_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cimax2.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cimax2.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cimax2.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cimax2.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,536 @@ +/* + * cimax2.c + * + * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * Copyright (C) 2009 Abylay Ospan + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx23885.h" +#include "dvb_ca_en50221.h" +/**** Bit definitions for MC417_RWD and MC417_OEN registers *** + bits 31-16 ++-----------+ +| Reserved | ++-----------+ + bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 ++-------+-------+-------+-------+-------+-------+-------+-------+ +| WR# | RD# | | ACK# | ADHI | ADLO | CS1# | CS0# | ++-------+-------+-------+-------+-------+-------+-------+-------+ + bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 ++-------+-------+-------+-------+-------+-------+-------+-------+ +| DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| ++-------+-------+-------+-------+-------+-------+-------+-------+ +***/ +/* MC417 */ +#define NETUP_DATA 0x000000ff +#define NETUP_WR 0x00008000 +#define NETUP_RD 0x00004000 +#define NETUP_ACK 0x00001000 +#define NETUP_ADHI 0x00000800 +#define NETUP_ADLO 0x00000400 +#define NETUP_CS1 0x00000200 +#define NETUP_CS0 0x00000100 +#define NETUP_EN_ALL 0x00001000 +#define NETUP_CTRL_OFF (NETUP_CS1 | NETUP_CS0 | NETUP_WR | NETUP_RD) +#define NETUP_CI_CTL 0x04 +#define NETUP_CI_RD 1 + +#define NETUP_IRQ_DETAM 0x1 +#define NETUP_IRQ_IRQAM 0x4 + +static unsigned int ci_dbg; +module_param(ci_dbg, int, 0644); +MODULE_PARM_DESC(ci_dbg, "Enable CI debugging"); + +static unsigned int ci_irq_enable; +module_param(ci_irq_enable, int, 0644); +MODULE_PARM_DESC(ci_irq_enable, "Enable IRQ from CAM"); + +#define ci_dbg_print(args...) \ + do { \ + if (ci_dbg) \ + printk(KERN_DEBUG args); \ + } while (0) + +#define ci_irq_flags() (ci_irq_enable ? NETUP_IRQ_IRQAM : 0) + +/* stores all private variables for communication with CI */ +struct netup_ci_state { + struct dvb_ca_en50221 ca; + struct mutex ca_mutex; + struct i2c_adapter *i2c_adap; + u8 ci_i2c_addr; + int status; + struct work_struct work; + void *priv; + u8 current_irq_mode; + int current_ci_flag; + unsigned long next_status_checked_time; +}; + + +int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, + u8 *buf, int len) +{ + int ret; + struct i2c_msg msg[] = { + { + .addr = addr, + .flags = 0, + .buf = ®, + .len = 1 + }, { + .addr = addr, + .flags = I2C_M_RD, + .buf = buf, + .len = len + } + }; + + ret = i2c_transfer(i2c_adap, msg, 2); + + if (ret != 2) { + ci_dbg_print("%s: i2c read error, Reg = 0x%02x, Status = %d\n", + __func__, reg, ret); + + return -1; + } + + ci_dbg_print("%s: i2c read Addr=0x%04x, Reg = 0x%02x, data = %02x\n", + __func__, addr, reg, buf[0]); + + return 0; +} + +int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, + u8 *buf, int len) +{ + int ret; + u8 buffer[len + 1]; + + struct i2c_msg msg = { + .addr = addr, + .flags = 0, + .buf = &buffer[0], + .len = len + 1 + }; + + buffer[0] = reg; + memcpy(&buffer[1], buf, len); + + ret = i2c_transfer(i2c_adap, &msg, 1); + + if (ret != 1) { + ci_dbg_print("%s: i2c write error, Reg=[0x%02x], Status=%d\n", + __func__, reg, ret); + return -1; + } + + return 0; +} + +int netup_ci_get_mem(struct cx23885_dev *dev) +{ + int mem; + unsigned long timeout = jiffies + msecs_to_jiffies(1); + + for (;;) { + mem = cx_read(MC417_RWD); + if ((mem & NETUP_ACK) == 0) + break; + if (time_after(jiffies, timeout)) + break; + udelay(1); + } + + cx_set(MC417_RWD, NETUP_CTRL_OFF); + + return mem & 0xff; +} + +int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, + u8 flag, u8 read, int addr, u8 data) +{ + struct netup_ci_state *state = en50221->data; + struct cx23885_tsport *port = state->priv; + struct cx23885_dev *dev = port->dev; + + u8 store; + int mem; + int ret; + + if (0 != slot) + return -EINVAL; + + if (state->current_ci_flag != flag) { + ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &store, 1); + if (ret != 0) + return ret; + + store &= ~0x0c; + store |= flag; + + ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &store, 1); + if (ret != 0) + return ret; + }; + state->current_ci_flag = flag; + + mutex_lock(&dev->gpio_lock); + + /* write addr */ + cx_write(MC417_OEN, NETUP_EN_ALL); + cx_write(MC417_RWD, NETUP_CTRL_OFF | + NETUP_ADLO | (0xff & addr)); + cx_clear(MC417_RWD, NETUP_ADLO); + cx_write(MC417_RWD, NETUP_CTRL_OFF | + NETUP_ADHI | (0xff & (addr >> 8))); + cx_clear(MC417_RWD, NETUP_ADHI); + + if (read) { /* data in */ + cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA); + } else /* data out */ + cx_write(MC417_RWD, NETUP_CTRL_OFF | data); + + /* choose chip */ + cx_clear(MC417_RWD, + (state->ci_i2c_addr == 0x40) ? NETUP_CS0 : NETUP_CS1); + /* read/write */ + cx_clear(MC417_RWD, (read) ? NETUP_RD : NETUP_WR); + mem = netup_ci_get_mem(dev); + + mutex_unlock(&dev->gpio_lock); + + if (!read) + if (mem < 0) + return -EREMOTEIO; + + ci_dbg_print("%s: %s: chipaddr=[0x%x] addr=[0x%02x], %s=%x\n", __func__, + (read) ? "read" : "write", state->ci_i2c_addr, addr, + (flag == NETUP_CI_CTL) ? "ctl" : "mem", + (read) ? mem : data); + + if (read) + return mem; + + return 0; +} + +int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr) +{ + return netup_ci_op_cam(en50221, slot, 0, NETUP_CI_RD, addr, 0); +} + +int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr, u8 data) +{ + return netup_ci_op_cam(en50221, slot, 0, 0, addr, data); +} + +int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) +{ + return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, + NETUP_CI_RD, addr, 0); +} + +int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, + u8 addr, u8 data) +{ + return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, 0, addr, data); +} + +int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +{ + struct netup_ci_state *state = en50221->data; + u8 buf = 0x80; + int ret; + + if (0 != slot) + return -EINVAL; + + udelay(500); + ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &buf, 1); + + if (ret != 0) + return ret; + + udelay(500); + + buf = 0x00; + ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &buf, 1); + + msleep(1000); + dvb_ca_en50221_camready_irq(&state->ca, 0); + + return 0; + +} + +int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +{ + /* not implemented */ + return 0; +} + +int netup_ci_set_irq(struct dvb_ca_en50221 *en50221, u8 irq_mode) +{ + struct netup_ci_state *state = en50221->data; + int ret; + + if (irq_mode == state->current_irq_mode) + return 0; + + ci_dbg_print("%s: chipaddr=[0x%x] setting ci IRQ to [0x%x] \n", + __func__, state->ci_i2c_addr, irq_mode); + ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0x1b, &irq_mode, 1); + + if (ret != 0) + return ret; + + state->current_irq_mode = irq_mode; + + return 0; +} + +int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) +{ + struct netup_ci_state *state = en50221->data; + u8 buf; + + if (0 != slot) + return -EINVAL; + + netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &buf, 1); + buf |= 0x60; + + return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &buf, 1); +} + +/* work handler */ +static void netup_read_ci_status(struct work_struct *work) +{ + struct netup_ci_state *state = + container_of(work, struct netup_ci_state, work); + u8 buf[33]; + int ret; + + /* CAM module IRQ processing. fast operation */ + dvb_ca_en50221_frda_irq(&state->ca, 0); + + /* CAM module INSERT/REMOVE processing. slow operation because of i2c + * transfers */ + if (time_after(jiffies, state->next_status_checked_time) + || !state->status) { + ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &buf[0], 33); + + state->next_status_checked_time = jiffies + + msecs_to_jiffies(1000); + + if (ret != 0) + return; + + ci_dbg_print("%s: Slot Status Addr=[0x%04x], " + "Reg=[0x%02x], data=%02x, " + "TS config = %02x\n", __func__, + state->ci_i2c_addr, 0, buf[0], + buf[0]); + + + if (buf[0] & 1) + state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + else + state->status = 0; + } +} + +/* CI irq handler */ +int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status) +{ + struct cx23885_tsport *port = NULL; + struct netup_ci_state *state = NULL; + + ci_dbg_print("%s:\n", __func__); + + if (0 == (pci_status & (PCI_MSK_GPIO0 | PCI_MSK_GPIO1))) + return 0; + + if (pci_status & PCI_MSK_GPIO0) { + port = &dev->ts1; + state = port->port_priv; + schedule_work(&state->work); + ci_dbg_print("%s: Wakeup CI0\n", __func__); + } + + if (pci_status & PCI_MSK_GPIO1) { + port = &dev->ts2; + state = port->port_priv; + schedule_work(&state->work); + ci_dbg_print("%s: Wakeup CI1\n", __func__); + } + + return 1; +} + +int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) +{ + struct netup_ci_state *state = en50221->data; + + if (0 != slot) + return -EINVAL; + + netup_ci_set_irq(en50221, open ? (NETUP_IRQ_DETAM | ci_irq_flags()) + : NETUP_IRQ_DETAM); + + return state->status; +} + +int netup_ci_init(struct cx23885_tsport *port) +{ + struct netup_ci_state *state; + u8 cimax_init[34] = { + 0x00, /* module A control*/ + 0x00, /* auto select mask high A */ + 0x00, /* auto select mask low A */ + 0x00, /* auto select pattern high A */ + 0x00, /* auto select pattern low A */ + 0x44, /* memory access time A */ + 0x00, /* invert input A */ + 0x00, /* RFU */ + 0x00, /* RFU */ + 0x00, /* module B control*/ + 0x00, /* auto select mask high B */ + 0x00, /* auto select mask low B */ + 0x00, /* auto select pattern high B */ + 0x00, /* auto select pattern low B */ + 0x44, /* memory access time B */ + 0x00, /* invert input B */ + 0x00, /* RFU */ + 0x00, /* RFU */ + 0x00, /* auto select mask high Ext */ + 0x00, /* auto select mask low Ext */ + 0x00, /* auto select pattern high Ext */ + 0x00, /* auto select pattern low Ext */ + 0x00, /* RFU */ + 0x02, /* destination - module A */ + 0x01, /* power on (use it like store place) */ + 0x00, /* RFU */ + 0x00, /* int status read only */ + ci_irq_flags() | NETUP_IRQ_DETAM, /* DETAM, IRQAM unmasked */ + 0x05, /* EXTINT=active-high, INT=push-pull */ + 0x00, /* USCG1 */ + 0x04, /* ack active low */ + 0x00, /* LOCK = 0 */ + 0x33, /* serial mode, rising in, rising out, MSB first*/ + 0x31, /* synchronization */ + }; + int ret; + + ci_dbg_print("%s\n", __func__); + state = kzalloc(sizeof(struct netup_ci_state), GFP_KERNEL); + if (!state) { + ci_dbg_print("%s: Unable create CI structure!\n", __func__); + ret = -ENOMEM; + goto err; + } + + port->port_priv = state; + + switch (port->nr) { + case 1: + state->ci_i2c_addr = 0x40; + break; + case 2: + state->ci_i2c_addr = 0x41; + break; + } + + state->i2c_adap = &port->dev->i2c_bus[0].i2c_adap; + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = netup_ci_read_attribute_mem; + state->ca.write_attribute_mem = netup_ci_write_attribute_mem; + state->ca.read_cam_control = netup_ci_read_cam_ctl; + state->ca.write_cam_control = netup_ci_write_cam_ctl; + state->ca.slot_reset = netup_ci_slot_reset; + state->ca.slot_shutdown = netup_ci_slot_shutdown; + state->ca.slot_ts_enable = netup_ci_slot_ts_ctl; + state->ca.poll_slot_status = netup_poll_ci_slot_status; + state->ca.data = state; + state->priv = port; + state->current_irq_mode = ci_irq_flags() | NETUP_IRQ_DETAM; + + ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &cimax_init[0], 34); + /* lock registers */ + ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0x1f, &cimax_init[0x18], 1); + /* power on slots */ + ret |= netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0x18, &cimax_init[0x18], 1); + + if (0 != ret) + goto err; + + ret = dvb_ca_en50221_init(&port->frontends.adapter, + &state->ca, + /* flags */ 0, + /* n_slots */ 1); + if (0 != ret) + goto err; + + INIT_WORK(&state->work, netup_read_ci_status); + schedule_work(&state->work); + + ci_dbg_print("%s: CI initialized!\n", __func__); + + return 0; +err: + ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret); + kfree(state); + return ret; +} + +void netup_ci_exit(struct cx23885_tsport *port) +{ + struct netup_ci_state *state; + + if (NULL == port) + return; + + state = (struct netup_ci_state *)port->port_priv; + if (NULL == state) + return; + + if (NULL == state->ca.data) + return; + + dvb_ca_en50221_release(&state->ca); + kfree(state); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cimax2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cimax2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cimax2.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cimax2.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * cimax2.h + * + * CIMax(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * Copyright (C) 2009 Abylay Ospan + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef CIMAX2_H +#define CIMAX2_H +#include "dvb_ca_en50221.h" + +extern int netup_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr); +extern int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr, u8 data); +extern int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, + int slot, u8 addr); +extern int netup_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, + int slot, u8 addr, u8 data); +extern int netup_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot); +extern int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot); +extern int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot); +extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status); +extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, + int slot, int open); +extern int netup_ci_init(struct cx23885_tsport *port); +extern void netup_ci_exit(struct cx23885_tsport *port); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-417.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-417.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-417.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-417.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1796 @@ +/* + * + * Support for a cx23417 mpeg encoder via cx23885 host port. + * + * (c) 2004 Jelle Foks + * (c) 2004 Gerd Knorr + * (c) 2008 Steven Toth + * - CX23885/7/8 support + * + * Includes parts from the ivtv driver + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" +#include "cx23885-ioctl.h" + +#define CX23885_FIRM_IMAGE_SIZE 376836 +#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" + +static unsigned int mpegbufs = 32; +module_param(mpegbufs, int, 0644); +MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32"); +static unsigned int mpeglines = 32; +module_param(mpeglines, int, 0644); +MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32"); +static unsigned int mpeglinesize = 512; +module_param(mpeglinesize, int, 0644); +MODULE_PARM_DESC(mpeglinesize, + "number of bytes in each line of an MPEG buffer, range 512-1024"); + +static unsigned int v4l_debug; +module_param(v4l_debug, int, 0644); +MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages"); + +#define dprintk(level, fmt, arg...)\ + do { if (v4l_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, \ + (dev) ? dev->name : "cx23885[?]", ## arg); \ + } while (0) + +static struct cx23885_tvnorm cx23885_tvnorms[] = { + { + .name = "NTSC-M", + .id = V4L2_STD_NTSC_M, + }, { + .name = "NTSC-JP", + .id = V4L2_STD_NTSC_M_JP, + }, { + .name = "PAL-BG", + .id = V4L2_STD_PAL_BG, + }, { + .name = "PAL-DK", + .id = V4L2_STD_PAL_DK, + }, { + .name = "PAL-I", + .id = V4L2_STD_PAL_I, + }, { + .name = "PAL-M", + .id = V4L2_STD_PAL_M, + }, { + .name = "PAL-N", + .id = V4L2_STD_PAL_N, + }, { + .name = "PAL-Nc", + .id = V4L2_STD_PAL_Nc, + }, { + .name = "PAL-60", + .id = V4L2_STD_PAL_60, + }, { + .name = "SECAM-L", + .id = V4L2_STD_SECAM_L, + }, { + .name = "SECAM-DK", + .id = V4L2_STD_SECAM_DK, + } +}; + +/* ------------------------------------------------------------------ */ +enum cx23885_capture_type { + CX23885_MPEG_CAPTURE, + CX23885_RAW_CAPTURE, + CX23885_RAW_PASSTHRU_CAPTURE +}; +enum cx23885_capture_bits { + CX23885_RAW_BITS_NONE = 0x00, + CX23885_RAW_BITS_YUV_CAPTURE = 0x01, + CX23885_RAW_BITS_PCM_CAPTURE = 0x02, + CX23885_RAW_BITS_VBI_CAPTURE = 0x04, + CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08, + CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10 +}; +enum cx23885_capture_end { + CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */ + CX23885_END_NOW, /* stop immediately, no irq */ +}; +enum cx23885_framerate { + CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */ + CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */ +}; +enum cx23885_stream_port { + CX23885_OUTPUT_PORT_MEMORY, + CX23885_OUTPUT_PORT_STREAMING, + CX23885_OUTPUT_PORT_SERIAL +}; +enum cx23885_data_xfer_status { + CX23885_MORE_BUFFERS_FOLLOW, + CX23885_LAST_BUFFER, +}; +enum cx23885_picture_mask { + CX23885_PICTURE_MASK_NONE, + CX23885_PICTURE_MASK_I_FRAMES, + CX23885_PICTURE_MASK_I_P_FRAMES = 0x3, + CX23885_PICTURE_MASK_ALL_FRAMES = 0x7, +}; +enum cx23885_vbi_mode_bits { + CX23885_VBI_BITS_SLICED, + CX23885_VBI_BITS_RAW, +}; +enum cx23885_vbi_insertion_bits { + CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, + CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, + CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1, + CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, + CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, +}; +enum cx23885_dma_unit { + CX23885_DMA_BYTES, + CX23885_DMA_FRAMES, +}; +enum cx23885_dma_transfer_status_bits { + CX23885_DMA_TRANSFER_BITS_DONE = 0x01, + CX23885_DMA_TRANSFER_BITS_ERROR = 0x04, + CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10, +}; +enum cx23885_pause { + CX23885_PAUSE_ENCODING, + CX23885_RESUME_ENCODING, +}; +enum cx23885_copyright { + CX23885_COPYRIGHT_OFF, + CX23885_COPYRIGHT_ON, +}; +enum cx23885_notification_type { + CX23885_NOTIFICATION_REFRESH, +}; +enum cx23885_notification_status { + CX23885_NOTIFICATION_OFF, + CX23885_NOTIFICATION_ON, +}; +enum cx23885_notification_mailbox { + CX23885_NOTIFICATION_NO_MAILBOX = -1, +}; +enum cx23885_field1_lines { + CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */ + CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */ + CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */ +}; +enum cx23885_field2_lines { + CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */ + CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */ + CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */ +}; +enum cx23885_custom_data_type { + CX23885_CUSTOM_EXTENSION_USR_DATA, + CX23885_CUSTOM_PRIVATE_PACKET, +}; +enum cx23885_mute { + CX23885_UNMUTE, + CX23885_MUTE, +}; +enum cx23885_mute_video_mask { + CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00, + CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000, + CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000, +}; +enum cx23885_mute_video_shift { + CX23885_MUTE_VIDEO_V_SHIFT = 8, + CX23885_MUTE_VIDEO_U_SHIFT = 16, + CX23885_MUTE_VIDEO_Y_SHIFT = 24, +}; + +/* defines below are from ivtv-driver.h */ +#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF + +/* Firmware API commands */ +#define IVTV_API_STD_TIMEOUT 500 + +/* Registers */ +/* IVTV_REG_OFFSET */ +#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) +#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) +#define IVTV_REG_SPU (0x9050) +#define IVTV_REG_HW_BLOCKS (0x9054) +#define IVTV_REG_VPU (0x9058) +#define IVTV_REG_APU (0xA064) + +/**** Bit definitions for MC417_RWD and MC417_OEN registers *** + bits 31-16 ++-----------+ +| Reserved | ++-----------+ + bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 ++-------+-------+-------+-------+-------+-------+-------+-------+ +| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0| ++-------+-------+-------+-------+-------+-------+-------+-------+ + bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 ++-------+-------+-------+-------+-------+-------+-------+-------+ +|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0| ++-------+-------+-------+-------+-------+-------+-------+-------+ +***/ +#define MC417_MIWR 0x8000 +#define MC417_MIRD 0x4000 +#define MC417_MICS 0x2000 +#define MC417_MIRDY 0x1000 +#define MC417_MIADDR 0x0F00 +#define MC417_MIDATA 0x00FF + +/* MIADDR* nibble definitions */ +#define MCI_MEMORY_DATA_BYTE0 0x000 +#define MCI_MEMORY_DATA_BYTE1 0x100 +#define MCI_MEMORY_DATA_BYTE2 0x200 +#define MCI_MEMORY_DATA_BYTE3 0x300 +#define MCI_MEMORY_ADDRESS_BYTE2 0x400 +#define MCI_MEMORY_ADDRESS_BYTE1 0x500 +#define MCI_MEMORY_ADDRESS_BYTE0 0x600 +#define MCI_REGISTER_DATA_BYTE0 0x800 +#define MCI_REGISTER_DATA_BYTE1 0x900 +#define MCI_REGISTER_DATA_BYTE2 0xA00 +#define MCI_REGISTER_DATA_BYTE3 0xB00 +#define MCI_REGISTER_ADDRESS_BYTE0 0xC00 +#define MCI_REGISTER_ADDRESS_BYTE1 0xD00 +#define MCI_REGISTER_MODE 0xE00 + +/* Read and write modes */ +#define MCI_MODE_REGISTER_READ 0 +#define MCI_MODE_REGISTER_WRITE 1 +#define MCI_MODE_MEMORY_READ 0 +#define MCI_MODE_MEMORY_WRITE 0x40 + +/*** Bit definitions for MC417_CTL register **** + bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0 ++--------+-------------+--------+--------------+------------+ +|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN| ++--------+-------------+--------+--------------+------------+ +***/ +#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030) +#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006) +#define MC417_UART_GPIO_EN 0x00000001 + +/* Values for speed control */ +#define MC417_SPD_CTL_SLOW 0x1 +#define MC417_SPD_CTL_MEDIUM 0x0 +#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */ + +/* Values for GPIO select */ +#define MC417_GPIO_SEL_GPIO3 0x3 +#define MC417_GPIO_SEL_GPIO2 0x2 +#define MC417_GPIO_SEL_GPIO1 0x1 +#define MC417_GPIO_SEL_GPIO0 0x0 + +void cx23885_mc417_init(struct cx23885_dev *dev) +{ + u32 regval; + + dprintk(2, "%s()\n", __func__); + + /* Configure MC417_CTL register to defaults. */ + regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) | + MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) | + MC417_UART_GPIO_EN; + cx_write(MC417_CTL, regval); + + /* Configure MC417_OEN to defaults. */ + regval = MC417_MIRDY; + cx_write(MC417_OEN, regval); + + /* Configure MC417_RWD to defaults. */ + regval = MC417_MIWR | MC417_MIRD | MC417_MICS; + cx_write(MC417_RWD, regval); +} + +static int mc417_wait_ready(struct cx23885_dev *dev) +{ + u32 mi_ready; + unsigned long timeout = jiffies + msecs_to_jiffies(1); + + for (;;) { + mi_ready = cx_read(MC417_RWD) & MC417_MIRDY; + if (mi_ready != 0) + return 0; + if (time_after(jiffies, timeout)) + return -1; + udelay(1); + } +} + +int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value) +{ + u32 regval; + + /* Enable MC417 GPIO outputs except for MC417_MIRDY, + * which is an input. + */ + cx_write(MC417_OEN, MC417_MIRDY); + + /* Write data byte 0 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 | + (value & 0x000000FF); + cx_write(MC417_RWD, regval); + + /* Transition CS/WR to effect write transaction across bus. */ + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write data byte 1 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 | + ((value >> 8) & 0x000000FF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write data byte 2 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 | + ((value >> 16) & 0x000000FF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write data byte 3 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 | + ((value >> 24) & 0x000000FF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write address byte 0 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | + (address & 0xFF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write address byte 1 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | + ((address >> 8) & 0xFF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Indicate that this is a write. */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | + MCI_MODE_REGISTER_WRITE; + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Wait for the trans to complete (MC417_MIRDY asserted). */ + return mc417_wait_ready(dev); +} + +int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value) +{ + int retval; + u32 regval; + u32 tempval; + u32 dataval; + + /* Enable MC417 GPIO outputs except for MC417_MIRDY, + * which is an input. + */ + cx_write(MC417_OEN, MC417_MIRDY); + + /* Write address byte 0 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | + ((address & 0x00FF)); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write address byte 1 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | + ((address >> 8) & 0xFF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Indicate that this is a register read. */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | + MCI_MODE_REGISTER_READ; + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Wait for the trans to complete (MC417_MIRDY asserted). */ + retval = mc417_wait_ready(dev); + + /* switch the DAT0-7 GPIO[10:3] to input mode */ + cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA); + + /* Read data byte 0 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; + cx_write(MC417_RWD, regval); + + /* Transition RD to effect read transaction across bus. + * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)? + * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its + * input only...) + */ + regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; + cx_write(MC417_RWD, regval); + + /* Collect byte */ + tempval = cx_read(MC417_RWD); + dataval = tempval & 0x000000FF; + + /* Bring CS and RD high. */ + regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; + cx_write(MC417_RWD, regval); + + /* Read data byte 1 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; + cx_write(MC417_RWD, regval); + regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; + cx_write(MC417_RWD, regval); + tempval = cx_read(MC417_RWD); + dataval |= ((tempval & 0x000000FF) << 8); + regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; + cx_write(MC417_RWD, regval); + + /* Read data byte 2 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; + cx_write(MC417_RWD, regval); + regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; + cx_write(MC417_RWD, regval); + tempval = cx_read(MC417_RWD); + dataval |= ((tempval & 0x000000FF) << 16); + regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; + cx_write(MC417_RWD, regval); + + /* Read data byte 3 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3; + cx_write(MC417_RWD, regval); + regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3; + cx_write(MC417_RWD, regval); + tempval = cx_read(MC417_RWD); + dataval |= ((tempval & 0x000000FF) << 24); + regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; + cx_write(MC417_RWD, regval); + + *value = dataval; + + return retval; +} + +int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value) +{ + u32 regval; + + /* Enable MC417 GPIO outputs except for MC417_MIRDY, + * which is an input. + */ + cx_write(MC417_OEN, MC417_MIRDY); + + /* Write data byte 0 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 | + (value & 0x000000FF); + cx_write(MC417_RWD, regval); + + /* Transition CS/WR to effect write transaction across bus. */ + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write data byte 1 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 | + ((value >> 8) & 0x000000FF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write data byte 2 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 | + ((value >> 16) & 0x000000FF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write data byte 3 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 | + ((value >> 24) & 0x000000FF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write address byte 2 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 | + MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write address byte 1 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 | + ((address >> 8) & 0xFF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write address byte 0 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 | + (address & 0xFF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Wait for the trans to complete (MC417_MIRDY asserted). */ + return mc417_wait_ready(dev); +} + +int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value) +{ + int retval; + u32 regval; + u32 tempval; + u32 dataval; + + /* Enable MC417 GPIO outputs except for MC417_MIRDY, + * which is an input. + */ + cx_write(MC417_OEN, MC417_MIRDY); + + /* Write address byte 2 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 | + MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write address byte 1 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 | + ((address >> 8) & 0xFF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Write address byte 0 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 | + (address & 0xFF); + cx_write(MC417_RWD, regval); + regval |= MC417_MICS | MC417_MIWR; + cx_write(MC417_RWD, regval); + + /* Wait for the trans to complete (MC417_MIRDY asserted). */ + retval = mc417_wait_ready(dev); + + /* switch the DAT0-7 GPIO[10:3] to input mode */ + cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA); + + /* Read data byte 3 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3; + cx_write(MC417_RWD, regval); + + /* Transition RD to effect read transaction across bus. */ + regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3; + cx_write(MC417_RWD, regval); + + /* Collect byte */ + tempval = cx_read(MC417_RWD); + dataval = ((tempval & 0x000000FF) << 24); + + /* Bring CS and RD high. */ + regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; + cx_write(MC417_RWD, regval); + + /* Read data byte 2 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2; + cx_write(MC417_RWD, regval); + regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2; + cx_write(MC417_RWD, regval); + tempval = cx_read(MC417_RWD); + dataval |= ((tempval & 0x000000FF) << 16); + regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; + cx_write(MC417_RWD, regval); + + /* Read data byte 1 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1; + cx_write(MC417_RWD, regval); + regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1; + cx_write(MC417_RWD, regval); + tempval = cx_read(MC417_RWD); + dataval |= ((tempval & 0x000000FF) << 8); + regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; + cx_write(MC417_RWD, regval); + + /* Read data byte 0 */ + regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0; + cx_write(MC417_RWD, regval); + regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0; + cx_write(MC417_RWD, regval); + tempval = cx_read(MC417_RWD); + dataval |= (tempval & 0x000000FF); + regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; + cx_write(MC417_RWD, regval); + + *value = dataval; + + return retval; +} + +void mc417_gpio_set(struct cx23885_dev *dev, u32 mask) +{ + u32 val; + + /* Set the gpio value */ + mc417_register_read(dev, 0x900C, &val); + val |= (mask & 0x000ffff); + mc417_register_write(dev, 0x900C, val); +} + +void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask) +{ + u32 val; + + /* Clear the gpio value */ + mc417_register_read(dev, 0x900C, &val); + val &= ~(mask & 0x0000ffff); + mc417_register_write(dev, 0x900C, val); +} + +void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) +{ + u32 val; + + /* Enable GPIO direction bits */ + mc417_register_read(dev, 0x9020, &val); + if (asoutput) + val |= (mask & 0x0000ffff); + else + val &= ~(mask & 0x0000ffff); + + mc417_register_write(dev, 0x9020, val); +} +/* ------------------------------------------------------------------ */ + +/* MPEG encoder API */ +static char *cmd_to_str(int cmd) +{ + switch (cmd) { + case CX2341X_ENC_PING_FW: + return "PING_FW"; + case CX2341X_ENC_START_CAPTURE: + return "START_CAPTURE"; + case CX2341X_ENC_STOP_CAPTURE: + return "STOP_CAPTURE"; + case CX2341X_ENC_SET_AUDIO_ID: + return "SET_AUDIO_ID"; + case CX2341X_ENC_SET_VIDEO_ID: + return "SET_VIDEO_ID"; + case CX2341X_ENC_SET_PCR_ID: + return "SET_PCR_ID"; + case CX2341X_ENC_SET_FRAME_RATE: + return "SET_FRAME_RATE"; + case CX2341X_ENC_SET_FRAME_SIZE: + return "SET_FRAME_SIZE"; + case CX2341X_ENC_SET_BIT_RATE: + return "SET_BIT_RATE"; + case CX2341X_ENC_SET_GOP_PROPERTIES: + return "SET_GOP_PROPERTIES"; + case CX2341X_ENC_SET_ASPECT_RATIO: + return "SET_ASPECT_RATIO"; + case CX2341X_ENC_SET_DNR_FILTER_MODE: + return "SET_DNR_FILTER_MODE"; + case CX2341X_ENC_SET_DNR_FILTER_PROPS: + return "SET_DNR_FILTER_PROPS"; + case CX2341X_ENC_SET_CORING_LEVELS: + return "SET_CORING_LEVELS"; + case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: + return "SET_SPATIAL_FILTER_TYPE"; + case CX2341X_ENC_SET_VBI_LINE: + return "SET_VBI_LINE"; + case CX2341X_ENC_SET_STREAM_TYPE: + return "SET_STREAM_TYPE"; + case CX2341X_ENC_SET_OUTPUT_PORT: + return "SET_OUTPUT_PORT"; + case CX2341X_ENC_SET_AUDIO_PROPERTIES: + return "SET_AUDIO_PROPERTIES"; + case CX2341X_ENC_HALT_FW: + return "HALT_FW"; + case CX2341X_ENC_GET_VERSION: + return "GET_VERSION"; + case CX2341X_ENC_SET_GOP_CLOSURE: + return "SET_GOP_CLOSURE"; + case CX2341X_ENC_GET_SEQ_END: + return "GET_SEQ_END"; + case CX2341X_ENC_SET_PGM_INDEX_INFO: + return "SET_PGM_INDEX_INFO"; + case CX2341X_ENC_SET_VBI_CONFIG: + return "SET_VBI_CONFIG"; + case CX2341X_ENC_SET_DMA_BLOCK_SIZE: + return "SET_DMA_BLOCK_SIZE"; + case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10: + return "GET_PREV_DMA_INFO_MB_10"; + case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9: + return "GET_PREV_DMA_INFO_MB_9"; + case CX2341X_ENC_SCHED_DMA_TO_HOST: + return "SCHED_DMA_TO_HOST"; + case CX2341X_ENC_INITIALIZE_INPUT: + return "INITIALIZE_INPUT"; + case CX2341X_ENC_SET_FRAME_DROP_RATE: + return "SET_FRAME_DROP_RATE"; + case CX2341X_ENC_PAUSE_ENCODER: + return "PAUSE_ENCODER"; + case CX2341X_ENC_REFRESH_INPUT: + return "REFRESH_INPUT"; + case CX2341X_ENC_SET_COPYRIGHT: + return "SET_COPYRIGHT"; + case CX2341X_ENC_SET_EVENT_NOTIFICATION: + return "SET_EVENT_NOTIFICATION"; + case CX2341X_ENC_SET_NUM_VSYNC_LINES: + return "SET_NUM_VSYNC_LINES"; + case CX2341X_ENC_SET_PLACEHOLDER: + return "SET_PLACEHOLDER"; + case CX2341X_ENC_MUTE_VIDEO: + return "MUTE_VIDEO"; + case CX2341X_ENC_MUTE_AUDIO: + return "MUTE_AUDIO"; + case CX2341X_ENC_MISC: + return "MISC"; + default: + return "UNKNOWN"; + } +} + +static int cx23885_mbox_func(void *priv, + u32 command, + int in, + int out, + u32 data[CX2341X_MBOX_MAX_DATA]) +{ + struct cx23885_dev *dev = priv; + unsigned long timeout; + u32 value, flag, retval = 0; + int i; + + dprintk(3, "%s: command(0x%X) = %s\n", __func__, command, + cmd_to_str(command)); + + /* this may not be 100% safe if we can't read any memory location + without side effects */ + mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value); + if (value != 0x12345678) { + printk(KERN_ERR + "Firmware and/or mailbox pointer not initialized " + "or corrupted, signature = 0x%x, cmd = %s\n", value, + cmd_to_str(command)); + return -1; + } + + /* This read looks at 32 bits, but flag is only 8 bits. + * Seems we also bail if CMD or TIMEOUT bytes are set??? + */ + mc417_memory_read(dev, dev->cx23417_mailbox, &flag); + if (flag) { + printk(KERN_ERR "ERROR: Mailbox appears to be in use " + "(%x), cmd = %s\n", flag, cmd_to_str(command)); + return -1; + } + + flag |= 1; /* tell 'em we're working on it */ + mc417_memory_write(dev, dev->cx23417_mailbox, flag); + + /* write command + args + fill remaining with zeros */ + /* command code */ + mc417_memory_write(dev, dev->cx23417_mailbox + 1, command); + mc417_memory_write(dev, dev->cx23417_mailbox + 3, + IVTV_API_STD_TIMEOUT); /* timeout */ + for (i = 0; i < in; i++) { + mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]); + dprintk(3, "API Input %d = %d\n", i, data[i]); + } + for (; i < CX2341X_MBOX_MAX_DATA; i++) + mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0); + + flag |= 3; /* tell 'em we're done writing */ + mc417_memory_write(dev, dev->cx23417_mailbox, flag); + + /* wait for firmware to handle the API command */ + timeout = jiffies + msecs_to_jiffies(10); + for (;;) { + mc417_memory_read(dev, dev->cx23417_mailbox, &flag); + if (0 != (flag & 4)) + break; + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "ERROR: API Mailbox timeout\n"); + return -1; + } + udelay(10); + } + + /* read output values */ + for (i = 0; i < out; i++) { + mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i); + dprintk(3, "API Output %d = %d\n", i, data[i]); + } + + mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval); + dprintk(3, "API result = %d\n", retval); + + flag = 0; + mc417_memory_write(dev, dev->cx23417_mailbox, flag); + + return retval; +} + +/* We don't need to call the API often, so using just one + * mailbox will probably suffice + */ +static int cx23885_api_cmd(struct cx23885_dev *dev, + u32 command, + u32 inputcnt, + u32 outputcnt, + ...) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + va_list vargs; + int i, err; + + dprintk(3, "%s() cmds = 0x%08x\n", __func__, command); + + va_start(vargs, outputcnt); + for (i = 0; i < inputcnt; i++) + data[i] = va_arg(vargs, int); + + err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data); + for (i = 0; i < outputcnt; i++) { + int *vptr = va_arg(vargs, int *); + *vptr = data[i]; + } + va_end(vargs); + + return err; +} + +static int cx23885_find_mailbox(struct cx23885_dev *dev) +{ + u32 signature[4] = { + 0x12345678, 0x34567812, 0x56781234, 0x78123456 + }; + int signaturecnt = 0; + u32 value; + int i; + + dprintk(2, "%s()\n", __func__); + + for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) { + mc417_memory_read(dev, i, &value); + if (value == signature[signaturecnt]) + signaturecnt++; + else + signaturecnt = 0; + if (4 == signaturecnt) { + dprintk(1, "Mailbox signature found at 0x%x\n", i+1); + return i+1; + } + } + printk(KERN_ERR "Mailbox signature values not found!\n"); + return -1; +} + +static int cx23885_load_firmware(struct cx23885_dev *dev) +{ + static const unsigned char magic[8] = { + 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa + }; + const struct firmware *firmware; + int i, retval = 0; + u32 value = 0; + u32 gpio_output = 0; + u32 checksum = 0; + u32 *dataptr; + + dprintk(2, "%s()\n", __func__); + + /* Save GPIO settings before reset of APU */ + retval |= mc417_memory_read(dev, 0x9020, &gpio_output); + retval |= mc417_memory_read(dev, 0x900C, &value); + + retval = mc417_register_write(dev, + IVTV_REG_VPU, 0xFFFFFFED); + retval |= mc417_register_write(dev, + IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); + retval |= mc417_register_write(dev, + IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800); + retval |= mc417_register_write(dev, + IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); + retval |= mc417_register_write(dev, + IVTV_REG_APU, 0); + + if (retval != 0) { + printk(KERN_ERR "%s: Error with mc417_register_write\n", + __func__); + return -1; + } + + retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME, + &dev->pci->dev); + + if (retval != 0) { + printk(KERN_ERR + "ERROR: Hotplug firmware request failed (%s).\n", + CX23885_FIRM_IMAGE_NAME); + printk(KERN_ERR "Please fix your hotplug setup, the board will " + "not work without firmware loaded!\n"); + return -1; + } + + if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { + printk(KERN_ERR "ERROR: Firmware size mismatch " + "(have %zd, expected %d)\n", + firmware->size, CX23885_FIRM_IMAGE_SIZE); + release_firmware(firmware); + return -1; + } + + if (0 != memcmp(firmware->data, magic, 8)) { + printk(KERN_ERR + "ERROR: Firmware magic mismatch, wrong file?\n"); + release_firmware(firmware); + return -1; + } + + /* transfer to the chip */ + dprintk(2, "Loading firmware ...\n"); + dataptr = (u32 *)firmware->data; + for (i = 0; i < (firmware->size >> 2); i++) { + value = *dataptr; + checksum += ~value; + if (mc417_memory_write(dev, i, value) != 0) { + printk(KERN_ERR "ERROR: Loading firmware failed!\n"); + release_firmware(firmware); + return -1; + } + dataptr++; + } + + /* read back to verify with the checksum */ + dprintk(1, "Verifying firmware ...\n"); + for (i--; i >= 0; i--) { + if (mc417_memory_read(dev, i, &value) != 0) { + printk(KERN_ERR "ERROR: Reading firmware failed!\n"); + release_firmware(firmware); + return -1; + } + checksum -= ~value; + } + if (checksum) { + printk(KERN_ERR + "ERROR: Firmware load failed (checksum mismatch).\n"); + release_firmware(firmware); + return -1; + } + release_firmware(firmware); + dprintk(1, "Firmware upload successful.\n"); + + retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS, + IVTV_CMD_HW_BLOCKS_RST); + + /* F/W power up disturbs the GPIOs, restore state */ + retval |= mc417_register_write(dev, 0x9020, gpio_output); + retval |= mc417_register_write(dev, 0x900C, value); + + retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); + retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); + + if (retval < 0) + printk(KERN_ERR "%s: Error with mc417_register_write\n", + __func__); + return 0; +} + +void cx23885_417_check_encoder(struct cx23885_dev *dev) +{ + u32 status, seq; + + status = seq = 0; + cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq); + dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq); +} + +static void cx23885_codec_settings(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __func__); + + /* assign frame size */ + cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, + dev->ts1.height, dev->ts1.width); + + dev->mpeg_params.width = dev->ts1.width; + dev->mpeg_params.height = dev->ts1.height; + dev->mpeg_params.is_50hz = + (dev->encodernorm.id & V4L2_STD_625_50) != 0; + + cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params); + + cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); + cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); +} + +static int cx23885_initialize_codec(struct cx23885_dev *dev) +{ + int version; + int retval; + u32 i, data[7]; + + dprintk(1, "%s()\n", __func__); + + retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ + if (retval < 0) { + dprintk(2, "%s() PING OK\n", __func__); + retval = cx23885_load_firmware(dev); + if (retval < 0) { + printk(KERN_ERR "%s() f/w load failed\n", __func__); + return retval; + } + retval = cx23885_find_mailbox(dev); + if (retval < 0) { + printk(KERN_ERR "%s() mailbox < 0, error\n", + __func__); + return -1; + } + dev->cx23417_mailbox = retval; + retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); + if (retval < 0) { + printk(KERN_ERR + "ERROR: cx23417 firmware ping failed!\n"); + return -1; + } + retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, + &version); + if (retval < 0) { + printk(KERN_ERR "ERROR: cx23417 firmware get encoder :" + "version failed!\n"); + return -1; + } + dprintk(1, "cx23417 firmware version is 0x%08x\n", version); + msleep(200); + } + + cx23885_codec_settings(dev); + msleep(60); + + cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, + CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115); + cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, + CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0); + + /* Setup to capture VBI */ + data[0] = 0x0001BD00; + data[1] = 1; /* frames per interrupt */ + data[2] = 4; /* total bufs */ + data[3] = 0x91559155; /* start codes */ + data[4] = 0x206080C0; /* stop codes */ + data[5] = 6; /* lines */ + data[6] = 64; /* BPL */ + + cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1], + data[2], data[3], data[4], data[5], data[6]); + + for (i = 2; i <= 24; i++) { + int valid; + + valid = ((i >= 19) && (i <= 21)); + cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i, + valid, 0 , 0, 0); + cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, + i | 0x80000000, valid, 0, 0, 0); + } + + cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE); + msleep(60); + + /* initialize the video input */ + cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); + msleep(60); + + /* Enable VIP style pixel invalidation so we work with scaled mode */ + mc417_memory_write(dev, 2120, 0x00000080); + + /* start capturing to the host interface */ + cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, + CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); + msleep(10); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int bb_buf_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct cx23885_fh *fh = q->priv_data; + + fh->dev->ts1.ts_packet_size = mpeglinesize; + fh->dev->ts1.ts_packet_count = mpeglines; + + *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; + *count = mpegbufs; + + return 0; +} + +static int bb_buf_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) +{ + struct cx23885_fh *fh = q->priv_data; + return cx23885_buf_prepare(q, &fh->dev->ts1, + (struct cx23885_buffer *)vb, + field); +} + +static void bb_buf_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct cx23885_fh *fh = q->priv_data; + cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb); +} + +static void bb_buf_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + cx23885_free_buffer(q, (struct cx23885_buffer *)vb); +} + +static struct videobuf_queue_ops cx23885_qops = { + .buf_setup = bb_buf_setup, + .buf_prepare = bb_buf_prepare, + .buf_queue = bb_buf_queue, + .buf_release = bb_buf_release, +}; + +/* ------------------------------------------------------------------ */ + +static const u32 *ctrl_classes[] = { + cx2341x_mpeg_ctrls, + NULL +}; + +static int cx23885_queryctrl(struct cx23885_dev *dev, + struct v4l2_queryctrl *qctrl) +{ + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (qctrl->id == 0) + return -EINVAL; + + /* MPEG V4L2 controls */ + if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + + return 0; +} + +static int cx23885_querymenu(struct cx23885_dev *dev, + struct v4l2_querymenu *qmenu) +{ + struct v4l2_queryctrl qctrl; + + qctrl.id = qmenu->id; + cx23885_queryctrl(dev, &qctrl); + return v4l2_ctrl_query_menu(qmenu, &qctrl, + cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) + if (*id & cx23885_tvnorms[i].id) + break; + if (i == ARRAY_SIZE(cx23885_tvnorms)) + return -EINVAL; + dev->encodernorm = cx23885_tvnorms[i]; + return 0; +} + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_input *input; + int n; + + if (i->index >= 4) + return -EINVAL; + + input = &cx23885_boards[dev->board].input[i->index]; + + if (input->type == 0) + return -EINVAL; + + /* FIXME + * strcpy(i->name, input->name); */ + strcpy(i->name, "unset"); + + if (input->type == CX23885_VMUX_TELEVISION || + input->type == CX23885_VMUX_CABLE) + i->type = V4L2_INPUT_TYPE_TUNER; + else + i->type = V4L2_INPUT_TYPE_CAMERA; + + for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++) + i->std |= cx23885_tvnorms[n].id; + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + *i = dev->input; + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i >= 4) + return -EINVAL; + + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + if (UNSET == dev->tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + strcpy(t->name, "Television"); + call_all(dev, tuner, g_tuner, t); + + dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type); + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + if (UNSET == dev->tuner_type) + return -EINVAL; + + /* Update the A/V core */ + call_all(dev, tuner, s_tuner, t); + + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + if (UNSET == dev->tuner_type) + return -EINVAL; + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = dev->freq; + + call_all(dev, tuner, g_frequency, f); + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + CX23885_END_NOW, CX23885_MPEG_CAPTURE, + CX23885_RAW_BITS_NONE); + + dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n", + dev->tuner_type); + dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n", + f->tuner, f->type); + if (UNSET == dev->tuner_type) + return -EINVAL; + if (f->tuner != 0) + return -EINVAL; + if (f->type != V4L2_TUNER_ANALOG_TV) + return -EINVAL; + dev->freq = f->frequency; + + call_all(dev, tuner, s_frequency, f); + + cx23885_initialize_codec(dev); + + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + /* Update the A/V core */ + call_all(dev, core, s_ctrl, ctl); + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_tsport *tsport = &dev->ts1; + + strlcpy(cap->driver, dev->name, sizeof(cap->driver)); + strlcpy(cap->card, cx23885_boards[tsport->dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = CX23885_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + 0; + if (UNSET != dev->tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + strlcpy(f->description, "MPEG", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_MPEG; + + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = + dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; + f->fmt.pix.colorspace = 0; + f->fmt.pix.width = dev->ts1.width; + f->fmt.pix.height = dev->ts1.height; + f->fmt.pix.field = fh->mpegq.field; + dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", + dev->ts1.width, dev->ts1.height, fh->mpegq.field); + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = + dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; + f->fmt.pix.colorspace = 0; + dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", + dev->ts1.width, dev->ts1.height, fh->mpegq.field); + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = + dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; + f->fmt.pix.colorspace = 0; + dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", + f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); + return 0; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_reqbufs(&fh->mpegq, p); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_querybuf(&fh->mpegq, p); +} + +static int vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_qbuf(&fh->mpegq, p); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct cx23885_fh *fh = priv; + + return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK); +} + + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_streamon(&fh->mpegq); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_streamoff(&fh->mpegq); +} + +static int vidioc_g_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); +} + +static int vidioc_s_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + struct cx2341x_mpeg_params p; + int err; + + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + p = dev->mpeg_params; + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); + + if (err == 0) { + err = cx2341x_update(dev, cx23885_mbox_func, + &dev->mpeg_params, &p); + dev->mpeg_params = p; + } + return err; +} + +static int vidioc_try_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + struct cx2341x_mpeg_params p; + int err; + + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + p = dev->mpeg_params; + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); + return err; +} + +static int vidioc_log_status(struct file *file, void *priv) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + char name[32 + 2]; + + snprintf(name, sizeof(name), "%s/2", dev->name); + printk(KERN_INFO + "%s/2: ============ START LOG STATUS ============\n", + dev->name); + call_all(dev, core, log_status); + cx2341x_log_status(&dev->mpeg_params, name); + printk(KERN_INFO + "%s/2: ============= END LOG STATUS =============\n", + dev->name); + return 0; +} + +static int vidioc_querymenu(struct file *file, void *priv, + struct v4l2_querymenu *a) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + return cx23885_querymenu(dev, a); +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + return cx23885_queryctrl(dev, c); +} + +static int mpeg_open(struct file *file) +{ + struct cx23885_dev *dev = video_drvdata(file); + struct cx23885_fh *fh; + + dprintk(2, "%s()\n", __func__); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (!fh) + return -ENOMEM; + + file->private_data = fh; + fh->dev = dev; + + videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops, + &dev->pci->dev, &dev->ts1.slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct cx23885_buffer), + fh, NULL); + return 0; +} + +static int mpeg_release(struct file *file) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + dprintk(2, "%s()\n", __func__); + + /* FIXME: Review this crap */ + /* Shut device down on last close */ + if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { + if (atomic_dec_return(&dev->v4l_reader_count) == 0) { + /* stop mpeg capture */ + cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + CX23885_END_NOW, CX23885_MPEG_CAPTURE, + CX23885_RAW_BITS_NONE); + + msleep(500); + cx23885_417_check_encoder(dev); + + cx23885_cancel_buffers(&fh->dev->ts1); + } + } + + if (fh->mpegq.streaming) + videobuf_streamoff(&fh->mpegq); + if (fh->mpegq.reading) + videobuf_read_stop(&fh->mpegq); + + videobuf_mmap_free(&fh->mpegq); + file->private_data = NULL; + kfree(fh); + + return 0; +} + +static ssize_t mpeg_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + dprintk(2, "%s()\n", __func__); + + /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ + /* Start mpeg encoder on first read. */ + if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { + if (atomic_inc_return(&dev->v4l_reader_count) == 1) { + if (cx23885_initialize_codec(dev) < 0) + return -EINVAL; + } + } + + return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, + file->f_flags & O_NONBLOCK); +} + +static unsigned int mpeg_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + dprintk(2, "%s\n", __func__); + + return videobuf_poll_stream(file, &fh->mpegq, wait); +} + +static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + dprintk(2, "%s()\n", __func__); + + return videobuf_mmap_mapper(&fh->mpegq, vma); +} + +static struct v4l2_file_operations mpeg_fops = { + .owner = THIS_MODULE, + .open = mpeg_open, + .release = mpeg_release, + .read = mpeg_read, + .poll = mpeg_poll, + .mmap = mpeg_mmap, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, + .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, + .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, + .vidioc_log_status = vidioc_log_status, + .vidioc_querymenu = vidioc_querymenu, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_chip_ident = cx23885_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = cx23885_g_register, + .vidioc_s_register = cx23885_s_register, +#endif +}; + +static struct video_device cx23885_mpeg_template = { + .name = "cx23885", + .fops = &mpeg_fops, + .ioctl_ops = &mpeg_ioctl_ops, + .tvnorms = CX23885_NORMS, + .current_norm = V4L2_STD_NTSC_M, +}; + +void cx23885_417_unregister(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __func__); + + if (dev->v4l_device) { + if (video_is_registered(dev->v4l_device)) + video_unregister_device(dev->v4l_device); + else + video_device_release(dev->v4l_device); + dev->v4l_device = NULL; + } +} + +static struct video_device *cx23885_video_dev_alloc( + struct cx23885_tsport *tsport, + struct pci_dev *pci, + struct video_device *template, + char *type) +{ + struct video_device *vfd; + struct cx23885_dev *dev = tsport->dev; + + dprintk(1, "%s()\n", __func__); + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, + type, cx23885_boards[tsport->dev->board].name); + vfd->parent = &pci->dev; + vfd->release = video_device_release; + return vfd; +} + +int cx23885_417_register(struct cx23885_dev *dev) +{ + /* FIXME: Port1 hardcoded here */ + int err = -ENODEV; + struct cx23885_tsport *tsport = &dev->ts1; + + dprintk(1, "%s()\n", __func__); + + if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER) + return err; + + /* Set default TV standard */ + dev->encodernorm = cx23885_tvnorms[0]; + + if (dev->encodernorm.id & V4L2_STD_525_60) + tsport->height = 480; + else + tsport->height = 576; + + tsport->width = 720; + cx2341x_fill_defaults(&dev->mpeg_params); + + dev->mpeg_params.port = CX2341X_PORT_SERIAL; + + /* Allocate and initialize V4L video device */ + dev->v4l_device = cx23885_video_dev_alloc(tsport, + dev->pci, &cx23885_mpeg_template, "mpeg"); + video_set_drvdata(dev->v4l_device, dev); + err = video_register_device(dev->v4l_device, + VFL_TYPE_GRABBER, -1); + if (err < 0) { + printk(KERN_INFO "%s: can't register mpeg device\n", dev->name); + return err; + } + + printk(KERN_INFO "%s: registered device %s [mpeg]\n", + dev->name, video_device_node_name(dev->v4l_device)); + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-av.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-av.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-av.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-av.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * AV device support routines - non-input, non-vl42_subdev routines + * + * Copyright (C) 2010 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx23885.h" + +void cx23885_av_work_handler(struct work_struct *work) +{ + struct cx23885_dev *dev = + container_of(work, struct cx23885_dev, cx25840_work); + bool handled; + + v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine, + PCI_MSK_AV_CORE, &handled); + cx23885_irq_enable(dev, PCI_MSK_AV_CORE); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-av.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-av.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-av.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-av.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * AV device support routines - non-input, non-vl42_subdev routines + * + * Copyright (C) 2010 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef _CX23885_AV_H_ +#define _CX23885_AV_H_ +void cx23885_av_work_handler(struct work_struct *work); +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-cards.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1418 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" +#include "tuner-xc2028.h" +#include "netup-init.h" +#include "altera-ci.h" +#include "xc5000.h" +#include "cx23888-ir.h" + +static unsigned int enable_885_ir; +module_param(enable_885_ir, int, 0644); +MODULE_PARM_DESC(enable_885_ir, + "Enable integrated IR controller for supported\n" + "\t\t CX2388[57] boards that are wired for it:\n" + "\t\t\tHVR-1250 (reported safe)\n" + "\t\t\tTeVii S470 (reported unsafe)\n" + "\t\t This can cause an interrupt storm with some cards.\n" + "\t\t Default: 0 [Disabled]"); + +/* ------------------------------------------------------------------ */ +/* board config info */ + +struct cx23885_board cx23885_boards[] = { + [CX23885_BOARD_UNKNOWN] = { + .name = "UNKNOWN/GENERIC", + /* Ensure safe default for unknown boards */ + .clk_freq = 0, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 0, + }, { + .type = CX23885_VMUX_COMPOSITE2, + .vmux = 1, + }, { + .type = CX23885_VMUX_COMPOSITE3, + .vmux = 2, + }, { + .type = CX23885_VMUX_COMPOSITE4, + .vmux = 3, + } }, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { + .name = "Hauppauge WinTV-HVR1800lp", + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + }, { + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + } }, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1800] = { + .name = "Hauppauge WinTV-HVR1800", + .porta = CX23885_ANALOG_VIDEO, + .portb = CX23885_MPEG_ENCODER, + .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_PHILIPS_TDA8290, + .tuner_addr = 0x42, /* 0x84 >> 1 */ + .tuner_bus = 1, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .gpio0 = 0, + } }, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1250] = { + .name = "Hauppauge WinTV-HVR1250", + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + }, { + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + } }, + }, + [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { + .name = "DViCO FusionHDTV5 Express", + .portb = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = { + .name = "Hauppauge WinTV-HVR1500Q", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1500] = { + .name = "Hauppauge WinTV-HVR1500", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1200] = { + .name = "Hauppauge WinTV-HVR1200", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1700] = { + .name = "Hauppauge WinTV-HVR1700", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1400] = { + .name = "Hauppauge WinTV-HVR1400", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = { + .name = "DViCO FusionHDTV7 Dual Express", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = { + .name = "DViCO FusionHDTV DVB-T Dual Express", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = { + .name = "Leadtek Winfast PxDVR3200 H", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = { + .name = "Compro VideoMate E650F", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_TBS_6920] = { + .name = "TurboSight TBS 6920", + .portb = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_TEVII_S470] = { + .name = "TeVii S470", + .portb = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_DVBWORLD_2005] = { + .name = "DVBWorld DVB-S2 2005", + .portb = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = { + .ci_type = 1, + .name = "NetUP Dual DVB-S2 CI", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1270] = { + .name = "Hauppauge WinTV-HVR1270", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1275] = { + .name = "Hauppauge WinTV-HVR1275", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1255] = { + .name = "Hauppauge WinTV-HVR1255", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1210] = { + .name = "Hauppauge WinTV-HVR1210", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_MYGICA_X8506] = { + .name = "Mygica X8506 DMB-TH", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .tuner_bus = 1, + .porta = CX23885_ANALOG_VIDEO, + .portb = CX23885_MPEG_DVB, + .input = { + { + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_COMPOSITE2, + }, + { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE8, + }, + { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_SVIDEO_LUMA3 | + CX25840_SVIDEO_CHROMA4, + }, + { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_COMPONENT_ON | + CX25840_VIN1_CH1 | + CX25840_VIN6_CH2 | + CX25840_VIN7_CH3, + }, + }, + }, + [CX23885_BOARD_MAGICPRO_PROHDTVE2] = { + .name = "Magic-Pro ProHDTV Extreme 2", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .tuner_bus = 1, + .porta = CX23885_ANALOG_VIDEO, + .portb = CX23885_MPEG_DVB, + .input = { + { + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_COMPOSITE2, + }, + { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE8, + }, + { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_SVIDEO_LUMA3 | + CX25840_SVIDEO_CHROMA4, + }, + { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_COMPONENT_ON | + CX25840_VIN1_CH1 | + CX25840_VIN6_CH2 | + CX25840_VIN7_CH3, + }, + }, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1850] = { + .name = "Hauppauge WinTV-HVR1850", + .portb = CX23885_MPEG_ENCODER, + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_COMPRO_VIDEOMATE_E800] = { + .name = "Compro VideoMate E800", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1290] = { + .name = "Hauppauge WinTV-HVR1290", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_MYGICA_X8558PRO] = { + .name = "Mygica X8558 PRO DMB-TH", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_LEADTEK_WINFAST_PXTV1200] = { + .name = "LEADTEK WinFast PxTV1200", + .porta = CX23885_ANALOG_VIDEO, + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .tuner_bus = 1, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN2_CH1 | + CX25840_VIN5_CH2 | + CX25840_NONE0_CH3, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE1, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_SVIDEO_LUMA3 | + CX25840_SVIDEO_CHROMA4, + }, { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_VIN7_CH1 | + CX25840_VIN6_CH2 | + CX25840_VIN8_CH3 | + CX25840_COMPONENT_ON, + } }, + }, + [CX23885_BOARD_GOTVIEW_X5_3D_HYBRID] = { + .name = "GoTView X5 3D Hybrid", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x64, + .tuner_bus = 1, + .porta = CX23885_ANALOG_VIDEO, + .portb = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN2_CH1 | + CX25840_VIN5_CH2, + .gpio0 = 0x02, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX23885_VMUX_COMPOSITE1, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_SVIDEO_LUMA3 | + CX25840_SVIDEO_CHROMA4, + } }, + }, + [CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF] = { + .ci_type = 2, + .name = "NetUP Dual DVB-T/C-CI RF", + .porta = CX23885_ANALOG_VIDEO, + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + .num_fds_portb = 2, + .num_fds_portc = 2, + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x64, + .input = { { + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_COMPOSITE1, + } }, + }, +}; +const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); + +/* ------------------------------------------------------------------ */ +/* PCI subsystem IDs */ + +struct cx23885_subid cx23885_subids[] = { + { + .subvendor = 0x0070, + .subdevice = 0x3400, + .card = CX23885_BOARD_UNKNOWN, + }, { + .subvendor = 0x0070, + .subdevice = 0x7600, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp, + }, { + .subvendor = 0x0070, + .subdevice = 0x7800, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + }, { + .subvendor = 0x0070, + .subdevice = 0x7801, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + }, { + .subvendor = 0x0070, + .subdevice = 0x7809, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + }, { + .subvendor = 0x0070, + .subdevice = 0x7911, + .card = CX23885_BOARD_HAUPPAUGE_HVR1250, + }, { + .subvendor = 0x18ac, + .subdevice = 0xd500, + .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, + }, { + .subvendor = 0x0070, + .subdevice = 0x7790, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, + }, { + .subvendor = 0x0070, + .subdevice = 0x7797, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, + }, { + .subvendor = 0x0070, + .subdevice = 0x7710, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500, + }, { + .subvendor = 0x0070, + .subdevice = 0x7717, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500, + }, { + .subvendor = 0x0070, + .subdevice = 0x71d1, + .card = CX23885_BOARD_HAUPPAUGE_HVR1200, + }, { + .subvendor = 0x0070, + .subdevice = 0x71d3, + .card = CX23885_BOARD_HAUPPAUGE_HVR1200, + }, { + .subvendor = 0x0070, + .subdevice = 0x8101, + .card = CX23885_BOARD_HAUPPAUGE_HVR1700, + }, { + .subvendor = 0x0070, + .subdevice = 0x8010, + .card = CX23885_BOARD_HAUPPAUGE_HVR1400, + }, { + .subvendor = 0x18ac, + .subdevice = 0xd618, + .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP, + }, { + .subvendor = 0x18ac, + .subdevice = 0xdb78, + .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP, + }, { + .subvendor = 0x107d, + .subdevice = 0x6681, + .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H, + }, { + .subvendor = 0x185b, + .subdevice = 0xe800, + .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F, + }, { + .subvendor = 0x6920, + .subdevice = 0x8888, + .card = CX23885_BOARD_TBS_6920, + }, { + .subvendor = 0xd470, + .subdevice = 0x9022, + .card = CX23885_BOARD_TEVII_S470, + }, { + .subvendor = 0x0001, + .subdevice = 0x2005, + .card = CX23885_BOARD_DVBWORLD_2005, + }, { + .subvendor = 0x1b55, + .subdevice = 0x2a2c, + .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI, + }, { + .subvendor = 0x0070, + .subdevice = 0x2211, + .card = CX23885_BOARD_HAUPPAUGE_HVR1270, + }, { + .subvendor = 0x0070, + .subdevice = 0x2215, + .card = CX23885_BOARD_HAUPPAUGE_HVR1275, + }, { + .subvendor = 0x0070, + .subdevice = 0x221d, + .card = CX23885_BOARD_HAUPPAUGE_HVR1275, + }, { + .subvendor = 0x0070, + .subdevice = 0x2251, + .card = CX23885_BOARD_HAUPPAUGE_HVR1255, + }, { + .subvendor = 0x0070, + .subdevice = 0x2259, + .card = CX23885_BOARD_HAUPPAUGE_HVR1255, + }, { + .subvendor = 0x0070, + .subdevice = 0x2291, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { + .subvendor = 0x0070, + .subdevice = 0x2295, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { + .subvendor = 0x0070, + .subdevice = 0x2299, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { + .subvendor = 0x0070, + .subdevice = 0x229d, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ + }, { + .subvendor = 0x0070, + .subdevice = 0x22f0, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { + .subvendor = 0x0070, + .subdevice = 0x22f1, + .card = CX23885_BOARD_HAUPPAUGE_HVR1255, + }, { + .subvendor = 0x0070, + .subdevice = 0x22f2, + .card = CX23885_BOARD_HAUPPAUGE_HVR1275, + }, { + .subvendor = 0x0070, + .subdevice = 0x22f3, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ + }, { + .subvendor = 0x0070, + .subdevice = 0x22f4, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { + .subvendor = 0x0070, + .subdevice = 0x22f5, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ + }, { + .subvendor = 0x14f1, + .subdevice = 0x8651, + .card = CX23885_BOARD_MYGICA_X8506, + }, { + .subvendor = 0x14f1, + .subdevice = 0x8657, + .card = CX23885_BOARD_MAGICPRO_PROHDTVE2, + }, { + .subvendor = 0x0070, + .subdevice = 0x8541, + .card = CX23885_BOARD_HAUPPAUGE_HVR1850, + }, { + .subvendor = 0x1858, + .subdevice = 0xe800, + .card = CX23885_BOARD_COMPRO_VIDEOMATE_E800, + }, { + .subvendor = 0x0070, + .subdevice = 0x8551, + .card = CX23885_BOARD_HAUPPAUGE_HVR1290, + }, { + .subvendor = 0x14f1, + .subdevice = 0x8578, + .card = CX23885_BOARD_MYGICA_X8558PRO, + }, { + .subvendor = 0x107d, + .subdevice = 0x6f22, + .card = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200, + }, { + .subvendor = 0x5654, + .subdevice = 0x2390, + .card = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID, + }, { + .subvendor = 0x1b55, + .subdevice = 0xe2e4, + .card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF, + }, +}; +const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); + +void cx23885_card_list(struct cx23885_dev *dev) +{ + int i; + + if (0 == dev->pci->subsystem_vendor && + 0 == dev->pci->subsystem_device) { + printk(KERN_INFO + "%s: Board has no valid PCIe Subsystem ID and can't\n" + "%s: be autodetected. Pass card= insmod option\n" + "%s: to workaround that. Redirect complaints to the\n" + "%s: vendor of the TV card. Best regards,\n" + "%s: -- tux\n", + dev->name, dev->name, dev->name, dev->name, dev->name); + } else { + printk(KERN_INFO + "%s: Your board isn't known (yet) to the driver.\n" + "%s: Try to pick one of the existing card configs via\n" + "%s: card= insmod option. Updating to the latest\n" + "%s: version might help as well.\n", + dev->name, dev->name, dev->name, dev->name); + } + printk(KERN_INFO "%s: Here is a list of valid choices for the card= insmod option:\n", + dev->name); + for (i = 0; i < cx23885_bcount; i++) + printk(KERN_INFO "%s: card=%d -> %s\n", + dev->name, i, cx23885_boards[i].name); +} + +static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, + eeprom_data); + + /* Make sure we support the board model */ + switch (tv.model) { + case 22001: + /* WinTV-HVR1270 (PCIe, Retail, half height) + * ATSC/QAM and basic analog, IR Blast */ + case 22009: + /* WinTV-HVR1210 (PCIe, Retail, half height) + * DVB-T and basic analog, IR Blast */ + case 22011: + /* WinTV-HVR1270 (PCIe, Retail, half height) + * ATSC/QAM and basic analog, IR Recv */ + case 22019: + /* WinTV-HVR1210 (PCIe, Retail, half height) + * DVB-T and basic analog, IR Recv */ + case 22021: + /* WinTV-HVR1275 (PCIe, Retail, half height) + * ATSC/QAM and basic analog, IR Recv */ + case 22029: + /* WinTV-HVR1210 (PCIe, Retail, half height) + * DVB-T and basic analog, IR Recv */ + case 22101: + /* WinTV-HVR1270 (PCIe, Retail, full height) + * ATSC/QAM and basic analog, IR Blast */ + case 22109: + /* WinTV-HVR1210 (PCIe, Retail, full height) + * DVB-T and basic analog, IR Blast */ + case 22111: + /* WinTV-HVR1270 (PCIe, Retail, full height) + * ATSC/QAM and basic analog, IR Recv */ + case 22119: + /* WinTV-HVR1210 (PCIe, Retail, full height) + * DVB-T and basic analog, IR Recv */ + case 22121: + /* WinTV-HVR1275 (PCIe, Retail, full height) + * ATSC/QAM and basic analog, IR Recv */ + case 22129: + /* WinTV-HVR1210 (PCIe, Retail, full height) + * DVB-T and basic analog, IR Recv */ + case 71009: + /* WinTV-HVR1200 (PCIe, Retail, full height) + * DVB-T and basic analog */ + case 71359: + /* WinTV-HVR1200 (PCIe, OEM, half height) + * DVB-T and basic analog */ + case 71439: + /* WinTV-HVR1200 (PCIe, OEM, half height) + * DVB-T and basic analog */ + case 71449: + /* WinTV-HVR1200 (PCIe, OEM, full height) + * DVB-T and basic analog */ + case 71939: + /* WinTV-HVR1200 (PCIe, OEM, half height) + * DVB-T and basic analog */ + case 71949: + /* WinTV-HVR1200 (PCIe, OEM, full height) + * DVB-T and basic analog */ + case 71959: + /* WinTV-HVR1200 (PCIe, OEM, full height) + * DVB-T and basic analog */ + case 71979: + /* WinTV-HVR1200 (PCIe, OEM, half height) + * DVB-T and basic analog */ + case 71999: + /* WinTV-HVR1200 (PCIe, OEM, full height) + * DVB-T and basic analog */ + case 76601: + /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual + channel ATSC and MPEG2 HW Encoder */ + case 77001: + /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC + and Basic analog */ + case 77011: + /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC + and Basic analog */ + case 77041: + /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM + and Basic analog */ + case 77051: + /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM + and Basic analog */ + case 78011: + /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, + Dual channel ATSC and MPEG2 HW Encoder */ + case 78501: + /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, + Dual channel ATSC and MPEG2 HW Encoder */ + case 78521: + /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, + Dual channel ATSC and MPEG2 HW Encoder */ + case 78531: + /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, + Dual channel ATSC and MPEG2 HW Encoder */ + case 78631: + /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, + Dual channel ATSC and MPEG2 HW Encoder */ + case 79001: + /* WinTV-HVR1250 (PCIe, Retail, IR, full height, + ATSC and Basic analog */ + case 79101: + /* WinTV-HVR1250 (PCIe, Retail, IR, half height, + ATSC and Basic analog */ + case 79501: + /* WinTV-HVR1250 (PCIe, No IR, half height, + ATSC [at least] and Basic analog) */ + case 79561: + /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, + ATSC and Basic analog */ + case 79571: + /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, + ATSC and Basic analog */ + case 79671: + /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, + ATSC and Basic analog */ + case 80019: + /* WinTV-HVR1400 (Express Card, Retail, IR, + * DVB-T and Basic analog */ + case 81509: + /* WinTV-HVR1700 (PCIe, OEM, No IR, half height) + * DVB-T and MPEG2 HW Encoder */ + case 81519: + /* WinTV-HVR1700 (PCIe, OEM, No IR, full height) + * DVB-T and MPEG2 HW Encoder */ + break; + case 85021: + /* WinTV-HVR1850 (PCIe, Retail, 3.5mm in, IR, FM, + Dual channel ATSC and MPEG2 HW Encoder */ + break; + case 85721: + /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR, + Dual channel ATSC and Basic analog */ + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", + dev->name, tv.model); + break; + } + + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + dev->name, tv.model); +} + +int cx23885_tuner_callback(void *priv, int component, int command, int arg) +{ + struct cx23885_tsport *port = priv; + struct cx23885_dev *dev = port->dev; + u32 bitmask = 0; + + if (command == XC2028_RESET_CLK) + return 0; + + if (command != 0) { + printk(KERN_ERR "%s(): Unknown command 0x%x.\n", + __func__, command); + return -EINVAL; + } + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1400: + case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: + case CX23885_BOARD_COMPRO_VIDEOMATE_E800: + case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: + /* Tuner Reset Command */ + bitmask = 0x04; + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: + /* Two identical tuners on two different i2c buses, + * we need to reset the correct gpio. */ + if (port->nr == 1) + bitmask = 0x01; + else if (port->nr == 2) + bitmask = 0x04; + break; + case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: + /* Tuner Reset Command */ + bitmask = 0x02; + break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + altera_ci_tuner_reset(dev, port->nr); + break; + } + + if (bitmask) { + /* Drive the tuner into reset and back out */ + cx_clear(GP0_IO, bitmask); + mdelay(200); + cx_set(GP0_IO, bitmask); + } + + return 0; +} + +void cx23885_gpio_setup(struct cx23885_dev *dev) +{ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* GPIO-0 cx24227 demodulator reset */ + cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ + break; + case CX23885_BOARD_HAUPPAUGE_HVR1500: + /* GPIO-0 cx24227 demodulator */ + /* GPIO-2 xc3028 tuner */ + + /* Put the parts into reset */ + cx_set(GP0_IO, 0x00050000); + cx_clear(GP0_IO, 0x00000005); + msleep(5); + + /* Bring the parts out of reset */ + cx_set(GP0_IO, 0x00050005); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + /* GPIO-0 cx24227 demodulator reset */ + /* GPIO-2 xc5000 tuner reset */ + cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */ + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* GPIO-0 656_CLK */ + /* GPIO-1 656_D0 */ + /* GPIO-2 8295A Reset */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + /* GPIO-19 IR_RX */ + + /* CX23417 GPIO's */ + /* EIO15 Zilog Reset */ + /* EIO14 S5H1409/CX24227 Reset */ + mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1); + + /* Put the demod into reset and protect the eeprom */ + mc417_gpio_clear(dev, GPIO_15 | GPIO_14); + mdelay(100); + + /* Bring the demod and blaster out of reset */ + mc417_gpio_set(dev, GPIO_15 | GPIO_14); + mdelay(100); + + /* Force the TDA8295A into reset and back */ + cx23885_gpio_enable(dev, GPIO_2, 1); + cx23885_gpio_set(dev, GPIO_2); + mdelay(20); + cx23885_gpio_clear(dev, GPIO_2); + mdelay(20); + cx23885_gpio_set(dev, GPIO_2); + mdelay(20); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1200: + /* GPIO-0 tda10048 demodulator reset */ + /* GPIO-2 tda18271 tuner reset */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x00050000); + mdelay(20); + cx_clear(GP0_IO, 0x00000005); + mdelay(20); + cx_set(GP0_IO, 0x00050005); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1700: + /* GPIO-0 TDA10048 demodulator reset */ + /* GPIO-2 TDA8295A Reset */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + + /* The following GPIO's are on the interna AVCore (cx25840) */ + /* GPIO-19 IR_RX */ + /* GPIO-20 IR_TX 416/DVBT Select */ + /* GPIO-21 IIS DAT */ + /* GPIO-22 IIS WCLK */ + /* GPIO-23 IIS BCLK */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x00050000); + mdelay(20); + cx_clear(GP0_IO, 0x00000005); + mdelay(20); + cx_set(GP0_IO, 0x00050005); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1400: + /* GPIO-0 Dibcom7000p demodulator reset */ + /* GPIO-2 xc3028L tuner reset */ + /* GPIO-13 LED */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x00050000); + mdelay(20); + cx_clear(GP0_IO, 0x00000005); + mdelay(20); + cx_set(GP0_IO, 0x00050005); + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + /* GPIO-0 xc5000 tuner reset i2c bus 0 */ + /* GPIO-1 s5h1409 demod reset i2c bus 0 */ + /* GPIO-2 xc5000 tuner reset i2c bus 1 */ + /* GPIO-3 s5h1409 demod reset i2c bus 0 */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x000f0000); + mdelay(20); + cx_clear(GP0_IO, 0x0000000f); + mdelay(20); + cx_set(GP0_IO, 0x000f000f); + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: + /* GPIO-0 portb xc3028 reset */ + /* GPIO-1 portb zl10353 reset */ + /* GPIO-2 portc xc3028 reset */ + /* GPIO-3 portc zl10353 reset */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x000f0000); + mdelay(20); + cx_clear(GP0_IO, 0x0000000f); + mdelay(20); + cx_set(GP0_IO, 0x000f000f); + break; + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: + case CX23885_BOARD_COMPRO_VIDEOMATE_E800: + case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: + /* GPIO-2 xc3028 tuner reset */ + + /* The following GPIO's are on the internal AVCore (cx25840) */ + /* GPIO-? zl10353 demod reset */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x00040000); + mdelay(20); + cx_clear(GP0_IO, 0x00000004); + mdelay(20); + cx_set(GP0_IO, 0x00040004); + break; + case CX23885_BOARD_TBS_6920: + cx_write(MC417_CTL, 0x00000036); + cx_write(MC417_OEN, 0x00001000); + cx_set(MC417_RWD, 0x00000002); + mdelay(200); + cx_clear(MC417_RWD, 0x00000800); + mdelay(200); + cx_set(MC417_RWD, 0x00000800); + mdelay(200); + break; + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: + /* GPIO-0 INTA from CiMax1 + GPIO-1 INTB from CiMax2 + GPIO-2 reset chips + GPIO-3 to GPIO-10 data/addr for CA + GPIO-11 ~CS0 to CiMax1 + GPIO-12 ~CS1 to CiMax2 + GPIO-13 ADL0 load LSB addr + GPIO-14 ADL1 load MSB addr + GPIO-15 ~RDY from CiMax + GPIO-17 ~RD to CiMax + GPIO-18 ~WR to CiMax + */ + cx_set(GP0_IO, 0x00040000); /* GPIO as out */ + /* GPIO1 and GPIO2 as INTA and INTB from CiMaxes, reset low */ + cx_clear(GP0_IO, 0x00030004); + mdelay(100);/* reset delay */ + cx_set(GP0_IO, 0x00040004); /* GPIO as out, reset high */ + cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */ + /* GPIO-15 IN as ~ACK, rest as OUT */ + cx_write(MC417_OEN, 0x00001000); + /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */ + cx_write(MC417_RWD, 0x0000c300); + /* enable irq */ + cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ + break; + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: + /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */ + /* GPIO-6 I2C Gate which can isolate the demod from the bus */ + /* GPIO-9 Demod reset */ + + /* Put the parts into reset and back */ + cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1); + cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5); + cx23885_gpio_clear(dev, GPIO_9); + mdelay(20); + cx23885_gpio_set(dev, GPIO_9); + break; + case CX23885_BOARD_MYGICA_X8506: + case CX23885_BOARD_MAGICPRO_PROHDTVE2: + /* GPIO-0 (0)Analog / (1)Digital TV */ + /* GPIO-1 reset XC5000 */ + /* GPIO-2 reset LGS8GL5 / LGS8G75 */ + cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1); + cx23885_gpio_clear(dev, GPIO_1 | GPIO_2); + mdelay(100); + cx23885_gpio_set(dev, GPIO_0 | GPIO_1 | GPIO_2); + mdelay(100); + break; + case CX23885_BOARD_MYGICA_X8558PRO: + /* GPIO-0 reset first ATBM8830 */ + /* GPIO-1 reset second ATBM8830 */ + cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1); + cx23885_gpio_clear(dev, GPIO_0 | GPIO_1); + mdelay(100); + cx23885_gpio_set(dev, GPIO_0 | GPIO_1); + mdelay(100); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + /* GPIO-0 656_CLK */ + /* GPIO-1 656_D0 */ + /* GPIO-2 Wake# */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + /* GPIO-19 IR_RX */ + /* GPIO-20 C_IR_TX */ + /* GPIO-21 I2S DAT */ + /* GPIO-22 I2S WCLK */ + /* GPIO-23 I2S BCLK */ + /* ALT GPIO: EXP GPIO LATCH */ + + /* CX23417 GPIO's */ + /* GPIO-14 S5H1411/CX24228 Reset */ + /* GPIO-13 EEPROM write protect */ + mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1); + + /* Put the demod into reset and protect the eeprom */ + mc417_gpio_clear(dev, GPIO_14 | GPIO_13); + mdelay(100); + + /* Bring the demod out of reset */ + mc417_gpio_set(dev, GPIO_14); + mdelay(100); + + /* CX24228 GPIO */ + /* Connected to IF / Mux */ + break; + case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: + cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ + break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + /* GPIO-0 ~INT in + GPIO-1 TMS out + GPIO-2 ~reset chips out + GPIO-3 to GPIO-10 data/addr for CA in/out + GPIO-11 ~CS out + GPIO-12 ADDR out + GPIO-13 ~WR out + GPIO-14 ~RD out + GPIO-15 ~RDY in + GPIO-16 TCK out + GPIO-17 TDO in + GPIO-18 TDI out + */ + cx_set(GP0_IO, 0x00060000); /* GPIO-1,2 as out */ + /* GPIO-0 as INT, reset & TMS low */ + cx_clear(GP0_IO, 0x00010006); + mdelay(100);/* reset delay */ + cx_set(GP0_IO, 0x00000004); /* reset high */ + cx_write(MC417_CTL, 0x00000037);/* enable GPIO-3..18 pins */ + /* GPIO-17 is TDO in, GPIO-15 is ~RDY in, rest is out */ + cx_write(MC417_OEN, 0x00005000); + /* ~RD, ~WR high; ADDR low; ~CS high */ + cx_write(MC417_RWD, 0x00000d00); + /* enable irq */ + cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ + break; + } +} + +int cx23885_ir_init(struct cx23885_dev *dev) +{ + static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = { + { + .flags = V4L2_SUBDEV_IO_PIN_INPUT, + .pin = CX23885_PIN_IR_RX_GPIO19, + .function = CX23885_PAD_IR_RX, + .value = 0, + .strength = CX25840_PIN_DRIVE_MEDIUM, + }, { + .flags = V4L2_SUBDEV_IO_PIN_OUTPUT, + .pin = CX23885_PIN_IR_TX_GPIO20, + .function = CX23885_PAD_IR_TX, + .value = 0, + .strength = CX25840_PIN_DRIVE_MEDIUM, + } + }; + const size_t ir_rxtx_pin_cfg_count = ARRAY_SIZE(ir_rxtx_pin_cfg); + + static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = { + { + .flags = V4L2_SUBDEV_IO_PIN_INPUT, + .pin = CX23885_PIN_IR_RX_GPIO19, + .function = CX23885_PAD_IR_RX, + .value = 0, + .strength = CX25840_PIN_DRIVE_MEDIUM, + } + }; + const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg); + + struct v4l2_subdev_ir_parameters params; + int ret = 0; + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1200: + case CX23885_BOARD_HAUPPAUGE_HVR1400: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: + /* FIXME: Implement me */ + break; + case CX23885_BOARD_HAUPPAUGE_HVR1270: + ret = cx23888_ir_probe(dev); + if (ret) + break; + dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); + v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, + ir_rx_pin_cfg_count, ir_rx_pin_cfg); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + ret = cx23888_ir_probe(dev); + if (ret) + break; + dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); + v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, + ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); + /* + * For these boards we need to invert the Tx output via the + * IR controller to have the LED off while idle + */ + v4l2_subdev_call(dev->sd_ir, ir, tx_g_parameters, ¶ms); + params.enable = false; + params.shutdown = false; + params.invert_level = true; + v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, ¶ms); + params.shutdown = true; + v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, ¶ms); + break; + case CX23885_BOARD_TEVII_S470: + if (!enable_885_ir) + break; + dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); + if (dev->sd_ir == NULL) { + ret = -ENODEV; + break; + } + v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, + ir_rx_pin_cfg_count, ir_rx_pin_cfg); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1250: + if (!enable_885_ir) + break; + dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); + if (dev->sd_ir == NULL) { + ret = -ENODEV; + break; + } + v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, + ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: + request_module("ir-kbd-i2c"); + break; + } + + return ret; +} + +void cx23885_ir_fini(struct cx23885_dev *dev) +{ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + cx23885_irq_remove(dev, PCI_MSK_IR); + cx23888_ir_remove(dev); + dev->sd_ir = NULL; + break; + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_HAUPPAUGE_HVR1250: + cx23885_irq_remove(dev, PCI_MSK_AV_CORE); + /* sd_ir is a duplicate pointer to the AV Core, just clear it */ + dev->sd_ir = NULL; + break; + } +} + +int netup_jtag_io(void *device, int tms, int tdi, int read_tdo) +{ + int data; + int tdo = 0; + struct cx23885_dev *dev = (struct cx23885_dev *)device; + /*TMS*/ + data = ((cx_read(GP0_IO)) & (~0x00000002)); + data |= (tms ? 0x00020002 : 0x00020000); + cx_write(GP0_IO, data); + + /*TDI*/ + data = ((cx_read(MC417_RWD)) & (~0x0000a000)); + data |= (tdi ? 0x00008000 : 0); + cx_write(MC417_RWD, data); + if (read_tdo) + tdo = (data & 0x00004000) ? 1 : 0; /*TDO*/ + + cx_write(MC417_RWD, data | 0x00002000); + udelay(1); + /*TCK*/ + cx_write(MC417_RWD, data); + + return tdo; +} + +void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) +{ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + if (dev->sd_ir) + cx23885_irq_add_enable(dev, PCI_MSK_IR); + break; + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_HAUPPAUGE_HVR1250: + if (dev->sd_ir) + cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE); + break; + } +} + +void cx23885_card_setup(struct cx23885_dev *dev) +{ + struct cx23885_tsport *ts1 = &dev->ts1; + struct cx23885_tsport *ts2 = &dev->ts2; + + static u8 eeprom[256]; + + if (dev->i2c_bus[0].i2c_rc == 0) { + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, + eeprom, sizeof(eeprom)); + } + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + if (dev->i2c_bus[0].i2c_rc == 0) { + if (eeprom[0x80] != 0x84) + hauppauge_eeprom(dev, eeprom+0xc0); + else + hauppauge_eeprom(dev, eeprom+0x80); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + case CX23885_BOARD_HAUPPAUGE_HVR1400: + if (dev->i2c_bus[0].i2c_rc == 0) + hauppauge_eeprom(dev, eeprom+0x80); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + case CX23885_BOARD_HAUPPAUGE_HVR1200: + case CX23885_BOARD_HAUPPAUGE_HVR1700: + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + if (dev->i2c_bus[0].i2c_rc == 0) + hauppauge_eeprom(dev, eeprom+0xc0); + break; + } + + switch (dev->board) { + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + /* break omitted intentionally */ + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* Defaults for VID B - Analog encoder */ + /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */ + ts1->gen_ctrl_val = 0x10e; + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + + /* APB_TSVALERR_POL (active low)*/ + ts1->vld_misc_val = 0x2000; + ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc); + + /* Defaults for VID C */ + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_TBS_6920: + ts1->gen_ctrl_val = 0x4; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_DVBWORLD_2005: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_MYGICA_X8506: + case CX23885_BOARD_MAGICPRO_PROHDTVE2: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_MYGICA_X8558PRO: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + case CX23885_BOARD_HAUPPAUGE_HVR1200: + case CX23885_BOARD_HAUPPAUGE_HVR1700: + case CX23885_BOARD_HAUPPAUGE_HVR1400: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_COMPRO_VIDEOMATE_E800: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: + default: + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + } + + /* Certain boards support analog, or require the avcore to be + * loaded, ensure this happens. + */ + switch (dev->board) { + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* Currently only enabled for the integrated IR controller */ + if (!enable_885_ir) + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + case CX23885_BOARD_HAUPPAUGE_HVR1700: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + case CX23885_BOARD_COMPRO_VIDEOMATE_E800: + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_MYGICA_X8506: + case CX23885_BOARD_MAGICPRO_PROHDTVE2: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: + case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: + dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_bus[2].i2c_adap, + "cx25840", 0x88 >> 1, NULL); + if (dev->sd_cx25840) { + dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; + v4l2_subdev_call(dev->sd_cx25840, core, load_fw); + } + break; + } + + /* AUX-PLL 27MHz CLK */ + switch (dev->board) { + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: + netup_initialize(dev); + break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { + int ret; + const struct firmware *fw; + const char *filename = "dvb-netup-altera-01.fw"; + char *action = "configure"; + struct altera_config netup_config = { + .dev = dev, + .action = action, + .jtag_io = netup_jtag_io, + }; + + netup_initialize(dev); + + ret = request_firmware(&fw, filename, &dev->pci->dev); + if (ret != 0) + printk(KERN_ERR "did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details " + "on firmware-problems.", filename); + else + altera_init(&netup_config, fw); + + release_firmware(fw); + break; + } + } +} + +/* ------------------------------------------------------------------ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-core.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,2174 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" +#include "cimax2.h" +#include "altera-ci.h" +#include "cx23888-ir.h" +#include "cx23885-ir.h" +#include "cx23885-av.h" +#include "cx23885-input.h" + +MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); +MODULE_AUTHOR("Steven Toth "); +MODULE_LICENSE("GPL"); + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); + +static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); + +#define dprintk(level, fmt, arg...)\ + do { if (debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) + +static unsigned int cx23885_devcount; + +#define NO_SYNC_LINE (-1U) + +/* FIXME, these allocations will change when + * analog arrives. The be reviewed. + * CX23887 Assumptions + * 1 line = 16 bytes of CDT + * cmds size = 80 + * cdt size = 16 * linesize + * iqsize = 64 + * maxlines = 6 + * + * Address Space: + * 0x00000000 0x00008fff FIFO clusters + * 0x00010000 0x000104af Channel Management Data Structures + * 0x000104b0 0x000104ff Free + * 0x00010500 0x000108bf 15 channels * iqsize + * 0x000108c0 0x000108ff Free + * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables + * 15 channels * (iqsize + (maxlines * linesize)) + * 0x00010ea0 0x00010xxx Free + */ + +static struct sram_channel cx23885_sram_channels[] = { + [SRAM_CH01] = { + .name = "VID A", + .cmds_start = 0x10000, + .ctrl_start = 0x10380, + .cdt = 0x104c0, + .fifo_start = 0x40, + .fifo_size = 0x2800, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "TS1 B", + .cmds_start = 0x100A0, + .ctrl_start = 0x10400, + .cdt = 0x10580, + .fifo_start = 0x5000, + .fifo_size = 0x1000, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10440, + .cdt = 0x105e0, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + +static struct sram_channel cx23887_sram_channels[] = { + [SRAM_CH01] = { + .name = "VID A", + .cmds_start = 0x10000, + .ctrl_start = 0x105b0, + .cdt = 0x107b0, + .fifo_start = 0x40, + .fifo_size = 0x2800, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "TS1 B", + .cmds_start = 0x100A0, + .ctrl_start = 0x10630, + .cdt = 0x10870, + .fifo_start = 0x5000, + .fifo_size = 0x1000, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10670, + .cdt = 0x108d0, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + +void cx23885_irq_add(struct cx23885_dev *dev, u32 mask) +{ + unsigned long flags; + spin_lock_irqsave(&dev->pci_irqmask_lock, flags); + + dev->pci_irqmask |= mask; + + spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); +} + +void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask) +{ + unsigned long flags; + spin_lock_irqsave(&dev->pci_irqmask_lock, flags); + + dev->pci_irqmask |= mask; + cx_set(PCI_INT_MSK, mask); + + spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); +} + +void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask) +{ + u32 v; + unsigned long flags; + spin_lock_irqsave(&dev->pci_irqmask_lock, flags); + + v = mask & dev->pci_irqmask; + if (v) + cx_set(PCI_INT_MSK, v); + + spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); +} + +static inline void cx23885_irq_enable_all(struct cx23885_dev *dev) +{ + cx23885_irq_enable(dev, 0xffffffff); +} + +void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask) +{ + unsigned long flags; + spin_lock_irqsave(&dev->pci_irqmask_lock, flags); + + cx_clear(PCI_INT_MSK, mask); + + spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); +} + +static inline void cx23885_irq_disable_all(struct cx23885_dev *dev) +{ + cx23885_irq_disable(dev, 0xffffffff); +} + +void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask) +{ + unsigned long flags; + spin_lock_irqsave(&dev->pci_irqmask_lock, flags); + + dev->pci_irqmask &= ~mask; + cx_clear(PCI_INT_MSK, mask); + + spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); +} + +static u32 cx23885_irq_get_mask(struct cx23885_dev *dev) +{ + u32 v; + unsigned long flags; + spin_lock_irqsave(&dev->pci_irqmask_lock, flags); + + v = cx_read(PCI_INT_MSK); + + spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); + return v; +} + +static int cx23885_risc_decode(u32 risc) +{ + static char *instr[16] = { + [RISC_SYNC >> 28] = "sync", + [RISC_WRITE >> 28] = "write", + [RISC_WRITEC >> 28] = "writec", + [RISC_READ >> 28] = "read", + [RISC_READC >> 28] = "readc", + [RISC_JUMP >> 28] = "jump", + [RISC_SKIP >> 28] = "skip", + [RISC_WRITERM >> 28] = "writerm", + [RISC_WRITECM >> 28] = "writecm", + [RISC_WRITECR >> 28] = "writecr", + }; + static int incr[16] = { + [RISC_WRITE >> 28] = 3, + [RISC_JUMP >> 28] = 3, + [RISC_SKIP >> 28] = 1, + [RISC_SYNC >> 28] = 1, + [RISC_WRITERM >> 28] = 3, + [RISC_WRITECM >> 28] = 3, + [RISC_WRITECR >> 28] = 4, + }; + static char *bits[] = { + "12", "13", "14", "resync", + "cnt0", "cnt1", "18", "19", + "20", "21", "22", "23", + "irq1", "irq2", "eol", "sol", + }; + int i; + + printk("0x%08x [ %s", risc, + instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) + if (risc & (1 << (i + 12))) + printk(" %s", bits[i]); + printk(" count=%d ]\n", risc & 0xfff); + return incr[risc >> 28] ? incr[risc >> 28] : 1; +} + +void cx23885_wakeup(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, u32 count) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf; + int bc; + + for (bc = 0;; bc++) { + if (list_empty(&q->active)) + break; + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + + /* count comes from the hw and is is 16bit wide -- + * this trick handles wrap-arounds correctly for + * up to 32767 buffers in flight... */ + if ((s16) (count - buf->count) < 0) + break; + + do_gettimeofday(&buf->vb.ts); + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, + count, buf->count); + buf->vb.state = VIDEOBUF_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + } + if (list_empty(&q->active)) + del_timer(&q->timeout); + else + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); + if (bc != 1) + printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n", + __func__, bc); +} + +int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) +{ + unsigned int i, lines; + u32 cdt; + + if (ch->cmds_start == 0) { + dprintk(1, "%s() Erasing channel [%s]\n", __func__, + ch->name); + cx_write(ch->ptr1_reg, 0); + cx_write(ch->ptr2_reg, 0); + cx_write(ch->cnt2_reg, 0); + cx_write(ch->cnt1_reg, 0); + return 0; + } else { + dprintk(1, "%s() Configuring channel [%s]\n", __func__, + ch->name); + } + + bpl = (bpl + 7) & ~7; /* alignment */ + cdt = ch->cdt; + lines = ch->fifo_size / bpl; + if (lines > 6) + lines = 6; + BUG_ON(lines < 2); + + cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + cx_write(8 + 4, 8); + cx_write(8 + 8, 0); + + /* write CDT */ + for (i = 0; i < lines; i++) { + dprintk(2, "%s() 0x%08x <- 0x%08x\n", __func__, cdt + 16*i, + ch->fifo_start + bpl*i); + cx_write(cdt + 16*i, ch->fifo_start + bpl*i); + cx_write(cdt + 16*i + 4, 0); + cx_write(cdt + 16*i + 8, 0); + cx_write(cdt + 16*i + 12, 0); + } + + /* write CMDS */ + if (ch->jumponly) + cx_write(ch->cmds_start + 0, 8); + else + cx_write(ch->cmds_start + 0, risc); + cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ + cx_write(ch->cmds_start + 8, cdt); + cx_write(ch->cmds_start + 12, (lines*16) >> 3); + cx_write(ch->cmds_start + 16, ch->ctrl_start); + if (ch->jumponly) + cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); + else + cx_write(ch->cmds_start + 20, 64 >> 2); + for (i = 24; i < 80; i += 4) + cx_write(ch->cmds_start + i, 0); + + /* fill registers */ + cx_write(ch->ptr1_reg, ch->fifo_start); + cx_write(ch->ptr2_reg, cdt); + cx_write(ch->cnt2_reg, (lines*16) >> 3); + cx_write(ch->cnt1_reg, (bpl >> 3) - 1); + + dprintk(2, "[bridge %d] sram setup %s: bpl=%d lines=%d\n", + dev->bridge, + ch->name, + bpl, + lines); + + return 0; +} + +void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch) +{ + static char *name[] = { + "init risc lo", + "init risc hi", + "cdt base", + "cdt size", + "iq base", + "iq size", + "risc pc lo", + "risc pc hi", + "iq wr ptr", + "iq rd ptr", + "cdt current", + "pci target lo", + "pci target hi", + "line / byte", + }; + u32 risc; + unsigned int i, j, n; + + printk(KERN_WARNING "%s: %s - dma channel status dump\n", + dev->name, ch->name); + for (i = 0; i < ARRAY_SIZE(name); i++) + printk(KERN_WARNING "%s: cmds: %-15s: 0x%08x\n", + dev->name, name[i], + cx_read(ch->cmds_start + 4*i)); + + for (i = 0; i < 4; i++) { + risc = cx_read(ch->cmds_start + 4 * (i + 14)); + printk(KERN_WARNING "%s: risc%d: ", dev->name, i); + cx23885_risc_decode(risc); + } + for (i = 0; i < (64 >> 2); i += n) { + risc = cx_read(ch->ctrl_start + 4 * i); + /* No consideration for bits 63-32 */ + + printk(KERN_WARNING "%s: (0x%08x) iq %x: ", dev->name, + ch->ctrl_start + 4 * i, i); + n = cx23885_risc_decode(risc); + for (j = 1; j < n; j++) { + risc = cx_read(ch->ctrl_start + 4 * (i + j)); + printk(KERN_WARNING "%s: iq %x: 0x%08x [ arg #%d ]\n", + dev->name, i+j, risc, j); + } + } + + printk(KERN_WARNING "%s: fifo: 0x%08x -> 0x%x\n", + dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); + printk(KERN_WARNING "%s: ctrl: 0x%08x -> 0x%x\n", + dev->name, ch->ctrl_start, ch->ctrl_start + 6*16); + printk(KERN_WARNING "%s: ptr1_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr1_reg)); + printk(KERN_WARNING "%s: ptr2_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr2_reg)); + printk(KERN_WARNING "%s: cnt1_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt1_reg)); + printk(KERN_WARNING "%s: cnt2_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt2_reg)); +} + +static void cx23885_risc_disasm(struct cx23885_tsport *port, + struct btcx_riscmem *risc) +{ + struct cx23885_dev *dev = port->dev; + unsigned int i, j, n; + + printk(KERN_INFO "%s: risc disasm: %p [dma=0x%08lx]\n", + dev->name, risc->cpu, (unsigned long)risc->dma); + for (i = 0; i < (risc->size >> 2); i += n) { + printk(KERN_INFO "%s: %04d: ", dev->name, i); + n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i])); + for (j = 1; j < n; j++) + printk(KERN_INFO "%s: %04d: 0x%08x [ arg #%d ]\n", + dev->name, i + j, risc->cpu[i + j], j); + if (risc->cpu[i] == cpu_to_le32(RISC_JUMP)) + break; + } +} + +static void cx23885_shutdown(struct cx23885_dev *dev) +{ + /* disable RISC controller */ + cx_write(DEV_CNTRL2, 0); + + /* Disable all IR activity */ + cx_write(IR_CNTRL_REG, 0); + + /* Disable Video A/B activity */ + cx_write(VID_A_DMA_CTL, 0); + cx_write(VID_B_DMA_CTL, 0); + cx_write(VID_C_DMA_CTL, 0); + + /* Disable Audio activity */ + cx_write(AUD_INT_DMA_CTL, 0); + cx_write(AUD_EXT_DMA_CTL, 0); + + /* Disable Serial port */ + cx_write(UART_CTL, 0); + + /* Disable Interrupts */ + cx23885_irq_disable_all(dev); + cx_write(VID_A_INT_MSK, 0); + cx_write(VID_B_INT_MSK, 0); + cx_write(VID_C_INT_MSK, 0); + cx_write(AUDIO_INT_INT_MSK, 0); + cx_write(AUDIO_EXT_INT_MSK, 0); + +} + +static void cx23885_reset(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __func__); + + cx23885_shutdown(dev); + + cx_write(PCI_INT_STAT, 0xffffffff); + cx_write(VID_A_INT_STAT, 0xffffffff); + cx_write(VID_B_INT_STAT, 0xffffffff); + cx_write(VID_C_INT_STAT, 0xffffffff); + cx_write(AUDIO_INT_INT_STAT, 0xffffffff); + cx_write(AUDIO_EXT_INT_STAT, 0xffffffff); + cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); + cx_write(PAD_CTRL, 0x00500300); + + mdelay(100); + + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], + 720*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03], + 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06], + 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0); + + cx23885_gpio_setup(dev); +} + + +static int cx23885_pci_quirks(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __func__); + + /* The cx23885 bridge has a weird bug which causes NMI to be asserted + * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not + * occur on the cx23887 bridge. + */ + if (dev->bridge == CX23885_BRIDGE_885) + cx_clear(RDR_TLCTL0, 1 << 4); + + return 0; +} + +static int get_resources(struct cx23885_dev *dev) +{ + if (request_mem_region(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0), + dev->name)) + return 0; + + printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); + + return -EBUSY; +} + +static void cx23885_timeout(unsigned long data); +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); + +static int cx23885_init_tsport(struct cx23885_dev *dev, + struct cx23885_tsport *port, int portno) +{ + dprintk(1, "%s(portno=%d)\n", __func__, portno); + + /* Transport bus init dma queue - Common settings */ + port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + port->vld_misc_val = 0x0; + port->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4); + + spin_lock_init(&port->slock); + port->dev = dev; + port->nr = portno; + + INIT_LIST_HEAD(&port->mpegq.active); + INIT_LIST_HEAD(&port->mpegq.queued); + port->mpegq.timeout.function = cx23885_timeout; + port->mpegq.timeout.data = (unsigned long)port; + init_timer(&port->mpegq.timeout); + + mutex_init(&port->frontends.lock); + INIT_LIST_HEAD(&port->frontends.felist); + port->frontends.active_fe_id = 0; + + /* This should be hardcoded allow a single frontend + * attachment to this tsport, keeping the -dvb.c + * code clean and safe. + */ + if (!port->num_frontends) + port->num_frontends = 1; + + switch (portno) { + case 1: + port->reg_gpcnt = VID_B_GPCNT; + port->reg_gpcnt_ctl = VID_B_GPCNT_CTL; + port->reg_dma_ctl = VID_B_DMA_CTL; + port->reg_lngth = VID_B_LNGTH; + port->reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; + port->reg_gen_ctrl = VID_B_GEN_CTL; + port->reg_bd_pkt_status = VID_B_BD_PKT_STATUS; + port->reg_sop_status = VID_B_SOP_STATUS; + port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; + port->reg_vld_misc = VID_B_VLD_MISC; + port->reg_ts_clk_en = VID_B_TS_CLK_EN; + port->reg_src_sel = VID_B_SRC_SEL; + port->reg_ts_int_msk = VID_B_INT_MSK; + port->reg_ts_int_stat = VID_B_INT_STAT; + port->sram_chno = SRAM_CH03; /* VID_B */ + port->pci_irqmask = 0x02; /* VID_B bit1 */ + break; + case 2: + port->reg_gpcnt = VID_C_GPCNT; + port->reg_gpcnt_ctl = VID_C_GPCNT_CTL; + port->reg_dma_ctl = VID_C_DMA_CTL; + port->reg_lngth = VID_C_LNGTH; + port->reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + port->reg_gen_ctrl = VID_C_GEN_CTL; + port->reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + port->reg_sop_status = VID_C_SOP_STATUS; + port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + port->reg_vld_misc = VID_C_VLD_MISC; + port->reg_ts_clk_en = VID_C_TS_CLK_EN; + port->reg_src_sel = 0; + port->reg_ts_int_msk = VID_C_INT_MSK; + port->reg_ts_int_stat = VID_C_INT_STAT; + port->sram_chno = SRAM_CH06; /* VID_C */ + port->pci_irqmask = 0x04; /* VID_C bit2 */ + break; + default: + BUG(); + } + + cx23885_risc_stopper(dev->pci, &port->mpegq.stopper, + port->reg_dma_ctl, port->dma_ctl_val, 0x00); + + return 0; +} + +static void cx23885_dev_checkrevision(struct cx23885_dev *dev) +{ + switch (cx_read(RDR_CFG2) & 0xff) { + case 0x00: + /* cx23885 */ + dev->hwrevision = 0xa0; + break; + case 0x01: + /* CX23885-12Z */ + dev->hwrevision = 0xa1; + break; + case 0x02: + /* CX23885-13Z/14Z */ + dev->hwrevision = 0xb0; + break; + case 0x03: + if (dev->pci->device == 0x8880) { + /* CX23888-21Z/22Z */ + dev->hwrevision = 0xc0; + } else { + /* CX23885-14Z */ + dev->hwrevision = 0xa4; + } + break; + case 0x04: + if (dev->pci->device == 0x8880) { + /* CX23888-31Z */ + dev->hwrevision = 0xd0; + } else { + /* CX23885-15Z, CX23888-31Z */ + dev->hwrevision = 0xa5; + } + break; + case 0x0e: + /* CX23887-15Z */ + dev->hwrevision = 0xc0; + break; + case 0x0f: + /* CX23887-14Z */ + dev->hwrevision = 0xb1; + break; + default: + printk(KERN_ERR "%s() New hardware revision found 0x%x\n", + __func__, dev->hwrevision); + } + if (dev->hwrevision) + printk(KERN_INFO "%s() Hardware revision = 0x%02x\n", + __func__, dev->hwrevision); + else + printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n", + __func__, dev->hwrevision); +} + +/* Find the first v4l2_subdev member of the group id in hw */ +struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw) +{ + struct v4l2_subdev *result = NULL; + struct v4l2_subdev *sd; + + spin_lock(&dev->v4l2_dev.lock); + v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) { + if (sd->grp_id == hw) { + result = sd; + break; + } + } + spin_unlock(&dev->v4l2_dev.lock); + return result; +} + +static int cx23885_dev_setup(struct cx23885_dev *dev) +{ + int i; + + spin_lock_init(&dev->pci_irqmask_lock); + + mutex_init(&dev->lock); + mutex_init(&dev->gpio_lock); + + atomic_inc(&dev->refcount); + + dev->nr = cx23885_devcount++; + sprintf(dev->name, "cx23885[%d]", dev->nr); + + /* Configure the internal memory */ + if (dev->pci->device == 0x8880) { + /* Could be 887 or 888, assume a default */ + dev->bridge = CX23885_BRIDGE_887; + /* Apply a sensible clock frequency for the PCIe bridge */ + dev->clk_freq = 25000000; + dev->sram_channels = cx23887_sram_channels; + } else + if (dev->pci->device == 0x8852) { + dev->bridge = CX23885_BRIDGE_885; + /* Apply a sensible clock frequency for the PCIe bridge */ + dev->clk_freq = 28000000; + dev->sram_channels = cx23885_sram_channels; + } else + BUG(); + + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", + __func__, dev->bridge); + + /* board config */ + dev->board = UNSET; + if (card[dev->nr] < cx23885_bcount) + dev->board = card[dev->nr]; + for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) + if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && + dev->pci->subsystem_device == cx23885_subids[i].subdevice) + dev->board = cx23885_subids[i].card; + if (UNSET == dev->board) { + dev->board = CX23885_BOARD_UNKNOWN; + cx23885_card_list(dev); + } + + /* If the user specific a clk freq override, apply it */ + if (cx23885_boards[dev->board].clk_freq > 0) + dev->clk_freq = cx23885_boards[dev->board].clk_freq; + + dev->pci_bus = dev->pci->bus->number; + dev->pci_slot = PCI_SLOT(dev->pci->devfn); + cx23885_irq_add(dev, 0x001f00); + + /* External Master 1 Bus */ + dev->i2c_bus[0].nr = 0; + dev->i2c_bus[0].dev = dev; + dev->i2c_bus[0].reg_stat = I2C1_STAT; + dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; + dev->i2c_bus[0].reg_addr = I2C1_ADDR; + dev->i2c_bus[0].reg_rdata = I2C1_RDATA; + dev->i2c_bus[0].reg_wdata = I2C1_WDATA; + dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */ + + /* External Master 2 Bus */ + dev->i2c_bus[1].nr = 1; + dev->i2c_bus[1].dev = dev; + dev->i2c_bus[1].reg_stat = I2C2_STAT; + dev->i2c_bus[1].reg_ctrl = I2C2_CTRL; + dev->i2c_bus[1].reg_addr = I2C2_ADDR; + dev->i2c_bus[1].reg_rdata = I2C2_RDATA; + dev->i2c_bus[1].reg_wdata = I2C2_WDATA; + dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */ + + /* Internal Master 3 Bus */ + dev->i2c_bus[2].nr = 2; + dev->i2c_bus[2].dev = dev; + dev->i2c_bus[2].reg_stat = I2C3_STAT; + dev->i2c_bus[2].reg_ctrl = I2C3_CTRL; + dev->i2c_bus[2].reg_addr = I2C3_ADDR; + dev->i2c_bus[2].reg_rdata = I2C3_RDATA; + dev->i2c_bus[2].reg_wdata = I2C3_WDATA; + dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ + + if ((cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) || + (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)) + cx23885_init_tsport(dev, &dev->ts1, 1); + + if ((cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) || + (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)) + cx23885_init_tsport(dev, &dev->ts2, 2); + + if (get_resources(dev) < 0) { + printk(KERN_ERR "CORE %s No more PCIe resources for " + "subsystem: %04x:%04x\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device); + + cx23885_devcount--; + return -ENODEV; + } + + /* PCIe stuff */ + dev->lmmio = ioremap(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0)); + + dev->bmmio = (u8 __iomem *)dev->lmmio; + + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, cx23885_boards[dev->board].name, + dev->board, card[dev->nr] == dev->board ? + "insmod option" : "autodetected"); + + cx23885_pci_quirks(dev); + + /* Assume some sensible defaults */ + dev->tuner_type = cx23885_boards[dev->board].tuner_type; + dev->tuner_addr = cx23885_boards[dev->board].tuner_addr; + dev->tuner_bus = cx23885_boards[dev->board].tuner_bus; + dev->radio_type = cx23885_boards[dev->board].radio_type; + dev->radio_addr = cx23885_boards[dev->board].radio_addr; + + dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x tuner_bus = %d\n", + __func__, dev->tuner_type, dev->tuner_addr, dev->tuner_bus); + dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n", + __func__, dev->radio_type, dev->radio_addr); + + /* The cx23417 encoder has GPIO's that need to be initialised + * before DVB, so that demodulators and tuners are out of + * reset before DVB uses them. + */ + if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) || + (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)) + cx23885_mc417_init(dev); + + /* init hardware */ + cx23885_reset(dev); + + cx23885_i2c_register(&dev->i2c_bus[0]); + cx23885_i2c_register(&dev->i2c_bus[1]); + cx23885_i2c_register(&dev->i2c_bus[2]); + cx23885_card_setup(dev); + call_all(dev, core, s_power, 0); + cx23885_ir_init(dev); + + if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { + if (cx23885_video_register(dev) < 0) { + printk(KERN_ERR "%s() Failed to register analog " + "video adapters on VID_A\n", __func__); + } + } + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + if (cx23885_boards[dev->board].num_fds_portb) + dev->ts1.num_frontends = + cx23885_boards[dev->board].num_fds_portb; + if (cx23885_dvb_register(&dev->ts1) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", + __func__); + } + } else + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { + if (cx23885_417_register(dev) < 0) { + printk(KERN_ERR + "%s() Failed to register 417 on VID_B\n", + __func__); + } + } + + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + if (cx23885_boards[dev->board].num_fds_portc) + dev->ts2.num_frontends = + cx23885_boards[dev->board].num_fds_portc; + if (cx23885_dvb_register(&dev->ts2) < 0) { + printk(KERN_ERR + "%s() Failed to register dvb on VID_C\n", + __func__); + } + } else + if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) { + if (cx23885_417_register(dev) < 0) { + printk(KERN_ERR + "%s() Failed to register 417 on VID_C\n", + __func__); + } + } + + cx23885_dev_checkrevision(dev); + + /* disable MSI for NetUP cards, otherwise CI is not working */ + if (cx23885_boards[dev->board].ci_type > 0) + cx_clear(RDR_RDRCTL1, 1 << 8); + + return 0; +} + +static void cx23885_dev_unregister(struct cx23885_dev *dev) +{ + release_mem_region(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0)); + + if (!atomic_dec_and_test(&dev->refcount)) + return; + + if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) + cx23885_video_unregister(dev); + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + cx23885_dvb_unregister(&dev->ts1); + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) + cx23885_417_unregister(dev); + + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + cx23885_dvb_unregister(&dev->ts2); + + if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) + cx23885_417_unregister(dev); + + cx23885_i2c_unregister(&dev->i2c_bus[2]); + cx23885_i2c_unregister(&dev->i2c_bus[1]); + cx23885_i2c_unregister(&dev->i2c_bus[0]); + + iounmap(dev->lmmio); +} + +static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines) +{ + struct scatterlist *sg; + unsigned int line, todo; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + /* scan lines */ + sg = sglist; + for (line = 0; line < lines; line++) { + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + if (bpl <= sg_dma_len(sg)-offset) { + /* fits into current chunk */ + *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + offset += bpl; + } else { + /* scanline needs to be split */ + todo = bpl; + *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL| + (sg_dma_len(sg)-offset)); + *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + todo -= (sg_dma_len(sg)-offset); + offset = 0; + sg++; + while (todo > sg_dma_len(sg)) { + *(rp++) = cpu_to_le32(RISC_WRITE| + sg_dma_len(sg)); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + todo -= sg_dma_len(sg); + sg++; + } + *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + offset += todo; + } + offset += padding; + } + + return rp; +} + +int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines) +{ + u32 instructions, fields; + __le32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + /* write and jump need and extra dword */ + instructions = fields * (1 + ((bpl + padding) * lines) + / PAGE_SIZE + lines); + instructions += 2; + rc = btcx_riscmem_alloc(pci, risc, instructions*12); + if (rc < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + if (UNSET != top_offset) + rp = cx23885_risc_field(rp, sglist, top_offset, 0, + bpl, padding, lines); + if (UNSET != bottom_offset) + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, + bpl, padding, lines); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + +static int cx23885_risc_databuffer(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int bpl, + unsigned int lines) +{ + u32 instructions; + __le32 *rp; + int rc; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Here + there is no padding and no sync. First DMA region may be smaller + than PAGE_SIZE */ + /* Jump and write need an extra dword */ + instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; + instructions += 1; + + rc = btcx_riscmem_alloc(pci, risc, instructions*12); + if (rc < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value) +{ + __le32 *rp; + int rc; + + rc = btcx_riscmem_alloc(pci, risc, 4*16); + if (rc < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); + *(rp++) = cpu_to_le32(reg); + *(rp++) = cpu_to_le32(value); + *(rp++) = cpu_to_le32(mask); + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc->dma); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + return 0; +} + +void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) +{ + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + + BUG_ON(in_interrupt()); + videobuf_waiton(q, &buf->vb, 0, 0); + videobuf_dma_unmap(q->dev, dma); + videobuf_dma_free(dma); + btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s() Register Dump\n", __func__); + dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__, + cx_read(DEV_CNTRL2)); + dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__, + cx23885_irq_get_mask(dev)); + dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__, + cx_read(AUDIO_INT_INT_MSK)); + dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__, + cx_read(AUD_INT_DMA_CTL)); + dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __func__, + cx_read(AUDIO_EXT_INT_MSK)); + dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __func__, + cx_read(AUD_EXT_DMA_CTL)); + dprintk(1, "%s() PAD_CTRL 0x%08X\n", __func__, + cx_read(PAD_CTRL)); + dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __func__, + cx_read(ALT_PIN_OUT_SEL)); + dprintk(1, "%s() GPIO2 0x%08X\n", __func__, + cx_read(GPIO2)); + dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __func__, + port->reg_gpcnt, cx_read(port->reg_gpcnt)); + dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __func__, + port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); + dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__, + port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); + if (port->reg_src_sel) + dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__, + port->reg_src_sel, cx_read(port->reg_src_sel)); + dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__, + port->reg_lngth, cx_read(port->reg_lngth)); + dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__, + port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl)); + dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __func__, + port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl)); + dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __func__, + port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status)); + dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __func__, + port->reg_sop_status, cx_read(port->reg_sop_status)); + dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__, + port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat)); + dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __func__, + port->reg_vld_misc, cx_read(port->reg_vld_misc)); + dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __func__, + port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en)); + dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__, + port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); +} + +static int cx23885_start_dma(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + struct cx23885_dev *dev = port->dev; + u32 reg; + + dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, + buf->vb.width, buf->vb.height, buf->vb.field); + + /* Stop the fifo and risc engine for this port */ + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, + &dev->sram_channels[port->sram_chno], + port->ts_packet_size, buf->risc.dma); + if (debug > 5) { + cx23885_sram_channel_dump(dev, + &dev->sram_channels[port->sram_chno]); + cx23885_risc_disasm(port, &buf->risc); + } + + /* write TS length to chip */ + cx_write(port->reg_lngth, buf->vb.width); + + if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && + (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { + printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n", + __func__, + cx23885_boards[dev->board].portb, + cx23885_boards[dev->board].portc); + return -EINVAL; + } + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) + cx23885_av_clk(dev, 0); + + udelay(100); + + /* If the port supports SRC SELECT, configure it */ + if (port->reg_src_sel) + cx_write(port->reg_src_sel, port->src_sel_val); + + cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val); + cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); + cx_write(port->reg_vld_misc, port->vld_misc_val); + cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); + udelay(100); + + /* NOTE: this is 2 (reserved) for portb, does it matter? */ + /* reset counter to zero */ + cx_write(port->reg_gpcnt_ctl, 3); + q->count = 1; + + /* Set VIDB pins to input */ + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + reg = cx_read(PAD_CTRL); + reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */ + cx_write(PAD_CTRL, reg); + } + + /* Set VIDC pins to input */ + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + reg = cx_read(PAD_CTRL); + reg &= ~0x4; /* Clear TS2_SOP_OE */ + cx_write(PAD_CTRL, reg); + } + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { + + reg = cx_read(PAD_CTRL); + reg = reg & ~0x1; /* Clear TS1_OE */ + + /* FIXME, bit 2 writing here is questionable */ + /* set TS1_SOP_OE and TS1_OE_HI */ + reg = reg | 0xa; + cx_write(PAD_CTRL, reg); + + /* FIXME and these two registers should be documented. */ + cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011); + cx_write(ALT_PIN_OUT_SEL, 0x10100045); + } + + switch (dev->bridge) { + case CX23885_BRIDGE_885: + case CX23885_BRIDGE_887: + case CX23885_BRIDGE_888: + /* enable irqs */ + dprintk(1, "%s() enabling TS int's and DMA\n", __func__); + cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); + cx_set(port->reg_dma_ctl, port->dma_ctl_val); + cx23885_irq_add(dev, port->pci_irqmask); + cx23885_irq_enable_all(dev); + break; + default: + BUG(); + } + + cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) + cx23885_av_clk(dev, 1); + + if (debug > 4) + cx23885_tsport_reg_dump(port); + + return 0; +} + +static int cx23885_stop_dma(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + u32 reg; + + dprintk(1, "%s()\n", __func__); + + /* Stop interrupts and DMA */ + cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { + + reg = cx_read(PAD_CTRL); + + /* Set TS1_OE */ + reg = reg | 0x1; + + /* clear TS1_SOP_OE and TS1_OE_HI */ + reg = reg & ~0xa; + cx_write(PAD_CTRL, reg); + cx_write(port->reg_src_sel, 0); + cx_write(port->reg_gen_ctrl, 8); + + } + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) + cx23885_av_clk(dev, 0); + + return 0; +} + +int cx23885_restart_queue(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf; + + dprintk(5, "%s()\n", __func__); + if (list_empty(&q->active)) { + struct cx23885_buffer *prev; + prev = NULL; + + dprintk(5, "%s() queue is empty\n", __func__); + + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, + vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_dma(port, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(5, "[%p/%d] restart_queue - f/active\n", + buf, buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + /* 64 bit bits 63-32 */ + prev->risc.jmp[2] = cpu_to_le32(0); + dprintk(5, "[%p/%d] restart_queue - m/active\n", + buf, buf->vb.i); + } else { + return 0; + } + prev = buf; + } + return 0; + } + + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + dprintk(2, "restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_dma(port, q, buf); + list_for_each_entry(buf, &q->active, vb.queue) + buf->count = q->count++; + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); + return 0; +} + +/* ------------------------------------------------------------------ */ + +int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, + struct cx23885_buffer *buf, enum v4l2_field field) +{ + struct cx23885_dev *dev = port->dev; + int size = port->ts_packet_size * port->ts_packet_count; + int rc; + + dprintk(1, "%s: %p\n", __func__, buf); + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + buf->vb.width = port->ts_packet_size; + buf->vb.height = port->ts_packet_count; + buf->vb.size = size; + buf->vb.field = field /*V4L2_FIELD_TOP*/; + + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) + goto fail; + cx23885_risc_databuffer(dev->pci, &buf->risc, + videobuf_to_dma(&buf->vb)->sglist, + buf->vb.width, buf->vb.height); + } + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q, buf); + return rc; +} + +void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) +{ + struct cx23885_buffer *prev; + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *cx88q = &port->mpegq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (list_empty(&cx88q->active)) { + dprintk(1, "queue is empty - first active\n"); + list_add_tail(&buf->vb.queue, &cx88q->active); + cx23885_start_dma(port, cx88q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = cx88q->count++; + mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); + dprintk(1, "[%p/%d] %s - first active\n", + buf, buf->vb.i, __func__); + } else { + dprintk(1, "queue is not empty - append to active\n"); + prev = list_entry(cx88q->active.prev, struct cx23885_buffer, + vb.queue); + list_add_tail(&buf->vb.queue, &cx88q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = cx88q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk(1, "[%p/%d] %s - append to active\n", + buf, buf->vb.i, __func__); + } +} + +/* ----------------------------------------------------------- */ + +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, + int restart) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *q = &port->mpegq; + struct cx23885_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&port->slock, flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", + buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); + } + if (restart) { + dprintk(1, "restarting queue\n"); + cx23885_restart_queue(port, q); + } + spin_unlock_irqrestore(&port->slock, flags); +} + +void cx23885_cancel_buffers(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *q = &port->mpegq; + + dprintk(1, "%s()\n", __func__); + del_timer_sync(&q->timeout); + cx23885_stop_dma(port); + do_cancel_buffers(port, "cancel", 0); +} + +static void cx23885_timeout(unsigned long data) +{ + struct cx23885_tsport *port = (struct cx23885_tsport *)data; + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s()\n", __func__); + + if (debug > 5) + cx23885_sram_channel_dump(dev, + &dev->sram_channels[port->sram_chno]); + + cx23885_stop_dma(port); + do_cancel_buffers(port, "timeout", 1); +} + +int cx23885_irq_417(struct cx23885_dev *dev, u32 status) +{ + /* FIXME: port1 assumption here. */ + struct cx23885_tsport *port = &dev->ts1; + int count = 0; + int handled = 0; + + if (status == 0) + return handled; + + count = cx_read(port->reg_gpcnt); + dprintk(7, "status: 0x%08x mask: 0x%08x count: 0x%x\n", + status, cx_read(port->reg_ts_int_msk), count); + + if ((status & VID_B_MSK_BAD_PKT) || + (status & VID_B_MSK_OPC_ERR) || + (status & VID_B_MSK_VBI_OPC_ERR) || + (status & VID_B_MSK_SYNC) || + (status & VID_B_MSK_VBI_SYNC) || + (status & VID_B_MSK_OF) || + (status & VID_B_MSK_VBI_OF)) { + printk(KERN_ERR "%s: V4L mpeg risc op code error, status " + "= 0x%x\n", dev->name, status); + if (status & VID_B_MSK_BAD_PKT) + dprintk(1, " VID_B_MSK_BAD_PKT\n"); + if (status & VID_B_MSK_OPC_ERR) + dprintk(1, " VID_B_MSK_OPC_ERR\n"); + if (status & VID_B_MSK_VBI_OPC_ERR) + dprintk(1, " VID_B_MSK_VBI_OPC_ERR\n"); + if (status & VID_B_MSK_SYNC) + dprintk(1, " VID_B_MSK_SYNC\n"); + if (status & VID_B_MSK_VBI_SYNC) + dprintk(1, " VID_B_MSK_VBI_SYNC\n"); + if (status & VID_B_MSK_OF) + dprintk(1, " VID_B_MSK_OF\n"); + if (status & VID_B_MSK_VBI_OF) + dprintk(1, " VID_B_MSK_VBI_OF\n"); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + cx23885_sram_channel_dump(dev, + &dev->sram_channels[port->sram_chno]); + cx23885_417_check_encoder(dev); + } else if (status & VID_B_MSK_RISCI1) { + dprintk(7, " VID_B_MSK_RISCI1\n"); + spin_lock(&port->slock); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + } else if (status & VID_B_MSK_RISCI2) { + dprintk(7, " VID_B_MSK_RISCI2\n"); + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + } + if (status) { + cx_write(port->reg_ts_int_stat, status); + handled = 1; + } + + return handled; +} + +static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) +{ + struct cx23885_dev *dev = port->dev; + int handled = 0; + u32 count; + + if ((status & VID_BC_MSK_OPC_ERR) || + (status & VID_BC_MSK_BAD_PKT) || + (status & VID_BC_MSK_SYNC) || + (status & VID_BC_MSK_OF)) { + + if (status & VID_BC_MSK_OPC_ERR) + dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", + VID_BC_MSK_OPC_ERR); + + if (status & VID_BC_MSK_BAD_PKT) + dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", + VID_BC_MSK_BAD_PKT); + + if (status & VID_BC_MSK_SYNC) + dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", + VID_BC_MSK_SYNC); + + if (status & VID_BC_MSK_OF) + dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", + VID_BC_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + cx23885_sram_channel_dump(dev, + &dev->sram_channels[port->sram_chno]); + + } else if (status & VID_BC_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (status & VID_BC_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + if (status) { + cx_write(port->reg_ts_int_stat, status); + handled = 1; + } + + return handled; +} + +static irqreturn_t cx23885_irq(int irq, void *dev_id) +{ + struct cx23885_dev *dev = dev_id; + struct cx23885_tsport *ts1 = &dev->ts1; + struct cx23885_tsport *ts2 = &dev->ts2; + u32 pci_status, pci_mask; + u32 vida_status, vida_mask; + u32 ts1_status, ts1_mask; + u32 ts2_status, ts2_mask; + int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; + bool subdev_handled; + + pci_status = cx_read(PCI_INT_STAT); + pci_mask = cx23885_irq_get_mask(dev); + vida_status = cx_read(VID_A_INT_STAT); + vida_mask = cx_read(VID_A_INT_MSK); + ts1_status = cx_read(VID_B_INT_STAT); + ts1_mask = cx_read(VID_B_INT_MSK); + ts2_status = cx_read(VID_C_INT_STAT); + ts2_mask = cx_read(VID_C_INT_MSK); + + if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0)) + goto out; + + vida_count = cx_read(VID_A_GPCNT); + ts1_count = cx_read(ts1->reg_gpcnt); + ts2_count = cx_read(ts2->reg_gpcnt); + dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", + pci_status, pci_mask); + dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n", + vida_status, vida_mask, vida_count); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", + ts1_status, ts1_mask, ts1_count); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", + ts2_status, ts2_mask, ts2_count); + + if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR | + PCI_MSK_AL_RD | PCI_MSK_AL_WR | PCI_MSK_APB_DMA | + PCI_MSK_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A | + PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT | + PCI_MSK_GPIO0 | PCI_MSK_GPIO1 | + PCI_MSK_AV_CORE | PCI_MSK_IR)) { + + if (pci_status & PCI_MSK_RISC_RD) + dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", + PCI_MSK_RISC_RD); + + if (pci_status & PCI_MSK_RISC_WR) + dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", + PCI_MSK_RISC_WR); + + if (pci_status & PCI_MSK_AL_RD) + dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", + PCI_MSK_AL_RD); + + if (pci_status & PCI_MSK_AL_WR) + dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", + PCI_MSK_AL_WR); + + if (pci_status & PCI_MSK_APB_DMA) + dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", + PCI_MSK_APB_DMA); + + if (pci_status & PCI_MSK_VID_C) + dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", + PCI_MSK_VID_C); + + if (pci_status & PCI_MSK_VID_B) + dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", + PCI_MSK_VID_B); + + if (pci_status & PCI_MSK_VID_A) + dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", + PCI_MSK_VID_A); + + if (pci_status & PCI_MSK_AUD_INT) + dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", + PCI_MSK_AUD_INT); + + if (pci_status & PCI_MSK_AUD_EXT) + dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", + PCI_MSK_AUD_EXT); + + if (pci_status & PCI_MSK_GPIO0) + dprintk(7, " (PCI_MSK_GPIO0 0x%08x)\n", + PCI_MSK_GPIO0); + + if (pci_status & PCI_MSK_GPIO1) + dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n", + PCI_MSK_GPIO1); + + if (pci_status & PCI_MSK_AV_CORE) + dprintk(7, " (PCI_MSK_AV_CORE 0x%08x)\n", + PCI_MSK_AV_CORE); + + if (pci_status & PCI_MSK_IR) + dprintk(7, " (PCI_MSK_IR 0x%08x)\n", + PCI_MSK_IR); + } + + if (cx23885_boards[dev->board].ci_type == 1 && + (pci_status & (PCI_MSK_GPIO1 | PCI_MSK_GPIO0))) + handled += netup_ci_slot_status(dev, pci_status); + + if (cx23885_boards[dev->board].ci_type == 2 && + (pci_status & PCI_MSK_GPIO0)) + handled += altera_ci_irq(dev); + + if (ts1_status) { + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + handled += cx23885_irq_ts(ts1, ts1_status); + else + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) + handled += cx23885_irq_417(dev, ts1_status); + } + + if (ts2_status) { + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + handled += cx23885_irq_ts(ts2, ts2_status); + else + if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) + handled += cx23885_irq_417(dev, ts2_status); + } + + if (vida_status) + handled += cx23885_video_irq(dev, vida_status); + + if (pci_status & PCI_MSK_IR) { + subdev_handled = false; + v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine, + pci_status, &subdev_handled); + if (subdev_handled) + handled++; + } + + if ((pci_status & pci_mask) & PCI_MSK_AV_CORE) { + cx23885_irq_disable(dev, PCI_MSK_AV_CORE); + if (!schedule_work(&dev->cx25840_work)) + printk(KERN_ERR "%s: failed to set up deferred work for" + " AV Core/IR interrupt. Interrupt is disabled" + " and won't be re-enabled\n", dev->name); + handled++; + } + + if (handled) + cx_write(PCI_INT_STAT, pci_status); +out: + return IRQ_RETVAL(handled); +} + +static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + struct cx23885_dev *dev; + + if (sd == NULL) + return; + + dev = to_cx23885(sd->v4l2_dev); + + switch (notification) { + case V4L2_SUBDEV_IR_RX_NOTIFY: /* Possibly called in an IRQ context */ + if (sd == dev->sd_ir) + cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg); + break; + case V4L2_SUBDEV_IR_TX_NOTIFY: /* Possibly called in an IRQ context */ + if (sd == dev->sd_ir) + cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg); + break; + } +} + +static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev) +{ + INIT_WORK(&dev->cx25840_work, cx23885_av_work_handler); + INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler); + INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler); + dev->v4l2_dev.notify = cx23885_v4l2_dev_notify; +} + +static inline int encoder_on_portb(struct cx23885_dev *dev) +{ + return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER; +} + +static inline int encoder_on_portc(struct cx23885_dev *dev) +{ + return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER; +} + +/* Mask represents 32 different GPIOs, GPIO's are split into multiple + * registers depending on the board configuration (and whether the + * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will + * be pushed into the correct hardware register, regardless of the + * physical location. Certain registers are shared so we sanity check + * and report errors if we think we're tampering with a GPIo that might + * be assigned to the encoder (and used for the host bus). + * + * GPIO 2 thru 0 - On the cx23885 bridge + * GPIO 18 thru 3 - On the cx23417 host bus interface + * GPIO 23 thru 19 - On the cx25840 a/v core + */ +void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask) +{ + if (mask & 0x7) + cx_set(GP0_IO, mask & 0x7); + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Setting GPIO on encoder ports\n", + dev->name); + cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3); + } + + /* TODO: 23-19 */ + if (mask & 0x00f80000) + printk(KERN_INFO "%s: Unsupported\n", dev->name); +} + +void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask) +{ + if (mask & 0x00000007) + cx_clear(GP0_IO, mask & 0x7); + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Clearing GPIO moving on encoder ports\n", + dev->name); + cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3); + } + + /* TODO: 23-19 */ + if (mask & 0x00f80000) + printk(KERN_INFO "%s: Unsupported\n", dev->name); +} + +u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask) +{ + if (mask & 0x00000007) + return (cx_read(GP0_IO) >> 8) & mask & 0x7; + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Reading GPIO moving on encoder ports\n", + dev->name); + return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3; + } + + /* TODO: 23-19 */ + if (mask & 0x00f80000) + printk(KERN_INFO "%s: Unsupported\n", dev->name); + + return 0; +} + +void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) +{ + if ((mask & 0x00000007) && asoutput) + cx_set(GP0_IO, (mask & 0x7) << 16); + else if ((mask & 0x00000007) && !asoutput) + cx_clear(GP0_IO, (mask & 0x7) << 16); + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Enabling GPIO on encoder ports\n", + dev->name); + } + + /* MC417_OEN is active low for output, write 1 for an input */ + if ((mask & 0x0007fff8) && asoutput) + cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3); + + else if ((mask & 0x0007fff8) && !asoutput) + cx_set(MC417_OEN, (mask & 0x7fff8) >> 3); + + /* TODO: 23-19 */ +} + +static int __devinit cx23885_initdev(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cx23885_dev *dev; + int err; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + + err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); + if (err < 0) + goto fail_free; + + /* Prepare to handle notifications from subdevices */ + cx23885_v4l2_dev_notify_init(dev); + + /* pci init */ + dev->pci = pci_dev; + if (pci_enable_device(pci_dev)) { + err = -EIO; + goto fail_unreg; + } + + if (cx23885_dev_setup(dev) < 0) { + err = -EINVAL; + goto fail_unreg; + } + + /* print pci info */ + dev->pci_rev = pci_dev->revision; + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%llx\n", dev->name, + pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, + (unsigned long long)pci_resource_start(pci_dev, 0)); + + pci_set_master(pci_dev); + if (!pci_dma_supported(pci_dev, 0xffffffff)) { + printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); + err = -EIO; + goto fail_irq; + } + + if (!pci_enable_msi(pci_dev)) + err = request_irq(pci_dev->irq, cx23885_irq, + IRQF_DISABLED, dev->name, dev); + else + err = request_irq(pci_dev->irq, cx23885_irq, + IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", + dev->name, pci_dev->irq); + goto fail_irq; + } + + switch (dev->board) { + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: + cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0); + break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + cx23885_irq_add_enable(dev, PCI_MSK_GPIO0); + break; + } + + /* + * The CX2388[58] IR controller can start firing interrupts when + * enabled, so these have to take place after the cx23885_irq() handler + * is hooked up by the call to request_irq() above. + */ + cx23885_ir_pci_int_enable(dev); + cx23885_input_init(dev); + + return 0; + +fail_irq: + cx23885_dev_unregister(dev); +fail_unreg: + v4l2_device_unregister(&dev->v4l2_dev); +fail_free: + kfree(dev); + return err; +} + +static void __devexit cx23885_finidev(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct cx23885_dev *dev = to_cx23885(v4l2_dev); + + cx23885_input_fini(dev); + cx23885_ir_fini(dev); + + cx23885_shutdown(dev); + + pci_disable_device(pci_dev); + + /* unregister stuff */ + free_irq(pci_dev->irq, dev); + pci_disable_msi(pci_dev); + + cx23885_dev_unregister(dev); + v4l2_device_unregister(v4l2_dev); + kfree(dev); +} + +static struct pci_device_id cx23885_pci_tbl[] = { + { + /* CX23885 */ + .vendor = 0x14f1, + .device = 0x8852, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + /* CX23887 Rev 2 */ + .vendor = 0x14f1, + .device = 0x8880, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + /* --- end of list --- */ + } +}; +MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl); + +static struct pci_driver cx23885_pci_driver = { + .name = "cx23885", + .id_table = cx23885_pci_tbl, + .probe = cx23885_initdev, + .remove = __devexit_p(cx23885_finidev), + /* TODO */ + .suspend = NULL, + .resume = NULL, +}; + +static int __init cx23885_init(void) +{ + printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", + (CX23885_VERSION_CODE >> 16) & 0xff, + (CX23885_VERSION_CODE >> 8) & 0xff, + CX23885_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx23885_pci_driver); +} + +static void __exit cx23885_fini(void) +{ + pci_unregister_driver(&cx23885_pci_driver); +} + +module_init(cx23885_init); +module_exit(cx23885_fini); + +/* ----------------------------------------------------------- */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-dvb.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1268 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" +#include + +#include "dvb_ca_en50221.h" +#include "s5h1409.h" +#include "s5h1411.h" +#include "mt2131.h" +#include "tda8290.h" +#include "tda18271.h" +#include "lgdt330x.h" +#include "xc5000.h" +#include "max2165.h" +#include "tda10048.h" +#include "tuner-xc2028.h" +#include "tuner-simple.h" +#include "dib7000p.h" +#include "dibx000_common.h" +#include "zl10353.h" +#include "stv0900.h" +#include "stv0900_reg.h" +#include "stv6110.h" +#include "lnbh24.h" +#include "cx24116.h" +#include "cimax2.h" +#include "lgs8gxx.h" +#include "netup-eeprom.h" +#include "netup-init.h" +#include "lgdt3305.h" +#include "atbm8830.h" +#include "ds3000.h" +#include "cx23885-f300.h" +#include "altera-ci.h" +#include "stv0367.h" + +static unsigned int debug; + +#define dprintk(level, fmt, arg...)\ + do { if (debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) + +/* ------------------------------------------------------------------ */ + +static unsigned int alt_tuner; +module_param(alt_tuner, int, 0644); +MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* ------------------------------------------------------------------ */ + +static int dvb_buf_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct cx23885_tsport *port = q->priv_data; + + port->ts_packet_size = 188 * 4; + port->ts_packet_count = 32; + + *size = port->ts_packet_size * port->ts_packet_count; + *count = 32; + return 0; +} + +static int dvb_buf_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) +{ + struct cx23885_tsport *port = q->priv_data; + return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field); +} + +static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx23885_tsport *port = q->priv_data; + cx23885_buf_queue(port, (struct cx23885_buffer *)vb); +} + +static void dvb_buf_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + cx23885_free_buffer(q, (struct cx23885_buffer *)vb); +} + +static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) +{ + struct videobuf_dvb_frontends *f; + struct videobuf_dvb_frontend *fe; + + f = &port->frontends; + + if (f->gate <= 1) /* undefined or fe0 */ + fe = videobuf_dvb_get_frontend(f, 1); + else + fe = videobuf_dvb_get_frontend(f, f->gate); + + if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) + fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); +} + +static struct videobuf_queue_ops dvb_qops = { + .buf_setup = dvb_buf_setup, + .buf_prepare = dvb_buf_prepare, + .buf_queue = dvb_buf_queue, + .buf_release = dvb_buf_release, +}; + +static struct s5h1409_config hauppauge_generic_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct tda10048_config hauppauge_hvr1200_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_SERIAL_OUTPUT, + .fwbulkwritelen = TDA10048_BULKWRITE_200, + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3800, + .dtv8_if_freq_khz = TDA10048_IF_4300, + .clk_freq_khz = TDA10048_CLK_16000, +}; + +static struct tda10048_config hauppauge_hvr1210_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_SERIAL_OUTPUT, + .fwbulkwritelen = TDA10048_BULKWRITE_200, + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3500, + .dtv8_if_freq_khz = TDA10048_IF_4000, + .clk_freq_khz = TDA10048_CLK_16000, +}; + +static struct s5h1409_config hauppauge_ezqam_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .qam_if = 4000, + .inversion = S5H1409_INVERSION_ON, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct s5h1409_config hauppauge_hvr1800lp_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct s5h1409_config hauppauge_hvr1500_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct mt2131_config hauppauge_generic_tunerconfig = { + 0x61 +}; + +static struct lgdt330x_config fusionhdtv_5_express = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, +}; + +static struct s5h1409_config hauppauge_hvr1500q_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct s5h1409_config dvico_s5h1409_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct s5h1411_config dvico_s5h1411_config = { + .output_mode = S5H1411_SERIAL_OUTPUT, + .gpio = S5H1411_GPIO_ON, + .qam_if = S5H1411_IF_44000, + .vsb_if = S5H1411_IF_44000, + .inversion = S5H1411_INVERSION_OFF, + .status_mode = S5H1411_DEMODLOCKING, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct s5h1411_config hcw_s5h1411_config = { + .output_mode = S5H1411_SERIAL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .vsb_if = S5H1411_IF_44000, + .qam_if = S5H1411_IF_4000, + .inversion = S5H1411_INVERSION_ON, + .status_mode = S5H1411_DEMODLOCKING, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { + .i2c_address = 0x61, + .if_khz = 5380, +}; + +static struct xc5000_config dvico_xc5000_tunerconfig = { + .i2c_address = 0x64, + .if_khz = 5380, +}; + +static struct tda829x_config tda829x_no_probe = { + .probe_tuner = TDA829X_DONT_PROBE, +}; + +static struct tda18271_std_map hauppauge_tda18271_std_map = { + .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, + .if_lvl = 6, .rfagc_top = 0x37 }, + .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, + .if_lvl = 6, .rfagc_top = 0x37 }, +}; + +static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = { + .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, + .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, + .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, +}; + +static struct tda18271_config hauppauge_tda18271_config = { + .std_map = &hauppauge_tda18271_std_map, + .gate = TDA18271_GATE_ANALOG, + .output_opt = TDA18271_OUTPUT_LT_OFF, +}; + +static struct tda18271_config hauppauge_hvr1200_tuner_config = { + .std_map = &hauppauge_hvr1200_tda18271_std_map, + .gate = TDA18271_GATE_ANALOG, + .output_opt = TDA18271_OUTPUT_LT_OFF, +}; + +static struct tda18271_config hauppauge_hvr1210_tuner_config = { + .gate = TDA18271_GATE_DIGITAL, + .output_opt = TDA18271_OUTPUT_LT_OFF, +}; + +static struct tda18271_std_map hauppauge_hvr127x_std_map = { + .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x58 }, + .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x58 }, +}; + +static struct tda18271_config hauppauge_hvr127x_config = { + .std_map = &hauppauge_hvr127x_std_map, + .output_opt = TDA18271_OUTPUT_LT_OFF, +}; + +static struct lgdt3305_config hauppauge_lgdt3305_config = { + .i2c_addr = 0x0e, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .deny_i2c_rptr = 1, + .spectral_inversion = 1, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, +}; + +static struct dibx000_agc_config xc3028_agc_config = { + BAND_VHF | BAND_UHF, /* band_caps */ + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, + * P_agc_nb_est=2, P_agc_write=0 + */ + (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | + (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */ + + 712, /* inv_gain */ + 21, /* time_stabiliz */ + + 0, /* alpha_level */ + 118, /* thlock */ + + 0, /* wbd_inv */ + 2867, /* wbd_ref */ + 0, /* wbd_sel */ + 2, /* wbd_alpha */ + + 0, /* agc1_max */ + 0, /* agc1_min */ + 39718, /* agc2_max */ + 9930, /* agc2_min */ + 0, /* agc1_pt1 */ + 0, /* agc1_pt2 */ + 0, /* agc1_pt3 */ + 0, /* agc1_slope1 */ + 0, /* agc1_slope2 */ + 0, /* agc2_pt1 */ + 128, /* agc2_pt2 */ + 29, /* agc2_slope1 */ + 29, /* agc2_slope2 */ + + 17, /* alpha_mant */ + 27, /* alpha_exp */ + 23, /* beta_mant */ + 51, /* beta_exp */ + + 1, /* perform_agc_softsplit */ +}; + +/* PLL Configuration for COFDM BW_MHz = 8.000000 + * With external clock = 30.000000 */ +static struct dibx000_bandwidth_config xc3028_bw_config = { + 60000, /* internal */ + 30000, /* sampling */ + 1, /* pll_cfg: prediv */ + 8, /* pll_cfg: ratio */ + 3, /* pll_cfg: range */ + 1, /* pll_cfg: reset */ + 0, /* pll_cfg: bypass */ + 0, /* misc: refdiv */ + 0, /* misc: bypclk_div */ + 1, /* misc: IO_CLK_en_core */ + 1, /* misc: ADClkSrc */ + 0, /* misc: modulo */ + (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ + (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ + 20452225, /* timf */ + 30000000 /* xtal_hz */ +}; + +static struct dib7000p_config hauppauge_hvr1400_dib7000_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 0, + .update_lna = NULL, + + .agc_config_count = 1, + .agc = &xc3028_agc_config, + .bw = &xc3028_bw_config, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + .agc_control = NULL, + .spur_protect = 0, + + .output_mode = OUTMODE_MPEG2_SERIAL, +}; + +static struct zl10353_config dvico_fusionhdtv_xc3028 = { + .demod_address = 0x0f, + .if2 = 45600, + .no_tuner = 1, + .disable_i2c_gate_ctrl = 1, +}; + +static struct stv0900_reg stv0900_ts_regs[] = { + { R0900_TSGENERAL, 0x00 }, + { R0900_P1_TSSPEED, 0x40 }, + { R0900_P2_TSSPEED, 0x40 }, + { R0900_P1_TSCFGM, 0xc0 }, + { R0900_P2_TSCFGM, 0xc0 }, + { R0900_P1_TSCFGH, 0xe0 }, + { R0900_P2_TSCFGH, 0xe0 }, + { R0900_P1_TSCFGL, 0x20 }, + { R0900_P2_TSCFGL, 0x20 }, + { 0xffff, 0xff }, /* terminate */ +}; + +static struct stv0900_config netup_stv0900_config = { + .demod_address = 0x68, + .demod_mode = 1, /* dual */ + .xtal = 8000000, + .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ + .diseqc_mode = 2,/* 2/3 PWM */ + .ts_config_regs = stv0900_ts_regs, + .tun1_maddress = 0,/* 0x60 */ + .tun2_maddress = 3,/* 0x63 */ + .tun1_adc = 1,/* 1 Vpp */ + .tun2_adc = 1,/* 1 Vpp */ +}; + +static struct stv6110_config netup_stv6110_tunerconfig_a = { + .i2c_address = 0x60, + .mclk = 16000000, + .clk_div = 1, + .gain = 8, /* +16 dB - maximum gain */ +}; + +static struct stv6110_config netup_stv6110_tunerconfig_b = { + .i2c_address = 0x63, + .mclk = 16000000, + .clk_div = 1, + .gain = 8, /* +16 dB - maximum gain */ +}; + +static struct cx24116_config tbs_cx24116_config = { + .demod_address = 0x55, +}; + +static struct ds3000_config tevii_ds3000_config = { + .demod_address = 0x68, +}; + +static struct cx24116_config dvbworld_cx24116_config = { + .demod_address = 0x05, +}; + +static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = { + .prod = LGS8GXX_PROD_LGS8GL5, + .demod_address = 0x19, + .serial_ts = 0, + .ts_clk_pol = 1, + .ts_clk_gated = 1, + .if_clk_freq = 30400, /* 30.4 MHz */ + .if_freq = 5380, /* 5.38 MHz */ + .if_neg_center = 1, + .ext_adc = 0, + .adc_signed = 0, + .if_neg_edge = 0, +}; + +static struct xc5000_config mygica_x8506_xc5000_config = { + .i2c_address = 0x61, + .if_khz = 5380, +}; + +static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct cx23885_tsport *port = fe->dvb->priv; + struct cx23885_dev *dev = port->dev; + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1275: + switch (param->u.vsb.modulation) { + case VSB_8: + cx23885_gpio_clear(dev, GPIO_5); + break; + case QAM_64: + case QAM_256: + default: + cx23885_gpio_set(dev, GPIO_5); + break; + } + break; + case CX23885_BOARD_MYGICA_X8506: + case CX23885_BOARD_MAGICPRO_PROHDTVE2: + /* Select Digital TV */ + cx23885_gpio_set(dev, GPIO_0); + break; + } + return 0; +} + +static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe, + unsigned int cmd, void *parg, + unsigned int stage) +{ + int err = 0; + + switch (stage) { + case DVB_FE_IOCTL_PRE: + + switch (cmd) { + case FE_SET_FRONTEND: + err = cx23885_dvb_set_frontend(fe, + (struct dvb_frontend_parameters *) parg); + break; + } + break; + + case DVB_FE_IOCTL_POST: + /* no post-ioctl handling required */ + break; + } + return err; +}; + + +static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { + .prod = LGS8GXX_PROD_LGS8G75, + .demod_address = 0x19, + .serial_ts = 0, + .ts_clk_pol = 1, + .ts_clk_gated = 1, + .if_clk_freq = 30400, /* 30.4 MHz */ + .if_freq = 6500, /* 6.50 MHz */ + .if_neg_center = 1, + .ext_adc = 0, + .adc_signed = 1, + .adc_vpp = 2, /* 1.6 Vpp */ + .if_neg_edge = 1, +}; + +static struct xc5000_config magicpro_prohdtve2_xc5000_config = { + .i2c_address = 0x61, + .if_khz = 6500, +}; + +static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = { + .prod = ATBM8830_PROD_8830, + .demod_address = 0x44, + .serial_ts = 0, + .ts_sampling_edge = 1, + .ts_clk_gated = 0, + .osc_clk_freq = 30400, /* in kHz */ + .if_freq = 0, /* zero IF */ + .zif_swap_iq = 1, + .agc_min = 0x2E, + .agc_max = 0xFF, + .agc_hold_loop = 0, +}; + +static struct max2165_config mygic_x8558pro_max2165_cfg1 = { + .i2c_address = 0x60, + .osc_clk = 20 +}; + +static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = { + .prod = ATBM8830_PROD_8830, + .demod_address = 0x44, + .serial_ts = 1, + .ts_sampling_edge = 1, + .ts_clk_gated = 0, + .osc_clk_freq = 30400, /* in kHz */ + .if_freq = 0, /* zero IF */ + .zif_swap_iq = 1, + .agc_min = 0x2E, + .agc_max = 0xFF, + .agc_hold_loop = 0, +}; + +static struct max2165_config mygic_x8558pro_max2165_cfg2 = { + .i2c_address = 0x60, + .osc_clk = 20 +}; +static struct stv0367_config netup_stv0367_config[] = { + { + .demod_address = 0x1c, + .xtal = 27000000, + .if_khz = 4500, + .if_iq_mode = 0, + .ts_mode = 1, + .clk_pol = 0, + }, { + .demod_address = 0x1d, + .xtal = 27000000, + .if_khz = 4500, + .if_iq_mode = 0, + .ts_mode = 1, + .clk_pol = 0, + }, +}; + +static struct xc5000_config netup_xc5000_config[] = { + { + .i2c_address = 0x61, + .if_khz = 4500, + }, { + .i2c_address = 0x64, + .if_khz = 4500, + }, +}; + +int netup_altera_fpga_rw(void *device, int flag, int data, int read) +{ + struct cx23885_dev *dev = (struct cx23885_dev *)device; + unsigned long timeout = jiffies + msecs_to_jiffies(1); + uint32_t mem = 0; + + mem = cx_read(MC417_RWD); + if (read) + cx_set(MC417_OEN, ALT_DATA); + else { + cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */ + mem &= ~ALT_DATA; + mem |= (data & ALT_DATA); + } + + if (flag) + mem |= ALT_AD_RG; + else + mem &= ~ALT_AD_RG; + + mem &= ~ALT_CS; + if (read) + mem = (mem & ~ALT_RD) | ALT_WR; + else + mem = (mem & ~ALT_WR) | ALT_RD; + + cx_write(MC417_RWD, mem); /* start RW cycle */ + + for (;;) { + mem = cx_read(MC417_RWD); + if ((mem & ALT_RDY) == 0) + break; + if (time_after(jiffies, timeout)) + break; + udelay(1); + } + + cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); + if (read) + return mem & ALT_DATA; + + return 0; +}; + +static int dvb_register(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; + struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + int mfe_shared = 0; /* bus not shared by default */ + int ret; + + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + if (!fe0) + return -EINVAL; + + /* init struct videobuf_dvb */ + fe0->dvb.name = dev->name; + + /* multi-frontend gate control is undefined or defaults to fe0 */ + port->frontends.gate = 0; + + /* Sets the gate control callback to be used by i2c command calls */ + port->gate_ctrl = cx23885_dvb_gate_ctrl; + + /* init frontend */ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_generic_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &hauppauge_generic_tunerconfig, 0); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(lgdt3305_attach, + &hauppauge_lgdt3305_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_hvr127x_config); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1255: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &hcw_s5h1411_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_tda18271_config); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + i2c_bus = &dev->i2c_bus[0]; + switch (alt_tuner) { + case 1: + fe0->dvb.frontend = + dvb_attach(s5h1409_attach, + &hauppauge_ezqam_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda829x_attach, fe0->dvb.frontend, + &dev->i2c_bus[1].i2c_adap, 0x42, + &tda829x_no_probe); + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_tda18271_config); + } + break; + case 0: + default: + fe0->dvb.frontend = + dvb_attach(s5h1409_attach, + &hauppauge_generic_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + dvb_attach(mt2131_attach, fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &hauppauge_generic_tunerconfig, 0); + break; + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800lp_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &hauppauge_generic_tunerconfig, 0); + } + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(lgdt330x_attach, + &fusionhdtv_5_express, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &i2c_bus->i2c_adap, 0x61, + TUNER_LG_TDVS_H06XF); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + i2c_bus = &dev->i2c_bus[1]; + fe0->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1500q_config, + &dev->i2c_bus[0].i2c_adap); + if (fe0->dvb.frontend != NULL) + dvb_attach(xc5000_attach, fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &hauppauge_hvr1500q_tunerconfig); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1500: + i2c_bus = &dev->i2c_bus[1]; + fe0->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1500_config, + &dev->i2c_bus[0].i2c_adap); + if (fe0->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &i2c_bus->i2c_adap, + .i2c_addr = 0x61, + }; + static struct xc2028_ctrl ctl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_OREN538, + }; + + fe = dvb_attach(xc2028_attach, + fe0->dvb.frontend, &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctl); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1200: + case CX23885_BOARD_HAUPPAUGE_HVR1700: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(tda10048_attach, + &hauppauge_hvr1200_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda829x_attach, fe0->dvb.frontend, + &dev->i2c_bus[1].i2c_adap, 0x42, + &tda829x_no_probe); + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_hvr1200_tuner_config); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1210: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(tda10048_attach, + &hauppauge_hvr1210_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_hvr1210_tuner_config); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1400: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(dib7000p_attach, + &i2c_bus->i2c_adap, + 0x12, &hauppauge_hvr1400_dib7000_config); + if (fe0->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &dev->i2c_bus[1].i2c_adap, + .i2c_addr = 0x64, + }; + static struct xc2028_ctrl ctl = { + .fname = XC3028L_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = 5000, + /* This is true for all demods with + v36 firmware? */ + .type = XC2028_D2633, + }; + + fe = dvb_attach(xc2028_attach, + fe0->dvb.frontend, &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctl); + } + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + i2c_bus = &dev->i2c_bus[port->nr - 1]; + + fe0->dvb.frontend = dvb_attach(s5h1409_attach, + &dvico_s5h1409_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend == NULL) + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &dvico_s5h1411_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + dvb_attach(xc5000_attach, fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &dvico_xc5000_tunerconfig); + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: { + i2c_bus = &dev->i2c_bus[port->nr - 1]; + + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &dvico_fusionhdtv_xc3028, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &i2c_bus->i2c_adap, + .i2c_addr = 0x61, + }; + static struct xc2028_ctrl ctl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_ZARLINK456, + }; + + fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, + &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctl); + } + break; + } + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: + case CX23885_BOARD_COMPRO_VIDEOMATE_E800: + i2c_bus = &dev->i2c_bus[0]; + + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &dvico_fusionhdtv_xc3028, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &dev->i2c_bus[1].i2c_adap, + .i2c_addr = 0x61, + }; + static struct xc2028_ctrl ctl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_ZARLINK456, + }; + + fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, + &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctl); + } + break; + case CX23885_BOARD_TBS_6920: + i2c_bus = &dev->i2c_bus[1]; + + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &tbs_cx24116_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; + + break; + case CX23885_BOARD_TEVII_S470: + i2c_bus = &dev->i2c_bus[1]; + + fe0->dvb.frontend = dvb_attach(ds3000_attach, + &tevii_ds3000_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; + + break; + case CX23885_BOARD_DVBWORLD_2005: + i2c_bus = &dev->i2c_bus[1]; + + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &dvbworld_cx24116_config, + &i2c_bus->i2c_adap); + break; + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: + i2c_bus = &dev->i2c_bus[0]; + switch (port->nr) { + /* port B */ + case 1: + fe0->dvb.frontend = dvb_attach(stv0900_attach, + &netup_stv0900_config, + &i2c_bus->i2c_adap, 0); + if (fe0->dvb.frontend != NULL) { + if (dvb_attach(stv6110_attach, + fe0->dvb.frontend, + &netup_stv6110_tunerconfig_a, + &i2c_bus->i2c_adap)) { + if (!dvb_attach(lnbh24_attach, + fe0->dvb.frontend, + &i2c_bus->i2c_adap, + LNBH24_PCL | LNBH24_TTX, + LNBH24_TEN, 0x09)) + printk(KERN_ERR + "No LNBH24 found!\n"); + + } + } + break; + /* port C */ + case 2: + fe0->dvb.frontend = dvb_attach(stv0900_attach, + &netup_stv0900_config, + &i2c_bus->i2c_adap, 1); + if (fe0->dvb.frontend != NULL) { + if (dvb_attach(stv6110_attach, + fe0->dvb.frontend, + &netup_stv6110_tunerconfig_b, + &i2c_bus->i2c_adap)) { + if (!dvb_attach(lnbh24_attach, + fe0->dvb.frontend, + &i2c_bus->i2c_adap, + LNBH24_PCL | LNBH24_TTX, + LNBH24_TEN, 0x0a)) + printk(KERN_ERR + "No LNBH24 found!\n"); + + } + } + break; + } + break; + case CX23885_BOARD_MYGICA_X8506: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, + &mygica_x8506_lgs8gl5_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(xc5000_attach, + fe0->dvb.frontend, + &i2c_bus2->i2c_adap, + &mygica_x8506_xc5000_config); + } + break; + case CX23885_BOARD_MAGICPRO_PROHDTVE2: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, + &magicpro_prohdtve2_lgs8g75_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(xc5000_attach, + fe0->dvb.frontend, + &i2c_bus2->i2c_adap, + &magicpro_prohdtve2_xc5000_config); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &hcw_s5h1411_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[0].i2c_adap, + &hauppauge_tda18271_config); + break; + case CX23885_BOARD_MYGICA_X8558PRO: + switch (port->nr) { + /* port B */ + case 1: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(atbm8830_attach, + &mygica_x8558pro_atbm8830_cfg1, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(max2165_attach, + fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &mygic_x8558pro_max2165_cfg1); + } + break; + /* port C */ + case 2: + i2c_bus = &dev->i2c_bus[1]; + fe0->dvb.frontend = dvb_attach(atbm8830_attach, + &mygica_x8558pro_atbm8830_cfg2, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(max2165_attach, + fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &mygic_x8558pro_max2165_cfg2); + } + break; + } + break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + i2c_bus = &dev->i2c_bus[0]; + mfe_shared = 1;/* MFE */ + port->frontends.gate = 0;/* not clear for me yet */ + /* ports B, C */ + /* MFE frontend 1 DVB-T */ + fe0->dvb.frontend = dvb_attach(stv0367ter_attach, + &netup_stv0367_config[port->nr - 1], + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (NULL == dvb_attach(xc5000_attach, + fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &netup_xc5000_config[port->nr - 1])) + goto frontend_detach; + /* load xc5000 firmware */ + fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend); + } + /* MFE frontend 2 */ + fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); + if (fe1 == NULL) + goto frontend_detach; + /* DVB-C init */ + fe1->dvb.frontend = dvb_attach(stv0367cab_attach, + &netup_stv0367_config[port->nr - 1], + &i2c_bus->i2c_adap); + if (fe1->dvb.frontend != NULL) { + fe1->dvb.frontend->id = 1; + if (NULL == dvb_attach(xc5000_attach, + fe1->dvb.frontend, + &i2c_bus->i2c_adap, + &netup_xc5000_config[port->nr - 1])) + goto frontend_detach; + } + break; + default: + printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " + " isn't supported yet\n", + dev->name); + break; + } + + if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) { + printk(KERN_ERR "%s: frontend initialization failed\n", + dev->name); + goto frontend_detach; + } + + /* define general-purpose callback pointer */ + fe0->dvb.frontend->callback = cx23885_tuner_callback; + if (fe1) + fe1->dvb.frontend->callback = cx23885_tuner_callback; +#if 0 + /* Ensure all frontends negotiate bus access */ + fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; + if (fe1) + fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; +#endif + + /* Put the analog decoder in standby to keep it quiet */ + call_all(dev, core, s_power, 0); + + if (fe0->dvb.frontend->ops.analog_ops.standby) + fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); + + /* register everything */ + ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, + &dev->pci->dev, adapter_nr, mfe_shared, + cx23885_dvb_fe_ioctl_override); + if (ret) + goto frontend_detach; + + /* init CI & MAC */ + switch (dev->board) { + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: { + static struct netup_card_info cinfo; + + netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); + memcpy(port->frontends.adapter.proposed_mac, + cinfo.port[port->nr - 1].mac, 6); + printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", + port->nr, port->frontends.adapter.proposed_mac); + + netup_ci_init(port); + break; + } + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { + struct altera_ci_config netup_ci_cfg = { + .dev = dev,/* magic number to identify*/ + .adapter = &port->frontends.adapter,/* for CI */ + .demux = &fe0->dvb.demux,/* for hw pid filter */ + .fpga_rw = netup_altera_fpga_rw, + }; + + altera_ci_init(&netup_ci_cfg, port->nr); + break; + } + case CX23885_BOARD_TEVII_S470: { + u8 eeprom[256]; /* 24C02 i2c eeprom */ + + if (port->nr != 1) + break; + + /* Read entire EEPROM */ + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); + printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0); + memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); + break; + } + } + + return ret; + +frontend_detach: + port->gate_ctrl = NULL; + videobuf_dvb_dealloc_frontends(&port->frontends); + return -EINVAL; +} + +int cx23885_dvb_register(struct cx23885_tsport *port) +{ + + struct videobuf_dvb_frontend *fe0; + struct cx23885_dev *dev = port->dev; + int err, i; + + /* Here we need to allocate the correct number of frontends, + * as reflected in the cards struct. The reality is that currently + * no cx23885 boards support this - yet. But, if we don't modify this + * code then the second frontend would never be allocated (later) + * and fail with error before the attach in dvb_register(). + * Without these changes we risk an OOPS later. The changes here + * are for safety, and should provide a good foundation for the + * future addition of any multi-frontend cx23885 based boards. + */ + printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, + port->num_frontends); + + for (i = 1; i <= port->num_frontends; i++) { + if (videobuf_dvb_alloc_frontend( + &port->frontends, i) == NULL) { + printk(KERN_ERR "%s() failed to alloc\n", __func__); + return -ENOMEM; + } + + fe0 = videobuf_dvb_get_frontend(&port->frontends, i); + if (!fe0) + err = -EINVAL; + + dprintk(1, "%s\n", __func__); + dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n", + dev->board, + dev->name, + dev->pci_bus, + dev->pci_slot); + + err = -ENODEV; + + /* dvb stuff */ + /* We have to init the queue for each frontend on a port. */ + printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name); + videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, + &dev->pci->dev, &port->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, + sizeof(struct cx23885_buffer), port, NULL); + } + err = dvb_register(port); + if (err != 0) + printk(KERN_ERR "%s() dvb_register failed err = %d\n", + __func__, err); + + return err; +} + +int cx23885_dvb_unregister(struct cx23885_tsport *port) +{ + struct videobuf_dvb_frontend *fe0; + + /* FIXME: in an error condition where the we have + * an expected number of frontends (attach problem) + * then this might not clean up correctly, if 1 + * is invalid. + * This comment only applies to future boards IF they + * implement MFE support. + */ + fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + if (fe0->dvb.frontend) + videobuf_dvb_unregister_bus(&port->frontends); + + switch (port->dev->board) { + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: + netup_ci_exit(port); + break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + altera_ci_release(port->dev, port->nr); + break; + } + + port->gate_ctrl = NULL; + + return 0; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-f300.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-f300.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-f300.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-f300.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,177 @@ +/* + * Driver for Silicon Labs C8051F300 microcontroller. + * + * It is used for LNB power control in TeVii S470, + * TBS 6920 PCIe DVB-S2 cards. + * + * Microcontroller connected to cx23885 GPIO pins: + * GPIO0 - data - P0.3 F300 + * GPIO1 - reset - P0.2 F300 + * GPIO2 - clk - P0.1 F300 + * GPIO3 - busy - P0.0 F300 + * + * Copyright (C) 2009 Igor M. Liplianin + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx23885.h" + +#define F300_DATA GPIO_0 +#define F300_RESET GPIO_1 +#define F300_CLK GPIO_2 +#define F300_BUSY GPIO_3 + +static void f300_set_line(struct cx23885_dev *dev, u32 line, u8 lvl) +{ + cx23885_gpio_enable(dev, line, 1); + if (lvl == 1) + cx23885_gpio_set(dev, line); + else + cx23885_gpio_clear(dev, line); +} + +static u8 f300_get_line(struct cx23885_dev *dev, u32 line) +{ + cx23885_gpio_enable(dev, line, 0); + + return cx23885_gpio_get(dev, line); +} + +static void f300_send_byte(struct cx23885_dev *dev, u8 dta) +{ + u8 i; + + for (i = 0; i < 8; i++) { + f300_set_line(dev, F300_CLK, 0); + udelay(30); + f300_set_line(dev, F300_DATA, (dta & 0x80) >> 7);/* msb first */ + udelay(30); + dta <<= 1; + f300_set_line(dev, F300_CLK, 1); + udelay(30); + } +} + +static u8 f300_get_byte(struct cx23885_dev *dev) +{ + u8 i, dta = 0; + + for (i = 0; i < 8; i++) { + f300_set_line(dev, F300_CLK, 0); + udelay(30); + dta <<= 1; + f300_set_line(dev, F300_CLK, 1); + udelay(30); + dta |= f300_get_line(dev, F300_DATA);/* msb first */ + + } + + return dta; +} + +static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf) +{ + struct cx23885_tsport *port = fe->dvb->priv; + struct cx23885_dev *dev = port->dev; + u8 i, temp, ret = 0; + + temp = buf[0]; + for (i = 0; i < buf[0]; i++) + temp += buf[i + 1]; + temp = (~temp + 1);/* get check sum */ + buf[1 + buf[0]] = temp; + + f300_set_line(dev, F300_RESET, 1); + f300_set_line(dev, F300_CLK, 1); + udelay(30); + f300_set_line(dev, F300_DATA, 1); + msleep(1); + + /* question: */ + f300_set_line(dev, F300_RESET, 0);/* begin to send data */ + msleep(1); + + f300_send_byte(dev, 0xe0);/* the slave address is 0xe0, write */ + msleep(1); + + temp = buf[0]; + temp += 2; + for (i = 0; i < temp; i++) + f300_send_byte(dev, buf[i]); + + f300_set_line(dev, F300_RESET, 1);/* sent data over */ + f300_set_line(dev, F300_DATA, 1); + + /* answer: */ + temp = 0; + for (i = 0; ((i < 8) & (temp == 0)); i++) { + msleep(1); + if (f300_get_line(dev, F300_BUSY) == 0) + temp = 1; + } + + if (i > 7) { + printk(KERN_ERR "%s: timeout, the slave no response\n", + __func__); + ret = 1; /* timeout, the slave no response */ + } else { /* the slave not busy, prepare for getting data */ + f300_set_line(dev, F300_RESET, 0);/*ready...*/ + msleep(1); + f300_send_byte(dev, 0xe1);/* 0xe1 is Read */ + msleep(1); + temp = f300_get_byte(dev);/*get the data length */ + if (temp > 14) + temp = 14; + + for (i = 0; i < (temp + 1); i++) + f300_get_byte(dev);/* get data to empty buffer */ + + f300_set_line(dev, F300_RESET, 1);/* received data over */ + f300_set_line(dev, F300_DATA, 1); + } + + return ret; +} + +int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + u8 buf[16]; + + buf[0] = 0x05; + buf[1] = 0x38;/* write port */ + buf[2] = 0x01;/* A port, lnb power */ + + switch (voltage) { + case SEC_VOLTAGE_13: + buf[3] = 0x01;/* power on */ + buf[4] = 0x02;/* B port, H/V */ + buf[5] = 0x00;/*13V v*/ + break; + case SEC_VOLTAGE_18: + buf[3] = 0x01; + buf[4] = 0x02; + buf[5] = 0x01;/* 18V h*/ + break; + case SEC_VOLTAGE_OFF: + buf[3] = 0x00;/* power off */ + buf[4] = 0x00; + buf[5] = 0x00; + break; + } + + return f300_xfer(fe, buf); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-f300.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-f300.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-f300.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-f300.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,2 @@ +extern int f300_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,583 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "btcx-risc.h" +#include "cx23885-reg.h" +#include "media/cx2341x.h" + +#include +#include + +#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 2) + +#define UNSET (-1U) + +#define CX23885_MAXBOARDS 8 + +/* Max number of inputs by card */ +#define MAX_CX23885_INPUT 8 +#define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 + +#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ + +#define CX23885_BOARD_NOAUTO UNSET +#define CX23885_BOARD_UNKNOWN 0 +#define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 +#define CX23885_BOARD_HAUPPAUGE_HVR1800 2 +#define CX23885_BOARD_HAUPPAUGE_HVR1250 3 +#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 +#define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 +#define CX23885_BOARD_HAUPPAUGE_HVR1500 6 +#define CX23885_BOARD_HAUPPAUGE_HVR1200 7 +#define CX23885_BOARD_HAUPPAUGE_HVR1700 8 +#define CX23885_BOARD_HAUPPAUGE_HVR1400 9 +#define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10 +#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11 +#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12 +#define CX23885_BOARD_COMPRO_VIDEOMATE_E650F 13 +#define CX23885_BOARD_TBS_6920 14 +#define CX23885_BOARD_TEVII_S470 15 +#define CX23885_BOARD_DVBWORLD_2005 16 +#define CX23885_BOARD_NETUP_DUAL_DVBS2_CI 17 +#define CX23885_BOARD_HAUPPAUGE_HVR1270 18 +#define CX23885_BOARD_HAUPPAUGE_HVR1275 19 +#define CX23885_BOARD_HAUPPAUGE_HVR1255 20 +#define CX23885_BOARD_HAUPPAUGE_HVR1210 21 +#define CX23885_BOARD_MYGICA_X8506 22 +#define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 +#define CX23885_BOARD_HAUPPAUGE_HVR1850 24 +#define CX23885_BOARD_COMPRO_VIDEOMATE_E800 25 +#define CX23885_BOARD_HAUPPAUGE_HVR1290 26 +#define CX23885_BOARD_MYGICA_X8558PRO 27 +#define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28 +#define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29 +#define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 + +#define GPIO_0 0x00000001 +#define GPIO_1 0x00000002 +#define GPIO_2 0x00000004 +#define GPIO_3 0x00000008 +#define GPIO_4 0x00000010 +#define GPIO_5 0x00000020 +#define GPIO_6 0x00000040 +#define GPIO_7 0x00000080 +#define GPIO_8 0x00000100 +#define GPIO_9 0x00000200 +#define GPIO_10 0x00000400 +#define GPIO_11 0x00000800 +#define GPIO_12 0x00001000 +#define GPIO_13 0x00002000 +#define GPIO_14 0x00004000 +#define GPIO_15 0x00008000 + +/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ +#define CX23885_NORMS (\ + V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \ + V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ + V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ + V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) + +struct cx23885_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 cxformat; +}; + +struct cx23885_ctrl { + struct v4l2_queryctrl v; + u32 off; + u32 reg; + u32 mask; + u32 shift; +}; + +struct cx23885_tvnorm { + char *name; + v4l2_std_id id; + u32 cxiformat; + u32 cxoformat; +}; + +struct cx23885_fh { + struct cx23885_dev *dev; + enum v4l2_buf_type type; + int radio; + u32 resources; + + /* video overlay */ + struct v4l2_window win; + struct v4l2_clip *clips; + unsigned int nclips; + + /* video capture */ + struct cx23885_fmt *fmt; + unsigned int width, height; + + /* vbi capture */ + struct videobuf_queue vidq; + struct videobuf_queue vbiq; + + /* MPEG Encoder specifics ONLY */ + struct videobuf_queue mpegq; + atomic_t v4l_reading; +}; + +enum cx23885_itype { + CX23885_VMUX_COMPOSITE1 = 1, + CX23885_VMUX_COMPOSITE2, + CX23885_VMUX_COMPOSITE3, + CX23885_VMUX_COMPOSITE4, + CX23885_VMUX_SVIDEO, + CX23885_VMUX_COMPONENT, + CX23885_VMUX_TELEVISION, + CX23885_VMUX_CABLE, + CX23885_VMUX_DVB, + CX23885_VMUX_DEBUG, + CX23885_RADIO, +}; + +enum cx23885_src_sel_type { + CX23885_SRC_SEL_EXT_656_VIDEO = 0, + CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO +}; + +/* buffer for one video frame */ +struct cx23885_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* cx23885 specific */ + unsigned int bpl; + struct btcx_riscmem risc; + struct cx23885_fmt *fmt; + u32 count; +}; + +struct cx23885_input { + enum cx23885_itype type; + unsigned int vmux; + u32 gpio0, gpio1, gpio2, gpio3; +}; + +typedef enum { + CX23885_MPEG_UNDEFINED = 0, + CX23885_MPEG_DVB, + CX23885_ANALOG_VIDEO, + CX23885_MPEG_ENCODER, +} port_t; + +struct cx23885_board { + char *name; + port_t porta, portb, portc; + int num_fds_portb, num_fds_portc; + unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + unsigned int tuner_bus; + + /* Vendors can and do run the PCIe bridge at different + * clock rates, driven physically by crystals on the PCBs. + * The core has to accommodate this. This allows the user + * to add new boards with new frequencys. The value is + * expressed in Hz. + * + * The core framework will default this value based on + * current designs, but it can vary. + */ + u32 clk_freq; + struct cx23885_input input[MAX_CX23885_INPUT]; + int ci_type; /* for NetUP */ +}; + +struct cx23885_subid { + u16 subvendor; + u16 subdevice; + u32 card; +}; + +struct cx23885_i2c { + struct cx23885_dev *dev; + + int nr; + + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + u32 i2c_rc; + + /* 885 registers used for raw addess */ + u32 i2c_period; + u32 reg_ctrl; + u32 reg_stat; + u32 reg_addr; + u32 reg_rdata; + u32 reg_wdata; +}; + +struct cx23885_dmaqueue { + struct list_head active; + struct list_head queued; + struct timer_list timeout; + struct btcx_riscmem stopper; + u32 count; +}; + +struct cx23885_tsport { + struct cx23885_dev *dev; + + int nr; + int sram_chno; + + struct videobuf_dvb_frontends frontends; + + /* dma queues */ + struct cx23885_dmaqueue mpegq; + u32 ts_packet_size; + u32 ts_packet_count; + + int width; + int height; + + spinlock_t slock; + + /* registers */ + u32 reg_gpcnt; + u32 reg_gpcnt_ctl; + u32 reg_dma_ctl; + u32 reg_lngth; + u32 reg_hw_sop_ctrl; + u32 reg_gen_ctrl; + u32 reg_bd_pkt_status; + u32 reg_sop_status; + u32 reg_fifo_ovfl_stat; + u32 reg_vld_misc; + u32 reg_ts_clk_en; + u32 reg_ts_int_msk; + u32 reg_ts_int_stat; + u32 reg_src_sel; + + /* Default register vals */ + int pci_irqmask; + u32 dma_ctl_val; + u32 ts_int_msk_val; + u32 gen_ctrl_val; + u32 ts_clk_en_val; + u32 src_sel_val; + u32 vld_misc_val; + u32 hw_sop_ctrl_val; + + /* Allow a single tsport to have multiple frontends */ + u32 num_frontends; + void (*gate_ctrl)(struct cx23885_tsport *port, int open); + void *port_priv; +}; + +struct cx23885_kernel_ir { + struct cx23885_dev *cx; + char *name; + char *phys; + + struct rc_dev *rc; +}; + +struct cx23885_dev { + atomic_t refcount; + struct v4l2_device v4l2_dev; + + /* pci stuff */ + struct pci_dev *pci; + unsigned char pci_rev, pci_lat; + int pci_bus, pci_slot; + u32 __iomem *lmmio; + u8 __iomem *bmmio; + int pci_irqmask; + spinlock_t pci_irqmask_lock; /* protects mask reg too */ + int hwrevision; + + /* This valud is board specific and is used to configure the + * AV core so we see nice clean and stable video and audio. */ + u32 clk_freq; + + /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ + struct cx23885_i2c i2c_bus[3]; + + int nr; + struct mutex lock; + struct mutex gpio_lock; + + /* board details */ + unsigned int board; + char name[32]; + + struct cx23885_tsport ts1, ts2; + + /* sram configuration */ + struct sram_channel *sram_channels; + + enum { + CX23885_BRIDGE_UNDEFINED = 0, + CX23885_BRIDGE_885 = 885, + CX23885_BRIDGE_887 = 887, + CX23885_BRIDGE_888 = 888, + } bridge; + + /* Analog video */ + u32 resources; + unsigned int input; + u32 tvaudio; + v4l2_std_id tvnorm; + unsigned int tuner_type; + unsigned char tuner_addr; + unsigned int tuner_bus; + unsigned int radio_type; + unsigned char radio_addr; + unsigned int has_radio; + struct v4l2_subdev *sd_cx25840; + struct work_struct cx25840_work; + + /* Infrared */ + struct v4l2_subdev *sd_ir; + struct work_struct ir_rx_work; + unsigned long ir_rx_notifications; + struct work_struct ir_tx_work; + unsigned long ir_tx_notifications; + + struct cx23885_kernel_ir *kernel_ir; + atomic_t ir_input_stopping; + + /* V4l */ + u32 freq; + struct video_device *video_dev; + struct video_device *vbi_dev; + struct video_device *radio_dev; + + struct cx23885_dmaqueue vidq; + struct cx23885_dmaqueue vbiq; + spinlock_t slock; + + /* MPEG Encoder ONLY settings */ + u32 cx23417_mailbox; + struct cx2341x_mpeg_params mpeg_params; + struct video_device *v4l_device; + atomic_t v4l_reader_count; + struct cx23885_tvnorm encodernorm; + +}; + +static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct cx23885_dev, v4l2_dev); +} + +#define call_all(dev, o, f, args...) \ + v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) + +#define CX23885_HW_888_IR (1 << 0) +#define CX23885_HW_AV_CORE (1 << 1) + +#define call_hw(dev, grpid, o, f, args...) \ + v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args) + +extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw); + +#define SRAM_CH01 0 /* Video A */ +#define SRAM_CH02 1 /* VBI A */ +#define SRAM_CH03 2 /* Video B */ +#define SRAM_CH04 3 /* Transport via B */ +#define SRAM_CH05 4 /* VBI B */ +#define SRAM_CH06 5 /* Video C */ +#define SRAM_CH07 6 /* Transport via C */ +#define SRAM_CH08 7 /* Audio Internal A */ +#define SRAM_CH09 8 /* Audio Internal B */ +#define SRAM_CH10 9 /* Audio External */ +#define SRAM_CH11 10 /* COMB_3D_N */ +#define SRAM_CH12 11 /* Comb 3D N1 */ +#define SRAM_CH13 12 /* Comb 3D N2 */ +#define SRAM_CH14 13 /* MOE Vid */ +#define SRAM_CH15 14 /* MOE RSLT */ + +struct sram_channel { + char *name; + u32 cmds_start; + u32 ctrl_start; + u32 cdt; + u32 fifo_start; + u32 fifo_size; + u32 ptr1_reg; + u32 ptr2_reg; + u32 cnt1_reg; + u32 cnt2_reg; + u32 jumponly; +}; + +/* ----------------------------------------------------------- */ + +#define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) +#define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) + +#define cx_andor(reg, mask, value) \ + writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ + ((value) & (mask)), dev->lmmio+((reg)>>2)) + +#define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) +#define cx_clear(reg, bit) cx_andor((reg), (bit), 0) + +/* ----------------------------------------------------------- */ +/* cx23885-core.c */ + +extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc); + +extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch); + +extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); + +extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines); + +void cx23885_cancel_buffers(struct cx23885_tsport *port); + +extern int cx23885_restart_queue(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q); + +extern void cx23885_wakeup(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, u32 count); + +extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); +extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); +extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask); +extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, + int asoutput); + +extern void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask); +extern void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask); +extern void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask); +extern void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask); + +/* ----------------------------------------------------------- */ +/* cx23885-cards.c */ +extern struct cx23885_board cx23885_boards[]; +extern const unsigned int cx23885_bcount; + +extern struct cx23885_subid cx23885_subids[]; +extern const unsigned int cx23885_idcount; + +extern int cx23885_tuner_callback(void *priv, int component, + int command, int arg); +extern void cx23885_card_list(struct cx23885_dev *dev); +extern int cx23885_ir_init(struct cx23885_dev *dev); +extern void cx23885_ir_pci_int_enable(struct cx23885_dev *dev); +extern void cx23885_ir_fini(struct cx23885_dev *dev); +extern void cx23885_gpio_setup(struct cx23885_dev *dev); +extern void cx23885_card_setup(struct cx23885_dev *dev); +extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); + +extern int cx23885_dvb_register(struct cx23885_tsport *port); +extern int cx23885_dvb_unregister(struct cx23885_tsport *port); + +extern int cx23885_buf_prepare(struct videobuf_queue *q, + struct cx23885_tsport *port, + struct cx23885_buffer *buf, + enum v4l2_field field); +extern void cx23885_buf_queue(struct cx23885_tsport *port, + struct cx23885_buffer *buf); +extern void cx23885_free_buffer(struct videobuf_queue *q, + struct cx23885_buffer *buf); + +/* ----------------------------------------------------------- */ +/* cx23885-video.c */ +/* Video */ +extern int cx23885_video_register(struct cx23885_dev *dev); +extern void cx23885_video_unregister(struct cx23885_dev *dev); +extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); + +/* ----------------------------------------------------------- */ +/* cx23885-vbi.c */ +extern int cx23885_vbi_fmt(struct file *file, void *priv, + struct v4l2_format *f); +extern void cx23885_vbi_timeout(unsigned long data); +extern struct videobuf_queue_ops cx23885_vbi_qops; + +/* cx23885-i2c.c */ +extern int cx23885_i2c_register(struct cx23885_i2c *bus); +extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); +extern void cx23885_av_clk(struct cx23885_dev *dev, int enable); + +/* ----------------------------------------------------------- */ +/* cx23885-417.c */ +extern int cx23885_417_register(struct cx23885_dev *dev); +extern void cx23885_417_unregister(struct cx23885_dev *dev); +extern int cx23885_irq_417(struct cx23885_dev *dev, u32 status); +extern void cx23885_417_check_encoder(struct cx23885_dev *dev); +extern void cx23885_mc417_init(struct cx23885_dev *dev); +extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value); +extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value); +extern int mc417_register_read(struct cx23885_dev *dev, + u16 address, u32 *value); +extern int mc417_register_write(struct cx23885_dev *dev, + u16 address, u32 value); +extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask); +extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask); +extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput); + + +/* ----------------------------------------------------------- */ +/* tv norms */ + +static inline unsigned int norm_maxw(v4l2_std_id norm) +{ + return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; +} + +static inline unsigned int norm_maxh(v4l2_std_id norm) +{ + return (norm & V4L2_STD_625_50) ? 576 : 480; +} + +static inline unsigned int norm_swidth(v4l2_std_id norm) +{ + return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-i2c.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,401 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "cx23885.h" + +#include + +static unsigned int i2c_debug; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + +static unsigned int i2c_scan; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); + +#define dprintk(level, fmt, arg...)\ + do { if (i2c_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) + +#define I2C_WAIT_DELAY 32 +#define I2C_WAIT_RETRY 64 + +#define I2C_EXTEND (1 << 3) +#define I2C_NOSTOP (1 << 4) + +static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x01; +} + +static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; +} + +static int i2c_wait_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_is_busy(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int joined_rlen) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + u32 wdata, addr, ctrl; + int retval, cnt; + + if (joined_rlen) + dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__, + msg->len, joined_rlen); + else + dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len); + + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); + if (!i2c_wait_done(i2c_adap)) + return -EIO; + if (!i2c_slave_did_ack(i2c_adap)) + return -ENXIO; + + dprintk(1, "%s() returns 0\n", __func__); + return 0; + } + + + /* dev, reg + first byte */ + addr = (msg->addr << 25) | msg->buf[0]; + wdata = msg->buf[0]; + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (msg->len > 1) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + else if (joined_rlen) + ctrl |= I2C_NOSTOP; + + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + if (!i2c_wait_done(i2c_adap)) + goto eio; + if (i2c_debug) { + printk(" addr << 1, msg->buf[0]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + + for (cnt = 1; cnt < msg->len; cnt++) { + /* following bytes */ + wdata = msg->buf[cnt]; + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (cnt < msg->len - 1) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + else if (joined_rlen) + ctrl |= I2C_NOSTOP; + + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + if (!i2c_wait_done(i2c_adap)) + goto eio; + if (i2c_debug) { + dprintk(1, " %02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + dprintk(1, " >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + if (i2c_debug) + printk(KERN_ERR " ERR: %d\n", retval); + return retval; +} + +static int i2c_readbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int joined) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + u32 ctrl, cnt; + int retval; + + + if (i2c_debug && !joined) + dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len); + + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); + if (!i2c_wait_done(i2c_adap)) + return -EIO; + if (!i2c_slave_did_ack(i2c_adap)) + return -ENXIO; + + + dprintk(1, "%s() returns 0\n", __func__); + return 0; + } + + if (i2c_debug) { + if (joined) + dprintk(1, " R"); + else + dprintk(1, " addr << 1) + 1); + } + + for (cnt = 0; cnt < msg->len; cnt++) { + + ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; + + if (cnt < msg->len - 1) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, ctrl); + + if (!i2c_wait_done(i2c_adap)) + goto eio; + msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; + if (i2c_debug) { + dprintk(1, " %02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + dprintk(1, " >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + if (i2c_debug) + printk(KERN_ERR " ERR: %d\n", retval); + return retval; +} + +static int i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + int i, retval = 0; + + dprintk(1, "%s(num = %d)\n", __func__, num); + + for (i = 0 ; i < num; i++) { + dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n", + __func__, num, msgs[i].addr, msgs[i].len); + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = i2c_readbytes(i2c_adap, &msgs[i], 0); + } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && + msgs[i].addr == msgs[i + 1].addr) { + /* write then read from same address */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], + msgs[i + 1].len); + if (retval < 0) + goto err; + i++; + retval = i2c_readbytes(i2c_adap, &msgs[i], 1); + } else { + /* write */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); + } + if (retval < 0) + goto err; + } + return num; + + err: + return retval; +} + +static u32 cx23885_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; +} + +static struct i2c_algorithm cx23885_i2c_algo_template = { + .master_xfer = i2c_xfer, + .functionality = cx23885_functionality, +}; + +/* ----------------------------------------------------------------------- */ + +static struct i2c_adapter cx23885_i2c_adap_template = { + .name = "cx23885", + .owner = THIS_MODULE, + .algo = &cx23885_i2c_algo_template, +}; + +static struct i2c_client cx23885_i2c_client_template = { + .name = "cx23885 internal", +}; + +static char *i2c_devs[128] = { + [0x10 >> 1] = "tda10048", + [0x12 >> 1] = "dib7000pc", + [0x1c >> 1] = "lgdt3303", + [0x86 >> 1] = "tda9887", + [0x32 >> 1] = "cx24227", + [0x88 >> 1] = "cx25837", + [0x84 >> 1] = "tda8295", + [0xa0 >> 1] = "eeprom", + [0xc0 >> 1] = "tuner/mt2131/tda8275", + [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028", + [0xc8 >> 1] = "tuner/xc3028L", +}; + +static void do_i2c_scan(char *name, struct i2c_client *c) +{ + unsigned char buf; + int i, rc; + + for (i = 0; i < 128; i++) { + c->addr = i; + rc = i2c_master_recv(c, &buf, 0); + if (rc < 0) + continue; + printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + } +} + +/* init + register i2c algo-bit adapter */ +int cx23885_i2c_register(struct cx23885_i2c *bus) +{ + struct cx23885_dev *dev = bus->dev; + + dprintk(1, "%s(bus = %d)\n", __func__, bus->nr); + + memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, + sizeof(bus->i2c_adap)); + memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, + sizeof(bus->i2c_algo)); + memcpy(&bus->i2c_client, &cx23885_i2c_client_template, + sizeof(bus->i2c_client)); + + bus->i2c_adap.dev.parent = &dev->pci->dev; + + strlcpy(bus->i2c_adap.name, bus->dev->name, + sizeof(bus->i2c_adap.name)); + + bus->i2c_algo.data = bus; + bus->i2c_adap.algo_data = bus; + i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); + i2c_add_adapter(&bus->i2c_adap); + + bus->i2c_client.adapter = &bus->i2c_adap; + + if (0 == bus->i2c_rc) { + dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr); + if (i2c_scan) { + printk(KERN_INFO "%s: scan bus %d:\n", + dev->name, bus->nr); + do_i2c_scan(dev->name, &bus->i2c_client); + } + } else + printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", + dev->name, bus->nr); + + /* Instantiate the IR receiver device, if present */ + if (0 == bus->i2c_rc) { + struct i2c_board_info info; + const unsigned short addr_list[] = { + 0x6b, I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + /* Use quick read command for probe, some IR chips don't + * support writes */ + i2c_new_probed_device(&bus->i2c_adap, &info, addr_list, + i2c_probe_func_quick_read); + } + + return bus->i2c_rc; +} + +int cx23885_i2c_unregister(struct cx23885_i2c *bus) +{ + i2c_del_adapter(&bus->i2c_adap); + return 0; +} + +void cx23885_av_clk(struct cx23885_dev *dev, int enable) +{ + /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ + char buffer[3]; + struct i2c_msg msg; + dprintk(1, "%s(enabled = %d)\n", __func__, enable); + + /* Register 0x144 */ + buffer[0] = 0x01; + buffer[1] = 0x44; + if (enable == 1) + buffer[2] = 0x05; + else + buffer[2] = 0x00; + + msg.addr = 0x44; + msg.flags = I2C_M_TEN; + msg.len = 3; + msg.buf = buffer; + + i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); +} + +/* ----------------------------------------------------------------------- */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-input.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-input.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,356 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * Infrared remote control input device + * + * Most of this file is + * + * Copyright (C) 2009 Andy Walls + * + * However, the cx23885_input_{init,fini} functions contained herein are + * derived from Linux kernel files linux/media/video/.../...-input.c marked as: + * + * Copyright (C) 2008 + * Copyright (C) 2005 Ludovico Cavedon + * Markus Rechberger + * Mauro Carvalho Chehab + * Sascha Sommer + * Copyright (C) 2004, 2005 Chris Pascoe + * Copyright (C) 2003, 2004 Gerd Knorr + * Copyright (C) 2003 Pavel Machek + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include + +#include "cx23885.h" + +#define MODULE_NAME "cx23885" + +static void cx23885_input_process_measurements(struct cx23885_dev *dev, + bool overrun) +{ + struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir; + + ssize_t num; + int count, i; + bool handle = false; + struct ir_raw_event ir_core_event[64]; + + do { + num = 0; + v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event, + sizeof(ir_core_event), &num); + + count = num / sizeof(struct ir_raw_event); + + for (i = 0; i < count; i++) { + ir_raw_event_store(kernel_ir->rc, + &ir_core_event[i]); + handle = true; + } + } while (num != 0); + + if (overrun) + ir_raw_event_reset(kernel_ir->rc); + else if (handle) + ir_raw_event_handle(kernel_ir->rc); +} + +void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) +{ + struct v4l2_subdev_ir_parameters params; + int overrun, data_available; + + if (dev->sd_ir == NULL || events == 0) + return; + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* + * The only boards we handle right now. However other boards + * using the CX2388x integrated IR controller should be similar + */ + break; + default: + return; + } + + overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN | + V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN); + + data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED | + V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ); + + if (overrun) { + /* If there was a FIFO overrun, stop the device */ + v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); + params.enable = false; + /* Mitigate race with cx23885_input_ir_stop() */ + params.shutdown = atomic_read(&dev->ir_input_stopping); + v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); + } + + if (data_available) + cx23885_input_process_measurements(dev, overrun); + + if (overrun) { + /* If there was a FIFO overrun, clear & restart the device */ + params.enable = true; + /* Mitigate race with cx23885_input_ir_stop() */ + params.shutdown = atomic_read(&dev->ir_input_stopping); + v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); + } +} + +static int cx23885_input_ir_start(struct cx23885_dev *dev) +{ + struct v4l2_subdev_ir_parameters params; + + if (dev->sd_ir == NULL) + return -ENODEV; + + atomic_set(&dev->ir_input_stopping, 0); + + v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* + * The IR controller on this board only returns pulse widths. + * Any other mode setting will fail to set up the device. + */ + params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; + params.enable = true; + params.interrupt_enable = true; + params.shutdown = false; + + /* Setup for baseband compatible with both RC-5 and RC-6A */ + params.modulation = false; + /* RC-5: 2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/ + /* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/ + params.max_pulse_width = 3333333; /* ns */ + /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ + /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ + params.noise_filter_min_width = 333333; /* ns */ + /* + * This board has inverted receive sense: + * mark is received as low logic level; + * falling edges are detected as rising edges; etc. + */ + params.invert_level = true; + break; + case CX23885_BOARD_TEVII_S470: + /* + * The IR controller on this board only returns pulse widths. + * Any other mode setting will fail to set up the device. + */ + params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; + params.enable = true; + params.interrupt_enable = true; + params.shutdown = false; + + /* Setup for a standard NEC protocol */ + params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */ + params.carrier_range_lower = 33000; /* Hz */ + params.carrier_range_upper = 43000; /* Hz */ + params.duty_cycle = 33; /* percent, 33 percent for NEC */ + + /* + * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units + * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns + */ + params.max_pulse_width = 12378022; /* ns */ + + /* + * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit + * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns + */ + params.noise_filter_min_width = 351648; /* ns */ + + params.modulation = false; + params.invert_level = true; + break; + } + v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); + return 0; +} + +static int cx23885_input_ir_open(struct rc_dev *rc) +{ + struct cx23885_kernel_ir *kernel_ir = rc->priv; + + if (kernel_ir->cx == NULL) + return -ENODEV; + + return cx23885_input_ir_start(kernel_ir->cx); +} + +static void cx23885_input_ir_stop(struct cx23885_dev *dev) +{ + struct v4l2_subdev_ir_parameters params; + + if (dev->sd_ir == NULL) + return; + + /* + * Stop the sd_ir subdevice from generating notifications and + * scheduling work. + * It is shutdown this way in order to mitigate a race with + * cx23885_input_rx_work_handler() in the overrun case, which could + * re-enable the subdevice. + */ + atomic_set(&dev->ir_input_stopping, 1); + v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); + while (params.shutdown == false) { + params.enable = false; + params.interrupt_enable = false; + params.shutdown = true; + v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); + v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); + } + flush_work_sync(&dev->cx25840_work); + flush_work_sync(&dev->ir_rx_work); + flush_work_sync(&dev->ir_tx_work); +} + +static void cx23885_input_ir_close(struct rc_dev *rc) +{ + struct cx23885_kernel_ir *kernel_ir = rc->priv; + + if (kernel_ir->cx != NULL) + cx23885_input_ir_stop(kernel_ir->cx); +} + +int cx23885_input_init(struct cx23885_dev *dev) +{ + struct cx23885_kernel_ir *kernel_ir; + struct rc_dev *rc; + char *rc_map; + enum rc_driver_type driver_type; + unsigned long allowed_protos; + + int ret; + + /* + * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't + * encapsulated in a v4l2_subdev, then I'm not going to deal with it. + */ + if (dev->sd_ir == NULL) + return -ENODEV; + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* Integrated CX2388[58] IR controller */ + driver_type = RC_DRIVER_IR_RAW; + allowed_protos = RC_TYPE_ALL; + /* The grey Hauppauge RC-5 remote */ + rc_map = RC_MAP_HAUPPAUGE; + break; + case CX23885_BOARD_TEVII_S470: + /* Integrated CX23885 IR controller */ + driver_type = RC_DRIVER_IR_RAW; + allowed_protos = RC_TYPE_ALL; + /* A guess at the remote */ + rc_map = RC_MAP_TEVII_NEC; + break; + default: + return -ENODEV; + } + + /* cx23885 board instance kernel IR state */ + kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL); + if (kernel_ir == NULL) + return -ENOMEM; + + kernel_ir->cx = dev; + kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)", + cx23885_boards[dev->board].name); + kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0", + pci_name(dev->pci)); + + /* input device */ + rc = rc_allocate_device(); + if (!rc) { + ret = -ENOMEM; + goto err_out_free; + } + + kernel_ir->rc = rc; + rc->input_name = kernel_ir->name; + rc->input_phys = kernel_ir->phys; + rc->input_id.bustype = BUS_PCI; + rc->input_id.version = 1; + if (dev->pci->subsystem_vendor) { + rc->input_id.vendor = dev->pci->subsystem_vendor; + rc->input_id.product = dev->pci->subsystem_device; + } else { + rc->input_id.vendor = dev->pci->vendor; + rc->input_id.product = dev->pci->device; + } + rc->dev.parent = &dev->pci->dev; + rc->driver_type = driver_type; + rc->allowed_protos = allowed_protos; + rc->priv = kernel_ir; + rc->open = cx23885_input_ir_open; + rc->close = cx23885_input_ir_close; + rc->map_name = rc_map; + rc->driver_name = MODULE_NAME; + + /* Go */ + dev->kernel_ir = kernel_ir; + ret = rc_register_device(rc); + if (ret) + goto err_out_stop; + + return 0; + +err_out_stop: + cx23885_input_ir_stop(dev); + dev->kernel_ir = NULL; + rc_free_device(rc); +err_out_free: + kfree(kernel_ir->phys); + kfree(kernel_ir->name); + kfree(kernel_ir); + return ret; +} + +void cx23885_input_fini(struct cx23885_dev *dev) +{ + /* Always stop the IR hardware from generating interrupts */ + cx23885_input_ir_stop(dev); + + if (dev->kernel_ir == NULL) + return; + rc_unregister_device(dev->kernel_ir->rc); + kfree(dev->kernel_ir->phys); + kfree(dev->kernel_ir->name); + kfree(dev->kernel_ir); + dev->kernel_ir = NULL; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-input.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-input.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-input.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-input.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * Infrared remote control input device + * + * Copyright (C) 2009 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef _CX23885_INPUT_H_ +#define _CX23885_INPUT_H_ +int cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events); + +int cx23885_input_init(struct cx23885_dev *dev); +void cx23885_input_fini(struct cx23885_dev *dev); +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ioctl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ioctl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ioctl.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ioctl.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,208 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * Various common ioctl() support functions + * + * Copyright (c) 2009 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx23885.h" +#include + +int cx23885_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + int err = 0; + u8 rev; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + switch (chip->match.type) { + case V4L2_CHIP_MATCH_HOST: + switch (chip->match.addr) { + case 0: + rev = cx_read(RDR_CFG2) & 0xff; + switch (dev->pci->device) { + case 0x8852: + /* rev 0x04 could be '885 or '888. Pick '888. */ + if (rev == 0x04) + chip->ident = V4L2_IDENT_CX23888; + else + chip->ident = V4L2_IDENT_CX23885; + break; + case 0x8880: + if (rev == 0x0e || rev == 0x0f) + chip->ident = V4L2_IDENT_CX23887; + else + chip->ident = V4L2_IDENT_CX23888; + break; + default: + chip->ident = V4L2_IDENT_UNKNOWN; + break; + } + chip->revision = (dev->pci->device << 16) | (rev << 8) | + (dev->hwrevision & 0xff); + break; + case 1: + if (dev->v4l_device != NULL) { + chip->ident = V4L2_IDENT_CX23417; + chip->revision = 0; + } + break; + case 2: + /* + * The integrated IR controller on the CX23888 is + * host chip 2. It may not be used/initialized or sd_ir + * may be pointing at the cx25840 subdevice for the + * IR controller on the CX23885. Thus we find it + * without using the dev->sd_ir pointer. + */ + call_hw(dev, CX23885_HW_888_IR, core, g_chip_ident, + chip); + break; + default: + err = -EINVAL; /* per V4L2 spec */ + break; + } + break; + case V4L2_CHIP_MATCH_I2C_DRIVER: + /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */ + call_all(dev, core, g_chip_ident, chip); + break; + case V4L2_CHIP_MATCH_I2C_ADDR: + /* + * We could return V4L2_IDENT_UNKNOWN, but we don't do the work + * to look if a chip is at the address with no driver. That's a + * dangerous thing to do with EEPROMs anyway. + */ + call_all(dev, core, g_chip_ident, chip); + break; + default: + err = -EINVAL; + break; + } + return err; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cx23885_g_host_register(struct cx23885_dev *dev, + struct v4l2_dbg_register *reg) +{ + if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) + return -EINVAL; + + reg->size = 4; + reg->val = cx_read(reg->reg); + return 0; +} + +static int cx23417_g_register(struct cx23885_dev *dev, + struct v4l2_dbg_register *reg) +{ + u32 value; + + if (dev->v4l_device == NULL) + return -EINVAL; + + if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) + return -EINVAL; + + if (mc417_register_read(dev, (u16) reg->reg, &value)) + return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ + + reg->size = 4; + reg->val = value; + return 0; +} + +int cx23885_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (reg->match.type == V4L2_CHIP_MATCH_HOST) { + switch (reg->match.addr) { + case 0: + return cx23885_g_host_register(dev, reg); + case 1: + return cx23417_g_register(dev, reg); + default: + break; + } + } + + /* FIXME - any error returns should not be ignored */ + call_all(dev, core, g_register, reg); + return 0; +} + +static int cx23885_s_host_register(struct cx23885_dev *dev, + struct v4l2_dbg_register *reg) +{ + if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) + return -EINVAL; + + reg->size = 4; + cx_write(reg->reg, reg->val); + return 0; +} + +static int cx23417_s_register(struct cx23885_dev *dev, + struct v4l2_dbg_register *reg) +{ + if (dev->v4l_device == NULL) + return -EINVAL; + + if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) + return -EINVAL; + + if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val)) + return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ + + reg->size = 4; + return 0; +} + +int cx23885_s_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (reg->match.type == V4L2_CHIP_MATCH_HOST) { + switch (reg->match.addr) { + case 0: + return cx23885_s_host_register(dev, reg); + case 1: + return cx23417_s_register(dev, reg); + default: + break; + } + } + + /* FIXME - any error returns should not be ignored */ + call_all(dev, core, s_register, reg); + return 0; +} +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ioctl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ioctl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ioctl.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ioctl.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * Various common ioctl() support functions + * + * Copyright (c) 2009 Andy Walls + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CX23885_IOCTL_H_ +#define _CX23885_IOCTL_H_ + +int cx23885_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip); + +#ifdef CONFIG_VIDEO_ADV_DEBUG +int cx23885_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg); + + +int cx23885_s_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg); + +#endif +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ir.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,117 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * Infrared device support routines - non-input, non-vl42_subdev routines + * + * Copyright (C) 2009 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include + +#include "cx23885.h" +#include "cx23885-input.h" + +#define CX23885_IR_RX_FIFO_SERVICE_REQ 0 +#define CX23885_IR_RX_END_OF_RX_DETECTED 1 +#define CX23885_IR_RX_HW_FIFO_OVERRUN 2 +#define CX23885_IR_RX_SW_FIFO_OVERRUN 3 + +#define CX23885_IR_TX_FIFO_SERVICE_REQ 0 + + +void cx23885_ir_rx_work_handler(struct work_struct *work) +{ + struct cx23885_dev *dev = + container_of(work, struct cx23885_dev, ir_rx_work); + u32 events = 0; + unsigned long *notifications = &dev->ir_rx_notifications; + + if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications)) + events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; + if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications)) + events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; + if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications)) + events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; + if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications)) + events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; + + if (events == 0) + return; + + if (dev->kernel_ir) + cx23885_input_rx_work_handler(dev, events); +} + +void cx23885_ir_tx_work_handler(struct work_struct *work) +{ + struct cx23885_dev *dev = + container_of(work, struct cx23885_dev, ir_tx_work); + u32 events = 0; + unsigned long *notifications = &dev->ir_tx_notifications; + + if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications)) + events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; + + if (events == 0) + return; + +} + +/* Possibly called in an IRQ context */ +void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) +{ + struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); + unsigned long *notifications = &dev->ir_rx_notifications; + + if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ) + set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications); + if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED) + set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications); + if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN) + set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications); + if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN) + set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications); + + /* + * For the integrated AV core, we are already in a workqueue context. + * For the CX23888 integrated IR, we are in an interrupt context. + */ + if (sd == dev->sd_cx25840) + cx23885_ir_rx_work_handler(&dev->ir_rx_work); + else + schedule_work(&dev->ir_rx_work); +} + +/* Possibly called in an IRQ context */ +void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) +{ + struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); + unsigned long *notifications = &dev->ir_tx_notifications; + + if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ) + set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications); + + /* + * For the integrated AV core, we are already in a workqueue context. + * For the CX23888 integrated IR, we are in an interrupt context. + */ + if (sd == dev->sd_cx25840) + cx23885_ir_tx_work_handler(&dev->ir_tx_work); + else + schedule_work(&dev->ir_tx_work); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ir.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-ir.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * Infrared device support routines - non-input, non-vl42_subdev routines + * + * Copyright (C) 2009 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef _CX23885_IR_H_ +#define _CX23885_IR_H_ +void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events); +void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events); + +void cx23885_ir_rx_work_handler(struct work_struct *work); +void cx23885_ir_tx_work_handler(struct work_struct *work); +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,449 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CX23885_REG_H_ +#define _CX23885_REG_H_ + +/* +Address Map +0x00000000 -> 0x00009000 TX SRAM (Fifos) +0x00010000 -> 0x00013c00 RX SRAM CMDS + CDT + +EACH CMDS struct is 0x80 bytes long + +DMAx_PTR1 = 0x03040 address of first cluster +DMAx_PTR2 = 0x10600 address of the CDT +DMAx_CNT1 = cluster size in (bytes >> 4) -1 +DMAx_CNT2 = total cdt size for all entries >> 3 + +Cluster Descriptor entry = 4 DWORDS + DWORD 0 -> ptr to cluster + DWORD 1 Reserved + DWORD 2 Reserved + DWORD 3 Reserved + +Channel manager Data Structure entry = 20 DWORD + 0 IntialProgramCounterLow + 1 IntialProgramCounterHigh + 2 ClusterDescriptorTableBase + 3 ClusterDescriptorTableSize + 4 InstructionQueueBase + 5 InstructionQueueSize +... Reserved + 19 Reserved +*/ + +/* Risc Instructions */ +#define RISC_CNT_INC 0x00010000 +#define RISC_CNT_RESET 0x00030000 +#define RISC_IRQ1 0x01000000 +#define RISC_IRQ2 0x02000000 +#define RISC_EOL 0x04000000 +#define RISC_SOL 0x08000000 +#define RISC_WRITE 0x10000000 +#define RISC_SKIP 0x20000000 +#define RISC_JUMP 0x70000000 +#define RISC_SYNC 0x80000000 +#define RISC_RESYNC 0x80008000 +#define RISC_READ 0x90000000 +#define RISC_WRITERM 0xB0000000 +#define RISC_WRITECM 0xC0000000 +#define RISC_WRITECR 0xD0000000 +#define RISC_WRITEC 0x50000000 +#define RISC_READC 0xA0000000 + + +/* Audio and Video Core */ +#define HOST_REG1 0x00000000 +#define HOST_REG2 0x00000001 +#define HOST_REG3 0x00000002 + +/* Chip Configuration Registers */ +#define CHIP_CTRL 0x00000100 +#define AFE_CTRL 0x00000104 +#define VID_PLL_INT_POST 0x00000108 +#define VID_PLL_FRAC 0x0000010C +#define AUX_PLL_INT_POST 0x00000110 +#define AUX_PLL_FRAC 0x00000114 +#define SYS_PLL_INT_POST 0x00000118 +#define SYS_PLL_FRAC 0x0000011C +#define PIN_CTRL 0x00000120 +#define AUD_IO_CTRL 0x00000124 +#define AUD_LOCK1 0x00000128 +#define AUD_LOCK2 0x0000012C +#define POWER_CTRL 0x00000130 +#define AFE_DIAG_CTRL1 0x00000134 +#define AFE_DIAG_CTRL3 0x0000013C +#define PLL_DIAG_CTRL 0x00000140 +#define AFE_CLK_OUT_CTRL 0x00000144 +#define DLL1_DIAG_CTRL 0x0000015C + +/* GPIO[23:19] Output Enable */ +#define GPIO2_OUT_EN_REG 0x00000160 +/* GPIO[23:19] Data Registers */ +#define GPIO2 0x00000164 + +#define IFADC_CTRL 0x00000180 + +/* Infrared Remote Registers */ +#define IR_CNTRL_REG 0x00000200 +#define IR_TXCLK_REG 0x00000204 +#define IR_RXCLK_REG 0x00000208 +#define IR_CDUTY_REG 0x0000020C +#define IR_STAT_REG 0x00000210 +#define IR_IRQEN_REG 0x00000214 +#define IR_FILTR_REG 0x00000218 +#define IR_FIFO_REG 0x0000023C + +/* Video Decoder Registers */ +#define MODE_CTRL 0x00000400 +#define OUT_CTRL1 0x00000404 +#define OUT_CTRL2 0x00000408 +#define GEN_STAT 0x0000040C +#define INT_STAT_MASK 0x00000410 +#define LUMA_CTRL 0x00000414 +#define HSCALE_CTRL 0x00000418 +#define VSCALE_CTRL 0x0000041C +#define CHROMA_CTRL 0x00000420 +#define VBI_LINE_CTRL1 0x00000424 +#define VBI_LINE_CTRL2 0x00000428 +#define VBI_LINE_CTRL3 0x0000042C +#define VBI_LINE_CTRL4 0x00000430 +#define VBI_LINE_CTRL5 0x00000434 +#define VBI_FC_CFG 0x00000438 +#define VBI_MISC_CFG1 0x0000043C +#define VBI_MISC_CFG2 0x00000440 +#define VBI_PAY1 0x00000444 +#define VBI_PAY2 0x00000448 +#define VBI_CUST1_CFG1 0x0000044C +#define VBI_CUST1_CFG2 0x00000450 +#define VBI_CUST1_CFG3 0x00000454 +#define VBI_CUST2_CFG1 0x00000458 +#define VBI_CUST2_CFG2 0x0000045C +#define VBI_CUST2_CFG3 0x00000460 +#define VBI_CUST3_CFG1 0x00000464 +#define VBI_CUST3_CFG2 0x00000468 +#define VBI_CUST3_CFG3 0x0000046C +#define HORIZ_TIM_CTRL 0x00000470 +#define VERT_TIM_CTRL 0x00000474 +#define SRC_COMB_CFG 0x00000478 +#define CHROMA_VBIOFF_CFG 0x0000047C +#define FIELD_COUNT 0x00000480 +#define MISC_TIM_CTRL 0x00000484 +#define DFE_CTRL1 0x00000488 +#define DFE_CTRL2 0x0000048C +#define DFE_CTRL3 0x00000490 +#define PLL_CTRL 0x00000494 +#define HTL_CTRL 0x00000498 +#define COMB_CTRL 0x0000049C +#define CRUSH_CTRL 0x000004A0 +#define SOFT_RST_CTRL 0x000004A4 +#define CX885_VERSION 0x000004B4 +#define VBI_PASS_CTRL 0x000004BC + +/* Audio Decoder Registers */ +/* 8051 Configuration */ +#define DL_CTL 0x00000800 +#define STD_DET_STATUS 0x00000804 +#define STD_DET_CTL 0x00000808 +#define DW8051_INT 0x0000080C +#define GENERAL_CTL 0x00000810 +#define AAGC_CTL 0x00000814 +#define DEMATRIX_CTL 0x000008CC +#define PATH1_CTL1 0x000008D0 +#define PATH1_VOL_CTL 0x000008D4 +#define PATH1_EQ_CTL 0x000008D8 +#define PATH1_SC_CTL 0x000008DC +#define PATH2_CTL1 0x000008E0 +#define PATH2_VOL_CTL 0x000008E4 +#define PATH2_EQ_CTL 0x000008E8 +#define PATH2_SC_CTL 0x000008EC + +/* Sample Rate Converter */ +#define SRC_CTL 0x000008F0 +#define SRC_LF_COEF 0x000008F4 +#define SRC1_CTL 0x000008F8 +#define SRC2_CTL 0x000008FC +#define SRC3_CTL 0x00000900 +#define SRC4_CTL 0x00000904 +#define SRC5_CTL 0x00000908 +#define SRC6_CTL 0x0000090C +#define BAND_OUT_SEL 0x00000910 +#define I2S_N_CTL 0x00000914 +#define I2S_OUT_CTL 0x00000918 +#define AUTOCONFIG_REG 0x000009C4 + +/* Audio ADC Registers */ +#define DSM_CTRL1 0x00000000 +#define DSM_CTRL2 0x00000001 +#define CHP_EN_CTRL 0x00000002 +#define CHP_CLK_CTRL1 0x00000004 +#define CHP_CLK_CTRL2 0x00000005 +#define BG_REF_CTRL 0x00000006 +#define SD2_SW_CTRL1 0x00000008 +#define SD2_SW_CTRL2 0x00000009 +#define SD2_BIAS_CTRL 0x0000000A +#define AMP_BIAS_CTRL 0x0000000C +#define CH_PWR_CTRL1 0x0000000E +#define CH_PWR_CTRL2 0x0000000F +#define DSM_STATUS1 0x00000010 +#define DSM_STATUS2 0x00000011 +#define DIG_CTL1 0x00000012 +#define DIG_CTL2 0x00000013 +#define I2S_TX_CFG 0x0000001A + +#define DEV_CNTRL2 0x00040000 + +#define PCI_MSK_IR (1 << 28) +#define PCI_MSK_AV_CORE (1 << 27) +#define PCI_MSK_GPIO1 (1 << 24) +#define PCI_MSK_GPIO0 (1 << 23) +#define PCI_MSK_APB_DMA (1 << 12) +#define PCI_MSK_AL_WR (1 << 11) +#define PCI_MSK_AL_RD (1 << 10) +#define PCI_MSK_RISC_WR (1 << 9) +#define PCI_MSK_RISC_RD (1 << 8) +#define PCI_MSK_AUD_EXT (1 << 4) +#define PCI_MSK_AUD_INT (1 << 3) +#define PCI_MSK_VID_C (1 << 2) +#define PCI_MSK_VID_B (1 << 1) +#define PCI_MSK_VID_A 1 +#define PCI_INT_MSK 0x00040010 + +#define PCI_INT_STAT 0x00040014 +#define PCI_INT_MSTAT 0x00040018 + +#define VID_A_INT_MSK 0x00040020 +#define VID_A_INT_STAT 0x00040024 +#define VID_A_INT_MSTAT 0x00040028 +#define VID_A_INT_SSTAT 0x0004002C + +#define VID_B_INT_MSK 0x00040030 +#define VID_B_MSK_BAD_PKT (1 << 20) +#define VID_B_MSK_VBI_OPC_ERR (1 << 17) +#define VID_B_MSK_OPC_ERR (1 << 16) +#define VID_B_MSK_VBI_SYNC (1 << 13) +#define VID_B_MSK_SYNC (1 << 12) +#define VID_B_MSK_VBI_OF (1 << 9) +#define VID_B_MSK_OF (1 << 8) +#define VID_B_MSK_VBI_RISCI2 (1 << 5) +#define VID_B_MSK_RISCI2 (1 << 4) +#define VID_B_MSK_VBI_RISCI1 (1 << 1) +#define VID_B_MSK_RISCI1 1 +#define VID_B_INT_STAT 0x00040034 +#define VID_B_INT_MSTAT 0x00040038 +#define VID_B_INT_SSTAT 0x0004003C + +#define VID_B_MSK_BAD_PKT (1 << 20) +#define VID_B_MSK_OPC_ERR (1 << 16) +#define VID_B_MSK_SYNC (1 << 12) +#define VID_B_MSK_OF (1 << 8) +#define VID_B_MSK_RISCI2 (1 << 4) +#define VID_B_MSK_RISCI1 1 + +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 + +/* A superset for testing purposes */ +#define VID_BC_MSK_BAD_PKT (1 << 20) +#define VID_BC_MSK_OPC_ERR (1 << 16) +#define VID_BC_MSK_SYNC (1 << 12) +#define VID_BC_MSK_OF (1 << 8) +#define VID_BC_MSK_RISCI2 (1 << 4) +#define VID_BC_MSK_RISCI1 1 + +#define VID_C_INT_MSK 0x00040040 +#define VID_C_INT_STAT 0x00040044 +#define VID_C_INT_MSTAT 0x00040048 +#define VID_C_INT_SSTAT 0x0004004C + +#define AUDIO_INT_INT_MSK 0x00040050 +#define AUDIO_INT_INT_STAT 0x00040054 +#define AUDIO_INT_INT_MSTAT 0x00040058 +#define AUDIO_INT_INT_SSTAT 0x0004005C + +#define AUDIO_EXT_INT_MSK 0x00040060 +#define AUDIO_EXT_INT_STAT 0x00040064 +#define AUDIO_EXT_INT_MSTAT 0x00040068 +#define AUDIO_EXT_INT_SSTAT 0x0004006C + +#define RDR_CFG0 0x00050000 +#define RDR_CFG1 0x00050004 +#define RDR_CFG2 0x00050008 +#define RDR_RDRCTL1 0x0005030c +#define RDR_TLCTL0 0x00050318 + +/* APB DMAC Current Buffer Pointer */ +#define DMA1_PTR1 0x00100000 +#define DMA2_PTR1 0x00100004 +#define DMA3_PTR1 0x00100008 +#define DMA4_PTR1 0x0010000C +#define DMA5_PTR1 0x00100010 +#define DMA6_PTR1 0x00100014 +#define DMA7_PTR1 0x00100018 +#define DMA8_PTR1 0x0010001C + +/* APB DMAC Current Table Pointer */ +#define DMA1_PTR2 0x00100040 +#define DMA2_PTR2 0x00100044 +#define DMA3_PTR2 0x00100048 +#define DMA4_PTR2 0x0010004C +#define DMA5_PTR2 0x00100050 +#define DMA6_PTR2 0x00100054 +#define DMA7_PTR2 0x00100058 +#define DMA8_PTR2 0x0010005C + +/* APB DMAC Buffer Limit */ +#define DMA1_CNT1 0x00100080 +#define DMA2_CNT1 0x00100084 +#define DMA3_CNT1 0x00100088 +#define DMA4_CNT1 0x0010008C +#define DMA5_CNT1 0x00100090 +#define DMA6_CNT1 0x00100094 +#define DMA7_CNT1 0x00100098 +#define DMA8_CNT1 0x0010009C + +/* APB DMAC Table Size */ +#define DMA1_CNT2 0x001000C0 +#define DMA2_CNT2 0x001000C4 +#define DMA3_CNT2 0x001000C8 +#define DMA4_CNT2 0x001000CC +#define DMA5_CNT2 0x001000D0 +#define DMA6_CNT2 0x001000D4 +#define DMA7_CNT2 0x001000D8 +#define DMA8_CNT2 0x001000DC + +/* Timer Counters */ +#define TM_CNT_LDW 0x00110000 +#define TM_CNT_UW 0x00110004 +#define TM_LMT_LDW 0x00110008 +#define TM_LMT_UW 0x0011000C + +/* GPIO */ +#define GP0_IO 0x00110010 +#define GPIO_ISM 0x00110014 +#define SOFT_RESET 0x0011001C + +/* GPIO (417 Microsoftcontroller) RW Data */ +#define MC417_RWD 0x00110020 + +/* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ +#define MC417_OEN 0x00110024 +#define MC417_CTL 0x00110028 +#define ALT_PIN_OUT_SEL 0x0011002C +#define CLK_DELAY 0x00110048 +#define PAD_CTRL 0x0011004C + +/* Video A Interface */ +#define VID_A_GPCNT 0x00130020 +#define VBI_A_GPCNT 0x00130024 +#define VID_A_GPCNT_CTL 0x00130030 +#define VBI_A_GPCNT_CTL 0x00130034 +#define VID_A_DMA_CTL 0x00130040 +#define VID_A_VIP_CTRL 0x00130080 +#define VID_A_PIXEL_FRMT 0x00130084 +#define VID_A_VBI_CTRL 0x00130088 + +/* Video B Interface */ +#define VID_B_DMA 0x00130100 +#define VBI_B_DMA 0x00130108 +#define VID_B_GPCNT 0x00130120 +#define VBI_B_GPCNT 0x00130124 +#define VID_B_GPCNT_CTL 0x00130134 +#define VBI_B_GPCNT_CTL 0x00130138 +#define VID_B_DMA_CTL 0x00130140 +#define VID_B_SRC_SEL 0x00130144 +#define VID_B_LNGTH 0x00130150 +#define VID_B_HW_SOP_CTL 0x00130154 +#define VID_B_GEN_CTL 0x00130158 +#define VID_B_BD_PKT_STATUS 0x0013015C +#define VID_B_SOP_STATUS 0x00130160 +#define VID_B_FIFO_OVFL_STAT 0x00130164 +#define VID_B_VLD_MISC 0x00130168 +#define VID_B_TS_CLK_EN 0x0013016C +#define VID_B_VIP_CTRL 0x00130180 +#define VID_B_PIXEL_FRMT 0x00130184 + +/* Video C Interface */ +#define VID_C_GPCNT 0x00130220 +#define VID_C_GPCNT_CTL 0x00130230 +#define VBI_C_GPCNT_CTL 0x00130234 +#define VID_C_DMA_CTL 0x00130240 +#define VID_C_LNGTH 0x00130250 +#define VID_C_HW_SOP_CTL 0x00130254 +#define VID_C_GEN_CTL 0x00130258 +#define VID_C_BD_PKT_STATUS 0x0013025C +#define VID_C_SOP_STATUS 0x00130260 +#define VID_C_FIFO_OVFL_STAT 0x00130264 +#define VID_C_VLD_MISC 0x00130268 +#define VID_C_TS_CLK_EN 0x0013026C + +/* Internal Audio Interface */ +#define AUD_INT_A_GPCNT 0x00140020 +#define AUD_INT_B_GPCNT 0x00140024 +#define AUD_INT_A_GPCNT_CTL 0x00140030 +#define AUD_INT_B_GPCNT_CTL 0x00140034 +#define AUD_INT_DMA_CTL 0x00140040 +#define AUD_INT_A_LNGTH 0x00140050 +#define AUD_INT_B_LNGTH 0x00140054 +#define AUD_INT_A_MODE 0x00140058 +#define AUD_INT_B_MODE 0x0014005C + +/* External Audio Interface */ +#define AUD_EXT_DMA 0x00140100 +#define AUD_EXT_GPCNT 0x00140120 +#define AUD_EXT_GPCNT_CTL 0x00140130 +#define AUD_EXT_DMA_CTL 0x00140140 +#define AUD_EXT_LNGTH 0x00140150 +#define AUD_EXT_A_MODE 0x00140158 + +/* I2C Bus 1 */ +#define I2C1_ADDR 0x00180000 +#define I2C1_WDATA 0x00180004 +#define I2C1_CTRL 0x00180008 +#define I2C1_RDATA 0x0018000C +#define I2C1_STAT 0x00180010 + +/* I2C Bus 2 */ +#define I2C2_ADDR 0x00190000 +#define I2C2_WDATA 0x00190004 +#define I2C2_CTRL 0x00190008 +#define I2C2_RDATA 0x0019000C +#define I2C2_STAT 0x00190010 + +/* I2C Bus 3 */ +#define I2C3_ADDR 0x001A0000 +#define I2C3_WDATA 0x001A0004 +#define I2C3_CTRL 0x001A0008 +#define I2C3_RDATA 0x001A000C +#define I2C3_STAT 0x001A0010 + +/* UART */ +#define UART_CTL 0x001B0000 +#define UART_BRD 0x001B0004 +#define UART_ISR 0x001B000C +#define UART_CNT 0x001B0010 + +#endif /* _CX23885_REG_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-vbi.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,247 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2007 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "cx23885.h" + +static unsigned int vbibufs = 4; +module_param(vbibufs, int, 0644); +MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); + +static unsigned int vbi_debug; +module_param(vbi_debug, int, 0644); +MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); + +#define dprintk(level, fmt, arg...)\ + do { if (vbi_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) + +/* ------------------------------------------------------------------ */ + +int cx23885_vbi_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (dev->tvnorm & V4L2_STD_525_60) { + /* ntsc */ + f->fmt.vbi.sampling_rate = 28636363; + f->fmt.vbi.start[0] = 10; + f->fmt.vbi.start[1] = 273; + + } else if (dev->tvnorm & V4L2_STD_625_50) { + /* pal */ + f->fmt.vbi.sampling_rate = 35468950; + f->fmt.vbi.start[0] = 7 - 1; + f->fmt.vbi.start[1] = 319 - 1; + } + return 0; +} + +static int cx23885_start_vbi_dma(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], + buf->vb.width, buf->risc.dma); + + /* reset counter */ + q->count = 1; + + /* enable irqs */ + cx23885_irq_add_enable(dev, 0x01); + cx_set(VID_A_INT_MSK, 0x000022); + + /* start dma */ + cx_set(DEV_CNTRL2, (1<<5)); + cx_set(VID_A_DMA_CTL, 0x00000022); + + return 0; +} + + +static int cx23885_restart_vbi_queue(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q) +{ + struct cx23885_buffer *buf; + struct list_head *item; + + if (list_empty(&q->active)) + return 0; + + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + dprintk(2, "restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_vbi_dma(dev, q, buf); + list_for_each(item, &q->active) { + buf = list_entry(item, struct cx23885_buffer, vb.queue); + buf->count = q->count++; + } + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +void cx23885_vbi_timeout(unsigned long data) +{ + struct cx23885_dev *dev = (struct cx23885_dev *)data; + struct cx23885_dmaqueue *q = &dev->vbiq; + struct cx23885_buffer *buf; + unsigned long flags; + + cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]); + + cx_clear(VID_A_DMA_CTL, 0x22); + + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, + buf, buf->vb.i, (unsigned long)buf->risc.dma); + } + cx23885_restart_vbi_queue(dev, q); + spin_unlock_irqrestore(&dev->slock, flags); +} + +/* ------------------------------------------------------------------ */ +#define VBI_LINE_LENGTH 2048 +#define VBI_LINE_COUNT 17 + +static int +vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; + if (0 == *count) + *count = vbibufs; + if (*count < 2) + *count = 2; + if (*count > 32) + *count = 32; + return 0; +} + +static int +vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + unsigned int size; + int rc; + + size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + buf->vb.width = VBI_LINE_LENGTH; + buf->vb.height = VBI_LINE_COUNT; + buf->vb.size = size; + buf->vb.field = V4L2_FIELD_SEQ_TB; + + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) + goto fail; + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->vb.width * buf->vb.height, + buf->vb.width, 0, + buf->vb.height); + } + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q, buf); + return rc; +} + +static void +vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + struct cx23885_buffer *prev; + struct cx23885_fh *fh = vq->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_dmaqueue *q = &dev->vbiq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (list_empty(&q->active)) { + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_vbi_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] vbi_queue - first active\n", + buf, buf->vb.i); + + } else { + prev = list_entry(q->active.prev, struct cx23885_buffer, + vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.i); + } +} + +static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + + cx23885_free_buffer(q, buf); +} + +struct videobuf_queue_ops cx23885_vbi_qops = { + .buf_setup = vbi_setup, + .buf_prepare = vbi_prepare, + .buf_queue = vbi_queue, + .buf_release = vbi_release, +}; + +/* ------------------------------------------------------------------ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-video.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23885-video.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1534 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2007 Steven Toth + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" +#include +#include +#include "cx23885-ioctl.h" +#include "tuner-xc2028.h" + +MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); +MODULE_AUTHOR("Steven Toth "); +MODULE_LICENSE("GPL"); + +/* ------------------------------------------------------------------ */ + +static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; + +module_param_array(video_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); + +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); + +static unsigned int video_debug; +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); + +static unsigned int irq_debug; +module_param(irq_debug, int, 0644); +MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); + +static unsigned int vid_limit = 16; +module_param(vid_limit, int, 0644); +MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); + +#define dprintk(level, fmt, arg...)\ + do { if (video_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) + +/* ------------------------------------------------------------------- */ +/* static data */ + +#define FORMAT_FLAGS_PACKED 0x01 + +static struct cx23885_fmt formats[] = { + { + .name = "8 bpp, gray", + .fourcc = V4L2_PIX_FMT_GREY, + .depth = 8, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "15 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB555, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "15 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB555X, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "16 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "16 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB565X, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "24 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR24, + .depth = 24, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "32 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR32, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "32 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, +}; + +static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (formats[i].fourcc == fourcc) + return formats+i; + + printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc); + return NULL; +} + +/* ------------------------------------------------------------------- */ + +static const struct v4l2_queryctrl no_ctl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; + +static struct cx23885_ctrl cx23885_ctls[] = { + /* --- video --- */ + { + .v = { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = LUMA_CTRL, + .mask = 0x00ff, + .shift = 0, + }, { + .v = { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = LUMA_CTRL, + .mask = 0xff00, + .shift = 8, + }, { + .v = { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = CHROMA_CTRL, + .mask = 0xff0000, + .shift = 16, + }, { + /* strictly, this only describes only U saturation. + * V saturation is handled specially through code. + */ + .v = { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = CHROMA_CTRL, + .mask = 0x00ff, + .shift = 0, + }, { + /* --- audio --- */ + .v = { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, + .reg = PATH1_CTL1, + .mask = (0x1f << 24), + .shift = 24, + }, { + .v = { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 0x3f, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .reg = PATH1_VOL_CTL, + .mask = 0xff, + .shift = 0, + } +}; +static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); + +/* Must be sorted from low to high control ID! */ +static const u32 cx23885_user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_AUDIO_VOLUME, + V4L2_CID_AUDIO_MUTE, + 0 +}; + +static const u32 *ctrl_classes[] = { + cx23885_user_ctrls, + NULL +}; + +static void cx23885_video_wakeup(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, u32 count) +{ + struct cx23885_buffer *buf; + int bc; + + for (bc = 0;; bc++) { + if (list_empty(&q->active)) + break; + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + + /* count comes from the hw and is is 16bit wide -- + * this trick handles wrap-arounds correctly for + * up to 32767 buffers in flight... */ + if ((s16) (count - buf->count) < 0) + break; + + do_gettimeofday(&buf->vb.ts); + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, + count, buf->count); + buf->vb.state = VIDEOBUF_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + } + if (list_empty(&q->active)) + del_timer(&q->timeout); + else + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + if (bc != 1) + printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", + __func__, bc); +} + +static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) +{ + dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", + __func__, + (unsigned int)norm, + v4l2_norm_to_name(norm)); + + dev->tvnorm = norm; + + call_all(dev, core, s_std, norm); + + return 0; +} + +static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, + struct pci_dev *pci, + struct video_device *template, + char *type) +{ + struct video_device *vfd; + dprintk(1, "%s()\n", __func__); + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", + dev->name, type, cx23885_boards[dev->board].name); + video_set_drvdata(vfd, dev); + return vfd; +} + +static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) +{ + int i; + + if (qctrl->id < V4L2_CID_BASE || + qctrl->id >= V4L2_CID_LASTP1) + return -EINVAL; + for (i = 0; i < CX23885_CTLS; i++) + if (cx23885_ctls[i].v.id == qctrl->id) + break; + if (i == CX23885_CTLS) { + *qctrl = no_ctl; + return 0; + } + *qctrl = cx23885_ctls[i].v; + return 0; +} + +/* ------------------------------------------------------------------- */ +/* resource management */ + +static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, + unsigned int bit) +{ + dprintk(1, "%s()\n", __func__); + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + mutex_lock(&dev->lock); + if (dev->resources & bit) { + /* no, someone else uses it */ + mutex_unlock(&dev->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->resources |= bit; + dprintk(1, "res: get %d\n", bit); + mutex_unlock(&dev->lock); + return 1; +} + +static int res_check(struct cx23885_fh *fh, unsigned int bit) +{ + return fh->resources & bit; +} + +static int res_locked(struct cx23885_dev *dev, unsigned int bit) +{ + return dev->resources & bit; +} + +static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, + unsigned int bits) +{ + BUG_ON((fh->resources & bits) != bits); + dprintk(1, "%s()\n", __func__); + + mutex_lock(&dev->lock); + fh->resources &= ~bits; + dev->resources &= ~bits; + dprintk(1, "res: put %d\n", bits); + mutex_unlock(&dev->lock); +} + +static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) +{ + dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", + __func__, + input, INPUT(input)->vmux, + INPUT(input)->gpio0, INPUT(input)->gpio1, + INPUT(input)->gpio2, INPUT(input)->gpio3); + dev->input = input; + + if (dev->board == CX23885_BOARD_MYGICA_X8506 || + dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) { + /* Select Analog TV */ + if (INPUT(input)->type == CX23885_VMUX_TELEVISION) + cx23885_gpio_clear(dev, GPIO_0); + } + + /* Tell the internal A/V decoder */ + v4l2_subdev_call(dev->sd_cx25840, video, s_routing, + INPUT(input)->vmux, 0, 0); + + return 0; +} + +/* ------------------------------------------------------------------ */ +static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, + unsigned int height, enum v4l2_field field) +{ + dprintk(1, "%s()\n", __func__); + return 0; +} + +static int cx23885_start_video_dma(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + dprintk(1, "%s()\n", __func__); + + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], + buf->bpl, buf->risc.dma); + cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); + + /* reset counter */ + cx_write(VID_A_GPCNT_CTL, 3); + q->count = 1; + + /* enable irq */ + cx23885_irq_add_enable(dev, 0x01); + cx_set(VID_A_INT_MSK, 0x000011); + + /* start dma */ + cx_set(DEV_CNTRL2, (1<<5)); + cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ + + return 0; +} + + +static int cx23885_restart_video_queue(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q) +{ + struct cx23885_buffer *buf, *prev; + struct list_head *item; + dprintk(1, "%s()\n", __func__); + + if (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); + dprintk(2, "restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_video_dma(dev, q, buf); + list_for_each(item, &q->active) { + buf = list_entry(item, struct cx23885_buffer, + vb.queue); + buf->count = q->count++; + } + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; + } + + prev = NULL; + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, + vb.queue); + if (NULL == prev) { + list_move_tail(&buf->vb.queue, &q->active); + cx23885_start_video_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] restart_queue - first active\n", + buf, buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_move_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ + dprintk(2, "[%p/%d] restart_queue - move to active\n", + buf, buf->vb.i); + } else { + return 0; + } + prev = buf; + } +} + +static int buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + struct cx23885_fh *fh = q->priv_data; + + *size = fh->fmt->depth*fh->width*fh->height >> 3; + if (0 == *count) + *count = 32; + if (*size * *count > vid_limit * 1024 * 1024) + *count = (vid_limit * 1024 * 1024) / *size; + return 0; +} + +static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + int rc, init_buffer = 0; + u32 line0_offset, line1_offset; + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + + BUG_ON(NULL == fh->fmt); + if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || + fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) + return -EINVAL; + buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + if (buf->fmt != fh->fmt || + buf->vb.width != fh->width || + buf->vb.height != fh->height || + buf->vb.field != field) { + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + init_buffer = 1; + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + init_buffer = 1; + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) + goto fail; + } + + if (init_buffer) { + buf->bpl = buf->vb.width * buf->fmt->depth >> 3; + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, 0, UNSET, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, UNSET, 0, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + if (dev->tvnorm & V4L2_STD_NTSC) { + /* cx25840 transmits NTSC bottom field first */ + dprintk(1, "%s() Creating NTSC risc\n", + __func__); + line0_offset = buf->bpl; + line1_offset = 0; + } else { + /* All other formats are top field first */ + dprintk(1, "%s() Creating PAL/SECAM risc\n", + __func__); + line0_offset = 0; + line1_offset = buf->bpl; + } + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, line0_offset, + line1_offset, + buf->bpl, buf->bpl, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->bpl * (buf->vb.height >> 1), + buf->bpl, 0, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + buf->bpl * (buf->vb.height >> 1), 0, + buf->bpl, 0, + buf->vb.height >> 1); + break; + default: + BUG(); + } + } + dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + buf, buf->vb.i, + fh->width, fh->height, fh->fmt->depth, fh->fmt->name, + (unsigned long)buf->risc.dma); + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q, buf); + return rc; +} + +static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct cx23885_buffer *prev; + struct cx23885_fh *fh = vq->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_dmaqueue *q = &dev->vidq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (!list_empty(&q->queued)) { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - append to queued\n", + buf, buf->vb.i); + + } else if (list_empty(&q->active)) { + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_video_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] buffer_queue - first active\n", + buf, buf->vb.i); + + } else { + prev = list_entry(q->active.prev, struct cx23885_buffer, + vb.queue); + if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + /* 64 bit bits 63-32 */ + prev->risc.jmp[2] = cpu_to_le32(0); + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.i); + + } else { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - first queued\n", + buf, buf->vb.i); + } + } +} + +static void buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + + cx23885_free_buffer(q, buf); +} + +static struct videobuf_queue_ops cx23885_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +static struct videobuf_queue *get_queue(struct cx23885_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &fh->vidq; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return &fh->vbiq; + default: + BUG(); + return NULL; + } +} + +static int get_resource(struct cx23885_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return RESOURCE_VIDEO; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return RESOURCE_VBI; + default: + BUG(); + return 0; + } +} + +static int video_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct cx23885_dev *dev = video_drvdata(file); + struct cx23885_fh *fh; + enum v4l2_buf_type type = 0; + int radio = 0; + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; + } + + dprintk(1, "open dev=%s radio=%d type=%s\n", + video_device_node_name(vdev), radio, v4l2_type_names[type]); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) + return -ENOMEM; + + file->private_data = fh; + fh->dev = dev; + fh->radio = radio; + fh->type = type; + fh->width = 320; + fh->height = 240; + fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + + videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct cx23885_buffer), + fh, NULL); + + dprintk(1, "post videobuf_queue_init()\n"); + + return 0; +} + +static ssize_t video_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct cx23885_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + return videobuf_read_one(&fh->vidq, data, count, ppos, + file->f_flags & O_NONBLOCK); + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (!res_get(fh->dev, fh, RESOURCE_VBI)) + return -EBUSY; + return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, + file->f_flags & O_NONBLOCK); + default: + BUG(); + return 0; + } +} + +static unsigned int video_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_buffer *buf; + unsigned int rc = POLLERR; + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (!res_get(fh->dev, fh, RESOURCE_VBI)) + return POLLERR; + return videobuf_poll_stream(file, &fh->vbiq, wait); + } + + mutex_lock(&fh->vidq.vb_lock); + if (res_check(fh, RESOURCE_VIDEO)) { + /* streaming capture */ + if (list_empty(&fh->vidq.stream)) + goto done; + buf = list_entry(fh->vidq.stream.next, + struct cx23885_buffer, vb.stream); + } else { + /* read() capture */ + buf = (struct cx23885_buffer *)fh->vidq.read_buf; + if (NULL == buf) + goto done; + } + poll_wait(file, &buf->vb.done, wait); + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) + rc = POLLIN|POLLRDNORM; + else + rc = 0; +done: + mutex_unlock(&fh->vidq.vb_lock); + return rc; +} + +static int video_release(struct file *file) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + /* turn off overlay */ + if (res_check(fh, RESOURCE_OVERLAY)) { + /* FIXME */ + res_free(dev, fh, RESOURCE_OVERLAY); + } + + /* stop video capture */ + if (res_check(fh, RESOURCE_VIDEO)) { + videobuf_queue_cancel(&fh->vidq); + res_free(dev, fh, RESOURCE_VIDEO); + } + if (fh->vidq.read_buf) { + buffer_release(&fh->vidq, fh->vidq.read_buf); + kfree(fh->vidq.read_buf); + } + + /* stop vbi capture */ + if (res_check(fh, RESOURCE_VBI)) { + if (fh->vbiq.streaming) + videobuf_streamoff(&fh->vbiq); + if (fh->vbiq.reading) + videobuf_read_stop(&fh->vbiq); + res_free(dev, fh, RESOURCE_VBI); + } + + videobuf_mmap_free(&fh->vidq); + file->private_data = NULL; + kfree(fh); + + /* We are not putting the tuner to sleep here on exit, because + * we want to use the mpeg encoder in another session to capture + * tuner video. Closing this will result in no video to the encoder. + */ + + return 0; +} + +static int video_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_mmap_mapper(get_queue(fh), vma); +} + +/* ------------------------------------------------------------------ */ +/* VIDEO CTRL IOCTLS */ + +static int cx23885_get_control(struct cx23885_dev *dev, + struct v4l2_control *ctl) +{ + dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); + call_all(dev, core, g_ctrl, ctl); + return 0; +} + +static int cx23885_set_control(struct cx23885_dev *dev, + struct v4l2_control *ctl) +{ + dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" + " (disabled - no action)\n", __func__); + return 0; +} + +static void init_controls(struct cx23885_dev *dev) +{ + struct v4l2_control ctrl; + int i; + + for (i = 0; i < CX23885_CTLS; i++) { + ctrl.id = cx23885_ctls[i].v.id; + ctrl.value = cx23885_ctls[i].v.default_value; + + cx23885_set_control(dev, &ctrl); + } +} + +/* ------------------------------------------------------------------ */ +/* VIDEO IOCTLS */ + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_fmt *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = norm_maxw(dev->tvnorm); + maxh = norm_maxh(dev->tvnorm); + + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + f->fmt.pix.field = field; + v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, + &f->fmt.pix.height, 32, maxh, 0, 0); + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct v4l2_mbus_framefmt mbus_fmt; + int err; + + dprintk(2, "%s()\n", __func__); + err = vidioc_try_fmt_vid_cap(file, priv, f); + + if (0 != err) + return err; + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->vidq.field = f->fmt.pix.field; + dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, + fh->width, fh->height, fh->vidq.field); + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); + call_all(dev, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + strcpy(cap->driver, "cx23885"); + strlcpy(cap->card, cx23885_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); + cap->version = CX23885_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (UNSET != dev->tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(formats))) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct cx23885_fh *fh = priv; + return videobuf_reqbufs(get_queue(fh), p); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = priv; + return videobuf_querybuf(get_queue(fh), p); +} + +static int vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = priv; + return videobuf_qbuf(get_queue(fh), p); +} + +static int vidioc_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = priv; + return videobuf_dqbuf(get_queue(fh), p, + file->f_flags & O_NONBLOCK); +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + dprintk(1, "%s()\n", __func__); + + if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + if (unlikely(i != fh->type)) + return -EINVAL; + + if (unlikely(!res_get(dev, fh, get_resource(fh)))) + return -EBUSY; + return videobuf_streamon(get_queue(fh)); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + int err, res; + dprintk(1, "%s()\n", __func__); + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (i != fh->type) + return -EINVAL; + + res = get_resource(fh); + err = videobuf_streamoff(get_queue(fh)); + if (err < 0) + return err; + res_free(dev, fh, res); + return 0; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __func__); + + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, *tvnorms); + mutex_unlock(&dev->lock); + + return 0; +} + +static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) +{ + static const char *iname[] = { + [CX23885_VMUX_COMPOSITE1] = "Composite1", + [CX23885_VMUX_COMPOSITE2] = "Composite2", + [CX23885_VMUX_COMPOSITE3] = "Composite3", + [CX23885_VMUX_COMPOSITE4] = "Composite4", + [CX23885_VMUX_SVIDEO] = "S-Video", + [CX23885_VMUX_COMPONENT] = "Component", + [CX23885_VMUX_TELEVISION] = "Television", + [CX23885_VMUX_CABLE] = "Cable TV", + [CX23885_VMUX_DVB] = "DVB", + [CX23885_VMUX_DEBUG] = "for debug only", + }; + unsigned int n; + dprintk(1, "%s()\n", __func__); + + n = i->index; + if (n >= 4) + return -EINVAL; + + if (0 == INPUT(n)->type) + return -EINVAL; + + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, iname[INPUT(n)->type]); + if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || + (CX23885_VMUX_CABLE == INPUT(n)->type)) { + i->type = V4L2_INPUT_TYPE_TUNER; + i->std = CX23885_NORMS; + } + return 0; +} + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __func__); + return cx23885_enum_input(dev, i); +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + *i = dev->input; + dprintk(1, "%s() returns %d\n", __func__, *i); + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + dprintk(1, "%s(%d)\n", __func__, i); + + if (i >= 4) { + dprintk(1, "%s() -EINVAL\n", __func__); + return -EINVAL; + } + + mutex_lock(&dev->lock); + cx23885_video_mux(dev, i); + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_log_status(struct file *file, void *priv) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + printk(KERN_INFO + "%s/0: ============ START LOG STATUS ============\n", + dev->name); + call_all(dev, core, log_status); + printk(KERN_INFO + "%s/0: ============= END LOG STATUS =============\n", + dev->name); + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qctrl) +{ + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (unlikely(qctrl->id == 0)) + return -EINVAL; + return cx23885_ctrl_query(qctrl); +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + return cx23885_get_control(dev, ctl); +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + return cx23885_set_control(dev, ctl); +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; + t->signal = 0xffff ; /* LOCKED */ + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + if (UNSET == dev->tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + + /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->freq; + + call_all(dev, tuner, g_frequency, f); + + return 0; +} + +static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) +{ + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; + + mutex_lock(&dev->lock); + dev->freq = f->frequency; + + call_all(dev, tuner, s_frequency, f); + + /* When changing channels it is required to reset TVAUDIO */ + msleep(10); + + mutex_unlock(&dev->lock); + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) + return -EINVAL; + + return + cx23885_set_freq(dev, f); +} + +/* ----------------------------------------------------------- */ + +static void cx23885_vid_timeout(unsigned long data) +{ + struct cx23885_dev *dev = (struct cx23885_dev *)data; + struct cx23885_dmaqueue *q = &dev->vidq; + struct cx23885_buffer *buf; + unsigned long flags; + + cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); + + cx_clear(VID_A_DMA_CTL, 0x11); + + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", + dev->name, buf, buf->vb.i, + (unsigned long)buf->risc.dma); + } + cx23885_restart_video_queue(dev, q); + spin_unlock_irqrestore(&dev->slock, flags); +} + +int cx23885_video_irq(struct cx23885_dev *dev, u32 status) +{ + u32 mask, count; + int handled = 0; + + mask = cx_read(VID_A_INT_MSK); + if (0 == (status & mask)) + return handled; + cx_write(VID_A_INT_STAT, status); + + dprintk(2, "%s() status = 0x%08x\n", __func__, status); + /* risc op code error */ + if (status & (1 << 16)) { + printk(KERN_WARNING "%s/0: video risc op code error\n", + dev->name); + cx_clear(VID_A_DMA_CTL, 0x11); + cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); + } + + /* risc1 y */ + if (status & 0x01) { + spin_lock(&dev->slock); + count = cx_read(VID_A_GPCNT); + cx23885_video_wakeup(dev, &dev->vidq, count); + spin_unlock(&dev->slock); + handled++; + } + /* risc2 y */ + if (status & 0x10) { + dprintk(2, "stopper video\n"); + spin_lock(&dev->slock); + cx23885_restart_video_queue(dev, &dev->vidq); + spin_unlock(&dev->slock); + handled++; + } + + return handled; +} + +/* ----------------------------------------------------------- */ +/* exported stuff */ + +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .read = video_read, + .poll = video_poll, + .mmap = video_mmap, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, + .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, + .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_log_status = vidioc_log_status, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_chip_ident = cx23885_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = cx23885_g_register, + .vidioc_s_register = cx23885_s_register, +#endif +}; + +static struct video_device cx23885_vbi_template; +static struct video_device cx23885_video_template = { + .name = "cx23885-video", + .fops = &video_fops, + .ioctl_ops = &video_ioctl_ops, + .tvnorms = CX23885_NORMS, + .current_norm = V4L2_STD_NTSC_M, +}; + +static const struct v4l2_file_operations radio_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .ioctl = video_ioctl2, +}; + + +void cx23885_video_unregister(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __func__); + cx23885_irq_remove(dev, 0x01); + + if (dev->video_dev) { + if (video_is_registered(dev->video_dev)) + video_unregister_device(dev->video_dev); + else + video_device_release(dev->video_dev); + dev->video_dev = NULL; + + btcx_riscmem_free(dev->pci, &dev->vidq.stopper); + } +} + +int cx23885_video_register(struct cx23885_dev *dev) +{ + int err; + + dprintk(1, "%s()\n", __func__); + spin_lock_init(&dev->slock); + + /* Initialize VBI template */ + memcpy(&cx23885_vbi_template, &cx23885_video_template, + sizeof(cx23885_vbi_template)); + strcpy(cx23885_vbi_template.name, "cx23885-vbi"); + + dev->tvnorm = cx23885_video_template.current_norm; + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + dev->vidq.timeout.function = cx23885_vid_timeout; + dev->vidq.timeout.data = (unsigned long)dev; + init_timer(&dev->vidq.timeout); + cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, + VID_A_DMA_CTL, 0x11, 0x00); + + /* Don't enable VBI yet */ + + cx23885_irq_add_enable(dev, 0x01); + + if ((TUNER_ABSENT != dev->tuner_type) && + ((dev->tuner_bus == 0) || (dev->tuner_bus == 1))) { + struct v4l2_subdev *sd = NULL; + + if (dev->tuner_addr) + sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_bus[dev->tuner_bus].i2c_adap, + "tuner", dev->tuner_addr, NULL); + else + sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_bus[dev->tuner_bus].i2c_adap, + "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV)); + if (sd) { + struct tuner_setup tun_setup; + + memset(&tun_setup, 0, sizeof(tun_setup)); + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = dev->tuner_type; + tun_setup.addr = v4l2_i2c_subdev_addr(sd); + tun_setup.tuner_callback = cx23885_tuner_callback; + + v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup); + + if (dev->board == CX23885_BOARD_LEADTEK_WINFAST_PXTV1200) { + struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64 + }; + struct v4l2_priv_tun_config cfg = { + .tuner = dev->tuner_type, + .priv = &ctrl + }; + v4l2_subdev_call(sd, tuner, s_config, &cfg); + } + } + } + + + /* register v4l devices */ + dev->video_dev = cx23885_vdev_init(dev, dev->pci, + &cx23885_video_template, "video"); + err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, + video_nr[dev->nr]); + if (err < 0) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + goto fail_unreg; + } + printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", + dev->name, video_device_node_name(dev->video_dev)); + /* initial device configuration */ + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, dev->tvnorm); + init_controls(dev); + cx23885_video_mux(dev, 0); + mutex_unlock(&dev->lock); + + return 0; + +fail_unreg: + cx23885_video_unregister(dev); + return err; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23888-ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23888-ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23888-ir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23888-ir.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1269 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * CX23888 Integrated Consumer Infrared Controller + * + * Copyright (C) 2009 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include + +#include "cx23885.h" + +static unsigned int ir_888_debug; +module_param(ir_888_debug, int, 0644); +MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]"); + +#define CX23888_IR_REG_BASE 0x170000 +/* + * These CX23888 register offsets have a straightforward one to one mapping + * to the CX23885 register offsets of 0x200 through 0x218 + */ +#define CX23888_IR_CNTRL_REG 0x170000 +#define CNTRL_WIN_3_3 0x00000000 +#define CNTRL_WIN_4_3 0x00000001 +#define CNTRL_WIN_3_4 0x00000002 +#define CNTRL_WIN_4_4 0x00000003 +#define CNTRL_WIN 0x00000003 +#define CNTRL_EDG_NONE 0x00000000 +#define CNTRL_EDG_FALL 0x00000004 +#define CNTRL_EDG_RISE 0x00000008 +#define CNTRL_EDG_BOTH 0x0000000C +#define CNTRL_EDG 0x0000000C +#define CNTRL_DMD 0x00000010 +#define CNTRL_MOD 0x00000020 +#define CNTRL_RFE 0x00000040 +#define CNTRL_TFE 0x00000080 +#define CNTRL_RXE 0x00000100 +#define CNTRL_TXE 0x00000200 +#define CNTRL_RIC 0x00000400 +#define CNTRL_TIC 0x00000800 +#define CNTRL_CPL 0x00001000 +#define CNTRL_LBM 0x00002000 +#define CNTRL_R 0x00004000 +/* CX23888 specific control flag */ +#define CNTRL_IVO 0x00008000 + +#define CX23888_IR_TXCLK_REG 0x170004 +#define TXCLK_TCD 0x0000FFFF + +#define CX23888_IR_RXCLK_REG 0x170008 +#define RXCLK_RCD 0x0000FFFF + +#define CX23888_IR_CDUTY_REG 0x17000C +#define CDUTY_CDC 0x0000000F + +#define CX23888_IR_STATS_REG 0x170010 +#define STATS_RTO 0x00000001 +#define STATS_ROR 0x00000002 +#define STATS_RBY 0x00000004 +#define STATS_TBY 0x00000008 +#define STATS_RSR 0x00000010 +#define STATS_TSR 0x00000020 + +#define CX23888_IR_IRQEN_REG 0x170014 +#define IRQEN_RTE 0x00000001 +#define IRQEN_ROE 0x00000002 +#define IRQEN_RSE 0x00000010 +#define IRQEN_TSE 0x00000020 + +#define CX23888_IR_FILTR_REG 0x170018 +#define FILTR_LPF 0x0000FFFF + +/* This register doesn't follow the pattern; it's 0x23C on a CX23885 */ +#define CX23888_IR_FIFO_REG 0x170040 +#define FIFO_RXTX 0x0000FFFF +#define FIFO_RXTX_LVL 0x00010000 +#define FIFO_RXTX_RTO 0x0001FFFF +#define FIFO_RX_NDV 0x00020000 +#define FIFO_RX_DEPTH 8 +#define FIFO_TX_DEPTH 8 + +/* CX23888 unique registers */ +#define CX23888_IR_SEEDP_REG 0x17001C +#define CX23888_IR_TIMOL_REG 0x170020 +#define CX23888_IR_WAKE0_REG 0x170024 +#define CX23888_IR_WAKE1_REG 0x170028 +#define CX23888_IR_WAKE2_REG 0x17002C +#define CX23888_IR_MASK0_REG 0x170030 +#define CX23888_IR_MASK1_REG 0x170034 +#define CX23888_IR_MAKS2_REG 0x170038 +#define CX23888_IR_DPIPG_REG 0x17003C +#define CX23888_IR_LEARN_REG 0x170044 + +#define CX23888_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */ +#define CX23888_IR_REFCLK_FREQ (CX23888_VIDCLK_FREQ / 2) + +/* + * We use this union internally for convenience, but callers to tx_write + * and rx_read will be expecting records of type struct ir_raw_event. + * Always ensure the size of this union is dictated by struct ir_raw_event. + */ +union cx23888_ir_fifo_rec { + u32 hw_fifo_data; + struct ir_raw_event ir_core_data; +}; + +#define CX23888_IR_RX_KFIFO_SIZE (256 * sizeof(union cx23888_ir_fifo_rec)) +#define CX23888_IR_TX_KFIFO_SIZE (256 * sizeof(union cx23888_ir_fifo_rec)) + +struct cx23888_ir_state { + struct v4l2_subdev sd; + struct cx23885_dev *dev; + u32 id; + u32 rev; + + struct v4l2_subdev_ir_parameters rx_params; + struct mutex rx_params_lock; + atomic_t rxclk_divider; + atomic_t rx_invert; + + struct kfifo rx_kfifo; + spinlock_t rx_kfifo_lock; + + struct v4l2_subdev_ir_parameters tx_params; + struct mutex tx_params_lock; + atomic_t txclk_divider; +}; + +static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd) +{ + return v4l2_get_subdevdata(sd); +} + +/* + * IR register block read and write functions + */ +static +inline int cx23888_ir_write4(struct cx23885_dev *dev, u32 addr, u32 value) +{ + cx_write(addr, value); + return 0; +} + +static inline u32 cx23888_ir_read4(struct cx23885_dev *dev, u32 addr) +{ + return cx_read(addr); +} + +static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr, + u32 and_mask, u32 or_value) +{ + cx_andor(addr, ~and_mask, or_value); + return 0; +} + +/* + * Rx and Tx Clock Divider register computations + * + * Note the largest clock divider value of 0xffff corresponds to: + * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns + * which fits in 21 bits, so we'll use unsigned int for time arguments. + */ +static inline u16 count_to_clock_divider(unsigned int d) +{ + if (d > RXCLK_RCD + 1) + d = RXCLK_RCD; + else if (d < 2) + d = 1; + else + d--; + return (u16) d; +} + +static inline u16 ns_to_clock_divider(unsigned int ns) +{ + return count_to_clock_divider( + DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000)); +} + +static inline unsigned int clock_divider_to_ns(unsigned int divider) +{ + /* Period of the Rx or Tx clock in ns */ + return DIV_ROUND_CLOSEST((divider + 1) * 1000, + CX23888_IR_REFCLK_FREQ / 1000000); +} + +static inline u16 carrier_freq_to_clock_divider(unsigned int freq) +{ + return count_to_clock_divider( + DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * 16)); +} + +static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) +{ + return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16); +} + +static inline u16 freq_to_clock_divider(unsigned int freq, + unsigned int rollovers) +{ + return count_to_clock_divider( + DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * rollovers)); +} + +static inline unsigned int clock_divider_to_freq(unsigned int divider, + unsigned int rollovers) +{ + return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, + (divider + 1) * rollovers); +} + +/* + * Low Pass Filter register calculations + * + * Note the largest count value of 0xffff corresponds to: + * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns + * which fits in 21 bits, so we'll use unsigned int for time arguments. + */ +static inline u16 count_to_lpf_count(unsigned int d) +{ + if (d > FILTR_LPF) + d = FILTR_LPF; + else if (d < 4) + d = 0; + return (u16) d; +} + +static inline u16 ns_to_lpf_count(unsigned int ns) +{ + return count_to_lpf_count( + DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000)); +} + +static inline unsigned int lpf_count_to_ns(unsigned int count) +{ + /* Duration of the Low Pass Filter rejection window in ns */ + return DIV_ROUND_CLOSEST(count * 1000, + CX23888_IR_REFCLK_FREQ / 1000000); +} + +static inline unsigned int lpf_count_to_us(unsigned int count) +{ + /* Duration of the Low Pass Filter rejection window in us */ + return DIV_ROUND_CLOSEST(count, CX23888_IR_REFCLK_FREQ / 1000000); +} + +/* + * FIFO register pulse width count compuations + */ +static u32 clock_divider_to_resolution(u16 divider) +{ + /* + * Resolution is the duration of 1 tick of the readable portion of + * of the pulse width counter as read from the FIFO. The two lsb's are + * not readable, hence the << 2. This function returns ns. + */ + return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, + CX23888_IR_REFCLK_FREQ / 1000000); +} + +static u64 pulse_width_count_to_ns(u16 count, u16 divider) +{ + u64 n; + u32 rem; + + /* + * The 2 lsb's of the pulse width timer count are not readable, hence + * the (count << 2) | 0x3 + */ + n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */ + rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */ + if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2) + n++; + return n; +} + +static unsigned int pulse_width_count_to_us(u16 count, u16 divider) +{ + u64 n; + u32 rem; + + /* + * The 2 lsb's of the pulse width timer count are not readable, hence + * the (count << 2) | 0x3 + */ + n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */ + rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => us */ + if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2) + n++; + return (unsigned int) n; +} + +/* + * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts + * + * The total pulse clock count is an 18 bit pulse width timer count as the most + * significant part and (up to) 16 bit clock divider count as a modulus. + * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse + * width timer count's least significant bit. + */ +static u64 ns_to_pulse_clocks(u32 ns) +{ + u64 clocks; + u32 rem; + clocks = CX23888_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */ + rem = do_div(clocks, 1000); /* /1000 = cycles */ + if (rem >= 1000 / 2) + clocks++; + return clocks; +} + +static u16 pulse_clocks_to_clock_divider(u64 count) +{ + u32 rem; + + rem = do_div(count, (FIFO_RXTX << 2) | 0x3); + + /* net result needs to be rounded down and decremented by 1 */ + if (count > RXCLK_RCD + 1) + count = RXCLK_RCD; + else if (count < 2) + count = 1; + else + count--; + return (u16) count; +} + +/* + * IR Control Register helpers + */ +enum tx_fifo_watermark { + TX_FIFO_HALF_EMPTY = 0, + TX_FIFO_EMPTY = CNTRL_TIC, +}; + +enum rx_fifo_watermark { + RX_FIFO_HALF_FULL = 0, + RX_FIFO_NOT_EMPTY = CNTRL_RIC, +}; + +static inline void control_tx_irq_watermark(struct cx23885_dev *dev, + enum tx_fifo_watermark level) +{ + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_TIC, level); +} + +static inline void control_rx_irq_watermark(struct cx23885_dev *dev, + enum rx_fifo_watermark level) +{ + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_RIC, level); +} + +static inline void control_tx_enable(struct cx23885_dev *dev, bool enable) +{ + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE), + enable ? (CNTRL_TXE | CNTRL_TFE) : 0); +} + +static inline void control_rx_enable(struct cx23885_dev *dev, bool enable) +{ + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE), + enable ? (CNTRL_RXE | CNTRL_RFE) : 0); +} + +static inline void control_tx_modulation_enable(struct cx23885_dev *dev, + bool enable) +{ + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_MOD, + enable ? CNTRL_MOD : 0); +} + +static inline void control_rx_demodulation_enable(struct cx23885_dev *dev, + bool enable) +{ + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_DMD, + enable ? CNTRL_DMD : 0); +} + +static inline void control_rx_s_edge_detection(struct cx23885_dev *dev, + u32 edge_types) +{ + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_EDG_BOTH, + edge_types & CNTRL_EDG_BOTH); +} + +static void control_rx_s_carrier_window(struct cx23885_dev *dev, + unsigned int carrier, + unsigned int *carrier_range_low, + unsigned int *carrier_range_high) +{ + u32 v; + unsigned int c16 = carrier * 16; + + if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) { + v = CNTRL_WIN_3_4; + *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4); + } else { + v = CNTRL_WIN_3_3; + *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3); + } + + if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { + v |= CNTRL_WIN_4_3; + *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); + } else { + v |= CNTRL_WIN_3_3; + *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); + } + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_WIN, v); +} + +static inline void control_tx_polarity_invert(struct cx23885_dev *dev, + bool invert) +{ + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_CPL, + invert ? CNTRL_CPL : 0); +} + +static inline void control_tx_level_invert(struct cx23885_dev *dev, + bool invert) +{ + cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_IVO, + invert ? CNTRL_IVO : 0); +} + +/* + * IR Rx & Tx Clock Register helpers + */ +static unsigned int txclk_tx_s_carrier(struct cx23885_dev *dev, + unsigned int freq, + u16 *divider) +{ + *divider = carrier_freq_to_clock_divider(freq); + cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); + return clock_divider_to_carrier_freq(*divider); +} + +static unsigned int rxclk_rx_s_carrier(struct cx23885_dev *dev, + unsigned int freq, + u16 *divider) +{ + *divider = carrier_freq_to_clock_divider(freq); + cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); + return clock_divider_to_carrier_freq(*divider); +} + +static u32 txclk_tx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, + u16 *divider) +{ + u64 pulse_clocks; + + if (ns > IR_MAX_DURATION) + ns = IR_MAX_DURATION; + pulse_clocks = ns_to_pulse_clocks(ns); + *divider = pulse_clocks_to_clock_divider(pulse_clocks); + cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); + return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); +} + +static u32 rxclk_rx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, + u16 *divider) +{ + u64 pulse_clocks; + + if (ns > IR_MAX_DURATION) + ns = IR_MAX_DURATION; + pulse_clocks = ns_to_pulse_clocks(ns); + *divider = pulse_clocks_to_clock_divider(pulse_clocks); + cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); + return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); +} + +/* + * IR Tx Carrier Duty Cycle register helpers + */ +static unsigned int cduty_tx_s_duty_cycle(struct cx23885_dev *dev, + unsigned int duty_cycle) +{ + u32 n; + n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */ + if (n != 0) + n--; + if (n > 15) + n = 15; + cx23888_ir_write4(dev, CX23888_IR_CDUTY_REG, n); + return DIV_ROUND_CLOSEST((n + 1) * 100, 16); +} + +/* + * IR Filter Register helpers + */ +static u32 filter_rx_s_min_width(struct cx23885_dev *dev, u32 min_width_ns) +{ + u32 count = ns_to_lpf_count(min_width_ns); + cx23888_ir_write4(dev, CX23888_IR_FILTR_REG, count); + return lpf_count_to_ns(count); +} + +/* + * IR IRQ Enable Register helpers + */ +static inline void irqenable_rx(struct cx23885_dev *dev, u32 mask) +{ + mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE); + cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, + ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask); +} + +static inline void irqenable_tx(struct cx23885_dev *dev, u32 mask) +{ + mask &= IRQEN_TSE; + cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, ~IRQEN_TSE, mask); +} + +/* + * V4L2 Subdevice IR Ops + */ +static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, + bool *handled) +{ + struct cx23888_ir_state *state = to_state(sd); + struct cx23885_dev *dev = state->dev; + unsigned long flags; + + u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); + u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); + u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); + + union cx23888_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; + unsigned int i, j, k; + u32 events, v; + int tsr, rsr, rto, ror, tse, rse, rte, roe, kror; + + tsr = stats & STATS_TSR; /* Tx FIFO Service Request */ + rsr = stats & STATS_RSR; /* Rx FIFO Service Request */ + rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */ + ror = stats & STATS_ROR; /* Rx FIFO Over Run */ + + tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ + rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ + rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ + roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ + + *handled = false; + v4l2_dbg(2, ir_888_debug, sd, "IRQ Status: %s %s %s %s %s %s\n", + tsr ? "tsr" : " ", rsr ? "rsr" : " ", + rto ? "rto" : " ", ror ? "ror" : " ", + stats & STATS_TBY ? "tby" : " ", + stats & STATS_RBY ? "rby" : " "); + + v4l2_dbg(2, ir_888_debug, sd, "IRQ Enables: %s %s %s %s\n", + tse ? "tse" : " ", rse ? "rse" : " ", + rte ? "rte" : " ", roe ? "roe" : " "); + + /* + * Transmitter interrupt service + */ + if (tse && tsr) { + /* + * TODO: + * Check the watermark threshold setting + * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo + * Push the data to the hardware FIFO. + * If there was nothing more to send in the tx_kfifo, disable + * the TSR IRQ and notify the v4l2_device. + * If there was something in the tx_kfifo, check the tx_kfifo + * level and notify the v4l2_device, if it is low. + */ + /* For now, inhibit TSR interrupt until Tx is implemented */ + irqenable_tx(dev, 0); + events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; + v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events); + *handled = true; + } + + /* + * Receiver interrupt service + */ + kror = 0; + if ((rse && rsr) || (rte && rto)) { + /* + * Receive data on RSR to clear the STATS_RSR. + * Receive data on RTO, since we may not have yet hit the RSR + * watermark when we receive the RTO. + */ + for (i = 0, v = FIFO_RX_NDV; + (v & FIFO_RX_NDV) && !kror; i = 0) { + for (j = 0; + (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) { + v = cx23888_ir_read4(dev, CX23888_IR_FIFO_REG); + rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV; + i++; + } + if (i == 0) + break; + j = i * sizeof(union cx23888_ir_fifo_rec); + k = kfifo_in_locked(&state->rx_kfifo, + (unsigned char *) rx_data, j, + &state->rx_kfifo_lock); + if (k != j) + kror++; /* rx_kfifo over run */ + } + *handled = true; + } + + events = 0; + v = 0; + if (kror) { + events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; + v4l2_err(sd, "IR receiver software FIFO overrun\n"); + } + if (roe && ror) { + /* + * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear + * the Rx FIFO Over Run status (STATS_ROR) + */ + v |= CNTRL_RFE; + events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; + v4l2_err(sd, "IR receiver hardware FIFO overrun\n"); + } + if (rte && rto) { + /* + * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear + * the Rx Pulse Width Timer Time Out (STATS_RTO) + */ + v |= CNTRL_RXE; + events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; + } + if (v) { + /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ + cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl & ~v); + cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl); + *handled = true; + } + + spin_lock_irqsave(&state->rx_kfifo_lock, flags); + if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) + events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; + spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); + + if (events) + v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); + return 0; +} + +/* Receiver */ +static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, + ssize_t *num) +{ + struct cx23888_ir_state *state = to_state(sd); + bool invert = (bool) atomic_read(&state->rx_invert); + u16 divider = (u16) atomic_read(&state->rxclk_divider); + + unsigned int i, n; + union cx23888_ir_fifo_rec *p; + unsigned u, v; + + n = count / sizeof(union cx23888_ir_fifo_rec) + * sizeof(union cx23888_ir_fifo_rec); + if (n == 0) { + *num = 0; + return 0; + } + + n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock); + + n /= sizeof(union cx23888_ir_fifo_rec); + *num = n * sizeof(union cx23888_ir_fifo_rec); + + for (p = (union cx23888_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) { + + if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { + /* Assume RTO was because of no IR light input */ + u = 0; + v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); + } else { + u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; + if (invert) + u = u ? 0 : 1; + } + + v = (unsigned) pulse_width_count_to_ns( + (u16) (p->hw_fifo_data & FIFO_RXTX), divider); + if (v > IR_MAX_DURATION) + v = IR_MAX_DURATION; + + init_ir_raw_event(&p->ir_core_data); + p->ir_core_data.pulse = u; + p->ir_core_data.duration = v; + + v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s\n", + v, u ? "mark" : "space"); + } + return 0; +} + +static int cx23888_ir_rx_g_parameters(struct v4l2_subdev *sd, + struct v4l2_subdev_ir_parameters *p) +{ + struct cx23888_ir_state *state = to_state(sd); + mutex_lock(&state->rx_params_lock); + memcpy(p, &state->rx_params, sizeof(struct v4l2_subdev_ir_parameters)); + mutex_unlock(&state->rx_params_lock); + return 0; +} + +static int cx23888_ir_rx_shutdown(struct v4l2_subdev *sd) +{ + struct cx23888_ir_state *state = to_state(sd); + struct cx23885_dev *dev = state->dev; + + mutex_lock(&state->rx_params_lock); + + /* Disable or slow down all IR Rx circuits and counters */ + irqenable_rx(dev, 0); + control_rx_enable(dev, false); + control_rx_demodulation_enable(dev, false); + control_rx_s_edge_detection(dev, CNTRL_EDG_NONE); + filter_rx_s_min_width(dev, 0); + cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, RXCLK_RCD); + + state->rx_params.shutdown = true; + + mutex_unlock(&state->rx_params_lock); + return 0; +} + +static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd, + struct v4l2_subdev_ir_parameters *p) +{ + struct cx23888_ir_state *state = to_state(sd); + struct cx23885_dev *dev = state->dev; + struct v4l2_subdev_ir_parameters *o = &state->rx_params; + u16 rxclk_divider; + + if (p->shutdown) + return cx23888_ir_rx_shutdown(sd); + + if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) + return -ENOSYS; + + mutex_lock(&state->rx_params_lock); + + o->shutdown = p->shutdown; + + o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; + + o->bytes_per_data_element = p->bytes_per_data_element + = sizeof(union cx23888_ir_fifo_rec); + + /* Before we tweak the hardware, we have to disable the receiver */ + irqenable_rx(dev, 0); + control_rx_enable(dev, false); + + control_rx_demodulation_enable(dev, p->modulation); + o->modulation = p->modulation; + + if (p->modulation) { + p->carrier_freq = rxclk_rx_s_carrier(dev, p->carrier_freq, + &rxclk_divider); + + o->carrier_freq = p->carrier_freq; + + o->duty_cycle = p->duty_cycle = 50; + + control_rx_s_carrier_window(dev, p->carrier_freq, + &p->carrier_range_lower, + &p->carrier_range_upper); + o->carrier_range_lower = p->carrier_range_lower; + o->carrier_range_upper = p->carrier_range_upper; + + p->max_pulse_width = + (u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider); + } else { + p->max_pulse_width = + rxclk_rx_s_max_pulse_width(dev, p->max_pulse_width, + &rxclk_divider); + } + o->max_pulse_width = p->max_pulse_width; + atomic_set(&state->rxclk_divider, rxclk_divider); + + p->noise_filter_min_width = + filter_rx_s_min_width(dev, p->noise_filter_min_width); + o->noise_filter_min_width = p->noise_filter_min_width; + + p->resolution = clock_divider_to_resolution(rxclk_divider); + o->resolution = p->resolution; + + /* FIXME - make this dependent on resolution for better performance */ + control_rx_irq_watermark(dev, RX_FIFO_HALF_FULL); + + control_rx_s_edge_detection(dev, CNTRL_EDG_BOTH); + + o->invert_level = p->invert_level; + atomic_set(&state->rx_invert, p->invert_level); + + o->interrupt_enable = p->interrupt_enable; + o->enable = p->enable; + if (p->enable) { + unsigned long flags; + + spin_lock_irqsave(&state->rx_kfifo_lock, flags); + kfifo_reset(&state->rx_kfifo); + /* reset tx_fifo too if there is one... */ + spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); + if (p->interrupt_enable) + irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); + control_rx_enable(dev, p->enable); + } + + mutex_unlock(&state->rx_params_lock); + return 0; +} + +/* Transmitter */ +static int cx23888_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count, + ssize_t *num) +{ + struct cx23888_ir_state *state = to_state(sd); + struct cx23885_dev *dev = state->dev; + /* For now enable the Tx FIFO Service interrupt & pretend we did work */ + irqenable_tx(dev, IRQEN_TSE); + *num = count; + return 0; +} + +static int cx23888_ir_tx_g_parameters(struct v4l2_subdev *sd, + struct v4l2_subdev_ir_parameters *p) +{ + struct cx23888_ir_state *state = to_state(sd); + mutex_lock(&state->tx_params_lock); + memcpy(p, &state->tx_params, sizeof(struct v4l2_subdev_ir_parameters)); + mutex_unlock(&state->tx_params_lock); + return 0; +} + +static int cx23888_ir_tx_shutdown(struct v4l2_subdev *sd) +{ + struct cx23888_ir_state *state = to_state(sd); + struct cx23885_dev *dev = state->dev; + + mutex_lock(&state->tx_params_lock); + + /* Disable or slow down all IR Tx circuits and counters */ + irqenable_tx(dev, 0); + control_tx_enable(dev, false); + control_tx_modulation_enable(dev, false); + cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, TXCLK_TCD); + + state->tx_params.shutdown = true; + + mutex_unlock(&state->tx_params_lock); + return 0; +} + +static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd, + struct v4l2_subdev_ir_parameters *p) +{ + struct cx23888_ir_state *state = to_state(sd); + struct cx23885_dev *dev = state->dev; + struct v4l2_subdev_ir_parameters *o = &state->tx_params; + u16 txclk_divider; + + if (p->shutdown) + return cx23888_ir_tx_shutdown(sd); + + if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) + return -ENOSYS; + + mutex_lock(&state->tx_params_lock); + + o->shutdown = p->shutdown; + + o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; + + o->bytes_per_data_element = p->bytes_per_data_element + = sizeof(union cx23888_ir_fifo_rec); + + /* Before we tweak the hardware, we have to disable the transmitter */ + irqenable_tx(dev, 0); + control_tx_enable(dev, false); + + control_tx_modulation_enable(dev, p->modulation); + o->modulation = p->modulation; + + if (p->modulation) { + p->carrier_freq = txclk_tx_s_carrier(dev, p->carrier_freq, + &txclk_divider); + o->carrier_freq = p->carrier_freq; + + p->duty_cycle = cduty_tx_s_duty_cycle(dev, p->duty_cycle); + o->duty_cycle = p->duty_cycle; + + p->max_pulse_width = + (u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider); + } else { + p->max_pulse_width = + txclk_tx_s_max_pulse_width(dev, p->max_pulse_width, + &txclk_divider); + } + o->max_pulse_width = p->max_pulse_width; + atomic_set(&state->txclk_divider, txclk_divider); + + p->resolution = clock_divider_to_resolution(txclk_divider); + o->resolution = p->resolution; + + /* FIXME - make this dependent on resolution for better performance */ + control_tx_irq_watermark(dev, TX_FIFO_HALF_EMPTY); + + control_tx_polarity_invert(dev, p->invert_carrier_sense); + o->invert_carrier_sense = p->invert_carrier_sense; + + control_tx_level_invert(dev, p->invert_level); + o->invert_level = p->invert_level; + + o->interrupt_enable = p->interrupt_enable; + o->enable = p->enable; + if (p->enable) { + if (p->interrupt_enable) + irqenable_tx(dev, IRQEN_TSE); + control_tx_enable(dev, p->enable); + } + + mutex_unlock(&state->tx_params_lock); + return 0; +} + + +/* + * V4L2 Subdevice Core Ops + */ +static int cx23888_ir_log_status(struct v4l2_subdev *sd) +{ + struct cx23888_ir_state *state = to_state(sd); + struct cx23885_dev *dev = state->dev; + char *s; + int i, j; + + u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); + u32 txclk = cx23888_ir_read4(dev, CX23888_IR_TXCLK_REG) & TXCLK_TCD; + u32 rxclk = cx23888_ir_read4(dev, CX23888_IR_RXCLK_REG) & RXCLK_RCD; + u32 cduty = cx23888_ir_read4(dev, CX23888_IR_CDUTY_REG) & CDUTY_CDC; + u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); + u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); + u32 filtr = cx23888_ir_read4(dev, CX23888_IR_FILTR_REG) & FILTR_LPF; + + v4l2_info(sd, "IR Receiver:\n"); + v4l2_info(sd, "\tEnabled: %s\n", + cntrl & CNTRL_RXE ? "yes" : "no"); + v4l2_info(sd, "\tDemodulation from a carrier: %s\n", + cntrl & CNTRL_DMD ? "enabled" : "disabled"); + v4l2_info(sd, "\tFIFO: %s\n", + cntrl & CNTRL_RFE ? "enabled" : "disabled"); + switch (cntrl & CNTRL_EDG) { + case CNTRL_EDG_NONE: + s = "disabled"; + break; + case CNTRL_EDG_FALL: + s = "falling edge"; + break; + case CNTRL_EDG_RISE: + s = "rising edge"; + break; + case CNTRL_EDG_BOTH: + s = "rising & falling edges"; + break; + default: + s = "??? edge"; + break; + } + v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s); + v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n", + cntrl & CNTRL_R ? "not loaded" : "overflow marker"); + v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", + cntrl & CNTRL_RIC ? "not empty" : "half full or greater"); + v4l2_info(sd, "\tLoopback mode: %s\n", + cntrl & CNTRL_LBM ? "loopback active" : "normal receive"); + if (cntrl & CNTRL_DMD) { + v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n", + clock_divider_to_carrier_freq(rxclk)); + switch (cntrl & CNTRL_WIN) { + case CNTRL_WIN_3_3: + i = 3; + j = 3; + break; + case CNTRL_WIN_4_3: + i = 4; + j = 3; + break; + case CNTRL_WIN_3_4: + i = 3; + j = 4; + break; + case CNTRL_WIN_4_4: + i = 4; + j = 4; + break; + default: + i = 0; + j = 0; + break; + } + v4l2_info(sd, "\tNext carrier edge window: 16 clocks " + "-%1d/+%1d, %u to %u Hz\n", i, j, + clock_divider_to_freq(rxclk, 16 + j), + clock_divider_to_freq(rxclk, 16 - i)); + } + v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n", + pulse_width_count_to_us(FIFO_RXTX, rxclk), + pulse_width_count_to_ns(FIFO_RXTX, rxclk)); + v4l2_info(sd, "\tLow pass filter: %s\n", + filtr ? "enabled" : "disabled"); + if (filtr) + v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " + "%u ns\n", + lpf_count_to_us(filtr), + lpf_count_to_ns(filtr)); + v4l2_info(sd, "\tPulse width timer timed-out: %s\n", + stats & STATS_RTO ? "yes" : "no"); + v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", + irqen & IRQEN_RTE ? "enabled" : "disabled"); + v4l2_info(sd, "\tFIFO overrun: %s\n", + stats & STATS_ROR ? "yes" : "no"); + v4l2_info(sd, "\tFIFO overrun interrupt: %s\n", + irqen & IRQEN_ROE ? "enabled" : "disabled"); + v4l2_info(sd, "\tBusy: %s\n", + stats & STATS_RBY ? "yes" : "no"); + v4l2_info(sd, "\tFIFO service requested: %s\n", + stats & STATS_RSR ? "yes" : "no"); + v4l2_info(sd, "\tFIFO service request interrupt: %s\n", + irqen & IRQEN_RSE ? "enabled" : "disabled"); + + v4l2_info(sd, "IR Transmitter:\n"); + v4l2_info(sd, "\tEnabled: %s\n", + cntrl & CNTRL_TXE ? "yes" : "no"); + v4l2_info(sd, "\tModulation onto a carrier: %s\n", + cntrl & CNTRL_MOD ? "enabled" : "disabled"); + v4l2_info(sd, "\tFIFO: %s\n", + cntrl & CNTRL_TFE ? "enabled" : "disabled"); + v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", + cntrl & CNTRL_TIC ? "not empty" : "half full or less"); + v4l2_info(sd, "\tOutput pin level inversion %s\n", + cntrl & CNTRL_IVO ? "yes" : "no"); + v4l2_info(sd, "\tCarrier polarity: %s\n", + cntrl & CNTRL_CPL ? "space:burst mark:noburst" + : "space:noburst mark:burst"); + if (cntrl & CNTRL_MOD) { + v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n", + clock_divider_to_carrier_freq(txclk)); + v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n", + cduty + 1); + } + v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n", + pulse_width_count_to_us(FIFO_RXTX, txclk), + pulse_width_count_to_ns(FIFO_RXTX, txclk)); + v4l2_info(sd, "\tBusy: %s\n", + stats & STATS_TBY ? "yes" : "no"); + v4l2_info(sd, "\tFIFO service requested: %s\n", + stats & STATS_TSR ? "yes" : "no"); + v4l2_info(sd, "\tFIFO service request interrupt: %s\n", + irqen & IRQEN_TSE ? "enabled" : "disabled"); + + return 0; +} + +static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match) +{ + return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2; +} + +static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct cx23888_ir_state *state = to_state(sd); + + if (cx23888_ir_dbg_match(&chip->match)) { + chip->ident = state->id; + chip->revision = state->rev; + } + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cx23888_ir_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct cx23888_ir_state *state = to_state(sd); + u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; + + if (!cx23888_ir_dbg_match(®->match)) + return -EINVAL; + if ((addr & 0x3) != 0) + return -EINVAL; + if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + reg->size = 4; + reg->val = cx23888_ir_read4(state->dev, addr); + return 0; +} + +static int cx23888_ir_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct cx23888_ir_state *state = to_state(sd); + u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; + + if (!cx23888_ir_dbg_match(®->match)) + return -EINVAL; + if ((addr & 0x3) != 0) + return -EINVAL; + if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + cx23888_ir_write4(state->dev, addr, reg->val); + return 0; +} +#endif + +static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = { + .g_chip_ident = cx23888_ir_g_chip_ident, + .log_status = cx23888_ir_log_status, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = cx23888_ir_g_register, + .s_register = cx23888_ir_s_register, +#endif + .interrupt_service_routine = cx23888_ir_irq_handler, +}; + +static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = { + .rx_read = cx23888_ir_rx_read, + .rx_g_parameters = cx23888_ir_rx_g_parameters, + .rx_s_parameters = cx23888_ir_rx_s_parameters, + + .tx_write = cx23888_ir_tx_write, + .tx_g_parameters = cx23888_ir_tx_g_parameters, + .tx_s_parameters = cx23888_ir_tx_s_parameters, +}; + +static const struct v4l2_subdev_ops cx23888_ir_controller_ops = { + .core = &cx23888_ir_core_ops, + .ir = &cx23888_ir_ir_ops, +}; + +static const struct v4l2_subdev_ir_parameters default_rx_params = { + .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec), + .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, + + .enable = false, + .interrupt_enable = false, + .shutdown = true, + + .modulation = true, + .carrier_freq = 36000, /* 36 kHz - RC-5, RC-6, and RC-6A carrier */ + + /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ + /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ + .noise_filter_min_width = 333333, /* ns */ + .carrier_range_lower = 35000, + .carrier_range_upper = 37000, + .invert_level = false, +}; + +static const struct v4l2_subdev_ir_parameters default_tx_params = { + .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec), + .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, + + .enable = false, + .interrupt_enable = false, + .shutdown = true, + + .modulation = true, + .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ + .duty_cycle = 25, /* 25 % - RC-5 carrier */ + .invert_level = false, + .invert_carrier_sense = false, +}; + +int cx23888_ir_probe(struct cx23885_dev *dev) +{ + struct cx23888_ir_state *state; + struct v4l2_subdev *sd; + struct v4l2_subdev_ir_parameters default_params; + int ret; + + state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + spin_lock_init(&state->rx_kfifo_lock); + if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL)) + return -ENOMEM; + + state->dev = dev; + state->id = V4L2_IDENT_CX23888_IR; + state->rev = 0; + sd = &state->sd; + + v4l2_subdev_init(sd, &cx23888_ir_controller_ops); + v4l2_set_subdevdata(sd, state); + /* FIXME - fix the formatting of dev->v4l2_dev.name and use it */ + snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name); + sd->grp_id = CX23885_HW_888_IR; + + ret = v4l2_device_register_subdev(&dev->v4l2_dev, sd); + if (ret == 0) { + /* + * Ensure no interrupts arrive from '888 specific conditions, + * since we ignore them in this driver to have commonality with + * similar IR controller cores. + */ + cx23888_ir_write4(dev, CX23888_IR_IRQEN_REG, 0); + + mutex_init(&state->rx_params_lock); + memcpy(&default_params, &default_rx_params, + sizeof(struct v4l2_subdev_ir_parameters)); + v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); + + mutex_init(&state->tx_params_lock); + memcpy(&default_params, &default_tx_params, + sizeof(struct v4l2_subdev_ir_parameters)); + v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); + } else { + kfifo_free(&state->rx_kfifo); + } + return ret; +} + +int cx23888_ir_remove(struct cx23885_dev *dev) +{ + struct v4l2_subdev *sd; + struct cx23888_ir_state *state; + + sd = cx23885_find_hw(dev, CX23885_HW_888_IR); + if (sd == NULL) + return -ENODEV; + + cx23888_ir_rx_shutdown(sd); + cx23888_ir_tx_shutdown(sd); + + state = to_state(sd); + v4l2_device_unregister_subdev(sd); + kfifo_free(&state->rx_kfifo); + kfree(state); + /* Nothing more to free() as state held the actual v4l2_subdev object */ + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23888-ir.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23888-ir.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23888-ir.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/cx23888-ir.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Driver for the Conexant CX23885/7/8 PCIe bridge + * + * CX23888 Integrated Consumer Infrared Controller + * + * Copyright (C) 2009 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef _CX23888_IR_H_ +#define _CX23888_IR_H_ +int cx23888_ir_probe(struct cx23885_dev *dev); +int cx23888_ir_remove(struct cx23885_dev *dev); +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,46 @@ +config VIDEO_CX23885 + tristate "Conexant cx23885 (2388x successor) support" + depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND + select SND_PCM + select I2C_ALGOBIT + select VIDEO_BTCX + select VIDEO_TUNER + select VIDEO_TVEEPROM + depends on RC_CORE + select VIDEOBUF_DVB + select VIDEOBUF_DMA_SG + select VIDEO_CX25840 + select VIDEO_CX2341X + select DVB_DIB7000P if !DVB_FE_CUSTOMISE + select DVB_S5H1409 if !DVB_FE_CUSTOMISE + select DVB_S5H1411 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_TDA10048 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE + select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STV0367 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + ---help--- + This is a video4linux driver for Conexant 23885 based + TV cards. + + To compile this driver as a module, choose M here: the + module will be called cx23885 + +config MEDIA_ALTERA_CI + tristate "Altera FPGA based CI module" + depends on VIDEO_CX23885 && DVB_CORE + select STAPL_ALTERA + ---help--- + An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. + + To compile this driver as a module, choose M here: the + module will be called altera-ci diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,15 @@ +cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \ + cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \ + cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \ + cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \ + cx23885-f300.o + +obj-$(CONFIG_VIDEO_CX23885) += cx23885.o +obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + +EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-eeprom.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-eeprom.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-eeprom.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-eeprom.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,107 @@ + +/* + * netup-eeprom.c + * + * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Abylay Ospan + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +# +#include "cx23885.h" +#include "netup-eeprom.h" + +#define EEPROM_I2C_ADDR 0x50 + +int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr) +{ + int ret; + unsigned char buf[2]; + + /* Read from EEPROM */ + struct i2c_msg msg[] = { + { + .addr = EEPROM_I2C_ADDR, + .flags = 0, + .buf = &buf[0], + .len = 1 + }, { + .addr = EEPROM_I2C_ADDR, + .flags = I2C_M_RD, + .buf = &buf[1], + .len = 1 + } + + }; + + buf[0] = addr; + buf[1] = 0x0; + + ret = i2c_transfer(i2c_adap, msg, 2); + + if (ret != 2) { + printk(KERN_ERR "eeprom i2c read error, status=%d\n", ret); + return -1; + } + + return buf[1]; +}; + +int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data) +{ + int ret; + unsigned char bufw[2]; + + /* Write into EEPROM */ + struct i2c_msg msg[] = { + { + .addr = EEPROM_I2C_ADDR, + .flags = 0, + .buf = &bufw[0], + .len = 2 + } + }; + + bufw[0] = addr; + bufw[1] = data; + + ret = i2c_transfer(i2c_adap, msg, 1); + + if (ret != 1) { + printk(KERN_ERR "eeprom i2c write error, status=%d\n", ret); + return -1; + } + + mdelay(10); /* prophylactic delay, datasheet write cycle time = 5 ms */ + return 0; +}; + +void netup_get_card_info(struct i2c_adapter *i2c_adap, + struct netup_card_info *cinfo) +{ + int i, j; + + cinfo->rev = netup_eeprom_read(i2c_adap, 63); + + for (i = 64, j = 0; i < 70; i++, j++) + cinfo->port[0].mac[j] = netup_eeprom_read(i2c_adap, i); + + for (i = 70, j = 0; i < 76; i++, j++) + cinfo->port[1].mac[j] = netup_eeprom_read(i2c_adap, i); +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-eeprom.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-eeprom.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-eeprom.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-eeprom.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * netup-eeprom.h + * + * 24LC02 EEPROM driver in conjunction with NetUP Dual DVB-S2 CI card + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Abylay Ospan + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef NETUP_EEPROM_H +#define NETUP_EEPROM_H + +struct netup_port_info { + u8 mac[6];/* card MAC address */ +}; + +struct netup_card_info { + struct netup_port_info port[2];/* ports - 1,2 */ + u8 rev;/* card revision */ +}; + +extern int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr); +extern int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data); +extern void netup_get_card_info(struct i2c_adapter *i2c_adap, + struct netup_card_info *cinfo); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-init.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-init.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-init.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-init.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,125 @@ +/* + * netup-init.c + * + * NetUP Dual DVB-S2 CI driver + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * Copyright (C) 2009 Abylay Ospan + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx23885.h" + +static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val) +{ + int ret; + u8 buf[3]; + struct i2c_msg msg = { + .addr = 0x88 >> 1, + .flags = 0, + .buf = buf, + .len = 3 + }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + buf[2] = val; + + ret = i2c_transfer(i2c, &msg, 1); + + if (ret != 1) + printk(KERN_ERR "%s: i2c write error!\n", __func__); +} + +static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val) +{ + int ret; + u8 buf[6]; + struct i2c_msg msg = { + .addr = 0x88 >> 1, + .flags = 0, + .buf = buf, + .len = 6 + }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + buf[2] = val & 0xff; + buf[3] = (val >> 8) & 0xff; + buf[4] = (val >> 16) & 0xff; + buf[5] = val >> 24; + + ret = i2c_transfer(i2c, &msg, 1); + + if (ret != 1) + printk(KERN_ERR "%s: i2c write error!\n", __func__); +} + +static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg) +{ + int ret; + u8 buf[2]; + struct i2c_msg msg = { + .addr = 0x88 >> 1, + .flags = 0, + .buf = buf, + .len = 2 + }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + ret = i2c_transfer(i2c, &msg, 1); + + if (ret != 1) + printk(KERN_ERR "%s: i2c write error!\n", __func__); + + msg.flags = I2C_M_RD; + msg.len = 1; + + ret = i2c_transfer(i2c, &msg, 1); + + if (ret != 1) + printk(KERN_ERR "%s: i2c read error!\n", __func__); + + return buf[0]; +} + +static void i2c_av_and_or(struct i2c_adapter *i2c, u16 reg, unsigned and_mask, + u8 or_value) +{ + i2c_av_write(i2c, reg, (i2c_av_read(i2c, reg) & and_mask) | or_value); +} +/* set 27MHz on AUX_CLK */ +void netup_initialize(struct cx23885_dev *dev) +{ + struct cx23885_i2c *i2c_bus = &dev->i2c_bus[2]; + struct i2c_adapter *i2c = &i2c_bus->i2c_adap; + + /* Stop microcontroller */ + i2c_av_and_or(i2c, 0x803, ~0x10, 0x00); + + /* Aux PLL frac for 27 MHz */ + i2c_av_write4(i2c, 0x114, 0xea0eb3); + + /* Aux PLL int for 27 MHz */ + i2c_av_write4(i2c, 0x110, 0x090319); + + /* start microcontroller */ + i2c_av_and_or(i2c, 0x803, ~0x10, 0x10); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-init.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-init.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-init.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx23885/netup-init.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * netup-init.h + * + * NetUP Dual DVB-S2 CI driver + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * Copyright (C) 2009 Abylay Ospan + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +extern void netup_initialize(struct cx23885_dev *dev); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-audio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-audio.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,571 @@ +/* cx25840 audio functions + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include +#include + +#include "cx25840-core.h" + +/* + * Note: The PLL and SRC parameters are based on a reference frequency that + * would ideally be: + * + * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz + * + * However, it's not the exact reference frequency that matters, only that the + * firmware and modules that comprise the driver for a particular board all + * use the same value (close to the ideal value). + * + * Comments below will note which reference frequency is assumed for various + * parameters. They will usually be one of + * + * ref_freq = 28.636360 MHz + * or + * ref_freq = 28.636363 MHz + */ + +static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + + if (state->aud_input != CX25840_AUDIO_SERIAL) { + switch (freq) { + case 32000: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10 + */ + cx25840_write4(client, 0x108, 0x1006040f); + + /* + * VID_PLL Fraction (register 0x10c) = 0x2be2fe + * 28636360 * 0xf.15f17f0/4 = 108 MHz + * 432 MHz pre-postdivide + */ + + /* + * AUX_PLL Fraction = 0x1bb39ee + * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384 + * 196.6 MHz pre-postdivide + * FIXME < 200 MHz is out of specified valid range + * FIXME 28636363 ref_freq doesn't match VID PLL ref + */ + cx25840_write4(client, 0x110, 0x01bb39ee); + + /* + * SA_MCLK_SEL = 1 + * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider + */ + cx25840_write(client, 0x127, 0x50); + + if (is_cx2583x(state)) + break; + + /* src3/4/6_ctl */ + /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */ + cx25840_write4(client, 0x900, 0x0801f77f); + cx25840_write4(client, 0x904, 0x0801f77f); + cx25840_write4(client, 0x90c, 0x0801f77f); + break; + + case 44100: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10 + */ + cx25840_write4(client, 0x108, 0x1009040f); + + /* + * VID_PLL Fraction (register 0x10c) = 0x2be2fe + * 28636360 * 0xf.15f17f0/4 = 108 MHz + * 432 MHz pre-postdivide + */ + + /* + * AUX_PLL Fraction = 0x0ec6bd6 + * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384 + * 271 MHz pre-postdivide + * FIXME 28636363 ref_freq doesn't match VID PLL ref + */ + cx25840_write4(client, 0x110, 0x00ec6bd6); + + /* + * SA_MCLK_SEL = 1 + * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider + */ + cx25840_write(client, 0x127, 0x50); + + if (is_cx2583x(state)) + break; + + /* src3/4/6_ctl */ + /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */ + cx25840_write4(client, 0x900, 0x08016d59); + cx25840_write4(client, 0x904, 0x08016d59); + cx25840_write4(client, 0x90c, 0x08016d59); + break; + + case 48000: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10 + */ + cx25840_write4(client, 0x108, 0x100a040f); + + /* + * VID_PLL Fraction (register 0x10c) = 0x2be2fe + * 28636360 * 0xf.15f17f0/4 = 108 MHz + * 432 MHz pre-postdivide + */ + + /* + * AUX_PLL Fraction = 0x098d6e5 + * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384 + * 295 MHz pre-postdivide + * FIXME 28636363 ref_freq doesn't match VID PLL ref + */ + cx25840_write4(client, 0x110, 0x0098d6e5); + + /* + * SA_MCLK_SEL = 1 + * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider + */ + cx25840_write(client, 0x127, 0x50); + + if (is_cx2583x(state)) + break; + + /* src3/4/6_ctl */ + /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ + cx25840_write4(client, 0x900, 0x08014faa); + cx25840_write4(client, 0x904, 0x08014faa); + cx25840_write4(client, 0x90c, 0x08014faa); + break; + } + } else { + switch (freq) { + case 32000: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e + */ + cx25840_write4(client, 0x108, 0x1e08040f); + + /* + * VID_PLL Fraction (register 0x10c) = 0x2be2fe + * 28636360 * 0xf.15f17f0/4 = 108 MHz + * 432 MHz pre-postdivide + */ + + /* + * AUX_PLL Fraction = 0x12a0869 + * 28636363 * 0x8.9504348/0x1e = 32000 * 256 + * 246 MHz pre-postdivide + * FIXME 28636363 ref_freq doesn't match VID PLL ref + */ + cx25840_write4(client, 0x110, 0x012a0869); + + /* + * SA_MCLK_SEL = 1 + * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider + */ + cx25840_write(client, 0x127, 0x54); + + if (is_cx2583x(state)) + break; + + /* src1_ctl */ + /* 0x1.0000 = 32000/32000 */ + cx25840_write4(client, 0x8f8, 0x08010000); + + /* src3/4/6_ctl */ + /* 0x2.0000 = 2 * (32000/32000) */ + cx25840_write4(client, 0x900, 0x08020000); + cx25840_write4(client, 0x904, 0x08020000); + cx25840_write4(client, 0x90c, 0x08020000); + break; + + case 44100: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18 + */ + cx25840_write4(client, 0x108, 0x1809040f); + + /* + * VID_PLL Fraction (register 0x10c) = 0x2be2fe + * 28636360 * 0xf.15f17f0/4 = 108 MHz + * 432 MHz pre-postdivide + */ + + /* + * AUX_PLL Fraction = 0x0ec6bd6 + * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256 + * 271 MHz pre-postdivide + * FIXME 28636363 ref_freq doesn't match VID PLL ref + */ + cx25840_write4(client, 0x110, 0x00ec6bd6); + + /* + * SA_MCLK_SEL = 1 + * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider + */ + cx25840_write(client, 0x127, 0x50); + + if (is_cx2583x(state)) + break; + + /* src1_ctl */ + /* 0x1.60cd = 44100/32000 */ + cx25840_write4(client, 0x8f8, 0x080160cd); + + /* src3/4/6_ctl */ + /* 0x1.7385 = 2 * (32000/44100) */ + cx25840_write4(client, 0x900, 0x08017385); + cx25840_write4(client, 0x904, 0x08017385); + cx25840_write4(client, 0x90c, 0x08017385); + break; + + case 48000: + /* + * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 + * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18 + */ + cx25840_write4(client, 0x108, 0x180a040f); + + /* + * VID_PLL Fraction (register 0x10c) = 0x2be2fe + * 28636360 * 0xf.15f17f0/4 = 108 MHz + * 432 MHz pre-postdivide + */ + + /* + * AUX_PLL Fraction = 0x098d6e5 + * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256 + * 295 MHz pre-postdivide + * FIXME 28636363 ref_freq doesn't match VID PLL ref + */ + cx25840_write4(client, 0x110, 0x0098d6e5); + + /* + * SA_MCLK_SEL = 1 + * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider + */ + cx25840_write(client, 0x127, 0x50); + + if (is_cx2583x(state)) + break; + + /* src1_ctl */ + /* 0x1.8000 = 48000/32000 */ + cx25840_write4(client, 0x8f8, 0x08018000); + + /* src3/4/6_ctl */ + /* 0x1.5555 = 2 * (32000/48000) */ + cx25840_write4(client, 0x900, 0x08015555); + cx25840_write4(client, 0x904, 0x08015555); + cx25840_write4(client, 0x90c, 0x08015555); + break; + } + } + + state->audclk_freq = freq; + + return 0; +} + +static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq) +{ + return cx25840_set_audclk_freq(client, freq); +} + +static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + + if (state->aud_input != CX25840_AUDIO_SERIAL) { + switch (freq) { + case 32000: + case 44100: + case 48000: + /* We don't have register values + * so avoid destroying registers. */ + /* FIXME return -EINVAL; */ + break; + } + } else { + switch (freq) { + case 32000: + case 44100: + /* We don't have register values + * so avoid destroying registers. */ + /* FIXME return -EINVAL; */ + break; + + case 48000: + /* src1_ctl */ + /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */ + cx25840_write4(client, 0x8f8, 0x0801867c); + + /* src3/4/6_ctl */ + /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ + cx25840_write4(client, 0x900, 0x08014faa); + cx25840_write4(client, 0x904, 0x08014faa); + cx25840_write4(client, 0x90c, 0x08014faa); + break; + } + } + + state->audclk_freq = freq; + + return 0; +} + +static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + + if (state->aud_input != CX25840_AUDIO_SERIAL) { + switch (freq) { + case 32000: + /* src3/4/6_ctl */ + /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */ + cx25840_write4(client, 0x900, 0x0801f77f); + cx25840_write4(client, 0x904, 0x0801f77f); + cx25840_write4(client, 0x90c, 0x0801f77f); + break; + + case 44100: + /* src3/4/6_ctl */ + /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */ + cx25840_write4(client, 0x900, 0x08016d59); + cx25840_write4(client, 0x904, 0x08016d59); + cx25840_write4(client, 0x90c, 0x08016d59); + break; + + case 48000: + /* src3/4/6_ctl */ + /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ + cx25840_write4(client, 0x900, 0x08014faa); + cx25840_write4(client, 0x904, 0x08014faa); + cx25840_write4(client, 0x90c, 0x08014faa); + break; + } + } else { + switch (freq) { + /* FIXME These cases make different assumptions about audclk */ + case 32000: + /* src1_ctl */ + /* 0x1.0000 = 32000/32000 */ + cx25840_write4(client, 0x8f8, 0x08010000); + + /* src3/4/6_ctl */ + /* 0x2.0000 = 2 * (32000/32000) */ + cx25840_write4(client, 0x900, 0x08020000); + cx25840_write4(client, 0x904, 0x08020000); + cx25840_write4(client, 0x90c, 0x08020000); + break; + + case 44100: + /* src1_ctl */ + /* 0x1.60cd = 44100/32000 */ + cx25840_write4(client, 0x8f8, 0x080160cd); + + /* src3/4/6_ctl */ + /* 0x1.7385 = 2 * (32000/44100) */ + cx25840_write4(client, 0x900, 0x08017385); + cx25840_write4(client, 0x904, 0x08017385); + cx25840_write4(client, 0x90c, 0x08017385); + break; + + case 48000: + /* src1_ctl */ + /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */ + cx25840_write4(client, 0x8f8, 0x0801867c); + + /* src3/4/6_ctl */ + /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ + cx25840_write4(client, 0x900, 0x08014faa); + cx25840_write4(client, 0x904, 0x08014faa); + cx25840_write4(client, 0x90c, 0x08014faa); + break; + } + } + + state->audclk_freq = freq; + + return 0; +} + +static int set_audclk_freq(struct i2c_client *client, u32 freq) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + + if (freq != 32000 && freq != 44100 && freq != 48000) + return -EINVAL; + + if (is_cx231xx(state)) + return cx231xx_set_audclk_freq(client, freq); + + if (is_cx2388x(state)) + return cx23885_set_audclk_freq(client, freq); + + if (is_cx2583x(state)) + return cx25836_set_audclk_freq(client, freq); + + return cx25840_set_audclk_freq(client, freq); +} + +void cx25840_audio_set_path(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + + if (!is_cx2583x(state)) { + /* assert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x01); + + /* stop microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0); + + /* Mute everything to prevent the PFFT! */ + cx25840_write(client, 0x8d3, 0x1f); + + if (state->aud_input == CX25840_AUDIO_SERIAL) { + /* Set Path1 to Serial Audio Input */ + cx25840_write4(client, 0x8d0, 0x01011012); + + /* The microcontroller should not be started for the + * non-tuner inputs: autodetection is specific for + * TV audio. */ + } else { + /* Set Path1 to Analog Demod Main Channel */ + cx25840_write4(client, 0x8d0, 0x1f063870); + } + } + + set_audclk_freq(client, state->audclk_freq); + + if (!is_cx2583x(state)) { + if (state->aud_input != CX25840_AUDIO_SERIAL) { + /* When the microcontroller detects the + * audio format, it will unmute the lines */ + cx25840_and_or(client, 0x803, ~0x10, 0x10); + } + + /* deassert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x00); + + /* Ensure the controller is running when we exit */ + if (is_cx2388x(state) || is_cx231xx(state)) + cx25840_and_or(client, 0x803, ~0x10, 0x10); + } +} + +static void set_volume(struct i2c_client *client, int volume) +{ + int vol; + + /* Convert the volume to msp3400 values (0-127) */ + vol = volume >> 9; + + /* now scale it up to cx25840 values + * -114dB to -96dB maps to 0 + * this should be 19, but in my testing that was 4dB too loud */ + if (vol <= 23) { + vol = 0; + } else { + vol -= 23; + } + + /* PATH1_VOLUME */ + cx25840_write(client, 0x8d4, 228 - (vol * 2)); +} + +static void set_balance(struct i2c_client *client, int balance) +{ + int bal = balance >> 8; + if (bal > 0x80) { + /* PATH1_BAL_LEFT */ + cx25840_and_or(client, 0x8d5, 0x7f, 0x80); + /* PATH1_BAL_LEVEL */ + cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f); + } else { + /* PATH1_BAL_LEFT */ + cx25840_and_or(client, 0x8d5, 0x7f, 0x00); + /* PATH1_BAL_LEVEL */ + cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal); + } +} + +int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct cx25840_state *state = to_state(sd); + int retval; + + if (!is_cx2583x(state)) + cx25840_and_or(client, 0x810, ~0x1, 1); + if (state->aud_input != CX25840_AUDIO_SERIAL) { + cx25840_and_or(client, 0x803, ~0x10, 0); + cx25840_write(client, 0x8d3, 0x1f); + } + retval = set_audclk_freq(client, freq); + if (state->aud_input != CX25840_AUDIO_SERIAL) + cx25840_and_or(client, 0x803, ~0x10, 0x10); + if (!is_cx2583x(state)) + cx25840_and_or(client, 0x810, ~0x1, 0); + return retval; +} + +static int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + if (state->mute->val) + set_volume(client, 0); + else + set_volume(client, state->volume->val); + break; + case V4L2_CID_AUDIO_BASS: + /* PATH1_EQ_BASS_VOL */ + cx25840_and_or(client, 0x8d9, ~0x3f, + 48 - (ctrl->val * 48 / 0xffff)); + break; + case V4L2_CID_AUDIO_TREBLE: + /* PATH1_EQ_TREBLE_VOL */ + cx25840_and_or(client, 0x8db, ~0x3f, + 48 - (ctrl->val * 48 / 0xffff)); + break; + case V4L2_CID_AUDIO_BALANCE: + set_balance(client, ctrl->val); + break; + default: + return -EINVAL; + } + return 0; +} + +const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops = { + .s_ctrl = cx25840_audio_s_ctrl, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2071 @@ +/* cx25840 - Conexant CX25840 audio/video decoder driver + * + * Copyright (C) 2004 Ulf Eklund + * + * Based on the saa7115 driver and on the first version of Chris Kennedy's + * cx25840 driver. + * + * Changes by Tyler Trafford + * - cleanup/rewrite for V4L2 API (2005) + * + * VBI support by Hans Verkuil . + * + * NTSC sliced VBI support by Christopher Neufeld + * with additional fixes by Hans Verkuil . + * + * CX23885 support by Steven Toth . + * + * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are + * Copyright (C) 2010 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx25840-core.h" + +MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver"); +MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford"); +MODULE_LICENSE("GPL"); + +#define CX25840_VID_INT_STAT_REG 0x410 +#define CX25840_VID_INT_STAT_BITS 0x0000ffff +#define CX25840_VID_INT_MASK_BITS 0xffff0000 +#define CX25840_VID_INT_MASK_SHFT 16 +#define CX25840_VID_INT_MASK_REG 0x412 + +#define CX23885_AUD_MC_INT_MASK_REG 0x80c +#define CX23885_AUD_MC_INT_STAT_BITS 0xffff0000 +#define CX23885_AUD_MC_INT_CTRL_BITS 0x0000ffff +#define CX23885_AUD_MC_INT_STAT_SHFT 16 + +#define CX25840_AUD_INT_CTRL_REG 0x812 +#define CX25840_AUD_INT_STAT_REG 0x813 + +#define CX23885_PIN_CTRL_IRQ_REG 0x123 +#define CX23885_PIN_CTRL_IRQ_IR_STAT 0x40 +#define CX23885_PIN_CTRL_IRQ_AUD_STAT 0x20 +#define CX23885_PIN_CTRL_IRQ_VID_STAT 0x10 + +#define CX25840_IR_STATS_REG 0x210 +#define CX25840_IR_IRQEN_REG 0x214 + +static int cx25840_debug; + +module_param_named(debug,cx25840_debug, int, 0644); + +MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); + + +/* ----------------------------------------------------------------------- */ + +int cx25840_write(struct i2c_client *client, u16 addr, u8 value) +{ + u8 buffer[3]; + buffer[0] = addr >> 8; + buffer[1] = addr & 0xff; + buffer[2] = value; + return i2c_master_send(client, buffer, 3); +} + +int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) +{ + u8 buffer[6]; + buffer[0] = addr >> 8; + buffer[1] = addr & 0xff; + buffer[2] = value & 0xff; + buffer[3] = (value >> 8) & 0xff; + buffer[4] = (value >> 16) & 0xff; + buffer[5] = value >> 24; + return i2c_master_send(client, buffer, 6); +} + +u8 cx25840_read(struct i2c_client * client, u16 addr) +{ + struct i2c_msg msgs[2]; + u8 tx_buf[2], rx_buf[1]; + + /* Write register address */ + tx_buf[0] = addr >> 8; + tx_buf[1] = addr & 0xff; + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (char *) tx_buf; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = 1; + msgs[1].buf = (char *) rx_buf; + + if (i2c_transfer(client->adapter, msgs, 2) < 2) + return 0; + + return rx_buf[0]; +} + +u32 cx25840_read4(struct i2c_client * client, u16 addr) +{ + struct i2c_msg msgs[2]; + u8 tx_buf[2], rx_buf[4]; + + /* Write register address */ + tx_buf[0] = addr >> 8; + tx_buf[1] = addr & 0xff; + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (char *) tx_buf; + + /* Read data from registers */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = 4; + msgs[1].buf = (char *) rx_buf; + + if (i2c_transfer(client->adapter, msgs, 2) < 2) + return 0; + + return (rx_buf[3] << 24) | (rx_buf[2] << 16) | (rx_buf[1] << 8) | + rx_buf[0]; +} + +int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, + u8 or_value) +{ + return cx25840_write(client, addr, + (cx25840_read(client, addr) & and_mask) | + or_value); +} + +int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, + u32 or_value) +{ + return cx25840_write4(client, addr, + (cx25840_read4(client, addr) & and_mask) | + or_value); +} + +/* ----------------------------------------------------------------------- */ + +static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, + enum cx25840_audio_input aud_input); + +/* ----------------------------------------------------------------------- */ + +static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, + struct v4l2_subdev_io_pin_config *p) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int i; + u32 pin_ctrl; + u8 gpio_oe, gpio_data, strength; + + pin_ctrl = cx25840_read4(client, 0x120); + gpio_oe = cx25840_read(client, 0x160); + gpio_data = cx25840_read(client, 0x164); + + for (i = 0; i < n; i++) { + strength = p[i].strength; + if (strength > CX25840_PIN_DRIVE_FAST) + strength = CX25840_PIN_DRIVE_FAST; + + switch (p[i].pin) { + case CX23885_PIN_IRQ_N_GPIO16: + if (p[i].function != CX23885_PAD_IRQ_N) { + /* GPIO16 */ + pin_ctrl &= ~(0x1 << 25); + } else { + /* IRQ_N */ + if (p[i].flags & + (V4L2_SUBDEV_IO_PIN_DISABLE | + V4L2_SUBDEV_IO_PIN_INPUT)) { + pin_ctrl &= ~(0x1 << 25); + } else { + pin_ctrl |= (0x1 << 25); + } + if (p[i].flags & + V4L2_SUBDEV_IO_PIN_ACTIVE_LOW) { + pin_ctrl &= ~(0x1 << 24); + } else { + pin_ctrl |= (0x1 << 24); + } + } + break; + case CX23885_PIN_IR_RX_GPIO19: + if (p[i].function != CX23885_PAD_GPIO19) { + /* IR_RX */ + gpio_oe |= (0x1 << 0); + pin_ctrl &= ~(0x3 << 18); + pin_ctrl |= (strength << 18); + } else { + /* GPIO19 */ + gpio_oe &= ~(0x1 << 0); + if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + gpio_data &= ~(0x1 << 0); + gpio_data |= ((p[i].value & 0x1) << 0); + } + pin_ctrl &= ~(0x3 << 12); + pin_ctrl |= (strength << 12); + } + break; + case CX23885_PIN_IR_TX_GPIO20: + if (p[i].function != CX23885_PAD_GPIO20) { + /* IR_TX */ + gpio_oe |= (0x1 << 1); + if (p[i].flags & V4L2_SUBDEV_IO_PIN_DISABLE) + pin_ctrl &= ~(0x1 << 10); + else + pin_ctrl |= (0x1 << 10); + pin_ctrl &= ~(0x3 << 18); + pin_ctrl |= (strength << 18); + } else { + /* GPIO20 */ + gpio_oe &= ~(0x1 << 1); + if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + gpio_data &= ~(0x1 << 1); + gpio_data |= ((p[i].value & 0x1) << 1); + } + pin_ctrl &= ~(0x3 << 12); + pin_ctrl |= (strength << 12); + } + break; + case CX23885_PIN_I2S_SDAT_GPIO21: + if (p[i].function != CX23885_PAD_GPIO21) { + /* I2S_SDAT */ + /* TODO: Input or Output config */ + gpio_oe |= (0x1 << 2); + pin_ctrl &= ~(0x3 << 22); + pin_ctrl |= (strength << 22); + } else { + /* GPIO21 */ + gpio_oe &= ~(0x1 << 2); + if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + gpio_data &= ~(0x1 << 2); + gpio_data |= ((p[i].value & 0x1) << 2); + } + pin_ctrl &= ~(0x3 << 12); + pin_ctrl |= (strength << 12); + } + break; + case CX23885_PIN_I2S_WCLK_GPIO22: + if (p[i].function != CX23885_PAD_GPIO22) { + /* I2S_WCLK */ + /* TODO: Input or Output config */ + gpio_oe |= (0x1 << 3); + pin_ctrl &= ~(0x3 << 22); + pin_ctrl |= (strength << 22); + } else { + /* GPIO22 */ + gpio_oe &= ~(0x1 << 3); + if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + gpio_data &= ~(0x1 << 3); + gpio_data |= ((p[i].value & 0x1) << 3); + } + pin_ctrl &= ~(0x3 << 12); + pin_ctrl |= (strength << 12); + } + break; + case CX23885_PIN_I2S_BCLK_GPIO23: + if (p[i].function != CX23885_PAD_GPIO23) { + /* I2S_BCLK */ + /* TODO: Input or Output config */ + gpio_oe |= (0x1 << 4); + pin_ctrl &= ~(0x3 << 22); + pin_ctrl |= (strength << 22); + } else { + /* GPIO23 */ + gpio_oe &= ~(0x1 << 4); + if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + gpio_data &= ~(0x1 << 4); + gpio_data |= ((p[i].value & 0x1) << 4); + } + pin_ctrl &= ~(0x3 << 12); + pin_ctrl |= (strength << 12); + } + break; + } + } + + cx25840_write(client, 0x164, gpio_data); + cx25840_write(client, 0x160, gpio_oe); + cx25840_write4(client, 0x120, pin_ctrl); + return 0; +} + +static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n, + struct v4l2_subdev_io_pin_config *pincfg) +{ + struct cx25840_state *state = to_state(sd); + + if (is_cx2388x(state)) + return cx23885_s_io_pin_config(sd, n, pincfg); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static void init_dll1(struct i2c_client *client) +{ + /* This is the Hauppauge sequence used to + * initialize the Delay Lock Loop 1 (ADC DLL). */ + cx25840_write(client, 0x159, 0x23); + cx25840_write(client, 0x15a, 0x87); + cx25840_write(client, 0x15b, 0x06); + udelay(10); + cx25840_write(client, 0x159, 0xe1); + udelay(10); + cx25840_write(client, 0x15a, 0x86); + cx25840_write(client, 0x159, 0xe0); + cx25840_write(client, 0x159, 0xe1); + cx25840_write(client, 0x15b, 0x10); +} + +static void init_dll2(struct i2c_client *client) +{ + /* This is the Hauppauge sequence used to + * initialize the Delay Lock Loop 2 (ADC DLL). */ + cx25840_write(client, 0x15d, 0xe3); + cx25840_write(client, 0x15e, 0x86); + cx25840_write(client, 0x15f, 0x06); + udelay(10); + cx25840_write(client, 0x15d, 0xe1); + cx25840_write(client, 0x15d, 0xe0); + cx25840_write(client, 0x15d, 0xe1); +} + +static void cx25836_initialize(struct i2c_client *client) +{ + /* reset configuration is described on page 3-77 of the CX25836 datasheet */ + /* 2. */ + cx25840_and_or(client, 0x000, ~0x01, 0x01); + cx25840_and_or(client, 0x000, ~0x01, 0x00); + /* 3a. */ + cx25840_and_or(client, 0x15a, ~0x70, 0x00); + /* 3b. */ + cx25840_and_or(client, 0x15b, ~0x1e, 0x06); + /* 3c. */ + cx25840_and_or(client, 0x159, ~0x02, 0x02); + /* 3d. */ + udelay(10); + /* 3e. */ + cx25840_and_or(client, 0x159, ~0x02, 0x00); + /* 3f. */ + cx25840_and_or(client, 0x159, ~0xc0, 0xc0); + /* 3g. */ + cx25840_and_or(client, 0x159, ~0x01, 0x00); + cx25840_and_or(client, 0x159, ~0x01, 0x01); + /* 3h. */ + cx25840_and_or(client, 0x15b, ~0x1e, 0x10); +} + +static void cx25840_work_handler(struct work_struct *work) +{ + struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); + cx25840_loadfw(state->c); + wake_up(&state->fw_wait); +} + +static void cx25840_initialize(struct i2c_client *client) +{ + DEFINE_WAIT(wait); + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + struct workqueue_struct *q; + + /* datasheet startup in numbered steps, refer to page 3-77 */ + /* 2. */ + cx25840_and_or(client, 0x803, ~0x10, 0x00); + /* The default of this register should be 4, but I get 0 instead. + * Set this register to 4 manually. */ + cx25840_write(client, 0x000, 0x04); + /* 3. */ + init_dll1(client); + init_dll2(client); + cx25840_write(client, 0x136, 0x0a); + /* 4. */ + cx25840_write(client, 0x13c, 0x01); + cx25840_write(client, 0x13c, 0x00); + /* 5. */ + /* Do the firmware load in a work handler to prevent. + Otherwise the kernel is blocked waiting for the + bit-banging i2c interface to finish uploading the + firmware. */ + INIT_WORK(&state->fw_work, cx25840_work_handler); + init_waitqueue_head(&state->fw_wait); + q = create_singlethread_workqueue("cx25840_fw"); + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + + /* 6. */ + cx25840_write(client, 0x115, 0x8c); + cx25840_write(client, 0x116, 0x07); + cx25840_write(client, 0x118, 0x02); + /* 7. */ + cx25840_write(client, 0x4a5, 0x80); + cx25840_write(client, 0x4a5, 0x00); + cx25840_write(client, 0x402, 0x00); + /* 8. */ + cx25840_and_or(client, 0x401, ~0x18, 0); + cx25840_and_or(client, 0x4a2, ~0x10, 0x10); + /* steps 8c and 8d are done in change_input() */ + /* 10. */ + cx25840_write(client, 0x8d3, 0x1f); + cx25840_write(client, 0x8e3, 0x03); + + cx25840_std_setup(client); + + /* trial and error says these are needed to get audio */ + cx25840_write(client, 0x914, 0xa0); + cx25840_write(client, 0x918, 0xa0); + cx25840_write(client, 0x919, 0x01); + + /* stereo preferred */ + cx25840_write(client, 0x809, 0x04); + /* AC97 shift */ + cx25840_write(client, 0x8cf, 0x0f); + + /* (re)set input */ + set_input(client, state->vid_input, state->aud_input); + + /* start microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0x10); +} + +static void cx23885_initialize(struct i2c_client *client) +{ + DEFINE_WAIT(wait); + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + struct workqueue_struct *q; + + /* + * Come out of digital power down + * The CX23888, at least, needs this, otherwise registers aside from + * 0x0-0x2 can't be read or written. + */ + cx25840_write(client, 0x000, 0); + + /* Internal Reset */ + cx25840_and_or(client, 0x102, ~0x01, 0x01); + cx25840_and_or(client, 0x102, ~0x01, 0x00); + + /* Stop microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0x00); + + /* DIF in reset? */ + cx25840_write(client, 0x398, 0); + + /* + * Trust the default xtal, no division + * '885: 28.636363... MHz + * '887: 25.000000 MHz + * '888: 50.000000 MHz + */ + cx25840_write(client, 0x2, 0x76); + + /* Power up all the PLL's and DLL */ + cx25840_write(client, 0x1, 0x40); + + /* Sys PLL */ + switch (state->id) { + case V4L2_IDENT_CX23888_AV: + /* + * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz + * 572.73 MHz before post divide + */ + cx25840_write4(client, 0x11c, 0x00e8ba26); + cx25840_write4(client, 0x118, 0x0000040b); + break; + case V4L2_IDENT_CX23887_AV: + /* + * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz + * 572.73 MHz before post divide + */ + cx25840_write4(client, 0x11c, 0x01d1744c); + cx25840_write4(client, 0x118, 0x00000416); + break; + case V4L2_IDENT_CX23885_AV: + default: + /* + * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz + * 572.73 MHz before post divide + */ + cx25840_write4(client, 0x11c, 0x00000000); + cx25840_write4(client, 0x118, 0x00000414); + break; + } + + /* Disable DIF bypass */ + cx25840_write4(client, 0x33c, 0x00000001); + + /* DIF Src phase inc */ + cx25840_write4(client, 0x340, 0x0df7df83); + + /* + * Vid PLL + * Setup for a BT.656 pixel clock of 13.5 Mpixels/second + * + * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz + * 432.0 MHz before post divide + */ + cx25840_write4(client, 0x10c, 0x002be2c9); + cx25840_write4(client, 0x108, 0x0000040f); + + /* Luma */ + cx25840_write4(client, 0x414, 0x00107d12); + + /* Chroma */ + cx25840_write4(client, 0x420, 0x3d008282); + + /* + * Aux PLL + * Initial setup for audio sample clock: + * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz + * Initial I2S output/master clock(?): + * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz + */ + switch (state->id) { + case V4L2_IDENT_CX23888_AV: + /* + * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz + * 368.64 MHz before post divide + * 122.88 MHz / 0xa = 12.288 MHz + */ + cx25840_write4(client, 0x114, 0x00bedfa4); + cx25840_write4(client, 0x110, 0x000a0307); + break; + case V4L2_IDENT_CX23887_AV: + /* + * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz + * 368.64 MHz before post divide + * 122.88 MHz / 0xa = 12.288 MHz + */ + cx25840_write4(client, 0x114, 0x017dbf48); + cx25840_write4(client, 0x110, 0x000a030e); + break; + case V4L2_IDENT_CX23885_AV: + default: + /* + * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz + * 368.64 MHz before post divide + * 122.88 MHz / 0xa = 12.288 MHz + */ + cx25840_write4(client, 0x114, 0x01bf0c9e); + cx25840_write4(client, 0x110, 0x000a030c); + break; + }; + + /* ADC2 input select */ + cx25840_write(client, 0x102, 0x10); + + /* VIN1 & VIN5 */ + cx25840_write(client, 0x103, 0x11); + + /* Enable format auto detect */ + cx25840_write(client, 0x400, 0); + /* Fast subchroma lock */ + /* White crush, Chroma AGC & Chroma Killer enabled */ + cx25840_write(client, 0x401, 0xe8); + + /* Select AFE clock pad output source */ + cx25840_write(client, 0x144, 0x05); + + /* Drive GPIO2 direction and values for HVR1700 + * where an onboard mux selects the output of demodulator + * vs the 417. Failure to set this results in no DTV. + * It's safe to set this across all Hauppauge boards + * currently, regardless of the board type. + */ + cx25840_write(client, 0x160, 0x1d); + cx25840_write(client, 0x164, 0x00); + + /* Do the firmware load in a work handler to prevent. + Otherwise the kernel is blocked waiting for the + bit-banging i2c interface to finish uploading the + firmware. */ + INIT_WORK(&state->fw_work, cx25840_work_handler); + init_waitqueue_head(&state->fw_wait); + q = create_singlethread_workqueue("cx25840_fw"); + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + + cx25840_std_setup(client); + + /* (re)set input */ + set_input(client, state->vid_input, state->aud_input); + + /* start microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0x10); + + /* Disable and clear video interrupts - we don't use them */ + cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff); + + /* Disable and clear audio interrupts - we don't use them */ + cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff); + cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff); +} + +/* ----------------------------------------------------------------------- */ + +static void cx231xx_initialize(struct i2c_client *client) +{ + DEFINE_WAIT(wait); + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + struct workqueue_struct *q; + + /* Internal Reset */ + cx25840_and_or(client, 0x102, ~0x01, 0x01); + cx25840_and_or(client, 0x102, ~0x01, 0x00); + + /* Stop microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0x00); + + /* DIF in reset? */ + cx25840_write(client, 0x398, 0); + + /* Trust the default xtal, no division */ + /* This changes for the cx23888 products */ + cx25840_write(client, 0x2, 0x76); + + /* Bring down the regulator for AUX clk */ + cx25840_write(client, 0x1, 0x40); + + /* Disable DIF bypass */ + cx25840_write4(client, 0x33c, 0x00000001); + + /* DIF Src phase inc */ + cx25840_write4(client, 0x340, 0x0df7df83); + + /* Luma */ + cx25840_write4(client, 0x414, 0x00107d12); + + /* Chroma */ + cx25840_write4(client, 0x420, 0x3d008282); + + /* ADC2 input select */ + cx25840_write(client, 0x102, 0x10); + + /* VIN1 & VIN5 */ + cx25840_write(client, 0x103, 0x11); + + /* Enable format auto detect */ + cx25840_write(client, 0x400, 0); + /* Fast subchroma lock */ + /* White crush, Chroma AGC & Chroma Killer enabled */ + cx25840_write(client, 0x401, 0xe8); + + /* Do the firmware load in a work handler to prevent. + Otherwise the kernel is blocked waiting for the + bit-banging i2c interface to finish uploading the + firmware. */ + INIT_WORK(&state->fw_work, cx25840_work_handler); + init_waitqueue_head(&state->fw_wait); + q = create_singlethread_workqueue("cx25840_fw"); + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + + cx25840_std_setup(client); + + /* (re)set input */ + set_input(client, state->vid_input, state->aud_input); + + /* start microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0x10); +} + +/* ----------------------------------------------------------------------- */ + +void cx25840_std_setup(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + v4l2_std_id std = state->std; + int hblank, hactive, burst, vblank, vactive, sc; + int vblank656, src_decimation; + int luma_lpf, uv_lpf, comb; + u32 pll_int, pll_frac, pll_post; + + /* datasheet startup, step 8d */ + if (std & ~V4L2_STD_NTSC) + cx25840_write(client, 0x49f, 0x11); + else + cx25840_write(client, 0x49f, 0x14); + + if (std & V4L2_STD_625_50) { + hblank = 132; + hactive = 720; + burst = 93; + vblank = 36; + vactive = 580; + vblank656 = 40; + src_decimation = 0x21f; + luma_lpf = 2; + + if (std & V4L2_STD_SECAM) { + uv_lpf = 0; + comb = 0; + sc = 0x0a425f; + } else if (std == V4L2_STD_PAL_Nc) { + uv_lpf = 1; + comb = 0x20; + sc = 556453; + } else { + uv_lpf = 1; + comb = 0x20; + sc = 688739; + } + } else { + hactive = 720; + hblank = 122; + vactive = 487; + luma_lpf = 1; + uv_lpf = 1; + + src_decimation = 0x21f; + if (std == V4L2_STD_PAL_60) { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + luma_lpf = 2; + comb = 0x20; + sc = 688739; + } else if (std == V4L2_STD_PAL_M) { + vblank = 20; + vblank656 = 24; + burst = 0x61; + comb = 0x20; + sc = 555452; + } else { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + comb = 0x66; + sc = 556063; + } + } + + /* DEBUG: Displays configured PLL frequency */ + if (!is_cx231xx(state)) { + pll_int = cx25840_read(client, 0x108); + pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; + pll_post = cx25840_read(client, 0x109); + v4l_dbg(1, cx25840_debug, client, + "PLL regs = int: %u, frac: %u, post: %u\n", + pll_int, pll_frac, pll_post); + + if (pll_post) { + int fin, fsc; + int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L; + + pll /= pll_post; + v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n", + pll / 1000000, pll % 1000000); + v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n", + pll / 8000000, (pll / 8) % 1000000); + + fin = ((u64)src_decimation * pll) >> 12; + v4l_dbg(1, cx25840_debug, client, + "ADC Sampling freq = %d.%06d MHz\n", + fin / 1000000, fin % 1000000); + + fsc = (((u64)sc) * pll) >> 24L; + v4l_dbg(1, cx25840_debug, client, + "Chroma sub-carrier freq = %d.%06d MHz\n", + fsc / 1000000, fsc % 1000000); + + v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " + "vblank %i, vactive %i, vblank656 %i, src_dec %i, " + "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, " + "sc 0x%06x\n", + hblank, hactive, vblank, vactive, vblank656, + src_decimation, burst, luma_lpf, uv_lpf, comb, sc); + } + } + + /* Sets horizontal blanking delay and active lines */ + cx25840_write(client, 0x470, hblank); + cx25840_write(client, 0x471, + 0xff & (((hblank >> 8) & 0x3) | (hactive << 4))); + cx25840_write(client, 0x472, hactive >> 4); + + /* Sets burst gate delay */ + cx25840_write(client, 0x473, burst); + + /* Sets vertical blanking delay and active duration */ + cx25840_write(client, 0x474, vblank); + cx25840_write(client, 0x475, + 0xff & (((vblank >> 8) & 0x3) | (vactive << 4))); + cx25840_write(client, 0x476, vactive >> 4); + cx25840_write(client, 0x477, vblank656); + + /* Sets src decimation rate */ + cx25840_write(client, 0x478, 0xff & src_decimation); + cx25840_write(client, 0x479, 0xff & (src_decimation >> 8)); + + /* Sets Luma and UV Low pass filters */ + cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); + + /* Enables comb filters */ + cx25840_write(client, 0x47b, comb); + + /* Sets SC Step*/ + cx25840_write(client, 0x47c, sc); + cx25840_write(client, 0x47d, 0xff & sc >> 8); + cx25840_write(client, 0x47e, 0xff & sc >> 16); + + /* Sets VBI parameters */ + if (std & V4L2_STD_625_50) { + cx25840_write(client, 0x47f, 0x01); + state->vbi_line_offset = 5; + } else { + cx25840_write(client, 0x47f, 0x00); + state->vbi_line_offset = 8; + } +} + +/* ----------------------------------------------------------------------- */ + +static void input_change(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + v4l2_std_id std = state->std; + + /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */ + if (std & V4L2_STD_SECAM) { + cx25840_write(client, 0x402, 0); + } + else { + cx25840_write(client, 0x402, 0x04); + cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); + } + cx25840_and_or(client, 0x401, ~0x60, 0); + cx25840_and_or(client, 0x401, ~0x60, 0x60); + + /* Don't write into audio registers on cx2583x chips */ + if (is_cx2583x(state)) + return; + + cx25840_and_or(client, 0x810, ~0x01, 1); + + if (state->radio) { + cx25840_write(client, 0x808, 0xf9); + cx25840_write(client, 0x80b, 0x00); + } + else if (std & V4L2_STD_525_60) { + /* Certain Hauppauge PVR150 models have a hardware bug + that causes audio to drop out. For these models the + audio standard must be set explicitly. + To be precise: it affects cards with tuner models + 85, 99 and 112 (model numbers from tveeprom). */ + int hw_fix = state->pvr150_workaround; + + if (std == V4L2_STD_NTSC_M_JP) { + /* Japan uses EIAJ audio standard */ + cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7); + } else if (std == V4L2_STD_NTSC_M_KR) { + /* South Korea uses A2 audio standard */ + cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8); + } else { + /* Others use the BTSC audio standard */ + cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6); + } + cx25840_write(client, 0x80b, 0x00); + } else if (std & V4L2_STD_PAL) { + /* Autodetect audio standard and audio system */ + cx25840_write(client, 0x808, 0xff); + /* Since system PAL-L is pretty much non-existent and + not used by any public broadcast network, force + 6.5 MHz carrier to be interpreted as System DK, + this avoids DK audio detection instability */ + cx25840_write(client, 0x80b, 0x00); + } else if (std & V4L2_STD_SECAM) { + /* Autodetect audio standard and audio system */ + cx25840_write(client, 0x808, 0xff); + /* If only one of SECAM-DK / SECAM-L is required, then force + 6.5MHz carrier, else autodetect it */ + if ((std & V4L2_STD_SECAM_DK) && + !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { + /* 6.5 MHz carrier to be interpreted as System DK */ + cx25840_write(client, 0x80b, 0x00); + } else if (!(std & V4L2_STD_SECAM_DK) && + (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { + /* 6.5 MHz carrier to be interpreted as System L */ + cx25840_write(client, 0x80b, 0x08); + } else { + /* 6.5 MHz carrier to be autodetected */ + cx25840_write(client, 0x80b, 0x10); + } + } + + cx25840_and_or(client, 0x810, ~0x01, 0); +} + +static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, + enum cx25840_audio_input aud_input) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && + vid_input <= CX25840_COMPOSITE8); + u8 is_component = (vid_input & CX25840_COMPONENT_ON) == + CX25840_COMPONENT_ON; + int luma = vid_input & 0xf0; + int chroma = vid_input & 0xf00; + u8 reg; + + v4l_dbg(1, cx25840_debug, client, + "decoder set video input %d, audio input %d\n", + vid_input, aud_input); + + if (vid_input >= CX25840_VIN1_CH1) { + v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", + vid_input); + reg = vid_input & 0xff; + is_composite = !is_component && + ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON); + + v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", + reg, is_composite); + } else if (is_composite) { + reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); + } else { + if ((vid_input & ~0xff0) || + luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 || + chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { + v4l_err(client, "0x%04x is not a valid video input!\n", + vid_input); + return -EINVAL; + } + reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); + if (chroma >= CX25840_SVIDEO_CHROMA7) { + reg &= 0x3f; + reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2; + } else { + reg &= 0xcf; + reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4; + } + } + + /* The caller has previously prepared the correct routing + * configuration in reg (for the cx23885) so we have no + * need to attempt to flip bits for earlier av decoders. + */ + if (!is_cx2388x(state) && !is_cx231xx(state)) { + switch (aud_input) { + case CX25840_AUDIO_SERIAL: + /* do nothing, use serial audio input */ + break; + case CX25840_AUDIO4: reg &= ~0x30; break; + case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; + case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; + case CX25840_AUDIO7: reg &= ~0xc0; break; + case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; + + default: + v4l_err(client, "0x%04x is not a valid audio input!\n", + aud_input); + return -EINVAL; + } + } + + cx25840_write(client, 0x103, reg); + + /* Set INPUT_MODE to Composite, S-Video or Component */ + if (is_component) + cx25840_and_or(client, 0x401, ~0x6, 0x6); + else + cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); + + if (!is_cx2388x(state) && !is_cx231xx(state)) { + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ + cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ + if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) + cx25840_and_or(client, 0x102, ~0x4, 4); + else + cx25840_and_or(client, 0x102, ~0x4, 0); + } else { + /* Set DUAL_MODE_ADC2 to 1 if component*/ + cx25840_and_or(client, 0x102, ~0x4, is_component ? 0x4 : 0x0); + if (is_composite) { + /* ADC2 input select channel 2 */ + cx25840_and_or(client, 0x102, ~0x2, 0); + } else if (!is_component) { + /* S-Video */ + if (chroma >= CX25840_SVIDEO_CHROMA7) { + /* ADC2 input select channel 3 */ + cx25840_and_or(client, 0x102, ~0x2, 2); + } else { + /* ADC2 input select channel 2 */ + cx25840_and_or(client, 0x102, ~0x2, 0); + } + } + } + + state->vid_input = vid_input; + state->aud_input = aud_input; + cx25840_audio_set_path(client); + input_change(client); + + if (is_cx2388x(state)) { + /* Audio channel 1 src : Parallel 1 */ + cx25840_write(client, 0x124, 0x03); + + /* Select AFE clock pad output source */ + cx25840_write(client, 0x144, 0x05); + + /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ + cx25840_write(client, 0x914, 0xa0); + + /* I2S_OUT_CTL: + * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 + * I2S_OUT_MASTER_MODE = Master + */ + cx25840_write(client, 0x918, 0xa0); + cx25840_write(client, 0x919, 0x01); + } else if (is_cx231xx(state)) { + /* Audio channel 1 src : Parallel 1 */ + cx25840_write(client, 0x124, 0x03); + + /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ + cx25840_write(client, 0x914, 0xa0); + + /* I2S_OUT_CTL: + * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 + * I2S_OUT_MASTER_MODE = Master + */ + cx25840_write(client, 0x918, 0xa0); + cx25840_write(client, 0x919, 0x01); + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int set_v4lstd(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { + pal_m = 1; + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { + fmt = 0x8; + } else { + /* Then, test against generic ones */ + if (state->std & V4L2_STD_NTSC) + fmt = 0x1; + else if (state->std & V4L2_STD_PAL) + fmt = 0x4; + else if (state->std & V4L2_STD_SECAM) + fmt = 0xc; + } + + v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt); + + /* Follow step 9 of section 3.16 in the cx25840 datasheet. + Without this PAL may display a vertical ghosting effect. + This happens for example with the Yuan MPC622. */ + if (fmt >= 4 && fmt < 8) { + /* Set format to NTSC-M */ + cx25840_and_or(client, 0x400, ~0xf, 1); + /* Turn off LCOMB */ + cx25840_and_or(client, 0x47b, ~6, 0); + } + cx25840_and_or(client, 0x400, ~0xf, fmt); + cx25840_and_or(client, 0x403, ~0x3, pal_m); + cx25840_std_setup(client); + if (!is_cx2583x(state)) + input_change(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + cx25840_write(client, 0x414, ctrl->val - 128); + break; + + case V4L2_CID_CONTRAST: + cx25840_write(client, 0x415, ctrl->val << 1); + break; + + case V4L2_CID_SATURATION: + cx25840_write(client, 0x420, ctrl->val << 1); + cx25840_write(client, 0x421, ctrl->val << 1); + break; + + case V4L2_CID_HUE: + cx25840_write(client, 0x422, ctrl->val); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int HSC, VSC, Vsrc, Hsrc, filter, Vlines; + int is_50Hz = !(state->std & V4L2_STD_525_60); + + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; + + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + + Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; + Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; + + Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; + Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; + + Vlines = fmt->height + (is_50Hz ? 4 : 7); + + if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || + (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + v4l_err(client, "%dx%d is not a valid size!\n", + fmt->width, fmt->height); + return -ERANGE; + } + + HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); + VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC &= 0x1fff; + + if (fmt->width >= 385) + filter = 0; + else if (fmt->width > 192) + filter = 1; + else if (fmt->width > 96) + filter = 2; + else + filter = 3; + + v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", + fmt->width, fmt->height, HSC, VSC); + + /* HSCALE=HSC */ + cx25840_write(client, 0x418, HSC & 0xff); + cx25840_write(client, 0x419, (HSC >> 8) & 0xff); + cx25840_write(client, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx25840_write(client, 0x41c, VSC & 0xff); + cx25840_write(client, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx25840_write(client, 0x41e, 0x8 | filter); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static void log_video_status(struct i2c_client *client) +{ + static const char *const fmt_strs[] = { + "0x0", + "NTSC-M", "NTSC-J", "NTSC-4.43", + "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", + "0x9", "0xA", "0xB", + "SECAM", + "0xD", "0xE", "0xF" + }; + + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; + u8 gen_stat1 = cx25840_read(client, 0x40d); + u8 gen_stat2 = cx25840_read(client, 0x40e); + int vid_input = state->vid_input; + + v4l_info(client, "Video signal: %spresent\n", + (gen_stat2 & 0x20) ? "" : "not "); + v4l_info(client, "Detected format: %s\n", + fmt_strs[gen_stat1 & 0xf]); + + v4l_info(client, "Specified standard: %s\n", + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + + if (vid_input >= CX25840_COMPOSITE1 && + vid_input <= CX25840_COMPOSITE8) { + v4l_info(client, "Specified video input: Composite %d\n", + vid_input - CX25840_COMPOSITE1 + 1); + } else { + v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + } + + v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); +} + +/* ----------------------------------------------------------------------- */ + +static void log_audio_status(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 download_ctl = cx25840_read(client, 0x803); + u8 mod_det_stat0 = cx25840_read(client, 0x804); + u8 mod_det_stat1 = cx25840_read(client, 0x805); + u8 audio_config = cx25840_read(client, 0x808); + u8 pref_mode = cx25840_read(client, 0x809); + u8 afc0 = cx25840_read(client, 0x80b); + u8 mute_ctl = cx25840_read(client, 0x8d3); + int aud_input = state->aud_input; + char *p; + + switch (mod_det_stat0) { + case 0x00: p = "mono"; break; + case 0x01: p = "stereo"; break; + case 0x02: p = "dual"; break; + case 0x04: p = "tri"; break; + case 0x10: p = "mono with SAP"; break; + case 0x11: p = "stereo with SAP"; break; + case 0x12: p = "dual with SAP"; break; + case 0x14: p = "tri with SAP"; break; + case 0xfe: p = "forced mode"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio mode: %s\n", p); + + switch (mod_det_stat1) { + case 0x00: p = "not defined"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; + case 0x0e: p = "IF FM Radio"; break; + case 0x0f: p = "BTSC"; break; + case 0x10: p = "high-deviation FM"; break; + case 0x11: p = "very high-deviation FM"; break; + case 0xfd: p = "unknown audio standard"; break; + case 0xfe: p = "forced audio standard"; break; + case 0xff: p = "no detected audio standard"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio standard: %s\n", p); + v4l_info(client, "Audio microcontroller: %s\n", + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); + + switch (audio_config >> 4) { + case 0x00: p = "undefined"; break; + case 0x01: p = "BTSC"; break; + case 0x02: p = "EIAJ"; break; + case 0x03: p = "A2-M"; break; + case 0x04: p = "A2-BG"; break; + case 0x05: p = "A2-DK1"; break; + case 0x06: p = "A2-DK2"; break; + case 0x07: p = "A2-DK3"; break; + case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x09: p = "AM-L"; break; + case 0x0a: p = "NICAM-BG"; break; + case 0x0b: p = "NICAM-DK"; break; + case 0x0c: p = "NICAM-I"; break; + case 0x0d: p = "NICAM-L"; break; + case 0x0e: p = "FM radio"; break; + case 0x0f: p = "automatic detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio standard: %s\n", p); + + if ((audio_config >> 4) < 0xF) { + switch (audio_config & 0xF) { + case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; + case 0x01: p = "MONO2 (LANGUAGE B)"; break; + case 0x02: p = "MONO3 (STEREO forced MONO)"; break; + case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; + case 0x04: p = "STEREO"; break; + case 0x05: p = "DUAL1 (AB)"; break; + case 0x06: p = "DUAL2 (AC) (FM)"; break; + case 0x07: p = "DUAL3 (BC) (FM)"; break; + case 0x08: p = "DUAL4 (AC) (AM)"; break; + case 0x09: p = "DUAL5 (BC) (AM)"; break; + case 0x0a: p = "SAP"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio mode: %s\n", p); + } else { + switch (audio_config & 0xF) { + case 0x00: p = "BG"; break; + case 0x01: p = "DK1"; break; + case 0x02: p = "DK2"; break; + case 0x03: p = "DK3"; break; + case 0x04: p = "I"; break; + case 0x05: p = "L"; break; + case 0x06: p = "BTSC"; break; + case 0x07: p = "EIAJ"; break; + case 0x08: p = "A2-M"; break; + case 0x09: p = "FM Radio"; break; + case 0x0f: p = "automatic standard and mode detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio system: %s\n", p); + } + + if (aud_input) { + v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); + } else { + v4l_info(client, "Specified audio input: External\n"); + } + + switch (pref_mode & 0xf) { + case 0: p = "mono/language A"; break; + case 1: p = "language B"; break; + case 2: p = "language C"; break; + case 3: p = "analog fallback"; break; + case 4: p = "stereo"; break; + case 5: p = "language AC"; break; + case 6: p = "language BC"; break; + case 7: p = "language AB"; break; + default: p = "undefined"; + } + v4l_info(client, "Preferred audio mode: %s\n", p); + + if ((audio_config & 0xf) == 0xf) { + switch ((afc0 >> 3) & 0x3) { + case 0: p = "system DK"; break; + case 1: p = "system L"; break; + case 2: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 65 MHz format: %s\n", p); + + switch (afc0 & 0x7) { + case 0: p = "chroma"; break; + case 1: p = "BTSC"; break; + case 2: p = "EIAJ"; break; + case 3: p = "A2-M"; break; + case 4: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 45 MHz format: %s\n", p); + } +} + +/* ----------------------------------------------------------------------- */ + +/* This load_fw operation must be called to load the driver's firmware. + Without this the audio standard detection will fail and you will + only get mono. + + Since loading the firmware is often problematic when the driver is + compiled into the kernel I recommend postponing calling this function + until the first open of the video device. Another reason for + postponing it is that loading this firmware takes a long time (seconds) + due to the slow i2c bus speed. So it will speed up the boot process if + you can avoid loading the fw as long as the video device isn't used. */ +static int cx25840_load_fw(struct v4l2_subdev *sd) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!state->is_initialized) { + /* initialize and load firmware */ + state->is_initialized = 1; + if (is_cx2583x(state)) + cx25836_initialize(client); + else if (is_cx2388x(state)) + cx23885_initialize(client); + else if (is_cx231xx(state)) + cx231xx_initialize(client); + else + cx25840_initialize(client); + } + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + reg->size = 1; + reg->val = cx25840_read(client, reg->reg & 0x0fff); + return 0; +} + +static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff); + return 0; +} +#endif + +static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 v; + + if (is_cx2583x(state) || is_cx2388x(state) || is_cx231xx(state)) + return 0; + + v4l_dbg(1, cx25840_debug, client, "%s audio output\n", + enable ? "enable" : "disable"); + + if (enable) { + v = cx25840_read(client, 0x115) | 0x80; + cx25840_write(client, 0x115, v); + v = cx25840_read(client, 0x116) | 0x03; + cx25840_write(client, 0x116, v); + } else { + v = cx25840_read(client, 0x115) & ~(0x80); + cx25840_write(client, 0x115, v); + v = cx25840_read(client, 0x116) & ~(0x03); + cx25840_write(client, 0x116, v); + } + return 0; +} + +static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 v; + + v4l_dbg(1, cx25840_debug, client, "%s video output\n", + enable ? "enable" : "disable"); + if (enable) { + if (is_cx2388x(state) || is_cx231xx(state)) { + v = cx25840_read(client, 0x421) | 0x0b; + cx25840_write(client, 0x421, v); + } else { + v = cx25840_read(client, 0x115) | 0x0c; + cx25840_write(client, 0x115, v); + v = cx25840_read(client, 0x116) | 0x04; + cx25840_write(client, 0x116, v); + } + } else { + if (is_cx2388x(state) || is_cx231xx(state)) { + v = cx25840_read(client, 0x421) & ~(0x0b); + cx25840_write(client, 0x421, v); + } else { + v = cx25840_read(client, 0x115) & ~(0x0c); + cx25840_write(client, 0x115, v); + v = cx25840_read(client, 0x116) & ~(0x04); + cx25840_write(client, 0x116, v); + } + } + return 0; +} + +static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (state->radio == 0 && state->std == std) + return 0; + state->radio = 0; + state->std = std; + return set_v4lstd(client); +} + +static int cx25840_s_radio(struct v4l2_subdev *sd) +{ + struct cx25840_state *state = to_state(sd); + + state->radio = 1; + return 0; +} + +static int cx25840_s_video_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return set_input(client, input, state->aud_input); +} + +static int cx25840_s_audio_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return set_input(client, state->vid_input, input); +} + +static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + input_change(client); + return 0; +} + +static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 vpres = cx25840_read(client, 0x40e) & 0x20; + u8 mode; + int val = 0; + + if (state->radio) + return 0; + + vt->signal = vpres ? 0xffff : 0x0; + if (is_cx2583x(state)) + return 0; + + vt->capability |= + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + + mode = cx25840_read(client, 0x804); + + /* get rxsubchans and audmode */ + if ((mode & 0xf) == 1) + val |= V4L2_TUNER_SUB_STEREO; + else + val |= V4L2_TUNER_SUB_MONO; + + if (mode == 2 || mode == 4) + val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + + if (mode & 0x10) + val |= V4L2_TUNER_SUB_SAP; + + vt->rxsubchans = val; + vt->audmode = state->audmode; + return 0; +} + +static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (state->radio || is_cx2583x(state)) + return 0; + + switch (vt->audmode) { + case V4L2_TUNER_MODE_MONO: + /* mono -> mono + stereo -> mono + bilingual -> lang1 */ + cx25840_and_or(client, 0x809, ~0xf, 0x00); + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + /* mono -> mono + stereo -> stereo + bilingual -> lang1 */ + cx25840_and_or(client, 0x809, ~0xf, 0x04); + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang1/lang2 */ + cx25840_and_or(client, 0x809, ~0xf, 0x07); + break; + case V4L2_TUNER_MODE_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang2 */ + cx25840_and_or(client, 0x809, ~0xf, 0x01); + break; + default: + return -EINVAL; + } + state->audmode = vt->audmode; + return 0; +} + +static int cx25840_reset(struct v4l2_subdev *sd, u32 val) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (is_cx2583x(state)) + cx25836_initialize(client); + else if (is_cx2388x(state)) + cx23885_initialize(client); + else if (is_cx231xx(state)) + cx231xx_initialize(client); + else + cx25840_initialize(client); + return 0; +} + +static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev); +} + +static int cx25840_log_status(struct v4l2_subdev *sd) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + log_video_status(client); + if (!is_cx2583x(state)) + log_audio_status(client); + cx25840_ir_log_status(sd); + v4l2_ctrl_handler_log_status(&state->hdl, sd->name); + return 0; +} + +static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status, + bool *handled) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *c = v4l2_get_subdevdata(sd); + u8 irq_stat, aud_stat, aud_en, ir_stat, ir_en; + u32 vid_stat, aud_mc_stat; + bool block_handled; + int ret = 0; + + irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG); + v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (entry): %s %s %s\n", + irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ", + irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ", + irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " "); + + if ((is_cx23885(state) || is_cx23887(state))) { + ir_stat = cx25840_read(c, CX25840_IR_STATS_REG); + ir_en = cx25840_read(c, CX25840_IR_IRQEN_REG); + v4l_dbg(2, cx25840_debug, c, + "AV Core ir IRQ status: %#04x disables: %#04x\n", + ir_stat, ir_en); + if (irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT) { + block_handled = false; + ret = cx25840_ir_irq_handler(sd, + status, &block_handled); + if (block_handled) + *handled = true; + } + } + + aud_stat = cx25840_read(c, CX25840_AUD_INT_STAT_REG); + aud_en = cx25840_read(c, CX25840_AUD_INT_CTRL_REG); + v4l_dbg(2, cx25840_debug, c, + "AV Core audio IRQ status: %#04x disables: %#04x\n", + aud_stat, aud_en); + aud_mc_stat = cx25840_read4(c, CX23885_AUD_MC_INT_MASK_REG); + v4l_dbg(2, cx25840_debug, c, + "AV Core audio MC IRQ status: %#06x enables: %#06x\n", + aud_mc_stat >> CX23885_AUD_MC_INT_STAT_SHFT, + aud_mc_stat & CX23885_AUD_MC_INT_CTRL_BITS); + if (irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT) { + if (aud_stat) { + cx25840_write(c, CX25840_AUD_INT_STAT_REG, aud_stat); + *handled = true; + } + } + + vid_stat = cx25840_read4(c, CX25840_VID_INT_STAT_REG); + v4l_dbg(2, cx25840_debug, c, + "AV Core video IRQ status: %#06x disables: %#06x\n", + vid_stat & CX25840_VID_INT_STAT_BITS, + vid_stat >> CX25840_VID_INT_MASK_SHFT); + if (irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT) { + if (vid_stat & CX25840_VID_INT_STAT_BITS) { + cx25840_write4(c, CX25840_VID_INT_STAT_REG, vid_stat); + *handled = true; + } + } + + irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG); + v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (exit): %s %s %s\n", + irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ", + irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ", + irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " "); + + return ret; +} + +static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status, + bool *handled) +{ + struct cx25840_state *state = to_state(sd); + + *handled = false; + + /* Only support the CX2388[578] AV Core for now */ + if (is_cx2388x(state)) + return cx23885_irq_handler(sd, status, handled); + + return -ENODEV; +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_ctrl_ops cx25840_ctrl_ops = { + .s_ctrl = cx25840_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops cx25840_core_ops = { + .log_status = cx25840_log_status, + .g_chip_ident = cx25840_g_chip_ident, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, + .s_std = cx25840_s_std, + .reset = cx25840_reset, + .load_fw = cx25840_load_fw, + .s_io_pin_config = common_s_io_pin_config, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = cx25840_g_register, + .s_register = cx25840_s_register, +#endif + .interrupt_service_routine = cx25840_irq_handler, +}; + +static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { + .s_frequency = cx25840_s_frequency, + .s_radio = cx25840_s_radio, + .g_tuner = cx25840_g_tuner, + .s_tuner = cx25840_s_tuner, +}; + +static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { + .s_clock_freq = cx25840_s_clock_freq, + .s_routing = cx25840_s_audio_routing, + .s_stream = cx25840_s_audio_stream, +}; + +static const struct v4l2_subdev_video_ops cx25840_video_ops = { + .s_routing = cx25840_s_video_routing, + .s_mbus_fmt = cx25840_s_mbus_fmt, + .s_stream = cx25840_s_stream, +}; + +static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = { + .decode_vbi_line = cx25840_decode_vbi_line, + .s_raw_fmt = cx25840_s_raw_fmt, + .s_sliced_fmt = cx25840_s_sliced_fmt, + .g_sliced_fmt = cx25840_g_sliced_fmt, +}; + +static const struct v4l2_subdev_ops cx25840_ops = { + .core = &cx25840_core_ops, + .tuner = &cx25840_tuner_ops, + .audio = &cx25840_audio_ops, + .video = &cx25840_video_ops, + .vbi = &cx25840_vbi_ops, + .ir = &cx25840_ir_ops, +}; + +/* ----------------------------------------------------------------------- */ + +static u32 get_cx2388x_ident(struct i2c_client *client) +{ + u32 ret; + + /* Come out of digital power down */ + cx25840_write(client, 0x000, 0); + + /* Detecting whether the part is cx23885/7/8 is more + * difficult than it needs to be. No ID register. Instead we + * probe certain registers indicated in the datasheets to look + * for specific defaults that differ between the silicon designs. */ + + /* It's either 885/7 if the IR Tx Clk Divider register exists */ + if (cx25840_read4(client, 0x204) & 0xffff) { + /* CX23885 returns bogus repetitive byte values for the DIF, + * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */ + ret = cx25840_read4(client, 0x300); + if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) { + /* No DIF */ + ret = V4L2_IDENT_CX23885_AV; + } else { + /* CX23887 has a broken DIF, but the registers + * appear valid (but unused), good enough to detect. */ + ret = V4L2_IDENT_CX23887_AV; + } + } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { + /* DIF PLL Freq Word reg exists; chip must be a CX23888 */ + ret = V4L2_IDENT_CX23888_AV; + } else { + v4l_err(client, "Unable to detect h/w, assuming cx23887\n"); + ret = V4L2_IDENT_CX23887_AV; + } + + /* Back into digital power down */ + cx25840_write(client, 0x000, 2); + return ret; +} + +static int cx25840_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct cx25840_state *state; + struct v4l2_subdev *sd; + int default_volume; + u32 id = V4L2_IDENT_NONE; + u16 device_id; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); + + device_id = cx25840_read(client, 0x101) << 8; + device_id |= cx25840_read(client, 0x100); + v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); + + /* The high byte of the device ID should be + * 0x83 for the cx2583x and 0x84 for the cx2584x */ + if ((device_id & 0xff00) == 0x8300) { + id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; + } else if ((device_id & 0xff00) == 0x8400) { + id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); + } else if (device_id == 0x0000) { + id = get_cx2388x_ident(client); + } else if ((device_id & 0xfff0) == 0x5A30) { + /* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */ + id = V4L2_IDENT_CX2310X_AV; + } else if ((device_id & 0xff) == (device_id >> 8)) { + v4l_err(client, + "likely a confused/unresponsive cx2388[578] A/V decoder" + " found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + v4l_err(client, "A method to reset it from the cx25840 driver" + " software is not known at this time\n"); + return -ENODEV; + } else { + v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); + return -ENODEV; + } + + state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &cx25840_ops); + + switch (id) { + case V4L2_IDENT_CX23885_AV: + v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX23887_AV: + v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX23888_AV: + v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX2310X_AV: + v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n", + device_id, client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX25840: + case V4L2_IDENT_CX25841: + case V4L2_IDENT_CX25842: + case V4L2_IDENT_CX25843: + /* Note: revision '(device_id & 0x0f) == 2' was never built. The + marking skips from 0x1 == 22 to 0x3 == 23. */ + v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", + (device_id & 0xfff0) >> 4, + (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 + : (device_id & 0x0f), + client->addr << 1, client->adapter->name); + break; + case V4L2_IDENT_CX25836: + case V4L2_IDENT_CX25837: + default: + v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n", + (device_id & 0xfff0) >> 4, device_id & 0x0f, + client->addr << 1, client->adapter->name); + break; + } + + state->c = client; + state->vid_input = CX25840_COMPOSITE7; + state->aud_input = CX25840_AUDIO8; + state->audclk_freq = 48000; + state->audmode = V4L2_TUNER_MODE_LANG1; + state->vbi_line_offset = 8; + state->id = id; + state->rev = device_id; + v4l2_ctrl_handler_init(&state->hdl, 9); + v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, + V4L2_CID_CONTRAST, 0, 127, 1, 64); + v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, + V4L2_CID_SATURATION, 0, 127, 1, 64); + v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + if (!is_cx2583x(state)) { + default_volume = cx25840_read(client, 0x8d4); + /* + * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume + * scale mapping limits to avoid -ERANGE errors when + * initializing the volume control + */ + if (default_volume > 228) { + /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ + default_volume = 228; + cx25840_write(client, 0x8d4, 228); + } + else if (default_volume < 20) { + /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ + default_volume = 20; + cx25840_write(client, 0x8d4, 20); + } + default_volume = (((228 - default_volume) >> 1) + 23) << 9; + + state->volume = v4l2_ctrl_new_std(&state->hdl, + &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, + 0, 65535, 65535 / 100, default_volume); + state->mute = v4l2_ctrl_new_std(&state->hdl, + &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, + 0, 1, 1, 0); + v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, + V4L2_CID_AUDIO_BALANCE, + 0, 65535, 65535 / 100, 32768); + v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, + V4L2_CID_AUDIO_BASS, + 0, 65535, 65535 / 100, 32768); + v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, + V4L2_CID_AUDIO_TREBLE, + 0, 65535, 65535 / 100, 32768); + } + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + if (!is_cx2583x(state)) + v4l2_ctrl_cluster(2, &state->volume); + v4l2_ctrl_handler_setup(&state->hdl); + + if (client->dev.platform_data) { + struct cx25840_platform_data *pdata = client->dev.platform_data; + + state->pvr150_workaround = pdata->pvr150_workaround; + } + + cx25840_ir_probe(sd); + return 0; +} + +static int cx25840_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct cx25840_state *state = to_state(sd); + + cx25840_ir_remove(sd); + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return 0; +} + +static const struct i2c_device_id cx25840_id[] = { + { "cx25840", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cx25840_id); + +static struct i2c_driver cx25840_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "cx25840", + }, + .probe = cx25840_probe, + .remove = cx25840_remove, + .id_table = cx25840_id, +}; + +static __init int init_cx25840(void) +{ + return i2c_add_driver(&cx25840_driver); +} + +static __exit void exit_cx25840(void) +{ + i2c_del_driver(&cx25840_driver); +} + +module_init(init_cx25840); +module_exit(exit_cx25840); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-core.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-core.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,137 @@ +/* cx25840 internal API header + * + * Copyright (C) 2003-2004 Chris Kennedy + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CX25840_CORE_H_ +#define _CX25840_CORE_H_ + + +#include +#include +#include +#include +#include + +struct cx25840_ir_state; + +struct cx25840_state { + struct i2c_client *c; + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + struct { + /* volume cluster */ + struct v4l2_ctrl *volume; + struct v4l2_ctrl *mute; + }; + int pvr150_workaround; + int radio; + v4l2_std_id std; + enum cx25840_video_input vid_input; + enum cx25840_audio_input aud_input; + u32 audclk_freq; + int audmode; + int vbi_line_offset; + u32 id; + u32 rev; + int is_initialized; + wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ + struct work_struct fw_work; /* work entry for fw load */ + struct cx25840_ir_state *ir_state; +}; + +static inline struct cx25840_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct cx25840_state, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct cx25840_state, hdl)->sd; +} + +static inline bool is_cx2583x(struct cx25840_state *state) +{ + return state->id == V4L2_IDENT_CX25836 || + state->id == V4L2_IDENT_CX25837; +} + +static inline bool is_cx231xx(struct cx25840_state *state) +{ + return state->id == V4L2_IDENT_CX2310X_AV; +} + +static inline bool is_cx2388x(struct cx25840_state *state) +{ + return state->id == V4L2_IDENT_CX23885_AV || + state->id == V4L2_IDENT_CX23887_AV || + state->id == V4L2_IDENT_CX23888_AV; +} + +static inline bool is_cx23885(struct cx25840_state *state) +{ + return state->id == V4L2_IDENT_CX23885_AV; +} + +static inline bool is_cx23887(struct cx25840_state *state) +{ + return state->id == V4L2_IDENT_CX23887_AV; +} + +static inline bool is_cx23888(struct cx25840_state *state) +{ + return state->id == V4L2_IDENT_CX23888_AV; +} + +/* ----------------------------------------------------------------------- */ +/* cx25850-core.c */ +int cx25840_write(struct i2c_client *client, u16 addr, u8 value); +int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); +u8 cx25840_read(struct i2c_client *client, u16 addr); +u32 cx25840_read4(struct i2c_client *client, u16 addr); +int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value); +int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, + u32 or_value); +void cx25840_std_setup(struct i2c_client *client); + +/* ----------------------------------------------------------------------- */ +/* cx25850-firmware.c */ +int cx25840_loadfw(struct i2c_client *client); + +/* ----------------------------------------------------------------------- */ +/* cx25850-audio.c */ +void cx25840_audio_set_path(struct i2c_client *client); +int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq); + +extern const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops; + +/* ----------------------------------------------------------------------- */ +/* cx25850-vbi.c */ +int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt); +int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); +int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); +int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi); + +/* ----------------------------------------------------------------------- */ +/* cx25850-ir.c */ +extern const struct v4l2_subdev_ir_ops cx25840_ir_ops; +int cx25840_ir_log_status(struct v4l2_subdev *sd); +int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled); +int cx25840_ir_probe(struct v4l2_subdev *sd); +int cx25840_ir_remove(struct v4l2_subdev *sd); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-firmware.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,166 @@ +/* cx25840 firmware functions + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include "cx25840-core.h" + +/* + * Mike Isely - The FWSEND parameter controls the + * size of the firmware chunks sent down the I2C bus to the chip. + * Previously this had been set to 1024 but unfortunately some I2C + * implementations can't transfer data in such big gulps. + * Specifically, the pvrusb2 driver has a hard limit of around 60 + * bytes, due to the encapsulation there of I2C traffic into USB + * messages. So we have to significantly reduce this parameter. + */ +#define FWSEND 48 + +#define FWDEV(x) &((x)->dev) + +static char *firmware = ""; + +module_param(firmware, charp, 0444); + +MODULE_PARM_DESC(firmware, "Firmware image to load"); + +static void start_fw_load(struct i2c_client *client) +{ + /* DL_ADDR_LB=0 DL_ADDR_HB=0 */ + cx25840_write(client, 0x800, 0x00); + cx25840_write(client, 0x801, 0x00); + // DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1 + cx25840_write(client, 0x803, 0x0b); + /* AUTO_INC_DIS=1 */ + cx25840_write(client, 0x000, 0x20); +} + +static void end_fw_load(struct i2c_client *client) +{ + /* AUTO_INC_DIS=0 */ + cx25840_write(client, 0x000, 0x00); + /* DL_ENABLE=0 */ + cx25840_write(client, 0x803, 0x03); +} + +static const char *get_fw_name(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + + if (firmware[0]) + return firmware; + if (is_cx2388x(state)) + return "v4l-cx23885-avcore-01.fw"; + if (is_cx231xx(state)) + return "v4l-cx231xx-avcore-01.fw"; + return "v4l-cx25840.fw"; +} + +static int check_fw_load(struct i2c_client *client, int size) +{ + /* DL_ADDR_HB DL_ADDR_LB */ + int s = cx25840_read(client, 0x801) << 8; + s |= cx25840_read(client, 0x800); + + if (size != s) { + v4l_err(client, "firmware %s load failed\n", + get_fw_name(client)); + return -EINVAL; + } + + v4l_info(client, "loaded %s firmware (%d bytes)\n", + get_fw_name(client), size); + return 0; +} + +static int fw_write(struct i2c_client *client, const u8 *data, int size) +{ + if (i2c_master_send(client, data, size) < size) { + v4l_err(client, "firmware load i2c failure\n"); + return -ENOSYS; + } + + return 0; +} + +int cx25840_loadfw(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + const struct firmware *fw = NULL; + u8 buffer[FWSEND]; + const u8 *ptr; + const char *fwname = get_fw_name(client); + int size, retval; + int MAX_BUF_SIZE = FWSEND; + u32 gpio_oe = 0, gpio_da = 0; + + if (is_cx2388x(state)) { + /* Preserve the GPIO OE and output bits */ + gpio_oe = cx25840_read(client, 0x160); + gpio_da = cx25840_read(client, 0x164); + } + + if (is_cx231xx(state) && MAX_BUF_SIZE > 16) { + v4l_err(client, " Firmware download size changed to 16 bytes max length\n"); + MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */ + } + + if (request_firmware(&fw, fwname, FWDEV(client)) != 0) { + v4l_err(client, "unable to open firmware %s\n", fwname); + return -EINVAL; + } + + start_fw_load(client); + + buffer[0] = 0x08; + buffer[1] = 0x02; + + size = fw->size; + ptr = fw->data; + while (size > 0) { + int len = min(MAX_BUF_SIZE - 2, size); + + memcpy(buffer + 2, ptr, len); + + retval = fw_write(client, buffer, len + 2); + + if (retval < 0) { + release_firmware(fw); + return retval; + } + + size -= len; + ptr += len; + } + + end_fw_load(client); + + size = fw->size; + release_firmware(fw); + + if (is_cx2388x(state)) { + /* Restore GPIO configuration after f/w load */ + cx25840_write(client, 0x160, gpio_oe); + cx25840_write(client, 0x164, gpio_da); + } + + return check_fw_load(client, size); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-ir.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-ir.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-ir.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-ir.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1280 @@ +/* + * Driver for the Conexant CX2584x Audio/Video decoder chip and related cores + * + * Integrated Consumer Infrared Controller + * + * Copyright (C) 2010 Andy Walls + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include "cx25840-core.h" + +static unsigned int ir_debug; +module_param(ir_debug, int, 0644); +MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages"); + +#define CX25840_IR_REG_BASE 0x200 + +#define CX25840_IR_CNTRL_REG 0x200 +#define CNTRL_WIN_3_3 0x00000000 +#define CNTRL_WIN_4_3 0x00000001 +#define CNTRL_WIN_3_4 0x00000002 +#define CNTRL_WIN_4_4 0x00000003 +#define CNTRL_WIN 0x00000003 +#define CNTRL_EDG_NONE 0x00000000 +#define CNTRL_EDG_FALL 0x00000004 +#define CNTRL_EDG_RISE 0x00000008 +#define CNTRL_EDG_BOTH 0x0000000C +#define CNTRL_EDG 0x0000000C +#define CNTRL_DMD 0x00000010 +#define CNTRL_MOD 0x00000020 +#define CNTRL_RFE 0x00000040 +#define CNTRL_TFE 0x00000080 +#define CNTRL_RXE 0x00000100 +#define CNTRL_TXE 0x00000200 +#define CNTRL_RIC 0x00000400 +#define CNTRL_TIC 0x00000800 +#define CNTRL_CPL 0x00001000 +#define CNTRL_LBM 0x00002000 +#define CNTRL_R 0x00004000 + +#define CX25840_IR_TXCLK_REG 0x204 +#define TXCLK_TCD 0x0000FFFF + +#define CX25840_IR_RXCLK_REG 0x208 +#define RXCLK_RCD 0x0000FFFF + +#define CX25840_IR_CDUTY_REG 0x20C +#define CDUTY_CDC 0x0000000F + +#define CX25840_IR_STATS_REG 0x210 +#define STATS_RTO 0x00000001 +#define STATS_ROR 0x00000002 +#define STATS_RBY 0x00000004 +#define STATS_TBY 0x00000008 +#define STATS_RSR 0x00000010 +#define STATS_TSR 0x00000020 + +#define CX25840_IR_IRQEN_REG 0x214 +#define IRQEN_RTE 0x00000001 +#define IRQEN_ROE 0x00000002 +#define IRQEN_RSE 0x00000010 +#define IRQEN_TSE 0x00000020 +#define IRQEN_MSK 0x00000033 + +#define CX25840_IR_FILTR_REG 0x218 +#define FILTR_LPF 0x0000FFFF + +#define CX25840_IR_FIFO_REG 0x23C +#define FIFO_RXTX 0x0000FFFF +#define FIFO_RXTX_LVL 0x00010000 +#define FIFO_RXTX_RTO 0x0001FFFF +#define FIFO_RX_NDV 0x00020000 +#define FIFO_RX_DEPTH 8 +#define FIFO_TX_DEPTH 8 + +#define CX25840_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */ +#define CX25840_IR_REFCLK_FREQ (CX25840_VIDCLK_FREQ / 2) + +/* + * We use this union internally for convenience, but callers to tx_write + * and rx_read will be expecting records of type struct ir_raw_event. + * Always ensure the size of this union is dictated by struct ir_raw_event. + */ +union cx25840_ir_fifo_rec { + u32 hw_fifo_data; + struct ir_raw_event ir_core_data; +}; + +#define CX25840_IR_RX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec)) +#define CX25840_IR_TX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec)) + +struct cx25840_ir_state { + struct i2c_client *c; + + struct v4l2_subdev_ir_parameters rx_params; + struct mutex rx_params_lock; /* protects Rx parameter settings cache */ + atomic_t rxclk_divider; + atomic_t rx_invert; + + struct kfifo rx_kfifo; + spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */ + + struct v4l2_subdev_ir_parameters tx_params; + struct mutex tx_params_lock; /* protects Tx parameter settings cache */ + atomic_t txclk_divider; +}; + +static inline struct cx25840_ir_state *to_ir_state(struct v4l2_subdev *sd) +{ + struct cx25840_state *state = to_state(sd); + return state ? state->ir_state : NULL; +} + + +/* + * Rx and Tx Clock Divider register computations + * + * Note the largest clock divider value of 0xffff corresponds to: + * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns + * which fits in 21 bits, so we'll use unsigned int for time arguments. + */ +static inline u16 count_to_clock_divider(unsigned int d) +{ + if (d > RXCLK_RCD + 1) + d = RXCLK_RCD; + else if (d < 2) + d = 1; + else + d--; + return (u16) d; +} + +static inline u16 ns_to_clock_divider(unsigned int ns) +{ + return count_to_clock_divider( + DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000)); +} + +static inline unsigned int clock_divider_to_ns(unsigned int divider) +{ + /* Period of the Rx or Tx clock in ns */ + return DIV_ROUND_CLOSEST((divider + 1) * 1000, + CX25840_IR_REFCLK_FREQ / 1000000); +} + +static inline u16 carrier_freq_to_clock_divider(unsigned int freq) +{ + return count_to_clock_divider( + DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * 16)); +} + +static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) +{ + return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, (divider + 1) * 16); +} + +static inline u16 freq_to_clock_divider(unsigned int freq, + unsigned int rollovers) +{ + return count_to_clock_divider( + DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * rollovers)); +} + +static inline unsigned int clock_divider_to_freq(unsigned int divider, + unsigned int rollovers) +{ + return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, + (divider + 1) * rollovers); +} + +/* + * Low Pass Filter register calculations + * + * Note the largest count value of 0xffff corresponds to: + * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns + * which fits in 21 bits, so we'll use unsigned int for time arguments. + */ +static inline u16 count_to_lpf_count(unsigned int d) +{ + if (d > FILTR_LPF) + d = FILTR_LPF; + else if (d < 4) + d = 0; + return (u16) d; +} + +static inline u16 ns_to_lpf_count(unsigned int ns) +{ + return count_to_lpf_count( + DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000)); +} + +static inline unsigned int lpf_count_to_ns(unsigned int count) +{ + /* Duration of the Low Pass Filter rejection window in ns */ + return DIV_ROUND_CLOSEST(count * 1000, + CX25840_IR_REFCLK_FREQ / 1000000); +} + +static inline unsigned int lpf_count_to_us(unsigned int count) +{ + /* Duration of the Low Pass Filter rejection window in us */ + return DIV_ROUND_CLOSEST(count, CX25840_IR_REFCLK_FREQ / 1000000); +} + +/* + * FIFO register pulse width count compuations + */ +static u32 clock_divider_to_resolution(u16 divider) +{ + /* + * Resolution is the duration of 1 tick of the readable portion of + * of the pulse width counter as read from the FIFO. The two lsb's are + * not readable, hence the << 2. This function returns ns. + */ + return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, + CX25840_IR_REFCLK_FREQ / 1000000); +} + +static u64 pulse_width_count_to_ns(u16 count, u16 divider) +{ + u64 n; + u32 rem; + + /* + * The 2 lsb's of the pulse width timer count are not readable, hence + * the (count << 2) | 0x3 + */ + n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */ + rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */ + if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2) + n++; + return n; +} + +#if 0 +/* Keep as we will need this for Transmit functionality */ +static u16 ns_to_pulse_width_count(u32 ns, u16 divider) +{ + u64 n; + u32 d; + u32 rem; + + /* + * The 2 lsb's of the pulse width timer count are not accessible, hence + * the (1 << 2) + */ + n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */ + d = (1 << 2) * ((u32) divider + 1) * 1000; /* millicycles/count */ + rem = do_div(n, d); + if (rem >= d / 2) + n++; + + if (n > FIFO_RXTX) + n = FIFO_RXTX; + else if (n == 0) + n = 1; + return (u16) n; +} + +#endif +static unsigned int pulse_width_count_to_us(u16 count, u16 divider) +{ + u64 n; + u32 rem; + + /* + * The 2 lsb's of the pulse width timer count are not readable, hence + * the (count << 2) | 0x3 + */ + n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */ + rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => us */ + if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2) + n++; + return (unsigned int) n; +} + +/* + * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts + * + * The total pulse clock count is an 18 bit pulse width timer count as the most + * significant part and (up to) 16 bit clock divider count as a modulus. + * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse + * width timer count's least significant bit. + */ +static u64 ns_to_pulse_clocks(u32 ns) +{ + u64 clocks; + u32 rem; + clocks = CX25840_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */ + rem = do_div(clocks, 1000); /* /1000 = cycles */ + if (rem >= 1000 / 2) + clocks++; + return clocks; +} + +static u16 pulse_clocks_to_clock_divider(u64 count) +{ + u32 rem; + + rem = do_div(count, (FIFO_RXTX << 2) | 0x3); + + /* net result needs to be rounded down and decremented by 1 */ + if (count > RXCLK_RCD + 1) + count = RXCLK_RCD; + else if (count < 2) + count = 1; + else + count--; + return (u16) count; +} + +/* + * IR Control Register helpers + */ +enum tx_fifo_watermark { + TX_FIFO_HALF_EMPTY = 0, + TX_FIFO_EMPTY = CNTRL_TIC, +}; + +enum rx_fifo_watermark { + RX_FIFO_HALF_FULL = 0, + RX_FIFO_NOT_EMPTY = CNTRL_RIC, +}; + +static inline void control_tx_irq_watermark(struct i2c_client *c, + enum tx_fifo_watermark level) +{ + cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_TIC, level); +} + +static inline void control_rx_irq_watermark(struct i2c_client *c, + enum rx_fifo_watermark level) +{ + cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_RIC, level); +} + +static inline void control_tx_enable(struct i2c_client *c, bool enable) +{ + cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE), + enable ? (CNTRL_TXE | CNTRL_TFE) : 0); +} + +static inline void control_rx_enable(struct i2c_client *c, bool enable) +{ + cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE), + enable ? (CNTRL_RXE | CNTRL_RFE) : 0); +} + +static inline void control_tx_modulation_enable(struct i2c_client *c, + bool enable) +{ + cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_MOD, + enable ? CNTRL_MOD : 0); +} + +static inline void control_rx_demodulation_enable(struct i2c_client *c, + bool enable) +{ + cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_DMD, + enable ? CNTRL_DMD : 0); +} + +static inline void control_rx_s_edge_detection(struct i2c_client *c, + u32 edge_types) +{ + cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_EDG_BOTH, + edge_types & CNTRL_EDG_BOTH); +} + +static void control_rx_s_carrier_window(struct i2c_client *c, + unsigned int carrier, + unsigned int *carrier_range_low, + unsigned int *carrier_range_high) +{ + u32 v; + unsigned int c16 = carrier * 16; + + if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) { + v = CNTRL_WIN_3_4; + *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4); + } else { + v = CNTRL_WIN_3_3; + *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3); + } + + if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { + v |= CNTRL_WIN_4_3; + *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); + } else { + v |= CNTRL_WIN_3_3; + *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); + } + cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_WIN, v); +} + +static inline void control_tx_polarity_invert(struct i2c_client *c, + bool invert) +{ + cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_CPL, + invert ? CNTRL_CPL : 0); +} + +/* + * IR Rx & Tx Clock Register helpers + */ +static unsigned int txclk_tx_s_carrier(struct i2c_client *c, + unsigned int freq, + u16 *divider) +{ + *divider = carrier_freq_to_clock_divider(freq); + cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider); + return clock_divider_to_carrier_freq(*divider); +} + +static unsigned int rxclk_rx_s_carrier(struct i2c_client *c, + unsigned int freq, + u16 *divider) +{ + *divider = carrier_freq_to_clock_divider(freq); + cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider); + return clock_divider_to_carrier_freq(*divider); +} + +static u32 txclk_tx_s_max_pulse_width(struct i2c_client *c, u32 ns, + u16 *divider) +{ + u64 pulse_clocks; + + if (ns > IR_MAX_DURATION) + ns = IR_MAX_DURATION; + pulse_clocks = ns_to_pulse_clocks(ns); + *divider = pulse_clocks_to_clock_divider(pulse_clocks); + cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider); + return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); +} + +static u32 rxclk_rx_s_max_pulse_width(struct i2c_client *c, u32 ns, + u16 *divider) +{ + u64 pulse_clocks; + + if (ns > IR_MAX_DURATION) + ns = IR_MAX_DURATION; + pulse_clocks = ns_to_pulse_clocks(ns); + *divider = pulse_clocks_to_clock_divider(pulse_clocks); + cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider); + return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); +} + +/* + * IR Tx Carrier Duty Cycle register helpers + */ +static unsigned int cduty_tx_s_duty_cycle(struct i2c_client *c, + unsigned int duty_cycle) +{ + u32 n; + n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */ + if (n != 0) + n--; + if (n > 15) + n = 15; + cx25840_write4(c, CX25840_IR_CDUTY_REG, n); + return DIV_ROUND_CLOSEST((n + 1) * 100, 16); +} + +/* + * IR Filter Register helpers + */ +static u32 filter_rx_s_min_width(struct i2c_client *c, u32 min_width_ns) +{ + u32 count = ns_to_lpf_count(min_width_ns); + cx25840_write4(c, CX25840_IR_FILTR_REG, count); + return lpf_count_to_ns(count); +} + +/* + * IR IRQ Enable Register helpers + */ +static inline void irqenable_rx(struct v4l2_subdev *sd, u32 mask) +{ + struct cx25840_state *state = to_state(sd); + + if (is_cx23885(state) || is_cx23887(state)) + mask ^= IRQEN_MSK; + mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE); + cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, + ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask); +} + +static inline void irqenable_tx(struct v4l2_subdev *sd, u32 mask) +{ + struct cx25840_state *state = to_state(sd); + + if (is_cx23885(state) || is_cx23887(state)) + mask ^= IRQEN_MSK; + mask &= IRQEN_TSE; + cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, ~IRQEN_TSE, mask); +} + +/* + * V4L2 Subdevice IR Ops + */ +int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled) +{ + struct cx25840_state *state = to_state(sd); + struct cx25840_ir_state *ir_state = to_ir_state(sd); + struct i2c_client *c = NULL; + unsigned long flags; + + union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH]; + unsigned int i, j, k; + u32 events, v; + int tsr, rsr, rto, ror, tse, rse, rte, roe, kror; + u32 cntrl, irqen, stats; + + *handled = false; + if (ir_state == NULL) + return -ENODEV; + + c = ir_state->c; + + /* Only support the IR controller for the CX2388[57] AV Core for now */ + if (!(is_cx23885(state) || is_cx23887(state))) + return -ENODEV; + + cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG); + irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG); + if (is_cx23885(state) || is_cx23887(state)) + irqen ^= IRQEN_MSK; + stats = cx25840_read4(c, CX25840_IR_STATS_REG); + + tsr = stats & STATS_TSR; /* Tx FIFO Service Request */ + rsr = stats & STATS_RSR; /* Rx FIFO Service Request */ + rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */ + ror = stats & STATS_ROR; /* Rx FIFO Over Run */ + + tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ + rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ + rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ + roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ + + v4l2_dbg(2, ir_debug, sd, "IR IRQ Status: %s %s %s %s %s %s\n", + tsr ? "tsr" : " ", rsr ? "rsr" : " ", + rto ? "rto" : " ", ror ? "ror" : " ", + stats & STATS_TBY ? "tby" : " ", + stats & STATS_RBY ? "rby" : " "); + + v4l2_dbg(2, ir_debug, sd, "IR IRQ Enables: %s %s %s %s\n", + tse ? "tse" : " ", rse ? "rse" : " ", + rte ? "rte" : " ", roe ? "roe" : " "); + + /* + * Transmitter interrupt service + */ + if (tse && tsr) { + /* + * TODO: + * Check the watermark threshold setting + * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo + * Push the data to the hardware FIFO. + * If there was nothing more to send in the tx_kfifo, disable + * the TSR IRQ and notify the v4l2_device. + * If there was something in the tx_kfifo, check the tx_kfifo + * level and notify the v4l2_device, if it is low. + */ + /* For now, inhibit TSR interrupt until Tx is implemented */ + irqenable_tx(sd, 0); + events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; + v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events); + *handled = true; + } + + /* + * Receiver interrupt service + */ + kror = 0; + if ((rse && rsr) || (rte && rto)) { + /* + * Receive data on RSR to clear the STATS_RSR. + * Receive data on RTO, since we may not have yet hit the RSR + * watermark when we receive the RTO. + */ + for (i = 0, v = FIFO_RX_NDV; + (v & FIFO_RX_NDV) && !kror; i = 0) { + for (j = 0; + (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) { + v = cx25840_read4(c, CX25840_IR_FIFO_REG); + rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV; + i++; + } + if (i == 0) + break; + j = i * sizeof(union cx25840_ir_fifo_rec); + k = kfifo_in_locked(&ir_state->rx_kfifo, + (unsigned char *) rx_data, j, + &ir_state->rx_kfifo_lock); + if (k != j) + kror++; /* rx_kfifo over run */ + } + *handled = true; + } + + events = 0; + v = 0; + if (kror) { + events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; + v4l2_err(sd, "IR receiver software FIFO overrun\n"); + } + if (roe && ror) { + /* + * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear + * the Rx FIFO Over Run status (STATS_ROR) + */ + v |= CNTRL_RFE; + events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; + v4l2_err(sd, "IR receiver hardware FIFO overrun\n"); + } + if (rte && rto) { + /* + * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear + * the Rx Pulse Width Timer Time Out (STATS_RTO) + */ + v |= CNTRL_RXE; + events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; + } + if (v) { + /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ + cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl & ~v); + cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl); + *handled = true; + } + spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); + if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) + events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; + spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); + + if (events) + v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); + return 0; +} + +/* Receiver */ +static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, + ssize_t *num) +{ + struct cx25840_ir_state *ir_state = to_ir_state(sd); + bool invert; + u16 divider; + unsigned int i, n; + union cx25840_ir_fifo_rec *p; + unsigned u, v; + + if (ir_state == NULL) + return -ENODEV; + + invert = (bool) atomic_read(&ir_state->rx_invert); + divider = (u16) atomic_read(&ir_state->rxclk_divider); + + n = count / sizeof(union cx25840_ir_fifo_rec) + * sizeof(union cx25840_ir_fifo_rec); + if (n == 0) { + *num = 0; + return 0; + } + + n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n, + &ir_state->rx_kfifo_lock); + + n /= sizeof(union cx25840_ir_fifo_rec); + *num = n * sizeof(union cx25840_ir_fifo_rec); + + for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) { + + if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { + /* Assume RTO was because of no IR light input */ + u = 0; + v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n"); + } else { + u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; + if (invert) + u = u ? 0 : 1; + } + + v = (unsigned) pulse_width_count_to_ns( + (u16) (p->hw_fifo_data & FIFO_RXTX), divider); + if (v > IR_MAX_DURATION) + v = IR_MAX_DURATION; + + init_ir_raw_event(&p->ir_core_data); + p->ir_core_data.pulse = u; + p->ir_core_data.duration = v; + + v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s\n", + v, u ? "mark" : "space"); + } + return 0; +} + +static int cx25840_ir_rx_g_parameters(struct v4l2_subdev *sd, + struct v4l2_subdev_ir_parameters *p) +{ + struct cx25840_ir_state *ir_state = to_ir_state(sd); + + if (ir_state == NULL) + return -ENODEV; + + mutex_lock(&ir_state->rx_params_lock); + memcpy(p, &ir_state->rx_params, + sizeof(struct v4l2_subdev_ir_parameters)); + mutex_unlock(&ir_state->rx_params_lock); + return 0; +} + +static int cx25840_ir_rx_shutdown(struct v4l2_subdev *sd) +{ + struct cx25840_ir_state *ir_state = to_ir_state(sd); + struct i2c_client *c; + + if (ir_state == NULL) + return -ENODEV; + + c = ir_state->c; + mutex_lock(&ir_state->rx_params_lock); + + /* Disable or slow down all IR Rx circuits and counters */ + irqenable_rx(sd, 0); + control_rx_enable(c, false); + control_rx_demodulation_enable(c, false); + control_rx_s_edge_detection(c, CNTRL_EDG_NONE); + filter_rx_s_min_width(c, 0); + cx25840_write4(c, CX25840_IR_RXCLK_REG, RXCLK_RCD); + + ir_state->rx_params.shutdown = true; + + mutex_unlock(&ir_state->rx_params_lock); + return 0; +} + +static int cx25840_ir_rx_s_parameters(struct v4l2_subdev *sd, + struct v4l2_subdev_ir_parameters *p) +{ + struct cx25840_ir_state *ir_state = to_ir_state(sd); + struct i2c_client *c; + struct v4l2_subdev_ir_parameters *o; + u16 rxclk_divider; + + if (ir_state == NULL) + return -ENODEV; + + if (p->shutdown) + return cx25840_ir_rx_shutdown(sd); + + if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) + return -ENOSYS; + + c = ir_state->c; + o = &ir_state->rx_params; + + mutex_lock(&ir_state->rx_params_lock); + + o->shutdown = p->shutdown; + + p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; + o->mode = p->mode; + + p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec); + o->bytes_per_data_element = p->bytes_per_data_element; + + /* Before we tweak the hardware, we have to disable the receiver */ + irqenable_rx(sd, 0); + control_rx_enable(c, false); + + control_rx_demodulation_enable(c, p->modulation); + o->modulation = p->modulation; + + if (p->modulation) { + p->carrier_freq = rxclk_rx_s_carrier(c, p->carrier_freq, + &rxclk_divider); + + o->carrier_freq = p->carrier_freq; + + p->duty_cycle = 50; + o->duty_cycle = p->duty_cycle; + + control_rx_s_carrier_window(c, p->carrier_freq, + &p->carrier_range_lower, + &p->carrier_range_upper); + o->carrier_range_lower = p->carrier_range_lower; + o->carrier_range_upper = p->carrier_range_upper; + + p->max_pulse_width = + (u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider); + } else { + p->max_pulse_width = + rxclk_rx_s_max_pulse_width(c, p->max_pulse_width, + &rxclk_divider); + } + o->max_pulse_width = p->max_pulse_width; + atomic_set(&ir_state->rxclk_divider, rxclk_divider); + + p->noise_filter_min_width = + filter_rx_s_min_width(c, p->noise_filter_min_width); + o->noise_filter_min_width = p->noise_filter_min_width; + + p->resolution = clock_divider_to_resolution(rxclk_divider); + o->resolution = p->resolution; + + /* FIXME - make this dependent on resolution for better performance */ + control_rx_irq_watermark(c, RX_FIFO_HALF_FULL); + + control_rx_s_edge_detection(c, CNTRL_EDG_BOTH); + + o->invert_level = p->invert_level; + atomic_set(&ir_state->rx_invert, p->invert_level); + + o->interrupt_enable = p->interrupt_enable; + o->enable = p->enable; + if (p->enable) { + unsigned long flags; + + spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); + kfifo_reset(&ir_state->rx_kfifo); + spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); + if (p->interrupt_enable) + irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); + control_rx_enable(c, p->enable); + } + + mutex_unlock(&ir_state->rx_params_lock); + return 0; +} + +/* Transmitter */ +static int cx25840_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count, + ssize_t *num) +{ + struct cx25840_ir_state *ir_state = to_ir_state(sd); + struct i2c_client *c; + + if (ir_state == NULL) + return -ENODEV; + + c = ir_state->c; +#if 0 + /* + * FIXME - the code below is an incomplete and untested sketch of what + * may need to be done. The critical part is to get 4 (or 8) pulses + * from the tx_kfifo, or converted from ns to the proper units from the + * input, and push them off to the hardware Tx FIFO right away, if the + * HW TX fifo needs service. The rest can be pushed to the tx_kfifo in + * a less critical timeframe. Also watch out for overruning the + * tx_kfifo - don't let it happen and let the caller know not all his + * pulses were written. + */ + u32 *ns_pulse = (u32 *) buf; + unsigned int n; + u32 fifo_pulse[FIFO_TX_DEPTH]; + u32 mark; + + /* Compute how much we can fit in the tx kfifo */ + n = CX25840_IR_TX_KFIFO_SIZE - kfifo_len(ir_state->tx_kfifo); + n = min(n, (unsigned int) count); + n /= sizeof(u32); + + /* FIXME - turn on Tx Fifo service interrupt + * check hardware fifo level, and other stuff + */ + for (i = 0; i < n; ) { + for (j = 0; j < FIFO_TX_DEPTH / 2 && i < n; j++) { + mark = ns_pulse[i] & LEVEL_MASK; + fifo_pulse[j] = ns_to_pulse_width_count( + ns_pulse[i] & + ~LEVEL_MASK, + ir_state->txclk_divider); + if (mark) + fifo_pulse[j] &= FIFO_RXTX_LVL; + i++; + } + kfifo_put(ir_state->tx_kfifo, (u8 *) fifo_pulse, + j * sizeof(u32)); + } + *num = n * sizeof(u32); +#else + /* For now enable the Tx FIFO Service interrupt & pretend we did work */ + irqenable_tx(sd, IRQEN_TSE); + *num = count; +#endif + return 0; +} + +static int cx25840_ir_tx_g_parameters(struct v4l2_subdev *sd, + struct v4l2_subdev_ir_parameters *p) +{ + struct cx25840_ir_state *ir_state = to_ir_state(sd); + + if (ir_state == NULL) + return -ENODEV; + + mutex_lock(&ir_state->tx_params_lock); + memcpy(p, &ir_state->tx_params, + sizeof(struct v4l2_subdev_ir_parameters)); + mutex_unlock(&ir_state->tx_params_lock); + return 0; +} + +static int cx25840_ir_tx_shutdown(struct v4l2_subdev *sd) +{ + struct cx25840_ir_state *ir_state = to_ir_state(sd); + struct i2c_client *c; + + if (ir_state == NULL) + return -ENODEV; + + c = ir_state->c; + mutex_lock(&ir_state->tx_params_lock); + + /* Disable or slow down all IR Tx circuits and counters */ + irqenable_tx(sd, 0); + control_tx_enable(c, false); + control_tx_modulation_enable(c, false); + cx25840_write4(c, CX25840_IR_TXCLK_REG, TXCLK_TCD); + + ir_state->tx_params.shutdown = true; + + mutex_unlock(&ir_state->tx_params_lock); + return 0; +} + +static int cx25840_ir_tx_s_parameters(struct v4l2_subdev *sd, + struct v4l2_subdev_ir_parameters *p) +{ + struct cx25840_ir_state *ir_state = to_ir_state(sd); + struct i2c_client *c; + struct v4l2_subdev_ir_parameters *o; + u16 txclk_divider; + + if (ir_state == NULL) + return -ENODEV; + + if (p->shutdown) + return cx25840_ir_tx_shutdown(sd); + + if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) + return -ENOSYS; + + c = ir_state->c; + o = &ir_state->tx_params; + mutex_lock(&ir_state->tx_params_lock); + + o->shutdown = p->shutdown; + + p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; + o->mode = p->mode; + + p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec); + o->bytes_per_data_element = p->bytes_per_data_element; + + /* Before we tweak the hardware, we have to disable the transmitter */ + irqenable_tx(sd, 0); + control_tx_enable(c, false); + + control_tx_modulation_enable(c, p->modulation); + o->modulation = p->modulation; + + if (p->modulation) { + p->carrier_freq = txclk_tx_s_carrier(c, p->carrier_freq, + &txclk_divider); + o->carrier_freq = p->carrier_freq; + + p->duty_cycle = cduty_tx_s_duty_cycle(c, p->duty_cycle); + o->duty_cycle = p->duty_cycle; + + p->max_pulse_width = + (u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider); + } else { + p->max_pulse_width = + txclk_tx_s_max_pulse_width(c, p->max_pulse_width, + &txclk_divider); + } + o->max_pulse_width = p->max_pulse_width; + atomic_set(&ir_state->txclk_divider, txclk_divider); + + p->resolution = clock_divider_to_resolution(txclk_divider); + o->resolution = p->resolution; + + /* FIXME - make this dependent on resolution for better performance */ + control_tx_irq_watermark(c, TX_FIFO_HALF_EMPTY); + + control_tx_polarity_invert(c, p->invert_carrier_sense); + o->invert_carrier_sense = p->invert_carrier_sense; + + /* + * FIXME: we don't have hardware help for IO pin level inversion + * here like we have on the CX23888. + * Act on this with some mix of logical inversion of data levels, + * carrier polarity, and carrier duty cycle. + */ + o->invert_level = p->invert_level; + + o->interrupt_enable = p->interrupt_enable; + o->enable = p->enable; + if (p->enable) { + /* reset tx_fifo here */ + if (p->interrupt_enable) + irqenable_tx(sd, IRQEN_TSE); + control_tx_enable(c, p->enable); + } + + mutex_unlock(&ir_state->tx_params_lock); + return 0; +} + + +/* + * V4L2 Subdevice Core Ops support + */ +int cx25840_ir_log_status(struct v4l2_subdev *sd) +{ + struct cx25840_state *state = to_state(sd); + struct i2c_client *c = state->c; + char *s; + int i, j; + u32 cntrl, txclk, rxclk, cduty, stats, irqen, filtr; + + /* The CX23888 chip doesn't have an IR controller on the A/V core */ + if (is_cx23888(state)) + return 0; + + cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG); + txclk = cx25840_read4(c, CX25840_IR_TXCLK_REG) & TXCLK_TCD; + rxclk = cx25840_read4(c, CX25840_IR_RXCLK_REG) & RXCLK_RCD; + cduty = cx25840_read4(c, CX25840_IR_CDUTY_REG) & CDUTY_CDC; + stats = cx25840_read4(c, CX25840_IR_STATS_REG); + irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG); + if (is_cx23885(state) || is_cx23887(state)) + irqen ^= IRQEN_MSK; + filtr = cx25840_read4(c, CX25840_IR_FILTR_REG) & FILTR_LPF; + + v4l2_info(sd, "IR Receiver:\n"); + v4l2_info(sd, "\tEnabled: %s\n", + cntrl & CNTRL_RXE ? "yes" : "no"); + v4l2_info(sd, "\tDemodulation from a carrier: %s\n", + cntrl & CNTRL_DMD ? "enabled" : "disabled"); + v4l2_info(sd, "\tFIFO: %s\n", + cntrl & CNTRL_RFE ? "enabled" : "disabled"); + switch (cntrl & CNTRL_EDG) { + case CNTRL_EDG_NONE: + s = "disabled"; + break; + case CNTRL_EDG_FALL: + s = "falling edge"; + break; + case CNTRL_EDG_RISE: + s = "rising edge"; + break; + case CNTRL_EDG_BOTH: + s = "rising & falling edges"; + break; + default: + s = "??? edge"; + break; + } + v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s); + v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n", + cntrl & CNTRL_R ? "not loaded" : "overflow marker"); + v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", + cntrl & CNTRL_RIC ? "not empty" : "half full or greater"); + v4l2_info(sd, "\tLoopback mode: %s\n", + cntrl & CNTRL_LBM ? "loopback active" : "normal receive"); + if (cntrl & CNTRL_DMD) { + v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n", + clock_divider_to_carrier_freq(rxclk)); + switch (cntrl & CNTRL_WIN) { + case CNTRL_WIN_3_3: + i = 3; + j = 3; + break; + case CNTRL_WIN_4_3: + i = 4; + j = 3; + break; + case CNTRL_WIN_3_4: + i = 3; + j = 4; + break; + case CNTRL_WIN_4_4: + i = 4; + j = 4; + break; + default: + i = 0; + j = 0; + break; + } + v4l2_info(sd, "\tNext carrier edge window: 16 clocks " + "-%1d/+%1d, %u to %u Hz\n", i, j, + clock_divider_to_freq(rxclk, 16 + j), + clock_divider_to_freq(rxclk, 16 - i)); + } + v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n", + pulse_width_count_to_us(FIFO_RXTX, rxclk), + pulse_width_count_to_ns(FIFO_RXTX, rxclk)); + v4l2_info(sd, "\tLow pass filter: %s\n", + filtr ? "enabled" : "disabled"); + if (filtr) + v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " + "%u ns\n", + lpf_count_to_us(filtr), + lpf_count_to_ns(filtr)); + v4l2_info(sd, "\tPulse width timer timed-out: %s\n", + stats & STATS_RTO ? "yes" : "no"); + v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", + irqen & IRQEN_RTE ? "enabled" : "disabled"); + v4l2_info(sd, "\tFIFO overrun: %s\n", + stats & STATS_ROR ? "yes" : "no"); + v4l2_info(sd, "\tFIFO overrun interrupt: %s\n", + irqen & IRQEN_ROE ? "enabled" : "disabled"); + v4l2_info(sd, "\tBusy: %s\n", + stats & STATS_RBY ? "yes" : "no"); + v4l2_info(sd, "\tFIFO service requested: %s\n", + stats & STATS_RSR ? "yes" : "no"); + v4l2_info(sd, "\tFIFO service request interrupt: %s\n", + irqen & IRQEN_RSE ? "enabled" : "disabled"); + + v4l2_info(sd, "IR Transmitter:\n"); + v4l2_info(sd, "\tEnabled: %s\n", + cntrl & CNTRL_TXE ? "yes" : "no"); + v4l2_info(sd, "\tModulation onto a carrier: %s\n", + cntrl & CNTRL_MOD ? "enabled" : "disabled"); + v4l2_info(sd, "\tFIFO: %s\n", + cntrl & CNTRL_TFE ? "enabled" : "disabled"); + v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", + cntrl & CNTRL_TIC ? "not empty" : "half full or less"); + v4l2_info(sd, "\tCarrier polarity: %s\n", + cntrl & CNTRL_CPL ? "space:burst mark:noburst" + : "space:noburst mark:burst"); + if (cntrl & CNTRL_MOD) { + v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n", + clock_divider_to_carrier_freq(txclk)); + v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n", + cduty + 1); + } + v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n", + pulse_width_count_to_us(FIFO_RXTX, txclk), + pulse_width_count_to_ns(FIFO_RXTX, txclk)); + v4l2_info(sd, "\tBusy: %s\n", + stats & STATS_TBY ? "yes" : "no"); + v4l2_info(sd, "\tFIFO service requested: %s\n", + stats & STATS_TSR ? "yes" : "no"); + v4l2_info(sd, "\tFIFO service request interrupt: %s\n", + irqen & IRQEN_TSE ? "enabled" : "disabled"); + + return 0; +} + + +const struct v4l2_subdev_ir_ops cx25840_ir_ops = { + .rx_read = cx25840_ir_rx_read, + .rx_g_parameters = cx25840_ir_rx_g_parameters, + .rx_s_parameters = cx25840_ir_rx_s_parameters, + + .tx_write = cx25840_ir_tx_write, + .tx_g_parameters = cx25840_ir_tx_g_parameters, + .tx_s_parameters = cx25840_ir_tx_s_parameters, +}; + + +static const struct v4l2_subdev_ir_parameters default_rx_params = { + .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec), + .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, + + .enable = false, + .interrupt_enable = false, + .shutdown = true, + + .modulation = true, + .carrier_freq = 36000, /* 36 kHz - RC-5, and RC-6 carrier */ + + /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ + /* RC-6: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ + .noise_filter_min_width = 333333, /* ns */ + .carrier_range_lower = 35000, + .carrier_range_upper = 37000, + .invert_level = false, +}; + +static const struct v4l2_subdev_ir_parameters default_tx_params = { + .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec), + .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, + + .enable = false, + .interrupt_enable = false, + .shutdown = true, + + .modulation = true, + .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ + .duty_cycle = 25, /* 25 % - RC-5 carrier */ + .invert_level = false, + .invert_carrier_sense = false, +}; + +int cx25840_ir_probe(struct v4l2_subdev *sd) +{ + struct cx25840_state *state = to_state(sd); + struct cx25840_ir_state *ir_state; + struct v4l2_subdev_ir_parameters default_params; + + /* Only init the IR controller for the CX2388[57] AV Core for now */ + if (!(is_cx23885(state) || is_cx23887(state))) + return 0; + + ir_state = kzalloc(sizeof(struct cx25840_ir_state), GFP_KERNEL); + if (ir_state == NULL) + return -ENOMEM; + + spin_lock_init(&ir_state->rx_kfifo_lock); + if (kfifo_alloc(&ir_state->rx_kfifo, + CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) { + kfree(ir_state); + return -ENOMEM; + } + + ir_state->c = state->c; + state->ir_state = ir_state; + + /* Ensure no interrupts arrive yet */ + if (is_cx23885(state) || is_cx23887(state)) + cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, IRQEN_MSK); + else + cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0); + + mutex_init(&ir_state->rx_params_lock); + memcpy(&default_params, &default_rx_params, + sizeof(struct v4l2_subdev_ir_parameters)); + v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); + + mutex_init(&ir_state->tx_params_lock); + memcpy(&default_params, &default_tx_params, + sizeof(struct v4l2_subdev_ir_parameters)); + v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); + + return 0; +} + +int cx25840_ir_remove(struct v4l2_subdev *sd) +{ + struct cx25840_state *state = to_state(sd); + struct cx25840_ir_state *ir_state = to_ir_state(sd); + + if (ir_state == NULL) + return -ENODEV; + + cx25840_ir_rx_shutdown(sd); + cx25840_ir_tx_shutdown(sd); + + kfifo_free(&ir_state->rx_kfifo); + kfree(ir_state); + state->ir_state = NULL; + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/cx25840-vbi.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,256 @@ +/* cx25840 VBI functions + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include +#include + +#include "cx25840-core.h" + +static int odd_parity(u8 c) +{ + c ^= (c >> 4); + c ^= (c >> 2); + c ^= (c >> 1); + + return c & 1; +} + +static int decode_vps(u8 * dst, u8 * p) +{ + static const u8 biphase_tbl[] = { + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, + 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, + 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, + 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, + 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, + 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, + 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + }; + + u8 c, err = 0; + int i; + + for (i = 0; i < 2 * 13; i += 2) { + err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; + c = (biphase_tbl[p[i + 1]] & 0xf) | + ((biphase_tbl[p[i]] & 0xf) << 4); + dst[i / 2] = c; + } + + return err & 0xf0; +} + +int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct cx25840_state *state = to_state(sd); + static const u16 lcr2vbi[] = { + 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ + 0, V4L2_SLICED_WSS_625, 0, /* 4 */ + V4L2_SLICED_CAPTION_525, /* 6 */ + 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ + 0, 0, 0, 0 + }; + int is_pal = !(state->std & V4L2_STD_525_60); + int i; + + memset(svbi, 0, sizeof(*svbi)); + /* we're done if raw VBI is active */ + if ((cx25840_read(client, 0x404) & 0x10) == 0) + return 0; + + if (is_pal) { + for (i = 7; i <= 23; i++) { + u8 v = cx25840_read(client, 0x424 + i - 7); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } else { + for (i = 10; i <= 21; i++) { + u8 v = cx25840_read(client, 0x424 + i - 10); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } + return 0; +} + +int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct cx25840_state *state = to_state(sd); + int is_pal = !(state->std & V4L2_STD_525_60); + int vbi_offset = is_pal ? 1 : 0; + + /* Setup standard */ + cx25840_std_setup(client); + + /* VBI Offset */ + cx25840_write(client, 0x47f, vbi_offset); + cx25840_write(client, 0x404, 0x2e); + return 0; +} + +int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct cx25840_state *state = to_state(sd); + int is_pal = !(state->std & V4L2_STD_525_60); + int vbi_offset = is_pal ? 1 : 0; + int i, x; + u8 lcr[24]; + + for (x = 0; x <= 23; x++) + lcr[x] = 0x00; + + /* Setup standard */ + cx25840_std_setup(client); + + /* Sliced VBI */ + cx25840_write(client, 0x404, 0x32); /* Ancillary data */ + cx25840_write(client, 0x406, 0x13); + cx25840_write(client, 0x47f, vbi_offset); + + if (is_pal) { + for (i = 0; i <= 6; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } else { + for (i = 0; i <= 9; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + + for (i = 22; i <= 23; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } + + for (i = 7; i <= 23; i++) { + for (x = 0; x <= 1; x++) { + switch (svbi->service_lines[1-x][i]) { + case V4L2_SLICED_TELETEXT_B: + lcr[i] |= 1 << (4 * x); + break; + case V4L2_SLICED_WSS_625: + lcr[i] |= 4 << (4 * x); + break; + case V4L2_SLICED_CAPTION_525: + lcr[i] |= 6 << (4 * x); + break; + case V4L2_SLICED_VPS: + lcr[i] |= 9 << (4 * x); + break; + } + } + } + + if (is_pal) { + for (x = 1, i = 0x424; i <= 0x434; i++, x++) + cx25840_write(client, i, lcr[6 + x]); + } else { + for (x = 1, i = 0x424; i <= 0x430; i++, x++) + cx25840_write(client, i, lcr[9 + x]); + for (i = 0x431; i <= 0x434; i++) + cx25840_write(client, i, 0); + } + + cx25840_write(client, 0x43c, 0x16); + cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22); + return 0; +} + +int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi) +{ + struct cx25840_state *state = to_state(sd); + u8 *p = vbi->p; + int id1, id2, l, err = 0; + + if (p[0] || p[1] != 0xff || p[2] != 0xff || + (p[3] != 0x55 && p[3] != 0x91)) { + vbi->line = vbi->type = 0; + return 0; + } + + p += 4; + id1 = p[-1]; + id2 = p[0] & 0xf; + l = p[2] & 0x3f; + l += state->vbi_line_offset; + p += 4; + + switch (id2) { + case 1: + id2 = V4L2_SLICED_TELETEXT_B; + break; + case 4: + id2 = V4L2_SLICED_WSS_625; + break; + case 6: + id2 = V4L2_SLICED_CAPTION_525; + err = !odd_parity(p[0]) || !odd_parity(p[1]); + break; + case 9: + id2 = V4L2_SLICED_VPS; + if (decode_vps(p, p) != 0) + err = 1; + break; + default: + id2 = 0; + err = 1; + break; + } + + vbi->type = err ? 0 : id2; + vbi->line = err ? 0 : l; + vbi->is_second_field = err ? 0 : (id1 == 0x55); + vbi->p = p; + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,8 @@ +config VIDEO_CX25840 + tristate "Conexant CX2584x audio/video decoders" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Conexant CX2584x audio/video decoders. + + To compile this driver as a module, choose M here: the + module will be called cx25840 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx25840/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,6 @@ +cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ + cx25840-vbi.o cx25840-ir.o + +obj-$(CONFIG_VIDEO_CX25840) += cx25840.o + +EXTRA_CFLAGS += -Idrivers/media/video diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-alsa.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-alsa.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-alsa.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-alsa.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1003 @@ +/* + * + * Support for audio capture + * PCI function #1 of the cx2388x. + * + * (c) 2007 Trent Piepho + * (c) 2005,2006 Ricardo Cerqueira + * (c) 2005 Mauro Carvalho Chehab + * Based on a dummy cx88 module by Gerd Knorr + * Based on dummy.c by Jaroslav Kysela + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx88.h" +#include "cx88-reg.h" + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg) + +#define dprintk_core(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg) + +/**************************************************************************** + Data type declarations - Can be moded to a header file later + ****************************************************************************/ + +struct cx88_audio_buffer { + unsigned int bpl; + struct btcx_riscmem risc; + struct videobuf_dmabuf dma; +}; + +struct cx88_audio_dev { + struct cx88_core *core; + struct cx88_dmaqueue q; + + /* pci i/o */ + struct pci_dev *pci; + + /* audio controls */ + int irq; + + struct snd_card *card; + + spinlock_t reg_lock; + atomic_t count; + + unsigned int dma_size; + unsigned int period_size; + unsigned int num_periods; + + struct videobuf_dmabuf *dma_risc; + + struct cx88_audio_buffer *buf; + + struct snd_pcm_substream *substream; +}; +typedef struct cx88_audio_dev snd_cx88_card_t; + + + +/**************************************************************************** + Module global static vars + ****************************************************************************/ + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; + +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled."); + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s)."); + + +/**************************************************************************** + Module macros + ****************************************************************************/ + +MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards"); +MODULE_AUTHOR("Ricardo Cerqueira"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Conexant,23881}," + "{{Conexant,23882}," + "{{Conexant,23883}"); +static unsigned int debug; +module_param(debug,int,0644); +MODULE_PARM_DESC(debug,"enable debug messages"); + +/**************************************************************************** + Module specific funtions + ****************************************************************************/ + +/* + * BOARD Specific: Sets audio DMA + */ + +static int _cx88_start_audio_dma(snd_cx88_card_t *chip) +{ + struct cx88_audio_buffer *buf = chip->buf; + struct cx88_core *core=chip->core; + const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25]; + + /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ + cx_clear(MO_AUD_DMACNTRL, 0x11); + + /* setup fifo + format - out channel */ + cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma); + + /* sets bpl size */ + cx_write(MO_AUDD_LNGTH, buf->bpl); + + /* reset counter */ + cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); + atomic_set(&chip->count, 0); + + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d " + "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, + chip->num_periods, buf->bpl * chip->num_periods); + + /* Enables corresponding bits at AUD_INT_STAT */ + cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); + + /* Clean any pending interrupt bits already set */ + cx_write(MO_AUD_INTSTAT, ~0); + + /* enable audio irqs */ + cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); + + /* start dma */ + cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */ + cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */ + + if (debug) + cx88_sram_channel_dump(chip->core, audio_ch); + + return 0; +} + +/* + * BOARD Specific: Resets audio DMA + */ +static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) +{ + struct cx88_core *core=chip->core; + dprintk(1, "Stopping audio DMA\n"); + + /* stop dma */ + cx_clear(MO_AUD_DMACNTRL, 0x11); + + /* disable irqs */ + cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); + cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); + + if (debug) + cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); + + return 0; +} + +#define MAX_IRQ_LOOP 50 + +/* + * BOARD Specific: IRQ dma bits + */ +static const char *cx88_aud_irqs[32] = { + "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */ + NULL, /* reserved */ + "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */ + NULL, /* reserved */ + "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ + NULL, /* reserved */ + "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ + NULL, /* reserved */ + "opc_err", "par_err", "rip_err", /* 16-18 */ + "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ +}; + +/* + * BOARD Specific: Threats IRQ audio specific calls + */ +static void cx8801_aud_irq(snd_cx88_card_t *chip) +{ + struct cx88_core *core = chip->core; + u32 status, mask; + + status = cx_read(MO_AUD_INTSTAT); + mask = cx_read(MO_AUD_INTMSK); + if (0 == (status & mask)) + return; + cx_write(MO_AUD_INTSTAT, status); + if (debug > 1 || (status & mask & ~0xff)) + cx88_print_irqbits(core->name, "irq aud", + cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), + status, mask); + /* risc op code error */ + if (status & AUD_INT_OPC_ERR) { + printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name); + cx_clear(MO_AUD_DMACNTRL, 0x11); + cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); + } + if (status & AUD_INT_DN_SYNC) { + dprintk(1, "Downstream sync error\n"); + cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); + return; + } + /* risc1 downstream */ + if (status & AUD_INT_DN_RISCI1) { + atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT)); + snd_pcm_period_elapsed(chip->substream); + } + /* FIXME: Any other status should deserve a special handling? */ +} + +/* + * BOARD Specific: Handles IRQ calls + */ +static irqreturn_t cx8801_irq(int irq, void *dev_id) +{ + snd_cx88_card_t *chip = dev_id; + struct cx88_core *core = chip->core; + u32 status; + int loop, handled = 0; + + for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_AUDINT); + if (0 == status) + goto out; + dprintk(3, "cx8801_irq loop %d/%d, status %x\n", + loop, MAX_IRQ_LOOP, status); + handled = 1; + cx_write(MO_PCI_INTSTAT, status); + + if (status & core->pci_irqmask) + cx88_core_irq(core, status); + if (status & PCI_INT_AUDINT) + cx8801_aud_irq(chip); + } + + if (MAX_IRQ_LOOP == loop) { + printk(KERN_ERR + "%s/1: IRQ loop detected, disabling interrupts\n", + core->name); + cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); + } + + out: + return IRQ_RETVAL(handled); +} + + +static int dsp_buffer_free(snd_cx88_card_t *chip) +{ + BUG_ON(!chip->dma_size); + + dprintk(2,"Freeing buffer\n"); + videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); + videobuf_dma_free(chip->dma_risc); + btcx_riscmem_free(chip->pci,&chip->buf->risc); + kfree(chip->buf); + + chip->dma_risc = NULL; + chip->dma_size = 0; + + return 0; +} + +/**************************************************************************** + ALSA PCM Interface + ****************************************************************************/ + +/* + * Digital hardware definition + */ +#define DEFAULT_FIFO_SIZE 4096 +static const struct snd_pcm_hardware snd_cx88_digital_hw = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + /* Analog audio output will be full of clicks and pops if there + are not exactly four lines in the SRAM FIFO buffer. */ + .period_bytes_min = DEFAULT_FIFO_SIZE/4, + .period_bytes_max = DEFAULT_FIFO_SIZE/4, + .periods_min = 1, + .periods_max = 1024, + .buffer_bytes_max = (1024*1024), +}; + +/* + * audio pcm capture open callback + */ +static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) +{ + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + + if (!chip) { + printk(KERN_ERR "BUG: cx88 can't find device struct." + " Can't proceed with open\n"); + return -ENODEV; + } + + err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) + goto _error; + + chip->substream = substream; + + runtime->hw = snd_cx88_digital_hw; + + if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) { + unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4; + bpl &= ~7; /* must be multiple of 8 */ + runtime->hw.period_bytes_min = bpl; + runtime->hw.period_bytes_max = bpl; + } + + return 0; +_error: + dprintk(1,"Error opening PCM!\n"); + return err; +} + +/* + * audio close callback + */ +static int snd_cx88_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* + * hw_params callback + */ +static int snd_cx88_hw_params(struct snd_pcm_substream * substream, + struct snd_pcm_hw_params * hw_params) +{ + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct videobuf_dmabuf *dma; + + struct cx88_audio_buffer *buf; + int ret; + + if (substream->runtime->dma_area) { + dsp_buffer_free(chip); + substream->runtime->dma_area = NULL; + } + + chip->period_size = params_period_bytes(hw_params); + chip->num_periods = params_periods(hw_params); + chip->dma_size = chip->period_size * params_periods(hw_params); + + BUG_ON(!chip->dma_size); + BUG_ON(chip->num_periods & (chip->num_periods-1)); + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (NULL == buf) + return -ENOMEM; + + buf->bpl = chip->period_size; + + dma = &buf->dma; + videobuf_dma_init(dma); + ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, + (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); + if (ret < 0) + goto error; + + ret = videobuf_dma_map(&chip->pci->dev, dma); + if (ret < 0) + goto error; + + ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist, + chip->period_size, chip->num_periods, 1); + if (ret < 0) + goto error; + + /* Loop back to start of program */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + + chip->buf = buf; + chip->dma_risc = dma; + + substream->runtime->dma_area = chip->dma_risc->vaddr; + substream->runtime->dma_bytes = chip->dma_size; + substream->runtime->dma_addr = 0; + return 0; + +error: + kfree(buf); + return ret; +} + +/* + * hw free callback + */ +static int snd_cx88_hw_free(struct snd_pcm_substream * substream) +{ + + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + + if (substream->runtime->dma_area) { + dsp_buffer_free(chip); + substream->runtime->dma_area = NULL; + } + + return 0; +} + +/* + * prepare callback + */ +static int snd_cx88_prepare(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* + * trigger callback + */ +static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd) +{ + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + int err; + + /* Local interrupts are already disabled by ALSA */ + spin_lock(&chip->reg_lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + err=_cx88_start_audio_dma(chip); + break; + case SNDRV_PCM_TRIGGER_STOP: + err=_cx88_stop_audio_dma(chip); + break; + default: + err=-EINVAL; + break; + } + + spin_unlock(&chip->reg_lock); + + return err; +} + +/* + * pointer callback + */ +static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) +{ + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + u16 count; + + count = atomic_read(&chip->count); + +// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__, +// count, new, count & (runtime->periods-1), +// runtime->period_size * (count & (runtime->periods-1))); + return runtime->period_size * (count & (runtime->periods-1)); +} + +/* + * page callback (needed for mmap) + */ +static struct page *snd_cx88_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + void *pageptr = substream->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + +/* + * operators + */ +static struct snd_pcm_ops snd_cx88_pcm_ops = { + .open = snd_cx88_pcm_open, + .close = snd_cx88_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cx88_hw_params, + .hw_free = snd_cx88_hw_free, + .prepare = snd_cx88_prepare, + .trigger = snd_cx88_card_trigger, + .pointer = snd_cx88_pointer, + .page = snd_cx88_page, +}; + +/* + * create a PCM device + */ +static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name) +{ + int err; + struct snd_pcm *pcm; + + err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); + if (err < 0) + return err; + pcm->private_data = chip; + strcpy(pcm->name, name); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops); + + return 0; +} + +/**************************************************************************** + CONTROL INTERFACE + ****************************************************************************/ +static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 0; + info->value.integer.max = 0x3f; + + return 0; +} + +static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_core *core=chip->core; + int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f), + bal = cx_read(AUD_BAL_CTL); + + value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol; + vol -= (bal & 0x3f); + value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol; + + return 0; +} + +static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_core *core = chip->core; + struct v4l2_control client_ctl; + int left = value->value.integer.value[0]; + int right = value->value.integer.value[1]; + int v, b; + + memset(&client_ctl, 0, sizeof(client_ctl)); + + /* Pass volume & balance onto any WM8775 */ + if (left >= right) { + v = left << 10; + b = left ? (0x8000 * right) / left : 0x8000; + } else { + v = right << 10; + b = right ? 0xffff - (0x8000 * left) / right : 0x8000; + } + client_ctl.value = v; + client_ctl.id = V4L2_CID_AUDIO_VOLUME; + call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); + + client_ctl.value = b; + client_ctl.id = V4L2_CID_AUDIO_BALANCE; + call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); +} + +/* OK - TODO: test it */ +static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_core *core=chip->core; + int left, right, v, b; + int changed = 0; + u32 old; + + if (core->board.audio_chip == V4L2_IDENT_WM8775) + snd_cx88_wm8775_volume_put(kcontrol, value); + + left = value->value.integer.value[0] & 0x3f; + right = value->value.integer.value[1] & 0x3f; + b = right - left; + if (b < 0) { + v = 0x3f - left; + b = (-b) | 0x40; + } else { + v = 0x3f - right; + } + /* Do we really know this will always be called with IRQs on? */ + spin_lock_irq(&chip->reg_lock); + old = cx_read(AUD_VOL_CTL); + if (v != (old & 0x3f)) { + cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v); + changed = 1; + } + if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) { + cx_write(AUD_BAL_CTL, b); + changed = 1; + } + spin_unlock_irq(&chip->reg_lock); + + return changed; +} + +static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0); + +static const struct snd_kcontrol_new snd_cx88_volume = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "Analog-TV Volume", + .info = snd_cx88_volume_info, + .get = snd_cx88_volume_get, + .put = snd_cx88_volume_put, + .tlv.p = snd_cx88_db_scale, +}; + +static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_core *core = chip->core; + u32 bit = kcontrol->private_value; + + value->value.integer.value[0] = !(cx_read(AUD_VOL_CTL) & bit); + return 0; +} + +static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_core *core = chip->core; + u32 bit = kcontrol->private_value; + int ret = 0; + u32 vol; + + spin_lock_irq(&chip->reg_lock); + vol = cx_read(AUD_VOL_CTL); + if (value->value.integer.value[0] != !(vol & bit)) { + vol ^= bit; + cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol); + /* Pass mute onto any WM8775 */ + if ((core->board.audio_chip == V4L2_IDENT_WM8775) && + ((1<<6) == bit)) { + struct v4l2_control client_ctl; + + memset(&client_ctl, 0, sizeof(client_ctl)); + client_ctl.value = 0 != (vol & bit); + client_ctl.id = V4L2_CID_AUDIO_MUTE; + call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); + } + ret = 1; + } + spin_unlock_irq(&chip->reg_lock); + return ret; +} + +static const struct snd_kcontrol_new snd_cx88_dac_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Audio-Out Switch", + .info = snd_ctl_boolean_mono_info, + .get = snd_cx88_switch_get, + .put = snd_cx88_switch_put, + .private_value = (1<<8), +}; + +static const struct snd_kcontrol_new snd_cx88_source_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog-TV Switch", + .info = snd_ctl_boolean_mono_info, + .get = snd_cx88_switch_get, + .put = snd_cx88_switch_put, + .private_value = (1<<6), +}; + +static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_core *core = chip->core; + struct v4l2_control client_ctl; + + memset(&client_ctl, 0, sizeof(client_ctl)); + client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; + call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl); + value->value.integer.value[0] = client_ctl.value ? 1 : 0; + + return 0; +} + +static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_core *core = chip->core; + struct v4l2_control client_ctl; + + memset(&client_ctl, 0, sizeof(client_ctl)); + client_ctl.value = 0 != value->value.integer.value[0]; + client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; + call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); + + return 0; +} + +static struct snd_kcontrol_new snd_cx88_alc_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line-In ALC Switch", + .info = snd_ctl_boolean_mono_info, + .get = snd_cx88_alc_get, + .put = snd_cx88_alc_put, +}; + +/**************************************************************************** + Basic Flow for Sound Devices + ****************************************************************************/ + +/* + * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio + * Only boards with eeprom and byte 1 at eeprom=1 have it + */ + +static const struct pci_device_id const cx88_audio_pci_tbl[] __devinitdata = { + {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {0, } +}; +MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl); + +/* + * Chip-specific destructor + */ + +static int snd_cx88_free(snd_cx88_card_t *chip) +{ + + if (chip->irq >= 0) + free_irq(chip->irq, chip); + + cx88_core_put(chip->core,chip->pci); + + pci_disable_device(chip->pci); + return 0; +} + +/* + * Component Destructor + */ +static void snd_cx88_dev_free(struct snd_card * card) +{ + snd_cx88_card_t *chip = card->private_data; + + snd_cx88_free(chip); +} + + +/* + * Alsa Constructor - Component probe + */ + +static int devno; +static int __devinit snd_cx88_create(struct snd_card *card, + struct pci_dev *pci, + snd_cx88_card_t **rchip, + struct cx88_core **core_ptr) +{ + snd_cx88_card_t *chip; + struct cx88_core *core; + int err; + unsigned char pci_lat; + + *rchip = NULL; + + err = pci_enable_device(pci); + if (err < 0) + return err; + + pci_set_master(pci); + + chip = card->private_data; + + core = cx88_core_get(pci); + if (NULL == core) { + err = -EINVAL; + return err; + } + + if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) { + dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); + err = -EIO; + cx88_core_put(core, pci); + return err; + } + + + /* pci init */ + chip->card = card; + chip->pci = pci; + chip->irq = -1; + spin_lock_init(&chip->reg_lock); + + chip->core = core; + + /* get irq */ + err = request_irq(chip->pci->irq, cx8801_irq, + IRQF_SHARED | IRQF_DISABLED, chip->core->name, chip); + if (err < 0) { + dprintk(0, "%s: can't get IRQ %d\n", + chip->core->name, chip->pci->irq); + return err; + } + + /* print pci info */ + pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat); + + dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%llx\n", core->name, devno, + pci_name(pci), pci->revision, pci->irq, + pci_lat, (unsigned long long)pci_resource_start(pci,0)); + + chip->irq = pci->irq; + synchronize_irq(chip->irq); + + snd_card_set_dev(card, &pci->dev); + + *rchip = chip; + *core_ptr = core; + + return 0; +} + +static int __devinit cx88_audio_initdev(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct snd_card *card; + snd_cx88_card_t *chip; + struct cx88_core *core = NULL; + int err; + + if (devno >= SNDRV_CARDS) + return (-ENODEV); + + if (!enable[devno]) { + ++devno; + return (-ENOENT); + } + + err = snd_card_create(index[devno], id[devno], THIS_MODULE, + sizeof(snd_cx88_card_t), &card); + if (err < 0) + return err; + + card->private_free = snd_cx88_dev_free; + + err = snd_cx88_create(card, pci, &chip, &core); + if (err < 0) + goto error; + + err = snd_cx88_pcm(chip, 0, "CX88 Digital"); + if (err < 0) + goto error; + + err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_volume, chip)); + if (err < 0) + goto error; + err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_dac_switch, chip)); + if (err < 0) + goto error; + err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_source_switch, chip)); + if (err < 0) + goto error; + + /* If there's a wm8775 then add a Line-In ALC switch */ + if (core->board.audio_chip == V4L2_IDENT_WM8775) + snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip)); + + strcpy (card->driver, "CX88x"); + sprintf(card->shortname, "Conexant CX%x", pci->device); + sprintf(card->longname, "%s at %#llx", + card->shortname,(unsigned long long)pci_resource_start(pci, 0)); + strcpy (card->mixername, "CX88"); + + dprintk (0, "%s/%i: ALSA support for cx2388x boards\n", + card->driver,devno); + + err = snd_card_register(card); + if (err < 0) + goto error; + pci_set_drvdata(pci,card); + + devno++; + return 0; + +error: + snd_card_free(card); + return err; +} +/* + * ALSA destructor + */ +static void __devexit cx88_audio_finidev(struct pci_dev *pci) +{ + struct cx88_audio_dev *card = pci_get_drvdata(pci); + + snd_card_free((void *)card); + + pci_set_drvdata(pci, NULL); + + devno--; +} + +/* + * PCI driver definition + */ + +static struct pci_driver cx88_audio_pci_driver = { + .name = "cx88_audio", + .id_table = cx88_audio_pci_tbl, + .probe = cx88_audio_initdev, + .remove = __devexit_p(cx88_audio_finidev), +}; + +/**************************************************************************** + LINUX MODULE INIT + ****************************************************************************/ + +/* + * module init + */ +static int __init cx88_audio_init(void) +{ + printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx88_audio_pci_driver); +} + +/* + * module remove + */ +static void __exit cx88_audio_fini(void) +{ + pci_unregister_driver(&cx88_audio_pci_driver); +} + +module_init(cx88_audio_init); +module_exit(cx88_audio_fini); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-blackbird.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-blackbird.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-blackbird.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-blackbird.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1399 @@ +/* + * + * Support for a cx23416 mpeg encoder via cx2388x host port. + * "blackbird" reference design. + * + * (c) 2004 Jelle Foks + * (c) 2004 Gerd Knorr + * + * (c) 2005-2006 Mauro Carvalho Chehab + * - video_ioctl2 conversion + * + * Includes parts from the ivtv driver + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx88.h" + +MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); +MODULE_AUTHOR("Jelle Foks , Gerd Knorr [SuSE Labs]"); +MODULE_LICENSE("GPL"); + +static unsigned int mpegbufs = 32; +module_param(mpegbufs,int,0644); +MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32"); + +static unsigned int debug; +module_param(debug,int,0644); +MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg) + + +/* ------------------------------------------------------------------ */ + +#define BLACKBIRD_FIRM_IMAGE_SIZE 376836 + +/* defines below are from ivtv-driver.h */ + +#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF + +/* Firmware API commands */ +#define IVTV_API_STD_TIMEOUT 500 + +enum blackbird_capture_type { + BLACKBIRD_MPEG_CAPTURE, + BLACKBIRD_RAW_CAPTURE, + BLACKBIRD_RAW_PASSTHRU_CAPTURE +}; +enum blackbird_capture_bits { + BLACKBIRD_RAW_BITS_NONE = 0x00, + BLACKBIRD_RAW_BITS_YUV_CAPTURE = 0x01, + BLACKBIRD_RAW_BITS_PCM_CAPTURE = 0x02, + BLACKBIRD_RAW_BITS_VBI_CAPTURE = 0x04, + BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08, + BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE = 0x10 +}; +enum blackbird_capture_end { + BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */ + BLACKBIRD_END_NOW, /* stop immediately, no irq */ +}; +enum blackbird_framerate { + BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */ + BLACKBIRD_FRAMERATE_PAL_25 /* PAL: 25fps */ +}; +enum blackbird_stream_port { + BLACKBIRD_OUTPUT_PORT_MEMORY, + BLACKBIRD_OUTPUT_PORT_STREAMING, + BLACKBIRD_OUTPUT_PORT_SERIAL +}; +enum blackbird_data_xfer_status { + BLACKBIRD_MORE_BUFFERS_FOLLOW, + BLACKBIRD_LAST_BUFFER, +}; +enum blackbird_picture_mask { + BLACKBIRD_PICTURE_MASK_NONE, + BLACKBIRD_PICTURE_MASK_I_FRAMES, + BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3, + BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7, +}; +enum blackbird_vbi_mode_bits { + BLACKBIRD_VBI_BITS_SLICED, + BLACKBIRD_VBI_BITS_RAW, +}; +enum blackbird_vbi_insertion_bits { + BLACKBIRD_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, + BLACKBIRD_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, + BLACKBIRD_VBI_BITS_SEPARATE_STREAM = 0x2 << 1, + BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, + BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, +}; +enum blackbird_dma_unit { + BLACKBIRD_DMA_BYTES, + BLACKBIRD_DMA_FRAMES, +}; +enum blackbird_dma_transfer_status_bits { + BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01, + BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04, + BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10, +}; +enum blackbird_pause { + BLACKBIRD_PAUSE_ENCODING, + BLACKBIRD_RESUME_ENCODING, +}; +enum blackbird_copyright { + BLACKBIRD_COPYRIGHT_OFF, + BLACKBIRD_COPYRIGHT_ON, +}; +enum blackbird_notification_type { + BLACKBIRD_NOTIFICATION_REFRESH, +}; +enum blackbird_notification_status { + BLACKBIRD_NOTIFICATION_OFF, + BLACKBIRD_NOTIFICATION_ON, +}; +enum blackbird_notification_mailbox { + BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1, +}; +enum blackbird_field1_lines { + BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */ + BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */ + BLACKBIRD_FIELD1_MICRONAS = 0x0105, /* 261 */ +}; +enum blackbird_field2_lines { + BLACKBIRD_FIELD2_SAA7114 = 0x00EF, /* 239 */ + BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */ + BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */ +}; +enum blackbird_custom_data_type { + BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, + BLACKBIRD_CUSTOM_PRIVATE_PACKET, +}; +enum blackbird_mute { + BLACKBIRD_UNMUTE, + BLACKBIRD_MUTE, +}; +enum blackbird_mute_video_mask { + BLACKBIRD_MUTE_VIDEO_V_MASK = 0x0000FF00, + BLACKBIRD_MUTE_VIDEO_U_MASK = 0x00FF0000, + BLACKBIRD_MUTE_VIDEO_Y_MASK = 0xFF000000, +}; +enum blackbird_mute_video_shift { + BLACKBIRD_MUTE_VIDEO_V_SHIFT = 8, + BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16, + BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24, +}; + +/* Registers */ +#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/) + +/* ------------------------------------------------------------------ */ + +static void host_setup(struct cx88_core *core) +{ + /* toggle reset of the host */ + cx_write(MO_GPHST_SOFT_RST, 1); + udelay(100); + cx_write(MO_GPHST_SOFT_RST, 0); + udelay(100); + + /* host port setup */ + cx_write(MO_GPHST_WSC, 0x44444444U); + cx_write(MO_GPHST_XFR, 0); + cx_write(MO_GPHST_WDTH, 15); + cx_write(MO_GPHST_HDSHK, 0); + cx_write(MO_GPHST_MUX16, 0x44448888U); + cx_write(MO_GPHST_MODE, 0); +} + +/* ------------------------------------------------------------------ */ + +#define P1_MDATA0 0x390000 +#define P1_MDATA1 0x390001 +#define P1_MDATA2 0x390002 +#define P1_MDATA3 0x390003 +#define P1_MADDR2 0x390004 +#define P1_MADDR1 0x390005 +#define P1_MADDR0 0x390006 +#define P1_RDATA0 0x390008 +#define P1_RDATA1 0x390009 +#define P1_RDATA2 0x39000A +#define P1_RDATA3 0x39000B +#define P1_RADDR0 0x39000C +#define P1_RADDR1 0x39000D +#define P1_RRDWR 0x39000E + +static int wait_ready_gpio0_bit1(struct cx88_core *core, u32 state) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1); + u32 gpio0,need; + + need = state ? 2 : 0; + for (;;) { + gpio0 = cx_read(MO_GP0_IO) & 2; + if (need == gpio0) + return 0; + if (time_after(jiffies,timeout)) + return -1; + udelay(1); + } +} + +static int memory_write(struct cx88_core *core, u32 address, u32 value) +{ + /* Warning: address is dword address (4 bytes) */ + cx_writeb(P1_MDATA0, (unsigned int)value); + cx_writeb(P1_MDATA1, (unsigned int)(value >> 8)); + cx_writeb(P1_MDATA2, (unsigned int)(value >> 16)); + cx_writeb(P1_MDATA3, (unsigned int)(value >> 24)); + cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) | 0x40); + cx_writeb(P1_MADDR1, (unsigned int)(address >> 8)); + cx_writeb(P1_MADDR0, (unsigned int)address); + cx_read(P1_MDATA0); + cx_read(P1_MADDR0); + + return wait_ready_gpio0_bit1(core,1); +} + +static int memory_read(struct cx88_core *core, u32 address, u32 *value) +{ + int retval; + u32 val; + + /* Warning: address is dword address (4 bytes) */ + cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) & ~0xC0); + cx_writeb(P1_MADDR1, (unsigned int)(address >> 8)); + cx_writeb(P1_MADDR0, (unsigned int)address); + cx_read(P1_MADDR0); + + retval = wait_ready_gpio0_bit1(core,1); + + cx_writeb(P1_MDATA3, 0); + val = (unsigned char)cx_read(P1_MDATA3) << 24; + cx_writeb(P1_MDATA2, 0); + val |= (unsigned char)cx_read(P1_MDATA2) << 16; + cx_writeb(P1_MDATA1, 0); + val |= (unsigned char)cx_read(P1_MDATA1) << 8; + cx_writeb(P1_MDATA0, 0); + val |= (unsigned char)cx_read(P1_MDATA0); + + *value = val; + return retval; +} + +static int register_write(struct cx88_core *core, u32 address, u32 value) +{ + cx_writeb(P1_RDATA0, (unsigned int)value); + cx_writeb(P1_RDATA1, (unsigned int)(value >> 8)); + cx_writeb(P1_RDATA2, (unsigned int)(value >> 16)); + cx_writeb(P1_RDATA3, (unsigned int)(value >> 24)); + cx_writeb(P1_RADDR0, (unsigned int)address); + cx_writeb(P1_RADDR1, (unsigned int)(address >> 8)); + cx_writeb(P1_RRDWR, 1); + cx_read(P1_RDATA0); + cx_read(P1_RADDR0); + + return wait_ready_gpio0_bit1(core,1); +} + + +static int register_read(struct cx88_core *core, u32 address, u32 *value) +{ + int retval; + u32 val; + + cx_writeb(P1_RADDR0, (unsigned int)address); + cx_writeb(P1_RADDR1, (unsigned int)(address >> 8)); + cx_writeb(P1_RRDWR, 0); + cx_read(P1_RADDR0); + + retval = wait_ready_gpio0_bit1(core,1); + val = (unsigned char)cx_read(P1_RDATA0); + val |= (unsigned char)cx_read(P1_RDATA1) << 8; + val |= (unsigned char)cx_read(P1_RDATA2) << 16; + val |= (unsigned char)cx_read(P1_RDATA3) << 24; + + *value = val; + return retval; +} + +/* ------------------------------------------------------------------ */ + +static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +{ + struct cx8802_dev *dev = priv; + unsigned long timeout; + u32 value, flag, retval; + int i; + + dprintk(1,"%s: 0x%X\n", __func__, command); + + /* this may not be 100% safe if we can't read any memory location + without side effects */ + memory_read(dev->core, dev->mailbox - 4, &value); + if (value != 0x12345678) { + dprintk(0, "Firmware and/or mailbox pointer not initialized or corrupted\n"); + return -1; + } + + memory_read(dev->core, dev->mailbox, &flag); + if (flag) { + dprintk(0, "ERROR: Mailbox appears to be in use (%x)\n", flag); + return -1; + } + + flag |= 1; /* tell 'em we're working on it */ + memory_write(dev->core, dev->mailbox, flag); + + /* write command + args + fill remaining with zeros */ + memory_write(dev->core, dev->mailbox + 1, command); /* command code */ + memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */ + for (i = 0; i < in; i++) { + memory_write(dev->core, dev->mailbox + 4 + i, data[i]); + dprintk(1, "API Input %d = %d\n", i, data[i]); + } + for (; i < CX2341X_MBOX_MAX_DATA; i++) + memory_write(dev->core, dev->mailbox + 4 + i, 0); + + flag |= 3; /* tell 'em we're done writing */ + memory_write(dev->core, dev->mailbox, flag); + + /* wait for firmware to handle the API command */ + timeout = jiffies + msecs_to_jiffies(10); + for (;;) { + memory_read(dev->core, dev->mailbox, &flag); + if (0 != (flag & 4)) + break; + if (time_after(jiffies,timeout)) { + dprintk(0, "ERROR: API Mailbox timeout\n"); + return -1; + } + udelay(10); + } + + /* read output values */ + for (i = 0; i < out; i++) { + memory_read(dev->core, dev->mailbox + 4 + i, data + i); + dprintk(1, "API Output %d = %d\n", i, data[i]); + } + + memory_read(dev->core, dev->mailbox + 2, &retval); + dprintk(1, "API result = %d\n",retval); + + flag = 0; + memory_write(dev->core, dev->mailbox, flag); + return retval; +} +/* ------------------------------------------------------------------ */ + +/* We don't need to call the API often, so using just one mailbox will probably suffice */ +static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command, + u32 inputcnt, u32 outputcnt, ...) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + va_list vargs; + int i, err; + + va_start(vargs, outputcnt); + + for (i = 0; i < inputcnt; i++) { + data[i] = va_arg(vargs, int); + } + err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data); + for (i = 0; i < outputcnt; i++) { + int *vptr = va_arg(vargs, int *); + *vptr = data[i]; + } + va_end(vargs); + return err; +} + +static int blackbird_find_mailbox(struct cx8802_dev *dev) +{ + u32 signature[4]={0x12345678, 0x34567812, 0x56781234, 0x78123456}; + int signaturecnt=0; + u32 value; + int i; + + for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) { + memory_read(dev->core, i, &value); + if (value == signature[signaturecnt]) + signaturecnt++; + else + signaturecnt = 0; + if (4 == signaturecnt) { + dprintk(1, "Mailbox signature found\n"); + return i+1; + } + } + dprintk(0, "Mailbox signature values not found!\n"); + return -1; +} + +static int blackbird_load_firmware(struct cx8802_dev *dev) +{ + static const unsigned char magic[8] = { + 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa + }; + const struct firmware *firmware; + int i, retval = 0; + u32 value = 0; + u32 checksum = 0; + u32 *dataptr; + + retval = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED); + retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); + retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640); + retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); + msleep(1); + retval |= register_write(dev->core, IVTV_REG_APU, 0); + + if (retval < 0) + dprintk(0, "Error with register_write\n"); + + retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME, + &dev->pci->dev); + + + if (retval != 0) { + dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n", + CX2341X_FIRM_ENC_FILENAME); + dprintk(0, "Please fix your hotplug setup, the board will " + "not work without firmware loaded!\n"); + return -1; + } + + if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) { + dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n", + firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE); + release_firmware(firmware); + return -1; + } + + if (0 != memcmp(firmware->data, magic, 8)) { + dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n"); + release_firmware(firmware); + return -1; + } + + /* transfer to the chip */ + dprintk(1,"Loading firmware ...\n"); + dataptr = (u32*)firmware->data; + for (i = 0; i < (firmware->size >> 2); i++) { + value = *dataptr; + checksum += ~value; + memory_write(dev->core, i, value); + dataptr++; + } + + /* read back to verify with the checksum */ + for (i--; i >= 0; i--) { + memory_read(dev->core, i, &value); + checksum -= ~value; + } + if (checksum) { + dprintk(0, "ERROR: Firmware load failed (checksum mismatch).\n"); + release_firmware(firmware); + return -1; + } + release_firmware(firmware); + dprintk(0, "Firmware upload successful.\n"); + + retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); + retval |= register_read(dev->core, IVTV_REG_SPU, &value); + retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE); + msleep(1); + + retval |= register_read(dev->core, IVTV_REG_VPU, &value); + retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8); + + if (retval < 0) + dprintk(0, "Error with register_write\n"); + return 0; +} + +/** + Settings used by the windows tv app for PVR2000: +================================================================================================================= +Profile | Codec | Resolution | CBR/VBR | Video Qlty | V. Bitrate | Frmrate | Audio Codec | A. Bitrate | A. Mode +----------------------------------------------------------------------------------------------------------------- +MPEG-1 | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 2000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo +MPEG-2 | MPEG2 | 720x576PAL | VBR | 600 :Good | 4000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo +VCD | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 1150 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo +DVD | MPEG2 | 720x576PAL | VBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo +DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo +================================================================================================================= +*DB: "DirectBurn" +*/ + +static void blackbird_codec_settings(struct cx8802_dev *dev) +{ + /* assign frame size */ + blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, + dev->height, dev->width); + + dev->params.width = dev->width; + dev->params.height = dev->height; + dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0; + + cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params); +} + +static int blackbird_initialize_codec(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + int version; + int retval; + + dprintk(1,"Initialize codec\n"); + retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ + if (retval < 0) { + + dev->mpeg_active = 0; + + /* ping was not successful, reset and upload firmware */ + cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */ + cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */ + retval = blackbird_load_firmware(dev); + if (retval < 0) + return retval; + + retval = blackbird_find_mailbox(dev); + if (retval < 0) + return -1; + + dev->mailbox = retval; + + retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ + if (retval < 0) { + dprintk(0, "ERROR: Firmware ping failed!\n"); + return -1; + } + + retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version); + if (retval < 0) { + dprintk(0, "ERROR: Firmware get encoder version failed!\n"); + return -1; + } + dprintk(0, "Firmware version is 0x%08x\n", version); + } + + cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */ + cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */ + cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */ + cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */ + + blackbird_codec_settings(dev); + + blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, + BLACKBIRD_FIELD1_SAA7115, + BLACKBIRD_FIELD2_SAA7115 + ); + + blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, + BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + return 0; +} + +static int blackbird_start_codec(struct file *file, void *priv) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + struct cx88_core *core = dev->core; + /* start capturing to the host interface */ + u32 reg; + + int i; + int lastchange = -1; + int lastval = 0; + + for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) { + reg = cx_read(AUD_STATUS); + + dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg); + if ((reg & 0x0F) != lastval) { + lastval = reg & 0x0F; + lastchange = i; + } + msleep(100); + } + + /* unmute audio source */ + cx_clear(AUD_VOL_CTL, (1 << 6)); + + blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0); + + /* initialize the video input */ + blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); + + /* start capturing to the host interface */ + blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, + BLACKBIRD_MPEG_CAPTURE, + BLACKBIRD_RAW_BITS_NONE + ); + + dev->mpeg_active = 1; + return 0; +} + +static int blackbird_stop_codec(struct cx8802_dev *dev) +{ + blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + BLACKBIRD_END_NOW, + BLACKBIRD_MPEG_CAPTURE, + BLACKBIRD_RAW_BITS_NONE + ); + + dev->mpeg_active = 0; + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int bb_buf_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct cx8802_fh *fh = q->priv_data; + + fh->dev->ts_packet_size = 188 * 4; /* was: 512 */ + fh->dev->ts_packet_count = mpegbufs; /* was: 100 */ + + *size = fh->dev->ts_packet_size * fh->dev->ts_packet_count; + *count = fh->dev->ts_packet_count; + return 0; +} + +static int +bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx8802_fh *fh = q->priv_data; + return cx8802_buf_prepare(q, fh->dev, (struct cx88_buffer*)vb, field); +} + +static void +bb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx8802_fh *fh = q->priv_data; + cx8802_buf_queue(fh->dev, (struct cx88_buffer*)vb); +} + +static void +bb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + cx88_free_buffer(q, (struct cx88_buffer*)vb); +} + +static struct videobuf_queue_ops blackbird_qops = { + .buf_setup = bb_buf_setup, + .buf_prepare = bb_buf_prepare, + .buf_queue = bb_buf_queue, + .buf_release = bb_buf_release, +}; + +/* ------------------------------------------------------------------ */ + +static const u32 *ctrl_classes[] = { + cx88_user_ctrls, + cx2341x_mpeg_ctrls, + NULL +}; + +static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qctrl) +{ + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (qctrl->id == 0) + return -EINVAL; + + /* Standard V4L2 controls */ + if (cx8800_ctrl_query(dev->core, qctrl) == 0) + return 0; + + /* MPEG V4L2 controls */ + if (cx2341x_ctrl_query(&dev->params, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; +} + +/* ------------------------------------------------------------------ */ +/* IOCTL Handlers */ + +static int vidioc_querymenu (struct file *file, void *priv, + struct v4l2_querymenu *qmenu) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + struct v4l2_queryctrl qctrl; + + qctrl.id = qmenu->id; + blackbird_queryctrl(dev, &qctrl); + return v4l2_ctrl_query_menu(qmenu, &qctrl, + cx2341x_ctrl_get_menu(&dev->params, qmenu->id)); +} + +static int vidioc_querycap (struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + struct cx88_core *core = dev->core; + + strcpy(cap->driver, "cx88_blackbird"); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); + cap->version = CX88_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (UNSET != core->board.tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + strlcpy(f->description, "MPEG", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_MPEG; + return 0; +} + +static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx8802_fh *fh = priv; + struct cx8802_dev *dev = fh->dev; + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */ + f->fmt.pix.colorspace = 0; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.field = fh->mpegq.field; + dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", + dev->width, dev->height, fh->mpegq.field ); + return 0; +} + +static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx8802_fh *fh = priv; + struct cx8802_dev *dev = fh->dev; + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; + f->fmt.pix.colorspace = 0; + dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", + dev->width, dev->height, fh->mpegq.field ); + return 0; +} + +static int vidioc_s_fmt_vid_cap (struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx8802_fh *fh = priv; + struct cx8802_dev *dev = fh->dev; + struct cx88_core *core = dev->core; + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; + f->fmt.pix.colorspace = 0; + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + fh->mpegq.field = f->fmt.pix.field; + cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); + blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, + f->fmt.pix.height, f->fmt.pix.width); + dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", + f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field ); + return 0; +} + +static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) +{ + struct cx8802_fh *fh = priv; + return (videobuf_reqbufs(&fh->mpegq, p)); +} + +static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx8802_fh *fh = priv; + return (videobuf_querybuf(&fh->mpegq, p)); +} + +static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx8802_fh *fh = priv; + return (videobuf_qbuf(&fh->mpegq, p)); +} + +static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx8802_fh *fh = priv; + return (videobuf_dqbuf(&fh->mpegq, p, + file->f_flags & O_NONBLOCK)); +} + +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx8802_fh *fh = priv; + return videobuf_streamon(&fh->mpegq); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx8802_fh *fh = priv; + return videobuf_streamoff(&fh->mpegq); +} + +static int vidioc_g_ext_ctrls (struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS); +} + +static int vidioc_s_ext_ctrls (struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + struct cx2341x_mpeg_params p; + int err; + + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + if (dev->mpeg_active) + blackbird_stop_codec(dev); + + p = dev->params; + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); + if (!err) { + err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); + dev->params = p; + } + return err; +} + +static int vidioc_try_ext_ctrls (struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + struct cx2341x_mpeg_params p; + int err; + + if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + p = dev->params; + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); + + return err; +} + +static int vidioc_s_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx8802_fh *fh = priv; + struct cx8802_dev *dev = fh->dev; + struct cx88_core *core = dev->core; + + if (dev->mpeg_active) + blackbird_stop_codec(dev); + + cx88_set_freq (core,f); + blackbird_initialize_codec(dev); + cx88_set_scale(dev->core, dev->width, dev->height, + fh->mpegq.field); + return 0; +} + +static int vidioc_log_status (struct file *file, void *priv) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + struct cx88_core *core = dev->core; + char name[32 + 2]; + + snprintf(name, sizeof(name), "%s/2", core->name); + printk("%s/2: ============ START LOG STATUS ============\n", + core->name); + call_all(core, core, log_status); + cx2341x_log_status(&dev->params, name); + printk("%s/2: ============= END LOG STATUS =============\n", + core->name); + return 0; +} + +static int vidioc_queryctrl (struct file *file, void *priv, + struct v4l2_queryctrl *qctrl) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + + if (blackbird_queryctrl(dev, qctrl) == 0) + return 0; + + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (unlikely(qctrl->id == 0)) + return -EINVAL; + return cx8800_ctrl_query(dev->core, qctrl); +} + +static int vidioc_enum_input (struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + return cx88_enum_input (core,i); +} + +static int vidioc_g_ctrl (struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + return + cx88_get_control(core,ctl); +} + +static int vidioc_s_ctrl (struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + return + cx88_set_control(core,ctl); +} + +static int vidioc_g_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx8802_fh *fh = priv; + struct cx88_core *core = fh->dev->core; + + if (unlikely(UNSET == core->board.tuner_type)) + return -EINVAL; + + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = core->freq; + call_all(core, tuner, g_frequency, f); + + return 0; +} + +static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + + *i = core->input; + return 0; +} + +static int vidioc_s_input (struct file *file, void *priv, unsigned int i) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + + if (i >= 4) + return -EINVAL; + + mutex_lock(&core->lock); + cx88_newstation(core); + cx88_video_mux(core,i); + mutex_unlock(&core->lock); + return 0; +} + +static int vidioc_g_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + u32 reg; + + if (unlikely(UNSET == core->board.tuner_type)) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; + + cx88_get_stereo(core ,t); + reg = cx_read(MO_DEVICE_STATUS); + t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; + return 0; +} + +static int vidioc_s_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + + if (UNSET == core->board.tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + cx88_set_stereo(core, t->audmode, 1); + return 0; +} + +static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + + mutex_lock(&core->lock); + cx88_set_tvnorm(core,*id); + mutex_unlock(&core->lock); + return 0; +} + +/* FIXME: cx88_ioctl_hook not implemented */ + +static int mpeg_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct cx8802_dev *dev = video_drvdata(file); + struct cx8802_fh *fh; + struct cx8802_driver *drv = NULL; + int err; + + dprintk( 1, "%s\n", __func__); + + mutex_lock(&dev->core->lock); + + /* Make sure we can acquire the hardware */ + drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); + if (!drv) { + dprintk(1, "%s: blackbird driver is not loaded\n", __func__); + mutex_unlock(&dev->core->lock); + return -ENODEV; + } + + err = drv->request_acquire(drv); + if (err != 0) { + dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err); + mutex_unlock(&dev->core->lock); + return err; + } + + if (!dev->core->mpeg_users && blackbird_initialize_codec(dev) < 0) { + drv->request_release(drv); + mutex_unlock(&dev->core->lock); + return -EINVAL; + } + dprintk(1, "open dev=%s\n", video_device_node_name(vdev)); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh),GFP_KERNEL); + if (NULL == fh) { + drv->request_release(drv); + mutex_unlock(&dev->core->lock); + return -ENOMEM; + } + file->private_data = fh; + fh->dev = dev; + + videobuf_queue_sg_init(&fh->mpegq, &blackbird_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct cx88_buffer), + fh, NULL); + + /* FIXME: locking against other video device */ + cx88_set_scale(dev->core, dev->width, dev->height, + fh->mpegq.field); + + dev->core->mpeg_users++; + mutex_unlock(&dev->core->lock); + return 0; +} + +static int mpeg_release(struct file *file) +{ + struct cx8802_fh *fh = file->private_data; + struct cx8802_dev *dev = fh->dev; + struct cx8802_driver *drv = NULL; + + mutex_lock(&dev->core->lock); + + if (dev->mpeg_active && dev->core->mpeg_users == 1) + blackbird_stop_codec(dev); + + cx8802_cancel_buffers(fh->dev); + /* stop mpeg capture */ + videobuf_stop(&fh->mpegq); + + videobuf_mmap_free(&fh->mpegq); + + file->private_data = NULL; + kfree(fh); + + /* Make sure we release the hardware */ + drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); + WARN_ON(!drv); + if (drv) + drv->request_release(drv); + + dev->core->mpeg_users--; + + mutex_unlock(&dev->core->lock); + + return 0; +} + +static ssize_t +mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +{ + struct cx8802_fh *fh = file->private_data; + struct cx8802_dev *dev = fh->dev; + + if (!dev->mpeg_active) + blackbird_start_codec(file, fh); + + return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, + file->f_flags & O_NONBLOCK); +} + +static unsigned int +mpeg_poll(struct file *file, struct poll_table_struct *wait) +{ + struct cx8802_fh *fh = file->private_data; + struct cx8802_dev *dev = fh->dev; + + if (!dev->mpeg_active) + blackbird_start_codec(file, fh); + + return videobuf_poll_stream(file, &fh->mpegq, wait); +} + +static int +mpeg_mmap(struct file *file, struct vm_area_struct * vma) +{ + struct cx8802_fh *fh = file->private_data; + + return videobuf_mmap_mapper(&fh->mpegq, vma); +} + +static const struct v4l2_file_operations mpeg_fops = +{ + .owner = THIS_MODULE, + .open = mpeg_open, + .release = mpeg_release, + .read = mpeg_read, + .poll = mpeg_poll, + .mmap = mpeg_mmap, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { + .vidioc_querymenu = vidioc_querymenu, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, + .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, + .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_log_status = vidioc_log_status, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_s_std = vidioc_s_std, +}; + +static struct video_device cx8802_mpeg_template = { + .name = "cx8802", + .fops = &mpeg_fops, + .ioctl_ops = &mpeg_ioctl_ops, + .tvnorms = CX88_NORMS, + .current_norm = V4L2_STD_NTSC_M, +}; + +/* ------------------------------------------------------------------ */ + +/* The CX8802 MPEG API will call this when we can use the hardware */ +static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + + switch (core->boardnr) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* By default, core setup will leave the cx22702 out of reset, on the bus. + * We left the hardware on power up with the cx22702 active. + * We're being given access to re-arrange the GPIOs. + * Take the bus off the cx22702 and put the cx23416 on it. + */ + /* Toggle reset on cx22702 leaving i2c active */ + cx_set(MO_GP0_IO, 0x00000080); + udelay(1000); + cx_clear(MO_GP0_IO, 0x00000080); + udelay(50); + cx_set(MO_GP0_IO, 0x00000080); + udelay(1000); + /* tri-state the cx22702 pins */ + cx_set(MO_GP0_IO, 0x00000004); + udelay(1000); + break; + default: + err = -ENODEV; + } + return err; +} + +/* The CX8802 MPEG API will call this when we need to release the hardware */ +static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + + switch (core->boardnr) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* Exit leaving the cx23416 on the bus */ + break; + default: + err = -ENODEV; + } + return err; +} + +static void blackbird_unregister_video(struct cx8802_dev *dev) +{ + if (dev->mpeg_dev) { + if (video_is_registered(dev->mpeg_dev)) + video_unregister_device(dev->mpeg_dev); + else + video_device_release(dev->mpeg_dev); + dev->mpeg_dev = NULL; + } +} + +static int blackbird_register_video(struct cx8802_dev *dev) +{ + int err; + + dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci, + &cx8802_mpeg_template,"mpeg"); + video_set_drvdata(dev->mpeg_dev, dev); + err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1); + if (err < 0) { + printk(KERN_INFO "%s/2: can't register mpeg device\n", + dev->core->name); + return err; + } + printk(KERN_INFO "%s/2: registered device %s [mpeg]\n", + dev->core->name, video_device_node_name(dev->mpeg_dev)); + return 0; +} + +/* ----------------------------------------------------------- */ + +static int cx8802_blackbird_probe(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + struct cx8802_dev *dev = core->dvbdev; + int err; + + dprintk( 1, "%s\n", __func__); + dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + core->boardnr, + core->name, + core->pci_bus, + core->pci_slot); + + err = -ENODEV; + if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD)) + goto fail_core; + + dev->width = 720; + dev->height = 576; + cx2341x_fill_defaults(&dev->params); + dev->params.port = CX2341X_PORT_STREAMING; + + cx8802_mpeg_template.current_norm = core->tvnorm; + + if (core->tvnorm & V4L2_STD_525_60) { + dev->height = 480; + } else { + dev->height = 576; + } + + /* blackbird stuff */ + printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n", + core->name); + host_setup(dev->core); + + blackbird_initialize_codec(dev); + blackbird_register_video(dev); + + /* initial device configuration: needed ? */ +// init_controls(core); + cx88_set_tvnorm(core,core->tvnorm); + cx88_video_mux(core,0); + + return 0; + + fail_core: + return err; +} + +static int cx8802_blackbird_remove(struct cx8802_driver *drv) +{ + /* blackbird */ + blackbird_unregister_video(drv->core->dvbdev); + + return 0; +} + +static struct cx8802_driver cx8802_blackbird_driver = { + .type_id = CX88_MPEG_BLACKBIRD, + .hw_access = CX8802_DRVCTL_SHARED, + .probe = cx8802_blackbird_probe, + .remove = cx8802_blackbird_remove, + .advise_acquire = cx8802_blackbird_advise_acquire, + .advise_release = cx8802_blackbird_advise_release, +}; + +static int __init blackbird_init(void) +{ + printk(KERN_INFO "cx2388x blackbird driver version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return cx8802_register_driver(&cx8802_blackbird_driver); +} + +static void __exit blackbird_fini(void) +{ + cx8802_unregister_driver(&cx8802_blackbird_driver); +} + +module_init(blackbird_init); +module_exit(blackbird_fini); + +module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644); +MODULE_PARM_DESC(debug,"enable debug messages [video]"); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-cards.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3699 @@ +/* + * + * device driver for Conexant 2388x based TV cards + * card-specific stuff. + * + * (c) 2003 Gerd Knorr [SuSE Labs] + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "cx88.h" +#include "tea5767.h" +#include "xc4000.h" + +static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; + +module_param_array(tuner, int, NULL, 0444); +module_param_array(radio, int, NULL, 0444); +module_param_array(card, int, NULL, 0444); + +MODULE_PARM_DESC(tuner,"tuner type"); +MODULE_PARM_DESC(radio,"radio tuner type"); +MODULE_PARM_DESC(card,"card type"); + +static unsigned int latency = UNSET; +module_param(latency,int,0444); +MODULE_PARM_DESC(latency,"pci latency timer"); + +static int disable_ir; +module_param(disable_ir, int, 0444); +MODULE_PARM_DESC(disable_ir, "Disable IR support"); + +#define info_printk(core, fmt, arg...) \ + printk(KERN_INFO "%s: " fmt, core->name , ## arg) + +#define warn_printk(core, fmt, arg...) \ + printk(KERN_WARNING "%s: " fmt, core->name , ## arg) + +#define err_printk(core, fmt, arg...) \ + printk(KERN_ERR "%s: " fmt, core->name , ## arg) + + +/* ------------------------------------------------------------------ */ +/* board config info */ + +/* If radio_type !=UNSET, radio_addr should be specified + */ + +static const struct cx88_board cx88_boards[] = { + [CX88_BOARD_UNKNOWN] = { + .name = "UNKNOWN/GENERIC", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE2, + .vmux = 1, + },{ + .type = CX88_VMUX_COMPOSITE3, + .vmux = 2, + },{ + .type = CX88_VMUX_COMPOSITE4, + .vmux = 3, + }}, + }, + [CX88_BOARD_HAUPPAUGE] = { + .name = "Hauppauge WinTV 34xxx models", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, // internal decoder + },{ + .type = CX88_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, // mono from tuner chip + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xff01, + }, + }, + [CX88_BOARD_GDI] = { + .name = "GDI Black Gold", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + }}, + }, + [CX88_BOARD_PIXELVIEW] = { + .name = "PixelView", + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, // internal decoder + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xff10, + }, + }, + [CX88_BOARD_ATI_WONDER_PRO] = { + .name = "ATI TV Wonder Pro", + .tuner_type = TUNER_PHILIPS_4IN1, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x03ff, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x03fe, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x03fe, + }}, + }, + [CX88_BOARD_WINFAST2000XP_EXPERT] = { + .name = "Leadtek Winfast 2000XP Expert", + .tuner_type = TUNER_PHILIPS_4IN1, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00F5e700, + .gpio1 = 0x00003004, + .gpio2 = 0x00F5e700, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00F5c700, + .gpio1 = 0x00003004, + .gpio2 = 0x00F5c700, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00F5c700, + .gpio1 = 0x00003004, + .gpio2 = 0x00F5c700, + .gpio3 = 0x02000000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00F5d700, + .gpio1 = 0x00003004, + .gpio2 = 0x00F5d700, + .gpio3 = 0x02000000, + }, + }, + [CX88_BOARD_AVERTV_STUDIO_303] = { + .name = "AverTV Studio 303 (M126)", + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio1 = 0xe09f, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio1 = 0xe05f, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio1 = 0xe05f, + }}, + .radio = { + .gpio1 = 0xe0df, + .type = CX88_RADIO, + }, + }, + [CX88_BOARD_MSI_TVANYWHERE_MASTER] = { + // added gpio values thanks to Michal + // values for PAL from DScaler + .name = "MSI TV-@nywhere Master", + .tuner_type = TUNER_MT2032, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x000040bf, + .gpio1 = 0x000080c0, + .gpio2 = 0x0000ff40, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x000040bf, + .gpio1 = 0x000080c0, + .gpio2 = 0x0000ff40, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x000040bf, + .gpio1 = 0x000080c0, + .gpio2 = 0x0000ff40, + }}, + .radio = { + .type = CX88_RADIO, + .vmux = 3, + .gpio0 = 0x000040bf, + .gpio1 = 0x000080c0, + .gpio2 = 0x0000ff20, + }, + }, + [CX88_BOARD_WINFAST_DV2000] = { + .name = "Leadtek Winfast DV2000", + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0035e700, + .gpio1 = 0x00003004, + .gpio2 = 0x0035e700, + .gpio3 = 0x02000000, + },{ + + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0035c700, + .gpio1 = 0x00003004, + .gpio2 = 0x0035c700, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0035c700, + .gpio1 = 0x0035c700, + .gpio2 = 0x02000000, + .gpio3 = 0x02000000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0035d700, + .gpio1 = 0x00007004, + .gpio2 = 0x0035d700, + .gpio3 = 0x02000000, + }, + }, + [CX88_BOARD_LEADTEK_PVR2000] = { + // gpio values for PAL version from regspy by DScaler + .name = "Leadtek PVR 2000", + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0000bde2, + .audioroute = 1, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0000bde6, + .audioroute = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0000bde6, + .audioroute = 1, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0000bd62, + .audioroute = 1, + }, + .mpeg = CX88_MPEG_BLACKBIRD, + }, + [CX88_BOARD_IODATA_GVVCP3PCI] = { + .name = "IODATA GV-VCP3/PCI", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE2, + .vmux = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + }}, + }, + [CX88_BOARD_PROLINK_PLAYTVPVR] = { + .name = "Prolink PlayTV PVR", + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xbff0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xbff3, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xbff3, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xbff0, + }, + }, + [CX88_BOARD_ASUS_PVR_416] = { + .name = "ASUS PVR-416", + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0000fde6, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? + .audioroute = 1, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0000fde2, + }, + .mpeg = CX88_MPEG_BLACKBIRD, + }, + [CX88_BOARD_MSI_TVANYWHERE] = { + .name = "MSI TV-@nywhere", + .tuner_type = TUNER_MT2032, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00000fbf, + .gpio2 = 0x0000fc08, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00000fbf, + .gpio2 = 0x0000fc68, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00000fbf, + .gpio2 = 0x0000fc68, + }}, + }, + [CX88_BOARD_KWORLD_DVB_T] = { + .name = "KWorld/VStream XPert DVB-T", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = { + .name = "DViCO FusionHDTV DVB-T1", + .tuner_type = TUNER_ABSENT, /* No analog tuner */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x000027df, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x000027df, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_KWORLD_LTV883] = { + .name = "KWorld LTV883RF", + .tuner_type = TUNER_TNF_8831BGFF, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x07f8, + },{ + .type = CX88_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0x07f9, // mono from tuner chip + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x000007fa, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x000007fa, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x000007f8, + }, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = { + .name = "DViCO FusionHDTV 3 Gold-Q", + .tuner_type = TUNER_MICROTUNE_4042FI5, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + /* + GPIO[0] resets DT3302 DTV receiver + 0 - reset asserted + 1 - normal operation + GPIO[1] mutes analog audio output connector + 0 - enable selected source + 1 - mute + GPIO[2] selects source for analog audio output connector + 0 - analog audio input connector on tab + 1 - analog DAC output from CX23881 chip + GPIO[3] selects RF input connector on tuner module + 0 - RF connector labeled CABLE + 1 - RF connector labeled ANT + GPIO[4] selects high RF for QAM256 mode + 0 - normal RF + 1 - high RF + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0f0d, + },{ + .type = CX88_VMUX_CABLE, + .vmux = 0, + .gpio0 = 0x0f05, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0f00, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0f00, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_HAUPPAUGE_DVB_T1] = { + .name = "Hauppauge Nova-T DVB-T", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_CONEXANT_DVB_T1] = { + .name = "Conexant DVB-T reference design", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_PROVIDEO_PV259] = { + .name = "Provideo PV259", + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .audioroute = 1, + }}, + .mpeg = CX88_MPEG_BLACKBIRD, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = { + .name = "DViCO FusionHDTV DVB-T Plus", + .tuner_type = TUNER_ABSENT, /* No analog tuner */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x000027df, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x000027df, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_DNTV_LIVE_DVB_T] = { + .name = "digitalnow DNTV Live! DVB-T", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00000700, + .gpio2 = 0x00000101, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00000700, + .gpio2 = 0x00000101, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_PCHDTV_HD3000] = { + .name = "pcHDTV HD3000 HDTV", + .tuner_type = TUNER_THOMSON_DTT761X, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + /* GPIO[2] = audio source for analog audio out connector + * 0 = analog audio input connector + * 1 = CX88 audio DACs + * + * GPIO[7] = input to CX88's audio/chroma ADC + * 0 = FM 10.7 MHz IF + * 1 = Sound 4.5 MHz IF + * + * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively + * + * GPIO[16] = Remote control input + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00008484, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00008400, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00008400, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00008404, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_HAUPPAUGE_ROSLYN] = { + // entry added by Kaustubh D. Bhalerao + // GPIO values obtained from regspy, courtesy Sean Covel + .name = "Hauppauge WinTV 28xxx (Roslyn) models", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xed1a, + .gpio2 = 0x00ff, + },{ + .type = CX88_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xed92, + .gpio2 = 0x00ff, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xed96, + .gpio2 = 0x00ff, + }, + .mpeg = CX88_MPEG_BLACKBIRD, + }, + [CX88_BOARD_DIGITALLOGIC_MEC] = { + .name = "Digital-Logic MICROSPACE Entertainment Center (MEC)", + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00009d80, + .audioroute = 1, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00009d76, + .audioroute = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00009d76, + .audioroute = 1, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00009d00, + .audioroute = 1, + }, + .mpeg = CX88_MPEG_BLACKBIRD, + }, + [CX88_BOARD_IODATA_GVBCTV7E] = { + .name = "IODATA GV/BCTV7E", + .tuner_type = TUNER_PHILIPS_FQ1286, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 1, + .gpio1 = 0x0000e03f, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 2, + .gpio1 = 0x0000e07f, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 3, + .gpio1 = 0x0000e07f, + }} + }, + [CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = { + .name = "PixelView PlayTV Ultra Pro (Stereo)", + /* May be also TUNER_YMEC_TVF_5533MF for NTSC/M or PAL/M */ + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + /* Some variants use a tda9874 and so need the tvaudio module. */ + .audio_chip = V4L2_IDENT_TVAUDIO, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xbf61, /* internal decoder */ + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xbf63, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xbf63, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xbf60, + }, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = { + .name = "DViCO FusionHDTV 3 Gold-T", + .tuner_type = TUNER_THOMSON_DTT761X, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x97ed, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x97e9, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x97e9, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_ADSTECH_DVB_T_PCI] = { + .name = "ADS Tech Instant TV DVB-T PCI", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = { + .name = "TerraTec Cinergy 1400 DVB-T", + .tuner_type = TUNER_ABSENT, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 2, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = { + .name = "DViCO FusionHDTV 5 Gold", + .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H062F */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x87fd, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x87f9, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x87f9, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = { + .name = "AverMedia UltraTV Media Center PCI 550", + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 0, + .gpio0 = 0x0000cd73, + .audioroute = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 1, + .gpio0 = 0x0000cd73, + .audioroute = 1, + },{ + .type = CX88_VMUX_TELEVISION, + .vmux = 3, + .gpio0 = 0x0000cdb3, + .audioroute = 1, + }}, + .radio = { + .type = CX88_RADIO, + .vmux = 2, + .gpio0 = 0x0000cdf3, + .audioroute = 1, + }, + .mpeg = CX88_MPEG_BLACKBIRD, + }, + [CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = { + /* Alexander Wold */ + .name = "Kworld V-Stream Xpert DVD", + .tuner_type = UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x03000000, + .gpio1 = 0x01000000, + .gpio2 = 0x02000000, + .gpio3 = 0x00100000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x03000000, + .gpio1 = 0x01000000, + .gpio2 = 0x02000000, + .gpio3 = 0x00100000, + }}, + }, + [CX88_BOARD_ATI_HDTVWONDER] = { + .name = "ATI HDTV Wonder", + .tuner_type = TUNER_PHILIPS_TUV1236D, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00000ff7, + .gpio1 = 0x000000ff, + .gpio2 = 0x00000001, + .gpio3 = 0x00000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00000ffe, + .gpio1 = 0x000000ff, + .gpio2 = 0x00000001, + .gpio3 = 0x00000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00000ffe, + .gpio1 = 0x000000ff, + .gpio2 = 0x00000001, + .gpio3 = 0x00000000, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_WINFAST_DTV1000] = { + .name = "WinFast DTV1000-T", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_AVERTV_303] = { + .name = "AVerTV 303 (M126)", + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00ff, + .gpio1 = 0xe09f, + .gpio2 = 0x0010, + .gpio3 = 0x0000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00ff, + .gpio1 = 0xe05f, + .gpio2 = 0x0010, + .gpio3 = 0x0000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00ff, + .gpio1 = 0xe05f, + .gpio2 = 0x0010, + .gpio3 = 0x0000, + }}, + }, + [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = { + .name = "Hauppauge Nova-S-Plus DVB-S", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .audio_chip = V4L2_IDENT_WM8775, + .i2sinputcntl = 2, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + /* 2: Line-In */ + .audioroute = 2, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + /* 2: Line-In */ + .audioroute = 2, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + /* 2: Line-In */ + .audioroute = 2, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = { + .name = "Hauppauge Nova-SE2 DVB-S", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_KWORLD_DVBS_100] = { + .name = "KWorld DVB-S 100", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .audio_chip = V4L2_IDENT_WM8775, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + /* 2: Line-In */ + .audioroute = 2, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + /* 2: Line-In */ + .audioroute = 2, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + /* 2: Line-In */ + .audioroute = 2, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_HAUPPAUGE_HVR1100] = { + .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + }}, + /* fixme: Add radio support */ + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_HAUPPAUGE_HVR1100LP] = { + .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + }}, + /* fixme: Add radio support */ + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_DNTV_LIVE_DVB_T_PRO] = { + .name = "digitalnow DNTV Live! DVB-T Pro", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xf80808, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xf80808, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xf80808, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xf80808, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_KWORLD_DVB_T_CX22702] = { + /* Kworld V-stream Xpert DVB-T with Thomson tuner */ + /* DTT 7579 Conexant CX22702-19 Conexant CX2388x */ + /* Manenti Marco */ + .name = "KWorld/VStream XPert DVB-T with cx22702", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = { + .name = "DViCO FusionHDTV DVB-T Dual Digital", + .tuner_type = TUNER_ABSENT, /* No analog tuner */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x000067df, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x000067df, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = { + .name = "KWorld HardwareMpegTV XPert", + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x3de2, + .gpio2 = 0x00ff, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x3de6, + .audioroute = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x3de6, + .audioroute = 1, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x3de6, + .gpio2 = 0x00ff, + }, + .mpeg = CX88_MPEG_BLACKBIRD, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = { + .name = "DViCO FusionHDTV DVB-T Hybrid", + .tuner_type = TUNER_THOMSON_FE6600, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0000a75f, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0000a75b, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0000a75b, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_PCHDTV_HD5500] = { + .name = "pcHDTV HD5500 HDTV", + .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x87fd, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x87f9, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x87f9, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_KWORLD_MCE200_DELUXE] = { + /* FIXME: tested TV input only, disabled composite, + svideo and radio until they can be tested also. */ + .name = "Kworld MCE 200 Deluxe", + .tuner_type = TUNER_TENA_9533_DI, + .radio_type = UNSET, + .tda9887_conf = TDA9887_PRESENT, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0000BDE6 + }}, + .mpeg = CX88_MPEG_BLACKBIRD, + }, + [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = { + /* FIXME: SVideo, Composite and FM inputs are untested */ + .name = "PixelView PlayTV P7000", + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x5da6, + }}, + .mpeg = CX88_MPEG_BLACKBIRD, + }, + [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = { + .name = "NPG Tech Real TV FM Top 10", + .tuner_type = TUNER_TNF_5335MF, /* Actually a TNF9535 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0788, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x078b, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x078b, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x074a, + }, + }, + [CX88_BOARD_WINFAST_DTV2000H] = { + .name = "WinFast DTV2000 H", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00017304, + .gpio1 = 0x00008203, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0001d701, + .gpio1 = 0x0000b207, + .gpio2 = 0x0001d701, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_COMPOSITE2, + .vmux = 2, + .gpio0 = 0x0001d503, + .gpio1 = 0x0000b207, + .gpio2 = 0x0001d503, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 3, + .gpio0 = 0x0001d701, + .gpio1 = 0x0000b207, + .gpio2 = 0x0001d701, + .gpio3 = 0x02000000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00015702, + .gpio1 = 0x0000f207, + .gpio2 = 0x00015702, + .gpio3 = 0x02000000, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_WINFAST_DTV2000H_J] = { + .name = "WinFast DTV2000 H rev. J", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00017300, + .gpio1 = 0x00008207, + .gpio2 = 0x00000000, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00018300, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00018301, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00018301, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00015702, + .gpio1 = 0x0000f207, + .gpio2 = 0x00015702, + .gpio3 = 0x02000000, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_GENIATECH_DVBS] = { + .name = "Geniatech DVB-S", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_HAUPPAUGE_HVR3000] = { + .name = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .audio_chip = V4L2_IDENT_WM8775, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x84bf, + /* 1: TV Audio / FM Mono */ + .audioroute = 1, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x84bf, + /* 2: Line-In */ + .audioroute = 2, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x84bf, + /* 2: Line-In */ + .audioroute = 2, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x84bf, + /* 4: FM Stereo (untested) */ + .audioroute = 8, + }, + .mpeg = CX88_MPEG_DVB, + .num_frontends = 2, + }, + [CX88_BOARD_NORWOOD_MICRO] = { + .name = "Norwood Micro TV Tuner", + .tuner_type = TUNER_TNF_5335MF, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0709, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x070b, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x070b, + }}, + }, + [CX88_BOARD_TE_DTV_250_OEM_SWANN] = { + .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM", + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x003fffff, + .gpio1 = 0x00e00000, + .gpio2 = 0x003fffff, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x003fffff, + .gpio1 = 0x00e00000, + .gpio2 = 0x003fffff, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x003fffff, + .gpio1 = 0x00e00000, + .gpio2 = 0x003fffff, + .gpio3 = 0x02000000, + }}, + }, + [CX88_BOARD_HAUPPAUGE_HVR1300] = { + .name = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .audio_chip = V4L2_IDENT_WM8775, + /* + * gpio0 as reported by Mike Crash + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xef88, + /* 1: TV Audio / FM Mono */ + .audioroute = 1, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xef88, + /* 2: Line-In */ + .audioroute = 2, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xef88, + /* 2: Line-In */ + .audioroute = 2, + }}, + .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xef88, + /* 4: FM Stereo (untested) */ + .audioroute = 8, + }, + }, + [CX88_BOARD_SAMSUNG_SMT_7020] = { + .name = "Samsung SMT 7020 DVB-S", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = { { + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_ADSTECH_PTV_390] = { + .name = "ADS Tech Instant Video PCI", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DEBUG, + .vmux = 3, + .gpio0 = 0x04ff, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x07fa, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x07fa, + }}, + }, + [CX88_BOARD_PINNACLE_PCTV_HD_800i] = { + .name = "Pinnacle PCTV HD 800i", + .tuner_type = TUNER_XC5000, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x04fb, + .gpio1 = 0x10ff, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x04fb, + .gpio1 = 0x10ef, + .audioroute = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x04fb, + .gpio1 = 0x10ef, + .audioroute = 1, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = { + .name = "DViCO FusionHDTV 5 PCI nano", + /* xc3008 tuner, digital only for now */ + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x000027df, /* Unconfirmed */ + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x000027df, /* Unconfirmed */ + .audioroute = 1, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x000027df, /* Unconfirmed */ + .audioroute = 1, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_PINNACLE_HYBRID_PCTV] = { + .name = "Pinnacle Hybrid PCTV", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .radio_type = TUNER_XC2028, + .radio_addr = 0x61, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x004ff, + .gpio1 = 0x010ff, + .gpio2 = 0x00001, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x004fb, + .gpio1 = 0x010ef, + .audioroute = 1, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x004fb, + .gpio1 = 0x010ef, + .audioroute = 1, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x004ff, + .gpio1 = 0x010ff, + .gpio2 = 0x0ff, + }, + .mpeg = CX88_MPEG_DVB, + }, + /* Terry Wu */ + /* TV Audio : set GPIO 2, 18, 19 value to 0, 1, 0 */ + /* FM Audio : set GPIO 2, 18, 19 value to 0, 0, 0 */ + /* Line-in Audio : set GPIO 2, 18, 19 value to 0, 1, 1 */ + /* Mute Audio : set GPIO 2 value to 1 */ + [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = { + .name = "Leadtek TV2000 XP Global", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .radio_type = TUNER_XC2028, + .radio_addr = 0x61, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C04, /* pin 18 = 1, pin 19 = 0 */ + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ + .gpio3 = 0x0000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C00, /* pin 18 = 0, pin 19 = 0 */ + .gpio3 = 0x0000, + }, + }, + [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = { + .name = "PowerColor RA330", /* Long names may confuse LIRC. */ + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .input = { { + .type = CX88_VMUX_DEBUG, + .vmux = 3, /* Due to the way the cx88 driver is written, */ + .gpio0 = 0x00ff, /* there is no way to deactivate audio pass- */ + .gpio1 = 0xf39d, /* through without this entry. Furthermore, if */ + .gpio3 = 0x0000, /* the TV mux entry is first, you get audio */ + }, { /* from the tuner on boot for a little while. */ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00ff, + .gpio1 = 0xf35d, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00ff, + .gpio1 = 0xf37d, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x000ff, + .gpio1 = 0x0f37d, + .gpio3 = 0x00000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x000ff, + .gpio1 = 0x0f35d, + .gpio3 = 0x00000, + }, + }, + [CX88_BOARD_GENIATECH_X8000_MT] = { + /* Also PowerColor Real Angel 330 and Geniatech X800 OEM */ + .name = "Geniatech X8000-MT DVBT", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00000000, + .gpio1 = 0x00e3e341, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00000000, + .gpio1 = 0x00e3e361, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00000000, + .gpio1 = 0x00e3e361, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00000000, + .gpio1 = 0x00e3e341, + .gpio2 = 0x00000000, + .gpio3 = 0x00000000, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO] = { + .name = "DViCO FusionHDTV DVB-T PRO", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, + .input = { { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x000067df, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x000067df, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD] = { + .name = "DViCO FusionHDTV 7 Gold", + .tuner_type = TUNER_XC5000, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x10df, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x16d9, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x16d9, + }}, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_PROLINK_PV_8000GT] = { + .name = "Prolink Pixelview MPEG 8000GT", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0ff, + .gpio2 = 0x0cfb, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio2 = 0x0cfb, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio2 = 0x0cfb, + } }, + .radio = { + .type = CX88_RADIO, + .gpio2 = 0x0cfb, + }, + }, + [CX88_BOARD_PROLINK_PV_GLOBAL_XTREME] = { + .name = "Prolink Pixelview Global Extreme", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x04fb, + .gpio1 = 0x04080, + .gpio2 = 0x0cf7, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x04fb, + .gpio1 = 0x04080, + .gpio2 = 0x0cfb, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x04fb, + .gpio1 = 0x04080, + .gpio2 = 0x0cfb, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x04ff, + .gpio1 = 0x04080, + .gpio2 = 0x0cf7, + }, + }, + /* Both radio, analog and ATSC work with this board. + However, for analog to work, s5h1409 gate should be open, + otherwise, tuner-xc3028 won't be detected. + A proper fix require using the newer i2c methods to add + tuner-xc3028 without doing an i2c probe. + */ + [CX88_BOARD_KWORLD_ATSC_120] = { + .name = "Kworld PlusTV HD PCI 120 (ATSC 120)", + .tuner_type = TUNER_XC2028, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x000000ff, + .gpio1 = 0x0000f35d, + .gpio2 = 0x00000000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x000000ff, + .gpio1 = 0x0000f37e, + .gpio2 = 0x00000000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x000000ff, + .gpio1 = 0x0000f37e, + .gpio2 = 0x00000000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x000000ff, + .gpio1 = 0x0000f35d, + .gpio2 = 0x00000000, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_HAUPPAUGE_HVR4000] = { + .name = "Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .audio_chip = V4L2_IDENT_WM8775, + /* + * GPIO0 (WINTV2000) + * + * Analogue SAT DVB-T + * Antenna 0xc4bf 0xc4bb + * Composite 0xc4bf 0xc4bb + * S-Video 0xc4bf 0xc4bb + * Composite1 0xc4ff 0xc4fb + * S-Video1 0xc4ff 0xc4fb + * + * BIT VALUE FUNCTION GP{x}_IO + * 0 1 I:? + * 1 1 I:? + * 2 1 O:MPEG PORT 0=DVB-T 1=DVB-S + * 3 1 I:? + * 4 1 I:? + * 5 1 I:? + * 6 0 O:INPUT SELECTOR 0=INTERNAL 1=EXPANSION + * 7 1 O:DVB-T DEMOD RESET LOW + * + * BIT VALUE FUNCTION GP{x}_OE + * 8 0 I + * 9 0 I + * a 1 O + * b 0 I + * c 0 I + * d 0 I + * e 1 O + * f 1 O + * + * WM8775 ADC + * + * 1: TV Audio / FM Mono + * 2: Line-In + * 3: Line-In Expansion + * 4: FM Stereo + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xc4bf, + /* 1: TV Audio / FM Mono */ + .audioroute = 1, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xc4bf, + /* 2: Line-In */ + .audioroute = 2, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xc4bf, + /* 2: Line-In */ + .audioroute = 2, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xc4bf, + /* 4: FM Stereo */ + .audioroute = 8, + }, + .mpeg = CX88_MPEG_DVB, + .num_frontends = 2, + }, + [CX88_BOARD_HAUPPAUGE_HVR4000LITE] = { + .name = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TEVII_S420] = { + .name = "TeVii S420 DVB-S", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TEVII_S460] = { + .name = "TeVii S460 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TEVII_S464] = { + .name = "TeVii S464 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_OMICOM_SS4_PCI] = { + .name = "Omicom SS4 DVB-S/S2 PCI", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TBS_8910] = { + .name = "TBS 8910 DVB-S", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TBS_8920] = { + .name = "TBS 8920 DVB-S/S2", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + .gpio0 = 0x8080, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_PROF_6200] = { + .name = "Prof 6200 DVB-S", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_PROF_7300] = { + .name = "PROF 7300 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_SATTRADE_ST4200] = { + .name = "SATTRADE ST4200 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII] = { + .name = "Terratec Cinergy HT PCI MKII", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .radio_type = TUNER_XC2028, + .radio_addr = 0x61, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x004ff, + .gpio1 = 0x010ff, + .gpio2 = 0x00001, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x004fb, + .gpio1 = 0x010ef, + .audioroute = 1, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x004fb, + .gpio1 = 0x010ef, + .audioroute = 1, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x004ff, + .gpio1 = 0x010ff, + .gpio2 = 0x0ff, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_HAUPPAUGE_IRONLY] = { + .name = "Hauppauge WinTV-IR Only", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, + [CX88_BOARD_WINFAST_DTV1800H] = { + .name = "Leadtek WinFast DTV1800 Hybrid", + .tuner_type = TUNER_XC2028, + .radio_type = TUNER_XC2028, + .tuner_addr = 0x61, + .radio_addr = 0x61, + /* + * GPIO setting + * + * 2: mute (0=off,1=on) + * 12: tuner reset pin + * 13: audio source (0=tuner audio,1=line in) + * 14: FM (0=on,1=off ???) + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6040, /* pin 13 = 0, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6000, /* pin 13 = 0, pin 14 = 0 */ + .gpio2 = 0x0000, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_WINFAST_DTV1800H_XC4000] = { + .name = "Leadtek WinFast DTV1800 H (XC4000)", + .tuner_type = TUNER_XC4000, + .radio_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_addr = 0x61, + /* + * GPIO setting + * + * 2: mute (0=off,1=on) + * 12: tuner reset pin + * 13: audio source (0=tuner audio,1=line in) + * 14: FM (0=on,1=off ???) + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6040, /* pin 13 = 0, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6000, /* pin 13 = 0, pin 14 = 0 */ + .gpio2 = 0x0000, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_WINFAST_DTV2000H_PLUS] = { + .name = "Leadtek WinFast DTV2000 H PLUS", + .tuner_type = TUNER_XC4000, + .radio_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_addr = 0x61, + /* + * GPIO + * 2: 1: mute audio + * 12: 0: reset XC4000 + * 13: 1: audio input is line in (0: tuner) + * 14: 0: FM radio + * 16: 0: RF input is cable + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0403, + .gpio1 = 0xF0D7, + .gpio2 = 0x0101, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_CABLE, + .vmux = 0, + .gpio0 = 0x0403, + .gpio1 = 0xF0D7, + .gpio2 = 0x0100, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0403, /* was 0x0407 */ + .gpio1 = 0xF0F7, + .gpio2 = 0x0101, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0403, /* was 0x0407 */ + .gpio1 = 0xF0F7, + .gpio2 = 0x0101, + .gpio3 = 0x0000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0403, + .gpio1 = 0xF097, + .gpio2 = 0x0100, + .gpio3 = 0x0000, + }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_PROF_7301] = { + .name = "Prof 7301 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = { { + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TWINHAN_VP1027_DVBS] = { + .name = "Twinhan VP-1027 DVB-S", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, +}; + +/* ------------------------------------------------------------------ */ +/* PCI subsystem IDs */ + +static const struct cx88_subid cx88_subids[] = { + { + .subvendor = 0x0070, + .subdevice = 0x3400, + .card = CX88_BOARD_HAUPPAUGE, + },{ + .subvendor = 0x0070, + .subdevice = 0x3401, + .card = CX88_BOARD_HAUPPAUGE, + },{ + .subvendor = 0x14c7, + .subdevice = 0x0106, + .card = CX88_BOARD_GDI, + },{ + .subvendor = 0x14c7, + .subdevice = 0x0107, /* with mpeg encoder */ + .card = CX88_BOARD_GDI, + },{ + .subvendor = PCI_VENDOR_ID_ATI, + .subdevice = 0x00f8, + .card = CX88_BOARD_ATI_WONDER_PRO, + }, { + .subvendor = PCI_VENDOR_ID_ATI, + .subdevice = 0x00f9, + .card = CX88_BOARD_ATI_WONDER_PRO, + }, { + .subvendor = 0x107d, + .subdevice = 0x6611, + .card = CX88_BOARD_WINFAST2000XP_EXPERT, + },{ + .subvendor = 0x107d, + .subdevice = 0x6613, /* NTSC */ + .card = CX88_BOARD_WINFAST2000XP_EXPERT, + },{ + .subvendor = 0x107d, + .subdevice = 0x6620, + .card = CX88_BOARD_WINFAST_DV2000, + },{ + .subvendor = 0x107d, + .subdevice = 0x663b, + .card = CX88_BOARD_LEADTEK_PVR2000, + },{ + .subvendor = 0x107d, + .subdevice = 0x663c, + .card = CX88_BOARD_LEADTEK_PVR2000, + },{ + .subvendor = 0x1461, + .subdevice = 0x000b, + .card = CX88_BOARD_AVERTV_STUDIO_303, + },{ + .subvendor = 0x1462, + .subdevice = 0x8606, + .card = CX88_BOARD_MSI_TVANYWHERE_MASTER, + },{ + .subvendor = 0x10fc, + .subdevice = 0xd003, + .card = CX88_BOARD_IODATA_GVVCP3PCI, + },{ + .subvendor = 0x1043, + .subdevice = 0x4823, /* with mpeg encoder */ + .card = CX88_BOARD_ASUS_PVR_416, + },{ + .subvendor = 0x17de, + .subdevice = 0x08a6, + .card = CX88_BOARD_KWORLD_DVB_T, + },{ + .subvendor = 0x18ac, + .subdevice = 0xd810, + .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, + },{ + .subvendor = 0x18ac, + .subdevice = 0xd820, + .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T, + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb00, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1, + },{ + .subvendor = 0x0070, + .subdevice = 0x9002, + .card = CX88_BOARD_HAUPPAUGE_DVB_T1, + },{ + .subvendor = 0x14f1, + .subdevice = 0x0187, + .card = CX88_BOARD_CONEXANT_DVB_T1, + },{ + .subvendor = 0x1540, + .subdevice = 0x2580, + .card = CX88_BOARD_PROVIDEO_PV259, + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb10, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, + },{ + .subvendor = 0x1554, + .subdevice = 0x4811, + .card = CX88_BOARD_PIXELVIEW, + },{ + .subvendor = 0x7063, + .subdevice = 0x3000, /* HD-3000 card */ + .card = CX88_BOARD_PCHDTV_HD3000, + },{ + .subvendor = 0x17de, + .subdevice = 0xa8a6, + .card = CX88_BOARD_DNTV_LIVE_DVB_T, + },{ + .subvendor = 0x0070, + .subdevice = 0x2801, + .card = CX88_BOARD_HAUPPAUGE_ROSLYN, + },{ + .subvendor = 0x14f1, + .subdevice = 0x0342, + .card = CX88_BOARD_DIGITALLOGIC_MEC, + },{ + .subvendor = 0x10fc, + .subdevice = 0xd035, + .card = CX88_BOARD_IODATA_GVBCTV7E, + },{ + .subvendor = 0x1421, + .subdevice = 0x0334, + .card = CX88_BOARD_ADSTECH_DVB_T_PCI, + },{ + .subvendor = 0x153b, + .subdevice = 0x1166, + .card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1, + },{ + .subvendor = 0x18ac, + .subdevice = 0xd500, + .card = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD, + },{ + .subvendor = 0x1461, + .subdevice = 0x8011, + .card = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550, + },{ + .subvendor = PCI_VENDOR_ID_ATI, + .subdevice = 0xa101, + .card = CX88_BOARD_ATI_HDTVWONDER, + },{ + .subvendor = 0x107d, + .subdevice = 0x665f, + .card = CX88_BOARD_WINFAST_DTV1000, + },{ + .subvendor = 0x1461, + .subdevice = 0x000a, + .card = CX88_BOARD_AVERTV_303, + },{ + .subvendor = 0x0070, + .subdevice = 0x9200, + .card = CX88_BOARD_HAUPPAUGE_NOVASE2_S1, + },{ + .subvendor = 0x0070, + .subdevice = 0x9201, + .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, + },{ + .subvendor = 0x0070, + .subdevice = 0x9202, + .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, + },{ + .subvendor = 0x17de, + .subdevice = 0x08b2, + .card = CX88_BOARD_KWORLD_DVBS_100, + },{ + .subvendor = 0x0070, + .subdevice = 0x9400, + .card = CX88_BOARD_HAUPPAUGE_HVR1100, + },{ + .subvendor = 0x0070, + .subdevice = 0x9402, + .card = CX88_BOARD_HAUPPAUGE_HVR1100, + },{ + .subvendor = 0x0070, + .subdevice = 0x9800, + .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, + },{ + .subvendor = 0x0070, + .subdevice = 0x9802, + .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, + },{ + .subvendor = 0x0070, + .subdevice = 0x9001, + .card = CX88_BOARD_HAUPPAUGE_DVB_T1, + },{ + .subvendor = 0x1822, + .subdevice = 0x0025, + .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, + },{ + .subvendor = 0x17de, + .subdevice = 0x08a1, + .card = CX88_BOARD_KWORLD_DVB_T_CX22702, + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb50, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL, + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb54, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL, + /* Re-branded DViCO: DigitalNow DVB-T Dual */ + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb11, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, + /* Re-branded DViCO: UltraView DVB-T Plus */ + }, { + .subvendor = 0x18ac, + .subdevice = 0xdb30, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO, + }, { + .subvendor = 0x17de, + .subdevice = 0x0840, + .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, + },{ + .subvendor = 0x1421, + .subdevice = 0x0305, + .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb40, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb44, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, + },{ + .subvendor = 0x7063, + .subdevice = 0x5500, + .card = CX88_BOARD_PCHDTV_HD5500, + },{ + .subvendor = 0x17de, + .subdevice = 0x0841, + .card = CX88_BOARD_KWORLD_MCE200_DELUXE, + },{ + .subvendor = 0x1822, + .subdevice = 0x0019, + .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, + },{ + .subvendor = 0x1554, + .subdevice = 0x4813, + .card = CX88_BOARD_PIXELVIEW_PLAYTV_P7000, + },{ + .subvendor = 0x14f1, + .subdevice = 0x0842, + .card = CX88_BOARD_NPGTECH_REALTV_TOP10FM, + },{ + .subvendor = 0x107d, + .subdevice = 0x665e, + .card = CX88_BOARD_WINFAST_DTV2000H, + },{ + .subvendor = 0x107d, + .subdevice = 0x6f2b, + .card = CX88_BOARD_WINFAST_DTV2000H_J, + },{ + .subvendor = 0x18ac, + .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */ + .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, + },{ + .subvendor = 0x14f1, + .subdevice = 0x0084, + .card = CX88_BOARD_GENIATECH_DVBS, + },{ + .subvendor = 0x0070, + .subdevice = 0x1404, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, + }, { + .subvendor = 0x18ac, + .subdevice = 0xdc00, + .card = CX88_BOARD_SAMSUNG_SMT_7020, + }, { + .subvendor = 0x18ac, + .subdevice = 0xdccd, + .card = CX88_BOARD_SAMSUNG_SMT_7020, + },{ + .subvendor = 0x1461, + .subdevice = 0xc111, /* AverMedia M150-D */ + /* This board is known to work with the ASUS PVR416 config */ + .card = CX88_BOARD_ASUS_PVR_416, + },{ + .subvendor = 0xc180, + .subdevice = 0xc980, + .card = CX88_BOARD_TE_DTV_250_OEM_SWANN, + },{ + .subvendor = 0x0070, + .subdevice = 0x9600, + .card = CX88_BOARD_HAUPPAUGE_HVR1300, + },{ + .subvendor = 0x0070, + .subdevice = 0x9601, + .card = CX88_BOARD_HAUPPAUGE_HVR1300, + },{ + .subvendor = 0x0070, + .subdevice = 0x9602, + .card = CX88_BOARD_HAUPPAUGE_HVR1300, + },{ + .subvendor = 0x107d, + .subdevice = 0x6632, + .card = CX88_BOARD_LEADTEK_PVR2000, + },{ + .subvendor = 0x12ab, + .subdevice = 0x2300, /* Club3D Zap TV2100 */ + .card = CX88_BOARD_KWORLD_DVB_T_CX22702, + },{ + .subvendor = 0x0070, + .subdevice = 0x9000, + .card = CX88_BOARD_HAUPPAUGE_DVB_T1, + },{ + .subvendor = 0x0070, + .subdevice = 0x1400, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, + },{ + .subvendor = 0x0070, + .subdevice = 0x1401, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, + },{ + .subvendor = 0x0070, + .subdevice = 0x1402, + .card = CX88_BOARD_HAUPPAUGE_HVR3000, + },{ + .subvendor = 0x1421, + .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */ + .card = CX88_BOARD_KWORLD_DVBS_100, + },{ + .subvendor = 0x1421, + .subdevice = 0x0390, + .card = CX88_BOARD_ADSTECH_PTV_390, + },{ + .subvendor = 0x11bd, + .subdevice = 0x0051, + .card = CX88_BOARD_PINNACLE_PCTV_HD_800i, + }, { + .subvendor = 0x18ac, + .subdevice = 0xd530, + .card = CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO, + }, { + .subvendor = 0x12ab, + .subdevice = 0x1788, + .card = CX88_BOARD_PINNACLE_HYBRID_PCTV, + }, { + .subvendor = 0x14f1, + .subdevice = 0xea3d, + .card = CX88_BOARD_POWERCOLOR_REAL_ANGEL, + }, { + .subvendor = 0x107d, + .subdevice = 0x6f18, + .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, + }, { + .subvendor = 0x14f1, + .subdevice = 0x8852, + .card = CX88_BOARD_GENIATECH_X8000_MT, + }, { + .subvendor = 0x18ac, + .subdevice = 0xd610, + .card = CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD, + }, { + .subvendor = 0x1554, + .subdevice = 0x4935, + .card = CX88_BOARD_PROLINK_PV_8000GT, + }, { + .subvendor = 0x1554, + .subdevice = 0x4976, + .card = CX88_BOARD_PROLINK_PV_GLOBAL_XTREME, + }, { + .subvendor = 0x17de, + .subdevice = 0x08c1, + .card = CX88_BOARD_KWORLD_ATSC_120, + }, { + .subvendor = 0x0070, + .subdevice = 0x6900, + .card = CX88_BOARD_HAUPPAUGE_HVR4000, + }, { + .subvendor = 0x0070, + .subdevice = 0x6904, + .card = CX88_BOARD_HAUPPAUGE_HVR4000, + }, { + .subvendor = 0x0070, + .subdevice = 0x6902, + .card = CX88_BOARD_HAUPPAUGE_HVR4000, + }, { + .subvendor = 0x0070, + .subdevice = 0x6905, + .card = CX88_BOARD_HAUPPAUGE_HVR4000LITE, + }, { + .subvendor = 0x0070, + .subdevice = 0x6906, + .card = CX88_BOARD_HAUPPAUGE_HVR4000LITE, + }, { + .subvendor = 0xd420, + .subdevice = 0x9022, + .card = CX88_BOARD_TEVII_S420, + }, { + .subvendor = 0xd460, + .subdevice = 0x9022, + .card = CX88_BOARD_TEVII_S460, + }, { + .subvendor = 0xd464, + .subdevice = 0x9022, + .card = CX88_BOARD_TEVII_S464, + }, { + .subvendor = 0xA044, + .subdevice = 0x2011, + .card = CX88_BOARD_OMICOM_SS4_PCI, + }, { + .subvendor = 0x8910, + .subdevice = 0x8888, + .card = CX88_BOARD_TBS_8910, + }, { + .subvendor = 0x8920, + .subdevice = 0x8888, + .card = CX88_BOARD_TBS_8920, + }, { + .subvendor = 0xb022, + .subdevice = 0x3022, + .card = CX88_BOARD_PROF_6200, + }, { + .subvendor = 0xB033, + .subdevice = 0x3033, + .card = CX88_BOARD_PROF_7300, + }, { + .subvendor = 0xb200, + .subdevice = 0x4200, + .card = CX88_BOARD_SATTRADE_ST4200, + }, { + .subvendor = 0x153b, + .subdevice = 0x1177, + .card = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII, + }, { + .subvendor = 0x0070, + .subdevice = 0x9290, + .card = CX88_BOARD_HAUPPAUGE_IRONLY, + }, { + .subvendor = 0x107d, + .subdevice = 0x6654, + .card = CX88_BOARD_WINFAST_DTV1800H, + }, { + /* WinFast DTV1800 H with XC4000 tuner */ + .subvendor = 0x107d, + .subdevice = 0x6f38, + .card = CX88_BOARD_WINFAST_DTV1800H_XC4000, + }, { + .subvendor = 0x107d, + .subdevice = 0x6f42, + .card = CX88_BOARD_WINFAST_DTV2000H_PLUS, + }, { + /* PVR2000 PAL Model [107d:6630] */ + .subvendor = 0x107d, + .subdevice = 0x6630, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* PVR2000 PAL Model [107d:6638] */ + .subvendor = 0x107d, + .subdevice = 0x6638, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* PVR2000 NTSC Model [107d:6631] */ + .subvendor = 0x107d, + .subdevice = 0x6631, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* PVR2000 NTSC Model [107d:6637] */ + .subvendor = 0x107d, + .subdevice = 0x6637, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* PVR2000 NTSC Model [107d:663d] */ + .subvendor = 0x107d, + .subdevice = 0x663d, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* DV2000 NTSC Model [107d:6621] */ + .subvendor = 0x107d, + .subdevice = 0x6621, + .card = CX88_BOARD_WINFAST_DV2000, + }, { + /* TV2000 XP Global [107d:6618] */ + .subvendor = 0x107d, + .subdevice = 0x6618, + .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, + }, { + .subvendor = 0xb034, + .subdevice = 0x3034, + .card = CX88_BOARD_PROF_7301, + }, { + .subvendor = 0x1822, + .subdevice = 0x0023, + .card = CX88_BOARD_TWINHAN_VP1027_DVBS, + }, +}; + +/* ----------------------------------------------------------------------- */ +/* some leadtek specific stuff */ + +static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) +{ + if (eeprom_data[4] != 0x7d || + eeprom_data[5] != 0x10 || + eeprom_data[7] != 0x66) { + warn_printk(core, "Leadtek eeprom invalid.\n"); + return; + } + + /* Terry Wu */ + switch (eeprom_data[6]) { + case 0x13: /* SSID 6613 for TV2000 XP Expert NTSC Model */ + case 0x21: /* SSID 6621 for DV2000 NTSC Model */ + case 0x31: /* SSID 6631 for PVR2000 NTSC Model */ + case 0x37: /* SSID 6637 for PVR2000 NTSC Model */ + case 0x3d: /* SSID 6637 for PVR2000 NTSC Model */ + core->board.tuner_type = TUNER_PHILIPS_FM1236_MK3; + break; + default: + core->board.tuner_type = TUNER_PHILIPS_FM1216ME_MK3; + break; + } + + info_printk(core, "Leadtek Winfast 2000XP Expert config: " + "tuner=%d, eeprom[0]=0x%02x\n", + core->board.tuner_type, eeprom_data[0]); +} + +static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); + core->board.tuner_type = tv.tuner_type; + core->tuner_formats = tv.tuner_formats; + core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; + + /* Make sure we support the board model */ + switch (tv.model) + { + case 14009: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */ + case 14019: /* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */ + case 14029: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */ + case 14109: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - low profile) */ + case 14129: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge - LP) */ + case 14559: /* WinTV-HVR3000 (OEM, no IR, b/panel video, 3.5mm audio in) */ + case 14569: /* WinTV-HVR3000 (OEM, no IR, no back panel video) */ + case 14659: /* WinTV-HVR3000 (OEM, no IR, b/panel video, RCA audio in - Low profile) */ + case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */ + case 28552: /* WinTV-PVR 'Roslyn' (No IR) */ + case 34519: /* WinTV-PCI-FM */ + case 69009: + /* WinTV-HVR4000 (DVBS/S2/T, Video and IR, back panel inputs) */ + case 69100: /* WinTV-HVR4000LITE (DVBS/S2, IR) */ + case 69500: /* WinTV-HVR4000LITE (DVBS/S2, No IR) */ + case 69559: + /* WinTV-HVR4000 (DVBS/S2/T, Video no IR, back panel inputs) */ + case 69569: /* WinTV-HVR4000 (DVBS/S2/T, Video no IR) */ + case 90002: /* Nova-T-PCI (9002) */ + case 92001: /* Nova-S-Plus (Video and IR) */ + case 92002: /* Nova-S-Plus (Video and IR) */ + case 90003: /* Nova-T-PCI (9002 No RF out) */ + case 90500: /* Nova-T-PCI (oem) */ + case 90501: /* Nova-T-PCI (oem/IR) */ + case 92000: /* Nova-SE2 (OEM, No Video or IR) */ + case 92900: /* WinTV-IROnly (No analog or digital Video inputs) */ + case 94009: /* WinTV-HVR1100 (Video and IR Retail) */ + case 94501: /* WinTV-HVR1100 (Video and IR OEM) */ + case 96009: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX) */ + case 96019: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX/TX) */ + case 96559: /* WinTV-HVR1300 (PAL Video, MPEG Video no IR) */ + case 96569: /* WinTV-HVR1300 () */ + case 96659: /* WinTV-HVR1300 () */ + case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */ + /* known */ + break; + case CX88_BOARD_SAMSUNG_SMT_7020: + cx_set(MO_GP0_IO, 0x008989FF); + break; + default: + warn_printk(core, "warning: unknown hauppauge model #%d\n", + tv.model); + break; + } + + info_printk(core, "hauppauge eeprom: model=%d\n", tv.model); +} + +/* ----------------------------------------------------------------------- */ +/* some GDI (was: Modular Technology) specific stuff */ + +static const struct { + int id; + int fm; + const char *name; +} gdi_tuner[] = { + [ 0x01 ] = { .id = TUNER_ABSENT, + .name = "NTSC_M" }, + [ 0x02 ] = { .id = TUNER_ABSENT, + .name = "PAL_B" }, + [ 0x03 ] = { .id = TUNER_ABSENT, + .name = "PAL_I" }, + [ 0x04 ] = { .id = TUNER_ABSENT, + .name = "PAL_D" }, + [ 0x05 ] = { .id = TUNER_ABSENT, + .name = "SECAM" }, + + [ 0x10 ] = { .id = TUNER_ABSENT, + .fm = 1, + .name = "TEMIC_4049" }, + [ 0x11 ] = { .id = TUNER_TEMIC_4136FY5, + .name = "TEMIC_4136" }, + [ 0x12 ] = { .id = TUNER_ABSENT, + .name = "TEMIC_4146" }, + + [ 0x20 ] = { .id = TUNER_PHILIPS_FQ1216ME, + .fm = 1, + .name = "PHILIPS_FQ1216_MK3" }, + [ 0x21 ] = { .id = TUNER_ABSENT, .fm = 1, + .name = "PHILIPS_FQ1236_MK3" }, + [ 0x22 ] = { .id = TUNER_ABSENT, + .name = "PHILIPS_FI1236_MK3" }, + [ 0x23 ] = { .id = TUNER_ABSENT, + .name = "PHILIPS_FI1216_MK3" }, +}; + +static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) +{ + const char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner)) + ? gdi_tuner[eeprom_data[0x0d]].name : NULL; + + info_printk(core, "GDI: tuner=%s\n", name ? name : "unknown"); + if (NULL == name) + return; + core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id; + core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ? + CX88_RADIO : 0; +} + +/* ------------------------------------------------------------------- */ +/* some Divco specific stuff */ +static int cx88_dvico_xc2028_callback(struct cx88_core *core, + int command, int arg) +{ + switch (command) { + case XC2028_TUNER_RESET: + switch (core->boardnr) { + case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: + /* GPIO-4 xc3028 tuner */ + + cx_set(MO_GP0_IO, 0x00001000); + cx_clear(MO_GP0_IO, 0x00000010); + msleep(100); + cx_set(MO_GP0_IO, 0x00000010); + msleep(100); + break; + default: + cx_write(MO_GP0_IO, 0x101000); + mdelay(5); + cx_set(MO_GP0_IO, 0x101010); + } + break; + default: + return -EINVAL; + } + + return 0; +} + + +/* ----------------------------------------------------------------------- */ +/* some Geniatech specific stuff */ + +static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core, + int command, int mode) +{ + switch (command) { + case XC2028_TUNER_RESET: + switch (INPUT(core->input).type) { + case CX88_RADIO: + break; + case CX88_VMUX_DVB: + cx_write(MO_GP1_IO, 0x030302); + mdelay(50); + break; + default: + cx_write(MO_GP1_IO, 0x030301); + mdelay(50); + } + cx_write(MO_GP1_IO, 0x101010); + mdelay(50); + cx_write(MO_GP1_IO, 0x101000); + mdelay(50); + cx_write(MO_GP1_IO, 0x101010); + mdelay(50); + return 0; + } + return -EINVAL; +} + +static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core, + int command, int arg) +{ + switch (command) { + case XC2028_TUNER_RESET: + /* GPIO 12 (xc3028 tuner reset) */ + cx_set(MO_GP1_IO, 0x1010); + mdelay(50); + cx_clear(MO_GP1_IO, 0x10); + mdelay(50); + cx_set(MO_GP1_IO, 0x10); + mdelay(50); + return 0; + } + return -EINVAL; +} + +static int cx88_xc4000_winfast2000h_plus_callback(struct cx88_core *core, + int command, int arg) +{ + switch (command) { + case XC4000_TUNER_RESET: + /* GPIO 12 (xc4000 tuner reset) */ + cx_set(MO_GP1_IO, 0x1010); + mdelay(50); + cx_clear(MO_GP1_IO, 0x10); + mdelay(75); + cx_set(MO_GP1_IO, 0x10); + mdelay(75); + return 0; + } + return -EINVAL; +} + +/* ------------------------------------------------------------------- */ +/* some Divco specific stuff */ +static int cx88_pv_8000gt_callback(struct cx88_core *core, + int command, int arg) +{ + switch (command) { + case XC2028_TUNER_RESET: + cx_write(MO_GP2_IO, 0xcf7); + mdelay(50); + cx_write(MO_GP2_IO, 0xef5); + mdelay(50); + cx_write(MO_GP2_IO, 0xcf7); + break; + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ +/* some DViCO specific stuff */ + +static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) +{ + struct i2c_msg msg = { .addr = 0x45, .flags = 0 }; + int i, err; + static u8 init_bufs[13][5] = { + { 0x10, 0x00, 0x20, 0x01, 0x03 }, + { 0x10, 0x10, 0x01, 0x00, 0x21 }, + { 0x10, 0x10, 0x10, 0x00, 0xCA }, + { 0x10, 0x10, 0x12, 0x00, 0x08 }, + { 0x10, 0x10, 0x13, 0x00, 0x0A }, + { 0x10, 0x10, 0x16, 0x01, 0xC0 }, + { 0x10, 0x10, 0x22, 0x01, 0x3D }, + { 0x10, 0x10, 0x73, 0x01, 0x2E }, + { 0x10, 0x10, 0x72, 0x00, 0xC5 }, + { 0x10, 0x10, 0x71, 0x01, 0x97 }, + { 0x10, 0x10, 0x70, 0x00, 0x0F }, + { 0x10, 0x10, 0xB0, 0x00, 0x01 }, + { 0x03, 0x0C }, + }; + + for (i = 0; i < ARRAY_SIZE(init_bufs); i++) { + msg.buf = init_bufs[i]; + msg.len = (i != 12 ? 5 : 2); + err = i2c_transfer(&core->i2c_adap, &msg, 1); + if (err != 1) { + warn_printk(core, "dvico_fusionhdtv_hybrid_init buf %d " + "failed (err = %d)!\n", i, err); + return; + } + } +} + +static int cx88_xc2028_tuner_callback(struct cx88_core *core, + int command, int arg) +{ + /* Board-specific callbacks */ + switch (core->boardnr) { + case CX88_BOARD_POWERCOLOR_REAL_ANGEL: + case CX88_BOARD_GENIATECH_X8000_MT: + case CX88_BOARD_KWORLD_ATSC_120: + return cx88_xc3028_geniatech_tuner_callback(core, + command, arg); + case CX88_BOARD_PROLINK_PV_8000GT: + case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: + return cx88_pv_8000gt_callback(core, command, arg); + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: + case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: + return cx88_dvico_xc2028_callback(core, command, arg); + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + case CX88_BOARD_WINFAST_DTV1800H: + return cx88_xc3028_winfast1800h_callback(core, command, arg); + } + + switch (command) { + case XC2028_TUNER_RESET: + switch (INPUT(core->input).type) { + case CX88_RADIO: + info_printk(core, "setting GPIO to radio!\n"); + cx_write(MO_GP0_IO, 0x4ff); + mdelay(250); + cx_write(MO_GP2_IO, 0xff); + mdelay(250); + break; + case CX88_VMUX_DVB: /* Digital TV*/ + default: /* Analog TV */ + info_printk(core, "setting GPIO to TV!\n"); + break; + } + cx_write(MO_GP1_IO, 0x101010); + mdelay(250); + cx_write(MO_GP1_IO, 0x101000); + mdelay(250); + cx_write(MO_GP1_IO, 0x101010); + mdelay(250); + return 0; + } + return -EINVAL; +} + +static int cx88_xc4000_tuner_callback(struct cx88_core *core, + int command, int arg) +{ + /* Board-specific callbacks */ + switch (core->boardnr) { + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + return cx88_xc4000_winfast2000h_plus_callback(core, + command, arg); + } + return -EINVAL; +} + +/* ----------------------------------------------------------------------- */ +/* Tuner callback function. Currently only needed for the Pinnacle * + * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * + * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ + +static int cx88_xc5000_tuner_callback(struct cx88_core *core, + int command, int arg) +{ + switch (core->boardnr) { + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + if (command == 0) { /* This is the reset command from xc5000 */ + + /* djh - According to the engineer at PCTV Systems, + the xc5000 reset pin is supposed to be on GPIO12. + However, despite three nights of effort, pulling + that GPIO low didn't reset the xc5000. While + pulling MO_SRST_IO low does reset the xc5000, this + also resets in the s5h1409 being reset as well. + This causes tuning to always fail since the internal + state of the s5h1409 does not match the driver's + state. Given that the only two conditions in which + the driver performs a reset is during firmware load + and powering down the chip, I am taking out the + reset. We know that the chip is being reset + when the cx88 comes online, and not being able to + do power management for this board is worse than + not having any tuning at all. */ + return 0; + } else { + err_printk(core, "xc5000: unknown tuner " + "callback command.\n"); + return -EINVAL; + } + break; + case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: + if (command == 0) { /* This is the reset command from xc5000 */ + cx_clear(MO_GP0_IO, 0x00000010); + msleep(10); + cx_set(MO_GP0_IO, 0x00000010); + return 0; + } else { + printk(KERN_ERR + "xc5000: unknown tuner callback command.\n"); + return -EINVAL; + } + break; + } + return 0; /* Should never be here */ +} + +int cx88_tuner_callback(void *priv, int component, int command, int arg) +{ + struct i2c_algo_bit_data *i2c_algo = priv; + struct cx88_core *core; + + if (!i2c_algo) { + printk(KERN_ERR "cx88: Error - i2c private data undefined.\n"); + return -EINVAL; + } + + core = i2c_algo->data; + + if (!core) { + printk(KERN_ERR "cx88: Error - device struct undefined.\n"); + return -EINVAL; + } + + if (component != DVB_FRONTEND_COMPONENT_TUNER) + return -EINVAL; + + switch (core->board.tuner_type) { + case TUNER_XC2028: + info_printk(core, "Calling XC2028/3028 callback\n"); + return cx88_xc2028_tuner_callback(core, command, arg); + case TUNER_XC4000: + info_printk(core, "Calling XC4000 callback\n"); + return cx88_xc4000_tuner_callback(core, command, arg); + case TUNER_XC5000: + info_printk(core, "Calling XC5000 callback\n"); + return cx88_xc5000_tuner_callback(core, command, arg); + } + err_printk(core, "Error: Calling callback for tuner %d\n", + core->board.tuner_type); + return -EINVAL; +} +EXPORT_SYMBOL(cx88_tuner_callback); + +/* ----------------------------------------------------------------------- */ + +static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) +{ + int i; + + if (0 == pci->subsystem_vendor && + 0 == pci->subsystem_device) { + printk(KERN_ERR + "%s: Your board has no valid PCI Subsystem ID and thus can't\n" + "%s: be autodetected. Please pass card= insmod option to\n" + "%s: workaround that. Redirect complaints to the vendor of\n" + "%s: the TV card. Best regards,\n" + "%s: -- tux\n", + core->name,core->name,core->name,core->name,core->name); + } else { + printk(KERN_ERR + "%s: Your board isn't known (yet) to the driver. You can\n" + "%s: try to pick one of the existing card configs via\n" + "%s: card= insmod option. Updating to the latest\n" + "%s: version might help as well.\n", + core->name,core->name,core->name,core->name); + } + err_printk(core, "Here is a list of valid choices for the card= " + "insmod option:\n"); + for (i = 0; i < ARRAY_SIZE(cx88_boards); i++) + printk(KERN_ERR "%s: card=%d -> %s\n", + core->name, i, cx88_boards[i].name); +} + +static void cx88_card_setup_pre_i2c(struct cx88_core *core) +{ + switch (core->boardnr) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* + * Bring the 702 demod up before i2c scanning/attach or devices are hidden + * We leave here with the 702 on the bus + * + * "reset the IR receiver on GPIO[3]" + * Reported by Mike Crash + */ + cx_write(MO_GP0_IO, 0x0000ef88); + udelay(1000); + cx_clear(MO_GP0_IO, 0x00000088); + udelay(50); + cx_set(MO_GP0_IO, 0x00000088); /* 702 out of reset */ + udelay(1000); + break; + + case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: + case CX88_BOARD_PROLINK_PV_8000GT: + cx_write(MO_GP2_IO, 0xcf7); + mdelay(50); + cx_write(MO_GP2_IO, 0xef5); + mdelay(50); + cx_write(MO_GP2_IO, 0xcf7); + msleep(10); + break; + + case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: + /* Enable the xc5000 tuner */ + cx_set(MO_GP0_IO, 0x00001010); + break; + + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + /* Init GPIO */ + cx_write(MO_GP0_IO, core->board.input[0].gpio0); + udelay(1000); + cx_clear(MO_GP0_IO, 0x00000080); + udelay(50); + cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */ + udelay(1000); + break; + + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + case CX88_BOARD_WINFAST_DTV1800H: + cx88_xc3028_winfast1800h_callback(core, XC2028_TUNER_RESET, 0); + break; + + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + cx88_xc4000_winfast2000h_plus_callback(core, + XC4000_TUNER_RESET, 0); + break; + + case CX88_BOARD_TWINHAN_VP1027_DVBS: + cx_write(MO_GP0_IO, 0x00003230); + cx_write(MO_GP0_IO, 0x00003210); + msleep(1); + cx_write(MO_GP0_IO, 0x00001230); + break; + } +} + +/* + * Sets board-dependent xc3028 configuration + */ +void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl) +{ + memset(ctl, 0, sizeof(*ctl)); + + ctl->fname = XC2028_DEFAULT_FIRMWARE; + ctl->max_len = 64; + + switch (core->boardnr) { + case CX88_BOARD_POWERCOLOR_REAL_ANGEL: + /* Now works with firmware version 2.7 */ + if (core->i2c_algo.udelay < 16) + core->i2c_algo.udelay = 16; + break; + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: + case CX88_BOARD_WINFAST_DTV1800H: + ctl->demod = XC3028_FE_ZARLINK456; + break; + case CX88_BOARD_KWORLD_ATSC_120: + case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: + ctl->demod = XC3028_FE_OREN538; + break; + case CX88_BOARD_GENIATECH_X8000_MT: + /* FIXME: For this board, the xc3028 never recovers after being + powered down (the reset GPIO probably is not set properly). + We don't have access to the hardware so we cannot determine + which GPIO is used for xc3028, so just disable power xc3028 + power management for now */ + ctl->disable_power_mgmt = 1; + break; + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: + case CX88_BOARD_PROLINK_PV_8000GT: + /* + * Those boards uses non-MTS firmware + */ + break; + case CX88_BOARD_PINNACLE_HYBRID_PCTV: + case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII: + ctl->demod = XC3028_FE_ZARLINK456; + ctl->mts = 1; + break; + default: + ctl->demod = XC3028_FE_OREN538; + ctl->mts = 1; + } +} +EXPORT_SYMBOL_GPL(cx88_setup_xc3028); + +static void cx88_card_setup(struct cx88_core *core) +{ + static u8 eeprom[256]; + struct tuner_setup tun_setup; + unsigned int mode_mask = T_RADIO | T_ANALOG_TV; + + memset(&tun_setup, 0, sizeof(tun_setup)); + + if (0 == core->i2c_rc) { + core->i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom)); + } + + switch (core->boardnr) { + case CX88_BOARD_HAUPPAUGE: + case CX88_BOARD_HAUPPAUGE_ROSLYN: + if (0 == core->i2c_rc) + hauppauge_eeprom(core, eeprom+8); + break; + case CX88_BOARD_GDI: + if (0 == core->i2c_rc) + gdi_eeprom(core, eeprom); + break; + case CX88_BOARD_LEADTEK_PVR2000: + case CX88_BOARD_WINFAST_DV2000: + case CX88_BOARD_WINFAST2000XP_EXPERT: + if (0 == core->i2c_rc) + leadtek_eeprom(core, eeprom); + break; + case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: + case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: + case CX88_BOARD_HAUPPAUGE_DVB_T1: + case CX88_BOARD_HAUPPAUGE_HVR1100: + case CX88_BOARD_HAUPPAUGE_HVR1100LP: + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR1300: + case CX88_BOARD_HAUPPAUGE_HVR4000: + case CX88_BOARD_HAUPPAUGE_HVR4000LITE: + case CX88_BOARD_HAUPPAUGE_IRONLY: + if (0 == core->i2c_rc) + hauppauge_eeprom(core, eeprom); + break; + case CX88_BOARD_KWORLD_DVBS_100: + cx_write(MO_GP0_IO, 0x000007f8); + cx_write(MO_GP1_IO, 0x00000001); + break; + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: + /* GPIO0:0 is hooked to demod reset */ + /* GPIO0:4 is hooked to xc3028 reset */ + cx_write(MO_GP0_IO, 0x00111100); + msleep(1); + cx_write(MO_GP0_IO, 0x00111111); + break; + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: + /* GPIO0:6 is hooked to FX2 reset pin */ + cx_set(MO_GP0_IO, 0x00004040); + cx_clear(MO_GP0_IO, 0x00000040); + msleep(1000); + cx_set(MO_GP0_IO, 0x00004040); + /* FALLTHROUGH */ + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: + /* GPIO0:0 is hooked to mt352 reset pin */ + cx_set(MO_GP0_IO, 0x00000101); + cx_clear(MO_GP0_IO, 0x00000001); + msleep(1); + cx_set(MO_GP0_IO, 0x00000101); + if (0 == core->i2c_rc && + core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) + dvico_fusionhdtv_hybrid_init(core); + break; + case CX88_BOARD_KWORLD_DVB_T: + case CX88_BOARD_DNTV_LIVE_DVB_T: + cx_set(MO_GP0_IO, 0x00000707); + cx_set(MO_GP2_IO, 0x00000101); + cx_clear(MO_GP2_IO, 0x00000001); + msleep(1); + cx_clear(MO_GP0_IO, 0x00000007); + cx_set(MO_GP2_IO, 0x00000101); + break; + case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: + cx_write(MO_GP0_IO, 0x00080808); + break; + case CX88_BOARD_ATI_HDTVWONDER: + if (0 == core->i2c_rc) { + /* enable tuner */ + int i; + static const u8 buffer [][2] = { + {0x10,0x12}, + {0x13,0x04}, + {0x16,0x00}, + {0x14,0x04}, + {0x17,0x00} + }; + core->i2c_client.addr = 0x0a; + + for (i = 0; i < ARRAY_SIZE(buffer); i++) + if (2 != i2c_master_send(&core->i2c_client, + buffer[i],2)) + warn_printk(core, "Unable to enable " + "tuner(%i).\n", i); + } + break; + case CX88_BOARD_MSI_TVANYWHERE_MASTER: + { + struct v4l2_priv_tun_config tea5767_cfg; + struct tea5767_ctrl ctl; + + memset(&ctl, 0, sizeof(ctl)); + + ctl.high_cut = 1; + ctl.st_noise = 1; + ctl.deemph_75 = 1; + ctl.xtal_freq = TEA5767_HIGH_LO_13MHz; + + tea5767_cfg.tuner = TUNER_TEA5767; + tea5767_cfg.priv = &ctl; + + call_all(core, tuner, s_config, &tea5767_cfg); + break; + } + case CX88_BOARD_TEVII_S420: + case CX88_BOARD_TEVII_S460: + case CX88_BOARD_TEVII_S464: + case CX88_BOARD_OMICOM_SS4_PCI: + case CX88_BOARD_TBS_8910: + case CX88_BOARD_TBS_8920: + case CX88_BOARD_PROF_6200: + case CX88_BOARD_PROF_7300: + case CX88_BOARD_PROF_7301: + case CX88_BOARD_SATTRADE_ST4200: + cx_write(MO_GP0_IO, 0x8000); + msleep(100); + cx_write(MO_SRST_IO, 0); + msleep(10); + cx_write(MO_GP0_IO, 0x8080); + msleep(100); + cx_write(MO_SRST_IO, 1); + msleep(100); + break; + } /*end switch() */ + + + /* Setup tuners */ + if ((core->board.radio_type != UNSET)) { + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; + tun_setup.tuner_callback = cx88_tuner_callback; + call_all(core, tuner, s_type_addr, &tun_setup); + mode_mask &= ~T_RADIO; + } + + if (core->board.tuner_type != TUNER_ABSENT) { + tun_setup.mode_mask = mode_mask; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; + tun_setup.tuner_callback = cx88_tuner_callback; + + call_all(core, tuner, s_type_addr, &tun_setup); + } + + if (core->board.tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &core->board.tda9887_conf; + + call_all(core, tuner, s_config, &tda9887_cfg); + } + + if (core->board.tuner_type == TUNER_XC2028) { + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + + /* Fills device-dependent initialization parameters */ + cx88_setup_xc3028(core, &ctl); + + /* Sends parameters to xc2028/3028 tuner */ + memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + info_printk(core, "Asking xc2028/3028 to load firmware %s\n", + ctl.fname); + call_all(core, tuner, s_config, &xc2028_cfg); + } + call_all(core, core, s_power, 0); +} + +/* ------------------------------------------------------------------ */ + +static int cx88_pci_quirks(const char *name, struct pci_dev *pci) +{ + unsigned int lat = UNSET; + u8 ctrl = 0; + u8 value; + + /* check pci quirks */ + if (pci_pci_problems & PCIPCI_TRITON) { + printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_NATOMA) { + printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_VIAETBF) { + printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_VSFX) { + printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", + name); + ctrl |= CX88X_EN_VSFX; + } +#ifdef PCIPCI_ALIMAGIK + if (pci_pci_problems & PCIPCI_ALIMAGIK) { + printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", + name); + lat = 0x0A; + } +#endif + + /* check insmod options */ + if (UNSET != latency) + lat = latency; + + /* apply stuff */ + if (ctrl) { + pci_read_config_byte(pci, CX88X_DEVCTRL, &value); + value |= ctrl; + pci_write_config_byte(pci, CX88X_DEVCTRL, value); + } + if (UNSET != lat) { + printk(KERN_INFO "%s: setting pci latency timer to %d\n", + name, latency); + pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); + } + return 0; +} + +int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci) +{ + if (request_mem_region(pci_resource_start(pci,0), + pci_resource_len(pci,0), + core->name)) + return 0; + printk(KERN_ERR + "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", + core->name, PCI_FUNC(pci->devfn), + (unsigned long long)pci_resource_start(pci, 0), + pci->subsystem_vendor, pci->subsystem_device); + return -EBUSY; +} + +/* Allocate and initialize the cx88 core struct. One should hold the + * devlist mutex before calling this. */ +struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) +{ + struct cx88_core *core; + int i; + + core = kzalloc(sizeof(*core), GFP_KERNEL); + if (core == NULL) + return NULL; + + atomic_inc(&core->refcount); + core->pci_bus = pci->bus->number; + core->pci_slot = PCI_SLOT(pci->devfn); + core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT | + PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT | + PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT; + mutex_init(&core->lock); + + core->nr = nr; + sprintf(core->name, "cx88[%d]", core->nr); + + strcpy(core->v4l2_dev.name, core->name); + if (v4l2_device_register(NULL, &core->v4l2_dev)) { + kfree(core); + return NULL; + } + + if (0 != cx88_get_resources(core, pci)) { + v4l2_device_unregister(&core->v4l2_dev); + kfree(core); + return NULL; + } + + /* PCI stuff */ + cx88_pci_quirks(core->name, pci); + core->lmmio = ioremap(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + core->bmmio = (u8 __iomem *)core->lmmio; + + if (core->lmmio == NULL) { + kfree(core); + return NULL; + } + + /* board config */ + core->boardnr = UNSET; + if (card[core->nr] < ARRAY_SIZE(cx88_boards)) + core->boardnr = card[core->nr]; + for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++) + if (pci->subsystem_vendor == cx88_subids[i].subvendor && + pci->subsystem_device == cx88_subids[i].subdevice) + core->boardnr = cx88_subids[i].card; + if (UNSET == core->boardnr) { + core->boardnr = CX88_BOARD_UNKNOWN; + cx88_card_list(core, pci); + } + + memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); + + if (!core->board.num_frontends && (core->board.mpeg & CX88_MPEG_DVB)) + core->board.num_frontends = 1; + + info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n", + pci->subsystem_vendor, pci->subsystem_device, core->board.name, + core->boardnr, card[core->nr] == core->boardnr ? + "insmod option" : "autodetected", + core->board.num_frontends); + + if (tuner[core->nr] != UNSET) + core->board.tuner_type = tuner[core->nr]; + if (radio[core->nr] != UNSET) + core->board.radio_type = radio[core->nr]; + + info_printk(core, "TV tuner type %d, Radio tuner type %d\n", + core->board.tuner_type, core->board.radio_type); + + /* init hardware */ + cx88_reset(core); + cx88_card_setup_pre_i2c(core); + cx88_i2c_init(core, pci); + + /* load tuner module, if needed */ + if (TUNER_ABSENT != core->board.tuner_type) { + /* Ignore 0x6b and 0x6f on cx88 boards. + * FusionHDTV5 RT Gold has an ir receiver at 0x6b + * and an RTC at 0x6f which can get corrupted if probed. */ + static const unsigned short tv_addrs[] = { + 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6c, 0x6d, 0x6e, + I2C_CLIENT_END + }; + int has_demod = (core->board.tda9887_conf & TDA9887_PRESENT); + + /* I don't trust the radio_type as is stored in the card + definitions, so we just probe for it. + The radio_type is sometimes missing, or set to UNSET but + later code configures a tea5767. + */ + v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, + "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); + if (has_demod) + v4l2_i2c_new_subdev(&core->v4l2_dev, + &core->i2c_adap, "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + if (core->board.tuner_addr == ADDR_UNSET) { + v4l2_i2c_new_subdev(&core->v4l2_dev, + &core->i2c_adap, "tuner", + 0, has_demod ? tv_addrs + 4 : tv_addrs); + } else { + v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, + "tuner", core->board.tuner_addr, NULL); + } + } + + cx88_card_setup(core); + if (!disable_ir) { + cx88_i2c_init_ir(core); + cx88_ir_init(core, pci); + } + + return core; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-core.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1126 @@ +/* + * + * device driver for Conexant 2388x based TV cards + * driver core + * + * (c) 2003 Gerd Knorr [SuSE Labs] + * + * (c) 2005-2006 Mauro Carvalho Chehab + * - Multituner support + * - video_ioctl2 conversion + * - PAL/M fixes + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx88.h" +#include +#include + +MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); +MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); +MODULE_LICENSE("GPL"); + +/* ------------------------------------------------------------------ */ + +static unsigned int core_debug; +module_param(core_debug,int,0644); +MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); + +static unsigned int nicam; +module_param(nicam,int,0644); +MODULE_PARM_DESC(nicam,"tv audio is nicam"); + +static unsigned int nocomb; +module_param(nocomb,int,0644); +MODULE_PARM_DESC(nocomb,"disable comb filter"); + +#define dprintk(level,fmt, arg...) if (core_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) + +static unsigned int cx88_devcount; +static LIST_HEAD(cx88_devlist); +static DEFINE_MUTEX(devlist); + +#define NO_SYNC_LINE (-1U) + +/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be + generated _after_ lpi lines are transferred. */ +static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines, unsigned int lpi) +{ + struct scatterlist *sg; + unsigned int line,todo,sol; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + /* scan lines */ + sg = sglist; + for (line = 0; line < lines; line++) { + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + if (lpi && line>0 && !(line % lpi)) + sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; + else + sol = RISC_SOL; + if (bpl <= sg_dma_len(sg)-offset) { + /* fits into current chunk */ + *(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + offset+=bpl; + } else { + /* scanline needs to be split */ + todo = bpl; + *(rp++)=cpu_to_le32(RISC_WRITE|sol| + (sg_dma_len(sg)-offset)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + todo -= (sg_dma_len(sg)-offset); + offset = 0; + sg++; + while (todo > sg_dma_len(sg)) { + *(rp++)=cpu_to_le32(RISC_WRITE| + sg_dma_len(sg)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + todo -= sg_dma_len(sg); + sg++; + } + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + offset += todo; + } + offset += padding; + } + + return rp; +} + +int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines) +{ + u32 instructions,fields; + __le32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); + instructions += 2; + if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + if (UNSET != top_offset) + rp = cx88_risc_field(rp, sglist, top_offset, 0, + bpl, padding, lines, 0); + if (UNSET != bottom_offset) + rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200, + bpl, padding, lines, 0); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + return 0; +} + +int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int bpl, + unsigned int lines, unsigned int lpi) +{ + u32 instructions; + __le32 *rp; + int rc; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Here + there is no padding and no sync. First DMA region may be smaller + than PAGE_SIZE */ + instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; + instructions += 1; + if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + return 0; +} + +int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value) +{ + __le32 *rp; + int rc; + + if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM); + *(rp++) = cpu_to_le32(reg); + *(rp++) = cpu_to_le32(value); + *(rp++) = cpu_to_le32(mask); + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc->dma); + return 0; +} + +void +cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) +{ + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + + BUG_ON(in_interrupt()); + videobuf_waiton(q, &buf->vb, 0, 0); + videobuf_dma_unmap(q->dev, dma); + videobuf_dma_free(dma); + btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +/* ------------------------------------------------------------------ */ +/* our SRAM memory layout */ + +/* we are going to put all thr risc programs into host memory, so we + * can use the whole SDRAM for the DMA fifos. To simplify things, we + * use a static memory layout. That surely will waste memory in case + * we don't use all DMA channels at the same time (which will be the + * case most of the time). But that still gives us enough FIFO space + * to be able to deal with insane long pci latencies ... + * + * FIFO space allocations: + * channel 21 (y video) - 10.0k + * channel 22 (u video) - 2.0k + * channel 23 (v video) - 2.0k + * channel 24 (vbi) - 4.0k + * channels 25+26 (audio) - 4.0k + * channel 28 (mpeg) - 4.0k + * channel 27 (audio rds)- 3.0k + * TOTAL = 29.0k + * + * Every channel has 160 bytes control data (64 bytes instruction + * queue and 6 CDT entries), which is close to 2k total. + * + * Address layout: + * 0x0000 - 0x03ff CMDs / reserved + * 0x0400 - 0x0bff instruction queues + CDs + * 0x0c00 - FIFOs + */ + +const struct sram_channel const cx88_sram_channels[] = { + [SRAM_CH21] = { + .name = "video y / packed", + .cmds_start = 0x180040, + .ctrl_start = 0x180400, + .cdt = 0x180400 + 64, + .fifo_start = 0x180c00, + .fifo_size = 0x002800, + .ptr1_reg = MO_DMA21_PTR1, + .ptr2_reg = MO_DMA21_PTR2, + .cnt1_reg = MO_DMA21_CNT1, + .cnt2_reg = MO_DMA21_CNT2, + }, + [SRAM_CH22] = { + .name = "video u", + .cmds_start = 0x180080, + .ctrl_start = 0x1804a0, + .cdt = 0x1804a0 + 64, + .fifo_start = 0x183400, + .fifo_size = 0x000800, + .ptr1_reg = MO_DMA22_PTR1, + .ptr2_reg = MO_DMA22_PTR2, + .cnt1_reg = MO_DMA22_CNT1, + .cnt2_reg = MO_DMA22_CNT2, + }, + [SRAM_CH23] = { + .name = "video v", + .cmds_start = 0x1800c0, + .ctrl_start = 0x180540, + .cdt = 0x180540 + 64, + .fifo_start = 0x183c00, + .fifo_size = 0x000800, + .ptr1_reg = MO_DMA23_PTR1, + .ptr2_reg = MO_DMA23_PTR2, + .cnt1_reg = MO_DMA23_CNT1, + .cnt2_reg = MO_DMA23_CNT2, + }, + [SRAM_CH24] = { + .name = "vbi", + .cmds_start = 0x180100, + .ctrl_start = 0x1805e0, + .cdt = 0x1805e0 + 64, + .fifo_start = 0x184400, + .fifo_size = 0x001000, + .ptr1_reg = MO_DMA24_PTR1, + .ptr2_reg = MO_DMA24_PTR2, + .cnt1_reg = MO_DMA24_CNT1, + .cnt2_reg = MO_DMA24_CNT2, + }, + [SRAM_CH25] = { + .name = "audio from", + .cmds_start = 0x180140, + .ctrl_start = 0x180680, + .cdt = 0x180680 + 64, + .fifo_start = 0x185400, + .fifo_size = 0x001000, + .ptr1_reg = MO_DMA25_PTR1, + .ptr2_reg = MO_DMA25_PTR2, + .cnt1_reg = MO_DMA25_CNT1, + .cnt2_reg = MO_DMA25_CNT2, + }, + [SRAM_CH26] = { + .name = "audio to", + .cmds_start = 0x180180, + .ctrl_start = 0x180720, + .cdt = 0x180680 + 64, /* same as audio IN */ + .fifo_start = 0x185400, /* same as audio IN */ + .fifo_size = 0x001000, /* same as audio IN */ + .ptr1_reg = MO_DMA26_PTR1, + .ptr2_reg = MO_DMA26_PTR2, + .cnt1_reg = MO_DMA26_CNT1, + .cnt2_reg = MO_DMA26_CNT2, + }, + [SRAM_CH28] = { + .name = "mpeg", + .cmds_start = 0x180200, + .ctrl_start = 0x1807C0, + .cdt = 0x1807C0 + 64, + .fifo_start = 0x186400, + .fifo_size = 0x001000, + .ptr1_reg = MO_DMA28_PTR1, + .ptr2_reg = MO_DMA28_PTR2, + .cnt1_reg = MO_DMA28_CNT1, + .cnt2_reg = MO_DMA28_CNT2, + }, + [SRAM_CH27] = { + .name = "audio rds", + .cmds_start = 0x1801C0, + .ctrl_start = 0x180860, + .cdt = 0x180860 + 64, + .fifo_start = 0x187400, + .fifo_size = 0x000C00, + .ptr1_reg = MO_DMA27_PTR1, + .ptr2_reg = MO_DMA27_PTR2, + .cnt1_reg = MO_DMA27_CNT1, + .cnt2_reg = MO_DMA27_CNT2, + }, +}; + +int cx88_sram_channel_setup(struct cx88_core *core, + const struct sram_channel *ch, + unsigned int bpl, u32 risc) +{ + unsigned int i,lines; + u32 cdt; + + bpl = (bpl + 7) & ~7; /* alignment */ + cdt = ch->cdt; + lines = ch->fifo_size / bpl; + if (lines > 6) + lines = 6; + BUG_ON(lines < 2); + + /* write CDT */ + for (i = 0; i < lines; i++) + cx_write(cdt + 16*i, ch->fifo_start + bpl*i); + + /* write CMDS */ + cx_write(ch->cmds_start + 0, risc); + cx_write(ch->cmds_start + 4, cdt); + cx_write(ch->cmds_start + 8, (lines*16) >> 3); + cx_write(ch->cmds_start + 12, ch->ctrl_start); + cx_write(ch->cmds_start + 16, 64 >> 2); + for (i = 20; i < 64; i += 4) + cx_write(ch->cmds_start + i, 0); + + /* fill registers */ + cx_write(ch->ptr1_reg, ch->fifo_start); + cx_write(ch->ptr2_reg, cdt); + cx_write(ch->cnt1_reg, (bpl >> 3) -1); + cx_write(ch->cnt2_reg, (lines*16) >> 3); + + dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines); + return 0; +} + +/* ------------------------------------------------------------------ */ +/* debug helper code */ + +static int cx88_risc_decode(u32 risc) +{ + static const char * const instr[16] = { + [ RISC_SYNC >> 28 ] = "sync", + [ RISC_WRITE >> 28 ] = "write", + [ RISC_WRITEC >> 28 ] = "writec", + [ RISC_READ >> 28 ] = "read", + [ RISC_READC >> 28 ] = "readc", + [ RISC_JUMP >> 28 ] = "jump", + [ RISC_SKIP >> 28 ] = "skip", + [ RISC_WRITERM >> 28 ] = "writerm", + [ RISC_WRITECM >> 28 ] = "writecm", + [ RISC_WRITECR >> 28 ] = "writecr", + }; + static int const incr[16] = { + [ RISC_WRITE >> 28 ] = 2, + [ RISC_JUMP >> 28 ] = 2, + [ RISC_WRITERM >> 28 ] = 3, + [ RISC_WRITECM >> 28 ] = 3, + [ RISC_WRITECR >> 28 ] = 4, + }; + static const char * const bits[] = { + "12", "13", "14", "resync", + "cnt0", "cnt1", "18", "19", + "20", "21", "22", "23", + "irq1", "irq2", "eol", "sol", + }; + int i; + + printk("0x%08x [ %s", risc, + instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + if (risc & (1 << (i + 12))) + printk(" %s",bits[i]); + printk(" count=%d ]\n", risc & 0xfff); + return incr[risc >> 28] ? incr[risc >> 28] : 1; +} + + +void cx88_sram_channel_dump(struct cx88_core *core, + const struct sram_channel *ch) +{ + static const char * const name[] = { + "initial risc", + "cdt base", + "cdt size", + "iq base", + "iq size", + "risc pc", + "iq wr ptr", + "iq rd ptr", + "cdt current", + "pci target", + "line / byte", + }; + u32 risc; + unsigned int i,j,n; + + printk("%s: %s - dma channel status dump\n", + core->name,ch->name); + for (i = 0; i < ARRAY_SIZE(name); i++) + printk("%s: cmds: %-12s: 0x%08x\n", + core->name,name[i], + cx_read(ch->cmds_start + 4*i)); + for (n = 1, i = 0; i < 4; i++) { + risc = cx_read(ch->cmds_start + 4 * (i+11)); + printk("%s: risc%d: ", core->name, i); + if (--n) + printk("0x%08x [ arg #%d ]\n", risc, n); + else + n = cx88_risc_decode(risc); + } + for (i = 0; i < 16; i += n) { + risc = cx_read(ch->ctrl_start + 4 * i); + printk("%s: iq %x: ", core->name, i); + n = cx88_risc_decode(risc); + for (j = 1; j < n; j++) { + risc = cx_read(ch->ctrl_start + 4 * (i+j)); + printk("%s: iq %x: 0x%08x [ arg #%d ]\n", + core->name, i+j, risc, j); + } + } + + printk("%s: fifo: 0x%08x -> 0x%x\n", + core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); + printk("%s: ctrl: 0x%08x -> 0x%x\n", + core->name, ch->ctrl_start, ch->ctrl_start+6*16); + printk("%s: ptr1_reg: 0x%08x\n", + core->name,cx_read(ch->ptr1_reg)); + printk("%s: ptr2_reg: 0x%08x\n", + core->name,cx_read(ch->ptr2_reg)); + printk("%s: cnt1_reg: 0x%08x\n", + core->name,cx_read(ch->cnt1_reg)); + printk("%s: cnt2_reg: 0x%08x\n", + core->name,cx_read(ch->cnt2_reg)); +} + +static const char *cx88_pci_irqs[32] = { + "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1", + "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err", + "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err", + "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1" +}; + +void cx88_print_irqbits(const char *name, const char *tag, const char *strings[], + int len, u32 bits, u32 mask) +{ + unsigned int i; + + printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits); + for (i = 0; i < len; i++) { + if (!(bits & (1 << i))) + continue; + if (strings[i]) + printk(" %s", strings[i]); + else + printk(" %d", i); + if (!(mask & (1 << i))) + continue; + printk("*"); + } + printk("\n"); +} + +/* ------------------------------------------------------------------ */ + +int cx88_core_irq(struct cx88_core *core, u32 status) +{ + int handled = 0; + + if (status & PCI_INT_IR_SMPINT) { + cx88_ir_irq(core); + handled++; + } + if (!handled) + cx88_print_irqbits(core->name, "irq pci", + cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs), + status, core->pci_irqmask); + return handled; +} + +void cx88_wakeup(struct cx88_core *core, + struct cx88_dmaqueue *q, u32 count) +{ + struct cx88_buffer *buf; + int bc; + + for (bc = 0;; bc++) { + if (list_empty(&q->active)) + break; + buf = list_entry(q->active.next, + struct cx88_buffer, vb.queue); + /* count comes from the hw and is is 16bit wide -- + * this trick handles wrap-arounds correctly for + * up to 32767 buffers in flight... */ + if ((s16) (count - buf->count) < 0) + break; + do_gettimeofday(&buf->vb.ts); + dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, + count, buf->count); + buf->vb.state = VIDEOBUF_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + } + if (list_empty(&q->active)) { + del_timer(&q->timeout); + } else { + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + } + if (bc != 1) + dprintk(2, "%s: %d buffers handled (should be 1)\n", + __func__, bc); +} + +void cx88_shutdown(struct cx88_core *core) +{ + /* disable RISC controller + IRQs */ + cx_write(MO_DEV_CNTRL2, 0); + + /* stop dma transfers */ + cx_write(MO_VID_DMACNTRL, 0x0); + cx_write(MO_AUD_DMACNTRL, 0x0); + cx_write(MO_TS_DMACNTRL, 0x0); + cx_write(MO_VIP_DMACNTRL, 0x0); + cx_write(MO_GPHST_DMACNTRL, 0x0); + + /* stop interrupts */ + cx_write(MO_PCI_INTMSK, 0x0); + cx_write(MO_VID_INTMSK, 0x0); + cx_write(MO_AUD_INTMSK, 0x0); + cx_write(MO_TS_INTMSK, 0x0); + cx_write(MO_VIP_INTMSK, 0x0); + cx_write(MO_GPHST_INTMSK, 0x0); + + /* stop capturing */ + cx_write(VID_CAPTURE_CONTROL, 0); +} + +int cx88_reset(struct cx88_core *core) +{ + dprintk(1,"%s\n",__func__); + cx88_shutdown(core); + + /* clear irq status */ + cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int + cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int + cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int + + /* wait a bit */ + msleep(100); + + /* init sram */ + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0); + + /* misc init ... */ + cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable + (1 << 12) | // agc gain + (1 << 11) | // adaptibe agc + (0 << 10) | // chroma agc + (0 << 9) | // ckillen + (7))); + + /* setup image format */ + cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000); + + /* setup FIFO Thresholds */ + cx_write(MO_PDMA_STHRSH, 0x0807); + cx_write(MO_PDMA_DTHRSH, 0x0807); + + /* fixes flashing of image */ + cx_write(MO_AGC_SYNC_TIP1, 0x0380000F); + cx_write(MO_AGC_BACK_VBI, 0x00E00555); + + cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int + cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int + cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int + + /* Reset on-board parts */ + cx_write(MO_SRST_IO, 0); + msleep(10); + cx_write(MO_SRST_IO, 1); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static unsigned int inline norm_swidth(v4l2_std_id norm) +{ + return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; +} + +static unsigned int inline norm_hdelay(v4l2_std_id norm) +{ + return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186; +} + +static unsigned int inline norm_vdelay(v4l2_std_id norm) +{ + return (norm & V4L2_STD_625_50) ? 0x24 : 0x18; +} + +static unsigned int inline norm_fsc8(v4l2_std_id norm) +{ + if (norm & V4L2_STD_PAL_M) + return 28604892; // 3.575611 MHz + + if (norm & (V4L2_STD_PAL_Nc)) + return 28656448; // 3.582056 MHz + + if (norm & V4L2_STD_NTSC) // All NTSC/M and variants + return 28636360; // 3.57954545 MHz +/- 10 Hz + + /* SECAM have also different sub carrier for chroma, + but step_db and step_dr, at cx88_set_tvnorm already handles that. + + The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N + */ + + return 35468950; // 4.43361875 MHz +/- 5 Hz +} + +static unsigned int inline norm_htotal(v4l2_std_id norm) +{ + + unsigned int fsc4=norm_fsc8(norm)/2; + + /* returns 4*FSC / vtotal / frames per seconds */ + return (norm & V4L2_STD_625_50) ? + ((fsc4+312)/625+12)/25 : + ((fsc4+262)/525*1001+15000)/30000; +} + +static unsigned int inline norm_vbipack(v4l2_std_id norm) +{ + return (norm & V4L2_STD_625_50) ? 511 : 400; +} + +int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height, + enum v4l2_field field) +{ + unsigned int swidth = norm_swidth(core->tvnorm); + unsigned int sheight = norm_maxh(core->tvnorm); + u32 value; + + dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height, + V4L2_FIELD_HAS_TOP(field) ? "T" : "", + V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", + v4l2_norm_to_name(core->tvnorm)); + if (!V4L2_FIELD_HAS_BOTH(field)) + height *= 2; + + // recalc H delay and scale registers + value = (width * norm_hdelay(core->tvnorm)) / swidth; + value &= 0x3fe; + cx_write(MO_HDELAY_EVEN, value); + cx_write(MO_HDELAY_ODD, value); + dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth); + + value = (swidth * 4096 / width) - 4096; + cx_write(MO_HSCALE_EVEN, value); + cx_write(MO_HSCALE_ODD, value); + dprintk(1,"set_scale: hscale 0x%04x\n", value); + + cx_write(MO_HACTIVE_EVEN, width); + cx_write(MO_HACTIVE_ODD, width); + dprintk(1,"set_scale: hactive 0x%04x\n", width); + + // recalc V scale Register (delay is constant) + cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm)); + cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm)); + dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm)); + + value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff; + cx_write(MO_VSCALE_EVEN, value); + cx_write(MO_VSCALE_ODD, value); + dprintk(1,"set_scale: vscale 0x%04x\n", value); + + cx_write(MO_VACTIVE_EVEN, sheight); + cx_write(MO_VACTIVE_ODD, sheight); + dprintk(1,"set_scale: vactive 0x%04x\n", sheight); + + // setup filters + value = 0; + value |= (1 << 19); // CFILT (default) + if (core->tvnorm & V4L2_STD_SECAM) { + value |= (1 << 15); + value |= (1 << 16); + } + if (INPUT(core->input).type == CX88_VMUX_SVIDEO) + value |= (1 << 13) | (1 << 5); + if (V4L2_FIELD_INTERLACED == field) + value |= (1 << 3); // VINT (interlaced vertical scaling) + if (width < 385) + value |= (1 << 0); // 3-tap interpolation + if (width < 193) + value |= (1 << 1); // 5-tap interpolation + if (nocomb) + value |= (3 << 5); // disable comb filter + + cx_write(MO_FILTER_EVEN, value); + cx_write(MO_FILTER_ODD, value); + dprintk(1,"set_scale: filter 0x%04x\n", value); + + return 0; +} + +static const u32 xtal = 28636363; + +static int set_pll(struct cx88_core *core, int prescale, u32 ofreq) +{ + static const u32 pre[] = { 0, 0, 0, 3, 2, 1 }; + u64 pll; + u32 reg; + int i; + + if (prescale < 2) + prescale = 2; + if (prescale > 5) + prescale = 5; + + pll = ofreq * 8 * prescale * (u64)(1 << 20); + do_div(pll,xtal); + reg = (pll & 0x3ffffff) | (pre[prescale] << 26); + if (((reg >> 20) & 0x3f) < 14) { + printk("%s/0: pll out of range\n",core->name); + return -1; + } + + dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n", + reg, cx_read(MO_PLL_REG), ofreq); + cx_write(MO_PLL_REG, reg); + for (i = 0; i < 100; i++) { + reg = cx_read(MO_DEVICE_STATUS); + if (reg & (1<<2)) { + dprintk(1,"pll locked [pre=%d,ofreq=%d]\n", + prescale,ofreq); + return 0; + } + dprintk(1,"pll not locked yet, waiting ...\n"); + msleep(10); + } + dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq); + return -1; +} + +int cx88_start_audio_dma(struct cx88_core *core) +{ + /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */ + int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4; + + int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES; + + /* If downstream RISC is enabled, bail out; ALSA is managing DMA */ + if (cx_read(MO_AUD_DMACNTRL) & 0x10) + return 0; + + /* setup fifo + format */ + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], + rds_bpl, 0); + + cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */ + cx_write(MO_AUDR_LNGTH, rds_bpl); /* fifo bpl size */ + + /* enable Up, Down and Audio RDS fifo */ + cx_write(MO_AUD_DMACNTRL, 0x0007); + + return 0; +} + +int cx88_stop_audio_dma(struct cx88_core *core) +{ + /* If downstream RISC is enabled, bail out; ALSA is managing DMA */ + if (cx_read(MO_AUD_DMACNTRL) & 0x10) + return 0; + + /* stop dma */ + cx_write(MO_AUD_DMACNTRL, 0x0000); + + return 0; +} + +static int set_tvaudio(struct cx88_core *core) +{ + v4l2_std_id norm = core->tvnorm; + + if (CX88_VMUX_TELEVISION != INPUT(core->input).type && + CX88_VMUX_CABLE != INPUT(core->input).type) + return 0; + + if (V4L2_STD_PAL_BG & norm) { + core->tvaudio = WW_BG; + + } else if (V4L2_STD_PAL_DK & norm) { + core->tvaudio = WW_DK; + + } else if (V4L2_STD_PAL_I & norm) { + core->tvaudio = WW_I; + + } else if (V4L2_STD_SECAM_L & norm) { + core->tvaudio = WW_L; + + } else if ((V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H) & norm) { + core->tvaudio = WW_BG; + + } else if (V4L2_STD_SECAM_DK & norm) { + core->tvaudio = WW_DK; + + } else if ((V4L2_STD_NTSC_M & norm) || + (V4L2_STD_PAL_M & norm)) { + core->tvaudio = WW_BTSC; + + } else if (V4L2_STD_NTSC_M_JP & norm) { + core->tvaudio = WW_EIAJ; + + } else { + printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n", + core->name, v4l2_norm_to_name(core->tvnorm)); + core->tvaudio = WW_NONE; + return 0; + } + + cx_andor(MO_AFECFG_IO, 0x1f, 0x0); + cx88_set_tvaudio(core); + /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */ + +/* + This should be needed only on cx88-alsa. It seems that some cx88 chips have + bugs and does require DMA enabled for it to work. + */ + cx88_start_audio_dma(core); + return 0; +} + + + +int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) +{ + u32 fsc8; + u32 adc_clock; + u32 vdec_clock; + u32 step_db,step_dr; + u64 tmp64; + u32 bdelay,agcdelay,htotal; + u32 cxiformat, cxoformat; + + core->tvnorm = norm; + fsc8 = norm_fsc8(norm); + adc_clock = xtal; + vdec_clock = fsc8; + step_db = fsc8; + step_dr = fsc8; + + if (norm & V4L2_STD_NTSC_M_JP) { + cxiformat = VideoFormatNTSCJapan; + cxoformat = 0x181f0008; + } else if (norm & V4L2_STD_NTSC_443) { + cxiformat = VideoFormatNTSC443; + cxoformat = 0x181f0008; + } else if (norm & V4L2_STD_PAL_M) { + cxiformat = VideoFormatPALM; + cxoformat = 0x1c1f0008; + } else if (norm & V4L2_STD_PAL_N) { + cxiformat = VideoFormatPALN; + cxoformat = 0x1c1f0008; + } else if (norm & V4L2_STD_PAL_Nc) { + cxiformat = VideoFormatPALNC; + cxoformat = 0x1c1f0008; + } else if (norm & V4L2_STD_PAL_60) { + cxiformat = VideoFormatPAL60; + cxoformat = 0x181f0008; + } else if (norm & V4L2_STD_NTSC) { + cxiformat = VideoFormatNTSC; + cxoformat = 0x181f0008; + } else if (norm & V4L2_STD_SECAM) { + step_db = 4250000 * 8; + step_dr = 4406250 * 8; + + cxiformat = VideoFormatSECAM; + cxoformat = 0x181f0008; + } else { /* PAL */ + cxiformat = VideoFormatPAL; + cxoformat = 0x181f0008; + } + + dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n", + v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock, + step_db, step_dr); + set_pll(core,2,vdec_clock); + + dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n", + cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f); + /* Chroma AGC must be disabled if SECAM is used, we enable it + by default on PAL and NTSC */ + cx_andor(MO_INPUT_FORMAT, 0x40f, + norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400); + + // FIXME: as-is from DScaler + dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n", + cxoformat, cx_read(MO_OUTPUT_FORMAT)); + cx_write(MO_OUTPUT_FORMAT, cxoformat); + + // MO_SCONV_REG = adc clock / video dec clock * 2^17 + tmp64 = adc_clock * (u64)(1 << 17); + do_div(tmp64, vdec_clock); + dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n", + (u32)tmp64, cx_read(MO_SCONV_REG)); + cx_write(MO_SCONV_REG, (u32)tmp64); + + // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22 + tmp64 = step_db * (u64)(1 << 22); + do_div(tmp64, vdec_clock); + dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n", + (u32)tmp64, cx_read(MO_SUB_STEP)); + cx_write(MO_SUB_STEP, (u32)tmp64); + + // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22 + tmp64 = step_dr * (u64)(1 << 22); + do_div(tmp64, vdec_clock); + dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n", + (u32)tmp64, cx_read(MO_SUB_STEP_DR)); + cx_write(MO_SUB_STEP_DR, (u32)tmp64); + + // bdelay + agcdelay + bdelay = vdec_clock * 65 / 20000000 + 21; + agcdelay = vdec_clock * 68 / 20000000 + 15; + dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n", + (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay); + cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay); + + // htotal + tmp64 = norm_htotal(norm) * (u64)vdec_clock; + do_div(tmp64, fsc8); + htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11); + dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n", + htotal, cx_read(MO_HTOTAL), (u32)tmp64); + cx_write(MO_HTOTAL, htotal); + + // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes + // the effective vbi offset ~244 samples, the same as the Bt8x8 + cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm)); + + // this is needed as well to set all tvnorm parameter + cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED); + + // audio + set_tvaudio(core); + + // tell i2c chips + call_all(core, core, s_std, norm); + + // done + return 0; +} + +/* ------------------------------------------------------------------ */ + +struct video_device *cx88_vdev_init(struct cx88_core *core, + struct pci_dev *pci, + const struct video_device *template_, + const char *type) +{ + struct video_device *vfd; + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template_; + vfd->v4l2_dev = &core->v4l2_dev; + vfd->parent = &pci->dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", + core->name, type, core->board.name); + return vfd; +} + +struct cx88_core* cx88_core_get(struct pci_dev *pci) +{ + struct cx88_core *core; + + mutex_lock(&devlist); + list_for_each_entry(core, &cx88_devlist, devlist) { + if (pci->bus->number != core->pci_bus) + continue; + if (PCI_SLOT(pci->devfn) != core->pci_slot) + continue; + + if (0 != cx88_get_resources(core, pci)) { + mutex_unlock(&devlist); + return NULL; + } + atomic_inc(&core->refcount); + mutex_unlock(&devlist); + return core; + } + + core = cx88_core_create(pci, cx88_devcount); + if (NULL != core) { + cx88_devcount++; + list_add_tail(&core->devlist, &cx88_devlist); + } + + mutex_unlock(&devlist); + return core; +} + +void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) +{ + release_mem_region(pci_resource_start(pci,0), + pci_resource_len(pci,0)); + + if (!atomic_dec_and_test(&core->refcount)) + return; + + mutex_lock(&devlist); + cx88_ir_fini(core); + if (0 == core->i2c_rc) { + if (core->i2c_rtc) + i2c_unregister_device(core->i2c_rtc); + i2c_del_adapter(&core->i2c_adap); + } + list_del(&core->devlist); + iounmap(core->lmmio); + cx88_devcount--; + mutex_unlock(&devlist); + v4l2_device_unregister(&core->v4l2_dev); + kfree(core); +} + +/* ------------------------------------------------------------------ */ + +EXPORT_SYMBOL(cx88_print_irqbits); + +EXPORT_SYMBOL(cx88_core_irq); +EXPORT_SYMBOL(cx88_wakeup); +EXPORT_SYMBOL(cx88_reset); +EXPORT_SYMBOL(cx88_shutdown); + +EXPORT_SYMBOL(cx88_risc_buffer); +EXPORT_SYMBOL(cx88_risc_databuffer); +EXPORT_SYMBOL(cx88_risc_stopper); +EXPORT_SYMBOL(cx88_free_buffer); + +EXPORT_SYMBOL(cx88_sram_channels); +EXPORT_SYMBOL(cx88_sram_channel_setup); +EXPORT_SYMBOL(cx88_sram_channel_dump); + +EXPORT_SYMBOL(cx88_set_tvnorm); +EXPORT_SYMBOL(cx88_set_scale); + +EXPORT_SYMBOL(cx88_vdev_init); +EXPORT_SYMBOL(cx88_core_get); +EXPORT_SYMBOL(cx88_core_put); + +EXPORT_SYMBOL(cx88_ir_start); +EXPORT_SYMBOL(cx88_ir_stop); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-dsp.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-dsp.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-dsp.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-dsp.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,322 @@ +/* + * + * Stereo and SAP detection for cx88 + * + * Copyright (c) 2009 Marton Balint + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "cx88.h" +#include "cx88-reg.h" + +#define INT_PI ((s32)(3.141592653589 * 32768.0)) + +#define compat_remainder(a, b) \ + ((float)(((s32)((a)*100))%((s32)((b)*100)))/100.0) + +#define baseband_freq(carrier, srate, tone) ((s32)( \ + (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI)) + +/* We calculate the baseband frequencies of the carrier and the pilot tones + * based on the the sampling rate of the audio rds fifo. */ + +#define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0) +#define FREQ_A2_DUAL baseband_freq(54687.5, 2689.36, 274.1) +#define FREQ_A2_STEREO baseband_freq(54687.5, 2689.36, 117.5) + +/* The frequencies below are from the reference driver. They probably need + * further adjustments, because they are not tested at all. You may even need + * to play a bit with the registers of the chip to select the proper signal + * for the input of the audio rds fifo, and measure it's sampling rate to + * calculate the proper baseband frequencies... */ + +#define FREQ_A2M_CARRIER ((s32)(2.114516 * 32768.0)) +#define FREQ_A2M_DUAL ((s32)(2.754916 * 32768.0)) +#define FREQ_A2M_STEREO ((s32)(2.462326 * 32768.0)) + +#define FREQ_EIAJ_CARRIER ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ +#define FREQ_EIAJ_DUAL ((s32)(2.562118 * 32768.0)) +#define FREQ_EIAJ_STEREO ((s32)(2.601053 * 32768.0)) + +#define FREQ_BTSC_DUAL ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ +#define FREQ_BTSC_DUAL_REF ((s32)(1.374446 * 32768.0)) /* 7pi/16 */ + +#define FREQ_BTSC_SAP ((s32)(2.471532 * 32768.0)) +#define FREQ_BTSC_SAP_REF ((s32)(1.730072 * 32768.0)) + +/* The spectrum of the signal should be empty between these frequencies. */ +#define FREQ_NOISE_START ((s32)(0.100000 * 32768.0)) +#define FREQ_NOISE_END ((s32)(1.200000 * 32768.0)) + +static unsigned int dsp_debug; +module_param(dsp_debug, int, 0644); +MODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages"); + +#define dprintk(level, fmt, arg...) if (dsp_debug >= level) \ + printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) + +static s32 int_cos(u32 x) +{ + u32 t2, t4, t6, t8; + s32 ret; + u16 period = x / INT_PI; + if (period % 2) + return -int_cos(x - INT_PI); + x = x % INT_PI; + if (x > INT_PI/2) + return -int_cos(INT_PI/2 - (x % (INT_PI/2))); + /* Now x is between 0 and INT_PI/2. + * To calculate cos(x) we use it's Taylor polinom. */ + t2 = x*x/32768/2; + t4 = t2*x/32768*x/32768/3/4; + t6 = t4*x/32768*x/32768/5/6; + t8 = t6*x/32768*x/32768/7/8; + ret = 32768-t2+t4-t6+t8; + return ret; +} + +static u32 int_goertzel(s16 x[], u32 N, u32 freq) +{ + /* We use the Goertzel algorithm to determine the power of the + * given frequency in the signal */ + s32 s_prev = 0; + s32 s_prev2 = 0; + s32 coeff = 2*int_cos(freq); + u32 i; + + u64 tmp; + u32 divisor; + + for (i = 0; i < N; i++) { + s32 s = x[i] + ((s64)coeff*s_prev/32768) - s_prev2; + s_prev2 = s_prev; + s_prev = s; + } + + tmp = (s64)s_prev2 * s_prev2 + (s64)s_prev * s_prev - + (s64)coeff * s_prev2 * s_prev / 32768; + + /* XXX: N must be low enough so that N*N fits in s32. + * Else we need two divisions. */ + divisor = N * N; + do_div(tmp, divisor); + + return (u32) tmp; +} + +static u32 freq_magnitude(s16 x[], u32 N, u32 freq) +{ + u32 sum = int_goertzel(x, N, freq); + return (u32)int_sqrt(sum); +} + +static u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end) +{ + int i; + u32 sum = 0; + u32 freq_step; + int samples = 5; + + if (N > 192) { + /* The last 192 samples are enough for noise detection */ + x += (N-192); + N = 192; + } + + freq_step = (freq_end - freq_start) / (samples - 1); + + for (i = 0; i < samples; i++) { + sum += int_goertzel(x, N, freq_start); + freq_start += freq_step; + } + + return (u32)int_sqrt(sum / samples); +} + +static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) +{ + s32 carrier, stereo, dual, noise; + s32 carrier_freq, stereo_freq, dual_freq; + s32 ret; + + switch (core->tvaudio) { + case WW_BG: + case WW_DK: + carrier_freq = FREQ_A2_CARRIER; + stereo_freq = FREQ_A2_STEREO; + dual_freq = FREQ_A2_DUAL; + break; + case WW_M: + carrier_freq = FREQ_A2M_CARRIER; + stereo_freq = FREQ_A2M_STEREO; + dual_freq = FREQ_A2M_DUAL; + break; + case WW_EIAJ: + carrier_freq = FREQ_EIAJ_CARRIER; + stereo_freq = FREQ_EIAJ_STEREO; + dual_freq = FREQ_EIAJ_DUAL; + break; + default: + printk(KERN_WARNING "%s/0: unsupported audio mode %d for %s\n", + core->name, core->tvaudio, __func__); + return UNSET; + } + + carrier = freq_magnitude(x, N, carrier_freq); + stereo = freq_magnitude(x, N, stereo_freq); + dual = freq_magnitude(x, N, dual_freq); + noise = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END); + + dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, " + "noise=%d\n", carrier, stereo, dual, noise); + + if (stereo > dual) + ret = V4L2_TUNER_SUB_STEREO; + else + ret = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + + if (core->tvaudio == WW_EIAJ) { + /* EIAJ checks may need adjustments */ + if ((carrier > max(stereo, dual)*2) && + (carrier < max(stereo, dual)*6) && + (carrier > 20 && carrier < 200) && + (max(stereo, dual) > min(stereo, dual))) { + /* For EIAJ the carrier is always present, + so we probably don't need noise detection */ + return ret; + } + } else { + if ((carrier > max(stereo, dual)*2) && + (carrier < max(stereo, dual)*8) && + (carrier > 20 && carrier < 200) && + (noise < 10) && + (max(stereo, dual) > min(stereo, dual)*2)) { + return ret; + } + } + return V4L2_TUNER_SUB_MONO; +} + +static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N) +{ + s32 sap_ref = freq_magnitude(x, N, FREQ_BTSC_SAP_REF); + s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP); + s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF); + s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL); + dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d" + "\n", dual_ref, dual, sap_ref, sap); + /* FIXME: Currently not supported */ + return UNSET; +} + +static s16 *read_rds_samples(struct cx88_core *core, u32 *N) +{ + const struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27]; + s16 *samples; + + unsigned int i; + unsigned int bpl = srch->fifo_size/AUD_RDS_LINES; + unsigned int spl = bpl/4; + unsigned int sample_count = spl*(AUD_RDS_LINES-1); + + u32 current_address = cx_read(srch->ptr1_reg); + u32 offset = (current_address - srch->fifo_start + bpl); + + dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), " + "sample_count=%d, aud_intstat=%08x\n", current_address, + current_address - srch->fifo_start, sample_count, + cx_read(MO_AUD_INTSTAT)); + + samples = kmalloc(sizeof(s16)*sample_count, GFP_KERNEL); + if (!samples) + return NULL; + + *N = sample_count; + + for (i = 0; i < sample_count; i++) { + offset = offset % (AUD_RDS_LINES*bpl); + samples[i] = cx_read(srch->fifo_start + offset); + offset += 4; + } + + if (dsp_debug >= 2) { + dprintk(2, "RDS samples dump: "); + for (i = 0; i < sample_count; i++) + printk("%hd ", samples[i]); + printk(".\n"); + } + + return samples; +} + +s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core) +{ + s16 *samples; + u32 N = 0; + s32 ret = UNSET; + + /* If audio RDS fifo is disabled, we can't read the samples */ + if (!(cx_read(MO_AUD_DMACNTRL) & 0x04)) + return ret; + if (!(cx_read(AUD_CTL) & EN_FMRADIO_EN_RDS)) + return ret; + + /* Wait at least 500 ms after an audio standard change */ + if (time_before(jiffies, core->last_change + msecs_to_jiffies(500))) + return ret; + + samples = read_rds_samples(core, &N); + + if (!samples) + return ret; + + switch (core->tvaudio) { + case WW_BG: + case WW_DK: + case WW_EIAJ: + case WW_M: + ret = detect_a2_a2m_eiaj(core, samples, N); + break; + case WW_BTSC: + ret = detect_btsc(core, samples, N); + break; + case WW_NONE: + case WW_I: + case WW_L: + case WW_I2SPT: + case WW_FM: + case WW_I2SADC: + break; + } + + kfree(samples); + + if (UNSET != ret) + dprintk(1, "stereo/sap detection result:%s%s%s\n", + (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "", + (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", + (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : ""); + + return ret; +} +EXPORT_SYMBOL(cx88_dsp_detect_stereo_sap); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-dvb.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1776 @@ +/* + * + * device driver for Conexant 2388x based TV cards + * MPEG Transport Stream (DVB) routines + * + * (c) 2004, 2005 Chris Pascoe + * (c) 2004 Gerd Knorr [SuSE Labs] + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cx88.h" +#include "dvb-pll.h" +#include + +#include "mt352.h" +#include "mt352_priv.h" +#include "cx88-vp3054-i2c.h" +#include "zl10353.h" +#include "cx22702.h" +#include "or51132.h" +#include "lgdt330x.h" +#include "s5h1409.h" +#include "xc4000.h" +#include "xc5000.h" +#include "nxt200x.h" +#include "cx24123.h" +#include "isl6421.h" +#include "tuner-simple.h" +#include "tda9887.h" +#include "s5h1411.h" +#include "stv0299.h" +#include "z0194a.h" +#include "stv0288.h" +#include "stb6000.h" +#include "cx24116.h" +#include "stv0900.h" +#include "stb6100.h" +#include "stb6100_proc.h" +#include "mb86a16.h" +#include "ds3000.h" + +MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); +MODULE_AUTHOR("Chris Pascoe "); +MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); +MODULE_LICENSE("GPL"); + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"enable debug messages [dvb]"); + +static unsigned int dvb_buf_tscnt = 32; +module_param(dvb_buf_tscnt, int, 0644); +MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg) + +/* ------------------------------------------------------------------ */ + +static int dvb_buf_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct cx8802_dev *dev = q->priv_data; + + dev->ts_packet_size = 188 * 4; + dev->ts_packet_count = dvb_buf_tscnt; + + *size = dev->ts_packet_size * dev->ts_packet_count; + *count = dvb_buf_tscnt; + return 0; +} + +static int dvb_buf_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) +{ + struct cx8802_dev *dev = q->priv_data; + return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field); +} + +static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx8802_dev *dev = q->priv_data; + cx8802_buf_queue(dev, (struct cx88_buffer*)vb); +} + +static void dvb_buf_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + cx88_free_buffer(q, (struct cx88_buffer*)vb); +} + +static const struct videobuf_queue_ops dvb_qops = { + .buf_setup = dvb_buf_setup, + .buf_prepare = dvb_buf_prepare, + .buf_queue = dvb_buf_queue, + .buf_release = dvb_buf_release, +}; + +/* ------------------------------------------------------------------ */ + +static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_driver *drv = NULL; + int ret = 0; + int fe_id; + + fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe); + if (!fe_id) { + printk(KERN_ERR "%s() No frontend found\n", __func__); + return -EINVAL; + } + + mutex_lock(&dev->core->lock); + drv = cx8802_get_driver(dev, CX88_MPEG_DVB); + if (drv) { + if (acquire){ + dev->frontends.active_fe_id = fe_id; + ret = drv->request_acquire(drv); + } else { + ret = drv->request_release(drv); + dev->frontends.active_fe_id = 0; + } + } + mutex_unlock(&dev->core->lock); + + return ret; +} + +static void cx88_dvb_gate_ctrl(struct cx88_core *core, int open) +{ + struct videobuf_dvb_frontends *f; + struct videobuf_dvb_frontend *fe; + + if (!core->dvbdev) + return; + + f = &core->dvbdev->frontends; + + if (!f) + return; + + if (f->gate <= 1) /* undefined or fe0 */ + fe = videobuf_dvb_get_frontend(f, 1); + else + fe = videobuf_dvb_get_frontend(f, f->gate); + + if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) + fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); +} + +/* ------------------------------------------------------------------ */ + +static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe) +{ + static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 }; + static const u8 reset [] = { RESET, 0x80 }; + static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static const u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; + static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + return 0; +} + +static int dvico_dual_demod_init(struct dvb_frontend *fe) +{ + static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 }; + static const u8 reset [] = { RESET, 0x80 }; + static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static const u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; + static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe) +{ + static const u8 clock_config [] = { 0x89, 0x38, 0x39 }; + static const u8 reset [] = { 0x50, 0x80 }; + static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static const u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x40, 0x40 }; + static const u8 dntv_extra[] = { 0xB5, 0x7A }; + static const u8 capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(2000); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + udelay(2000); + mt352_write(fe, dntv_extra, sizeof(dntv_extra)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +static const struct mt352_config dvico_fusionhdtv = { + .demod_address = 0x0f, + .demod_init = dvico_fusionhdtv_demod_init, +}; + +static const struct mt352_config dntv_live_dvbt_config = { + .demod_address = 0x0f, + .demod_init = dntv_live_dvbt_demod_init, +}; + +static const struct mt352_config dvico_fusionhdtv_dual = { + .demod_address = 0x0f, + .demod_init = dvico_dual_demod_init, +}; + +static const struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .if2 = 45600, +}; + +static struct mb86a16_config twinhan_vp1027 = { + .demod_address = 0x08, +}; + +#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) +static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe) +{ + static const u8 clock_config [] = { 0x89, 0x38, 0x38 }; + static const u8 reset [] = { 0x50, 0x80 }; + static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static const u8 agc_cfg [] = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x40, 0x40 }; + static const u8 dntv_extra[] = { 0xB5, 0x7A }; + static const u8 capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(2000); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + udelay(2000); + mt352_write(fe, dntv_extra, sizeof(dntv_extra)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +static const struct mt352_config dntv_live_dvbt_pro_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .demod_init = dntv_live_dvbt_pro_demod_init, +}; +#endif + +static const struct zl10353_config dvico_fusionhdtv_hybrid = { + .demod_address = 0x0f, + .no_tuner = 1, +}; + +static const struct zl10353_config dvico_fusionhdtv_xc3028 = { + .demod_address = 0x0f, + .if2 = 45600, + .no_tuner = 1, +}; + +static const struct mt352_config dvico_fusionhdtv_mt352_xc3028 = { + .demod_address = 0x0f, + .if2 = 4560, + .no_tuner = 1, + .demod_init = dvico_fusionhdtv_demod_init, +}; + +static const struct zl10353_config dvico_fusionhdtv_plus_v1_1 = { + .demod_address = 0x0f, +}; + +static const struct cx22702_config connexant_refboard_config = { + .demod_address = 0x43, + .output_mode = CX22702_SERIAL_OUTPUT, +}; + +static const struct cx22702_config hauppauge_hvr_config = { + .demod_address = 0x63, + .output_mode = CX22702_SERIAL_OUTPUT, +}; + +static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) +{ + struct cx8802_dev *dev= fe->dvb->priv; + dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; + return 0; +} + +static const struct or51132_config pchdtv_hd3000 = { + .demod_address = 0x15, + .set_ts_params = or51132_set_ts_param, +}; + +static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx88_core *core = dev->core; + + dprintk(1, "%s: index = %d\n", __func__, index); + if (index == 0) + cx_clear(MO_GP0_IO, 8); + else + cx_set(MO_GP0_IO, 8); + return 0; +} + +static int lgdt330x_set_ts_param(struct dvb_frontend* fe, int is_punctured) +{ + struct cx8802_dev *dev= fe->dvb->priv; + if (is_punctured) + dev->ts_gen_cntrl |= 0x04; + else + dev->ts_gen_cntrl &= ~0x04; + return 0; +} + +static struct lgdt330x_config fusionhdtv_3_gold = { + .demod_address = 0x0e, + .demod_chip = LGDT3302, + .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */ + .set_ts_params = lgdt330x_set_ts_param, +}; + +static const struct lgdt330x_config fusionhdtv_5_gold = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ + .set_ts_params = lgdt330x_set_ts_param, +}; + +static const struct lgdt330x_config pchdtv_hd5500 = { + .demod_address = 0x59, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ + .set_ts_params = lgdt330x_set_ts_param, +}; + +static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured) +{ + struct cx8802_dev *dev= fe->dvb->priv; + dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; + return 0; +} + +static const struct nxt200x_config ati_hdtvwonder = { + .demod_address = 0x0a, + .set_ts_params = nxt200x_set_ts_param, +}; + +static int cx24123_set_ts_param(struct dvb_frontend* fe, + int is_punctured) +{ + struct cx8802_dev *dev= fe->dvb->priv; + dev->ts_gen_cntrl = 0x02; + return 0; +} + +static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, + fe_sec_voltage_t voltage) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx88_core *core = dev->core; + + if (voltage == SEC_VOLTAGE_OFF) + cx_write(MO_GP0_IO, 0x000006fb); + else + cx_write(MO_GP0_IO, 0x000006f9); + + if (core->prev_set_voltage) + return core->prev_set_voltage(fe, voltage); + return 0; +} + +static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx88_core *core = dev->core; + + if (voltage == SEC_VOLTAGE_OFF) { + dprintk(1,"LNB Voltage OFF\n"); + cx_write(MO_GP0_IO, 0x0000efff); + } + + if (core->prev_set_voltage) + return core->prev_set_voltage(fe, voltage); + return 0; +} + +static int tevii_dvbs_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx88_core *core = dev->core; + + cx_set(MO_GP0_IO, 0x6040); + switch (voltage) { + case SEC_VOLTAGE_13: + cx_clear(MO_GP0_IO, 0x20); + break; + case SEC_VOLTAGE_18: + cx_set(MO_GP0_IO, 0x20); + break; + case SEC_VOLTAGE_OFF: + cx_clear(MO_GP0_IO, 0x20); + break; + } + + if (core->prev_set_voltage) + return core->prev_set_voltage(fe, voltage); + return 0; +} + +static int vp1027_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx8802_dev *dev = fe->dvb->priv; + struct cx88_core *core = dev->core; + + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk(1, "LNB SEC Voltage=13\n"); + cx_write(MO_GP0_IO, 0x00001220); + break; + case SEC_VOLTAGE_18: + dprintk(1, "LNB SEC Voltage=18\n"); + cx_write(MO_GP0_IO, 0x00001222); + break; + case SEC_VOLTAGE_OFF: + dprintk(1, "LNB Voltage OFF\n"); + cx_write(MO_GP0_IO, 0x00001230); + break; + } + + if (core->prev_set_voltage) + return core->prev_set_voltage(fe, voltage); + return 0; +} + +static const struct cx24123_config geniatech_dvbs_config = { + .demod_address = 0x55, + .set_ts_params = cx24123_set_ts_param, +}; + +static const struct cx24123_config hauppauge_novas_config = { + .demod_address = 0x55, + .set_ts_params = cx24123_set_ts_param, +}; + +static const struct cx24123_config kworld_dvbs_100_config = { + .demod_address = 0x15, + .set_ts_params = cx24123_set_ts_param, + .lnb_polarity = 1, +}; + +static const struct s5h1409_config pinnacle_pctv_hd_800i_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_PARALLEL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, +}; + +static const struct s5h1409_config dvico_hdtv5_pci_nano_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static const struct s5h1409_config kworld_atsc_120_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { + .i2c_address = 0x64, + .if_khz = 5380, +}; + +static const struct zl10353_config cx88_pinnacle_hybrid_pctv = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .if2 = 45600, +}; + +static const struct zl10353_config cx88_geniatech_x8000_mt = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .disable_i2c_gate_ctrl = 1, +}; + +static const struct s5h1411_config dvico_fusionhdtv7_config = { + .output_mode = S5H1411_SERIAL_OUTPUT, + .gpio = S5H1411_GPIO_ON, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .qam_if = S5H1411_IF_44000, + .vsb_if = S5H1411_IF_44000, + .inversion = S5H1411_INVERSION_OFF, + .status_mode = S5H1411_DEMODLOCKING +}; + +static const struct xc5000_config dvico_fusionhdtv7_tuner_config = { + .i2c_address = 0xc2 >> 1, + .if_khz = 5380, +}; + +static int attach_xc3028(u8 addr, struct cx8802_dev *dev) +{ + struct dvb_frontend *fe; + struct videobuf_dvb_frontend *fe0 = NULL; + struct xc2028_ctrl ctl; + struct xc2028_config cfg = { + .i2c_adap = &dev->core->i2c_adap, + .i2c_addr = addr, + .ctrl = &ctl, + }; + + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); + if (!fe0) + return -EINVAL; + + if (!fe0->dvb.frontend) { + printk(KERN_ERR "%s/2: dvb frontend not attached. " + "Can't attach xc3028\n", + dev->core->name); + return -EINVAL; + } + + /* + * Some xc3028 devices may be hidden by an I2C gate. This is known + * to happen with some s5h1409-based devices. + * Now that I2C gate is open, sets up xc3028 configuration + */ + cx88_setup_xc3028(dev->core, &ctl); + + fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); + if (!fe) { + printk(KERN_ERR "%s/2: xc3028 attach failed\n", + dev->core->name); + dvb_frontend_detach(fe0->dvb.frontend); + dvb_unregister_frontend(fe0->dvb.frontend); + fe0->dvb.frontend = NULL; + return -EINVAL; + } + + printk(KERN_INFO "%s/2: xc3028 attached\n", + dev->core->name); + + return 0; +} + +static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg) +{ + struct dvb_frontend *fe; + struct videobuf_dvb_frontend *fe0 = NULL; + + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); + if (!fe0) + return -EINVAL; + + if (!fe0->dvb.frontend) { + printk(KERN_ERR "%s/2: dvb frontend not attached. " + "Can't attach xc4000\n", + dev->core->name); + return -EINVAL; + } + + fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap, + cfg); + if (!fe) { + printk(KERN_ERR "%s/2: xc4000 attach failed\n", + dev->core->name); + dvb_frontend_detach(fe0->dvb.frontend); + dvb_unregister_frontend(fe0->dvb.frontend); + fe0->dvb.frontend = NULL; + return -EINVAL; + } + + printk(KERN_INFO "%s/2: xc4000 attached\n", dev->core->name); + + return 0; +} + +static int cx24116_set_ts_param(struct dvb_frontend *fe, + int is_punctured) +{ + struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = 0x2; + + return 0; +} + +static int stv0900_set_ts_param(struct dvb_frontend *fe, + int is_punctured) +{ + struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = 0; + + return 0; +} + +static int cx24116_reset_device(struct dvb_frontend *fe) +{ + struct cx8802_dev *dev = fe->dvb->priv; + struct cx88_core *core = dev->core; + + /* Reset the part */ + /* Put the cx24116 into reset */ + cx_write(MO_SRST_IO, 0); + msleep(10); + /* Take the cx24116 out of reset */ + cx_write(MO_SRST_IO, 1); + msleep(10); + + return 0; +} + +static const struct cx24116_config hauppauge_hvr4000_config = { + .demod_address = 0x05, + .set_ts_params = cx24116_set_ts_param, + .reset_device = cx24116_reset_device, +}; + +static const struct cx24116_config tevii_s460_config = { + .demod_address = 0x55, + .set_ts_params = cx24116_set_ts_param, + .reset_device = cx24116_reset_device, +}; + +static int ds3000_set_ts_param(struct dvb_frontend *fe, + int is_punctured) +{ + struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = 4; + + return 0; +} + +static struct ds3000_config tevii_ds3000_config = { + .demod_address = 0x68, + .set_ts_params = ds3000_set_ts_param, +}; + +static const struct stv0900_config prof_7301_stv0900_config = { + .demod_address = 0x6a, +/* demod_mode = 0,*/ + .xtal = 27000000, + .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ + .diseqc_mode = 2,/* 2/3 PWM */ + .tun1_maddress = 0,/* 0x60 */ + .tun1_adc = 0,/* 2 Vpp */ + .path1_mode = 3, + .set_ts_params = stv0900_set_ts_param, +}; + +static const struct stb6100_config prof_7301_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static const struct stv0299_config tevii_tuner_sharp_config = { + .demod_address = 0x68, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = 1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, + .set_ts_params = cx24116_set_ts_param, +}; + +static const struct stv0288_config tevii_tuner_earda_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + .set_ts_params = cx24116_set_ts_param, +}; + +static int cx8802_alloc_frontends(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + struct videobuf_dvb_frontend *fe = NULL; + int i; + + mutex_init(&dev->frontends.lock); + INIT_LIST_HEAD(&dev->frontends.felist); + + if (!core->board.num_frontends) + return -ENODEV; + + printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, + core->board.num_frontends); + for (i = 1; i <= core->board.num_frontends; i++) { + fe = videobuf_dvb_alloc_frontend(&dev->frontends, i); + if (!fe) { + printk(KERN_ERR "%s() failed to alloc\n", __func__); + videobuf_dvb_dealloc_frontends(&dev->frontends); + return -ENOMEM; + } + } + return 0; +} + + + +static const u8 samsung_smt_7020_inittab[] = { + 0x01, 0x15, + 0x02, 0x00, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x0F, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0x60, + + 0x0A, 0xC2, + 0x0B, 0x00, + 0x0C, 0x01, + 0x0D, 0x81, + 0x0E, 0x44, + 0x0F, 0x09, + 0x10, 0x3C, + 0x11, 0x84, + 0x12, 0xDA, + 0x13, 0x99, + 0x14, 0x8D, + 0x15, 0xCE, + 0x16, 0xE8, + 0x17, 0x43, + 0x18, 0x1C, + 0x19, 0x1B, + 0x1A, 0x1D, + + 0x1C, 0x12, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x00, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + + 0x28, 0x02, + 0x29, 0x28, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFC, + 0x34, 0x13, + 0xff, 0xff, +}; + + +static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct cx8802_dev *dev = fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = { + .addr = 0x61, + .flags = 0, + .buf = buf, + .len = sizeof(buf) }; + + div = params->frequency / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x84; /* 0xC4 */ + buf[3] = 0x00; + + if (params->frequency < 1500000) + buf[3] |= 0x10; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(&dev->core->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static int samsung_smt_7020_set_tone(struct dvb_frontend *fe, + fe_sec_tone_mode_t tone) +{ + struct cx8802_dev *dev = fe->dvb->priv; + struct cx88_core *core = dev->core; + + cx_set(MO_GP0_IO, 0x0800); + + switch (tone) { + case SEC_TONE_ON: + cx_set(MO_GP0_IO, 0x08); + break; + case SEC_TONE_OFF: + cx_clear(MO_GP0_IO, 0x08); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx8802_dev *dev = fe->dvb->priv; + struct cx88_core *core = dev->core; + + u8 data; + struct i2c_msg msg = { + .addr = 8, + .flags = 0, + .buf = &data, + .len = sizeof(data) }; + + cx_set(MO_GP0_IO, 0x8000); + + switch (voltage) { + case SEC_VOLTAGE_OFF: + break; + case SEC_VOLTAGE_13: + data = ISL6421_EN1 | ISL6421_LLC1; + cx_clear(MO_GP0_IO, 0x80); + break; + case SEC_VOLTAGE_18: + data = ISL6421_EN1 | ISL6421_LLC1 | ISL6421_VSEL1; + cx_clear(MO_GP0_IO, 0x80); + break; + default: + return -EINVAL; + }; + + return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO; +} + +static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; + bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; + bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; + bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; + bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; + bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; + bclk = 0x51; + } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, ratio & 0xf0); + + return 0; +} + + +static const struct stv0299_config samsung_stv0299_config = { + .demod_address = 0x68, + .inittab = samsung_smt_7020_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_LK, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate, +}; + +static int dvb_register(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + int mfe_shared = 0; /* bus not shared by default */ + + if (0 != core->i2c_rc) { + printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); + goto frontend_detach; + } + + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); + if (!fe0) + goto frontend_detach; + + /* multi-frontend gate control is undefined or defaults to fe0 */ + dev->frontends.gate = 0; + + /* Sets the gate control callback to be used by i2c command calls */ + core->gate_ctrl = cx88_dvb_gate_ctrl; + + /* init frontend(s) */ + switch (core->boardnr) { + case CX88_BOARD_HAUPPAUGE_DVB_T1: + fe0->dvb.frontend = dvb_attach(cx22702_attach, + &connexant_refboard_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, + 0x61, &core->i2c_adap, + DVB_PLL_THOMSON_DTT759X)) + goto frontend_detach; + } + break; + case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: + case CX88_BOARD_CONEXANT_DVB_T1: + case CX88_BOARD_KWORLD_DVB_T_CX22702: + case CX88_BOARD_WINFAST_DTV1000: + fe0->dvb.frontend = dvb_attach(cx22702_attach, + &connexant_refboard_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, + 0x60, &core->i2c_adap, + DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; + } + break; + case CX88_BOARD_WINFAST_DTV2000H: + case CX88_BOARD_WINFAST_DTV2000H_J: + case CX88_BOARD_HAUPPAUGE_HVR1100: + case CX88_BOARD_HAUPPAUGE_HVR1100LP: + case CX88_BOARD_HAUPPAUGE_HVR1300: + fe0->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; + } + break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + /* MFE frontend 1 */ + mfe_shared = 1; + dev->frontends.gate = 2; + /* DVB-S init */ + fe0->dvb.frontend = dvb_attach(cx24123_attach, + &hauppauge_novas_config, + &dev->core->i2c_adap); + if (fe0->dvb.frontend) { + if (!dvb_attach(isl6421_attach, + fe0->dvb.frontend, + &dev->core->i2c_adap, + 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; + } + /* MFE frontend 2 */ + fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); + if (!fe1) + goto frontend_detach; + /* DVB-T init */ + fe1->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (fe1->dvb.frontend) { + fe1->dvb.frontend->id = 1; + if (!dvb_attach(simple_tuner_attach, + fe1->dvb.frontend, + &dev->core->i2c_adap, + 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; + } + break; + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: + fe0->dvb.frontend = dvb_attach(mt352_attach, + &dvico_fusionhdtv, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, + 0x60, NULL, DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; + break; + } + /* ZL10353 replaces MT352 on later cards */ + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &dvico_fusionhdtv_plus_v1_1, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, + 0x60, NULL, DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; + } + break; + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: + /* The tin box says DEE1601, but it seems to be DTT7579 + * compatible, with a slightly different MT352 AGC gain. */ + fe0->dvb.frontend = dvb_attach(mt352_attach, + &dvico_fusionhdtv_dual, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, + 0x61, NULL, DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; + break; + } + /* ZL10353 replaces MT352 on later cards */ + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &dvico_fusionhdtv_plus_v1_1, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, + 0x61, NULL, DVB_PLL_THOMSON_DTT7579)) + goto frontend_detach; + } + break; + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: + fe0->dvb.frontend = dvb_attach(mt352_attach, + &dvico_fusionhdtv, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, + 0x61, NULL, DVB_PLL_LG_Z201)) + goto frontend_detach; + } + break; + case CX88_BOARD_KWORLD_DVB_T: + case CX88_BOARD_DNTV_LIVE_DVB_T: + case CX88_BOARD_ADSTECH_DVB_T_PCI: + fe0->dvb.frontend = dvb_attach(mt352_attach, + &dntv_live_dvbt_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, + 0x61, NULL, DVB_PLL_UNKNOWN_1)) + goto frontend_detach; + } + break; + case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: +#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) + /* MT352 is on a secondary I2C bus made from some GPIO lines */ + fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config, + &dev->vp3054->adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; + } +#else + printk(KERN_ERR "%s/2: built without vp3054 support\n", + core->name); +#endif + break; + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &dvico_fusionhdtv_hybrid, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_THOMSON_FE6600)) + goto frontend_detach; + } + break; + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &dvico_fusionhdtv_xc3028, + &core->i2c_adap); + if (fe0->dvb.frontend == NULL) + fe0->dvb.frontend = dvb_attach(mt352_attach, + &dvico_fusionhdtv_mt352_xc3028, + &core->i2c_adap); + /* + * On this board, the demod provides the I2C bus pullup. + * We must not permit gate_ctrl to be performed, or + * the xc3028 cannot communicate on the bus. + */ + if (fe0->dvb.frontend) + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (attach_xc3028(0x61, dev) < 0) + goto frontend_detach; + break; + case CX88_BOARD_PCHDTV_HD3000: + fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_THOMSON_DTT761X)) + goto frontend_detach; + } + break; + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: + dev->ts_gen_cntrl = 0x08; + + /* Do a hardware reset of chip before using it. */ + cx_clear(MO_GP0_IO, 1); + mdelay(100); + cx_set(MO_GP0_IO, 1); + mdelay(200); + + /* Select RF connector callback */ + fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set; + fe0->dvb.frontend = dvb_attach(lgdt330x_attach, + &fusionhdtv_3_gold, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_MICROTUNE_4042FI5)) + goto frontend_detach; + } + break; + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: + dev->ts_gen_cntrl = 0x08; + + /* Do a hardware reset of chip before using it. */ + cx_clear(MO_GP0_IO, 1); + mdelay(100); + cx_set(MO_GP0_IO, 9); + mdelay(200); + fe0->dvb.frontend = dvb_attach(lgdt330x_attach, + &fusionhdtv_3_gold, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_THOMSON_DTT761X)) + goto frontend_detach; + } + break; + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: + dev->ts_gen_cntrl = 0x08; + + /* Do a hardware reset of chip before using it. */ + cx_clear(MO_GP0_IO, 1); + mdelay(100); + cx_set(MO_GP0_IO, 1); + mdelay(200); + fe0->dvb.frontend = dvb_attach(lgdt330x_attach, + &fusionhdtv_5_gold, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_LG_TDVS_H06XF)) + goto frontend_detach; + if (!dvb_attach(tda9887_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x43)) + goto frontend_detach; + } + break; + case CX88_BOARD_PCHDTV_HD5500: + dev->ts_gen_cntrl = 0x08; + + /* Do a hardware reset of chip before using it. */ + cx_clear(MO_GP0_IO, 1); + mdelay(100); + cx_set(MO_GP0_IO, 1); + mdelay(200); + fe0->dvb.frontend = dvb_attach(lgdt330x_attach, + &pchdtv_hd5500, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_LG_TDVS_H06XF)) + goto frontend_detach; + if (!dvb_attach(tda9887_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x43)) + goto frontend_detach; + } + break; + case CX88_BOARD_ATI_HDTVWONDER: + fe0->dvb.frontend = dvb_attach(nxt200x_attach, + &ati_hdtvwonder, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_PHILIPS_TUV1236D)) + goto frontend_detach; + } + break; + case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: + case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: + fe0->dvb.frontend = dvb_attach(cx24123_attach, + &hauppauge_novas_config, + &core->i2c_adap); + if (fe0->dvb.frontend) { + if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; + } + break; + case CX88_BOARD_KWORLD_DVBS_100: + fe0->dvb.frontend = dvb_attach(cx24123_attach, + &kworld_dvbs_100_config, + &core->i2c_adap); + if (fe0->dvb.frontend) { + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage; + } + break; + case CX88_BOARD_GENIATECH_DVBS: + fe0->dvb.frontend = dvb_attach(cx24123_attach, + &geniatech_dvbs_config, + &core->i2c_adap); + if (fe0->dvb.frontend) { + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; + } + break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + fe0->dvb.frontend = dvb_attach(s5h1409_attach, + &pinnacle_pctv_hd_800i_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(xc5000_attach, fe0->dvb.frontend, + &core->i2c_adap, + &pinnacle_pctv_hd_800i_tuner_config)) + goto frontend_detach; + } + break; + case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: + fe0->dvb.frontend = dvb_attach(s5h1409_attach, + &dvico_hdtv5_pci_nano_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &core->i2c_adap, + .i2c_addr = 0x61, + }; + static struct xc2028_ctrl ctl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .scode_table = XC3028_FE_OREN538, + }; + + fe = dvb_attach(xc2028_attach, + fe0->dvb.frontend, &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctl); + } + break; + case CX88_BOARD_PINNACLE_HYBRID_PCTV: + case CX88_BOARD_WINFAST_DTV1800H: + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &cx88_pinnacle_hybrid_pctv, + &core->i2c_adap); + if (fe0->dvb.frontend) { + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (attach_xc3028(0x61, dev) < 0) + goto frontend_detach; + } + break; + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &cx88_pinnacle_hybrid_pctv, + &core->i2c_adap); + if (fe0->dvb.frontend) { + struct xc4000_config cfg = { + .i2c_address = 0x61, + .default_pm = 0, + .dvb_amplitude = 134, + .set_smoothedcvbs = 1, + .if_khz = 4560 + }; + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (attach_xc4000(dev, &cfg) < 0) + goto frontend_detach; + } + break; + case CX88_BOARD_GENIATECH_X8000_MT: + dev->ts_gen_cntrl = 0x00; + + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &cx88_geniatech_x8000_mt, + &core->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) + goto frontend_detach; + break; + case CX88_BOARD_KWORLD_ATSC_120: + fe0->dvb.frontend = dvb_attach(s5h1409_attach, + &kworld_atsc_120_config, + &core->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) + goto frontend_detach; + break; + case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &dvico_fusionhdtv7_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(xc5000_attach, fe0->dvb.frontend, + &core->i2c_adap, + &dvico_fusionhdtv7_tuner_config)) + goto frontend_detach; + } + break; + case CX88_BOARD_HAUPPAUGE_HVR4000: + /* MFE frontend 1 */ + mfe_shared = 1; + dev->frontends.gate = 2; + /* DVB-S/S2 Init */ + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &hauppauge_hvr4000_config, + &dev->core->i2c_adap); + if (fe0->dvb.frontend) { + if (!dvb_attach(isl6421_attach, + fe0->dvb.frontend, + &dev->core->i2c_adap, + 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; + } + /* MFE frontend 2 */ + fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); + if (!fe1) + goto frontend_detach; + /* DVB-T Init */ + fe1->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (fe1->dvb.frontend) { + fe1->dvb.frontend->id = 1; + if (!dvb_attach(simple_tuner_attach, + fe1->dvb.frontend, + &dev->core->i2c_adap, + 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; + } + break; + case CX88_BOARD_HAUPPAUGE_HVR4000LITE: + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &hauppauge_hvr4000_config, + &dev->core->i2c_adap); + if (fe0->dvb.frontend) { + if (!dvb_attach(isl6421_attach, + fe0->dvb.frontend, + &dev->core->i2c_adap, + 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; + } + break; + case CX88_BOARD_PROF_6200: + case CX88_BOARD_TBS_8910: + case CX88_BOARD_TEVII_S420: + fe0->dvb.frontend = dvb_attach(stv0299_attach, + &tevii_tuner_sharp_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, + &core->i2c_adap, DVB_PLL_OPERA1)) + goto frontend_detach; + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; + + } else { + fe0->dvb.frontend = dvb_attach(stv0288_attach, + &tevii_tuner_earda_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61, + &core->i2c_adap)) + goto frontend_detach; + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; + } + } + break; + case CX88_BOARD_TEVII_S460: + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &tevii_s460_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; + break; + case CX88_BOARD_TEVII_S464: + fe0->dvb.frontend = dvb_attach(ds3000_attach, + &tevii_ds3000_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = + tevii_dvbs_set_voltage; + break; + case CX88_BOARD_OMICOM_SS4_PCI: + case CX88_BOARD_TBS_8920: + case CX88_BOARD_PROF_7300: + case CX88_BOARD_SATTRADE_ST4200: + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &hauppauge_hvr4000_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; + break; + case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII: + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &cx88_terratec_cinergy_ht_pci_mkii_config, + &core->i2c_adap); + if (fe0->dvb.frontend) { + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (attach_xc3028(0x61, dev) < 0) + goto frontend_detach; + } + break; + case CX88_BOARD_PROF_7301:{ + struct dvb_tuner_ops *tuner_ops = NULL; + + fe0->dvb.frontend = dvb_attach(stv0900_attach, + &prof_7301_stv0900_config, + &core->i2c_adap, 0); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(stb6100_attach, fe0->dvb.frontend, + &prof_7301_stb6100_config, + &core->i2c_adap)) + goto frontend_detach; + + tuner_ops = &fe0->dvb.frontend->ops.tuner_ops; + tuner_ops->set_frequency = stb6100_set_freq; + tuner_ops->get_frequency = stb6100_get_freq; + tuner_ops->set_bandwidth = stb6100_set_bandw; + tuner_ops->get_bandwidth = stb6100_get_bandw; + + core->prev_set_voltage = + fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = + tevii_dvbs_set_voltage; + } + break; + } + case CX88_BOARD_SAMSUNG_SMT_7020: + dev->ts_gen_cntrl = 0x08; + + cx_set(MO_GP0_IO, 0x0101); + + cx_clear(MO_GP0_IO, 0x01); + mdelay(100); + cx_set(MO_GP0_IO, 0x01); + mdelay(200); + + fe0->dvb.frontend = dvb_attach(stv0299_attach, + &samsung_stv0299_config, + &dev->core->i2c_adap); + if (fe0->dvb.frontend) { + fe0->dvb.frontend->ops.tuner_ops.set_params = + samsung_smt_7020_tuner_set_params; + fe0->dvb.frontend->tuner_priv = + &dev->core->i2c_adap; + fe0->dvb.frontend->ops.set_voltage = + samsung_smt_7020_set_voltage; + fe0->dvb.frontend->ops.set_tone = + samsung_smt_7020_set_tone; + } + + break; + case CX88_BOARD_TWINHAN_VP1027_DVBS: + dev->ts_gen_cntrl = 0x00; + fe0->dvb.frontend = dvb_attach(mb86a16_attach, + &twinhan_vp1027, + &core->i2c_adap); + if (fe0->dvb.frontend) { + core->prev_set_voltage = + fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = + vp1027_set_voltage; + } + break; + + default: + printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", + core->name); + break; + } + + if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) { + printk(KERN_ERR + "%s/2: frontend initialization failed\n", + core->name); + goto frontend_detach; + } + /* define general-purpose callback pointer */ + fe0->dvb.frontend->callback = cx88_tuner_callback; + + /* Ensure all frontends negotiate bus access */ + fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; + if (fe1) + fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; + + /* Put the analog decoder in standby to keep it quiet */ + call_all(core, core, s_power, 0); + + /* register everything */ + return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, + &dev->pci->dev, adapter_nr, mfe_shared, NULL); + +frontend_detach: + core->gate_ctrl = NULL; + videobuf_dvb_dealloc_frontends(&dev->frontends); + return -EINVAL; +} + +/* ----------------------------------------------------------- */ + +/* CX8802 MPEG -> mini driver - We have been given the hardware */ +static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + dprintk( 1, "%s\n", __func__); + + switch (core->boardnr) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* We arrive here with either the cx23416 or the cx22702 + * on the bus. Take the bus from the cx23416 and enable the + * cx22702 demod + */ + /* Toggle reset on cx22702 leaving i2c active */ + cx_set(MO_GP0_IO, 0x00000080); + udelay(1000); + cx_clear(MO_GP0_IO, 0x00000080); + udelay(50); + cx_set(MO_GP0_IO, 0x00000080); + udelay(1000); + /* enable the cx22702 pins */ + cx_clear(MO_GP0_IO, 0x00000004); + udelay(1000); + break; + + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + /* Toggle reset on cx22702 leaving i2c active */ + cx_set(MO_GP0_IO, 0x00000080); + udelay(1000); + cx_clear(MO_GP0_IO, 0x00000080); + udelay(50); + cx_set(MO_GP0_IO, 0x00000080); + udelay(1000); + switch (core->dvbdev->frontends.active_fe_id) { + case 1: /* DVB-S/S2 Enabled */ + /* tri-state the cx22702 pins */ + cx_set(MO_GP0_IO, 0x00000004); + /* Take the cx24116/cx24123 out of reset */ + cx_write(MO_SRST_IO, 1); + core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */ + break; + case 2: /* DVB-T Enabled */ + /* Put the cx24116/cx24123 into reset */ + cx_write(MO_SRST_IO, 0); + /* enable the cx22702 pins */ + cx_clear(MO_GP0_IO, 0x00000004); + core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */ + break; + } + udelay(1000); + break; + + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + /* set RF input to AIR for DVB-T (GPIO 16) */ + cx_write(MO_GP2_IO, 0x0101); + break; + + default: + err = -ENODEV; + } + return err; +} + +/* CX8802 MPEG -> mini driver - We no longer have the hardware */ +static int cx8802_dvb_advise_release(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + dprintk( 1, "%s\n", __func__); + + switch (core->boardnr) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* Do Nothing, leave the cx22702 on the bus. */ + break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + break; + default: + err = -ENODEV; + } + return err; +} + +static int cx8802_dvb_probe(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + struct cx8802_dev *dev = drv->core->dvbdev; + int err; + struct videobuf_dvb_frontend *fe; + int i; + + dprintk( 1, "%s\n", __func__); + dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + core->boardnr, + core->name, + core->pci_bus, + core->pci_slot); + + err = -ENODEV; + if (!(core->board.mpeg & CX88_MPEG_DVB)) + goto fail_core; + + /* If vp3054 isn't enabled, a stub will just return 0 */ + err = vp3054_i2c_probe(dev); + if (0 != err) + goto fail_core; + + /* dvb stuff */ + printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); + dev->ts_gen_cntrl = 0x0c; + + err = cx8802_alloc_frontends(dev); + if (err) + goto fail_core; + + err = -ENODEV; + for (i = 1; i <= core->board.num_frontends; i++) { + fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i); + if (fe == NULL) { + printk(KERN_ERR "%s() failed to get frontend(%d)\n", + __func__, i); + goto fail_probe; + } + videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_TOP, + sizeof(struct cx88_buffer), + dev, NULL); + /* init struct videobuf_dvb */ + fe->dvb.name = dev->core->name; + } + + err = dvb_register(dev); + if (err) + /* frontends/adapter de-allocated in dvb_register */ + printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n", + core->name, err); + return err; +fail_probe: + videobuf_dvb_dealloc_frontends(&core->dvbdev->frontends); +fail_core: + return err; +} + +static int cx8802_dvb_remove(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + struct cx8802_dev *dev = drv->core->dvbdev; + + dprintk( 1, "%s\n", __func__); + + videobuf_dvb_unregister_bus(&dev->frontends); + + vp3054_i2c_remove(dev); + + core->gate_ctrl = NULL; + + return 0; +} + +static struct cx8802_driver cx8802_dvb_driver = { + .type_id = CX88_MPEG_DVB, + .hw_access = CX8802_DRVCTL_SHARED, + .probe = cx8802_dvb_probe, + .remove = cx8802_dvb_remove, + .advise_acquire = cx8802_dvb_advise_acquire, + .advise_release = cx8802_dvb_advise_release, +}; + +static int __init dvb_init(void) +{ + printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return cx8802_register_driver(&cx8802_dvb_driver); +} + +static void __exit dvb_fini(void) +{ + cx8802_unregister_driver(&cx8802_dvb_driver); +} + +module_init(dvb_init); +module_exit(dvb_fini); + +/* + * Local variables: + * c-basic-offset: 8 + * compile-command: "make DVB=1" + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,729 @@ +/* + * + * v4l2 device driver for cx2388x based TV cards + * + * (c) 2003,04 Gerd Knorr [SUSE Labs] + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "btcx-risc.h" +#include "cx88-reg.h" +#include "tuner-xc2028.h" + +#include +#include +#define CX88_VERSION_CODE KERNEL_VERSION(0, 0, 8) + +#define UNSET (-1U) + +#define CX88_MAXBOARDS 8 + +/* Max number of inputs by card */ +#define MAX_CX88_INPUT 8 + +/* ----------------------------------------------------------- */ +/* defines and enums */ + +/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM/LC */ +#define CX88_NORMS (V4L2_STD_ALL \ + & ~V4L2_STD_PAL_H \ + & ~V4L2_STD_NTSC_M_KR \ + & ~V4L2_STD_SECAM_LC) + +#define FORMAT_FLAGS_PACKED 0x01 +#define FORMAT_FLAGS_PLANAR 0x02 + +#define VBI_LINE_COUNT 17 +#define VBI_LINE_LENGTH 2048 + +#define AUD_RDS_LINES 4 + +/* need "shadow" registers for some write-only ones ... */ +#define SHADOW_AUD_VOL_CTL 1 +#define SHADOW_AUD_BAL_CTL 2 +#define SHADOW_MAX 3 + +/* FM Radio deemphasis type */ +enum cx88_deemph_type { + FM_NO_DEEMPH = 0, + FM_DEEMPH_50, + FM_DEEMPH_75 +}; + +enum cx88_board_type { + CX88_BOARD_NONE = 0, + CX88_MPEG_DVB, + CX88_MPEG_BLACKBIRD +}; + +enum cx8802_board_access { + CX8802_DRVCTL_SHARED = 1, + CX8802_DRVCTL_EXCLUSIVE = 2, +}; + +/* ----------------------------------------------------------- */ +/* tv norms */ + +static unsigned int inline norm_maxw(v4l2_std_id norm) +{ + return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; +} + + +static unsigned int inline norm_maxh(v4l2_std_id norm) +{ + return (norm & V4L2_STD_625_50) ? 576 : 480; +} + +/* ----------------------------------------------------------- */ +/* static data */ + +struct cx8800_fmt { + const char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 cxformat; +}; + +struct cx88_ctrl { + struct v4l2_queryctrl v; + u32 off; + u32 reg; + u32 sreg; + u32 mask; + u32 shift; +}; + +/* ----------------------------------------------------------- */ +/* SRAM memory management data (see cx88-core.c) */ + +#define SRAM_CH21 0 /* video */ +#define SRAM_CH22 1 +#define SRAM_CH23 2 +#define SRAM_CH24 3 /* vbi */ +#define SRAM_CH25 4 /* audio */ +#define SRAM_CH26 5 +#define SRAM_CH28 6 /* mpeg */ +#define SRAM_CH27 7 /* audio rds */ +/* more */ + +struct sram_channel { + const char *name; + u32 cmds_start; + u32 ctrl_start; + u32 cdt; + u32 fifo_start; + u32 fifo_size; + u32 ptr1_reg; + u32 ptr2_reg; + u32 cnt1_reg; + u32 cnt2_reg; +}; +extern const struct sram_channel const cx88_sram_channels[]; + +/* ----------------------------------------------------------- */ +/* card configuration */ + +#define CX88_BOARD_NOAUTO UNSET +#define CX88_BOARD_UNKNOWN 0 +#define CX88_BOARD_HAUPPAUGE 1 +#define CX88_BOARD_GDI 2 +#define CX88_BOARD_PIXELVIEW 3 +#define CX88_BOARD_ATI_WONDER_PRO 4 +#define CX88_BOARD_WINFAST2000XP_EXPERT 5 +#define CX88_BOARD_AVERTV_STUDIO_303 6 +#define CX88_BOARD_MSI_TVANYWHERE_MASTER 7 +#define CX88_BOARD_WINFAST_DV2000 8 +#define CX88_BOARD_LEADTEK_PVR2000 9 +#define CX88_BOARD_IODATA_GVVCP3PCI 10 +#define CX88_BOARD_PROLINK_PLAYTVPVR 11 +#define CX88_BOARD_ASUS_PVR_416 12 +#define CX88_BOARD_MSI_TVANYWHERE 13 +#define CX88_BOARD_KWORLD_DVB_T 14 +#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15 +#define CX88_BOARD_KWORLD_LTV883 16 +#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q 17 +#define CX88_BOARD_HAUPPAUGE_DVB_T1 18 +#define CX88_BOARD_CONEXANT_DVB_T1 19 +#define CX88_BOARD_PROVIDEO_PV259 20 +#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21 +#define CX88_BOARD_PCHDTV_HD3000 22 +#define CX88_BOARD_DNTV_LIVE_DVB_T 23 +#define CX88_BOARD_HAUPPAUGE_ROSLYN 24 +#define CX88_BOARD_DIGITALLOGIC_MEC 25 +#define CX88_BOARD_IODATA_GVBCTV7E 26 +#define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27 +#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T 28 +#define CX88_BOARD_ADSTECH_DVB_T_PCI 29 +#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30 +#define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31 +#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32 +#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33 +#define CX88_BOARD_ATI_HDTVWONDER 34 +#define CX88_BOARD_WINFAST_DTV1000 35 +#define CX88_BOARD_AVERTV_303 36 +#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37 +#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38 +#define CX88_BOARD_KWORLD_DVBS_100 39 +#define CX88_BOARD_HAUPPAUGE_HVR1100 40 +#define CX88_BOARD_HAUPPAUGE_HVR1100LP 41 +#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42 +#define CX88_BOARD_KWORLD_DVB_T_CX22702 43 +#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44 +#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45 +#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46 +#define CX88_BOARD_PCHDTV_HD5500 47 +#define CX88_BOARD_KWORLD_MCE200_DELUXE 48 +#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000 49 +#define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50 +#define CX88_BOARD_WINFAST_DTV2000H 51 +#define CX88_BOARD_GENIATECH_DVBS 52 +#define CX88_BOARD_HAUPPAUGE_HVR3000 53 +#define CX88_BOARD_NORWOOD_MICRO 54 +#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55 +#define CX88_BOARD_HAUPPAUGE_HVR1300 56 +#define CX88_BOARD_ADSTECH_PTV_390 57 +#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58 +#define CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO 59 +#define CX88_BOARD_PINNACLE_HYBRID_PCTV 60 +#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL 61 +#define CX88_BOARD_POWERCOLOR_REAL_ANGEL 62 +#define CX88_BOARD_GENIATECH_X8000_MT 63 +#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO 64 +#define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65 +#define CX88_BOARD_PROLINK_PV_8000GT 66 +#define CX88_BOARD_KWORLD_ATSC_120 67 +#define CX88_BOARD_HAUPPAUGE_HVR4000 68 +#define CX88_BOARD_HAUPPAUGE_HVR4000LITE 69 +#define CX88_BOARD_TEVII_S460 70 +#define CX88_BOARD_OMICOM_SS4_PCI 71 +#define CX88_BOARD_TBS_8920 72 +#define CX88_BOARD_TEVII_S420 73 +#define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74 +#define CX88_BOARD_PROF_7300 75 +#define CX88_BOARD_SATTRADE_ST4200 76 +#define CX88_BOARD_TBS_8910 77 +#define CX88_BOARD_PROF_6200 78 +#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79 +#define CX88_BOARD_HAUPPAUGE_IRONLY 80 +#define CX88_BOARD_WINFAST_DTV1800H 81 +#define CX88_BOARD_WINFAST_DTV2000H_J 82 +#define CX88_BOARD_PROF_7301 83 +#define CX88_BOARD_SAMSUNG_SMT_7020 84 +#define CX88_BOARD_TWINHAN_VP1027_DVBS 85 +#define CX88_BOARD_TEVII_S464 86 +#define CX88_BOARD_WINFAST_DTV2000H_PLUS 87 +#define CX88_BOARD_WINFAST_DTV1800H_XC4000 88 + +enum cx88_itype { + CX88_VMUX_COMPOSITE1 = 1, + CX88_VMUX_COMPOSITE2, + CX88_VMUX_COMPOSITE3, + CX88_VMUX_COMPOSITE4, + CX88_VMUX_SVIDEO, + CX88_VMUX_TELEVISION, + CX88_VMUX_CABLE, + CX88_VMUX_DVB, + CX88_VMUX_DEBUG, + CX88_RADIO, +}; + +struct cx88_input { + enum cx88_itype type; + u32 gpio0, gpio1, gpio2, gpio3; + unsigned int vmux:2; + unsigned int audioroute:4; +}; + +struct cx88_board { + const char *name; + unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + int tda9887_conf; + struct cx88_input input[MAX_CX88_INPUT]; + struct cx88_input radio; + enum cx88_board_type mpeg; + unsigned int audio_chip; + int num_frontends; + + /* Used for I2S devices */ + int i2sinputcntl; +}; + +struct cx88_subid { + u16 subvendor; + u16 subdevice; + u32 card; +}; + +enum cx88_tvaudio { + WW_NONE = 1, + WW_BTSC, + WW_BG, + WW_DK, + WW_I, + WW_L, + WW_EIAJ, + WW_I2SPT, + WW_FM, + WW_I2SADC, + WW_M +}; + +#define INPUT(nr) (core->board.input[nr]) + +/* ----------------------------------------------------------- */ +/* device / file handle status */ + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 + +#define BUFFER_TIMEOUT msecs_to_jiffies(2000) + +/* buffer for one video frame */ +struct cx88_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* cx88 specific */ + unsigned int bpl; + struct btcx_riscmem risc; + const struct cx8800_fmt *fmt; + u32 count; +}; + +struct cx88_dmaqueue { + struct list_head active; + struct list_head queued; + struct timer_list timeout; + struct btcx_riscmem stopper; + u32 count; +}; + +struct cx88_core { + struct list_head devlist; + atomic_t refcount; + + /* board name */ + int nr; + char name[32]; + + /* pci stuff */ + int pci_bus; + int pci_slot; + u32 __iomem *lmmio; + u8 __iomem *bmmio; + u32 shadow[SHADOW_MAX]; + int pci_irqmask; + + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + u32 i2c_state, i2c_rc; + + /* config info -- analog */ + struct v4l2_device v4l2_dev; + struct i2c_client *i2c_rtc; + unsigned int boardnr; + struct cx88_board board; + + /* Supported V4L _STD_ tuner formats */ + unsigned int tuner_formats; + + /* config info -- dvb */ +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) + int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); +#endif + void (*gate_ctrl)(struct cx88_core *core, int open); + + /* state info */ + struct task_struct *kthread; + v4l2_std_id tvnorm; + enum cx88_tvaudio tvaudio; + u32 audiomode_manual; + u32 audiomode_current; + u32 input; + u32 astat; + u32 use_nicam; + unsigned long last_change; + + /* IR remote control state */ + struct cx88_IR *ir; + + /* I2C remote data */ + struct IR_i2c_init_data init_data; + struct wm8775_platform_data wm8775_data; + + struct mutex lock; + /* various v4l controls */ + u32 freq; + int users; + int mpeg_users; + + /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ + struct cx8802_dev *dvbdev; + enum cx88_board_type active_type_id; + int active_ref; + int active_fe_id; +}; + +static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct cx88_core, v4l2_dev); +} + +#define WM8775_GID (1 << 0) + +#define call_hw(core, grpid, o, f, args...) \ + do { \ + if (!core->i2c_rc) { \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 1); \ + v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 0); \ + } \ + } while (0) + +#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) + +struct cx8800_dev; +struct cx8802_dev; + +/* ----------------------------------------------------------- */ +/* function 0: video stuff */ + +struct cx8800_fh { + struct cx8800_dev *dev; + enum v4l2_buf_type type; + int radio; + unsigned int resources; + + /* video overlay */ + struct v4l2_window win; + struct v4l2_clip *clips; + unsigned int nclips; + + /* video capture */ + const struct cx8800_fmt *fmt; + unsigned int width,height; + struct videobuf_queue vidq; + + /* vbi capture */ + struct videobuf_queue vbiq; +}; + +struct cx8800_suspend_state { + int disabled; +}; + +struct cx8800_dev { + struct cx88_core *core; + spinlock_t slock; + + /* various device info */ + unsigned int resources; + struct video_device *video_dev; + struct video_device *vbi_dev; + struct video_device *radio_dev; + + /* pci i/o */ + struct pci_dev *pci; + unsigned char pci_rev,pci_lat; + + + /* capture queues */ + struct cx88_dmaqueue vidq; + struct cx88_dmaqueue vbiq; + + /* various v4l controls */ + + /* other global state info */ + struct cx8800_suspend_state state; +}; + +/* ----------------------------------------------------------- */ +/* function 1: audio/alsa stuff */ +/* =============> moved to cx88-alsa.c <====================== */ + + +/* ----------------------------------------------------------- */ +/* function 2: mpeg stuff */ + +struct cx8802_fh { + struct cx8802_dev *dev; + struct videobuf_queue mpegq; +}; + +struct cx8802_suspend_state { + int disabled; +}; + +struct cx8802_driver { + struct cx88_core *core; + + /* List of drivers attached to device */ + struct list_head drvlist; + + /* Type of driver and access required */ + enum cx88_board_type type_id; + enum cx8802_board_access hw_access; + + /* MPEG 8802 internal only */ + int (*suspend)(struct pci_dev *pci_dev, pm_message_t state); + int (*resume)(struct pci_dev *pci_dev); + + /* Callers to the following functions must hold core->lock */ + + /* MPEG 8802 -> mini driver - Driver probe and configuration */ + int (*probe)(struct cx8802_driver *drv); + int (*remove)(struct cx8802_driver *drv); + + /* MPEG 8802 -> mini driver - Access for hardware control */ + int (*advise_acquire)(struct cx8802_driver *drv); + int (*advise_release)(struct cx8802_driver *drv); + + /* MPEG 8802 <- mini driver - Access for hardware control */ + int (*request_acquire)(struct cx8802_driver *drv); + int (*request_release)(struct cx8802_driver *drv); +}; + +struct cx8802_dev { + struct cx88_core *core; + spinlock_t slock; + + /* pci i/o */ + struct pci_dev *pci; + unsigned char pci_rev,pci_lat; + + /* dma queues */ + struct cx88_dmaqueue mpegq; + u32 ts_packet_size; + u32 ts_packet_count; + + /* other global state info */ + struct cx8802_suspend_state state; + + /* for blackbird only */ + struct list_head devlist; +#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \ + defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE) + struct video_device *mpeg_dev; + u32 mailbox; + int width; + int height; + unsigned char mpeg_active; /* nonzero if mpeg encoder is active */ + + /* mpeg params */ + struct cx2341x_mpeg_params params; +#endif + +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) + /* for dvb only */ + struct videobuf_dvb_frontends frontends; +#endif + +#if defined(CONFIG_VIDEO_CX88_VP3054) || \ + defined(CONFIG_VIDEO_CX88_VP3054_MODULE) + /* For VP3045 secondary I2C bus support */ + struct vp3054_i2c_state *vp3054; +#endif + /* for switching modulation types */ + unsigned char ts_gen_cntrl; + + /* List of attached drivers; must hold core->lock to access */ + struct list_head drvlist; + + struct work_struct request_module_wk; +}; + +/* ----------------------------------------------------------- */ + +#define cx_read(reg) readl(core->lmmio + ((reg)>>2)) +#define cx_write(reg,value) writel((value), core->lmmio + ((reg)>>2)) +#define cx_writeb(reg,value) writeb((value), core->bmmio + (reg)) + +#define cx_andor(reg,mask,value) \ + writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\ + ((value) & (mask)), core->lmmio+((reg)>>2)) +#define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) +#define cx_clear(reg,bit) cx_andor((reg),(bit),0) + +#define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); } + +/* shadow registers */ +#define cx_sread(sreg) (core->shadow[sreg]) +#define cx_swrite(sreg,reg,value) \ + (core->shadow[sreg] = value, \ + writel(core->shadow[sreg], core->lmmio + ((reg)>>2))) +#define cx_sandor(sreg,reg,mask,value) \ + (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \ + writel(core->shadow[sreg], core->lmmio + ((reg)>>2))) + +/* ----------------------------------------------------------- */ +/* cx88-core.c */ + +extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[], + int len, u32 bits, u32 mask); + +extern int cx88_core_irq(struct cx88_core *core, u32 status); +extern void cx88_wakeup(struct cx88_core *core, + struct cx88_dmaqueue *q, u32 count); +extern void cx88_shutdown(struct cx88_core *core); +extern int cx88_reset(struct cx88_core *core); + +extern int +cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines); +extern int +cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int bpl, + unsigned int lines, unsigned int lpi); +extern int +cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); +extern void +cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf); + +extern void cx88_risc_disasm(struct cx88_core *core, + struct btcx_riscmem *risc); +extern int cx88_sram_channel_setup(struct cx88_core *core, + const struct sram_channel *ch, + unsigned int bpl, u32 risc); +extern void cx88_sram_channel_dump(struct cx88_core *core, + const struct sram_channel *ch); + +extern int cx88_set_scale(struct cx88_core *core, unsigned int width, + unsigned int height, enum v4l2_field field); +extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm); + +extern struct video_device *cx88_vdev_init(struct cx88_core *core, + struct pci_dev *pci, + const struct video_device *template_, + const char *type); +extern struct cx88_core* cx88_core_get(struct pci_dev *pci); +extern void cx88_core_put(struct cx88_core *core, + struct pci_dev *pci); + +extern int cx88_start_audio_dma(struct cx88_core *core); +extern int cx88_stop_audio_dma(struct cx88_core *core); + + +/* ----------------------------------------------------------- */ +/* cx88-vbi.c */ + +/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */ +int cx8800_vbi_fmt (struct file *file, void *priv, + struct v4l2_format *f); + +/* +int cx8800_start_vbi_dma(struct cx8800_dev *dev, + struct cx88_dmaqueue *q, + struct cx88_buffer *buf); +*/ +int cx8800_stop_vbi_dma(struct cx8800_dev *dev); +int cx8800_restart_vbi_queue(struct cx8800_dev *dev, + struct cx88_dmaqueue *q); +void cx8800_vbi_timeout(unsigned long data); + +extern const struct videobuf_queue_ops cx8800_vbi_qops; + +/* ----------------------------------------------------------- */ +/* cx88-i2c.c */ + +extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci); + + +/* ----------------------------------------------------------- */ +/* cx88-cards.c */ + +extern int cx88_tuner_callback(void *dev, int component, int command, int arg); +extern int cx88_get_resources(const struct cx88_core *core, + struct pci_dev *pci); +extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); +extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl); + +/* ----------------------------------------------------------- */ +/* cx88-tvaudio.c */ + +void cx88_set_tvaudio(struct cx88_core *core); +void cx88_newstation(struct cx88_core *core); +void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); +void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); +int cx88_audio_thread(void *data); + +int cx8802_register_driver(struct cx8802_driver *drv); +int cx8802_unregister_driver(struct cx8802_driver *drv); + +/* Caller must hold core->lock */ +struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); + +/* ----------------------------------------------------------- */ +/* cx88-dsp.c */ + +s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core); + +/* ----------------------------------------------------------- */ +/* cx88-input.c */ + +int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci); +int cx88_ir_fini(struct cx88_core *core); +void cx88_ir_irq(struct cx88_core *core); +int cx88_ir_start(struct cx88_core *core); +void cx88_ir_stop(struct cx88_core *core); +extern void cx88_i2c_init_ir(struct cx88_core *core); + +/* ----------------------------------------------------------- */ +/* cx88-mpeg.c */ + +int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev, + struct cx88_buffer *buf, enum v4l2_field field); +void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf); +void cx8802_cancel_buffers(struct cx8802_dev *dev); + +/* ----------------------------------------------------------- */ +/* cx88-video.c*/ +extern const u32 cx88_user_ctrls[]; +extern int cx8800_ctrl_query(struct cx88_core *core, + struct v4l2_queryctrl *qctrl); +int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i); +int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f); +int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl); +int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl); +int cx88_video_mux(struct cx88_core *core, unsigned int input); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-i2c.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,184 @@ + +/* + + cx88-i2c.c -- all the i2c code is here + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 2002 Yurij Sysoev + (c) 1999-2003 Gerd Knorr + + (c) 2005 Mauro Carvalho Chehab + - Multituner support and i2c address binding + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include + +#include "cx88.h" +#include + +static unsigned int i2c_debug; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); + +static unsigned int i2c_scan; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); + +static unsigned int i2c_udelay = 5; +module_param(i2c_udelay, int, 0644); +MODULE_PARM_DESC(i2c_udelay,"i2c delay at insmod time, in usecs " + "(should be 5 or higher). Lower value means higher bus speed."); + +#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) + +/* ----------------------------------------------------------------------- */ + +static void cx8800_bit_setscl(void *data, int state) +{ + struct cx88_core *core = data; + + if (state) + core->i2c_state |= 0x02; + else + core->i2c_state &= ~0x02; + cx_write(MO_I2C, core->i2c_state); + cx_read(MO_I2C); +} + +static void cx8800_bit_setsda(void *data, int state) +{ + struct cx88_core *core = data; + + if (state) + core->i2c_state |= 0x01; + else + core->i2c_state &= ~0x01; + cx_write(MO_I2C, core->i2c_state); + cx_read(MO_I2C); +} + +static int cx8800_bit_getscl(void *data) +{ + struct cx88_core *core = data; + u32 state; + + state = cx_read(MO_I2C); + return state & 0x02 ? 1 : 0; +} + +static int cx8800_bit_getsda(void *data) +{ + struct cx88_core *core = data; + u32 state; + + state = cx_read(MO_I2C); + return state & 0x01; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_algo_bit_data cx8800_i2c_algo_template = { + .setsda = cx8800_bit_setsda, + .setscl = cx8800_bit_setscl, + .getsda = cx8800_bit_getsda, + .getscl = cx8800_bit_getscl, + .udelay = 16, + .timeout = 200, +}; + +/* ----------------------------------------------------------------------- */ + +static const char * const i2c_devs[128] = { + [ 0x1c >> 1 ] = "lgdt330x", + [ 0x86 >> 1 ] = "tda9887/cx22702", + [ 0xa0 >> 1 ] = "eeprom", + [ 0xc0 >> 1 ] = "tuner (analog)", + [ 0xc2 >> 1 ] = "tuner (analog/dvb)", + [ 0xc8 >> 1 ] = "xc5000", +}; + +static void do_i2c_scan(const char *name, struct i2c_client *c) +{ + unsigned char buf; + int i,rc; + + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { + c->addr = i; + rc = i2c_master_recv(c,&buf,0); + if (rc < 0) + continue; + printk("%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + } +} + +/* init + register i2c algo-bit adapter */ +int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) +{ + /* Prevents usage of invalid delay values */ + if (i2c_udelay<5) + i2c_udelay=5; + + memcpy(&core->i2c_algo, &cx8800_i2c_algo_template, + sizeof(core->i2c_algo)); + + + core->i2c_adap.dev.parent = &pci->dev; + strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name)); + core->i2c_adap.owner = THIS_MODULE; + core->i2c_algo.udelay = i2c_udelay; + core->i2c_algo.data = core; + i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev); + core->i2c_adap.algo_data = &core->i2c_algo; + core->i2c_client.adapter = &core->i2c_adap; + strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE); + + cx8800_bit_setscl(core,1); + cx8800_bit_setsda(core,1); + + core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap); + if (0 == core->i2c_rc) { + static u8 tuner_data[] = + { 0x0b, 0xdc, 0x86, 0x52 }; + static struct i2c_msg tuner_msg = + { .flags = 0, .addr = 0xc2 >> 1, .buf = tuner_data, .len = 4 }; + + dprintk(1, "i2c register ok\n"); + switch( core->boardnr ) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + printk("%s: i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n", + core->name); + i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1); + break; + default: + break; + } + if (i2c_scan) + do_i2c_scan(core->name,&core->i2c_client); + } else + printk("%s: i2c register FAILED\n", core->name); + + return core->i2c_rc; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-input.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-input.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,631 @@ +/* + * + * Device driver for GPIO attached remote control interfaces + * on Conexant 2388x based TV/DVB cards. + * + * Copyright (c) 2003 Pavel Machek + * Copyright (c) 2004 Gerd Knorr + * Copyright (c) 2004, 2005 Chris Pascoe + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include + +#include "cx88.h" +#include + +#define MODULE_NAME "cx88xx" + +/* ---------------------------------------------------------------------- */ + +struct cx88_IR { + struct cx88_core *core; + struct rc_dev *dev; + + int users; + + char name[32]; + char phys[32]; + + /* sample from gpio pin 16 */ + u32 sampling; + + /* poll external decoder */ + int polling; + struct hrtimer timer; + u32 gpio_addr; + u32 last_gpio; + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; +}; + +static unsigned ir_samplerate = 4; +module_param(ir_samplerate, uint, 0444); +MODULE_PARM_DESC(ir_samplerate, "IR samplerate in kHz, 1 - 20, default 4"); + +static int ir_debug; +module_param(ir_debug, int, 0644); /* debug level [IR] */ +MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); + +#define ir_dprintk(fmt, arg...) if (ir_debug) \ + printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg) + +#define dprintk(fmt, arg...) if (ir_debug) \ + printk(KERN_DEBUG "cx88 IR: " fmt , ##arg) + +/* ---------------------------------------------------------------------- */ + +static void cx88_ir_handle_key(struct cx88_IR *ir) +{ + struct cx88_core *core = ir->core; + u32 gpio, data, auxgpio; + + /* read gpio value */ + gpio = cx_read(ir->gpio_addr); + switch (core->boardnr) { + case CX88_BOARD_NPGTECH_REALTV_TOP10FM: + /* This board apparently uses a combination of 2 GPIO + to represent the keys. Additionally, the second GPIO + can be used for parity. + + Example: + + for key "5" + gpio = 0x758, auxgpio = 0xe5 or 0xf5 + for key "Power" + gpio = 0x758, auxgpio = 0xed or 0xfd + */ + + auxgpio = cx_read(MO_GP1_IO); + /* Take out the parity part */ + gpio=(gpio & 0x7fd) + (auxgpio & 0xef); + break; + case CX88_BOARD_WINFAST_DTV1000: + case CX88_BOARD_WINFAST_DTV1800H: + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); + auxgpio = gpio; + break; + default: + auxgpio = gpio; + } + if (ir->polling) { + if (ir->last_gpio == auxgpio) + return; + ir->last_gpio = auxgpio; + } + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n", + gpio, data, + ir->polling ? "poll" : "irq", + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); + + if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) { + u32 gpio_key = cx_read(MO_GP0_IO); + + data = (data << 4) | ((gpio_key & 0xf0) >> 4); + + rc_keydown(ir->dev, data, 0); + + } else if (ir->mask_keydown) { + /* bit set on keydown */ + if (gpio & ir->mask_keydown) + rc_keydown_notimeout(ir->dev, data, 0); + else + rc_keyup(ir->dev); + + } else if (ir->mask_keyup) { + /* bit cleared on keydown */ + if (0 == (gpio & ir->mask_keyup)) + rc_keydown_notimeout(ir->dev, data, 0); + else + rc_keyup(ir->dev); + + } else { + /* can't distinguish keydown/up :-/ */ + rc_keydown_notimeout(ir->dev, data, 0); + rc_keyup(ir->dev); + } +} + +static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer) +{ + unsigned long missed; + struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer); + + cx88_ir_handle_key(ir); + missed = hrtimer_forward_now(&ir->timer, + ktime_set(0, ir->polling * 1000000)); + if (missed > 1) + ir_dprintk("Missed ticks %ld\n", missed - 1); + + return HRTIMER_RESTART; +} + +static int __cx88_ir_start(void *priv) +{ + struct cx88_core *core = priv; + struct cx88_IR *ir; + + if (!core || !core->ir) + return -EINVAL; + + ir = core->ir; + + if (ir->polling) { + hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ir->timer.function = cx88_ir_work; + hrtimer_start(&ir->timer, + ktime_set(0, ir->polling * 1000000), + HRTIMER_MODE_REL); + } + if (ir->sampling) { + core->pci_irqmask |= PCI_INT_IR_SMPINT; + cx_write(MO_DDS_IO, 0x33F286 * ir_samplerate); /* samplerate */ + cx_write(MO_DDSCFG_IO, 0x5); /* enable */ + } + return 0; +} + +static void __cx88_ir_stop(void *priv) +{ + struct cx88_core *core = priv; + struct cx88_IR *ir; + + if (!core || !core->ir) + return; + + ir = core->ir; + if (ir->sampling) { + cx_write(MO_DDSCFG_IO, 0x0); + core->pci_irqmask &= ~PCI_INT_IR_SMPINT; + } + + if (ir->polling) + hrtimer_cancel(&ir->timer); +} + +int cx88_ir_start(struct cx88_core *core) +{ + if (core->ir->users) + return __cx88_ir_start(core); + + return 0; +} + +void cx88_ir_stop(struct cx88_core *core) +{ + if (core->ir->users) + __cx88_ir_stop(core); +} + +static int cx88_ir_open(struct rc_dev *rc) +{ + struct cx88_core *core = rc->priv; + + core->ir->users++; + return __cx88_ir_start(core); +} + +static void cx88_ir_close(struct rc_dev *rc) +{ + struct cx88_core *core = rc->priv; + + core->ir->users--; + if (!core->ir->users) + __cx88_ir_stop(core); +} + +/* ---------------------------------------------------------------------- */ + +int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) +{ + struct cx88_IR *ir; + struct rc_dev *dev; + char *ir_codes = NULL; + u64 rc_type = RC_TYPE_OTHER; + int err = -ENOMEM; + u32 hardware_mask = 0; /* For devices with a hardware mask, when + * used with a full-code IR table + */ + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + dev = rc_allocate_device(); + if (!ir || !dev) + goto err_out_free; + + ir->dev = dev; + + /* detect & configure */ + switch (core->boardnr) { + case CX88_BOARD_DNTV_LIVE_DVB_T: + case CX88_BOARD_KWORLD_DVB_T: + case CX88_BOARD_KWORLD_DVB_T_CX22702: + ir_codes = RC_MAP_DNTV_LIVE_DVB_T; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x1f; + ir->mask_keyup = 0x60; + ir->polling = 50; /* ms */ + break; + case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: + ir_codes = RC_MAP_CINERGY_1400; + ir->sampling = 0xeb04; /* address */ + break; + case CX88_BOARD_HAUPPAUGE: + case CX88_BOARD_HAUPPAUGE_DVB_T1: + case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: + case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: + case CX88_BOARD_HAUPPAUGE_HVR1100: + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + case CX88_BOARD_HAUPPAUGE_HVR4000LITE: + case CX88_BOARD_PCHDTV_HD3000: + case CX88_BOARD_PCHDTV_HD5500: + case CX88_BOARD_HAUPPAUGE_IRONLY: + ir_codes = RC_MAP_HAUPPAUGE; + ir->sampling = 1; + break; + case CX88_BOARD_WINFAST_DTV2000H: + case CX88_BOARD_WINFAST_DTV2000H_J: + case CX88_BOARD_WINFAST_DTV1800H: + case CX88_BOARD_WINFAST_DTV1800H_XC4000: + case CX88_BOARD_WINFAST_DTV2000H_PLUS: + ir_codes = RC_MAP_WINFAST; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0x8f8; + ir->mask_keyup = 0x100; + ir->polling = 50; /* ms */ + break; + case CX88_BOARD_WINFAST2000XP_EXPERT: + case CX88_BOARD_WINFAST_DTV1000: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + ir_codes = RC_MAP_WINFAST; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0x8f8; + ir->mask_keyup = 0x100; + ir->polling = 1; /* ms */ + break; + case CX88_BOARD_IODATA_GVBCTV7E: + ir_codes = RC_MAP_IODATA_BCTV7E; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0xfd; + ir->mask_keydown = 0x02; + ir->polling = 5; /* ms */ + break; + case CX88_BOARD_PROLINK_PLAYTVPVR: + case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO: + /* + * It seems that this hardware is paired with NEC extended + * address 0x866b. So, unfortunately, its usage with other + * IR's with different address won't work. Still, there are + * other IR's from the same manufacturer that works, like the + * 002-T mini RC, provided with newer PV hardware + */ + ir_codes = RC_MAP_PIXELVIEW_MK12; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keyup = 0x80; + ir->polling = 10; /* ms */ + hardware_mask = 0x3f; /* Hardware returns only 6 bits from command part */ + break; + case CX88_BOARD_PROLINK_PV_8000GT: + case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: + ir_codes = RC_MAP_PIXELVIEW_NEW; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x3f; + ir->mask_keyup = 0x80; + ir->polling = 1; /* ms */ + break; + case CX88_BOARD_KWORLD_LTV883: + ir_codes = RC_MAP_PIXELVIEW; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x1f; + ir->mask_keyup = 0x60; + ir->polling = 1; /* ms */ + break; + case CX88_BOARD_ADSTECH_DVB_T_PCI: + ir_codes = RC_MAP_ADSTECH_DVB_T_PCI; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0xbf; + ir->mask_keyup = 0x40; + ir->polling = 50; /* ms */ + break; + case CX88_BOARD_MSI_TVANYWHERE_MASTER: + ir_codes = RC_MAP_MSI_TVANYWHERE; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x1f; + ir->mask_keyup = 0x40; + ir->polling = 1; /* ms */ + break; + case CX88_BOARD_AVERTV_303: + case CX88_BOARD_AVERTV_STUDIO_303: + ir_codes = RC_MAP_AVERTV_303; + ir->gpio_addr = MO_GP2_IO; + ir->mask_keycode = 0xfb; + ir->mask_keydown = 0x02; + ir->polling = 50; /* ms */ + break; + case CX88_BOARD_OMICOM_SS4_PCI: + case CX88_BOARD_SATTRADE_ST4200: + case CX88_BOARD_TBS_8920: + case CX88_BOARD_TBS_8910: + case CX88_BOARD_PROF_7300: + case CX88_BOARD_PROF_7301: + case CX88_BOARD_PROF_6200: + ir_codes = RC_MAP_TBS_NEC; + ir->sampling = 0xff00; /* address */ + break; + case CX88_BOARD_TEVII_S464: + case CX88_BOARD_TEVII_S460: + case CX88_BOARD_TEVII_S420: + ir_codes = RC_MAP_TEVII_NEC; + ir->sampling = 0xff00; /* address */ + break; + case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: + ir_codes = RC_MAP_DNTV_LIVE_DVBT_PRO; + ir->sampling = 0xff00; /* address */ + break; + case CX88_BOARD_NORWOOD_MICRO: + ir_codes = RC_MAP_NORWOOD; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x0e; + ir->mask_keyup = 0x80; + ir->polling = 50; /* ms */ + break; + case CX88_BOARD_NPGTECH_REALTV_TOP10FM: + ir_codes = RC_MAP_NPGTECH; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0xfa; + ir->polling = 50; /* ms */ + break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + ir_codes = RC_MAP_PINNACLE_PCTV_HD; + ir->sampling = 1; + break; + case CX88_BOARD_POWERCOLOR_REAL_ANGEL: + ir_codes = RC_MAP_POWERCOLOR_REAL_ANGEL; + ir->gpio_addr = MO_GP2_IO; + ir->mask_keycode = 0x7e; + ir->polling = 100; /* ms */ + break; + case CX88_BOARD_TWINHAN_VP1027_DVBS: + ir_codes = RC_MAP_TWINHAN_VP1027_DVBS; + rc_type = RC_TYPE_NEC; + ir->sampling = 0xff00; /* address */ + break; + } + + if (!ir_codes) { + err = -ENODEV; + goto err_out_free; + } + + /* + * The usage of mask_keycode were very convenient, due to several + * reasons. Among others, the scancode tables were using the scancode + * as the index elements. So, the less bits it was used, the smaller + * the table were stored. After the input changes, the better is to use + * the full scancodes, since it allows replacing the IR remote by + * another one. Unfortunately, there are still some hardware, like + * Pixelview Ultra Pro, where only part of the scancode is sent via + * GPIO. So, there's no way to get the full scancode. Due to that, + * hardware_mask were introduced here: it represents those hardware + * that has such limits. + */ + if (hardware_mask && !ir->mask_keycode) + ir->mask_keycode = hardware_mask; + + /* init input device */ + snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); + + dev->input_name = ir->name; + dev->input_phys = ir->phys; + dev->input_id.bustype = BUS_PCI; + dev->input_id.version = 1; + if (pci->subsystem_vendor) { + dev->input_id.vendor = pci->subsystem_vendor; + dev->input_id.product = pci->subsystem_device; + } else { + dev->input_id.vendor = pci->vendor; + dev->input_id.product = pci->device; + } + dev->dev.parent = &pci->dev; + dev->map_name = ir_codes; + dev->driver_name = MODULE_NAME; + dev->priv = core; + dev->open = cx88_ir_open; + dev->close = cx88_ir_close; + dev->scanmask = hardware_mask; + + if (ir->sampling) { + dev->driver_type = RC_DRIVER_IR_RAW; + dev->timeout = 10 * 1000 * 1000; /* 10 ms */ + } else { + dev->driver_type = RC_DRIVER_SCANCODE; + dev->allowed_protos = rc_type; + } + + ir->core = core; + core->ir = ir; + + /* all done */ + err = rc_register_device(dev); + if (err) + goto err_out_free; + + return 0; + +err_out_free: + rc_free_device(dev); + core->ir = NULL; + kfree(ir); + return err; +} + +int cx88_ir_fini(struct cx88_core *core) +{ + struct cx88_IR *ir = core->ir; + + /* skip detach on non attached boards */ + if (NULL == ir) + return 0; + + cx88_ir_stop(core); + rc_unregister_device(ir->dev); + kfree(ir); + + /* done */ + core->ir = NULL; + return 0; +} + +/* ---------------------------------------------------------------------- */ + +void cx88_ir_irq(struct cx88_core *core) +{ + struct cx88_IR *ir = core->ir; + u32 samples; + unsigned todo, bits; + struct ir_raw_event ev; + + if (!ir || !ir->sampling) + return; + + /* + * Samples are stored in a 32 bit register, oldest sample in + * the msb. A set bit represents space and an unset bit + * represents a pulse. + */ + samples = cx_read(MO_SAMPLE_IO); + + if (samples == 0xff && ir->dev->idle) + return; + + init_ir_raw_event(&ev); + for (todo = 32; todo > 0; todo -= bits) { + ev.pulse = samples & 0x80000000 ? false : true; + bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples)); + ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate; + ir_raw_event_store_with_filter(ir->dev, &ev); + samples <<= bits; + } + ir_raw_event_handle(ir->dev); +} + +static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + int flags, code; + + /* poll IR chip */ + flags = i2c_smbus_read_byte_data(ir->c, 0x10); + if (flags < 0) { + dprintk("read error\n"); + return 0; + } + /* key pressed ? */ + if (0 == (flags & 0x80)) + return 0; + + /* read actual key code */ + code = i2c_smbus_read_byte_data(ir->c, 0x00); + if (code < 0) { + dprintk("read error\n"); + return 0; + } + + dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", + code & 0xff, flags & 0xff); + + *ir_key = code & 0xff; + *ir_raw = code; + return 1; +} + +void cx88_i2c_init_ir(struct cx88_core *core) +{ + struct i2c_board_info info; + const unsigned short default_addr_list[] = { + 0x18, 0x6b, 0x71, + I2C_CLIENT_END + }; + const unsigned short pvr2000_addr_list[] = { + 0x18, 0x1a, + I2C_CLIENT_END + }; + const unsigned short *addr_list = default_addr_list; + const unsigned short *addrp; + /* Instantiate the IR receiver device, if present */ + if (0 != core->i2c_rc) + return; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + + switch (core->boardnr) { + case CX88_BOARD_LEADTEK_PVR2000: + addr_list = pvr2000_addr_list; + core->init_data.name = "cx88 Leadtek PVR 2000 remote"; + core->init_data.type = RC_TYPE_UNKNOWN; + core->init_data.get_key = get_key_pvr2000; + core->init_data.ir_codes = RC_MAP_EMPTY; + break; + } + + /* + * We can't call i2c_new_probed_device() because it uses + * quick writes for probing and at least some RC receiver + * devices only reply to reads. + * Also, Hauppauge XVR needs to be specified, as address 0x71 + * conflicts with another remote type used with saa7134 + */ + for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) { + info.platform_data = NULL; + memset(&core->init_data, 0, sizeof(core->init_data)); + + if (*addrp == 0x71) { + /* Hauppauge XVR */ + core->init_data.name = "cx88 Hauppauge XVR remote"; + core->init_data.ir_codes = RC_MAP_HAUPPAUGE; + core->init_data.type = RC_TYPE_RC5; + core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; + + info.platform_data = &core->init_data; + } + if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0, + I2C_SMBUS_READ, 0, + I2C_SMBUS_QUICK, NULL) >= 0) { + info.addr = *addrp; + i2c_new_device(&core->i2c_adap, &info); + break; + } + } +} + +/* ---------------------------------------------------------------------- */ + +MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe"); +MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-mpeg.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-mpeg.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-mpeg.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-mpeg.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,924 @@ +/* + * + * Support for the mpeg transport stream transfers + * PCI function #2 of the cx2388x. + * + * (c) 2004 Jelle Foks + * (c) 2004 Chris Pascoe + * (c) 2004 Gerd Knorr + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cx88.h" + +/* ------------------------------------------------------------------ */ + +MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards"); +MODULE_AUTHOR("Jelle Foks "); +MODULE_AUTHOR("Chris Pascoe "); +MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); +MODULE_LICENSE("GPL"); + +static unsigned int debug; +module_param(debug,int,0644); +MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg) + +#define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) + +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk); + + if (dev->core->board.mpeg & CX88_MPEG_DVB) + request_module("cx88-dvb"); + if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD) + request_module("cx88-blackbird"); +} + +static void request_modules(struct cx8802_dev *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); +} + +static void flush_request_modules(struct cx8802_dev *dev) +{ + flush_work_sync(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#define flush_request_modules(dev) +#endif /* CONFIG_MODULES */ + + +static LIST_HEAD(cx8802_devlist); +static DEFINE_MUTEX(cx8802_mutex); +/* ------------------------------------------------------------------ */ + +static int cx8802_start_dma(struct cx8802_dev *dev, + struct cx88_dmaqueue *q, + struct cx88_buffer *buf) +{ + struct cx88_core *core = dev->core; + + dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n", + buf->vb.width, buf->vb.height, buf->vb.field); + + /* setup fifo + format */ + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], + dev->ts_packet_size, buf->risc.dma); + + /* write TS length to chip */ + cx_write(MO_TS_LNGTH, buf->vb.width); + + /* FIXME: this needs a review. + * also: move to cx88-blackbird + cx88-dvb source files? */ + + dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id); + + if ( (core->active_type_id == CX88_MPEG_DVB) && + (core->board.mpeg & CX88_MPEG_DVB) ) { + + dprintk( 1, "cx8802_start_dma doing .dvb\n"); + /* negedge driven & software reset */ + cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); + udelay(100); + cx_write(MO_PINMUX_IO, 0x00); + cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01); + switch (core->boardnr) { + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: + case CX88_BOARD_PCHDTV_HD5500: + cx_write(TS_SOP_STAT, 1<<13); + break; + case CX88_BOARD_SAMSUNG_SMT_7020: + cx_write(TS_SOP_STAT, 0x00); + break; + case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: + case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: + cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ + udelay(100); + break; + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* Enable MPEG parallel IO and video signal pins */ + cx_write(MO_PINMUX_IO, 0x88); + cx_write(TS_SOP_STAT, 0); + cx_write(TS_VALERR_CNTRL, 0); + break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + /* Enable MPEG parallel IO and video signal pins */ + cx_write(MO_PINMUX_IO, 0x88); + cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4)); + dev->ts_gen_cntrl = 5; + cx_write(TS_SOP_STAT, 0); + cx_write(TS_VALERR_CNTRL, 0); + udelay(100); + break; + default: + cx_write(TS_SOP_STAT, 0x00); + break; + } + cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); + udelay(100); + } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && + (core->board.mpeg & CX88_MPEG_BLACKBIRD) ) { + dprintk( 1, "cx8802_start_dma doing .blackbird\n"); + cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ + + cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ + udelay(100); + + cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */ + cx_write(TS_VALERR_CNTRL, 0x2000); + + cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ + udelay(100); + } else { + printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __func__, + core->board.mpeg ); + return -EINVAL; + } + + /* reset counter */ + cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET); + q->count = 1; + + /* enable irqs */ + dprintk( 1, "setting the interrupt mask\n" ); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT); + cx_set(MO_TS_INTMSK, 0x1f0011); + + /* start dma */ + cx_set(MO_DEV_CNTRL2, (1<<5)); + cx_set(MO_TS_DMACNTRL, 0x11); + return 0; +} + +static int cx8802_stop_dma(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + dprintk( 1, "cx8802_stop_dma\n" ); + + /* stop dma */ + cx_clear(MO_TS_DMACNTRL, 0x11); + + /* disable irqs */ + cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT); + cx_clear(MO_TS_INTMSK, 0x1f0011); + + /* Reset the controller */ + cx_write(TS_GEN_CNTRL, 0xcd); + return 0; +} + +static int cx8802_restart_queue(struct cx8802_dev *dev, + struct cx88_dmaqueue *q) +{ + struct cx88_buffer *buf; + + dprintk( 1, "cx8802_restart_queue\n" ); + if (list_empty(&q->active)) + { + struct cx88_buffer *prev; + prev = NULL; + + dprintk(1, "cx8802_restart_queue: queue is empty\n" ); + + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + cx8802_start_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(1,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(1,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); + } else { + return 0; + } + prev = buf; + } + return 0; + } + + buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); + dprintk(2,"restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx8802_start_dma(dev, q, buf); + list_for_each_entry(buf, &q->active, vb.queue) + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +/* ------------------------------------------------------------------ */ + +int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, + struct cx88_buffer *buf, enum v4l2_field field) +{ + int size = dev->ts_packet_size * dev->ts_packet_count; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + int rc; + + dprintk(1, "%s: %p\n", __func__, buf); + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + buf->vb.width = dev->ts_packet_size; + buf->vb.height = dev->ts_packet_count; + buf->vb.size = size; + buf->vb.field = field /*V4L2_FIELD_TOP*/; + + if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) + goto fail; + cx88_risc_databuffer(dev->pci, &buf->risc, + dma->sglist, + buf->vb.width, buf->vb.height, 0); + } + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx88_free_buffer(q,buf); + return rc; +} + +void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) +{ + struct cx88_buffer *prev; + struct cx88_dmaqueue *cx88q = &dev->mpegq; + + dprintk( 1, "cx8802_buf_queue\n" ); + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); + + if (list_empty(&cx88q->active)) { + dprintk( 1, "queue is empty - first active\n" ); + list_add_tail(&buf->vb.queue,&cx88q->active); + cx8802_start_dma(dev, cx88q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = cx88q->count++; + mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(1,"[%p/%d] %s - first active\n", + buf, buf->vb.i, __func__); + + } else { + dprintk( 1, "queue is not empty - append to active\n" ); + prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue); + list_add_tail(&buf->vb.queue,&cx88q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = cx88q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk( 1, "[%p/%d] %s - append to active\n", + buf, buf->vb.i, __func__); + } +} + +/* ----------------------------------------------------------- */ + +static void do_cancel_buffers(struct cx8802_dev *dev, const char *reason, int restart) +{ + struct cx88_dmaqueue *q = &dev->mpegq; + struct cx88_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&dev->slock,flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", + buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); + } + if (restart) + { + dprintk(1, "restarting queue\n" ); + cx8802_restart_queue(dev,q); + } + spin_unlock_irqrestore(&dev->slock,flags); +} + +void cx8802_cancel_buffers(struct cx8802_dev *dev) +{ + struct cx88_dmaqueue *q = &dev->mpegq; + + dprintk( 1, "cx8802_cancel_buffers" ); + del_timer_sync(&q->timeout); + cx8802_stop_dma(dev); + do_cancel_buffers(dev,"cancel",0); +} + +static void cx8802_timeout(unsigned long data) +{ + struct cx8802_dev *dev = (struct cx8802_dev*)data; + + dprintk(1, "%s\n",__func__); + + if (debug) + cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]); + cx8802_stop_dma(dev); + do_cancel_buffers(dev,"timeout",1); +} + +static const char * cx88_mpeg_irqs[32] = { + "ts_risci1", NULL, NULL, NULL, + "ts_risci2", NULL, NULL, NULL, + "ts_oflow", NULL, NULL, NULL, + "ts_sync", NULL, NULL, NULL, + "opc_err", "par_err", "rip_err", "pci_abort", + "ts_err?", +}; + +static void cx8802_mpeg_irq(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + u32 status, mask, count; + + dprintk( 1, "cx8802_mpeg_irq\n" ); + status = cx_read(MO_TS_INTSTAT); + mask = cx_read(MO_TS_INTMSK); + if (0 == (status & mask)) + return; + + cx_write(MO_TS_INTSTAT, status); + + if (debug || (status & mask & ~0xff)) + cx88_print_irqbits(core->name, "irq mpeg ", + cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs), + status, mask); + + /* risc op code error */ + if (status & (1 << 16)) { + printk(KERN_WARNING "%s: mpeg risc op code error\n",core->name); + cx_clear(MO_TS_DMACNTRL, 0x11); + cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]); + } + + /* risc1 y */ + if (status & 0x01) { + dprintk( 1, "wake up\n" ); + spin_lock(&dev->slock); + count = cx_read(MO_TS_GPCNT); + cx88_wakeup(dev->core, &dev->mpegq, count); + spin_unlock(&dev->slock); + } + + /* risc2 y */ + if (status & 0x10) { + spin_lock(&dev->slock); + cx8802_restart_queue(dev,&dev->mpegq); + spin_unlock(&dev->slock); + } + + /* other general errors */ + if (status & 0x1f0100) { + dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 ); + spin_lock(&dev->slock); + cx8802_stop_dma(dev); + cx8802_restart_queue(dev,&dev->mpegq); + spin_unlock(&dev->slock); + } +} + +#define MAX_IRQ_LOOP 10 + +static irqreturn_t cx8802_irq(int irq, void *dev_id) +{ + struct cx8802_dev *dev = dev_id; + struct cx88_core *core = dev->core; + u32 status; + int loop, handled = 0; + + for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_TSINT); + if (0 == status) + goto out; + dprintk( 1, "cx8802_irq\n" ); + dprintk( 1, " loop: %d/%d\n", loop, MAX_IRQ_LOOP ); + dprintk( 1, " status: %d\n", status ); + handled = 1; + cx_write(MO_PCI_INTSTAT, status); + + if (status & core->pci_irqmask) + cx88_core_irq(core,status); + if (status & PCI_INT_TSINT) + cx8802_mpeg_irq(dev); + }; + if (MAX_IRQ_LOOP == loop) { + dprintk( 0, "clearing mask\n" ); + printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", + core->name); + cx_write(MO_PCI_INTMSK,0); + } + + out: + return IRQ_RETVAL(handled); +} + +static int cx8802_init_common(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + int err; + + /* pci init */ + if (pci_enable_device(dev->pci)) + return -EIO; + pci_set_master(dev->pci); + if (!pci_dma_supported(dev->pci,DMA_BIT_MASK(32))) { + printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name); + return -EIO; + } + + dev->pci_rev = dev->pci->revision; + pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%llx\n", dev->core->name, + pci_name(dev->pci), dev->pci_rev, dev->pci->irq, + dev->pci_lat,(unsigned long long)pci_resource_start(dev->pci,0)); + + /* initialize driver struct */ + spin_lock_init(&dev->slock); + + /* init dma queue */ + INIT_LIST_HEAD(&dev->mpegq.active); + INIT_LIST_HEAD(&dev->mpegq.queued); + dev->mpegq.timeout.function = cx8802_timeout; + dev->mpegq.timeout.data = (unsigned long)dev; + init_timer(&dev->mpegq.timeout); + cx88_risc_stopper(dev->pci,&dev->mpegq.stopper, + MO_TS_DMACNTRL,0x11,0x00); + + /* get irq */ + err = request_irq(dev->pci->irq, cx8802_irq, + IRQF_SHARED | IRQF_DISABLED, dev->core->name, dev); + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", + dev->core->name, dev->pci->irq); + return err; + } + cx_set(MO_PCI_INTMSK, core->pci_irqmask); + + /* everything worked */ + pci_set_drvdata(dev->pci,dev); + return 0; +} + +static void cx8802_fini_common(struct cx8802_dev *dev) +{ + dprintk( 2, "cx8802_fini_common\n" ); + cx8802_stop_dma(dev); + pci_disable_device(dev->pci); + + /* unregister stuff */ + free_irq(dev->pci->irq, dev); + pci_set_drvdata(dev->pci, NULL); + + /* free memory */ + btcx_riscmem_free(dev->pci,&dev->mpegq.stopper); +} + +/* ----------------------------------------------------------- */ + +static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) +{ + struct cx8802_dev *dev = pci_get_drvdata(pci_dev); + struct cx88_core *core = dev->core; + + /* stop mpeg dma */ + spin_lock(&dev->slock); + if (!list_empty(&dev->mpegq.active)) { + dprintk( 2, "suspend\n" ); + printk("%s: suspend mpeg\n", core->name); + cx8802_stop_dma(dev); + del_timer(&dev->mpegq.timeout); + } + spin_unlock(&dev->slock); + + /* FIXME -- shutdown device */ + cx88_shutdown(dev->core); + + pci_save_state(pci_dev); + if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { + pci_disable_device(pci_dev); + dev->state.disabled = 1; + } + return 0; +} + +static int cx8802_resume_common(struct pci_dev *pci_dev) +{ + struct cx8802_dev *dev = pci_get_drvdata(pci_dev); + struct cx88_core *core = dev->core; + int err; + + if (dev->state.disabled) { + err=pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + dev->core->name); + return err; + } + dev->state.disabled = 0; + } + err=pci_set_power_state(pci_dev, PCI_D0); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + dev->core->name); + pci_disable_device(pci_dev); + dev->state.disabled = 1; + + return err; + } + pci_restore_state(pci_dev); + + /* FIXME: re-initialize hardware */ + cx88_reset(dev->core); + + /* restart video+vbi capture */ + spin_lock(&dev->slock); + if (!list_empty(&dev->mpegq.active)) { + printk("%s: resume mpeg\n", core->name); + cx8802_restart_queue(dev,&dev->mpegq); + } + spin_unlock(&dev->slock); + + return 0; +} + +struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) +{ + struct cx8802_driver *d; + + list_for_each_entry(d, &dev->drvlist, drvlist) + if (d->type_id == btype) + return d; + + return NULL; +} + +/* Driver asked for hardware access. */ +static int cx8802_request_acquire(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + unsigned int i; + + /* Fail a request for hardware if the device is busy. */ + if (core->active_type_id != CX88_BOARD_NONE && + core->active_type_id != drv->type_id) + return -EBUSY; + + core->input = 0; + for (i = 0; + i < (sizeof(core->board.input) / sizeof(struct cx88_input)); + i++) { + if (core->board.input[i].type == CX88_VMUX_DVB) { + core->input = i; + break; + } + } + + if (drv->advise_acquire) + { + core->active_ref++; + if (core->active_type_id == CX88_BOARD_NONE) { + core->active_type_id = drv->type_id; + drv->advise_acquire(drv); + } + + mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); + } + + return 0; +} + +/* Driver asked to release hardware. */ +static int cx8802_request_release(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + + if (drv->advise_release && --core->active_ref == 0) + { + drv->advise_release(drv); + core->active_type_id = CX88_BOARD_NONE; + mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); + } + + return 0; +} + +static int cx8802_check_driver(struct cx8802_driver *drv) +{ + if (drv == NULL) + return -ENODEV; + + if ((drv->type_id != CX88_MPEG_DVB) && + (drv->type_id != CX88_MPEG_BLACKBIRD)) + return -EINVAL; + + if ((drv->hw_access != CX8802_DRVCTL_SHARED) && + (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE)) + return -EINVAL; + + if ((drv->probe == NULL) || + (drv->remove == NULL) || + (drv->advise_acquire == NULL) || + (drv->advise_release == NULL)) + return -EINVAL; + + return 0; +} + +int cx8802_register_driver(struct cx8802_driver *drv) +{ + struct cx8802_dev *dev; + struct cx8802_driver *driver; + int err, i = 0; + + printk(KERN_INFO + "cx88/2: registering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + + if ((err = cx8802_check_driver(drv)) != 0) { + printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n"); + return err; + } + + mutex_lock(&cx8802_mutex); + + list_for_each_entry(dev, &cx8802_devlist, devlist) { + printk(KERN_INFO + "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", + dev->core->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, dev->core->board.name, + dev->core->boardnr); + + /* Bring up a new struct for each driver instance */ + driver = kzalloc(sizeof(*drv),GFP_KERNEL); + if (driver == NULL) { + err = -ENOMEM; + goto out; + } + + /* Snapshot of the driver registration data */ + drv->core = dev->core; + drv->suspend = cx8802_suspend_common; + drv->resume = cx8802_resume_common; + drv->request_acquire = cx8802_request_acquire; + drv->request_release = cx8802_request_release; + memcpy(driver, drv, sizeof(*driver)); + + mutex_lock(&drv->core->lock); + err = drv->probe(driver); + if (err == 0) { + i++; + list_add_tail(&driver->drvlist, &dev->drvlist); + } else { + printk(KERN_ERR + "%s/2: cx8802 probe failed, err = %d\n", + dev->core->name, err); + } + mutex_unlock(&drv->core->lock); + } + + err = i ? 0 : -ENODEV; +out: + mutex_unlock(&cx8802_mutex); + return err; +} + +int cx8802_unregister_driver(struct cx8802_driver *drv) +{ + struct cx8802_dev *dev; + struct cx8802_driver *d, *dtmp; + int err = 0; + + printk(KERN_INFO + "cx88/2: unregistering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + + mutex_lock(&cx8802_mutex); + + list_for_each_entry(dev, &cx8802_devlist, devlist) { + printk(KERN_INFO + "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", + dev->core->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, dev->core->board.name, + dev->core->boardnr); + + mutex_lock(&dev->core->lock); + + list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) { + /* only unregister the correct driver type */ + if (d->type_id != drv->type_id) + continue; + + err = d->remove(d); + if (err == 0) { + list_del(&d->drvlist); + kfree(d); + } else + printk(KERN_ERR "%s/2: cx8802 driver remove " + "failed (%d)\n", dev->core->name, err); + } + + mutex_unlock(&dev->core->lock); + } + + mutex_unlock(&cx8802_mutex); + + return err; +} + +/* ----------------------------------------------------------- */ +static int __devinit cx8802_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cx8802_dev *dev; + struct cx88_core *core; + int err; + + /* general setup */ + core = cx88_core_get(pci_dev); + if (NULL == core) + return -EINVAL; + + printk("%s/2: cx2388x 8802 Driver Manager\n", core->name); + + err = -ENODEV; + if (!core->board.mpeg) + goto fail_core; + + err = -ENOMEM; + dev = kzalloc(sizeof(*dev),GFP_KERNEL); + if (NULL == dev) + goto fail_core; + dev->pci = pci_dev; + dev->core = core; + + /* Maintain a reference so cx88-video can query the 8802 device. */ + core->dvbdev = dev; + + err = cx8802_init_common(dev); + if (err != 0) + goto fail_free; + + INIT_LIST_HEAD(&dev->drvlist); + mutex_lock(&cx8802_mutex); + list_add_tail(&dev->devlist,&cx8802_devlist); + mutex_unlock(&cx8802_mutex); + + /* now autoload cx88-dvb or cx88-blackbird */ + request_modules(dev); + return 0; + + fail_free: + kfree(dev); + fail_core: + core->dvbdev = NULL; + cx88_core_put(core,pci_dev); + return err; +} + +static void __devexit cx8802_remove(struct pci_dev *pci_dev) +{ + struct cx8802_dev *dev; + + dev = pci_get_drvdata(pci_dev); + + dprintk( 1, "%s\n", __func__); + + flush_request_modules(dev); + + mutex_lock(&dev->core->lock); + + if (!list_empty(&dev->drvlist)) { + struct cx8802_driver *drv, *tmp; + int err; + + printk(KERN_WARNING "%s/2: Trying to remove cx8802 driver " + "while cx8802 sub-drivers still loaded?!\n", + dev->core->name); + + list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) { + err = drv->remove(drv); + if (err == 0) { + list_del(&drv->drvlist); + } else + printk(KERN_ERR "%s/2: cx8802 driver remove " + "failed (%d)\n", dev->core->name, err); + kfree(drv); + } + } + + mutex_unlock(&dev->core->lock); + + /* Destroy any 8802 reference. */ + dev->core->dvbdev = NULL; + + /* common */ + cx8802_fini_common(dev); + cx88_core_put(dev->core,dev->pci); + kfree(dev); +} + +static const struct pci_device_id cx8802_pci_tbl[] = { + { + .vendor = 0x14f1, + .device = 0x8802, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* --- end of list --- */ + } +}; +MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); + +static struct pci_driver cx8802_pci_driver = { + .name = "cx88-mpeg driver manager", + .id_table = cx8802_pci_tbl, + .probe = cx8802_probe, + .remove = __devexit_p(cx8802_remove), +}; + +static int __init cx8802_init(void) +{ + printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx8802_pci_driver); +} + +static void __exit cx8802_fini(void) +{ + pci_unregister_driver(&cx8802_pci_driver); +} + +module_init(cx8802_init); +module_exit(cx8802_fini); +EXPORT_SYMBOL(cx8802_buf_prepare); +EXPORT_SYMBOL(cx8802_buf_queue); +EXPORT_SYMBOL(cx8802_cancel_buffers); + +EXPORT_SYMBOL(cx8802_register_driver); +EXPORT_SYMBOL(cx8802_unregister_driver); +EXPORT_SYMBOL(cx8802_get_driver); +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,836 @@ +/* + + cx88x-hw.h - CX2388x register offsets + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + 2001 Michael Eskin + 2002 Yurij Sysoev + 2003 Gerd Knorr + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _CX88_REG_H_ +#define _CX88_REG_H_ + +/* ---------------------------------------------------------------------- */ +/* PCI IDs and config space */ + +#ifndef PCI_VENDOR_ID_CONEXANT +# define PCI_VENDOR_ID_CONEXANT 0x14F1 +#endif +#ifndef PCI_DEVICE_ID_CX2300_VID +# define PCI_DEVICE_ID_CX2300_VID 0x8800 +#endif + +#define CX88X_DEVCTRL 0x40 +#define CX88X_EN_TBFX 0x02 +#define CX88X_EN_VSFX 0x04 + +/* ---------------------------------------------------------------------- */ +/* PCI controller registers */ + +/* Command and Status Register */ +#define F0_CMD_STAT_MM 0x2f0004 +#define F1_CMD_STAT_MM 0x2f0104 +#define F2_CMD_STAT_MM 0x2f0204 +#define F3_CMD_STAT_MM 0x2f0304 +#define F4_CMD_STAT_MM 0x2f0404 + +/* Device Control #1 */ +#define F0_DEV_CNTRL1_MM 0x2f0040 +#define F1_DEV_CNTRL1_MM 0x2f0140 +#define F2_DEV_CNTRL1_MM 0x2f0240 +#define F3_DEV_CNTRL1_MM 0x2f0340 +#define F4_DEV_CNTRL1_MM 0x2f0440 + +/* Device Control #1 */ +#define F0_BAR0_MM 0x2f0010 +#define F1_BAR0_MM 0x2f0110 +#define F2_BAR0_MM 0x2f0210 +#define F3_BAR0_MM 0x2f0310 +#define F4_BAR0_MM 0x2f0410 + +/* ---------------------------------------------------------------------- */ +/* DMA Controller registers */ + +#define MO_PDMA_STHRSH 0x200000 // Source threshold +#define MO_PDMA_STADRS 0x200004 // Source target address +#define MO_PDMA_SIADRS 0x200008 // Source internal address +#define MO_PDMA_SCNTRL 0x20000C // Source control +#define MO_PDMA_DTHRSH 0x200010 // Destination threshold +#define MO_PDMA_DTADRS 0x200014 // Destination target address +#define MO_PDMA_DIADRS 0x200018 // Destination internal address +#define MO_PDMA_DCNTRL 0x20001C // Destination control +#define MO_LD_SSID 0x200030 // Load subsystem ID +#define MO_DEV_CNTRL2 0x200034 // Device control +#define MO_PCI_INTMSK 0x200040 // PCI interrupt mask +#define MO_PCI_INTSTAT 0x200044 // PCI interrupt status +#define MO_PCI_INTMSTAT 0x200048 // PCI interrupt masked status +#define MO_VID_INTMSK 0x200050 // Video interrupt mask +#define MO_VID_INTSTAT 0x200054 // Video interrupt status +#define MO_VID_INTMSTAT 0x200058 // Video interrupt masked status +#define MO_VID_INTSSTAT 0x20005C // Video interrupt set status +#define MO_AUD_INTMSK 0x200060 // Audio interrupt mask +#define MO_AUD_INTSTAT 0x200064 // Audio interrupt status +#define MO_AUD_INTMSTAT 0x200068 // Audio interrupt masked status +#define MO_AUD_INTSSTAT 0x20006C // Audio interrupt set status +#define MO_TS_INTMSK 0x200070 // Transport stream interrupt mask +#define MO_TS_INTSTAT 0x200074 // Transport stream interrupt status +#define MO_TS_INTMSTAT 0x200078 // Transport stream interrupt mask status +#define MO_TS_INTSSTAT 0x20007C // Transport stream interrupt set status +#define MO_VIP_INTMSK 0x200080 // VIP interrupt mask +#define MO_VIP_INTSTAT 0x200084 // VIP interrupt status +#define MO_VIP_INTMSTAT 0x200088 // VIP interrupt masked status +#define MO_VIP_INTSSTAT 0x20008C // VIP interrupt set status +#define MO_GPHST_INTMSK 0x200090 // Host interrupt mask +#define MO_GPHST_INTSTAT 0x200094 // Host interrupt status +#define MO_GPHST_INTMSTAT 0x200098 // Host interrupt masked status +#define MO_GPHST_INTSSTAT 0x20009C // Host interrupt set status + +// DMA Channels 1-6 belong to SPIPE +#define MO_DMA7_PTR1 0x300018 // {24}RW* DMA Current Ptr : Ch#7 +#define MO_DMA8_PTR1 0x30001C // {24}RW* DMA Current Ptr : Ch#8 + +// DMA Channels 9-20 belong to SPIPE +#define MO_DMA21_PTR1 0x300080 // {24}R0* DMA Current Ptr : Ch#21 +#define MO_DMA22_PTR1 0x300084 // {24}R0* DMA Current Ptr : Ch#22 +#define MO_DMA23_PTR1 0x300088 // {24}R0* DMA Current Ptr : Ch#23 +#define MO_DMA24_PTR1 0x30008C // {24}R0* DMA Current Ptr : Ch#24 +#define MO_DMA25_PTR1 0x300090 // {24}R0* DMA Current Ptr : Ch#25 +#define MO_DMA26_PTR1 0x300094 // {24}R0* DMA Current Ptr : Ch#26 +#define MO_DMA27_PTR1 0x300098 // {24}R0* DMA Current Ptr : Ch#27 +#define MO_DMA28_PTR1 0x30009C // {24}R0* DMA Current Ptr : Ch#28 +#define MO_DMA29_PTR1 0x3000A0 // {24}R0* DMA Current Ptr : Ch#29 +#define MO_DMA30_PTR1 0x3000A4 // {24}R0* DMA Current Ptr : Ch#30 +#define MO_DMA31_PTR1 0x3000A8 // {24}R0* DMA Current Ptr : Ch#31 +#define MO_DMA32_PTR1 0x3000AC // {24}R0* DMA Current Ptr : Ch#32 + +#define MO_DMA21_PTR2 0x3000C0 // {24}RW* DMA Tab Ptr : Ch#21 +#define MO_DMA22_PTR2 0x3000C4 // {24}RW* DMA Tab Ptr : Ch#22 +#define MO_DMA23_PTR2 0x3000C8 // {24}RW* DMA Tab Ptr : Ch#23 +#define MO_DMA24_PTR2 0x3000CC // {24}RW* DMA Tab Ptr : Ch#24 +#define MO_DMA25_PTR2 0x3000D0 // {24}RW* DMA Tab Ptr : Ch#25 +#define MO_DMA26_PTR2 0x3000D4 // {24}RW* DMA Tab Ptr : Ch#26 +#define MO_DMA27_PTR2 0x3000D8 // {24}RW* DMA Tab Ptr : Ch#27 +#define MO_DMA28_PTR2 0x3000DC // {24}RW* DMA Tab Ptr : Ch#28 +#define MO_DMA29_PTR2 0x3000E0 // {24}RW* DMA Tab Ptr : Ch#29 +#define MO_DMA30_PTR2 0x3000E4 // {24}RW* DMA Tab Ptr : Ch#30 +#define MO_DMA31_PTR2 0x3000E8 // {24}RW* DMA Tab Ptr : Ch#31 +#define MO_DMA32_PTR2 0x3000EC // {24}RW* DMA Tab Ptr : Ch#32 + +#define MO_DMA21_CNT1 0x300100 // {11}RW* DMA Buffer Size : Ch#21 +#define MO_DMA22_CNT1 0x300104 // {11}RW* DMA Buffer Size : Ch#22 +#define MO_DMA23_CNT1 0x300108 // {11}RW* DMA Buffer Size : Ch#23 +#define MO_DMA24_CNT1 0x30010C // {11}RW* DMA Buffer Size : Ch#24 +#define MO_DMA25_CNT1 0x300110 // {11}RW* DMA Buffer Size : Ch#25 +#define MO_DMA26_CNT1 0x300114 // {11}RW* DMA Buffer Size : Ch#26 +#define MO_DMA27_CNT1 0x300118 // {11}RW* DMA Buffer Size : Ch#27 +#define MO_DMA28_CNT1 0x30011C // {11}RW* DMA Buffer Size : Ch#28 +#define MO_DMA29_CNT1 0x300120 // {11}RW* DMA Buffer Size : Ch#29 +#define MO_DMA30_CNT1 0x300124 // {11}RW* DMA Buffer Size : Ch#30 +#define MO_DMA31_CNT1 0x300128 // {11}RW* DMA Buffer Size : Ch#31 +#define MO_DMA32_CNT1 0x30012C // {11}RW* DMA Buffer Size : Ch#32 + +#define MO_DMA21_CNT2 0x300140 // {11}RW* DMA Table Size : Ch#21 +#define MO_DMA22_CNT2 0x300144 // {11}RW* DMA Table Size : Ch#22 +#define MO_DMA23_CNT2 0x300148 // {11}RW* DMA Table Size : Ch#23 +#define MO_DMA24_CNT2 0x30014C // {11}RW* DMA Table Size : Ch#24 +#define MO_DMA25_CNT2 0x300150 // {11}RW* DMA Table Size : Ch#25 +#define MO_DMA26_CNT2 0x300154 // {11}RW* DMA Table Size : Ch#26 +#define MO_DMA27_CNT2 0x300158 // {11}RW* DMA Table Size : Ch#27 +#define MO_DMA28_CNT2 0x30015C // {11}RW* DMA Table Size : Ch#28 +#define MO_DMA29_CNT2 0x300160 // {11}RW* DMA Table Size : Ch#29 +#define MO_DMA30_CNT2 0x300164 // {11}RW* DMA Table Size : Ch#30 +#define MO_DMA31_CNT2 0x300168 // {11}RW* DMA Table Size : Ch#31 +#define MO_DMA32_CNT2 0x30016C // {11}RW* DMA Table Size : Ch#32 + + +/* ---------------------------------------------------------------------- */ +/* Video registers */ + +#define MO_VIDY_DMA 0x310000 // {64}RWp Video Y +#define MO_VIDU_DMA 0x310008 // {64}RWp Video U +#define MO_VIDV_DMA 0x310010 // {64}RWp Video V +#define MO_VBI_DMA 0x310018 // {64}RWp VBI (Vertical blanking interval) + +#define MO_DEVICE_STATUS 0x310100 +#define MO_INPUT_FORMAT 0x310104 +#define MO_AGC_BURST 0x31010c +#define MO_CONTR_BRIGHT 0x310110 +#define MO_UV_SATURATION 0x310114 +#define MO_HUE 0x310118 +#define MO_HTOTAL 0x310120 +#define MO_HDELAY_EVEN 0x310124 +#define MO_HDELAY_ODD 0x310128 +#define MO_VDELAY_ODD 0x31012c +#define MO_VDELAY_EVEN 0x310130 +#define MO_HACTIVE_EVEN 0x31013c +#define MO_HACTIVE_ODD 0x310140 +#define MO_VACTIVE_EVEN 0x310144 +#define MO_VACTIVE_ODD 0x310148 +#define MO_HSCALE_EVEN 0x31014c +#define MO_HSCALE_ODD 0x310150 +#define MO_VSCALE_EVEN 0x310154 +#define MO_FILTER_EVEN 0x31015c +#define MO_VSCALE_ODD 0x310158 +#define MO_FILTER_ODD 0x310160 +#define MO_OUTPUT_FORMAT 0x310164 + +#define MO_PLL_REG 0x310168 // PLL register +#define MO_PLL_ADJ_CTRL 0x31016c // PLL adjust control register +#define MO_SCONV_REG 0x310170 // sample rate conversion register +#define MO_SCONV_FIFO 0x310174 // sample rate conversion fifo +#define MO_SUB_STEP 0x310178 // subcarrier step size +#define MO_SUB_STEP_DR 0x31017c // subcarrier step size for DR line + +#define MO_CAPTURE_CTRL 0x310180 // capture control +#define MO_COLOR_CTRL 0x310184 +#define MO_VBI_PACKET 0x310188 // vbi packet size / delay +#define MO_FIELD_COUNT 0x310190 // field counter +#define MO_VIP_CONFIG 0x310194 +#define MO_VBOS_CONTROL 0x3101a8 + +#define MO_AGC_BACK_VBI 0x310200 +#define MO_AGC_SYNC_TIP1 0x310208 + +#define MO_VIDY_GPCNT 0x31C020 // {16}RO Video Y general purpose counter +#define MO_VIDU_GPCNT 0x31C024 // {16}RO Video U general purpose counter +#define MO_VIDV_GPCNT 0x31C028 // {16}RO Video V general purpose counter +#define MO_VBI_GPCNT 0x31C02C // {16}RO VBI general purpose counter +#define MO_VIDY_GPCNTRL 0x31C030 // {2}WO Video Y general purpose control +#define MO_VIDU_GPCNTRL 0x31C034 // {2}WO Video U general purpose control +#define MO_VIDV_GPCNTRL 0x31C038 // {2}WO Video V general purpose control +#define MO_VBI_GPCNTRL 0x31C03C // {2}WO VBI general purpose counter +#define MO_VID_DMACNTRL 0x31C040 // {8}RW Video DMA control +#define MO_VID_XFR_STAT 0x31C044 // {1}RO Video transfer status + + +/* ---------------------------------------------------------------------- */ +/* audio registers */ + +#define MO_AUDD_DMA 0x320000 // {64}RWp Audio downstream +#define MO_AUDU_DMA 0x320008 // {64}RWp Audio upstream +#define MO_AUDR_DMA 0x320010 // {64}RWp Audio RDS (downstream) +#define MO_AUDD_GPCNT 0x32C020 // {16}RO Audio down general purpose counter +#define MO_AUDU_GPCNT 0x32C024 // {16}RO Audio up general purpose counter +#define MO_AUDR_GPCNT 0x32C028 // {16}RO Audio RDS general purpose counter +#define MO_AUDD_GPCNTRL 0x32C030 // {2}WO Audio down general purpose control +#define MO_AUDU_GPCNTRL 0x32C034 // {2}WO Audio up general purpose control +#define MO_AUDR_GPCNTRL 0x32C038 // {2}WO Audio RDS general purpose control +#define MO_AUD_DMACNTRL 0x32C040 // {6}RW Audio DMA control +#define MO_AUD_XFR_STAT 0x32C044 // {1}RO Audio transfer status +#define MO_AUDD_LNGTH 0x32C048 // {12}RW Audio down line length +#define MO_AUDR_LNGTH 0x32C04C // {12}RW Audio RDS line length + +#define AUD_INIT 0x320100 +#define AUD_INIT_LD 0x320104 +#define AUD_SOFT_RESET 0x320108 +#define AUD_I2SINPUTCNTL 0x320120 +#define AUD_BAUDRATE 0x320124 +#define AUD_I2SOUTPUTCNTL 0x320128 +#define AAGC_HYST 0x320134 +#define AAGC_GAIN 0x320138 +#define AAGC_DEF 0x32013c +#define AUD_IIR1_0_SEL 0x320150 +#define AUD_IIR1_0_SHIFT 0x320154 +#define AUD_IIR1_1_SEL 0x320158 +#define AUD_IIR1_1_SHIFT 0x32015c +#define AUD_IIR1_2_SEL 0x320160 +#define AUD_IIR1_2_SHIFT 0x320164 +#define AUD_IIR1_3_SEL 0x320168 +#define AUD_IIR1_3_SHIFT 0x32016c +#define AUD_IIR1_4_SEL 0x320170 +#define AUD_IIR1_4_SHIFT 0x32017c +#define AUD_IIR1_5_SEL 0x320180 +#define AUD_IIR1_5_SHIFT 0x320184 +#define AUD_IIR2_0_SEL 0x320190 +#define AUD_IIR2_0_SHIFT 0x320194 +#define AUD_IIR2_1_SEL 0x320198 +#define AUD_IIR2_1_SHIFT 0x32019c +#define AUD_IIR2_2_SEL 0x3201a0 +#define AUD_IIR2_2_SHIFT 0x3201a4 +#define AUD_IIR2_3_SEL 0x3201a8 +#define AUD_IIR2_3_SHIFT 0x3201ac +#define AUD_IIR3_0_SEL 0x3201c0 +#define AUD_IIR3_0_SHIFT 0x3201c4 +#define AUD_IIR3_1_SEL 0x3201c8 +#define AUD_IIR3_1_SHIFT 0x3201cc +#define AUD_IIR3_2_SEL 0x3201d0 +#define AUD_IIR3_2_SHIFT 0x3201d4 +#define AUD_IIR4_0_SEL 0x3201e0 +#define AUD_IIR4_0_SHIFT 0x3201e4 +#define AUD_IIR4_1_SEL 0x3201e8 +#define AUD_IIR4_1_SHIFT 0x3201ec +#define AUD_IIR4_2_SEL 0x3201f0 +#define AUD_IIR4_2_SHIFT 0x3201f4 +#define AUD_IIR4_0_CA0 0x320200 +#define AUD_IIR4_0_CA1 0x320204 +#define AUD_IIR4_0_CA2 0x320208 +#define AUD_IIR4_0_CB0 0x32020c +#define AUD_IIR4_0_CB1 0x320210 +#define AUD_IIR4_1_CA0 0x320214 +#define AUD_IIR4_1_CA1 0x320218 +#define AUD_IIR4_1_CA2 0x32021c +#define AUD_IIR4_1_CB0 0x320220 +#define AUD_IIR4_1_CB1 0x320224 +#define AUD_IIR4_2_CA0 0x320228 +#define AUD_IIR4_2_CA1 0x32022c +#define AUD_IIR4_2_CA2 0x320230 +#define AUD_IIR4_2_CB0 0x320234 +#define AUD_IIR4_2_CB1 0x320238 +#define AUD_HP_MD_IIR4_1 0x320250 +#define AUD_HP_PROG_IIR4_1 0x320254 +#define AUD_FM_MODE_ENABLE 0x320258 +#define AUD_POLY0_DDS_CONSTANT 0x320270 +#define AUD_DN0_FREQ 0x320274 +#define AUD_DN1_FREQ 0x320278 +#define AUD_DN1_FREQ_SHIFT 0x32027c +#define AUD_DN1_AFC 0x320280 +#define AUD_DN1_SRC_SEL 0x320284 +#define AUD_DN1_SHFT 0x320288 +#define AUD_DN2_FREQ 0x32028c +#define AUD_DN2_FREQ_SHIFT 0x320290 +#define AUD_DN2_AFC 0x320294 +#define AUD_DN2_SRC_SEL 0x320298 +#define AUD_DN2_SHFT 0x32029c +#define AUD_CRDC0_SRC_SEL 0x320300 +#define AUD_CRDC0_SHIFT 0x320304 +#define AUD_CORDIC_SHIFT_0 0x320308 +#define AUD_CRDC1_SRC_SEL 0x32030c +#define AUD_CRDC1_SHIFT 0x320310 +#define AUD_CORDIC_SHIFT_1 0x320314 +#define AUD_DCOC_0_SRC 0x320320 +#define AUD_DCOC0_SHIFT 0x320324 +#define AUD_DCOC_0_SHIFT_IN0 0x320328 +#define AUD_DCOC_0_SHIFT_IN1 0x32032c +#define AUD_DCOC_1_SRC 0x320330 +#define AUD_DCOC1_SHIFT 0x320334 +#define AUD_DCOC_1_SHIFT_IN0 0x320338 +#define AUD_DCOC_1_SHIFT_IN1 0x32033c +#define AUD_DCOC_2_SRC 0x320340 +#define AUD_DCOC2_SHIFT 0x320344 +#define AUD_DCOC_2_SHIFT_IN0 0x320348 +#define AUD_DCOC_2_SHIFT_IN1 0x32034c +#define AUD_DCOC_PASS_IN 0x320350 +#define AUD_PDET_SRC 0x320370 +#define AUD_PDET_SHIFT 0x320374 +#define AUD_PILOT_BQD_1_K0 0x320380 +#define AUD_PILOT_BQD_1_K1 0x320384 +#define AUD_PILOT_BQD_1_K2 0x320388 +#define AUD_PILOT_BQD_1_K3 0x32038c +#define AUD_PILOT_BQD_1_K4 0x320390 +#define AUD_PILOT_BQD_2_K0 0x320394 +#define AUD_PILOT_BQD_2_K1 0x320398 +#define AUD_PILOT_BQD_2_K2 0x32039c +#define AUD_PILOT_BQD_2_K3 0x3203a0 +#define AUD_PILOT_BQD_2_K4 0x3203a4 +#define AUD_THR_FR 0x3203c0 +#define AUD_X_PROG 0x3203c4 +#define AUD_Y_PROG 0x3203c8 +#define AUD_HARMONIC_MULT 0x3203cc +#define AUD_C1_UP_THR 0x3203d0 +#define AUD_C1_LO_THR 0x3203d4 +#define AUD_C2_UP_THR 0x3203d8 +#define AUD_C2_LO_THR 0x3203dc +#define AUD_PLL_EN 0x320400 +#define AUD_PLL_SRC 0x320404 +#define AUD_PLL_SHIFT 0x320408 +#define AUD_PLL_IF_SEL 0x32040c +#define AUD_PLL_IF_SHIFT 0x320410 +#define AUD_BIQUAD_PLL_K0 0x320414 +#define AUD_BIQUAD_PLL_K1 0x320418 +#define AUD_BIQUAD_PLL_K2 0x32041c +#define AUD_BIQUAD_PLL_K3 0x320420 +#define AUD_BIQUAD_PLL_K4 0x320424 +#define AUD_DEEMPH0_SRC_SEL 0x320440 +#define AUD_DEEMPH0_SHIFT 0x320444 +#define AUD_DEEMPH0_G0 0x320448 +#define AUD_DEEMPH0_A0 0x32044c +#define AUD_DEEMPH0_B0 0x320450 +#define AUD_DEEMPH0_A1 0x320454 +#define AUD_DEEMPH0_B1 0x320458 +#define AUD_DEEMPH1_SRC_SEL 0x32045c +#define AUD_DEEMPH1_SHIFT 0x320460 +#define AUD_DEEMPH1_G0 0x320464 +#define AUD_DEEMPH1_A0 0x320468 +#define AUD_DEEMPH1_B0 0x32046c +#define AUD_DEEMPH1_A1 0x320470 +#define AUD_DEEMPH1_B1 0x320474 +#define AUD_OUT0_SEL 0x320490 +#define AUD_OUT0_SHIFT 0x320494 +#define AUD_OUT1_SEL 0x320498 +#define AUD_OUT1_SHIFT 0x32049c +#define AUD_RDSI_SEL 0x3204a0 +#define AUD_RDSI_SHIFT 0x3204a4 +#define AUD_RDSQ_SEL 0x3204a8 +#define AUD_RDSQ_SHIFT 0x3204ac +#define AUD_DBX_IN_GAIN 0x320500 +#define AUD_DBX_WBE_GAIN 0x320504 +#define AUD_DBX_SE_GAIN 0x320508 +#define AUD_DBX_RMS_WBE 0x32050c +#define AUD_DBX_RMS_SE 0x320510 +#define AUD_DBX_SE_BYPASS 0x320514 +#define AUD_FAWDETCTL 0x320530 +#define AUD_FAWDETWINCTL 0x320534 +#define AUD_DEEMPHGAIN_R 0x320538 +#define AUD_DEEMPHNUMER1_R 0x32053c +#define AUD_DEEMPHNUMER2_R 0x320540 +#define AUD_DEEMPHDENOM1_R 0x320544 +#define AUD_DEEMPHDENOM2_R 0x320548 +#define AUD_ERRLOGPERIOD_R 0x32054c +#define AUD_ERRINTRPTTHSHLD1_R 0x320550 +#define AUD_ERRINTRPTTHSHLD2_R 0x320554 +#define AUD_ERRINTRPTTHSHLD3_R 0x320558 +#define AUD_NICAM_STATUS1 0x32055c +#define AUD_NICAM_STATUS2 0x320560 +#define AUD_ERRLOG1 0x320564 +#define AUD_ERRLOG2 0x320568 +#define AUD_ERRLOG3 0x32056c +#define AUD_DAC_BYPASS_L 0x320580 +#define AUD_DAC_BYPASS_R 0x320584 +#define AUD_DAC_BYPASS_CTL 0x320588 +#define AUD_CTL 0x32058c +#define AUD_STATUS 0x320590 +#define AUD_VOL_CTL 0x320594 +#define AUD_BAL_CTL 0x320598 +#define AUD_START_TIMER 0x3205b0 +#define AUD_MODE_CHG_TIMER 0x3205b4 +#define AUD_POLYPH80SCALEFAC 0x3205b8 +#define AUD_DMD_RA_DDS 0x3205bc +#define AUD_I2S_RA_DDS 0x3205c0 +#define AUD_RATE_THRES_DMD 0x3205d0 +#define AUD_RATE_THRES_I2S 0x3205d4 +#define AUD_RATE_ADJ1 0x3205d8 +#define AUD_RATE_ADJ2 0x3205dc +#define AUD_RATE_ADJ3 0x3205e0 +#define AUD_RATE_ADJ4 0x3205e4 +#define AUD_RATE_ADJ5 0x3205e8 +#define AUD_APB_IN_RATE_ADJ 0x3205ec +#define AUD_I2SCNTL 0x3205ec +#define AUD_PHASE_FIX_CTL 0x3205f0 +#define AUD_PLL_PRESCALE 0x320600 +#define AUD_PLL_DDS 0x320604 +#define AUD_PLL_INT 0x320608 +#define AUD_PLL_FRAC 0x32060c +#define AUD_PLL_JTAG 0x320620 +#define AUD_PLL_SPMP 0x320624 +#define AUD_AFE_12DB_EN 0x320628 + +// Audio QAM Register Addresses +#define AUD_PDF_DDS_CNST_BYTE2 0x320d01 +#define AUD_PDF_DDS_CNST_BYTE1 0x320d02 +#define AUD_PDF_DDS_CNST_BYTE0 0x320d03 +#define AUD_PHACC_FREQ_8MSB 0x320d2a +#define AUD_PHACC_FREQ_8LSB 0x320d2b +#define AUD_QAM_MODE 0x320d04 + + +/* ---------------------------------------------------------------------- */ +/* transport stream registers */ + +#define MO_TS_DMA 0x330000 // {64}RWp Transport stream downstream +#define MO_TS_GPCNT 0x33C020 // {16}RO TS general purpose counter +#define MO_TS_GPCNTRL 0x33C030 // {2}WO TS general purpose control +#define MO_TS_DMACNTRL 0x33C040 // {6}RW TS DMA control +#define MO_TS_XFR_STAT 0x33C044 // {1}RO TS transfer status +#define MO_TS_LNGTH 0x33C048 // {12}RW TS line length + +#define TS_HW_SOP_CNTRL 0x33C04C +#define TS_GEN_CNTRL 0x33C050 +#define TS_BD_PKT_STAT 0x33C054 +#define TS_SOP_STAT 0x33C058 +#define TS_FIFO_OVFL_STAT 0x33C05C +#define TS_VALERR_CNTRL 0x33C060 + + +/* ---------------------------------------------------------------------- */ +/* VIP registers */ + +#define MO_VIPD_DMA 0x340000 // {64}RWp VIP downstream +#define MO_VIPU_DMA 0x340008 // {64}RWp VIP upstream +#define MO_VIPD_GPCNT 0x34C020 // {16}RO VIP down general purpose counter +#define MO_VIPU_GPCNT 0x34C024 // {16}RO VIP up general purpose counter +#define MO_VIPD_GPCNTRL 0x34C030 // {2}WO VIP down general purpose control +#define MO_VIPU_GPCNTRL 0x34C034 // {2}WO VIP up general purpose control +#define MO_VIP_DMACNTRL 0x34C040 // {6}RW VIP DMA control +#define MO_VIP_XFR_STAT 0x34C044 // {1}RO VIP transfer status +#define MO_VIP_CFG 0x340048 // VIP configuration +#define MO_VIPU_CNTRL 0x34004C // VIP upstream control #1 +#define MO_VIPD_CNTRL 0x340050 // VIP downstream control #2 +#define MO_VIPD_LNGTH 0x340054 // VIP downstream line length +#define MO_VIP_BRSTLN 0x340058 // VIP burst length +#define MO_VIP_INTCNTRL 0x34C05C // VIP Interrupt Control +#define MO_VIP_XFTERM 0x340060 // VIP transfer terminate + + +/* ---------------------------------------------------------------------- */ +/* misc registers */ + +#define MO_M2M_DMA 0x350000 // {64}RWp Mem2Mem DMA Bfr +#define MO_GP0_IO 0x350010 // {32}RW* GPIOoutput enablesdata I/O +#define MO_GP1_IO 0x350014 // {32}RW* GPIOoutput enablesdata I/O +#define MO_GP2_IO 0x350018 // {32}RW* GPIOoutput enablesdata I/O +#define MO_GP3_IO 0x35001C // {32}RW* GPIO Mode/Ctrloutput enables +#define MO_GPIO 0x350020 // {32}RW* GPIO I2C Ctrldata I/O +#define MO_GPOE 0x350024 // {32}RW GPIO I2C Ctrloutput enables +#define MO_GP_ISM 0x350028 // {16}WO GPIO Intr Sens/Pol + +#define MO_PLL_B 0x35C008 // {32}RW* PLL Control for ASB bus clks +#define MO_M2M_CNT 0x35C024 // {32}RW Mem2Mem DMA Cnt +#define MO_M2M_XSUM 0x35C028 // {32}RO M2M XOR-Checksum +#define MO_CRC 0x35C02C // {16}RW CRC16 init/result +#define MO_CRC_D 0x35C030 // {32}WO CRC16 new data in +#define MO_TM_CNT_LDW 0x35C034 // {32}RO Timer : Counter low dword +#define MO_TM_CNT_UW 0x35C038 // {16}RO Timer : Counter high word +#define MO_TM_LMT_LDW 0x35C03C // {32}RW Timer : Limit low dword +#define MO_TM_LMT_UW 0x35C040 // {32}RW Timer : Limit high word +#define MO_PINMUX_IO 0x35C044 // {8}RW Pin Mux Control +#define MO_TSTSEL_IO 0x35C048 // {2}RW Pin Mux Control +#define MO_AFECFG_IO 0x35C04C // AFE configuration reg +#define MO_DDS_IO 0x35C050 // DDS Increment reg +#define MO_DDSCFG_IO 0x35C054 // DDS Configuration reg +#define MO_SAMPLE_IO 0x35C058 // IRIn sample reg +#define MO_SRST_IO 0x35C05C // Output system reset reg + +#define MO_INT1_MSK 0x35C060 // DMA RISC interrupt mask +#define MO_INT1_STAT 0x35C064 // DMA RISC interrupt status +#define MO_INT1_MSTAT 0x35C068 // DMA RISC interrupt masked status + + +/* ---------------------------------------------------------------------- */ +/* i2c bus registers */ + +#define MO_I2C 0x368000 // I2C data/control +#define MO_I2C_DIV (0xf<<4) +#define MO_I2C_SYNC (1<<3) +#define MO_I2C_W3B (1<<2) +#define MO_I2C_SCL (1<<1) +#define MO_I2C_SDA (1<<0) + + +/* ---------------------------------------------------------------------- */ +/* general purpose host registers */ +/* FIXME: tyops? s/0x35/0x38/ ?? */ + +#define MO_GPHSTD_DMA 0x350000 // {64}RWp Host downstream +#define MO_GPHSTU_DMA 0x350008 // {64}RWp Host upstream +#define MO_GPHSTU_CNTRL 0x380048 // Host upstream control #1 +#define MO_GPHSTD_CNTRL 0x38004C // Host downstream control #2 +#define MO_GPHSTD_LNGTH 0x380050 // Host downstream line length +#define MO_GPHST_WSC 0x380054 // Host wait state control +#define MO_GPHST_XFR 0x380058 // Host transfer control +#define MO_GPHST_WDTH 0x38005C // Host interface width +#define MO_GPHST_HDSHK 0x380060 // Host peripheral handshake +#define MO_GPHST_MUX16 0x380064 // Host muxed 16-bit transfer parameters +#define MO_GPHST_MODE 0x380068 // Host mode select + +#define MO_GPHSTD_GPCNT 0x35C020 // Host down general purpose counter +#define MO_GPHSTU_GPCNT 0x35C024 // Host up general purpose counter +#define MO_GPHSTD_GPCNTRL 0x38C030 // Host down general purpose control +#define MO_GPHSTU_GPCNTRL 0x38C034 // Host up general purpose control +#define MO_GPHST_DMACNTRL 0x38C040 // Host DMA control +#define MO_GPHST_XFR_STAT 0x38C044 // Host transfer status +#define MO_GPHST_SOFT_RST 0x38C06C // Host software reset + + +/* ---------------------------------------------------------------------- */ +/* RISC instructions */ + +#define RISC_SYNC 0x80000000 +#define RISC_SYNC_ODD 0x80000000 +#define RISC_SYNC_EVEN 0x80000200 +#define RISC_RESYNC 0x80008000 +#define RISC_RESYNC_ODD 0x80008000 +#define RISC_RESYNC_EVEN 0x80008200 +#define RISC_WRITE 0x10000000 +#define RISC_WRITEC 0x50000000 +#define RISC_READ 0x90000000 +#define RISC_READC 0xA0000000 +#define RISC_JUMP 0x70000000 +#define RISC_SKIP 0x20000000 +#define RISC_WRITERM 0xB0000000 +#define RISC_WRITECM 0xC0000000 +#define RISC_WRITECR 0xD0000000 +#define RISC_IMM 0x00000001 + +#define RISC_SOL 0x08000000 +#define RISC_EOL 0x04000000 + +#define RISC_IRQ2 0x02000000 +#define RISC_IRQ1 0x01000000 + +#define RISC_CNT_NONE 0x00000000 +#define RISC_CNT_INC 0x00010000 +#define RISC_CNT_RSVR 0x00020000 +#define RISC_CNT_RESET 0x00030000 +#define RISC_JMP_SRP 0x01 + + +/* ---------------------------------------------------------------------- */ +/* various constants */ + +// DMA +/* Interrupt mask/status */ +#define PCI_INT_VIDINT (1 << 0) +#define PCI_INT_AUDINT (1 << 1) +#define PCI_INT_TSINT (1 << 2) +#define PCI_INT_VIPINT (1 << 3) +#define PCI_INT_HSTINT (1 << 4) +#define PCI_INT_TM1INT (1 << 5) +#define PCI_INT_SRCDMAINT (1 << 6) +#define PCI_INT_DSTDMAINT (1 << 7) +#define PCI_INT_RISC_RD_BERRINT (1 << 10) +#define PCI_INT_RISC_WR_BERRINT (1 << 11) +#define PCI_INT_BRDG_BERRINT (1 << 12) +#define PCI_INT_SRC_DMA_BERRINT (1 << 13) +#define PCI_INT_DST_DMA_BERRINT (1 << 14) +#define PCI_INT_IPB_DMA_BERRINT (1 << 15) +#define PCI_INT_I2CDONE (1 << 16) +#define PCI_INT_I2CRACK (1 << 17) +#define PCI_INT_IR_SMPINT (1 << 18) +#define PCI_INT_GPIO_INT0 (1 << 19) +#define PCI_INT_GPIO_INT1 (1 << 20) + +#define SEL_BTSC 0x01 +#define SEL_EIAJ 0x02 +#define SEL_A2 0x04 +#define SEL_SAP 0x08 +#define SEL_NICAM 0x10 +#define SEL_FMRADIO 0x20 + +// AUD_CTL +#define AUD_INT_DN_RISCI1 (1 << 0) +#define AUD_INT_UP_RISCI1 (1 << 1) +#define AUD_INT_RDS_DN_RISCI1 (1 << 2) +#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ +#define AUD_INT_UP_RISCI2 (1 << 5) +#define AUD_INT_RDS_DN_RISCI2 (1 << 6) +#define AUD_INT_DN_SYNC (1 << 12) +#define AUD_INT_UP_SYNC (1 << 13) +#define AUD_INT_RDS_DN_SYNC (1 << 14) +#define AUD_INT_OPC_ERR (1 << 16) +#define AUD_INT_BER_IRQ (1 << 20) +#define AUD_INT_MCHG_IRQ (1 << 21) + +#define EN_BTSC_FORCE_MONO 0 +#define EN_BTSC_FORCE_STEREO 1 +#define EN_BTSC_FORCE_SAP 2 +#define EN_BTSC_AUTO_STEREO 3 +#define EN_BTSC_AUTO_SAP 4 + +#define EN_A2_FORCE_MONO1 8 +#define EN_A2_FORCE_MONO2 9 +#define EN_A2_FORCE_STEREO 10 +#define EN_A2_AUTO_MONO2 11 +#define EN_A2_AUTO_STEREO 12 + +#define EN_EIAJ_FORCE_MONO1 16 +#define EN_EIAJ_FORCE_MONO2 17 +#define EN_EIAJ_FORCE_STEREO 18 +#define EN_EIAJ_AUTO_MONO2 19 +#define EN_EIAJ_AUTO_STEREO 20 + +#define EN_NICAM_FORCE_MONO1 32 +#define EN_NICAM_FORCE_MONO2 33 +#define EN_NICAM_FORCE_STEREO 34 +#define EN_NICAM_AUTO_MONO2 35 +#define EN_NICAM_AUTO_STEREO 36 + +#define EN_FMRADIO_FORCE_MONO 24 +#define EN_FMRADIO_FORCE_STEREO 25 +#define EN_FMRADIO_AUTO_STEREO 26 + +#define EN_NICAM_AUTO_FALLBACK 0x00000040 +#define EN_FMRADIO_EN_RDS 0x00000200 +#define EN_NICAM_TRY_AGAIN_BIT 0x00000400 +#define EN_DAC_ENABLE 0x00001000 +#define EN_I2SOUT_ENABLE 0x00002000 +#define EN_I2SIN_STR2DAC 0x00004000 +#define EN_I2SIN_ENABLE 0x00008000 + +#define EN_DMTRX_SUMDIFF (0 << 7) +#define EN_DMTRX_SUMR (1 << 7) +#define EN_DMTRX_LR (2 << 7) +#define EN_DMTRX_MONO (3 << 7) +#define EN_DMTRX_BYPASS (1 << 11) + +// Video +#define VID_CAPTURE_CONTROL 0x310180 + +#define CX23880_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define CX23880_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define CX23880_CAP_CTL_CAPTURE_ODD (1<<1) +#define CX23880_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define VideoInputMux0 0x0 +#define VideoInputMux1 0x1 +#define VideoInputMux2 0x2 +#define VideoInputMux3 0x3 +#define VideoInputTuner 0x0 +#define VideoInputComposite 0x1 +#define VideoInputSVideo 0x2 +#define VideoInputOther 0x3 + +#define Xtal0 0x1 +#define Xtal1 0x2 +#define XtalAuto 0x3 + +#define VideoFormatAuto 0x0 +#define VideoFormatNTSC 0x1 +#define VideoFormatNTSCJapan 0x2 +#define VideoFormatNTSC443 0x3 +#define VideoFormatPAL 0x4 +#define VideoFormatPALB 0x4 +#define VideoFormatPALD 0x4 +#define VideoFormatPALG 0x4 +#define VideoFormatPALH 0x4 +#define VideoFormatPALI 0x4 +#define VideoFormatPALBDGHI 0x4 +#define VideoFormatPALM 0x5 +#define VideoFormatPALN 0x6 +#define VideoFormatPALNC 0x7 +#define VideoFormatPAL60 0x8 +#define VideoFormatSECAM 0x9 + +#define VideoFormatAuto27MHz 0x10 +#define VideoFormatNTSC27MHz 0x11 +#define VideoFormatNTSCJapan27MHz 0x12 +#define VideoFormatNTSC44327MHz 0x13 +#define VideoFormatPAL27MHz 0x14 +#define VideoFormatPALB27MHz 0x14 +#define VideoFormatPALD27MHz 0x14 +#define VideoFormatPALG27MHz 0x14 +#define VideoFormatPALH27MHz 0x14 +#define VideoFormatPALI27MHz 0x14 +#define VideoFormatPALBDGHI27MHz 0x14 +#define VideoFormatPALM27MHz 0x15 +#define VideoFormatPALN27MHz 0x16 +#define VideoFormatPALNC27MHz 0x17 +#define VideoFormatPAL6027MHz 0x18 +#define VideoFormatSECAM27MHz 0x19 + +#define NominalUSECAM 0x87 +#define NominalVSECAM 0x85 +#define NominalUNTSC 0xFE +#define NominalVNTSC 0xB4 + +#define NominalContrast 0xD8 + +#define HFilterAutoFormat 0x0 +#define HFilterCIF 0x1 +#define HFilterQCIF 0x2 +#define HFilterICON 0x3 + +#define VFilter2TapInterpolate 0 +#define VFilter3TapInterpolate 1 +#define VFilter4TapInterpolate 2 +#define VFilter5TapInterpolate 3 +#define VFilter2TapNoInterpolate 4 +#define VFilter3TapNoInterpolate 5 +#define VFilter4TapNoInterpolate 6 +#define VFilter5TapNoInterpolate 7 + +#define ColorFormatRGB32 0x0000 +#define ColorFormatRGB24 0x0011 +#define ColorFormatRGB16 0x0022 +#define ColorFormatRGB15 0x0033 +#define ColorFormatYUY2 0x0044 +#define ColorFormatBTYUV 0x0055 +#define ColorFormatY8 0x0066 +#define ColorFormatRGB8 0x0077 +#define ColorFormatPL422 0x0088 +#define ColorFormatPL411 0x0099 +#define ColorFormatYUV12 0x00AA +#define ColorFormatYUV9 0x00BB +#define ColorFormatRAW 0x00EE +#define ColorFormatBSWAP 0x0300 +#define ColorFormatWSWAP 0x0c00 +#define ColorFormatEvenMask 0x050f +#define ColorFormatOddMask 0x0af0 +#define ColorFormatGamma 0x1000 + +#define Interlaced 0x1 +#define NonInterlaced 0x0 + +#define FieldEven 0x1 +#define FieldOdd 0x0 + +#define TGReadWriteMode 0x0 +#define TGEnableMode 0x1 + +#define DV_CbAlign 0x0 +#define DV_Y0Align 0x1 +#define DV_CrAlign 0x2 +#define DV_Y1Align 0x3 + +#define DVF_Analog 0x0 +#define DVF_CCIR656 0x1 +#define DVF_ByteStream 0x2 +#define DVF_ExtVSYNC 0x4 +#define DVF_ExtField 0x5 + +#define CHANNEL_VID_Y 0x1 +#define CHANNEL_VID_U 0x2 +#define CHANNEL_VID_V 0x3 +#define CHANNEL_VID_VBI 0x4 +#define CHANNEL_AUD_DN 0x5 +#define CHANNEL_AUD_UP 0x6 +#define CHANNEL_AUD_RDS_DN 0x7 +#define CHANNEL_MPEG_DN 0x8 +#define CHANNEL_VIP_DN 0x9 +#define CHANNEL_VIP_UP 0xA +#define CHANNEL_HOST_DN 0xB +#define CHANNEL_HOST_UP 0xC +#define CHANNEL_FIRST 0x1 +#define CHANNEL_LAST 0xC + +#define GP_COUNT_CONTROL_NONE 0x0 +#define GP_COUNT_CONTROL_INC 0x1 +#define GP_COUNT_CONTROL_RESERVED 0x2 +#define GP_COUNT_CONTROL_RESET 0x3 + +#define PLL_PRESCALE_BY_2 2 +#define PLL_PRESCALE_BY_3 3 +#define PLL_PRESCALE_BY_4 4 +#define PLL_PRESCALE_BY_5 5 + +#define HLNotchFilter4xFsc 0 +#define HLNotchFilterSquare 1 +#define HLNotchFilter135NTSC 2 +#define HLNotchFilter135PAL 3 + +#define NTSC_8x_SUB_CARRIER 28.63636E6 +#define PAL_8x_SUB_CARRIER 35.46895E6 + +// Default analog settings +#define DEFAULT_HUE_NTSC 0x00 +#define DEFAULT_BRIGHTNESS_NTSC 0x00 +#define DEFAULT_CONTRAST_NTSC 0x39 +#define DEFAULT_SAT_U_NTSC 0x7F +#define DEFAULT_SAT_V_NTSC 0x5A + +typedef enum +{ + SOURCE_TUNER = 0, + SOURCE_COMPOSITE, + SOURCE_SVIDEO, + SOURCE_OTHER1, + SOURCE_OTHER2, + SOURCE_COMPVIASVIDEO, + SOURCE_CCIR656 +} VIDEOSOURCETYPE; + +#endif /* _CX88_REG_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-tvaudio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-tvaudio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-tvaudio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-tvaudio.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1059 @@ +/* + + cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver + + (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version] + (c) 2002 Yurij Sysoev + (c) 2003 Gerd Knorr + + ----------------------------------------------------------------------- + + Lot of voodoo here. Even the data sheet doesn't help to + understand what is going on here, the documentation for the audio + part of the cx2388x chip is *very* bad. + + Some of this comes from party done linux driver sources I got from + [undocumented]. + + Some comes from the dscaler sources, one of the dscaler driver guy works + for Conexant ... + + ----------------------------------------------------------------------- + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx88.h" + +static unsigned int audio_debug; +module_param(audio_debug, int, 0644); +MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]"); + +static unsigned int always_analog; +module_param(always_analog,int,0644); +MODULE_PARM_DESC(always_analog,"force analog audio out"); + +static unsigned int radio_deemphasis; +module_param(radio_deemphasis,int,0644); +MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, " + "0=None, 1=50us (elsewhere), 2=75us (USA)"); + +#define dprintk(fmt, arg...) if (audio_debug) \ + printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) + +/* ----------------------------------------------------------- */ + +static const char * const aud_ctl_names[64] = { + [EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO", + [EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO", + [EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP", + [EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO", + [EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP", + [EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1", + [EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2", + [EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO", + [EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2", + [EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO", + [EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1", + [EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2", + [EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO", + [EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2", + [EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO", + [EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1", + [EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2", + [EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO", + [EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2", + [EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO", + [EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO", + [EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO", + [EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO", +}; + +struct rlist { + u32 reg; + u32 val; +}; + +static void set_audio_registers(struct cx88_core *core, const struct rlist *l) +{ + int i; + + for (i = 0; l[i].reg; i++) { + switch (l[i].reg) { + case AUD_PDF_DDS_CNST_BYTE2: + case AUD_PDF_DDS_CNST_BYTE1: + case AUD_PDF_DDS_CNST_BYTE0: + case AUD_QAM_MODE: + case AUD_PHACC_FREQ_8MSB: + case AUD_PHACC_FREQ_8LSB: + cx_writeb(l[i].reg, l[i].val); + break; + default: + cx_write(l[i].reg, l[i].val); + break; + } + } +} + +static void set_audio_start(struct cx88_core *core, u32 mode) +{ + /* mute */ + cx_write(AUD_VOL_CTL, (1 << 6)); + + /* start programming */ + cx_write(AUD_INIT, mode); + cx_write(AUD_INIT_LD, 0x0001); + cx_write(AUD_SOFT_RESET, 0x0001); +} + +static void set_audio_finish(struct cx88_core *core, u32 ctl) +{ + u32 volume; + + /* restart dma; This avoids buzz in NICAM and is good in others */ + cx88_stop_audio_dma(core); + cx_write(AUD_RATE_THRES_DMD, 0x000000C0); + cx88_start_audio_dma(core); + + if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { + cx_write(AUD_I2SINPUTCNTL, 4); + cx_write(AUD_BAUDRATE, 1); + /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ + cx_set(AUD_CTL, EN_I2SOUT_ENABLE); + cx_write(AUD_I2SOUTPUTCNTL, 1); + cx_write(AUD_I2SCNTL, 0); + /* cx_write(AUD_APB_IN_RATE_ADJ, 0); */ + } + if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) { + ctl |= EN_DAC_ENABLE; + cx_write(AUD_CTL, ctl); + } + + /* finish programming */ + cx_write(AUD_SOFT_RESET, 0x0000); + + /* unmute */ + volume = cx_sread(SHADOW_AUD_VOL_CTL); + cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume); + + core->last_change = jiffies; +} + +/* ----------------------------------------------------------- */ + +static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap, + u32 mode) +{ + static const struct rlist btsc[] = { + {AUD_AFE_12DB_EN, 0x00000001}, + {AUD_OUT1_SEL, 0x00000013}, + {AUD_OUT1_SHIFT, 0x00000000}, + {AUD_POLY0_DDS_CONSTANT, 0x0012010c}, + {AUD_DMD_RA_DDS, 0x00c3e7aa}, + {AUD_DBX_IN_GAIN, 0x00004734}, + {AUD_DBX_WBE_GAIN, 0x00004640}, + {AUD_DBX_SE_GAIN, 0x00008d31}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_IIR1_4_SEL, 0x00000021}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_DN0_FREQ, 0x0000283b}, + {AUD_DN2_SRC_SEL, 0x00000008}, + {AUD_DN2_FREQ, 0x00003000}, + {AUD_DN2_AFC, 0x00000002}, + {AUD_DN2_SHFT, 0x00000000}, + {AUD_IIR2_2_SEL, 0x00000020}, + {AUD_IIR2_2_SHIFT, 0x00000000}, + {AUD_IIR2_3_SEL, 0x0000001f}, + {AUD_IIR2_3_SHIFT, 0x00000000}, + {AUD_CRDC1_SRC_SEL, 0x000003ce}, + {AUD_CRDC1_SHIFT, 0x00000000}, + {AUD_CORDIC_SHIFT_1, 0x00000007}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_RDSI_SEL, 0x00000008}, + {AUD_RDSQ_SEL, 0x00000008}, + {AUD_RDSI_SHIFT, 0x00000000}, + {AUD_RDSQ_SHIFT, 0x00000000}, + {AUD_POLYPH80SCALEFAC, 0x00000003}, + { /* end of list */ }, + }; + static const struct rlist btsc_sap[] = { + {AUD_AFE_12DB_EN, 0x00000001}, + {AUD_DBX_IN_GAIN, 0x00007200}, + {AUD_DBX_WBE_GAIN, 0x00006200}, + {AUD_DBX_SE_GAIN, 0x00006200}, + {AUD_IIR1_1_SEL, 0x00000000}, + {AUD_IIR1_3_SEL, 0x00000001}, + {AUD_DN1_SRC_SEL, 0x00000007}, + {AUD_IIR1_4_SHIFT, 0x00000006}, + {AUD_IIR2_1_SHIFT, 0x00000000}, + {AUD_IIR2_2_SHIFT, 0x00000000}, + {AUD_IIR3_0_SHIFT, 0x00000000}, + {AUD_IIR3_1_SHIFT, 0x00000000}, + {AUD_IIR3_0_SEL, 0x0000000d}, + {AUD_IIR3_1_SEL, 0x0000000e}, + {AUD_DEEMPH1_SRC_SEL, 0x00000014}, + {AUD_DEEMPH1_SHIFT, 0x00000000}, + {AUD_DEEMPH1_G0, 0x00004000}, + {AUD_DEEMPH1_A0, 0x00000000}, + {AUD_DEEMPH1_B0, 0x00000000}, + {AUD_DEEMPH1_A1, 0x00000000}, + {AUD_DEEMPH1_B1, 0x00000000}, + {AUD_OUT0_SEL, 0x0000003f}, + {AUD_OUT1_SEL, 0x0000003f}, + {AUD_DN1_AFC, 0x00000002}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_IIR1_0_SEL, 0x0000001d}, + {AUD_IIR1_2_SEL, 0x0000001e}, + {AUD_IIR2_1_SEL, 0x00000002}, + {AUD_IIR2_2_SEL, 0x00000004}, + {AUD_IIR3_2_SEL, 0x0000000f}, + {AUD_DCOC2_SHIFT, 0x00000001}, + {AUD_IIR3_2_SHIFT, 0x00000001}, + {AUD_DEEMPH0_SRC_SEL, 0x00000014}, + {AUD_CORDIC_SHIFT_1, 0x00000006}, + {AUD_POLY0_DDS_CONSTANT, 0x000e4db2}, + {AUD_DMD_RA_DDS, 0x00f696e6}, + {AUD_IIR2_3_SEL, 0x00000025}, + {AUD_IIR1_4_SEL, 0x00000021}, + {AUD_DN1_FREQ, 0x0000c965}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_RDSI_SEL, 0x00000009}, + {AUD_RDSQ_SEL, 0x00000009}, + {AUD_RDSI_SHIFT, 0x00000000}, + {AUD_RDSQ_SHIFT, 0x00000000}, + {AUD_POLYPH80SCALEFAC, 0x00000003}, + { /* end of list */ }, + }; + + mode |= EN_FMRADIO_EN_RDS; + + if (sap) { + dprintk("%s SAP (status: unknown)\n", __func__); + set_audio_start(core, SEL_SAP); + set_audio_registers(core, btsc_sap); + set_audio_finish(core, mode); + } else { + dprintk("%s (status: known-good)\n", __func__); + set_audio_start(core, SEL_BTSC); + set_audio_registers(core, btsc); + set_audio_finish(core, mode); + } +} + +static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode) +{ + static const struct rlist nicam_l[] = { + {AUD_AFE_12DB_EN, 0x00000001}, + {AUD_RATE_ADJ1, 0x00000060}, + {AUD_RATE_ADJ2, 0x000000F9}, + {AUD_RATE_ADJ3, 0x000001CC}, + {AUD_RATE_ADJ4, 0x000002B3}, + {AUD_RATE_ADJ5, 0x00000726}, + {AUD_DEEMPHDENOM1_R, 0x0000F3D0}, + {AUD_DEEMPHDENOM2_R, 0x00000000}, + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F}, + {AUD_POLYPH80SCALEFAC, 0x00000003}, + {AUD_DMD_RA_DDS, 0x00C00000}, + {AUD_PLL_INT, 0x0000001E}, + {AUD_PLL_DDS, 0x00000000}, + {AUD_PLL_FRAC, 0x0000E542}, + {AUD_START_TIMER, 0x00000000}, + {AUD_DEEMPHNUMER1_R, 0x000353DE}, + {AUD_DEEMPHNUMER2_R, 0x000001B1}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_QAM_MODE, 0x05}, + {AUD_PHACC_FREQ_8MSB, 0x34}, + {AUD_PHACC_FREQ_8LSB, 0x4C}, + {AUD_DEEMPHGAIN_R, 0x00006680}, + {AUD_RATE_THRES_DMD, 0x000000C0}, + { /* end of list */ }, + }; + + static const struct rlist nicam_bgdki_common[] = { + {AUD_AFE_12DB_EN, 0x00000001}, + {AUD_RATE_ADJ1, 0x00000010}, + {AUD_RATE_ADJ2, 0x00000040}, + {AUD_RATE_ADJ3, 0x00000100}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00001000}, + {AUD_ERRLOGPERIOD_R, 0x00000fff}, + {AUD_ERRINTRPTTHSHLD1_R, 0x000003ff}, + {AUD_ERRINTRPTTHSHLD2_R, 0x000000ff}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000003f}, + {AUD_POLYPH80SCALEFAC, 0x00000003}, + {AUD_DEEMPHGAIN_R, 0x000023c2}, + {AUD_DEEMPHNUMER1_R, 0x0002a7bc}, + {AUD_DEEMPHNUMER2_R, 0x0003023e}, + {AUD_DEEMPHDENOM1_R, 0x0000f3d0}, + {AUD_DEEMPHDENOM2_R, 0x00000000}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_QAM_MODE, 0x05}, + { /* end of list */ }, + }; + + static const struct rlist nicam_i[] = { + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_PHACC_FREQ_8MSB, 0x3a}, + {AUD_PHACC_FREQ_8LSB, 0x93}, + { /* end of list */ }, + }; + + static const struct rlist nicam_default[] = { + {AUD_PDF_DDS_CNST_BYTE0, 0x16}, + {AUD_PHACC_FREQ_8MSB, 0x34}, + {AUD_PHACC_FREQ_8LSB, 0x4c}, + { /* end of list */ }, + }; + + set_audio_start(core,SEL_NICAM); + switch (core->tvaudio) { + case WW_L: + dprintk("%s SECAM-L NICAM (status: devel)\n", __func__); + set_audio_registers(core, nicam_l); + break; + case WW_I: + dprintk("%s PAL-I NICAM (status: known-good)\n", __func__); + set_audio_registers(core, nicam_bgdki_common); + set_audio_registers(core, nicam_i); + break; + case WW_NONE: + case WW_BTSC: + case WW_BG: + case WW_DK: + case WW_EIAJ: + case WW_I2SPT: + case WW_FM: + case WW_I2SADC: + case WW_M: + dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__); + set_audio_registers(core, nicam_bgdki_common); + set_audio_registers(core, nicam_default); + break; + }; + + mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS; + set_audio_finish(core, mode); +} + +static void set_audio_standard_A2(struct cx88_core *core, u32 mode) +{ + static const struct rlist a2_bgdk_common[] = { + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_QAM_MODE, 0x05}, + {AUD_PHACC_FREQ_8MSB, 0x34}, + {AUD_PHACC_FREQ_8LSB, 0x4c}, + {AUD_RATE_ADJ1, 0x00000100}, + {AUD_RATE_ADJ2, 0x00000200}, + {AUD_RATE_ADJ3, 0x00000300}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00000500}, + {AUD_THR_FR, 0x00000000}, + {AAGC_HYST, 0x0000001a}, + {AUD_PILOT_BQD_1_K0, 0x0000755b}, + {AUD_PILOT_BQD_1_K1, 0x00551340}, + {AUD_PILOT_BQD_1_K2, 0x006d30be}, + {AUD_PILOT_BQD_1_K3, 0xffd394af}, + {AUD_PILOT_BQD_1_K4, 0x00400000}, + {AUD_PILOT_BQD_2_K0, 0x00040000}, + {AUD_PILOT_BQD_2_K1, 0x002a4841}, + {AUD_PILOT_BQD_2_K2, 0x00400000}, + {AUD_PILOT_BQD_2_K3, 0x00000000}, + {AUD_PILOT_BQD_2_K4, 0x00000000}, + {AUD_MODE_CHG_TIMER, 0x00000040}, + {AUD_AFE_12DB_EN, 0x00000001}, + {AUD_CORDIC_SHIFT_0, 0x00000007}, + {AUD_CORDIC_SHIFT_1, 0x00000007}, + {AUD_DEEMPH0_G0, 0x00000380}, + {AUD_DEEMPH1_G0, 0x00000380}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_DCOC0_SHIFT, 0x00000000}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_IIR3_0_SEL, 0x00000021}, + {AUD_DN2_AFC, 0x00000002}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_IIR3_1_SEL, 0x00000023}, + {AUD_RDSI_SEL, 0x00000017}, + {AUD_RDSI_SHIFT, 0x00000000}, + {AUD_RDSQ_SEL, 0x00000017}, + {AUD_RDSQ_SHIFT, 0x00000000}, + {AUD_PLL_INT, 0x0000001e}, + {AUD_PLL_DDS, 0x00000000}, + {AUD_PLL_FRAC, 0x0000e542}, + {AUD_POLYPH80SCALEFAC, 0x00000001}, + {AUD_START_TIMER, 0x00000000}, + { /* end of list */ }, + }; + + static const struct rlist a2_bg[] = { + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, + { /* end of list */ }, + }; + + static const struct rlist a2_dk[] = { + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, + {AUD_DN0_FREQ, 0x00003a1c}, + {AUD_DN2_FREQ, 0x0000d2e0}, + { /* end of list */ }, + }; + + static const struct rlist a1_i[] = { + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_QAM_MODE, 0x05}, + {AUD_PHACC_FREQ_8MSB, 0x3a}, + {AUD_PHACC_FREQ_8LSB, 0x93}, + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_PLL_INT, 0x0000001e}, + {AUD_PLL_DDS, 0x00000004}, + {AUD_PLL_FRAC, 0x0000e542}, + {AUD_RATE_ADJ1, 0x00000100}, + {AUD_RATE_ADJ2, 0x00000200}, + {AUD_RATE_ADJ3, 0x00000300}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00000500}, + {AUD_THR_FR, 0x00000000}, + {AUD_PILOT_BQD_1_K0, 0x0000755b}, + {AUD_PILOT_BQD_1_K1, 0x00551340}, + {AUD_PILOT_BQD_1_K2, 0x006d30be}, + {AUD_PILOT_BQD_1_K3, 0xffd394af}, + {AUD_PILOT_BQD_1_K4, 0x00400000}, + {AUD_PILOT_BQD_2_K0, 0x00040000}, + {AUD_PILOT_BQD_2_K1, 0x002a4841}, + {AUD_PILOT_BQD_2_K2, 0x00400000}, + {AUD_PILOT_BQD_2_K3, 0x00000000}, + {AUD_PILOT_BQD_2_K4, 0x00000000}, + {AUD_MODE_CHG_TIMER, 0x00000060}, + {AUD_AFE_12DB_EN, 0x00000001}, + {AAGC_HYST, 0x0000000a}, + {AUD_CORDIC_SHIFT_0, 0x00000007}, + {AUD_CORDIC_SHIFT_1, 0x00000007}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_DCOC0_SHIFT, 0x00000000}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_IIR3_0_SEL, 0x00000021}, + {AUD_DN2_AFC, 0x00000002}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_IIR3_1_SEL, 0x00000023}, + {AUD_DN0_FREQ, 0x000035a3}, + {AUD_DN2_FREQ, 0x000029c7}, + {AUD_CRDC0_SRC_SEL, 0x00000511}, + {AUD_IIR1_0_SEL, 0x00000001}, + {AUD_IIR1_1_SEL, 0x00000000}, + {AUD_IIR3_2_SEL, 0x00000003}, + {AUD_IIR3_2_SHIFT, 0x00000000}, + {AUD_IIR3_0_SEL, 0x00000002}, + {AUD_IIR2_0_SEL, 0x00000021}, + {AUD_IIR2_0_SHIFT, 0x00000002}, + {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, + {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, + {AUD_POLYPH80SCALEFAC, 0x00000001}, + {AUD_START_TIMER, 0x00000000}, + { /* end of list */ }, + }; + + static const struct rlist am_l[] = { + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F}, + {AUD_PDF_DDS_CNST_BYTE2, 0x48}, + {AUD_PDF_DDS_CNST_BYTE1, 0x3D}, + {AUD_QAM_MODE, 0x00}, + {AUD_PDF_DDS_CNST_BYTE0, 0xf5}, + {AUD_PHACC_FREQ_8MSB, 0x3a}, + {AUD_PHACC_FREQ_8LSB, 0x4a}, + {AUD_DEEMPHGAIN_R, 0x00006680}, + {AUD_DEEMPHNUMER1_R, 0x000353DE}, + {AUD_DEEMPHNUMER2_R, 0x000001B1}, + {AUD_DEEMPHDENOM1_R, 0x0000F3D0}, + {AUD_DEEMPHDENOM2_R, 0x00000000}, + {AUD_FM_MODE_ENABLE, 0x00000007}, + {AUD_POLYPH80SCALEFAC, 0x00000003}, + {AUD_AFE_12DB_EN, 0x00000001}, + {AAGC_GAIN, 0x00000000}, + {AAGC_HYST, 0x00000018}, + {AAGC_DEF, 0x00000020}, + {AUD_DN0_FREQ, 0x00000000}, + {AUD_POLY0_DDS_CONSTANT, 0x000E4DB2}, + {AUD_DCOC_0_SRC, 0x00000021}, + {AUD_IIR1_0_SEL, 0x00000000}, + {AUD_IIR1_0_SHIFT, 0x00000007}, + {AUD_IIR1_1_SEL, 0x00000002}, + {AUD_IIR1_1_SHIFT, 0x00000000}, + {AUD_DCOC_1_SRC, 0x00000003}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_DCOC_PASS_IN, 0x00000000}, + {AUD_IIR1_2_SEL, 0x00000023}, + {AUD_IIR1_2_SHIFT, 0x00000000}, + {AUD_IIR1_3_SEL, 0x00000004}, + {AUD_IIR1_3_SHIFT, 0x00000007}, + {AUD_IIR1_4_SEL, 0x00000005}, + {AUD_IIR1_4_SHIFT, 0x00000007}, + {AUD_IIR3_0_SEL, 0x00000007}, + {AUD_IIR3_0_SHIFT, 0x00000000}, + {AUD_DEEMPH0_SRC_SEL, 0x00000011}, + {AUD_DEEMPH0_SHIFT, 0x00000000}, + {AUD_DEEMPH0_G0, 0x00007000}, + {AUD_DEEMPH0_A0, 0x00000000}, + {AUD_DEEMPH0_B0, 0x00000000}, + {AUD_DEEMPH0_A1, 0x00000000}, + {AUD_DEEMPH0_B1, 0x00000000}, + {AUD_DEEMPH1_SRC_SEL, 0x00000011}, + {AUD_DEEMPH1_SHIFT, 0x00000000}, + {AUD_DEEMPH1_G0, 0x00007000}, + {AUD_DEEMPH1_A0, 0x00000000}, + {AUD_DEEMPH1_B0, 0x00000000}, + {AUD_DEEMPH1_A1, 0x00000000}, + {AUD_DEEMPH1_B1, 0x00000000}, + {AUD_OUT0_SEL, 0x0000003F}, + {AUD_OUT1_SEL, 0x0000003F}, + {AUD_DMD_RA_DDS, 0x00F5C285}, + {AUD_PLL_INT, 0x0000001E}, + {AUD_PLL_DDS, 0x00000000}, + {AUD_PLL_FRAC, 0x0000E542}, + {AUD_RATE_ADJ1, 0x00000100}, + {AUD_RATE_ADJ2, 0x00000200}, + {AUD_RATE_ADJ3, 0x00000300}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00000500}, + {AUD_RATE_THRES_DMD, 0x000000C0}, + { /* end of list */ }, + }; + + static const struct rlist a2_deemph50[] = { + {AUD_DEEMPH0_G0, 0x00000380}, + {AUD_DEEMPH1_G0, 0x00000380}, + {AUD_DEEMPHGAIN_R, 0x000011e1}, + {AUD_DEEMPHNUMER1_R, 0x0002a7bc}, + {AUD_DEEMPHNUMER2_R, 0x0003023c}, + { /* end of list */ }, + }; + + set_audio_start(core, SEL_A2); + switch (core->tvaudio) { + case WW_BG: + dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__); + set_audio_registers(core, a2_bgdk_common); + set_audio_registers(core, a2_bg); + set_audio_registers(core, a2_deemph50); + break; + case WW_DK: + dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__); + set_audio_registers(core, a2_bgdk_common); + set_audio_registers(core, a2_dk); + set_audio_registers(core, a2_deemph50); + break; + case WW_I: + dprintk("%s PAL-I A1 (status: known-good)\n", __func__); + set_audio_registers(core, a1_i); + set_audio_registers(core, a2_deemph50); + break; + case WW_L: + dprintk("%s AM-L (status: devel)\n", __func__); + set_audio_registers(core, am_l); + break; + case WW_NONE: + case WW_BTSC: + case WW_EIAJ: + case WW_I2SPT: + case WW_FM: + case WW_I2SADC: + case WW_M: + dprintk("%s Warning: wrong value\n", __func__); + return; + break; + }; + + mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; + set_audio_finish(core, mode); +} + +static void set_audio_standard_EIAJ(struct cx88_core *core) +{ + static const struct rlist eiaj[] = { + /* TODO: eiaj register settings are not there yet ... */ + + { /* end of list */ }, + }; + dprintk("%s (status: unknown)\n", __func__); + + set_audio_start(core, SEL_EIAJ); + set_audio_registers(core, eiaj); + set_audio_finish(core, EN_EIAJ_AUTO_STEREO); +} + +static void set_audio_standard_FM(struct cx88_core *core, + enum cx88_deemph_type deemph) +{ + static const struct rlist fm_deemph_50[] = { + {AUD_DEEMPH0_G0, 0x0C45}, + {AUD_DEEMPH0_A0, 0x6262}, + {AUD_DEEMPH0_B0, 0x1C29}, + {AUD_DEEMPH0_A1, 0x3FC66}, + {AUD_DEEMPH0_B1, 0x399A}, + + {AUD_DEEMPH1_G0, 0x0D80}, + {AUD_DEEMPH1_A0, 0x6262}, + {AUD_DEEMPH1_B0, 0x1C29}, + {AUD_DEEMPH1_A1, 0x3FC66}, + {AUD_DEEMPH1_B1, 0x399A}, + + {AUD_POLYPH80SCALEFAC, 0x0003}, + { /* end of list */ }, + }; + static const struct rlist fm_deemph_75[] = { + {AUD_DEEMPH0_G0, 0x091B}, + {AUD_DEEMPH0_A0, 0x6B68}, + {AUD_DEEMPH0_B0, 0x11EC}, + {AUD_DEEMPH0_A1, 0x3FC66}, + {AUD_DEEMPH0_B1, 0x399A}, + + {AUD_DEEMPH1_G0, 0x0AA0}, + {AUD_DEEMPH1_A0, 0x6B68}, + {AUD_DEEMPH1_B0, 0x11EC}, + {AUD_DEEMPH1_A1, 0x3FC66}, + {AUD_DEEMPH1_B1, 0x399A}, + + {AUD_POLYPH80SCALEFAC, 0x0003}, + { /* end of list */ }, + }; + + /* It is enough to leave default values? */ + /* No, it's not! The deemphasis registers are reset to the 75us + * values by default. Analyzing the spectrum of the decoded audio + * reveals that "no deemphasis" is the same as 75 us, while the 50 us + * setting results in less deemphasis. */ + static const struct rlist fm_no_deemph[] = { + + {AUD_POLYPH80SCALEFAC, 0x0003}, + { /* end of list */ }, + }; + + dprintk("%s (status: unknown)\n", __func__); + set_audio_start(core, SEL_FMRADIO); + + switch (deemph) { + default: + case FM_NO_DEEMPH: + set_audio_registers(core, fm_no_deemph); + break; + + case FM_DEEMPH_50: + set_audio_registers(core, fm_deemph_50); + break; + + case FM_DEEMPH_75: + set_audio_registers(core, fm_deemph_75); + break; + } + + set_audio_finish(core, EN_FMRADIO_AUTO_STEREO); +} + +/* ----------------------------------------------------------- */ + +static int cx88_detect_nicam(struct cx88_core *core) +{ + int i, j = 0; + + dprintk("start nicam autodetect.\n"); + + for (i = 0; i < 6; i++) { + /* if bit1=1 then nicam is detected */ + j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1); + + if (j == 1) { + dprintk("nicam is detected.\n"); + return 1; + } + + /* wait a little bit for next reading status */ + msleep(10); + } + + dprintk("nicam is not detected.\n"); + return 0; +} + +void cx88_set_tvaudio(struct cx88_core *core) +{ + switch (core->tvaudio) { + case WW_BTSC: + set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); + break; + case WW_BG: + case WW_DK: + case WW_M: + case WW_I: + case WW_L: + /* prepare all dsp registers */ + set_audio_standard_A2(core, EN_A2_FORCE_MONO1); + + /* set nicam mode - otherwise + AUD_NICAM_STATUS2 contains wrong values */ + set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO); + if (0 == cx88_detect_nicam(core)) { + /* fall back to fm / am mono */ + set_audio_standard_A2(core, EN_A2_FORCE_MONO1); + core->audiomode_current = V4L2_TUNER_MODE_MONO; + core->use_nicam = 0; + } else { + core->use_nicam = 1; + } + break; + case WW_EIAJ: + set_audio_standard_EIAJ(core); + break; + case WW_FM: + set_audio_standard_FM(core, radio_deemphasis); + break; + case WW_I2SADC: + set_audio_start(core, 0x01); + /* + * Slave/Philips/Autobaud + * NB on Nova-S bit1 NPhilipsSony appears to be inverted: + * 0= Sony, 1=Philips + */ + cx_write(AUD_I2SINPUTCNTL, core->board.i2sinputcntl); + /* Switch to "I2S ADC mode" */ + cx_write(AUD_I2SCNTL, 0x1); + set_audio_finish(core, EN_I2SIN_ENABLE); + break; + case WW_NONE: + case WW_I2SPT: + printk("%s/0: unknown tv audio mode [%d]\n", + core->name, core->tvaudio); + break; + } + return; +} + +void cx88_newstation(struct cx88_core *core) +{ + core->audiomode_manual = UNSET; + core->last_change = jiffies; +} + +void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) +{ + static const char * const m[] = { "stereo", "dual mono", "mono", "sap" }; + static const char * const p[] = { "no pilot", "pilot c1", "pilot c2", "?" }; + u32 reg, mode, pilot; + + reg = cx_read(AUD_STATUS); + mode = reg & 0x03; + pilot = (reg >> 2) & 0x03; + + if (core->astat != reg) + dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n", + reg, m[mode], p[pilot], + aud_ctl_names[cx_read(AUD_CTL) & 63]); + core->astat = reg; + + t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + t->rxsubchans = UNSET; + t->audmode = V4L2_TUNER_MODE_MONO; + + switch (mode) { + case 0: + t->audmode = V4L2_TUNER_MODE_STEREO; + break; + case 1: + t->audmode = V4L2_TUNER_MODE_LANG2; + break; + case 2: + t->audmode = V4L2_TUNER_MODE_MONO; + break; + case 3: + t->audmode = V4L2_TUNER_MODE_SAP; + break; + } + + switch (core->tvaudio) { + case WW_BTSC: + case WW_BG: + case WW_DK: + case WW_M: + case WW_EIAJ: + if (!core->use_nicam) { + t->rxsubchans = cx88_dsp_detect_stereo_sap(core); + break; + } + break; + case WW_NONE: + case WW_I: + case WW_L: + case WW_I2SPT: + case WW_FM: + case WW_I2SADC: + /* nothing */ + break; + } + + /* If software stereo detection is not supported... */ + if (UNSET == t->rxsubchans) { + t->rxsubchans = V4L2_TUNER_SUB_MONO; + /* If the hardware itself detected stereo, also return + stereo as an available subchannel */ + if (V4L2_TUNER_MODE_STEREO == t->audmode) + t->rxsubchans |= V4L2_TUNER_SUB_STEREO; + } + return; +} + +void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) +{ + u32 ctl = UNSET; + u32 mask = UNSET; + + if (manual) { + core->audiomode_manual = mode; + } else { + if (UNSET != core->audiomode_manual) + return; + } + core->audiomode_current = mode; + + switch (core->tvaudio) { + case WW_BTSC: + switch (mode) { + case V4L2_TUNER_MODE_MONO: + set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_MONO); + break; + case V4L2_TUNER_MODE_LANG1: + set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); + break; + case V4L2_TUNER_MODE_LANG2: + set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP); + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO); + break; + } + break; + case WW_BG: + case WW_DK: + case WW_M: + case WW_I: + case WW_L: + if (1 == core->use_nicam) { + switch (mode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + set_audio_standard_NICAM(core, + EN_NICAM_FORCE_MONO1); + break; + case V4L2_TUNER_MODE_LANG2: + set_audio_standard_NICAM(core, + EN_NICAM_FORCE_MONO2); + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + set_audio_standard_NICAM(core, + EN_NICAM_FORCE_STEREO); + break; + } + } else { + if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) { + /* fall back to fm / am mono */ + set_audio_standard_A2(core, EN_A2_FORCE_MONO1); + } else { + /* TODO: Add A2 autodection */ + mask = 0x3f; + switch (mode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + ctl = EN_A2_FORCE_MONO1; + break; + case V4L2_TUNER_MODE_LANG2: + ctl = EN_A2_FORCE_MONO2; + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + ctl = EN_A2_FORCE_STEREO; + break; + } + } + } + break; + case WW_FM: + switch (mode) { + case V4L2_TUNER_MODE_MONO: + ctl = EN_FMRADIO_FORCE_MONO; + mask = 0x3f; + break; + case V4L2_TUNER_MODE_STEREO: + ctl = EN_FMRADIO_AUTO_STEREO; + mask = 0x3f; + break; + } + break; + case WW_I2SADC: + case WW_NONE: + case WW_EIAJ: + case WW_I2SPT: + /* DO NOTHING */ + break; + } + + if (UNSET != ctl) { + dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x " + "[status=0x%x,ctl=0x%x,vol=0x%x]\n", + mask, ctl, cx_read(AUD_STATUS), + cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL)); + cx_andor(AUD_CTL, mask, ctl); + } + return; +} + +int cx88_audio_thread(void *data) +{ + struct cx88_core *core = data; + struct v4l2_tuner t; + u32 mode = 0; + + dprintk("cx88: tvaudio thread started\n"); + set_freezable(); + for (;;) { + msleep_interruptible(1000); + if (kthread_should_stop()) + break; + try_to_freeze(); + + switch (core->tvaudio) { + case WW_BG: + case WW_DK: + case WW_M: + case WW_I: + case WW_L: + if (core->use_nicam) + goto hw_autodetect; + + /* just monitor the audio status for now ... */ + memset(&t, 0, sizeof(t)); + cx88_get_stereo(core, &t); + + if (UNSET != core->audiomode_manual) + /* manually set, don't do anything. */ + continue; + + /* monitor signal and set stereo if available */ + if (t.rxsubchans & V4L2_TUNER_SUB_STEREO) + mode = V4L2_TUNER_MODE_STEREO; + else + mode = V4L2_TUNER_MODE_MONO; + if (mode == core->audiomode_current) + continue; + /* automatically switch to best available mode */ + cx88_set_stereo(core, mode, 0); + break; + case WW_NONE: + case WW_BTSC: + case WW_EIAJ: + case WW_I2SPT: + case WW_FM: + case WW_I2SADC: +hw_autodetect: + /* stereo autodetection is supported by hardware so + we don't need to do it manually. Do nothing. */ + break; + } + } + + dprintk("cx88: tvaudio thread exiting\n"); + return 0; +} + +/* ----------------------------------------------------------- */ + +EXPORT_SYMBOL(cx88_set_tvaudio); +EXPORT_SYMBOL(cx88_newstation); +EXPORT_SYMBOL(cx88_set_stereo); +EXPORT_SYMBOL(cx88_get_stereo); +EXPORT_SYMBOL(cx88_audio_thread); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vbi.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,245 @@ +/* + */ +#include +#include +#include + +#include "cx88.h" + +static unsigned int vbibufs = 4; +module_param(vbibufs,int,0644); +MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); + +static unsigned int vbi_debug; +module_param(vbi_debug,int,0644); +MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); + +#define dprintk(level,fmt, arg...) if (vbi_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg) + +/* ------------------------------------------------------------------ */ + +int cx8800_vbi_fmt (struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx8800_fh *fh = priv; + struct cx8800_dev *dev = fh->dev; + + f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 244; + f->fmt.vbi.count[0] = VBI_LINE_COUNT; + f->fmt.vbi.count[1] = VBI_LINE_COUNT; + + if (dev->core->tvnorm & V4L2_STD_525_60) { + /* ntsc */ + f->fmt.vbi.sampling_rate = 28636363; + f->fmt.vbi.start[0] = 10; + f->fmt.vbi.start[1] = 273; + + } else if (dev->core->tvnorm & V4L2_STD_625_50) { + /* pal */ + f->fmt.vbi.sampling_rate = 35468950; + f->fmt.vbi.start[0] = 7 -1; + f->fmt.vbi.start[1] = 319 -1; + } + return 0; +} + +static int cx8800_start_vbi_dma(struct cx8800_dev *dev, + struct cx88_dmaqueue *q, + struct cx88_buffer *buf) +{ + struct cx88_core *core = dev->core; + + /* setup fifo + format */ + cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24], + buf->vb.width, buf->risc.dma); + + cx_write(MO_VBOS_CONTROL, ( (1 << 18) | // comb filter delay fixup + (1 << 15) | // enable vbi capture + (1 << 11) )); + + /* reset counter */ + cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET); + q->count = 1; + + /* enable irqs */ + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); + cx_set(MO_VID_INTMSK, 0x0f0088); + + /* enable capture */ + cx_set(VID_CAPTURE_CONTROL,0x18); + + /* start dma */ + cx_set(MO_DEV_CNTRL2, (1<<5)); + cx_set(MO_VID_DMACNTRL, 0x88); + + return 0; +} + +int cx8800_stop_vbi_dma(struct cx8800_dev *dev) +{ + struct cx88_core *core = dev->core; + + /* stop dma */ + cx_clear(MO_VID_DMACNTRL, 0x88); + + /* disable capture */ + cx_clear(VID_CAPTURE_CONTROL,0x18); + + /* disable irqs */ + cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); + cx_clear(MO_VID_INTMSK, 0x0f0088); + return 0; +} + +int cx8800_restart_vbi_queue(struct cx8800_dev *dev, + struct cx88_dmaqueue *q) +{ + struct cx88_buffer *buf; + + if (list_empty(&q->active)) + return 0; + + buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); + dprintk(2,"restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx8800_start_vbi_dma(dev, q, buf); + list_for_each_entry(buf, &q->active, vb.queue) + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +void cx8800_vbi_timeout(unsigned long data) +{ + struct cx8800_dev *dev = (struct cx8800_dev*)data; + struct cx88_core *core = dev->core; + struct cx88_dmaqueue *q = &dev->vbiq; + struct cx88_buffer *buf; + unsigned long flags; + + cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH24]); + + cx_clear(MO_VID_DMACNTRL, 0x88); + cx_clear(VID_CAPTURE_CONTROL, 0x18); + + spin_lock_irqsave(&dev->slock,flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name, + buf, buf->vb.i, (unsigned long)buf->risc.dma); + } + cx8800_restart_vbi_queue(dev,q); + spin_unlock_irqrestore(&dev->slock,flags); +} + +/* ------------------------------------------------------------------ */ + +static int +vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; + if (0 == *count) + *count = vbibufs; + if (*count < 2) + *count = 2; + if (*count > 32) + *count = 32; + return 0; +} + +static int +vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx8800_fh *fh = q->priv_data; + struct cx8800_dev *dev = fh->dev; + struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + unsigned int size; + int rc; + + size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = VBI_LINE_LENGTH; + buf->vb.height = VBI_LINE_COUNT; + buf->vb.size = size; + buf->vb.field = V4L2_FIELD_SEQ_TB; + + if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) + goto fail; + cx88_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->vb.width * buf->vb.height, + buf->vb.width, 0, + buf->vb.height); + } + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx88_free_buffer(q,buf); + return rc; +} + +static void +vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + struct cx88_buffer *prev; + struct cx8800_fh *fh = vq->priv_data; + struct cx8800_dev *dev = fh->dev; + struct cx88_dmaqueue *q = &dev->vbiq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + + if (list_empty(&q->active)) { + list_add_tail(&buf->vb.queue,&q->active); + cx8800_start_vbi_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2,"[%p/%d] vbi_queue - first active\n", + buf, buf->vb.i); + + } else { + prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(2,"[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.i); + } +} + +static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + + cx88_free_buffer(q,buf); +} + +const struct videobuf_queue_ops cx8800_vbi_qops = { + .buf_setup = vbi_setup, + .buf_prepare = vbi_prepare, + .buf_queue = vbi_queue, + .buf_release = vbi_release, +}; + +/* ------------------------------------------------------------------ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-video.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-video.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,2167 @@ +/* + * + * device driver for Conexant 2388x based TV cards + * video4linux video interface + * + * (c) 2003-04 Gerd Knorr [SuSE Labs] + * + * (c) 2005-2006 Mauro Carvalho Chehab + * - Multituner support + * - video_ioctl2 conversion + * - PAL/M fixes + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx88.h" +#include +#include +#include + +MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); +MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); +MODULE_LICENSE("GPL"); + +/* ------------------------------------------------------------------ */ + +static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; + +module_param_array(video_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); + +MODULE_PARM_DESC(video_nr,"video device numbers"); +MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); +MODULE_PARM_DESC(radio_nr,"radio device numbers"); + +static unsigned int video_debug; +module_param(video_debug,int,0644); +MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); + +static unsigned int irq_debug; +module_param(irq_debug,int,0644); +MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); + +static unsigned int vid_limit = 16; +module_param(vid_limit,int,0644); +MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); + +#define dprintk(level,fmt, arg...) if (video_debug >= level) \ + printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) + +/* ------------------------------------------------------------------- */ +/* static data */ + +static const struct cx8800_fmt formats[] = { + { + .name = "8 bpp, gray", + .fourcc = V4L2_PIX_FMT_GREY, + .cxformat = ColorFormatY8, + .depth = 8, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "15 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB555, + .cxformat = ColorFormatRGB15, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "15 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB555X, + .cxformat = ColorFormatRGB15 | ColorFormatBSWAP, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "16 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB565, + .cxformat = ColorFormatRGB16, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "16 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB565X, + .cxformat = ColorFormatRGB16 | ColorFormatBSWAP, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "24 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR24, + .cxformat = ColorFormatRGB24, + .depth = 24, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "32 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR32, + .cxformat = ColorFormatRGB32, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "32 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB32, + .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .cxformat = ColorFormatYUY2, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .cxformat = ColorFormatYUY2 | ColorFormatBSWAP, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, +}; + +static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (formats[i].fourcc == fourcc) + return formats+i; + return NULL; +} + +/* ------------------------------------------------------------------- */ + +static const struct v4l2_queryctrl no_ctl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; + +static const struct cx88_ctrl cx8800_ctls[] = { + /* --- video --- */ + { + .v = { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = MO_CONTR_BRIGHT, + .mask = 0x00ff, + .shift = 0, + },{ + .v = { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = MO_CONTR_BRIGHT, + .mask = 0xff00, + .shift = 8, + },{ + .v = { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = MO_HUE, + .mask = 0x00ff, + .shift = 0, + },{ + /* strictly, this only describes only U saturation. + * V saturation is handled specially through code. + */ + .v = { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = MO_UV_SATURATION, + .mask = 0x00ff, + .shift = 0, + },{ + .v = { + .id = V4L2_CID_CHROMA_AGC, + .name = "Chroma AGC", + .minimum = 0, + .maximum = 1, + .default_value = 0x1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, + .reg = MO_INPUT_FORMAT, + .mask = 1 << 10, + .shift = 10, + }, { + .v = { + .id = V4L2_CID_COLOR_KILLER, + .name = "Color killer", + .minimum = 0, + .maximum = 1, + .default_value = 0x1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, + .reg = MO_INPUT_FORMAT, + .mask = 1 << 9, + .shift = 9, + }, { + /* --- audio --- */ + .v = { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, + .reg = AUD_VOL_CTL, + .sreg = SHADOW_AUD_VOL_CTL, + .mask = (1 << 6), + .shift = 6, + },{ + .v = { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 0x3f, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .reg = AUD_VOL_CTL, + .sreg = SHADOW_AUD_VOL_CTL, + .mask = 0x3f, + .shift = 0, + },{ + .v = { + .id = V4L2_CID_AUDIO_BALANCE, + .name = "Balance", + .minimum = 0, + .maximum = 0x7f, + .step = 1, + .default_value = 0x40, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .reg = AUD_BAL_CTL, + .sreg = SHADOW_AUD_BAL_CTL, + .mask = 0x7f, + .shift = 0, + } +}; +enum { CX8800_CTLS = ARRAY_SIZE(cx8800_ctls) }; + +/* Must be sorted from low to high control ID! */ +const u32 cx88_user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_AUDIO_VOLUME, + V4L2_CID_AUDIO_BALANCE, + V4L2_CID_AUDIO_MUTE, + V4L2_CID_CHROMA_AGC, + V4L2_CID_COLOR_KILLER, + 0 +}; +EXPORT_SYMBOL(cx88_user_ctrls); + +static const u32 * const ctrl_classes[] = { + cx88_user_ctrls, + NULL +}; + +int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl) +{ + int i; + + if (qctrl->id < V4L2_CID_BASE || + qctrl->id >= V4L2_CID_LASTP1) + return -EINVAL; + for (i = 0; i < CX8800_CTLS; i++) + if (cx8800_ctls[i].v.id == qctrl->id) + break; + if (i == CX8800_CTLS) { + *qctrl = no_ctl; + return 0; + } + *qctrl = cx8800_ctls[i].v; + /* Report chroma AGC as inactive when SECAM is selected */ + if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC && + core->tvnorm & V4L2_STD_SECAM) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + + return 0; +} +EXPORT_SYMBOL(cx8800_ctrl_query); + +/* ------------------------------------------------------------------- */ +/* resource management */ + +static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit) +{ + struct cx88_core *core = dev->core; + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + mutex_lock(&core->lock); + if (dev->resources & bit) { + /* no, someone else uses it */ + mutex_unlock(&core->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->resources |= bit; + dprintk(1,"res: get %d\n",bit); + mutex_unlock(&core->lock); + return 1; +} + +static +int res_check(struct cx8800_fh *fh, unsigned int bit) +{ + return (fh->resources & bit); +} + +static +int res_locked(struct cx8800_dev *dev, unsigned int bit) +{ + return (dev->resources & bit); +} + +static +void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits) +{ + struct cx88_core *core = dev->core; + BUG_ON((fh->resources & bits) != bits); + + mutex_lock(&core->lock); + fh->resources &= ~bits; + dev->resources &= ~bits; + dprintk(1,"res: put %d\n",bits); + mutex_unlock(&core->lock); +} + +/* ------------------------------------------------------------------ */ + +int cx88_video_mux(struct cx88_core *core, unsigned int input) +{ + /* struct cx88_core *core = dev->core; */ + + dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", + input, INPUT(input).vmux, + INPUT(input).gpio0,INPUT(input).gpio1, + INPUT(input).gpio2,INPUT(input).gpio3); + core->input = input; + cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14); + cx_write(MO_GP3_IO, INPUT(input).gpio3); + cx_write(MO_GP0_IO, INPUT(input).gpio0); + cx_write(MO_GP1_IO, INPUT(input).gpio1); + cx_write(MO_GP2_IO, INPUT(input).gpio2); + + switch (INPUT(input).type) { + case CX88_VMUX_SVIDEO: + cx_set(MO_AFECFG_IO, 0x00000001); + cx_set(MO_INPUT_FORMAT, 0x00010010); + cx_set(MO_FILTER_EVEN, 0x00002020); + cx_set(MO_FILTER_ODD, 0x00002020); + break; + default: + cx_clear(MO_AFECFG_IO, 0x00000001); + cx_clear(MO_INPUT_FORMAT, 0x00010010); + cx_clear(MO_FILTER_EVEN, 0x00002020); + cx_clear(MO_FILTER_ODD, 0x00002020); + break; + } + + /* if there are audioroutes defined, we have an external + ADC to deal with audio */ + if (INPUT(input).audioroute) { + /* The wm8775 module has the "2" route hardwired into + the initialization. Some boards may use different + routes for different inputs. HVR-1300 surely does */ + if (core->board.audio_chip && + core->board.audio_chip == V4L2_IDENT_WM8775) { + call_all(core, audio, s_routing, + INPUT(input).audioroute, 0, 0); + } + /* cx2388's C-ADC is connected to the tuner only. + When used with S-Video, that ADC is busy dealing with + chroma, so an external must be used for baseband audio */ + if (INPUT(input).type != CX88_VMUX_TELEVISION && + INPUT(input).type != CX88_VMUX_CABLE) { + /* "I2S ADC mode" */ + core->tvaudio = WW_I2SADC; + cx88_set_tvaudio(core); + } else { + /* Normal mode */ + cx_write(AUD_I2SCNTL, 0x0); + cx_clear(AUD_CTL, EN_I2SIN_ENABLE); + } + } + + return 0; +} +EXPORT_SYMBOL(cx88_video_mux); + +/* ------------------------------------------------------------------ */ + +static int start_video_dma(struct cx8800_dev *dev, + struct cx88_dmaqueue *q, + struct cx88_buffer *buf) +{ + struct cx88_core *core = dev->core; + + /* setup fifo + format */ + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], + buf->bpl, buf->risc.dma); + cx88_set_scale(core, buf->vb.width, buf->vb.height, buf->vb.field); + cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma); + + /* reset counter */ + cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET); + q->count = 1; + + /* enable irqs */ + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); + + /* Enables corresponding bits at PCI_INT_STAT: + bits 0 to 4: video, audio, transport stream, VIP, Host + bit 7: timer + bits 8 and 9: DMA complete for: SRC, DST + bits 10 and 11: BERR signal asserted for RISC: RD, WR + bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB + */ + cx_set(MO_VID_INTMSK, 0x0f0011); + + /* enable capture */ + cx_set(VID_CAPTURE_CONTROL,0x06); + + /* start dma */ + cx_set(MO_DEV_CNTRL2, (1<<5)); + cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */ + + return 0; +} + +#ifdef CONFIG_PM +static int stop_video_dma(struct cx8800_dev *dev) +{ + struct cx88_core *core = dev->core; + + /* stop dma */ + cx_clear(MO_VID_DMACNTRL, 0x11); + + /* disable capture */ + cx_clear(VID_CAPTURE_CONTROL,0x06); + + /* disable irqs */ + cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); + cx_clear(MO_VID_INTMSK, 0x0f0011); + return 0; +} +#endif + +static int restart_video_queue(struct cx8800_dev *dev, + struct cx88_dmaqueue *q) +{ + struct cx88_core *core = dev->core; + struct cx88_buffer *buf, *prev; + + if (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); + dprintk(2,"restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + start_video_dma(dev, q, buf); + list_for_each_entry(buf, &q->active, vb.queue) + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; + } + + prev = NULL; + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); + if (NULL == prev) { + list_move_tail(&buf->vb.queue, &q->active); + start_video_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_move_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(2,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); + } else { + return 0; + } + prev = buf; + } +} + +/* ------------------------------------------------------------------ */ + +static int +buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + struct cx8800_fh *fh = q->priv_data; + + *size = fh->fmt->depth*fh->width*fh->height >> 3; + if (0 == *count) + *count = 32; + if (*size * *count > vid_limit * 1024 * 1024) + *count = (vid_limit * 1024 * 1024) / *size; + return 0; +} + +static int +buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx8800_fh *fh = q->priv_data; + struct cx8800_dev *dev = fh->dev; + struct cx88_core *core = dev->core; + struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + int rc, init_buffer = 0; + + BUG_ON(NULL == fh->fmt); + if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || + fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) + return -EINVAL; + buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + if (buf->fmt != fh->fmt || + buf->vb.width != fh->width || + buf->vb.height != fh->height || + buf->vb.field != field) { + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + init_buffer = 1; + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + init_buffer = 1; + if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) + goto fail; + } + + if (init_buffer) { + buf->bpl = buf->vb.width * buf->fmt->depth >> 3; + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + cx88_risc_buffer(dev->pci, &buf->risc, + dma->sglist, 0, UNSET, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + cx88_risc_buffer(dev->pci, &buf->risc, + dma->sglist, UNSET, 0, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + cx88_risc_buffer(dev->pci, &buf->risc, + dma->sglist, 0, buf->bpl, + buf->bpl, buf->bpl, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + cx88_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->bpl * (buf->vb.height >> 1), + buf->bpl, 0, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + cx88_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + buf->bpl * (buf->vb.height >> 1), 0, + buf->bpl, 0, + buf->vb.height >> 1); + break; + default: + BUG(); + } + } + dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + buf, buf->vb.i, + fh->width, fh->height, fh->fmt->depth, fh->fmt->name, + (unsigned long)buf->risc.dma); + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx88_free_buffer(q,buf); + return rc; +} + +static void +buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + struct cx88_buffer *prev; + struct cx8800_fh *fh = vq->priv_data; + struct cx8800_dev *dev = fh->dev; + struct cx88_core *core = dev->core; + struct cx88_dmaqueue *q = &dev->vidq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + + if (!list_empty(&q->queued)) { + list_add_tail(&buf->vb.queue,&q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2,"[%p/%d] buffer_queue - append to queued\n", + buf, buf->vb.i); + + } else if (list_empty(&q->active)) { + list_add_tail(&buf->vb.queue,&q->active); + start_video_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2,"[%p/%d] buffer_queue - first active\n", + buf, buf->vb.i); + + } else { + prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); + if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(2,"[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.i); + + } else { + list_add_tail(&buf->vb.queue,&q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2,"[%p/%d] buffer_queue - first queued\n", + buf, buf->vb.i); + } + } +} + +static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + + cx88_free_buffer(q,buf); +} + +static const struct videobuf_queue_ops cx8800_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/* ------------------------------------------------------------------ */ + + +/* ------------------------------------------------------------------ */ + +static struct videobuf_queue* get_queue(struct cx8800_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &fh->vidq; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return &fh->vbiq; + default: + BUG(); + return NULL; + } +} + +static int get_ressource(struct cx8800_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return RESOURCE_VIDEO; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return RESOURCE_VBI; + default: + BUG(); + return 0; + } +} + +static int video_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct cx8800_dev *dev = video_drvdata(file); + struct cx88_core *core = dev->core; + struct cx8800_fh *fh; + enum v4l2_buf_type type = 0; + int radio = 0; + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; + } + + dprintk(1, "open dev=%s radio=%d type=%s\n", + video_device_node_name(vdev), radio, v4l2_type_names[type]); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh),GFP_KERNEL); + if (unlikely(!fh)) + return -ENOMEM; + + file->private_data = fh; + fh->dev = dev; + fh->radio = radio; + fh->type = type; + fh->width = 320; + fh->height = 240; + fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + + mutex_lock(&core->lock); + + videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct cx88_buffer), + fh, NULL); + videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, + sizeof(struct cx88_buffer), + fh, NULL); + + if (fh->radio) { + dprintk(1,"video_open: setting radio device\n"); + cx_write(MO_GP3_IO, core->board.radio.gpio3); + cx_write(MO_GP0_IO, core->board.radio.gpio0); + cx_write(MO_GP1_IO, core->board.radio.gpio1); + cx_write(MO_GP2_IO, core->board.radio.gpio2); + if (core->board.radio.audioroute) { + if(core->board.audio_chip && + core->board.audio_chip == V4L2_IDENT_WM8775) { + call_all(core, audio, s_routing, + core->board.radio.audioroute, 0, 0); + } + /* "I2S ADC mode" */ + core->tvaudio = WW_I2SADC; + cx88_set_tvaudio(core); + } else { + /* FM Mode */ + core->tvaudio = WW_FM; + cx88_set_tvaudio(core); + cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); + } + call_all(core, tuner, s_radio); + } + + core->users++; + mutex_unlock(&core->lock); + + return 0; +} + +static ssize_t +video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +{ + struct cx8800_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (res_locked(fh->dev,RESOURCE_VIDEO)) + return -EBUSY; + return videobuf_read_one(&fh->vidq, data, count, ppos, + file->f_flags & O_NONBLOCK); + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (!res_get(fh->dev,fh,RESOURCE_VBI)) + return -EBUSY; + return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, + file->f_flags & O_NONBLOCK); + default: + BUG(); + return 0; + } +} + +static unsigned int +video_poll(struct file *file, struct poll_table_struct *wait) +{ + struct cx8800_fh *fh = file->private_data; + struct cx88_buffer *buf; + unsigned int rc = POLLERR; + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (!res_get(fh->dev,fh,RESOURCE_VBI)) + return POLLERR; + return videobuf_poll_stream(file, &fh->vbiq, wait); + } + + mutex_lock(&fh->vidq.vb_lock); + if (res_check(fh,RESOURCE_VIDEO)) { + /* streaming capture */ + if (list_empty(&fh->vidq.stream)) + goto done; + buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream); + } else { + /* read() capture */ + buf = (struct cx88_buffer*)fh->vidq.read_buf; + if (NULL == buf) + goto done; + } + poll_wait(file, &buf->vb.done, wait); + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) + rc = POLLIN|POLLRDNORM; + else + rc = 0; +done: + mutex_unlock(&fh->vidq.vb_lock); + return rc; +} + +static int video_release(struct file *file) +{ + struct cx8800_fh *fh = file->private_data; + struct cx8800_dev *dev = fh->dev; + + /* turn off overlay */ + if (res_check(fh, RESOURCE_OVERLAY)) { + /* FIXME */ + res_free(dev,fh,RESOURCE_OVERLAY); + } + + /* stop video capture */ + if (res_check(fh, RESOURCE_VIDEO)) { + videobuf_queue_cancel(&fh->vidq); + res_free(dev,fh,RESOURCE_VIDEO); + } + if (fh->vidq.read_buf) { + buffer_release(&fh->vidq,fh->vidq.read_buf); + kfree(fh->vidq.read_buf); + } + + /* stop vbi capture */ + if (res_check(fh, RESOURCE_VBI)) { + videobuf_stop(&fh->vbiq); + res_free(dev,fh,RESOURCE_VBI); + } + + videobuf_mmap_free(&fh->vidq); + videobuf_mmap_free(&fh->vbiq); + + mutex_lock(&dev->core->lock); + file->private_data = NULL; + kfree(fh); + + dev->core->users--; + if (!dev->core->users) + call_all(dev->core, core, s_power, 0); + mutex_unlock(&dev->core->lock); + + return 0; +} + +static int +video_mmap(struct file *file, struct vm_area_struct * vma) +{ + struct cx8800_fh *fh = file->private_data; + + return videobuf_mmap_mapper(get_queue(fh), vma); +} + +/* ------------------------------------------------------------------ */ +/* VIDEO CTRL IOCTLS */ + +int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl) +{ + const struct cx88_ctrl *c = NULL; + u32 value; + int i; + + for (i = 0; i < CX8800_CTLS; i++) + if (cx8800_ctls[i].v.id == ctl->id) + c = &cx8800_ctls[i]; + if (unlikely(NULL == c)) + return -EINVAL; + + value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); + switch (ctl->id) { + case V4L2_CID_AUDIO_BALANCE: + ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) + : (0x7f - (value & 0x7f)); + break; + case V4L2_CID_AUDIO_VOLUME: + ctl->value = 0x3f - (value & 0x3f); + break; + default: + ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; + break; + } + dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctl->id, c->v.name, ctl->value, c->reg, + value,c->mask, c->sreg ? " [shadowed]" : ""); + return 0; +} +EXPORT_SYMBOL(cx88_get_control); + +int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) +{ + const struct cx88_ctrl *c = NULL; + u32 value,mask; + int i; + + for (i = 0; i < CX8800_CTLS; i++) { + if (cx8800_ctls[i].v.id == ctl->id) { + c = &cx8800_ctls[i]; + } + } + if (unlikely(NULL == c)) + return -EINVAL; + + if (ctl->value < c->v.minimum) + ctl->value = c->v.minimum; + if (ctl->value > c->v.maximum) + ctl->value = c->v.maximum; + + /* Pass changes onto any WM8775 */ + if (core->board.audio_chip == V4L2_IDENT_WM8775) { + struct v4l2_control client_ctl; + memset(&client_ctl, 0, sizeof(client_ctl)); + client_ctl.id = ctl->id; + + switch (ctl->id) { + case V4L2_CID_AUDIO_MUTE: + client_ctl.value = ctl->value; + break; + case V4L2_CID_AUDIO_VOLUME: + client_ctl.value = (ctl->value) ? + (0x90 + ctl->value) << 8 : 0; + break; + case V4L2_CID_AUDIO_BALANCE: + client_ctl.value = ctl->value << 9; + break; + default: + client_ctl.id = 0; + break; + } + if (client_ctl.id) + call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); + } + + mask=c->mask; + switch (ctl->id) { + case V4L2_CID_AUDIO_BALANCE: + value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); + break; + case V4L2_CID_AUDIO_VOLUME: + value = 0x3f - (ctl->value & 0x3f); + break; + case V4L2_CID_SATURATION: + /* special v_sat handling */ + + value = ((ctl->value - c->off) << c->shift) & c->mask; + + if (core->tvnorm & V4L2_STD_SECAM) { + /* For SECAM, both U and V sat should be equal */ + value=value<<8|value; + } else { + /* Keeps U Saturation proportional to V Sat */ + value=(value*0x5a)/0x7f<<8|value; + } + mask=0xffff; + break; + case V4L2_CID_CHROMA_AGC: + /* Do not allow chroma AGC to be enabled for SECAM */ + value = ((ctl->value - c->off) << c->shift) & c->mask; + if (core->tvnorm & V4L2_STD_SECAM && value) + return -EINVAL; + break; + default: + value = ((ctl->value - c->off) << c->shift) & c->mask; + break; + } + dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctl->id, c->v.name, ctl->value, c->reg, value, + mask, c->sreg ? " [shadowed]" : ""); + if (c->sreg) { + cx_sandor(c->sreg, c->reg, mask, value); + } else { + cx_andor(c->reg, mask, value); + } + return 0; +} +EXPORT_SYMBOL(cx88_set_control); + +static void init_controls(struct cx88_core *core) +{ + struct v4l2_control ctrl; + int i; + + for (i = 0; i < CX8800_CTLS; i++) { + ctrl.id=cx8800_ctls[i].v.id; + ctrl.value=cx8800_ctls[i].v.default_value; + + cx88_set_control(core, &ctrl); + } +} + +/* ------------------------------------------------------------------ */ +/* VIDEO IOCTLS */ + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx8800_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + const struct cx8800_fmt *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = norm_maxw(core->tvnorm); + maxh = norm_maxh(core->tvnorm); + + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + f->fmt.pix.field = field; + v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, + &f->fmt.pix.height, 32, maxh, 0, 0); + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx8800_fh *fh = priv; + int err = vidioc_try_fmt_vid_cap (file,priv,f); + + if (0 != err) + return err; + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->vidq.field = f->fmt.pix.field; + return 0; +} + +static int vidioc_querycap (struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; + struct cx88_core *core = dev->core; + + strcpy(cap->driver, "cx8800"); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); + cap->version = CX88_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (UNSET != core->board.tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(formats))) + return -EINVAL; + + strlcpy(f->description,formats[f->index].name,sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) +{ + struct cx8800_fh *fh = priv; + return (videobuf_reqbufs(get_queue(fh), p)); +} + +static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx8800_fh *fh = priv; + return (videobuf_querybuf(get_queue(fh), p)); +} + +static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx8800_fh *fh = priv; + return (videobuf_qbuf(get_queue(fh), p)); +} + +static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct cx8800_fh *fh = priv; + return (videobuf_dqbuf(get_queue(fh), p, + file->f_flags & O_NONBLOCK)); +} + +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx8800_fh *fh = priv; + struct cx8800_dev *dev = fh->dev; + + /* We should remember that this driver also supports teletext, */ + /* so we have to test if the v4l2_buf_type is VBI capture data. */ + if (unlikely((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))) + return -EINVAL; + + if (unlikely(i != fh->type)) + return -EINVAL; + + if (unlikely(!res_get(dev,fh,get_ressource(fh)))) + return -EBUSY; + return videobuf_streamon(get_queue(fh)); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx8800_fh *fh = priv; + struct cx8800_dev *dev = fh->dev; + int err, res; + + if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) + return -EINVAL; + + if (i != fh->type) + return -EINVAL; + + res = get_ressource(fh); + err = videobuf_streamoff(get_queue(fh)); + if (err < 0) + return err; + res_free(dev,fh,res); + return 0; +} + +static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + mutex_lock(&core->lock); + cx88_set_tvnorm(core,*tvnorms); + mutex_unlock(&core->lock); + + return 0; +} + +/* only one input in this sample driver */ +int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) +{ + static const char * const iname[] = { + [ CX88_VMUX_COMPOSITE1 ] = "Composite1", + [ CX88_VMUX_COMPOSITE2 ] = "Composite2", + [ CX88_VMUX_COMPOSITE3 ] = "Composite3", + [ CX88_VMUX_COMPOSITE4 ] = "Composite4", + [ CX88_VMUX_SVIDEO ] = "S-Video", + [ CX88_VMUX_TELEVISION ] = "Television", + [ CX88_VMUX_CABLE ] = "Cable TV", + [ CX88_VMUX_DVB ] = "DVB", + [ CX88_VMUX_DEBUG ] = "for debug only", + }; + unsigned int n = i->index; + + if (n >= 4) + return -EINVAL; + if (0 == INPUT(n).type) + return -EINVAL; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name,iname[INPUT(n).type]); + if ((CX88_VMUX_TELEVISION == INPUT(n).type) || + (CX88_VMUX_CABLE == INPUT(n).type)) { + i->type = V4L2_INPUT_TYPE_TUNER; + i->std = CX88_NORMS; + } + return 0; +} +EXPORT_SYMBOL(cx88_enum_input); + +static int vidioc_enum_input (struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + return cx88_enum_input (core,i); +} + +static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + *i = core->input; + return 0; +} + +static int vidioc_s_input (struct file *file, void *priv, unsigned int i) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + if (i >= 4) + return -EINVAL; + + mutex_lock(&core->lock); + cx88_newstation(core); + cx88_video_mux(core,i); + mutex_unlock(&core->lock); + return 0; +} + + + +static int vidioc_queryctrl (struct file *file, void *priv, + struct v4l2_queryctrl *qctrl) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (unlikely(qctrl->id == 0)) + return -EINVAL; + return cx8800_ctrl_query(core, qctrl); +} + +static int vidioc_g_ctrl (struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + return + cx88_get_control(core,ctl); +} + +static int vidioc_s_ctrl (struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + return + cx88_set_control(core,ctl); +} + +static int vidioc_g_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + u32 reg; + + if (unlikely(UNSET == core->board.tuner_type)) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; + + cx88_get_stereo(core ,t); + reg = cx_read(MO_DEVICE_STATUS); + t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; + return 0; +} + +static int vidioc_s_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + if (UNSET == core->board.tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + cx88_set_stereo(core, t->audmode, 1); + return 0; +} + +static int vidioc_g_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx8800_fh *fh = priv; + struct cx88_core *core = fh->dev->core; + + if (unlikely(UNSET == core->board.tuner_type)) + return -EINVAL; + + /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = core->freq; + + call_all(core, tuner, g_frequency, f); + + return 0; +} + +int cx88_set_freq (struct cx88_core *core, + struct v4l2_frequency *f) +{ + if (unlikely(UNSET == core->board.tuner_type)) + return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; + + mutex_lock(&core->lock); + core->freq = f->frequency; + cx88_newstation(core); + call_all(core, tuner, s_frequency, f); + + /* When changing channels it is required to reset TVAUDIO */ + msleep (10); + cx88_set_tvaudio(core); + + mutex_unlock(&core->lock); + + return 0; +} +EXPORT_SYMBOL(cx88_set_freq); + +static int vidioc_s_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx8800_fh *fh = priv; + struct cx88_core *core = fh->dev->core; + + if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) + return -EINVAL; + + return + cx88_set_freq (core,f); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register (struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; + + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + /* cx2388x has a 24-bit register space */ + reg->val = cx_read(reg->reg & 0xffffff); + reg->size = 4; + return 0; +} + +static int vidioc_s_register (struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; + + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + cx_write(reg->reg & 0xffffff, reg->val); + return 0; +} +#endif + +/* ----------------------------------------------------------- */ +/* RADIO ESPECIFIC IOCTLS */ +/* ----------------------------------------------------------- */ + +static int radio_querycap (struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; + struct cx88_core *core = dev->core; + + strcpy(cap->driver, "cx8800"); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); + cap->version = CX88_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; +} + +static int radio_g_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + if (unlikely(t->index > 0)) + return -EINVAL; + + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + call_all(core, tuner, g_tuner, t); + return 0; +} + +static int radio_enum_input (struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + strcpy(i->name,"Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + strcpy(a->name,"Radio"); + return 0; +} + +/* FIXME: Should add a standard for radio */ + +static int radio_s_tuner (struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + if (0 != t->index) + return -EINVAL; + + call_all(core, tuner, s_tuner, t); + + return 0; +} + +static int radio_s_audio (struct file *file, void *fh, + struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input (struct file *file, void *fh, unsigned int i) +{ + return 0; +} + +static int radio_queryctrl (struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + int i; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE || + c->id == V4L2_CID_AUDIO_VOLUME || + c->id == V4L2_CID_AUDIO_BALANCE) { + for (i = 0; i < CX8800_CTLS; i++) { + if (cx8800_ctls[i].v.id == c->id) + break; + } + if (i == CX8800_CTLS) + return -EINVAL; + *c = cx8800_ctls[i].v; + } else + *c = no_ctl; + return 0; +} + +/* ----------------------------------------------------------- */ + +static void cx8800_vid_timeout(unsigned long data) +{ + struct cx8800_dev *dev = (struct cx8800_dev*)data; + struct cx88_core *core = dev->core; + struct cx88_dmaqueue *q = &dev->vidq; + struct cx88_buffer *buf; + unsigned long flags; + + cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); + + cx_clear(MO_VID_DMACNTRL, 0x11); + cx_clear(VID_CAPTURE_CONTROL, 0x06); + + spin_lock_irqsave(&dev->slock,flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, + buf, buf->vb.i, (unsigned long)buf->risc.dma); + } + restart_video_queue(dev,q); + spin_unlock_irqrestore(&dev->slock,flags); +} + +static const char *cx88_vid_irqs[32] = { + "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", + "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", + "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", + "y_sync", "u_sync", "v_sync", "vbi_sync", + "opc_err", "par_err", "rip_err", "pci_abort", +}; + +static void cx8800_vid_irq(struct cx8800_dev *dev) +{ + struct cx88_core *core = dev->core; + u32 status, mask, count; + + status = cx_read(MO_VID_INTSTAT); + mask = cx_read(MO_VID_INTMSK); + if (0 == (status & mask)) + return; + cx_write(MO_VID_INTSTAT, status); + if (irq_debug || (status & mask & ~0xff)) + cx88_print_irqbits(core->name, "irq vid", + cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), + status, mask); + + /* risc op code error */ + if (status & (1 << 16)) { + printk(KERN_WARNING "%s/0: video risc op code error\n",core->name); + cx_clear(MO_VID_DMACNTRL, 0x11); + cx_clear(VID_CAPTURE_CONTROL, 0x06); + cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); + } + + /* risc1 y */ + if (status & 0x01) { + spin_lock(&dev->slock); + count = cx_read(MO_VIDY_GPCNT); + cx88_wakeup(core, &dev->vidq, count); + spin_unlock(&dev->slock); + } + + /* risc1 vbi */ + if (status & 0x08) { + spin_lock(&dev->slock); + count = cx_read(MO_VBI_GPCNT); + cx88_wakeup(core, &dev->vbiq, count); + spin_unlock(&dev->slock); + } + + /* risc2 y */ + if (status & 0x10) { + dprintk(2,"stopper video\n"); + spin_lock(&dev->slock); + restart_video_queue(dev,&dev->vidq); + spin_unlock(&dev->slock); + } + + /* risc2 vbi */ + if (status & 0x80) { + dprintk(2,"stopper vbi\n"); + spin_lock(&dev->slock); + cx8800_restart_vbi_queue(dev,&dev->vbiq); + spin_unlock(&dev->slock); + } +} + +static irqreturn_t cx8800_irq(int irq, void *dev_id) +{ + struct cx8800_dev *dev = dev_id; + struct cx88_core *core = dev->core; + u32 status; + int loop, handled = 0; + + for (loop = 0; loop < 10; loop++) { + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_VIDINT); + if (0 == status) + goto out; + cx_write(MO_PCI_INTSTAT, status); + handled = 1; + + if (status & core->pci_irqmask) + cx88_core_irq(core,status); + if (status & PCI_INT_VIDINT) + cx8800_vid_irq(dev); + }; + if (10 == loop) { + printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", + core->name); + cx_write(MO_PCI_INTMSK,0); + } + + out: + return IRQ_RETVAL(handled); +} + +/* ----------------------------------------------------------- */ +/* exported stuff */ + +static const struct v4l2_file_operations video_fops = +{ + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .read = video_read, + .poll = video_poll, + .mmap = video_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +static struct video_device cx8800_vbi_template; + +static const struct video_device cx8800_video_template = { + .name = "cx8800-video", + .fops = &video_fops, + .ioctl_ops = &video_ioctl_ops, + .tvnorms = CX88_NORMS, + .current_norm = V4L2_STD_NTSC_M, +}; + +static const struct v4l2_file_operations radio_fops = +{ + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +static const struct video_device cx8800_radio_template = { + .name = "cx8800-radio", + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, +}; + +/* ----------------------------------------------------------- */ + +static void cx8800_unregister_video(struct cx8800_dev *dev) +{ + if (dev->radio_dev) { + if (video_is_registered(dev->radio_dev)) + video_unregister_device(dev->radio_dev); + else + video_device_release(dev->radio_dev); + dev->radio_dev = NULL; + } + if (dev->vbi_dev) { + if (video_is_registered(dev->vbi_dev)) + video_unregister_device(dev->vbi_dev); + else + video_device_release(dev->vbi_dev); + dev->vbi_dev = NULL; + } + if (dev->video_dev) { + if (video_is_registered(dev->video_dev)) + video_unregister_device(dev->video_dev); + else + video_device_release(dev->video_dev); + dev->video_dev = NULL; + } +} + +static int __devinit cx8800_initdev(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cx8800_dev *dev; + struct cx88_core *core; + + int err; + + dev = kzalloc(sizeof(*dev),GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + + /* pci init */ + dev->pci = pci_dev; + if (pci_enable_device(pci_dev)) { + err = -EIO; + goto fail_free; + } + core = cx88_core_get(dev->pci); + if (NULL == core) { + err = -EINVAL; + goto fail_free; + } + dev->core = core; + + /* print pci info */ + dev->pci_rev = pci_dev->revision; + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%llx\n", core->name, + pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); + + pci_set_master(pci_dev); + if (!pci_dma_supported(pci_dev,DMA_BIT_MASK(32))) { + printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); + err = -EIO; + goto fail_core; + } + + /* Initialize VBI template */ + memcpy( &cx8800_vbi_template, &cx8800_video_template, + sizeof(cx8800_vbi_template) ); + strcpy(cx8800_vbi_template.name,"cx8800-vbi"); + + /* initialize driver struct */ + spin_lock_init(&dev->slock); + core->tvnorm = cx8800_video_template.current_norm; + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + dev->vidq.timeout.function = cx8800_vid_timeout; + dev->vidq.timeout.data = (unsigned long)dev; + init_timer(&dev->vidq.timeout); + cx88_risc_stopper(dev->pci,&dev->vidq.stopper, + MO_VID_DMACNTRL,0x11,0x00); + + /* init vbi dma queues */ + INIT_LIST_HEAD(&dev->vbiq.active); + INIT_LIST_HEAD(&dev->vbiq.queued); + dev->vbiq.timeout.function = cx8800_vbi_timeout; + dev->vbiq.timeout.data = (unsigned long)dev; + init_timer(&dev->vbiq.timeout); + cx88_risc_stopper(dev->pci,&dev->vbiq.stopper, + MO_VID_DMACNTRL,0x88,0x00); + + /* get irq */ + err = request_irq(pci_dev->irq, cx8800_irq, + IRQF_SHARED | IRQF_DISABLED, core->name, dev); + if (err < 0) { + printk(KERN_ERR "%s/0: can't get IRQ %d\n", + core->name,pci_dev->irq); + goto fail_core; + } + cx_set(MO_PCI_INTMSK, core->pci_irqmask); + + /* load and configure helper modules */ + + if (core->board.audio_chip == V4L2_IDENT_WM8775) { + struct i2c_board_info wm8775_info = { + .type = "wm8775", + .addr = 0x36 >> 1, + .platform_data = &core->wm8775_data, + }; + struct v4l2_subdev *sd; + + if (core->boardnr == CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1) + core->wm8775_data.is_nova_s = true; + else + core->wm8775_data.is_nova_s = false; + + sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap, + &wm8775_info, NULL); + if (sd != NULL) + sd->grp_id = WM8775_GID; + } + + if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { + /* This probes for a tda9874 as is used on some + Pixelview Ultra boards. */ + v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, + "tvaudio", 0, I2C_ADDRS(0xb0 >> 1)); + } + + switch (core->boardnr) { + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: + case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: { + static const struct i2c_board_info rtc_info = { + I2C_BOARD_INFO("isl1208", 0x6f) + }; + + request_module("rtc-isl1208"); + core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info); + } + /* break intentionally omitted */ + case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: + request_module("ir-kbd-i2c"); + } + + /* Sets device info at pci_dev */ + pci_set_drvdata(pci_dev, dev); + + /* initial device configuration */ + mutex_lock(&core->lock); + cx88_set_tvnorm(core, core->tvnorm); + init_controls(core); + cx88_video_mux(core, 0); + + /* register v4l devices */ + dev->video_dev = cx88_vdev_init(core,dev->pci, + &cx8800_video_template,"video"); + video_set_drvdata(dev->video_dev, dev); + err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, + video_nr[core->nr]); + if (err < 0) { + printk(KERN_ERR "%s/0: can't register video device\n", + core->name); + goto fail_unreg; + } + printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", + core->name, video_device_node_name(dev->video_dev)); + + dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); + video_set_drvdata(dev->vbi_dev, dev); + err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, + vbi_nr[core->nr]); + if (err < 0) { + printk(KERN_ERR "%s/0: can't register vbi device\n", + core->name); + goto fail_unreg; + } + printk(KERN_INFO "%s/0: registered device %s\n", + core->name, video_device_node_name(dev->vbi_dev)); + + if (core->board.radio.type == CX88_RADIO) { + dev->radio_dev = cx88_vdev_init(core,dev->pci, + &cx8800_radio_template,"radio"); + video_set_drvdata(dev->radio_dev, dev); + err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, + radio_nr[core->nr]); + if (err < 0) { + printk(KERN_ERR "%s/0: can't register radio device\n", + core->name); + goto fail_unreg; + } + printk(KERN_INFO "%s/0: registered device %s\n", + core->name, video_device_node_name(dev->radio_dev)); + } + + /* start tvaudio thread */ + if (core->board.tuner_type != TUNER_ABSENT) { + core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); + if (IS_ERR(core->kthread)) { + err = PTR_ERR(core->kthread); + printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n", + core->name, err); + } + } + mutex_unlock(&core->lock); + + return 0; + +fail_unreg: + cx8800_unregister_video(dev); + free_irq(pci_dev->irq, dev); + mutex_unlock(&core->lock); +fail_core: + cx88_core_put(core,dev->pci); +fail_free: + kfree(dev); + return err; +} + +static void __devexit cx8800_finidev(struct pci_dev *pci_dev) +{ + struct cx8800_dev *dev = pci_get_drvdata(pci_dev); + struct cx88_core *core = dev->core; + + /* stop thread */ + if (core->kthread) { + kthread_stop(core->kthread); + core->kthread = NULL; + } + + if (core->ir) + cx88_ir_stop(core); + + cx88_shutdown(core); /* FIXME */ + pci_disable_device(pci_dev); + + /* unregister stuff */ + + free_irq(pci_dev->irq, dev); + cx8800_unregister_video(dev); + pci_set_drvdata(pci_dev, NULL); + + /* free memory */ + btcx_riscmem_free(dev->pci,&dev->vidq.stopper); + cx88_core_put(core,dev->pci); + kfree(dev); +} + +#ifdef CONFIG_PM +static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) +{ + struct cx8800_dev *dev = pci_get_drvdata(pci_dev); + struct cx88_core *core = dev->core; + + /* stop video+vbi capture */ + spin_lock(&dev->slock); + if (!list_empty(&dev->vidq.active)) { + printk("%s/0: suspend video\n", core->name); + stop_video_dma(dev); + del_timer(&dev->vidq.timeout); + } + if (!list_empty(&dev->vbiq.active)) { + printk("%s/0: suspend vbi\n", core->name); + cx8800_stop_vbi_dma(dev); + del_timer(&dev->vbiq.timeout); + } + spin_unlock(&dev->slock); + + if (core->ir) + cx88_ir_stop(core); + /* FIXME -- shutdown device */ + cx88_shutdown(core); + + pci_save_state(pci_dev); + if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { + pci_disable_device(pci_dev); + dev->state.disabled = 1; + } + return 0; +} + +static int cx8800_resume(struct pci_dev *pci_dev) +{ + struct cx8800_dev *dev = pci_get_drvdata(pci_dev); + struct cx88_core *core = dev->core; + int err; + + if (dev->state.disabled) { + err=pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR "%s/0: can't enable device\n", + core->name); + return err; + } + + dev->state.disabled = 0; + } + err= pci_set_power_state(pci_dev, PCI_D0); + if (err) { + printk(KERN_ERR "%s/0: can't set power state\n", core->name); + pci_disable_device(pci_dev); + dev->state.disabled = 1; + + return err; + } + pci_restore_state(pci_dev); + + /* FIXME: re-initialize hardware */ + cx88_reset(core); + if (core->ir) + cx88_ir_start(core); + + cx_set(MO_PCI_INTMSK, core->pci_irqmask); + + /* restart video+vbi capture */ + spin_lock(&dev->slock); + if (!list_empty(&dev->vidq.active)) { + printk("%s/0: resume video\n", core->name); + restart_video_queue(dev,&dev->vidq); + } + if (!list_empty(&dev->vbiq.active)) { + printk("%s/0: resume vbi\n", core->name); + cx8800_restart_vbi_queue(dev,&dev->vbiq); + } + spin_unlock(&dev->slock); + + return 0; +} +#endif + +/* ----------------------------------------------------------- */ + +static const struct pci_device_id cx8800_pci_tbl[] = { + { + .vendor = 0x14f1, + .device = 0x8800, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* --- end of list --- */ + } +}; +MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl); + +static struct pci_driver cx8800_pci_driver = { + .name = "cx8800", + .id_table = cx8800_pci_tbl, + .probe = cx8800_initdev, + .remove = __devexit_p(cx8800_finidev), +#ifdef CONFIG_PM + .suspend = cx8800_suspend, + .resume = cx8800_resume, +#endif +}; + +static int __init cx8800_init(void) +{ + printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx8800_pci_driver); +} + +static void __exit cx8800_fini(void) +{ + pci_unregister_driver(&cx8800_pci_driver); +} + +module_init(cx8800_init); +module_exit(cx8800_fini); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vp3054-i2c.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,159 @@ +/* + + cx88-vp3054-i2c.c -- support for the secondary I2C bus of the + DNTV Live! DVB-T Pro (VP-3054), wired as: + GPIO[0] -> SCL, GPIO[1] -> SDA + + (c) 2005 Chris Pascoe + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include + +#include + +#include "cx88.h" +#include "cx88-vp3054-i2c.h" + +MODULE_DESCRIPTION("driver for cx2388x VP3054 design"); +MODULE_AUTHOR("Chris Pascoe "); +MODULE_LICENSE("GPL"); + +/* ----------------------------------------------------------------------- */ + +static void vp3054_bit_setscl(void *data, int state) +{ + struct cx8802_dev *dev = data; + struct cx88_core *core = dev->core; + struct vp3054_i2c_state *vp3054_i2c = dev->vp3054; + + if (state) { + vp3054_i2c->state |= 0x0001; /* SCL high */ + vp3054_i2c->state &= ~0x0100; /* external pullup */ + } else { + vp3054_i2c->state &= ~0x0001; /* SCL low */ + vp3054_i2c->state |= 0x0100; /* drive pin */ + } + cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state); + cx_read(MO_GP0_IO); +} + +static void vp3054_bit_setsda(void *data, int state) +{ + struct cx8802_dev *dev = data; + struct cx88_core *core = dev->core; + struct vp3054_i2c_state *vp3054_i2c = dev->vp3054; + + if (state) { + vp3054_i2c->state |= 0x0002; /* SDA high */ + vp3054_i2c->state &= ~0x0200; /* tristate pin */ + } else { + vp3054_i2c->state &= ~0x0002; /* SDA low */ + vp3054_i2c->state |= 0x0200; /* drive pin */ + } + cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state); + cx_read(MO_GP0_IO); +} + +static int vp3054_bit_getscl(void *data) +{ + struct cx8802_dev *dev = data; + struct cx88_core *core = dev->core; + u32 state; + + state = cx_read(MO_GP0_IO); + return (state & 0x01) ? 1 : 0; +} + +static int vp3054_bit_getsda(void *data) +{ + struct cx8802_dev *dev = data; + struct cx88_core *core = dev->core; + u32 state; + + state = cx_read(MO_GP0_IO); + return (state & 0x02) ? 1 : 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_algo_bit_data vp3054_i2c_algo_template = { + .setsda = vp3054_bit_setsda, + .setscl = vp3054_bit_setscl, + .getsda = vp3054_bit_getsda, + .getscl = vp3054_bit_getscl, + .udelay = 16, + .timeout = 200, +}; + +/* ----------------------------------------------------------------------- */ + +int vp3054_i2c_probe(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + struct vp3054_i2c_state *vp3054_i2c; + int rc; + + if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + return 0; + + vp3054_i2c = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL); + if (vp3054_i2c == NULL) + return -ENOMEM; + dev->vp3054 = vp3054_i2c; + + memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template, + sizeof(vp3054_i2c->algo)); + + vp3054_i2c->adap.dev.parent = &dev->pci->dev; + strlcpy(vp3054_i2c->adap.name, core->name, + sizeof(vp3054_i2c->adap.name)); + vp3054_i2c->adap.owner = THIS_MODULE; + vp3054_i2c->algo.data = dev; + i2c_set_adapdata(&vp3054_i2c->adap, dev); + vp3054_i2c->adap.algo_data = &vp3054_i2c->algo; + + vp3054_bit_setscl(dev,1); + vp3054_bit_setsda(dev,1); + + rc = i2c_bit_add_bus(&vp3054_i2c->adap); + if (0 != rc) { + printk("%s: vp3054_i2c register FAILED\n", core->name); + + kfree(dev->vp3054); + dev->vp3054 = NULL; + } + + return rc; +} + +void vp3054_i2c_remove(struct cx8802_dev *dev) +{ + struct vp3054_i2c_state *vp3054_i2c = dev->vp3054; + + if (vp3054_i2c == NULL || + dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + return; + + i2c_del_adapter(&vp3054_i2c->adap); + kfree(vp3054_i2c); +} + +EXPORT_SYMBOL(vp3054_i2c_probe); +EXPORT_SYMBOL(vp3054_i2c_remove); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vp3054-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vp3054-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vp3054-i2c.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/cx88-vp3054-i2c.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,41 @@ +/* + + cx88-vp3054-i2c.h -- support for the secondary I2C bus of the + DNTV Live! DVB-T Pro (VP-3054), wired as: + GPIO[0] -> SCL, GPIO[1] -> SDA + + (c) 2005 Chris Pascoe + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/* ----------------------------------------------------------------------- */ +struct vp3054_i2c_state { + struct i2c_adapter adap; + struct i2c_algo_bit_data algo; + u32 state; +}; + +/* ----------------------------------------------------------------------- */ +#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) +int vp3054_i2c_probe(struct cx8802_dev *dev); +void vp3054_i2c_remove(struct cx8802_dev *dev); +#else +static inline int vp3054_i2c_probe(struct cx8802_dev *dev) +{ return 0; } +static inline void vp3054_i2c_remove(struct cx8802_dev *dev) +{ } +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,86 @@ +config VIDEO_CX88 + tristate "Conexant 2388x (bt878 successor) support" + depends on VIDEO_DEV && PCI && I2C && RC_CORE + select I2C_ALGOBIT + select VIDEO_BTCX + select VIDEOBUF_DMA_SG + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO + ---help--- + This is a video4linux driver for Conexant 2388x based + TV cards. + + To compile this driver as a module, choose M here: the + module will be called cx8800 + +config VIDEO_CX88_ALSA + tristate "Conexant 2388x DMA audio support" + depends on VIDEO_CX88 && SND + select SND_PCM + ---help--- + This is a video4linux driver for direct (DMA) audio on + Conexant 2388x based TV cards using ALSA. + + It only works with boards with function 01 enabled. + To check if your board supports, use lspci -n. + If supported, you should see 14f1:8801 or 14f1:8811 + PCI device. + + To compile this driver as a module, choose M here: the + module will be called cx88-alsa. + +config VIDEO_CX88_BLACKBIRD + tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" + depends on VIDEO_CX88 + select VIDEO_CX2341X + ---help--- + This adds support for MPEG encoder cards based on the + Blackbird reference design, using the Conexant 2388x + and 23416 chips. + + To compile this driver as a module, choose M here: the + module will be called cx88-blackbird. + +config VIDEO_CX88_DVB + tristate "DVB/ATSC Support for cx2388x based TV cards" + depends on VIDEO_CX88 && DVB_CORE + select VIDEOBUF_DVB + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_OR51132 if !DVB_FE_CUSTOMISE + select DVB_CX22702 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_NXT200X if !DVB_FE_CUSTOMISE + select DVB_CX24123 if !DVB_FE_CUSTOMISE + select DVB_ISL6421 if !DVB_FE_CUSTOMISE + select DVB_S5H1411 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + ---help--- + This adds support for DVB/ATSC cards based on the + Conexant 2388x chip. + + To compile this driver as a module, choose M here: the + module will be called cx88-dvb. + +config VIDEO_CX88_MPEG + tristate + depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD + default y + +config VIDEO_CX88_VP3054 + tristate "VP-3054 Secondary I2C Bus Support" + default m + depends on VIDEO_CX88_DVB && DVB_MT352 + ---help--- + This adds DVB-T support for cards based on the + Conexant 2388x chip and the MT352 demodulator, + which also require support for the VP-3054 + Secondary I2C bus, such at DNTV Live! DVB-T Pro. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/cx88/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,16 @@ +cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \ + cx88-dsp.o cx88-input.o +cx8800-objs := cx88-video.o cx88-vbi.o +cx8802-objs := cx88-mpeg.o + +obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o +obj-$(CONFIG_VIDEO_CX88_MPEG) += cx8802.o +obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o +obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o +obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o +obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/ccdc_hw_device.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/ccdc_hw_device.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/ccdc_hw_device.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/ccdc_hw_device.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * ccdc device API + */ +#ifndef _CCDC_HW_DEVICE_H +#define _CCDC_HW_DEVICE_H + +#ifdef __KERNEL__ +#include +#include +#include +#include + +/* + * ccdc hw operations + */ +struct ccdc_hw_ops { + /* Pointer to initialize function to initialize ccdc device */ + int (*open) (struct device *dev); + /* Pointer to deinitialize function */ + int (*close) (struct device *dev); + /* set ccdc base address */ + void (*set_ccdc_base)(void *base, int size); + /* Pointer to function to enable or disable ccdc */ + void (*enable) (int en); + /* reset sbl. only for 6446 */ + void (*reset) (void); + /* enable output to sdram */ + void (*enable_out_to_sdram) (int en); + /* Pointer to function to set hw parameters */ + int (*set_hw_if_params) (struct vpfe_hw_if_param *param); + /* get interface parameters */ + int (*get_hw_if_params) (struct vpfe_hw_if_param *param); + /* + * Pointer to function to set parameters. Used + * for implementing VPFE_S_CCDC_PARAMS + */ + int (*set_params) (void *params); + /* + * Pointer to function to get parameter. Used + * for implementing VPFE_G_CCDC_PARAMS + */ + int (*get_params) (void *params); + /* Pointer to function to configure ccdc */ + int (*configure) (void); + + /* Pointer to function to set buffer type */ + int (*set_buftype) (enum ccdc_buftype buf_type); + /* Pointer to function to get buffer type */ + enum ccdc_buftype (*get_buftype) (void); + /* Pointer to function to set frame format */ + int (*set_frame_format) (enum ccdc_frmfmt frm_fmt); + /* Pointer to function to get frame format */ + enum ccdc_frmfmt (*get_frame_format) (void); + /* enumerate hw pix formats */ + int (*enum_pix)(u32 *hw_pix, int i); + /* Pointer to function to set buffer type */ + u32 (*get_pixel_format) (void); + /* Pointer to function to get pixel format. */ + int (*set_pixel_format) (u32 pixfmt); + /* Pointer to function to set image window */ + int (*set_image_window) (struct v4l2_rect *win); + /* Pointer to function to set image window */ + void (*get_image_window) (struct v4l2_rect *win); + /* Pointer to function to get line length */ + unsigned int (*get_line_length) (void); + + /* Query CCDC control IDs */ + int (*queryctrl)(struct v4l2_queryctrl *qctrl); + /* Set CCDC control */ + int (*set_control)(struct v4l2_control *ctrl); + /* Get CCDC control */ + int (*get_control)(struct v4l2_control *ctrl); + + /* Pointer to function to set frame buffer address */ + void (*setfbaddr) (unsigned long addr); + /* Pointer to function to get field id */ + int (*getfid) (void); +}; + +struct ccdc_hw_device { + /* ccdc device name */ + char name[32]; + /* module owner */ + struct module *owner; + /* hw ops */ + struct ccdc_hw_ops hw_ops; +}; + +/* Used by CCDC module to register & unregister with vpfe capture driver */ +int vpfe_register_ccdc_device(struct ccdc_hw_device *dev); +void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev); + +#endif +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm355_ccdc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm355_ccdc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm355_ccdc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm355_ccdc.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1082 @@ +/* + * Copyright (C) 2005-2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * CCDC hardware module for DM355 + * ------------------------------ + * + * This module is for configuring DM355 CCD controller of VPFE to capture + * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules + * such as Defect Pixel Correction, Color Space Conversion etc to + * pre-process the Bayer RGB data, before writing it to SDRAM. This + * module also allows application to configure individual + * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. + * To do so, application include dm355_ccdc.h and vpfe_capture.h header + * files. The setparams() API is called by vpfe_capture driver + * to configure module parameters + * + * TODO: 1) Raw bayer parameter settings and bayer capture + * 2) Split module parameter structure to module specific ioctl structs + * 3) add support for lense shading correction + * 4) investigate if enum used for user space type definition + * to be replaced by #defines or integer + */ +#include +#include +#include +#include +#include + +#include +#include + +#include "dm355_ccdc_regs.h" +#include "ccdc_hw_device.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CCDC Driver for DM355"); +MODULE_AUTHOR("Texas Instruments"); + +static struct ccdc_oper_config { + struct device *dev; + /* CCDC interface type */ + enum vpfe_hw_if_type if_type; + /* Raw Bayer configuration */ + struct ccdc_params_raw bayer; + /* YCbCr configuration */ + struct ccdc_params_ycbcr ycbcr; + /* Master clock */ + struct clk *mclk; + /* slave clock */ + struct clk *sclk; + /* ccdc base address */ + void __iomem *base_addr; +} ccdc_cfg = { + /* Raw configurations */ + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = CCDC_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .gain = { + .r_ye = 256, + .gb_g = 256, + .gr_cy = 256, + .b_mg = 256 + }, + .config_params = { + .datasft = 2, + .mfilt1 = CCDC_NO_MEDIAN_FILTER1, + .mfilt2 = CCDC_NO_MEDIAN_FILTER2, + .alaw = { + .gama_wd = 2, + }, + .blk_clamp = { + .sample_pixel = 1, + .dc_sub = 25 + }, + .col_pat_field0 = { + .olop = CCDC_GREEN_BLUE, + .olep = CCDC_BLUE, + .elop = CCDC_RED, + .elep = CCDC_GREEN_RED + }, + .col_pat_field1 = { + .olop = CCDC_GREEN_BLUE, + .olep = CCDC_BLUE, + .elop = CCDC_RED, + .elep = CCDC_GREEN_RED + }, + }, + }, + /* YCbCr configuration */ + .ycbcr = { + .win = CCDC_WIN_PAL, + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .bt656_enable = 1, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED + }, +}; + + +/* Raw Bayer formats */ +static u32 ccdc_raw_bayer_pix_formats[] = + {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; + +/* Raw YUV formats */ +static u32 ccdc_raw_yuv_pix_formats[] = + {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; + +/* register access routines */ +static inline u32 regr(u32 offset) +{ + return __raw_readl(ccdc_cfg.base_addr + offset); +} + +static inline void regw(u32 val, u32 offset) +{ + __raw_writel(val, ccdc_cfg.base_addr + offset); +} + +static void ccdc_enable(int en) +{ + unsigned int temp; + temp = regr(SYNCEN); + temp &= (~CCDC_SYNCEN_VDHDEN_MASK); + temp |= (en & CCDC_SYNCEN_VDHDEN_MASK); + regw(temp, SYNCEN); +} + +static void ccdc_enable_output_to_sdram(int en) +{ + unsigned int temp; + temp = regr(SYNCEN); + temp &= (~(CCDC_SYNCEN_WEN_MASK)); + temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK); + regw(temp, SYNCEN); +} + +static void ccdc_config_gain_offset(void) +{ + /* configure gain */ + regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); + regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); + regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); + regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); + /* configure offset */ + regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); +} + +/* + * ccdc_restore_defaults() + * This function restore power on defaults in the ccdc registers + */ +static int ccdc_restore_defaults(void) +{ + int i; + + dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); + /* set all registers to zero */ + for (i = 0; i <= CCDC_REG_LAST; i += 4) + regw(0, i); + + /* now override the values with power on defaults in registers */ + regw(MODESET_DEFAULT, MODESET); + /* no culling support */ + regw(CULH_DEFAULT, CULH); + regw(CULV_DEFAULT, CULV); + /* Set default Gain and Offset */ + ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; + ccdc_config_gain_offset(); + regw(OUTCLIP_DEFAULT, OUTCLIP); + regw(LSCCFG2_DEFAULT, LSCCFG2); + /* select ccdc input */ + if (vpss_select_ccdc_source(VPSS_CCDCIN)) { + dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); + return -EFAULT; + } + /* select ccdc clock */ + if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { + dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); + return -EFAULT; + } + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); + return 0; +} + +static int ccdc_open(struct device *device) +{ + return ccdc_restore_defaults(); +} + +static int ccdc_close(struct device *device) +{ + /* disable clock */ + vpss_enable_clock(VPSS_CCDC_CLOCK, 0); + /* do nothing for now */ + return 0; +} +/* + * ccdc_setwin() + * This function will configure the window size to + * be capture in CCDC reg. + */ +static void ccdc_setwin(struct v4l2_rect *image_win, + enum ccdc_frmfmt frm_fmt, int ppc) +{ + int horz_start, horz_nr_pixels; + int vert_start, vert_nr_lines; + int mid_img = 0; + + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); + + /* + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + horz_start = image_win->left << (ppc - 1); + horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; + + /* Writing the horizontal info into the registers */ + regw(horz_start, SPH); + regw(horz_nr_pixels, NPH); + vert_start = image_win->top; + + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + vert_nr_lines = (image_win->height >> 1) - 1; + vert_start >>= 1; + /* Since first line doesn't have any data */ + vert_start += 1; + /* configure VDINT0 and VDINT1 */ + regw(vert_start, VDINT0); + } else { + /* Since first line doesn't have any data */ + vert_start += 1; + vert_nr_lines = image_win->height - 1; + /* configure VDINT0 and VDINT1 */ + mid_img = vert_start + (image_win->height / 2); + regw(vert_start, VDINT0); + regw(mid_img, VDINT1); + } + regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0); + regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); + regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); +} + +static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) +{ + if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT || + ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) { + dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n"); + return -EINVAL; + } + + if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 || + ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) { + dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n"); + return -EINVAL; + } + + if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 || + ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) { + dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n"); + return -EINVAL; + } + + if ((ccdcparam->med_filt_thres < 0) || + (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { + dev_dbg(ccdc_cfg.dev, + "Invalid value of median filter thresold\n"); + return -EINVAL; + } + + if (ccdcparam->data_sz < CCDC_DATA_16BITS || + ccdcparam->data_sz > CCDC_DATA_8BITS) { + dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n"); + return -EINVAL; + } + + if (ccdcparam->alaw.enable) { + if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || + ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { + dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); + return -EINVAL; + } + } + + if (ccdcparam->blk_clamp.b_clamp_enable) { + if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS || + ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) { + dev_dbg(ccdc_cfg.dev, + "Invalid value of sample pixel\n"); + return -EINVAL; + } + if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES || + ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) { + dev_dbg(ccdc_cfg.dev, + "Invalid value of sample lines\n"); + return -EINVAL; + } + } + return 0; +} + +/* Parameter operations */ +static int ccdc_set_params(void __user *params) +{ + struct ccdc_config_params_raw ccdc_raw_params; + int x; + + /* only raw module parameters can be set through the IOCTL */ + if (ccdc_cfg.if_type != VPFE_RAW_BAYER) + return -EINVAL; + + x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); + if (x) { + dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc" + "params, %d\n", x); + return -EFAULT; + } + + if (!validate_ccdc_param(&ccdc_raw_params)) { + memcpy(&ccdc_cfg.bayer.config_params, + &ccdc_raw_params, + sizeof(ccdc_raw_params)); + return 0; + } + return -EINVAL; +} + +/* This function will configure CCDC for YCbCr video capture */ +static void ccdc_config_ycbcr(void) +{ + struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; + u32 temp; + + /* first set the CCDC power on defaults values in all registers */ + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); + ccdc_restore_defaults(); + + /* configure pixel format & video frame format */ + temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) << + CCDC_INPUT_MODE_SHIFT) | + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << + CCDC_FRM_FMT_SHIFT)); + + /* setup BT.656 sync mode */ + if (params->bt656_enable) { + regw(CCDC_REC656IF_BT656_EN, REC656IF); + /* + * configure the FID, VD, HD pin polarity fld,hd pol positive, + * vd negative, 8-bit pack mode + */ + temp |= CCDC_VD_POL_NEGATIVE; + } else { /* y/c external sync mode */ + temp |= (((params->fid_pol & CCDC_FID_POL_MASK) << + CCDC_FID_POL_SHIFT) | + ((params->hd_pol & CCDC_HD_POL_MASK) << + CCDC_HD_POL_SHIFT) | + ((params->vd_pol & CCDC_VD_POL_MASK) << + CCDC_VD_POL_SHIFT)); + } + + /* pack the data to 8-bit */ + temp |= CCDC_DATA_PACK_ENABLE; + + regw(temp, MODESET); + + /* configure video window */ + ccdc_setwin(¶ms->win, params->frm_fmt, 2); + + /* configure the order of y cb cr in SD-RAM */ + temp = (params->pix_order << CCDC_Y8POS_SHIFT); + temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC; + regw(temp, CCDCFG); + + /* + * configure the horizontal line offset. This is done by rounding up + * width to a multiple of 16 pixels and multiply by two to account for + * y:cb:cr 4:2:2 data + */ + regw(((params->win.width * 2 + 31) >> 5), HSIZE); + + /* configure the memory line offset */ + if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { + /* two fields are interleaved in memory */ + regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); + } + + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); +} + +/* + * ccdc_config_black_clamp() + * configure parameters for Optical Black Clamp + */ +static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) +{ + u32 val; + + if (!bclamp->b_clamp_enable) { + /* configure DCSub */ + regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB); + regw(0x0000, CLAMP); + return; + } + /* Enable the Black clamping, set sample lines and pixels */ + val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) | + ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << + CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE; + regw(val, CLAMP); + + /* If Black clamping is enable then make dcsub 0 */ + val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK) + << CCDC_NUM_LINE_CALC_SHIFT; + regw(val, DCSUB); +} + +/* + * ccdc_config_black_compense() + * configure parameters for Black Compensation + */ +static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) +{ + u32 val; + + val = (bcomp->b & CCDC_BLK_COMP_MASK) | + ((bcomp->gb & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_GB_COMP_SHIFT); + regw(val, BLKCMP1); + + val = ((bcomp->gr & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_GR_COMP_SHIFT) | + ((bcomp->r & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_R_COMP_SHIFT); + regw(val, BLKCMP0); +} + +/* + * ccdc_write_dfc_entry() + * write an entry in the dfc table. + */ +int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) +{ +/* TODO This is to be re-visited and adjusted */ +#define DFC_WRITE_WAIT_COUNT 1000 + u32 val, count = DFC_WRITE_WAIT_COUNT; + + regw(dfc->dft_corr_vert[index], DFCMEM0); + regw(dfc->dft_corr_horz[index], DFCMEM1); + regw(dfc->dft_corr_sub1[index], DFCMEM2); + regw(dfc->dft_corr_sub2[index], DFCMEM3); + regw(dfc->dft_corr_sub3[index], DFCMEM4); + /* set WR bit to write */ + val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK; + regw(val, DFCMEMCTL); + + /* + * Assume, it is very short. If we get an error, we need to + * adjust this value + */ + while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK) + count--; + /* + * TODO We expect the count to be non-zero to be successful. Adjust + * the count if write requires more time + */ + + if (count) { + dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); + return -1; + } + return 0; +} + +/* + * ccdc_config_vdfc() + * configure parameters for Vertical Defect Correction + */ +static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc) +{ + u32 val; + int i; + + /* Configure General Defect Correction. The table used is from IPIPE */ + val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; + + /* Configure Vertical Defect Correction if needed */ + if (!dfc->ver_dft_en) { + /* Enable only General Defect Correction */ + regw(val, DFCCTL); + return 0; + } + + if (dfc->table_size > CCDC_DFT_TABLE_SIZE) + return -EINVAL; + + val |= CCDC_DFCCTL_VDFC_DISABLE; + val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << + CCDC_DFCCTL_VDFCSL_SHIFT; + val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << + CCDC_DFCCTL_VDFCUDA_SHIFT; + val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << + CCDC_DFCCTL_VDFLSFT_SHIFT; + regw(val , DFCCTL); + + /* clear address ptr to offset 0 */ + val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT; + + /* write defect table entries */ + for (i = 0; i < dfc->table_size; i++) { + /* increment address for non zero index */ + if (i != 0) + val = CCDC_DFCMEMCTL_INC_ADDR; + regw(val, DFCMEMCTL); + if (ccdc_write_dfc_entry(i, dfc) < 0) + return -EFAULT; + } + + /* update saturation level and enable dfc */ + regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); + val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK << + CCDC_DFCCTL_VDFCEN_SHIFT); + regw(val, DFCCTL); + return 0; +} + +/* + * ccdc_config_csc() + * configure parameters for color space conversion + * Each register CSCM0-7 has two values in S8Q5 format. + */ +static void ccdc_config_csc(struct ccdc_csc *csc) +{ + u32 val1, val2; + int i; + + if (!csc->enable) + return; + + /* Enable the CSC sub-module */ + regw(CCDC_CSC_ENABLE, CSCCTL); + + /* Converting the co-eff as per the format of the register */ + for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) { + if ((i % 2) == 0) { + /* CSCM - LSB */ + val1 = (csc->coeff[i].integer & + CCDC_CSC_COEF_INTEG_MASK) + << CCDC_CSC_COEF_INTEG_SHIFT; + /* + * convert decimal part to binary. Use 2 decimal + * precision, user values range from .00 - 0.99 + */ + val1 |= (((csc->coeff[i].decimal & + CCDC_CSC_COEF_DECIMAL_MASK) * + CCDC_CSC_DEC_MAX) / 100); + } else { + + /* CSCM - MSB */ + val2 = (csc->coeff[i].integer & + CCDC_CSC_COEF_INTEG_MASK) + << CCDC_CSC_COEF_INTEG_SHIFT; + val2 |= (((csc->coeff[i].decimal & + CCDC_CSC_COEF_DECIMAL_MASK) * + CCDC_CSC_DEC_MAX) / 100); + val2 <<= CCDC_CSCM_MSB_SHIFT; + val2 |= val1; + regw(val2, (CSCM0 + ((i - 1) << 1))); + } + } +} + +/* + * ccdc_config_color_patterns() + * configure parameters for color patterns + */ +static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, + struct ccdc_col_pat *pat1) +{ + u32 val; + + val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) | + (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) | + (pat1->elop << 12) | (pat1->elep << 14)); + regw(val, COLPTN); +} + +/* This function will configure CCDC for Raw mode image capture */ +static int ccdc_config_raw(void) +{ + struct ccdc_params_raw *params = &ccdc_cfg.bayer; + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int val; + + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); + + /* restore power on defaults to register */ + ccdc_restore_defaults(); + + /* CCDCFG register: + * set CCD Not to swap input since input is RAW data + * set FID detection function to Latch at V-Sync + * set WENLOG - ccdc valid area to AND + * set TRGSEL to WENBIT + * set EXTRG to DISABLE + * disable latching function on VSYNC - shadowed registers + */ + regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | + CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | + CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); + + /* + * Set VDHD direction to input, input type to raw input + * normal data polarity, do not use external WEN + */ + val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL | + CCDC_EXWEN_DISABLE); + + /* + * Configure the vertical sync polarity (MODESET.VDPOL), horizontal + * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL), + * frame format(progressive or interlace), & pixel format (Input mode) + */ + val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | + ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | + ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | + ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT)); + + /* set pack for alaw compression */ + if ((config_params->data_sz == CCDC_DATA_8BITS) || + config_params->alaw.enable) + val |= CCDC_DATA_PACK_ENABLE; + + /* Configure for LPF */ + if (config_params->lpf_enable) + val |= (config_params->lpf_enable & CCDC_LPF_MASK) << + CCDC_LPF_SHIFT; + + /* Configure the data shift */ + val |= (config_params->datasft & CCDC_DATASFT_MASK) << + CCDC_DATASFT_SHIFT; + regw(val , MODESET); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); + + /* Configure the Median Filter threshold */ + regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); + + /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */ + val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT | + CCDC_CFA_MOSAIC; + + /* Enable and configure aLaw register if needed */ + if (config_params->alaw.enable) { + val |= (CCDC_ALAW_ENABLE | + ((config_params->alaw.gama_wd & + CCDC_ALAW_GAMA_WD_MASK) << + CCDC_GAMMAWD_INPUT_SHIFT)); + } + + /* Configure Median filter1 & filter2 */ + val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) | + (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); + + regw(val, GAMMAWD); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); + + /* configure video window */ + ccdc_setwin(¶ms->win, params->frm_fmt, 1); + + /* Optical Clamp Averaging */ + ccdc_config_black_clamp(&config_params->blk_clamp); + + /* Black level compensation */ + ccdc_config_black_compense(&config_params->blk_comp); + + /* Vertical Defect Correction if needed */ + if (ccdc_config_vdfc(&config_params->vertical_dft) < 0) + return -EFAULT; + + /* color space conversion */ + ccdc_config_csc(&config_params->csc); + + /* color pattern */ + ccdc_config_color_patterns(&config_params->col_pat_field0, + &config_params->col_pat_field1); + + /* Configure the Gain & offset control */ + ccdc_config_gain_offset(); + + dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); + + /* Configure DATAOFST register */ + val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << + CCDC_DATAOFST_H_SHIFT; + val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) << + CCDC_DATAOFST_V_SHIFT; + regw(val, DATAOFST); + + /* configuring HSIZE register */ + val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) << + CCDC_HSIZE_FLIP_SHIFT; + + /* If pack 8 is enable then 1 pixel will take 1 byte */ + if ((config_params->data_sz == CCDC_DATA_8BITS) || + config_params->alaw.enable) { + val |= (((params->win.width) + 31) >> 5) & + CCDC_HSIZE_VAL_MASK; + + /* adjust to multiple of 32 */ + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", + (((params->win.width) + 31) >> 5) & + CCDC_HSIZE_VAL_MASK); + } else { + /* else one pixel will take 2 byte */ + val |= (((params->win.width * 2) + 31) >> 5) & + CCDC_HSIZE_VAL_MASK; + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", + (((params->win.width * 2) + 31) >> 5) & + CCDC_HSIZE_VAL_MASK); + } + regw(val, HSIZE); + + /* Configure SDOFST register */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_enable) { + /* For interlace inverse mode */ + regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", + CCDC_SDOFST_INTERLACE_INVERSE); + } else { + /* For interlace non inverse mode */ + regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", + CCDC_SDOFST_INTERLACE_NORMAL); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + if (params->image_invert_enable) { + /* For progessive inverse mode */ + regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", + CCDC_SDOFST_PROGRESSIVE_INVERSE); + } else { + /* For progessive non inverse mode */ + regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", + CCDC_SDOFST_PROGRESSIVE_NORMAL); + } + } + dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); + return 0; +} + +static int ccdc_configure(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_config_raw(); + else + ccdc_config_ycbcr(); + return 0; +} + +static int ccdc_set_buftype(enum ccdc_buftype buf_type) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.buf_type = buf_type; + else + ccdc_cfg.ycbcr.buf_type = buf_type; + return 0; +} +static enum ccdc_buftype ccdc_get_buftype(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.buf_type; + return ccdc_cfg.ycbcr.buf_type; +} + +static int ccdc_enum_pix(u32 *pix, int i) +{ + int ret = -EINVAL; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { + *pix = ccdc_raw_bayer_pix_formats[i]; + ret = 0; + } + } else { + if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { + *pix = ccdc_raw_yuv_pix_formats[i]; + ret = 0; + } + } + return ret; +} + +static int ccdc_set_pixel_format(u32 pixfmt) +{ + struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + if (pixfmt == V4L2_PIX_FMT_SBGGR8) + alaw->enable = 1; + else if (pixfmt != V4L2_PIX_FMT_SBGGR16) + return -EINVAL; + } else { + if (pixfmt == V4L2_PIX_FMT_YUYV) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + else if (pixfmt == V4L2_PIX_FMT_UYVY) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + else + return -EINVAL; + } + return 0; +} +static u32 ccdc_get_pixel_format(void) +{ + struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; + u32 pixfmt; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + if (alaw->enable) + pixfmt = V4L2_PIX_FMT_SBGGR8; + else + pixfmt = V4L2_PIX_FMT_SBGGR16; + else { + if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + return pixfmt; +} +static int ccdc_set_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.win = *win; + else + ccdc_cfg.ycbcr.win = *win; + return 0; +} + +static void ccdc_get_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + *win = ccdc_cfg.bayer.win; + else + *win = ccdc_cfg.ycbcr.win; +} + +static unsigned int ccdc_get_line_length(void) +{ + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int len; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if ((config_params->alaw.enable) || + (config_params->data_sz == CCDC_DATA_8BITS)) + len = ccdc_cfg.bayer.win.width; + else + len = ccdc_cfg.bayer.win.width * 2; + } else + len = ccdc_cfg.ycbcr.win.width * 2; + return ALIGN(len, 32); +} + +static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.frm_fmt = frm_fmt; + else + ccdc_cfg.ycbcr.frm_fmt = frm_fmt; + return 0; +} + +static enum ccdc_frmfmt ccdc_get_frame_format(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.frm_fmt; + else + return ccdc_cfg.ycbcr.frm_fmt; +} + +static int ccdc_getfid(void) +{ + return (regr(MODESET) >> 15) & 1; +} + +/* misc operations */ +static inline void ccdc_setfbaddr(unsigned long addr) +{ + regw((addr >> 21) & 0x007f, STADRH); + regw((addr >> 5) & 0x0ffff, STADRL); +} + +static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) +{ + ccdc_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_YCBCR_SYNC_16: + case VPFE_YCBCR_SYNC_8: + ccdc_cfg.ycbcr.vd_pol = params->vdpol; + ccdc_cfg.ycbcr.hd_pol = params->hdpol; + break; + default: + /* TODO add support for raw bayer here */ + return -EINVAL; + } + return 0; +} + +static struct ccdc_hw_device ccdc_hw_dev = { + .name = "DM355 CCDC", + .owner = THIS_MODULE, + .hw_ops = { + .open = ccdc_open, + .close = ccdc_close, + .enable = ccdc_enable, + .enable_out_to_sdram = ccdc_enable_output_to_sdram, + .set_hw_if_params = ccdc_set_hw_if_params, + .set_params = ccdc_set_params, + .configure = ccdc_configure, + .set_buftype = ccdc_set_buftype, + .get_buftype = ccdc_get_buftype, + .enum_pix = ccdc_enum_pix, + .set_pixel_format = ccdc_set_pixel_format, + .get_pixel_format = ccdc_get_pixel_format, + .set_frame_format = ccdc_set_frame_format, + .get_frame_format = ccdc_get_frame_format, + .set_image_window = ccdc_set_image_window, + .get_image_window = ccdc_get_image_window, + .get_line_length = ccdc_get_line_length, + .setfbaddr = ccdc_setfbaddr, + .getfid = ccdc_getfid, + }, +}; + +static int __init dm355_ccdc_probe(struct platform_device *pdev) +{ + void (*setup_pinmux)(void); + struct resource *res; + int status = 0; + + /* + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&ccdc_hw_dev); + if (status < 0) + return status; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + status = -ENODEV; + goto fail_nores; + } + + res = request_mem_region(res->start, resource_size(res), res->name); + if (!res) { + status = -EBUSY; + goto fail_nores; + } + + ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); + if (!ccdc_cfg.base_addr) { + status = -ENOMEM; + goto fail_nomem; + } + + /* Get and enable Master clock */ + ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); + if (IS_ERR(ccdc_cfg.mclk)) { + status = PTR_ERR(ccdc_cfg.mclk); + goto fail_nomap; + } + if (clk_enable(ccdc_cfg.mclk)) { + status = -ENODEV; + goto fail_mclk; + } + + /* Get and enable Slave clock */ + ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); + if (IS_ERR(ccdc_cfg.sclk)) { + status = PTR_ERR(ccdc_cfg.sclk); + goto fail_mclk; + } + if (clk_enable(ccdc_cfg.sclk)) { + status = -ENODEV; + goto fail_sclk; + } + + /* Platform data holds setup_pinmux function ptr */ + if (NULL == pdev->dev.platform_data) { + status = -ENODEV; + goto fail_sclk; + } + setup_pinmux = pdev->dev.platform_data; + /* + * setup Mux configuration for ccdc which may be different for + * different SoCs using this CCDC + */ + setup_pinmux(); + ccdc_cfg.dev = &pdev->dev; + printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); + return 0; +fail_sclk: + clk_put(ccdc_cfg.sclk); +fail_mclk: + clk_put(ccdc_cfg.mclk); +fail_nomap: + iounmap(ccdc_cfg.base_addr); +fail_nomem: + release_mem_region(res->start, resource_size(res)); +fail_nores: + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return status; +} + +static int dm355_ccdc_remove(struct platform_device *pdev) +{ + struct resource *res; + + clk_put(ccdc_cfg.mclk); + clk_put(ccdc_cfg.sclk); + iounmap(ccdc_cfg.base_addr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return 0; +} + +static struct platform_driver dm355_ccdc_driver = { + .driver = { + .name = "dm355_ccdc", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(dm355_ccdc_remove), + .probe = dm355_ccdc_probe, +}; + +static int __init dm355_ccdc_init(void) +{ + return platform_driver_register(&dm355_ccdc_driver); +} + +static void __exit dm355_ccdc_exit(void) +{ + platform_driver_unregister(&dm355_ccdc_driver); +} + +module_init(dm355_ccdc_init); +module_exit(dm355_ccdc_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm355_ccdc_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm355_ccdc_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm355_ccdc_regs.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm355_ccdc_regs.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2005-2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + */ +#ifndef _DM355_CCDC_REGS_H +#define _DM355_CCDC_REGS_H + +/**************************************************************************\ +* Register OFFSET Definitions +\**************************************************************************/ +#define SYNCEN 0x00 +#define MODESET 0x04 +#define HDWIDTH 0x08 +#define VDWIDTH 0x0c +#define PPLN 0x10 +#define LPFR 0x14 +#define SPH 0x18 +#define NPH 0x1c +#define SLV0 0x20 +#define SLV1 0x24 +#define NLV 0x28 +#define CULH 0x2c +#define CULV 0x30 +#define HSIZE 0x34 +#define SDOFST 0x38 +#define STADRH 0x3c +#define STADRL 0x40 +#define CLAMP 0x44 +#define DCSUB 0x48 +#define COLPTN 0x4c +#define BLKCMP0 0x50 +#define BLKCMP1 0x54 +#define MEDFILT 0x58 +#define RYEGAIN 0x5c +#define GRCYGAIN 0x60 +#define GBGGAIN 0x64 +#define BMGGAIN 0x68 +#define OFFSET 0x6c +#define OUTCLIP 0x70 +#define VDINT0 0x74 +#define VDINT1 0x78 +#define RSV0 0x7c +#define GAMMAWD 0x80 +#define REC656IF 0x84 +#define CCDCFG 0x88 +#define FMTCFG 0x8c +#define FMTPLEN 0x90 +#define FMTSPH 0x94 +#define FMTLNH 0x98 +#define FMTSLV 0x9c +#define FMTLNV 0xa0 +#define FMTRLEN 0xa4 +#define FMTHCNT 0xa8 +#define FMT_ADDR_PTR_B 0xac +#define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i * 4)) +#define FMTPGM_VF0 0xcc +#define FMTPGM_VF1 0xd0 +#define FMTPGM_AP0 0xd4 +#define FMTPGM_AP1 0xd8 +#define FMTPGM_AP2 0xdc +#define FMTPGM_AP3 0xe0 +#define FMTPGM_AP4 0xe4 +#define FMTPGM_AP5 0xe8 +#define FMTPGM_AP6 0xec +#define FMTPGM_AP7 0xf0 +#define LSCCFG1 0xf4 +#define LSCCFG2 0xf8 +#define LSCH0 0xfc +#define LSCV0 0x100 +#define LSCKH 0x104 +#define LSCKV 0x108 +#define LSCMEMCTL 0x10c +#define LSCMEMD 0x110 +#define LSCMEMQ 0x114 +#define DFCCTL 0x118 +#define DFCVSAT 0x11c +#define DFCMEMCTL 0x120 +#define DFCMEM0 0x124 +#define DFCMEM1 0x128 +#define DFCMEM2 0x12c +#define DFCMEM3 0x130 +#define DFCMEM4 0x134 +#define CSCCTL 0x138 +#define CSCM0 0x13c +#define CSCM1 0x140 +#define CSCM2 0x144 +#define CSCM3 0x148 +#define CSCM4 0x14c +#define CSCM5 0x150 +#define CSCM6 0x154 +#define CSCM7 0x158 +#define DATAOFST 0x15c +#define CCDC_REG_LAST DATAOFST +/************************************************************** +* Define for various register bit mask and shifts for CCDC +* +**************************************************************/ +#define CCDC_RAW_IP_MODE 0 +#define CCDC_VDHDOUT_INPUT 0 +#define CCDC_YCINSWP_RAW (0 << 4) +#define CCDC_EXWEN_DISABLE 0 +#define CCDC_DATAPOL_NORMAL 0 +#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0 +#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6) +#define CCDC_CCDCFG_WENLOG_AND 0 +#define CCDC_CCDCFG_TRGSEL_WEN 0 +#define CCDC_CCDCFG_EXTRG_DISABLE 0 +#define CCDC_CFA_MOSAIC 0 +#define CCDC_Y8POS_SHIFT 11 + +#define CCDC_VDC_DFCVSAT_MASK 0x3fff +#define CCDC_DATAOFST_MASK 0x0ff +#define CCDC_DATAOFST_H_SHIFT 0 +#define CCDC_DATAOFST_V_SHIFT 8 +#define CCDC_GAMMAWD_CFA_MASK 1 +#define CCDC_GAMMAWD_CFA_SHIFT 5 +#define CCDC_GAMMAWD_INPUT_SHIFT 2 +#define CCDC_FID_POL_MASK 1 +#define CCDC_FID_POL_SHIFT 4 +#define CCDC_HD_POL_MASK 1 +#define CCDC_HD_POL_SHIFT 3 +#define CCDC_VD_POL_MASK 1 +#define CCDC_VD_POL_SHIFT 2 +#define CCDC_VD_POL_NEGATIVE (1 << 2) +#define CCDC_FRM_FMT_MASK 1 +#define CCDC_FRM_FMT_SHIFT 7 +#define CCDC_DATA_SZ_MASK 7 +#define CCDC_DATA_SZ_SHIFT 8 +#define CCDC_VDHDOUT_MASK 1 +#define CCDC_VDHDOUT_SHIFT 0 +#define CCDC_EXWEN_MASK 1 +#define CCDC_EXWEN_SHIFT 5 +#define CCDC_INPUT_MODE_MASK 3 +#define CCDC_INPUT_MODE_SHIFT 12 +#define CCDC_PIX_FMT_MASK 3 +#define CCDC_PIX_FMT_SHIFT 12 +#define CCDC_DATAPOL_MASK 1 +#define CCDC_DATAPOL_SHIFT 6 +#define CCDC_WEN_ENABLE (1 << 1) +#define CCDC_VDHDEN_ENABLE (1 << 16) +#define CCDC_LPF_ENABLE (1 << 14) +#define CCDC_ALAW_ENABLE 1 +#define CCDC_ALAW_GAMA_WD_MASK 7 +#define CCDC_REC656IF_BT656_EN 3 + +#define CCDC_FMTCFG_FMTMODE_MASK 3 +#define CCDC_FMTCFG_FMTMODE_SHIFT 1 +#define CCDC_FMTCFG_LNUM_MASK 3 +#define CCDC_FMTCFG_LNUM_SHIFT 4 +#define CCDC_FMTCFG_ADDRINC_MASK 7 +#define CCDC_FMTCFG_ADDRINC_SHIFT 8 + +#define CCDC_CCDCFG_FIDMD_SHIFT 6 +#define CCDC_CCDCFG_WENLOG_SHIFT 8 +#define CCDC_CCDCFG_TRGSEL_SHIFT 9 +#define CCDC_CCDCFG_EXTRG_SHIFT 10 +#define CCDC_CCDCFG_MSBINVI_SHIFT 13 + +#define CCDC_HSIZE_FLIP_SHIFT 12 +#define CCDC_HSIZE_FLIP_MASK 1 +#define CCDC_HSIZE_VAL_MASK 0xFFF +#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 +#define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D +#define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D +#define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000 +#define CCDC_SDOFST_PROGRESSIVE_NORMAL 0 +#define CCDC_START_PX_HOR_MASK 0x7FFF +#define CCDC_NUM_PX_HOR_MASK 0x7FFF +#define CCDC_START_VER_ONE_MASK 0x7FFF +#define CCDC_START_VER_TWO_MASK 0x7FFF +#define CCDC_NUM_LINES_VER 0x7FFF + +#define CCDC_BLK_CLAMP_ENABLE (1 << 15) +#define CCDC_BLK_SGAIN_MASK 0x1F +#define CCDC_BLK_ST_PXL_MASK 0x1FFF +#define CCDC_BLK_SAMPLE_LN_MASK 3 +#define CCDC_BLK_SAMPLE_LN_SHIFT 13 + +#define CCDC_NUM_LINE_CALC_MASK 3 +#define CCDC_NUM_LINE_CALC_SHIFT 14 + +#define CCDC_BLK_DC_SUB_MASK 0x3FFF +#define CCDC_BLK_COMP_MASK 0xFF +#define CCDC_BLK_COMP_GB_COMP_SHIFT 8 +#define CCDC_BLK_COMP_GR_COMP_SHIFT 0 +#define CCDC_BLK_COMP_R_COMP_SHIFT 8 +#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) +#define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15) +#define CCDC_FPC_ENABLE (1 << 15) +#define CCDC_FPC_FPC_NUM_MASK 0x7FFF +#define CCDC_DATA_PACK_ENABLE (1 << 11) +#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF +#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF +#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 +#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF +#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF +#define CCDC_FMT_VERT_FMTSLV_SHIFT 16 +#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF +#define CCDC_VP_OUT_VERT_NUM_SHIFT 17 +#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF +#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 +#define CCDC_VP_OUT_HORZ_ST_MASK 0xF + +#define CCDC_CSC_COEF_INTEG_MASK 7 +#define CCDC_CSC_COEF_DECIMAL_MASK 0x1f +#define CCDC_CSC_COEF_INTEG_SHIFT 5 +#define CCDC_CSCM_MSB_SHIFT 8 +#define CCDC_CSC_ENABLE 1 +#define CCDC_CSC_DEC_MAX 32 + +#define CCDC_MFILT1_SHIFT 10 +#define CCDC_MFILT2_SHIFT 8 +#define CCDC_MED_FILT_THRESH 0x3FFF +#define CCDC_LPF_MASK 1 +#define CCDC_LPF_SHIFT 14 +#define CCDC_OFFSET_MASK 0x3FF +#define CCDC_DATASFT_MASK 7 +#define CCDC_DATASFT_SHIFT 8 + +#define CCDC_DF_ENABLE 1 + +#define CCDC_FMTPLEN_P0_MASK 0xF +#define CCDC_FMTPLEN_P1_MASK 0xF +#define CCDC_FMTPLEN_P2_MASK 7 +#define CCDC_FMTPLEN_P3_MASK 7 +#define CCDC_FMTPLEN_P0_SHIFT 0 +#define CCDC_FMTPLEN_P1_SHIFT 4 +#define CCDC_FMTPLEN_P2_SHIFT 8 +#define CCDC_FMTPLEN_P3_SHIFT 12 + +#define CCDC_FMTSPH_MASK 0x1FFF +#define CCDC_FMTLNH_MASK 0x1FFF +#define CCDC_FMTSLV_MASK 0x1FFF +#define CCDC_FMTLNV_MASK 0x7FFF +#define CCDC_FMTRLEN_MASK 0x1FFF +#define CCDC_FMTHCNT_MASK 0x1FFF + +#define CCDC_ADP_INIT_MASK 0x1FFF +#define CCDC_ADP_LINE_SHIFT 13 +#define CCDC_ADP_LINE_MASK 3 +#define CCDC_FMTPGN_APTR_MASK 7 + +#define CCDC_DFCCTL_GDFCEN_MASK 1 +#define CCDC_DFCCTL_VDFCEN_MASK 1 +#define CCDC_DFCCTL_VDFC_DISABLE (0 << 4) +#define CCDC_DFCCTL_VDFCEN_SHIFT 4 +#define CCDC_DFCCTL_VDFCSL_MASK 3 +#define CCDC_DFCCTL_VDFCSL_SHIFT 5 +#define CCDC_DFCCTL_VDFCUDA_MASK 1 +#define CCDC_DFCCTL_VDFCUDA_SHIFT 7 +#define CCDC_DFCCTL_VDFLSFT_MASK 3 +#define CCDC_DFCCTL_VDFLSFT_SHIFT 8 +#define CCDC_DFCMEMCTL_DFCMARST_MASK 1 +#define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2 +#define CCDC_DFCMEMCTL_DFCMWR_MASK 1 +#define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0 +#define CCDC_DFCMEMCTL_INC_ADDR (0 << 2) + +#define CCDC_LSCCFG_GFTSF_MASK 7 +#define CCDC_LSCCFG_GFTSF_SHIFT 1 +#define CCDC_LSCCFG_GFTINV_MASK 0xf +#define CCDC_LSCCFG_GFTINV_SHIFT 4 +#define CCDC_LSC_GFTABLE_SEL_MASK 3 +#define CCDC_LSC_GFTABLE_EPEL_SHIFT 8 +#define CCDC_LSC_GFTABLE_OPEL_SHIFT 10 +#define CCDC_LSC_GFTABLE_EPOL_SHIFT 12 +#define CCDC_LSC_GFTABLE_OPOL_SHIFT 14 +#define CCDC_LSC_GFMODE_MASK 3 +#define CCDC_LSC_GFMODE_SHIFT 4 +#define CCDC_LSC_DISABLE 0 +#define CCDC_LSC_ENABLE 1 +#define CCDC_LSC_TABLE1_SLC 0 +#define CCDC_LSC_TABLE2_SLC 1 +#define CCDC_LSC_TABLE3_SLC 2 +#define CCDC_LSC_MEMADDR_RESET (1 << 2) +#define CCDC_LSC_MEMADDR_INCR (0 << 2) +#define CCDC_LSC_FRAC_MASK_T1 0xFF +#define CCDC_LSC_INT_MASK 3 +#define CCDC_LSC_FRAC_MASK 0x3FFF +#define CCDC_LSC_CENTRE_MASK 0x3FFF +#define CCDC_LSC_COEF_MASK 0xff +#define CCDC_LSC_COEFL_SHIFT 0 +#define CCDC_LSC_COEFU_SHIFT 8 +#define CCDC_GAIN_MASK 0x7FF +#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0) +#define CCDC_SYNCEN_WEN_MASK (1 << 1) +#define CCDC_SYNCEN_WEN_SHIFT 1 + +/* Power on Defaults in hardware */ +#define MODESET_DEFAULT 0x200 +#define CULH_DEFAULT 0xFFFF +#define CULV_DEFAULT 0xFF +#define GAIN_DEFAULT 256 +#define OUTCLIP_DEFAULT 0x3FFF +#define LSCCFG2_DEFAULT 0xE + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm644x_ccdc.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm644x_ccdc.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm644x_ccdc.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm644x_ccdc.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1091 @@ +/* + * Copyright (C) 2006-2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * CCDC hardware module for DM6446 + * ------------------------------ + * + * This module is for configuring CCD controller of DM6446 VPFE to capture + * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules + * such as Defect Pixel Correction, Color Space Conversion etc to + * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This + * module also allows application to configure individual + * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. + * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header + * files. The setparams() API is called by vpfe_capture driver + * to configure module parameters. This file is named DM644x so that other + * variants such DM6443 may be supported using the same module. + * + * TODO: Test Raw bayer parameter settings and bayer capture + * Split module parameter structure to module specific ioctl structs + * investigate if enum used for user space type definition + * to be replaced by #defines or integer + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "dm644x_ccdc_regs.h" +#include "ccdc_hw_device.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CCDC Driver for DM6446"); +MODULE_AUTHOR("Texas Instruments"); + +static struct ccdc_oper_config { + struct device *dev; + /* CCDC interface type */ + enum vpfe_hw_if_type if_type; + /* Raw Bayer configuration */ + struct ccdc_params_raw bayer; + /* YCbCr configuration */ + struct ccdc_params_ycbcr ycbcr; + /* Master clock */ + struct clk *mclk; + /* slave clock */ + struct clk *sclk; + /* ccdc base address */ + void __iomem *base_addr; +} ccdc_cfg = { + /* Raw configurations */ + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = CCDC_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .config_params = { + .data_sz = CCDC_DATA_10BITS, + }, + }, + .ycbcr = { + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .win = CCDC_WIN_PAL, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .bt656_enable = 1, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED + }, +}; + +#define CCDC_MAX_RAW_YUV_FORMATS 2 + +/* Raw Bayer formats */ +static u32 ccdc_raw_bayer_pix_formats[] = + {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; + +/* Raw YUV formats */ +static u32 ccdc_raw_yuv_pix_formats[] = + {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; + +/* CCDC Save/Restore context */ +static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)]; + +/* register access routines */ +static inline u32 regr(u32 offset) +{ + return __raw_readl(ccdc_cfg.base_addr + offset); +} + +static inline void regw(u32 val, u32 offset) +{ + __raw_writel(val, ccdc_cfg.base_addr + offset); +} + +static void ccdc_enable(int flag) +{ + regw(flag, CCDC_PCR); +} + +static void ccdc_enable_vport(int flag) +{ + if (flag) + /* enable video port */ + regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG); + else + regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG); +} + +/* + * ccdc_setwin() + * This function will configure the window size + * to be capture in CCDC reg + */ +void ccdc_setwin(struct v4l2_rect *image_win, + enum ccdc_frmfmt frm_fmt, + int ppc) +{ + int horz_start, horz_nr_pixels; + int vert_start, vert_nr_lines; + int val = 0, mid_img = 0; + + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); + /* + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + horz_start = image_win->left << (ppc - 1); + horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; + regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels, + CCDC_HORZ_INFO); + + vert_start = image_win->top; + + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + vert_nr_lines = (image_win->height >> 1) - 1; + vert_start >>= 1; + /* Since first line doesn't have any data */ + vert_start += 1; + /* configure VDINT0 */ + val = (vert_start << CCDC_VDINT_VDINT0_SHIFT); + regw(val, CCDC_VDINT); + + } else { + /* Since first line doesn't have any data */ + vert_start += 1; + vert_nr_lines = image_win->height - 1; + /* + * configure VDINT0 and VDINT1. VDINT1 will be at half + * of image height + */ + mid_img = vert_start + (image_win->height / 2); + val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) | + (mid_img & CCDC_VDINT_VDINT1_MASK); + regw(val, CCDC_VDINT); + + } + regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, + CCDC_VERT_START); + regw(vert_nr_lines, CCDC_VERT_LINES); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); +} + +static void ccdc_readregs(void) +{ + unsigned int val = 0; + + val = regr(CCDC_ALAW); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val); + val = regr(CCDC_CLAMP); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val); + val = regr(CCDC_DCSUB); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val); + val = regr(CCDC_BLKCMP); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val); + val = regr(CCDC_FPC_ADDR); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val); + val = regr(CCDC_FPC); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val); + val = regr(CCDC_FMTCFG); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val); + val = regr(CCDC_COLPTN); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val); + val = regr(CCDC_FMT_HORZ); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val); + val = regr(CCDC_FMT_VERT); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val); + val = regr(CCDC_HSIZE_OFF); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val); + val = regr(CCDC_SDOFST); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val); + val = regr(CCDC_VP_OUT); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val); + val = regr(CCDC_SYN_MODE); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val); + val = regr(CCDC_HORZ_INFO); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val); + val = regr(CCDC_VERT_START); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val); + val = regr(CCDC_VERT_LINES); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val); +} + +static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) +{ + if (ccdcparam->alaw.enable) { + if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) || + (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) || + (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { + dev_dbg(ccdc_cfg.dev, "\nInvalid data line select"); + return -1; + } + } + return 0; +} + +static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) +{ + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int *fpc_virtaddr = NULL; + unsigned int *fpc_physaddr = NULL; + + memcpy(config_params, raw_params, sizeof(*raw_params)); + /* + * allocate memory for fault pixel table and copy the user + * values to the table + */ + if (!config_params->fault_pxl.enable) + return 0; + + fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr; + fpc_virtaddr = (unsigned int *)phys_to_virt( + (unsigned long)fpc_physaddr); + /* + * Allocate memory for FPC table if current + * FPC table buffer is not big enough to + * accommodate FPC Number requested + */ + if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) { + if (fpc_physaddr != NULL) { + free_pages((unsigned long)fpc_physaddr, + get_order + (config_params->fault_pxl.fp_num * + FP_NUM_BYTES)); + } + + /* Allocate memory for FPC table */ + fpc_virtaddr = + (unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA, + get_order(raw_params-> + fault_pxl.fp_num * + FP_NUM_BYTES)); + + if (fpc_virtaddr == NULL) { + dev_dbg(ccdc_cfg.dev, + "\nUnable to allocate memory for FPC"); + return -EFAULT; + } + fpc_physaddr = + (unsigned int *)virt_to_phys((void *)fpc_virtaddr); + } + + /* Copy number of fault pixels and FPC table */ + config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num; + if (copy_from_user(fpc_virtaddr, + (void __user *)raw_params->fault_pxl.fpc_table_addr, + config_params->fault_pxl.fp_num * FP_NUM_BYTES)) { + dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed"); + return -EFAULT; + } + config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr; + return 0; +} + +static int ccdc_close(struct device *dev) +{ + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL; + + fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr; + + if (fpc_physaddr != NULL) { + fpc_virtaddr = (unsigned int *) + phys_to_virt((unsigned long)fpc_physaddr); + free_pages((unsigned long)fpc_virtaddr, + get_order(config_params->fault_pxl.fp_num * + FP_NUM_BYTES)); + } + return 0; +} + +/* + * ccdc_restore_defaults() + * This function will write defaults to all CCDC registers + */ +static void ccdc_restore_defaults(void) +{ + int i; + + /* disable CCDC */ + ccdc_enable(0); + /* set all registers to default value */ + for (i = 4; i <= 0x94; i += 4) + regw(0, i); + regw(CCDC_NO_CULLING, CCDC_CULLING); + regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW); +} + +static int ccdc_open(struct device *device) +{ + ccdc_restore_defaults(); + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_enable_vport(1); + return 0; +} + +static void ccdc_sbl_reset(void) +{ + vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O); +} + +/* Parameter operations */ +static int ccdc_set_params(void __user *params) +{ + struct ccdc_config_params_raw ccdc_raw_params; + int x; + + if (ccdc_cfg.if_type != VPFE_RAW_BAYER) + return -EINVAL; + + x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); + if (x) { + dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying" + "ccdc params, %d\n", x); + return -EFAULT; + } + + if (!validate_ccdc_param(&ccdc_raw_params)) { + if (!ccdc_update_raw_params(&ccdc_raw_params)) + return 0; + } + return -EINVAL; +} + +/* + * ccdc_config_ycbcr() + * This function will configure CCDC for YCbCr video capture + */ +void ccdc_config_ycbcr(void) +{ + struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; + u32 syn_mode; + + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); + /* + * first restore the CCDC registers to default values + * This is important since we assume default values to be set in + * a lot of registers that we didn't touch + */ + ccdc_restore_defaults(); + + /* + * configure pixel format, frame format, configure video frame + * format, enable output to SDRAM, enable internal timing generator + * and 8bit pack mode + */ + syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) << + CCDC_SYN_MODE_INPMOD_SHIFT) | + ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) << + CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE | + CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE); + + /* setup BT.656 sync mode */ + if (params->bt656_enable) { + regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF); + + /* + * configure the FID, VD, HD pin polarity, + * fld,hd pol positive, vd negative, 8-bit data + */ + syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE; + if (ccdc_cfg.if_type == VPFE_BT656_10BIT) + syn_mode |= CCDC_SYN_MODE_10BITS; + else + syn_mode |= CCDC_SYN_MODE_8BITS; + } else { + /* y/c external sync mode */ + syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) << + CCDC_FID_POL_SHIFT) | + ((params->hd_pol & CCDC_HD_POL_MASK) << + CCDC_HD_POL_SHIFT) | + ((params->vd_pol & CCDC_VD_POL_MASK) << + CCDC_VD_POL_SHIFT)); + } + regw(syn_mode, CCDC_SYN_MODE); + + /* configure video window */ + ccdc_setwin(¶ms->win, params->frm_fmt, 2); + + /* + * configure the order of y cb cr in SDRAM, and disable latch + * internal register on vsync + */ + if (ccdc_cfg.if_type == VPFE_BT656_10BIT) + regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | + CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT, + CCDC_CCDCFG); + else + regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | + CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); + + /* + * configure the horizontal line offset. This should be a + * on 32 byte boundary. So clear LSB 5 bits + */ + regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); + + /* configure the memory line offset */ + if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) + /* two fields are interleaved in memory */ + regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); + + ccdc_sbl_reset(); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); +} + +static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) +{ + u32 val; + + if (!bclamp->enable) { + /* configure DCSub */ + val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; + regw(val, CCDC_DCSUB); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val); + regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n"); + return; + } + /* + * Configure gain, Start pixel, No of line to be avg, + * No of pixel/line to be avg, & Enable the Black clamping + */ + val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) | + ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) << + CCDC_BLK_ST_PXL_SHIFT) | + ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) << + CCDC_BLK_SAMPLE_LINE_SHIFT) | + ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << + CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); + regw(val, CCDC_CLAMP); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val); + /* If Black clamping is enable then make dcsub 0 */ + regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n"); +} + +static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) +{ + u32 val; + + val = ((bcomp->b & CCDC_BLK_COMP_MASK) | + ((bcomp->gb & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_GB_COMP_SHIFT) | + ((bcomp->gr & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_GR_COMP_SHIFT) | + ((bcomp->r & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_R_COMP_SHIFT)); + regw(val, CCDC_BLKCMP); +} + +static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) +{ + u32 val; + + /* Initially disable FPC */ + val = CCDC_FPC_DISABLE; + regw(val, CCDC_FPC); + + if (!fpc->enable) + return; + + /* Configure Fault pixel if needed */ + regw(fpc->fpc_table_addr, CCDC_FPC_ADDR); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n", + (fpc->fpc_table_addr)); + /* Write the FPC params with FPC disable */ + val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK; + regw(val, CCDC_FPC); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); + /* read the FPC register */ + val = regr(CCDC_FPC) | CCDC_FPC_ENABLE; + regw(val, CCDC_FPC); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); +} + +/* + * ccdc_config_raw() + * This function will configure CCDC for Raw capture mode + */ +void ccdc_config_raw(void) +{ + struct ccdc_params_raw *params = &ccdc_cfg.bayer; + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int syn_mode = 0; + unsigned int val; + + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); + + /* Reset CCDC */ + ccdc_restore_defaults(); + + /* Disable latching function registers on VSYNC */ + regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); + + /* + * Configure the vertical sync polarity(SYN_MODE.VDPOL), + * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity + * (SYN_MODE.FLDPOL), frame format(progressive or interlace), + * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output + * SDRAM, enable internal timing generator + */ + syn_mode = + (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | + ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | + ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | + ((config_params->data_sz & CCDC_DATA_SZ_MASK) << + CCDC_DATA_SZ_SHIFT) | + ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) | + CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE); + + /* Enable and configure aLaw register if needed */ + if (config_params->alaw.enable) { + val = ((config_params->alaw.gama_wd & + CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE); + regw(val, CCDC_ALAW); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); + } + + /* Configure video window */ + ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW); + + /* Configure Black Clamp */ + ccdc_config_black_clamp(&config_params->blk_clamp); + + /* Configure Black level compensation */ + ccdc_config_black_compense(&config_params->blk_comp); + + /* Configure Fault Pixel Correction */ + ccdc_config_fpc(&config_params->fault_pxl); + + /* If data size is 8 bit then pack the data */ + if ((config_params->data_sz == CCDC_DATA_8BITS) || + config_params->alaw.enable) + syn_mode |= CCDC_DATA_PACK_ENABLE; + +#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE + /* enable video port */ + val = CCDC_ENABLE_VIDEO_PORT; +#else + /* disable video port */ + val = CCDC_DISABLE_VIDEO_PORT; +#endif + + if (config_params->data_sz == CCDC_DATA_8BITS) + val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK) + << CCDC_FMTCFG_VPIN_SHIFT; + else + val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK) + << CCDC_FMTCFG_VPIN_SHIFT; + /* Write value in FMTCFG */ + regw(val, CCDC_FMTCFG); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val); + /* Configure the color pattern according to mt9t001 sensor */ + regw(CCDC_COLPTN_VAL, CCDC_COLPTN); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); + /* + * Configure Data formatter(Video port) pixel selection + * (FMT_HORZ, FMT_VERT) + */ + val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) << + CCDC_FMT_HORZ_FMTSPH_SHIFT) | + (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); + regw(val, CCDC_FMT_HORZ); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val); + val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK) + << CCDC_FMT_VERT_FMTSLV_SHIFT; + if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) + val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK; + else + val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK; + + dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n", + params->win.height); + regw(val, CCDC_FMT_VERT); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val); + + dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)..."); + + /* + * Configure Horizontal offset register. If pack 8 is enabled then + * 1 pixel will take 1 byte + */ + if ((config_params->data_sz == CCDC_DATA_8BITS) || + config_params->alaw.enable) + regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) & + CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF); + else + /* else one pixel will take 2 byte */ + regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) + + CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK, + CCDC_HSIZE_OFF); + + /* Set value for SDOFST */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_enable) { + /* For intelace inverse mode */ + regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n"); + } + + else { + /* For intelace non inverse mode */ + regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n"); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n"); + } + + /* + * Configure video port pixel selection (VPOUT) + * Here -1 is to make the height value less than FMT_VERT.FMTLNV + */ + if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) + val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) + << CCDC_VP_OUT_VERT_NUM_SHIFT; + else + val = + ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) - + 1) & CCDC_VP_OUT_VERT_NUM_MASK)) << + CCDC_VP_OUT_VERT_NUM_SHIFT; + + val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK) + << CCDC_VP_OUT_HORZ_NUM_SHIFT; + val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK; + regw(val, CCDC_VP_OUT); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val); + regw(syn_mode, CCDC_SYN_MODE); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); + + ccdc_sbl_reset(); + dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); + ccdc_readregs(); +} + +static int ccdc_configure(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_config_raw(); + else + ccdc_config_ycbcr(); + return 0; +} + +static int ccdc_set_buftype(enum ccdc_buftype buf_type) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.buf_type = buf_type; + else + ccdc_cfg.ycbcr.buf_type = buf_type; + return 0; +} + +static enum ccdc_buftype ccdc_get_buftype(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.buf_type; + return ccdc_cfg.ycbcr.buf_type; +} + +static int ccdc_enum_pix(u32 *pix, int i) +{ + int ret = -EINVAL; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { + *pix = ccdc_raw_bayer_pix_formats[i]; + ret = 0; + } + } else { + if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { + *pix = ccdc_raw_yuv_pix_formats[i]; + ret = 0; + } + } + return ret; +} + +static int ccdc_set_pixel_format(u32 pixfmt) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + if (pixfmt == V4L2_PIX_FMT_SBGGR8) + ccdc_cfg.bayer.config_params.alaw.enable = 1; + else if (pixfmt != V4L2_PIX_FMT_SBGGR16) + return -EINVAL; + } else { + if (pixfmt == V4L2_PIX_FMT_YUYV) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + else if (pixfmt == V4L2_PIX_FMT_UYVY) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + else + return -EINVAL; + } + return 0; +} + +static u32 ccdc_get_pixel_format(void) +{ + struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; + u32 pixfmt; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + if (alaw->enable) + pixfmt = V4L2_PIX_FMT_SBGGR8; + else + pixfmt = V4L2_PIX_FMT_SBGGR16; + else { + if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + return pixfmt; +} + +static int ccdc_set_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.win = *win; + else + ccdc_cfg.ycbcr.win = *win; + return 0; +} + +static void ccdc_get_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + *win = ccdc_cfg.bayer.win; + else + *win = ccdc_cfg.ycbcr.win; +} + +static unsigned int ccdc_get_line_length(void) +{ + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int len; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if ((config_params->alaw.enable) || + (config_params->data_sz == CCDC_DATA_8BITS)) + len = ccdc_cfg.bayer.win.width; + else + len = ccdc_cfg.bayer.win.width * 2; + } else + len = ccdc_cfg.ycbcr.win.width * 2; + return ALIGN(len, 32); +} + +static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.frm_fmt = frm_fmt; + else + ccdc_cfg.ycbcr.frm_fmt = frm_fmt; + return 0; +} + +static enum ccdc_frmfmt ccdc_get_frame_format(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.frm_fmt; + else + return ccdc_cfg.ycbcr.frm_fmt; +} + +static int ccdc_getfid(void) +{ + return (regr(CCDC_SYN_MODE) >> 15) & 1; +} + +/* misc operations */ +static inline void ccdc_setfbaddr(unsigned long addr) +{ + regw(addr & 0xffffffe0, CCDC_SDR_ADDR); +} + +static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) +{ + ccdc_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_YCBCR_SYNC_16: + case VPFE_YCBCR_SYNC_8: + case VPFE_BT656_10BIT: + ccdc_cfg.ycbcr.vd_pol = params->vdpol; + ccdc_cfg.ycbcr.hd_pol = params->hdpol; + break; + default: + /* TODO add support for raw bayer here */ + return -EINVAL; + } + return 0; +} + +static void ccdc_save_context(void) +{ + ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR); + ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE); + ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID); + ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES); + ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO); + ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START); + ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES); + ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING); + ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF); + ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST); + ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR); + ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP); + ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB); + ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN); + ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP); + ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC); + ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR); + ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT); + ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW); + ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF); + ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG); + ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG); + ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ); + ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT); + ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0); + ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1); + ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2); + ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3); + ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4); + ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5); + ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6); + ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7); + ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0); + ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1); + ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0); + ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1); + ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT); +} + +static void ccdc_restore_context(void) +{ + regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE); + regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID); + regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES); + regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO); + regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START); + regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES); + regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING); + regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF); + regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST); + regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR); + regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP); + regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB); + regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN); + regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP); + regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC); + regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR); + regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT); + regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW); + regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF); + regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG); + regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG); + regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ); + regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT); + regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0); + regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1); + regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2); + regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3); + regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4); + regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5); + regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6); + regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7); + regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0); + regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1); + regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0); + regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1); + regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); + regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); +} +static struct ccdc_hw_device ccdc_hw_dev = { + .name = "DM6446 CCDC", + .owner = THIS_MODULE, + .hw_ops = { + .open = ccdc_open, + .close = ccdc_close, + .reset = ccdc_sbl_reset, + .enable = ccdc_enable, + .set_hw_if_params = ccdc_set_hw_if_params, + .set_params = ccdc_set_params, + .configure = ccdc_configure, + .set_buftype = ccdc_set_buftype, + .get_buftype = ccdc_get_buftype, + .enum_pix = ccdc_enum_pix, + .set_pixel_format = ccdc_set_pixel_format, + .get_pixel_format = ccdc_get_pixel_format, + .set_frame_format = ccdc_set_frame_format, + .get_frame_format = ccdc_get_frame_format, + .set_image_window = ccdc_set_image_window, + .get_image_window = ccdc_get_image_window, + .get_line_length = ccdc_get_line_length, + .setfbaddr = ccdc_setfbaddr, + .getfid = ccdc_getfid, + }, +}; + +static int __init dm644x_ccdc_probe(struct platform_device *pdev) +{ + struct resource *res; + int status = 0; + + /* + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&ccdc_hw_dev); + if (status < 0) + return status; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + status = -ENODEV; + goto fail_nores; + } + + res = request_mem_region(res->start, resource_size(res), res->name); + if (!res) { + status = -EBUSY; + goto fail_nores; + } + + ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); + if (!ccdc_cfg.base_addr) { + status = -ENOMEM; + goto fail_nomem; + } + + /* Get and enable Master clock */ + ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); + if (IS_ERR(ccdc_cfg.mclk)) { + status = PTR_ERR(ccdc_cfg.mclk); + goto fail_nomap; + } + if (clk_enable(ccdc_cfg.mclk)) { + status = -ENODEV; + goto fail_mclk; + } + + /* Get and enable Slave clock */ + ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); + if (IS_ERR(ccdc_cfg.sclk)) { + status = PTR_ERR(ccdc_cfg.sclk); + goto fail_mclk; + } + if (clk_enable(ccdc_cfg.sclk)) { + status = -ENODEV; + goto fail_sclk; + } + ccdc_cfg.dev = &pdev->dev; + printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); + return 0; +fail_sclk: + clk_put(ccdc_cfg.sclk); +fail_mclk: + clk_put(ccdc_cfg.mclk); +fail_nomap: + iounmap(ccdc_cfg.base_addr); +fail_nomem: + release_mem_region(res->start, resource_size(res)); +fail_nores: + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return status; +} + +static int dm644x_ccdc_remove(struct platform_device *pdev) +{ + struct resource *res; + + clk_put(ccdc_cfg.mclk); + clk_put(ccdc_cfg.sclk); + iounmap(ccdc_cfg.base_addr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return 0; +} + +static int dm644x_ccdc_suspend(struct device *dev) +{ + /* Save CCDC context */ + ccdc_save_context(); + /* Disable CCDC */ + ccdc_enable(0); + /* Disable both master and slave clock */ + clk_disable(ccdc_cfg.mclk); + clk_disable(ccdc_cfg.sclk); + + return 0; +} + +static int dm644x_ccdc_resume(struct device *dev) +{ + /* Enable both master and slave clock */ + clk_enable(ccdc_cfg.mclk); + clk_enable(ccdc_cfg.sclk); + /* Restore CCDC context */ + ccdc_restore_context(); + + return 0; +} + +static const struct dev_pm_ops dm644x_ccdc_pm_ops = { + .suspend = dm644x_ccdc_suspend, + .resume = dm644x_ccdc_resume, +}; + +static struct platform_driver dm644x_ccdc_driver = { + .driver = { + .name = "dm644x_ccdc", + .owner = THIS_MODULE, + .pm = &dm644x_ccdc_pm_ops, + }, + .remove = __devexit_p(dm644x_ccdc_remove), + .probe = dm644x_ccdc_probe, +}; + +static int __init dm644x_ccdc_init(void) +{ + return platform_driver_register(&dm644x_ccdc_driver); +} + +static void __exit dm644x_ccdc_exit(void) +{ + platform_driver_unregister(&dm644x_ccdc_driver); +} + +module_init(dm644x_ccdc_init); +module_exit(dm644x_ccdc_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm644x_ccdc_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm644x_ccdc_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm644x_ccdc_regs.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/dm644x_ccdc_regs.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2006-2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + */ +#ifndef _DM644X_CCDC_REGS_H +#define _DM644X_CCDC_REGS_H + +/**************************************************************************\ +* Register OFFSET Definitions +\**************************************************************************/ +#define CCDC_PID 0x0 +#define CCDC_PCR 0x4 +#define CCDC_SYN_MODE 0x8 +#define CCDC_HD_VD_WID 0xc +#define CCDC_PIX_LINES 0x10 +#define CCDC_HORZ_INFO 0x14 +#define CCDC_VERT_START 0x18 +#define CCDC_VERT_LINES 0x1c +#define CCDC_CULLING 0x20 +#define CCDC_HSIZE_OFF 0x24 +#define CCDC_SDOFST 0x28 +#define CCDC_SDR_ADDR 0x2c +#define CCDC_CLAMP 0x30 +#define CCDC_DCSUB 0x34 +#define CCDC_COLPTN 0x38 +#define CCDC_BLKCMP 0x3c +#define CCDC_FPC 0x40 +#define CCDC_FPC_ADDR 0x44 +#define CCDC_VDINT 0x48 +#define CCDC_ALAW 0x4c +#define CCDC_REC656IF 0x50 +#define CCDC_CCDCFG 0x54 +#define CCDC_FMTCFG 0x58 +#define CCDC_FMT_HORZ 0x5c +#define CCDC_FMT_VERT 0x60 +#define CCDC_FMT_ADDR0 0x64 +#define CCDC_FMT_ADDR1 0x68 +#define CCDC_FMT_ADDR2 0x6c +#define CCDC_FMT_ADDR3 0x70 +#define CCDC_FMT_ADDR4 0x74 +#define CCDC_FMT_ADDR5 0x78 +#define CCDC_FMT_ADDR6 0x7c +#define CCDC_FMT_ADDR7 0x80 +#define CCDC_PRGEVEN_0 0x84 +#define CCDC_PRGEVEN_1 0x88 +#define CCDC_PRGODD_0 0x8c +#define CCDC_PRGODD_1 0x90 +#define CCDC_VP_OUT 0x94 +#define CCDC_REG_END 0x98 + +/*************************************************************** +* Define for various register bit mask and shifts for CCDC +****************************************************************/ +#define CCDC_FID_POL_MASK 1 +#define CCDC_FID_POL_SHIFT 4 +#define CCDC_HD_POL_MASK 1 +#define CCDC_HD_POL_SHIFT 3 +#define CCDC_VD_POL_MASK 1 +#define CCDC_VD_POL_SHIFT 2 +#define CCDC_HSIZE_OFF_MASK 0xffffffe0 +#define CCDC_32BYTE_ALIGN_VAL 31 +#define CCDC_FRM_FMT_MASK 0x1 +#define CCDC_FRM_FMT_SHIFT 7 +#define CCDC_DATA_SZ_MASK 7 +#define CCDC_DATA_SZ_SHIFT 8 +#define CCDC_PIX_FMT_MASK 3 +#define CCDC_PIX_FMT_SHIFT 12 +#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF +#define CCDC_WEN_ENABLE (1 << 17) +#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF +#define CCDC_VDHDEN_ENABLE (1 << 16) +#define CCDC_LPF_ENABLE (1 << 14) +#define CCDC_ALAW_ENABLE (1 << 3) +#define CCDC_ALAW_GAMA_WD_MASK 7 +#define CCDC_BLK_CLAMP_ENABLE (1 << 31) +#define CCDC_BLK_SGAIN_MASK 0x1F +#define CCDC_BLK_ST_PXL_MASK 0x7FFF +#define CCDC_BLK_ST_PXL_SHIFT 10 +#define CCDC_BLK_SAMPLE_LN_MASK 7 +#define CCDC_BLK_SAMPLE_LN_SHIFT 28 +#define CCDC_BLK_SAMPLE_LINE_MASK 7 +#define CCDC_BLK_SAMPLE_LINE_SHIFT 25 +#define CCDC_BLK_DC_SUB_MASK 0x03FFF +#define CCDC_BLK_COMP_MASK 0xFF +#define CCDC_BLK_COMP_GB_COMP_SHIFT 8 +#define CCDC_BLK_COMP_GR_COMP_SHIFT 16 +#define CCDC_BLK_COMP_R_COMP_SHIFT 24 +#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) +#define CCDC_FPC_ENABLE (1 << 15) +#define CCDC_FPC_DISABLE 0 +#define CCDC_FPC_FPC_NUM_MASK 0x7FFF +#define CCDC_DATA_PACK_ENABLE (1 << 11) +#define CCDC_FMTCFG_VPIN_MASK 7 +#define CCDC_FMTCFG_VPIN_SHIFT 12 +#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF +#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF +#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 +#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF +#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF +#define CCDC_FMT_VERT_FMTSLV_SHIFT 16 +#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF +#define CCDC_VP_OUT_VERT_NUM_SHIFT 17 +#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF +#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 +#define CCDC_VP_OUT_HORZ_ST_MASK 0xF +#define CCDC_HORZ_INFO_SPH_SHIFT 16 +#define CCDC_VERT_START_SLV0_SHIFT 16 +#define CCDC_VDINT_VDINT0_SHIFT 16 +#define CCDC_VDINT_VDINT1_MASK 0xFFFF +#define CCDC_PPC_RAW 1 +#define CCDC_DCSUB_DEFAULT_VAL 0 +#define CCDC_CLAMP_DEFAULT_VAL 0 +#define CCDC_ENABLE_VIDEO_PORT 0x8000 +#define CCDC_DISABLE_VIDEO_PORT 0 +#define CCDC_COLPTN_VAL 0xBB11BB11 +#define CCDC_TWO_BYTES_PER_PIXEL 2 +#define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D +#define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249 +#define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000 +#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0 +#define CCDC_INTERLACED_HEIGHT_SHIFT 1 +#define CCDC_SYN_MODE_INPMOD_SHIFT 12 +#define CCDC_SYN_MODE_INPMOD_MASK 3 +#define CCDC_SYN_MODE_8BITS (7 << 8) +#define CCDC_SYN_MODE_10BITS (6 << 8) +#define CCDC_SYN_MODE_11BITS (5 << 8) +#define CCDC_SYN_MODE_12BITS (4 << 8) +#define CCDC_SYN_MODE_13BITS (3 << 8) +#define CCDC_SYN_MODE_14BITS (2 << 8) +#define CCDC_SYN_MODE_15BITS (1 << 8) +#define CCDC_SYN_MODE_16BITS (0 << 8) +#define CCDC_SYN_FLDMODE_MASK 1 +#define CCDC_SYN_FLDMODE_SHIFT 7 +#define CCDC_REC656IF_BT656_EN 3 +#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2) +#define CCDC_CCDCFG_Y8POS_SHIFT 11 +#define CCDC_CCDCFG_BW656_10BIT (1 << 5) +#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 +#define CCDC_NO_CULLING 0xffff00ff +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/isif.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/isif.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/isif.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/isif.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1172 @@ +/* + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * Image Sensor Interface (ISIF) driver + * + * This driver is for configuring the ISIF IP available on DM365 or any other + * TI SoCs. This is used for capturing yuv or bayer video or image data + * from a decoder or sensor. This IP is similar to the CCDC IP on DM355 + * and DM6446, but with enhanced or additional ip blocks. The driver + * configures the ISIF upon commands from the vpfe bridge driver through + * ccdc_hw_device interface. + * + * TODO: 1) Raw bayer parameter settings and bayer capture + * 2) Add support for control ioctl + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "isif_regs.h" +#include "ccdc_hw_device.h" + +/* Defaults for module configuration parameters */ +static struct isif_config_params_raw isif_config_defaults = { + .linearize = { + .en = 0, + .corr_shft = ISIF_NO_SHIFT, + .scale_fact = {1, 0}, + }, + .df_csc = { + .df_or_csc = 0, + .csc = { + .en = 0, + }, + }, + .dfc = { + .en = 0, + }, + .bclamp = { + .en = 0, + }, + .gain_offset = { + .gain = { + .r_ye = {1, 0}, + .gr_cy = {1, 0}, + .gb_g = {1, 0}, + .b_mg = {1, 0}, + }, + }, + .culling = { + .hcpat_odd = 0xff, + .hcpat_even = 0xff, + .vcpat = 0xff, + }, + .compress = { + .alg = ISIF_ALAW, + }, +}; + +/* ISIF operation configuration */ +static struct isif_oper_config { + struct device *dev; + enum vpfe_hw_if_type if_type; + struct isif_ycbcr_config ycbcr; + struct isif_params_raw bayer; + enum isif_data_pack data_pack; + /* Master clock */ + struct clk *mclk; + /* ISIF base address */ + void __iomem *base_addr; + /* ISIF Linear Table 0 */ + void __iomem *linear_tbl0_addr; + /* ISIF Linear Table 1 */ + void __iomem *linear_tbl1_addr; +} isif_cfg = { + .ycbcr = { + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .win = ISIF_WIN_NTSC, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, + }, + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = ISIF_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .gain = { + .r_ye = {1, 0}, + .gr_cy = {1, 0}, + .gb_g = {1, 0}, + .b_mg = {1, 0}, + }, + .cfa_pat = ISIF_CFA_PAT_MOSAIC, + .data_msb = ISIF_BIT_MSB_11, + .config_params = { + .data_shift = ISIF_NO_SHIFT, + .col_pat_field0 = { + .olop = ISIF_GREEN_BLUE, + .olep = ISIF_BLUE, + .elop = ISIF_RED, + .elep = ISIF_GREEN_RED, + }, + .col_pat_field1 = { + .olop = ISIF_GREEN_BLUE, + .olep = ISIF_BLUE, + .elop = ISIF_RED, + .elep = ISIF_GREEN_RED, + }, + .test_pat_gen = 0, + }, + }, + .data_pack = ISIF_DATA_PACK8, +}; + +/* Raw Bayer formats */ +static const u32 isif_raw_bayer_pix_formats[] = { + V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; + +/* Raw YUV formats */ +static const u32 isif_raw_yuv_pix_formats[] = { + V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; + +/* register access routines */ +static inline u32 regr(u32 offset) +{ + return __raw_readl(isif_cfg.base_addr + offset); +} + +static inline void regw(u32 val, u32 offset) +{ + __raw_writel(val, isif_cfg.base_addr + offset); +} + +/* reg_modify() - read, modify and write register */ +static inline u32 reg_modify(u32 mask, u32 val, u32 offset) +{ + u32 new_val = (regr(offset) & ~mask) | (val & mask); + + regw(new_val, offset); + return new_val; +} + +static inline void regw_lin_tbl(u32 val, u32 offset, int i) +{ + if (!i) + __raw_writel(val, isif_cfg.linear_tbl0_addr + offset); + else + __raw_writel(val, isif_cfg.linear_tbl1_addr + offset); +} + +static void isif_disable_all_modules(void) +{ + /* disable BC */ + regw(0, CLAMPCFG); + /* disable vdfc */ + regw(0, DFCCTL); + /* disable CSC */ + regw(0, CSCCTL); + /* disable linearization */ + regw(0, LINCFG0); + /* disable other modules here as they are supported */ +} + +static void isif_enable(int en) +{ + if (!en) { + /* Before disable isif, disable all ISIF modules */ + isif_disable_all_modules(); + /* + * wait for next VD. Assume lowest scan rate is 12 Hz. So + * 100 msec delay is good enough + */ + msleep(100); + } + reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN); +} + +static void isif_enable_output_to_sdram(int en) +{ + reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); +} + +static void isif_config_culling(struct isif_cul *cul) +{ + u32 val; + + /* Horizontal pattern */ + val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd; + regw(val, CULH); + + /* vertical pattern */ + regw(cul->vcpat, CULV); + + /* LPF */ + reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT, + cul->en_lpf << ISIF_LPF_SHIFT, MODESET); +} + +static void isif_config_gain_offset(void) +{ + struct isif_gain_offsets_adj *gain_off_p = + &isif_cfg.bayer.config_params.gain_offset; + u32 val; + + val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) | + (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) | + (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) | + (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) | + (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) | + (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT); + + reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); + + val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.r_ye.decimal; + regw(val, CRGAIN); + + val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.gr_cy.decimal; + regw(val, CGRGAIN); + + val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.gb_g.decimal; + regw(val, CGBGAIN); + + val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.b_mg.decimal; + regw(val, CBGAIN); + + regw(gain_off_p->offset, COFSTA); +} + +static void isif_restore_defaults(void) +{ + enum vpss_ccdc_source_sel source = VPSS_CCDCIN; + + dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults..."); + isif_cfg.bayer.config_params = isif_config_defaults; + /* Enable clock to ISIF, IPIPEIF and BL */ + vpss_enable_clock(VPSS_CCDC_CLOCK, 1); + vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); + vpss_enable_clock(VPSS_BL_CLOCK, 1); + /* Set default offset and gain */ + isif_config_gain_offset(); + vpss_select_ccdc_source(source); + dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults..."); +} + +static int isif_open(struct device *device) +{ + isif_restore_defaults(); + return 0; +} + +/* This function will configure the window size to be capture in ISIF reg */ +static void isif_setwin(struct v4l2_rect *image_win, + enum ccdc_frmfmt frm_fmt, int ppc) +{ + int horz_start, horz_nr_pixels; + int vert_start, vert_nr_lines; + int mid_img = 0; + + dev_dbg(isif_cfg.dev, "\nStarting isif_setwin..."); + /* + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + horz_start = image_win->left << (ppc - 1); + horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; + + /* Writing the horizontal info into the registers */ + regw(horz_start & START_PX_HOR_MASK, SPH); + regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); + vert_start = image_win->top; + + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + vert_nr_lines = (image_win->height >> 1) - 1; + vert_start >>= 1; + /* To account for VD since line 0 doesn't have any data */ + vert_start += 1; + } else { + /* To account for VD since line 0 doesn't have any data */ + vert_start += 1; + vert_nr_lines = image_win->height - 1; + /* configure VDINT0 and VDINT1 */ + mid_img = vert_start + (image_win->height / 2); + regw(mid_img, VDINT1); + } + + regw(0, VDINT0); + regw(vert_start & START_VER_ONE_MASK, SLV0); + regw(vert_start & START_VER_TWO_MASK, SLV1); + regw(vert_nr_lines & NUM_LINES_VER, LNV); +} + +static void isif_config_bclamp(struct isif_black_clamp *bc) +{ + u32 val; + + /* + * DC Offset is always added to image data irrespective of bc enable + * status + */ + regw(bc->dc_offset, CLDCOFST); + + if (bc->en) { + val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; + + /* Enable BC and horizontal clamp caculation paramaters */ + val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); + + regw(val, CLAMPCFG); + + if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) { + /* + * Window count for calculation + * Base window selection + * pixel limit + * Horizontal size of window + * vertical size of the window + * Horizontal start position of the window + * Vertical start position of the window + */ + val = bc->horz.win_count_calc | + ((!!bc->horz.base_win_sel_calc) << + ISIF_HORZ_BC_WIN_SEL_SHIFT) | + ((!!bc->horz.clamp_pix_limit) << + ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | + (bc->horz.win_h_sz_calc << + ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | + (bc->horz.win_v_sz_calc << + ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); + regw(val, CLHWIN0); + + regw(bc->horz.win_start_h_calc, CLHWIN1); + regw(bc->horz.win_start_v_calc, CLHWIN2); + } + + /* vertical clamp caculation paramaters */ + + /* Reset clamp value sel for previous line */ + val |= + (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) | + (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT); + regw(val, CLVWIN0); + + /* Optical Black horizontal start position */ + regw(bc->vert.ob_start_h, CLVWIN1); + /* Optical Black vertical start position */ + regw(bc->vert.ob_start_v, CLVWIN2); + /* Optical Black vertical size for calculation */ + regw(bc->vert.ob_v_sz_calc, CLVWIN3); + /* Vertical start position for BC subtraction */ + regw(bc->vert_start_sub, CLSV); + } +} + +static void isif_config_linearization(struct isif_linearize *linearize) +{ + u32 val, i; + + if (!linearize->en) { + regw(0, LINCFG0); + return; + } + + /* shift value for correction & enable linearization (set lsb) */ + val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1; + regw(val, LINCFG0); + + /* Scale factor */ + val = ((!!linearize->scale_fact.integer) << + ISIF_LIN_SCALE_FACT_INTEG_SHIFT) | + linearize->scale_fact.decimal; + regw(val, LINCFG1); + + for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) { + if (i % 2) + regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1); + else + regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0); + } +} + +static int isif_config_dfc(struct isif_dfc *vdfc) +{ + /* initialize retries to loop for max ~ 250 usec */ + u32 val, count, retries = loops_per_jiffy / (4000/HZ); + int i; + + if (!vdfc->en) + return 0; + + /* Correction mode */ + val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT); + + /* Correct whole line or partial */ + if (vdfc->corr_whole_line) + val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; + + /* level shift value */ + val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT; + + regw(val, DFCCTL); + + /* Defect saturation level */ + regw(vdfc->def_sat_level, VDFSATLV); + + regw(vdfc->table[0].pos_vert, DFCMEM0); + regw(vdfc->table[0].pos_horz, DFCMEM1); + if (vdfc->corr_mode == ISIF_VDFC_NORMAL || + vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { + regw(vdfc->table[0].level_at_pos, DFCMEM2); + regw(vdfc->table[0].level_up_pixels, DFCMEM3); + regw(vdfc->table[0].level_low_pixels, DFCMEM4); + } + + /* set DFCMARST and set DFCMWR */ + val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1; + regw(val, DFCMEMCTL); + + count = retries; + while (count && (regr(DFCMEMCTL) & 0x1)) + count--; + + if (!count) { + dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n"); + return -1; + } + + for (i = 1; i < vdfc->num_vdefects; i++) { + regw(vdfc->table[i].pos_vert, DFCMEM0); + regw(vdfc->table[i].pos_horz, DFCMEM1); + if (vdfc->corr_mode == ISIF_VDFC_NORMAL || + vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { + regw(vdfc->table[i].level_at_pos, DFCMEM2); + regw(vdfc->table[i].level_up_pixels, DFCMEM3); + regw(vdfc->table[i].level_low_pixels, DFCMEM4); + } + val = regr(DFCMEMCTL); + /* clear DFCMARST and set DFCMWR */ + val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); + val |= 1; + regw(val, DFCMEMCTL); + + count = retries; + while (count && (regr(DFCMEMCTL) & 0x1)) + count--; + + if (!count) { + dev_err(isif_cfg.dev, + "defect table write timeout !!!\n"); + return -1; + } + } + if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) { + /* Extra cycle needed */ + regw(0, DFCMEM0); + regw(0x1FFF, DFCMEM1); + regw(1, DFCMEMCTL); + } + + /* enable VDFC */ + reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT), + DFCCTL); + return 0; +} + +static void isif_config_csc(struct isif_df_csc *df_csc) +{ + u32 val1 = 0, val2 = 0, i; + + if (!df_csc->csc.en) { + regw(0, CSCCTL); + return; + } + for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) { + if ((i % 2) == 0) { + /* CSCM - LSB */ + val1 = (df_csc->csc.coeff[i].integer << + ISIF_CSC_COEF_INTEG_SHIFT) | + df_csc->csc.coeff[i].decimal; + } else { + + /* CSCM - MSB */ + val2 = (df_csc->csc.coeff[i].integer << + ISIF_CSC_COEF_INTEG_SHIFT) | + df_csc->csc.coeff[i].decimal; + val2 <<= ISIF_CSCM_MSB_SHIFT; + val2 |= val1; + regw(val2, (CSCM0 + ((i - 1) << 1))); + } + } + + /* program the active area */ + regw(df_csc->start_pix, FMTSPH); + /* + * one extra pixel as required for CSC. Actually number of + * pixel - 1 should be configured in this register. So we + * need to subtract 1 before writing to FMTSPH, but we will + * not do this since csc requires one extra pixel + */ + regw(df_csc->num_pixels, FMTLNH); + regw(df_csc->start_line, FMTSLV); + /* + * one extra line as required for CSC. See reason documented for + * num_pixels + */ + regw(df_csc->num_lines, FMTLNV); + + /* Enable CSC */ + regw(1, CSCCTL); +} + +static int isif_config_raw(void) +{ + struct isif_params_raw *params = &isif_cfg.bayer; + struct isif_config_params_raw *module_params = + &isif_cfg.bayer.config_params; + struct vpss_pg_frame_size frame_size; + struct vpss_sync_pol sync; + u32 val; + + dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n"); + + /* + * Configure CCDCFG register:- + * Set CCD Not to swap input since input is RAW data + * Set FID detection function to Latch at V-Sync + * Set WENLOG - isif valid area + * Set TRGSEL + * Set EXTRG + * Packed to 8 or 16 bits + */ + + val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | + ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | + ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack; + + dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val); + regw(val, CCDCFG); + + /* + * Configure the vertical sync polarity(MODESET.VDPOL) + * Configure the horizontal sync polarity (MODESET.HDPOL) + * Configure frame id polarity (MODESET.FLDPOL) + * Configure data polarity + * Configure External WEN Selection + * Configure frame format(progressive or interlace) + * Configure pixel format (Input mode) + * Configure the data shift + */ + + val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) | + (params->hd_pol << ISIF_HD_POL_SHIFT) | + (params->fid_pol << ISIF_FID_POL_SHIFT) | + (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) | + (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) | + (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | + (params->pix_fmt << ISIF_INPUT_SHIFT) | + (params->config_params.data_shift << ISIF_DATASFT_SHIFT); + + regw(val, MODESET); + dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val); + + /* + * Configure GAMMAWD register + * CFA pattern setting + */ + val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT; + + /* Gamma msb */ + if (module_params->compress.alg == ISIF_ALAW) + val |= ISIF_ALAW_ENABLE; + + val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT); + regw(val, CGAMMAWD); + + /* Configure DPCM compression settings */ + if (module_params->compress.alg == ISIF_DPCM) { + val = BIT(ISIF_DPCM_EN_SHIFT) | + (module_params->compress.pred << + ISIF_DPCM_PREDICTOR_SHIFT); + } + + regw(val, MISC); + + /* Configure Gain & Offset */ + isif_config_gain_offset(); + + /* Configure Color pattern */ + val = (params->config_params.col_pat_field0.olop) | + (params->config_params.col_pat_field0.olep << 2) | + (params->config_params.col_pat_field0.elop << 4) | + (params->config_params.col_pat_field0.elep << 6) | + (params->config_params.col_pat_field1.olop << 8) | + (params->config_params.col_pat_field1.olep << 10) | + (params->config_params.col_pat_field1.elop << 12) | + (params->config_params.col_pat_field1.elep << 14); + regw(val, CCOLP); + dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val); + + /* Configure HSIZE register */ + val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT; + + /* calculate line offset in 32 bytes based on pack value */ + if (isif_cfg.data_pack == ISIF_PACK_8BIT) + val |= ((params->win.width + 31) >> 5); + else if (isif_cfg.data_pack == ISIF_PACK_12BIT) + val |= (((params->win.width + + (params->win.width >> 2)) + 31) >> 5); + else + val |= (((params->win.width * 2) + 31) >> 5); + regw(val, HSIZE); + + /* Configure SDOFST register */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_en) { + /* For interlace inverse mode */ + regw(0x4B6D, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n"); + } else { + /* For interlace non inverse mode */ + regw(0x0B6D, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n"); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + if (params->image_invert_en) { + /* For progressive inverse mode */ + regw(0x4000, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n"); + } else { + /* For progressive non inverse mode */ + regw(0x0000, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n"); + } + } + + /* Configure video window */ + isif_setwin(¶ms->win, params->frm_fmt, 1); + + /* Configure Black Clamp */ + isif_config_bclamp(&module_params->bclamp); + + /* Configure Vertical Defection Pixel Correction */ + if (isif_config_dfc(&module_params->dfc) < 0) + return -EFAULT; + + if (!module_params->df_csc.df_or_csc) + /* Configure Color Space Conversion */ + isif_config_csc(&module_params->df_csc); + + isif_config_linearization(&module_params->linearize); + + /* Configure Culling */ + isif_config_culling(&module_params->culling); + + /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */ + regw(module_params->horz_offset, DATAHOFST); + regw(module_params->vert_offset, DATAVOFST); + + /* Setup test pattern if enabled */ + if (params->config_params.test_pat_gen) { + /* Use the HD/VD pol settings from user */ + sync.ccdpg_hdpol = params->hd_pol; + sync.ccdpg_vdpol = params->vd_pol; + dm365_vpss_set_sync_pol(sync); + frame_size.hlpfr = isif_cfg.bayer.win.width; + frame_size.pplen = isif_cfg.bayer.win.height; + dm365_vpss_set_pg_frame_size(frame_size); + vpss_select_ccdc_source(VPSS_PGLPBK); + } + + dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n"); + return 0; +} + +static int isif_set_buftype(enum ccdc_buftype buf_type) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + isif_cfg.bayer.buf_type = buf_type; + else + isif_cfg.ycbcr.buf_type = buf_type; + + return 0; + +} +static enum ccdc_buftype isif_get_buftype(void) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + return isif_cfg.bayer.buf_type; + + return isif_cfg.ycbcr.buf_type; +} + +static int isif_enum_pix(u32 *pix, int i) +{ + int ret = -EINVAL; + + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) { + *pix = isif_raw_bayer_pix_formats[i]; + ret = 0; + } + } else { + if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) { + *pix = isif_raw_yuv_pix_formats[i]; + ret = 0; + } + } + + return ret; +} + +static int isif_set_pixel_format(unsigned int pixfmt) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + if (pixfmt == V4L2_PIX_FMT_SBGGR8) { + if ((isif_cfg.bayer.config_params.compress.alg != + ISIF_ALAW) && + (isif_cfg.bayer.config_params.compress.alg != + ISIF_DPCM)) { + dev_dbg(isif_cfg.dev, + "Either configure A-Law or DPCM\n"); + return -EINVAL; + } + isif_cfg.data_pack = ISIF_PACK_8BIT; + } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { + isif_cfg.bayer.config_params.compress.alg = + ISIF_NO_COMPRESSION; + isif_cfg.data_pack = ISIF_PACK_16BIT; + } else + return -EINVAL; + isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + } else { + if (pixfmt == V4L2_PIX_FMT_YUYV) + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + else if (pixfmt == V4L2_PIX_FMT_UYVY) + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + else + return -EINVAL; + isif_cfg.data_pack = ISIF_PACK_8BIT; + } + return 0; +} + +static u32 isif_get_pixel_format(void) +{ + u32 pixfmt; + + if (isif_cfg.if_type == VPFE_RAW_BAYER) + if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW || + isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM) + pixfmt = V4L2_PIX_FMT_SBGGR8; + else + pixfmt = V4L2_PIX_FMT_SBGGR16; + else { + if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + return pixfmt; +} + +static int isif_set_image_window(struct v4l2_rect *win) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + isif_cfg.bayer.win.top = win->top; + isif_cfg.bayer.win.left = win->left; + isif_cfg.bayer.win.width = win->width; + isif_cfg.bayer.win.height = win->height; + } else { + isif_cfg.ycbcr.win.top = win->top; + isif_cfg.ycbcr.win.left = win->left; + isif_cfg.ycbcr.win.width = win->width; + isif_cfg.ycbcr.win.height = win->height; + } + return 0; +} + +static void isif_get_image_window(struct v4l2_rect *win) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + *win = isif_cfg.bayer.win; + else + *win = isif_cfg.ycbcr.win; +} + +static unsigned int isif_get_line_length(void) +{ + unsigned int len; + + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + if (isif_cfg.data_pack == ISIF_PACK_8BIT) + len = ((isif_cfg.bayer.win.width)); + else if (isif_cfg.data_pack == ISIF_PACK_12BIT) + len = (((isif_cfg.bayer.win.width * 2) + + (isif_cfg.bayer.win.width >> 2))); + else + len = (((isif_cfg.bayer.win.width * 2))); + } else + len = (((isif_cfg.ycbcr.win.width * 2))); + return ALIGN(len, 32); +} + +static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + isif_cfg.bayer.frm_fmt = frm_fmt; + else + isif_cfg.ycbcr.frm_fmt = frm_fmt; + return 0; +} +static enum ccdc_frmfmt isif_get_frame_format(void) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + return isif_cfg.bayer.frm_fmt; + return isif_cfg.ycbcr.frm_fmt; +} + +static int isif_getfid(void) +{ + return (regr(MODESET) >> 15) & 0x1; +} + +/* misc operations */ +static void isif_setfbaddr(unsigned long addr) +{ + regw((addr >> 21) & 0x07ff, CADU); + regw((addr >> 5) & 0x0ffff, CADL); +} + +static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) +{ + isif_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_BT656_10BIT: + case VPFE_YCBCR_SYNC_8: + isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + case VPFE_BT1120: + case VPFE_YCBCR_SYNC_16: + isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + case VPFE_RAW_BAYER: + isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + break; + default: + dev_dbg(isif_cfg.dev, "Invalid interface type\n"); + return -EINVAL; + } + + return 0; +} + +/* This function will configure ISIF for YCbCr parameters. */ +static int isif_config_ycbcr(void) +{ + struct isif_ycbcr_config *params = &isif_cfg.ycbcr; + struct vpss_pg_frame_size frame_size; + u32 modeset = 0, ccdcfg = 0; + struct vpss_sync_pol sync; + + dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); + + /* configure pixel format or input mode */ + modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) | + (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | + (params->fid_pol << ISIF_FID_POL_SHIFT) | + (params->hd_pol << ISIF_HD_POL_SHIFT) | + (params->vd_pol << ISIF_VD_POL_SHIFT); + + /* pack the data to 8-bit ISIFCFG */ + switch (isif_cfg.if_type) { + case VPFE_BT656: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT); + regw(3, REC656IF); + ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR; + break; + case VPFE_BT656_10BIT: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + /* setup BT.656, embedded sync */ + regw(3, REC656IF); + /* enable 10 bit mode in ccdcfg */ + ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR | + ISIF_BW656_ENABLE; + break; + case VPFE_BT1120: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + regw(3, REC656IF); + break; + + case VPFE_YCBCR_SYNC_8: + ccdcfg |= ISIF_DATA_PACK8; + ccdcfg |= ISIF_YCINSWP_YCBCR; + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + break; + case VPFE_YCBCR_SYNC_16: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + break; + default: + /* should never come here */ + dev_dbg(isif_cfg.dev, "Invalid interface type\n"); + return -EINVAL; + } + + regw(modeset, MODESET); + + /* Set up pix order */ + ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT; + + regw(ccdcfg, CCDCFG); + + /* configure video window */ + if ((isif_cfg.if_type == VPFE_BT1120) || + (isif_cfg.if_type == VPFE_YCBCR_SYNC_16)) + isif_setwin(¶ms->win, params->frm_fmt, 1); + else + isif_setwin(¶ms->win, params->frm_fmt, 2); + + /* + * configure the horizontal line offset + * this is done by rounding up width to a multiple of 16 pixels + * and multiply by two to account for y:cb:cr 4:2:2 data + */ + regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE); + + /* configure the memory line offset */ + if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) && + (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) + /* two fields are interleaved in memory */ + regw(0x00000249, SDOFST); + + /* Setup test pattern if enabled */ + if (isif_cfg.bayer.config_params.test_pat_gen) { + sync.ccdpg_hdpol = params->hd_pol; + sync.ccdpg_vdpol = params->vd_pol; + dm365_vpss_set_sync_pol(sync); + dm365_vpss_set_pg_frame_size(frame_size); + } + return 0; +} + +static int isif_configure(void) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + return isif_config_raw(); + return isif_config_ycbcr(); +} + +static int isif_close(struct device *device) +{ + /* copy defaults to module params */ + isif_cfg.bayer.config_params = isif_config_defaults; + return 0; +} + +static struct ccdc_hw_device isif_hw_dev = { + .name = "ISIF", + .owner = THIS_MODULE, + .hw_ops = { + .open = isif_open, + .close = isif_close, + .enable = isif_enable, + .enable_out_to_sdram = isif_enable_output_to_sdram, + .set_hw_if_params = isif_set_hw_if_params, + .configure = isif_configure, + .set_buftype = isif_set_buftype, + .get_buftype = isif_get_buftype, + .enum_pix = isif_enum_pix, + .set_pixel_format = isif_set_pixel_format, + .get_pixel_format = isif_get_pixel_format, + .set_frame_format = isif_set_frame_format, + .get_frame_format = isif_get_frame_format, + .set_image_window = isif_set_image_window, + .get_image_window = isif_get_image_window, + .get_line_length = isif_get_line_length, + .setfbaddr = isif_setfbaddr, + .getfid = isif_getfid, + }, +}; + +static int __init isif_probe(struct platform_device *pdev) +{ + void (*setup_pinmux)(void); + struct resource *res; + void *__iomem addr; + int status = 0, i; + + /* + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&isif_hw_dev); + if (status < 0) + return status; + + /* Get and enable Master clock */ + isif_cfg.mclk = clk_get(&pdev->dev, "master"); + if (IS_ERR(isif_cfg.mclk)) { + status = PTR_ERR(isif_cfg.mclk); + goto fail_mclk; + } + if (clk_enable(isif_cfg.mclk)) { + status = -ENODEV; + goto fail_mclk; + } + + /* Platform data holds setup_pinmux function ptr */ + if (NULL == pdev->dev.platform_data) { + status = -ENODEV; + goto fail_mclk; + } + setup_pinmux = pdev->dev.platform_data; + /* + * setup Mux configuration for ccdc which may be different for + * different SoCs using this CCDC + */ + setup_pinmux(); + + i = 0; + /* Get the ISIF base address, linearization table0 and table1 addr. */ + while (i < 3) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) { + status = -ENODEV; + goto fail_nobase_res; + } + res = request_mem_region(res->start, resource_size(res), + res->name); + if (!res) { + status = -EBUSY; + goto fail_nobase_res; + } + addr = ioremap_nocache(res->start, resource_size(res)); + if (!addr) { + status = -ENOMEM; + goto fail_base_iomap; + } + switch (i) { + case 0: + /* ISIF base address */ + isif_cfg.base_addr = addr; + break; + case 1: + /* ISIF linear tbl0 address */ + isif_cfg.linear_tbl0_addr = addr; + break; + default: + /* ISIF linear tbl0 address */ + isif_cfg.linear_tbl1_addr = addr; + break; + } + i++; + } + isif_cfg.dev = &pdev->dev; + + printk(KERN_NOTICE "%s is registered with vpfe.\n", + isif_hw_dev.name); + return 0; +fail_base_iomap: + release_mem_region(res->start, resource_size(res)); + i--; +fail_nobase_res: + if (isif_cfg.base_addr) + iounmap(isif_cfg.base_addr); + if (isif_cfg.linear_tbl0_addr) + iounmap(isif_cfg.linear_tbl0_addr); + + while (i >= 0) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + release_mem_region(res->start, resource_size(res)); + i--; + } +fail_mclk: + clk_put(isif_cfg.mclk); + vpfe_unregister_ccdc_device(&isif_hw_dev); + return status; +} + +static int isif_remove(struct platform_device *pdev) +{ + struct resource *res; + int i = 0; + + iounmap(isif_cfg.base_addr); + iounmap(isif_cfg.linear_tbl0_addr); + iounmap(isif_cfg.linear_tbl1_addr); + while (i < 3) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (res) + release_mem_region(res->start, resource_size(res)); + i++; + } + vpfe_unregister_ccdc_device(&isif_hw_dev); + return 0; +} + +static struct platform_driver isif_driver = { + .driver = { + .name = "isif", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(isif_remove), + .probe = isif_probe, +}; + +static int __init isif_init(void) +{ + return platform_driver_register(&isif_driver); +} + +static void isif_exit(void) +{ + platform_driver_unregister(&isif_driver); +} + +module_init(isif_init); +module_exit(isif_exit); + +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/isif_regs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/isif_regs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/isif_regs.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/isif_regs.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + */ +#ifndef _ISIF_REGS_H +#define _ISIF_REGS_H + +/* ISIF registers relative offsets */ +#define SYNCEN 0x00 +#define MODESET 0x04 +#define HDW 0x08 +#define VDW 0x0c +#define PPLN 0x10 +#define LPFR 0x14 +#define SPH 0x18 +#define LNH 0x1c +#define SLV0 0x20 +#define SLV1 0x24 +#define LNV 0x28 +#define CULH 0x2c +#define CULV 0x30 +#define HSIZE 0x34 +#define SDOFST 0x38 +#define CADU 0x3c +#define CADL 0x40 +#define LINCFG0 0x44 +#define LINCFG1 0x48 +#define CCOLP 0x4c +#define CRGAIN 0x50 +#define CGRGAIN 0x54 +#define CGBGAIN 0x58 +#define CBGAIN 0x5c +#define COFSTA 0x60 +#define FLSHCFG0 0x64 +#define FLSHCFG1 0x68 +#define FLSHCFG2 0x6c +#define VDINT0 0x70 +#define VDINT1 0x74 +#define VDINT2 0x78 +#define MISC 0x7c +#define CGAMMAWD 0x80 +#define REC656IF 0x84 +#define CCDCFG 0x88 +/***************************************************** +* Defect Correction registers +*****************************************************/ +#define DFCCTL 0x8c +#define VDFSATLV 0x90 +#define DFCMEMCTL 0x94 +#define DFCMEM0 0x98 +#define DFCMEM1 0x9c +#define DFCMEM2 0xa0 +#define DFCMEM3 0xa4 +#define DFCMEM4 0xa8 +/**************************************************** +* Black Clamp registers +****************************************************/ +#define CLAMPCFG 0xac +#define CLDCOFST 0xb0 +#define CLSV 0xb4 +#define CLHWIN0 0xb8 +#define CLHWIN1 0xbc +#define CLHWIN2 0xc0 +#define CLVRV 0xc4 +#define CLVWIN0 0xc8 +#define CLVWIN1 0xcc +#define CLVWIN2 0xd0 +#define CLVWIN3 0xd4 +/**************************************************** +* Lense Shading Correction +****************************************************/ +#define DATAHOFST 0xd8 +#define DATAVOFST 0xdc +#define LSCHVAL 0xe0 +#define LSCVVAL 0xe4 +#define TWODLSCCFG 0xe8 +#define TWODLSCOFST 0xec +#define TWODLSCINI 0xf0 +#define TWODLSCGRBU 0xf4 +#define TWODLSCGRBL 0xf8 +#define TWODLSCGROF 0xfc +#define TWODLSCORBU 0x100 +#define TWODLSCORBL 0x104 +#define TWODLSCOROF 0x108 +#define TWODLSCIRQEN 0x10c +#define TWODLSCIRQST 0x110 +/**************************************************** +* Data formatter +****************************************************/ +#define FMTCFG 0x114 +#define FMTPLEN 0x118 +#define FMTSPH 0x11c +#define FMTLNH 0x120 +#define FMTSLV 0x124 +#define FMTLNV 0x128 +#define FMTRLEN 0x12c +#define FMTHCNT 0x130 +#define FMTAPTR_BASE 0x134 +/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ +#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) +#define FMTPGMVF0 0x174 +#define FMTPGMVF1 0x178 +#define FMTPGMAPU0 0x17c +#define FMTPGMAPU1 0x180 +#define FMTPGMAPS0 0x184 +#define FMTPGMAPS1 0x188 +#define FMTPGMAPS2 0x18c +#define FMTPGMAPS3 0x190 +#define FMTPGMAPS4 0x194 +#define FMTPGMAPS5 0x198 +#define FMTPGMAPS6 0x19c +#define FMTPGMAPS7 0x1a0 +/************************************************ +* Color Space Converter +************************************************/ +#define CSCCTL 0x1a4 +#define CSCM0 0x1a8 +#define CSCM1 0x1ac +#define CSCM2 0x1b0 +#define CSCM3 0x1b4 +#define CSCM4 0x1b8 +#define CSCM5 0x1bc +#define CSCM6 0x1c0 +#define CSCM7 0x1c4 +#define OBWIN0 0x1c8 +#define OBWIN1 0x1cc +#define OBWIN2 0x1d0 +#define OBWIN3 0x1d4 +#define OBVAL0 0x1d8 +#define OBVAL1 0x1dc +#define OBVAL2 0x1e0 +#define OBVAL3 0x1e4 +#define OBVAL4 0x1e8 +#define OBVAL5 0x1ec +#define OBVAL6 0x1f0 +#define OBVAL7 0x1f4 +#define CLKCTL 0x1f8 + +/* Masks & Shifts below */ +#define START_PX_HOR_MASK 0x7FFF +#define NUM_PX_HOR_MASK 0x7FFF +#define START_VER_ONE_MASK 0x7FFF +#define START_VER_TWO_MASK 0x7FFF +#define NUM_LINES_VER 0x7FFF + +/* gain - offset masks */ +#define GAIN_INTEGER_SHIFT 9 +#define OFFSET_MASK 0xFFF +#define GAIN_SDRAM_EN_SHIFT 12 +#define GAIN_IPIPE_EN_SHIFT 13 +#define GAIN_H3A_EN_SHIFT 14 +#define OFST_SDRAM_EN_SHIFT 8 +#define OFST_IPIPE_EN_SHIFT 9 +#define OFST_H3A_EN_SHIFT 10 +#define GAIN_OFFSET_EN_MASK 0x7700 + +/* Culling */ +#define CULL_PAT_EVEN_LINE_SHIFT 8 + +/* CCDCFG register */ +#define ISIF_YCINSWP_RAW (0x00 << 4) +#define ISIF_YCINSWP_YCBCR (0x01 << 4) +#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) +#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) +#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) +#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) +#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) +#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) +#define ISIF_DATA_PACK_MASK 3 +#define ISIF_DATA_PACK16 0 +#define ISIF_DATA_PACK12 1 +#define ISIF_DATA_PACK8 2 +#define ISIF_PIX_ORDER_SHIFT 11 +#define ISIF_BW656_ENABLE (0x01 << 5) + +/* MODESET registers */ +#define ISIF_VDHDOUT_INPUT (0x00 << 0) +#define ISIF_INPUT_SHIFT 12 +#define ISIF_RAW_INPUT_MODE 0 +#define ISIF_FID_POL_SHIFT 4 +#define ISIF_HD_POL_SHIFT 3 +#define ISIF_VD_POL_SHIFT 2 +#define ISIF_DATAPOL_NORMAL 0 +#define ISIF_DATAPOL_SHIFT 6 +#define ISIF_EXWEN_DISABLE 0 +#define ISIF_EXWEN_SHIFT 5 +#define ISIF_FRM_FMT_SHIFT 7 +#define ISIF_DATASFT_SHIFT 8 +#define ISIF_LPF_SHIFT 14 +#define ISIF_LPF_MASK 1 + +/* GAMMAWD registers */ +#define ISIF_ALAW_GAMA_WD_MASK 0xF +#define ISIF_ALAW_GAMA_WD_SHIFT 1 +#define ISIF_ALAW_ENABLE 1 +#define ISIF_GAMMAWD_CFA_SHIFT 5 + +/* HSIZE registers */ +#define ISIF_HSIZE_FLIP_MASK 1 +#define ISIF_HSIZE_FLIP_SHIFT 12 + +/* MISC registers */ +#define ISIF_DPCM_EN_SHIFT 12 +#define ISIF_DPCM_PREDICTOR_SHIFT 13 + +/* Black clamp related */ +#define ISIF_BC_MODE_COLOR_SHIFT 4 +#define ISIF_HORZ_BC_MODE_SHIFT 1 +#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 +#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 +#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 +#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 +#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 +#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 + +/* VDFC registers */ +#define ISIF_VDFC_EN_SHIFT 4 +#define ISIF_VDFC_CORR_MOD_SHIFT 5 +#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 +#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 +#define ISIF_VDFC_POS_MASK 0x1FFF +#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 + +/* CSC registers */ +#define ISIF_CSC_COEF_INTEG_MASK 7 +#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f +#define ISIF_CSC_COEF_INTEG_SHIFT 5 +#define ISIF_CSCM_MSB_SHIFT 8 +#define ISIF_DF_CSC_SPH_MASK 0x1FFF +#define ISIF_DF_CSC_LNH_MASK 0x1FFF +#define ISIF_DF_CSC_SLV_MASK 0x1FFF +#define ISIF_DF_CSC_LNV_MASK 0x1FFF +#define ISIF_DF_NUMLINES 0x7FFF +#define ISIF_DF_NUMPIX 0x1FFF + +/* Offsets for LSC/DFC/Gain */ +#define ISIF_DATA_H_OFFSET_MASK 0x1FFF +#define ISIF_DATA_V_OFFSET_MASK 0x1FFF + +/* Linearization */ +#define ISIF_LIN_CORRSFT_SHIFT 4 +#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 + + +/* Pattern registers */ +#define ISIF_PG_EN (1 << 3) +#define ISIF_SEL_PG_SRC (3 << 4) +#define ISIF_PG_VD_POL_SHIFT 0 +#define ISIF_PG_HD_POL_SHIFT 1 + +/*random other junk*/ +#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) +#define ISIF_SYNCEN_WEN_MASK (1 << 1) +#define ISIF_SYNCEN_WEN_SHIFT 1 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,93 @@ +config DISPLAY_DAVINCI_DM646X_EVM + tristate "DM646x EVM Video Display" + depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM + select VIDEOBUF_DMA_CONTIG + select VIDEO_DAVINCI_VPIF + select VIDEO_ADV7343 + select VIDEO_THS7303 + help + Support for DM6467 based display device. + + To compile this driver as a module, choose M here: the + module will be called vpif_display. + +config CAPTURE_DAVINCI_DM646X_EVM + tristate "DM646x EVM Video Capture" + depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM + select VIDEOBUF_DMA_CONTIG + select VIDEO_DAVINCI_VPIF + help + Support for DM6467 based capture device. + + To compile this driver as a module, choose M here: the + module will be called vpif_capture. + +config VIDEO_DAVINCI_VPIF + tristate "DaVinci VPIF Driver" + depends on DISPLAY_DAVINCI_DM646X_EVM + help + Support for DaVinci VPIF Driver. + + To compile this driver as a module, choose M here: the + module will be called vpif. + +config VIDEO_VPSS_SYSTEM + tristate "VPSS System module driver" + depends on ARCH_DAVINCI + help + Support for vpss system module for video driver + +config VIDEO_VPFE_CAPTURE + tristate "VPFE Video Capture Driver" + depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3) + select VIDEOBUF_DMA_CONTIG + help + Support for DMx/AMx VPFE based frame grabber. This is the + common V4L2 module for following DMx/AMx SoCs from Texas + Instruments:- DM6446, DM365, DM355 & AM3517/05. + + To compile this driver as a module, choose M here: the + module will be called vpfe-capture. + +config VIDEO_DM6446_CCDC + tristate "DM6446 CCDC HW module" + depends on VIDEO_VPFE_CAPTURE + select VIDEO_VPSS_SYSTEM + default y + help + Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces + with decoder modules such as TVP5146 over BT656 or + sensor module such as MT9T001 over a raw interface. This + module configures the interface and CCDC/ISIF to do + video frame capture from slave decoders. + + To compile this driver as a module, choose M here: the + module will be called vpfe. + +config VIDEO_DM355_CCDC + tristate "DM355 CCDC HW module" + depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE + select VIDEO_VPSS_SYSTEM + default y + help + Enables DM355 CCD hw module. DM355 CCDC hw interfaces + with decoder modules such as TVP5146 over BT656 or + sensor module such as MT9T001 over a raw interface. This + module configures the interface and CCDC/ISIF to do + video frame capture from a slave decoders + + To compile this driver as a module, choose M here: the + module will be called vpfe. + +config VIDEO_ISIF + tristate "ISIF HW module" + depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE + select VIDEO_VPSS_SYSTEM + default y + help + Enables ISIF hw module. This is the hardware module for + configuring ISIF in VPFE to capture Raw Bayer RGB data from + a image sensor or YUV data from a YUV source. + + To compile this driver as a module, choose M here: the + module will be called vpfe. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,18 @@ +# +# Makefile for the davinci video device drivers. +# + +# VPIF +obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o + +#DM646x EVM Display driver +obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o +#DM646x EVM Capture driver +obj-$(CONFIG_CAPTURE_DAVINCI_DM646X_EVM) += vpif_capture.o + +# Capture: DM6446 and DM355 +obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o +obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o +obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o +obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o +obj-$(CONFIG_VIDEO_ISIF) += isif.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpfe_capture.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpfe_capture.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpfe_capture.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpfe_capture.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2095 @@ +/* + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * Driver name : VPFE Capture driver + * VPFE Capture driver allows applications to capture and stream video + * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as + * TVP5146 or Raw Bayer RGB image data from an image sensor + * such as Microns' MT9T001, MT9T031 etc. + * + * These SoCs have, in common, a Video Processing Subsystem (VPSS) that + * consists of a Video Processing Front End (VPFE) for capturing + * video/raw image data and Video Processing Back End (VPBE) for displaying + * YUV data through an in-built analog encoder or Digital LCD port. This + * driver is for capture through VPFE. A typical EVM using these SoCs have + * following high level configuration. + * + * + * decoder(TVP5146/ YUV/ + * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) + * data input | | + * V | + * SDRAM | + * V + * Image Processor + * | + * V + * SDRAM + * The data flow happens from a decoder connected to the VPFE over a + * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface + * and to the input of VPFE through an optional MUX (if more inputs are + * to be interfaced on the EVM). The input data is first passed through + * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC + * does very little or no processing on YUV data and does pre-process Raw + * Bayer RGB data through modules such as Defect Pixel Correction (DFC) + * Color Space Conversion (CSC), data gain/offset etc. After this, data + * can be written to SDRAM or can be connected to the image processing + * block such as IPIPE (on DM355 only). + * + * Features supported + * - MMAP IO + * - Capture using TVP5146 over BT.656 + * - support for interfacing decoders using sub device model + * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV + * data capture to SDRAM. + * TODO list + * - Support multiple REQBUF after open + * - Support for de-allocating buffers through REQBUF + * - Support for Raw Bayer RGB capture + * - Support for chaining Image Processor + * - Support for static allocation of buffers + * - Support for USERPTR IO + * - Support for STREAMON before QBUF + * - Support for control ioctls + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ccdc_hw_device.h" + +static int debug; +static u32 numbuffers = 3; +static u32 bufsize = (720 * 576 * 2); + +module_param(numbuffers, uint, S_IRUGO); +module_param(bufsize, uint, S_IRUGO); +module_param(debug, int, 0644); + +MODULE_PARM_DESC(numbuffers, "buffer count (default:3)"); +MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)"); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); + +/* standard information */ +struct vpfe_standard { + v4l2_std_id std_id; + unsigned int width; + unsigned int height; + struct v4l2_fract pixelaspect; + /* 0 - progressive, 1 - interlaced */ + int frame_format; +}; + +/* ccdc configuration */ +struct ccdc_config { + /* This make sure vpfe is probed and ready to go */ + int vpfe_probed; + /* name of ccdc device */ + char name[32]; +}; + +/* data structures */ +static struct vpfe_config_params config_params = { + .min_numbuffers = 3, + .numbuffers = 3, + .min_bufsize = 720 * 480 * 2, + .device_bufsize = 720 * 576 * 2, +}; + +/* ccdc device registered */ +static struct ccdc_hw_device *ccdc_dev; +/* lock for accessing ccdc information */ +static DEFINE_MUTEX(ccdc_lock); +/* ccdc configuration */ +static struct ccdc_config *ccdc_cfg; + +const struct vpfe_standard vpfe_standards[] = { + {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, + {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, +}; + +/* Used when raw Bayer image from ccdc is directly captured to SDRAM */ +static const struct vpfe_pixel_format vpfe_pix_fmts[] = { + { + .fmtdesc = { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "Bayer GrRBGb 8bit A-Law compr.", + .pixelformat = V4L2_PIX_FMT_SBGGR8, + }, + .bpp = 1, + }, + { + .fmtdesc = { + .index = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "Bayer GrRBGb - 16bit", + .pixelformat = V4L2_PIX_FMT_SBGGR16, + }, + .bpp = 2, + }, + { + .fmtdesc = { + .index = 2, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "Bayer GrRBGb 8bit DPCM compr.", + .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, + }, + .bpp = 1, + }, + { + .fmtdesc = { + .index = 3, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "YCbCr 4:2:2 Interleaved UYVY", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, + .bpp = 2, + }, + { + .fmtdesc = { + .index = 4, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "YCbCr 4:2:2 Interleaved YUYV", + .pixelformat = V4L2_PIX_FMT_YUYV, + }, + .bpp = 2, + }, + { + .fmtdesc = { + .index = 5, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "Y/CbCr 4:2:0 - Semi planar", + .pixelformat = V4L2_PIX_FMT_NV12, + }, + .bpp = 1, + }, +}; + +/* + * vpfe_lookup_pix_format() + * lookup an entry in the vpfe pix format table based on pix_format + */ +static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { + if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat) + return &vpfe_pix_fmts[i]; + } + return NULL; +} + +/* + * vpfe_register_ccdc_device. CCDC module calls this to + * register with vpfe capture + */ +int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) +{ + int ret = 0; + printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); + + BUG_ON(!dev->hw_ops.open); + BUG_ON(!dev->hw_ops.enable); + BUG_ON(!dev->hw_ops.set_hw_if_params); + BUG_ON(!dev->hw_ops.configure); + BUG_ON(!dev->hw_ops.set_buftype); + BUG_ON(!dev->hw_ops.get_buftype); + BUG_ON(!dev->hw_ops.enum_pix); + BUG_ON(!dev->hw_ops.set_frame_format); + BUG_ON(!dev->hw_ops.get_frame_format); + BUG_ON(!dev->hw_ops.get_pixel_format); + BUG_ON(!dev->hw_ops.set_pixel_format); + BUG_ON(!dev->hw_ops.set_image_window); + BUG_ON(!dev->hw_ops.get_image_window); + BUG_ON(!dev->hw_ops.get_line_length); + BUG_ON(!dev->hw_ops.getfid); + + mutex_lock(&ccdc_lock); + if (NULL == ccdc_cfg) { + /* + * TODO. Will this ever happen? if so, we need to fix it. + * Proabably we need to add the request to a linked list and + * walk through it during vpfe probe + */ + printk(KERN_ERR "vpfe capture not initialized\n"); + ret = -EFAULT; + goto unlock; + } + + if (strcmp(dev->name, ccdc_cfg->name)) { + /* ignore this ccdc */ + ret = -EINVAL; + goto unlock; + } + + if (ccdc_dev) { + printk(KERN_ERR "ccdc already registered\n"); + ret = -EINVAL; + goto unlock; + } + + ccdc_dev = dev; +unlock: + mutex_unlock(&ccdc_lock); + return ret; +} +EXPORT_SYMBOL(vpfe_register_ccdc_device); + +/* + * vpfe_unregister_ccdc_device. CCDC module calls this to + * unregister with vpfe capture + */ +void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) +{ + if (NULL == dev) { + printk(KERN_ERR "invalid ccdc device ptr\n"); + return; + } + + printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n", + dev->name); + + if (strcmp(dev->name, ccdc_cfg->name)) { + /* ignore this ccdc */ + return; + } + + mutex_lock(&ccdc_lock); + ccdc_dev = NULL; + mutex_unlock(&ccdc_lock); + return; +} +EXPORT_SYMBOL(vpfe_unregister_ccdc_device); + +/* + * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings + */ +static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev, + struct v4l2_format *f) +{ + struct v4l2_rect image_win; + enum ccdc_buftype buf_type; + enum ccdc_frmfmt frm_fmt; + + memset(f, 0, sizeof(*f)); + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + ccdc_dev->hw_ops.get_image_window(&image_win); + f->fmt.pix.width = image_win.width; + f->fmt.pix.height = image_win.height; + f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height; + buf_type = ccdc_dev->hw_ops.get_buftype(); + f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format(); + frm_fmt = ccdc_dev->hw_ops.get_frame_format(); + if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE) + f->fmt.pix.field = V4L2_FIELD_NONE; + else if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED) + f->fmt.pix.field = V4L2_FIELD_SEQ_TB; + else { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n"); + return -EINVAL; + } + } else { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n"); + return -EINVAL; + } + return 0; +} + +/* + * vpfe_config_ccdc_image_format() + * For a pix format, configure ccdc to setup the capture + */ +static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) +{ + enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; + int ret = 0; + + if (ccdc_dev->hw_ops.set_pixel_format( + vpfe_dev->fmt.fmt.pix.pixelformat) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "couldn't set pix format in ccdc\n"); + return -EINVAL; + } + /* configure the image window */ + ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop); + + switch (vpfe_dev->fmt.fmt.pix.field) { + case V4L2_FIELD_INTERLACED: + /* do nothing, since it is default */ + ret = ccdc_dev->hw_ops.set_buftype( + CCDC_BUFTYPE_FLD_INTERLEAVED); + break; + case V4L2_FIELD_NONE: + frm_fmt = CCDC_FRMFMT_PROGRESSIVE; + /* buffer type only applicable for interlaced scan */ + break; + case V4L2_FIELD_SEQ_TB: + ret = ccdc_dev->hw_ops.set_buftype( + CCDC_BUFTYPE_FLD_SEPARATED); + break; + default: + return -EINVAL; + } + + /* set the frame format */ + if (!ret) + ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt); + return ret; +} +/* + * vpfe_config_image_format() + * For a given standard, this functions sets up the default + * pix format & crop values in the vpfe device and ccdc. It first + * starts with defaults based values from the standard table. + * It then checks if sub device support g_mbus_fmt and then override the + * values based on that.Sets crop values to match with scan resolution + * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the + * values in ccdc + */ +static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, + const v4l2_std_id *std_id) +{ + struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; + struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix; + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { + if (vpfe_standards[i].std_id & *std_id) { + vpfe_dev->std_info.active_pixels = + vpfe_standards[i].width; + vpfe_dev->std_info.active_lines = + vpfe_standards[i].height; + vpfe_dev->std_info.frame_format = + vpfe_standards[i].frame_format; + vpfe_dev->std_index = i; + break; + } + } + + if (i == ARRAY_SIZE(vpfe_standards)) { + v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n"); + return -EINVAL; + } + + vpfe_dev->crop.top = 0; + vpfe_dev->crop.left = 0; + vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels; + vpfe_dev->crop.height = vpfe_dev->std_info.active_lines; + pix->width = vpfe_dev->crop.width; + pix->height = vpfe_dev->crop.height; + + /* first field and frame format based on standard frame format */ + if (vpfe_dev->std_info.frame_format) { + pix->field = V4L2_FIELD_INTERLACED; + /* assume V4L2_PIX_FMT_UYVY as default */ + pix->pixelformat = V4L2_PIX_FMT_UYVY; + v4l2_fill_mbus_format(&mbus_fmt, pix, + V4L2_MBUS_FMT_YUYV10_2X10); + } else { + pix->field = V4L2_FIELD_NONE; + /* assume V4L2_PIX_FMT_SBGGR8 */ + pix->pixelformat = V4L2_PIX_FMT_SBGGR8; + v4l2_fill_mbus_format(&mbus_fmt, pix, + V4L2_MBUS_FMT_SBGGR8_1X8); + } + + /* if sub device supports g_mbus_fmt, override the defaults */ + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, + sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt); + + if (ret && ret != -ENOIOCTLCMD) { + v4l2_err(&vpfe_dev->v4l2_dev, + "error in getting g_mbus_fmt from sub device\n"); + return ret; + } + v4l2_fill_pix_format(pix, &mbus_fmt); + pix->bytesperline = pix->width * 2; + pix->sizeimage = pix->bytesperline * pix->height; + + /* Sets the values in CCDC */ + ret = vpfe_config_ccdc_image_format(vpfe_dev); + if (ret) + return ret; + + /* Update the values of sizeimage and bytesperline */ + if (!ret) { + pix->bytesperline = ccdc_dev->hw_ops.get_line_length(); + pix->sizeimage = pix->bytesperline * pix->height; + } + return ret; +} + +static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) +{ + int ret = 0; + + /* set first input of current subdevice as the current input */ + vpfe_dev->current_input = 0; + + /* set default standard */ + vpfe_dev->std_index = 0; + + /* Configure the default format information */ + ret = vpfe_config_image_format(vpfe_dev, + &vpfe_standards[vpfe_dev->std_index].std_id); + if (ret) + return ret; + + /* now open the ccdc device to initialize it */ + mutex_lock(&ccdc_lock); + if (NULL == ccdc_dev) { + v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n"); + ret = -ENODEV; + goto unlock; + } + + if (!try_module_get(ccdc_dev->owner)) { + v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n"); + ret = -ENODEV; + goto unlock; + } + ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev); + if (!ret) + vpfe_dev->initialized = 1; + + /* Clear all VPFE/CCDC interrupts */ + if (vpfe_dev->cfg->clr_intr) + vpfe_dev->cfg->clr_intr(-1); + +unlock: + mutex_unlock(&ccdc_lock); + return ret; +} + +/* + * vpfe_open : It creates object of file handle structure and + * stores it in private_data member of filepointer + */ +static int vpfe_open(struct file *file) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n"); + + if (!vpfe_dev->cfg->num_subdevs) { + v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n"); + return -ENODEV; + } + + /* Allocate memory for the file handle object */ + fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL); + if (NULL == fh) { + v4l2_err(&vpfe_dev->v4l2_dev, + "unable to allocate memory for file handle object\n"); + return -ENOMEM; + } + /* store pointer to fh in private_data member of file */ + file->private_data = fh; + fh->vpfe_dev = vpfe_dev; + mutex_lock(&vpfe_dev->lock); + /* If decoder is not initialized. initialize it */ + if (!vpfe_dev->initialized) { + if (vpfe_initialize_device(vpfe_dev)) { + mutex_unlock(&vpfe_dev->lock); + return -ENODEV; + } + } + /* Increment device usrs counter */ + vpfe_dev->usrs++; + /* Set io_allowed member to false */ + fh->io_allowed = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&vpfe_dev->prio, &fh->prio); + mutex_unlock(&vpfe_dev->lock); + return 0; +} + +static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev) +{ + unsigned long addr; + + vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, + struct videobuf_buffer, queue); + list_del(&vpfe_dev->next_frm->queue); + vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE; + addr = videobuf_to_dma_contig(vpfe_dev->next_frm); + + ccdc_dev->hw_ops.setfbaddr(addr); +} + +static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev) +{ + unsigned long addr; + + addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); + addr += vpfe_dev->field_off; + ccdc_dev->hw_ops.setfbaddr(addr); +} + +static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev) +{ + struct timeval timevalue; + + do_gettimeofday(&timevalue); + vpfe_dev->cur_frm->ts = timevalue; + vpfe_dev->cur_frm->state = VIDEOBUF_DONE; + vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage; + wake_up_interruptible(&vpfe_dev->cur_frm->done); + vpfe_dev->cur_frm = vpfe_dev->next_frm; +} + +/* ISR for VINT0*/ +static irqreturn_t vpfe_isr(int irq, void *dev_id) +{ + struct vpfe_device *vpfe_dev = dev_id; + enum v4l2_field field; + int fid; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n"); + field = vpfe_dev->fmt.fmt.pix.field; + + /* if streaming not started, don't do anything */ + if (!vpfe_dev->started) + goto clear_intr; + + /* only for 6446 this will be applicable */ + if (NULL != ccdc_dev->hw_ops.reset) + ccdc_dev->hw_ops.reset(); + + if (field == V4L2_FIELD_NONE) { + /* handle progressive frame capture */ + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "frame format is progressive...\n"); + if (vpfe_dev->cur_frm != vpfe_dev->next_frm) + vpfe_process_buffer_complete(vpfe_dev); + goto clear_intr; + } + + /* interlaced or TB capture check which field we are in hardware */ + fid = ccdc_dev->hw_ops.getfid(); + + /* switch the software maintained field id */ + vpfe_dev->field_id ^= 1; + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n", + fid, vpfe_dev->field_id); + if (fid == vpfe_dev->field_id) { + /* we are in-sync here,continue */ + if (fid == 0) { + /* + * One frame is just being captured. If the next frame + * is available, release the current frame and move on + */ + if (vpfe_dev->cur_frm != vpfe_dev->next_frm) + vpfe_process_buffer_complete(vpfe_dev); + /* + * based on whether the two fields are stored + * interleavely or separately in memory, reconfigure + * the CCDC memory address + */ + if (field == V4L2_FIELD_SEQ_TB) { + vpfe_schedule_bottom_field(vpfe_dev); + } + goto clear_intr; + } + /* + * if one field is just being captured configure + * the next frame get the next frame from the empty + * queue if no frame is available hold on to the + * current buffer + */ + spin_lock(&vpfe_dev->dma_queue_lock); + if (!list_empty(&vpfe_dev->dma_queue) && + vpfe_dev->cur_frm == vpfe_dev->next_frm) + vpfe_schedule_next_buffer(vpfe_dev); + spin_unlock(&vpfe_dev->dma_queue_lock); + } else if (fid == 0) { + /* + * out of sync. Recover from any hardware out-of-sync. + * May loose one frame + */ + vpfe_dev->field_id = fid; + } +clear_intr: + if (vpfe_dev->cfg->clr_intr) + vpfe_dev->cfg->clr_intr(irq); + + return IRQ_HANDLED; +} + +/* vdint1_isr - isr handler for VINT1 interrupt */ +static irqreturn_t vdint1_isr(int irq, void *dev_id) +{ + struct vpfe_device *vpfe_dev = dev_id; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n"); + + /* if streaming not started, don't do anything */ + if (!vpfe_dev->started) { + if (vpfe_dev->cfg->clr_intr) + vpfe_dev->cfg->clr_intr(irq); + return IRQ_HANDLED; + } + + spin_lock(&vpfe_dev->dma_queue_lock); + if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) && + !list_empty(&vpfe_dev->dma_queue) && + vpfe_dev->cur_frm == vpfe_dev->next_frm) + vpfe_schedule_next_buffer(vpfe_dev); + spin_unlock(&vpfe_dev->dma_queue_lock); + + if (vpfe_dev->cfg->clr_intr) + vpfe_dev->cfg->clr_intr(irq); + + return IRQ_HANDLED; +} + +static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) +{ + enum ccdc_frmfmt frame_format; + + frame_format = ccdc_dev->hw_ops.get_frame_format(); + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) + free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); +} + +static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) +{ + enum ccdc_frmfmt frame_format; + + frame_format = ccdc_dev->hw_ops.get_frame_format(); + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) { + return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr, + IRQF_DISABLED, "vpfe_capture1", + vpfe_dev); + } + return 0; +} + +/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */ +static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev) +{ + vpfe_dev->started = 0; + ccdc_dev->hw_ops.enable(0); + if (ccdc_dev->hw_ops.enable_out_to_sdram) + ccdc_dev->hw_ops.enable_out_to_sdram(0); +} + +/* + * vpfe_release : This function deletes buffer queue, frees the + * buffers and the vpfe file handle + */ +static int vpfe_release(struct file *file) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + struct vpfe_subdev_info *sdinfo; + int ret; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); + + /* Get the device lock */ + mutex_lock(&vpfe_dev->lock); + /* if this instance is doing IO */ + if (fh->io_allowed) { + if (vpfe_dev->started) { + sdinfo = vpfe_dev->current_subdev; + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, + sdinfo->grp_id, + video, s_stream, 0); + if (ret && (ret != -ENOIOCTLCMD)) + v4l2_err(&vpfe_dev->v4l2_dev, + "stream off failed in subdev\n"); + vpfe_stop_ccdc_capture(vpfe_dev); + vpfe_detach_irq(vpfe_dev); + videobuf_streamoff(&vpfe_dev->buffer_queue); + } + vpfe_dev->io_usrs = 0; + vpfe_dev->numbuffers = config_params.numbuffers; + } + + /* Decrement device usrs counter */ + vpfe_dev->usrs--; + /* Close the priority */ + v4l2_prio_close(&vpfe_dev->prio, fh->prio); + /* If this is the last file handle */ + if (!vpfe_dev->usrs) { + vpfe_dev->initialized = 0; + if (ccdc_dev->hw_ops.close) + ccdc_dev->hw_ops.close(vpfe_dev->pdev); + module_put(ccdc_dev->owner); + } + mutex_unlock(&vpfe_dev->lock); + file->private_data = NULL; + /* Free memory allocated to file handle object */ + kfree(fh); + return 0; +} + +/* + * vpfe_mmap : It is used to map kernel space buffers + * into user spaces + */ +static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) +{ + /* Get the device object and file handle object */ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); + + return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma); +} + +/* + * vpfe_poll: It is used for select/poll system call + */ +static unsigned int vpfe_poll(struct file *file, poll_table *wait) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); + + if (vpfe_dev->started) + return videobuf_poll_stream(file, + &vpfe_dev->buffer_queue, wait); + return 0; +} + +/* vpfe capture driver file operations */ +static const struct v4l2_file_operations vpfe_fops = { + .owner = THIS_MODULE, + .open = vpfe_open, + .release = vpfe_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vpfe_mmap, + .poll = vpfe_poll +}; + +/* + * vpfe_check_format() + * This function adjust the input pixel format as per hardware + * capabilities and update the same in pixfmt. + * Following algorithm used :- + * + * If given pixformat is not in the vpfe list of pix formats or not + * supported by the hardware, current value of pixformat in the device + * is used + * If given field is not supported, then current field is used. If field + * is different from current, then it is matched with that from sub device. + * Minimum height is 2 lines for interlaced or tb field and 1 line for + * progressive. Maximum height is clamped to active active lines of scan + * Minimum width is 32 bytes in memory and width is clamped to active + * pixels of scan. + * bytesperline is a multiple of 32. + */ +static const struct vpfe_pixel_format * + vpfe_check_format(struct vpfe_device *vpfe_dev, + struct v4l2_pix_format *pixfmt) +{ + u32 min_height = 1, min_width = 32, max_width, max_height; + const struct vpfe_pixel_format *vpfe_pix_fmt; + u32 pix; + int temp, found; + + vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); + if (NULL == vpfe_pix_fmt) { + /* + * use current pixel format in the vpfe device. We + * will find this pix format in the table + */ + pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; + vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); + } + + /* check if hw supports it */ + temp = 0; + found = 0; + while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { + if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) { + found = 1; + break; + } + temp++; + } + + if (!found) { + /* use current pixel format */ + pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; + /* + * Since this is currently used in the vpfe device, we + * will find this pix format in the table + */ + vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); + } + + /* check what field format is supported */ + if (pixfmt->field == V4L2_FIELD_ANY) { + /* if field is any, use current value as default */ + pixfmt->field = vpfe_dev->fmt.fmt.pix.field; + } + + /* + * if field is not same as current field in the vpfe device + * try matching the field with the sub device field + */ + if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) { + /* + * If field value is not in the supported fields, use current + * field used in the device as default + */ + switch (pixfmt->field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_SEQ_TB: + /* if sub device is supporting progressive, use that */ + if (!vpfe_dev->std_info.frame_format) + pixfmt->field = V4L2_FIELD_NONE; + break; + case V4L2_FIELD_NONE: + if (vpfe_dev->std_info.frame_format) + pixfmt->field = V4L2_FIELD_INTERLACED; + break; + + default: + /* use current field as default */ + pixfmt->field = vpfe_dev->fmt.fmt.pix.field; + break; + } + } + + /* Now adjust image resolutions supported */ + if (pixfmt->field == V4L2_FIELD_INTERLACED || + pixfmt->field == V4L2_FIELD_SEQ_TB) + min_height = 2; + + max_width = vpfe_dev->std_info.active_pixels; + max_height = vpfe_dev->std_info.active_lines; + min_width /= vpfe_pix_fmt->bpp; + + v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n", + pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp); + + pixfmt->width = clamp((pixfmt->width), min_width, max_width); + pixfmt->height = clamp((pixfmt->height), min_height, max_height); + + /* If interlaced, adjust height to be a multiple of 2 */ + if (pixfmt->field == V4L2_FIELD_INTERLACED) + pixfmt->height &= (~1); + /* + * recalculate bytesperline and sizeimage since width + * and height might have changed + */ + pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31) + & ~31); + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + pixfmt->sizeimage = + pixfmt->bytesperline * pixfmt->height + + ((pixfmt->bytesperline * pixfmt->height) >> 1); + else + pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; + + v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height =" + " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", + pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp, + pixfmt->bytesperline, pixfmt->sizeimage); + return vpfe_pix_fmt; +} + +static int vpfe_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); + + cap->version = VPFE_CAPTURE_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); + strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); + strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); + return 0; +} + +static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n"); + /* Fill in the information about format */ + *fmt = vpfe_dev->fmt; + return ret; +} + +static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + const struct vpfe_pixel_format *pix_fmt; + int temp_index; + u32 pix; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); + + if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0) + return -EINVAL; + + /* Fill in the information about format */ + pix_fmt = vpfe_lookup_pix_format(pix); + if (NULL != pix_fmt) { + temp_index = fmt->index; + *fmt = pix_fmt->fmtdesc; + fmt->index = temp_index; + return 0; + } + return -EINVAL; +} + +static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + const struct vpfe_pixel_format *pix_fmts; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); + + /* If streaming is started, return error */ + if (vpfe_dev->started) { + v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + + /* Check for valid frame format */ + pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix); + + if (NULL == pix_fmts) + return -EINVAL; + + /* store the pixel format in the device object */ + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + /* First detach any IRQ if currently attached */ + vpfe_detach_irq(vpfe_dev); + vpfe_dev->fmt = *fmt; + /* set image capture parameters in the ccdc */ + ret = vpfe_config_ccdc_image_format(vpfe_dev); + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + const struct vpfe_pixel_format *pix_fmts; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n"); + + pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix); + if (NULL == pix_fmts) + return -EINVAL; + return 0; +} + +/* + * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a + * given app input index + */ +static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev, + int *subdev_index, + int *subdev_input_index, + int app_input_index) +{ + struct vpfe_config *cfg = vpfe_dev->cfg; + struct vpfe_subdev_info *sdinfo; + int i, j = 0; + + for (i = 0; i < cfg->num_subdevs; i++) { + sdinfo = &cfg->sub_devs[i]; + if (app_input_index < (j + sdinfo->num_inputs)) { + *subdev_index = i; + *subdev_input_index = app_input_index - j; + return 0; + } + j += sdinfo->num_inputs; + } + return -EINVAL; +} + +/* + * vpfe_get_app_input - Get app input index for a given subdev input index + * driver stores the input index of the current sub device and translate it + * when application request the current input + */ +static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev, + int *app_input_index) +{ + struct vpfe_config *cfg = vpfe_dev->cfg; + struct vpfe_subdev_info *sdinfo; + int i, j = 0; + + for (i = 0; i < cfg->num_subdevs; i++) { + sdinfo = &cfg->sub_devs[i]; + if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) { + if (vpfe_dev->current_input >= sdinfo->num_inputs) + return -1; + *app_input_index = j + vpfe_dev->current_input; + return 0; + } + j += sdinfo->num_inputs; + } + return -EINVAL; +} + +static int vpfe_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int subdev, index ; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); + + if (vpfe_get_subdev_input_index(vpfe_dev, + &subdev, + &index, + inp->index) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, "input information not found" + " for the subdev\n"); + return -EINVAL; + } + sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; + memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input)); + return 0; +} + +static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); + + return vpfe_get_app_input_index(vpfe_dev, index); +} + + +static int vpfe_s_input(struct file *file, void *priv, unsigned int index) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int subdev_index, inp_index; + struct vpfe_route *route; + u32 input = 0, output = 0; + int ret = -EINVAL; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + /* + * If streaming is started return device busy + * error + */ + if (vpfe_dev->started) { + v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); + ret = -EBUSY; + goto unlock_out; + } + + if (vpfe_get_subdev_input_index(vpfe_dev, + &subdev_index, + &inp_index, + index) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n"); + goto unlock_out; + } + + sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; + route = &sdinfo->routes[inp_index]; + if (route && sdinfo->can_route) { + input = route->input; + output = route->output; + } + + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + video, s_routing, input, output, 0); + + if (ret) { + v4l2_err(&vpfe_dev->v4l2_dev, + "vpfe_doioctl:error in setting input in decoder\n"); + ret = -EINVAL; + goto unlock_out; + } + vpfe_dev->current_subdev = sdinfo; + vpfe_dev->current_input = index; + vpfe_dev->std_index = 0; + + /* set the bus/interface parameter for the sub device in ccdc */ + ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params); + if (ret) + goto unlock_out; + + /* set the default image parameters in the device */ + ret = vpfe_config_image_format(vpfe_dev, + &vpfe_standards[vpfe_dev->std_index].std_id); +unlock_out: + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + sdinfo = vpfe_dev->current_subdev; + if (ret) + return ret; + /* Call querystd function of decoder device */ + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + video, querystd, std_id); + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); + + /* Call decoder driver function to set the standard */ + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + sdinfo = vpfe_dev->current_subdev; + /* If streaming is started, return device busy error */ + if (vpfe_dev->started) { + v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); + ret = -EBUSY; + goto unlock_out; + } + + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + core, s_std, *std_id); + if (ret < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); + goto unlock_out; + } + ret = vpfe_config_image_format(vpfe_dev, std_id); + +unlock_out: + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); + + *std_id = vpfe_standards[vpfe_dev->std_index].std_id; + return 0; +} +/* + * Videobuf operations + */ +static int vpfe_videobuf_setup(struct videobuf_queue *vq, + unsigned int *count, + unsigned int *size) +{ + struct vpfe_fh *fh = vq->priv_data; + struct vpfe_device *vpfe_dev = fh->vpfe_dev; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n"); + *size = vpfe_dev->fmt.fmt.pix.sizeimage; + if (vpfe_dev->memory == V4L2_MEMORY_MMAP && + vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize) + *size = config_params.device_bufsize; + + if (*count < config_params.min_numbuffers) + *count = config_params.min_numbuffers; + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "count=%d, size=%d\n", *count, *size); + return 0; +} + +static int vpfe_videobuf_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct vpfe_fh *fh = vq->priv_data; + struct vpfe_device *vpfe_dev = fh->vpfe_dev; + unsigned long addr; + int ret; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); + + /* If buffer is not initialized, initialize it */ + if (VIDEOBUF_NEEDS_INIT == vb->state) { + vb->width = vpfe_dev->fmt.fmt.pix.width; + vb->height = vpfe_dev->fmt.fmt.pix.height; + vb->size = vpfe_dev->fmt.fmt.pix.sizeimage; + vb->field = field; + + ret = videobuf_iolock(vq, vb, NULL); + if (ret < 0) + return ret; + + addr = videobuf_to_dma_contig(vb); + /* Make sure user addresses are aligned to 32 bytes */ + if (!ALIGN(addr, 32)) + return -EINVAL; + + vb->state = VIDEOBUF_PREPARED; + } + return 0; +} + +static void vpfe_videobuf_queue(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and device object */ + struct vpfe_fh *fh = vq->priv_data; + struct vpfe_device *vpfe_dev = fh->vpfe_dev; + unsigned long flags; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n"); + + /* add the buffer to the DMA queue */ + spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); + list_add_tail(&vb->queue, &vpfe_dev->dma_queue); + spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); + + /* Change state of the buffer */ + vb->state = VIDEOBUF_QUEUED; +} + +static void vpfe_videobuf_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct vpfe_fh *fh = vq->priv_data; + struct vpfe_device *vpfe_dev = fh->vpfe_dev; + unsigned long flags; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n"); + + /* + * We need to flush the buffer from the dma queue since + * they are de-allocated + */ + spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); + INIT_LIST_HEAD(&vpfe_dev->dma_queue); + spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); + videobuf_dma_contig_free(vq, vb); + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static struct videobuf_queue_ops vpfe_videobuf_qops = { + .buf_setup = vpfe_videobuf_setup, + .buf_prepare = vpfe_videobuf_prepare, + .buf_queue = vpfe_videobuf_queue, + .buf_release = vpfe_videobuf_release, +}; + +/* + * vpfe_reqbufs. currently support REQBUF only once opening + * the device. + */ +static int vpfe_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *req_buf) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + if (vpfe_dev->io_usrs != 0) { + v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); + ret = -EBUSY; + goto unlock_out; + } + + vpfe_dev->memory = req_buf->memory; + videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue, + &vpfe_videobuf_qops, + vpfe_dev->pdev, + &vpfe_dev->irqlock, + req_buf->type, + vpfe_dev->fmt.fmt.pix.field, + sizeof(struct videobuf_buffer), + fh, NULL); + + fh->io_allowed = 1; + vpfe_dev->io_usrs = 1; + INIT_LIST_HEAD(&vpfe_dev->dma_queue); + ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf); +unlock_out: + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + if (vpfe_dev->memory != V4L2_MEMORY_MMAP) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); + return -EINVAL; + } + /* Call videobuf_querybuf to get information */ + return videobuf_querybuf(&vpfe_dev->buffer_queue, buf); +} + +static int vpfe_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + /* + * If this file handle is not allowed to do IO, + * return error + */ + if (!fh->io_allowed) { + v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); + return -EACCES; + } + return videobuf_qbuf(&vpfe_dev->buffer_queue, p); +} + +static int vpfe_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + return videobuf_dqbuf(&vpfe_dev->buffer_queue, + buf, file->f_flags & O_NONBLOCK); +} + +static int vpfe_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qctrl) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + sdinfo = vpfe_dev->current_subdev; + + return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + core, queryctrl, qctrl); + +} + +static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + sdinfo = vpfe_dev->current_subdev; + + return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + core, g_ctrl, ctrl); +} + +static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + sdinfo = vpfe_dev->current_subdev; + + return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + core, s_ctrl, ctrl); +} + +/* + * vpfe_calculate_offsets : This function calculates buffers offset + * for top and bottom field + */ +static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev) +{ + struct v4l2_rect image_win; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n"); + + ccdc_dev->hw_ops.get_image_window(&image_win); + vpfe_dev->field_off = image_win.height * image_win.width; +} + +/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */ +static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev) +{ + ccdc_dev->hw_ops.enable(1); + if (ccdc_dev->hw_ops.enable_out_to_sdram) + ccdc_dev->hw_ops.enable_out_to_sdram(1); + vpfe_dev->started = 1; +} + +/* + * vpfe_streamon. Assume the DMA queue is not empty. + * application is expected to call QBUF before calling + * this ioctl. If not, driver returns error + */ +static int vpfe_streamon(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + struct vpfe_subdev_info *sdinfo; + unsigned long addr; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + /* If file handle is not allowed IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); + return -EACCES; + } + + sdinfo = vpfe_dev->current_subdev; + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + video, s_stream, 1); + + if (ret && (ret != -ENOIOCTLCMD)) { + v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n"); + return -EINVAL; + } + + /* If buffer queue is empty, return error */ + if (list_empty(&vpfe_dev->buffer_queue.stream)) { + v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); + return -EIO; + } + + /* Call videobuf_streamon to start streaming * in videobuf */ + ret = videobuf_streamon(&vpfe_dev->buffer_queue); + if (ret) + return ret; + + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + goto streamoff; + /* Get the next frame from the buffer queue */ + vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, + struct videobuf_buffer, queue); + vpfe_dev->cur_frm = vpfe_dev->next_frm; + /* Remove buffer from the buffer queue */ + list_del(&vpfe_dev->cur_frm->queue); + /* Mark state of the current frame to active */ + vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE; + /* Initialize field_id and started member */ + vpfe_dev->field_id = 0; + addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); + + /* Calculate field offset */ + vpfe_calculate_offsets(vpfe_dev); + + if (vpfe_attach_irq(vpfe_dev) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "Error in attaching interrupt handle\n"); + ret = -EFAULT; + goto unlock_out; + } + if (ccdc_dev->hw_ops.configure() < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "Error in configuring ccdc\n"); + ret = -EINVAL; + goto unlock_out; + } + ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr)); + vpfe_start_ccdc_capture(vpfe_dev); + mutex_unlock(&vpfe_dev->lock); + return ret; +unlock_out: + mutex_unlock(&vpfe_dev->lock); +streamoff: + ret = videobuf_streamoff(&vpfe_dev->buffer_queue); + return ret; +} + +static int vpfe_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + struct vpfe_subdev_info *sdinfo; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + /* If io is allowed for this file handle, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); + return -EACCES; + } + + /* If streaming is not started, return error */ + if (!vpfe_dev->started) { + v4l2_err(&vpfe_dev->v4l2_dev, "device started\n"); + return -EINVAL; + } + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + vpfe_stop_ccdc_capture(vpfe_dev); + vpfe_detach_irq(vpfe_dev); + + sdinfo = vpfe_dev->current_subdev; + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + video, s_stream, 0); + + if (ret && (ret != -ENOIOCTLCMD)) + v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n"); + ret = videobuf_streamoff(&vpfe_dev->buffer_queue); + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *crop) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n"); + + if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards)) + return -EINVAL; + + memset(crop, 0, sizeof(struct v4l2_cropcap)); + crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop->bounds.width = crop->defrect.width = + vpfe_standards[vpfe_dev->std_index].width; + crop->bounds.height = crop->defrect.height = + vpfe_standards[vpfe_dev->std_index].height; + crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect; + return 0; +} + +static int vpfe_g_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n"); + + crop->c = vpfe_dev->crop; + return 0; +} + +static int vpfe_s_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); + + if (vpfe_dev->started) { + /* make sure streaming is not started */ + v4l2_err(&vpfe_dev->v4l2_dev, + "Cannot change crop when streaming is ON\n"); + return -EBUSY; + } + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + if (crop->c.top < 0 || crop->c.left < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "doesn't support negative values for top & left\n"); + ret = -EINVAL; + goto unlock_out; + } + + /* adjust the width to 16 pixel boundary */ + crop->c.width = ((crop->c.width + 15) & ~0xf); + + /* make sure parameters are valid */ + if ((crop->c.left + crop->c.width > + vpfe_dev->std_info.active_pixels) || + (crop->c.top + crop->c.height > + vpfe_dev->std_info.active_lines)) { + v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); + ret = -EINVAL; + goto unlock_out; + } + ccdc_dev->hw_ops.set_image_window(&crop->c); + vpfe_dev->fmt.fmt.pix.width = crop->c.width; + vpfe_dev->fmt.fmt.pix.height = crop->c.height; + vpfe_dev->fmt.fmt.pix.bytesperline = + ccdc_dev->hw_ops.get_line_length(); + vpfe_dev->fmt.fmt.pix.sizeimage = + vpfe_dev->fmt.fmt.pix.bytesperline * + vpfe_dev->fmt.fmt.pix.height; + vpfe_dev->crop = crop->c; +unlock_out: + mutex_unlock(&vpfe_dev->lock); + return ret; +} + + +static long vpfe_param_handler(struct file *file, void *priv, + bool valid_prio, int cmd, void *param) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + int ret = 0; + + v4l2_dbg(2, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n"); + + if (vpfe_dev->started) { + /* only allowed if streaming is not started */ + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "device already started\n"); + return -EBUSY; + } + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + switch (cmd) { + case VPFE_CMD_S_CCDC_RAW_PARAMS: + v4l2_warn(&vpfe_dev->v4l2_dev, + "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n"); + if (ccdc_dev->hw_ops.set_params) { + ret = ccdc_dev->hw_ops.set_params(param); + if (ret) { + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "Error setting parameters in CCDC\n"); + goto unlock_out; + } + if (vpfe_get_ccdc_image_format(vpfe_dev, + &vpfe_dev->fmt) < 0) { + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "Invalid image format at CCDC\n"); + goto unlock_out; + } + } else { + ret = -EINVAL; + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n"); + } + break; + default: + ret = -EINVAL; + } +unlock_out: + mutex_unlock(&vpfe_dev->lock); + return ret; +} + + +/* vpfe capture ioctl operations */ +static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { + .vidioc_querycap = vpfe_querycap, + .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap, + .vidioc_enum_input = vpfe_enum_input, + .vidioc_g_input = vpfe_g_input, + .vidioc_s_input = vpfe_s_input, + .vidioc_querystd = vpfe_querystd, + .vidioc_s_std = vpfe_s_std, + .vidioc_g_std = vpfe_g_std, + .vidioc_queryctrl = vpfe_queryctrl, + .vidioc_g_ctrl = vpfe_g_ctrl, + .vidioc_s_ctrl = vpfe_s_ctrl, + .vidioc_reqbufs = vpfe_reqbufs, + .vidioc_querybuf = vpfe_querybuf, + .vidioc_qbuf = vpfe_qbuf, + .vidioc_dqbuf = vpfe_dqbuf, + .vidioc_streamon = vpfe_streamon, + .vidioc_streamoff = vpfe_streamoff, + .vidioc_cropcap = vpfe_cropcap, + .vidioc_g_crop = vpfe_g_crop, + .vidioc_s_crop = vpfe_s_crop, + .vidioc_default = vpfe_param_handler, +}; + +static struct vpfe_device *vpfe_initialize(void) +{ + struct vpfe_device *vpfe_dev; + + /* Default number of buffers should be 3 */ + if ((numbuffers > 0) && + (numbuffers < config_params.min_numbuffers)) + numbuffers = config_params.min_numbuffers; + + /* + * Set buffer size to min buffers size if invalid buffer size is + * given + */ + if (bufsize < config_params.min_bufsize) + bufsize = config_params.min_bufsize; + + config_params.numbuffers = numbuffers; + + if (numbuffers) + config_params.device_bufsize = bufsize; + + /* Allocate memory for device objects */ + vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); + + return vpfe_dev; +} + +/* + * vpfe_probe : This function creates device entries by register + * itself to the V4L2 driver and initializes fields of each + * device objects + */ +static __init int vpfe_probe(struct platform_device *pdev) +{ + struct vpfe_subdev_info *sdinfo; + struct vpfe_config *vpfe_cfg; + struct resource *res1; + struct vpfe_device *vpfe_dev; + struct i2c_adapter *i2c_adap; + struct video_device *vfd; + int ret = -ENOMEM, i, j; + int num_subdevs = 0; + + /* Get the pointer to the device object */ + vpfe_dev = vpfe_initialize(); + + if (!vpfe_dev) { + v4l2_err(pdev->dev.driver, + "Failed to allocate memory for vpfe_dev\n"); + return ret; + } + + vpfe_dev->pdev = &pdev->dev; + + if (NULL == pdev->dev.platform_data) { + v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); + ret = -ENODEV; + goto probe_free_dev_mem; + } + + vpfe_cfg = pdev->dev.platform_data; + vpfe_dev->cfg = vpfe_cfg; + if (NULL == vpfe_cfg->ccdc || + NULL == vpfe_cfg->card_name || + NULL == vpfe_cfg->sub_devs) { + v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); + ret = -ENOENT; + goto probe_free_dev_mem; + } + + /* Allocate memory for ccdc configuration */ + ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); + if (NULL == ccdc_cfg) { + v4l2_err(pdev->dev.driver, + "Memory allocation failed for ccdc_cfg\n"); + goto probe_free_lock; + } + + mutex_lock(&ccdc_lock); + + strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); + /* Get VINT0 irq resource */ + res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res1) { + v4l2_err(pdev->dev.driver, + "Unable to get interrupt for VINT0\n"); + ret = -ENODEV; + goto probe_free_ccdc_cfg_mem; + } + vpfe_dev->ccdc_irq0 = res1->start; + + /* Get VINT1 irq resource */ + res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!res1) { + v4l2_err(pdev->dev.driver, + "Unable to get interrupt for VINT1\n"); + ret = -ENODEV; + goto probe_free_ccdc_cfg_mem; + } + vpfe_dev->ccdc_irq1 = res1->start; + + ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED, + "vpfe_capture0", vpfe_dev); + + if (0 != ret) { + v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); + goto probe_free_ccdc_cfg_mem; + } + + /* Allocate memory for video device */ + vfd = video_device_alloc(); + if (NULL == vfd) { + ret = -ENOMEM; + v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); + goto probe_out_release_irq; + } + + /* Initialize field of video device */ + vfd->release = video_device_release; + vfd->fops = &vpfe_fops; + vfd->ioctl_ops = &vpfe_ioctl_ops; + vfd->tvnorms = 0; + vfd->current_norm = V4L2_STD_PAL; + vfd->v4l2_dev = &vpfe_dev->v4l2_dev; + snprintf(vfd->name, sizeof(vfd->name), + "%s_V%d.%d.%d", + CAPTURE_DRV_NAME, + (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, + (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, + (VPFE_CAPTURE_VERSION_CODE) & 0xff); + /* Set video_dev to the video device */ + vpfe_dev->video_dev = vfd; + + ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); + if (ret) { + v4l2_err(pdev->dev.driver, + "Unable to register v4l2 device.\n"); + goto probe_out_video_release; + } + v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); + spin_lock_init(&vpfe_dev->irqlock); + spin_lock_init(&vpfe_dev->dma_queue_lock); + mutex_init(&vpfe_dev->lock); + + /* Initialize field of the device objects */ + vpfe_dev->numbuffers = config_params.numbuffers; + + /* Initialize prio member of device object */ + v4l2_prio_init(&vpfe_dev->prio); + /* register video device */ + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "trying to register vpfe device.\n"); + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "video_dev=%x\n", (int)&vpfe_dev->video_dev); + vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret = video_register_device(vpfe_dev->video_dev, + VFL_TYPE_GRABBER, -1); + + if (ret) { + v4l2_err(pdev->dev.driver, + "Unable to register video device.\n"); + goto probe_out_v4l2_unregister; + } + + v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n"); + /* set the driver data in platform device */ + platform_set_drvdata(pdev, vpfe_dev); + /* set driver private data */ + video_set_drvdata(vpfe_dev->video_dev, vpfe_dev); + i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); + num_subdevs = vpfe_cfg->num_subdevs; + vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, + GFP_KERNEL); + if (NULL == vpfe_dev->sd) { + v4l2_err(&vpfe_dev->v4l2_dev, + "unable to allocate memory for subdevice pointers\n"); + ret = -ENOMEM; + goto probe_out_video_unregister; + } + + for (i = 0; i < num_subdevs; i++) { + struct v4l2_input *inps; + + sdinfo = &vpfe_cfg->sub_devs[i]; + + /* Load up the subdevice */ + vpfe_dev->sd[i] = + v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, + i2c_adap, + &sdinfo->board_info, + NULL); + if (vpfe_dev->sd[i]) { + v4l2_info(&vpfe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + sdinfo->name); + vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; + /* update tvnorms from the sub devices */ + for (j = 0; j < sdinfo->num_inputs; j++) { + inps = &sdinfo->inputs[j]; + vfd->tvnorms |= inps->std; + } + } else { + v4l2_info(&vpfe_dev->v4l2_dev, + "v4l2 sub device %s register fails\n", + sdinfo->name); + goto probe_sd_out; + } + } + + /* set first sub device as current one */ + vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; + + /* We have at least one sub device to work with */ + mutex_unlock(&ccdc_lock); + return 0; + +probe_sd_out: + kfree(vpfe_dev->sd); +probe_out_video_unregister: + video_unregister_device(vpfe_dev->video_dev); +probe_out_v4l2_unregister: + v4l2_device_unregister(&vpfe_dev->v4l2_dev); +probe_out_video_release: + if (!video_is_registered(vpfe_dev->video_dev)) + video_device_release(vpfe_dev->video_dev); +probe_out_release_irq: + free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); +probe_free_ccdc_cfg_mem: + kfree(ccdc_cfg); +probe_free_lock: + mutex_unlock(&ccdc_lock); +probe_free_dev_mem: + kfree(vpfe_dev); + return ret; +} + +/* + * vpfe_remove : It un-register device from V4L2 driver + */ +static int __devexit vpfe_remove(struct platform_device *pdev) +{ + struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); + + v4l2_info(pdev->dev.driver, "vpfe_remove\n"); + + free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); + kfree(vpfe_dev->sd); + v4l2_device_unregister(&vpfe_dev->v4l2_dev); + video_unregister_device(vpfe_dev->video_dev); + kfree(vpfe_dev); + kfree(ccdc_cfg); + return 0; +} + +static int vpfe_suspend(struct device *dev) +{ + return 0; +} + +static int vpfe_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops vpfe_dev_pm_ops = { + .suspend = vpfe_suspend, + .resume = vpfe_resume, +}; + +static struct platform_driver vpfe_driver = { + .driver = { + .name = CAPTURE_DRV_NAME, + .owner = THIS_MODULE, + .pm = &vpfe_dev_pm_ops, + }, + .probe = vpfe_probe, + .remove = __devexit_p(vpfe_remove), +}; + +static __init int vpfe_init(void) +{ + printk(KERN_NOTICE "vpfe_init\n"); + /* Register driver to the kernel */ + return platform_driver_register(&vpfe_driver); +} + +/* + * vpfe_cleanup : This function un-registers device driver + */ +static void vpfe_cleanup(void) +{ + platform_driver_unregister(&vpfe_driver); +} + +module_init(vpfe_init); +module_exit(vpfe_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,473 @@ +/* + * vpif - DM646x Video Port Interface driver + * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) + * that receiveing video byte stream and two channels(2, 3) for video output. + * The hardware supports SDTV, HDTV formats, raw data capture. + * Currently, the driver supports NTSC and PAL standards. + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "vpif.h" + +MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver"); +MODULE_LICENSE("GPL"); + +#define VPIF_CH0_MAX_MODES (22) +#define VPIF_CH1_MAX_MODES (02) +#define VPIF_CH2_MAX_MODES (15) +#define VPIF_CH3_MAX_MODES (02) + +static resource_size_t res_len; +static struct resource *res; +spinlock_t vpif_lock; + +void __iomem *vpif_base; + +/** + * ch_params: video standard configuration parameters for vpif + * The table must include all presets from supported subdevices. + */ +const struct vpif_channel_config_params ch_params[] = { + /* HDTV formats */ + { + .name = "480p59_94", + .width = 720, + .height = 480, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 138-8, + .sav2eav = 720, + .l1 = 1, + .l3 = 43, + .l5 = 523, + .vsize = 525, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_480P59_94, + }, + { + .name = "576p50", + .width = 720, + .height = 576, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 144-8, + .sav2eav = 720, + .l1 = 1, + .l3 = 45, + .l5 = 621, + .vsize = 625, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_576P50, + }, + { + .name = "720p50", + .width = 1280, + .height = 720, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 700-8, + .sav2eav = 1280, + .l1 = 1, + .l3 = 26, + .l5 = 746, + .vsize = 750, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_720P50, + }, + { + .name = "720p60", + .width = 1280, + .height = 720, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 370 - 8, + .sav2eav = 1280, + .l1 = 1, + .l3 = 26, + .l5 = 746, + .vsize = 750, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_720P60, + }, + { + .name = "1080I50", + .width = 1920, + .height = 1080, + .frm_fmt = 0, + .ycmux_mode = 0, + .eav2sav = 720 - 8, + .sav2eav = 1920, + .l1 = 1, + .l3 = 21, + .l5 = 561, + .l7 = 563, + .l9 = 584, + .l11 = 1124, + .vsize = 1125, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_1080I50, + }, + { + .name = "1080I60", + .width = 1920, + .height = 1080, + .frm_fmt = 0, + .ycmux_mode = 0, + .eav2sav = 280 - 8, + .sav2eav = 1920, + .l1 = 1, + .l3 = 21, + .l5 = 561, + .l7 = 563, + .l9 = 584, + .l11 = 1124, + .vsize = 1125, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_1080I60, + }, + { + .name = "1080p60", + .width = 1920, + .height = 1080, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 280 - 8, + .sav2eav = 1920, + .l1 = 1, + .l3 = 42, + .l5 = 1122, + .vsize = 1125, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_1080P60, + }, + + /* SDTV formats */ + { + .name = "NTSC_M", + .width = 720, + .height = 480, + .frm_fmt = 0, + .ycmux_mode = 1, + .eav2sav = 268, + .sav2eav = 1440, + .l1 = 1, + .l3 = 23, + .l5 = 263, + .l7 = 266, + .l9 = 286, + .l11 = 525, + .vsize = 525, + .capture_format = 0, + .vbi_supported = 1, + .hd_sd = 0, + .stdid = V4L2_STD_525_60, + }, + { + .name = "PAL_BDGHIK", + .width = 720, + .height = 576, + .frm_fmt = 0, + .ycmux_mode = 1, + .eav2sav = 280, + .sav2eav = 1440, + .l1 = 1, + .l3 = 23, + .l5 = 311, + .l7 = 313, + .l9 = 336, + .l11 = 624, + .vsize = 625, + .capture_format = 0, + .vbi_supported = 1, + .hd_sd = 0, + .stdid = V4L2_STD_625_50, + }, +}; + +const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params); + +static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) +{ + if (val) + vpif_set_bit(reg, bit); + else + vpif_clr_bit(reg, bit); +} + +/* This structure is used to keep track of VPIF size register's offsets */ +struct vpif_registers { + u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl; + u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt; + u32 vanc1_size, width_mask, len_mask; + u8 max_modes; +}; + +static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = { + /* Channel0 */ + { + VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01, + VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL, + VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, + VPIF_CH0_MAX_MODES, + }, + /* Channel1 */ + { + VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01, + VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL, + VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, + VPIF_CH1_MAX_MODES, + }, + /* Channel2 */ + { + VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01, + VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL, + VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE, + VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF, + VPIF_CH2_MAX_MODES + }, + /* Channel3 */ + { + VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01, + VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL, + VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE, + VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF, + VPIF_CH3_MAX_MODES + }, +}; + +/* vpif_set_mode_info: + * This function is used to set horizontal and vertical config parameters + * As per the standard in the channel, configure the values of L1, L3, + * L5, L7 L9, L11 in VPIF Register , also write width and height + */ +static void vpif_set_mode_info(const struct vpif_channel_config_params *config, + u8 channel_id, u8 config_channel_id) +{ + u32 value; + + value = (config->eav2sav & vpifregs[config_channel_id].width_mask); + value <<= VPIF_CH_LEN_SHIFT; + value |= (config->sav2eav & vpifregs[config_channel_id].width_mask); + regw(value, vpifregs[channel_id].h_cfg); + + value = (config->l1 & vpifregs[config_channel_id].len_mask); + value <<= VPIF_CH_LEN_SHIFT; + value |= (config->l3 & vpifregs[config_channel_id].len_mask); + regw(value, vpifregs[channel_id].v_cfg_00); + + value = (config->l5 & vpifregs[config_channel_id].len_mask); + value <<= VPIF_CH_LEN_SHIFT; + value |= (config->l7 & vpifregs[config_channel_id].len_mask); + regw(value, vpifregs[channel_id].v_cfg_01); + + value = (config->l9 & vpifregs[config_channel_id].len_mask); + value <<= VPIF_CH_LEN_SHIFT; + value |= (config->l11 & vpifregs[config_channel_id].len_mask); + regw(value, vpifregs[channel_id].v_cfg_02); + + value = (config->vsize & vpifregs[config_channel_id].len_mask); + regw(value, vpifregs[channel_id].v_cfg); +} + +/* config_vpif_params + * Function to set the parameters of a channel + * Mainly modifies the channel ciontrol register + * It sets frame format, yc mux mode + */ +static void config_vpif_params(struct vpif_params *vpifparams, + u8 channel_id, u8 found) +{ + const struct vpif_channel_config_params *config = &vpifparams->std_info; + u32 value, ch_nip, reg; + u8 start, end; + int i; + + start = channel_id; + end = channel_id + found; + + for (i = start; i < end; i++) { + reg = vpifregs[i].ch_ctrl; + if (channel_id < 2) + ch_nip = VPIF_CAPTURE_CH_NIP; + else + ch_nip = VPIF_DISPLAY_CH_NIP; + + vpif_wr_bit(reg, ch_nip, config->frm_fmt); + vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode); + vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, + vpifparams->video_params.storage_mode); + + /* Set raster scanning SDR Format */ + vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT); + vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format); + + if (channel_id > 1) /* Set the Pixel enable bit */ + vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT); + else if (config->capture_format) { + /* Set the polarity of various pins */ + vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, + vpifparams->iface.fid_pol); + vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, + vpifparams->iface.vd_pol); + vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, + vpifparams->iface.hd_pol); + + value = regr(reg); + /* Set data width */ + value &= ((~(unsigned int)(0x3)) << + VPIF_CH_DATA_WIDTH_BIT); + value |= ((vpifparams->params.data_sz) << + VPIF_CH_DATA_WIDTH_BIT); + regw(value, reg); + } + + /* Write the pitch in the driver */ + regw((vpifparams->video_params.hpitch), + vpifregs[i].line_offset); + } +} + +/* vpif_set_video_params + * This function is used to set video parameters in VPIF register + */ +int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id) +{ + const struct vpif_channel_config_params *config = &vpifparams->std_info; + int found = 1; + + vpif_set_mode_info(config, channel_id, channel_id); + if (!config->ycmux_mode) { + /* YC are on separate channels (HDTV formats) */ + vpif_set_mode_info(config, channel_id + 1, channel_id); + found = 2; + } + + config_vpif_params(vpifparams, channel_id, found); + + regw(0x80, VPIF_REQ_SIZE); + regw(0x01, VPIF_EMULATION_CTRL); + + return found; +} +EXPORT_SYMBOL(vpif_set_video_params); + +void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, + u8 channel_id) +{ + u32 value; + + value = 0x3F8 & (vbiparams->hstart0); + value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16); + regw(value, vpifregs[channel_id].vanc0_strt); + + value = 0x3F8 & (vbiparams->hstart1); + value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16); + regw(value, vpifregs[channel_id].vanc1_strt); + + value = 0x3F8 & (vbiparams->hsize0); + value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16); + regw(value, vpifregs[channel_id].vanc0_size); + + value = 0x3F8 & (vbiparams->hsize1); + value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16); + regw(value, vpifregs[channel_id].vanc1_size); + +} +EXPORT_SYMBOL(vpif_set_vbi_display_params); + +int vpif_channel_getfid(u8 channel_id) +{ + return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK) + >> VPIF_CH_FID_SHIFT; +} +EXPORT_SYMBOL(vpif_channel_getfid); + +static int __init vpif_probe(struct platform_device *pdev) +{ + int status = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + res_len = res->end - res->start + 1; + + res = request_mem_region(res->start, res_len, res->name); + if (!res) + return -EBUSY; + + vpif_base = ioremap(res->start, res_len); + if (!vpif_base) { + status = -EBUSY; + goto fail; + } + + spin_lock_init(&vpif_lock); + dev_info(&pdev->dev, "vpif probe success\n"); + return 0; + +fail: + release_mem_region(res->start, res_len); + return status; +} + +static int __devexit vpif_remove(struct platform_device *pdev) +{ + iounmap(vpif_base); + release_mem_region(res->start, res_len); + return 0; +} + +static struct platform_driver vpif_driver = { + .driver = { + .name = "vpif", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(vpif_remove), + .probe = vpif_probe, +}; + +static void vpif_exit(void) +{ + platform_driver_unregister(&vpif_driver); +} + +static int __init vpif_init(void) +{ + return platform_driver_register(&vpif_driver); +} +subsys_initcall(vpif_init); +module_exit(vpif_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_capture.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_capture.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_capture.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_capture.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2415 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * TODO : add support for VBI & HBI data service + * add static buffer allocation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vpif_capture.h" +#include "vpif.h" + +MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver"); +MODULE_LICENSE("GPL"); + +#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) +#define vpif_dbg(level, debug, fmt, arg...) \ + v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) + +static int debug = 1; +static u32 ch0_numbuffers = 3; +static u32 ch1_numbuffers = 3; +static u32 ch0_bufsize = 1920 * 1080 * 2; +static u32 ch1_bufsize = 720 * 576 * 2; + +module_param(debug, int, 0644); +module_param(ch0_numbuffers, uint, S_IRUGO); +module_param(ch1_numbuffers, uint, S_IRUGO); +module_param(ch0_bufsize, uint, S_IRUGO); +module_param(ch1_bufsize, uint, S_IRUGO); + +MODULE_PARM_DESC(debug, "Debug level 0-1"); +MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)"); +MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)"); +MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)"); +MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)"); + +static struct vpif_config_params config_params = { + .min_numbuffers = 3, + .numbuffers[0] = 3, + .numbuffers[1] = 3, + .min_bufsize[0] = 720 * 480 * 2, + .min_bufsize[1] = 720 * 480 * 2, + .channel_bufsize[0] = 1920 * 1080 * 2, + .channel_bufsize[1] = 720 * 576 * 2, +}; + +/* global variables */ +static struct vpif_device vpif_obj = { {NULL} }; +static struct device *vpif_dev; + +/** + * vpif_uservirt_to_phys : translate user/virtual address to phy address + * @virtp: user/virtual address + * + * This inline function is used to convert user space virtual address to + * physical address. + */ +static inline u32 vpif_uservirt_to_phys(u32 virtp) +{ + unsigned long physp = 0; + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + + vma = find_vma(mm, virtp); + + /* For kernel direct-mapped memory, take the easy way */ + if (virtp >= PAGE_OFFSET) + physp = virt_to_phys((void *)virtp); + else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) + /** + * this will catch, kernel-allocated, mmaped-to-usermode + * addresses + */ + physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); + else { + /* otherwise, use get_user_pages() for general userland pages */ + int res, nr_pages = 1; + struct page *pages; + + down_read(¤t->mm->mmap_sem); + + res = get_user_pages(current, current->mm, + virtp, nr_pages, 1, 0, &pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (res == nr_pages) + physp = __pa(page_address(&pages[0]) + + (virtp & ~PAGE_MASK)); + else { + vpif_err("get_user_pages failed\n"); + return 0; + } + } + return physp; +} + +/** + * buffer_prepare : callback function for buffer prepare + * @q : buffer queue ptr + * @vb: ptr to video buffer + * @field: field info + * + * This is the callback function for buffer prepare when videobuf_qbuf() + * function is called. The buffer is prepared and user space virtual address + * or user address is converted into physical address + */ +static int vpif_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + /* Get the file handle object and channel object */ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + unsigned long addr; + + + vpif_dbg(2, debug, "vpif_buffer_prepare\n"); + + common = &ch->common[VPIF_VIDEO_INDEX]; + + /* If buffer is not initialized, initialize it */ + if (VIDEOBUF_NEEDS_INIT == vb->state) { + vb->width = common->width; + vb->height = common->height; + vb->size = vb->width * vb->height; + vb->field = field; + } + vb->state = VIDEOBUF_PREPARED; + /** + * if user pointer memory mechanism is used, get the physical + * address of the buffer + */ + if (V4L2_MEMORY_USERPTR == common->memory) { + if (0 == vb->baddr) { + vpif_dbg(1, debug, "buffer address is 0\n"); + return -EINVAL; + + } + vb->boff = vpif_uservirt_to_phys(vb->baddr); + if (!IS_ALIGNED(vb->boff, 8)) + goto exit; + } + + addr = vb->boff; + if (q->streaming) { + if (!IS_ALIGNED((addr + common->ytop_off), 8) || + !IS_ALIGNED((addr + common->ybtm_off), 8) || + !IS_ALIGNED((addr + common->ctop_off), 8) || + !IS_ALIGNED((addr + common->cbtm_off), 8)) + goto exit; + } + return 0; +exit: + vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n"); + return -EINVAL; +} + +/** + * vpif_buffer_setup : Callback function for buffer setup. + * @q: buffer queue ptr + * @count: number of buffers + * @size: size of the buffer + * + * This callback function is called when reqbuf() is called to adjust + * the buffer count and buffer size + */ +static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + /* Get the file handle object and channel object */ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_buffer_setup\n"); + + /* If memory type is not mmap, return */ + if (V4L2_MEMORY_MMAP != common->memory) + return 0; + + /* Calculate the size of the buffer */ + *size = config_params.channel_bufsize[ch->channel_id]; + + if (*count < config_params.min_numbuffers) + *count = config_params.min_numbuffers; + return 0; +} + +/** + * vpif_buffer_queue : Callback function to add buffer to DMA queue + * @q: ptr to videobuf_queue + * @vb: ptr to videobuf_buffer + */ +static void vpif_buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and channel object */ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_buffer_queue\n"); + + /* add the buffer to the DMA queue */ + list_add_tail(&vb->queue, &common->dma_queue); + /* Change state of the buffer */ + vb->state = VIDEOBUF_QUEUED; +} + +/** + * vpif_buffer_release : Callback function to free buffer + * @q: buffer queue ptr + * @vb: ptr to video buffer + * + * This function is called from the videobuf layer to free memory + * allocated to the buffers + */ +static void vpif_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and channel object */ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + videobuf_dma_contig_free(q, vb); + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = vpif_buffer_setup, + .buf_prepare = vpif_buffer_prepare, + .buf_queue = vpif_buffer_queue, + .buf_release = vpif_buffer_release, +}; + +static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = + { {1, 1} }; + +/** + * vpif_process_buffer_complete: process a completed buffer + * @common: ptr to common channel object + * + * This function time stamp the buffer and mark it as DONE. It also + * wake up any process waiting on the QUEUE and set the next buffer + * as current + */ +static void vpif_process_buffer_complete(struct common_obj *common) +{ + do_gettimeofday(&common->cur_frm->ts); + common->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible(&common->cur_frm->done); + /* Make curFrm pointing to nextFrm */ + common->cur_frm = common->next_frm; +} + +/** + * vpif_schedule_next_buffer: set next buffer address for capture + * @common : ptr to common channel object + * + * This function will get next buffer from the dma queue and + * set the buffer address in the vpif register for capture. + * the buffer is marked active + */ +static void vpif_schedule_next_buffer(struct common_obj *common) +{ + unsigned long addr = 0; + + common->next_frm = list_entry(common->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove that buffer from the buffer queue */ + list_del(&common->next_frm->queue); + common->next_frm->state = VIDEOBUF_ACTIVE; + if (V4L2_MEMORY_USERPTR == common->memory) + addr = common->next_frm->boff; + else + addr = videobuf_to_dma_contig(common->next_frm); + + /* Set top and bottom field addresses in VPIF registers */ + common->set_addr(addr + common->ytop_off, + addr + common->ybtm_off, + addr + common->ctop_off, + addr + common->cbtm_off); +} + +/** + * vpif_channel_isr : ISR handler for vpif capture + * @irq: irq number + * @dev_id: dev_id ptr + * + * It changes status of the captured buffer, takes next buffer from the queue + * and sets its address in VPIF registers + */ +static irqreturn_t vpif_channel_isr(int irq, void *dev_id) +{ + struct vpif_device *dev = &vpif_obj; + struct common_obj *common; + struct channel_obj *ch; + enum v4l2_field field; + int channel_id = 0; + int fid = -1, i; + + channel_id = *(int *)(dev_id); + ch = dev->dev[channel_id]; + + field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; + + for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) { + common = &ch->common[i]; + /* skip If streaming is not started in this channel */ + if (0 == common->started) + continue; + + /* Check the field format */ + if (1 == ch->vpifparams.std_info.frm_fmt) { + /* Progressive mode */ + if (list_empty(&common->dma_queue)) + continue; + + if (!channel_first_int[i][channel_id]) + vpif_process_buffer_complete(common); + + channel_first_int[i][channel_id] = 0; + + vpif_schedule_next_buffer(common); + + + channel_first_int[i][channel_id] = 0; + } else { + /** + * Interlaced mode. If it is first interrupt, ignore + * it + */ + if (channel_first_int[i][channel_id]) { + channel_first_int[i][channel_id] = 0; + continue; + } + if (0 == i) { + ch->field_id ^= 1; + /* Get field id from VPIF registers */ + fid = vpif_channel_getfid(ch->channel_id); + if (fid != ch->field_id) { + /** + * If field id does not match stored + * field id, make them in sync + */ + if (0 == fid) + ch->field_id = fid; + return IRQ_HANDLED; + } + } + /* device field id and local field id are in sync */ + if (0 == fid) { + /* this is even field */ + if (common->cur_frm == common->next_frm) + continue; + + /* mark the current buffer as done */ + vpif_process_buffer_complete(common); + } else if (1 == fid) { + /* odd field */ + if (list_empty(&common->dma_queue) || + (common->cur_frm != common->next_frm)) + continue; + + vpif_schedule_next_buffer(common); + } + } + } + return IRQ_HANDLED; +} + +/** + * vpif_update_std_info() - update standard related info + * @ch: ptr to channel object + * + * For a given standard selected by application, update values + * in the device data structures + */ +static int vpif_update_std_info(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct vpif_params *vpifparams = &ch->vpifparams; + const struct vpif_channel_config_params *config; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; + struct video_obj *vid_ch = &ch->video; + int index; + + vpif_dbg(2, debug, "vpif_update_std_info\n"); + + for (index = 0; index < vpif_ch_params_count; index++) { + config = &ch_params[index]; + if (config->hd_sd == 0) { + vpif_dbg(2, debug, "SD format\n"); + if (config->stdid & vid_ch->stdid) { + memcpy(std_info, config, sizeof(*config)); + break; + } + } else { + vpif_dbg(2, debug, "HD format\n"); + if (config->dv_preset == vid_ch->dv_preset) { + memcpy(std_info, config, sizeof(*config)); + break; + } + } + } + + /* standard not found */ + if (index == vpif_ch_params_count) + return -EINVAL; + + common->fmt.fmt.pix.width = std_info->width; + common->width = std_info->width; + common->fmt.fmt.pix.height = std_info->height; + common->height = std_info->height; + common->fmt.fmt.pix.bytesperline = std_info->width; + vpifparams->video_params.hpitch = std_info->width; + vpifparams->video_params.storage_mode = std_info->frm_fmt; + + return 0; +} + +/** + * vpif_calculate_offsets : This function calculates buffers offsets + * @ch : ptr to channel object + * + * This function calculates buffer offsets for Y and C in the top and + * bottom field + */ +static void vpif_calculate_offsets(struct channel_obj *ch) +{ + unsigned int hpitch, vpitch, sizeimage; + struct video_obj *vid_ch = &(ch->video); + struct vpif_params *vpifparams = &ch->vpifparams; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + enum v4l2_field field = common->fmt.fmt.pix.field; + + vpif_dbg(2, debug, "vpif_calculate_offsets\n"); + + if (V4L2_FIELD_ANY == field) { + if (vpifparams->std_info.frm_fmt) + vid_ch->buf_field = V4L2_FIELD_NONE; + else + vid_ch->buf_field = V4L2_FIELD_INTERLACED; + } else + vid_ch->buf_field = common->fmt.fmt.pix.field; + + if (V4L2_MEMORY_USERPTR == common->memory) + sizeimage = common->fmt.fmt.pix.sizeimage; + else + sizeimage = config_params.channel_bufsize[ch->channel_id]; + + hpitch = common->fmt.fmt.pix.bytesperline; + vpitch = sizeimage / (hpitch * 2); + + if ((V4L2_FIELD_NONE == vid_ch->buf_field) || + (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { + /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ + common->ytop_off = 0; + common->ybtm_off = hpitch; + common->ctop_off = sizeimage / 2; + common->cbtm_off = sizeimage / 2 + hpitch; + } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { + /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ + common->ytop_off = 0; + common->ybtm_off = sizeimage / 4; + common->ctop_off = sizeimage / 2; + common->cbtm_off = common->ctop_off + sizeimage / 4; + } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { + /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ + common->ybtm_off = 0; + common->ytop_off = sizeimage / 4; + common->cbtm_off = sizeimage / 2; + common->ctop_off = common->cbtm_off + sizeimage / 4; + } + if ((V4L2_FIELD_NONE == vid_ch->buf_field) || + (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) + vpifparams->video_params.storage_mode = 1; + else + vpifparams->video_params.storage_mode = 0; + + if (1 == vpifparams->std_info.frm_fmt) + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline; + else { + if ((field == V4L2_FIELD_ANY) + || (field == V4L2_FIELD_INTERLACED)) + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline * 2; + else + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline; + } + + ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid; +} + +/** + * vpif_config_format: configure default frame format in the device + * ch : ptr to channel object + */ +static void vpif_config_format(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_config_format\n"); + + common->fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (config_params.numbuffers[ch->channel_id] == 0) + common->memory = V4L2_MEMORY_USERPTR; + else + common->memory = V4L2_MEMORY_MMAP; + + common->fmt.fmt.pix.sizeimage + = config_params.channel_bufsize[ch->channel_id]; + + if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) + common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; + else + common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; + common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +} + +/** + * vpif_get_default_field() - Get default field type based on interface + * @vpif_params - ptr to vpif params + */ +static inline enum v4l2_field vpif_get_default_field( + struct vpif_interface *iface) +{ + return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE : + V4L2_FIELD_INTERLACED; +} + +/** + * vpif_check_format() - check given pixel format for compatibility + * @ch - channel ptr + * @pixfmt - Given pixel format + * @update - update the values as per hardware requirement + * + * Check the application pixel format for S_FMT and update the input + * values as per hardware limits for TRY_FMT. The default pixel and + * field format is selected based on interface type. + */ +static int vpif_check_format(struct channel_obj *ch, + struct v4l2_pix_format *pixfmt, + int update) +{ + struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); + struct vpif_params *vpif_params = &ch->vpifparams; + enum v4l2_field field = pixfmt->field; + u32 sizeimage, hpitch, vpitch; + int ret = -EINVAL; + + vpif_dbg(2, debug, "vpif_check_format\n"); + /** + * first check for the pixel format. If if_type is Raw bayer, + * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only + * V4L2_PIX_FMT_YUV422P is supported + */ + if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) { + if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) { + if (!update) { + vpif_dbg(2, debug, "invalid pix format\n"); + goto exit; + } + pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8; + } + } else { + if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) { + if (!update) { + vpif_dbg(2, debug, "invalid pixel format\n"); + goto exit; + } + pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P; + } + } + + if (!(VPIF_VALID_FIELD(field))) { + if (!update) { + vpif_dbg(2, debug, "invalid field format\n"); + goto exit; + } + /** + * By default use FIELD_NONE for RAW Bayer capture + * and FIELD_INTERLACED for other interfaces + */ + field = vpif_get_default_field(&vpif_params->iface); + } else if (field == V4L2_FIELD_ANY) + /* unsupported field. Use default */ + field = vpif_get_default_field(&vpif_params->iface); + + /* validate the hpitch */ + hpitch = pixfmt->bytesperline; + if (hpitch < vpif_params->std_info.width) { + if (!update) { + vpif_dbg(2, debug, "invalid hpitch\n"); + goto exit; + } + hpitch = vpif_params->std_info.width; + } + + if (V4L2_MEMORY_USERPTR == common->memory) + sizeimage = pixfmt->sizeimage; + else + sizeimage = config_params.channel_bufsize[ch->channel_id]; + + vpitch = sizeimage / (hpitch * 2); + + /* validate the vpitch */ + if (vpitch < vpif_params->std_info.height) { + if (!update) { + vpif_dbg(2, debug, "Invalid vpitch\n"); + goto exit; + } + vpitch = vpif_params->std_info.height; + } + + /* Check for 8 byte alignment */ + if (!ALIGN(hpitch, 8)) { + if (!update) { + vpif_dbg(2, debug, "invalid pitch alignment\n"); + goto exit; + } + /* adjust to next 8 byte boundary */ + hpitch = (((hpitch + 7) / 8) * 8); + } + /* if update is set, modify the bytesperline and sizeimage */ + if (update) { + pixfmt->bytesperline = hpitch; + pixfmt->sizeimage = hpitch * vpitch * 2; + } + /** + * Image width and height is always based on current standard width and + * height + */ + pixfmt->width = common->fmt.fmt.pix.width; + pixfmt->height = common->fmt.fmt.pix.height; + return 0; +exit: + return ret; +} + +/** + * vpif_config_addr() - function to configure buffer address in vpif + * @ch - channel ptr + * @muxmode - channel mux mode + */ +static void vpif_config_addr(struct channel_obj *ch, int muxmode) +{ + struct common_obj *common; + + vpif_dbg(2, debug, "vpif_config_addr\n"); + + common = &(ch->common[VPIF_VIDEO_INDEX]); + + if (VPIF_CHANNEL1_VIDEO == ch->channel_id) + common->set_addr = ch1_set_videobuf_addr; + else if (2 == muxmode) + common->set_addr = ch0_set_videobuf_addr_yc_nmux; + else + common->set_addr = ch0_set_videobuf_addr; +} + +/** + * vpfe_mmap : It is used to map kernel space buffers into user spaces + * @filep: file pointer + * @vma: ptr to vm_area_struct + */ +static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) +{ + /* Get the channel object and file handle object */ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); + + vpif_dbg(2, debug, "vpif_mmap\n"); + + return videobuf_mmap_mapper(&common->buffer_queue, vma); +} + +/** + * vpif_poll: It is used for select/poll system call + * @filep: file pointer + * @wait: poll table to wait + */ +static unsigned int vpif_poll(struct file *filep, poll_table * wait) +{ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *channel = fh->channel; + struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]); + + vpif_dbg(2, debug, "vpif_poll\n"); + + if (common->started) + return videobuf_poll_stream(filep, &common->buffer_queue, wait); + return 0; +} + +/** + * vpif_open : vpif open handler + * @filep: file ptr + * + * It creates object of file handle structure and stores it in private_data + * member of filepointer + */ +static int vpif_open(struct file *filep) +{ + struct vpif_capture_config *config = vpif_dev->platform_data; + struct video_device *vdev = video_devdata(filep); + struct common_obj *common; + struct video_obj *vid_ch; + struct channel_obj *ch; + struct vpif_fh *fh; + int i; + + vpif_dbg(2, debug, "vpif_open\n"); + + ch = video_get_drvdata(vdev); + + vid_ch = &ch->video; + common = &ch->common[VPIF_VIDEO_INDEX]; + + if (NULL == ch->curr_subdev_info) { + /** + * search through the sub device to see a registered + * sub device and make it as current sub device + */ + for (i = 0; i < config->subdev_count; i++) { + if (vpif_obj.sd[i]) { + /* the sub device is registered */ + ch->curr_subdev_info = &config->subdev_info[i]; + /* make first input as the current input */ + vid_ch->input_idx = 0; + break; + } + } + if (i == config->subdev_count) { + vpif_err("No sub device registered\n"); + return -ENOENT; + } + } + + /* Allocate memory for the file handle object */ + fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); + if (NULL == fh) { + vpif_err("unable to allocate memory for file handle object\n"); + return -ENOMEM; + } + + /* store pointer to fh in private_data member of filep */ + filep->private_data = fh; + fh->channel = ch; + fh->initialized = 0; + /* If decoder is not initialized. initialize it */ + if (!ch->initialized) { + fh->initialized = 1; + ch->initialized = 1; + memset(&(ch->vpifparams), 0, sizeof(struct vpif_params)); + } + /* Increment channel usrs counter */ + ch->usrs++; + /* Set io_allowed member to false */ + fh->io_allowed[VPIF_VIDEO_INDEX] = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&ch->prio, &fh->prio); + return 0; +} + +/** + * vpif_release : function to clean up file close + * @filep: file pointer + * + * This function deletes buffer queue, frees the buffers and the vpfe file + * handle + */ +static int vpif_release(struct file *filep) +{ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + vpif_dbg(2, debug, "vpif_release\n"); + + common = &ch->common[VPIF_VIDEO_INDEX]; + + /* if this instance is doing IO */ + if (fh->io_allowed[VPIF_VIDEO_INDEX]) { + /* Reset io_usrs member of channel object */ + common->io_usrs = 0; + /* Disable channel as per its device type and channel id */ + if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { + enable_channel0(0); + channel0_intr_enable(0); + } + if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || + (2 == common->started)) { + enable_channel1(0); + channel1_intr_enable(0); + } + common->started = 0; + /* Free buffers allocated */ + videobuf_queue_cancel(&common->buffer_queue); + videobuf_mmap_free(&common->buffer_queue); + } + + /* Decrement channel usrs counter */ + ch->usrs--; + + /* Close the priority */ + v4l2_prio_close(&ch->prio, fh->prio); + + if (fh->initialized) + ch->initialized = 0; + + filep->private_data = NULL; + kfree(fh); + return 0; +} + +/** + * vpif_reqbufs() - request buffer handler + * @file: file ptr + * @priv: file handle + * @reqbuf: request buffer structure ptr + */ +static int vpif_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbuf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + u8 index = 0; + + vpif_dbg(2, debug, "vpif_reqbufs\n"); + + /** + * This file handle has not initialized the channel, + * It is not allowed to do settings + */ + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) + || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type) + return -EINVAL; + + index = VPIF_VIDEO_INDEX; + + common = &ch->common[index]; + + if (0 != common->io_usrs) + return -EBUSY; + + /* Initialize videobuf queue as per the buffer type */ + videobuf_queue_dma_contig_init(&common->buffer_queue, + &video_qops, NULL, + &common->irqlock, + reqbuf->type, + common->fmt.fmt.pix.field, + sizeof(struct videobuf_buffer), fh, + &common->lock); + + /* Set io allowed member of file handle to TRUE */ + fh->io_allowed[index] = 1; + /* Increment io usrs member of channel object to 1 */ + common->io_usrs = 1; + /* Store type of memory requested in channel object */ + common->memory = reqbuf->memory; + INIT_LIST_HEAD(&common->dma_queue); + + /* Allocate buffers */ + return videobuf_reqbufs(&common->buffer_queue, reqbuf); +} + +/** + * vpif_querybuf() - query buffer handler + * @file: file ptr + * @priv: file handle + * @buf: v4l2 buffer structure ptr + */ +static int vpif_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_querybuf\n"); + + if (common->fmt.type != buf->type) + return -EINVAL; + + if (common->memory != V4L2_MEMORY_MMAP) { + vpif_dbg(1, debug, "Invalid memory\n"); + return -EINVAL; + } + + return videobuf_querybuf(&common->buffer_queue, buf); +} + +/** + * vpif_qbuf() - query buffer handler + * @file: file ptr + * @priv: file handle + * @buf: v4l2 buffer structure ptr + */ +static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct v4l2_buffer tbuf = *buf; + struct videobuf_buffer *buf1; + unsigned long addr = 0; + unsigned long flags; + int ret = 0; + + vpif_dbg(2, debug, "vpif_qbuf\n"); + + if (common->fmt.type != tbuf.type) { + vpif_err("invalid buffer type\n"); + return -EINVAL; + } + + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_err("fh io not allowed \n"); + return -EACCES; + } + + if (!(list_empty(&common->dma_queue)) || + (common->cur_frm != common->next_frm) || + !common->started || + (common->started && (0 == ch->field_id))) + return videobuf_qbuf(&common->buffer_queue, buf); + + /* bufferqueue is empty store buffer address in VPIF registers */ + mutex_lock(&common->buffer_queue.vb_lock); + buf1 = common->buffer_queue.bufs[tbuf.index]; + + if ((buf1->state == VIDEOBUF_QUEUED) || + (buf1->state == VIDEOBUF_ACTIVE)) { + vpif_err("invalid state\n"); + goto qbuf_exit; + } + + switch (buf1->memory) { + case V4L2_MEMORY_MMAP: + if (buf1->baddr == 0) + goto qbuf_exit; + break; + + case V4L2_MEMORY_USERPTR: + if (tbuf.length < buf1->bsize) + goto qbuf_exit; + + if ((VIDEOBUF_NEEDS_INIT != buf1->state) + && (buf1->baddr != tbuf.m.userptr)) { + vpif_buffer_release(&common->buffer_queue, buf1); + buf1->baddr = tbuf.m.userptr; + } + break; + + default: + goto qbuf_exit; + } + + local_irq_save(flags); + ret = vpif_buffer_prepare(&common->buffer_queue, buf1, + common->buffer_queue.field); + if (ret < 0) { + local_irq_restore(flags); + goto qbuf_exit; + } + + buf1->state = VIDEOBUF_ACTIVE; + + if (V4L2_MEMORY_USERPTR == common->memory) + addr = buf1->boff; + else + addr = videobuf_to_dma_contig(buf1); + + common->next_frm = buf1; + common->set_addr(addr + common->ytop_off, + addr + common->ybtm_off, + addr + common->ctop_off, + addr + common->cbtm_off); + + local_irq_restore(flags); + list_add_tail(&buf1->stream, &common->buffer_queue.stream); + mutex_unlock(&common->buffer_queue.vb_lock); + return 0; + +qbuf_exit: + mutex_unlock(&common->buffer_queue.vb_lock); + return -EINVAL; +} + +/** + * vpif_dqbuf() - query buffer handler + * @file: file ptr + * @priv: file handle + * @buf: v4l2 buffer structure ptr + */ +static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_dqbuf\n"); + + return videobuf_dqbuf(&common->buffer_queue, buf, + file->f_flags & O_NONBLOCK); +} + +/** + * vpif_streamon() - streamon handler + * @file: file ptr + * @priv: file handle + * @buftype: v4l2 buffer type + */ +static int vpif_streamon(struct file *file, void *priv, + enum v4l2_buf_type buftype) +{ + + struct vpif_capture_config *config = vpif_dev->platform_data; + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; + struct vpif_params *vpif; + unsigned long addr = 0; + int ret = 0; + + vpif_dbg(2, debug, "vpif_streamon\n"); + + vpif = &ch->vpifparams; + + if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + vpif_dbg(1, debug, "buffer type not supported\n"); + return -EINVAL; + } + + /* If file handle is not allowed IO, return error */ + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_dbg(1, debug, "io not allowed\n"); + return -EACCES; + } + + /* If Streaming is already started, return error */ + if (common->started) { + vpif_dbg(1, debug, "channel->started\n"); + return -EBUSY; + } + + if ((ch->channel_id == VPIF_CHANNEL0_VIDEO && + oth_ch->common[VPIF_VIDEO_INDEX].started && + vpif->std_info.ycmux_mode == 0) || + ((ch->channel_id == VPIF_CHANNEL1_VIDEO) && + (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { + vpif_dbg(1, debug, "other channel is being used\n"); + return -EBUSY; + } + + ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0); + if (ret) + return ret; + + /* Enable streamon on the sub device */ + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, + s_stream, 1); + + if (ret && (ret != -ENOIOCTLCMD)) { + vpif_dbg(1, debug, "stream on failed in subdev\n"); + return ret; + } + + /* Call videobuf_streamon to start streaming in videobuf */ + ret = videobuf_streamon(&common->buffer_queue); + if (ret) { + vpif_dbg(1, debug, "videobuf_streamon\n"); + return ret; + } + + /* If buffer queue is empty, return error */ + if (list_empty(&common->dma_queue)) { + vpif_dbg(1, debug, "buffer queue is empty\n"); + ret = -EIO; + goto exit; + } + + /* Get the next frame from the buffer queue */ + common->cur_frm = list_entry(common->dma_queue.next, + struct videobuf_buffer, queue); + common->next_frm = common->cur_frm; + + /* Remove buffer from the buffer queue */ + list_del(&common->cur_frm->queue); + /* Mark state of the current frame to active */ + common->cur_frm->state = VIDEOBUF_ACTIVE; + /* Initialize field_id and started member */ + ch->field_id = 0; + common->started = 1; + + if (V4L2_MEMORY_USERPTR == common->memory) + addr = common->cur_frm->boff; + else + addr = videobuf_to_dma_contig(common->cur_frm); + + /* Calculate the offset for Y and C data in the buffer */ + vpif_calculate_offsets(ch); + + if ((vpif->std_info.frm_fmt && + ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && + (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || + (!vpif->std_info.frm_fmt && + (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { + vpif_dbg(1, debug, "conflict in field format and std format\n"); + ret = -EINVAL; + goto exit; + } + + /* configure 1 or 2 channel mode */ + ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); + + if (ret < 0) { + vpif_dbg(1, debug, "can't set vpif channel mode\n"); + goto exit; + } + + /* Call vpif_set_params function to set the parameters and addresses */ + ret = vpif_set_video_params(vpif, ch->channel_id); + + if (ret < 0) { + vpif_dbg(1, debug, "can't set video params\n"); + goto exit; + } + + common->started = ret; + vpif_config_addr(ch, ret); + + common->set_addr(addr + common->ytop_off, + addr + common->ybtm_off, + addr + common->ctop_off, + addr + common->cbtm_off); + + /** + * Set interrupt for both the fields in VPIF Register enable channel in + * VPIF register + */ + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { + channel0_intr_assert(); + channel0_intr_enable(1); + enable_channel0(1); + } + if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || + (common->started == 2)) { + channel1_intr_assert(); + channel1_intr_enable(1); + enable_channel1(1); + } + channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; + return ret; + +exit: + videobuf_streamoff(&common->buffer_queue); + return ret; +} + +/** + * vpif_streamoff() - streamoff handler + * @file: file ptr + * @priv: file handle + * @buftype: v4l2 buffer type + */ +static int vpif_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buftype) +{ + + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret; + + vpif_dbg(2, debug, "vpif_streamoff\n"); + + if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + vpif_dbg(1, debug, "buffer type not supported\n"); + return -EINVAL; + } + + /* If io is allowed for this file handle, return error */ + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_dbg(1, debug, "io not allowed\n"); + return -EACCES; + } + + /* If streaming is not started, return error */ + if (!common->started) { + vpif_dbg(1, debug, "channel->started\n"); + return -EINVAL; + } + + /* disable channel */ + if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { + enable_channel0(0); + channel0_intr_enable(0); + } else { + enable_channel1(0); + channel1_intr_enable(0); + } + + common->started = 0; + + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, + s_stream, 0); + + if (ret && (ret != -ENOIOCTLCMD)) + vpif_dbg(1, debug, "stream off failed in subdev\n"); + + return videobuf_streamoff(&common->buffer_queue); +} + +/** + * vpif_map_sub_device_to_input() - Maps sub device to input + * @ch - ptr to channel + * @config - ptr to capture configuration + * @input_index - Given input index from application + * @sub_device_index - index into sd table + * + * lookup the sub device information for a given input index. + * we report all the inputs to application. inputs table also + * has sub device name for the each input + */ +static struct vpif_subdev_info *vpif_map_sub_device_to_input( + struct channel_obj *ch, + struct vpif_capture_config *vpif_cfg, + int input_index, + int *sub_device_index) +{ + struct vpif_capture_chan_config *chan_cfg; + struct vpif_subdev_info *subdev_info = NULL; + const char *subdev_name = NULL; + int i; + + vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); + + chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; + + /** + * search through the inputs to find the sub device supporting + * the input + */ + for (i = 0; i < chan_cfg->input_count; i++) { + /* For each sub device, loop through input */ + if (i == input_index) { + subdev_name = chan_cfg->inputs[i].subdev_name; + break; + } + } + + /* if reached maximum. return null */ + if (i == chan_cfg->input_count || (NULL == subdev_name)) + return subdev_info; + + /* loop through the sub device list to get the sub device info */ + for (i = 0; i < vpif_cfg->subdev_count; i++) { + subdev_info = &vpif_cfg->subdev_info[i]; + if (!strcmp(subdev_info->name, subdev_name)) + break; + } + + if (i == vpif_cfg->subdev_count) + return subdev_info; + + /* check if the sub device is registered */ + if (NULL == vpif_obj.sd[i]) + return NULL; + + *sub_device_index = i; + return subdev_info; +} + +/** + * vpif_querystd() - querystd handler + * @file: file ptr + * @priv: file handle + * @std_id: ptr to std id + * + * This function is called to detect standard at the selected input + */ +static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + int ret = 0; + + vpif_dbg(2, debug, "vpif_querystd\n"); + + /* Call querystd function of decoder device */ + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, + querystd, std_id); + if (ret < 0) + vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); + + return ret; +} + +/** + * vpif_g_std() - get STD handler + * @file: file ptr + * @priv: file handle + * @std_id: ptr to std id + */ +static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + vpif_dbg(2, debug, "vpif_g_std\n"); + + *std = ch->video.stdid; + return 0; +} + +/** + * vpif_s_std() - set STD handler + * @file: file ptr + * @priv: file handle + * @std_id: ptr to std id + */ +static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + vpif_dbg(2, debug, "vpif_s_std\n"); + + if (common->started) { + vpif_err("streaming in progress\n"); + return -EBUSY; + } + + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || + (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + ret = v4l2_prio_check(&ch->prio, fh->prio); + if (0 != ret) + return ret; + + fh->initialized = 1; + + /* Call encoder subdevice function to set the standard */ + ch->video.stdid = *std_id; + ch->video.dv_preset = V4L2_DV_INVALID; + memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); + + /* Get the information about the standard */ + if (vpif_update_std_info(ch)) { + vpif_err("Error getting the standard info\n"); + return -EINVAL; + } + + /* Configure the default format information */ + vpif_config_format(ch); + + /* set standard in the sub device */ + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, + s_std, *std_id); + if (ret < 0) + vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); + return ret; +} + +/** + * vpif_enum_input() - ENUMINPUT handler + * @file: file ptr + * @priv: file handle + * @input: ptr to input structure + */ +static int vpif_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + + struct vpif_capture_config *config = vpif_dev->platform_data; + struct vpif_capture_chan_config *chan_cfg; + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + chan_cfg = &config->chan_config[ch->channel_id]; + + if (input->index >= chan_cfg->input_count) { + vpif_dbg(1, debug, "Invalid input index\n"); + return -EINVAL; + } + + memcpy(input, &chan_cfg->inputs[input->index].input, + sizeof(*input)); + return 0; +} + +/** + * vpif_g_input() - Get INPUT handler + * @file: file ptr + * @priv: file handle + * @index: ptr to input index + */ +static int vpif_g_input(struct file *file, void *priv, unsigned int *index) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + *index = vid_ch->input_idx; + + return 0; +} + +/** + * vpif_s_input() - Set INPUT handler + * @file: file ptr + * @priv: file handle + * @index: input index + */ +static int vpif_s_input(struct file *file, void *priv, unsigned int index) +{ + struct vpif_capture_config *config = vpif_dev->platform_data; + struct vpif_capture_chan_config *chan_cfg; + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct video_obj *vid_ch = &ch->video; + struct vpif_subdev_info *subdev_info; + int ret = 0, sd_index = 0; + u32 input = 0, output = 0; + + chan_cfg = &config->chan_config[ch->channel_id]; + + if (common->started) { + vpif_err("Streaming in progress\n"); + return -EBUSY; + } + + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || + (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + ret = v4l2_prio_check(&ch->prio, fh->prio); + if (0 != ret) + return ret; + + fh->initialized = 1; + subdev_info = vpif_map_sub_device_to_input(ch, config, index, + &sd_index); + if (NULL == subdev_info) { + vpif_dbg(1, debug, + "couldn't lookup sub device for the input index\n"); + return -EINVAL; + } + + /* first setup input path from sub device to vpif */ + if (config->setup_input_path) { + ret = config->setup_input_path(ch->channel_id, + subdev_info->name); + if (ret < 0) { + vpif_dbg(1, debug, "couldn't setup input path for the" + " sub device %s, for input index %d\n", + subdev_info->name, index); + return ret; + } + } + + if (subdev_info->can_route) { + input = subdev_info->input; + output = subdev_info->output; + ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, + input, output, 0); + if (ret < 0) { + vpif_dbg(1, debug, "Failed to set input\n"); + return ret; + } + } + vid_ch->input_idx = index; + ch->curr_subdev_info = subdev_info; + ch->curr_sd_index = sd_index; + /* copy interface parameters to vpif */ + ch->vpifparams.iface = subdev_info->vpif_if; + + /* update tvnorms from the sub device input info */ + ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; + return ret; +} + +/** + * vpif_enum_fmt_vid_cap() - ENUM_FMT handler + * @file: file ptr + * @priv: file handle + * @index: input index + */ +static int vpif_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + if (fmt->index != 0) { + vpif_dbg(1, debug, "Invalid format index\n"); + return -EINVAL; + } + + /* Fill in the information about format */ + if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) { + fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb"); + fmt->pixelformat = V4L2_PIX_FMT_SBGGR8; + } else { + fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); + fmt->pixelformat = V4L2_PIX_FMT_YUV422P; + } + return 0; +} + +/** + * vpif_try_fmt_vid_cap() - TRY_FMT handler + * @file: file ptr + * @priv: file handle + * @fmt: ptr to v4l2 format structure + */ +static int vpif_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + return vpif_check_format(ch, pixfmt, 1); +} + + +/** + * vpif_g_fmt_vid_cap() - Set INPUT handler + * @file: file ptr + * @priv: file handle + * @fmt: ptr to v4l2 format structure + */ +static int vpif_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + /* Check the validity of the buffer type */ + if (common->fmt.type != fmt->type) + return -EINVAL; + + /* Fill in the information about format */ + *fmt = common->fmt; + return 0; +} + +/** + * vpif_s_fmt_vid_cap() - Set FMT handler + * @file: file ptr + * @priv: file handle + * @fmt: ptr to v4l2 format structure + */ +static int vpif_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct v4l2_pix_format *pixfmt; + int ret = 0; + + vpif_dbg(2, debug, "%s\n", __func__); + + /* If streaming is started, return error */ + if (common->started) { + vpif_dbg(1, debug, "Streaming is started\n"); + return -EBUSY; + } + + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || + (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + ret = v4l2_prio_check(&ch->prio, fh->prio); + if (0 != ret) + return ret; + + fh->initialized = 1; + + pixfmt = &fmt->fmt.pix; + /* Check for valid field format */ + ret = vpif_check_format(ch, pixfmt, 0); + + if (ret) + return ret; + /* store the format in the channel object */ + common->fmt = *fmt; + return 0; +} + +/** + * vpif_querycap() - QUERYCAP handler + * @file: file ptr + * @priv: file handle + * @cap: ptr to v4l2_capability structure + */ +static int vpif_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpif_capture_config *config = vpif_dev->platform_data; + + cap->version = VPIF_CAPTURE_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); + strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); + strlcpy(cap->card, config->card_name, sizeof(cap->card)); + + return 0; +} + +/** + * vpif_g_priority() - get priority handler + * @file: file ptr + * @priv: file handle + * @prio: ptr to v4l2_priority structure + */ +static int vpif_g_priority(struct file *file, void *priv, + enum v4l2_priority *prio) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + *prio = v4l2_prio_max(&ch->prio); + + return 0; +} + +/** + * vpif_s_priority() - set priority handler + * @file: file ptr + * @priv: file handle + * @prio: ptr to v4l2_priority structure + */ +static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_prio_change(&ch->prio, &fh->prio, p); +} + +/** + * vpif_cropcap() - cropcap handler + * @file: file ptr + * @priv: file handle + * @crop: ptr to v4l2_cropcap structure + */ +static int vpif_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *crop) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type) + return -EINVAL; + + crop->bounds.left = 0; + crop->bounds.top = 0; + crop->bounds.height = common->height; + crop->bounds.width = common->width; + crop->defrect = crop->bounds; + return 0; +} + +/** + * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_enum_dv_presets(struct file *file, void *priv, + struct v4l2_dv_enum_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], + video, enum_dv_presets, preset); +} + +/** + * vpif_query_dv_presets() - QUERY_DV_PRESET handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_query_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], + video, query_dv_preset, preset); +} +/** + * vpif_s_dv_presets() - S_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_s_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + if (common->started) { + vpif_dbg(1, debug, "streaming in progress\n"); + return -EBUSY; + } + + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || + (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + ret = v4l2_prio_check(&ch->prio, fh->prio); + if (ret) + return ret; + + fh->initialized = 1; + + /* Call encoder subdevice function to set the standard */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + ch->video.dv_preset = preset->preset; + ch->video.stdid = V4L2_STD_UNKNOWN; + memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); + + /* Get the information about the standard */ + if (vpif_update_std_info(ch)) { + vpif_dbg(1, debug, "Error getting the standard info\n"); + ret = -EINVAL; + } else { + /* Configure the default format information */ + vpif_config_format(ch); + + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], + video, s_dv_preset, preset); + } + + mutex_unlock(&common->lock); + + return ret; +} +/** + * vpif_g_dv_presets() - G_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_g_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + preset->preset = ch->video.dv_preset; + + return 0; +} + +/** + * vpif_s_dv_timings() - S_DV_TIMINGS handler + * @file: file ptr + * @priv: file handle + * @timings: digital video timings + */ +static int vpif_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct vpif_params *vpifparams = &ch->vpifparams; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; + struct video_obj *vid_ch = &ch->video; + struct v4l2_bt_timings *bt = &vid_ch->bt_timings; + int ret; + + if (timings->type != V4L2_DV_BT_656_1120) { + vpif_dbg(2, debug, "Timing type not defined\n"); + return -EINVAL; + } + + /* Configure subdevice timings, if any */ + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], + video, s_dv_timings, timings); + if (ret == -ENOIOCTLCMD) { + vpif_dbg(2, debug, "Custom DV timings not supported by " + "subdevice\n"); + return -EINVAL; + } + if (ret < 0) { + vpif_dbg(2, debug, "Error setting custom DV timings\n"); + return ret; + } + + if (!(timings->bt.width && timings->bt.height && + (timings->bt.hbackporch || + timings->bt.hfrontporch || + timings->bt.hsync) && + timings->bt.vfrontporch && + (timings->bt.vbackporch || + timings->bt.vsync))) { + vpif_dbg(2, debug, "Timings for width, height, " + "horizontal back porch, horizontal sync, " + "horizontal front porch, vertical back porch, " + "vertical sync and vertical back porch " + "must be defined\n"); + return -EINVAL; + } + + *bt = timings->bt; + + /* Configure video port timings */ + + std_info->eav2sav = bt->hbackporch + bt->hfrontporch + + bt->hsync - 8; + std_info->sav2eav = bt->width; + + std_info->l1 = 1; + std_info->l3 = bt->vsync + bt->vbackporch + 1; + + if (bt->interlaced) { + if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) { + std_info->vsize = bt->height * 2 + + bt->vfrontporch + bt->vsync + bt->vbackporch + + bt->il_vfrontporch + bt->il_vsync + + bt->il_vbackporch; + std_info->l5 = std_info->vsize/2 - + (bt->vfrontporch - 1); + std_info->l7 = std_info->vsize/2 + 1; + std_info->l9 = std_info->l7 + bt->il_vsync + + bt->il_vbackporch + 1; + std_info->l11 = std_info->vsize - + (bt->il_vfrontporch - 1); + } else { + vpif_dbg(2, debug, "Required timing values for " + "interlaced BT format missing\n"); + return -EINVAL; + } + } else { + std_info->vsize = bt->height + bt->vfrontporch + + bt->vsync + bt->vbackporch; + std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); + } + strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME); + std_info->width = bt->width; + std_info->height = bt->height; + std_info->frm_fmt = bt->interlaced ? 0 : 1; + std_info->ycmux_mode = 0; + std_info->capture_format = 0; + std_info->vbi_supported = 0; + std_info->hd_sd = 1; + std_info->stdid = 0; + std_info->dv_preset = V4L2_DV_INVALID; + + vid_ch->stdid = 0; + vid_ch->dv_preset = V4L2_DV_INVALID; + return 0; +} + +/** + * vpif_g_dv_timings() - G_DV_TIMINGS handler + * @file: file ptr + * @priv: file handle + * @timings: digital video timings + */ +static int vpif_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + struct v4l2_bt_timings *bt = &vid_ch->bt_timings; + + timings->bt = *bt; + + return 0; +} + +/* + * vpif_g_chip_ident() - Identify the chip + * @file: file ptr + * @priv: file handle + * @chip: chip identity + * + * Returns zero or -EINVAL if read operations fails. + */ +static int vpif_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && + chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) { + vpif_dbg(2, debug, "match_type is invalid.\n"); + return -EINVAL; + } + + return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core, + g_chip_ident, chip); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* + * vpif_dbg_g_register() - Read register + * @file: file ptr + * @priv: file handle + * @reg: register to be read + * + * Debugging only + * Returns zero or -EINVAL if read operations fails. + */ +static int vpif_dbg_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg){ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, + g_register, reg); +} + +/* + * vpif_dbg_s_register() - Write to register + * @file: file ptr + * @priv: file handle + * @reg: register to be modified + * + * Debugging only + * Returns zero or -EINVAL if write operations fails. + */ +static int vpif_dbg_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg){ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, + s_register, reg); +} +#endif + +/* + * vpif_log_status() - Status information + * @file: file ptr + * @priv: file handle + * + * Returns zero. + */ +static int vpif_log_status(struct file *filep, void *priv) +{ + /* status for sub devices */ + v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status); + + return 0; +} + +/* vpif capture ioctl operations */ +static const struct v4l2_ioctl_ops vpif_ioctl_ops = { + .vidioc_querycap = vpif_querycap, + .vidioc_g_priority = vpif_g_priority, + .vidioc_s_priority = vpif_s_priority, + .vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap, + .vidioc_enum_input = vpif_enum_input, + .vidioc_s_input = vpif_s_input, + .vidioc_g_input = vpif_g_input, + .vidioc_reqbufs = vpif_reqbufs, + .vidioc_querybuf = vpif_querybuf, + .vidioc_querystd = vpif_querystd, + .vidioc_s_std = vpif_s_std, + .vidioc_g_std = vpif_g_std, + .vidioc_qbuf = vpif_qbuf, + .vidioc_dqbuf = vpif_dqbuf, + .vidioc_streamon = vpif_streamon, + .vidioc_streamoff = vpif_streamoff, + .vidioc_cropcap = vpif_cropcap, + .vidioc_enum_dv_presets = vpif_enum_dv_presets, + .vidioc_s_dv_preset = vpif_s_dv_preset, + .vidioc_g_dv_preset = vpif_g_dv_preset, + .vidioc_query_dv_preset = vpif_query_dv_preset, + .vidioc_s_dv_timings = vpif_s_dv_timings, + .vidioc_g_dv_timings = vpif_g_dv_timings, + .vidioc_g_chip_ident = vpif_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vpif_dbg_g_register, + .vidioc_s_register = vpif_dbg_s_register, +#endif + .vidioc_log_status = vpif_log_status, +}; + +/* vpif file operations */ +static struct v4l2_file_operations vpif_fops = { + .owner = THIS_MODULE, + .open = vpif_open, + .release = vpif_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vpif_mmap, + .poll = vpif_poll +}; + +/* vpif video template */ +static struct video_device vpif_video_template = { + .name = "vpif", + .fops = &vpif_fops, + .minor = -1, + .ioctl_ops = &vpif_ioctl_ops, +}; + +/** + * initialize_vpif() - Initialize vpif data structures + * + * Allocate memory for data structures and initialize them + */ +static int initialize_vpif(void) +{ + int err = 0, i, j; + int free_channel_objects_index; + + /* Default number of buffers should be 3 */ + if ((ch0_numbuffers > 0) && + (ch0_numbuffers < config_params.min_numbuffers)) + ch0_numbuffers = config_params.min_numbuffers; + if ((ch1_numbuffers > 0) && + (ch1_numbuffers < config_params.min_numbuffers)) + ch1_numbuffers = config_params.min_numbuffers; + + /* Set buffer size to min buffers size if it is invalid */ + if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]) + ch0_bufsize = + config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]; + if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]) + ch1_bufsize = + config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]; + + config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers; + config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers; + if (ch0_numbuffers) { + config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO] + = ch0_bufsize; + } + if (ch1_numbuffers) { + config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO] + = ch1_bufsize; + } + + /* Allocate memory for six channel objects */ + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + vpif_obj.dev[i] = + kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL); + /* If memory allocation fails, return error */ + if (!vpif_obj.dev[i]) { + free_channel_objects_index = i; + err = -ENOMEM; + goto vpif_init_free_channel_objects; + } + } + return 0; + +vpif_init_free_channel_objects: + for (j = 0; j < free_channel_objects_index; j++) + kfree(vpif_obj.dev[j]); + return err; +} + +/** + * vpif_probe : This function probes the vpif capture driver + * @pdev: platform device pointer + * + * This creates device entries by register itself to the V4L2 driver and + * initializes fields of each channel objects + */ +static __init int vpif_probe(struct platform_device *pdev) +{ + struct vpif_subdev_info *subdevdata; + struct vpif_capture_config *config; + int i, j, k, m, q, err; + struct i2c_adapter *i2c_adap; + struct channel_obj *ch; + struct common_obj *common; + struct video_device *vfd; + struct resource *res; + int subdev_count; + + vpif_dev = &pdev->dev; + + err = initialize_vpif(); + if (err) { + v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); + return err; + } + + k = 0; + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + for (i = res->start; i <= res->end; i++) { + if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, + "DM646x_Capture", + (void *)(&vpif_obj.dev[k]->channel_id))) { + err = -EBUSY; + i--; + goto vpif_int_err; + } + } + k++; + } + + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + /* Allocate memory for video device */ + vfd = video_device_alloc(); + if (NULL == vfd) { + for (j = 0; j < i; j++) { + ch = vpif_obj.dev[j]; + video_device_release(ch->video_dev); + } + err = -ENOMEM; + goto vpif_dev_alloc_err; + } + + /* Initialize field of video device */ + *vfd = vpif_video_template; + vfd->v4l2_dev = &vpif_obj.v4l2_dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), + "DM646x_VPIFCapture_DRIVER_V%d.%d.%d", + (VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff, + (VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff, + (VPIF_CAPTURE_VERSION_CODE) & 0xff); + /* Set video_dev to the video device */ + ch->video_dev = vfd; + } + + for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + ch->channel_id = j; + common = &(ch->common[VPIF_VIDEO_INDEX]); + spin_lock_init(&common->irqlock); + mutex_init(&common->lock); + ch->video_dev->lock = &common->lock; + /* Initialize prio member of channel object */ + v4l2_prio_init(&ch->prio); + err = video_register_device(ch->video_dev, + VFL_TYPE_GRABBER, (j ? 1 : 0)); + if (err) + goto probe_out; + + video_set_drvdata(ch->video_dev, ch); + + } + + i2c_adap = i2c_get_adapter(1); + config = pdev->dev.platform_data; + + subdev_count = config->subdev_count; + vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, + GFP_KERNEL); + if (vpif_obj.sd == NULL) { + vpif_err("unable to allocate memory for subdevice pointers\n"); + err = -ENOMEM; + goto probe_out; + } + + err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); + if (err) { + v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); + goto probe_subdev_out; + } + + for (i = 0; i < subdev_count; i++) { + subdevdata = &config->subdev_info[i]; + vpif_obj.sd[i] = + v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, + i2c_adap, + &subdevdata->board_info, + NULL); + + if (!vpif_obj.sd[i]) { + vpif_err("Error registering v4l2 subdevice\n"); + goto probe_subdev_out; + } + v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n", + subdevdata->name); + + if (vpif_obj.sd[i]) + vpif_obj.sd[i]->grp_id = 1 << i; + } + + v4l2_info(&vpif_obj.v4l2_dev, + "DM646x VPIF capture driver initialized\n"); + return 0; + +probe_subdev_out: + /* free sub devices memory */ + kfree(vpif_obj.sd); + + j = VPIF_CAPTURE_MAX_DEVICES; +probe_out: + v4l2_device_unregister(&vpif_obj.v4l2_dev); + for (k = 0; k < j; k++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[k]; + /* Unregister video device */ + video_unregister_device(ch->video_dev); + } + +vpif_dev_alloc_err: + k = VPIF_CAPTURE_MAX_DEVICES-1; + res = platform_get_resource(pdev, IORESOURCE_IRQ, k); + i = res->end; + +vpif_int_err: + for (q = k; q >= 0; q--) { + for (m = i; m >= (int)res->start; m--) + free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); + if (res) + i = res->end; + } + return err; +} + +/** + * vpif_remove() - driver remove handler + * @device: ptr to platform device structure + * + * The vidoe device is unregistered + */ +static int vpif_remove(struct platform_device *device) +{ + int i; + struct channel_obj *ch; + + v4l2_device_unregister(&vpif_obj.v4l2_dev); + + /* un-register device */ + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + /* Unregister video device */ + video_unregister_device(ch->video_dev); + } + return 0; +} + +/** + * vpif_suspend: vpif device suspend + * + * TODO: Add suspend code here + */ +static int +vpif_suspend(struct device *dev) +{ + return -1; +} + +/** + * vpif_resume: vpif device suspend + * + * TODO: Add resume code here + */ +static int +vpif_resume(struct device *dev) +{ + return -1; +} + +static const struct dev_pm_ops vpif_dev_pm_ops = { + .suspend = vpif_suspend, + .resume = vpif_resume, +}; + +static __refdata struct platform_driver vpif_driver = { + .driver = { + .name = "vpif_capture", + .owner = THIS_MODULE, + .pm = &vpif_dev_pm_ops, + }, + .probe = vpif_probe, + .remove = vpif_remove, +}; + +/** + * vpif_init: initialize the vpif driver + * + * This function registers device and driver to the kernel, requests irq + * handler and allocates memory + * for channel objects + */ +static __init int vpif_init(void) +{ + return platform_driver_register(&vpif_driver); +} + +/** + * vpif_cleanup : This function clean up the vpif capture resources + * + * This will un-registers device and driver to the kernel, frees + * requested irq handler and de-allocates memory allocated for channel + * objects. + */ +static void vpif_cleanup(void) +{ + struct platform_device *pdev; + struct resource *res; + int irq_num; + int i = 0; + + pdev = container_of(vpif_dev, struct platform_device, dev); + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { + for (irq_num = res->start; irq_num <= res->end; irq_num++) + free_irq(irq_num, + (void *)(&vpif_obj.dev[i]->channel_id)); + i++; + } + + platform_driver_unregister(&vpif_driver); + + kfree(vpif_obj.sd); + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) + kfree(vpif_obj.dev[i]); +} + +/* Function for module initialization and cleanup */ +module_init(vpif_init); +module_exit(vpif_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_capture.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_capture.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_capture.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_capture.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +#ifndef VPIF_CAPTURE_H +#define VPIF_CAPTURE_H + +#ifdef __KERNEL__ + +/* Header files */ +#include +#include +#include +#include +#include +#include +#include + +#include "vpif.h" + +/* Macros */ +#define VPIF_MAJOR_RELEASE 0 +#define VPIF_MINOR_RELEASE 0 +#define VPIF_BUILD 1 +#define VPIF_CAPTURE_VERSION_CODE ((VPIF_MAJOR_RELEASE << 16) | \ + (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) + +#define VPIF_VALID_FIELD(field) (((V4L2_FIELD_ANY == field) || \ + (V4L2_FIELD_NONE == field)) || \ + (((V4L2_FIELD_INTERLACED == field) || \ + (V4L2_FIELD_SEQ_TB == field)) || \ + (V4L2_FIELD_SEQ_BT == field))) + +#define VPIF_CAPTURE_MAX_DEVICES 2 +#define VPIF_VIDEO_INDEX 0 +#define VPIF_NUMBER_OF_OBJECTS 1 + +/* Enumerated data type to give id to each device per channel */ +enum vpif_channel_id { + VPIF_CHANNEL0_VIDEO = 0, + VPIF_CHANNEL1_VIDEO, +}; + +struct video_obj { + enum v4l2_field buf_field; + /* Currently selected or default standard */ + v4l2_std_id stdid; + u32 dv_preset; + struct v4l2_bt_timings bt_timings; + /* This is to track the last input that is passed to application */ + u32 input_idx; +}; + +struct common_obj { + /* Pointer pointing to current v4l2_buffer */ + struct videobuf_buffer *cur_frm; + /* Pointer pointing to current v4l2_buffer */ + struct videobuf_buffer *next_frm; + /* + * This field keeps track of type of buffer exchange mechanism + * user has selected + */ + enum v4l2_memory memory; + /* Used to store pixel format */ + struct v4l2_format fmt; + /* Buffer queue used in video-buf */ + struct videobuf_queue buffer_queue; + /* Queue of filled frames */ + struct list_head dma_queue; + /* Used in video-buf */ + spinlock_t irqlock; + /* lock used to access this structure */ + struct mutex lock; + /* number of users performing IO */ + u32 io_usrs; + /* Indicates whether streaming started */ + u8 started; + /* Function pointer to set the addresses */ + void (*set_addr) (unsigned long, unsigned long, unsigned long, + unsigned long); + /* offset where Y top starts from the starting of the buffer */ + u32 ytop_off; + /* offset where Y bottom starts from the starting of the buffer */ + u32 ybtm_off; + /* offset where C top starts from the starting of the buffer */ + u32 ctop_off; + /* offset where C bottom starts from the starting of the buffer */ + u32 cbtm_off; + /* Indicates width of the image data */ + u32 width; + /* Indicates height of the image data */ + u32 height; +}; + +struct channel_obj { + /* Identifies video device for this channel */ + struct video_device *video_dev; + /* Used to keep track of state of the priority */ + struct v4l2_prio_state prio; + /* number of open instances of the channel */ + int usrs; + /* Indicates id of the field which is being displayed */ + u32 field_id; + /* flag to indicate whether decoder is initialized */ + u8 initialized; + /* Identifies channel */ + enum vpif_channel_id channel_id; + /* index into sd table */ + int curr_sd_index; + /* ptr to current sub device information */ + struct vpif_subdev_info *curr_subdev_info; + /* vpif configuration params */ + struct vpif_params vpifparams; + /* common object array */ + struct common_obj common[VPIF_NUMBER_OF_OBJECTS]; + /* video object */ + struct video_obj video; +}; + +/* File handle structure */ +struct vpif_fh { + /* pointer to channel object for opened device */ + struct channel_obj *channel; + /* Indicates whether this file handle is doing IO */ + u8 io_allowed[VPIF_NUMBER_OF_OBJECTS]; + /* Used to keep track priority of this instance */ + enum v4l2_priority prio; + /* Used to indicate channel is initialize or not */ + u8 initialized; +}; + +struct vpif_device { + struct v4l2_device v4l2_dev; + struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS]; + struct v4l2_subdev **sd; +}; + +struct vpif_config_params { + u8 min_numbuffers; + u8 numbuffers[VPIF_CAPTURE_NUM_CHANNELS]; + s8 device_type; + u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; + u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; + u8 default_device[VPIF_CAPTURE_NUM_CHANNELS]; + u8 max_device_type; +}; +/* Struct which keeps track of the line numbers for the sliced vbi service */ +struct vpif_service_line { + u16 service_id; + u16 service_line[2]; +}; +#endif /* End of __KERNEL__ */ +#endif /* VPIF_CAPTURE_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_display.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_display.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_display.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_display.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1917 @@ +/* + * vpif-display - VPIF display driver + * Display driver for TI DaVinci VPIF + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "vpif_display.h" +#include "vpif.h" + +MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); +MODULE_LICENSE("GPL"); + +#define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) + +#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) +#define vpif_dbg(level, debug, fmt, arg...) \ + v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) + +static int debug = 1; +static u32 ch2_numbuffers = 3; +static u32 ch3_numbuffers = 3; +static u32 ch2_bufsize = 1920 * 1080 * 2; +static u32 ch3_bufsize = 720 * 576 * 2; + +module_param(debug, int, 0644); +module_param(ch2_numbuffers, uint, S_IRUGO); +module_param(ch3_numbuffers, uint, S_IRUGO); +module_param(ch2_bufsize, uint, S_IRUGO); +module_param(ch3_bufsize, uint, S_IRUGO); + +MODULE_PARM_DESC(debug, "Debug level 0-1"); +MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)"); +MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)"); +MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)"); +MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)"); + +static struct vpif_config_params config_params = { + .min_numbuffers = 3, + .numbuffers[0] = 3, + .numbuffers[1] = 3, + .min_bufsize[0] = 720 * 480 * 2, + .min_bufsize[1] = 720 * 480 * 2, + .channel_bufsize[0] = 1920 * 1080 * 2, + .channel_bufsize[1] = 720 * 576 * 2, +}; + +static struct vpif_device vpif_obj = { {NULL} }; +static struct device *vpif_dev; + +/* + * vpif_uservirt_to_phys: This function is used to convert user + * space virtual address to physical address. + */ +static u32 vpif_uservirt_to_phys(u32 virtp) +{ + struct mm_struct *mm = current->mm; + unsigned long physp = 0; + struct vm_area_struct *vma; + + vma = find_vma(mm, virtp); + + /* For kernel direct-mapped memory, take the easy way */ + if (virtp >= PAGE_OFFSET) { + physp = virt_to_phys((void *)virtp); + } else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) { + /* this will catch, kernel-allocated, mmaped-to-usermode addr */ + physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); + } else { + /* otherwise, use get_user_pages() for general userland pages */ + int res, nr_pages = 1; + struct page *pages; + down_read(¤t->mm->mmap_sem); + + res = get_user_pages(current, current->mm, + virtp, nr_pages, 1, 0, &pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (res == nr_pages) { + physp = __pa(page_address(&pages[0]) + + (virtp & ~PAGE_MASK)); + } else { + vpif_err("get_user_pages failed\n"); + return 0; + } + } + + return physp; +} + +/* + * buffer_prepare: This is the callback function called from videobuf_qbuf() + * function the buffer is prepared and user space virtual address is converted + * into physical address + */ +static int vpif_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct vpif_fh *fh = q->priv_data; + struct common_obj *common; + unsigned long addr; + + common = &fh->channel->common[VPIF_VIDEO_INDEX]; + if (VIDEOBUF_NEEDS_INIT == vb->state) { + vb->width = common->width; + vb->height = common->height; + vb->size = vb->width * vb->height; + vb->field = field; + } + vb->state = VIDEOBUF_PREPARED; + + /* if user pointer memory mechanism is used, get the physical + * address of the buffer */ + if (V4L2_MEMORY_USERPTR == common->memory) { + if (!vb->baddr) { + vpif_err("buffer_address is 0\n"); + return -EINVAL; + } + + vb->boff = vpif_uservirt_to_phys(vb->baddr); + if (!ISALIGNED(vb->boff)) + goto buf_align_exit; + } + + addr = vb->boff; + if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) { + if (!ISALIGNED(addr + common->ytop_off) || + !ISALIGNED(addr + common->ybtm_off) || + !ISALIGNED(addr + common->ctop_off) || + !ISALIGNED(addr + common->cbtm_off)) + goto buf_align_exit; + } + return 0; + +buf_align_exit: + vpif_err("buffer offset not aligned to 8 bytes\n"); + return -EINVAL; +} + +/* + * vpif_buffer_setup: This function allocates memory for the buffers + */ +static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (V4L2_MEMORY_MMAP != common->memory) + return 0; + + *size = config_params.channel_bufsize[ch->channel_id]; + if (*count < config_params.min_numbuffers) + *count = config_params.min_numbuffers; + + return 0; +} + +/* + * vpif_buffer_queue: This function adds the buffer to DMA queue + */ +static void vpif_buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct vpif_fh *fh = q->priv_data; + struct common_obj *common; + + common = &fh->channel->common[VPIF_VIDEO_INDEX]; + + /* add the buffer to the DMA queue */ + list_add_tail(&vb->queue, &common->dma_queue); + vb->state = VIDEOBUF_QUEUED; +} + +/* + * vpif_buffer_release: This function is called from the videobuf layer to + * free memory allocated to the buffers + */ +static void vpif_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + unsigned int buf_size = 0; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + videobuf_dma_contig_free(q, vb); + vb->state = VIDEOBUF_NEEDS_INIT; + + if (V4L2_MEMORY_MMAP != common->memory) + return; + + buf_size = config_params.channel_bufsize[ch->channel_id]; +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = vpif_buffer_setup, + .buf_prepare = vpif_buffer_prepare, + .buf_queue = vpif_buffer_queue, + .buf_release = vpif_buffer_release, +}; +static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} }; + +static void process_progressive_mode(struct common_obj *common) +{ + unsigned long addr = 0; + + /* Get the next buffer from buffer queue */ + common->next_frm = list_entry(common->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove that buffer from the buffer queue */ + list_del(&common->next_frm->queue); + /* Mark status of the buffer as active */ + common->next_frm->state = VIDEOBUF_ACTIVE; + + /* Set top and bottom field addrs in VPIF registers */ + addr = videobuf_to_dma_contig(common->next_frm); + common->set_addr(addr + common->ytop_off, + addr + common->ybtm_off, + addr + common->ctop_off, + addr + common->cbtm_off); +} + +static void process_interlaced_mode(int fid, struct common_obj *common) +{ + /* device field id and local field id are in sync */ + /* If this is even field */ + if (0 == fid) { + if (common->cur_frm == common->next_frm) + return; + + /* one frame is displayed If next frame is + * available, release cur_frm and move on */ + /* Copy frame display time */ + do_gettimeofday(&common->cur_frm->ts); + /* Change status of the cur_frm */ + common->cur_frm->state = VIDEOBUF_DONE; + /* unlock semaphore on cur_frm */ + wake_up_interruptible(&common->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + common->cur_frm = common->next_frm; + + } else if (1 == fid) { /* odd field */ + if (list_empty(&common->dma_queue) + || (common->cur_frm != common->next_frm)) { + return; + } + /* one field is displayed configure the next + * frame if it is available else hold on current + * frame */ + /* Get next from the buffer queue */ + process_progressive_mode(common); + + } +} + +/* + * vpif_channel_isr: It changes status of the displayed buffer, takes next + * buffer from the queue and sets its address in VPIF registers + */ +static irqreturn_t vpif_channel_isr(int irq, void *dev_id) +{ + struct vpif_device *dev = &vpif_obj; + struct channel_obj *ch; + struct common_obj *common; + enum v4l2_field field; + int fid = -1, i; + int channel_id = 0; + + channel_id = *(int *)(dev_id); + ch = dev->dev[channel_id]; + field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; + for (i = 0; i < VPIF_NUMOBJECTS; i++) { + common = &ch->common[i]; + /* If streaming is started in this channel */ + if (0 == common->started) + continue; + + if (1 == ch->vpifparams.std_info.frm_fmt) { + if (list_empty(&common->dma_queue)) + continue; + + /* Progressive mode */ + if (!channel_first_int[i][channel_id]) { + /* Mark status of the cur_frm to + * done and unlock semaphore on it */ + do_gettimeofday(&common->cur_frm->ts); + common->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible(&common->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + common->cur_frm = common->next_frm; + } + + channel_first_int[i][channel_id] = 0; + process_progressive_mode(common); + } else { + /* Interlaced mode */ + /* If it is first interrupt, ignore it */ + + if (channel_first_int[i][channel_id]) { + channel_first_int[i][channel_id] = 0; + continue; + } + + if (0 == i) { + ch->field_id ^= 1; + /* Get field id from VPIF registers */ + fid = vpif_channel_getfid(ch->channel_id + 2); + /* If fid does not match with stored field id */ + if (fid != ch->field_id) { + /* Make them in sync */ + if (0 == fid) + ch->field_id = fid; + + return IRQ_HANDLED; + } + } + process_interlaced_mode(fid, common); + } + } + + return IRQ_HANDLED; +} + +static int vpif_update_std_info(struct channel_obj *ch) +{ + struct video_obj *vid_ch = &ch->video; + struct vpif_params *vpifparams = &ch->vpifparams; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; + const struct vpif_channel_config_params *config; + + int i; + + for (i = 0; i < vpif_ch_params_count; i++) { + config = &ch_params[i]; + if (config->hd_sd == 0) { + vpif_dbg(2, debug, "SD format\n"); + if (config->stdid & vid_ch->stdid) { + memcpy(std_info, config, sizeof(*config)); + break; + } + } else { + vpif_dbg(2, debug, "HD format\n"); + if (config->dv_preset == vid_ch->dv_preset) { + memcpy(std_info, config, sizeof(*config)); + break; + } + } + } + + if (i == vpif_ch_params_count) { + vpif_dbg(1, debug, "Format not found\n"); + return -EINVAL; + } + + return 0; +} + +static int vpif_update_resolution(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct video_obj *vid_ch = &ch->video; + struct vpif_params *vpifparams = &ch->vpifparams; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; + + if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height) + return -EINVAL; + + if (vid_ch->stdid || vid_ch->dv_preset) { + if (vpif_update_std_info(ch)) + return -EINVAL; + } + + common->fmt.fmt.pix.width = std_info->width; + common->fmt.fmt.pix.height = std_info->height; + vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n", + common->fmt.fmt.pix.width, common->fmt.fmt.pix.height); + + /* Set height and width paramateres */ + common->height = std_info->height; + common->width = std_info->width; + + return 0; +} + +/* + * vpif_calculate_offsets: This function calculates buffers offset for Y and C + * in the top and bottom field + */ +static void vpif_calculate_offsets(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct vpif_params *vpifparams = &ch->vpifparams; + enum v4l2_field field = common->fmt.fmt.pix.field; + struct video_obj *vid_ch = &ch->video; + unsigned int hpitch, vpitch, sizeimage; + + if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) { + if (ch->vpifparams.std_info.frm_fmt) + vid_ch->buf_field = V4L2_FIELD_NONE; + else + vid_ch->buf_field = V4L2_FIELD_INTERLACED; + } else { + vid_ch->buf_field = common->fmt.fmt.pix.field; + } + + if (V4L2_MEMORY_USERPTR == common->memory) + sizeimage = common->fmt.fmt.pix.sizeimage; + else + sizeimage = config_params.channel_bufsize[ch->channel_id]; + + hpitch = common->fmt.fmt.pix.bytesperline; + vpitch = sizeimage / (hpitch * 2); + if ((V4L2_FIELD_NONE == vid_ch->buf_field) || + (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { + common->ytop_off = 0; + common->ybtm_off = hpitch; + common->ctop_off = sizeimage / 2; + common->cbtm_off = sizeimage / 2 + hpitch; + } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { + common->ytop_off = 0; + common->ybtm_off = sizeimage / 4; + common->ctop_off = sizeimage / 2; + common->cbtm_off = common->ctop_off + sizeimage / 4; + } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { + common->ybtm_off = 0; + common->ytop_off = sizeimage / 4; + common->cbtm_off = sizeimage / 2; + common->ctop_off = common->cbtm_off + sizeimage / 4; + } + + if ((V4L2_FIELD_NONE == vid_ch->buf_field) || + (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { + vpifparams->video_params.storage_mode = 1; + } else { + vpifparams->video_params.storage_mode = 0; + } + + if (ch->vpifparams.std_info.frm_fmt == 1) { + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline; + } else { + if ((field == V4L2_FIELD_ANY) || + (field == V4L2_FIELD_INTERLACED)) + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline * 2; + else + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline; + } + + ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid; +} + +static void vpif_config_format(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + common->fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (config_params.numbuffers[ch->channel_id] == 0) + common->memory = V4L2_MEMORY_USERPTR; + else + common->memory = V4L2_MEMORY_MMAP; + + common->fmt.fmt.pix.sizeimage = + config_params.channel_bufsize[ch->channel_id]; + common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; + common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +} + +static int vpif_check_format(struct channel_obj *ch, + struct v4l2_pix_format *pixfmt) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + enum v4l2_field field = pixfmt->field; + u32 sizeimage, hpitch, vpitch; + + if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) + goto invalid_fmt_exit; + + if (!(VPIF_VALID_FIELD(field))) + goto invalid_fmt_exit; + + if (pixfmt->bytesperline <= 0) + goto invalid_pitch_exit; + + if (V4L2_MEMORY_USERPTR == common->memory) + sizeimage = pixfmt->sizeimage; + else + sizeimage = config_params.channel_bufsize[ch->channel_id]; + + if (vpif_update_resolution(ch)) + return -EINVAL; + + hpitch = pixfmt->bytesperline; + vpitch = sizeimage / (hpitch * 2); + + /* Check for valid value of pitch */ + if ((hpitch < ch->vpifparams.std_info.width) || + (vpitch < ch->vpifparams.std_info.height)) + goto invalid_pitch_exit; + + /* Check for 8 byte alignment */ + if (!ISALIGNED(hpitch)) { + vpif_err("invalid pitch alignment\n"); + return -EINVAL; + } + pixfmt->width = common->fmt.fmt.pix.width; + pixfmt->height = common->fmt.fmt.pix.height; + + return 0; + +invalid_fmt_exit: + vpif_err("invalid field format\n"); + return -EINVAL; + +invalid_pitch_exit: + vpif_err("invalid pitch\n"); + return -EINVAL; +} + +static void vpif_config_addr(struct channel_obj *ch, int muxmode) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (VPIF_CHANNEL3_VIDEO == ch->channel_id) { + common->set_addr = ch3_set_videobuf_addr; + } else { + if (2 == muxmode) + common->set_addr = ch2_set_videobuf_addr_yc_nmux; + else + common->set_addr = ch2_set_videobuf_addr; + } +} + +/* + * vpif_mmap: It is used to map kernel space buffers into user spaces + */ +static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) +{ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); + + vpif_dbg(2, debug, "vpif_mmap\n"); + + return videobuf_mmap_mapper(&common->buffer_queue, vma); +} + +/* + * vpif_poll: It is used for select/poll system call + */ +static unsigned int vpif_poll(struct file *filep, poll_table *wait) +{ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (common->started) + return videobuf_poll_stream(filep, &common->buffer_queue, wait); + + return 0; +} + +/* + * vpif_open: It creates object of file handle structure and stores it in + * private_data member of filepointer + */ +static int vpif_open(struct file *filep) +{ + struct video_device *vdev = video_devdata(filep); + struct channel_obj *ch = NULL; + struct vpif_fh *fh = NULL; + + ch = video_get_drvdata(vdev); + /* Allocate memory for the file handle object */ + fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); + if (fh == NULL) { + vpif_err("unable to allocate memory for file handle object\n"); + return -ENOMEM; + } + + /* store pointer to fh in private_data member of filep */ + filep->private_data = fh; + fh->channel = ch; + fh->initialized = 0; + if (!ch->initialized) { + fh->initialized = 1; + ch->initialized = 1; + memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); + } + + /* Increment channel usrs counter */ + atomic_inc(&ch->usrs); + /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */ + fh->io_allowed[VPIF_VIDEO_INDEX] = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&ch->prio, &fh->prio); + + return 0; +} + +/* + * vpif_release: This function deletes buffer queue, frees the buffers and + * the vpif file handle + */ +static int vpif_release(struct file *filep) +{ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + /* if this instance is doing IO */ + if (fh->io_allowed[VPIF_VIDEO_INDEX]) { + /* Reset io_usrs member of channel object */ + common->io_usrs = 0; + /* Disable channel */ + if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + enable_channel2(0); + channel2_intr_enable(0); + } + if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || + (2 == common->started)) { + enable_channel3(0); + channel3_intr_enable(0); + } + common->started = 0; + /* Free buffers allocated */ + videobuf_queue_cancel(&common->buffer_queue); + videobuf_mmap_free(&common->buffer_queue); + common->numbuffers = + config_params.numbuffers[ch->channel_id]; + } + + /* Decrement channel usrs counter */ + atomic_dec(&ch->usrs); + /* If this file handle has initialize encoder device, reset it */ + if (fh->initialized) + ch->initialized = 0; + + /* Close the priority */ + v4l2_prio_close(&ch->prio, fh->prio); + filep->private_data = NULL; + fh->initialized = 0; + kfree(fh); + + return 0; +} + +/* functions implementing ioctls */ +/** + * vpif_querycap() - QUERYCAP handler + * @file: file ptr + * @priv: file handle + * @cap: ptr to v4l2_capability structure + */ +static int vpif_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpif_display_config *config = vpif_dev->platform_data; + + cap->version = VPIF_DISPLAY_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); + strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); + strlcpy(cap->card, config->card_name, sizeof(cap->card)); + + return 0; +} + +static int vpif_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + if (fmt->index != 0) { + vpif_err("Invalid format index\n"); + return -EINVAL; + } + + /* Fill in the information about format */ + fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); + fmt->pixelformat = V4L2_PIX_FMT_YUV422P; + + return 0; +} + +static int vpif_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + /* Check the validity of the buffer type */ + if (common->fmt.type != fmt->type) + return -EINVAL; + + if (vpif_update_resolution(ch)) + return -EINVAL; + *fmt = common->fmt; + return 0; +} + +static int vpif_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct v4l2_pix_format *pixfmt; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) + || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + + /* Check for the priority */ + ret = v4l2_prio_check(&ch->prio, fh->prio); + if (0 != ret) + return ret; + fh->initialized = 1; + } + + if (common->started) { + vpif_dbg(1, debug, "Streaming in progress\n"); + return -EBUSY; + } + + pixfmt = &fmt->fmt.pix; + /* Check for valid field format */ + ret = vpif_check_format(ch, pixfmt); + if (ret) + return ret; + + /* store the pix format in the channel object */ + common->fmt.fmt.pix = *pixfmt; + /* store the format in the channel object */ + common->fmt = *fmt; + return 0; +} + +static int vpif_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + int ret = 0; + + ret = vpif_check_format(ch, pixfmt); + if (ret) { + *pixfmt = common->fmt.fmt.pix; + pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2; + } + + return ret; +} + +static int vpif_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbuf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + enum v4l2_field field; + u8 index = 0; + + /* This file handle has not initialized the channel, + It is not allowed to do settings */ + if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) + || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_err("Channel Busy\n"); + return -EBUSY; + } + } + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type) + return -EINVAL; + + index = VPIF_VIDEO_INDEX; + + common = &ch->common[index]; + + if (common->fmt.type != reqbuf->type) + return -EINVAL; + + if (0 != common->io_usrs) + return -EBUSY; + + if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY) + field = V4L2_FIELD_INTERLACED; + else + field = common->fmt.fmt.pix.field; + } else { + field = V4L2_VBI_INTERLACED; + } + + /* Initialize videobuf queue as per the buffer type */ + videobuf_queue_dma_contig_init(&common->buffer_queue, + &video_qops, NULL, + &common->irqlock, + reqbuf->type, field, + sizeof(struct videobuf_buffer), fh, + &common->lock); + + /* Set io allowed member of file handle to TRUE */ + fh->io_allowed[index] = 1; + /* Increment io usrs member of channel object to 1 */ + common->io_usrs = 1; + /* Store type of memory requested in channel object */ + common->memory = reqbuf->memory; + INIT_LIST_HEAD(&common->dma_queue); + + /* Allocate buffers */ + return videobuf_reqbufs(&common->buffer_queue, reqbuf); +} + +static int vpif_querybuf(struct file *file, void *priv, + struct v4l2_buffer *tbuf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (common->fmt.type != tbuf->type) + return -EINVAL; + + return videobuf_querybuf(&common->buffer_queue, tbuf); +} + +static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct v4l2_buffer tbuf = *buf; + struct videobuf_buffer *buf1; + unsigned long addr = 0; + unsigned long flags; + int ret = 0; + + if (common->fmt.type != tbuf.type) + return -EINVAL; + + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_err("fh->io_allowed\n"); + return -EACCES; + } + + if (!(list_empty(&common->dma_queue)) || + (common->cur_frm != common->next_frm) || + !(common->started) || + (common->started && (0 == ch->field_id))) + return videobuf_qbuf(&common->buffer_queue, buf); + + /* bufferqueue is empty store buffer address in VPIF registers */ + mutex_lock(&common->buffer_queue.vb_lock); + buf1 = common->buffer_queue.bufs[tbuf.index]; + if (buf1->memory != tbuf.memory) { + vpif_err("invalid buffer type\n"); + goto qbuf_exit; + } + + if ((buf1->state == VIDEOBUF_QUEUED) || + (buf1->state == VIDEOBUF_ACTIVE)) { + vpif_err("invalid state\n"); + goto qbuf_exit; + } + + switch (buf1->memory) { + case V4L2_MEMORY_MMAP: + if (buf1->baddr == 0) + goto qbuf_exit; + break; + + case V4L2_MEMORY_USERPTR: + if (tbuf.length < buf1->bsize) + goto qbuf_exit; + + if ((VIDEOBUF_NEEDS_INIT != buf1->state) + && (buf1->baddr != tbuf.m.userptr)) { + vpif_buffer_release(&common->buffer_queue, buf1); + buf1->baddr = tbuf.m.userptr; + } + break; + + default: + goto qbuf_exit; + } + + local_irq_save(flags); + ret = vpif_buffer_prepare(&common->buffer_queue, buf1, + common->buffer_queue.field); + if (ret < 0) { + local_irq_restore(flags); + goto qbuf_exit; + } + + buf1->state = VIDEOBUF_ACTIVE; + addr = buf1->boff; + common->next_frm = buf1; + if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { + common->set_addr((addr + common->ytop_off), + (addr + common->ybtm_off), + (addr + common->ctop_off), + (addr + common->cbtm_off)); + } + + local_irq_restore(flags); + list_add_tail(&buf1->stream, &common->buffer_queue.stream); + mutex_unlock(&common->buffer_queue.vb_lock); + return 0; + +qbuf_exit: + mutex_unlock(&common->buffer_queue.vb_lock); + return -EINVAL; +} + +static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + if (!(*std_id & DM646X_V4L2_STD)) + return -EINVAL; + + if (common->started) { + vpif_err("streaming in progress\n"); + return -EBUSY; + } + + /* Call encoder subdevice function to set the standard */ + ch->video.stdid = *std_id; + ch->video.dv_preset = V4L2_DV_INVALID; + memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); + + /* Get the information about the standard */ + if (vpif_update_resolution(ch)) + return -EINVAL; + + if ((ch->vpifparams.std_info.width * + ch->vpifparams.std_info.height * 2) > + config_params.channel_bufsize[ch->channel_id]) { + vpif_err("invalid std for this size\n"); + return -EINVAL; + } + + common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width; + /* Configure the default format information */ + vpif_config_format(ch); + + ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, + s_std_output, *std_id); + if (ret < 0) { + vpif_err("Failed to set output standard\n"); + return ret; + } + + ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core, + s_std, *std_id); + if (ret < 0) + vpif_err("Failed to set standard for sub devices\n"); + return ret; +} + +static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + *std = ch->video.stdid; + return 0; +} + +static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + return videobuf_dqbuf(&common->buffer_queue, p, + (file->f_flags & O_NONBLOCK)); +} + +static int vpif_streamon(struct file *file, void *priv, + enum v4l2_buf_type buftype) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; + struct vpif_params *vpif = &ch->vpifparams; + struct vpif_display_config *vpif_config_data = + vpif_dev->platform_data; + unsigned long addr = 0; + int ret = 0; + + if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + vpif_err("buffer type not supported\n"); + return -EINVAL; + } + + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_err("fh->io_allowed\n"); + return -EACCES; + } + + /* If Streaming is already started, return error */ + if (common->started) { + vpif_err("channel->started\n"); + return -EBUSY; + } + + if ((ch->channel_id == VPIF_CHANNEL2_VIDEO + && oth_ch->common[VPIF_VIDEO_INDEX].started && + ch->vpifparams.std_info.ycmux_mode == 0) + || ((ch->channel_id == VPIF_CHANNEL3_VIDEO) + && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { + vpif_err("other channel is using\n"); + return -EBUSY; + } + + ret = vpif_check_format(ch, &common->fmt.fmt.pix); + if (ret < 0) + return ret; + + /* Call videobuf_streamon to start streaming in videobuf */ + ret = videobuf_streamon(&common->buffer_queue); + if (ret < 0) { + vpif_err("videobuf_streamon\n"); + return ret; + } + + /* If buffer queue is empty, return error */ + if (list_empty(&common->dma_queue)) { + vpif_err("buffer queue is empty\n"); + return -EIO; + } + + /* Get the next frame from the buffer queue */ + common->next_frm = common->cur_frm = + list_entry(common->dma_queue.next, + struct videobuf_buffer, queue); + + list_del(&common->cur_frm->queue); + /* Mark state of the current frame to active */ + common->cur_frm->state = VIDEOBUF_ACTIVE; + + /* Initialize field_id and started member */ + ch->field_id = 0; + common->started = 1; + if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + addr = common->cur_frm->boff; + /* Calculate the offset for Y and C data in the buffer */ + vpif_calculate_offsets(ch); + + if ((ch->vpifparams.std_info.frm_fmt && + ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) + && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) + || (!ch->vpifparams.std_info.frm_fmt + && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { + vpif_err("conflict in field format and std format\n"); + return -EINVAL; + } + + /* clock settings */ + ret = + vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, + ch->vpifparams.std_info.hd_sd); + if (ret < 0) { + vpif_err("can't set clock\n"); + return ret; + } + + /* set the parameters and addresses */ + ret = vpif_set_video_params(vpif, ch->channel_id + 2); + if (ret < 0) + return ret; + + common->started = ret; + vpif_config_addr(ch, ret); + common->set_addr((addr + common->ytop_off), + (addr + common->ybtm_off), + (addr + common->ctop_off), + (addr + common->cbtm_off)); + + /* Set interrupt for both the fields in VPIF + Register enable channel in VPIF register */ + if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + channel2_intr_assert(); + channel2_intr_enable(1); + enable_channel2(1); + } + + if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) + || (common->started == 2)) { + channel3_intr_assert(); + channel3_intr_enable(1); + enable_channel3(1); + } + channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; + } + return ret; +} + +static int vpif_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buftype) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + vpif_err("buffer type not supported\n"); + return -EINVAL; + } + + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_err("fh->io_allowed\n"); + return -EACCES; + } + + if (!common->started) { + vpif_err("channel->started\n"); + return -EINVAL; + } + + if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + /* disable channel */ + if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + enable_channel2(0); + channel2_intr_enable(0); + } + if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || + (2 == common->started)) { + enable_channel3(0); + channel3_intr_enable(0); + } + } + + common->started = 0; + return videobuf_streamoff(&common->buffer_queue); +} + +static int vpif_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *crop) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type) + return -EINVAL; + + crop->bounds.left = crop->bounds.top = 0; + crop->defrect.left = crop->defrect.top = 0; + crop->defrect.height = crop->bounds.height = common->height; + crop->defrect.width = crop->bounds.width = common->width; + + return 0; +} + +static int vpif_enum_output(struct file *file, void *fh, + struct v4l2_output *output) +{ + + struct vpif_display_config *config = vpif_dev->platform_data; + + if (output->index >= config->output_count) { + vpif_dbg(1, debug, "Invalid output index\n"); + return -EINVAL; + } + + strcpy(output->name, config->output[output->index]); + output->type = V4L2_OUTPUT_TYPE_ANALOG; + output->std = DM646X_V4L2_STD; + + return 0; +} + +static int vpif_s_output(struct file *file, void *priv, unsigned int i) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + if (common->started) { + vpif_err("Streaming in progress\n"); + return -EBUSY; + } + + ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, + s_routing, 0, i, 0); + + if (ret < 0) + vpif_err("Failed to set output standard\n"); + + vid_ch->output_id = i; + return ret; +} + +static int vpif_g_output(struct file *file, void *priv, unsigned int *i) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + *i = vid_ch->output_id; + + return 0; +} + +static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + *p = v4l2_prio_max(&ch->prio); + + return 0; +} + +static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_prio_change(&ch->prio, &fh->prio, p); +} + +/** + * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_enum_dv_presets(struct file *file, void *priv, + struct v4l2_dv_enum_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], + video, enum_dv_presets, preset); +} + +/** + * vpif_s_dv_presets() - S_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_s_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct video_obj *vid_ch = &ch->video; + int ret = 0; + + if (common->started) { + vpif_dbg(1, debug, "streaming in progress\n"); + return -EBUSY; + } + + ret = v4l2_prio_check(&ch->prio, fh->prio); + if (ret != 0) + return ret; + + fh->initialized = 1; + + /* Call encoder subdevice function to set the standard */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + ch->video.dv_preset = preset->preset; + ch->video.stdid = V4L2_STD_UNKNOWN; + memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); + + /* Get the information about the standard */ + if (vpif_update_resolution(ch)) { + ret = -EINVAL; + } else { + /* Configure the default format information */ + vpif_config_format(ch); + + ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], + video, s_dv_preset, preset); + } + + mutex_unlock(&common->lock); + + return ret; +} +/** + * vpif_g_dv_presets() - G_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_g_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + preset->preset = ch->video.dv_preset; + + return 0; +} +/** + * vpif_s_dv_timings() - S_DV_TIMINGS handler + * @file: file ptr + * @priv: file handle + * @timings: digital video timings + */ +static int vpif_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct vpif_params *vpifparams = &ch->vpifparams; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; + struct video_obj *vid_ch = &ch->video; + struct v4l2_bt_timings *bt = &vid_ch->bt_timings; + int ret; + + if (timings->type != V4L2_DV_BT_656_1120) { + vpif_dbg(2, debug, "Timing type not defined\n"); + return -EINVAL; + } + + /* Configure subdevice timings, if any */ + ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], + video, s_dv_timings, timings); + if (ret == -ENOIOCTLCMD) { + vpif_dbg(2, debug, "Custom DV timings not supported by " + "subdevice\n"); + return -EINVAL; + } + if (ret < 0) { + vpif_dbg(2, debug, "Error setting custom DV timings\n"); + return ret; + } + + if (!(timings->bt.width && timings->bt.height && + (timings->bt.hbackporch || + timings->bt.hfrontporch || + timings->bt.hsync) && + timings->bt.vfrontporch && + (timings->bt.vbackporch || + timings->bt.vsync))) { + vpif_dbg(2, debug, "Timings for width, height, " + "horizontal back porch, horizontal sync, " + "horizontal front porch, vertical back porch, " + "vertical sync and vertical back porch " + "must be defined\n"); + return -EINVAL; + } + + *bt = timings->bt; + + /* Configure video port timings */ + + std_info->eav2sav = bt->hbackporch + bt->hfrontporch + + bt->hsync - 8; + std_info->sav2eav = bt->width; + + std_info->l1 = 1; + std_info->l3 = bt->vsync + bt->vbackporch + 1; + + if (bt->interlaced) { + if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) { + std_info->vsize = bt->height * 2 + + bt->vfrontporch + bt->vsync + bt->vbackporch + + bt->il_vfrontporch + bt->il_vsync + + bt->il_vbackporch; + std_info->l5 = std_info->vsize/2 - + (bt->vfrontporch - 1); + std_info->l7 = std_info->vsize/2 + 1; + std_info->l9 = std_info->l7 + bt->il_vsync + + bt->il_vbackporch + 1; + std_info->l11 = std_info->vsize - + (bt->il_vfrontporch - 1); + } else { + vpif_dbg(2, debug, "Required timing values for " + "interlaced BT format missing\n"); + return -EINVAL; + } + } else { + std_info->vsize = bt->height + bt->vfrontporch + + bt->vsync + bt->vbackporch; + std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); + } + strncpy(std_info->name, "Custom timings BT656/1120", + VPIF_MAX_NAME); + std_info->width = bt->width; + std_info->height = bt->height; + std_info->frm_fmt = bt->interlaced ? 0 : 1; + std_info->ycmux_mode = 0; + std_info->capture_format = 0; + std_info->vbi_supported = 0; + std_info->hd_sd = 1; + std_info->stdid = 0; + std_info->dv_preset = V4L2_DV_INVALID; + + vid_ch->stdid = 0; + vid_ch->dv_preset = V4L2_DV_INVALID; + + return 0; +} + +/** + * vpif_g_dv_timings() - G_DV_TIMINGS handler + * @file: file ptr + * @priv: file handle + * @timings: digital video timings + */ +static int vpif_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + struct v4l2_bt_timings *bt = &vid_ch->bt_timings; + + timings->bt = *bt; + + return 0; +} + +/* + * vpif_g_chip_ident() - Identify the chip + * @file: file ptr + * @priv: file handle + * @chip: chip identity + * + * Returns zero or -EINVAL if read operations fails. + */ +static int vpif_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && + chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) { + vpif_dbg(2, debug, "match_type is invalid.\n"); + return -EINVAL; + } + + return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core, + g_chip_ident, chip); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* + * vpif_dbg_g_register() - Read register + * @file: file ptr + * @priv: file handle + * @reg: register to be read + * + * Debugging only + * Returns zero or -EINVAL if read operations fails. + */ +static int vpif_dbg_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg){ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, + g_register, reg); +} + +/* + * vpif_dbg_s_register() - Write to register + * @file: file ptr + * @priv: file handle + * @reg: register to be modified + * + * Debugging only + * Returns zero or -EINVAL if write operations fails. + */ +static int vpif_dbg_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg){ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, + s_register, reg); +} +#endif + +/* + * vpif_log_status() - Status information + * @file: file ptr + * @priv: file handle + * + * Returns zero. + */ +static int vpif_log_status(struct file *filep, void *priv) +{ + /* status for sub devices */ + v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status); + + return 0; +} + +/* vpif display ioctl operations */ +static const struct v4l2_ioctl_ops vpif_ioctl_ops = { + .vidioc_querycap = vpif_querycap, + .vidioc_g_priority = vpif_g_priority, + .vidioc_s_priority = vpif_s_priority, + .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out, + .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out, + .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out, + .vidioc_reqbufs = vpif_reqbufs, + .vidioc_querybuf = vpif_querybuf, + .vidioc_qbuf = vpif_qbuf, + .vidioc_dqbuf = vpif_dqbuf, + .vidioc_streamon = vpif_streamon, + .vidioc_streamoff = vpif_streamoff, + .vidioc_s_std = vpif_s_std, + .vidioc_g_std = vpif_g_std, + .vidioc_enum_output = vpif_enum_output, + .vidioc_s_output = vpif_s_output, + .vidioc_g_output = vpif_g_output, + .vidioc_cropcap = vpif_cropcap, + .vidioc_enum_dv_presets = vpif_enum_dv_presets, + .vidioc_s_dv_preset = vpif_s_dv_preset, + .vidioc_g_dv_preset = vpif_g_dv_preset, + .vidioc_s_dv_timings = vpif_s_dv_timings, + .vidioc_g_dv_timings = vpif_g_dv_timings, + .vidioc_g_chip_ident = vpif_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vpif_dbg_g_register, + .vidioc_s_register = vpif_dbg_s_register, +#endif + .vidioc_log_status = vpif_log_status, +}; + +static const struct v4l2_file_operations vpif_fops = { + .owner = THIS_MODULE, + .open = vpif_open, + .release = vpif_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vpif_mmap, + .poll = vpif_poll +}; + +static struct video_device vpif_video_template = { + .name = "vpif", + .fops = &vpif_fops, + .ioctl_ops = &vpif_ioctl_ops, + .tvnorms = DM646X_V4L2_STD, + .current_norm = V4L2_STD_625_50, + +}; + +/*Configure the channels, buffer sizei, request irq */ +static int initialize_vpif(void) +{ + int free_channel_objects_index; + int free_buffer_channel_index; + int free_buffer_index; + int err = 0, i, j; + + /* Default number of buffers should be 3 */ + if ((ch2_numbuffers > 0) && + (ch2_numbuffers < config_params.min_numbuffers)) + ch2_numbuffers = config_params.min_numbuffers; + if ((ch3_numbuffers > 0) && + (ch3_numbuffers < config_params.min_numbuffers)) + ch3_numbuffers = config_params.min_numbuffers; + + /* Set buffer size to min buffers size if invalid buffer size is + * given */ + if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]) + ch2_bufsize = + config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]; + if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]) + ch3_bufsize = + config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]; + + config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers; + + if (ch2_numbuffers) { + config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] = + ch2_bufsize; + } + config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers; + + if (ch3_numbuffers) { + config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] = + ch3_bufsize; + } + + /* Allocate memory for six channel objects */ + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + vpif_obj.dev[i] = + kzalloc(sizeof(struct channel_obj), GFP_KERNEL); + /* If memory allocation fails, return error */ + if (!vpif_obj.dev[i]) { + free_channel_objects_index = i; + err = -ENOMEM; + goto vpif_init_free_channel_objects; + } + } + + free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES; + free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS; + free_buffer_index = config_params.numbuffers[i - 1]; + + return 0; + +vpif_init_free_channel_objects: + for (j = 0; j < free_channel_objects_index; j++) + kfree(vpif_obj.dev[j]); + return err; +} + +/* + * vpif_probe: This function creates device entries by register itself to the + * V4L2 driver and initializes fields of each channel objects + */ +static __init int vpif_probe(struct platform_device *pdev) +{ + struct vpif_subdev_info *subdevdata; + struct vpif_display_config *config; + int i, j = 0, k, q, m, err = 0; + struct i2c_adapter *i2c_adap; + struct common_obj *common; + struct channel_obj *ch; + struct video_device *vfd; + struct resource *res; + int subdev_count; + + vpif_dev = &pdev->dev; + + err = initialize_vpif(); + + if (err) { + v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); + return err; + } + + err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); + if (err) { + v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); + return err; + } + + k = 0; + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + for (i = res->start; i <= res->end; i++) { + if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, + "DM646x_Display", + (void *)(&vpif_obj.dev[k]->channel_id))) { + err = -EBUSY; + goto vpif_int_err; + } + } + k++; + } + + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + + /* Allocate memory for video device */ + vfd = video_device_alloc(); + if (vfd == NULL) { + for (j = 0; j < i; j++) { + ch = vpif_obj.dev[j]; + video_device_release(ch->video_dev); + } + err = -ENOMEM; + goto vpif_int_err; + } + + /* Initialize field of video device */ + *vfd = vpif_video_template; + vfd->v4l2_dev = &vpif_obj.v4l2_dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), + "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d", + (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff, + (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff, + (VPIF_DISPLAY_VERSION_CODE) & 0xff); + + /* Set video_dev to the video device */ + ch->video_dev = vfd; + } + + for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + /* Initialize field of the channel objects */ + atomic_set(&ch->usrs, 0); + for (k = 0; k < VPIF_NUMOBJECTS; k++) { + ch->common[k].numbuffers = 0; + common = &ch->common[k]; + common->io_usrs = 0; + common->started = 0; + spin_lock_init(&common->irqlock); + mutex_init(&common->lock); + common->numbuffers = 0; + common->set_addr = NULL; + common->ytop_off = common->ybtm_off = 0; + common->ctop_off = common->cbtm_off = 0; + common->cur_frm = common->next_frm = NULL; + memset(&common->fmt, 0, sizeof(common->fmt)); + common->numbuffers = config_params.numbuffers[k]; + + } + ch->initialized = 0; + ch->channel_id = j; + if (j < 2) + ch->common[VPIF_VIDEO_INDEX].numbuffers = + config_params.numbuffers[ch->channel_id]; + else + ch->common[VPIF_VIDEO_INDEX].numbuffers = 0; + + memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); + + /* Initialize prio member of channel object */ + v4l2_prio_init(&ch->prio); + ch->common[VPIF_VIDEO_INDEX].fmt.type = + V4L2_BUF_TYPE_VIDEO_OUTPUT; + ch->video_dev->lock = &common->lock; + + /* register video device */ + vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", + (int)ch, (int)&ch->video_dev); + + err = video_register_device(ch->video_dev, + VFL_TYPE_GRABBER, (j ? 3 : 2)); + if (err < 0) + goto probe_out; + + video_set_drvdata(ch->video_dev, ch); + } + + i2c_adap = i2c_get_adapter(1); + config = pdev->dev.platform_data; + subdev_count = config->subdev_count; + subdevdata = config->subdevinfo; + vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, + GFP_KERNEL); + if (vpif_obj.sd == NULL) { + vpif_err("unable to allocate memory for subdevice pointers\n"); + err = -ENOMEM; + goto probe_out; + } + + for (i = 0; i < subdev_count; i++) { + vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, + i2c_adap, + &subdevdata[i].board_info, + NULL); + if (!vpif_obj.sd[i]) { + vpif_err("Error registering v4l2 subdevice\n"); + goto probe_subdev_out; + } + + if (vpif_obj.sd[i]) + vpif_obj.sd[i]->grp_id = 1 << i; + } + + v4l2_info(&vpif_obj.v4l2_dev, + "DM646x VPIF display driver initialized\n"); + return 0; + +probe_subdev_out: + kfree(vpif_obj.sd); +probe_out: + for (k = 0; k < j; k++) { + ch = vpif_obj.dev[k]; + video_unregister_device(ch->video_dev); + video_device_release(ch->video_dev); + ch->video_dev = NULL; + } +vpif_int_err: + v4l2_device_unregister(&vpif_obj.v4l2_dev); + vpif_err("VPIF IRQ request failed\n"); + for (q = k; k >= 0; k--) { + for (m = i; m >= res->start; m--) + free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id)); + res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1); + m = res->end; + } + + return err; +} + +/* + * vpif_remove: It un-register channels from V4L2 driver + */ +static int vpif_remove(struct platform_device *device) +{ + struct channel_obj *ch; + int i; + + v4l2_device_unregister(&vpif_obj.v4l2_dev); + + /* un-register device */ + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + /* Unregister video device */ + video_unregister_device(ch->video_dev); + + ch->video_dev = NULL; + } + + return 0; +} + +static __refdata struct platform_driver vpif_driver = { + .driver = { + .name = "vpif_display", + .owner = THIS_MODULE, + }, + .probe = vpif_probe, + .remove = vpif_remove, +}; + +static __init int vpif_init(void) +{ + return platform_driver_register(&vpif_driver); +} + +/* + * vpif_cleanup: This function un-registers device and driver to the kernel, + * frees requested irq handler and de-allocates memory allocated for channel + * objects. + */ +static void vpif_cleanup(void) +{ + struct platform_device *pdev; + struct resource *res; + int irq_num; + int i = 0; + + pdev = container_of(vpif_dev, struct platform_device, dev); + + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { + for (irq_num = res->start; irq_num <= res->end; irq_num++) + free_irq(irq_num, + (void *)(&vpif_obj.dev[i]->channel_id)); + i++; + } + + platform_driver_unregister(&vpif_driver); + kfree(vpif_obj.sd); + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) + kfree(vpif_obj.dev[i]); +} + +module_init(vpif_init); +module_exit(vpif_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_display.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_display.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_display.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif_display.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,177 @@ +/* + * DM646x display header file + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef DAVINCIHD_DISPLAY_H +#define DAVINCIHD_DISPLAY_H + +/* Header files */ +#include +#include +#include +#include +#include +#include + +#include "vpif.h" + +/* Macros */ +#define VPIF_MAJOR_RELEASE (0) +#define VPIF_MINOR_RELEASE (0) +#define VPIF_BUILD (1) + +#define VPIF_DISPLAY_VERSION_CODE \ + ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) + +#define VPIF_VALID_FIELD(field) \ + (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \ + (((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \ + (V4L2_FIELD_SEQ_BT == field))) + +#define VPIF_DISPLAY_MAX_DEVICES (2) +#define VPIF_SLICED_BUF_SIZE (256) +#define VPIF_SLICED_MAX_SERVICES (3) +#define VPIF_VIDEO_INDEX (0) +#define VPIF_VBI_INDEX (1) +#define VPIF_HBI_INDEX (2) + +/* Setting it to 1 as HBI/VBI support yet to be added , else 3*/ +#define VPIF_NUMOBJECTS (1) + +/* Macros */ +#define ISALIGNED(a) (0 == ((a) & 7)) + +/* enumerated data types */ +/* Enumerated data type to give id to each device per channel */ +enum vpif_channel_id { + VPIF_CHANNEL2_VIDEO = 0, /* Channel2 Video */ + VPIF_CHANNEL3_VIDEO, /* Channel3 Video */ +}; + +/* structures */ + +struct video_obj { + enum v4l2_field buf_field; + u32 latest_only; /* indicate whether to return + * most recent displayed frame only */ + v4l2_std_id stdid; /* Currently selected or default + * standard */ + u32 dv_preset; + struct v4l2_bt_timings bt_timings; + u32 output_id; /* Current output id */ +}; + +struct vbi_obj { + int num_services; + struct vpif_vbi_params vbiparams; /* vpif parameters for the raw + * vbi data */ +}; + +struct common_obj { + /* Buffer specific parameters */ + u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for + * storing frames */ + u32 numbuffers; /* number of buffers */ + struct videobuf_buffer *cur_frm; /* Pointer pointing to current + * videobuf_buffer */ + struct videobuf_buffer *next_frm; /* Pointer pointing to next + * videobuf_buffer */ + enum v4l2_memory memory; /* This field keeps track of + * type of buffer exchange + * method user has selected */ + struct v4l2_format fmt; /* Used to store the format */ + struct videobuf_queue buffer_queue; /* Buffer queue used in + * video-buf */ + struct list_head dma_queue; /* Queue of filled frames */ + spinlock_t irqlock; /* Used in video-buf */ + + /* channel specific parameters */ + struct mutex lock; /* lock used to access this + * structure */ + u32 io_usrs; /* number of users performing + * IO */ + u8 started; /* Indicates whether streaming + * started */ + u32 ytop_off; /* offset of Y top from the + * starting of the buffer */ + u32 ybtm_off; /* offset of Y bottom from the + * starting of the buffer */ + u32 ctop_off; /* offset of C top from the + * starting of the buffer */ + u32 cbtm_off; /* offset of C bottom from the + * starting of the buffer */ + /* Function pointer to set the addresses */ + void (*set_addr) (unsigned long, unsigned long, + unsigned long, unsigned long); + u32 height; + u32 width; +}; + +struct channel_obj { + /* V4l2 specific parameters */ + struct video_device *video_dev; /* Identifies video device for + * this channel */ + struct v4l2_prio_state prio; /* Used to keep track of state of + * the priority */ + atomic_t usrs; /* number of open instances of + * the channel */ + u32 field_id; /* Indicates id of the field + * which is being displayed */ + u8 initialized; /* flag to indicate whether + * encoder is initialized */ + + enum vpif_channel_id channel_id;/* Identifies channel */ + struct vpif_params vpifparams; + struct common_obj common[VPIF_NUMOBJECTS]; + struct video_obj video; + struct vbi_obj vbi; +}; + +/* File handle structure */ +struct vpif_fh { + struct channel_obj *channel; /* pointer to channel object for + * opened device */ + u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle + * is doing IO */ + enum v4l2_priority prio; /* Used to keep track priority of + * this instance */ + u8 initialized; /* Used to keep track of whether this + * file handle has initialized + * channel or not */ +}; + +/* vpif device structure */ +struct vpif_device { + struct v4l2_device v4l2_dev; + struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS]; + struct v4l2_subdev **sd; + +}; + +struct vpif_config_params { + u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; + u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; + u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS]; + u8 min_numbuffers; +}; + +/* Struct which keeps track of the line numbers for the sliced vbi service */ +struct vpif_service_line { + u16 service_id; + u16 service_line[2]; + u16 enc_service_id; + u8 bytestowrite; +}; + +#endif /* DAVINCIHD_DISPLAY_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpif.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,644 @@ +/* + * VPIF header file + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef VPIF_H +#define VPIF_H + +#include +#include +#include +#include + +/* Maximum channel allowed */ +#define VPIF_NUM_CHANNELS (4) +#define VPIF_CAPTURE_NUM_CHANNELS (2) +#define VPIF_DISPLAY_NUM_CHANNELS (2) + +/* Macros to read/write registers */ +extern void __iomem *vpif_base; +extern spinlock_t vpif_lock; + +#define regr(reg) readl((reg) + vpif_base) +#define regw(value, reg) writel(value, (reg + vpif_base)) + +/* Register Address Offsets */ +#define VPIF_PID (0x0000) +#define VPIF_CH0_CTRL (0x0004) +#define VPIF_CH1_CTRL (0x0008) +#define VPIF_CH2_CTRL (0x000C) +#define VPIF_CH3_CTRL (0x0010) + +#define VPIF_INTEN (0x0020) +#define VPIF_INTEN_SET (0x0024) +#define VPIF_INTEN_CLR (0x0028) +#define VPIF_STATUS (0x002C) +#define VPIF_STATUS_CLR (0x0030) +#define VPIF_EMULATION_CTRL (0x0034) +#define VPIF_REQ_SIZE (0x0038) + +#define VPIF_CH0_TOP_STRT_ADD_LUMA (0x0040) +#define VPIF_CH0_BTM_STRT_ADD_LUMA (0x0044) +#define VPIF_CH0_TOP_STRT_ADD_CHROMA (0x0048) +#define VPIF_CH0_BTM_STRT_ADD_CHROMA (0x004c) +#define VPIF_CH0_TOP_STRT_ADD_HANC (0x0050) +#define VPIF_CH0_BTM_STRT_ADD_HANC (0x0054) +#define VPIF_CH0_TOP_STRT_ADD_VANC (0x0058) +#define VPIF_CH0_BTM_STRT_ADD_VANC (0x005c) +#define VPIF_CH0_SP_CFG (0x0060) +#define VPIF_CH0_IMG_ADD_OFST (0x0064) +#define VPIF_CH0_HANC_ADD_OFST (0x0068) +#define VPIF_CH0_H_CFG (0x006c) +#define VPIF_CH0_V_CFG_00 (0x0070) +#define VPIF_CH0_V_CFG_01 (0x0074) +#define VPIF_CH0_V_CFG_02 (0x0078) +#define VPIF_CH0_V_CFG_03 (0x007c) + +#define VPIF_CH1_TOP_STRT_ADD_LUMA (0x0080) +#define VPIF_CH1_BTM_STRT_ADD_LUMA (0x0084) +#define VPIF_CH1_TOP_STRT_ADD_CHROMA (0x0088) +#define VPIF_CH1_BTM_STRT_ADD_CHROMA (0x008c) +#define VPIF_CH1_TOP_STRT_ADD_HANC (0x0090) +#define VPIF_CH1_BTM_STRT_ADD_HANC (0x0094) +#define VPIF_CH1_TOP_STRT_ADD_VANC (0x0098) +#define VPIF_CH1_BTM_STRT_ADD_VANC (0x009c) +#define VPIF_CH1_SP_CFG (0x00a0) +#define VPIF_CH1_IMG_ADD_OFST (0x00a4) +#define VPIF_CH1_HANC_ADD_OFST (0x00a8) +#define VPIF_CH1_H_CFG (0x00ac) +#define VPIF_CH1_V_CFG_00 (0x00b0) +#define VPIF_CH1_V_CFG_01 (0x00b4) +#define VPIF_CH1_V_CFG_02 (0x00b8) +#define VPIF_CH1_V_CFG_03 (0x00bc) + +#define VPIF_CH2_TOP_STRT_ADD_LUMA (0x00c0) +#define VPIF_CH2_BTM_STRT_ADD_LUMA (0x00c4) +#define VPIF_CH2_TOP_STRT_ADD_CHROMA (0x00c8) +#define VPIF_CH2_BTM_STRT_ADD_CHROMA (0x00cc) +#define VPIF_CH2_TOP_STRT_ADD_HANC (0x00d0) +#define VPIF_CH2_BTM_STRT_ADD_HANC (0x00d4) +#define VPIF_CH2_TOP_STRT_ADD_VANC (0x00d8) +#define VPIF_CH2_BTM_STRT_ADD_VANC (0x00dc) +#define VPIF_CH2_SP_CFG (0x00e0) +#define VPIF_CH2_IMG_ADD_OFST (0x00e4) +#define VPIF_CH2_HANC_ADD_OFST (0x00e8) +#define VPIF_CH2_H_CFG (0x00ec) +#define VPIF_CH2_V_CFG_00 (0x00f0) +#define VPIF_CH2_V_CFG_01 (0x00f4) +#define VPIF_CH2_V_CFG_02 (0x00f8) +#define VPIF_CH2_V_CFG_03 (0x00fc) +#define VPIF_CH2_HANC0_STRT (0x0100) +#define VPIF_CH2_HANC0_SIZE (0x0104) +#define VPIF_CH2_HANC1_STRT (0x0108) +#define VPIF_CH2_HANC1_SIZE (0x010c) +#define VPIF_CH2_VANC0_STRT (0x0110) +#define VPIF_CH2_VANC0_SIZE (0x0114) +#define VPIF_CH2_VANC1_STRT (0x0118) +#define VPIF_CH2_VANC1_SIZE (0x011c) + +#define VPIF_CH3_TOP_STRT_ADD_LUMA (0x0140) +#define VPIF_CH3_BTM_STRT_ADD_LUMA (0x0144) +#define VPIF_CH3_TOP_STRT_ADD_CHROMA (0x0148) +#define VPIF_CH3_BTM_STRT_ADD_CHROMA (0x014c) +#define VPIF_CH3_TOP_STRT_ADD_HANC (0x0150) +#define VPIF_CH3_BTM_STRT_ADD_HANC (0x0154) +#define VPIF_CH3_TOP_STRT_ADD_VANC (0x0158) +#define VPIF_CH3_BTM_STRT_ADD_VANC (0x015c) +#define VPIF_CH3_SP_CFG (0x0160) +#define VPIF_CH3_IMG_ADD_OFST (0x0164) +#define VPIF_CH3_HANC_ADD_OFST (0x0168) +#define VPIF_CH3_H_CFG (0x016c) +#define VPIF_CH3_V_CFG_00 (0x0170) +#define VPIF_CH3_V_CFG_01 (0x0174) +#define VPIF_CH3_V_CFG_02 (0x0178) +#define VPIF_CH3_V_CFG_03 (0x017c) +#define VPIF_CH3_HANC0_STRT (0x0180) +#define VPIF_CH3_HANC0_SIZE (0x0184) +#define VPIF_CH3_HANC1_STRT (0x0188) +#define VPIF_CH3_HANC1_SIZE (0x018c) +#define VPIF_CH3_VANC0_STRT (0x0190) +#define VPIF_CH3_VANC0_SIZE (0x0194) +#define VPIF_CH3_VANC1_STRT (0x0198) +#define VPIF_CH3_VANC1_SIZE (0x019c) + +#define VPIF_IODFT_CTRL (0x01c0) + +/* Functions for bit Manipulation */ +static inline void vpif_set_bit(u32 reg, u32 bit) +{ + regw((regr(reg)) | (0x01 << bit), reg); +} + +static inline void vpif_clr_bit(u32 reg, u32 bit) +{ + regw(((regr(reg)) & ~(0x01 << bit)), reg); +} + +/* Macro for Generating mask */ +#ifdef GENERATE_MASK +#undef GENERATE_MASK +#endif + +#define GENERATE_MASK(bits, pos) \ + ((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos) + +/* Bit positions in the channel control registers */ +#define VPIF_CH_DATA_MODE_BIT (2) +#define VPIF_CH_YC_MUX_BIT (3) +#define VPIF_CH_SDR_FMT_BIT (4) +#define VPIF_CH_HANC_EN_BIT (8) +#define VPIF_CH_VANC_EN_BIT (9) + +#define VPIF_CAPTURE_CH_NIP (10) +#define VPIF_DISPLAY_CH_NIP (11) + +#define VPIF_DISPLAY_PIX_EN_BIT (10) + +#define VPIF_CH_INPUT_FIELD_FRAME_BIT (12) + +#define VPIF_CH_FID_POLARITY_BIT (15) +#define VPIF_CH_V_VALID_POLARITY_BIT (14) +#define VPIF_CH_H_VALID_POLARITY_BIT (13) +#define VPIF_CH_DATA_WIDTH_BIT (28) + +#define VPIF_CH_CLK_EDGE_CTRL_BIT (31) + +/* Mask various length */ +#define VPIF_CH_EAVSAV_MASK GENERATE_MASK(13, 0) +#define VPIF_CH_LEN_MASK GENERATE_MASK(12, 0) +#define VPIF_CH_WIDTH_MASK GENERATE_MASK(13, 0) +#define VPIF_CH_LEN_SHIFT (16) + +/* VPIF masks for registers */ +#define VPIF_REQ_SIZE_MASK (0x1ff) + +/* bit posotion of interrupt vpif_ch_intr register */ +#define VPIF_INTEN_FRAME_CH0 (0x00000001) +#define VPIF_INTEN_FRAME_CH1 (0x00000002) +#define VPIF_INTEN_FRAME_CH2 (0x00000004) +#define VPIF_INTEN_FRAME_CH3 (0x00000008) + +/* bit position of clock and channel enable in vpif_chn_ctrl register */ + +#define VPIF_CH0_CLK_EN (0x00000002) +#define VPIF_CH0_EN (0x00000001) +#define VPIF_CH1_CLK_EN (0x00000002) +#define VPIF_CH1_EN (0x00000001) +#define VPIF_CH2_CLK_EN (0x00000002) +#define VPIF_CH2_EN (0x00000001) +#define VPIF_CH3_CLK_EN (0x00000002) +#define VPIF_CH3_EN (0x00000001) +#define VPIF_CH_CLK_EN (0x00000002) +#define VPIF_CH_EN (0x00000001) + +#define VPIF_INT_TOP (0x00) +#define VPIF_INT_BOTTOM (0x01) +#define VPIF_INT_BOTH (0x02) + +#define VPIF_CH0_INT_CTRL_SHIFT (6) +#define VPIF_CH1_INT_CTRL_SHIFT (6) +#define VPIF_CH2_INT_CTRL_SHIFT (6) +#define VPIF_CH3_INT_CTRL_SHIFT (6) +#define VPIF_CH_INT_CTRL_SHIFT (6) + +/* enabled interrupt on both the fields on vpid_ch0_ctrl register */ +#define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\ + (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL)) + +/* enabled interrupt on both the fields on vpid_ch1_ctrl register */ +#define channel1_intr_assert() (regw((regr(VPIF_CH1_CTRL)|\ + (VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL)) + +/* enabled interrupt on both the fields on vpid_ch0_ctrl register */ +#define channel2_intr_assert() (regw((regr(VPIF_CH2_CTRL)|\ + (VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL)) + +/* enabled interrupt on both the fields on vpid_ch1_ctrl register */ +#define channel3_intr_assert() (regw((regr(VPIF_CH3_CTRL)|\ + (VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL)) + +#define VPIF_CH_FID_MASK (0x20) +#define VPIF_CH_FID_SHIFT (5) + +#define VPIF_NTSC_VBI_START_FIELD0 (1) +#define VPIF_NTSC_VBI_START_FIELD1 (263) +#define VPIF_PAL_VBI_START_FIELD0 (624) +#define VPIF_PAL_VBI_START_FIELD1 (311) + +#define VPIF_NTSC_HBI_START_FIELD0 (1) +#define VPIF_NTSC_HBI_START_FIELD1 (263) +#define VPIF_PAL_HBI_START_FIELD0 (624) +#define VPIF_PAL_HBI_START_FIELD1 (311) + +#define VPIF_NTSC_VBI_COUNT_FIELD0 (20) +#define VPIF_NTSC_VBI_COUNT_FIELD1 (19) +#define VPIF_PAL_VBI_COUNT_FIELD0 (24) +#define VPIF_PAL_VBI_COUNT_FIELD1 (25) + +#define VPIF_NTSC_HBI_COUNT_FIELD0 (263) +#define VPIF_NTSC_HBI_COUNT_FIELD1 (262) +#define VPIF_PAL_HBI_COUNT_FIELD0 (312) +#define VPIF_PAL_HBI_COUNT_FIELD1 (313) + +#define VPIF_NTSC_VBI_SAMPLES_PER_LINE (720) +#define VPIF_PAL_VBI_SAMPLES_PER_LINE (720) +#define VPIF_NTSC_HBI_SAMPLES_PER_LINE (268) +#define VPIF_PAL_HBI_SAMPLES_PER_LINE (280) + +#define VPIF_CH_VANC_EN (0x20) +#define VPIF_DMA_REQ_SIZE (0x080) +#define VPIF_EMULATION_DISABLE (0x01) + +extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS]; + +/* inline function to enable/disable channel0 */ +static inline void enable_channel0(int enable) +{ + if (enable) + regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL); + else + regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL); +} + +/* inline function to enable/disable channel1 */ +static inline void enable_channel1(int enable) +{ + if (enable) + regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL); + else + regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL); +} + +/* inline function to enable interrupt for channel0 */ +static inline void channel0_intr_enable(int enable) +{ + unsigned long flags; + + spin_lock_irqsave(&vpif_lock, flags); + + if (enable) { + regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); + + regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), + VPIF_INTEN_SET); + } else { + regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), + VPIF_INTEN_SET); + } + spin_unlock_irqrestore(&vpif_lock, flags); +} + +/* inline function to enable interrupt for channel1 */ +static inline void channel1_intr_enable(int enable) +{ + unsigned long flags; + + spin_lock_irqsave(&vpif_lock, flags); + + if (enable) { + regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); + + regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), + VPIF_INTEN_SET); + } else { + regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), + VPIF_INTEN_SET); + } + spin_unlock_irqrestore(&vpif_lock, flags); +} + +/* inline function to set buffer addresses in case of Y/C non mux mode */ +static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); +} + +/* inline function to set buffer addresses in VPIF registers for video data */ +static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA); +} + +static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + + regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); +} + +static inline void ch0_set_vbi_addr(unsigned long top_vbi, + unsigned long btm_vbi, unsigned long a, unsigned long b) +{ + regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC); + regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC); +} + +static inline void ch0_set_hbi_addr(unsigned long top_vbi, + unsigned long btm_vbi, unsigned long a, unsigned long b) +{ + regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC); + regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC); +} + +static inline void ch1_set_vbi_addr(unsigned long top_vbi, + unsigned long btm_vbi, unsigned long a, unsigned long b) +{ + regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC); + regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC); +} + +static inline void ch1_set_hbi_addr(unsigned long top_vbi, + unsigned long btm_vbi, unsigned long a, unsigned long b) +{ + regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC); + regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC); +} + +/* Inline function to enable raw vbi in the given channel */ +static inline void disable_raw_feature(u8 channel_id, u8 index) +{ + u32 ctrl_reg; + if (0 == channel_id) + ctrl_reg = VPIF_CH0_CTRL; + else + ctrl_reg = VPIF_CH1_CTRL; + + if (1 == index) + vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); + else + vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); +} + +static inline void enable_raw_feature(u8 channel_id, u8 index) +{ + u32 ctrl_reg; + if (0 == channel_id) + ctrl_reg = VPIF_CH0_CTRL; + else + ctrl_reg = VPIF_CH1_CTRL; + + if (1 == index) + vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); + else + vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); +} + +/* inline function to enable/disable channel2 */ +static inline void enable_channel2(int enable) +{ + if (enable) { + regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); + regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL); + } else { + regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); + regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL); + } +} + +/* inline function to enable/disable channel3 */ +static inline void enable_channel3(int enable) +{ + if (enable) { + regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); + regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL); + } else { + regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); + regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL); + } +} + +/* inline function to enable interrupt for channel2 */ +static inline void channel2_intr_enable(int enable) +{ + unsigned long flags; + + spin_lock_irqsave(&vpif_lock, flags); + + if (enable) { + regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); + regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), + VPIF_INTEN_SET); + } else { + regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), + VPIF_INTEN_SET); + } + spin_unlock_irqrestore(&vpif_lock, flags); +} + +/* inline function to enable interrupt for channel3 */ +static inline void channel3_intr_enable(int enable) +{ + unsigned long flags; + + spin_lock_irqsave(&vpif_lock, flags); + + if (enable) { + regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); + + regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), + VPIF_INTEN_SET); + } else { + regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), + VPIF_INTEN_SET); + } + spin_unlock_irqrestore(&vpif_lock, flags); +} + +/* inline function to enable raw vbi data for channel2 */ +static inline void channel2_raw_enable(int enable, u8 index) +{ + u32 mask; + + if (1 == index) + mask = VPIF_CH_VANC_EN_BIT; + else + mask = VPIF_CH_HANC_EN_BIT; + + if (enable) + vpif_set_bit(VPIF_CH2_CTRL, mask); + else + vpif_clr_bit(VPIF_CH2_CTRL, mask); +} + +/* inline function to enable raw vbi data for channel3*/ +static inline void channel3_raw_enable(int enable, u8 index) +{ + u32 mask; + + if (1 == index) + mask = VPIF_CH_VANC_EN_BIT; + else + mask = VPIF_CH_HANC_EN_BIT; + + if (enable) + vpif_set_bit(VPIF_CH3_CTRL, mask); + else + vpif_clr_bit(VPIF_CH3_CTRL, mask); +} + +/* inline function to set buffer addresses in case of Y/C non mux mode */ +static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); +} + +/* inline function to set buffer addresses in VPIF registers for video data */ +static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA); +} + +static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); +} + +/* inline function to set buffer addresses in VPIF registers for vbi data */ +static inline void ch2_set_vbi_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC); + regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC); +} + +static inline void ch3_set_vbi_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC); + regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC); +} + +#define VPIF_MAX_NAME (30) + +/* This structure will store size parameters as per the mode selected by user */ +struct vpif_channel_config_params { + char name[VPIF_MAX_NAME]; /* Name of the mode */ + u16 width; /* Indicates width of the image */ + u16 height; /* Indicates height of the image */ + u8 frm_fmt; /* Interlaced (0) or progressive (1) */ + u8 ycmux_mode; /* This mode requires one (0) or two (1) + channels */ + u16 eav2sav; /* length of eav 2 sav */ + u16 sav2eav; /* length of sav 2 eav */ + u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */ + u16 vsize; /* Vertical size of the image */ + u8 capture_format; /* Indicates whether capture format + * is in BT or in CCD/CMOS */ + u8 vbi_supported; /* Indicates whether this mode + * supports capturing vbi or not */ + u8 hd_sd; /* HDTV (1) or SDTV (0) format */ + v4l2_std_id stdid; /* SDTV format */ + u32 dv_preset; /* HDTV format */ +}; + +extern const unsigned int vpif_ch_params_count; +extern const struct vpif_channel_config_params ch_params[]; + +struct vpif_video_params; +struct vpif_params; +struct vpif_vbi_params; + +int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id); +void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, + u8 channel_id); +int vpif_channel_getfid(u8 channel_id); + +enum data_size { + _8BITS = 0, + _10BITS, + _12BITS, +}; + +/* Structure for vpif parameters for raw vbi data */ +struct vpif_vbi_params { + __u32 hstart0; /* Horizontal start of raw vbi data for first field */ + __u32 vstart0; /* Vertical start of raw vbi data for first field */ + __u32 hsize0; /* Horizontal size of raw vbi data for first field */ + __u32 vsize0; /* Vertical size of raw vbi data for first field */ + __u32 hstart1; /* Horizontal start of raw vbi data for second field */ + __u32 vstart1; /* Vertical start of raw vbi data for second field */ + __u32 hsize1; /* Horizontal size of raw vbi data for second field */ + __u32 vsize1; /* Vertical size of raw vbi data for second field */ +}; + +/* structure for vpif parameters */ +struct vpif_video_params { + __u8 storage_mode; /* Indicates field or frame mode */ + unsigned long hpitch; + v4l2_std_id stdid; +}; + +struct vpif_params { + struct vpif_interface iface; + struct vpif_video_params video_params; + struct vpif_channel_config_params std_info; + union param { + struct vpif_vbi_params vbi_params; + enum data_size data_sz; + } params; +}; + +#endif /* End of #ifndef VPIF_H */ + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpss.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpss.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpss.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/davinci/vpss.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,482 @@ +/* + * Copyright (C) 2009 Texas Instruments. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * common vpss system module platform driver for all video drivers. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VPSS Driver"); +MODULE_AUTHOR("Texas Instruments"); + +/* DM644x defines */ +#define DM644X_SBL_PCR_VPSS (4) + +#define DM355_VPSSBL_INTSEL 0x10 +#define DM355_VPSSBL_EVTSEL 0x14 +/* vpss BL register offsets */ +#define DM355_VPSSBL_CCDCMUX 0x1c +/* vpss CLK register offsets */ +#define DM355_VPSSCLK_CLKCTRL 0x04 +/* masks and shifts */ +#define VPSS_HSSISEL_SHIFT 4 +/* + * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4, + * IPIPE_INT1_SDR - vpss_int5 + */ +#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10 +/* VENCINT - vpss_int8 */ +#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4 + +#define DM365_ISP5_PCCR 0x04 +#define DM365_ISP5_INTSEL1 0x10 +#define DM365_ISP5_INTSEL2 0x14 +#define DM365_ISP5_INTSEL3 0x18 +#define DM365_ISP5_CCDCMUX 0x20 +#define DM365_ISP5_PG_FRAME_SIZE 0x28 +#define DM365_VPBE_CLK_CTRL 0x00 +/* + * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1, + * AF - vpss_int3 + */ +#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100 +/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */ +#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f +/* VENC - vpss_int8 */ +#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015 + +/* masks and shifts for DM365*/ +#define DM365_CCDC_PG_VD_POL_SHIFT 0 +#define DM365_CCDC_PG_HD_POL_SHIFT 1 + +#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4)) +#define CCD_SRC_SEL_SHIFT 4 + +/* Different SoC platforms supported by this driver */ +enum vpss_platform_type { + DM644X, + DM355, + DM365, +}; + +/* + * vpss operations. Depends on platform. Not all functions are available + * on all platforms. The api, first check if a functio is available before + * invoking it. In the probe, the function ptrs are initialized based on + * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. + */ +struct vpss_hw_ops { + /* enable clock */ + int (*enable_clock)(enum vpss_clock_sel clock_sel, int en); + /* select input to ccdc */ + void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel); + /* clear wbl overflow bit */ + int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel); +}; + +/* vpss configuration */ +struct vpss_oper_config { + __iomem void *vpss_regs_base0; + __iomem void *vpss_regs_base1; + enum vpss_platform_type platform; + spinlock_t vpss_lock; + struct vpss_hw_ops hw_ops; +}; + +static struct vpss_oper_config oper_cfg; + +/* register access routines */ +static inline u32 bl_regr(u32 offset) +{ + return __raw_readl(oper_cfg.vpss_regs_base0 + offset); +} + +static inline void bl_regw(u32 val, u32 offset) +{ + __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); +} + +static inline u32 vpss_regr(u32 offset) +{ + return __raw_readl(oper_cfg.vpss_regs_base1 + offset); +} + +static inline void vpss_regw(u32 val, u32 offset) +{ + __raw_writel(val, oper_cfg.vpss_regs_base1 + offset); +} + +/* For DM365 only */ +static inline u32 isp5_read(u32 offset) +{ + return __raw_readl(oper_cfg.vpss_regs_base0 + offset); +} + +/* For DM365 only */ +static inline void isp5_write(u32 val, u32 offset) +{ + __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); +} + +static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) +{ + u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK; + + /* if we are using pattern generator, enable it */ + if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG) + temp |= 0x08; + + temp |= (src_sel << CCD_SRC_SEL_SHIFT); + isp5_write(temp, DM365_ISP5_CCDCMUX); +} + +static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) +{ + bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX); +} + +int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) +{ + if (!oper_cfg.hw_ops.select_ccdc_source) + return -EINVAL; + + oper_cfg.hw_ops.select_ccdc_source(src_sel); + return 0; +} +EXPORT_SYMBOL(vpss_select_ccdc_source); + +static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) +{ + u32 mask = 1, val; + + if (wbl_sel < VPSS_PCR_AEW_WBL_0 || + wbl_sel > VPSS_PCR_CCDC_WBL_O) + return -EINVAL; + + /* writing a 0 clear the overflow */ + mask = ~(mask << wbl_sel); + val = bl_regr(DM644X_SBL_PCR_VPSS) & mask; + bl_regw(val, DM644X_SBL_PCR_VPSS); + return 0; +} + +int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) +{ + if (!oper_cfg.hw_ops.clear_wbl_overflow) + return -EINVAL; + + return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); +} +EXPORT_SYMBOL(vpss_clear_wbl_overflow); + +/* + * dm355_enable_clock - Enable VPSS Clock + * @clock_sel: CLock to be enabled/disabled + * @en: enable/disable flag + * + * This is called to enable or disable a vpss clock + */ +static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) +{ + unsigned long flags; + u32 utemp, mask = 0x1, shift = 0; + + switch (clock_sel) { + case VPSS_VPBE_CLOCK: + /* nothing since lsb */ + break; + case VPSS_VENC_CLOCK_SEL: + shift = 2; + break; + case VPSS_CFALD_CLOCK: + shift = 3; + break; + case VPSS_H3A_CLOCK: + shift = 4; + break; + case VPSS_IPIPE_CLOCK: + shift = 5; + break; + case VPSS_CCDC_CLOCK: + shift = 6; + break; + default: + printk(KERN_ERR "dm355_enable_clock:" + " Invalid selector: %d\n", clock_sel); + return -EINVAL; + } + + spin_lock_irqsave(&oper_cfg.vpss_lock, flags); + utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL); + if (!en) + utemp &= ~(mask << shift); + else + utemp |= (mask << shift); + + vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL); + spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); + return 0; +} + +static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en) +{ + unsigned long flags; + u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR; + u32 (*read)(u32 offset) = isp5_read; + void(*write)(u32 val, u32 offset) = isp5_write; + + switch (clock_sel) { + case VPSS_BL_CLOCK: + break; + case VPSS_CCDC_CLOCK: + shift = 1; + break; + case VPSS_H3A_CLOCK: + shift = 2; + break; + case VPSS_RSZ_CLOCK: + shift = 3; + break; + case VPSS_IPIPE_CLOCK: + shift = 4; + break; + case VPSS_IPIPEIF_CLOCK: + shift = 5; + break; + case VPSS_PCLK_INTERNAL: + shift = 6; + break; + case VPSS_PSYNC_CLOCK_SEL: + shift = 7; + break; + case VPSS_VPBE_CLOCK: + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_VENC_CLOCK_SEL: + shift = 2; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_LDC_CLOCK: + shift = 3; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_FDIF_CLOCK: + shift = 4; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_OSD_CLOCK_SEL: + shift = 6; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_LDC_CLOCK_SEL: + shift = 7; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + default: + printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n", + clock_sel); + return -1; + } + + spin_lock_irqsave(&oper_cfg.vpss_lock, flags); + utemp = read(offset); + if (!en) { + mask = ~mask; + utemp &= (mask << shift); + } else + utemp |= (mask << shift); + + write(utemp, offset); + spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); + + return 0; +} + +int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) +{ + if (!oper_cfg.hw_ops.enable_clock) + return -EINVAL; + + return oper_cfg.hw_ops.enable_clock(clock_sel, en); +} +EXPORT_SYMBOL(vpss_enable_clock); + +void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync) +{ + int val = 0; + val = isp5_read(DM365_ISP5_CCDCMUX); + + val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT); + val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT); + + isp5_write(val, DM365_ISP5_CCDCMUX); +} +EXPORT_SYMBOL(dm365_vpss_set_sync_pol); + +void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) +{ + int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16; + + current_reg |= (frame_size.pplen - 1); + isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE); +} +EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); + +static int __init vpss_probe(struct platform_device *pdev) +{ + struct resource *r1, *r2; + char *platform_name; + int status; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENOENT; + } + + platform_name = pdev->dev.platform_data; + if (!strcmp(platform_name, "dm355_vpss")) + oper_cfg.platform = DM355; + else if (!strcmp(platform_name, "dm365_vpss")) + oper_cfg.platform = DM365; + else if (!strcmp(platform_name, "dm644x_vpss")) + oper_cfg.platform = DM644X; + else { + dev_err(&pdev->dev, "vpss driver not supported on" + " this platform\n"); + return -ENODEV; + } + + dev_info(&pdev->dev, "%s vpss probed\n", platform_name); + r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r1) + return -ENOENT; + + r1 = request_mem_region(r1->start, resource_size(r1), r1->name); + if (!r1) + return -EBUSY; + + oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1)); + if (!oper_cfg.vpss_regs_base0) { + status = -EBUSY; + goto fail1; + } + + if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { + r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!r2) { + status = -ENOENT; + goto fail2; + } + r2 = request_mem_region(r2->start, resource_size(r2), r2->name); + if (!r2) { + status = -EBUSY; + goto fail2; + } + + oper_cfg.vpss_regs_base1 = ioremap(r2->start, + resource_size(r2)); + if (!oper_cfg.vpss_regs_base1) { + status = -EBUSY; + goto fail3; + } + } + + if (oper_cfg.platform == DM355) { + oper_cfg.hw_ops.enable_clock = dm355_enable_clock; + oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; + /* Setup vpss interrupts */ + bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL); + bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL); + } else if (oper_cfg.platform == DM365) { + oper_cfg.hw_ops.enable_clock = dm365_enable_clock; + oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source; + /* Setup vpss interrupts */ + isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1); + isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2); + isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3); + } else + oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; + + spin_lock_init(&oper_cfg.vpss_lock); + dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); + return 0; + +fail3: + release_mem_region(r2->start, resource_size(r2)); +fail2: + iounmap(oper_cfg.vpss_regs_base0); +fail1: + release_mem_region(r1->start, resource_size(r1)); + return status; +} + +static int __devexit vpss_remove(struct platform_device *pdev) +{ + struct resource *res; + + iounmap(oper_cfg.vpss_regs_base0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { + iounmap(oper_cfg.vpss_regs_base1); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + release_mem_region(res->start, resource_size(res)); + } + return 0; +} + +static struct platform_driver vpss_driver = { + .driver = { + .name = "vpss", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(vpss_remove), + .probe = vpss_probe, +}; + +static void vpss_exit(void) +{ + platform_driver_unregister(&vpss_driver); +} + +static int __init vpss_init(void) +{ + return platform_driver_register(&vpss_driver); +} +subsys_initcall(vpss_init); +module_exit(vpss_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-audio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-audio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-audio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-audio.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,748 @@ +/* + * Empiatech em28x1 audio extension + * + * Copyright (C) 2006 Markus Rechberger + * + * Copyright (C) 2007-2011 Mauro Carvalho Chehab + * - Port to work with the in-kernel driver + * - Cleanups, fixes, alsa-controls, etc. + * + * This driver is based on my previous au600 usb pstn audio driver + * and inherits all the copyrights + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "em28xx.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); + +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_INFO "em28xx-audio %s: " fmt, \ + __func__, ##arg); \ + } while (0) + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; + +static int em28xx_deinit_isoc_audio(struct em28xx *dev) +{ + int i; + + dprintk("Stopping isoc\n"); + for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { + if (!irqs_disabled()) + usb_kill_urb(dev->adev.urb[i]); + else + usb_unlink_urb(dev->adev.urb[i]); + + usb_free_urb(dev->adev.urb[i]); + dev->adev.urb[i] = NULL; + + kfree(dev->adev.transfer_buffer[i]); + dev->adev.transfer_buffer[i] = NULL; + } + + return 0; +} + +static void em28xx_audio_isocirq(struct urb *urb) +{ + struct em28xx *dev = urb->context; + int i; + unsigned int oldptr; + int period_elapsed = 0; + int status; + unsigned char *cp; + unsigned int stride; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + dprintk("urb completition error %d.\n", urb->status); + break; + } + + if (atomic_read(&dev->stream_started) == 0) + return; + + if (dev->adev.capture_pcm_substream) { + substream = dev->adev.capture_pcm_substream; + runtime = substream->runtime; + stride = runtime->frame_bits >> 3; + + for (i = 0; i < urb->number_of_packets; i++) { + int length = + urb->iso_frame_desc[i].actual_length / stride; + cp = (unsigned char *)urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + + if (!length) + continue; + + oldptr = dev->adev.hwptr_done_capture; + if (oldptr + length >= runtime->buffer_size) { + unsigned int cnt = + runtime->buffer_size - oldptr; + memcpy(runtime->dma_area + oldptr * stride, cp, + cnt * stride); + memcpy(runtime->dma_area, cp + cnt * stride, + length * stride - cnt * stride); + } else { + memcpy(runtime->dma_area + oldptr * stride, cp, + length * stride); + } + + snd_pcm_stream_lock(substream); + + dev->adev.hwptr_done_capture += length; + if (dev->adev.hwptr_done_capture >= + runtime->buffer_size) + dev->adev.hwptr_done_capture -= + runtime->buffer_size; + + dev->adev.capture_transfer_done += length; + if (dev->adev.capture_transfer_done >= + runtime->period_size) { + dev->adev.capture_transfer_done -= + runtime->period_size; + period_elapsed = 1; + } + + snd_pcm_stream_unlock(substream); + } + if (period_elapsed) + snd_pcm_period_elapsed(substream); + } + urb->status = 0; + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { + em28xx_errdev("resubmit of audio urb failed (error=%i)\n", + status); + } + return; +} + +static int em28xx_init_audio_isoc(struct em28xx *dev) +{ + int i, errCode; + const int sb_size = EM28XX_NUM_AUDIO_PACKETS * + EM28XX_AUDIO_MAX_PACKET_SIZE; + + dprintk("Starting isoc transfers\n"); + + for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { + struct urb *urb; + int j, k; + + dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); + if (!dev->adev.transfer_buffer[i]) + return -ENOMEM; + + memset(dev->adev.transfer_buffer[i], 0x80, sb_size); + urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); + if (!urb) { + em28xx_errdev("usb_alloc_urb failed!\n"); + for (j = 0; j < i; j++) { + usb_free_urb(dev->adev.urb[j]); + kfree(dev->adev.transfer_buffer[j]); + } + return -ENOMEM; + } + + urb->dev = dev->udev; + urb->context = dev; + urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = dev->adev.transfer_buffer[i]; + urb->interval = 1; + urb->complete = em28xx_audio_isocirq; + urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; + urb->transfer_buffer_length = sb_size; + + for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS; + j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = + EM28XX_AUDIO_MAX_PACKET_SIZE; + } + dev->adev.urb[i] = urb; + } + + for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { + errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); + if (errCode) { + em28xx_errdev("submit of audio urb failed\n"); + em28xx_deinit_isoc_audio(dev); + atomic_set(&dev->stream_started, 0); + return errCode; + } + + } + + return 0; +} + +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + dprintk("Allocating vbuffer\n"); + if (runtime->dma_area) { + if (runtime->dma_bytes > size) + return 0; + + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc(size); + if (!runtime->dma_area) + return -ENOMEM; + + runtime->dma_bytes = size; + + return 0; +} + +static struct snd_pcm_hardware snd_em28xx_hw_capture = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_MMAP_VALID, + + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, + + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ + .period_bytes_min = 64, /* 12544/2, */ + .period_bytes_max = 12544, + .periods_min = 2, + .periods_max = 98, /* 12544, */ +}; + +static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret = 0; + + dprintk("opening device and trying to acquire exclusive lock\n"); + + if (!dev) { + em28xx_err("BUG: em28xx can't find device struct." + " Can't proceed with open\n"); + return -ENODEV; + } + + runtime->hw = snd_em28xx_hw_capture; + if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) { + if (dev->audio_ifnum) + dev->alt = 1; + else + dev->alt = 7; + + dprintk("changing alternate number on interface %d to %d\n", + dev->audio_ifnum, dev->alt); + usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt); + + /* Sets volume, mute, etc */ + dev->mute = 0; + mutex_lock(&dev->lock); + ret = em28xx_audio_analog_set(dev); + if (ret < 0) + goto err; + + dev->adev.users++; + mutex_unlock(&dev->lock); + } + + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + dev->adev.capture_pcm_substream = substream; + runtime->private_data = dev; + + return 0; +err: + mutex_unlock(&dev->lock); + + em28xx_err("Error while configuring em28xx mixer\n"); + return ret; +} + +static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + + dprintk("closing device\n"); + + dev->mute = 1; + mutex_lock(&dev->lock); + dev->adev.users--; + if (atomic_read(&dev->stream_started) > 0) { + atomic_set(&dev->stream_started, 0); + schedule_work(&dev->wq_trigger); + } + + em28xx_audio_analog_set(dev); + if (substream->runtime->dma_area) { + dprintk("freeing\n"); + vfree(substream->runtime->dma_area); + substream->runtime->dma_area = NULL; + } + mutex_unlock(&dev->lock); + + return 0; +} + +static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + unsigned int channels, rate, format; + int ret; + + dprintk("Setting capture parameters\n"); + + ret = snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (ret < 0) + return ret; + format = params_format(hw_params); + rate = params_rate(hw_params); + channels = params_channels(hw_params); + + /* TODO: set up em28xx audio chip to deliver the correct audio format, + current default is 48000hz multiplexed => 96000hz mono + which shouldn't matter since analogue TV only supports mono */ + return 0; +} + +static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + + dprintk("Stop capture, if needed\n"); + + if (atomic_read(&dev->stream_started) > 0) { + atomic_set(&dev->stream_started, 0); + schedule_work(&dev->wq_trigger); + } + + return 0; +} + +static int snd_em28xx_prepare(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + + dev->adev.hwptr_done_capture = 0; + dev->adev.capture_transfer_done = 0; + + return 0; +} + +static void audio_trigger(struct work_struct *work) +{ + struct em28xx *dev = container_of(work, struct em28xx, wq_trigger); + + if (atomic_read(&dev->stream_started)) { + dprintk("starting capture"); + em28xx_init_audio_isoc(dev); + } else { + dprintk("stopping capture"); + em28xx_deinit_isoc_audio(dev); + } +} + +static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + int retval = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ + case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ + case SNDRV_PCM_TRIGGER_START: + atomic_set(&dev->stream_started, 1); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ + case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ + case SNDRV_PCM_TRIGGER_STOP: + atomic_set(&dev->stream_started, 0); + break; + default: + retval = -EINVAL; + } + schedule_work(&dev->wq_trigger); + return retval; +} + +static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream + *substream) +{ + unsigned long flags; + struct em28xx *dev; + snd_pcm_uframes_t hwptr_done; + + dev = snd_pcm_substream_chip(substream); + spin_lock_irqsave(&dev->adev.slock, flags); + hwptr_done = dev->adev.hwptr_done_capture; + spin_unlock_irqrestore(&dev->adev.slock, flags); + + return hwptr_done; +} + +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + + return vmalloc_to_page(pageptr); +} + +/* + * AC97 volume control support + */ +static int em28xx_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 0; + info->value.integer.max = 0x1f; + + return 0; +} + +static int em28xx_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) | + (0x1f - (value->value.integer.value[1] & 0x1f)) << 8; + int rc; + + mutex_lock(&dev->lock); + rc = em28xx_read_ac97(dev, kcontrol->private_value); + if (rc < 0) + goto err; + + val |= rc & 0x8000; /* Preserve the mute flag */ + + rc = em28xx_write_ac97(dev, kcontrol->private_value, val); + if (rc < 0) + goto err; + + dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + +err: + mutex_unlock(&dev->lock); + return rc; +} + +static int em28xx_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + int val; + + mutex_lock(&dev->lock); + val = em28xx_read_ac97(dev, kcontrol->private_value); + mutex_unlock(&dev->lock); + if (val < 0) + return val; + + dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + + value->value.integer.value[0] = 0x1f - (val & 0x1f); + value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f); + + return 0; +} + +static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + u16 val = value->value.integer.value[0]; + int rc; + + mutex_lock(&dev->lock); + rc = em28xx_read_ac97(dev, kcontrol->private_value); + if (rc < 0) + goto err; + + if (val) + rc &= 0x1f1f; + else + rc |= 0x8000; + + rc = em28xx_write_ac97(dev, kcontrol->private_value, rc); + if (rc < 0) + goto err; + + dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + +err: + mutex_unlock(&dev->lock); + return rc; +} + +static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + int val; + + mutex_lock(&dev->lock); + val = em28xx_read_ac97(dev, kcontrol->private_value); + mutex_unlock(&dev->lock); + if (val < 0) + return val; + + if (val & 0x8000) + value->value.integer.value[0] = 0; + else + value->value.integer.value[0] = 1; + + dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n", + (val & 0x8000) ? "muted " : "", + 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), + val, (int)kcontrol->private_value); + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0); + +static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev, + char *name, int id) +{ + int err; + char ctl_name[44]; + struct snd_kcontrol *kctl; + struct snd_kcontrol_new tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, + tmp.private_value = id, + tmp.name = ctl_name, + + /* Add Mute Control */ + sprintf(ctl_name, "%s Switch", name); + tmp.get = em28xx_vol_get_mute; + tmp.put = em28xx_vol_put_mute; + tmp.info = snd_ctl_boolean_mono_info; + kctl = snd_ctl_new1(&tmp, dev); + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; + dprintk("Added control %s for ac97 volume control 0x%04x\n", + ctl_name, id); + + memset (&tmp, 0, sizeof(tmp)); + tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, + tmp.private_value = id, + tmp.name = ctl_name, + + /* Add Volume Control */ + sprintf(ctl_name, "%s Volume", name); + tmp.get = em28xx_vol_get; + tmp.put = em28xx_vol_put; + tmp.info = em28xx_vol_info; + tmp.tlv.p = em28xx_db_scale, + kctl = snd_ctl_new1(&tmp, dev); + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; + dprintk("Added control %s for ac97 volume control 0x%04x\n", + ctl_name, id); + + return 0; +} + +/* + * register/unregister code and data + */ +static struct snd_pcm_ops snd_em28xx_pcm_capture = { + .open = snd_em28xx_capture_open, + .close = snd_em28xx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_em28xx_hw_capture_params, + .hw_free = snd_em28xx_hw_capture_free, + .prepare = snd_em28xx_prepare, + .trigger = snd_em28xx_capture_trigger, + .pointer = snd_em28xx_capture_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +static int em28xx_audio_init(struct em28xx *dev) +{ + struct em28xx_audio *adev = &dev->adev; + struct snd_pcm *pcm; + struct snd_card *card; + static int devnr; + int err; + + if (!dev->has_alsa_audio || dev->audio_ifnum < 0) { + /* This device does not support the extension (in this case + the device is expecting the snd-usb-audio module or + doesn't have analog audio support at all) */ + return 0; + } + + printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n"); + printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " + "Rechberger\n"); + printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n"); + + err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0, + &card); + if (err < 0) + return err; + + spin_lock_init(&adev->slock); + err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); + if (err < 0) { + snd_card_free(card); + return err; + } + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); + pcm->info_flags = 0; + pcm->private_data = dev; + strcpy(pcm->name, "Empia 28xx Capture"); + + snd_card_set_dev(card, &dev->udev->dev); + strcpy(card->driver, "Em28xx-Audio"); + strcpy(card->shortname, "Em28xx Audio"); + strcpy(card->longname, "Empia Em28xx Audio"); + + INIT_WORK(&dev->wq_trigger, audio_trigger); + + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + em28xx_cvol_new(card, dev, "Video", AC97_VIDEO_VOL); + em28xx_cvol_new(card, dev, "Line In", AC97_LINEIN_VOL); + em28xx_cvol_new(card, dev, "Phone", AC97_PHONE_VOL); + em28xx_cvol_new(card, dev, "Microphone", AC97_PHONE_VOL); + em28xx_cvol_new(card, dev, "CD", AC97_CD_VOL); + em28xx_cvol_new(card, dev, "AUX", AC97_AUX_VOL); + em28xx_cvol_new(card, dev, "PCM", AC97_PCM_OUT_VOL); + + em28xx_cvol_new(card, dev, "Master", AC97_MASTER_VOL); + em28xx_cvol_new(card, dev, "Line", AC97_LINE_LEVEL_VOL); + em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO_VOL); + em28xx_cvol_new(card, dev, "LFE", AC97_LFE_MASTER_VOL); + em28xx_cvol_new(card, dev, "Surround", AC97_SURR_MASTER_VOL); + } + + err = snd_card_register(card); + if (err < 0) { + snd_card_free(card); + return err; + } + adev->sndcard = card; + adev->udev = dev->udev; + + return 0; +} + +static int em28xx_audio_fini(struct em28xx *dev) +{ + if (dev == NULL) + return 0; + + if (dev->has_alsa_audio != 1) { + /* This device does not support the extension (in this case + the device is expecting the snd-usb-audio module or + doesn't have analog audio support at all) */ + return 0; + } + + if (dev->adev.sndcard) { + snd_card_free(dev->adev.sndcard); + dev->adev.sndcard = NULL; + } + + return 0; +} + +static struct em28xx_ops audio_ops = { + .id = EM28XX_AUDIO, + .name = "Em28xx Audio Extension", + .init = em28xx_audio_init, + .fini = em28xx_audio_fini, +}; + +static int __init em28xx_alsa_register(void) +{ + return em28xx_register_extension(&audio_ops); +} + +static void __exit em28xx_alsa_unregister(void) +{ + em28xx_unregister_extension(&audio_ops); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Markus Rechberger "); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_DESCRIPTION("Em28xx Audio driver"); + +module_init(em28xx_alsa_register); +module_exit(em28xx_alsa_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-cards.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,3278 @@ +/* + em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB + video capture devices + + Copyright (C) 2005 Ludovico Cavedon + Markus Rechberger + Mauro Carvalho Chehab + Sascha Sommer + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "em28xx.h" + +#define DRIVER_NAME "em28xx" + +static int tuner = -1; +module_param(tuner, int, 0444); +MODULE_PARM_DESC(tuner, "tuner type"); + +static unsigned int disable_ir; +module_param(disable_ir, int, 0444); +MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); + +static unsigned int disable_usb_speed_check; +module_param(disable_usb_speed_check, int, 0444); +MODULE_PARM_DESC(disable_usb_speed_check, + "override min bandwidth requirement of 480M bps"); + +static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); + +/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ +static unsigned long em28xx_devused; + +struct em28xx_hash_table { + unsigned long hash; + unsigned int model; + unsigned int tuner; +}; + +/* + * Reset sequences for analog/digital modes + */ + +/* Reset for the most [analog] boards */ +static struct em28xx_reg_seq default_analog[] = { + {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Reset for the most [digital] boards */ +static struct em28xx_reg_seq default_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Board Hauppauge WinTV HVR 900 analog */ +static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { + {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10}, + {0x05, 0xff, 0x10, 10}, + { -1, -1, -1, -1}, +}; + +/* Board Hauppauge WinTV HVR 900 digital */ +static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { + {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x04, 0x0f, 10}, + {EM2880_R04_GPO, 0x0c, 0x0f, 10}, + { -1, -1, -1, -1}, +}; + +/* Board Hauppauge WinTV HVR 900 (R2) digital */ +static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = { + {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x0c, 0x0f, 10}, + { -1, -1, -1, -1}, +}; + +/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ +static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { + {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ + +/* Board - EM2870 Kworld 355u + Analog - No input analog */ + +/* Board - EM2882 Kworld 315U digital */ +static struct em28xx_reg_seq em2882_kworld_315u_digital[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM28XX_R08_GPIO, 0xfe, 0xff, 10}, + {EM2880_R04_GPO, 0x04, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 10}, + {EM28XX_R08_GPIO, 0x7e, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { + {EM2880_R04_GPO, 0x08, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 10}, + {EM2880_R04_GPO, 0x08, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq kworld_330u_analog[] = { + {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x00, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq kworld_330u_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x08, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +/* Evga inDtube + GPIO0 - Enable digital power (s5h1409) - low to enable + GPIO1 - Enable analog power (tvp5150/emp202) - low to enable + GPIO4 - xc3028 reset + GOP3 - s5h1409 reset + */ +static struct em28xx_reg_seq evga_indtube_analog[] = { + {EM28XX_R08_GPIO, 0x79, 0xff, 60}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq evga_indtube_digital[] = { + {EM28XX_R08_GPIO, 0x7a, 0xff, 1}, + {EM2880_R04_GPO, 0x04, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 1}, + { -1, -1, -1, -1}, +}; + +/* + * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map: + * EM_GPIO_0 - currently unknown + * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on) + * EM_GPIO_2 - currently unknown + * EM_GPIO_3 - currently unknown + * EM_GPIO_4 - TDA18271HD/C1 tuner (1 = active, 0 = in reset) + * EM_GPIO_5 - LGDT3304 ATSC/QAM demod (1 = active, 0 = in reset) + * EM_GPIO_6 - currently unknown + * EM_GPIO_7 - currently unknown + */ +static struct em28xx_reg_seq kworld_a340_digital[] = { + {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Pinnacle Hybrid Pro eb1a:2881 */ +static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = { + {EM28XX_R08_GPIO, 0xfd, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x04, 0xff, 100},/* zl10353 reset */ + {EM2880_R04_GPO, 0x0c, 0xff, 1}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = { + {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x00, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x08, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +/* eb1a:2868 Reddo DVB-C USB TV Box + GPIO4 - CU1216L NIM + Other GPIOs seems to be don't care. */ +static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { + {EM28XX_R08_GPIO, 0xfe, 0xff, 10}, + {EM28XX_R08_GPIO, 0xde, 0xff, 10}, + {EM28XX_R08_GPIO, 0xfe, 0xff, 10}, + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM28XX_R08_GPIO, 0x7f, 0xff, 10}, + {EM28XX_R08_GPIO, 0x6f, 0xff, 10}, + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {-1, -1, -1, -1}, +}; + +/* Callback for the most boards */ +static struct em28xx_reg_seq default_tuner_gpio[] = { + {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, + {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10}, + {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Mute/unmute */ +static struct em28xx_reg_seq compro_unmute_tv_gpio[] = { + {EM28XX_R08_GPIO, 5, 7, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq compro_unmute_svid_gpio[] = { + {EM28XX_R08_GPIO, 4, 7, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq compro_mute_gpio[] = { + {EM28XX_R08_GPIO, 6, 7, 10}, + { -1, -1, -1, -1}, +}; + +/* Terratec AV350 */ +static struct em28xx_reg_seq terratec_av350_mute_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0x7f, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq silvercrest_reg_seq[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM28XX_R08_GPIO, 0x01, 0xf7, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq vc211a_enable[] = { + {EM28XX_R08_GPIO, 0xff, 0x07, 10}, + {EM28XX_R08_GPIO, 0xff, 0x0f, 10}, + {EM28XX_R08_GPIO, 0xff, 0x0b, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq dikom_dk300_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x08, 0xff, 10}, + { -1, -1, -1, -1}, +}; + + +/* Reset for the most [digital] boards */ +static struct em28xx_reg_seq leadership_digital[] = { + {EM2874_R80_GPIO, 0x70, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq leadership_reset[] = { + {EM2874_R80_GPIO, 0xf0, 0xff, 10}, + {EM2874_R80_GPIO, 0xb0, 0xff, 10}, + {EM2874_R80_GPIO, 0xf0, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +/* 2013:024f PCTV nanoStick T2 290e + * GPIO_6 - demod reset + * GPIO_7 - LED + */ +static struct em28xx_reg_seq pctv_290e[] = { + {EM2874_R80_GPIO, 0x00, 0xff, 80}, + {EM2874_R80_GPIO, 0x40, 0xff, 80}, /* GPIO_6 = 1 */ + {EM2874_R80_GPIO, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */ + {-1, -1, -1, -1}, +}; + +/* + * Board definitions + */ +struct em28xx_board em28xx_boards[] = { + [EM2750_BOARD_UNKNOWN] = { + .name = "EM2710/EM2750/EM2751 webcam grabber", + .xclk = EM28XX_XCLK_FREQUENCY_20MHZ, + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = silvercrest_reg_seq, + } }, + }, + [EM2800_BOARD_UNKNOWN] = { + .name = "Unknown EM2800 video grabber", + .is_em2800 = 1, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .tuner_type = TUNER_ABSENT, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_UNKNOWN] = { + .name = "Unknown EM2750/28xx video grabber", + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, /* To enable sensor probe */ + }, + [EM2750_BOARD_DLCW_130] = { + /* Beijing Huaqi Information Digital Technology Co., Ltd */ + .name = "Huaqi DLCW-130", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .xclk = EM28XX_XCLK_FREQUENCY_48MHZ, + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = EM28XX_AMUX_VIDEO, + } }, + }, + [EM2820_BOARD_KWORLD_PVRTV2800RF] = { + .name = "Kworld PVR TV 2800 RF", + .tuner_type = TUNER_TEMIC_PAL, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_GADMEI_TVR200] = { + .name = "Gadmei TVR200", + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_TERRATEC_CINERGY_250] = { + .name = "Terratec Cinergy 250 USB", + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .has_ir_i2c = 1, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_PINNACLE_USB_2] = { + .name = "Pinnacle PCTV USB 2", + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .has_ir_i2c = 1, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = { + .name = "Hauppauge WinTV USB 2", + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .decoder = EM28XX_TVP5150, + .has_msp34xx = 1, + .has_ir_i2c = 1, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = MSP_INPUT_DEFAULT, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), + } }, + }, + [EM2820_BOARD_DLINK_USB_TV] = { + .name = "D-Link DUB-T210 TV Tuner", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_HERCULES_SMART_TV_USB2] = { + .name = "Hercules Smart TV USB 2.0", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = { + .name = "Pinnacle PCTV USB 2 (Philips FM1216ME)", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_GADMEI_UTV310] = { + .name = "Gadmei UTV310", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_TNF_5335MF, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = { + .name = "Leadtek Winfast USB II Deluxe", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .has_ir_i2c = 1, + .tvaudio_addr = 0x58, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT2_ACTIVE | + TDA9887_QSS, + .decoder = EM28XX_SAA711X, + .adecoder = EM28XX_TVAUDIO, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE4, + .amux = EM28XX_AMUX_AUX, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE5, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + .radio = { + .type = EM28XX_RADIO, + .amux = EM28XX_AMUX_AUX, + } + }, + [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { + .name = "Videology 20K14XUSB USB2.0", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = EM28XX_AMUX_VIDEO, + } }, + }, + [EM2820_BOARD_SILVERCREST_WEBCAM] = { + .name = "Silvercrest Webcam 1.3mpix", + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = silvercrest_reg_seq, + } }, + }, + [EM2821_BOARD_SUPERCOMP_USB_2] = { + .name = "Supercomp USB 2.0 TV", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2821_BOARD_USBGEAR_VD204] = { + .name = "Usbgear VD204v9", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* Capture only device */ + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2860_BOARD_NETGMBH_CAM] = { + /* Beijing Huaqi Information Digital Technology Co., Ltd */ + .name = "NetGMBH Cam", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = EM28XX_AMUX_VIDEO, + } }, + }, + [EM2860_BOARD_TYPHOON_DVD_MAKER] = { + .name = "Typhoon DVD Maker", + .decoder = EM28XX_SAA711X, + .tuner_type = TUNER_ABSENT, /* Capture only device */ + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2860_BOARD_GADMEI_UTV330] = { + .name = "Gadmei UTV330", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_TNF_5335MF, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2861_BOARD_GADMEI_UTV330PLUS] = { + .name = "Gadmei UTV330+", + .tuner_type = TUNER_TNF_5335MF, + .tda9887_conf = TDA9887_PRESENT, + .ir_codes = RC_MAP_GADMEI_RM008Z, + .decoder = EM28XX_SAA711X, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2860_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Cinergy A Hybrid XS", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2861_BOARD_KWORLD_PVRTV_300U] = { + .name = "KWorld PVRTV 300U", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = { + .name = "Yakumo MovieMixer", + .tuner_type = TUNER_ABSENT, /* Capture only device */ + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2860_BOARD_TVP5150_REFERENCE_DESIGN] = { + .name = "EM2860/TVP5150 Reference Design", + .tuner_type = TUNER_ABSENT, /* Capture only device */ + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2861_BOARD_PLEXTOR_PX_TV100U] = { + .name = "Plextor ConvertX PX-TV100U", + .tuner_type = TUNER_TNF_5335MF, + .xclk = EM28XX_XCLK_I2S_MSB_TIMING | + EM28XX_XCLK_FREQUENCY_12MHZ, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_TVP5150, + .has_msp34xx = 1, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = pinnacle_hybrid_pro_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = pinnacle_hybrid_pro_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = pinnacle_hybrid_pro_analog, + } }, + }, + + /* Those boards with em2870 are DVB Only*/ + + [EM2870_BOARD_TERRATEC_XS] = { + .name = "Terratec Cinergy T XS", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + }, + [EM2870_BOARD_TERRATEC_XS_MT2060] = { + .name = "Terratec Cinergy T XS (MT2060)", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* MT2060 */ + }, + [EM2870_BOARD_KWORLD_350U] = { + .name = "Kworld 350 U DVB-T", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + }, + [EM2870_BOARD_KWORLD_355U] = { + .name = "Kworld 355 U DVB-T", + .valid = EM28XX_BOARD_NOT_VALIDATED, + }, + [EM2870_BOARD_PINNACLE_PCTV_DVB] = { + .name = "Pinnacle PCTV DVB-T", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* MT2060 */ + /* djh - I have serious doubts this is right... */ + .xclk = EM28XX_XCLK_IR_RC5_MODE | + EM28XX_XCLK_FREQUENCY_10MHZ, + }, + [EM2870_BOARD_COMPRO_VIDEOMATE] = { + .name = "Compro, VideoMate U3", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* MT2060 */ + }, + + [EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = { + .name = "Terratec Hybrid XS Secam", + .has_msp34xx = 1, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .has_dvb = 1, + .dvb_gpio = terratec_cinergy_USB_XS_FR_digital, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = terratec_cinergy_USB_XS_FR_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = terratec_cinergy_USB_XS_FR_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = terratec_cinergy_USB_XS_FR_analog, + } }, + }, + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { + .name = "Hauppauge WinTV HVR 900", + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, + .ir_codes = RC_MAP_HAUPPAUGE, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = { + .name = "Hauppauge WinTV HVR 900 (R2)", + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900R2_digital, + .ir_codes = RC_MAP_HAUPPAUGE, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850] = { + .name = "Hauppauge WinTV HVR 850", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, + .ir_codes = RC_MAP_HAUPPAUGE, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { + .name = "Hauppauge WinTV HVR 950", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, + .ir_codes = RC_MAP_HAUPPAUGE, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { + .name = "Pinnacle PCTV HD Pro Stick", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { + .name = "AMD ATI TV Wonder HD 600", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, + .ir_codes = RC_MAP_ATI_TV_WONDER_HD_600, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2880_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Hybrid XS", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .has_dvb = 1, + .dvb_gpio = default_digital, + .ir_codes = RC_MAP_TERRATEC_CINERGY_XS, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */ + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + } }, + }, + /* maybe there's a reason behind it why Terratec sells the Hybrid XS + as Prodigy XS with a different PID, let's keep it separated for now + maybe we'll need it lateron */ + [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { + .name = "Terratec Prodigy XS", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2820_BOARD_MSI_VOX_USB_2] = { + .name = "MSI VOX USB 2.0", + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .max_range_640_480 = 1, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE4, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2800_BOARD_TERRATEC_CINERGY_200] = { + .name = "Terratec Cinergy 200 USB", + .is_em2800 = 1, + .has_ir_i2c = 1, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2800_BOARD_GRABBEEX_USB2800] = { + .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder", + .is_em2800 = 1, + .decoder = EM28XX_SAA711X, + .tuner_type = TUNER_ABSENT, /* capture only board */ + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2800_BOARD_VC211A] = { + .name = "Actionmaster/LinXcel/Digitus VC211A", + .is_em2800 = 1, + .tuner_type = TUNER_ABSENT, /* Capture-only board */ + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = vc211a_enable, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = vc211a_enable, + } }, + }, + [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { + .name = "Leadtek Winfast USB II", + .is_em2800 = 1, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2800_BOARD_KWORLD_USB2800] = { + .name = "Kworld USB2800", + .is_em2800 = 1, + .tuner_type = TUNER_PHILIPS_FCV1236D, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_PINNACLE_DVC_90] = { + .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker " + "/ Kworld DVD Maker 2", + .tuner_type = TUNER_ABSENT, /* capture only board */ + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2800_BOARD_VGEAR_POCKETTV] = { + .name = "V-Gear PocketTV", + .is_em2800 = 1, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2] = { + .name = "Pixelview PlayTV Box 4 USB 2.0", + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_YMEC_TVF_5533MF, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + .aout = EM28XX_AOUT_MONO | /* I2S */ + EM28XX_AOUT_MASTER, /* Line out pin */ + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { + .name = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0", + .has_snapshot_button = 1, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_YMEC_TVF_5533MF, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + .aout = EM28XX_AOUT_MONO | /* I2S */ + EM28XX_AOUT_MASTER, /* Line out pin */ + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = { + .name = "EM2860/SAA711X Reference Design", + .has_snapshot_button = 1, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + } }, + }, + + [EM2874_BOARD_LEADERSHIP_ISDBT] = { + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ, + .xclk = EM28XX_XCLK_FREQUENCY_10MHZ, + .name = "EM2874 Leadership ISDBT", + .tuner_type = TUNER_ABSENT, + .tuner_gpio = leadership_reset, + .dvb_gpio = leadership_digital, + .has_dvb = 1, + }, + + [EM2880_BOARD_MSI_DIGIVOX_AD] = { + .name = "MSI DigiVox A/D", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = em2880_msi_digivox_ad_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2880_msi_digivox_ad_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2880_msi_digivox_ad_analog, + } }, + }, + [EM2880_BOARD_MSI_DIGIVOX_AD_II] = { + .name = "MSI DigiVox A/D II", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = em2880_msi_digivox_ad_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2880_msi_digivox_ad_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2880_msi_digivox_ad_analog, + } }, + }, + [EM2880_BOARD_KWORLD_DVB_305U] = { + .name = "KWorld DVB-T 305U", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2880_BOARD_KWORLD_DVB_310U] = { + .name = "KWorld DVB-T 310U", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .has_dvb = 1, + .dvb_gpio = default_digital, + .mts_firmware = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + }, { /* S-video has not been tested yet */ + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + } }, + }, + [EM2882_BOARD_KWORLD_ATSC_315U] = { + .name = "KWorld ATSC 315U HDTV TV Box", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_THOMSON_DTT761X, + .tuner_gpio = em2882_kworld_315u_tuner_gpio, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .has_dvb = 1, + .dvb_gpio = em2882_kworld_315u_digital, + .ir_codes = RC_MAP_KWORLD_315U, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE, + /* Analog mode - still not ready */ + /*.input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + .gpio = em2882_kworld_315u_analog, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2882_kworld_315u_analog1, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2882_kworld_315u_analog1, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, + } }, */ + }, + [EM2880_BOARD_EMPIRE_DUAL_TV] = { + .name = "Empire dual TV", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .has_dvb = 1, + .dvb_gpio = default_digital, + .mts_firmware = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + } }, + }, + [EM2881_BOARD_DNT_DA2_HYBRID] = { + .name = "DNT DA2 Hybrid", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + } }, + }, + [EM2881_BOARD_PINNACLE_HYBRID_PRO] = { + .name = "Pinnacle Hybrid Pro", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .has_dvb = 1, + .dvb_gpio = pinnacle_hybrid_pro_digital, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = pinnacle_hybrid_pro_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = pinnacle_hybrid_pro_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = pinnacle_hybrid_pro_analog, + } }, + }, + [EM2882_BOARD_PINNACLE_HYBRID_PRO_330E] = { + .name = "Pinnacle Hybrid Pro (330e)", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900R2_digital, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2882_BOARD_KWORLD_VS_DVBT] = { + .name = "Kworld VS-DVB-T 323UR", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = kworld_330u_digital, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */ + .ir_codes = RC_MAP_KWORLD_315U, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2882_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Cinnergy Hybrid T USB XS (em2882)", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .mts_firmware = 1, + .decoder = EM28XX_TVP5150, + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, + .ir_codes = RC_MAP_TERRATEC_CINERGY_XS, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, + [EM2882_BOARD_DIKOM_DK300] = { + .name = "Dikom DK300", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = dikom_dk300_digital, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, + } }, + }, + [EM2883_BOARD_KWORLD_HYBRID_330U] = { + .name = "Kworld PlusTV HD Hybrid 330", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = kworld_330u_digital, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_EEPROM_ON_BOARD | + EM28XX_I2C_EEPROM_KEY_VALID, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = kworld_330u_analog, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = kworld_330u_analog, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = kworld_330u_analog, + } }, + }, + [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { + .name = "Compro VideoMate ForYou/Stereo", + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tvaudio_addr = 0xb0, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_TVP5150, + .adecoder = EM28XX_TVAUDIO, + .mute_gpio = compro_mute_gpio, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = compro_unmute_tv_gpio, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = compro_unmute_svid_gpio, + } }, + }, + [EM2860_BOARD_KAIOMY_TVNPC_U2] = { + .name = "Kaiomy TVnPC U2", + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .mts_firmware = 1, + .decoder = EM28XX_TVP5150, + .tuner_gpio = default_tuner_gpio, + .ir_codes = RC_MAP_KAIOMY, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + .radio = { + .type = EM28XX_RADIO, + .amux = EM28XX_AMUX_LINE_IN, + } + }, + [EM2860_BOARD_EASYCAP] = { + .name = "Easy Cap Capture DC-60", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2820_BOARD_IODATA_GVMVP_SZ] = { + .name = "IO-DATA GV-MVP/SZ", + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .tuner_gpio = default_tuner_gpio, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + }, { /* Composite has not been tested yet */ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_VIDEO, + }, { /* S-video has not been tested yet */ + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_VIDEO, + } }, + }, + [EM2860_BOARD_TERRATEC_GRABBY] = { + .name = "Terratec Grabby", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA711X, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2860_BOARD_TERRATEC_AV350] = { + .name = "Terratec AV350", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_TVP5150, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .mute_gpio = terratec_av350_mute_gpio, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AUDIO_SRC_LINE, + .gpio = terratec_av350_unmute_gpio, + + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AUDIO_SRC_LINE, + .gpio = terratec_av350_unmute_gpio, + } }, + }, + + [EM2860_BOARD_ELGATO_VIDEO_CAPTURE] = { + .name = "Elgato Video Capture", + .decoder = EM28XX_SAA711X, + .tuner_type = TUNER_ABSENT, /* Capture only device */ + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + + [EM2882_BOARD_EVGA_INDTUBE] = { + .name = "Evga inDtube", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */ + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = evga_indtube_digital, + .ir_codes = RC_MAP_EVGA_INDTUBE, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = evga_indtube_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = evga_indtube_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = evga_indtube_analog, + } }, + }, + /* eb1a:2868 Empia EM2870 + Philips CU1216L NIM (Philips TDA10023 + + Infineon TUA6034) */ + [EM2870_BOARD_REDDO_DVB_C_USB_BOX] = { + .name = "Reddo DVB-C USB TV Box", + .tuner_type = TUNER_ABSENT, + .tuner_gpio = reddo_dvb_c_usb_box, + .has_dvb = 1, + }, + /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold + * initially as the KWorld PlusTV 340U, then as the UB435-Q. + * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */ + [EM2870_BOARD_KWORLD_A340] = { + .name = "KWorld PlusTV 340U or UB435-Q (ATSC)", + .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */ + .has_dvb = 1, + .dvb_gpio = kworld_a340_digital, + .tuner_gpio = default_tuner_gpio, + }, + /* 2013:024f PCTV nanoStick T2 290e. + * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */ + [EM28174_BOARD_PCTV_290E] = { + .name = "PCTV nanoStick T2 290e", + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, + .tuner_type = TUNER_ABSENT, + .tuner_gpio = pctv_290e, + .has_dvb = 1, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + }, +}; +const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); + +/* table of devices that work with this driver */ +struct usb_device_id em28xx_id_table[] = { + { USB_DEVICE(0xeb1a, 0x2750), + .driver_info = EM2750_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2751), + .driver_info = EM2750_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2800), + .driver_info = EM2800_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2710), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2820), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2821), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2860), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2861), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2862), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2863), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2870), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2881), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2883), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2868), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2875), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0xe300), + .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U }, + { USB_DEVICE(0xeb1a, 0xe303), + .driver_info = EM2860_BOARD_KAIOMY_TVNPC_U2 }, + { USB_DEVICE(0xeb1a, 0xe305), + .driver_info = EM2880_BOARD_KWORLD_DVB_305U }, + { USB_DEVICE(0xeb1a, 0xe310), + .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD }, + { USB_DEVICE(0xeb1a, 0xa313), + .driver_info = EM2882_BOARD_KWORLD_ATSC_315U }, + { USB_DEVICE(0xeb1a, 0xa316), + .driver_info = EM2883_BOARD_KWORLD_HYBRID_330U }, + { USB_DEVICE(0xeb1a, 0xe320), + .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD_II }, + { USB_DEVICE(0xeb1a, 0xe323), + .driver_info = EM2882_BOARD_KWORLD_VS_DVBT }, + { USB_DEVICE(0xeb1a, 0xe350), + .driver_info = EM2870_BOARD_KWORLD_350U }, + { USB_DEVICE(0xeb1a, 0xe355), + .driver_info = EM2870_BOARD_KWORLD_355U }, + { USB_DEVICE(0xeb1a, 0x2801), + .driver_info = EM2800_BOARD_GRABBEEX_USB2800 }, + { USB_DEVICE(0xeb1a, 0xe357), + .driver_info = EM2870_BOARD_KWORLD_355U }, + { USB_DEVICE(0x1b80, 0xe302), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */ + { USB_DEVICE(0x1b80, 0xe304), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kworld DVD Maker 2 */ + { USB_DEVICE(0x0ccd, 0x0036), + .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, + { USB_DEVICE(0x0ccd, 0x004c), + .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS_FR }, + { USB_DEVICE(0x0ccd, 0x004f), + .driver_info = EM2860_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x005e), + .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x0042), + .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x0043), + .driver_info = EM2870_BOARD_TERRATEC_XS }, + { USB_DEVICE(0x0ccd, 0x0047), + .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + { USB_DEVICE(0x0ccd, 0x0084), + .driver_info = EM2860_BOARD_TERRATEC_AV350 }, + { USB_DEVICE(0x0ccd, 0x0096), + .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, + { USB_DEVICE(0x0fd9, 0x0033), + .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, + { USB_DEVICE(0x185b, 0x2870), + .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, + { USB_DEVICE(0x185b, 0x2041), + .driver_info = EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU }, + { USB_DEVICE(0x2040, 0x4200), + .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, + { USB_DEVICE(0x2040, 0x4201), + .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, + { USB_DEVICE(0x2040, 0x6500), + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + { USB_DEVICE(0x2040, 0x6502), + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 }, + { USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */ + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */ + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */ + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x2040, 0x651f), + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, + { USB_DEVICE(0x0438, 0xb002), + .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, + { USB_DEVICE(0x2001, 0xf112), + .driver_info = EM2820_BOARD_DLINK_USB_TV }, + { USB_DEVICE(0x2304, 0x0207), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2304, 0x0208), + .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, + { USB_DEVICE(0x2304, 0x021a), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2304, 0x0226), + .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E }, + { USB_DEVICE(0x2304, 0x0227), + .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, + { USB_DEVICE(0x0413, 0x6023), + .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, + { USB_DEVICE(0x093b, 0xa005), + .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U }, + { USB_DEVICE(0x04bb, 0x0515), + .driver_info = EM2820_BOARD_IODATA_GVMVP_SZ }, + { USB_DEVICE(0xeb1a, 0x50a6), + .driver_info = EM2860_BOARD_GADMEI_UTV330 }, + { USB_DEVICE(0x1b80, 0xa340), + .driver_info = EM2870_BOARD_KWORLD_A340 }, + { USB_DEVICE(0x2013, 0x024f), + .driver_info = EM28174_BOARD_PCTV_290E }, + { }, +}; +MODULE_DEVICE_TABLE(usb, em28xx_id_table); + +/* + * EEPROM hash table for devices with generic USB IDs + */ +static struct em28xx_hash_table em28xx_eeprom_hash[] = { + /* P/N: SA 60002070465 Tuner: TVF7533-MF */ + {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, + {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF}, + {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028}, + {0x166a0441, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028}, + {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028}, + {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028}, + {0x63f653bd, EM2870_BOARD_REDDO_DVB_C_USB_BOX, TUNER_ABSENT}, + {0x4e913442, EM2882_BOARD_DIKOM_DK300, TUNER_XC2028}, +}; + +/* I2C devicelist hash table for devices with generic USB IDs */ +static struct em28xx_hash_table em28xx_i2c_hash[] = { + {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, + {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, + {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT}, + {0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT}, + {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC}, + {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF}, + {0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT}, +}; + +/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ +static unsigned short saa711x_addrs[] = { + 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ + 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ + I2C_CLIENT_END }; + +static unsigned short tvp5150_addrs[] = { + 0xb8 >> 1, + 0xba >> 1, + I2C_CLIENT_END +}; + +static unsigned short msp3400_addrs[] = { + 0x80 >> 1, + 0x88 >> 1, + I2C_CLIENT_END +}; + +int em28xx_tuner_callback(void *ptr, int component, int command, int arg) +{ + int rc = 0; + struct em28xx *dev = ptr; + + if (dev->tuner_type != TUNER_XC2028) + return 0; + + if (command != XC2028_TUNER_RESET) + return 0; + + rc = em28xx_gpio_set(dev, dev->board.tuner_gpio); + + return rc; +} +EXPORT_SYMBOL_GPL(em28xx_tuner_callback); + +static inline void em28xx_set_model(struct em28xx *dev) +{ + memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board)); + + /* Those are the default values for the majority of boards + Use those values if not specified otherwise at boards entry + */ + if (!dev->board.xclk) + dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE | + EM28XX_XCLK_FREQUENCY_12MHZ; + + if (!dev->board.i2c_speed) + dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ; +} + + +/* FIXME: Should be replaced by a proper mt9m111 driver */ +static int em28xx_initialize_mt9m111(struct em28xx *dev) +{ + int i; + unsigned char regs[][3] = { + { 0x0d, 0x00, 0x01, }, /* reset and use defaults */ + { 0x0d, 0x00, 0x00, }, + { 0x0a, 0x00, 0x21, }, + { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */ + }; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client, ®s[i][0], 3); + + return 0; +} + + +/* FIXME: Should be replaced by a proper mt9m001 driver */ +static int em28xx_initialize_mt9m001(struct em28xx *dev) +{ + int i; + unsigned char regs[][3] = { + { 0x0d, 0x00, 0x01, }, + { 0x0d, 0x00, 0x00, }, + { 0x04, 0x05, 0x00, }, /* hres = 1280 */ + { 0x03, 0x04, 0x00, }, /* vres = 1024 */ + { 0x20, 0x11, 0x00, }, + { 0x06, 0x00, 0x10, }, + { 0x2b, 0x00, 0x24, }, + { 0x2e, 0x00, 0x24, }, + { 0x35, 0x00, 0x24, }, + { 0x2d, 0x00, 0x20, }, + { 0x2c, 0x00, 0x20, }, + { 0x09, 0x0a, 0xd4, }, + { 0x35, 0x00, 0x57, }, + }; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client, ®s[i][0], 3); + + return 0; +} + +/* HINT method: webcam I2C chips + * + * This method works for webcams with Micron sensors + */ +static int em28xx_hint_sensor(struct em28xx *dev) +{ + int rc; + char *sensor_name; + unsigned char cmd; + __be16 version_be; + u16 version; + + /* Micron sensor detection */ + dev->i2c_client.addr = 0xba >> 1; + cmd = 0; + i2c_master_send(&dev->i2c_client, &cmd, 1); + rc = i2c_master_recv(&dev->i2c_client, (char *)&version_be, 2); + if (rc != 2) + return -EINVAL; + + version = be16_to_cpu(version_be); + switch (version) { + case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */ + case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ + dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; + em28xx_set_model(dev); + + sensor_name = "mt9v011"; + dev->em28xx_sensor = EM28XX_MT9V011; + dev->sensor_xres = 640; + dev->sensor_yres = 480; + /* + * FIXME: mt9v011 uses I2S speed as xtal clk - at least with + * the Silvercrest cam I have here for testing - for higher + * resolutions, a high clock cause horizontal artifacts, so we + * need to use a lower xclk frequency. + * Yet, it would be possible to adjust xclk depending on the + * desired resolution, since this affects directly the + * frame rate. + */ + dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; + dev->sensor_xtal = 4300000; + + /* probably means GRGB 16 bit bayer */ + dev->vinmode = 0x0d; + dev->vinctl = 0x00; + + break; + + case 0x143a: /* MT9M111 as found in the ECS G200 */ + dev->model = EM2750_BOARD_UNKNOWN; + em28xx_set_model(dev); + + sensor_name = "mt9m111"; + dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; + dev->em28xx_sensor = EM28XX_MT9M111; + em28xx_initialize_mt9m111(dev); + dev->sensor_xres = 640; + dev->sensor_yres = 512; + + dev->vinmode = 0x0a; + dev->vinctl = 0x00; + + break; + + case 0x8431: + dev->model = EM2750_BOARD_UNKNOWN; + em28xx_set_model(dev); + + sensor_name = "mt9m001"; + dev->em28xx_sensor = EM28XX_MT9M001; + em28xx_initialize_mt9m001(dev); + dev->sensor_xres = 1280; + dev->sensor_yres = 1024; + + /* probably means BGGR 16 bit bayer */ + dev->vinmode = 0x0c; + dev->vinctl = 0x00; + + break; + default: + printk("Unknown Micron Sensor 0x%04x\n", version); + return -EINVAL; + } + + /* Setup webcam defaults */ + em28xx_pre_card_setup(dev); + + em28xx_errdev("Sensor is %s, using model %s entry.\n", + sensor_name, em28xx_boards[dev->model].name); + + return 0; +} + +/* Since em28xx_pre_card_setup() requires a proper dev->model, + * this won't work for boards with generic PCI IDs + */ +void em28xx_pre_card_setup(struct em28xx *dev) +{ + /* Set the initial XCLK and I2C clock values based on the board + definition */ + em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); + msleep(50); + + /* request some modules */ + switch (dev->model) { + case EM2861_BOARD_PLEXTOR_PX_TV100U: + /* Sets the msp34xx I2S speed */ + dev->i2s_speed = 2048000; + break; + case EM2861_BOARD_KWORLD_PVRTV_300U: + case EM2880_BOARD_KWORLD_DVB_305U: + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x6d); + msleep(10); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x7d); + msleep(10); + break; + case EM2870_BOARD_COMPRO_VIDEOMATE: + /* TODO: someone can do some cleanup here... + not everything's needed */ + em28xx_write_reg(dev, EM2880_R04_GPO, 0x00); + msleep(10); + em28xx_write_reg(dev, EM2880_R04_GPO, 0x01); + msleep(10); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); + mdelay(70); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc); + mdelay(70); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xdc); + mdelay(70); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc); + mdelay(70); + break; + case EM2870_BOARD_TERRATEC_XS_MT2060: + /* this device needs some gpio writes to get the DVB-T + demod work */ + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); + mdelay(70); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde); + mdelay(70); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); + mdelay(70); + break; + case EM2870_BOARD_PINNACLE_PCTV_DVB: + /* this device needs some gpio writes to get the + DVB-T demod work */ + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); + mdelay(70); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde); + mdelay(70); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); + mdelay(70); + break; + case EM2820_BOARD_GADMEI_UTV310: + case EM2820_BOARD_MSI_VOX_USB_2: + /* enables audio for that devices */ + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); + break; + + case EM2882_BOARD_KWORLD_ATSC_315U: + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); + msleep(10); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); + msleep(10); + em28xx_write_reg(dev, EM2880_R04_GPO, 0x00); + msleep(10); + em28xx_write_reg(dev, EM2880_R04_GPO, 0x08); + msleep(10); + break; + + case EM2860_BOARD_KAIOMY_TVNPC_U2: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + em28xx_write_regs(dev, 0x0d, "\x42", 1); + em28xx_write_regs(dev, 0x08, "\xfd", 1); + msleep(10); + em28xx_write_regs(dev, 0x08, "\xff", 1); + msleep(10); + em28xx_write_regs(dev, 0x08, "\x7f", 1); + msleep(10); + em28xx_write_regs(dev, 0x08, "\x6b", 1); + + break; + case EM2860_BOARD_EASYCAP: + em28xx_write_regs(dev, 0x08, "\xf8", 1); + break; + + case EM2820_BOARD_IODATA_GVMVP_SZ: + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); + msleep(70); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); + msleep(10); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); + msleep(70); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); + msleep(70); + break; + } + + em28xx_gpio_set(dev, dev->board.tuner_gpio); + em28xx_set_mode(dev, EM28XX_ANALOG_MODE); + + /* Unlock device */ + em28xx_set_mode(dev, EM28XX_SUSPEND); +} + +static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) +{ + memset(ctl, 0, sizeof(*ctl)); + + ctl->fname = XC2028_DEFAULT_FIRMWARE; + ctl->max_len = 64; + ctl->mts = em28xx_boards[dev->model].mts_firmware; + + switch (dev->model) { + case EM2880_BOARD_EMPIRE_DUAL_TV: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2882_BOARD_TERRATEC_HYBRID_XS: + ctl->demod = XC3028_FE_ZARLINK456; + break; + case EM2880_BOARD_TERRATEC_HYBRID_XS: + case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: + case EM2881_BOARD_PINNACLE_HYBRID_PRO: + ctl->demod = XC3028_FE_ZARLINK456; + break; + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: + case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: + ctl->demod = XC3028_FE_DEFAULT; + break; + case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: + ctl->demod = XC3028_FE_DEFAULT; + ctl->fname = XC3028L_DEFAULT_FIRMWARE; + break; + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + /* FIXME: Better to specify the needed IF */ + ctl->demod = XC3028_FE_DEFAULT; + break; + case EM2883_BOARD_KWORLD_HYBRID_330U: + case EM2882_BOARD_DIKOM_DK300: + case EM2882_BOARD_KWORLD_VS_DVBT: + ctl->demod = XC3028_FE_CHINA; + ctl->fname = XC2028_DEFAULT_FIRMWARE; + break; + case EM2882_BOARD_EVGA_INDTUBE: + ctl->demod = XC3028_FE_CHINA; + ctl->fname = XC3028L_DEFAULT_FIRMWARE; + break; + default: + ctl->demod = XC3028_FE_OREN538; + } +} + +static void em28xx_tuner_setup(struct em28xx *dev) +{ + struct tuner_setup tun_setup; + struct v4l2_frequency f; + + if (dev->tuner_type == TUNER_ABSENT) + return; + + memset(&tun_setup, 0, sizeof(tun_setup)); + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.tuner_callback = em28xx_tuner_callback; + + if (dev->board.radio.type) { + tun_setup.type = dev->board.radio.type; + tun_setup.addr = dev->board.radio_addr; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); + } + + if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); + } + + if (dev->tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg); + } + + if (dev->tuner_type == TUNER_XC2028) { + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + + memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); + memset(&ctl, 0, sizeof(ctl)); + + em28xx_setup_xc3028(dev, &ctl); + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg); + } + + /* configure tuner */ + f.tuner = 0; + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = 9076; /* just a magic number */ + dev->ctl_freq = f.frequency; + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); +} + +static int em28xx_hint_board(struct em28xx *dev) +{ + int i; + + /* HINT method: EEPROM + * + * This method works only for boards with eeprom. + * Uses a hash of all eeprom bytes. The hash should be + * unique for a vendor/tuner pair. + * There are a high chance that tuners for different + * video standards produce different hashes. + */ + for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) { + if (dev->hash == em28xx_eeprom_hash[i].hash) { + dev->model = em28xx_eeprom_hash[i].model; + dev->tuner_type = em28xx_eeprom_hash[i].tuner; + + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on eeprom hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " \n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); + + return 0; + } + } + + /* HINT method: I2C attached devices + * + * This method works for all boards. + * Uses a hash of i2c scanned devices. + * Devices with the same i2c attached chips will + * be considered equal. + * This method is less precise than the eeprom one. + */ + + /* user did not request i2c scanning => do it now */ + if (!dev->i2c_hash) + em28xx_do_i2c_scan(dev); + + for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) { + if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { + dev->model = em28xx_i2c_hash[i].model; + dev->tuner_type = em28xx_i2c_hash[i].tuner; + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on i2c devicelist hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " \n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); + + return 0; + } + } + + em28xx_errdev("Your board has no unique USB ID and thus need a " + "hint to be detected.\n"); + em28xx_errdev("You may try to use card= insmod option to " + "workaround that.\n"); + em28xx_errdev("Please send an email with this log to:\n"); + em28xx_errdev("\tV4L Mailing List \n"); + em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); + em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); + + em28xx_errdev("Here is a list of valid choices for the card=" + " insmod option:\n"); + for (i = 0; i < em28xx_bcount; i++) { + em28xx_errdev(" card=%d -> %s\n", + i, em28xx_boards[i].name); + } + return -1; +} + +/* ----------------------------------------------------------------------- */ +void em28xx_register_i2c_ir(struct em28xx *dev) +{ + /* Leadtek winfast tv USBII deluxe can find a non working IR-device */ + /* at address 0x18, so if that address is needed for another board in */ + /* the future, please put it after 0x1f. */ + struct i2c_board_info info; + const unsigned short addr_list[] = { + 0x1f, 0x30, 0x47, I2C_CLIENT_END + }; + + if (disable_ir) + return; + + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&dev->init_data, 0, sizeof(dev->init_data)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + + /* detect & configure */ + switch (dev->model) { + case EM2800_BOARD_TERRATEC_CINERGY_200: + case EM2820_BOARD_TERRATEC_CINERGY_250: + dev->init_data.ir_codes = RC_MAP_EM_TERRATEC; + dev->init_data.get_key = em28xx_get_key_terratec; + dev->init_data.name = "i2c IR (EM28XX Terratec)"; + break; + case EM2820_BOARD_PINNACLE_USB_2: + dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY; + dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey; + dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; + break; + case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: + dev->init_data.ir_codes = RC_MAP_HAUPPAUGE; + dev->init_data.get_key = em28xx_get_key_em_haup; + dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; + break; + case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE: + dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE; + dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe; + dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)"; + break; + } + + if (dev->init_data.name) + info.platform_data = &dev->init_data; + i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL); +} + +void em28xx_card_setup(struct em28xx *dev) +{ + /* + * If the device can be a webcam, seek for a sensor. + * If sensor is not found, then it isn't a webcam. + */ + if (dev->board.is_webcam) { + if (em28xx_hint_sensor(dev) < 0) + dev->board.is_webcam = 0; + else + dev->progressive = 1; + } + + if (!dev->board.is_webcam) { + switch (dev->model) { + case EM2820_BOARD_UNKNOWN: + case EM2800_BOARD_UNKNOWN: + /* + * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD. + * + * This occurs because they share identical USB vendor and + * product IDs. + * + * What we do here is look up the EEPROM hash of the K-WORLD + * and if it is found then we decide that we do not have + * a DIGIVOX and reset the device to the K-WORLD instead. + * + * This solution is only valid if they do not share eeprom + * hash identities which has not been determined as yet. + */ + if (em28xx_hint_board(dev) < 0) + em28xx_errdev("Board not discovered\n"); + else { + em28xx_set_model(dev); + em28xx_pre_card_setup(dev); + } + break; + default: + em28xx_set_model(dev); + } + } + + em28xx_info("Identified as %s (card=%d)\n", + dev->board.name, dev->model); + + dev->tuner_type = em28xx_boards[dev->model].tuner_type; + if (em28xx_boards[dev->model].tuner_addr) + dev->tuner_addr = em28xx_boards[dev->model].tuner_addr; + + if (em28xx_boards[dev->model].tda9887_conf) + dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; + + /* request some modules */ + switch (dev->model) { + case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: + { + struct tveeprom tv; +#if defined(CONFIG_MODULES) && defined(MODULE) + request_module("tveeprom"); +#endif + /* Call first TVeeprom */ + + dev->i2c_client.addr = 0xa0 >> 1; + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); + + dev->tuner_type = tv.tuner_type; + + if (tv.audio_processor == V4L2_IDENT_MSPX4XX) { + dev->i2s_speed = 2048000; + dev->board.has_msp34xx = 1; + } + break; + } + case EM2882_BOARD_KWORLD_ATSC_315U: + em28xx_write_reg(dev, 0x0d, 0x42); + msleep(10); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); + msleep(10); + break; + case EM2820_BOARD_KWORLD_PVRTV2800RF: + /* GPIO enables sound on KWORLD PVR TV 2800RF */ + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9); + break; + case EM2820_BOARD_UNKNOWN: + case EM2800_BOARD_UNKNOWN: + /* + * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD. + * + * This occurs because they share identical USB vendor and + * product IDs. + * + * What we do here is look up the EEPROM hash of the K-WORLD + * and if it is found then we decide that we do not have + * a DIGIVOX and reset the device to the K-WORLD instead. + * + * This solution is only valid if they do not share eeprom + * hash identities which has not been determined as yet. + */ + case EM2880_BOARD_MSI_DIGIVOX_AD: + if (!em28xx_hint_board(dev)) + em28xx_set_model(dev); + + /* In cases where we had to use a board hint, the call to + em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, + so make the call now so the analog GPIOs are set properly + before probing the i2c bus. */ + em28xx_gpio_set(dev, dev->board.tuner_gpio); + em28xx_set_mode(dev, EM28XX_ANALOG_MODE); + break; + +/* + * The Dikom DK300 is detected as an Kworld VS-DVB-T 323UR. + * + * This occurs because they share identical USB vendor and + * product IDs. + * + * What we do here is look up the EEPROM hash of the Dikom + * and if it is found then we decide that we do not have + * a Kworld and reset the device to the Dikom instead. + * + * This solution is only valid if they do not share eeprom + * hash identities which has not been determined as yet. + */ + case EM2882_BOARD_KWORLD_VS_DVBT: + if (!em28xx_hint_board(dev)) + em28xx_set_model(dev); + + /* In cases where we had to use a board hint, the call to + em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, + so make the call now so the analog GPIOs are set properly + before probing the i2c bus. */ + em28xx_gpio_set(dev, dev->board.tuner_gpio); + em28xx_set_mode(dev, EM28XX_ANALOG_MODE); + break; + } + +#if defined(CONFIG_MODULES) && defined(MODULE) + if (dev->board.has_ir_i2c && !disable_ir) + request_module("ir-kbd-i2c"); +#endif + if (dev->board.has_snapshot_button) + em28xx_register_snapshot_button(dev); + + if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) { + em28xx_errdev("\n\n"); + em28xx_errdev("The support for this board weren't " + "valid yet.\n"); + em28xx_errdev("Please send a report of having this working\n"); + em28xx_errdev("not to V4L mailing list (and/or to other " + "addresses)\n\n"); + } + + /* Allow override tuner type by a module parameter */ + if (tuner >= 0) + dev->tuner_type = tuner; + + /* request some modules */ + if (dev->board.has_msp34xx) + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "msp3400", 0, msp3400_addrs); + + if (dev->board.decoder == EM28XX_SAA711X) + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "saa7115_auto", 0, saa711x_addrs); + + if (dev->board.decoder == EM28XX_TVP5150) + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "tvp5150", 0, tvp5150_addrs); + + if (dev->em28xx_sensor == EM28XX_MT9V011) { + struct mt9v011_platform_data pdata; + struct i2c_board_info mt9v011_info = { + .type = "mt9v011", + .addr = 0xba >> 1, + .platform_data = &pdata, + }; + + pdata.xtal = dev->sensor_xtal; + v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap, + &mt9v011_info, NULL); + } + + + if (dev->board.adecoder == EM28XX_TVAUDIO) + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "tvaudio", dev->board.tvaudio_addr, NULL); + + if (dev->board.tuner_type != TUNER_ABSENT) { + int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); + + if (dev->board.radio.type) + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "tuner", dev->board.radio_addr, NULL); + + if (has_demod) + v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_adap, "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + if (dev->tuner_addr == 0) { + enum v4l2_i2c_tuner_type type = + has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; + struct v4l2_subdev *sd; + + sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_adap, "tuner", + 0, v4l2_i2c_tuner_addrs(type)); + + if (sd) + dev->tuner_addr = v4l2_i2c_subdev_addr(sd); + } else { + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "tuner", dev->tuner_addr, NULL); + } + } + + em28xx_tuner_setup(dev); + + if(!disable_ir) + em28xx_ir_init(dev); +} + + +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + struct em28xx *dev = container_of(work, + struct em28xx, request_module_wk); + + if (dev->has_audio_class) + request_module("snd-usb-audio"); + else if (dev->has_alsa_audio) + request_module("em28xx-alsa"); + + if (dev->board.has_dvb) + request_module("em28xx-dvb"); +} + +static void request_modules(struct em28xx *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); +} + +static void flush_request_modules(struct em28xx *dev) +{ + flush_work_sync(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#define flush_request_modules(dev) +#endif /* CONFIG_MODULES */ + +/* + * em28xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +void em28xx_release_resources(struct em28xx *dev) +{ + if (dev->sbutton_input_dev) + em28xx_deregister_snapshot_button(dev); + + if (dev->ir) + em28xx_ir_fini(dev); + + /*FIXME: I2C IR should be disconnected */ + + em28xx_release_analog_resources(dev); + + em28xx_remove_from_devlist(dev); + + em28xx_i2c_unregister(dev); + + v4l2_device_unregister(&dev->v4l2_dev); + + usb_put_dev(dev->udev); + + /* Mark device as unused */ + em28xx_devused &= ~(1 << dev->devno); +}; + +/* + * em28xx_init_dev() + * allocates and inits the device structs, registers i2c bus and v4l device + */ +static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, + struct usb_interface *interface, + int minor) +{ + struct em28xx *dev = *devhandle; + int retval; + int errCode; + + dev->udev = udev; + mutex_init(&dev->ctrl_urb_lock); + spin_lock_init(&dev->slock); + init_waitqueue_head(&dev->open); + init_waitqueue_head(&dev->wait_frame); + init_waitqueue_head(&dev->wait_stream); + + dev->em28xx_write_regs = em28xx_write_regs; + dev->em28xx_read_reg = em28xx_read_reg; + dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; + dev->em28xx_write_regs_req = em28xx_write_regs_req; + dev->em28xx_read_reg_req = em28xx_read_reg_req; + dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800; + + em28xx_set_model(dev); + + /* Set the default GPO/GPIO for legacy devices */ + dev->reg_gpo_num = EM2880_R04_GPO; + dev->reg_gpio_num = EM28XX_R08_GPIO; + + dev->wait_after_write = 5; + + /* Based on the Chip ID, set the device configuration */ + retval = em28xx_read_reg(dev, EM28XX_R0A_CHIPID); + if (retval > 0) { + dev->chip_id = retval; + + switch (dev->chip_id) { + case CHIP_ID_EM2800: + em28xx_info("chip ID is em2800\n"); + break; + case CHIP_ID_EM2710: + em28xx_info("chip ID is em2710\n"); + break; + case CHIP_ID_EM2750: + em28xx_info("chip ID is em2750\n"); + break; + case CHIP_ID_EM2820: + em28xx_info("chip ID is em2820 (or em2710)\n"); + break; + case CHIP_ID_EM2840: + em28xx_info("chip ID is em2840\n"); + break; + case CHIP_ID_EM2860: + em28xx_info("chip ID is em2860\n"); + break; + case CHIP_ID_EM2870: + em28xx_info("chip ID is em2870\n"); + dev->wait_after_write = 0; + break; + case CHIP_ID_EM2874: + em28xx_info("chip ID is em2874\n"); + dev->reg_gpio_num = EM2874_R80_GPIO; + dev->wait_after_write = 0; + break; + case CHIP_ID_EM28174: + em28xx_info("chip ID is em28174\n"); + dev->reg_gpio_num = EM2874_R80_GPIO; + dev->wait_after_write = 0; + break; + case CHIP_ID_EM2883: + em28xx_info("chip ID is em2882/em2883\n"); + dev->wait_after_write = 0; + break; + default: + em28xx_info("em28xx chip ID = %d\n", dev->chip_id); + } + } + + if (dev->is_audio_only) { + errCode = em28xx_audio_setup(dev); + if (errCode) + return -ENODEV; + em28xx_add_into_devlist(dev); + em28xx_init_extension(dev); + + return 0; + } + + /* Prepopulate cached GPO register content */ + retval = em28xx_read_reg(dev, dev->reg_gpo_num); + if (retval >= 0) + dev->reg_gpo = retval; + + em28xx_pre_card_setup(dev); + + if (!dev->board.is_em2800) { + /* Resets I2C speed */ + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); + if (retval < 0) { + em28xx_errdev("%s: em28xx_write_regs_req failed!" + " retval [%d]\n", + __func__, retval); + return retval; + } + } + + retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); + if (retval < 0) { + em28xx_errdev("Call to v4l2_device_register() failed!\n"); + return retval; + } + + /* register i2c bus */ + errCode = em28xx_i2c_register(dev); + if (errCode < 0) { + v4l2_device_unregister(&dev->v4l2_dev); + em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + + /* + * Default format, used for tvp5150 or saa711x output formats + */ + dev->vinmode = 0x10; + dev->vinctl = EM28XX_VINCTRL_INTERLACED | + EM28XX_VINCTRL_CCIR656_ENABLE; + + /* Do board specific init and eeprom reading */ + em28xx_card_setup(dev); + + /* Configure audio */ + errCode = em28xx_audio_setup(dev); + if (errCode < 0) { + v4l2_device_unregister(&dev->v4l2_dev); + em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n", + __func__, errCode); + } + + /* wake i2c devices */ + em28xx_wake_i2c(dev); + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + INIT_LIST_HEAD(&dev->vbiq.active); + INIT_LIST_HEAD(&dev->vbiq.queued); + + if (dev->board.has_msp34xx) { + /* Send a reset to other chips via gpio */ + errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); + if (errCode < 0) { + em28xx_errdev("%s: em28xx_write_regs_req - " + "msp34xx(1) failed! errCode [%d]\n", + __func__, errCode); + return errCode; + } + msleep(3); + + errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); + if (errCode < 0) { + em28xx_errdev("%s: em28xx_write_regs_req - " + "msp34xx(2) failed! errCode [%d]\n", + __func__, errCode); + return errCode; + } + msleep(3); + } + + em28xx_add_into_devlist(dev); + + retval = em28xx_register_analog_devices(dev); + if (retval < 0) { + em28xx_release_resources(dev); + goto fail_reg_devices; + } + + em28xx_init_extension(dev); + + /* Save some power by putting tuner to sleep */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); + + return 0; + +fail_reg_devices: + return retval; +} + +/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ +#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) + +/* + * em28xx_usb_probe() + * checks for supported devices + */ +static int em28xx_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + const struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev; + struct em28xx *dev = NULL; + int retval; + bool is_audio_only = false, has_audio = false; + int i, nr, isoc_pipe; + const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; + char *speed; + char descr[255] = ""; + + udev = usb_get_dev(interface_to_usbdev(interface)); + + /* Check to see next free device and mark as used */ + nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); + em28xx_devused |= 1<altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { + em28xx_err(DRIVER_NAME " audio device (%04x:%04x): " + "interface %i, class %i\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting[0].desc.bInterfaceClass); + + em28xx_devused &= ~(1<num_altsetting; i++) { + int ep; + + for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { + struct usb_host_endpoint *e; + e = &interface->altsetting[i].endpoint[ep]; + + if (e->desc.bEndpointAddress == 0x83) + has_audio = true; + } + } + + endpoint = &interface->cur_altsetting->endpoint[0].desc; + + /* check if the device has the iso in endpoint at the correct place */ + if (usb_endpoint_xfer_isoc(endpoint) + && + (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) { + /* It's a newer em2874/em2875 device */ + isoc_pipe = 0; + } else { + int check_interface = 1; + isoc_pipe = 1; + endpoint = &interface->cur_altsetting->endpoint[1].desc; + if (!usb_endpoint_xfer_isoc(endpoint)) + check_interface = 0; + + if (usb_endpoint_dir_out(endpoint)) + check_interface = 0; + + if (!check_interface) { + if (has_audio) { + is_audio_only = true; + } else { + em28xx_err(DRIVER_NAME " video device (%04x:%04x): " + "interface %i, class %i found.\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting[0].desc.bInterfaceClass); + em28xx_err(DRIVER_NAME " This is an anciliary " + "interface not used by the driver\n"); + + em28xx_devused &= ~(1<speed) { + case USB_SPEED_LOW: + speed = "1.5"; + break; + case USB_SPEED_UNKNOWN: + case USB_SPEED_FULL: + speed = "12"; + break; + case USB_SPEED_HIGH: + speed = "480"; + break; + default: + speed = "unknown"; + } + + if (udev->manufacturer) + strlcpy(descr, udev->manufacturer, sizeof(descr)); + + if (udev->product) { + if (*descr) + strlcat(descr, " ", sizeof(descr)); + strlcat(descr, udev->product, sizeof(descr)); + } + if (*descr) + strlcat(descr, " ", sizeof(descr)); + + printk(KERN_INFO DRIVER_NAME + ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n", + descr, + speed, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting->desc.bInterfaceNumber); + + if (has_audio) + printk(KERN_INFO DRIVER_NAME + ": Audio Vendor Class interface %i found\n", + ifnum); + + /* + * Make sure we have 480 Mbps of bandwidth, otherwise things like + * video stream wouldn't likely work, since 12 Mbps is generally + * not enough even for most Digital TV streams. + */ + if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { + printk(DRIVER_NAME ": Device initialization failed.\n"); + printk(DRIVER_NAME ": Device must be connected to a high-speed" + " USB 2.0 port.\n"); + em28xx_devused &= ~(1<= EM28XX_MAXBOARDS) { + printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", + EM28XX_MAXBOARDS); + em28xx_devused &= ~(1<name, 29, "em28xx #%d", nr); + dev->devno = nr; + dev->model = id->driver_info; + dev->alt = -1; + dev->is_audio_only = is_audio_only; + dev->has_alsa_audio = has_audio; + dev->audio_ifnum = ifnum; + + /* Checks if audio is provided by some interface */ + for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { + struct usb_interface *uif = udev->config->interface[i]; + if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { + dev->has_audio_class = 1; + break; + } + } + + /* compute alternate max packet sizes */ + dev->num_alt = interface->num_altsetting; + dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); + + if (dev->alt_max_pkt_size == NULL) { + em28xx_errdev("out of memory!\n"); + em28xx_devused &= ~(1<num_alt ; i++) { + u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); + unsigned int size = tmp & 0x7ff; + + if (udev->speed == USB_SPEED_HIGH) + size = size * hb_mult(tmp); + + dev->alt_max_pkt_size[i] = size; + } + + if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) + dev->model = card[nr]; + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + + /* allocate device struct */ + mutex_init(&dev->lock); + mutex_lock(&dev->lock); + retval = em28xx_init_dev(&dev, udev, interface, nr); + if (retval) { + em28xx_devused &= ~(1<devno); + mutex_unlock(&dev->lock); + kfree(dev); + goto err; + } + + request_modules(dev); + + /* Should be the last thing to do, to avoid newer udev's to + open the device before fully initializing it + */ + mutex_unlock(&dev->lock); + + return 0; + +err: + return retval; +} + +/* + * em28xx_usb_disconnect() + * called when the device gets diconencted + * video device will be unregistered on v4l2_close in case it is still open + */ +static void em28xx_usb_disconnect(struct usb_interface *interface) +{ + struct em28xx *dev; + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + if (!dev) + return; + + if (dev->is_audio_only) { + mutex_lock(&dev->lock); + em28xx_close_extension(dev); + mutex_unlock(&dev->lock); + return; + } + + em28xx_info("disconnecting %s\n", dev->vdev->name); + + flush_request_modules(dev); + + /* wait until all current v4l2 io is finished then deallocate + resources */ + mutex_lock(&dev->lock); + + wake_up_interruptible_all(&dev->open); + + v4l2_device_disconnect(&dev->v4l2_dev); + + if (dev->users) { + em28xx_warn + ("device %s is open! Deregistration and memory " + "deallocation are deferred on close.\n", + video_device_node_name(dev->vdev)); + + dev->state |= DEV_MISCONFIGURED; + em28xx_uninit_isoc(dev); + dev->state |= DEV_DISCONNECTED; + wake_up_interruptible(&dev->wait_frame); + wake_up_interruptible(&dev->wait_stream); + } else { + dev->state |= DEV_DISCONNECTED; + em28xx_release_resources(dev); + } + + em28xx_close_extension(dev); + + mutex_unlock(&dev->lock); + + if (!dev->users) { + kfree(dev->alt_max_pkt_size); + kfree(dev); + } +} + +static struct usb_driver em28xx_usb_driver = { + .name = "em28xx", + .probe = em28xx_usb_probe, + .disconnect = em28xx_usb_disconnect, + .id_table = em28xx_id_table, +}; + +static int __init em28xx_module_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&em28xx_usb_driver); + if (result) + em28xx_err(DRIVER_NAME + " usb_register failed. Error number %d.\n", result); + + printk(KERN_INFO DRIVER_NAME " driver loaded\n"); + + return result; +} + +static void __exit em28xx_module_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&em28xx_usb_driver); +} + +module_init(em28xx_module_init); +module_exit(em28xx_module_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1245 @@ +/* + em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices + + Copyright (C) 2005 Ludovico Cavedon + Markus Rechberger + Mauro Carvalho Chehab + Sascha Sommer + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "em28xx.h" + +/* #define ENABLE_DEBUG_ISOC_FRAMES */ + +static unsigned int core_debug; +module_param(core_debug, int, 0644); +MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); + +#define em28xx_coredbg(fmt, arg...) do {\ + if (core_debug) \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); } while (0) + +static unsigned int reg_debug; +module_param(reg_debug, int, 0644); +MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); + +#define em28xx_regdbg(fmt, arg...) do {\ + if (reg_debug) \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); } while (0) + +static int alt; +module_param(alt, int, 0644); +MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); + +static unsigned int disable_vbi; +module_param(disable_vbi, int, 0644); +MODULE_PARM_DESC(disable_vbi, "disable vbi support"); + +/* FIXME */ +#define em28xx_isocdbg(fmt, arg...) do {\ + if (core_debug) \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); } while (0) + +/* + * em28xx_read_reg_req() + * reads data from the usb device specifying bRequest + */ +int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, + char *buf, int len) +{ + int ret; + int pipe = usb_rcvctrlpipe(dev->udev, 0); + + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + + if (len > URB_MAX_CTRL_SIZE) + return -EINVAL; + + if (reg_debug) { + printk(KERN_DEBUG "(pipe 0x%08x): " + "IN: %02x %02x %02x %02x %02x %02x %02x %02x ", + pipe, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8); + } + + mutex_lock(&dev->ctrl_urb_lock); + ret = usb_control_msg(dev->udev, pipe, req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0000, reg, dev->urb_buf, len, HZ); + if (ret < 0) { + if (reg_debug) + printk(" failed!\n"); + mutex_unlock(&dev->ctrl_urb_lock); + return ret; + } + + if (len) + memcpy(buf, dev->urb_buf, len); + + mutex_unlock(&dev->ctrl_urb_lock); + + if (reg_debug) { + int byte; + + printk("<<<"); + for (byte = 0; byte < len; byte++) + printk(" %02x", (unsigned char)buf[byte]); + printk("\n"); + } + + return ret; +} + +/* + * em28xx_read_reg_req() + * reads data from the usb device specifying bRequest + */ +int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg) +{ + int ret; + u8 val; + + ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1); + if (ret < 0) + return ret; + + return val; +} + +int em28xx_read_reg(struct em28xx *dev, u16 reg) +{ + return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg); +} + +/* + * em28xx_write_regs_req() + * sends data to the usb device, specifying bRequest + */ +int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, + int len) +{ + int ret; + int pipe = usb_sndctrlpipe(dev->udev, 0); + + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + + if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) + return -EINVAL; + + if (reg_debug) { + int byte; + + printk(KERN_DEBUG "(pipe 0x%08x): " + "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", + pipe, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8); + + for (byte = 0; byte < len; byte++) + printk(" %02x", (unsigned char)buf[byte]); + printk("\n"); + } + + mutex_lock(&dev->ctrl_urb_lock); + memcpy(dev->urb_buf, buf, len); + ret = usb_control_msg(dev->udev, pipe, req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0000, reg, dev->urb_buf, len, HZ); + mutex_unlock(&dev->ctrl_urb_lock); + + if (dev->wait_after_write) + msleep(dev->wait_after_write); + + return ret; +} + +int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len) +{ + int rc; + + rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len); + + /* Stores GPO/GPIO values at the cache, if changed + Only write values should be stored, since input on a GPIO + register will return the input bits. + Not sure what happens on reading GPO register. + */ + if (rc >= 0) { + if (reg == dev->reg_gpo_num) + dev->reg_gpo = buf[0]; + else if (reg == dev->reg_gpio_num) + dev->reg_gpio = buf[0]; + } + + return rc; +} + +/* Write a single register */ +int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val) +{ + return em28xx_write_regs(dev, reg, &val, 1); +} + +/* + * em28xx_write_reg_bits() + * sets only some bits (specified by bitmask) of a register, by first reading + * the actual value + */ +int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, + u8 bitmask) +{ + int oldval; + u8 newval; + + /* Uses cache for gpo/gpio registers */ + if (reg == dev->reg_gpo_num) + oldval = dev->reg_gpo; + else if (reg == dev->reg_gpio_num) + oldval = dev->reg_gpio; + else + oldval = em28xx_read_reg(dev, reg); + + if (oldval < 0) + return oldval; + + newval = (((u8) oldval) & ~bitmask) | (val & bitmask); + + return em28xx_write_regs(dev, reg, &newval, 1); +} + +/* + * em28xx_is_ac97_ready() + * Checks if ac97 is ready + */ +static int em28xx_is_ac97_ready(struct em28xx *dev) +{ + int ret, i; + + /* Wait up to 50 ms for AC97 command to complete */ + for (i = 0; i < 10; i++, msleep(5)) { + ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); + if (ret < 0) + return ret; + + if (!(ret & 0x01)) + return 0; + } + + em28xx_warn("AC97 command still being executed: not handled properly!\n"); + return -EBUSY; +} + +/* + * em28xx_read_ac97() + * write a 16 bit value to the specified AC97 address (LSB first!) + */ +int em28xx_read_ac97(struct em28xx *dev, u8 reg) +{ + int ret; + u8 addr = (reg & 0x7f) | 0x80; + u16 val; + + ret = em28xx_is_ac97_ready(dev); + if (ret < 0) + return ret; + + ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1); + if (ret < 0) + return ret; + + ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB, + (u8 *)&val, sizeof(val)); + + if (ret < 0) + return ret; + return le16_to_cpu(val); +} +EXPORT_SYMBOL_GPL(em28xx_read_ac97); + +/* + * em28xx_write_ac97() + * write a 16 bit value to the specified AC97 address (LSB first!) + */ +int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val) +{ + int ret; + u8 addr = reg & 0x7f; + __le16 value; + + value = cpu_to_le16(val); + + ret = em28xx_is_ac97_ready(dev); + if (ret < 0) + return ret; + + ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2); + if (ret < 0) + return ret; + + ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(em28xx_write_ac97); + +struct em28xx_vol_itable { + enum em28xx_amux mux; + u8 reg; +}; + +static struct em28xx_vol_itable inputs[] = { + { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL }, + { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL }, + { EM28XX_AMUX_PHONE, AC97_PHONE_VOL }, + { EM28XX_AMUX_MIC, AC97_MIC_VOL }, + { EM28XX_AMUX_CD, AC97_CD_VOL }, + { EM28XX_AMUX_AUX, AC97_AUX_VOL }, + { EM28XX_AMUX_PCM_OUT, AC97_PCM_OUT_VOL }, +}; + +static int set_ac97_input(struct em28xx *dev) +{ + int ret, i; + enum em28xx_amux amux = dev->ctl_ainput; + + /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that + em28xx should point to LINE IN, while AC97 should use VIDEO + */ + if (amux == EM28XX_AMUX_VIDEO2) + amux = EM28XX_AMUX_VIDEO; + + /* Mute all entres but the one that were selected */ + for (i = 0; i < ARRAY_SIZE(inputs); i++) { + if (amux == inputs[i].mux) + ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808); + else + ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000); + + if (ret < 0) + em28xx_warn("couldn't setup AC97 register %d\n", + inputs[i].reg); + } + return 0; +} + +static int em28xx_set_audio_source(struct em28xx *dev) +{ + int ret; + u8 input; + + if (dev->board.is_em2800) { + if (dev->ctl_ainput == EM28XX_AMUX_VIDEO) + input = EM2800_AUDIO_SRC_TUNER; + else + input = EM2800_AUDIO_SRC_LINE; + + ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1); + if (ret < 0) + return ret; + } + + if (dev->board.has_msp34xx) + input = EM28XX_AUDIO_SRC_TUNER; + else { + switch (dev->ctl_ainput) { + case EM28XX_AMUX_VIDEO: + input = EM28XX_AUDIO_SRC_TUNER; + break; + default: + input = EM28XX_AUDIO_SRC_LINE; + break; + } + } + + if (dev->board.mute_gpio && dev->mute) + em28xx_gpio_set(dev, dev->board.mute_gpio); + else + em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio); + + ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0); + if (ret < 0) + return ret; + msleep(5); + + switch (dev->audio_mode.ac97) { + case EM28XX_NO_AC97: + break; + default: + ret = set_ac97_input(dev); + } + + return ret; +} + +struct em28xx_vol_otable { + enum em28xx_aout mux; + u8 reg; +}; + +static const struct em28xx_vol_otable outputs[] = { + { EM28XX_AOUT_MASTER, AC97_MASTER_VOL }, + { EM28XX_AOUT_LINE, AC97_LINE_LEVEL_VOL }, + { EM28XX_AOUT_MONO, AC97_MASTER_MONO_VOL }, + { EM28XX_AOUT_LFE, AC97_LFE_MASTER_VOL }, + { EM28XX_AOUT_SURR, AC97_SURR_MASTER_VOL }, +}; + +int em28xx_audio_analog_set(struct em28xx *dev) +{ + int ret, i; + u8 xclk; + + if (!dev->audio_mode.has_audio) + return 0; + + /* It is assumed that all devices use master volume for output. + It would be possible to use also line output. + */ + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + /* Mute all outputs */ + for (i = 0; i < ARRAY_SIZE(outputs); i++) { + ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000); + if (ret < 0) + em28xx_warn("couldn't setup AC97 register %d\n", + outputs[i].reg); + } + } + + xclk = dev->board.xclk & 0x7f; + if (!dev->mute) + xclk |= EM28XX_XCLK_AUDIO_UNMUTE; + + ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk); + if (ret < 0) + return ret; + msleep(10); + + /* Selects the proper audio input */ + ret = em28xx_set_audio_source(dev); + + /* Sets volume */ + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + int vol; + + em28xx_write_ac97(dev, AC97_POWER_DOWN_CTRL, 0x4200); + em28xx_write_ac97(dev, AC97_EXT_AUD_CTRL, 0x0031); + em28xx_write_ac97(dev, AC97_PCM_IN_SRATE, 0xbb80); + + /* LSB: left channel - both channels with the same level */ + vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8); + + /* Mute device, if needed */ + if (dev->mute) + vol |= 0x8000; + + /* Sets volume */ + for (i = 0; i < ARRAY_SIZE(outputs); i++) { + if (dev->ctl_aoutput & outputs[i].mux) + ret = em28xx_write_ac97(dev, outputs[i].reg, + vol); + if (ret < 0) + em28xx_warn("couldn't setup AC97 register %d\n", + outputs[i].reg); + } + + if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) { + int sel = ac97_return_record_select(dev->ctl_aoutput); + + /* Use the same input for both left and right + channels */ + sel |= (sel << 8); + + em28xx_write_ac97(dev, AC97_RECORD_SELECT, sel); + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); + +int em28xx_audio_setup(struct em28xx *dev) +{ + int vid1, vid2, feat, cfg; + u32 vid; + + if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874 + || dev->chip_id == CHIP_ID_EM28174) { + /* Digital only device - don't load any alsa module */ + dev->audio_mode.has_audio = false; + dev->has_audio_class = false; + dev->has_alsa_audio = false; + return 0; + } + + dev->audio_mode.has_audio = true; + + /* See how this device is configured */ + cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); + em28xx_info("Config register raw data: 0x%02x\n", cfg); + if (cfg < 0) { + /* Register read error? */ + cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ + } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) { + /* The device doesn't have vendor audio at all */ + dev->has_alsa_audio = false; + dev->audio_mode.has_audio = false; + return 0; + } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM28XX_CHIPCFG_I2S_3_SAMPRATES) { + em28xx_info("I2S Audio (3 sample rates)\n"); + dev->audio_mode.i2s_3rates = 1; + } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM28XX_CHIPCFG_I2S_5_SAMPRATES) { + em28xx_info("I2S Audio (5 sample rates)\n"); + dev->audio_mode.i2s_5rates = 1; + } + + if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) { + /* Skip the code that does AC97 vendor detection */ + dev->audio_mode.ac97 = EM28XX_NO_AC97; + goto init_audio; + } + + dev->audio_mode.ac97 = EM28XX_AC97_OTHER; + + vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1); + if (vid1 < 0) { + /* + * Device likely doesn't support AC97 + * Note: (some) em2800 devices without eeprom reports 0x91 on + * CHIPCFG register, even not having an AC97 chip + */ + em28xx_warn("AC97 chip type couldn't be determined\n"); + dev->audio_mode.ac97 = EM28XX_NO_AC97; + dev->has_alsa_audio = false; + dev->audio_mode.has_audio = false; + goto init_audio; + } + + vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2); + if (vid2 < 0) + goto init_audio; + + vid = vid1 << 16 | vid2; + + dev->audio_mode.ac97_vendor_id = vid; + em28xx_warn("AC97 vendor ID = 0x%08x\n", vid); + + feat = em28xx_read_ac97(dev, AC97_RESET); + if (feat < 0) + goto init_audio; + + dev->audio_mode.ac97_feat = feat; + em28xx_warn("AC97 features = 0x%04x\n", feat); + + /* Try to identify what audio processor we have */ + if ((vid == 0xffffffff) && (feat == 0x6a90)) + dev->audio_mode.ac97 = EM28XX_AC97_EM202; + else if ((vid >> 8) == 0x838476) + dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL; + +init_audio: + /* Reports detected AC97 processor */ + switch (dev->audio_mode.ac97) { + case EM28XX_NO_AC97: + em28xx_info("No AC97 audio processor\n"); + break; + case EM28XX_AC97_EM202: + em28xx_info("Empia 202 AC97 audio processor detected\n"); + break; + case EM28XX_AC97_SIGMATEL: + em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n", + dev->audio_mode.ac97_vendor_id & 0xff); + break; + case EM28XX_AC97_OTHER: + em28xx_warn("Unknown AC97 audio processor detected!\n"); + break; + default: + break; + } + + return em28xx_audio_analog_set(dev); +} +EXPORT_SYMBOL_GPL(em28xx_audio_setup); + +int em28xx_colorlevels_set_default(struct em28xx *dev) +{ + em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10); /* contrast */ + em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00); /* brightness */ + em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */ + em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00); + em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00); + em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00); + + em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); + em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); + em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20); + em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20); + em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00); + em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00); + return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00); +} + +int em28xx_capture_start(struct em28xx *dev, int start) +{ + int rc; + + if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { + /* The Transport Stream Enable Register moved in em2874 */ + if (!start) { + rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, + 0x00, + EM2874_TS1_CAPTURE_ENABLE); + return rc; + } + + /* Enable Transport Stream */ + rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, + EM2874_TS1_CAPTURE_ENABLE, + EM2874_TS1_CAPTURE_ENABLE); + return rc; + } + + + /* FIXME: which is the best order? */ + /* video registers are sampled by VREF */ + rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, + start ? 0x10 : 0x00, 0x10); + if (rc < 0) + return rc; + + if (!start) { + /* disable video capture */ + rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27); + return rc; + } + + if (dev->board.is_webcam) + rc = em28xx_write_reg(dev, 0x13, 0x0c); + + /* enable video capture */ + rc = em28xx_write_reg(dev, 0x48, 0x00); + + if (dev->mode == EM28XX_ANALOG_MODE) + rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); + else + rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); + + msleep(6); + + return rc; +} + +int em28xx_vbi_supported(struct em28xx *dev) +{ + /* Modprobe option to manually disable */ + if (disable_vbi == 1) + return 0; + + if (dev->chip_id == CHIP_ID_EM2860 || + dev->chip_id == CHIP_ID_EM2883) + return 1; + + /* Version of em28xx that does not support VBI */ + return 0; +} + +int em28xx_set_outfmt(struct em28xx *dev) +{ + int ret; + u8 vinctrl; + + ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, + dev->format->reg | 0x20, 0xff); + if (ret < 0) + return ret; + + ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode); + if (ret < 0) + return ret; + + vinctrl = dev->vinctl; + if (em28xx_vbi_supported(dev) == 1) { + vinctrl |= EM28XX_VINCTRL_VBI_RAW; + em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); + em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4); + em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height); + if (dev->norm & V4L2_STD_525_60) { + /* NTSC */ + em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); + } else if (dev->norm & V4L2_STD_625_50) { + /* PAL */ + em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07); + } + } + + return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); +} + +static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, + u8 ymin, u8 ymax) +{ + em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", + xmin, ymin, xmax, ymax); + + em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); + em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); + em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); + return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); +} + +static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, + u16 width, u16 height) +{ + u8 cwidth = width; + u8 cheight = height; + u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01); + + em28xx_coredbg("em28xx Area Set: (%d,%d)\n", + (width | (overflow & 2) << 7), + (height | (overflow & 1) << 8)); + + em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); + em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); + em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); + em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); + return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); +} + +static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) +{ + u8 mode; + /* the em2800 scaler only supports scaling down to 50% */ + + if (dev->board.is_em2800) { + mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); + } else { + u8 buf[2]; + + buf[0] = h; + buf[1] = h >> 8; + em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); + + buf[0] = v; + buf[1] = v >> 8; + em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); + /* it seems that both H and V scalers must be active + to work correctly */ + mode = (h || v) ? 0x30 : 0x00; + } + return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30); +} + +/* FIXME: this only function read values from dev */ +int em28xx_resolution_set(struct em28xx *dev) +{ + int width, height; + width = norm_maxw(dev); + height = norm_maxh(dev); + + /* Properly setup VBI */ + dev->vbi_width = 720; + if (dev->norm & V4L2_STD_525_60) + dev->vbi_height = 12; + else + dev->vbi_height = 18; + + if (!dev->progressive) + height >>= norm_maxh(dev); + + em28xx_set_outfmt(dev); + + + em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); + + /* If we don't set the start position to 2 in VBI mode, we end up + with line 20/21 being YUYV encoded instead of being in 8-bit + greyscale. The core of the issue is that line 21 (and line 23 for + PAL WSS) are inside of active video region, and as a result they + get the pixelformatting associated with that area. So by cropping + it out, we end up with the same format as the rest of the VBI + region */ + if (em28xx_vbi_supported(dev) == 1) + em28xx_capture_area_set(dev, 0, 2, width >> 2, height >> 2); + else + em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); + + return em28xx_scaler_set(dev, dev->hscale, dev->vscale); +} + +int em28xx_set_alternate(struct em28xx *dev) +{ + int errCode, prev_alt = dev->alt; + int i; + unsigned int min_pkt_size = dev->width * 2 + 4; + + /* + * alt = 0 is used only for control messages, so, only values + * greater than 0 can be used for streaming. + */ + if (alt && alt < dev->num_alt) { + em28xx_coredbg("alternate forced to %d\n", dev->alt); + dev->alt = alt; + goto set_alt; + } + + /* When image size is bigger than a certain value, + the frame size should be increased, otherwise, only + green screen will be received. + */ + if (dev->width * 2 * dev->height > 720 * 240 * 2) + min_pkt_size *= 2; + + for (i = 0; i < dev->num_alt; i++) { + /* stop when the selected alt setting offers enough bandwidth */ + if (dev->alt_max_pkt_size[i] >= min_pkt_size) { + dev->alt = i; + break; + /* otherwise make sure that we end up with the maximum bandwidth + because the min_pkt_size equation might be wrong... + */ + } else if (dev->alt_max_pkt_size[i] > + dev->alt_max_pkt_size[dev->alt]) + dev->alt = i; + } + +set_alt: + if (dev->alt != prev_alt) { + em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", + min_pkt_size, dev->alt); + dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt]; + em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", + dev->alt, dev->max_pkt_size); + errCode = usb_set_interface(dev->udev, 0, dev->alt); + if (errCode < 0) { + em28xx_errdev("cannot change alternate number to %d (error=%i)\n", + dev->alt, errCode); + return errCode; + } + } + return 0; +} + +int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) +{ + int rc = 0; + + if (!gpio) + return rc; + + if (dev->mode != EM28XX_SUSPEND) { + em28xx_write_reg(dev, 0x48, 0x00); + if (dev->mode == EM28XX_ANALOG_MODE) + em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); + else + em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); + msleep(6); + } + + /* Send GPIO reset sequences specified at board entry */ + while (gpio->sleep >= 0) { + if (gpio->reg >= 0) { + rc = em28xx_write_reg_bits(dev, + gpio->reg, + gpio->val, + gpio->mask); + if (rc < 0) + return rc; + } + if (gpio->sleep > 0) + msleep(gpio->sleep); + + gpio++; + } + return rc; +} + +int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode) +{ + if (dev->mode == set_mode) + return 0; + + if (set_mode == EM28XX_SUSPEND) { + dev->mode = set_mode; + + /* FIXME: add suspend support for ac97 */ + + return em28xx_gpio_set(dev, dev->board.suspend_gpio); + } + + dev->mode = set_mode; + + if (dev->mode == EM28XX_DIGITAL_MODE) + return em28xx_gpio_set(dev, dev->board.dvb_gpio); + else + return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio); +} +EXPORT_SYMBOL_GPL(em28xx_set_mode); + +/* ------------------------------------------------------------------ + URB control + ------------------------------------------------------------------*/ + +/* + * IRQ callback, called by URB callback + */ +static void em28xx_irq_callback(struct urb *urb) +{ + struct em28xx *dev = urb->context; + int i; + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + em28xx_isocdbg("urb completition error %d.\n", urb->status); + break; + } + + /* Copy data from URB */ + spin_lock(&dev->slock); + dev->isoc_ctl.isoc_copy(dev, urb); + spin_unlock(&dev->slock); + + /* Reset urb buffers */ + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + urb->status = 0; + + urb->status = usb_submit_urb(urb, GFP_ATOMIC); + if (urb->status) { + em28xx_isocdbg("urb resubmit failed (error=%i)\n", + urb->status); + } +} + +/* + * Stop and Deallocate URBs + */ +void em28xx_uninit_isoc(struct em28xx *dev) +{ + struct urb *urb; + int i; + + em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n"); + + dev->isoc_ctl.nfields = -1; + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = dev->isoc_ctl.urb[i]; + if (urb) { + if (!irqs_disabled()) + usb_kill_urb(urb); + else + usb_unlink_urb(urb); + + if (dev->isoc_ctl.transfer_buffer[i]) { + usb_free_coherent(dev->udev, + urb->transfer_buffer_length, + dev->isoc_ctl.transfer_buffer[i], + urb->transfer_dma); + } + usb_free_urb(urb); + dev->isoc_ctl.urb[i] = NULL; + } + dev->isoc_ctl.transfer_buffer[i] = NULL; + } + + kfree(dev->isoc_ctl.urb); + kfree(dev->isoc_ctl.transfer_buffer); + + dev->isoc_ctl.urb = NULL; + dev->isoc_ctl.transfer_buffer = NULL; + dev->isoc_ctl.num_bufs = 0; + + em28xx_capture_start(dev, 0); +} +EXPORT_SYMBOL_GPL(em28xx_uninit_isoc); + +/* + * Allocate URBs and start IRQ + */ +int em28xx_init_isoc(struct em28xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) +{ + struct em28xx_dmaqueue *dma_q = &dev->vidq; + struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; + int i; + int sb_size, pipe; + struct urb *urb; + int j, k; + int rc; + + em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n"); + + /* De-allocates all pending stuff */ + em28xx_uninit_isoc(dev); + + dev->isoc_ctl.isoc_copy = isoc_copy; + dev->isoc_ctl.num_bufs = num_bufs; + + dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + if (!dev->isoc_ctl.urb) { + em28xx_errdev("cannot alloc memory for usb buffers\n"); + return -ENOMEM; + } + + dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, + GFP_KERNEL); + if (!dev->isoc_ctl.transfer_buffer) { + em28xx_errdev("cannot allocate memory for usb transfer\n"); + kfree(dev->isoc_ctl.urb); + return -ENOMEM; + } + + dev->isoc_ctl.max_pkt_size = max_pkt_size; + dev->isoc_ctl.vid_buf = NULL; + dev->isoc_ctl.vbi_buf = NULL; + + sb_size = max_packets * dev->isoc_ctl.max_pkt_size; + + /* allocate urbs and transfer buffers */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = usb_alloc_urb(max_packets, GFP_KERNEL); + if (!urb) { + em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); + em28xx_uninit_isoc(dev); + return -ENOMEM; + } + dev->isoc_ctl.urb[i] = urb; + + dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, + sb_size, GFP_KERNEL, &urb->transfer_dma); + if (!dev->isoc_ctl.transfer_buffer[i]) { + em28xx_err("unable to allocate %i bytes for transfer" + " buffer %i%s\n", + sb_size, i, + in_interrupt() ? " while in int" : ""); + em28xx_uninit_isoc(dev); + return -ENOMEM; + } + memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); + + /* FIXME: this is a hack - should be + 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' + should also be using 'desc.bInterval' + */ + pipe = usb_rcvisocpipe(dev->udev, + dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84); + + usb_fill_int_urb(urb, dev->udev, pipe, + dev->isoc_ctl.transfer_buffer[i], sb_size, + em28xx_irq_callback, dev, 1); + + urb->number_of_packets = max_packets; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + + k = 0; + for (j = 0; j < max_packets; j++) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = + dev->isoc_ctl.max_pkt_size; + k += dev->isoc_ctl.max_pkt_size; + } + } + + init_waitqueue_head(&dma_q->wq); + init_waitqueue_head(&vbi_dma_q->wq); + + em28xx_capture_start(dev, 1); + + /* submit urbs and enables IRQ */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); + if (rc) { + em28xx_err("submit of urb %i failed (error=%i)\n", i, + rc); + em28xx_uninit_isoc(dev); + return rc; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(em28xx_init_isoc); + +/* Determine the packet size for the DVB stream for the given device + (underlying value programmed into the eeprom) */ +int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) +{ + unsigned int chip_cfg2; + unsigned int packet_size = 564; + + if (dev->chip_id == CHIP_ID_EM2874) { + /* FIXME - for now assume 564 like it was before, but the + em2874 code should be added to return the proper value... */ + packet_size = 564; + } else if (dev->chip_id == CHIP_ID_EM28174) { + /* FIXME same as em2874. 564 was enough for 22 Mbit DVB-T + but too much for 44 Mbit DVB-C. */ + packet_size = 752; + } else { + /* TS max packet size stored in bits 1-0 of R01 */ + chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); + switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) { + case EM28XX_CHIPCFG2_TS_PACKETSIZE_188: + packet_size = 188; + break; + case EM28XX_CHIPCFG2_TS_PACKETSIZE_376: + packet_size = 376; + break; + case EM28XX_CHIPCFG2_TS_PACKETSIZE_564: + packet_size = 564; + break; + case EM28XX_CHIPCFG2_TS_PACKETSIZE_752: + packet_size = 752; + break; + } + } + + em28xx_coredbg("dvb max packet size=%d\n", packet_size); + return packet_size; +} +EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize); + +/* + * em28xx_wake_i2c() + * configure i2c attached devices + */ +void em28xx_wake_i2c(struct em28xx *dev) +{ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, + INPUT(dev->ctl_input)->vmux, 0, 0); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); +} + +/* + * Device control list + */ + +static LIST_HEAD(em28xx_devlist); +static DEFINE_MUTEX(em28xx_devlist_mutex); + +/* + * em28xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +void em28xx_remove_from_devlist(struct em28xx *dev) +{ + mutex_lock(&em28xx_devlist_mutex); + list_del(&dev->devlist); + mutex_unlock(&em28xx_devlist_mutex); +}; + +void em28xx_add_into_devlist(struct em28xx *dev) +{ + mutex_lock(&em28xx_devlist_mutex); + list_add_tail(&dev->devlist, &em28xx_devlist); + mutex_unlock(&em28xx_devlist_mutex); +}; + +/* + * Extension interface + */ + +static LIST_HEAD(em28xx_extension_devlist); + +int em28xx_register_extension(struct em28xx_ops *ops) +{ + struct em28xx *dev = NULL; + + mutex_lock(&em28xx_devlist_mutex); + list_add_tail(&ops->next, &em28xx_extension_devlist); + list_for_each_entry(dev, &em28xx_devlist, devlist) { + ops->init(dev); + } + printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); + mutex_unlock(&em28xx_devlist_mutex); + return 0; +} +EXPORT_SYMBOL(em28xx_register_extension); + +void em28xx_unregister_extension(struct em28xx_ops *ops) +{ + struct em28xx *dev = NULL; + + mutex_lock(&em28xx_devlist_mutex); + list_for_each_entry(dev, &em28xx_devlist, devlist) { + ops->fini(dev); + } + printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); + list_del(&ops->next); + mutex_unlock(&em28xx_devlist_mutex); +} +EXPORT_SYMBOL(em28xx_unregister_extension); + +void em28xx_init_extension(struct em28xx *dev) +{ + struct em28xx_ops *ops = NULL; + + mutex_lock(&em28xx_devlist_mutex); + if (!list_empty(&em28xx_extension_devlist)) { + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->init) + ops->init(dev); + } + } + mutex_unlock(&em28xx_devlist_mutex); +} + +void em28xx_close_extension(struct em28xx *dev) +{ + struct em28xx_ops *ops = NULL; + + mutex_lock(&em28xx_devlist_mutex); + if (!list_empty(&em28xx_extension_devlist)) { + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->fini) + ops->fini(dev); + } + } + mutex_unlock(&em28xx_devlist_mutex); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-dvb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-dvb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-dvb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-dvb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,757 @@ +/* + DVB device driver for em28xx + + (c) 2008 Mauro Carvalho Chehab + + (c) 2008 Devin Heitmueller + - Fixes for the driver to properly work with HVR-950 + - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick + - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600 + + (c) 2008 Aidan Thornton + + Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: + (c) 2004, 2005 Chris Pascoe + (c) 2004 Gerd Knorr [SuSE Labs] + + 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. + */ + +#include +#include +#include + +#include "em28xx.h" +#include +#include +#include +#include "tuner-simple.h" + +#include "lgdt330x.h" +#include "lgdt3305.h" +#include "zl10353.h" +#include "s5h1409.h" +#include "mt352.h" +#include "mt352_priv.h" /* FIXME */ +#include "tda1002x.h" +#include "tda18271.h" +#include "s921.h" +#include "drxd.h" +#include "cxd2820r.h" + +MODULE_DESCRIPTION("driver for em28xx based DVB cards"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages [dvb]"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define dprintk(level, fmt, arg...) do { \ +if (debug >= level) \ + printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ +} while (0) + +#define EM28XX_DVB_NUM_BUFS 5 +#define EM28XX_DVB_MAX_PACKETS 64 + +struct em28xx_dvb { + struct dvb_frontend *fe[2]; + + /* feed count management */ + struct mutex lock; + int nfeeds; + + /* general boilerplate stuff */ + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net net; +}; + + +static inline void print_err_status(struct em28xx *dev, + int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + dprintk(1, "URB status %d [%s].\n", status, errmsg); + } else { + dprintk(1, "URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + +static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) +{ + int i; + + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + for (i = 0; i < urb->number_of_packets; i++) { + int status = urb->iso_frame_desc[i].status; + + if (status < 0) { + print_err_status(dev, i, status); + if (urb->iso_frame_desc[i].status != -EPROTO) + continue; + } + + dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer + + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } + + return 0; +} + +static int start_streaming(struct em28xx_dvb *dvb) +{ + int rc; + struct em28xx *dev = dvb->adapter.priv; + int max_dvb_packet_size; + + usb_set_interface(dev->udev, 0, 1); + rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); + if (rc < 0) + return rc; + + max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev); + + return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, + EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, + dvb_isoc_copy); +} + +static int stop_streaming(struct em28xx_dvb *dvb) +{ + struct em28xx *dev = dvb->adapter.priv; + + em28xx_uninit_isoc(dev); + + em28xx_set_mode(dev, EM28XX_SUSPEND); + + return 0; +} + +static int start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct em28xx_dvb *dvb = demux->priv; + int rc, ret; + + if (!demux->dmx.frontend) + return -EINVAL; + + mutex_lock(&dvb->lock); + dvb->nfeeds++; + rc = dvb->nfeeds; + + if (dvb->nfeeds == 1) { + ret = start_streaming(dvb); + if (ret < 0) + rc = ret; + } + + mutex_unlock(&dvb->lock); + return rc; +} + +static int stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct em28xx_dvb *dvb = demux->priv; + int err = 0; + + mutex_lock(&dvb->lock); + dvb->nfeeds--; + + if (0 == dvb->nfeeds) + err = stop_streaming(dvb); + + mutex_unlock(&dvb->lock); + return err; +} + + + +/* ------------------------------------------------------------------ */ +static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct em28xx *dev = fe->dvb->priv; + + if (acquire) + return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); + else + return em28xx_set_mode(dev, EM28XX_SUSPEND); +} + +/* ------------------------------------------------------------------ */ + +static struct lgdt330x_config em2880_lgdt3303_dev = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, +}; + +static struct lgdt3305_config em2870_lgdt3304_dev = { + .i2c_addr = 0x0e, + .demod_chip = LGDT3304, + .spectral_inversion = 1, + .deny_i2c_rptr = 1, + .mpeg_mode = LGDT3305_MPEG_PARALLEL, + .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .vsb_if_khz = 3250, + .qam_if_khz = 4000, +}; + +static struct s921_config sharp_isdbt = { + .demod_address = 0x30 >> 1 +}; + +static struct zl10353_config em28xx_zl10353_with_xc3028 = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .parallel_ts = 1, + .if2 = 45600, +}; + +static struct s5h1409_config em28xx_s5h1409_with_xc3028 = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_PARALLEL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK +}; + +static struct tda18271_std_map kworld_a340_std_map = { + .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 0, + .if_lvl = 1, .rfagc_top = 0x37, }, + .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 1, + .if_lvl = 1, .rfagc_top = 0x37, }, +}; + +static struct tda18271_config kworld_a340_config = { + .std_map = &kworld_a340_std_map, +}; + +static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .disable_i2c_gate_ctrl = 1, + .parallel_ts = 1, + .if2 = 45600, +}; + +static struct drxd_config em28xx_drxd = { + .index = 0, .demod_address = 0x70, .demod_revision = 0xa2, + .demoda_address = 0x00, .pll_address = 0x00, + .pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1, + .pll_set = NULL, .osc_deviation = NULL, .IF = 42800000, + .disable_i2c_gate_ctrl = 1, +}; + +static int mt352_terratec_xs_init(struct dvb_frontend *fe) +{ + /* Values extracted from a USB trace of the Terratec Windows driver */ + static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x2c }; + static u8 reset[] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0xa0 }; + static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 }; + static u8 rs_err_cfg[] = { RS_ERR_PER_1, 0x00, 0x4d }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + static u8 trl_nom_cfg[] = { TRL_NOMINAL_RATE_1, 0x64, 0x00 }; + static u8 tps_given_cfg[] = { TPS_GIVEN_1, 0x40, 0x80, 0x50 }; + static u8 tuner_go[] = { TUNER_GO, 0x01}; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg)); + mt352_write(fe, rs_err_cfg, sizeof(rs_err_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + mt352_write(fe, trl_nom_cfg, sizeof(trl_nom_cfg)); + mt352_write(fe, tps_given_cfg, sizeof(tps_given_cfg)); + mt352_write(fe, tuner_go, sizeof(tuner_go)); + return 0; +} + +static struct mt352_config terratec_xs_mt352_cfg = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .if2 = 45600, + .demod_init = mt352_terratec_xs_init, +}; + +static struct tda10023_config em28xx_tda10023_config = { + .demod_address = 0x0c, + .invert = 1, +}; + +static struct cxd2820r_config em28xx_cxd2820r_config = { + .i2c_address = (0xd8 >> 1), + .ts_mode = CXD2820R_TS_SERIAL, + .if_dvbt_6 = 3300, + .if_dvbt_7 = 3500, + .if_dvbt_8 = 4000, + .if_dvbt2_6 = 3300, + .if_dvbt2_7 = 3500, + .if_dvbt2_8 = 4000, + .if_dvbc = 5000, + + /* enable LNA for DVB-T2 and DVB-C */ + .gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L, + .gpio_dvbc[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L, +}; + +static struct tda18271_config em28xx_cxd2820r_tda18271_config = { + .output_opt = TDA18271_OUTPUT_LT_OFF, +}; + +/* ------------------------------------------------------------------ */ + +static int attach_xc3028(u8 addr, struct em28xx *dev) +{ + struct dvb_frontend *fe; + struct xc2028_config cfg; + + memset(&cfg, 0, sizeof(cfg)); + cfg.i2c_adap = &dev->i2c_adap; + cfg.i2c_addr = addr; + + if (!dev->dvb->fe[0]) { + em28xx_errdev("/2: dvb frontend not attached. " + "Can't attach xc3028\n"); + return -EINVAL; + } + + fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg); + if (!fe) { + em28xx_errdev("/2: xc3028 attach failed\n"); + dvb_frontend_detach(dev->dvb->fe[0]); + dev->dvb->fe[0] = NULL; + return -EINVAL; + } + + em28xx_info("%s/2: xc3028 attached\n", dev->name); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int register_dvb(struct em28xx_dvb *dvb, + struct module *module, + struct em28xx *dev, + struct device *device) +{ + int result; + + mutex_init(&dvb->lock); + + /* register adapter */ + result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, + adapter_nr); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", + dev->name, result); + goto fail_adapter; + } + + /* Ensure all frontends negotiate bus access */ + dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; + if (dvb->fe[1]) + dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; + + dvb->adapter.priv = dev; + + /* register frontend */ + result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", + dev->name, result); + goto fail_frontend0; + } + + /* register 2nd frontend */ + if (dvb->fe[1]) { + result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]); + if (result < 0) { + printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n", + dev->name, result); + goto fail_frontend1; + } + } + + /* register demux stuff */ + dvb->demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + dvb->demux.priv = dvb; + dvb->demux.filternum = 256; + dvb->demux.feednum = 256; + dvb->demux.start_feed = start_feed; + dvb->demux.stop_feed = stop_feed; + + result = dvb_dmx_init(&dvb->demux); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", + dev->name, result); + goto fail_dmx; + } + + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = &dvb->demux.dmx; + dvb->dmxdev.capabilities = 0; + result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", + dev->name, result); + goto fail_dmxdev; + } + + dvb->fe_hw.source = DMX_FRONTEND_0; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", + dev->name, result); + goto fail_fe_hw; + } + + dvb->fe_mem.source = DMX_MEMORY_FE; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); + if (result < 0) { + printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", + dev->name, result); + goto fail_fe_mem; + } + + result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", + dev->name, result); + goto fail_fe_conn; + } + + /* register network adapter */ + dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); + return 0; + +fail_fe_conn: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); +fail_fe_mem: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); +fail_fe_hw: + dvb_dmxdev_release(&dvb->dmxdev); +fail_dmxdev: + dvb_dmx_release(&dvb->demux); +fail_dmx: + if (dvb->fe[1]) + dvb_unregister_frontend(dvb->fe[1]); + dvb_unregister_frontend(dvb->fe[0]); +fail_frontend1: + if (dvb->fe[1]) + dvb_frontend_detach(dvb->fe[1]); +fail_frontend0: + dvb_frontend_detach(dvb->fe[0]); + dvb_unregister_adapter(&dvb->adapter); +fail_adapter: + return result; +} + +static void unregister_dvb(struct em28xx_dvb *dvb) +{ + dvb_net_release(&dvb->net); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(&dvb->demux); + if (dvb->fe[1]) + dvb_unregister_frontend(dvb->fe[1]); + dvb_unregister_frontend(dvb->fe[0]); + if (dvb->fe[1]) + dvb_frontend_detach(dvb->fe[1]); + dvb_frontend_detach(dvb->fe[0]); + dvb_unregister_adapter(&dvb->adapter); +} + +static int dvb_init(struct em28xx *dev) +{ + int result = 0; + struct em28xx_dvb *dvb; + + if (!dev->board.has_dvb) { + /* This device does not support the extension */ + printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n"); + return 0; + } + + dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); + + if (dvb == NULL) { + em28xx_info("em28xx_dvb: memory allocation failed\n"); + return -ENOMEM; + } + dev->dvb = dvb; + dvb->fe[0] = dvb->fe[1] = NULL; + + mutex_lock(&dev->lock); + em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); + /* init frontend */ + switch (dev->model) { + case EM2874_BOARD_LEADERSHIP_ISDBT: + dvb->fe[0] = dvb_attach(s921_attach, + &sharp_isdbt, &dev->i2c_adap); + + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + + break; + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: + dvb->fe[0] = dvb_attach(lgdt330x_attach, + &em2880_lgdt3303_dev, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; + case EM2880_BOARD_KWORLD_DVB_310U: + dvb->fe[0] = dvb_attach(zl10353_attach, + &em28xx_zl10353_with_xc3028, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2882_BOARD_TERRATEC_HYBRID_XS: + case EM2880_BOARD_EMPIRE_DUAL_TV: + dvb->fe[0] = dvb_attach(zl10353_attach, + &em28xx_zl10353_xc3028_no_i2c_gate, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; + case EM2880_BOARD_TERRATEC_HYBRID_XS: + case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: + case EM2881_BOARD_PINNACLE_HYBRID_PRO: + case EM2882_BOARD_DIKOM_DK300: + case EM2882_BOARD_KWORLD_VS_DVBT: + dvb->fe[0] = dvb_attach(zl10353_attach, + &em28xx_zl10353_xc3028_no_i2c_gate, + &dev->i2c_adap); + if (dvb->fe[0] == NULL) { + /* This board could have either a zl10353 or a mt352. + If the chip id isn't for zl10353, try mt352 */ + dvb->fe[0] = dvb_attach(mt352_attach, + &terratec_xs_mt352_cfg, + &dev->i2c_adap); + } + + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; + case EM2883_BOARD_KWORLD_HYBRID_330U: + case EM2882_BOARD_EVGA_INDTUBE: + dvb->fe[0] = dvb_attach(s5h1409_attach, + &em28xx_s5h1409_with_xc3028, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; + case EM2882_BOARD_KWORLD_ATSC_315U: + dvb->fe[0] = dvb_attach(lgdt330x_attach, + &em2880_lgdt3303_dev, + &dev->i2c_adap); + if (dvb->fe[0] != NULL) { + if (!dvb_attach(simple_tuner_attach, dvb->fe[0], + &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) { + result = -EINVAL; + goto out_free; + } + } + break; + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: + case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: + dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL, + &dev->i2c_adap, &dev->udev->dev); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; + case EM2870_BOARD_REDDO_DVB_C_USB_BOX: + /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ + dvb->fe[0] = dvb_attach(tda10023_attach, + &em28xx_tda10023_config, + &dev->i2c_adap, 0x48); + if (dvb->fe[0]) { + if (!dvb_attach(simple_tuner_attach, dvb->fe[0], + &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) { + result = -EINVAL; + goto out_free; + } + } + break; + case EM2870_BOARD_KWORLD_A340: + dvb->fe[0] = dvb_attach(lgdt3305_attach, + &em2870_lgdt3304_dev, + &dev->i2c_adap); + if (dvb->fe[0] != NULL) + dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + &dev->i2c_adap, &kworld_a340_config); + break; + case EM28174_BOARD_PCTV_290E: + /* MFE + * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */ + /* FE 0 */ + dvb->fe[0] = dvb_attach(cxd2820r_attach, + &em28xx_cxd2820r_config, &dev->i2c_adap, NULL); + if (dvb->fe[0]) { + struct i2c_adapter *i2c_tuner; + i2c_tuner = cxd2820r_get_tuner_i2c_adapter(dvb->fe[0]); + /* FE 0 attach tuner */ + if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { + dvb_frontend_detach(dvb->fe[0]); + result = -EINVAL; + goto out_free; + } + /* FE 1. This dvb_attach() cannot fail. */ + dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL, + dvb->fe[0]); + dvb->fe[1]->id = 1; + /* FE 1 attach tuner */ + if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60, + i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { + dvb_frontend_detach(dvb->fe[1]); + /* leave FE 0 still active */ + } + } + break; + default: + em28xx_errdev("/2: The frontend of your DVB/ATSC card" + " isn't supported yet\n"); + break; + } + if (NULL == dvb->fe[0]) { + em28xx_errdev("/2: frontend initialization failed\n"); + result = -EINVAL; + goto out_free; + } + /* define general-purpose callback pointer */ + dvb->fe[0]->callback = em28xx_tuner_callback; + + /* register everything */ + result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); + + if (result < 0) + goto out_free; + + em28xx_info("Successfully loaded em28xx-dvb\n"); +ret: + em28xx_set_mode(dev, EM28XX_SUSPEND); + mutex_unlock(&dev->lock); + return result; + +out_free: + kfree(dvb); + dev->dvb = NULL; + goto ret; +} + +static int dvb_fini(struct em28xx *dev) +{ + if (!dev->board.has_dvb) { + /* This device does not support the extension */ + return 0; + } + + if (dev->dvb) { + unregister_dvb(dev->dvb); + kfree(dev->dvb); + dev->dvb = NULL; + } + + return 0; +} + +static struct em28xx_ops dvb_ops = { + .id = EM28XX_DVB, + .name = "Em28xx dvb Extension", + .init = dvb_init, + .fini = dvb_fini, +}; + +static int __init em28xx_dvb_register(void) +{ + return em28xx_register_extension(&dvb_ops); +} + +static void __exit em28xx_dvb_unregister(void) +{ + em28xx_unregister_extension(&dvb_ops); +} + +module_init(em28xx_dvb_register); +module_exit(em28xx_dvb_unregister); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,845 @@ +/* + em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices + + Copyright (C) 2005 Markus Rechberger + Ludovico Cavedon + Mauro Carvalho Chehab + + Based on the em2800 driver from Sascha Sommer + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _EM28XX_H +#define _EM28XX_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) +#include +#endif +#include "tuner-xc2028.h" +#include "em28xx-reg.h" + +/* Boards supported by driver */ +#define EM2800_BOARD_UNKNOWN 0 +#define EM2820_BOARD_UNKNOWN 1 +#define EM2820_BOARD_TERRATEC_CINERGY_250 2 +#define EM2820_BOARD_PINNACLE_USB_2 3 +#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 +#define EM2820_BOARD_MSI_VOX_USB_2 5 +#define EM2800_BOARD_TERRATEC_CINERGY_200 6 +#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 +#define EM2800_BOARD_KWORLD_USB2800 8 +#define EM2820_BOARD_PINNACLE_DVC_90 9 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 +#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 +#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 +#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 +#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 +#define EM2800_BOARD_VGEAR_POCKETTV 15 +#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16 +#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 +#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19 +#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 +#define EM2800_BOARD_GRABBEEX_USB2800 21 +#define EM2750_BOARD_UNKNOWN 22 +#define EM2750_BOARD_DLCW_130 23 +#define EM2820_BOARD_DLINK_USB_TV 24 +#define EM2820_BOARD_GADMEI_UTV310 25 +#define EM2820_BOARD_HERCULES_SMART_TV_USB2 26 +#define EM2820_BOARD_PINNACLE_USB_2_FM1216ME 27 +#define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28 +#define EM2860_BOARD_TVP5150_REFERENCE_DESIGN 29 +#define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30 +#define EM2821_BOARD_USBGEAR_VD204 31 +#define EM2821_BOARD_SUPERCOMP_USB_2 32 +#define EM2860_BOARD_ELGATO_VIDEO_CAPTURE 33 +#define EM2860_BOARD_TERRATEC_HYBRID_XS 34 +#define EM2860_BOARD_TYPHOON_DVD_MAKER 35 +#define EM2860_BOARD_NETGMBH_CAM 36 +#define EM2860_BOARD_GADMEI_UTV330 37 +#define EM2861_BOARD_YAKUMO_MOVIE_MIXER 38 +#define EM2861_BOARD_KWORLD_PVRTV_300U 39 +#define EM2861_BOARD_PLEXTOR_PX_TV100U 40 +#define EM2870_BOARD_KWORLD_350U 41 +#define EM2870_BOARD_KWORLD_355U 42 +#define EM2870_BOARD_TERRATEC_XS 43 +#define EM2870_BOARD_TERRATEC_XS_MT2060 44 +#define EM2870_BOARD_PINNACLE_PCTV_DVB 45 +#define EM2870_BOARD_COMPRO_VIDEOMATE 46 +#define EM2880_BOARD_KWORLD_DVB_305U 47 +#define EM2880_BOARD_KWORLD_DVB_310U 48 +#define EM2880_BOARD_MSI_DIGIVOX_AD 49 +#define EM2880_BOARD_MSI_DIGIVOX_AD_II 50 +#define EM2880_BOARD_TERRATEC_HYBRID_XS_FR 51 +#define EM2881_BOARD_DNT_DA2_HYBRID 52 +#define EM2881_BOARD_PINNACLE_HYBRID_PRO 53 +#define EM2882_BOARD_KWORLD_VS_DVBT 54 +#define EM2882_BOARD_TERRATEC_HYBRID_XS 55 +#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56 +#define EM2883_BOARD_KWORLD_HYBRID_330U 57 +#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 +#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 +#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61 +#define EM2820_BOARD_GADMEI_TVR200 62 +#define EM2860_BOARD_KAIOMY_TVNPC_U2 63 +#define EM2860_BOARD_EASYCAP 64 +#define EM2820_BOARD_IODATA_GVMVP_SZ 65 +#define EM2880_BOARD_EMPIRE_DUAL_TV 66 +#define EM2860_BOARD_TERRATEC_GRABBY 67 +#define EM2860_BOARD_TERRATEC_AV350 68 +#define EM2882_BOARD_KWORLD_ATSC_315U 69 +#define EM2882_BOARD_EVGA_INDTUBE 70 +#define EM2820_BOARD_SILVERCREST_WEBCAM 71 +#define EM2861_BOARD_GADMEI_UTV330PLUS 72 +#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73 +#define EM2800_BOARD_VC211A 74 +#define EM2882_BOARD_DIKOM_DK300 75 +#define EM2870_BOARD_KWORLD_A340 76 +#define EM2874_BOARD_LEADERSHIP_ISDBT 77 +#define EM28174_BOARD_PCTV_290E 78 + + +/* Limits minimum and default number of buffers */ +#define EM28XX_MIN_BUF 4 +#define EM28XX_DEF_BUF 8 + +/*Limits the max URB message size */ +#define URB_MAX_CTRL_SIZE 80 + +/* Params for validated field */ +#define EM28XX_BOARD_NOT_VALIDATED 1 +#define EM28XX_BOARD_VALIDATED 0 + +/* Params for em28xx_cmd() audio */ +#define EM28XX_START_AUDIO 1 +#define EM28XX_STOP_AUDIO 0 + +/* maximum number of em28xx boards */ +#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ + +/* maximum number of frames that can be queued */ +#define EM28XX_NUM_FRAMES 5 +/* number of frames that get used for v4l2_read() */ +#define EM28XX_NUM_READ_FRAMES 2 + +/* number of buffers for isoc transfers */ +#define EM28XX_NUM_BUFS 5 + +/* number of packets for each buffer + windows requests only 64 packets .. so we better do the same + this is what I found out for all alternate numbers there! + */ +#define EM28XX_NUM_PACKETS 64 + +#define EM28XX_INTERLACED_DEFAULT 1 + +/* +#define (use usbview if you want to get the other alternate number infos) +#define +#define alternate number 2 +#define Endpoint Address: 82 + Direction: in + Attribute: 1 + Type: Isoc + Max Packet Size: 1448 + Interval: 125us + + alternate number 7 + + Endpoint Address: 82 + Direction: in + Attribute: 1 + Type: Isoc + Max Packet Size: 3072 + Interval: 125us +*/ + +/* time to wait when stopping the isoc transfer */ +#define EM28XX_URB_TIMEOUT \ + msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS) + +/* time in msecs to wait for i2c writes to finish */ +#define EM2800_I2C_WRITE_TIMEOUT 20 + +enum em28xx_mode { + EM28XX_SUSPEND, + EM28XX_ANALOG_MODE, + EM28XX_DIGITAL_MODE, +}; + + +struct em28xx; + +struct em28xx_usb_isoc_ctl { + /* max packet size of isoc transaction */ + int max_pkt_size; + + /* number of allocated urbs */ + int num_bufs; + + /* urb for isoc transfers */ + struct urb **urb; + + /* transfer buffers for isoc transfer */ + char **transfer_buffer; + + /* Last buffer command and region */ + u8 cmd; + int pos, size, pktsize; + + /* Last field: ODD or EVEN? */ + int field; + + /* Stores incomplete commands */ + u32 tmp_buf; + int tmp_buf_len; + + /* Stores already requested buffers */ + struct em28xx_buffer *vid_buf; + struct em28xx_buffer *vbi_buf; + + /* Stores the number of received fields */ + int nfields; + + /* isoc urb callback */ + int (*isoc_copy) (struct em28xx *dev, struct urb *urb); + +}; + +/* Struct to enumberate video formats */ +struct em28xx_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int reg; +}; + +/* buffer for one video frame */ +struct em28xx_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + struct list_head frame; + int top_field; + int receiving; +}; + +struct em28xx_dmaqueue { + struct list_head active; + struct list_head queued; + + wait_queue_head_t wq; + + /* Counters to control buffer fill */ + int pos; +}; + +/* io methods */ +enum em28xx_io_method { + IO_NONE, + IO_READ, + IO_MMAP, +}; + +/* inputs */ + +#define MAX_EM28XX_INPUT 4 +enum enum28xx_itype { + EM28XX_VMUX_COMPOSITE1 = 1, + EM28XX_VMUX_COMPOSITE2, + EM28XX_VMUX_COMPOSITE3, + EM28XX_VMUX_COMPOSITE4, + EM28XX_VMUX_SVIDEO, + EM28XX_VMUX_TELEVISION, + EM28XX_VMUX_CABLE, + EM28XX_VMUX_DVB, + EM28XX_VMUX_DEBUG, + EM28XX_RADIO, +}; + +enum em28xx_ac97_mode { + EM28XX_NO_AC97 = 0, + EM28XX_AC97_EM202, + EM28XX_AC97_SIGMATEL, + EM28XX_AC97_OTHER, +}; + +struct em28xx_audio_mode { + enum em28xx_ac97_mode ac97; + + u16 ac97_feat; + u32 ac97_vendor_id; + + unsigned int has_audio:1; + + unsigned int i2s_3rates:1; + unsigned int i2s_5rates:1; +}; + +/* em28xx has two audio inputs: tuner and line in. + However, on most devices, an auxiliary AC97 codec device is used. + The AC97 device may have several different inputs and outputs, + depending on their model. So, it is possible to use AC97 mixer to + address more than two different entries. + */ +enum em28xx_amux { + /* This is the only entry for em28xx tuner input */ + EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */ + + EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */ + + /* Some less-common mixer setups */ + EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */ + EM28XX_AMUX_PHONE, + EM28XX_AMUX_MIC, + EM28XX_AMUX_CD, + EM28XX_AMUX_AUX, + EM28XX_AMUX_PCM_OUT, +}; + +enum em28xx_aout { + /* AC97 outputs */ + EM28XX_AOUT_MASTER = 1 << 0, + EM28XX_AOUT_LINE = 1 << 1, + EM28XX_AOUT_MONO = 1 << 2, + EM28XX_AOUT_LFE = 1 << 3, + EM28XX_AOUT_SURR = 1 << 4, + + /* PCM IN Mixer - used by AC97_RECORD_SELECT register */ + EM28XX_AOUT_PCM_IN = 1 << 7, + + /* Bits 10-8 are used to indicate the PCM IN record select */ + EM28XX_AOUT_PCM_MIC_PCM = 0 << 8, + EM28XX_AOUT_PCM_CD = 1 << 8, + EM28XX_AOUT_PCM_VIDEO = 2 << 8, + EM28XX_AOUT_PCM_AUX = 3 << 8, + EM28XX_AOUT_PCM_LINE = 4 << 8, + EM28XX_AOUT_PCM_STEREO = 5 << 8, + EM28XX_AOUT_PCM_MONO = 6 << 8, + EM28XX_AOUT_PCM_PHONE = 7 << 8, +}; + +static inline int ac97_return_record_select(int a_out) +{ + return (a_out & 0x700) >> 8; +} + +struct em28xx_reg_seq { + int reg; + unsigned char val, mask; + int sleep; +}; + +struct em28xx_input { + enum enum28xx_itype type; + unsigned int vmux; + enum em28xx_amux amux; + enum em28xx_aout aout; + struct em28xx_reg_seq *gpio; +}; + +#define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) + +enum em28xx_decoder { + EM28XX_NODECODER = 0, + EM28XX_TVP5150, + EM28XX_SAA711X, +}; + +enum em28xx_sensor { + EM28XX_NOSENSOR = 0, + EM28XX_MT9V011, + EM28XX_MT9M001, + EM28XX_MT9M111, +}; + +enum em28xx_adecoder { + EM28XX_NOADECODER = 0, + EM28XX_TVAUDIO, +}; + +struct em28xx_board { + char *name; + int vchannels; + int tuner_type; + int tuner_addr; + + /* i2c flags */ + unsigned int tda9887_conf; + + /* GPIO sequences */ + struct em28xx_reg_seq *dvb_gpio; + struct em28xx_reg_seq *suspend_gpio; + struct em28xx_reg_seq *tuner_gpio; + struct em28xx_reg_seq *mute_gpio; + + unsigned int is_em2800:1; + unsigned int has_msp34xx:1; + unsigned int mts_firmware:1; + unsigned int max_range_640_480:1; + unsigned int has_dvb:1; + unsigned int has_snapshot_button:1; + unsigned int is_webcam:1; + unsigned int valid:1; + unsigned int has_ir_i2c:1; + + unsigned char xclk, i2c_speed; + unsigned char radio_addr; + unsigned short tvaudio_addr; + + enum em28xx_decoder decoder; + enum em28xx_adecoder adecoder; + + struct em28xx_input input[MAX_EM28XX_INPUT]; + struct em28xx_input radio; + char *ir_codes; +}; + +struct em28xx_eeprom { + u32 id; /* 0x9567eb1a */ + u16 vendor_ID; + u16 product_ID; + + u16 chip_conf; + + u16 board_conf; + + u16 string1, string2, string3; + + u8 string_idx_table; +}; + +/* device states */ +enum em28xx_dev_state { + DEV_INITIALIZED = 0x01, + DEV_DISCONNECTED = 0x02, + DEV_MISCONFIGURED = 0x04, +}; + +#define EM28XX_AUDIO_BUFS 5 +#define EM28XX_NUM_AUDIO_PACKETS 64 +#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */ +#define EM28XX_CAPTURE_STREAM_EN 1 + +/* em28xx extensions */ +#define EM28XX_AUDIO 0x10 +#define EM28XX_DVB 0x20 + +/* em28xx resource types (used for res_get/res_lock etc */ +#define EM28XX_RESOURCE_VIDEO 0x01 +#define EM28XX_RESOURCE_VBI 0x02 + +struct em28xx_audio { + char name[50]; + char *transfer_buffer[EM28XX_AUDIO_BUFS]; + struct urb *urb[EM28XX_AUDIO_BUFS]; + struct usb_device *udev; + unsigned int capture_transfer_done; + struct snd_pcm_substream *capture_pcm_substream; + + unsigned int hwptr_done_capture; + struct snd_card *sndcard; + + int users; + spinlock_t slock; +}; + +struct em28xx; + +struct em28xx_fh { + struct em28xx *dev; + int radio; + unsigned int resources; + + struct videobuf_queue vb_vidq; + struct videobuf_queue vb_vbiq; + + enum v4l2_buf_type type; +}; + +/* main device struct */ +struct em28xx { + /* generic device properties */ + char name[30]; /* name (including minor) of the device */ + int model; /* index in the device_data struct */ + int devno; /* marks the number of this device */ + enum em28xx_chip_id chip_id; + + int audio_ifnum; + + struct v4l2_device v4l2_dev; + struct em28xx_board board; + + /* Webcam specific fields */ + enum em28xx_sensor em28xx_sensor; + int sensor_xres, sensor_yres; + int sensor_xtal; + + /* Allows progressive (e. g. non-interlaced) mode */ + int progressive; + + /* Vinmode/Vinctl used at the driver */ + int vinmode, vinctl; + + unsigned int has_audio_class:1; + unsigned int has_alsa_audio:1; + unsigned int is_audio_only:1; + + /* Controls audio streaming */ + struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ + atomic_t stream_started; /* stream should be running if true */ + + struct em28xx_fmt *format; + + struct em28xx_IR *ir; + + /* Some older em28xx chips needs a waiting time after writing */ + unsigned int wait_after_write; + + struct list_head devlist; + + u32 i2s_speed; /* I2S speed for audio digital stream */ + + struct em28xx_audio_mode audio_mode; + + int tuner_type; /* type of the tuner */ + int tuner_addr; /* tuner address */ + int tda9887_conf; + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_client i2c_client; + /* video for linux */ + int users; /* user count for exclusive use */ + struct video_device *vdev; /* video for linux device struct */ + v4l2_std_id norm; /* selected tv norm */ + int ctl_freq; /* selected frequency */ + unsigned int ctl_input; /* selected input */ + unsigned int ctl_ainput;/* selected audio input */ + unsigned int ctl_aoutput;/* selected audio output */ + int mute; + int volume; + /* frame properties */ + int width; /* current frame width */ + int height; /* current frame height */ + unsigned hscale; /* horizontal scale factor (see datasheet) */ + unsigned vscale; /* vertical scale factor (see datasheet) */ + int interlaced; /* 1=interlace fileds, 0=just top fileds */ + unsigned int video_bytesread; /* Number of bytes read */ + + unsigned long hash; /* eeprom hash - for boards with generic ID */ + unsigned long i2c_hash; /* i2c devicelist hash - + for boards with generic ID */ + + struct em28xx_audio adev; + + /* states */ + enum em28xx_dev_state state; + enum em28xx_io_method io; + + /* vbi related state tracking */ + int capture_type; + int vbi_read; + unsigned char cur_field; + unsigned int vbi_width; + unsigned int vbi_height; /* lines per field */ + + struct work_struct request_module_wk; + + /* locks */ + struct mutex lock; + struct mutex ctrl_urb_lock; /* protects urb_buf */ + /* spinlock_t queue_lock; */ + struct list_head inqueue, outqueue; + wait_queue_head_t open, wait_frame, wait_stream; + struct video_device *vbi_dev; + struct video_device *radio_dev; + + /* resources in use */ + unsigned int resources; + + unsigned char eedata[256]; + + /* Isoc control struct */ + struct em28xx_dmaqueue vidq; + struct em28xx_dmaqueue vbiq; + struct em28xx_usb_isoc_ctl isoc_ctl; + spinlock_t slock; + + /* usb transfer */ + struct usb_device *udev; /* the usb device */ + int alt; /* alternate */ + int max_pkt_size; /* max packet size of isoc transaction */ + int num_alt; /* Number of alternative settings */ + unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ + struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ + char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc + transfer */ + char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ + + /* helper funcs that call usb_control_msg */ + int (*em28xx_write_regs) (struct em28xx *dev, u16 reg, + char *buf, int len); + int (*em28xx_read_reg) (struct em28xx *dev, u16 reg); + int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg, + char *buf, int len); + int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg, + char *buf, int len); + int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg); + + enum em28xx_mode mode; + + /* register numbers for GPO/GPIO registers */ + u16 reg_gpo_num, reg_gpio_num; + + /* Caches GPO and GPIO registers */ + unsigned char reg_gpo, reg_gpio; + + /* Snapshot button */ + char snapshot_button_path[30]; /* path of the input dev */ + struct input_dev *sbutton_input_dev; + struct delayed_work sbutton_query_work; + + struct em28xx_dvb *dvb; + + /* I2C keyboard data */ + struct IR_i2c_init_data init_data; +}; + +struct em28xx_ops { + struct list_head next; + char *name; + int id; + int (*init)(struct em28xx *); + int (*fini)(struct em28xx *); +}; + +/* Provided by em28xx-i2c.c */ +void em28xx_do_i2c_scan(struct em28xx *dev); +int em28xx_i2c_register(struct em28xx *dev); +int em28xx_i2c_unregister(struct em28xx *dev); + +/* Provided by em28xx-core.c */ + +u32 em28xx_request_buffers(struct em28xx *dev, u32 count); +void em28xx_queue_unusedframes(struct em28xx *dev); +void em28xx_release_buffers(struct em28xx *dev); + +int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, + char *buf, int len); +int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg); +int em28xx_read_reg(struct em28xx *dev, u16 reg); +int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, + int len); +int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); +int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); +int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, + u8 bitmask); + +int em28xx_read_ac97(struct em28xx *dev, u8 reg); +int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); + +int em28xx_audio_analog_set(struct em28xx *dev); +int em28xx_audio_setup(struct em28xx *dev); + +int em28xx_colorlevels_set_default(struct em28xx *dev); +int em28xx_capture_start(struct em28xx *dev, int start); +int em28xx_vbi_supported(struct em28xx *dev); +int em28xx_set_outfmt(struct em28xx *dev); +int em28xx_resolution_set(struct em28xx *dev); +int em28xx_set_alternate(struct em28xx *dev); +int em28xx_init_isoc(struct em28xx *dev, int max_packets, + int num_bufs, int max_pkt_size, + int (*isoc_copy) (struct em28xx *dev, struct urb *urb)); +void em28xx_uninit_isoc(struct em28xx *dev); +int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); +int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); +int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); +void em28xx_wake_i2c(struct em28xx *dev); +void em28xx_remove_from_devlist(struct em28xx *dev); +void em28xx_add_into_devlist(struct em28xx *dev); +int em28xx_register_extension(struct em28xx_ops *dev); +void em28xx_unregister_extension(struct em28xx_ops *dev); +void em28xx_init_extension(struct em28xx *dev); +void em28xx_close_extension(struct em28xx *dev); + +/* Provided by em28xx-video.c */ +int em28xx_register_analog_devices(struct em28xx *dev); +void em28xx_release_analog_resources(struct em28xx *dev); + +/* Provided by em28xx-cards.c */ +extern int em2800_variant_detect(struct usb_device *udev, int model); +extern void em28xx_pre_card_setup(struct em28xx *dev); +extern void em28xx_card_setup(struct em28xx *dev); +extern struct em28xx_board em28xx_boards[]; +extern struct usb_device_id em28xx_id_table[]; +extern const unsigned int em28xx_bcount; +void em28xx_register_i2c_ir(struct em28xx *dev); +int em28xx_tuner_callback(void *ptr, int component, int command, int arg); +void em28xx_release_resources(struct em28xx *dev); + +/* Provided by em28xx-input.c */ + +#ifdef CONFIG_VIDEO_EM28XX_RC + +int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); +int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); +int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, + u32 *ir_raw); +int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key, + u32 *ir_raw); +void em28xx_register_snapshot_button(struct em28xx *dev); +void em28xx_deregister_snapshot_button(struct em28xx *dev); + +int em28xx_ir_init(struct em28xx *dev); +int em28xx_ir_fini(struct em28xx *dev); + +#else + +#define em28xx_get_key_terratec NULL +#define em28xx_get_key_em_haup NULL +#define em28xx_get_key_pinnacle_usb_grey NULL +#define em28xx_get_key_winfast_usbii_deluxe NULL + +static inline void em28xx_register_snapshot_button(struct em28xx *dev) {} +static inline void em28xx_deregister_snapshot_button(struct em28xx *dev) {} +static inline int em28xx_ir_init(struct em28xx *dev) { return 0; } +static inline int em28xx_ir_fini(struct em28xx *dev) { return 0; } + +#endif + +/* Provided by em28xx-vbi.c */ +extern struct videobuf_queue_ops em28xx_vbi_qops; + +/* printk macros */ + +#define em28xx_err(fmt, arg...) do {\ + printk(KERN_ERR fmt , ##arg); } while (0) + +#define em28xx_errdev(fmt, arg...) do {\ + printk(KERN_ERR "%s: "fmt,\ + dev->name , ##arg); } while (0) + +#define em28xx_info(fmt, arg...) do {\ + printk(KERN_INFO "%s: "fmt,\ + dev->name , ##arg); } while (0) +#define em28xx_warn(fmt, arg...) do {\ + printk(KERN_WARNING "%s: "fmt,\ + dev->name , ##arg); } while (0) + +static inline int em28xx_compression_disable(struct em28xx *dev) +{ + /* side effect of disabling scaler and mixer */ + return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00); +} + +static inline int em28xx_contrast_get(struct em28xx *dev) +{ + return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f; +} + +static inline int em28xx_brightness_get(struct em28xx *dev) +{ + return em28xx_read_reg(dev, EM28XX_R21_YOFFSET); +} + +static inline int em28xx_saturation_get(struct em28xx *dev) +{ + return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f; +} + +static inline int em28xx_u_balance_get(struct em28xx *dev) +{ + return em28xx_read_reg(dev, EM28XX_R23_UOFFSET); +} + +static inline int em28xx_v_balance_get(struct em28xx *dev) +{ + return em28xx_read_reg(dev, EM28XX_R24_VOFFSET); +} + +static inline int em28xx_gamma_get(struct em28xx *dev) +{ + return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f; +} + +static inline int em28xx_contrast_set(struct em28xx *dev, s32 val) +{ + u8 tmp = (u8) val; + return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1); +} + +static inline int em28xx_brightness_set(struct em28xx *dev, s32 val) +{ + u8 tmp = (u8) val; + return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1); +} + +static inline int em28xx_saturation_set(struct em28xx *dev, s32 val) +{ + u8 tmp = (u8) val; + return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1); +} + +static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val) +{ + u8 tmp = (u8) val; + return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1); +} + +static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val) +{ + u8 tmp = (u8) val; + return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1); +} + +static inline int em28xx_gamma_set(struct em28xx *dev, s32 val) +{ + u8 tmp = (u8) val; + return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1); +} + +/*FIXME: maxw should be dependent of alt mode */ +static inline unsigned int norm_maxw(struct em28xx *dev) +{ + if (dev->board.is_webcam) + return dev->sensor_xres; + + if (dev->board.max_range_640_480 || dev->board.is_em2800) + return 640; + + return 720; +} + +static inline unsigned int norm_maxh(struct em28xx *dev) +{ + if (dev->board.is_webcam) + return dev->sensor_yres; + + if (dev->board.max_range_640_480) + return 480; + + return (dev->norm & V4L2_STD_625_50) ? 576 : 480; +} +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,567 @@ +/* + em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices + + Copyright (C) 2005 Ludovico Cavedon + Markus Rechberger + Mauro Carvalho Chehab + Sascha Sommer + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "em28xx.h" +#include "tuner-xc2028.h" +#include +#include + +/* ----------------------------------------------------------- */ + +static unsigned int i2c_scan; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); + +static unsigned int i2c_debug; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + + +#define dprintk1(lvl, fmt, args...) \ +do { \ + if (i2c_debug >= lvl) { \ + printk(fmt, ##args); \ + } \ +} while (0) + +#define dprintk2(lvl, fmt, args...) \ +do { \ + if (i2c_debug >= lvl) { \ + printk(KERN_DEBUG "%s at %s: " fmt, \ + dev->name, __func__ , ##args); \ + } \ +} while (0) + +/* + * em2800_i2c_send_max4() + * send up to 4 bytes to the i2c device + */ +static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr, + char *buf, int len) +{ + int ret; + int write_timeout; + unsigned char b2[6]; + BUG_ON(len < 1 || len > 4); + b2[5] = 0x80 + len - 1; + b2[4] = addr; + b2[3] = buf[0]; + if (len > 1) + b2[2] = buf[1]; + if (len > 2) + b2[1] = buf[2]; + if (len > 3) + b2[0] = buf[3]; + + ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); + if (ret != 2 + len) { + em28xx_warn("writing to i2c device failed (error=%i)\n", ret); + return -EIO; + } + for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; + write_timeout -= 5) { + ret = dev->em28xx_read_reg(dev, 0x05); + if (ret == 0x80 + len - 1) + return len; + msleep(5); + } + em28xx_warn("i2c write timed out\n"); + return -EIO; +} + +/* + * em2800_i2c_send_bytes() + */ +static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf, + short len) +{ + char *bufPtr = buf; + int ret; + int wrcount = 0; + int count; + int maxLen = 4; + struct em28xx *dev = (struct em28xx *)data; + while (len > 0) { + count = (len > maxLen) ? maxLen : len; + ret = em2800_i2c_send_max4(dev, addr, bufPtr, count); + if (ret > 0) { + len -= count; + bufPtr += count; + wrcount += count; + } else + return (ret < 0) ? ret : -EFAULT; + } + return wrcount; +} + +/* + * em2800_i2c_check_for_device() + * check if there is a i2c_device at the supplied address + */ +static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr) +{ + char msg; + int ret; + int write_timeout; + msg = addr; + ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1); + if (ret < 0) { + em28xx_warn("setting i2c device address failed (error=%i)\n", + ret); + return ret; + } + msg = 0x84; + ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1); + if (ret < 0) { + em28xx_warn("preparing i2c read failed (error=%i)\n", ret); + return ret; + } + for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; + write_timeout -= 5) { + unsigned reg = dev->em28xx_read_reg(dev, 0x5); + + if (reg == 0x94) + return -ENODEV; + else if (reg == 0x84) + return 0; + msleep(5); + } + return -ENODEV; +} + +/* + * em2800_i2c_recv_bytes() + * read from the i2c device + */ +static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, + char *buf, int len) +{ + int ret; + /* check for the device and set i2c read address */ + ret = em2800_i2c_check_for_device(dev, addr); + if (ret) { + em28xx_warn + ("preparing read at i2c address 0x%x failed (error=%i)\n", + addr, ret); + return ret; + } + ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len); + if (ret < 0) { + em28xx_warn("reading from i2c device at 0x%x failed (error=%i)", + addr, ret); + return ret; + } + return ret; +} + +/* + * em28xx_i2c_send_bytes() + * untested for more than 4 bytes + */ +static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf, + short len, int stop) +{ + int wrcount = 0; + struct em28xx *dev = (struct em28xx *)data; + + wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); + + return wrcount; +} + +/* + * em28xx_i2c_recv_bytes() + * read a byte from the i2c device + */ +static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, + char *buf, int len) +{ + int ret; + ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); + if (ret < 0) { + em28xx_warn("reading i2c device failed (error=%i)\n", ret); + return ret; + } + if (dev->em28xx_read_reg(dev, 0x5) != 0) + return -ENODEV; + return ret; +} + +/* + * em28xx_i2c_check_for_device() + * check if there is a i2c_device at the supplied address + */ +static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr) +{ + int ret; + + ret = dev->em28xx_read_reg_req(dev, 2, addr); + if (ret < 0) { + em28xx_warn("reading from i2c device failed (error=%i)\n", ret); + return ret; + } + if (dev->em28xx_read_reg(dev, 0x5) != 0) + return -ENODEV; + return 0; +} + +/* + * em28xx_i2c_xfer() + * the main i2c transfer function + */ +static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct em28xx *dev = i2c_adap->algo_data; + int addr, rc, i, byte; + + if (num <= 0) + return 0; + for (i = 0; i < num; i++) { + addr = msgs[i].addr << 1; + dprintk2(2, "%s %s addr=%x len=%d:", + (msgs[i].flags & I2C_M_RD) ? "read" : "write", + i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); + if (!msgs[i].len) { /* no len: check only for device presence */ + if (dev->board.is_em2800) + rc = em2800_i2c_check_for_device(dev, addr); + else + rc = em28xx_i2c_check_for_device(dev, addr); + if (rc < 0) { + dprintk2(2, " no device\n"); + return rc; + } + + } else if (msgs[i].flags & I2C_M_RD) { + /* read bytes */ + if (dev->board.is_em2800) + rc = em2800_i2c_recv_bytes(dev, addr, + msgs[i].buf, + msgs[i].len); + else + rc = em28xx_i2c_recv_bytes(dev, addr, + msgs[i].buf, + msgs[i].len); + if (i2c_debug >= 2) { + for (byte = 0; byte < msgs[i].len; byte++) + printk(" %02x", msgs[i].buf[byte]); + } + } else { + /* write bytes */ + if (i2c_debug >= 2) { + for (byte = 0; byte < msgs[i].len; byte++) + printk(" %02x", msgs[i].buf[byte]); + } + if (dev->board.is_em2800) + rc = em2800_i2c_send_bytes(dev, addr, + msgs[i].buf, + msgs[i].len); + else + rc = em28xx_i2c_send_bytes(dev, addr, + msgs[i].buf, + msgs[i].len, + i == num - 1); + } + if (rc < 0) + goto err; + if (i2c_debug >= 2) + printk("\n"); + } + + return num; +err: + dprintk2(2, " ERROR: %i\n", rc); + return rc; +} + +/* based on linux/sunrpc/svcauth.h and linux/hash.h + * The original hash function returns a different value, if arch is x86_64 + * or i386. + */ +static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) +{ + unsigned long hash = 0; + unsigned long l = 0; + int len = 0; + unsigned char c; + do { + if (len == length) { + c = (char)len; + len = -1; + } else + c = *buf++; + l = (l << 8) | c; + len++; + if ((len & (32 / 8 - 1)) == 0) + hash = ((hash^l) * 0x9e370001UL); + } while (len); + + return (hash >> (32 - bits)) & 0xffffffffUL; +} + +static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) +{ + unsigned char buf, *p = eedata; + struct em28xx_eeprom *em_eeprom = (void *)eedata; + int i, err, size = len, block; + + if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { + /* Empia switched to a 16-bit addressable eeprom in newer + devices. While we could certainly write a routine to read + the eeprom, there is nothing of use in there that cannot be + accessed through registers, and there is the risk that we + could corrupt the eeprom (since a 16-bit read call is + interpreted as a write call by 8-bit eeproms). + */ + return 0; + } + + dev->i2c_client.addr = 0xa0 >> 1; + + /* Check if board has eeprom */ + err = i2c_master_recv(&dev->i2c_client, &buf, 0); + if (err < 0) { + em28xx_errdev("board has no eeprom\n"); + memset(eedata, 0, len); + return -ENODEV; + } + + buf = 0; + + err = i2c_master_send(&dev->i2c_client, &buf, 1); + if (err != 1) { + printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", + dev->name, err); + return err; + } + while (size > 0) { + if (size > 16) + block = 16; + else + block = size; + + if (block != + (err = i2c_master_recv(&dev->i2c_client, p, block))) { + printk(KERN_WARNING + "%s: i2c eeprom read error (err=%d)\n", + dev->name, err); + return err; + } + size -= block; + p += block; + } + for (i = 0; i < len; i++) { + if (0 == (i % 16)) + printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); + printk(" %02x", eedata[i]); + if (15 == (i % 16)) + printk("\n"); + } + + if (em_eeprom->id == 0x9567eb1a) + dev->hash = em28xx_hash_mem(eedata, len, 32); + + printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n", + dev->name, em_eeprom->id, dev->hash); + + printk(KERN_INFO "%s: EEPROM info:\n", dev->name); + + switch (em_eeprom->chip_conf >> 4 & 0x3) { + case 0: + printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name); + break; + case 1: + printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n", + dev->name); + break; + case 2: + printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n", + dev->name); + break; + case 3: + printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n", + dev->name); + break; + } + + if (em_eeprom->chip_conf & 1 << 3) + printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name); + + if (em_eeprom->chip_conf & 1 << 2) + printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name); + + switch (em_eeprom->chip_conf & 0x3) { + case 0: + printk(KERN_INFO "%s:\t500mA max power\n", dev->name); + break; + case 1: + printk(KERN_INFO "%s:\t400mA max power\n", dev->name); + break; + case 2: + printk(KERN_INFO "%s:\t300mA max power\n", dev->name); + break; + case 3: + printk(KERN_INFO "%s:\t200mA max power\n", dev->name); + break; + } + printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", + dev->name, + em_eeprom->string_idx_table, + em_eeprom->string1, + em_eeprom->string2, + em_eeprom->string3); + + return 0; +} + +/* ----------------------------------------------------------- */ + +/* + * functionality() + */ +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm em28xx_algo = { + .master_xfer = em28xx_i2c_xfer, + .functionality = functionality, +}; + +static struct i2c_adapter em28xx_adap_template = { + .owner = THIS_MODULE, + .name = "em28xx", + .algo = &em28xx_algo, +}; + +static struct i2c_client em28xx_client_template = { + .name = "em28xx internal", +}; + +/* ----------------------------------------------------------- */ + +/* + * i2c_devs + * incomplete list of known devices + */ +static char *i2c_devs[128] = { + [0x4a >> 1] = "saa7113h", + [0x60 >> 1] = "remote IR sensor", + [0x8e >> 1] = "remote IR sensor", + [0x86 >> 1] = "tda9887", + [0x80 >> 1] = "msp34xx", + [0x88 >> 1] = "msp34xx", + [0xa0 >> 1] = "eeprom", + [0xb0 >> 1] = "tda9874", + [0xb8 >> 1] = "tvp5150a", + [0xba >> 1] = "webcam sensor or tvp5150a", + [0xc0 >> 1] = "tuner (analog)", + [0xc2 >> 1] = "tuner (analog)", + [0xc4 >> 1] = "tuner (analog)", + [0xc6 >> 1] = "tuner (analog)", +}; + +/* + * do_i2c_scan() + * check i2c address range for devices + */ +void em28xx_do_i2c_scan(struct em28xx *dev) +{ + u8 i2c_devicelist[128]; + unsigned char buf; + int i, rc; + + memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); + + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { + dev->i2c_client.addr = i; + rc = i2c_master_recv(&dev->i2c_client, &buf, 0); + if (rc < 0) + continue; + i2c_devicelist[i] = i; + printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", + dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + } + + dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, + ARRAY_SIZE(i2c_devicelist), 32); +} + +/* + * em28xx_i2c_register() + * register i2c bus + */ +int em28xx_i2c_register(struct em28xx *dev) +{ + int retval; + + BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); + BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); + dev->i2c_adap = em28xx_adap_template; + dev->i2c_adap.dev.parent = &dev->udev->dev; + strcpy(dev->i2c_adap.name, dev->name); + dev->i2c_adap.algo_data = dev; + i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); + + retval = i2c_add_adapter(&dev->i2c_adap); + if (retval < 0) { + em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n", + __func__, retval); + return retval; + } + + dev->i2c_client = em28xx_client_template; + dev->i2c_client.adapter = &dev->i2c_adap; + + retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); + if ((retval < 0) && (retval != -ENODEV)) { + em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", + __func__, retval); + + return retval; + } + + if (i2c_scan) + em28xx_do_i2c_scan(dev); + + /* Instantiate the IR receiver device, if present */ + em28xx_register_i2c_ir(dev); + + return 0; +} + +/* + * em28xx_i2c_unregister() + * unregister i2c_bus + */ +int em28xx_i2c_unregister(struct em28xx *dev) +{ + i2c_del_adapter(&dev->i2c_adap); + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-input.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-input.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-input.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-input.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,560 @@ +/* + handle em28xx IR remotes via linux kernel input layer. + + Copyright (C) 2005 Ludovico Cavedon + Markus Rechberger + Mauro Carvalho Chehab + Sascha Sommer + + 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, or + (at your option) any later version. + + 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 +#include +#include +#include +#include +#include + +#include "em28xx.h" + +#define EM28XX_SNAPSHOT_KEY KEY_CAMERA +#define EM28XX_SBUTTON_QUERY_INTERVAL 500 +#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20 + +static unsigned int ir_debug; +module_param(ir_debug, int, 0644); +MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); + +#define MODULE_NAME "em28xx" + +#define i2cdprintk(fmt, arg...) \ + if (ir_debug) { \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ + } + +#define dprintk(fmt, arg...) \ + if (ir_debug) { \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ + } + +/********************************************************** + Polling structure used by em28xx IR's + **********************************************************/ + +struct em28xx_ir_poll_result { + unsigned int toggle_bit:1; + unsigned int read_count:7; + u8 rc_address; + u8 rc_data[4]; /* 1 byte on em2860/2880, 4 on em2874 */ +}; + +struct em28xx_IR { + struct em28xx *dev; + struct rc_dev *rc; + char name[32]; + char phys[32]; + + /* poll external decoder */ + int polling; + struct delayed_work work; + unsigned int full_code:1; + unsigned int last_readcount; + + int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); +}; + +/********************************************************** + I2C IR based get keycodes - should be used with ir-kbd-i2c + **********************************************************/ + +int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b; + + /* poll IR chip */ + if (1 != i2c_master_recv(ir->c, &b, 1)) { + i2cdprintk("read error\n"); + return -EIO; + } + + /* it seems that 0xFE indicates that a button is still hold + down, while 0xff indicates that no button is hold + down. 0xfe sequences are sometimes interrupted by 0xFF */ + + i2cdprintk("key %02x\n", b); + + if (b == 0xff) + return 0; + + if (b == 0xfe) + /* keep old data */ + return 1; + + *ir_key = b; + *ir_raw = b; + return 1; +} + +int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char buf[2]; + u16 code; + int size; + + /* poll IR chip */ + size = i2c_master_recv(ir->c, buf, sizeof(buf)); + + if (size != 2) + return -EIO; + + /* Does eliminate repeated parity code */ + if (buf[1] == 0xff) + return 0; + + ir->old = buf[1]; + + /* + * Rearranges bits to the right order. + * The bit order were determined experimentally by using + * The original Hauppauge Grey IR and another RC5 that uses addr=0x08 + * The RC5 code has 14 bits, but we've experimentally determined + * the meaning for only 11 bits. + * So, the code translation is not complete. Yet, it is enough to + * work with the provided RC5 IR. + */ + code = + ((buf[0] & 0x01) ? 0x0020 : 0) | /* 0010 0000 */ + ((buf[0] & 0x02) ? 0x0010 : 0) | /* 0001 0000 */ + ((buf[0] & 0x04) ? 0x0008 : 0) | /* 0000 1000 */ + ((buf[0] & 0x08) ? 0x0004 : 0) | /* 0000 0100 */ + ((buf[0] & 0x10) ? 0x0002 : 0) | /* 0000 0010 */ + ((buf[0] & 0x20) ? 0x0001 : 0) | /* 0000 0001 */ + ((buf[1] & 0x08) ? 0x1000 : 0) | /* 0001 0000 */ + ((buf[1] & 0x10) ? 0x0800 : 0) | /* 0000 1000 */ + ((buf[1] & 0x20) ? 0x0400 : 0) | /* 0000 0100 */ + ((buf[1] & 0x40) ? 0x0200 : 0) | /* 0000 0010 */ + ((buf[1] & 0x80) ? 0x0100 : 0); /* 0000 0001 */ + + i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x%02x)\n", + code, buf[1], buf[0]); + + /* return key */ + *ir_key = code; + *ir_raw = code; + return 1; +} + +int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, + u32 *ir_raw) +{ + unsigned char buf[3]; + + /* poll IR chip */ + + if (3 != i2c_master_recv(ir->c, buf, 3)) { + i2cdprintk("read error\n"); + return -EIO; + } + + i2cdprintk("key %02x\n", buf[2]&0x3f); + if (buf[0] != 0x00) + return 0; + + *ir_key = buf[2]&0x3f; + *ir_raw = buf[2]&0x3f; + + return 1; +} + +int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char subaddr, keydetect, key; + + struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, .buf = &subaddr, .len = 1}, + + { .addr = ir->c->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} }; + + subaddr = 0x10; + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { + i2cdprintk("read error\n"); + return -EIO; + } + if (keydetect == 0x00) + return 0; + + subaddr = 0x00; + msg[1].buf = &key; + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { + i2cdprintk("read error\n"); + return -EIO; + } + if (key == 0x00) + return 0; + + *ir_key = key; + *ir_raw = key; + return 1; +} + +/********************************************************** + Poll based get keycode functions + **********************************************************/ + +/* This is for the em2860/em2880 */ +static int default_polling_getkey(struct em28xx_IR *ir, + struct em28xx_ir_poll_result *poll_result) +{ + struct em28xx *dev = ir->dev; + int rc; + u8 msg[3] = { 0, 0, 0 }; + + /* Read key toggle, brand, and key code + on registers 0x45, 0x46 and 0x47 + */ + rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR, + msg, sizeof(msg)); + if (rc < 0) + return rc; + + /* Infrared toggle (Reg 0x45[7]) */ + poll_result->toggle_bit = (msg[0] >> 7); + + /* Infrared read count (Reg 0x45[6:0] */ + poll_result->read_count = (msg[0] & 0x7f); + + /* Remote Control Address (Reg 0x46) */ + poll_result->rc_address = msg[1]; + + /* Remote Control Data (Reg 0x47) */ + poll_result->rc_data[0] = msg[2]; + + return 0; +} + +static int em2874_polling_getkey(struct em28xx_IR *ir, + struct em28xx_ir_poll_result *poll_result) +{ + struct em28xx *dev = ir->dev; + int rc; + u8 msg[5] = { 0, 0, 0, 0, 0 }; + + /* Read key toggle, brand, and key code + on registers 0x51-55 + */ + rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR, + msg, sizeof(msg)); + if (rc < 0) + return rc; + + /* Infrared toggle (Reg 0x51[7]) */ + poll_result->toggle_bit = (msg[0] >> 7); + + /* Infrared read count (Reg 0x51[6:0] */ + poll_result->read_count = (msg[0] & 0x7f); + + /* Remote Control Address (Reg 0x52) */ + poll_result->rc_address = msg[1]; + + /* Remote Control Data (Reg 0x53-55) */ + poll_result->rc_data[0] = msg[2]; + poll_result->rc_data[1] = msg[3]; + poll_result->rc_data[2] = msg[4]; + + return 0; +} + +/********************************************************** + Polling code for em28xx + **********************************************************/ + +static void em28xx_ir_handle_key(struct em28xx_IR *ir) +{ + int result; + struct em28xx_ir_poll_result poll_result; + + /* read the registers containing the IR status */ + result = ir->get_key(ir, &poll_result); + if (unlikely(result < 0)) { + dprintk("ir->get_key() failed %d\n", result); + return; + } + + if (unlikely(poll_result.read_count != ir->last_readcount)) { + dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__, + poll_result.toggle_bit, poll_result.read_count, + poll_result.rc_address, poll_result.rc_data[0]); + if (ir->full_code) + rc_keydown(ir->rc, + poll_result.rc_address << 8 | + poll_result.rc_data[0], + poll_result.toggle_bit); + else + rc_keydown(ir->rc, + poll_result.rc_data[0], + poll_result.toggle_bit); + + if (ir->dev->chip_id == CHIP_ID_EM2874) + /* The em2874 clears the readcount field every time the + register is read. The em2860/2880 datasheet says that it + is supposed to clear the readcount, but it doesn't. So with + the em2874, we are looking for a non-zero read count as + opposed to a readcount that is incrementing */ + ir->last_readcount = 0; + else + ir->last_readcount = poll_result.read_count; + } +} + +static void em28xx_ir_work(struct work_struct *work) +{ + struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work); + + em28xx_ir_handle_key(ir); + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); +} + +static int em28xx_ir_start(struct rc_dev *rc) +{ + struct em28xx_IR *ir = rc->priv; + + INIT_DELAYED_WORK(&ir->work, em28xx_ir_work); + schedule_delayed_work(&ir->work, 0); + + return 0; +} + +static void em28xx_ir_stop(struct rc_dev *rc) +{ + struct em28xx_IR *ir = rc->priv; + + cancel_delayed_work_sync(&ir->work); +} + +int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) +{ + int rc = 0; + struct em28xx_IR *ir = rc_dev->priv; + struct em28xx *dev = ir->dev; + u8 ir_config = EM2874_IR_RC5; + + /* Adjust xclk based o IR table for RC5/NEC tables */ + + if (rc_type == RC_TYPE_RC5) { + dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE; + ir->full_code = 1; + } else if (rc_type == RC_TYPE_NEC) { + dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE; + ir_config = EM2874_IR_NEC; + ir->full_code = 1; + } else if (rc_type != RC_TYPE_UNKNOWN) + rc = -EINVAL; + + em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk, + EM28XX_XCLK_IR_RC5_MODE); + + /* Setup the proper handler based on the chip */ + switch (dev->chip_id) { + case CHIP_ID_EM2860: + case CHIP_ID_EM2883: + ir->get_key = default_polling_getkey; + break; + case CHIP_ID_EM2874: + case CHIP_ID_EM28174: + ir->get_key = em2874_polling_getkey; + em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); + break; + default: + printk("Unrecognized em28xx chip id: IR not supported\n"); + rc = -EINVAL; + } + + return rc; +} + +int em28xx_ir_init(struct em28xx *dev) +{ + struct em28xx_IR *ir; + struct rc_dev *rc; + int err = -ENOMEM; + + if (dev->board.ir_codes == NULL) { + /* No remote control support */ + return 0; + } + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + rc = rc_allocate_device(); + if (!ir || !rc) + goto err_out_free; + + /* record handles to ourself */ + ir->dev = dev; + dev->ir = ir; + ir->rc = rc; + + /* + * em2874 supports more protocols. For now, let's just announce + * the two protocols that were already tested + */ + rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; + rc->priv = ir; + rc->change_protocol = em28xx_ir_change_protocol; + rc->open = em28xx_ir_start; + rc->close = em28xx_ir_stop; + + /* By default, keep protocol field untouched */ + err = em28xx_ir_change_protocol(rc, RC_TYPE_UNKNOWN); + if (err) + goto err_out_free; + + /* This is how often we ask the chip for IR information */ + ir->polling = 100; /* ms */ + + /* init input device */ + snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", + dev->name); + + usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); + strlcat(ir->phys, "/input0", sizeof(ir->phys)); + + rc->input_name = ir->name; + rc->input_phys = ir->phys; + rc->input_id.bustype = BUS_USB; + rc->input_id.version = 1; + rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + rc->dev.parent = &dev->udev->dev; + rc->map_name = dev->board.ir_codes; + rc->driver_name = MODULE_NAME; + + /* all done */ + err = rc_register_device(rc); + if (err) + goto err_out_stop; + + return 0; + + err_out_stop: + dev->ir = NULL; + err_out_free: + rc_free_device(rc); + kfree(ir); + return err; +} + +int em28xx_ir_fini(struct em28xx *dev) +{ + struct em28xx_IR *ir = dev->ir; + + /* skip detach on non attached boards */ + if (!ir) + return 0; + + em28xx_ir_stop(ir->rc); + rc_unregister_device(ir->rc); + kfree(ir); + + /* done */ + dev->ir = NULL; + return 0; +} + +/********************************************************** + Handle Webcam snapshot button + **********************************************************/ + +static void em28xx_query_sbutton(struct work_struct *work) +{ + /* Poll the register and see if the button is depressed */ + struct em28xx *dev = + container_of(work, struct em28xx, sbutton_query_work.work); + int ret; + + ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP); + + if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) { + u8 cleared; + /* Button is depressed, clear the register */ + cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT; + em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1); + + /* Not emulate the keypress */ + input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, + 1); + /* Now unpress the key */ + input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, + 0); + } + + /* Schedule next poll */ + schedule_delayed_work(&dev->sbutton_query_work, + msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); +} + +void em28xx_register_snapshot_button(struct em28xx *dev) +{ + struct input_dev *input_dev; + int err; + + em28xx_info("Registering snapshot button...\n"); + input_dev = input_allocate_device(); + if (!input_dev) { + em28xx_errdev("input_allocate_device failed\n"); + return; + } + + usb_make_path(dev->udev, dev->snapshot_button_path, + sizeof(dev->snapshot_button_path)); + strlcat(dev->snapshot_button_path, "/sbutton", + sizeof(dev->snapshot_button_path)); + INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton); + + input_dev->name = "em28xx snapshot button"; + input_dev->phys = dev->snapshot_button_path; + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit); + input_dev->keycodesize = 0; + input_dev->keycodemax = 0; + input_dev->id.bustype = BUS_USB; + input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + input_dev->id.version = 1; + input_dev->dev.parent = &dev->udev->dev; + + err = input_register_device(input_dev); + if (err) { + em28xx_errdev("input_register_device failed\n"); + input_free_device(input_dev); + return; + } + + dev->sbutton_input_dev = input_dev; + schedule_delayed_work(&dev->sbutton_query_work, + msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); + return; + +} + +void em28xx_deregister_snapshot_button(struct em28xx *dev) +{ + if (dev->sbutton_input_dev != NULL) { + em28xx_info("Deregistering snapshot button\n"); + cancel_delayed_work_sync(&dev->sbutton_query_work); + input_unregister_device(dev->sbutton_input_dev); + dev->sbutton_input_dev = NULL; + } + return; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,269 @@ +#define EM_GPIO_0 (1 << 0) +#define EM_GPIO_1 (1 << 1) +#define EM_GPIO_2 (1 << 2) +#define EM_GPIO_3 (1 << 3) +#define EM_GPIO_4 (1 << 4) +#define EM_GPIO_5 (1 << 5) +#define EM_GPIO_6 (1 << 6) +#define EM_GPIO_7 (1 << 7) + +#define EM_GPO_0 (1 << 0) +#define EM_GPO_1 (1 << 1) +#define EM_GPO_2 (1 << 2) +#define EM_GPO_3 (1 << 3) + +/* em2800 registers */ +#define EM2800_R08_AUDIOSRC 0x08 + +/* em28xx registers */ + +#define EM28XX_R00_CHIPCFG 0x00 + +/* em28xx Chip Configuration 0x00 */ +#define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80 +#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40 +#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x30 +#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x20 +#define EM28XX_CHIPCFG_AC97 0x10 +#define EM28XX_CHIPCFG_AUDIOMASK 0x30 + +#define EM28XX_R01_CHIPCFG2 0x01 + +/* em28xx Chip Configuration 2 0x01 */ +#define EM28XX_CHIPCFG2_TS_PRESENT 0x10 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_MASK 0x0c /* bits 3-2 */ +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_1MF 0x00 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_2MF 0x04 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_4MF 0x08 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_8MF 0x0c +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK 0x03 /* bits 0-1 */ +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_188 0x00 +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_376 0x01 +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564 0x02 +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03 + + + /* GPIO/GPO registers */ +#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */ +#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ + +#define EM28XX_R06_I2C_CLK 0x06 + +/* em28xx I2C Clock Register (0x06) */ +#define EM28XX_I2C_CLK_ACK_LAST_READ 0x80 +#define EM28XX_I2C_CLK_WAIT_ENABLE 0x40 +#define EM28XX_I2C_EEPROM_ON_BOARD 0x08 +#define EM28XX_I2C_EEPROM_KEY_VALID 0x04 +#define EM2874_I2C_SECONDARY_BUS_SELECT 0x04 /* em2874 has two i2c busses */ +#define EM28XX_I2C_FREQ_1_5_MHZ 0x03 /* bus frequency (bits [1-0]) */ +#define EM28XX_I2C_FREQ_25_KHZ 0x02 +#define EM28XX_I2C_FREQ_400_KHZ 0x01 +#define EM28XX_I2C_FREQ_100_KHZ 0x00 + + +#define EM28XX_R0A_CHIPID 0x0a +#define EM28XX_R0C_USBSUSP 0x0c /* */ + +#define EM28XX_R0E_AUDIOSRC 0x0e +#define EM28XX_R0F_XCLK 0x0f + +/* em28xx XCLK Register (0x0f) */ +#define EM28XX_XCLK_AUDIO_UNMUTE 0x80 /* otherwise audio muted */ +#define EM28XX_XCLK_I2S_MSB_TIMING 0x40 /* otherwise standard timing */ +#define EM28XX_XCLK_IR_RC5_MODE 0x20 /* otherwise NEC mode */ +#define EM28XX_XCLK_IR_NEC_CHK_PARITY 0x10 +#define EM28XX_XCLK_FREQUENCY_30MHZ 0x00 /* Freq. select (bits [3-0]) */ +#define EM28XX_XCLK_FREQUENCY_15MHZ 0x01 +#define EM28XX_XCLK_FREQUENCY_10MHZ 0x02 +#define EM28XX_XCLK_FREQUENCY_7_5MHZ 0x03 +#define EM28XX_XCLK_FREQUENCY_6MHZ 0x04 +#define EM28XX_XCLK_FREQUENCY_5MHZ 0x05 +#define EM28XX_XCLK_FREQUENCY_4_3MHZ 0x06 +#define EM28XX_XCLK_FREQUENCY_12MHZ 0x07 +#define EM28XX_XCLK_FREQUENCY_20MHZ 0x08 +#define EM28XX_XCLK_FREQUENCY_20MHZ_2 0x09 +#define EM28XX_XCLK_FREQUENCY_48MHZ 0x0a +#define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b + +#define EM28XX_R10_VINMODE 0x10 + +#define EM28XX_R11_VINCTRL 0x11 + +/* em28xx Video Input Control Register 0x11 */ +#define EM28XX_VINCTRL_VBI_SLICED 0x80 +#define EM28XX_VINCTRL_VBI_RAW 0x40 +#define EM28XX_VINCTRL_VOUT_MODE_IN 0x20 /* HREF,VREF,VACT in output */ +#define EM28XX_VINCTRL_CCIR656_ENABLE 0x10 +#define EM28XX_VINCTRL_VBI_16BIT_RAW 0x08 /* otherwise 8-bit raw */ +#define EM28XX_VINCTRL_FID_ON_HREF 0x04 +#define EM28XX_VINCTRL_DUAL_EDGE_STROBE 0x02 +#define EM28XX_VINCTRL_INTERLACED 0x01 + +#define EM28XX_R12_VINENABLE 0x12 /* */ + +#define EM28XX_R14_GAMMA 0x14 +#define EM28XX_R15_RGAIN 0x15 +#define EM28XX_R16_GGAIN 0x16 +#define EM28XX_R17_BGAIN 0x17 +#define EM28XX_R18_ROFFSET 0x18 +#define EM28XX_R19_GOFFSET 0x19 +#define EM28XX_R1A_BOFFSET 0x1a + +#define EM28XX_R1B_OFLOW 0x1b +#define EM28XX_R1C_HSTART 0x1c +#define EM28XX_R1D_VSTART 0x1d +#define EM28XX_R1E_CWIDTH 0x1e +#define EM28XX_R1F_CHEIGHT 0x1f + +#define EM28XX_R20_YGAIN 0x20 +#define EM28XX_R21_YOFFSET 0x21 +#define EM28XX_R22_UVGAIN 0x22 +#define EM28XX_R23_UOFFSET 0x23 +#define EM28XX_R24_VOFFSET 0x24 +#define EM28XX_R25_SHARPNESS 0x25 + +#define EM28XX_R26_COMPR 0x26 +#define EM28XX_R27_OUTFMT 0x27 + +/* em28xx Output Format Register (0x27) */ +#define EM28XX_OUTFMT_RGB_8_RGRG 0x00 +#define EM28XX_OUTFMT_RGB_8_GRGR 0x01 +#define EM28XX_OUTFMT_RGB_8_GBGB 0x02 +#define EM28XX_OUTFMT_RGB_8_BGBG 0x03 +#define EM28XX_OUTFMT_RGB_16_656 0x04 +#define EM28XX_OUTFMT_RGB_8_BAYER 0x08 /* Pattern in Reg 0x10[1-0] */ +#define EM28XX_OUTFMT_YUV211 0x10 +#define EM28XX_OUTFMT_YUV422_Y0UY1V 0x14 +#define EM28XX_OUTFMT_YUV422_Y1UY0V 0x15 +#define EM28XX_OUTFMT_YUV411 0x18 + + +#define EM28XX_R28_XMIN 0x28 +#define EM28XX_R29_XMAX 0x29 +#define EM28XX_R2A_YMIN 0x2a +#define EM28XX_R2B_YMAX 0x2b + +#define EM28XX_R30_HSCALELOW 0x30 +#define EM28XX_R31_HSCALEHIGH 0x31 +#define EM28XX_R32_VSCALELOW 0x32 +#define EM28XX_R33_VSCALEHIGH 0x33 +#define EM28XX_R34_VBI_START_H 0x34 +#define EM28XX_R35_VBI_START_V 0x35 +#define EM28XX_R36_VBI_WIDTH 0x36 +#define EM28XX_R37_VBI_HEIGHT 0x37 + +#define EM28XX_R40_AC97LSB 0x40 +#define EM28XX_R41_AC97MSB 0x41 +#define EM28XX_R42_AC97ADDR 0x42 +#define EM28XX_R43_AC97BUSY 0x43 + +#define EM28XX_R45_IR 0x45 + /* 0x45 bit 7 - parity bit + bits 6-0 - count + 0x46 IR brand + 0x47 IR data + */ + +/* em2874 registers */ +#define EM2874_R50_IR_CONFIG 0x50 +#define EM2874_R51_IR 0x51 +#define EM2874_R5F_TS_ENABLE 0x5f +#define EM2874_R80_GPIO 0x80 + +/* em2874 IR config register (0x50) */ +#define EM2874_IR_NEC 0x00 +#define EM2874_IR_RC5 0x04 +#define EM2874_IR_RC6_MODE_0 0x08 +#define EM2874_IR_RC6_MODE_6A 0x0b + +/* em2874 Transport Stream Enable Register (0x5f) */ +#define EM2874_TS1_CAPTURE_ENABLE (1 << 0) +#define EM2874_TS1_FILTER_ENABLE (1 << 1) +#define EM2874_TS1_NULL_DISCARD (1 << 2) +#define EM2874_TS2_CAPTURE_ENABLE (1 << 4) +#define EM2874_TS2_FILTER_ENABLE (1 << 5) +#define EM2874_TS2_NULL_DISCARD (1 << 6) + +/* register settings */ +#define EM2800_AUDIO_SRC_TUNER 0x0d +#define EM2800_AUDIO_SRC_LINE 0x0c +#define EM28XX_AUDIO_SRC_TUNER 0xc0 +#define EM28XX_AUDIO_SRC_LINE 0x80 + +/* FIXME: Need to be populated with the other chip ID's */ +enum em28xx_chip_id { + CHIP_ID_EM2800 = 7, + CHIP_ID_EM2710 = 17, + CHIP_ID_EM2820 = 18, /* Also used by some em2710 */ + CHIP_ID_EM2840 = 20, + CHIP_ID_EM2750 = 33, + CHIP_ID_EM2860 = 34, + CHIP_ID_EM2870 = 35, + CHIP_ID_EM2883 = 36, + CHIP_ID_EM2874 = 65, + CHIP_ID_EM28174 = 113, +}; + +/* + * Registers used by em202 and other AC97 chips + */ + +/* Standard AC97 registers */ +#define AC97_RESET 0x00 + + /* Output volumes */ +#define AC97_MASTER_VOL 0x02 +#define AC97_LINE_LEVEL_VOL 0x04 /* Some devices use for headphones */ +#define AC97_MASTER_MONO_VOL 0x06 + + /* Input volumes */ +#define AC97_PC_BEEP_VOL 0x0a +#define AC97_PHONE_VOL 0x0c +#define AC97_MIC_VOL 0x0e +#define AC97_LINEIN_VOL 0x10 +#define AC97_CD_VOL 0x12 +#define AC97_VIDEO_VOL 0x14 +#define AC97_AUX_VOL 0x16 +#define AC97_PCM_OUT_VOL 0x18 + + /* capture registers */ +#define AC97_RECORD_SELECT 0x1a +#define AC97_RECORD_GAIN 0x1c + + /* control registers */ +#define AC97_GENERAL_PURPOSE 0x20 +#define AC97_3D_CTRL 0x22 +#define AC97_AUD_INT_AND_PAG 0x24 +#define AC97_POWER_DOWN_CTRL 0x26 +#define AC97_EXT_AUD_ID 0x28 +#define AC97_EXT_AUD_CTRL 0x2a + +/* Supported rate varies for each AC97 device + if write an unsupported value, it will return the closest one + */ +#define AC97_PCM_OUT_FRONT_SRATE 0x2c +#define AC97_PCM_OUT_SURR_SRATE 0x2e +#define AC97_PCM_OUT_LFE_SRATE 0x30 +#define AC97_PCM_IN_SRATE 0x32 + + /* For devices with more than 2 channels, extra output volumes */ +#define AC97_LFE_MASTER_VOL 0x36 +#define AC97_SURR_MASTER_VOL 0x38 + + /* Digital SPDIF output control */ +#define AC97_SPDIF_OUT_CTRL 0x3a + + /* Vendor ID identifier */ +#define AC97_VENDOR_ID1 0x7c +#define AC97_VENDOR_ID2 0x7e + +/* EMP202 vendor registers */ +#define EM202_EXT_MODEM_CTRL 0x3e +#define EM202_GPIO_CONF 0x4c +#define EM202_GPIO_POLARITY 0x4e +#define EM202_GPIO_STICKY 0x50 +#define EM202_GPIO_MASK 0x52 +#define EM202_GPIO_STATUS 0x54 +#define EM202_SPDIF_OUT_SEL 0x6a +#define EM202_ANTIPOP 0x72 +#define EM202_EAPD_GPIO_ACCESS 0x74 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-vbi.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,145 @@ +/* + em28xx-vbi.c - VBI driver for em28xx + + Copyright (C) 2009 Devin Heitmueller + + This work was sponsored by EyeMagnet Limited. + + 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, or + (at your option) any later version. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include "em28xx.h" + +static unsigned int vbibufs = 5; +module_param(vbibufs, int, 0644); +MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); + +static unsigned int vbi_debug; +module_param(vbi_debug, int, 0644); +MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); + +#define dprintk(level, fmt, arg...) if (vbi_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg) + +/* ------------------------------------------------------------------ */ + +static void +free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) +{ + struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = fh->dev; + unsigned long flags = 0; + if (in_interrupt()) + BUG(); + + /* We used to wait for the buffer to finish here, but this didn't work + because, as we were keeping the state as VIDEOBUF_QUEUED, + videobuf_queue_cancel marked it as finished for us. + (Also, it could wedge forever if the hardware was misconfigured.) + + This should be safe; by the time we get here, the buffer isn't + queued anymore. If we ever start marking the buffers as + VIDEOBUF_ACTIVE, it won't be, though. + */ + spin_lock_irqsave(&dev->slock, flags); + if (dev->isoc_ctl.vbi_buf == buf) + dev->isoc_ctl.vbi_buf = NULL; + spin_unlock_irqrestore(&dev->slock, flags); + + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int +vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + struct em28xx_fh *fh = q->priv_data; + struct em28xx *dev = fh->dev; + + *size = dev->vbi_width * dev->vbi_height * 2; + + if (0 == *count) + *count = vbibufs; + if (*count < 2) + *count = 2; + if (*count > 32) + *count = 32; + return 0; +} + +static int +vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct em28xx_fh *fh = q->priv_data; + struct em28xx *dev = fh->dev; + struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); + int rc = 0; + + buf->vb.size = dev->vbi_width * dev->vbi_height * 2; + + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + buf->vb.width = dev->vbi_width; + buf->vb.height = dev->vbi_height; + buf->vb.field = field; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(q, &buf->vb, NULL); + if (rc < 0) + goto fail; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(q, buf); + return rc; +} + +static void +vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct em28xx_buffer *buf = container_of(vb, + struct em28xx_buffer, + vb); + struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = fh->dev; + struct em28xx_dmaqueue *vbiq = &dev->vbiq; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vbiq->active); +} + +static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); + free_buffer(q, buf); +} + +struct videobuf_queue_ops em28xx_vbi_qops = { + .buf_setup = vbi_setup, + .buf_prepare = vbi_prepare, + .buf_queue = vbi_queue, + .buf_release = vbi_release, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-video.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/em28xx-video.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2539 @@ +/* + em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB + video capture devices + + Copyright (C) 2005 Ludovico Cavedon + Markus Rechberger + Mauro Carvalho Chehab + Sascha Sommer + + Some parts based on SN9C10x PC Camera Controllers GPL driver made + by Luca Risolia + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "em28xx.h" +#include +#include +#include +#include +#include + +#define DRIVER_AUTHOR "Ludovico Cavedon , " \ + "Markus Rechberger , " \ + "Mauro Carvalho Chehab , " \ + "Sascha Sommer " + +#define DRIVER_DESC "Empia em28xx based USB video device driver" +#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 2) + +#define em28xx_videodbg(fmt, arg...) do {\ + if (video_debug) \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); } while (0) + +static unsigned int isoc_debug; +module_param(isoc_debug, int, 0644); +MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); + +#define em28xx_isocdbg(fmt, arg...) \ +do {\ + if (isoc_debug) { \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); \ + } \ + } while (0) + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; + +module_param_array(video_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); + +static unsigned int video_debug; +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); + +/* supported video standards */ +static struct em28xx_fmt format[] = { + { + .name = "16 bpp YUY2, 4:2:2, packed", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .reg = EM28XX_OUTFMT_YUV422_Y0UY1V, + }, { + .name = "16 bpp RGB 565, LE", + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = 16, + .reg = EM28XX_OUTFMT_RGB_16_656, + }, { + .name = "8 bpp Bayer BGBG..GRGR", + .fourcc = V4L2_PIX_FMT_SBGGR8, + .depth = 8, + .reg = EM28XX_OUTFMT_RGB_8_BGBG, + }, { + .name = "8 bpp Bayer GRGR..BGBG", + .fourcc = V4L2_PIX_FMT_SGRBG8, + .depth = 8, + .reg = EM28XX_OUTFMT_RGB_8_GRGR, + }, { + .name = "8 bpp Bayer GBGB..RGRG", + .fourcc = V4L2_PIX_FMT_SGBRG8, + .depth = 8, + .reg = EM28XX_OUTFMT_RGB_8_GBGB, + }, { + .name = "12 bpp YUV411", + .fourcc = V4L2_PIX_FMT_YUV411P, + .depth = 12, + .reg = EM28XX_OUTFMT_YUV411, + }, +}; + +/* supported controls */ +/* Common to all boards */ +static struct v4l2_queryctrl ac97_qctrl[] = { + { + .id = V4L2_CID_AUDIO_VOLUME, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Volume", + .minimum = 0x0, + .maximum = 0x1f, + .step = 0x1, + .default_value = 0x1f, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_AUDIO_MUTE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + } +}; + +/* ------------------------------------------------------------------ + DMA and thread functions + ------------------------------------------------------------------*/ + +/* + * Announces that a buffer were filled and request the next + */ +static inline void buffer_filled(struct em28xx *dev, + struct em28xx_dmaqueue *dma_q, + struct em28xx_buffer *buf) +{ + /* Advice that buffer was filled */ + em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + + dev->isoc_ctl.vid_buf = NULL; + + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); +} + +static inline void vbi_buffer_filled(struct em28xx *dev, + struct em28xx_dmaqueue *dma_q, + struct em28xx_buffer *buf) +{ + /* Advice that buffer was filled */ + em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); + + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + + dev->isoc_ctl.vbi_buf = NULL; + + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); +} + +/* + * Identify the buffer header type and properly handles + */ +static void em28xx_copy_video(struct em28xx *dev, + struct em28xx_dmaqueue *dma_q, + struct em28xx_buffer *buf, + unsigned char *p, + unsigned char *outp, unsigned long len) +{ + void *fieldstart, *startwrite, *startread; + int linesdone, currlinedone, offset, lencopy, remain; + int bytesperline = dev->width << 1; + + if (dma_q->pos + len > buf->vb.size) + len = buf->vb.size - dma_q->pos; + + startread = p; + remain = len; + + if (dev->progressive) + fieldstart = outp; + else { + /* Interlaces two half frames */ + if (buf->top_field) + fieldstart = outp; + else + fieldstart = outp + bytesperline; + } + + linesdone = dma_q->pos / bytesperline; + currlinedone = dma_q->pos % bytesperline; + + if (dev->progressive) + offset = linesdone * bytesperline + currlinedone; + else + offset = linesdone * bytesperline * 2 + currlinedone; + + startwrite = fieldstart + offset; + lencopy = bytesperline - currlinedone; + lencopy = lencopy > remain ? remain : lencopy; + + if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) { + em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n", + ((char *)startwrite + lencopy) - + ((char *)outp + buf->vb.size)); + remain = (char *)outp + buf->vb.size - (char *)startwrite; + lencopy = remain; + } + if (lencopy <= 0) + return; + memcpy(startwrite, startread, lencopy); + + remain -= lencopy; + + while (remain > 0) { + startwrite += lencopy + bytesperline; + startread += lencopy; + if (bytesperline > remain) + lencopy = remain; + else + lencopy = bytesperline; + + if ((char *)startwrite + lencopy > (char *)outp + + buf->vb.size) { + em28xx_isocdbg("Overflow of %zi bytes past buffer end" + "(2)\n", + ((char *)startwrite + lencopy) - + ((char *)outp + buf->vb.size)); + lencopy = remain = (char *)outp + buf->vb.size - + (char *)startwrite; + } + if (lencopy <= 0) + break; + + memcpy(startwrite, startread, lencopy); + + remain -= lencopy; + } + + dma_q->pos += len; +} + +static void em28xx_copy_vbi(struct em28xx *dev, + struct em28xx_dmaqueue *dma_q, + struct em28xx_buffer *buf, + unsigned char *p, + unsigned char *outp, unsigned long len) +{ + void *startwrite, *startread; + int offset; + int bytesperline; + + if (dev == NULL) { + em28xx_isocdbg("dev is null\n"); + return; + } + bytesperline = dev->vbi_width; + + if (dma_q == NULL) { + em28xx_isocdbg("dma_q is null\n"); + return; + } + if (buf == NULL) { + return; + } + if (p == NULL) { + em28xx_isocdbg("p is null\n"); + return; + } + if (outp == NULL) { + em28xx_isocdbg("outp is null\n"); + return; + } + + if (dma_q->pos + len > buf->vb.size) + len = buf->vb.size - dma_q->pos; + + startread = p; + + startwrite = outp + dma_q->pos; + offset = dma_q->pos; + + /* Make sure the bottom field populates the second half of the frame */ + if (buf->top_field == 0) { + startwrite += bytesperline * dev->vbi_height; + offset += bytesperline * dev->vbi_height; + } + + memcpy(startwrite, startread, len); + dma_q->pos += len; +} + +static inline void print_err_status(struct em28xx *dev, + int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + em28xx_isocdbg("URB status %d [%s].\n", status, errmsg); + } else { + em28xx_isocdbg("URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + +/* + * video-buf generic routine to get the next available buffer + */ +static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, + struct em28xx_buffer **buf) +{ + struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); + char *outp; + + if (list_empty(&dma_q->active)) { + em28xx_isocdbg("No active queue to serve\n"); + dev->isoc_ctl.vid_buf = NULL; + *buf = NULL; + return; + } + + /* Get the next buffer */ + *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); + + /* Cleans up buffer - Useful for testing for frame/URB loss */ + outp = videobuf_to_vmalloc(&(*buf)->vb); + memset(outp, 0, (*buf)->vb.size); + + dev->isoc_ctl.vid_buf = *buf; + + return; +} + +/* + * video-buf generic routine to get the next available VBI buffer + */ +static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q, + struct em28xx_buffer **buf) +{ + struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq); + char *outp; + + if (list_empty(&dma_q->active)) { + em28xx_isocdbg("No active queue to serve\n"); + dev->isoc_ctl.vbi_buf = NULL; + *buf = NULL; + return; + } + + /* Get the next buffer */ + *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); + /* Cleans up buffer - Useful for testing for frame/URB loss */ + outp = videobuf_to_vmalloc(&(*buf)->vb); + memset(outp, 0x00, (*buf)->vb.size); + + dev->isoc_ctl.vbi_buf = *buf; + + return; +} + +/* + * Controls the isoc copy of each urb packet + */ +static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) +{ + struct em28xx_buffer *buf; + struct em28xx_dmaqueue *dma_q = &dev->vidq; + unsigned char *outp = NULL; + int i, len = 0, rc = 1; + unsigned char *p; + + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + buf = dev->isoc_ctl.vid_buf; + if (buf != NULL) + outp = videobuf_to_vmalloc(&buf->vb); + + for (i = 0; i < urb->number_of_packets; i++) { + int status = urb->iso_frame_desc[i].status; + + if (status < 0) { + print_err_status(dev, i, status); + if (urb->iso_frame_desc[i].status != -EPROTO) + continue; + } + + len = urb->iso_frame_desc[i].actual_length - 4; + + if (urb->iso_frame_desc[i].actual_length <= 0) { + /* em28xx_isocdbg("packet %d is empty",i); - spammy */ + continue; + } + if (urb->iso_frame_desc[i].actual_length > + dev->max_pkt_size) { + em28xx_isocdbg("packet bigger than packet size"); + continue; + } + + p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + /* FIXME: incomplete buffer checks where removed to make + logic simpler. Impacts of those changes should be evaluated + */ + if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) { + em28xx_isocdbg("VBI HEADER!!!\n"); + /* FIXME: Should add vbi copy */ + continue; + } + if (p[0] == 0x22 && p[1] == 0x5a) { + em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], + len, (p[2] & 1) ? "odd" : "even"); + + if (dev->progressive || !(p[2] & 1)) { + if (buf != NULL) + buffer_filled(dev, dma_q, buf); + get_next_buf(dma_q, &buf); + if (buf == NULL) + outp = NULL; + else + outp = videobuf_to_vmalloc(&buf->vb); + } + + if (buf != NULL) { + if (p[2] & 1) + buf->top_field = 0; + else + buf->top_field = 1; + } + + dma_q->pos = 0; + } + if (buf != NULL) { + if (p[0] != 0x88 && p[0] != 0x22) { + em28xx_isocdbg("frame is not complete\n"); + len += 4; + } else { + p += 4; + } + em28xx_copy_video(dev, dma_q, buf, p, outp, len); + } + } + return rc; +} + +/* Version of isoc handler that takes into account a mixture of video and + VBI data */ +static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb) +{ + struct em28xx_buffer *buf, *vbi_buf; + struct em28xx_dmaqueue *dma_q = &dev->vidq; + struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; + unsigned char *outp = NULL; + unsigned char *vbioutp = NULL; + int i, len = 0, rc = 1; + unsigned char *p; + int vbi_size; + + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + buf = dev->isoc_ctl.vid_buf; + if (buf != NULL) + outp = videobuf_to_vmalloc(&buf->vb); + + vbi_buf = dev->isoc_ctl.vbi_buf; + if (vbi_buf != NULL) + vbioutp = videobuf_to_vmalloc(&vbi_buf->vb); + + for (i = 0; i < urb->number_of_packets; i++) { + int status = urb->iso_frame_desc[i].status; + + if (status < 0) { + print_err_status(dev, i, status); + if (urb->iso_frame_desc[i].status != -EPROTO) + continue; + } + + len = urb->iso_frame_desc[i].actual_length; + if (urb->iso_frame_desc[i].actual_length <= 0) { + /* em28xx_isocdbg("packet %d is empty",i); - spammy */ + continue; + } + if (urb->iso_frame_desc[i].actual_length > + dev->max_pkt_size) { + em28xx_isocdbg("packet bigger than packet size"); + continue; + } + + p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + /* capture type 0 = vbi start + capture type 1 = video start + capture type 2 = video in progress */ + if (p[0] == 0x33 && p[1] == 0x95) { + dev->capture_type = 0; + dev->vbi_read = 0; + em28xx_isocdbg("VBI START HEADER!!!\n"); + dev->cur_field = p[2]; + p += 4; + len -= 4; + } else if (p[0] == 0x88 && p[1] == 0x88 && + p[2] == 0x88 && p[3] == 0x88) { + /* continuation */ + p += 4; + len -= 4; + } else if (p[0] == 0x22 && p[1] == 0x5a) { + /* start video */ + p += 4; + len -= 4; + } + + vbi_size = dev->vbi_width * dev->vbi_height; + + if (dev->capture_type == 0) { + if (dev->vbi_read >= vbi_size) { + /* We've already read all the VBI data, so + treat the rest as video */ + em28xx_isocdbg("dev->vbi_read > vbi_size\n"); + } else if ((dev->vbi_read + len) < vbi_size) { + /* This entire frame is VBI data */ + if (dev->vbi_read == 0 && + (!(dev->cur_field & 1))) { + /* Brand new frame */ + if (vbi_buf != NULL) + vbi_buffer_filled(dev, + vbi_dma_q, + vbi_buf); + vbi_get_next_buf(vbi_dma_q, &vbi_buf); + if (vbi_buf == NULL) + vbioutp = NULL; + else + vbioutp = videobuf_to_vmalloc( + &vbi_buf->vb); + } + + if (dev->vbi_read == 0) { + vbi_dma_q->pos = 0; + if (vbi_buf != NULL) { + if (dev->cur_field & 1) + vbi_buf->top_field = 0; + else + vbi_buf->top_field = 1; + } + } + + dev->vbi_read += len; + em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p, + vbioutp, len); + } else { + /* Some of this frame is VBI data and some is + video data */ + int vbi_data_len = vbi_size - dev->vbi_read; + dev->vbi_read += vbi_data_len; + em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p, + vbioutp, vbi_data_len); + dev->capture_type = 1; + p += vbi_data_len; + len -= vbi_data_len; + } + } + + if (dev->capture_type == 1) { + dev->capture_type = 2; + if (dev->progressive || !(dev->cur_field & 1)) { + if (buf != NULL) + buffer_filled(dev, dma_q, buf); + get_next_buf(dma_q, &buf); + if (buf == NULL) + outp = NULL; + else + outp = videobuf_to_vmalloc(&buf->vb); + } + if (buf != NULL) { + if (dev->cur_field & 1) + buf->top_field = 0; + else + buf->top_field = 1; + } + + dma_q->pos = 0; + } + + if (buf != NULL && dev->capture_type == 2) { + if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 && + p[2] == 0x88 && p[3] == 0x88) { + p += 4; + len -= 4; + } + if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) { + em28xx_isocdbg("Video frame %d, len=%i, %s\n", + p[2], len, (p[2] & 1) ? + "odd" : "even"); + p += 4; + len -= 4; + } + + if (len > 0) + em28xx_copy_video(dev, dma_q, buf, p, outp, + len); + } + } + return rc; +} + + +/* ------------------------------------------------------------------ + Videobuf operations + ------------------------------------------------------------------*/ + +static int +buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) +{ + struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = fh->dev; + struct v4l2_frequency f; + + *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) + >> 3; + + if (0 == *count) + *count = EM28XX_DEF_BUF; + + if (*count < EM28XX_MIN_BUF) + *count = EM28XX_MIN_BUF; + + /* Ask tuner to go to analog or radio mode */ + memset(&f, 0, sizeof(f)); + f.frequency = dev->ctl_freq; + f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); + + return 0; +} + +/* This is called *without* dev->slock held; please keep it that way */ +static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) +{ + struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = fh->dev; + unsigned long flags = 0; + if (in_interrupt()) + BUG(); + + /* We used to wait for the buffer to finish here, but this didn't work + because, as we were keeping the state as VIDEOBUF_QUEUED, + videobuf_queue_cancel marked it as finished for us. + (Also, it could wedge forever if the hardware was misconfigured.) + + This should be safe; by the time we get here, the buffer isn't + queued anymore. If we ever start marking the buffers as + VIDEOBUF_ACTIVE, it won't be, though. + */ + spin_lock_irqsave(&dev->slock, flags); + if (dev->isoc_ctl.vid_buf == buf) + dev->isoc_ctl.vid_buf = NULL; + spin_unlock_irqrestore(&dev->slock, flags); + + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int +buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct em28xx_fh *fh = vq->priv_data; + struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); + struct em28xx *dev = fh->dev; + int rc = 0, urb_init = 0; + + buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + + 7) >> 3; + + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + buf->vb.width = dev->width; + buf->vb.height = dev->height; + buf->vb.field = field; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc < 0) + goto fail; + } + + if (!dev->isoc_ctl.num_bufs) + urb_init = 1; + + if (urb_init) { + if (em28xx_vbi_supported(dev) == 1) + rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, + EM28XX_NUM_BUFS, + dev->max_pkt_size, + em28xx_isoc_copy_vbi); + else + rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, + EM28XX_NUM_BUFS, + dev->max_pkt_size, + em28xx_isoc_copy); + if (rc < 0) + goto fail; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(vq, buf); + return rc; +} + +static void +buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct em28xx_buffer *buf = container_of(vb, + struct em28xx_buffer, + vb); + struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = fh->dev; + struct em28xx_dmaqueue *vidq = &dev->vidq; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vidq->active); + +} + +static void buffer_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct em28xx_buffer *buf = container_of(vb, + struct em28xx_buffer, + vb); + struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = (struct em28xx *)fh->dev; + + em28xx_isocdbg("em28xx: called buffer_release\n"); + + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops em28xx_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/********************* v4l2 interface **************************************/ + +static void video_mux(struct em28xx *dev, int index) +{ + dev->ctl_input = index; + dev->ctl_ainput = INPUT(index)->amux; + dev->ctl_aoutput = INPUT(index)->aout; + + if (!dev->ctl_aoutput) + dev->ctl_aoutput = EM28XX_AOUT_MASTER; + + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, + INPUT(index)->vmux, 0, 0); + + if (dev->board.has_msp34xx) { + if (dev->i2s_speed) { + v4l2_device_call_all(&dev->v4l2_dev, 0, audio, + s_i2s_clock_freq, dev->i2s_speed); + } + /* Note: this is msp3400 specific */ + v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, + dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0); + } + + if (dev->board.adecoder != EM28XX_NOADECODER) { + v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, + dev->ctl_ainput, dev->ctl_aoutput, 0); + } + + em28xx_audio_analog_set(dev); +} + +/* Usage lock check functions */ +static int res_get(struct em28xx_fh *fh, unsigned int bit) +{ + struct em28xx *dev = fh->dev; + + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + if (dev->resources & bit) { + /* no, someone else uses it */ + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->resources |= bit; + em28xx_videodbg("res: get %d\n", bit); + return 1; +} + +static int res_check(struct em28xx_fh *fh, unsigned int bit) +{ + return fh->resources & bit; +} + +static int res_locked(struct em28xx *dev, unsigned int bit) +{ + return dev->resources & bit; +} + +static void res_free(struct em28xx_fh *fh, unsigned int bits) +{ + struct em28xx *dev = fh->dev; + + BUG_ON((fh->resources & bits) != bits); + + fh->resources &= ~bits; + dev->resources &= ~bits; + em28xx_videodbg("res: put %d\n", bits); +} + +static int get_ressource(struct em28xx_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return EM28XX_RESOURCE_VIDEO; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return EM28XX_RESOURCE_VBI; + default: + BUG(); + return 0; + } +} + +/* + * ac97_queryctrl() + * return the ac97 supported controls + */ +static int ac97_queryctrl(struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) { + if (qc->id && qc->id == ac97_qctrl[i].id) { + memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc)); + return 0; + } + } + + /* Control is not ac97 related */ + return 1; +} + +/* + * ac97_get_ctrl() + * return the current values for ac97 mute and volume + */ +static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = dev->mute; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = dev->volume; + return 0; + default: + /* Control is not ac97 related */ + return 1; + } +} + +/* + * ac97_set_ctrl() + * set values for ac97 mute and volume + */ +static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) + if (ctrl->id == ac97_qctrl[i].id) + goto handle; + + /* Announce that hasn't handle it */ + return 1; + +handle: + if (ctrl->value < ac97_qctrl[i].minimum || + ctrl->value > ac97_qctrl[i].maximum) + return -ERANGE; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + dev->mute = ctrl->value; + break; + case V4L2_CID_AUDIO_VOLUME: + dev->volume = ctrl->value; + break; + } + + return em28xx_audio_analog_set(dev); +} + +static int check_dev(struct em28xx *dev) +{ + if (dev->state & DEV_DISCONNECTED) { + em28xx_errdev("v4l2 ioctl: device not present\n"); + return -ENODEV; + } + + if (dev->state & DEV_MISCONFIGURED) { + em28xx_errdev("v4l2 ioctl: device is misconfigured; " + "close and open it again\n"); + return -EIO; + } + return 0; +} + +static void get_scale(struct em28xx *dev, + unsigned int width, unsigned int height, + unsigned int *hscale, unsigned int *vscale) +{ + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + + *hscale = (((unsigned long)maxw) << 12) / width - 4096L; + if (*hscale >= 0x4000) + *hscale = 0x3fff; + + *vscale = (((unsigned long)maxh) << 12) / height - 4096L; + if (*vscale >= 0x4000) + *vscale = 0x3fff; +} + +/* ------------------------------------------------------------------ + IOCTL vidioc handling + ------------------------------------------------------------------*/ + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.pixelformat = dev->format->fourcc; + f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + + /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ + if (dev->progressive) + f->fmt.pix.field = V4L2_FIELD_NONE; + else + f->fmt.pix.field = dev->interlaced ? + V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; + return 0; +} + +static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(format); i++) + if (format[i].fourcc == fourcc) + return &format[i]; + + return NULL; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned int width = f->fmt.pix.width; + unsigned int height = f->fmt.pix.height; + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + unsigned int hscale, vscale; + struct em28xx_fmt *fmt; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmt) { + em28xx_videodbg("Fourcc format (%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + if (dev->board.is_em2800) { + /* the em2800 can only scale down to 50% */ + height = height > (3 * maxh / 4) ? maxh : maxh / 2; + width = width > (3 * maxw / 4) ? maxw : maxw / 2; + } else { + /* width must even because of the YUYV format + height must be even because of interlacing */ + v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, + 1, 0); + } + + get_scale(dev, width, height, &hscale, &vscale); + + width = (((unsigned long)maxw) << 12) / (hscale + 4096L); + height = (((unsigned long)maxh) << 12) / (vscale + 4096L); + + f->fmt.pix.width = width; + f->fmt.pix.height = height; + f->fmt.pix.pixelformat = fmt->fourcc; + f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + if (dev->progressive) + f->fmt.pix.field = V4L2_FIELD_NONE; + else + f->fmt.pix.field = dev->interlaced ? + V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; + + return 0; +} + +static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc, + unsigned width, unsigned height) +{ + struct em28xx_fmt *fmt; + + fmt = format_by_fourcc(fourcc); + if (!fmt) + return -EINVAL; + + dev->format = fmt; + dev->width = width; + dev->height = height; + + /* set new image size */ + get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + + em28xx_set_alternate(dev); + em28xx_resolution_set(dev); + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + vidioc_try_fmt_vid_cap(file, priv, f); + + if (videobuf_queue_is_busy(&fh->vb_vidq)) { + em28xx_errdev("%s queue busy\n", __func__); + return -EBUSY; + } + + return em28xx_set_video_format(dev, f->fmt.pix.pixelformat, + f->fmt.pix.width, f->fmt.pix.height); +} + +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + *norm = dev->norm; + + return 0; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct v4l2_format f; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + dev->norm = *norm; + + /* Adjusts width/height, if needed */ + f.fmt.pix.width = dev->width; + f.fmt.pix.height = dev->height; + vidioc_try_fmt_vid_cap(file, priv, &f); + + /* set new image size */ + dev->width = f.fmt.pix.width; + dev->height = f.fmt.pix.height; + get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + + em28xx_resolution_set(dev); + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); + + return 0; +} + +static int vidioc_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc = 0; + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (dev->board.is_webcam) + rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, + video, g_parm, p); + else + v4l2_video_std_frame_period(dev->norm, + &p->parm.capture.timeperframe); + + return rc; +} + +static int vidioc_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (!dev->board.is_webcam) + return -EINVAL; + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p); +} + +static const char *iname[] = { + [EM28XX_VMUX_COMPOSITE1] = "Composite1", + [EM28XX_VMUX_COMPOSITE2] = "Composite2", + [EM28XX_VMUX_COMPOSITE3] = "Composite3", + [EM28XX_VMUX_COMPOSITE4] = "Composite4", + [EM28XX_VMUX_SVIDEO] = "S-Video", + [EM28XX_VMUX_TELEVISION] = "Television", + [EM28XX_VMUX_CABLE] = "Cable TV", + [EM28XX_VMUX_DVB] = "DVB", + [EM28XX_VMUX_DEBUG] = "for debug only", +}; + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned int n; + + n = i->index; + if (n >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(n)->type) + return -EINVAL; + + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + + strcpy(i->name, iname[INPUT(n)->type]); + + if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || + (EM28XX_VMUX_CABLE == INPUT(n)->type)) + i->type = V4L2_INPUT_TYPE_TUNER; + + i->std = dev->vdev->tvnorms; + + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + *i = dev->ctl_input; + + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (i >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(i)->type) + return -EINVAL; + + dev->ctl_input = i; + + video_mux(dev, dev->ctl_input); + return 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (!dev->audio_mode.has_audio) + return -EINVAL; + + switch (a->index) { + case EM28XX_AMUX_VIDEO: + strcpy(a->name, "Television"); + break; + case EM28XX_AMUX_LINE_IN: + strcpy(a->name, "Line In"); + break; + case EM28XX_AMUX_VIDEO2: + strcpy(a->name, "Television alt"); + break; + case EM28XX_AMUX_PHONE: + strcpy(a->name, "Phone"); + break; + case EM28XX_AMUX_MIC: + strcpy(a->name, "Mic"); + break; + case EM28XX_AMUX_CD: + strcpy(a->name, "CD"); + break; + case EM28XX_AMUX_AUX: + strcpy(a->name, "Aux"); + break; + case EM28XX_AMUX_PCM_OUT: + strcpy(a->name, "PCM"); + break; + default: + return -EINVAL; + } + + a->index = dev->ctl_ainput; + a->capability = V4L2_AUDCAP_STEREO; + + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + + if (!dev->audio_mode.has_audio) + return -EINVAL; + + if (a->index >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(a->index)->type) + return -EINVAL; + + dev->ctl_ainput = INPUT(a->index)->amux; + dev->ctl_aoutput = INPUT(a->index)->aout; + + if (!dev->ctl_aoutput) + dev->ctl_aoutput = EM28XX_AOUT_MASTER; + + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int id = qc->id; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + memset(qc, 0, sizeof(*qc)); + + qc->id = id; + + /* enumerate AC97 controls */ + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + rc = ac97_queryctrl(qc); + if (!rc) + return 0; + } + + /* enumerate V4L2 device controls */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc); + + if (qc->type) + return 0; + else + return -EINVAL; +} + +/* + * FIXME: This is an indirect way to check if a control exists at a + * subdev. Instead of that hack, maybe the better would be to change all + * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported. + */ +static int check_subdev_ctrl(struct em28xx *dev, int id) +{ + struct v4l2_queryctrl qc; + + memset(&qc, 0, sizeof(qc)); + qc.id = id; + + /* enumerate V4L2 device controls */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc); + + if (qc.type) + return 0; + else + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + rc = 0; + + /* Set an AC97 control */ + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) + rc = ac97_get_ctrl(dev, ctrl); + else + rc = 1; + + /* It were not an AC97 control. Sends it to the v4l2 dev interface */ + if (rc == 1) { + if (check_subdev_ctrl(dev, ctrl->id)) + return -EINVAL; + + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); + rc = 0; + } + + return rc; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + /* Set an AC97 control */ + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) + rc = ac97_set_ctrl(dev, ctrl); + else + rc = 1; + + /* It isn't an AC97 control. Sends it to the v4l2 dev interface */ + if (rc == 1) { + rc = check_subdev_ctrl(dev, ctrl->id); + if (!rc) + v4l2_device_call_all(&dev->v4l2_dev, 0, + core, s_ctrl, ctrl); + /* + * In the case of non-AC97 volume controls, we still need + * to do some setups at em28xx, in order to mute/unmute + * and to adjust audio volume. However, the value ranges + * should be checked by the corresponding V4L subdriver. + */ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + dev->mute = ctrl->value; + rc = em28xx_audio_analog_set(dev); + break; + case V4L2_CID_AUDIO_VOLUME: + dev->volume = ctrl->value; + rc = em28xx_audio_analog_set(dev); + } + } + return (rc < 0) ? rc : 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Tuner"); + t->type = V4L2_TUNER_ANALOG_TV; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) + return -EINVAL; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != f->tuner) + return -EINVAL; + + if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) + return -EINVAL; + + dev->ctl_freq = f->frequency; + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int em28xx_reg_len(int reg) +{ + switch (reg) { + case EM28XX_R40_AC97LSB: + case EM28XX_R30_HSCALELOW: + case EM28XX_R32_VSCALELOW: + return 2; + default: + return 1; + } +} + +static int vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip); + + return 0; +} + + +static int vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int ret; + + switch (reg->match.type) { + case V4L2_CHIP_MATCH_AC97: + ret = em28xx_read_ac97(dev, reg->reg); + if (ret < 0) + return ret; + + reg->val = ret; + reg->size = 1; + return 0; + case V4L2_CHIP_MATCH_I2C_DRIVER: + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + /* TODO: is this correct? */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); + return 0; + default: + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + } + + /* Match host */ + reg->size = em28xx_reg_len(reg->reg); + if (reg->size == 1) { + ret = em28xx_read_reg(dev, reg->reg); + + if (ret < 0) + return ret; + + reg->val = ret; + } else { + __le16 val = 0; + ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, + reg->reg, (char *)&val, 2); + if (ret < 0) + return ret; + + reg->val = le16_to_cpu(val); + } + + return 0; +} + +static int vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + __le16 buf; + + switch (reg->match.type) { + case V4L2_CHIP_MATCH_AC97: + return em28xx_write_ac97(dev, reg->reg, reg->val); + case V4L2_CHIP_MATCH_I2C_DRIVER: + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + /* TODO: is this correct? */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); + return 0; + default: + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + } + + /* Match host */ + buf = cpu_to_le16(reg->val); + + return em28xx_write_regs(dev, reg->reg, (char *)&buf, + em28xx_reg_len(reg->reg)); +} +#endif + + +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cc) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + cc->bounds.left = 0; + cc->bounds.top = 0; + cc->bounds.width = dev->width; + cc->bounds.height = dev->height; + cc->defrect = cc->bounds; + cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ + cc->pixelaspect.denominator = 59; + + return 0; +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc = -EINVAL; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (unlikely(type != fh->type)) + return -EINVAL; + + em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n", + fh, type, fh->resources, dev->resources); + + if (unlikely(!res_get(fh, get_ressource(fh)))) + return -EBUSY; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + rc = videobuf_streamon(&fh->vb_vidq); + else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + rc = videobuf_streamon(&fh->vb_vbiq); + + return rc; +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) + return -EINVAL; + if (type != fh->type) + return -EINVAL; + + em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n", + fh, type, fh->resources, dev->resources); + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (res_check(fh, EM28XX_RESOURCE_VIDEO)) { + videobuf_streamoff(&fh->vb_vidq); + res_free(fh, EM28XX_RESOURCE_VIDEO); + } + } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (res_check(fh, EM28XX_RESOURCE_VBI)) { + videobuf_streamoff(&fh->vb_vbiq); + res_free(fh, EM28XX_RESOURCE_VBI); + } + } + + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); + strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + + cap->version = EM28XX_VERSION_CODE; + + cap->capabilities = + V4L2_CAP_SLICED_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + + if (dev->vbi_dev) + cap->capabilities |= V4L2_CAP_VBI_CAPTURE; + + if (dev->audio_mode.has_audio) + cap->capabilities |= V4L2_CAP_AUDIO; + + if (dev->tuner_type != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; + + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(format))) + return -EINVAL; + + strlcpy(f->description, format[f->index].name, sizeof(f->description)); + f->pixelformat = format[f->index].fourcc; + + return 0; +} + +/* Sliced VBI ioctls */ +static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + f->fmt.sliced.service_set = 0; + v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced); + + if (f->fmt.sliced.service_set == 0) + rc = -EINVAL; + + return rc; +} + +static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced); + + if (f->fmt.sliced.service_set == 0) + return -EINVAL; + + return 0; +} + +/* RAW VBI ioctls */ + +static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *format) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + format->fmt.vbi.samples_per_line = dev->vbi_width; + format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + format->fmt.vbi.offset = 0; + format->fmt.vbi.flags = 0; + format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; + format->fmt.vbi.count[0] = dev->vbi_height; + format->fmt.vbi.count[1] = dev->vbi_height; + + /* Varies by video standard (NTSC, PAL, etc.) */ + if (dev->norm & V4L2_STD_525_60) { + /* NTSC */ + format->fmt.vbi.start[0] = 10; + format->fmt.vbi.start[1] = 273; + } else if (dev->norm & V4L2_STD_625_50) { + /* PAL */ + format->fmt.vbi.start[0] = 6; + format->fmt.vbi.start[1] = 318; + } + + return 0; +} + +static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *format) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + format->fmt.vbi.samples_per_line = dev->vbi_width; + format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + format->fmt.vbi.offset = 0; + format->fmt.vbi.flags = 0; + format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; + format->fmt.vbi.count[0] = dev->vbi_height; + format->fmt.vbi.count[1] = dev->vbi_height; + + /* Varies by video standard (NTSC, PAL, etc.) */ + if (dev->norm & V4L2_STD_525_60) { + /* NTSC */ + format->fmt.vbi.start[0] = 10; + format->fmt.vbi.start[1] = 273; + } else if (dev->norm & V4L2_STD_625_50) { + /* PAL */ + format->fmt.vbi.start[0] = 6; + format->fmt.vbi.start[1] = 318; + } + + return 0; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_reqbufs(&fh->vb_vidq, rb); + else + return videobuf_reqbufs(&fh->vb_vbiq, rb); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_querybuf(&fh->vb_vidq, b); + else { + /* FIXME: I'm not sure yet whether this is a bug in zvbi or + the videobuf framework, but we probably shouldn't be + returning a buffer larger than that which was asked for. + At a minimum, it causes a crash in zvbi since it does + a memcpy based on the source buffer length */ + int result = videobuf_querybuf(&fh->vb_vbiq, b); + b->length = dev->vbi_width * dev->vbi_height * 2; + + return result; + } +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_qbuf(&fh->vb_vidq, b); + else + return videobuf_qbuf(&fh->vb_vbiq, b); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & + O_NONBLOCK); + else + return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & + O_NONBLOCK); +} + +/* ----------------------------------------------------------- */ +/* RADIO ESPECIFIC IOCTLS */ +/* ----------------------------------------------------------- */ + +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + + strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); + strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + + cap->version = EM28XX_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; +} + +static int radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + + if (unlikely(t->index > 0)) + return -EINVAL; + + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); + + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + strcpy(a->name, "Radio"); + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + + if (0 != t->index) + return -EINVAL; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); + + return 0; +} + +static int radio_s_audio(struct file *file, void *fh, + struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input(struct file *file, void *fh, unsigned int i) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + if (qc->id < V4L2_CID_BASE || + qc->id >= V4L2_CID_LASTP1) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) { + if (qc->id && qc->id == ac97_qctrl[i].id) { + memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc)); + return 0; + } + } + + return -EINVAL; +} + +/* + * em28xx_v4l2_open() + * inits the device and starts isoc transfer + */ +static int em28xx_v4l2_open(struct file *filp) +{ + int errCode = 0, radio = 0; + struct video_device *vdev = video_devdata(filp); + struct em28xx *dev = video_drvdata(filp); + enum v4l2_buf_type fh_type = 0; + struct em28xx_fh *fh; + enum v4l2_field field; + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; + } + + em28xx_videodbg("open dev=%s type=%s users=%d\n", + video_device_node_name(vdev), v4l2_type_names[fh_type], + dev->users); + + + fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); + if (!fh) { + em28xx_errdev("em28xx-video.c: Out of memory?!\n"); + return -ENOMEM; + } + fh->dev = dev; + fh->radio = radio; + fh->type = fh_type; + filp->private_data = fh; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { + em28xx_set_mode(dev, EM28XX_ANALOG_MODE); + em28xx_set_alternate(dev); + em28xx_resolution_set(dev); + + /* Needed, since GPIO might have disabled power of + some i2c device + */ + em28xx_wake_i2c(dev); + + } + if (fh->radio) { + em28xx_videodbg("video_open: setting radio device\n"); + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); + } + + dev->users++; + + if (dev->progressive) + field = V4L2_FIELD_NONE; + else + field = V4L2_FIELD_INTERLACED; + + videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, + NULL, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, field, + sizeof(struct em28xx_buffer), fh, &dev->lock); + + videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops, + NULL, &dev->slock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, + sizeof(struct em28xx_buffer), fh, &dev->lock); + + return errCode; +} + +/* + * em28xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +void em28xx_release_analog_resources(struct em28xx *dev) +{ + + /*FIXME: I2C IR should be disconnected */ + + if (dev->radio_dev) { + if (video_is_registered(dev->radio_dev)) + video_unregister_device(dev->radio_dev); + else + video_device_release(dev->radio_dev); + dev->radio_dev = NULL; + } + if (dev->vbi_dev) { + em28xx_info("V4L2 device %s deregistered\n", + video_device_node_name(dev->vbi_dev)); + if (video_is_registered(dev->vbi_dev)) + video_unregister_device(dev->vbi_dev); + else + video_device_release(dev->vbi_dev); + dev->vbi_dev = NULL; + } + if (dev->vdev) { + em28xx_info("V4L2 device %s deregistered\n", + video_device_node_name(dev->vdev)); + if (video_is_registered(dev->vdev)) + video_unregister_device(dev->vdev); + else + video_device_release(dev->vdev); + dev->vdev = NULL; + } +} + +/* + * em28xx_v4l2_close() + * stops streaming and deallocates all resources allocated by the v4l2 + * calls and ioctls + */ +static int em28xx_v4l2_close(struct file *filp) +{ + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + int errCode; + + em28xx_videodbg("users=%d\n", dev->users); + + if (res_check(fh, EM28XX_RESOURCE_VIDEO)) { + videobuf_stop(&fh->vb_vidq); + res_free(fh, EM28XX_RESOURCE_VIDEO); + } + + if (res_check(fh, EM28XX_RESOURCE_VBI)) { + videobuf_stop(&fh->vb_vbiq); + res_free(fh, EM28XX_RESOURCE_VBI); + } + + if (dev->users == 1) { + /* the device is already disconnect, + free the remaining resources */ + if (dev->state & DEV_DISCONNECTED) { + em28xx_release_resources(dev); + kfree(dev); + return 0; + } + + /* Save some power by putting tuner to sleep */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); + + /* do this before setting alternate! */ + em28xx_uninit_isoc(dev); + em28xx_set_mode(dev, EM28XX_SUSPEND); + + /* set alternate 0 */ + dev->alt = 0; + em28xx_videodbg("setting alternate 0\n"); + errCode = usb_set_interface(dev->udev, 0, 0); + if (errCode < 0) { + em28xx_errdev("cannot change alternate number to " + "0 (error=%i)\n", errCode); + } + } + + videobuf_mmap_free(&fh->vb_vidq); + videobuf_mmap_free(&fh->vb_vbiq); + kfree(fh); + dev->users--; + wake_up_interruptible_nr(&dev->open, 1); + return 0; +} + +/* + * em28xx_v4l2_read() + * will allocate buffers when called for the first time + */ +static ssize_t +em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos) +{ + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + /* FIXME: read() is not prepared to allow changing the video + resolution while streaming. Seems a bug at em28xx_set_fmt + */ + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (res_locked(dev, EM28XX_RESOURCE_VIDEO)) + return -EBUSY; + + return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, + filp->f_flags & O_NONBLOCK); + } + + + if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (!res_get(fh, EM28XX_RESOURCE_VBI)) + return -EBUSY; + + return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, + filp->f_flags & O_NONBLOCK); + } + + return 0; +} + +/* + * em28xx_v4l2_poll() + * will allocate buffers when called for the first time + */ +static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait) +{ + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (!res_get(fh, EM28XX_RESOURCE_VIDEO)) + return POLLERR; + return videobuf_poll_stream(filp, &fh->vb_vidq, wait); + } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (!res_get(fh, EM28XX_RESOURCE_VBI)) + return POLLERR; + return videobuf_poll_stream(filp, &fh->vb_vbiq, wait); + } else { + return POLLERR; + } +} + +/* + * em28xx_v4l2_mmap() + */ +static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); + else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma); + + em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", + (unsigned long)vma->vm_start, + (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, + rc); + + return rc; +} + +static const struct v4l2_file_operations em28xx_v4l_fops = { + .owner = THIS_MODULE, + .open = em28xx_v4l2_open, + .release = em28xx_v4l2_close, + .read = em28xx_v4l2_read, + .poll = em28xx_v4l2_poll, + .mmap = em28xx_v4l2_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_cropcap = vidioc_cropcap, + + .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, + + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_g_std = vidioc_g_std, + .vidioc_s_std = vidioc_s_std, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_s_parm = vidioc_s_parm, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, + .vidioc_g_chip_ident = vidioc_g_chip_ident, +#endif +}; + +static const struct video_device em28xx_video_template = { + .fops = &em28xx_v4l_fops, + .release = video_device_release, + .ioctl_ops = &video_ioctl_ops, + + .tvnorms = V4L2_STD_ALL, + .current_norm = V4L2_STD_PAL, +}; + +static const struct v4l2_file_operations radio_fops = { + .owner = THIS_MODULE, + .open = em28xx_v4l2_open, + .release = em28xx_v4l2_close, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +static struct video_device em28xx_radio_template = { + .name = "em28xx-radio", + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, +}; + +/******************************** usb interface ******************************/ + + + +static struct video_device *em28xx_vdev_init(struct em28xx *dev, + const struct video_device *template, + const char *type_name) +{ + struct video_device *vfd; + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + + *vfd = *template; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->release = video_device_release; + vfd->debug = video_debug; + vfd->lock = &dev->lock; + + snprintf(vfd->name, sizeof(vfd->name), "%s %s", + dev->name, type_name); + + video_set_drvdata(vfd, dev); + return vfd; +} + +int em28xx_register_analog_devices(struct em28xx *dev) +{ + u8 val; + int ret; + + printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n", + dev->name, + (EM28XX_VERSION_CODE >> 16) & 0xff, + (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff); + + /* set default norm */ + dev->norm = em28xx_video_template.current_norm; + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); + dev->interlaced = EM28XX_INTERLACED_DEFAULT; + dev->ctl_input = 0; + + /* Analog specific initialization */ + dev->format = &format[0]; + em28xx_set_video_format(dev, format[0].fourcc, + norm_maxw(dev), norm_maxh(dev)); + + video_mux(dev, dev->ctl_input); + + /* Audio defaults */ + dev->mute = 1; + dev->volume = 0x1f; + +/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */ + val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK); + em28xx_write_reg(dev, EM28XX_R0F_XCLK, + (EM28XX_XCLK_AUDIO_UNMUTE | val)); + + em28xx_set_outfmt(dev); + em28xx_colorlevels_set_default(dev); + em28xx_compression_disable(dev); + + /* allocate and fill video video_device struct */ + dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); + if (!dev->vdev) { + em28xx_errdev("cannot allocate video_device.\n"); + return -ENODEV; + } + + /* register v4l2 video video_device */ + ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + video_nr[dev->devno]); + if (ret) { + em28xx_errdev("unable to register video device (error=%i).\n", + ret); + return ret; + } + + /* Allocate and fill vbi video_device struct */ + if (em28xx_vbi_supported(dev) == 1) { + dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, + "vbi"); + + /* register v4l2 vbi video_device */ + ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->devno]); + if (ret < 0) { + em28xx_errdev("unable to register vbi device\n"); + return ret; + } + } + + if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { + dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, + "radio"); + if (!dev->radio_dev) { + em28xx_errdev("cannot allocate video_device.\n"); + return -ENODEV; + } + ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr[dev->devno]); + if (ret < 0) { + em28xx_errdev("can't register radio device\n"); + return ret; + } + em28xx_info("Registered radio device as %s\n", + video_device_node_name(dev->radio_dev)); + } + + em28xx_info("V4L2 video device registered as %s\n", + video_device_node_name(dev->vdev)); + + if (dev->vbi_dev) + em28xx_info("V4L2 VBI device registered as %s\n", + video_device_node_name(dev->vbi_dev)); + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,54 @@ +config VIDEO_EM28XX + tristate "Empia EM28xx USB video capture support" + depends on VIDEO_DEV && I2C + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEOBUF_VMALLOC + select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_MT9V011 if VIDEO_HELPER_CHIPS_AUTO + + ---help--- + This is a video4linux driver for Empia 28xx based TV cards. + + To compile this driver as a module, choose M here: the + module will be called em28xx + +config VIDEO_EM28XX_ALSA + depends on VIDEO_EM28XX && SND + select SND_PCM + tristate "Empia EM28xx ALSA audio module" + ---help--- + This is an ALSA driver for some Empia 28xx based TV cards. + + This is not required for em2800/em2820/em2821 boards. However, + newer em28xx devices uses Vendor Class for audio, instead of + implementing the USB Audio Class. For those chips, this module + will enable digital audio. + + To compile this driver as a module, choose M here: the + module will be called em28xx-alsa + +config VIDEO_EM28XX_DVB + tristate "DVB/ATSC Support for em28xx based TV cards" + depends on VIDEO_EM28XX && DVB_CORE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_S921 if !DVB_FE_CUSTOMISE + select DVB_DRXD if !DVB_FE_CUSTOMISE + select DVB_CXD2820R if !DVB_FE_CUSTOMISE + select VIDEOBUF_DVB + ---help--- + This adds support for DVB cards based on the + Empiatech em28xx chips. + +config VIDEO_EM28XX_RC + bool "EM28XX Remote Controller support" + depends on RC_CORE + depends on VIDEO_EM28XX + depends on !(RC_CORE=m && VIDEO_EM28XX=y) + default y + ---help--- + Enables Remote Controller support on em28xx driver. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/em28xx/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,16 @@ +em28xx-y := em28xx-video.o em28xx-i2c.o em28xx-cards.o +em28xx-y += em28xx-core.o em28xx-vbi.o + +em28xx-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-input.o + +em28xx-alsa-objs := em28xx-audio.o + +obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o +obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o +obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2711 @@ +/*************************************************************************** + * V4L2 driver for ET61X[12]51 PC Camera Controllers * + * * + * Copyright (C) 2006-2007 by Luca Risolia * + * * + * 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, or * + * (at your option) any later version. * + * * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "et61x251.h" + +/*****************************************************************************/ + +#define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \ + "PC Camera Controllers" +#define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia" +#define ET61X251_AUTHOR_EMAIL "" +#define ET61X251_MODULE_LICENSE "GPL" +#define ET61X251_MODULE_VERSION "1:1.09" +#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 9) + +/*****************************************************************************/ + +MODULE_DEVICE_TABLE(usb, et61x251_id_table); + +MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL); +MODULE_DESCRIPTION(ET61X251_MODULE_NAME); +MODULE_LICENSE(ET61X251_MODULE_LICENSE); + +static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1}; +module_param_array(video_nr, short, NULL, 0444); +MODULE_PARM_DESC(video_nr, + "\n<-1|n[,...]> Specify V4L2 minor mode number." + "\n -1 = use next available (default)" + "\n n = use minor number n (integer >= 0)" + "\nYou can specify up to " + __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way." + "\nFor example:" + "\nvideo_nr=-1,2,-1 would assign minor number 2 to" + "\nthe second registered camera and use auto for the first" + "\none and for every other camera." + "\n"); + +static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] = + ET61X251_FORCE_MUNMAP}; +module_param_array(force_munmap, bool, NULL, 0444); +MODULE_PARM_DESC(force_munmap, + "\n<0|1[,...]> Force the application to unmap previously" + "\nmapped buffer memory before calling any VIDIOC_S_CROP or" + "\nVIDIOC_S_FMT ioctl's. Not all the applications support" + "\nthis feature. This parameter is specific for each" + "\ndetected camera." + "\n 0 = do not force memory unmapping" + "\n 1 = force memory unmapping (save memory)" + "\nDefault value is "__MODULE_STRING(ET61X251_FORCE_MUNMAP)"." + "\n"); + +static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] = + ET61X251_FRAME_TIMEOUT}; +module_param_array(frame_timeout, uint, NULL, 0644); +MODULE_PARM_DESC(frame_timeout, + "\n Timeout for a video frame in seconds." + "\nThis parameter is specific for each detected camera." + "\nDefault value is " + __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"." + "\n"); + +#ifdef ET61X251_DEBUG +static unsigned short debug = ET61X251_DEBUG_LEVEL; +module_param(debug, ushort, 0644); +MODULE_PARM_DESC(debug, + "\n Debugging information level, from 0 to 3:" + "\n0 = none (use carefully)" + "\n1 = critical errors" + "\n2 = significant informations" + "\n3 = more verbose messages" + "\nLevel 3 is useful for testing only, when only " + "one device is used." + "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"." + "\n"); +#endif + +/*****************************************************************************/ + +static u32 +et61x251_request_buffers(struct et61x251_device* cam, u32 count, + enum et61x251_io_method io) +{ + struct v4l2_pix_format* p = &(cam->sensor.pix_format); + struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); + const size_t imagesize = cam->module_param.force_munmap || + io == IO_READ ? + (p->width * p->height * p->priv) / 8 : + (r->width * r->height * p->priv) / 8; + void* buff = NULL; + u32 i; + + if (count > ET61X251_MAX_FRAMES) + count = ET61X251_MAX_FRAMES; + + cam->nbuffers = count; + while (cam->nbuffers > 0) { + if ((buff = vmalloc_32_user(cam->nbuffers * + PAGE_ALIGN(imagesize)))) + break; + cam->nbuffers--; + } + + for (i = 0; i < cam->nbuffers; i++) { + cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); + cam->frame[i].buf.index = i; + cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); + cam->frame[i].buf.length = imagesize; + cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cam->frame[i].buf.sequence = 0; + cam->frame[i].buf.field = V4L2_FIELD_NONE; + cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; + cam->frame[i].buf.flags = 0; + } + + return cam->nbuffers; +} + + +static void et61x251_release_buffers(struct et61x251_device* cam) +{ + if (cam->nbuffers) { + vfree(cam->frame[0].bufmem); + cam->nbuffers = 0; + } + cam->frame_current = NULL; +} + + +static void et61x251_empty_framequeues(struct et61x251_device* cam) +{ + u32 i; + + INIT_LIST_HEAD(&cam->inqueue); + INIT_LIST_HEAD(&cam->outqueue); + + for (i = 0; i < ET61X251_MAX_FRAMES; i++) { + cam->frame[i].state = F_UNUSED; + cam->frame[i].buf.bytesused = 0; + } +} + + +static void et61x251_requeue_outqueue(struct et61x251_device* cam) +{ + struct et61x251_frame_t *i; + + list_for_each_entry(i, &cam->outqueue, frame) { + i->state = F_QUEUED; + list_add(&i->frame, &cam->inqueue); + } + + INIT_LIST_HEAD(&cam->outqueue); +} + + +static void et61x251_queue_unusedframes(struct et61x251_device* cam) +{ + unsigned long lock_flags; + u32 i; + + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].state == F_UNUSED) { + cam->frame[i].state = F_QUEUED; + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_add_tail(&cam->frame[i].frame, &cam->inqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + } +} + +/*****************************************************************************/ + +int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index) +{ + struct usb_device* udev = cam->usbdev; + u8* buff = cam->control_buffer; + int res; + + *buff = value; + + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); + if (res < 0) { + DBG(3, "Failed to write a register (value 0x%02X, index " + "0x%02X, error %d)", value, index, res); + return -1; + } + + return 0; +} + + +static int et61x251_read_reg(struct et61x251_device* cam, u16 index) +{ + struct usb_device* udev = cam->usbdev; + u8* buff = cam->control_buffer; + int res; + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, + 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); + if (res < 0) + DBG(3, "Failed to read a register (index 0x%02X, error %d)", + index, res); + + return (res >= 0) ? (int)(*buff) : -1; +} + + +static int +et61x251_i2c_wait(struct et61x251_device* cam, + const struct et61x251_sensor* sensor) +{ + int i, r; + + for (i = 1; i <= 8; i++) { + if (sensor->interface == ET61X251_I2C_3WIRES) { + r = et61x251_read_reg(cam, 0x8e); + if (!(r & 0x02) && (r >= 0)) + return 0; + } else { + r = et61x251_read_reg(cam, 0x8b); + if (!(r & 0x01) && (r >= 0)) + return 0; + } + if (r < 0) + return -EIO; + udelay(8*8); /* minimum for sensors at 400kHz */ + } + + return -EBUSY; +} + + +int +et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, + u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, + u8 data8, u8 address) +{ + struct usb_device* udev = cam->usbdev; + u8* data = cam->control_buffer; + int err = 0, res; + + data[0] = data2; + data[1] = data3; + data[2] = data4; + data[3] = data5; + data[4] = data6; + data[5] = data7; + data[6] = data8; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + data[0] = address; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x02 | (n << 4); + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + /* Start writing through the serial interface */ + data[0] = data1; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += et61x251_i2c_wait(cam, &cam->sensor); + + if (err) + DBG(3, "I2C raw write failed for %s image sensor", + cam->sensor.name); + + PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, " + "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X," + " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address, + data1, data2, data3, data4, data5, data6, data7, data8); + + return err ? -1 : 0; + +} + + +/*****************************************************************************/ + +static void et61x251_urb_complete(struct urb *urb) +{ + struct et61x251_device* cam = urb->context; + struct et61x251_frame_t** f; + size_t imagesize; + u8 i; + int err = 0; + + if (urb->status == -ENOENT) + return; + + f = &cam->frame_current; + + if (cam->stream == STREAM_INTERRUPT) { + cam->stream = STREAM_OFF; + if ((*f)) + (*f)->state = F_QUEUED; + DBG(3, "Stream interrupted"); + wake_up(&cam->wait_stream); + } + + if (cam->state & DEV_DISCONNECTED) + return; + + if (cam->state & DEV_MISCONFIGURED) { + wake_up_interruptible(&cam->wait_frame); + return; + } + + if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) + goto resubmit_urb; + + if (!(*f)) + (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t, + frame); + + imagesize = (cam->sensor.pix_format.width * + cam->sensor.pix_format.height * + cam->sensor.pix_format.priv) / 8; + + for (i = 0; i < urb->number_of_packets; i++) { + unsigned int len, status; + void *pos; + u8* b1, * b2, sof; + const u8 VOID_BYTES = 6; + size_t imglen; + + len = urb->iso_frame_desc[i].actual_length; + status = urb->iso_frame_desc[i].status; + pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; + + if (status) { + DBG(3, "Error in isochronous frame"); + (*f)->state = F_ERROR; + continue; + } + + b1 = pos++; + b2 = pos++; + sof = ((*b1 & 0x3f) == 63); + imglen = ((*b1 & 0xc0) << 2) | *b2; + + PDBGG("Isochrnous frame: length %u, #%u i, image length %zu", + len, i, imglen); + + if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) +start_of_frame: + if (sof) { + (*f)->state = F_GRABBING; + (*f)->buf.bytesused = 0; + do_gettimeofday(&(*f)->buf.timestamp); + pos += 22; + DBG(3, "SOF detected: new video frame"); + } + + if ((*f)->state == F_GRABBING) { + if (sof && (*f)->buf.bytesused) { + if (cam->sensor.pix_format.pixelformat == + V4L2_PIX_FMT_ET61X251) + goto end_of_frame; + else { + DBG(3, "Not expected SOF detected " + "after %lu bytes", + (unsigned long)(*f)->buf.bytesused); + (*f)->state = F_ERROR; + continue; + } + } + + if ((*f)->buf.bytesused + imglen > imagesize) { + DBG(3, "Video frame size exceeded"); + (*f)->state = F_ERROR; + continue; + } + + pos += VOID_BYTES; + + memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen); + (*f)->buf.bytesused += imglen; + + if ((*f)->buf.bytesused == imagesize) { + u32 b; +end_of_frame: + b = (*f)->buf.bytesused; + (*f)->state = F_DONE; + (*f)->buf.sequence= ++cam->frame_count; + spin_lock(&cam->queue_lock); + list_move_tail(&(*f)->frame, &cam->outqueue); + if (!list_empty(&cam->inqueue)) + (*f) = list_entry(cam->inqueue.next, + struct et61x251_frame_t, + frame); + else + (*f) = NULL; + spin_unlock(&cam->queue_lock); + DBG(3, "Video frame captured: : %lu bytes", + (unsigned long)(b)); + + if (!(*f)) + goto resubmit_urb; + + if (sof && + cam->sensor.pix_format.pixelformat == + V4L2_PIX_FMT_ET61X251) + goto start_of_frame; + } + } + } + +resubmit_urb: + urb->dev = cam->usbdev; + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0 && err != -EPERM) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "usb_submit_urb() failed"); + } + + wake_up_interruptible(&cam->wait_frame); +} + + +static int et61x251_start_transfer(struct et61x251_device* cam) +{ + struct usb_device *udev = cam->usbdev; + struct urb* urb; + struct usb_host_interface* altsetting = usb_altnum_to_altsetting( + usb_ifnum_to_if(udev, 0), + ET61X251_ALTERNATE_SETTING); + const unsigned int psz = le16_to_cpu(altsetting-> + endpoint[0].desc.wMaxPacketSize); + s8 i, j; + int err = 0; + + for (i = 0; i < ET61X251_URBS; i++) { + cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz, + GFP_KERNEL); + if (!cam->transfer_buffer[i]) { + err = -ENOMEM; + DBG(1, "Not enough memory"); + goto free_buffers; + } + } + + for (i = 0; i < ET61X251_URBS; i++) { + urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL); + cam->urb[i] = urb; + if (!urb) { + err = -ENOMEM; + DBG(1, "usb_alloc_urb() failed"); + goto free_urbs; + } + urb->dev = udev; + urb->context = cam; + urb->pipe = usb_rcvisocpipe(udev, 1); + urb->transfer_flags = URB_ISO_ASAP; + urb->number_of_packets = ET61X251_ISO_PACKETS; + urb->complete = et61x251_urb_complete; + urb->transfer_buffer = cam->transfer_buffer[i]; + urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS; + urb->interval = 1; + for (j = 0; j < ET61X251_ISO_PACKETS; j++) { + urb->iso_frame_desc[j].offset = psz * j; + urb->iso_frame_desc[j].length = psz; + } + } + + err = et61x251_write_reg(cam, 0x01, 0x03); + err = et61x251_write_reg(cam, 0x00, 0x03); + err = et61x251_write_reg(cam, 0x08, 0x03); + if (err) { + err = -EIO; + DBG(1, "I/O hardware error"); + goto free_urbs; + } + + err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING); + if (err) { + DBG(1, "usb_set_interface() failed"); + goto free_urbs; + } + + cam->frame_current = NULL; + + for (i = 0; i < ET61X251_URBS; i++) { + err = usb_submit_urb(cam->urb[i], GFP_KERNEL); + if (err) { + for (j = i-1; j >= 0; j--) + usb_kill_urb(cam->urb[j]); + DBG(1, "usb_submit_urb() failed, error %d", err); + goto free_urbs; + } + } + + return 0; + +free_urbs: + for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++) + usb_free_urb(cam->urb[i]); + +free_buffers: + for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++) + kfree(cam->transfer_buffer[i]); + + return err; +} + + +static int et61x251_stop_transfer(struct et61x251_device* cam) +{ + struct usb_device *udev = cam->usbdev; + s8 i; + int err = 0; + + if (cam->state & DEV_DISCONNECTED) + return 0; + + for (i = ET61X251_URBS-1; i >= 0; i--) { + usb_kill_urb(cam->urb[i]); + usb_free_urb(cam->urb[i]); + kfree(cam->transfer_buffer[i]); + } + + err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ + if (err) + DBG(3, "usb_set_interface() failed"); + + return err; +} + + +static int et61x251_stream_interrupt(struct et61x251_device* cam) +{ + long timeout; + + cam->stream = STREAM_INTERRUPT; + timeout = wait_event_timeout(cam->wait_stream, + (cam->stream == STREAM_OFF) || + (cam->state & DEV_DISCONNECTED), + ET61X251_URB_TIMEOUT); + if (cam->state & DEV_DISCONNECTED) + return -ENODEV; + else if (cam->stream != STREAM_OFF) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "URB timeout reached. The camera is misconfigured. To " + "use it, close and open %s again.", + video_device_node_name(cam->v4ldev)); + return -EIO; + } + + return 0; +} + +/*****************************************************************************/ + +#ifdef CONFIG_VIDEO_ADV_DEBUG + +static int et61x251_i2c_try_read(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address) +{ + struct usb_device* udev = cam->usbdev; + u8* data = cam->control_buffer; + int err = 0, res; + + data[0] = address; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x10; + data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += et61x251_i2c_wait(cam, sensor); + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, + 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + if (err) + DBG(3, "I2C read failed for %s image sensor", sensor->name); + + PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]); + + return err ? -1 : (int)data[0]; +} + + +static int et61x251_i2c_try_write(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address, u8 value) +{ + struct usb_device* udev = cam->usbdev; + u8* data = cam->control_buffer; + int err = 0, res; + + data[0] = address; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x12; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + data[0] = value; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += et61x251_i2c_wait(cam, sensor); + + if (err) + DBG(3, "I2C write failed for %s image sensor", sensor->name); + + PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value); + + return err ? -1 : 0; +} + +static int et61x251_i2c_read(struct et61x251_device* cam, u8 address) +{ + return et61x251_i2c_try_read(cam, &cam->sensor, address); +} + +static int et61x251_i2c_write(struct et61x251_device* cam, + u8 address, u8 value) +{ + return et61x251_i2c_try_write(cam, &cam->sensor, address, value); +} + +static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) +{ + char str[5]; + char* endp; + unsigned long val; + + if (len < 4) { + strncpy(str, buff, len); + str[len] = '\0'; + } else { + strncpy(str, buff, 4); + str[4] = '\0'; + } + + val = simple_strtoul(str, &endp, 0); + + *count = 0; + if (val <= 0xff) + *count = (ssize_t)(endp - str); + if ((*count) && (len == *count+1) && (buff[*count] == '\n')) + *count += 1; + + return (u8)val; +} + +/* + NOTE 1: being inside one of the following methods implies that the v4l + device exists for sure (see kobjects and reference counters) + NOTE 2: buffers are PAGE_SIZE long +*/ + +static ssize_t et61x251_show_reg(struct device* cd, + struct device_attribute *attr, char* buf) +{ + struct et61x251_device* cam; + ssize_t count; + + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENODEV; + } + + count = sprintf(buf, "%u\n", cam->sysfs.reg); + + mutex_unlock(&et61x251_sysfs_lock); + + return count; +} + + +static ssize_t +et61x251_store_reg(struct device* cd, + struct device_attribute *attr, const char* buf, size_t len) +{ + struct et61x251_device* cam; + u8 index; + ssize_t count; + + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENODEV; + } + + index = et61x251_strtou8(buf, len, &count); + if (index > 0x8e || !count) { + mutex_unlock(&et61x251_sysfs_lock); + return -EINVAL; + } + + cam->sysfs.reg = index; + + DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg); + DBG(3, "Written bytes: %zd", count); + + mutex_unlock(&et61x251_sysfs_lock); + + return count; +} + + +static ssize_t et61x251_show_val(struct device* cd, + struct device_attribute *attr, char* buf) +{ + struct et61x251_device* cam; + ssize_t count; + int val; + + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENODEV; + } + + if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) { + mutex_unlock(&et61x251_sysfs_lock); + return -EIO; + } + + count = sprintf(buf, "%d\n", val); + + DBG(3, "Read bytes: %zd", count); + + mutex_unlock(&et61x251_sysfs_lock); + + return count; +} + + +static ssize_t +et61x251_store_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) +{ + struct et61x251_device* cam; + u8 value; + ssize_t count; + int err; + + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENODEV; + } + + value = et61x251_strtou8(buf, len, &count); + if (!count) { + mutex_unlock(&et61x251_sysfs_lock); + return -EINVAL; + } + + err = et61x251_write_reg(cam, value, cam->sysfs.reg); + if (err) { + mutex_unlock(&et61x251_sysfs_lock); + return -EIO; + } + + DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X", + cam->sysfs.reg, value); + DBG(3, "Written bytes: %zd", count); + + mutex_unlock(&et61x251_sysfs_lock); + + return count; +} + + +static ssize_t et61x251_show_i2c_reg(struct device* cd, + struct device_attribute *attr, char* buf) +{ + struct et61x251_device* cam; + ssize_t count; + + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENODEV; + } + + count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); + + DBG(3, "Read bytes: %zd", count); + + mutex_unlock(&et61x251_sysfs_lock); + + return count; +} + + +static ssize_t +et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) +{ + struct et61x251_device* cam; + u8 index; + ssize_t count; + + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENODEV; + } + + index = et61x251_strtou8(buf, len, &count); + if (!count) { + mutex_unlock(&et61x251_sysfs_lock); + return -EINVAL; + } + + cam->sysfs.i2c_reg = index; + + DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); + DBG(3, "Written bytes: %zd", count); + + mutex_unlock(&et61x251_sysfs_lock); + + return count; +} + + +static ssize_t et61x251_show_i2c_val(struct device* cd, + struct device_attribute *attr, char* buf) +{ + struct et61x251_device* cam; + ssize_t count; + int val; + + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENODEV; + } + + if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENOSYS; + } + + if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { + mutex_unlock(&et61x251_sysfs_lock); + return -EIO; + } + + count = sprintf(buf, "%d\n", val); + + DBG(3, "Read bytes: %zd", count); + + mutex_unlock(&et61x251_sysfs_lock); + + return count; +} + + +static ssize_t +et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) +{ + struct et61x251_device* cam; + u8 value; + ssize_t count; + int err; + + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENODEV; + } + + if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { + mutex_unlock(&et61x251_sysfs_lock); + return -ENOSYS; + } + + value = et61x251_strtou8(buf, len, &count); + if (!count) { + mutex_unlock(&et61x251_sysfs_lock); + return -EINVAL; + } + + err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value); + if (err) { + mutex_unlock(&et61x251_sysfs_lock); + return -EIO; + } + + DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", + cam->sysfs.i2c_reg, value); + DBG(3, "Written bytes: %zd", count); + + mutex_unlock(&et61x251_sysfs_lock); + + return count; +} + + +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, + et61x251_show_reg, et61x251_store_reg); +static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, + et61x251_show_val, et61x251_store_val); +static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + et61x251_show_i2c_reg, et61x251_store_i2c_reg); +static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + et61x251_show_i2c_val, et61x251_store_i2c_val); + + +static int et61x251_create_sysfs(struct et61x251_device* cam) +{ + struct device *classdev = &(cam->v4ldev->dev); + int err = 0; + + if ((err = device_create_file(classdev, &dev_attr_reg))) + goto err_out; + if ((err = device_create_file(classdev, &dev_attr_val))) + goto err_reg; + + if (cam->sensor.sysfs_ops) { + if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) + goto err_val; + if ((err = device_create_file(classdev, &dev_attr_i2c_val))) + goto err_i2c_reg; + } + +err_i2c_reg: + if (cam->sensor.sysfs_ops) + device_remove_file(classdev, &dev_attr_i2c_reg); +err_val: + device_remove_file(classdev, &dev_attr_val); +err_reg: + device_remove_file(classdev, &dev_attr_reg); +err_out: + return err; +} +#endif /* CONFIG_VIDEO_ADV_DEBUG */ + +/*****************************************************************************/ + +static int +et61x251_set_pix_format(struct et61x251_device* cam, + struct v4l2_pix_format* pix) +{ + int r, err = 0; + + if ((r = et61x251_read_reg(cam, 0x12)) < 0) + err += r; + if (pix->pixelformat == V4L2_PIX_FMT_ET61X251) + err += et61x251_write_reg(cam, r & 0xfd, 0x12); + else + err += et61x251_write_reg(cam, r | 0x02, 0x12); + + return err ? -EIO : 0; +} + + +static int +et61x251_set_compression(struct et61x251_device* cam, + struct v4l2_jpegcompression* compression) +{ + int r, err = 0; + + if ((r = et61x251_read_reg(cam, 0x12)) < 0) + err += r; + if (compression->quality == 0) + err += et61x251_write_reg(cam, r & 0xfb, 0x12); + else + err += et61x251_write_reg(cam, r | 0x04, 0x12); + + return err ? -EIO : 0; +} + + +static int et61x251_set_scale(struct et61x251_device* cam, u8 scale) +{ + int r = 0, err = 0; + + r = et61x251_read_reg(cam, 0x12); + if (r < 0) + err += r; + + if (scale == 1) + err += et61x251_write_reg(cam, r & ~0x01, 0x12); + else if (scale == 2) + err += et61x251_write_reg(cam, r | 0x01, 0x12); + + if (err) + return -EIO; + + PDBGG("Scaling factor: %u", scale); + + return 0; +} + + +static int +et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect) +{ + struct et61x251_sensor* s = &cam->sensor; + u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left + + s->active_pixel.left), + fmw_sy = (u16)(rect->top - s->cropcap.bounds.top + + s->active_pixel.top), + fmw_length = (u16)(rect->width), + fmw_height = (u16)(rect->height); + int err = 0; + + err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69); + err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a); + err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b); + err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c); + err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6) + | ((fmw_length & 0x300) >> 4) + | ((fmw_height & 0x300) >> 2), 0x6d); + if (err) + return -EIO; + + PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u", + fmw_sx, fmw_sy, fmw_length, fmw_height); + + return 0; +} + + +static int et61x251_init(struct et61x251_device* cam) +{ + struct et61x251_sensor* s = &cam->sensor; + struct v4l2_control ctrl; + struct v4l2_queryctrl *qctrl; + struct v4l2_rect* rect; + u8 i = 0; + int err = 0; + + if (!(cam->state & DEV_INITIALIZED)) { + mutex_init(&cam->open_mutex); + init_waitqueue_head(&cam->wait_open); + qctrl = s->qctrl; + rect = &(s->cropcap.defrect); + cam->compression.quality = ET61X251_COMPRESSION_QUALITY; + } else { /* use current values */ + qctrl = s->_qctrl; + rect = &(s->_rect); + } + + err += et61x251_set_scale(cam, rect->width / s->pix_format.width); + err += et61x251_set_crop(cam, rect); + if (err) + return err; + + if (s->init) { + err = s->init(cam); + if (err) { + DBG(3, "Sensor initialization failed"); + return err; + } + } + + err += et61x251_set_compression(cam, &cam->compression); + err += et61x251_set_pix_format(cam, &s->pix_format); + if (s->set_pix_format) + err += s->set_pix_format(cam, &s->pix_format); + if (err) + return err; + + if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251) + DBG(3, "Compressed video format is active, quality %d", + cam->compression.quality); + else + DBG(3, "Uncompressed video format is active"); + + if (s->set_crop) + if ((err = s->set_crop(cam, rect))) { + DBG(3, "set_crop() failed"); + return err; + } + + if (s->set_ctrl) { + for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) + if (s->qctrl[i].id != 0 && + !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { + ctrl.id = s->qctrl[i].id; + ctrl.value = qctrl[i].default_value; + err = s->set_ctrl(cam, &ctrl); + if (err) { + DBG(3, "Set %s control failed", + s->qctrl[i].name); + return err; + } + DBG(3, "Image sensor supports '%s' control", + s->qctrl[i].name); + } + } + + if (!(cam->state & DEV_INITIALIZED)) { + mutex_init(&cam->fileop_mutex); + spin_lock_init(&cam->queue_lock); + init_waitqueue_head(&cam->wait_frame); + init_waitqueue_head(&cam->wait_stream); + cam->nreadbuffers = 2; + memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); + memcpy(&(s->_rect), &(s->cropcap.defrect), + sizeof(struct v4l2_rect)); + cam->state |= DEV_INITIALIZED; + } + + DBG(2, "Initialization succeeded"); + return 0; +} + +/*****************************************************************************/ + +static void et61x251_release_resources(struct kref *kref) +{ + struct et61x251_device *cam; + + mutex_lock(&et61x251_sysfs_lock); + + cam = container_of(kref, struct et61x251_device, kref); + + DBG(2, "V4L2 device %s deregistered", + video_device_node_name(cam->v4ldev)); + video_set_drvdata(cam->v4ldev, NULL); + video_unregister_device(cam->v4ldev); + usb_put_dev(cam->usbdev); + kfree(cam->control_buffer); + kfree(cam); + + mutex_unlock(&et61x251_sysfs_lock); +} + + +static int et61x251_open(struct file *filp) +{ + struct et61x251_device* cam; + int err = 0; + + if (!down_read_trylock(&et61x251_dev_lock)) + return -ERESTARTSYS; + + cam = video_drvdata(filp); + + if (wait_for_completion_interruptible(&cam->probe)) { + up_read(&et61x251_dev_lock); + return -ERESTARTSYS; + } + + kref_get(&cam->kref); + + if (mutex_lock_interruptible(&cam->open_mutex)) { + kref_put(&cam->kref, et61x251_release_resources); + up_read(&et61x251_dev_lock); + return -ERESTARTSYS; + } + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + err = -ENODEV; + goto out; + } + + if (cam->users) { + DBG(2, "Device %s is already in use", + video_device_node_name(cam->v4ldev)); + DBG(3, "Simultaneous opens are not supported"); + if ((filp->f_flags & O_NONBLOCK) || + (filp->f_flags & O_NDELAY)) { + err = -EWOULDBLOCK; + goto out; + } + DBG(2, "A blocking open() has been requested. Wait for the " + "device to be released..."); + up_read(&et61x251_dev_lock); + err = wait_event_interruptible_exclusive(cam->wait_open, + (cam->state & DEV_DISCONNECTED) + || !cam->users); + down_read(&et61x251_dev_lock); + if (err) + goto out; + if (cam->state & DEV_DISCONNECTED) { + err = -ENODEV; + goto out; + } + } + + if (cam->state & DEV_MISCONFIGURED) { + err = et61x251_init(cam); + if (err) { + DBG(1, "Initialization failed again. " + "I will retry on next open()."); + goto out; + } + cam->state &= ~DEV_MISCONFIGURED; + } + + if ((err = et61x251_start_transfer(cam))) + goto out; + + filp->private_data = cam; + cam->users++; + cam->io = IO_NONE; + cam->stream = STREAM_OFF; + cam->nbuffers = 0; + cam->frame_count = 0; + et61x251_empty_framequeues(cam); + + DBG(3, "Video device %s is open", + video_device_node_name(cam->v4ldev)); + +out: + mutex_unlock(&cam->open_mutex); + if (err) + kref_put(&cam->kref, et61x251_release_resources); + up_read(&et61x251_dev_lock); + return err; +} + + +static int et61x251_release(struct file *filp) +{ + struct et61x251_device* cam; + + down_write(&et61x251_dev_lock); + + cam = video_drvdata(filp); + + et61x251_stop_transfer(cam); + et61x251_release_buffers(cam); + cam->users--; + wake_up_interruptible_nr(&cam->wait_open, 1); + + DBG(3, "Video device %s closed", + video_device_node_name(cam->v4ldev)); + + kref_put(&cam->kref, et61x251_release_resources); + + up_write(&et61x251_dev_lock); + + return 0; +} + + +static ssize_t +et61x251_read(struct file* filp, char __user * buf, + size_t count, loff_t* f_pos) +{ + struct et61x251_device *cam = video_drvdata(filp); + struct et61x251_frame_t* f, * i; + unsigned long lock_flags; + long timeout; + int err = 0; + + if (mutex_lock_interruptible(&cam->fileop_mutex)) + return -ERESTARTSYS; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + mutex_unlock(&cam->fileop_mutex); + return -ENODEV; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it " + "again."); + mutex_unlock(&cam->fileop_mutex); + return -EIO; + } + + if (cam->io == IO_MMAP) { + DBG(3, "Close and open the device again to choose the read " + "method"); + mutex_unlock(&cam->fileop_mutex); + return -EBUSY; + } + + if (cam->io == IO_NONE) { + if (!et61x251_request_buffers(cam, cam->nreadbuffers, + IO_READ)) { + DBG(1, "read() failed, not enough memory"); + mutex_unlock(&cam->fileop_mutex); + return -ENOMEM; + } + cam->io = IO_READ; + cam->stream = STREAM_ON; + } + + if (list_empty(&cam->inqueue)) { + if (!list_empty(&cam->outqueue)) + et61x251_empty_framequeues(cam); + et61x251_queue_unusedframes(cam); + } + + if (!count) { + mutex_unlock(&cam->fileop_mutex); + return 0; + } + + if (list_empty(&cam->outqueue)) { + if (filp->f_flags & O_NONBLOCK) { + mutex_unlock(&cam->fileop_mutex); + return -EAGAIN; + } + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + msecs_to_jiffies( + cam->module_param.frame_timeout * 1000 + ) + ); + if (timeout < 0) { + mutex_unlock(&cam->fileop_mutex); + return timeout; + } + if (cam->state & DEV_DISCONNECTED) { + mutex_unlock(&cam->fileop_mutex); + return -ENODEV; + } + if (!timeout || (cam->state & DEV_MISCONFIGURED)) { + mutex_unlock(&cam->fileop_mutex); + return -EIO; + } + } + + f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame); + + if (count > f->buf.bytesused) + count = f->buf.bytesused; + + if (copy_to_user(buf, f->bufmem, count)) { + err = -EFAULT; + goto exit; + } + *f_pos += count; + +exit: + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_for_each_entry(i, &cam->outqueue, frame) + i->state = F_UNUSED; + INIT_LIST_HEAD(&cam->outqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + + et61x251_queue_unusedframes(cam); + + PDBGG("Frame #%lu, bytes read: %zu", + (unsigned long)f->buf.index, count); + + mutex_unlock(&cam->fileop_mutex); + + return err ? err : count; +} + + +static unsigned int et61x251_poll(struct file *filp, poll_table *wait) +{ + struct et61x251_device *cam = video_drvdata(filp); + struct et61x251_frame_t* f; + unsigned long lock_flags; + unsigned int mask = 0; + + if (mutex_lock_interruptible(&cam->fileop_mutex)) + return POLLERR; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + goto error; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it " + "again."); + goto error; + } + + if (cam->io == IO_NONE) { + if (!et61x251_request_buffers(cam, cam->nreadbuffers, + IO_READ)) { + DBG(1, "poll() failed, not enough memory"); + goto error; + } + cam->io = IO_READ; + cam->stream = STREAM_ON; + } + + if (cam->io == IO_READ) { + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_for_each_entry(f, &cam->outqueue, frame) + f->state = F_UNUSED; + INIT_LIST_HEAD(&cam->outqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + et61x251_queue_unusedframes(cam); + } + + poll_wait(filp, &cam->wait_frame, wait); + + if (!list_empty(&cam->outqueue)) + mask |= POLLIN | POLLRDNORM; + + mutex_unlock(&cam->fileop_mutex); + + return mask; + +error: + mutex_unlock(&cam->fileop_mutex); + return POLLERR; +} + + +static void et61x251_vm_open(struct vm_area_struct* vma) +{ + struct et61x251_frame_t* f = vma->vm_private_data; + f->vma_use_count++; +} + + +static void et61x251_vm_close(struct vm_area_struct* vma) +{ + /* NOTE: buffers are not freed here */ + struct et61x251_frame_t* f = vma->vm_private_data; + f->vma_use_count--; +} + + +static const struct vm_operations_struct et61x251_vm_ops = { + .open = et61x251_vm_open, + .close = et61x251_vm_close, +}; + + +static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) +{ + struct et61x251_device *cam = video_drvdata(filp); + unsigned long size = vma->vm_end - vma->vm_start, + start = vma->vm_start; + void *pos; + u32 i; + + if (mutex_lock_interruptible(&cam->fileop_mutex)) + return -ERESTARTSYS; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + mutex_unlock(&cam->fileop_mutex); + return -ENODEV; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it " + "again."); + mutex_unlock(&cam->fileop_mutex); + return -EIO; + } + + if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { + mutex_unlock(&cam->fileop_mutex); + return -EACCES; + } + + if (cam->io != IO_MMAP || + size != PAGE_ALIGN(cam->frame[0].buf.length)) { + mutex_unlock(&cam->fileop_mutex); + return -EINVAL; + } + + for (i = 0; i < cam->nbuffers; i++) { + if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) + break; + } + if (i == cam->nbuffers) { + mutex_unlock(&cam->fileop_mutex); + return -EINVAL; + } + + vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED; + + pos = cam->frame[i].bufmem; + while (size > 0) { /* size is page-aligned */ + if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { + mutex_unlock(&cam->fileop_mutex); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + + vma->vm_ops = &et61x251_vm_ops; + vma->vm_private_data = &cam->frame[i]; + et61x251_vm_open(vma); + + mutex_unlock(&cam->fileop_mutex); + + return 0; +} + +/*****************************************************************************/ + +static int +et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_capability cap = { + .driver = "et61x251", + .version = ET61X251_MODULE_VERSION_CODE, + .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, + }; + + strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); + if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) + strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev), + sizeof(cap.bus_info)); + + if (copy_to_user(arg, &cap, sizeof(cap))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_input i; + + if (copy_from_user(&i, arg, sizeof(i))) + return -EFAULT; + + if (i.index) + return -EINVAL; + + memset(&i, 0, sizeof(i)); + strcpy(i.name, "Camera"); + i.type = V4L2_INPUT_TYPE_CAMERA; + i.capabilities = V4L2_IN_CAP_STD; + + if (copy_to_user(arg, &i, sizeof(i))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg) +{ + int index = 0; + + if (copy_to_user(arg, &index, sizeof(index))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg) +{ + int index; + + if (copy_from_user(&index, arg, sizeof(index))) + return -EFAULT; + + if (index != 0) + return -EINVAL; + + return 0; +} + + +static int +et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg) +{ + struct et61x251_sensor* s = &cam->sensor; + struct v4l2_queryctrl qc; + u8 i; + + if (copy_from_user(&qc, arg, sizeof(qc))) + return -EFAULT; + + for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) + if (qc.id && qc.id == s->qctrl[i].id) { + memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); + if (copy_to_user(arg, &qc, sizeof(qc))) + return -EFAULT; + return 0; + } + + return -EINVAL; +} + + +static int +et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg) +{ + struct et61x251_sensor* s = &cam->sensor; + struct v4l2_control ctrl; + int err = 0; + u8 i; + + if (!s->get_ctrl && !s->set_ctrl) + return -EINVAL; + + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) + return -EFAULT; + + if (!s->get_ctrl) { + for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) + if (ctrl.id == s->qctrl[i].id) { + ctrl.value = s->_qctrl[i].default_value; + goto exit; + } + return -EINVAL; + } else + err = s->get_ctrl(cam, &ctrl); + +exit: + if (copy_to_user(arg, &ctrl, sizeof(ctrl))) + return -EFAULT; + + return err; +} + + +static int +et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) +{ + struct et61x251_sensor* s = &cam->sensor; + struct v4l2_control ctrl; + u8 i; + int err = 0; + + if (!s->set_ctrl) + return -EINVAL; + + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) + return -EFAULT; + + for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) { + if (ctrl.id == s->qctrl[i].id) { + if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) + return -EINVAL; + if (ctrl.value < s->qctrl[i].minimum || + ctrl.value > s->qctrl[i].maximum) + return -ERANGE; + ctrl.value -= ctrl.value % s->qctrl[i].step; + break; + } + } + if (i == ARRAY_SIZE(s->qctrl)) + return -EINVAL; + if ((err = s->set_ctrl(cam, &ctrl))) + return err; + + s->_qctrl[i].default_value = ctrl.value; + + return 0; +} + + +static int +et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_cropcap* cc = &(cam->sensor.cropcap); + + cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cc->pixelaspect.numerator = 1; + cc->pixelaspect.denominator = 1; + + if (copy_to_user(arg, cc, sizeof(*cc))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg) +{ + struct et61x251_sensor* s = &cam->sensor; + struct v4l2_crop crop = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + }; + + memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); + + if (copy_to_user(arg, &crop, sizeof(crop))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) +{ + struct et61x251_sensor* s = &cam->sensor; + struct v4l2_crop crop; + struct v4l2_rect* rect; + struct v4l2_rect* bounds = &(s->cropcap.bounds); + struct v4l2_pix_format* pix_format = &(s->pix_format); + u8 scale; + const enum et61x251_stream_state stream = cam->stream; + const u32 nbuffers = cam->nbuffers; + u32 i; + int err = 0; + + if (copy_from_user(&crop, arg, sizeof(crop))) + return -EFAULT; + + rect = &(crop.c); + + if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (cam->module_param.force_munmap) + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_S_CROP failed. " + "Unmap the buffers first."); + return -EBUSY; + } + + /* Preserve R,G or B origin */ + rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; + rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; + + if (rect->width < 16) + rect->width = 16; + if (rect->height < 16) + rect->height = 16; + if (rect->width > bounds->width) + rect->width = bounds->width; + if (rect->height > bounds->height) + rect->height = bounds->height; + if (rect->left < bounds->left) + rect->left = bounds->left; + if (rect->top < bounds->top) + rect->top = bounds->top; + if (rect->left + rect->width > bounds->left + bounds->width) + rect->left = bounds->left+bounds->width - rect->width; + if (rect->top + rect->height > bounds->top + bounds->height) + rect->top = bounds->top+bounds->height - rect->height; + + rect->width &= ~15L; + rect->height &= ~15L; + + if (ET61X251_PRESERVE_IMGSCALE) { + /* Calculate the actual scaling factor */ + u32 a, b; + a = rect->width * rect->height; + b = pix_format->width * pix_format->height; + scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; + } else + scale = 1; + + if (cam->stream == STREAM_ON) + if ((err = et61x251_stream_interrupt(cam))) + return err; + + if (copy_to_user(arg, &crop, sizeof(crop))) { + cam->stream = stream; + return -EFAULT; + } + + if (cam->module_param.force_munmap || cam->io == IO_READ) + et61x251_release_buffers(cam); + + err = et61x251_set_crop(cam, rect); + if (s->set_crop) + err += s->set_crop(cam, rect); + err += et61x251_set_scale(cam, scale); + + if (err) { /* atomic, no rollback in ioctl() */ + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); + return -EIO; + } + + s->pix_format.width = rect->width/scale; + s->pix_format.height = rect->height/scale; + memcpy(&(s->_rect), rect, sizeof(*rect)); + + if ((cam->module_param.force_munmap || cam->io == IO_READ) && + nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); + return -ENOMEM; + } + + if (cam->io == IO_READ) + et61x251_empty_framequeues(cam); + else if (cam->module_param.force_munmap) + et61x251_requeue_outqueue(cam); + + cam->stream = stream; + + return 0; +} + + +static int +et61x251_vidioc_enum_framesizes(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_frmsizeenum frmsize; + + if (copy_from_user(&frmsize, arg, sizeof(frmsize))) + return -EFAULT; + + if (frmsize.index != 0) + return -EINVAL; + + if (frmsize.pixel_format != V4L2_PIX_FMT_ET61X251 && + frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) + return -EINVAL; + + frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE; + frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16; + frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16; + frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width; + frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height; + memset(&frmsize.reserved, 0, sizeof(frmsize.reserved)); + + if (copy_to_user(arg, &frmsize, sizeof(frmsize))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_fmtdesc fmtd; + + if (copy_from_user(&fmtd, arg, sizeof(fmtd))) + return -EFAULT; + + if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (fmtd.index == 0) { + strcpy(fmtd.description, "bayer rgb"); + fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; + } else if (fmtd.index == 1) { + strcpy(fmtd.description, "compressed"); + fmtd.pixelformat = V4L2_PIX_FMT_ET61X251; + fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; + } else + return -EINVAL; + + fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); + + if (copy_to_user(arg, &fmtd, sizeof(fmtd))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_format format; + struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); + + if (copy_from_user(&format, arg, sizeof(format))) + return -EFAULT; + + if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ? + 0 : V4L2_COLORSPACE_SRGB; + pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251) + ? 0 : (pfmt->width * pfmt->priv) / 8; + pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); + pfmt->field = V4L2_FIELD_NONE; + memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); + + if (copy_to_user(arg, &format, sizeof(format))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, + void __user * arg) +{ + struct et61x251_sensor* s = &cam->sensor; + struct v4l2_format format; + struct v4l2_pix_format* pix; + struct v4l2_pix_format* pfmt = &(s->pix_format); + struct v4l2_rect* bounds = &(s->cropcap.bounds); + struct v4l2_rect rect; + u8 scale; + const enum et61x251_stream_state stream = cam->stream; + const u32 nbuffers = cam->nbuffers; + u32 i; + int err = 0; + + if (copy_from_user(&format, arg, sizeof(format))) + return -EFAULT; + + pix = &(format.fmt.pix); + + if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memcpy(&rect, &(s->_rect), sizeof(rect)); + + { /* calculate the actual scaling factor */ + u32 a, b; + a = rect.width * rect.height; + b = pix->width * pix->height; + scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; + } + + rect.width = scale * pix->width; + rect.height = scale * pix->height; + + if (rect.width < 16) + rect.width = 16; + if (rect.height < 16) + rect.height = 16; + if (rect.width > bounds->left + bounds->width - rect.left) + rect.width = bounds->left + bounds->width - rect.left; + if (rect.height > bounds->top + bounds->height - rect.top) + rect.height = bounds->top + bounds->height - rect.top; + + rect.width &= ~15L; + rect.height &= ~15L; + + { /* adjust the scaling factor */ + u32 a, b; + a = rect.width * rect.height; + b = pix->width * pix->height; + scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; + } + + pix->width = rect.width / scale; + pix->height = rect.height / scale; + + if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 && + pix->pixelformat != V4L2_PIX_FMT_SBGGR8) + pix->pixelformat = pfmt->pixelformat; + pix->priv = pfmt->priv; /* bpp */ + pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ? + 0 : V4L2_COLORSPACE_SRGB; + pix->colorspace = pfmt->colorspace; + pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) + ? 0 : (pix->width * pix->priv) / 8; + pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); + pix->field = V4L2_FIELD_NONE; + + if (cmd == VIDIOC_TRY_FMT) { + if (copy_to_user(arg, &format, sizeof(format))) + return -EFAULT; + return 0; + } + + if (cam->module_param.force_munmap) + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_S_FMT failed. " + "Unmap the buffers first."); + return -EBUSY; + } + + if (cam->stream == STREAM_ON) + if ((err = et61x251_stream_interrupt(cam))) + return err; + + if (copy_to_user(arg, &format, sizeof(format))) { + cam->stream = stream; + return -EFAULT; + } + + if (cam->module_param.force_munmap || cam->io == IO_READ) + et61x251_release_buffers(cam); + + err += et61x251_set_pix_format(cam, pix); + err += et61x251_set_crop(cam, &rect); + if (s->set_pix_format) + err += s->set_pix_format(cam, pix); + if (s->set_crop) + err += s->set_crop(cam, &rect); + err += et61x251_set_scale(cam, scale); + + if (err) { /* atomic, no rollback in ioctl() */ + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); + return -EIO; + } + + memcpy(pfmt, pix, sizeof(*pix)); + memcpy(&(s->_rect), &rect, sizeof(rect)); + + if ((cam->module_param.force_munmap || cam->io == IO_READ) && + nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); + return -ENOMEM; + } + + if (cam->io == IO_READ) + et61x251_empty_framequeues(cam); + else if (cam->module_param.force_munmap) + et61x251_requeue_outqueue(cam); + + cam->stream = stream; + + return 0; +} + + +static int +et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg) +{ + if (copy_to_user(arg, &cam->compression, + sizeof(cam->compression))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_jpegcompression jc; + const enum et61x251_stream_state stream = cam->stream; + int err = 0; + + if (copy_from_user(&jc, arg, sizeof(jc))) + return -EFAULT; + + if (jc.quality != 0 && jc.quality != 1) + return -EINVAL; + + if (cam->stream == STREAM_ON) + if ((err = et61x251_stream_interrupt(cam))) + return err; + + err += et61x251_set_compression(cam, &jc); + if (err) { /* atomic, no rollback in ioctl() */ + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " + "problems. To use the camera, close and open " + "%s again.", video_device_node_name(cam->v4ldev)); + return -EIO; + } + + cam->compression.quality = jc.quality; + + cam->stream = stream; + + return 0; +} + + +static int +et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_requestbuffers rb; + u32 i; + int err; + + if (copy_from_user(&rb, arg, sizeof(rb))) + return -EFAULT; + + if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + rb.memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + if (cam->io == IO_READ) { + DBG(3, "Close and open the device again to choose the mmap " + "I/O method"); + return -EBUSY; + } + + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_REQBUFS failed. " + "Previous buffers are still mapped."); + return -EBUSY; + } + + if (cam->stream == STREAM_ON) + if ((err = et61x251_stream_interrupt(cam))) + return err; + + et61x251_empty_framequeues(cam); + + et61x251_release_buffers(cam); + if (rb.count) + rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP); + + if (copy_to_user(arg, &rb, sizeof(rb))) { + et61x251_release_buffers(cam); + cam->io = IO_NONE; + return -EFAULT; + } + + cam->io = rb.count ? IO_MMAP : IO_NONE; + + return 0; +} + + +static int +et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_buffer b; + + if (copy_from_user(&b, arg, sizeof(b))) + return -EFAULT; + + if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b.index >= cam->nbuffers || cam->io != IO_MMAP) + return -EINVAL; + + memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); + + if (cam->frame[b.index].vma_use_count) + b.flags |= V4L2_BUF_FLAG_MAPPED; + + if (cam->frame[b.index].state == F_DONE) + b.flags |= V4L2_BUF_FLAG_DONE; + else if (cam->frame[b.index].state != F_UNUSED) + b.flags |= V4L2_BUF_FLAG_QUEUED; + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_buffer b; + unsigned long lock_flags; + + if (copy_from_user(&b, arg, sizeof(b))) + return -EFAULT; + + if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b.index >= cam->nbuffers || cam->io != IO_MMAP) + return -EINVAL; + + if (cam->frame[b.index].state != F_UNUSED) + return -EINVAL; + + cam->frame[b.index].state = F_QUEUED; + + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + + PDBGG("Frame #%lu queued", (unsigned long)b.index); + + return 0; +} + + +static int +et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp, + void __user * arg) +{ + struct v4l2_buffer b; + struct et61x251_frame_t *f; + unsigned long lock_flags; + long timeout; + + if (copy_from_user(&b, arg, sizeof(b))) + return -EFAULT; + + if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) + return -EINVAL; + + if (list_empty(&cam->outqueue)) { + if (cam->stream == STREAM_OFF) + return -EINVAL; + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) + return timeout; + if (cam->state & DEV_DISCONNECTED) + return -ENODEV; + if (!timeout || (cam->state & DEV_MISCONFIGURED)) + return -EIO; + } + + spin_lock_irqsave(&cam->queue_lock, lock_flags); + f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame); + list_del(cam->outqueue.next); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + + f->state = F_UNUSED; + + memcpy(&b, &f->buf, sizeof(b)); + if (f->vma_use_count) + b.flags |= V4L2_BUF_FLAG_MAPPED; + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + + PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); + + return 0; +} + + +static int +et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg) +{ + int type; + + if (copy_from_user(&type, arg, sizeof(type))) + return -EFAULT; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) + return -EINVAL; + + cam->stream = STREAM_ON; + + DBG(3, "Stream on"); + + return 0; +} + + +static int +et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg) +{ + int type, err; + + if (copy_from_user(&type, arg, sizeof(type))) + return -EFAULT; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) + return -EINVAL; + + if (cam->stream == STREAM_ON) + if ((err = et61x251_stream_interrupt(cam))) + return err; + + et61x251_empty_framequeues(cam); + + DBG(3, "Stream off"); + + return 0; +} + + +static int +et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_streamparm sp; + + if (copy_from_user(&sp, arg, sizeof(sp))) + return -EFAULT; + + if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + sp.parm.capture.extendedmode = 0; + sp.parm.capture.readbuffers = cam->nreadbuffers; + + if (copy_to_user(arg, &sp, sizeof(sp))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg) +{ + struct v4l2_streamparm sp; + + if (copy_from_user(&sp, arg, sizeof(sp))) + return -EFAULT; + + if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + sp.parm.capture.extendedmode = 0; + + if (sp.parm.capture.readbuffers == 0) + sp.parm.capture.readbuffers = cam->nreadbuffers; + + if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES) + sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES; + + if (copy_to_user(arg, &sp, sizeof(sp))) + return -EFAULT; + + cam->nreadbuffers = sp.parm.capture.readbuffers; + + return 0; +} + + +static long et61x251_ioctl_v4l2(struct file *filp, + unsigned int cmd, void __user *arg) +{ + struct et61x251_device *cam = video_drvdata(filp); + + switch (cmd) { + + case VIDIOC_QUERYCAP: + return et61x251_vidioc_querycap(cam, arg); + + case VIDIOC_ENUMINPUT: + return et61x251_vidioc_enuminput(cam, arg); + + case VIDIOC_G_INPUT: + return et61x251_vidioc_g_input(cam, arg); + + case VIDIOC_S_INPUT: + return et61x251_vidioc_s_input(cam, arg); + + case VIDIOC_QUERYCTRL: + return et61x251_vidioc_query_ctrl(cam, arg); + + case VIDIOC_G_CTRL: + return et61x251_vidioc_g_ctrl(cam, arg); + + case VIDIOC_S_CTRL: + return et61x251_vidioc_s_ctrl(cam, arg); + + case VIDIOC_CROPCAP: + return et61x251_vidioc_cropcap(cam, arg); + + case VIDIOC_G_CROP: + return et61x251_vidioc_g_crop(cam, arg); + + case VIDIOC_S_CROP: + return et61x251_vidioc_s_crop(cam, arg); + + case VIDIOC_ENUM_FMT: + return et61x251_vidioc_enum_fmt(cam, arg); + + case VIDIOC_G_FMT: + return et61x251_vidioc_g_fmt(cam, arg); + + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: + return et61x251_vidioc_try_s_fmt(cam, cmd, arg); + + case VIDIOC_ENUM_FRAMESIZES: + return et61x251_vidioc_enum_framesizes(cam, arg); + + case VIDIOC_G_JPEGCOMP: + return et61x251_vidioc_g_jpegcomp(cam, arg); + + case VIDIOC_S_JPEGCOMP: + return et61x251_vidioc_s_jpegcomp(cam, arg); + + case VIDIOC_REQBUFS: + return et61x251_vidioc_reqbufs(cam, arg); + + case VIDIOC_QUERYBUF: + return et61x251_vidioc_querybuf(cam, arg); + + case VIDIOC_QBUF: + return et61x251_vidioc_qbuf(cam, arg); + + case VIDIOC_DQBUF: + return et61x251_vidioc_dqbuf(cam, filp, arg); + + case VIDIOC_STREAMON: + return et61x251_vidioc_streamon(cam, arg); + + case VIDIOC_STREAMOFF: + return et61x251_vidioc_streamoff(cam, arg); + + case VIDIOC_G_PARM: + return et61x251_vidioc_g_parm(cam, arg); + + case VIDIOC_S_PARM: + return et61x251_vidioc_s_parm(cam, arg); + + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_QUERYSTD: + case VIDIOC_ENUMSTD: + case VIDIOC_QUERYMENU: + case VIDIOC_ENUM_FRAMEINTERVALS: + return -EINVAL; + + default: + return -EINVAL; + + } +} + + +static long et61x251_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct et61x251_device *cam = video_drvdata(filp); + long err = 0; + + if (mutex_lock_interruptible(&cam->fileop_mutex)) + return -ERESTARTSYS; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + mutex_unlock(&cam->fileop_mutex); + return -ENODEV; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it " + "again."); + mutex_unlock(&cam->fileop_mutex); + return -EIO; + } + + V4LDBG(3, "et61x251", cmd); + + err = et61x251_ioctl_v4l2(filp, cmd, (void __user *)arg); + + mutex_unlock(&cam->fileop_mutex); + + return err; +} + + +static const struct v4l2_file_operations et61x251_fops = { + .owner = THIS_MODULE, + .open = et61x251_open, + .release = et61x251_release, + .unlocked_ioctl = et61x251_ioctl, + .read = et61x251_read, + .poll = et61x251_poll, + .mmap = et61x251_mmap, +}; + +/*****************************************************************************/ + +/* It exists a single interface only. We do not need to validate anything. */ +static int +et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct et61x251_device* cam; + static unsigned int dev_nr; + unsigned int i; + int err = 0; + + if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL))) + return -ENOMEM; + + cam->usbdev = udev; + + if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { + DBG(1, "kmalloc() failed"); + err = -ENOMEM; + goto fail; + } + + if (!(cam->v4ldev = video_device_alloc())) { + DBG(1, "video_device_alloc() failed"); + err = -ENOMEM; + goto fail; + } + + DBG(2, "ET61X[12]51 PC Camera Controller detected " + "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct); + + for (i = 0; et61x251_sensor_table[i]; i++) { + err = et61x251_sensor_table[i](cam); + if (!err) + break; + } + + if (!err) + DBG(2, "%s image sensor detected", cam->sensor.name); + else { + DBG(1, "No supported image sensor detected"); + err = -ENODEV; + goto fail; + } + + if (et61x251_init(cam)) { + DBG(1, "Initialization failed. I will retry on open()."); + cam->state |= DEV_MISCONFIGURED; + } + + strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); + cam->v4ldev->fops = &et61x251_fops; + cam->v4ldev->release = video_device_release; + cam->v4ldev->parent = &udev->dev; + video_set_drvdata(cam->v4ldev, cam); + + init_completion(&cam->probe); + + err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, + video_nr[dev_nr]); + if (err) { + DBG(1, "V4L2 device registration failed"); + if (err == -ENFILE && video_nr[dev_nr] == -1) + DBG(1, "Free /dev/videoX node not found"); + video_nr[dev_nr] = -1; + dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; + complete_all(&cam->probe); + goto fail; + } + + DBG(2, "V4L2 device registered as %s", + video_device_node_name(cam->v4ldev)); + + cam->module_param.force_munmap = force_munmap[dev_nr]; + cam->module_param.frame_timeout = frame_timeout[dev_nr]; + + dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + err = et61x251_create_sysfs(cam); + if (!err) + DBG(2, "Optional device control through 'sysfs' " + "interface ready"); + else + DBG(2, "Failed to create 'sysfs' interface for optional " + "device controlling. Error #%d", err); +#else + DBG(2, "Optional device control through 'sysfs' interface disabled"); + DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " + "configuration option to enable it."); +#endif + + usb_set_intfdata(intf, cam); + kref_init(&cam->kref); + usb_get_dev(cam->usbdev); + + complete_all(&cam->probe); + + return 0; + +fail: + if (cam) { + kfree(cam->control_buffer); + if (cam->v4ldev) + video_device_release(cam->v4ldev); + kfree(cam); + } + return err; +} + + +static void et61x251_usb_disconnect(struct usb_interface* intf) +{ + struct et61x251_device* cam; + + down_write(&et61x251_dev_lock); + + cam = usb_get_intfdata(intf); + + DBG(2, "Disconnecting %s...", cam->v4ldev->name); + + if (cam->users) { + DBG(2, "Device %s is open! Deregistration and memory " + "deallocation are deferred.", + video_device_node_name(cam->v4ldev)); + cam->state |= DEV_MISCONFIGURED; + et61x251_stop_transfer(cam); + cam->state |= DEV_DISCONNECTED; + wake_up_interruptible(&cam->wait_frame); + wake_up(&cam->wait_stream); + } else + cam->state |= DEV_DISCONNECTED; + + wake_up_interruptible_all(&cam->wait_open); + + kref_put(&cam->kref, et61x251_release_resources); + + up_write(&et61x251_dev_lock); +} + + +static struct usb_driver et61x251_usb_driver = { + .name = "et61x251", + .id_table = et61x251_id_table, + .probe = et61x251_usb_probe, + .disconnect = et61x251_usb_disconnect, +}; + +/*****************************************************************************/ + +static int __init et61x251_module_init(void) +{ + int err = 0; + + KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION); + KDBG(3, ET61X251_MODULE_AUTHOR); + + if ((err = usb_register(&et61x251_usb_driver))) + KDBG(1, "usb_register() failed"); + + return err; +} + + +static void __exit et61x251_module_exit(void) +{ + usb_deregister(&et61x251_usb_driver); +} + + +module_init(et61x251_module_init); +module_exit(et61x251_module_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,210 @@ +/*************************************************************************** + * V4L2 driver for ET61X[12]51 PC Camera Controllers * + * * + * Copyright (C) 2006 by Luca Risolia * + * * + * 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, or * + * (at your option) any later version. * + * * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#ifndef _ET61X251_H_ +#define _ET61X251_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "et61x251_sensor.h" + +/*****************************************************************************/ + +#define ET61X251_DEBUG +#define ET61X251_DEBUG_LEVEL 2 +#define ET61X251_MAX_DEVICES 64 +#define ET61X251_PRESERVE_IMGSCALE 0 +#define ET61X251_FORCE_MUNMAP 0 +#define ET61X251_MAX_FRAMES 32 +#define ET61X251_COMPRESSION_QUALITY 0 +#define ET61X251_URBS 2 +#define ET61X251_ISO_PACKETS 7 +#define ET61X251_ALTERNATE_SETTING 13 +#define ET61X251_URB_TIMEOUT msecs_to_jiffies(2 * ET61X251_ISO_PACKETS) +#define ET61X251_CTRL_TIMEOUT 100 +#define ET61X251_FRAME_TIMEOUT 2 + +/*****************************************************************************/ + +static const struct usb_device_id et61x251_id_table[] = { + { USB_DEVICE(0x102c, 0x6251), }, + { } +}; + +ET61X251_SENSOR_TABLE + +/*****************************************************************************/ + +enum et61x251_frame_state { + F_UNUSED, + F_QUEUED, + F_GRABBING, + F_DONE, + F_ERROR, +}; + +struct et61x251_frame_t { + void* bufmem; + struct v4l2_buffer buf; + enum et61x251_frame_state state; + struct list_head frame; + unsigned long vma_use_count; +}; + +enum et61x251_dev_state { + DEV_INITIALIZED = 0x01, + DEV_DISCONNECTED = 0x02, + DEV_MISCONFIGURED = 0x04, +}; + +enum et61x251_io_method { + IO_NONE, + IO_READ, + IO_MMAP, +}; + +enum et61x251_stream_state { + STREAM_OFF, + STREAM_INTERRUPT, + STREAM_ON, +}; + +struct et61x251_sysfs_attr { + u8 reg, i2c_reg; +}; + +struct et61x251_module_param { + u8 force_munmap; + u16 frame_timeout; +}; + +static DEFINE_MUTEX(et61x251_sysfs_lock); +static DECLARE_RWSEM(et61x251_dev_lock); + +struct et61x251_device { + struct video_device* v4ldev; + + struct et61x251_sensor sensor; + + struct usb_device* usbdev; + struct urb* urb[ET61X251_URBS]; + void* transfer_buffer[ET61X251_URBS]; + u8* control_buffer; + + struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES]; + struct list_head inqueue, outqueue; + u32 frame_count, nbuffers, nreadbuffers; + + enum et61x251_io_method io; + enum et61x251_stream_state stream; + + struct v4l2_jpegcompression compression; + + struct et61x251_sysfs_attr sysfs; + struct et61x251_module_param module_param; + + struct kref kref; + enum et61x251_dev_state state; + u8 users; + + struct completion probe; + struct mutex open_mutex, fileop_mutex; + spinlock_t queue_lock; + wait_queue_head_t wait_open, wait_frame, wait_stream; +}; + +/*****************************************************************************/ + +struct et61x251_device* +et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id) +{ + return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; +} + + +void +et61x251_attach_sensor(struct et61x251_device* cam, + const struct et61x251_sensor* sensor) +{ + memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor)); +} + +/*****************************************************************************/ + +#undef DBG +#undef KDBG +#ifdef ET61X251_DEBUG +# define DBG(level, fmt, args...) \ +do { \ + if (debug >= (level)) { \ + if ((level) == 1) \ + dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ + else if ((level) == 2) \ + dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ + else if ((level) >= 3) \ + dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ + __FILE__, __func__, __LINE__ , ## args); \ + } \ +} while (0) +# define KDBG(level, fmt, args...) \ +do { \ + if (debug >= (level)) { \ + if ((level) == 1 || (level) == 2) \ + pr_info("et61x251: " fmt "\n", ## args); \ + else if ((level) == 3) \ + pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \ + __func__, __LINE__ , ## args); \ + } \ +} while (0) +# define V4LDBG(level, name, cmd) \ +do { \ + if (debug >= (level)) \ + v4l_print_ioctl(name, cmd); \ +} while (0) +#else +# define DBG(level, fmt, args...) do {;} while(0) +# define KDBG(level, fmt, args...) do {;} while(0) +# define V4LDBG(level, name, cmd) do {;} while(0) +#endif + +#undef PDBG +#define PDBG(fmt, args...) \ +dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \ + __LINE__ , ## args) + +#undef PDBGG +#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ + +#endif /* _ET61X251_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_sensor.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_sensor.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_sensor.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_sensor.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,108 @@ +/*************************************************************************** + * API for image sensors connected to ET61X[12]51 PC Camera Controllers * + * * + * Copyright (C) 2006-2007 by Luca Risolia * + * * + * 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, or * + * (at your option) any later version. * + * * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#ifndef _ET61X251_SENSOR_H_ +#define _ET61X251_SENSOR_H_ + +#include +#include +#include +#include +#include +#include + +struct et61x251_device; +struct et61x251_sensor; + +/*****************************************************************************/ + +extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam); + +#define ET61X251_SENSOR_TABLE \ +/* Weak detections must go at the end of the list */ \ +static int (*et61x251_sensor_table[])(struct et61x251_device*) = { \ + &et61x251_probe_tas5130d1b, \ + NULL, \ +}; + +extern struct et61x251_device* +et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id); + +extern void +et61x251_attach_sensor(struct et61x251_device* cam, + const struct et61x251_sensor* sensor); + +/*****************************************************************************/ + +extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index); +extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1, + u8 data2, u8 data3, u8 data4, u8 data5, + u8 data6, u8 data7, u8 data8, u8 address); + +/*****************************************************************************/ + +enum et61x251_i2c_sysfs_ops { + ET61X251_I2C_READ = 0x01, + ET61X251_I2C_WRITE = 0x02, +}; + +enum et61x251_i2c_interface { + ET61X251_I2C_2WIRES, + ET61X251_I2C_3WIRES, +}; + +/* Repeat start condition when RSTA is high */ +enum et61x251_i2c_rsta { + ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */ + ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */ +}; + +#define ET61X251_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10) + +struct et61x251_sensor { + char name[32]; + + enum et61x251_i2c_sysfs_ops sysfs_ops; + + enum et61x251_i2c_interface interface; + u8 i2c_slave_id; + enum et61x251_i2c_rsta rsta; + struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */ + + struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS]; + struct v4l2_cropcap cropcap; + struct v4l2_pix_format pix_format; + + int (*init)(struct et61x251_device* cam); + int (*get_ctrl)(struct et61x251_device* cam, + struct v4l2_control* ctrl); + int (*set_ctrl)(struct et61x251_device* cam, + const struct v4l2_control* ctrl); + int (*set_crop)(struct et61x251_device* cam, + const struct v4l2_rect* rect); + int (*set_pix_format)(struct et61x251_device* cam, + const struct v4l2_pix_format* pix); + + /* Private */ + struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS]; + struct v4l2_rect _rect; +}; + +#endif /* _ET61X251_SENSOR_H_ */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_tas5130d1b.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_tas5130d1b.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_tas5130d1b.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/et61x251_tas5130d1b.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,141 @@ +/*************************************************************************** + * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51 * + * PC Camera Controllers * + * * + * Copyright (C) 2006-2007 by Luca Risolia * + * * + * 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, or * + * (at your option) any later version. * + * * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "et61x251_sensor.h" + + +static int tas5130d1b_init(struct et61x251_device* cam) +{ + int err = 0; + + err += et61x251_write_reg(cam, 0x14, 0x01); + err += et61x251_write_reg(cam, 0x1b, 0x02); + err += et61x251_write_reg(cam, 0x02, 0x12); + err += et61x251_write_reg(cam, 0x0e, 0x60); + err += et61x251_write_reg(cam, 0x80, 0x61); + err += et61x251_write_reg(cam, 0xf0, 0x62); + err += et61x251_write_reg(cam, 0x03, 0x63); + err += et61x251_write_reg(cam, 0x14, 0x64); + err += et61x251_write_reg(cam, 0xf4, 0x65); + err += et61x251_write_reg(cam, 0x01, 0x66); + err += et61x251_write_reg(cam, 0x05, 0x67); + err += et61x251_write_reg(cam, 0x8f, 0x68); + err += et61x251_write_reg(cam, 0x0f, 0x8d); + err += et61x251_write_reg(cam, 0x08, 0x8e); + + return err; +} + + +static int tas5130d1b_set_ctrl(struct et61x251_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_GAIN: + err += et61x251_i2c_raw_write(cam, 2, 0x20, + 0xf6-ctrl->value, 0, 0, 0, + 0, 0, 0, 0); + break; + case V4L2_CID_EXPOSURE: + err += et61x251_i2c_raw_write(cam, 2, 0x40, + 0x47-ctrl->value, 0, 0, 0, + 0, 0, 0, 0); + break; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + + +static const struct et61x251_sensor tas5130d1b = { + .name = "TAS5130D1B", + .interface = ET61X251_I2C_3WIRES, + .rsta = ET61X251_I2C_RSTA_STOP, + .active_pixel = { + .left = 106, + .top = 13, + }, + .init = &tas5130d1b_init, + .qctrl = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0xf6, + .step = 0x02, + .default_value = 0x0d, + .flags = 0, + }, + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = 0x47, + .step = 0x01, + .default_value = 0x23, + .flags = 0, + }, + }, + .set_ctrl = &tas5130d1b_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, +}; + + +int et61x251_probe_tas5130d1b(struct et61x251_device* cam) +{ + const struct usb_device_id tas5130d1b_id_table[] = { + { USB_DEVICE(0x102c, 0x6251), }, + { } + }; + + /* Sensor detection is based on USB pid/vid */ + if (!et61x251_match_id(cam, tas5130d1b_id_table)) + return -ENODEV; + + et61x251_attach_sensor(cam, &tas5130d1b); + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,18 @@ +config USB_ET61X251 + tristate "USB ET61X[12]51 PC Camera Controller support (DEPRECATED)" + depends on VIDEO_V4L2 + default n + ---help--- + This driver is DEPRECATED please use the gspca zc3xx module + instead. + + Say Y here if you want support for cameras based on Etoms ET61X151 + or ET61X251 PC Camera Controllers. + + See for more info. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" to use this driver. + + To compile this driver as a module, choose M here: the + module will be called et61x251. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/et61x251/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,4 @@ +et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o + +obj-$(CONFIG_USB_ET61X251) += et61x251.o + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/fsl-viu.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/fsl-viu.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/fsl-viu.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/fsl-viu.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1686 @@ +/* + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Freescale VIU video driver + * + * Authors: Hongjun Chen + * Porting to 2.6.35 by DENX Software Engineering, + * Anatolij Gustschin + * + * 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, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "fsl_viu" +#define VIU_MAJOR_VERSION 0 +#define VIU_MINOR_VERSION 5 +#define VIU_RELEASE 0 +#define VIU_VERSION KERNEL_VERSION(VIU_MAJOR_VERSION, \ + VIU_MINOR_VERSION, \ + VIU_RELEASE) + +#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ + +#define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */ + +/* I2C address of video decoder chip is 0x4A */ +#define VIU_VIDEO_DECODER_ADDR 0x25 + +/* supported controls */ +static struct v4l2_queryctrl viu_qctrl[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + .flags = 0, + }, { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 0x1, + .default_value = 0x10, + .flags = 0, + }, { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 0x1, + .default_value = 127, + .flags = 0, + }, { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = -128, + .maximum = 127, + .step = 0x1, + .default_value = 0, + .flags = 0, + } +}; + +static int qctl_regs[ARRAY_SIZE(viu_qctrl)]; + +static int info_level; + +#define dprintk(level, fmt, arg...) \ + do { \ + if (level <= info_level) \ + printk(KERN_DEBUG "viu: " fmt , ## arg); \ + } while (0) + +/* + * Basic structures + */ +struct viu_fmt { + char name[32]; + u32 fourcc; /* v4l2 format id */ + u32 pixelformat; + int depth; +}; + +static struct viu_fmt formats[] = { + { + .name = "RGB-16 (5/B-6/G-5/R)", + .fourcc = V4L2_PIX_FMT_RGB565, + .pixelformat = V4L2_PIX_FMT_RGB565, + .depth = 16, + }, { + .name = "RGB-32 (A-R-G-B)", + .fourcc = V4L2_PIX_FMT_RGB32, + .pixelformat = V4L2_PIX_FMT_RGB32, + .depth = 32, + } +}; + +struct viu_dev; +struct viu_buf; + +/* buffer for one video frame */ +struct viu_buf { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + struct viu_fmt *fmt; +}; + +struct viu_dmaqueue { + struct viu_dev *dev; + struct list_head active; + struct list_head queued; + struct timer_list timeout; +}; + +struct viu_status { + u32 field_irq; + u32 vsync_irq; + u32 hsync_irq; + u32 vstart_irq; + u32 dma_end_irq; + u32 error_irq; +}; + +struct viu_reg { + u32 status_cfg; + u32 luminance; + u32 chroma_r; + u32 chroma_g; + u32 chroma_b; + u32 field_base_addr; + u32 dma_inc; + u32 picture_count; + u32 req_alarm; + u32 alpha; +} __attribute__ ((packed)); + +struct viu_dev { + struct v4l2_device v4l2_dev; + struct mutex lock; + spinlock_t slock; + int users; + + struct device *dev; + /* various device info */ + struct video_device *vdev; + struct viu_dmaqueue vidq; + enum v4l2_field capfield; + int field; + int first; + int dma_done; + + /* Hardware register area */ + struct viu_reg *vr; + + /* Interrupt vector */ + int irq; + struct viu_status irqs; + + /* video overlay */ + struct v4l2_framebuffer ovbuf; + struct viu_fmt *ovfmt; + unsigned int ovenable; + enum v4l2_field ovfield; + + /* crop */ + struct v4l2_rect crop_current; + + /* clock pointer */ + struct clk *clk; + + /* decoder */ + struct v4l2_subdev *decoder; + + v4l2_std_id std; +}; + +struct viu_fh { + struct viu_dev *dev; + + /* video capture */ + struct videobuf_queue vb_vidq; + spinlock_t vbq_lock; /* spinlock for the videobuf queue */ + + /* video overlay */ + struct v4l2_window win; + struct v4l2_clip clips[1]; + + /* video capture */ + struct viu_fmt *fmt; + int width, height, sizeimage; + enum v4l2_buf_type type; +}; + +static struct viu_reg reg_val; + +/* + * Macro definitions of VIU registers + */ + +/* STATUS_CONFIG register */ +enum status_config { + SOFT_RST = 1 << 0, + + ERR_MASK = 0x0f << 4, /* Error code mask */ + ERR_NO = 0x00, /* No error */ + ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */ + ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */ + ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */ + ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */ + ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */ + ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */ + ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */ + ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */ + ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */ + ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */ + + INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */ + INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */ + INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */ + INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */ + INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */ + INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */ + INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */ + + INT_FIELD_STATUS = 0x01 << 16, /* field interrupt status */ + INT_VSYNC_STATUS = 0x01 << 17, /* vsync interrupt status */ + INT_HSYNC_STATUS = 0x01 << 18, /* hsync interrupt status */ + INT_VSTART_STATUS = 0x01 << 19, /* vstart interrupt status */ + INT_DMA_END_STATUS = 0x01 << 20, /* DMA end interrupt status */ + INT_ERROR_STATUS = 0x01 << 21, /* error interrupt status */ + + DMA_ACT = 0x01 << 27, /* Enable DMA transfer */ + FIELD_NO = 0x01 << 28, /* Field number */ + DITHER_ON = 0x01 << 29, /* Dithering is on */ + ROUND_ON = 0x01 << 30, /* Round is on */ + MODE_32BIT = 0x01 << 31, /* Data in RGBa888, + * 0 in RGB565 + */ +}; + +#define norm_maxw() 720 +#define norm_maxh() 576 + +#define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \ + INT_HSYNC_STATUS | INT_VSTART_STATUS | \ + INT_DMA_END_STATUS | INT_ERROR_STATUS) + +#define NUM_FORMATS ARRAY_SIZE(formats) + +static irqreturn_t viu_intr(int irq, void *dev_id); + +struct viu_fmt *format_by_fourcc(int fourcc) +{ + int i; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].pixelformat == fourcc) + return formats + i; + } + + dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc); + return NULL; +} + +void viu_start_dma(struct viu_dev *dev) +{ + struct viu_reg *vr = dev->vr; + + dev->field = 0; + + /* Enable DMA operation */ + out_be32(&vr->status_cfg, SOFT_RST); + out_be32(&vr->status_cfg, INT_FIELD_EN); +} + +void viu_stop_dma(struct viu_dev *dev) +{ + struct viu_reg *vr = dev->vr; + int cnt = 100; + u32 status_cfg; + + out_be32(&vr->status_cfg, 0); + + /* Clear pending interrupts */ + status_cfg = in_be32(&vr->status_cfg); + if (status_cfg & 0x3f0000) + out_be32(&vr->status_cfg, status_cfg & 0x3f0000); + + if (status_cfg & DMA_ACT) { + do { + status_cfg = in_be32(&vr->status_cfg); + if (status_cfg & INT_DMA_END_STATUS) + break; + } while (cnt--); + + if (cnt < 0) { + /* timed out, issue soft reset */ + out_be32(&vr->status_cfg, SOFT_RST); + out_be32(&vr->status_cfg, 0); + } else { + /* clear DMA_END and other pending irqs */ + out_be32(&vr->status_cfg, status_cfg & 0x3f0000); + } + } + + dev->field = 0; +} + +static int restart_video_queue(struct viu_dmaqueue *vidq) +{ + struct viu_buf *buf, *prev; + + dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq); + if (!list_empty(&vidq->active)) { + buf = list_entry(vidq->active.next, struct viu_buf, vb.queue); + dprintk(2, "restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + + viu_stop_dma(vidq->dev); + + /* cancel all outstanding capture requests */ + list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) { + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + } + mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); + return 0; + } + + prev = NULL; + for (;;) { + if (list_empty(&vidq->queued)) + return 0; + buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue); + if (prev == NULL) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &vidq->active); + + dprintk(1, "Restarting video dma\n"); + viu_stop_dma(vidq->dev); + viu_start_dma(vidq->dev); + + buf->vb.state = VIDEOBUF_ACTIVE; + mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] restart_queue - first active\n", + buf, buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &vidq->active); + buf->vb.state = VIDEOBUF_ACTIVE; + dprintk(2, "[%p/%d] restart_queue - move to active\n", + buf, buf->vb.i); + } else { + return 0; + } + prev = buf; + } +} + +static void viu_vid_timeout(unsigned long data) +{ + struct viu_dev *dev = (struct viu_dev *)data; + struct viu_buf *buf; + struct viu_dmaqueue *vidq = &dev->vidq; + + while (!list_empty(&vidq->active)) { + buf = list_entry(vidq->active.next, struct viu_buf, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i); + } + + restart_video_queue(vidq); +} + +/* + * Videobuf operations + */ +static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, + unsigned int *size) +{ + struct viu_fh *fh = vq->priv_data; + + *size = fh->width * fh->height * fh->fmt->depth >> 3; + if (*count == 0) + *count = 32; + + while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024) + (*count)--; + + dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size); + return 0; +} + +static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf) +{ + struct videobuf_buffer *vb = &buf->vb; + void *vaddr = NULL; + + BUG_ON(in_interrupt()); + + videobuf_waiton(vq, &buf->vb, 0, 0); + + if (vq->int_ops && vq->int_ops->vaddr) + vaddr = vq->int_ops->vaddr(vb); + + if (vaddr) + videobuf_dma_contig_free(vq, &buf->vb); + + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf) +{ + struct viu_reg *vr = dev->vr; + int bpp; + + /* setup the DMA base address */ + reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb); + + dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n", + buf, buf->vb.i, (unsigned long)reg_val.field_base_addr); + + /* interlace is on by default, set horizontal DMA increment */ + reg_val.status_cfg = 0; + bpp = buf->fmt->depth >> 3; + switch (bpp) { + case 2: + reg_val.status_cfg &= ~MODE_32BIT; + reg_val.dma_inc = buf->vb.width * 2; + break; + case 4: + reg_val.status_cfg |= MODE_32BIT; + reg_val.dma_inc = buf->vb.width * 4; + break; + default: + dprintk(0, "doesn't support color depth(%d)\n", + bpp * 8); + return -EINVAL; + } + + /* setup picture_count register */ + reg_val.picture_count = (buf->vb.height / 2) << 16 | + buf->vb.width; + + reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN; + + buf->vb.state = VIDEOBUF_ACTIVE; + dev->capfield = buf->vb.field; + + /* reset dma increment if needed */ + if (!V4L2_FIELD_HAS_BOTH(buf->vb.field)) + reg_val.dma_inc = 0; + + out_be32(&vr->dma_inc, reg_val.dma_inc); + out_be32(&vr->picture_count, reg_val.picture_count); + out_be32(&vr->field_base_addr, reg_val.field_base_addr); + mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT); + return 0; +} + +static int buffer_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct viu_fh *fh = vq->priv_data; + struct viu_buf *buf = container_of(vb, struct viu_buf, vb); + int rc; + + BUG_ON(fh->fmt == NULL); + + if (fh->width < 48 || fh->width > norm_maxw() || + fh->height < 32 || fh->height > norm_maxh()) + return -EINVAL; + buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + if (buf->fmt != fh->fmt || + buf->vb.width != fh->width || + buf->vb.height != fh->height || + buf->vb.field != field) { + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + } + + if (buf->vb.state == VIDEOBUF_NEEDS_INIT) { + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc != 0) + goto fail; + + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + buf->fmt = fh->fmt; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(vq, buf); + return rc; +} + +static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct viu_buf *buf = container_of(vb, struct viu_buf, vb); + struct viu_fh *fh = vq->priv_data; + struct viu_dev *dev = fh->dev; + struct viu_dmaqueue *vidq = &dev->vidq; + struct viu_buf *prev; + + if (!list_empty(&vidq->queued)) { + dprintk(1, "adding vb queue=0x%08lx\n", + (unsigned long)&buf->vb.queue); + dprintk(1, "vidq pointer 0x%p, queued 0x%p\n", + vidq, &vidq->queued); + dprintk(1, "dev %p, queued: self %p, next %p, head %p\n", + dev, &vidq->queued, vidq->queued.next, + vidq->queued.prev); + list_add_tail(&buf->vb.queue, &vidq->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - append to queued\n", + buf, buf->vb.i); + } else if (list_empty(&vidq->active)) { + dprintk(1, "adding vb active=0x%08lx\n", + (unsigned long)&buf->vb.queue); + list_add_tail(&buf->vb.queue, &vidq->active); + buf->vb.state = VIDEOBUF_ACTIVE; + mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] buffer_queue - first active\n", + buf, buf->vb.i); + + buffer_activate(dev, buf); + } else { + dprintk(1, "adding vb queue2=0x%08lx\n", + (unsigned long)&buf->vb.queue); + prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue); + if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_add_tail(&buf->vb.queue, &vidq->active); + buf->vb.state = VIDEOBUF_ACTIVE; + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.i); + } else { + list_add_tail(&buf->vb.queue, &vidq->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - first queued\n", + buf, buf->vb.i); + } + } +} + +static void buffer_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct viu_buf *buf = container_of(vb, struct viu_buf, vb); + struct viu_fh *fh = vq->priv_data; + struct viu_dev *dev = (struct viu_dev *)fh->dev; + + viu_stop_dma(dev); + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops viu_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/* + * IOCTL vidioc handling + */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strcpy(cap->driver, "viu"); + strcpy(cap->card, "viu"); + cap->version = VIU_VERSION; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_READWRITE; + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int index = f->index; + + if (f->index > NUM_FORMATS) + return -EINVAL; + + strlcpy(f->description, formats[index].name, sizeof(f->description)); + f->pixelformat = formats[index].fourcc; + return 0; +} + +static int vidioc_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct viu_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vb_vidq.field; + f->fmt.pix.pixelformat = fh->fmt->pixelformat; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = fh->sizeimage; + return 0; +} + +static int vidioc_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct viu_fmt *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmt) { + dprintk(1, "Fourcc format (0x%08x) invalid.", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + field = f->fmt.pix.field; + + if (field == V4L2_FIELD_ANY) { + field = V4L2_FIELD_INTERLACED; + } else if (field != V4L2_FIELD_INTERLACED) { + dprintk(1, "Field type invalid.\n"); + return -EINVAL; + } + + maxw = norm_maxw(); + maxh = norm_maxh(); + + f->fmt.pix.field = field; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + + return 0; +} + +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct viu_fh *fh = priv; + int ret; + + ret = vidioc_try_fmt_cap(file, fh, f); + if (ret < 0) + return ret; + + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->sizeimage = f->fmt.pix.sizeimage; + fh->vb_vidq.field = f->fmt.pix.field; + fh->type = f->type; + dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name); + return 0; +} + +static int vidioc_g_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct viu_fh *fh = priv; + + f->fmt.win = fh->win; + return 0; +} + +static int verify_preview(struct viu_dev *dev, struct v4l2_window *win) +{ + enum v4l2_field field; + int maxw, maxh; + + if (dev->ovbuf.base == NULL) + return -EINVAL; + if (dev->ovfmt == NULL) + return -EINVAL; + if (win->w.width < 48 || win->w.height < 32) + return -EINVAL; + + field = win->field; + maxw = dev->crop_current.width; + maxh = dev->crop_current.height; + + if (field == V4L2_FIELD_ANY) { + field = (win->w.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + win->field = field; + if (win->w.width > maxw) + win->w.width = maxw; + if (win->w.height > maxh) + win->w.height = maxh; + return 0; +} + +inline void viu_activate_overlay(struct viu_reg *viu_reg) +{ + struct viu_reg *vr = viu_reg; + + out_be32(&vr->field_base_addr, reg_val.field_base_addr); + out_be32(&vr->dma_inc, reg_val.dma_inc); + out_be32(&vr->picture_count, reg_val.picture_count); +} + +static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh) +{ + int bpp; + + dprintk(1, "%s %dx%d %s\n", __func__, + fh->win.w.width, fh->win.w.height, dev->ovfmt->name); + + reg_val.status_cfg = 0; + + /* setup window */ + reg_val.picture_count = (fh->win.w.height / 2) << 16 | + fh->win.w.width; + + /* setup color depth and dma increment */ + bpp = dev->ovfmt->depth / 8; + switch (bpp) { + case 2: + reg_val.status_cfg &= ~MODE_32BIT; + reg_val.dma_inc = fh->win.w.width * 2; + break; + case 4: + reg_val.status_cfg |= MODE_32BIT; + reg_val.dma_inc = fh->win.w.width * 4; + break; + default: + dprintk(0, "device doesn't support color depth(%d)\n", + bpp * 8); + return -EINVAL; + } + + dev->ovfield = fh->win.field; + if (!V4L2_FIELD_HAS_BOTH(dev->ovfield)) + reg_val.dma_inc = 0; + + reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN; + + /* setup the base address of the overlay buffer */ + reg_val.field_base_addr = (u32)dev->ovbuf.base; + + return 0; +} + +static int vidioc_s_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct viu_fh *fh = priv; + struct viu_dev *dev = (struct viu_dev *)fh->dev; + unsigned long flags; + int err; + + err = verify_preview(dev, &f->fmt.win); + if (err) + return err; + + fh->win = f->fmt.win; + + spin_lock_irqsave(&dev->slock, flags); + viu_setup_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); + return 0; +} + +static int vidioc_try_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + return 0; +} + +static int vidioc_overlay(struct file *file, void *priv, unsigned int on) +{ + struct viu_fh *fh = priv; + struct viu_dev *dev = (struct viu_dev *)fh->dev; + unsigned long flags; + + if (on) { + spin_lock_irqsave(&dev->slock, flags); + viu_activate_overlay(dev->vr); + dev->ovenable = 1; + + /* start dma */ + viu_start_dma(dev); + spin_unlock_irqrestore(&dev->slock, flags); + } else { + viu_stop_dma(dev); + dev->ovenable = 0; + } + + return 0; +} + +int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) +{ + struct viu_fh *fh = priv; + struct viu_dev *dev = fh->dev; + struct v4l2_framebuffer *fb = arg; + + *fb = dev->ovbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + return 0; +} + +int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) +{ + struct viu_fh *fh = priv; + struct viu_dev *dev = fh->dev; + struct v4l2_framebuffer *fb = arg; + struct viu_fmt *fmt; + + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (fmt == NULL) + return -EINVAL; + + /* ok, accept it */ + dev->ovbuf = *fb; + dev->ovfmt = fmt; + if (dev->ovbuf.fmt.bytesperline == 0) { + dev->ovbuf.fmt.bytesperline = + dev->ovbuf.fmt.width * fmt->depth / 8; + } + return 0; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct viu_fh *fh = priv; + + return videobuf_reqbufs(&fh->vb_vidq, p); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct viu_fh *fh = priv; + + return videobuf_querybuf(&fh->vb_vidq, p); +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct viu_fh *fh = priv; + + return videobuf_qbuf(&fh->vb_vidq, p); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct viu_fh *fh = priv; + + return videobuf_dqbuf(&fh->vb_vidq, p, + file->f_flags & O_NONBLOCK); +} + +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct viu_fh *fh = priv; + struct viu_dev *dev = fh->dev; + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (fh->type != i) + return -EINVAL; + + if (dev->ovenable) + dev->ovenable = 0; + + viu_start_dma(fh->dev); + + return videobuf_streamon(&fh->vb_vidq); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct viu_fh *fh = priv; + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (fh->type != i) + return -EINVAL; + + viu_stop_dma(fh->dev); + + return videobuf_streamoff(&fh->vb_vidq); +} + +#define decoder_call(viu, o, f, args...) \ + v4l2_subdev_call(viu->decoder, o, f, ##args) + +static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct viu_fh *fh = priv; + + decoder_call(fh->dev, video, querystd, std_id); + return 0; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct viu_fh *fh = priv; + + fh->dev->std = *id; + decoder_call(fh->dev, core, s_std, *id); + return 0; +} + +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct viu_fh *fh = priv; + + *std_id = fh->dev->std; + return 0; +} + +/* only one input in this driver */ +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct viu_fh *fh = priv; + + if (inp->index != 0) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->std = fh->dev->vdev->tvnorms; + strcpy(inp->name, "Camera"); + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct viu_fh *fh = priv; + + if (i > 1) + return -EINVAL; + + decoder_call(fh->dev, video, s_routing, i, 0, 0); + return 0; +} + +/* Controls */ +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) { + if (qc->id && qc->id == viu_qctrl[i].id) { + memcpy(qc, &(viu_qctrl[i]), sizeof(*qc)); + return 0; + } + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) { + if (ctrl->id == viu_qctrl[i].id) { + ctrl->value = qctl_regs[i]; + return 0; + } + } + return -EINVAL; +} +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) { + if (ctrl->id == viu_qctrl[i].id) { + if (ctrl->value < viu_qctrl[i].minimum + || ctrl->value > viu_qctrl[i].maximum) + return -ERANGE; + qctl_regs[i] = ctrl->value; + return 0; + } + } + return -EINVAL; +} + +inline void viu_activate_next_buf(struct viu_dev *dev, + struct viu_dmaqueue *viuq) +{ + struct viu_dmaqueue *vidq = viuq; + struct viu_buf *buf; + + /* launch another DMA operation for an active/queued buffer */ + if (!list_empty(&vidq->active)) { + buf = list_entry(vidq->active.next, struct viu_buf, + vb.queue); + dprintk(1, "start another queued buffer: 0x%p\n", buf); + buffer_activate(dev, buf); + } else if (!list_empty(&vidq->queued)) { + buf = list_entry(vidq->queued.next, struct viu_buf, + vb.queue); + list_del(&buf->vb.queue); + + dprintk(1, "start another queued buffer: 0x%p\n", buf); + list_add_tail(&buf->vb.queue, &vidq->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buffer_activate(dev, buf); + } +} + +inline void viu_default_settings(struct viu_reg *viu_reg) +{ + struct viu_reg *vr = viu_reg; + + out_be32(&vr->luminance, 0x9512A254); + out_be32(&vr->chroma_r, 0x03310000); + out_be32(&vr->chroma_g, 0x06600F38); + out_be32(&vr->chroma_b, 0x00000409); + out_be32(&vr->alpha, 0x000000ff); + out_be32(&vr->req_alarm, 0x00000090); + dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n", + in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr)); +} + +static void viu_overlay_intr(struct viu_dev *dev, u32 status) +{ + struct viu_reg *vr = dev->vr; + + if (status & INT_DMA_END_STATUS) + dev->dma_done = 1; + + if (status & INT_FIELD_STATUS) { + if (dev->dma_done) { + u32 addr = reg_val.field_base_addr; + + dev->dma_done = 0; + if (status & FIELD_NO) + addr += reg_val.dma_inc; + + out_be32(&vr->field_base_addr, addr); + out_be32(&vr->dma_inc, reg_val.dma_inc); + out_be32(&vr->status_cfg, + (status & 0xffc0ffff) | + (status & INT_ALL_STATUS) | + reg_val.status_cfg); + } else if (status & INT_VSYNC_STATUS) { + out_be32(&vr->status_cfg, + (status & 0xffc0ffff) | + (status & INT_ALL_STATUS) | + reg_val.status_cfg); + } + } +} + +static void viu_capture_intr(struct viu_dev *dev, u32 status) +{ + struct viu_dmaqueue *vidq = &dev->vidq; + struct viu_reg *vr = dev->vr; + struct viu_buf *buf; + int field_num; + int need_two; + int dma_done = 0; + + field_num = status & FIELD_NO; + need_two = V4L2_FIELD_HAS_BOTH(dev->capfield); + + if (status & INT_DMA_END_STATUS) { + dma_done = 1; + if (((field_num == 0) && (dev->field == 0)) || + (field_num && (dev->field == 1))) + dev->field++; + } + + if (status & INT_FIELD_STATUS) { + dprintk(1, "irq: field %d, done %d\n", + !!field_num, dma_done); + if (unlikely(dev->first)) { + if (field_num == 0) { + dev->first = 0; + dprintk(1, "activate first buf\n"); + viu_activate_next_buf(dev, vidq); + } else + dprintk(1, "wait field 0\n"); + return; + } + + /* setup buffer address for next dma operation */ + if (!list_empty(&vidq->active)) { + u32 addr = reg_val.field_base_addr; + + if (field_num && need_two) { + addr += reg_val.dma_inc; + dprintk(1, "field 1, 0x%lx, dev field %d\n", + (unsigned long)addr, dev->field); + } + out_be32(&vr->field_base_addr, addr); + out_be32(&vr->dma_inc, reg_val.dma_inc); + out_be32(&vr->status_cfg, + (status & 0xffc0ffff) | + (status & INT_ALL_STATUS) | + reg_val.status_cfg); + return; + } + } + + if (dma_done && field_num && (dev->field == 2)) { + dev->field = 0; + buf = list_entry(vidq->active.next, + struct viu_buf, vb.queue); + dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n", + buf, buf->vb.i, + (unsigned long)videobuf_to_dma_contig(&buf->vb), + (unsigned long)in_be32(&vr->field_base_addr)); + + if (waitqueue_active(&buf->vb.done)) { + list_del(&buf->vb.queue); + do_gettimeofday(&buf->vb.ts); + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + wake_up(&buf->vb.done); + } + /* activate next dma buffer */ + viu_activate_next_buf(dev, vidq); + } +} + +static irqreturn_t viu_intr(int irq, void *dev_id) +{ + struct viu_dev *dev = (struct viu_dev *)dev_id; + struct viu_reg *vr = dev->vr; + u32 status; + u32 error; + + status = in_be32(&vr->status_cfg); + + if (status & INT_ERROR_STATUS) { + dev->irqs.error_irq++; + error = status & ERR_MASK; + if (error) + dprintk(1, "Err: error(%d), times:%d!\n", + error >> 4, dev->irqs.error_irq); + /* Clear interrupt error bit and error flags */ + out_be32(&vr->status_cfg, + (status & 0xffc0ffff) | INT_ERROR_STATUS); + } + + if (status & INT_DMA_END_STATUS) { + dev->irqs.dma_end_irq++; + dev->dma_done = 1; + dprintk(2, "VIU DMA end interrupt times: %d\n", + dev->irqs.dma_end_irq); + } + + if (status & INT_HSYNC_STATUS) + dev->irqs.hsync_irq++; + + if (status & INT_FIELD_STATUS) { + dev->irqs.field_irq++; + dprintk(2, "VIU field interrupt times: %d\n", + dev->irqs.field_irq); + } + + if (status & INT_VSTART_STATUS) + dev->irqs.vstart_irq++; + + if (status & INT_VSYNC_STATUS) { + dev->irqs.vsync_irq++; + dprintk(2, "VIU vsync interrupt times: %d\n", + dev->irqs.vsync_irq); + } + + /* clear all pending irqs */ + status = in_be32(&vr->status_cfg); + out_be32(&vr->status_cfg, + (status & 0xffc0ffff) | (status & INT_ALL_STATUS)); + + if (dev->ovenable) { + viu_overlay_intr(dev, status); + return IRQ_HANDLED; + } + + /* Capture mode */ + viu_capture_intr(dev, status); + return IRQ_HANDLED; +} + +/* + * File operations for the device + */ +static int viu_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct viu_dev *dev = video_get_drvdata(vdev); + struct viu_fh *fh; + struct viu_reg *vr; + int minor = vdev->minor; + u32 status_cfg; + int i; + + dprintk(1, "viu: open (minor=%d)\n", minor); + + dev->users++; + if (dev->users > 1) { + dev->users--; + return -EBUSY; + } + + vr = dev->vr; + + dprintk(1, "open minor=%d type=%s users=%d\n", minor, + v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); + + /* allocate and initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (!fh) { + dev->users--; + return -ENOMEM; + } + + file->private_data = fh; + fh->dev = dev; + + fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fh->fmt = format_by_fourcc(V4L2_PIX_FMT_RGB32); + fh->width = norm_maxw(); + fh->height = norm_maxh(); + dev->crop_current.width = fh->width; + dev->crop_current.height = fh->height; + + /* Put all controls at a sane state */ + for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) + qctl_regs[i] = viu_qctrl[i].default_value; + + dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", + (unsigned long)fh, (unsigned long)dev, + (unsigned long)&dev->vidq); + dprintk(1, "Open: list_empty queued=%d\n", + list_empty(&dev->vidq.queued)); + dprintk(1, "Open: list_empty active=%d\n", + list_empty(&dev->vidq.active)); + + viu_default_settings(vr); + + status_cfg = in_be32(&vr->status_cfg); + out_be32(&vr->status_cfg, + status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN | + INT_FIELD_EN | INT_VSTART_EN | + INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN)); + + status_cfg = in_be32(&vr->status_cfg); + out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS); + + spin_lock_init(&fh->vbq_lock); + videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops, + dev->dev, &fh->vbq_lock, + fh->type, V4L2_FIELD_INTERLACED, + sizeof(struct viu_buf), fh, + &fh->dev->lock); + return 0; +} + +static ssize_t viu_read(struct file *file, char __user *data, size_t count, + loff_t *ppos) +{ + struct viu_fh *fh = file->private_data; + struct viu_dev *dev = fh->dev; + int ret = 0; + + dprintk(2, "%s\n", __func__); + if (dev->ovenable) + dev->ovenable = 0; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + viu_start_dma(dev); + ret = videobuf_read_stream(&fh->vb_vidq, data, count, + ppos, 0, file->f_flags & O_NONBLOCK); + return ret; + } + return 0; +} + +static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait) +{ + struct viu_fh *fh = file->private_data; + struct videobuf_queue *q = &fh->vb_vidq; + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) + return POLLERR; + + return videobuf_poll_stream(file, q, wait); +} + +static int viu_release(struct file *file) +{ + struct viu_fh *fh = file->private_data; + struct viu_dev *dev = fh->dev; + int minor = video_devdata(file)->minor; + + viu_stop_dma(dev); + videobuf_stop(&fh->vb_vidq); + videobuf_mmap_free(&fh->vb_vidq); + + kfree(fh); + + dev->users--; + dprintk(1, "close (minor=%d, users=%d)\n", + minor, dev->users); + return 0; +} + +void viu_reset(struct viu_reg *reg) +{ + out_be32(®->status_cfg, 0); + out_be32(®->luminance, 0x9512a254); + out_be32(®->chroma_r, 0x03310000); + out_be32(®->chroma_g, 0x06600f38); + out_be32(®->chroma_b, 0x00000409); + out_be32(®->field_base_addr, 0); + out_be32(®->dma_inc, 0); + out_be32(®->picture_count, 0x01e002d0); + out_be32(®->req_alarm, 0x00000090); + out_be32(®->alpha, 0x000000ff); +} + +static int viu_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct viu_fh *fh = file->private_data; + int ret; + + dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); + + ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); + + dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n", + (unsigned long)vma->vm_start, + (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, + ret); + + return ret; +} + +static struct v4l2_file_operations viu_fops = { + .owner = THIS_MODULE, + .open = viu_open, + .release = viu_release, + .read = viu_read, + .poll = viu_poll, + .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ + .mmap = viu_mmap, +}; + +static const struct v4l2_ioctl_ops viu_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap, + .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt, + .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay, + .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay, + .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay, + .vidioc_overlay = vidioc_overlay, + .vidioc_g_fbuf = vidioc_g_fbuf, + .vidioc_s_fbuf = vidioc_s_fbuf, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_g_std = vidioc_g_std, + .vidioc_s_std = vidioc_s_std, + .vidioc_querystd = vidioc_querystd, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +}; + +static struct video_device viu_template = { + .name = "FSL viu", + .fops = &viu_fops, + .minor = -1, + .ioctl_ops = &viu_ioctl_ops, + .release = video_device_release, + + .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, + .current_norm = V4L2_STD_NTSC_M, +}; + +static int __devinit viu_of_probe(struct platform_device *op) +{ + struct viu_dev *viu_dev; + struct video_device *vdev; + struct resource r; + struct viu_reg __iomem *viu_regs; + struct i2c_adapter *ad; + int ret, viu_irq; + + ret = of_address_to_resource(op->dev.of_node, 0, &r); + if (ret) { + dev_err(&op->dev, "Can't parse device node resource\n"); + return -ENODEV; + } + + viu_irq = irq_of_parse_and_map(op->dev.of_node, 0); + if (viu_irq == NO_IRQ) { + dev_err(&op->dev, "Error while mapping the irq\n"); + return -EINVAL; + } + + /* request mem region */ + if (!devm_request_mem_region(&op->dev, r.start, + sizeof(struct viu_reg), DRV_NAME)) { + dev_err(&op->dev, "Error while requesting mem region\n"); + ret = -EBUSY; + goto err; + } + + /* remap registers */ + viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg)); + if (!viu_regs) { + dev_err(&op->dev, "Can't map register set\n"); + ret = -ENOMEM; + goto err; + } + + /* Prepare our private structure */ + viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC); + if (!viu_dev) { + dev_err(&op->dev, "Can't allocate private structure\n"); + ret = -ENOMEM; + goto err; + } + + viu_dev->vr = viu_regs; + viu_dev->irq = viu_irq; + viu_dev->dev = &op->dev; + + /* init video dma queues */ + INIT_LIST_HEAD(&viu_dev->vidq.active); + INIT_LIST_HEAD(&viu_dev->vidq.queued); + + snprintf(viu_dev->v4l2_dev.name, + sizeof(viu_dev->v4l2_dev.name), "%s", "VIU"); + ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev); + if (ret < 0) { + dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret); + goto err; + } + + ad = i2c_get_adapter(0); + viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad, + "saa7113", VIU_VIDEO_DECODER_ADDR, NULL); + + viu_dev->vidq.timeout.function = viu_vid_timeout; + viu_dev->vidq.timeout.data = (unsigned long)viu_dev; + init_timer(&viu_dev->vidq.timeout); + viu_dev->first = 1; + + /* Allocate memory for video device */ + vdev = video_device_alloc(); + if (vdev == NULL) { + ret = -ENOMEM; + goto err_vdev; + } + + memcpy(vdev, &viu_template, sizeof(viu_template)); + + vdev->v4l2_dev = &viu_dev->v4l2_dev; + + viu_dev->vdev = vdev; + + /* initialize locks */ + mutex_init(&viu_dev->lock); + viu_dev->vdev->lock = &viu_dev->lock; + spin_lock_init(&viu_dev->slock); + + video_set_drvdata(viu_dev->vdev, viu_dev); + + mutex_lock(&viu_dev->lock); + + ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + video_device_release(viu_dev->vdev); + goto err_vdev; + } + + /* enable VIU clock */ + viu_dev->clk = clk_get(&op->dev, "viu_clk"); + if (IS_ERR(viu_dev->clk)) { + dev_err(&op->dev, "failed to find the clock module!\n"); + ret = -ENODEV; + goto err_clk; + } else { + clk_enable(viu_dev->clk); + } + + /* reset VIU module */ + viu_reset(viu_dev->vr); + + /* install interrupt handler */ + if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) { + dev_err(&op->dev, "Request VIU IRQ failed.\n"); + ret = -ENODEV; + goto err_irq; + } + + mutex_unlock(&viu_dev->lock); + + dev_info(&op->dev, "Freescale VIU Video Capture Board\n"); + return ret; + +err_irq: + clk_disable(viu_dev->clk); + clk_put(viu_dev->clk); +err_clk: + video_unregister_device(viu_dev->vdev); +err_vdev: + mutex_unlock(&viu_dev->lock); + i2c_put_adapter(ad); + v4l2_device_unregister(&viu_dev->v4l2_dev); +err: + irq_dispose_mapping(viu_irq); + return ret; +} + +static int __devexit viu_of_remove(struct platform_device *op) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); + struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); + struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next, + struct v4l2_subdev, list); + struct i2c_client *client = v4l2_get_subdevdata(sdev); + + free_irq(dev->irq, (void *)dev); + irq_dispose_mapping(dev->irq); + + clk_disable(dev->clk); + clk_put(dev->clk); + + video_unregister_device(dev->vdev); + i2c_put_adapter(client->adapter); + v4l2_device_unregister(&dev->v4l2_dev); + return 0; +} + +#ifdef CONFIG_PM +static int viu_suspend(struct platform_device *op, pm_message_t state) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); + struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); + + clk_disable(dev->clk); + return 0; +} + +static int viu_resume(struct platform_device *op) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); + struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); + + clk_enable(dev->clk); + return 0; +} +#endif + +/* + * Initialization and module stuff + */ +static struct of_device_id mpc512x_viu_of_match[] = { + { + .compatible = "fsl,mpc5121-viu", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match); + +static struct platform_driver viu_of_platform_driver = { + .probe = viu_of_probe, + .remove = __devexit_p(viu_of_remove), +#ifdef CONFIG_PM + .suspend = viu_suspend, + .resume = viu_resume, +#endif + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = mpc512x_viu_of_match, + }, +}; + +static int __init viu_init(void) +{ + return platform_driver_register(&viu_of_platform_driver); +} + +static void __exit viu_exit(void) +{ + platform_driver_unregister(&viu_of_platform_driver); +} + +module_init(viu_init); +module_exit(viu_exit); + +MODULE_DESCRIPTION("Freescale Video-In(VIU)"); +MODULE_AUTHOR("Hongjun Chen"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/autogain_functions.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/autogain_functions.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/autogain_functions.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/autogain_functions.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,179 @@ +/* + * Functions for auto gain. + * + * Copyright (C) 2010-2011 Hans de Goede + * + * 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, or + * (at your option) any later version. + * + * 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 + */ + +/* auto gain and exposure algorithm based on the knee algorithm described here: + http://ytse.tricolour.net/docs/LowLightOptimization.html + + Returns 0 if no changes were made, 1 if the gain and or exposure settings + where changed. */ +static inline int auto_gain_n_exposure( + struct gspca_dev *gspca_dev, + int avg_lum, + int desired_avg_lum, + int deadzone, + int gain_knee, + int exposure_knee) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, steps, gain, orig_gain, exposure, orig_exposure; + int retval = 0; + + orig_gain = gain = sd->ctrls[GAIN].val; + orig_exposure = exposure = sd->ctrls[EXPOSURE].val; + + /* If we are of a multiple of deadzone, do multiple steps to reach the + desired lumination fast (with the risc of a slight overshoot) */ + steps = abs(desired_avg_lum - avg_lum) / deadzone; + + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", + avg_lum, desired_avg_lum, steps); + + for (i = 0; i < steps; i++) { + if (avg_lum > desired_avg_lum) { + if (gain > gain_knee) + gain--; + else if (exposure > exposure_knee) + exposure--; + else if (gain > sd->ctrls[GAIN].def) + gain--; + else if (exposure > sd->ctrls[EXPOSURE].min) + exposure--; + else if (gain > sd->ctrls[GAIN].min) + gain--; + else + break; + } else { + if (gain < sd->ctrls[GAIN].def) + gain++; + else if (exposure < exposure_knee) + exposure++; + else if (gain < gain_knee) + gain++; + else if (exposure < sd->ctrls[EXPOSURE].max) + exposure++; + else if (gain < sd->ctrls[GAIN].max) + gain++; + else + break; + } + } + + if (gain != orig_gain) { + sd->ctrls[GAIN].val = gain; + setgain(gspca_dev); + retval = 1; + } + if (exposure != orig_exposure) { + sd->ctrls[EXPOSURE].val = exposure; + setexposure(gspca_dev); + retval = 1; + } + + if (retval) + PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", + gain, exposure); + return retval; +} + +/* Autogain + exposure algorithm for cameras with a coarse exposure control + (usually this means we can only control the clockdiv to change exposure) + As changing the clockdiv so that the fps drops from 30 to 15 fps for + example, will lead to a huge exposure change (it effectively doubles), + this algorithm normally tries to only adjust the gain (between 40 and + 80 %) and if that does not help, only then changes exposure. This leads + to a much more stable image then using the knee algorithm which at + certain points of the knee graph will only try to adjust exposure, + which leads to oscilating as one exposure step is huge. + + Note this assumes that the sd struct for the cam in question has + exp_too_high_cnt and exp_too_high_cnt int members for use by this function. + + Returns 0 if no changes were made, 1 if the gain and or exposure settings + where changed. */ +static inline int coarse_grained_expo_autogain( + struct gspca_dev *gspca_dev, + int avg_lum, + int desired_avg_lum, + int deadzone) +{ + struct sd *sd = (struct sd *) gspca_dev; + int steps, gain, orig_gain, exposure, orig_exposure; + int gain_low, gain_high; + int retval = 0; + + orig_gain = gain = sd->ctrls[GAIN].val; + orig_exposure = exposure = sd->ctrls[EXPOSURE].val; + + gain_low = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 2; + gain_low += sd->ctrls[GAIN].min; + gain_high = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 4; + gain_high += sd->ctrls[GAIN].min; + + /* If we are of a multiple of deadzone, do multiple steps to reach the + desired lumination fast (with the risc of a slight overshoot) */ + steps = (desired_avg_lum - avg_lum) / deadzone; + + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", + avg_lum, desired_avg_lum, steps); + + if ((gain + steps) > gain_high && + exposure < sd->ctrls[EXPOSURE].max) { + gain = gain_high; + sd->exp_too_low_cnt++; + sd->exp_too_high_cnt = 0; + } else if ((gain + steps) < gain_low && + exposure > sd->ctrls[EXPOSURE].min) { + gain = gain_low; + sd->exp_too_high_cnt++; + sd->exp_too_low_cnt = 0; + } else { + gain += steps; + if (gain > sd->ctrls[GAIN].max) + gain = sd->ctrls[GAIN].max; + else if (gain < sd->ctrls[GAIN].min) + gain = sd->ctrls[GAIN].min; + sd->exp_too_high_cnt = 0; + sd->exp_too_low_cnt = 0; + } + + if (sd->exp_too_high_cnt > 3) { + exposure--; + sd->exp_too_high_cnt = 0; + } else if (sd->exp_too_low_cnt > 3) { + exposure++; + sd->exp_too_low_cnt = 0; + } + + if (gain != orig_gain) { + sd->ctrls[GAIN].val = gain; + setgain(gspca_dev); + retval = 1; + } + if (exposure != orig_exposure) { + sd->ctrls[EXPOSURE].val = exposure; + setexposure(gspca_dev); + retval = 1; + } + + if (retval) + PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", + gain, exposure); + return retval; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/benq.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/benq.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/benq.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/benq.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,315 @@ +/* + * Benq DC E300 subdriver + * + * Copyright (C) 2009 Jean-Francois Moine (http://moinejf.free.fr) + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "benq" + +#include "gspca.h" + +MODULE_AUTHOR("Jean-Francois Moine "); +MODULE_DESCRIPTION("Benq DC E300 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ +}; + +/* V4L2 controls supported by the driver */ +static const struct ctrl sd_ctrls[] = { +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, +}; + +static void sd_isoc_irq(struct urb *urb); + +/* -- write a register -- */ +static void reg_w(struct gspca_dev *gspca_dev, + u16 value, u16 index) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x02, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + NULL, + 0, + 500); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + gspca_dev->cam.cam_mode = vga_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + gspca_dev->cam.no_urb_create = 1; + gspca_dev->cam.reverse_alts = 1; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + int ret; + + ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, + gspca_dev->nbalt - 1); + if (ret < 0) { + err("usb_set_interface failed"); + return ret; + } +/* reg_w(gspca_dev, 0x0003, 0x0002); */ + return 0; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct urb *urb; + int i, n; + + /* create 4 URBs - 2 on endpoint 0x83 and 2 on 0x082 */ +#if MAX_NURBS < 4 +#error "Not enough URBs in the gspca table" +#endif +#define SD_PKT_SZ 64 +#define SD_NPKT 32 + for (n = 0; n < 4; n++) { + urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); + if (!urb) { + err("usb_alloc_urb failed"); + return -ENOMEM; + } + gspca_dev->urb[n] = urb; + urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, + SD_PKT_SZ * SD_NPKT, + GFP_KERNEL, + &urb->transfer_dma); + + if (urb->transfer_buffer == NULL) { + err("usb_alloc_coherent failed"); + return -ENOMEM; + } + urb->dev = gspca_dev->dev; + urb->context = gspca_dev; + urb->transfer_buffer_length = SD_PKT_SZ * SD_NPKT; + urb->pipe = usb_rcvisocpipe(gspca_dev->dev, + n & 1 ? 0x82 : 0x83); + urb->transfer_flags = URB_ISO_ASAP + | URB_NO_TRANSFER_DMA_MAP; + urb->interval = 1; + urb->complete = sd_isoc_irq; + urb->number_of_packets = SD_NPKT; + for (i = 0; i < SD_NPKT; i++) { + urb->iso_frame_desc[i].length = SD_PKT_SZ; + urb->iso_frame_desc[i].offset = SD_PKT_SZ * i; + } + } + + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0x003c, 0x0003); + reg_w(gspca_dev, 0x003c, 0x0004); + reg_w(gspca_dev, 0x003c, 0x0005); + reg_w(gspca_dev, 0x003c, 0x0006); + reg_w(gspca_dev, 0x003c, 0x0007); + usb_set_interface(gspca_dev->dev, gspca_dev->iface, + gspca_dev->nbalt - 1); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + /* unused */ +} + +/* reception of an URB */ +static void sd_isoc_irq(struct urb *urb) +{ + struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; + struct urb *urb0; + u8 *data; + int i, st; + + PDEBUG(D_PACK, "sd isoc irq"); + if (!gspca_dev->streaming) + return; + if (urb->status != 0) { + if (urb->status == -ESHUTDOWN) + return; /* disconnection */ +#ifdef CONFIG_PM + if (gspca_dev->frozen) + return; +#endif + err("urb status: %d", urb->status); + return; + } + + /* if this is a control URN (ep 0x83), wait */ + if (urb == gspca_dev->urb[0] || urb == gspca_dev->urb[2]) + return; + + /* scan both received URBs */ + if (urb == gspca_dev->urb[1]) + urb0 = gspca_dev->urb[0]; + else + urb0 = gspca_dev->urb[2]; + for (i = 0; i < urb->number_of_packets; i++) { + + /* check the packet status and length */ + if (urb0->iso_frame_desc[i].actual_length != SD_PKT_SZ + || urb->iso_frame_desc[i].actual_length != SD_PKT_SZ) { + PDEBUG(D_ERR, "ISOC bad lengths %d / %d", + urb0->iso_frame_desc[i].actual_length, + urb->iso_frame_desc[i].actual_length); + gspca_dev->last_packet_type = DISCARD_PACKET; + continue; + } + st = urb0->iso_frame_desc[i].status; + if (st == 0) + st = urb->iso_frame_desc[i].status; + if (st) { + err("ISOC data error: [%d] status=%d", + i, st); + gspca_dev->last_packet_type = DISCARD_PACKET; + continue; + } + + /* + * The images are received in URBs of different endpoints + * (0x83 and 0x82). + * Image pieces in URBs of ep 0x83 are continuated in URBs of + * ep 0x82 of the same index. + * The packets in the URBs of endpoint 0x83 start with: + * - 80 ba/bb 00 00 = start of image followed by 'ff d8' + * - 04 ba/bb oo oo = image piece + * where 'oo oo' is the image offset + (not cheked) + * - (other -> bad frame) + * The images are JPEG encoded with full header and + * normal ff escape. + * The end of image ('ff d9') may occur in any URB. + * (not cheked) + */ + data = (u8 *) urb0->transfer_buffer + + urb0->iso_frame_desc[i].offset; + if (data[0] == 0x80 && (data[1] & 0xfe) == 0xba) { + + /* new image */ + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, + data + 4, SD_PKT_SZ - 4); + } else if (data[0] == 0x04 && (data[1] & 0xfe) == 0xba) { + gspca_frame_add(gspca_dev, INTER_PACKET, + data + 4, SD_PKT_SZ - 4); + } else { + gspca_dev->last_packet_type = DISCARD_PACKET; + continue; + } + data = (u8 *) urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + gspca_frame_add(gspca_dev, INTER_PACKET, + data, SD_PKT_SZ); + } + + /* resubmit the URBs */ + st = usb_submit_urb(urb0, GFP_ATOMIC); + if (st < 0) + err("usb_submit_urb(0) ret %d", st); + st = usb_submit_urb(urb, GFP_ATOMIC); + if (st < 0) + err("usb_submit_urb() ret %d", st); +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x04a5, 0x3035)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/conex.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/conex.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/conex.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/conex.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1079 @@ +/* + * Connexant Cx11646 library + * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "conex" + +#include "gspca.h" +#define CONEX_CAM 1 /* special JPEG header */ +#include "jpeg.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + u8 quality; +#define QUALITY_MIN 30 +#define QUALITY_MAX 60 +#define QUALITY_DEF 40 + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 0xd4 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0x0a, + .maximum = 0x1f, + .step = 1, +#define CONTRAST_DEF 0x0c + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 7, + .step = 1, +#define COLOR_DEF 3 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* the read bytes are found in gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 index, + __u16 len) +{ + struct usb_device *dev = gspca_dev->dev; + +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_r: buffer overflow"); + return; + } +#endif + usb_control_msg(dev, + usb_rcvctrlpipe(dev, 0), + 0, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, + index, gspca_dev->usb_buf, len, + 500); + PDEBUG(D_USBI, "reg read [%02x] -> %02x ..", + index, gspca_dev->usb_buf[0]); +} + +/* the bytes to write are in gspca_dev->usb_buf */ +static void reg_w_val(struct gspca_dev *gspca_dev, + __u16 index, + __u8 val) +{ + struct usb_device *dev = gspca_dev->dev; + + gspca_dev->usb_buf[0] = val; + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, + index, gspca_dev->usb_buf, 1, 500); +} + +static void reg_w(struct gspca_dev *gspca_dev, + __u16 index, + const __u8 *buffer, + __u16 len) +{ + struct usb_device *dev = gspca_dev->dev; + +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_w: buffer overflow"); + return; + } + PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); +#endif + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, + index, gspca_dev->usb_buf, len, 500); +} + +static const __u8 cx_sensor_init[][4] = { + {0x88, 0x11, 0x01, 0x01}, + {0x88, 0x12, 0x70, 0x01}, + {0x88, 0x0f, 0x00, 0x01}, + {0x88, 0x05, 0x01, 0x01}, + {} +}; + +static const __u8 cx11646_fw1[][3] = { + {0x00, 0x02, 0x00}, + {0x01, 0x43, 0x00}, + {0x02, 0xA7, 0x00}, + {0x03, 0x8B, 0x01}, + {0x04, 0xE9, 0x02}, + {0x05, 0x08, 0x04}, + {0x06, 0x08, 0x05}, + {0x07, 0x07, 0x06}, + {0x08, 0xE7, 0x06}, + {0x09, 0xC6, 0x07}, + {0x0A, 0x86, 0x08}, + {0x0B, 0x46, 0x09}, + {0x0C, 0x05, 0x0A}, + {0x0D, 0xA5, 0x0A}, + {0x0E, 0x45, 0x0B}, + {0x0F, 0xE5, 0x0B}, + {0x10, 0x85, 0x0C}, + {0x11, 0x25, 0x0D}, + {0x12, 0xC4, 0x0D}, + {0x13, 0x45, 0x0E}, + {0x14, 0xE4, 0x0E}, + {0x15, 0x64, 0x0F}, + {0x16, 0xE4, 0x0F}, + {0x17, 0x64, 0x10}, + {0x18, 0xE4, 0x10}, + {0x19, 0x64, 0x11}, + {0x1A, 0xE4, 0x11}, + {0x1B, 0x64, 0x12}, + {0x1C, 0xE3, 0x12}, + {0x1D, 0x44, 0x13}, + {0x1E, 0xC3, 0x13}, + {0x1F, 0x24, 0x14}, + {0x20, 0xA3, 0x14}, + {0x21, 0x04, 0x15}, + {0x22, 0x83, 0x15}, + {0x23, 0xE3, 0x15}, + {0x24, 0x43, 0x16}, + {0x25, 0xA4, 0x16}, + {0x26, 0x23, 0x17}, + {0x27, 0x83, 0x17}, + {0x28, 0xE3, 0x17}, + {0x29, 0x43, 0x18}, + {0x2A, 0xA3, 0x18}, + {0x2B, 0x03, 0x19}, + {0x2C, 0x63, 0x19}, + {0x2D, 0xC3, 0x19}, + {0x2E, 0x22, 0x1A}, + {0x2F, 0x63, 0x1A}, + {0x30, 0xC3, 0x1A}, + {0x31, 0x23, 0x1B}, + {0x32, 0x83, 0x1B}, + {0x33, 0xE2, 0x1B}, + {0x34, 0x23, 0x1C}, + {0x35, 0x83, 0x1C}, + {0x36, 0xE2, 0x1C}, + {0x37, 0x23, 0x1D}, + {0x38, 0x83, 0x1D}, + {0x39, 0xE2, 0x1D}, + {0x3A, 0x23, 0x1E}, + {0x3B, 0x82, 0x1E}, + {0x3C, 0xC3, 0x1E}, + {0x3D, 0x22, 0x1F}, + {0x3E, 0x63, 0x1F}, + {0x3F, 0xC1, 0x1F}, + {} +}; +static void cx11646_fw(struct gspca_dev*gspca_dev) +{ + int i = 0; + + reg_w_val(gspca_dev, 0x006a, 0x02); + while (cx11646_fw1[i][1]) { + reg_w(gspca_dev, 0x006b, cx11646_fw1[i], 3); + i++; + } + reg_w_val(gspca_dev, 0x006a, 0x00); +} + +static const __u8 cxsensor[] = { + 0x88, 0x12, 0x70, 0x01, + 0x88, 0x0d, 0x02, 0x01, + 0x88, 0x0f, 0x00, 0x01, + 0x88, 0x03, 0x71, 0x01, 0x88, 0x04, 0x00, 0x01, /* 3 */ + 0x88, 0x02, 0x10, 0x01, + 0x88, 0x00, 0xD4, 0x01, 0x88, 0x01, 0x01, 0x01, /* 5 */ + 0x88, 0x0B, 0x00, 0x01, + 0x88, 0x0A, 0x0A, 0x01, + 0x88, 0x00, 0x08, 0x01, 0x88, 0x01, 0x00, 0x01, /* 8 */ + 0x88, 0x05, 0x01, 0x01, + 0xA1, 0x18, 0x00, 0x01, + 0x00 +}; + +static const __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff }; +static const __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff }; +static const __u8 reg10[] = { 0xb1, 0xb1 }; +static const __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e }; /* 640 */ +static const __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f }; + /* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */ +static const __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 }; + /* 320{0x04,0x0c,0x05,0x0f}; //320 */ +static const __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 }; /* 176 */ +static const __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }; + +static void cx_sensor(struct gspca_dev*gspca_dev) +{ + int i = 0; + int length; + const __u8 *ptsensor = cxsensor; + + reg_w(gspca_dev, 0x0020, reg20, 8); + reg_w(gspca_dev, 0x0028, reg28, 8); + reg_w(gspca_dev, 0x0010, reg10, 8); + reg_w_val(gspca_dev, 0x0092, 0x03); + + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 0: + reg_w(gspca_dev, 0x0071, reg71a, 4); + break; + case 1: + reg_w(gspca_dev, 0x0071, reg71b, 4); + break; + default: +/* case 2: */ + reg_w(gspca_dev, 0x0071, reg71c, 4); + break; + case 3: + reg_w(gspca_dev, 0x0071, reg71d, 4); + break; + } + reg_w(gspca_dev, 0x007b, reg7b, 6); + reg_w_val(gspca_dev, 0x00f8, 0x00); + reg_w(gspca_dev, 0x0010, reg10, 8); + reg_w_val(gspca_dev, 0x0098, 0x41); + for (i = 0; i < 11; i++) { + if (i == 3 || i == 5 || i == 8) + length = 8; + else + length = 4; + reg_w(gspca_dev, 0x00e5, ptsensor, length); + if (length == 4) + reg_r(gspca_dev, 0x00e8, 1); + else + reg_r(gspca_dev, 0x00e8, length); + ptsensor += length; + } + reg_r(gspca_dev, 0x00e7, 8); +} + +static const __u8 cx_inits_176[] = { + 0x33, 0x81, 0xB0, 0x00, 0x90, 0x00, 0x0A, 0x03, /* 176x144 */ + 0x00, 0x03, 0x03, 0x03, 0x1B, 0x05, 0x30, 0x03, + 0x65, 0x15, 0x18, 0x25, 0x03, 0x25, 0x08, 0x30, + 0x3B, 0x25, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xDC, 0xFF, 0xEE, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF, + 0xF7, 0xFF, 0x88, 0xFF, 0x66, 0x02, 0x28, 0x02, + 0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const __u8 cx_inits_320[] = { + 0x7f, 0x7f, 0x40, 0x01, 0xf0, 0x00, 0x02, 0x01, + 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x02, 0x01, + 0x65, 0x45, 0xfa, 0x4c, 0x2c, 0xdf, 0xb9, 0x81, + 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff, + 0xf5, 0xff, 0x6d, 0xff, 0xf6, 0x01, 0x43, 0x02, + 0xd3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const __u8 cx_inits_352[] = { + 0x2e, 0x7c, 0x60, 0x01, 0x20, 0x01, 0x05, 0x03, + 0x00, 0x06, 0x03, 0x06, 0x1b, 0x10, 0x05, 0x3b, + 0x30, 0x25, 0x18, 0x25, 0x08, 0x30, 0x03, 0x25, + 0x3b, 0x30, 0x25, 0x1b, 0x10, 0x05, 0x00, 0x00, + 0xe3, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff, + 0xf5, 0xff, 0x6b, 0xff, 0xee, 0x01, 0x43, 0x02, + 0xe4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const __u8 cx_inits_640[] = { + 0x7e, 0x7e, 0x80, 0x02, 0xe0, 0x01, 0x01, 0x01, + 0x00, 0x02, 0x01, 0x02, 0x10, 0x30, 0x01, 0x01, + 0x65, 0x45, 0xf7, 0x52, 0x2c, 0xdf, 0xb9, 0x81, + 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff, + 0xf6, 0xff, 0x7b, 0xff, 0x01, 0x02, 0x43, 0x02, + 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void cx11646_initsize(struct gspca_dev *gspca_dev) +{ + const __u8 *cxinit; + static const __u8 reg12[] = { 0x08, 0x05, 0x07, 0x04, 0x24 }; + static const __u8 reg17[] = + { 0x0a, 0x00, 0xf2, 0x01, 0x0f, 0x00, 0x97, 0x02 }; + + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 0: + cxinit = cx_inits_640; + break; + case 1: + cxinit = cx_inits_352; + break; + default: +/* case 2: */ + cxinit = cx_inits_320; + break; + case 3: + cxinit = cx_inits_176; + break; + } + reg_w_val(gspca_dev, 0x009a, 0x01); + reg_w_val(gspca_dev, 0x0010, 0x10); + reg_w(gspca_dev, 0x0012, reg12, 5); + reg_w(gspca_dev, 0x0017, reg17, 8); + reg_w_val(gspca_dev, 0x00c0, 0x00); + reg_w_val(gspca_dev, 0x00c1, 0x04); + reg_w_val(gspca_dev, 0x00c2, 0x04); + + reg_w(gspca_dev, 0x0061, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x00ca, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x00d2, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x00da, cxinit, 6); + cxinit += 8; + reg_w(gspca_dev, 0x0041, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x0049, cxinit, 8); + cxinit += 8; + reg_w(gspca_dev, 0x0051, cxinit, 2); + + reg_r(gspca_dev, 0x0010, 1); +} + +static const __u8 cx_jpeg_init[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x15}, /* 1 */ + {0x0f, 0x10, 0x12, 0x10, 0x0d, 0x15, 0x12, 0x11}, + {0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35, 0x22}, + {0x20, 0x1d, 0x1d, 0x20, 0x41, 0x2e, 0x31, 0x26}, + {0x35, 0x4d, 0x43, 0x51, 0x4f, 0x4b, 0x43, 0x4a}, + {0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A, 0x73}, + {0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73, 0x7D}, + {0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95, 0xA0}, + {0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83, 0x01}, + {0x15, 0x0F, 0x10, 0x12, 0x10, 0x0D, 0x15, 0x12}, + {0x11, 0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35}, + {0x22, 0x20, 0x1D, 0x1D, 0x20, 0x41, 0x2E, 0x31}, + {0x26, 0x35, 0x4D, 0x43, 0x51, 0x4F, 0x4B, 0x43}, + {0x4A, 0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A}, + {0x73, 0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73}, + {0x7D, 0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95}, + {0xA0, 0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83}, + {0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05}, + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}, + {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, + {0x0B, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01}, + {0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}, + {0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00}, + {0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05}, + {0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01}, + {0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21}, + {0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22}, + {0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23}, + {0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24}, + {0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17}, + {0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29}, + {0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A}, + {0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A}, + {0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A}, + {0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A}, + {0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A}, + {0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A}, + {0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99}, + {0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8}, + {0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7}, + {0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6}, + {0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5}, + {0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3}, + {0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1}, + {0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9}, + {0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04}, + {0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01}, + {0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04}, + {0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07}, + {0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14}, + {0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33}, + {0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16}, + {0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19}, + {0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36}, + {0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46}, + {0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56}, + {0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66}, + {0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76}, + {0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85}, + {0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94}, + {0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3}, + {0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2}, + {0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA}, + {0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9}, + {0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8}, + {0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7}, + {0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6}, + {0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0x20, 0x00, 0x1F}, + {0x02, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x11, 0x00, 0x11, 0x22, 0x00, 0x22}, + {0x22, 0x11, 0x22, 0x22, 0x11, 0x33, 0x33, 0x11}, + {0x44, 0x66, 0x22, 0x55, 0x66, 0xFF, 0xDD, 0x00}, + {0x04, 0x00, 0x14, 0xFF, 0xC0, 0x00, 0x11, 0x08}, + {0x00, 0xF0, 0x01, 0x40, 0x03, 0x00, 0x21, 0x00}, + {0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xDA}, + {0x00, 0x0C, 0x03, 0x00, 0x00, 0x01, 0x11, 0x02}, + {0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9, 0x00, 0x00} /* 79 */ +}; + + +static const __u8 cxjpeg_640[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x10}, /* 1 */ + {0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d}, + {0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a}, + {0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d}, + {0x28, 0x3a, 0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38}, + {0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57}, + {0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F}, + {0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79}, + {0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63, 0x01}, + {0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E}, + {0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28}, + {0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25}, + {0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33}, + {0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44}, + {0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57}, + {0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71}, + {0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63}, + {0xFF, 0x20, 0x00, 0x1F, 0x00, 0x83, 0x00, 0x00}, + {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, + {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, + {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, + {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x28, 0xFF}, + {0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80}, + {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, + {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, + {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */ +}; +static const __u8 cxjpeg_352[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d}, + {0x09, 0x09, 0x0b, 0x09, 0x08, 0x0D, 0x0b, 0x0a}, + {0x0b, 0x0e, 0x0d, 0x0d, 0x0f, 0x13, 0x1f, 0x14}, + {0x13, 0x11, 0x11, 0x13, 0x26, 0x1b, 0x1d, 0x17}, + {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C}, + {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44}, + {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A}, + {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F}, + {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01}, + {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B}, + {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F}, + {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D}, + {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28}, + {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35}, + {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44}, + {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58}, + {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D}, + {0xFF, 0x20, 0x00, 0x1F, 0x01, 0x83, 0x00, 0x00}, + {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, + {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, + {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, + {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x16, 0xFF}, + {0xC0, 0x00, 0x11, 0x08, 0x01, 0x20, 0x01, 0x60}, + {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, + {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, + {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; +static const __u8 cxjpeg_320[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x05}, + {0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04}, + {0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08}, + {0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09}, + {0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0f, 0x11}, + {0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 0x1A}, + {0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D}, + {0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 0x24}, + {0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0x01}, + {0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04}, + {0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C}, + {0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B}, + {0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F}, + {0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14}, + {0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A}, + {0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22}, + {0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E}, + {0xFF, 0x20, 0x00, 0x1F, 0x02, 0x0C, 0x00, 0x00}, + {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, + {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, + {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, + {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x14, 0xFF}, + {0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 0x40}, + {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, + {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, + {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 27 */ +}; +static const __u8 cxjpeg_176[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d}, + {0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B, 0x0A}, + {0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F, 0x14}, + {0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D, 0x17}, + {0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C}, + {0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44}, + {0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A}, + {0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F}, + {0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01}, + {0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B}, + {0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F}, + {0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D}, + {0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28}, + {0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35}, + {0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44}, + {0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58}, + {0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D}, + {0xFF, 0x20, 0x00, 0x1F, 0x03, 0xA1, 0x00, 0x00}, + {0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00}, + {0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22}, + {0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55}, + {0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x0B, 0xFF}, + {0xC0, 0x00, 0x11, 0x08, 0x00, 0x90, 0x00, 0xB0}, + {0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02}, + {0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00}, + {0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; +/* 640 take with the zcx30x part */ +static const __u8 cxjpeg_qtable[][8] = { + {0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x08}, + {0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 0x07}, + {0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0a}, + {0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, 0x0f}, + {0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c}, + {0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, 0x2c}, + {0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30}, + {0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, 0x3d}, + {0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0x01}, + {0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0a}, + {0x0a, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32}, + {0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} /* 18 */ +}; + + +static void cx11646_jpegInit(struct gspca_dev*gspca_dev) +{ + int i; + int length; + + reg_w_val(gspca_dev, 0x00c0, 0x01); + reg_w_val(gspca_dev, 0x00c3, 0x00); + reg_w_val(gspca_dev, 0x00c0, 0x00); + reg_r(gspca_dev, 0x0001, 1); + length = 8; + for (i = 0; i < 79; i++) { + if (i == 78) + length = 6; + reg_w(gspca_dev, 0x0008, cx_jpeg_init[i], length); + } + reg_r(gspca_dev, 0x0002, 1); + reg_w_val(gspca_dev, 0x0055, 0x14); +} + +static const __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 }; +static const __u8 regE5_8[] = + { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 }; +static const __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 }; +static const __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 }; +static const __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 }; +static const __u8 reg51[] = { 0x77, 0x03 }; +#define reg70 0x03 + +static void cx11646_jpeg(struct gspca_dev*gspca_dev) +{ + int i; + int length; + __u8 Reg55; + int retry; + + reg_w_val(gspca_dev, 0x00c0, 0x01); + reg_w_val(gspca_dev, 0x00c3, 0x00); + reg_w_val(gspca_dev, 0x00c0, 0x00); + reg_r(gspca_dev, 0x0001, 1); + length = 8; + switch (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv) { + case 0: + for (i = 0; i < 27; i++) { + if (i == 26) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_640[i], length); + } + Reg55 = 0x28; + break; + case 1: + for (i = 0; i < 27; i++) { + if (i == 26) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_352[i], length); + } + Reg55 = 0x16; + break; + default: +/* case 2: */ + for (i = 0; i < 27; i++) { + if (i == 26) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_320[i], length); + } + Reg55 = 0x14; + break; + case 3: + for (i = 0; i < 27; i++) { + if (i == 26) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_176[i], length); + } + Reg55 = 0x0B; + break; + } + + reg_r(gspca_dev, 0x0002, 1); + reg_w_val(gspca_dev, 0x0055, Reg55); + reg_r(gspca_dev, 0x0002, 1); + reg_w(gspca_dev, 0x0010, reg10, 2); + reg_w_val(gspca_dev, 0x0054, 0x02); + reg_w_val(gspca_dev, 0x0054, 0x01); + reg_w_val(gspca_dev, 0x0000, 0x94); + reg_w_val(gspca_dev, 0x0053, 0xc0); + reg_w_val(gspca_dev, 0x00fc, 0xe1); + reg_w_val(gspca_dev, 0x0000, 0x00); + /* wait for completion */ + retry = 50; + do { + reg_r(gspca_dev, 0x0002, 1); + /* 0x07 until 0x00 */ + if (gspca_dev->usb_buf[0] == 0x00) + break; + reg_w_val(gspca_dev, 0x0053, 0x00); + } while (--retry); + if (retry == 0) + PDEBUG(D_ERR, "Damned Errors sending jpeg Table"); + /* send the qtable now */ + reg_r(gspca_dev, 0x0001, 1); /* -> 0x18 */ + length = 8; + for (i = 0; i < 18; i++) { + if (i == 17) + length = 2; + reg_w(gspca_dev, 0x0008, cxjpeg_qtable[i], length); + + } + reg_r(gspca_dev, 0x0002, 1); /* 0x00 */ + reg_r(gspca_dev, 0x0053, 1); /* 0x00 */ + reg_w_val(gspca_dev, 0x0054, 0x02); + reg_w_val(gspca_dev, 0x0054, 0x01); + reg_w_val(gspca_dev, 0x0000, 0x94); + reg_w_val(gspca_dev, 0x0053, 0xc0); + + reg_r(gspca_dev, 0x0038, 1); /* 0x40 */ + reg_r(gspca_dev, 0x0038, 1); /* 0x40 */ + reg_r(gspca_dev, 0x001f, 1); /* 0x38 */ + reg_w(gspca_dev, 0x0012, reg12, 5); + reg_w(gspca_dev, 0x00e5, regE5_8, 8); + reg_r(gspca_dev, 0x00e8, 8); + reg_w(gspca_dev, 0x00e5, regE5a, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + reg_w_val(gspca_dev, 0x009a, 0x01); + reg_w(gspca_dev, 0x00e5, regE5b, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + reg_w(gspca_dev, 0x00e5, regE5c, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + + reg_w(gspca_dev, 0x0051, reg51, 2); + reg_w(gspca_dev, 0x0010, reg10, 2); + reg_w_val(gspca_dev, 0x0070, reg70); +} + +static void cx11646_init1(struct gspca_dev *gspca_dev) +{ + int i = 0; + + reg_w_val(gspca_dev, 0x0010, 0x00); + reg_w_val(gspca_dev, 0x0053, 0x00); + reg_w_val(gspca_dev, 0x0052, 0x00); + reg_w_val(gspca_dev, 0x009b, 0x2f); + reg_w_val(gspca_dev, 0x009c, 0x10); + reg_r(gspca_dev, 0x0098, 1); + reg_w_val(gspca_dev, 0x0098, 0x40); + reg_r(gspca_dev, 0x0099, 1); + reg_w_val(gspca_dev, 0x0099, 0x07); + reg_w_val(gspca_dev, 0x0039, 0x40); + reg_w_val(gspca_dev, 0x003c, 0xff); + reg_w_val(gspca_dev, 0x003f, 0x1f); + reg_w_val(gspca_dev, 0x003d, 0x40); +/* reg_w_val(gspca_dev, 0x003d, 0x60); */ + reg_r(gspca_dev, 0x0099, 1); /* ->0x07 */ + + while (cx_sensor_init[i][0]) { + reg_w_val(gspca_dev, 0x00e5, cx_sensor_init[i][0]); + reg_r(gspca_dev, 0x00e8, 1); /* -> 0x00 */ + if (i == 1) { + reg_w_val(gspca_dev, 0x00ed, 0x01); + reg_r(gspca_dev, 0x00ed, 1); /* -> 0x01 */ + } + i++; + } + reg_w_val(gspca_dev, 0x00c3, 0x00); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->quality = QUALITY_DEF; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + cx11646_init1(gspca_dev); + cx11646_initsize(gspca_dev); + cx11646_fw(gspca_dev); + cx_sensor(gspca_dev); + cx11646_jpegInit(gspca_dev); + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* create the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x22); /* JPEG 411 */ + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + cx11646_initsize(gspca_dev); + cx11646_fw(gspca_dev); + cx_sensor(gspca_dev); + cx11646_jpeg(gspca_dev); + return 0; +} + +/* called on streamoff with alt 0 and on disconnect */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + int retry = 50; + + if (!gspca_dev->present) + return; + reg_w_val(gspca_dev, 0x0000, 0x00); + reg_r(gspca_dev, 0x0002, 1); + reg_w_val(gspca_dev, 0x0053, 0x00); + + while (retry--) { +/* reg_r(gspca_dev, 0x0002, 1);*/ + reg_r(gspca_dev, 0x0053, 1); + if (gspca_dev->usb_buf[0] == 0) + break; + } + reg_w_val(gspca_dev, 0x0000, 0x00); + reg_r(gspca_dev, 0x0002, 1); + + reg_w_val(gspca_dev, 0x0010, 0x00); + reg_r(gspca_dev, 0x0033, 1); + reg_w_val(gspca_dev, 0x00fc, 0xe0); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (data[0] == 0xff && data[1] == 0xd8) { + + /* start of frame */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + + /* put the JPEG header in the new frame */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + data += 2; + len -= 2; + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 }; + __u8 reg51c[2]; + __u8 bright; + __u8 colors; + + bright = sd->brightness; + regE5cbx[2] = bright; + reg_w(gspca_dev, 0x00e5, regE5cbx, 8); + reg_r(gspca_dev, 0x00e8, 8); + reg_w(gspca_dev, 0x00e5, regE5c, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + + colors = sd->colors; + reg51c[0] = 0x77; + reg51c[1] = colors; + reg_w(gspca_dev, 0x0051, reg51c, 2); + reg_w(gspca_dev, 0x0010, reg10, 2); + reg_w_val(gspca_dev, 0x0070, reg70); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 }; /* seem MSB */ +/* __u8 regE5bcx[] = { 0x88, 0x0b, 0x12, 0x01}; * LSB */ + __u8 reg51c[2]; + + regE5acx[2] = sd->contrast; + reg_w(gspca_dev, 0x00e5, regE5acx, 4); + reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ + reg51c[0] = 0x77; + reg51c[1] = sd->colors; + reg_w(gspca_dev, 0x0051, reg51c, 2); + reg_w(gspca_dev, 0x0010, reg10, 2); + reg_w_val(gspca_dev, 0x0070, reg70); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) { + setbrightness(gspca_dev); + setcontrast(gspca_dev); + } + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (jcomp->quality < QUALITY_MIN) + sd->quality = QUALITY_MIN; + else if (jcomp->quality > QUALITY_MAX) + sd->quality = QUALITY_MAX; + else + sd->quality = jcomp->quality; + if (gspca_dev->streaming) + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + return 0; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0572, 0x0041)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/cpia1.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/cpia1.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/cpia1.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/cpia1.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2145 @@ +/* + * cpia CPiA (1) gspca driver + * + * Copyright (C) 2010-2011 Hans de Goede + * + * This module is adapted from the in kernel v4l1 cpia driver which is : + * + * (C) Copyright 1999-2000 Peter Pregler + * (C) Copyright 1999-2000 Scott J. Bertin + * (C) Copyright 1999-2000 Johannes Erdfelt + * (C) Copyright 2000 STMicroelectronics + * + * 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, or + * (at your option) any later version. + * + * 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 + * + */ + +#define MODULE_NAME "cpia1" + +#include +#include "gspca.h" + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Vision CPiA"); +MODULE_LICENSE("GPL"); + +/* constant value's */ +#define MAGIC_0 0x19 +#define MAGIC_1 0x68 +#define DATA_IN 0xc0 +#define DATA_OUT 0x40 +#define VIDEOSIZE_QCIF 0 /* 176x144 */ +#define VIDEOSIZE_CIF 1 /* 352x288 */ +#define SUBSAMPLE_420 0 +#define SUBSAMPLE_422 1 +#define YUVORDER_YUYV 0 +#define YUVORDER_UYVY 1 +#define NOT_COMPRESSED 0 +#define COMPRESSED 1 +#define NO_DECIMATION 0 +#define DECIMATION_ENAB 1 +#define EOI 0xff /* End Of Image */ +#define EOL 0xfd /* End Of Line */ +#define FRAME_HEADER_SIZE 64 + +/* Image grab modes */ +#define CPIA_GRAB_SINGLE 0 +#define CPIA_GRAB_CONTINEOUS 1 + +/* Compression parameters */ +#define CPIA_COMPRESSION_NONE 0 +#define CPIA_COMPRESSION_AUTO 1 +#define CPIA_COMPRESSION_MANUAL 2 +#define CPIA_COMPRESSION_TARGET_QUALITY 0 +#define CPIA_COMPRESSION_TARGET_FRAMERATE 1 + +/* Return offsets for GetCameraState */ +#define SYSTEMSTATE 0 +#define GRABSTATE 1 +#define STREAMSTATE 2 +#define FATALERROR 3 +#define CMDERROR 4 +#define DEBUGFLAGS 5 +#define VPSTATUS 6 +#define ERRORCODE 7 + +/* SystemState */ +#define UNINITIALISED_STATE 0 +#define PASS_THROUGH_STATE 1 +#define LO_POWER_STATE 2 +#define HI_POWER_STATE 3 +#define WARM_BOOT_STATE 4 + +/* GrabState */ +#define GRAB_IDLE 0 +#define GRAB_ACTIVE 1 +#define GRAB_DONE 2 + +/* StreamState */ +#define STREAM_NOT_READY 0 +#define STREAM_READY 1 +#define STREAM_OPEN 2 +#define STREAM_PAUSED 3 +#define STREAM_FINISHED 4 + +/* Fatal Error, CmdError, and DebugFlags */ +#define CPIA_FLAG 1 +#define SYSTEM_FLAG 2 +#define INT_CTRL_FLAG 4 +#define PROCESS_FLAG 8 +#define COM_FLAG 16 +#define VP_CTRL_FLAG 32 +#define CAPTURE_FLAG 64 +#define DEBUG_FLAG 128 + +/* VPStatus */ +#define VP_STATE_OK 0x00 + +#define VP_STATE_FAILED_VIDEOINIT 0x01 +#define VP_STATE_FAILED_AECACBINIT 0x02 +#define VP_STATE_AEC_MAX 0x04 +#define VP_STATE_ACB_BMAX 0x08 + +#define VP_STATE_ACB_RMIN 0x10 +#define VP_STATE_ACB_GMIN 0x20 +#define VP_STATE_ACB_RMAX 0x40 +#define VP_STATE_ACB_GMAX 0x80 + +/* default (minimum) compensation values */ +#define COMP_RED 220 +#define COMP_GREEN1 214 +#define COMP_GREEN2 COMP_GREEN1 +#define COMP_BLUE 230 + +/* exposure status */ +#define EXPOSURE_VERY_LIGHT 0 +#define EXPOSURE_LIGHT 1 +#define EXPOSURE_NORMAL 2 +#define EXPOSURE_DARK 3 +#define EXPOSURE_VERY_DARK 4 + +#define CPIA_MODULE_CPIA (0 << 5) +#define CPIA_MODULE_SYSTEM (1 << 5) +#define CPIA_MODULE_VP_CTRL (5 << 5) +#define CPIA_MODULE_CAPTURE (6 << 5) +#define CPIA_MODULE_DEBUG (7 << 5) + +#define INPUT (DATA_IN << 8) +#define OUTPUT (DATA_OUT << 8) + +#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1) +#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2) +#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3) +#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4) +#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5) +#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7) +#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8) +#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10) + +#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1) +#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2) +#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3) +#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4) +#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5) +#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6) +#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7) +#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8) +#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9) +#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10) +#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11) +#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12) +#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13) + +#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1) +#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2) +#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3) +#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4) +#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6) +#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7) +#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8) +#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9) +#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10) +#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11) +#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16) +#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17) +#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18) +#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19) +#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25) +#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30) +#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31) + +#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1) +#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2) +#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3) +#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4) +#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5) +#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6) +#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7) +#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8) +#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9) +#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10) +#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11) +#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12) +#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13) +#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14) +#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15) + +#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1) +#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4) +#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5) +#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6) +#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8) +#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9) +#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10) +#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11) + +#define ROUND_UP_EXP_FOR_FLICKER 15 + +/* Constants for automatic frame rate adjustment */ +#define MAX_EXP 302 +#define MAX_EXP_102 255 +#define LOW_EXP 140 +#define VERY_LOW_EXP 70 +#define TC 94 +#define EXP_ACC_DARK 50 +#define EXP_ACC_LIGHT 90 +#define HIGH_COMP_102 160 +#define MAX_COMP 239 +#define DARK_TIME 3 +#define LIGHT_TIME 3 + +#define FIRMWARE_VERSION(x, y) (sd->params.version.firmwareVersion == (x) && \ + sd->params.version.firmwareRevision == (y)) + +/* Developer's Guide Table 5 p 3-34 + * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ +static u8 flicker_jumps[2][2][4] = +{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } }, + { { 64, 32, 16, 8 }, { 76, 38, 19, 9} } +}; + +struct cam_params { + struct { + u8 firmwareVersion; + u8 firmwareRevision; + u8 vcVersion; + u8 vcRevision; + } version; + struct { + u16 vendor; + u16 product; + u16 deviceRevision; + } pnpID; + struct { + u8 vpVersion; + u8 vpRevision; + u16 cameraHeadID; + } vpVersion; + struct { + u8 systemState; + u8 grabState; + u8 streamState; + u8 fatalError; + u8 cmdError; + u8 debugFlags; + u8 vpStatus; + u8 errorCode; + } status; + struct { + u8 brightness; + u8 contrast; + u8 saturation; + } colourParams; + struct { + u8 gainMode; + u8 expMode; + u8 compMode; + u8 centreWeight; + u8 gain; + u8 fineExp; + u8 coarseExpLo; + u8 coarseExpHi; + u8 redComp; + u8 green1Comp; + u8 green2Comp; + u8 blueComp; + } exposure; + struct { + u8 balanceMode; + u8 redGain; + u8 greenGain; + u8 blueGain; + } colourBalance; + struct { + u8 divisor; + u8 baserate; + } sensorFps; + struct { + u8 gain1; + u8 gain2; + u8 gain4; + u8 gain8; + } apcor; + struct { + u8 disabled; + u8 flickerMode; + u8 coarseJump; + u8 allowableOverExposure; + } flickerControl; + struct { + u8 gain1; + u8 gain2; + u8 gain4; + u8 gain8; + } vlOffset; + struct { + u8 mode; + u8 decimation; + } compression; + struct { + u8 frTargeting; + u8 targetFR; + u8 targetQ; + } compressionTarget; + struct { + u8 yThreshold; + u8 uvThreshold; + } yuvThreshold; + struct { + u8 hysteresis; + u8 threshMax; + u8 smallStep; + u8 largeStep; + u8 decimationHysteresis; + u8 frDiffStepThresh; + u8 qDiffStepThresh; + u8 decimationThreshMod; + } compressionParams; + struct { + u8 videoSize; /* CIF/QCIF */ + u8 subSample; + u8 yuvOrder; + } format; + struct { /* Intel QX3 specific data */ + u8 qx3_detected; /* a QX3 is present */ + u8 toplight; /* top light lit , R/W */ + u8 bottomlight; /* bottom light lit, R/W */ + u8 button; /* snapshot button pressed (R/O) */ + u8 cradled; /* microscope is in cradle (R/O) */ + } qx3; + struct { + u8 colStart; /* skip first 8*colStart pixels */ + u8 colEnd; /* finish at 8*colEnd pixels */ + u8 rowStart; /* skip first 4*rowStart lines */ + u8 rowEnd; /* finish at 4*rowEnd lines */ + } roi; + u8 ecpTiming; + u8 streamStartLine; +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + struct cam_params params; /* camera settings */ + + atomic_t cam_exposure; + atomic_t fps; + int exposure_count; + u8 exposure_status; + u8 mainsFreq; /* 0 = 50hz, 1 = 60hz */ + u8 first_frame; + u8 freq; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { +#define BRIGHTNESS_IDX 0 + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 100, + .step = 1, +#define BRIGHTNESS_DEF 50 + .default_value = BRIGHTNESS_DEF, + .flags = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define CONTRAST_IDX 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 96, + .step = 8, +#define CONTRAST_DEF 48 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SATURATION_IDX 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 100, + .step = 1, +#define SATURATION_DEF 50 + .default_value = SATURATION_DEF, + }, + .set = sd_setsaturation, + .get = sd_getsaturation, + }, +#define POWER_LINE_FREQUENCY_IDX 3 + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ + .step = 1, +#define FREQ_DEF 1 + .default_value = FREQ_DEF, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, +#define ILLUMINATORS_1_IDX 4 + { + { + .id = V4L2_CID_ILLUMINATORS_1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Illuminator 1", + .minimum = 0, + .maximum = 1, + .step = 1, +#define ILLUMINATORS_1_DEF 0 + .default_value = ILLUMINATORS_1_DEF, + }, + .set = sd_setilluminator1, + .get = sd_getilluminator1, + }, +#define ILLUMINATORS_2_IDX 5 + { + { + .id = V4L2_CID_ILLUMINATORS_2, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Illuminator 2", + .minimum = 0, + .maximum = 1, + .step = 1, +#define ILLUMINATORS_2_DEF 0 + .default_value = ILLUMINATORS_2_DEF, + }, + .set = sd_setilluminator2, + .get = sd_getilluminator2, + }, +#define COMP_TARGET_IDX 6 + { + { +#define V4L2_CID_COMP_TARGET V4L2_CID_PRIVATE_BASE + .id = V4L2_CID_COMP_TARGET, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Compression Target", + .minimum = 0, + .maximum = 1, + .step = 1, +#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY + .default_value = COMP_TARGET_DEF, + }, + .set = sd_setcomptarget, + .get = sd_getcomptarget, + }, +}; + +static const struct v4l2_pix_format mode[] = { + {160, 120, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, + /* The sizeimage is trial and error, as with low framerates + the camera will pad out usb frames, making the image + data larger then strictly necessary */ + .bytesperline = 160, + .sizeimage = 65536, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, + .bytesperline = 172, + .sizeimage = 65536, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 262144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 262144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/********************************************************************** + * + * General functions + * + **********************************************************************/ + +static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command) +{ + u8 requesttype; + unsigned int pipe; + int ret, databytes = command[6] | (command[7] << 8); + /* Sometimes we see spurious EPIPE errors */ + int retries = 3; + + if (command[0] == DATA_IN) { + pipe = usb_rcvctrlpipe(gspca_dev->dev, 0); + requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + } else if (command[0] == DATA_OUT) { + pipe = usb_sndctrlpipe(gspca_dev->dev, 0); + requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE; + } else { + PDEBUG(D_ERR, "Unexpected first byte of command: %x", + command[0]); + return -EINVAL; + } + +retry: + ret = usb_control_msg(gspca_dev->dev, pipe, + command[1], + requesttype, + command[2] | (command[3] << 8), + command[4] | (command[5] << 8), + gspca_dev->usb_buf, databytes, 1000); + + if (ret < 0) + err("usb_control_msg %02x, error %d", command[1], + ret); + + if (ret == -EPIPE && retries > 0) { + retries--; + goto retry; + } + + return (ret < 0) ? ret : 0; +} + +/* send an arbitrary command to the camera */ +static int do_command(struct gspca_dev *gspca_dev, u16 command, + u8 a, u8 b, u8 c, u8 d) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret, datasize; + u8 cmd[8]; + + switch (command) { + case CPIA_COMMAND_GetCPIAVersion: + case CPIA_COMMAND_GetPnPID: + case CPIA_COMMAND_GetCameraStatus: + case CPIA_COMMAND_GetVPVersion: + case CPIA_COMMAND_GetColourParams: + case CPIA_COMMAND_GetColourBalance: + case CPIA_COMMAND_GetExposure: + datasize = 8; + break; + case CPIA_COMMAND_ReadMCPorts: + case CPIA_COMMAND_ReadVCRegs: + datasize = 4; + break; + default: + datasize = 0; + break; + } + + cmd[0] = command >> 8; + cmd[1] = command & 0xff; + cmd[2] = a; + cmd[3] = b; + cmd[4] = c; + cmd[5] = d; + cmd[6] = datasize; + cmd[7] = 0; + + ret = cpia_usb_transferCmd(gspca_dev, cmd); + if (ret) + return ret; + + switch (command) { + case CPIA_COMMAND_GetCPIAVersion: + sd->params.version.firmwareVersion = gspca_dev->usb_buf[0]; + sd->params.version.firmwareRevision = gspca_dev->usb_buf[1]; + sd->params.version.vcVersion = gspca_dev->usb_buf[2]; + sd->params.version.vcRevision = gspca_dev->usb_buf[3]; + break; + case CPIA_COMMAND_GetPnPID: + sd->params.pnpID.vendor = + gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8); + sd->params.pnpID.product = + gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8); + sd->params.pnpID.deviceRevision = + gspca_dev->usb_buf[4] | (gspca_dev->usb_buf[5] << 8); + break; + case CPIA_COMMAND_GetCameraStatus: + sd->params.status.systemState = gspca_dev->usb_buf[0]; + sd->params.status.grabState = gspca_dev->usb_buf[1]; + sd->params.status.streamState = gspca_dev->usb_buf[2]; + sd->params.status.fatalError = gspca_dev->usb_buf[3]; + sd->params.status.cmdError = gspca_dev->usb_buf[4]; + sd->params.status.debugFlags = gspca_dev->usb_buf[5]; + sd->params.status.vpStatus = gspca_dev->usb_buf[6]; + sd->params.status.errorCode = gspca_dev->usb_buf[7]; + break; + case CPIA_COMMAND_GetVPVersion: + sd->params.vpVersion.vpVersion = gspca_dev->usb_buf[0]; + sd->params.vpVersion.vpRevision = gspca_dev->usb_buf[1]; + sd->params.vpVersion.cameraHeadID = + gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8); + break; + case CPIA_COMMAND_GetColourParams: + sd->params.colourParams.brightness = gspca_dev->usb_buf[0]; + sd->params.colourParams.contrast = gspca_dev->usb_buf[1]; + sd->params.colourParams.saturation = gspca_dev->usb_buf[2]; + break; + case CPIA_COMMAND_GetColourBalance: + sd->params.colourBalance.redGain = gspca_dev->usb_buf[0]; + sd->params.colourBalance.greenGain = gspca_dev->usb_buf[1]; + sd->params.colourBalance.blueGain = gspca_dev->usb_buf[2]; + break; + case CPIA_COMMAND_GetExposure: + sd->params.exposure.gain = gspca_dev->usb_buf[0]; + sd->params.exposure.fineExp = gspca_dev->usb_buf[1]; + sd->params.exposure.coarseExpLo = gspca_dev->usb_buf[2]; + sd->params.exposure.coarseExpHi = gspca_dev->usb_buf[3]; + sd->params.exposure.redComp = gspca_dev->usb_buf[4]; + sd->params.exposure.green1Comp = gspca_dev->usb_buf[5]; + sd->params.exposure.green2Comp = gspca_dev->usb_buf[6]; + sd->params.exposure.blueComp = gspca_dev->usb_buf[7]; + break; + + case CPIA_COMMAND_ReadMCPorts: + /* test button press */ + a = ((gspca_dev->usb_buf[1] & 0x02) == 0); + if (a != sd->params.qx3.button) { +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + input_report_key(gspca_dev->input_dev, KEY_CAMERA, a); + input_sync(gspca_dev->input_dev); +#endif + sd->params.qx3.button = a; + } + if (sd->params.qx3.button) { + /* button pressed - unlock the latch */ + do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, + 3, 0xdf, 0xdf, 0); + do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, + 3, 0xff, 0xff, 0); + } + + /* test whether microscope is cradled */ + sd->params.qx3.cradled = ((gspca_dev->usb_buf[2] & 0x40) == 0); + break; + } + + return 0; +} + +/* send a command to the camera with an additional data transaction */ +static int do_command_extended(struct gspca_dev *gspca_dev, u16 command, + u8 a, u8 b, u8 c, u8 d, + u8 e, u8 f, u8 g, u8 h, + u8 i, u8 j, u8 k, u8 l) +{ + u8 cmd[8]; + + cmd[0] = command >> 8; + cmd[1] = command & 0xff; + cmd[2] = a; + cmd[3] = b; + cmd[4] = c; + cmd[5] = d; + cmd[6] = 8; + cmd[7] = 0; + gspca_dev->usb_buf[0] = e; + gspca_dev->usb_buf[1] = f; + gspca_dev->usb_buf[2] = g; + gspca_dev->usb_buf[3] = h; + gspca_dev->usb_buf[4] = i; + gspca_dev->usb_buf[5] = j; + gspca_dev->usb_buf[6] = k; + gspca_dev->usb_buf[7] = l; + + return cpia_usb_transferCmd(gspca_dev, cmd); +} + +/* find_over_exposure + * Finds a suitable value of OverExposure for use with SetFlickerCtrl + * Some calculation is required because this value changes with the brightness + * set with SetColourParameters + * + * Parameters: Brightness - last brightness value set with SetColourParameters + * + * Returns: OverExposure value to use with SetFlickerCtrl + */ +#define FLICKER_MAX_EXPOSURE 250 +#define FLICKER_ALLOWABLE_OVER_EXPOSURE 146 +#define FLICKER_BRIGHTNESS_CONSTANT 59 +static int find_over_exposure(int brightness) +{ + int MaxAllowableOverExposure, OverExposure; + + MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness - + FLICKER_BRIGHTNESS_CONSTANT; + + if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) + OverExposure = MaxAllowableOverExposure; + else + OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE; + + return OverExposure; +} +#undef FLICKER_MAX_EXPOSURE +#undef FLICKER_ALLOWABLE_OVER_EXPOSURE +#undef FLICKER_BRIGHTNESS_CONSTANT + +/* initialise cam_data structure */ +static void reset_camera_params(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam_params *params = &sd->params; + + /* The following parameter values are the defaults from + * "Software Developer's Guide for CPiA Cameras". Any changes + * to the defaults are noted in comments. */ + params->colourParams.brightness = BRIGHTNESS_DEF; + params->colourParams.contrast = CONTRAST_DEF; + params->colourParams.saturation = SATURATION_DEF; + params->exposure.gainMode = 4; + params->exposure.expMode = 2; /* AEC */ + params->exposure.compMode = 1; + params->exposure.centreWeight = 1; + params->exposure.gain = 0; + params->exposure.fineExp = 0; + params->exposure.coarseExpLo = 185; + params->exposure.coarseExpHi = 0; + params->exposure.redComp = COMP_RED; + params->exposure.green1Comp = COMP_GREEN1; + params->exposure.green2Comp = COMP_GREEN2; + params->exposure.blueComp = COMP_BLUE; + params->colourBalance.balanceMode = 2; /* ACB */ + params->colourBalance.redGain = 32; + params->colourBalance.greenGain = 6; + params->colourBalance.blueGain = 92; + params->apcor.gain1 = 0x18; + params->apcor.gain2 = 0x16; + params->apcor.gain4 = 0x24; + params->apcor.gain8 = 0x34; + params->flickerControl.flickerMode = 0; + params->flickerControl.disabled = 1; + + params->flickerControl.coarseJump = + flicker_jumps[sd->mainsFreq] + [params->sensorFps.baserate] + [params->sensorFps.divisor]; + params->flickerControl.allowableOverExposure = + find_over_exposure(params->colourParams.brightness); + params->vlOffset.gain1 = 20; + params->vlOffset.gain2 = 24; + params->vlOffset.gain4 = 26; + params->vlOffset.gain8 = 26; + params->compressionParams.hysteresis = 3; + params->compressionParams.threshMax = 11; + params->compressionParams.smallStep = 1; + params->compressionParams.largeStep = 3; + params->compressionParams.decimationHysteresis = 2; + params->compressionParams.frDiffStepThresh = 5; + params->compressionParams.qDiffStepThresh = 3; + params->compressionParams.decimationThreshMod = 2; + /* End of default values from Software Developer's Guide */ + + /* Set Sensor FPS to 15fps. This seems better than 30fps + * for indoor lighting. */ + params->sensorFps.divisor = 1; + params->sensorFps.baserate = 1; + + params->yuvThreshold.yThreshold = 6; /* From windows driver */ + params->yuvThreshold.uvThreshold = 6; /* From windows driver */ + + params->format.subSample = SUBSAMPLE_420; + params->format.yuvOrder = YUVORDER_YUYV; + + params->compression.mode = CPIA_COMPRESSION_AUTO; + params->compression.decimation = NO_DECIMATION; + + params->compressionTarget.frTargeting = COMP_TARGET_DEF; + params->compressionTarget.targetFR = 15; /* From windows driver */ + params->compressionTarget.targetQ = 5; /* From windows driver */ + + params->qx3.qx3_detected = 0; + params->qx3.toplight = 0; + params->qx3.bottomlight = 0; + params->qx3.button = 0; + params->qx3.cradled = 0; +} + +static void printstatus(struct cam_params *params) +{ + PDEBUG(D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x", + params->status.systemState, params->status.grabState, + params->status.streamState, params->status.fatalError, + params->status.cmdError, params->status.debugFlags, + params->status.vpStatus, params->status.errorCode); +} + +static int goto_low_power(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + ret = do_command(gspca_dev, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0); + if (ret) + return ret; + + ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); + if (ret) + return ret; + + if (sd->params.status.systemState != LO_POWER_STATE) { + if (sd->params.status.systemState != WARM_BOOT_STATE) { + PDEBUG(D_ERR, + "unexpected state after lo power cmd: %02x", + sd->params.status.systemState); + printstatus(&sd->params); + } + return -EIO; + } + + PDEBUG(D_CONF, "camera now in LOW power state"); + return 0; +} + +static int goto_high_power(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + ret = do_command(gspca_dev, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0); + if (ret) + return ret; + + msleep_interruptible(40); /* windows driver does it too */ + + if (signal_pending(current)) + return -EINTR; + + do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); + if (ret) + return ret; + + if (sd->params.status.systemState != HI_POWER_STATE) { + PDEBUG(D_ERR, "unexpected state after hi power cmd: %02x", + sd->params.status.systemState); + printstatus(&sd->params); + return -EIO; + } + + PDEBUG(D_CONF, "camera now in HIGH power state"); + return 0; +} + +static int get_version_information(struct gspca_dev *gspca_dev) +{ + int ret; + + /* GetCPIAVersion */ + ret = do_command(gspca_dev, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0); + if (ret) + return ret; + + /* GetPnPID */ + return do_command(gspca_dev, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0); +} + +static int save_camera_state(struct gspca_dev *gspca_dev) +{ + int ret; + + ret = do_command(gspca_dev, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); + if (ret) + return ret; + + return do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); +} + +static int command_setformat(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + ret = do_command(gspca_dev, CPIA_COMMAND_SetFormat, + sd->params.format.videoSize, + sd->params.format.subSample, + sd->params.format.yuvOrder, 0); + if (ret) + return ret; + + return do_command(gspca_dev, CPIA_COMMAND_SetROI, + sd->params.roi.colStart, sd->params.roi.colEnd, + sd->params.roi.rowStart, sd->params.roi.rowEnd); +} + +static int command_setcolourparams(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + return do_command(gspca_dev, CPIA_COMMAND_SetColourParams, + sd->params.colourParams.brightness, + sd->params.colourParams.contrast, + sd->params.colourParams.saturation, 0); +} + +static int command_setapcor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + return do_command(gspca_dev, CPIA_COMMAND_SetApcor, + sd->params.apcor.gain1, + sd->params.apcor.gain2, + sd->params.apcor.gain4, + sd->params.apcor.gain8); +} + +static int command_setvloffset(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + return do_command(gspca_dev, CPIA_COMMAND_SetVLOffset, + sd->params.vlOffset.gain1, + sd->params.vlOffset.gain2, + sd->params.vlOffset.gain4, + sd->params.vlOffset.gain8); +} + +static int command_setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure, + sd->params.exposure.gainMode, + 1, + sd->params.exposure.compMode, + sd->params.exposure.centreWeight, + sd->params.exposure.gain, + sd->params.exposure.fineExp, + sd->params.exposure.coarseExpLo, + sd->params.exposure.coarseExpHi, + sd->params.exposure.redComp, + sd->params.exposure.green1Comp, + sd->params.exposure.green2Comp, + sd->params.exposure.blueComp); + if (ret) + return ret; + + if (sd->params.exposure.expMode != 1) { + ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure, + 0, + sd->params.exposure.expMode, + 0, 0, + sd->params.exposure.gain, + sd->params.exposure.fineExp, + sd->params.exposure.coarseExpLo, + sd->params.exposure.coarseExpHi, + 0, 0, 0, 0); + } + + return ret; +} + +static int command_setcolourbalance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->params.colourBalance.balanceMode == 1) { + int ret; + + ret = do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, + 1, + sd->params.colourBalance.redGain, + sd->params.colourBalance.greenGain, + sd->params.colourBalance.blueGain); + if (ret) + return ret; + + return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, + 3, 0, 0, 0); + } + if (sd->params.colourBalance.balanceMode == 2) { + return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, + 2, 0, 0, 0); + } + if (sd->params.colourBalance.balanceMode == 3) { + return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, + 3, 0, 0, 0); + } + + return -EINVAL; +} + +static int command_setcompressiontarget(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return do_command(gspca_dev, CPIA_COMMAND_SetCompressionTarget, + sd->params.compressionTarget.frTargeting, + sd->params.compressionTarget.targetFR, + sd->params.compressionTarget.targetQ, 0); +} + +static int command_setyuvtresh(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return do_command(gspca_dev, CPIA_COMMAND_SetYUVThresh, + sd->params.yuvThreshold.yThreshold, + sd->params.yuvThreshold.uvThreshold, 0, 0); +} + +static int command_setcompressionparams(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return do_command_extended(gspca_dev, + CPIA_COMMAND_SetCompressionParams, + 0, 0, 0, 0, + sd->params.compressionParams.hysteresis, + sd->params.compressionParams.threshMax, + sd->params.compressionParams.smallStep, + sd->params.compressionParams.largeStep, + sd->params.compressionParams.decimationHysteresis, + sd->params.compressionParams.frDiffStepThresh, + sd->params.compressionParams.qDiffStepThresh, + sd->params.compressionParams.decimationThreshMod); +} + +static int command_setcompression(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return do_command(gspca_dev, CPIA_COMMAND_SetCompression, + sd->params.compression.mode, + sd->params.compression.decimation, 0, 0); +} + +static int command_setsensorfps(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return do_command(gspca_dev, CPIA_COMMAND_SetSensorFPS, + sd->params.sensorFps.divisor, + sd->params.sensorFps.baserate, 0, 0); +} + +static int command_setflickerctrl(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return do_command(gspca_dev, CPIA_COMMAND_SetFlickerCtrl, + sd->params.flickerControl.flickerMode, + sd->params.flickerControl.coarseJump, + sd->params.flickerControl.allowableOverExposure, + 0); +} + +static int command_setecptiming(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return do_command(gspca_dev, CPIA_COMMAND_SetECPTiming, + sd->params.ecpTiming, 0, 0, 0); +} + +static int command_pause(struct gspca_dev *gspca_dev) +{ + return do_command(gspca_dev, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0); +} + +static int command_resume(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return do_command(gspca_dev, CPIA_COMMAND_InitStreamCap, + 0, sd->params.streamStartLine, 0, 0); +} + +static int command_setlights(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret, p1, p2; + + if (!sd->params.qx3.qx3_detected) + return 0; + + p1 = (sd->params.qx3.bottomlight == 0) << 1; + p2 = (sd->params.qx3.toplight == 0) << 3; + + ret = do_command(gspca_dev, CPIA_COMMAND_WriteVCReg, + 0x90, 0x8f, 0x50, 0); + if (ret) + return ret; + + return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0, + p1 | p2 | 0xe0, 0); +} + +static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply) +{ + /* Everything in here is from the Windows driver */ +/* define for compgain calculation */ +#if 0 +#define COMPGAIN(base, curexp, newexp) \ + (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5) +#define EXP_FROM_COMP(basecomp, curcomp, curexp) \ + (u16)((float)curexp * (float)(u8)(curcomp + 128) / \ + (float)(u8)(basecomp - 128)) +#else + /* equivalent functions without floating point math */ +#define COMPGAIN(base, curexp, newexp) \ + (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2 * newexp))) +#define EXP_FROM_COMP(basecomp, curcomp, curexp) \ + (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128))) +#endif + + struct sd *sd = (struct sd *) gspca_dev; + int currentexp = sd->params.exposure.coarseExpLo + + sd->params.exposure.coarseExpHi * 256; + int ret, startexp; + + if (on) { + int cj = sd->params.flickerControl.coarseJump; + sd->params.flickerControl.flickerMode = 1; + sd->params.flickerControl.disabled = 0; + if (sd->params.exposure.expMode != 2) { + sd->params.exposure.expMode = 2; + sd->exposure_status = EXPOSURE_NORMAL; + } + currentexp = currentexp << sd->params.exposure.gain; + sd->params.exposure.gain = 0; + /* round down current exposure to nearest value */ + startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj; + if (startexp < 1) + startexp = 1; + startexp = (startexp * cj) - 1; + if (FIRMWARE_VERSION(1, 2)) + while (startexp > MAX_EXP_102) + startexp -= cj; + else + while (startexp > MAX_EXP) + startexp -= cj; + sd->params.exposure.coarseExpLo = startexp & 0xff; + sd->params.exposure.coarseExpHi = startexp >> 8; + if (currentexp > startexp) { + if (currentexp > (2 * startexp)) + currentexp = 2 * startexp; + sd->params.exposure.redComp = + COMPGAIN(COMP_RED, currentexp, startexp); + sd->params.exposure.green1Comp = + COMPGAIN(COMP_GREEN1, currentexp, startexp); + sd->params.exposure.green2Comp = + COMPGAIN(COMP_GREEN2, currentexp, startexp); + sd->params.exposure.blueComp = + COMPGAIN(COMP_BLUE, currentexp, startexp); + } else { + sd->params.exposure.redComp = COMP_RED; + sd->params.exposure.green1Comp = COMP_GREEN1; + sd->params.exposure.green2Comp = COMP_GREEN2; + sd->params.exposure.blueComp = COMP_BLUE; + } + if (FIRMWARE_VERSION(1, 2)) + sd->params.exposure.compMode = 0; + else + sd->params.exposure.compMode = 1; + + sd->params.apcor.gain1 = 0x18; + sd->params.apcor.gain2 = 0x18; + sd->params.apcor.gain4 = 0x16; + sd->params.apcor.gain8 = 0x14; + } else { + sd->params.flickerControl.flickerMode = 0; + sd->params.flickerControl.disabled = 1; + /* Average equivalent coarse for each comp channel */ + startexp = EXP_FROM_COMP(COMP_RED, + sd->params.exposure.redComp, currentexp); + startexp += EXP_FROM_COMP(COMP_GREEN1, + sd->params.exposure.green1Comp, currentexp); + startexp += EXP_FROM_COMP(COMP_GREEN2, + sd->params.exposure.green2Comp, currentexp); + startexp += EXP_FROM_COMP(COMP_BLUE, + sd->params.exposure.blueComp, currentexp); + startexp = startexp >> 2; + while (startexp > MAX_EXP && sd->params.exposure.gain < + sd->params.exposure.gainMode - 1) { + startexp = startexp >> 1; + ++sd->params.exposure.gain; + } + if (FIRMWARE_VERSION(1, 2) && startexp > MAX_EXP_102) + startexp = MAX_EXP_102; + if (startexp > MAX_EXP) + startexp = MAX_EXP; + sd->params.exposure.coarseExpLo = startexp & 0xff; + sd->params.exposure.coarseExpHi = startexp >> 8; + sd->params.exposure.redComp = COMP_RED; + sd->params.exposure.green1Comp = COMP_GREEN1; + sd->params.exposure.green2Comp = COMP_GREEN2; + sd->params.exposure.blueComp = COMP_BLUE; + sd->params.exposure.compMode = 1; + sd->params.apcor.gain1 = 0x18; + sd->params.apcor.gain2 = 0x16; + sd->params.apcor.gain4 = 0x24; + sd->params.apcor.gain8 = 0x34; + } + sd->params.vlOffset.gain1 = 20; + sd->params.vlOffset.gain2 = 24; + sd->params.vlOffset.gain4 = 26; + sd->params.vlOffset.gain8 = 26; + + if (apply) { + ret = command_setexposure(gspca_dev); + if (ret) + return ret; + + ret = command_setapcor(gspca_dev); + if (ret) + return ret; + + ret = command_setvloffset(gspca_dev); + if (ret) + return ret; + + ret = command_setflickerctrl(gspca_dev); + if (ret) + return ret; + } + + return 0; +#undef EXP_FROM_COMP +#undef COMPGAIN +} + +/* monitor the exposure and adjust the sensor frame rate if needed */ +static void monitor_exposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 exp_acc, bcomp, cmd[8]; + int ret, light_exp, dark_exp, very_dark_exp; + int old_exposure, new_exposure, framerate; + int setfps = 0, setexp = 0, setflicker = 0; + + /* get necessary stats and register settings from camera */ + /* do_command can't handle this, so do it ourselves */ + cmd[0] = CPIA_COMMAND_ReadVPRegs >> 8; + cmd[1] = CPIA_COMMAND_ReadVPRegs & 0xff; + cmd[2] = 30; + cmd[3] = 4; + cmd[4] = 9; + cmd[5] = 8; + cmd[6] = 8; + cmd[7] = 0; + ret = cpia_usb_transferCmd(gspca_dev, cmd); + if (ret) { + err("ReadVPRegs(30,4,9,8) - failed: %d", ret); + return; + } + exp_acc = gspca_dev->usb_buf[0]; + bcomp = gspca_dev->usb_buf[1]; + + light_exp = sd->params.colourParams.brightness + + TC - 50 + EXP_ACC_LIGHT; + if (light_exp > 255) + light_exp = 255; + dark_exp = sd->params.colourParams.brightness + + TC - 50 - EXP_ACC_DARK; + if (dark_exp < 0) + dark_exp = 0; + very_dark_exp = dark_exp / 2; + + old_exposure = sd->params.exposure.coarseExpHi * 256 + + sd->params.exposure.coarseExpLo; + + if (!sd->params.flickerControl.disabled) { + /* Flicker control on */ + int max_comp = FIRMWARE_VERSION(1, 2) ? MAX_COMP : + HIGH_COMP_102; + bcomp += 128; /* decode */ + if (bcomp >= max_comp && exp_acc < dark_exp) { + /* dark */ + if (exp_acc < very_dark_exp) { + /* very dark */ + if (sd->exposure_status == EXPOSURE_VERY_DARK) + ++sd->exposure_count; + else { + sd->exposure_status = + EXPOSURE_VERY_DARK; + sd->exposure_count = 1; + } + } else { + /* just dark */ + if (sd->exposure_status == EXPOSURE_DARK) + ++sd->exposure_count; + else { + sd->exposure_status = EXPOSURE_DARK; + sd->exposure_count = 1; + } + } + } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) { + /* light */ + if (old_exposure <= VERY_LOW_EXP) { + /* very light */ + if (sd->exposure_status == EXPOSURE_VERY_LIGHT) + ++sd->exposure_count; + else { + sd->exposure_status = + EXPOSURE_VERY_LIGHT; + sd->exposure_count = 1; + } + } else { + /* just light */ + if (sd->exposure_status == EXPOSURE_LIGHT) + ++sd->exposure_count; + else { + sd->exposure_status = EXPOSURE_LIGHT; + sd->exposure_count = 1; + } + } + } else { + /* not dark or light */ + sd->exposure_status = EXPOSURE_NORMAL; + } + } else { + /* Flicker control off */ + if (old_exposure >= MAX_EXP && exp_acc < dark_exp) { + /* dark */ + if (exp_acc < very_dark_exp) { + /* very dark */ + if (sd->exposure_status == EXPOSURE_VERY_DARK) + ++sd->exposure_count; + else { + sd->exposure_status = + EXPOSURE_VERY_DARK; + sd->exposure_count = 1; + } + } else { + /* just dark */ + if (sd->exposure_status == EXPOSURE_DARK) + ++sd->exposure_count; + else { + sd->exposure_status = EXPOSURE_DARK; + sd->exposure_count = 1; + } + } + } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) { + /* light */ + if (old_exposure <= VERY_LOW_EXP) { + /* very light */ + if (sd->exposure_status == EXPOSURE_VERY_LIGHT) + ++sd->exposure_count; + else { + sd->exposure_status = + EXPOSURE_VERY_LIGHT; + sd->exposure_count = 1; + } + } else { + /* just light */ + if (sd->exposure_status == EXPOSURE_LIGHT) + ++sd->exposure_count; + else { + sd->exposure_status = EXPOSURE_LIGHT; + sd->exposure_count = 1; + } + } + } else { + /* not dark or light */ + sd->exposure_status = EXPOSURE_NORMAL; + } + } + + framerate = atomic_read(&sd->fps); + if (framerate > 30 || framerate < 1) + framerate = 1; + + if (!sd->params.flickerControl.disabled) { + /* Flicker control on */ + if ((sd->exposure_status == EXPOSURE_VERY_DARK || + sd->exposure_status == EXPOSURE_DARK) && + sd->exposure_count >= DARK_TIME * framerate && + sd->params.sensorFps.divisor < 2) { + + /* dark for too long */ + ++sd->params.sensorFps.divisor; + setfps = 1; + + sd->params.flickerControl.coarseJump = + flicker_jumps[sd->mainsFreq] + [sd->params.sensorFps.baserate] + [sd->params.sensorFps.divisor]; + setflicker = 1; + + new_exposure = sd->params.flickerControl.coarseJump-1; + while (new_exposure < old_exposure / 2) + new_exposure += + sd->params.flickerControl.coarseJump; + sd->params.exposure.coarseExpLo = new_exposure & 0xff; + sd->params.exposure.coarseExpHi = new_exposure >> 8; + setexp = 1; + sd->exposure_status = EXPOSURE_NORMAL; + PDEBUG(D_CONF, "Automatically decreasing sensor_fps"); + + } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT || + sd->exposure_status == EXPOSURE_LIGHT) && + sd->exposure_count >= LIGHT_TIME * framerate && + sd->params.sensorFps.divisor > 0) { + + /* light for too long */ + int max_exp = FIRMWARE_VERSION(1, 2) ? MAX_EXP_102 : + MAX_EXP; + --sd->params.sensorFps.divisor; + setfps = 1; + + sd->params.flickerControl.coarseJump = + flicker_jumps[sd->mainsFreq] + [sd->params.sensorFps.baserate] + [sd->params.sensorFps.divisor]; + setflicker = 1; + + new_exposure = sd->params.flickerControl.coarseJump-1; + while (new_exposure < 2 * old_exposure && + new_exposure + + sd->params.flickerControl.coarseJump < max_exp) + new_exposure += + sd->params.flickerControl.coarseJump; + sd->params.exposure.coarseExpLo = new_exposure & 0xff; + sd->params.exposure.coarseExpHi = new_exposure >> 8; + setexp = 1; + sd->exposure_status = EXPOSURE_NORMAL; + PDEBUG(D_CONF, "Automatically increasing sensor_fps"); + } + } else { + /* Flicker control off */ + if ((sd->exposure_status == EXPOSURE_VERY_DARK || + sd->exposure_status == EXPOSURE_DARK) && + sd->exposure_count >= DARK_TIME * framerate && + sd->params.sensorFps.divisor < 2) { + + /* dark for too long */ + ++sd->params.sensorFps.divisor; + setfps = 1; + + if (sd->params.exposure.gain > 0) { + --sd->params.exposure.gain; + setexp = 1; + } + sd->exposure_status = EXPOSURE_NORMAL; + PDEBUG(D_CONF, "Automatically decreasing sensor_fps"); + + } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT || + sd->exposure_status == EXPOSURE_LIGHT) && + sd->exposure_count >= LIGHT_TIME * framerate && + sd->params.sensorFps.divisor > 0) { + + /* light for too long */ + --sd->params.sensorFps.divisor; + setfps = 1; + + if (sd->params.exposure.gain < + sd->params.exposure.gainMode - 1) { + ++sd->params.exposure.gain; + setexp = 1; + } + sd->exposure_status = EXPOSURE_NORMAL; + PDEBUG(D_CONF, "Automatically increasing sensor_fps"); + } + } + + if (setexp) + command_setexposure(gspca_dev); + + if (setfps) + command_setsensorfps(gspca_dev); + + if (setflicker) + command_setflickerctrl(gspca_dev); +} + +/*-----------------------------------------------------------------*/ +/* if flicker is switched off, this function switches it back on.It checks, + however, that conditions are suitable before restarting it. + This should only be called for firmware version 1.2. + + It also adjust the colour balance when an exposure step is detected - as + long as flicker is running +*/ +static void restart_flicker(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int cam_exposure, old_exp; + + if (!FIRMWARE_VERSION(1, 2)) + return; + + cam_exposure = atomic_read(&sd->cam_exposure); + + if (sd->params.flickerControl.flickerMode == 0 || + cam_exposure == 0) + return; + + old_exp = sd->params.exposure.coarseExpLo + + sd->params.exposure.coarseExpHi*256; + /* + see how far away camera exposure is from a valid + flicker exposure value + */ + cam_exposure %= sd->params.flickerControl.coarseJump; + if (!sd->params.flickerControl.disabled && + cam_exposure <= sd->params.flickerControl.coarseJump - 3) { + /* Flicker control auto-disabled */ + sd->params.flickerControl.disabled = 1; + } + + if (sd->params.flickerControl.disabled && + old_exp > sd->params.flickerControl.coarseJump + + ROUND_UP_EXP_FOR_FLICKER) { + /* exposure is now high enough to switch + flicker control back on */ + set_flicker(gspca_dev, 1, 1); + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam; + + reset_camera_params(gspca_dev); + + PDEBUG(D_PROBE, "cpia CPiA camera detected (vid/pid 0x%04X:0x%04X)", + id->idVendor, id->idProduct); + + cam = &gspca_dev->cam; + cam->cam_mode = mode; + cam->nmodes = ARRAY_SIZE(mode); + + sd_setfreq(gspca_dev, FREQ_DEF); + + return 0; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int priv, ret; + + /* Start the camera in low power mode */ + if (goto_low_power(gspca_dev)) { + if (sd->params.status.systemState != WARM_BOOT_STATE) { + PDEBUG(D_ERR, "unexpected systemstate: %02x", + sd->params.status.systemState); + printstatus(&sd->params); + return -ENODEV; + } + + /* FIXME: this is just dirty trial and error */ + ret = goto_high_power(gspca_dev); + if (ret) + return ret; + + ret = do_command(gspca_dev, CPIA_COMMAND_DiscardFrame, + 0, 0, 0, 0); + if (ret) + return ret; + + ret = goto_low_power(gspca_dev); + if (ret) + return ret; + } + + /* procedure described in developer's guide p3-28 */ + + /* Check the firmware version. */ + sd->params.version.firmwareVersion = 0; + get_version_information(gspca_dev); + if (sd->params.version.firmwareVersion != 1) { + PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)", + sd->params.version.firmwareVersion); + return -ENODEV; + } + + /* A bug in firmware 1-02 limits gainMode to 2 */ + if (sd->params.version.firmwareRevision <= 2 && + sd->params.exposure.gainMode > 2) { + sd->params.exposure.gainMode = 2; + } + + /* set QX3 detected flag */ + sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 && + sd->params.pnpID.product == 0x0001); + + /* The fatal error checking should be done after + * the camera powers up (developer's guide p 3-38) */ + + /* Set streamState before transition to high power to avoid bug + * in firmware 1-02 */ + ret = do_command(gspca_dev, CPIA_COMMAND_ModifyCameraStatus, + STREAMSTATE, 0, STREAM_NOT_READY, 0); + if (ret) + return ret; + + /* GotoHiPower */ + ret = goto_high_power(gspca_dev); + if (ret) + return ret; + + /* Check the camera status */ + ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); + if (ret) + return ret; + + if (sd->params.status.fatalError) { + PDEBUG(D_ERR, "fatal_error: %04x, vp_status: %04x", + sd->params.status.fatalError, + sd->params.status.vpStatus); + return -EIO; + } + + /* VPVersion can't be retrieved before the camera is in HiPower, + * so get it here instead of in get_version_information. */ + ret = do_command(gspca_dev, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0); + if (ret) + return ret; + + /* Determine video mode settings */ + sd->params.streamStartLine = 120; + + priv = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + if (priv & 0x01) { /* crop */ + sd->params.roi.colStart = 2; + sd->params.roi.rowStart = 6; + } else { + sd->params.roi.colStart = 0; + sd->params.roi.rowStart = 0; + } + + if (priv & 0x02) { /* quarter */ + sd->params.format.videoSize = VIDEOSIZE_QCIF; + sd->params.roi.colStart /= 2; + sd->params.roi.rowStart /= 2; + sd->params.streamStartLine /= 2; + } else + sd->params.format.videoSize = VIDEOSIZE_CIF; + + sd->params.roi.colEnd = sd->params.roi.colStart + + (gspca_dev->width >> 3); + sd->params.roi.rowEnd = sd->params.roi.rowStart + + (gspca_dev->height >> 2); + + /* And now set the camera to a known state */ + ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode, + CPIA_GRAB_CONTINEOUS, 0, 0, 0); + if (ret) + return ret; + /* We start with compression disabled, as we need one uncompressed + frame to handle later compressed frames */ + ret = do_command(gspca_dev, CPIA_COMMAND_SetCompression, + CPIA_COMPRESSION_NONE, + NO_DECIMATION, 0, 0); + if (ret) + return ret; + ret = command_setcompressiontarget(gspca_dev); + if (ret) + return ret; + ret = command_setcolourparams(gspca_dev); + if (ret) + return ret; + ret = command_setformat(gspca_dev); + if (ret) + return ret; + ret = command_setyuvtresh(gspca_dev); + if (ret) + return ret; + ret = command_setecptiming(gspca_dev); + if (ret) + return ret; + ret = command_setcompressionparams(gspca_dev); + if (ret) + return ret; + ret = command_setexposure(gspca_dev); + if (ret) + return ret; + ret = command_setcolourbalance(gspca_dev); + if (ret) + return ret; + ret = command_setsensorfps(gspca_dev); + if (ret) + return ret; + ret = command_setapcor(gspca_dev); + if (ret) + return ret; + ret = command_setflickerctrl(gspca_dev); + if (ret) + return ret; + ret = command_setvloffset(gspca_dev); + if (ret) + return ret; + + /* Start stream */ + ret = command_resume(gspca_dev); + if (ret) + return ret; + + /* Wait 6 frames before turning compression on for the sensor to get + all settings and AEC/ACB to settle */ + sd->first_frame = 6; + sd->exposure_status = EXPOSURE_NORMAL; + sd->exposure_count = 0; + atomic_set(&sd->cam_exposure, 0); + atomic_set(&sd->fps, 0); + + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + command_pause(gspca_dev); + + /* save camera state for later open (developers guide ch 3.5.3) */ + save_camera_state(gspca_dev); + + /* GotoLoPower */ + goto_low_power(gspca_dev); + + /* Update the camera status */ + do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + /* If the last button state is pressed, release it now! */ + if (sd->params.qx3.button) { + /* The camera latch will hold the pressed state until we reset + the latch, so we do not reset sd->params.qx3.button now, to + avoid a false keypress being reported the next sd_start */ + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + } +#endif +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + /* Start / Stop the camera to make sure we are talking to + a supported camera, and to get some information from it + to print. */ + ret = sd_start(gspca_dev); + if (ret) + return ret; + + /* Ensure the QX3 illuminators' states are restored upon resume, + or disable the illuminator controls, if this isn't a QX3 */ + if (sd->params.qx3.qx3_detected) + command_setlights(gspca_dev); + else + gspca_dev->ctrl_dis |= + ((1 << ILLUMINATORS_1_IDX) | (1 << ILLUMINATORS_2_IDX)); + + sd_stopN(gspca_dev); + + PDEBUG(D_PROBE, "CPIA Version: %d.%02d (%d.%d)", + sd->params.version.firmwareVersion, + sd->params.version.firmwareRevision, + sd->params.version.vcVersion, + sd->params.version.vcRevision); + PDEBUG(D_PROBE, "CPIA PnP-ID: %04x:%04x:%04x", + sd->params.pnpID.vendor, sd->params.pnpID.product, + sd->params.pnpID.deviceRevision); + PDEBUG(D_PROBE, "VP-Version: %d.%d %04x", + sd->params.vpVersion.vpVersion, + sd->params.vpVersion.vpRevision, + sd->params.vpVersion.cameraHeadID); + + return 0; +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, + int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* Check for SOF */ + if (len >= 64 && + data[0] == MAGIC_0 && data[1] == MAGIC_1 && + data[16] == sd->params.format.videoSize && + data[17] == sd->params.format.subSample && + data[18] == sd->params.format.yuvOrder && + data[24] == sd->params.roi.colStart && + data[25] == sd->params.roi.colEnd && + data[26] == sd->params.roi.rowStart && + data[27] == sd->params.roi.rowEnd) { + u8 *image; + + atomic_set(&sd->cam_exposure, data[39] * 2); + atomic_set(&sd->fps, data[41]); + + /* Check for proper EOF for last frame */ + image = gspca_dev->image; + if (image != NULL && + gspca_dev->image_len > 4 && + image[gspca_dev->image_len - 4] == 0xff && + image[gspca_dev->image_len - 3] == 0xff && + image[gspca_dev->image_len - 2] == 0xff && + image[gspca_dev->image_len - 1] == 0xff) + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + return; + } + + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static void sd_dq_callback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* Set the normal compression settings once we have captured a + few uncompressed frames (and AEC has hopefully settled) */ + if (sd->first_frame) { + sd->first_frame--; + if (sd->first_frame == 0) + command_setcompression(gspca_dev); + } + + /* Switch flicker control back on if it got turned off */ + restart_flicker(gspca_dev); + + /* If AEC is enabled, monitor the exposure and + adjust the sensor frame rate if needed */ + if (sd->params.exposure.expMode == 2) + monitor_exposure(gspca_dev); + + /* Update our knowledge of the camera state */ + do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); + do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + sd->params.colourParams.brightness = val; + sd->params.flickerControl.allowableOverExposure = + find_over_exposure(sd->params.colourParams.brightness); + if (gspca_dev->streaming) { + ret = command_setcolourparams(gspca_dev); + if (ret) + return ret; + return command_setflickerctrl(gspca_dev); + } + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->params.colourParams.brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->params.colourParams.contrast = val; + if (gspca_dev->streaming) + return command_setcolourparams(gspca_dev); + + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->params.colourParams.contrast; + return 0; +} + +static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->params.colourParams.saturation = val; + if (gspca_dev->streaming) + return command_setcolourparams(gspca_dev); + + return 0; +} + +static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->params.colourParams.saturation; + return 0; +} + +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + int on; + + switch (val) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + on = 0; + break; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + on = 1; + sd->mainsFreq = 0; + break; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + on = 1; + sd->mainsFreq = 1; + break; + default: + return -EINVAL; + } + + sd->freq = val; + sd->params.flickerControl.coarseJump = + flicker_jumps[sd->mainsFreq] + [sd->params.sensorFps.baserate] + [sd->params.sensorFps.divisor]; + + return set_flicker(gspca_dev, on, gspca_dev->streaming); +} + +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->freq; + return 0; +} + +static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->params.compressionTarget.frTargeting = val; + if (gspca_dev->streaming) + return command_setcompressiontarget(gspca_dev); + + return 0; +} + +static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->params.compressionTarget.frTargeting; + return 0; +} + +static int sd_setilluminator(struct gspca_dev *gspca_dev, __s32 val, int n) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + if (!sd->params.qx3.qx3_detected) + return -EINVAL; + + switch (n) { + case 1: + sd->params.qx3.bottomlight = val ? 1 : 0; + break; + case 2: + sd->params.qx3.toplight = val ? 1 : 0; + break; + default: + return -EINVAL; + } + + ret = command_setlights(gspca_dev); + if (ret && ret != -EINVAL) + ret = -EBUSY; + + return ret; +} + +static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val) +{ + return sd_setilluminator(gspca_dev, val, 1); +} + +static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val) +{ + return sd_setilluminator(gspca_dev, val, 2); +} + +static int sd_getilluminator(struct gspca_dev *gspca_dev, __s32 *val, int n) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!sd->params.qx3.qx3_detected) + return -EINVAL; + + switch (n) { + case 1: + *val = sd->params.qx3.bottomlight; + break; + case 2: + *val = sd->params.qx3.toplight; + break; + default: + return -EINVAL; + } + return 0; +} + +static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val) +{ + return sd_getilluminator(gspca_dev, val, 1); +} + +static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val) +{ + return sd_getilluminator(gspca_dev, val, 2); +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "NoFliker"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + case V4L2_CID_COMP_TARGET: + switch (menu->index) { + case CPIA_COMPRESSION_TARGET_QUALITY: + strcpy((char *) menu->name, "Quality"); + return 0; + case CPIA_COMPRESSION_TARGET_FRAMERATE: + strcpy((char *) menu->name, "Framerate"); + return 0; + } + break; + } + return -EINVAL; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .dq_callback = sd_dq_callback, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .other_input = 1, +#endif +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0553, 0x0002)}, + {USB_DEVICE(0x0813, 0x0001)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/etoms.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/etoms.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/etoms.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/etoms.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,908 @@ +/* + * Etoms Et61x151 GPL Linux driver by Michel Xhaard (09/09/2004) + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "etoms" + +#include "gspca.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("Etoms USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + unsigned char autogain; + + char sensor; +#define SENSOR_PAS106 0 +#define SENSOR_TAS5130CXX 1 + signed char ag_cnt; +#define AG_CNT_START 13 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 1, + .maximum = 127, + .step = 1, +#define BRIGHTNESS_DEF 63 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, +#define CONTRAST_DEF 127 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define COLOR_IDX 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 15, + .step = 1, +#define COLOR_DEF 7 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, +/* {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, */ +}; + +static const struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +#define ETOMS_ALT_SIZE_1000 12 + +#define ET_GPIO_DIR_CTRL 0x04 /* Control IO bit[0..5] (0 in 1 out) */ +#define ET_GPIO_OUT 0x05 /* Only IO data */ +#define ET_GPIO_IN 0x06 /* Read Only IO data */ +#define ET_RESET_ALL 0x03 +#define ET_ClCK 0x01 +#define ET_CTRL 0x02 /* enable i2c OutClck Powerdown mode */ + +#define ET_COMP 0x12 /* Compression register */ +#define ET_MAXQt 0x13 +#define ET_MINQt 0x14 +#define ET_COMP_VAL0 0x02 +#define ET_COMP_VAL1 0x03 + +#define ET_REG1d 0x1d +#define ET_REG1e 0x1e +#define ET_REG1f 0x1f +#define ET_REG20 0x20 +#define ET_REG21 0x21 +#define ET_REG22 0x22 +#define ET_REG23 0x23 +#define ET_REG24 0x24 +#define ET_REG25 0x25 +/* base registers for luma calculation */ +#define ET_LUMA_CENTER 0x39 + +#define ET_G_RED 0x4d +#define ET_G_GREEN1 0x4e +#define ET_G_BLUE 0x4f +#define ET_G_GREEN2 0x50 +#define ET_G_GR_H 0x51 +#define ET_G_GB_H 0x52 + +#define ET_O_RED 0x34 +#define ET_O_GREEN1 0x35 +#define ET_O_BLUE 0x36 +#define ET_O_GREEN2 0x37 + +#define ET_SYNCHRO 0x68 +#define ET_STARTX 0x69 +#define ET_STARTY 0x6a +#define ET_WIDTH_LOW 0x6b +#define ET_HEIGTH_LOW 0x6c +#define ET_W_H_HEIGTH 0x6d + +#define ET_REG6e 0x6e /* OBW */ +#define ET_REG6f 0x6f /* OBW */ +#define ET_REG70 0x70 /* OBW_AWB */ +#define ET_REG71 0x71 /* OBW_AWB */ +#define ET_REG72 0x72 /* OBW_AWB */ +#define ET_REG73 0x73 /* Clkdelay ns */ +#define ET_REG74 0x74 /* test pattern */ +#define ET_REG75 0x75 /* test pattern */ + +#define ET_I2C_CLK 0x8c +#define ET_PXL_CLK 0x60 + +#define ET_I2C_BASE 0x89 +#define ET_I2C_COUNT 0x8a +#define ET_I2C_PREFETCH 0x8b +#define ET_I2C_REG 0x88 +#define ET_I2C_DATA7 0x87 +#define ET_I2C_DATA6 0x86 +#define ET_I2C_DATA5 0x85 +#define ET_I2C_DATA4 0x84 +#define ET_I2C_DATA3 0x83 +#define ET_I2C_DATA2 0x82 +#define ET_I2C_DATA1 0x81 +#define ET_I2C_DATA0 0x80 + +#define PAS106_REG2 0x02 /* pxlClk = systemClk/(reg2) */ +#define PAS106_REG3 0x03 /* line/frame H [11..4] */ +#define PAS106_REG4 0x04 /* line/frame L [3..0] */ +#define PAS106_REG5 0x05 /* exposure time line offset(default 5) */ +#define PAS106_REG6 0x06 /* exposure time pixel offset(default 6) */ +#define PAS106_REG7 0x07 /* signbit Dac (default 0) */ +#define PAS106_REG9 0x09 +#define PAS106_REG0e 0x0e /* global gain [4..0](default 0x0e) */ +#define PAS106_REG13 0x13 /* end i2c write */ + +static const __u8 GainRGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; + +static const __u8 I2c2[] = { 0x08, 0x08, 0x08, 0x08, 0x0d }; + +static const __u8 I2c3[] = { 0x12, 0x05 }; + +static const __u8 I2c4[] = { 0x41, 0x08 }; + +/* read 'len' bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 index, + __u16 len) +{ + struct usb_device *dev = gspca_dev->dev; + +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_r: buffer overflow"); + return; + } +#endif + usb_control_msg(dev, + usb_rcvctrlpipe(dev, 0), + 0, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0, + index, gspca_dev->usb_buf, len, 500); + PDEBUG(D_USBI, "reg read [%02x] -> %02x ..", + index, gspca_dev->usb_buf[0]); +} + +static void reg_w_val(struct gspca_dev *gspca_dev, + __u16 index, + __u8 val) +{ + struct usb_device *dev = gspca_dev->dev; + + gspca_dev->usb_buf[0] = val; + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0, + index, gspca_dev->usb_buf, 1, 500); +} + +static void reg_w(struct gspca_dev *gspca_dev, + __u16 index, + const __u8 *buffer, + __u16 len) +{ + struct usb_device *dev = gspca_dev->dev; + +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_w: buffer overflow"); + return; + } + PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); +#endif + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0, index, gspca_dev->usb_buf, len, 500); +} + +static int i2c_w(struct gspca_dev *gspca_dev, + __u8 reg, + const __u8 *buffer, + int len, __u8 mode) +{ + /* buffer should be [D0..D7] */ + __u8 ptchcount; + + /* set the base address */ + reg_w_val(gspca_dev, ET_I2C_BASE, 0x40); + /* sensor base for the pas106 */ + /* set count and prefetch */ + ptchcount = ((len & 0x07) << 4) | (mode & 0x03); + reg_w_val(gspca_dev, ET_I2C_COUNT, ptchcount); + /* set the register base */ + reg_w_val(gspca_dev, ET_I2C_REG, reg); + while (--len >= 0) + reg_w_val(gspca_dev, ET_I2C_DATA0 + len, buffer[len]); + return 0; +} + +static int i2c_r(struct gspca_dev *gspca_dev, + __u8 reg) +{ + /* set the base address */ + reg_w_val(gspca_dev, ET_I2C_BASE, 0x40); + /* sensor base for the pas106 */ + /* set count and prefetch (cnd: 4 bits - mode: 4 bits) */ + reg_w_val(gspca_dev, ET_I2C_COUNT, 0x11); + reg_w_val(gspca_dev, ET_I2C_REG, reg); /* set the register base */ + reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x02); /* prefetch */ + reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x00); + reg_r(gspca_dev, ET_I2C_DATA0, 1); /* read one byte */ + return 0; +} + +static int Et_WaitStatus(struct gspca_dev *gspca_dev) +{ + int retry = 10; + + while (retry--) { + reg_r(gspca_dev, ET_ClCK, 1); + if (gspca_dev->usb_buf[0] != 0) + return 1; + } + return 0; +} + +static int et_video(struct gspca_dev *gspca_dev, + int on) +{ + int ret; + + reg_w_val(gspca_dev, ET_GPIO_OUT, + on ? 0x10 /* startvideo - set Bit5 */ + : 0); /* stopvideo */ + ret = Et_WaitStatus(gspca_dev); + if (ret != 0) + PDEBUG(D_ERR, "timeout video on/off"); + return ret; +} + +static void Et_init2(struct gspca_dev *gspca_dev) +{ + __u8 value; + static const __u8 FormLine[] = { 0x84, 0x03, 0x14, 0xf4, 0x01, 0x05 }; + + PDEBUG(D_STREAM, "Open Init2 ET"); + reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 0x2f); + reg_w_val(gspca_dev, ET_GPIO_OUT, 0x10); + reg_r(gspca_dev, ET_GPIO_IN, 1); + reg_w_val(gspca_dev, ET_ClCK, 0x14); /* 0x14 // 0x16 enabled pattern */ + reg_w_val(gspca_dev, ET_CTRL, 0x1b); + + /* compression et subsampling */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) + value = ET_COMP_VAL1; /* 320 */ + else + value = ET_COMP_VAL0; /* 640 */ + reg_w_val(gspca_dev, ET_COMP, value); + reg_w_val(gspca_dev, ET_MAXQt, 0x1f); + reg_w_val(gspca_dev, ET_MINQt, 0x04); + /* undocumented registers */ + reg_w_val(gspca_dev, ET_REG1d, 0xff); + reg_w_val(gspca_dev, ET_REG1e, 0xff); + reg_w_val(gspca_dev, ET_REG1f, 0xff); + reg_w_val(gspca_dev, ET_REG20, 0x35); + reg_w_val(gspca_dev, ET_REG21, 0x01); + reg_w_val(gspca_dev, ET_REG22, 0x00); + reg_w_val(gspca_dev, ET_REG23, 0xff); + reg_w_val(gspca_dev, ET_REG24, 0xff); + reg_w_val(gspca_dev, ET_REG25, 0x0f); + /* colors setting */ + reg_w_val(gspca_dev, 0x30, 0x11); /* 0x30 */ + reg_w_val(gspca_dev, 0x31, 0x40); + reg_w_val(gspca_dev, 0x32, 0x00); + reg_w_val(gspca_dev, ET_O_RED, 0x00); /* 0x34 */ + reg_w_val(gspca_dev, ET_O_GREEN1, 0x00); + reg_w_val(gspca_dev, ET_O_BLUE, 0x00); + reg_w_val(gspca_dev, ET_O_GREEN2, 0x00); + /*************/ + reg_w_val(gspca_dev, ET_G_RED, 0x80); /* 0x4d */ + reg_w_val(gspca_dev, ET_G_GREEN1, 0x80); + reg_w_val(gspca_dev, ET_G_BLUE, 0x80); + reg_w_val(gspca_dev, ET_G_GREEN2, 0x80); + reg_w_val(gspca_dev, ET_G_GR_H, 0x00); + reg_w_val(gspca_dev, ET_G_GB_H, 0x00); /* 0x52 */ + /* Window control registers */ + reg_w_val(gspca_dev, 0x61, 0x80); /* use cmc_out */ + reg_w_val(gspca_dev, 0x62, 0x02); + reg_w_val(gspca_dev, 0x63, 0x03); + reg_w_val(gspca_dev, 0x64, 0x14); + reg_w_val(gspca_dev, 0x65, 0x0e); + reg_w_val(gspca_dev, 0x66, 0x02); + reg_w_val(gspca_dev, 0x67, 0x02); + + /**************************************/ + reg_w_val(gspca_dev, ET_SYNCHRO, 0x8f); /* 0x68 */ + reg_w_val(gspca_dev, ET_STARTX, 0x69); /* 0x6a //0x69 */ + reg_w_val(gspca_dev, ET_STARTY, 0x0d); /* 0x0d //0x0c */ + reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x80); + reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0xe0); + reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x60); /* 6d */ + reg_w_val(gspca_dev, ET_REG6e, 0x86); + reg_w_val(gspca_dev, ET_REG6f, 0x01); + reg_w_val(gspca_dev, ET_REG70, 0x26); + reg_w_val(gspca_dev, ET_REG71, 0x7a); + reg_w_val(gspca_dev, ET_REG72, 0x01); + /* Clock Pattern registers ***************** */ + reg_w_val(gspca_dev, ET_REG73, 0x00); + reg_w_val(gspca_dev, ET_REG74, 0x18); /* 0x28 */ + reg_w_val(gspca_dev, ET_REG75, 0x0f); /* 0x01 */ + /**********************************************/ + reg_w_val(gspca_dev, 0x8a, 0x20); + reg_w_val(gspca_dev, 0x8d, 0x0f); + reg_w_val(gspca_dev, 0x8e, 0x08); + /**************************************/ + reg_w_val(gspca_dev, 0x03, 0x08); + reg_w_val(gspca_dev, ET_PXL_CLK, 0x03); + reg_w_val(gspca_dev, 0x81, 0xff); + reg_w_val(gspca_dev, 0x80, 0x00); + reg_w_val(gspca_dev, 0x81, 0xff); + reg_w_val(gspca_dev, 0x80, 0x20); + reg_w_val(gspca_dev, 0x03, 0x01); + reg_w_val(gspca_dev, 0x03, 0x00); + reg_w_val(gspca_dev, 0x03, 0x08); + /********************************************/ + +/* reg_r(gspca_dev, ET_I2C_BASE, 1); + always 0x40 as the pas106 ??? */ + /* set the sensor */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) + value = 0x04; /* 320 */ + else /* 640 */ + value = 0x1e; /* 0x17 * setting PixelClock + * 0x03 mean 24/(3+1) = 6 Mhz + * 0x05 -> 24/(5+1) = 4 Mhz + * 0x0b -> 24/(11+1) = 2 Mhz + * 0x17 -> 24/(23+1) = 1 Mhz + */ + reg_w_val(gspca_dev, ET_PXL_CLK, value); + /* now set by fifo the FormatLine setting */ + reg_w(gspca_dev, 0x62, FormLine, 6); + + /* set exposure times [ 0..0x78] 0->longvalue 0x78->shortvalue */ + reg_w_val(gspca_dev, 0x81, 0x47); /* 0x47; */ + reg_w_val(gspca_dev, 0x80, 0x40); /* 0x40; */ + /* Pedro change */ + /* Brightness change Brith+ decrease value */ + /* Brigth- increase value */ + /* original value = 0x70; */ + reg_w_val(gspca_dev, 0x81, 0x30); /* 0x20; - set brightness */ + reg_w_val(gspca_dev, 0x80, 0x20); /* 0x20; */ +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + __u8 brightness = sd->brightness; + + for (i = 0; i < 4; i++) + reg_w_val(gspca_dev, ET_O_RED + i, brightness); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; + __u8 contrast = sd->contrast; + + memset(RGBG, contrast, sizeof(RGBG) - 2); + reg_w(gspca_dev, ET_G_RED, RGBG, 6); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d }; + __u8 i2cflags = 0x01; + /* __u8 green = 0; */ + __u8 colors = sd->colors; + + I2cc[3] = colors; /* red */ + I2cc[0] = 15 - colors; /* blue */ + /* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */ + /* I2cc[1] = I2cc[2] = green; */ + if (sd->sensor == SENSOR_PAS106) { + i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3); + i2c_w(gspca_dev, PAS106_REG9, I2cc, sizeof I2cc, 1); + } +/* PDEBUG(D_CONF , "Etoms red %d blue %d green %d", + I2cc[3], I2cc[0], green); */ +} + +static void getcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) { +/* i2c_r(gspca_dev, PAS106_REG9); * blue */ + i2c_r(gspca_dev, PAS106_REG9 + 3); /* red */ + sd->colors = gspca_dev->usb_buf[0] & 0x0f; + } +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->autogain) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; +} + +static void Et_init1(struct gspca_dev *gspca_dev) +{ + __u8 value; +/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0x22, 0xac, 0x00, 0x01, 0x00}; */ + __u8 I2c0[] = { 0x0a, 0x12, 0x05, 0x6d, 0xcd, 0x00, 0x01, 0x00 }; + /* try 1/120 0x6d 0xcd 0x40 */ +/* __u8 I2c0 [] = {0x0a, 0x12, 0x05, 0xfe, 0xfe, 0xc0, 0x01, 0x00}; + * 1/60000 hmm ?? */ + + PDEBUG(D_STREAM, "Open Init1 ET"); + reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 7); + reg_r(gspca_dev, ET_GPIO_IN, 1); + reg_w_val(gspca_dev, ET_RESET_ALL, 1); + reg_w_val(gspca_dev, ET_RESET_ALL, 0); + reg_w_val(gspca_dev, ET_ClCK, 0x10); + reg_w_val(gspca_dev, ET_CTRL, 0x19); + /* compression et subsampling */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) + value = ET_COMP_VAL1; + else + value = ET_COMP_VAL0; + PDEBUG(D_STREAM, "Open mode %d Compression %d", + gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv, + value); + reg_w_val(gspca_dev, ET_COMP, value); + reg_w_val(gspca_dev, ET_MAXQt, 0x1d); + reg_w_val(gspca_dev, ET_MINQt, 0x02); + /* undocumented registers */ + reg_w_val(gspca_dev, ET_REG1d, 0xff); + reg_w_val(gspca_dev, ET_REG1e, 0xff); + reg_w_val(gspca_dev, ET_REG1f, 0xff); + reg_w_val(gspca_dev, ET_REG20, 0x35); + reg_w_val(gspca_dev, ET_REG21, 0x01); + reg_w_val(gspca_dev, ET_REG22, 0x00); + reg_w_val(gspca_dev, ET_REG23, 0xf7); + reg_w_val(gspca_dev, ET_REG24, 0xff); + reg_w_val(gspca_dev, ET_REG25, 0x07); + /* colors setting */ + reg_w_val(gspca_dev, ET_G_RED, 0x80); + reg_w_val(gspca_dev, ET_G_GREEN1, 0x80); + reg_w_val(gspca_dev, ET_G_BLUE, 0x80); + reg_w_val(gspca_dev, ET_G_GREEN2, 0x80); + reg_w_val(gspca_dev, ET_G_GR_H, 0x00); + reg_w_val(gspca_dev, ET_G_GB_H, 0x00); + /* Window control registers */ + reg_w_val(gspca_dev, ET_SYNCHRO, 0xf0); + reg_w_val(gspca_dev, ET_STARTX, 0x56); /* 0x56 */ + reg_w_val(gspca_dev, ET_STARTY, 0x05); /* 0x04 */ + reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x60); + reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0x20); + reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x50); + reg_w_val(gspca_dev, ET_REG6e, 0x86); + reg_w_val(gspca_dev, ET_REG6f, 0x01); + reg_w_val(gspca_dev, ET_REG70, 0x86); + reg_w_val(gspca_dev, ET_REG71, 0x14); + reg_w_val(gspca_dev, ET_REG72, 0x00); + /* Clock Pattern registers */ + reg_w_val(gspca_dev, ET_REG73, 0x00); + reg_w_val(gspca_dev, ET_REG74, 0x00); + reg_w_val(gspca_dev, ET_REG75, 0x0a); + reg_w_val(gspca_dev, ET_I2C_CLK, 0x04); + reg_w_val(gspca_dev, ET_PXL_CLK, 0x01); + /* set the sensor */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + I2c0[0] = 0x06; + i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1); + i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1); + value = 0x06; + i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1); + i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1); + /* value = 0x1f; */ + value = 0x04; + i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1); + } else { + I2c0[0] = 0x0a; + + i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1); + i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1); + value = 0x0a; + i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1); + i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1); + value = 0x04; + /* value = 0x10; */ + i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1); + /* bit 2 enable bit 1:2 select 0 1 2 3 + value = 0x07; * curve 0 * + i2c_w(gspca_dev, PAS106_REG0f, &value, 1, 1); + */ + } + +/* value = 0x01; */ +/* value = 0x22; */ +/* i2c_w(gspca_dev, PAS106_REG5, &value, 1, 1); */ + /* magnetude and sign bit for DAC */ + i2c_w(gspca_dev, PAS106_REG7, I2c4, sizeof I2c4, 1); + /* now set by fifo the whole colors setting */ + reg_w(gspca_dev, ET_G_RED, GainRGBG, 6); + getcolors(gspca_dev); + setcolors(gspca_dev); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + sd->sensor = id->driver_info; + if (sd->sensor == SENSOR_PAS106) { + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + } else { + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + gspca_dev->ctrl_dis = (1 << COLOR_IDX); + } + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->ag_cnt = -1; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) + Et_init1(gspca_dev); + else + Et_init2(gspca_dev); + reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); + et_video(gspca_dev, 0); /* video off */ + return 0; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) + Et_init1(gspca_dev); + else + Et_init2(gspca_dev); + + setautogain(gspca_dev); + + reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); + et_video(gspca_dev, 1); /* video on */ + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + et_video(gspca_dev, 0); /* video off */ +} + +static __u8 Et_getgainG(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) { + i2c_r(gspca_dev, PAS106_REG0e); + PDEBUG(D_CONF, "Etoms gain G %d", gspca_dev->usb_buf[0]); + return gspca_dev->usb_buf[0]; + } + return 0x1f; +} + +static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAS106) { + __u8 i2cflags = 0x01; + + i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3); + i2c_w(gspca_dev, PAS106_REG0e, &gain, 1, 1); + } +} + +#define BLIMIT(bright) \ + (u8)((bright > 0x1f) ? 0x1f : ((bright < 4) ? 3 : bright)) +#define LIMIT(color) \ + (u8)((color > 0xff) ? 0xff : ((color < 0) ? 0 : color)) + +static void do_autogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 luma; + __u8 luma_mean = 128; + __u8 luma_delta = 20; + __u8 spring = 4; + int Gbright; + __u8 r, g, b; + + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt >= 0) + return; + sd->ag_cnt = AG_CNT_START; + + Gbright = Et_getgainG(gspca_dev); + reg_r(gspca_dev, ET_LUMA_CENTER, 4); + g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1; + r = gspca_dev->usb_buf[1]; + b = gspca_dev->usb_buf[2]; + r = ((r << 8) - (r << 4) - (r << 3)) >> 10; + b = ((b << 7) >> 10); + g = ((g << 9) + (g << 7) + (g << 5)) >> 10; + luma = LIMIT(r + g + b); + PDEBUG(D_FRAM, "Etoms luma G %d", luma); + if (luma < luma_mean - luma_delta || luma > luma_mean + luma_delta) { + Gbright += (luma_mean - luma) >> spring; + Gbright = BLIMIT(Gbright); + PDEBUG(D_FRAM, "Etoms Gbright %d", Gbright); + Et_setgainG(gspca_dev, (__u8) Gbright); + } +} + +#undef BLIMIT +#undef LIMIT + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + int seqframe; + + seqframe = data[0] & 0x3f; + len = (int) (((data[0] & 0xc0) << 2) | data[1]); + if (seqframe == 0x3f) { + PDEBUG(D_FRAM, + "header packet found datalength %d !!", len); + PDEBUG(D_FRAM, "G %d R %d G %d B %d", + data[2], data[3], data[4], data[5]); + data += 30; + /* don't change datalength as the chips provided it */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + return; + } + if (len) { + data += 8; + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + } else { /* Drop Packet */ + gspca_dev->last_packet_type = DISCARD_PACKET; + } +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (gspca_dev->streaming) + setautogain(gspca_dev); + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, +#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE + {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, +#endif + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/finepix.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/finepix.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/finepix.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/finepix.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,303 @@ +/* + * Fujifilm Finepix subdriver + * + * Copyright (C) 2008 Frank Zago + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "finepix" + +#include "gspca.h" + +MODULE_AUTHOR("Frank Zago "); +MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver"); +MODULE_LICENSE("GPL"); + +/* Default timeout, in ms */ +#define FPIX_TIMEOUT 250 + +/* Maximum transfer size to use. The windows driver reads by chunks of + * 0x2000 bytes, so do the same. Note: reading more seems to work + * too. */ +#define FPIX_MAX_TRANSFER 0x2000 + +/* Structure to hold all of our device specific stuff */ +struct usb_fpix { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct work_struct work_struct; + struct workqueue_struct *work_thread; +}; + +/* Delay after which claim the next frame. If the delay is too small, + * the camera will return old frames. On the 4800Z, 20ms is bad, 25ms + * will fail every 4 or 5 frames, but 30ms is perfect. On the A210, + * 30ms is bad while 35ms is perfect. */ +#define NEXT_FRAME_DELAY 35 + +/* These cameras only support 320x200. */ +static const struct v4l2_pix_format fpix_mode[1] = { + { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0} +}; + +/* send a command to the webcam */ +static int command(struct gspca_dev *gspca_dev, + int order) /* 0: reset, 1: frame request */ +{ + static u8 order_values[2][12] = { + {0xc6, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0}, /* reset */ + {0xd3, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0}, /* fr req */ + }; + + memcpy(gspca_dev->usb_buf, order_values[order], 12); + return usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + USB_REQ_GET_STATUS, + USB_DIR_OUT | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf, + 12, FPIX_TIMEOUT); +} + +/* workqueue */ +static void dostream(struct work_struct *work) +{ + struct usb_fpix *dev = container_of(work, struct usb_fpix, work_struct); + struct gspca_dev *gspca_dev = &dev->gspca_dev; + struct urb *urb = gspca_dev->urb[0]; + u8 *data = urb->transfer_buffer; + int ret = 0; + int len; + + /* synchronize with the main driver */ + mutex_lock(&gspca_dev->usb_lock); + mutex_unlock(&gspca_dev->usb_lock); + PDEBUG(D_STREAM, "dostream started"); + + /* loop reading a frame */ +again: + while (gspca_dev->present && gspca_dev->streaming) { + + /* request a frame */ + mutex_lock(&gspca_dev->usb_lock); + ret = command(gspca_dev, 1); + mutex_unlock(&gspca_dev->usb_lock); + if (ret < 0) + break; + if (!gspca_dev->present || !gspca_dev->streaming) + break; + + /* the frame comes in parts */ + for (;;) { + ret = usb_bulk_msg(gspca_dev->dev, + urb->pipe, + data, + FPIX_MAX_TRANSFER, + &len, FPIX_TIMEOUT); + if (ret < 0) { + /* Most of the time we get a timeout + * error. Just restart. */ + goto again; + } + if (!gspca_dev->present || !gspca_dev->streaming) + goto out; + if (len < FPIX_MAX_TRANSFER || + (data[len - 2] == 0xff && + data[len - 1] == 0xd9)) { + + /* If the result is less than what was asked + * for, then it's the end of the + * frame. Sometimes the jpeg is not complete, + * but there's nothing we can do. We also end + * here if the the jpeg ends right at the end + * of the frame. */ + gspca_frame_add(gspca_dev, LAST_PACKET, + data, len); + break; + } + + /* got a partial image */ + gspca_frame_add(gspca_dev, + gspca_dev->last_packet_type + == LAST_PACKET + ? FIRST_PACKET : INTER_PACKET, + data, len); + } + + /* We must wait before trying reading the next + * frame. If we don't, or if the delay is too short, + * the camera will disconnect. */ + msleep(NEXT_FRAME_DELAY); + } + +out: + PDEBUG(D_STREAM, "dostream stopped"); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + + cam->cam_mode = fpix_mode; + cam->nmodes = 1; + cam->bulk = 1; + cam->bulk_size = FPIX_MAX_TRANSFER; + + INIT_WORK(&dev->work_struct, dostream); + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +/* start the camera */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; + int ret, len; + + /* Init the device */ + ret = command(gspca_dev, 0); + if (ret < 0) { + err("init failed %d", ret); + return ret; + } + + /* Read the result of the command. Ignore the result, for it + * varies with the device. */ + ret = usb_bulk_msg(gspca_dev->dev, + gspca_dev->urb[0]->pipe, + gspca_dev->urb[0]->transfer_buffer, + FPIX_MAX_TRANSFER, &len, + FPIX_TIMEOUT); + if (ret < 0) { + err("usb_bulk_msg failed %d", ret); + return ret; + } + + /* Request a frame, but don't read it */ + ret = command(gspca_dev, 1); + if (ret < 0) { + err("frame request failed %d", ret); + return ret; + } + + /* Again, reset bulk in endpoint */ + usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe); + + /* Start the workqueue function to do the streaming */ + dev->work_thread = create_singlethread_workqueue(MODULE_NAME); + queue_work(dev->work_thread, &dev->work_struct); + + return 0; +} + +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; + + /* wait for the work queue to terminate */ + mutex_unlock(&gspca_dev->usb_lock); + destroy_workqueue(dev->work_thread); + mutex_lock(&gspca_dev->usb_lock); + dev->work_thread = NULL; +} + +/* Table of supported USB devices */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x04cb, 0x0104)}, + {USB_DEVICE(0x04cb, 0x0109)}, + {USB_DEVICE(0x04cb, 0x010b)}, + {USB_DEVICE(0x04cb, 0x010f)}, + {USB_DEVICE(0x04cb, 0x0111)}, + {USB_DEVICE(0x04cb, 0x0113)}, + {USB_DEVICE(0x04cb, 0x0115)}, + {USB_DEVICE(0x04cb, 0x0117)}, + {USB_DEVICE(0x04cb, 0x0119)}, + {USB_DEVICE(0x04cb, 0x011b)}, + {USB_DEVICE(0x04cb, 0x011d)}, + {USB_DEVICE(0x04cb, 0x0121)}, + {USB_DEVICE(0x04cb, 0x0123)}, + {USB_DEVICE(0x04cb, 0x0125)}, + {USB_DEVICE(0x04cb, 0x0127)}, + {USB_DEVICE(0x04cb, 0x0129)}, + {USB_DEVICE(0x04cb, 0x012b)}, + {USB_DEVICE(0x04cb, 0x012d)}, + {USB_DEVICE(0x04cb, 0x012f)}, + {USB_DEVICE(0x04cb, 0x0131)}, + {USB_DEVICE(0x04cb, 0x013b)}, + {USB_DEVICE(0x04cb, 0x013d)}, + {USB_DEVICE(0x04cb, 0x013f)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, +}; + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + &sd_desc, + sizeof(struct usb_fpix), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,735 @@ +/* GSPCA subdrivers for Genesys Logic webcams with the GL860 chip + * Subdriver core + * + * 2009/09/24 Olivier Lorin + * GSPCA by Jean-Francois Moine + * Thanks BUGabundo and Malmostoso for your amazing help! + * + * 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, or + * any later version. + * + * 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, see . + */ +#include "gspca.h" +#include "gl860.h" + +MODULE_AUTHOR("Olivier Lorin "); +MODULE_DESCRIPTION("Genesys Logic USB PC Camera Driver"); +MODULE_LICENSE("GPL"); + +/*======================== static function declarations ====================*/ + +static void (*dev_init_settings)(struct gspca_dev *gspca_dev); + +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id); +static int sd_init(struct gspca_dev *gspca_dev); +static int sd_isoc_init(struct gspca_dev *gspca_dev); +static int sd_start(struct gspca_dev *gspca_dev); +static void sd_stop0(struct gspca_dev *gspca_dev); +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, int len); +static void sd_callback(struct gspca_dev *gspca_dev); + +static int gl860_guess_sensor(struct gspca_dev *gspca_dev, + u16 vendor_id, u16 product_id); + +/*============================ driver options ==============================*/ + +static s32 AC50Hz = 0xff; +module_param(AC50Hz, int, 0644); +MODULE_PARM_DESC(AC50Hz, " Does AC power frequency is 50Hz? (0/1)"); + +static char sensor[7]; +module_param_string(sensor, sensor, sizeof(sensor), 0644); +MODULE_PARM_DESC(sensor, + " Driver sensor ('MI1320'/'MI2020'/'OV9655'/'OV2640')"); + +/*============================ webcam controls =============================*/ + +/* Functions to get and set a control value */ +#define SD_SETGET(thename) \ +static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\ +{\ + struct sd *sd = (struct sd *) gspca_dev;\ +\ + sd->vcur.thename = val;\ + if (gspca_dev->streaming)\ + sd->waitSet = 1;\ + return 0;\ +} \ +static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\ +{\ + struct sd *sd = (struct sd *) gspca_dev;\ +\ + *val = sd->vcur.thename;\ + return 0;\ +} + +SD_SETGET(mirror) +SD_SETGET(flip) +SD_SETGET(AC50Hz) +SD_SETGET(backlight) +SD_SETGET(brightness) +SD_SETGET(gamma) +SD_SETGET(hue) +SD_SETGET(saturation) +SD_SETGET(sharpness) +SD_SETGET(whitebal) +SD_SETGET(contrast) + +#define GL860_NCTRLS 11 + +/* control table */ +static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS]; +static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS]; +static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS]; +static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS]; + +#define SET_MY_CTRL(theid, \ + thetype, thelabel, thename) \ + if (sd->vmax.thename != 0) {\ + sd_ctrls[nCtrls].qctrl.id = theid;\ + sd_ctrls[nCtrls].qctrl.type = thetype;\ + strcpy(sd_ctrls[nCtrls].qctrl.name, thelabel);\ + sd_ctrls[nCtrls].qctrl.minimum = 0;\ + sd_ctrls[nCtrls].qctrl.maximum = sd->vmax.thename;\ + sd_ctrls[nCtrls].qctrl.default_value = sd->vcur.thename;\ + sd_ctrls[nCtrls].qctrl.step = \ + (sd->vmax.thename < 16) ? 1 : sd->vmax.thename/16;\ + sd_ctrls[nCtrls].set = sd_set_##thename;\ + sd_ctrls[nCtrls].get = sd_get_##thename;\ + nCtrls++;\ + } + +static int gl860_build_control_table(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct ctrl *sd_ctrls; + int nCtrls = 0; + + if (_MI1320_) + sd_ctrls = sd_ctrls_mi1320; + else if (_MI2020_) + sd_ctrls = sd_ctrls_mi2020; + else if (_OV2640_) + sd_ctrls = sd_ctrls_ov2640; + else if (_OV9655_) + sd_ctrls = sd_ctrls_ov9655; + else + return 0; + + memset(sd_ctrls, 0, GL860_NCTRLS * sizeof(struct ctrl)); + + SET_MY_CTRL(V4L2_CID_BRIGHTNESS, + V4L2_CTRL_TYPE_INTEGER, "Brightness", brightness) + SET_MY_CTRL(V4L2_CID_SHARPNESS, + V4L2_CTRL_TYPE_INTEGER, "Sharpness", sharpness) + SET_MY_CTRL(V4L2_CID_CONTRAST, + V4L2_CTRL_TYPE_INTEGER, "Contrast", contrast) + SET_MY_CTRL(V4L2_CID_GAMMA, + V4L2_CTRL_TYPE_INTEGER, "Gamma", gamma) + SET_MY_CTRL(V4L2_CID_HUE, + V4L2_CTRL_TYPE_INTEGER, "Palette", hue) + SET_MY_CTRL(V4L2_CID_SATURATION, + V4L2_CTRL_TYPE_INTEGER, "Saturation", saturation) + SET_MY_CTRL(V4L2_CID_WHITE_BALANCE_TEMPERATURE, + V4L2_CTRL_TYPE_INTEGER, "White Bal.", whitebal) + SET_MY_CTRL(V4L2_CID_BACKLIGHT_COMPENSATION, + V4L2_CTRL_TYPE_INTEGER, "Backlight" , backlight) + + SET_MY_CTRL(V4L2_CID_HFLIP, + V4L2_CTRL_TYPE_BOOLEAN, "Mirror", mirror) + SET_MY_CTRL(V4L2_CID_VFLIP, + V4L2_CTRL_TYPE_BOOLEAN, "Flip", flip) + SET_MY_CTRL(V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CTRL_TYPE_BOOLEAN, "AC power 50Hz", AC50Hz) + + return nCtrls; +} + +/*==================== sud-driver structure initialisation =================*/ + +static const struct sd_desc sd_desc_mi1320 = { + .name = MODULE_NAME, + .ctrls = sd_ctrls_mi1320, + .nctrls = GL860_NCTRLS, + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = sd_callback, +}; + +static const struct sd_desc sd_desc_mi2020 = { + .name = MODULE_NAME, + .ctrls = sd_ctrls_mi2020, + .nctrls = GL860_NCTRLS, + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = sd_callback, +}; + +static const struct sd_desc sd_desc_ov2640 = { + .name = MODULE_NAME, + .ctrls = sd_ctrls_ov2640, + .nctrls = GL860_NCTRLS, + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = sd_callback, +}; + +static const struct sd_desc sd_desc_ov9655 = { + .name = MODULE_NAME, + .ctrls = sd_ctrls_ov9655, + .nctrls = GL860_NCTRLS, + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = sd_callback, +}; + +/*=========================== sub-driver image sizes =======================*/ + +static struct v4l2_pix_format mi2020_mode[] = { + { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + }, + { 800, 598, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 598, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + }, + {1280, 1024, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 + }, + {1600, 1198, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 1600, + .sizeimage = 1600 * 1198, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3 + }, +}; + +static struct v4l2_pix_format ov2640_mode[] = { + { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + }, + { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 600, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + }, + {1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 960, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 + }, + {1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 1600, + .sizeimage = 1600 * 1200, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3 + }, +}; + +static struct v4l2_pix_format mi1320_mode[] = { + { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + }, + { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 600, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + }, + {1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 960, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 + }, +}; + +static struct v4l2_pix_format ov9655_mode[] = { + { 640, 480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + }, + {1280, 960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 960, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + }, +}; + +/*========================= sud-driver functions ===========================*/ + +/* This function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + u16 vendor_id, product_id; + + /* Get USB VendorID and ProductID */ + vendor_id = id->idVendor; + product_id = id->idProduct; + + sd->nbRightUp = 1; + sd->nbIm = -1; + + sd->sensor = 0xff; + if (strcmp(sensor, "MI1320") == 0) + sd->sensor = ID_MI1320; + else if (strcmp(sensor, "OV2640") == 0) + sd->sensor = ID_OV2640; + else if (strcmp(sensor, "OV9655") == 0) + sd->sensor = ID_OV9655; + else if (strcmp(sensor, "MI2020") == 0) + sd->sensor = ID_MI2020; + + /* Get sensor and set the suitable init/start/../stop functions */ + if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1) + return -1; + + cam = &gspca_dev->cam; + gspca_dev->nbalt = 4; + + switch (sd->sensor) { + case ID_MI1320: + gspca_dev->sd_desc = &sd_desc_mi1320; + cam->cam_mode = mi1320_mode; + cam->nmodes = ARRAY_SIZE(mi1320_mode); + dev_init_settings = mi1320_init_settings; + break; + + case ID_MI2020: + gspca_dev->sd_desc = &sd_desc_mi2020; + cam->cam_mode = mi2020_mode; + cam->nmodes = ARRAY_SIZE(mi2020_mode); + dev_init_settings = mi2020_init_settings; + break; + + case ID_OV2640: + gspca_dev->sd_desc = &sd_desc_ov2640; + cam->cam_mode = ov2640_mode; + cam->nmodes = ARRAY_SIZE(ov2640_mode); + dev_init_settings = ov2640_init_settings; + break; + + case ID_OV9655: + gspca_dev->sd_desc = &sd_desc_ov9655; + cam->cam_mode = ov9655_mode; + cam->nmodes = ARRAY_SIZE(ov9655_mode); + dev_init_settings = ov9655_init_settings; + break; + } + + dev_init_settings(gspca_dev); + if (AC50Hz != 0xff) + ((struct sd *) gspca_dev)->vcur.AC50Hz = AC50Hz; + gl860_build_control_table(gspca_dev); + + return 0; +} + +/* This function is called at probe time after sd_config */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return sd->dev_init_at_startup(gspca_dev); +} + +/* This function is called before to choose the alt setting */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return sd->dev_configure_alt(gspca_dev); +} + +/* This function is called to start the webcam */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return sd->dev_init_pre_alt(gspca_dev); +} + +/* This function is called to stop the webcam */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + return sd->dev_post_unset_alt(gspca_dev); +} + +/* This function is called when an image is being received */ +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + static s32 nSkipped; + + s32 mode = (s32) gspca_dev->curr_mode; + s32 nToSkip = + sd->swapRB * (gspca_dev->cam.cam_mode[mode].bytesperline + 1); + + /* Test only against 0202h, so endianess does not matter */ + switch (*(s16 *) data) { + case 0x0202: /* End of frame, start a new one */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + nSkipped = 0; + if (sd->nbIm >= 0 && sd->nbIm < 10) + sd->nbIm++; + gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); + break; + + default: + data += 2; + len -= 2; + if (nSkipped + len <= nToSkip) + nSkipped += len; + else { + if (nSkipped < nToSkip && nSkipped + len > nToSkip) { + data += nToSkip - nSkipped; + len -= nToSkip - nSkipped; + nSkipped = nToSkip + 1; + } + gspca_frame_add(gspca_dev, + INTER_PACKET, data, len); + } + break; + } +} + +/* This function is called when an image has been read */ +/* This function is used to monitor webcam orientation */ +static void sd_callback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!_OV9655_) { + u8 state; + u8 upsideDown; + + /* Probe sensor orientation */ + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, (void *)&state); + + /* C8/40 means upside-down (looking backwards) */ + /* D8/50 means right-up (looking onwards) */ + upsideDown = (state == 0xc8 || state == 0x40); + + if (upsideDown && sd->nbRightUp > -4) { + if (sd->nbRightUp > 0) + sd->nbRightUp = 0; + if (sd->nbRightUp == -3) { + sd->mirrorMask = 1; + sd->waitSet = 1; + } + sd->nbRightUp--; + } + if (!upsideDown && sd->nbRightUp < 4) { + if (sd->nbRightUp < 0) + sd->nbRightUp = 0; + if (sd->nbRightUp == 3) { + sd->mirrorMask = 0; + sd->waitSet = 1; + } + sd->nbRightUp++; + } + } + + if (sd->waitSet) + sd->dev_camera_settings(gspca_dev); +} + +/*=================== USB driver structure initialisation ==================*/ + +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x05e3, 0x0503)}, + {USB_DEVICE(0x05e3, 0xf191)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + &sd_desc_mi1320, sizeof(struct sd), THIS_MODULE); +} + +static void sd_disconnect(struct usb_interface *intf) +{ + gspca_disconnect(intf); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = sd_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/*====================== Init and Exit module functions ====================*/ + +static int __init sd_mod_init(void) +{ + PDEBUG(D_PROBE, "driver startup - version %s", DRIVER_VERSION); + + if (usb_register(&sd_driver) < 0) + return -1; + return 0; +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +/*==========================================================================*/ + +int gl860_RTx(struct gspca_dev *gspca_dev, + unsigned char pref, u32 req, u16 val, u16 index, + s32 len, void *pdata) +{ + struct usb_device *udev = gspca_dev->dev; + s32 r = 0; + + if (pref == 0x40) { /* Send */ + if (len > 0) { + memcpy(gspca_dev->usb_buf, pdata, len); + r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + req, pref, val, index, + gspca_dev->usb_buf, + len, 400 + 200 * (len > 1)); + } else { + r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + req, pref, val, index, NULL, len, 400); + } + } else { /* Receive */ + if (len > 0) { + r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + req, pref, val, index, + gspca_dev->usb_buf, + len, 400 + 200 * (len > 1)); + memcpy(pdata, gspca_dev->usb_buf, len); + } else { + r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + req, pref, val, index, NULL, len, 400); + } + } + + if (r < 0) + err("ctrl transfer failed %4d " + "[p%02x r%d v%04x i%04x len%d]", + r, pref, req, val, index, len); + else if (len > 1 && r < len) + PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len); + + msleep(1); + + return r; +} + +int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len) +{ + int n; + + for (n = 0; n < len; n++) { + if (tbl[n].idx != 0xffff) + ctrl_out(gspca_dev, 0x40, 1, tbl[n].val, + tbl[n].idx, 0, NULL); + else if (tbl[n].val == 0xffff) + break; + else + msleep(tbl[n].val); + } + return n; +} + +int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl, + int len, int n) +{ + while (++n < len) { + if (tbl[n].idx != 0xffff) + ctrl_out(gspca_dev, 0x40, 1, tbl[n].val, tbl[n].idx, + 0, NULL); + else if (tbl[n].val == 0xffff) + break; + else + msleep(tbl[n].val); + } + return n; +} + +void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len) +{ + int n; + + for (n = 0; n < len; n++) { + if (memcmp(tbl[n].data, "\xff\xff\xff", 3) != 0) + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, tbl[n].idx, + 3, tbl[n].data); + else + msleep(tbl[n].idx); + } +} + +static int gl860_guess_sensor(struct gspca_dev *gspca_dev, + u16 vendor_id, u16 product_id) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 probe, nb26, nb96, nOV, ntry; + + if (product_id == 0xf191) + sd->sensor = ID_MI1320; + + if (sd->sensor == 0xff) { + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe); + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe); + + ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x0000, 0, NULL); + msleep(3); + ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); + msleep(3); + ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x00c0, 0, NULL); + msleep(3); + ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c1, 0, NULL); + msleep(3); + ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c2, 0, NULL); + msleep(3); + ctrl_out(gspca_dev, 0x40, 1, 0x0020, 0x0006, 0, NULL); + msleep(3); + ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL); + msleep(56); + + PDEBUG(D_PROBE, "probing for sensor MI2020 or OVXXXX"); + nOV = 0; + for (ntry = 0; ntry < 4; ntry++) { + ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); + msleep(3); + ctrl_out(gspca_dev, 0x40, 1, 0x0063, 0x0006, 0, NULL); + msleep(3); + ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL); + msleep(10); + ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &probe); + PDEBUG(D_PROBE, "probe=0x%02x", probe); + if (probe == 0xff) + nOV++; + } + + if (nOV) { + PDEBUG(D_PROBE, "0xff -> OVXXXX"); + PDEBUG(D_PROBE, "probing for sensor OV2640 or OV9655"); + + nb26 = nb96 = 0; + for (ntry = 0; ntry < 4; ntry++) { + ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, + 0, NULL); + msleep(3); + ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x800a, + 0, NULL); + msleep(10); + + /* Wait for 26(OV2640) or 96(OV9655) */ + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x800a, + 1, &probe); + + if (probe == 0x26 || probe == 0x40) { + PDEBUG(D_PROBE, + "probe=0x%02x -> OV2640", + probe); + sd->sensor = ID_OV2640; + nb26 += 4; + break; + } + if (probe == 0x96 || probe == 0x55) { + PDEBUG(D_PROBE, + "probe=0x%02x -> OV9655", + probe); + sd->sensor = ID_OV9655; + nb96 += 4; + break; + } + PDEBUG(D_PROBE, "probe=0x%02x", probe); + if (probe == 0x00) + nb26++; + if (probe == 0xff) + nb96++; + msleep(3); + } + if (nb26 < 4 && nb96 < 4) + return -1; + } else { + PDEBUG(D_PROBE, "Not any 0xff -> MI2020"); + sd->sensor = ID_MI2020; + } + } + + if (_MI1320_) { + PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)"); + } else if (_MI2020_) { + PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)"); + } else if (_OV9655_) { + PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)"); + } else if (_OV2640_) { + PDEBUG(D_PROBE, "05e3:0503 sensor OV2640 (2.0M)"); + } else { + PDEBUG(D_PROBE, "***** Unknown sensor *****"); + return -1; + } + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,106 @@ +/* GSPCA subdrivers for Genesys Logic webcams with the GL860 chip + * Subdriver declarations + * + * 2009/10/14 Olivier LORIN + * + * 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, or + * any later version. + * + * 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, see . + */ +#ifndef GL860_DEV_H +#define GL860_DEV_H +#include + +#include "gspca.h" + +#define MODULE_NAME "gspca_gl860" +#define DRIVER_VERSION "0.9d10" + +#define ctrl_in gl860_RTx +#define ctrl_out gl860_RTx + +#define ID_MI1320 1 +#define ID_OV2640 2 +#define ID_OV9655 4 +#define ID_MI2020 8 + +#define _MI1320_ (((struct sd *) gspca_dev)->sensor == ID_MI1320) +#define _MI2020_ (((struct sd *) gspca_dev)->sensor == ID_MI2020) +#define _OV2640_ (((struct sd *) gspca_dev)->sensor == ID_OV2640) +#define _OV9655_ (((struct sd *) gspca_dev)->sensor == ID_OV9655) + +#define IMAGE_640 0 +#define IMAGE_800 1 +#define IMAGE_1280 2 +#define IMAGE_1600 3 + +struct sd_gl860 { + u16 backlight; + u16 brightness; + u16 sharpness; + u16 contrast; + u16 gamma; + u16 hue; + u16 saturation; + u16 whitebal; + u8 mirror; + u8 flip; + u8 AC50Hz; +}; + +/* Specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct sd_gl860 vcur; + struct sd_gl860 vold; + struct sd_gl860 vmax; + + int (*dev_configure_alt) (struct gspca_dev *); + int (*dev_init_at_startup)(struct gspca_dev *); + int (*dev_init_pre_alt) (struct gspca_dev *); + void (*dev_post_unset_alt) (struct gspca_dev *); + int (*dev_camera_settings)(struct gspca_dev *); + + u8 swapRB; + u8 mirrorMask; + u8 sensor; + s32 nbIm; + s32 nbRightUp; + u8 waitSet; +}; + +struct validx { + u16 val; + u16 idx; +}; + +struct idxdata { + u8 idx; + u8 data[3]; +}; + +int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len); +int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl, + int len, int n); +void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len); + +int gl860_RTx(struct gspca_dev *gspca_dev, + unsigned char pref, u32 req, u16 val, u16 index, + s32 len, void *pdata); + +void mi1320_init_settings(struct gspca_dev *); +void ov2640_init_settings(struct gspca_dev *); +void ov9655_init_settings(struct gspca_dev *); +void mi2020_init_settings(struct gspca_dev *); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-mi1320.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-mi1320.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-mi1320.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-mi1320.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,536 @@ +/* Subdriver for the GL860 chip with the MI1320 sensor + * Author Olivier LORIN from own logs + * + * 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, or + * any later version. + * + * 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, see . + */ + +/* Sensor : MI1320 */ + +#include "gl860.h" + +static struct validx tbl_common[] = { + {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba51, 0x0066}, {0xba02, 0x00f1}, + {0xba05, 0x0067}, {0xba05, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1}, + {0xffff, 0xffff}, + {0xba00, 0x00f0}, {0xba02, 0x00f1}, {0xbafa, 0x0028}, {0xba02, 0x00f1}, + {0xba00, 0x00f0}, {0xba01, 0x00f1}, {0xbaf0, 0x0006}, {0xba0e, 0x00f1}, + {0xba70, 0x0006}, {0xba0e, 0x00f1}, + {0xffff, 0xffff}, + {0xba74, 0x0006}, {0xba0e, 0x00f1}, + {0xffff, 0xffff}, + {0x0061, 0x0000}, {0x0068, 0x000d}, +}; + +static struct validx tbl_init_at_startup[] = { + {0x0000, 0x0000}, {0x0010, 0x0010}, + {35, 0xffff}, + {0x0008, 0x00c0}, {0x0001, 0x00c1}, {0x0001, 0x00c2}, {0x0020, 0x0006}, + {0x006a, 0x000d}, +}; + +static struct validx tbl_sensor_settings_common[] = { + {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0040, 0x0000}, + {0x006a, 0x0007}, {0x006a, 0x000d}, {0x0063, 0x0006}, +}; +static struct validx tbl_sensor_settings_1280[] = { + {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1}, + {0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1}, +}; +static struct validx tbl_sensor_settings_800[] = { + {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xba5a, 0x0066}, {0xba02, 0x00f1}, + {0xba05, 0x0067}, {0xba05, 0x00f1}, {0xba20, 0x0065}, {0xba00, 0x00f1}, +}; +static struct validx tbl_sensor_settings_640[] = { + {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1}, + {0xba51, 0x0066}, {0xba02, 0x00f1}, {0xba05, 0x0067}, {0xba05, 0x00f1}, + {0xba20, 0x0065}, {0xba00, 0x00f1}, +}; +static struct validx tbl_post_unset_alt[] = { + {0xba00, 0x00f0}, {0xba00, 0x00f1}, {0xbaa0, 0x0065}, {0xba00, 0x00f1}, + {0x0061, 0x0000}, {0x0068, 0x000d}, +}; + +static u8 *tbl_1280[] = { + "\x0d\x80\xf1\x08\x03\x04\xf1\x00" "\x04\x05\xf1\x02\x05\x00\xf1\xf1" + "\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08" + "\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00" + "\xa9\x04\xf1\x00\xa1\x05\xf1\x00" "\xa4\x04\xf1\x00\xae\x0a\xf1\x08" + , + "\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47" + "\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c" + "\xd2\x00\xf1\xcf\xcb\x00\xf1\x01" + , + "\xd3\x02\xd4\x28\xd5\x01\xd0\x02" "\xd1\x18\xd2\xc1" +}; + +static u8 *tbl_800[] = { + "\x0d\x80\xf1\x08\x03\x03\xf1\xc0" "\x04\x05\xf1\x02\x05\x00\xf1\xf1" + "\x06\x00\xf1\x0d\x20\x01\xf1\x00" "\x21\x84\xf1\x00\x0d\x00\xf1\x08" + "\xf0\x00\xf1\x01\x34\x00\xf1\x00" "\x9b\x43\xf1\x00\xa6\x05\xf1\x00" + "\xa9\x03\xf1\xc0\xa1\x03\xf1\x20" "\xa4\x02\xf1\x5a\xae\x0a\xf1\x08" + , + "\xf0\x00\xf1\x02\x3a\x05\xf1\xf1" "\x3c\x05\xf1\xf1\x59\x01\xf1\x47" + "\x5a\x01\xf1\x88\x5c\x0a\xf1\x06" "\x5d\x0e\xf1\x0a\x64\x5e\xf1\x1c" + "\xd2\x00\xf1\xcf\xcb\x00\xf1\x01" + , + "\xd3\x02\xd4\x18\xd5\x21\xd0\x02" "\xd1\x10\xd2\x59" +}; + +static u8 *tbl_640[] = { + "\x0d\x80\xf1\x08\x03\x04\xf1\x04" "\x04\x05\xf1\x02\x07\x01\xf1\x7c" + "\x08\x00\xf1\x0e\x21\x80\xf1\x00" "\x0d\x00\xf1\x08\xf0\x00\xf1\x01" + "\x34\x10\xf1\x10\x3a\x43\xf1\x00" "\xa6\x05\xf1\x02\xa9\x04\xf1\x04" + "\xa7\x02\xf1\x81\xaa\x01\xf1\xe2" "\xae\x0c\xf1\x09" + , + "\xf0\x00\xf1\x02\x39\x03\xf1\xfc" "\x3b\x04\xf1\x04\x57\x01\xf1\xb6" + "\x58\x02\xf1\x0d\x5c\x1f\xf1\x19" "\x5d\x24\xf1\x1e\x64\x5e\xf1\x1c" + "\xd2\x00\xf1\x00\xcb\x00\xf1\x01" + , + "\xd3\x02\xd4\x10\xd5\x81\xd0\x02" "\xd1\x08\xd2\xe1" +}; + +static s32 tbl_sat[] = {0x25, 0x1d, 0x15, 0x0d, 0x05, 0x4d, 0x55, 0x5d, 0x2d}; +static s32 tbl_bright[] = {0, 8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70}; +static s32 tbl_backlight[] = {0x0e, 0x06, 0x02}; + +static s32 tbl_cntr1[] = { + 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, 0xe0, 0xf0}; +static s32 tbl_cntr2[] = { + 0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40, 0x38, 0x30, 0x20, 0x10}; + +static u8 dat_wbalNL[] = + "\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x3b\x04\xf1\x2a\x47\x10\xf1\x10" + "\x9d\x3c\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\x91\xf1\x20" + "\x9c\x91\xf1\x20\x37\x03\xf1\x00" "\x9d\xc5\xf1\x0f\xf0\x00\xf1\x00"; + +static u8 dat_wbalLL[] = + "\xf0\x00\xf1\x01\x05\x00\xf1\x0c" "\x3b\x04\xf1\x2a\x47\x40\xf1\x40" + "\x9d\x20\xf1\xae\xaf\x10\xf1\x00" "\xf0\x00\xf1\x02\x2f\xd1\xf1\x00" + "\x9c\xd1\xf1\x00\x37\x03\xf1\x00" "\x9d\xc5\xf1\x3f\xf0\x00\xf1\x00"; + +static u8 dat_wbalBL[] = + "\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x47\x10\xf1\x30\x9d\x3c\xf1\xae" + "\xaf\x10\xf1\x00\xf0\x00\xf1\x02" "\x2f\x91\xf1\x20\x9c\x91\xf1\x20" + "\x37\x03\xf1\x00\x9d\xc5\xf1\x2f" "\xf0\x00\xf1\x00"; + +static u8 dat_hvflip1[] = {0xf0, 0x00, 0xf1, 0x00}; + +static u8 dat_common00[] = + "\x00\x01\x07\x6a\x06\x63\x0d\x6a" "\xc0\x00\x10\x10\xc1\x03\xc2\x42" + "\xd8\x04\x58\x00\x04\x02"; +static u8 dat_common01[] = + "\x0d\x00\xf1\x0b\x0d\x00\xf1\x08" "\x35\x00\xf1\x22\x68\x00\xf1\x5d" + "\xf0\x00\xf1\x01\x06\x70\xf1\x0e" "\xf0\x00\xf1\x02\xdd\x18\xf1\xe0"; +static u8 dat_common02[] = + "\x05\x01\xf1\x84\x06\x00\xf1\x44" "\x07\x00\xf1\xbe\x08\x00\xf1\x1e" + "\x20\x01\xf1\x03\x21\x84\xf1\x00" "\x22\x0d\xf1\x0f\x24\x80\xf1\x00" + "\x34\x18\xf1\x2d\x35\x00\xf1\x22" "\x43\x83\xf1\x83\x59\x00\xf1\xff"; +static u8 dat_common03[] = + "\xf0\x00\xf1\x02\x39\x06\xf1\x8c" "\x3a\x06\xf1\x8c\x3b\x03\xf1\xda" + "\x3c\x05\xf1\x30\x57\x01\xf1\x0c" "\x58\x01\xf1\x42\x59\x01\xf1\x0c" + "\x5a\x01\xf1\x42\x5c\x13\xf1\x0e" "\x5d\x17\xf1\x12\x64\x1e\xf1\x1c"; +static u8 dat_common04[] = + "\xf0\x00\xf1\x02\x24\x5f\xf1\x20" "\x28\xea\xf1\x02\x5f\x41\xf1\x43"; +static u8 dat_common05[] = + "\x02\x00\xf1\xee\x03\x29\xf1\x1a" "\x04\x02\xf1\xa4\x09\x00\xf1\x68" + "\x0a\x00\xf1\x2a\x0b\x00\xf1\x04" "\x0c\x00\xf1\x93\x0d\x00\xf1\x82" + "\x0e\x00\xf1\x40\x0f\x00\xf1\x5f" "\x10\x00\xf1\x4e\x11\x00\xf1\x5b"; +static u8 dat_common06[] = + "\x15\x00\xf1\xc9\x16\x00\xf1\x5e" "\x17\x00\xf1\x9d\x18\x00\xf1\x06" + "\x19\x00\xf1\x89\x1a\x00\xf1\x12" "\x1b\x00\xf1\xa1\x1c\x00\xf1\xe4" + "\x1d\x00\xf1\x7a\x1e\x00\xf1\x64" "\xf6\x00\xf1\x5f"; +static u8 dat_common07[] = + "\xf0\x00\xf1\x01\x53\x09\xf1\x03" "\x54\x3d\xf1\x1c\x55\x99\xf1\x72" + "\x56\xc1\xf1\xb1\x57\xd8\xf1\xce" "\x58\xe0\xf1\x00\xdc\x0a\xf1\x03" + "\xdd\x45\xf1\x20\xde\xae\xf1\x82" "\xdf\xdc\xf1\xc9\xe0\xf6\xf1\xea" + "\xe1\xff\xf1\x00"; +static u8 dat_common08[] = + "\xf0\x00\xf1\x01\x80\x00\xf1\x06" "\x81\xf6\xf1\x08\x82\xfb\xf1\xf7" + "\x83\x00\xf1\xfe\xb6\x07\xf1\x03" "\xb7\x18\xf1\x0c\x84\xfb\xf1\x06" + "\x85\xfb\xf1\xf9\x86\x00\xf1\xff" "\xb8\x07\xf1\x04\xb9\x16\xf1\x0a"; +static u8 dat_common09[] = + "\x87\xfa\xf1\x05\x88\xfc\xf1\xf9" "\x89\x00\xf1\xff\xba\x06\xf1\x03" + "\xbb\x17\xf1\x09\x8a\xe8\xf1\x14" "\x8b\xf7\xf1\xf0\x8c\xfd\xf1\xfa" + "\x8d\x00\xf1\x00\xbc\x05\xf1\x01" "\xbd\x0c\xf1\x08\xbe\x00\xf1\x14"; +static u8 dat_common10[] = + "\x8e\xea\xf1\x13\x8f\xf7\xf1\xf2" "\x90\xfd\xf1\xfa\x91\x00\xf1\x00" + "\xbf\x05\xf1\x01\xc0\x0a\xf1\x08" "\xc1\x00\xf1\x0c\x92\xed\xf1\x0f" + "\x93\xf9\xf1\xf4\x94\xfe\xf1\xfb" "\x95\x00\xf1\x00\xc2\x04\xf1\x01" + "\xc3\x0a\xf1\x07\xc4\x00\xf1\x10"; +static u8 dat_common11[] = + "\xf0\x00\xf1\x01\x05\x00\xf1\x06" "\x25\x00\xf1\x55\x34\x10\xf1\x10" + "\x35\xf0\xf1\x10\x3a\x02\xf1\x03" "\x3b\x04\xf1\x2a\x9b\x43\xf1\x00" + "\xa4\x03\xf1\xc0\xa7\x02\xf1\x81"; + +static int mi1320_init_at_startup(struct gspca_dev *gspca_dev); +static int mi1320_configure_alt(struct gspca_dev *gspca_dev); +static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev); +static int mi1320_init_post_alt(struct gspca_dev *gspca_dev); +static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev); +static int mi1320_sensor_settings(struct gspca_dev *gspca_dev); +static int mi1320_camera_settings(struct gspca_dev *gspca_dev); +/*==========================================================================*/ + +void mi1320_init_settings(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vcur.backlight = 0; + sd->vcur.brightness = 0; + sd->vcur.sharpness = 6; + sd->vcur.contrast = 10; + sd->vcur.gamma = 20; + sd->vcur.hue = 0; + sd->vcur.saturation = 6; + sd->vcur.whitebal = 0; + sd->vcur.mirror = 0; + sd->vcur.flip = 0; + sd->vcur.AC50Hz = 1; + + sd->vmax.backlight = 2; + sd->vmax.brightness = 8; + sd->vmax.sharpness = 7; + sd->vmax.contrast = 0; /* 10 but not working with this driver */ + sd->vmax.gamma = 40; + sd->vmax.hue = 5 + 1; + sd->vmax.saturation = 8; + sd->vmax.whitebal = 2; + sd->vmax.mirror = 1; + sd->vmax.flip = 1; + sd->vmax.AC50Hz = 1; + + sd->dev_camera_settings = mi1320_camera_settings; + sd->dev_init_at_startup = mi1320_init_at_startup; + sd->dev_configure_alt = mi1320_configure_alt; + sd->dev_init_pre_alt = mi1320_init_pre_alt; + sd->dev_post_unset_alt = mi1320_post_unset_alt; +} + +/*==========================================================================*/ + +static void common(struct gspca_dev *gspca_dev) +{ + s32 n; /* reserved for FETCH functions */ + + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 22, dat_common00); + ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 32, dat_common01); + n = fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common)); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common02); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common03); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 16, dat_common04); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common05); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 44, dat_common06); + keep_on_fetching_validx(gspca_dev, tbl_common, + ARRAY_SIZE(tbl_common), n); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 52, dat_common07); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common08); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 48, dat_common09); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 56, dat_common10); + keep_on_fetching_validx(gspca_dev, tbl_common, + ARRAY_SIZE(tbl_common), n); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, dat_common11); + keep_on_fetching_validx(gspca_dev, tbl_common, + ARRAY_SIZE(tbl_common), n); +} + +static int mi1320_init_at_startup(struct gspca_dev *gspca_dev) +{ + fetch_validx(gspca_dev, tbl_init_at_startup, + ARRAY_SIZE(tbl_init_at_startup)); + + common(gspca_dev); + +/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */ + + return 0; +} + +static int mi1320_init_pre_alt(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->mirrorMask = 0; + + sd->vold.backlight = -1; + sd->vold.brightness = -1; + sd->vold.sharpness = -1; + sd->vold.contrast = -1; + sd->vold.saturation = -1; + sd->vold.gamma = -1; + sd->vold.hue = -1; + sd->vold.whitebal = -1; + sd->vold.mirror = -1; + sd->vold.flip = -1; + sd->vold.AC50Hz = -1; + + common(gspca_dev); + + mi1320_sensor_settings(gspca_dev); + + mi1320_init_post_alt(gspca_dev); + + return 0; +} + +static int mi1320_init_post_alt(struct gspca_dev *gspca_dev) +{ + mi1320_camera_settings(gspca_dev); + + return 0; +} + +static int mi1320_sensor_settings(struct gspca_dev *gspca_dev) +{ + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; + + ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); + + fetch_validx(gspca_dev, tbl_sensor_settings_common, + ARRAY_SIZE(tbl_sensor_settings_common)); + + switch (reso) { + case IMAGE_1280: + fetch_validx(gspca_dev, tbl_sensor_settings_1280, + ARRAY_SIZE(tbl_sensor_settings_1280)); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_1280[0]); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_1280[1]); + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_1280[2]); + break; + + case IMAGE_800: + fetch_validx(gspca_dev, tbl_sensor_settings_800, + ARRAY_SIZE(tbl_sensor_settings_800)); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 64, tbl_800[0]); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_800[1]); + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_800[2]); + break; + + default: + fetch_validx(gspca_dev, tbl_sensor_settings_640, + ARRAY_SIZE(tbl_sensor_settings_640)); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 60, tbl_640[0]); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 40, tbl_640[1]); + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, tbl_640[2]); + break; + } + return 0; +} + +static int mi1320_configure_alt(struct gspca_dev *gspca_dev) +{ + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; + + switch (reso) { + case IMAGE_640: + gspca_dev->alt = 3 + 1; + break; + + case IMAGE_800: + case IMAGE_1280: + gspca_dev->alt = 1 + 1; + break; + } + return 0; +} + +static int mi1320_camera_settings(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + s32 backlight = sd->vcur.backlight; + s32 bright = sd->vcur.brightness; + s32 sharp = sd->vcur.sharpness; + s32 cntr = sd->vcur.contrast; + s32 gam = sd->vcur.gamma; + s32 hue = sd->vcur.hue; + s32 sat = sd->vcur.saturation; + s32 wbal = sd->vcur.whitebal; + s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); + s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); + s32 freq = (sd->vcur.AC50Hz > 0); + s32 i; + + if (freq != sd->vold.AC50Hz) { + sd->vold.AC50Hz = freq; + + freq = 2 * (freq == 0); + ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba02, 0x00f1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x005b, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba01 + freq, 0x00f1, 0, NULL); + } + + if (wbal != sd->vold.whitebal) { + sd->vold.whitebal = wbal; + if (wbal < 0 || wbal > sd->vmax.whitebal) + wbal = 0; + + for (i = 0; i < 2; i++) { + if (wbal == 0) { /* Normal light */ + ctrl_out(gspca_dev, 0x40, 1, + 0x0010, 0x0010, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, + 0x0003, 0x00c1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, + 0x0042, 0x00c2, 0, NULL); + ctrl_out(gspca_dev, 0x40, 3, + 0xba00, 0x0200, 48, dat_wbalNL); + } + + if (wbal == 1) { /* Low light */ + ctrl_out(gspca_dev, 0x40, 1, + 0x0010, 0x0010, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, + 0x0004, 0x00c1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, + 0x0043, 0x00c2, 0, NULL); + ctrl_out(gspca_dev, 0x40, 3, + 0xba00, 0x0200, 48, dat_wbalLL); + } + + if (wbal == 2) { /* Back light */ + ctrl_out(gspca_dev, 0x40, 1, + 0x0010, 0x0010, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, + 0x0003, 0x00c1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, + 0x0042, 0x00c2, 0, NULL); + ctrl_out(gspca_dev, 0x40, 3, + 0xba00, 0x0200, 44, dat_wbalBL); + } + } + } + + if (bright != sd->vold.brightness) { + sd->vold.brightness = bright; + if (bright < 0 || bright > sd->vmax.brightness) + bright = 0; + + bright = tbl_bright[bright]; + ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x0034, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 + bright, 0x00f1, 0, NULL); + } + + if (sat != sd->vold.saturation) { + sd->vold.saturation = sat; + if (sat < 0 || sat > sd->vmax.saturation) + sat = 0; + + sat = tbl_sat[sat]; + ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x0025, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sat, 0x00f1, 0, NULL); + } + + if (sharp != sd->vold.sharpness) { + sd->vold.sharpness = sharp; + if (sharp < 0 || sharp > sd->vmax.sharpness) + sharp = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 , 0x0005, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 + sharp, 0x00f1, 0, NULL); + } + + if (hue != sd->vold.hue) { + /* 0=normal 1=NB 2="sepia" 3=negative 4=other 5=other2 */ + if (hue < 0 || hue > sd->vmax.hue) + hue = 0; + if (hue == sd->vmax.hue) + sd->swapRB = 1; + else + sd->swapRB = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1, + 0, NULL); + } + + if (backlight != sd->vold.backlight) { + sd->vold.backlight = backlight; + if (backlight < 0 || backlight > sd->vmax.backlight) + backlight = 0; + + backlight = tbl_backlight[backlight]; + for (i = 0; i < 2; i++) { + ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba74, 0x0006, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba80 + backlight, 0x00f1, + 0, NULL); + } + } + + if (hue != sd->vold.hue) { + sd->vold.hue = hue; + + ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba70, 0x00e2, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 + hue * (hue < 6), 0x00f1, + 0, NULL); + } + + if (mirror != sd->vold.mirror || flip != sd->vold.flip) { + u8 dat_hvflip2[4] = {0x20, 0x01, 0xf1, 0x00}; + sd->vold.mirror = mirror; + sd->vold.flip = flip; + + dat_hvflip2[3] = flip + 2 * mirror; + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip1); + ctrl_out(gspca_dev, 0x40, 3, 0xba00, 0x0200, 4, dat_hvflip2); + } + + if (gam != sd->vold.gamma) { + sd->vold.gamma = gam; + if (gam < 0 || gam > sd->vmax.gamma) + gam = 0; + + gam = 2 * gam; + ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba04 , 0x003b, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba02 + gam, 0x00f1, 0, NULL); + } + + if (cntr != sd->vold.contrast) { + sd->vold.contrast = cntr; + if (cntr < 0 || cntr > sd->vmax.contrast) + cntr = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0xba00, 0x00f0, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba01, 0x00f1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr1[cntr], 0x0035, + 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0xba00 + tbl_cntr2[cntr], 0x00f1, + 0, NULL); + } + + return 0; +} + +static void mi1320_post_unset_alt(struct gspca_dev *gspca_dev) +{ + ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); + + fetch_validx(gspca_dev, tbl_post_unset_alt, + ARRAY_SIZE(tbl_post_unset_alt)); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-mi2020.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-mi2020.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-mi2020.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-mi2020.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,733 @@ +/* Subdriver for the GL860 chip with the MI2020 sensor + * Author Olivier LORIN, from logs by Iceman/Soro2005 + Fret_saw/Hulkie/Tricid + * with the help of Kytrix/BUGabundo/Blazercist. + * Driver achieved thanks to a webcam gift by Kytrix. + * + * 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, or + * any later version. + * + * 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, see . + */ + +/* Sensor : MI2020 */ + +#include "gl860.h" + +static u8 dat_wbal1[] = {0x8c, 0xa2, 0x0c}; + +static u8 dat_bright1[] = {0x8c, 0xa2, 0x06}; +static u8 dat_bright3[] = {0x8c, 0xa1, 0x02}; +static u8 dat_bright4[] = {0x90, 0x00, 0x0f}; +static u8 dat_bright5[] = {0x8c, 0xa1, 0x03}; +static u8 dat_bright6[] = {0x90, 0x00, 0x05}; + +static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19}; +static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b}; +static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03}; +static u8 dat_hvflip6[] = {0x90, 0x00, 0x06}; + +static struct idxdata tbl_middle_hvflip_low[] = { + {0x33, "\x90\x00\x06"}, + {6, "\xff\xff\xff"}, + {0x33, "\x90\x00\x06"}, + {6, "\xff\xff\xff"}, + {0x33, "\x90\x00\x06"}, + {6, "\xff\xff\xff"}, + {0x33, "\x90\x00\x06"}, + {6, "\xff\xff\xff"}, +}; + +static struct idxdata tbl_middle_hvflip_big[] = { + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, + {102, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"}, + {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, +}; + +static struct idxdata tbl_end_hvflip[] = { + {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, + {6, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, + {6, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, + {6, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, +}; + +static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 }; + +static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 }; +static u8 dat_multi6[] = { 0x90, 0x00, 0x05 }; + +static struct validx tbl_init_at_startup[] = { + {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1}, + {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d}, + {53, 0xffff}, + {0x0040, 0x0000}, {0x0063, 0x0006}, +}; + +static struct validx tbl_common_0B[] = { + {0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d}, + {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, + {0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000}, +}; + +static struct idxdata tbl_common_3B[] = { + {0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"}, + {2, "\xff\xff\xff"}, + {0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"}, + {6, "\xff\xff\xff"}, /* 12 */ + {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, + {2, "\xff\xff\xff"}, /* - */ + {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\x22\x23"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0f"}, {0x33, "\x90\x00\x0d"}, + {0x33, "\x8c\xa2\x10"}, {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x11"}, + {0x33, "\x90\x00\x07"}, {0x33, "\xf4\x03\x1d"}, {0x35, "\xa2\x00\xe2"}, + {0x33, "\x8c\xab\x05"}, {0x33, "\x90\x00\x01"}, {0x32, "\x6e\x00\x86"}, + {0x32, "\x70\x0f\xaa"}, {0x32, "\x72\x0f\xe4"}, {0x33, "\x8c\xa3\x4a"}, + {0x33, "\x90\x00\x5a"}, {0x33, "\x8c\xa3\x4b"}, {0x33, "\x90\x00\xa6"}, + {0x33, "\x8c\xa3\x61"}, {0x33, "\x90\x00\xc8"}, {0x33, "\x8c\xa3\x62"}, + {0x33, "\x90\x00\xe1"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, + {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, + {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, + {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, + {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, + {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, + {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, + {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, + {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, + {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, + {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, + {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, + {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, + {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, + {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, + {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, + {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, + {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, + {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, + {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, + {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, + {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, + {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, + {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, + {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, + {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, + {0x33, "\x78\x00\x00"}, + {2, "\xff\xff\xff"}, + {0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"}, + {0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"}, + {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"}, + {0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"}, + {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"}, + {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"}, + {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"}, + {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"}, + {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"}, + {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"}, + {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, + {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"}, + {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"}, + {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"}, + {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"}, + {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"}, + {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"}, + {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"}, + {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"}, + {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"}, + {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"}, + {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"}, + {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"}, + {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"}, + {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"}, + {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"}, + {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"}, + {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"}, + {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, + {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"}, + {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"}, + {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"}, + {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"}, + {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"}, + {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"}, + {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"}, + {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"}, + {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"}, + {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"}, + {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"}, + {0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, + {3, "\xff\xff\xff"}, +}; + +static struct idxdata tbl_init_post_alt_low1[] = { + {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\x22\x2e"}, + {0x33, "\x90\x00\x81"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x17"}, + {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x1a"}, {0x33, "\x8c\xa4\x0a"}, + {0x33, "\x90\x00\x1d"}, {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x20"}, + {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\x81"}, {0x33, "\x8c\x24\x13"}, + {0x33, "\x90\x00\x9b"}, +}; + +static struct idxdata tbl_init_post_alt_low2[] = { + {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x03\x24"}, {0x33, "\x8c\x27\x05"}, + {0x33, "\x90\x02\x58"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, + {2, "\xff\xff\xff"}, +}; + +static struct idxdata tbl_init_post_alt_low3[] = { + {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, + {2, "\xff\xff\xff"}, + {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x20"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, + {0x33, "\x2e\x01\x00"}, {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, + {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x95"}, {0x33, "\x90\x01\x00"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"}, + {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, + {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, +}; + +static struct idxdata tbl_init_post_alt_big[] = { + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, + {2, "\xff\xff\xff"}, + {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, + {2, "\xff\xff\xff"}, + {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"}, + {0x33, "\x90\x00\x05"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, + {2, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, {0x33, "\x8c\xa1\x20"}, + {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x30"}, {0x33, "\x90\x00\x03"}, + {0x33, "\x8c\xa1\x31"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x32"}, + {0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"}, + {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"}, + {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, + {0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"}, + {51, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, + {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, + {51, "\xff\xff\xff"}, + {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"}, + {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, + {51, "\xff\xff\xff"}, +}; + +static struct idxdata tbl_init_post_alt_3B[] = { + {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, + {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, + {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, + {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, + {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, + {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, + {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, + {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, + {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, + {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, + {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, + {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, + {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, + {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, + {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, + {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, + {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, + {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, + {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, + {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, + {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, + {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, + {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, + {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, + {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, + {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, +}; + +static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81"; +static u8 *dat_800 = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21"; +static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01"; +static u8 *dat_1600 = "\xd0\x02\xd1\x20\xd2\xaf\xd3\x02\xd4\x30\xd5\x41"; + +static int mi2020_init_at_startup(struct gspca_dev *gspca_dev); +static int mi2020_configure_alt(struct gspca_dev *gspca_dev); +static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev); +static int mi2020_init_post_alt(struct gspca_dev *gspca_dev); +static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev); +static int mi2020_camera_settings(struct gspca_dev *gspca_dev); +/*==========================================================================*/ + +void mi2020_init_settings(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vcur.backlight = 0; + sd->vcur.brightness = 70; + sd->vcur.sharpness = 20; + sd->vcur.contrast = 0; + sd->vcur.gamma = 0; + sd->vcur.hue = 0; + sd->vcur.saturation = 60; + sd->vcur.whitebal = 0; /* 50, not done by hardware */ + sd->vcur.mirror = 0; + sd->vcur.flip = 0; + sd->vcur.AC50Hz = 1; + + sd->vmax.backlight = 64; + sd->vmax.brightness = 128; + sd->vmax.sharpness = 40; + sd->vmax.contrast = 3; + sd->vmax.gamma = 2; + sd->vmax.hue = 0 + 1; /* 200, not done by hardware */ + sd->vmax.saturation = 0; /* 100, not done by hardware */ + sd->vmax.whitebal = 2; /* 100, not done by hardware */ + sd->vmax.mirror = 1; + sd->vmax.flip = 1; + sd->vmax.AC50Hz = 1; + + sd->dev_camera_settings = mi2020_camera_settings; + sd->dev_init_at_startup = mi2020_init_at_startup; + sd->dev_configure_alt = mi2020_configure_alt; + sd->dev_init_pre_alt = mi2020_init_pre_alt; + sd->dev_post_unset_alt = mi2020_post_unset_alt; +} + +/*==========================================================================*/ + +static void common(struct gspca_dev *gspca_dev) +{ + fetch_validx(gspca_dev, tbl_common_0B, ARRAY_SIZE(tbl_common_0B)); + fetch_idxdata(gspca_dev, tbl_common_3B, ARRAY_SIZE(tbl_common_3B)); + ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL); +} + +static int mi2020_init_at_startup(struct gspca_dev *gspca_dev) +{ + u8 c; + + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c); + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &c); + + fetch_validx(gspca_dev, tbl_init_at_startup, + ARRAY_SIZE(tbl_init_at_startup)); + + ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL); + ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &c); + + common(gspca_dev); + + msleep(61); +/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */ +/* msleep(36); */ + ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL); + + return 0; +} + +static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->mirrorMask = 0; + sd->vold.hue = -1; + + /* These controls need to be reset */ + sd->vold.brightness = -1; + sd->vold.sharpness = -1; + + /* If not different from default, they do not need to be set */ + sd->vold.contrast = 0; + sd->vold.gamma = 0; + sd->vold.backlight = 0; + + mi2020_init_post_alt(gspca_dev); + + return 0; +} + +static int mi2020_init_post_alt(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; + + s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); + s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); + s32 freq = (sd->vcur.AC50Hz > 0); + s32 wbal = sd->vcur.whitebal; + + u8 dat_freq2[] = {0x90, 0x00, 0x80}; + u8 dat_multi1[] = {0x8c, 0xa7, 0x00}; + u8 dat_multi2[] = {0x90, 0x00, 0x00}; + u8 dat_multi3[] = {0x8c, 0xa7, 0x00}; + u8 dat_multi4[] = {0x90, 0x00, 0x00}; + u8 dat_hvflip2[] = {0x90, 0x04, 0x6c}; + u8 dat_hvflip4[] = {0x90, 0x00, 0x24}; + u8 dat_wbal2[] = {0x90, 0x00, 0x00}; + u8 c; + + sd->nbIm = -1; + + dat_freq2[2] = freq ? 0xc0 : 0x80; + dat_multi1[2] = 0x9d; + dat_multi3[2] = dat_multi1[2] + 1; + if (wbal == 0) { + dat_multi4[2] = dat_multi2[2] = 0; + dat_wbal2[2] = 0x17; + } else if (wbal == 1) { + dat_multi4[2] = dat_multi2[2] = 0; + dat_wbal2[2] = 0x35; + } else if (wbal == 2) { + dat_multi4[2] = dat_multi2[2] = 0x20; + dat_wbal2[2] = 0x17; + } + dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror); + dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror); + + msleep(200); + ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); + msleep(2); + + common(gspca_dev); + + msleep(142); + ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0003, 0x00c1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0042, 0x00c2, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL); + + switch (reso) { + case IMAGE_640: + case IMAGE_800: + if (reso != IMAGE_800) + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, + 12, dat_640); + else + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, + 12, dat_800); + + fetch_idxdata(gspca_dev, tbl_init_post_alt_low1, + ARRAY_SIZE(tbl_init_post_alt_low1)); + + if (reso == IMAGE_800) + fetch_idxdata(gspca_dev, tbl_init_post_alt_low2, + ARRAY_SIZE(tbl_init_post_alt_low2)); + + fetch_idxdata(gspca_dev, tbl_init_post_alt_low3, + ARRAY_SIZE(tbl_init_post_alt_low3)); + + ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); + msleep(120); + break; + + case IMAGE_1280: + case IMAGE_1600: + if (reso == IMAGE_1280) { + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, + 12, dat_1280); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, + 3, "\x8c\x27\x07"); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, + 3, "\x90\x05\x04"); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, + 3, "\x8c\x27\x09"); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, + 3, "\x90\x04\x02"); + } else { + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, + 12, dat_1600); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, + 3, "\x8c\x27\x07"); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, + 3, "\x90\x06\x40"); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, + 3, "\x8c\x27\x09"); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, + 3, "\x90\x04\xb0"); + } + + fetch_idxdata(gspca_dev, tbl_init_post_alt_big, + ARRAY_SIZE(tbl_init_post_alt_big)); + + ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL); + msleep(1850); + } + + ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL); + msleep(40); + + /* AC power frequency */ + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); + msleep(33); + /* light source */ + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); + msleep(7); + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c); + + fetch_idxdata(gspca_dev, tbl_init_post_alt_3B, + ARRAY_SIZE(tbl_init_post_alt_3B)); + + /* hvflip */ + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6); + msleep(250); + + if (reso == IMAGE_640 || reso == IMAGE_800) + fetch_idxdata(gspca_dev, tbl_middle_hvflip_low, + ARRAY_SIZE(tbl_middle_hvflip_low)); + else + fetch_idxdata(gspca_dev, tbl_middle_hvflip_big, + ARRAY_SIZE(tbl_middle_hvflip_big)); + + fetch_idxdata(gspca_dev, tbl_end_hvflip, + ARRAY_SIZE(tbl_end_hvflip)); + + sd->nbIm = 0; + + sd->vold.mirror = mirror; + sd->vold.flip = flip; + sd->vold.AC50Hz = freq; + sd->vold.whitebal = wbal; + + mi2020_camera_settings(gspca_dev); + + return 0; +} + +static int mi2020_configure_alt(struct gspca_dev *gspca_dev) +{ + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; + + switch (reso) { + case IMAGE_640: + gspca_dev->alt = 3 + 1; + break; + + case IMAGE_800: + case IMAGE_1280: + case IMAGE_1600: + gspca_dev->alt = 1 + 1; + break; + } + return 0; +} + +static int mi2020_camera_settings(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; + + s32 backlight = sd->vcur.backlight; + s32 bright = sd->vcur.brightness; + s32 sharp = sd->vcur.sharpness; + s32 cntr = sd->vcur.contrast; + s32 gam = sd->vcur.gamma; + s32 hue = (sd->vcur.hue > 0); + s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0); + s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0); + s32 freq = (sd->vcur.AC50Hz > 0); + s32 wbal = sd->vcur.whitebal; + + u8 dat_sharp[] = {0x6c, 0x00, 0x08}; + u8 dat_bright2[] = {0x90, 0x00, 0x00}; + u8 dat_freq2[] = {0x90, 0x00, 0x80}; + u8 dat_multi1[] = {0x8c, 0xa7, 0x00}; + u8 dat_multi2[] = {0x90, 0x00, 0x00}; + u8 dat_multi3[] = {0x8c, 0xa7, 0x00}; + u8 dat_multi4[] = {0x90, 0x00, 0x00}; + u8 dat_hvflip2[] = {0x90, 0x04, 0x6c}; + u8 dat_hvflip4[] = {0x90, 0x00, 0x24}; + u8 dat_wbal2[] = {0x90, 0x00, 0x00}; + + /* Less than 4 images received -> too early to set the settings */ + if (sd->nbIm < 4) { + sd->waitSet = 1; + return 0; + } + sd->waitSet = 0; + + if (freq != sd->vold.AC50Hz) { + sd->vold.AC50Hz = freq; + + dat_freq2[2] = freq ? 0xc0 : 0x80; + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2); + msleep(20); + } + + if (wbal != sd->vold.whitebal) { + sd->vold.whitebal = wbal; + if (wbal < 0 || wbal > sd->vmax.whitebal) + wbal = 0; + + dat_multi1[2] = 0x9d; + dat_multi3[2] = dat_multi1[2] + 1; + if (wbal == 0) { + dat_multi4[2] = dat_multi2[2] = 0; + dat_wbal2[2] = 0x17; + } else if (wbal == 1) { + dat_multi4[2] = dat_multi2[2] = 0; + dat_wbal2[2] = 0x35; + } else if (wbal == 2) { + dat_multi4[2] = dat_multi2[2] = 0x20; + dat_wbal2[2] = 0x17; + } + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); + } + + if (mirror != sd->vold.mirror || flip != sd->vold.flip) { + sd->vold.mirror = mirror; + sd->vold.flip = flip; + + dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror); + dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror); + + fetch_idxdata(gspca_dev, tbl_init_post_alt_3B, + ARRAY_SIZE(tbl_init_post_alt_3B)); + + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6); + msleep(40); + + if (reso == IMAGE_640 || reso == IMAGE_800) + fetch_idxdata(gspca_dev, tbl_middle_hvflip_low, + ARRAY_SIZE(tbl_middle_hvflip_low)); + else + fetch_idxdata(gspca_dev, tbl_middle_hvflip_big, + ARRAY_SIZE(tbl_middle_hvflip_big)); + + fetch_idxdata(gspca_dev, tbl_end_hvflip, + ARRAY_SIZE(tbl_end_hvflip)); + } + + if (bright != sd->vold.brightness) { + sd->vold.brightness = bright; + if (bright < 0 || bright > sd->vmax.brightness) + bright = 0; + + dat_bright2[2] = bright; + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6); + } + + if (cntr != sd->vold.contrast || gam != sd->vold.gamma) { + sd->vold.contrast = cntr; + if (cntr < 0 || cntr > sd->vmax.contrast) + cntr = 0; + sd->vold.gamma = gam; + if (gam < 0 || gam > sd->vmax.gamma) + gam = 0; + + dat_multi1[2] = 0x6d; + dat_multi3[2] = dat_multi1[2] + 1; + if (cntr == 0) + cntr = 4; + dat_multi4[2] = dat_multi2[2] = cntr * 0x10 + 2 - gam; + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); + } + + if (backlight != sd->vold.backlight) { + sd->vold.backlight = backlight; + if (backlight < 0 || backlight > sd->vmax.backlight) + backlight = 0; + + dat_multi1[2] = 0x9d; + dat_multi3[2] = dat_multi1[2] + 1; + dat_multi4[2] = dat_multi2[2] = backlight; + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5); + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6); + } + + if (sharp != sd->vold.sharpness) { + sd->vold.sharpness = sharp; + if (sharp < 0 || sharp > sd->vmax.sharpness) + sharp = 0; + + dat_sharp[1] = sharp; + ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0032, 3, dat_sharp); + } + + if (hue != sd->vold.hue) { + sd->swapRB = hue; + sd->vold.hue = hue; + } + + return 0; +} + +static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev) +{ + ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); + msleep(40); + ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-ov2640.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-ov2640.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-ov2640.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-ov2640.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,489 @@ +/* Subdriver for the GL860 chip with the OV2640 sensor + * Author Olivier LORIN, from Malmostoso's logs + * + * 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, or + * any later version. + * + * 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, see . + */ + +/* Sensor : OV2640 */ + +#include "gl860.h" + +static u8 dat_init1[] = "\x00\x41\x07\x6a\x06\x61\x0d\x6a" "\x10\x10\xc1\x01"; + +static u8 c61[] = {0x61}; /* expected */ +static u8 c51[] = {0x51}; /* expected */ +static u8 c50[] = {0x50}; /* expected */ +static u8 c28[] = {0x28}; /* expected */ +static u8 ca8[] = {0xa8}; /* expected */ + +static u8 dat_post[] = + "\x00\x41\x07\x6a\x06\xef\x0d\x6a" "\x10\x10\xc1\x01"; + +static u8 dat_640[] = "\xd0\x01\xd1\x08\xd2\xe0\xd3\x02\xd4\x10\xd5\x81"; +static u8 dat_800[] = "\xd0\x01\xd1\x10\xd2\x58\xd3\x02\xd4\x18\xd5\x21"; +static u8 dat_1280[] = "\xd0\x01\xd1\x18\xd2\xc0\xd3\x02\xd4\x28\xd5\x01"; +static u8 dat_1600[] = "\xd0\x01\xd1\x20\xd2\xb0\xd3\x02\xd4\x30\xd5\x41"; + +static struct validx tbl_init_at_startup[] = { + {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1}, + {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d}, + {0x0050, 0x0000}, {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0061, 0x0006}, + {0x006a, 0x000d}, {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, + {0x0041, 0x00c2}, {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, + {0x0041, 0x0000}, {0x0061, 0x0000}, +}; + +static struct validx tbl_common[] = { + {0x6000, 0x00ff}, {0x60ff, 0x002c}, {0x60df, 0x002e}, {0x6001, 0x00ff}, + {0x6080, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010}, + {0x6035, 0x003c}, {0x6000, 0x0011}, {0x6028, 0x0004}, {0x60e5, 0x0013}, + {0x6088, 0x0014}, {0x600c, 0x002c}, {0x6078, 0x0033}, {0x60f7, 0x003b}, + {0x6000, 0x003e}, {0x6011, 0x0043}, {0x6010, 0x0016}, {0x6082, 0x0039}, + {0x6088, 0x0035}, {0x600a, 0x0022}, {0x6040, 0x0037}, {0x6000, 0x0023}, + {0x60a0, 0x0034}, {0x601a, 0x0036}, {0x6002, 0x0006}, {0x60c0, 0x0007}, + {0x60b7, 0x000d}, {0x6001, 0x000e}, {0x6000, 0x004c}, {0x6081, 0x004a}, + {0x6099, 0x0021}, {0x6002, 0x0009}, {0x603e, 0x0024}, {0x6034, 0x0025}, + {0x6081, 0x0026}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010}, + {0x6000, 0x005c}, {0x6000, 0x0063}, {0x6000, 0x007c}, {0x6070, 0x0061}, + {0x6080, 0x0062}, {0x6080, 0x0020}, {0x6030, 0x0028}, {0x6000, 0x006c}, + {0x6000, 0x006e}, {0x6002, 0x0070}, {0x6094, 0x0071}, {0x60c1, 0x0073}, + {0x6034, 0x003d}, {0x6057, 0x005a}, {0x60bb, 0x004f}, {0x609c, 0x0050}, + {0x6080, 0x006d}, {0x6002, 0x0039}, {0x6033, 0x003a}, {0x60f1, 0x003b}, + {0x6031, 0x003c}, {0x6000, 0x00ff}, {0x6014, 0x00e0}, {0x60ff, 0x0076}, + {0x60a0, 0x0033}, {0x6020, 0x0042}, {0x6018, 0x0043}, {0x6000, 0x004c}, + {0x60d0, 0x0087}, {0x600f, 0x0088}, {0x6003, 0x00d7}, {0x6010, 0x00d9}, + {0x6005, 0x00da}, {0x6082, 0x00d3}, {0x60c0, 0x00f9}, {0x6006, 0x0044}, + {0x6007, 0x00d1}, {0x6002, 0x00d2}, {0x6000, 0x00d2}, {0x6011, 0x00d8}, + {0x6008, 0x00c8}, {0x6080, 0x00c9}, {0x6008, 0x007c}, {0x6020, 0x007d}, + {0x6020, 0x007d}, {0x6000, 0x0090}, {0x600e, 0x0091}, {0x601a, 0x0091}, + {0x6031, 0x0091}, {0x605a, 0x0091}, {0x6069, 0x0091}, {0x6075, 0x0091}, + {0x607e, 0x0091}, {0x6088, 0x0091}, {0x608f, 0x0091}, {0x6096, 0x0091}, + {0x60a3, 0x0091}, {0x60af, 0x0091}, {0x60c4, 0x0091}, {0x60d7, 0x0091}, + {0x60e8, 0x0091}, {0x6020, 0x0091}, {0x6000, 0x0092}, {0x6006, 0x0093}, + {0x60e3, 0x0093}, {0x6005, 0x0093}, {0x6005, 0x0093}, {0x6000, 0x0093}, + {0x6004, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, + {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, + {0x6000, 0x0096}, {0x6008, 0x0097}, {0x6019, 0x0097}, {0x6002, 0x0097}, + {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097}, {0x6028, 0x0097}, + {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6098, 0x0097}, {0x6080, 0x0097}, + {0x6000, 0x0097}, {0x6000, 0x0097}, {0x60ed, 0x00c3}, {0x609a, 0x00c4}, + {0x6000, 0x00a4}, {0x6011, 0x00c5}, {0x6051, 0x00c6}, {0x6010, 0x00c7}, + {0x6066, 0x00b6}, {0x60a5, 0x00b8}, {0x6064, 0x00b7}, {0x607c, 0x00b9}, + {0x60af, 0x00b3}, {0x6097, 0x00b4}, {0x60ff, 0x00b5}, {0x60c5, 0x00b0}, + {0x6094, 0x00b1}, {0x600f, 0x00b2}, {0x605c, 0x00c4}, {0x6000, 0x00a8}, + {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x601d, 0x0086}, {0x6000, 0x0050}, + {0x6090, 0x0051}, {0x6018, 0x0052}, {0x6000, 0x0053}, {0x6000, 0x0054}, + {0x6088, 0x0055}, {0x6000, 0x0057}, {0x6090, 0x005a}, {0x6018, 0x005b}, + {0x6005, 0x005c}, {0x60ed, 0x00c3}, {0x6000, 0x007f}, {0x6005, 0x00da}, + {0x601f, 0x00e5}, {0x6067, 0x00e1}, {0x6000, 0x00e0}, {0x60ff, 0x00dd}, + {0x6000, 0x0005}, {0x6001, 0x00ff}, {0x6000, 0x0000}, {0x6000, 0x0045}, + {0x6000, 0x0010}, +}; + +static struct validx tbl_sensor_settings_common1[] = { + {0x0041, 0x0000}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d}, + {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2}, + {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0041, 0x0000}, + {50, 0xffff}, + {0x0061, 0x0000}, + {0xffff, 0xffff}, + {0x6000, 0x00ff}, {0x6000, 0x007c}, {0x6007, 0x007d}, + {30, 0xffff}, + {0x0040, 0x0000}, +}; + +static struct validx tbl_sensor_settings_common2[] = { + {0x6001, 0x00ff}, {0x6038, 0x000c}, + {10, 0xffff}, + {0x6000, 0x0011}, +}; + +static struct validx tbl_640[] = { + {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1}, + {0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, + {0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017}, + {0x6075, 0x0018}, {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032}, + {0x60bb, 0x004f}, {0x6057, 0x005a}, {0x609c, 0x0050}, {0x6080, 0x006d}, + {0x6092, 0x0026}, {0x60ff, 0x0020}, {0x6000, 0x0027}, {0x6000, 0x00ff}, + {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c}, {0x603d, 0x0086}, + {0x6089, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052}, {0x6000, 0x0053}, + {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057}, {0x60a0, 0x005a}, + {0x6078, 0x005b}, {0x6000, 0x005c}, {0x6004, 0x00d3}, {0x6000, 0x00e0}, + {0x60ff, 0x00dd}, {0x60a1, 0x005a}, +}; + +static struct validx tbl_800[] = { + {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1}, + {0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, + {0x6001, 0x00ff}, {0x6040, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017}, + {0x6043, 0x0018}, {0x6000, 0x0019}, {0x604b, 0x001a}, {0x6009, 0x0032}, + {0x60ca, 0x004f}, {0x60a8, 0x0050}, {0x6000, 0x006d}, {0x6038, 0x003d}, + {0x60c8, 0x0035}, {0x6000, 0x0022}, {0x6092, 0x0026}, {0x60ff, 0x0020}, + {0x6000, 0x0027}, {0x6000, 0x00ff}, {0x6064, 0x00c0}, {0x604b, 0x00c1}, + {0x6000, 0x008c}, {0x601d, 0x0086}, {0x6082, 0x00d3}, {0x6000, 0x00e0}, + {0x60ff, 0x00dd}, {0x6020, 0x008c}, {0x6001, 0x00ff}, {0x6044, 0x0018}, +}; + +static struct validx tbl_big1[] = { + {0x0002, 0x00c1}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, + {0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045}, + {0x6000, 0x0010}, {0x6000, 0x0011}, {0x6011, 0x0017}, {0x6075, 0x0018}, + {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032}, {0x60bb, 0x004f}, + {0x609c, 0x0050}, {0x6057, 0x005a}, {0x6080, 0x006d}, {0x6043, 0x000f}, + {0x608f, 0x0003}, {0x6005, 0x007c}, {0x6081, 0x0026}, {0x6000, 0x00ff}, + {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c}, +}; + +static struct validx tbl_big2[] = { + {0x603d, 0x0086}, {0x6000, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052}, + {0x6000, 0x0053}, {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057}, + {0x6040, 0x005a}, {0x60f0, 0x005b}, {0x6001, 0x005c}, {0x6082, 0x00d3}, + {0x6000, 0x008e}, +}; + +static struct validx tbl_big3[] = { + {0x6004, 0x00da}, {0x6000, 0x00e0}, {0x6067, 0x00e1}, {0x60ff, 0x00dd}, + {0x6001, 0x00ff}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, + {0x6001, 0x00ff}, {0x6000, 0x0011}, {0x6000, 0x00ff}, {0x6010, 0x00c7}, + {0x6000, 0x0092}, {0x6006, 0x0093}, {0x60e3, 0x0093}, {0x6005, 0x0093}, + {0x6005, 0x0093}, {0x60ed, 0x00c3}, {0x6000, 0x00a4}, {0x60d0, 0x0087}, + {0x6003, 0x0096}, {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097}, + {0x6028, 0x0097}, {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6001, 0x00ff}, + {0x6043, 0x000f}, {0x608f, 0x0003}, {0x6000, 0x002d}, {0x6000, 0x002e}, + {0x600a, 0x0022}, {0x6002, 0x0070}, {0x6008, 0x0014}, {0x6048, 0x0014}, + {0x6000, 0x00ff}, {0x6000, 0x00e0}, {0x60ff, 0x00dd}, +}; + +static struct validx tbl_post_unset_alt[] = { + {0x006a, 0x000d}, {0x6001, 0x00ff}, {0x6081, 0x0026}, {0x6000, 0x0000}, + {0x6000, 0x0045}, {0x6000, 0x0010}, {0x6068, 0x000d}, + {50, 0xffff}, + {0x0021, 0x0000}, +}; + +static int ov2640_init_at_startup(struct gspca_dev *gspca_dev); +static int ov2640_configure_alt(struct gspca_dev *gspca_dev); +static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev); +static int ov2640_init_post_alt(struct gspca_dev *gspca_dev); +static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev); +static int ov2640_camera_settings(struct gspca_dev *gspca_dev); +/*==========================================================================*/ + +void ov2640_init_settings(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vcur.backlight = 32; + sd->vcur.brightness = 0; + sd->vcur.sharpness = 6; + sd->vcur.contrast = 0; + sd->vcur.gamma = 32; + sd->vcur.hue = 0; + sd->vcur.saturation = 128; + sd->vcur.whitebal = 64; + sd->vcur.mirror = 0; + sd->vcur.flip = 0; + + sd->vmax.backlight = 64; + sd->vmax.brightness = 255; + sd->vmax.sharpness = 31; + sd->vmax.contrast = 255; + sd->vmax.gamma = 64; + sd->vmax.hue = 254 + 2; + sd->vmax.saturation = 255; + sd->vmax.whitebal = 128; + sd->vmax.mirror = 1; + sd->vmax.flip = 1; + sd->vmax.AC50Hz = 0; + + sd->dev_camera_settings = ov2640_camera_settings; + sd->dev_init_at_startup = ov2640_init_at_startup; + sd->dev_configure_alt = ov2640_configure_alt; + sd->dev_init_pre_alt = ov2640_init_pre_alt; + sd->dev_post_unset_alt = ov2640_post_unset_alt; +} + +/*==========================================================================*/ + +static void common(struct gspca_dev *gspca_dev) +{ + fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common)); +} + +static int ov2640_init_at_startup(struct gspca_dev *gspca_dev) +{ + fetch_validx(gspca_dev, tbl_init_at_startup, + ARRAY_SIZE(tbl_init_at_startup)); + + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_init1); + + common(gspca_dev); + + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0006, 1, c61); + + ctrl_out(gspca_dev, 0x40, 1, 0x00ef, 0x0006, 0, NULL); + + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c51); + + ctrl_out(gspca_dev, 0x40, 1, 0x0051, 0x0000, 0, NULL); +/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */ + + return 0; +} + +static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->mirrorMask = 0; + + sd->vold.backlight = -1; + sd->vold.brightness = -1; + sd->vold.sharpness = -1; + sd->vold.contrast = -1; + sd->vold.saturation = -1; + sd->vold.gamma = -1; + sd->vold.hue = -1; + sd->vold.whitebal = -1; + sd->vold.mirror = -1; + sd->vold.flip = -1; + + ov2640_init_post_alt(gspca_dev); + + return 0; +} + +static int ov2640_init_post_alt(struct gspca_dev *gspca_dev) +{ + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; + s32 n; /* reserved for FETCH functions */ + + ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); + + n = fetch_validx(gspca_dev, tbl_sensor_settings_common1, + ARRAY_SIZE(tbl_sensor_settings_common1)); + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_post); + common(gspca_dev); + keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common1, + ARRAY_SIZE(tbl_sensor_settings_common1), n); + + switch (reso) { + case IMAGE_640: + n = fetch_validx(gspca_dev, tbl_640, ARRAY_SIZE(tbl_640)); + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_640); + break; + + case IMAGE_800: + n = fetch_validx(gspca_dev, tbl_800, ARRAY_SIZE(tbl_800)); + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_800); + break; + + case IMAGE_1600: + case IMAGE_1280: + n = fetch_validx(gspca_dev, tbl_big1, ARRAY_SIZE(tbl_big1)); + + if (reso == IMAGE_1280) { + n = fetch_validx(gspca_dev, tbl_big2, + ARRAY_SIZE(tbl_big2)); + } else { + ctrl_out(gspca_dev, 0x40, 1, 0x601d, 0x0086, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00d7, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6082, 0x00d3, 0, NULL); + } + + n = fetch_validx(gspca_dev, tbl_big3, ARRAY_SIZE(tbl_big3)); + + if (reso == IMAGE_1280) { + ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, + 12, dat_1280); + } else { + ctrl_out(gspca_dev, 0x40, 1, 0x6020, 0x008c, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6076, 0x0018, 0, NULL); + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, + 12, dat_1600); + } + break; + } + + n = fetch_validx(gspca_dev, tbl_sensor_settings_common2, + ARRAY_SIZE(tbl_sensor_settings_common2)); + + ov2640_camera_settings(gspca_dev); + + return 0; +} + +static int ov2640_configure_alt(struct gspca_dev *gspca_dev) +{ + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; + + switch (reso) { + case IMAGE_640: + gspca_dev->alt = 3 + 1; + break; + + case IMAGE_800: + case IMAGE_1280: + case IMAGE_1600: + gspca_dev->alt = 1 + 1; + break; + } + return 0; +} + +static int ov2640_camera_settings(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + s32 backlight = sd->vcur.backlight; + s32 bright = sd->vcur.brightness; + s32 sharp = sd->vcur.sharpness; + s32 gam = sd->vcur.gamma; + s32 cntr = sd->vcur.contrast; + s32 sat = sd->vcur.saturation; + s32 hue = sd->vcur.hue; + s32 wbal = sd->vcur.whitebal; + s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) == 0); + s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) == 0); + + if (backlight != sd->vold.backlight) { + /* No sd->vold.backlight=backlight; (to be done again later) */ + if (backlight < 0 || backlight > sd->vmax.backlight) + backlight = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x00ff, + 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight , 0x0024, + 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025, + 0, NULL); + } + + if (bright != sd->vold.brightness) { + sd->vold.brightness = bright; + if (bright < 0 || bright > sd->vmax.brightness) + bright = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6009 , 0x007c, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6000 + bright, 0x007d, 0, NULL); + } + + if (wbal != sd->vold.whitebal) { + sd->vold.whitebal = wbal; + if (wbal < 0 || wbal > sd->vmax.whitebal) + wbal = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6003 , 0x007c, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6000 + wbal, 0x007d, 0, NULL); + } + + if (cntr != sd->vold.contrast) { + sd->vold.contrast = cntr; + if (cntr < 0 || cntr > sd->vmax.contrast) + cntr = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6007 , 0x007c, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6000 + cntr, 0x007d, 0, NULL); + } + + if (sat != sd->vold.saturation) { + sd->vold.saturation = sat; + if (sat < 0 || sat > sd->vmax.saturation) + sat = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x007c, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6000 + sat, 0x007d, 0, NULL); + } + + if (sharp != sd->vold.sharpness) { + sd->vold.sharpness = sharp; + if (sharp < 0 || sharp > sd->vmax.sharpness) + sharp = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x0092, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x60c0 + sharp, 0x0093, 0, NULL); + } + + if (hue != sd->vold.hue) { + sd->vold.hue = hue; + if (hue < 0 || hue > sd->vmax.hue) + hue = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6002 , 0x007c, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6000 + hue * (hue < 255), 0x007d, + 0, NULL); + if (hue >= 255) + sd->swapRB = 1; + else + sd->swapRB = 0; + } + + if (gam != sd->vold.gamma) { + sd->vold.gamma = gam; + if (gam < 0 || gam > sd->vmax.gamma) + gam = 0; + + ctrl_out(gspca_dev, 0x40, 1, 0x6000 , 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6008 , 0x007c, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6000 + gam, 0x007d, 0, NULL); + } + + if (mirror != sd->vold.mirror || flip != sd->vold.flip) { + sd->vold.mirror = mirror; + sd->vold.flip = flip; + + mirror = 0x80 * mirror; + ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL); + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, c28); + ctrl_out(gspca_dev, 0x40, 1, 0x6028 + mirror, 0x0004, 0, NULL); + + flip = 0x50 * flip + mirror; + ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL); + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, ca8); + ctrl_out(gspca_dev, 0x40, 1, 0x6028 + flip, 0x0004, 0, NULL); + + ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50); + } + + if (backlight != sd->vold.backlight) { + sd->vold.backlight = backlight; + + ctrl_out(gspca_dev, 0x40, 1, 0x6001 , 0x00ff, + 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight , 0x0024, + 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025, + 0, NULL); + } + + return 0; +} + +static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev) +{ + ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); + msleep(20); + fetch_validx(gspca_dev, tbl_post_unset_alt, + ARRAY_SIZE(tbl_post_unset_alt)); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-ov9655.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-ov9655.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-ov9655.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/gl860-ov9655.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,336 @@ +/* Subdriver for the GL860 chip with the OV9655 sensor + * Author Olivier LORIN, from logs done by Simon (Sur3) and Almighurt + * on dsd's weblog + * + * 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, or + * any later version. + * + * 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, see . + */ + +/* Sensor : OV9655 */ + +#include "gl860.h" + +static struct validx tbl_init_at_startup[] = { + {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1}, + {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d}, + + {0x0040, 0x0000}, +}; + +static struct validx tbl_commmon[] = { + {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, + {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2}, + {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0040, 0x0000}, + {0x00f3, 0x0006}, {0x0058, 0x0000}, {0x0048, 0x0000}, {0x0061, 0x0000}, +}; + +static s32 tbl_length[] = {12, 56, 52, 54, 56, 42, 32, 12}; + +static u8 *tbl_640[] = { + "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01" + , + "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x03\x0b\x57\x0e\x61" + "\x0f\x42\x11\x01\x12\x60\x13\x00" "\x14\x3a\x16\x24\x17\x14\x18\x00" + "\x19\x01\x1a\x3d\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08" + "\x29\x15\x2a\x00\x2b\x00\x2c\x08" + , + "\x32\xff\x33\x00\x34\x3d\x35\x00" "\x36\xfa\x38\x72\x39\x57\x3a\x00" + "\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc1" "\x40\xc0\x41\x00\x42\xc0\x43\x0a" + "\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xee\x4b\xe7\x4c\xe7" + "\x4d\xe7\x4e\xe7" + , + "\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85" + "\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0" + "\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x0a\x6b\x5a\x6c\x04" + "\x6d\x55\x6e\x00\x6f\x9d" + , + "\x70\x15\x71\x78\x72\x00\x73\x00" "\x74\x3a\x75\x35\x76\x01\x77\x02" + "\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52" + "\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5" + "\x8a\x23\x8c\x8d\x90\x7c\x91\x7b" + , + "\x9d\x02\x9e\x02\x9f\x74\xa0\x73" "\xa1\x40\xa4\x50\xa5\x68\xa6\x70" + "\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80" + "\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf" + , + "\xbb\xae\xbc\x4f\xbd\x4e\xbe\x6a" "\xbf\x68\xc0\xaa\xc1\xc0\xc2\x01" + "\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93" + , + "\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80" +}; + +static u8 *tbl_1280[] = { + "\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01" + , + "\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61" + "\x0f\x42\x11\x00\x12\x00\x13\x00" "\x14\x3a\x16\x24\x17\x1b\x18\xbb" + "\x19\x01\x1a\x81\x1e\x04\x24\x3c" "\x25\x36\x26\x72\x27\x08\x28\x08" + "\x29\x15\x2a\x00\x2b\x00\x2c\x08" + , + "\x32\xa4\x33\x00\x34\x3d\x35\x00" "\x36\xf8\x38\x72\x39\x57\x3a\x00" + "\x3b\x0c\x3d\x99\x3e\x0c\x3f\xc2" "\x40\xc0\x41\x00\x42\xc0\x43\x0a" + "\x44\xf0\x45\x46\x46\x62\x47\x2a" "\x48\x3c\x4a\xec\x4b\xe8\x4c\xe8" + "\x4d\xe8\x4e\xe8" + , + "\x4f\x98\x50\x98\x51\x00\x52\x28" "\x53\x70\x54\x98\x58\x1a\x59\x85" + "\x5a\xa9\x5b\x64\x5c\x84\x5d\x53" "\x5e\x0e\x5f\xf0\x60\xf0\x61\xf0" + "\x62\x00\x63\x00\x64\x02\x65\x20" "\x66\x00\x69\x02\x6b\x5a\x6c\x04" + "\x6d\x55\x6e\x00\x6f\x9d" + , + "\x70\x08\x71\x78\x72\x00\x73\x01" "\x74\x3a\x75\x35\x76\x01\x77\x02" + "\x7a\x24\x7b\x04\x7c\x07\x7d\x10" "\x7e\x28\x7f\x36\x80\x44\x81\x52" + "\x82\x60\x83\x6c\x84\x78\x85\x8c" "\x86\x9e\x87\xbb\x88\xd2\x89\xe5" + "\x8a\x23\x8c\x0d\x90\x90\x91\x90" + , + "\x9d\x02\x9e\x02\x9f\x94\xa0\x94" "\xa1\x01\xa4\x50\xa5\x68\xa6\x70" + "\xa8\xc1\xa9\xef\xaa\x92\xab\x04" "\xac\x80\xad\x80\xae\x80\xaf\x80" + "\xb2\xf2\xb3\x20\xb4\x20\xb5\x00" "\xb6\xaf" + , + "\xbb\xae\xbc\x38\xbd\x39\xbe\x01" "\xbf\x01\xc0\xe2\xc1\xc0\xc2\x01" + "\xc3\x4e\xc6\x85\xc7\x81\xc9\xe0" "\xca\xe8\xcb\xf0\xcc\xd8\xcd\x93" + , + "\xd0\x21\xd1\x18\xd2\xe0\xd3\x01" "\xd4\x28\xd5\x00" +}; + +static u8 c04[] = {0x04}; +static u8 dat_post1[] = "\x04\x00\x10\x20\xa1\x00\x00\x02"; +static u8 dat_post2[] = "\x10\x10\xc1\x02"; +static u8 dat_post3[] = "\x04\x00\x10\x7c\xa1\x00\x00\x04"; +static u8 dat_post4[] = "\x10\x02\xc1\x06"; +static u8 dat_post5[] = "\x04\x00\x10\x7b\xa1\x00\x00\x08"; +static u8 dat_post6[] = "\x10\x10\xc1\x05"; +static u8 dat_post7[] = "\x04\x00\x10\x7c\xa1\x00\x00\x08"; +static u8 dat_post8[] = "\x04\x00\x10\x7c\xa1\x00\x00\x09"; + +static struct validx tbl_init_post_alt[] = { + {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x603c, 0x00ff}, + {0x6003, 0x00ff}, {0x6032, 0x00ff}, {0x6032, 0x00ff}, {0x6001, 0x00ff}, + {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6012, 0x0003}, + {0xffff, 0xffff}, + {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6012, 0x0003}, {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6012, 0x0003}, + {0xffff, 0xffff}, + {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6000, 0x801e}, + {0xffff, 0xffff}, + {0x6004, 0x001e}, {0x6012, 0x0003}, +}; + +static int ov9655_init_at_startup(struct gspca_dev *gspca_dev); +static int ov9655_configure_alt(struct gspca_dev *gspca_dev); +static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev); +static int ov9655_init_post_alt(struct gspca_dev *gspca_dev); +static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev); +static int ov9655_camera_settings(struct gspca_dev *gspca_dev); +/*==========================================================================*/ + +void ov9655_init_settings(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vcur.backlight = 0; + sd->vcur.brightness = 128; + sd->vcur.sharpness = 0; + sd->vcur.contrast = 0; + sd->vcur.gamma = 0; + sd->vcur.hue = 0; + sd->vcur.saturation = 0; + sd->vcur.whitebal = 0; + + sd->vmax.backlight = 0; + sd->vmax.brightness = 255; + sd->vmax.sharpness = 0; + sd->vmax.contrast = 0; + sd->vmax.gamma = 0; + sd->vmax.hue = 0 + 1; + sd->vmax.saturation = 0; + sd->vmax.whitebal = 0; + sd->vmax.mirror = 0; + sd->vmax.flip = 0; + sd->vmax.AC50Hz = 0; + + sd->dev_camera_settings = ov9655_camera_settings; + sd->dev_init_at_startup = ov9655_init_at_startup; + sd->dev_configure_alt = ov9655_configure_alt; + sd->dev_init_pre_alt = ov9655_init_pre_alt; + sd->dev_post_unset_alt = ov9655_post_unset_alt; +} + +/*==========================================================================*/ + +static int ov9655_init_at_startup(struct gspca_dev *gspca_dev) +{ + fetch_validx(gspca_dev, tbl_init_at_startup, + ARRAY_SIZE(tbl_init_at_startup)); + fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon)); +/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL);*/ + + return 0; +} + +static int ov9655_init_pre_alt(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vold.brightness = -1; + sd->vold.hue = -1; + + fetch_validx(gspca_dev, tbl_commmon, ARRAY_SIZE(tbl_commmon)); + + ov9655_init_post_alt(gspca_dev); + + return 0; +} + +static int ov9655_init_post_alt(struct gspca_dev *gspca_dev) +{ + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; + s32 n; /* reserved for FETCH functions */ + s32 i; + u8 **tbl; + + ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL); + + tbl = (reso == IMAGE_640) ? tbl_640 : tbl_1280; + + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, + tbl_length[0], tbl[0]); + for (i = 1; i < 7; i++) + ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, + tbl_length[i], tbl[i]); + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, + tbl_length[7], tbl[7]); + + n = fetch_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt)); + + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x801e, 1, c04); + keep_on_fetching_validx(gspca_dev, tbl_init_post_alt, + ARRAY_SIZE(tbl_init_post_alt), n); + + ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post1); + + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post2); + ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post3); + + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post4); + ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post5); + + ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 4, dat_post6); + ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post7); + + ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_post8); + + ov9655_camera_settings(gspca_dev); + + return 0; +} + +static int ov9655_configure_alt(struct gspca_dev *gspca_dev) +{ + s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv; + + switch (reso) { + case IMAGE_640: + gspca_dev->alt = 1 + 1; + break; + + default: + gspca_dev->alt = 1 + 1; + break; + } + return 0; +} + +static int ov9655_camera_settings(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + u8 dat_bright[] = "\x04\x00\x10\x7c\xa1\x00\x00\x70"; + + s32 bright = sd->vcur.brightness; + s32 hue = sd->vcur.hue; + + if (bright != sd->vold.brightness) { + sd->vold.brightness = bright; + if (bright < 0 || bright > sd->vmax.brightness) + bright = 0; + + dat_bright[3] = bright; + ctrl_out(gspca_dev, 0x40, 3, 0x6000, 0x0200, 8, dat_bright); + } + + if (hue != sd->vold.hue) { + sd->vold.hue = hue; + sd->swapRB = (hue != 0); + } + + return 0; +} + +static void ov9655_post_unset_alt(struct gspca_dev *gspca_dev) +{ + ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL); + ctrl_out(gspca_dev, 0x40, 1, 0x0061, 0x0000, 0, NULL); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,8 @@ +config USB_GL860 + tristate "GL860 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the GL860 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_gl860. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gl860/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,10 @@ +obj-$(CONFIG_USB_GL860) += gspca_gl860.o + +gspca_gl860-objs := gl860.o \ + gl860-mi1320.o \ + gl860-ov2640.o \ + gl860-ov9655.o \ + gl860-mi2020.o + +EXTRA_CFLAGS += -Idrivers/media/video/gspca + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gspca.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gspca.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gspca.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gspca.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2500 @@ +/* + * Main USB camera driver + * + * Copyright (C) 2008-2011 Jean-François Moine + * + * Camera button input handling by Márton Németh + * Copyright (C) 2009-2010 Márton Németh + * + * 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, or (at your + * option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define MODULE_NAME "gspca" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gspca.h" + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +#include +#include +#endif + +/* global values */ +#define DEF_NURBS 3 /* default number of URBs */ +#if DEF_NURBS > MAX_NURBS +#error "DEF_NURBS too big" +#endif + +MODULE_AUTHOR("Jean-François Moine "); +MODULE_DESCRIPTION("GSPCA USB Camera Driver"); +MODULE_LICENSE("GPL"); + +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 13, 0) + +#ifdef GSPCA_DEBUG +int gspca_debug = D_ERR | D_PROBE; +EXPORT_SYMBOL(gspca_debug); + +static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h) +{ + if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') { + PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d", + txt, + pixfmt & 0xff, + (pixfmt >> 8) & 0xff, + (pixfmt >> 16) & 0xff, + pixfmt >> 24, + w, h); + } else { + PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d", + txt, + pixfmt, + w, h); + } +} +#else +#define PDEBUG_MODE(txt, pixfmt, w, h) +#endif + +/* specific memory types - !! should be different from V4L2_MEMORY_xxx */ +#define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */ +#define GSPCA_MEMORY_READ 7 + +#define BUF_ALL_FLAGS (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE) + +/* + * VMA operations. + */ +static void gspca_vm_open(struct vm_area_struct *vma) +{ + struct gspca_frame *frame = vma->vm_private_data; + + frame->vma_use_count++; + frame->v4l2_buf.flags |= V4L2_BUF_FLAG_MAPPED; +} + +static void gspca_vm_close(struct vm_area_struct *vma) +{ + struct gspca_frame *frame = vma->vm_private_data; + + if (--frame->vma_use_count <= 0) + frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_MAPPED; +} + +static const struct vm_operations_struct gspca_vm_ops = { + .open = gspca_vm_open, + .close = gspca_vm_close, +}; + +/* + * Input and interrupt endpoint handling functions + */ +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static void int_irq(struct urb *urb) +{ + struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; + int ret; + + ret = urb->status; + switch (ret) { + case 0: + if (gspca_dev->sd_desc->int_pkt_scan(gspca_dev, + urb->transfer_buffer, urb->actual_length) < 0) { + PDEBUG(D_ERR, "Unknown packet received"); + } + break; + + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + /* Stop is requested either by software or hardware is gone, + * keep the ret value non-zero and don't resubmit later. + */ + break; + + default: + PDEBUG(D_ERR, "URB error %i, resubmitting", urb->status); + urb->status = 0; + ret = 0; + } + + if (ret == 0) { + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) + err("Resubmit URB failed with error %i", ret); + } +} + +static int gspca_input_connect(struct gspca_dev *dev) +{ + struct input_dev *input_dev; + int err = 0; + + dev->input_dev = NULL; + if (dev->sd_desc->int_pkt_scan || dev->sd_desc->other_input) { + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + usb_make_path(dev->dev, dev->phys, sizeof(dev->phys)); + strlcat(dev->phys, "/input0", sizeof(dev->phys)); + + input_dev->name = dev->sd_desc->name; + input_dev->phys = dev->phys; + + usb_to_input_id(dev->dev, &input_dev->id); + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA); + input_dev->dev.parent = &dev->dev->dev; + + err = input_register_device(input_dev); + if (err) { + err("Input device registration failed with error %i", + err); + input_dev->dev.parent = NULL; + input_free_device(input_dev); + } else { + dev->input_dev = input_dev; + } + } + + return err; +} + +static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev, + struct usb_endpoint_descriptor *ep) +{ + unsigned int buffer_len; + int interval; + struct urb *urb; + struct usb_device *dev; + void *buffer = NULL; + int ret = -EINVAL; + + buffer_len = le16_to_cpu(ep->wMaxPacketSize); + interval = ep->bInterval; + PDEBUG(D_CONF, "found int in endpoint: 0x%x, " + "buffer_len=%u, interval=%u", + ep->bEndpointAddress, buffer_len, interval); + + dev = gspca_dev->dev; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + ret = -ENOMEM; + goto error; + } + + buffer = usb_alloc_coherent(dev, buffer_len, + GFP_KERNEL, &urb->transfer_dma); + if (!buffer) { + ret = -ENOMEM; + goto error_buffer; + } + usb_fill_int_urb(urb, dev, + usb_rcvintpipe(dev, ep->bEndpointAddress), + buffer, buffer_len, + int_irq, (void *)gspca_dev, interval); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret < 0) { + PDEBUG(D_ERR, "submit int URB failed with error %i", ret); + goto error_submit; + } + gspca_dev->int_urb = urb; + return ret; + +error_submit: + usb_free_coherent(dev, + urb->transfer_buffer_length, + urb->transfer_buffer, + urb->transfer_dma); +error_buffer: + usb_free_urb(urb); +error: + return ret; +} + +static void gspca_input_create_urb(struct gspca_dev *gspca_dev) +{ + struct usb_interface *intf; + struct usb_host_interface *intf_desc; + struct usb_endpoint_descriptor *ep; + int i; + + if (gspca_dev->sd_desc->int_pkt_scan) { + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + intf_desc = intf->cur_altsetting; + for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { + ep = &intf_desc->endpoint[i].desc; + if (usb_endpoint_dir_in(ep) && + usb_endpoint_xfer_int(ep)) { + + alloc_and_submit_int_urb(gspca_dev, ep); + break; + } + } + } +} + +static void gspca_input_destroy_urb(struct gspca_dev *gspca_dev) +{ + struct urb *urb; + + urb = gspca_dev->int_urb; + if (urb) { + gspca_dev->int_urb = NULL; + usb_kill_urb(urb); + usb_free_coherent(gspca_dev->dev, + urb->transfer_buffer_length, + urb->transfer_buffer, + urb->transfer_dma); + usb_free_urb(urb); + } +} +#else +static inline void gspca_input_destroy_urb(struct gspca_dev *gspca_dev) +{ +} + +static inline void gspca_input_create_urb(struct gspca_dev *gspca_dev) +{ +} + +static inline int gspca_input_connect(struct gspca_dev *dev) +{ + return 0; +} +#endif + +/* + * fill a video frame from an URB and resubmit + */ +static void fill_frame(struct gspca_dev *gspca_dev, + struct urb *urb) +{ + u8 *data; /* address of data in the iso message */ + int i, len, st; + cam_pkt_op pkt_scan; + + if (urb->status != 0) { + if (urb->status == -ESHUTDOWN) + return; /* disconnection */ +#ifdef CONFIG_PM + if (gspca_dev->frozen) + return; +#endif + PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); + urb->status = 0; + goto resubmit; + } + pkt_scan = gspca_dev->sd_desc->pkt_scan; + for (i = 0; i < urb->number_of_packets; i++) { + len = urb->iso_frame_desc[i].actual_length; + + /* check the packet status and length */ + st = urb->iso_frame_desc[i].status; + if (st) { + err("ISOC data error: [%d] len=%d, status=%d", + i, len, st); + gspca_dev->last_packet_type = DISCARD_PACKET; + continue; + } + if (len == 0) { + if (gspca_dev->empty_packet == 0) + gspca_dev->empty_packet = 1; + continue; + } + + /* let the packet be analyzed by the subdriver */ + PDEBUG(D_PACK, "packet [%d] o:%d l:%d", + i, urb->iso_frame_desc[i].offset, len); + data = (u8 *) urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + pkt_scan(gspca_dev, data, len); + } + +resubmit: + /* resubmit the URB */ + st = usb_submit_urb(urb, GFP_ATOMIC); + if (st < 0) + err("usb_submit_urb() ret %d", st); +} + +/* + * ISOC message interrupt from the USB device + * + * Analyse each packet and call the subdriver for copy to the frame buffer. + */ +static void isoc_irq(struct urb *urb) +{ + struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; + + PDEBUG(D_PACK, "isoc irq"); + if (!gspca_dev->streaming) + return; + fill_frame(gspca_dev, urb); +} + +/* + * bulk message interrupt from the USB device + */ +static void bulk_irq(struct urb *urb) +{ + struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; + int st; + + PDEBUG(D_PACK, "bulk irq"); + if (!gspca_dev->streaming) + return; + switch (urb->status) { + case 0: + break; + case -ESHUTDOWN: + return; /* disconnection */ + default: +#ifdef CONFIG_PM + if (gspca_dev->frozen) + return; +#endif + PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); + urb->status = 0; + goto resubmit; + } + + PDEBUG(D_PACK, "packet l:%d", urb->actual_length); + gspca_dev->sd_desc->pkt_scan(gspca_dev, + urb->transfer_buffer, + urb->actual_length); + +resubmit: + /* resubmit the URB */ + if (gspca_dev->cam.bulk_nurbs != 0) { + st = usb_submit_urb(urb, GFP_ATOMIC); + if (st < 0) + err("usb_submit_urb() ret %d", st); + } +} + +/* + * add data to the current frame + * + * This function is called by the subdrivers at interrupt level. + * + * To build a frame, these ones must add + * - one FIRST_PACKET + * - 0 or many INTER_PACKETs + * - one LAST_PACKET + * DISCARD_PACKET invalidates the whole frame. + */ +void gspca_frame_add(struct gspca_dev *gspca_dev, + enum gspca_packet_type packet_type, + const u8 *data, + int len) +{ + struct gspca_frame *frame; + int i, j; + + PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len); + + if (packet_type == FIRST_PACKET) { + i = atomic_read(&gspca_dev->fr_i); + + /* if there are no queued buffer, discard the whole frame */ + if (i == atomic_read(&gspca_dev->fr_q)) { + gspca_dev->last_packet_type = DISCARD_PACKET; + gspca_dev->sequence++; + return; + } + j = gspca_dev->fr_queue[i]; + frame = &gspca_dev->frame[j]; + frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get()); + frame->v4l2_buf.sequence = gspca_dev->sequence++; + gspca_dev->image = frame->data; + gspca_dev->image_len = 0; + } else { + switch (gspca_dev->last_packet_type) { + case DISCARD_PACKET: + if (packet_type == LAST_PACKET) + gspca_dev->last_packet_type = packet_type; + return; + case LAST_PACKET: + return; + } + } + + /* append the packet to the frame buffer */ + if (len > 0) { + if (gspca_dev->image_len + len > gspca_dev->frsz) { + PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d", + gspca_dev->image_len + len, + gspca_dev->frsz); + packet_type = DISCARD_PACKET; + } else { +/* !! image is NULL only when last pkt is LAST or DISCARD + if (gspca_dev->image == NULL) { + err("gspca_frame_add() image == NULL"); + return; + } + */ + memcpy(gspca_dev->image + gspca_dev->image_len, + data, len); + gspca_dev->image_len += len; + } + } + gspca_dev->last_packet_type = packet_type; + + /* if last packet, invalidate packet concatenation until + * next first packet, wake up the application and advance + * in the queue */ + if (packet_type == LAST_PACKET) { + i = atomic_read(&gspca_dev->fr_i); + j = gspca_dev->fr_queue[i]; + frame = &gspca_dev->frame[j]; + frame->v4l2_buf.bytesused = gspca_dev->image_len; + frame->v4l2_buf.flags = (frame->v4l2_buf.flags + | V4L2_BUF_FLAG_DONE) + & ~V4L2_BUF_FLAG_QUEUED; + i = (i + 1) % GSPCA_MAX_FRAMES; + atomic_set(&gspca_dev->fr_i, i); + wake_up_interruptible(&gspca_dev->wq); /* event = new frame */ + PDEBUG(D_FRAM, "frame complete len:%d", + frame->v4l2_buf.bytesused); + gspca_dev->image = NULL; + gspca_dev->image_len = 0; + } +} +EXPORT_SYMBOL(gspca_frame_add); + +static int gspca_is_compressed(__u32 format) +{ + switch (format) { + case V4L2_PIX_FMT_MJPEG: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_SPCA561: + case V4L2_PIX_FMT_PAC207: + case V4L2_PIX_FMT_MR97310A: + return 1; + } + return 0; +} + +static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file, + enum v4l2_memory memory, unsigned int count) +{ + struct gspca_frame *frame; + unsigned int frsz; + int i; + + i = gspca_dev->curr_mode; + frsz = gspca_dev->cam.cam_mode[i].sizeimage; + PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz); + frsz = PAGE_ALIGN(frsz); + if (count >= GSPCA_MAX_FRAMES) + count = GSPCA_MAX_FRAMES - 1; + gspca_dev->frbuf = vmalloc_32(frsz * count); + if (!gspca_dev->frbuf) { + err("frame alloc failed"); + return -ENOMEM; + } + gspca_dev->capt_file = file; + gspca_dev->memory = memory; + gspca_dev->frsz = frsz; + gspca_dev->nframes = count; + for (i = 0; i < count; i++) { + frame = &gspca_dev->frame[i]; + frame->v4l2_buf.index = i; + frame->v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + frame->v4l2_buf.flags = 0; + frame->v4l2_buf.field = V4L2_FIELD_NONE; + frame->v4l2_buf.length = frsz; + frame->v4l2_buf.memory = memory; + frame->v4l2_buf.sequence = 0; + frame->data = gspca_dev->frbuf + i * frsz; + frame->v4l2_buf.m.offset = i * frsz; + } + atomic_set(&gspca_dev->fr_q, 0); + atomic_set(&gspca_dev->fr_i, 0); + gspca_dev->fr_o = 0; + return 0; +} + +static void frame_free(struct gspca_dev *gspca_dev) +{ + int i; + + PDEBUG(D_STREAM, "frame free"); + if (gspca_dev->frbuf != NULL) { + vfree(gspca_dev->frbuf); + gspca_dev->frbuf = NULL; + for (i = 0; i < gspca_dev->nframes; i++) + gspca_dev->frame[i].data = NULL; + } + gspca_dev->nframes = 0; + gspca_dev->frsz = 0; + gspca_dev->capt_file = NULL; + gspca_dev->memory = GSPCA_MEMORY_NO; +} + +static void destroy_urbs(struct gspca_dev *gspca_dev) +{ + struct urb *urb; + unsigned int i; + + PDEBUG(D_STREAM, "kill transfer"); + for (i = 0; i < MAX_NURBS; i++) { + urb = gspca_dev->urb[i]; + if (urb == NULL) + break; + + gspca_dev->urb[i] = NULL; + usb_kill_urb(urb); + if (urb->transfer_buffer != NULL) + usb_free_coherent(gspca_dev->dev, + urb->transfer_buffer_length, + urb->transfer_buffer, + urb->transfer_dma); + usb_free_urb(urb); + } +} + +static int gspca_set_alt0(struct gspca_dev *gspca_dev) +{ + int ret; + + if (gspca_dev->alt == 0) + return 0; + ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0); + if (ret < 0) + err("set alt 0 err %d", ret); + return ret; +} + +/* Note: both the queue and the usb locks should be held when calling this */ +static void gspca_stream_off(struct gspca_dev *gspca_dev) +{ + gspca_dev->streaming = 0; + if (gspca_dev->present) { + if (gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); + destroy_urbs(gspca_dev); + gspca_input_destroy_urb(gspca_dev); + gspca_set_alt0(gspca_dev); + gspca_input_create_urb(gspca_dev); + } + + /* always call stop0 to free the subdriver's resources */ + if (gspca_dev->sd_desc->stop0) + gspca_dev->sd_desc->stop0(gspca_dev); + PDEBUG(D_STREAM, "stream off OK"); +} + +/* + * look for an input transfer endpoint in an alternate setting + */ +static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, + int xfer) +{ + struct usb_host_endpoint *ep; + int i, attr; + + for (i = 0; i < alt->desc.bNumEndpoints; i++) { + ep = &alt->endpoint[i]; + attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (attr == xfer + && ep->desc.wMaxPacketSize != 0 + && usb_endpoint_dir_in(&ep->desc)) + return ep; + } + return NULL; +} + +/* + * look for an input (isoc or bulk) endpoint + * + * The endpoint is defined by the subdriver. + * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep). + * This routine may be called many times when the bandwidth is too small + * (the bandwidth is checked on urb submit). + */ +static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) +{ + struct usb_interface *intf; + struct usb_host_endpoint *ep; + int xfer, i, ret; + + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + ep = NULL; + xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK + : USB_ENDPOINT_XFER_ISOC; + i = gspca_dev->alt; /* previous alt setting */ + if (gspca_dev->cam.reverse_alts) { + while (++i < gspca_dev->nbalt) { + ep = alt_xfer(&intf->altsetting[i], xfer); + if (ep) + break; + } + } else { + while (--i >= 0) { + ep = alt_xfer(&intf->altsetting[i], xfer); + if (ep) + break; + } + } + if (ep == NULL) { + err("no transfer endpoint found"); + return NULL; + } + PDEBUG(D_STREAM, "use alt %d ep 0x%02x", + i, ep->desc.bEndpointAddress); + gspca_dev->alt = i; /* memorize the current alt setting */ + if (gspca_dev->nbalt > 1) { + ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); + if (ret < 0) { + err("set alt %d err %d", i, ret); + ep = NULL; + } + } + return ep; +} + +/* + * create the URBs for image transfer + */ +static int create_urbs(struct gspca_dev *gspca_dev, + struct usb_host_endpoint *ep) +{ + struct urb *urb; + int n, nurbs, i, psize, npkt, bsize; + + /* calculate the packet size and the number of packets */ + psize = le16_to_cpu(ep->desc.wMaxPacketSize); + + if (!gspca_dev->cam.bulk) { /* isoc */ + + /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ + if (gspca_dev->pkt_size == 0) + psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); + else + psize = gspca_dev->pkt_size; + npkt = gspca_dev->cam.npkt; + if (npkt == 0) + npkt = 32; /* default value */ + bsize = psize * npkt; + PDEBUG(D_STREAM, + "isoc %d pkts size %d = bsize:%d", + npkt, psize, bsize); + nurbs = DEF_NURBS; + } else { /* bulk */ + npkt = 0; + bsize = gspca_dev->cam.bulk_size; + if (bsize == 0) + bsize = psize; + PDEBUG(D_STREAM, "bulk bsize:%d", bsize); + if (gspca_dev->cam.bulk_nurbs != 0) + nurbs = gspca_dev->cam.bulk_nurbs; + else + nurbs = 1; + } + + for (n = 0; n < nurbs; n++) { + urb = usb_alloc_urb(npkt, GFP_KERNEL); + if (!urb) { + err("usb_alloc_urb failed"); + return -ENOMEM; + } + gspca_dev->urb[n] = urb; + urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, + bsize, + GFP_KERNEL, + &urb->transfer_dma); + + if (urb->transfer_buffer == NULL) { + err("usb_alloc_coherent failed"); + return -ENOMEM; + } + urb->dev = gspca_dev->dev; + urb->context = gspca_dev; + urb->transfer_buffer_length = bsize; + if (npkt != 0) { /* ISOC */ + urb->pipe = usb_rcvisocpipe(gspca_dev->dev, + ep->desc.bEndpointAddress); + urb->transfer_flags = URB_ISO_ASAP + | URB_NO_TRANSFER_DMA_MAP; + urb->interval = ep->desc.bInterval; + urb->complete = isoc_irq; + urb->number_of_packets = npkt; + for (i = 0; i < npkt; i++) { + urb->iso_frame_desc[i].length = psize; + urb->iso_frame_desc[i].offset = psize * i; + } + } else { /* bulk */ + urb->pipe = usb_rcvbulkpipe(gspca_dev->dev, + ep->desc.bEndpointAddress); + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + urb->complete = bulk_irq; + } + } + return 0; +} + +/* + * start the USB transfer + */ +static int gspca_init_transfer(struct gspca_dev *gspca_dev) +{ + struct usb_host_endpoint *ep; + struct urb *urb; + int n, ret; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + + if (!gspca_dev->present) { + ret = -ENODEV; + goto unlock; + } + + /* reset the streaming variables */ + gspca_dev->image = NULL; + gspca_dev->image_len = 0; + gspca_dev->last_packet_type = DISCARD_PACKET; + gspca_dev->sequence = 0; + + gspca_dev->usb_err = 0; + + /* set the higher alternate setting and + * loop until urb submit succeeds */ + if (gspca_dev->cam.reverse_alts) + gspca_dev->alt = 0; + else + gspca_dev->alt = gspca_dev->nbalt; + + if (gspca_dev->sd_desc->isoc_init) { + ret = gspca_dev->sd_desc->isoc_init(gspca_dev); + if (ret < 0) + goto unlock; + } + + gspca_input_destroy_urb(gspca_dev); + ep = get_ep(gspca_dev); + if (ep == NULL) { + ret = -EIO; + goto out; + } + for (;;) { + if (!gspca_dev->cam.no_urb_create) { + PDEBUG(D_STREAM, "init transfer alt %d", + gspca_dev->alt); + ret = create_urbs(gspca_dev, ep); + if (ret < 0) { + destroy_urbs(gspca_dev); + goto out; + } + } + + /* clear the bulk endpoint */ + if (gspca_dev->cam.bulk) + usb_clear_halt(gspca_dev->dev, + gspca_dev->urb[0]->pipe); + + /* start the cam */ + ret = gspca_dev->sd_desc->start(gspca_dev); + if (ret < 0) { + destroy_urbs(gspca_dev); + goto out; + } + gspca_dev->streaming = 1; + + /* some bulk transfers are started by the subdriver */ + if (gspca_dev->cam.bulk && gspca_dev->cam.bulk_nurbs == 0) + break; + + /* submit the URBs */ + for (n = 0; n < MAX_NURBS; n++) { + urb = gspca_dev->urb[n]; + if (urb == NULL) + break; + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret < 0) + break; + } + if (ret >= 0) + break; + gspca_stream_off(gspca_dev); + if (ret != -ENOSPC) { + err("usb_submit_urb alt %d err %d", + gspca_dev->alt, ret); + goto out; + } + + /* the bandwidth is not wide enough + * negotiate or try a lower alternate setting */ + PDEBUG(D_ERR|D_STREAM, + "bandwidth not wide enough - trying again"); + msleep(20); /* wait for kill complete */ + if (gspca_dev->sd_desc->isoc_nego) { + ret = gspca_dev->sd_desc->isoc_nego(gspca_dev); + if (ret < 0) + goto out; + } else { + ep = get_ep(gspca_dev); + if (ep == NULL) { + ret = -EIO; + goto out; + } + } + } +out: + gspca_input_create_urb(gspca_dev); +unlock: + mutex_unlock(&gspca_dev->usb_lock); + return ret; +} + +static void gspca_set_default_mode(struct gspca_dev *gspca_dev) +{ + struct gspca_ctrl *ctrl; + int i; + + i = gspca_dev->cam.nmodes - 1; /* take the highest mode */ + gspca_dev->curr_mode = i; + gspca_dev->width = gspca_dev->cam.cam_mode[i].width; + gspca_dev->height = gspca_dev->cam.cam_mode[i].height; + gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat; + + /* set the current control values to their default values + * which may have changed in sd_init() */ + ctrl = gspca_dev->cam.ctrls; + if (ctrl != NULL) { + for (i = 0; + i < gspca_dev->sd_desc->nctrls; + i++, ctrl++) + ctrl->val = ctrl->def; + } +} + +static int wxh_to_mode(struct gspca_dev *gspca_dev, + int width, int height) +{ + int i; + + for (i = gspca_dev->cam.nmodes; --i > 0; ) { + if (width >= gspca_dev->cam.cam_mode[i].width + && height >= gspca_dev->cam.cam_mode[i].height) + break; + } + return i; +} + +/* + * search a mode with the right pixel format + */ +static int gspca_get_mode(struct gspca_dev *gspca_dev, + int mode, + int pixfmt) +{ + int modeU, modeD; + + modeU = modeD = mode; + while ((modeU < gspca_dev->cam.nmodes) || modeD >= 0) { + if (--modeD >= 0) { + if (gspca_dev->cam.cam_mode[modeD].pixelformat + == pixfmt) + return modeD; + } + if (++modeU < gspca_dev->cam.nmodes) { + if (gspca_dev->cam.cam_mode[modeU].pixelformat + == pixfmt) + return modeU; + } + } + return -EINVAL; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + int ret; + struct gspca_dev *gspca_dev = priv; + + if (!gspca_dev->sd_desc->get_chip_ident) + return -EINVAL; + + if (!gspca_dev->sd_desc->get_register) + return -EINVAL; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + gspca_dev->usb_err = 0; + if (gspca_dev->present) + ret = gspca_dev->sd_desc->get_register(gspca_dev, reg); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + + return ret; +} + +static int vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + int ret; + struct gspca_dev *gspca_dev = priv; + + if (!gspca_dev->sd_desc->get_chip_ident) + return -EINVAL; + + if (!gspca_dev->sd_desc->set_register) + return -EINVAL; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + gspca_dev->usb_err = 0; + if (gspca_dev->present) + ret = gspca_dev->sd_desc->set_register(gspca_dev, reg); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + + return ret; +} +#endif + +static int vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + int ret; + struct gspca_dev *gspca_dev = priv; + + if (!gspca_dev->sd_desc->get_chip_ident) + return -EINVAL; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + gspca_dev->usb_err = 0; + if (gspca_dev->present) + ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + + return ret; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *fmtdesc) +{ + struct gspca_dev *gspca_dev = priv; + int i, j, index; + __u32 fmt_tb[8]; + + /* give an index to each format */ + index = 0; + j = 0; + for (i = gspca_dev->cam.nmodes; --i >= 0; ) { + fmt_tb[index] = gspca_dev->cam.cam_mode[i].pixelformat; + j = 0; + for (;;) { + if (fmt_tb[j] == fmt_tb[index]) + break; + j++; + } + if (j == index) { + if (fmtdesc->index == index) + break; /* new format */ + index++; + if (index >= ARRAY_SIZE(fmt_tb)) + return -EINVAL; + } + } + if (i < 0) + return -EINVAL; /* no more format */ + + fmtdesc->pixelformat = fmt_tb[index]; + if (gspca_is_compressed(fmt_tb[index])) + fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED; + fmtdesc->description[0] = fmtdesc->pixelformat & 0xff; + fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff; + fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff; + fmtdesc->description[3] = fmtdesc->pixelformat >> 24; + fmtdesc->description[4] = '\0'; + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct gspca_dev *gspca_dev = priv; + int mode; + + mode = gspca_dev->curr_mode; + memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode], + sizeof fmt->fmt.pix); + return 0; +} + +static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, + struct v4l2_format *fmt) +{ + int w, h, mode, mode2; + + w = fmt->fmt.pix.width; + h = fmt->fmt.pix.height; + +#ifdef GSPCA_DEBUG + if (gspca_debug & D_CONF) + PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); +#endif + /* search the closest mode for width and height */ + mode = wxh_to_mode(gspca_dev, w, h); + + /* OK if right palette */ + if (gspca_dev->cam.cam_mode[mode].pixelformat + != fmt->fmt.pix.pixelformat) { + + /* else, search the closest mode with the same pixel format */ + mode2 = gspca_get_mode(gspca_dev, mode, + fmt->fmt.pix.pixelformat); + if (mode2 >= 0) + mode = mode2; +/* else + ; * no chance, return this mode */ + } + memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode], + sizeof fmt->fmt.pix); + return mode; /* used when s_fmt */ +} + +static int vidioc_try_fmt_vid_cap(struct file *file, + void *priv, + struct v4l2_format *fmt) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + ret = try_fmt_vid_cap(gspca_dev, fmt); + if (ret < 0) + return ret; + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + ret = try_fmt_vid_cap(gspca_dev, fmt); + if (ret < 0) + goto out; + + if (gspca_dev->nframes != 0 + && fmt->fmt.pix.sizeimage > gspca_dev->frsz) { + ret = -EINVAL; + goto out; + } + + if (ret == gspca_dev->curr_mode) { + ret = 0; + goto out; /* same mode */ + } + + if (gspca_dev->streaming) { + ret = -EBUSY; + goto out; + } + gspca_dev->width = fmt->fmt.pix.width; + gspca_dev->height = fmt->fmt.pix.height; + gspca_dev->pixfmt = fmt->fmt.pix.pixelformat; + gspca_dev->curr_mode = ret; + + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct gspca_dev *gspca_dev = priv; + int i; + __u32 index = 0; + + for (i = 0; i < gspca_dev->cam.nmodes; i++) { + if (fsize->pixel_format != + gspca_dev->cam.cam_mode[i].pixelformat) + continue; + + if (fsize->index == index) { + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = + gspca_dev->cam.cam_mode[i].width; + fsize->discrete.height = + gspca_dev->cam.cam_mode[i].height; + return 0; + } + index++; + } + + return -EINVAL; +} + +static int vidioc_enum_frameintervals(struct file *filp, void *priv, + struct v4l2_frmivalenum *fival) +{ + struct gspca_dev *gspca_dev = priv; + int mode = wxh_to_mode(gspca_dev, fival->width, fival->height); + __u32 i; + + if (gspca_dev->cam.mode_framerates == NULL || + gspca_dev->cam.mode_framerates[mode].nrates == 0) + return -EINVAL; + + if (fival->pixel_format != + gspca_dev->cam.cam_mode[mode].pixelformat) + return -EINVAL; + + for (i = 0; i < gspca_dev->cam.mode_framerates[mode].nrates; i++) { + if (fival->index == i) { + fival->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fival->discrete.numerator = 1; + fival->discrete.denominator = + gspca_dev->cam.mode_framerates[mode].rates[i]; + return 0; + } + } + + return -EINVAL; +} + +static void gspca_release(struct video_device *vfd) +{ + struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); + + PDEBUG(D_PROBE, "%s released", + video_device_node_name(&gspca_dev->vdev)); + + kfree(gspca_dev->usb_buf); + kfree(gspca_dev); +} + +static int dev_open(struct file *file) +{ + struct gspca_dev *gspca_dev; + + PDEBUG(D_STREAM, "[%s] open", current->comm); + gspca_dev = (struct gspca_dev *) video_devdata(file); + if (!gspca_dev->present) + return -ENODEV; + + /* protect the subdriver against rmmod */ + if (!try_module_get(gspca_dev->module)) + return -ENODEV; + + file->private_data = gspca_dev; +#ifdef GSPCA_DEBUG + /* activate the v4l2 debug */ + if (gspca_debug & D_V4L2) + gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL + | V4L2_DEBUG_IOCTL_ARG; + else + gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL + | V4L2_DEBUG_IOCTL_ARG); +#endif + return 0; +} + +static int dev_close(struct file *file) +{ + struct gspca_dev *gspca_dev = file->private_data; + + PDEBUG(D_STREAM, "[%s] close", current->comm); + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + /* if the file did the capture, free the streaming resources */ + if (gspca_dev->capt_file == file) { + if (gspca_dev->streaming) { + mutex_lock(&gspca_dev->usb_lock); + gspca_dev->usb_err = 0; + gspca_stream_off(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + } + frame_free(gspca_dev); + } + file->private_data = NULL; + module_put(gspca_dev->module); + mutex_unlock(&gspca_dev->queue_lock); + + PDEBUG(D_STREAM, "close done"); + + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + /* protect the access to the usb device */ + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (!gspca_dev->present) { + ret = -ENODEV; + goto out; + } + strncpy((char *) cap->driver, gspca_dev->sd_desc->name, + sizeof cap->driver); + if (gspca_dev->dev->product != NULL) { + strncpy((char *) cap->card, gspca_dev->dev->product, + sizeof cap->card); + } else { + snprintf((char *) cap->card, sizeof cap->card, + "USB Camera (%04x:%04x)", + le16_to_cpu(gspca_dev->dev->descriptor.idVendor), + le16_to_cpu(gspca_dev->dev->descriptor.idProduct)); + } + usb_make_path(gspca_dev->dev, (char *) cap->bus_info, + sizeof(cap->bus_info)); + cap->version = DRIVER_VERSION_NUMBER; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_STREAMING + | V4L2_CAP_READWRITE; + ret = 0; +out: + mutex_unlock(&gspca_dev->usb_lock); + return ret; +} + +static int get_ctrl(struct gspca_dev *gspca_dev, + int id) +{ + const struct ctrl *ctrls; + int i; + + for (i = 0, ctrls = gspca_dev->sd_desc->ctrls; + i < gspca_dev->sd_desc->nctrls; + i++, ctrls++) { + if (gspca_dev->ctrl_dis & (1 << i)) + continue; + if (id == ctrls->qctrl.id) + return i; + } + return -1; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *q_ctrl) +{ + struct gspca_dev *gspca_dev = priv; + const struct ctrl *ctrls; + struct gspca_ctrl *gspca_ctrl; + int i, idx; + u32 id; + + id = q_ctrl->id; + if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { + id &= V4L2_CTRL_ID_MASK; + id++; + idx = -1; + for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { + if (gspca_dev->ctrl_dis & (1 << i)) + continue; + if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id) + continue; + if (idx >= 0 + && gspca_dev->sd_desc->ctrls[i].qctrl.id + > gspca_dev->sd_desc->ctrls[idx].qctrl.id) + continue; + idx = i; + } + } else { + idx = get_ctrl(gspca_dev, id); + } + if (idx < 0) + return -EINVAL; + ctrls = &gspca_dev->sd_desc->ctrls[idx]; + memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl); + if (gspca_dev->cam.ctrls != NULL) { + gspca_ctrl = &gspca_dev->cam.ctrls[idx]; + q_ctrl->default_value = gspca_ctrl->def; + q_ctrl->minimum = gspca_ctrl->min; + q_ctrl->maximum = gspca_ctrl->max; + } + if (gspca_dev->ctrl_inac & (1 << idx)) + q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct gspca_dev *gspca_dev = priv; + const struct ctrl *ctrls; + struct gspca_ctrl *gspca_ctrl; + int idx, ret; + + idx = get_ctrl(gspca_dev, ctrl->id); + if (idx < 0) + return -EINVAL; + if (gspca_dev->ctrl_inac & (1 << idx)) + return -EINVAL; + ctrls = &gspca_dev->sd_desc->ctrls[idx]; + if (gspca_dev->cam.ctrls != NULL) { + gspca_ctrl = &gspca_dev->cam.ctrls[idx]; + if (ctrl->value < gspca_ctrl->min + || ctrl->value > gspca_ctrl->max) + return -ERANGE; + } else { + gspca_ctrl = NULL; + if (ctrl->value < ctrls->qctrl.minimum + || ctrl->value > ctrls->qctrl.maximum) + return -ERANGE; + } + PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (!gspca_dev->present) { + ret = -ENODEV; + goto out; + } + gspca_dev->usb_err = 0; + if (ctrls->set != NULL) { + ret = ctrls->set(gspca_dev, ctrl->value); + goto out; + } + if (gspca_ctrl != NULL) { + gspca_ctrl->val = ctrl->value; + if (ctrls->set_control != NULL + && gspca_dev->streaming) + ctrls->set_control(gspca_dev); + } + ret = gspca_dev->usb_err; +out: + mutex_unlock(&gspca_dev->usb_lock); + return ret; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct gspca_dev *gspca_dev = priv; + const struct ctrl *ctrls; + int idx, ret; + + idx = get_ctrl(gspca_dev, ctrl->id); + if (idx < 0) + return -EINVAL; + ctrls = &gspca_dev->sd_desc->ctrls[idx]; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (!gspca_dev->present) { + ret = -ENODEV; + goto out; + } + gspca_dev->usb_err = 0; + if (ctrls->get != NULL) { + ret = ctrls->get(gspca_dev, &ctrl->value); + goto out; + } + if (gspca_dev->cam.ctrls != NULL) + ctrl->value = gspca_dev->cam.ctrls[idx].val; + ret = 0; +out: + mutex_unlock(&gspca_dev->usb_lock); + return ret; +} + +static int vidioc_querymenu(struct file *file, void *priv, + struct v4l2_querymenu *qmenu) +{ + struct gspca_dev *gspca_dev = priv; + + if (!gspca_dev->sd_desc->querymenu) + return -EINVAL; + return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu); +} + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + struct gspca_dev *gspca_dev = priv; + + if (input->index != 0) + return -EINVAL; + input->type = V4L2_INPUT_TYPE_CAMERA; + input->status = gspca_dev->cam.input_flags; + strncpy(input->name, gspca_dev->sd_desc->name, + sizeof input->name); + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i > 0) + return -EINVAL; + return (0); +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct gspca_dev *gspca_dev = priv; + int i, ret = 0, streaming; + + i = rb->memory; /* (avoid compilation warning) */ + switch (i) { + case GSPCA_MEMORY_READ: /* (internal call) */ + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_USERPTR: + break; + default: + return -EINVAL; + } + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + if (gspca_dev->memory != GSPCA_MEMORY_NO + && gspca_dev->memory != GSPCA_MEMORY_READ + && gspca_dev->memory != rb->memory) { + ret = -EBUSY; + goto out; + } + + /* only one file may do the capture */ + if (gspca_dev->capt_file != NULL + && gspca_dev->capt_file != file) { + ret = -EBUSY; + goto out; + } + + /* if allocated, the buffers must not be mapped */ + for (i = 0; i < gspca_dev->nframes; i++) { + if (gspca_dev->frame[i].vma_use_count) { + ret = -EBUSY; + goto out; + } + } + + /* stop streaming */ + streaming = gspca_dev->streaming; + if (streaming) { + mutex_lock(&gspca_dev->usb_lock); + gspca_dev->usb_err = 0; + gspca_stream_off(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + + /* Don't restart the stream when switching from read + * to mmap mode */ + if (gspca_dev->memory == GSPCA_MEMORY_READ) + streaming = 0; + } + + /* free the previous allocated buffers, if any */ + if (gspca_dev->nframes != 0) + frame_free(gspca_dev); + if (rb->count == 0) /* unrequest */ + goto out; + ret = frame_alloc(gspca_dev, file, rb->memory, rb->count); + if (ret == 0) { + rb->count = gspca_dev->nframes; + if (streaming) + ret = gspca_init_transfer(gspca_dev); + } +out: + mutex_unlock(&gspca_dev->queue_lock); + PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count); + return ret; +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *v4l2_buf) +{ + struct gspca_dev *gspca_dev = priv; + struct gspca_frame *frame; + + if (v4l2_buf->index < 0 + || v4l2_buf->index >= gspca_dev->nframes) + return -EINVAL; + + frame = &gspca_dev->frame[v4l2_buf->index]; + memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); + return 0; +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + /* check the capture file */ + if (gspca_dev->capt_file != file) { + ret = -EBUSY; + goto out; + } + + if (gspca_dev->nframes == 0 + || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) { + ret = -EINVAL; + goto out; + } + if (!gspca_dev->streaming) { + ret = gspca_init_transfer(gspca_dev); + if (ret < 0) + goto out; + } +#ifdef GSPCA_DEBUG + if (gspca_debug & D_STREAM) { + PDEBUG_MODE("stream on OK", + gspca_dev->pixfmt, + gspca_dev->width, + gspca_dev->height); + } +#endif + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + if (!gspca_dev->streaming) { + ret = 0; + goto out; + } + + /* check the capture file */ + if (gspca_dev->capt_file != file) { + ret = -EBUSY; + goto out; + } + + /* stop streaming */ + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { + ret = -ERESTARTSYS; + goto out; + } + gspca_dev->usb_err = 0; + gspca_stream_off(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + /* In case another thread is waiting in dqbuf */ + wake_up_interruptible(&gspca_dev->wq); + + /* empty the transfer queues */ + atomic_set(&gspca_dev->fr_q, 0); + atomic_set(&gspca_dev->fr_i, 0); + gspca_dev->fr_o = 0; + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +static int vidioc_g_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *jpegcomp) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + if (!gspca_dev->sd_desc->get_jcomp) + return -EINVAL; + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + gspca_dev->usb_err = 0; + if (gspca_dev->present) + ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + return ret; +} + +static int vidioc_s_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *jpegcomp) +{ + struct gspca_dev *gspca_dev = priv; + int ret; + + if (!gspca_dev->sd_desc->set_jcomp) + return -EINVAL; + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + gspca_dev->usb_err = 0; + if (gspca_dev->present) + ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + return ret; +} + +static int vidioc_g_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parm) +{ + struct gspca_dev *gspca_dev = priv; + + parm->parm.capture.readbuffers = gspca_dev->nbufread; + + if (gspca_dev->sd_desc->get_streamparm) { + int ret; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (gspca_dev->present) { + gspca_dev->usb_err = 0; + gspca_dev->sd_desc->get_streamparm(gspca_dev, parm); + ret = gspca_dev->usb_err; + } else { + ret = -ENODEV; + } + mutex_unlock(&gspca_dev->usb_lock); + return ret; + } + + return 0; +} + +static int vidioc_s_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parm) +{ + struct gspca_dev *gspca_dev = priv; + int n; + + n = parm->parm.capture.readbuffers; + if (n == 0 || n >= GSPCA_MAX_FRAMES) + parm->parm.capture.readbuffers = gspca_dev->nbufread; + else + gspca_dev->nbufread = n; + + if (gspca_dev->sd_desc->set_streamparm) { + int ret; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (gspca_dev->present) { + gspca_dev->usb_err = 0; + gspca_dev->sd_desc->set_streamparm(gspca_dev, parm); + ret = gspca_dev->usb_err; + } else { + ret = -ENODEV; + } + mutex_unlock(&gspca_dev->usb_lock); + return ret; + } + + return 0; +} + +static int dev_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct gspca_dev *gspca_dev = file->private_data; + struct gspca_frame *frame; + struct page *page; + unsigned long addr, start, size; + int i, ret; + + start = vma->vm_start; + size = vma->vm_end - vma->vm_start; + PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size); + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + if (!gspca_dev->present) { + ret = -ENODEV; + goto out; + } + if (gspca_dev->capt_file != file) { + ret = -EINVAL; + goto out; + } + + frame = NULL; + for (i = 0; i < gspca_dev->nframes; ++i) { + if (gspca_dev->frame[i].v4l2_buf.memory != V4L2_MEMORY_MMAP) { + PDEBUG(D_STREAM, "mmap bad memory type"); + break; + } + if ((gspca_dev->frame[i].v4l2_buf.m.offset >> PAGE_SHIFT) + == vma->vm_pgoff) { + frame = &gspca_dev->frame[i]; + break; + } + } + if (frame == NULL) { + PDEBUG(D_STREAM, "mmap no frame buffer found"); + ret = -EINVAL; + goto out; + } + if (size != frame->v4l2_buf.length) { + PDEBUG(D_STREAM, "mmap bad size"); + ret = -EINVAL; + goto out; + } + + /* + * - VM_IO marks the area as being a mmaped region for I/O to a + * device. It also prevents the region from being core dumped. + */ + vma->vm_flags |= VM_IO; + + addr = (unsigned long) frame->data; + while (size > 0) { + page = vmalloc_to_page((void *) addr); + ret = vm_insert_page(vma, start, page); + if (ret < 0) + goto out; + start += PAGE_SIZE; + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + vma->vm_ops = &gspca_vm_ops; + vma->vm_private_data = frame; + gspca_vm_open(vma); + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +static int frame_ready_nolock(struct gspca_dev *gspca_dev, struct file *file, + enum v4l2_memory memory) +{ + if (!gspca_dev->present) + return -ENODEV; + if (gspca_dev->capt_file != file || gspca_dev->memory != memory || + !gspca_dev->streaming) + return -EINVAL; + + /* check if a frame is ready */ + return gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i); +} + +static int frame_ready(struct gspca_dev *gspca_dev, struct file *file, + enum v4l2_memory memory) +{ + int ret; + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + ret = frame_ready_nolock(gspca_dev, file, memory); + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +/* + * dequeue a video buffer + * + * If nonblock_ing is false, block until a buffer is available. + */ +static int vidioc_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *v4l2_buf) +{ + struct gspca_dev *gspca_dev = priv; + struct gspca_frame *frame; + int i, j, ret; + + PDEBUG(D_FRAM, "dqbuf"); + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + for (;;) { + ret = frame_ready_nolock(gspca_dev, file, v4l2_buf->memory); + if (ret < 0) + goto out; + if (ret > 0) + break; + + mutex_unlock(&gspca_dev->queue_lock); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + /* wait till a frame is ready */ + ret = wait_event_interruptible_timeout(gspca_dev->wq, + frame_ready(gspca_dev, file, v4l2_buf->memory), + msecs_to_jiffies(3000)); + if (ret < 0) + return ret; + if (ret == 0) + return -EIO; + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + } + + i = gspca_dev->fr_o; + j = gspca_dev->fr_queue[i]; + frame = &gspca_dev->frame[j]; + + gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES; + + if (gspca_dev->sd_desc->dq_callback) { + mutex_lock(&gspca_dev->usb_lock); + gspca_dev->usb_err = 0; + if (gspca_dev->present) + gspca_dev->sd_desc->dq_callback(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + } + + frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; + memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); + PDEBUG(D_FRAM, "dqbuf %d", j); + ret = 0; + + if (gspca_dev->memory == V4L2_MEMORY_USERPTR) { + if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr, + frame->data, + frame->v4l2_buf.bytesused)) { + PDEBUG(D_ERR|D_STREAM, + "dqbuf cp to user failed"); + ret = -EFAULT; + } + } +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +/* + * queue a video buffer + * + * Attempting to queue a buffer that has already been + * queued will return -EINVAL. + */ +static int vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *v4l2_buf) +{ + struct gspca_dev *gspca_dev = priv; + struct gspca_frame *frame; + int i, index, ret; + + PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index); + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + index = v4l2_buf->index; + if ((unsigned) index >= gspca_dev->nframes) { + PDEBUG(D_FRAM, + "qbuf idx %d >= %d", index, gspca_dev->nframes); + ret = -EINVAL; + goto out; + } + if (v4l2_buf->memory != gspca_dev->memory) { + PDEBUG(D_FRAM, "qbuf bad memory type"); + ret = -EINVAL; + goto out; + } + + frame = &gspca_dev->frame[index]; + if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) { + PDEBUG(D_FRAM, "qbuf bad state"); + ret = -EINVAL; + goto out; + } + + frame->v4l2_buf.flags |= V4L2_BUF_FLAG_QUEUED; + + if (frame->v4l2_buf.memory == V4L2_MEMORY_USERPTR) { + frame->v4l2_buf.m.userptr = v4l2_buf->m.userptr; + frame->v4l2_buf.length = v4l2_buf->length; + } + + /* put the buffer in the 'queued' queue */ + i = atomic_read(&gspca_dev->fr_q); + gspca_dev->fr_queue[i] = index; + atomic_set(&gspca_dev->fr_q, (i + 1) % GSPCA_MAX_FRAMES); + + v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; + v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE; + ret = 0; +out: + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + +/* + * allocate the resources for read() + */ +static int read_alloc(struct gspca_dev *gspca_dev, + struct file *file) +{ + struct v4l2_buffer v4l2_buf; + int i, ret; + + PDEBUG(D_STREAM, "read alloc"); + if (gspca_dev->nframes == 0) { + struct v4l2_requestbuffers rb; + + memset(&rb, 0, sizeof rb); + rb.count = gspca_dev->nbufread; + rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + rb.memory = GSPCA_MEMORY_READ; + ret = vidioc_reqbufs(file, gspca_dev, &rb); + if (ret != 0) { + PDEBUG(D_STREAM, "read reqbuf err %d", ret); + return ret; + } + memset(&v4l2_buf, 0, sizeof v4l2_buf); + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2_buf.memory = GSPCA_MEMORY_READ; + for (i = 0; i < gspca_dev->nbufread; i++) { + v4l2_buf.index = i; + ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf); + if (ret != 0) { + PDEBUG(D_STREAM, "read qbuf err: %d", ret); + return ret; + } + } + gspca_dev->memory = GSPCA_MEMORY_READ; + } + + /* start streaming */ + ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret != 0) + PDEBUG(D_STREAM, "read streamon err %d", ret); + return ret; +} + +static unsigned int dev_poll(struct file *file, poll_table *wait) +{ + struct gspca_dev *gspca_dev = file->private_data; + int ret; + + PDEBUG(D_FRAM, "poll"); + + poll_wait(file, &gspca_dev->wq, wait); + + /* if reqbufs is not done, the user would use read() */ + if (gspca_dev->memory == GSPCA_MEMORY_NO) { + ret = read_alloc(gspca_dev, file); + if (ret != 0) + return POLLERR; + } + + if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) + return POLLERR; + + /* check if an image has been received */ + if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i)) + ret = POLLIN | POLLRDNORM; /* yes */ + else + ret = 0; + mutex_unlock(&gspca_dev->queue_lock); + if (!gspca_dev->present) + return POLLHUP; + return ret; +} + +static ssize_t dev_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct gspca_dev *gspca_dev = file->private_data; + struct gspca_frame *frame; + struct v4l2_buffer v4l2_buf; + struct timeval timestamp; + int n, ret, ret2; + + PDEBUG(D_FRAM, "read (%zd)", count); + if (!gspca_dev->present) + return -ENODEV; + if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */ + ret = read_alloc(gspca_dev, file); + if (ret != 0) + return ret; + } + + /* get a frame */ + timestamp = ktime_to_timeval(ktime_get()); + timestamp.tv_sec--; + n = 2; + for (;;) { + memset(&v4l2_buf, 0, sizeof v4l2_buf); + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2_buf.memory = GSPCA_MEMORY_READ; + ret = vidioc_dqbuf(file, gspca_dev, &v4l2_buf); + if (ret != 0) { + PDEBUG(D_STREAM, "read dqbuf err %d", ret); + return ret; + } + + /* if the process slept for more than 1 second, + * get a newer frame */ + frame = &gspca_dev->frame[v4l2_buf.index]; + if (--n < 0) + break; /* avoid infinite loop */ + if (frame->v4l2_buf.timestamp.tv_sec >= timestamp.tv_sec) + break; + ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf); + if (ret != 0) { + PDEBUG(D_STREAM, "read qbuf err %d", ret); + return ret; + } + } + + /* copy the frame */ + if (count > frame->v4l2_buf.bytesused) + count = frame->v4l2_buf.bytesused; + ret = copy_to_user(data, frame->data, count); + if (ret != 0) { + PDEBUG(D_ERR|D_STREAM, + "read cp to user lack %d / %zd", ret, count); + ret = -EFAULT; + goto out; + } + ret = count; +out: + /* in each case, requeue the buffer */ + ret2 = vidioc_qbuf(file, gspca_dev, &v4l2_buf); + if (ret2 != 0) + return ret2; + return ret; +} + +static struct v4l2_file_operations dev_fops = { + .owner = THIS_MODULE, + .open = dev_open, + .release = dev_close, + .read = dev_read, + .mmap = dev_mmap, + .unlocked_ioctl = video_ioctl2, + .poll = dev_poll, +}; + +static const struct v4l2_ioctl_ops dev_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_streamon = vidioc_streamon, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_querymenu = vidioc_querymenu, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_jpegcomp = vidioc_g_jpegcomp, + .vidioc_s_jpegcomp = vidioc_s_jpegcomp, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_s_parm = vidioc_s_parm, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_enum_frameintervals = vidioc_enum_frameintervals, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif + .vidioc_g_chip_ident = vidioc_g_chip_ident, +}; + +static const struct video_device gspca_template = { + .name = "gspca main driver", + .fops = &dev_fops, + .ioctl_ops = &dev_ioctl_ops, + .release = gspca_release, +}; + +/* initialize the controls */ +static void ctrls_init(struct gspca_dev *gspca_dev) +{ + struct gspca_ctrl *ctrl; + int i; + + for (i = 0, ctrl = gspca_dev->cam.ctrls; + i < gspca_dev->sd_desc->nctrls; + i++, ctrl++) { + ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value; + ctrl->val = ctrl->def; + ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum; + ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum; + } +} + +/* + * probe and create a new gspca device + * + * This function must be called by the sub-driver when it is + * called for probing a new device. + */ +int gspca_dev_probe2(struct usb_interface *intf, + const struct usb_device_id *id, + const struct sd_desc *sd_desc, + int dev_size, + struct module *module) +{ + struct gspca_dev *gspca_dev; + struct usb_device *dev = interface_to_usbdev(intf); + int ret; + + PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct); + + /* create the device */ + if (dev_size < sizeof *gspca_dev) + dev_size = sizeof *gspca_dev; + gspca_dev = kzalloc(dev_size, GFP_KERNEL); + if (!gspca_dev) { + err("couldn't kzalloc gspca struct"); + return -ENOMEM; + } + gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); + if (!gspca_dev->usb_buf) { + err("out of memory"); + ret = -ENOMEM; + goto out; + } + gspca_dev->dev = dev; + gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber; + gspca_dev->nbalt = intf->num_altsetting; + + /* check if any audio device */ + if (dev->config->desc.bNumInterfaces != 1) { + int i; + struct usb_interface *intf2; + + for (i = 0; i < dev->config->desc.bNumInterfaces; i++) { + intf2 = dev->config->interface[i]; + if (intf2 != NULL + && intf2->altsetting != NULL + && intf2->altsetting->desc.bInterfaceClass == + USB_CLASS_AUDIO) { + gspca_dev->audio = 1; + break; + } + } + } + + gspca_dev->sd_desc = sd_desc; + gspca_dev->nbufread = 2; + gspca_dev->empty_packet = -1; /* don't check the empty packets */ + + /* configure the subdriver and initialize the USB device */ + ret = sd_desc->config(gspca_dev, id); + if (ret < 0) + goto out; + if (gspca_dev->cam.ctrls != NULL) + ctrls_init(gspca_dev); + ret = sd_desc->init(gspca_dev); + if (ret < 0) + goto out; + gspca_set_default_mode(gspca_dev); + + ret = gspca_input_connect(gspca_dev); + if (ret) + goto out; + + mutex_init(&gspca_dev->usb_lock); + mutex_init(&gspca_dev->queue_lock); + init_waitqueue_head(&gspca_dev->wq); + + /* init video stuff */ + memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template); + gspca_dev->vdev.parent = &intf->dev; + gspca_dev->module = module; + gspca_dev->present = 1; + ret = video_register_device(&gspca_dev->vdev, + VFL_TYPE_GRABBER, + -1); + if (ret < 0) { + err("video_register_device err %d", ret); + goto out; + } + + usb_set_intfdata(intf, gspca_dev); + PDEBUG(D_PROBE, "%s created", video_device_node_name(&gspca_dev->vdev)); + + gspca_input_create_urb(gspca_dev); + + return 0; +out: +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + if (gspca_dev->input_dev) + input_unregister_device(gspca_dev->input_dev); +#endif + kfree(gspca_dev->usb_buf); + kfree(gspca_dev); + return ret; +} +EXPORT_SYMBOL(gspca_dev_probe2); + +/* same function as the previous one, but check the interface */ +int gspca_dev_probe(struct usb_interface *intf, + const struct usb_device_id *id, + const struct sd_desc *sd_desc, + int dev_size, + struct module *module) +{ + struct usb_device *dev = interface_to_usbdev(intf); + + /* we don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) { + err("%04x:%04x too many config", + id->idVendor, id->idProduct); + return -ENODEV; + } + + /* the USB video interface must be the first one */ + if (dev->config->desc.bNumInterfaces != 1 + && intf->cur_altsetting->desc.bInterfaceNumber != 0) + return -ENODEV; + + return gspca_dev_probe2(intf, id, sd_desc, dev_size, module); +} +EXPORT_SYMBOL(gspca_dev_probe); + +/* + * USB disconnection + * + * This function must be called by the sub-driver + * when the device disconnects, after the specific resources are freed. + */ +void gspca_disconnect(struct usb_interface *intf) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + struct input_dev *input_dev; +#endif + + PDEBUG(D_PROBE, "%s disconnect", + video_device_node_name(&gspca_dev->vdev)); + mutex_lock(&gspca_dev->usb_lock); + + gspca_dev->present = 0; + wake_up_interruptible(&gspca_dev->wq); + + destroy_urbs(gspca_dev); + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + gspca_input_destroy_urb(gspca_dev); + input_dev = gspca_dev->input_dev; + if (input_dev) { + gspca_dev->input_dev = NULL; + input_unregister_device(input_dev); + } +#endif + + /* the device is freed at exit of this function */ + gspca_dev->dev = NULL; + mutex_unlock(&gspca_dev->usb_lock); + + usb_set_intfdata(intf, NULL); + + /* release the device */ + /* (this will call gspca_release() immediately or on last close) */ + video_unregister_device(&gspca_dev->vdev); + +/* PDEBUG(D_PROBE, "disconnect complete"); */ +} +EXPORT_SYMBOL(gspca_disconnect); + +#ifdef CONFIG_PM +int gspca_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + + if (!gspca_dev->streaming) + return 0; + gspca_dev->frozen = 1; /* avoid urb error messages */ + if (gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); + destroy_urbs(gspca_dev); + gspca_input_destroy_urb(gspca_dev); + gspca_set_alt0(gspca_dev); + if (gspca_dev->sd_desc->stop0) + gspca_dev->sd_desc->stop0(gspca_dev); + return 0; +} +EXPORT_SYMBOL(gspca_suspend); + +int gspca_resume(struct usb_interface *intf) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + + gspca_dev->frozen = 0; + gspca_dev->sd_desc->init(gspca_dev); + gspca_input_create_urb(gspca_dev); + if (gspca_dev->streaming) + return gspca_init_transfer(gspca_dev); + return 0; +} +EXPORT_SYMBOL(gspca_resume); +#endif +/* -- cam driver utility functions -- */ + +/* auto gain and exposure algorithm based on the knee algorithm described here: + http://ytse.tricolour.net/docs/LowLightOptimization.html + + Returns 0 if no changes were made, 1 if the gain and or exposure settings + where changed. */ +int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, + int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee) +{ + int i, steps, gain, orig_gain, exposure, orig_exposure, autogain; + const struct ctrl *gain_ctrl = NULL; + const struct ctrl *exposure_ctrl = NULL; + const struct ctrl *autogain_ctrl = NULL; + int retval = 0; + + for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { + if (gspca_dev->ctrl_dis & (1 << i)) + continue; + if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN) + gain_ctrl = &gspca_dev->sd_desc->ctrls[i]; + if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE) + exposure_ctrl = &gspca_dev->sd_desc->ctrls[i]; + if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN) + autogain_ctrl = &gspca_dev->sd_desc->ctrls[i]; + } + if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) { + PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called " + "on cam without (auto)gain/exposure"); + return 0; + } + + if (gain_ctrl->get(gspca_dev, &gain) || + exposure_ctrl->get(gspca_dev, &exposure) || + autogain_ctrl->get(gspca_dev, &autogain) || !autogain) + return 0; + + orig_gain = gain; + orig_exposure = exposure; + + /* If we are of a multiple of deadzone, do multiple steps to reach the + desired lumination fast (with the risc of a slight overshoot) */ + steps = abs(desired_avg_lum - avg_lum) / deadzone; + + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", + avg_lum, desired_avg_lum, steps); + + for (i = 0; i < steps; i++) { + if (avg_lum > desired_avg_lum) { + if (gain > gain_knee) + gain--; + else if (exposure > exposure_knee) + exposure--; + else if (gain > gain_ctrl->qctrl.default_value) + gain--; + else if (exposure > exposure_ctrl->qctrl.minimum) + exposure--; + else if (gain > gain_ctrl->qctrl.minimum) + gain--; + else + break; + } else { + if (gain < gain_ctrl->qctrl.default_value) + gain++; + else if (exposure < exposure_knee) + exposure++; + else if (gain < gain_knee) + gain++; + else if (exposure < exposure_ctrl->qctrl.maximum) + exposure++; + else if (gain < gain_ctrl->qctrl.maximum) + gain++; + else + break; + } + } + + if (gain != orig_gain) { + gain_ctrl->set(gspca_dev, gain); + retval = 1; + } + if (exposure != orig_exposure) { + exposure_ctrl->set(gspca_dev, exposure); + retval = 1; + } + + return retval; +} +EXPORT_SYMBOL(gspca_auto_gain_n_exposure); + +/* -- module insert / remove -- */ +static int __init gspca_init(void) +{ + info("v%d.%d.%d registered", + (DRIVER_VERSION_NUMBER >> 16) & 0xff, + (DRIVER_VERSION_NUMBER >> 8) & 0xff, + DRIVER_VERSION_NUMBER & 0xff); + return 0; +} +static void __exit gspca_exit(void) +{ +} + +module_init(gspca_init); +module_exit(gspca_exit); + +#ifdef GSPCA_DEBUG +module_param_named(debug, gspca_debug, int, 0644); +MODULE_PARM_DESC(debug, + "Debug (bit) 0x01:error 0x02:probe 0x04:config" + " 0x08:stream 0x10:frame 0x20:packet" + " 0x0100: v4l2"); +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gspca.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gspca.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gspca.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/gspca.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,244 @@ +#ifndef GSPCAV2_H +#define GSPCAV2_H + +#include +#include +#include +#include +#include +#include + +/* compilation option */ +/*#define GSPCA_DEBUG 1*/ + +#ifdef GSPCA_DEBUG +/* GSPCA our debug messages */ +extern int gspca_debug; +#define PDEBUG(level, fmt, args...) \ + do {\ + if (gspca_debug & (level)) \ + printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \ + } while (0) +#define D_ERR 0x01 +#define D_PROBE 0x02 +#define D_CONF 0x04 +#define D_STREAM 0x08 +#define D_FRAM 0x10 +#define D_PACK 0x20 +#define D_USBI 0x00 +#define D_USBO 0x00 +#define D_V4L2 0x0100 +#else +#define PDEBUG(level, fmt, args...) +#endif +#undef err +#define err(fmt, args...) \ + printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args) +#undef info +#define info(fmt, args...) \ + printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args) +#undef warn +#define warn(fmt, args...) \ + printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args) + +#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ +/* image transfers */ +#define MAX_NURBS 4 /* max number of URBs */ + + +/* used to list framerates supported by a camera mode (resolution) */ +struct framerates { + const u8 *rates; + int nrates; +}; + +/* control definition */ +struct gspca_ctrl { + s16 val; /* current value */ + s16 def; /* default value */ + s16 min, max; /* minimum and maximum values */ +}; + +/* device information - set at probe time */ +struct cam { + const struct v4l2_pix_format *cam_mode; /* size nmodes */ + const struct framerates *mode_framerates; /* must have size nmodes, + * just like cam_mode */ + struct gspca_ctrl *ctrls; /* control table - size nctrls */ + /* may be NULL */ + u32 bulk_size; /* buffer size when image transfer by bulk */ + u32 input_flags; /* value for ENUM_INPUT status flags */ + u8 nmodes; /* size of cam_mode */ + u8 no_urb_create; /* don't create transfer URBs */ + u8 bulk_nurbs; /* number of URBs in bulk mode + * - cannot be > MAX_NURBS + * - when 0 and bulk_size != 0 means + * 1 URB and submit done by subdriver */ + u8 bulk; /* image transfer by 0:isoc / 1:bulk */ + u8 npkt; /* number of packets in an ISOC message + * 0 is the default value: 32 packets */ + u8 reverse_alts; /* Alt settings are in high to low order */ +}; + +struct gspca_dev; +struct gspca_frame; + +/* subdriver operations */ +typedef int (*cam_op) (struct gspca_dev *); +typedef void (*cam_v_op) (struct gspca_dev *); +typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *); +typedef int (*cam_jpg_op) (struct gspca_dev *, + struct v4l2_jpegcompression *); +typedef int (*cam_reg_op) (struct gspca_dev *, + struct v4l2_dbg_register *); +typedef int (*cam_ident_op) (struct gspca_dev *, + struct v4l2_dbg_chip_ident *); +typedef void (*cam_streamparm_op) (struct gspca_dev *, + struct v4l2_streamparm *); +typedef int (*cam_qmnu_op) (struct gspca_dev *, + struct v4l2_querymenu *); +typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev, + u8 *data, + int len); +typedef int (*cam_int_pkt_op) (struct gspca_dev *gspca_dev, + u8 *data, + int len); + +struct ctrl { + struct v4l2_queryctrl qctrl; + int (*set)(struct gspca_dev *, __s32); + int (*get)(struct gspca_dev *, __s32 *); + cam_v_op set_control; +}; + +/* subdriver description */ +struct sd_desc { +/* information */ + const char *name; /* sub-driver name */ +/* controls */ + const struct ctrl *ctrls; /* static control definition */ + int nctrls; +/* mandatory operations */ + cam_cf_op config; /* called on probe */ + cam_op init; /* called on probe and resume */ + cam_op start; /* called on stream on after URBs creation */ + cam_pkt_op pkt_scan; +/* optional operations */ + cam_op isoc_init; /* called on stream on before getting the EP */ + cam_op isoc_nego; /* called when URB submit failed with NOSPC */ + cam_v_op stopN; /* called on stream off - main alt */ + cam_v_op stop0; /* called on stream off & disconnect - alt 0 */ + cam_v_op dq_callback; /* called when a frame has been dequeued */ + cam_jpg_op get_jcomp; + cam_jpg_op set_jcomp; + cam_qmnu_op querymenu; + cam_streamparm_op get_streamparm; + cam_streamparm_op set_streamparm; +#ifdef CONFIG_VIDEO_ADV_DEBUG + cam_reg_op set_register; + cam_reg_op get_register; +#endif + cam_ident_op get_chip_ident; +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + cam_int_pkt_op int_pkt_scan; + /* other_input makes the gspca core create gspca_dev->input even when + int_pkt_scan is NULL, for cams with non interrupt driven buttons */ + u8 other_input; +#endif +}; + +/* packet types when moving from iso buf to frame buf */ +enum gspca_packet_type { + DISCARD_PACKET, + FIRST_PACKET, + INTER_PACKET, + LAST_PACKET +}; + +struct gspca_frame { + __u8 *data; /* frame buffer */ + int vma_use_count; + struct v4l2_buffer v4l2_buf; +}; + +struct gspca_dev { + struct video_device vdev; /* !! must be the first item */ + struct module *module; /* subdriver handling the device */ + struct usb_device *dev; + struct file *capt_file; /* file doing video capture */ +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + struct input_dev *input_dev; + char phys[64]; /* physical device path */ +#endif + + struct cam cam; /* device information */ + const struct sd_desc *sd_desc; /* subdriver description */ + unsigned ctrl_dis; /* disabled controls (bit map) */ + unsigned ctrl_inac; /* inactive controls (bit map) */ + +#define USB_BUF_SZ 64 + __u8 *usb_buf; /* buffer for USB exchanges */ + struct urb *urb[MAX_NURBS]; +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + struct urb *int_urb; +#endif + + __u8 *frbuf; /* buffer for nframes */ + struct gspca_frame frame[GSPCA_MAX_FRAMES]; + u8 *image; /* image beeing filled */ + __u32 frsz; /* frame size */ + u32 image_len; /* current length of image */ + atomic_t fr_q; /* next frame to queue */ + atomic_t fr_i; /* frame being filled */ + signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */ + char nframes; /* number of frames */ + u8 fr_o; /* next frame to dequeue */ + __u8 last_packet_type; + __s8 empty_packet; /* if (-1) don't check empty packets */ + __u8 streaming; + + __u8 curr_mode; /* current camera mode */ + __u32 pixfmt; /* current mode parameters */ + __u16 width; + __u16 height; + __u32 sequence; /* frame sequence number */ + + wait_queue_head_t wq; /* wait queue */ + struct mutex usb_lock; /* usb exchange protection */ + struct mutex queue_lock; /* ISOC queue protection */ + int usb_err; /* USB error - protected by usb_lock */ + u16 pkt_size; /* ISOC packet size */ +#ifdef CONFIG_PM + char frozen; /* suspend - resume */ +#endif + char present; /* device connected */ + char nbufread; /* number of buffers for read() */ + char memory; /* memory type (V4L2_MEMORY_xxx) */ + __u8 iface; /* USB interface number */ + __u8 alt; /* USB alternate setting */ + __u8 nbalt; /* number of USB alternate settings */ + u8 audio; /* presence of audio device */ +}; + +int gspca_dev_probe(struct usb_interface *intf, + const struct usb_device_id *id, + const struct sd_desc *sd_desc, + int dev_size, + struct module *module); +int gspca_dev_probe2(struct usb_interface *intf, + const struct usb_device_id *id, + const struct sd_desc *sd_desc, + int dev_size, + struct module *module); +void gspca_disconnect(struct usb_interface *intf); +void gspca_frame_add(struct gspca_dev *gspca_dev, + enum gspca_packet_type packet_type, + const u8 *data, + int len); +#ifdef CONFIG_PM +int gspca_suspend(struct usb_interface *intf, pm_message_t message); +int gspca_resume(struct usb_interface *intf); +#endif +int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, + int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee); +#endif /* GSPCAV2_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/jeilinj.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/jeilinj.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/jeilinj.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/jeilinj.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,601 @@ +/* + * Jeilinj subdriver + * + * Supports some Jeilin dual-mode cameras which use bulk transport and + * download raw JPEG data. + * + * Copyright (C) 2009 Theodore Kilgore + * + * Sportscam DV15 support and control settings are + * Copyright (C) 2011 Patrice Chotard + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "jeilinj" + +#include +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Theodore Kilgore "); +MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* Default timeouts, in ms */ +#define JEILINJ_CMD_TIMEOUT 500 +#define JEILINJ_CMD_DELAY 160 +#define JEILINJ_DATA_TIMEOUT 1000 + +/* Maximum transfer size to use. */ +#define JEILINJ_MAX_TRANSFER 0x200 +#define FRAME_HEADER_LEN 0x10 +#define FRAME_START 0xFFFFFFFF + +enum { + SAKAR_57379, + SPORTSCAM_DV15, +}; + +#define CAMQUALITY_MIN 0 /* highest cam quality */ +#define CAMQUALITY_MAX 97 /* lowest cam quality */ + +enum e_ctrl { + LIGHTFREQ, + AUTOGAIN, + RED, + GREEN, + BLUE, + NCTRLS /* number of controls */ +}; + +/* Structure to hold all of our device specific stuff */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + struct gspca_ctrl ctrls[NCTRLS]; + int blocks_left; + const struct v4l2_pix_format *cap_mode; + /* Driver stuff */ + u8 type; + u8 quality; /* image quality */ +#define QUALITY_MIN 35 +#define QUALITY_MAX 85 +#define QUALITY_DEF 85 + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +struct jlj_command { + unsigned char instruction[2]; + unsigned char ack_wanted; + unsigned char delay; +}; + +/* AFAICT these cameras will only do 320x240. */ +static struct v4l2_pix_format jlj_mode[] = { + { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, + { 640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0} +}; + +/* + * cam uses endpoint 0x03 to send commands, 0x84 for read commands, + * and 0x82 for bulk transfer. + */ + +/* All commands are two bytes only */ +static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) +{ + int retval; + + if (gspca_dev->usb_err < 0) + return; + memcpy(gspca_dev->usb_buf, command, 2); + retval = usb_bulk_msg(gspca_dev->dev, + usb_sndbulkpipe(gspca_dev->dev, 3), + gspca_dev->usb_buf, 2, NULL, 500); + if (retval < 0) { + err("command write [%02x] error %d", + gspca_dev->usb_buf[0], retval); + gspca_dev->usb_err = retval; + } +} + +/* Responses are one byte only */ +static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) +{ + int retval; + + if (gspca_dev->usb_err < 0) + return; + retval = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x84), + gspca_dev->usb_buf, 1, NULL, 500); + response = gspca_dev->usb_buf[0]; + if (retval < 0) { + err("read command [%02x] error %d", + gspca_dev->usb_buf[0], retval); + gspca_dev->usb_err = retval; + } +} + +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 freq_commands[][2] = { + {0x71, 0x80}, + {0x70, 0x07} + }; + + freq_commands[0][1] |= (sd->ctrls[LIGHTFREQ].val >> 1); + + jlj_write2(gspca_dev, freq_commands[0]); + jlj_write2(gspca_dev, freq_commands[1]); +} + +static void setcamquality(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 quality_commands[][2] = { + {0x71, 0x1E}, + {0x70, 0x06} + }; + u8 camquality; + + /* adapt camera quality from jpeg quality */ + camquality = ((QUALITY_MAX - sd->quality) * CAMQUALITY_MAX) + / (QUALITY_MAX - QUALITY_MIN); + quality_commands[0][1] += camquality; + + jlj_write2(gspca_dev, quality_commands[0]); + jlj_write2(gspca_dev, quality_commands[1]); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 autogain_commands[][2] = { + {0x94, 0x02}, + {0xcf, 0x00} + }; + + autogain_commands[1][1] = (sd->ctrls[AUTOGAIN].val << 4); + + jlj_write2(gspca_dev, autogain_commands[0]); + jlj_write2(gspca_dev, autogain_commands[1]); +} + +static void setred(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 setred_commands[][2] = { + {0x94, 0x02}, + {0xe6, 0x00} + }; + + setred_commands[1][1] = sd->ctrls[RED].val; + + jlj_write2(gspca_dev, setred_commands[0]); + jlj_write2(gspca_dev, setred_commands[1]); +} + +static void setgreen(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 setgreen_commands[][2] = { + {0x94, 0x02}, + {0xe7, 0x00} + }; + + setgreen_commands[1][1] = sd->ctrls[GREEN].val; + + jlj_write2(gspca_dev, setgreen_commands[0]); + jlj_write2(gspca_dev, setgreen_commands[1]); +} + +static void setblue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 setblue_commands[][2] = { + {0x94, 0x02}, + {0xe9, 0x00} + }; + + setblue_commands[1][1] = sd->ctrls[BLUE].val; + + jlj_write2(gspca_dev, setblue_commands[0]); + jlj_write2(gspca_dev, setblue_commands[1]); +} + +static const struct ctrl sd_ctrls[NCTRLS] = { +[LIGHTFREQ] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, /* 1 */ + .maximum = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, /* 2 */ + .step = 1, + .default_value = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, + }, + .set_control = setfreq + }, +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Automatic Gain (and Exposure)", + .minimum = 0, + .maximum = 3, + .step = 1, +#define AUTOGAIN_DEF 0 + .default_value = AUTOGAIN_DEF, + }, + .set_control = setautogain + }, +[RED] = { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0, + .maximum = 3, + .step = 1, +#define RED_BALANCE_DEF 2 + .default_value = RED_BALANCE_DEF, + }, + .set_control = setred + }, + +[GREEN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0, + .maximum = 3, + .step = 1, +#define GREEN_BALANCE_DEF 2 + .default_value = GREEN_BALANCE_DEF, + }, + .set_control = setgreen + }, +[BLUE] = { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0, + .maximum = 3, + .step = 1, +#define BLUE_BALANCE_DEF 2 + .default_value = BLUE_BALANCE_DEF, + }, + .set_control = setblue + }, +}; + +static int jlj_start(struct gspca_dev *gspca_dev) +{ + int i; + int start_commands_size; + u8 response = 0xff; + struct sd *sd = (struct sd *) gspca_dev; + struct jlj_command start_commands[] = { + {{0x71, 0x81}, 0, 0}, + {{0x70, 0x05}, 0, JEILINJ_CMD_DELAY}, + {{0x95, 0x70}, 1, 0}, + {{0x71, 0x81 - gspca_dev->curr_mode}, 0, 0}, + {{0x70, 0x04}, 0, JEILINJ_CMD_DELAY}, + {{0x95, 0x70}, 1, 0}, + {{0x71, 0x00}, 0, 0}, /* start streaming ??*/ + {{0x70, 0x08}, 0, JEILINJ_CMD_DELAY}, + {{0x95, 0x70}, 1, 0}, +#define SPORTSCAM_DV15_CMD_SIZE 9 + {{0x94, 0x02}, 0, 0}, + {{0xde, 0x24}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xdd, 0xf0}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xe3, 0x2c}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xe4, 0x00}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xe5, 0x00}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xe6, 0x2c}, 0, 0}, + {{0x94, 0x03}, 0, 0}, + {{0xaa, 0x00}, 0, 0} + }; + + sd->blocks_left = 0; + /* Under Windows, USB spy shows that only the 9 first start + * commands are used for SPORTSCAM_DV15 webcam + */ + if (sd->type == SPORTSCAM_DV15) + start_commands_size = SPORTSCAM_DV15_CMD_SIZE; + else + start_commands_size = ARRAY_SIZE(start_commands); + + for (i = 0; i < start_commands_size; i++) { + jlj_write2(gspca_dev, start_commands[i].instruction); + if (start_commands[i].delay) + msleep(start_commands[i].delay); + if (start_commands[i].ack_wanted) + jlj_read1(gspca_dev, response); + } + setcamquality(gspca_dev); + msleep(2); + setfreq(gspca_dev); + if (gspca_dev->usb_err < 0) + PDEBUG(D_ERR, "Start streaming command failed"); + return gspca_dev->usb_err; +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + int packet_type; + u32 header_marker; + + PDEBUG(D_STREAM, "Got %d bytes out of %d for Block 0", + len, JEILINJ_MAX_TRANSFER); + if (len != JEILINJ_MAX_TRANSFER) { + PDEBUG(D_PACK, "bad length"); + goto discard; + } + /* check if it's start of frame */ + header_marker = ((u32 *)data)[0]; + if (header_marker == FRAME_START) { + sd->blocks_left = data[0x0a] - 1; + PDEBUG(D_STREAM, "blocks_left = 0x%x", sd->blocks_left); + /* Start a new frame, and add the JPEG header, first thing */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + /* Toss line 0 of data block 0, keep the rest. */ + gspca_frame_add(gspca_dev, INTER_PACKET, + data + FRAME_HEADER_LEN, + JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN); + } else if (sd->blocks_left > 0) { + PDEBUG(D_STREAM, "%d blocks remaining for frame", + sd->blocks_left); + sd->blocks_left -= 1; + if (sd->blocks_left == 0) + packet_type = LAST_PACKET; + else + packet_type = INTER_PACKET; + gspca_frame_add(gspca_dev, packet_type, + data, JEILINJ_MAX_TRANSFER); + } else + goto discard; + return; +discard: + /* Discard data until a new frame starts. */ + gspca_dev->last_packet_type = DISCARD_PACKET; +} + +/* This function is called at probe time just before sd_init */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam = &gspca_dev->cam; + struct sd *dev = (struct sd *) gspca_dev; + + dev->type = id->driver_info; + gspca_dev->cam.ctrls = dev->ctrls; + dev->quality = QUALITY_DEF; + dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ; + dev->ctrls[RED].def = RED_BALANCE_DEF; + dev->ctrls[GREEN].def = GREEN_BALANCE_DEF; + dev->ctrls[BLUE].def = BLUE_BALANCE_DEF; + PDEBUG(D_PROBE, + "JEILINJ camera detected" + " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + cam->cam_mode = jlj_mode; + cam->nmodes = ARRAY_SIZE(jlj_mode); + cam->bulk = 1; + cam->bulk_nurbs = 1; + cam->bulk_size = JEILINJ_MAX_TRANSFER; + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + int i; + u8 *buf; + u8 stop_commands[][2] = { + {0x71, 0x00}, + {0x70, 0x09}, + {0x71, 0x80}, + {0x70, 0x05} + }; + + for (;;) { + /* get the image remaining blocks */ + usb_bulk_msg(gspca_dev->dev, + gspca_dev->urb[0]->pipe, + gspca_dev->urb[0]->transfer_buffer, + JEILINJ_MAX_TRANSFER, NULL, + JEILINJ_DATA_TIMEOUT); + + /* search for 0xff 0xd9 (EOF for JPEG) */ + i = 0; + buf = gspca_dev->urb[0]->transfer_buffer; + while ((i < (JEILINJ_MAX_TRANSFER - 1)) && + ((buf[i] != 0xff) || (buf[i+1] != 0xd9))) + i++; + + if (i != (JEILINJ_MAX_TRANSFER - 1)) + /* last remaining block found */ + break; + } + + for (i = 0; i < ARRAY_SIZE(stop_commands); i++) + jlj_write2(gspca_dev, stop_commands[i]); +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return gspca_dev->usb_err; +} + +/* Set up for getting frames. */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *) gspca_dev; + + /* create the JPEG header */ + jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x21); /* JPEG 422 */ + jpeg_set_qual(dev->jpeg_hdr, dev->quality); + PDEBUG(D_STREAM, "Start streaming at %dx%d", + gspca_dev->height, gspca_dev->width); + jlj_start(gspca_dev); + return gspca_dev->usb_err; +} + +/* Table of supported USB devices */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0979, 0x0280), .driver_info = SAKAR_57379}, + {USB_DEVICE(0x0979, 0x0270), .driver_info = SPORTSCAM_DV15}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "disable"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (jcomp->quality < QUALITY_MIN) + sd->quality = QUALITY_MIN; + else if (jcomp->quality > QUALITY_MAX) + sd->quality = QUALITY_MAX; + else + sd->quality = jcomp->quality; + if (gspca_dev->streaming) { + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + setcamquality(gspca_dev); + } + return 0; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + + +/* sub-driver description */ +static const struct sd_desc sd_desc_sakar_57379 = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* sub-driver description */ +static const struct sd_desc sd_desc_sportscam_dv15 = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .querymenu = sd_querymenu, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +}; + +static const struct sd_desc *sd_desc[2] = { + &sd_desc_sakar_57379, + &sd_desc_sportscam_dv15 +}; + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + sd_desc[id->driver_info], + sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/jpeg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/jpeg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/jpeg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/jpeg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,168 @@ +#ifndef JPEG_H +#define JPEG_H 1 +/* + * Insert a JPEG header at start of frame + * + * This module is used by the gspca subdrivers. + * A special case is done for Conexant webcams. + * + * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr) + * + * 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, or + * any later version. + * + * 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 + * + */ + +/* + * generation options + * CONEX_CAM Conexant if present + */ + +/* JPEG header */ +static const u8 jpeg_head[] = { + 0xff, 0xd8, /* jpeg */ + +/* quantization table quality 50% */ + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, +#define JPEG_QT0_OFFSET 7 + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, +1, +#define JPEG_QT1_OFFSET 72 + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + +/* huffman table */ + 0xff, 0xc4, 0x01, 0xa2, + 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, + 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, + 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, + 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, + 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, + 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, + 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, + 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, + 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, + 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, + 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, + 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, + 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, + 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, + 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, + 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, + 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, + 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, + 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, + 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, +#ifdef CONEX_CAM +/* the Conexant frames start with SOF0 */ +#define JPEG_HDR_SZ 556 +#else + 0xff, 0xc0, 0x00, 0x11, /* SOF0 (start of frame 0 */ + 0x08, /* data precision */ +#define JPEG_HEIGHT_OFFSET 561 + 0x01, 0xe0, /* height */ + 0x02, 0x80, /* width */ + 0x03, /* component number */ + 0x01, + 0x21, /* samples Y */ + 0x00, /* quant Y */ + 0x02, 0x11, 0x01, /* samples CbCr - quant CbCr */ + 0x03, 0x11, 0x01, + + 0xff, 0xda, 0x00, 0x0c, /* SOS (start of scan) */ + 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 +#define JPEG_HDR_SZ 589 +#endif +}; + +/* define the JPEG header */ +static void jpeg_define(u8 *jpeg_hdr, + int height, + int width, + int samplesY) +{ + memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head); +#ifndef CONEX_CAM + jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8; + jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height; + jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8; + jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width; + jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY; +#endif +} + +/* set the JPEG quality */ +static void jpeg_set_qual(u8 *jpeg_hdr, + int quality) +{ + int i, sc; + + if (quality < 50) + sc = 5000 / quality; + else + sc = 200 - quality * 2; + for (i = 0; i < 64; i++) { + jpeg_hdr[JPEG_QT0_OFFSET + i] = + (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100; + jpeg_hdr[JPEG_QT1_OFFSET + i] = + (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100; + } +} +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,395 @@ +menuconfig USB_GSPCA + tristate "GSPCA based webcams" + depends on VIDEO_V4L2 + default m + ---help--- + Say Y here if you want to enable selecting webcams based + on the GSPCA framework. + + See for more info. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" to use this driver. + + To compile this driver as modules, choose M here: the + module will be called gspca_main. + + +if USB_GSPCA && VIDEO_V4L2 + +source "drivers/media/video/gspca/m5602/Kconfig" +source "drivers/media/video/gspca/stv06xx/Kconfig" +source "drivers/media/video/gspca/gl860/Kconfig" + +config USB_GSPCA_BENQ + tristate "Benq USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for the Benq DC E300 camera. + + To compile this driver as a module, choose M here: the + module will be called gspca_benq. + +config USB_GSPCA_CONEX + tristate "Conexant Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Conexant chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_conex. + +config USB_GSPCA_CPIA1 + tristate "cpia CPiA (version 1) Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for USB cameras based on the cpia + CPiA chip. Note that you need atleast version 0.6.4 of libv4l for + applications to understand the videoformat generated by this driver. + + To compile this driver as a module, choose M here: the + module will be called gspca_cpia1. + +config USB_GSPCA_ETOMS + tristate "Etoms USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Etoms chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_etoms. + +config USB_GSPCA_FINEPIX + tristate "Fujifilm FinePix USB V4L2 driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the FinePix chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_finepix. + +config USB_GSPCA_JEILINJ + tristate "Jeilin JPEG USB V4L2 driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on this Jeilin chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_jeilinj. + +config USB_GSPCA_KINECT + tristate "Kinect sensor device USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for the Microsoft Kinect sensor device. + + To compile this driver as a module, choose M here: the + module will be called gspca_kinect. + +config USB_GSPCA_KONICA + tristate "Konica USB Camera V4L2 driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Konica chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_konica. + +config USB_GSPCA_MARS + tristate "Mars USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Mars chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_mars. + +config USB_GSPCA_MR97310A + tristate "Mars-Semi MR97310A USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the MR97310A chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_mr97310a. + +config USB_GSPCA_NW80X + tristate "Divio based (NW80x) USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the NW80x chips. + + To compile this driver as a module, choose M here: the + module will be called gspca_nw80x. + +config USB_GSPCA_OV519 + tristate "OV51x / OVFX2 / W996xCF USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on one of these: + OV511(+), OV518(+), OV519, OVFX2, W9967CF, W9968CF + + To compile this driver as a module, choose M here: the + module will be called gspca_ov519. + +config USB_GSPCA_OV534 + tristate "OV534 OV772x USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the OV534 chip + and sensor OV772x (e.g. Sony Playstation EYE) + + To compile this driver as a module, choose M here: the + module will be called gspca_ov534. + +config USB_GSPCA_OV534_9 + tristate "OV534 OV965x USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the OV534 chip + and sensor OV965x (e.g. Hercules Dualpix) + + To compile this driver as a module, choose M here: the + module will be called gspca_ov534_9. + +config USB_GSPCA_PAC207 + tristate "Pixart PAC207 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the PAC207 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_pac207. + +config USB_GSPCA_PAC7302 + tristate "Pixart PAC7302 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the PAC7302 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_pac7302. + +config USB_GSPCA_PAC7311 + tristate "Pixart PAC7311 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the PAC7311 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_pac7311. + +config USB_GSPCA_SN9C2028 + tristate "SONIX Dual-Mode USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want streaming support for Sonix SN9C2028 cameras. + These are supported as stillcams in libgphoto2/camlibs/sonix. + + To compile this driver as a module, choose M here: the + module will be called gspca_sn9c2028. + +config USB_GSPCA_SN9C20X + tristate "SN9C20X USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the + sn9c20x chips (SN9C201 and SN9C202). + + To compile this driver as a module, choose M here: the + module will be called gspca_sn9c20x. + +config USB_GSPCA_SONIXB + tristate "SONIX Bayer USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Sonix + chips with Bayer format (SN9C101, SN9C102 and SN9C103). + + To compile this driver as a module, choose M here: the + module will be called gspca_sonixb. + +config USB_GSPCA_SONIXJ + tristate "SONIX JPEG USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Sonix + chips with JPEG format (SN9C102P, SN9C105 and >= SN9C110). + + To compile this driver as a module, choose M here: the + module will be called gspca_sonixj + +config USB_GSPCA_SPCA500 + tristate "SPCA500 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA500 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca500. + +config USB_GSPCA_SPCA501 + tristate "SPCA501 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA501 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca501. + +config USB_GSPCA_SPCA505 + tristate "SPCA505 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA505 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca505. + +config USB_GSPCA_SPCA506 + tristate "SPCA506 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA506 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca506. + +config USB_GSPCA_SPCA508 + tristate "SPCA508 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA508 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca508. + +config USB_GSPCA_SPCA561 + tristate "SPCA561 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA561 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca561. + +config USB_GSPCA_SPCA1528 + tristate "SPCA1528 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SPCA1528 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_spca1528. + +config USB_GSPCA_SQ905 + tristate "SQ Technologies SQ905 based USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SQ905 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_sq905. + +config USB_GSPCA_SQ905C + tristate "SQ Technologies SQ905C based USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SQ905C chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_sq905c. + +config USB_GSPCA_SQ930X + tristate "SQ Technologies SQ930X based USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the SQ930X chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_sq930x. + +config USB_GSPCA_STK014 + tristate "Syntek DV4000 (STK014) USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the STK014 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_stk014. + +config USB_GSPCA_STV0680 + tristate "STV0680 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the STV0680 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_stv0680. + +config USB_GSPCA_SUNPLUS + tristate "SUNPLUS USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the Sunplus + SPCA504(abc) SPCA533 SPCA536 chips. + + To compile this driver as a module, choose M here: the + module will be called gspca_sunplus. + +config USB_GSPCA_T613 + tristate "T613 (JPEG Compliance) USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the T613 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_t613. + +config USB_GSPCA_TV8532 + tristate "TV8532 USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the TV8531 chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_tv8532. + +config USB_GSPCA_VC032X + tristate "VC032X USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the VC032X chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_vc032x. + +config USB_GSPCA_VICAM + tristate "ViCam USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for the 3com homeconnect camera + (vicam). + + To compile this driver as a module, choose M here: the + module will be called gspca_vicam. + +config USB_GSPCA_XIRLINK_CIT + tristate "Xirlink C-It USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for Xirlink C-It bases cameras. + + To compile this driver as a module, choose M here: the + module will be called gspca_xirlink_cit. + +config USB_GSPCA_ZC3XX + tristate "ZC3XX USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the ZC3XX chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_zc3xx. + +endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/kinect.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/kinect.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/kinect.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/kinect.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,429 @@ +/* + * kinect sensor device camera, gspca driver + * + * Copyright (C) 2011 Antonio Ospite + * + * Based on the OpenKinect project and libfreenect + * http://openkinect.org/wiki/Init_Analysis + * + * Special thanks to Steven Toth and kernellabs.com for sponsoring a Kinect + * sensor device which I tested the driver on. + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "kinect" + +#include "gspca.h" + +#define CTRL_TIMEOUT 500 + +MODULE_AUTHOR("Antonio Ospite "); +MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); +MODULE_LICENSE("GPL"); + +#ifdef GSPCA_DEBUG +int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK | + D_USBI | D_USBO | D_V4L2; +#endif + +struct pkt_hdr { + uint8_t magic[2]; + uint8_t pad; + uint8_t flag; + uint8_t unk1; + uint8_t seq; + uint8_t unk2; + uint8_t unk3; + uint32_t timestamp; +}; + +struct cam_hdr { + uint8_t magic[2]; + uint16_t len; + uint16_t cmd; + uint16_t tag; +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + uint16_t cam_tag; /* a sequence number for packets */ + uint8_t stream_flag; /* to identify different stream types */ + uint8_t obuf[0x400]; /* output buffer for control commands */ + uint8_t ibuf[0x200]; /* input buffer for control commands */ +}; + +/* V4L2 controls supported by the driver */ +/* controls prototypes here */ + +static const struct ctrl sd_ctrls[] = { +}; + +#define MODE_640x480 0x0001 +#define MODE_640x488 0x0002 +#define MODE_1280x1024 0x0004 + +#define FORMAT_BAYER 0x0010 +#define FORMAT_UYVY 0x0020 +#define FORMAT_Y10B 0x0040 + +#define FPS_HIGH 0x0100 + +static const struct v4l2_pix_format video_camera_mode[] = { + {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_640x480 | FORMAT_BAYER | FPS_HIGH}, + {640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, + .bytesperline = 640 * 2, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_640x480 | FORMAT_UYVY}, + {1280, 1024, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_1280x1024 | FORMAT_BAYER}, + {640, 488, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, + .bytesperline = 640 * 10 / 8, + .sizeimage = 640 * 488 * 10 / 8, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_640x488 | FORMAT_Y10B | FPS_HIGH}, + {1280, 1024, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, + .bytesperline = 1280 * 10 / 8, + .sizeimage = 1280 * 1024 * 10 / 8, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_1280x1024 | FORMAT_Y10B}, +}; + +static int kinect_write(struct usb_device *udev, uint8_t *data, + uint16_t wLength) +{ + return usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + 0x00, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, data, wLength, CTRL_TIMEOUT); +} + +static int kinect_read(struct usb_device *udev, uint8_t *data, uint16_t wLength) +{ + return usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, data, wLength, CTRL_TIMEOUT); +} + +static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, + unsigned int cmd_len, void *replybuf, unsigned int reply_len) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *udev = gspca_dev->dev; + int res, actual_len; + uint8_t *obuf = sd->obuf; + uint8_t *ibuf = sd->ibuf; + struct cam_hdr *chdr = (void *)obuf; + struct cam_hdr *rhdr = (void *)ibuf; + + if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) { + err("send_cmd: Invalid command length (0x%x)", cmd_len); + return -1; + } + + chdr->magic[0] = 0x47; + chdr->magic[1] = 0x4d; + chdr->cmd = cpu_to_le16(cmd); + chdr->tag = cpu_to_le16(sd->cam_tag); + chdr->len = cpu_to_le16(cmd_len / 2); + + memcpy(obuf+sizeof(*chdr), cmdbuf, cmd_len); + + res = kinect_write(udev, obuf, cmd_len + sizeof(*chdr)); + PDEBUG(D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d", cmd, + sd->cam_tag, cmd_len, res); + if (res < 0) { + err("send_cmd: Output control transfer failed (%d)", res); + return res; + } + + do { + actual_len = kinect_read(udev, ibuf, 0x200); + } while (actual_len == 0); + PDEBUG(D_USBO, "Control reply: %d", res); + if (actual_len < sizeof(*rhdr)) { + err("send_cmd: Input control transfer failed (%d)", res); + return res; + } + actual_len -= sizeof(*rhdr); + + if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) { + err("send_cmd: Bad magic %02x %02x", rhdr->magic[0], + rhdr->magic[1]); + return -1; + } + if (rhdr->cmd != chdr->cmd) { + err("send_cmd: Bad cmd %02x != %02x", rhdr->cmd, chdr->cmd); + return -1; + } + if (rhdr->tag != chdr->tag) { + err("send_cmd: Bad tag %04x != %04x", rhdr->tag, chdr->tag); + return -1; + } + if (cpu_to_le16(rhdr->len) != (actual_len/2)) { + err("send_cmd: Bad len %04x != %04x", + cpu_to_le16(rhdr->len), (int)(actual_len/2)); + return -1; + } + + if (actual_len > reply_len) { + warn("send_cmd: Data buffer is %d bytes long, but got %d bytes", + reply_len, actual_len); + memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len); + } else { + memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len); + } + + sd->cam_tag++; + + return actual_len; +} + +static int write_register(struct gspca_dev *gspca_dev, uint16_t reg, + uint16_t data) +{ + uint16_t reply[2]; + uint16_t cmd[2]; + int res; + + cmd[0] = cpu_to_le16(reg); + cmd[1] = cpu_to_le16(data); + + PDEBUG(D_USBO, "Write Reg 0x%04x <= 0x%02x", reg, data); + res = send_cmd(gspca_dev, 0x03, cmd, 4, reply, 4); + if (res < 0) + return res; + if (res != 2) { + warn("send_cmd returned %d [%04x %04x], 0000 expected", + res, reply[0], reply[1]); + } + return 0; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + sd->cam_tag = 0; + + /* Only video stream is supported for now, + * which has stream flag = 0x80 */ + sd->stream_flag = 0x80; + + cam = &gspca_dev->cam; + + cam->cam_mode = video_camera_mode; + cam->nmodes = ARRAY_SIZE(video_camera_mode); + +#if 0 + /* Setting those values is not needed for video stream */ + cam->npkt = 15; + gspca_dev->pkt_size = 960 * 2; +#endif + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + PDEBUG(D_PROBE, "Kinect Camera device."); + + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + int mode; + uint8_t fmt_reg, fmt_val; + uint8_t res_reg, res_val; + uint8_t fps_reg, fps_val; + uint8_t mode_val; + + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + + if (mode & FORMAT_Y10B) { + fmt_reg = 0x19; + res_reg = 0x1a; + fps_reg = 0x1b; + mode_val = 0x03; + } else { + fmt_reg = 0x0c; + res_reg = 0x0d; + fps_reg = 0x0e; + mode_val = 0x01; + } + + /* format */ + if (mode & FORMAT_UYVY) + fmt_val = 0x05; + else + fmt_val = 0x00; + + if (mode & MODE_1280x1024) + res_val = 0x02; + else + res_val = 0x01; + + if (mode & FPS_HIGH) + fps_val = 0x1e; + else + fps_val = 0x0f; + + + /* turn off IR-reset function */ + write_register(gspca_dev, 0x105, 0x00); + + /* Reset video stream */ + write_register(gspca_dev, 0x05, 0x00); + + /* Due to some ridiculous condition in the firmware, we have to start + * and stop the depth stream before the camera will hand us 1280x1024 + * IR. This is a stupid workaround, but we've yet to find a better + * solution. + * + * Thanks to Drew Fisher for figuring this out. + */ + if (mode & (FORMAT_Y10B | MODE_1280x1024)) { + write_register(gspca_dev, 0x13, 0x01); + write_register(gspca_dev, 0x14, 0x1e); + write_register(gspca_dev, 0x06, 0x02); + write_register(gspca_dev, 0x06, 0x00); + } + + write_register(gspca_dev, fmt_reg, fmt_val); + write_register(gspca_dev, res_reg, res_val); + write_register(gspca_dev, fps_reg, fps_val); + + /* Start video stream */ + write_register(gspca_dev, 0x05, mode_val); + + /* disable Hflip */ + write_register(gspca_dev, 0x47, 0x00); + + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* reset video stream */ + write_register(gspca_dev, 0x05, 0x00); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + + struct pkt_hdr *hdr = (void *)__data; + uint8_t *data = __data + sizeof(*hdr); + int datalen = len - sizeof(*hdr); + + uint8_t sof = sd->stream_flag | 1; + uint8_t mof = sd->stream_flag | 2; + uint8_t eof = sd->stream_flag | 5; + + if (len < 12) + return; + + if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') { + warn("[Stream %02x] Invalid magic %02x%02x", sd->stream_flag, + hdr->magic[0], hdr->magic[1]); + return; + } + + if (hdr->flag == sof) + gspca_frame_add(gspca_dev, FIRST_PACKET, data, datalen); + + else if (hdr->flag == mof) + gspca_frame_add(gspca_dev, INTER_PACKET, data, datalen); + + else if (hdr->flag == eof) + gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen); + + else + warn("Packet type not recognized..."); +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + /* + .querymenu = sd_querymenu, + .get_streamparm = sd_get_streamparm, + .set_streamparm = sd_set_streamparm, + */ +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x045e, 0x02ae)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/konica.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/konica.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/konica.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/konica.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,646 @@ +/* + * Driver for USB webcams based on Konica chipset. This + * chipset is used in Intel YC76 camera. + * + * Copyright (C) 2010 Hans de Goede + * + * Based on the usbvideo v4l1 konicawc driver which is: + * + * Copyright (C) 2002 Simon Evans + * + * The code for making gspca work with a webcam with 2 isoc endpoints was + * taken from the benq gspca subdriver which is: + * + * Copyright (C) 2009 Jean-Francois Moine (http://moinejf.free.fr) + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "konica" + +#include +#include "gspca.h" + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Konica chipset USB Camera Driver"); +MODULE_LICENSE("GPL"); + +#define WHITEBAL_REG 0x01 +#define BRIGHTNESS_REG 0x02 +#define SHARPNESS_REG 0x03 +#define CONTRAST_REG 0x04 +#define SATURATION_REG 0x05 + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + struct urb *last_data_urb; + u8 snapshot_pressed; + u8 brightness; + u8 contrast; + u8 saturation; + u8 whitebal; + u8 sharpness; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 9, + .step = 1, +#define BRIGHTNESS_DEFAULT 4 + .default_value = BRIGHTNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 9, + .step = 4, +#define CONTRAST_DEFAULT 10 + .default_value = CONTRAST_DEFAULT, + .flags = 0, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SD_SATURATION 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 9, + .step = 1, +#define SATURATION_DEFAULT 4 + .default_value = SATURATION_DEFAULT, + .flags = 0, + }, + .set = sd_setsaturation, + .get = sd_getsaturation, + }, +#define SD_WHITEBAL 3 + { + { + .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "White Balance", + .minimum = 0, + .maximum = 33, + .step = 1, +#define WHITEBAL_DEFAULT 25 + .default_value = WHITEBAL_DEFAULT, + .flags = 0, + }, + .set = sd_setwhitebal, + .get = sd_getwhitebal, + }, +#define SD_SHARPNESS 4 + { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 9, + .step = 1, +#define SHARPNESS_DEFAULT 4 + .default_value = SHARPNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, +}; + +/* .priv is what goes to register 8 for this mode, known working values: + 0x00 -> 176x144, cropped + 0x01 -> 176x144, cropped + 0x02 -> 176x144, cropped + 0x03 -> 176x144, cropped + 0x04 -> 176x144, binned + 0x05 -> 320x240 + 0x06 -> 320x240 + 0x07 -> 160x120, cropped + 0x08 -> 160x120, cropped + 0x09 -> 160x120, binned (note has 136 lines) + 0x0a -> 160x120, binned (note has 136 lines) + 0x0b -> 160x120, cropped +*/ +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 136 * 3 / 2 + 960, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0x0a}, + {176, 144, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2 + 960, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0x04}, + {320, 240, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2 + 960, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0x05}, +}; + +static void sd_isoc_irq(struct urb *urb); + +static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x02, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + NULL, + 0, + 1000); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x03, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + gspca_dev->usb_buf, + 2, + 1000); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void konica_stream_on(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 1, 0x0b); +} + +static void konica_stream_off(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0, 0x0b); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->cam.cam_mode = vga_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + gspca_dev->cam.no_urb_create = 1; + /* The highest alt setting has an isoc packetsize of 0, so we + don't want to use it */ + gspca_dev->nbalt--; + + sd->brightness = BRIGHTNESS_DEFAULT; + sd->contrast = CONTRAST_DEFAULT; + sd->saturation = SATURATION_DEFAULT; + sd->whitebal = WHITEBAL_DEFAULT; + sd->sharpness = SHARPNESS_DEFAULT; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + /* HDG not sure if these 2 reads are needed */ + reg_r(gspca_dev, 0, 0x10); + PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); + reg_r(gspca_dev, 0, 0x10); + PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); + reg_w(gspca_dev, 0, 0x0d); + + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct urb *urb; + int i, n, packet_size; + struct usb_host_interface *alt; + struct usb_interface *intf; + + intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) { + err("Couldn't get altsetting"); + return -EIO; + } + + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + + reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG); + reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG); + reg_w(gspca_dev, sd->contrast, CONTRAST_REG); + reg_w(gspca_dev, sd->saturation, SATURATION_REG); + reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG); + + n = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + reg_w(gspca_dev, n, 0x08); + + konica_stream_on(gspca_dev); + + if (gspca_dev->usb_err) + return gspca_dev->usb_err; + + /* create 4 URBs - 2 on endpoint 0x83 and 2 on 0x082 */ +#if MAX_NURBS < 4 +#error "Not enough URBs in the gspca table" +#endif +#define SD_NPKT 32 + for (n = 0; n < 4; n++) { + i = n & 1 ? 0 : 1; + packet_size = + le16_to_cpu(alt->endpoint[i].desc.wMaxPacketSize); + urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); + if (!urb) { + err("usb_alloc_urb failed"); + return -ENOMEM; + } + gspca_dev->urb[n] = urb; + urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, + packet_size * SD_NPKT, + GFP_KERNEL, + &urb->transfer_dma); + if (urb->transfer_buffer == NULL) { + err("usb_buffer_alloc failed"); + return -ENOMEM; + } + + urb->dev = gspca_dev->dev; + urb->context = gspca_dev; + urb->transfer_buffer_length = packet_size * SD_NPKT; + urb->pipe = usb_rcvisocpipe(gspca_dev->dev, + n & 1 ? 0x81 : 0x82); + urb->transfer_flags = URB_ISO_ASAP + | URB_NO_TRANSFER_DMA_MAP; + urb->interval = 1; + urb->complete = sd_isoc_irq; + urb->number_of_packets = SD_NPKT; + for (i = 0; i < SD_NPKT; i++) { + urb->iso_frame_desc[i].length = packet_size; + urb->iso_frame_desc[i].offset = packet_size * i; + } + } + + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + konica_stream_off(gspca_dev); +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + /* Don't keep the button in the pressed state "forever" if it was + pressed when streaming is stopped */ + if (sd->snapshot_pressed) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + sd->snapshot_pressed = 0; + } +#endif +} + +/* reception of an URB */ +static void sd_isoc_irq(struct urb *urb) +{ + struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; + struct sd *sd = (struct sd *) gspca_dev; + struct urb *data_urb, *status_urb; + u8 *data; + int i, st; + + PDEBUG(D_PACK, "sd isoc irq"); + if (!gspca_dev->streaming) + return; + + if (urb->status != 0) { + if (urb->status == -ESHUTDOWN) + return; /* disconnection */ +#ifdef CONFIG_PM + if (gspca_dev->frozen) + return; +#endif + PDEBUG(D_ERR, "urb status: %d", urb->status); + st = usb_submit_urb(urb, GFP_ATOMIC); + if (st < 0) + err("resubmit urb error %d", st); + return; + } + + /* if this is a data URB (ep 0x82), wait */ + if (urb->transfer_buffer_length > 32) { + sd->last_data_urb = urb; + return; + } + + status_urb = urb; + data_urb = sd->last_data_urb; + sd->last_data_urb = NULL; + + if (!data_urb || data_urb->start_frame != status_urb->start_frame) { + PDEBUG(D_ERR|D_PACK, "lost sync on frames"); + goto resubmit; + } + + if (data_urb->number_of_packets != status_urb->number_of_packets) { + PDEBUG(D_ERR|D_PACK, + "no packets does not match, data: %d, status: %d", + data_urb->number_of_packets, + status_urb->number_of_packets); + goto resubmit; + } + + for (i = 0; i < status_urb->number_of_packets; i++) { + if (data_urb->iso_frame_desc[i].status || + status_urb->iso_frame_desc[i].status) { + PDEBUG(D_ERR|D_PACK, + "pkt %d data-status %d, status-status %d", i, + data_urb->iso_frame_desc[i].status, + status_urb->iso_frame_desc[i].status); + gspca_dev->last_packet_type = DISCARD_PACKET; + continue; + } + + if (status_urb->iso_frame_desc[i].actual_length != 1) { + PDEBUG(D_ERR|D_PACK, + "bad status packet length %d", + status_urb->iso_frame_desc[i].actual_length); + gspca_dev->last_packet_type = DISCARD_PACKET; + continue; + } + + st = *((u8 *)status_urb->transfer_buffer + + status_urb->iso_frame_desc[i].offset); + + data = (u8 *)data_urb->transfer_buffer + + data_urb->iso_frame_desc[i].offset; + + /* st: 0x80-0xff: frame start with frame number (ie 0-7f) + * otherwise: + * bit 0 0: keep packet + * 1: drop packet (padding data) + * + * bit 4 0 button not clicked + * 1 button clicked + * button is used to `take a picture' (in software) + */ + if (st & 0x80) { + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); + } else { +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + u8 button_state = st & 0x40 ? 1 : 0; + if (sd->snapshot_pressed != button_state) { + input_report_key(gspca_dev->input_dev, + KEY_CAMERA, + button_state); + input_sync(gspca_dev->input_dev); + sd->snapshot_pressed = button_state; + } +#endif + if (st & 0x01) + continue; + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, + data_urb->iso_frame_desc[i].actual_length); + } + +resubmit: + if (data_urb) { + st = usb_submit_urb(data_urb, GFP_ATOMIC); + if (st < 0) + PDEBUG(D_ERR|D_PACK, + "usb_submit_urb(data_urb) ret %d", st); + } + st = usb_submit_urb(status_urb, GFP_ATOMIC); + if (st < 0) + err("usb_submit_urb(status_urb) ret %d", st); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) { + konica_stream_off(gspca_dev); + reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG); + konica_stream_on(gspca_dev); + } + + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) { + konica_stream_off(gspca_dev); + reg_w(gspca_dev, sd->contrast, CONTRAST_REG); + konica_stream_on(gspca_dev); + } + + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + + return 0; +} + +static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->saturation = val; + if (gspca_dev->streaming) { + konica_stream_off(gspca_dev); + reg_w(gspca_dev, sd->saturation, SATURATION_REG); + konica_stream_on(gspca_dev); + } + return 0; +} + +static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->saturation; + + return 0; +} + +static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->whitebal = val; + if (gspca_dev->streaming) { + konica_stream_off(gspca_dev); + reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG); + konica_stream_on(gspca_dev); + } + return 0; +} + +static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->whitebal; + + return 0; +} + +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) { + konica_stream_off(gspca_dev); + reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG); + konica_stream_on(gspca_dev); + } + return 0; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .other_input = 1, +#endif +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x04c8, 0x0720)}, /* Intel YC 76 */ + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,11 @@ +config USB_M5602 + tristate "ALi USB m5602 Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the + ALi m5602 connected to various image sensors. + + See for more info. + + To compile this driver as a module, choose M here: the + module will be called gspca_m5602. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_bridge.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_bridge.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_bridge.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_bridge.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,163 @@ +/* + * USB Driver for ALi m5602 based webcams + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#ifndef M5602_BRIDGE_H_ +#define M5602_BRIDGE_H_ + +#include +#include "gspca.h" + +#define MODULE_NAME "ALi m5602" + +/*****************************************************************************/ + +#define M5602_XB_SENSOR_TYPE 0x00 +#define M5602_XB_SENSOR_CTRL 0x01 +#define M5602_XB_LINE_OF_FRAME_H 0x02 +#define M5602_XB_LINE_OF_FRAME_L 0x03 +#define M5602_XB_PIX_OF_LINE_H 0x04 +#define M5602_XB_PIX_OF_LINE_L 0x05 +#define M5602_XB_VSYNC_PARA 0x06 +#define M5602_XB_HSYNC_PARA 0x07 +#define M5602_XB_TEST_MODE_1 0x08 +#define M5602_XB_TEST_MODE_2 0x09 +#define M5602_XB_SIG_INI 0x0a +#define M5602_XB_DS_PARA 0x0e +#define M5602_XB_TRIG_PARA 0x0f +#define M5602_XB_CLK_PD 0x10 +#define M5602_XB_MCU_CLK_CTRL 0x12 +#define M5602_XB_MCU_CLK_DIV 0x13 +#define M5602_XB_SEN_CLK_CTRL 0x14 +#define M5602_XB_SEN_CLK_DIV 0x15 +#define M5602_XB_AUD_CLK_CTRL 0x16 +#define M5602_XB_AUD_CLK_DIV 0x17 +#define M5602_OB_AC_LINK_STATE 0x22 +#define M5602_OB_PCM_SLOT_INDEX 0x24 +#define M5602_OB_GPIO_SLOT_INDEX 0x25 +#define M5602_OB_ACRX_STATUS_ADDRESS_H 0x28 +#define M5602_OB_ACRX_STATUS_DATA_L 0x29 +#define M5602_OB_ACRX_STATUS_DATA_H 0x2a +#define M5602_OB_ACTX_COMMAND_ADDRESS 0x31 +#define M5602_OB_ACRX_COMMAND_DATA_L 0x32 +#define M5602_OB_ACTX_COMMAND_DATA_H 0X33 +#define M5602_XB_DEVCTR1 0x41 +#define M5602_XB_EPSETR0 0x42 +#define M5602_XB_EPAFCTR 0x47 +#define M5602_XB_EPBFCTR 0x49 +#define M5602_XB_EPEFCTR 0x4f +#define M5602_XB_TEST_REG 0x53 +#define M5602_XB_ALT2SIZE 0x54 +#define M5602_XB_ALT3SIZE 0x55 +#define M5602_XB_OBSFRAME 0x56 +#define M5602_XB_PWR_CTL 0x59 +#define M5602_XB_ADC_CTRL 0x60 +#define M5602_XB_ADC_DATA 0x61 +#define M5602_XB_MISC_CTRL 0x62 +#define M5602_XB_SNAPSHOT 0x63 +#define M5602_XB_SCRATCH_1 0x64 +#define M5602_XB_SCRATCH_2 0x65 +#define M5602_XB_SCRATCH_3 0x66 +#define M5602_XB_SCRATCH_4 0x67 +#define M5602_XB_I2C_CTRL 0x68 +#define M5602_XB_I2C_CLK_DIV 0x69 +#define M5602_XB_I2C_DEV_ADDR 0x6a +#define M5602_XB_I2C_REG_ADDR 0x6b +#define M5602_XB_I2C_DATA 0x6c +#define M5602_XB_I2C_STATUS 0x6d +#define M5602_XB_GPIO_DAT_H 0x70 +#define M5602_XB_GPIO_DAT_L 0x71 +#define M5602_XB_GPIO_DIR_H 0x72 +#define M5602_XB_GPIO_DIR_L 0x73 +#define M5602_XB_GPIO_EN_H 0x74 +#define M5602_XB_GPIO_EN_L 0x75 +#define M5602_XB_GPIO_DAT 0x76 +#define M5602_XB_GPIO_DIR 0x77 +#define M5602_XB_SEN_CLK_CONTROL 0x80 +#define M5602_XB_SEN_CLK_DIVISION 0x81 +#define M5602_XB_CPR_CLK_CONTROL 0x82 +#define M5602_XB_CPR_CLK_DIVISION 0x83 +#define M5602_XB_MCU_CLK_CONTROL 0x84 +#define M5602_XB_MCU_CLK_DIVISION 0x85 +#define M5602_XB_DCT_CLK_CONTROL 0x86 +#define M5602_XB_DCT_CLK_DIVISION 0x87 +#define M5602_XB_EC_CLK_CONTROL 0x88 +#define M5602_XB_EC_CLK_DIVISION 0x89 +#define M5602_XB_LBUF_CLK_CONTROL 0x8a +#define M5602_XB_LBUF_CLK_DIVISION 0x8b + +#define I2C_BUSY 0x80 + +/*****************************************************************************/ + +/* Driver info */ +#define DRIVER_AUTHOR "ALi m5602 Linux Driver Project" +#define DRIVER_DESC "ALi m5602 webcam driver" + +#define M5602_ISOC_ENDPOINT_ADDR 0x81 +#define M5602_INTR_ENDPOINT_ADDR 0x82 + +#define M5602_URB_MSG_TIMEOUT 5000 + +/*****************************************************************************/ + +/* A skeleton used for sending messages to the m5602 bridge */ +static const unsigned char bridge_urb_skeleton[] = { + 0x13, 0x00, 0x81, 0x00 +}; + +/* A skeleton used for sending messages to the sensor */ +static const unsigned char sensor_urb_skeleton[] = { + 0x23, M5602_XB_GPIO_EN_H, 0x81, 0x06, + 0x23, M5602_XB_MISC_CTRL, 0x81, 0x80, + 0x13, M5602_XB_I2C_DEV_ADDR, 0x81, 0x00, + 0x13, M5602_XB_I2C_REG_ADDR, 0x81, 0x00, + 0x13, M5602_XB_I2C_DATA, 0x81, 0x00, + 0x13, M5602_XB_I2C_CTRL, 0x81, 0x11 +}; + +struct sd { + struct gspca_dev gspca_dev; + + /* A pointer to the currently connected sensor */ + const struct m5602_sensor *sensor; + + struct sd_desc *desc; + + /* Sensor private data */ + void *sensor_priv; + + /* The current frame's id, used to detect frame boundaries */ + u8 frame_id; + + /* The current frame count */ + u32 frame_count; +}; + +int m5602_read_bridge( + struct sd *sd, const u8 address, u8 *i2c_data); + +int m5602_write_bridge( + struct sd *sd, const u8 address, const u8 i2c_data); + +int m5602_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + +int m5602_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,434 @@ + /* + * USB Driver for ALi m5602 based webcams + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#include "m5602_ov9650.h" +#include "m5602_ov7660.h" +#include "m5602_mt9m111.h" +#include "m5602_po1030.h" +#include "m5602_s5k83a.h" +#include "m5602_s5k4aa.h" + +/* Kernel module parameters */ +int force_sensor; +static int dump_bridge; +int dump_sensor; + +static const struct usb_device_id m5602_table[] = { + {USB_DEVICE(0x0402, 0x5602)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, m5602_table); + +/* Reads a byte from the m5602 */ +int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x04, 0xc0, 0x14, + 0x8100 + address, buf, + 1, M5602_URB_MSG_TIMEOUT); + *i2c_data = buf[0]; + + PDEBUG(D_CONF, "Reading bridge register 0x%x containing 0x%x", + address, *i2c_data); + + /* usb_control_msg(...) returns the number of bytes sent upon success, + mask that and return zero instead*/ + return (err < 0) ? err : 0; +} + +/* Writes a byte to the m5602 */ +int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + PDEBUG(D_CONF, "Writing bridge register 0x%x with 0x%x", + address, i2c_data); + + memcpy(buf, bridge_urb_skeleton, + sizeof(bridge_urb_skeleton)); + buf[1] = address; + buf[3] = i2c_data; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x19, + 0x0000, buf, + 4, M5602_URB_MSG_TIMEOUT); + + /* usb_control_msg(...) returns the number of bytes sent upon success, + mask that and return zero instead */ + return (err < 0) ? err : 0; +} + +static int m5602_wait_for_i2c(struct sd *sd) +{ + int err; + u8 data; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data); + } while ((data & I2C_BUSY) && !err); + return err; +} + +int m5602_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + + if (!len || len > sd->sensor->i2c_regW) + return -EINVAL; + + err = m5602_wait_for_i2c(sd); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, + sd->sensor->i2c_slave_id); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); + if (err < 0) + return err; + + /* Sensors with registers that are of only + one byte width are differently read */ + + /* FIXME: This works with the ov9650, but has issues with the po1030 */ + if (sd->sensor->i2c_regW == 1) { + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 1); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08); + } else { + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len); + } + + for (i = 0; (i < len) && !err; i++) { + err = m5602_wait_for_i2c(sd); + if (err < 0) + return err; + + err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); + + PDEBUG(D_CONF, "Reading sensor register " + "0x%x containing 0x%x ", address, *i2c_data); + } + return err; +} + +int m5602_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + u8 *p; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + /* No sensor with a data width larger than 16 bits has yet been seen */ + if (len > sd->sensor->i2c_regW || !len) + return -EINVAL; + + memcpy(buf, sensor_urb_skeleton, + sizeof(sensor_urb_skeleton)); + + buf[11] = sd->sensor->i2c_slave_id; + buf[15] = address; + + /* Special case larger sensor writes */ + p = buf + 16; + + /* Copy a four byte write sequence for each byte to be written to */ + for (i = 0; i < len; i++) { + memcpy(p, sensor_urb_skeleton + 16, 4); + p[3] = i2c_data[i]; + p += 4; + PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x", + address, i2c_data[i]); + } + + /* Copy the tailer */ + memcpy(p, sensor_urb_skeleton + 20, 4); + + /* Set the total length */ + p[3] = 0x10 + len; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x19, + 0x0000, buf, + 20 + len * 4, M5602_URB_MSG_TIMEOUT); + + return (err < 0) ? err : 0; +} + +/* Dump all the registers of the m5602 bridge, + unfortunately this breaks the camera until it's power cycled */ +static void m5602_dump_bridge(struct sd *sd) +{ + int i; + for (i = 0; i < 0x80; i++) { + unsigned char val = 0; + m5602_read_bridge(sd, i, &val); + info("ALi m5602 address 0x%x contains 0x%x", i, val); + } + info("Warning: The ALi m5602 webcam probably won't work " + "until it's power cycled"); +} + +static int m5602_probe_sensor(struct sd *sd) +{ + /* Try the po1030 */ + sd->sensor = &po1030; + if (!sd->sensor->probe(sd)) + return 0; + + /* Try the mt9m111 sensor */ + sd->sensor = &mt9m111; + if (!sd->sensor->probe(sd)) + return 0; + + /* Try the s5k4aa */ + sd->sensor = &s5k4aa; + if (!sd->sensor->probe(sd)) + return 0; + + /* Try the ov9650 */ + sd->sensor = &ov9650; + if (!sd->sensor->probe(sd)) + return 0; + + /* Try the ov7660 */ + sd->sensor = &ov7660; + if (!sd->sensor->probe(sd)) + return 0; + + /* Try the s5k83a */ + sd->sensor = &s5k83a; + if (!sd->sensor->probe(sd)) + return 0; + + /* More sensor probe function goes here */ + info("Failed to find a sensor"); + sd->sensor = NULL; + return -ENODEV; +} + +static int m5602_configure(struct gspca_dev *gspca_dev, + const struct usb_device_id *id); + +static int m5602_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err; + + PDEBUG(D_CONF, "Initializing ALi m5602 webcam"); + /* Run the init sequence */ + err = sd->sensor->init(sd); + + return err; +} + +static int m5602_start_transfer(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 *buf = sd->gspca_dev.usb_buf; + int err; + + /* Send start command to the camera */ + const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01}; + + if (sd->sensor->start) + sd->sensor->start(sd); + + memcpy(buf, buffer, sizeof(buffer)); + err = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x04, 0x40, 0x19, 0x0000, buf, + sizeof(buffer), M5602_URB_MSG_TIMEOUT); + + PDEBUG(D_STREAM, "Transfer started"); + return (err < 0) ? err : 0; +} + +static void m5602_urb_complete(struct gspca_dev *gspca_dev, + u8 *data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (len < 6) { + PDEBUG(D_PACK, "Packet is less than 6 bytes"); + return; + } + + /* Frame delimiter: ff xx xx xx ff ff */ + if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff && + data[2] != sd->frame_id) { + PDEBUG(D_FRAM, "Frame delimiter detected"); + sd->frame_id = data[2]; + + /* Remove the extra fluff appended on each header */ + data += 6; + len -= 6; + + /* Complete the last frame (if any) */ + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + sd->frame_count++; + + /* Create a new frame */ + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + + PDEBUG(D_FRAM, "Starting new frame %d", + sd->frame_count); + + } else { + int cur_frame_len; + + cur_frame_len = gspca_dev->image_len; + /* Remove urb header */ + data += 4; + len -= 4; + + if (cur_frame_len + len <= gspca_dev->frsz) { + PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes", + sd->frame_count, len); + + gspca_frame_add(gspca_dev, INTER_PACKET, + data, len); + } else { + /* Add the remaining data up to frame size */ + gspca_frame_add(gspca_dev, INTER_PACKET, data, + gspca_dev->frsz - cur_frame_len); + } + } +} + +static void m5602_stop_transfer(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* Run the sensor specific end transfer sequence */ + if (sd->sensor->stop) + sd->sensor->stop(sd); +} + +/* sub-driver description, the ctrl and nctrl is filled at probe time */ +static struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = m5602_configure, + .init = m5602_init, + .start = m5602_start_transfer, + .stopN = m5602_stop_transfer, + .pkt_scan = m5602_urb_complete +}; + +/* this function is called at probe time */ +static int m5602_configure(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + int err; + + cam = &gspca_dev->cam; + sd->desc = &sd_desc; + + if (dump_bridge) + m5602_dump_bridge(sd); + + /* Probe sensor */ + err = m5602_probe_sensor(sd); + if (err) + goto fail; + + return 0; + +fail: + PDEBUG(D_ERR, "ALi m5602 webcam failed"); + cam->cam_mode = NULL; + cam->nmodes = 0; + + return err; +} + +static int m5602_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static void m5602_disconnect(struct usb_interface *intf) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor->disconnect) + sd->sensor->disconnect(sd); + + gspca_disconnect(intf); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = m5602_table, + .probe = m5602_probe, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif + .disconnect = m5602_disconnect +}; + +/* -- module insert / remove -- */ +static int __init mod_m5602_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit mod_m5602_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(mod_m5602_init); +module_exit(mod_m5602_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +module_param(force_sensor, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(force_sensor, + "forces detection of a sensor, " + "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, " + "4 = MT9M111, 5 = PO1030, 6 = OV7660"); + +module_param(dump_bridge, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup"); + +module_param(dump_sensor, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers " + "at startup providing a sensor is found"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,645 @@ +/* + * Driver for the mt9m111 sensor + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#include "m5602_mt9m111.h" + +static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val); +static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val); +static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); + +static struct v4l2_pix_format mt9m111_modes[] = { + { + 640, + 480, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = 640 * 480, + .bytesperline = 640, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + } +}; + +static const struct ctrl mt9m111_ctrls[] = { +#define VFLIP_IDX 0 + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = mt9m111_set_vflip, + .get = mt9m111_get_vflip + }, +#define HFLIP_IDX 1 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = mt9m111_set_hflip, + .get = mt9m111_get_hflip + }, +#define GAIN_IDX 2 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0, + .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, + .step = 1, + .default_value = MT9M111_DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = mt9m111_set_gain, + .get = mt9m111_get_gain + }, +#define AUTO_WHITE_BALANCE_IDX 3 + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = mt9m111_set_auto_white_balance, + .get = mt9m111_get_auto_white_balance + }, +#define GREEN_BALANCE_IDX 4 + { + { + .id = M5602_V4L2_CID_GREEN_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0x00, + .maximum = 0x7ff, + .step = 0x1, + .default_value = MT9M111_GREEN_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = mt9m111_set_green_balance, + .get = mt9m111_get_green_balance + }, +#define BLUE_BALANCE_IDX 5 + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x7ff, + .step = 0x1, + .default_value = MT9M111_BLUE_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = mt9m111_set_blue_balance, + .get = mt9m111_get_blue_balance + }, +#define RED_BALANCE_IDX 5 + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x7ff, + .step = 0x1, + .default_value = MT9M111_RED_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = mt9m111_set_red_balance, + .get = mt9m111_get_red_balance + }, +}; + +static void mt9m111_dump_registers(struct sd *sd); + +int mt9m111_probe(struct sd *sd) +{ + u8 data[2] = {0x00, 0x00}; + int i; + s32 *sensor_settings; + + if (force_sensor) { + if (force_sensor == MT9M111_SENSOR) { + info("Forcing a %s sensor", mt9m111.name); + goto sensor_found; + } + /* If we want to force another sensor, don't try to probe this + * one */ + return -ENODEV; + } + + PDEBUG(D_PROBE, "Probing for a mt9m111 sensor"); + + /* Do the preinit */ + for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { + if (preinit_mt9m111[i][0] == BRIDGE) { + m5602_write_bridge(sd, + preinit_mt9m111[i][1], + preinit_mt9m111[i][2]); + } else { + data[0] = preinit_mt9m111[i][2]; + data[1] = preinit_mt9m111[i][3]; + m5602_write_sensor(sd, + preinit_mt9m111[i][1], data, 2); + } + } + + if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) + return -ENODEV; + + if ((data[0] == 0x14) && (data[1] == 0x3a)) { + info("Detected a mt9m111 sensor"); + goto sensor_found; + } + + return -ENODEV; + +sensor_found: + sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32), + GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + sd->gspca_dev.cam.cam_mode = mt9m111_modes; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes); + sd->desc->ctrls = mt9m111_ctrls; + sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls); + + for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++) + sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + + return 0; +} + +int mt9m111_init(struct sd *sd) +{ + int i, err = 0; + s32 *sensor_settings = sd->sensor_priv; + + /* Init the sensor */ + for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) { + u8 data[2]; + + if (init_mt9m111[i][0] == BRIDGE) { + err = m5602_write_bridge(sd, + init_mt9m111[i][1], + init_mt9m111[i][2]); + } else { + data[0] = init_mt9m111[i][2]; + data[1] = init_mt9m111[i][3]; + err = m5602_write_sensor(sd, + init_mt9m111[i][1], data, 2); + } + } + + if (dump_sensor) + mt9m111_dump_registers(sd); + + err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + if (err < 0) + return err; + + err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); + if (err < 0) + return err; + + err = mt9m111_set_green_balance(&sd->gspca_dev, + sensor_settings[GREEN_BALANCE_IDX]); + if (err < 0) + return err; + + err = mt9m111_set_blue_balance(&sd->gspca_dev, + sensor_settings[BLUE_BALANCE_IDX]); + if (err < 0) + return err; + + err = mt9m111_set_red_balance(&sd->gspca_dev, + sensor_settings[RED_BALANCE_IDX]); + if (err < 0) + return err; + + return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); +} + +int mt9m111_start(struct sd *sd) +{ + int i, err = 0; + u8 data[2]; + struct cam *cam = &sd->gspca_dev.cam; + s32 *sensor_settings = sd->sensor_priv; + + int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1; + int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; + + for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) { + if (start_mt9m111[i][0] == BRIDGE) { + err = m5602_write_bridge(sd, + start_mt9m111[i][1], + start_mt9m111[i][2]); + } else { + data[0] = start_mt9m111[i][2]; + data[1] = start_mt9m111[i][3]; + err = m5602_write_sensor(sd, + start_mt9m111[i][1], data, 2); + } + } + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, + (width >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + + switch (width) { + case 640: + PDEBUG(D_V4L2, "Configuring camera for VGA mode"); + data[0] = MT9M111_RMB_OVER_SIZED; + data[1] = MT9M111_RMB_ROW_SKIP_2X | + MT9M111_RMB_COLUMN_SKIP_2X | + (sensor_settings[VFLIP_IDX] << 0) | + (sensor_settings[HFLIP_IDX] << 1); + + err = m5602_write_sensor(sd, + MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + break; + + case 320: + PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); + data[0] = MT9M111_RMB_OVER_SIZED; + data[1] = MT9M111_RMB_ROW_SKIP_4X | + MT9M111_RMB_COLUMN_SKIP_4X | + (sensor_settings[VFLIP_IDX] << 0) | + (sensor_settings[HFLIP_IDX] << 1); + err = m5602_write_sensor(sd, + MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + break; + } + return err; +} + +void mt9m111_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[VFLIP_IDX]; + PDEBUG(D_V4L2, "Read vertical flip %d", *val); + + return 0; +} + +static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2] = {0x00, 0x00}; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set vertical flip to %d", val); + + sensor_settings[VFLIP_IDX] = val; + + /* The mt9m111 is flipped by default */ + val = !val; + + /* Set the correct page map */ + err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); + if (err < 0) + return err; + + err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + if (err < 0) + return err; + + data[1] = (data[1] & 0xfe) | val; + err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + data, 2); + return err; +} + +static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[HFLIP_IDX]; + PDEBUG(D_V4L2, "Read horizontal flip %d", *val); + + return 0; +} + +static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2] = {0x00, 0x00}; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set horizontal flip to %d", val); + + sensor_settings[HFLIP_IDX] = val; + + /* The mt9m111 is flipped by default */ + val = !val; + + /* Set the correct page map */ + err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); + if (err < 0) + return err; + + err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + if (err < 0) + return err; + + data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02); + err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + data, 2); + return err; +} + +static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + PDEBUG(D_V4L2, "Read gain %d", *val); + + return 0; +} + +static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + int err; + u8 data[2]; + + err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); + if (err < 0) + return err; + + sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01; + data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1)); + + err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); + + PDEBUG(D_V4L2, "Set auto white balance %d", val); + return err; +} + +static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val) { + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read auto white balance %d", *val); + return 0; +} + +static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err, tmp; + u8 data[2] = {0x00, 0x00}; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[GAIN_IDX] = val; + + /* Set the correct page map */ + err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); + if (err < 0) + return err; + + if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2) + return -EINVAL; + + if ((val >= INITIAL_MAX_GAIN * 2 * 2) && + (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2)) + tmp = (1 << 10) | (val << 9) | + (val << 8) | (val / 8); + else if ((val >= INITIAL_MAX_GAIN * 2) && + (val < INITIAL_MAX_GAIN * 2 * 2)) + tmp = (1 << 9) | (1 << 8) | (val / 4); + else if ((val >= INITIAL_MAX_GAIN) && + (val < INITIAL_MAX_GAIN * 2)) + tmp = (1 << 8) | (val / 2); + else + tmp = val; + + data[1] = (tmp & 0xff); + data[0] = (tmp & 0xff00) >> 8; + PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp, + data[1], data[0]); + + err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN, + data, 2); + + return err; +} + +static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[GREEN_BALANCE_IDX] = val; + data[1] = (val & 0xff); + data[0] = (val & 0xff00) >> 8; + + PDEBUG(D_V4L2, "Set green balance %d", val); + err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN, + data, 2); + if (err < 0) + return err; + + return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN, + data, 2); +} + +static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GREEN_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read green balance %d", *val); + return 0; +} + +static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[BLUE_BALANCE_IDX] = val; + data[1] = (val & 0xff); + data[0] = (val & 0xff00) >> 8; + + PDEBUG(D_V4L2, "Set blue balance %d", val); + + return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN, + data, 2); +} + +static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[BLUE_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read blue balance %d", *val); + return 0; +} + +static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[RED_BALANCE_IDX] = val; + data[1] = (val & 0xff); + data[0] = (val & 0xff00) >> 8; + + PDEBUG(D_V4L2, "Set red balance %d", val); + + return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN, + data, 2); +} + +static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[RED_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read red balance %d", *val); + return 0; +} + +static void mt9m111_dump_registers(struct sd *sd) +{ + u8 address, value[2] = {0x00, 0x00}; + + info("Dumping the mt9m111 register state"); + + info("Dumping the mt9m111 sensor core registers"); + value[1] = MT9M111_SENSOR_CORE; + m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); + for (address = 0; address < 0xff; address++) { + m5602_read_sensor(sd, address, value, 2); + info("register 0x%x contains 0x%x%x", + address, value[0], value[1]); + } + + info("Dumping the mt9m111 color pipeline registers"); + value[1] = MT9M111_COLORPIPE; + m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); + for (address = 0; address < 0xff; address++) { + m5602_read_sensor(sd, address, value, 2); + info("register 0x%x contains 0x%x%x", + address, value[0], value[1]); + } + + info("Dumping the mt9m111 camera control registers"); + value[1] = MT9M111_CAMERA_CONTROL; + m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); + for (address = 0; address < 0xff; address++) { + m5602_read_sensor(sd, address, value, 2); + info("register 0x%x contains 0x%x%x", + address, value[0], value[1]); + } + + info("mt9m111 register state dump complete"); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,271 @@ +/* + * Driver for the mt9m111 sensor + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * Some defines taken from the mt9m111 sensor driver + * Copyright (C) 2008, Robert Jarzmik + * + * 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, version 2. + * + */ + +#ifndef M5602_MT9M111_H_ +#define M5602_MT9M111_H_ + +#include "m5602_sensor.h" + +/*****************************************************************************/ + +#define MT9M111_SC_CHIPVER 0x00 +#define MT9M111_SC_ROWSTART 0x01 +#define MT9M111_SC_COLSTART 0x02 +#define MT9M111_SC_WINDOW_HEIGHT 0x03 +#define MT9M111_SC_WINDOW_WIDTH 0x04 +#define MT9M111_SC_HBLANK_CONTEXT_B 0x05 +#define MT9M111_SC_VBLANK_CONTEXT_B 0x06 +#define MT9M111_SC_HBLANK_CONTEXT_A 0x07 +#define MT9M111_SC_VBLANK_CONTEXT_A 0x08 +#define MT9M111_SC_SHUTTER_WIDTH 0x09 +#define MT9M111_SC_ROW_SPEED 0x0a +#define MT9M111_SC_EXTRA_DELAY 0x0b +#define MT9M111_SC_SHUTTER_DELAY 0x0c +#define MT9M111_SC_RESET 0x0d +#define MT9M111_SC_R_MODE_CONTEXT_B 0x20 +#define MT9M111_SC_R_MODE_CONTEXT_A 0x21 +#define MT9M111_SC_FLASH_CONTROL 0x23 +#define MT9M111_SC_GREEN_1_GAIN 0x2b +#define MT9M111_SC_BLUE_GAIN 0x2c +#define MT9M111_SC_RED_GAIN 0x2d +#define MT9M111_SC_GREEN_2_GAIN 0x2e +#define MT9M111_SC_GLOBAL_GAIN 0x2f + +#define MT9M111_CONTEXT_CONTROL 0xc8 +#define MT9M111_PAGE_MAP 0xf0 +#define MT9M111_BYTEWISE_ADDRESS 0xf1 + +#define MT9M111_CP_OPERATING_MODE_CTL 0x06 +#define MT9M111_CP_LUMA_OFFSET 0x34 +#define MT9M111_CP_LUMA_CLIP 0x35 +#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A 0x3a +#define MT9M111_CP_LENS_CORRECTION_1 0x3b +#define MT9M111_CP_DEFECT_CORR_CONTEXT_A 0x4c +#define MT9M111_CP_DEFECT_CORR_CONTEXT_B 0x4d +#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B 0x9b +#define MT9M111_CP_GLOBAL_CLK_CONTROL 0xb3 + +#define MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18 0x65 +#define MT9M111_CC_AWB_PARAMETER_7 0x28 + +#define MT9M111_SENSOR_CORE 0x00 +#define MT9M111_COLORPIPE 0x01 +#define MT9M111_CAMERA_CONTROL 0x02 + +#define MT9M111_RESET (1 << 0) +#define MT9M111_RESTART (1 << 1) +#define MT9M111_ANALOG_STANDBY (1 << 2) +#define MT9M111_CHIP_ENABLE (1 << 3) +#define MT9M111_CHIP_DISABLE (0 << 3) +#define MT9M111_OUTPUT_DISABLE (1 << 4) +#define MT9M111_SHOW_BAD_FRAMES (1 << 0) +#define MT9M111_RESTART_BAD_FRAMES (1 << 1) +#define MT9M111_SYNCHRONIZE_CHANGES (1 << 7) + +#define MT9M111_RMB_OVER_SIZED (1 << 0) +#define MT9M111_RMB_MIRROR_ROWS (1 << 0) +#define MT9M111_RMB_MIRROR_COLS (1 << 1) +#define MT9M111_RMB_ROW_SKIP_2X (1 << 2) +#define MT9M111_RMB_COLUMN_SKIP_2X (1 << 3) +#define MT9M111_RMB_ROW_SKIP_4X (1 << 4) +#define MT9M111_RMB_COLUMN_SKIP_4X (1 << 5) + +#define MT9M111_COLOR_MATRIX_BYPASS (1 << 4) +#define MT9M111_SEL_CONTEXT_B (1 << 3) + +#define MT9M111_TRISTATE_PIN_IN_STANDBY (1 << 1) +#define MT9M111_SOC_SOFT_STANDBY (1 << 0) + +#define MT9M111_2D_DEFECT_CORRECTION_ENABLE (1 << 0) + +#define INITIAL_MAX_GAIN 64 +#define MT9M111_DEFAULT_GAIN 283 +#define MT9M111_GREEN_GAIN_DEFAULT 0x20 +#define MT9M111_BLUE_GAIN_DEFAULT 0x20 +#define MT9M111_RED_GAIN_DEFAULT 0x20 + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; + +int mt9m111_probe(struct sd *sd); +int mt9m111_init(struct sd *sd); +int mt9m111_start(struct sd *sd); +void mt9m111_disconnect(struct sd *sd); + +static const struct m5602_sensor mt9m111 = { + .name = "MT9M111", + + .i2c_slave_id = 0xba, + .i2c_regW = 2, + + .probe = mt9m111_probe, + .init = mt9m111_init, + .disconnect = mt9m111_disconnect, + .start = mt9m111_start, +}; + +static const unsigned char preinit_mt9m111[][4] = { + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, + MT9M111_RESET | + MT9M111_RESTART | + MT9M111_ANALOG_STANDBY | + MT9M111_CHIP_DISABLE, + MT9M111_SHOW_BAD_FRAMES | + MT9M111_RESTART_BAD_FRAMES | + MT9M111_SYNCHRONIZE_CHANGES}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00} +}; + +static const unsigned char init_mt9m111[][4] = { + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, + + {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, + {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, + MT9M111_CP_OPERATING_MODE_CTL}, + {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, + MT9M111_2D_DEFECT_CORRECTION_ENABLE}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, + MT9M111_2D_DEFECT_CORRECTION_ENABLE}, + {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, + {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, + {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, + {SENSOR, 0xcd, 0x00, 0x0e}, + {SENSOR, 0xd0, 0x00, 0x40}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, + {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, + {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, + + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, + {SENSOR, 0x33, 0x03, 0x49}, + {SENSOR, 0x34, 0xc0, 0x19}, + {SENSOR, 0x3f, 0x20, 0x20}, + {SENSOR, 0x40, 0x20, 0x20}, + {SENSOR, 0x5a, 0xc0, 0x0a}, + {SENSOR, 0x70, 0x7b, 0x0a}, + {SENSOR, 0x71, 0xff, 0x00}, + {SENSOR, 0x72, 0x19, 0x0e}, + {SENSOR, 0x73, 0x18, 0x0f}, + {SENSOR, 0x74, 0x57, 0x32}, + {SENSOR, 0x75, 0x56, 0x34}, + {SENSOR, 0x76, 0x73, 0x35}, + {SENSOR, 0x77, 0x30, 0x12}, + {SENSOR, 0x78, 0x79, 0x02}, + {SENSOR, 0x79, 0x75, 0x06}, + {SENSOR, 0x7a, 0x77, 0x0a}, + {SENSOR, 0x7b, 0x78, 0x09}, + {SENSOR, 0x7c, 0x7d, 0x06}, + {SENSOR, 0x7d, 0x31, 0x10}, + {SENSOR, 0x7e, 0x00, 0x7e}, + {SENSOR, 0x80, 0x59, 0x04}, + {SENSOR, 0x81, 0x59, 0x04}, + {SENSOR, 0x82, 0x57, 0x0a}, + {SENSOR, 0x83, 0x58, 0x0b}, + {SENSOR, 0x84, 0x47, 0x0c}, + {SENSOR, 0x85, 0x48, 0x0e}, + {SENSOR, 0x86, 0x5b, 0x02}, + {SENSOR, 0x87, 0x00, 0x5c}, + {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, MT9M111_SEL_CONTEXT_B}, + {SENSOR, 0x60, 0x00, 0x80}, + {SENSOR, 0x61, 0x00, 0x00}, + {SENSOR, 0x62, 0x00, 0x00}, + {SENSOR, 0x63, 0x00, 0x00}, + {SENSOR, 0x64, 0x00, 0x00}, + + {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, /* 13 */ + {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, /* 18 */ + {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, /* 1024 */ + {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, /* 1296 */ + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, /* 352 */ + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, /* 17 */ + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, /* 352 */ + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, /* 17 */ + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, /* 271 */ + {SENSOR, 0x30, 0x04, 0x00}, + /* Set number of blank rows chosen to 400 */ + {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90}, +}; + +static const unsigned char start_mt9m111[][4] = { + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, +}; +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,487 @@ +/* + * Driver for the ov7660 sensor + * + * Copyright (C) 2009 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#include "m5602_ov7660.h" + +static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val); +static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val); +static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); +static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val); + +static const struct ctrl ov7660_ctrls[] = { +#define GAIN_IDX 1 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = OV7660_DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov7660_set_gain, + .get = ov7660_get_gain + }, +#define BLUE_BALANCE_IDX 2 +#define RED_BALANCE_IDX 3 +#define AUTO_WHITE_BALANCE_IDX 4 + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = ov7660_set_auto_white_balance, + .get = ov7660_get_auto_white_balance + }, +#define AUTO_GAIN_CTRL_IDX 5 + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto gain control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = ov7660_set_auto_gain, + .get = ov7660_get_auto_gain + }, +#define AUTO_EXPOSURE_IDX 6 + { + { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = ov7660_set_auto_exposure, + .get = ov7660_get_auto_exposure + }, +#define HFLIP_IDX 7 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = ov7660_set_hflip, + .get = ov7660_get_hflip + }, +#define VFLIP_IDX 8 + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = ov7660_set_vflip, + .get = ov7660_get_vflip + }, + +}; + +static struct v4l2_pix_format ov7660_modes[] = { + { + 640, + 480, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 640 * 480, + .bytesperline = 640, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + } +}; + +static void ov7660_dump_registers(struct sd *sd); + +int ov7660_probe(struct sd *sd) +{ + int err = 0, i; + u8 prod_id = 0, ver_id = 0; + + s32 *sensor_settings; + + if (force_sensor) { + if (force_sensor == OV7660_SENSOR) { + info("Forcing an %s sensor", ov7660.name); + goto sensor_found; + } + /* If we want to force another sensor, + don't try to probe this one */ + return -ENODEV; + } + + /* Do the preinit */ + for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) { + u8 data[2]; + + if (preinit_ov7660[i][0] == BRIDGE) { + err = m5602_write_bridge(sd, + preinit_ov7660[i][1], + preinit_ov7660[i][2]); + } else { + data[0] = preinit_ov7660[i][2]; + err = m5602_write_sensor(sd, + preinit_ov7660[i][1], data, 1); + } + } + if (err < 0) + return err; + + if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1)) + return -ENODEV; + + if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1)) + return -ENODEV; + + info("Sensor reported 0x%x%x", prod_id, ver_id); + + if ((prod_id == 0x76) && (ver_id == 0x60)) { + info("Detected a ov7660 sensor"); + goto sensor_found; + } + return -ENODEV; + +sensor_found: + sensor_settings = kmalloc( + ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + sd->gspca_dev.cam.cam_mode = ov7660_modes; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes); + sd->desc->ctrls = ov7660_ctrls; + sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls); + + for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++) + sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + + return 0; +} + +int ov7660_init(struct sd *sd) +{ + int i, err = 0; + s32 *sensor_settings = sd->sensor_priv; + + /* Init the sensor */ + for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { + u8 data[2]; + + if (init_ov7660[i][0] == BRIDGE) { + err = m5602_write_bridge(sd, + init_ov7660[i][1], + init_ov7660[i][2]); + } else { + data[0] = init_ov7660[i][2]; + err = m5602_write_sensor(sd, + init_ov7660[i][1], data, 1); + } + } + + if (dump_sensor) + ov7660_dump_registers(sd); + + err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + if (err < 0) + return err; + + err = ov7660_set_auto_white_balance(&sd->gspca_dev, + sensor_settings[AUTO_WHITE_BALANCE_IDX]); + if (err < 0) + return err; + + err = ov7660_set_auto_gain(&sd->gspca_dev, + sensor_settings[AUTO_GAIN_CTRL_IDX]); + if (err < 0) + return err; + + err = ov7660_set_auto_exposure(&sd->gspca_dev, + sensor_settings[AUTO_EXPOSURE_IDX]); + if (err < 0) + return err; + err = ov7660_set_hflip(&sd->gspca_dev, + sensor_settings[HFLIP_IDX]); + if (err < 0) + return err; + + err = ov7660_set_vflip(&sd->gspca_dev, + sensor_settings[VFLIP_IDX]); + + return err; +} + +int ov7660_start(struct sd *sd) +{ + return 0; +} + +int ov7660_stop(struct sd *sd) +{ + return 0; +} + +void ov7660_disconnect(struct sd *sd) +{ + ov7660_stop(sd); + + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + PDEBUG(D_V4L2, "Read gain %d", *val); + return 0; +} + +static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Setting gain to %d", val); + + sensor_settings[GAIN_IDX] = val; + + err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); + return err; +} + + +static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; + return 0; +} + +static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set auto white balance to %d", val); + + sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; + err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); + if (err < 0) + return err; + + i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); + err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); + + return err; +} + +static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_GAIN_CTRL_IDX]; + PDEBUG(D_V4L2, "Read auto gain control %d", *val); + return 0; +} + +static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set auto gain control to %d", val); + + sensor_settings[AUTO_GAIN_CTRL_IDX] = val; + err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); + if (err < 0) + return err; + + i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); + + return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); +} + +static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Read auto exposure control %d", *val); + return 0; +} + +static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, + __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set auto exposure control to %d", val); + + sensor_settings[AUTO_EXPOSURE_IDX] = val; + err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); + if (err < 0) + return err; + + i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); + + return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); +} + +static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[HFLIP_IDX]; + PDEBUG(D_V4L2, "Read horizontal flip %d", *val); + return 0; +} + +static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set horizontal flip to %d", val); + + sensor_settings[HFLIP_IDX] = val; + + i2c_data = ((val & 0x01) << 5) | + (sensor_settings[VFLIP_IDX] << 4); + + err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); + + return err; +} + +static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[VFLIP_IDX]; + PDEBUG(D_V4L2, "Read vertical flip %d", *val); + + return 0; +} + +static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set vertical flip to %d", val); + sensor_settings[VFLIP_IDX] = val; + + i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); + err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); + if (err < 0) + return err; + + /* When vflip is toggled we need to readjust the bridge hsync/vsync */ + if (gspca_dev->streaming) + err = ov7660_start(sd); + + return err; +} + +static void ov7660_dump_registers(struct sd *sd) +{ + int address; + info("Dumping the ov7660 register state"); + for (address = 0; address < 0xa9; address++) { + u8 value; + m5602_read_sensor(sd, address, &value, 1); + info("register 0x%x contains 0x%x", + address, value); + } + + info("ov7660 register state dump complete"); + + info("Probing for which registers that are read/write"); + for (address = 0; address < 0xff; address++) { + u8 old_value, ctrl_value; + u8 test_value[2] = {0xff, 0xff}; + + m5602_read_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, test_value, 1); + m5602_read_sensor(sd, address, &ctrl_value, 1); + + if (ctrl_value == test_value[0]) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original value */ + m5602_write_sensor(sd, address, &old_value, 1); + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,260 @@ +/* + * Driver for the ov7660 sensor + * + * Copyright (C) 2009 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#ifndef M5602_OV7660_H_ +#define M5602_OV7660_H_ + +#include "m5602_sensor.h" + +#define OV7660_GAIN 0x00 +#define OV7660_BLUE_GAIN 0x01 +#define OV7660_RED_GAIN 0x02 +#define OV7660_VREF 0x03 +#define OV7660_COM1 0x04 +#define OV7660_BAVE 0x05 +#define OV7660_GEAVE 0x06 +#define OV7660_AECHH 0x07 +#define OV7660_RAVE 0x08 +#define OV7660_COM2 0x09 +#define OV7660_PID 0x0a +#define OV7660_VER 0x0b +#define OV7660_COM3 0x0c +#define OV7660_COM4 0x0d +#define OV7660_COM5 0x0e +#define OV7660_COM6 0x0f +#define OV7660_AECH 0x10 +#define OV7660_CLKRC 0x11 +#define OV7660_COM7 0x12 +#define OV7660_COM8 0x13 +#define OV7660_COM9 0x14 +#define OV7660_COM10 0x15 +#define OV7660_RSVD16 0x16 +#define OV7660_HSTART 0x17 +#define OV7660_HSTOP 0x18 +#define OV7660_VSTART 0x19 +#define OV7660_VSTOP 0x1a +#define OV7660_PSHFT 0x1b +#define OV7660_MIDH 0x1c +#define OV7660_MIDL 0x1d +#define OV7660_MVFP 0x1e +#define OV7660_LAEC 0x1f +#define OV7660_BOS 0x20 +#define OV7660_GBOS 0x21 +#define OV7660_GROS 0x22 +#define OV7660_ROS 0x23 +#define OV7660_AEW 0x24 +#define OV7660_AEB 0x25 +#define OV7660_VPT 0x26 +#define OV7660_BBIAS 0x27 +#define OV7660_GbBIAS 0x28 +#define OV7660_RSVD29 0x29 +#define OV7660_RBIAS 0x2c +#define OV7660_HREF 0x32 +#define OV7660_ADC 0x37 +#define OV7660_OFON 0x39 +#define OV7660_TSLB 0x3a +#define OV7660_COM12 0x3c +#define OV7660_COM13 0x3d +#define OV7660_LCC1 0x62 +#define OV7660_LCC2 0x63 +#define OV7660_LCC3 0x64 +#define OV7660_LCC4 0x65 +#define OV7660_LCC5 0x66 +#define OV7660_HV 0x69 +#define OV7660_RSVDA1 0xa1 + +#define OV7660_DEFAULT_GAIN 0x0e +#define OV7660_DEFAULT_RED_GAIN 0x80 +#define OV7660_DEFAULT_BLUE_GAIN 0x80 +#define OV7660_DEFAULT_SATURATION 0x00 +#define OV7660_DEFAULT_EXPOSURE 0x20 + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; + +int ov7660_probe(struct sd *sd); +int ov7660_init(struct sd *sd); +int ov7660_start(struct sd *sd); +int ov7660_stop(struct sd *sd); +void ov7660_disconnect(struct sd *sd); + +static const struct m5602_sensor ov7660 = { + .name = "ov7660", + .i2c_slave_id = 0x42, + .i2c_regW = 1, + .probe = ov7660_probe, + .init = ov7660_init, + .start = ov7660_start, + .stop = ov7660_stop, + .disconnect = ov7660_disconnect, +}; + +static const unsigned char preinit_ov7660[][4] = { + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + + {SENSOR, OV7660_OFON, 0x0c}, + {SENSOR, OV7660_COM2, 0x11}, + {SENSOR, OV7660_COM7, 0x05}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00} +}; + +static const unsigned char init_ov7660[][4] = { + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, + {SENSOR, OV7660_COM7, 0x80}, + {SENSOR, OV7660_CLKRC, 0x80}, + {SENSOR, OV7660_COM9, 0x4c}, + {SENSOR, OV7660_OFON, 0x43}, + {SENSOR, OV7660_COM12, 0x28}, + {SENSOR, OV7660_COM8, 0x00}, + {SENSOR, OV7660_COM10, 0x40}, + {SENSOR, OV7660_HSTART, 0x0c}, + {SENSOR, OV7660_HSTOP, 0x61}, + {SENSOR, OV7660_HREF, 0xa4}, + {SENSOR, OV7660_PSHFT, 0x0b}, + {SENSOR, OV7660_VSTART, 0x01}, + {SENSOR, OV7660_VSTOP, 0x7a}, + {SENSOR, OV7660_VSTOP, 0x00}, + {SENSOR, OV7660_COM7, 0x05}, + {SENSOR, OV7660_COM6, 0x42}, + {SENSOR, OV7660_BBIAS, 0x94}, + {SENSOR, OV7660_GbBIAS, 0x94}, + {SENSOR, OV7660_RSVD29, 0x94}, + {SENSOR, OV7660_RBIAS, 0x94}, + {SENSOR, OV7660_COM1, 0x00}, + {SENSOR, OV7660_AECH, 0x00}, + {SENSOR, OV7660_AECHH, 0x00}, + {SENSOR, OV7660_ADC, 0x05}, + {SENSOR, OV7660_COM13, 0x00}, + {SENSOR, OV7660_RSVDA1, 0x23}, + {SENSOR, OV7660_TSLB, 0x0d}, + {SENSOR, OV7660_HV, 0x80}, + {SENSOR, OV7660_LCC1, 0x00}, + {SENSOR, OV7660_LCC2, 0x00}, + {SENSOR, OV7660_LCC3, 0x10}, + {SENSOR, OV7660_LCC4, 0x40}, + {SENSOR, OV7660_LCC5, 0x01}, + + {SENSOR, OV7660_AECH, 0x20}, + {SENSOR, OV7660_COM1, 0x00}, + {SENSOR, OV7660_OFON, 0x0c}, + {SENSOR, OV7660_COM2, 0x11}, + {SENSOR, OV7660_COM7, 0x05}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, + {SENSOR, OV7660_AECH, 0x5f}, + {SENSOR, OV7660_COM1, 0x03}, + {SENSOR, OV7660_OFON, 0x0c}, + {SENSOR, OV7660_COM2, 0x11}, + {SENSOR, OV7660_COM7, 0x05}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, + {BRIDGE, M5602_XB_SIG_INI, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x08}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x27}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0xa7}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, +}; +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,880 @@ +/* + * Driver for the ov9650 sensor + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#include "m5602_ov9650.h" + +static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val); +static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val); +static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val); + +/* Vertically and horizontally flips the image if matched, needed for machines + where the sensor is mounted upside down */ +static + const + struct dmi_system_id ov9650_flip_dmi_table[] = { + { + .ident = "ASUS A6Ja", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6J") + } + }, + { + .ident = "ASUS A6JC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") + } + }, + { + .ident = "ASUS A6K", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6K") + } + }, + { + .ident = "ASUS A6Kt", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") + } + }, + { + .ident = "ASUS A6VA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VA") + } + }, + { + + .ident = "ASUS A6VC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VC") + } + }, + { + .ident = "ASUS A6VM", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VM") + } + }, + { + .ident = "ASUS A7V", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A7V") + } + }, + { + .ident = "Alienware Aurora m9700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700") + } + }, + {} +}; + +static const struct ctrl ov9650_ctrls[] = { +#define EXPOSURE_IDX 0 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = 0x1ff, + .step = 0x4, + .default_value = EXPOSURE_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov9650_set_exposure, + .get = ov9650_get_exposure + }, +#define GAIN_IDX 1 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0x3ff, + .step = 0x1, + .default_value = GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov9650_set_gain, + .get = ov9650_get_gain + }, +#define RED_BALANCE_IDX 2 + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = RED_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov9650_set_red_balance, + .get = ov9650_get_red_balance + }, +#define BLUE_BALANCE_IDX 3 + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = BLUE_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov9650_set_blue_balance, + .get = ov9650_get_blue_balance + }, +#define HFLIP_IDX 4 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = ov9650_set_hflip, + .get = ov9650_get_hflip + }, +#define VFLIP_IDX 5 + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = ov9650_set_vflip, + .get = ov9650_get_vflip + }, +#define AUTO_WHITE_BALANCE_IDX 6 + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = ov9650_set_auto_white_balance, + .get = ov9650_get_auto_white_balance + }, +#define AUTO_GAIN_CTRL_IDX 7 + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto gain control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = ov9650_set_auto_gain, + .get = ov9650_get_auto_gain + }, +#define AUTO_EXPOSURE_IDX 8 + { + { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = ov9650_set_auto_exposure, + .get = ov9650_get_auto_exposure + } + +}; + +static struct v4l2_pix_format ov9650_modes[] = { + { + 176, + 144, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 176 * 144, + .bytesperline = 176, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 9 + }, { + 320, + 240, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 320 * 240, + .bytesperline = 320, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 8 + }, { + 352, + 288, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 352 * 288, + .bytesperline = 352, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 9 + }, { + 640, + 480, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 640 * 480, + .bytesperline = 640, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 9 + } +}; + +static void ov9650_dump_registers(struct sd *sd); + +int ov9650_probe(struct sd *sd) +{ + int err = 0; + u8 prod_id = 0, ver_id = 0, i; + s32 *sensor_settings; + + if (force_sensor) { + if (force_sensor == OV9650_SENSOR) { + info("Forcing an %s sensor", ov9650.name); + goto sensor_found; + } + /* If we want to force another sensor, + don't try to probe this one */ + return -ENODEV; + } + + PDEBUG(D_PROBE, "Probing for an ov9650 sensor"); + + /* Run the pre-init before probing the sensor */ + for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) { + u8 data = preinit_ov9650[i][2]; + if (preinit_ov9650[i][0] == SENSOR) + err = m5602_write_sensor(sd, + preinit_ov9650[i][1], &data, 1); + else + err = m5602_write_bridge(sd, + preinit_ov9650[i][1], data); + } + + if (err < 0) + return err; + + if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1)) + return -ENODEV; + + if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1)) + return -ENODEV; + + if ((prod_id == 0x96) && (ver_id == 0x52)) { + info("Detected an ov9650 sensor"); + goto sensor_found; + } + return -ENODEV; + +sensor_found: + sensor_settings = kmalloc( + ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + sd->gspca_dev.cam.cam_mode = ov9650_modes; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes); + sd->desc->ctrls = ov9650_ctrls; + sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls); + + for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++) + sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + return 0; +} + +int ov9650_init(struct sd *sd) +{ + int i, err = 0; + u8 data; + s32 *sensor_settings = sd->sensor_priv; + + if (dump_sensor) + ov9650_dump_registers(sd); + + for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) { + data = init_ov9650[i][2]; + if (init_ov9650[i][0] == SENSOR) + err = m5602_write_sensor(sd, init_ov9650[i][1], + &data, 1); + else + err = m5602_write_bridge(sd, init_ov9650[i][1], data); + } + + err = ov9650_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); + if (err < 0) + return err; + + err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + if (err < 0) + return err; + + err = ov9650_set_red_balance(&sd->gspca_dev, + sensor_settings[RED_BALANCE_IDX]); + if (err < 0) + return err; + + err = ov9650_set_blue_balance(&sd->gspca_dev, + sensor_settings[BLUE_BALANCE_IDX]); + if (err < 0) + return err; + + err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); + if (err < 0) + return err; + + err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + if (err < 0) + return err; + + err = ov9650_set_auto_exposure(&sd->gspca_dev, + sensor_settings[AUTO_EXPOSURE_IDX]); + if (err < 0) + return err; + + err = ov9650_set_auto_white_balance(&sd->gspca_dev, + sensor_settings[AUTO_WHITE_BALANCE_IDX]); + if (err < 0) + return err; + + err = ov9650_set_auto_gain(&sd->gspca_dev, + sensor_settings[AUTO_GAIN_CTRL_IDX]); + return err; +} + +int ov9650_start(struct sd *sd) +{ + u8 data; + int i, err = 0; + struct cam *cam = &sd->gspca_dev.cam; + s32 *sensor_settings = sd->sensor_priv; + + int width = cam->cam_mode[sd->gspca_dev.curr_mode].width; + int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; + int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; + int hor_offs = OV9650_LEFT_OFFSET; + + if ((!dmi_check_system(ov9650_flip_dmi_table) && + sensor_settings[VFLIP_IDX]) || + (dmi_check_system(ov9650_flip_dmi_table) && + !sensor_settings[VFLIP_IDX])) + ver_offs--; + + if (width <= 320) + hor_offs /= 2; + + /* Synthesize the vsync/hsync setup */ + for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) { + if (res_init_ov9650[i][0] == BRIDGE) + err = m5602_write_bridge(sd, res_init_ov9650[i][1], + res_init_ov9650[i][2]); + else if (res_init_ov9650[i][0] == SENSOR) { + data = res_init_ov9650[i][2]; + err = m5602_write_sensor(sd, + res_init_ov9650[i][1], &data, 1); + } + } + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, + ((ver_offs >> 8) & 0xff)); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff)); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, + (hor_offs >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, + ((width + hor_offs) >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, + ((width + hor_offs) & 0xff)); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + + switch (width) { + case 640: + PDEBUG(D_V4L2, "Configuring camera for VGA mode"); + + data = OV9650_VGA_SELECT | OV9650_RGB_SELECT | + OV9650_RAW_RGB_SELECT; + err = m5602_write_sensor(sd, OV9650_COM7, &data, 1); + break; + + case 352: + PDEBUG(D_V4L2, "Configuring camera for CIF mode"); + + data = OV9650_CIF_SELECT | OV9650_RGB_SELECT | + OV9650_RAW_RGB_SELECT; + err = m5602_write_sensor(sd, OV9650_COM7, &data, 1); + break; + + case 320: + PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); + + data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT | + OV9650_RAW_RGB_SELECT; + err = m5602_write_sensor(sd, OV9650_COM7, &data, 1); + break; + + case 176: + PDEBUG(D_V4L2, "Configuring camera for QCIF mode"); + + data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT | + OV9650_RAW_RGB_SELECT; + err = m5602_write_sensor(sd, OV9650_COM7, &data, 1); + break; + } + return err; +} + +int ov9650_stop(struct sd *sd) +{ + u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X; + return m5602_write_sensor(sd, OV9650_COM2, &data, 1); +} + +void ov9650_disconnect(struct sd *sd) +{ + ov9650_stop(sd); + + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Read exposure %d", *val); + return 0; +} + +static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + PDEBUG(D_V4L2, "Set exposure to %d", val); + + sensor_settings[EXPOSURE_IDX] = val; + /* The 6 MSBs */ + i2c_data = (val >> 10) & 0x3f; + err = m5602_write_sensor(sd, OV9650_AECHM, + &i2c_data, 1); + if (err < 0) + return err; + + /* The 8 middle bits */ + i2c_data = (val >> 2) & 0xff; + err = m5602_write_sensor(sd, OV9650_AECH, + &i2c_data, 1); + if (err < 0) + return err; + + /* The 2 LSBs */ + i2c_data = val & 0x03; + err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1); + return err; +} + +static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + PDEBUG(D_V4L2, "Read gain %d", *val); + return 0; +} + +static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Setting gain to %d", val); + + sensor_settings[GAIN_IDX] = val; + + /* The 2 MSB */ + /* Read the OV9650_VREF register first to avoid + corrupting the VREF high and low bits */ + err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + if (err < 0) + return err; + + /* Mask away all uninteresting bits */ + i2c_data = ((val & 0x0300) >> 2) | + (i2c_data & 0x3f); + err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1); + if (err < 0) + return err; + + /* The 8 LSBs */ + i2c_data = val & 0xff; + err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); + return err; +} + +static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[RED_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read red gain %d", *val); + return 0; +} + +static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set red gain to %d", val); + + sensor_settings[RED_BALANCE_IDX] = val; + + i2c_data = val & 0xff; + err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1); + return err; +} + +static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[BLUE_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read blue gain %d", *val); + + return 0; +} + +static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set blue gain to %d", val); + + sensor_settings[BLUE_BALANCE_IDX] = val; + + i2c_data = val & 0xff; + err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); + return err; +} + +static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[HFLIP_IDX]; + PDEBUG(D_V4L2, "Read horizontal flip %d", *val); + return 0; +} + +static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set horizontal flip to %d", val); + + sensor_settings[HFLIP_IDX] = val; + + if (!dmi_check_system(ov9650_flip_dmi_table)) + i2c_data = ((val & 0x01) << 5) | + (sensor_settings[VFLIP_IDX] << 4); + else + i2c_data = ((val & 0x01) << 5) | + (!sensor_settings[VFLIP_IDX] << 4); + + err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); + + return err; +} + +static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[VFLIP_IDX]; + PDEBUG(D_V4L2, "Read vertical flip %d", *val); + + return 0; +} + +static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set vertical flip to %d", val); + sensor_settings[VFLIP_IDX] = val; + + if (dmi_check_system(ov9650_flip_dmi_table)) + val = !val; + + i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); + err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); + if (err < 0) + return err; + + /* When vflip is toggled we need to readjust the bridge hsync/vsync */ + if (gspca_dev->streaming) + err = ov9650_start(sd); + + return err; +} + +static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Read auto exposure control %d", *val); + return 0; +} + +static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, + __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set auto exposure control to %d", val); + + sensor_settings[AUTO_EXPOSURE_IDX] = val; + err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + if (err < 0) + return err; + + i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); + + return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); +} + +static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; + return 0; +} + +static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set auto white balance to %d", val); + + sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; + err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + if (err < 0) + return err; + + i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); + err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); + + return err; +} + +static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_GAIN_CTRL_IDX]; + PDEBUG(D_V4L2, "Read auto gain control %d", *val); + return 0; +} + +static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Set auto gain control to %d", val); + + sensor_settings[AUTO_GAIN_CTRL_IDX] = val; + err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + if (err < 0) + return err; + + i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); + + return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); +} + +static void ov9650_dump_registers(struct sd *sd) +{ + int address; + info("Dumping the ov9650 register state"); + for (address = 0; address < 0xa9; address++) { + u8 value; + m5602_read_sensor(sd, address, &value, 1); + info("register 0x%x contains 0x%x", + address, value); + } + + info("ov9650 register state dump complete"); + + info("Probing for which registers that are read/write"); + for (address = 0; address < 0xff; address++) { + u8 old_value, ctrl_value; + u8 test_value[2] = {0xff, 0xff}; + + m5602_read_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, test_value, 1); + m5602_read_sensor(sd, address, &ctrl_value, 1); + + if (ctrl_value == test_value[0]) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original value */ + m5602_write_sensor(sd, address, &old_value, 1); + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,307 @@ +/* + * Driver for the ov9650 sensor + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#ifndef M5602_OV9650_H_ +#define M5602_OV9650_H_ + +#include +#include "m5602_sensor.h" + +/*****************************************************************************/ + +#define OV9650_GAIN 0x00 +#define OV9650_BLUE 0x01 +#define OV9650_RED 0x02 +#define OV9650_VREF 0x03 +#define OV9650_COM1 0x04 +#define OV9650_BAVE 0x05 +#define OV9650_GEAVE 0x06 +#define OV9650_RSVD7 0x07 +#define OV9650_COM2 0x09 +#define OV9650_PID 0x0a +#define OV9650_VER 0x0b +#define OV9650_COM3 0x0c +#define OV9650_COM4 0x0d +#define OV9650_COM5 0x0e +#define OV9650_COM6 0x0f +#define OV9650_AECH 0x10 +#define OV9650_CLKRC 0x11 +#define OV9650_COM7 0x12 +#define OV9650_COM8 0x13 +#define OV9650_COM9 0x14 +#define OV9650_COM10 0x15 +#define OV9650_RSVD16 0x16 +#define OV9650_HSTART 0x17 +#define OV9650_HSTOP 0x18 +#define OV9650_VSTRT 0x19 +#define OV9650_VSTOP 0x1a +#define OV9650_PSHFT 0x1b +#define OV9650_MVFP 0x1e +#define OV9650_AEW 0x24 +#define OV9650_AEB 0x25 +#define OV9650_VPT 0x26 +#define OV9650_BBIAS 0x27 +#define OV9650_GbBIAS 0x28 +#define OV9650_Gr_COM 0x29 +#define OV9650_RBIAS 0x2c +#define OV9650_HREF 0x32 +#define OV9650_CHLF 0x33 +#define OV9650_ARBLM 0x34 +#define OV9650_RSVD35 0x35 +#define OV9650_RSVD36 0x36 +#define OV9650_ADC 0x37 +#define OV9650_ACOM38 0x38 +#define OV9650_OFON 0x39 +#define OV9650_TSLB 0x3a +#define OV9650_COM12 0x3c +#define OV9650_COM13 0x3d +#define OV9650_COM15 0x40 +#define OV9650_COM16 0x41 +#define OV9650_LCC1 0x62 +#define OV9650_LCC2 0x63 +#define OV9650_LCC3 0x64 +#define OV9650_LCC4 0x65 +#define OV9650_LCC5 0x66 +#define OV9650_HV 0x69 +#define OV9650_DBLV 0x6b +#define OV9650_COM21 0x8b +#define OV9650_COM22 0x8c +#define OV9650_COM24 0x8e +#define OV9650_DBLC1 0x8f +#define OV9650_RSVD94 0x94 +#define OV9650_RSVD95 0x95 +#define OV9650_RSVD96 0x96 +#define OV9650_LCCFB 0x9d +#define OV9650_LCCFR 0x9e +#define OV9650_AECHM 0xa1 +#define OV9650_COM26 0xa5 +#define OV9650_ACOMA8 0xa8 +#define OV9650_ACOMA9 0xa9 + +#define OV9650_REGISTER_RESET (1 << 7) +#define OV9650_VGA_SELECT (1 << 6) +#define OV9650_CIF_SELECT (1 << 5) +#define OV9650_QVGA_SELECT (1 << 4) +#define OV9650_QCIF_SELECT (1 << 3) +#define OV9650_RGB_SELECT (1 << 2) +#define OV9650_RAW_RGB_SELECT (1 << 0) + +#define OV9650_FAST_AGC_AEC (1 << 7) +#define OV9650_AEC_UNLIM_STEP_SIZE (1 << 6) +#define OV9650_BANDING (1 << 5) +#define OV9650_AGC_EN (1 << 2) +#define OV9650_AWB_EN (1 << 1) +#define OV9650_AEC_EN (1 << 0) + +#define OV9650_VARIOPIXEL (1 << 2) +#define OV9650_SYSTEM_CLK_SEL (1 << 7) +#define OV9650_SLAM_MODE (1 << 4) + +#define OV9650_QVGA_VARIOPIXEL (1 << 7) + +#define OV9650_VFLIP (1 << 4) +#define OV9650_HFLIP (1 << 5) + +#define OV9650_SOFT_SLEEP (1 << 4) +#define OV9650_OUTPUT_DRIVE_2X (1 << 0) + +#define OV9650_DENOISE_ENABLE (1 << 5) +#define OV9650_WHITE_PIXEL_ENABLE (1 << 1) +#define OV9650_WHITE_PIXEL_OPTION (1 << 0) + +#define OV9650_LEFT_OFFSET 0x62 + +#define GAIN_DEFAULT 0x14 +#define RED_GAIN_DEFAULT 0x70 +#define BLUE_GAIN_DEFAULT 0x20 +#define EXPOSURE_DEFAULT 0x1ff + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; + +int ov9650_probe(struct sd *sd); +int ov9650_init(struct sd *sd); +int ov9650_start(struct sd *sd); +int ov9650_stop(struct sd *sd); +void ov9650_disconnect(struct sd *sd); + +static const struct m5602_sensor ov9650 = { + .name = "OV9650", + .i2c_slave_id = 0x60, + .i2c_regW = 1, + .probe = ov9650_probe, + .init = ov9650_init, + .start = ov9650_start, + .stop = ov9650_stop, + .disconnect = ov9650_disconnect, +}; + +static const unsigned char preinit_ov9650[][3] = { + /* [INITCAM] */ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a}, + /* Reset chip */ + {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, + /* Enable double clock */ + {SENSOR, OV9650_CLKRC, 0x80}, + /* Do something out of spec with the power */ + {SENSOR, OV9650_OFON, 0x40} +}; + +static const unsigned char init_ov9650[][3] = { + /* [INITCAM] */ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a}, + + /* Reset chip */ + {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, + /* One extra reset is needed in order to make the sensor behave + properly when resuming from ram, could be a timing issue */ + {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, + + /* Enable double clock */ + {SENSOR, OV9650_CLKRC, 0x80}, + /* Do something out of spec with the power */ + {SENSOR, OV9650_OFON, 0x40}, + + /* Set fast AGC/AEC algorithm with unlimited step size */ + {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC | + OV9650_AEC_UNLIM_STEP_SIZE}, + + {SENSOR, OV9650_CHLF, 0x10}, + {SENSOR, OV9650_ARBLM, 0xbf}, + {SENSOR, OV9650_ACOM38, 0x81}, + /* Turn off color matrix coefficient double option */ + {SENSOR, OV9650_COM16, 0x00}, + /* Enable color matrix for RGB/YUV, Delay Y channel, + set output Y/UV delay to 1 */ + {SENSOR, OV9650_COM13, 0x19}, + /* Enable digital BLC, Set output mode to U Y V Y */ + {SENSOR, OV9650_TSLB, 0x0c}, + /* Limit the AGC/AEC stable upper region */ + {SENSOR, OV9650_COM24, 0x00}, + /* Enable HREF and some out of spec things */ + {SENSOR, OV9650_COM12, 0x73}, + /* Set all DBLC offset signs to positive and + do some out of spec stuff */ + {SENSOR, OV9650_DBLC1, 0xdf}, + {SENSOR, OV9650_COM21, 0x06}, + {SENSOR, OV9650_RSVD35, 0x91}, + /* Necessary, no camera stream without it */ + {SENSOR, OV9650_RSVD16, 0x06}, + {SENSOR, OV9650_RSVD94, 0x99}, + {SENSOR, OV9650_RSVD95, 0x99}, + {SENSOR, OV9650_RSVD96, 0x04}, + /* Enable full range output */ + {SENSOR, OV9650_COM15, 0x0}, + /* Enable HREF at optical black, enable ADBLC bias, + enable ADBLC, reset timings at format change */ + {SENSOR, OV9650_COM6, 0x4b}, + /* Subtract 32 from the B channel bias */ + {SENSOR, OV9650_BBIAS, 0xa0}, + /* Subtract 32 from the Gb channel bias */ + {SENSOR, OV9650_GbBIAS, 0xa0}, + /* Do not bypass the analog BLC and to some out of spec stuff */ + {SENSOR, OV9650_Gr_COM, 0x00}, + /* Subtract 32 from the R channel bias */ + {SENSOR, OV9650_RBIAS, 0xa0}, + /* Subtract 32 from the R channel bias */ + {SENSOR, OV9650_RBIAS, 0x0}, + {SENSOR, OV9650_COM26, 0x80}, + {SENSOR, OV9650_ACOMA9, 0x98}, + /* Set the AGC/AEC stable region upper limit */ + {SENSOR, OV9650_AEW, 0x68}, + /* Set the AGC/AEC stable region lower limit */ + {SENSOR, OV9650_AEB, 0x5c}, + /* Set the high and low limit nibbles to 3 */ + {SENSOR, OV9650_VPT, 0xc3}, + /* Set the Automatic Gain Ceiling (AGC) to 128x, + drop VSYNC at frame drop, + limit exposure timing, + drop frame when the AEC step is larger than the exposure gap */ + {SENSOR, OV9650_COM9, 0x6e}, + /* Set VSYNC negative, Set RESET to SLHS (slave mode horizontal sync) + and set PWDN to SLVS (slave mode vertical sync) */ + {SENSOR, OV9650_COM10, 0x42}, + /* Set horizontal column start high to default value */ + {SENSOR, OV9650_HSTART, 0x1a}, /* 210 */ + /* Set horizontal column end */ + {SENSOR, OV9650_HSTOP, 0xbf}, /* 1534 */ + /* Complementing register to the two writes above */ + {SENSOR, OV9650_HREF, 0xb2}, + /* Set vertical row start high bits */ + {SENSOR, OV9650_VSTRT, 0x02}, + /* Set vertical row end low bits */ + {SENSOR, OV9650_VSTOP, 0x7e}, + /* Set complementing vertical frame control */ + {SENSOR, OV9650_VREF, 0x10}, + {SENSOR, OV9650_ADC, 0x04}, + {SENSOR, OV9650_HV, 0x40}, + + /* Enable denoise, and white-pixel erase */ + {SENSOR, OV9650_COM22, OV9650_DENOISE_ENABLE | + OV9650_WHITE_PIXEL_ENABLE | + OV9650_WHITE_PIXEL_OPTION}, + + /* Enable VARIOPIXEL */ + {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL}, + {SENSOR, OV9650_COM4, OV9650_QVGA_VARIOPIXEL}, + + /* Put the sensor in soft sleep mode */ + {SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X}, +}; + +static const unsigned char res_init_ov9650[][3] = { + {SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X}, + + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, + {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01} +}; +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_po1030.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_po1030.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_po1030.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_po1030.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,762 @@ +/* + * Driver for the po1030 sensor + * + * Copyright (c) 2008 Erik Andrén + * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (c) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#include "m5602_po1030.h" + +static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val); +static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val); +static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, + __s32 val); +static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, + __s32 *val); + +static struct v4l2_pix_format po1030_modes[] = { + { + 640, + 480, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = 640 * 480, + .bytesperline = 640, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 + } +}; + +static const struct ctrl po1030_ctrls[] = { +#define GAIN_IDX 0 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0x4f, + .step = 0x1, + .default_value = PO1030_GLOBAL_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_gain, + .get = po1030_get_gain + }, +#define EXPOSURE_IDX 1 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = 0x02ff, + .step = 0x1, + .default_value = PO1030_EXPOSURE_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_exposure, + .get = po1030_get_exposure + }, +#define RED_BALANCE_IDX 2 + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = PO1030_RED_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_red_balance, + .get = po1030_get_red_balance + }, +#define BLUE_BALANCE_IDX 3 + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = PO1030_BLUE_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_blue_balance, + .get = po1030_get_blue_balance + }, +#define HFLIP_IDX 4 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = po1030_set_hflip, + .get = po1030_get_hflip + }, +#define VFLIP_IDX 5 + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = po1030_set_vflip, + .get = po1030_get_vflip + }, +#define AUTO_WHITE_BALANCE_IDX 6 + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = po1030_set_auto_white_balance, + .get = po1030_get_auto_white_balance + }, +#define AUTO_EXPOSURE_IDX 7 + { + { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = po1030_set_auto_exposure, + .get = po1030_get_auto_exposure + }, +#define GREEN_BALANCE_IDX 8 + { + { + .id = M5602_V4L2_CID_GREEN_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = PO1030_GREEN_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_green_balance, + .get = po1030_get_green_balance + }, +}; + +static void po1030_dump_registers(struct sd *sd); + +int po1030_probe(struct sd *sd) +{ + u8 dev_id_h = 0, i; + s32 *sensor_settings; + + if (force_sensor) { + if (force_sensor == PO1030_SENSOR) { + info("Forcing a %s sensor", po1030.name); + goto sensor_found; + } + /* If we want to force another sensor, don't try to probe this + * one */ + return -ENODEV; + } + + PDEBUG(D_PROBE, "Probing for a po1030 sensor"); + + /* Run the pre-init to actually probe the unit */ + for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { + u8 data = preinit_po1030[i][2]; + if (preinit_po1030[i][0] == SENSOR) + m5602_write_sensor(sd, + preinit_po1030[i][1], &data, 1); + else + m5602_write_bridge(sd, preinit_po1030[i][1], data); + } + + if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1)) + return -ENODEV; + + if (dev_id_h == 0x30) { + info("Detected a po1030 sensor"); + goto sensor_found; + } + return -ENODEV; + +sensor_found: + sensor_settings = kmalloc( + ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + sd->gspca_dev.cam.cam_mode = po1030_modes; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes); + sd->desc->ctrls = po1030_ctrls; + sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls); + + for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++) + sensor_settings[i] = po1030_ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + + return 0; +} + +int po1030_init(struct sd *sd) +{ + s32 *sensor_settings = sd->sensor_priv; + int i, err = 0; + + /* Init the sensor */ + for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) { + u8 data[2] = {0x00, 0x00}; + + switch (init_po1030[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + init_po1030[i][1], + init_po1030[i][2]); + break; + + case SENSOR: + data[0] = init_po1030[i][2]; + err = m5602_write_sensor(sd, + init_po1030[i][1], data, 1); + break; + + default: + info("Invalid stream command, exiting init"); + return -EINVAL; + } + } + if (err < 0) + return err; + + if (dump_sensor) + po1030_dump_registers(sd); + + err = po1030_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); + if (err < 0) + return err; + + err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + if (err < 0) + return err; + + err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); + if (err < 0) + return err; + + err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + if (err < 0) + return err; + + err = po1030_set_red_balance(&sd->gspca_dev, + sensor_settings[RED_BALANCE_IDX]); + if (err < 0) + return err; + + err = po1030_set_blue_balance(&sd->gspca_dev, + sensor_settings[BLUE_BALANCE_IDX]); + if (err < 0) + return err; + + err = po1030_set_green_balance(&sd->gspca_dev, + sensor_settings[GREEN_BALANCE_IDX]); + if (err < 0) + return err; + + err = po1030_set_auto_white_balance(&sd->gspca_dev, + sensor_settings[AUTO_WHITE_BALANCE_IDX]); + if (err < 0) + return err; + + err = po1030_set_auto_exposure(&sd->gspca_dev, + sensor_settings[AUTO_EXPOSURE_IDX]); + return err; +} + +int po1030_start(struct sd *sd) +{ + struct cam *cam = &sd->gspca_dev.cam; + int i, err = 0; + int width = cam->cam_mode[sd->gspca_dev.curr_mode].width; + int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; + int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; + u8 data; + + switch (width) { + case 320: + data = PO1030_SUBSAMPLING; + err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); + if (err < 0) + return err; + + data = ((width + 3) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); + if (err < 0) + return err; + + data = (width + 3) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); + if (err < 0) + return err; + + data = ((height + 1) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); + if (err < 0) + return err; + + data = (height + 1) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); + + height += 6; + width -= 1; + break; + + case 640: + data = 0; + err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); + if (err < 0) + return err; + + data = ((width + 7) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); + if (err < 0) + return err; + + data = (width + 7) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); + if (err < 0) + return err; + + data = ((height + 3) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); + if (err < 0) + return err; + + data = (height + 3) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); + + height += 12; + width -= 2; + break; + } + err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, + ((ver_offs >> 8) & 0xff)); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff)); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff)); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + return err; +} + +static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Exposure read as %d", *val); + return 0; +} + +static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[EXPOSURE_IDX] = val; + PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff); + + i2c_data = ((val & 0xff00) >> 8); + PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x", + i2c_data); + + err = m5602_write_sensor(sd, PO1030_INTEGLINES_H, + &i2c_data, 1); + if (err < 0) + return err; + + i2c_data = (val & 0xff); + PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x", + i2c_data); + err = m5602_write_sensor(sd, PO1030_INTEGLINES_M, + &i2c_data, 1); + + return err; +} + +static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + PDEBUG(D_V4L2, "Read global gain %d", *val); + return 0; +} + +static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[GAIN_IDX] = val; + + i2c_data = val & 0xff; + PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); + err = m5602_write_sensor(sd, PO1030_GLOBALGAIN, + &i2c_data, 1); + return err; +} + +static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[HFLIP_IDX]; + PDEBUG(D_V4L2, "Read hflip %d", *val); + + return 0; +} + +static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[HFLIP_IDX] = val; + + PDEBUG(D_V4L2, "Set hflip %d", val); + err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); + if (err < 0) + return err; + + i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7); + + err = m5602_write_sensor(sd, PO1030_CONTROL2, + &i2c_data, 1); + + return err; +} + +static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[VFLIP_IDX]; + PDEBUG(D_V4L2, "Read vflip %d", *val); + + return 0; +} + +static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[VFLIP_IDX] = val; + + PDEBUG(D_V4L2, "Set vflip %d", val); + err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); + if (err < 0) + return err; + + i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6); + + err = m5602_write_sensor(sd, PO1030_CONTROL2, + &i2c_data, 1); + + return err; +} + +static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[RED_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read red gain %d", *val); + return 0; +} + +static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[RED_BALANCE_IDX] = val; + + i2c_data = val & 0xff; + PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); + err = m5602_write_sensor(sd, PO1030_RED_GAIN, + &i2c_data, 1); + return err; +} + +static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[BLUE_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read blue gain %d", *val); + + return 0; +} + +static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[BLUE_BALANCE_IDX] = val; + + i2c_data = val & 0xff; + PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); + err = m5602_write_sensor(sd, PO1030_BLUE_GAIN, + &i2c_data, 1); + + return err; +} + +static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GREEN_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read green gain %d", *val); + + return 0; +} + +static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[GREEN_BALANCE_IDX] = val; + i2c_data = val & 0xff; + PDEBUG(D_V4L2, "Set green gain to %d", i2c_data); + + err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN, + &i2c_data, 1); + if (err < 0) + return err; + + return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN, + &i2c_data, 1); +} + +static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; + PDEBUG(D_V4L2, "Auto white balancing is %d", *val); + + return 0; +} + +static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; + + err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); + if (err < 0) + return err; + + PDEBUG(D_V4L2, "Set auto white balance to %d", val); + i2c_data = (i2c_data & 0xfe) | (val & 0x01); + err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); + return err; +} + +static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, + __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Auto exposure is %d", *val); + return 0; +} + +static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, + __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[AUTO_EXPOSURE_IDX] = val; + err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); + if (err < 0) + return err; + + PDEBUG(D_V4L2, "Set auto exposure to %d", val); + i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1); + return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); +} + +void po1030_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static void po1030_dump_registers(struct sd *sd) +{ + int address; + u8 value = 0; + + info("Dumping the po1030 sensor core registers"); + for (address = 0; address < 0x7f; address++) { + m5602_read_sensor(sd, address, &value, 1); + info("register 0x%x contains 0x%x", + address, value); + } + + info("po1030 register state dump complete"); + + info("Probing for which registers that are read/write"); + for (address = 0; address < 0xff; address++) { + u8 old_value, ctrl_value; + u8 test_value[2] = {0xff, 0xff}; + + m5602_read_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, test_value, 1); + m5602_read_sensor(sd, address, &ctrl_value, 1); + + if (ctrl_value == test_value[0]) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original value */ + m5602_write_sensor(sd, address, &old_value, 1); + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_po1030.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_po1030.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_po1030.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_po1030.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,272 @@ +/* + * Driver for the po1030 sensor. + * + * Copyright (c) 2008 Erik Andrén + * Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (c) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * Register defines taken from Pascal Stangs Procyon Armlib + * + * 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, version 2. + * + */ + +#ifndef M5602_PO1030_H_ +#define M5602_PO1030_H_ + +#include "m5602_sensor.h" + +/*****************************************************************************/ + +#define PO1030_DEVID_H 0x00 +#define PO1030_DEVID_L 0x01 +#define PO1030_FRAMEWIDTH_H 0x04 +#define PO1030_FRAMEWIDTH_L 0x05 +#define PO1030_FRAMEHEIGHT_H 0x06 +#define PO1030_FRAMEHEIGHT_L 0x07 +#define PO1030_WINDOWX_H 0x08 +#define PO1030_WINDOWX_L 0x09 +#define PO1030_WINDOWY_H 0x0a +#define PO1030_WINDOWY_L 0x0b +#define PO1030_WINDOWWIDTH_H 0x0c +#define PO1030_WINDOWWIDTH_L 0x0d +#define PO1030_WINDOWHEIGHT_H 0x0e +#define PO1030_WINDOWHEIGHT_L 0x0f + +#define PO1030_GLOBALIBIAS 0x12 +#define PO1030_PIXELIBIAS 0x13 + +#define PO1030_GLOBALGAIN 0x15 +#define PO1030_RED_GAIN 0x16 +#define PO1030_GREEN_1_GAIN 0x17 +#define PO1030_BLUE_GAIN 0x18 +#define PO1030_GREEN_2_GAIN 0x19 + +#define PO1030_INTEGLINES_H 0x1a +#define PO1030_INTEGLINES_M 0x1b +#define PO1030_INTEGLINES_L 0x1c + +#define PO1030_CONTROL1 0x1d +#define PO1030_CONTROL2 0x1e +#define PO1030_CONTROL3 0x1f +#define PO1030_CONTROL4 0x20 + +#define PO1030_PERIOD50_H 0x23 +#define PO1030_PERIOD50_L 0x24 +#define PO1030_PERIOD60_H 0x25 +#define PO1030_PERIOD60_L 0x26 +#define PO1030_REGCLK167 0x27 +#define PO1030_FLICKER_DELTA50 0x28 +#define PO1030_FLICKERDELTA60 0x29 + +#define PO1030_ADCOFFSET 0x2c + +/* Gamma Correction Coeffs */ +#define PO1030_GC0 0x2d +#define PO1030_GC1 0x2e +#define PO1030_GC2 0x2f +#define PO1030_GC3 0x30 +#define PO1030_GC4 0x31 +#define PO1030_GC5 0x32 +#define PO1030_GC6 0x33 +#define PO1030_GC7 0x34 + +/* Color Transform Matrix */ +#define PO1030_CT0 0x35 +#define PO1030_CT1 0x36 +#define PO1030_CT2 0x37 +#define PO1030_CT3 0x38 +#define PO1030_CT4 0x39 +#define PO1030_CT5 0x3a +#define PO1030_CT6 0x3b +#define PO1030_CT7 0x3c +#define PO1030_CT8 0x3d + +#define PO1030_AUTOCTRL1 0x3e +#define PO1030_AUTOCTRL2 0x3f + +#define PO1030_YTARGET 0x40 +#define PO1030_GLOBALGAINMIN 0x41 +#define PO1030_GLOBALGAINMAX 0x42 + +#define PO1030_AWB_RED_TUNING 0x47 +#define PO1030_AWB_BLUE_TUNING 0x48 + +/* Output format control */ +#define PO1030_OUTFORMCTRL1 0x5a +#define PO1030_OUTFORMCTRL2 0x5b +#define PO1030_OUTFORMCTRL3 0x5c +#define PO1030_OUTFORMCTRL4 0x5d +#define PO1030_OUTFORMCTRL5 0x5e + +#define PO1030_EDGE_ENH_OFF 0x5f +#define PO1030_EGA 0x60 + +#define PO1030_Cb_U_GAIN 0x63 +#define PO1030_Cr_V_GAIN 0x64 + +#define PO1030_YCONTRAST 0x74 +#define PO1030_YSATURATION 0x75 + +#define PO1030_HFLIP (1 << 7) +#define PO1030_VFLIP (1 << 6) + +#define PO1030_HREF_ENABLE (1 << 6) + +#define PO1030_RAW_RGB_BAYER 0x4 + +#define PO1030_FRAME_EQUAL (1 << 3) +#define PO1030_AUTO_SUBSAMPLING (1 << 4) + +#define PO1030_WEIGHT_WIN_2X (1 << 3) + +#define PO1030_SHUTTER_MODE (1 << 6) +#define PO1030_AUTO_SUBSAMPLING (1 << 4) +#define PO1030_FRAME_EQUAL (1 << 3) + +#define PO1030_SENSOR_RESET (1 << 5) + +#define PO1030_SUBSAMPLING (1 << 6) + +/*****************************************************************************/ + +#define PO1030_GLOBAL_GAIN_DEFAULT 0x12 +#define PO1030_EXPOSURE_DEFAULT 0x0085 +#define PO1030_BLUE_GAIN_DEFAULT 0x36 +#define PO1030_RED_GAIN_DEFAULT 0x36 +#define PO1030_GREEN_GAIN_DEFAULT 0x40 + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; + +int po1030_probe(struct sd *sd); +int po1030_init(struct sd *sd); +int po1030_start(struct sd *sd); +void po1030_disconnect(struct sd *sd); + +static const struct m5602_sensor po1030 = { + .name = "PO1030", + + .i2c_slave_id = 0xdc, + .i2c_regW = 1, + + .probe = po1030_probe, + .init = po1030_init, + .start = po1030_start, + .disconnect = po1030_disconnect, +}; + +static const unsigned char preinit_po1030[][3] = { + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, + + {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00} +}; + +static const unsigned char init_po1030[][3] = { + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + + {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + + {SENSOR, PO1030_AUTOCTRL2, 0x04}, + + {SENSOR, PO1030_OUTFORMCTRL2, PO1030_RAW_RGB_BAYER}, + {SENSOR, PO1030_AUTOCTRL1, PO1030_WEIGHT_WIN_2X}, + + {SENSOR, PO1030_CONTROL2, 0x03}, + {SENSOR, 0x21, 0x90}, + {SENSOR, PO1030_YTARGET, 0x60}, + {SENSOR, 0x59, 0x13}, + {SENSOR, PO1030_OUTFORMCTRL1, PO1030_HREF_ENABLE}, + {SENSOR, PO1030_EDGE_ENH_OFF, 0x00}, + {SENSOR, PO1030_EGA, 0x80}, + {SENSOR, 0x78, 0x14}, + {SENSOR, 0x6f, 0x01}, + {SENSOR, PO1030_GLOBALGAINMAX, 0x14}, + {SENSOR, PO1030_Cb_U_GAIN, 0x38}, + {SENSOR, PO1030_Cr_V_GAIN, 0x38}, + {SENSOR, PO1030_CONTROL1, PO1030_SHUTTER_MODE | + PO1030_AUTO_SUBSAMPLING | + PO1030_FRAME_EQUAL}, + {SENSOR, PO1030_GC0, 0x10}, + {SENSOR, PO1030_GC1, 0x20}, + {SENSOR, PO1030_GC2, 0x40}, + {SENSOR, PO1030_GC3, 0x60}, + {SENSOR, PO1030_GC4, 0x80}, + {SENSOR, PO1030_GC5, 0xa0}, + {SENSOR, PO1030_GC6, 0xc0}, + {SENSOR, PO1030_GC7, 0xff}, + + /* Set the width to 751 */ + {SENSOR, PO1030_FRAMEWIDTH_H, 0x02}, + {SENSOR, PO1030_FRAMEWIDTH_L, 0xef}, + + /* Set the height to 540 */ + {SENSOR, PO1030_FRAMEHEIGHT_H, 0x02}, + {SENSOR, PO1030_FRAMEHEIGHT_L, 0x1c}, + + /* Set the x window to 1 */ + {SENSOR, PO1030_WINDOWX_H, 0x00}, + {SENSOR, PO1030_WINDOWX_L, 0x01}, + + /* Set the y window to 1 */ + {SENSOR, PO1030_WINDOWY_H, 0x00}, + {SENSOR, PO1030_WINDOWY_L, 0x01}, + + /* with a very low lighted environment increase the exposure but + * decrease the FPS (Frame Per Second) */ + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, +}; +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,721 @@ +/* + * Driver for the s5k4aa sensor + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#include "m5602_s5k4aa.h" + +static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val); + +static + const + struct dmi_system_id s5k4aa_vflip_dmi_table[] = { + { + .ident = "BRUNEINIT", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"), + DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"), + DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001") + } + }, { + .ident = "Fujitsu-Siemens Amilo Xa 2528", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") + } + }, { + .ident = "Fujitsu-Siemens Amilo Xi 2428", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428") + } + }, { + .ident = "Fujitsu-Siemens Amilo Xi 2528", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528") + } + }, { + .ident = "Fujitsu-Siemens Amilo Xi 2550", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") + } + }, { + .ident = "Fujitsu-Siemens Amilo Pa 2548", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548") + } + }, { + .ident = "MSI GX700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), + DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), + DMI_MATCH(DMI_BIOS_DATE, "12/02/2008") + } + }, { + .ident = "MSI GX700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), + DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), + DMI_MATCH(DMI_BIOS_DATE, "07/26/2007") + } + }, { + .ident = "MSI GX700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), + DMI_MATCH(DMI_PRODUCT_NAME, "GX700"), + DMI_MATCH(DMI_BIOS_DATE, "07/19/2007") + } + }, { + .ident = "MSI GX700/GX705/EX700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), + DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700") + } + }, { + .ident = "MSI L735", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X") + } + }, { + .ident = "Lenovo Y300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"), + DMI_MATCH(DMI_PRODUCT_NAME, "Y300") + } + }, + { } +}; + +static struct v4l2_pix_format s5k4aa_modes[] = { + { + 640, + 480, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 640 * 480, + .bytesperline = 640, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + }, + { + 1280, + 1024, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 1280 * 1024, + .bytesperline = 1280, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + } +}; + +static const struct ctrl s5k4aa_ctrls[] = { +#define VFLIP_IDX 0 + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = s5k4aa_set_vflip, + .get = s5k4aa_get_vflip + }, +#define HFLIP_IDX 1 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = s5k4aa_set_hflip, + .get = s5k4aa_get_hflip + }, +#define GAIN_IDX 2 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = S5K4AA_DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k4aa_set_gain, + .get = s5k4aa_get_gain + }, +#define EXPOSURE_IDX 3 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 13, + .maximum = 0xfff, + .step = 1, + .default_value = 0x100, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k4aa_set_exposure, + .get = s5k4aa_get_exposure + }, +#define NOISE_SUPP_IDX 4 + { + { + .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Noise suppression (smoothing)", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set = s5k4aa_set_noise, + .get = s5k4aa_get_noise + }, +#define BRIGHTNESS_IDX 5 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0x1f, + .step = 1, + .default_value = S5K4AA_DEFAULT_BRIGHTNESS, + }, + .set = s5k4aa_set_brightness, + .get = s5k4aa_get_brightness + }, + +}; + +static void s5k4aa_dump_registers(struct sd *sd); + +int s5k4aa_probe(struct sd *sd) +{ + u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; + int i, err = 0; + s32 *sensor_settings; + + if (force_sensor) { + if (force_sensor == S5K4AA_SENSOR) { + info("Forcing a %s sensor", s5k4aa.name); + goto sensor_found; + } + /* If we want to force another sensor, don't try to probe this + * one */ + return -ENODEV; + } + + PDEBUG(D_PROBE, "Probing for a s5k4aa sensor"); + + /* Preinit the sensor */ + for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) { + u8 data[2] = {0x00, 0x00}; + + switch (preinit_s5k4aa[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + preinit_s5k4aa[i][1], + preinit_s5k4aa[i][2]); + break; + + case SENSOR: + data[0] = preinit_s5k4aa[i][2]; + err = m5602_write_sensor(sd, + preinit_s5k4aa[i][1], + data, 1); + break; + + case SENSOR_LONG: + data[0] = preinit_s5k4aa[i][2]; + data[1] = preinit_s5k4aa[i][3]; + err = m5602_write_sensor(sd, + preinit_s5k4aa[i][1], + data, 2); + break; + default: + info("Invalid stream command, exiting init"); + return -EINVAL; + } + } + + /* Test some registers, but we don't know their exact meaning yet */ + if (m5602_read_sensor(sd, 0x00, prod_id, 2)) + return -ENODEV; + if (m5602_read_sensor(sd, 0x02, prod_id+2, 2)) + return -ENODEV; + if (m5602_read_sensor(sd, 0x04, prod_id+4, 2)) + return -ENODEV; + + if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) + return -ENODEV; + else + info("Detected a s5k4aa sensor"); + +sensor_found: + sensor_settings = kmalloc( + ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + sd->gspca_dev.cam.cam_mode = s5k4aa_modes; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes); + sd->desc->ctrls = s5k4aa_ctrls; + sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls); + + for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++) + sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + + return 0; +} + +int s5k4aa_start(struct sd *sd) +{ + int i, err = 0; + u8 data[2]; + struct cam *cam = &sd->gspca_dev.cam; + s32 *sensor_settings = sd->sensor_priv; + + switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { + case 1280: + PDEBUG(D_V4L2, "Configuring camera for SXGA mode"); + + for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) { + switch (SXGA_s5k4aa[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + SXGA_s5k4aa[i][1], + SXGA_s5k4aa[i][2]); + break; + + case SENSOR: + data[0] = SXGA_s5k4aa[i][2]; + err = m5602_write_sensor(sd, + SXGA_s5k4aa[i][1], + data, 1); + break; + + case SENSOR_LONG: + data[0] = SXGA_s5k4aa[i][2]; + data[1] = SXGA_s5k4aa[i][3]; + err = m5602_write_sensor(sd, + SXGA_s5k4aa[i][1], + data, 2); + break; + + default: + err("Invalid stream command, exiting init"); + return -EINVAL; + } + } + err = s5k4aa_set_noise(&sd->gspca_dev, 0); + if (err < 0) + return err; + break; + + case 640: + PDEBUG(D_V4L2, "Configuring camera for VGA mode"); + + for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) { + switch (VGA_s5k4aa[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + VGA_s5k4aa[i][1], + VGA_s5k4aa[i][2]); + break; + + case SENSOR: + data[0] = VGA_s5k4aa[i][2]; + err = m5602_write_sensor(sd, + VGA_s5k4aa[i][1], + data, 1); + break; + + case SENSOR_LONG: + data[0] = VGA_s5k4aa[i][2]; + data[1] = VGA_s5k4aa[i][3]; + err = m5602_write_sensor(sd, + VGA_s5k4aa[i][1], + data, 2); + break; + + default: + err("Invalid stream command, exiting init"); + return -EINVAL; + } + } + err = s5k4aa_set_noise(&sd->gspca_dev, 1); + if (err < 0) + return err; + break; + } + if (err < 0) + return err; + + err = s5k4aa_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); + if (err < 0) + return err; + + err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + if (err < 0) + return err; + + err = s5k4aa_set_brightness(&sd->gspca_dev, + sensor_settings[BRIGHTNESS_IDX]); + if (err < 0) + return err; + + err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]); + if (err < 0) + return err; + + err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + if (err < 0) + return err; + + return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); +} + +int s5k4aa_init(struct sd *sd) +{ + int i, err = 0; + + for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) { + u8 data[2] = {0x00, 0x00}; + + switch (init_s5k4aa[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + init_s5k4aa[i][1], + init_s5k4aa[i][2]); + break; + + case SENSOR: + data[0] = init_s5k4aa[i][2]; + err = m5602_write_sensor(sd, + init_s5k4aa[i][1], data, 1); + break; + + case SENSOR_LONG: + data[0] = init_s5k4aa[i][2]; + data[1] = init_s5k4aa[i][3]; + err = m5602_write_sensor(sd, + init_s5k4aa[i][1], data, 2); + break; + default: + info("Invalid stream command, exiting init"); + return -EINVAL; + } + } + + if (dump_sensor) + s5k4aa_dump_registers(sd); + + return err; +} + +static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Read exposure %d", *val); + + return 0; +} + +static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + sensor_settings[EXPOSURE_IDX] = val; + PDEBUG(D_V4L2, "Set exposure to %d", val); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + return err; + data = (val >> 8) & 0xff; + err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); + if (err < 0) + return err; + data = val & 0xff; + err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); + + return err; +} + +static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[VFLIP_IDX]; + PDEBUG(D_V4L2, "Read vertical flip %d", *val); + + return 0; +} + +static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + sensor_settings[VFLIP_IDX] = val; + + PDEBUG(D_V4L2, "Set vertical flip to %d", val); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + return err; + + err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + return err; + + if (dmi_check_system(s5k4aa_vflip_dmi_table)) + val = !val; + + data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7)); + err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + return err; + + err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + if (err < 0) + return err; + if (val) + data &= 0xfe; + else + data |= 0x01; + err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + return err; +} + +static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[HFLIP_IDX]; + PDEBUG(D_V4L2, "Read horizontal flip %d", *val); + + return 0; +} + +static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + sensor_settings[HFLIP_IDX] = val; + + PDEBUG(D_V4L2, "Set horizontal flip to %d", val); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + return err; + + err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + return err; + + if (dmi_check_system(s5k4aa_vflip_dmi_table)) + val = !val; + + data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6)); + err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + return err; + + err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + if (err < 0) + return err; + if (val) + data &= 0xfe; + else + data |= 0x01; + err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + return err; +} + +static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + PDEBUG(D_V4L2, "Read gain %d", *val); + return 0; +} + +static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + sensor_settings[GAIN_IDX] = val; + + PDEBUG(D_V4L2, "Set gain to %d", val); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + return err; + + data = val & 0xff; + err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1); + + return err; +} + +static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[BRIGHTNESS_IDX]; + PDEBUG(D_V4L2, "Read brightness %d", *val); + return 0; +} + +static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + sensor_settings[BRIGHTNESS_IDX] = val; + + PDEBUG(D_V4L2, "Set brightness to %d", val); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + return err; + + data = val & 0xff; + return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1); +} + +static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[NOISE_SUPP_IDX]; + PDEBUG(D_V4L2, "Read noise %d", *val); + return 0; +} + +static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + sensor_settings[NOISE_SUPP_IDX] = val; + + PDEBUG(D_V4L2, "Set noise to %d", val); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + return err; + + data = val & 0x01; + return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1); +} + +void s5k4aa_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static void s5k4aa_dump_registers(struct sd *sd) +{ + int address; + u8 page, old_page; + m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); + for (page = 0; page < 16; page++) { + m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); + info("Dumping the s5k4aa register state for page 0x%x", page); + for (address = 0; address <= 0xff; address++) { + u8 value = 0; + m5602_read_sensor(sd, address, &value, 1); + info("register 0x%x contains 0x%x", + address, value); + } + } + info("s5k4aa register state dump complete"); + + for (page = 0; page < 16; page++) { + m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); + info("Probing for which registers that are " + "read/write for page 0x%x", page); + for (address = 0; address <= 0xff; address++) { + u8 old_value, ctrl_value, test_value = 0xff; + + m5602_read_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, &test_value, 1); + m5602_read_sensor(sd, address, &ctrl_value, 1); + + if (ctrl_value == test_value) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original value */ + m5602_write_sensor(sd, address, &old_value, 1); + } + } + info("Read/write register probing complete"); + m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,283 @@ +/* + * Driver for the s5k4aa sensor + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#ifndef M5602_S5K4AA_H_ +#define M5602_S5K4AA_H_ + +#include + +#include "m5602_sensor.h" + +/*****************************************************************************/ + +#define S5K4AA_PAGE_MAP 0xec + +#define S5K4AA_PAGE_MAP_0 0x00 +#define S5K4AA_PAGE_MAP_1 0x01 +#define S5K4AA_PAGE_MAP_2 0x02 + +/* Sensor register definitions for page 0x02 */ +#define S5K4AA_READ_MODE 0x03 +#define S5K4AA_ROWSTART_HI 0x04 +#define S5K4AA_ROWSTART_LO 0x05 +#define S5K4AA_COLSTART_HI 0x06 +#define S5K4AA_COLSTART_LO 0x07 +#define S5K4AA_WINDOW_HEIGHT_HI 0x08 +#define S5K4AA_WINDOW_HEIGHT_LO 0x09 +#define S5K4AA_WINDOW_WIDTH_HI 0x0a +#define S5K4AA_WINDOW_WIDTH_LO 0x0b +#define S5K4AA_GLOBAL_GAIN__ 0x0f +/* sync lost, if too low, reduces frame rate if too high */ +#define S5K4AA_H_BLANK_HI__ 0x1d +#define S5K4AA_H_BLANK_LO__ 0x1e +#define S5K4AA_EXPOSURE_HI 0x17 +#define S5K4AA_EXPOSURE_LO 0x18 +#define S5K4AA_BRIGHTNESS 0x1f /* (digital?) gain : 5 bits */ +#define S5K4AA_GAIN 0x20 /* (analogue?) gain : 7 bits */ +#define S5K4AA_NOISE_SUPP 0x37 + +#define S5K4AA_RM_ROW_SKIP_4X 0x08 +#define S5K4AA_RM_ROW_SKIP_2X 0x04 +#define S5K4AA_RM_COL_SKIP_4X 0x02 +#define S5K4AA_RM_COL_SKIP_2X 0x01 +#define S5K4AA_RM_H_FLIP 0x40 +#define S5K4AA_RM_V_FLIP 0x80 + +#define S5K4AA_DEFAULT_GAIN 0x5f +#define S5K4AA_DEFAULT_BRIGHTNESS 0x10 + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; + +int s5k4aa_probe(struct sd *sd); +int s5k4aa_init(struct sd *sd); +int s5k4aa_start(struct sd *sd); +void s5k4aa_disconnect(struct sd *sd); + +static const struct m5602_sensor s5k4aa = { + .name = "S5K4AA", + .i2c_slave_id = 0x5a, + .i2c_regW = 2, + + .probe = s5k4aa_probe, + .init = s5k4aa_init, + .start = s5k4aa_start, + .disconnect = s5k4aa_disconnect, +}; + +static const unsigned char preinit_s5k4aa[][4] = { + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, + + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, + + {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00} +}; + +static const unsigned char init_s5k4aa[][4] = { + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, + + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, + + {SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00}, + {SENSOR, 0x36, 0x01, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}, + {SENSOR, 0x7b, 0xff, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, 0x0c, 0x05, 0x00}, + {SENSOR, 0x02, 0x0e, 0x00}, + {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00}, + {SENSOR, 0x37, 0x00, 0x00}, +}; + +static const unsigned char VGA_s5k4aa[][4] = { + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ + + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X + | S5K4AA_RM_COL_SKIP_2X, 0x00}, + /* 0x37 : Fix image stability when light is too bright and improves + * image quality in 640x480, but worsens it in 1280x1024 */ + {SENSOR, 0x37, 0x01, 0x00}, + /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */ + {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00}, + {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00}, + /* window_height_hi, window_height_lo : 960 = 0x03c0 */ + {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00}, + {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00}, + /* window_width_hi, window_width_lo : 1280 = 0x0500 */ + {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, + {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, + {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00}, + {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */ + {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, + {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, + {SENSOR, 0x11, 0x04, 0x00}, + {SENSOR, 0x12, 0xc3, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, 0x02, 0x0e, 0x00}, +}; + +static const unsigned char SXGA_s5k4aa[][4] = { + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ + + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00}, + {SENSOR, 0x37, 0x01, 0x00}, + {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00}, + {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00}, + {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00}, + {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00}, + {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, + {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, + {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00}, + {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, + {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, + {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, + {SENSOR, 0x11, 0x04, 0x00}, + {SENSOR, 0x12, 0xc3, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, 0x02, 0x0e, 0x00}, +}; +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,601 @@ +/* + * Driver for the s5k83a sensor + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#include +#include "m5602_s5k83a.h" + +static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val); +static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val); + +static struct v4l2_pix_format s5k83a_modes[] = { + { + 640, + 480, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 640 * 480, + .bytesperline = 640, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + } +}; + +static const struct ctrl s5k83a_ctrls[] = { +#define GAIN_IDX 0 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = S5K83A_DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k83a_set_gain, + .get = s5k83a_get_gain + + }, +#define BRIGHTNESS_IDX 1 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = S5K83A_DEFAULT_BRIGHTNESS, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k83a_set_brightness, + .get = s5k83a_get_brightness, + }, +#define EXPOSURE_IDX 2 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = S5K83A_MAXIMUM_EXPOSURE, + .step = 0x01, + .default_value = S5K83A_DEFAULT_EXPOSURE, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k83a_set_exposure, + .get = s5k83a_get_exposure + }, +#define HFLIP_IDX 3 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = s5k83a_set_hflip, + .get = s5k83a_get_hflip + }, +#define VFLIP_IDX 4 + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = s5k83a_set_vflip, + .get = s5k83a_get_vflip + } +}; + +static void s5k83a_dump_registers(struct sd *sd); +static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data); +static int s5k83a_set_led_indication(struct sd *sd, u8 val); +static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, + __s32 vflip, __s32 hflip); + +int s5k83a_probe(struct sd *sd) +{ + struct s5k83a_priv *sens_priv; + u8 prod_id = 0, ver_id = 0; + int i, err = 0; + + if (force_sensor) { + if (force_sensor == S5K83A_SENSOR) { + info("Forcing a %s sensor", s5k83a.name); + goto sensor_found; + } + /* If we want to force another sensor, don't try to probe this + * one */ + return -ENODEV; + } + + PDEBUG(D_PROBE, "Probing for a s5k83a sensor"); + + /* Preinit the sensor */ + for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) { + u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]}; + if (preinit_s5k83a[i][0] == SENSOR) + err = m5602_write_sensor(sd, preinit_s5k83a[i][1], + data, 2); + else + err = m5602_write_bridge(sd, preinit_s5k83a[i][1], + data[0]); + } + + /* We don't know what register (if any) that contain the product id + * Just pick the first addresses that seem to produce the same results + * on multiple machines */ + if (m5602_read_sensor(sd, 0x00, &prod_id, 1)) + return -ENODEV; + + if (m5602_read_sensor(sd, 0x01, &ver_id, 1)) + return -ENODEV; + + if ((prod_id == 0xff) || (ver_id == 0xff)) + return -ENODEV; + else + info("Detected a s5k83a sensor"); + +sensor_found: + sens_priv = kmalloc( + sizeof(struct s5k83a_priv), GFP_KERNEL); + if (!sens_priv) + return -ENOMEM; + + sens_priv->settings = + kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL); + if (!sens_priv->settings) { + kfree(sens_priv); + return -ENOMEM; + } + + sd->gspca_dev.cam.cam_mode = s5k83a_modes; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes); + sd->desc->ctrls = s5k83a_ctrls; + sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls); + + /* null the pointer! thread is't running now */ + sens_priv->rotation_thread = NULL; + + for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++) + sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value; + + sd->sensor_priv = sens_priv; + return 0; +} + +int s5k83a_init(struct sd *sd) +{ + int i, err = 0; + s32 *sensor_settings = + ((struct s5k83a_priv *) sd->sensor_priv)->settings; + + for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) { + u8 data[2] = {0x00, 0x00}; + + switch (init_s5k83a[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + init_s5k83a[i][1], + init_s5k83a[i][2]); + break; + + case SENSOR: + data[0] = init_s5k83a[i][2]; + err = m5602_write_sensor(sd, + init_s5k83a[i][1], data, 1); + break; + + case SENSOR_LONG: + data[0] = init_s5k83a[i][2]; + data[1] = init_s5k83a[i][3]; + err = m5602_write_sensor(sd, + init_s5k83a[i][1], data, 2); + break; + default: + info("Invalid stream command, exiting init"); + return -EINVAL; + } + } + + if (dump_sensor) + s5k83a_dump_registers(sd); + + err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + if (err < 0) + return err; + + err = s5k83a_set_brightness(&sd->gspca_dev, + sensor_settings[BRIGHTNESS_IDX]); + if (err < 0) + return err; + + err = s5k83a_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); + if (err < 0) + return err; + + err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); + if (err < 0) + return err; + + err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + + return err; +} + +static int rotation_thread_function(void *data) +{ + struct sd *sd = (struct sd *) data; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + u8 reg, previous_rotation = 0; + __s32 vflip, hflip; + + set_current_state(TASK_INTERRUPTIBLE); + while (!schedule_timeout(100)) { + if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock)) + break; + + s5k83a_get_rotation(sd, ®); + if (previous_rotation != reg) { + previous_rotation = reg; + info("Camera was flipped"); + + s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); + s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); + + if (reg) { + vflip = !vflip; + hflip = !hflip; + } + s5k83a_set_flip_real((struct gspca_dev *) sd, + vflip, hflip); + } + + mutex_unlock(&sd->gspca_dev.usb_lock); + set_current_state(TASK_INTERRUPTIBLE); + } + + /* return to "front" flip */ + if (previous_rotation) { + s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); + s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); + s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip); + } + + sens_priv->rotation_thread = NULL; + return 0; +} + +int s5k83a_start(struct sd *sd) +{ + int i, err = 0; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + /* Create another thread, polling the GPIO ports of the camera to check + if it got rotated. This is how the windows driver does it so we have + to assume that there is no better way of accomplishing this */ + sens_priv->rotation_thread = kthread_create(rotation_thread_function, + sd, "rotation thread"); + wake_up_process(sens_priv->rotation_thread); + + /* Preinit the sensor */ + for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) { + u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]}; + if (start_s5k83a[i][0] == SENSOR) + err = m5602_write_sensor(sd, start_s5k83a[i][1], + data, 2); + else + err = m5602_write_bridge(sd, start_s5k83a[i][1], + data[0]); + } + if (err < 0) + return err; + + return s5k83a_set_led_indication(sd, 1); +} + +int s5k83a_stop(struct sd *sd) +{ + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + if (sens_priv->rotation_thread) + kthread_stop(sens_priv->rotation_thread); + + return s5k83a_set_led_indication(sd, 0); +} + +void s5k83a_disconnect(struct sd *sd) +{ + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + s5k83a_stop(sd); + + sd->sensor = NULL; + kfree(sens_priv->settings); + kfree(sens_priv); +} + +static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[GAIN_IDX]; + return 0; +} + +static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[GAIN_IDX] = val; + + data[0] = 0x00; + data[1] = 0x20; + err = m5602_write_sensor(sd, 0x14, data, 2); + if (err < 0) + return err; + + data[0] = 0x01; + data[1] = 0x00; + err = m5602_write_sensor(sd, 0x0d, data, 2); + if (err < 0) + return err; + + /* FIXME: This is not sane, we need to figure out the composition + of these registers */ + data[0] = val >> 3; /* gain, high 5 bits */ + data[1] = val >> 1; /* gain, high 7 bits */ + err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2); + + return err; +} + +static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[BRIGHTNESS_IDX]; + return 0; +} + +static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[1]; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[BRIGHTNESS_IDX] = val; + data[0] = val; + err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1); + return err; +} + +static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[EXPOSURE_IDX]; + return 0; +} + +static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[EXPOSURE_IDX] = val; + data[0] = 0; + data[1] = val; + err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2); + return err; +} + +static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[VFLIP_IDX]; + return 0; +} + +static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, + __s32 vflip, __s32 hflip) +{ + int err; + u8 data[1]; + struct sd *sd = (struct sd *) gspca_dev; + + data[0] = 0x05; + err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + if (err < 0) + return err; + + /* six bit is vflip, seven is hflip */ + data[0] = S5K83A_FLIP_MASK; + data[0] = (vflip) ? data[0] | 0x40 : data[0]; + data[0] = (hflip) ? data[0] | 0x80 : data[0]; + + err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1); + if (err < 0) + return err; + + data[0] = (vflip) ? 0x0b : 0x0a; + err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1); + if (err < 0) + return err; + + data[0] = (hflip) ? 0x0a : 0x0b; + err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1); + return err; +} + +static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 reg; + __s32 hflip; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[VFLIP_IDX] = val; + + s5k83a_get_hflip(gspca_dev, &hflip); + + err = s5k83a_get_rotation(sd, ®); + if (err < 0) + return err; + if (reg) { + val = !val; + hflip = !hflip; + } + + err = s5k83a_set_flip_real(gspca_dev, val, hflip); + return err; +} + +static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[HFLIP_IDX]; + return 0; +} + +static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 reg; + __s32 vflip; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[HFLIP_IDX] = val; + + s5k83a_get_vflip(gspca_dev, &vflip); + + err = s5k83a_get_rotation(sd, ®); + if (err < 0) + return err; + if (reg) { + val = !val; + vflip = !vflip; + } + + err = s5k83a_set_flip_real(gspca_dev, vflip, val); + return err; +} + +static int s5k83a_set_led_indication(struct sd *sd, u8 val) +{ + int err = 0; + u8 data[1]; + + err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data); + if (err < 0) + return err; + + if (val) + data[0] = data[0] | S5K83A_GPIO_LED_MASK; + else + data[0] = data[0] & ~S5K83A_GPIO_LED_MASK; + + err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]); + + return err; +} + +/* Get camera rotation on Acer notebooks */ +static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data) +{ + int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data); + *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1; + return err; +} + +static void s5k83a_dump_registers(struct sd *sd) +{ + int address; + u8 page, old_page; + m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); + + for (page = 0; page < 16; page++) { + m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); + info("Dumping the s5k83a register state for page 0x%x", page); + for (address = 0; address <= 0xff; address++) { + u8 val = 0; + m5602_read_sensor(sd, address, &val, 1); + info("register 0x%x contains 0x%x", + address, val); + } + } + info("s5k83a register state dump complete"); + + for (page = 0; page < 16; page++) { + m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); + info("Probing for which registers that are read/write " + "for page 0x%x", page); + for (address = 0; address <= 0xff; address++) { + u8 old_val, ctrl_val, test_val = 0xff; + + m5602_read_sensor(sd, address, &old_val, 1); + m5602_write_sensor(sd, address, &test_val, 1); + m5602_read_sensor(sd, address, &ctrl_val, 1); + + if (ctrl_val == test_val) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original val */ + m5602_write_sensor(sd, address, &old_val, 1); + } + } + info("Read/write register probing complete"); + m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,193 @@ +/* + * Driver for the s5k83a sensor + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#ifndef M5602_S5K83A_H_ +#define M5602_S5K83A_H_ + +#include "m5602_sensor.h" + +#define S5K83A_FLIP 0x01 +#define S5K83A_HFLIP_TUNE 0x03 +#define S5K83A_VFLIP_TUNE 0x05 +#define S5K83A_BRIGHTNESS 0x0a +#define S5K83A_EXPOSURE 0x18 +#define S5K83A_GAIN 0x1b +#define S5K83A_PAGE_MAP 0xec + +#define S5K83A_DEFAULT_GAIN 0x71 +#define S5K83A_DEFAULT_BRIGHTNESS 0x7e +#define S5K83A_DEFAULT_EXPOSURE 0x00 +#define S5K83A_MAXIMUM_EXPOSURE 0x3c +#define S5K83A_FLIP_MASK 0x10 +#define S5K83A_GPIO_LED_MASK 0x10 +#define S5K83A_GPIO_ROTATION_MASK 0x40 + +/*****************************************************************************/ + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; + +int s5k83a_probe(struct sd *sd); +int s5k83a_init(struct sd *sd); +int s5k83a_start(struct sd *sd); +int s5k83a_stop(struct sd *sd); +void s5k83a_disconnect(struct sd *sd); + +static const struct m5602_sensor s5k83a = { + .name = "S5K83A", + .probe = s5k83a_probe, + .init = s5k83a_init, + .start = s5k83a_start, + .stop = s5k83a_stop, + .disconnect = s5k83a_disconnect, + .i2c_slave_id = 0x5a, + .i2c_regW = 2, +}; + +struct s5k83a_priv { + /* We use another thread periodically + probing the orientation of the camera */ + struct task_struct *rotation_thread; + s32 *settings; +}; + +static const unsigned char preinit_s5k83a[][4] = { + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, + + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, +}; + +/* This could probably be considerably shortened. + I don't have the hardware to experiment with it, patches welcome +*/ +static const unsigned char init_s5k83a[][4] = { + /* The following sequence is useless after a clean boot + but is necessary after resume from suspend */ + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, + + {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00}, + {SENSOR, 0xaf, 0x01, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}, + {SENSOR, 0x7b, 0xff, 0x00}, + {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR, 0x01, 0x50, 0x00}, + {SENSOR, 0x12, 0x20, 0x00}, + {SENSOR, 0x17, 0x40, 0x00}, + {SENSOR, 0x1c, 0x00, 0x00}, + {SENSOR, 0x02, 0x70, 0x00}, + {SENSOR, 0x03, 0x0b, 0x00}, + {SENSOR, 0x04, 0xf0, 0x00}, + {SENSOR, 0x05, 0x0b, 0x00}, + {SENSOR, 0x06, 0x71, 0x00}, + {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */ + {SENSOR, 0x08, 0x02, 0x00}, + {SENSOR, 0x09, 0x88, 0x00}, /* 648 */ + {SENSOR, 0x14, 0x00, 0x00}, + {SENSOR, 0x15, 0x20, 0x00}, /* 32 */ + {SENSOR, 0x19, 0x00, 0x00}, + {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */ + {SENSOR, 0x0f, 0x02, 0x00}, + {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */ + /* normal colors + (this is value after boot, but after tries can be different) */ + {SENSOR, 0x00, 0x06, 0x00}, +}; + +static const unsigned char start_s5k83a[][4] = { + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */ + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, +}; +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_sensor.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_sensor.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_sensor.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/m5602_sensor.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,70 @@ +/* + * USB Driver for ALi m5602 based webcams + * + * Copyright (C) 2008 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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, version 2. + * + */ + +#ifndef M5602_SENSOR_H_ +#define M5602_SENSOR_H_ + +#include "m5602_bridge.h" + +#define M5602_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 0) +#define M5602_V4L2_CID_NOISE_SUPPRESION (V4L2_CID_PRIVATE_BASE + 1) + +/* Enumerates all supported sensors */ +enum sensors { + OV9650_SENSOR = 1, + S5K83A_SENSOR = 2, + S5K4AA_SENSOR = 3, + MT9M111_SENSOR = 4, + PO1030_SENSOR = 5, + OV7660_SENSOR = 6, +}; + +/* Enumerates all possible instruction types */ +enum instruction { + BRIDGE, + SENSOR, + SENSOR_LONG +}; + +struct m5602_sensor { + /* Defines the name of a sensor */ + char name[32]; + + /* What i2c address the sensor is connected to */ + u8 i2c_slave_id; + + /* Width of each i2c register (in bytes) */ + u8 i2c_regW; + + /* Probes if the sensor is connected */ + int (*probe)(struct sd *sd); + + /* Performs a initialization sequence */ + int (*init)(struct sd *sd); + + /* Executed when the camera starts to send data */ + int (*start)(struct sd *sd); + + /* Executed when the camera ends to send data */ + int (*stop)(struct sd *sd); + + /* Executed when the device is disconnected */ + void (*disconnect)(struct sd *sd); +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/m5602/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,11 @@ +obj-$(CONFIG_USB_M5602) += gspca_m5602.o + +gspca_m5602-objs := m5602_core.o \ + m5602_ov9650.o \ + m5602_ov7660.o \ + m5602_mt9m111.o \ + m5602_po1030.o \ + m5602_s5k83a.o \ + m5602_s5k4aa.o + +EXTRA_CFLAGS += -Idrivers/media/video/gspca diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,87 @@ +obj-$(CONFIG_USB_GSPCA) += gspca_main.o +obj-$(CONFIG_USB_GSPCA_BENQ) += gspca_benq.o +obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o +obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o +obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o +obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o +obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o +obj-$(CONFIG_USB_GSPCA_KINECT) += gspca_kinect.o +obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o +obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o +obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o +obj-$(CONFIG_USB_GSPCA_NW80X) += gspca_nw80x.o +obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o +obj-$(CONFIG_USB_GSPCA_OV534) += gspca_ov534.o +obj-$(CONFIG_USB_GSPCA_OV534_9) += gspca_ov534_9.o +obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o +obj-$(CONFIG_USB_GSPCA_PAC7302) += gspca_pac7302.o +obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o +obj-$(CONFIG_USB_GSPCA_SN9C2028) += gspca_sn9c2028.o +obj-$(CONFIG_USB_GSPCA_SN9C20X) += gspca_sn9c20x.o +obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o +obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o +obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o +obj-$(CONFIG_USB_GSPCA_SPCA501) += gspca_spca501.o +obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o +obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o +obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o +obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o +obj-$(CONFIG_USB_GSPCA_SPCA1528) += gspca_spca1528.o +obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o +obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o +obj-$(CONFIG_USB_GSPCA_SQ930X) += gspca_sq930x.o +obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o +obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o +obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o +obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o +obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o +obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o +obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o +obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o +obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o + +gspca_main-objs := gspca.o +gspca_benq-objs := benq.o +gspca_conex-objs := conex.o +gspca_cpia1-objs := cpia1.o +gspca_etoms-objs := etoms.o +gspca_finepix-objs := finepix.o +gspca_jeilinj-objs := jeilinj.o +gspca_kinect-objs := kinect.o +gspca_konica-objs := konica.o +gspca_mars-objs := mars.o +gspca_mr97310a-objs := mr97310a.o +gspca_nw80x-objs := nw80x.o +gspca_ov519-objs := ov519.o +gspca_ov534-objs := ov534.o +gspca_ov534_9-objs := ov534_9.o +gspca_pac207-objs := pac207.o +gspca_pac7302-objs := pac7302.o +gspca_pac7311-objs := pac7311.o +gspca_sn9c2028-objs := sn9c2028.o +gspca_sn9c20x-objs := sn9c20x.o +gspca_sonixb-objs := sonixb.o +gspca_sonixj-objs := sonixj.o +gspca_spca500-objs := spca500.o +gspca_spca501-objs := spca501.o +gspca_spca505-objs := spca505.o +gspca_spca506-objs := spca506.o +gspca_spca508-objs := spca508.o +gspca_spca561-objs := spca561.o +gspca_spca1528-objs := spca1528.o +gspca_sq905-objs := sq905.o +gspca_sq905c-objs := sq905c.o +gspca_sq930x-objs := sq930x.o +gspca_stk014-objs := stk014.o +gspca_stv0680-objs := stv0680.o +gspca_sunplus-objs := sunplus.o +gspca_t613-objs := t613.o +gspca_tv8532-objs := tv8532.o +gspca_vc032x-objs := vc032x.o +gspca_vicam-objs := vicam.o +gspca_xirlink_cit-objs := xirlink_cit.o +gspca_zc3xx-objs := zc3xx.o + +obj-$(CONFIG_USB_M5602) += m5602/ +obj-$(CONFIG_USB_STV06XX) += stv06xx/ +obj-$(CONFIG_USB_GL860) += gl860/ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/mars.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/mars.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/mars.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/mars.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,529 @@ +/* + * Mars-Semi MR97311A library + * Copyright (C) 2005 + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "mars" + +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* controls */ +enum e_ctrl { + BRIGHTNESS, + COLORS, + GAMMA, + SHARPNESS, + ILLUM_TOP, + ILLUM_BOT, + NCTRLS /* number of controls */ +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + + u8 quality; +#define QUALITY_MIN 40 +#define QUALITY_MAX 70 +#define QUALITY_DEF 50 + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +/* V4L2 controls supported by the driver */ +static void setbrightness(struct gspca_dev *gspca_dev); +static void setcolors(struct gspca_dev *gspca_dev); +static void setgamma(struct gspca_dev *gspca_dev); +static void setsharpness(struct gspca_dev *gspca_dev); +static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val); +static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val); + +static const struct ctrl sd_ctrls[NCTRLS] = { +[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 30, + .step = 1, + .default_value = 15, + }, + .set_control = setbrightness + }, +[COLORS] = { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 1, + .maximum = 255, + .step = 1, + .default_value = 200, + }, + .set_control = setcolors + }, +[GAMMA] = { + { + .id = V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 1, + }, + .set_control = setgamma + }, +[SHARPNESS] = { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 1, + }, + .set_control = setsharpness + }, +[ILLUM_TOP] = { + { + .id = V4L2_CID_ILLUMINATORS_1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Top illuminator", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = V4L2_CTRL_FLAG_UPDATE, + }, + .set = sd_setilluminator1 + }, +[ILLUM_BOT] = { + { + .id = V4L2_CID_ILLUMINATORS_2, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Bottom illuminator", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = V4L2_CTRL_FLAG_UPDATE, + }, + .set = sd_setilluminator2 + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +static const __u8 mi_data[0x20] = { +/* 01 02 03 04 05 06 07 08 */ + 0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00, +/* 09 0a 0b 0c 0d 0e 0f 10 */ + 0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, +/* 11 12 13 14 15 16 17 18 */ + 0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02, +/* 19 1a 1b 1c 1d 1e 1f 20 */ + 0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00 +}; + +/* write bytes from gspca_dev->usb_buf */ +static void reg_w(struct gspca_dev *gspca_dev, + int len) +{ + int alen, ret; + + if (gspca_dev->usb_err < 0) + return; + + ret = usb_bulk_msg(gspca_dev->dev, + usb_sndbulkpipe(gspca_dev->dev, 4), + gspca_dev->usb_buf, + len, + &alen, + 500); /* timeout in milliseconds */ + if (ret < 0) { + err("reg write [%02x] error %d", + gspca_dev->usb_buf[0], ret); + gspca_dev->usb_err = ret; + } +} + +static void mi_w(struct gspca_dev *gspca_dev, + u8 addr, + u8 value) +{ + gspca_dev->usb_buf[0] = 0x1f; + gspca_dev->usb_buf[1] = 0; /* control byte */ + gspca_dev->usb_buf[2] = addr; + gspca_dev->usb_buf[3] = value; + + reg_w(gspca_dev, 4); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->usb_buf[0] = 0x61; + gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val; + reg_w(gspca_dev, 2); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + s16 val; + + val = sd->ctrls[COLORS].val; + gspca_dev->usb_buf[0] = 0x5f; + gspca_dev->usb_buf[1] = val << 3; + gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04; + reg_w(gspca_dev, 3); +} + +static void setgamma(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->usb_buf[0] = 0x06; + gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40; + reg_w(gspca_dev, 2); +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->usb_buf[0] = 0x67; + gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3; + reg_w(gspca_dev, 2); +} + +static void setilluminators(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->usb_buf[0] = 0x22; + if (sd->ctrls[ILLUM_TOP].val) + gspca_dev->usb_buf[1] = 0x76; + else if (sd->ctrls[ILLUM_BOT].val) + gspca_dev->usb_buf[1] = 0x7a; + else + gspca_dev->usb_buf[1] = 0x7e; + reg_w(gspca_dev, 2); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + cam->ctrls = sd->ctrls; + sd->quality = QUALITY_DEF; + gspca_dev->nbalt = 9; /* use the altsetting 08 */ + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT); + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 *data; + int i; + + /* create the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x21); /* JPEG 422 */ + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + data = gspca_dev->usb_buf; + + data[0] = 0x01; /* address */ + data[1] = 0x01; + reg_w(gspca_dev, 2); + + /* + Initialize the MR97113 chip register + */ + data[0] = 0x00; /* address */ + data[1] = 0x0c | 0x01; /* reg 0 */ + data[2] = 0x01; /* reg 1 */ + data[3] = gspca_dev->width / 8; /* h_size , reg 2 */ + data[4] = gspca_dev->height / 8; /* v_size , reg 3 */ + data[5] = 0x30; /* reg 4, MI, PAS5101 : + * 0x30 for 24mhz , 0x28 for 12mhz */ + data[6] = 0x02; /* reg 5, H start - was 0x04 */ + data[7] = sd->ctrls[GAMMA].val * 0x40; /* reg 0x06: gamma */ + data[8] = 0x01; /* reg 7, V start - was 0x03 */ +/* if (h_size == 320 ) */ +/* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */ +/* else */ + data[9] = 0x52; /* reg 8, 24MHz, no scale down */ +/*jfm: from win trace*/ + data[10] = 0x18; + + reg_w(gspca_dev, 11); + + data[0] = 0x23; /* address */ + data[1] = 0x09; /* reg 35, append frame header */ + + reg_w(gspca_dev, 2); + + data[0] = 0x3c; /* address */ +/* if (gspca_dev->width == 1280) */ +/* data[1] = 200; * reg 60, pc-cam frame size + * (unit: 4KB) 800KB */ +/* else */ + data[1] = 50; /* 50 reg 60, pc-cam frame size + * (unit: 4KB) 200KB */ + reg_w(gspca_dev, 2); + + /* auto dark-gain */ + data[0] = 0x5e; /* address */ + data[1] = 0; /* reg 94, Y Gain (auto) */ +/*jfm: from win trace*/ + /* reg 0x5f/0x60 (LE) = saturation */ + /* h (60): xxxx x100 + * l (5f): xxxx x000 */ + data[2] = sd->ctrls[COLORS].val << 3; + data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04; + data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */ + data[5] = 0x00; + + reg_w(gspca_dev, 6); + + data[0] = 0x67; +/*jfm: from win trace*/ + data[1] = sd->ctrls[SHARPNESS].val * 4 + 3; + data[2] = 0x14; + reg_w(gspca_dev, 3); + + data[0] = 0x69; + data[1] = 0x2f; + data[2] = 0x28; + data[3] = 0x42; + reg_w(gspca_dev, 4); + + data[0] = 0x63; + data[1] = 0x07; + reg_w(gspca_dev, 2); +/*jfm: win trace - many writes here to reg 0x64*/ + + /* initialize the MI sensor */ + for (i = 0; i < sizeof mi_data; i++) + mi_w(gspca_dev, i + 1, mi_data[i]); + + data[0] = 0x00; + data[1] = 0x4d; /* ISOC transferring enable... */ + reg_w(gspca_dev, 2); + + gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */ + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT); + if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) { + sd->ctrls[ILLUM_TOP].val = 0; + sd->ctrls[ILLUM_BOT].val = 0; + setilluminators(gspca_dev); + msleep(20); + } + + gspca_dev->usb_buf[0] = 1; + gspca_dev->usb_buf[1] = 0; + reg_w(gspca_dev, 2); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int p; + + if (len < 6) { +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + for (p = 0; p < len - 6; p++) { + if (data[0 + p] == 0xff + && data[1 + p] == 0xff + && data[2 + p] == 0x00 + && data[3 + p] == 0xff + && data[4 + p] == 0x96) { + if (data[5 + p] == 0x64 + || data[5 + p] == 0x65 + || data[5 + p] == 0x66 + || data[5 + p] == 0x67) { + PDEBUG(D_PACK, "sof offset: %d len: %d", + p, len); + gspca_frame_add(gspca_dev, LAST_PACKET, + data, p); + + /* put the JPEG header */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + data += p + 16; + len -= p + 16; + break; + } + } + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* only one illuminator may be on */ + sd->ctrls[ILLUM_TOP].val = val; + if (val) + sd->ctrls[ILLUM_BOT].val = 0; + setilluminators(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* only one illuminator may be on */ + sd->ctrls[ILLUM_BOT].val = val; + if (val) + sd->ctrls[ILLUM_TOP].val = 0; + setilluminators(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (jcomp->quality < QUALITY_MIN) + sd->quality = QUALITY_MIN; + else if (jcomp->quality > QUALITY_MAX) + sd->quality = QUALITY_MAX; + else + sd->quality = jcomp->quality; + if (gspca_dev->streaming) + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + return 0; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = NCTRLS, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x093a, 0x050f)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/mr97310a.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/mr97310a.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/mr97310a.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/mr97310a.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1271 @@ +/* + * Mars MR97310A library + * + * The original mr97310a driver, which supported the Aiptek Pencam VGA+, is + * Copyright (C) 2009 Kyle Guinn + * + * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+ + * and for the routines for detecting and classifying these various cameras, + * is Copyright (C) 2009 Theodore Kilgore + * + * Support for the control settings for the CIF cameras is + * Copyright (C) 2009 Hans de Goede and + * Thomas Kaiser + * + * Support for the control settings for the VGA cameras is + * Copyright (C) 2009 Theodore Kilgore + * + * Several previously unsupported cameras are owned and have been tested by + * Hans de Goede and + * Thomas Kaiser and + * Theodore Kilgore and + * Edmond Rodriguez and + * Aurelien Jacobs + * + * The MR97311A support in gspca/mars.c has been helpful in understanding some + * of the registers in these cameras. + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "mr97310a" + +#include "gspca.h" + +#define CAM_TYPE_CIF 0 +#define CAM_TYPE_VGA 1 + +#define MR97310A_BRIGHTNESS_DEFAULT 0 + +#define MR97310A_EXPOSURE_MIN 0 +#define MR97310A_EXPOSURE_MAX 4095 +#define MR97310A_EXPOSURE_DEFAULT 1000 + +#define MR97310A_GAIN_MIN 0 +#define MR97310A_GAIN_MAX 31 +#define MR97310A_GAIN_DEFAULT 25 + +#define MR97310A_CONTRAST_MIN 0 +#define MR97310A_CONTRAST_MAX 31 +#define MR97310A_CONTRAST_DEFAULT 23 + +#define MR97310A_CS_GAIN_MIN 0 +#define MR97310A_CS_GAIN_MAX 0x7ff +#define MR97310A_CS_GAIN_DEFAULT 0x110 + +#define MR97310A_MIN_CLOCKDIV_MIN 3 +#define MR97310A_MIN_CLOCKDIV_MAX 8 +#define MR97310A_MIN_CLOCKDIV_DEFAULT 3 + +MODULE_AUTHOR("Kyle Guinn ," + "Theodore Kilgore "); +MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* global parameters */ +static int force_sensor_type = -1; +module_param(force_sensor_type, int, 0644); +MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + u8 sof_read; + u8 cam_type; /* 0 is CIF and 1 is VGA */ + u8 sensor_type; /* We use 0 and 1 here, too. */ + u8 do_lcd_stop; + u8 adj_colors; + + int brightness; + u16 exposure; + u32 gain; + u8 contrast; + u8 min_clockdiv; +}; + +struct sensor_w_data { + u8 reg; + u8 flags; + u8 data[16]; + int len; +}; + +static void sd_stopN(struct gspca_dev *gspca_dev); +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val); +static void setbrightness(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static void setgain(struct gspca_dev *gspca_dev); +static void setcontrast(struct gspca_dev *gspca_dev); + +/* V4L2 controls supported by the driver */ +static const struct ctrl sd_ctrls[] = { +/* Separate brightness control description for Argus QuickClix as it has + * different limits from the other mr97310a cameras, and separate gain + * control for Sakar CyberPix camera. */ + { +#define NORM_BRIGHTNESS_IDX 0 + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = -254, + .maximum = 255, + .step = 1, + .default_value = MR97310A_BRIGHTNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { +#define ARGUS_QC_BRIGHTNESS_IDX 1 + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = MR97310A_BRIGHTNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { +#define EXPOSURE_IDX 2 + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = MR97310A_EXPOSURE_MIN, + .maximum = MR97310A_EXPOSURE_MAX, + .step = 1, + .default_value = MR97310A_EXPOSURE_DEFAULT, + .flags = 0, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { +#define GAIN_IDX 3 + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = MR97310A_GAIN_MIN, + .maximum = MR97310A_GAIN_MAX, + .step = 1, + .default_value = MR97310A_GAIN_DEFAULT, + .flags = 0, + }, + .set = sd_setgain, + .get = sd_getgain, + }, + { +#define SAKAR_CS_GAIN_IDX 4 + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = MR97310A_CS_GAIN_MIN, + .maximum = MR97310A_CS_GAIN_MAX, + .step = 1, + .default_value = MR97310A_CS_GAIN_DEFAULT, + .flags = 0, + }, + .set = sd_setgain, + .get = sd_getgain, + }, + { +#define CONTRAST_IDX 5 + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = MR97310A_CONTRAST_MIN, + .maximum = MR97310A_CONTRAST_MAX, + .step = 1, + .default_value = MR97310A_CONTRAST_DEFAULT, + .flags = 0, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { +#define MIN_CLOCKDIV_IDX 6 + { + .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Minimum Clock Divider", + .minimum = MR97310A_MIN_CLOCKDIV_MIN, + .maximum = MR97310A_MIN_CLOCKDIV_MAX, + .step = 1, + .default_value = MR97310A_MIN_CLOCKDIV_DEFAULT, + .flags = 0, + }, + .set = sd_setmin_clockdiv, + .get = sd_getmin_clockdiv, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 4}, + {176, 144, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {320, 240, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* the bytes to write are in gspca_dev->usb_buf */ +static int mr_write(struct gspca_dev *gspca_dev, int len) +{ + int rc; + + rc = usb_bulk_msg(gspca_dev->dev, + usb_sndbulkpipe(gspca_dev->dev, 4), + gspca_dev->usb_buf, len, NULL, 500); + if (rc < 0) + err("reg write [%02x] error %d", + gspca_dev->usb_buf[0], rc); + return rc; +} + +/* the bytes are read into gspca_dev->usb_buf */ +static int mr_read(struct gspca_dev *gspca_dev, int len) +{ + int rc; + + rc = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 3), + gspca_dev->usb_buf, len, NULL, 500); + if (rc < 0) + err("reg read [%02x] error %d", + gspca_dev->usb_buf[0], rc); + return rc; +} + +static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags, + const u8 *data, int len) +{ + gspca_dev->usb_buf[0] = 0x1f; + gspca_dev->usb_buf[1] = flags; + gspca_dev->usb_buf[2] = reg; + memcpy(gspca_dev->usb_buf + 3, data, len); + + return mr_write(gspca_dev, len + 3); +} + +static int sensor_write_regs(struct gspca_dev *gspca_dev, + const struct sensor_w_data *data, int len) +{ + int i, rc; + + for (i = 0; i < len; i++) { + rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags, + data[i].data, data[i].len); + if (rc < 0) + return rc; + } + + return 0; +} + +static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 buf, confirm_reg; + int rc; + + buf = data; + if (sd->cam_type == CAM_TYPE_CIF) { + rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1); + confirm_reg = sd->sensor_type ? 0x13 : 0x11; + } else { + rc = sensor_write_reg(gspca_dev, reg, 0x00, &buf, 1); + confirm_reg = 0x11; + } + if (rc < 0) + return rc; + + buf = 0x01; + rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1); + if (rc < 0) + return rc; + + return 0; +} + +static int cam_get_response16(struct gspca_dev *gspca_dev, u8 reg, int verbose) +{ + int err_code; + + gspca_dev->usb_buf[0] = reg; + err_code = mr_write(gspca_dev, 1); + if (err_code < 0) + return err_code; + + err_code = mr_read(gspca_dev, 16); + if (err_code < 0) + return err_code; + + if (verbose) + PDEBUG(D_PROBE, "Register: %02x reads %02x%02x%02x", reg, + gspca_dev->usb_buf[0], + gspca_dev->usb_buf[1], + gspca_dev->usb_buf[2]); + + return 0; +} + +static int zero_the_pointer(struct gspca_dev *gspca_dev) +{ + __u8 *data = gspca_dev->usb_buf; + int err_code; + u8 status = 0; + int tries = 0; + + err_code = cam_get_response16(gspca_dev, 0x21, 0); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0x51; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev, 0x21, 0); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0xba; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev, 0x21, 0); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev, 0x21, 0); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + while (status != 0x0a && tries < 256) { + err_code = cam_get_response16(gspca_dev, 0x21, 0); + status = data[0]; + tries++; + if (err_code < 0) + return err_code; + } + if (status != 0x0a) + PDEBUG(D_ERR, "status is %02x", status); + + tries = 0; + while (tries < 4) { + data[0] = 0x19; + data[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev, 0x21, 0); + status = data[0]; + tries++; + if (err_code < 0) + return err_code; + } + + data[0] = 0x19; + err_code = mr_write(gspca_dev, 1); + if (err_code < 0) + return err_code; + + err_code = mr_read(gspca_dev, 16); + if (err_code < 0) + return err_code; + + return 0; +} + +static int stream_start(struct gspca_dev *gspca_dev) +{ + gspca_dev->usb_buf[0] = 0x01; + gspca_dev->usb_buf[1] = 0x01; + return mr_write(gspca_dev, 2); +} + +static void stream_stop(struct gspca_dev *gspca_dev) +{ + gspca_dev->usb_buf[0] = 0x01; + gspca_dev->usb_buf[1] = 0x00; + if (mr_write(gspca_dev, 2) < 0) + PDEBUG(D_ERR, "Stream Stop failed"); +} + +static void lcd_stop(struct gspca_dev *gspca_dev) +{ + gspca_dev->usb_buf[0] = 0x19; + gspca_dev->usb_buf[1] = 0x54; + if (mr_write(gspca_dev, 2) < 0) + PDEBUG(D_ERR, "LCD Stop failed"); +} + +static int isoc_enable(struct gspca_dev *gspca_dev) +{ + gspca_dev->usb_buf[0] = 0x00; + gspca_dev->usb_buf[1] = 0x4d; /* ISOC transferring enable... */ + return mr_write(gspca_dev, 2); +} + +/* This function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + int gain_default = MR97310A_GAIN_DEFAULT; + int err_code; + + cam = &gspca_dev->cam; + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + sd->do_lcd_stop = 0; + + /* Several of the supported CIF cameras share the same USB ID but + * require different initializations and different control settings. + * The same is true of the VGA cameras. Therefore, we are forced + * to start the initialization process in order to determine which + * camera is present. Some of the supported cameras require the + * memory pointer to be set to 0 as the very first item of business + * or else they will not stream. So we do that immediately. + */ + err_code = zero_the_pointer(gspca_dev); + if (err_code < 0) + return err_code; + + err_code = stream_start(gspca_dev); + if (err_code < 0) + return err_code; + + /* Now, the query for sensor type. */ + err_code = cam_get_response16(gspca_dev, 0x07, 1); + if (err_code < 0) + return err_code; + + if (id->idProduct == 0x0110 || id->idProduct == 0x010e) { + sd->cam_type = CAM_TYPE_CIF; + cam->nmodes--; + /* + * All but one of the known CIF cameras share the same USB ID, + * but two different init routines are in use, and the control + * settings are different, too. We need to detect which camera + * of the two known varieties is connected! + * + * A list of known CIF cameras follows. They all report either + * 0200 for type 0 or 0300 for type 1. + * If you have another to report, please do + * + * Name sd->sensor_type reported by + * + * Sakar 56379 Spy-shot 0 T. Kilgore + * Innovage 0 T. Kilgore + * Vivitar Mini 0 H. De Goede + * Vivitar Mini 0 E. Rodriguez + * Vivitar Mini 1 T. Kilgore + * Elta-Media 8212dc 1 T. Kaiser + * Philips dig. keych. 1 T. Kilgore + * Trust Spyc@m 100 1 A. Jacobs + */ + switch (gspca_dev->usb_buf[0]) { + case 2: + sd->sensor_type = 0; + break; + case 3: + sd->sensor_type = 1; + break; + default: + err("Unknown CIF Sensor id : %02x", + gspca_dev->usb_buf[1]); + return -ENODEV; + } + PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d", + sd->sensor_type); + } else { + sd->cam_type = CAM_TYPE_VGA; + + /* + * Here is a table of the responses to the query for sensor + * type, from the known MR97310A VGA cameras. Six different + * cameras of which five share the same USB ID. + * + * Name gspca_dev->usb_buf[] sd->sensor_type + * sd->do_lcd_stop + * Aiptek Pencam VGA+ 0300 0 1 + * ION digital 0300 0 1 + * Argus DC-1620 0450 1 0 + * Argus QuickClix 0420 1 1 + * Sakar 77379 Digital 0350 0 1 + * Sakar 1638x CyberPix 0120 0 2 + * + * Based upon these results, we assume default settings + * and then correct as necessary, as follows. + * + */ + + sd->sensor_type = 1; + sd->do_lcd_stop = 0; + sd->adj_colors = 0; + if (gspca_dev->usb_buf[0] == 0x01) { + sd->sensor_type = 2; + } else if ((gspca_dev->usb_buf[0] != 0x03) && + (gspca_dev->usb_buf[0] != 0x04)) { + err("Unknown VGA Sensor id Byte 0: %02x", + gspca_dev->usb_buf[0]); + err("Defaults assumed, may not work"); + err("Please report this"); + } + /* Sakar Digital color needs to be adjusted. */ + if ((gspca_dev->usb_buf[0] == 0x03) && + (gspca_dev->usb_buf[1] == 0x50)) + sd->adj_colors = 1; + if (gspca_dev->usb_buf[0] == 0x04) { + sd->do_lcd_stop = 1; + switch (gspca_dev->usb_buf[1]) { + case 0x50: + sd->sensor_type = 0; + PDEBUG(D_PROBE, "sensor_type corrected to 0"); + break; + case 0x20: + /* Nothing to do here. */ + break; + default: + err("Unknown VGA Sensor id Byte 1: %02x", + gspca_dev->usb_buf[1]); + err("Defaults assumed, may not work"); + err("Please report this"); + } + } + PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d", + sd->sensor_type); + } + /* Stop streaming as we've started it only to probe the sensor type. */ + sd_stopN(gspca_dev); + + if (force_sensor_type != -1) { + sd->sensor_type = !!force_sensor_type; + PDEBUG(D_PROBE, "Forcing sensor type to: %d", + sd->sensor_type); + } + + /* Setup controls depending on camera type */ + if (sd->cam_type == CAM_TYPE_CIF) { + /* No brightness for sensor_type 0 */ + if (sd->sensor_type == 0) + gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | + (1 << ARGUS_QC_BRIGHTNESS_IDX) | + (1 << CONTRAST_IDX) | + (1 << SAKAR_CS_GAIN_IDX); + else + gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) | + (1 << CONTRAST_IDX) | + (1 << SAKAR_CS_GAIN_IDX) | + (1 << MIN_CLOCKDIV_IDX); + } else { + /* All controls need to be disabled if VGA sensor_type is 0 */ + if (sd->sensor_type == 0) + gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | + (1 << ARGUS_QC_BRIGHTNESS_IDX) | + (1 << EXPOSURE_IDX) | + (1 << GAIN_IDX) | + (1 << CONTRAST_IDX) | + (1 << SAKAR_CS_GAIN_IDX) | + (1 << MIN_CLOCKDIV_IDX); + else if (sd->sensor_type == 2) { + gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | + (1 << ARGUS_QC_BRIGHTNESS_IDX) | + (1 << GAIN_IDX) | + (1 << MIN_CLOCKDIV_IDX); + gain_default = MR97310A_CS_GAIN_DEFAULT; + } else if (sd->do_lcd_stop) + /* Argus QuickClix has different brightness limits */ + gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | + (1 << CONTRAST_IDX) | + (1 << SAKAR_CS_GAIN_IDX); + else + gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) | + (1 << CONTRAST_IDX) | + (1 << SAKAR_CS_GAIN_IDX); + } + + sd->brightness = MR97310A_BRIGHTNESS_DEFAULT; + sd->exposure = MR97310A_EXPOSURE_DEFAULT; + sd->gain = gain_default; + sd->contrast = MR97310A_CONTRAST_DEFAULT; + sd->min_clockdiv = MR97310A_MIN_CLOCKDIV_DEFAULT; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +static int start_cif_cam(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 *data = gspca_dev->usb_buf; + int err_code; + static const __u8 startup_string[] = { + 0x00, + 0x0d, + 0x01, + 0x00, /* Hsize/8 for 352 or 320 */ + 0x00, /* Vsize/4 for 288 or 240 */ + 0x13, /* or 0xbb, depends on sensor */ + 0x00, /* Hstart, depends on res. */ + 0x00, /* reserved ? */ + 0x00, /* Vstart, depends on res. and sensor */ + 0x50, /* 0x54 to get 176 or 160 */ + 0xc0 + }; + + /* Note: Some of the above descriptions guessed from MR97113A driver */ + + memcpy(data, startup_string, 11); + if (sd->sensor_type) + data[5] = 0xbb; + + switch (gspca_dev->width) { + case 160: + data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */ + /* fall thru */ + case 320: + default: + data[3] = 0x28; /* reg 2, H size/8 */ + data[4] = 0x3c; /* reg 3, V size/4 */ + data[6] = 0x14; /* reg 5, H start */ + data[8] = 0x1a + sd->sensor_type; /* reg 7, V start */ + break; + case 176: + data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */ + /* fall thru */ + case 352: + data[3] = 0x2c; /* reg 2, H size/8 */ + data[4] = 0x48; /* reg 3, V size/4 */ + data[6] = 0x06; /* reg 5, H start */ + data[8] = 0x06 - sd->sensor_type; /* reg 7, V start */ + break; + } + err_code = mr_write(gspca_dev, 11); + if (err_code < 0) + return err_code; + + if (!sd->sensor_type) { + static const struct sensor_w_data cif_sensor0_init_data[] = { + {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01, + 0x0f, 0x14, 0x0f, 0x10}, 8}, + {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5}, + {0x12, 0x00, {0x07}, 1}, + {0x1f, 0x00, {0x06}, 1}, + {0x27, 0x00, {0x04}, 1}, + {0x29, 0x00, {0x0c}, 1}, + {0x40, 0x00, {0x40, 0x00, 0x04}, 3}, + {0x50, 0x00, {0x60}, 1}, + {0x60, 0x00, {0x06}, 1}, + {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6}, + {0x72, 0x00, {0x1e, 0x56}, 2}, + {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02, + 0x31, 0x80, 0x00}, 9}, + {0x11, 0x00, {0x01}, 1}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data, + ARRAY_SIZE(cif_sensor0_init_data)); + } else { /* sd->sensor_type = 1 */ + static const struct sensor_w_data cif_sensor1_init_data[] = { + /* Reg 3,4, 7,8 get set by the controls */ + {0x02, 0x00, {0x10}, 1}, + {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */ + {0x06, 0x01, {0x00}, 1}, + {0x09, 0x02, {0x0e}, 1}, + {0x0a, 0x02, {0x05}, 1}, + {0x0b, 0x02, {0x05}, 1}, + {0x0c, 0x02, {0x0f}, 1}, + {0x0d, 0x02, {0x07}, 1}, + {0x0e, 0x02, {0x0c}, 1}, + {0x0f, 0x00, {0x00}, 1}, + {0x10, 0x00, {0x06}, 1}, + {0x11, 0x00, {0x07}, 1}, + {0x12, 0x00, {0x00}, 1}, + {0x13, 0x00, {0x01}, 1}, + {0, 0, {0}, 0} + }; + /* Without this command the cam won't work with USB-UHCI */ + gspca_dev->usb_buf[0] = 0x0a; + gspca_dev->usb_buf[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data, + ARRAY_SIZE(cif_sensor1_init_data)); + } + return err_code; +} + +static int start_vga_cam(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 *data = gspca_dev->usb_buf; + int err_code; + static const __u8 startup_string[] = + {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, 0x00, 0x00, + 0x00, 0x50, 0xc0}; + /* What some of these mean is explained in start_cif_cam(), above */ + + memcpy(data, startup_string, 11); + if (!sd->sensor_type) { + data[5] = 0x00; + data[10] = 0x91; + } + if (sd->sensor_type == 2) { + data[5] = 0x00; + data[10] = 0x18; + } + + switch (gspca_dev->width) { + case 160: + data[9] |= 0x0c; /* reg 8, 4:1 scale down */ + /* fall thru */ + case 320: + data[9] |= 0x04; /* reg 8, 2:1 scale down */ + /* fall thru */ + case 640: + default: + data[3] = 0x50; /* reg 2, H size/8 */ + data[4] = 0x78; /* reg 3, V size/4 */ + data[6] = 0x04; /* reg 5, H start */ + data[8] = 0x03; /* reg 7, V start */ + if (sd->sensor_type == 2) { + data[6] = 2; + data[8] = 1; + } + if (sd->do_lcd_stop) + data[8] = 0x04; /* Bayer tile shifted */ + break; + + case 176: + data[9] |= 0x04; /* reg 8, 2:1 scale down */ + /* fall thru */ + case 352: + data[3] = 0x2c; /* reg 2, H size */ + data[4] = 0x48; /* reg 3, V size */ + data[6] = 0x94; /* reg 5, H start */ + data[8] = 0x63; /* reg 7, V start */ + if (sd->do_lcd_stop) + data[8] = 0x64; /* Bayer tile shifted */ + break; + } + + err_code = mr_write(gspca_dev, 11); + if (err_code < 0) + return err_code; + + if (!sd->sensor_type) { + static const struct sensor_w_data vga_sensor0_init_data[] = { + {0x01, 0x00, {0x0c, 0x00, 0x04}, 3}, + {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4}, + {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4}, + {0x25, 0x00, {0x03, 0xa9, 0x80}, 3}, + {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data, + ARRAY_SIZE(vga_sensor0_init_data)); + } else if (sd->sensor_type == 1) { + static const struct sensor_w_data color_adj[] = { + {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00, + /* adjusted blue, green, red gain correct + too much blue from the Sakar Digital */ + 0x05, 0x01, 0x04}, 8} + }; + + static const struct sensor_w_data color_no_adj[] = { + {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00, + /* default blue, green, red gain settings */ + 0x07, 0x00, 0x01}, 8} + }; + + static const struct sensor_w_data vga_sensor1_init_data[] = { + {0x11, 0x04, {0x01}, 1}, + {0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01, + /* These settings may be better for some cameras */ + /* {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, */ + 0x00, 0x0a}, 7}, + {0x11, 0x04, {0x01}, 1}, + {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6}, + {0x11, 0x04, {0x01}, 1}, + {0, 0, {0}, 0} + }; + + if (sd->adj_colors) + err_code = sensor_write_regs(gspca_dev, color_adj, + ARRAY_SIZE(color_adj)); + else + err_code = sensor_write_regs(gspca_dev, color_no_adj, + ARRAY_SIZE(color_no_adj)); + + if (err_code < 0) + return err_code; + + err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data, + ARRAY_SIZE(vga_sensor1_init_data)); + } else { /* sensor type == 2 */ + static const struct sensor_w_data vga_sensor2_init_data[] = { + + {0x01, 0x00, {0x48}, 1}, + {0x02, 0x00, {0x22}, 1}, + /* Reg 3 msb and 4 is lsb of the exposure setting*/ + {0x05, 0x00, {0x10}, 1}, + {0x06, 0x00, {0x00}, 1}, + {0x07, 0x00, {0x00}, 1}, + {0x08, 0x00, {0x00}, 1}, + {0x09, 0x00, {0x00}, 1}, + /* The following are used in the gain control + * which is BTW completely borked in the OEM driver + * The values for each color go from 0 to 0x7ff + *{0x0a, 0x00, {0x01}, 1}, green1 gain msb + *{0x0b, 0x00, {0x10}, 1}, green1 gain lsb + *{0x0c, 0x00, {0x01}, 1}, red gain msb + *{0x0d, 0x00, {0x10}, 1}, red gain lsb + *{0x0e, 0x00, {0x01}, 1}, blue gain msb + *{0x0f, 0x00, {0x10}, 1}, blue gain lsb + *{0x10, 0x00, {0x01}, 1}, green2 gain msb + *{0x11, 0x00, {0x10}, 1}, green2 gain lsb + */ + {0x12, 0x00, {0x00}, 1}, + {0x13, 0x00, {0x04}, 1}, /* weird effect on colors */ + {0x14, 0x00, {0x00}, 1}, + {0x15, 0x00, {0x06}, 1}, + {0x16, 0x00, {0x01}, 1}, + {0x17, 0x00, {0xe2}, 1}, /* vertical alignment */ + {0x18, 0x00, {0x02}, 1}, + {0x19, 0x00, {0x82}, 1}, /* don't mess with */ + {0x1a, 0x00, {0x00}, 1}, + {0x1b, 0x00, {0x20}, 1}, + /* {0x1c, 0x00, {0x17}, 1}, contrast control */ + {0x1d, 0x00, {0x80}, 1}, /* moving causes a mess */ + {0x1e, 0x00, {0x08}, 1}, /* moving jams the camera */ + {0x1f, 0x00, {0x0c}, 1}, + {0x20, 0x00, {0x00}, 1}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, vga_sensor2_init_data, + ARRAY_SIZE(vga_sensor2_init_data)); + } + return err_code; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err_code; + + sd->sof_read = 0; + + /* Some of the VGA cameras require the memory pointer + * to be set to 0 again. We have been forced to start the + * stream in sd_config() to detect the hardware, and closed it. + * Thus, we need here to do a completely fresh and clean start. */ + err_code = zero_the_pointer(gspca_dev); + if (err_code < 0) + return err_code; + + err_code = stream_start(gspca_dev); + if (err_code < 0) + return err_code; + + if (sd->cam_type == CAM_TYPE_CIF) { + err_code = start_cif_cam(gspca_dev); + } else { + err_code = start_vga_cam(gspca_dev); + } + if (err_code < 0) + return err_code; + + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setexposure(gspca_dev); + setgain(gspca_dev); + + return isoc_enable(gspca_dev); +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + stream_stop(gspca_dev); + /* Not all the cams need this, but even if not, probably a good idea */ + zero_the_pointer(gspca_dev); + if (sd->do_lcd_stop) + lcd_stop(gspca_dev); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */ + u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */ + static const u8 quick_clix_table[] = + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + { 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15}; + /* + * This control is disabled for CIF type 1 and VGA type 0 cameras. + * It does not quite act linearly for the Argus QuickClix camera, + * but it does control brightness. The values are 0 - 15 only, and + * the table above makes them act consecutively. + */ + if ((gspca_dev->ctrl_dis & (1 << NORM_BRIGHTNESS_IDX)) && + (gspca_dev->ctrl_dis & (1 << ARGUS_QC_BRIGHTNESS_IDX))) + return; + + if (sd->cam_type == CAM_TYPE_VGA) { + sign_reg += 4; + value_reg += 4; + } + + /* Note register 7 is also seen as 0x8x or 0xCx in some dumps */ + if (sd->brightness > 0) { + sensor_write1(gspca_dev, sign_reg, 0x00); + val = sd->brightness; + } else { + sensor_write1(gspca_dev, sign_reg, 0x01); + val = (257 - sd->brightness); + } + /* Use lookup table for funky Argus QuickClix brightness */ + if (sd->do_lcd_stop) + val = quick_clix_table[val]; + + sensor_write1(gspca_dev, value_reg, val); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int exposure = MR97310A_EXPOSURE_DEFAULT; + u8 buf[2]; + + if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) + return; + + if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) { + /* This cam does not like exposure settings < 300, + so scale 0 - 4095 to 300 - 4095 */ + exposure = (sd->exposure * 9267) / 10000 + 300; + sensor_write1(gspca_dev, 3, exposure >> 4); + sensor_write1(gspca_dev, 4, exposure & 0x0f); + } else if (sd->sensor_type == 2) { + exposure = sd->exposure; + exposure >>= 3; + sensor_write1(gspca_dev, 3, exposure >> 8); + sensor_write1(gspca_dev, 4, exposure & 0xff); + } else { + /* We have both a clock divider and an exposure register. + We first calculate the clock divider, as that determines + the maximum exposure and then we calculate the exposure + register setting (which goes from 0 - 511). + + Note our 0 - 4095 exposure is mapped to 0 - 511 + milliseconds exposure time */ + u8 clockdiv = (60 * sd->exposure + 7999) / 8000; + + /* Limit framerate to not exceed usb bandwidth */ + if (clockdiv < sd->min_clockdiv && gspca_dev->width >= 320) + clockdiv = sd->min_clockdiv; + else if (clockdiv < 2) + clockdiv = 2; + + if (sd->cam_type == CAM_TYPE_VGA && clockdiv < 4) + clockdiv = 4; + + /* Frame exposure time in ms = 1000 * clockdiv / 60 -> + exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */ + exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv); + if (exposure > 511) + exposure = 511; + + /* exposure register value is reversed! */ + exposure = 511 - exposure; + + buf[0] = exposure & 0xff; + buf[1] = exposure >> 8; + sensor_write_reg(gspca_dev, 0x0e, 0, buf, 2); + sensor_write1(gspca_dev, 0x02, clockdiv); + } +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 gainreg; + + if ((gspca_dev->ctrl_dis & (1 << GAIN_IDX)) && + (gspca_dev->ctrl_dis & (1 << SAKAR_CS_GAIN_IDX))) + return; + + if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) + sensor_write1(gspca_dev, 0x0e, sd->gain); + else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2) + for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) { + sensor_write1(gspca_dev, gainreg, sd->gain >> 8); + sensor_write1(gspca_dev, gainreg + 1, sd->gain & 0xff); + } + else + sensor_write1(gspca_dev, 0x10, sd->gain); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX)) + return; + + sensor_write1(gspca_dev, 0x1c, sd->contrast); +} + + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->min_clockdiv = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->min_clockdiv; + return 0; +} + +/* Include pac common sof detection functions */ +#include "pac_common.h" + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned char *sof; + + sof = pac_find_sof(&sd->sof_read, data, len); + if (sof) { + int n; + + /* finish decoding current frame */ + n = sof - data; + if (n > sizeof pac_sof_marker) + n -= sizeof pac_sof_marker; + else + n = 0; + gspca_frame_add(gspca_dev, LAST_PACKET, + data, n); + /* Start next frame. */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + pac_sof_marker, sizeof pac_sof_marker); + len -= sof - data; + data = sof; + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x08ca, 0x0110)}, /* Trust Spyc@m 100 */ + {USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */ + {USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */ + {USB_DEVICE(0x093a, 0x010e)}, /* All known MR97310A CIF cams */ + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/nw80x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/nw80x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/nw80x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/nw80x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2145 @@ +/* + * DivIO nw80x subdriver + * + * Copyright (C) 2011 Jean-François Moine (http://moinejf.free.fr) + * Copyright (C) 2003 Sylvain Munaut + * Kjell Claesson + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "nw80x" + +#include "gspca.h" + +MODULE_AUTHOR("Jean-Francois Moine "); +MODULE_DESCRIPTION("NW80x USB Camera Driver"); +MODULE_LICENSE("GPL"); + +static int webcam; + +/* controls */ +enum e_ctrl { + GAIN, + EXPOSURE, + AUTOGAIN, + NCTRLS /* number of controls */ +}; + +#define AUTOGAIN_DEF 1 + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + + u32 ae_res; + s8 ag_cnt; +#define AG_CNT_START 13 + u8 exp_too_low_cnt; + u8 exp_too_high_cnt; + + u8 bridge; + u8 webcam; +}; + +enum bridges { + BRIDGE_NW800, /* and et31x110 */ + BRIDGE_NW801, + BRIDGE_NW802, +}; +enum webcams { + Generic800, + SpaceCam, /* Trust 120 SpaceCam */ + SpaceCam2, /* other Trust 120 SpaceCam */ + Cvideopro, /* Conceptronic Video Pro */ + Dlink350c, + DS3303u, + Kr651us, + Kritter, + Mustek300, + Proscope, + Twinkle, + DvcV6, + P35u, + Generic802, + NWEBCAMS /* number of webcams */ +}; + +static const u8 webcam_chip[NWEBCAMS] = { + [Generic800] = BRIDGE_NW800, /* 06a5:0000 + * Typhoon Webcam 100 USB */ + + [SpaceCam] = BRIDGE_NW800, /* 06a5:d800 + * Trust SpaceCam120 or SpaceCam100 PORTABLE */ + + [SpaceCam2] = BRIDGE_NW800, /* 06a5:d800 - pas106 + * other Trust SpaceCam120 or SpaceCam100 PORTABLE */ + + [Cvideopro] = BRIDGE_NW802, /* 06a5:d001 + * Conceptronic Video Pro 'CVIDEOPRO USB Webcam CCD' */ + + [Dlink350c] = BRIDGE_NW802, /* 06a5:d001 + * D-Link NetQam Pro 250plus */ + + [DS3303u] = BRIDGE_NW801, /* 06a5:d001 + * Plustek Opticam 500U or ProLink DS3303u */ + + [Kr651us] = BRIDGE_NW802, /* 06a5:d001 + * Panasonic GP-KR651US */ + + [Kritter] = BRIDGE_NW802, /* 06a5:d001 + * iRez Kritter cam */ + + [Mustek300] = BRIDGE_NW802, /* 055f:d001 + * Mustek Wcam 300 mini */ + + [Proscope] = BRIDGE_NW802, /* 06a5:d001 + * Scalar USB Microscope (ProScope) */ + + [Twinkle] = BRIDGE_NW800, /* 06a5:d800 - hv7121b? (seems pas106) + * Divio Chicony TwinkleCam + * DSB-C110 */ + + [DvcV6] = BRIDGE_NW802, /* 0502:d001 + * DVC V6 */ + + [P35u] = BRIDGE_NW801, /* 052b:d001, 06a5:d001 and 06be:d001 + * EZCam Pro p35u */ + + [Generic802] = BRIDGE_NW802, +}; +/* + * other webcams: + * - nw801 046d:d001 + * Logitech QuickCam Pro (dark focus ring) + * - nw801 0728:d001 + * AVerMedia Camguard + * - nw??? 06a5:d001 + * D-Link NetQam Pro 250plus + * - nw800 065a:d800 + * Showcam NGS webcam + * - nw??? ????:???? + * Sceptre svc300 + */ + +/* + * registers + * nw800/et31x110 nw801 nw802 + * 0000..009e 0000..00a1 0000..009e + * 0200..0211 id id + * 0300..0302 id id + * 0400..0406 (inex) 0400..0406 + * 0500..0505 0500..0506 (inex) + * 0600..061a 0600..0601 0600..0601 + * 0800..0814 id id + * 1000..109c 1000..10a1 1000..109a + */ + +/* resolutions + * nw800: 320x240, 352x288 + * nw801/802: 320x240, 640x480 + */ +static const struct v4l2_pix_format cif_mode[] = { + {320, 240, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8, + .colorspace = V4L2_COLORSPACE_JPEG}, + {352, 288, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 4 / 8, + .colorspace = V4L2_COLORSPACE_JPEG} +}; +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8, + .colorspace = V4L2_COLORSPACE_JPEG}, + {640, 480, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8, + .colorspace = V4L2_COLORSPACE_JPEG}, +}; + +/* + * The sequences below contain: + * - 1st and 2nd bytes: either + * - register number (BE) + * - I2C0 + i2c address + * - 3rd byte: data length (=0 for end of sequence) + * - n bytes: data + */ +#define I2C0 0xff + +static const u8 nw800_init[] = { + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x01, + 0x04, 0x06, 0x01, 0x04, + 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x05, 0x01, 0x00, + 0, 0, 0 +}; +static const u8 nw800_start[] = { + 0x04, 0x06, 0x01, 0xc0, + 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24, + 0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08, + 0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0xc0, + 0x05, 0x00, 0x06, 0xe8, 0x00, 0x00, 0x00, 0x20, 0x20, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + + 0x04, 0x04, 0x01, 0xff, + 0x04, 0x06, 0x01, 0xc4, + + 0x04, 0x06, 0x01, 0xc0, + 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24, + 0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08, + 0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0xc0, + 0x05, 0x00, 0x06, 0xe8, 0x00, 0x00, 0x00, 0x20, 0x20, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + + 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, + 0x40, + 0x00, 0x80, 0x01, 0xa0, + 0x10, 0x1a, 0x01, 0x00, + 0x00, 0x91, 0x02, 0x6c, 0x01, + 0x00, 0x03, 0x02, 0xc8, 0x01, + 0x10, 0x1a, 0x01, 0x00, + 0x10, 0x00, 0x01, 0x83, + 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, + 0x20, 0x01, 0x60, 0x01, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x10, 0x1b, 0x02, 0x69, 0x00, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x05, 0x02, 0x01, 0x02, + 0x06, 0x00, 0x02, 0x04, 0xd9, + 0x05, 0x05, 0x01, 0x20, + 0x05, 0x05, 0x01, 0x21, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x08, 0x21, 0x3d, 0x52, 0x63, 0x75, 0x83, + 0x91, 0x9e, 0xaa, 0xb6, 0xc1, 0xcc, 0xd6, 0xe0, + 0xea, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x13, 0x13, + 0x10, 0x03, 0x01, 0x14, + 0x10, 0x41, 0x11, 0x00, 0x08, 0x21, 0x3d, 0x52, 0x63, 0x75, 0x83, + 0x91, 0x9e, 0xaa, 0xb6, 0xc1, 0xcc, 0xd6, 0xe0, + 0xea, + 0x10, 0x0b, 0x01, 0x14, + 0x10, 0x0d, 0x01, 0x20, + 0x10, 0x0c, 0x01, 0x34, + 0x04, 0x06, 0x01, 0xc3, + 0x04, 0x04, 0x01, 0x00, + 0x05, 0x02, 0x01, 0x02, + 0x06, 0x00, 0x02, 0x00, 0x48, + 0x05, 0x05, 0x01, 0x20, + 0x05, 0x05, 0x01, 0x21, + 0, 0, 0 +}; + +/* 06a5:d001 - nw801 - Panasonic + * P35u */ +static const u8 nw801_start_1[] = { + 0x05, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x0e, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e, + 0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x22, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x69, 0xa8, 0x1f, 0x00, + 0x0d, 0x02, 0x07, 0x00, 0x01, 0x00, 0x19, 0x00, + 0xf2, 0x00, 0x18, 0x06, 0x10, 0x06, 0x10, 0x00, + 0x36, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x22, 0x02, 0x80, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, 0x15, 0x08, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x35, 0xfd, 0x07, 0x3d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x02, + 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, 0xf7, + 0x10, 0x40, 0x40, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, 0x80, + 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, 0xa4, + 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, 0xcf, + 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, + 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, + 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x10, 0x80, 0x22, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x82, 0x02, + 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, 0x01, + 0xf0, 0x00, + 0, 0, 0, +}; +static const u8 nw801_start_qvga[] = { + 0x02, 0x00, 0x10, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x18, 0x0b, 0x06, 0xa2, 0x86, 0x78, + 0x02, 0x0f, 0x01, 0x6b, + 0x10, 0x1a, 0x01, 0x15, + 0x00, 0x00, 0x01, 0x1e, + 0x10, 0x00, 0x01, 0x2f, + 0x10, 0x8c, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x11, 0x08, 0x29, 0x00, 0x18, 0x01, 0x1f, 0x00, 0xd2, 0x00, + /* AE window */ + 0, 0, 0, +}; +static const u8 nw801_start_vga[] = { + 0x02, 0x00, 0x10, 0x78, 0xa0, 0x97, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xf0, + 0x02, 0x0f, 0x01, 0xd5, + 0x10, 0x1a, 0x01, 0x15, + 0x00, 0x00, 0x01, 0x0e, + 0x10, 0x00, 0x01, 0x22, + 0x10, 0x8c, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, + 0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01, + 0, 0, 0, +}; +static const u8 nw801_start_2[] = { + 0x10, 0x04, 0x01, 0x1a, + 0x10, 0x19, 0x01, 0x09, /* clock */ + 0x10, 0x24, 0x06, 0xc0, 0x00, 0x3f, 0x02, 0x00, 0x01, + /* .. gain .. */ + 0x00, 0x03, 0x02, 0x92, 0x03, + 0x00, 0x1d, 0x04, 0xf2, 0x00, 0x24, 0x07, + 0x00, 0x7b, 0x01, 0xcf, + 0x10, 0x94, 0x01, 0x07, + 0x05, 0x05, 0x01, 0x01, + 0x05, 0x04, 0x01, 0x01, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x48, 0x11, 0x00, 0x37, 0x55, 0x6b, 0x7d, 0x8d, 0x9b, 0xa8, + 0xb4, 0xbf, 0xca, 0xd4, 0xdd, 0xe6, 0xef, 0xf0, + 0xf0, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x0c, 0x0c, + 0x10, 0x03, 0x01, 0x08, + 0x10, 0x48, 0x11, 0x00, 0x37, 0x55, 0x6b, 0x7d, 0x8d, 0x9b, 0xa8, + 0xb4, 0xbf, 0xca, 0xd4, 0xdd, 0xe6, 0xef, 0xf0, + 0xf0, + 0x10, 0x0b, 0x01, 0x0b, + 0x10, 0x0d, 0x01, 0x0b, + 0x10, 0x0c, 0x01, 0x1f, + 0x05, 0x06, 0x01, 0x03, + 0, 0, 0 +}; + +/* nw802 (sharp IR3Y38M?) */ +static const u8 nw802_start[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x4d, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x08, 0x00, 0x18, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0xff, 0x01, 0xc0, 0x00, 0x14, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x00, + 0x10, 0x00, 0x01, 0xad, + 0x00, 0x00, 0x01, 0x08, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x51, 0x00, 0xf0, 0x00, 0x3d, 0x00, 0xb4, 0x00, + 0x10, 0x1d, 0x08, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, + 0x10, 0x0e, 0x01, 0x27, + 0x10, 0x41, 0x11, 0x00, 0x0e, 0x35, 0x4f, 0x62, 0x71, 0x7f, 0x8b, + 0x96, 0xa0, 0xa9, 0xb2, 0xbb, 0xc3, 0xca, 0xd2, + 0xd8, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x14, 0x14, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, 0xf1, + 0xff, +/* 0x00, 0x0e, 0x35, 0x4f, 0x62, 0x71, 0x7f, 0x8b, + * 0x96, 0xa0, 0xa9, 0xb2, 0xbb, 0xc3, 0xca, 0xd2, + * 0xd8, */ + 0x10, 0x0b, 0x01, 0x10, + 0x10, 0x0d, 0x01, 0x11, + 0x10, 0x0c, 0x01, 0x1c, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; +/* et31x110 - Trust 120 SpaceCam */ +static const u8 spacecam_init[] = { + 0x04, 0x05, 0x01, 0x01, + 0x04, 0x04, 0x01, 0x01, + 0x04, 0x06, 0x01, 0x04, + 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x05, 0x01, 0x00, + 0, 0, 0 +}; +static const u8 spacecam_start[] = { + 0x04, 0x06, 0x01, 0x44, + 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24, + 0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08, + 0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x7c, 0x00, 0x80, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + 0x04, 0x06, 0x01, 0xc0, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, + 0x40, + 0x00, 0x80, 0x01, 0xa0, + 0x10, 0x1a, 0x01, 0x00, + 0x00, 0x91, 0x02, 0x32, 0x01, + 0x00, 0x03, 0x02, 0x08, 0x02, + 0x10, 0x00, 0x01, 0x83, + 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, + 0x20, 0x01, 0x60, 0x01, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x64, 0x99, 0xc0, 0xe2, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x13, 0x13, + 0x10, 0x03, 0x01, 0x06, + 0x10, 0x41, 0x11, 0x00, 0x64, 0x99, 0xc0, 0xe2, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, + 0x10, 0x0b, 0x01, 0x08, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1f, + 0x04, 0x06, 0x01, 0xc3, + 0x04, 0x05, 0x01, 0x40, + 0x04, 0x04, 0x01, 0x40, + 0, 0, 0 +}; +/* et31x110 - pas106 - other Trust SpaceCam120 */ +static const u8 spacecam2_start[] = { + 0x04, 0x06, 0x01, 0x44, + 0x04, 0x06, 0x01, 0x00, + 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc, + 0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03, + 0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00, + 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x04, 0x04, 0x01, 0x40, + 0x04, 0x04, 0x01, 0x00, + I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x05, 0x05, + I2C0, 0x40, 0x02, 0x11, 0x06, + I2C0, 0x40, 0x02, 0x14, 0x00, + I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ + 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, + 0x40, + I2C0, 0x40, 0x02, 0x02, 0x0c, /* pixel clock */ + I2C0, 0x40, 0x02, 0x0f, 0x00, + I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ + 0x10, 0x00, 0x01, 0x01, + 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, + 0x20, 0x01, 0x60, 0x01, + I2C0, 0x40, 0x02, 0x05, 0x0f, /* exposure */ + I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ + I2C0, 0x40, 0x07, 0x09, 0x0b, 0x0f, 0x05, 0x05, 0x0f, 0x00, + /* gains */ + I2C0, 0x40, 0x03, 0x12, 0x04, 0x01, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x13, 0x13, + 0x10, 0x03, 0x01, 0x06, + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x0b, 0x01, 0x11, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x14, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw802 - Conceptronic Video Pro */ +static const u8 cvideopro_start[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4, + 0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, + 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30, + 0x00, 0x80, 0x1f, 0x98, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, + 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0, + 0x40, + 0x10, 0x1a, 0x01, 0x03, + 0x10, 0x00, 0x01, 0xac, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x3b, 0x01, + 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, + 0x10, 0x1f, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x1d, 0x02, 0x40, 0x06, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x46, 0x62, 0x76, 0x86, 0x94, 0xa0, + 0xab, 0xb6, 0xbf, 0xc8, 0xcf, 0xd7, 0xdc, 0xdc, + 0xdc, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x12, 0x12, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x46, 0x62, 0x76, 0x86, 0x94, 0xa0, + 0xab, 0xb6, 0xbf, 0xc8, 0xcf, 0xd7, 0xdc, 0xdc, + 0xdc, + 0x10, 0x0b, 0x01, 0x09, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x2f, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw802 - D-link dru-350c cam */ +static const u8 dlink_start[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x10, 0x00, 0x36, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xc0, 0x00, 0x14, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x00, + 0x10, 0x00, 0x01, 0xad, + 0x00, 0x00, 0x01, 0x08, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x51, 0x00, 0xf0, 0x00, 0x3d, 0x00, 0xb4, 0x00, + 0x10, 0x1d, 0x08, 0x40, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x0e, 0x01, 0x20, + 0x10, 0x41, 0x11, 0x00, 0x07, 0x1e, 0x38, 0x4d, 0x60, 0x70, 0x7f, + 0x8e, 0x9b, 0xa8, 0xb4, 0xbf, 0xca, 0xd5, 0xdf, + 0xea, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x11, 0x11, + 0x10, 0x03, 0x01, 0x10, + 0x10, 0x41, 0x11, 0x00, 0x07, 0x1e, 0x38, 0x4d, 0x60, 0x70, 0x7f, + 0x8e, 0x9b, 0xa8, 0xb4, 0xbf, 0xca, 0xd5, 0xdf, + 0xea, + 0x10, 0x0b, 0x01, 0x19, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1e, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* 06a5:d001 - nw801 - Sony + * Plustek Opticam 500U or ProLink DS3303u (Hitachi HD49322BF) */ +/*fixme: 320x240 only*/ +static const u8 ds3303_start[] = { + 0x05, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x16, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e, + 0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x22, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa9, 0xa8, 0x1f, 0x00, + 0x0d, 0x02, 0x07, 0x00, 0x01, 0x00, 0x19, 0x00, + 0xf2, 0x00, 0x18, 0x06, 0x10, 0x06, 0x10, 0x00, + 0x36, 0x00, + 0x02, 0x00, 0x12, 0x03, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0x50, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x05, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x2f, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x1f, 0x10, 0x08, 0x0a, + 0x0a, 0x51, 0x00, 0xf1, 0x00, 0x3c, 0x00, 0xb4, + 0x00, 0x01, 0x15, 0xfd, 0x07, 0x3d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8c, 0x04, 0x01, 0x20, + 0x02, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, 0xf7, + 0x10, 0x40, 0x40, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, 0x80, + 0x00, 0x2d, 0x46, 0x58, 0x67, 0x74, 0x7f, 0x88, + 0x94, 0x9d, 0xa6, 0xae, 0xb5, 0xbd, 0xc4, 0xcb, + 0xd1, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, + 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, + 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x10, 0x80, 0x22, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x3f, 0x01, + 0x00, 0x00, 0xef, 0x00, 0x02, 0x0a, 0x82, 0x02, + 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, 0x01, + 0xf0, 0x00, + + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x3f, 0x00, 0xf2, 0x8f, 0x81, + 0x40, + 0x10, 0x1a, 0x01, 0x15, + 0x10, 0x00, 0x01, 0x2f, + 0x10, 0x8c, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, + 0x10, 0x26, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x24, 0x02, 0x40, 0x06, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x48, 0x11, 0x00, 0x15, 0x40, 0x67, 0x84, 0x9d, 0xb2, 0xc6, + 0xd6, 0xe7, 0xf6, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x16, 0x16, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x48, 0x11, 0x00, 0x15, 0x40, 0x67, 0x84, 0x9d, 0xb2, 0xc6, + 0xd6, 0xe7, 0xf6, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, + 0x10, 0x0b, 0x01, 0x26, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1c, + 0x05, 0x06, 0x01, 0x03, + 0x05, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* 06a5:d001 - nw802 - Panasonic + * GP-KR651US (Philips TDA8786) */ +static const u8 kr651_start_1[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x48, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4, + 0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, + 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30, + 0x00, 0x80, 0x1f, 0x18, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, + 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0, 0, 0 +}; +static const u8 kr651_start_qvga[] = { + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x03, + 0x10, 0x00, 0x01, 0xac, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x29, 0x00, 0x18, 0x01, 0x1f, 0x00, 0xd2, 0x00, + 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, + 0x10, 0x1d, 0x02, 0x28, 0x01, + 0, 0, 0 +}; +static const u8 kr651_start_vga[] = { + 0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x30, 0x03, 0x01, 0x82, 0x82, 0x98, + 0x80, + 0x10, 0x1a, 0x01, 0x03, + 0x10, 0x00, 0x01, 0xa0, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01, + 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, + 0x10, 0x1d, 0x02, 0x68, 0x00, +}; +static const u8 kr651_start_2[] = { + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x11, 0x3c, 0x5c, 0x74, 0x88, 0x99, 0xa8, + 0xb7, 0xc4, 0xd0, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdc, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x0c, 0x0c, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x11, 0x3c, 0x5c, 0x74, 0x88, 0x99, 0xa8, + 0xb7, 0xc4, 0xd0, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdc, + 0x10, 0x0b, 0x01, 0x10, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x2d, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw802 - iRez Kritter cam */ +static const u8 kritter_start[] = { + 0x04, 0x06, 0x01, 0x06, + 0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0x94, 0x03, 0x18, 0x00, 0x48, + 0x0f, 0x1e, 0x00, 0x0c, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x0b, 0x00, 0x1b, 0x00, 0x0a, 0x01, 0x28, + 0x07, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, + 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x5d, 0x00, 0x0e, 0x00, 0x7e, 0x00, 0x30, + 0x00, 0x80, 0x1f, 0x18, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, + 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0b, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0, + 0x40, + 0x10, 0x1a, 0x01, 0x03, + 0x10, 0x00, 0x01, 0xaf, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x3b, 0x01, + 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, + 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, + 0x10, 0x1d, 0x02, 0x00, 0x00, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x0d, 0x36, 0x4e, 0x60, 0x6f, 0x7b, 0x86, + 0x90, 0x98, 0xa1, 0xa9, 0xb1, 0xb7, 0xbe, 0xc4, + 0xcb, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x0d, 0x0d, + 0x10, 0x03, 0x01, 0x02, + 0x10, 0x41, 0x11, 0x00, 0x0d, 0x36, 0x4e, 0x60, 0x6f, 0x7b, 0x86, + 0x90, 0x98, 0xa1, 0xa9, 0xb1, 0xb7, 0xbe, 0xc4, + 0xcb, + 0x10, 0x0b, 0x01, 0x17, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1e, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw802 - Mustek Wcam 300 mini */ +static const u8 mustek_start[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, + 0x00, 0x10, 0x06, 0xfc, 0x05, 0x0c, 0x06, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xc0, 0x00, 0x14, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x00, + 0x10, 0x00, 0x01, 0xad, + 0x00, 0x00, 0x01, 0x08, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1d, 0x08, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x10, 0x0e, 0x01, 0x0f, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x29, 0x4a, 0x64, 0x7a, 0x8c, 0x9e, + 0xad, 0xba, 0xc7, 0xd3, 0xde, 0xe8, 0xf1, 0xf9, + 0xff, + 0x10, 0x0f, 0x02, 0x11, 0x11, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x29, 0x4a, 0x64, 0x7a, 0x8c, 0x9e, + 0xad, 0xba, 0xc7, 0xd3, 0xde, 0xe8, 0xf1, 0xf9, + 0xff, + 0x10, 0x0b, 0x01, 0x1c, + 0x10, 0x0d, 0x01, 0x1a, + 0x10, 0x0c, 0x01, 0x34, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x40, + 0x04, 0x06, 0x01, 0x03, + 0, 0, 0 +}; + +/* nw802 - Scope USB Microscope M2 (ProScope) (Hitachi HD49322BF) */ +static const u8 proscope_init[] = { + 0x04, 0x05, 0x01, 0x21, + 0x04, 0x04, 0x01, 0x01, + 0, 0, 0 +}; +static const u8 proscope_start_1[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x10, 0x01, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x04, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x08, 0x00, 0x17, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0xce, 0x00, 0xf8, 0x03, 0x3e, 0x00, 0x86, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0xb6, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xf6, 0x03, 0x34, 0x04, 0xf6, 0x03, 0x34, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xe8, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x1f, 0x0f, 0x08, 0x20, 0xa8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x01, 0x00, 0x19, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x10, 0x00, 0x36, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xad, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x1f, 0x10, 0x08, 0x0a, + 0x0a, 0x51, 0x00, 0xf1, 0x00, 0x3c, 0x00, 0xb4, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x8c, 0x04, 0x01, + 0x20, 0x02, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x2d, 0x46, 0x58, 0x67, 0x74, 0x7f, + 0x88, 0x94, 0x9d, 0xa6, 0xae, 0xb5, 0xbd, 0xc4, + 0xcb, 0xd1, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x3f, + 0x01, 0x00, 0x00, 0xef, 0x00, 0x09, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0, 0, 0 +}; +static const u8 proscope_start_qvga[] = { + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x06, + 0x00, 0x03, 0x02, 0xf9, 0x02, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1d, 0x08, 0xc0, 0x0d, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x0e, 0x01, 0x10, + 0, 0, 0 +}; +static const u8 proscope_start_vga[] = { + 0x00, 0x03, 0x02, 0xf9, 0x02, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, + 0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x16, 0x00, 0x00, 0x82, 0x84, 0x00, + 0x80, + 0x10, 0x1a, 0x01, 0x06, + 0x10, 0x00, 0x01, 0xa1, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x1d, 0x08, 0xc0, 0x0d, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, + 0x10, 0x0e, 0x01, 0x10, + 0x10, 0x41, 0x11, 0x00, 0x10, 0x51, 0x6e, 0x83, 0x93, 0xa1, 0xae, + 0xb9, 0xc3, 0xcc, 0xd4, 0xdd, 0xe4, 0xeb, 0xf2, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0, 0, 0 +}; +static const u8 proscope_start_2[] = { + 0x10, 0x0f, 0x02, 0x0c, 0x0c, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x10, 0x51, 0x6e, 0x83, 0x93, 0xa1, 0xae, + 0xb9, 0xc3, 0xcc, 0xd4, 0xdd, 0xe4, 0xeb, 0xf2, + 0xf9, + 0x10, 0x0b, 0x01, 0x0b, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1b, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x05, 0x01, 0x21, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw800 - hv7121b? (seems pas106) - Divio Chicony TwinkleCam */ +static const u8 twinkle_start[] = { + 0x04, 0x06, 0x01, 0x44, + 0x04, 0x06, 0x01, 0x00, + 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc, + 0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03, + 0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00, + 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x08, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x10, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x00, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + + 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x04, 0x04, 0x01, 0x10, + 0x04, 0x04, 0x01, 0x00, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x01, + I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, + I2C0, 0x40, 0x02, 0x11, 0x06, + I2C0, 0x40, 0x02, 0x14, 0x00, + I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ + I2C0, 0x40, 0x02, 0x07, 0x01, + 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, + 0x40, + I2C0, 0x40, 0x02, 0x02, 0x0c, + I2C0, 0x40, 0x02, 0x13, 0x01, + 0x10, 0x00, 0x01, 0x01, + 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, + 0x20, 0x01, 0x60, 0x01, + I2C0, 0x40, 0x02, 0x05, 0x0f, + I2C0, 0x40, 0x02, 0x13, 0x01, + I2C0, 0x40, 0x08, 0x08, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x17, + I2C0, 0x40, 0x03, 0x12, 0x00, 0x01, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + I2C0, 0x40, 0x02, 0x12, 0x00, + I2C0, 0x40, 0x02, 0x0e, 0x00, + I2C0, 0x40, 0x02, 0x11, 0x06, + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x0c, 0x0c, + 0x10, 0x03, 0x01, 0x06, + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x0b, 0x01, 0x19, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x0d, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x41, + 0, 0, 0 +}; + +/* nw802 dvc-v6 */ +static const u8 dvcv6_start[] = { + 0x04, 0x06, 0x01, 0x06, + 0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4, + 0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, + 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30, + 0x00, 0x80, 0x1f, 0x98, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, + 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x00, 0x03, 0x02, 0x94, 0x03, + 0x00, 0x1d, 0x04, 0x0a, 0x01, 0x28, 0x07, + 0x00, 0x7b, 0x02, 0xe0, 0x00, + 0x10, 0x8d, 0x01, 0x00, + 0x00, 0x09, 0x04, 0x1e, 0x00, 0x0c, 0x02, + 0x00, 0x91, 0x02, 0x0b, 0x02, + 0x10, 0x00, 0x01, 0xaf, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8f, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0, + 0x40, + 0x10, 0x1a, 0x01, 0x02, + 0x10, 0x00, 0x01, 0xaf, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x07, 0x01, + 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, + 0x10, 0x1f, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x1d, 0x02, 0x40, 0x06, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x54, 0x6f, 0x82, 0x91, 0x9f, 0xaa, + 0xb4, 0xbd, 0xc5, 0xcd, 0xd5, 0xdb, 0xdc, 0xdc, + 0xdc, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x12, 0x12, + 0x10, 0x03, 0x01, 0x11, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x54, 0x6f, 0x82, 0x91, 0x9f, 0xaa, + 0xb4, 0xbd, 0xc5, 0xcd, 0xd5, 0xdb, 0xdc, 0xdc, + 0xdc, + 0x10, 0x0b, 0x01, 0x16, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1a, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, +}; + +static const u8 *webcam_start[] = { + [Generic800] = nw800_start, + [SpaceCam] = spacecam_start, + [SpaceCam2] = spacecam2_start, + [Cvideopro] = cvideopro_start, + [Dlink350c] = dlink_start, + [DS3303u] = ds3303_start, + [Kr651us] = kr651_start_1, + [Kritter] = kritter_start, + [Mustek300] = mustek_start, + [Proscope] = proscope_start_1, + [Twinkle] = twinkle_start, + [DvcV6] = dvcv6_start, + [P35u] = nw801_start_1, + [Generic802] = nw802_start, +}; + +/* -- write a register -- */ +static void reg_w(struct gspca_dev *gspca_dev, + u16 index, + const u8 *data, + int len) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + if (len == 1) + PDEBUG(D_USBO, "SET 00 0000 %04x %02x", index, *data); + else + PDEBUG(D_USBO, "SET 00 0000 %04x %02x %02x ...", + index, *data, data[1]); + memcpy(gspca_dev->usb_buf, data, len); + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x00, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, /* value */ + index, + gspca_dev->usb_buf, + len, + 500); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* -- read registers in usb_buf -- */ +static void reg_r(struct gspca_dev *gspca_dev, + u16 index, + int len) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, index, + gspca_dev->usb_buf, len, 500); + if (ret < 0) { + err("reg_r err %d", ret); + gspca_dev->usb_err = ret; + return; + } + if (len == 1) + PDEBUG(D_USBI, "GET 00 0000 %04x %02x", + index, gspca_dev->usb_buf[0]); + else + PDEBUG(D_USBI, "GET 00 0000 %04x %02x %02x ..", + index, gspca_dev->usb_buf[0], + gspca_dev->usb_buf[1]); +} + +static void i2c_w(struct gspca_dev *gspca_dev, + u8 i2c_addr, + const u8 *data, + int len) +{ + u8 val[2]; + int i; + + reg_w(gspca_dev, 0x0600, data + 1, len - 1); + reg_w(gspca_dev, 0x0600, data, len); + val[0] = len; + val[1] = i2c_addr; + reg_w(gspca_dev, 0x0502, val, 2); + val[0] = 0x01; + reg_w(gspca_dev, 0x0501, val, 1); + for (i = 5; --i >= 0; ) { + msleep(4); + reg_r(gspca_dev, 0x0505, 1); + if (gspca_dev->usb_err < 0) + return; + if (gspca_dev->usb_buf[0] == 0) + return; + } + gspca_dev->usb_err = -ETIME; +} + +static void reg_w_buf(struct gspca_dev *gspca_dev, + const u8 *cmd) +{ + u16 reg; + int len; + + for (;;) { + reg = *cmd++ << 8; + reg += *cmd++; + len = *cmd++; + if (len == 0) + break; + if (cmd[-3] != I2C0) + reg_w(gspca_dev, reg, cmd, len); + else + i2c_w(gspca_dev, reg, cmd, len); + cmd += len; + } +} + +static int swap_bits(int v) +{ + int r, i; + + r = 0; + for (i = 0; i < 8; i++) { + r <<= 1; + if (v & 1) + r++; + v >>= 1; + } + return r; +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val, v[2]; + + val = sd->ctrls[GAIN].val; + switch (sd->webcam) { + case P35u: + /* Note the control goes from 0-255 not 0-127, but anything + above 127 just means amplifying noise */ + val >>= 1; /* 0 - 255 -> 0 - 127 */ + reg_w(gspca_dev, 0x1026, &val, 1); + break; + case Kr651us: + /* 0 - 253 */ + val = swap_bits(val); + v[0] = val << 3; + v[1] = val >> 5; + reg_w(gspca_dev, 0x101d, v, 2); /* SIF reg0/1 (AGC) */ + break; + } +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + s16 val; + u8 v[2]; + + val = sd->ctrls[EXPOSURE].val; + switch (sd->webcam) { + case P35u: + v[0] = ((9 - val) << 3) | 0x01; + reg_w(gspca_dev, 0x1019, v, 1); + break; + case Cvideopro: + case DvcV6: + case Kritter: + case Kr651us: + v[0] = val; + v[1] = val >> 8; + reg_w(gspca_dev, 0x101b, v, 2); + break; + } +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int w, h; + + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) + return; + if (!sd->ctrls[AUTOGAIN].val) { + sd->ag_cnt = -1; + return; + } + sd->ag_cnt = AG_CNT_START; + + reg_r(gspca_dev, 0x1004, 1); + if (gspca_dev->usb_buf[0] & 0x04) { /* if AE_FULL_FRM */ + sd->ae_res = gspca_dev->width * gspca_dev->height; + } else { /* get the AE window size */ + reg_r(gspca_dev, 0x1011, 8); + w = (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0] + - (gspca_dev->usb_buf[3] << 8) - gspca_dev->usb_buf[2]; + h = (gspca_dev->usb_buf[5] << 8) + gspca_dev->usb_buf[4] + - (gspca_dev->usb_buf[7] << 8) - gspca_dev->usb_buf[6]; + sd->ae_res = h * w; + if (sd->ae_res == 0) + sd->ae_res = gspca_dev->width * gspca_dev->height; + } +} + +static int nw802_test_reg(struct gspca_dev *gspca_dev, + u16 index, + u8 value) +{ + /* write the value */ + reg_w(gspca_dev, index, &value, 1); + + /* read it */ + reg_r(gspca_dev, index, 1); + + return gspca_dev->usb_buf[0] == value; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if ((unsigned) webcam >= NWEBCAMS) + webcam = 0; + sd->webcam = webcam; + gspca_dev->cam.reverse_alts = 1; + gspca_dev->cam.ctrls = sd->ctrls; + sd->ag_cnt = -1; + + /* + * Autodetect sequence inspired from some log. + * We try to detect what registers exist or not. + * If 0x0500 does not exist => NW802 + * If it does, test 0x109b. If it doesn't exist, + * then it's a NW801. Else, a NW800 + * If a et31x110 (nw800 and 06a5:d800) + * get the sensor ID + */ + if (!nw802_test_reg(gspca_dev, 0x0500, 0x55)) { + sd->bridge = BRIDGE_NW802; + if (sd->webcam == Generic800) + sd->webcam = Generic802; + } else if (!nw802_test_reg(gspca_dev, 0x109b, 0xaa)) { + sd->bridge = BRIDGE_NW801; + if (sd->webcam == Generic800) + sd->webcam = P35u; + } else if (id->idVendor == 0x06a5 && id->idProduct == 0xd800) { + reg_r(gspca_dev, 0x0403, 1); /* GPIO */ + PDEBUG(D_PROBE, "et31x110 sensor type %02x", + gspca_dev->usb_buf[0]); + switch (gspca_dev->usb_buf[0] >> 1) { + case 0x00: /* ?? */ + if (sd->webcam == Generic800) + sd->webcam = SpaceCam; + break; + case 0x01: /* Hynix? */ + if (sd->webcam == Generic800) + sd->webcam = Twinkle; + break; + case 0x0a: /* Pixart */ + if (sd->webcam == Generic800) + sd->webcam = SpaceCam2; + break; + } + } + if (webcam_chip[sd->webcam] != sd->bridge) { + err("Bad webcam type %d for NW80%d", sd->webcam, sd->bridge); + gspca_dev->usb_err = -ENODEV; + return gspca_dev->usb_err; + } + PDEBUG(D_PROBE, "Bridge nw80%d - type: %d", sd->bridge, sd->webcam); + + if (sd->bridge == BRIDGE_NW800) { + switch (sd->webcam) { + case DS3303u: + gspca_dev->cam.cam_mode = cif_mode; /* qvga */ + break; + default: + gspca_dev->cam.cam_mode = &cif_mode[1]; /* cif */ + break; + } + gspca_dev->cam.nmodes = 1; + } else { + gspca_dev->cam.cam_mode = vga_mode; + switch (sd->webcam) { + case Kr651us: + case Proscope: + case P35u: + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + break; + default: + gspca_dev->cam.nmodes = 1; /* qvga only */ + break; + } + } + switch (sd->webcam) { + case P35u: +/* sd->ctrls[EXPOSURE].max = 9; + * sd->ctrls[EXPOSURE].def = 9; */ + /* coarse expo auto gain function gain minimum, to avoid + * a large settings jump the first auto adjustment */ + sd->ctrls[GAIN].def = 255 / 5 * 2; + break; + case Cvideopro: + case DvcV6: + case Kritter: + gspca_dev->ctrl_dis = (1 << GAIN) | (1 << AUTOGAIN); + /* fall thru */ + case Kr651us: + sd->ctrls[EXPOSURE].max = 315; + sd->ctrls[EXPOSURE].def = 150; + break; + default: + gspca_dev->ctrl_dis = (1 << GAIN) | (1 << EXPOSURE) + | (1 << AUTOGAIN); + break; + } + +#if AUTOGAIN_DEF + if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN))) + gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); +#endif + return gspca_dev->usb_err; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->bridge) { + case BRIDGE_NW800: + switch (sd->webcam) { + case SpaceCam: + reg_w_buf(gspca_dev, spacecam_init); + break; + default: + reg_w_buf(gspca_dev, nw800_init); + break; + } + break; + default: + switch (sd->webcam) { + case Mustek300: + case P35u: + case Proscope: + reg_w_buf(gspca_dev, proscope_init); + break; + } + break; + } + return gspca_dev->usb_err; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + const u8 *cmd; + + cmd = webcam_start[sd->webcam]; + reg_w_buf(gspca_dev, cmd); + switch (sd->webcam) { + case P35u: + if (gspca_dev->width == 320) + reg_w_buf(gspca_dev, nw801_start_qvga); + else + reg_w_buf(gspca_dev, nw801_start_vga); + reg_w_buf(gspca_dev, nw801_start_2); + break; + case Kr651us: + if (gspca_dev->width == 320) + reg_w_buf(gspca_dev, kr651_start_qvga); + else + reg_w_buf(gspca_dev, kr651_start_vga); + reg_w_buf(gspca_dev, kr651_start_2); + break; + case Proscope: + if (gspca_dev->width == 320) + reg_w_buf(gspca_dev, proscope_start_qvga); + else + reg_w_buf(gspca_dev, proscope_start_vga); + reg_w_buf(gspca_dev, proscope_start_2); + break; + } + + setgain(gspca_dev); + setexposure(gspca_dev); + setautogain(gspca_dev); + sd->exp_too_high_cnt = 0; + sd->exp_too_low_cnt = 0; + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 value; + + /* 'go' off */ + if (sd->bridge != BRIDGE_NW801) { + value = 0x02; + reg_w(gspca_dev, 0x0406, &value, 1); + } + + /* LED off */ + switch (sd->webcam) { + case Cvideopro: + case Kr651us: + case DvcV6: + case Kritter: + value = 0xff; + break; + case Dlink350c: + value = 0x21; + break; + case SpaceCam: + case SpaceCam2: + case Proscope: + case Twinkle: + value = 0x01; + break; + default: + return; + } + reg_w(gspca_dev, 0x0404, &value, 1); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + /* + * frame header = '00 00 hh ww ss xx ff ff' + * with: + * - 'hh': height / 4 + * - 'ww': width / 4 + * - 'ss': frame sequence number c0..dd + */ + if (data[0] == 0x00 && data[1] == 0x00 + && data[6] == 0xff && data[7] == 0xff) { + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, data + 8, len - 8); + } else { + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + } +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[AUTOGAIN].val = val; + if (val) + gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); + else + gspca_dev->ctrl_inac = 0; + if (gspca_dev->streaming) + setautogain(gspca_dev); + return gspca_dev->usb_err; +} + +#include "autogain_functions.h" + +static void do_autogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int luma; + + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt >= 0) + return; + sd->ag_cnt = AG_CNT_START; + + /* get the average luma */ + reg_r(gspca_dev, sd->bridge == BRIDGE_NW801 ? 0x080d : 0x080c, 4); + luma = (gspca_dev->usb_buf[3] << 24) + (gspca_dev->usb_buf[2] << 16) + + (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; + luma /= sd->ae_res; + + switch (sd->webcam) { + case P35u: + coarse_grained_expo_autogain(gspca_dev, luma, 100, 5); + break; + default: + auto_gain_n_exposure(gspca_dev, luma, 100, 5, 230, 0); + break; + } +} + +/* V4L2 controls supported by the driver */ +static const struct ctrl sd_ctrls[NCTRLS] = { +[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 253, + .step = 1, + .default_value = 128 + }, + .set_control = setgain + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 9, + .step = 1, + .default_value = 9 + }, + .set_control = setexposure + }, +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = AUTOGAIN_DEF, + .flags = V4L2_CTRL_FLAG_UPDATE + }, + .set = sd_setautogain + }, +}; + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x046d, 0xd001)}, + {USB_DEVICE(0x0502, 0xd001)}, + {USB_DEVICE(0x052b, 0xd001)}, + {USB_DEVICE(0x055f, 0xd001)}, + {USB_DEVICE(0x06a5, 0x0000)}, + {USB_DEVICE(0x06a5, 0xd001)}, + {USB_DEVICE(0x06a5, 0xd800)}, + {USB_DEVICE(0x06be, 0xd001)}, + {USB_DEVICE(0x0728, 0xd001)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(webcam, int, 0644); +MODULE_PARM_DESC(webcam, + "Webcam type\n" + "0: generic\n" + "1: Trust 120 SpaceCam\n" + "2: other Trust 120 SpaceCam\n" + "3: Conceptronic Video Pro\n" + "4: D-link dru-350c\n" + "5: Plustek Opticam 500U\n" + "6: Panasonic GP-KR651US\n" + "7: iRez Kritter\n" + "8: Mustek Wcam 300 mini\n" + "9: Scalar USB Microscope M2 (Proscope)\n" + "10: Divio Chicony TwinkleCam\n" + "11: DVC-V6\n"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov519.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov519.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov519.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov519.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,5070 @@ +/** + * OV519 driver + * + * Copyright (C) 2008-2011 Jean-François Moine + * Copyright (C) 2009 Hans de Goede + * + * This module is adapted from the ov51x-jpeg package, which itself + * was adapted from the ov511 driver. + * + * Original copyright for the ov511 driver is: + * + * Copyright (c) 1999-2006 Mark W. McClelland + * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach + * Many improvements by Bret Wallach + * Color fixes by by Orion Sky Lawlor (2/26/2000) + * OV7620 fixes by Charl P. Botha + * Changes by Claudio Matsuoka + * + * ov51x-jpeg original copyright is: + * + * Copyright (c) 2004-2007 Romain Beauxis + * Support for OV7670 sensors was contributed by Sam Skipsey + * + * 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, or + * any later version. + * + * 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 + * + */ +#define MODULE_NAME "ov519" + +#include +#include "gspca.h" + +/* The jpeg_hdr is used by w996Xcf only */ +/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */ +#define CONEX_CAM +#include "jpeg.h" + +MODULE_AUTHOR("Jean-Francois Moine "); +MODULE_DESCRIPTION("OV519 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* global parameters */ +static int frame_rate; + +/* Number of times to retry a failed I2C transaction. Increase this if you + * are getting "Failed to read sensor ID..." */ +static int i2c_detect_tries = 10; + +/* controls */ +enum e_ctrl { + BRIGHTNESS, + CONTRAST, + EXPOSURE, + COLORS, + HFLIP, + VFLIP, + AUTOBRIGHT, + AUTOGAIN, + FREQ, + NCTRL /* number of controls */ +}; + +/* ov519 device descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRL]; + + u8 packet_nr; + + char bridge; +#define BRIDGE_OV511 0 +#define BRIDGE_OV511PLUS 1 +#define BRIDGE_OV518 2 +#define BRIDGE_OV518PLUS 3 +#define BRIDGE_OV519 4 /* = ov530 */ +#define BRIDGE_OVFX2 5 +#define BRIDGE_W9968CF 6 +#define BRIDGE_MASK 7 + + char invert_led; +#define BRIDGE_INVERT_LED 8 + + char snapshot_pressed; + char snapshot_needs_reset; + + /* Determined by sensor type */ + u8 sif; + + u8 quality; +#define QUALITY_MIN 50 +#define QUALITY_MAX 70 +#define QUALITY_DEF 50 + + u8 stopped; /* Streaming is temporarily paused */ + u8 first_frame; + + u8 frame_rate; /* current Framerate */ + u8 clockdiv; /* clockdiv override */ + + s8 sensor; /* Type of image sensor chip (SEN_*) */ + + u8 sensor_addr; + u16 sensor_width; + u16 sensor_height; + s16 sensor_reg_cache[256]; + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; +enum sensors { + SEN_OV2610, + SEN_OV2610AE, + SEN_OV3610, + SEN_OV6620, + SEN_OV6630, + SEN_OV66308AF, + SEN_OV7610, + SEN_OV7620, + SEN_OV7620AE, + SEN_OV7640, + SEN_OV7648, + SEN_OV7660, + SEN_OV7670, + SEN_OV76BE, + SEN_OV8610, + SEN_OV9600, +}; + +/* Note this is a bit of a hack, but the w9968cf driver needs the code for all + the ov sensors which is already present here. When we have the time we + really should move the sensor drivers to v4l2 sub drivers. */ +#include "w996Xcf.c" + +/* V4L2 controls supported by the driver */ +static void setbrightness(struct gspca_dev *gspca_dev); +static void setcontrast(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static void setcolors(struct gspca_dev *gspca_dev); +static void sethvflip(struct gspca_dev *gspca_dev); +static void setautobright(struct gspca_dev *gspca_dev); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static void setfreq(struct gspca_dev *gspca_dev); +static void setfreq_i(struct sd *sd); + +static const struct ctrl sd_ctrls[] = { +[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set_control = setbrightness, + }, +[CONTRAST] = { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set_control = setcontrast, + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set_control = setexposure, + }, +[COLORS] = { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set_control = setcolors, + }, +/* The flip controls work for sensors ov7660 and ov7670 only */ +[HFLIP] = { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set_control = sethvflip, + }, +[VFLIP] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set_control = sethvflip, + }, +[AUTOBRIGHT] = { + { + .id = V4L2_CID_AUTOBRIGHTNESS, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Brightness", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set_control = setautobright, + }, +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = V4L2_CTRL_FLAG_UPDATE + }, + .set = sd_setautogain, + }, +[FREQ] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: no flicker, 1: 50Hz, 2:60Hz, 3: auto */ + .step = 1, + .default_value = 0, + }, + .set_control = setfreq, + }, +}; + +/* table of the disabled controls */ +static const unsigned ctrl_dis[] = { +[SEN_OV2610] = ((1 << NCTRL) - 1) /* no control */ + ^ ((1 << EXPOSURE) /* but exposure */ + | (1 << AUTOGAIN)), /* and autogain */ + +[SEN_OV2610AE] = ((1 << NCTRL) - 1) /* no control */ + ^ ((1 << EXPOSURE) /* but exposure */ + | (1 << AUTOGAIN)), /* and autogain */ + +[SEN_OV3610] = (1 << NCTRL) - 1, /* no control */ + +[SEN_OV6620] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV6630] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV66308AF] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV7610] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV7620] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV7620AE] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV7640] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << AUTOBRIGHT) | + (1 << CONTRAST) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV7648] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << AUTOBRIGHT) | + (1 << CONTRAST) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV7660] = (1 << AUTOBRIGHT) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV7670] = (1 << COLORS) | + (1 << AUTOBRIGHT) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV76BE] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), + +[SEN_OV8610] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN) | + (1 << FREQ), +[SEN_OV9600] = ((1 << NCTRL) - 1) /* no control */ + ^ ((1 << EXPOSURE) /* but exposure */ + | (1 << AUTOGAIN)), /* and autogain */ + +}; + +static const struct v4l2_pix_format ov519_vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; +static const struct v4l2_pix_format ov519_sif_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* Note some of the sizeimage values for the ov511 / ov518 may seem + larger then necessary, however they need to be this big as the ov511 / + ov518 always fills the entire isoc frame, using 0 padding bytes when + it doesn't have any data. So with low framerates the amount of data + transferred can become quite large (libv4l will remove all the 0 padding + in userspace). */ +static const struct v4l2_pix_format ov518_vga_mode[] = { + {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; +static const struct v4l2_pix_format ov518_sif_mode[] = { + {160, 120, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 70000, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 70000, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static const struct v4l2_pix_format ov511_vga_mode[] = { + {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; +static const struct v4l2_pix_format ov511_sif_mode[] = { + {160, 120, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 70000, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 70000, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static const struct v4l2_pix_format ovfx2_vga_mode[] = { + {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; +static const struct v4l2_pix_format ovfx2_cif_mode[] = { + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; +static const struct v4l2_pix_format ovfx2_ov2610_mode[] = { + {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 600, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 1600, + .sizeimage = 1600 * 1200, + .colorspace = V4L2_COLORSPACE_SRGB}, +}; +static const struct v4l2_pix_format ovfx2_ov3610_mode[] = { + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 600, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 1024, + .sizeimage = 1024 * 768, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 1600, + .sizeimage = 1600 * 1200, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + {2048, 1536, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 2048, + .sizeimage = 2048 * 1536, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; +static const struct v4l2_pix_format ovfx2_ov9600_mode[] = { + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024, + .colorspace = V4L2_COLORSPACE_SRGB}, +}; + +/* Registers common to OV511 / OV518 */ +#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ +#define R51x_SYS_RESET 0x50 + /* Reset type flags */ + #define OV511_RESET_OMNICE 0x08 +#define R51x_SYS_INIT 0x53 +#define R51x_SYS_SNAP 0x52 +#define R51x_SYS_CUST_ID 0x5f +#define R51x_COMP_LUT_BEGIN 0x80 + +/* OV511 Camera interface register numbers */ +#define R511_CAM_DELAY 0x10 +#define R511_CAM_EDGE 0x11 +#define R511_CAM_PXCNT 0x12 +#define R511_CAM_LNCNT 0x13 +#define R511_CAM_PXDIV 0x14 +#define R511_CAM_LNDIV 0x15 +#define R511_CAM_UV_EN 0x16 +#define R511_CAM_LINE_MODE 0x17 +#define R511_CAM_OPTS 0x18 + +#define R511_SNAP_FRAME 0x19 +#define R511_SNAP_PXCNT 0x1a +#define R511_SNAP_LNCNT 0x1b +#define R511_SNAP_PXDIV 0x1c +#define R511_SNAP_LNDIV 0x1d +#define R511_SNAP_UV_EN 0x1e +#define R511_SNAP_OPTS 0x1f + +#define R511_DRAM_FLOW_CTL 0x20 +#define R511_FIFO_OPTS 0x31 +#define R511_I2C_CTL 0x40 +#define R511_SYS_LED_CTL 0x55 /* OV511+ only */ +#define R511_COMP_EN 0x78 +#define R511_COMP_LUT_EN 0x79 + +/* OV518 Camera interface register numbers */ +#define R518_GPIO_OUT 0x56 /* OV518(+) only */ +#define R518_GPIO_CTL 0x57 /* OV518(+) only */ + +/* OV519 Camera interface register numbers */ +#define OV519_R10_H_SIZE 0x10 +#define OV519_R11_V_SIZE 0x11 +#define OV519_R12_X_OFFSETL 0x12 +#define OV519_R13_X_OFFSETH 0x13 +#define OV519_R14_Y_OFFSETL 0x14 +#define OV519_R15_Y_OFFSETH 0x15 +#define OV519_R16_DIVIDER 0x16 +#define OV519_R20_DFR 0x20 +#define OV519_R25_FORMAT 0x25 + +/* OV519 System Controller register numbers */ +#define OV519_R51_RESET1 0x51 +#define OV519_R54_EN_CLK1 0x54 +#define OV519_R57_SNAPSHOT 0x57 + +#define OV519_GPIO_DATA_OUT0 0x71 +#define OV519_GPIO_IO_CTRL0 0x72 + +/*#define OV511_ENDPOINT_ADDRESS 1 * Isoc endpoint number */ + +/* + * The FX2 chip does not give us a zero length read at end of frame. + * It does, however, give a short read at the end of a frame, if + * necessary, rather than run two frames together. + * + * By choosing the right bulk transfer size, we are guaranteed to always + * get a short read for the last read of each frame. Frame sizes are + * always a composite number (width * height, or a multiple) so if we + * choose a prime number, we are guaranteed that the last read of a + * frame will be short. + * + * But it isn't that easy: the 2.6 kernel requires a multiple of 4KB, + * otherwise EOVERFLOW "babbling" errors occur. I have not been able + * to figure out why. [PMiller] + * + * The constant (13 * 4096) is the largest "prime enough" number less than 64KB. + * + * It isn't enough to know the number of bytes per frame, in case we + * have data dropouts or buffer overruns (even though the FX2 double + * buffers, there are some pretty strict real time constraints for + * isochronous transfer for larger frame sizes). + */ +/*jfm: this value does not work for 800x600 - see isoc_init */ +#define OVFX2_BULK_SIZE (13 * 4096) + +/* I2C registers */ +#define R51x_I2C_W_SID 0x41 +#define R51x_I2C_SADDR_3 0x42 +#define R51x_I2C_SADDR_2 0x43 +#define R51x_I2C_R_SID 0x44 +#define R51x_I2C_DATA 0x45 +#define R518_I2C_CTL 0x47 /* OV518(+) only */ +#define OVFX2_I2C_ADDR 0x00 + +/* I2C ADDRESSES */ +#define OV7xx0_SID 0x42 +#define OV_HIRES_SID 0x60 /* OV9xxx / OV2xxx / OV3xxx */ +#define OV8xx0_SID 0xa0 +#define OV6xx0_SID 0xc0 + +/* OV7610 registers */ +#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ +#define OV7610_REG_BLUE 0x01 /* blue channel balance */ +#define OV7610_REG_RED 0x02 /* red channel balance */ +#define OV7610_REG_SAT 0x03 /* saturation */ +#define OV8610_REG_HUE 0x04 /* 04 reserved */ +#define OV7610_REG_CNT 0x05 /* Y contrast */ +#define OV7610_REG_BRT 0x06 /* Y brightness */ +#define OV7610_REG_COM_C 0x14 /* misc common regs */ +#define OV7610_REG_ID_HIGH 0x1c /* manufacturer ID MSB */ +#define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */ +#define OV7610_REG_COM_I 0x29 /* misc settings */ + +/* OV7660 and OV7670 registers */ +#define OV7670_R00_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ +#define OV7670_R01_BLUE 0x01 /* blue gain */ +#define OV7670_R02_RED 0x02 /* red gain */ +#define OV7670_R03_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ +#define OV7670_R04_COM1 0x04 /* Control 1 */ +/*#define OV7670_R07_AECHH 0x07 * AEC MS 5 bits */ +#define OV7670_R0C_COM3 0x0c /* Control 3 */ +#define OV7670_R0D_COM4 0x0d /* Control 4 */ +#define OV7670_R0E_COM5 0x0e /* All "reserved" */ +#define OV7670_R0F_COM6 0x0f /* Control 6 */ +#define OV7670_R10_AECH 0x10 /* More bits of AEC value */ +#define OV7670_R11_CLKRC 0x11 /* Clock control */ +#define OV7670_R12_COM7 0x12 /* Control 7 */ +#define OV7670_COM7_FMT_VGA 0x00 +/*#define OV7670_COM7_YUV 0x00 * YUV */ +#define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */ +#define OV7670_COM7_FMT_MASK 0x38 +#define OV7670_COM7_RESET 0x80 /* Register reset */ +#define OV7670_R13_COM8 0x13 /* Control 8 */ +#define OV7670_COM8_AEC 0x01 /* Auto exposure enable */ +#define OV7670_COM8_AWB 0x02 /* White balance enable */ +#define OV7670_COM8_AGC 0x04 /* Auto gain enable */ +#define OV7670_COM8_BFILT 0x20 /* Band filter enable */ +#define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */ +#define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ +#define OV7670_R14_COM9 0x14 /* Control 9 - gain ceiling */ +#define OV7670_R15_COM10 0x15 /* Control 10 */ +#define OV7670_R17_HSTART 0x17 /* Horiz start high bits */ +#define OV7670_R18_HSTOP 0x18 /* Horiz stop high bits */ +#define OV7670_R19_VSTART 0x19 /* Vert start high bits */ +#define OV7670_R1A_VSTOP 0x1a /* Vert stop high bits */ +#define OV7670_R1E_MVFP 0x1e /* Mirror / vflip */ +#define OV7670_MVFP_VFLIP 0x10 /* vertical flip */ +#define OV7670_MVFP_MIRROR 0x20 /* Mirror image */ +#define OV7670_R24_AEW 0x24 /* AGC upper limit */ +#define OV7670_R25_AEB 0x25 /* AGC lower limit */ +#define OV7670_R26_VPT 0x26 /* AGC/AEC fast mode op region */ +#define OV7670_R32_HREF 0x32 /* HREF pieces */ +#define OV7670_R3A_TSLB 0x3a /* lots of stuff */ +#define OV7670_R3B_COM11 0x3b /* Control 11 */ +#define OV7670_COM11_EXP 0x02 +#define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ +#define OV7670_R3C_COM12 0x3c /* Control 12 */ +#define OV7670_R3D_COM13 0x3d /* Control 13 */ +#define OV7670_COM13_GAMMA 0x80 /* Gamma enable */ +#define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */ +#define OV7670_R3E_COM14 0x3e /* Control 14 */ +#define OV7670_R3F_EDGE 0x3f /* Edge enhancement factor */ +#define OV7670_R40_COM15 0x40 /* Control 15 */ +/*#define OV7670_COM15_R00FF 0xc0 * 00 to FF */ +#define OV7670_R41_COM16 0x41 /* Control 16 */ +#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */ +/* end of ov7660 common registers */ +#define OV7670_R55_BRIGHT 0x55 /* Brightness */ +#define OV7670_R56_CONTRAS 0x56 /* Contrast control */ +#define OV7670_R69_GFIX 0x69 /* Fix gain control */ +/*#define OV7670_R8C_RGB444 0x8c * RGB 444 control */ +#define OV7670_R9F_HAECC1 0x9f /* Hist AEC/AGC control 1 */ +#define OV7670_RA0_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ +#define OV7670_RA5_BD50MAX 0xa5 /* 50hz banding step limit */ +#define OV7670_RA6_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ +#define OV7670_RA7_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ +#define OV7670_RA8_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ +#define OV7670_RA9_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ +#define OV7670_RAA_HAECC7 0xaa /* Hist AEC/AGC control 7 */ +#define OV7670_RAB_BD60MAX 0xab /* 60hz banding step limit */ + +struct ov_regvals { + u8 reg; + u8 val; +}; +struct ov_i2c_regvals { + u8 reg; + u8 val; +}; + +/* Settings for OV2610 camera chip */ +static const struct ov_i2c_regvals norm_2610[] = { + { 0x12, 0x80 }, /* reset */ +}; + +static const struct ov_i2c_regvals norm_2610ae[] = { + {0x12, 0x80}, /* reset */ + {0x13, 0xcd}, + {0x09, 0x01}, + {0x0d, 0x00}, + {0x11, 0x80}, + {0x12, 0x20}, /* 1600x1200 */ + {0x33, 0x0c}, + {0x35, 0x90}, + {0x36, 0x37}, +/* ms-win traces */ + {0x11, 0x83}, /* clock / 3 ? */ + {0x2d, 0x00}, /* 60 Hz filter */ + {0x24, 0xb0}, /* normal colors */ + {0x25, 0x90}, + {0x10, 0x43}, +}; + +static const struct ov_i2c_regvals norm_3620b[] = { + /* + * From the datasheet: "Note that after writing to register COMH + * (0x12) to change the sensor mode, registers related to the + * sensor’s cropping window will be reset back to their default + * values." + * + * "wait 4096 external clock ... to make sure the sensor is + * stable and ready to access registers" i.e. 160us at 24MHz + */ + { 0x12, 0x80 }, /* COMH reset */ + { 0x12, 0x00 }, /* QXGA, master */ + + /* + * 11 CLKRC "Clock Rate Control" + * [7] internal frequency doublers: on + * [6] video port mode: master + * [5:0] clock divider: 1 + */ + { 0x11, 0x80 }, + + /* + * 13 COMI "Common Control I" + * = 192 (0xC0) 11000000 + * COMI[7] "AEC speed selection" + * = 1 (0x01) 1....... "Faster AEC correction" + * COMI[6] "AEC speed step selection" + * = 1 (0x01) .1...... "Big steps, fast" + * COMI[5] "Banding filter on off" + * = 0 (0x00) ..0..... "Off" + * COMI[4] "Banding filter option" + * = 0 (0x00) ...0.... "Main clock is 48 MHz and + * the PLL is ON" + * COMI[3] "Reserved" + * = 0 (0x00) ....0... + * COMI[2] "AGC auto manual control selection" + * = 0 (0x00) .....0.. "Manual" + * COMI[1] "AWB auto manual control selection" + * = 0 (0x00) ......0. "Manual" + * COMI[0] "Exposure control" + * = 0 (0x00) .......0 "Manual" + */ + { 0x13, 0xc0 }, + + /* + * 09 COMC "Common Control C" + * = 8 (0x08) 00001000 + * COMC[7:5] "Reserved" + * = 0 (0x00) 000..... + * COMC[4] "Sleep Mode Enable" + * = 0 (0x00) ...0.... "Normal mode" + * COMC[3:2] "Sensor sampling reset timing selection" + * = 2 (0x02) ....10.. "Longer reset time" + * COMC[1:0] "Output drive current select" + * = 0 (0x00) ......00 "Weakest" + */ + { 0x09, 0x08 }, + + /* + * 0C COMD "Common Control D" + * = 8 (0x08) 00001000 + * COMD[7] "Reserved" + * = 0 (0x00) 0....... + * COMD[6] "Swap MSB and LSB at the output port" + * = 0 (0x00) .0...... "False" + * COMD[5:3] "Reserved" + * = 1 (0x01) ..001... + * COMD[2] "Output Average On Off" + * = 0 (0x00) .....0.. "Output Normal" + * COMD[1] "Sensor precharge voltage selection" + * = 0 (0x00) ......0. "Selects internal + * reference precharge + * voltage" + * COMD[0] "Snapshot option" + * = 0 (0x00) .......0 "Enable live video output + * after snapshot sequence" + */ + { 0x0c, 0x08 }, + + /* + * 0D COME "Common Control E" + * = 161 (0xA1) 10100001 + * COME[7] "Output average option" + * = 1 (0x01) 1....... "Output average of 4 pixels" + * COME[6] "Anti-blooming control" + * = 0 (0x00) .0...... "Off" + * COME[5:3] "Reserved" + * = 4 (0x04) ..100... + * COME[2] "Clock output power down pin status" + * = 0 (0x00) .....0.. "Tri-state data output pin + * on power down" + * COME[1] "Data output pin status selection at power down" + * = 0 (0x00) ......0. "Tri-state VSYNC, PCLK, + * HREF, and CHSYNC pins on + * power down" + * COME[0] "Auto zero circuit select" + * = 1 (0x01) .......1 "On" + */ + { 0x0d, 0xa1 }, + + /* + * 0E COMF "Common Control F" + * = 112 (0x70) 01110000 + * COMF[7] "System clock selection" + * = 0 (0x00) 0....... "Use 24 MHz system clock" + * COMF[6:4] "Reserved" + * = 7 (0x07) .111.... + * COMF[3] "Manual auto negative offset canceling selection" + * = 0 (0x00) ....0... "Auto detect negative + * offset and cancel it" + * COMF[2:0] "Reserved" + * = 0 (0x00) .....000 + */ + { 0x0e, 0x70 }, + + /* + * 0F COMG "Common Control G" + * = 66 (0x42) 01000010 + * COMG[7] "Optical black output selection" + * = 0 (0x00) 0....... "Disable" + * COMG[6] "Black level calibrate selection" + * = 1 (0x01) .1...... "Use optical black pixels + * to calibrate" + * COMG[5:4] "Reserved" + * = 0 (0x00) ..00.... + * COMG[3] "Channel offset adjustment" + * = 0 (0x00) ....0... "Disable offset adjustment" + * COMG[2] "ADC black level calibration option" + * = 0 (0x00) .....0.. "Use B/G line and G/R + * line to calibrate each + * channel's black level" + * COMG[1] "Reserved" + * = 1 (0x01) ......1. + * COMG[0] "ADC black level calibration enable" + * = 0 (0x00) .......0 "Disable" + */ + { 0x0f, 0x42 }, + + /* + * 14 COMJ "Common Control J" + * = 198 (0xC6) 11000110 + * COMJ[7:6] "AGC gain ceiling" + * = 3 (0x03) 11...... "8x" + * COMJ[5:4] "Reserved" + * = 0 (0x00) ..00.... + * COMJ[3] "Auto banding filter" + * = 0 (0x00) ....0... "Banding filter is always + * on off depending on + * COMI[5] setting" + * COMJ[2] "VSYNC drop option" + * = 1 (0x01) .....1.. "SYNC is dropped if frame + * data is dropped" + * COMJ[1] "Frame data drop" + * = 1 (0x01) ......1. "Drop frame data if + * exposure is not within + * tolerance. In AEC mode, + * data is normally dropped + * when data is out of + * range." + * COMJ[0] "Reserved" + * = 0 (0x00) .......0 + */ + { 0x14, 0xc6 }, + + /* + * 15 COMK "Common Control K" + * = 2 (0x02) 00000010 + * COMK[7] "CHSYNC pin output swap" + * = 0 (0x00) 0....... "CHSYNC" + * COMK[6] "HREF pin output swap" + * = 0 (0x00) .0...... "HREF" + * COMK[5] "PCLK output selection" + * = 0 (0x00) ..0..... "PCLK always output" + * COMK[4] "PCLK edge selection" + * = 0 (0x00) ...0.... "Data valid on falling edge" + * COMK[3] "HREF output polarity" + * = 0 (0x00) ....0... "positive" + * COMK[2] "Reserved" + * = 0 (0x00) .....0.. + * COMK[1] "VSYNC polarity" + * = 1 (0x01) ......1. "negative" + * COMK[0] "HSYNC polarity" + * = 0 (0x00) .......0 "positive" + */ + { 0x15, 0x02 }, + + /* + * 33 CHLF "Current Control" + * = 9 (0x09) 00001001 + * CHLF[7:6] "Sensor current control" + * = 0 (0x00) 00...... + * CHLF[5] "Sensor current range control" + * = 0 (0x00) ..0..... "normal range" + * CHLF[4] "Sensor current" + * = 0 (0x00) ...0.... "normal current" + * CHLF[3] "Sensor buffer current control" + * = 1 (0x01) ....1... "half current" + * CHLF[2] "Column buffer current control" + * = 0 (0x00) .....0.. "normal current" + * CHLF[1] "Analog DSP current control" + * = 0 (0x00) ......0. "normal current" + * CHLF[1] "ADC current control" + * = 0 (0x00) ......0. "normal current" + */ + { 0x33, 0x09 }, + + /* + * 34 VBLM "Blooming Control" + * = 80 (0x50) 01010000 + * VBLM[7] "Hard soft reset switch" + * = 0 (0x00) 0....... "Hard reset" + * VBLM[6:4] "Blooming voltage selection" + * = 5 (0x05) .101.... + * VBLM[3:0] "Sensor current control" + * = 0 (0x00) ....0000 + */ + { 0x34, 0x50 }, + + /* + * 36 VCHG "Sensor Precharge Voltage Control" + * = 0 (0x00) 00000000 + * VCHG[7] "Reserved" + * = 0 (0x00) 0....... + * VCHG[6:4] "Sensor precharge voltage control" + * = 0 (0x00) .000.... + * VCHG[3:0] "Sensor array common reference" + * = 0 (0x00) ....0000 + */ + { 0x36, 0x00 }, + + /* + * 37 ADC "ADC Reference Control" + * = 4 (0x04) 00000100 + * ADC[7:4] "Reserved" + * = 0 (0x00) 0000.... + * ADC[3] "ADC input signal range" + * = 0 (0x00) ....0... "Input signal 1.0x" + * ADC[2:0] "ADC range control" + * = 4 (0x04) .....100 + */ + { 0x37, 0x04 }, + + /* + * 38 ACOM "Analog Common Ground" + * = 82 (0x52) 01010010 + * ACOM[7] "Analog gain control" + * = 0 (0x00) 0....... "Gain 1x" + * ACOM[6] "Analog black level calibration" + * = 1 (0x01) .1...... "On" + * ACOM[5:0] "Reserved" + * = 18 (0x12) ..010010 + */ + { 0x38, 0x52 }, + + /* + * 3A FREFA "Internal Reference Adjustment" + * = 0 (0x00) 00000000 + * FREFA[7:0] "Range" + * = 0 (0x00) 00000000 + */ + { 0x3a, 0x00 }, + + /* + * 3C FVOPT "Internal Reference Adjustment" + * = 31 (0x1F) 00011111 + * FVOPT[7:0] "Range" + * = 31 (0x1F) 00011111 + */ + { 0x3c, 0x1f }, + + /* + * 44 Undocumented = 0 (0x00) 00000000 + * 44[7:0] "It's a secret" + * = 0 (0x00) 00000000 + */ + { 0x44, 0x00 }, + + /* + * 40 Undocumented = 0 (0x00) 00000000 + * 40[7:0] "It's a secret" + * = 0 (0x00) 00000000 + */ + { 0x40, 0x00 }, + + /* + * 41 Undocumented = 0 (0x00) 00000000 + * 41[7:0] "It's a secret" + * = 0 (0x00) 00000000 + */ + { 0x41, 0x00 }, + + /* + * 42 Undocumented = 0 (0x00) 00000000 + * 42[7:0] "It's a secret" + * = 0 (0x00) 00000000 + */ + { 0x42, 0x00 }, + + /* + * 43 Undocumented = 0 (0x00) 00000000 + * 43[7:0] "It's a secret" + * = 0 (0x00) 00000000 + */ + { 0x43, 0x00 }, + + /* + * 45 Undocumented = 128 (0x80) 10000000 + * 45[7:0] "It's a secret" + * = 128 (0x80) 10000000 + */ + { 0x45, 0x80 }, + + /* + * 48 Undocumented = 192 (0xC0) 11000000 + * 48[7:0] "It's a secret" + * = 192 (0xC0) 11000000 + */ + { 0x48, 0xc0 }, + + /* + * 49 Undocumented = 25 (0x19) 00011001 + * 49[7:0] "It's a secret" + * = 25 (0x19) 00011001 + */ + { 0x49, 0x19 }, + + /* + * 4B Undocumented = 128 (0x80) 10000000 + * 4B[7:0] "It's a secret" + * = 128 (0x80) 10000000 + */ + { 0x4b, 0x80 }, + + /* + * 4D Undocumented = 196 (0xC4) 11000100 + * 4D[7:0] "It's a secret" + * = 196 (0xC4) 11000100 + */ + { 0x4d, 0xc4 }, + + /* + * 35 VREF "Reference Voltage Control" + * = 76 (0x4c) 01001100 + * VREF[7:5] "Column high reference control" + * = 2 (0x02) 010..... "higher voltage" + * VREF[4:2] "Column low reference control" + * = 3 (0x03) ...011.. "Highest voltage" + * VREF[1:0] "Reserved" + * = 0 (0x00) ......00 + */ + { 0x35, 0x4c }, + + /* + * 3D Undocumented = 0 (0x00) 00000000 + * 3D[7:0] "It's a secret" + * = 0 (0x00) 00000000 + */ + { 0x3d, 0x00 }, + + /* + * 3E Undocumented = 0 (0x00) 00000000 + * 3E[7:0] "It's a secret" + * = 0 (0x00) 00000000 + */ + { 0x3e, 0x00 }, + + /* + * 3B FREFB "Internal Reference Adjustment" + * = 24 (0x18) 00011000 + * FREFB[7:0] "Range" + * = 24 (0x18) 00011000 + */ + { 0x3b, 0x18 }, + + /* + * 33 CHLF "Current Control" + * = 25 (0x19) 00011001 + * CHLF[7:6] "Sensor current control" + * = 0 (0x00) 00...... + * CHLF[5] "Sensor current range control" + * = 0 (0x00) ..0..... "normal range" + * CHLF[4] "Sensor current" + * = 1 (0x01) ...1.... "double current" + * CHLF[3] "Sensor buffer current control" + * = 1 (0x01) ....1... "half current" + * CHLF[2] "Column buffer current control" + * = 0 (0x00) .....0.. "normal current" + * CHLF[1] "Analog DSP current control" + * = 0 (0x00) ......0. "normal current" + * CHLF[1] "ADC current control" + * = 0 (0x00) ......0. "normal current" + */ + { 0x33, 0x19 }, + + /* + * 34 VBLM "Blooming Control" + * = 90 (0x5A) 01011010 + * VBLM[7] "Hard soft reset switch" + * = 0 (0x00) 0....... "Hard reset" + * VBLM[6:4] "Blooming voltage selection" + * = 5 (0x05) .101.... + * VBLM[3:0] "Sensor current control" + * = 10 (0x0A) ....1010 + */ + { 0x34, 0x5a }, + + /* + * 3B FREFB "Internal Reference Adjustment" + * = 0 (0x00) 00000000 + * FREFB[7:0] "Range" + * = 0 (0x00) 00000000 + */ + { 0x3b, 0x00 }, + + /* + * 33 CHLF "Current Control" + * = 9 (0x09) 00001001 + * CHLF[7:6] "Sensor current control" + * = 0 (0x00) 00...... + * CHLF[5] "Sensor current range control" + * = 0 (0x00) ..0..... "normal range" + * CHLF[4] "Sensor current" + * = 0 (0x00) ...0.... "normal current" + * CHLF[3] "Sensor buffer current control" + * = 1 (0x01) ....1... "half current" + * CHLF[2] "Column buffer current control" + * = 0 (0x00) .....0.. "normal current" + * CHLF[1] "Analog DSP current control" + * = 0 (0x00) ......0. "normal current" + * CHLF[1] "ADC current control" + * = 0 (0x00) ......0. "normal current" + */ + { 0x33, 0x09 }, + + /* + * 34 VBLM "Blooming Control" + * = 80 (0x50) 01010000 + * VBLM[7] "Hard soft reset switch" + * = 0 (0x00) 0....... "Hard reset" + * VBLM[6:4] "Blooming voltage selection" + * = 5 (0x05) .101.... + * VBLM[3:0] "Sensor current control" + * = 0 (0x00) ....0000 + */ + { 0x34, 0x50 }, + + /* + * 12 COMH "Common Control H" + * = 64 (0x40) 01000000 + * COMH[7] "SRST" + * = 0 (0x00) 0....... "No-op" + * COMH[6:4] "Resolution selection" + * = 4 (0x04) .100.... "XGA" + * COMH[3] "Master slave selection" + * = 0 (0x00) ....0... "Master mode" + * COMH[2] "Internal B/R channel option" + * = 0 (0x00) .....0.. "B/R use same channel" + * COMH[1] "Color bar test pattern" + * = 0 (0x00) ......0. "Off" + * COMH[0] "Reserved" + * = 0 (0x00) .......0 + */ + { 0x12, 0x40 }, + + /* + * 17 HREFST "Horizontal window start" + * = 31 (0x1F) 00011111 + * HREFST[7:0] "Horizontal window start, 8 MSBs" + * = 31 (0x1F) 00011111 + */ + { 0x17, 0x1f }, + + /* + * 18 HREFEND "Horizontal window end" + * = 95 (0x5F) 01011111 + * HREFEND[7:0] "Horizontal Window End, 8 MSBs" + * = 95 (0x5F) 01011111 + */ + { 0x18, 0x5f }, + + /* + * 19 VSTRT "Vertical window start" + * = 0 (0x00) 00000000 + * VSTRT[7:0] "Vertical Window Start, 8 MSBs" + * = 0 (0x00) 00000000 + */ + { 0x19, 0x00 }, + + /* + * 1A VEND "Vertical window end" + * = 96 (0x60) 01100000 + * VEND[7:0] "Vertical Window End, 8 MSBs" + * = 96 (0x60) 01100000 + */ + { 0x1a, 0x60 }, + + /* + * 32 COMM "Common Control M" + * = 18 (0x12) 00010010 + * COMM[7:6] "Pixel clock divide option" + * = 0 (0x00) 00...... "/1" + * COMM[5:3] "Horizontal window end position, 3 LSBs" + * = 2 (0x02) ..010... + * COMM[2:0] "Horizontal window start position, 3 LSBs" + * = 2 (0x02) .....010 + */ + { 0x32, 0x12 }, + + /* + * 03 COMA "Common Control A" + * = 74 (0x4A) 01001010 + * COMA[7:4] "AWB Update Threshold" + * = 4 (0x04) 0100.... + * COMA[3:2] "Vertical window end line control 2 LSBs" + * = 2 (0x02) ....10.. + * COMA[1:0] "Vertical window start line control 2 LSBs" + * = 2 (0x02) ......10 + */ + { 0x03, 0x4a }, + + /* + * 11 CLKRC "Clock Rate Control" + * = 128 (0x80) 10000000 + * CLKRC[7] "Internal frequency doublers on off seclection" + * = 1 (0x01) 1....... "On" + * CLKRC[6] "Digital video master slave selection" + * = 0 (0x00) .0...... "Master mode, sensor + * provides PCLK" + * CLKRC[5:0] "Clock divider { CLK = PCLK/(1+CLKRC[5:0]) }" + * = 0 (0x00) ..000000 + */ + { 0x11, 0x80 }, + + /* + * 12 COMH "Common Control H" + * = 0 (0x00) 00000000 + * COMH[7] "SRST" + * = 0 (0x00) 0....... "No-op" + * COMH[6:4] "Resolution selection" + * = 0 (0x00) .000.... "QXGA" + * COMH[3] "Master slave selection" + * = 0 (0x00) ....0... "Master mode" + * COMH[2] "Internal B/R channel option" + * = 0 (0x00) .....0.. "B/R use same channel" + * COMH[1] "Color bar test pattern" + * = 0 (0x00) ......0. "Off" + * COMH[0] "Reserved" + * = 0 (0x00) .......0 + */ + { 0x12, 0x00 }, + + /* + * 12 COMH "Common Control H" + * = 64 (0x40) 01000000 + * COMH[7] "SRST" + * = 0 (0x00) 0....... "No-op" + * COMH[6:4] "Resolution selection" + * = 4 (0x04) .100.... "XGA" + * COMH[3] "Master slave selection" + * = 0 (0x00) ....0... "Master mode" + * COMH[2] "Internal B/R channel option" + * = 0 (0x00) .....0.. "B/R use same channel" + * COMH[1] "Color bar test pattern" + * = 0 (0x00) ......0. "Off" + * COMH[0] "Reserved" + * = 0 (0x00) .......0 + */ + { 0x12, 0x40 }, + + /* + * 17 HREFST "Horizontal window start" + * = 31 (0x1F) 00011111 + * HREFST[7:0] "Horizontal window start, 8 MSBs" + * = 31 (0x1F) 00011111 + */ + { 0x17, 0x1f }, + + /* + * 18 HREFEND "Horizontal window end" + * = 95 (0x5F) 01011111 + * HREFEND[7:0] "Horizontal Window End, 8 MSBs" + * = 95 (0x5F) 01011111 + */ + { 0x18, 0x5f }, + + /* + * 19 VSTRT "Vertical window start" + * = 0 (0x00) 00000000 + * VSTRT[7:0] "Vertical Window Start, 8 MSBs" + * = 0 (0x00) 00000000 + */ + { 0x19, 0x00 }, + + /* + * 1A VEND "Vertical window end" + * = 96 (0x60) 01100000 + * VEND[7:0] "Vertical Window End, 8 MSBs" + * = 96 (0x60) 01100000 + */ + { 0x1a, 0x60 }, + + /* + * 32 COMM "Common Control M" + * = 18 (0x12) 00010010 + * COMM[7:6] "Pixel clock divide option" + * = 0 (0x00) 00...... "/1" + * COMM[5:3] "Horizontal window end position, 3 LSBs" + * = 2 (0x02) ..010... + * COMM[2:0] "Horizontal window start position, 3 LSBs" + * = 2 (0x02) .....010 + */ + { 0x32, 0x12 }, + + /* + * 03 COMA "Common Control A" + * = 74 (0x4A) 01001010 + * COMA[7:4] "AWB Update Threshold" + * = 4 (0x04) 0100.... + * COMA[3:2] "Vertical window end line control 2 LSBs" + * = 2 (0x02) ....10.. + * COMA[1:0] "Vertical window start line control 2 LSBs" + * = 2 (0x02) ......10 + */ + { 0x03, 0x4a }, + + /* + * 02 RED "Red Gain Control" + * = 175 (0xAF) 10101111 + * RED[7] "Action" + * = 1 (0x01) 1....... "gain = 1/(1+bitrev([6:0]))" + * RED[6:0] "Value" + * = 47 (0x2F) .0101111 + */ + { 0x02, 0xaf }, + + /* + * 2D ADDVSL "VSYNC Pulse Width" + * = 210 (0xD2) 11010010 + * ADDVSL[7:0] "VSYNC pulse width, LSB" + * = 210 (0xD2) 11010010 + */ + { 0x2d, 0xd2 }, + + /* + * 00 GAIN = 24 (0x18) 00011000 + * GAIN[7:6] "Reserved" + * = 0 (0x00) 00...... + * GAIN[5] "Double" + * = 0 (0x00) ..0..... "False" + * GAIN[4] "Double" + * = 1 (0x01) ...1.... "True" + * GAIN[3:0] "Range" + * = 8 (0x08) ....1000 + */ + { 0x00, 0x18 }, + + /* + * 01 BLUE "Blue Gain Control" + * = 240 (0xF0) 11110000 + * BLUE[7] "Action" + * = 1 (0x01) 1....... "gain = 1/(1+bitrev([6:0]))" + * BLUE[6:0] "Value" + * = 112 (0x70) .1110000 + */ + { 0x01, 0xf0 }, + + /* + * 10 AEC "Automatic Exposure Control" + * = 10 (0x0A) 00001010 + * AEC[7:0] "Automatic Exposure Control, 8 MSBs" + * = 10 (0x0A) 00001010 + */ + { 0x10, 0x0a }, + + { 0xe1, 0x67 }, + { 0xe3, 0x03 }, + { 0xe4, 0x26 }, + { 0xe5, 0x3e }, + { 0xf8, 0x01 }, + { 0xff, 0x01 }, +}; + +static const struct ov_i2c_regvals norm_6x20[] = { + { 0x12, 0x80 }, /* reset */ + { 0x11, 0x01 }, + { 0x03, 0x60 }, + { 0x05, 0x7f }, /* For when autoadjust is off */ + { 0x07, 0xa8 }, + /* The ratio of 0x0c and 0x0d controls the white point */ + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, + { 0x0f, 0x15 }, /* COMS */ + { 0x10, 0x75 }, /* AEC Exposure time */ + { 0x12, 0x24 }, /* Enable AGC */ + { 0x14, 0x04 }, + /* 0x16: 0x06 helps frame stability with moving objects */ + { 0x16, 0x06 }, +/* { 0x20, 0x30 }, * Aperture correction enable */ + { 0x26, 0xb2 }, /* BLC enable */ + /* 0x28: 0x05 Selects RGB format if RGB on */ + { 0x28, 0x05 }, + { 0x2a, 0x04 }, /* Disable framerate adjust */ +/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ + { 0x2d, 0x85 }, + { 0x33, 0xa0 }, /* Color Processing Parameter */ + { 0x34, 0xd2 }, /* Max A/D range */ + { 0x38, 0x8b }, + { 0x39, 0x40 }, + + { 0x3c, 0x39 }, /* Enable AEC mode changing */ + { 0x3c, 0x3c }, /* Change AEC mode */ + { 0x3c, 0x24 }, /* Disable AEC mode changing */ + + { 0x3d, 0x80 }, + /* These next two registers (0x4a, 0x4b) are undocumented. + * They control the color balance */ + { 0x4a, 0x80 }, + { 0x4b, 0x80 }, + { 0x4d, 0xd2 }, /* This reduces noise a bit */ + { 0x4e, 0xc1 }, + { 0x4f, 0x04 }, +/* Do 50-53 have any effect? */ +/* Toggle 0x12[2] off and on here? */ +}; + +static const struct ov_i2c_regvals norm_6x30[] = { + { 0x12, 0x80 }, /* Reset */ + { 0x00, 0x1f }, /* Gain */ + { 0x01, 0x99 }, /* Blue gain */ + { 0x02, 0x7c }, /* Red gain */ + { 0x03, 0xc0 }, /* Saturation */ + { 0x05, 0x0a }, /* Contrast */ + { 0x06, 0x95 }, /* Brightness */ + { 0x07, 0x2d }, /* Sharpness */ + { 0x0c, 0x20 }, + { 0x0d, 0x20 }, + { 0x0e, 0xa0 }, /* Was 0x20, bit7 enables a 2x gain which we need */ + { 0x0f, 0x05 }, + { 0x10, 0x9a }, + { 0x11, 0x00 }, /* Pixel clock = fastest */ + { 0x12, 0x24 }, /* Enable AGC and AWB */ + { 0x13, 0x21 }, + { 0x14, 0x80 }, + { 0x15, 0x01 }, + { 0x16, 0x03 }, + { 0x17, 0x38 }, + { 0x18, 0xea }, + { 0x19, 0x04 }, + { 0x1a, 0x93 }, + { 0x1b, 0x00 }, + { 0x1e, 0xc4 }, + { 0x1f, 0x04 }, + { 0x20, 0x20 }, + { 0x21, 0x10 }, + { 0x22, 0x88 }, + { 0x23, 0xc0 }, /* Crystal circuit power level */ + { 0x25, 0x9a }, /* Increase AEC black ratio */ + { 0x26, 0xb2 }, /* BLC enable */ + { 0x27, 0xa2 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x84 }, /* 60 Hz power */ + { 0x2b, 0xa8 }, /* 60 Hz power */ + { 0x2c, 0xa0 }, + { 0x2d, 0x95 }, /* Enable auto-brightness */ + { 0x2e, 0x88 }, + { 0x33, 0x26 }, + { 0x34, 0x03 }, + { 0x36, 0x8f }, + { 0x37, 0x80 }, + { 0x38, 0x83 }, + { 0x39, 0x80 }, + { 0x3a, 0x0f }, + { 0x3b, 0x3c }, + { 0x3c, 0x1a }, + { 0x3d, 0x80 }, + { 0x3e, 0x80 }, + { 0x3f, 0x0e }, + { 0x40, 0x00 }, /* White bal */ + { 0x41, 0x00 }, /* White bal */ + { 0x42, 0x80 }, + { 0x43, 0x3f }, /* White bal */ + { 0x44, 0x80 }, + { 0x45, 0x20 }, + { 0x46, 0x20 }, + { 0x47, 0x80 }, + { 0x48, 0x7f }, + { 0x49, 0x00 }, + { 0x4a, 0x00 }, + { 0x4b, 0x80 }, + { 0x4c, 0xd0 }, + { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ + { 0x4e, 0x40 }, + { 0x4f, 0x07 }, /* UV avg., col. killer: max */ + { 0x50, 0xff }, + { 0x54, 0x23 }, /* Max AGC gain: 18dB */ + { 0x55, 0xff }, + { 0x56, 0x12 }, + { 0x57, 0x81 }, + { 0x58, 0x75 }, + { 0x59, 0x01 }, /* AGC dark current comp.: +1 */ + { 0x5a, 0x2c }, + { 0x5b, 0x0f }, /* AWB chrominance levels */ + { 0x5c, 0x10 }, + { 0x3d, 0x80 }, + { 0x27, 0xa6 }, + { 0x12, 0x20 }, /* Toggle AWB */ + { 0x12, 0x24 }, +}; + +/* Lawrence Glaister reports: + * + * Register 0x0f in the 7610 has the following effects: + * + * 0x85 (AEC method 1): Best overall, good contrast range + * 0x45 (AEC method 2): Very overexposed + * 0xa5 (spec sheet default): Ok, but the black level is + * shifted resulting in loss of contrast + * 0x05 (old driver setting): very overexposed, too much + * contrast + */ +static const struct ov_i2c_regvals norm_7610[] = { + { 0x10, 0xff }, + { 0x16, 0x06 }, + { 0x28, 0x24 }, + { 0x2b, 0xac }, + { 0x12, 0x00 }, + { 0x38, 0x81 }, + { 0x28, 0x24 }, /* 0c */ + { 0x0f, 0x85 }, /* lg's setting */ + { 0x15, 0x01 }, + { 0x20, 0x1c }, + { 0x23, 0x2a }, + { 0x24, 0x10 }, + { 0x25, 0x8a }, + { 0x26, 0xa2 }, + { 0x27, 0xc2 }, + { 0x2a, 0x04 }, + { 0x2c, 0xfe }, + { 0x2d, 0x93 }, + { 0x30, 0x71 }, + { 0x31, 0x60 }, + { 0x32, 0x26 }, + { 0x33, 0x20 }, + { 0x34, 0x48 }, + { 0x12, 0x24 }, + { 0x11, 0x01 }, + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, +}; + +static const struct ov_i2c_regvals norm_7620[] = { + { 0x12, 0x80 }, /* reset */ + { 0x00, 0x00 }, /* gain */ + { 0x01, 0x80 }, /* blue gain */ + { 0x02, 0x80 }, /* red gain */ + { 0x03, 0xc0 }, /* OV7670_R03_VREF */ + { 0x06, 0x60 }, + { 0x07, 0x00 }, + { 0x0c, 0x24 }, + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, + { 0x11, 0x01 }, + { 0x12, 0x24 }, + { 0x13, 0x01 }, + { 0x14, 0x84 }, + { 0x15, 0x01 }, + { 0x16, 0x03 }, + { 0x17, 0x2f }, + { 0x18, 0xcf }, + { 0x19, 0x06 }, + { 0x1a, 0xf5 }, + { 0x1b, 0x00 }, + { 0x20, 0x18 }, + { 0x21, 0x80 }, + { 0x22, 0x80 }, + { 0x23, 0x00 }, + { 0x26, 0xa2 }, + { 0x27, 0xea }, + { 0x28, 0x22 }, /* Was 0x20, bit1 enables a 2x gain which we need */ + { 0x29, 0x00 }, + { 0x2a, 0x10 }, + { 0x2b, 0x00 }, + { 0x2c, 0x88 }, + { 0x2d, 0x91 }, + { 0x2e, 0x80 }, + { 0x2f, 0x44 }, + { 0x60, 0x27 }, + { 0x61, 0x02 }, + { 0x62, 0x5f }, + { 0x63, 0xd5 }, + { 0x64, 0x57 }, + { 0x65, 0x83 }, + { 0x66, 0x55 }, + { 0x67, 0x92 }, + { 0x68, 0xcf }, + { 0x69, 0x76 }, + { 0x6a, 0x22 }, + { 0x6b, 0x00 }, + { 0x6c, 0x02 }, + { 0x6d, 0x44 }, + { 0x6e, 0x80 }, + { 0x6f, 0x1d }, + { 0x70, 0x8b }, + { 0x71, 0x00 }, + { 0x72, 0x14 }, + { 0x73, 0x54 }, + { 0x74, 0x00 }, + { 0x75, 0x8e }, + { 0x76, 0x00 }, + { 0x77, 0xff }, + { 0x78, 0x80 }, + { 0x79, 0x80 }, + { 0x7a, 0x80 }, + { 0x7b, 0xe2 }, + { 0x7c, 0x00 }, +}; + +/* 7640 and 7648. The defaults should be OK for most registers. */ +static const struct ov_i2c_regvals norm_7640[] = { + { 0x12, 0x80 }, + { 0x12, 0x14 }, +}; + +static const struct ov_regvals init_519_ov7660[] = { + { 0x5d, 0x03 }, /* Turn off suspend mode */ + { 0x53, 0x9b }, /* 0x9f enables the (unused) microcontroller */ + { 0x54, 0x0f }, /* bit2 (jpeg enable) */ + { 0xa2, 0x20 }, /* a2-a5 are undocumented */ + { 0xa3, 0x18 }, + { 0xa4, 0x04 }, + { 0xa5, 0x28 }, + { 0x37, 0x00 }, /* SetUsbInit */ + { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ + /* Enable both fields, YUV Input, disable defect comp (why?) */ + { 0x20, 0x0c }, /* 0x0d does U <-> V swap */ + { 0x21, 0x38 }, + { 0x22, 0x1d }, + { 0x17, 0x50 }, /* undocumented */ + { 0x37, 0x00 }, /* undocumented */ + { 0x40, 0xff }, /* I2C timeout counter */ + { 0x46, 0x00 }, /* I2C clock prescaler */ +}; +static const struct ov_i2c_regvals norm_7660[] = { + {OV7670_R12_COM7, OV7670_COM7_RESET}, + {OV7670_R11_CLKRC, 0x81}, + {0x92, 0x00}, /* DM_LNL */ + {0x93, 0x00}, /* DM_LNH */ + {0x9d, 0x4c}, /* BD50ST */ + {0x9e, 0x3f}, /* BD60ST */ + {OV7670_R3B_COM11, 0x02}, + {OV7670_R13_COM8, 0xf5}, + {OV7670_R10_AECH, 0x00}, + {OV7670_R00_GAIN, 0x00}, + {OV7670_R01_BLUE, 0x7c}, + {OV7670_R02_RED, 0x9d}, + {OV7670_R12_COM7, 0x00}, + {OV7670_R04_COM1, 00}, + {OV7670_R18_HSTOP, 0x01}, + {OV7670_R17_HSTART, 0x13}, + {OV7670_R32_HREF, 0x92}, + {OV7670_R19_VSTART, 0x02}, + {OV7670_R1A_VSTOP, 0x7a}, + {OV7670_R03_VREF, 0x00}, + {OV7670_R0E_COM5, 0x04}, + {OV7670_R0F_COM6, 0x62}, + {OV7670_R15_COM10, 0x00}, + {0x16, 0x02}, /* RSVD */ + {0x1b, 0x00}, /* PSHFT */ + {OV7670_R1E_MVFP, 0x01}, + {0x29, 0x3c}, /* RSVD */ + {0x33, 0x00}, /* CHLF */ + {0x34, 0x07}, /* ARBLM */ + {0x35, 0x84}, /* RSVD */ + {0x36, 0x00}, /* RSVD */ + {0x37, 0x04}, /* ADC */ + {0x39, 0x43}, /* OFON */ + {OV7670_R3A_TSLB, 0x00}, + {OV7670_R3C_COM12, 0x6c}, + {OV7670_R3D_COM13, 0x98}, + {OV7670_R3F_EDGE, 0x23}, + {OV7670_R40_COM15, 0xc1}, + {OV7670_R41_COM16, 0x22}, + {0x6b, 0x0a}, /* DBLV */ + {0xa1, 0x08}, /* RSVD */ + {0x69, 0x80}, /* HV */ + {0x43, 0xf0}, /* RSVD.. */ + {0x44, 0x10}, + {0x45, 0x78}, + {0x46, 0xa8}, + {0x47, 0x60}, + {0x48, 0x80}, + {0x59, 0xba}, + {0x5a, 0x9a}, + {0x5b, 0x22}, + {0x5c, 0xb9}, + {0x5d, 0x9b}, + {0x5e, 0x10}, + {0x5f, 0xe0}, + {0x60, 0x85}, + {0x61, 0x60}, + {0x9f, 0x9d}, /* RSVD */ + {0xa0, 0xa0}, /* DSPC2 */ + {0x4f, 0x60}, /* matrix */ + {0x50, 0x64}, + {0x51, 0x04}, + {0x52, 0x18}, + {0x53, 0x3c}, + {0x54, 0x54}, + {0x55, 0x40}, + {0x56, 0x40}, + {0x57, 0x40}, + {0x58, 0x0d}, /* matrix sign */ + {0x8b, 0xcc}, /* RSVD */ + {0x8c, 0xcc}, + {0x8d, 0xcf}, + {0x6c, 0x40}, /* gamma curve */ + {0x6d, 0xe0}, + {0x6e, 0xa0}, + {0x6f, 0x80}, + {0x70, 0x70}, + {0x71, 0x80}, + {0x72, 0x60}, + {0x73, 0x60}, + {0x74, 0x50}, + {0x75, 0x40}, + {0x76, 0x38}, + {0x77, 0x3c}, + {0x78, 0x32}, + {0x79, 0x1a}, + {0x7a, 0x28}, + {0x7b, 0x24}, + {0x7c, 0x04}, /* gamma curve */ + {0x7d, 0x12}, + {0x7e, 0x26}, + {0x7f, 0x46}, + {0x80, 0x54}, + {0x81, 0x64}, + {0x82, 0x70}, + {0x83, 0x7c}, + {0x84, 0x86}, + {0x85, 0x8e}, + {0x86, 0x9c}, + {0x87, 0xab}, + {0x88, 0xc4}, + {0x89, 0xd1}, + {0x8a, 0xe5}, + {OV7670_R14_COM9, 0x1e}, + {OV7670_R24_AEW, 0x80}, + {OV7670_R25_AEB, 0x72}, + {OV7670_R26_VPT, 0xb3}, + {0x62, 0x80}, /* LCC1 */ + {0x63, 0x80}, /* LCC2 */ + {0x64, 0x06}, /* LCC3 */ + {0x65, 0x00}, /* LCC4 */ + {0x66, 0x01}, /* LCC5 */ + {0x94, 0x0e}, /* RSVD.. */ + {0x95, 0x14}, + {OV7670_R13_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT + | 0x10 + | OV7670_COM8_AGC + | OV7670_COM8_AWB + | OV7670_COM8_AEC}, + {0xa1, 0xc8} +}; +static const struct ov_i2c_regvals norm_9600[] = { + {0x12, 0x80}, + {0x0c, 0x28}, + {0x11, 0x80}, + {0x13, 0xb5}, + {0x14, 0x3e}, + {0x1b, 0x04}, + {0x24, 0xb0}, + {0x25, 0x90}, + {0x26, 0x94}, + {0x35, 0x90}, + {0x37, 0x07}, + {0x38, 0x08}, + {0x01, 0x8e}, + {0x02, 0x85} +}; + +/* 7670. Defaults taken from OmniVision provided data, +* as provided by Jonathan Corbet of OLPC */ +static const struct ov_i2c_regvals norm_7670[] = { + { OV7670_R12_COM7, OV7670_COM7_RESET }, + { OV7670_R3A_TSLB, 0x04 }, /* OV */ + { OV7670_R12_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ + { OV7670_R11_CLKRC, 0x01 }, +/* + * Set the hardware window. These values from OV don't entirely + * make sense - hstop is less than hstart. But they work... + */ + { OV7670_R17_HSTART, 0x13 }, + { OV7670_R18_HSTOP, 0x01 }, + { OV7670_R32_HREF, 0xb6 }, + { OV7670_R19_VSTART, 0x02 }, + { OV7670_R1A_VSTOP, 0x7a }, + { OV7670_R03_VREF, 0x0a }, + + { OV7670_R0C_COM3, 0x00 }, + { OV7670_R3E_COM14, 0x00 }, +/* Mystery scaling numbers */ + { 0x70, 0x3a }, + { 0x71, 0x35 }, + { 0x72, 0x11 }, + { 0x73, 0xf0 }, + { 0xa2, 0x02 }, +/* { OV7670_R15_COM10, 0x0 }, */ + +/* Gamma curve values */ + { 0x7a, 0x20 }, + { 0x7b, 0x10 }, + { 0x7c, 0x1e }, + { 0x7d, 0x35 }, + { 0x7e, 0x5a }, + { 0x7f, 0x69 }, + { 0x80, 0x76 }, + { 0x81, 0x80 }, + { 0x82, 0x88 }, + { 0x83, 0x8f }, + { 0x84, 0x96 }, + { 0x85, 0xa3 }, + { 0x86, 0xaf }, + { 0x87, 0xc4 }, + { 0x88, 0xd7 }, + { 0x89, 0xe8 }, + +/* AGC and AEC parameters. Note we start by disabling those features, + then turn them only after tweaking the values. */ + { OV7670_R13_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT }, + { OV7670_R00_GAIN, 0x00 }, + { OV7670_R10_AECH, 0x00 }, + { OV7670_R0D_COM4, 0x40 }, /* magic reserved bit */ + { OV7670_R14_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ + { OV7670_RA5_BD50MAX, 0x05 }, + { OV7670_RAB_BD60MAX, 0x07 }, + { OV7670_R24_AEW, 0x95 }, + { OV7670_R25_AEB, 0x33 }, + { OV7670_R26_VPT, 0xe3 }, + { OV7670_R9F_HAECC1, 0x78 }, + { OV7670_RA0_HAECC2, 0x68 }, + { 0xa1, 0x03 }, /* magic */ + { OV7670_RA6_HAECC3, 0xd8 }, + { OV7670_RA7_HAECC4, 0xd8 }, + { OV7670_RA8_HAECC5, 0xf0 }, + { OV7670_RA9_HAECC6, 0x90 }, + { OV7670_RAA_HAECC7, 0x94 }, + { OV7670_R13_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT + | OV7670_COM8_AGC + | OV7670_COM8_AEC }, + +/* Almost all of these are magic "reserved" values. */ + { OV7670_R0E_COM5, 0x61 }, + { OV7670_R0F_COM6, 0x4b }, + { 0x16, 0x02 }, + { OV7670_R1E_MVFP, 0x07 }, + { 0x21, 0x02 }, + { 0x22, 0x91 }, + { 0x29, 0x07 }, + { 0x33, 0x0b }, + { 0x35, 0x0b }, + { 0x37, 0x1d }, + { 0x38, 0x71 }, + { 0x39, 0x2a }, + { OV7670_R3C_COM12, 0x78 }, + { 0x4d, 0x40 }, + { 0x4e, 0x20 }, + { OV7670_R69_GFIX, 0x00 }, + { 0x6b, 0x4a }, + { 0x74, 0x10 }, + { 0x8d, 0x4f }, + { 0x8e, 0x00 }, + { 0x8f, 0x00 }, + { 0x90, 0x00 }, + { 0x91, 0x00 }, + { 0x96, 0x00 }, + { 0x9a, 0x00 }, + { 0xb0, 0x84 }, + { 0xb1, 0x0c }, + { 0xb2, 0x0e }, + { 0xb3, 0x82 }, + { 0xb8, 0x0a }, + +/* More reserved magic, some of which tweaks white balance */ + { 0x43, 0x0a }, + { 0x44, 0xf0 }, + { 0x45, 0x34 }, + { 0x46, 0x58 }, + { 0x47, 0x28 }, + { 0x48, 0x3a }, + { 0x59, 0x88 }, + { 0x5a, 0x88 }, + { 0x5b, 0x44 }, + { 0x5c, 0x67 }, + { 0x5d, 0x49 }, + { 0x5e, 0x0e }, + { 0x6c, 0x0a }, + { 0x6d, 0x55 }, + { 0x6e, 0x11 }, + { 0x6f, 0x9f }, /* "9e for advance AWB" */ + { 0x6a, 0x40 }, + { OV7670_R01_BLUE, 0x40 }, + { OV7670_R02_RED, 0x60 }, + { OV7670_R13_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT + | OV7670_COM8_AGC + | OV7670_COM8_AEC + | OV7670_COM8_AWB }, + +/* Matrix coefficients */ + { 0x4f, 0x80 }, + { 0x50, 0x80 }, + { 0x51, 0x00 }, + { 0x52, 0x22 }, + { 0x53, 0x5e }, + { 0x54, 0x80 }, + { 0x58, 0x9e }, + + { OV7670_R41_COM16, OV7670_COM16_AWBGAIN }, + { OV7670_R3F_EDGE, 0x00 }, + { 0x75, 0x05 }, + { 0x76, 0xe1 }, + { 0x4c, 0x00 }, + { 0x77, 0x01 }, + { OV7670_R3D_COM13, OV7670_COM13_GAMMA + | OV7670_COM13_UVSAT + | 2}, /* was 3 */ + { 0x4b, 0x09 }, + { 0xc9, 0x60 }, + { OV7670_R41_COM16, 0x38 }, + { 0x56, 0x40 }, + + { 0x34, 0x11 }, + { OV7670_R3B_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, + { 0xa4, 0x88 }, + { 0x96, 0x00 }, + { 0x97, 0x30 }, + { 0x98, 0x20 }, + { 0x99, 0x30 }, + { 0x9a, 0x84 }, + { 0x9b, 0x29 }, + { 0x9c, 0x03 }, + { 0x9d, 0x4c }, + { 0x9e, 0x3f }, + { 0x78, 0x04 }, + +/* Extra-weird stuff. Some sort of multiplexor register */ + { 0x79, 0x01 }, + { 0xc8, 0xf0 }, + { 0x79, 0x0f }, + { 0xc8, 0x00 }, + { 0x79, 0x10 }, + { 0xc8, 0x7e }, + { 0x79, 0x0a }, + { 0xc8, 0x80 }, + { 0x79, 0x0b }, + { 0xc8, 0x01 }, + { 0x79, 0x0c }, + { 0xc8, 0x0f }, + { 0x79, 0x0d }, + { 0xc8, 0x20 }, + { 0x79, 0x09 }, + { 0xc8, 0x80 }, + { 0x79, 0x02 }, + { 0xc8, 0xc0 }, + { 0x79, 0x03 }, + { 0xc8, 0x40 }, + { 0x79, 0x05 }, + { 0xc8, 0x30 }, + { 0x79, 0x26 }, +}; + +static const struct ov_i2c_regvals norm_8610[] = { + { 0x12, 0x80 }, + { 0x00, 0x00 }, + { 0x01, 0x80 }, + { 0x02, 0x80 }, + { 0x03, 0xc0 }, + { 0x04, 0x30 }, + { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ + { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ + { 0x0a, 0x86 }, + { 0x0b, 0xb0 }, + { 0x0c, 0x20 }, + { 0x0d, 0x20 }, + { 0x11, 0x01 }, + { 0x12, 0x25 }, + { 0x13, 0x01 }, + { 0x14, 0x04 }, + { 0x15, 0x01 }, /* Lin and Win think different about UV order */ + { 0x16, 0x03 }, + { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ + { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ + { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ + { 0x1a, 0xf5 }, + { 0x1b, 0x00 }, + { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ + { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ + { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ + { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ + { 0x26, 0xa2 }, + { 0x27, 0xea }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x80 }, + { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ + { 0x2c, 0xac }, + { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ + { 0x2e, 0x80 }, + { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ + { 0x4c, 0x00 }, + { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ + { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ + { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ + { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ + { 0x63, 0xff }, + { 0x64, 0x53 }, /* new windrv 090403 says 0x57, + * maybe thats wrong */ + { 0x65, 0x00 }, + { 0x66, 0x55 }, + { 0x67, 0xb0 }, + { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ + { 0x69, 0x02 }, + { 0x6a, 0x22 }, + { 0x6b, 0x00 }, + { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but + * deleting bit7 colors the first images red */ + { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ + { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ + { 0x6f, 0x01 }, + { 0x70, 0x8b }, + { 0x71, 0x00 }, + { 0x72, 0x14 }, + { 0x73, 0x54 }, + { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */ + { 0x75, 0x0e }, + { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ + { 0x77, 0xff }, + { 0x78, 0x80 }, + { 0x79, 0x80 }, + { 0x7a, 0x80 }, + { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ + { 0x7c, 0x00 }, + { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ + { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ + { 0x7f, 0xfb }, + { 0x80, 0x28 }, + { 0x81, 0x00 }, + { 0x82, 0x23 }, + { 0x83, 0x0b }, + { 0x84, 0x00 }, + { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ + { 0x86, 0xc9 }, + { 0x87, 0x00 }, + { 0x88, 0x00 }, + { 0x89, 0x01 }, + { 0x12, 0x20 }, + { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ +}; + +static unsigned char ov7670_abs_to_sm(unsigned char v) +{ + if (v > 127) + return v & 0x7f; + return (128 - v) | 0x80; +} + +/* Write a OV519 register */ +static void reg_w(struct sd *sd, u16 index, u16 value) +{ + int ret, req = 0; + + if (sd->gspca_dev.usb_err < 0) + return; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + req = 2; + break; + case BRIDGE_OVFX2: + req = 0x0a; + /* fall through */ + case BRIDGE_W9968CF: + PDEBUG(D_USBO, "SET %02x %04x %04x", + req, value, index); + ret = usb_control_msg(sd->gspca_dev.dev, + usb_sndctrlpipe(sd->gspca_dev.dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + goto leave; + default: + req = 1; + } + + PDEBUG(D_USBO, "SET %02x 0000 %04x %02x", + req, index, value); + sd->gspca_dev.usb_buf[0] = value; + ret = usb_control_msg(sd->gspca_dev.dev, + usb_sndctrlpipe(sd->gspca_dev.dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, + sd->gspca_dev.usb_buf, 1, 500); +leave: + if (ret < 0) { + err("reg_w %02x failed %d", index, ret); + sd->gspca_dev.usb_err = ret; + return; + } +} + +/* Read from a OV519 register, note not valid for the w9968cf!! */ +/* returns: negative is error, pos or zero is data */ +static int reg_r(struct sd *sd, u16 index) +{ + int ret; + int req; + + if (sd->gspca_dev.usb_err < 0) + return -1; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + req = 3; + break; + case BRIDGE_OVFX2: + req = 0x0b; + break; + default: + req = 1; + } + + ret = usb_control_msg(sd->gspca_dev.dev, + usb_rcvctrlpipe(sd->gspca_dev.dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, sd->gspca_dev.usb_buf, 1, 500); + + if (ret >= 0) { + ret = sd->gspca_dev.usb_buf[0]; + PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", + req, index, ret); + } else { + err("reg_r %02x failed %d", index, ret); + sd->gspca_dev.usb_err = ret; + } + + return ret; +} + +/* Read 8 values from a OV519 register */ +static int reg_r8(struct sd *sd, + u16 index) +{ + int ret; + + if (sd->gspca_dev.usb_err < 0) + return -1; + + ret = usb_control_msg(sd->gspca_dev.dev, + usb_rcvctrlpipe(sd->gspca_dev.dev, 0), + 1, /* REQ_IO */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, sd->gspca_dev.usb_buf, 8, 500); + + if (ret >= 0) { + ret = sd->gspca_dev.usb_buf[0]; + } else { + err("reg_r8 %02x failed %d", index, ret); + sd->gspca_dev.usb_err = ret; + } + + return ret; +} + +/* + * Writes bits at positions specified by mask to an OV51x reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static void reg_w_mask(struct sd *sd, + u16 index, + u8 value, + u8 mask) +{ + int ret; + u8 oldval; + + if (mask != 0xff) { + value &= mask; /* Enforce mask on value */ + ret = reg_r(sd, index); + if (ret < 0) + return; + + oldval = ret & ~mask; /* Clear the masked bits */ + value |= oldval; /* Set the desired bits */ + } + reg_w(sd, index, value); +} + +/* + * Writes multiple (n) byte value to a single register. Only valid with certain + * registers (0x30 and 0xc4 - 0xce). + */ +static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n) +{ + int ret; + + if (sd->gspca_dev.usb_err < 0) + return; + + *((__le32 *) sd->gspca_dev.usb_buf) = __cpu_to_le32(value); + + ret = usb_control_msg(sd->gspca_dev.dev, + usb_sndctrlpipe(sd->gspca_dev.dev, 0), + 1 /* REG_IO */, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, + sd->gspca_dev.usb_buf, n, 500); + if (ret < 0) { + err("reg_w32 %02x failed %d", index, ret); + sd->gspca_dev.usb_err = ret; + } +} + +static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value) +{ + int rc, retries; + + PDEBUG(D_USBO, "ov511_i2c_w %02x %02x", reg, value); + + /* Three byte write cycle */ + for (retries = 6; ; ) { + /* Select camera register */ + reg_w(sd, R51x_I2C_SADDR_3, reg); + + /* Write "value" to I2C data port of OV511 */ + reg_w(sd, R51x_I2C_DATA, value); + + /* Initiate 3-byte write cycle */ + reg_w(sd, R511_I2C_CTL, 0x01); + + do { + rc = reg_r(sd, R511_I2C_CTL); + } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ + + if (rc < 0) + return; + + if ((rc & 2) == 0) /* Ack? */ + break; + if (--retries < 0) { + PDEBUG(D_USBO, "i2c write retries exhausted"); + return; + } + } +} + +static int ov511_i2c_r(struct sd *sd, u8 reg) +{ + int rc, value, retries; + + /* Two byte write cycle */ + for (retries = 6; ; ) { + /* Select camera register */ + reg_w(sd, R51x_I2C_SADDR_2, reg); + + /* Initiate 2-byte write cycle */ + reg_w(sd, R511_I2C_CTL, 0x03); + + do { + rc = reg_r(sd, R511_I2C_CTL); + } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ + + if (rc < 0) + return rc; + + if ((rc & 2) == 0) /* Ack? */ + break; + + /* I2C abort */ + reg_w(sd, R511_I2C_CTL, 0x10); + + if (--retries < 0) { + PDEBUG(D_USBI, "i2c write retries exhausted"); + return -1; + } + } + + /* Two byte read cycle */ + for (retries = 6; ; ) { + /* Initiate 2-byte read cycle */ + reg_w(sd, R511_I2C_CTL, 0x05); + + do { + rc = reg_r(sd, R511_I2C_CTL); + } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ + + if (rc < 0) + return rc; + + if ((rc & 2) == 0) /* Ack? */ + break; + + /* I2C abort */ + reg_w(sd, R511_I2C_CTL, 0x10); + + if (--retries < 0) { + PDEBUG(D_USBI, "i2c read retries exhausted"); + return -1; + } + } + + value = reg_r(sd, R51x_I2C_DATA); + + PDEBUG(D_USBI, "ov511_i2c_r %02x %02x", reg, value); + + /* This is needed to make i2c_w() work */ + reg_w(sd, R511_I2C_CTL, 0x05); + + return value; +} + +/* + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from i2c_w(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static void ov518_i2c_w(struct sd *sd, + u8 reg, + u8 value) +{ + PDEBUG(D_USBO, "ov518_i2c_w %02x %02x", reg, value); + + /* Select camera register */ + reg_w(sd, R51x_I2C_SADDR_3, reg); + + /* Write "value" to I2C data port of OV511 */ + reg_w(sd, R51x_I2C_DATA, value); + + /* Initiate 3-byte write cycle */ + reg_w(sd, R518_I2C_CTL, 0x01); + + /* wait for write complete */ + msleep(4); + reg_r8(sd, R518_I2C_CTL); +} + +/* + * returns: negative is error, pos or zero is data + * + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from i2c_r(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static int ov518_i2c_r(struct sd *sd, u8 reg) +{ + int value; + + /* Select camera register */ + reg_w(sd, R51x_I2C_SADDR_2, reg); + + /* Initiate 2-byte write cycle */ + reg_w(sd, R518_I2C_CTL, 0x03); + + /* Initiate 2-byte read cycle */ + reg_w(sd, R518_I2C_CTL, 0x05); + value = reg_r(sd, R51x_I2C_DATA); + PDEBUG(D_USBI, "ov518_i2c_r %02x %02x", reg, value); + return value; +} + +static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value) +{ + int ret; + + if (sd->gspca_dev.usb_err < 0) + return; + + ret = usb_control_msg(sd->gspca_dev.dev, + usb_sndctrlpipe(sd->gspca_dev.dev, 0), + 0x02, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + (u16) value, (u16) reg, NULL, 0, 500); + + if (ret < 0) { + err("ovfx2_i2c_w %02x failed %d", reg, ret); + sd->gspca_dev.usb_err = ret; + } + + PDEBUG(D_USBO, "ovfx2_i2c_w %02x %02x", reg, value); +} + +static int ovfx2_i2c_r(struct sd *sd, u8 reg) +{ + int ret; + + if (sd->gspca_dev.usb_err < 0) + return -1; + + ret = usb_control_msg(sd->gspca_dev.dev, + usb_rcvctrlpipe(sd->gspca_dev.dev, 0), + 0x03, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, (u16) reg, sd->gspca_dev.usb_buf, 1, 500); + + if (ret >= 0) { + ret = sd->gspca_dev.usb_buf[0]; + PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret); + } else { + err("ovfx2_i2c_r %02x failed %d", reg, ret); + sd->gspca_dev.usb_err = ret; + } + + return ret; +} + +static void i2c_w(struct sd *sd, u8 reg, u8 value) +{ + if (sd->sensor_reg_cache[reg] == value) + return; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + ov511_i2c_w(sd, reg, value); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + case BRIDGE_OV519: + ov518_i2c_w(sd, reg, value); + break; + case BRIDGE_OVFX2: + ovfx2_i2c_w(sd, reg, value); + break; + case BRIDGE_W9968CF: + w9968cf_i2c_w(sd, reg, value); + break; + } + + if (sd->gspca_dev.usb_err >= 0) { + /* Up on sensor reset empty the register cache */ + if (reg == 0x12 && (value & 0x80)) + memset(sd->sensor_reg_cache, -1, + sizeof(sd->sensor_reg_cache)); + else + sd->sensor_reg_cache[reg] = value; + } +} + +static int i2c_r(struct sd *sd, u8 reg) +{ + int ret = -1; + + if (sd->sensor_reg_cache[reg] != -1) + return sd->sensor_reg_cache[reg]; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + ret = ov511_i2c_r(sd, reg); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + case BRIDGE_OV519: + ret = ov518_i2c_r(sd, reg); + break; + case BRIDGE_OVFX2: + ret = ovfx2_i2c_r(sd, reg); + break; + case BRIDGE_W9968CF: + ret = w9968cf_i2c_r(sd, reg); + break; + } + + if (ret >= 0) + sd->sensor_reg_cache[reg] = ret; + + return ret; +} + +/* Writes bits at positions specified by mask to an I2C reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static void i2c_w_mask(struct sd *sd, + u8 reg, + u8 value, + u8 mask) +{ + int rc; + u8 oldval; + + value &= mask; /* Enforce mask on value */ + rc = i2c_r(sd, reg); + if (rc < 0) + return; + oldval = rc & ~mask; /* Clear the masked bits */ + value |= oldval; /* Set the desired bits */ + i2c_w(sd, reg, value); +} + +/* Temporarily stops OV511 from functioning. Must do this before changing + * registers while the camera is streaming */ +static inline void ov51x_stop(struct sd *sd) +{ + PDEBUG(D_STREAM, "stopping"); + sd->stopped = 1; + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + reg_w(sd, R51x_SYS_RESET, 0x3d); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a); + break; + case BRIDGE_OV519: + reg_w(sd, OV519_R51_RESET1, 0x0f); + reg_w(sd, OV519_R51_RESET1, 0x00); + reg_w(sd, 0x22, 0x00); /* FRAR */ + break; + case BRIDGE_OVFX2: + reg_w_mask(sd, 0x0f, 0x00, 0x02); + break; + case BRIDGE_W9968CF: + reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */ + break; + } +} + +/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not + * actually stopped (for performance). */ +static inline void ov51x_restart(struct sd *sd) +{ + PDEBUG(D_STREAM, "restarting"); + if (!sd->stopped) + return; + sd->stopped = 0; + + /* Reinitialize the stream */ + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + reg_w(sd, R51x_SYS_RESET, 0x00); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + reg_w(sd, 0x2f, 0x80); + reg_w(sd, R51x_SYS_RESET, 0x00); + break; + case BRIDGE_OV519: + reg_w(sd, OV519_R51_RESET1, 0x0f); + reg_w(sd, OV519_R51_RESET1, 0x00); + reg_w(sd, 0x22, 0x1d); /* FRAR */ + break; + case BRIDGE_OVFX2: + reg_w_mask(sd, 0x0f, 0x02, 0x02); + break; + case BRIDGE_W9968CF: + reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */ + break; + } +} + +static void ov51x_set_slave_ids(struct sd *sd, u8 slave); + +/* This does an initial reset of an OmniVision sensor and ensures that I2C + * is synchronized. Returns <0 on failure. + */ +static int init_ov_sensor(struct sd *sd, u8 slave) +{ + int i; + + ov51x_set_slave_ids(sd, slave); + + /* Reset the sensor */ + i2c_w(sd, 0x12, 0x80); + + /* Wait for it to initialize */ + msleep(150); + + for (i = 0; i < i2c_detect_tries; i++) { + if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f && + i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) { + PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i); + return 0; + } + + /* Reset the sensor */ + i2c_w(sd, 0x12, 0x80); + + /* Wait for it to initialize */ + msleep(150); + + /* Dummy read to sync I2C */ + if (i2c_r(sd, 0x00) < 0) + return -1; + } + return -1; +} + +/* Set the read and write slave IDs. The "slave" argument is the write slave, + * and the read slave will be set to (slave + 1). + * This should not be called from outside the i2c I/O functions. + * Sets I2C read and write slave IDs. Returns <0 for error + */ +static void ov51x_set_slave_ids(struct sd *sd, + u8 slave) +{ + switch (sd->bridge) { + case BRIDGE_OVFX2: + reg_w(sd, OVFX2_I2C_ADDR, slave); + return; + case BRIDGE_W9968CF: + sd->sensor_addr = slave; + return; + } + + reg_w(sd, R51x_I2C_W_SID, slave); + reg_w(sd, R51x_I2C_R_SID, slave + 1); +} + +static void write_regvals(struct sd *sd, + const struct ov_regvals *regvals, + int n) +{ + while (--n >= 0) { + reg_w(sd, regvals->reg, regvals->val); + regvals++; + } +} + +static void write_i2c_regvals(struct sd *sd, + const struct ov_i2c_regvals *regvals, + int n) +{ + while (--n >= 0) { + i2c_w(sd, regvals->reg, regvals->val); + regvals++; + } +} + +/**************************************************************************** + * + * OV511 and sensor configuration + * + ***************************************************************************/ + +/* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */ +static void ov_hires_configure(struct sd *sd) +{ + int high, low; + + if (sd->bridge != BRIDGE_OVFX2) { + err("error hires sensors only supported with ovfx2"); + return; + } + + PDEBUG(D_PROBE, "starting ov hires configuration"); + + /* Detect sensor (sub)type */ + high = i2c_r(sd, 0x0a); + low = i2c_r(sd, 0x0b); + /* info("%x, %x", high, low); */ + switch (high) { + case 0x96: + switch (low) { + case 0x40: + PDEBUG(D_PROBE, "Sensor is a OV2610"); + sd->sensor = SEN_OV2610; + return; + case 0x41: + PDEBUG(D_PROBE, "Sensor is a OV2610AE"); + sd->sensor = SEN_OV2610AE; + return; + case 0xb1: + PDEBUG(D_PROBE, "Sensor is a OV9600"); + sd->sensor = SEN_OV9600; + return; + } + break; + case 0x36: + if ((low & 0x0f) == 0x00) { + PDEBUG(D_PROBE, "Sensor is a OV3610"); + sd->sensor = SEN_OV3610; + return; + } + break; + } + err("Error unknown sensor type: %02x%02x", high, low); +} + +/* This initializes the OV8110, OV8610 sensor. The OV8110 uses + * the same register settings as the OV8610, since they are very similar. + */ +static void ov8xx0_configure(struct sd *sd) +{ + int rc; + + PDEBUG(D_PROBE, "starting ov8xx0 configuration"); + + /* Detect sensor (sub)type */ + rc = i2c_r(sd, OV7610_REG_COM_I); + if (rc < 0) { + PDEBUG(D_ERR, "Error detecting sensor type"); + return; + } + if ((rc & 3) == 1) + sd->sensor = SEN_OV8610; + else + err("Unknown image sensor version: %d", rc & 3); +} + +/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses + * the same register settings as the OV7610, since they are very similar. + */ +static void ov7xx0_configure(struct sd *sd) +{ + int rc, high, low; + + PDEBUG(D_PROBE, "starting OV7xx0 configuration"); + + /* Detect sensor (sub)type */ + rc = i2c_r(sd, OV7610_REG_COM_I); + + /* add OV7670 here + * it appears to be wrongly detected as a 7610 by default */ + if (rc < 0) { + PDEBUG(D_ERR, "Error detecting sensor type"); + return; + } + if ((rc & 3) == 3) { + /* quick hack to make OV7670s work */ + high = i2c_r(sd, 0x0a); + low = i2c_r(sd, 0x0b); + /* info("%x, %x", high, low); */ + if (high == 0x76 && (low & 0xf0) == 0x70) { + PDEBUG(D_PROBE, "Sensor is an OV76%02x", low); + sd->sensor = SEN_OV7670; + } else { + PDEBUG(D_PROBE, "Sensor is an OV7610"); + sd->sensor = SEN_OV7610; + } + } else if ((rc & 3) == 1) { + /* I don't know what's different about the 76BE yet. */ + if (i2c_r(sd, 0x15) & 1) { + PDEBUG(D_PROBE, "Sensor is an OV7620AE"); + sd->sensor = SEN_OV7620AE; + } else { + PDEBUG(D_PROBE, "Sensor is an OV76BE"); + sd->sensor = SEN_OV76BE; + } + } else if ((rc & 3) == 0) { + /* try to read product id registers */ + high = i2c_r(sd, 0x0a); + if (high < 0) { + PDEBUG(D_ERR, "Error detecting camera chip PID"); + return; + } + low = i2c_r(sd, 0x0b); + if (low < 0) { + PDEBUG(D_ERR, "Error detecting camera chip VER"); + return; + } + if (high == 0x76) { + switch (low) { + case 0x30: + err("Sensor is an OV7630/OV7635"); + err("7630 is not supported by this driver"); + return; + case 0x40: + PDEBUG(D_PROBE, "Sensor is an OV7645"); + sd->sensor = SEN_OV7640; /* FIXME */ + break; + case 0x45: + PDEBUG(D_PROBE, "Sensor is an OV7645B"); + sd->sensor = SEN_OV7640; /* FIXME */ + break; + case 0x48: + PDEBUG(D_PROBE, "Sensor is an OV7648"); + sd->sensor = SEN_OV7648; + break; + case 0x60: + PDEBUG(D_PROBE, "Sensor is a OV7660"); + sd->sensor = SEN_OV7660; + sd->invert_led = 0; + break; + default: + PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); + return; + } + } else { + PDEBUG(D_PROBE, "Sensor is an OV7620"); + sd->sensor = SEN_OV7620; + } + } else { + err("Unknown image sensor version: %d", rc & 3); + } +} + +/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ +static void ov6xx0_configure(struct sd *sd) +{ + int rc; + PDEBUG(D_PROBE, "starting OV6xx0 configuration"); + + /* Detect sensor (sub)type */ + rc = i2c_r(sd, OV7610_REG_COM_I); + if (rc < 0) { + PDEBUG(D_ERR, "Error detecting sensor type"); + return; + } + + /* Ugh. The first two bits are the version bits, but + * the entire register value must be used. I guess OVT + * underestimated how many variants they would make. */ + switch (rc) { + case 0x00: + sd->sensor = SEN_OV6630; + warn("WARNING: Sensor is an OV66308. Your camera may have"); + warn("been misdetected in previous driver versions."); + break; + case 0x01: + sd->sensor = SEN_OV6620; + PDEBUG(D_PROBE, "Sensor is an OV6620"); + break; + case 0x02: + sd->sensor = SEN_OV6630; + PDEBUG(D_PROBE, "Sensor is an OV66308AE"); + break; + case 0x03: + sd->sensor = SEN_OV66308AF; + PDEBUG(D_PROBE, "Sensor is an OV66308AF"); + break; + case 0x90: + sd->sensor = SEN_OV6630; + warn("WARNING: Sensor is an OV66307. Your camera may have"); + warn("been misdetected in previous driver versions."); + break; + default: + err("FATAL: Unknown sensor version: 0x%02x", rc); + return; + } + + /* Set sensor-specific vars */ + sd->sif = 1; +} + +/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ +static void ov51x_led_control(struct sd *sd, int on) +{ + if (sd->invert_led) + on = !on; + + switch (sd->bridge) { + /* OV511 has no LED control */ + case BRIDGE_OV511PLUS: + reg_w(sd, R511_SYS_LED_CTL, on); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + reg_w_mask(sd, R518_GPIO_OUT, 0x02 * on, 0x02); + break; + case BRIDGE_OV519: + reg_w_mask(sd, OV519_GPIO_DATA_OUT0, on, 1); + break; + } +} + +static void sd_reset_snapshot(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!sd->snapshot_needs_reset) + return; + + /* Note it is important that we clear sd->snapshot_needs_reset, + before actually clearing the snapshot state in the bridge + otherwise we might race with the pkt_scan interrupt handler */ + sd->snapshot_needs_reset = 0; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + reg_w(sd, R51x_SYS_SNAP, 0x02); + reg_w(sd, R51x_SYS_SNAP, 0x00); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + reg_w(sd, R51x_SYS_SNAP, 0x02); /* Reset */ + reg_w(sd, R51x_SYS_SNAP, 0x01); /* Enable */ + break; + case BRIDGE_OV519: + reg_w(sd, R51x_SYS_RESET, 0x40); + reg_w(sd, R51x_SYS_RESET, 0x00); + break; + } +} + +static void ov51x_upload_quan_tables(struct sd *sd) +{ + const unsigned char yQuanTable511[] = { + 0, 1, 1, 2, 2, 3, 3, 4, + 1, 1, 1, 2, 2, 3, 4, 4, + 1, 1, 2, 2, 3, 4, 4, 4, + 2, 2, 2, 3, 4, 4, 4, 4, + 2, 2, 3, 4, 4, 5, 5, 5, + 3, 3, 4, 4, 5, 5, 5, 5, + 3, 4, 4, 4, 5, 5, 5, 5, + 4, 4, 4, 4, 5, 5, 5, 5 + }; + + const unsigned char uvQuanTable511[] = { + 0, 2, 2, 3, 4, 4, 4, 4, + 2, 2, 2, 4, 4, 4, 4, 4, + 2, 2, 3, 4, 4, 4, 4, 4, + 3, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4 + }; + + /* OV518 quantization tables are 8x4 (instead of 8x8) */ + const unsigned char yQuanTable518[] = { + 5, 4, 5, 6, 6, 7, 7, 7, + 5, 5, 5, 5, 6, 7, 7, 7, + 6, 6, 6, 6, 7, 7, 7, 8, + 7, 7, 6, 7, 7, 7, 8, 8 + }; + const unsigned char uvQuanTable518[] = { + 6, 6, 6, 7, 7, 7, 7, 7, + 6, 6, 6, 7, 7, 7, 7, 7, + 6, 6, 6, 7, 7, 7, 7, 8, + 7, 7, 7, 7, 7, 7, 8, 8 + }; + + const unsigned char *pYTable, *pUVTable; + unsigned char val0, val1; + int i, size, reg = R51x_COMP_LUT_BEGIN; + + PDEBUG(D_PROBE, "Uploading quantization tables"); + + if (sd->bridge == BRIDGE_OV511 || sd->bridge == BRIDGE_OV511PLUS) { + pYTable = yQuanTable511; + pUVTable = uvQuanTable511; + size = 32; + } else { + pYTable = yQuanTable518; + pUVTable = uvQuanTable518; + size = 16; + } + + for (i = 0; i < size; i++) { + val0 = *pYTable++; + val1 = *pYTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + reg_w(sd, reg, val0); + + val0 = *pUVTable++; + val1 = *pUVTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + reg_w(sd, reg + size, val0); + + reg++; + } +} + +/* This initializes the OV511/OV511+ and the sensor */ +static void ov511_configure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* For 511 and 511+ */ + const struct ov_regvals init_511[] = { + { R51x_SYS_RESET, 0x7f }, + { R51x_SYS_INIT, 0x01 }, + { R51x_SYS_RESET, 0x7f }, + { R51x_SYS_INIT, 0x01 }, + { R51x_SYS_RESET, 0x3f }, + { R51x_SYS_INIT, 0x01 }, + { R51x_SYS_RESET, 0x3d }, + }; + + const struct ov_regvals norm_511[] = { + { R511_DRAM_FLOW_CTL, 0x01 }, + { R51x_SYS_SNAP, 0x00 }, + { R51x_SYS_SNAP, 0x02 }, + { R51x_SYS_SNAP, 0x00 }, + { R511_FIFO_OPTS, 0x1f }, + { R511_COMP_EN, 0x00 }, + { R511_COMP_LUT_EN, 0x03 }, + }; + + const struct ov_regvals norm_511_p[] = { + { R511_DRAM_FLOW_CTL, 0xff }, + { R51x_SYS_SNAP, 0x00 }, + { R51x_SYS_SNAP, 0x02 }, + { R51x_SYS_SNAP, 0x00 }, + { R511_FIFO_OPTS, 0xff }, + { R511_COMP_EN, 0x00 }, + { R511_COMP_LUT_EN, 0x03 }, + }; + + const struct ov_regvals compress_511[] = { + { 0x70, 0x1f }, + { 0x71, 0x05 }, + { 0x72, 0x06 }, + { 0x73, 0x06 }, + { 0x74, 0x14 }, + { 0x75, 0x03 }, + { 0x76, 0x04 }, + { 0x77, 0x04 }, + }; + + PDEBUG(D_PROBE, "Device custom id %x", reg_r(sd, R51x_SYS_CUST_ID)); + + write_regvals(sd, init_511, ARRAY_SIZE(init_511)); + + switch (sd->bridge) { + case BRIDGE_OV511: + write_regvals(sd, norm_511, ARRAY_SIZE(norm_511)); + break; + case BRIDGE_OV511PLUS: + write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p)); + break; + } + + /* Init compression */ + write_regvals(sd, compress_511, ARRAY_SIZE(compress_511)); + + ov51x_upload_quan_tables(sd); +} + +/* This initializes the OV518/OV518+ and the sensor */ +static void ov518_configure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* For 518 and 518+ */ + const struct ov_regvals init_518[] = { + { R51x_SYS_RESET, 0x40 }, + { R51x_SYS_INIT, 0xe1 }, + { R51x_SYS_RESET, 0x3e }, + { R51x_SYS_INIT, 0xe1 }, + { R51x_SYS_RESET, 0x00 }, + { R51x_SYS_INIT, 0xe1 }, + { 0x46, 0x00 }, + { 0x5d, 0x03 }, + }; + + const struct ov_regvals norm_518[] = { + { R51x_SYS_SNAP, 0x02 }, /* Reset */ + { R51x_SYS_SNAP, 0x01 }, /* Enable */ + { 0x31, 0x0f }, + { 0x5d, 0x03 }, + { 0x24, 0x9f }, + { 0x25, 0x90 }, + { 0x20, 0x00 }, + { 0x51, 0x04 }, + { 0x71, 0x19 }, + { 0x2f, 0x80 }, + }; + + const struct ov_regvals norm_518_p[] = { + { R51x_SYS_SNAP, 0x02 }, /* Reset */ + { R51x_SYS_SNAP, 0x01 }, /* Enable */ + { 0x31, 0x0f }, + { 0x5d, 0x03 }, + { 0x24, 0x9f }, + { 0x25, 0x90 }, + { 0x20, 0x60 }, + { 0x51, 0x02 }, + { 0x71, 0x19 }, + { 0x40, 0xff }, + { 0x41, 0x42 }, + { 0x46, 0x00 }, + { 0x33, 0x04 }, + { 0x21, 0x19 }, + { 0x3f, 0x10 }, + { 0x2f, 0x80 }, + }; + + /* First 5 bits of custom ID reg are a revision ID on OV518 */ + PDEBUG(D_PROBE, "Device revision %d", + 0x1f & reg_r(sd, R51x_SYS_CUST_ID)); + + write_regvals(sd, init_518, ARRAY_SIZE(init_518)); + + /* Set LED GPIO pin to output mode */ + reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02); + + switch (sd->bridge) { + case BRIDGE_OV518: + write_regvals(sd, norm_518, ARRAY_SIZE(norm_518)); + break; + case BRIDGE_OV518PLUS: + write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p)); + break; + } + + ov51x_upload_quan_tables(sd); + + reg_w(sd, 0x2f, 0x80); +} + +static void ov519_configure(struct sd *sd) +{ + static const struct ov_regvals init_519[] = { + { 0x5a, 0x6d }, /* EnableSystem */ + { 0x53, 0x9b }, /* don't enable the microcontroller */ + { OV519_R54_EN_CLK1, 0xff }, /* set bit2 to enable jpeg */ + { 0x5d, 0x03 }, + { 0x49, 0x01 }, + { 0x48, 0x00 }, + /* Set LED pin to output mode. Bit 4 must be cleared or sensor + * detection will fail. This deserves further investigation. */ + { OV519_GPIO_IO_CTRL0, 0xee }, + { OV519_R51_RESET1, 0x0f }, + { OV519_R51_RESET1, 0x00 }, + { 0x22, 0x00 }, + /* windows reads 0x55 at this point*/ + }; + + write_regvals(sd, init_519, ARRAY_SIZE(init_519)); +} + +static void ovfx2_configure(struct sd *sd) +{ + static const struct ov_regvals init_fx2[] = { + { 0x00, 0x60 }, + { 0x02, 0x01 }, + { 0x0f, 0x1d }, + { 0xe9, 0x82 }, + { 0xea, 0xc7 }, + { 0xeb, 0x10 }, + { 0xec, 0xf6 }, + }; + + sd->stopped = 1; + + write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2)); +} + +/* set the mode */ +/* This function works for ov7660 only */ +static void ov519_set_mode(struct sd *sd) +{ + static const struct ov_regvals bridge_ov7660[2][10] = { + {{0x10, 0x14}, {0x11, 0x1e}, {0x12, 0x00}, {0x13, 0x00}, + {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c}, + {0x25, 0x01}, {0x26, 0x00}}, + {{0x10, 0x28}, {0x11, 0x3c}, {0x12, 0x00}, {0x13, 0x00}, + {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c}, + {0x25, 0x03}, {0x26, 0x00}} + }; + static const struct ov_i2c_regvals sensor_ov7660[2][3] = { + {{0x12, 0x00}, {0x24, 0x00}, {0x0c, 0x0c}}, + {{0x12, 0x00}, {0x04, 0x00}, {0x0c, 0x00}} + }; + static const struct ov_i2c_regvals sensor_ov7660_2[] = { + {OV7670_R17_HSTART, 0x13}, + {OV7670_R18_HSTOP, 0x01}, + {OV7670_R32_HREF, 0x92}, + {OV7670_R19_VSTART, 0x02}, + {OV7670_R1A_VSTOP, 0x7a}, + {OV7670_R03_VREF, 0x00}, +/* {0x33, 0x00}, */ +/* {0x34, 0x07}, */ +/* {0x36, 0x00}, */ +/* {0x6b, 0x0a}, */ + }; + + write_regvals(sd, bridge_ov7660[sd->gspca_dev.curr_mode], + ARRAY_SIZE(bridge_ov7660[0])); + write_i2c_regvals(sd, sensor_ov7660[sd->gspca_dev.curr_mode], + ARRAY_SIZE(sensor_ov7660[0])); + write_i2c_regvals(sd, sensor_ov7660_2, + ARRAY_SIZE(sensor_ov7660_2)); +} + +/* set the frame rate */ +/* This function works for sensors ov7640, ov7648 ov7660 and ov7670 only */ +static void ov519_set_fr(struct sd *sd) +{ + int fr; + u8 clock; + /* frame rate table with indices: + * - mode = 0: 320x240, 1: 640x480 + * - fr rate = 0: 30, 1: 25, 2: 20, 3: 15, 4: 10, 5: 5 + * - reg = 0: bridge a4, 1: bridge 23, 2: sensor 11 (clock) + */ + static const u8 fr_tb[2][6][3] = { + {{0x04, 0xff, 0x00}, + {0x04, 0x1f, 0x00}, + {0x04, 0x1b, 0x00}, + {0x04, 0x15, 0x00}, + {0x04, 0x09, 0x00}, + {0x04, 0x01, 0x00}}, + {{0x0c, 0xff, 0x00}, + {0x0c, 0x1f, 0x00}, + {0x0c, 0x1b, 0x00}, + {0x04, 0xff, 0x01}, + {0x04, 0x1f, 0x01}, + {0x04, 0x1b, 0x01}}, + }; + + if (frame_rate > 0) + sd->frame_rate = frame_rate; + if (sd->frame_rate >= 30) + fr = 0; + else if (sd->frame_rate >= 25) + fr = 1; + else if (sd->frame_rate >= 20) + fr = 2; + else if (sd->frame_rate >= 15) + fr = 3; + else if (sd->frame_rate >= 10) + fr = 4; + else + fr = 5; + reg_w(sd, 0xa4, fr_tb[sd->gspca_dev.curr_mode][fr][0]); + reg_w(sd, 0x23, fr_tb[sd->gspca_dev.curr_mode][fr][1]); + clock = fr_tb[sd->gspca_dev.curr_mode][fr][2]; + if (sd->sensor == SEN_OV7660) + clock |= 0x80; /* enable double clock */ + ov518_i2c_w(sd, OV7670_R11_CLKRC, clock); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + i2c_w_mask(sd, 0x13, sd->ctrls[AUTOGAIN].val ? 0x05 : 0x00, 0x05); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + + sd->bridge = id->driver_info & BRIDGE_MASK; + sd->invert_led = (id->driver_info & BRIDGE_INVERT_LED) != 0; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + cam->cam_mode = ov511_vga_mode; + cam->nmodes = ARRAY_SIZE(ov511_vga_mode); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + cam->cam_mode = ov518_vga_mode; + cam->nmodes = ARRAY_SIZE(ov518_vga_mode); + break; + case BRIDGE_OV519: + cam->cam_mode = ov519_vga_mode; + cam->nmodes = ARRAY_SIZE(ov519_vga_mode); + sd->invert_led = !sd->invert_led; + break; + case BRIDGE_OVFX2: + cam->cam_mode = ov519_vga_mode; + cam->nmodes = ARRAY_SIZE(ov519_vga_mode); + cam->bulk_size = OVFX2_BULK_SIZE; + cam->bulk_nurbs = MAX_NURBS; + cam->bulk = 1; + break; + case BRIDGE_W9968CF: + cam->cam_mode = w9968cf_vga_mode; + cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode); + cam->reverse_alts = 1; + break; + } + + gspca_dev->cam.ctrls = sd->ctrls; + sd->quality = QUALITY_DEF; + sd->frame_rate = 15; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + ov511_configure(gspca_dev); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + ov518_configure(gspca_dev); + break; + case BRIDGE_OV519: + ov519_configure(sd); + break; + case BRIDGE_OVFX2: + ovfx2_configure(sd); + break; + case BRIDGE_W9968CF: + w9968cf_configure(sd); + break; + } + + /* The OV519 must be more aggressive about sensor detection since + * I2C write will never fail if the sensor is not present. We have + * to try to initialize the sensor to detect its presence */ + sd->sensor = -1; + + /* Test for 76xx */ + if (init_ov_sensor(sd, OV7xx0_SID) >= 0) { + ov7xx0_configure(sd); + + /* Test for 6xx0 */ + } else if (init_ov_sensor(sd, OV6xx0_SID) >= 0) { + ov6xx0_configure(sd); + + /* Test for 8xx0 */ + } else if (init_ov_sensor(sd, OV8xx0_SID) >= 0) { + ov8xx0_configure(sd); + + /* Test for 3xxx / 2xxx */ + } else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) { + ov_hires_configure(sd); + } else { + err("Can't determine sensor slave IDs"); + goto error; + } + + if (sd->sensor < 0) + goto error; + + ov51x_led_control(sd, 0); /* turn LED off */ + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + if (sd->sif) { + cam->cam_mode = ov511_sif_mode; + cam->nmodes = ARRAY_SIZE(ov511_sif_mode); + } + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + if (sd->sif) { + cam->cam_mode = ov518_sif_mode; + cam->nmodes = ARRAY_SIZE(ov518_sif_mode); + } + break; + case BRIDGE_OV519: + if (sd->sif) { + cam->cam_mode = ov519_sif_mode; + cam->nmodes = ARRAY_SIZE(ov519_sif_mode); + } + break; + case BRIDGE_OVFX2: + switch (sd->sensor) { + case SEN_OV2610: + case SEN_OV2610AE: + cam->cam_mode = ovfx2_ov2610_mode; + cam->nmodes = ARRAY_SIZE(ovfx2_ov2610_mode); + break; + case SEN_OV3610: + cam->cam_mode = ovfx2_ov3610_mode; + cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode); + break; + case SEN_OV9600: + cam->cam_mode = ovfx2_ov9600_mode; + cam->nmodes = ARRAY_SIZE(ovfx2_ov9600_mode); + break; + default: + if (sd->sif) { + cam->cam_mode = ov519_sif_mode; + cam->nmodes = ARRAY_SIZE(ov519_sif_mode); + } + break; + } + break; + case BRIDGE_W9968CF: + if (sd->sif) + cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode) - 1; + + /* w9968cf needs initialisation once the sensor is known */ + w9968cf_init(sd); + break; + } + + gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; + + /* initialize the sensor */ + switch (sd->sensor) { + case SEN_OV2610: + write_i2c_regvals(sd, norm_2610, ARRAY_SIZE(norm_2610)); + + /* Enable autogain, autoexpo, awb, bandfilter */ + i2c_w_mask(sd, 0x13, 0x27, 0x27); + break; + case SEN_OV2610AE: + write_i2c_regvals(sd, norm_2610ae, ARRAY_SIZE(norm_2610ae)); + + /* enable autoexpo */ + i2c_w_mask(sd, 0x13, 0x05, 0x05); + break; + case SEN_OV3610: + write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b)); + + /* Enable autogain, autoexpo, awb, bandfilter */ + i2c_w_mask(sd, 0x13, 0x27, 0x27); + break; + case SEN_OV6620: + write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)); + break; + case SEN_OV6630: + case SEN_OV66308AF: + sd->ctrls[CONTRAST].def = 200; + /* The default is too low for the ov6630 */ + write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)); + break; + default: +/* case SEN_OV7610: */ +/* case SEN_OV76BE: */ + write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)); + i2c_w_mask(sd, 0x0e, 0x00, 0x40); + break; + case SEN_OV7620: + case SEN_OV7620AE: + write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)); + break; + case SEN_OV7640: + case SEN_OV7648: + write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)); + break; + case SEN_OV7660: + i2c_w(sd, OV7670_R12_COM7, OV7670_COM7_RESET); + msleep(14); + reg_w(sd, OV519_R57_SNAPSHOT, 0x23); + write_regvals(sd, init_519_ov7660, + ARRAY_SIZE(init_519_ov7660)); + write_i2c_regvals(sd, norm_7660, ARRAY_SIZE(norm_7660)); + sd->gspca_dev.curr_mode = 1; /* 640x480 */ + ov519_set_mode(sd); + ov519_set_fr(sd); + sd->ctrls[COLORS].max = 4; /* 0..4 */ + sd->ctrls[COLORS].val = + sd->ctrls[COLORS].def = 2; + setcolors(gspca_dev); + sd->ctrls[CONTRAST].max = 6; /* 0..6 */ + sd->ctrls[CONTRAST].val = + sd->ctrls[CONTRAST].def = 3; + setcontrast(gspca_dev); + sd->ctrls[BRIGHTNESS].max = 6; /* 0..6 */ + sd->ctrls[BRIGHTNESS].val = + sd->ctrls[BRIGHTNESS].def = 3; + setbrightness(gspca_dev); + sd_reset_snapshot(gspca_dev); + ov51x_restart(sd); + ov51x_stop(sd); /* not in win traces */ + ov51x_led_control(sd, 0); + break; + case SEN_OV7670: + sd->ctrls[FREQ].max = 3; /* auto */ + sd->ctrls[FREQ].def = 3; + write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)); + break; + case SEN_OV8610: + write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)); + break; + case SEN_OV9600: + write_i2c_regvals(sd, norm_9600, ARRAY_SIZE(norm_9600)); + + /* enable autoexpo */ +/* i2c_w_mask(sd, 0x13, 0x05, 0x05); */ + break; + } + return gspca_dev->usb_err; +error: + PDEBUG(D_ERR, "OV519 Config failed"); + return -EINVAL; +} + +/* function called at start time before URB creation */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->bridge) { + case BRIDGE_OVFX2: + if (gspca_dev->width != 800) + gspca_dev->cam.bulk_size = OVFX2_BULK_SIZE; + else + gspca_dev->cam.bulk_size = 7 * 4096; + break; + } + return 0; +} + +/* Set up the OV511/OV511+ with the given image parameters. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static void ov511_mode_init_regs(struct sd *sd) +{ + int hsegs, vsegs, packet_size, fps, needed; + int interlaced = 0; + struct usb_host_interface *alt; + struct usb_interface *intf; + + intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) { + err("Couldn't get altsetting"); + sd->gspca_dev.usb_err = -EIO; + return; + } + + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5); + + reg_w(sd, R511_CAM_UV_EN, 0x01); + reg_w(sd, R511_SNAP_UV_EN, 0x01); + reg_w(sd, R511_SNAP_OPTS, 0x03); + + /* Here I'm assuming that snapshot size == image size. + * I hope that's always true. --claudio + */ + hsegs = (sd->gspca_dev.width >> 3) - 1; + vsegs = (sd->gspca_dev.height >> 3) - 1; + + reg_w(sd, R511_CAM_PXCNT, hsegs); + reg_w(sd, R511_CAM_LNCNT, vsegs); + reg_w(sd, R511_CAM_PXDIV, 0x00); + reg_w(sd, R511_CAM_LNDIV, 0x00); + + /* YUV420, low pass filter on */ + reg_w(sd, R511_CAM_OPTS, 0x03); + + /* Snapshot additions */ + reg_w(sd, R511_SNAP_PXCNT, hsegs); + reg_w(sd, R511_SNAP_LNCNT, vsegs); + reg_w(sd, R511_SNAP_PXDIV, 0x00); + reg_w(sd, R511_SNAP_LNDIV, 0x00); + + /******** Set the framerate ********/ + if (frame_rate > 0) + sd->frame_rate = frame_rate; + + switch (sd->sensor) { + case SEN_OV6620: + /* No framerate control, doesn't like higher rates yet */ + sd->clockdiv = 3; + break; + + /* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed + for more sensors we need to do this for them too */ + case SEN_OV7620: + case SEN_OV7620AE: + case SEN_OV7640: + case SEN_OV7648: + case SEN_OV76BE: + if (sd->gspca_dev.width == 320) + interlaced = 1; + /* Fall through */ + case SEN_OV6630: + case SEN_OV7610: + case SEN_OV7670: + switch (sd->frame_rate) { + case 30: + case 25: + /* Not enough bandwidth to do 640x480 @ 30 fps */ + if (sd->gspca_dev.width != 640) { + sd->clockdiv = 0; + break; + } + /* Fall through for 640x480 case */ + default: +/* case 20: */ +/* case 15: */ + sd->clockdiv = 1; + break; + case 10: + sd->clockdiv = 2; + break; + case 5: + sd->clockdiv = 5; + break; + } + if (interlaced) { + sd->clockdiv = (sd->clockdiv + 1) * 2 - 1; + /* Higher then 10 does not work */ + if (sd->clockdiv > 10) + sd->clockdiv = 10; + } + break; + + case SEN_OV8610: + /* No framerate control ?? */ + sd->clockdiv = 0; + break; + } + + /* Check if we have enough bandwidth to disable compression */ + fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1; + needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2; + /* 1400 is a conservative estimate of the max nr of isoc packets/sec */ + if (needed > 1400 * packet_size) { + /* Enable Y and UV quantization and compression */ + reg_w(sd, R511_COMP_EN, 0x07); + reg_w(sd, R511_COMP_LUT_EN, 0x03); + } else { + reg_w(sd, R511_COMP_EN, 0x06); + reg_w(sd, R511_COMP_LUT_EN, 0x00); + } + + reg_w(sd, R51x_SYS_RESET, OV511_RESET_OMNICE); + reg_w(sd, R51x_SYS_RESET, 0); +} + +/* Sets up the OV518/OV518+ with the given image parameters + * + * OV518 needs a completely different approach, until we can figure out what + * the individual registers do. Also, only 15 FPS is supported now. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static void ov518_mode_init_regs(struct sd *sd) +{ + int hsegs, vsegs, packet_size; + struct usb_host_interface *alt; + struct usb_interface *intf; + + intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) { + err("Couldn't get altsetting"); + sd->gspca_dev.usb_err = -EIO; + return; + } + + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2); + + /******** Set the mode ********/ + reg_w(sd, 0x2b, 0); + reg_w(sd, 0x2c, 0); + reg_w(sd, 0x2d, 0); + reg_w(sd, 0x2e, 0); + reg_w(sd, 0x3b, 0); + reg_w(sd, 0x3c, 0); + reg_w(sd, 0x3d, 0); + reg_w(sd, 0x3e, 0); + + if (sd->bridge == BRIDGE_OV518) { + /* Set 8-bit (YVYU) input format */ + reg_w_mask(sd, 0x20, 0x08, 0x08); + + /* Set 12-bit (4:2:0) output format */ + reg_w_mask(sd, 0x28, 0x80, 0xf0); + reg_w_mask(sd, 0x38, 0x80, 0xf0); + } else { + reg_w(sd, 0x28, 0x80); + reg_w(sd, 0x38, 0x80); + } + + hsegs = sd->gspca_dev.width / 16; + vsegs = sd->gspca_dev.height / 4; + + reg_w(sd, 0x29, hsegs); + reg_w(sd, 0x2a, vsegs); + + reg_w(sd, 0x39, hsegs); + reg_w(sd, 0x3a, vsegs); + + /* Windows driver does this here; who knows why */ + reg_w(sd, 0x2f, 0x80); + + /******** Set the framerate ********/ + sd->clockdiv = 1; + + /* Mode independent, but framerate dependent, regs */ + /* 0x51: Clock divider; Only works on some cams which use 2 crystals */ + reg_w(sd, 0x51, 0x04); + reg_w(sd, 0x22, 0x18); + reg_w(sd, 0x23, 0xff); + + if (sd->bridge == BRIDGE_OV518PLUS) { + switch (sd->sensor) { + case SEN_OV7620AE: + if (sd->gspca_dev.width == 320) { + reg_w(sd, 0x20, 0x00); + reg_w(sd, 0x21, 0x19); + } else { + reg_w(sd, 0x20, 0x60); + reg_w(sd, 0x21, 0x1f); + } + break; + case SEN_OV7620: + reg_w(sd, 0x20, 0x00); + reg_w(sd, 0x21, 0x19); + break; + default: + reg_w(sd, 0x21, 0x19); + } + } else + reg_w(sd, 0x71, 0x17); /* Compression-related? */ + + /* FIXME: Sensor-specific */ + /* Bit 5 is what matters here. Of course, it is "reserved" */ + i2c_w(sd, 0x54, 0x23); + + reg_w(sd, 0x2f, 0x80); + + if (sd->bridge == BRIDGE_OV518PLUS) { + reg_w(sd, 0x24, 0x94); + reg_w(sd, 0x25, 0x90); + ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(sd, 0xc6, 540, 2); /* 21ch */ + ov518_reg_w32(sd, 0xc7, 540, 2); /* 21ch */ + ov518_reg_w32(sd, 0xc8, 108, 2); /* 6ch */ + ov518_reg_w32(sd, 0xca, 131098, 3); /* 2001ah */ + ov518_reg_w32(sd, 0xcb, 532, 2); /* 214h */ + ov518_reg_w32(sd, 0xcc, 2400, 2); /* 960h */ + ov518_reg_w32(sd, 0xcd, 32, 2); /* 20h */ + ov518_reg_w32(sd, 0xce, 608, 2); /* 260h */ + } else { + reg_w(sd, 0x24, 0x9f); + reg_w(sd, 0x25, 0x90); + ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(sd, 0xc6, 381, 2); /* 17dh */ + ov518_reg_w32(sd, 0xc7, 381, 2); /* 17dh */ + ov518_reg_w32(sd, 0xc8, 128, 2); /* 80h */ + ov518_reg_w32(sd, 0xca, 183331, 3); /* 2cc23h */ + ov518_reg_w32(sd, 0xcb, 746, 2); /* 2eah */ + ov518_reg_w32(sd, 0xcc, 1750, 2); /* 6d6h */ + ov518_reg_w32(sd, 0xcd, 45, 2); /* 2dh */ + ov518_reg_w32(sd, 0xce, 851, 2); /* 353h */ + } + + reg_w(sd, 0x2f, 0x80); +} + +/* Sets up the OV519 with the given image parameters + * + * OV519 needs a completely different approach, until we can figure out what + * the individual registers do. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static void ov519_mode_init_regs(struct sd *sd) +{ + static const struct ov_regvals mode_init_519_ov7670[] = { + { 0x5d, 0x03 }, /* Turn off suspend mode */ + { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */ + { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */ + { 0xa2, 0x20 }, /* a2-a5 are undocumented */ + { 0xa3, 0x18 }, + { 0xa4, 0x04 }, + { 0xa5, 0x28 }, + { 0x37, 0x00 }, /* SetUsbInit */ + { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ + /* Enable both fields, YUV Input, disable defect comp (why?) */ + { 0x20, 0x0c }, + { 0x21, 0x38 }, + { 0x22, 0x1d }, + { 0x17, 0x50 }, /* undocumented */ + { 0x37, 0x00 }, /* undocumented */ + { 0x40, 0xff }, /* I2C timeout counter */ + { 0x46, 0x00 }, /* I2C clock prescaler */ + { 0x59, 0x04 }, /* new from windrv 090403 */ + { 0xff, 0x00 }, /* undocumented */ + /* windows reads 0x55 at this point, why? */ + }; + + static const struct ov_regvals mode_init_519[] = { + { 0x5d, 0x03 }, /* Turn off suspend mode */ + { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */ + { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */ + { 0xa2, 0x20 }, /* a2-a5 are undocumented */ + { 0xa3, 0x18 }, + { 0xa4, 0x04 }, + { 0xa5, 0x28 }, + { 0x37, 0x00 }, /* SetUsbInit */ + { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ + /* Enable both fields, YUV Input, disable defect comp (why?) */ + { 0x22, 0x1d }, + { 0x17, 0x50 }, /* undocumented */ + { 0x37, 0x00 }, /* undocumented */ + { 0x40, 0xff }, /* I2C timeout counter */ + { 0x46, 0x00 }, /* I2C clock prescaler */ + { 0x59, 0x04 }, /* new from windrv 090403 */ + { 0xff, 0x00 }, /* undocumented */ + /* windows reads 0x55 at this point, why? */ + }; + + /******** Set the mode ********/ + switch (sd->sensor) { + default: + write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519)); + if (sd->sensor == SEN_OV7640 || + sd->sensor == SEN_OV7648) { + /* Select 8-bit input mode */ + reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10); + } + break; + case SEN_OV7660: + return; /* done by ov519_set_mode/fr() */ + case SEN_OV7670: + write_regvals(sd, mode_init_519_ov7670, + ARRAY_SIZE(mode_init_519_ov7670)); + break; + } + + reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4); + reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.height >> 3); + if (sd->sensor == SEN_OV7670 && + sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv) + reg_w(sd, OV519_R12_X_OFFSETL, 0x04); + else if (sd->sensor == SEN_OV7648 && + sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv) + reg_w(sd, OV519_R12_X_OFFSETL, 0x01); + else + reg_w(sd, OV519_R12_X_OFFSETL, 0x00); + reg_w(sd, OV519_R13_X_OFFSETH, 0x00); + reg_w(sd, OV519_R14_Y_OFFSETL, 0x00); + reg_w(sd, OV519_R15_Y_OFFSETH, 0x00); + reg_w(sd, OV519_R16_DIVIDER, 0x00); + reg_w(sd, OV519_R25_FORMAT, 0x03); /* YUV422 */ + reg_w(sd, 0x26, 0x00); /* Undocumented */ + + /******** Set the framerate ********/ + if (frame_rate > 0) + sd->frame_rate = frame_rate; + +/* FIXME: These are only valid at the max resolution. */ + sd->clockdiv = 0; + switch (sd->sensor) { + case SEN_OV7640: + case SEN_OV7648: + switch (sd->frame_rate) { + default: +/* case 30: */ + reg_w(sd, 0xa4, 0x0c); + reg_w(sd, 0x23, 0xff); + break; + case 25: + reg_w(sd, 0xa4, 0x0c); + reg_w(sd, 0x23, 0x1f); + break; + case 20: + reg_w(sd, 0xa4, 0x0c); + reg_w(sd, 0x23, 0x1b); + break; + case 15: + reg_w(sd, 0xa4, 0x04); + reg_w(sd, 0x23, 0xff); + sd->clockdiv = 1; + break; + case 10: + reg_w(sd, 0xa4, 0x04); + reg_w(sd, 0x23, 0x1f); + sd->clockdiv = 1; + break; + case 5: + reg_w(sd, 0xa4, 0x04); + reg_w(sd, 0x23, 0x1b); + sd->clockdiv = 1; + break; + } + break; + case SEN_OV8610: + switch (sd->frame_rate) { + default: /* 15 fps */ +/* case 15: */ + reg_w(sd, 0xa4, 0x06); + reg_w(sd, 0x23, 0xff); + break; + case 10: + reg_w(sd, 0xa4, 0x06); + reg_w(sd, 0x23, 0x1f); + break; + case 5: + reg_w(sd, 0xa4, 0x06); + reg_w(sd, 0x23, 0x1b); + break; + } + break; + case SEN_OV7670: /* guesses, based on 7640 */ + PDEBUG(D_STREAM, "Setting framerate to %d fps", + (sd->frame_rate == 0) ? 15 : sd->frame_rate); + reg_w(sd, 0xa4, 0x10); + switch (sd->frame_rate) { + case 30: + reg_w(sd, 0x23, 0xff); + break; + case 20: + reg_w(sd, 0x23, 0x1b); + break; + default: +/* case 15: */ + reg_w(sd, 0x23, 0xff); + sd->clockdiv = 1; + break; + } + break; + } +} + +static void mode_init_ov_sensor_regs(struct sd *sd) +{ + struct gspca_dev *gspca_dev; + int qvga, xstart, xend, ystart, yend; + u8 v; + + gspca_dev = &sd->gspca_dev; + qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1; + + /******** Mode (VGA/QVGA) and sensor specific regs ********/ + switch (sd->sensor) { + case SEN_OV2610: + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); + i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); + i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); + i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); + i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); + i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); + return; + case SEN_OV2610AE: { + u8 v; + + /* frame rates: + * 10fps / 5 fps for 1600x1200 + * 40fps / 20fps for 800x600 + */ + v = 80; + if (qvga) { + if (sd->frame_rate < 25) + v = 0x81; + } else { + if (sd->frame_rate < 10) + v = 0x81; + } + i2c_w(sd, 0x11, v); + i2c_w(sd, 0x12, qvga ? 0x60 : 0x20); + return; + } + case SEN_OV3610: + if (qvga) { + xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4); + ystart = (776 - gspca_dev->height) / 2; + } else { + xstart = (2076 - gspca_dev->width) / 2 + (0x10 << 4); + ystart = (1544 - gspca_dev->height) / 2; + } + xend = xstart + gspca_dev->width; + yend = ystart + gspca_dev->height; + /* Writing to the COMH register resets the other windowing regs + to their default values, so we must do this first. */ + i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0xf0); + i2c_w_mask(sd, 0x32, + (((xend >> 1) & 7) << 3) | ((xstart >> 1) & 7), + 0x3f); + i2c_w_mask(sd, 0x03, + (((yend >> 1) & 3) << 2) | ((ystart >> 1) & 3), + 0x0f); + i2c_w(sd, 0x17, xstart >> 4); + i2c_w(sd, 0x18, xend >> 4); + i2c_w(sd, 0x19, ystart >> 3); + i2c_w(sd, 0x1a, yend >> 3); + return; + case SEN_OV8610: + /* For OV8610 qvga means qsvga */ + i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5); + i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ + i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ + i2c_w_mask(sd, 0x2d, 0x00, 0x40); /* from windrv 090403 */ + i2c_w_mask(sd, 0x28, 0x20, 0x20); /* progressive mode on */ + break; + case SEN_OV7610: + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e); + i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ + i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ + break; + case SEN_OV7620: + case SEN_OV7620AE: + case SEN_OV76BE: + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); + i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); + i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); + i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); + i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0); + i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); + i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ + i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ + if (sd->sensor == SEN_OV76BE) + i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e); + break; + case SEN_OV7640: + case SEN_OV7648: + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); + /* Setting this undocumented bit in qvga mode removes a very + annoying vertical shaking of the image */ + i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); + /* Unknown */ + i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); + /* Allow higher automatic gain (to allow higher framerates) */ + i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); + i2c_w_mask(sd, 0x12, 0x04, 0x04); /* AWB: 1 */ + break; + case SEN_OV7670: + /* set COM7_FMT_VGA or COM7_FMT_QVGA + * do we need to set anything else? + * HSTART etc are set in set_ov_sensor_window itself */ + i2c_w_mask(sd, OV7670_R12_COM7, + qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA, + OV7670_COM7_FMT_MASK); + i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ + i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_AWB, + OV7670_COM8_AWB); + if (qvga) { /* QVGA from ov7670.c by + * Jonathan Corbet */ + xstart = 164; + xend = 28; + ystart = 14; + yend = 494; + } else { /* VGA */ + xstart = 158; + xend = 14; + ystart = 10; + yend = 490; + } + /* OV7670 hardware window registers are split across + * multiple locations */ + i2c_w(sd, OV7670_R17_HSTART, xstart >> 3); + i2c_w(sd, OV7670_R18_HSTOP, xend >> 3); + v = i2c_r(sd, OV7670_R32_HREF); + v = (v & 0xc0) | ((xend & 0x7) << 3) | (xstart & 0x07); + msleep(10); /* need to sleep between read and write to + * same reg! */ + i2c_w(sd, OV7670_R32_HREF, v); + + i2c_w(sd, OV7670_R19_VSTART, ystart >> 2); + i2c_w(sd, OV7670_R1A_VSTOP, yend >> 2); + v = i2c_r(sd, OV7670_R03_VREF); + v = (v & 0xc0) | ((yend & 0x3) << 2) | (ystart & 0x03); + msleep(10); /* need to sleep between read and write to + * same reg! */ + i2c_w(sd, OV7670_R03_VREF, v); + break; + case SEN_OV6620: + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */ + i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ + break; + case SEN_OV6630: + case SEN_OV66308AF: + i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); + i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ + break; + case SEN_OV9600: { + const struct ov_i2c_regvals *vals; + static const struct ov_i2c_regvals sxga_15[] = { + {0x11, 0x80}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75} + }; + static const struct ov_i2c_regvals sxga_7_5[] = { + {0x11, 0x81}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75} + }; + static const struct ov_i2c_regvals vga_30[] = { + {0x11, 0x81}, {0x14, 0x7e}, {0x24, 0x70}, {0x25, 0x60} + }; + static const struct ov_i2c_regvals vga_15[] = { + {0x11, 0x83}, {0x14, 0x3e}, {0x24, 0x80}, {0x25, 0x70} + }; + + /* frame rates: + * 15fps / 7.5 fps for 1280x1024 + * 30fps / 15fps for 640x480 + */ + i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0x40); + if (qvga) + vals = sd->frame_rate < 30 ? vga_15 : vga_30; + else + vals = sd->frame_rate < 15 ? sxga_7_5 : sxga_15; + write_i2c_regvals(sd, vals, ARRAY_SIZE(sxga_15)); + return; + } + default: + return; + } + + /******** Clock programming ********/ + i2c_w(sd, 0x11, sd->clockdiv); +} + +/* this function works for bridge ov519 and sensors ov7660 and ov7670 only */ +static void sethvflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->gspca_dev.streaming) + reg_w(sd, OV519_R51_RESET1, 0x0f); /* block stream */ + i2c_w_mask(sd, OV7670_R1E_MVFP, + OV7670_MVFP_MIRROR * sd->ctrls[HFLIP].val + | OV7670_MVFP_VFLIP * sd->ctrls[VFLIP].val, + OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP); + if (sd->gspca_dev.streaming) + reg_w(sd, OV519_R51_RESET1, 0x00); /* restart stream */ +} + +static void set_ov_sensor_window(struct sd *sd) +{ + struct gspca_dev *gspca_dev; + int qvga, crop; + int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale; + + /* mode setup is fully handled in mode_init_ov_sensor_regs for these */ + switch (sd->sensor) { + case SEN_OV2610: + case SEN_OV2610AE: + case SEN_OV3610: + case SEN_OV7670: + case SEN_OV9600: + mode_init_ov_sensor_regs(sd); + return; + case SEN_OV7660: + ov519_set_mode(sd); + ov519_set_fr(sd); + return; + } + + gspca_dev = &sd->gspca_dev; + qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1; + crop = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 2; + + /* The different sensor ICs handle setting up of window differently. + * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */ + switch (sd->sensor) { + case SEN_OV8610: + hwsbase = 0x1e; + hwebase = 0x1e; + vwsbase = 0x02; + vwebase = 0x02; + break; + case SEN_OV7610: + case SEN_OV76BE: + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = vwebase = 0x05; + break; + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV66308AF: + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = 0x05; + vwebase = 0x06; + if (sd->sensor == SEN_OV66308AF && qvga) + /* HDG: this fixes U and V getting swapped */ + hwsbase++; + if (crop) { + hwsbase += 8; + hwebase += 8; + vwsbase += 11; + vwebase += 11; + } + break; + case SEN_OV7620: + case SEN_OV7620AE: + hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ + hwebase = 0x2f; + vwsbase = vwebase = 0x05; + break; + case SEN_OV7640: + case SEN_OV7648: + hwsbase = 0x1a; + hwebase = 0x1a; + vwsbase = vwebase = 0x03; + break; + default: + return; + } + + switch (sd->sensor) { + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV66308AF: + if (qvga) { /* QCIF */ + hwscale = 0; + vwscale = 0; + } else { /* CIF */ + hwscale = 1; + vwscale = 1; /* The datasheet says 0; + * it's wrong */ + } + break; + case SEN_OV8610: + if (qvga) { /* QSVGA */ + hwscale = 1; + vwscale = 1; + } else { /* SVGA */ + hwscale = 2; + vwscale = 2; + } + break; + default: /* SEN_OV7xx0 */ + if (qvga) { /* QVGA */ + hwscale = 1; + vwscale = 0; + } else { /* VGA */ + hwscale = 2; + vwscale = 1; + } + } + + mode_init_ov_sensor_regs(sd); + + i2c_w(sd, 0x17, hwsbase); + i2c_w(sd, 0x18, hwebase + (sd->sensor_width >> hwscale)); + i2c_w(sd, 0x19, vwsbase); + i2c_w(sd, 0x1a, vwebase + (sd->sensor_height >> vwscale)); +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* Default for most bridges, allow bridge_mode_init_regs to override */ + sd->sensor_width = sd->gspca_dev.width; + sd->sensor_height = sd->gspca_dev.height; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + ov511_mode_init_regs(sd); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + ov518_mode_init_regs(sd); + break; + case BRIDGE_OV519: + ov519_mode_init_regs(sd); + break; + /* case BRIDGE_OVFX2: nothing to do */ + case BRIDGE_W9968CF: + w9968cf_mode_init_regs(sd); + break; + } + + set_ov_sensor_window(sd); + + if (!(sd->gspca_dev.ctrl_dis & (1 << CONTRAST))) + setcontrast(gspca_dev); + if (!(sd->gspca_dev.ctrl_dis & (1 << BRIGHTNESS))) + setbrightness(gspca_dev); + if (!(sd->gspca_dev.ctrl_dis & (1 << EXPOSURE))) + setexposure(gspca_dev); + if (!(sd->gspca_dev.ctrl_dis & (1 << COLORS))) + setcolors(gspca_dev); + if (!(sd->gspca_dev.ctrl_dis & ((1 << HFLIP) | (1 << VFLIP)))) + sethvflip(gspca_dev); + if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOBRIGHT))) + setautobright(gspca_dev); + if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOGAIN))) + setautogain(gspca_dev); + if (!(sd->gspca_dev.ctrl_dis & (1 << FREQ))) + setfreq_i(sd); + + /* Force clear snapshot state in case the snapshot button was + pressed while we weren't streaming */ + sd->snapshot_needs_reset = 1; + sd_reset_snapshot(gspca_dev); + + sd->first_frame = 3; + + ov51x_restart(sd); + ov51x_led_control(sd, 1); + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + ov51x_stop(sd); + ov51x_led_control(sd, 0); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!sd->gspca_dev.present) + return; + if (sd->bridge == BRIDGE_W9968CF) + w9968cf_stop0(sd); + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + /* If the last button state is pressed, release it now! */ + if (sd->snapshot_pressed) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + sd->snapshot_pressed = 0; + } +#endif + if (sd->bridge == BRIDGE_OV519) + reg_w(sd, OV519_R57_SNAPSHOT, 0x23); +} + +static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->snapshot_pressed != state) { +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + input_report_key(gspca_dev->input_dev, KEY_CAMERA, state); + input_sync(gspca_dev->input_dev); +#endif + if (state) + sd->snapshot_needs_reset = 1; + + sd->snapshot_pressed = state; + } else { + /* On the ov511 / ov519 we need to reset the button state + multiple times, as resetting does not work as long as the + button stays pressed */ + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + case BRIDGE_OV519: + if (state) + sd->snapshot_needs_reset = 1; + break; + } + } +} + +static void ov511_pkt_scan(struct gspca_dev *gspca_dev, + u8 *in, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th + * byte non-zero. The EOF packet has image width/height in the + * 10th and 11th bytes. The 9th byte is given as follows: + * + * bit 7: EOF + * 6: compression enabled + * 5: 422/420/400 modes + * 4: 422/420/400 modes + * 3: 1 + * 2: snapshot button on + * 1: snapshot frame + * 0: even/odd field + */ + if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) && + (in[8] & 0x08)) { + ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1); + if (in[8] & 0x80) { + /* Frame end */ + if ((in[9] + 1) * 8 != gspca_dev->width || + (in[10] + 1) * 8 != gspca_dev->height) { + PDEBUG(D_ERR, "Invalid frame size, got: %dx%d," + " requested: %dx%d\n", + (in[9] + 1) * 8, (in[10] + 1) * 8, + gspca_dev->width, gspca_dev->height); + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + /* Add 11 byte footer to frame, might be useful */ + gspca_frame_add(gspca_dev, LAST_PACKET, in, 11); + return; + } else { + /* Frame start */ + gspca_frame_add(gspca_dev, FIRST_PACKET, in, 0); + sd->packet_nr = 0; + } + } + + /* Ignore the packet number */ + len--; + + /* intermediate packet */ + gspca_frame_add(gspca_dev, INTER_PACKET, in, len); +} + +static void ov518_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* A false positive here is likely, until OVT gives me + * the definitive SOF/EOF format */ + if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) { + ov51x_handle_button(gspca_dev, (data[6] >> 1) & 1); + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); + sd->packet_nr = 0; + } + + if (gspca_dev->last_packet_type == DISCARD_PACKET) + return; + + /* Does this device use packet numbers ? */ + if (len & 7) { + len--; + if (sd->packet_nr == data[len]) + sd->packet_nr++; + /* The last few packets of the frame (which are all 0's + except that they may contain part of the footer), are + numbered 0 */ + else if (sd->packet_nr == 0 || data[len]) { + PDEBUG(D_ERR, "Invalid packet nr: %d (expect: %d)", + (int)data[len], (int)sd->packet_nr); + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + } + + /* intermediate packet */ + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static void ov519_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + /* Header of ov519 is 16 bytes: + * Byte Value Description + * 0 0xff magic + * 1 0xff magic + * 2 0xff magic + * 3 0xXX 0x50 = SOF, 0x51 = EOF + * 9 0xXX 0x01 initial frame without data, + * 0x00 standard frame with image + * 14 Lo in EOF: length of image data / 8 + * 15 Hi + */ + + if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) { + switch (data[3]) { + case 0x50: /* start of frame */ + /* Don't check the button state here, as the state + usually (always ?) changes at EOF and checking it + here leads to unnecessary snapshot state resets. */ +#define HDRSZ 16 + data += HDRSZ; + len -= HDRSZ; +#undef HDRSZ + if (data[0] == 0xff || data[1] == 0xd8) + gspca_frame_add(gspca_dev, FIRST_PACKET, + data, len); + else + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + case 0x51: /* end of frame */ + ov51x_handle_button(gspca_dev, data[11] & 1); + if (data[9] != 0) + gspca_dev->last_packet_type = DISCARD_PACKET; + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + return; + } + } + + /* intermediate packet */ + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + + /* A short read signals EOF */ + if (len < gspca_dev->cam.bulk_size) { + /* If the frame is short, and it is one of the first ones + the sensor and bridge are still syncing, so drop it. */ + if (sd->first_frame) { + sd->first_frame--; + if (gspca_dev->image_len < + sd->gspca_dev.width * sd->gspca_dev.height) + gspca_dev->last_packet_type = DISCARD_PACKET; + } + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + ov511_pkt_scan(gspca_dev, data, len); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + ov518_pkt_scan(gspca_dev, data, len); + break; + case BRIDGE_OV519: + ov519_pkt_scan(gspca_dev, data, len); + break; + case BRIDGE_OVFX2: + ovfx2_pkt_scan(gspca_dev, data, len); + break; + case BRIDGE_W9968CF: + w9968cf_pkt_scan(gspca_dev, data, len); + break; + } +} + +/* -- management routines -- */ + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + static const struct ov_i2c_regvals brit_7660[][7] = { + {{0x0f, 0x6a}, {0x24, 0x40}, {0x25, 0x2b}, {0x26, 0x90}, + {0x27, 0xe0}, {0x28, 0xe0}, {0x2c, 0xe0}}, + {{0x0f, 0x6a}, {0x24, 0x50}, {0x25, 0x40}, {0x26, 0xa1}, + {0x27, 0xc0}, {0x28, 0xc0}, {0x2c, 0xc0}}, + {{0x0f, 0x6a}, {0x24, 0x68}, {0x25, 0x58}, {0x26, 0xc2}, + {0x27, 0xa0}, {0x28, 0xa0}, {0x2c, 0xa0}}, + {{0x0f, 0x6a}, {0x24, 0x70}, {0x25, 0x68}, {0x26, 0xd3}, + {0x27, 0x80}, {0x28, 0x80}, {0x2c, 0x80}}, + {{0x0f, 0x6a}, {0x24, 0x80}, {0x25, 0x70}, {0x26, 0xd3}, + {0x27, 0x20}, {0x28, 0x20}, {0x2c, 0x20}}, + {{0x0f, 0x6a}, {0x24, 0x88}, {0x25, 0x78}, {0x26, 0xd3}, + {0x27, 0x40}, {0x28, 0x40}, {0x2c, 0x40}}, + {{0x0f, 0x6a}, {0x24, 0x90}, {0x25, 0x80}, {0x26, 0xd4}, + {0x27, 0x60}, {0x28, 0x60}, {0x2c, 0x60}} + }; + + val = sd->ctrls[BRIGHTNESS].val; + switch (sd->sensor) { + case SEN_OV8610: + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV66308AF: + case SEN_OV7640: + case SEN_OV7648: + i2c_w(sd, OV7610_REG_BRT, val); + break; + case SEN_OV7620: + case SEN_OV7620AE: + /* 7620 doesn't like manual changes when in auto mode */ + if (!sd->ctrls[AUTOBRIGHT].val) + i2c_w(sd, OV7610_REG_BRT, val); + break; + case SEN_OV7660: + write_i2c_regvals(sd, brit_7660[val], + ARRAY_SIZE(brit_7660[0])); + break; + case SEN_OV7670: +/*win trace + * i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_AEC); */ + i2c_w(sd, OV7670_R55_BRIGHT, ov7670_abs_to_sm(val)); + break; + } +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + static const struct ov_i2c_regvals contrast_7660[][31] = { + {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0xa0}, + {0x70, 0x58}, {0x71, 0x38}, {0x72, 0x30}, {0x73, 0x30}, + {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x24}, {0x77, 0x24}, + {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x34}, + {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x65}, + {0x80, 0x70}, {0x81, 0x77}, {0x82, 0x7d}, {0x83, 0x83}, + {0x84, 0x88}, {0x85, 0x8d}, {0x86, 0x96}, {0x87, 0x9f}, + {0x88, 0xb0}, {0x89, 0xc4}, {0x8a, 0xd9}}, + {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0x94}, + {0x70, 0x58}, {0x71, 0x40}, {0x72, 0x30}, {0x73, 0x30}, + {0x74, 0x30}, {0x75, 0x30}, {0x76, 0x2c}, {0x77, 0x24}, + {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x31}, + {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x62}, + {0x80, 0x6d}, {0x81, 0x75}, {0x82, 0x7b}, {0x83, 0x81}, + {0x84, 0x87}, {0x85, 0x8d}, {0x86, 0x98}, {0x87, 0xa1}, + {0x88, 0xb2}, {0x89, 0xc6}, {0x8a, 0xdb}}, + {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x84}, + {0x70, 0x58}, {0x71, 0x48}, {0x72, 0x40}, {0x73, 0x40}, + {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x28}, {0x77, 0x24}, + {0x78, 0x26}, {0x79, 0x28}, {0x7a, 0x28}, {0x7b, 0x34}, + {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x5d}, + {0x80, 0x68}, {0x81, 0x71}, {0x82, 0x79}, {0x83, 0x81}, + {0x84, 0x86}, {0x85, 0x8b}, {0x86, 0x95}, {0x87, 0x9e}, + {0x88, 0xb1}, {0x89, 0xc5}, {0x8a, 0xd9}}, + {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x70}, + {0x70, 0x58}, {0x71, 0x58}, {0x72, 0x48}, {0x73, 0x48}, + {0x74, 0x38}, {0x75, 0x40}, {0x76, 0x34}, {0x77, 0x34}, + {0x78, 0x2e}, {0x79, 0x28}, {0x7a, 0x24}, {0x7b, 0x22}, + {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x58}, + {0x80, 0x63}, {0x81, 0x6e}, {0x82, 0x77}, {0x83, 0x80}, + {0x84, 0x87}, {0x85, 0x8f}, {0x86, 0x9c}, {0x87, 0xa9}, + {0x88, 0xc0}, {0x89, 0xd4}, {0x8a, 0xe6}}, + {{0x6c, 0xa0}, {0x6d, 0xf0}, {0x6e, 0x90}, {0x6f, 0x80}, + {0x70, 0x70}, {0x71, 0x80}, {0x72, 0x60}, {0x73, 0x60}, + {0x74, 0x58}, {0x75, 0x60}, {0x76, 0x4c}, {0x77, 0x38}, + {0x78, 0x38}, {0x79, 0x2a}, {0x7a, 0x20}, {0x7b, 0x0e}, + {0x7c, 0x0a}, {0x7d, 0x14}, {0x7e, 0x26}, {0x7f, 0x46}, + {0x80, 0x54}, {0x81, 0x64}, {0x82, 0x70}, {0x83, 0x7c}, + {0x84, 0x87}, {0x85, 0x93}, {0x86, 0xa6}, {0x87, 0xb4}, + {0x88, 0xd0}, {0x89, 0xe5}, {0x8a, 0xf5}}, + {{0x6c, 0x60}, {0x6d, 0x80}, {0x6e, 0x60}, {0x6f, 0x80}, + {0x70, 0x80}, {0x71, 0x80}, {0x72, 0x88}, {0x73, 0x30}, + {0x74, 0x70}, {0x75, 0x68}, {0x76, 0x64}, {0x77, 0x50}, + {0x78, 0x3c}, {0x79, 0x22}, {0x7a, 0x10}, {0x7b, 0x08}, + {0x7c, 0x06}, {0x7d, 0x0e}, {0x7e, 0x1a}, {0x7f, 0x3a}, + {0x80, 0x4a}, {0x81, 0x5a}, {0x82, 0x6b}, {0x83, 0x7b}, + {0x84, 0x89}, {0x85, 0x96}, {0x86, 0xaf}, {0x87, 0xc3}, + {0x88, 0xe1}, {0x89, 0xf2}, {0x8a, 0xfa}}, + {{0x6c, 0x20}, {0x6d, 0x40}, {0x6e, 0x20}, {0x6f, 0x60}, + {0x70, 0x88}, {0x71, 0xc8}, {0x72, 0xc0}, {0x73, 0xb8}, + {0x74, 0xa8}, {0x75, 0xb8}, {0x76, 0x80}, {0x77, 0x5c}, + {0x78, 0x26}, {0x79, 0x10}, {0x7a, 0x08}, {0x7b, 0x04}, + {0x7c, 0x02}, {0x7d, 0x06}, {0x7e, 0x0a}, {0x7f, 0x22}, + {0x80, 0x33}, {0x81, 0x4c}, {0x82, 0x64}, {0x83, 0x7b}, + {0x84, 0x90}, {0x85, 0xa7}, {0x86, 0xc7}, {0x87, 0xde}, + {0x88, 0xf1}, {0x89, 0xf9}, {0x8a, 0xfd}}, + }; + + val = sd->ctrls[CONTRAST].val; + switch (sd->sensor) { + case SEN_OV7610: + case SEN_OV6620: + i2c_w(sd, OV7610_REG_CNT, val); + break; + case SEN_OV6630: + case SEN_OV66308AF: + i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f); + break; + case SEN_OV8610: { + static const u8 ctab[] = { + 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f + }; + + /* Use Y gamma control instead. Bit 0 enables it. */ + i2c_w(sd, 0x64, ctab[val >> 5]); + break; + } + case SEN_OV7620: + case SEN_OV7620AE: { + static const u8 ctab[] = { + 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, + 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff + }; + + /* Use Y gamma control instead. Bit 0 enables it. */ + i2c_w(sd, 0x64, ctab[val >> 4]); + break; + } + case SEN_OV7660: + write_i2c_regvals(sd, contrast_7660[val], + ARRAY_SIZE(contrast_7660[0])); + break; + case SEN_OV7670: + /* check that this isn't just the same as ov7610 */ + i2c_w(sd, OV7670_R56_CONTRAS, val >> 1); + break; + } +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!sd->ctrls[AUTOGAIN].val) + i2c_w(sd, 0x10, sd->ctrls[EXPOSURE].val); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + static const struct ov_i2c_regvals colors_7660[][6] = { + {{0x4f, 0x28}, {0x50, 0x2a}, {0x51, 0x02}, {0x52, 0x0a}, + {0x53, 0x19}, {0x54, 0x23}}, + {{0x4f, 0x47}, {0x50, 0x4a}, {0x51, 0x03}, {0x52, 0x11}, + {0x53, 0x2c}, {0x54, 0x3e}}, + {{0x4f, 0x66}, {0x50, 0x6b}, {0x51, 0x05}, {0x52, 0x19}, + {0x53, 0x40}, {0x54, 0x59}}, + {{0x4f, 0x84}, {0x50, 0x8b}, {0x51, 0x06}, {0x52, 0x20}, + {0x53, 0x53}, {0x54, 0x73}}, + {{0x4f, 0xa3}, {0x50, 0xab}, {0x51, 0x08}, {0x52, 0x28}, + {0x53, 0x66}, {0x54, 0x8e}}, + }; + + val = sd->ctrls[COLORS].val; + switch (sd->sensor) { + case SEN_OV8610: + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV66308AF: + i2c_w(sd, OV7610_REG_SAT, val); + break; + case SEN_OV7620: + case SEN_OV7620AE: + /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ +/* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e); + if (rc < 0) + goto out; */ + i2c_w(sd, OV7610_REG_SAT, val); + break; + case SEN_OV7640: + case SEN_OV7648: + i2c_w(sd, OV7610_REG_SAT, val & 0xf0); + break; + case SEN_OV7660: + write_i2c_regvals(sd, colors_7660[val], + ARRAY_SIZE(colors_7660[0])); + break; + case SEN_OV7670: + /* supported later once I work out how to do it + * transparently fail now! */ + /* set REG_COM13 values for UV sat auto mode */ + break; + } +} + +static void setautobright(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + i2c_w_mask(sd, 0x2d, sd->ctrls[AUTOBRIGHT].val ? 0x10 : 0x00, 0x10); +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[AUTOGAIN].val = val; + if (val) { + gspca_dev->ctrl_inac |= (1 << EXPOSURE); + } else { + gspca_dev->ctrl_inac &= ~(1 << EXPOSURE); + sd->ctrls[EXPOSURE].val = i2c_r(sd, 0x10); + } + if (gspca_dev->streaming) + setautogain(gspca_dev); + return gspca_dev->usb_err; +} + +static void setfreq_i(struct sd *sd) +{ + if (sd->sensor == SEN_OV7660 + || sd->sensor == SEN_OV7670) { + switch (sd->ctrls[FREQ].val) { + case 0: /* Banding filter disabled */ + i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_BFILT); + break; + case 1: /* 50 hz */ + i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT, + OV7670_COM8_BFILT); + i2c_w_mask(sd, OV7670_R3B_COM11, 0x08, 0x18); + break; + case 2: /* 60 hz */ + i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT, + OV7670_COM8_BFILT); + i2c_w_mask(sd, OV7670_R3B_COM11, 0x00, 0x18); + break; + case 3: /* Auto hz - ov7670 only */ + i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT, + OV7670_COM8_BFILT); + i2c_w_mask(sd, OV7670_R3B_COM11, OV7670_COM11_HZAUTO, + 0x18); + break; + } + } else { + switch (sd->ctrls[FREQ].val) { + case 0: /* Banding filter disabled */ + i2c_w_mask(sd, 0x2d, 0x00, 0x04); + i2c_w_mask(sd, 0x2a, 0x00, 0x80); + break; + case 1: /* 50 hz (filter on and framerate adj) */ + i2c_w_mask(sd, 0x2d, 0x04, 0x04); + i2c_w_mask(sd, 0x2a, 0x80, 0x80); + /* 20 fps -> 16.667 fps */ + if (sd->sensor == SEN_OV6620 || + sd->sensor == SEN_OV6630 || + sd->sensor == SEN_OV66308AF) + i2c_w(sd, 0x2b, 0x5e); + else + i2c_w(sd, 0x2b, 0xac); + break; + case 2: /* 60 hz (filter on, ...) */ + i2c_w_mask(sd, 0x2d, 0x04, 0x04); + if (sd->sensor == SEN_OV6620 || + sd->sensor == SEN_OV6630 || + sd->sensor == SEN_OV66308AF) { + /* 20 fps -> 15 fps */ + i2c_w_mask(sd, 0x2a, 0x80, 0x80); + i2c_w(sd, 0x2b, 0xa8); + } else { + /* no framerate adj. */ + i2c_w_mask(sd, 0x2a, 0x00, 0x80); + } + break; + } + } +} +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + setfreq_i(sd); + + /* Ugly but necessary */ + if (sd->bridge == BRIDGE_W9968CF) + w9968cf_set_crop_window(sd); +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "NoFliker"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + case 3: + if (sd->sensor != SEN_OV7670) + return -EINVAL; + + strcpy((char *) menu->name, "Automatic"); + return 0; + } + break; + } + return -EINVAL; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->bridge != BRIDGE_W9968CF) + return -EINVAL; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT | + V4L2_JPEG_MARKER_DRI; + return 0; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->bridge != BRIDGE_W9968CF) + return -EINVAL; + + if (gspca_dev->streaming) + return -EBUSY; + + if (jcomp->quality < QUALITY_MIN) + sd->quality = QUALITY_MIN; + else if (jcomp->quality > QUALITY_MAX) + sd->quality = QUALITY_MAX; + else + sd->quality = jcomp->quality; + + /* Return resulting jcomp params to app */ + sd_get_jcomp(gspca_dev, jcomp); + + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = sd_reset_snapshot, + .querymenu = sd_querymenu, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .other_input = 1, +#endif +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF }, + {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x4064), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x4068), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x054c, 0x0155), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 }, + {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 }, + {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 }, + {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0xa511), .driver_info = BRIDGE_OV511PLUS }, + {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS }, + {USB_DEVICE(0x0813, 0x0002), .driver_info = BRIDGE_OV511PLUS }, + {USB_DEVICE(0x0b62, 0x0059), .driver_info = BRIDGE_OVFX2 }, + {USB_DEVICE(0x0e96, 0xc001), .driver_info = BRIDGE_OVFX2 }, + {USB_DEVICE(0x1046, 0x9967), .driver_info = BRIDGE_W9968CF }, + {USB_DEVICE(0x8020, 0xef04), .driver_info = BRIDGE_OVFX2 }, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(frame_rate, int, 0644); +MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov534_9.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov534_9.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov534_9.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov534_9.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1469 @@ +/* + * ov534-ov965x gspca driver + * + * Copyright (C) 2009-2010 Jean-Francois Moine http://moinejf.free.fr + * Copyright (C) 2008 Antonio Ospite + * Copyright (C) 2008 Jim Paris + * + * Based on a prototype written by Mark Ferrell + * USB protocol reverse engineered by Jim Paris + * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "ov534_9" + +#include "gspca.h" + +#define OV534_REG_ADDRESS 0xf1 /* sensor address */ +#define OV534_REG_SUBADDR 0xf2 +#define OV534_REG_WRITE 0xf3 +#define OV534_REG_READ 0xf4 +#define OV534_REG_OPERATION 0xf5 +#define OV534_REG_STATUS 0xf6 + +#define OV534_OP_WRITE_3 0x37 +#define OV534_OP_WRITE_2 0x33 +#define OV534_OP_READ_2 0xf9 + +#define CTRL_TIMEOUT 500 + +MODULE_AUTHOR("Jean-Francois Moine "); +MODULE_DESCRIPTION("GSPCA/OV534_9 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + __u32 last_pts; + u8 last_fid; + + u8 brightness; + u8 contrast; + u8 autogain; + u8 exposure; + s8 sharpness; + u8 satur; + u8 freq; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { /* 0 */ + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 15, + .step = 1, +#define BRIGHTNESS_DEF 7 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { /* 1 */ + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 15, + .step = 1, +#define CONTRAST_DEF 3 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { /* 2 */ + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Autogain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +#define EXPO_IDX 3 + { /* 3 */ + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 3, + .step = 1, +#define EXPO_DEF 0 + .default_value = EXPO_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { /* 4 */ + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = -1, /* -1 = auto */ + .maximum = 4, + .step = 1, +#define SHARPNESS_DEF -1 + .default_value = SHARPNESS_DEF, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, + { /* 5 */ + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 4, + .step = 1, +#define SATUR_DEF 2 + .default_value = SATUR_DEF, + }, + .set = sd_setsatur, + .get = sd_getsatur, + }, + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ + .step = 1, +#define FREQ_DEF 0 + .default_value = FREQ_DEF, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, +}; + +static const struct v4l2_pix_format ov965x_mode[] = { +#define QVGA_MODE 0 + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, +#define VGA_MODE 1 + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, +#define SVGA_MODE 2 + {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 600 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, +#define XGA_MODE 3 + {1024, 768, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 1024, + .sizeimage = 1024 * 768 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, +#define SXGA_MODE 4 + {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, +}; + +static const u8 bridge_init[][2] = { + {0x88, 0xf8}, + {0x89, 0xff}, + {0x76, 0x03}, + {0x92, 0x03}, + {0x95, 0x10}, + {0xe2, 0x00}, + {0xe7, 0x3e}, + {0x8d, 0x1c}, + {0x8e, 0x00}, + {0x8f, 0x00}, + {0x1f, 0x00}, + {0xc3, 0xf9}, + {0x89, 0xff}, + {0x88, 0xf8}, + {0x76, 0x03}, + {0x92, 0x01}, + {0x93, 0x18}, + {0x1c, 0x0a}, + {0x1d, 0x48}, + {0xc0, 0x50}, + {0xc1, 0x3c}, + {0x34, 0x05}, + {0xc2, 0x0c}, + {0xc3, 0xf9}, + {0x34, 0x05}, + {0xe7, 0x2e}, + {0x31, 0xf9}, + {0x35, 0x02}, + {0xd9, 0x10}, + {0x25, 0x42}, + {0x94, 0x11}, +}; + +static const u8 sensor_init[][2] = { + {0x12, 0x80}, /* com7 - SSCB reset */ + {0x00, 0x00}, /* gain */ + {0x01, 0x80}, /* blue */ + {0x02, 0x80}, /* red */ + {0x03, 0x1b}, /* vref */ + {0x04, 0x03}, /* com1 - exposure low bits */ + {0x0b, 0x57}, /* ver */ + {0x0e, 0x61}, /* com5 */ + {0x0f, 0x42}, /* com6 */ + {0x11, 0x00}, /* clkrc */ + {0x12, 0x02}, /* com7 - 15fps VGA YUYV */ + {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ + {0x14, 0x28}, /* com9 */ + {0x16, 0x24}, /* reg16 */ + {0x17, 0x1d}, /* hstart*/ + {0x18, 0xbd}, /* hstop */ + {0x19, 0x01}, /* vstrt */ + {0x1a, 0x81}, /* vstop*/ + {0x1e, 0x04}, /* mvfp */ + {0x24, 0x3c}, /* aew */ + {0x25, 0x36}, /* aeb */ + {0x26, 0x71}, /* vpt */ + {0x27, 0x08}, /* bbias */ + {0x28, 0x08}, /* gbbias */ + {0x29, 0x15}, /* gr com */ + {0x2a, 0x00}, /* exhch */ + {0x2b, 0x00}, /* exhcl */ + {0x2c, 0x08}, /* rbias */ + {0x32, 0xff}, /* href */ + {0x33, 0x00}, /* chlf */ + {0x34, 0x3f}, /* aref1 */ + {0x35, 0x00}, /* aref2 */ + {0x36, 0xf8}, /* aref3 */ + {0x38, 0x72}, /* adc2 */ + {0x39, 0x57}, /* aref4 */ + {0x3a, 0x80}, /* tslb - yuyv */ + {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ + {0x3d, 0x99}, /* com13 */ + {0x3f, 0xc1}, /* edge */ + {0x40, 0xc0}, /* com15 */ + {0x41, 0x40}, /* com16 */ + {0x42, 0xc0}, /* com17 */ + {0x43, 0x0a}, /* rsvd */ + {0x44, 0xf0}, + {0x45, 0x46}, + {0x46, 0x62}, + {0x47, 0x2a}, + {0x48, 0x3c}, + {0x4a, 0xfc}, + {0x4b, 0xfc}, + {0x4c, 0x7f}, + {0x4d, 0x7f}, + {0x4e, 0x7f}, + {0x4f, 0x98}, /* matrix */ + {0x50, 0x98}, + {0x51, 0x00}, + {0x52, 0x28}, + {0x53, 0x70}, + {0x54, 0x98}, + {0x58, 0x1a}, /* matrix coef sign */ + {0x59, 0x85}, /* AWB control */ + {0x5a, 0xa9}, + {0x5b, 0x64}, + {0x5c, 0x84}, + {0x5d, 0x53}, + {0x5e, 0x0e}, + {0x5f, 0xf0}, /* AWB blue limit */ + {0x60, 0xf0}, /* AWB red limit */ + {0x61, 0xf0}, /* AWB green limit */ + {0x62, 0x00}, /* lcc1 */ + {0x63, 0x00}, /* lcc2 */ + {0x64, 0x02}, /* lcc3 */ + {0x65, 0x16}, /* lcc4 */ + {0x66, 0x01}, /* lcc5 */ + {0x69, 0x02}, /* hv */ + {0x6b, 0x5a}, /* dbvl */ + {0x6c, 0x04}, + {0x6d, 0x55}, + {0x6e, 0x00}, + {0x6f, 0x9d}, + {0x70, 0x21}, /* dnsth */ + {0x71, 0x78}, + {0x72, 0x00}, /* poidx */ + {0x73, 0x01}, /* pckdv */ + {0x74, 0x3a}, /* xindx */ + {0x75, 0x35}, /* yindx */ + {0x76, 0x01}, + {0x77, 0x02}, + {0x7a, 0x12}, /* gamma curve */ + {0x7b, 0x08}, + {0x7c, 0x16}, + {0x7d, 0x30}, + {0x7e, 0x5e}, + {0x7f, 0x72}, + {0x80, 0x82}, + {0x81, 0x8e}, + {0x82, 0x9a}, + {0x83, 0xa4}, + {0x84, 0xac}, + {0x85, 0xb8}, + {0x86, 0xc3}, + {0x87, 0xd6}, + {0x88, 0xe6}, + {0x89, 0xf2}, + {0x8a, 0x03}, + {0x8c, 0x89}, /* com19 */ + {0x14, 0x28}, /* com9 */ + {0x90, 0x7d}, + {0x91, 0x7b}, + {0x9d, 0x03}, /* lcc6 */ + {0x9e, 0x04}, /* lcc7 */ + {0x9f, 0x7a}, + {0xa0, 0x79}, + {0xa1, 0x40}, /* aechm */ + {0xa4, 0x50}, /* com21 */ + {0xa5, 0x68}, /* com26 */ + {0xa6, 0x4a}, /* AWB green */ + {0xa8, 0xc1}, /* refa8 */ + {0xa9, 0xef}, /* refa9 */ + {0xaa, 0x92}, + {0xab, 0x04}, + {0xac, 0x80}, /* black level control */ + {0xad, 0x80}, + {0xae, 0x80}, + {0xaf, 0x80}, + {0xb2, 0xf2}, + {0xb3, 0x20}, + {0xb4, 0x20}, /* ctrlb4 */ + {0xb5, 0x00}, + {0xb6, 0xaf}, + {0xbb, 0xae}, + {0xbc, 0x7f}, /* ADC channel offsets */ + {0xdb, 0x7f}, + {0xbe, 0x7f}, + {0xbf, 0x7f}, + {0xc0, 0xe2}, + {0xc1, 0xc0}, + {0xc2, 0x01}, + {0xc3, 0x4e}, + {0xc6, 0x85}, + {0xc7, 0x80}, /* com24 */ + {0xc9, 0xe0}, + {0xca, 0xe8}, + {0xcb, 0xf0}, + {0xcc, 0xd8}, + {0xcd, 0xf1}, + {0x4f, 0x98}, /* matrix */ + {0x50, 0x98}, + {0x51, 0x00}, + {0x52, 0x28}, + {0x53, 0x70}, + {0x54, 0x98}, + {0x58, 0x1a}, + {0xff, 0x41}, /* read 41, write ff 00 */ + {0x41, 0x40}, /* com16 */ + + {0xc5, 0x03}, /* 60 Hz banding filter */ + {0x6a, 0x02}, /* 50 Hz banding filter */ + + {0x12, 0x62}, /* com7 - 30fps VGA YUV */ + {0x36, 0xfa}, /* aref3 */ + {0x69, 0x0a}, /* hv */ + {0x8c, 0x89}, /* com22 */ + {0x14, 0x28}, /* com9 */ + {0x3e, 0x0c}, + {0x41, 0x40}, /* com16 */ + {0x72, 0x00}, + {0x73, 0x00}, + {0x74, 0x3a}, + {0x75, 0x35}, + {0x76, 0x01}, + {0xc7, 0x80}, + {0x03, 0x12}, /* vref */ + {0x17, 0x16}, /* hstart */ + {0x18, 0x02}, /* hstop */ + {0x19, 0x01}, /* vstrt */ + {0x1a, 0x3d}, /* vstop */ + {0x32, 0xff}, /* href */ + {0xc0, 0xaa}, +}; + +static const u8 bridge_init_2[][2] = { + {0x94, 0xaa}, + {0xf1, 0x60}, + {0xe5, 0x04}, + {0xc0, 0x50}, + {0xc1, 0x3c}, + {0x8c, 0x00}, + {0x8d, 0x1c}, + {0x34, 0x05}, + + {0xc2, 0x0c}, + {0xc3, 0xf9}, + {0xda, 0x01}, + {0x50, 0x00}, + {0x51, 0xa0}, + {0x52, 0x3c}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x57, 0x00}, + {0x5c, 0x00}, + {0x5a, 0xa0}, + {0x5b, 0x78}, + {0x35, 0x02}, + {0xd9, 0x10}, + {0x94, 0x11}, +}; + +static const u8 sensor_init_2[][2] = { + {0x3b, 0xc4}, + {0x1e, 0x04}, /* mvfp */ + {0x13, 0xe0}, /* com8 */ + {0x00, 0x00}, /* gain */ + {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ + {0x11, 0x03}, /* clkrc */ + {0x6b, 0x5a}, /* dblv */ + {0x6a, 0x05}, + {0xc5, 0x07}, + {0xa2, 0x4b}, + {0xa3, 0x3e}, + {0x2d, 0x00}, + {0xff, 0x42}, /* read 42, write ff 00 */ + {0x42, 0xc0}, /* com17 */ + {0x2d, 0x00}, + {0xff, 0x42}, /* read 42, write ff 00 */ + {0x42, 0xc1}, /* com17 */ +/* sharpness */ + {0x3f, 0x01}, + {0xff, 0x42}, /* read 42, write ff 00 */ + {0x42, 0xc1}, /* com17 */ +/* saturation */ + {0x4f, 0x98}, /* matrix */ + {0x50, 0x98}, + {0x51, 0x00}, + {0x52, 0x28}, + {0x53, 0x70}, + {0x54, 0x98}, + {0x58, 0x1a}, + {0xff, 0x41}, /* read 41, write ff 00 */ + {0x41, 0x40}, /* com16 */ +/* contrast */ + {0x56, 0x40}, +/* brightness */ + {0x55, 0x8f}, +/* expo */ + {0x10, 0x25}, /* aech - exposure high bits */ + {0xff, 0x13}, /* read 13, write ff 00 */ + {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ +}; + +static const u8 sensor_start_1_vga[][2] = { /* same for qvga */ + {0x12, 0x62}, /* com7 - 30fps VGA YUV */ + {0x36, 0xfa}, /* aref3 */ + {0x69, 0x0a}, /* hv */ + {0x8c, 0x89}, /* com22 */ + {0x14, 0x28}, /* com9 */ + {0x3e, 0x0c}, /* com14 */ + {0x41, 0x40}, /* com16 */ + {0x72, 0x00}, + {0x73, 0x00}, + {0x74, 0x3a}, + {0x75, 0x35}, + {0x76, 0x01}, + {0xc7, 0x80}, /* com24 */ + {0x03, 0x12}, /* vref */ + {0x17, 0x16}, /* hstart */ + {0x18, 0x02}, /* hstop */ + {0x19, 0x01}, /* vstrt */ + {0x1a, 0x3d}, /* vstop */ + {0x32, 0xff}, /* href */ + {0xc0, 0xaa}, +}; + +static const u8 sensor_start_1_svga[][2] = { + {0x12, 0x02}, /* com7 - YUYV - VGA 15 full resolution */ + {0x36, 0xf8}, /* aref3 */ + {0x69, 0x02}, /* hv */ + {0x8c, 0x0d}, /* com22 */ + {0x3e, 0x0c}, /* com14 */ + {0x41, 0x40}, /* com16 */ + {0x72, 0x00}, + {0x73, 0x01}, + {0x74, 0x3a}, + {0x75, 0x35}, + {0x76, 0x01}, + {0xc7, 0x80}, /* com24 */ + {0x03, 0x1b}, /* vref */ + {0x17, 0x1d}, /* hstart */ + {0x18, 0xbd}, /* hstop */ + {0x19, 0x01}, /* vstrt */ + {0x1a, 0x81}, /* vstop */ + {0x32, 0xff}, /* href */ + {0xc0, 0xe2}, +}; + +static const u8 sensor_start_1_xga[][2] = { + {0x12, 0x02}, /* com7 */ + {0x36, 0xf8}, /* aref3 */ + {0x69, 0x02}, /* hv */ + {0x8c, 0x89}, /* com22 */ + {0x14, 0x28}, /* com9 */ + {0x3e, 0x0c}, /* com14 */ + {0x41, 0x40}, /* com16 */ + {0x72, 0x00}, + {0x73, 0x01}, + {0x74, 0x3a}, + {0x75, 0x35}, + {0x76, 0x01}, + {0xc7, 0x80}, /* com24 */ + {0x03, 0x1b}, /* vref */ + {0x17, 0x1d}, /* hstart */ + {0x18, 0xbd}, /* hstop */ + {0x19, 0x01}, /* vstrt */ + {0x1a, 0x81}, /* vstop */ + {0x32, 0xff}, /* href */ + {0xc0, 0xe2}, +}; + +static const u8 sensor_start_1_sxga[][2] = { + {0x12, 0x02}, /* com7 */ + {0x36, 0xf8}, /* aref3 */ + {0x69, 0x02}, /* hv */ + {0x8c, 0x89}, /* com22 */ + {0x14, 0x28}, /* com9 */ + {0x3e, 0x0c}, /* com14 */ + {0x41, 0x40}, /* com16 */ + {0x72, 0x00}, + {0x73, 0x01}, + {0x74, 0x3a}, + {0x75, 0x35}, + {0x76, 0x01}, + {0xc7, 0x80}, /* com24 */ + {0x03, 0x1b}, /* vref */ + {0x17, 0x1d}, /* hstart */ + {0x18, 0x02}, /* hstop */ + {0x19, 0x01}, /* vstrt */ + {0x1a, 0x81}, /* vstop */ + {0x32, 0xff}, /* href */ + {0xc0, 0xe2}, +}; + +static const u8 bridge_start_qvga[][2] = { + {0x94, 0xaa}, + {0xf1, 0x60}, + {0xe5, 0x04}, + {0xc0, 0x50}, + {0xc1, 0x3c}, + {0x8c, 0x00}, + {0x8d, 0x1c}, + {0x34, 0x05}, + + {0xc2, 0x4c}, + {0xc3, 0xf9}, + {0xda, 0x00}, + {0x50, 0x00}, + {0x51, 0xa0}, + {0x52, 0x78}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x57, 0x00}, + {0x5c, 0x00}, + {0x5a, 0x50}, + {0x5b, 0x3c}, + {0x35, 0x02}, + {0xd9, 0x10}, + {0x94, 0x11}, +}; + +static const u8 bridge_start_vga[][2] = { + {0x94, 0xaa}, + {0xf1, 0x60}, + {0xe5, 0x04}, + {0xc0, 0x50}, + {0xc1, 0x3c}, + {0x8c, 0x00}, + {0x8d, 0x1c}, + {0x34, 0x05}, + {0xc2, 0x0c}, + {0xc3, 0xf9}, + {0xda, 0x01}, + {0x50, 0x00}, + {0x51, 0xa0}, + {0x52, 0x3c}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x57, 0x00}, + {0x5c, 0x00}, + {0x5a, 0xa0}, + {0x5b, 0x78}, + {0x35, 0x02}, + {0xd9, 0x10}, + {0x94, 0x11}, +}; + +static const u8 bridge_start_svga[][2] = { + {0x94, 0xaa}, + {0xf1, 0x60}, + {0xe5, 0x04}, + {0xc0, 0xa0}, + {0xc1, 0x80}, + {0x8c, 0x00}, + {0x8d, 0x1c}, + {0x34, 0x05}, + {0xc2, 0x4c}, + {0xc3, 0xf9}, + {0x50, 0x00}, + {0x51, 0x40}, + {0x52, 0x00}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x88}, + {0x57, 0x00}, + {0x5c, 0x00}, + {0x5a, 0xc8}, + {0x5b, 0x96}, + {0x35, 0x02}, + {0xd9, 0x10}, + {0xda, 0x00}, + {0x94, 0x11}, +}; + +static const u8 bridge_start_xga[][2] = { + {0x94, 0xaa}, + {0xf1, 0x60}, + {0xe5, 0x04}, + {0xc0, 0xa0}, + {0xc1, 0x80}, + {0x8c, 0x00}, + {0x8d, 0x1c}, + {0x34, 0x05}, + {0xc2, 0x4c}, + {0xc3, 0xf9}, + {0x50, 0x00}, + {0x51, 0x40}, + {0x52, 0x00}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x88}, + {0x57, 0x00}, + {0x5c, 0x01}, + {0x5a, 0x00}, + {0x5b, 0xc0}, + {0x35, 0x02}, + {0xd9, 0x10}, + {0xda, 0x01}, + {0x94, 0x11}, +}; + +static const u8 bridge_start_sxga[][2] = { + {0x94, 0xaa}, + {0xf1, 0x60}, + {0xe5, 0x04}, + {0xc0, 0xa0}, + {0xc1, 0x80}, + {0x8c, 0x00}, + {0x8d, 0x1c}, + {0x34, 0x05}, + {0xc2, 0x0c}, + {0xc3, 0xf9}, + {0xda, 0x00}, + {0x35, 0x02}, + {0xd9, 0x10}, + {0x94, 0x11}, +}; + +static const u8 sensor_start_2_qvga[][2] = { + {0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */ + {0x1e, 0x04}, /* mvfp */ + {0x13, 0xe0}, /* com8 */ + {0x00, 0x00}, + {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ + {0x11, 0x01}, /* clkrc */ + {0x6b, 0x5a}, /* dblv */ + {0x6a, 0x02}, /* 50 Hz banding filter */ + {0xc5, 0x03}, /* 60 Hz banding filter */ + {0xa2, 0x96}, /* bd50 */ + {0xa3, 0x7d}, /* bd60 */ + + {0xff, 0x13}, /* read 13, write ff 00 */ + {0x13, 0xe7}, + {0x3a, 0x80}, /* tslb - yuyv */ +}; + +static const u8 sensor_start_2_vga[][2] = { + {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ + {0x1e, 0x04}, /* mvfp */ + {0x13, 0xe0}, /* com8 */ + {0x00, 0x00}, + {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ + {0x11, 0x03}, /* clkrc */ + {0x6b, 0x5a}, /* dblv */ + {0x6a, 0x05}, /* 50 Hz banding filter */ + {0xc5, 0x07}, /* 60 Hz banding filter */ + {0xa2, 0x4b}, /* bd50 */ + {0xa3, 0x3e}, /* bd60 */ + + {0x2d, 0x00}, /* advfl */ +}; + +static const u8 sensor_start_2_svga[][2] = { /* same for xga */ + {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ + {0x1e, 0x04}, /* mvfp */ + {0x13, 0xe0}, /* com8 */ + {0x00, 0x00}, + {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ + {0x11, 0x01}, /* clkrc */ + {0x6b, 0x5a}, /* dblv */ + {0x6a, 0x0c}, /* 50 Hz banding filter */ + {0xc5, 0x0f}, /* 60 Hz banding filter */ + {0xa2, 0x4e}, /* bd50 */ + {0xa3, 0x41}, /* bd60 */ +}; + +static const u8 sensor_start_2_sxga[][2] = { + {0x13, 0xe0}, /* com8 */ + {0x00, 0x00}, + {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ + {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ + {0x1e, 0x04}, /* mvfp */ + {0x11, 0x01}, /* clkrc */ + {0x6b, 0x5a}, /* dblv */ + {0x6a, 0x0c}, /* 50 Hz banding filter */ + {0xc5, 0x0f}, /* 60 Hz banding filter */ + {0xa2, 0x4e}, /* bd50 */ + {0xa3, 0x41}, /* bd60 */ +}; + +static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val) +{ + struct usb_device *udev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + gspca_dev->usb_buf[0] = val; + ret = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + 0x01, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); + if (ret < 0) { + err("reg_w failed %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w(struct gspca_dev *gspca_dev, u16 reg, u8 val) +{ + PDEBUG(D_USBO, "reg_w [%04x] = %02x", reg, val); + reg_w_i(gspca_dev, reg, val); +} + +static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg) +{ + struct usb_device *udev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return 0; + ret = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + 0x01, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); + PDEBUG(D_USBI, "reg_r [%04x] -> %02x", reg, gspca_dev->usb_buf[0]); + if (ret < 0) { + err("reg_r err %d", ret); + gspca_dev->usb_err = ret; + } + return gspca_dev->usb_buf[0]; +} + +static int sccb_check_status(struct gspca_dev *gspca_dev) +{ + u8 data; + int i; + + for (i = 0; i < 5; i++) { + data = reg_r(gspca_dev, OV534_REG_STATUS); + + switch (data) { + case 0x00: + return 1; + case 0x04: + return 0; + case 0x03: + break; + default: + PDEBUG(D_USBI|D_USBO, + "sccb status 0x%02x, attempt %d/5", + data, i + 1); + } + } + return 0; +} + +static void sccb_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) +{ + PDEBUG(D_USBO, "sccb_write [%02x] = %02x", reg, val); + reg_w_i(gspca_dev, OV534_REG_SUBADDR, reg); + reg_w_i(gspca_dev, OV534_REG_WRITE, val); + reg_w_i(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); + + if (!sccb_check_status(gspca_dev)) + err("sccb_write failed"); +} + +static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg) +{ + reg_w(gspca_dev, OV534_REG_SUBADDR, reg); + reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); + if (!sccb_check_status(gspca_dev)) + err("sccb_read failed 1"); + + reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); + if (!sccb_check_status(gspca_dev)) + err("sccb_read failed 2"); + + return reg_r(gspca_dev, OV534_REG_READ); +} + +/* output a bridge sequence (reg - val) */ +static void reg_w_array(struct gspca_dev *gspca_dev, + const u8 (*data)[2], int len) +{ + while (--len >= 0) { + reg_w(gspca_dev, (*data)[0], (*data)[1]); + data++; + } +} + +/* output a sensor sequence (reg - val) */ +static void sccb_w_array(struct gspca_dev *gspca_dev, + const u8 (*data)[2], int len) +{ + while (--len >= 0) { + if ((*data)[0] != 0xff) { + sccb_write(gspca_dev, (*data)[0], (*data)[1]); + } else { + sccb_read(gspca_dev, (*data)[1]); + sccb_write(gspca_dev, 0xff, 0x00); + } + data++; + } +} + +/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. + * (direction and output)? */ +static void set_led(struct gspca_dev *gspca_dev, int status) +{ + u8 data; + + PDEBUG(D_CONF, "led status: %d", status); + + data = reg_r(gspca_dev, 0x21); + data |= 0x80; + reg_w(gspca_dev, 0x21, data); + + data = reg_r(gspca_dev, 0x23); + if (status) + data |= 0x80; + else + data &= ~0x80; + + reg_w(gspca_dev, 0x23, data); + + if (!status) { + data = reg_r(gspca_dev, 0x21); + data &= ~0x80; + reg_w(gspca_dev, 0x21, data); + } +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + val = sd->brightness; + if (val < 8) + val = 15 - val; /* f .. 8 */ + else + val = val - 8; /* 0 .. 7 */ + sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */ + 0x0f | (val << 4)); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sccb_write(gspca_dev, 0x56, /* cnst1 - contrast 1 ctrl coeff */ + sd->contrast << 4); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + +/*fixme: should adjust agc/awb/aec by different controls */ + val = sccb_read(gspca_dev, 0x13); /* com8 */ + sccb_write(gspca_dev, 0xff, 0x00); + if (sd->autogain) + val |= 0x05; /* agc & aec */ + else + val &= 0xfa; + sccb_write(gspca_dev, 0x13, val); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e}; + + sccb_write(gspca_dev, 0x10, /* aec[9:2] */ + expo[sd->exposure]); + + val = sccb_read(gspca_dev, 0x13); /* com8 */ + sccb_write(gspca_dev, 0xff, 0x00); + sccb_write(gspca_dev, 0x13, val); + + val = sccb_read(gspca_dev, 0xa1); /* aech */ + sccb_write(gspca_dev, 0xff, 0x00); + sccb_write(gspca_dev, 0xa1, val & 0xe0); /* aec[15:10] = 0 */ +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + s8 val; + + val = sd->sharpness; + if (val < 0) { /* auto */ + val = sccb_read(gspca_dev, 0x42); /* com17 */ + sccb_write(gspca_dev, 0xff, 0x00); + sccb_write(gspca_dev, 0x42, val | 0x40); + /* Edge enhancement strength auto adjust */ + return; + } + if (val != 0) + val = 1 << (val - 1); + sccb_write(gspca_dev, 0x3f, /* edge - edge enhance. factor */ + val); + val = sccb_read(gspca_dev, 0x42); /* com17 */ + sccb_write(gspca_dev, 0xff, 0x00); + sccb_write(gspca_dev, 0x42, val & 0xbf); +} + +static void setsatur(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val1, val2, val3; + static const u8 matrix[5][2] = { + {0x14, 0x38}, + {0x1e, 0x54}, + {0x28, 0x70}, + {0x32, 0x8c}, + {0x48, 0x90} + }; + + val1 = matrix[sd->satur][0]; + val2 = matrix[sd->satur][1]; + val3 = val1 + val2; + sccb_write(gspca_dev, 0x4f, val3); /* matrix coeff */ + sccb_write(gspca_dev, 0x50, val3); + sccb_write(gspca_dev, 0x51, 0x00); + sccb_write(gspca_dev, 0x52, val1); + sccb_write(gspca_dev, 0x53, val2); + sccb_write(gspca_dev, 0x54, val3); + sccb_write(gspca_dev, 0x58, 0x1a); /* mtxs - coeff signs */ + + val1 = sccb_read(gspca_dev, 0x41); /* com16 */ + sccb_write(gspca_dev, 0xff, 0x00); + sccb_write(gspca_dev, 0x41, val1); +} + +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + val = sccb_read(gspca_dev, 0x13); /* com8 */ + sccb_write(gspca_dev, 0xff, 0x00); + if (sd->freq == 0) { + sccb_write(gspca_dev, 0x13, val & 0xdf); + return; + } + sccb_write(gspca_dev, 0x13, val | 0x20); + + val = sccb_read(gspca_dev, 0x42); /* com17 */ + sccb_write(gspca_dev, 0xff, 0x00); + if (sd->freq == 1) + val |= 0x01; + else + val &= 0xfe; + sccb_write(gspca_dev, 0x42, val); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + + cam->cam_mode = ov965x_mode; + cam->nmodes = ARRAY_SIZE(ov965x_mode); + + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; +#if AUTOGAIN_DEF != 0 + sd->autogain = AUTOGAIN_DEF; + gspca_dev->ctrl_inac |= (1 << EXPO_IDX); +#endif +#if EXPO_DEF != 0 + sd->exposure = EXPO_DEF; +#endif +#if SHARPNESS_DEF != 0 + sd->sharpness = SHARPNESS_DEF; +#endif + sd->satur = SATUR_DEF; + sd->freq = FREQ_DEF; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + u16 sensor_id; + + /* reset bridge */ + reg_w(gspca_dev, 0xe7, 0x3a); + reg_w(gspca_dev, 0xe0, 0x08); + msleep(100); + + /* initialize the sensor address */ + reg_w(gspca_dev, OV534_REG_ADDRESS, 0x60); + + /* reset sensor */ + sccb_write(gspca_dev, 0x12, 0x80); + msleep(10); + + /* probe the sensor */ + sccb_read(gspca_dev, 0x0a); + sensor_id = sccb_read(gspca_dev, 0x0a) << 8; + sccb_read(gspca_dev, 0x0b); + sensor_id |= sccb_read(gspca_dev, 0x0b); + PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id); + + /* initialize */ + reg_w_array(gspca_dev, bridge_init, + ARRAY_SIZE(bridge_init)); + sccb_w_array(gspca_dev, sensor_init, + ARRAY_SIZE(sensor_init)); + reg_w_array(gspca_dev, bridge_init_2, + ARRAY_SIZE(bridge_init_2)); + sccb_w_array(gspca_dev, sensor_init_2, + ARRAY_SIZE(sensor_init_2)); + reg_w(gspca_dev, 0xe0, 0x00); + reg_w(gspca_dev, 0xe0, 0x01); + set_led(gspca_dev, 0); + reg_w(gspca_dev, 0xe0, 0x00); + + return gspca_dev->usb_err; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + switch (gspca_dev->curr_mode) { + case QVGA_MODE: /* 320x240 */ + sccb_w_array(gspca_dev, sensor_start_1_vga, + ARRAY_SIZE(sensor_start_1_vga)); + reg_w_array(gspca_dev, bridge_start_qvga, + ARRAY_SIZE(bridge_start_qvga)); + sccb_w_array(gspca_dev, sensor_start_2_qvga, + ARRAY_SIZE(sensor_start_2_qvga)); + break; + case VGA_MODE: /* 640x480 */ + sccb_w_array(gspca_dev, sensor_start_1_vga, + ARRAY_SIZE(sensor_start_1_vga)); + reg_w_array(gspca_dev, bridge_start_vga, + ARRAY_SIZE(bridge_start_vga)); + sccb_w_array(gspca_dev, sensor_start_2_vga, + ARRAY_SIZE(sensor_start_2_vga)); + break; + case SVGA_MODE: /* 800x600 */ + sccb_w_array(gspca_dev, sensor_start_1_svga, + ARRAY_SIZE(sensor_start_1_svga)); + reg_w_array(gspca_dev, bridge_start_svga, + ARRAY_SIZE(bridge_start_svga)); + sccb_w_array(gspca_dev, sensor_start_2_svga, + ARRAY_SIZE(sensor_start_2_svga)); + break; + case XGA_MODE: /* 1024x768 */ + sccb_w_array(gspca_dev, sensor_start_1_xga, + ARRAY_SIZE(sensor_start_1_xga)); + reg_w_array(gspca_dev, bridge_start_xga, + ARRAY_SIZE(bridge_start_xga)); + sccb_w_array(gspca_dev, sensor_start_2_svga, + ARRAY_SIZE(sensor_start_2_svga)); + break; + default: +/* case SXGA_MODE: * 1280x1024 */ + sccb_w_array(gspca_dev, sensor_start_1_sxga, + ARRAY_SIZE(sensor_start_1_sxga)); + reg_w_array(gspca_dev, bridge_start_sxga, + ARRAY_SIZE(bridge_start_sxga)); + sccb_w_array(gspca_dev, sensor_start_2_sxga, + ARRAY_SIZE(sensor_start_2_sxga)); + break; + } + setfreq(gspca_dev); + setautogain(gspca_dev); + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setexposure(gspca_dev); + setsharpness(gspca_dev); + setsatur(gspca_dev); + + reg_w(gspca_dev, 0xe0, 0x00); + reg_w(gspca_dev, 0xe0, 0x00); + set_led(gspca_dev, 1); + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0xe0, 0x01); + set_led(gspca_dev, 0); + reg_w(gspca_dev, 0xe0, 0x00); +} + +/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ +#define UVC_STREAM_EOH (1 << 7) +#define UVC_STREAM_ERR (1 << 6) +#define UVC_STREAM_STI (1 << 5) +#define UVC_STREAM_RES (1 << 4) +#define UVC_STREAM_SCR (1 << 3) +#define UVC_STREAM_PTS (1 << 2) +#define UVC_STREAM_EOF (1 << 1) +#define UVC_STREAM_FID (1 << 0) + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u32 this_pts; + u8 this_fid; + int remaining_len = len; + + do { + len = min(remaining_len, 2040); + + /* Payloads are prefixed with a UVC-style header. We + consider a frame to start when the FID toggles, or the PTS + changes. A frame ends when EOF is set, and we've received + the correct number of bytes. */ + + /* Verify UVC header. Header length is always 12 */ + if (data[0] != 12 || len < 12) { + PDEBUG(D_PACK, "bad header"); + goto discard; + } + + /* Check errors */ + if (data[1] & UVC_STREAM_ERR) { + PDEBUG(D_PACK, "payload error"); + goto discard; + } + + /* Extract PTS and FID */ + if (!(data[1] & UVC_STREAM_PTS)) { + PDEBUG(D_PACK, "PTS not present"); + goto discard; + } + this_pts = (data[5] << 24) | (data[4] << 16) + | (data[3] << 8) | data[2]; + this_fid = data[1] & UVC_STREAM_FID; + + /* If PTS or FID has changed, start a new frame. */ + if (this_pts != sd->last_pts || this_fid != sd->last_fid) { + if (gspca_dev->last_packet_type == INTER_PACKET) + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + sd->last_pts = this_pts; + sd->last_fid = this_fid; + gspca_frame_add(gspca_dev, FIRST_PACKET, + data + 12, len - 12); + /* If this packet is marked as EOF, end the frame */ + } else if (data[1] & UVC_STREAM_EOF) { + sd->last_pts = 0; + gspca_frame_add(gspca_dev, LAST_PACKET, + data + 12, len - 12); + } else { + + /* Add the data from this payload */ + gspca_frame_add(gspca_dev, INTER_PACKET, + data + 12, len - 12); + } + + /* Done this payload */ + goto scan_next; + +discard: + /* Discard data until a new frame starts. */ + gspca_dev->last_packet_type = DISCARD_PACKET; + +scan_next: + remaining_len -= len; + data += len; + } while (remaining_len > 0); +} + +/* controls */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + + if (gspca_dev->streaming) { + if (val) + gspca_dev->ctrl_inac |= (1 << EXPO_IDX); + else + gspca_dev->ctrl_inac &= ~(1 << EXPO_IDX); + setautogain(gspca_dev); + } + return gspca_dev->usb_err; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) + setsharpness(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + return 0; +} + +static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->satur = val; + if (gspca_dev->streaming) + setsatur(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->satur; + return 0; +} +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->freq = val; + if (gspca_dev->streaming) + setfreq(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->freq; + return 0; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "NoFliker"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x06f8, 0x3003)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov534.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov534.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov534.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/ov534.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1546 @@ +/* + * ov534-ov7xxx gspca driver + * + * Copyright (C) 2008 Antonio Ospite + * Copyright (C) 2008 Jim Paris + * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr + * + * Based on a prototype written by Mark Ferrell + * USB protocol reverse engineered by Jim Paris + * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ + * + * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr + * PS3 Eye camera - brightness, contrast, awb, agc, aec controls + * added by Max Thrun + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "ov534" + +#include "gspca.h" + +#define OV534_REG_ADDRESS 0xf1 /* sensor address */ +#define OV534_REG_SUBADDR 0xf2 +#define OV534_REG_WRITE 0xf3 +#define OV534_REG_READ 0xf4 +#define OV534_REG_OPERATION 0xf5 +#define OV534_REG_STATUS 0xf6 + +#define OV534_OP_WRITE_3 0x37 +#define OV534_OP_WRITE_2 0x33 +#define OV534_OP_READ_2 0xf9 + +#define CTRL_TIMEOUT 500 + +MODULE_AUTHOR("Antonio Ospite "); +MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* controls */ +enum e_ctrl { + BRIGHTNESS, + CONTRAST, + GAIN, + EXPOSURE, + AGC, + AWB, + AEC, + SHARPNESS, + HFLIP, + VFLIP, + COLORS, + LIGHTFREQ, + NCTRLS /* number of controls */ +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + + __u32 last_pts; + u16 last_fid; + u8 frame_rate; + + u8 sensor; +}; +enum sensors { + SENSOR_OV767x, + SENSOR_OV772x, + NSENSORS +}; + +/* V4L2 controls supported by the driver */ +static void setbrightness(struct gspca_dev *gspca_dev); +static void setcontrast(struct gspca_dev *gspca_dev); +static void setgain(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val); +static void setawb(struct gspca_dev *gspca_dev); +static void setaec(struct gspca_dev *gspca_dev); +static void setsharpness(struct gspca_dev *gspca_dev); +static void sethvflip(struct gspca_dev *gspca_dev); +static void setcolors(struct gspca_dev *gspca_dev); +static void setlightfreq(struct gspca_dev *gspca_dev); + +static int sd_start(struct gspca_dev *gspca_dev); +static void sd_stopN(struct gspca_dev *gspca_dev); + +static const struct ctrl sd_ctrls[] = { +[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0, + }, + .set_control = setbrightness + }, +[CONTRAST] = { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 32, + }, + .set_control = setcontrast + }, +[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Main Gain", + .minimum = 0, + .maximum = 63, + .step = 1, + .default_value = 20, + }, + .set_control = setgain + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 120, + }, + .set_control = setexposure + }, +[AGC] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set = sd_setagc + }, +[AWB] = { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto White Balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set_control = setawb + }, +[AEC] = { + { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set_control = setaec + }, +[SHARPNESS] = { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 63, + .step = 1, + .default_value = 0, + }, + .set_control = setsharpness + }, +[HFLIP] = { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "HFlip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set_control = sethvflip + }, +[VFLIP] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "VFlip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set_control = sethvflip + }, +[COLORS] = { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 3, + }, + .set_control = setcolors + }, +[LIGHTFREQ] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light Frequency Filter", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set_control = setlightfreq + }, +}; + +static const struct v4l2_pix_format ov772x_mode[] = { + {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 320 * 2, + .sizeimage = 320 * 240 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 640 * 2, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; +static const struct v4l2_pix_format ov767x_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, +}; + +static const u8 qvga_rates[] = {125, 100, 75, 60, 50, 40, 30}; +static const u8 vga_rates[] = {60, 50, 40, 30, 15}; + +static const struct framerates ov772x_framerates[] = { + { /* 320x240 */ + .rates = qvga_rates, + .nrates = ARRAY_SIZE(qvga_rates), + }, + { /* 640x480 */ + .rates = vga_rates, + .nrates = ARRAY_SIZE(vga_rates), + }, +}; + +struct reg_array { + const u8 (*val)[2]; + int len; +}; + +static const u8 bridge_init_767x[][2] = { +/* comments from the ms-win file apollo7670.set */ +/* str1 */ + {0xf1, 0x42}, + {0x88, 0xf8}, + {0x89, 0xff}, + {0x76, 0x03}, + {0x92, 0x03}, + {0x95, 0x10}, + {0xe2, 0x00}, + {0xe7, 0x3e}, + {0x8d, 0x1c}, + {0x8e, 0x00}, + {0x8f, 0x00}, + {0x1f, 0x00}, + {0xc3, 0xf9}, + {0x89, 0xff}, + {0x88, 0xf8}, + {0x76, 0x03}, + {0x92, 0x01}, + {0x93, 0x18}, + {0x1c, 0x00}, + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1d, 0x02}, + {0x1d, 0x58}, + {0x1d, 0x00}, + {0x1c, 0x0a}, + {0x1d, 0x0a}, + {0x1d, 0x0e}, + {0xc0, 0x50}, /* HSize 640 */ + {0xc1, 0x3c}, /* VSize 480 */ + {0x34, 0x05}, /* enable Audio Suspend mode */ + {0xc2, 0x0c}, /* Input YUV */ + {0xc3, 0xf9}, /* enable PRE */ + {0x34, 0x05}, /* enable Audio Suspend mode */ + {0xe7, 0x2e}, /* this solves failure of "SuspendResumeTest" */ + {0x31, 0xf9}, /* enable 1.8V Suspend */ + {0x35, 0x02}, /* turn on JPEG */ + {0xd9, 0x10}, + {0x25, 0x42}, /* GPIO[8]:Input */ + {0x94, 0x11}, /* If the default setting is loaded when + * system boots up, this flag is closed here */ +}; +static const u8 sensor_init_767x[][2] = { + {0x12, 0x80}, + {0x11, 0x03}, + {0x3a, 0x04}, + {0x12, 0x00}, + {0x17, 0x13}, + {0x18, 0x01}, + {0x32, 0xb6}, + {0x19, 0x02}, + {0x1a, 0x7a}, + {0x03, 0x0a}, + {0x0c, 0x00}, + {0x3e, 0x00}, + {0x70, 0x3a}, + {0x71, 0x35}, + {0x72, 0x11}, + {0x73, 0xf0}, + {0xa2, 0x02}, + {0x7a, 0x2a}, /* set Gamma=1.6 below */ + {0x7b, 0x12}, + {0x7c, 0x1d}, + {0x7d, 0x2d}, + {0x7e, 0x45}, + {0x7f, 0x50}, + {0x80, 0x59}, + {0x81, 0x62}, + {0x82, 0x6b}, + {0x83, 0x73}, + {0x84, 0x7b}, + {0x85, 0x8a}, + {0x86, 0x98}, + {0x87, 0xb2}, + {0x88, 0xca}, + {0x89, 0xe0}, + {0x13, 0xe0}, + {0x00, 0x00}, + {0x10, 0x00}, + {0x0d, 0x40}, + {0x14, 0x38}, /* gain max 16x */ + {0xa5, 0x05}, + {0xab, 0x07}, + {0x24, 0x95}, + {0x25, 0x33}, + {0x26, 0xe3}, + {0x9f, 0x78}, + {0xa0, 0x68}, + {0xa1, 0x03}, + {0xa6, 0xd8}, + {0xa7, 0xd8}, + {0xa8, 0xf0}, + {0xa9, 0x90}, + {0xaa, 0x94}, + {0x13, 0xe5}, + {0x0e, 0x61}, + {0x0f, 0x4b}, + {0x16, 0x02}, + {0x21, 0x02}, + {0x22, 0x91}, + {0x29, 0x07}, + {0x33, 0x0b}, + {0x35, 0x0b}, + {0x37, 0x1d}, + {0x38, 0x71}, + {0x39, 0x2a}, + {0x3c, 0x78}, + {0x4d, 0x40}, + {0x4e, 0x20}, + {0x69, 0x00}, + {0x6b, 0x4a}, + {0x74, 0x10}, + {0x8d, 0x4f}, + {0x8e, 0x00}, + {0x8f, 0x00}, + {0x90, 0x00}, + {0x91, 0x00}, + {0x96, 0x00}, + {0x9a, 0x80}, + {0xb0, 0x84}, + {0xb1, 0x0c}, + {0xb2, 0x0e}, + {0xb3, 0x82}, + {0xb8, 0x0a}, + {0x43, 0x0a}, + {0x44, 0xf0}, + {0x45, 0x34}, + {0x46, 0x58}, + {0x47, 0x28}, + {0x48, 0x3a}, + {0x59, 0x88}, + {0x5a, 0x88}, + {0x5b, 0x44}, + {0x5c, 0x67}, + {0x5d, 0x49}, + {0x5e, 0x0e}, + {0x6c, 0x0a}, + {0x6d, 0x55}, + {0x6e, 0x11}, + {0x6f, 0x9f}, + {0x6a, 0x40}, + {0x01, 0x40}, + {0x02, 0x40}, + {0x13, 0xe7}, + {0x4f, 0x80}, + {0x50, 0x80}, + {0x51, 0x00}, + {0x52, 0x22}, + {0x53, 0x5e}, + {0x54, 0x80}, + {0x58, 0x9e}, + {0x41, 0x08}, + {0x3f, 0x00}, + {0x75, 0x04}, + {0x76, 0xe1}, + {0x4c, 0x00}, + {0x77, 0x01}, + {0x3d, 0xc2}, + {0x4b, 0x09}, + {0xc9, 0x60}, + {0x41, 0x38}, /* jfm: auto sharpness + auto de-noise */ + {0x56, 0x40}, + {0x34, 0x11}, + {0x3b, 0xc2}, + {0xa4, 0x8a}, /* Night mode trigger point */ + {0x96, 0x00}, + {0x97, 0x30}, + {0x98, 0x20}, + {0x99, 0x20}, + {0x9a, 0x84}, + {0x9b, 0x29}, + {0x9c, 0x03}, + {0x9d, 0x4c}, + {0x9e, 0x3f}, + {0x78, 0x04}, + {0x79, 0x01}, + {0xc8, 0xf0}, + {0x79, 0x0f}, + {0xc8, 0x00}, + {0x79, 0x10}, + {0xc8, 0x7e}, + {0x79, 0x0a}, + {0xc8, 0x80}, + {0x79, 0x0b}, + {0xc8, 0x01}, + {0x79, 0x0c}, + {0xc8, 0x0f}, + {0x79, 0x0d}, + {0xc8, 0x20}, + {0x79, 0x09}, + {0xc8, 0x80}, + {0x79, 0x02}, + {0xc8, 0xc0}, + {0x79, 0x03}, + {0xc8, 0x20}, + {0x79, 0x26}, +}; +static const u8 bridge_start_vga_767x[][2] = { +/* str59 JPG */ + {0x94, 0xaa}, + {0xf1, 0x42}, + {0xe5, 0x04}, + {0xc0, 0x50}, + {0xc1, 0x3c}, + {0xc2, 0x0c}, + {0x35, 0x02}, /* turn on JPEG */ + {0xd9, 0x10}, + {0xda, 0x00}, /* for higher clock rate(30fps) */ + {0x34, 0x05}, /* enable Audio Suspend mode */ + {0xc3, 0xf9}, /* enable PRE */ + {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ + {0x8d, 0x1c}, /* output YUV */ +/* {0x34, 0x05}, * enable Audio Suspend mode (?) */ + {0x50, 0x00}, /* H/V divider=0 */ + {0x51, 0xa0}, /* input H=640/4 */ + {0x52, 0x3c}, /* input V=480/4 */ + {0x53, 0x00}, /* offset X=0 */ + {0x54, 0x00}, /* offset Y=0 */ + {0x55, 0x00}, /* H/V size[8]=0 */ + {0x57, 0x00}, /* H-size[9]=0 */ + {0x5c, 0x00}, /* output size[9:8]=0 */ + {0x5a, 0xa0}, /* output H=640/4 */ + {0x5b, 0x78}, /* output V=480/4 */ + {0x1c, 0x0a}, + {0x1d, 0x0a}, + {0x94, 0x11}, +}; +static const u8 sensor_start_vga_767x[][2] = { + {0x11, 0x01}, + {0x1e, 0x04}, + {0x19, 0x02}, + {0x1a, 0x7a}, +}; +static const u8 bridge_start_qvga_767x[][2] = { +/* str86 JPG */ + {0x94, 0xaa}, + {0xf1, 0x42}, + {0xe5, 0x04}, + {0xc0, 0x80}, + {0xc1, 0x60}, + {0xc2, 0x0c}, + {0x35, 0x02}, /* turn on JPEG */ + {0xd9, 0x10}, + {0xc0, 0x50}, /* CIF HSize 640 */ + {0xc1, 0x3c}, /* CIF VSize 480 */ + {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ + {0x8d, 0x1c}, /* output YUV */ + {0x34, 0x05}, /* enable Audio Suspend mode */ + {0xc2, 0x4c}, /* output YUV and Enable DCW */ + {0xc3, 0xf9}, /* enable PRE */ + {0x1c, 0x00}, /* indirect addressing */ + {0x1d, 0x48}, /* output YUV422 */ + {0x50, 0x89}, /* H/V divider=/2; plus DCW AVG */ + {0x51, 0xa0}, /* DCW input H=640/4 */ + {0x52, 0x78}, /* DCW input V=480/4 */ + {0x53, 0x00}, /* offset X=0 */ + {0x54, 0x00}, /* offset Y=0 */ + {0x55, 0x00}, /* H/V size[8]=0 */ + {0x57, 0x00}, /* H-size[9]=0 */ + {0x5c, 0x00}, /* DCW output size[9:8]=0 */ + {0x5a, 0x50}, /* DCW output H=320/4 */ + {0x5b, 0x3c}, /* DCW output V=240/4 */ + {0x1c, 0x0a}, + {0x1d, 0x0a}, + {0x94, 0x11}, +}; +static const u8 sensor_start_qvga_767x[][2] = { + {0x11, 0x01}, + {0x1e, 0x04}, + {0x19, 0x02}, + {0x1a, 0x7a}, +}; + +static const u8 bridge_init_772x[][2] = { + { 0xc2, 0x0c }, + { 0x88, 0xf8 }, + { 0xc3, 0x69 }, + { 0x89, 0xff }, + { 0x76, 0x03 }, + { 0x92, 0x01 }, + { 0x93, 0x18 }, + { 0x94, 0x10 }, + { 0x95, 0x10 }, + { 0xe2, 0x00 }, + { 0xe7, 0x3e }, + + { 0x96, 0x00 }, + + { 0x97, 0x20 }, + { 0x97, 0x20 }, + { 0x97, 0x20 }, + { 0x97, 0x0a }, + { 0x97, 0x3f }, + { 0x97, 0x4a }, + { 0x97, 0x20 }, + { 0x97, 0x15 }, + { 0x97, 0x0b }, + + { 0x8e, 0x40 }, + { 0x1f, 0x81 }, + { 0x34, 0x05 }, + { 0xe3, 0x04 }, + { 0x88, 0x00 }, + { 0x89, 0x00 }, + { 0x76, 0x00 }, + { 0xe7, 0x2e }, + { 0x31, 0xf9 }, + { 0x25, 0x42 }, + { 0x21, 0xf0 }, + + { 0x1c, 0x00 }, + { 0x1d, 0x40 }, + { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */ + { 0x1d, 0x00 }, /* payload size */ + + { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */ + { 0x1d, 0x58 }, /* frame size */ + { 0x1d, 0x00 }, /* frame size */ + + { 0x1c, 0x0a }, + { 0x1d, 0x08 }, /* turn on UVC header */ + { 0x1d, 0x0e }, /* .. */ + + { 0x8d, 0x1c }, + { 0x8e, 0x80 }, + { 0xe5, 0x04 }, + + { 0xc0, 0x50 }, + { 0xc1, 0x3c }, + { 0xc2, 0x0c }, +}; +static const u8 sensor_init_772x[][2] = { + { 0x12, 0x80 }, + { 0x11, 0x01 }, +/*fixme: better have a delay?*/ + { 0x11, 0x01 }, + { 0x11, 0x01 }, + { 0x11, 0x01 }, + { 0x11, 0x01 }, + { 0x11, 0x01 }, + { 0x11, 0x01 }, + { 0x11, 0x01 }, + { 0x11, 0x01 }, + { 0x11, 0x01 }, + { 0x11, 0x01 }, + + { 0x3d, 0x03 }, + { 0x17, 0x26 }, + { 0x18, 0xa0 }, + { 0x19, 0x07 }, + { 0x1a, 0xf0 }, + { 0x32, 0x00 }, + { 0x29, 0xa0 }, + { 0x2c, 0xf0 }, + { 0x65, 0x20 }, + { 0x11, 0x01 }, + { 0x42, 0x7f }, + { 0x63, 0xaa }, /* AWB - was e0 */ + { 0x64, 0xff }, + { 0x66, 0x00 }, + { 0x13, 0xf0 }, /* com8 */ + { 0x0d, 0x41 }, + { 0x0f, 0xc5 }, + { 0x14, 0x11 }, + + { 0x22, 0x7f }, + { 0x23, 0x03 }, + { 0x24, 0x40 }, + { 0x25, 0x30 }, + { 0x26, 0xa1 }, + { 0x2a, 0x00 }, + { 0x2b, 0x00 }, + { 0x6b, 0xaa }, + { 0x13, 0xff }, /* AWB */ + + { 0x90, 0x05 }, + { 0x91, 0x01 }, + { 0x92, 0x03 }, + { 0x93, 0x00 }, + { 0x94, 0x60 }, + { 0x95, 0x3c }, + { 0x96, 0x24 }, + { 0x97, 0x1e }, + { 0x98, 0x62 }, + { 0x99, 0x80 }, + { 0x9a, 0x1e }, + { 0x9b, 0x08 }, + { 0x9c, 0x20 }, + { 0x9e, 0x81 }, + + { 0xa6, 0x04 }, + { 0x7e, 0x0c }, + { 0x7f, 0x16 }, + { 0x80, 0x2a }, + { 0x81, 0x4e }, + { 0x82, 0x61 }, + { 0x83, 0x6f }, + { 0x84, 0x7b }, + { 0x85, 0x86 }, + { 0x86, 0x8e }, + { 0x87, 0x97 }, + { 0x88, 0xa4 }, + { 0x89, 0xaf }, + { 0x8a, 0xc5 }, + { 0x8b, 0xd7 }, + { 0x8c, 0xe8 }, + { 0x8d, 0x20 }, + + { 0x0c, 0x90 }, + + { 0x2b, 0x00 }, + { 0x22, 0x7f }, + { 0x23, 0x03 }, + { 0x11, 0x01 }, + { 0x0c, 0xd0 }, + { 0x64, 0xff }, + { 0x0d, 0x41 }, + + { 0x14, 0x41 }, + { 0x0e, 0xcd }, + { 0xac, 0xbf }, + { 0x8e, 0x00 }, /* De-noise threshold */ + { 0x0c, 0xd0 } +}; +static const u8 bridge_start_vga_772x[][2] = { + {0x1c, 0x00}, + {0x1d, 0x40}, + {0x1d, 0x02}, + {0x1d, 0x00}, + {0x1d, 0x02}, + {0x1d, 0x58}, + {0x1d, 0x00}, + {0xc0, 0x50}, + {0xc1, 0x3c}, +}; +static const u8 sensor_start_vga_772x[][2] = { + {0x12, 0x00}, + {0x17, 0x26}, + {0x18, 0xa0}, + {0x19, 0x07}, + {0x1a, 0xf0}, + {0x29, 0xa0}, + {0x2c, 0xf0}, + {0x65, 0x20}, +}; +static const u8 bridge_start_qvga_772x[][2] = { + {0x1c, 0x00}, + {0x1d, 0x40}, + {0x1d, 0x02}, + {0x1d, 0x00}, + {0x1d, 0x01}, + {0x1d, 0x4b}, + {0x1d, 0x00}, + {0xc0, 0x28}, + {0xc1, 0x1e}, +}; +static const u8 sensor_start_qvga_772x[][2] = { + {0x12, 0x40}, + {0x17, 0x3f}, + {0x18, 0x50}, + {0x19, 0x03}, + {0x1a, 0x78}, + {0x29, 0x50}, + {0x2c, 0x78}, + {0x65, 0x2f}, +}; + +static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) +{ + struct usb_device *udev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + + PDEBUG(D_USBO, "SET 01 0000 %04x %02x", reg, val); + gspca_dev->usb_buf[0] = val; + ret = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + 0x01, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); + if (ret < 0) { + err("write failed %d", ret); + gspca_dev->usb_err = ret; + } +} + +static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) +{ + struct usb_device *udev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return 0; + ret = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + 0x01, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); + PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]); + if (ret < 0) { + err("read failed %d", ret); + gspca_dev->usb_err = ret; + } + return gspca_dev->usb_buf[0]; +} + +/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. + * (direction and output)? */ +static void ov534_set_led(struct gspca_dev *gspca_dev, int status) +{ + u8 data; + + PDEBUG(D_CONF, "led status: %d", status); + + data = ov534_reg_read(gspca_dev, 0x21); + data |= 0x80; + ov534_reg_write(gspca_dev, 0x21, data); + + data = ov534_reg_read(gspca_dev, 0x23); + if (status) + data |= 0x80; + else + data &= ~0x80; + + ov534_reg_write(gspca_dev, 0x23, data); + + if (!status) { + data = ov534_reg_read(gspca_dev, 0x21); + data &= ~0x80; + ov534_reg_write(gspca_dev, 0x21, data); + } +} + +static int sccb_check_status(struct gspca_dev *gspca_dev) +{ + u8 data; + int i; + + for (i = 0; i < 5; i++) { + data = ov534_reg_read(gspca_dev, OV534_REG_STATUS); + + switch (data) { + case 0x00: + return 1; + case 0x04: + return 0; + case 0x03: + break; + default: + PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5", + data, i + 1); + } + } + return 0; +} + +static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) +{ + PDEBUG(D_USBO, "sccb write: %02x %02x", reg, val); + ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); + ov534_reg_write(gspca_dev, OV534_REG_WRITE, val); + ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); + + if (!sccb_check_status(gspca_dev)) { + err("sccb_reg_write failed"); + gspca_dev->usb_err = -EIO; + } +} + +static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg) +{ + ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); + ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); + if (!sccb_check_status(gspca_dev)) + err("sccb_reg_read failed 1"); + + ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); + if (!sccb_check_status(gspca_dev)) + err("sccb_reg_read failed 2"); + + return ov534_reg_read(gspca_dev, OV534_REG_READ); +} + +/* output a bridge sequence (reg - val) */ +static void reg_w_array(struct gspca_dev *gspca_dev, + const u8 (*data)[2], int len) +{ + while (--len >= 0) { + ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]); + data++; + } +} + +/* output a sensor sequence (reg - val) */ +static void sccb_w_array(struct gspca_dev *gspca_dev, + const u8 (*data)[2], int len) +{ + while (--len >= 0) { + if ((*data)[0] != 0xff) { + sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]); + } else { + sccb_reg_read(gspca_dev, (*data)[1]); + sccb_reg_write(gspca_dev, 0xff, 0x00); + } + data++; + } +} + +/* ov772x specific controls */ +static void set_frame_rate(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + struct rate_s { + u8 fps; + u8 r11; + u8 r0d; + u8 re5; + }; + const struct rate_s *r; + static const struct rate_s rate_0[] = { /* 640x480 */ + {60, 0x01, 0xc1, 0x04}, + {50, 0x01, 0x41, 0x02}, + {40, 0x02, 0xc1, 0x04}, + {30, 0x04, 0x81, 0x02}, + {15, 0x03, 0x41, 0x04}, + }; + static const struct rate_s rate_1[] = { /* 320x240 */ + {125, 0x02, 0x81, 0x02}, + {100, 0x02, 0xc1, 0x04}, + {75, 0x03, 0xc1, 0x04}, + {60, 0x04, 0xc1, 0x04}, + {50, 0x02, 0x41, 0x04}, + {40, 0x03, 0x41, 0x04}, + {30, 0x04, 0x41, 0x04}, + }; + + if (sd->sensor != SENSOR_OV772x) + return; + if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) { + r = rate_0; + i = ARRAY_SIZE(rate_0); + } else { + r = rate_1; + i = ARRAY_SIZE(rate_1); + } + while (--i > 0) { + if (sd->frame_rate >= r->fps) + break; + r++; + } + + sccb_reg_write(gspca_dev, 0x11, r->r11); + sccb_reg_write(gspca_dev, 0x0d, r->r0d); + ov534_reg_write(gspca_dev, 0xe5, r->re5); + + PDEBUG(D_PROBE, "frame_rate: %d", r->fps); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + + val = sd->ctrls[BRIGHTNESS].val; + if (sd->sensor == SENSOR_OV767x) { + if (val < 0) + val = 0x80 - val; + sccb_reg_write(gspca_dev, 0x55, val); /* bright */ + } else { + sccb_reg_write(gspca_dev, 0x9b, val); + } +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + val = sd->ctrls[CONTRAST].val; + if (sd->sensor == SENSOR_OV767x) + sccb_reg_write(gspca_dev, 0x56, val); /* contras */ + else + sccb_reg_write(gspca_dev, 0x9c, val); +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + if (sd->ctrls[AGC].val) + return; + + val = sd->ctrls[GAIN].val; + switch (val & 0x30) { + case 0x00: + val &= 0x0f; + break; + case 0x10: + val &= 0x0f; + val |= 0x30; + break; + case 0x20: + val &= 0x0f; + val |= 0x70; + break; + default: +/* case 0x30: */ + val &= 0x0f; + val |= 0xf0; + break; + } + sccb_reg_write(gspca_dev, 0x00, val); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + if (sd->ctrls[AEC].val) + return; + + val = sd->ctrls[EXPOSURE].val; + if (sd->sensor == SENSOR_OV767x) { + + /* set only aec[9:2] */ + sccb_reg_write(gspca_dev, 0x10, val); /* aech */ + } else { + + /* 'val' is one byte and represents half of the exposure value + * we are going to set into registers, a two bytes value: + * + * MSB: ((u16) val << 1) >> 8 == val >> 7 + * LSB: ((u16) val << 1) & 0xff == val << 1 + */ + sccb_reg_write(gspca_dev, 0x08, val >> 7); + sccb_reg_write(gspca_dev, 0x10, val << 1); + } +} + +static void setagc(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->ctrls[AGC].val) { + sccb_reg_write(gspca_dev, 0x13, + sccb_reg_read(gspca_dev, 0x13) | 0x04); + sccb_reg_write(gspca_dev, 0x64, + sccb_reg_read(gspca_dev, 0x64) | 0x03); + } else { + sccb_reg_write(gspca_dev, 0x13, + sccb_reg_read(gspca_dev, 0x13) & ~0x04); + sccb_reg_write(gspca_dev, 0x64, + sccb_reg_read(gspca_dev, 0x64) & ~0x03); + + setgain(gspca_dev); + } +} + +static void setawb(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->ctrls[AWB].val) { + sccb_reg_write(gspca_dev, 0x13, + sccb_reg_read(gspca_dev, 0x13) | 0x02); + if (sd->sensor == SENSOR_OV772x) + sccb_reg_write(gspca_dev, 0x63, + sccb_reg_read(gspca_dev, 0x63) | 0xc0); + } else { + sccb_reg_write(gspca_dev, 0x13, + sccb_reg_read(gspca_dev, 0x13) & ~0x02); + if (sd->sensor == SENSOR_OV772x) + sccb_reg_write(gspca_dev, 0x63, + sccb_reg_read(gspca_dev, 0x63) & ~0xc0); + } +} + +static void setaec(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data; + + data = sd->sensor == SENSOR_OV767x ? + 0x05 : /* agc + aec */ + 0x01; /* agc */ + if (sd->ctrls[AEC].val) + sccb_reg_write(gspca_dev, 0x13, + sccb_reg_read(gspca_dev, 0x13) | data); + else { + sccb_reg_write(gspca_dev, 0x13, + sccb_reg_read(gspca_dev, 0x13) & ~data); + if (sd->sensor == SENSOR_OV767x) + sd->ctrls[EXPOSURE].val = + sccb_reg_read(gspca_dev, 10); /* aech */ + else + setexposure(gspca_dev); + } +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + val = sd->ctrls[SHARPNESS].val; + sccb_reg_write(gspca_dev, 0x91, val); /* Auto de-noise threshold */ + sccb_reg_write(gspca_dev, 0x8e, val); /* De-noise threshold */ +} + +static void sethvflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + if (sd->sensor == SENSOR_OV767x) { + val = sccb_reg_read(gspca_dev, 0x1e); /* mvfp */ + val &= ~0x30; + if (sd->ctrls[HFLIP].val) + val |= 0x20; + if (sd->ctrls[VFLIP].val) + val |= 0x10; + sccb_reg_write(gspca_dev, 0x1e, val); + } else { + val = sccb_reg_read(gspca_dev, 0x0c); + val &= ~0xc0; + if (sd->ctrls[HFLIP].val == 0) + val |= 0x40; + if (sd->ctrls[VFLIP].val == 0) + val |= 0x80; + sccb_reg_write(gspca_dev, 0x0c, val); + } +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + int i; + static u8 color_tb[][6] = { + {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, + {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, + {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, + {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, + {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, + {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, + {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, + }; + + val = sd->ctrls[COLORS].val; + for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) + sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); +} + +static void setlightfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + val = sd->ctrls[LIGHTFREQ].val ? 0x9e : 0x00; + if (sd->sensor == SENSOR_OV767x) { + sccb_reg_write(gspca_dev, 0x2a, 0x00); + if (val) + val = 0x9d; /* insert dummy to 25fps for 50Hz */ + } + sccb_reg_write(gspca_dev, 0x2b, val); +} + + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + + cam->ctrls = sd->ctrls; + + /* the auto white balance control works only when auto gain is set */ + if (sd_ctrls[AGC].qctrl.default_value == 0) + gspca_dev->ctrl_inac |= (1 << AWB); + + cam->cam_mode = ov772x_mode; + cam->nmodes = ARRAY_SIZE(ov772x_mode); + + sd->frame_rate = 30; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 sensor_id; + static const struct reg_array bridge_init[NSENSORS] = { + [SENSOR_OV767x] = {bridge_init_767x, ARRAY_SIZE(bridge_init_767x)}, + [SENSOR_OV772x] = {bridge_init_772x, ARRAY_SIZE(bridge_init_772x)}, + }; + static const struct reg_array sensor_init[NSENSORS] = { + [SENSOR_OV767x] = {sensor_init_767x, ARRAY_SIZE(sensor_init_767x)}, + [SENSOR_OV772x] = {sensor_init_772x, ARRAY_SIZE(sensor_init_772x)}, + }; + + /* reset bridge */ + ov534_reg_write(gspca_dev, 0xe7, 0x3a); + ov534_reg_write(gspca_dev, 0xe0, 0x08); + msleep(100); + + /* initialize the sensor address */ + ov534_reg_write(gspca_dev, OV534_REG_ADDRESS, 0x42); + + /* reset sensor */ + sccb_reg_write(gspca_dev, 0x12, 0x80); + msleep(10); + + /* probe the sensor */ + sccb_reg_read(gspca_dev, 0x0a); + sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8; + sccb_reg_read(gspca_dev, 0x0b); + sensor_id |= sccb_reg_read(gspca_dev, 0x0b); + PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id); + + if ((sensor_id & 0xfff0) == 0x7670) { + sd->sensor = SENSOR_OV767x; + gspca_dev->ctrl_dis = (1 << GAIN) | + (1 << AGC) | + (1 << SHARPNESS); /* auto */ + sd->ctrls[BRIGHTNESS].min = -127; + sd->ctrls[BRIGHTNESS].max = 127; + sd->ctrls[BRIGHTNESS].def = 0; + sd->ctrls[CONTRAST].max = 0x80; + sd->ctrls[CONTRAST].def = 0x40; + sd->ctrls[EXPOSURE].min = 0x08; + sd->ctrls[EXPOSURE].max = 0x60; + sd->ctrls[EXPOSURE].def = 0x13; + sd->ctrls[SHARPNESS].max = 9; + sd->ctrls[SHARPNESS].def = 4; + sd->ctrls[HFLIP].def = 1; + gspca_dev->cam.cam_mode = ov767x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); + } else { + sd->sensor = SENSOR_OV772x; + gspca_dev->ctrl_dis = (1 << COLORS); + gspca_dev->cam.bulk = 1; + gspca_dev->cam.bulk_size = 16384; + gspca_dev->cam.bulk_nurbs = 2; + gspca_dev->cam.mode_framerates = ov772x_framerates; + } + + /* initialize */ + reg_w_array(gspca_dev, bridge_init[sd->sensor].val, + bridge_init[sd->sensor].len); + ov534_set_led(gspca_dev, 1); + sccb_w_array(gspca_dev, sensor_init[sd->sensor].val, + sensor_init[sd->sensor].len); + if (sd->sensor == SENSOR_OV767x) + sd_start(gspca_dev); + sd_stopN(gspca_dev); +/* set_frame_rate(gspca_dev); */ + + return gspca_dev->usb_err; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int mode; + static const struct reg_array bridge_start[NSENSORS][2] = { + [SENSOR_OV767x] = {{bridge_start_qvga_767x, + ARRAY_SIZE(bridge_start_qvga_767x)}, + {bridge_start_vga_767x, + ARRAY_SIZE(bridge_start_vga_767x)}}, + [SENSOR_OV772x] = {{bridge_start_qvga_772x, + ARRAY_SIZE(bridge_start_qvga_772x)}, + {bridge_start_vga_772x, + ARRAY_SIZE(bridge_start_vga_772x)}}, + }; + static const struct reg_array sensor_start[NSENSORS][2] = { + [SENSOR_OV767x] = {{sensor_start_qvga_767x, + ARRAY_SIZE(sensor_start_qvga_767x)}, + {sensor_start_vga_767x, + ARRAY_SIZE(sensor_start_vga_767x)}}, + [SENSOR_OV772x] = {{sensor_start_qvga_772x, + ARRAY_SIZE(sensor_start_qvga_772x)}, + {sensor_start_vga_772x, + ARRAY_SIZE(sensor_start_vga_772x)}}, + }; + + /* (from ms-win trace) */ + if (sd->sensor == SENSOR_OV767x) + sccb_reg_write(gspca_dev, 0x1e, 0x04); + /* black sun enable ? */ + + mode = gspca_dev->curr_mode; /* 0: 320x240, 1: 640x480 */ + reg_w_array(gspca_dev, bridge_start[sd->sensor][mode].val, + bridge_start[sd->sensor][mode].len); + sccb_w_array(gspca_dev, sensor_start[sd->sensor][mode].val, + sensor_start[sd->sensor][mode].len); + + set_frame_rate(gspca_dev); + + if (!(gspca_dev->ctrl_dis & (1 << AGC))) + setagc(gspca_dev); + setawb(gspca_dev); + setaec(gspca_dev); + if (!(gspca_dev->ctrl_dis & (1 << GAIN))) + setgain(gspca_dev); + setexposure(gspca_dev); + setbrightness(gspca_dev); + setcontrast(gspca_dev); + if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS))) + setsharpness(gspca_dev); + sethvflip(gspca_dev); + if (!(gspca_dev->ctrl_dis & (1 << COLORS))) + setcolors(gspca_dev); + setlightfreq(gspca_dev); + + ov534_set_led(gspca_dev, 1); + ov534_reg_write(gspca_dev, 0xe0, 0x00); + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + ov534_reg_write(gspca_dev, 0xe0, 0x09); + ov534_set_led(gspca_dev, 0); +} + +/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ +#define UVC_STREAM_EOH (1 << 7) +#define UVC_STREAM_ERR (1 << 6) +#define UVC_STREAM_STI (1 << 5) +#define UVC_STREAM_RES (1 << 4) +#define UVC_STREAM_SCR (1 << 3) +#define UVC_STREAM_PTS (1 << 2) +#define UVC_STREAM_EOF (1 << 1) +#define UVC_STREAM_FID (1 << 0) + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u32 this_pts; + u16 this_fid; + int remaining_len = len; + int payload_len; + + payload_len = gspca_dev->cam.bulk ? 2048 : 2040; + do { + len = min(remaining_len, payload_len); + + /* Payloads are prefixed with a UVC-style header. We + consider a frame to start when the FID toggles, or the PTS + changes. A frame ends when EOF is set, and we've received + the correct number of bytes. */ + + /* Verify UVC header. Header length is always 12 */ + if (data[0] != 12 || len < 12) { + PDEBUG(D_PACK, "bad header"); + goto discard; + } + + /* Check errors */ + if (data[1] & UVC_STREAM_ERR) { + PDEBUG(D_PACK, "payload error"); + goto discard; + } + + /* Extract PTS and FID */ + if (!(data[1] & UVC_STREAM_PTS)) { + PDEBUG(D_PACK, "PTS not present"); + goto discard; + } + this_pts = (data[5] << 24) | (data[4] << 16) + | (data[3] << 8) | data[2]; + this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0; + + /* If PTS or FID has changed, start a new frame. */ + if (this_pts != sd->last_pts || this_fid != sd->last_fid) { + if (gspca_dev->last_packet_type == INTER_PACKET) + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + sd->last_pts = this_pts; + sd->last_fid = this_fid; + gspca_frame_add(gspca_dev, FIRST_PACKET, + data + 12, len - 12); + /* If this packet is marked as EOF, end the frame */ + } else if (data[1] & UVC_STREAM_EOF) { + sd->last_pts = 0; + if (gspca_dev->pixfmt == V4L2_PIX_FMT_YUYV + && gspca_dev->image_len + len - 12 != + gspca_dev->width * gspca_dev->height * 2) { + PDEBUG(D_PACK, "wrong sized frame"); + goto discard; + } + gspca_frame_add(gspca_dev, LAST_PACKET, + data + 12, len - 12); + } else { + + /* Add the data from this payload */ + gspca_frame_add(gspca_dev, INTER_PACKET, + data + 12, len - 12); + } + + /* Done this payload */ + goto scan_next; + +discard: + /* Discard data until a new frame starts. */ + gspca_dev->last_packet_type = DISCARD_PACKET; + +scan_next: + remaining_len -= len; + data += len; + } while (remaining_len > 0); +} + +static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[AGC].val = val; + + /* the auto white balance control works only + * when auto gain is set */ + if (val) { + gspca_dev->ctrl_inac &= ~(1 << AWB); + } else { + gspca_dev->ctrl_inac |= (1 << AWB); + if (sd->ctrls[AWB].val) { + sd->ctrls[AWB].val = 0; + if (gspca_dev->streaming) + setawb(gspca_dev); + } + } + if (gspca_dev->streaming) + setagc(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "Disabled"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + } + break; + } + + return -EINVAL; +} + +/* get stream parameters (framerate) */ +static void sd_get_streamparm(struct gspca_dev *gspca_dev, + struct v4l2_streamparm *parm) +{ + struct v4l2_captureparm *cp = &parm->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + struct sd *sd = (struct sd *) gspca_dev; + + cp->capability |= V4L2_CAP_TIMEPERFRAME; + tpf->numerator = 1; + tpf->denominator = sd->frame_rate; +} + +/* set stream parameters (framerate) */ +static void sd_set_streamparm(struct gspca_dev *gspca_dev, + struct v4l2_streamparm *parm) +{ + struct v4l2_captureparm *cp = &parm->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + struct sd *sd = (struct sd *) gspca_dev; + + /* Set requested framerate */ + sd->frame_rate = tpf->denominator / tpf->numerator; + if (gspca_dev->streaming) + set_frame_rate(gspca_dev); + + /* Return the actual framerate */ + tpf->numerator = 1; + tpf->denominator = sd->frame_rate; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, + .get_streamparm = sd_get_streamparm, + .set_streamparm = sd_set_streamparm, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x1415, 0x2000)}, + {USB_DEVICE(0x06f8, 0x3002)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac207.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac207.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac207.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac207.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,581 @@ +/* + * Pixart PAC207BCA library + * + * Copyright (C) 2008 Hans de Goede + * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li + * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * (at your option) any later version. + * + * 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 + * + */ + +#define MODULE_NAME "pac207" + +#include +#include "gspca.h" + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Pixart PAC207"); +MODULE_LICENSE("GPL"); + +#define PAC207_CTRL_TIMEOUT 100 /* ms */ + +#define PAC207_BRIGHTNESS_MIN 0 +#define PAC207_BRIGHTNESS_MAX 255 +#define PAC207_BRIGHTNESS_DEFAULT 46 + +#define PAC207_EXPOSURE_MIN 3 +#define PAC207_EXPOSURE_MAX 26 +#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */ +#define PAC207_EXPOSURE_KNEE 8 /* 4 = 30 fps, 11 = 8, 15 = 6 */ + +#define PAC207_GAIN_MIN 0 +#define PAC207_GAIN_MAX 31 +#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */ +#define PAC207_GAIN_KNEE 31 + +#define PAC207_AUTOGAIN_DEADZONE 30 + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u8 mode; + + u8 brightness; + u8 exposure; + u8 autogain; + u8 gain; + + u8 sof_read; + u8 header_read; + u8 autogain_ignore_frames; + + atomic_t avg_lum; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = PAC207_BRIGHTNESS_MIN, + .maximum = PAC207_BRIGHTNESS_MAX, + .step = 1, + .default_value = PAC207_BRIGHTNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_EXPOSURE 1 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = PAC207_EXPOSURE_MIN, + .maximum = PAC207_EXPOSURE_MAX, + .step = 1, + .default_value = PAC207_EXPOSURE_DEFAULT, + .flags = 0, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, +#define SD_AUTOGAIN 2 + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + .flags = 0, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +#define SD_GAIN 3 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = PAC207_GAIN_MIN, + .maximum = PAC207_GAIN_MAX, + .step = 1, + .default_value = PAC207_GAIN_DEFAULT, + .flags = 0, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static const struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = (176 + 2) * 144, + /* uncompressed, add 2 bytes / line for line header */ + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, + .bytesperline = 352, + /* compressed, but only when needed (not compressed + when the framerate is low) */ + .sizeimage = (352 + 2) * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +static const __u8 pac207_sensor_init[][8] = { + {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84}, + {0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30}, + {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00}, + {0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00}, +}; + +static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, + const u8 *buffer, u16 length) +{ + struct usb_device *udev = gspca_dev->dev; + int err; + + memcpy(gspca_dev->usb_buf, buffer, length); + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x00, index, + gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT); + if (err < 0) + err("Failed to write registers to index 0x%04X, error %d)", + index, err); + + return err; +} + + +static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) +{ + struct usb_device *udev = gspca_dev->dev; + int err; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, index, NULL, 0, PAC207_CTRL_TIMEOUT); + if (err) + err("Failed to write a register (index 0x%04X," + " value 0x%02X, error %d)", index, value, err); + + return err; +} + +static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) +{ + struct usb_device *udev = gspca_dev->dev; + int res; + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x00, index, + gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT); + if (res < 0) { + err("Failed to read a register (index 0x%04X, error %d)", + index, res); + return res; + } + + return gspca_dev->usb_buf[0]; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + u8 idreg[2]; + + idreg[0] = pac207_read_reg(gspca_dev, 0x0000); + idreg[1] = pac207_read_reg(gspca_dev, 0x0001); + idreg[0] = ((idreg[0] & 0x0f) << 4) | ((idreg[1] & 0xf0) >> 4); + idreg[1] = idreg[1] & 0x0f; + PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X", + idreg[0], idreg[1]); + + if (idreg[0] != 0x27) { + PDEBUG(D_PROBE, "Error invalid sensor ID!"); + return -ENODEV; + } + + PDEBUG(D_PROBE, + "Pixart PAC207BCA Image Processor and Control Chip detected" + " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + + cam = &gspca_dev->cam; + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + sd->brightness = PAC207_BRIGHTNESS_DEFAULT; + sd->exposure = PAC207_EXPOSURE_DEFAULT; + sd->gain = PAC207_GAIN_DEFAULT; + sd->autogain = AUTOGAIN_DEF; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + pac207_write_reg(gspca_dev, 0x41, 0x00); + /* Bit_0=Image Format, + * Bit_1=LED, + * Bit_2=Compression test mode enable */ + pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ + + return 0; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 mode; + + pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */ + pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8); + pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8); + pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8); + pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8); + + /* Compression Balance */ + if (gspca_dev->width == 176) + pac207_write_reg(gspca_dev, 0x4a, 0xff); + else + pac207_write_reg(gspca_dev, 0x4a, 0x30); + pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */ + pac207_write_reg(gspca_dev, 0x08, sd->brightness); + + /* PGA global gain (Bit 4-0) */ + pac207_write_reg(gspca_dev, 0x0e, sd->gain); + pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */ + + mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */ + if (gspca_dev->width == 176) { /* 176x144 */ + mode |= 0x01; + PDEBUG(D_STREAM, "pac207_start mode 176x144"); + } else { /* 352x288 */ + PDEBUG(D_STREAM, "pac207_start mode 352x288"); + } + pac207_write_reg(gspca_dev, 0x41, mode); + + pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ + pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ + msleep(10); + pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */ + + sd->sof_read = 0; + sd->autogain_ignore_frames = 0; + atomic_set(&sd->avg_lum, -1); + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */ + pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */ + pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ +} + +/* Include pac common sof detection functions */ +#include "pac_common.h" + +static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum = atomic_read(&sd->avg_lum); + + if (avg_lum == -1) + return; + + if (sd->autogain_ignore_frames > 0) + sd->autogain_ignore_frames--; + else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, + 100, PAC207_AUTOGAIN_DEADZONE, + PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, + int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned char *sof; + + sof = pac_find_sof(&sd->sof_read, data, len); + if (sof) { + int n; + + /* finish decoding current frame */ + n = sof - data; + if (n > sizeof pac_sof_marker) + n -= sizeof pac_sof_marker; + else + n = 0; + gspca_frame_add(gspca_dev, LAST_PACKET, + data, n); + sd->header_read = 0; + gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); + len -= sof - data; + data = sof; + } + if (sd->header_read < 11) { + int needed; + + /* get average lumination from frame header (byte 5) */ + if (sd->header_read < 5) { + needed = 5 - sd->header_read; + if (len >= needed) + atomic_set(&sd->avg_lum, data[needed - 1]); + } + /* skip the rest of the header */ + needed = 11 - sd->header_read; + if (len <= needed) { + sd->header_read += len; + return; + } + data += needed; + len -= needed; + sd->header_read = 11; + } + + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + pac207_write_reg(gspca_dev, 0x08, sd->brightness); + pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ + pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + pac207_write_reg(gspca_dev, 0x02, sd->exposure); + pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ + pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + pac207_write_reg(gspca_dev, 0x0e, sd->gain); + pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ + pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + if (sd->autogain) { + sd->exposure = PAC207_EXPOSURE_DEFAULT; + sd->gain = PAC207_GAIN_DEFAULT; + if (gspca_dev->streaming) { + sd->autogain_ignore_frames = + PAC_AUTOGAIN_IGNORE_FRAMES; + setexposure(gspca_dev); + setgain(gspca_dev); + } + } + + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet data */ + int len) /* interrput packet length */ +{ + int ret = -EINVAL; + + if (len == 2 && data[0] == 0x5a && data[1] == 0x5a) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); + input_sync(gspca_dev->input_dev); + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + ret = 0; + } + + return ret; +} +#endif + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .dq_callback = pac207_do_auto_gain, + .pkt_scan = sd_pkt_scan, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +#endif +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x4028)}, + {USB_DEVICE(0x093a, 0x2460)}, + {USB_DEVICE(0x093a, 0x2461)}, + {USB_DEVICE(0x093a, 0x2463)}, + {USB_DEVICE(0x093a, 0x2464)}, + {USB_DEVICE(0x093a, 0x2468)}, + {USB_DEVICE(0x093a, 0x2470)}, + {USB_DEVICE(0x093a, 0x2471)}, + {USB_DEVICE(0x093a, 0x2472)}, + {USB_DEVICE(0x093a, 0x2474)}, + {USB_DEVICE(0x093a, 0x2476)}, + {USB_DEVICE(0x145f, 0x013a)}, + {USB_DEVICE(0x2001, 0xf115)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac7302.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac7302.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac7302.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac7302.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1233 @@ +/* + * Pixart PAC7302 library + * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li + * + * V4L2 by Jean-Francois Moine + * + * Separated from Pixart PAC7311 library by Márton Németh + * Camera button input handling by Márton Németh + * Copyright (C) 2009-2010 Márton Németh + * + * 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, or + * any later version. + * + * 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 + */ + +/* Some documentation about various registers as determined by trial and error. + + Register page 1: + + Address Description + 0x78 Global control, bit 6 controls the LED (inverted) + + Register page 3: + + Address Description + 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on + the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? + 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps + 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps, + 63 -> ~27 fps, the 2 msb's must always be 1 !! + 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0: + 1 -> ~30 fps, 2 -> ~20 fps + 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time + 0x0f Exposure bit 8, 0-448, 448 = no exposure at all + 0x10 Master gain 0-31 + 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused + + The registers are accessed in the following functions: + + Page | Register | Function + -----+------------+--------------------------------------------------- + 0 | 0x0f..0x20 | setcolors() + 0 | 0xa2..0xab | setbrightcont() + 0 | 0xc5 | setredbalance() + 0 | 0xc6 | setwhitebalance() + 0 | 0xc7 | setbluebalance() + 0 | 0xdc | setbrightcont(), setcolors() + 3 | 0x02 | setexposure() + 3 | 0x10 | setgain() + 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip() + 3 | 0x21 | sethvflip() +*/ + +#define MODULE_NAME "pac7302" + +#include +#include +#include "gspca.h" + +MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); +MODULE_DESCRIPTION("Pixart PAC7302"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor for pac7302 */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + unsigned char white_balance; + unsigned char red_balance; + unsigned char blue_balance; + unsigned char gain; + unsigned char autogain; + unsigned short exposure; + __u8 hflip; + __u8 vflip; + u8 flags; +#define FL_HFLIP 0x01 /* mirrored by default */ +#define FL_VFLIP 0x02 /* vertical flipped by default */ + + u8 sof_read; + u8 autogain_ignore_frames; + + atomic_t avg_lum; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, +#define BRIGHTNESS_MAX 0x20 + .maximum = BRIGHTNESS_MAX, + .step = 1, +#define BRIGHTNESS_DEF 0x10 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, +#define CONTRAST_MAX 255 + .maximum = CONTRAST_MAX, + .step = 1, +#define CONTRAST_DEF 127 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, +#define COLOR_MAX 255 + .maximum = COLOR_MAX, + .step = 1, +#define COLOR_DEF 127 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, + { + { + .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "White Balance", + .minimum = 0, + .maximum = 255, + .step = 1, +#define WHITEBALANCE_DEF 4 + .default_value = WHITEBALANCE_DEF, + }, + .set = sd_setwhitebalance, + .get = sd_getwhitebalance, + }, + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red", + .minimum = 0, + .maximum = 3, + .step = 1, +#define REDBALANCE_DEF 1 + .default_value = REDBALANCE_DEF, + }, + .set = sd_setredbalance, + .get = sd_getredbalance, + }, + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue", + .minimum = 0, + .maximum = 3, + .step = 1, +#define BLUEBALANCE_DEF 1 + .default_value = BLUEBALANCE_DEF, + }, + .set = sd_setbluebalance, + .get = sd_getbluebalance, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, +#define GAIN_MAX 255 + .maximum = GAIN_MAX, + .step = 1, +#define GAIN_DEF 127 +#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 1023, + .step = 1, +#define EXPOSURE_DEF 66 /* 33 ms / 30 fps */ +#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, +#define HFLIP_DEF 0 + .default_value = HFLIP_DEF, + }, + .set = sd_sethflip, + .get = sd_gethflip, + }, + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define VFLIP_DEF 0 + .default_value = VFLIP_DEF, + }, + .set = sd_setvflip, + .get = sd_getvflip, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +#define LOAD_PAGE3 255 +#define END_OF_SEQUENCE 0 + +/* pac 7302 */ +static const __u8 init_7302[] = { +/* index,value */ + 0xff, 0x01, /* page 1 */ + 0x78, 0x00, /* deactivate */ + 0xff, 0x01, + 0x78, 0x40, /* led off */ +}; +static const __u8 start_7302[] = { +/* index, len, [value]* */ + 0xff, 1, 0x00, /* page 0 */ + 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00, + 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7, + 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11, + 0x26, 2, 0xaa, 0xaa, + 0x2e, 1, 0x31, + 0x38, 1, 0x01, + 0x3a, 3, 0x14, 0xff, 0x5a, + 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11, + 0x00, 0x54, 0x11, + 0x55, 1, 0x00, + 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, + 0x6b, 1, 0x00, + 0x6e, 3, 0x08, 0x06, 0x00, + 0x72, 3, 0x00, 0xff, 0x00, + 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c, + 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50, + 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00, + 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9, + 0xd2, 0xeb, + 0xaf, 1, 0x02, + 0xb5, 2, 0x08, 0x08, + 0xb8, 2, 0x08, 0x88, + 0xc4, 4, 0xae, 0x01, 0x04, 0x01, + 0xcc, 1, 0x00, + 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9, + 0xc1, 0xd7, 0xec, + 0xdc, 1, 0x01, + 0xff, 1, 0x01, /* page 1 */ + 0x12, 3, 0x02, 0x00, 0x01, + 0x3e, 2, 0x00, 0x00, + 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2, + 0x7c, 1, 0x00, + 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20, + 0x02, 0x00, + 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04, + 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x07, 0x00, 0x01, 0x07, 0x04, 0x01, + 0xd8, 1, 0x01, + 0xdb, 2, 0x00, 0x01, + 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00, + 0xe6, 4, 0x00, 0x00, 0x00, 0x01, + 0xeb, 1, 0x00, + 0xff, 1, 0x02, /* page 2 */ + 0x22, 1, 0x00, + 0xff, 1, 0x03, /* page 3 */ + 0, LOAD_PAGE3, /* load the page 3 */ + 0x11, 1, 0x01, + 0xff, 1, 0x02, /* page 2 */ + 0x13, 1, 0x00, + 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96, + 0x27, 2, 0x14, 0x0c, + 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22, + 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44, + 0x6e, 1, 0x08, + 0xff, 1, 0x01, /* page 1 */ + 0x78, 1, 0x00, + 0, END_OF_SEQUENCE /* end of sequence */ +}; + +#define SKIP 0xaa +/* page 3 - the value SKIP says skip the index - see reg_w_page() */ +static const __u8 page3_7302[] = { + 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16, + 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, + 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21, + 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54, + 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00, + SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8, + 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00, + 0x00 +}; + +static void reg_w_buf(struct gspca_dev *gspca_dev, + __u8 index, + const u8 *buffer, int len) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + memcpy(gspca_dev->usb_buf, buffer, len); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, len, + 500); + if (ret < 0) { + err("reg_w_buf failed index 0x%02x, error %d", + index, ret); + gspca_dev->usb_err = ret; + } +} + + +static void reg_w(struct gspca_dev *gspca_dev, + __u8 index, + __u8 value) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + gspca_dev->usb_buf[0] = value; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { + err("reg_w() failed index 0x%02x, value 0x%02x, error %d", + index, value, ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w_seq(struct gspca_dev *gspca_dev, + const __u8 *seq, int len) +{ + while (--len >= 0) { + reg_w(gspca_dev, seq[0], seq[1]); + seq += 2; + } +} + +/* load the beginning of a page */ +static void reg_w_page(struct gspca_dev *gspca_dev, + const __u8 *page, int len) +{ + int index; + int ret = 0; + + if (gspca_dev->usb_err < 0) + return; + for (index = 0; index < len; index++) { + if (page[index] == SKIP) /* skip this index */ + continue; + gspca_dev->usb_buf[0] = page[index]; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { + err("reg_w_page() failed index 0x%02x, " + "value 0x%02x, error %d", + index, page[index], ret); + gspca_dev->usb_err = ret; + break; + } + } +} + +/* output a variable sequence */ +static void reg_w_var(struct gspca_dev *gspca_dev, + const __u8 *seq, + const __u8 *page3, unsigned int page3_len) +{ + int index, len; + + for (;;) { + index = *seq++; + len = *seq++; + switch (len) { + case END_OF_SEQUENCE: + return; + case LOAD_PAGE3: + reg_w_page(gspca_dev, page3, page3_len); + break; + default: + if (len > USB_BUF_SZ) { + PDEBUG(D_ERR|D_STREAM, + "Incorrect variable sequence"); + return; + } + while (len > 0) { + if (len < 8) { + reg_w_buf(gspca_dev, + index, seq, len); + seq += len; + break; + } + reg_w_buf(gspca_dev, index, seq, 8); + seq += 8; + index += 8; + len -= 8; + } + } + } + /* not reached */ +} + +/* this function is called at probe time for pac7302 */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + + PDEBUG(D_CONF, "Find Sensor PAC7302"); + cam->cam_mode = vga_mode; /* only 640x480 */ + cam->nmodes = ARRAY_SIZE(vga_mode); + + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->white_balance = WHITEBALANCE_DEF; + sd->red_balance = REDBALANCE_DEF; + sd->blue_balance = BLUEBALANCE_DEF; + sd->gain = GAIN_DEF; + sd->exposure = EXPOSURE_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->hflip = HFLIP_DEF; + sd->vflip = VFLIP_DEF; + sd->flags = id->driver_info; + return 0; +} + +/* This function is used by pac7302 only */ +static void setbrightcont(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, v; + static const __u8 max[10] = + {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, + 0xd4, 0xec}; + static const __u8 delta[10] = + {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, + 0x11, 0x0b}; + + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + for (i = 0; i < 10; i++) { + v = max[i]; + v += (sd->brightness - BRIGHTNESS_MAX) + * 150 / BRIGHTNESS_MAX; /* 200 ? */ + v -= delta[i] * sd->contrast / CONTRAST_MAX; + if (v < 0) + v = 0; + else if (v > 0xff) + v = 0xff; + reg_w(gspca_dev, 0xa2 + i, v); + } + reg_w(gspca_dev, 0xdc, 0x01); +} + +/* This function is used by pac7302 only */ +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, v; + static const int a[9] = + {217, -212, 0, -101, 170, -67, -38, -315, 355}; + static const int b[9] = + {19, 106, 0, 19, 106, 1, 19, 106, 1}; + + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x11, 0x01); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + for (i = 0; i < 9; i++) { + v = a[i] * sd->colors / COLOR_MAX + b[i]; + reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); + reg_w(gspca_dev, 0x0f + 2 * i + 1, v); + } + reg_w(gspca_dev, 0xdc, 0x01); + PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); +} + +static void setwhitebalance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xc6, sd->white_balance); + + reg_w(gspca_dev, 0xdc, 0x01); + PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance); +} + +static void setredbalance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xc5, sd->red_balance); + + reg_w(gspca_dev, 0xdc, 0x01); + PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance); +} + +static void setbluebalance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xc7, sd->blue_balance); + + reg_w(gspca_dev, 0xdc, 0x01); + PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance); +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x10, sd->gain >> 3); + + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 clockdiv; + __u16 exposure; + + /* register 2 of frame 3 contains the clock divider configuring the + no fps according to the formula: 90 / reg. sd->exposure is the + desired exposure time in 0.5 ms. */ + clockdiv = (90 * sd->exposure + 1999) / 2000; + + /* Note clockdiv = 3 also works, but when running at 30 fps, depending + on the scene being recorded, the camera switches to another + quantization table for certain JPEG blocks, and we don't know how + to decompress these blocks. So we cap the framerate at 15 fps */ + if (clockdiv < 6) + clockdiv = 6; + else if (clockdiv > 63) + clockdiv = 63; + + /* reg2 MUST be a multiple of 3, except when between 6 and 12? + Always round up, otherwise we cannot get the desired frametime + using the partial frame time exposure control */ + if (clockdiv < 6 || clockdiv > 12) + clockdiv = ((clockdiv + 2) / 3) * 3; + + /* frame exposure time in ms = 1000 * clockdiv / 90 -> + exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ + exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv); + /* 0 = use full frametime, 448 = no exposure, reverse it */ + exposure = 448 - exposure; + + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x02, clockdiv); + reg_w(gspca_dev, 0x0e, exposure & 0xff); + reg_w(gspca_dev, 0x0f, exposure >> 8); + + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); +} + +static void sethvflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data, hflip, vflip; + + hflip = sd->hflip; + if (sd->flags & FL_HFLIP) + hflip = !hflip; + vflip = sd->vflip; + if (sd->flags & FL_VFLIP) + vflip = !vflip; + + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00); + reg_w(gspca_dev, 0x21, data); + + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); +} + +/* this function is called at probe and resume time for pac7302 */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2); + return gspca_dev->usb_err; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sof_read = 0; + + reg_w_var(gspca_dev, start_7302, + page3_7302, sizeof(page3_7302)); + setbrightcont(gspca_dev); + setcolors(gspca_dev); + setwhitebalance(gspca_dev); + setredbalance(gspca_dev); + setbluebalance(gspca_dev); + setgain(gspca_dev); + setexposure(gspca_dev); + sethvflip(gspca_dev); + + /* only resolution 640x480 is supported for pac7302 */ + + sd->sof_read = 0; + sd->autogain_ignore_frames = 0; + atomic_set(&sd->avg_lum, -1); + + /* start stream */ + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x01); + + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + + /* stop stream */ + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x00); +} + +/* called on streamoff with alt 0 and on disconnect for pac7302 */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + if (!gspca_dev->present) + return; + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x40); +} + +/* Include pac common sof detection functions */ +#include "pac_common.h" + +static void do_autogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum = atomic_read(&sd->avg_lum); + int desired_lum; + const int deadzone = 30; + + if (avg_lum == -1) + return; + + desired_lum = 270 + sd->brightness; + + if (sd->autogain_ignore_frames > 0) + sd->autogain_ignore_frames--; + else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, + deadzone, GAIN_KNEE, EXPOSURE_KNEE)) + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; +} + +/* JPEG header, part 1 */ +static const unsigned char pac_jpeg_header1[] = { + 0xff, 0xd8, /* SOI: Start of Image */ + + 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ + 0x00, 0x11, /* length = 17 bytes (including this length field) */ + 0x08 /* Precision: 8 */ + /* 2 bytes is placed here: number of image lines */ + /* 2 bytes is placed here: samples per line */ +}; + +/* JPEG header, continued */ +static const unsigned char pac_jpeg_header2[] = { + 0x03, /* Number of image components: 3 */ + 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ + 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ + 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ + + 0xff, 0xda, /* SOS: Start Of Scan */ + 0x00, 0x0c, /* length = 12 bytes (including this length field) */ + 0x03, /* number of components: 3 */ + 0x01, 0x00, /* selector 1, table 0x00 */ + 0x02, 0x11, /* selector 2, table 0x11 */ + 0x03, 0x11, /* selector 3, table 0x11 */ + 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ + 0x00 /* Successive approximation: 0 */ +}; + +static void pac_start_frame(struct gspca_dev *gspca_dev, + __u16 lines, __u16 samples_per_line) +{ + unsigned char tmpbuf[4]; + + gspca_frame_add(gspca_dev, FIRST_PACKET, + pac_jpeg_header1, sizeof(pac_jpeg_header1)); + + tmpbuf[0] = lines >> 8; + tmpbuf[1] = lines & 0xff; + tmpbuf[2] = samples_per_line >> 8; + tmpbuf[3] = samples_per_line & 0xff; + + gspca_frame_add(gspca_dev, INTER_PACKET, + tmpbuf, sizeof(tmpbuf)); + gspca_frame_add(gspca_dev, INTER_PACKET, + pac_jpeg_header2, sizeof(pac_jpeg_header2)); +} + +/* this function is run at interrupt level */ +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 *image; + unsigned char *sof; + + sof = pac_find_sof(&sd->sof_read, data, len); + if (sof) { + int n, lum_offset, footer_length; + + /* 6 bytes after the FF D9 EOF marker a number of lumination + bytes are send corresponding to different parts of the + image, the 14th and 15th byte after the EOF seem to + correspond to the center of the image */ + lum_offset = 61 + sizeof pac_sof_marker; + footer_length = 74; + + /* Finish decoding current frame */ + n = (sof - data) - (footer_length + sizeof pac_sof_marker); + if (n < 0) { + gspca_dev->image_len += n; + n = 0; + } else { + gspca_frame_add(gspca_dev, INTER_PACKET, data, n); + } + + image = gspca_dev->image; + if (image != NULL + && image[gspca_dev->image_len - 2] == 0xff + && image[gspca_dev->image_len - 1] == 0xd9) + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + + n = sof - data; + len -= n; + data = sof; + + /* Get average lumination */ + if (gspca_dev->last_packet_type == LAST_PACKET && + n >= lum_offset) + atomic_set(&sd->avg_lum, data[-lum_offset] + + data[-lum_offset + 1]); + else + atomic_set(&sd->avg_lum, -1); + + /* Start the new frame with the jpeg header */ + /* The PAC7302 has the image rotated 90 degrees */ + pac_start_frame(gspca_dev, + gspca_dev->width, gspca_dev->height); + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightcont(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setbrightcont(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->white_balance = val; + if (gspca_dev->streaming) + setwhitebalance(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->white_balance; + return 0; +} + +static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->red_balance = val; + if (gspca_dev->streaming) + setredbalance(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->red_balance; + return 0; +} + +static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->blue_balance = val; + if (gspca_dev->streaming) + setbluebalance(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->blue_balance; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + if (sd->autogain) { + sd->exposure = EXPOSURE_DEF; + sd->gain = GAIN_DEF; + if (gspca_dev->streaming) { + sd->autogain_ignore_frames = + PAC_AUTOGAIN_IGNORE_FRAMES; + setexposure(gspca_dev); + setgain(gspca_dev); + } + } + + return gspca_dev->usb_err; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hflip; + return 0; +} + +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->vflip; + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int sd_dbg_s_register(struct gspca_dev *gspca_dev, + struct v4l2_dbg_register *reg) +{ + __u8 index; + __u8 value; + + /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit + long on the USB bus) + */ + if (reg->match.type == V4L2_CHIP_MATCH_HOST && + reg->match.addr == 0 && + (reg->reg < 0x000000ff) && + (reg->val <= 0x000000ff) + ) { + /* Currently writing to page 0 is only supported. */ + /* reg_w() only supports 8bit index */ + index = reg->reg & 0x000000ff; + value = reg->val & 0x000000ff; + + /* Note that there shall be no access to other page + by any other function between the page swith and + the actual register write */ + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, index, value); + + reg_w(gspca_dev, 0xdc, 0x01); + } + return gspca_dev->usb_err; +} + +static int sd_chip_ident(struct gspca_dev *gspca_dev, + struct v4l2_dbg_chip_ident *chip) +{ + int ret = -EINVAL; + + if (chip->match.type == V4L2_CHIP_MATCH_HOST && + chip->match.addr == 0) { + chip->revision = 0; + chip->ident = V4L2_IDENT_UNKNOWN; + ret = 0; + } + return ret; +} +#endif + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet data */ + int len) /* interrput packet length */ +{ + int ret = -EINVAL; + u8 data0, data1; + + if (len == 2) { + data0 = data[0]; + data1 = data[1]; + if ((data0 == 0x00 && data1 == 0x11) || + (data0 == 0x22 && data1 == 0x33) || + (data0 == 0x44 && data1 == 0x55) || + (data0 == 0x66 && data1 == 0x77) || + (data0 == 0x88 && data1 == 0x99) || + (data0 == 0xaa && data1 == 0xbb) || + (data0 == 0xcc && data1 == 0xdd) || + (data0 == 0xee && data1 == 0xff)) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); + input_sync(gspca_dev->input_dev); + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + ret = 0; + } + } + + return ret; +} +#endif + +/* sub-driver description for pac7302 */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .set_register = sd_dbg_s_register, + .get_chip_ident = sd_chip_ident, +#endif +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +#endif +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x06f8, 0x3009)}, + {USB_DEVICE(0x093a, 0x2620)}, + {USB_DEVICE(0x093a, 0x2621)}, + {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, + {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, + {USB_DEVICE(0x093a, 0x2625)}, + {USB_DEVICE(0x093a, 0x2626)}, + {USB_DEVICE(0x093a, 0x2628)}, + {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, + {USB_DEVICE(0x093a, 0x262a)}, + {USB_DEVICE(0x093a, 0x262c)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac7311.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac7311.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac7311.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac7311.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,881 @@ +/* + * Pixart PAC7311 library + * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + */ + +/* Some documentation about various registers as determined by trial and error. + When the register addresses differ between the 7202 and the 7311 the 2 + different addresses are written as 7302addr/7311addr, when one of the 2 + addresses is a - sign that register description is not valid for the + matching IC. + + Register page 1: + + Address Description + -/0x08 Unknown compressor related, must always be 8 except when not + in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 ! + -/0x1b Auto white balance related, bit 0 is AWB enable (inverted) + bits 345 seem to toggle per color gains on/off (inverted) + 0x78 Global control, bit 6 controls the LED (inverted) + -/0x80 JPEG compression ratio ? Best not touched + + Register page 3/4: + + Address Description + 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on + the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? + -/0x0f Master gain 1-245, low value = high gain + 0x10/- Master gain 0-31 + -/0x10 Another gain 0-15, limited influence (1-2x gain I guess) + 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused + -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to + completely disable the analog amplification block. Set to 0x68 + for max gain, 0x14 for minimal gain. +*/ + +#define MODULE_NAME "pac7311" + +#include +#include "gspca.h" + +MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); +MODULE_DESCRIPTION("Pixart PAC7311"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor for pac7311 */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char contrast; + unsigned char gain; + unsigned char exposure; + unsigned char autogain; + __u8 hflip; + __u8 vflip; + + u8 sof_read; + u8 autogain_ignore_frames; + + atomic_t avg_lum; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { +/* This control is for both the 7302 and the 7311 */ + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, +#define CONTRAST_MAX 255 + .maximum = CONTRAST_MAX, + .step = 1, +#define CONTRAST_DEF 127 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +/* All controls below are for both the 7302 and the 7311 */ + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, +#define GAIN_MAX 255 + .maximum = GAIN_MAX, + .step = 1, +#define GAIN_DEF 127 +#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, +#define EXPOSURE_MAX 255 + .maximum = EXPOSURE_MAX, + .step = 1, +#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ +#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, +#define HFLIP_DEF 0 + .default_value = HFLIP_DEF, + }, + .set = sd_sethflip, + .get = sd_gethflip, + }, + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define VFLIP_DEF 0 + .default_value = VFLIP_DEF, + }, + .set = sd_setvflip, + .get = sd_getvflip, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +#define LOAD_PAGE4 254 +#define END_OF_SEQUENCE 0 + +/* pac 7311 */ +static const __u8 init_7311[] = { + 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */ + 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */ + 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */ + 0xff, 0x04, + 0x27, 0x80, + 0x28, 0xca, + 0x29, 0x53, + 0x2a, 0x0e, + 0xff, 0x01, + 0x3e, 0x20, +}; + +static const __u8 start_7311[] = { +/* index, len, [value]* */ + 0xff, 1, 0x01, /* page 1 */ + 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c, + 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e, + 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49, + 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48, + 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78, + 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b, + 0xd0, 0xff, + 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80, + 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84, + 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14, + 0x18, 0x20, + 0x96, 3, 0x01, 0x08, 0x04, + 0xa0, 4, 0x44, 0x44, 0x44, 0x04, + 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00, + 0x3f, 0x00, 0x0a, 0x01, 0x00, + 0xff, 1, 0x04, /* page 4 */ + 0, LOAD_PAGE4, /* load the page 4 */ + 0x11, 1, 0x01, + 0, END_OF_SEQUENCE /* end of sequence */ +}; + +#define SKIP 0xaa +/* page 4 - the value SKIP says skip the index - see reg_w_page() */ +static const __u8 page4_7311[] = { + SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f, + 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62, + 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP, + SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68, + 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x28, 0x04, 0x11, 0x00, 0x00 +}; + +static void reg_w_buf(struct gspca_dev *gspca_dev, + __u8 index, + const u8 *buffer, int len) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + memcpy(gspca_dev->usb_buf, buffer, len); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, len, + 500); + if (ret < 0) { + err("reg_w_buf() failed index 0x%02x, error %d", + index, ret); + gspca_dev->usb_err = ret; + } +} + + +static void reg_w(struct gspca_dev *gspca_dev, + __u8 index, + __u8 value) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + gspca_dev->usb_buf[0] = value; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { + err("reg_w() failed index 0x%02x, value 0x%02x, error %d", + index, value, ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w_seq(struct gspca_dev *gspca_dev, + const __u8 *seq, int len) +{ + while (--len >= 0) { + reg_w(gspca_dev, seq[0], seq[1]); + seq += 2; + } +} + +/* load the beginning of a page */ +static void reg_w_page(struct gspca_dev *gspca_dev, + const __u8 *page, int len) +{ + int index; + int ret = 0; + + if (gspca_dev->usb_err < 0) + return; + for (index = 0; index < len; index++) { + if (page[index] == SKIP) /* skip this index */ + continue; + gspca_dev->usb_buf[0] = page[index]; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { + err("reg_w_page() failed index 0x%02x, " + "value 0x%02x, error %d", + index, page[index], ret); + gspca_dev->usb_err = ret; + break; + } + } +} + +/* output a variable sequence */ +static void reg_w_var(struct gspca_dev *gspca_dev, + const __u8 *seq, + const __u8 *page4, unsigned int page4_len) +{ + int index, len; + + for (;;) { + index = *seq++; + len = *seq++; + switch (len) { + case END_OF_SEQUENCE: + return; + case LOAD_PAGE4: + reg_w_page(gspca_dev, page4, page4_len); + break; + default: + if (len > USB_BUF_SZ) { + PDEBUG(D_ERR|D_STREAM, + "Incorrect variable sequence"); + return; + } + while (len > 0) { + if (len < 8) { + reg_w_buf(gspca_dev, + index, seq, len); + seq += len; + break; + } + reg_w_buf(gspca_dev, index, seq, 8); + seq += 8; + index += 8; + len -= 8; + } + } + } + /* not reached */ +} + +/* this function is called at probe time for pac7311 */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + + PDEBUG(D_CONF, "Find Sensor PAC7311"); + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + + sd->contrast = CONTRAST_DEF; + sd->gain = GAIN_DEF; + sd->exposure = EXPOSURE_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->hflip = HFLIP_DEF; + sd->vflip = VFLIP_DEF; + return 0; +} + +/* This function is used by pac7311 only */ +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x10, sd->contrast >> 4); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int gain = GAIN_MAX - sd->gain; + + if (gain < 1) + gain = 1; + else if (gain > 245) + gain = 245; + reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ + reg_w(gspca_dev, 0x0e, 0x00); + reg_w(gspca_dev, 0x0f, gain); + + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 reg; + + /* register 2 of frame 3/4 contains the clock divider configuring the + no fps according to the formula: 60 / reg. sd->exposure is the + desired exposure time in ms. */ + reg = 120 * sd->exposure / 1000; + if (reg < 2) + reg = 2; + else if (reg > 63) + reg = 63; + + reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ + reg_w(gspca_dev, 0x02, reg); + + /* Page 1 register 8 must always be 0x08 except when not in + 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */ + reg_w(gspca_dev, 0xff, 0x01); + if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv && + reg <= 3) { + reg_w(gspca_dev, 0x08, 0x09); + } else { + reg_w(gspca_dev, 0x08, 0x08); + } + + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); +} + +static void sethvflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 data; + + reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ + data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00); + reg_w(gspca_dev, 0x21, data); + + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); +} + +/* this function is called at probe and resume time for pac7311 */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2); + return gspca_dev->usb_err; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sof_read = 0; + + reg_w_var(gspca_dev, start_7311, + page4_7311, sizeof(page4_7311)); + setcontrast(gspca_dev); + setgain(gspca_dev); + setexposure(gspca_dev); + sethvflip(gspca_dev); + + /* set correct resolution */ + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 2: /* 160x120 pac7311 */ + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x17, 0x20); + reg_w(gspca_dev, 0x87, 0x10); + break; + case 1: /* 320x240 pac7311 */ + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x17, 0x30); + reg_w(gspca_dev, 0x87, 0x11); + break; + case 0: /* 640x480 */ + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x17, 0x00); + reg_w(gspca_dev, 0x87, 0x12); + break; + } + + sd->sof_read = 0; + sd->autogain_ignore_frames = 0; + atomic_set(&sd->avg_lum, -1); + + /* start stream */ + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x05); + + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x27, 0x80); + reg_w(gspca_dev, 0x28, 0xca); + reg_w(gspca_dev, 0x29, 0x53); + reg_w(gspca_dev, 0x2a, 0x0e); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x3e, 0x20); + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ +} + +/* called on streamoff with alt 0 and on disconnect for 7311 */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ +} + +/* Include pac common sof detection functions */ +#include "pac_common.h" + +static void do_autogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum = atomic_read(&sd->avg_lum); + int desired_lum, deadzone; + + if (avg_lum == -1) + return; + + desired_lum = 200; + deadzone = 20; + + if (sd->autogain_ignore_frames > 0) + sd->autogain_ignore_frames--; + else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, + deadzone, GAIN_KNEE, EXPOSURE_KNEE)) + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; +} + +/* JPEG header, part 1 */ +static const unsigned char pac_jpeg_header1[] = { + 0xff, 0xd8, /* SOI: Start of Image */ + + 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ + 0x00, 0x11, /* length = 17 bytes (including this length field) */ + 0x08 /* Precision: 8 */ + /* 2 bytes is placed here: number of image lines */ + /* 2 bytes is placed here: samples per line */ +}; + +/* JPEG header, continued */ +static const unsigned char pac_jpeg_header2[] = { + 0x03, /* Number of image components: 3 */ + 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ + 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ + 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ + + 0xff, 0xda, /* SOS: Start Of Scan */ + 0x00, 0x0c, /* length = 12 bytes (including this length field) */ + 0x03, /* number of components: 3 */ + 0x01, 0x00, /* selector 1, table 0x00 */ + 0x02, 0x11, /* selector 2, table 0x11 */ + 0x03, 0x11, /* selector 3, table 0x11 */ + 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ + 0x00 /* Successive approximation: 0 */ +}; + +static void pac_start_frame(struct gspca_dev *gspca_dev, + __u16 lines, __u16 samples_per_line) +{ + unsigned char tmpbuf[4]; + + gspca_frame_add(gspca_dev, FIRST_PACKET, + pac_jpeg_header1, sizeof(pac_jpeg_header1)); + + tmpbuf[0] = lines >> 8; + tmpbuf[1] = lines & 0xff; + tmpbuf[2] = samples_per_line >> 8; + tmpbuf[3] = samples_per_line & 0xff; + + gspca_frame_add(gspca_dev, INTER_PACKET, + tmpbuf, sizeof(tmpbuf)); + gspca_frame_add(gspca_dev, INTER_PACKET, + pac_jpeg_header2, sizeof(pac_jpeg_header2)); +} + +/* this function is run at interrupt level */ +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 *image; + unsigned char *sof; + + sof = pac_find_sof(&sd->sof_read, data, len); + if (sof) { + int n, lum_offset, footer_length; + + /* 6 bytes after the FF D9 EOF marker a number of lumination + bytes are send corresponding to different parts of the + image, the 14th and 15th byte after the EOF seem to + correspond to the center of the image */ + lum_offset = 24 + sizeof pac_sof_marker; + footer_length = 26; + + /* Finish decoding current frame */ + n = (sof - data) - (footer_length + sizeof pac_sof_marker); + if (n < 0) { + gspca_dev->image_len += n; + n = 0; + } else { + gspca_frame_add(gspca_dev, INTER_PACKET, data, n); + } + image = gspca_dev->image; + if (image != NULL + && image[gspca_dev->image_len - 2] == 0xff + && image[gspca_dev->image_len - 1] == 0xd9) + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + + n = sof - data; + len -= n; + data = sof; + + /* Get average lumination */ + if (gspca_dev->last_packet_type == LAST_PACKET && + n >= lum_offset) + atomic_set(&sd->avg_lum, data[-lum_offset] + + data[-lum_offset + 1]); + else + atomic_set(&sd->avg_lum, -1); + + /* Start the new frame with the jpeg header */ + pac_start_frame(gspca_dev, + gspca_dev->height, gspca_dev->width); + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + if (sd->autogain) { + sd->exposure = EXPOSURE_DEF; + sd->gain = GAIN_DEF; + if (gspca_dev->streaming) { + sd->autogain_ignore_frames = + PAC_AUTOGAIN_IGNORE_FRAMES; + setexposure(gspca_dev); + setgain(gspca_dev); + } + } + + return gspca_dev->usb_err; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hflip; + return 0; +} + +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->vflip; + return 0; +} + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet data */ + int len) /* interrupt packet length */ +{ + int ret = -EINVAL; + u8 data0, data1; + + if (len == 2) { + data0 = data[0]; + data1 = data[1]; + if ((data0 == 0x00 && data1 == 0x11) || + (data0 == 0x22 && data1 == 0x33) || + (data0 == 0x44 && data1 == 0x55) || + (data0 == 0x66 && data1 == 0x77) || + (data0 == 0x88 && data1 == 0x99) || + (data0 == 0xaa && data1 == 0xbb) || + (data0 == 0xcc && data1 == 0xdd) || + (data0 == 0xee && data1 == 0xff)) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); + input_sync(gspca_dev->input_dev); + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + ret = 0; + } + } + + return ret; +} +#endif + +/* sub-driver description for pac7311 */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +#endif +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x093a, 0x2600)}, + {USB_DEVICE(0x093a, 0x2601)}, + {USB_DEVICE(0x093a, 0x2603)}, + {USB_DEVICE(0x093a, 0x2608)}, + {USB_DEVICE(0x093a, 0x260e)}, + {USB_DEVICE(0x093a, 0x260f)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac_common.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac_common.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac_common.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/pac_common.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,134 @@ +/* + * Pixart PAC207BCA / PAC73xx common functions + * + * Copyright (C) 2008 Hans de Goede + * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li + * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * (at your option) any later version. + * + * 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 + * + */ + +/* We calculate the autogain at the end of the transfer of a frame, at this + moment a frame with the old settings is being captured and transmitted. So + if we adjust the gain or exposure we must ignore atleast the next frame for + the new settings to come into effect before doing any other adjustments. */ +#define PAC_AUTOGAIN_IGNORE_FRAMES 2 + +static const unsigned char pac_sof_marker[5] = + { 0xff, 0xff, 0x00, 0xff, 0x96 }; + +/* + The following state machine finds the SOF marker sequence + 0xff, 0xff, 0x00, 0xff, 0x96 in a byte stream. + + +----------+ + | 0: START |<---------------\ + +----------+<-\ | + | \---/otherwise | + v 0xff | + +----------+ otherwise | + | 1 |--------------->* + | | ^ + +----------+ | + | | + v 0xff | + +----------+<-\0xff | + /->| |--/ | + | | 2 |--------------->* + | | | otherwise ^ + | +----------+ | + | | | + | v 0x00 | + | +----------+ | + | | 3 | | + | | |--------------->* + | +----------+ otherwise ^ + | | | + 0xff | v 0xff | + | +----------+ | + \--| 4 | | + | |----------------/ + +----------+ otherwise + | + v 0x96 + +----------+ + | FOUND | + +----------+ +*/ + +static unsigned char *pac_find_sof(u8 *sof_read, + unsigned char *m, int len) +{ + int i; + + /* Search for the SOF marker (fixed part) in the header */ + for (i = 0; i < len; i++) { + switch (*sof_read) { + case 0: + if (m[i] == 0xff) + *sof_read = 1; + break; + case 1: + if (m[i] == 0xff) + *sof_read = 2; + else + *sof_read = 0; + break; + case 2: + switch (m[i]) { + case 0x00: + *sof_read = 3; + break; + case 0xff: + /* stay in this state */ + break; + default: + *sof_read = 0; + } + break; + case 3: + if (m[i] == 0xff) + *sof_read = 4; + else + *sof_read = 0; + break; + case 4: + switch (m[i]) { + case 0x96: + /* Pattern found */ + PDEBUG(D_FRAM, + "SOF found, bytes to analyze: %u." + " Frame starts at byte #%u", + len, i + 1); + *sof_read = 0; + return m + i + 1; + break; + case 0xff: + *sof_read = 2; + break; + default: + *sof_read = 0; + } + break; + default: + *sof_read = 0; + } + } + + return NULL; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c2028.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c2028.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c2028.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c2028.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,750 @@ +/* + * SN9C2028 library + * + * Copyright (C) 2009 Theodore Kilgore + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "sn9c2028" + +#include "gspca.h" + +MODULE_AUTHOR("Theodore Kilgore"); +MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + u8 sof_read; + u16 model; +}; + +struct init_command { + unsigned char instruction[6]; + unsigned char to_read; /* length to read. 0 means no reply requested */ +}; + +/* V4L2 controls supported by the driver */ +static const struct ctrl sd_ctrls[] = { +}; + +/* How to change the resolution of any of the VGA cams is unknown */ +static const struct v4l2_pix_format vga_mode[] = { + {640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* No way to change the resolution of the CIF cams is known */ +static const struct v4l2_pix_format cif_mode[] = { + {352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* the bytes to write are in gspca_dev->usb_buf */ +static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command) +{ + int rc; + + PDEBUG(D_USBO, "sending command %02x%02x%02x%02x%02x%02x", command[0], + command[1], command[2], command[3], command[4], command[5]); + + memcpy(gspca_dev->usb_buf, command, 6); + rc = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + USB_REQ_GET_CONFIGURATION, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 2, 0, gspca_dev->usb_buf, 6, 500); + if (rc < 0) { + err("command write [%02x] error %d", + gspca_dev->usb_buf[0], rc); + return rc; + } + + return 0; +} + +static int sn9c2028_read1(struct gspca_dev *gspca_dev) +{ + int rc; + + rc = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + USB_REQ_GET_STATUS, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 1, 0, gspca_dev->usb_buf, 1, 500); + if (rc != 1) { + err("read1 error %d", rc); + return (rc < 0) ? rc : -EIO; + } + PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]); + return gspca_dev->usb_buf[0]; +} + +static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading) +{ + int rc; + rc = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + USB_REQ_GET_STATUS, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 4, 0, gspca_dev->usb_buf, 4, 500); + if (rc != 4) { + err("read4 error %d", rc); + return (rc < 0) ? rc : -EIO; + } + memcpy(reading, gspca_dev->usb_buf, 4); + PDEBUG(D_USBI, "read4 response %02x%02x%02x%02x", reading[0], + reading[1], reading[2], reading[3]); + return rc; +} + +static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) +{ + int i, status; + __u8 reading[4]; + + status = sn9c2028_command(gspca_dev, command); + if (status < 0) + return status; + + status = -1; + for (i = 0; i < 256 && status < 2; i++) + status = sn9c2028_read1(gspca_dev); + if (status != 2) { + err("long command status read error %d", status); + return (status < 0) ? status : -EIO; + } + + memset(reading, 0, 4); + status = sn9c2028_read4(gspca_dev, reading); + if (status < 0) + return status; + + /* in general, the first byte of the response is the first byte of + * the command, or'ed with 8 */ + status = sn9c2028_read1(gspca_dev); + if (status < 0) + return status; + + return 0; +} + +static int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command) +{ + int err_code; + + err_code = sn9c2028_command(gspca_dev, command); + if (err_code < 0) + return err_code; + + err_code = sn9c2028_read1(gspca_dev); + if (err_code < 0) + return err_code; + + return 0; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + + PDEBUG(D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)", + id->idVendor, id->idProduct); + + sd->model = id->idProduct; + + switch (sd->model) { + case 0x7005: + PDEBUG(D_PROBE, "Genius Smart 300 camera"); + break; + case 0x8000: + PDEBUG(D_PROBE, "DC31VC"); + break; + case 0x8001: + PDEBUG(D_PROBE, "Spy camera"); + break; + case 0x8003: + PDEBUG(D_PROBE, "CIF camera"); + break; + case 0x8008: + PDEBUG(D_PROBE, "Mini-Shotz ms-350 camera"); + break; + case 0x800a: + PDEBUG(D_PROBE, "Vivitar 3350b type camera"); + cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP; + break; + } + + switch (sd->model) { + case 0x8000: + case 0x8001: + case 0x8003: + cam->cam_mode = cif_mode; + cam->nmodes = ARRAY_SIZE(cif_mode); + break; + default: + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + } + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + int status = -1; + + sn9c2028_read1(gspca_dev); + sn9c2028_read1(gspca_dev); + status = sn9c2028_read1(gspca_dev); + + return (status < 0) ? status : 0; +} + +static int run_start_commands(struct gspca_dev *gspca_dev, + struct init_command *cam_commands, int n) +{ + int i, err_code = -1; + + for (i = 0; i < n; i++) { + switch (cam_commands[i].to_read) { + case 4: + err_code = sn9c2028_long_command(gspca_dev, + cam_commands[i].instruction); + break; + case 1: + err_code = sn9c2028_short_command(gspca_dev, + cam_commands[i].instruction); + break; + case 0: + err_code = sn9c2028_command(gspca_dev, + cam_commands[i].instruction); + break; + } + if (err_code < 0) + return err_code; + } + return 0; +} + +static int start_spy_cam(struct gspca_dev *gspca_dev) +{ + struct init_command spy_start_commands[] = { + {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4}, + {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4}, + {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width 352 */ + {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */ + /* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */ + {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, + {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/ + /* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */ + {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4}, + /* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */ + {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, + /* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */ + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, + /* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */ + {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, + {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, + {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/ + /*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */ + {{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */ + /*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */ + {{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */ + {{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */ + {{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4}, + /*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */ + {{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4}, + /* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */ + /* brightness or gain. 0 is default. 4 is good + * indoors at night with incandescent lighting */ + {{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/ + {{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4}, + /* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */ + {{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */ + /* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */ + {{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1}, + {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */ + /* Camera should start to capture now. */ + }; + + return run_start_commands(gspca_dev, spy_start_commands, + ARRAY_SIZE(spy_start_commands)); +} + +static int start_cif_cam(struct gspca_dev *gspca_dev) +{ + struct init_command cif_start_commands[] = { + {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, + /* The entire sequence below seems redundant */ + /* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4}, + {{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width? + {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height? + {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample? + {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4}, + {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, + {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, + {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/ + {{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1}, + {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */ + {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */ + /* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample? + * {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing + * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */ + /* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, + * causes subsampling + * but not a change in the resolution setting! */ + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4}, + {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1}, + {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1}, + {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1}, + {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */ + /* Camera should start to capture now. */ + }; + + return run_start_commands(gspca_dev, cif_start_commands, + ARRAY_SIZE(cif_start_commands)); +} + +static int start_ms350_cam(struct gspca_dev *gspca_dev) +{ + struct init_command ms350_start_commands[] = { + {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4}, + {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4}, + {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, + {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, + {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, + {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, + {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, + {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width */ + {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */ + {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */ + {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */ + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, + {{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1}, + {{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0}, + /* Camera should start to capture now. */ + }; + + return run_start_commands(gspca_dev, ms350_start_commands, + ARRAY_SIZE(ms350_start_commands)); +} + +static int start_genius_cam(struct gspca_dev *gspca_dev) +{ + struct init_command genius_start_commands[] = { + {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, + {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, + /* "preliminary" width and height settings */ + {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, + {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, + {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */ + {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */ + {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, + {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, + {{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, + {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4}, + {{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4}, + {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1}, + {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1}, + {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0} + /* Camera should start to capture now. */ + }; + + return run_start_commands(gspca_dev, genius_start_commands, + ARRAY_SIZE(genius_start_commands)); +} + +static int start_vivitar_cam(struct gspca_dev *gspca_dev) +{ + struct init_command vivitar_start_commands[] = { + {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4}, + {{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4}, + {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, + {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, + {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, + {{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4}, + /* + * Above is changed from OEM 0x0b. Fixes Bayer tiling. + * Presumably gives a vertical shift of one row. + */ + {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4}, + /* Above seems to do horizontal shift. */ + {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, + {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, + {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, + {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, + /* Above three commands seem to relate to brightness. */ + {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, + {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1}, + /* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, + {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, + {{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */ + {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1}, + {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1}, + {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1}, + {{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1}, + /* Above is brightness; OEM driver setting is 0x10 */ + {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4}, + {{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1}, + {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1} + }; + + return run_start_commands(gspca_dev, vivitar_start_commands, + ARRAY_SIZE(vivitar_start_commands)); +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err_code; + + sd->sof_read = 0; + + switch (sd->model) { + case 0x7005: + err_code = start_genius_cam(gspca_dev); + break; + case 0x8001: + err_code = start_spy_cam(gspca_dev); + break; + case 0x8003: + err_code = start_cif_cam(gspca_dev); + break; + case 0x8008: + err_code = start_ms350_cam(gspca_dev); + break; + case 0x800a: + err_code = start_vivitar_cam(gspca_dev); + break; + default: + err("Starting unknown camera, please report this"); + return -ENXIO; + } + + return err_code; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + int result; + __u8 data[6]; + + result = sn9c2028_read1(gspca_dev); + if (result < 0) + PDEBUG(D_ERR, "Camera Stop read failed"); + + memset(data, 0, 6); + data[0] = 0x14; + result = sn9c2028_command(gspca_dev, data); + if (result < 0) + PDEBUG(D_ERR, "Camera Stop command failed"); +} + +/* Include sn9c2028 sof detection functions */ +#include "sn9c2028.h" + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + unsigned char *sof; + + sof = sn9c2028_find_sof(gspca_dev, data, len); + if (sof) { + int n; + + /* finish decoding current frame */ + n = sof - data; + if (n > sizeof sn9c2028_sof_marker) + n -= sizeof sn9c2028_sof_marker; + else + n = 0; + gspca_frame_add(gspca_dev, LAST_PACKET, data, n); + /* Start next frame. */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + sn9c2028_sof_marker, sizeof sn9c2028_sof_marker); + len -= sof - data; + data = sof; + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */ + /* The Genius Smart is untested. I can't find an owner ! */ + /* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */ + {USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */ + {USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */ + /* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */ + {USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */ + {USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */ + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c2028.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c2028.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c2028.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c2028.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * SN9C2028 common functions + * + * Copyright (C) 2009 Theodore Kilgore + * + * Based closely upon the file gspca/pac_common.h + * + * 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, or + * (at your option) any later version. + * + * 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 + * + */ + +static const unsigned char sn9c2028_sof_marker[5] = + { 0xff, 0xff, 0x00, 0xc4, 0xc4 }; + +static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev, + unsigned char *m, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + + /* Search for the SOF marker (fixed part) in the header */ + for (i = 0; i < len; i++) { + if (m[i] == sn9c2028_sof_marker[sd->sof_read]) { + sd->sof_read++; + if (sd->sof_read == sizeof(sn9c2028_sof_marker)) { + PDEBUG(D_FRAM, + "SOF found, bytes to analyze: %u." + " Frame starts at byte #%u", + len, i + 1); + sd->sof_read = 0; + return m + i + 1; + } + } else { + sd->sof_read = 0; + } + } + + return NULL; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c20x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c20x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c20x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sn9c20x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2566 @@ +/* + * Sonix sn9c201 sn9c202 library + * Copyright (C) 2008-2009 microdia project + * Copyright (C) 2009 Brian Johnson + * + * 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, or + * any later version. + * + * 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 + +#include "gspca.h" +#include "jpeg.h" + +#include +#include + +MODULE_AUTHOR("Brian Johnson , " + "microdia project "); +MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver"); +MODULE_LICENSE("GPL"); + +#define MODULE_NAME "sn9c20x" + +/* + * Pixel format private data + */ +#define SCALE_MASK 0x0f +#define SCALE_160x120 0 +#define SCALE_320x240 1 +#define SCALE_640x480 2 +#define SCALE_1280x1024 3 +#define MODE_RAW 0x10 +#define MODE_JPEG 0x20 +#define MODE_SXGA 0x80 + +#define SENSOR_OV9650 0 +#define SENSOR_OV9655 1 +#define SENSOR_SOI968 2 +#define SENSOR_OV7660 3 +#define SENSOR_OV7670 4 +#define SENSOR_MT9V011 5 +#define SENSOR_MT9V111 6 +#define SENSOR_MT9V112 7 +#define SENSOR_MT9M001 8 +#define SENSOR_MT9M111 9 +#define SENSOR_MT9M112 10 +#define SENSOR_HV7131R 11 +#define SENSOR_MT9VPRB 20 + +/* camera flags */ +#define HAS_NO_BUTTON 0x1 +#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */ +#define FLIP_DETECT 0x4 + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; + +#define MIN_AVG_LUM 80 +#define MAX_AVG_LUM 130 + atomic_t avg_lum; + u8 old_step; + u8 older_step; + u8 exposure_step; + + u8 brightness; + u8 contrast; + u8 saturation; + s16 hue; + u8 gamma; + u8 red; + u8 blue; + + u8 hflip; + u8 vflip; + u8 gain; + u16 exposure; + u8 auto_exposure; + + u8 i2c_addr; + u8 sensor; + u8 hstart; + u8 vstart; + + u8 jpeg_hdr[JPEG_HDR_SZ]; + u8 quality; + + u8 flags; +}; + +struct i2c_reg_u8 { + u8 reg; + u8 val; +}; + +struct i2c_reg_u16 { + u8 reg; + u16 val; +}; + +static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val); +static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val); +static int sd_sethue(struct gspca_dev *gspca_dev, s32 val); +static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val); +static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val); +static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val); +static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val); +static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val); +static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val); +static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val); +static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val); + +static const struct dmi_system_id flip_dmi_table[] = { + { + .ident = "MSI MS-1034", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"), + DMI_MATCH(DMI_PRODUCT_VERSION, "0341") + } + }, + { + .ident = "MSI MS-1632", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), + DMI_MATCH(DMI_BOARD_NAME, "MS-1632") + } + }, + { + .ident = "MSI MS-1633X", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), + DMI_MATCH(DMI_BOARD_NAME, "MS-1633X") + } + }, + { + .ident = "MSI MS-1635X", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), + DMI_MATCH(DMI_BOARD_NAME, "MS-1635X") + } + }, + { + .ident = "ASUSTeK W7J", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_BOARD_NAME, "W7J ") + } + }, + {} +}; + +static const struct ctrl sd_ctrls[] = { + { +#define BRIGHTNESS_IDX 0 + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define BRIGHTNESS_DEFAULT 0x7f + .default_value = BRIGHTNESS_DEFAULT, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { +#define CONTRAST_IDX 1 + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define CONTRAST_DEFAULT 0x7f + .default_value = CONTRAST_DEFAULT, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { +#define SATURATION_IDX 2 + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define SATURATION_DEFAULT 0x7f + .default_value = SATURATION_DEFAULT, + }, + .set = sd_setsaturation, + .get = sd_getsaturation, + }, + { +#define HUE_IDX 3 + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = -180, + .maximum = 180, + .step = 1, +#define HUE_DEFAULT 0 + .default_value = HUE_DEFAULT, + }, + .set = sd_sethue, + .get = sd_gethue, + }, + { +#define GAMMA_IDX 4 + { + .id = V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define GAMMA_DEFAULT 0x10 + .default_value = GAMMA_DEFAULT, + }, + .set = sd_setgamma, + .get = sd_getgamma, + }, + { +#define BLUE_IDX 5 + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0, + .maximum = 0x7f, + .step = 1, +#define BLUE_DEFAULT 0x28 + .default_value = BLUE_DEFAULT, + }, + .set = sd_setbluebalance, + .get = sd_getbluebalance, + }, + { +#define RED_IDX 6 + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0, + .maximum = 0x7f, + .step = 1, +#define RED_DEFAULT 0x28 + .default_value = RED_DEFAULT, + }, + .set = sd_setredbalance, + .get = sd_getredbalance, + }, + { +#define HFLIP_IDX 7 + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Horizontal Flip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define HFLIP_DEFAULT 0 + .default_value = HFLIP_DEFAULT, + }, + .set = sd_sethflip, + .get = sd_gethflip, + }, + { +#define VFLIP_IDX 8 + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define VFLIP_DEFAULT 0 + .default_value = VFLIP_DEFAULT, + }, + .set = sd_setvflip, + .get = sd_getvflip, + }, + { +#define EXPOSURE_IDX 9 + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 0x1780, + .step = 1, +#define EXPOSURE_DEFAULT 0x33 + .default_value = EXPOSURE_DEFAULT, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { +#define GAIN_IDX 10 + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 28, + .step = 1, +#define GAIN_DEFAULT 0x00 + .default_value = GAIN_DEFAULT, + }, + .set = sd_setgain, + .get = sd_getgain, + }, + { +#define AUTOGAIN_IDX 11 + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTO_EXPOSURE_DEFAULT 1 + .default_value = AUTO_EXPOSURE_DEFAULT, + }, + .set = sd_setautoexposure, + .get = sd_getautoexposure, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = SCALE_160x120 | MODE_JPEG}, + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_160x120 | MODE_RAW}, + {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 240 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_160x120}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = SCALE_320x240 | MODE_JPEG}, + {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 , + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_320x240 | MODE_RAW}, + {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 480 * 240 , + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_320x240}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = SCALE_640x480 | MODE_JPEG}, + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_640x480 | MODE_RAW}, + {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 960 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_640x480}, +}; + +static const struct v4l2_pix_format sxga_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = SCALE_160x120 | MODE_JPEG}, + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_160x120 | MODE_RAW}, + {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 240 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_160x120}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = SCALE_320x240 | MODE_JPEG}, + {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 , + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_320x240 | MODE_RAW}, + {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 480 * 240 , + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_320x240}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = SCALE_640x480 | MODE_JPEG}, + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_640x480 | MODE_RAW}, + {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 960 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_640x480}, + {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA}, +}; + +static const struct v4l2_pix_format mono_mode[] = { + {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_160x120 | MODE_RAW}, + {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 , + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_320x240 | MODE_RAW}, + {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_640x480 | MODE_RAW}, + {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA}, +}; + +static const s16 hsv_red_x[] = { + 41, 44, 46, 48, 50, 52, 54, 56, + 58, 60, 62, 64, 66, 68, 70, 72, + 74, 76, 78, 80, 81, 83, 85, 87, + 88, 90, 92, 93, 95, 97, 98, 100, + 101, 102, 104, 105, 107, 108, 109, 110, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 123, 124, 125, 125, + 126, 127, 127, 128, 128, 129, 129, 129, + 130, 130, 130, 130, 131, 131, 131, 131, + 131, 131, 131, 131, 130, 130, 130, 130, + 129, 129, 129, 128, 128, 127, 127, 126, + 125, 125, 124, 123, 122, 122, 121, 120, + 119, 118, 117, 116, 115, 114, 112, 111, + 110, 109, 107, 106, 105, 103, 102, 101, + 99, 98, 96, 94, 93, 91, 90, 88, + 86, 84, 83, 81, 79, 77, 75, 74, + 72, 70, 68, 66, 64, 62, 60, 58, + 56, 54, 52, 49, 47, 45, 43, 41, + 39, 36, 34, 32, 30, 28, 25, 23, + 21, 19, 16, 14, 12, 9, 7, 5, + 3, 0, -1, -3, -6, -8, -10, -12, + -15, -17, -19, -22, -24, -26, -28, -30, + -33, -35, -37, -39, -41, -44, -46, -48, + -50, -52, -54, -56, -58, -60, -62, -64, + -66, -68, -70, -72, -74, -76, -78, -80, + -81, -83, -85, -87, -88, -90, -92, -93, + -95, -97, -98, -100, -101, -102, -104, -105, + -107, -108, -109, -110, -112, -113, -114, -115, + -116, -117, -118, -119, -120, -121, -122, -123, + -123, -124, -125, -125, -126, -127, -127, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -127, -127, -126, -125, -125, -124, -123, + -122, -122, -121, -120, -119, -118, -117, -116, + -115, -114, -112, -111, -110, -109, -107, -106, + -105, -103, -102, -101, -99, -98, -96, -94, + -93, -91, -90, -88, -86, -84, -83, -81, + -79, -77, -75, -74, -72, -70, -68, -66, + -64, -62, -60, -58, -56, -54, -52, -49, + -47, -45, -43, -41, -39, -36, -34, -32, + -30, -28, -25, -23, -21, -19, -16, -14, + -12, -9, -7, -5, -3, 0, 1, 3, + 6, 8, 10, 12, 15, 17, 19, 22, + 24, 26, 28, 30, 33, 35, 37, 39, 41 +}; + +static const s16 hsv_red_y[] = { + 82, 80, 78, 76, 74, 73, 71, 69, + 67, 65, 63, 61, 58, 56, 54, 52, + 50, 48, 46, 44, 41, 39, 37, 35, + 32, 30, 28, 26, 23, 21, 19, 16, + 14, 12, 10, 7, 5, 3, 0, -1, + -3, -6, -8, -10, -13, -15, -17, -19, + -22, -24, -26, -29, -31, -33, -35, -38, + -40, -42, -44, -46, -48, -51, -53, -55, + -57, -59, -61, -63, -65, -67, -69, -71, + -73, -75, -77, -79, -81, -82, -84, -86, + -88, -89, -91, -93, -94, -96, -98, -99, + -101, -102, -104, -105, -106, -108, -109, -110, + -112, -113, -114, -115, -116, -117, -119, -120, + -120, -121, -122, -123, -124, -125, -126, -126, + -127, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -127, -127, -126, -125, -125, -124, -123, -122, + -121, -120, -119, -118, -117, -116, -115, -114, + -113, -111, -110, -109, -107, -106, -105, -103, + -102, -100, -99, -97, -96, -94, -92, -91, + -89, -87, -85, -84, -82, -80, -78, -76, + -74, -73, -71, -69, -67, -65, -63, -61, + -58, -56, -54, -52, -50, -48, -46, -44, + -41, -39, -37, -35, -32, -30, -28, -26, + -23, -21, -19, -16, -14, -12, -10, -7, + -5, -3, 0, 1, 3, 6, 8, 10, + 13, 15, 17, 19, 22, 24, 26, 29, + 31, 33, 35, 38, 40, 42, 44, 46, + 48, 51, 53, 55, 57, 59, 61, 63, + 65, 67, 69, 71, 73, 75, 77, 79, + 81, 82, 84, 86, 88, 89, 91, 93, + 94, 96, 98, 99, 101, 102, 104, 105, + 106, 108, 109, 110, 112, 113, 114, 115, + 116, 117, 119, 120, 120, 121, 122, 123, + 124, 125, 126, 126, 127, 128, 128, 129, + 129, 130, 130, 131, 131, 131, 131, 132, + 132, 132, 132, 132, 132, 132, 132, 132, + 132, 132, 132, 131, 131, 131, 130, 130, + 130, 129, 129, 128, 127, 127, 126, 125, + 125, 124, 123, 122, 121, 120, 119, 118, + 117, 116, 115, 114, 113, 111, 110, 109, + 107, 106, 105, 103, 102, 100, 99, 97, + 96, 94, 92, 91, 89, 87, 85, 84, 82 +}; + +static const s16 hsv_green_x[] = { + -124, -124, -125, -125, -125, -125, -125, -125, + -125, -126, -126, -125, -125, -125, -125, -125, + -125, -124, -124, -124, -123, -123, -122, -122, + -121, -121, -120, -120, -119, -118, -117, -117, + -116, -115, -114, -113, -112, -111, -110, -109, + -108, -107, -105, -104, -103, -102, -100, -99, + -98, -96, -95, -93, -92, -91, -89, -87, + -86, -84, -83, -81, -79, -77, -76, -74, + -72, -70, -69, -67, -65, -63, -61, -59, + -57, -55, -53, -51, -49, -47, -45, -43, + -41, -39, -37, -35, -33, -30, -28, -26, + -24, -22, -20, -18, -15, -13, -11, -9, + -7, -4, -2, 0, 1, 3, 6, 8, + 10, 12, 14, 17, 19, 21, 23, 25, + 27, 29, 32, 34, 36, 38, 40, 42, + 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 66, 68, 70, 71, 73, + 75, 77, 78, 80, 82, 83, 85, 87, + 88, 90, 91, 93, 94, 96, 97, 98, + 100, 101, 102, 104, 105, 106, 107, 108, + 109, 111, 112, 113, 113, 114, 115, 116, + 117, 118, 118, 119, 120, 120, 121, 122, + 122, 123, 123, 124, 124, 124, 125, 125, + 125, 125, 125, 125, 125, 126, 126, 125, + 125, 125, 125, 125, 125, 124, 124, 124, + 123, 123, 122, 122, 121, 121, 120, 120, + 119, 118, 117, 117, 116, 115, 114, 113, + 112, 111, 110, 109, 108, 107, 105, 104, + 103, 102, 100, 99, 98, 96, 95, 93, + 92, 91, 89, 87, 86, 84, 83, 81, + 79, 77, 76, 74, 72, 70, 69, 67, + 65, 63, 61, 59, 57, 55, 53, 51, + 49, 47, 45, 43, 41, 39, 37, 35, + 33, 30, 28, 26, 24, 22, 20, 18, + 15, 13, 11, 9, 7, 4, 2, 0, + -1, -3, -6, -8, -10, -12, -14, -17, + -19, -21, -23, -25, -27, -29, -32, -34, + -36, -38, -40, -42, -44, -46, -48, -50, + -52, -54, -56, -58, -60, -62, -64, -66, + -68, -70, -71, -73, -75, -77, -78, -80, + -82, -83, -85, -87, -88, -90, -91, -93, + -94, -96, -97, -98, -100, -101, -102, -104, + -105, -106, -107, -108, -109, -111, -112, -113, + -113, -114, -115, -116, -117, -118, -118, -119, + -120, -120, -121, -122, -122, -123, -123, -124, -124 +}; + +static const s16 hsv_green_y[] = { + -100, -99, -98, -97, -95, -94, -93, -91, + -90, -89, -87, -86, -84, -83, -81, -80, + -78, -76, -75, -73, -71, -70, -68, -66, + -64, -63, -61, -59, -57, -55, -53, -51, + -49, -48, -46, -44, -42, -40, -38, -36, + -34, -32, -30, -27, -25, -23, -21, -19, + -17, -15, -13, -11, -9, -7, -4, -2, + 0, 1, 3, 5, 7, 9, 11, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 59, 61, + 63, 65, 67, 68, 70, 72, 74, 75, + 77, 78, 80, 82, 83, 85, 86, 88, + 89, 90, 92, 93, 95, 96, 97, 98, + 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 112, 113, 114, + 115, 115, 116, 116, 117, 117, 118, 118, + 119, 119, 119, 120, 120, 120, 120, 120, + 121, 121, 121, 121, 121, 121, 120, 120, + 120, 120, 120, 119, 119, 119, 118, 118, + 117, 117, 116, 116, 115, 114, 114, 113, + 112, 111, 111, 110, 109, 108, 107, 106, + 105, 104, 103, 102, 100, 99, 98, 97, + 95, 94, 93, 91, 90, 89, 87, 86, + 84, 83, 81, 80, 78, 76, 75, 73, + 71, 70, 68, 66, 64, 63, 61, 59, + 57, 55, 53, 51, 49, 48, 46, 44, + 42, 40, 38, 36, 34, 32, 30, 27, + 25, 23, 21, 19, 17, 15, 13, 11, + 9, 7, 4, 2, 0, -1, -3, -5, + -7, -9, -11, -14, -16, -18, -20, -22, + -24, -26, -28, -30, -32, -34, -36, -38, + -40, -42, -44, -46, -48, -50, -52, -54, + -56, -58, -59, -61, -63, -65, -67, -68, + -70, -72, -74, -75, -77, -78, -80, -82, + -83, -85, -86, -88, -89, -90, -92, -93, + -95, -96, -97, -98, -100, -101, -102, -103, + -104, -105, -106, -107, -108, -109, -110, -111, + -112, -112, -113, -114, -115, -115, -116, -116, + -117, -117, -118, -118, -119, -119, -119, -120, + -120, -120, -120, -120, -121, -121, -121, -121, + -121, -121, -120, -120, -120, -120, -120, -119, + -119, -119, -118, -118, -117, -117, -116, -116, + -115, -114, -114, -113, -112, -111, -111, -110, + -109, -108, -107, -106, -105, -104, -103, -102, -100 +}; + +static const s16 hsv_blue_x[] = { + 112, 113, 114, 114, 115, 116, 117, 117, + 118, 118, 119, 119, 120, 120, 120, 121, + 121, 121, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 121, 121, + 121, 120, 120, 120, 119, 119, 118, 118, + 117, 116, 116, 115, 114, 113, 113, 112, + 111, 110, 109, 108, 107, 106, 105, 104, + 103, 102, 100, 99, 98, 97, 95, 94, + 93, 91, 90, 88, 87, 85, 84, 82, + 80, 79, 77, 76, 74, 72, 70, 69, + 67, 65, 63, 61, 60, 58, 56, 54, + 52, 50, 48, 46, 44, 42, 40, 38, + 36, 34, 32, 30, 28, 26, 24, 22, + 19, 17, 15, 13, 11, 9, 7, 5, + 2, 0, -1, -3, -5, -7, -9, -12, + -14, -16, -18, -20, -22, -24, -26, -28, + -31, -33, -35, -37, -39, -41, -43, -45, + -47, -49, -51, -53, -54, -56, -58, -60, + -62, -64, -66, -67, -69, -71, -73, -74, + -76, -78, -79, -81, -83, -84, -86, -87, + -89, -90, -92, -93, -94, -96, -97, -98, + -99, -101, -102, -103, -104, -105, -106, -107, + -108, -109, -110, -111, -112, -113, -114, -114, + -115, -116, -117, -117, -118, -118, -119, -119, + -120, -120, -120, -121, -121, -121, -122, -122, + -122, -122, -122, -122, -122, -122, -122, -122, + -122, -122, -121, -121, -121, -120, -120, -120, + -119, -119, -118, -118, -117, -116, -116, -115, + -114, -113, -113, -112, -111, -110, -109, -108, + -107, -106, -105, -104, -103, -102, -100, -99, + -98, -97, -95, -94, -93, -91, -90, -88, + -87, -85, -84, -82, -80, -79, -77, -76, + -74, -72, -70, -69, -67, -65, -63, -61, + -60, -58, -56, -54, -52, -50, -48, -46, + -44, -42, -40, -38, -36, -34, -32, -30, + -28, -26, -24, -22, -19, -17, -15, -13, + -11, -9, -7, -5, -2, 0, 1, 3, + 5, 7, 9, 12, 14, 16, 18, 20, + 22, 24, 26, 28, 31, 33, 35, 37, + 39, 41, 43, 45, 47, 49, 51, 53, + 54, 56, 58, 60, 62, 64, 66, 67, + 69, 71, 73, 74, 76, 78, 79, 81, + 83, 84, 86, 87, 89, 90, 92, 93, + 94, 96, 97, 98, 99, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112 +}; + +static const s16 hsv_blue_y[] = { + -11, -13, -15, -17, -19, -21, -23, -25, + -27, -29, -31, -33, -35, -37, -39, -41, + -43, -45, -46, -48, -50, -52, -54, -55, + -57, -59, -61, -62, -64, -66, -67, -69, + -71, -72, -74, -75, -77, -78, -80, -81, + -83, -84, -86, -87, -88, -90, -91, -92, + -93, -95, -96, -97, -98, -99, -100, -101, + -102, -103, -104, -105, -106, -106, -107, -108, + -109, -109, -110, -111, -111, -112, -112, -113, + -113, -114, -114, -114, -115, -115, -115, -115, + -116, -116, -116, -116, -116, -116, -116, -116, + -116, -115, -115, -115, -115, -114, -114, -114, + -113, -113, -112, -112, -111, -111, -110, -110, + -109, -108, -108, -107, -106, -105, -104, -103, + -102, -101, -100, -99, -98, -97, -96, -95, + -94, -93, -91, -90, -89, -88, -86, -85, + -84, -82, -81, -79, -78, -76, -75, -73, + -71, -70, -68, -67, -65, -63, -62, -60, + -58, -56, -55, -53, -51, -49, -47, -45, + -44, -42, -40, -38, -36, -34, -32, -30, + -28, -26, -24, -22, -20, -18, -16, -14, + -12, -10, -8, -6, -4, -2, 0, 1, + 3, 5, 7, 9, 11, 13, 15, 17, + 19, 21, 23, 25, 27, 29, 31, 33, + 35, 37, 39, 41, 43, 45, 46, 48, + 50, 52, 54, 55, 57, 59, 61, 62, + 64, 66, 67, 69, 71, 72, 74, 75, + 77, 78, 80, 81, 83, 84, 86, 87, + 88, 90, 91, 92, 93, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, + 106, 106, 107, 108, 109, 109, 110, 111, + 111, 112, 112, 113, 113, 114, 114, 114, + 115, 115, 115, 115, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 115, 115, 115, + 115, 114, 114, 114, 113, 113, 112, 112, + 111, 111, 110, 110, 109, 108, 108, 107, + 106, 105, 104, 103, 102, 101, 100, 99, + 98, 97, 96, 95, 94, 93, 91, 90, + 89, 88, 86, 85, 84, 82, 81, 79, + 78, 76, 75, 73, 71, 70, 68, 67, + 65, 63, 62, 60, 58, 56, 55, 53, + 51, 49, 47, 45, 44, 42, 40, 38, + 36, 34, 32, 30, 28, 26, 24, 22, + 20, 18, 16, 14, 12, 10, 8, 6, + 4, 2, 0, -1, -3, -5, -7, -9, -11 +}; + +static u16 i2c_ident[] = { + V4L2_IDENT_OV9650, + V4L2_IDENT_OV9655, + V4L2_IDENT_SOI968, + V4L2_IDENT_OV7660, + V4L2_IDENT_OV7670, + V4L2_IDENT_MT9V011, + V4L2_IDENT_MT9V111, + V4L2_IDENT_MT9V112, + V4L2_IDENT_MT9M001C12ST, + V4L2_IDENT_MT9M111, + V4L2_IDENT_MT9M112, + V4L2_IDENT_HV7131R, +}; + +static u16 bridge_init[][2] = { + {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c}, + {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40}, + {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10}, + {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00}, + {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50}, + {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50}, + {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04}, + {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05}, + {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00}, + {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d}, + {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04}, + {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8}, + {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32}, + {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd}, + {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01}, + {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f}, + {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f}, + {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01}, + {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80}, + {0x1007, 0x00} +}; + +/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */ +static u8 ov_gain[] = { + 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */, + 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */, + 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */, + 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */, + 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */, + 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */, + 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */, + 0x70 /* 8x */ +}; + +/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */ +static u16 micron1_gain[] = { + /* 1x 1.25x 1.5x 1.75x */ + 0x0020, 0x0028, 0x0030, 0x0038, + /* 2x 2.25x 2.5x 2.75x */ + 0x00a0, 0x00a4, 0x00a8, 0x00ac, + /* 3x 3.25x 3.5x 3.75x */ + 0x00b0, 0x00b4, 0x00b8, 0x00bc, + /* 4x 4.25x 4.5x 4.75x */ + 0x00c0, 0x00c4, 0x00c8, 0x00cc, + /* 5x 5.25x 5.5x 5.75x */ + 0x00d0, 0x00d4, 0x00d8, 0x00dc, + /* 6x 6.25x 6.5x 6.75x */ + 0x00e0, 0x00e4, 0x00e8, 0x00ec, + /* 7x 7.25x 7.5x 7.75x */ + 0x00f0, 0x00f4, 0x00f8, 0x00fc, + /* 8x */ + 0x01c0 +}; + +/* mt9m001 sensor uses a different gain formula then other micron sensors */ +/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */ +static u16 micron2_gain[] = { + /* 1x 1.25x 1.5x 1.75x */ + 0x0008, 0x000a, 0x000c, 0x000e, + /* 2x 2.25x 2.5x 2.75x */ + 0x0010, 0x0012, 0x0014, 0x0016, + /* 3x 3.25x 3.5x 3.75x */ + 0x0018, 0x001a, 0x001c, 0x001e, + /* 4x 4.25x 4.5x 4.75x */ + 0x0020, 0x0051, 0x0052, 0x0053, + /* 5x 5.25x 5.5x 5.75x */ + 0x0054, 0x0055, 0x0056, 0x0057, + /* 6x 6.25x 6.5x 6.75x */ + 0x0058, 0x0059, 0x005a, 0x005b, + /* 7x 7.25x 7.5x 7.75x */ + 0x005c, 0x005d, 0x005e, 0x005f, + /* 8x */ + 0x0060 +}; + +/* Gain = .5 + bit[7:0] / 16 */ +static u8 hv7131r_gain[] = { + 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */, + 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */, + 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */, + 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */, + 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */, + 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */, + 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */, + 0x78 /* 8x */ +}; + +static struct i2c_reg_u8 soi968_init[] = { + {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f}, + {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00}, + {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c}, + {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff}, + {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20}, + {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e}, + {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13}, + {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79}, + {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40}, + {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32}, + {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80}, +}; + +static struct i2c_reg_u8 ov7660_init[] = { + {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3}, + {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40}, + {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a}, + /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using + 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */ + {0x17, 0x10}, {0x18, 0x61}, + {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43}, + {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6}, + {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50}, +}; + +static struct i2c_reg_u8 ov7670_init[] = { + {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01}, + {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00}, + {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0}, + {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00}, + {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07}, + {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75}, + {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8}, + {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5}, + {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27}, + {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b}, + {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a}, + {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00}, + {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00}, + {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80}, + {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82}, + {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20}, + {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c}, + {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66}, + {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11}, + {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40}, + {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02}, + {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a}, + {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08}, + {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04}, + {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30}, + {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88}, + {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30}, + {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99}, + {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0}, + {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e}, + {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01}, + {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20}, + {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0}, + {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30}, + {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06}, + {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a}, + {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a}, + {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84}, + {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d}, + {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d}, + {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00}, + {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, + {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60}, + {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, + {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e}, + {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56}, + {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03}, + {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47}, + {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74}, + {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2}, + {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00}, + {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a}, + {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00}, + {0x93, 0x00}, +}; + +static struct i2c_reg_u8 ov9650_init[] = { + {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78}, + {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03}, + {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00}, + {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00}, + {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c}, + {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2}, + {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07}, + {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00}, + {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04}, + {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68}, + {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80}, + {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00}, + {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00}, + {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30}, + {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf}, + {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00}, + {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01}, + {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19}, + {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1}, + {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80}, + {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00}, + {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20}, + {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf}, + {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88}, + {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00}, + {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8}, + {0xaa, 0x92}, {0xab, 0x0a}, +}; + +static struct i2c_reg_u8 ov9655_init[] = { + {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba}, + {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08}, + {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d}, + {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57}, + {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19}, + {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80}, + {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c}, + {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc}, + {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05}, + {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e}, + {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68}, + {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92}, + {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80}, + {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00}, + {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44}, + {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01}, + {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0}, + {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00}, + {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61}, + {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a}, + {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01}, + {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a}, + {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c}, + {0x04, 0x03}, {0x00, 0x13}, +}; + +static struct i2c_reg_u16 mt9v112_init[] = { + {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020}, + {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b}, + {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001}, + {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a}, + {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58}, + {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001}, + {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020}, + {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020}, + {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020}, + {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c}, + {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2}, + {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0}, + {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020}, + {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c}, + {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae}, + {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae}, +}; + +static struct i2c_reg_u16 mt9v111_init[] = { + {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000}, + {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0}, + {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e}, + {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016}, + {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004}, + {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008}, + {0x0e, 0x0008}, {0x20, 0x0000} +}; + +static struct i2c_reg_u16 mt9v011_init[] = { + {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000}, + {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1}, + {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006}, + {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000}, + {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000}, + {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000}, + {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000}, + {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000}, + {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000}, + {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000}, + {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000}, + {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000}, + {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024}, + {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000}, + {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100}, + {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1}, + {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000}, + {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000}, + {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000}, + {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101}, + {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003}, + {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0}, + {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000}, + {0x06, 0x0029}, {0x05, 0x0009}, +}; + +static struct i2c_reg_u16 mt9m001_init[] = { + {0x0d, 0x0001}, + {0x0d, 0x0000}, + {0x04, 0x0500}, /* hres = 1280 */ + {0x03, 0x0400}, /* vres = 1024 */ + {0x20, 0x1100}, + {0x06, 0x0010}, + {0x2b, 0x0024}, + {0x2e, 0x0024}, + {0x35, 0x0024}, + {0x2d, 0x0020}, + {0x2c, 0x0020}, + {0x09, 0x0ad4}, + {0x35, 0x0057}, +}; + +static struct i2c_reg_u16 mt9m111_init[] = { + {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008}, + {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300}, + {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e}, + {0xf0, 0x0000}, +}; + +static struct i2c_reg_u16 mt9m112_init[] = { + {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008}, + {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300}, + {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e}, + {0xf0, 0x0000}, +}; + +static struct i2c_reg_u8 hv7131r_init[] = { + {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08}, + {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0}, + {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08}, + {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07}, + {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62}, + {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10}, + {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00}, + {0x23, 0x09}, {0x01, 0x08}, +}; + +static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) +{ + struct usb_device *dev = gspca_dev->dev; + int result; + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + reg, + 0x00, + gspca_dev->usb_buf, + length, + 500); + if (unlikely(result < 0 || result != length)) { + err("Read register failed 0x%02X", reg); + return -EIO; + } + return 0; +} + +static int reg_w(struct gspca_dev *gspca_dev, u16 reg, + const u8 *buffer, int length) +{ + struct usb_device *dev = gspca_dev->dev; + int result; + memcpy(gspca_dev->usb_buf, buffer, length); + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + reg, + 0x00, + gspca_dev->usb_buf, + length, + 500); + if (unlikely(result < 0 || result != length)) { + err("Write register failed index 0x%02X", reg); + return -EIO; + } + return 0; +} + +static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value) +{ + u8 data[1] = {value}; + return reg_w(gspca_dev, reg, data, 1); +} + +static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer) +{ + int i; + reg_w(gspca_dev, 0x10c0, buffer, 8); + for (i = 0; i < 5; i++) { + reg_r(gspca_dev, 0x10c0, 1); + if (gspca_dev->usb_buf[0] & 0x04) { + if (gspca_dev->usb_buf[0] & 0x08) + return -EIO; + return 0; + } + msleep(1); + } + return -EIO; +} + +static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + u8 row[8]; + + /* + * from the point of view of the bridge, the length + * includes the address + */ + row[0] = 0x81 | (2 << 4); + row[1] = sd->i2c_addr; + row[2] = reg; + row[3] = val; + row[4] = 0x00; + row[5] = 0x00; + row[6] = 0x00; + row[7] = 0x10; + + return i2c_w(gspca_dev, row); +} + +static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 row[8]; + + /* + * from the point of view of the bridge, the length + * includes the address + */ + row[0] = 0x81 | (3 << 4); + row[1] = sd->i2c_addr; + row[2] = reg; + row[3] = (val >> 8) & 0xff; + row[4] = val & 0xff; + row[5] = 0x00; + row[6] = 0x00; + row[7] = 0x10; + + return i2c_w(gspca_dev, row); +} + +static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 row[8]; + + row[0] = 0x81 | (1 << 4); + row[1] = sd->i2c_addr; + row[2] = reg; + row[3] = 0; + row[4] = 0; + row[5] = 0; + row[6] = 0; + row[7] = 0x10; + if (i2c_w(gspca_dev, row) < 0) + return -EIO; + row[0] = 0x81 | (1 << 4) | 0x02; + row[2] = 0; + if (i2c_w(gspca_dev, row) < 0) + return -EIO; + if (reg_r(gspca_dev, 0x10c2, 5) < 0) + return -EIO; + *val = gspca_dev->usb_buf[4]; + return 0; +} + +static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 row[8]; + + row[0] = 0x81 | (1 << 4); + row[1] = sd->i2c_addr; + row[2] = reg; + row[3] = 0; + row[4] = 0; + row[5] = 0; + row[6] = 0; + row[7] = 0x10; + if (i2c_w(gspca_dev, row) < 0) + return -EIO; + row[0] = 0x81 | (2 << 4) | 0x02; + row[2] = 0; + if (i2c_w(gspca_dev, row) < 0) + return -EIO; + if (reg_r(gspca_dev, 0x10c2, 5) < 0) + return -EIO; + *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; + return 0; +} + +static int ov9650_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + u16 id; + struct sd *sd = (struct sd *) gspca_dev; + + if (i2c_r2(gspca_dev, 0x1c, &id) < 0) + return -EINVAL; + + if (id != 0x7fa2) { + err("sensor id for ov9650 doesn't match (0x%04x)", id); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) { + if (i2c_w1(gspca_dev, ov9650_init[i].reg, + ov9650_init[i].val) < 0) { + err("OV9650 sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 1; + sd->vstart = 7; + return 0; +} + +static int ov9655_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) { + if (i2c_w1(gspca_dev, ov9655_init[i].reg, + ov9655_init[i].val) < 0) { + err("OV9655 sensor initialization failed"); + return -ENODEV; + } + } + /* disable hflip and vflip */ + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); + sd->hstart = 1; + sd->vstart = 2; + return 0; +} + +static int soi968_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(soi968_init); i++) { + if (i2c_w1(gspca_dev, soi968_init[i].reg, + soi968_init[i].val) < 0) { + err("SOI968 sensor initialization failed"); + return -ENODEV; + } + } + /* disable hflip and vflip */ + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) + | (1 << EXPOSURE_IDX); + sd->hstart = 60; + sd->vstart = 11; + return 0; +} + +static int ov7660_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) { + if (i2c_w1(gspca_dev, ov7660_init[i].reg, + ov7660_init[i].val) < 0) { + err("OV7660 sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 3; + sd->vstart = 3; + return 0; +} + +static int ov7670_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) { + if (i2c_w1(gspca_dev, ov7670_init[i].reg, + ov7670_init[i].val) < 0) { + err("OV7670 sensor initialization failed"); + return -ENODEV; + } + } + /* disable hflip and vflip */ + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); + sd->hstart = 0; + sd->vstart = 1; + return 0; +} + +static int mt9v_init_sensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + u16 value; + int ret; + + sd->i2c_addr = 0x5d; + ret = i2c_r2(gspca_dev, 0xff, &value); + if ((ret == 0) && (value == 0x8243)) { + for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) { + if (i2c_w2(gspca_dev, mt9v011_init[i].reg, + mt9v011_init[i].val) < 0) { + err("MT9V011 sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 2; + sd->vstart = 2; + sd->sensor = SENSOR_MT9V011; + info("MT9V011 sensor detected"); + return 0; + } + + sd->i2c_addr = 0x5c; + i2c_w2(gspca_dev, 0x01, 0x0004); + ret = i2c_r2(gspca_dev, 0xff, &value); + if ((ret == 0) && (value == 0x823a)) { + for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) { + if (i2c_w2(gspca_dev, mt9v111_init[i].reg, + mt9v111_init[i].val) < 0) { + err("MT9V111 sensor initialization failed"); + return -ENODEV; + } + } + gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) + | (1 << GAIN_IDX); + sd->hstart = 2; + sd->vstart = 2; + sd->sensor = SENSOR_MT9V111; + info("MT9V111 sensor detected"); + return 0; + } + + sd->i2c_addr = 0x5d; + ret = i2c_w2(gspca_dev, 0xf0, 0x0000); + if (ret < 0) { + sd->i2c_addr = 0x48; + i2c_w2(gspca_dev, 0xf0, 0x0000); + } + ret = i2c_r2(gspca_dev, 0x00, &value); + if ((ret == 0) && (value == 0x1229)) { + for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) { + if (i2c_w2(gspca_dev, mt9v112_init[i].reg, + mt9v112_init[i].val) < 0) { + err("MT9V112 sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 6; + sd->vstart = 2; + sd->sensor = SENSOR_MT9V112; + info("MT9V112 sensor detected"); + return 0; + } + + return -ENODEV; +} + +static int mt9m112_init_sensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) { + if (i2c_w2(gspca_dev, mt9m112_init[i].reg, + mt9m112_init[i].val) < 0) { + err("MT9M112 sensor initialization failed"); + return -ENODEV; + } + } + gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) + | (1 << GAIN_IDX); + sd->hstart = 0; + sd->vstart = 2; + return 0; +} + +static int mt9m111_init_sensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) { + if (i2c_w2(gspca_dev, mt9m111_init[i].reg, + mt9m111_init[i].val) < 0) { + err("MT9M111 sensor initialization failed"); + return -ENODEV; + } + } + gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) + | (1 << GAIN_IDX); + sd->hstart = 0; + sd->vstart = 2; + return 0; +} + +static int mt9m001_init_sensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + u16 id; + + if (i2c_r2(gspca_dev, 0x00, &id) < 0) + return -EINVAL; + + /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ + switch (id) { + case 0x8411: + case 0x8421: + info("MT9M001 color sensor detected"); + break; + case 0x8431: + info("MT9M001 mono sensor detected"); + break; + default: + err("No MT9M001 chip detected, ID = %x\n", id); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) { + if (i2c_w2(gspca_dev, mt9m001_init[i].reg, + mt9m001_init[i].val) < 0) { + err("MT9M001 sensor initialization failed"); + return -ENODEV; + } + } + /* disable hflip and vflip */ + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); + sd->hstart = 1; + sd->vstart = 1; + return 0; +} + +static int hv7131r_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) { + if (i2c_w1(gspca_dev, hv7131r_init[i].reg, + hv7131r_init[i].val) < 0) { + err("HV7131R Sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 0; + sd->vstart = 1; + return 0; +} + +static int set_cmatrix(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 hue_coord, hue_index = 180 + sd->hue; + u8 cmatrix[21]; + + memset(cmatrix, 0, sizeof cmatrix); + cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26; + cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; + cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; + cmatrix[18] = sd->brightness - 0x80; + + hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8; + cmatrix[6] = hue_coord; + cmatrix[7] = (hue_coord >> 8) & 0x0f; + + hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8; + cmatrix[8] = hue_coord; + cmatrix[9] = (hue_coord >> 8) & 0x0f; + + hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8; + cmatrix[10] = hue_coord; + cmatrix[11] = (hue_coord >> 8) & 0x0f; + + hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8; + cmatrix[12] = hue_coord; + cmatrix[13] = (hue_coord >> 8) & 0x0f; + + hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8; + cmatrix[14] = hue_coord; + cmatrix[15] = (hue_coord >> 8) & 0x0f; + + hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8; + cmatrix[16] = hue_coord; + cmatrix[17] = (hue_coord >> 8) & 0x0f; + + return reg_w(gspca_dev, 0x10e1, cmatrix, 21); +} + +static int set_gamma(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 gamma[17]; + u8 gval = sd->gamma * 0xb8 / 0x100; + + + gamma[0] = 0x0a; + gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); + gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8); + gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8); + gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8); + gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8); + gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8); + gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8); + gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8); + gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8); + gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8); + gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8); + gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8); + gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8); + gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8); + gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8); + gamma[16] = 0xf5; + + return reg_w(gspca_dev, 0x1190, gamma, 17); +} + +static int set_redblue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + reg_w1(gspca_dev, 0x118c, sd->red); + reg_w1(gspca_dev, 0x118f, sd->blue); + return 0; +} + +static int set_hvflip(struct gspca_dev *gspca_dev) +{ + u8 value, tslb, hflip, vflip; + u16 value2; + struct sd *sd = (struct sd *) gspca_dev; + + if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) { + hflip = !sd->hflip; + vflip = !sd->vflip; + } else { + hflip = sd->hflip; + vflip = sd->vflip; + } + + switch (sd->sensor) { + case SENSOR_OV7660: + value = 0x01; + if (hflip) + value |= 0x20; + if (vflip) { + value |= 0x10; + sd->vstart = 2; + } else + sd->vstart = 3; + reg_w1(gspca_dev, 0x1182, sd->vstart); + i2c_w1(gspca_dev, 0x1e, value); + break; + case SENSOR_OV9650: + i2c_r1(gspca_dev, 0x1e, &value); + value &= ~0x30; + tslb = 0x01; + if (hflip) + value |= 0x20; + if (vflip) { + value |= 0x10; + tslb = 0x49; + } + i2c_w1(gspca_dev, 0x1e, value); + i2c_w1(gspca_dev, 0x3a, tslb); + break; + case SENSOR_MT9V111: + case SENSOR_MT9V011: + i2c_r2(gspca_dev, 0x20, &value2); + value2 &= ~0xc0a0; + if (hflip) + value2 |= 0x8080; + if (vflip) + value2 |= 0x4020; + i2c_w2(gspca_dev, 0x20, value2); + break; + case SENSOR_MT9M112: + case SENSOR_MT9M111: + case SENSOR_MT9V112: + i2c_r2(gspca_dev, 0x20, &value2); + value2 &= ~0x0003; + if (hflip) + value2 |= 0x0002; + if (vflip) + value2 |= 0x0001; + i2c_w2(gspca_dev, 0x20, value2); + break; + case SENSOR_HV7131R: + i2c_r1(gspca_dev, 0x01, &value); + value &= ~0x03; + if (vflip) + value |= 0x01; + if (hflip) + value |= 0x02; + i2c_w1(gspca_dev, 0x01, value); + break; + } + return 0; +} + +static int set_exposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e}; + switch (sd->sensor) { + case SENSOR_OV7660: + case SENSOR_OV7670: + case SENSOR_OV9655: + case SENSOR_OV9650: + exp[0] |= (3 << 4); + exp[2] = 0x2d; + exp[3] = sd->exposure & 0xff; + exp[4] = sd->exposure >> 8; + break; + case SENSOR_MT9M001: + case SENSOR_MT9V112: + case SENSOR_MT9V011: + exp[0] |= (3 << 4); + exp[2] = 0x09; + exp[3] = sd->exposure >> 8; + exp[4] = sd->exposure & 0xff; + break; + case SENSOR_HV7131R: + exp[0] |= (4 << 4); + exp[2] = 0x25; + exp[3] = (sd->exposure >> 5) & 0xff; + exp[4] = (sd->exposure << 3) & 0xff; + exp[5] = 0; + break; + default: + return 0; + } + i2c_w(gspca_dev, exp); + return 0; +} + +static int set_gain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; + switch (sd->sensor) { + case SENSOR_OV7660: + case SENSOR_OV7670: + case SENSOR_SOI968: + case SENSOR_OV9655: + case SENSOR_OV9650: + gain[0] |= (2 << 4); + gain[3] = ov_gain[sd->gain]; + break; + case SENSOR_MT9V011: + gain[0] |= (3 << 4); + gain[2] = 0x35; + gain[3] = micron1_gain[sd->gain] >> 8; + gain[4] = micron1_gain[sd->gain] & 0xff; + break; + case SENSOR_MT9V112: + gain[0] |= (3 << 4); + gain[2] = 0x2f; + gain[3] = micron1_gain[sd->gain] >> 8; + gain[4] = micron1_gain[sd->gain] & 0xff; + break; + case SENSOR_MT9M001: + gain[0] |= (3 << 4); + gain[2] = 0x2f; + gain[3] = micron2_gain[sd->gain] >> 8; + gain[4] = micron2_gain[sd->gain] & 0xff; + break; + case SENSOR_HV7131R: + gain[0] |= (2 << 4); + gain[2] = 0x30; + gain[3] = hv7131r_gain[sd->gain]; + break; + default: + return 0; + } + i2c_w(gspca_dev, gain); + return 0; +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + return set_cmatrix(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->brightness; + return 0; +} + + +static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + return set_cmatrix(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->contrast; + return 0; +} + +static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->saturation = val; + if (gspca_dev->streaming) + return set_cmatrix(gspca_dev); + return 0; +} + +static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->saturation; + return 0; +} + +static int sd_sethue(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hue = val; + if (gspca_dev->streaming) + return set_cmatrix(gspca_dev); + return 0; +} + +static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->hue; + return 0; +} + +static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gamma = val; + if (gspca_dev->streaming) + return set_gamma(gspca_dev); + return 0; +} + +static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->gamma; + return 0; +} + +static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->red = val; + if (gspca_dev->streaming) + return set_redblue(gspca_dev); + return 0; +} + +static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->red; + return 0; +} + +static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->blue = val; + if (gspca_dev->streaming) + return set_redblue(gspca_dev); + return 0; +} + +static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->blue; + return 0; +} + +static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hflip = val; + if (gspca_dev->streaming) + return set_hvflip(gspca_dev); + return 0; +} + +static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->hflip; + return 0; +} + +static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vflip = val; + if (gspca_dev->streaming) + return set_hvflip(gspca_dev); + return 0; +} + +static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->vflip; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + return set_exposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->exposure; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + return set_gain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->gain; + return 0; +} + +static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + sd->auto_exposure = val; + return 0; +} + +static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->auto_exposure; + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int sd_dbg_g_register(struct gspca_dev *gspca_dev, + struct v4l2_dbg_register *reg) +{ + struct sd *sd = (struct sd *) gspca_dev; + switch (reg->match.type) { + case V4L2_CHIP_MATCH_HOST: + if (reg->match.addr != 0) + return -EINVAL; + if (reg->reg < 0x1000 || reg->reg > 0x11ff) + return -EINVAL; + if (reg_r(gspca_dev, reg->reg, 1) < 0) + return -EINVAL; + reg->val = gspca_dev->usb_buf[0]; + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + if (reg->match.addr != sd->i2c_addr) + return -EINVAL; + if (sd->sensor >= SENSOR_MT9V011 && + sd->sensor <= SENSOR_MT9M112) { + if (i2c_r2(gspca_dev, reg->reg, (u16 *)®->val) < 0) + return -EINVAL; + } else { + if (i2c_r1(gspca_dev, reg->reg, (u8 *)®->val) < 0) + return -EINVAL; + } + return 0; + } + return -EINVAL; +} + +static int sd_dbg_s_register(struct gspca_dev *gspca_dev, + struct v4l2_dbg_register *reg) +{ + struct sd *sd = (struct sd *) gspca_dev; + switch (reg->match.type) { + case V4L2_CHIP_MATCH_HOST: + if (reg->match.addr != 0) + return -EINVAL; + if (reg->reg < 0x1000 || reg->reg > 0x11ff) + return -EINVAL; + if (reg_w1(gspca_dev, reg->reg, reg->val) < 0) + return -EINVAL; + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + if (reg->match.addr != sd->i2c_addr) + return -EINVAL; + if (sd->sensor >= SENSOR_MT9V011 && + sd->sensor <= SENSOR_MT9M112) { + if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0) + return -EINVAL; + } else { + if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0) + return -EINVAL; + } + return 0; + } + return -EINVAL; +} +#endif + +static int sd_chip_ident(struct gspca_dev *gspca_dev, + struct v4l2_dbg_chip_ident *chip) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (chip->match.type) { + case V4L2_CHIP_MATCH_HOST: + if (chip->match.addr != 0) + return -EINVAL; + chip->revision = 0; + chip->ident = V4L2_IDENT_SN9C20X; + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + if (chip->match.addr != sd->i2c_addr) + return -EINVAL; + chip->revision = 0; + chip->ident = i2c_ident[sd->sensor]; + return 0; + } + return -EINVAL; +} + +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + + sd->sensor = (id->driver_info >> 8) & 0xff; + sd->i2c_addr = id->driver_info & 0xff; + sd->flags = (id->driver_info >> 16) & 0xff; + + switch (sd->sensor) { + case SENSOR_MT9M112: + case SENSOR_MT9M111: + case SENSOR_OV9650: + case SENSOR_SOI968: + cam->cam_mode = sxga_mode; + cam->nmodes = ARRAY_SIZE(sxga_mode); + break; + case SENSOR_MT9M001: + cam->cam_mode = mono_mode; + cam->nmodes = ARRAY_SIZE(mono_mode); + break; + default: + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + break; + } + + sd->old_step = 0; + sd->older_step = 0; + sd->exposure_step = 16; + + sd->brightness = BRIGHTNESS_DEFAULT; + sd->contrast = CONTRAST_DEFAULT; + sd->saturation = SATURATION_DEFAULT; + sd->hue = HUE_DEFAULT; + sd->gamma = GAMMA_DEFAULT; + sd->red = RED_DEFAULT; + sd->blue = BLUE_DEFAULT; + + sd->hflip = HFLIP_DEFAULT; + sd->vflip = VFLIP_DEFAULT; + sd->exposure = EXPOSURE_DEFAULT; + sd->gain = GAIN_DEFAULT; + sd->auto_exposure = AUTO_EXPOSURE_DEFAULT; + + sd->quality = 95; + + return 0; +} + +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + u8 value; + u8 i2c_init[9] = + {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}; + + for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { + value = bridge_init[i][1]; + if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) { + err("Device initialization failed"); + return -ENODEV; + } + } + + if (sd->flags & LED_REVERSE) + reg_w1(gspca_dev, 0x1006, 0x00); + else + reg_w1(gspca_dev, 0x1006, 0x20); + + if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) { + err("Device initialization failed"); + return -ENODEV; + } + + switch (sd->sensor) { + case SENSOR_OV9650: + if (ov9650_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("OV9650 sensor detected"); + break; + case SENSOR_OV9655: + if (ov9655_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("OV9655 sensor detected"); + break; + case SENSOR_SOI968: + if (soi968_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("SOI968 sensor detected"); + break; + case SENSOR_OV7660: + if (ov7660_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("OV7660 sensor detected"); + break; + case SENSOR_OV7670: + if (ov7670_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("OV7670 sensor detected"); + break; + case SENSOR_MT9VPRB: + if (mt9v_init_sensor(gspca_dev) < 0) + return -ENODEV; + break; + case SENSOR_MT9M111: + if (mt9m111_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("MT9M111 sensor detected"); + break; + case SENSOR_MT9M112: + if (mt9m112_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("MT9M112 sensor detected"); + break; + case SENSOR_MT9M001: + if (mt9m001_init_sensor(gspca_dev) < 0) + return -ENODEV; + break; + case SENSOR_HV7131R: + if (hv7131r_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("HV7131R sensor detected"); + break; + default: + info("Unsupported Sensor"); + return -ENODEV; + } + + return 0; +} + +static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 value; + switch (sd->sensor) { + case SENSOR_SOI968: + if (mode & MODE_SXGA) { + i2c_w1(gspca_dev, 0x17, 0x1d); + i2c_w1(gspca_dev, 0x18, 0xbd); + i2c_w1(gspca_dev, 0x19, 0x01); + i2c_w1(gspca_dev, 0x1a, 0x81); + i2c_w1(gspca_dev, 0x12, 0x00); + sd->hstart = 140; + sd->vstart = 19; + } else { + i2c_w1(gspca_dev, 0x17, 0x13); + i2c_w1(gspca_dev, 0x18, 0x63); + i2c_w1(gspca_dev, 0x19, 0x01); + i2c_w1(gspca_dev, 0x1a, 0x79); + i2c_w1(gspca_dev, 0x12, 0x40); + sd->hstart = 60; + sd->vstart = 11; + } + break; + case SENSOR_OV9650: + if (mode & MODE_SXGA) { + i2c_w1(gspca_dev, 0x17, 0x1b); + i2c_w1(gspca_dev, 0x18, 0xbc); + i2c_w1(gspca_dev, 0x19, 0x01); + i2c_w1(gspca_dev, 0x1a, 0x82); + i2c_r1(gspca_dev, 0x12, &value); + i2c_w1(gspca_dev, 0x12, value & 0x07); + } else { + i2c_w1(gspca_dev, 0x17, 0x24); + i2c_w1(gspca_dev, 0x18, 0xc5); + i2c_w1(gspca_dev, 0x19, 0x00); + i2c_w1(gspca_dev, 0x1a, 0x3c); + i2c_r1(gspca_dev, 0x12, &value); + i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40); + } + break; + case SENSOR_MT9M112: + case SENSOR_MT9M111: + if (mode & MODE_SXGA) { + i2c_w2(gspca_dev, 0xf0, 0x0002); + i2c_w2(gspca_dev, 0xc8, 0x970b); + i2c_w2(gspca_dev, 0xf0, 0x0000); + } else { + i2c_w2(gspca_dev, 0xf0, 0x0002); + i2c_w2(gspca_dev, 0xc8, 0x8000); + i2c_w2(gspca_dev, 0xf0, 0x0000); + } + break; + } +} + +#define HW_WIN(mode, hstart, vstart) \ +((const u8 []){hstart, 0, vstart, 0, \ +(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \ +(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)}) + +#define CLR_WIN(width, height) \ +((const u8 [])\ +{0, width >> 2, 0, height >> 1,\ +((width >> 10) & 0x01) | ((height >> 8) & 0x6)}) + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + int width = gspca_dev->width; + int height = gspca_dev->height; + u8 fmt, scale = 0; + + jpeg_define(sd->jpeg_hdr, height, width, + 0x21); + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + if (mode & MODE_RAW) + fmt = 0x2d; + else if (mode & MODE_JPEG) + fmt = 0x2c; + else + fmt = 0x2f; /* YUV 420 */ + + switch (mode & SCALE_MASK) { + case SCALE_1280x1024: + scale = 0xc0; + info("Set 1280x1024"); + break; + case SCALE_640x480: + scale = 0x80; + info("Set 640x480"); + break; + case SCALE_320x240: + scale = 0x90; + info("Set 320x240"); + break; + case SCALE_160x120: + scale = 0xa0; + info("Set 160x120"); + break; + } + + configure_sensor_output(gspca_dev, mode); + reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); + reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64); + reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5); + reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6); + reg_w1(gspca_dev, 0x1189, scale); + reg_w1(gspca_dev, 0x10e0, fmt); + + set_cmatrix(gspca_dev); + set_gamma(gspca_dev); + set_redblue(gspca_dev); + set_gain(gspca_dev); + set_exposure(gspca_dev); + set_hvflip(gspca_dev); + + reg_w1(gspca_dev, 0x1007, 0x20); + + reg_r(gspca_dev, 0x1061, 1); + reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02); + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w1(gspca_dev, 0x1007, 0x00); + + reg_r(gspca_dev, 0x1061, 1); + reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02); +} + +static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) +{ + struct sd *sd = (struct sd *) gspca_dev; + s16 new_exp; + + /* + * some hardcoded values are present + * like those for maximal/minimal exposure + * and exposure steps + */ + if (avg_lum < MIN_AVG_LUM) { + if (sd->exposure > 0x1770) + return; + + new_exp = sd->exposure + sd->exposure_step; + if (new_exp > 0x1770) + new_exp = 0x1770; + if (new_exp < 0x10) + new_exp = 0x10; + sd->exposure = new_exp; + set_exposure(gspca_dev); + + sd->older_step = sd->old_step; + sd->old_step = 1; + + if (sd->old_step ^ sd->older_step) + sd->exposure_step /= 2; + else + sd->exposure_step += 2; + } + if (avg_lum > MAX_AVG_LUM) { + if (sd->exposure < 0x10) + return; + new_exp = sd->exposure - sd->exposure_step; + if (new_exp > 0x1700) + new_exp = 0x1770; + if (new_exp < 0x10) + new_exp = 0x10; + sd->exposure = new_exp; + set_exposure(gspca_dev); + sd->older_step = sd->old_step; + sd->old_step = 0; + + if (sd->old_step ^ sd->older_step) + sd->exposure_step /= 2; + else + sd->exposure_step += 2; + } +} + +static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (avg_lum < MIN_AVG_LUM) { + if (sd->gain + 1 <= 28) { + sd->gain++; + set_gain(gspca_dev); + } + } + if (avg_lum > MAX_AVG_LUM) { + if (sd->gain > 0) { + sd->gain--; + set_gain(gspca_dev); + } + } +} + +static void sd_dqcallback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum; + + if (!sd->auto_exposure) + return; + + avg_lum = atomic_read(&sd->avg_lum); + if (sd->sensor == SENSOR_SOI968) + do_autogain(gspca_dev, avg_lum); + else + do_autoexposure(gspca_dev, avg_lum); +} + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet */ + int len) /* interrupt packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret = -EINVAL; + if (!(sd->flags & HAS_NO_BUTTON) && len == 1) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); + input_sync(gspca_dev->input_dev); + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + ret = 0; + } + return ret; +} +#endif + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum; + static u8 frame_header[] = + {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; + if (len == 64 && memcmp(data, frame_header, 6) == 0) { + avg_lum = ((data[35] >> 2) & 3) | + (data[20] << 2) | + (data[19] << 10); + avg_lum += ((data[35] >> 4) & 3) | + (data[22] << 2) | + (data[21] << 10); + avg_lum += ((data[35] >> 6) & 3) | + (data[24] << 2) | + (data[23] << 10); + avg_lum += (data[36] & 3) | + (data[26] << 2) | + (data[25] << 10); + avg_lum += ((data[36] >> 2) & 3) | + (data[28] << 2) | + (data[27] << 10); + avg_lum += ((data[36] >> 4) & 3) | + (data[30] << 2) | + (data[29] << 10); + avg_lum += ((data[36] >> 6) & 3) | + (data[32] << 2) | + (data[31] << 10); + avg_lum += ((data[44] >> 4) & 3) | + (data[34] << 2) | + (data[33] << 10); + avg_lum >>= 9; + atomic_set(&sd->avg_lum, avg_lum); + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + return; + } + if (gspca_dev->last_packet_type == LAST_PACKET) { + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv + & MODE_JPEG) { + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + gspca_frame_add(gspca_dev, INTER_PACKET, + data, len); + } else { + gspca_frame_add(gspca_dev, FIRST_PACKET, + data, len); + } + } else { + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + } +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +#endif + .dq_callback = sd_dqcallback, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .set_register = sd_dbg_s_register, + .get_register = sd_dbg_g_register, +#endif + .get_chip_ident = sd_chip_ident, +}; + +#define SN9C20X(sensor, i2c_addr, flags) \ + .driver_info = ((flags & 0xff) << 16) \ + | (SENSOR_ ## sensor << 8) \ + | (i2c_addr) + +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)}, + {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30, + (FLIP_DETECT | HAS_NO_BUTTON))}, + {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)}, + {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)}, + {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, FLIP_DETECT)}, + {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)}, + {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)}, + {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)}, + {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)}, + {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)}, + {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)}, + {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)}, + {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)}, + {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, + .reset_resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sonixb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sonixb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sonixb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sonixb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1541 @@ +/* + * sonix sn9c102 (bayer) library + * + * Copyright (C) 2009-2011 Jean-François Moine + * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr + * Add Pas106 Stefano Mozzi (C) 2004 + * + * 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, or + * any later version. + * + * 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 + */ + +/* Some documentation on known sonixb registers: + +Reg Use +sn9c101 / sn9c102: +0x10 high nibble red gain low nibble blue gain +0x11 low nibble green gain +sn9c103: +0x05 red gain 0-127 +0x06 blue gain 0-127 +0x07 green gain 0-127 +all: +0x08-0x0f i2c / 3wire registers +0x12 hstart +0x13 vstart +0x15 hsize (hsize = register-value * 16) +0x16 vsize (vsize = register-value * 16) +0x17 bit 0 toggle compression quality (according to sn9c102 driver) +0x18 bit 7 enables compression, bit 4-5 set image down scaling: + 00 scale 1, 01 scale 1/2, 10, scale 1/4 +0x19 high-nibble is sensor clock divider, changes exposure on sensors which + use a clock generated by the bridge. Some sensors have their own clock. +0x1c auto_exposure area (for avg_lum) startx (startx = register-value * 32) +0x1d auto_exposure area (for avg_lum) starty (starty = register-value * 32) +0x1e auto_exposure area (for avg_lum) stopx (hsize = (0x1e - 0x1c) * 32) +0x1f auto_exposure area (for avg_lum) stopy (vsize = (0x1f - 0x1d) * 32) +*/ + +#define MODULE_NAME "sonixb" + +#include +#include "gspca.h" + +MODULE_AUTHOR("Jean-François Moine "); +MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* controls */ +enum e_ctrl { + BRIGHTNESS, + GAIN, + EXPOSURE, + AUTOGAIN, + FREQ, + NCTRLS /* number of controls */ +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + + atomic_t avg_lum; + int prev_avg_lum; + int exp_too_low_cnt; + int exp_too_high_cnt; + int header_read; + u8 header[12]; /* Header without sof marker */ + + unsigned char autogain_ignore_frames; + unsigned char frames_to_drop; + + __u8 bridge; /* Type of bridge */ +#define BRIDGE_101 0 +#define BRIDGE_102 0 /* We make no difference between 101 and 102 */ +#define BRIDGE_103 1 + + __u8 sensor; /* Type of image sensor chip */ +#define SENSOR_HV7131D 0 +#define SENSOR_HV7131R 1 +#define SENSOR_OV6650 2 +#define SENSOR_OV7630 3 +#define SENSOR_PAS106 4 +#define SENSOR_PAS202 5 +#define SENSOR_TAS5110C 6 +#define SENSOR_TAS5110D 7 +#define SENSOR_TAS5130CXX 8 + __u8 reg11; +}; + +typedef const __u8 sensor_init_t[8]; + +struct sensor_data { + const __u8 *bridge_init; + sensor_init_t *sensor_init; + int sensor_init_size; + int flags; + unsigned ctrl_dis; + __u8 sensor_addr; +}; + +/* sensor_data flags */ +#define F_GAIN 0x01 /* has gain */ +#define F_SIF 0x02 /* sif or vga */ +#define F_COARSE_EXPO 0x04 /* exposure control is coarse */ + +/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */ +#define MODE_RAW 0x10 /* raw bayer mode */ +#define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */ + +/* ctrl_dis helper macros */ +#define NO_EXPO ((1 << EXPOSURE) | (1 << AUTOGAIN)) +#define NO_FREQ (1 << FREQ) +#define NO_BRIGHTNESS (1 << BRIGHTNESS) + +#define COMP 0xc7 /* 0x87 //0x07 */ +#define COMP1 0xc9 /* 0x89 //0x09 */ + +#define MCK_INIT 0x63 +#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/ + +#define SYS_CLK 0x04 + +#define SENS(bridge, sensor, _flags, _ctrl_dis, _sensor_addr) \ +{ \ + .bridge_init = bridge, \ + .sensor_init = sensor, \ + .sensor_init_size = sizeof(sensor), \ + .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \ +} + +/* We calculate the autogain at the end of the transfer of a frame, at this + moment a frame with the old settings is being captured and transmitted. So + if we adjust the gain or exposure we must ignore atleast the next frame for + the new settings to come into effect before doing any other adjustments. */ +#define AUTOGAIN_IGNORE_FRAMES 1 + +/* V4L2 controls supported by the driver */ +static void setbrightness(struct gspca_dev *gspca_dev); +static void setgain(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static void setfreq(struct gspca_dev *gspca_dev); + +static const struct ctrl sd_ctrls[NCTRLS] = { +[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set_control = setbrightness + }, +[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 255, + .step = 1, +#define GAIN_KNEE 230 + .default_value = 127, + }, + .set_control = setgain + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 1023, + .step = 1, + .default_value = 66, + /* 33 ms / 30 fps (except on PASXXX) */ +#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PASXXX) */ + .flags = 0, + }, + .set_control = setexposure + }, +/* for coarse exposure */ +#define COARSE_EXPOSURE_MIN 2 +#define COARSE_EXPOSURE_MAX 15 +#define COARSE_EXPOSURE_DEF 2 /* 30 fps */ +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Gain (and Exposure)", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + .flags = V4L2_CTRL_FLAG_UPDATE + }, + .set = sd_setautogain, + }, +[FREQ] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ + .step = 1, +#define FREQ_DEF 0 + .default_value = FREQ_DEF, + }, + .set_control = setfreq + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 | MODE_RAW}, + {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; +static const struct v4l2_pix_format sif_mode[] = { + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_RAW | MODE_REDUCED_SIF}, + {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_REDUCED_SIF}, + {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_RAW}, + {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 | MODE_REDUCED_SIF}, + {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +static const __u8 initHv7131d[] = { + 0x04, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, + 0x28, 0x1e, 0x60, 0x8e, 0x42, +}; +static const __u8 hv7131d_sensor_init[][8] = { + {0xa0, 0x11, 0x01, 0x04, 0x00, 0x00, 0x00, 0x17}, + {0xa0, 0x11, 0x02, 0x00, 0x00, 0x00, 0x00, 0x17}, + {0xa0, 0x11, 0x28, 0x00, 0x00, 0x00, 0x00, 0x17}, + {0xa0, 0x11, 0x30, 0x30, 0x00, 0x00, 0x00, 0x17}, /* reset level */ + {0xa0, 0x11, 0x34, 0x02, 0x00, 0x00, 0x00, 0x17}, /* pixel bias volt */ +}; + +static const __u8 initHv7131r[] = { + 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, + 0x28, 0x1e, 0x60, 0x8a, 0x20, +}; +static const __u8 hv7131r_sensor_init[][8] = { + {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10}, + {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10}, + {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10}, + {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16}, + {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15}, +}; +static const __u8 initOv6650[] = { + 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b, + 0x10, +}; +static const __u8 ov6650_sensor_init[][8] = { + /* Bright, contrast, etc are set through SCBB interface. + * AVCAP on win2 do not send any data on this controls. */ + /* Anyway, some registers appears to alter bright and constrat */ + + /* Reset sensor */ + {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, + /* Set clock register 0x11 low nibble is clock divider */ + {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10}, + /* Next some unknown stuff */ + {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10}, +/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10}, + * THIS SET GREEN SCREEN + * (pixels could be innverted in decode kind of "brg", + * but blue wont be there. Avoid this data ... */ + {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */ + {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, + {0xa0, 0x60, 0x30, 0x3d, 0x0a, 0xd8, 0xa4, 0x10}, + /* Enable rgb brightness control */ + {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10}, + /* HDG: Note windows uses the line below, which sets both register 0x60 + and 0x61 I believe these registers of the ov6650 are identical as + those of the ov7630, because if this is true the windows settings + add a bit additional red gain and a lot additional blue gain, which + matches my findings that the windows settings make blue much too + blue and red a little too red. + {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */ + /* Some more unknown stuff */ + {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10}, + {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */ +}; + +static const __u8 initOv7630[] = { + 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */ + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */ + 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */ + 0x28, 0x1e, /* H & V sizes r15 .. r16 */ + 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */ +}; +static const __u8 ov7630_sensor_init[][8] = { + {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10}, +/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */ + {0xd0, 0x21, 0x12, 0x5c, 0x00, 0x80, 0x34, 0x10}, /* jfm */ + {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10}, + {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10}, + {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10}, + {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10}, + {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10}, + {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10}, + {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10}, + {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10}, +/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */ + {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10}, + {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10}, + {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10}, + {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10}, + {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10}, + {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10}, +}; + +static const __u8 initPas106[] = { + 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, + 0x16, 0x12, 0x24, COMP1, MCK_INIT1, +}; +/* compression 0x86 mckinit1 0x2b */ + +/* "Known" PAS106B registers: + 0x02 clock divider + 0x03 Variable framerate bits 4-11 + 0x04 Var framerate bits 0-3, one must leave the 4 msb's at 0 !! + The variable framerate control must never be set lower then 300, + which sets the framerate at 90 / reg02, otherwise vsync is lost. + 0x05 Shutter Time Line Offset, this can be used as an exposure control: + 0 = use full frame time, 255 = no exposure at all + Note this may never be larger then "var-framerate control" / 2 - 2. + When var-framerate control is < 514, no exposure is reached at the max + allowed value for the framerate control value, rather then at 255. + 0x06 Shutter Time Pixel Offset, like reg05 this influences exposure, but + only a very little bit, leave at 0xcd + 0x07 offset sign bit (bit0 1 > negative offset) + 0x08 offset + 0x09 Blue Gain + 0x0a Green1 Gain + 0x0b Green2 Gain + 0x0c Red Gain + 0x0e Global gain + 0x13 Write 1 to commit settings to sensor +*/ + +static const __u8 pas106_sensor_init[][8] = { + /* Pixel Clock Divider 6 */ + { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 }, + /* Frame Time MSB (also seen as 0x12) */ + { 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 }, + /* Frame Time LSB (also seen as 0x05) */ + { 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* Shutter Time Line Offset (also seen as 0x6d) */ + { 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 }, + /* Shutter Time Pixel Offset (also seen as 0xb1) */ + { 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 }, + /* Black Level Subtract Sign (also seen 0x00) */ + { 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 }, + /* Black Level Subtract Level (also seen 0x01) */ + { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 }, + { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain B Pixel 5 a */ + { 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain G1 Pixel 1 5 */ + { 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain G2 Pixel 1 0 5 */ + { 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain R Pixel 3 1 */ + { 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 }, + /* Color GainH Pixel */ + { 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 }, + /* Global Gain */ + { 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 }, + /* Contrast */ + { 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 }, + /* H&V synchro polarity */ + { 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* ?default */ + { 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* DAC scale */ + { 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* ?default */ + { 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 }, + /* Validate Settings */ + { 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 }, +}; + +static const __u8 initPas202[] = { + 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a, + 0x28, 0x1e, 0x20, 0x89, 0x20, +}; + +/* "Known" PAS202BCB registers: + 0x02 clock divider + 0x04 Variable framerate bits 6-11 (*) + 0x05 Var framerate bits 0-5, one must leave the 2 msb's at 0 !! + 0x07 Blue Gain + 0x08 Green Gain + 0x09 Red Gain + 0x0b offset sign bit (bit0 1 > negative offset) + 0x0c offset + 0x0e Unknown image is slightly brighter when bit 0 is 0, if reg0f is 0 too, + leave at 1 otherwise we get a jump in our exposure control + 0x0f Exposure 0-255, 0 = use full frame time, 255 = no exposure at all + 0x10 Master gain 0 - 31 + 0x11 write 1 to apply changes + (*) The variable framerate control must never be set lower then 500 + which sets the framerate at 30 / reg02, otherwise vsync is lost. +*/ +static const __u8 pas202_sensor_init[][8] = { + /* Set the clock divider to 4 -> 30 / 4 = 7.5 fps, we would like + to set it lower, but for some reason the bridge starts missing + vsync's then */ + {0xa0, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10}, + {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10}, + {0xd0, 0x40, 0x0c, 0x00, 0x0c, 0x01, 0x32, 0x10}, + {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10}, + {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10}, +}; + +static const __u8 initTas5110c[] = { + 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x45, 0x09, 0x0a, + 0x16, 0x12, 0x60, 0x86, 0x2b, +}; +/* Same as above, except a different hstart */ +static const __u8 initTas5110d[] = { + 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x41, 0x09, 0x0a, + 0x16, 0x12, 0x60, 0x86, 0x2b, +}; +/* tas5110c is 3 wire, tas5110d is 2 wire (regular i2c) */ +static const __u8 tas5110c_sensor_init[][8] = { + {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10}, + {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10}, +}; +/* Known TAS5110D registers + * reg02: gain, bit order reversed!! 0 == max gain, 255 == min gain + * reg03: bit3: vflip, bit4: ~hflip, bit7: ~gainboost (~ == inverted) + * Note: writing reg03 seems to only work when written together with 02 + */ +static const __u8 tas5110d_sensor_init[][8] = { + {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17}, /* reset */ +}; + +static const __u8 initTas5130[] = { + 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x68, 0x0c, 0x0a, + 0x28, 0x1e, 0x60, COMP, MCK_INIT, +}; +static const __u8 tas5130_sensor_init[][8] = { +/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10}, + * shutter 0x47 short exposure? */ + {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10}, + /* shutter 0x01 long exposure */ + {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}, +}; + +static const struct sensor_data sensor_data[] = { +SENS(initHv7131d, hv7131d_sensor_init, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0), +SENS(initHv7131r, hv7131r_sensor_init, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), +SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60), +SENS(initOv7630, ov7630_sensor_init, F_GAIN, 0, 0x21), +SENS(initPas106, pas106_sensor_init, F_GAIN|F_SIF, NO_FREQ, 0), +SENS(initPas202, pas202_sensor_init, F_GAIN, NO_FREQ, 0), +SENS(initTas5110c, tas5110c_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, + NO_BRIGHTNESS|NO_FREQ, 0), +SENS(initTas5110d, tas5110d_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, + NO_BRIGHTNESS|NO_FREQ, 0), +SENS(initTas5130, tas5130_sensor_init, F_GAIN, + NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), +}; + +/* get one byte in gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 value) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, + 0, /* index */ + gspca_dev->usb_buf, 1, + 500); +} + +static void reg_w(struct gspca_dev *gspca_dev, + __u16 value, + const __u8 *buffer, + int len) +{ +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow"); + return; + } +#endif + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, + 0, /* index */ + gspca_dev->usb_buf, len, + 500); +} + +static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer) +{ + int retry = 60; + + /* is i2c ready */ + reg_w(gspca_dev, 0x08, buffer, 8); + while (retry--) { + msleep(10); + reg_r(gspca_dev, 0x08); + if (gspca_dev->usb_buf[0] & 0x04) { + if (gspca_dev->usb_buf[0] & 0x08) + return -1; + return 0; + } + } + return -1; +} + +static void i2c_w_vector(struct gspca_dev *gspca_dev, + const __u8 buffer[][8], int len) +{ + for (;;) { + reg_w(gspca_dev, 0x08, *buffer, 8); + len -= 8; + if (len <= 0) + break; + buffer++; + } +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { + case SENSOR_OV6650: + case SENSOR_OV7630: { + __u8 i2cOV[] = + {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}; + + /* change reg 0x06 */ + i2cOV[1] = sensor_data[sd->sensor].sensor_addr; + i2cOV[3] = sd->ctrls[BRIGHTNESS].val; + if (i2c_w(gspca_dev, i2cOV) < 0) + goto err; + break; + } + case SENSOR_PAS106: + case SENSOR_PAS202: { + __u8 i2cpbright[] = + {0xb0, 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x16}; + __u8 i2cpdoit[] = + {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16}; + + /* PAS106 uses reg 7 and 8 instead of b and c */ + if (sd->sensor == SENSOR_PAS106) { + i2cpbright[2] = 7; + i2cpdoit[2] = 0x13; + } + + if (sd->ctrls[BRIGHTNESS].val < 127) { + /* change reg 0x0b, signreg */ + i2cpbright[3] = 0x01; + /* set reg 0x0c, offset */ + i2cpbright[4] = 127 - sd->ctrls[BRIGHTNESS].val; + } else + i2cpbright[4] = sd->ctrls[BRIGHTNESS].val - 127; + + if (i2c_w(gspca_dev, i2cpbright) < 0) + goto err; + if (i2c_w(gspca_dev, i2cpdoit) < 0) + goto err; + break; + } + } + return; +err: + PDEBUG(D_ERR, "i2c error brightness"); +} + +static void setsensorgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 gain = sd->ctrls[GAIN].val; + + switch (sd->sensor) { + case SENSOR_HV7131D: { + __u8 i2c[] = + {0xc0, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x17}; + + i2c[3] = 0x3f - (gain / 4); + i2c[4] = 0x3f - (gain / 4); + i2c[5] = 0x3f - (gain / 4); + + if (i2c_w(gspca_dev, i2c) < 0) + goto err; + break; + } + case SENSOR_TAS5110C: + case SENSOR_TAS5130CXX: { + __u8 i2c[] = + {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}; + + i2c[4] = 255 - gain; + if (i2c_w(gspca_dev, i2c) < 0) + goto err; + break; + } + case SENSOR_TAS5110D: { + __u8 i2c[] = { + 0xb0, 0x61, 0x02, 0x00, 0x10, 0x00, 0x00, 0x17 }; + gain = 255 - gain; + /* The bits in the register are the wrong way around!! */ + i2c[3] |= (gain & 0x80) >> 7; + i2c[3] |= (gain & 0x40) >> 5; + i2c[3] |= (gain & 0x20) >> 3; + i2c[3] |= (gain & 0x10) >> 1; + i2c[3] |= (gain & 0x08) << 1; + i2c[3] |= (gain & 0x04) << 3; + i2c[3] |= (gain & 0x02) << 5; + i2c[3] |= (gain & 0x01) << 7; + if (i2c_w(gspca_dev, i2c) < 0) + goto err; + break; + } + + case SENSOR_OV6650: + gain >>= 1; + /* fall thru */ + case SENSOR_OV7630: { + __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; + + i2c[1] = sensor_data[sd->sensor].sensor_addr; + i2c[3] = gain >> 2; + if (i2c_w(gspca_dev, i2c) < 0) + goto err; + break; + } + case SENSOR_PAS106: + case SENSOR_PAS202: { + __u8 i2cpgain[] = + {0xa0, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15}; + __u8 i2cpcolorgain[] = + {0xc0, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x15}; + __u8 i2cpdoit[] = + {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16}; + + /* PAS106 uses different regs (and has split green gains) */ + if (sd->sensor == SENSOR_PAS106) { + i2cpgain[2] = 0x0e; + i2cpcolorgain[0] = 0xd0; + i2cpcolorgain[2] = 0x09; + i2cpdoit[2] = 0x13; + } + + i2cpgain[3] = gain >> 3; + i2cpcolorgain[3] = gain >> 4; + i2cpcolorgain[4] = gain >> 4; + i2cpcolorgain[5] = gain >> 4; + i2cpcolorgain[6] = gain >> 4; + + if (i2c_w(gspca_dev, i2cpgain) < 0) + goto err; + if (i2c_w(gspca_dev, i2cpcolorgain) < 0) + goto err; + if (i2c_w(gspca_dev, i2cpdoit) < 0) + goto err; + break; + } + } + return; +err: + PDEBUG(D_ERR, "i2c error gain"); +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 gain; + __u8 buf[3] = { 0, 0, 0 }; + + if (sensor_data[sd->sensor].flags & F_GAIN) { + /* Use the sensor gain to do the actual gain */ + setsensorgain(gspca_dev); + return; + } + + if (sd->bridge == BRIDGE_103) { + gain = sd->ctrls[GAIN].val >> 1; + buf[0] = gain; /* Red */ + buf[1] = gain; /* Green */ + buf[2] = gain; /* Blue */ + reg_w(gspca_dev, 0x05, buf, 3); + } else { + gain = sd->ctrls[GAIN].val >> 4; + buf[0] = gain << 4 | gain; /* Red and blue */ + buf[1] = gain; /* Green */ + reg_w(gspca_dev, 0x10, buf, 2); + } +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { + case SENSOR_HV7131D: { + /* Note the datasheet wrongly says line mode exposure uses reg + 0x26 and 0x27, testing has shown 0x25 + 0x26 */ + __u8 i2c[] = {0xc0, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x17}; + /* The HV7131D's exposure goes from 0 - 65535, we scale our + exposure of 0-1023 to 0-6138. There are 2 reasons for this: + 1) This puts our exposure knee of 200 at approx the point + where the framerate starts dropping + 2) At 6138 the framerate has already dropped to 2 fps, + going any lower makes little sense */ + u16 reg = sd->ctrls[EXPOSURE].val * 6; + + i2c[3] = reg >> 8; + i2c[4] = reg & 0xff; + if (i2c_w(gspca_dev, i2c) != 0) + goto err; + break; + } + case SENSOR_TAS5110C: + case SENSOR_TAS5110D: { + /* register 19's high nibble contains the sn9c10x clock divider + The high nibble configures the no fps according to the + formula: 60 / high_nibble. With a maximum of 30 fps */ + u8 reg = sd->ctrls[EXPOSURE].val; + + reg = (reg << 4) | 0x0b; + reg_w(gspca_dev, 0x19, ®, 1); + break; + } + case SENSOR_OV6650: + case SENSOR_OV7630: { + /* The ov6650 / ov7630 have 2 registers which both influence + exposure, register 11, whose low nibble sets the nr off fps + according to: fps = 30 / (low_nibble + 1) + + The fps configures the maximum exposure setting, but it is + possible to use less exposure then what the fps maximum + allows by setting register 10. register 10 configures the + actual exposure as quotient of the full exposure, with 0 + being no exposure at all (not very useful) and reg10_max + being max exposure possible at that framerate. + + The code maps our 0 - 510 ms exposure ctrl to these 2 + registers, trying to keep fps as high as possible. + */ + __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}; + int reg10, reg11, reg10_max; + + /* ov6645 datasheet says reg10_max is 9a, but that uses + tline * 2 * reg10 as formula for calculating texpo, the + ov6650 probably uses the same formula as the 7730 which uses + tline * 4 * reg10, which explains why the reg10max we've + found experimentally for the ov6650 is exactly half that of + the ov6645. The ov7630 datasheet says the max is 0x41. */ + if (sd->sensor == SENSOR_OV6650) { + reg10_max = 0x4d; + i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */ + } else + reg10_max = 0x41; + + reg11 = (15 * sd->ctrls[EXPOSURE].val + 999) / 1000; + if (reg11 < 1) + reg11 = 1; + else if (reg11 > 16) + reg11 = 16; + + /* In 640x480, if the reg11 has less than 4, the image is + unstable (the bridge goes into a higher compression mode + which we have not reverse engineered yet). */ + if (gspca_dev->width == 640 && reg11 < 4) + reg11 = 4; + + /* frame exposure time in ms = 1000 * reg11 / 30 -> + reg10 = (sd->ctrls[EXPOSURE].val / 2) * reg10_max + / (1000 * reg11 / 30) */ + reg10 = (sd->ctrls[EXPOSURE].val * 15 * reg10_max) + / (1000 * reg11); + + /* Don't allow this to get below 10 when using autogain, the + steps become very large (relatively) when below 10 causing + the image to oscilate from much too dark, to much too bright + and back again. */ + if (sd->ctrls[AUTOGAIN].val && reg10 < 10) + reg10 = 10; + else if (reg10 > reg10_max) + reg10 = reg10_max; + + /* Write reg 10 and reg11 low nibble */ + i2c[1] = sensor_data[sd->sensor].sensor_addr; + i2c[3] = reg10; + i2c[4] |= reg11 - 1; + + /* If register 11 didn't change, don't change it */ + if (sd->reg11 == reg11) + i2c[0] = 0xa0; + + if (i2c_w(gspca_dev, i2c) == 0) + sd->reg11 = reg11; + else + goto err; + break; + } + case SENSOR_PAS202: { + __u8 i2cpframerate[] = + {0xb0, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x16}; + __u8 i2cpexpo[] = + {0xa0, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x16}; + const __u8 i2cpdoit[] = + {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16}; + int framerate_ctrl; + + /* The exposure knee for the autogain algorithm is 200 + (100 ms / 10 fps on other sensors), for values below this + use the control for setting the partial frame expose time, + above that use variable framerate. This way we run at max + framerate (640x480@7.5 fps, 320x240@10fps) until the knee + is reached. Using the variable framerate control above 200 + is better then playing around with both clockdiv + partial + frame exposure times (like we are doing with the ov chips), + as that sometimes leads to jumps in the exposure control, + which are bad for auto exposure. */ + if (sd->ctrls[EXPOSURE].val < 200) { + i2cpexpo[3] = 255 - (sd->ctrls[EXPOSURE].val * 255) + / 200; + framerate_ctrl = 500; + } else { + /* The PAS202's exposure control goes from 0 - 4095, + but anything below 500 causes vsync issues, so scale + our 200-1023 to 500-4095 */ + framerate_ctrl = (sd->ctrls[EXPOSURE].val - 200) + * 1000 / 229 + 500; + } + + i2cpframerate[3] = framerate_ctrl >> 6; + i2cpframerate[4] = framerate_ctrl & 0x3f; + if (i2c_w(gspca_dev, i2cpframerate) < 0) + goto err; + if (i2c_w(gspca_dev, i2cpexpo) < 0) + goto err; + if (i2c_w(gspca_dev, i2cpdoit) < 0) + goto err; + break; + } + case SENSOR_PAS106: { + __u8 i2cpframerate[] = + {0xb1, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x14}; + __u8 i2cpexpo[] = + {0xa1, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x14}; + const __u8 i2cpdoit[] = + {0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14}; + int framerate_ctrl; + + /* For values below 150 use partial frame exposure, above + that use framerate ctrl */ + if (sd->ctrls[EXPOSURE].val < 150) { + i2cpexpo[3] = 150 - sd->ctrls[EXPOSURE].val; + framerate_ctrl = 300; + } else { + /* The PAS106's exposure control goes from 0 - 4095, + but anything below 300 causes vsync issues, so scale + our 150-1023 to 300-4095 */ + framerate_ctrl = (sd->ctrls[EXPOSURE].val - 150) + * 1000 / 230 + 300; + } + + i2cpframerate[3] = framerate_ctrl >> 4; + i2cpframerate[4] = framerate_ctrl & 0x0f; + if (i2c_w(gspca_dev, i2cpframerate) < 0) + goto err; + if (i2c_w(gspca_dev, i2cpexpo) < 0) + goto err; + if (i2c_w(gspca_dev, i2cpdoit) < 0) + goto err; + break; + } + } + return; +err: + PDEBUG(D_ERR, "i2c error exposure"); +} + +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { + case SENSOR_OV6650: + case SENSOR_OV7630: { + /* Framerate adjust register for artificial light 50 hz flicker + compensation, for the ov6650 this is identical to ov6630 + 0x2b register, see ov6630 datasheet. + 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */ + __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}; + switch (sd->ctrls[FREQ].val) { + default: +/* case 0: * no filter*/ +/* case 2: * 60 hz */ + i2c[3] = 0; + break; + case 1: /* 50 hz */ + i2c[3] = (sd->sensor == SENSOR_OV6650) + ? 0x4f : 0x8a; + break; + } + i2c[1] = sensor_data[sd->sensor].sensor_addr; + if (i2c_w(gspca_dev, i2c) < 0) + PDEBUG(D_ERR, "i2c error setfreq"); + break; + } + } +} + +#include "autogain_functions.h" + +static void do_autogain(struct gspca_dev *gspca_dev) +{ + int deadzone, desired_avg_lum, result; + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum = atomic_read(&sd->avg_lum); + + if ((gspca_dev->ctrl_dis & (1 << AUTOGAIN)) || + avg_lum == -1 || !sd->ctrls[AUTOGAIN].val) + return; + + if (sd->autogain_ignore_frames > 0) { + sd->autogain_ignore_frames--; + return; + } + + /* SIF / VGA sensors have a different autoexposure area and thus + different avg_lum values for the same picture brightness */ + if (sensor_data[sd->sensor].flags & F_SIF) { + deadzone = 500; + /* SIF sensors tend to overexpose, so keep this small */ + desired_avg_lum = 5000; + } else { + deadzone = 1500; + desired_avg_lum = 13000; + } + + if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) + result = coarse_grained_expo_autogain(gspca_dev, avg_lum, + sd->ctrls[BRIGHTNESS].val + * desired_avg_lum / 127, + deadzone); + else + result = auto_gain_n_exposure(gspca_dev, avg_lum, + sd->ctrls[BRIGHTNESS].val + * desired_avg_lum / 127, + deadzone, GAIN_KNEE, EXPOSURE_KNEE); + + if (result) { + PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d", + (int) sd->ctrls[GAIN].val, + (int) sd->ctrls[EXPOSURE].val); + sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + reg_r(gspca_dev, 0x00); + if (gspca_dev->usb_buf[0] != 0x10) + return -ENODEV; + + /* copy the webcam info from the device id */ + sd->sensor = id->driver_info >> 8; + sd->bridge = id->driver_info & 0xff; + + gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis; +#if AUTOGAIN_DEF + if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN))) + gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); +#endif + + cam = &gspca_dev->cam; + cam->ctrls = sd->ctrls; + if (!(sensor_data[sd->sensor].flags & F_SIF)) { + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + } else { + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + } + cam->npkt = 36; /* 36 packets per ISOC message */ + + if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) { + sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN; + sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX; + sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF; + } + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + const __u8 stop = 0x09; /* Disable stream turn of LED */ + + reg_w(gspca_dev, 0x01, &stop, 1); + + return 0; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + int i, mode; + __u8 regs[0x31]; + + mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07; + /* Copy registers 0x01 - 0x19 from the template */ + memcpy(®s[0x01], sensor_data[sd->sensor].bridge_init, 0x19); + /* Set the mode */ + regs[0x18] |= mode << 4; + + /* Set bridge gain to 1.0 */ + if (sd->bridge == BRIDGE_103) { + regs[0x05] = 0x20; /* Red */ + regs[0x06] = 0x20; /* Green */ + regs[0x07] = 0x20; /* Blue */ + } else { + regs[0x10] = 0x00; /* Red and blue */ + regs[0x11] = 0x00; /* Green */ + } + + /* Setup pixel numbers and auto exposure window */ + if (sensor_data[sd->sensor].flags & F_SIF) { + regs[0x1a] = 0x14; /* HO_SIZE 640, makes no sense */ + regs[0x1b] = 0x0a; /* VO_SIZE 320, makes no sense */ + regs[0x1c] = 0x02; /* AE H-start 64 */ + regs[0x1d] = 0x02; /* AE V-start 64 */ + regs[0x1e] = 0x09; /* AE H-end 288 */ + regs[0x1f] = 0x07; /* AE V-end 224 */ + } else { + regs[0x1a] = 0x1d; /* HO_SIZE 960, makes no sense */ + regs[0x1b] = 0x10; /* VO_SIZE 512, makes no sense */ + regs[0x1c] = 0x05; /* AE H-start 160 */ + regs[0x1d] = 0x03; /* AE V-start 96 */ + regs[0x1e] = 0x0f; /* AE H-end 480 */ + regs[0x1f] = 0x0c; /* AE V-end 384 */ + } + + /* Setup the gamma table (only used with the sn9c103 bridge) */ + for (i = 0; i < 16; i++) + regs[0x20 + i] = i * 16; + regs[0x20 + i] = 255; + + /* Special cases where some regs depend on mode or bridge */ + switch (sd->sensor) { + case SENSOR_TAS5130CXX: + /* FIXME / TESTME + probably not mode specific at all most likely the upper + nibble of 0x19 is exposure (clock divider) just as with + the tas5110, we need someone to test this. */ + regs[0x19] = mode ? 0x23 : 0x43; + break; + case SENSOR_OV7630: + /* FIXME / TESTME for some reason with the 101/102 bridge the + clock is set to 12 Mhz (reg1 == 0x04), rather then 24. + Also the hstart needs to go from 1 to 2 when using a 103, + which is likely related. This does not seem right. */ + if (sd->bridge == BRIDGE_103) { + regs[0x01] = 0x44; /* Select 24 Mhz clock */ + regs[0x12] = 0x02; /* Set hstart to 2 */ + } + } + /* Disable compression when the raw bayer format has been selected */ + if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) + regs[0x18] &= ~0x80; + + /* Vga mode emulation on SIF sensor? */ + if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) { + regs[0x12] += 16; /* hstart adjust */ + regs[0x13] += 24; /* vstart adjust */ + regs[0x15] = 320 / 16; /* hsize */ + regs[0x16] = 240 / 16; /* vsize */ + } + + /* reg 0x01 bit 2 video transfert on */ + reg_w(gspca_dev, 0x01, ®s[0x01], 1); + /* reg 0x17 SensorClk enable inv Clk 0x60 */ + reg_w(gspca_dev, 0x17, ®s[0x17], 1); + /* Set the registers from the template */ + reg_w(gspca_dev, 0x01, ®s[0x01], + (sd->bridge == BRIDGE_103) ? 0x30 : 0x1f); + + /* Init the sensor */ + i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init, + sensor_data[sd->sensor].sensor_init_size); + + /* Mode / bridge specific sensor setup */ + switch (sd->sensor) { + case SENSOR_PAS202: { + const __u8 i2cpclockdiv[] = + {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10}; + /* clockdiv from 4 to 3 (7.5 -> 10 fps) when in low res mode */ + if (mode) + i2c_w(gspca_dev, i2cpclockdiv); + break; + } + case SENSOR_OV7630: + /* FIXME / TESTME We should be able to handle this identical + for the 101/102 and the 103 case */ + if (sd->bridge == BRIDGE_103) { + const __u8 i2c[] = { 0xa0, 0x21, 0x13, + 0x80, 0x00, 0x00, 0x00, 0x10 }; + i2c_w(gspca_dev, i2c); + } + break; + } + /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */ + reg_w(gspca_dev, 0x15, ®s[0x15], 2); + /* compression register */ + reg_w(gspca_dev, 0x18, ®s[0x18], 1); + /* H_start */ + reg_w(gspca_dev, 0x12, ®s[0x12], 1); + /* V_START */ + reg_w(gspca_dev, 0x13, ®s[0x13], 1); + /* reset 0x17 SensorClk enable inv Clk 0x60 */ + /*fixme: ov7630 [17]=68 8f (+20 if 102)*/ + reg_w(gspca_dev, 0x17, ®s[0x17], 1); + /*MCKSIZE ->3 */ /*fixme: not ov7630*/ + reg_w(gspca_dev, 0x19, ®s[0x19], 1); + /* AE_STRX AE_STRY AE_ENDX AE_ENDY */ + reg_w(gspca_dev, 0x1c, ®s[0x1c], 4); + /* Enable video transfert */ + reg_w(gspca_dev, 0x01, ®s[0x01], 1); + /* Compression */ + reg_w(gspca_dev, 0x18, ®s[0x18], 2); + msleep(20); + + sd->reg11 = -1; + + setgain(gspca_dev); + setbrightness(gspca_dev); + setexposure(gspca_dev); + setfreq(gspca_dev); + + sd->frames_to_drop = 0; + sd->autogain_ignore_frames = 0; + sd->exp_too_high_cnt = 0; + sd->exp_too_low_cnt = 0; + atomic_set(&sd->avg_lum, -1); + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + sd_init(gspca_dev); +} + +static u8* find_sof(struct gspca_dev *gspca_dev, u8 *data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, header_size = (sd->bridge == BRIDGE_103) ? 18 : 12; + + /* frames start with: + * ff ff 00 c4 c4 96 synchro + * 00 (unknown) + * xx (frame sequence / size / compression) + * (xx) (idem - extra byte for sn9c103) + * ll mm brightness sum inside auto exposure + * ll mm brightness sum outside auto exposure + * (xx xx xx xx xx) audio values for snc103 + */ + for (i = 0; i < len; i++) { + switch (sd->header_read) { + case 0: + if (data[i] == 0xff) + sd->header_read++; + break; + case 1: + if (data[i] == 0xff) + sd->header_read++; + else + sd->header_read = 0; + break; + case 2: + if (data[i] == 0x00) + sd->header_read++; + else if (data[i] != 0xff) + sd->header_read = 0; + break; + case 3: + if (data[i] == 0xc4) + sd->header_read++; + else if (data[i] == 0xff) + sd->header_read = 1; + else + sd->header_read = 0; + break; + case 4: + if (data[i] == 0xc4) + sd->header_read++; + else if (data[i] == 0xff) + sd->header_read = 1; + else + sd->header_read = 0; + break; + case 5: + if (data[i] == 0x96) + sd->header_read++; + else if (data[i] == 0xff) + sd->header_read = 1; + else + sd->header_read = 0; + break; + default: + sd->header[sd->header_read - 6] = data[i]; + sd->header_read++; + if (sd->header_read == header_size) { + sd->header_read = 0; + return data + i + 1; + } + } + } + return NULL; +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + int fr_h_sz = 0, lum_offset = 0, len_after_sof = 0; + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + u8 *sof; + + sof = find_sof(gspca_dev, data, len); + if (sof) { + if (sd->bridge == BRIDGE_103) { + fr_h_sz = 18; + lum_offset = 3; + } else { + fr_h_sz = 12; + lum_offset = 2; + } + + len_after_sof = len - (sof - data); + len = (sof - data) - fr_h_sz; + if (len < 0) + len = 0; + } + + if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { + /* In raw mode we sometimes get some garbage after the frame + ignore this */ + int used; + int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage; + + used = gspca_dev->image_len; + if (used + len > size) + len = size - used; + } + + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + + if (sof) { + int lum = sd->header[lum_offset] + + (sd->header[lum_offset + 1] << 8); + + /* When exposure changes midway a frame we + get a lum of 0 in this case drop 2 frames + as the frames directly after an exposure + change have an unstable image. Sometimes lum + *really* is 0 (cam used in low light with + low exposure setting), so do not drop frames + if the previous lum was 0 too. */ + if (lum == 0 && sd->prev_avg_lum != 0) { + lum = -1; + sd->frames_to_drop = 2; + sd->prev_avg_lum = 0; + } else + sd->prev_avg_lum = lum; + atomic_set(&sd->avg_lum, lum); + + if (sd->frames_to_drop) + sd->frames_to_drop--; + else + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + + gspca_frame_add(gspca_dev, FIRST_PACKET, sof, len_after_sof); + } +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[AUTOGAIN].val = val; + sd->exp_too_high_cnt = 0; + sd->exp_too_low_cnt = 0; + + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + if (sd->ctrls[AUTOGAIN].val + && !(sensor_data[sd->sensor].flags & F_COARSE_EXPO)) { + sd->ctrls[EXPOSURE].val = sd->ctrls[EXPOSURE].def; + sd->ctrls[GAIN].val = sd->ctrls[GAIN].def; + if (gspca_dev->streaming) { + sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; + setexposure(gspca_dev); + setgain(gspca_dev); + } + } + + if (sd->ctrls[AUTOGAIN].val) + gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); + else + gspca_dev->ctrl_inac = 0; + + return 0; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "NoFliker"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet data */ + int len) /* interrupt packet length */ +{ + int ret = -EINVAL; + + if (len == 1 && data[0] == 1) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); + input_sync(gspca_dev->input_dev); + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + ret = 0; + } + + return ret; +} +#endif + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, + .dq_callback = do_autogain, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +#endif +}; + +/* -- module initialisation -- */ +#define SB(sensor, bridge) \ + .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge + + +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110C, 102)}, /* TAS5110C1B */ + {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110C, 101)}, /* TAS5110C1B */ + {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110D, 101)}, /* TAS5110D */ + {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)}, + {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)}, + {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)}, + {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)}, + {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, +#endif + {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)}, + {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, + {USB_DEVICE(0x0c45, 0x602a), SB(HV7131D, 102)}, + /* {USB_DEVICE(0x0c45, 0x602b), SB(MI0343, 102)}, */ + {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, + {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)}, + {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)}, + /* {USB_DEVICE(0x0c45, 0x6030), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */ + /* {USB_DEVICE(0x0c45, 0x6082), SB(MI03XX, 103)}, */ /* MI0343 MI0360 */ + {USB_DEVICE(0x0c45, 0x6083), SB(HV7131D, 103)}, + {USB_DEVICE(0x0c45, 0x608c), SB(HV7131R, 103)}, + /* {USB_DEVICE(0x0c45, 0x608e), SB(CISVF10, 103)}, */ + {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)}, + {USB_DEVICE(0x0c45, 0x60a8), SB(PAS106, 103)}, + {USB_DEVICE(0x0c45, 0x60aa), SB(TAS5130CXX, 103)}, + {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)}, + {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sonixj.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sonixj.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sonixj.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sonixj.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,3115 @@ +/* + * Sonix sn9c102p sn9c105 sn9c120 (jpeg) subdriver + * + * Copyright (C) 2009-2010 Jean-François Moine + * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "sonixj" + +#include +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Jean-François Moine "); +MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* controls */ +enum e_ctrl { + BRIGHTNESS, + CONTRAST, + COLORS, + BLUE, + RED, + GAMMA, + AUTOGAIN, + HFLIP, + VFLIP, + SHARPNESS, + ILLUM, + FREQ, + NCTRLS /* number of controls */ +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + + atomic_t avg_lum; + u32 exposure; + + struct work_struct work; + struct workqueue_struct *work_thread; + + u32 pktsz; /* (used by pkt_scan) */ + u16 npkt; + s8 nchg; + s8 short_mark; + + u8 quality; /* image quality */ +#define QUALITY_MIN 25 +#define QUALITY_MAX 90 +#define QUALITY_DEF 70 + + u8 reg01; + u8 reg17; + u8 reg18; + u8 flags; + + s8 ag_cnt; +#define AG_CNT_START 13 + + u8 bridge; +#define BRIDGE_SN9C102P 0 +#define BRIDGE_SN9C105 1 +#define BRIDGE_SN9C110 2 +#define BRIDGE_SN9C120 3 + u8 sensor; /* Type of image sensor chip */ + u8 i2c_addr; + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; +enum sensors { + SENSOR_ADCM1700, + SENSOR_GC0307, + SENSOR_HV7131R, + SENSOR_MI0360, + SENSOR_MI0360B, + SENSOR_MO4000, + SENSOR_MT9V111, + SENSOR_OM6802, + SENSOR_OV7630, + SENSOR_OV7648, + SENSOR_OV7660, + SENSOR_PO1030, + SENSOR_PO2030N, + SENSOR_SOI768, + SENSOR_SP80708, +}; + +static void qual_upd(struct work_struct *work); + +/* device flags */ +#define F_PDN_INV 0x01 /* inverse pin S_PWR_DN / sn_xxx tables */ +#define F_ILLUM 0x02 /* presence of illuminator */ + +/* sn9c1xx definitions */ +/* register 0x01 */ +#define S_PWR_DN 0x01 /* sensor power down */ +#define S_PDN_INV 0x02 /* inverse pin S_PWR_DN */ +#define V_TX_EN 0x04 /* video transfer enable */ +#define LED 0x08 /* output to pin LED */ +#define SCL_SEL_OD 0x20 /* open-drain mode */ +#define SYS_SEL_48M 0x40 /* system clock 0: 24MHz, 1: 48MHz */ +/* register 0x17 */ +#define MCK_SIZE_MASK 0x1f /* sensor master clock */ +#define SEN_CLK_EN 0x20 /* enable sensor clock */ +#define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */ + +/* V4L2 controls supported by the driver */ +static void setbrightness(struct gspca_dev *gspca_dev); +static void setcontrast(struct gspca_dev *gspca_dev); +static void setcolors(struct gspca_dev *gspca_dev); +static void setredblue(struct gspca_dev *gspca_dev); +static void setgamma(struct gspca_dev *gspca_dev); +static void setautogain(struct gspca_dev *gspca_dev); +static void sethvflip(struct gspca_dev *gspca_dev); +static void setsharpness(struct gspca_dev *gspca_dev); +static void setillum(struct gspca_dev *gspca_dev); +static void setfreq(struct gspca_dev *gspca_dev); + +static const struct ctrl sd_ctrls[NCTRLS] = { +[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x80, + }, + .set_control = setbrightness + }, +[CONTRAST] = { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, +#define CONTRAST_MAX 127 + .maximum = CONTRAST_MAX, + .step = 1, + .default_value = 63, + }, + .set_control = setcontrast + }, +[COLORS] = { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 40, + .step = 1, +#define COLORS_DEF 25 + .default_value = COLORS_DEF, + }, + .set_control = setcolors + }, +[BLUE] = { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 24, + .maximum = 40, + .step = 1, + .default_value = 32, + }, + .set_control = setredblue + }, +[RED] = { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 24, + .maximum = 40, + .step = 1, + .default_value = 32, + }, + .set_control = setredblue + }, +[GAMMA] = { + { + .id = V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = 0, + .maximum = 40, + .step = 1, +#define GAMMA_DEF 20 + .default_value = GAMMA_DEF, + }, + .set_control = setgamma + }, +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set_control = setautogain + }, +[HFLIP] = { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set_control = sethvflip + }, +[VFLIP] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set_control = sethvflip + }, +[SHARPNESS] = { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 90, + }, + .set_control = setsharpness + }, +[ILLUM] = { + { + .id = V4L2_CID_ILLUMINATORS_1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Illuminator / infrared", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set_control = setillum + }, +/* ov7630/ov7648/ov7660 only */ +[FREQ] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ + .step = 1, + .default_value = 1, + }, + .set_control = setfreq + }, +}; + +/* table of the disabled controls */ +static const __u32 ctrl_dis[] = { +[SENSOR_ADCM1700] = (1 << AUTOGAIN) | + (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +[SENSOR_GC0307] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +[SENSOR_HV7131R] = (1 << HFLIP) | + (1 << FREQ), + +[SENSOR_MI0360] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +[SENSOR_MI0360B] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +[SENSOR_MO4000] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +[SENSOR_MT9V111] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +[SENSOR_OM6802] = (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +[SENSOR_OV7630] = (1 << HFLIP), + +[SENSOR_OV7648] = (1 << HFLIP), + +[SENSOR_OV7660] = (1 << AUTOGAIN) | + (1 << HFLIP) | + (1 << VFLIP), + +[SENSOR_PO1030] = (1 << AUTOGAIN) | + (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +[SENSOR_PO2030N] = (1 << AUTOGAIN) | + (1 << FREQ), + +[SENSOR_SOI768] = (1 << AUTOGAIN) | + (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), + +[SENSOR_SP80708] = (1 << AUTOGAIN) | + (1 << HFLIP) | + (1 << VFLIP) | + (1 << FREQ), +}; + +static const struct v4l2_pix_format cif_mode[] = { + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + /* Note 3 / 8 is not large enough, not even 5 / 8 is ?! */ + .sizeimage = 640 * 480 * 3 / 4 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static const u8 sn_adcm1700[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x43, 0x60, 0x00, 0x1a, 0x00, 0x00, 0x00, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x80, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x05, 0x01, 0x05, 0x16, 0x12, 0x42, +/* reg18 reg19 reg1a reg1b */ + 0x06, 0x00, 0x00, 0x00 +}; + +static const u8 sn_gc0307[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x61, 0x62, 0x00, 0x1a, 0x00, 0x00, 0x00, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x80, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x03, 0x01, 0x08, 0x28, 0x1e, 0x02, +/* reg18 reg19 reg1a reg1b */ + 0x06, 0x00, 0x00, 0x00 +}; + +static const u8 sn_hv7131[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x03, 0x60, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, +/* reg18 reg19 reg1a reg1b */ + 0x0a, 0x00, 0x00, 0x00 +}; + +static const u8 sn_mi0360[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x63, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, +/* reg18 reg19 reg1a reg1b */ + 0x06, 0x00, 0x00, 0x00 +}; + +static const u8 sn_mi0360b[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x40, +/* reg18 reg19 reg1a reg1b */ + 0x06, 0x00, 0x00, 0x00 +}; + +static const u8 sn_mo4000[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x23, 0x60, 0x00, 0x1a, 0x00, 0x20, 0x18, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, +/* reg18 reg19 reg1a reg1b */ + 0x08, 0x00, 0x00, 0x00 +}; + +static const u8 sn_mt9v111[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x02, 0x1c, 0x28, 0x1e, 0x40, +/* reg18 reg19 reg1a reg1b */ + 0x06, 0x00, 0x00, 0x00 +}; + +static const u8 sn_om6802[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x23, 0x72, 0x00, 0x1a, 0x20, 0x20, 0x19, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x51, 0x01, 0x00, 0x28, 0x1e, 0x40, +/* reg18 reg19 reg1a reg1b */ + 0x05, 0x00, 0x00, 0x00 +}; + +static const u8 sn_ov7630[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x21, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x04, 0x01, 0x0a, 0x28, 0x1e, 0xc2, +/* reg18 reg19 reg1a reg1b */ + 0x0b, 0x00, 0x00, 0x00 +}; + +static const u8 sn_ov7648[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x63, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x01, 0x00, 0x28, 0x1e, 0x00, +/* reg18 reg19 reg1a reg1b */ + 0x0b, 0x00, 0x00, 0x00 +}; + +static const u8 sn_ov7660[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, +/* reg18 reg19 reg1a reg1b */ + 0x07, 0x00, 0x00, 0x00 +}; + +static const u8 sn_po1030[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1e, 0x00, +/* reg18 reg19 reg1a reg1b */ + 0x07, 0x00, 0x00, 0x00 +}; + +static const u8 sn_po2030n[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x63, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x01, 0x14, 0x28, 0x1e, 0x00, +/* reg18 reg19 reg1a reg1b */ + 0x07, 0x00, 0x00, 0x00 +}; + +static const u8 sn_soi768[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x21, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x01, 0x08, 0x28, 0x1e, 0x00, +/* reg18 reg19 reg1a reg1b */ + 0x07, 0x00, 0x00, 0x00 +}; + +static const u8 sn_sp80708[0x1c] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x63, 0x60, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x03, 0x04, 0x28, 0x1e, 0x00, +/* reg18 reg19 reg1a reg1b */ + 0x07, 0x00, 0x00, 0x00 +}; + +/* sequence specific to the sensors - !! index = SENSOR_xxx */ +static const u8 *sn_tb[] = { +[SENSOR_ADCM1700] = sn_adcm1700, +[SENSOR_GC0307] = sn_gc0307, +[SENSOR_HV7131R] = sn_hv7131, +[SENSOR_MI0360] = sn_mi0360, +[SENSOR_MI0360B] = sn_mi0360b, +[SENSOR_MO4000] = sn_mo4000, +[SENSOR_MT9V111] = sn_mt9v111, +[SENSOR_OM6802] = sn_om6802, +[SENSOR_OV7630] = sn_ov7630, +[SENSOR_OV7648] = sn_ov7648, +[SENSOR_OV7660] = sn_ov7660, +[SENSOR_PO1030] = sn_po1030, +[SENSOR_PO2030N] = sn_po2030n, +[SENSOR_SOI768] = sn_soi768, +[SENSOR_SP80708] = sn_sp80708, +}; + +/* default gamma table */ +static const u8 gamma_def[17] = { + 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99, + 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff +}; +/* gamma for sensor ADCM1700 */ +static const u8 gamma_spec_0[17] = { + 0x0f, 0x39, 0x5a, 0x74, 0x86, 0x95, 0xa6, 0xb4, + 0xbd, 0xc4, 0xcc, 0xd4, 0xd5, 0xde, 0xe4, 0xed, 0xf5 +}; +/* gamma for sensors HV7131R and MT9V111 */ +static const u8 gamma_spec_1[17] = { + 0x08, 0x3a, 0x52, 0x65, 0x75, 0x83, 0x91, 0x9d, + 0xa9, 0xb4, 0xbe, 0xc8, 0xd2, 0xdb, 0xe4, 0xed, 0xf5 +}; +/* gamma for sensor GC0307 */ +static const u8 gamma_spec_2[17] = { + 0x14, 0x37, 0x50, 0x6a, 0x7c, 0x8d, 0x9d, 0xab, + 0xb5, 0xbf, 0xc2, 0xcb, 0xd1, 0xd6, 0xdb, 0xe1, 0xeb +}; +/* gamma for sensor SP80708 */ +static const u8 gamma_spec_3[17] = { + 0x0a, 0x2d, 0x4e, 0x68, 0x7d, 0x8f, 0x9f, 0xab, + 0xb7, 0xc2, 0xcc, 0xd3, 0xd8, 0xde, 0xe2, 0xe5, 0xe6 +}; + +/* color matrix and offsets */ +static const u8 reg84[] = { + 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, /* YR YG YB gains */ + 0xe8, 0x0f, 0xda, 0x0f, 0x40, 0x00, /* UR UG UB */ + 0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f, /* VR VG VB */ + 0x00, 0x00, 0x00 /* YUV offsets */ +}; + +#define DELAY 0xdd + +static const u8 adcm1700_sensor_init[][8] = { + {0xa0, 0x51, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x04, 0x08, 0x00, 0x00, 0x00, 0x10}, /* reset */ + {DELAY, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xb0, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xb0, 0x51, 0x0c, 0xe0, 0x2e, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x10, 0x02, 0x02, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x14, 0x0e, 0x0e, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x1c, 0x00, 0x80, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x20, 0x01, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xb0, 0x51, 0x04, 0x04, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xb0, 0x51, 0x04, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x14, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 adcm1700_sensor_param1[][8] = { + {0xb0, 0x51, 0x26, 0xf9, 0x01, 0x00, 0x00, 0x10}, /* exposure? */ + {0xd0, 0x51, 0x1e, 0x8e, 0x8e, 0x8e, 0x8e, 0x10}, + + {0xa0, 0x51, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x32, 0x00, 0x72, 0x00, 0x00, 0x10}, + {0xd0, 0x51, 0x1e, 0xbe, 0xd7, 0xe8, 0xbe, 0x10}, /* exposure? */ + + {0xa0, 0x51, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x51, 0x32, 0x00, 0xa2, 0x00, 0x00, 0x10}, + {} +}; +static const u8 gc0307_sensor_init[][8] = { + {0xa0, 0x21, 0x43, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x44, 0xa2, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x01, 0x6a, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x02, 0x70, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x11, 0x05, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x08, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x09, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x0a, 0xe8, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x0b, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x0c, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x0d, 0x22, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x0f, 0xb2, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x12, 0x70, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 10ms*/ + {0xa0, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x15, 0xb8, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x16, 0x13, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x17, 0x52, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x18, 0x50, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x1e, 0x0d, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x1f, 0x32, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x61, 0x90, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x63, 0x70, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x65, 0x98, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x67, 0x90, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x04, 0x96, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x45, 0x27, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x47, 0x2c, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x43, 0x47, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x44, 0xd8, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 gc0307_sensor_param1[][8] = { + {0xa0, 0x21, 0x68, 0x13, 0x00, 0x00, 0x00, 0x10}, + {0xd0, 0x21, 0x61, 0x80, 0x00, 0x80, 0x00, 0x10}, + {0xc0, 0x21, 0x65, 0x80, 0x00, 0x80, 0x00, 0x10}, + {0xc0, 0x21, 0x63, 0xa0, 0x00, 0xa6, 0x00, 0x10}, +/*param3*/ + {0xa0, 0x21, 0x01, 0x6e, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x21, 0x02, 0x88, 0x00, 0x00, 0x00, 0x10}, + {} +}; + +static const u8 hv7131r_sensor_init[][8] = { + {0xc1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10}, + {0xb1, 0x11, 0x34, 0x17, 0x7f, 0x00, 0x00, 0x10}, + {0xd1, 0x11, 0x40, 0xff, 0x7f, 0x7f, 0x7f, 0x10}, +/* {0x91, 0x11, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10}, */ + {0xd1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x11, 0x14, 0x01, 0xe2, 0x02, 0x82, 0x10}, +/* {0x91, 0x11, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, */ + + {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xc1, 0x11, 0x25, 0x00, 0x61, 0xa8, 0x00, 0x10}, + {0xa1, 0x11, 0x30, 0x22, 0x00, 0x00, 0x00, 0x10}, + {0xc1, 0x11, 0x31, 0x20, 0x2e, 0x20, 0x00, 0x10}, + {0xc1, 0x11, 0x25, 0x00, 0xc3, 0x50, 0x00, 0x10}, + {0xa1, 0x11, 0x30, 0x07, 0x00, 0x00, 0x00, 0x10}, /* gain14 */ + {0xc1, 0x11, 0x31, 0x10, 0x10, 0x10, 0x00, 0x10}, /* r g b 101a10 */ + + {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x21, 0xd0, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x23, 0x09, 0x00, 0x00, 0x00, 0x10}, + + {0xa1, 0x11, 0x01, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x21, 0xd0, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x23, 0x10, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x11, 0x01, 0x18, 0x00, 0x00, 0x00, 0x10}, + /* set sensor clock */ + {} +}; +static const u8 mi0360_sensor_init[][8] = { + {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10}, + {0xd1, 0x5d, 0x03, 0x01, 0xe2, 0x02, 0x82, 0x10}, + {0xd1, 0x5d, 0x05, 0x00, 0x09, 0x00, 0x53, 0x10}, + {0xb1, 0x5d, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10}, + {0xd1, 0x5d, 0x2f, 0xf7, 0xB0, 0x00, 0x04, 0x10}, + {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10}, + {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x40, 0x01, 0xe0, 0x00, 0xd1, 0x10}, + {0xb1, 0x5d, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10}, + {0xd1, 0x5d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x5e, 0x00, 0x00, 0xa3, 0x1d, 0x10}, + {0xb1, 0x5d, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10}, + + {0xb1, 0x5d, 0x20, 0x91, 0x01, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x2b, 0x00, 0xa0, 0x00, 0xb0, 0x10}, + {0xd1, 0x5d, 0x2d, 0x00, 0xa0, 0x00, 0xa0, 0x10}, + + {0xb1, 0x5d, 0x0a, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor clck ?2 */ + {0xb1, 0x5d, 0x06, 0x00, 0x30, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */ + + {0xd1, 0x5d, 0x2b, 0x00, 0xb9, 0x00, 0xe3, 0x10}, + {0xd1, 0x5d, 0x2d, 0x00, 0x5f, 0x00, 0xb9, 0x10}, /* 42 */ +/* {0xb1, 0x5d, 0x35, 0x00, 0x67, 0x00, 0x00, 0x10}, * gain orig */ +/* {0xb1, 0x5d, 0x35, 0x00, 0x20, 0x00, 0x00, 0x10}, * gain */ + {0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */ + {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */ + {} +}; +static const u8 mi0360b_sensor_init[][8] = { + {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, + {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 20ms*/ + {0xb1, 0x5d, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 20ms*/ + {0xd1, 0x5d, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10}, + {0xd1, 0x5d, 0x03, 0x01, 0xe2, 0x02, 0x82, 0x10}, + {0xd1, 0x5d, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10}, + {0xd1, 0x5d, 0x2f, 0xf7, 0xb0, 0x00, 0x04, 0x10}, + {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10}, + {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x40, 0x01, 0xe0, 0x00, 0xd1, 0x10}, + {0xb1, 0x5d, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10}, + {0xd1, 0x5d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x5e, 0x00, 0x00, 0xa3, 0x1d, 0x10}, + {0xb1, 0x5d, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10}, + + {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10}, + {0xd1, 0x5d, 0x2b, 0x00, 0x33, 0x00, 0xa0, 0x10}, + {0xd1, 0x5d, 0x2d, 0x00, 0xa0, 0x00, 0x33, 0x10}, + {} +}; +static const u8 mi0360b_sensor_param1[][8] = { + {0xb1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x06, 0x00, 0x53, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x05, 0x00, 0x09, 0x00, 0x00, 0x10}, + {0xb1, 0x5d, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */ + + {0xd1, 0x5d, 0x2b, 0x00, 0xd1, 0x01, 0xc9, 0x10}, + {0xd1, 0x5d, 0x2d, 0x00, 0xed, 0x00, 0xd1, 0x10}, + {0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */ + {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */ + {} +}; +static const u8 mo4000_sensor_init[][8] = { + {0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x06, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x06, 0x81, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x20, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x30, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x0f, 0x20, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 mt9v111_sensor_init[][8] = { + {0xb1, 0x5c, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, /* reset? */ + {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ + {0xb1, 0x5c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x5c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x10}, /* IFP select */ + {0xb1, 0x5c, 0x08, 0x04, 0x80, 0x00, 0x00, 0x10}, /* output fmt ctrl */ + {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, /* op mode ctrl */ + {0xb1, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10}, /* sensor select */ + {0xb1, 0x5c, 0x08, 0x00, 0x08, 0x00, 0x00, 0x10}, /* row start */ + {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10}, /* col start */ + {0xb1, 0x5c, 0x03, 0x01, 0xe7, 0x00, 0x00, 0x10}, /* window height */ + {0xb1, 0x5c, 0x04, 0x02, 0x87, 0x00, 0x00, 0x10}, /* window width */ + {0xb1, 0x5c, 0x07, 0x30, 0x02, 0x00, 0x00, 0x10}, /* output ctrl */ + {0xb1, 0x5c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10}, /* shutter delay */ + {0xb1, 0x5c, 0x12, 0x00, 0xb0, 0x00, 0x00, 0x10}, /* zoom col start */ + {0xb1, 0x5c, 0x13, 0x00, 0x7c, 0x00, 0x00, 0x10}, /* zoom row start */ + {0xb1, 0x5c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* digital zoom */ + {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, /* read mode */ + {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 mt9v111_sensor_param1[][8] = { + {0xd1, 0x5c, 0x2b, 0x00, 0x33, 0x00, 0xad, 0x10}, /* G1 and B gains */ + {0xd1, 0x5c, 0x2d, 0x00, 0xad, 0x00, 0x33, 0x10}, /* R and G2 gains */ + {0xb1, 0x5c, 0x06, 0x00, 0x40, 0x00, 0x00, 0x10}, /* vert blanking */ + {0xb1, 0x5c, 0x05, 0x00, 0x09, 0x00, 0x00, 0x10}, /* horiz blanking */ + {0xb1, 0x5c, 0x35, 0x01, 0xc0, 0x00, 0x00, 0x10}, /* global gain */ + {} +}; +static const u8 om6802_init0[2][8] = { +/*fixme: variable*/ + {0xa0, 0x34, 0x29, 0x0e, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x23, 0xb0, 0x00, 0x00, 0x00, 0x10}, +}; +static const u8 om6802_sensor_init[][8] = { + {0xa0, 0x34, 0xdf, 0x6d, 0x00, 0x00, 0x00, 0x10}, + /* factory mode */ + {0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10}, + /* output raw RGB */ + {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10}, +/* {0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */ + {0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10}, + /* auto-exposure speed (0) / white balance mode (auto RGB) */ +/* {0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10}, + * set color mode */ +/* {0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10}, + * max AGC value in AE */ +/* {0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset AGC */ +/* {0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset brightness */ +/* {0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset contrast */ +/* {0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10}, + * preset gamma */ + {0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10}, + /* luminance mode (0x4f -> AutoExpo on) */ + {0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10}, + /* preset shutter */ +/* {0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10}, + * auto frame rate */ +/* {0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */ + {0xa0, 0x34, 0x5d, 0x80, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 om6802_sensor_param1[][8] = { + {0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 ov7630_sensor_init[][8] = { + {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, +/* win: i2c_r from 00 to 80 */ + {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10}, + {0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10}, +/* HDG: 0x11 was 0x00 change to 0x01 for better exposure (15 fps instead of 30) + 0x13 was 0xc0 change to 0xc3 for auto gain and exposure */ + {0xd1, 0x21, 0x11, 0x01, 0x48, 0xc3, 0x00, 0x10}, + {0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10}, + {0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10}, + {0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10}, + {0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10}, + {0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10}, + {0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10}, + {0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10}, + {0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10}, + {0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10}, + {0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10}, + {0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 ov7630_sensor_param1[][8] = { + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, +/*fixme: + 0x12, 0x04*/ +/* {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10}, * COMN + * set by setvflip */ + {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10}, +/* */ +/* {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */ +/* {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */ +/* */ + {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10}, +/* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */ + {} +}; + +static const u8 ov7648_sensor_init[][8] = { + {0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */ + {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ + {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x03, 0xa4, 0x30, 0x88, 0x00, 0x10}, + {0xb1, 0x21, 0x11, 0x80, 0x08, 0x00, 0x00, 0x10}, + {0xc1, 0x21, 0x13, 0xa0, 0x04, 0x84, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1a, 0x02, 0xba, 0xf4, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x1f, 0x41, 0xc0, 0x80, 0x80, 0x10}, + {0xd1, 0x21, 0x23, 0xde, 0xa0, 0x80, 0x32, 0x10}, + {0xd1, 0x21, 0x27, 0xfe, 0xa0, 0x00, 0x91, 0x10}, + {0xd1, 0x21, 0x2b, 0x00, 0x88, 0x85, 0x80, 0x10}, + {0xc1, 0x21, 0x2f, 0x9c, 0x00, 0xc4, 0x00, 0x10}, + {0xd1, 0x21, 0x60, 0xa6, 0x60, 0x88, 0x12, 0x10}, + {0xd1, 0x21, 0x64, 0x88, 0x00, 0x00, 0x94, 0x10}, + {0xd1, 0x21, 0x68, 0x7a, 0x0c, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x6c, 0x11, 0x33, 0x22, 0x00, 0x10}, + {0xd1, 0x21, 0x70, 0x11, 0x00, 0x10, 0x50, 0x10}, + {0xd1, 0x21, 0x74, 0x20, 0x06, 0x00, 0xb5, 0x10}, + {0xd1, 0x21, 0x78, 0x8a, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x7c, 0x00, 0x43, 0x00, 0x00, 0x10}, + + {0xd1, 0x21, 0x21, 0x86, 0x00, 0xde, 0xa0, 0x10}, +/* {0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */ +/* {0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */ +/* {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10}, set by setfreq */ + {} +}; +static const u8 ov7648_sensor_param1[][8] = { +/* {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, * COMN + * set by setvflip */ + {0xa1, 0x21, 0x19, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10}, +/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, * GAIN - def */ +/* {0xb1, 0x21, 0x01, 0x6c, 0x6c, 0x00, 0x00, 0x10}, * B R - def: 80 */ +/*...*/ + {0xa1, 0x21, 0x11, 0x81, 0x00, 0x00, 0x00, 0x10}, /* CLKRC */ +/* {0xa1, 0x21, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x2a, 0x91, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xb1, 0x21, 0x01, 0x64, 0x84, 0x00, 0x00, 0x10}, * B R - def: 80 */ + + {} +}; + +static const u8 ov7660_sensor_init[][8] = { + {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ + {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ + {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10}, + /* Outformat = rawRGB */ + {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */ + {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10}, + /* GAIN BLUE RED VREF */ + {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10}, + /* COM 1 BAVE GEAVE AECHH */ + {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */ + {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */ + {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, + /* AECH CLKRC COM7 COM8 */ + {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */ + {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10}, + /* HSTART HSTOP VSTRT VSTOP */ + {0xa1, 0x21, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x10}, /* PSHFT */ + {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */ + {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10}, + /* BOS GBOS GROS ROS (BGGR offset) */ +/* {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10}, */ + {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, + /* AEW AEB VPT BBIAS */ + {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10}, + /* GbBIAS RSVD EXHCH EXHCL */ + {0xd1, 0x21, 0x2c, 0x80, 0x00, 0x00, 0x62, 0x10}, + /* RBIAS ADVFL ASDVFH YAVE */ + {0xc1, 0x21, 0x30, 0x08, 0x30, 0xb4, 0x00, 0x10}, + /* HSYST HSYEN HREF */ + {0xd1, 0x21, 0x33, 0x00, 0x07, 0x84, 0x00, 0x10}, /* reserved */ + {0xd1, 0x21, 0x37, 0x0c, 0x02, 0x43, 0x00, 0x10}, + /* ADC ACOM OFON TSLB */ + {0xd1, 0x21, 0x3b, 0x02, 0x6c, 0x19, 0x0e, 0x10}, + /* COM11 COM12 COM13 COM14 */ + {0xd1, 0x21, 0x3f, 0x41, 0xc1, 0x22, 0x08, 0x10}, + /* EDGE COM15 COM16 COM17 */ + {0xd1, 0x21, 0x43, 0xf0, 0x10, 0x78, 0xa8, 0x10}, /* reserved */ + {0xd1, 0x21, 0x47, 0x60, 0x80, 0x00, 0x00, 0x10}, /* reserved */ + {0xd1, 0x21, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* reserved */ + {0xd1, 0x21, 0x4f, 0x46, 0x36, 0x0f, 0x17, 0x10}, /* MTX 1 2 3 4 */ + {0xd1, 0x21, 0x53, 0x7f, 0x96, 0x40, 0x40, 0x10}, /* MTX 5 6 7 8 */ + {0xb1, 0x21, 0x57, 0x40, 0x0f, 0x00, 0x00, 0x10}, /* MTX9 MTXS */ + {0xd1, 0x21, 0x59, 0xba, 0x9a, 0x22, 0xb9, 0x10}, /* reserved */ + {0xd1, 0x21, 0x5d, 0x9b, 0x10, 0xf0, 0x05, 0x10}, /* reserved */ + {0xa1, 0x21, 0x61, 0x60, 0x00, 0x00, 0x00, 0x10}, /* reserved */ + {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10}, + /* LCC1 LCC2 LCC3 LCC4 */ + {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */ + {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10}, /* MANU */ + {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10}, + /* band gap reference [0:3] DBLV */ + {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x78, 0x34, 0x30, 0x2f, 0x2b, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x7c, 0x03, 0x07, 0x17, 0x34, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x80, 0x41, 0x4d, 0x58, 0x63, 0x10}, /* gamma curve */ + {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */ + {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */ + {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */ + {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */ +/* not in all ms-win traces*/ + {0xa1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 ov7660_sensor_param1[][8] = { + {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */ + /* bits[3..0]reserved */ + {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, + /* VREF vertical frame ctrl */ + {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* AECH 0x20 */ + {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFL */ + {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFH */ + {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, /* GAIN */ +/* {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, * BLUE */ +/****** (some exchanges in the win trace) ******/ +/*fixme:param2*/ + {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */ + {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10}, /* dummy line low */ + {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCH */ + {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCL */ +/* {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, * RED */ +/****** (some exchanges in the win trace) ******/ +/******!! startsensor KO if changed !!****/ +/*fixme: param3*/ + {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10}, + {} +}; + +static const u8 po1030_sensor_init[][8] = { +/* the sensor registers are described in m5602/m5602_po1030.h */ + {0xa1, 0x6e, 0x3f, 0x20, 0x00, 0x00, 0x00, 0x10}, /* sensor reset */ + {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */ + {0xa1, 0x6e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x04, 0x02, 0xb1, 0x02, 0x39, 0x10}, + {0xd1, 0x6e, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x0c, 0x02, 0x7f, 0x01, 0xe0, 0x10}, + {0xd1, 0x6e, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10}, + {0xd1, 0x6e, 0x16, 0x85, 0x40, 0x4a, 0x40, 0x10}, /* r/g1/b/g2 gains */ + {0xc1, 0x6e, 0x1a, 0x00, 0x80, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x1d, 0x08, 0x03, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x23, 0x00, 0xb0, 0x00, 0x94, 0x10}, + {0xd1, 0x6e, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x6e, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x2d, 0x14, 0x35, 0x61, 0x84, 0x10}, /* gamma corr */ + {0xd1, 0x6e, 0x31, 0xa2, 0xbd, 0xd8, 0xff, 0x10}, + {0xd1, 0x6e, 0x35, 0x06, 0x1e, 0x12, 0x02, 0x10}, /* color matrix */ + {0xd1, 0x6e, 0x39, 0xaa, 0x53, 0x37, 0xd5, 0x10}, + {0xa1, 0x6e, 0x3d, 0xf2, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x3e, 0x00, 0x00, 0x80, 0x03, 0x10}, + {0xd1, 0x6e, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10}, + {0xc1, 0x6e, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10}, + {0xd1, 0x6e, 0x4b, 0x02, 0xef, 0x08, 0xcd, 0x10}, + {0xd1, 0x6e, 0x4f, 0x00, 0xd0, 0x00, 0xa0, 0x10}, + {0xd1, 0x6e, 0x53, 0x01, 0xaa, 0x01, 0x40, 0x10}, + {0xd1, 0x6e, 0x5a, 0x50, 0x04, 0x30, 0x03, 0x10}, /* raw rgb bayer */ + {0xa1, 0x6e, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x5f, 0x10, 0x40, 0xff, 0x00, 0x10}, + + {0xd1, 0x6e, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xc1, 0x6e, 0x73, 0x10, 0x80, 0xeb, 0x00, 0x10}, + {} +}; +static const u8 po1030_sensor_param1[][8] = { +/* from ms-win traces - these values change with auto gain/expo/wb.. */ + {0xa1, 0x6e, 0x1e, 0x03, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x1e, 0x03, 0x00, 0x00, 0x00, 0x10}, +/* mean values */ + {0xc1, 0x6e, 0x1a, 0x02, 0xd4, 0xa4, 0x00, 0x10}, /* integlines */ + {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, /* global gain */ + {0xc1, 0x6e, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10}, /* r/g1/b gains */ + + {0xa1, 0x6e, 0x1d, 0x08, 0x00, 0x00, 0x00, 0x10}, /* control1 */ + {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, /* frameheight */ + {0xa1, 0x6e, 0x07, 0xd5, 0x00, 0x00, 0x00, 0x10}, +/* {0xc1, 0x6e, 0x16, 0x49, 0x40, 0x45, 0x00, 0x10}, */ + {} +}; + +static const u8 po2030n_sensor_init[][8] = { + {0xa1, 0x6e, 0x1e, 0x1a, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x1f, 0x99, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */ + {0xa1, 0x6e, 0x1e, 0x0a, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x1f, 0x19, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */ + {0xa1, 0x6e, 0x20, 0x44, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x05, 0x70, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x10}, + {0xd1, 0x6e, 0x0c, 0x03, 0x50, 0x01, 0xe8, 0x10}, + {0xd1, 0x6e, 0x1d, 0x20, 0x0a, 0x19, 0x44, 0x10}, + {0xd1, 0x6e, 0x21, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x25, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x29, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x35, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x39, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x41, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x45, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x49, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x4d, 0x00, 0x00, 0x00, 0xed, 0x10}, + {0xd1, 0x6e, 0x51, 0x17, 0x4a, 0x2f, 0xc0, 0x10}, + {0xd1, 0x6e, 0x55, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x59, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x61, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x69, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x71, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x79, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x85, 0x00, 0x00, 0x00, 0x08, 0x10}, + {0xd1, 0x6e, 0x89, 0x01, 0xe8, 0x00, 0x01, 0x10}, + {0xa1, 0x6e, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x21, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x25, 0x00, 0x00, 0x00, 0x01, 0x10}, + {0xd1, 0x6e, 0x29, 0xe6, 0x00, 0xbd, 0x03, 0x10}, + {0xd1, 0x6e, 0x2d, 0x41, 0x38, 0x68, 0x40, 0x10}, + {0xd1, 0x6e, 0x31, 0x2b, 0x00, 0x36, 0x00, 0x10}, + {0xd1, 0x6e, 0x35, 0x30, 0x30, 0x08, 0x00, 0x10}, + {0xd1, 0x6e, 0x39, 0x00, 0x00, 0x33, 0x06, 0x10}, + {0xb1, 0x6e, 0x3d, 0x06, 0x02, 0x00, 0x00, 0x10}, + {} +}; +static const u8 po2030n_sensor_param1[][8] = { + {0xa1, 0x6e, 0x1a, 0x01, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */ + {0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10}, +/*param2*/ + {0xa1, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10}, +/*after start*/ + {0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ + {0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10}, + {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ + {0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10}, + {} +}; + +static const u8 soi768_sensor_init[][8] = { + {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */ + {DELAY, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 96ms */ + {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x19, 0x00, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 soi768_sensor_param1[][8] = { + {0xa1, 0x21, 0x10, 0x10, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x01, 0x7f, 0x7f, 0x00, 0x00, 0x10}, +/* */ +/* {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa1, 0x21, 0x2d, 0x25, 0x00, 0x00, 0x00, 0x10}, */ + {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, +/* {0xb1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, */ + {0xa1, 0x21, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x10}, +/* the next sequence should be used for auto gain */ + {0xa1, 0x21, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10}, + /* global gain ? : 07 - change with 0x15 at the end */ + {0xa1, 0x21, 0x10, 0x3f, 0x00, 0x00, 0x00, 0x10}, /* ???? : 063f */ + {0xa1, 0x21, 0x04, 0x06, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x2d, 0x00, 0x02, 0x00, 0x00, 0x10}, + /* exposure ? : 0200 - change with 0x1e at the end */ + {} +}; + +static const u8 sp80708_sensor_init[][8] = { + {0xa1, 0x18, 0x06, 0xf9, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x09, 0x1f, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x10, 0x40, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x12, 0x53, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x15, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x19, 0x18, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x1a, 0x10, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x1c, 0x28, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x1d, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x26, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x27, 0x1e, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x28, 0x5a, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x29, 0x28, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x2a, 0x78, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x2c, 0xf7, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x2d, 0x2d, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x2e, 0xd5, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x39, 0x42, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x3a, 0x67, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x3b, 0x87, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x3c, 0xa3, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x3d, 0xb0, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x3e, 0xbc, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x3f, 0xc8, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x40, 0xd4, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x41, 0xdf, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x42, 0xea, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x43, 0xf5, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x45, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x46, 0x60, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x47, 0x50, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x48, 0x30, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x49, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x4d, 0xae, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x4e, 0x03, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x4f, 0x66, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x50, 0x1c, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x44, 0x10, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x4a, 0x30, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x51, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x52, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x53, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x54, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x55, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x56, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x57, 0xe0, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x58, 0xc0, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x59, 0xab, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x5a, 0xa0, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x5b, 0x99, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x5c, 0x90, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x5e, 0x24, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x61, 0x73, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x63, 0x42, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x64, 0x42, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x65, 0x42, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x66, 0x24, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x67, 0x24, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x68, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x2f, 0xc9, 0x00, 0x00, 0x00, 0x10}, + {} +}; +static const u8 sp80708_sensor_param1[][8] = { + {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x03, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x04, 0xa4, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x14, 0x3f, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x18, 0x5d, 0x80, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x18, 0x11, 0x40, 0x40, 0x00, 0x00, 0x10}, + {} +}; + +static const u8 (*sensor_init[])[8] = { +[SENSOR_ADCM1700] = adcm1700_sensor_init, +[SENSOR_GC0307] = gc0307_sensor_init, +[SENSOR_HV7131R] = hv7131r_sensor_init, +[SENSOR_MI0360] = mi0360_sensor_init, +[SENSOR_MI0360B] = mi0360b_sensor_init, +[SENSOR_MO4000] = mo4000_sensor_init, +[SENSOR_MT9V111] = mt9v111_sensor_init, +[SENSOR_OM6802] = om6802_sensor_init, +[SENSOR_OV7630] = ov7630_sensor_init, +[SENSOR_OV7648] = ov7648_sensor_init, +[SENSOR_OV7660] = ov7660_sensor_init, +[SENSOR_PO1030] = po1030_sensor_init, +[SENSOR_PO2030N] = po2030n_sensor_init, +[SENSOR_SOI768] = soi768_sensor_init, +[SENSOR_SP80708] = sp80708_sensor_init, +}; + +/* read bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + u16 value, int len) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_r: buffer overflow"); + return; + } +#endif + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, 0, + gspca_dev->usb_buf, len, + 500); + PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]); + if (ret < 0) { + err("reg_r err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w1(struct gspca_dev *gspca_dev, + u16 value, + u8 data) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "reg_w1 [%04x] = %02x", value, data); + gspca_dev->usb_buf[0] = data; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, + 0, + gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { + err("reg_w1 err %d", ret); + gspca_dev->usb_err = ret; + } +} +static void reg_w(struct gspca_dev *gspca_dev, + u16 value, + const u8 *buffer, + int len) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..", + value, buffer[0], buffer[1]); +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_w: buffer overflow"); + return; + } +#endif + memcpy(gspca_dev->usb_buf, buffer, len); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, 0, + gspca_dev->usb_buf, len, + 500); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* I2C write 1 byte */ +static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "i2c_w1 [%02x] = %02x", reg, val); + switch (sd->sensor) { + case SENSOR_ADCM1700: + case SENSOR_OM6802: + case SENSOR_GC0307: /* i2c command = a0 (100 kHz) */ + gspca_dev->usb_buf[0] = 0x80 | (2 << 4); + break; + default: /* i2c command = a1 (400 kHz) */ + gspca_dev->usb_buf[0] = 0x81 | (2 << 4); + break; + } + gspca_dev->usb_buf[1] = sd->i2c_addr; + gspca_dev->usb_buf[2] = reg; + gspca_dev->usb_buf[3] = val; + gspca_dev->usb_buf[4] = 0; + gspca_dev->usb_buf[5] = 0; + gspca_dev->usb_buf[6] = 0; + gspca_dev->usb_buf[7] = 0x10; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x08, /* value = i2c */ + 0, + gspca_dev->usb_buf, 8, + 500); + if (ret < 0) { + err("i2c_w1 err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* I2C write 8 bytes */ +static void i2c_w8(struct gspca_dev *gspca_dev, + const u8 *buffer) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "i2c_w8 [%02x] = %02x ..", + buffer[2], buffer[3]); + memcpy(gspca_dev->usb_buf, buffer, 8); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x08, 0, /* value, index */ + gspca_dev->usb_buf, 8, + 500); + msleep(2); + if (ret < 0) { + err("i2c_w8 err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* sensor read 'len' (1..5) bytes in gspca_dev->usb_buf */ +static void i2c_r(struct gspca_dev *gspca_dev, u8 reg, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 mode[8]; + + switch (sd->sensor) { + case SENSOR_ADCM1700: + case SENSOR_OM6802: + case SENSOR_GC0307: /* i2c command = a0 (100 kHz) */ + mode[0] = 0x80 | 0x10; + break; + default: /* i2c command = 91 (400 kHz) */ + mode[0] = 0x81 | 0x10; + break; + } + mode[1] = sd->i2c_addr; + mode[2] = reg; + mode[3] = 0; + mode[4] = 0; + mode[5] = 0; + mode[6] = 0; + mode[7] = 0x10; + i2c_w8(gspca_dev, mode); + msleep(2); + mode[0] = (mode[0] & 0x81) | (len << 4) | 0x02; + mode[2] = 0; + i2c_w8(gspca_dev, mode); + msleep(2); + reg_r(gspca_dev, 0x0a, 5); +} + +static void i2c_w_seq(struct gspca_dev *gspca_dev, + const u8 (*data)[8]) +{ + while ((*data)[0] != 0) { + if ((*data)[0] != DELAY) + i2c_w8(gspca_dev, *data); + else + msleep((*data)[1]); + data++; + } +} + +/* check the ID of the hv7131 sensor */ +/* this sequence is needed because it activates the sensor */ +static void hv7131r_probe(struct gspca_dev *gspca_dev) +{ + i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */ + msleep(10); + reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */ + msleep(10); + i2c_r(gspca_dev, 0, 5); /* read sensor id */ + if (gspca_dev->usb_buf[0] == 0x02 /* chip ID (02 is R) */ + && gspca_dev->usb_buf[1] == 0x09 + && gspca_dev->usb_buf[2] == 0x01) { + PDEBUG(D_PROBE, "Sensor HV7131R found"); + return; + } + warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1], + gspca_dev->usb_buf[2]); +} + +static void mi0360_probe(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, j; + u16 val = 0; + static const u8 probe_tb[][4][8] = { + { /* mi0360 */ + {0xb0, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, + {0x90, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa2, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb0, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10} + }, + { /* mt9v111 */ + {0xb0, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10}, + {0x90, 0x5c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa2, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {} + }, + }; + + for (i = 0; i < ARRAY_SIZE(probe_tb); i++) { + reg_w1(gspca_dev, 0x17, 0x62); + reg_w1(gspca_dev, 0x01, 0x08); + for (j = 0; j < 3; j++) + i2c_w8(gspca_dev, probe_tb[i][j]); + msleep(2); + reg_r(gspca_dev, 0x0a, 5); + val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; + if (probe_tb[i][3][0] != 0) + i2c_w8(gspca_dev, probe_tb[i][3]); + reg_w1(gspca_dev, 0x01, 0x29); + reg_w1(gspca_dev, 0x17, 0x42); + if (val != 0xffff) + break; + } + if (gspca_dev->usb_err < 0) + return; + switch (val) { + case 0x8221: + PDEBUG(D_PROBE, "Sensor mi0360b"); + sd->sensor = SENSOR_MI0360B; + break; + case 0x823a: + PDEBUG(D_PROBE, "Sensor mt9v111"); + sd->sensor = SENSOR_MT9V111; + break; + case 0x8243: + PDEBUG(D_PROBE, "Sensor mi0360"); + break; + default: + PDEBUG(D_PROBE, "Unknown sensor %04x - forced to mi0360", val); + break; + } +} + +static void ov7630_probe(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 val; + + /* check ov76xx */ + reg_w1(gspca_dev, 0x17, 0x62); + reg_w1(gspca_dev, 0x01, 0x08); + sd->i2c_addr = 0x21; + i2c_r(gspca_dev, 0x0a, 2); + val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; + reg_w1(gspca_dev, 0x01, 0x29); + reg_w1(gspca_dev, 0x17, 0x42); + if (gspca_dev->usb_err < 0) + return; + if (val == 0x7628) { /* soi768 */ + sd->sensor = SENSOR_SOI768; +/*fixme: only valid for 0c45:613e?*/ + gspca_dev->cam.input_flags = + V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP; + PDEBUG(D_PROBE, "Sensor soi768"); + return; + } + PDEBUG(D_PROBE, "Sensor ov%04x", val); +} + +static void ov7648_probe(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 val; + + /* check ov76xx */ + reg_w1(gspca_dev, 0x17, 0x62); + reg_w1(gspca_dev, 0x01, 0x08); + sd->i2c_addr = 0x21; + i2c_r(gspca_dev, 0x0a, 2); + val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; + reg_w1(gspca_dev, 0x01, 0x29); + reg_w1(gspca_dev, 0x17, 0x42); + if ((val & 0xff00) == 0x7600) { /* ov76xx */ + PDEBUG(D_PROBE, "Sensor ov%04x", val); + return; + } + + /* check po1030 */ + reg_w1(gspca_dev, 0x17, 0x62); + reg_w1(gspca_dev, 0x01, 0x08); + sd->i2c_addr = 0x6e; + i2c_r(gspca_dev, 0x00, 2); + val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; + reg_w1(gspca_dev, 0x01, 0x29); + reg_w1(gspca_dev, 0x17, 0x42); + if (gspca_dev->usb_err < 0) + return; + if (val == 0x1030) { /* po1030 */ + PDEBUG(D_PROBE, "Sensor po1030"); + sd->sensor = SENSOR_PO1030; + return; + } + err("Unknown sensor %04x", val); +} + +/* 0c45:6142 sensor may be po2030n, gc0305 or gc0307 */ +static void po2030n_probe(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 val; + + /* check gc0307 */ + reg_w1(gspca_dev, 0x17, 0x62); + reg_w1(gspca_dev, 0x01, 0x08); + reg_w1(gspca_dev, 0x02, 0x22); + sd->i2c_addr = 0x21; + i2c_r(gspca_dev, 0x00, 1); + val = gspca_dev->usb_buf[4]; + reg_w1(gspca_dev, 0x01, 0x29); /* reset */ + reg_w1(gspca_dev, 0x17, 0x42); + if (val == 0x99) { /* gc0307 (?) */ + PDEBUG(D_PROBE, "Sensor gc0307"); + sd->sensor = SENSOR_GC0307; + return; + } + + /* check po2030n */ + reg_w1(gspca_dev, 0x17, 0x62); + reg_w1(gspca_dev, 0x01, 0x0a); + sd->i2c_addr = 0x6e; + i2c_r(gspca_dev, 0x00, 2); + val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; + reg_w1(gspca_dev, 0x01, 0x29); + reg_w1(gspca_dev, 0x17, 0x42); + if (gspca_dev->usb_err < 0) + return; + if (val == 0x2030) { + PDEBUG(D_PROBE, "Sensor po2030n"); +/* sd->sensor = SENSOR_PO2030N; */ + } else { + err("Unknown sensor ID %04x", val); + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + sd->bridge = id->driver_info >> 16; + sd->sensor = id->driver_info >> 8; + sd->flags = id->driver_info; + + cam = &gspca_dev->cam; + if (sd->sensor == SENSOR_ADCM1700) { + cam->cam_mode = cif_mode; + cam->nmodes = ARRAY_SIZE(cif_mode); + } else { + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + } + cam->npkt = 24; /* 24 packets per ISOC message */ + cam->ctrls = sd->ctrls; + + sd->ag_cnt = -1; + sd->quality = QUALITY_DEF; + + /* if USB 1.1, let some bandwidth for the audio device */ + if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) + gspca_dev->nbalt--; + + INIT_WORK(&sd->work, qual_upd); + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + const u8 *sn9c1xx; + u8 regGpio[] = { 0x29, 0x70 }; /* no audio */ + u8 regF1; + + /* setup a selector by bridge */ + reg_w1(gspca_dev, 0xf1, 0x01); + reg_r(gspca_dev, 0x00, 1); + reg_w1(gspca_dev, 0xf1, 0x00); + reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */ + regF1 = gspca_dev->usb_buf[0]; + if (gspca_dev->usb_err < 0) + return gspca_dev->usb_err; + PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1); + if (gspca_dev->audio) + regGpio[1] |= 0x04; /* with audio */ + switch (sd->bridge) { + case BRIDGE_SN9C102P: + case BRIDGE_SN9C105: + if (regF1 != 0x11) + return -ENODEV; + break; + default: +/* case BRIDGE_SN9C110: */ +/* case BRIDGE_SN9C120: */ + if (regF1 != 0x12) + return -ENODEV; + } + + switch (sd->sensor) { + case SENSOR_MI0360: + mi0360_probe(gspca_dev); + break; + case SENSOR_OV7630: + ov7630_probe(gspca_dev); + break; + case SENSOR_OV7648: + ov7648_probe(gspca_dev); + break; + case SENSOR_PO2030N: + po2030n_probe(gspca_dev); + break; + } + + switch (sd->bridge) { + case BRIDGE_SN9C102P: + reg_w1(gspca_dev, 0x02, regGpio[1]); + break; + default: + reg_w(gspca_dev, 0x01, regGpio, 2); + break; + } + + if (sd->sensor == SENSOR_OM6802) + sd->ctrls[SHARPNESS].def = 0x10; + + /* Note we do not disable the sensor clock here (power saving mode), + as that also disables the button on the cam. */ + reg_w1(gspca_dev, 0xf1, 0x00); + + /* set the i2c address */ + sn9c1xx = sn_tb[sd->sensor]; + sd->i2c_addr = sn9c1xx[9]; + + gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; + if (!(sd->flags & F_ILLUM)) + gspca_dev->ctrl_dis |= (1 << ILLUM); + + return gspca_dev->usb_err; +} + +static u32 setexposure(struct gspca_dev *gspca_dev, + u32 expo) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { + case SENSOR_GC0307: { + int a, b; + + /* expo = 0..255 -> a = 19..43 */ + a = 19 + expo * 25 / 256; + i2c_w1(gspca_dev, 0x68, a); + a -= 12; + b = a * a * 4; /* heuristic */ + i2c_w1(gspca_dev, 0x03, b >> 8); + i2c_w1(gspca_dev, 0x04, b); + break; + } + case SENSOR_HV7131R: { + u8 Expodoit[] = + { 0xc1, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x16 }; + + Expodoit[3] = expo >> 16; + Expodoit[4] = expo >> 8; + Expodoit[5] = expo; + i2c_w8(gspca_dev, Expodoit); + break; + } + case SENSOR_MI0360: + case SENSOR_MI0360B: { + u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */ + { 0xb1, 0x5d, 0x09, 0x00, 0x00, 0x00, 0x00, 0x16 }; + static const u8 doit[] = /* update sensor */ + { 0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10 }; + static const u8 sensorgo[] = /* sensor on */ + { 0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10 }; + + if (expo > 0x0635) + expo = 0x0635; + else if (expo < 0x0001) + expo = 0x0001; + expoMi[3] = expo >> 8; + expoMi[4] = expo; + i2c_w8(gspca_dev, expoMi); + i2c_w8(gspca_dev, doit); + i2c_w8(gspca_dev, sensorgo); + break; + } + case SENSOR_MO4000: { + u8 expoMof[] = + { 0xa1, 0x21, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x10 }; + u8 expoMo10[] = + { 0xa1, 0x21, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10 }; + static const u8 gainMo[] = + { 0xa1, 0x21, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1d }; + + if (expo > 0x1fff) + expo = 0x1fff; + else if (expo < 0x0001) + expo = 0x0001; + expoMof[3] = (expo & 0x03fc) >> 2; + i2c_w8(gspca_dev, expoMof); + expoMo10[3] = ((expo & 0x1c00) >> 10) + | ((expo & 0x0003) << 4); + i2c_w8(gspca_dev, expoMo10); + i2c_w8(gspca_dev, gainMo); + PDEBUG(D_FRAM, "set exposure %d", + ((expoMo10[3] & 0x07) << 10) + | (expoMof[3] << 2) + | ((expoMo10[3] & 0x30) >> 4)); + break; + } + case SENSOR_MT9V111: { + u8 expo_c1[] = + { 0xb1, 0x5c, 0x09, 0x00, 0x00, 0x00, 0x00, 0x10 }; + + if (expo > 0x0390) + expo = 0x0390; + else if (expo < 0x0060) + expo = 0x0060; + expo_c1[3] = expo >> 8; + expo_c1[4] = expo; + i2c_w8(gspca_dev, expo_c1); + break; + } + case SENSOR_OM6802: { + u8 gainOm[] = + { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 }; + /* preset AGC - works when AutoExpo = off */ + + if (expo > 0x03ff) + expo = 0x03ff; + if (expo < 0x0001) + expo = 0x0001; + gainOm[3] = expo >> 2; + i2c_w8(gspca_dev, gainOm); + reg_w1(gspca_dev, 0x96, expo >> 5); + PDEBUG(D_FRAM, "set exposure %d", gainOm[3]); + break; + } + } + return expo; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned int expo; + int brightness; + u8 k2; + + brightness = sd->ctrls[BRIGHTNESS].val; + k2 = (brightness - 0x80) >> 2; + switch (sd->sensor) { + case SENSOR_ADCM1700: + if (k2 > 0x1f) + k2 = 0; /* only positive Y offset */ + break; + case SENSOR_HV7131R: + expo = brightness << 12; + if (expo > 0x002dc6c0) + expo = 0x002dc6c0; + else if (expo < 0x02a0) + expo = 0x02a0; + sd->exposure = setexposure(gspca_dev, expo); + break; + case SENSOR_MI0360: + case SENSOR_MO4000: + expo = brightness << 4; + sd->exposure = setexposure(gspca_dev, expo); + break; + case SENSOR_MI0360B: + expo = brightness << 2; + sd->exposure = setexposure(gspca_dev, expo); + break; + case SENSOR_GC0307: + expo = brightness; + sd->exposure = setexposure(gspca_dev, expo); + return; /* don't set the Y offset */ + case SENSOR_MT9V111: + expo = brightness << 2; + sd->exposure = setexposure(gspca_dev, expo); + return; /* don't set the Y offset */ + case SENSOR_OM6802: + expo = brightness << 2; + sd->exposure = setexposure(gspca_dev, expo); + k2 = brightness >> 3; + break; + } + + reg_w1(gspca_dev, 0x96, k2); /* color matrix Y offset */ +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 k2; + u8 contrast[6]; + + k2 = sd->ctrls[CONTRAST].val * 0x30 / (CONTRAST_MAX + 1) + + 0x10; /* 10..40 */ + contrast[0] = (k2 + 1) / 2; /* red */ + contrast[1] = 0; + contrast[2] = k2; /* green */ + contrast[3] = 0; + contrast[4] = (k2 + 1) / 5; /* blue */ + contrast[5] = 0; + reg_w(gspca_dev, 0x84, contrast, sizeof contrast); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, v, colors; + const s16 *uv; + u8 reg8a[12]; /* U & V gains */ + static const s16 uv_com[6] = { /* same as reg84 in signed decimal */ + -24, -38, 64, /* UR UG UB */ + 62, -51, -9 /* VR VG VB */ + }; + static const s16 uv_mi0360b[6] = { + -20, -38, 64, /* UR UG UB */ + 60, -51, -9 /* VR VG VB */ + }; + + colors = sd->ctrls[COLORS].val; + if (sd->sensor == SENSOR_MI0360B) + uv = uv_mi0360b; + else + uv = uv_com; + for (i = 0; i < 6; i++) { + v = uv[i] * colors / COLORS_DEF; + reg8a[i * 2] = v; + reg8a[i * 2 + 1] = (v >> 8) & 0x0f; + } + reg_w(gspca_dev, 0x8a, reg8a, sizeof reg8a); +} + +static void setredblue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val); +/* reg_w1(gspca_dev, 0x07, 32); */ + reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val); +} + +static void setgamma(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, val; + u8 gamma[17]; + const u8 *gamma_base; + static const u8 delta[17] = { + 0x00, 0x14, 0x1c, 0x1c, 0x1c, 0x1c, 0x1b, 0x1a, + 0x18, 0x13, 0x10, 0x0e, 0x08, 0x07, 0x04, 0x02, 0x00 + }; + + switch (sd->sensor) { + case SENSOR_ADCM1700: + gamma_base = gamma_spec_0; + break; + case SENSOR_HV7131R: + case SENSOR_MI0360B: + case SENSOR_MT9V111: + gamma_base = gamma_spec_1; + break; + case SENSOR_GC0307: + gamma_base = gamma_spec_2; + break; + case SENSOR_SP80708: + gamma_base = gamma_spec_3; + break; + default: + gamma_base = gamma_def; + break; + } + + val = sd->ctrls[GAMMA].val; + for (i = 0; i < sizeof gamma; i++) + gamma[i] = gamma_base[i] + + delta[i] * (val - GAMMA_DEF) / 32; + reg_w(gspca_dev, 0x20, gamma, sizeof gamma); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) + return; + switch (sd->sensor) { + case SENSOR_OV7630: + case SENSOR_OV7648: { + u8 comb; + + if (sd->sensor == SENSOR_OV7630) + comb = 0xc0; + else + comb = 0xa0; + if (sd->ctrls[AUTOGAIN].val) + comb |= 0x03; + i2c_w1(&sd->gspca_dev, 0x13, comb); + return; + } + } + if (sd->ctrls[AUTOGAIN].val) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; +} + +static void sethvflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 comn; + + switch (sd->sensor) { + case SENSOR_HV7131R: + comn = 0x18; /* clkdiv = 1, ablcen = 1 */ + if (sd->ctrls[VFLIP].val) + comn |= 0x01; + i2c_w1(gspca_dev, 0x01, comn); /* sctra */ + break; + case SENSOR_OV7630: + comn = 0x02; + if (!sd->ctrls[VFLIP].val) + comn |= 0x80; + i2c_w1(gspca_dev, 0x75, comn); + break; + case SENSOR_OV7648: + comn = 0x06; + if (sd->ctrls[VFLIP].val) + comn |= 0x80; + i2c_w1(gspca_dev, 0x75, comn); + break; + case SENSOR_PO2030N: + /* Reg. 0x1E: Timing Generator Control Register 2 (Tgcontrol2) + * (reset value: 0x0A) + * bit7: HM: Horizontal Mirror: 0: disable, 1: enable + * bit6: VM: Vertical Mirror: 0: disable, 1: enable + * bit5: ST: Shutter Selection: 0: electrical, 1: mechanical + * bit4: FT: Single Frame Transfer: 0: disable, 1: enable + * bit3-0: X + */ + comn = 0x0a; + if (sd->ctrls[HFLIP].val) + comn |= 0x80; + if (sd->ctrls[VFLIP].val) + comn |= 0x40; + i2c_w1(&sd->gspca_dev, 0x1e, comn); + break; + } +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w1(gspca_dev, 0x99, sd->ctrls[SHARPNESS].val); +} + +static void setillum(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (gspca_dev->ctrl_dis & (1 << ILLUM)) + return; + switch (sd->sensor) { + case SENSOR_ADCM1700: + reg_w1(gspca_dev, 0x02, /* gpio */ + sd->ctrls[ILLUM].val ? 0x64 : 0x60); + break; + case SENSOR_MT9V111: + reg_w1(gspca_dev, 0x02, + sd->ctrls[ILLUM].val ? 0x77 : 0x74); +/* should have been: */ +/* 0x55 : 0x54); * 370i */ +/* 0x66 : 0x64); * Clip */ + break; + } +} + +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (gspca_dev->ctrl_dis & (1 << FREQ)) + return; + if (sd->sensor == SENSOR_OV7660) { + u8 com8; + + com8 = 0xdf; /* auto gain/wb/expo */ + switch (sd->ctrls[FREQ].val) { + case 0: /* Banding filter disabled */ + i2c_w1(gspca_dev, 0x13, com8 | 0x20); + break; + case 1: /* 50 hz */ + i2c_w1(gspca_dev, 0x13, com8); + i2c_w1(gspca_dev, 0x3b, 0x0a); + break; + case 2: /* 60 hz */ + i2c_w1(gspca_dev, 0x13, com8); + i2c_w1(gspca_dev, 0x3b, 0x02); + break; + } + } else { + u8 reg2a = 0, reg2b = 0, reg2d = 0; + + /* Get reg2a / reg2d base values */ + switch (sd->sensor) { + case SENSOR_OV7630: + reg2a = 0x08; + reg2d = 0x01; + break; + case SENSOR_OV7648: + reg2a = 0x11; + reg2d = 0x81; + break; + } + + switch (sd->ctrls[FREQ].val) { + case 0: /* Banding filter disabled */ + break; + case 1: /* 50 hz (filter on and framerate adj) */ + reg2a |= 0x80; + reg2b = 0xac; + reg2d |= 0x04; + break; + case 2: /* 60 hz (filter on, no framerate adj) */ + reg2a |= 0x80; + reg2d |= 0x04; + break; + } + i2c_w1(gspca_dev, 0x2a, reg2a); + i2c_w1(gspca_dev, 0x2b, reg2b); + i2c_w1(gspca_dev, 0x2d, reg2d); + } +} + +static void setjpegqual(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + jpeg_set_qual(sd->jpeg_hdr, sd->quality); +#if USB_BUF_SZ < 64 +#error "No room enough in usb_buf for quantization table" +#endif + memcpy(gspca_dev->usb_buf, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x0100, 0, + gspca_dev->usb_buf, 64, + 500); + memcpy(gspca_dev->usb_buf, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x0140, 0, + gspca_dev->usb_buf, 64, + 500); + + sd->reg18 ^= 0x40; + reg_w1(gspca_dev, 0x18, sd->reg18); +} + +/* JPEG quality update */ +/* This function is executed from a work queue. */ +static void qual_upd(struct work_struct *work) +{ + struct sd *sd = container_of(work, struct sd, work); + struct gspca_dev *gspca_dev = &sd->gspca_dev; + + mutex_lock(&gspca_dev->usb_lock); + PDEBUG(D_STREAM, "qual_upd %d%%", sd->quality); + setjpegqual(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + u8 reg01, reg17; + u8 reg0102[2]; + const u8 *sn9c1xx; + const u8 (*init)[8]; + const u8 *reg9a; + int mode; + static const u8 reg9a_def[] = + {0x00, 0x40, 0x20, 0x00, 0x00, 0x00}; + static const u8 reg9a_spec[] = + {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; + static const u8 regd4[] = {0x60, 0x00, 0x00}; + static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; + static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; + static const u8 CA_adcm1700[] = + { 0x14, 0xec, 0x0a, 0xf6 }; + static const u8 CA_po2030n[] = + { 0x1e, 0xe2, 0x14, 0xec }; + static const u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */ + static const u8 CE_gc0307[] = + { 0x32, 0xce, 0x2d, 0xd3 }; + static const u8 CE_ov76xx[] = + { 0x32, 0xdd, 0x32, 0xdd }; + static const u8 CE_po2030n[] = + { 0x14, 0xe7, 0x1e, 0xdd }; + + /* create the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x21); /* JPEG 422 */ + + /* initialize the bridge */ + sn9c1xx = sn_tb[sd->sensor]; + + /* sensor clock already enabled in sd_init */ + /* reg_w1(gspca_dev, 0xf1, 0x00); */ + reg01 = sn9c1xx[1]; + if (sd->flags & F_PDN_INV) + reg01 ^= S_PDN_INV; /* power down inverted */ + reg_w1(gspca_dev, 0x01, reg01); + + /* configure gpio */ + reg0102[0] = reg01; + reg0102[1] = sn9c1xx[2]; + if (gspca_dev->audio) + reg0102[1] |= 0x04; /* keep the audio connection */ + reg_w(gspca_dev, 0x01, reg0102, 2); + reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2); + reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); + switch (sd->sensor) { + case SENSOR_GC0307: + case SENSOR_OV7660: + case SENSOR_PO1030: + case SENSOR_PO2030N: + case SENSOR_SOI768: + case SENSOR_SP80708: + reg9a = reg9a_spec; + break; + default: + reg9a = reg9a_def; + break; + } + reg_w(gspca_dev, 0x9a, reg9a, 6); + + reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); + + reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); + + reg17 = sn9c1xx[0x17]; + switch (sd->sensor) { + case SENSOR_GC0307: + msleep(50); /*fixme: is it useful? */ + break; + case SENSOR_OM6802: + msleep(10); + reg_w1(gspca_dev, 0x02, 0x73); + reg17 |= SEN_CLK_EN; + reg_w1(gspca_dev, 0x17, reg17); + reg_w1(gspca_dev, 0x01, 0x22); + msleep(100); + reg01 = SCL_SEL_OD | S_PDN_INV; + reg17 &= MCK_SIZE_MASK; + reg17 |= 0x04; /* clock / 4 */ + break; + } + reg01 |= SYS_SEL_48M; + reg_w1(gspca_dev, 0x01, reg01); + reg17 |= SEN_CLK_EN; + reg_w1(gspca_dev, 0x17, reg17); + reg01 &= ~S_PWR_DN; /* sensor power on */ + reg_w1(gspca_dev, 0x01, reg01); + reg01 &= ~SYS_SEL_48M; + reg_w1(gspca_dev, 0x01, reg01); + + switch (sd->sensor) { + case SENSOR_HV7131R: + hv7131r_probe(gspca_dev); /*fixme: is it useful? */ + break; + case SENSOR_OM6802: + msleep(10); + reg_w1(gspca_dev, 0x01, reg01); + i2c_w8(gspca_dev, om6802_init0[0]); + i2c_w8(gspca_dev, om6802_init0[1]); + msleep(15); + reg_w1(gspca_dev, 0x02, 0x71); + msleep(150); + break; + case SENSOR_SP80708: + msleep(100); + reg_w1(gspca_dev, 0x02, 0x62); + break; + } + + /* initialize the sensor */ + i2c_w_seq(gspca_dev, sensor_init[sd->sensor]); + + reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]); + reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]); + reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]); + reg_w1(gspca_dev, 0x13, sn9c1xx[0x13]); + reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); + if (sd->sensor == SENSOR_ADCM1700) { + reg_w1(gspca_dev, 0xd2, 0x3a); /* AE_H_SIZE = 116 */ + reg_w1(gspca_dev, 0xd3, 0x30); /* AE_V_SIZE = 96 */ + } else { + reg_w1(gspca_dev, 0xd2, 0x6a); /* AE_H_SIZE = 212 */ + reg_w1(gspca_dev, 0xd3, 0x50); /* AE_V_SIZE = 160 */ + } + reg_w1(gspca_dev, 0xc6, 0x00); + reg_w1(gspca_dev, 0xc7, 0x00); + if (sd->sensor == SENSOR_ADCM1700) { + reg_w1(gspca_dev, 0xc8, 0x2c); /* AW_H_STOP = 352 */ + reg_w1(gspca_dev, 0xc9, 0x24); /* AW_V_STOP = 288 */ + } else { + reg_w1(gspca_dev, 0xc8, 0x50); /* AW_H_STOP = 640 */ + reg_w1(gspca_dev, 0xc9, 0x3c); /* AW_V_STOP = 480 */ + } + reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); + switch (sd->sensor) { + case SENSOR_OM6802: +/* case SENSOR_OV7648: * fixme: sometimes */ + break; + default: + reg17 |= DEF_EN; + break; + } + reg_w1(gspca_dev, 0x17, reg17); + + reg_w1(gspca_dev, 0x05, 0x00); /* red */ + reg_w1(gspca_dev, 0x07, 0x00); /* green */ + reg_w1(gspca_dev, 0x06, 0x00); /* blue */ + reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]); + + setgamma(gspca_dev); + +/*fixme: 8 times with all zeroes and 1 or 2 times with normal values */ + for (i = 0; i < 8; i++) + reg_w(gspca_dev, 0x84, reg84, sizeof reg84); + switch (sd->sensor) { + case SENSOR_ADCM1700: + case SENSOR_OV7660: + case SENSOR_SP80708: + reg_w1(gspca_dev, 0x9a, 0x05); + break; + case SENSOR_GC0307: + case SENSOR_MT9V111: + case SENSOR_MI0360B: + reg_w1(gspca_dev, 0x9a, 0x07); + break; + case SENSOR_OV7630: + case SENSOR_OV7648: + reg_w1(gspca_dev, 0x9a, 0x0a); + break; + case SENSOR_PO2030N: + case SENSOR_SOI768: + reg_w1(gspca_dev, 0x9a, 0x06); + break; + default: + reg_w1(gspca_dev, 0x9a, 0x08); + break; + } + setsharpness(gspca_dev); + + reg_w(gspca_dev, 0x84, reg84, sizeof reg84); + reg_w1(gspca_dev, 0x05, 0x20); /* red */ + reg_w1(gspca_dev, 0x07, 0x20); /* green */ + reg_w1(gspca_dev, 0x06, 0x20); /* blue */ + + init = NULL; + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + reg01 |= SYS_SEL_48M | V_TX_EN; + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x02; /* clock / 2 */ + switch (sd->sensor) { + case SENSOR_ADCM1700: + init = adcm1700_sensor_param1; + break; + case SENSOR_GC0307: + init = gc0307_sensor_param1; + break; + case SENSOR_HV7131R: + case SENSOR_MI0360: + if (mode) + reg01 |= SYS_SEL_48M; /* 320x240: clk 48Mhz */ + else + reg01 &= ~SYS_SEL_48M; /* 640x480: clk 24Mhz */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 1 */ + break; + case SENSOR_MI0360B: + init = mi0360b_sensor_param1; + break; + case SENSOR_MO4000: + if (mode) { /* if 320x240 */ + reg01 &= ~SYS_SEL_48M; /* clk 24Mz */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 1 */ + } + break; + case SENSOR_MT9V111: + init = mt9v111_sensor_param1; + break; + case SENSOR_OM6802: + init = om6802_sensor_param1; + if (!mode) { /* if 640x480 */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x04; /* clock / 4 */ + } + break; + case SENSOR_OV7630: + init = ov7630_sensor_param1; + break; + case SENSOR_OV7648: + init = ov7648_sensor_param1; + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 1 */ + break; + case SENSOR_OV7660: + init = ov7660_sensor_param1; + break; + case SENSOR_PO1030: + init = po1030_sensor_param1; + break; + case SENSOR_PO2030N: + init = po2030n_sensor_param1; + break; + case SENSOR_SOI768: + init = soi768_sensor_param1; + break; + case SENSOR_SP80708: + init = sp80708_sensor_param1; + break; + } + + /* more sensor initialization - param1 */ + if (init != NULL) { + i2c_w_seq(gspca_dev, init); +/* init = NULL; */ + } + + reg_w(gspca_dev, 0xc0, C0, 6); + switch (sd->sensor) { + case SENSOR_ADCM1700: + case SENSOR_GC0307: + case SENSOR_SOI768: + reg_w(gspca_dev, 0xca, CA_adcm1700, 4); + break; + case SENSOR_PO2030N: + reg_w(gspca_dev, 0xca, CA_po2030n, 4); + break; + default: + reg_w(gspca_dev, 0xca, CA, 4); + break; + } + switch (sd->sensor) { + case SENSOR_ADCM1700: + case SENSOR_OV7630: + case SENSOR_OV7648: + case SENSOR_OV7660: + case SENSOR_SOI768: + reg_w(gspca_dev, 0xce, CE_ov76xx, 4); + break; + case SENSOR_GC0307: + reg_w(gspca_dev, 0xce, CE_gc0307, 4); + break; + case SENSOR_PO2030N: + reg_w(gspca_dev, 0xce, CE_po2030n, 4); + break; + default: + reg_w(gspca_dev, 0xce, CE, 4); + /* ?? {0x1e, 0xdd, 0x2d, 0xe7} */ + break; + } + + /* here change size mode 0 -> VGA; 1 -> CIF */ + sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40; + reg_w1(gspca_dev, 0x18, sd->reg18); + setjpegqual(gspca_dev); + + reg_w1(gspca_dev, 0x17, reg17); + reg_w1(gspca_dev, 0x01, reg01); + sd->reg01 = reg01; + sd->reg17 = reg17; + + sethvflip(gspca_dev); + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setcolors(gspca_dev); + setautogain(gspca_dev); + setfreq(gspca_dev); + + sd->pktsz = sd->npkt = 0; + sd->nchg = sd->short_mark = 0; + sd->work_thread = create_singlethread_workqueue(MODULE_NAME); + + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + static const u8 stophv7131[] = + { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 }; + static const u8 stopmi0360[] = + { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 }; + static const u8 stopov7648[] = + { 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 }; + static const u8 stopsoi768[] = + { 0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10 }; + u8 reg01; + u8 reg17; + + reg01 = sd->reg01; + reg17 = sd->reg17 & ~SEN_CLK_EN; + switch (sd->sensor) { + case SENSOR_ADCM1700: + case SENSOR_GC0307: + case SENSOR_PO2030N: + case SENSOR_SP80708: + reg01 |= LED; + reg_w1(gspca_dev, 0x01, reg01); + reg01 &= ~(LED | V_TX_EN); + reg_w1(gspca_dev, 0x01, reg01); +/* reg_w1(gspca_dev, 0x02, 0x??); * LED off ? */ + break; + case SENSOR_HV7131R: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); + i2c_w8(gspca_dev, stophv7131); + break; + case SENSOR_MI0360: + case SENSOR_MI0360B: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); +/* reg_w1(gspca_dev, 0x02, 0x40); * LED off ? */ + i2c_w8(gspca_dev, stopmi0360); + break; + case SENSOR_MT9V111: + case SENSOR_OM6802: + case SENSOR_PO1030: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); + break; + case SENSOR_OV7630: + case SENSOR_OV7648: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); + i2c_w8(gspca_dev, stopov7648); + break; + case SENSOR_OV7660: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); + break; + case SENSOR_SOI768: + i2c_w8(gspca_dev, stopsoi768); + break; + } + + reg01 |= SCL_SEL_OD; + reg_w1(gspca_dev, 0x01, reg01); + reg01 |= S_PWR_DN; /* sensor power down */ + reg_w1(gspca_dev, 0x01, reg01); + reg_w1(gspca_dev, 0x17, reg17); + reg01 &= ~SYS_SEL_48M; /* clock 24MHz */ + reg_w1(gspca_dev, 0x01, reg01); + reg01 |= LED; + reg_w1(gspca_dev, 0x01, reg01); + /* Don't disable sensor clock as that disables the button on the cam */ + /* reg_w1(gspca_dev, 0xf1, 0x01); */ +} + +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->work_thread != NULL) { + mutex_unlock(&gspca_dev->usb_lock); + destroy_workqueue(sd->work_thread); + mutex_lock(&gspca_dev->usb_lock); + sd->work_thread = NULL; + } +} + +static void do_autogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int delta; + int expotimes; + u8 luma_mean = 130; + u8 luma_delta = 20; + + /* Thanks S., without your advice, autobright should not work :) */ + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt >= 0) + return; + sd->ag_cnt = AG_CNT_START; + + delta = atomic_read(&sd->avg_lum); + PDEBUG(D_FRAM, "mean lum %d", delta); + if (delta < luma_mean - luma_delta || + delta > luma_mean + luma_delta) { + switch (sd->sensor) { + case SENSOR_GC0307: + expotimes = sd->exposure; + expotimes += (luma_mean - delta) >> 6; + if (expotimes < 0) + expotimes = 0; + sd->exposure = setexposure(gspca_dev, + (unsigned int) expotimes); + break; + case SENSOR_HV7131R: + expotimes = sd->exposure >> 8; + expotimes += (luma_mean - delta) >> 4; + if (expotimes < 0) + expotimes = 0; + sd->exposure = setexposure(gspca_dev, + (unsigned int) (expotimes << 8)); + break; + case SENSOR_OM6802: + case SENSOR_MT9V111: + expotimes = sd->exposure; + expotimes += (luma_mean - delta) >> 2; + if (expotimes < 0) + expotimes = 0; + sd->exposure = setexposure(gspca_dev, + (unsigned int) expotimes); + setredblue(gspca_dev); + break; + default: +/* case SENSOR_MO4000: */ +/* case SENSOR_MI0360: */ +/* case SENSOR_MI0360B: */ + expotimes = sd->exposure; + expotimes += (luma_mean - delta) >> 6; + if (expotimes < 0) + expotimes = 0; + sd->exposure = setexposure(gspca_dev, + (unsigned int) expotimes); + setredblue(gspca_dev); + break; + } + } +} + +/* set the average luminosity from an isoc marker */ +static void set_lum(struct sd *sd, + u8 *data) +{ + int avg_lum; + + /* w0 w1 w2 + * w3 w4 w5 + * w6 w7 w8 + */ + avg_lum = (data[27] << 8) + data[28] /* w3 */ + + + (data[31] << 8) + data[32] /* w5 */ + + + (data[23] << 8) + data[24] /* w1 */ + + + (data[35] << 8) + data[36] /* w7 */ + + + (data[29] << 10) + (data[30] << 2); /* w4 * 4 */ + avg_lum >>= 10; + atomic_set(&sd->avg_lum, avg_lum); +} + +/* scan the URB packets */ +/* This function is run at interrupt level. */ +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, new_qual; + + /* + * A frame ends on the marker + * ff ff 00 c4 c4 96 .. + * which is 62 bytes long and is followed by various information + * including statuses and luminosity. + * + * A marker may be splitted on two packets. + * + * The 6th byte of a marker contains the bits: + * 0x08: USB full + * 0xc0: frame sequence + * When the bit 'USB full' is set, the frame must be discarded; + * this is also the case when the 2 bytes before the marker are + * not the JPEG end of frame ('ff d9'). + */ + +/*fixme: assumption about the following code: + * - there can be only one marker in a packet + */ + + /* skip the remaining bytes of a short marker */ + i = sd->short_mark; + if (i != 0) { + sd->short_mark = 0; + if (i < 0 /* if 'ff' at end of previous packet */ + && data[0] == 0xff + && data[1] == 0x00) + goto marker_found; + if (data[0] == 0xff && data[1] == 0xff) { + i = 0; + goto marker_found; + } + len -= i; + if (len <= 0) + return; + data += i; + } + + /* count the packets and their size */ + sd->npkt++; + sd->pktsz += len; + + /* search backwards if there is a marker in the packet */ + for (i = len - 1; --i >= 0; ) { + if (data[i] != 0xff) { + i--; + continue; + } + if (data[i + 1] == 0xff) { + + /* (there may be 'ff ff' inside a marker) */ + if (i + 2 >= len || data[i + 2] == 0x00) + goto marker_found; + } + } + + /* no marker found */ + /* add the JPEG header if first fragment */ + if (data[len - 1] == 0xff) + sd->short_mark = -1; + if (gspca_dev->last_packet_type == LAST_PACKET) + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + return; + + /* marker found */ + /* if some error, discard the frame and decrease the quality */ +marker_found: + new_qual = 0; + if (i > 2) { + if (data[i - 2] != 0xff || data[i - 1] != 0xd9) { + gspca_dev->last_packet_type = DISCARD_PACKET; + new_qual = -3; + } + } else if (i + 6 < len) { + if (data[i + 6] & 0x08) { + gspca_dev->last_packet_type = DISCARD_PACKET; + new_qual = -5; + } + } + + gspca_frame_add(gspca_dev, LAST_PACKET, data, i); + + /* compute the filling rate and a new JPEG quality */ + if (new_qual == 0) { + int r; + + r = (sd->pktsz * 100) / + (sd->npkt * + gspca_dev->urb[0]->iso_frame_desc[0].length); + if (r >= 85) + new_qual = -3; + else if (r < 75) + new_qual = 2; + } + if (new_qual != 0) { + sd->nchg += new_qual; + if (sd->nchg < -6 || sd->nchg >= 12) { + sd->nchg = 0; + new_qual += sd->quality; + if (new_qual < QUALITY_MIN) + new_qual = QUALITY_MIN; + else if (new_qual > QUALITY_MAX) + new_qual = QUALITY_MAX; + if (new_qual != sd->quality) { + sd->quality = new_qual; + queue_work(sd->work_thread, &sd->work); + } + } + } else { + sd->nchg = 0; + } + sd->pktsz = sd->npkt = 0; + + /* if the marker is smaller than 62 bytes, + * memorize the number of bytes to skip in the next packet */ + if (i + 62 > len) { /* no more usable data */ + sd->short_mark = i + 62 - len; + return; + } + if (sd->ag_cnt >= 0) + set_lum(sd, data + i); + + /* if more data, start a new frame */ + i += 62; + if (i < len) { + data += i; + len -= i; + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + } +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "NoFliker"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet data */ + int len) /* interrupt packet length */ +{ + int ret = -EINVAL; + + if (len == 1 && data[0] == 1) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); + input_sync(gspca_dev->input_dev); + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + ret = 0; + } + + return ret; +} +#endif + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = NCTRLS, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, + .get_jcomp = sd_get_jcomp, + .querymenu = sd_querymenu, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +#endif +}; + +/* -- module initialisation -- */ +#define BS(bridge, sensor) \ + .driver_info = (BRIDGE_ ## bridge << 16) \ + | (SENSOR_ ## sensor << 8) +#define BSF(bridge, sensor, flags) \ + .driver_info = (BRIDGE_ ## bridge << 16) \ + | (SENSOR_ ## sensor << 8) \ + | (flags) +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)}, + {USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)}, + {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, F_PDN_INV)}, + {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, F_PDN_INV)}, + {USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)}, + {USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)}, + {USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)}, + {USB_DEVICE(0x06f8, 0x3004), BS(SN9C105, OV7660)}, + {USB_DEVICE(0x06f8, 0x3008), BS(SN9C105, OV7660)}, +/* {USB_DEVICE(0x0c45, 0x603a), BS(SN9C102P, OV7648)}, */ + {USB_DEVICE(0x0c45, 0x6040), BS(SN9C102P, HV7131R)}, +/* {USB_DEVICE(0x0c45, 0x607a), BS(SN9C102P, OV7648)}, */ +/* {USB_DEVICE(0x0c45, 0x607b), BS(SN9C102P, OV7660)}, */ + {USB_DEVICE(0x0c45, 0x607c), BS(SN9C102P, HV7131R)}, +/* {USB_DEVICE(0x0c45, 0x607e), BS(SN9C102P, OV7630)}, */ + {USB_DEVICE(0x0c45, 0x60c0), BSF(SN9C105, MI0360, F_ILLUM)}, + /* or MT9V111 */ +/* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */ +/* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */ +/* {USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */ + {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)}, + {USB_DEVICE(0x0c45, 0x60ec), BS(SN9C105, MO4000)}, +/* {USB_DEVICE(0x0c45, 0x60ef), BS(SN9C105, ICM105C)}, */ +/* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */ +/* {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */ + {USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)}, + {USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)}, + {USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)}, + {USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)}, /*sn9c128*/ + {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)}, /* /GC0305*/ +/* {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */ + {USB_DEVICE(0x0c45, 0x610a), BS(SN9C120, OV7648)}, /*sn9c128*/ + {USB_DEVICE(0x0c45, 0x610b), BS(SN9C120, OV7660)}, /*sn9c128*/ + {USB_DEVICE(0x0c45, 0x610c), BS(SN9C120, HV7131R)}, /*sn9c128*/ + {USB_DEVICE(0x0c45, 0x610e), BS(SN9C120, OV7630)}, /*sn9c128*/ +/* {USB_DEVICE(0x0c45, 0x610f), BS(SN9C120, S5K53BEB)}, */ +/* {USB_DEVICE(0x0c45, 0x6122), BS(SN9C110, ICM105C)}, */ +/* {USB_DEVICE(0x0c45, 0x6123), BS(SN9C110, SanyoCCD)}, */ + {USB_DEVICE(0x0c45, 0x6128), BS(SN9C120, OM6802)}, /*sn9c325?*/ +/*bw600.inf:*/ + {USB_DEVICE(0x0c45, 0x612a), BS(SN9C120, OV7648)}, /*sn9c325?*/ + {USB_DEVICE(0x0c45, 0x612b), BS(SN9C110, ADCM1700)}, + {USB_DEVICE(0x0c45, 0x612c), BS(SN9C110, MO4000)}, + {USB_DEVICE(0x0c45, 0x612e), BS(SN9C110, OV7630)}, +/* {USB_DEVICE(0x0c45, 0x612f), BS(SN9C110, ICM105C)}, */ + {USB_DEVICE(0x0c45, 0x6130), BS(SN9C120, MI0360)}, + /* or MT9V111 / MI0360B */ +/* {USB_DEVICE(0x0c45, 0x6132), BS(SN9C120, OV7670)}, */ + {USB_DEVICE(0x0c45, 0x6138), BS(SN9C120, MO4000)}, + {USB_DEVICE(0x0c45, 0x613a), BS(SN9C120, OV7648)}, + {USB_DEVICE(0x0c45, 0x613b), BS(SN9C120, OV7660)}, + {USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)}, + {USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)}, + {USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)}, /*sn9c120b*/ + /* or GC0305 / GC0307 */ + {USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/ + {USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/ + {USB_DEVICE(0x0c45, 0x614a), BSF(SN9C120, ADCM1700, F_ILLUM)}, +/* {USB_DEVICE(0x0c45, 0x614c), BS(SN9C120, GC0306)}, */ /*sn9c120b*/ + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca1528.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca1528.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca1528.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca1528.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,598 @@ +/* + * spca1528 subdriver + * + * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr) + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "spca1528" + +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Jean-Francois Moine "); +MODULE_DESCRIPTION("SPCA1528 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u8 brightness; + u8 contrast; + u8 hue; + u8 color; + u8 sharpness; + + u8 pkt_seq; + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 128 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 8, + .step = 1, +#define CONTRAST_DEF 1 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = 0, + .maximum = 255, + .step = 1, +#define HUE_DEF 0 + .default_value = HUE_DEF, + }, + .set = sd_sethue, + .get = sd_gethue, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 8, + .step = 1, +#define COLOR_DEF 1 + .default_value = COLOR_DEF, + }, + .set = sd_setcolor, + .get = sd_getcolor, + }, + { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define SHARPNESS_DEF 0 + .default_value = SHARPNESS_DEF, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { +/* (does not work correctly) + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 5 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, +*/ + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +/* read bytes to gspca usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + u8 req, + u16 index, + int len) +{ +#if USB_BUF_SZ < 64 +#error "USB buffer too small" +#endif + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0000, /* value */ + index, + gspca_dev->usb_buf, len, + 500); + PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index, + gspca_dev->usb_buf[0]); + if (ret < 0) { + err("reg_r err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w(struct gspca_dev *gspca_dev, + u8 req, + u16 value, + u16 index) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index); + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + NULL, 0, 500); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_wb(struct gspca_dev *gspca_dev, + u8 req, + u16 value, + u16 index, + u8 byte) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "SET %02x %04x %04x %02x", req, value, index, byte); + gspca_dev->usb_buf[0] = byte; + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + gspca_dev->usb_buf, 1, 500); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void wait_status_0(struct gspca_dev *gspca_dev) +{ + int i; + + i = 20; + do { + reg_r(gspca_dev, 0x21, 0x0000, 1); + if (gspca_dev->usb_buf[0] == 0) + return; + msleep(30); + } while (--i > 0); + PDEBUG(D_ERR, "wait_status_0 timeout"); + gspca_dev->usb_err = -ETIME; +} + +static void wait_status_1(struct gspca_dev *gspca_dev) +{ + int i; + + i = 10; + do { + reg_r(gspca_dev, 0x21, 0x0001, 1); + msleep(10); + if (gspca_dev->usb_buf[0] == 1) { + reg_wb(gspca_dev, 0x21, 0x0000, 0x0001, 0x00); + reg_r(gspca_dev, 0x21, 0x0001, 1); + return; + } + } while (--i > 0); + PDEBUG(D_ERR, "wait_status_1 timeout"); + gspca_dev->usb_err = -ETIME; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, sd->brightness); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, sd->contrast); +} + +static void sethue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, sd->hue); +} + +static void setcolor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, sd->color); +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, sd->sharpness); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->cam.cam_mode = vga_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */ + /*fixme: 256 in ms-win traces*/ + + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->hue = HUE_DEF; + sd->color = COLOR_DEF; + sd->sharpness = SHARPNESS_DEF; + + gspca_dev->nbalt = 4; /* use alternate setting 3 */ + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0x00, 0x0001, 0x2067); + reg_w(gspca_dev, 0x00, 0x00d0, 0x206b); + reg_w(gspca_dev, 0x00, 0x0000, 0x206c); + reg_w(gspca_dev, 0x00, 0x0001, 0x2069); + msleep(8); + reg_w(gspca_dev, 0x00, 0x00c0, 0x206b); + reg_w(gspca_dev, 0x00, 0x0000, 0x206c); + reg_w(gspca_dev, 0x00, 0x0001, 0x2069); + + reg_r(gspca_dev, 0x20, 0x0000, 1); + reg_r(gspca_dev, 0x20, 0x0000, 5); + reg_r(gspca_dev, 0x23, 0x0000, 64); + PDEBUG(D_PROBE, "%s%s", &gspca_dev->usb_buf[0x1c], + &gspca_dev->usb_buf[0x30]); + reg_r(gspca_dev, 0x23, 0x0001, 64); + return gspca_dev->usb_err; +} + +/* function called at start time before URB creation */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + u8 mode; + + reg_r(gspca_dev, 0x00, 0x2520, 1); + wait_status_0(gspca_dev); + reg_w(gspca_dev, 0xc5, 0x0003, 0x0000); + wait_status_1(gspca_dev); + + wait_status_0(gspca_dev); + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode); + reg_r(gspca_dev, 0x25, 0x0004, 1); + reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06); + reg_r(gspca_dev, 0x27, 0x0000, 1); + return gspca_dev->usb_err; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* initialize the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x22); /* JPEG 411 */ + + /* the JPEG quality seems to be 82% */ + jpeg_set_qual(sd->jpeg_hdr, 82); + + /* set the controls */ + setbrightness(gspca_dev); + setcontrast(gspca_dev); + sethue(gspca_dev); + setcolor(gspca_dev); + setsharpness(gspca_dev); + + msleep(5); + reg_r(gspca_dev, 0x00, 0x2520, 1); + msleep(8); + + /* start the capture */ + wait_status_0(gspca_dev); + reg_w(gspca_dev, 0x31, 0x0000, 0x0004); + wait_status_1(gspca_dev); + wait_status_0(gspca_dev); + msleep(200); + + sd->pkt_seq = 0; + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* stop the capture */ + wait_status_0(gspca_dev); + reg_w(gspca_dev, 0x31, 0x0000, 0x0000); + wait_status_1(gspca_dev); + wait_status_0(gspca_dev); +} + +/* move a packet adding 0x00 after 0xff */ +static void add_packet(struct gspca_dev *gspca_dev, + u8 *data, + int len) +{ + int i; + + i = 0; + do { + if (data[i] == 0xff) { + gspca_frame_add(gspca_dev, INTER_PACKET, + data, i + 1); + len -= i; + data += i; + *data = 0x00; + i = 0; + } + } while (++i < len); + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + static const u8 ffd9[] = {0xff, 0xd9}; + + /* image packets start with: + * 02 8n + * with bit: + * 0x01: even (0) / odd (1) image + * 0x02: end of image when set + */ + if (len < 3) + return; /* empty packet */ + if (*data == 0x02) { + if (data[1] & 0x02) { + sd->pkt_seq = !(data[1] & 1); + add_packet(gspca_dev, data + 2, len - 2); + gspca_frame_add(gspca_dev, LAST_PACKET, + ffd9, 2); + return; + } + if ((data[1] & 1) != sd->pkt_seq) + goto err; + if (gspca_dev->last_packet_type == LAST_PACKET) + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + add_packet(gspca_dev, data + 2, len - 2); + return; + } +err: + gspca_dev->last_packet_type = DISCARD_PACKET; +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hue = val; + if (gspca_dev->streaming) + sethue(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hue; + return 0; +} + +static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->color = val; + if (gspca_dev->streaming) + setcolor(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->color; + return 0; +} + +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) + setsharpness(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x04fc, 0x1528)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + /* the video interface for isochronous transfer is 1 */ + if (intf->cur_altsetting->desc.bInterfaceNumber != 1) + return -ENODEV; + + return gspca_dev_probe2(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca500.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca500.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca500.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca500.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1104 @@ +/* + * SPCA500 chip based cameras initialization data + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + * + */ + +#define MODULE_NAME "spca500" + +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + u8 quality; +#define QUALITY_MIN 70 +#define QUALITY_MAX 95 +#define QUALITY_DEF 85 + + char subtype; +#define AgfaCl20 0 +#define AiptekPocketDV 1 +#define BenqDC1016 2 +#define CreativePCCam300 3 +#define DLinkDSC350 4 +#define Gsmartmini 5 +#define IntelPocketPCCamera 6 +#define KodakEZ200 7 +#define LogitechClickSmart310 8 +#define LogitechClickSmart510 9 +#define LogitechTraveler 10 +#define MustekGsmart300 11 +#define Optimedia 12 +#define PalmPixDC85 13 +#define ToptroIndus 14 + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 127 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 63, + .step = 1, +#define CONTRAST_DEF 31 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 63, + .step = 1, +#define COLOR_DEF 31 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static const struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* Frame packet header offsets for the spca500 */ +#define SPCA500_OFFSET_PADDINGLB 2 +#define SPCA500_OFFSET_PADDINGHB 3 +#define SPCA500_OFFSET_MODE 4 +#define SPCA500_OFFSET_IMGWIDTH 5 +#define SPCA500_OFFSET_IMGHEIGHT 6 +#define SPCA500_OFFSET_IMGMODE 7 +#define SPCA500_OFFSET_QTBLINDEX 8 +#define SPCA500_OFFSET_FRAMSEQ 9 +#define SPCA500_OFFSET_CDSPINFO 10 +#define SPCA500_OFFSET_GPIO 11 +#define SPCA500_OFFSET_AUGPIO 12 +#define SPCA500_OFFSET_DATA 16 + + +static const __u16 spca500_visual_defaults[][3] = { + {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync, + * hue (H byte) = 0, + * saturation/hue enable, + * brightness/contrast enable. + */ + {0x00, 0x0000, 0x8167}, /* brightness = 0 */ + {0x00, 0x0020, 0x8168}, /* contrast = 0 */ + {0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync, + * hue (H byte) = 0, saturation/hue enable, + * brightness/contrast enable. + * was 0x0003, now 0x0000. + */ + {0x00, 0x0000, 0x816a}, /* hue (L byte) = 0 */ + {0x00, 0x0020, 0x8169}, /* saturation = 0x20 */ + {0x00, 0x0050, 0x8157}, /* edge gain high threshold */ + {0x00, 0x0030, 0x8158}, /* edge gain low threshold */ + {0x00, 0x0028, 0x8159}, /* edge bandwidth high threshold */ + {0x00, 0x000a, 0x815a}, /* edge bandwidth low threshold */ + {0x00, 0x0001, 0x8202}, /* clock rate compensation = 1/25 sec/frame */ + {0x0c, 0x0004, 0x0000}, + /* set interface */ + {} +}; +static const __u16 Clicksmart510_defaults[][3] = { + {0x00, 0x00, 0x8211}, + {0x00, 0x01, 0x82c0}, + {0x00, 0x10, 0x82cb}, + {0x00, 0x0f, 0x800d}, + {0x00, 0x82, 0x8225}, + {0x00, 0x21, 0x8228}, + {0x00, 0x00, 0x8203}, + {0x00, 0x00, 0x8204}, + {0x00, 0x08, 0x8205}, + {0x00, 0xf8, 0x8206}, + {0x00, 0x28, 0x8207}, + {0x00, 0xa0, 0x8208}, + {0x00, 0x08, 0x824a}, + {0x00, 0x08, 0x8214}, + {0x00, 0x80, 0x82c1}, + {0x00, 0x00, 0x82c2}, + {0x00, 0x00, 0x82ca}, + {0x00, 0x80, 0x82c1}, + {0x00, 0x04, 0x82c2}, + {0x00, 0x00, 0x82ca}, + {0x00, 0xfc, 0x8100}, + {0x00, 0xfc, 0x8105}, + {0x00, 0x30, 0x8101}, + {0x00, 0x00, 0x8102}, + {0x00, 0x00, 0x8103}, + {0x00, 0x66, 0x8107}, + {0x00, 0x00, 0x816b}, + {0x00, 0x00, 0x8155}, + {0x00, 0x01, 0x8156}, + {0x00, 0x60, 0x8157}, + {0x00, 0x40, 0x8158}, + {0x00, 0x0a, 0x8159}, + {0x00, 0x06, 0x815a}, + {0x00, 0x00, 0x813f}, + {0x00, 0x00, 0x8200}, + {0x00, 0x19, 0x8201}, + {0x00, 0x00, 0x82c1}, + {0x00, 0xa0, 0x82c2}, + {0x00, 0x00, 0x82ca}, + {0x00, 0x00, 0x8117}, + {0x00, 0x00, 0x8118}, + {0x00, 0x65, 0x8119}, + {0x00, 0x00, 0x811a}, + {0x00, 0x00, 0x811b}, + {0x00, 0x55, 0x811c}, + {0x00, 0x65, 0x811d}, + {0x00, 0x55, 0x811e}, + {0x00, 0x16, 0x811f}, + {0x00, 0x19, 0x8120}, + {0x00, 0x80, 0x8103}, + {0x00, 0x83, 0x816b}, + {0x00, 0x25, 0x8168}, + {0x00, 0x01, 0x820f}, + {0x00, 0xff, 0x8115}, + {0x00, 0x48, 0x8116}, + {0x00, 0x50, 0x8151}, + {0x00, 0x40, 0x8152}, + {0x00, 0x78, 0x8153}, + {0x00, 0x40, 0x8154}, + {0x00, 0x00, 0x8167}, + {0x00, 0x20, 0x8168}, + {0x00, 0x00, 0x816a}, + {0x00, 0x03, 0x816b}, + {0x00, 0x20, 0x8169}, + {0x00, 0x60, 0x8157}, + {0x00, 0x00, 0x8190}, + {0x00, 0x00, 0x81a1}, + {0x00, 0x00, 0x81b2}, + {0x00, 0x27, 0x8191}, + {0x00, 0x27, 0x81a2}, + {0x00, 0x27, 0x81b3}, + {0x00, 0x4b, 0x8192}, + {0x00, 0x4b, 0x81a3}, + {0x00, 0x4b, 0x81b4}, + {0x00, 0x66, 0x8193}, + {0x00, 0x66, 0x81a4}, + {0x00, 0x66, 0x81b5}, + {0x00, 0x79, 0x8194}, + {0x00, 0x79, 0x81a5}, + {0x00, 0x79, 0x81b6}, + {0x00, 0x8a, 0x8195}, + {0x00, 0x8a, 0x81a6}, + {0x00, 0x8a, 0x81b7}, + {0x00, 0x9b, 0x8196}, + {0x00, 0x9b, 0x81a7}, + {0x00, 0x9b, 0x81b8}, + {0x00, 0xa6, 0x8197}, + {0x00, 0xa6, 0x81a8}, + {0x00, 0xa6, 0x81b9}, + {0x00, 0xb2, 0x8198}, + {0x00, 0xb2, 0x81a9}, + {0x00, 0xb2, 0x81ba}, + {0x00, 0xbe, 0x8199}, + {0x00, 0xbe, 0x81aa}, + {0x00, 0xbe, 0x81bb}, + {0x00, 0xc8, 0x819a}, + {0x00, 0xc8, 0x81ab}, + {0x00, 0xc8, 0x81bc}, + {0x00, 0xd2, 0x819b}, + {0x00, 0xd2, 0x81ac}, + {0x00, 0xd2, 0x81bd}, + {0x00, 0xdb, 0x819c}, + {0x00, 0xdb, 0x81ad}, + {0x00, 0xdb, 0x81be}, + {0x00, 0xe4, 0x819d}, + {0x00, 0xe4, 0x81ae}, + {0x00, 0xe4, 0x81bf}, + {0x00, 0xed, 0x819e}, + {0x00, 0xed, 0x81af}, + {0x00, 0xed, 0x81c0}, + {0x00, 0xf7, 0x819f}, + {0x00, 0xf7, 0x81b0}, + {0x00, 0xf7, 0x81c1}, + {0x00, 0xff, 0x81a0}, + {0x00, 0xff, 0x81b1}, + {0x00, 0xff, 0x81c2}, + {0x00, 0x03, 0x8156}, + {0x00, 0x00, 0x8211}, + {0x00, 0x20, 0x8168}, + {0x00, 0x01, 0x8202}, + {0x00, 0x30, 0x8101}, + {0x00, 0x00, 0x8111}, + {0x00, 0x00, 0x8112}, + {0x00, 0x00, 0x8113}, + {0x00, 0x00, 0x8114}, + {} +}; + +static const __u8 qtable_creative_pccam[2][64] = { + { /* Q-table Y-components */ + 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, + 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, + 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, + 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, + 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, + 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, + 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, + 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e}, + { /* Q-table C-components */ + 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, + 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} +}; + +static const __u8 qtable_kodak_ez200[2][64] = { + { /* Q-table Y-components */ + 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06, + 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06, + 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06, + 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08, + 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09, + 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a, + 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a}, + { /* Q-table C-components */ + 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a, + 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, + 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a} +}; + +static const __u8 qtable_pocketdv[2][64] = { + { /* Q-table Y-components start registers 0x8800 */ + 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18, + 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16, + 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16, + 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19, + 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f, + 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25, + 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28, + 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28, + }, + { /* Q-table C-components start registers 0x8840 */ + 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28, + 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28, + 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28} +}; + +/* read 'len' bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 index, + __u16 length) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, length, 500); +} + +static int reg_w(struct gspca_dev *gspca_dev, + __u16 req, __u16 index, __u16 value) +{ + int ret; + + PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x", index, value); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + if (ret < 0) + err("reg write: error %d", ret); + return ret; +} + +/* returns: negative is error, pos or zero is data */ +static int reg_r_12(struct gspca_dev *gspca_dev, + __u16 req, /* bRequest */ + __u16 index, /* wIndex */ + __u16 length) /* wLength (1 or 2 only) */ +{ + int ret; + + gspca_dev->usb_buf[1] = 0; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + gspca_dev->usb_buf, length, + 500); /* timeout */ + if (ret < 0) { + err("reg_r_12 err %d", ret); + return ret; + } + return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; +} + +/* + * Simple function to wait for a given 8-bit value to be returned from + * a reg_read call. + * Returns: negative is error or timeout, zero is success. + */ +static int reg_r_wait(struct gspca_dev *gspca_dev, + __u16 reg, __u16 index, __u16 value) +{ + int ret, cnt = 20; + + while (--cnt > 0) { + ret = reg_r_12(gspca_dev, reg, index, 1); + if (ret == value) + return 0; + msleep(50); + } + return -EIO; +} + +static int write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][3]) +{ + int ret, i = 0; + + while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { + ret = reg_w(gspca_dev, data[i][0], data[i][2], data[i][1]); + if (ret < 0) + return ret; + i++; + } + return 0; +} + +static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, + unsigned int request, + unsigned int ybase, + unsigned int cbase, + const __u8 qtable[2][64]) +{ + int i, err; + + /* loop over y components */ + for (i = 0; i < 64; i++) { + err = reg_w(gspca_dev, request, ybase + i, qtable[0][i]); + if (err < 0) + return err; + } + + /* loop over c components */ + for (i = 0; i < 64; i++) { + err = reg_w(gspca_dev, request, cbase + i, qtable[1][i]); + if (err < 0) + return err; + } + return 0; +} + +static void spca500_ping310(struct gspca_dev *gspca_dev) +{ + reg_r(gspca_dev, 0x0d04, 2); + PDEBUG(D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); +} + +static void spca500_clksmart310_init(struct gspca_dev *gspca_dev) +{ + reg_r(gspca_dev, 0x0d05, 2); + PDEBUG(D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); + reg_w(gspca_dev, 0x00, 0x8167, 0x5a); + spca500_ping310(gspca_dev); + + reg_w(gspca_dev, 0x00, 0x8168, 0x22); + reg_w(gspca_dev, 0x00, 0x816a, 0xc0); + reg_w(gspca_dev, 0x00, 0x816b, 0x0b); + reg_w(gspca_dev, 0x00, 0x8169, 0x25); + reg_w(gspca_dev, 0x00, 0x8157, 0x5b); + reg_w(gspca_dev, 0x00, 0x8158, 0x5b); + reg_w(gspca_dev, 0x00, 0x813f, 0x03); + reg_w(gspca_dev, 0x00, 0x8151, 0x4a); + reg_w(gspca_dev, 0x00, 0x8153, 0x78); + reg_w(gspca_dev, 0x00, 0x0d01, 0x04); + /* 00 for adjust shutter */ + reg_w(gspca_dev, 0x00, 0x0d02, 0x01); + reg_w(gspca_dev, 0x00, 0x8169, 0x25); + reg_w(gspca_dev, 0x00, 0x0d01, 0x02); +} + +static void spca500_setmode(struct gspca_dev *gspca_dev, + __u8 xmult, __u8 ymult) +{ + int mode; + + /* set x multiplier */ + reg_w(gspca_dev, 0, 0x8001, xmult); + + /* set y multiplier */ + reg_w(gspca_dev, 0, 0x8002, ymult); + + /* use compressed mode, VGA, with mode specific subsample */ + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + reg_w(gspca_dev, 0, 0x8003, mode << 4); +} + +static int spca500_full_reset(struct gspca_dev *gspca_dev) +{ + int err; + + /* send the reset command */ + err = reg_w(gspca_dev, 0xe0, 0x0001, 0x0000); + if (err < 0) + return err; + + /* wait for the reset to complete */ + err = reg_r_wait(gspca_dev, 0x06, 0x0000, 0x0000); + if (err < 0) + return err; + err = reg_w(gspca_dev, 0xe0, 0x0000, 0x0000); + if (err < 0) + return err; + err = reg_r_wait(gspca_dev, 0x06, 0, 0); + if (err < 0) { + PDEBUG(D_ERR, "reg_r_wait() failed"); + return err; + } + /* all ok */ + return 0; +} + +/* Synchro the Bridge with sensor */ +/* Maybe that will work on all spca500 chip */ +/* because i only own a clicksmart310 try for that chip */ +/* using spca50x_set_packet_size() cause an Ooops here */ +/* usb_set_interface from kernel 2.6.x clear all the urb stuff */ +/* up-port the same feature as in 2.4.x kernel */ +static int spca500_synch310(struct gspca_dev *gspca_dev) +{ + if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) { + PDEBUG(D_ERR, "Set packet size: set interface error"); + goto error; + } + spca500_ping310(gspca_dev); + + reg_r(gspca_dev, 0x0d00, 1); + + /* need alt setting here */ + PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt); + + /* Windoze use pipe with altsetting 6 why 7 here */ + if (usb_set_interface(gspca_dev->dev, + gspca_dev->iface, + gspca_dev->alt) < 0) { + PDEBUG(D_ERR, "Set packet size: set interface error"); + goto error; + } + return 0; +error: + return -EBUSY; +} + +static void spca500_reinit(struct gspca_dev *gspca_dev) +{ + int err; + __u8 Data; + + /* some unknown command from Aiptek pocket dv and family300 */ + + reg_w(gspca_dev, 0x00, 0x0d01, 0x01); + reg_w(gspca_dev, 0x00, 0x0d03, 0x00); + reg_w(gspca_dev, 0x00, 0x0d02, 0x01); + + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + + err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840, + qtable_pocketdv); + if (err < 0) + PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init"); + + /* set qtable index */ + reg_w(gspca_dev, 0x00, 0x8880, 2); + /* family cam Quicksmart stuff */ + reg_w(gspca_dev, 0x00, 0x800a, 0x00); + /* Set agc transfer: synced between frames */ + reg_w(gspca_dev, 0x00, 0x820f, 0x01); + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + /*Start init sequence or stream */ + reg_w(gspca_dev, 0, 0x8003, 0x00); + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + msleep(2000); + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) { + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + sd->subtype = id->driver_info; + if (sd->subtype != LogitechClickSmart310) { + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + } else { + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + } + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->quality = QUALITY_DEF; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* initialisation of spca500 based cameras is deferred */ + PDEBUG(D_STREAM, "SPCA500 init"); + if (sd->subtype == LogitechClickSmart310) + spca500_clksmart310_init(gspca_dev); +/* else + spca500_initialise(gspca_dev); */ + PDEBUG(D_STREAM, "SPCA500 init done"); + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err; + __u8 Data; + __u8 xmult, ymult; + + /* create the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x22); /* JPEG 411 */ + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + if (sd->subtype == LogitechClickSmart310) { + xmult = 0x16; + ymult = 0x12; + } else { + xmult = 0x28; + ymult = 0x1e; + } + + /* is there a sensor here ? */ + reg_r(gspca_dev, 0x8a04, 1); + PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02x", + gspca_dev->usb_buf[0]); + PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02x, Ymult: 0x%02x", + gspca_dev->curr_mode, xmult, ymult); + + /* setup qtable */ + switch (sd->subtype) { + case LogitechClickSmart310: + spca500_setmode(gspca_dev, xmult, ymult); + + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + reg_w(gspca_dev, 0x00, 0x8880, 3); + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, + qtable_creative_pccam); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + msleep(500); + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) + PDEBUG(D_ERR, "reg_r_wait() failed"); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + + spca500_synch310(gspca_dev); + + write_vector(gspca_dev, spca500_visual_defaults); + spca500_setmode(gspca_dev, xmult, ymult); + /* enable drop packet */ + err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + if (err < 0) + PDEBUG(D_ERR, "failed to enable drop packet"); + reg_w(gspca_dev, 0x00, 0x8880, 3); + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, + qtable_creative_pccam); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) + PDEBUG(D_ERR, "reg_r_wait() failed"); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + break; + case CreativePCCam300: /* Creative PC-CAM 300 640x480 CCD */ + case IntelPocketPCCamera: /* FIXME: Temporary fix for + * Intel Pocket PC Camera + * - NWG (Sat 29th March 2003) */ + + /* do a full reset */ + err = spca500_full_reset(gspca_dev); + if (err < 0) + PDEBUG(D_ERR, "spca500_full_reset failed"); + + /* enable drop packet */ + err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + if (err < 0) + PDEBUG(D_ERR, "failed to enable drop packet"); + reg_w(gspca_dev, 0x00, 0x8880, 3); + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, + qtable_creative_pccam); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + + spca500_setmode(gspca_dev, xmult, ymult); + reg_w(gspca_dev, 0x20, 0x0001, 0x0004); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) + PDEBUG(D_ERR, "reg_r_wait() failed"); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + +/* write_vector(gspca_dev, spca500_visual_defaults); */ + break; + case KodakEZ200: /* Kodak EZ200 */ + + /* do a full reset */ + err = spca500_full_reset(gspca_dev); + if (err < 0) + PDEBUG(D_ERR, "spca500_full_reset failed"); + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + reg_w(gspca_dev, 0x00, 0x8880, 0); + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, + qtable_kodak_ez200); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + spca500_setmode(gspca_dev, xmult, ymult); + + reg_w(gspca_dev, 0x20, 0x0001, 0x0004); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + + if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) + PDEBUG(D_ERR, "reg_r_wait() failed"); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + +/* write_vector(gspca_dev, spca500_visual_defaults); */ + break; + + case BenqDC1016: + case DLinkDSC350: /* FamilyCam 300 */ + case AiptekPocketDV: /* Aiptek PocketDV */ + case Gsmartmini: /*Mustek Gsmart Mini */ + case MustekGsmart300: /* Mustek Gsmart 300 */ + case PalmPixDC85: + case Optimedia: + case ToptroIndus: + case AgfaCl20: + spca500_reinit(gspca_dev); + reg_w(gspca_dev, 0x00, 0x0d01, 0x01); + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, 0x8840, qtable_pocketdv); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + reg_w(gspca_dev, 0x00, 0x8880, 2); + + /* familycam Quicksmart pocketDV stuff */ + reg_w(gspca_dev, 0x00, 0x800a, 0x00); + /* Set agc transfer: synced between frames */ + reg_w(gspca_dev, 0x00, 0x820f, 0x01); + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + + spca500_setmode(gspca_dev, xmult, ymult); + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + + reg_r_wait(gspca_dev, 0, 0x8000, 0x44); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + break; + case LogitechTraveler: + case LogitechClickSmart510: + reg_w(gspca_dev, 0x02, 0x00, 0x00); + /* enable drop packet */ + reg_w(gspca_dev, 0x00, 0x850a, 0x0001); + + err = spca50x_setup_qtable(gspca_dev, + 0x00, 0x8800, + 0x8840, qtable_creative_pccam); + if (err < 0) + PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + reg_w(gspca_dev, 0x00, 0x8880, 3); + reg_w(gspca_dev, 0x00, 0x800a, 0x00); + /* Init SDRAM - needed for SDRAM access */ + reg_w(gspca_dev, 0x00, 0x870a, 0x04); + + spca500_setmode(gspca_dev, xmult, ymult); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + reg_r_wait(gspca_dev, 0, 0x8000, 0x44); + + reg_r(gspca_dev, 0x816b, 1); + Data = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, 0x00, 0x816b, Data); + write_vector(gspca_dev, Clicksmart510_defaults); + break; + } + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, 0, 0x8003, 0x00); + + /* switch to video camera mode */ + reg_w(gspca_dev, 0x00, 0x8000, 0x0004); + reg_r(gspca_dev, 0x8000, 1); + PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x", + gspca_dev->usb_buf[0]); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + static __u8 ffd9[] = {0xff, 0xd9}; + +/* frames are jpeg 4.1.1 without 0xff escape */ + if (data[0] == 0xff) { + if (data[1] != 0x01) { /* drop packet */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + gspca_frame_add(gspca_dev, LAST_PACKET, + ffd9, 2); + + /* put the JPEG header in the new frame */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + + data += SPCA500_OFFSET_DATA; + len -= SPCA500_OFFSET_DATA; + } else { + data += 1; + len -= 1; + } + + /* add 0x00 after 0xff */ + i = 0; + do { + if (data[i] == 0xff) { + gspca_frame_add(gspca_dev, INTER_PACKET, + data, i + 1); + len -= i; + data += i; + *data = 0x00; + i = 0; + } + i++; + } while (i < len); + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0x00, 0x8167, + (__u8) (sd->brightness - 128)); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0x00, 0x8168, sd->contrast); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, 0x00, 0x8169, sd->colors); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (jcomp->quality < QUALITY_MIN) + sd->quality = QUALITY_MIN; + else if (jcomp->quality > QUALITY_MAX) + sd->quality = QUALITY_MAX; + else + sd->quality = jcomp->quality; + if (gspca_dev->streaming) + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + return 0; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200}, + {USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300}, + {USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler}, + {USB_DEVICE(0x046d, 0x0900), .driver_info = LogitechClickSmart310}, + {USB_DEVICE(0x046d, 0x0901), .driver_info = LogitechClickSmart510}, + {USB_DEVICE(0x04a5, 0x300c), .driver_info = BenqDC1016}, + {USB_DEVICE(0x04fc, 0x7333), .driver_info = PalmPixDC85}, + {USB_DEVICE(0x055f, 0xc200), .driver_info = MustekGsmart300}, + {USB_DEVICE(0x055f, 0xc220), .driver_info = Gsmartmini}, + {USB_DEVICE(0x06bd, 0x0404), .driver_info = AgfaCl20}, + {USB_DEVICE(0x06be, 0x0800), .driver_info = Optimedia}, + {USB_DEVICE(0x084d, 0x0003), .driver_info = DLinkDSC350}, + {USB_DEVICE(0x08ca, 0x0103), .driver_info = AiptekPocketDV}, + {USB_DEVICE(0x2899, 0x012c), .driver_info = ToptroIndus}, + {USB_DEVICE(0x8086, 0x0630), .driver_info = IntelPocketPCCamera}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca501.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca501.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca501.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca501.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2200 @@ +/* + * SPCA501 chip based cameras initialization data + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + * + */ + +#define MODULE_NAME "spca501" + +#include "gspca.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA/SPCA501 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned short contrast; + __u8 brightness; + __u8 colors; + __u8 blue_balance; + __u8 red_balance; + + char subtype; +#define Arowana300KCMOSCamera 0 +#define IntelCreateAndShare 1 +#define KodakDVC325 2 +#define MystFromOriUnknownCamera 3 +#define SmileIntlCamera 4 +#define ThreeComHomeConnectLite 5 +#define ViewQuestM318B 6 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { +#define MY_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define MY_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 64725, + .step = 1, + .default_value = 64725, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define MY_COLOR 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 63, + .step = 1, + .default_value = 20, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +#define MY_BLUE_BALANCE 3 + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0, + }, + .set = sd_setblue_balance, + .get = sd_getblue_balance, + }, +#define MY_RED_BALANCE 4 + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0, + }, + .set = sd_setred_balance, + .get = sd_getred_balance, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +#define SPCA50X_REG_USB 0x2 /* spca505 501 */ +/* + * Data to initialize a SPCA501. From a capture file provided by Bill Roehl + * With SPCA501 chip description + */ +#define CCDSP_SET /* set CCDSP parameters */ +#define TG_SET /* set time generator set */ +#undef DSPWIN_SET /* set DSP windows parameters */ +#undef ALTER_GAMA /* Set alternate set to YUV transform coeffs. */ +#define SPCA501_SNAPBIT 0x80 +#define SPCA501_SNAPCTRL 0x10 +/* Frame packet header offsets for the spca501 */ +#define SPCA501_OFFSET_GPIO 1 +#define SPCA501_OFFSET_TYPE 2 +#define SPCA501_OFFSET_TURN3A 3 +#define SPCA501_OFFSET_FRAMSEQ 4 +#define SPCA501_OFFSET_COMPRESS 5 +#define SPCA501_OFFSET_QUANT 6 +#define SPCA501_OFFSET_QUANT2 7 +#define SPCA501_OFFSET_DATA 8 + +#define SPCA501_PROP_COMP_ENABLE(d) ((d) & 1) +#define SPCA501_PROP_SNAP(d) ((d) & 0x40) +#define SPCA501_PROP_SNAP_CTRL(d) ((d) & 0x10) +#define SPCA501_PROP_COMP_THRESH(d) (((d) & 0x0e) >> 1) +#define SPCA501_PROP_COMP_QUANT(d) (((d) & 0x70) >> 4) + +/* SPCA501 CCDSP control */ +#define SPCA501_REG_CCDSP 0x01 +/* SPCA501 control/status registers */ +#define SPCA501_REG_CTLRL 0x02 + +/* registers for color correction and YUV transformation */ +#define SPCA501_A11 0x08 +#define SPCA501_A12 0x09 +#define SPCA501_A13 0x0A +#define SPCA501_A21 0x0B +#define SPCA501_A22 0x0C +#define SPCA501_A23 0x0D +#define SPCA501_A31 0x0E +#define SPCA501_A32 0x0F +#define SPCA501_A33 0x10 + +/* Data for video camera initialization before capturing */ +static const __u16 spca501_open_data[][3] = { + /* bmRequest,value,index */ + + {0x2, 0x50, 0x00}, /* C/S enable soft reset */ + {0x2, 0x40, 0x00}, /* C/S disable soft reset */ + {0x2, 0x02, 0x05}, /* C/S general purpose I/O data */ + {0x2, 0x03, 0x05}, /* C/S general purpose I/O data */ + +#ifdef CCDSP_SET + {0x1, 0x38, 0x01}, /* CCDSP options */ + {0x1, 0x05, 0x02}, /* CCDSP Optical black level for user settings */ + {0x1, 0xC0, 0x03}, /* CCDSP Optical black settings */ + + {0x1, 0x67, 0x07}, + {0x1, 0x63, 0x3f}, /* CCDSP CCD gamma enable */ + {0x1, 0x03, 0x56}, /* Add gamma correction */ + + {0x1, 0xFF, 0x15}, /* CCDSP High luminance for white balance */ + {0x1, 0x01, 0x16}, /* CCDSP Low luminance for white balance */ + +/* Color correction and RGB-to-YUV transformation coefficients changing */ +#ifdef ALTER_GAMA + {0x0, 0x00, 0x08}, /* A11 */ + {0x0, 0x00, 0x09}, /* A12 */ + {0x0, 0x90, 0x0A}, /* A13 */ + {0x0, 0x12, 0x0B}, /* A21 */ + {0x0, 0x00, 0x0C}, /* A22 */ + {0x0, 0x00, 0x0D}, /* A23 */ + {0x0, 0x00, 0x0E}, /* A31 */ + {0x0, 0x02, 0x0F}, /* A32 */ + {0x0, 0x00, 0x10}, /* A33 */ +#else + {0x1, 0x2a, 0x08}, /* A11 0x31 */ + {0x1, 0xf8, 0x09}, /* A12 f8 */ + {0x1, 0xf8, 0x0A}, /* A13 f8 */ + {0x1, 0xf8, 0x0B}, /* A21 f8 */ + {0x1, 0x14, 0x0C}, /* A22 0x14 */ + {0x1, 0xf8, 0x0D}, /* A23 f8 */ + {0x1, 0xf8, 0x0E}, /* A31 f8 */ + {0x1, 0xf8, 0x0F}, /* A32 f8 */ + {0x1, 0x20, 0x10}, /* A33 0x20 */ +#endif + {0x1, 0x00, 0x11}, /* R offset */ + {0x1, 0x00, 0x12}, /* G offset */ + {0x1, 0x00, 0x13}, /* B offset */ + {0x1, 0x00, 0x14}, /* GB offset */ + +#endif + +#ifdef TG_SET + /* Time generator manipulations */ + {0x0, 0xfc, 0x0}, /* Set up high bits of shutter speed */ + {0x0, 0x01, 0x1}, /* Set up low bits of shutter speed */ + + {0x0, 0xe4, 0x04}, /* DCLK*2 clock phase adjustment */ + {0x0, 0x08, 0x05}, /* ADCK phase adjustment, inv. ext. VB */ + {0x0, 0x03, 0x06}, /* FR phase adjustment */ + {0x0, 0x01, 0x07}, /* FCDS phase adjustment */ + {0x0, 0x39, 0x08}, /* FS phase adjustment */ + {0x0, 0x88, 0x0a}, /* FH1 phase and delay adjustment */ + {0x0, 0x03, 0x0f}, /* pixel identification */ + {0x0, 0x00, 0x11}, /* clock source selection (default) */ + + /*VERY strange manipulations with + * select DMCLP or OBPX to be ADCLP output (0x0C) + * OPB always toggle or not (0x0D) but they allow + * us to set up brightness + */ + {0x0, 0x01, 0x0c}, + {0x0, 0xe0, 0x0d}, + /* Done */ +#endif + +#ifdef DSPWIN_SET + {0x1, 0xa0, 0x01}, /* Setting image processing parameters */ + {0x1, 0x1c, 0x17}, /* Changing Windows positions X1 */ + {0x1, 0xe2, 0x19}, /* X2 */ + {0x1, 0x1c, 0x1b}, /* X3 */ + {0x1, 0xe2, 0x1d}, /* X4 */ + {0x1, 0x5f, 0x1f}, /* X5 */ + {0x1, 0x32, 0x20}, /* Y5 */ + {0x1, 0x01, 0x10}, /* Changing A33 */ +#endif + + {0x2, 0x204a, 0x07},/* Setting video compression & resolution 160x120 */ + {0x2, 0x94, 0x06}, /* Setting video no compression */ + {} +}; + +/* + The SPCAxxx docs from Sunplus document these values + in tables, one table per register number. In the data + below, dmRequest is the register number, index is the Addr, + and value is a combination of Bit values. + Bit Value (hex) + 0 01 + 1 02 + 2 04 + 3 08 + 4 10 + 5 20 + 6 40 + 7 80 + */ + +/* Data for chip initialization (set default values) */ +static const __u16 spca501_init_data[][3] = { + /* Set all the values to powerup defaults */ + /* bmRequest,value,index */ + {0x0, 0xAA, 0x00}, + {0x0, 0x02, 0x01}, + {0x0, 0x01, 0x02}, + {0x0, 0x02, 0x03}, + {0x0, 0xCE, 0x04}, + {0x0, 0x00, 0x05}, + {0x0, 0x00, 0x06}, + {0x0, 0x00, 0x07}, + {0x0, 0x00, 0x08}, + {0x0, 0x00, 0x09}, + {0x0, 0x90, 0x0A}, + {0x0, 0x12, 0x0B}, + {0x0, 0x00, 0x0C}, + {0x0, 0x00, 0x0D}, + {0x0, 0x00, 0x0E}, + {0x0, 0x02, 0x0F}, + {0x0, 0x00, 0x10}, + {0x0, 0x00, 0x11}, + {0x0, 0x00, 0x12}, + {0x0, 0x00, 0x13}, + {0x0, 0x00, 0x14}, + {0x0, 0x00, 0x15}, + {0x0, 0x00, 0x16}, + {0x0, 0x00, 0x17}, + {0x0, 0x00, 0x18}, + {0x0, 0x00, 0x19}, + {0x0, 0x00, 0x1A}, + {0x0, 0x00, 0x1B}, + {0x0, 0x00, 0x1C}, + {0x0, 0x00, 0x1D}, + {0x0, 0x00, 0x1E}, + {0x0, 0x00, 0x1F}, + {0x0, 0x00, 0x20}, + {0x0, 0x00, 0x21}, + {0x0, 0x00, 0x22}, + {0x0, 0x00, 0x23}, + {0x0, 0x00, 0x24}, + {0x0, 0x00, 0x25}, + {0x0, 0x00, 0x26}, + {0x0, 0x00, 0x27}, + {0x0, 0x00, 0x28}, + {0x0, 0x00, 0x29}, + {0x0, 0x00, 0x2A}, + {0x0, 0x00, 0x2B}, + {0x0, 0x00, 0x2C}, + {0x0, 0x00, 0x2D}, + {0x0, 0x00, 0x2E}, + {0x0, 0x00, 0x2F}, + {0x0, 0x00, 0x30}, + {0x0, 0x00, 0x31}, + {0x0, 0x00, 0x32}, + {0x0, 0x00, 0x33}, + {0x0, 0x00, 0x34}, + {0x0, 0x00, 0x35}, + {0x0, 0x00, 0x36}, + {0x0, 0x00, 0x37}, + {0x0, 0x00, 0x38}, + {0x0, 0x00, 0x39}, + {0x0, 0x00, 0x3A}, + {0x0, 0x00, 0x3B}, + {0x0, 0x00, 0x3C}, + {0x0, 0x00, 0x3D}, + {0x0, 0x00, 0x3E}, + {0x0, 0x00, 0x3F}, + {0x0, 0x00, 0x40}, + {0x0, 0x00, 0x41}, + {0x0, 0x00, 0x42}, + {0x0, 0x00, 0x43}, + {0x0, 0x00, 0x44}, + {0x0, 0x00, 0x45}, + {0x0, 0x00, 0x46}, + {0x0, 0x00, 0x47}, + {0x0, 0x00, 0x48}, + {0x0, 0x00, 0x49}, + {0x0, 0x00, 0x4A}, + {0x0, 0x00, 0x4B}, + {0x0, 0x00, 0x4C}, + {0x0, 0x00, 0x4D}, + {0x0, 0x00, 0x4E}, + {0x0, 0x00, 0x4F}, + {0x0, 0x00, 0x50}, + {0x0, 0x00, 0x51}, + {0x0, 0x00, 0x52}, + {0x0, 0x00, 0x53}, + {0x0, 0x00, 0x54}, + {0x0, 0x00, 0x55}, + {0x0, 0x00, 0x56}, + {0x0, 0x00, 0x57}, + {0x0, 0x00, 0x58}, + {0x0, 0x00, 0x59}, + {0x0, 0x00, 0x5A}, + {0x0, 0x00, 0x5B}, + {0x0, 0x00, 0x5C}, + {0x0, 0x00, 0x5D}, + {0x0, 0x00, 0x5E}, + {0x0, 0x00, 0x5F}, + {0x0, 0x00, 0x60}, + {0x0, 0x00, 0x61}, + {0x0, 0x00, 0x62}, + {0x0, 0x00, 0x63}, + {0x0, 0x00, 0x64}, + {0x0, 0x00, 0x65}, + {0x0, 0x00, 0x66}, + {0x0, 0x00, 0x67}, + {0x0, 0x00, 0x68}, + {0x0, 0x00, 0x69}, + {0x0, 0x00, 0x6A}, + {0x0, 0x00, 0x6B}, + {0x0, 0x00, 0x6C}, + {0x0, 0x00, 0x6D}, + {0x0, 0x00, 0x6E}, + {0x0, 0x00, 0x6F}, + {0x0, 0x00, 0x70}, + {0x0, 0x00, 0x71}, + {0x0, 0x00, 0x72}, + {0x0, 0x00, 0x73}, + {0x0, 0x00, 0x74}, + {0x0, 0x00, 0x75}, + {0x0, 0x00, 0x76}, + {0x0, 0x00, 0x77}, + {0x0, 0x00, 0x78}, + {0x0, 0x00, 0x79}, + {0x0, 0x00, 0x7A}, + {0x0, 0x00, 0x7B}, + {0x0, 0x00, 0x7C}, + {0x0, 0x00, 0x7D}, + {0x0, 0x00, 0x7E}, + {0x0, 0x00, 0x7F}, + {0x0, 0x00, 0x80}, + {0x0, 0x00, 0x81}, + {0x0, 0x00, 0x82}, + {0x0, 0x00, 0x83}, + {0x0, 0x00, 0x84}, + {0x0, 0x00, 0x85}, + {0x0, 0x00, 0x86}, + {0x0, 0x00, 0x87}, + {0x0, 0x00, 0x88}, + {0x0, 0x00, 0x89}, + {0x0, 0x00, 0x8A}, + {0x0, 0x00, 0x8B}, + {0x0, 0x00, 0x8C}, + {0x0, 0x00, 0x8D}, + {0x0, 0x00, 0x8E}, + {0x0, 0x00, 0x8F}, + {0x0, 0x00, 0x90}, + {0x0, 0x00, 0x91}, + {0x0, 0x00, 0x92}, + {0x0, 0x00, 0x93}, + {0x0, 0x00, 0x94}, + {0x0, 0x00, 0x95}, + {0x0, 0x00, 0x96}, + {0x0, 0x00, 0x97}, + {0x0, 0x00, 0x98}, + {0x0, 0x00, 0x99}, + {0x0, 0x00, 0x9A}, + {0x0, 0x00, 0x9B}, + {0x0, 0x00, 0x9C}, + {0x0, 0x00, 0x9D}, + {0x0, 0x00, 0x9E}, + {0x0, 0x00, 0x9F}, + {0x0, 0x00, 0xA0}, + {0x0, 0x00, 0xA1}, + {0x0, 0x00, 0xA2}, + {0x0, 0x00, 0xA3}, + {0x0, 0x00, 0xA4}, + {0x0, 0x00, 0xA5}, + {0x0, 0x00, 0xA6}, + {0x0, 0x00, 0xA7}, + {0x0, 0x00, 0xA8}, + {0x0, 0x00, 0xA9}, + {0x0, 0x00, 0xAA}, + {0x0, 0x00, 0xAB}, + {0x0, 0x00, 0xAC}, + {0x0, 0x00, 0xAD}, + {0x0, 0x00, 0xAE}, + {0x0, 0x00, 0xAF}, + {0x0, 0x00, 0xB0}, + {0x0, 0x00, 0xB1}, + {0x0, 0x00, 0xB2}, + {0x0, 0x00, 0xB3}, + {0x0, 0x00, 0xB4}, + {0x0, 0x00, 0xB5}, + {0x0, 0x00, 0xB6}, + {0x0, 0x00, 0xB7}, + {0x0, 0x00, 0xB8}, + {0x0, 0x00, 0xB9}, + {0x0, 0x00, 0xBA}, + {0x0, 0x00, 0xBB}, + {0x0, 0x00, 0xBC}, + {0x0, 0x00, 0xBD}, + {0x0, 0x00, 0xBE}, + {0x0, 0x00, 0xBF}, + {0x0, 0x00, 0xC0}, + {0x0, 0x00, 0xC1}, + {0x0, 0x00, 0xC2}, + {0x0, 0x00, 0xC3}, + {0x0, 0x00, 0xC4}, + {0x0, 0x00, 0xC5}, + {0x0, 0x00, 0xC6}, + {0x0, 0x00, 0xC7}, + {0x0, 0x00, 0xC8}, + {0x0, 0x00, 0xC9}, + {0x0, 0x00, 0xCA}, + {0x0, 0x00, 0xCB}, + {0x0, 0x00, 0xCC}, + {0x1, 0xF4, 0x00}, + {0x1, 0x38, 0x01}, + {0x1, 0x40, 0x02}, + {0x1, 0x0A, 0x03}, + {0x1, 0x40, 0x04}, + {0x1, 0x40, 0x05}, + {0x1, 0x40, 0x06}, + {0x1, 0x67, 0x07}, + {0x1, 0x31, 0x08}, + {0x1, 0x00, 0x09}, + {0x1, 0x00, 0x0A}, + {0x1, 0x00, 0x0B}, + {0x1, 0x14, 0x0C}, + {0x1, 0x00, 0x0D}, + {0x1, 0x00, 0x0E}, + {0x1, 0x00, 0x0F}, + {0x1, 0x1E, 0x10}, + {0x1, 0x00, 0x11}, + {0x1, 0x00, 0x12}, + {0x1, 0x00, 0x13}, + {0x1, 0x00, 0x14}, + {0x1, 0xFF, 0x15}, + {0x1, 0x01, 0x16}, + {0x1, 0x32, 0x17}, + {0x1, 0x23, 0x18}, + {0x1, 0xCE, 0x19}, + {0x1, 0x23, 0x1A}, + {0x1, 0x32, 0x1B}, + {0x1, 0x8D, 0x1C}, + {0x1, 0xCE, 0x1D}, + {0x1, 0x8D, 0x1E}, + {0x1, 0x00, 0x1F}, + {0x1, 0x00, 0x20}, + {0x1, 0xFF, 0x3E}, + {0x1, 0x02, 0x3F}, + {0x1, 0x00, 0x40}, + {0x1, 0x00, 0x41}, + {0x1, 0x00, 0x42}, + {0x1, 0x00, 0x43}, + {0x1, 0x00, 0x44}, + {0x1, 0x00, 0x45}, + {0x1, 0x00, 0x46}, + {0x1, 0x00, 0x47}, + {0x1, 0x00, 0x48}, + {0x1, 0x00, 0x49}, + {0x1, 0x00, 0x4A}, + {0x1, 0x00, 0x4B}, + {0x1, 0x00, 0x4C}, + {0x1, 0x00, 0x4D}, + {0x1, 0x00, 0x4E}, + {0x1, 0x00, 0x4F}, + {0x1, 0x00, 0x50}, + {0x1, 0x00, 0x51}, + {0x1, 0x00, 0x52}, + {0x1, 0x00, 0x53}, + {0x1, 0x00, 0x54}, + {0x1, 0x00, 0x55}, + {0x1, 0x00, 0x56}, + {0x1, 0x00, 0x57}, + {0x1, 0x00, 0x58}, + {0x1, 0x00, 0x59}, + {0x1, 0x00, 0x5A}, + {0x2, 0x03, 0x00}, + {0x2, 0x00, 0x01}, + {0x2, 0x00, 0x05}, + {0x2, 0x00, 0x06}, + {0x2, 0x00, 0x07}, + {0x2, 0x00, 0x10}, + {0x2, 0x00, 0x11}, + /* Strange - looks like the 501 driver doesn't do anything + * at insert time except read the EEPROM + */ + {} +}; + +/* Data for video camera init before capture. + * Capture and decoding by Colin Peart. + * This is is for the 3com HomeConnect Lite which is spca501a based. + */ +static const __u16 spca501_3com_open_data[][3] = { + /* bmRequest,value,index */ + {0x2, 0x0050, 0x0000}, /* C/S Enable TG soft reset, timing mode=010 */ + {0x2, 0x0043, 0x0000}, /* C/S Disable TG soft reset, timing mode=010 */ + {0x2, 0x0002, 0x0005}, /* C/S GPIO */ + {0x2, 0x0003, 0x0005}, /* C/S GPIO */ + +#ifdef CCDSP_SET + {0x1, 0x0020, 0x0001}, /* CCDSP Options */ + + {0x1, 0x0020, 0x0002}, /* CCDSP Black Level */ + {0x1, 0x006e, 0x0007}, /* CCDSP Gamma options */ + {0x1, 0x0090, 0x0015}, /* CCDSP Luminance Low */ + {0x1, 0x00ff, 0x0016}, /* CCDSP Luminance High */ + {0x1, 0x0003, 0x003F}, /* CCDSP Gamma correction toggle */ + +#ifdef ALTER_GAMMA + {0x1, 0x0010, 0x0008}, /* CCDSP YUV A11 */ + {0x1, 0x0000, 0x0009}, /* CCDSP YUV A12 */ + {0x1, 0x0000, 0x000a}, /* CCDSP YUV A13 */ + {0x1, 0x0000, 0x000b}, /* CCDSP YUV A21 */ + {0x1, 0x0010, 0x000c}, /* CCDSP YUV A22 */ + {0x1, 0x0000, 0x000d}, /* CCDSP YUV A23 */ + {0x1, 0x0000, 0x000e}, /* CCDSP YUV A31 */ + {0x1, 0x0000, 0x000f}, /* CCDSP YUV A32 */ + {0x1, 0x0010, 0x0010}, /* CCDSP YUV A33 */ + {0x1, 0x0000, 0x0011}, /* CCDSP R Offset */ + {0x1, 0x0000, 0x0012}, /* CCDSP G Offset */ + {0x1, 0x0001, 0x0013}, /* CCDSP B Offset */ + {0x1, 0x0001, 0x0014}, /* CCDSP BG Offset */ + {0x1, 0x003f, 0x00C1}, /* CCDSP Gamma Correction Enable */ +#endif +#endif + +#ifdef TG_SET + {0x0, 0x00fc, 0x0000}, /* TG Shutter Speed High Bits */ + {0x0, 0x0000, 0x0001}, /* TG Shutter Speed Low Bits */ + {0x0, 0x00e4, 0x0004}, /* TG DCLK*2 Adjust */ + {0x0, 0x0008, 0x0005}, /* TG ADCK Adjust */ + {0x0, 0x0003, 0x0006}, /* TG FR Phase Adjust */ + {0x0, 0x0001, 0x0007}, /* TG FCDS Phase Adjust */ + {0x0, 0x0039, 0x0008}, /* TG FS Phase Adjust */ + {0x0, 0x0088, 0x000a}, /* TG MH1 */ + {0x0, 0x0003, 0x000f}, /* TG Pixel ID */ + + /* Like below, unexplained toglleing */ + {0x0, 0x0080, 0x000c}, + {0x0, 0x0000, 0x000d}, + {0x0, 0x0080, 0x000c}, + {0x0, 0x0004, 0x000d}, + {0x0, 0x0000, 0x000c}, + {0x0, 0x0000, 0x000d}, + {0x0, 0x0040, 0x000c}, + {0x0, 0x0017, 0x000d}, + {0x0, 0x00c0, 0x000c}, + {0x0, 0x0000, 0x000d}, + {0x0, 0x0080, 0x000c}, + {0x0, 0x0006, 0x000d}, + {0x0, 0x0080, 0x000c}, + {0x0, 0x0004, 0x000d}, + {0x0, 0x0002, 0x0003}, +#endif + +#ifdef DSPWIN_SET + {0x1, 0x001c, 0x0017}, /* CCDSP W1 Start X */ + {0x1, 0x00e2, 0x0019}, /* CCDSP W2 Start X */ + {0x1, 0x001c, 0x001b}, /* CCDSP W3 Start X */ + {0x1, 0x00e2, 0x001d}, /* CCDSP W4 Start X */ + {0x1, 0x00aa, 0x001f}, /* CCDSP W5 Start X */ + {0x1, 0x0070, 0x0020}, /* CCDSP W5 Start Y */ +#endif + {0x0, 0x0001, 0x0010}, /* TG Start Clock */ + +/* {0x2, 0x006a, 0x0001}, * C/S Enable ISOSYNCH Packet Engine */ + {0x2, 0x0068, 0x0001}, /* C/S Diable ISOSYNCH Packet Engine */ + {0x2, 0x0000, 0x0005}, + {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */ + {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */ + {0x2, 0x0002, 0x0005}, /* C/S GPIO */ + {0x2, 0x0003, 0x0005}, /* C/S GPIO */ + + {0x2, 0x006a, 0x0001}, /* C/S Enable ISOSYNCH Packet Engine */ + {} +}; + +/* + * Data used to initialize a SPCA501C with HV7131B sensor. + * From a capture file taken with USBSnoop v 1.5 + * I have a "SPCA501C pc camera chipset" manual by sunplus, but some + * of the value meanings are obscure or simply "reserved". + * to do list: + * 1) Understand what every value means + * 2) Understand why some values seem to appear more than once + * 3) Write a small comment for each line of the following arrays. + */ +static const __u16 spca501c_arowana_open_data[][3] = { + /* bmRequest,value,index */ + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x01, 0x0006, 0x0011}, + {0x01, 0x00ff, 0x0012}, + {0x01, 0x0014, 0x0013}, + {0x01, 0x0000, 0x0014}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0040, 0x0052}, + {0x01, 0x0051, 0x0053}, + {0x01, 0x0040, 0x0054}, + {0x01, 0x0000, 0x0055}, + {0x00, 0x0025, 0x0000}, + {0x00, 0x0026, 0x0000}, + {0x00, 0x0001, 0x0000}, + {0x00, 0x0027, 0x0000}, + {0x00, 0x008a, 0x0000}, + {} +}; + +static const __u16 spca501c_arowana_init_data[][3] = { + /* bmRequest,value,index */ + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x01, 0x0006, 0x0011}, + {0x01, 0x00ff, 0x0012}, + {0x01, 0x0014, 0x0013}, + {0x01, 0x0000, 0x0014}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0040, 0x0052}, + {0x01, 0x0051, 0x0053}, + {0x01, 0x0040, 0x0054}, + {0x01, 0x0000, 0x0055}, + {0x00, 0x0025, 0x0000}, + {0x00, 0x0026, 0x0000}, + {0x00, 0x0001, 0x0000}, + {0x00, 0x0027, 0x0000}, + {0x00, 0x008a, 0x0000}, + {0x02, 0x0000, 0x0005}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0xfffd, 0x000a}, + {0x01, 0x0023, 0x000b}, + {0x01, 0xffea, 0x000c}, + {0x01, 0xfff4, 0x000d}, + {0x01, 0xfffc, 0x000e}, + {0x01, 0xffe3, 0x000f}, + {0x01, 0x001f, 0x0010}, + {0x01, 0x00a8, 0x0001}, + {0x01, 0x0067, 0x0007}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x00c8, 0x0015}, + {0x01, 0x0032, 0x0016}, + {0x01, 0x0000, 0x0011}, + {0x01, 0x0000, 0x0012}, + {0x01, 0x0000, 0x0013}, + {0x01, 0x000a, 0x0003}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xc000, 0x0001}, + {0x02, 0x0000, 0x0005}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x000f, 0x0000}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0xfffd, 0x000a}, + {0x01, 0x0023, 0x000b}, + {0x01, 0xffea, 0x000c}, + {0x01, 0xfff4, 0x000d}, + {0x01, 0xfffc, 0x000e}, + {0x01, 0xffe3, 0x000f}, + {0x01, 0x001f, 0x0010}, + {0x01, 0x00a8, 0x0001}, + {0x01, 0x0067, 0x0007}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0051, 0x0053}, + {0x01, 0x000a, 0x0003}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xc000, 0x0001}, + {0x02, 0x0000, 0x0005}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x000c, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0000, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, + {0x00, 0x0000, 0x0024}, + {0x00, 0x00d5, 0x0025}, + {0x00, 0x0000, 0x0026}, + {0x00, 0x000b, 0x0027}, + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, + {0xff, 0x0000, 0x00d0}, + {0xff, 0x00d8, 0x00d1}, + {0xff, 0x0000, 0x00d4}, + {0xff, 0x0000, 0x00d5}, + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0x00fd, 0x000a}, + {0x01, 0x0038, 0x000b}, + {0x01, 0x00d1, 0x000c}, + {0x01, 0x00f7, 0x000d}, + {0x01, 0x00ed, 0x000e}, + {0x01, 0x00d8, 0x000f}, + {0x01, 0x0038, 0x0010}, + {0x01, 0x00ff, 0x0015}, + {0x01, 0x0001, 0x0016}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, + {0x01, 0x00ff, 0x003e}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0060, 0x0057}, + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x100a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x001e, 0x0000}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x0011, 0x0008}, + {0x01, 0x0032, 0x0009}, + {0x01, 0xfffd, 0x000a}, + {0x01, 0x0023, 0x000b}, + {0x01, 0xffea, 0x000c}, + {0x01, 0xfff4, 0x000d}, + {0x01, 0xfffc, 0x000e}, + {0x01, 0xffe3, 0x000f}, + {0x01, 0x001f, 0x0010}, + {0x01, 0x00a8, 0x0001}, + {0x01, 0x0067, 0x0007}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0051, 0x0053}, + {0x01, 0x000a, 0x0003}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x0007, 0x0005}, + {0x01, 0x0042, 0x0051}, + {0x01, 0x0051, 0x0053}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x002d, 0x0000}, + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x02, 0xc000, 0x0001}, + {0x02, 0x0000, 0x0005}, + {} +}; + +/* Unknown camera from Ori Usbid 0x0000:0x0000 */ +/* Based on snoops from Ori Cohen */ +static const __u16 spca501c_mysterious_open_data[][3] = { + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, +/* DSP Registers */ + {0x01, 0x0016, 0x0011}, /* RGB offset */ + {0x01, 0x0000, 0x0012}, + {0x01, 0x0006, 0x0013}, + {0x01, 0x0078, 0x0051}, + {0x01, 0x0040, 0x0052}, + {0x01, 0x0046, 0x0053}, + {0x01, 0x0040, 0x0054}, + {0x00, 0x0025, 0x0000}, +/* {0x00, 0x0000, 0x0000 }, */ +/* Part 2 */ +/* TG Registers */ + {0x00, 0x0026, 0x0000}, + {0x00, 0x0001, 0x0000}, + {0x00, 0x0027, 0x0000}, + {0x00, 0x008a, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x2000, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0015, 0x0001}, + {0x05, 0x00ea, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0023, 0x0001}, + {0x05, 0x0003, 0x0000}, + {0x05, 0x0030, 0x0001}, + {0x05, 0x002b, 0x0000}, + {0x05, 0x0031, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0032, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0033, 0x0001}, + {0x05, 0x0023, 0x0000}, + {0x05, 0x0034, 0x0001}, + {0x05, 0x0002, 0x0000}, + {0x05, 0x0050, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0051, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0052, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0054, 0x0001}, + {0x05, 0x0001, 0x0000}, + {} +}; + +/* Based on snoops from Ori Cohen */ +static const __u16 spca501c_mysterious_init_data[][3] = { +/* Part 3 */ +/* TG registers */ +/* {0x00, 0x0000, 0x0000}, */ + {0x00, 0x0000, 0x0001}, + {0x00, 0x0000, 0x0002}, + {0x00, 0x0006, 0x0003}, + {0x00, 0x0000, 0x0004}, + {0x00, 0x0090, 0x0005}, + {0x00, 0x0000, 0x0006}, + {0x00, 0x0040, 0x0007}, + {0x00, 0x00c0, 0x0008}, + {0x00, 0x004a, 0x0009}, + {0x00, 0x0000, 0x000a}, + {0x00, 0x0000, 0x000b}, + {0x00, 0x0001, 0x000c}, + {0x00, 0x0001, 0x000d}, + {0x00, 0x0000, 0x000e}, + {0x00, 0x0002, 0x000f}, + {0x00, 0x0001, 0x0010}, + {0x00, 0x0000, 0x0011}, + {0x00, 0x0001, 0x0012}, + {0x00, 0x0002, 0x0020}, + {0x00, 0x0080, 0x0021}, /* 640 */ + {0x00, 0x0001, 0x0022}, + {0x00, 0x00e0, 0x0023}, /* 480 */ + {0x00, 0x0000, 0x0024}, /* Offset H hight */ + {0x00, 0x00d3, 0x0025}, /* low */ + {0x00, 0x0000, 0x0026}, /* Offset V */ + {0x00, 0x000d, 0x0027}, /* low */ + {0x00, 0x0000, 0x0046}, + {0x00, 0x0000, 0x0047}, + {0x00, 0x0000, 0x0048}, + {0x00, 0x0000, 0x0049}, + {0x00, 0x0008, 0x004a}, +/* DSP Registers */ + {0x01, 0x00a6, 0x0000}, + {0x01, 0x0028, 0x0001}, + {0x01, 0x0000, 0x0002}, + {0x01, 0x000a, 0x0003}, /* Level Calc bit7 ->1 Auto */ + {0x01, 0x0040, 0x0004}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x000f, 0x0008}, /* A11 Color correction coeff */ + {0x01, 0x002d, 0x0009}, /* A12 */ + {0x01, 0x0005, 0x000a}, /* A13 */ + {0x01, 0x0023, 0x000b}, /* A21 */ + {0x01, 0x00e0, 0x000c}, /* A22 */ + {0x01, 0x00fd, 0x000d}, /* A23 */ + {0x01, 0x00f4, 0x000e}, /* A31 */ + {0x01, 0x00e4, 0x000f}, /* A32 */ + {0x01, 0x0028, 0x0010}, /* A33 */ + {0x01, 0x00ff, 0x0015}, /* Reserved */ + {0x01, 0x0001, 0x0016}, /* Reserved */ + {0x01, 0x0032, 0x0017}, /* Win1 Start begin */ + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x0000, 0x001f}, + {0x01, 0x0000, 0x0020}, /* Win1 Start end */ + {0x01, 0x00ff, 0x003e}, /* Reserved begin */ + {0x01, 0x0002, 0x003f}, + {0x01, 0x0000, 0x0040}, + {0x01, 0x0035, 0x0041}, + {0x01, 0x0053, 0x0042}, + {0x01, 0x0069, 0x0043}, + {0x01, 0x007c, 0x0044}, + {0x01, 0x008c, 0x0045}, + {0x01, 0x009a, 0x0046}, + {0x01, 0x00a8, 0x0047}, + {0x01, 0x00b4, 0x0048}, + {0x01, 0x00bf, 0x0049}, + {0x01, 0x00ca, 0x004a}, + {0x01, 0x00d4, 0x004b}, + {0x01, 0x00dd, 0x004c}, + {0x01, 0x00e7, 0x004d}, + {0x01, 0x00ef, 0x004e}, + {0x01, 0x00f8, 0x004f}, + {0x01, 0x00ff, 0x0050}, + {0x01, 0x0003, 0x0056}, /* Reserved end */ + {0x01, 0x0060, 0x0057}, /* Edge Gain */ + {0x01, 0x0040, 0x0058}, + {0x01, 0x0011, 0x0059}, /* Edge Bandwidth */ + {0x01, 0x0001, 0x005a}, + {0x02, 0x0007, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x02, 0x0007, 0x0005}, + {0x02, 0x0015, 0x0006}, + {0x02, 0x200a, 0x0007}, + {0x02, 0xa048, 0x0000}, + {0x02, 0xc000, 0x0001}, + {0x02, 0x000f, 0x0005}, + {0x02, 0xa048, 0x0000}, + {0x05, 0x0022, 0x0004}, + {0x05, 0x0025, 0x0001}, + {0x05, 0x0000, 0x0000}, +/* Part 4 */ + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0001, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x05, 0x0021, 0x0001}, + {0x05, 0x00d2, 0x0000}, + {0x05, 0x0020, 0x0001}, + {0x05, 0x0000, 0x0000}, + {0x00, 0x0090, 0x0005}, + {0x01, 0x00a6, 0x0000}, + {0x02, 0x0000, 0x0005}, + {0x05, 0x0026, 0x0001}, + {0x05, 0x0001, 0x0000}, + {0x05, 0x0027, 0x0001}, + {0x05, 0x004e, 0x0000}, +/* Part 5 */ + {0x01, 0x0003, 0x003f}, + {0x01, 0x0001, 0x0056}, + {0x01, 0x000f, 0x0008}, + {0x01, 0x002d, 0x0009}, + {0x01, 0x0005, 0x000a}, + {0x01, 0x0023, 0x000b}, + {0x01, 0xffe0, 0x000c}, + {0x01, 0xfffd, 0x000d}, + {0x01, 0xfff4, 0x000e}, + {0x01, 0xffe4, 0x000f}, + {0x01, 0x0028, 0x0010}, + {0x01, 0x00a8, 0x0001}, + {0x01, 0x0066, 0x0007}, + {0x01, 0x0032, 0x0017}, + {0x01, 0x0023, 0x0018}, + {0x01, 0x00ce, 0x0019}, + {0x01, 0x0023, 0x001a}, + {0x01, 0x0032, 0x001b}, + {0x01, 0x008d, 0x001c}, + {0x01, 0x00ce, 0x001d}, + {0x01, 0x008d, 0x001e}, + {0x01, 0x00c8, 0x0015}, /* c8 Poids fort Luma */ + {0x01, 0x0032, 0x0016}, /* 32 */ + {0x01, 0x0016, 0x0011}, /* R 00 */ + {0x01, 0x0016, 0x0012}, /* G 00 */ + {0x01, 0x0016, 0x0013}, /* B 00 */ + {0x01, 0x000a, 0x0003}, + {0x02, 0xc002, 0x0001}, + {0x02, 0x0007, 0x0005}, + {} +}; + +static int reg_write(struct usb_device *dev, + __u16 req, __u16 index, __u16 value) +{ + int ret; + + ret = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + req, + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x", + req, index, value); + if (ret < 0) + err("reg write: error %d", ret); + return ret; +} + + +static int write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][3]) +{ + struct usb_device *dev = gspca_dev->dev; + int ret, i = 0; + + while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { + ret = reg_write(dev, data[i][0], data[i][2], data[i][1]); + if (ret < 0) { + PDEBUG(D_ERR, + "Reg write failed for 0x%02x,0x%02x,0x%02x", + data[i][0], data[i][1], data[i][2]); + return ret; + } + i++; + } + return 0; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, 0x00, 0x00, + (sd->contrast >> 8) & 0xff); + reg_write(gspca_dev->dev, 0x00, 0x01, + sd->contrast & 0xff); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors); +} + +static void setblue_balance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->blue_balance); +} + +static void setred_balance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->red_balance); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + sd->subtype = id->driver_info; + sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value; + sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->subtype) { + case Arowana300KCMOSCamera: + case SmileIntlCamera: + /* Arowana 300k CMOS Camera data */ + if (write_vector(gspca_dev, spca501c_arowana_init_data)) + goto error; + break; + case MystFromOriUnknownCamera: + /* Unknown Ori CMOS Camera data */ + if (write_vector(gspca_dev, spca501c_mysterious_open_data)) + goto error; + break; + default: + /* generic spca501 init data */ + if (write_vector(gspca_dev, spca501_init_data)) + goto error; + break; + } + PDEBUG(D_STREAM, "Initializing SPCA501 finished"); + return 0; +error: + return -EINVAL; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int mode; + + switch (sd->subtype) { + case ThreeComHomeConnectLite: + /* Special handling for 3com data */ + write_vector(gspca_dev, spca501_3com_open_data); + break; + case Arowana300KCMOSCamera: + case SmileIntlCamera: + /* Arowana 300k CMOS Camera data */ + write_vector(gspca_dev, spca501c_arowana_open_data); + break; + case MystFromOriUnknownCamera: + /* Unknown CMOS Camera data */ + write_vector(gspca_dev, spca501c_mysterious_init_data); + break; + default: + /* Generic 501 open data */ + write_vector(gspca_dev, spca501_open_data); + } + + /* memorize the wanted pixel format */ + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + + /* Enable ISO packet machine CTRL reg=2, + * index=1 bitmask=0x2 (bit ordinal 1) */ + reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94); + switch (mode) { + case 0: /* 640x480 */ + reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a); + break; + case 1: /* 320x240 */ + reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a); + break; + default: +/* case 2: * 160x120 */ + reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a); + break; + } + reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02); + + /* HDG atleast the Intel CreateAndShare needs to have one of its + * brightness / contrast / color set otherwise it assumes what seems + * max contrast. Note that strange enough setting any of these is + * enough to fix the max contrast problem, to be sure we set all 3 */ + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setcolors(gspca_dev); + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* Disable ISO packet + * machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */ + reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00); +} + +/* called on streamoff with alt 0 and on disconnect */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + if (!gspca_dev->present) + return; + reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + switch (data[0]) { + case 0: /* start of frame */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + data += SPCA501_OFFSET_DATA; + len -= SPCA501_OFFSET_DATA; + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + return; + case 0xff: /* drop */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + data++; + len--; + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->blue_balance = val; + if (gspca_dev->streaming) + setblue_balance(gspca_dev); + return 0; +} + +static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->blue_balance; + return 0; +} + +static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->red_balance = val; + if (gspca_dev->streaming) + setred_balance(gspca_dev); + return 0; +} + +static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->red_balance; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x040a, 0x0002), .driver_info = KodakDVC325}, + {USB_DEVICE(0x0497, 0xc001), .driver_info = SmileIntlCamera}, + {USB_DEVICE(0x0506, 0x00df), .driver_info = ThreeComHomeConnectLite}, + {USB_DEVICE(0x0733, 0x0401), .driver_info = IntelCreateAndShare}, + {USB_DEVICE(0x0733, 0x0402), .driver_info = ViewQuestM318B}, + {USB_DEVICE(0x1776, 0x501c), .driver_info = Arowana300KCMOSCamera}, + {USB_DEVICE(0x0000, 0x0000), .driver_info = MystFromOriUnknownCamera}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca505.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca505.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca505.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca505.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,827 @@ +/* + * SPCA505 chip based cameras initialization data + * + * V4L2 by Jean-Francis Moine + * + * 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, or + * any later version. + * + * 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 + * + */ + +#define MODULE_NAME "spca505" + +#include "gspca.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u8 brightness; + + u8 subtype; +#define IntelPCCameraPro 0 +#define Nxultra 1 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 127 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 4}, + {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +#define SPCA50X_OFFSET_DATA 10 + +#define SPCA50X_REG_USB 0x02 /* spca505 501 */ + +#define SPCA50X_USB_CTRL 0x00 /* spca505 */ +#define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */ + +#define SPCA50X_REG_GLOBAL 0x03 /* spca505 */ +#define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */ +#define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */ + +#define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */ +#define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */ +#define SPCA50X_GMISC3_SAA7113RST 0x20 /* Not sure about this one spca505 */ + +/* Image format and compression control */ +#define SPCA50X_REG_COMPRESS 0x04 + +/* + * Data to initialize a SPCA505. Common to the CCD and external modes + */ +static const u8 spca505_init_data[][3] = { + /* bmRequest,value,index */ + {SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3}, + /* Sensor reset */ + {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3}, + {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1}, + /* Block USB reset */ + {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL, SPCA50X_GLOBAL_MISC0}, + + {0x05, 0x01, 0x10}, + /* Maybe power down some stuff */ + {0x05, 0x0f, 0x11}, + + /* Setup internal CCD ? */ + {0x06, 0x10, 0x08}, + {0x06, 0x00, 0x09}, + {0x06, 0x00, 0x0a}, + {0x06, 0x00, 0x0b}, + {0x06, 0x10, 0x0c}, + {0x06, 0x00, 0x0d}, + {0x06, 0x00, 0x0e}, + {0x06, 0x00, 0x0f}, + {0x06, 0x10, 0x10}, + {0x06, 0x02, 0x11}, + {0x06, 0x00, 0x12}, + {0x06, 0x04, 0x13}, + {0x06, 0x02, 0x14}, + {0x06, 0x8a, 0x51}, + {0x06, 0x40, 0x52}, + {0x06, 0xb6, 0x53}, + {0x06, 0x3d, 0x54}, + {} +}; + +/* + * Data to initialize the camera using the internal CCD + */ +static const u8 spca505_open_data_ccd[][3] = { + /* bmRequest,value,index */ + /* Internal CCD data set */ + {0x03, 0x04, 0x01}, + /* This could be a reset */ + {0x03, 0x00, 0x01}, + + /* Setup compression and image registers. 0x6 and 0x7 seem to be + related to H&V hold, and are resolution mode specific */ + {0x04, 0x10, 0x01}, + /* DIFF(0x50), was (0x10) */ + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + {0x04, 0x20, 0x06}, + {0x04, 0x20, 0x07}, + + {0x08, 0x0a, 0x00}, + /* DIFF (0x4a), was (0xa) */ + + {0x05, 0x00, 0x10}, + {0x05, 0x00, 0x11}, + {0x05, 0x00, 0x00}, + /* DIFF not written */ + {0x05, 0x00, 0x01}, + /* DIFF not written */ + {0x05, 0x00, 0x02}, + /* DIFF not written */ + {0x05, 0x00, 0x03}, + /* DIFF not written */ + {0x05, 0x00, 0x04}, + /* DIFF not written */ + {0x05, 0x80, 0x05}, + /* DIFF not written */ + {0x05, 0xe0, 0x06}, + /* DIFF not written */ + {0x05, 0x20, 0x07}, + /* DIFF not written */ + {0x05, 0xa0, 0x08}, + /* DIFF not written */ + {0x05, 0x0, 0x12}, + /* DIFF not written */ + {0x05, 0x02, 0x0f}, + /* DIFF not written */ + {0x05, 0x10, 0x46}, + /* DIFF not written */ + {0x05, 0x8, 0x4a}, + /* DIFF not written */ + + {0x03, 0x08, 0x03}, + /* DIFF (0x3,0x28,0x3) */ + {0x03, 0x08, 0x01}, + {0x03, 0x0c, 0x03}, + /* DIFF not written */ + {0x03, 0x21, 0x00}, + /* DIFF (0x39) */ + +/* Extra block copied from init to hopefully ensure CCD is in a sane state */ + {0x06, 0x10, 0x08}, + {0x06, 0x00, 0x09}, + {0x06, 0x00, 0x0a}, + {0x06, 0x00, 0x0b}, + {0x06, 0x10, 0x0c}, + {0x06, 0x00, 0x0d}, + {0x06, 0x00, 0x0e}, + {0x06, 0x00, 0x0f}, + {0x06, 0x10, 0x10}, + {0x06, 0x02, 0x11}, + {0x06, 0x00, 0x12}, + {0x06, 0x04, 0x13}, + {0x06, 0x02, 0x14}, + {0x06, 0x8a, 0x51}, + {0x06, 0x40, 0x52}, + {0x06, 0xb6, 0x53}, + {0x06, 0x3d, 0x54}, + /* End of extra block */ + + {0x06, 0x3f, 0x1}, + /* Block skipped */ + {0x06, 0x10, 0x02}, + {0x06, 0x64, 0x07}, + {0x06, 0x10, 0x08}, + {0x06, 0x00, 0x09}, + {0x06, 0x00, 0x0a}, + {0x06, 0x00, 0x0b}, + {0x06, 0x10, 0x0c}, + {0x06, 0x00, 0x0d}, + {0x06, 0x00, 0x0e}, + {0x06, 0x00, 0x0f}, + {0x06, 0x10, 0x10}, + {0x06, 0x02, 0x11}, + {0x06, 0x00, 0x12}, + {0x06, 0x04, 0x13}, + {0x06, 0x02, 0x14}, + {0x06, 0x8a, 0x51}, + {0x06, 0x40, 0x52}, + {0x06, 0xb6, 0x53}, + {0x06, 0x3d, 0x54}, + {0x06, 0x60, 0x57}, + {0x06, 0x20, 0x58}, + {0x06, 0x15, 0x59}, + {0x06, 0x05, 0x5a}, + + {0x05, 0x01, 0xc0}, + {0x05, 0x10, 0xcb}, + {0x05, 0x80, 0xc1}, + /* */ + {0x05, 0x0, 0xc2}, + /* 4 was 0 */ + {0x05, 0x00, 0xca}, + {0x05, 0x80, 0xc1}, + /* */ + {0x05, 0x04, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0x0, 0xc1}, + /* */ + {0x05, 0x00, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0x40, 0xc1}, + /* */ + {0x05, 0x17, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0x80, 0xc1}, + /* */ + {0x05, 0x06, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0x80, 0xc1}, + /* */ + {0x05, 0x04, 0xc2}, + {0x05, 0x00, 0xca}, + + {0x03, 0x4c, 0x3}, + {0x03, 0x18, 0x1}, + + {0x06, 0x70, 0x51}, + {0x06, 0xbe, 0x53}, + {0x06, 0x71, 0x57}, + {0x06, 0x20, 0x58}, + {0x06, 0x05, 0x59}, + {0x06, 0x15, 0x5a}, + + {0x04, 0x00, 0x08}, + /* Compress = OFF (0x1 to turn on) */ + {0x04, 0x12, 0x09}, + {0x04, 0x21, 0x0a}, + {0x04, 0x10, 0x0b}, + {0x04, 0x21, 0x0c}, + {0x04, 0x05, 0x00}, + /* was 5 (Image Type ? ) */ + {0x04, 0x00, 0x01}, + + {0x06, 0x3f, 0x01}, + + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + {0x04, 0x40, 0x06}, + {0x04, 0x40, 0x07}, + + {0x06, 0x1c, 0x17}, + {0x06, 0xe2, 0x19}, + {0x06, 0x1c, 0x1b}, + {0x06, 0xe2, 0x1d}, + {0x06, 0xaa, 0x1f}, + {0x06, 0x70, 0x20}, + + {0x05, 0x01, 0x10}, + {0x05, 0x00, 0x11}, + {0x05, 0x01, 0x00}, + {0x05, 0x05, 0x01}, + {0x05, 0x00, 0xc1}, + /* */ + {0x05, 0x00, 0xc2}, + {0x05, 0x00, 0xca}, + + {0x06, 0x70, 0x51}, + {0x06, 0xbe, 0x53}, + {} +}; + +/* + * Made by Tomasz Zablocki (skalamandra@poczta.onet.pl) + * SPCA505b chip based cameras initialization data + */ +/* jfm */ +#define initial_brightness 0x7f /* 0x0(white)-0xff(black) */ +/* #define initial_brightness 0x0 //0x0(white)-0xff(black) */ +/* + * Data to initialize a SPCA505. Common to the CCD and external modes + */ +static const u8 spca505b_init_data[][3] = { +/* start */ + {0x02, 0x00, 0x00}, /* init */ + {0x02, 0x00, 0x01}, + {0x02, 0x00, 0x02}, + {0x02, 0x00, 0x03}, + {0x02, 0x00, 0x04}, + {0x02, 0x00, 0x05}, + {0x02, 0x00, 0x06}, + {0x02, 0x00, 0x07}, + {0x02, 0x00, 0x08}, + {0x02, 0x00, 0x09}, + {0x03, 0x00, 0x00}, + {0x03, 0x00, 0x01}, + {0x03, 0x00, 0x02}, + {0x03, 0x00, 0x03}, + {0x03, 0x00, 0x04}, + {0x03, 0x00, 0x05}, + {0x03, 0x00, 0x06}, + {0x04, 0x00, 0x00}, + {0x04, 0x00, 0x02}, + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + {0x04, 0x00, 0x06}, + {0x04, 0x00, 0x07}, + {0x04, 0x00, 0x08}, + {0x04, 0x00, 0x09}, + {0x04, 0x00, 0x0a}, + {0x04, 0x00, 0x0b}, + {0x04, 0x00, 0x0c}, + {0x07, 0x00, 0x00}, + {0x07, 0x00, 0x03}, + {0x08, 0x00, 0x00}, + {0x08, 0x00, 0x01}, + {0x08, 0x00, 0x02}, + {0x06, 0x18, 0x08}, + {0x06, 0xfc, 0x09}, + {0x06, 0xfc, 0x0a}, + {0x06, 0xfc, 0x0b}, + {0x06, 0x18, 0x0c}, + {0x06, 0xfc, 0x0d}, + {0x06, 0xfc, 0x0e}, + {0x06, 0xfc, 0x0f}, + {0x06, 0x18, 0x10}, + {0x06, 0xfe, 0x12}, + {0x06, 0x00, 0x11}, + {0x06, 0x00, 0x14}, + {0x06, 0x00, 0x13}, + {0x06, 0x28, 0x51}, + {0x06, 0xff, 0x53}, + {0x02, 0x00, 0x08}, + + {0x03, 0x00, 0x03}, + {0x03, 0x10, 0x03}, + {} +}; + +/* + * Data to initialize the camera using the internal CCD + */ +static const u8 spca505b_open_data_ccd[][3] = { + +/* {0x02,0x00,0x00}, */ + {0x03, 0x04, 0x01}, /* rst */ + {0x03, 0x00, 0x01}, + {0x03, 0x00, 0x00}, + {0x03, 0x21, 0x00}, + {0x03, 0x00, 0x04}, + {0x03, 0x00, 0x03}, + {0x03, 0x18, 0x03}, + {0x03, 0x08, 0x01}, + {0x03, 0x1c, 0x03}, + {0x03, 0x5c, 0x03}, + {0x03, 0x5c, 0x03}, + {0x03, 0x18, 0x01}, + +/* same as 505 */ + {0x04, 0x10, 0x01}, + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + {0x04, 0x20, 0x06}, + {0x04, 0x20, 0x07}, + + {0x08, 0x0a, 0x00}, + + {0x05, 0x00, 0x10}, + {0x05, 0x00, 0x11}, + {0x05, 0x00, 0x12}, + {0x05, 0x6f, 0x00}, + {0x05, initial_brightness >> 6, 0x00}, + {0x05, (initial_brightness << 2) & 0xff, 0x01}, + {0x05, 0x00, 0x02}, + {0x05, 0x01, 0x03}, + {0x05, 0x00, 0x04}, + {0x05, 0x03, 0x05}, + {0x05, 0xe0, 0x06}, + {0x05, 0x20, 0x07}, + {0x05, 0xa0, 0x08}, + {0x05, 0x00, 0x12}, + {0x05, 0x02, 0x0f}, + {0x05, 0x80, 0x14}, /* max exposure off (0=on) */ + {0x05, 0x01, 0xb0}, + {0x05, 0x01, 0xbf}, + {0x03, 0x02, 0x06}, + {0x05, 0x10, 0x46}, + {0x05, 0x08, 0x4a}, + + {0x06, 0x00, 0x01}, + {0x06, 0x10, 0x02}, + {0x06, 0x64, 0x07}, + {0x06, 0x18, 0x08}, + {0x06, 0xfc, 0x09}, + {0x06, 0xfc, 0x0a}, + {0x06, 0xfc, 0x0b}, + {0x04, 0x00, 0x01}, + {0x06, 0x18, 0x0c}, + {0x06, 0xfc, 0x0d}, + {0x06, 0xfc, 0x0e}, + {0x06, 0xfc, 0x0f}, + {0x06, 0x11, 0x10}, /* contrast */ + {0x06, 0x00, 0x11}, + {0x06, 0xfe, 0x12}, + {0x06, 0x00, 0x13}, + {0x06, 0x00, 0x14}, + {0x06, 0x9d, 0x51}, + {0x06, 0x40, 0x52}, + {0x06, 0x7c, 0x53}, + {0x06, 0x40, 0x54}, + {0x06, 0x02, 0x57}, + {0x06, 0x03, 0x58}, + {0x06, 0x15, 0x59}, + {0x06, 0x05, 0x5a}, + {0x06, 0x03, 0x56}, + {0x06, 0x02, 0x3f}, + {0x06, 0x00, 0x40}, + {0x06, 0x39, 0x41}, + {0x06, 0x69, 0x42}, + {0x06, 0x87, 0x43}, + {0x06, 0x9e, 0x44}, + {0x06, 0xb1, 0x45}, + {0x06, 0xbf, 0x46}, + {0x06, 0xcc, 0x47}, + {0x06, 0xd5, 0x48}, + {0x06, 0xdd, 0x49}, + {0x06, 0xe3, 0x4a}, + {0x06, 0xe8, 0x4b}, + {0x06, 0xed, 0x4c}, + {0x06, 0xf2, 0x4d}, + {0x06, 0xf7, 0x4e}, + {0x06, 0xfc, 0x4f}, + {0x06, 0xff, 0x50}, + + {0x05, 0x01, 0xc0}, + {0x05, 0x10, 0xcb}, + {0x05, 0x40, 0xc1}, + {0x05, 0x04, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0x40, 0xc1}, + {0x05, 0x09, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0xc0, 0xc1}, + {0x05, 0x09, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0x40, 0xc1}, + {0x05, 0x59, 0xc2}, + {0x05, 0x00, 0xca}, + {0x04, 0x00, 0x01}, + {0x05, 0x80, 0xc1}, + {0x05, 0xec, 0xc2}, + {0x05, 0x0, 0xca}, + + {0x06, 0x02, 0x57}, + {0x06, 0x01, 0x58}, + {0x06, 0x15, 0x59}, + {0x06, 0x0a, 0x5a}, + {0x06, 0x01, 0x57}, + {0x06, 0x8a, 0x03}, + {0x06, 0x0a, 0x6c}, + {0x06, 0x30, 0x01}, + {0x06, 0x20, 0x02}, + {0x06, 0x00, 0x03}, + + {0x05, 0x8c, 0x25}, + + {0x06, 0x4d, 0x51}, /* maybe saturation (4d) */ + {0x06, 0x84, 0x53}, /* making green (84) */ + {0x06, 0x00, 0x57}, /* sharpness (1) */ + {0x06, 0x18, 0x08}, + {0x06, 0xfc, 0x09}, + {0x06, 0xfc, 0x0a}, + {0x06, 0xfc, 0x0b}, + {0x06, 0x18, 0x0c}, /* maybe hue (18) */ + {0x06, 0xfc, 0x0d}, + {0x06, 0xfc, 0x0e}, + {0x06, 0xfc, 0x0f}, + {0x06, 0x18, 0x10}, /* maybe contrast (18) */ + + {0x05, 0x01, 0x02}, + + {0x04, 0x00, 0x08}, /* compression */ + {0x04, 0x12, 0x09}, + {0x04, 0x21, 0x0a}, + {0x04, 0x10, 0x0b}, + {0x04, 0x21, 0x0c}, + {0x04, 0x1d, 0x00}, /* imagetype (1d) */ + {0x04, 0x41, 0x01}, /* hardware snapcontrol */ + + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + {0x04, 0x10, 0x06}, + {0x04, 0x10, 0x07}, + {0x04, 0x40, 0x06}, + {0x04, 0x40, 0x07}, + {0x04, 0x00, 0x04}, + {0x04, 0x00, 0x05}, + + {0x06, 0x1c, 0x17}, + {0x06, 0xe2, 0x19}, + {0x06, 0x1c, 0x1b}, + {0x06, 0xe2, 0x1d}, + {0x06, 0x5f, 0x1f}, + {0x06, 0x32, 0x20}, + + {0x05, initial_brightness >> 6, 0x00}, + {0x05, (initial_brightness << 2) & 0xff, 0x01}, + {0x05, 0x06, 0xc1}, + {0x05, 0x58, 0xc2}, + {0x05, 0x00, 0xca}, + {0x05, 0x00, 0x11}, + {} +}; + +static int reg_write(struct usb_device *dev, + u16 req, u16 index, u16 value) +{ + int ret; + + ret = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + req, + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d", + req, index, value, ret); + if (ret < 0) + err("reg write: error %d", ret); + return ret; +} + +/* returns: negative is error, pos or zero is data */ +static int reg_read(struct gspca_dev *gspca_dev, + u16 req, /* bRequest */ + u16 index) /* wIndex */ +{ + int ret; + + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + gspca_dev->usb_buf, 2, + 500); /* timeout */ + if (ret < 0) + return ret; + return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; +} + +static int write_vector(struct gspca_dev *gspca_dev, + const u8 data[][3]) +{ + struct usb_device *dev = gspca_dev->dev; + int ret, i = 0; + + while (data[i][0] != 0) { + ret = reg_write(dev, data[i][0], data[i][2], data[i][1]); + if (ret < 0) + return ret; + i++; + } + return 0; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->cam_mode = vga_mode; + sd->subtype = id->driver_info; + if (sd->subtype != IntelPCCameraPro) + cam->nmodes = ARRAY_SIZE(vga_mode); + else /* no 640x480 for IntelPCCameraPro */ + cam->nmodes = ARRAY_SIZE(vga_mode) - 1; + sd->brightness = BRIGHTNESS_DEF; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (write_vector(gspca_dev, + sd->subtype == Nxultra + ? spca505b_init_data + : spca505_init_data)) + return -EIO; + return 0; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 brightness = sd->brightness; + + reg_write(gspca_dev->dev, 0x05, 0x00, (255 - brightness) >> 6); + reg_write(gspca_dev->dev, 0x05, 0x01, (255 - brightness) << 2); +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int ret, mode; + static u8 mode_tb[][3] = { + /* r00 r06 r07 */ + {0x00, 0x10, 0x10}, /* 640x480 */ + {0x01, 0x1a, 0x1a}, /* 352x288 */ + {0x02, 0x1c, 0x1d}, /* 320x240 */ + {0x04, 0x34, 0x34}, /* 176x144 */ + {0x05, 0x40, 0x40} /* 160x120 */ + }; + + if (sd->subtype == Nxultra) + write_vector(gspca_dev, spca505b_open_data_ccd); + else + write_vector(gspca_dev, spca505_open_data_ccd); + ret = reg_read(gspca_dev, 0x06, 0x16); + + if (ret < 0) { + PDEBUG(D_ERR|D_CONF, + "register read failed err: %d", + ret); + return ret; + } + if (ret != 0x0101) { + err("After vector read returns 0x%04x should be 0x0101", + ret); + } + + ret = reg_write(gspca_dev->dev, 0x06, 0x16, 0x0a); + if (ret < 0) + return ret; + reg_write(gspca_dev->dev, 0x05, 0xc2, 0x12); + + /* necessary because without it we can see stream + * only once after loading module */ + /* stopping usb registers Tomasz change */ + reg_write(dev, 0x02, 0x00, 0x00); + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + reg_write(dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]); + reg_write(dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]); + reg_write(dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]); + + ret = reg_write(dev, SPCA50X_REG_USB, + SPCA50X_USB_CTRL, + SPCA50X_CUSB_ENABLE); + + setbrightness(gspca_dev); + + return ret; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* Disable ISO packet machine */ + reg_write(gspca_dev->dev, 0x02, 0x00, 0x00); +} + +/* called on streamoff with alt 0 and on disconnect */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + if (!gspca_dev->present) + return; + + /* This maybe reset or power control */ + reg_write(gspca_dev->dev, 0x03, 0x03, 0x20); + reg_write(gspca_dev->dev, 0x03, 0x01, 0x00); + reg_write(gspca_dev->dev, 0x03, 0x00, 0x01); + reg_write(gspca_dev->dev, 0x05, 0x10, 0x01); + reg_write(gspca_dev->dev, 0x05, 0x11, 0x0f); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + switch (data[0]) { + case 0: /* start of frame */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + data += SPCA50X_OFFSET_DATA; + len -= SPCA50X_OFFSET_DATA; + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + break; + case 0xff: /* drop */ + break; + default: + data += 1; + len -= 1; + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + break; + } +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra}, + {USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro}, +/*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca506.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca506.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca506.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca506.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,734 @@ +/* + * SPCA506 chip based cameras function + * M Xhaard 15/04/2004 based on different work Mark Taylor and others + * and my own snoopy file on a pv-321c donate by a german compagny + * "Firma Frank Gmbh" from Saarbruecken + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "spca506" + +#include "gspca.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + unsigned char brightness; + unsigned char contrast; + unsigned char colors; + unsigned char hue; + char norme; + char channel; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x80, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x47, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SD_COLOR 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x40, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +#define SD_HUE 3 + { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0, + }, + .set = sd_sethue, + .get = sd_gethue, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 5}, + {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 4}, + {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +#define SPCA50X_OFFSET_DATA 10 + +#define SAA7113_bright 0x0a /* defaults 0x80 */ +#define SAA7113_contrast 0x0b /* defaults 0x47 */ +#define SAA7113_saturation 0x0c /* defaults 0x40 */ +#define SAA7113_hue 0x0d /* defaults 0x00 */ +#define SAA7113_I2C_BASE_WRITE 0x4a + +/* read 'len' bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 req, + __u16 index, + __u16 length) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, length, + 500); +} + +static void reg_w(struct usb_device *dev, + __u16 req, + __u16 value, + __u16 index) +{ + usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + NULL, 0, 500); +} + +static void spca506_Initi2c(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004); +} + +static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur, + __u16 reg) +{ + int retry = 60; + + reg_w(gspca_dev->dev, 0x07, reg, 0x0001); + reg_w(gspca_dev->dev, 0x07, valeur, 0x0000); + while (retry--) { + reg_r(gspca_dev, 0x07, 0x0003, 2); + if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00) + break; + } +} + +static void spca506_SetNormeInput(struct gspca_dev *gspca_dev, + __u16 norme, + __u16 channel) +{ + struct sd *sd = (struct sd *) gspca_dev; +/* fixme: check if channel == 0..3 and 6..9 (8 values) */ + __u8 setbit0 = 0x00; + __u8 setbit1 = 0x00; + __u8 videomask = 0x00; + + PDEBUG(D_STREAM, "** Open Set Norme **"); + spca506_Initi2c(gspca_dev); + /* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l) */ + /* Composite channel bit1 -> 1 S-video bit 1 -> 0 */ + /* and exclude SAA7113 reserved channel set default 0 otherwise */ + if (norme & V4L2_STD_NTSC) + setbit0 = 0x01; + if (channel == 4 || channel == 5 || channel > 9) + channel = 0; + if (channel < 4) + setbit1 = 0x02; + videomask = (0x48 | setbit0 | setbit1); + reg_w(gspca_dev->dev, 0x08, videomask, 0x0000); + spca506_WriteI2c(gspca_dev, (0xc0 | (channel & 0x0F)), 0x02); + + if (norme & V4L2_STD_NTSC) + spca506_WriteI2c(gspca_dev, 0x33, 0x0e); + /* Chrominance Control NTSC N */ + else if (norme & V4L2_STD_SECAM) + spca506_WriteI2c(gspca_dev, 0x53, 0x0e); + /* Chrominance Control SECAM */ + else + spca506_WriteI2c(gspca_dev, 0x03, 0x0e); + /* Chrominance Control PAL BGHIV */ + + sd->norme = norme; + sd->channel = channel; + PDEBUG(D_STREAM, "Set Video Byte to 0x%2x", videomask); + PDEBUG(D_STREAM, "Set Norme: %08x Channel %d", norme, channel); +} + +static void spca506_GetNormeInput(struct gspca_dev *gspca_dev, + __u16 *norme, __u16 *channel) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* Read the register is not so good value change so + we use your own copy in spca50x struct */ + *norme = sd->norme; + *channel = sd->channel; + PDEBUG(D_STREAM, "Get Norme: %d Channel %d", *norme, *channel); +} + +static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code, + __u16 xmult, __u16 ymult) +{ + struct usb_device *dev = gspca_dev->dev; + + PDEBUG(D_STREAM, "** SetSize **"); + reg_w(dev, 0x04, (0x18 | (code & 0x07)), 0x0000); + /* Soft snap 0x40 Hard 0x41 */ + reg_w(dev, 0x04, 0x41, 0x0001); + reg_w(dev, 0x04, 0x00, 0x0002); + /* reserved */ + reg_w(dev, 0x04, 0x00, 0x0003); + + /* reserved */ + reg_w(dev, 0x04, 0x00, 0x0004); + /* reserved */ + reg_w(dev, 0x04, 0x01, 0x0005); + /* reserced */ + reg_w(dev, 0x04, xmult, 0x0006); + /* reserved */ + reg_w(dev, 0x04, ymult, 0x0007); + /* compression 1 */ + reg_w(dev, 0x04, 0x00, 0x0008); + /* T=64 -> 2 */ + reg_w(dev, 0x04, 0x00, 0x0009); + /* threshold2D */ + reg_w(dev, 0x04, 0x21, 0x000a); + /* quantization */ + reg_w(dev, 0x04, 0x00, 0x000b); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; + sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; + sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; + sd->hue = sd_ctrls[SD_HUE].qctrl.default_value; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0xFF, 0x0003); + reg_w(dev, 0x03, 0x00, 0x0000); + reg_w(dev, 0x03, 0x1c, 0x0001); + reg_w(dev, 0x03, 0x18, 0x0001); + /* Init on PAL and composite input0 */ + spca506_SetNormeInput(gspca_dev, 0, 0); + reg_w(dev, 0x03, 0x1c, 0x0001); + reg_w(dev, 0x03, 0x18, 0x0001); + reg_w(dev, 0x05, 0x00, 0x0000); + reg_w(dev, 0x05, 0xef, 0x0001); + reg_w(dev, 0x05, 0x00, 0x00c1); + reg_w(dev, 0x05, 0x00, 0x00c2); + reg_w(dev, 0x06, 0x18, 0x0002); + reg_w(dev, 0x06, 0xf5, 0x0011); + reg_w(dev, 0x06, 0x02, 0x0012); + reg_w(dev, 0x06, 0xfb, 0x0013); + reg_w(dev, 0x06, 0x00, 0x0014); + reg_w(dev, 0x06, 0xa4, 0x0051); + reg_w(dev, 0x06, 0x40, 0x0052); + reg_w(dev, 0x06, 0x71, 0x0053); + reg_w(dev, 0x06, 0x40, 0x0054); + /************************************************/ + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0x00, 0x0003); + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0xFF, 0x0003); + reg_w(dev, 0x02, 0x00, 0x0000); + reg_w(dev, 0x03, 0x60, 0x0000); + reg_w(dev, 0x03, 0x18, 0x0001); + /* for a better reading mx :) */ + /*sdca506_WriteI2c(value,register) */ + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, 0x08, 0x01); + spca506_WriteI2c(gspca_dev, 0xc0, 0x02); + /* input composite video */ + spca506_WriteI2c(gspca_dev, 0x33, 0x03); + spca506_WriteI2c(gspca_dev, 0x00, 0x04); + spca506_WriteI2c(gspca_dev, 0x00, 0x05); + spca506_WriteI2c(gspca_dev, 0x0d, 0x06); + spca506_WriteI2c(gspca_dev, 0xf0, 0x07); + spca506_WriteI2c(gspca_dev, 0x98, 0x08); + spca506_WriteI2c(gspca_dev, 0x03, 0x09); + spca506_WriteI2c(gspca_dev, 0x80, 0x0a); + spca506_WriteI2c(gspca_dev, 0x47, 0x0b); + spca506_WriteI2c(gspca_dev, 0x48, 0x0c); + spca506_WriteI2c(gspca_dev, 0x00, 0x0d); + spca506_WriteI2c(gspca_dev, 0x03, 0x0e); /* Chroma Pal adjust */ + spca506_WriteI2c(gspca_dev, 0x2a, 0x0f); + spca506_WriteI2c(gspca_dev, 0x00, 0x10); + spca506_WriteI2c(gspca_dev, 0x0c, 0x11); + spca506_WriteI2c(gspca_dev, 0xb8, 0x12); + spca506_WriteI2c(gspca_dev, 0x01, 0x13); + spca506_WriteI2c(gspca_dev, 0x00, 0x14); + spca506_WriteI2c(gspca_dev, 0x00, 0x15); + spca506_WriteI2c(gspca_dev, 0x00, 0x16); + spca506_WriteI2c(gspca_dev, 0x00, 0x17); + spca506_WriteI2c(gspca_dev, 0x00, 0x18); + spca506_WriteI2c(gspca_dev, 0x00, 0x19); + spca506_WriteI2c(gspca_dev, 0x00, 0x1a); + spca506_WriteI2c(gspca_dev, 0x00, 0x1b); + spca506_WriteI2c(gspca_dev, 0x00, 0x1c); + spca506_WriteI2c(gspca_dev, 0x00, 0x1d); + spca506_WriteI2c(gspca_dev, 0x00, 0x1e); + spca506_WriteI2c(gspca_dev, 0xa1, 0x1f); + spca506_WriteI2c(gspca_dev, 0x02, 0x40); + spca506_WriteI2c(gspca_dev, 0xff, 0x41); + spca506_WriteI2c(gspca_dev, 0xff, 0x42); + spca506_WriteI2c(gspca_dev, 0xff, 0x43); + spca506_WriteI2c(gspca_dev, 0xff, 0x44); + spca506_WriteI2c(gspca_dev, 0xff, 0x45); + spca506_WriteI2c(gspca_dev, 0xff, 0x46); + spca506_WriteI2c(gspca_dev, 0xff, 0x47); + spca506_WriteI2c(gspca_dev, 0xff, 0x48); + spca506_WriteI2c(gspca_dev, 0xff, 0x49); + spca506_WriteI2c(gspca_dev, 0xff, 0x4a); + spca506_WriteI2c(gspca_dev, 0xff, 0x4b); + spca506_WriteI2c(gspca_dev, 0xff, 0x4c); + spca506_WriteI2c(gspca_dev, 0xff, 0x4d); + spca506_WriteI2c(gspca_dev, 0xff, 0x4e); + spca506_WriteI2c(gspca_dev, 0xff, 0x4f); + spca506_WriteI2c(gspca_dev, 0xff, 0x50); + spca506_WriteI2c(gspca_dev, 0xff, 0x51); + spca506_WriteI2c(gspca_dev, 0xff, 0x52); + spca506_WriteI2c(gspca_dev, 0xff, 0x53); + spca506_WriteI2c(gspca_dev, 0xff, 0x54); + spca506_WriteI2c(gspca_dev, 0xff, 0x55); + spca506_WriteI2c(gspca_dev, 0xff, 0x56); + spca506_WriteI2c(gspca_dev, 0xff, 0x57); + spca506_WriteI2c(gspca_dev, 0x00, 0x58); + spca506_WriteI2c(gspca_dev, 0x54, 0x59); + spca506_WriteI2c(gspca_dev, 0x07, 0x5a); + spca506_WriteI2c(gspca_dev, 0x83, 0x5b); + spca506_WriteI2c(gspca_dev, 0x00, 0x5c); + spca506_WriteI2c(gspca_dev, 0x00, 0x5d); + spca506_WriteI2c(gspca_dev, 0x00, 0x5e); + spca506_WriteI2c(gspca_dev, 0x00, 0x5f); + spca506_WriteI2c(gspca_dev, 0x00, 0x60); + spca506_WriteI2c(gspca_dev, 0x05, 0x61); + spca506_WriteI2c(gspca_dev, 0x9f, 0x62); + PDEBUG(D_STREAM, "** Close Init *"); + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + __u16 norme; + __u16 channel; + + /**************************************/ + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0x00, 0x0003); + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0xFF, 0x0003); + reg_w(dev, 0x02, 0x00, 0x0000); + reg_w(dev, 0x03, 0x60, 0x0000); + reg_w(dev, 0x03, 0x18, 0x0001); + + /*sdca506_WriteI2c(value,register) */ + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, 0x08, 0x01); /* Increment Delay */ +/* spca506_WriteI2c(gspca_dev, 0xc0, 0x02); * Analog Input Control 1 */ + spca506_WriteI2c(gspca_dev, 0x33, 0x03); + /* Analog Input Control 2 */ + spca506_WriteI2c(gspca_dev, 0x00, 0x04); + /* Analog Input Control 3 */ + spca506_WriteI2c(gspca_dev, 0x00, 0x05); + /* Analog Input Control 4 */ + spca506_WriteI2c(gspca_dev, 0x0d, 0x06); + /* Horizontal Sync Start 0xe9-0x0d */ + spca506_WriteI2c(gspca_dev, 0xf0, 0x07); + /* Horizontal Sync Stop 0x0d-0xf0 */ + + spca506_WriteI2c(gspca_dev, 0x98, 0x08); /* Sync Control */ +/* Defaults value */ + spca506_WriteI2c(gspca_dev, 0x03, 0x09); /* Luminance Control */ + spca506_WriteI2c(gspca_dev, 0x80, 0x0a); + /* Luminance Brightness */ + spca506_WriteI2c(gspca_dev, 0x47, 0x0b); /* Luminance Contrast */ + spca506_WriteI2c(gspca_dev, 0x48, 0x0c); + /* Chrominance Saturation */ + spca506_WriteI2c(gspca_dev, 0x00, 0x0d); + /* Chrominance Hue Control */ + spca506_WriteI2c(gspca_dev, 0x2a, 0x0f); + /* Chrominance Gain Control */ + /**************************************/ + spca506_WriteI2c(gspca_dev, 0x00, 0x10); + /* Format/Delay Control */ + spca506_WriteI2c(gspca_dev, 0x0c, 0x11); /* Output Control 1 */ + spca506_WriteI2c(gspca_dev, 0xb8, 0x12); /* Output Control 2 */ + spca506_WriteI2c(gspca_dev, 0x01, 0x13); /* Output Control 3 */ + spca506_WriteI2c(gspca_dev, 0x00, 0x14); /* reserved */ + spca506_WriteI2c(gspca_dev, 0x00, 0x15); /* VGATE START */ + spca506_WriteI2c(gspca_dev, 0x00, 0x16); /* VGATE STOP */ + spca506_WriteI2c(gspca_dev, 0x00, 0x17); /* VGATE Control (MSB) */ + spca506_WriteI2c(gspca_dev, 0x00, 0x18); + spca506_WriteI2c(gspca_dev, 0x00, 0x19); + spca506_WriteI2c(gspca_dev, 0x00, 0x1a); + spca506_WriteI2c(gspca_dev, 0x00, 0x1b); + spca506_WriteI2c(gspca_dev, 0x00, 0x1c); + spca506_WriteI2c(gspca_dev, 0x00, 0x1d); + spca506_WriteI2c(gspca_dev, 0x00, 0x1e); + spca506_WriteI2c(gspca_dev, 0xa1, 0x1f); + spca506_WriteI2c(gspca_dev, 0x02, 0x40); + spca506_WriteI2c(gspca_dev, 0xff, 0x41); + spca506_WriteI2c(gspca_dev, 0xff, 0x42); + spca506_WriteI2c(gspca_dev, 0xff, 0x43); + spca506_WriteI2c(gspca_dev, 0xff, 0x44); + spca506_WriteI2c(gspca_dev, 0xff, 0x45); + spca506_WriteI2c(gspca_dev, 0xff, 0x46); + spca506_WriteI2c(gspca_dev, 0xff, 0x47); + spca506_WriteI2c(gspca_dev, 0xff, 0x48); + spca506_WriteI2c(gspca_dev, 0xff, 0x49); + spca506_WriteI2c(gspca_dev, 0xff, 0x4a); + spca506_WriteI2c(gspca_dev, 0xff, 0x4b); + spca506_WriteI2c(gspca_dev, 0xff, 0x4c); + spca506_WriteI2c(gspca_dev, 0xff, 0x4d); + spca506_WriteI2c(gspca_dev, 0xff, 0x4e); + spca506_WriteI2c(gspca_dev, 0xff, 0x4f); + spca506_WriteI2c(gspca_dev, 0xff, 0x50); + spca506_WriteI2c(gspca_dev, 0xff, 0x51); + spca506_WriteI2c(gspca_dev, 0xff, 0x52); + spca506_WriteI2c(gspca_dev, 0xff, 0x53); + spca506_WriteI2c(gspca_dev, 0xff, 0x54); + spca506_WriteI2c(gspca_dev, 0xff, 0x55); + spca506_WriteI2c(gspca_dev, 0xff, 0x56); + spca506_WriteI2c(gspca_dev, 0xff, 0x57); + spca506_WriteI2c(gspca_dev, 0x00, 0x58); + spca506_WriteI2c(gspca_dev, 0x54, 0x59); + spca506_WriteI2c(gspca_dev, 0x07, 0x5a); + spca506_WriteI2c(gspca_dev, 0x83, 0x5b); + spca506_WriteI2c(gspca_dev, 0x00, 0x5c); + spca506_WriteI2c(gspca_dev, 0x00, 0x5d); + spca506_WriteI2c(gspca_dev, 0x00, 0x5e); + spca506_WriteI2c(gspca_dev, 0x00, 0x5f); + spca506_WriteI2c(gspca_dev, 0x00, 0x60); + spca506_WriteI2c(gspca_dev, 0x05, 0x61); + spca506_WriteI2c(gspca_dev, 0x9f, 0x62); + /**************************************/ + reg_w(dev, 0x05, 0x00, 0x0003); + reg_w(dev, 0x05, 0x00, 0x0004); + reg_w(dev, 0x03, 0x10, 0x0001); + reg_w(dev, 0x03, 0x78, 0x0000); + switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + case 0: + spca506_Setsize(gspca_dev, 0, 0x10, 0x10); + break; + case 1: + spca506_Setsize(gspca_dev, 1, 0x1a, 0x1a); + break; + case 2: + spca506_Setsize(gspca_dev, 2, 0x1c, 0x1c); + break; + case 4: + spca506_Setsize(gspca_dev, 4, 0x34, 0x34); + break; + default: +/* case 5: */ + spca506_Setsize(gspca_dev, 5, 0x40, 0x40); + break; + } + + /* compress setting and size */ + /* set i2c luma */ + reg_w(dev, 0x02, 0x01, 0x0000); + reg_w(dev, 0x03, 0x12, 0x0000); + reg_r(gspca_dev, 0x04, 0x0001, 2); + PDEBUG(D_STREAM, "webcam started"); + spca506_GetNormeInput(gspca_dev, &norme, &channel); + spca506_SetNormeInput(gspca_dev, norme, channel); + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + + reg_w(dev, 0x02, 0x00, 0x0000); + reg_w(dev, 0x03, 0x00, 0x0004); + reg_w(dev, 0x03, 0x00, 0x0003); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + switch (data[0]) { + case 0: /* start of frame */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + data += SPCA50X_OFFSET_DATA; + len -= SPCA50X_OFFSET_DATA; + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + break; + case 0xff: /* drop */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + break; + default: + data += 1; + len -= 1; + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + break; + } +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, sd->brightness, SAA7113_bright); + spca506_WriteI2c(gspca_dev, 0x01, 0x09); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, sd->contrast, SAA7113_contrast); + spca506_WriteI2c(gspca_dev, 0x01, 0x09); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, sd->colors, SAA7113_saturation); + spca506_WriteI2c(gspca_dev, 0x01, 0x09); +} + +static void sethue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + spca506_Initi2c(gspca_dev); + spca506_WriteI2c(gspca_dev, sd->hue, SAA7113_hue); + spca506_WriteI2c(gspca_dev, 0x01, 0x09); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hue = val; + if (gspca_dev->streaming) + sethue(gspca_dev); + return 0; +} + +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hue; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] __devinitconst = { + {USB_DEVICE(0x06e1, 0xa190)}, +/*fixme: may be IntelPCCameraPro BRIDGE_SPCA505 + {USB_DEVICE(0x0733, 0x0430)}, */ + {USB_DEVICE(0x0734, 0x043b)}, + {USB_DEVICE(0x99fa, 0x8988)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int __devinit sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + int ret; + ret = usb_register(&sd_driver); + if (ret < 0) + return ret; + PDEBUG(D_PROBE, "registered"); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca508.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca508.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca508.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca508.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1556 @@ +/* + * SPCA508 chip based cameras subdriver + * + * Copyright (C) 2009 Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "spca508" + +#include "gspca.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA/SPCA508 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u8 brightness; + + u8 subtype; +#define CreativeVista 0 +#define HamaUSBSightcam 1 +#define HamaUSBSightcam2 2 +#define IntelEasyPCCamera 3 +#define MicroInnovationIC200 4 +#define ViewQuestVQ110 5 +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 128 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +}; + +static const struct v4l2_pix_format sif_mode[] = { + {160, 120, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* Frame packet header offsets for the spca508 */ +#define SPCA508_OFFSET_DATA 37 + +/* + * Initialization data: this is the first set-up data written to the + * device (before the open data). + */ +static const u16 spca508_init_data[][2] = { + {0x0000, 0x870b}, + + {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */ + {0x0003, 0x8111}, /* Reset compression & memory */ + {0x0000, 0x8110}, /* Disable all outputs */ + /* READ {0x0000, 0x8114} -> 0000: 00 */ + {0x0000, 0x8114}, /* SW GPIO data */ + {0x0008, 0x8110}, /* Enable charge pump output */ + {0x0002, 0x8116}, /* 200 kHz pump clock */ + /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */ + {0x0003, 0x8111}, /* Reset compression & memory */ + {0x0000, 0x8111}, /* Normal mode (not reset) */ + {0x0098, 0x8110}, + /* Enable charge pump output, sync.serial,external 2x clock */ + {0x000d, 0x8114}, /* SW GPIO data */ + {0x0002, 0x8116}, /* 200 kHz pump clock */ + {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */ +/* --------------------------------------- */ + {0x000f, 0x8402}, /* memory bank */ + {0x0000, 0x8403}, /* ... address */ +/* --------------------------------------- */ +/* 0x88__ is Synchronous Serial Interface. */ +/* TBD: This table could be expressed more compactly */ +/* using spca508_write_i2c_vector(). */ +/* TBD: Should see if the values in spca50x_i2c_data */ +/* would work with the VQ110 instead of the values */ +/* below. */ + {0x00c0, 0x8804}, /* SSI slave addr */ + {0x0008, 0x8802}, /* 375 Khz SSI clock */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, /* 375 Khz SSI clock */ + {0x0012, 0x8801}, /* SSI reg addr */ + {0x0080, 0x8800}, /* SSI data to write */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, /* 375 Khz SSI clock */ + {0x0012, 0x8801}, /* SSI reg addr */ + {0x0000, 0x8800}, /* SSI data to write */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, /* 375 Khz SSI clock */ + {0x0011, 0x8801}, /* SSI reg addr */ + {0x0040, 0x8800}, /* SSI data to write */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0013, 0x8801}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0014, 0x8801}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0015, 0x8801}, + {0x0001, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0016, 0x8801}, + {0x0003, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0017, 0x8801}, + {0x0036, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0018, 0x8801}, + {0x00ec, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x001a, 0x8801}, + {0x0094, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x001b, 0x8801}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0027, 0x8801}, + {0x00a2, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0028, 0x8801}, + {0x0040, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x002a, 0x8801}, + {0x0084, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x002b, 0x8801}, + {0x00a8, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x002c, 0x8801}, + {0x00fe, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x002d, 0x8801}, + {0x0003, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0038, 0x8801}, + {0x0083, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0033, 0x8801}, + {0x0081, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0034, 0x8801}, + {0x004a, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0039, 0x8801}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0010, 0x8801}, + {0x00a8, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0006, 0x8801}, + {0x0058, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0000, 0x8801}, + {0x0004, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0040, 0x8801}, + {0x0080, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0041, 0x8801}, + {0x000c, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0042, 0x8801}, + {0x000c, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0043, 0x8801}, + {0x0028, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0044, 0x8801}, + {0x0080, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0045, 0x8801}, + {0x0020, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0046, 0x8801}, + {0x0020, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0047, 0x8801}, + {0x0080, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0048, 0x8801}, + {0x004c, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0049, 0x8801}, + {0x0084, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x004a, 0x8801}, + {0x0084, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x004b, 0x8801}, + {0x0084, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* --------------------------------------- */ + {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ + {0x0000, 0x8701}, /* CKx1 clock delay adj */ + {0x0000, 0x8701}, /* CKx1 clock delay adj */ + {0x0001, 0x870c}, /* CKOx2 output */ + /* --------------------------------------- */ + {0x0080, 0x8600}, /* Line memory read counter (L) */ + {0x0001, 0x8606}, /* reserved */ + {0x0064, 0x8607}, /* Line memory read counter (H) 0x6480=25,728 */ + {0x002a, 0x8601}, /* CDSP sharp interpolation mode, + * line sel for color sep, edge enhance enab */ + {0x0000, 0x8602}, /* optical black level for user settng = 0 */ + {0x0080, 0x8600}, /* Line memory read counter (L) */ + {0x000a, 0x8603}, /* optical black level calc mode: + * auto; optical black offset = 10 */ + {0x00df, 0x865b}, /* Horiz offset for valid pixels (L)=0xdf */ + {0x0012, 0x865c}, /* Vert offset for valid lines (L)=0x12 */ + +/* The following two lines seem to be the "wrong" resolution. */ +/* But perhaps these indicate the actual size of the sensor */ +/* rather than the size of the current video mode. */ + {0x0058, 0x865d}, /* Horiz valid pixels (*4) (L) = 352 */ + {0x0048, 0x865e}, /* Vert valid lines (*4) (L) = 288 */ + + {0x0015, 0x8608}, /* A11 Coef ... */ + {0x0030, 0x8609}, + {0x00fb, 0x860a}, + {0x003e, 0x860b}, + {0x00ce, 0x860c}, + {0x00f4, 0x860d}, + {0x00eb, 0x860e}, + {0x00dc, 0x860f}, + {0x0039, 0x8610}, + {0x0001, 0x8611}, /* R offset for white balance ... */ + {0x0000, 0x8612}, + {0x0001, 0x8613}, + {0x0000, 0x8614}, + {0x005b, 0x8651}, /* R gain for white balance ... */ + {0x0040, 0x8652}, + {0x0060, 0x8653}, + {0x0040, 0x8654}, + {0x0000, 0x8655}, + {0x0001, 0x863f}, /* Fixed gamma correction enable, USB control, + * lum filter disable, lum noise clip disable */ + {0x00a1, 0x8656}, /* Window1 size 256x256, Windows2 size 64x64, + * gamma look-up disable, + * new edge enhancement enable */ + {0x0018, 0x8657}, /* Edge gain high thresh */ + {0x0020, 0x8658}, /* Edge gain low thresh */ + {0x000a, 0x8659}, /* Edge bandwidth high threshold */ + {0x0005, 0x865a}, /* Edge bandwidth low threshold */ + /* -------------------------------- */ + {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0xa908, 0x8802}, + {0x0034, 0x8801}, /* SSI reg addr */ + {0x00ca, 0x8800}, + /* SSI data to write */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x1f08, 0x8802}, + {0x0006, 0x8801}, + {0x0080, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + +/* ----- Read back coefs we wrote earlier. */ + /* READ { 0x0000, 0x8608 } -> 0000: 15 */ + /* READ { 0x0000, 0x8609 } -> 0000: 30 */ + /* READ { 0x0000, 0x860a } -> 0000: fb */ + /* READ { 0x0000, 0x860b } -> 0000: 3e */ + /* READ { 0x0000, 0x860c } -> 0000: ce */ + /* READ { 0x0000, 0x860d } -> 0000: f4 */ + /* READ { 0x0000, 0x860e } -> 0000: eb */ + /* READ { 0x0000, 0x860f } -> 0000: dc */ + /* READ { 0x0000, 0x8610 } -> 0000: 39 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0xb008, 0x8802}, + {0x0006, 0x8801}, + {0x007d, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + + /* This chunk is seemingly redundant with */ + /* earlier commands (A11 Coef...), but if I disable it, */ + /* the image appears too dark. Maybe there was some kind of */ + /* reset since the earlier commands, so this is necessary again. */ + {0x0015, 0x8608}, + {0x0030, 0x8609}, + {0xfffb, 0x860a}, + {0x003e, 0x860b}, + {0xffce, 0x860c}, + {0xfff4, 0x860d}, + {0xffeb, 0x860e}, + {0xffdc, 0x860f}, + {0x0039, 0x8610}, + {0x0018, 0x8657}, + + {0x0000, 0x8508}, /* Disable compression. */ + /* Previous line was: + {0x0021, 0x8508}, * Enable compression. */ + {0x0032, 0x850b}, /* compression stuff */ + {0x0003, 0x8509}, /* compression stuff */ + {0x0011, 0x850a}, /* compression stuff */ + {0x0021, 0x850d}, /* compression stuff */ + {0x0010, 0x850c}, /* compression stuff */ + {0x0003, 0x8500}, /* *** Video mode: 160x120 */ + {0x0001, 0x8501}, /* Hardware-dominated snap control */ + {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128, + * gamma look-up disable, + * new edge enhancement enable */ + {0x0018, 0x8617}, /* Window1 start X (*2) */ + {0x0008, 0x8618}, /* Window1 start Y (*2) */ + {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128, + * gamma look-up disable, + * new edge enhancement enable */ + {0x0058, 0x8619}, /* Window2 start X (*2) */ + {0x0008, 0x861a}, /* Window2 start Y (*2) */ + {0x00ff, 0x8615}, /* High lum thresh for white balance */ + {0x0000, 0x8616}, /* Low lum thresh for white balance */ + {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ + {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ + /* READ { 0x0000, 0x8656 } -> 0000: 61 */ + {0x0028, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 28 */ + {0x1f28, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */ + {0x0010, 0x8801}, /* SSI reg addr */ + {0x003e, 0x8800}, /* SSI data to write */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + {0x0028, 0x8802}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 28 */ + {0x1f28, 0x8802}, + {0x0000, 0x8801}, + {0x001f, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + {0x0001, 0x8602}, /* optical black level for user settning = 1 */ + + /* Original: */ + {0x0023, 0x8700}, /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */ + {0x000f, 0x8602}, /* optical black level for user settning = 15 */ + + {0x0028, 0x8802}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 28 */ + {0x1f28, 0x8802}, + {0x0010, 0x8801}, + {0x007b, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + {0x002f, 0x8651}, /* R gain for white balance ... */ + {0x0080, 0x8653}, + /* READ { 0x0000, 0x8655 } -> 0000: 00 */ + {0x0000, 0x8655}, + + {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */ + {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */ + /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */ + {} +}; + +/* + * Initialization data for Intel EasyPC Camera CS110 + */ +static const u16 spca508cs110_init_data[][2] = { + {0x0000, 0x870b}, /* Reset CTL3 */ + {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */ + {0x0000, 0x8111}, /* Normal operation on reset */ + {0x0090, 0x8110}, + /* External Clock 2x & Synchronous Serial Interface Output */ + {0x0020, 0x8112}, /* Video Drop packet enable */ + {0x0000, 0x8114}, /* Software GPIO output data */ + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0003, 0x8114}, + + /* Initial sequence Synchronous Serial Interface */ + {0x000f, 0x8402}, /* Memory bank Address */ + {0x0000, 0x8403}, /* Memory bank Address */ + {0x00ba, 0x8804}, /* SSI Slave address */ + {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */ + {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */ + + {0x0001, 0x8801}, + {0x000a, 0x8805}, /* a - NWG: Dunno what this is about */ + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0002, 0x8801}, + {0x0000, 0x8805}, + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0003, 0x8801}, + {0x0027, 0x8805}, + {0x0001, 0x8800}, + {0x0010, 0x8802}, + + {0x0004, 0x8801}, + {0x0065, 0x8805}, + {0x0001, 0x8800}, + {0x0010, 0x8802}, + + {0x0005, 0x8801}, + {0x0003, 0x8805}, + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0006, 0x8801}, + {0x001c, 0x8805}, + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0007, 0x8801}, + {0x002a, 0x8805}, + {0x0000, 0x8800}, + {0x0010, 0x8802}, + + {0x0002, 0x8704}, /* External input CKIx1 */ + {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */ + {0x009a, 0x8600}, /* Line memory Read Counter (L) */ + {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */ + {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */ + {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */ + + {0x0006, 0x8660}, /* Nibble data + input order */ + + {0x000a, 0x8602}, /* Optical black level set to 0x0a */ + {0x0000, 0x8603}, /* Optical black level Offset */ + +/* {0x0000, 0x8611}, * 0 R Offset for white Balance */ +/* {0x0000, 0x8612}, * 1 Gr Offset for white Balance */ +/* {0x0000, 0x8613}, * 1f B Offset for white Balance */ +/* {0x0000, 0x8614}, * f0 Gb Offset for white Balance */ + + {0x0040, 0x8651}, /* 2b BLUE gain for white balance good at all 60 */ + {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */ + {0x0035, 0x8653}, /* 26 RED gain for white balance */ + {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */ + {0x0041, 0x863f}, + /* Fixed Gamma correction enabled (makes colours look better) */ + + {0x0000, 0x8655}, + /* High bits for white balance*****brightness control*** */ + {} +}; + +static const u16 spca508_sightcam_init_data[][2] = { +/* This line seems to setup the frame/canvas */ + {0x000f, 0x8402}, + +/* These 6 lines are needed to startup the webcam */ + {0x0090, 0x8110}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0003, 0x8114}, + {0x0080, 0x8804}, + +/* This part seems to make the pictures darker? (autobrightness?) */ + {0x0001, 0x8801}, + {0x0004, 0x8800}, + {0x0003, 0x8801}, + {0x00e0, 0x8800}, + {0x0004, 0x8801}, + {0x00b4, 0x8800}, + {0x0005, 0x8801}, + {0x0000, 0x8800}, + + {0x0006, 0x8801}, + {0x00e0, 0x8800}, + {0x0007, 0x8801}, + {0x000c, 0x8800}, + +/* This section is just needed, it probably + * does something like the previous section, + * but the cam won't start if it's not included. + */ + {0x0014, 0x8801}, + {0x0008, 0x8800}, + {0x0015, 0x8801}, + {0x0067, 0x8800}, + {0x0016, 0x8801}, + {0x0000, 0x8800}, + {0x0017, 0x8801}, + {0x0020, 0x8800}, + {0x0018, 0x8801}, + {0x0044, 0x8800}, + +/* Makes the picture darker - and the + * cam won't start if not included + */ + {0x001e, 0x8801}, + {0x00ea, 0x8800}, + {0x001f, 0x8801}, + {0x0001, 0x8800}, + {0x0003, 0x8801}, + {0x00e0, 0x8800}, + +/* seems to place the colors ontop of each other #1 */ + {0x0006, 0x8704}, + {0x0001, 0x870c}, + {0x0016, 0x8600}, + {0x0002, 0x8606}, + +/* if not included the pictures becomes _very_ dark */ + {0x0064, 0x8607}, + {0x003a, 0x8601}, + {0x0000, 0x8602}, + +/* seems to place the colors ontop of each other #2 */ + {0x0016, 0x8600}, + {0x0018, 0x8617}, + {0x0008, 0x8618}, + {0x00a1, 0x8656}, + +/* webcam won't start if not included */ + {0x0007, 0x865b}, + {0x0001, 0x865c}, + {0x0058, 0x865d}, + {0x0048, 0x865e}, + +/* adjusts the colors */ + {0x0049, 0x8651}, + {0x0040, 0x8652}, + {0x004c, 0x8653}, + {0x0040, 0x8654}, + {} +}; + +static const u16 spca508_sightcam2_init_data[][2] = { + {0x0020, 0x8112}, + + {0x000f, 0x8402}, + {0x0000, 0x8403}, + + {0x0008, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x0009, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000a, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000b, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000c, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000d, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000e, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x0007, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000f, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + + {0x0018, 0x8660}, + {0x0010, 0x8201}, + + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x0011, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + + {0x0000, 0x86b0}, + {0x0034, 0x86b1}, + {0x0000, 0x86b2}, + {0x0049, 0x86b3}, + {0x0000, 0x86b4}, + {0x0000, 0x86b4}, + + {0x0012, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x0013, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + + {0x0001, 0x86b0}, + {0x00aa, 0x86b1}, + {0x0000, 0x86b2}, + {0x00e4, 0x86b3}, + {0x0000, 0x86b4}, + {0x0000, 0x86b4}, + + {0x0018, 0x8660}, + + {0x0090, 0x8110}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0003, 0x8114}, + + {0x0080, 0x8804}, + {0x0003, 0x8801}, + {0x0012, 0x8800}, + {0x0004, 0x8801}, + {0x0005, 0x8800}, + {0x0005, 0x8801}, + {0x0000, 0x8800}, + {0x0006, 0x8801}, + {0x0000, 0x8800}, + {0x0007, 0x8801}, + {0x0000, 0x8800}, + {0x0008, 0x8801}, + {0x0005, 0x8800}, + {0x000a, 0x8700}, + {0x000e, 0x8801}, + {0x0004, 0x8800}, + {0x0005, 0x8801}, + {0x0047, 0x8800}, + {0x0006, 0x8801}, + {0x0000, 0x8800}, + {0x0007, 0x8801}, + {0x00c0, 0x8800}, + {0x0008, 0x8801}, + {0x0003, 0x8800}, + {0x0013, 0x8801}, + {0x0001, 0x8800}, + {0x0009, 0x8801}, + {0x0000, 0x8800}, + {0x000a, 0x8801}, + {0x0000, 0x8800}, + {0x000b, 0x8801}, + {0x0000, 0x8800}, + {0x000c, 0x8801}, + {0x0000, 0x8800}, + {0x000e, 0x8801}, + {0x0004, 0x8800}, + {0x000f, 0x8801}, + {0x0000, 0x8800}, + {0x0010, 0x8801}, + {0x0006, 0x8800}, + {0x0011, 0x8801}, + {0x0006, 0x8800}, + {0x0012, 0x8801}, + {0x0000, 0x8800}, + {0x0013, 0x8801}, + {0x0001, 0x8800}, + + {0x000a, 0x8700}, + {0x0000, 0x8702}, + {0x0000, 0x8703}, + {0x00c2, 0x8704}, + {0x0001, 0x870c}, + + {0x0044, 0x8600}, + {0x0002, 0x8606}, + {0x0064, 0x8607}, + {0x003a, 0x8601}, + {0x0008, 0x8602}, + {0x0044, 0x8600}, + {0x0018, 0x8617}, + {0x0008, 0x8618}, + {0x00a1, 0x8656}, + {0x0004, 0x865b}, + {0x0002, 0x865c}, + {0x0058, 0x865d}, + {0x0048, 0x865e}, + {0x0012, 0x8608}, + {0x002c, 0x8609}, + {0x0002, 0x860a}, + {0x002c, 0x860b}, + {0x00db, 0x860c}, + {0x00f9, 0x860d}, + {0x00f1, 0x860e}, + {0x00e3, 0x860f}, + {0x002c, 0x8610}, + {0x006c, 0x8651}, + {0x0041, 0x8652}, + {0x0059, 0x8653}, + {0x0040, 0x8654}, + {0x00fa, 0x8611}, + {0x00ff, 0x8612}, + {0x00f8, 0x8613}, + {0x0000, 0x8614}, + {0x0001, 0x863f}, + {0x0000, 0x8640}, + {0x0026, 0x8641}, + {0x0045, 0x8642}, + {0x0060, 0x8643}, + {0x0075, 0x8644}, + {0x0088, 0x8645}, + {0x009b, 0x8646}, + {0x00b0, 0x8647}, + {0x00c5, 0x8648}, + {0x00d2, 0x8649}, + {0x00dc, 0x864a}, + {0x00e5, 0x864b}, + {0x00eb, 0x864c}, + {0x00f0, 0x864d}, + {0x00f6, 0x864e}, + {0x00fa, 0x864f}, + {0x00ff, 0x8650}, + {0x0060, 0x8657}, + {0x0010, 0x8658}, + {0x0018, 0x8659}, + {0x0005, 0x865a}, + {0x0018, 0x8660}, + {0x0003, 0x8509}, + {0x0011, 0x850a}, + {0x0032, 0x850b}, + {0x0010, 0x850c}, + {0x0021, 0x850d}, + {0x0001, 0x8500}, + {0x0000, 0x8508}, + {0x0012, 0x8608}, + {0x002c, 0x8609}, + {0x0002, 0x860a}, + {0x0039, 0x860b}, + {0x00d0, 0x860c}, + {0x00f7, 0x860d}, + {0x00ed, 0x860e}, + {0x00db, 0x860f}, + {0x0039, 0x8610}, + {0x0012, 0x8657}, + {0x000c, 0x8619}, + {0x0004, 0x861a}, + {0x00a1, 0x8656}, + {0x00c8, 0x8615}, + {0x0032, 0x8616}, + + {0x0030, 0x8112}, + {0x0020, 0x8112}, + {0x0020, 0x8112}, + {0x000f, 0x8402}, + {0x0000, 0x8403}, + + {0x0090, 0x8110}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0003, 0x8114}, + {0x0080, 0x8804}, + + {0x0003, 0x8801}, + {0x0012, 0x8800}, + {0x0004, 0x8801}, + {0x0005, 0x8800}, + {0x0005, 0x8801}, + {0x0047, 0x8800}, + {0x0006, 0x8801}, + {0x0000, 0x8800}, + {0x0007, 0x8801}, + {0x00c0, 0x8800}, + {0x0008, 0x8801}, + {0x0003, 0x8800}, + {0x000a, 0x8700}, + {0x000e, 0x8801}, + {0x0004, 0x8800}, + {0x0005, 0x8801}, + {0x0047, 0x8800}, + {0x0006, 0x8801}, + {0x0000, 0x8800}, + {0x0007, 0x8801}, + {0x00c0, 0x8800}, + {0x0008, 0x8801}, + {0x0003, 0x8800}, + {0x0013, 0x8801}, + {0x0001, 0x8800}, + {0x0009, 0x8801}, + {0x0000, 0x8800}, + {0x000a, 0x8801}, + {0x0000, 0x8800}, + {0x000b, 0x8801}, + {0x0000, 0x8800}, + {0x000c, 0x8801}, + {0x0000, 0x8800}, + {0x000e, 0x8801}, + {0x0004, 0x8800}, + {0x000f, 0x8801}, + {0x0000, 0x8800}, + {0x0010, 0x8801}, + {0x0006, 0x8800}, + {0x0011, 0x8801}, + {0x0006, 0x8800}, + {0x0012, 0x8801}, + {0x0000, 0x8800}, + {0x0013, 0x8801}, + {0x0001, 0x8800}, + {0x000a, 0x8700}, + {0x0000, 0x8702}, + {0x0000, 0x8703}, + {0x00c2, 0x8704}, + {0x0001, 0x870c}, + {0x0044, 0x8600}, + {0x0002, 0x8606}, + {0x0064, 0x8607}, + {0x003a, 0x8601}, + {0x0008, 0x8602}, + {0x0044, 0x8600}, + {0x0018, 0x8617}, + {0x0008, 0x8618}, + {0x00a1, 0x8656}, + {0x0004, 0x865b}, + {0x0002, 0x865c}, + {0x0058, 0x865d}, + {0x0048, 0x865e}, + {0x0012, 0x8608}, + {0x002c, 0x8609}, + {0x0002, 0x860a}, + {0x002c, 0x860b}, + {0x00db, 0x860c}, + {0x00f9, 0x860d}, + {0x00f1, 0x860e}, + {0x00e3, 0x860f}, + {0x002c, 0x8610}, + {0x006c, 0x8651}, + {0x0041, 0x8652}, + {0x0059, 0x8653}, + {0x0040, 0x8654}, + {0x00fa, 0x8611}, + {0x00ff, 0x8612}, + {0x00f8, 0x8613}, + {0x0000, 0x8614}, + {0x0001, 0x863f}, + {0x0000, 0x8640}, + {0x0026, 0x8641}, + {0x0045, 0x8642}, + {0x0060, 0x8643}, + {0x0075, 0x8644}, + {0x0088, 0x8645}, + {0x009b, 0x8646}, + {0x00b0, 0x8647}, + {0x00c5, 0x8648}, + {0x00d2, 0x8649}, + {0x00dc, 0x864a}, + {0x00e5, 0x864b}, + {0x00eb, 0x864c}, + {0x00f0, 0x864d}, + {0x00f6, 0x864e}, + {0x00fa, 0x864f}, + {0x00ff, 0x8650}, + {0x0060, 0x8657}, + {0x0010, 0x8658}, + {0x0018, 0x8659}, + {0x0005, 0x865a}, + {0x0018, 0x8660}, + {0x0003, 0x8509}, + {0x0011, 0x850a}, + {0x0032, 0x850b}, + {0x0010, 0x850c}, + {0x0021, 0x850d}, + {0x0001, 0x8500}, + {0x0000, 0x8508}, + + {0x0012, 0x8608}, + {0x002c, 0x8609}, + {0x0002, 0x860a}, + {0x0039, 0x860b}, + {0x00d0, 0x860c}, + {0x00f7, 0x860d}, + {0x00ed, 0x860e}, + {0x00db, 0x860f}, + {0x0039, 0x8610}, + {0x0012, 0x8657}, + {0x0064, 0x8619}, + +/* This line starts it all, it is not needed here */ +/* since it has been build into the driver */ +/* jfm: don't start now */ +/* {0x0030, 0x8112}, */ + {} +}; + +/* + * Initialization data for Creative Webcam Vista + */ +static const u16 spca508_vista_init_data[][2] = { + {0x0008, 0x8200}, /* Clear register */ + {0x0000, 0x870b}, /* Reset CTL3 */ + {0x0020, 0x8112}, /* Video Drop packet enable */ + {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */ + {0x0000, 0x8110}, /* Disable everything */ + {0x0000, 0x8114}, /* Software GPIO output data */ + {0x0000, 0x8114}, + + {0x0003, 0x8111}, + {0x0000, 0x8111}, + {0x0090, 0x8110}, /* Enable: SSI output, External 2X clock output */ + {0x0020, 0x8112}, + {0x0000, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0003, 0x8114}, + + {0x000f, 0x8402}, /* Memory bank Address */ + {0x0000, 0x8403}, /* Memory bank Address */ + {0x00ba, 0x8804}, /* SSI Slave address */ + {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, /* Will write 2 bytes (DATA1+DATA2) */ + {0x0020, 0x8801}, /* Register address for SSI read/write */ + {0x0044, 0x8805}, /* DATA2 */ + {0x0004, 0x8800}, /* DATA1 -> write triggered */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0009, 0x8801}, + {0x0042, 0x8805}, + {0x0001, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x003c, 0x8801}, + {0x0001, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0001, 0x8801}, + {0x000a, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0002, 0x8801}, + {0x0000, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0003, 0x8801}, + {0x0027, 0x8805}, + {0x0001, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0004, 0x8801}, + {0x0065, 0x8805}, + {0x0001, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0005, 0x8801}, + {0x0003, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0006, 0x8801}, + {0x001c, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0007, 0x8801}, + {0x002a, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x000e, 0x8801}, + {0x0000, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0028, 0x8801}, + {0x002e, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0039, 0x8801}, + {0x0013, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x003b, 0x8801}, + {0x000c, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0035, 0x8801}, + {0x0028, 0x8805}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ + {0x0010, 0x8802}, + {0x0009, 0x8801}, + {0x0042, 0x8805}, + {0x0001, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + + {0x0050, 0x8703}, + {0x0002, 0x8704}, /* External input CKIx1 */ + {0x0001, 0x870c}, /* Select CKOx2 output */ + {0x009a, 0x8600}, /* Line memory Read Counter (L) */ + {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */ + {0x0023, 0x8601}, + {0x0010, 0x8602}, + {0x000a, 0x8603}, + {0x009a, 0x8600}, + {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */ + {0x0003, 0x865c}, /* Vertical offset for valid lines (L) */ + {0x0058, 0x865d}, /* Horizontal valid pixels window (L) */ + {0x0048, 0x865e}, /* Vertical valid lines window (L) */ + {0x0000, 0x865f}, + + {0x0006, 0x8660}, + /* Enable nibble data input, select nibble input order */ + + {0x0013, 0x8608}, /* A11 Coeficients for color correction */ + {0x0028, 0x8609}, + /* Note: these values are confirmed at the end of array */ + {0x0005, 0x860a}, /* ... */ + {0x0025, 0x860b}, + {0x00e1, 0x860c}, + {0x00fa, 0x860d}, + {0x00f4, 0x860e}, + {0x00e8, 0x860f}, + {0x0025, 0x8610}, /* A33 Coef. */ + {0x00fc, 0x8611}, /* White balance offset: R */ + {0x0001, 0x8612}, /* White balance offset: Gr */ + {0x00fe, 0x8613}, /* White balance offset: B */ + {0x0000, 0x8614}, /* White balance offset: Gb */ + + {0x0064, 0x8651}, /* R gain for white balance (L) */ + {0x0040, 0x8652}, /* Gr gain for white balance (L) */ + {0x0066, 0x8653}, /* B gain for white balance (L) */ + {0x0040, 0x8654}, /* Gb gain for white balance (L) */ + {0x0001, 0x863f}, /* Enable fixed gamma correction */ + + {0x00a1, 0x8656}, /* Size - Window1: 256x256, Window2: 128x128, + * UV division: UV no change, + * Enable New edge enhancement */ + {0x0018, 0x8657}, /* Edge gain high threshold */ + {0x0020, 0x8658}, /* Edge gain low threshold */ + {0x000a, 0x8659}, /* Edge bandwidth high threshold */ + {0x0005, 0x865a}, /* Edge bandwidth low threshold */ + {0x0064, 0x8607}, /* UV filter enable */ + + {0x0016, 0x8660}, + {0x0000, 0x86b0}, /* Bad pixels compensation address */ + {0x00dc, 0x86b1}, /* X coord for bad pixels compensation (L) */ + {0x0000, 0x86b2}, + {0x0009, 0x86b3}, /* Y coord for bad pixels compensation (L) */ + {0x0000, 0x86b4}, + + {0x0001, 0x86b0}, + {0x00f5, 0x86b1}, + {0x0000, 0x86b2}, + {0x00c6, 0x86b3}, + {0x0000, 0x86b4}, + + {0x0002, 0x86b0}, + {0x001c, 0x86b1}, + {0x0001, 0x86b2}, + {0x00d7, 0x86b3}, + {0x0000, 0x86b4}, + + {0x0003, 0x86b0}, + {0x001c, 0x86b1}, + {0x0001, 0x86b2}, + {0x00d8, 0x86b3}, + {0x0000, 0x86b4}, + + {0x0004, 0x86b0}, + {0x001d, 0x86b1}, + {0x0001, 0x86b2}, + {0x00d8, 0x86b3}, + {0x0000, 0x86b4}, + {0x001e, 0x8660}, + + /* READ { 0x0000, 0x8608 } -> 0000: 13 */ + /* READ { 0x0000, 0x8609 } -> 0000: 28 */ + /* READ { 0x0000, 0x8610 } -> 0000: 05 */ + /* READ { 0x0000, 0x8611 } -> 0000: 25 */ + /* READ { 0x0000, 0x8612 } -> 0000: e1 */ + /* READ { 0x0000, 0x8613 } -> 0000: fa */ + /* READ { 0x0000, 0x8614 } -> 0000: f4 */ + /* READ { 0x0000, 0x8615 } -> 0000: e8 */ + /* READ { 0x0000, 0x8616 } -> 0000: 25 */ + {} +}; + +static int reg_write(struct usb_device *dev, + u16 index, u16 value) +{ + int ret; + + ret = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, /* request */ + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x", + index, value); + if (ret < 0) + err("reg write: error %d", ret); + return ret; +} + +/* read 1 byte */ +/* returns: negative is error, pos or zero is data */ +static int reg_read(struct gspca_dev *gspca_dev, + u16 index) /* wIndex */ +{ + int ret; + + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* register */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + gspca_dev->usb_buf, 1, + 500); /* timeout */ + PDEBUG(D_USBI, "reg read i:%04x --> %02x", + index, gspca_dev->usb_buf[0]); + if (ret < 0) { + err("reg_read err %d", ret); + return ret; + } + return gspca_dev->usb_buf[0]; +} + +/* send 1 or 2 bytes to the sensor via the Synchronous Serial Interface */ +static int ssi_w(struct gspca_dev *gspca_dev, + u16 reg, u16 val) +{ + struct usb_device *dev = gspca_dev->dev; + int ret, retry; + + ret = reg_write(dev, 0x8802, reg >> 8); + if (ret < 0) + goto out; + ret = reg_write(dev, 0x8801, reg & 0x00ff); + if (ret < 0) + goto out; + if ((reg & 0xff00) == 0x1000) { /* if 2 bytes */ + ret = reg_write(dev, 0x8805, val & 0x00ff); + if (ret < 0) + goto out; + val >>= 8; + } + ret = reg_write(dev, 0x8800, val); + if (ret < 0) + goto out; + + /* poll until not busy */ + retry = 10; + for (;;) { + ret = reg_read(gspca_dev, 0x8803); + if (ret < 0) + break; + if (gspca_dev->usb_buf[0] == 0) + break; + if (--retry <= 0) { + PDEBUG(D_ERR, "ssi_w busy %02x", + gspca_dev->usb_buf[0]); + ret = -1; + break; + } + msleep(8); + } + +out: + return ret; +} + +static int write_vector(struct gspca_dev *gspca_dev, + const u16 (*data)[2]) +{ + struct usb_device *dev = gspca_dev->dev; + int ret = 0; + + while ((*data)[1] != 0) { + if ((*data)[1] & 0x8000) { + if ((*data)[1] == 0xdd00) /* delay */ + msleep((*data)[0]); + else + ret = reg_write(dev, (*data)[1], (*data)[0]); + } else { + ret = ssi_w(gspca_dev, (*data)[1], (*data)[0]); + } + if (ret < 0) + break; + data++; + } + return ret; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + const u16 (*init_data)[2]; + static const u16 (*(init_data_tb[]))[2] = { + spca508_vista_init_data, /* CreativeVista 0 */ + spca508_sightcam_init_data, /* HamaUSBSightcam 1 */ + spca508_sightcam2_init_data, /* HamaUSBSightcam2 2 */ + spca508cs110_init_data, /* IntelEasyPCCamera 3 */ + spca508cs110_init_data, /* MicroInnovationIC200 4 */ + spca508_init_data, /* ViewQuestVQ110 5 */ + }; + +#ifdef GSPCA_DEBUG + int data1, data2; + + /* Read from global register the USB product and vendor IDs, just to + * prove that we can communicate with the device. This works, which + * confirms at we are communicating properly and that the device + * is a 508. */ + data1 = reg_read(gspca_dev, 0x8104); + data2 = reg_read(gspca_dev, 0x8105); + PDEBUG(D_PROBE, "Webcam Vendor ID: 0x%02x%02x", data2, data1); + + data1 = reg_read(gspca_dev, 0x8106); + data2 = reg_read(gspca_dev, 0x8107); + PDEBUG(D_PROBE, "Webcam Product ID: 0x%02x%02x", data2, data1); + + data1 = reg_read(gspca_dev, 0x8621); + PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1); +#endif + + cam = &gspca_dev->cam; + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + + sd->subtype = id->driver_info; + sd->brightness = BRIGHTNESS_DEF; + + init_data = init_data_tb[sd->subtype]; + return write_vector(gspca_dev, init_data); +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + int mode; + + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + reg_write(gspca_dev->dev, 0x8500, mode); + switch (mode) { + case 0: + case 1: + reg_write(gspca_dev->dev, 0x8700, 0x28); /* clock */ + break; + default: +/* case 2: */ +/* case 3: */ + reg_write(gspca_dev->dev, 0x8700, 0x23); /* clock */ + break; + } + reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20); + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* Video ISO disable, Video Drop Packet enable: */ + reg_write(gspca_dev->dev, 0x8112, 0x20); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + switch (data[0]) { + case 0: /* start of frame */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + data += SPCA508_OFFSET_DATA; + len -= SPCA508_OFFSET_DATA; + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + break; + case 0xff: /* drop */ + break; + default: + data += 1; + len -= 1; + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + break; + } +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 brightness = sd->brightness; + + /* MX seem contrast */ + reg_write(gspca_dev->dev, 0x8651, brightness); + reg_write(gspca_dev->dev, 0x8652, brightness); + reg_write(gspca_dev->dev, 0x8653, brightness); + reg_write(gspca_dev->dev, 0x8654, brightness); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0130, 0x0130), .driver_info = HamaUSBSightcam}, + {USB_DEVICE(0x041e, 0x4018), .driver_info = CreativeVista}, + {USB_DEVICE(0x0733, 0x0110), .driver_info = ViewQuestVQ110}, + {USB_DEVICE(0x0af9, 0x0010), .driver_info = HamaUSBSightcam}, + {USB_DEVICE(0x0af9, 0x0011), .driver_info = HamaUSBSightcam2}, + {USB_DEVICE(0x8086, 0x0110), .driver_info = IntelEasyPCCamera}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca561.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca561.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca561.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/spca561.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1118 @@ +/* + * Sunplus spca561 subdriver + * + * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "spca561" + +#include +#include "gspca.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + __u16 exposure; /* rev12a only */ +#define EXPOSURE_MIN 1 +#define EXPOSURE_DEF 700 /* == 10 fps */ +#define EXPOSURE_MAX (2047 + 325) /* see setexposure */ + + __u8 contrast; /* rev72a only */ +#define CONTRAST_MIN 0x00 +#define CONTRAST_DEF 0x20 +#define CONTRAST_MAX 0x3f + + __u8 brightness; /* rev72a only */ +#define BRIGHTNESS_MIN 0 +#define BRIGHTNESS_DEF 0x20 +#define BRIGHTNESS_MAX 0x3f + + __u8 white; +#define HUE_MIN 1 +#define HUE_DEF 0x40 +#define HUE_MAX 0x7f + + __u8 autogain; +#define AUTOGAIN_MIN 0 +#define AUTOGAIN_DEF 1 +#define AUTOGAIN_MAX 1 + + __u8 gain; /* rev12a only */ +#define GAIN_MIN 0 +#define GAIN_DEF 63 +#define GAIN_MAX 255 + +#define EXPO12A_DEF 3 + __u8 expo12a; /* expo/gain? for rev 12a */ + + __u8 chip_revision; +#define Rev012A 0 +#define Rev072A 1 + + signed char ag_cnt; +#define AG_CNT_START 13 +}; + +static const struct v4l2_pix_format sif_012a_mode[] = { + {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 4 / 8, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +static const struct v4l2_pix_format sif_072a_mode[] = { + {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* + * Initialization data + * I'm not very sure how to split initialization from open data + * chunks. For now, we'll consider everything as initialization + */ +/* Frame packet header offsets for the spca561 */ +#define SPCA561_OFFSET_SNAP 1 +#define SPCA561_OFFSET_TYPE 2 +#define SPCA561_OFFSET_COMPRESS 3 +#define SPCA561_OFFSET_FRAMSEQ 4 +#define SPCA561_OFFSET_GPIO 5 +#define SPCA561_OFFSET_USBBUFF 6 +#define SPCA561_OFFSET_WIN2GRAVE 7 +#define SPCA561_OFFSET_WIN2RAVE 8 +#define SPCA561_OFFSET_WIN2BAVE 9 +#define SPCA561_OFFSET_WIN2GBAVE 10 +#define SPCA561_OFFSET_WIN1GRAVE 11 +#define SPCA561_OFFSET_WIN1RAVE 12 +#define SPCA561_OFFSET_WIN1BAVE 13 +#define SPCA561_OFFSET_WIN1GBAVE 14 +#define SPCA561_OFFSET_FREQ 15 +#define SPCA561_OFFSET_VSYNC 16 +#define SPCA561_INDEX_I2C_BASE 0x8800 +#define SPCA561_SNAPBIT 0x20 +#define SPCA561_SNAPCTRL 0x40 + +static const u16 rev72a_reset[][2] = { + {0x0000, 0x8114}, /* Software GPIO output data */ + {0x0001, 0x8114}, /* Software GPIO output data */ + {0x0000, 0x8112}, /* Some kind of reset */ + {} +}; +static const __u16 rev72a_init_data1[][2] = { + {0x0003, 0x8701}, /* PCLK clock delay adjustment */ + {0x0001, 0x8703}, /* HSYNC from cmos inverted */ + {0x0011, 0x8118}, /* Enable and conf sensor */ + {0x0001, 0x8118}, /* Conf sensor */ + {0x0092, 0x8804}, /* I know nothing about these */ + {0x0010, 0x8802}, /* 0x88xx registers, so I won't */ + {} +}; +static const u16 rev72a_init_sensor1[][2] = { + {0x0001, 0x000d}, + {0x0002, 0x0018}, + {0x0004, 0x0165}, + {0x0005, 0x0021}, + {0x0007, 0x00aa}, + {0x0020, 0x1504}, + {0x0039, 0x0002}, + {0x0035, 0x0010}, + {0x0009, 0x1049}, + {0x0028, 0x000b}, + {0x003b, 0x000f}, + {0x003c, 0x0000}, + {} +}; +static const __u16 rev72a_init_data2[][2] = { + {0x0018, 0x8601}, /* Pixel/line selection for color separation */ + {0x0000, 0x8602}, /* Optical black level for user setting */ + {0x0060, 0x8604}, /* Optical black horizontal offset */ + {0x0002, 0x8605}, /* Optical black vertical offset */ + {0x0000, 0x8603}, /* Non-automatic optical black level */ + {0x0002, 0x865b}, /* Horizontal offset for valid pixels */ + {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */ + {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */ + {0x0090, 0x865e}, /* Vertical valid lines window (x2) */ + {0x00e0, 0x8406}, /* Memory buffer threshold */ + {0x0000, 0x8660}, /* Compensation memory stuff */ + {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */ + {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */ + {0x0001, 0x8200}, /* OprMode to be executed by hardware */ +/* from ms-win */ + {0x0000, 0x8611}, /* R offset for white balance */ + {0x00fd, 0x8612}, /* Gr offset for white balance */ + {0x0003, 0x8613}, /* B offset for white balance */ + {0x0000, 0x8614}, /* Gb offset for white balance */ +/* from ms-win */ + {0x0035, 0x8651}, /* R gain for white balance */ + {0x0040, 0x8652}, /* Gr gain for white balance */ + {0x005f, 0x8653}, /* B gain for white balance */ + {0x0040, 0x8654}, /* Gb gain for white balance */ + {0x0002, 0x8502}, /* Maximum average bit rate stuff */ + {0x0011, 0x8802}, + + {0x0087, 0x8700}, /* Set master clock (96Mhz????) */ + {0x0081, 0x8702}, /* Master clock output enable */ + + {0x0000, 0x8500}, /* Set image type (352x288 no compression) */ + /* Originally was 0x0010 (352x288 compression) */ + + {0x0002, 0x865b}, /* Horizontal offset for valid pixels */ + {0x0003, 0x865c}, /* Vertical offset for valid lines */ + {} +}; +static const u16 rev72a_init_sensor2[][2] = { + {0x0003, 0x0121}, + {0x0004, 0x0165}, + {0x0005, 0x002f}, /* blanking control column */ + {0x0006, 0x0000}, /* blanking mode row*/ + {0x000a, 0x0002}, + {0x0009, 0x1061}, /* setexposure times && pixel clock + * 0001 0 | 000 0110 0001 */ + {0x0035, 0x0014}, + {} +}; + +/******************** QC Express etch2 stuff ********************/ +static const __u16 Pb100_1map8300[][2] = { + /* reg, value */ + {0x8320, 0x3304}, + + {0x8303, 0x0125}, /* image area */ + {0x8304, 0x0169}, + {0x8328, 0x000b}, + {0x833c, 0x0001}, /*fixme: win:07*/ + + {0x832f, 0x1904}, /*fixme: was 0419*/ + {0x8307, 0x00aa}, + {0x8301, 0x0003}, + {0x8302, 0x000e}, + {} +}; +static const __u16 Pb100_2map8300[][2] = { + /* reg, value */ + {0x8339, 0x0000}, + {0x8307, 0x00aa}, + {} +}; + +static const __u16 spca561_161rev12A_data1[][2] = { + {0x29, 0x8118}, /* Control register (various enable bits) */ + {0x08, 0x8114}, /* GPIO: Led off */ + {0x0e, 0x8112}, /* 0x0e stream off 0x3e stream on */ + {0x00, 0x8102}, /* white balance - new */ + {0x92, 0x8804}, + {0x04, 0x8802}, /* windows uses 08 */ + {} +}; +static const __u16 spca561_161rev12A_data2[][2] = { + {0x21, 0x8118}, + {0x10, 0x8500}, + {0x07, 0x8601}, + {0x07, 0x8602}, + {0x04, 0x8501}, + + {0x07, 0x8201}, /* windows uses 02 */ + {0x08, 0x8200}, + {0x01, 0x8200}, + + {0x90, 0x8604}, + {0x00, 0x8605}, + {0xb0, 0x8603}, + + /* sensor gains */ + {0x07, 0x8601}, /* white balance - new */ + {0x07, 0x8602}, /* white balance - new */ + {0x00, 0x8610}, /* *red */ + {0x00, 0x8611}, /* 3f *green */ + {0x00, 0x8612}, /* green *blue */ + {0x00, 0x8613}, /* blue *green */ + {0x43, 0x8614}, /* green *red - white balance - was 0x35 */ + {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */ + {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */ + {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */ + + {0x0c, 0x8620}, /* 0c */ + {0xc8, 0x8631}, /* c8 */ + {0xc8, 0x8634}, /* c8 */ + {0x23, 0x8635}, /* 23 */ + {0x1f, 0x8636}, /* 1f */ + {0xdd, 0x8637}, /* dd */ + {0xe1, 0x8638}, /* e1 */ + {0x1d, 0x8639}, /* 1d */ + {0x21, 0x863a}, /* 21 */ + {0xe3, 0x863b}, /* e3 */ + {0xdf, 0x863c}, /* df */ + {0xf0, 0x8505}, + {0x32, 0x850a}, +/* {0x99, 0x8700}, * - white balance - new (removed) */ + /* HDG we used to do this in stop0, making the init state and the state + after a start / stop different, so do this here instead. */ + {0x29, 0x8118}, + {} +}; + +static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) +{ + int ret; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value); + if (ret < 0) + err("reg write: error %d", ret); +} + +static void write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][2]) +{ + struct usb_device *dev = gspca_dev->dev; + int i; + + i = 0; + while (data[i][1] != 0) { + reg_w_val(dev, data[i][1], data[i][0]); + i++; + } +} + +/* read 'len' bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 index, __u16 length) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, length, 500); +} + +/* write 'len' bytes from gspca_dev->usb_buf */ +static void reg_w_buf(struct gspca_dev *gspca_dev, + __u16 index, __u16 len) +{ + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, len, 500); +} + +static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg) +{ + int retry = 60; + + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8805, value); + reg_w_val(gspca_dev->dev, 0x8800, value >> 8); + do { + reg_r(gspca_dev, 0x8803, 1); + if (!gspca_dev->usb_buf[0]) + return; + msleep(10); + } while (--retry); +} + +static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) +{ + int retry = 60; + __u8 value; + + reg_w_val(gspca_dev->dev, 0x8804, 0x92); + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01); + do { + reg_r(gspca_dev, 0x8803, 1); + if (!gspca_dev->usb_buf[0]) { + reg_r(gspca_dev, 0x8800, 1); + value = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8805, 1); + return ((int) value << 8) | gspca_dev->usb_buf[0]; + } + msleep(10); + } while (--retry); + return -1; +} + +static void sensor_mapwrite(struct gspca_dev *gspca_dev, + const __u16 (*sensormap)[2]) +{ + while ((*sensormap)[0]) { + gspca_dev->usb_buf[0] = (*sensormap)[1]; + gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8; + reg_w_buf(gspca_dev, (*sensormap)[0], 2); + sensormap++; + } +} + +static void write_sensor_72a(struct gspca_dev *gspca_dev, + const __u16 (*sensor)[2]) +{ + while ((*sensor)[0]) { + i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]); + sensor++; + } +} + +static void init_161rev12A(struct gspca_dev *gspca_dev) +{ + write_vector(gspca_dev, spca561_161rev12A_data1); + sensor_mapwrite(gspca_dev, Pb100_1map8300); +/*fixme: should be in sd_start*/ + write_vector(gspca_dev, spca561_161rev12A_data2); + sensor_mapwrite(gspca_dev, Pb100_2map8300); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + __u16 vendor, product; + __u8 data1, data2; + + /* Read frm global register the USB product and vendor IDs, just to + * prove that we can communicate with the device. This works, which + * confirms at we are communicating properly and that the device + * is a 561. */ + reg_r(gspca_dev, 0x8104, 1); + data1 = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8105, 1); + data2 = gspca_dev->usb_buf[0]; + vendor = (data2 << 8) | data1; + reg_r(gspca_dev, 0x8106, 1); + data1 = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8107, 1); + data2 = gspca_dev->usb_buf[0]; + product = (data2 << 8) | data1; + if (vendor != id->idVendor || product != id->idProduct) { + PDEBUG(D_PROBE, "Bad vendor / product from device"); + return -EINVAL; + } + + cam = &gspca_dev->cam; + gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ + + sd->chip_revision = id->driver_info; + if (sd->chip_revision == Rev012A) { + cam->cam_mode = sif_012a_mode; + cam->nmodes = ARRAY_SIZE(sif_012a_mode); + } else { + cam->cam_mode = sif_072a_mode; + cam->nmodes = ARRAY_SIZE(sif_072a_mode); + } + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->white = HUE_DEF; + sd->exposure = EXPOSURE_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->gain = GAIN_DEF; + sd->expo12a = EXPO12A_DEF; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init_12a(struct gspca_dev *gspca_dev) +{ + PDEBUG(D_STREAM, "Chip revision: 012a"); + init_161rev12A(gspca_dev); + return 0; +} +static int sd_init_72a(struct gspca_dev *gspca_dev) +{ + PDEBUG(D_STREAM, "Chip revision: 072a"); + write_vector(gspca_dev, rev72a_reset); + msleep(200); + write_vector(gspca_dev, rev72a_init_data1); + write_sensor_72a(gspca_dev, rev72a_init_sensor1); + write_vector(gspca_dev, rev72a_init_data2); + write_sensor_72a(gspca_dev, rev72a_init_sensor2); + reg_w_val(gspca_dev->dev, 0x8112, 0x30); + return 0; +} + +/* rev 72a only */ +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + __u8 value; + + value = sd->brightness; + + /* offsets for white balance */ + reg_w_val(dev, 0x8611, value); /* R */ + reg_w_val(dev, 0x8612, value); /* Gr */ + reg_w_val(dev, 0x8613, value); /* B */ + reg_w_val(dev, 0x8614, value); /* Gb */ +} + +static void setwhite(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u16 white; + __u8 blue, red; + __u16 reg; + + /* try to emulate MS-win as possible */ + white = sd->white; + red = 0x20 + white * 3 / 8; + blue = 0x90 - white * 5 / 8; + if (sd->chip_revision == Rev012A) { + reg = 0x8614; + } else { + reg = 0x8651; + red += sd->contrast - 0x20; + blue += sd->contrast - 0x20; + } + reg_w_val(gspca_dev->dev, reg, red); + reg_w_val(gspca_dev->dev, reg + 2, blue); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + __u8 value; + + if (sd->chip_revision != Rev072A) + return; + value = sd->contrast + 0x20; + + /* gains for white balance */ + setwhite(gspca_dev); +/* reg_w_val(dev, 0x8651, value); * R - done by setwhite */ + reg_w_val(dev, 0x8652, value); /* Gr */ +/* reg_w_val(dev, 0x8653, value); * B - done by setwhite */ + reg_w_val(dev, 0x8654, value); /* Gb */ +} + +/* rev 12a only */ +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, expo = 0; + + /* Register 0x8309 controls exposure for the spca561, + the basic exposure setting goes from 1-2047, where 1 is completely + dark and 2047 is very bright. It not only influences exposure but + also the framerate (to allow for longer exposure) from 1 - 300 it + only raises the exposure time then from 300 - 600 it halves the + framerate to be able to further raise the exposure time and for every + 300 more it halves the framerate again. This allows for a maximum + exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps). + Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12 + configure a divider for the base framerate which us used at the + exposure setting of 1-300. These bits configure the base framerate + according to the following formula: fps = 60 / (value + 2) */ + + /* We choose to use the high bits setting the fixed framerate divisor + asap, as setting high basic exposure setting without the fixed + divider in combination with high gains makes the cam stop */ + int table[] = { 0, 450, 550, 625, EXPOSURE_MAX }; + + for (i = 0; i < ARRAY_SIZE(table) - 1; i++) { + if (sd->exposure <= table[i + 1]) { + expo = sd->exposure - table[i]; + if (i) + expo += 300; + expo |= i << 11; + break; + } + } + + gspca_dev->usb_buf[0] = expo; + gspca_dev->usb_buf[1] = expo >> 8; + reg_w_buf(gspca_dev, 0x8309, 2); +} + +/* rev 12a only */ +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the + sensitivity when set, so 31 + one of them set == 63, and 15 + with both of them set == 63 */ + if (sd->gain < 64) + gspca_dev->usb_buf[0] = sd->gain; + else if (sd->gain < 128) + gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40; + else + gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xc0; + + gspca_dev->usb_buf[1] = 0; + reg_w_buf(gspca_dev, 0x8335, 2); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->autogain) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; +} + +static int sd_start_12a(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + int mode; + static const __u8 Reg8391[8] = + {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00}; + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + if (mode <= 1) { + /* Use compression on 320x240 and above */ + reg_w_val(dev, 0x8500, 0x10 | mode); + } else { + /* I couldn't get the compression to work below 320x240 + * Fortunately at these resolutions the bandwidth + * is sufficient to push raw frames at ~20fps */ + reg_w_val(dev, 0x8500, mode); + } /* -- qq@kuku.eu.org */ + + gspca_dev->usb_buf[0] = 0xaa; + gspca_dev->usb_buf[1] = 0x00; + reg_w_buf(gspca_dev, 0x8307, 2); + /* clock - lower 0x8X values lead to fps > 30 */ + reg_w_val(gspca_dev->dev, 0x8700, 0x8a); + /* 0x8f 0x85 0x27 clock */ + reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); + reg_w_val(gspca_dev->dev, 0x850b, 0x03); + memcpy(gspca_dev->usb_buf, Reg8391, 8); + reg_w_buf(gspca_dev, 0x8391, 8); + reg_w_buf(gspca_dev, 0x8390, 8); + setwhite(gspca_dev); + setgain(gspca_dev); + setexposure(gspca_dev); + + /* Led ON (bit 3 -> 0 */ + reg_w_val(gspca_dev->dev, 0x8114, 0x00); + return 0; +} +static int sd_start_72a(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + int Clck; + int mode; + + write_vector(gspca_dev, rev72a_reset); + msleep(200); + write_vector(gspca_dev, rev72a_init_data1); + write_sensor_72a(gspca_dev, rev72a_init_sensor1); + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + switch (mode) { + default: + case 0: + Clck = 0x27; /* ms-win 0x87 */ + break; + case 1: + Clck = 0x25; + break; + case 2: + Clck = 0x22; + break; + case 3: + Clck = 0x21; + break; + } + reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ + reg_w_val(dev, 0x8702, 0x81); + reg_w_val(dev, 0x8500, mode); /* mode */ + write_sensor_72a(gspca_dev, rev72a_init_sensor2); + setcontrast(gspca_dev); +/* setbrightness(gspca_dev); * fixme: bad values */ + setautogain(gspca_dev); + reg_w_val(dev, 0x8112, 0x10 | 0x20); + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->chip_revision == Rev012A) { + reg_w_val(gspca_dev->dev, 0x8112, 0x0e); + /* Led Off (bit 3 -> 1 */ + reg_w_val(gspca_dev->dev, 0x8114, 0x08); + } else { + reg_w_val(gspca_dev->dev, 0x8112, 0x20); +/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */ + } +} + +static void do_autogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int expotimes; + int pixelclk; + int gainG; + __u8 R, Gr, Gb, B; + int y; + __u8 luma_mean = 110; + __u8 luma_delta = 20; + __u8 spring = 4; + + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt >= 0) + return; + sd->ag_cnt = AG_CNT_START; + + switch (sd->chip_revision) { + case Rev072A: + reg_r(gspca_dev, 0x8621, 1); + Gr = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8622, 1); + R = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8623, 1); + B = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8624, 1); + Gb = gspca_dev->usb_buf[0]; + y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8; + /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */ + /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */ + /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */ + + if (y < luma_mean - luma_delta || + y > luma_mean + luma_delta) { + expotimes = i2c_read(gspca_dev, 0x09, 0x10); + pixelclk = 0x0800; + expotimes = expotimes & 0x07ff; + /* PDEBUG(D_PACK, + "Exposition Times 0x%03X Clock 0x%04X ", + expotimes,pixelclk); */ + gainG = i2c_read(gspca_dev, 0x35, 0x10); + /* PDEBUG(D_PACK, + "reading Gain register %d", gainG); */ + + expotimes += (luma_mean - y) >> spring; + gainG += (luma_mean - y) / 50; + /* PDEBUG(D_PACK, + "compute expotimes %d gain %d", + expotimes,gainG); */ + + if (gainG > 0x3f) + gainG = 0x3f; + else if (gainG < 3) + gainG = 3; + i2c_write(gspca_dev, gainG, 0x35); + + if (expotimes > 0x0256) + expotimes = 0x0256; + else if (expotimes < 3) + expotimes = 3; + i2c_write(gspca_dev, expotimes | pixelclk, 0x09); + } + break; + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + len--; + switch (*data++) { /* sequence number */ + case 0: /* start of frame */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + + /* This should never happen */ + if (len < 2) { + PDEBUG(D_ERR, "Short SOF packet, ignoring"); + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + if (data[0] & 0x20) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); + input_sync(gspca_dev->input_dev); + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + } +#endif + + if (data[1] & 0x10) { + /* compressed bayer */ + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + } else { + /* raw bayer (with a header, which we skip) */ + if (sd->chip_revision == Rev012A) { + data += 20; + len -= 20; + } else { + data += 16; + len -= 16; + } + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + } + return; + case 0xff: /* drop (empty mpackets) */ + return; + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +/* rev 72a only */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +/* rev 72a only */ +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (gspca_dev->streaming) + setautogain(gspca_dev); + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->white = val; + if (gspca_dev->streaming) + setwhite(gspca_dev); + return 0; +} + +static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->white; + return 0; +} + +/* rev12a only */ +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +/* rev12a only */ +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +/* control tables */ +static const struct ctrl sd_ctrls_12a[] = { + { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = HUE_MIN, + .maximum = HUE_MAX, + .step = 1, + .default_value = HUE_DEF, + }, + .set = sd_setwhite, + .get = sd_getwhite, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = EXPOSURE_MIN, + .maximum = EXPOSURE_MAX, + .step = 1, + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = GAIN_MIN, + .maximum = GAIN_MAX, + .step = 1, + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static const struct ctrl sd_ctrls_72a[] = { + { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = HUE_MIN, + .maximum = HUE_MAX, + .step = 1, + .default_value = HUE_DEF, + }, + .set = sd_setwhite, + .get = sd_getwhite, + }, + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = BRIGHTNESS_MIN, + .maximum = BRIGHTNESS_MAX, + .step = 1, + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = CONTRAST_MIN, + .maximum = CONTRAST_MAX, + .step = 1, + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = AUTOGAIN_MIN, + .maximum = AUTOGAIN_MAX, + .step = 1, + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + +/* sub-driver description */ +static const struct sd_desc sd_desc_12a = { + .name = MODULE_NAME, + .ctrls = sd_ctrls_12a, + .nctrls = ARRAY_SIZE(sd_ctrls_12a), + .config = sd_config, + .init = sd_init_12a, + .start = sd_start_12a, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .other_input = 1, +#endif +}; +static const struct sd_desc sd_desc_72a = { + .name = MODULE_NAME, + .ctrls = sd_ctrls_72a, + .nctrls = ARRAY_SIZE(sd_ctrls_72a), + .config = sd_config, + .init = sd_init_72a, + .start = sd_start_72a, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .other_input = 1, +#endif +}; +static const struct sd_desc *sd_desc[2] = { + &sd_desc_12a, + &sd_desc_72a +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A}, + {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A}, + {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A}, + {USB_DEVICE(0x0461, 0x0815), .driver_info = Rev072A}, + {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A}, + {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A}, + {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A}, + {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A}, + {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + sd_desc[id->driver_info], + sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq905.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq905.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq905.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq905.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,448 @@ +/* + * SQ905 subdriver + * + * Copyright (C) 2008, 2009 Adam Baker and Theodore Kilgore + * + * 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, or + * any later version. + * + * 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 + */ + +/* + * History and Acknowledgments + * + * The original Linux driver for SQ905 based cameras was written by + * Marcell Lengyel and furter developed by many other contributors + * and is available from http://sourceforge.net/projects/sqcam/ + * + * This driver takes advantage of the reverse engineering work done for + * that driver and for libgphoto2 but shares no code with them. + * + * This driver has used as a base the finepix driver and other gspca + * based drivers and may still contain code fragments taken from those + * drivers. + */ + +#define MODULE_NAME "sq905" + +#include +#include +#include "gspca.h" + +MODULE_AUTHOR("Adam Baker , " + "Theodore Kilgore "); +MODULE_DESCRIPTION("GSPCA/SQ905 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* Default timeouts, in ms */ +#define SQ905_CMD_TIMEOUT 500 +#define SQ905_DATA_TIMEOUT 1000 + +/* Maximum transfer size to use. */ +#define SQ905_MAX_TRANSFER 0x8000 +#define FRAME_HEADER_LEN 64 + +/* The known modes, or registers. These go in the "value" slot. */ + +/* 00 is "none" obviously */ + +#define SQ905_BULK_READ 0x03 /* precedes any bulk read */ +#define SQ905_COMMAND 0x06 /* precedes the command codes below */ +#define SQ905_PING 0x07 /* when reading an "idling" command */ +#define SQ905_READ_DONE 0xc0 /* ack bulk read completed */ + +/* Any non-zero value in the bottom 2 bits of the 2nd byte of + * the ID appears to indicate the camera can do 640*480. If the + * LSB of that byte is set the image is just upside down, otherwise + * it is rotated 180 degrees. */ +#define SQ905_HIRES_MASK 0x00000300 +#define SQ905_ORIENTATION_MASK 0x00000100 + +/* Some command codes. These go in the "index" slot. */ + +#define SQ905_ID 0xf0 /* asks for model string */ +#define SQ905_CONFIG 0x20 /* gets photo alloc. table, not used here */ +#define SQ905_DATA 0x30 /* accesses photo data, not used here */ +#define SQ905_CLEAR 0xa0 /* clear everything */ +#define SQ905_CAPTURE_LOW 0x60 /* Starts capture at 160x120 */ +#define SQ905_CAPTURE_MED 0x61 /* Starts capture at 320x240 */ +#define SQ905_CAPTURE_HIGH 0x62 /* Starts capture at 640x480 (some cams only) */ +/* note that the capture command also controls the output dimensions */ + +/* Structure to hold all of our device specific stuff */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + /* + * Driver stuff + */ + struct work_struct work_struct; + struct workqueue_struct *work_thread; +}; + +static struct v4l2_pix_format sq905_mode[] = { + { 160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + { 320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + { 640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0} +}; + +/* + * Send a command to the camera. + */ +static int sq905_command(struct gspca_dev *gspca_dev, u16 index) +{ + int ret; + + gspca_dev->usb_buf[0] = '\0'; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + USB_REQ_SYNCH_FRAME, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + SQ905_COMMAND, index, gspca_dev->usb_buf, 1, + SQ905_CMD_TIMEOUT); + if (ret < 0) { + err("%s: usb_control_msg failed (%d)", + __func__, ret); + return ret; + } + + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + USB_REQ_SYNCH_FRAME, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + SQ905_PING, 0, gspca_dev->usb_buf, 1, + SQ905_CMD_TIMEOUT); + if (ret < 0) { + err("%s: usb_control_msg failed 2 (%d)", + __func__, ret); + return ret; + } + + return 0; +} + +/* + * Acknowledge the end of a frame - see warning on sq905_command. + */ +static int sq905_ack_frame(struct gspca_dev *gspca_dev) +{ + int ret; + + gspca_dev->usb_buf[0] = '\0'; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + USB_REQ_SYNCH_FRAME, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + SQ905_READ_DONE, 0, gspca_dev->usb_buf, 1, + SQ905_CMD_TIMEOUT); + if (ret < 0) { + err("%s: usb_control_msg failed (%d)", __func__, ret); + return ret; + } + + return 0; +} + +/* + * request and read a block of data - see warning on sq905_command. + */ +static int +sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock) +{ + int ret; + int act_len; + + gspca_dev->usb_buf[0] = '\0'; + if (need_lock) + mutex_lock(&gspca_dev->usb_lock); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + USB_REQ_SYNCH_FRAME, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + SQ905_BULK_READ, size, gspca_dev->usb_buf, + 1, SQ905_CMD_TIMEOUT); + if (need_lock) + mutex_unlock(&gspca_dev->usb_lock); + if (ret < 0) { + err("%s: usb_control_msg failed (%d)", __func__, ret); + return ret; + } + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x81), + data, size, &act_len, SQ905_DATA_TIMEOUT); + + /* successful, it returns 0, otherwise negative */ + if (ret < 0 || act_len != size) { + err("bulk read fail (%d) len %d/%d", + ret, act_len, size); + return -EIO; + } + return 0; +} + +/* This function is called as a workqueue function and runs whenever the camera + * is streaming data. Because it is a workqueue function it is allowed to sleep + * so we can use synchronous USB calls. To avoid possible collisions with other + * threads attempting to use the camera's USB interface we take the gspca + * usb_lock when performing USB operations. In practice the only thing we need + * to protect against is the usb_set_interface call that gspca makes during + * stream_off as the camera doesn't provide any controls that the user could try + * to change. + */ +static void sq905_dostream(struct work_struct *work) +{ + struct sd *dev = container_of(work, struct sd, work_struct); + struct gspca_dev *gspca_dev = &dev->gspca_dev; + int bytes_left; /* bytes remaining in current frame. */ + int data_len; /* size to use for the next read. */ + int header_read; /* true if we have already read the frame header. */ + int packet_type; + int frame_sz; + int ret; + u8 *data; + u8 *buffer; + + buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); + if (!buffer) { + err("Couldn't allocate USB buffer"); + goto quit_stream; + } + + frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage + + FRAME_HEADER_LEN; + + while (gspca_dev->present && gspca_dev->streaming) { + /* request some data and then read it until we have + * a complete frame. */ + bytes_left = frame_sz; + header_read = 0; + + /* Note we do not check for gspca_dev->streaming here, as + we must finish reading an entire frame, otherwise the + next time we stream we start reading in the middle of a + frame. */ + while (bytes_left > 0 && gspca_dev->present) { + data_len = bytes_left > SQ905_MAX_TRANSFER ? + SQ905_MAX_TRANSFER : bytes_left; + ret = sq905_read_data(gspca_dev, buffer, data_len, 1); + if (ret < 0) + goto quit_stream; + PDEBUG(D_PACK, + "Got %d bytes out of %d for frame", + data_len, bytes_left); + bytes_left -= data_len; + data = buffer; + if (!header_read) { + packet_type = FIRST_PACKET; + /* The first 64 bytes of each frame are + * a header full of FF 00 bytes */ + data += FRAME_HEADER_LEN; + data_len -= FRAME_HEADER_LEN; + header_read = 1; + } else if (bytes_left == 0) { + packet_type = LAST_PACKET; + } else { + packet_type = INTER_PACKET; + } + gspca_frame_add(gspca_dev, packet_type, + data, data_len); + /* If entire frame fits in one packet we still + need to add a LAST_PACKET */ + if (packet_type == FIRST_PACKET && + bytes_left == 0) + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + } + if (gspca_dev->present) { + /* acknowledge the frame */ + mutex_lock(&gspca_dev->usb_lock); + ret = sq905_ack_frame(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + if (ret < 0) + goto quit_stream; + } + } +quit_stream: + if (gspca_dev->present) { + mutex_lock(&gspca_dev->usb_lock); + sq905_command(gspca_dev, SQ905_CLEAR); + mutex_unlock(&gspca_dev->usb_lock); + } + kfree(buffer); +} + +/* This function is called at probe time just before sd_init */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam = &gspca_dev->cam; + struct sd *dev = (struct sd *) gspca_dev; + + /* We don't use the buffer gspca allocates so make it small. */ + cam->bulk = 1; + cam->bulk_size = 64; + + INIT_WORK(&dev->work_struct, sq905_dostream); + + return 0; +} + +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *) gspca_dev; + + /* wait for the work queue to terminate */ + mutex_unlock(&gspca_dev->usb_lock); + /* This waits for sq905_dostream to finish */ + destroy_workqueue(dev->work_thread); + dev->work_thread = NULL; + mutex_lock(&gspca_dev->usb_lock); +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + u32 ident; + int ret; + + /* connect to the camera and read + * the model ID and process that and put it away. + */ + ret = sq905_command(gspca_dev, SQ905_CLEAR); + if (ret < 0) + return ret; + ret = sq905_command(gspca_dev, SQ905_ID); + if (ret < 0) + return ret; + ret = sq905_read_data(gspca_dev, gspca_dev->usb_buf, 4, 0); + if (ret < 0) + return ret; + /* usb_buf is allocated with kmalloc so is aligned. + * Camera model number is the right way round if we assume this + * reverse engineered ID is supposed to be big endian. */ + ident = be32_to_cpup((__be32 *)gspca_dev->usb_buf); + ret = sq905_command(gspca_dev, SQ905_CLEAR); + if (ret < 0) + return ret; + PDEBUG(D_CONF, "SQ905 camera ID %08x detected", ident); + gspca_dev->cam.cam_mode = sq905_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(sq905_mode); + if (!(ident & SQ905_HIRES_MASK)) + gspca_dev->cam.nmodes--; + + if (ident & SQ905_ORIENTATION_MASK) + gspca_dev->cam.input_flags = V4L2_IN_ST_VFLIP; + else + gspca_dev->cam.input_flags = V4L2_IN_ST_VFLIP | + V4L2_IN_ST_HFLIP; + return 0; +} + +/* Set up for getting frames. */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *) gspca_dev; + int ret; + + /* "Open the shutter" and set size, to start capture */ + switch (gspca_dev->curr_mode) { + default: +/* case 2: */ + PDEBUG(D_STREAM, "Start streaming at high resolution"); + ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_HIGH); + break; + case 1: + PDEBUG(D_STREAM, "Start streaming at medium resolution"); + ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_MED); + break; + case 0: + PDEBUG(D_STREAM, "Start streaming at low resolution"); + ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_LOW); + } + + if (ret < 0) { + PDEBUG(D_ERR, "Start streaming command failed"); + return ret; + } + /* Start the workqueue function to do the streaming */ + dev->work_thread = create_singlethread_workqueue(MODULE_NAME); + queue_work(dev->work_thread, &dev->work_struct); + + return 0; +} + +/* Table of supported USB devices */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x2770, 0x9120)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, +}; + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + &sd_desc, + sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq905c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq905c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq905c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq905c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,354 @@ +/* + * SQ905C subdriver + * + * Copyright (C) 2009 Theodore Kilgore + * + * 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, or + * any later version. + * + * 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 + */ + +/* + * + * This driver uses work done in + * libgphoto2/camlibs/digigr8, Copyright (C) Theodore Kilgore. + * + * This driver has also used as a base the sq905c driver + * and may contain code fragments from it. + */ + +#define MODULE_NAME "sq905c" + +#include +#include +#include "gspca.h" + +MODULE_AUTHOR("Theodore Kilgore "); +MODULE_DESCRIPTION("GSPCA/SQ905C USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* Default timeouts, in ms */ +#define SQ905C_CMD_TIMEOUT 500 +#define SQ905C_DATA_TIMEOUT 1000 + +/* Maximum transfer size to use. */ +#define SQ905C_MAX_TRANSFER 0x8000 + +#define FRAME_HEADER_LEN 0x50 + +/* Commands. These go in the "value" slot. */ +#define SQ905C_CLEAR 0xa0 /* clear everything */ +#define SQ905C_GET_ID 0x14f4 /* Read version number */ +#define SQ905C_CAPTURE_LOW 0xa040 /* Starts capture at 160x120 */ +#define SQ905C_CAPTURE_MED 0x1440 /* Starts capture at 320x240 */ +#define SQ905C_CAPTURE_HI 0x2840 /* Starts capture at 320x240 */ + +/* For capture, this must go in the "index" slot. */ +#define SQ905C_CAPTURE_INDEX 0x110f + +/* Structure to hold all of our device specific stuff */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + const struct v4l2_pix_format *cap_mode; + /* Driver stuff */ + struct work_struct work_struct; + struct workqueue_struct *work_thread; +}; + +/* + * Most of these cameras will do 640x480 and 320x240. 160x120 works + * in theory but gives very poor output. Therefore, not supported. + * The 0x2770:0x9050 cameras have max resolution of 320x240. + */ +static struct v4l2_pix_format sq905c_mode[] = { + { 320, 240, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + { 640, 480, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0} +}; + +/* Send a command to the camera. */ +static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index) +{ + int ret; + + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + USB_REQ_SYNCH_FRAME, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + command, index, NULL, 0, + SQ905C_CMD_TIMEOUT); + if (ret < 0) { + err("%s: usb_control_msg failed (%d)", + __func__, ret); + return ret; + } + + return 0; +} + +static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index, + int size) +{ + int ret; + + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + USB_REQ_SYNCH_FRAME, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + command, index, gspca_dev->usb_buf, size, + SQ905C_CMD_TIMEOUT); + if (ret < 0) { + err("%s: usb_control_msg failed (%d)", + __func__, ret); + return ret; + } + + return 0; +} + +/* This function is called as a workqueue function and runs whenever the camera + * is streaming data. Because it is a workqueue function it is allowed to sleep + * so we can use synchronous USB calls. To avoid possible collisions with other + * threads attempting to use the camera's USB interface the gspca usb_lock is + * used when performing the one USB control operation inside the workqueue, + * which tells the camera to close the stream. In practice the only thing + * which needs to be protected against is the usb_set_interface call that + * gspca makes during stream_off. Otherwise the camera doesn't provide any + * controls that the user could try to change. + */ +static void sq905c_dostream(struct work_struct *work) +{ + struct sd *dev = container_of(work, struct sd, work_struct); + struct gspca_dev *gspca_dev = &dev->gspca_dev; + int bytes_left; /* bytes remaining in current frame. */ + int data_len; /* size to use for the next read. */ + int act_len; + int packet_type; + int ret; + u8 *buffer; + + buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); + if (!buffer) { + err("Couldn't allocate USB buffer"); + goto quit_stream; + } + + while (gspca_dev->present && gspca_dev->streaming) { + /* Request the header, which tells the size to download */ + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x81), + buffer, FRAME_HEADER_LEN, &act_len, + SQ905C_DATA_TIMEOUT); + PDEBUG(D_STREAM, + "Got %d bytes out of %d for header", + act_len, FRAME_HEADER_LEN); + if (ret < 0 || act_len < FRAME_HEADER_LEN) + goto quit_stream; + /* size is read from 4 bytes starting 0x40, little endian */ + bytes_left = buffer[0x40]|(buffer[0x41]<<8)|(buffer[0x42]<<16) + |(buffer[0x43]<<24); + PDEBUG(D_STREAM, "bytes_left = 0x%x", bytes_left); + /* We keep the header. It has other information, too. */ + packet_type = FIRST_PACKET; + gspca_frame_add(gspca_dev, packet_type, + buffer, FRAME_HEADER_LEN); + while (bytes_left > 0 && gspca_dev->present) { + data_len = bytes_left > SQ905C_MAX_TRANSFER ? + SQ905C_MAX_TRANSFER : bytes_left; + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x81), + buffer, data_len, &act_len, + SQ905C_DATA_TIMEOUT); + if (ret < 0 || act_len < data_len) + goto quit_stream; + PDEBUG(D_STREAM, + "Got %d bytes out of %d for frame", + data_len, bytes_left); + bytes_left -= data_len; + if (bytes_left == 0) + packet_type = LAST_PACKET; + else + packet_type = INTER_PACKET; + gspca_frame_add(gspca_dev, packet_type, + buffer, data_len); + } + } +quit_stream: + if (gspca_dev->present) { + mutex_lock(&gspca_dev->usb_lock); + sq905c_command(gspca_dev, SQ905C_CLEAR, 0); + mutex_unlock(&gspca_dev->usb_lock); + } + kfree(buffer); +} + +/* This function is called at probe time just before sd_init */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam = &gspca_dev->cam; + struct sd *dev = (struct sd *) gspca_dev; + int ret; + + PDEBUG(D_PROBE, + "SQ9050 camera detected" + " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + + ret = sq905c_command(gspca_dev, SQ905C_GET_ID, 0); + if (ret < 0) { + PDEBUG(D_ERR, "Get version command failed"); + return ret; + } + + ret = sq905c_read(gspca_dev, 0xf5, 0, 20); + if (ret < 0) { + PDEBUG(D_ERR, "Reading version command failed"); + return ret; + } + /* Note we leave out the usb id and the manufacturing date */ + PDEBUG(D_PROBE, + "SQ9050 ID string: %02x - %02x %02x %02x %02x %02x %02x", + gspca_dev->usb_buf[3], + gspca_dev->usb_buf[14], gspca_dev->usb_buf[15], + gspca_dev->usb_buf[16], gspca_dev->usb_buf[17], + gspca_dev->usb_buf[18], gspca_dev->usb_buf[19]); + + cam->cam_mode = sq905c_mode; + cam->nmodes = 2; + if (gspca_dev->usb_buf[15] == 0) + cam->nmodes = 1; + /* We don't use the buffer gspca allocates so make it small. */ + cam->bulk_size = 32; + cam->bulk = 1; + INIT_WORK(&dev->work_struct, sq905c_dostream); + return 0; +} + +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *) gspca_dev; + + /* wait for the work queue to terminate */ + mutex_unlock(&gspca_dev->usb_lock); + /* This waits for sq905c_dostream to finish */ + destroy_workqueue(dev->work_thread); + dev->work_thread = NULL; + mutex_lock(&gspca_dev->usb_lock); +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + int ret; + + /* connect to the camera and reset it. */ + ret = sq905c_command(gspca_dev, SQ905C_CLEAR, 0); + return ret; +} + +/* Set up for getting frames. */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *) gspca_dev; + int ret; + + dev->cap_mode = gspca_dev->cam.cam_mode; + /* "Open the shutter" and set size, to start capture */ + switch (gspca_dev->width) { + case 640: + PDEBUG(D_STREAM, "Start streaming at high resolution"); + dev->cap_mode++; + ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_HI, + SQ905C_CAPTURE_INDEX); + break; + default: /* 320 */ + PDEBUG(D_STREAM, "Start streaming at medium resolution"); + ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_MED, + SQ905C_CAPTURE_INDEX); + } + + if (ret < 0) { + PDEBUG(D_ERR, "Start streaming command failed"); + return ret; + } + /* Start the workqueue function to do the streaming */ + dev->work_thread = create_singlethread_workqueue(MODULE_NAME); + queue_work(dev->work_thread, &dev->work_struct); + + return 0; +} + +/* Table of supported USB devices */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x2770, 0x905c)}, + {USB_DEVICE(0x2770, 0x9050)}, + {USB_DEVICE(0x2770, 0x9051)}, + {USB_DEVICE(0x2770, 0x9052)}, + {USB_DEVICE(0x2770, 0x913d)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, +}; + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + &sd_desc, + sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq930x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq930x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq930x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sq930x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1208 @@ +/* + * SQ930x subdriver + * + * Copyright (C) 2010 Jean-François Moine + * Copyright (C) 2006 -2008 Gerard Klaver + * Copyright (C) 2007 Sam Revitch + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "sq930x" + +#include "gspca.h" + +MODULE_AUTHOR("Jean-Francois Moine \n" + "Gerard Klaver "); +MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* Structure to hold all of our device specific stuff */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u16 expo; + u8 gain; + + u8 do_ctrl; + u8 gpio[2]; + u8 sensor; + u8 type; +#define Generic 0 +#define Creative_live_motion 1 +}; +enum sensors { + SENSOR_ICX098BQ, + SENSOR_LZ24BP, + SENSOR_MI0360, + SENSOR_MT9V111, /* = MI360SOC */ + SENSOR_OV7660, + SENSOR_OV9630, +}; + +static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0x0001, + .maximum = 0x0fff, + .step = 1, +#define EXPO_DEF 0x0356 + .default_value = EXPO_DEF, + }, + .set = sd_setexpo, + .get = sd_getexpo, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0x01, + .maximum = 0xff, + .step = 1, +#define GAIN_DEF 0x8d + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + {640, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, +}; + +/* sq930x registers */ +#define SQ930_CTRL_UCBUS_IO 0x0001 +#define SQ930_CTRL_I2C_IO 0x0002 +#define SQ930_CTRL_GPIO 0x0005 +#define SQ930_CTRL_CAP_START 0x0010 +#define SQ930_CTRL_CAP_STOP 0x0011 +#define SQ930_CTRL_SET_EXPOSURE 0x001d +#define SQ930_CTRL_RESET 0x001e +#define SQ930_CTRL_GET_DEV_INFO 0x001f + +/* gpio 1 (8..15) */ +#define SQ930_GPIO_DFL_I2C_SDA 0x0001 +#define SQ930_GPIO_DFL_I2C_SCL 0x0002 +#define SQ930_GPIO_RSTBAR 0x0004 +#define SQ930_GPIO_EXTRA1 0x0040 +#define SQ930_GPIO_EXTRA2 0x0080 +/* gpio 3 (24..31) */ +#define SQ930_GPIO_POWER 0x0200 +#define SQ930_GPIO_DFL_LED 0x1000 + +struct ucbus_write_cmd { + u16 bw_addr; + u8 bw_data; +}; +struct i2c_write_cmd { + u8 reg; + u16 val; +}; + +static const struct ucbus_write_cmd icx098bq_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce}, + {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e}, + {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02}, + {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02}, + {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00}, + {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04}, + {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00}, + {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48}, + {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, + {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, + {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff}, + {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, + {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00}, + {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, + {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, + {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c}, + {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30}, + {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30}, + {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc}, + {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, + {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00}, + {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00}, + {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa}, + {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa}, + {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, + {0xf800, 0x03} +}; +static const struct ucbus_write_cmd icx098bq_start_1[] = { + {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xc0}, + {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xc0}, + {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, + {0xf5f9, 0x00} +}; + +static const struct ucbus_write_cmd icx098bq_start_2[] = { + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03} +}; + +static const struct ucbus_write_cmd lz24bp_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe}, + {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06}, + {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02}, + {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00}, + {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00}, + {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03}, + {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00}, + {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48}, + {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, + {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, + {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0}, + {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, + {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00}, + {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, + {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, + {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30}, + {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c}, + {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c}, + {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d}, + {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, + {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d}, + {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d}, + {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04}, + {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04}, + {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, + {0xf800, 0x03} +}; +static const struct ucbus_write_cmd lz24bp_start_1_gen[] = { + {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xb3}, + {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xb3}, + {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, + {0xf5f9, 0x00} +}; + +static const struct ucbus_write_cmd lz24bp_start_1_clm[] = { + {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, + {0xf5f4, 0xc0}, + {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, + {0xf5f4, 0xc0}, + {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, + {0xf5f9, 0x00} +}; + +static const struct ucbus_write_cmd lz24bp_start_2[] = { + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48}, + {0xf807, 0x7f}, {0xf800, 0x03}, + {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, + {0xf807, 0x7f}, {0xf800, 0x03} +}; + +static const struct ucbus_write_cmd mi0360_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc}, + {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00} +}; +static const struct i2c_write_cmd mi0360_init_23[] = { + {0x30, 0x0040}, /* reserved - def 0x0005 */ + {0x31, 0x0000}, /* reserved - def 0x002a */ + {0x34, 0x0100}, /* reserved - def 0x0100 */ + {0x3d, 0x068f}, /* reserved - def 0x068f */ +}; +static const struct i2c_write_cmd mi0360_init_24[] = { + {0x03, 0x01e5}, /* window height */ + {0x04, 0x0285}, /* window width */ +}; +static const struct i2c_write_cmd mi0360_init_25[] = { + {0x35, 0x0020}, /* global gain */ + {0x2b, 0x0020}, /* green1 gain */ + {0x2c, 0x002a}, /* blue gain */ + {0x2d, 0x0028}, /* red gain */ + {0x2e, 0x0020}, /* green2 gain */ +}; +static const struct ucbus_write_cmd mi0360_start_1[] = { + {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xa6}, + {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xa6}, + {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, + {0xf5f9, 0x00} +}; +static const struct i2c_write_cmd mi0360_start_2[] = { + {0x62, 0x041d}, /* reserved - def 0x0418 */ +}; +static const struct i2c_write_cmd mi0360_start_3[] = { + {0x05, 0x007b}, /* horiz blanking */ +}; +static const struct i2c_write_cmd mi0360_start_4[] = { + {0x05, 0x03f5}, /* horiz blanking */ +}; + +static const struct i2c_write_cmd mt9v111_init_0[] = { + {0x01, 0x0001}, /* select IFP/SOC registers */ + {0x06, 0x300c}, /* operating mode control */ + {0x08, 0xcc00}, /* output format control (RGB) */ + {0x01, 0x0004}, /* select sensor core registers */ +}; +static const struct i2c_write_cmd mt9v111_init_1[] = { + {0x03, 0x01e5}, /* window height */ + {0x04, 0x0285}, /* window width */ +}; +static const struct i2c_write_cmd mt9v111_init_2[] = { + {0x30, 0x7800}, + {0x31, 0x0000}, + {0x07, 0x3002}, /* output control */ + {0x35, 0x0020}, /* global gain */ + {0x2b, 0x0020}, /* green1 gain */ + {0x2c, 0x0020}, /* blue gain */ + {0x2d, 0x0020}, /* red gain */ + {0x2e, 0x0020}, /* green2 gain */ +}; +static const struct ucbus_write_cmd mt9v111_start_1[] = { + {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xaa}, + {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, + {0xf5f4, 0xaa}, + {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a}, + {0xf5f9, 0x0a} +}; +static const struct i2c_write_cmd mt9v111_init_3[] = { + {0x62, 0x0405}, +}; +static const struct i2c_write_cmd mt9v111_init_4[] = { +/* {0x05, 0x00ce}, */ + {0x05, 0x005d}, /* horizontal blanking */ +}; + +static const struct ucbus_write_cmd ov7660_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0}, + {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03} +}; + +static const struct ucbus_write_cmd ov9630_start_0[] = { + {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00}, + {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03} +}; + +/* start parameters indexed by [sensor][mode] */ +static const struct cap_s { + u8 cc_sizeid; + u8 cc_bytes[32]; +} capconfig[4][2] = { + [SENSOR_ICX098BQ] = { + {2, /* Bayer 320x240 */ + {0x05, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, + 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {4, /* Bayer 640x480 */ + {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + }, + [SENSOR_LZ24BP] = { + {2, /* Bayer 320x240 */ + {0x05, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, + 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {4, /* Bayer 640x480 */ + {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + }, + [SENSOR_MI0360] = { + {2, /* Bayer 320x240 */ + {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, + 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {4, /* Bayer 640x480 */ + {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + }, + [SENSOR_MT9V111] = { + {2, /* Bayer 320x240 */ + {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, + 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + {4, /* Bayer 640x480 */ + {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, + 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + }, +}; + +struct sensor_s { + const char *name; + u8 i2c_addr; + u8 i2c_dum; + u8 gpio[5]; + u8 cmd_len; + const struct ucbus_write_cmd *cmd; +}; + +static const struct sensor_s sensor_tb[] = { + [SENSOR_ICX098BQ] = { + "icx098bp", + 0x00, 0x00, + {0, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + SQ930_GPIO_RSTBAR + }, + 8, icx098bq_start_0 + }, + [SENSOR_LZ24BP] = { + "lz24bp", + 0x00, 0x00, + {0, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + SQ930_GPIO_RSTBAR + }, + 8, lz24bp_start_0 + }, + [SENSOR_MI0360] = { + "mi0360", + 0x5d, 0x80, + {SQ930_GPIO_RSTBAR, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + 0 + }, + 7, mi0360_start_0 + }, + [SENSOR_MT9V111] = { + "mt9v111", + 0x5c, 0x7f, + {SQ930_GPIO_RSTBAR, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + 0 + }, + 7, mi0360_start_0 + }, + [SENSOR_OV7660] = { + "ov7660", + 0x21, 0x00, + {0, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + SQ930_GPIO_RSTBAR + }, + 7, ov7660_start_0 + }, + [SENSOR_OV9630] = { + "ov9630", + 0x30, 0x00, + {0, + SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, + SQ930_GPIO_DFL_I2C_SDA, + 0, + SQ930_GPIO_RSTBAR + }, + 7, ov9630_start_0 + }, +}; + +static void reg_r(struct gspca_dev *gspca_dev, + u16 value, int len) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0x0c, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, 0, gspca_dev->usb_buf, len, + 500); + if (ret < 0) { + err("reg_r %04x failed %d", value, ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x0c, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, + 500); + msleep(30); + if (ret < 0) { + err("reg_w %04x %04x failed %d", value, index, ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index, + const u8 *data, int len) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x", + value, index, *data, data[len - 1]); + memcpy(gspca_dev->usb_buf, data, len); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x0c, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, gspca_dev->usb_buf, len, + 1000); + msleep(30); + if (ret < 0) { + err("reg_wb %04x %04x failed %d", value, index, ret); + gspca_dev->usb_err = ret; + } +} + +static void i2c_write(struct sd *sd, + const struct i2c_write_cmd *cmd, + int ncmds) +{ + struct gspca_dev *gspca_dev = &sd->gspca_dev; + const struct sensor_s *sensor; + u16 val, idx; + u8 *buf; + int ret; + + if (gspca_dev->usb_err < 0) + return; + + sensor = &sensor_tb[sd->sensor]; + + val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO; + idx = (cmd->val & 0xff00) | cmd->reg; + + buf = gspca_dev->usb_buf; + *buf++ = sensor->i2c_dum; + *buf++ = cmd->val; + + while (--ncmds > 0) { + cmd++; + *buf++ = cmd->reg; + *buf++ = cmd->val >> 8; + *buf++ = sensor->i2c_dum; + *buf++ = cmd->val; + } + + PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x", + val, idx, gspca_dev->usb_buf[0], buf[-1]); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x0c, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, idx, + gspca_dev->usb_buf, buf - gspca_dev->usb_buf, + 500); + if (ret < 0) { + err("i2c_write failed %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void ucbus_write(struct gspca_dev *gspca_dev, + const struct ucbus_write_cmd *cmd, + int ncmds, + int batchsize) +{ + u8 *buf; + u16 val, idx; + int len, ret; + + if (gspca_dev->usb_err < 0) + return; + +#ifdef GSPCA_DEBUG + if ((batchsize - 1) * 3 > USB_BUF_SZ) { + err("Bug: usb_buf overflow"); + gspca_dev->usb_err = -ENOMEM; + return; + } +#endif + + for (;;) { + len = ncmds; + if (len > batchsize) + len = batchsize; + ncmds -= len; + + val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO; + idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8); + + buf = gspca_dev->usb_buf; + while (--len > 0) { + cmd++; + *buf++ = cmd->bw_addr; + *buf++ = cmd->bw_addr >> 8; + *buf++ = cmd->bw_data; + } + if (buf != gspca_dev->usb_buf) + PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x", + val, idx, + gspca_dev->usb_buf[0], buf[-1]); + else + PDEBUG(D_USBO, "ucbus v: %04x i: %04x", + val, idx); + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x0c, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, idx, + gspca_dev->usb_buf, buf - gspca_dev->usb_buf, + 500); + if (ret < 0) { + err("ucbus_write failed %d", ret); + gspca_dev->usb_err = ret; + return; + } + msleep(30); + if (ncmds <= 0) + break; + cmd++; + } +} + +static void gpio_set(struct sd *sd, u16 val, u16 mask) +{ + struct gspca_dev *gspca_dev = &sd->gspca_dev; + + if (mask & 0x00ff) { + sd->gpio[0] &= ~mask; + sd->gpio[0] |= val; + reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO, + ~sd->gpio[0] << 8); + } + mask >>= 8; + val >>= 8; + if (mask) { + sd->gpio[1] &= ~mask; + sd->gpio[1] |= val; + reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO, + ~sd->gpio[1] << 8); + } +} + +static void gpio_init(struct sd *sd, + const u8 *gpio) +{ + gpio_set(sd, *gpio++, 0x000f); + gpio_set(sd, *gpio++, 0x000f); + gpio_set(sd, *gpio++, 0x000f); + gpio_set(sd, *gpio++, 0x000f); + gpio_set(sd, *gpio, 0x000f); +} + +static void bridge_init(struct sd *sd) +{ + static const struct ucbus_write_cmd clkfreq_cmd = { + 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */ + }; + + ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1); + + gpio_set(sd, SQ930_GPIO_POWER, 0xff00); +} + +static void cmos_probe(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + const struct sensor_s *sensor; + static const u8 probe_order[] = { +/* SENSOR_LZ24BP, (tested as ccd) */ + SENSOR_OV9630, + SENSOR_MI0360, + SENSOR_OV7660, + SENSOR_MT9V111, + }; + + for (i = 0; i < ARRAY_SIZE(probe_order); i++) { + sensor = &sensor_tb[probe_order[i]]; + ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8); + gpio_init(sd, sensor->gpio); + msleep(100); + reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1); + msleep(100); + if (gspca_dev->usb_buf[0] != 0) + break; + } + if (i >= ARRAY_SIZE(probe_order)) { + err("Unknown sensor"); + gspca_dev->usb_err = -EINVAL; + return; + } + sd->sensor = probe_order[i]; + switch (sd->sensor) { + case SENSOR_OV7660: + case SENSOR_OV9630: + err("Sensor %s not yet treated", sensor_tb[sd->sensor].name); + gspca_dev->usb_err = -EINVAL; + break; + } +} + +static void mt9v111_init(struct gspca_dev *gspca_dev) +{ + int i, nwait; + static const u8 cmd_001b[] = { + 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00 + }; + static const u8 cmd_011b[][7] = { + {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00}, + {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00}, + {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00}, + }; + + reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b); + for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) { + reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i], + ARRAY_SIZE(cmd_011b[0])); + msleep(400); + nwait = 20; + for (;;) { + reg_r(gspca_dev, 0x031b, 1); + if (gspca_dev->usb_buf[0] == 0 + || gspca_dev->usb_err != 0) + break; + if (--nwait < 0) { + PDEBUG(D_PROBE, "mt9v111_init timeout"); + gspca_dev->usb_err = -ETIME; + return; + } + msleep(50); + } + } +} + +static void global_init(struct sd *sd, int first_time) +{ + switch (sd->sensor) { + case SENSOR_ICX098BQ: + if (first_time) + ucbus_write(&sd->gspca_dev, + icx098bq_start_0, + 8, 8); + gpio_init(sd, sensor_tb[sd->sensor].gpio); + break; + case SENSOR_LZ24BP: + if (sd->type != Creative_live_motion) + gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff); + else + gpio_set(sd, 0, 0x00ff); + msleep(50); + if (first_time) + ucbus_write(&sd->gspca_dev, + lz24bp_start_0, + 8, 8); + gpio_init(sd, sensor_tb[sd->sensor].gpio); + break; + case SENSOR_MI0360: + if (first_time) + ucbus_write(&sd->gspca_dev, + mi0360_start_0, + ARRAY_SIZE(mi0360_start_0), + 8); + gpio_init(sd, sensor_tb[sd->sensor].gpio); + gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2); + break; + default: +/* case SENSOR_MT9V111: */ + if (first_time) + mt9v111_init(&sd->gspca_dev); + else + gpio_init(sd, sensor_tb[sd->sensor].gpio); + break; + } +} + +static void lz24bp_ppl(struct sd *sd, u16 ppl) +{ + struct ucbus_write_cmd cmds[2] = { + {0xf810, ppl >> 8}, + {0xf811, ppl} + }; + + ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, integclks, intstartclk, frameclks, min_frclk; + const struct sensor_s *sensor; + u16 cmd; + u8 buf[15]; + + integclks = sd->expo; + i = 0; + cmd = SQ930_CTRL_SET_EXPOSURE; + + switch (sd->sensor) { + case SENSOR_ICX098BQ: /* ccd */ + case SENSOR_LZ24BP: + min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f; + if (integclks >= min_frclk) { + intstartclk = 0; + frameclks = integclks; + } else { + intstartclk = min_frclk - integclks; + frameclks = min_frclk; + } + buf[i++] = intstartclk >> 8; + buf[i++] = intstartclk; + buf[i++] = frameclks >> 8; + buf[i++] = frameclks; + buf[i++] = sd->gain; + break; + default: /* cmos */ +/* case SENSOR_MI0360: */ +/* case SENSOR_MT9V111: */ + cmd |= 0x0100; + sensor = &sensor_tb[sd->sensor]; + buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */ + buf[i++] = 0x08; /* 2 * ni2c */ + buf[i++] = 0x09; /* reg = shutter width */ + buf[i++] = integclks >> 8; /* val H */ + buf[i++] = sensor->i2c_dum; + buf[i++] = integclks; /* val L */ + buf[i++] = 0x35; /* reg = global gain */ + buf[i++] = 0x00; /* val H */ + buf[i++] = sensor->i2c_dum; + buf[i++] = 0x80 + sd->gain / 2; /* val L */ + buf[i++] = 0x00; + buf[i++] = 0x00; + buf[i++] = 0x00; + buf[i++] = 0x00; + buf[i++] = 0x83; + break; + } + reg_wb(gspca_dev, cmd, 0, buf, i); +} + +/* This function is called at probe time just before sd_init */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + + sd->sensor = id->driver_info >> 8; + sd->type = id->driver_info; + + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + + cam->bulk = 1; + + sd->gain = GAIN_DEF; + sd->expo = EXPO_DEF; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */ + +/*fixme: is this needed for icx098bp and mi0360? + if (sd->sensor != SENSOR_LZ24BP) + reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000); + */ + + reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8); + if (gspca_dev->usb_err < 0) + return gspca_dev->usb_err; + +/* it returns: + * 03 00 12 93 0b f6 c9 00 live! ultra + * 03 00 07 93 0b f6 ca 00 live! ultra for notebook + * 03 00 12 93 0b fe c8 00 Trust WB-3500T + * 02 00 06 93 0b fe c8 00 Joy-IT 318S + * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq + * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam + * + * byte + * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit) + * 1: 00 + * 2: 06 / 07 / 12 = mode webcam? firmware?? + * 3: 93 chip = 930b (930b or 930c) + * 4: 0b + * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors) + * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam? + * 7: 00 + */ + PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x", + gspca_dev->usb_buf[0], + gspca_dev->usb_buf[1], + gspca_dev->usb_buf[2], + gspca_dev->usb_buf[3], + gspca_dev->usb_buf[4], + gspca_dev->usb_buf[5], + gspca_dev->usb_buf[6], + gspca_dev->usb_buf[7]); + + bridge_init(sd); + + if (sd->sensor == SENSOR_MI0360) { + + /* no sensor probe for icam tracer */ + if (gspca_dev->usb_buf[5] == 0xf6) /* if ccd */ + sd->sensor = SENSOR_ICX098BQ; + else + cmos_probe(gspca_dev); + } + if (gspca_dev->usb_err >= 0) { + PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name); + global_init(sd, 1); + } + return gspca_dev->usb_err; +} + +/* send the start/stop commands to the webcam */ +static void send_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + const struct cap_s *cap; + int mode; + + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + cap = &capconfig[sd->sensor][mode]; + reg_wb(gspca_dev, 0x0900 | SQ930_CTRL_CAP_START, + 0x0a00 | cap->cc_sizeid, + cap->cc_bytes, 32); +} + +static void send_stop(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0); +} + +/* function called at start time before URB creation */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */ + sd->do_ctrl = 0; + gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height + 8; + return 0; +} + +/* start the capture */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int mode; + + bridge_init(sd); + global_init(sd, 0); + msleep(100); + + switch (sd->sensor) { + case SENSOR_ICX098BQ: + ucbus_write(gspca_dev, icx098bq_start_0, + ARRAY_SIZE(icx098bq_start_0), + 8); + ucbus_write(gspca_dev, icx098bq_start_1, + ARRAY_SIZE(icx098bq_start_1), + 5); + ucbus_write(gspca_dev, icx098bq_start_2, + ARRAY_SIZE(icx098bq_start_2), + 6); + msleep(50); + + /* 1st start */ + send_start(gspca_dev); + gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); + msleep(70); + reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000); + gpio_set(sd, 0x7f, 0x00ff); + + /* 2nd start */ + send_start(gspca_dev); + gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); + goto out; + case SENSOR_LZ24BP: + ucbus_write(gspca_dev, lz24bp_start_0, + ARRAY_SIZE(lz24bp_start_0), + 8); + if (sd->type != Creative_live_motion) + ucbus_write(gspca_dev, lz24bp_start_1_gen, + ARRAY_SIZE(lz24bp_start_1_gen), + 5); + else + ucbus_write(gspca_dev, lz24bp_start_1_clm, + ARRAY_SIZE(lz24bp_start_1_clm), + 5); + ucbus_write(gspca_dev, lz24bp_start_2, + ARRAY_SIZE(lz24bp_start_2), + 6); + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + lz24bp_ppl(sd, mode == 1 ? 0x0564 : 0x0310); + msleep(10); + break; + case SENSOR_MI0360: + ucbus_write(gspca_dev, mi0360_start_0, + ARRAY_SIZE(mi0360_start_0), + 8); + i2c_write(sd, mi0360_init_23, + ARRAY_SIZE(mi0360_init_23)); + i2c_write(sd, mi0360_init_24, + ARRAY_SIZE(mi0360_init_24)); + i2c_write(sd, mi0360_init_25, + ARRAY_SIZE(mi0360_init_25)); + ucbus_write(gspca_dev, mi0360_start_1, + ARRAY_SIZE(mi0360_start_1), + 5); + i2c_write(sd, mi0360_start_2, + ARRAY_SIZE(mi0360_start_2)); + i2c_write(sd, mi0360_start_3, + ARRAY_SIZE(mi0360_start_3)); + + /* 1st start */ + send_start(gspca_dev); + msleep(60); + send_stop(gspca_dev); + + i2c_write(sd, + mi0360_start_4, ARRAY_SIZE(mi0360_start_4)); + break; + default: +/* case SENSOR_MT9V111: */ + ucbus_write(gspca_dev, mi0360_start_0, + ARRAY_SIZE(mi0360_start_0), + 8); + i2c_write(sd, mt9v111_init_0, + ARRAY_SIZE(mt9v111_init_0)); + i2c_write(sd, mt9v111_init_1, + ARRAY_SIZE(mt9v111_init_1)); + i2c_write(sd, mt9v111_init_2, + ARRAY_SIZE(mt9v111_init_2)); + ucbus_write(gspca_dev, mt9v111_start_1, + ARRAY_SIZE(mt9v111_start_1), + 5); + i2c_write(sd, mt9v111_init_3, + ARRAY_SIZE(mt9v111_init_3)); + i2c_write(sd, mt9v111_init_4, + ARRAY_SIZE(mt9v111_init_4)); + break; + } + + send_start(gspca_dev); +out: + msleep(1000); + + if (sd->sensor == SENSOR_MT9V111) + gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED); + + sd->do_ctrl = 1; /* set the exposure */ + + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_MT9V111) + gpio_set(sd, 0, SQ930_GPIO_DFL_LED); + send_stop(gspca_dev); +} + +/* function called when the application gets a new frame */ +/* It sets the exposure if required and restart the bulk transfer. */ +static void sd_dq_callback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret; + + if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0) + return; + sd->do_ctrl = 0; + + setexposure(gspca_dev); + + gspca_dev->cam.bulk_nurbs = 1; + ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC); + if (ret < 0) + err("sd_dq_callback() err %d", ret); + + /* wait a little time, otherwise the webcam crashes */ + msleep(100); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->do_ctrl) + gspca_dev->cam.bulk_nurbs = 0; + gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); + gspca_frame_add(gspca_dev, INTER_PACKET, data, len - 8); + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + sd->do_ctrl = 1; + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} +static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->expo = val; + if (gspca_dev->streaming) + sd->do_ctrl = 1; + return 0; +} + +static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->expo; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .dq_callback = sd_dq_callback, +}; + +/* Table of supported USB devices */ +#define ST(sensor, type) \ + .driver_info = (SENSOR_ ## sensor << 8) \ + | (type) +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)}, + {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)}, + {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)}, + {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)}, + {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)}, + {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stk014.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stk014.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stk014.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stk014.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,531 @@ +/* + * Syntek DV4000 (STK014) subdriver + * + * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr) + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "stk014" + +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Jean-Francois Moine "); +MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* controls */ +enum e_ctrl { + BRIGHTNESS, + CONTRAST, + COLORS, + LIGHTFREQ, + NCTRLS /* number of controls */ +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + + u8 quality; +#define QUALITY_MIN 70 +#define QUALITY_MAX 95 +#define QUALITY_DEF 88 + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +/* V4L2 controls supported by the driver */ +static void setbrightness(struct gspca_dev *gspca_dev); +static void setcontrast(struct gspca_dev *gspca_dev); +static void setcolors(struct gspca_dev *gspca_dev); +static void setlightfreq(struct gspca_dev *gspca_dev); + +static const struct ctrl sd_ctrls[NCTRLS] = { +[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set_control = setbrightness + }, +[CONTRAST] = { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set_control = setcontrast + }, +[COLORS] = { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set_control = setcolors + }, +[LIGHTFREQ] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 1, + .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ + .step = 1, + .default_value = 1, + }, + .set_control = setlightfreq + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* -- read a register -- */ +static u8 reg_r(struct gspca_dev *gspca_dev, + __u16 index) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return 0; + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, + index, + gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { + err("reg_r err %d", ret); + gspca_dev->usb_err = ret; + return 0; + } + return gspca_dev->usb_buf[0]; +} + +/* -- write a register -- */ +static void reg_w(struct gspca_dev *gspca_dev, + __u16 index, __u16 value) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x01, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + NULL, + 0, + 500); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* -- get a bulk value (4 bytes) -- */ +static void rcv_val(struct gspca_dev *gspca_dev, + int ads) +{ + struct usb_device *dev = gspca_dev->dev; + int alen, ret; + + reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff); + reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff); + reg_w(gspca_dev, 0x636, ads & 0xff); + reg_w(gspca_dev, 0x637, 0); + reg_w(gspca_dev, 0x638, 4); /* len & 0xff */ + reg_w(gspca_dev, 0x639, 0); /* len >> 8 */ + reg_w(gspca_dev, 0x63a, 0); + reg_w(gspca_dev, 0x63b, 0); + reg_w(gspca_dev, 0x630, 5); + if (gspca_dev->usb_err < 0) + return; + ret = usb_bulk_msg(dev, + usb_rcvbulkpipe(dev, 0x05), + gspca_dev->usb_buf, + 4, /* length */ + &alen, + 500); /* timeout in milliseconds */ + if (ret < 0) { + err("rcv_val err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* -- send a bulk value -- */ +static void snd_val(struct gspca_dev *gspca_dev, + int ads, + unsigned int val) +{ + struct usb_device *dev = gspca_dev->dev; + int alen, ret; + __u8 seq = 0; + + if (ads == 0x003f08) { + reg_r(gspca_dev, 0x0704); + seq = reg_r(gspca_dev, 0x0705); + reg_r(gspca_dev, 0x0650); + reg_w(gspca_dev, 0x654, seq); + } else { + reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff); + } + reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff); + reg_w(gspca_dev, 0x656, ads & 0xff); + reg_w(gspca_dev, 0x657, 0); + reg_w(gspca_dev, 0x658, 0x04); /* size */ + reg_w(gspca_dev, 0x659, 0); + reg_w(gspca_dev, 0x65a, 0); + reg_w(gspca_dev, 0x65b, 0); + reg_w(gspca_dev, 0x650, 5); + if (gspca_dev->usb_err < 0) + return; + gspca_dev->usb_buf[0] = val >> 24; + gspca_dev->usb_buf[1] = val >> 16; + gspca_dev->usb_buf[2] = val >> 8; + gspca_dev->usb_buf[3] = val; + ret = usb_bulk_msg(dev, + usb_sndbulkpipe(dev, 6), + gspca_dev->usb_buf, + 4, + &alen, + 500); /* timeout in milliseconds */ + if (ret < 0) { + err("snd_val err %d", ret); + gspca_dev->usb_err = ret; + } else { + if (ads == 0x003f08) { + seq += 4; + seq &= 0x3f; + reg_w(gspca_dev, 0x705, seq); + } + } +} + +/* set a camera parameter */ +static void set_par(struct gspca_dev *gspca_dev, + int parval) +{ + snd_val(gspca_dev, 0x003f08, parval); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int parval; + + parval = 0x06000000 /* whiteness */ + + (sd->ctrls[BRIGHTNESS].val << 16); + set_par(gspca_dev, parval); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int parval; + + parval = 0x07000000 /* contrast */ + + (sd->ctrls[CONTRAST].val << 16); + set_par(gspca_dev, parval); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int parval; + + parval = 0x08000000 /* saturation */ + + (sd->ctrls[COLORS].val << 16); + set_par(gspca_dev, parval); +} + +static void setlightfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + set_par(gspca_dev, sd->ctrls[LIGHTFREQ].val == 1 + ? 0x33640000 /* 50 Hz */ + : 0x33780000); /* 60 Hz */ +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->cam.cam_mode = vga_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + gspca_dev->cam.ctrls = sd->ctrls; + sd->quality = QUALITY_DEF; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + u8 ret; + + /* check if the device responds */ + usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); + ret = reg_r(gspca_dev, 0x0740); + if (gspca_dev->usb_err >= 0) { + if (ret != 0xff) { + err("init reg: 0x%02x", ret); + gspca_dev->usb_err = -EIO; + } + } + return gspca_dev->usb_err; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret, value; + + /* create the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x22); /* JPEG 411 */ + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + /* work on alternate 1 */ + usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); + + set_par(gspca_dev, 0x10000000); + set_par(gspca_dev, 0x00000000); + set_par(gspca_dev, 0x8002e001); + set_par(gspca_dev, 0x14000000); + if (gspca_dev->width > 320) + value = 0x8002e001; /* 640x480 */ + else + value = 0x4001f000; /* 320x240 */ + set_par(gspca_dev, value); + ret = usb_set_interface(gspca_dev->dev, + gspca_dev->iface, + gspca_dev->alt); + if (ret < 0) { + err("set intf %d %d failed", + gspca_dev->iface, gspca_dev->alt); + gspca_dev->usb_err = ret; + goto out; + } + reg_r(gspca_dev, 0x0630); + rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ + reg_r(gspca_dev, 0x0650); + snd_val(gspca_dev, 0x000020, 0xffffffff); + reg_w(gspca_dev, 0x0620, 0); + reg_w(gspca_dev, 0x0630, 0); + reg_w(gspca_dev, 0x0640, 0); + reg_w(gspca_dev, 0x0650, 0); + reg_w(gspca_dev, 0x0660, 0); + setbrightness(gspca_dev); /* whiteness */ + setcontrast(gspca_dev); /* contrast */ + setcolors(gspca_dev); /* saturation */ + set_par(gspca_dev, 0x09800000); /* Red ? */ + set_par(gspca_dev, 0x0a800000); /* Green ? */ + set_par(gspca_dev, 0x0b800000); /* Blue ? */ + set_par(gspca_dev, 0x0d030000); /* Gamma ? */ + setlightfreq(gspca_dev); + + /* start the video flow */ + set_par(gspca_dev, 0x01000000); + set_par(gspca_dev, 0x01000000); + if (gspca_dev->usb_err >= 0) + PDEBUG(D_STREAM, "camera started alt: 0x%02x", + gspca_dev->alt); +out: + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + + set_par(gspca_dev, 0x02000000); + set_par(gspca_dev, 0x02000000); + usb_set_interface(dev, gspca_dev->iface, 1); + reg_r(gspca_dev, 0x0630); + rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ + reg_r(gspca_dev, 0x0650); + snd_val(gspca_dev, 0x000020, 0xffffffff); + reg_w(gspca_dev, 0x0620, 0); + reg_w(gspca_dev, 0x0630, 0); + reg_w(gspca_dev, 0x0640, 0); + reg_w(gspca_dev, 0x0650, 0); + reg_w(gspca_dev, 0x0660, 0); + PDEBUG(D_STREAM, "camera stopped"); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + static unsigned char ffd9[] = {0xff, 0xd9}; + + /* a frame starts with: + * - 0xff 0xfe + * - 0x08 0x00 - length (little endian ?!) + * - 4 bytes = size of whole frame (BE - including header) + * - 0x00 0x0c + * - 0xff 0xd8 + * - .. JPEG image with escape sequences (ff 00) + * (without ending - ff d9) + */ + if (data[0] == 0xff && data[1] == 0xfe) { + gspca_frame_add(gspca_dev, LAST_PACKET, + ffd9, 2); + + /* put the JPEG 411 header */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + + /* beginning of the frame */ +#define STKHDRSZ 12 + data += STKHDRSZ; + len -= STKHDRSZ; + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; + + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm)) + break; + strcpy((char *) menu->name, freq_nm[menu->index]); + return 0; + } + return -EINVAL; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (jcomp->quality < QUALITY_MIN) + sd->quality = QUALITY_MIN; + else if (jcomp->quality > QUALITY_MAX) + sd->quality = QUALITY_MAX; + else + sd->quality = jcomp->quality; + if (gspca_dev->streaming) + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + return gspca_dev->usb_err; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = NCTRLS, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x05e1, 0x0893)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv0680.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv0680.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv0680.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv0680.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,367 @@ +/* + * STV0680 USB Camera Driver + * + * Copyright (C) 2009 Hans de Goede + * + * This module is adapted from the in kernel v4l1 stv680 driver: + * + * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net) + * + * Thanks to STMicroelectronics for information on the usb commands, and + * to Steve Miller at STM for his help and encouragement while I was + * writing this driver. + * + * 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, or + * (at your option) any later version. + * + * 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 + * + */ + +#define MODULE_NAME "stv0680" + +#include "gspca.h" + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("STV0680 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + struct v4l2_pix_format mode; + u8 orig_mode; + u8 video_mode; + u8 current_mode; +}; + +/* V4L2 controls supported by the driver */ +static const struct ctrl sd_ctrls[] = { +}; + +static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val, + int size) +{ + int ret = -1; + u8 req_type = 0; + unsigned int pipe = 0; + + switch (set) { + case 0: /* 0xc1 */ + req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; + pipe = usb_rcvctrlpipe(gspca_dev->dev, 0); + break; + case 1: /* 0x41 */ + req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; + pipe = usb_sndctrlpipe(gspca_dev->dev, 0); + break; + case 2: /* 0x80 */ + req_type = USB_DIR_IN | USB_RECIP_DEVICE; + pipe = usb_rcvctrlpipe(gspca_dev->dev, 0); + break; + case 3: /* 0x40 */ + req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + pipe = usb_sndctrlpipe(gspca_dev->dev, 0); + break; + } + + ret = usb_control_msg(gspca_dev->dev, pipe, + req, req_type, + val, 0, gspca_dev->usb_buf, size, 500); + + if ((ret < 0) && (req != 0x0a)) + err("usb_control_msg error %i, request = 0x%x, error = %i", + set, req, ret); + + return ret; +} + +static int stv0680_handle_error(struct gspca_dev *gspca_dev, int ret) +{ + stv_sndctrl(gspca_dev, 0, 0x80, 0, 0x02); /* Get Last Error */ + PDEBUG(D_ERR, "last error: %i, command = 0x%x", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); + return ret; +} + +static int stv0680_get_video_mode(struct gspca_dev *gspca_dev) +{ + /* Note not sure if this init of usb_buf is really necessary */ + memset(gspca_dev->usb_buf, 0, 8); + gspca_dev->usb_buf[0] = 0x0f; + + if (stv_sndctrl(gspca_dev, 0, 0x87, 0, 0x08) != 0x08) { + PDEBUG(D_ERR, "Get_Camera_Mode failed"); + return stv0680_handle_error(gspca_dev, -EIO); + } + + return gspca_dev->usb_buf[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */ +} + +static int stv0680_set_video_mode(struct gspca_dev *gspca_dev, u8 mode) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->current_mode == mode) + return 0; + + memset(gspca_dev->usb_buf, 0, 8); + gspca_dev->usb_buf[0] = mode; + + if (stv_sndctrl(gspca_dev, 3, 0x07, 0x0100, 0x08) != 0x08) { + PDEBUG(D_ERR, "Set_Camera_Mode failed"); + return stv0680_handle_error(gspca_dev, -EIO); + } + + /* Verify we got what we've asked for */ + if (stv0680_get_video_mode(gspca_dev) != mode) { + PDEBUG(D_ERR, "Error setting camera video mode!"); + return -EIO; + } + + sd->current_mode = mode; + + return 0; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + int ret; + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; + + /* Give the camera some time to settle, otherwise initalization will + fail on hotplug, and yes it really needs a full second. */ + msleep(1000); + + /* ping camera to be sure STV0680 is present */ + if (stv_sndctrl(gspca_dev, 0, 0x88, 0x5678, 0x02) != 0x02 || + gspca_dev->usb_buf[0] != 0x56 || gspca_dev->usb_buf[1] != 0x78) { + PDEBUG(D_ERR, "STV(e): camera ping failed!!"); + return stv0680_handle_error(gspca_dev, -ENODEV); + } + + /* get camera descriptor */ + if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x09) != 0x09) + return stv0680_handle_error(gspca_dev, -ENODEV); + + if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x22) != 0x22 || + gspca_dev->usb_buf[7] != 0xa0 || gspca_dev->usb_buf[8] != 0x23) { + PDEBUG(D_ERR, "Could not get descriptor 0200."); + return stv0680_handle_error(gspca_dev, -ENODEV); + } + if (stv_sndctrl(gspca_dev, 0, 0x8a, 0, 0x02) != 0x02) + return stv0680_handle_error(gspca_dev, -ENODEV); + if (stv_sndctrl(gspca_dev, 0, 0x8b, 0, 0x24) != 0x24) + return stv0680_handle_error(gspca_dev, -ENODEV); + if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10) + return stv0680_handle_error(gspca_dev, -ENODEV); + + if (!(gspca_dev->usb_buf[7] & 0x09)) { + PDEBUG(D_ERR, "Camera supports neither CIF nor QVGA mode"); + return -ENODEV; + } + if (gspca_dev->usb_buf[7] & 0x01) + PDEBUG(D_PROBE, "Camera supports CIF mode"); + if (gspca_dev->usb_buf[7] & 0x02) + PDEBUG(D_PROBE, "Camera supports VGA mode"); + if (gspca_dev->usb_buf[7] & 0x04) + PDEBUG(D_PROBE, "Camera supports QCIF mode"); + if (gspca_dev->usb_buf[7] & 0x08) + PDEBUG(D_PROBE, "Camera supports QVGA mode"); + + if (gspca_dev->usb_buf[7] & 0x01) + sd->video_mode = 0x00; /* CIF */ + else + sd->video_mode = 0x03; /* QVGA */ + + /* FW rev, ASIC rev, sensor ID */ + PDEBUG(D_PROBE, "Firmware rev is %i.%i", + gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); + PDEBUG(D_PROBE, "ASIC rev is %i.%i", + gspca_dev->usb_buf[2], gspca_dev->usb_buf[3]); + PDEBUG(D_PROBE, "Sensor ID is %i", + (gspca_dev->usb_buf[4]*16) + (gspca_dev->usb_buf[5]>>4)); + + + ret = stv0680_get_video_mode(gspca_dev); + if (ret < 0) + return ret; + sd->current_mode = sd->orig_mode = ret; + + ret = stv0680_set_video_mode(gspca_dev, sd->video_mode); + if (ret < 0) + return ret; + + /* Get mode details */ + if (stv_sndctrl(gspca_dev, 0, 0x8f, 0, 0x10) != 0x10) + return stv0680_handle_error(gspca_dev, -EIO); + + cam->bulk = 1; + cam->bulk_nurbs = 1; /* The cam cannot handle more */ + cam->bulk_size = (gspca_dev->usb_buf[0] << 24) | + (gspca_dev->usb_buf[1] << 16) | + (gspca_dev->usb_buf[2] << 8) | + (gspca_dev->usb_buf[3]); + sd->mode.width = (gspca_dev->usb_buf[4] << 8) | + (gspca_dev->usb_buf[5]); /* 322, 356, 644 */ + sd->mode.height = (gspca_dev->usb_buf[6] << 8) | + (gspca_dev->usb_buf[7]); /* 242, 292, 484 */ + sd->mode.pixelformat = V4L2_PIX_FMT_STV0680; + sd->mode.field = V4L2_FIELD_NONE; + sd->mode.bytesperline = sd->mode.width; + sd->mode.sizeimage = cam->bulk_size; + sd->mode.colorspace = V4L2_COLORSPACE_SRGB; + + /* origGain = gspca_dev->usb_buf[12]; */ + + cam->cam_mode = &sd->mode; + cam->nmodes = 1; + + + ret = stv0680_set_video_mode(gspca_dev, sd->orig_mode); + if (ret < 0) + return ret; + + if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 || + gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) { + err("Could not get descriptor 0100."); + return stv0680_handle_error(gspca_dev, -EIO); + } + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + int ret; + struct sd *sd = (struct sd *) gspca_dev; + + ret = stv0680_set_video_mode(gspca_dev, sd->video_mode); + if (ret < 0) + return ret; + + if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10) + return stv0680_handle_error(gspca_dev, -EIO); + + /* Start stream at: + 0x0000 = CIF (352x288) + 0x0100 = VGA (640x480) + 0x0300 = QVGA (320x240) */ + if (stv_sndctrl(gspca_dev, 1, 0x09, sd->video_mode << 8, 0x0) != 0x0) + return stv0680_handle_error(gspca_dev, -EIO); + + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* This is a high priority command; it stops all lower order cmds */ + if (stv_sndctrl(gspca_dev, 1, 0x04, 0x0000, 0x0) != 0x0) + stv0680_handle_error(gspca_dev, -EIO); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!sd->gspca_dev.present) + return; + + stv0680_set_video_mode(gspca_dev, sd->orig_mode); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, + int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* Every now and then the camera sends a 16 byte packet, no idea + what it contains, but it is not image data, when this + happens the frame received before this packet is corrupt, + so discard it. */ + if (len != sd->mode.sizeimage) { + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + + /* Finish the previous frame, we do this upon reception of the next + packet, even though it is already complete so that the strange 16 + byte packets send after a corrupt frame can discard it. */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + + /* Store the just received frame */ + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0553, 0x0202)}, + {USB_DEVICE(0x041e, 0x4007)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,9 @@ +config USB_STV06XX + tristate "STV06XX USB Camera Driver" + depends on USB_GSPCA + help + Say Y here if you want support for cameras based on + the ST STV06XX chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_stv06xx. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,10 @@ +obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o + +gspca_stv06xx-objs := stv06xx.o \ + stv06xx_vv6410.o \ + stv06xx_hdcs.o \ + stv06xx_pb0100.o \ + stv06xx_st6422.o + +EXTRA_CFLAGS += -Idrivers/media/video/gspca + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#include +#include "stv06xx_sensor.h" + +MODULE_AUTHOR("Erik Andrén"); +MODULE_DESCRIPTION("STV06XX USB Camera Driver"); +MODULE_LICENSE("GPL"); + +static int dump_bridge; +static int dump_sensor; + +int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + u8 len = (i2c_data > 0xff) ? 2 : 1; + + buf[0] = i2c_data & 0xff; + buf[1] = (i2c_data >> 8) & 0xff; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, address, 0, buf, len, + STV06XX_URB_MSG_TIMEOUT); + + PDEBUG(D_CONF, "Written 0x%x to address 0x%x, status: %d", + i2c_data, address, err); + + return (err < 0) ? err : 0; +} + +int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x04, 0xc0, address, 0, buf, 1, + STV06XX_URB_MSG_TIMEOUT); + + *i2c_data = buf[0]; + + PDEBUG(D_CONF, "Reading 0x%x from address 0x%x, status %d", + *i2c_data, address, err); + + return (err < 0) ? err : 0; +} + +/* Wraps the normal write sensor bytes / words functions for writing a + single value */ +int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value) +{ + if (sd->sensor->i2c_len == 2) { + u16 data[2] = { address, value }; + return stv06xx_write_sensor_words(sd, data, 1); + } else { + u8 data[2] = { address, value }; + return stv06xx_write_sensor_bytes(sd, data, 1); + } +} + +static int stv06xx_write_sensor_finish(struct sd *sd) +{ + int err = 0; + + if (sd->bridge == BRIDGE_STV610) { + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + buf[0] = 0; + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x1704, 0, buf, 1, + STV06XX_URB_MSG_TIMEOUT); + } + + return (err < 0) ? err : 0; +} + +int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len) +{ + int err, i, j; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len); + for (i = 0; i < len;) { + /* Build the command buffer */ + memset(buf, 0, I2C_BUFFER_LENGTH); + for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) { + buf[j] = data[2*i]; + buf[0x10 + j] = data[2*i+1]; + PDEBUG(D_CONF, "I2C: Writing 0x%02x to reg 0x%02x", + data[2*i+1], data[2*i]); + } + buf[0x20] = sd->sensor->i2c_addr; + buf[0x21] = j - 1; /* Number of commands to send - 1 */ + buf[0x22] = I2C_WRITE_CMD; + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x0400, 0, buf, + I2C_BUFFER_LENGTH, + STV06XX_URB_MSG_TIMEOUT); + if (err < 0) + return err; + } + return stv06xx_write_sensor_finish(sd); +} + +int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len) +{ + int err, i, j; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len); + + for (i = 0; i < len;) { + /* Build the command buffer */ + memset(buf, 0, I2C_BUFFER_LENGTH); + for (j = 0; j < I2C_MAX_WORDS && i < len; j++, i++) { + buf[j] = data[2*i]; + buf[0x10 + j * 2] = data[2*i+1]; + buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8; + PDEBUG(D_CONF, "I2C: Writing 0x%04x to reg 0x%02x", + data[2*i+1], data[2*i]); + } + buf[0x20] = sd->sensor->i2c_addr; + buf[0x21] = j - 1; /* Number of commands to send - 1 */ + buf[0x22] = I2C_WRITE_CMD; + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x0400, 0, buf, + I2C_BUFFER_LENGTH, + STV06XX_URB_MSG_TIMEOUT); + if (err < 0) + return err; + } + return stv06xx_write_sensor_finish(sd); +} + +int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + err = stv06xx_write_bridge(sd, STV_I2C_FLUSH, sd->sensor->i2c_flush); + if (err < 0) + return err; + + /* Clear mem */ + memset(buf, 0, I2C_BUFFER_LENGTH); + + buf[0] = address; + buf[0x20] = sd->sensor->i2c_addr; + buf[0x21] = 0; + + /* Read I2C register */ + buf[0x22] = I2C_READ_CMD; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH, + STV06XX_URB_MSG_TIMEOUT); + if (err < 0) { + err("I2C: Read error writing address: %d", err); + return err; + } + + err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x04, 0xc0, 0x1410, 0, buf, sd->sensor->i2c_len, + STV06XX_URB_MSG_TIMEOUT); + if (sd->sensor->i2c_len == 2) + *value = buf[0] | (buf[1] << 8); + else + *value = buf[0]; + + PDEBUG(D_CONF, "I2C: Read 0x%x from address 0x%x, status: %d", + *value, address, err); + + return (err < 0) ? err : 0; +} + +/* Dumps all bridge registers */ +static void stv06xx_dump_bridge(struct sd *sd) +{ + int i; + u8 data, buf; + + info("Dumping all stv06xx bridge registers"); + for (i = 0x1400; i < 0x160f; i++) { + stv06xx_read_bridge(sd, i, &data); + + info("Read 0x%x from address 0x%x", data, i); + } + + info("Testing stv06xx bridge registers for writability"); + for (i = 0x1400; i < 0x160f; i++) { + stv06xx_read_bridge(sd, i, &data); + buf = data; + + stv06xx_write_bridge(sd, i, 0xff); + stv06xx_read_bridge(sd, i, &data); + if (data == 0xff) + info("Register 0x%x is read/write", i); + else if (data != buf) + info("Register 0x%x is read/write," + " but only partially", i); + else + info("Register 0x%x is read-only", i); + + stv06xx_write_bridge(sd, i, buf); + } +} + +/* this function is called at probe and resume time */ +static int stv06xx_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err; + + PDEBUG(D_PROBE, "Initializing camera"); + + /* Let the usb init settle for a bit + before performing the initialization */ + msleep(250); + + err = sd->sensor->init(sd); + + if (dump_sensor && sd->sensor->dump) + sd->sensor->dump(sd); + + return (err < 0) ? err : 0; +} + +/* Start the camera */ +static int stv06xx_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_host_interface *alt; + struct usb_interface *intf; + int err, packet_size; + + intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) { + PDEBUG(D_ERR, "Couldn't get altsetting"); + return -EIO; + } + + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size); + if (err < 0) + return err; + + /* Prepare the sensor for start */ + err = sd->sensor->start(sd); + if (err < 0) + goto out; + + /* Start isochronous streaming */ + err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 1); + +out: + if (err < 0) + PDEBUG(D_STREAM, "Starting stream failed"); + else + PDEBUG(D_STREAM, "Started streaming"); + + return (err < 0) ? err : 0; +} + +static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) +{ + struct usb_host_interface *alt; + struct sd *sd = (struct sd *) gspca_dev; + + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ + alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt->endpoint[0].desc.wMaxPacketSize = + cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]); + + return 0; +} + +static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev) +{ + int ret, packet_size, min_packet_size; + struct usb_host_interface *alt; + struct sd *sd = (struct sd *) gspca_dev; + + alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; + if (packet_size <= min_packet_size) + return -EIO; + + packet_size -= 100; + if (packet_size < min_packet_size) + packet_size = min_packet_size; + alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size); + + ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); + if (ret < 0) + PDEBUG(D_ERR|D_STREAM, "set alt 1 err %d", ret); + + return ret; +} + +static void stv06xx_stopN(struct gspca_dev *gspca_dev) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + + /* stop ISO-streaming */ + err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0); + if (err < 0) + goto out; + + err = sd->sensor->stop(sd); + +out: + if (err < 0) + PDEBUG(D_STREAM, "Failed to stop stream"); + else + PDEBUG(D_STREAM, "Stopped streaming"); +} + +/* + * Analyse an USB packet of the data stream and store it appropriately. + * Each packet contains an integral number of chunks. Each chunk has + * 2-bytes identification, followed by 2-bytes that describe the chunk + * length. Known/guessed chunk identifications are: + * 8001/8005/C001/C005 - Begin new frame + * 8002/8006/C002/C006 - End frame + * 0200/4200 - Contains actual image data, bayer or compressed + * 0005 - 11 bytes of unknown data + * 0100 - 2 bytes of unknown data + * The 0005 and 0100 chunks seem to appear only in compressed stream. + */ +static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(D_PACK, "Packet of length %d arrived", len); + + /* A packet may contain several frames + loop until the whole packet is reached */ + while (len) { + int id, chunk_len; + + if (len < 4) { + PDEBUG(D_PACK, "Packet is smaller than 4 bytes"); + return; + } + + /* Capture the id */ + id = (data[0] << 8) | data[1]; + + /* Capture the chunk length */ + chunk_len = (data[2] << 8) | data[3]; + PDEBUG(D_PACK, "Chunk id: %x, length: %d", id, chunk_len); + + data += 4; + len -= 4; + + if (len < chunk_len) { + PDEBUG(D_ERR, "URB packet length is smaller" + " than the specified chunk length"); + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + + /* First byte seem to be 02=data 2nd byte is unknown??? */ + if (sd->bridge == BRIDGE_ST6422 && (id & 0xff00) == 0x0200) + goto frame_data; + + switch (id) { + case 0x0200: + case 0x4200: +frame_data: + PDEBUG(D_PACK, "Frame data packet detected"); + + if (sd->to_skip) { + int skip = (sd->to_skip < chunk_len) ? + sd->to_skip : chunk_len; + data += skip; + len -= skip; + chunk_len -= skip; + sd->to_skip -= skip; + } + + gspca_frame_add(gspca_dev, INTER_PACKET, + data, chunk_len); + break; + + case 0x8001: + case 0x8005: + case 0xc001: + case 0xc005: + PDEBUG(D_PACK, "Starting new frame"); + + /* Create a new frame, chunk length should be zero */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + NULL, 0); + + if (sd->bridge == BRIDGE_ST6422) + sd->to_skip = gspca_dev->width * 4; + + if (chunk_len) + PDEBUG(D_ERR, "Chunk length is " + "non-zero on a SOF"); + break; + + case 0x8002: + case 0x8006: + case 0xc002: + PDEBUG(D_PACK, "End of frame detected"); + + /* Complete the last frame (if any) */ + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + + if (chunk_len) + PDEBUG(D_ERR, "Chunk length is " + "non-zero on a EOF"); + break; + + case 0x0005: + PDEBUG(D_PACK, "Chunk 0x005 detected"); + /* Unknown chunk with 11 bytes of data, + occurs just before end of each frame + in compressed mode */ + break; + + case 0x0100: + PDEBUG(D_PACK, "Chunk 0x0100 detected"); + /* Unknown chunk with 2 bytes of data, + occurs 2-3 times per USB interrupt */ + break; + case 0x42ff: + PDEBUG(D_PACK, "Chunk 0x42ff detected"); + /* Special chunk seen sometimes on the ST6422 */ + break; + default: + PDEBUG(D_PACK, "Unknown chunk 0x%04x detected", id); + /* Unknown chunk */ + } + data += chunk_len; + len -= chunk_len; + } +} + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet data */ + int len) /* interrupt packet length */ +{ + int ret = -EINVAL; + + if (len == 1 && data[0] == 0x80) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); + input_sync(gspca_dev->input_dev); + ret = 0; + } + + if (len == 1 && data[0] == 0x88) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + ret = 0; + } + + return ret; +} +#endif + +static int stv06xx_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id); + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = stv06xx_config, + .init = stv06xx_init, + .start = stv06xx_start, + .stopN = stv06xx_stopN, + .pkt_scan = stv06xx_pkt_scan, + .isoc_init = stv06xx_isoc_init, + .isoc_nego = stv06xx_isoc_nego, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +#endif +}; + +/* This function is called at probe time */ +static int stv06xx_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(D_PROBE, "Configuring camera"); + + sd->desc = sd_desc; + sd->bridge = id->driver_info; + gspca_dev->sd_desc = &sd->desc; + + if (dump_bridge) + stv06xx_dump_bridge(sd); + + sd->sensor = &stv06xx_sensor_st6422; + if (!sd->sensor->probe(sd)) + return 0; + + sd->sensor = &stv06xx_sensor_vv6410; + if (!sd->sensor->probe(sd)) + return 0; + + sd->sensor = &stv06xx_sensor_hdcs1x00; + if (!sd->sensor->probe(sd)) + return 0; + + sd->sensor = &stv06xx_sensor_hdcs1020; + if (!sd->sensor->probe(sd)) + return 0; + + sd->sensor = &stv06xx_sensor_pb0100; + if (!sd->sensor->probe(sd)) + return 0; + + sd->sensor = NULL; + return -ENODEV; +} + + + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + /* QuickCam Express */ + {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 }, + /* LEGO cam / QuickCam Web */ + {USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 }, + /* Dexxa WebCam USB */ + {USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 }, + /* QuickCam Messenger */ + {USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 }, + /* QuickCam Communicate */ + {USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 }, + /* QuickCam Messenger (new) */ + {USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 }, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + PDEBUG(D_PROBE, "Probing for a stv06xx device"); + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static void sd_disconnect(struct usb_interface *intf) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + struct sd *sd = (struct sd *) gspca_dev; + PDEBUG(D_PROBE, "Disconnecting the stv06xx device"); + + if (sd->sensor->disconnect) + sd->sensor->disconnect(sd); + gspca_disconnect(intf); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = sd_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(dump_bridge, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup"); + +module_param(dump_sensor, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_sensor, "Dumps all sensor registers at startup"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_H_ +#define STV06XX_H_ + +#include +#include "gspca.h" + +#define MODULE_NAME "STV06xx" + +#define STV_ISOC_ENDPOINT_ADDR 0x81 + +#define STV_REG23 0x0423 + +/* Control registers of the STV0600 ASIC */ +#define STV_I2C_PARTNER 0x1420 +#define STV_I2C_VAL_REG_VAL_PAIRS_MIN1 0x1421 +#define STV_I2C_READ_WRITE_TOGGLE 0x1422 +#define STV_I2C_FLUSH 0x1423 +#define STV_I2C_SUCC_READ_REG_VALS 0x1424 + +#define STV_ISO_ENABLE 0x1440 +#define STV_SCAN_RATE 0x1443 +#define STV_LED_CTRL 0x1445 +#define STV_STV0600_EMULATION 0x1446 +#define STV_REG00 0x1500 +#define STV_REG01 0x1501 +#define STV_REG02 0x1502 +#define STV_REG03 0x1503 +#define STV_REG04 0x1504 + +#define STV_ISO_SIZE_L 0x15c1 +#define STV_ISO_SIZE_H 0x15c2 + +/* Refers to the CIF 352x288 and QCIF 176x144 */ +/* 1: 288 lines, 2: 144 lines */ +#define STV_Y_CTRL 0x15c3 + +/* 0xa: 352 columns, 0x6: 176 columns */ +#define STV_X_CTRL 0x1680 + +#define STV06XX_URB_MSG_TIMEOUT 5000 + +#define I2C_MAX_BYTES 16 +#define I2C_MAX_WORDS 8 + +#define I2C_BUFFER_LENGTH 0x23 +#define I2C_READ_CMD 3 +#define I2C_WRITE_CMD 1 + +#define LED_ON 1 +#define LED_OFF 0 + +/* STV06xx device descriptor */ +struct sd { + struct gspca_dev gspca_dev; + + /* A pointer to the currently connected sensor */ + const struct stv06xx_sensor *sensor; + + /* A pointer to the sd_desc struct */ + struct sd_desc desc; + + /* Sensor private data */ + void *sensor_priv; + + /* The first 4 lines produced by the stv6422 are no good, this keeps + track of how many bytes we still need to skip during a frame */ + int to_skip; + + /* Bridge / Camera type */ + u8 bridge; + #define BRIDGE_STV600 0 + #define BRIDGE_STV602 1 + #define BRIDGE_STV610 2 + #define BRIDGE_ST6422 3 /* With integrated sensor */ +}; + +int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data); +int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data); + +int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len); +int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len); + +int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value); +int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * Copyright (c) 2008 Chia-I Wu + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#include "stv06xx_hdcs.h" + +static const struct ctrl hdcs1x00_ctrl[] = { + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = HDCS_DEFAULT_EXPOSURE, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = hdcs_set_exposure, + .get = hdcs_get_exposure + }, { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = HDCS_DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = hdcs_set_gain, + .get = hdcs_get_gain + } +}; + +static struct v4l2_pix_format hdcs1x00_mode[] = { + { + HDCS_1X00_DEF_WIDTH, + HDCS_1X00_DEF_HEIGHT, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = + HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT, + .bytesperline = HDCS_1X00_DEF_WIDTH, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + } +}; + +static const struct ctrl hdcs1020_ctrl[] = { + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = 0xffff, + .step = 0x1, + .default_value = HDCS_DEFAULT_EXPOSURE, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = hdcs_set_exposure, + .get = hdcs_get_exposure + }, { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = HDCS_DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = hdcs_set_gain, + .get = hdcs_get_gain + } +}; + +static struct v4l2_pix_format hdcs1020_mode[] = { + { + HDCS_1020_DEF_WIDTH, + HDCS_1020_DEF_HEIGHT, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = + HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT, + .bytesperline = HDCS_1020_DEF_WIDTH, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + } +}; + +enum hdcs_power_state { + HDCS_STATE_SLEEP, + HDCS_STATE_IDLE, + HDCS_STATE_RUN +}; + +/* no lock? */ +struct hdcs { + enum hdcs_power_state state; + int w, h; + + /* visible area of the sensor array */ + struct { + int left, top; + int width, height; + int border; + } array; + + struct { + /* Column timing overhead */ + u8 cto; + /* Column processing overhead */ + u8 cpo; + /* Row sample period constant */ + u16 rs; + /* Exposure reset duration */ + u16 er; + } exp; + + int psmp; + u8 exp_cache, gain_cache; +}; + +static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len) +{ + u8 regs[I2C_MAX_BYTES * 2]; + int i; + + if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) || + (reg + len > 0xff))) + return -EINVAL; + + for (i = 0; i < len; i++) { + regs[2 * i] = reg; + regs[2 * i + 1] = vals[i]; + /* All addresses are shifted left one bit + * as bit 0 toggles r/w */ + reg += 2; + } + + return stv06xx_write_sensor_bytes(sd, regs, len); +} + +static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state) +{ + struct hdcs *hdcs = sd->sensor_priv; + u8 val; + int ret; + + if (hdcs->state == state) + return 0; + + /* we need to go idle before running or sleeping */ + if (hdcs->state != HDCS_STATE_IDLE) { + ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); + if (ret) + return ret; + } + + hdcs->state = HDCS_STATE_IDLE; + + if (state == HDCS_STATE_IDLE) + return 0; + + switch (state) { + case HDCS_STATE_SLEEP: + val = HDCS_SLEEP_MODE; + break; + + case HDCS_STATE_RUN: + val = HDCS_RUN_ENABLE; + break; + + default: + return -EINVAL; + } + + ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val); + + /* Update the state if the write succeeded */ + if (!ret) + hdcs->state = state; + + return ret; +} + +static int hdcs_reset(struct sd *sd) +{ + struct hdcs *hdcs = sd->sensor_priv; + int err; + + err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1); + if (err < 0) + return err; + + err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); + if (err < 0) + hdcs->state = HDCS_STATE_IDLE; + + return err; +} + +static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct hdcs *hdcs = sd->sensor_priv; + + *val = hdcs->exp_cache; + + return 0; +} + +static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct hdcs *hdcs = sd->sensor_priv; + int rowexp, srowexp; + int max_srowexp; + /* Column time period */ + int ct; + /* Column processing period */ + int cp; + /* Row processing period */ + int rp; + /* Minimum number of column timing periods + within the column processing period */ + int mnct; + int cycles, err; + u8 exp[14]; + + val &= 0xff; + hdcs->exp_cache = val; + + cycles = val * HDCS_CLK_FREQ_MHZ * 257; + + ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); + cp = hdcs->exp.cto + (hdcs->w * ct / 2); + + /* the cycles one row takes */ + rp = hdcs->exp.rs + cp; + + rowexp = cycles / rp; + + /* the remaining cycles */ + cycles -= rowexp * rp; + + /* calculate sub-row exposure */ + if (IS_1020(sd)) { + /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */ + srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct; + + mnct = (hdcs->exp.er + 12 + ct - 1) / ct; + max_srowexp = hdcs->w - mnct; + } else { + /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */ + srowexp = cp - hdcs->exp.er - 6 - cycles; + + mnct = (hdcs->exp.er + 5 + ct - 1) / ct; + max_srowexp = cp - mnct * ct - 1; + } + + if (srowexp < 0) + srowexp = 0; + else if (srowexp > max_srowexp) + srowexp = max_srowexp; + + if (IS_1020(sd)) { + exp[0] = HDCS20_CONTROL; + exp[1] = 0x00; /* Stop streaming */ + exp[2] = HDCS_ROWEXPL; + exp[3] = rowexp & 0xff; + exp[4] = HDCS_ROWEXPH; + exp[5] = rowexp >> 8; + exp[6] = HDCS20_SROWEXP; + exp[7] = (srowexp >> 2) & 0xff; + exp[8] = HDCS20_ERROR; + exp[9] = 0x10; /* Clear exposure error flag*/ + exp[10] = HDCS20_CONTROL; + exp[11] = 0x04; /* Restart streaming */ + err = stv06xx_write_sensor_bytes(sd, exp, 6); + } else { + exp[0] = HDCS00_CONTROL; + exp[1] = 0x00; /* Stop streaming */ + exp[2] = HDCS_ROWEXPL; + exp[3] = rowexp & 0xff; + exp[4] = HDCS_ROWEXPH; + exp[5] = rowexp >> 8; + exp[6] = HDCS00_SROWEXPL; + exp[7] = srowexp & 0xff; + exp[8] = HDCS00_SROWEXPH; + exp[9] = srowexp >> 8; + exp[10] = HDCS_STATUS; + exp[11] = 0x10; /* Clear exposure error flag*/ + exp[12] = HDCS00_CONTROL; + exp[13] = 0x04; /* Restart streaming */ + err = stv06xx_write_sensor_bytes(sd, exp, 7); + if (err < 0) + return err; + } + PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d", + val, rowexp, srowexp); + return err; +} + +static int hdcs_set_gains(struct sd *sd, u8 g) +{ + struct hdcs *hdcs = sd->sensor_priv; + int err; + u8 gains[4]; + + hdcs->gain_cache = g; + + /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */ + if (g > 127) + g = 0x80 | (g / 2); + + gains[0] = g; + gains[1] = g; + gains[2] = g; + gains[3] = g; + + err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4); + return err; +} + +static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct hdcs *hdcs = sd->sensor_priv; + + *val = hdcs->gain_cache; + + return 0; +} + +static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + PDEBUG(D_V4L2, "Writing gain %d", val); + return hdcs_set_gains((struct sd *) gspca_dev, + val & 0xff); +} + +static int hdcs_set_size(struct sd *sd, + unsigned int width, unsigned int height) +{ + struct hdcs *hdcs = sd->sensor_priv; + u8 win[4]; + unsigned int x, y; + int err; + + /* must be multiple of 4 */ + width = (width + 3) & ~0x3; + height = (height + 3) & ~0x3; + + if (width > hdcs->array.width) + width = hdcs->array.width; + + if (IS_1020(sd)) { + /* the borders are also invalid */ + if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP + > hdcs->array.height) + height = hdcs->array.height - 2 * hdcs->array.border - + HDCS_1020_BOTTOM_Y_SKIP; + + y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2 + + hdcs->array.top; + } else { + if (height > hdcs->array.height) + height = hdcs->array.height; + + y = hdcs->array.top + (hdcs->array.height - height) / 2; + } + + x = hdcs->array.left + (hdcs->array.width - width) / 2; + + win[0] = y / 4; + win[1] = x / 4; + win[2] = (y + height) / 4 - 1; + win[3] = (x + width) / 4 - 1; + + err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4); + if (err < 0) + return err; + + /* Update the current width and height */ + hdcs->w = width; + hdcs->h = height; + return err; +} + +static int hdcs_probe_1x00(struct sd *sd) +{ + struct hdcs *hdcs; + u16 sensor; + int ret; + + ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); + if (ret < 0 || sensor != 0x08) + return -ENODEV; + + info("HDCS-1000/1100 sensor detected"); + + sd->gspca_dev.cam.cam_mode = hdcs1x00_mode; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode); + sd->desc.ctrls = hdcs1x00_ctrl; + sd->desc.nctrls = ARRAY_SIZE(hdcs1x00_ctrl); + + hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); + if (!hdcs) + return -ENOMEM; + + hdcs->array.left = 8; + hdcs->array.top = 8; + hdcs->array.width = HDCS_1X00_DEF_WIDTH; + hdcs->array.height = HDCS_1X00_DEF_HEIGHT; + hdcs->array.border = 4; + + hdcs->exp.cto = 4; + hdcs->exp.cpo = 2; + hdcs->exp.rs = 186; + hdcs->exp.er = 100; + + /* + * Frame rate on HDCS-1000 with STV600 depends on PSMP: + * 4 = doesn't work at all + * 5 = 7.8 fps, + * 6 = 6.9 fps, + * 8 = 6.3 fps, + * 10 = 5.5 fps, + * 15 = 4.4 fps, + * 31 = 2.8 fps + * + * Frame rate on HDCS-1000 with STV602 depends on PSMP: + * 15 = doesn't work at all + * 18 = doesn't work at all + * 19 = 7.3 fps + * 20 = 7.4 fps + * 21 = 7.4 fps + * 22 = 7.4 fps + * 24 = 6.3 fps + * 30 = 5.4 fps + */ + hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5; + + sd->sensor_priv = hdcs; + + return 0; +} + +static int hdcs_probe_1020(struct sd *sd) +{ + struct hdcs *hdcs; + u16 sensor; + int ret; + + ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); + if (ret < 0 || sensor != 0x10) + return -ENODEV; + + info("HDCS-1020 sensor detected"); + + sd->gspca_dev.cam.cam_mode = hdcs1020_mode; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode); + sd->desc.ctrls = hdcs1020_ctrl; + sd->desc.nctrls = ARRAY_SIZE(hdcs1020_ctrl); + + hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); + if (!hdcs) + return -ENOMEM; + + /* + * From Andrey's test image: looks like HDCS-1020 upper-left + * visible pixel is at 24,8 (y maybe even smaller?) and lower-right + * visible pixel at 375,299 (x maybe even larger?) + */ + hdcs->array.left = 24; + hdcs->array.top = 4; + hdcs->array.width = HDCS_1020_DEF_WIDTH; + hdcs->array.height = 304; + hdcs->array.border = 4; + + hdcs->psmp = 6; + + hdcs->exp.cto = 3; + hdcs->exp.cpo = 3; + hdcs->exp.rs = 155; + hdcs->exp.er = 96; + + sd->sensor_priv = hdcs; + + return 0; +} + +static int hdcs_start(struct sd *sd) +{ + PDEBUG(D_STREAM, "Starting stream"); + + return hdcs_set_state(sd, HDCS_STATE_RUN); +} + +static int hdcs_stop(struct sd *sd) +{ + PDEBUG(D_STREAM, "Halting stream"); + + return hdcs_set_state(sd, HDCS_STATE_SLEEP); +} + +static void hdcs_disconnect(struct sd *sd) +{ + PDEBUG(D_PROBE, "Disconnecting the sensor"); + kfree(sd->sensor_priv); +} + +static int hdcs_init(struct sd *sd) +{ + struct hdcs *hdcs = sd->sensor_priv; + int i, err = 0; + + /* Set the STV0602AA in STV0600 emulation mode */ + if (sd->bridge == BRIDGE_STV602) + stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1); + + /* Execute the bridge init */ + for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) { + err = stv06xx_write_bridge(sd, stv_bridge_init[i][0], + stv_bridge_init[i][1]); + } + if (err < 0) + return err; + + /* sensor soft reset */ + hdcs_reset(sd); + + /* Execute the sensor init */ + for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) { + err = stv06xx_write_sensor(sd, stv_sensor_init[i][0], + stv_sensor_init[i][1]); + } + if (err < 0) + return err; + + /* Enable continuous frame capture, bit 2: stop when frame complete */ + err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3)); + if (err < 0) + return err; + + /* Set PGA sample duration + (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */ + if (IS_1020(sd)) + err = stv06xx_write_sensor(sd, HDCS_TCTRL, + (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp); + else + err = stv06xx_write_sensor(sd, HDCS_TCTRL, + (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp); + if (err < 0) + return err; + + err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN); + if (err < 0) + return err; + + err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height); + if (err < 0) + return err; + + err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE); + return err; +} + +static int hdcs_dump(struct sd *sd) +{ + u16 reg, val; + + info("Dumping sensor registers:"); + + for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { + stv06xx_read_sensor(sd, reg, &val); + info("reg 0x%02x = 0x%02x", reg, val); + } + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * Copyright (c) 2008 Chia-I Wu + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_HDCS_H_ +#define STV06XX_HDCS_H_ + +#include "stv06xx_sensor.h" + +#define HDCS_REG_CONFIG(sd) (IS_1020(sd) ? HDCS20_CONFIG : HDCS00_CONFIG) +#define HDCS_REG_CONTROL(sd) (IS_1020(sd) ? HDCS20_CONTROL : HDCS00_CONTROL) + +#define HDCS_1X00_DEF_WIDTH 360 +#define HDCS_1X00_DEF_HEIGHT 296 + +#define HDCS_1020_DEF_WIDTH 352 +#define HDCS_1020_DEF_HEIGHT 292 + +#define HDCS_1020_BOTTOM_Y_SKIP 4 + +#define HDCS_CLK_FREQ_MHZ 25 + +#define HDCS_ADC_START_SIG_DUR 3 + +/* LSB bit of I2C or register address signifies write (0) or read (1) */ +/* I2C Registers common for both HDCS-1000/1100 and HDCS-1020 */ +/* Identifications Register */ +#define HDCS_IDENT (0x00 << 1) +/* Status Register */ +#define HDCS_STATUS (0x01 << 1) +/* Interrupt Mask Register */ +#define HDCS_IMASK (0x02 << 1) +/* Pad Control Register */ +#define HDCS_PCTRL (0x03 << 1) +/* Pad Drive Control Register */ +#define HDCS_PDRV (0x04 << 1) +/* Interface Control Register */ +#define HDCS_ICTRL (0x05 << 1) +/* Interface Timing Register */ +#define HDCS_ITMG (0x06 << 1) +/* Baud Fraction Register */ +#define HDCS_BFRAC (0x07 << 1) +/* Baud Rate Register */ +#define HDCS_BRATE (0x08 << 1) +/* ADC Control Register */ +#define HDCS_ADCCTRL (0x09 << 1) +/* First Window Row Register */ +#define HDCS_FWROW (0x0a << 1) +/* First Window Column Register */ +#define HDCS_FWCOL (0x0b << 1) +/* Last Window Row Register */ +#define HDCS_LWROW (0x0c << 1) +/* Last Window Column Register */ +#define HDCS_LWCOL (0x0d << 1) +/* Timing Control Register */ +#define HDCS_TCTRL (0x0e << 1) +/* PGA Gain Register: Even Row, Even Column */ +#define HDCS_ERECPGA (0x0f << 1) +/* PGA Gain Register: Even Row, Odd Column */ +#define HDCS_EROCPGA (0x10 << 1) +/* PGA Gain Register: Odd Row, Even Column */ +#define HDCS_ORECPGA (0x11 << 1) +/* PGA Gain Register: Odd Row, Odd Column */ +#define HDCS_OROCPGA (0x12 << 1) +/* Row Exposure Low Register */ +#define HDCS_ROWEXPL (0x13 << 1) +/* Row Exposure High Register */ +#define HDCS_ROWEXPH (0x14 << 1) + +/* I2C Registers only for HDCS-1000/1100 */ +/* Sub-Row Exposure Low Register */ +#define HDCS00_SROWEXPL (0x15 << 1) +/* Sub-Row Exposure High Register */ +#define HDCS00_SROWEXPH (0x16 << 1) +/* Configuration Register */ +#define HDCS00_CONFIG (0x17 << 1) +/* Control Register */ +#define HDCS00_CONTROL (0x18 << 1) + +/* I2C Registers only for HDCS-1020 */ +/* Sub-Row Exposure Register */ +#define HDCS20_SROWEXP (0x15 << 1) +/* Error Control Register */ +#define HDCS20_ERROR (0x16 << 1) +/* Interface Timing 2 Register */ +#define HDCS20_ITMG2 (0x17 << 1) +/* Interface Control 2 Register */ +#define HDCS20_ICTRL2 (0x18 << 1) +/* Horizontal Blank Register */ +#define HDCS20_HBLANK (0x19 << 1) +/* Vertical Blank Register */ +#define HDCS20_VBLANK (0x1a << 1) +/* Configuration Register */ +#define HDCS20_CONFIG (0x1b << 1) +/* Control Register */ +#define HDCS20_CONTROL (0x1c << 1) + +#define HDCS_RUN_ENABLE (1 << 2) +#define HDCS_SLEEP_MODE (1 << 1) + +#define HDCS_DEFAULT_EXPOSURE 48 +#define HDCS_DEFAULT_GAIN 50 + +static int hdcs_probe_1x00(struct sd *sd); +static int hdcs_probe_1020(struct sd *sd); +static int hdcs_start(struct sd *sd); +static int hdcs_init(struct sd *sd); +static int hdcs_stop(struct sd *sd); +static int hdcs_dump(struct sd *sd); +static void hdcs_disconnect(struct sd *sd); + +static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val); + +const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = { + .name = "HP HDCS-1000/1100", + .i2c_flush = 0, + .i2c_addr = (0x55 << 1), + .i2c_len = 1, + + /* FIXME (see if we can lower min_packet_size, needs testing, and also + adjusting framerate when the bandwidth gets lower) */ + .min_packet_size = { 847 }, + .max_packet_size = { 847 }, + + .init = hdcs_init, + .probe = hdcs_probe_1x00, + .start = hdcs_start, + .stop = hdcs_stop, + .disconnect = hdcs_disconnect, + .dump = hdcs_dump, +}; + +const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = { + .name = "HDCS-1020", + .i2c_flush = 0, + .i2c_addr = (0x55 << 1), + .i2c_len = 1, + + /* FIXME (see if we can lower min_packet_size, needs testing, and also + adjusting framerate when the bandwidthm gets lower) */ + .min_packet_size = { 847 }, + .max_packet_size = { 847 }, + + .init = hdcs_init, + .probe = hdcs_probe_1020, + .start = hdcs_start, + .stop = hdcs_stop, + .dump = hdcs_dump, +}; + +static const u16 stv_bridge_init[][2] = { + {STV_ISO_ENABLE, 0}, + {STV_REG23, 0}, + {STV_REG00, 0x1d}, + {STV_REG01, 0xb5}, + {STV_REG02, 0xa8}, + {STV_REG03, 0x95}, + {STV_REG04, 0x07}, + + {STV_SCAN_RATE, 0x20}, + {STV_Y_CTRL, 0x01}, + {STV_X_CTRL, 0x0a} +}; + +static const u8 stv_sensor_init[][2] = { + /* Clear status (writing 1 will clear the corresponding status bit) */ + {HDCS_STATUS, BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, + /* Disable all interrupts */ + {HDCS_IMASK, 0x00}, + {HDCS_PCTRL, BIT(6) | BIT(5) | BIT(1) | BIT(0)}, + {HDCS_PDRV, 0x00}, + {HDCS_ICTRL, BIT(5)}, + {HDCS_ITMG, BIT(4) | BIT(1)}, + /* ADC output resolution to 10 bits */ + {HDCS_ADCCTRL, 10} +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +/* + * The spec file for the PB-0100 suggests the following for best quality + * images after the sensor has been reset : + * + * PB_ADCGAINL = R60 = 0x03 (3 dec) : sets low reference of ADC + to produce good black level + * PB_PREADCTRL = R32 = 0x1400 (5120 dec) : Enables global gain changes + through R53 + * PB_ADCMINGAIN = R52 = 0x10 (16 dec) : Sets the minimum gain for + auto-exposure + * PB_ADCGLOBALGAIN = R53 = 0x10 (16 dec) : Sets the global gain + * PB_EXPGAIN = R14 = 0x11 (17 dec) : Sets the auto-exposure value + * PB_UPDATEINT = R23 = 0x02 (2 dec) : Sets the speed on + auto-exposure routine + * PB_CFILLIN = R5 = 0x0E (14 dec) : Sets the frame rate + */ + +#include "stv06xx_pb0100.h" + +static const struct ctrl pb0100_ctrl[] = { +#define GAIN_IDX 0 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128 + }, + .set = pb0100_set_gain, + .get = pb0100_get_gain + }, +#define RED_BALANCE_IDX 1 + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = -255, + .maximum = 255, + .step = 1, + .default_value = 0 + }, + .set = pb0100_set_red_balance, + .get = pb0100_get_red_balance + }, +#define BLUE_BALANCE_IDX 2 + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = -255, + .maximum = 255, + .step = 1, + .default_value = 0 + }, + .set = pb0100_set_blue_balance, + .get = pb0100_get_blue_balance + }, +#define EXPOSURE_IDX 3 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 511, + .step = 1, + .default_value = 12 + }, + .set = pb0100_set_exposure, + .get = pb0100_get_exposure + }, +#define AUTOGAIN_IDX 4 + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Gain and Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = pb0100_set_autogain, + .get = pb0100_get_autogain + }, +#define AUTOGAIN_TARGET_IDX 5 + { + { + .id = V4L2_CTRL_CLASS_USER + 0x1000, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Automatic Gain Target", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128 + }, + .set = pb0100_set_autogain_target, + .get = pb0100_get_autogain_target + }, +#define NATURAL_IDX 6 + { + { + .id = V4L2_CTRL_CLASS_USER + 0x1001, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Natural Light Source", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = pb0100_set_natural, + .get = pb0100_get_natural + } +}; + +static struct v4l2_pix_format pb0100_mode[] = { +/* low res / subsample modes disabled as they are only half res horizontal, + halving the vertical resolution does not seem to work */ + { + 320, + 240, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 320 * 240, + .bytesperline = 320, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = PB0100_CROP_TO_VGA + }, + { + 352, + 288, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 352 * 288, + .bytesperline = 352, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + } +}; + +static int pb0100_probe(struct sd *sd) +{ + u16 sensor; + int i, err; + s32 *sensor_settings; + + err = stv06xx_read_sensor(sd, PB_IDENT, &sensor); + + if (err < 0) + return -ENODEV; + + if ((sensor >> 8) == 0x64) { + sensor_settings = kmalloc( + ARRAY_SIZE(pb0100_ctrl) * sizeof(s32), + GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + info("Photobit pb0100 sensor detected"); + + sd->gspca_dev.cam.cam_mode = pb0100_mode; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode); + sd->desc.ctrls = pb0100_ctrl; + sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl); + for (i = 0; i < sd->desc.nctrls; i++) + sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + + return 0; + } + + return -ENODEV; +} + +static int pb0100_start(struct sd *sd) +{ + int err, packet_size, max_packet_size; + struct usb_host_interface *alt; + struct usb_interface *intf; + struct cam *cam = &sd->gspca_dev.cam; + s32 *sensor_settings = sd->sensor_priv; + u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv; + + intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) + return -ENODEV; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + + /* If we don't have enough bandwidth use a lower framerate */ + max_packet_size = sd->sensor->max_packet_size[sd->gspca_dev.curr_mode]; + if (packet_size < max_packet_size) + stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1)); + else + stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(5)|BIT(3)|BIT(1)); + + /* Setup sensor window */ + if (mode & PB0100_CROP_TO_VGA) { + stv06xx_write_sensor(sd, PB_RSTART, 30); + stv06xx_write_sensor(sd, PB_CSTART, 20); + stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1); + stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1); + } else { + stv06xx_write_sensor(sd, PB_RSTART, 8); + stv06xx_write_sensor(sd, PB_CSTART, 4); + stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1); + stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1); + } + + if (mode & PB0100_SUBSAMPLE) { + stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */ + stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); + + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); + } else { + stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); + stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); + /* larger -> slower */ + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); + } + + /* set_gain also sets red and blue balance */ + pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]); + pb0100_set_autogain_target(&sd->gspca_dev, + sensor_settings[AUTOGAIN_TARGET_IDX]); + pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]); + + err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1)); + PDEBUG(D_STREAM, "Started stream, status: %d", err); + + return (err < 0) ? err : 0; +} + +static int pb0100_stop(struct sd *sd) +{ + int err; + + err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1); + + if (err < 0) + goto out; + + /* Set bit 1 to zero */ + err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)); + + PDEBUG(D_STREAM, "Halting stream"); +out: + return (err < 0) ? err : 0; +} + +static void pb0100_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +/* FIXME: Sort the init commands out and put them into tables, + this is only for getting the camera to work */ +/* FIXME: No error handling for now, + add this once the init has been converted to proper tables */ +static int pb0100_init(struct sd *sd) +{ + stv06xx_write_bridge(sd, STV_REG00, 1); + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0); + + /* Reset sensor */ + stv06xx_write_sensor(sd, PB_RESET, 1); + stv06xx_write_sensor(sd, PB_RESET, 0); + + /* Disable chip */ + stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)); + + /* Gain stuff...*/ + stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6)); + stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12); + + /* Set up auto-exposure */ + /* ADC VREF_HI new setting for a transition + from the Expose1 to the Expose2 setting */ + stv06xx_write_sensor(sd, PB_R28, 12); + /* gain max for autoexposure */ + stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180); + /* gain min for autoexposure */ + stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12); + /* Maximum frame integration time (programmed into R8) + allowed for auto-exposure routine */ + stv06xx_write_sensor(sd, PB_R54, 3); + /* Minimum frame integration time (programmed into R8) + allowed for auto-exposure routine */ + stv06xx_write_sensor(sd, PB_R55, 0); + stv06xx_write_sensor(sd, PB_UPDATEINT, 1); + /* R15 Expose0 (maximum that auto-exposure may use) */ + stv06xx_write_sensor(sd, PB_R15, 800); + /* R17 Expose2 (minimum that auto-exposure may use) */ + stv06xx_write_sensor(sd, PB_R17, 10); + + stv06xx_write_sensor(sd, PB_EXPGAIN, 0); + + /* 0x14 */ + stv06xx_write_sensor(sd, PB_VOFFSET, 0); + /* 0x0D */ + stv06xx_write_sensor(sd, PB_ADCGAINH, 11); + /* Set black level (important!) */ + stv06xx_write_sensor(sd, PB_ADCGAINL, 0); + + /* ??? */ + stv06xx_write_bridge(sd, STV_REG00, 0x11); + stv06xx_write_bridge(sd, STV_REG03, 0x45); + stv06xx_write_bridge(sd, STV_REG04, 0x07); + + /* Scan/timing for the sensor */ + stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1)); + stv06xx_write_sensor(sd, PB_CFILLIN, 14); + stv06xx_write_sensor(sd, PB_VBL, 0); + stv06xx_write_sensor(sd, PB_FINTTIME, 0); + stv06xx_write_sensor(sd, PB_RINTTIME, 123); + + stv06xx_write_bridge(sd, STV_REG01, 0xc2); + stv06xx_write_bridge(sd, STV_REG02, 0xb0); + return 0; +} + +static int pb0100_dump(struct sd *sd) +{ + return 0; +} + +static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + + return 0; +} + +static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + if (sensor_settings[AUTOGAIN_IDX]) + return -EBUSY; + + sensor_settings[GAIN_IDX] = val; + err = stv06xx_write_sensor(sd, PB_G1GAIN, val); + if (!err) + err = stv06xx_write_sensor(sd, PB_G2GAIN, val); + PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err); + + if (!err) + err = pb0100_set_red_balance(gspca_dev, + sensor_settings[RED_BALANCE_IDX]); + if (!err) + err = pb0100_set_blue_balance(gspca_dev, + sensor_settings[BLUE_BALANCE_IDX]); + + return err; +} + +static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[RED_BALANCE_IDX]; + + return 0; +} + +static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + if (sensor_settings[AUTOGAIN_IDX]) + return -EBUSY; + + sensor_settings[RED_BALANCE_IDX] = val; + val += sensor_settings[GAIN_IDX]; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + + err = stv06xx_write_sensor(sd, PB_RGAIN, val); + PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err); + + return err; +} + +static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[BLUE_BALANCE_IDX]; + + return 0; +} + +static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + if (sensor_settings[AUTOGAIN_IDX]) + return -EBUSY; + + sensor_settings[BLUE_BALANCE_IDX] = val; + val += sensor_settings[GAIN_IDX]; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + + err = stv06xx_write_sensor(sd, PB_BGAIN, val); + PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err); + + return err; +} + +static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[EXPOSURE_IDX]; + + return 0; +} + +static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + if (sensor_settings[AUTOGAIN_IDX]) + return -EBUSY; + + sensor_settings[EXPOSURE_IDX] = val; + err = stv06xx_write_sensor(sd, PB_RINTTIME, val); + PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err); + + return err; +} + +static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTOGAIN_IDX]; + + return 0; +} + +static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[AUTOGAIN_IDX] = val; + if (sensor_settings[AUTOGAIN_IDX]) { + if (sensor_settings[NATURAL_IDX]) + val = BIT(6)|BIT(4)|BIT(0); + else + val = BIT(4)|BIT(0); + } else + val = 0; + + err = stv06xx_write_sensor(sd, PB_EXPGAIN, val); + PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d", + sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX], + err); + + return err; +} + +static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTOGAIN_TARGET_IDX]; + + return 0; +} + +static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val) +{ + int err, totalpixels, brightpixels, darkpixels; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[AUTOGAIN_TARGET_IDX] = val; + + /* Number of pixels counted by the sensor when subsampling the pixels. + * Slightly larger than the real value to avoid oscillation */ + totalpixels = gspca_dev->width * gspca_dev->height; + totalpixels = totalpixels/(8*8) + totalpixels/(64*64); + + brightpixels = (totalpixels * val) >> 8; + darkpixels = totalpixels - brightpixels; + err = stv06xx_write_sensor(sd, PB_R21, brightpixels); + if (!err) + err = stv06xx_write_sensor(sd, PB_R22, darkpixels); + + PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err); + + return err; +} + +static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[NATURAL_IDX]; + + return 0; +} + +static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[NATURAL_IDX] = val; + + return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_PB0100_H_ +#define STV06XX_PB0100_H_ + +#include "stv06xx_sensor.h" + +/* mode priv field flags */ +#define PB0100_CROP_TO_VGA 0x01 +#define PB0100_SUBSAMPLE 0x02 + +/* I2C Registers */ +#define PB_IDENT 0x00 /* Chip Version */ +#define PB_RSTART 0x01 /* Row Window Start */ +#define PB_CSTART 0x02 /* Column Window Start */ +#define PB_RWSIZE 0x03 /* Row Window Size */ +#define PB_CWSIZE 0x04 /* Column Window Size */ +#define PB_CFILLIN 0x05 /* Column Fill-In */ +#define PB_VBL 0x06 /* Vertical Blank Count */ +#define PB_CONTROL 0x07 /* Control Mode */ +#define PB_FINTTIME 0x08 /* Integration Time/Frame Unit Count */ +#define PB_RINTTIME 0x09 /* Integration Time/Row Unit Count */ +#define PB_ROWSPEED 0x0a /* Row Speed Control */ +#define PB_ABORTFRAME 0x0b /* Abort Frame */ +#define PB_R12 0x0c /* Reserved */ +#define PB_RESET 0x0d /* Reset */ +#define PB_EXPGAIN 0x0e /* Exposure Gain Command */ +#define PB_R15 0x0f /* Expose0 */ +#define PB_R16 0x10 /* Expose1 */ +#define PB_R17 0x11 /* Expose2 */ +#define PB_R18 0x12 /* Low0_DAC */ +#define PB_R19 0x13 /* Low1_DAC */ +#define PB_R20 0x14 /* Low2_DAC */ +#define PB_R21 0x15 /* Threshold11 */ +#define PB_R22 0x16 /* Threshold0x */ +#define PB_UPDATEINT 0x17 /* Update Interval */ +#define PB_R24 0x18 /* High_DAC */ +#define PB_R25 0x19 /* Trans0H */ +#define PB_R26 0x1a /* Trans1L */ +#define PB_R27 0x1b /* Trans1H */ +#define PB_R28 0x1c /* Trans2L */ +#define PB_R29 0x1d /* Reserved */ +#define PB_R30 0x1e /* Reserved */ +#define PB_R31 0x1f /* Wait to Read */ +#define PB_PREADCTRL 0x20 /* Pixel Read Control Mode */ +#define PB_R33 0x21 /* IREF_VLN */ +#define PB_R34 0x22 /* IREF_VLP */ +#define PB_R35 0x23 /* IREF_VLN_INTEG */ +#define PB_R36 0x24 /* IREF_MASTER */ +#define PB_R37 0x25 /* IDACP */ +#define PB_R38 0x26 /* IDACN */ +#define PB_R39 0x27 /* DAC_Control_Reg */ +#define PB_R40 0x28 /* VCL */ +#define PB_R41 0x29 /* IREF_VLN_ADCIN */ +#define PB_R42 0x2a /* Reserved */ +#define PB_G1GAIN 0x2b /* Green 1 Gain */ +#define PB_BGAIN 0x2c /* Blue Gain */ +#define PB_RGAIN 0x2d /* Red Gain */ +#define PB_G2GAIN 0x2e /* Green 2 Gain */ +#define PB_R47 0x2f /* Dark Row Address */ +#define PB_R48 0x30 /* Dark Row Options */ +#define PB_R49 0x31 /* Reserved */ +#define PB_R50 0x32 /* Image Test Data */ +#define PB_ADCMAXGAIN 0x33 /* Maximum Gain */ +#define PB_ADCMINGAIN 0x34 /* Minimum Gain */ +#define PB_ADCGLOBALGAIN 0x35 /* Global Gain */ +#define PB_R54 0x36 /* Maximum Frame */ +#define PB_R55 0x37 /* Minimum Frame */ +#define PB_R56 0x38 /* Reserved */ +#define PB_VOFFSET 0x39 /* VOFFSET */ +#define PB_R58 0x3a /* Snap-Shot Sequence Trigger */ +#define PB_ADCGAINH 0x3b /* VREF_HI */ +#define PB_ADCGAINL 0x3c /* VREF_LO */ +#define PB_R61 0x3d /* Reserved */ +#define PB_R62 0x3e /* Reserved */ +#define PB_R63 0x3f /* Reserved */ +#define PB_R64 0x40 /* Red/Blue Gain */ +#define PB_R65 0x41 /* Green 2/Green 1 Gain */ +#define PB_R66 0x42 /* VREF_HI/LO */ +#define PB_R67 0x43 /* Integration Time/Row Unit Count */ +#define PB_R240 0xf0 /* ADC Test */ +#define PB_R241 0xf1 /* Chip Enable */ +#define PB_R242 0xf2 /* Reserved */ + +static int pb0100_probe(struct sd *sd); +static int pb0100_start(struct sd *sd); +static int pb0100_init(struct sd *sd); +static int pb0100_stop(struct sd *sd); +static int pb0100_dump(struct sd *sd); +static void pb0100_disconnect(struct sd *sd); + +/* V4L2 controls supported by the driver */ +static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); +static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val); +static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val); +static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val); +static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val); +static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val); +static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val); + +const struct stv06xx_sensor stv06xx_sensor_pb0100 = { + .name = "PB-0100", + .i2c_flush = 1, + .i2c_addr = 0xba, + .i2c_len = 2, + + .min_packet_size = { 635, 847 }, + .max_packet_size = { 847, 923 }, + + .init = pb0100_init, + .probe = pb0100_probe, + .start = pb0100_start, + .stop = pb0100_stop, + .dump = pb0100_dump, + .disconnect = pb0100_disconnect, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_SENSOR_H_ +#define STV06XX_SENSOR_H_ + +#include "stv06xx.h" + +#define IS_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020) + +extern const struct stv06xx_sensor stv06xx_sensor_vv6410; +extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00; +extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020; +extern const struct stv06xx_sensor stv06xx_sensor_pb0100; +extern const struct stv06xx_sensor stv06xx_sensor_st6422; + +struct stv06xx_sensor { + /* Defines the name of a sensor */ + char name[32]; + + /* Sensor i2c address */ + u8 i2c_addr; + + /* Flush value*/ + u8 i2c_flush; + + /* length of an i2c word */ + u8 i2c_len; + + /* Isoc packet size (per mode) */ + int min_packet_size[4]; + int max_packet_size[4]; + + /* Probes if the sensor is connected */ + int (*probe)(struct sd *sd); + + /* Performs a initialization sequence */ + int (*init)(struct sd *sd); + + /* Executed at device disconnect */ + void (*disconnect)(struct sd *sd); + + /* Reads a sensor register */ + int (*read_sensor)(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + + /* Writes to a sensor register */ + int (*write_sensor)(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + + /* Instructs the sensor to start streaming */ + int (*start)(struct sd *sd); + + /* Instructs the sensor to stop streaming */ + int (*stop)(struct sd *sd); + + /* Instructs the sensor to dump all its contents */ + int (*dump)(struct sd *sd); +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,401 @@ +/* + * Support for the sensor part which is integrated (I think) into the + * st6422 stv06xx alike bridge, as its integrated there are no i2c writes + * but instead direct bridge writes. + * + * Copyright (c) 2009 Hans de Goede + * + * Strongly based on qc-usb-messenger, which is: + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * + * 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, or + * (at your option) any later version. + * + * 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 "stv06xx_st6422.h" + +/* controls */ +enum e_ctrl { + BRIGHTNESS, + CONTRAST, + GAIN, + EXPOSURE, + NCTRLS /* number of controls */ +}; + +/* sensor settings */ +struct st6422_settings { + struct gspca_ctrl ctrls[NCTRLS]; +}; + +static struct v4l2_pix_format st6422_mode[] = { + /* Note we actually get 124 lines of data, of which we skip the 4st + 4 as they are garbage */ + { + 162, + 120, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 162 * 120, + .bytesperline = 162, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + }, + /* Note we actually get 248 lines of data, of which we skip the 4st + 4 as they are garbage, and we tell the app it only gets the + first 240 of the 244 lines it actually gets, so that it ignores + the last 4. */ + { + 324, + 240, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 324 * 244, + .bytesperline = 324, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + }, +}; + +/* V4L2 controls supported by the driver */ +static void st6422_set_brightness(struct gspca_dev *gspca_dev); +static void st6422_set_contrast(struct gspca_dev *gspca_dev); +static void st6422_set_gain(struct gspca_dev *gspca_dev); +static void st6422_set_exposure(struct gspca_dev *gspca_dev); + +static const struct ctrl st6422_ctrl[NCTRLS] = { +[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 31, + .step = 1, + .default_value = 3 + }, + .set_control = st6422_set_brightness + }, +[CONTRAST] = { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 11 + }, + .set_control = st6422_set_contrast + }, +[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 64 + }, + .set_control = st6422_set_gain + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, +#define EXPOSURE_MAX 1023 + .maximum = EXPOSURE_MAX, + .step = 1, + .default_value = 256 + }, + .set_control = st6422_set_exposure + }, +}; + +static int st6422_probe(struct sd *sd) +{ + struct st6422_settings *sensor_settings; + + if (sd->bridge != BRIDGE_ST6422) + return -ENODEV; + + info("st6422 sensor detected"); + + sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + sd->gspca_dev.cam.cam_mode = st6422_mode; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode); + sd->gspca_dev.cam.ctrls = sensor_settings->ctrls; + sd->desc.ctrls = st6422_ctrl; + sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl); + sd->sensor_priv = sensor_settings; + + return 0; +} + +static int st6422_init(struct sd *sd) +{ + int err = 0, i; + + const u16 st6422_bridge_init[][2] = { + { STV_ISO_ENABLE, 0x00 }, /* disable capture */ + { 0x1436, 0x00 }, + { 0x1432, 0x03 }, /* 0x00-0x1F brightness */ + { 0x143a, 0xf9 }, /* 0x00-0x0F contrast */ + { 0x0509, 0x38 }, /* R */ + { 0x050a, 0x38 }, /* G */ + { 0x050b, 0x38 }, /* B */ + { 0x050c, 0x2a }, + { 0x050d, 0x01 }, + + + { 0x1431, 0x00 }, /* 0x00-0x07 ??? */ + { 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */ + { 0x1438, 0x18 }, /* 640x480 */ +/* 18 bayes */ +/* 10 compressed? */ + + { 0x1439, 0x00 }, +/* anti-noise? 0xa2 gives a perfect image */ + + { 0x143b, 0x05 }, + { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ + + +/* shutter time 0x0000-0x03FF */ +/* low value give good picures on moving objects (but requires much light) */ +/* high value gives good picures in darkness (but tends to be overexposed) */ + { 0x143e, 0x01 }, + { 0x143d, 0x00 }, + + { 0x1442, 0xe2 }, +/* write: 1x1x xxxx */ +/* read: 1x1x xxxx */ +/* bit 5 == button pressed and hold if 0 */ +/* write 0xe2,0xea */ + +/* 0x144a */ +/* 0x00 init */ +/* bit 7 == button has been pressed, but not handled */ + +/* interrupt */ +/* if(urb->iso_frame_desc[i].status == 0x80) { */ +/* if(urb->iso_frame_desc[i].status == 0x88) { */ + + { 0x1500, 0xd0 }, + { 0x1500, 0xd0 }, + { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ + + { 0x1501, 0xaf }, +/* high val-> light area gets darker */ +/* low val -> light area gets lighter */ + { 0x1502, 0xc2 }, +/* high val-> light area gets darker */ +/* low val -> light area gets lighter */ + { 0x1503, 0x45 }, +/* high val-> light area gets darker */ +/* low val -> light area gets lighter */ + { 0x1505, 0x02 }, +/* 2 : 324x248 80352 bytes */ +/* 7 : 248x162 40176 bytes */ +/* c+f: 162*124 20088 bytes */ + + { 0x150e, 0x8e }, + { 0x150f, 0x37 }, + { 0x15c0, 0x00 }, + { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */ + + + { 0x143f, 0x01 }, /* commit settings */ + + }; + + for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) { + err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0], + st6422_bridge_init[i][1]); + } + + return err; +} + +static void st6422_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static int setbrightness(struct sd *sd) +{ + struct st6422_settings *sensor_settings = sd->sensor_priv; + + /* val goes from 0 -> 31 */ + return stv06xx_write_bridge(sd, 0x1432, + sensor_settings->ctrls[BRIGHTNESS].val); +} + +static int setcontrast(struct sd *sd) +{ + struct st6422_settings *sensor_settings = sd->sensor_priv; + + /* Val goes from 0 -> 15 */ + return stv06xx_write_bridge(sd, 0x143a, + sensor_settings->ctrls[CONTRAST].val | 0xf0); +} + +static int setgain(struct sd *sd) +{ + struct st6422_settings *sensor_settings = sd->sensor_priv; + u8 gain; + int err; + + gain = sensor_settings->ctrls[GAIN].val; + + /* Set red, green, blue, gain */ + err = stv06xx_write_bridge(sd, 0x0509, gain); + if (err < 0) + return err; + + err = stv06xx_write_bridge(sd, 0x050a, gain); + if (err < 0) + return err; + + err = stv06xx_write_bridge(sd, 0x050b, gain); + if (err < 0) + return err; + + /* 2 mystery writes */ + err = stv06xx_write_bridge(sd, 0x050c, 0x2a); + if (err < 0) + return err; + + return stv06xx_write_bridge(sd, 0x050d, 0x01); +} + +static int setexposure(struct sd *sd) +{ + struct st6422_settings *sensor_settings = sd->sensor_priv; + u16 expo; + int err; + + expo = sensor_settings->ctrls[EXPOSURE].val; + err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff); + if (err < 0) + return err; + + return stv06xx_write_bridge(sd, 0x143e, expo >> 8); +} + +static int st6422_start(struct sd *sd) +{ + int err; + struct cam *cam = &sd->gspca_dev.cam; + + if (cam->cam_mode[sd->gspca_dev.curr_mode].priv) + err = stv06xx_write_bridge(sd, 0x1505, 0x0f); + else + err = stv06xx_write_bridge(sd, 0x1505, 0x02); + if (err < 0) + return err; + + err = setbrightness(sd); + if (err < 0) + return err; + + err = setcontrast(sd); + if (err < 0) + return err; + + err = setexposure(sd); + if (err < 0) + return err; + + err = setgain(sd); + if (err < 0) + return err; + + /* commit settings */ + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + return (err < 0) ? err : 0; +} + +static int st6422_stop(struct sd *sd) +{ + PDEBUG(D_STREAM, "Halting stream"); + + return 0; +} + +static void st6422_set_brightness(struct gspca_dev *gspca_dev) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + + err = setbrightness(sd); + + /* commit settings */ + if (err >= 0) + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + + gspca_dev->usb_err = err; +} + +static void st6422_set_contrast(struct gspca_dev *gspca_dev) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + + err = setcontrast(sd); + + /* commit settings */ + if (err >= 0) + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + + gspca_dev->usb_err = err; +} + +static void st6422_set_gain(struct gspca_dev *gspca_dev) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + + err = setgain(sd); + + /* commit settings */ + if (err >= 0) + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + + gspca_dev->usb_err = err; +} + +static void st6422_set_exposure(struct gspca_dev *gspca_dev) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + + err = setexposure(sd); + + /* commit settings */ + if (err >= 0) + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + + gspca_dev->usb_err = err; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Support for the sensor part which is integrated (I think) into the + * st6422 stv06xx alike bridge, as its integrated there are no i2c writes + * but instead direct bridge writes. + * + * Copyright (c) 2009 Hans de Goede + * + * Strongly based on qc-usb-messenger, which is: + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * + * 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, or + * (at your option) any later version. + * + * 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 + * + */ + +#ifndef STV06XX_ST6422_H_ +#define STV06XX_ST6422_H_ + +#include "stv06xx_sensor.h" + +static int st6422_probe(struct sd *sd); +static int st6422_start(struct sd *sd); +static int st6422_init(struct sd *sd); +static int st6422_stop(struct sd *sd); +static void st6422_disconnect(struct sd *sd); + +const struct stv06xx_sensor stv06xx_sensor_st6422 = { + .name = "ST6422", + /* No known way to lower framerate in case of less bandwidth */ + .min_packet_size = { 300, 847 }, + .max_packet_size = { 300, 847 }, + .init = st6422_init, + .probe = st6422_probe, + .start = st6422_start, + .stop = st6422_stop, + .disconnect = st6422_disconnect, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#include "stv06xx_vv6410.h" + +static struct v4l2_pix_format vv6410_mode[] = { + { + 356, + 292, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 356 * 292, + .bytesperline = 356, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + } +}; + +static const struct ctrl vv6410_ctrl[] = { +#define HFLIP_IDX 0 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = vv6410_set_hflip, + .get = vv6410_get_hflip + }, +#define VFLIP_IDX 1 + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 + }, + .set = vv6410_set_vflip, + .get = vv6410_get_vflip + }, +#define GAIN_IDX 2 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "analog gain", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 10 + }, + .set = vv6410_set_analog_gain, + .get = vv6410_get_analog_gain + }, +#define EXPOSURE_IDX 3 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0, + .maximum = 32768, + .step = 1, + .default_value = 20000 + }, + .set = vv6410_set_exposure, + .get = vv6410_get_exposure + } + }; + +static int vv6410_probe(struct sd *sd) +{ + u16 data; + int err, i; + s32 *sensor_settings; + + err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data); + if (err < 0) + return -ENODEV; + + if (data == 0x19) { + info("vv6410 sensor detected"); + + sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32), + GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + sd->gspca_dev.cam.cam_mode = vv6410_mode; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode); + sd->desc.ctrls = vv6410_ctrl; + sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl); + + for (i = 0; i < sd->desc.nctrls; i++) + sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + return 0; + } + return -ENODEV; +} + +static int vv6410_init(struct sd *sd) +{ + int err = 0, i; + s32 *sensor_settings = sd->sensor_priv; + + for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { + /* if NULL then len contains single value */ + if (stv_bridge_init[i].data == NULL) { + err = stv06xx_write_bridge(sd, + stv_bridge_init[i].start, + stv_bridge_init[i].len); + } else { + int j; + for (j = 0; j < stv_bridge_init[i].len; j++) + err = stv06xx_write_bridge(sd, + stv_bridge_init[i].start + j, + stv_bridge_init[i].data[j]); + } + } + + if (err < 0) + return err; + + err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, + ARRAY_SIZE(vv6410_sensor_init)); + if (err < 0) + return err; + + err = vv6410_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); + if (err < 0) + return err; + + err = vv6410_set_analog_gain(&sd->gspca_dev, + sensor_settings[GAIN_IDX]); + + return (err < 0) ? err : 0; +} + +static void vv6410_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static int vv6410_start(struct sd *sd) +{ + int err; + struct cam *cam = &sd->gspca_dev.cam; + u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; + + if (priv & VV6410_CROP_TO_QVGA) { + PDEBUG(D_CONF, "Cropping to QVGA"); + stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1); + stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1); + } else { + stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1); + stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1); + } + + if (priv & VV6410_SUBSAMPLE) { + PDEBUG(D_CONF, "Enabling subsampling"); + stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); + stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); + + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); + } else { + stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); + stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); + + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); + } + + /* Turn on LED */ + err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON); + if (err < 0) + return err; + + err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0); + if (err < 0) + return err; + + PDEBUG(D_STREAM, "Starting stream"); + + return 0; +} + +static int vv6410_stop(struct sd *sd) +{ + int err; + + /* Turn off LED */ + err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF); + if (err < 0) + return err; + + err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE); + if (err < 0) + return err; + + PDEBUG(D_STREAM, "Halting stream"); + + return (err < 0) ? err : 0; +} + +static int vv6410_dump(struct sd *sd) +{ + u8 i; + int err = 0; + + info("Dumping all vv6410 sensor registers"); + for (i = 0; i < 0xff && !err; i++) { + u16 data; + err = stv06xx_read_sensor(sd, i, &data); + info("Register 0x%x contained 0x%x", i, data); + } + return (err < 0) ? err : 0; +} + +static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[HFLIP_IDX]; + PDEBUG(D_V4L2, "Read horizontal flip %d", *val); + + return 0; +} + +static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u16 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[HFLIP_IDX] = val; + err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); + if (err < 0) + return err; + + if (val) + i2c_data |= VV6410_HFLIP; + else + i2c_data &= ~VV6410_HFLIP; + + PDEBUG(D_V4L2, "Set horizontal flip to %d", val); + err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); + + return (err < 0) ? err : 0; +} + +static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[VFLIP_IDX]; + PDEBUG(D_V4L2, "Read vertical flip %d", *val); + + return 0; +} + +static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u16 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[VFLIP_IDX] = val; + err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); + if (err < 0) + return err; + + if (val) + i2c_data |= VV6410_VFLIP; + else + i2c_data &= ~VV6410_VFLIP; + + PDEBUG(D_V4L2, "Set vertical flip to %d", val); + err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); + + return (err < 0) ? err : 0; +} + +static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + + PDEBUG(D_V4L2, "Read analog gain %d", *val); + + return 0; +} + +static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[GAIN_IDX] = val; + PDEBUG(D_V4L2, "Set analog gain to %d", val); + err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); + + return (err < 0) ? err : 0; +} + +static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[EXPOSURE_IDX]; + + PDEBUG(D_V4L2, "Read exposure %d", *val); + + return 0; +} + +static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + unsigned int fine, coarse; + + sensor_settings[EXPOSURE_IDX] = val; + + val = (val * val >> 14) + val / 4; + + fine = val % VV6410_CIF_LINELENGTH; + coarse = min(512, val / VV6410_CIF_LINELENGTH); + + PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d", + coarse, fine); + + err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8); + if (err < 0) + goto out; + + err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff); + if (err < 0) + goto out; + + err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8); + if (err < 0) + goto out; + + err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff); + +out: + return err; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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, or + * (at your option) any later version. + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_VV6410_H_ +#define STV06XX_VV6410_H_ + +#include "stv06xx_sensor.h" + +#define VV6410_COLS 416 +#define VV6410_ROWS 320 + +/* Status registers */ +/* Chip identification number including revision indicator */ +#define VV6410_DEVICEH 0x00 +#define VV6410_DEVICEL 0x01 + +/* User can determine whether timed I2C data + has been consumed by interrogating flag states */ +#define VV6410_STATUS0 0x02 + +/* Current line counter value */ +#define VV6410_LINECOUNTH 0x03 +#define VV6410_LINECOUNTL 0x04 + +/* End x coordinate of image size */ +#define VV6410_XENDH 0x05 +#define VV6410_XENDL 0x06 + +/* End y coordinate of image size */ +#define VV6410_YENDH 0x07 +#define VV6410_YENDL 0x08 + +/* This is the average pixel value returned from the + dark line offset cancellation algorithm */ +#define VV6410_DARKAVGH 0x09 +#define VV6410_DARKAVGL 0x0a + +/* This is the average pixel value returned from the + black line offset cancellation algorithm */ +#define VV6410_BLACKAVGH 0x0b +#define VV6410_BLACKAVGL 0x0c + +/* Flags to indicate whether the x or y image coordinates have been clipped */ +#define VV6410_STATUS1 0x0d + +/* Setup registers */ + +/* Low-power/sleep modes & video timing */ +#define VV6410_SETUP0 0x10 + +/* Various parameters */ +#define VV6410_SETUP1 0x11 + +/* Contains pixel counter reset value used by external sync */ +#define VV6410_SYNCVALUE 0x12 + +/* Frame grabbing modes (FST, LST and QCK) */ +#define VV6410_FGMODES 0x14 + +/* FST and QCK mapping modes. */ +#define VV6410_PINMAPPING 0x15 + +/* Data resolution */ +#define VV6410_DATAFORMAT 0x16 + +/* Output coding formats */ +#define VV6410_OPFORMAT 0x17 + +/* Various mode select bits */ +#define VV6410_MODESELECT 0x18 + +/* Exposure registers */ +/* Fine exposure. */ +#define VV6410_FINEH 0x20 +#define VV6410_FINEL 0x21 + +/* Coarse exposure */ +#define VV6410_COARSEH 0x22 +#define VV6410_COARSEL 0x23 + +/* Analog gain setting */ +#define VV6410_ANALOGGAIN 0x24 + +/* Clock division */ +#define VV6410_CLKDIV 0x25 + +/* Dark line offset cancellation value */ +#define VV6410_DARKOFFSETH 0x2c +#define VV6410_DARKOFFSETL 0x2d + +/* Dark line offset cancellation enable */ +#define VV6410_DARKOFFSETSETUP 0x2e + +/* Video timing registers */ +/* Line Length (Pixel Clocks) */ +#define VV6410_LINELENGTHH 0x52 +#define VV6410_LINELENGTHL 0x53 + +/* X-co-ordinate of top left corner of region of interest (x-offset) */ +#define VV6410_XOFFSETH 0x57 +#define VV6410_XOFFSETL 0x58 + +/* Y-coordinate of top left corner of region of interest (y-offset) */ +#define VV6410_YOFFSETH 0x59 +#define VV6410_YOFFSETL 0x5a + +/* Field length (Lines) */ +#define VV6410_FIELDLENGTHH 0x61 +#define VV6410_FIELDLENGTHL 0x62 + +/* System registers */ +/* Black offset cancellation default value */ +#define VV6410_BLACKOFFSETH 0x70 +#define VV6410_BLACKOFFSETL 0x71 + +/* Black offset cancellation setup */ +#define VV6410_BLACKOFFSETSETUP 0x72 + +/* Analog Control Register 0 */ +#define VV6410_CR0 0x75 + +/* Analog Control Register 1 */ +#define VV6410_CR1 0x76 + +/* ADC Setup Register */ +#define VV6410_AS0 0x77 + +/* Analog Test Register */ +#define VV6410_AT0 0x78 + +/* Audio Amplifier Setup Register */ +#define VV6410_AT1 0x79 + +#define VV6410_HFLIP (1 << 3) +#define VV6410_VFLIP (1 << 4) + +#define VV6410_LOW_POWER_MODE (1 << 0) +#define VV6410_SOFT_RESET (1 << 2) +#define VV6410_PAL_25_FPS (0 << 3) + +#define VV6410_CLK_DIV_2 (1 << 1) + +#define VV6410_FINE_EXPOSURE 320 +#define VV6410_COARSE_EXPOSURE 192 +#define VV6410_DEFAULT_GAIN 5 + +#define VV6410_SUBSAMPLE 0x01 +#define VV6410_CROP_TO_QVGA 0x02 + +#define VV6410_CIF_LINELENGTH 415 + +static int vv6410_probe(struct sd *sd); +static int vv6410_start(struct sd *sd); +static int vv6410_init(struct sd *sd); +static int vv6410_stop(struct sd *sd); +static int vv6410_dump(struct sd *sd); +static void vv6410_disconnect(struct sd *sd); + +/* V4L2 controls supported by the driver */ +static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val); +static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val); + +const struct stv06xx_sensor stv06xx_sensor_vv6410 = { + .name = "ST VV6410", + .i2c_flush = 5, + .i2c_addr = 0x20, + .i2c_len = 1, + /* FIXME (see if we can lower packet_size-s, needs testing, and also + adjusting framerate when the bandwidth gets lower) */ + .min_packet_size = { 1023 }, + .max_packet_size = { 1023 }, + .init = vv6410_init, + .probe = vv6410_probe, + .start = vv6410_start, + .stop = vv6410_stop, + .dump = vv6410_dump, + .disconnect = vv6410_disconnect, +}; + +/* If NULL, only single value to write, stored in len */ +struct stv_init { + const u8 *data; + u16 start; + u8 len; +}; + +static const u8 x1500[] = { /* 0x1500 - 0x150f */ + 0x0b, 0xa7, 0xb7, 0x00, 0x00 +}; + +static const u8 x1536[] = { /* 0x1536 - 0x153b */ + 0x02, 0x00, 0x60, 0x01, 0x20, 0x01 +}; + +static const struct stv_init stv_bridge_init[] = { + /* This reg is written twice. Some kind of reset? */ + {NULL, 0x1620, 0x80}, + {NULL, 0x1620, 0x00}, + {NULL, 0x1443, 0x00}, + {NULL, 0x1423, 0x04}, + {x1500, 0x1500, ARRAY_SIZE(x1500)}, + {x1536, 0x1536, ARRAY_SIZE(x1536)}, +}; + +static const u8 vv6410_sensor_init[][2] = { + /* Setup registers */ + {VV6410_SETUP0, VV6410_SOFT_RESET}, + {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, + /* Use shuffled read-out mode */ + {VV6410_SETUP1, BIT(6)}, + /* All modes to 1 */ + {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, + {VV6410_PINMAPPING, 0x00}, + /* Pre-clock generator divide off */ + {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, + + {VV6410_CLKDIV, VV6410_CLK_DIV_2}, + + /* System registers */ + /* Enable voltage doubler */ + {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, + {VV6410_AT0, 0x00}, + /* Power up audio, differential */ + {VV6410_AT1, BIT(4)|BIT(0)}, +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sunplus.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sunplus.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sunplus.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/sunplus.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1226 @@ +/* + * Sunplus spca504(abc) spca533 spca536 library + * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "sunplus" + +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + s8 brightness; + u8 contrast; + u8 colors; + u8 autogain; + u8 quality; +#define QUALITY_MIN 70 +#define QUALITY_MAX 95 +#define QUALITY_DEF 85 + + u8 bridge; +#define BRIDGE_SPCA504 0 +#define BRIDGE_SPCA504B 1 +#define BRIDGE_SPCA504C 2 +#define BRIDGE_SPCA533 3 +#define BRIDGE_SPCA536 4 + u8 subtype; +#define AiptekMiniPenCam13 1 +#define LogitechClickSmart420 2 +#define LogitechClickSmart820 3 +#define MegapixV4 4 +#define MegaImageVI 5 + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = -128, + .maximum = 127, + .step = 1, +#define BRIGHTNESS_DEF 0 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define CONTRAST_DEF 0x20 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define COLOR_DEF 0x1a + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +static const struct v4l2_pix_format custom_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 464, + .sizeimage = 464 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +static const struct v4l2_pix_format vga_mode2[] = { + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 4}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, +}; + +#define SPCA50X_OFFSET_DATA 10 +#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3 +#define SPCA504_PCCAM600_OFFSET_COMPRESS 4 +#define SPCA504_PCCAM600_OFFSET_MODE 5 +#define SPCA504_PCCAM600_OFFSET_DATA 14 + /* Frame packet header offsets for the spca533 */ +#define SPCA533_OFFSET_DATA 16 +#define SPCA533_OFFSET_FRAMSEQ 15 +/* Frame packet header offsets for the spca536 */ +#define SPCA536_OFFSET_DATA 4 +#define SPCA536_OFFSET_FRAMSEQ 1 + +struct cmd { + u8 req; + u16 val; + u16 idx; +}; + +/* Initialisation data for the Creative PC-CAM 600 */ +static const struct cmd spca504_pccam600_init_data[] = { +/* {0xa0, 0x0000, 0x0503}, * capture mode */ + {0x00, 0x0000, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, + {0x00, 0x0001, 0x21ac}, + {0x00, 0x0001, 0x21a6}, + {0x00, 0x0000, 0x21a7}, /* brightness */ + {0x00, 0x0020, 0x21a8}, /* contrast */ + {0x00, 0x0001, 0x21ac}, /* sat/hue */ + {0x00, 0x0000, 0x21ad}, /* hue */ + {0x00, 0x001a, 0x21ae}, /* saturation */ + {0x00, 0x0002, 0x21a3}, /* gamma */ + {0x30, 0x0154, 0x0008}, + {0x30, 0x0004, 0x0006}, + {0x30, 0x0258, 0x0009}, + {0x30, 0x0004, 0x0000}, + {0x30, 0x0093, 0x0004}, + {0x30, 0x0066, 0x0005}, + {0x00, 0x0000, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, +}; + +/* Creative PC-CAM 600 specific open data, sent before using the + * generic initialisation data from spca504_open_data. + */ +static const struct cmd spca504_pccam600_open_data[] = { + {0x00, 0x0001, 0x2501}, + {0x20, 0x0500, 0x0001}, /* snapshot mode */ + {0x00, 0x0003, 0x2880}, + {0x00, 0x0001, 0x2881}, +}; + +/* Initialisation data for the logitech clicksmart 420 */ +static const struct cmd spca504A_clicksmart420_init_data[] = { +/* {0xa0, 0x0000, 0x0503}, * capture mode */ + {0x00, 0x0000, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, + {0x00, 0x0001, 0x21ac}, + {0x00, 0x0001, 0x21a6}, + {0x00, 0x0000, 0x21a7}, /* brightness */ + {0x00, 0x0020, 0x21a8}, /* contrast */ + {0x00, 0x0001, 0x21ac}, /* sat/hue */ + {0x00, 0x0000, 0x21ad}, /* hue */ + {0x00, 0x001a, 0x21ae}, /* saturation */ + {0x00, 0x0002, 0x21a3}, /* gamma */ + {0x30, 0x0004, 0x000a}, + {0xb0, 0x0001, 0x0000}, + + + {0xa1, 0x0080, 0x0001}, + {0x30, 0x0049, 0x0000}, + {0x30, 0x0060, 0x0005}, + {0x0c, 0x0004, 0x0000}, + {0x00, 0x0000, 0x0000}, + {0x00, 0x0000, 0x2000}, + {0x00, 0x0013, 0x2301}, + {0x00, 0x0003, 0x2000}, + {0x00, 0x0000, 0x2000}, + +}; + +/* clicksmart 420 open data ? */ +static const struct cmd spca504A_clicksmart420_open_data[] = { + {0x00, 0x0001, 0x2501}, + {0x20, 0x0502, 0x0000}, + {0x06, 0x0000, 0x0000}, + {0x00, 0x0004, 0x2880}, + {0x00, 0x0001, 0x2881}, + + {0xa0, 0x0000, 0x0503}, +}; + +static const u8 qtable_creative_pccam[2][64] = { + { /* Q-table Y-components */ + 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, + 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, + 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, + 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, + 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, + 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, + 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, + 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e}, + { /* Q-table C-components */ + 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, + 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} +}; + +/* FIXME: This Q-table is identical to the Creative PC-CAM one, + * except for one byte. Possibly a typo? + * NWG: 18/05/2003. + */ +static const u8 qtable_spca504_default[2][64] = { + { /* Q-table Y-components */ + 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, + 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, + 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, + 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, + 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, + 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, + 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, + 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e, + }, + { /* Q-table C-components */ + 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, + 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} +}; + +/* read bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + u8 req, + u16 index, + u16 len) +{ + int ret; + +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_r: buffer overflow"); + return; + } +#endif + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + len ? gspca_dev->usb_buf : NULL, len, + 500); + if (ret < 0) { + err("reg_r err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* write one byte */ +static void reg_w_1(struct gspca_dev *gspca_dev, + u8 req, + u16 value, + u16 index, + u16 byte) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + gspca_dev->usb_buf[0] = byte; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, + gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { + err("reg_w_1 err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* write req / index / value */ +static void reg_w_riv(struct gspca_dev *gspca_dev, + u8 req, u16 index, u16 value) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + if (ret < 0) { + err("reg_w_riv err %d", ret); + gspca_dev->usb_err = ret; + return; + } + PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x", + req, index, value); +} + +static void write_vector(struct gspca_dev *gspca_dev, + const struct cmd *data, int ncmds) +{ + while (--ncmds >= 0) { + reg_w_riv(gspca_dev, data->req, data->idx, data->val); + data++; + } +} + +static void setup_qtable(struct gspca_dev *gspca_dev, + const u8 qtable[2][64]) +{ + int i; + + /* loop over y components */ + for (i = 0; i < 64; i++) + reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]); + + /* loop over c components */ + for (i = 0; i < 64; i++) + reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]); +} + +static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, + u8 req, u16 idx, u16 val) +{ + reg_w_riv(gspca_dev, req, idx, val); + reg_r(gspca_dev, 0x01, 0x0001, 1); + PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]); + reg_w_riv(gspca_dev, req, idx, val); + + msleep(200); + reg_r(gspca_dev, 0x01, 0x0001, 1); + PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]); +} + +#ifdef GSPCA_DEBUG +static void spca504_read_info(struct gspca_dev *gspca_dev) +{ + int i; + u8 info[6]; + + for (i = 0; i < 6; i++) { + reg_r(gspca_dev, 0, i, 1); + info[i] = gspca_dev->usb_buf[0]; + } + PDEBUG(D_STREAM, + "Read info: %d %d %d %d %d %d." + " Should be 1,0,2,2,0,0", + info[0], info[1], info[2], + info[3], info[4], info[5]); +} +#endif + +static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, + u8 req, + u16 idx, u16 val, u8 endcode, u8 count) +{ + u16 status; + + reg_w_riv(gspca_dev, req, idx, val); + reg_r(gspca_dev, 0x01, 0x0001, 1); + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x", + gspca_dev->usb_buf[0], endcode); + if (!count) + return; + count = 200; + while (--count > 0) { + msleep(10); + /* gsmart mini2 write a each wait setting 1 ms is enough */ +/* reg_w_riv(gspca_dev, req, idx, val); */ + reg_r(gspca_dev, 0x01, 0x0001, 1); + status = gspca_dev->usb_buf[0]; + if (status == endcode) { + PDEBUG(D_FRAM, "status 0x%04x after wait %d", + status, 200 - count); + break; + } + } +} + +static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev) +{ + int count = 10; + + while (--count > 0) { + reg_r(gspca_dev, 0x21, 0, 1); + if ((gspca_dev->usb_buf[0] & 0x01) == 0) + break; + msleep(10); + } +} + +static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) +{ + int count = 50; + + while (--count > 0) { + reg_r(gspca_dev, 0x21, 1, 1); + if (gspca_dev->usb_buf[0] != 0) { + reg_w_1(gspca_dev, 0x21, 0, 1, 0); + reg_r(gspca_dev, 0x21, 1, 1); + spca504B_PollingDataReady(gspca_dev); + break; + } + msleep(10); + } +} + +#ifdef GSPCA_DEBUG +static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) +{ + u8 *data; + + data = gspca_dev->usb_buf; + reg_r(gspca_dev, 0x20, 0, 5); + PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d", + data[0], data[1], data[2], data[3], data[4]); + reg_r(gspca_dev, 0x23, 0, 64); + reg_r(gspca_dev, 0x23, 1, 64); +} +#endif + +static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 Size; + + Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + switch (sd->bridge) { + case BRIDGE_SPCA533: + reg_w_riv(gspca_dev, 0x31, 0, 0); + spca504B_WaitCmdStatus(gspca_dev); + spca504B_PollingDataReady(gspca_dev); +#ifdef GSPCA_DEBUG + spca50x_GetFirmware(gspca_dev); +#endif + reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ + reg_r(gspca_dev, 0x24, 8, 1); + + reg_w_1(gspca_dev, 0x25, 0, 4, Size); + reg_r(gspca_dev, 0x25, 4, 1); /* size */ + spca504B_PollingDataReady(gspca_dev); + + /* Init the cam width height with some values get on init ? */ + reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00); + spca504B_WaitCmdStatus(gspca_dev); + spca504B_PollingDataReady(gspca_dev); + break; + default: +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA536: */ + reg_w_1(gspca_dev, 0x25, 0, 4, Size); + reg_r(gspca_dev, 0x25, 4, 1); /* size */ + reg_w_1(gspca_dev, 0x27, 0, 0, 6); + reg_r(gspca_dev, 0x27, 0, 1); /* type */ + spca504B_PollingDataReady(gspca_dev); + break; + case BRIDGE_SPCA504: + Size += 3; + if (sd->subtype == AiptekMiniPenCam13) { + /* spca504a aiptek */ + spca504A_acknowledged_command(gspca_dev, + 0x08, Size, 0, + 0x80 | (Size & 0x0f), 1); + spca504A_acknowledged_command(gspca_dev, + 1, 3, 0, 0x9f, 0); + } else { + spca504_acknowledged_command(gspca_dev, 0x08, Size, 0); + } + break; + case BRIDGE_SPCA504C: + /* capture mode */ + reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); + reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); + break; + } +} + +static void spca504_wait_status(struct gspca_dev *gspca_dev) +{ + int cnt; + + cnt = 256; + while (--cnt > 0) { + /* With this we get the status, when return 0 it's all ok */ + reg_r(gspca_dev, 0x06, 0x00, 1); + if (gspca_dev->usb_buf[0] == 0) + return; + msleep(10); + } +} + +static void spca504B_setQtable(struct gspca_dev *gspca_dev) +{ + reg_w_1(gspca_dev, 0x26, 0, 0, 3); + reg_r(gspca_dev, 0x26, 0, 1); + spca504B_PollingDataReady(gspca_dev); +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 reg; + + reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7; + reg_w_riv(gspca_dev, 0x00, reg, sd->brightness); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 reg; + + reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8; + reg_w_riv(gspca_dev, 0x00, reg, sd->contrast); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 reg; + + reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae; + reg_w_riv(gspca_dev, 0x00, reg, sd->colors); +} + +static void init_ctl_reg(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int pollreg = 1; + + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setcolors(gspca_dev); + + switch (sd->bridge) { + case BRIDGE_SPCA504: + case BRIDGE_SPCA504C: + pollreg = 0; + /* fall thru */ + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA504B: */ + reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */ + reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */ + reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */ + break; + case BRIDGE_SPCA536: + reg_w_riv(gspca_dev, 0, 0x20f5, 0x40); + reg_w_riv(gspca_dev, 0, 0x20f4, 0x01); + reg_w_riv(gspca_dev, 0, 0x2089, 0x00); + break; + } + if (pollreg) + spca504B_PollingDataReady(gspca_dev); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + + sd->bridge = id->driver_info >> 8; + sd->subtype = id->driver_info; + + if (sd->subtype == AiptekMiniPenCam13) { + + /* try to get the firmware as some cam answer 2.0.1.2.2 + * and should be a spca504b then overwrite that setting */ + reg_r(gspca_dev, 0x20, 0, 1); + switch (gspca_dev->usb_buf[0]) { + case 1: + break; /* (right bridge/subtype) */ + case 2: + sd->bridge = BRIDGE_SPCA504B; + sd->subtype = 0; + break; + default: + return -ENODEV; + } + } + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA536: */ + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + break; + case BRIDGE_SPCA533: + cam->cam_mode = custom_mode; + if (sd->subtype == MegaImageVI) /* 320x240 only */ + cam->nmodes = ARRAY_SIZE(custom_mode) - 1; + else + cam->nmodes = ARRAY_SIZE(custom_mode); + break; + case BRIDGE_SPCA504C: + cam->cam_mode = vga_mode2; + cam->nmodes = ARRAY_SIZE(vga_mode2); + break; + } + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->quality = QUALITY_DEF; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->bridge) { + case BRIDGE_SPCA504B: + reg_w_riv(gspca_dev, 0x1d, 0x00, 0); + reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01); + reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00); + reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00); + reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13); + reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00); + /* fall thru */ + case BRIDGE_SPCA533: + spca504B_PollingDataReady(gspca_dev); +#ifdef GSPCA_DEBUG + spca50x_GetFirmware(gspca_dev); +#endif + break; + case BRIDGE_SPCA536: +#ifdef GSPCA_DEBUG + spca50x_GetFirmware(gspca_dev); +#endif + reg_r(gspca_dev, 0x00, 0x5002, 1); + reg_w_1(gspca_dev, 0x24, 0, 0, 0); + reg_r(gspca_dev, 0x24, 0, 1); + spca504B_PollingDataReady(gspca_dev); + reg_w_riv(gspca_dev, 0x34, 0, 0); + spca504B_WaitCmdStatus(gspca_dev); + break; + case BRIDGE_SPCA504C: /* pccam600 */ + PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)"); + reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000); + reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */ + spca504_wait_status(gspca_dev); + if (sd->subtype == LogitechClickSmart420) + write_vector(gspca_dev, + spca504A_clicksmart420_open_data, + ARRAY_SIZE(spca504A_clicksmart420_open_data)); + else + write_vector(gspca_dev, spca504_pccam600_open_data, + ARRAY_SIZE(spca504_pccam600_open_data)); + setup_qtable(gspca_dev, qtable_creative_pccam); + break; + default: +/* case BRIDGE_SPCA504: */ + PDEBUG(D_STREAM, "Opening SPCA504"); + if (sd->subtype == AiptekMiniPenCam13) { +#ifdef GSPCA_DEBUG + spca504_read_info(gspca_dev); +#endif + + /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 8, 3, 0x9e, 1); + /* Twice sequential need status 0xff->0x9e->0x9d */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 8, 3, 0x9e, 0); + + spca504A_acknowledged_command(gspca_dev, 0x24, + 0, 0, 0x9d, 1); + /******************************/ + /* spca504a aiptek */ + spca504A_acknowledged_command(gspca_dev, 0x08, + 6, 0, 0x86, 1); +/* reg_write (dev, 0, 0x2000, 0); */ +/* reg_write (dev, 0, 0x2883, 1); */ +/* spca504A_acknowledged_command (gspca_dev, 0x08, + 6, 0, 0x86, 1); */ +/* spca504A_acknowledged_command (gspca_dev, 0x24, + 0, 0, 0x9D, 1); */ + reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); + /* L92 sno1t.txt */ + reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); + spca504A_acknowledged_command(gspca_dev, 0x01, + 0x0f, 0, 0xff, 0); + } + /* setup qtable */ + reg_w_riv(gspca_dev, 0, 0x2000, 0); + reg_w_riv(gspca_dev, 0, 0x2883, 1); + setup_qtable(gspca_dev, qtable_spca504_default); + break; + } + return gspca_dev->usb_err; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int enable; + + /* create the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x22); /* JPEG 411 */ + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + if (sd->bridge == BRIDGE_SPCA504B) + spca504B_setQtable(gspca_dev); + spca504B_SetSizeType(gspca_dev); + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA504B: */ +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA536: */ + switch (sd->subtype) { + case MegapixV4: + case LogitechClickSmart820: + case MegaImageVI: + reg_w_riv(gspca_dev, 0xf0, 0, 0); + spca504B_WaitCmdStatus(gspca_dev); + reg_r(gspca_dev, 0xf0, 4, 0); + spca504B_WaitCmdStatus(gspca_dev); + break; + default: + reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00); + spca504B_WaitCmdStatus(gspca_dev); + spca504B_PollingDataReady(gspca_dev); + break; + } + break; + case BRIDGE_SPCA504: + if (sd->subtype == AiptekMiniPenCam13) { +#ifdef GSPCA_DEBUG + spca504_read_info(gspca_dev); +#endif + + /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 8, 3, 0x9e, 1); + /* Twice sequential need status 0xff->0x9e->0x9d */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 8, 3, 0x9e, 0); + spca504A_acknowledged_command(gspca_dev, 0x24, + 0, 0, 0x9d, 1); + } else { + spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); +#ifdef GSPCA_DEBUG + spca504_read_info(gspca_dev); +#endif + spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); + spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); + } + spca504B_SetSizeType(gspca_dev); + reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); + /* L92 sno1t.txt */ + reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); + break; + case BRIDGE_SPCA504C: + if (sd->subtype == LogitechClickSmart420) { + write_vector(gspca_dev, + spca504A_clicksmart420_init_data, + ARRAY_SIZE(spca504A_clicksmart420_init_data)); + } else { + write_vector(gspca_dev, spca504_pccam600_init_data, + ARRAY_SIZE(spca504_pccam600_init_data)); + } + enable = (sd->autogain ? 0x04 : 0x01); + reg_w_riv(gspca_dev, 0x0c, 0x0000, enable); + /* auto exposure */ + reg_w_riv(gspca_dev, 0xb0, 0x0000, enable); + /* auto whiteness */ + + /* set default exposure compensation and whiteness balance */ + reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */ + reg_w_riv(gspca_dev, 0x30, 0x0002, 1600); + spca504B_SetSizeType(gspca_dev); + break; + } + init_ctl_reg(gspca_dev); + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->bridge) { + default: +/* case BRIDGE_SPCA533: */ +/* case BRIDGE_SPCA536: */ +/* case BRIDGE_SPCA504B: */ + reg_w_riv(gspca_dev, 0x31, 0, 0); + spca504B_WaitCmdStatus(gspca_dev); + spca504B_PollingDataReady(gspca_dev); + break; + case BRIDGE_SPCA504: + case BRIDGE_SPCA504C: + reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000); + + if (sd->subtype == AiptekMiniPenCam13) { + /* spca504a aiptek */ +/* spca504A_acknowledged_command(gspca_dev, 0x08, + 6, 0, 0x86, 1); */ + spca504A_acknowledged_command(gspca_dev, 0x24, + 0x00, 0x00, 0x9d, 1); + spca504A_acknowledged_command(gspca_dev, 0x01, + 0x0f, 0x00, 0xff, 1); + } else { + spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); + reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000); + } + break; + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, sof = 0; + static u8 ffd9[] = {0xff, 0xd9}; + +/* frames are jpeg 4.1.1 without 0xff escape */ + switch (sd->bridge) { + case BRIDGE_SPCA533: + if (data[0] == 0xff) { + if (data[1] != 0x01) { /* drop packet */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + } + sof = 1; + data += SPCA533_OFFSET_DATA; + len -= SPCA533_OFFSET_DATA; + } else { + data += 1; + len -= 1; + } + break; + case BRIDGE_SPCA536: + if (data[0] == 0xff) { + sof = 1; + data += SPCA536_OFFSET_DATA; + len -= SPCA536_OFFSET_DATA; + } else { + data += 2; + len -= 2; + } + break; + default: +/* case BRIDGE_SPCA504: */ +/* case BRIDGE_SPCA504B: */ + switch (data[0]) { + case 0xfe: /* start of frame */ + sof = 1; + data += SPCA50X_OFFSET_DATA; + len -= SPCA50X_OFFSET_DATA; + break; + case 0xff: /* drop packet */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + default: + data += 1; + len -= 1; + break; + } + break; + case BRIDGE_SPCA504C: + switch (data[0]) { + case 0xfe: /* start of frame */ + sof = 1; + data += SPCA504_PCCAM600_OFFSET_DATA; + len -= SPCA504_PCCAM600_OFFSET_DATA; + break; + case 0xff: /* drop packet */ +/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + return; + default: + data += 1; + len -= 1; + break; + } + break; + } + if (sof) { /* start of frame */ + gspca_frame_add(gspca_dev, LAST_PACKET, + ffd9, 2); + + /* put the JPEG header in the new frame */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + } + + /* add 0x00 after 0xff */ + i = 0; + do { + if (data[i] == 0xff) { + gspca_frame_add(gspca_dev, INTER_PACKET, + data, i + 1); + len -= i; + data += i; + *data = 0x00; + i = 0; + } + i++; + } while (i < len); + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + return 0; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (jcomp->quality < QUALITY_MIN) + sd->quality = QUALITY_MIN; + else if (jcomp->quality > QUALITY_MAX) + sd->quality = QUALITY_MAX; + else + sd->quality = jcomp->quality; + if (gspca_dev->streaming) + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + return gspca_dev->usb_err; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +}; + +/* -- module initialisation -- */ +#define BS(bridge, subtype) \ + .driver_info = (BRIDGE_ ## bridge << 8) \ + | (subtype) +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)}, + {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)}, + {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)}, + {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)}, + {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)}, + {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)}, + {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)}, + {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)}, + {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)}, + {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)}, + {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)}, + {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)}, + {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)}, + {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)}, + {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)}, + {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)}, + {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)}, + {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)}, + {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)}, + {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)}, + {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)}, + {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)}, + {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)}, + {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)}, + {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)}, + {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)}, + {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)}, + {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)}, + {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)}, + {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)}, + {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/t613.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/t613.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/t613.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/t613.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1450 @@ +/* + * T613 subdriver + * + * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr) + * + * 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, or + * any later version. + * + * 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 + * + *Notes: * t613 + tas5130A + * * Focus to light do not balance well as in win. + * Quality in win is not good, but its kinda better. + * * Fix some "extraneous bytes", most of apps will show the image anyway + * * Gamma table, is there, but its really doing something? + * * 7~8 Fps, its ok, max on win its 10. + * Costantino Leandro + */ + +#define MODULE_NAME "t613" + +#include +#include "gspca.h" + +#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0) + +MODULE_AUTHOR("Leandro Costantino "); +MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver"); +MODULE_LICENSE("GPL"); + +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u8 brightness; + u8 contrast; + u8 colors; + u8 autogain; + u8 gamma; + u8 sharpness; + u8 freq; + u8 red_gain; + u8 blue_gain; + u8 green_gain; + u8 awb; /* set default r/g/b and activate */ + u8 mirror; + u8 effect; + + u8 sensor; +}; +enum sensors { + SENSOR_OM6802, + SENSOR_OTHER, + SENSOR_TAS5130A, + SENSOR_LT168G, /* must verify if this is the actual model */ +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); + +static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); + +static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val); +static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 14, + .step = 1, +#define BRIGHTNESS_DEF 8 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0x0d, + .step = 1, +#define CONTRAST_DEF 0x07 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Color", + .minimum = 0, + .maximum = 0x0f, + .step = 1, +#define COLORS_DEF 0x05 + .default_value = COLORS_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +#define GAMMA_MAX 16 +#define GAMMA_DEF 10 + { + { + .id = V4L2_CID_GAMMA, /* (gamma on win) */ + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = 0, + .maximum = GAMMA_MAX - 1, + .step = 1, + .default_value = GAMMA_DEF, + }, + .set = sd_setgamma, + .get = sd_getgamma, + }, + { + { + .id = V4L2_CID_BACKLIGHT_COMPENSATION, /* Activa lowlight, + * some apps dont bring up the + * backligth_compensation control) */ + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Low Light", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 0x01 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setlowlight, + .get = sd_getlowlight, + }, + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Image", + .minimum = 0, + .maximum = 1, + .step = 1, +#define MIRROR_DEF 0 + .default_value = MIRROR_DEF, + }, + .set = sd_setmirror, + .get = sd_getmirror + }, + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light Frequency Filter", + .minimum = 1, /* 1 -> 0x50, 2->0x60 */ + .maximum = 2, + .step = 1, +#define FREQ_DEF 1 + .default_value = FREQ_DEF, + }, + .set = sd_setfreq, + .get = sd_getfreq}, + + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Auto White Balance", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AWB_DEF 0 + .default_value = AWB_DEF, + }, + .set = sd_setawb, + .get = sd_getawb + }, + { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 15, + .step = 1, +#define SHARPNESS_DEF 0x06 + .default_value = SHARPNESS_DEF, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, + { + { + .id = V4L2_CID_EFFECTS, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Webcam Effects", + .minimum = 0, + .maximum = 4, + .step = 1, +#define EFFECTS_DEF 0 + .default_value = EFFECTS_DEF, + }, + .set = sd_seteffect, + .get = sd_geteffect + }, + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0x10, + .maximum = 0x40, + .step = 1, +#define BLUE_GAIN_DEF 0x20 + .default_value = BLUE_GAIN_DEF, + }, + .set = sd_setblue_gain, + .get = sd_getblue_gain, + }, + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0x10, + .maximum = 0x40, + .step = 1, +#define RED_GAIN_DEF 0x20 + .default_value = RED_GAIN_DEF, + }, + .set = sd_setred_gain, + .get = sd_getred_gain, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0x10, + .maximum = 0x40, + .step = 1, +#define GAIN_DEF 0x20 + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static const struct v4l2_pix_format vga_mode_t16[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 4}, + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* sensor specific data */ +struct additional_sensor_data { + const u8 n3[6]; + const u8 *n4, n4sz; + const u8 reg80, reg8e; + const u8 nset8[6]; + const u8 data1[10]; + const u8 data2[9]; + const u8 data3[9]; + const u8 data5[6]; + const u8 stream[4]; +}; + +static const u8 n4_om6802[] = { + 0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c, + 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68, + 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1, + 0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8, + 0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48, + 0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0, + 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68, + 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40, + 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46 +}; +static const u8 n4_other[] = { + 0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69, + 0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68, + 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8, + 0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8, + 0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56, + 0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5, + 0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0, + 0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00 +}; +static const u8 n4_tas5130a[] = { + 0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20, + 0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4, + 0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10, + 0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08, + 0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a, + 0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8, + 0xc6, 0xda +}; +static const u8 n4_lt168g[] = { + 0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28, + 0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70, + 0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3, + 0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20, + 0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68, + 0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40, + 0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0, + 0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c, + 0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80 +}; + +static const struct additional_sensor_data sensor_data[] = { +[SENSOR_OM6802] = { + .n3 = + {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04}, + .n4 = n4_om6802, + .n4sz = sizeof n4_om6802, + .reg80 = 0x3c, + .reg8e = 0x33, + .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00}, + .data1 = + {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06, + 0xb3, 0xfc}, + .data2 = + {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff, + 0xff}, + .data3 = + {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff, + 0xff}, + .data5 = /* this could be removed later */ + {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23}, + .stream = + {0x0b, 0x04, 0x0a, 0x78}, + }, +[SENSOR_OTHER] = { + .n3 = + {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00}, + .n4 = n4_other, + .n4sz = sizeof n4_other, + .reg80 = 0xac, + .reg8e = 0xb8, + .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00}, + .data1 = + {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a, + 0xe8, 0xfc}, + .data2 = + {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96, + 0xd9}, + .data3 = + {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96, + 0xd9}, + .data5 = + {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69}, + .stream = + {0x0b, 0x04, 0x0a, 0x00}, + }, +[SENSOR_TAS5130A] = { + .n3 = + {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08}, + .n4 = n4_tas5130a, + .n4sz = sizeof n4_tas5130a, + .reg80 = 0x3c, + .reg8e = 0xb4, + .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00}, + .data1 = + {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27, + 0xc8, 0xfc}, + .data2 = + {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8, + 0xe0}, + .data3 = + {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8, + 0xe0}, + .data5 = + {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20}, + .stream = + {0x0b, 0x04, 0x0a, 0x40}, + }, +[SENSOR_LT168G] = { + .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00}, + .n4 = n4_lt168g, + .n4sz = sizeof n4_lt168g, + .reg80 = 0x7c, + .reg8e = 0xb3, + .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00}, + .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40, + 0xb0, 0xf4}, + .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6, + 0xff}, + .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6, + 0xff}, + .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b}, + .stream = {0x0b, 0x04, 0x0a, 0x28}, + }, +}; + +#define MAX_EFFECTS 7 +/* easily done by soft, this table could be removed, + * i keep it here just in case */ +static char *effects_control[MAX_EFFECTS] = { + "Normal", + "Emboss", /* disabled */ + "Monochrome", + "Sepia", + "Sketch", + "Sun Effect", /* disabled */ + "Negative", +}; +static const u8 effects_table[MAX_EFFECTS][6] = { + {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */ + {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */ + {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20}, /* Monochrome */ + {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80}, /* Sepia */ + {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02}, /* Croquis */ + {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10}, /* Sun Effect */ + {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */ +}; + +static const u8 gamma_table[GAMMA_MAX][17] = { +/* gamma table from cam1690.ini */ + {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */ + 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb, + 0xff}, + {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */ + 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1, + 0xff}, + {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */ + 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3, + 0xff}, + {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */ + 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6, + 0xff}, + {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */ + 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9, + 0xff}, + {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */ + 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec, + 0xff}, + {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */ + 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff}, + {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */ + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0xff}, + {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */ + 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0, + 0xff}, + {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */ + 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2, + 0xff}, + {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */ + 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3, + 0xff}, + {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */ + 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5, + 0xff}, + {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */ + 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6, + 0xff}, + {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7, /* 13 */ + 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9, + 0xff}, + {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6, /* 14 */ + 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa, + 0xff}, + {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8, /* 15 */ + 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc, + 0xff} +}; + +static const u8 tas5130a_sensor_init[][8] = { + {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09}, + {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09}, + {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}, +}; + +static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07}; + +/* read 1 byte */ +static u8 reg_r(struct gspca_dev *gspca_dev, + u16 index) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, + gspca_dev->usb_buf, 1, 500); + return gspca_dev->usb_buf[0]; +} + +static void reg_w(struct gspca_dev *gspca_dev, + u16 index) +{ + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, + NULL, 0, 500); +} + +static void reg_w_buf(struct gspca_dev *gspca_dev, + const u8 *buffer, u16 len) +{ + if (len <= USB_BUF_SZ) { + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x01, 0, + gspca_dev->usb_buf, len, 500); + } else { + u8 *tmpbuf; + + tmpbuf = kmemdup(buffer, len, GFP_KERNEL); + if (!tmpbuf) { + err("Out of memory"); + return; + } + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x01, 0, + tmpbuf, len, 500); + kfree(tmpbuf); + } +} + +/* write values to consecutive registers */ +static void reg_w_ixbuf(struct gspca_dev *gspca_dev, + u8 reg, + const u8 *buffer, u16 len) +{ + int i; + u8 *p, *tmpbuf; + + if (len * 2 <= USB_BUF_SZ) { + p = tmpbuf = gspca_dev->usb_buf; + } else { + p = tmpbuf = kmalloc(len * 2, GFP_KERNEL); + if (!tmpbuf) { + err("Out of memory"); + return; + } + } + i = len; + while (--i >= 0) { + *p++ = reg++; + *p++ = *buffer++; + } + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x01, 0, + tmpbuf, len * 2, 500); + if (len * 2 > USB_BUF_SZ) + kfree(tmpbuf); +} + +static void om6802_sensor_init(struct gspca_dev *gspca_dev) +{ + int i; + const u8 *p; + u8 byte; + u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05}; + static const u8 sensor_init[] = { + 0xdf, 0x6d, + 0xdd, 0x18, + 0x5a, 0xe0, + 0x5c, 0x07, + 0x5d, 0xb0, + 0x5e, 0x1e, + 0x60, 0x71, + 0xef, 0x00, + 0xe9, 0x00, + 0xea, 0x00, + 0x90, 0x24, + 0x91, 0xb2, + 0x82, 0x32, + 0xfd, 0x41, + 0x00 /* table end */ + }; + + reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset); + msleep(100); + i = 4; + while (--i > 0) { + byte = reg_r(gspca_dev, 0x0060); + if (!(byte & 0x01)) + break; + msleep(100); + } + byte = reg_r(gspca_dev, 0x0063); + if (byte != 0x17) { + err("Bad sensor reset %02x", byte); + /* continue? */ + } + + p = sensor_init; + while (*p != 0) { + val[1] = *p++; + val[3] = *p++; + if (*p == 0) + reg_w(gspca_dev, 0x3c80); + reg_w_buf(gspca_dev, val, sizeof val); + i = 4; + while (--i >= 0) { + msleep(15); + byte = reg_r(gspca_dev, 0x60); + if (!(byte & 0x01)) + break; + } + } + msleep(15); + reg_w(gspca_dev, 0x3c80); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + + cam->cam_mode = vga_mode_t16; + cam->nmodes = ARRAY_SIZE(vga_mode_t16); + + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLORS_DEF; + sd->gamma = GAMMA_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->mirror = MIRROR_DEF; + sd->freq = FREQ_DEF; + sd->awb = AWB_DEF; + sd->sharpness = SHARPNESS_DEF; + sd->effect = EFFECTS_DEF; + sd->red_gain = RED_GAIN_DEF; + sd->blue_gain = BLUE_GAIN_DEF; + sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF; + + return 0; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned int brightness; + u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 }; + + brightness = sd->brightness; + if (brightness < 7) { + set6[1] = 0x26; + set6[3] = 0x70 - brightness * 0x10; + } else { + set6[3] = 0x00 + ((brightness - 7) * 0x10); + } + + reg_w_buf(gspca_dev, set6, sizeof set6); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned int contrast = sd->contrast; + u16 reg_to_write; + + if (contrast < 7) + reg_to_write = 0x8ea9 - contrast * 0x200; + else + reg_to_write = 0x00a9 + (contrast - 7) * 0x200; + + reg_w(gspca_dev, reg_to_write); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 reg_to_write; + + reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */ + reg_w(gspca_dev, reg_to_write); +} + +static void setgamma(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(D_CONF, "Gamma: %d", sd->gamma); + reg_w_ixbuf(gspca_dev, 0x90, + gamma_table[sd->gamma], sizeof gamma_table[0]); +} + +static void setRGB(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 all_gain_reg[6] = + {0x87, 0x00, 0x88, 0x00, 0x89, 0x00}; + + all_gain_reg[1] = sd->red_gain; + all_gain_reg[3] = sd->blue_gain; + all_gain_reg[5] = sd->green_gain; + reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg); +} + +/* Generic fnc for r/b balance, exposure and awb */ +static void setawb(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 reg80; + + reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80; + + /* on awb leave defaults values */ + if (!sd->awb) { + /* shoud we wait here.. */ + /* update and reset RGB gains with webcam values */ + sd->red_gain = reg_r(gspca_dev, 0x0087); + sd->blue_gain = reg_r(gspca_dev, 0x0088); + sd->green_gain = reg_r(gspca_dev, 0x0089); + reg80 &= ~0x0400; /* AWB off */ + } + reg_w(gspca_dev, reg80); + reg_w(gspca_dev, reg80); +} + +static void init_gains(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 reg80; + u8 all_gain_reg[8] = + {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00}; + + all_gain_reg[1] = sd->red_gain; + all_gain_reg[3] = sd->blue_gain; + all_gain_reg[5] = sd->green_gain; + reg80 = sensor_data[sd->sensor].reg80; + if (!sd->awb) + reg80 &= ~0x04; + all_gain_reg[7] = reg80; + reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg); + + reg_w(gspca_dev, (sd->red_gain << 8) + 0x87); + reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88); + reg_w(gspca_dev, (sd->green_gain << 8) + 0x89); +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 reg_to_write; + + reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness; + + reg_w(gspca_dev, reg_to_write); +} + +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 reg66; + u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 }; + + switch (sd->sensor) { + case SENSOR_LT168G: + if (sd->freq != 0) + freq[3] = 0xa8; + reg66 = 0x41; + break; + case SENSOR_OM6802: + reg66 = 0xca; + break; + default: + reg66 = 0x40; + break; + } + switch (sd->freq) { + case 0: /* no flicker */ + freq[3] = 0xf0; + break; + case 2: /* 60Hz */ + reg66 &= ~0x40; + break; + } + freq[1] = reg66; + + reg_w_buf(gspca_dev, freq, sizeof freq); +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + /* some of this registers are not really neded, because + * they are overriden by setbrigthness, setcontrast, etc, + * but wont hurt anyway, and can help someone with similar webcam + * to see the initial parameters.*/ + struct sd *sd = (struct sd *) gspca_dev; + const struct additional_sensor_data *sensor; + int i; + u16 sensor_id; + u8 test_byte = 0; + + static const u8 read_indexs[] = + { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5, + 0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 }; + static const u8 n1[] = + {0x08, 0x03, 0x09, 0x03, 0x12, 0x04}; + static const u8 n2[] = + {0x08, 0x00}; + + sensor_id = (reg_r(gspca_dev, 0x06) << 8) + | reg_r(gspca_dev, 0x07); + switch (sensor_id & 0xff0f) { + case 0x0801: + PDEBUG(D_PROBE, "sensor tas5130a"); + sd->sensor = SENSOR_TAS5130A; + break; + case 0x0802: + PDEBUG(D_PROBE, "sensor lt168g"); + sd->sensor = SENSOR_LT168G; + break; + case 0x0803: + PDEBUG(D_PROBE, "sensor 'other'"); + sd->sensor = SENSOR_OTHER; + break; + case 0x0807: + PDEBUG(D_PROBE, "sensor om6802"); + sd->sensor = SENSOR_OM6802; + break; + default: + err("unknown sensor %04x", sensor_id); + return -EINVAL; + } + + if (sd->sensor == SENSOR_OM6802) { + reg_w_buf(gspca_dev, n1, sizeof n1); + i = 5; + while (--i >= 0) { + reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset); + test_byte = reg_r(gspca_dev, 0x0063); + msleep(100); + if (test_byte == 0x17) + break; /* OK */ + } + if (i < 0) { + err("Bad sensor reset %02x", test_byte); + return -EIO; + } + reg_w_buf(gspca_dev, n2, sizeof n2); + } + + i = 0; + while (read_indexs[i] != 0x00) { + test_byte = reg_r(gspca_dev, read_indexs[i]); + PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i], + test_byte); + i++; + } + + sensor = &sensor_data[sd->sensor]; + reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3); + reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz); + + if (sd->sensor == SENSOR_LT168G) { + test_byte = reg_r(gspca_dev, 0x80); + PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80, + test_byte); + reg_w(gspca_dev, 0x6c80); + } + + reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1); + reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2); + reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3); + + reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80); + reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80); + reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e); + + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setgamma(gspca_dev); + setcolors(gspca_dev); + setsharpness(gspca_dev); + init_gains(gspca_dev); + setfreq(gspca_dev); + + reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5); + reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8); + reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); + + if (sd->sensor == SENSOR_LT168G) { + test_byte = reg_r(gspca_dev, 0x80); + PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", 0x80, + test_byte); + reg_w(gspca_dev, 0x6c80); + } + + reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1); + reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2); + reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3); + + return 0; +} + +static void setmirror(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 hflipcmd[8] = + {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}; + + if (sd->mirror) + hflipcmd[3] = 0x01; + + reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd); +} + +static void seteffect(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w_buf(gspca_dev, effects_table[sd->effect], + sizeof effects_table[0]); + if (sd->effect == 1 || sd->effect == 5) { + PDEBUG(D_CONF, + "This effect have been disabled for webcam \"safety\""); + return; + } + + if (sd->effect == 1 || sd->effect == 4) + reg_w(gspca_dev, 0x4aa6); + else + reg_w(gspca_dev, 0xfaa6); +} + +/* Is this really needed? + * i added some module parameters for test with some users */ +static void poll_sensor(struct gspca_dev *gspca_dev) +{ + static const u8 poll1[] = + {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82, + 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34, + 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01, + 0x60, 0x14}; + static const u8 poll2[] = + {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9, + 0x73, 0x02, 0x73, 0x02, 0x60, 0x14}; + static const u8 noise03[] = /* (some differences / ms-drv) */ + {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f, + 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c, + 0xc2, 0x80, 0xc3, 0x10}; + + PDEBUG(D_STREAM, "[Sensor requires polling]"); + reg_w_buf(gspca_dev, poll1, sizeof poll1); + reg_w_buf(gspca_dev, poll2, sizeof poll2); + reg_w_buf(gspca_dev, noise03, sizeof noise03); +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + const struct additional_sensor_data *sensor; + int i, mode; + u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 }; + static const u8 t3[] = + { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 }; + + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + switch (mode) { + case 0: /* 640x480 (0x00) */ + break; + case 1: /* 352x288 */ + t2[1] = 0x40; + break; + case 2: /* 320x240 */ + t2[1] = 0x10; + break; + case 3: /* 176x144 */ + t2[1] = 0x50; + break; + default: +/* case 4: * 160x120 */ + t2[1] = 0x20; + break; + } + + switch (sd->sensor) { + case SENSOR_OM6802: + om6802_sensor_init(gspca_dev); + break; + case SENSOR_TAS5130A: + i = 0; + for (;;) { + reg_w_buf(gspca_dev, tas5130a_sensor_init[i], + sizeof tas5130a_sensor_init[0]); + if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1) + break; + i++; + } + reg_w(gspca_dev, 0x3c80); + /* just in case and to keep sync with logs (for mine) */ + reg_w_buf(gspca_dev, tas5130a_sensor_init[i], + sizeof tas5130a_sensor_init[0]); + reg_w(gspca_dev, 0x3c80); + break; + } + sensor = &sensor_data[sd->sensor]; + setfreq(gspca_dev); + reg_r(gspca_dev, 0x0012); + reg_w_buf(gspca_dev, t2, sizeof t2); + reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3); + reg_w(gspca_dev, 0x0013); + msleep(15); + reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); + reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream); + + if (sd->sensor == SENSOR_OM6802) + poll_sensor(gspca_dev); + + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream, + sizeof sensor_data[sd->sensor].stream); + reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream, + sizeof sensor_data[sd->sensor].stream); + if (sd->sensor == SENSOR_OM6802) { + msleep(20); + reg_w(gspca_dev, 0x0309); + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + int pkt_type; + + if (data[0] == 0x5a) { + /* Control Packet, after this came the header again, + * but extra bytes came in the packet before this, + * sometimes an EOF arrives, sometimes not... */ + return; + } + data += 2; + len -= 2; + if (data[0] == 0xff && data[1] == 0xd8) + pkt_type = FIRST_PACKET; + else if (data[len - 2] == 0xff && data[len - 1] == 0xd9) + pkt_type = LAST_PACKET; + else + pkt_type = INTER_PACKET; + gspca_frame_add(gspca_dev, pkt_type, data, len); +} + +static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->blue_gain = val; + if (gspca_dev->streaming) + reg_w(gspca_dev, (val << 8) + 0x88); + return 0; +} + +static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->blue_gain; + return 0; +} + +static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->red_gain = val; + if (gspca_dev->streaming) + reg_w(gspca_dev, (val << 8) + 0x87); + + return 0; +} + +static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->red_gain; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 psg, nsg; + + psg = sd->red_gain + sd->blue_gain + sd->green_gain; + nsg = val * 3; + sd->red_gain = sd->red_gain * nsg / psg; + if (sd->red_gain > 0x40) + sd->red_gain = 0x40; + else if (sd->red_gain < 0x10) + sd->red_gain = 0x10; + sd->blue_gain = sd->blue_gain * nsg / psg; + if (sd->blue_gain > 0x40) + sd->blue_gain = 0x40; + else if (sd->blue_gain < 0x10) + sd->blue_gain = 0x10; + sd->green_gain = sd->green_gain * nsg / psg; + if (sd->green_gain > 0x40) + sd->green_gain = 0x40; + else if (sd->green_gain < 0x10) + sd->green_gain = 0x10; + + if (gspca_dev->streaming) + setRGB(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3; + return 0; +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return *val; +} + +static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->awb = val; + if (gspca_dev->streaming) + setawb(gspca_dev); + return 0; +} + +static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->awb; + return *val; +} + +static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->mirror = val; + if (gspca_dev->streaming) + setmirror(gspca_dev); + return 0; +} + +static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->mirror; + return *val; +} + +static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->effect = val; + if (gspca_dev->streaming) + seteffect(gspca_dev); + return 0; +} + +static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->effect; + return *val; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return *val; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return 0; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gamma = val; + if (gspca_dev->streaming) + setgamma(gspca_dev); + return 0; +} + +static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gamma; + return 0; +} + +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->freq = val; + if (gspca_dev->streaming) + setfreq(gspca_dev); + return 0; +} + +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->freq; + return 0; +} + +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) + setsharpness(gspca_dev); + return 0; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + return 0; +} + +/* Low Light set here......*/ +static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (val != 0) + reg_w(gspca_dev, 0xf48e); + else + reg_w(gspca_dev, 0xb48e); + return 0; +} + +static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; + + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm)) + break; + strcpy((char *) menu->name, freq_nm[menu->index]); + return 0; + case V4L2_CID_EFFECTS: + if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { + strncpy((char *) menu->name, + effects_control[menu->index], + sizeof menu->name); + return 0; + } + break; + } + return -EINVAL; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x17a1, 0x0128)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/tv8532.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/tv8532.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/tv8532.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/tv8532.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,433 @@ +/* + * Quickcam cameras initialization data + * + * V4L2 by Jean-Francois Moine + * + * 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, or + * any later version. + * + * 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 + * + */ +#define MODULE_NAME "tv8532" + +#include "gspca.h" + +MODULE_AUTHOR("Michel Xhaard "); +MODULE_DESCRIPTION("TV8532 USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + __u16 exposure; + __u16 gain; + + __u8 packet; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 1, + .maximum = 0x18f, + .step = 1, +#define EXPOSURE_DEF 0x18f + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 0x7ff, + .step = 1, +#define GAIN_DEF 0x100 + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static const struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* TV-8532A (ICM532A) registers (LE) */ +#define R00_PART_CONTROL 0x00 +#define LATENT_CHANGE 0x80 +#define EXPO_CHANGE 0x04 +#define R01_TIMING_CONTROL_LOW 0x01 +#define CMD_EEprom_Open 0x30 +#define CMD_EEprom_Close 0x29 +#define R03_TABLE_ADDR 0x03 +#define R04_WTRAM_DATA_L 0x04 +#define R05_WTRAM_DATA_M 0x05 +#define R06_WTRAM_DATA_H 0x06 +#define R07_TABLE_LEN 0x07 +#define R08_RAM_WRITE_ACTION 0x08 +#define R0C_AD_WIDTHL 0x0c +#define R0D_AD_WIDTHH 0x0d +#define R0E_AD_HEIGHTL 0x0e +#define R0F_AD_HEIGHTH 0x0f +#define R10_AD_COL_BEGINL 0x10 +#define R11_AD_COL_BEGINH 0x11 +#define MIRROR 0x04 /* [10] */ +#define R14_AD_ROW_BEGINL 0x14 +#define R15_AD_ROWBEGINH 0x15 +#define R1C_AD_EXPOSE_TIMEL 0x1c +#define R20_GAIN_G1L 0x20 +#define R21_GAIN_G1H 0x21 +#define R22_GAIN_RL 0x22 +#define R23_GAIN_RH 0x23 +#define R24_GAIN_BL 0x24 +#define R25_GAIN_BH 0x25 +#define R26_GAIN_G2L 0x26 +#define R27_GAIN_G2H 0x27 +#define R28_QUANT 0x28 +#define R29_LINE 0x29 +#define R2C_POLARITY 0x2c +#define R2D_POINT 0x2d +#define R2E_POINTH 0x2e +#define R2F_POINTB 0x2f +#define R30_POINTBH 0x30 +#define R31_UPD 0x31 +#define R2A_HIGH_BUDGET 0x2a +#define R2B_LOW_BUDGET 0x2b +#define R34_VID 0x34 +#define R35_VIDH 0x35 +#define R36_PID 0x36 +#define R37_PIDH 0x37 +#define R39_Test1 0x39 /* GPIO */ +#define R3B_Test3 0x3b /* GPIO */ +#define R83_AD_IDH 0x83 +#define R91_AD_SLOPEREG 0x91 +#define R94_AD_BITCONTROL 0x94 + +static const u8 eeprom_data[][3] = { +/* dataH dataM dataL */ + {0x01, 0x00, 0x01}, + {0x01, 0x80, 0x11}, + {0x05, 0x00, 0x14}, + {0x05, 0x00, 0x1c}, + {0x0d, 0x00, 0x1e}, + {0x05, 0x00, 0x1f}, + {0x05, 0x05, 0x19}, + {0x05, 0x01, 0x1b}, + {0x05, 0x09, 0x1e}, + {0x0d, 0x89, 0x2e}, + {0x05, 0x89, 0x2f}, + {0x05, 0x0d, 0xd9}, + {0x05, 0x09, 0xf1}, +}; + + +/* write 1 byte */ +static void reg_w1(struct gspca_dev *gspca_dev, + __u16 index, __u8 value) +{ + gspca_dev->usb_buf[0] = value; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x02, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, 1, 500); +} + +/* write 2 bytes */ +static void reg_w2(struct gspca_dev *gspca_dev, + u16 index, u16 value) +{ + gspca_dev->usb_buf[0] = value; + gspca_dev->usb_buf[1] = value >> 8; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x02, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, 2, 500); +} + +static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev) +{ + int i; + + reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Open); + for (i = 0; i < ARRAY_SIZE(eeprom_data); i++) { + reg_w1(gspca_dev, R03_TABLE_ADDR, i); + reg_w1(gspca_dev, R04_WTRAM_DATA_L, eeprom_data[i][2]); + reg_w1(gspca_dev, R05_WTRAM_DATA_M, eeprom_data[i][1]); + reg_w1(gspca_dev, R06_WTRAM_DATA_H, eeprom_data[i][0]); + reg_w1(gspca_dev, R08_RAM_WRITE_ACTION, 0); + } + reg_w1(gspca_dev, R07_TABLE_LEN, i); + reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + cam = &gspca_dev->cam; + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + + sd->exposure = EXPOSURE_DEF; + sd->gain = GAIN_DEF; + return 0; +} + +static void tv_8532_setReg(struct gspca_dev *gspca_dev) +{ + reg_w1(gspca_dev, R3B_Test3, 0x0a); /* Test0Sel = 10 */ + /******************************************************/ + reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90); + reg_w1(gspca_dev, R0F_AD_HEIGHTH, 0x01); + reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f); + reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44); + /* begin active line */ + reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00); + /* mirror and digital gain */ + reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a); + + reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02); + reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00); + reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); + /* = 0x84 */ +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + tv_8532WriteEEprom(gspca_dev); + + return 0; +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->exposure); + reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); + /* 0x84 */ +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w2(gspca_dev, R20_GAIN_G1L, sd->gain); + reg_w2(gspca_dev, R22_GAIN_RL, sd->gain); + reg_w2(gspca_dev, R24_GAIN_BL, sd->gain); + reg_w2(gspca_dev, R26_GAIN_G2L, sd->gain); +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); /* 0x20; 0x0c */ + reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03); + + /************************************************/ + reg_w1(gspca_dev, R28_QUANT, 0x90); + /* 0x72 compressed mode 0x28 */ + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { + /* 176x144 */ + reg_w1(gspca_dev, R29_LINE, 0x41); + /* CIF - 2 lines/packet */ + } else { + /* 352x288 */ + reg_w1(gspca_dev, R29_LINE, 0x81); + /* CIF - 2 lines/packet */ + } + /************************************************/ + reg_w1(gspca_dev, R2C_POLARITY, 0x10); /* slow clock */ + reg_w1(gspca_dev, R2D_POINT, 0x14); + reg_w1(gspca_dev, R2E_POINTH, 0x01); + reg_w1(gspca_dev, R2F_POINTB, 0x12); + reg_w1(gspca_dev, R30_POINTBH, 0x01); + + tv_8532_setReg(gspca_dev); + + setexposure(gspca_dev); + setgain(gspca_dev); + + /************************************************/ + reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */ + msleep(200); + reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */ + + gspca_dev->empty_packet = 0; /* check the empty packets */ + sd->packet = 0; /* ignore the first packets */ + + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */ +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int packet_type0, packet_type1; + + packet_type0 = packet_type1 = INTER_PACKET; + if (gspca_dev->empty_packet) { + gspca_dev->empty_packet = 0; + sd->packet = gspca_dev->height / 2; + packet_type0 = FIRST_PACKET; + } else if (sd->packet == 0) + return; /* 2 more lines in 352x288 ! */ + sd->packet--; + if (sd->packet == 0) + packet_type1 = LAST_PACKET; + + /* each packet contains: + * - header 2 bytes + * - RGRG line + * - 4 bytes + * - GBGB line + * - 4 bytes + */ + gspca_frame_add(gspca_dev, packet_type0, + data + 2, gspca_dev->width); + gspca_frame_add(gspca_dev, packet_type1, + data + gspca_dev->width + 5, gspca_dev->width); +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x046d, 0x0920)}, + {USB_DEVICE(0x046d, 0x0921)}, + {USB_DEVICE(0x0545, 0x808b)}, + {USB_DEVICE(0x0545, 0x8333)}, + {USB_DEVICE(0x0923, 0x010f)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/vc032x.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/vc032x.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/vc032x.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/vc032x.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,4243 @@ +/* + * Z-star vc0321 library + * + * Copyright (C) 2009-2010 Jean-François Moine + * Copyright (C) 2006 Koninski Artur takeshi87@o2.pl + * Copyright (C) 2006 Michel Xhaard + * + * 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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "vc032x" + +#include "gspca.h" + +MODULE_AUTHOR("Jean-François Moine "); +MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + u8 brightness; + u8 contrast; + u8 colors; + u8 hflip; + u8 vflip; + u8 lightfreq; + s8 sharpness; + u16 exposure; + u8 gain; + u8 autogain; + u8 backlight; + + u8 image_offset; + + u8 bridge; + u8 sensor; + u8 flags; +#define FL_SAMSUNG 0x01 /* SamsungQ1 (2 sensors) */ +#define FL_HFLIP 0x02 /* mirrored by default */ +#define FL_VFLIP 0x04 /* vertical flipped by default */ +}; +enum bridges { + BRIDGE_VC0321, + BRIDGE_VC0323, +}; +enum sensors { + SENSOR_HV7131R, + SENSOR_MI0360, + SENSOR_MI1310_SOC, + SENSOR_MI1320, + SENSOR_MI1320_SOC, + SENSOR_OV7660, + SENSOR_OV7670, + SENSOR_PO1200, + SENSOR_PO3130NC, + SENSOR_POxxxx, + NSENSORS +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setbacklight(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbacklight(struct gspca_dev *gspca_dev, __s32 *val); + +static const struct ctrl sd_ctrls[] = { +#define BRIGHTNESS_IDX 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, +#define BRIGHTNESS_DEF 128 + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define CONTRAST_IDX 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, +#define CONTRAST_DEF 127 + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define COLORS_IDX 2 + { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 1, + .maximum = 127, + .step = 1, +#define COLOR_DEF 63 + .default_value = COLOR_DEF, + }, + .set = sd_setcolors, + .get = sd_getcolors, + }, +/* next 2 controls work with some sensors only */ +#define HFLIP_IDX 3 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, +#define HFLIP_DEF 0 + .default_value = HFLIP_DEF, + }, + .set = sd_sethflip, + .get = sd_gethflip, + }, +#define VFLIP_IDX 4 + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define VFLIP_DEF 0 + .default_value = VFLIP_DEF, + }, + .set = sd_setvflip, + .get = sd_getvflip, + }, +#define LIGHTFREQ_IDX 5 + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: No, 1: 50Hz, 2:60Hz */ + .step = 1, +#define FREQ_DEF 1 + .default_value = FREQ_DEF, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, +#define SHARPNESS_IDX 6 + { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = -1, + .maximum = 2, + .step = 1, +#define SHARPNESS_DEF -1 + .default_value = SHARPNESS_DEF, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, +#define GAIN_IDX 7 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 78, + .step = 1, +#define GAIN_DEF 0 + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +#define EXPOSURE_IDX 8 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", +#define EXPOSURE_DEF 450 + .minimum = 0, + .maximum = 4095, + .step = 1, + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, +#define AUTOGAIN_IDX 9 + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Gain and Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +#define BACKLIGHT_IDX 10 + { + { + .id = V4L2_CID_BACKLIGHT_COMPENSATION, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Backlight Compensation", + .minimum = 0, + .maximum = 15, + .step = 1, +#define BACKLIGHT_DEF 15 + .default_value = BACKLIGHT_DEF, + }, + .set = sd_setbacklight, + .get = sd_getbacklight, + }, +}; + +/* table of the disabled controls */ +static u32 ctrl_dis[NSENSORS] = { + [SENSOR_HV7131R] = + (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) + | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX) + | (1 << SHARPNESS_IDX) + | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), + [SENSOR_MI0360] = + (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) + | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX) + | (1 << SHARPNESS_IDX) + | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), + [SENSOR_MI1310_SOC] = + (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) + | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) + | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), + [SENSOR_MI1320] = + (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) + | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) + | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), + [SENSOR_MI1320_SOC] = + (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) + | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) + | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), + [SENSOR_OV7660] = + (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) + | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) + | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), + [SENSOR_OV7670] = + (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) + | (1 << SHARPNESS_IDX) + | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), + [SENSOR_PO1200] = + (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) + | (1 << LIGHTFREQ_IDX) + | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), + [SENSOR_PO3130NC] = + (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) + | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX) + | (1 << SHARPNESS_IDX) + | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) + | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), + [SENSOR_POxxxx] = + (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX), +}; + +static const struct v4l2_pix_format vc0321_mode[] = { + {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; +static const struct v4l2_pix_format vc0323_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, + {1280, 960, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi1310_soc only */ + .bytesperline = 1280, + .sizeimage = 1280 * 960 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, +}; +static const struct v4l2_pix_format bi_mode[] = { + {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; +static const struct v4l2_pix_format svga_mode[] = { + {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 600 * 1 / 4 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* OV7660/7670 registers */ +#define OV7660_REG_MVFP 0x1e +#define OV7660_MVFP_MIRROR 0x20 +#define OV7660_MVFP_VFLIP 0x10 + +static const u8 mi0360_matrix[9] = { + 0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50 +}; + +static const u8 mi0360_initVGA_JPG[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */ + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xbc, 0x00, 0x71, 0xcc}, + {0xb8, 0x00, 0x13, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, + {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, + {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x50, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, + {0xb8, 0x08, 0xe0, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, + {0xb8, 0x14, 0x18, 0xcc}, + {0xb8, 0xb2, 0x0a, 0xcc}, + {0xb8, 0xb4, 0x0a, 0xcc}, + {0xb8, 0xb5, 0x0a, 0xcc}, + {0xb8, 0xfe, 0x00, 0xcc}, + {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, + {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, + {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, + {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, + {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0x31, 0x00, 0x00, 0xbb}, + {0x09, 0x01, 0xc7, 0xbb}, + {0x34, 0x01, 0x00, 0xbb}, + {0x2b, 0x00, 0x28, 0xbb}, + {0x2c, 0x00, 0x30, 0xbb}, + {0x2d, 0x00, 0x30, 0xbb}, + {0x2e, 0x00, 0x28, 0xbb}, + {0x62, 0x04, 0x11, 0xbb}, + {0x03, 0x01, 0xe0, 0xbb}, + {0x2c, 0x00, 0x2c, 0xbb}, + {0x20, 0xd0, 0x00, 0xbb}, + {0x01, 0x00, 0x08, 0xbb}, + {0x06, 0x00, 0x10, 0xbb}, + {0x05, 0x00, 0x20, 0xbb}, + {0x20, 0x00, 0x00, 0xbb}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x02, 0xcc}, + {0xb6, 0x02, 0x80, 0xcc}, + {0xb6, 0x05, 0x01, 0xcc}, + {0xb6, 0x04, 0xe0, 0xcc}, + {0xb6, 0x12, 0x78, 0xcc}, + {0xb6, 0x18, 0x02, 0xcc}, + {0xb6, 0x17, 0x58, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x10, 0xcc}, + {0xb9, 0x12, 0x00, 0xcc}, + {0xb9, 0x13, 0x0a, 0xcc}, + {0xb9, 0x14, 0x0a, 0xcc}, + {0xb9, 0x15, 0x0a, 0xcc}, + {0xb9, 0x16, 0x0a, 0xcc}, + {0xb9, 0x18, 0x00, 0xcc}, + {0xb9, 0x19, 0x0f, 0xcc}, + {0xb9, 0x1a, 0x0f, 0xcc}, + {0xb9, 0x1b, 0x0f, 0xcc}, + {0xb9, 0x1c, 0x0f, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb8, 0x0c, 0x20, 0xcc}, + {0xb8, 0x0d, 0x70, 0xcc}, + {0xb6, 0x13, 0x13, 0xcc}, + {0x35, 0x00, 0x60, 0xbb}, + {0xb3, 0x5c, 0x01, 0xcc}, + {} +}; +static const u8 mi0360_initQVGA_JPG[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x35, 0xdd, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xbc, 0x00, 0xd1, 0xcc}, + {0xb8, 0x00, 0x13, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, + {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, + {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x50, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, + {0xb8, 0x08, 0xe0, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, + {0xb8, 0x14, 0x18, 0xcc}, + {0xb8, 0xb2, 0x0a, 0xcc}, + {0xb8, 0xb4, 0x0a, 0xcc}, + {0xb8, 0xb5, 0x0a, 0xcc}, + {0xb8, 0xfe, 0x00, 0xcc}, + {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, + {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, + {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, + {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, + {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0x31, 0x00, 0x00, 0xbb}, + {0x09, 0x01, 0xc7, 0xbb}, + {0x34, 0x01, 0x00, 0xbb}, + {0x2b, 0x00, 0x28, 0xbb}, + {0x2c, 0x00, 0x30, 0xbb}, + {0x2d, 0x00, 0x30, 0xbb}, + {0x2e, 0x00, 0x28, 0xbb}, + {0x62, 0x04, 0x11, 0xbb}, + {0x03, 0x01, 0xe0, 0xbb}, + {0x2c, 0x00, 0x2c, 0xbb}, + {0x20, 0xd0, 0x00, 0xbb}, + {0x01, 0x00, 0x08, 0xbb}, + {0x06, 0x00, 0x10, 0xbb}, + {0x05, 0x00, 0x20, 0xbb}, + {0x20, 0x00, 0x00, 0xbb}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x01, 0xcc}, + {0xb6, 0x02, 0x40, 0xcc}, + {0xb6, 0x05, 0x00, 0xcc}, + {0xb6, 0x04, 0xf0, 0xcc}, + {0xb6, 0x12, 0x78, 0xcc}, + {0xb6, 0x18, 0x00, 0xcc}, + {0xb6, 0x17, 0x96, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x10, 0xcc}, + {0xb9, 0x12, 0x00, 0xcc}, + {0xb9, 0x13, 0x0a, 0xcc}, + {0xb9, 0x14, 0x0a, 0xcc}, + {0xb9, 0x15, 0x0a, 0xcc}, + {0xb9, 0x16, 0x0a, 0xcc}, + {0xb9, 0x18, 0x00, 0xcc}, + {0xb9, 0x19, 0x0f, 0xcc}, + {0xb9, 0x1a, 0x0f, 0xcc}, + {0xb9, 0x1b, 0x0f, 0xcc}, + {0xb9, 0x1c, 0x0f, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x13, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, + {0xb8, 0x0c, 0x20, 0xcc}, + {0xb8, 0x0d, 0x70, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, + {0x35, 0x00, 0xef, 0xbb}, + {0xb3, 0x5c, 0x01, 0xcc}, + {} +}; + +static const u8 mi1310_socinitVGA_JPG[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0xb3, 0x00, 0x64, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xdd, 0xcc}, /* i2c add: 5d */ + {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x03, 0xcc}, + {0xb3, 0x23, 0xc0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x04, 0xcc}, + {0xb3, 0x17, 0xff, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, + {0xb8, 0x00, 0x00, 0xcc}, + {0xbc, 0x00, 0xd0, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0xf0, 0x00, 0x02, 0xbb}, + {0xc8, 0x9f, 0x0b, 0xbb}, + {0x5b, 0x00, 0x01, 0xbb}, + {0x2f, 0xde, 0x20, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */ + {0xf0, 0x00, 0x01, 0xbb}, + {0x05, 0x00, 0x07, 0xbb}, + {0x34, 0x00, 0x00, 0xbb}, + {0x35, 0xff, 0x00, 0xbb}, + {0xdc, 0x07, 0x02, 0xbb}, + {0xdd, 0x3c, 0x18, 0xbb}, + {0xde, 0x92, 0x6d, 0xbb}, + {0xdf, 0xcd, 0xb1, 0xbb}, + {0xe0, 0xff, 0xe7, 0xbb}, + {0x06, 0xf0, 0x0d, 0xbb}, + {0x06, 0x70, 0x0e, 0xbb}, + {0x4c, 0x00, 0x01, 0xbb}, + {0x4d, 0x00, 0x01, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x2e, 0x0c, 0x55, 0xbb}, + {0x21, 0xb6, 0x6e, 0xbb}, + {0x36, 0x30, 0x10, 0xbb}, + {0x37, 0x00, 0xc1, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x07, 0x00, 0x84, 0xbb}, + {0x08, 0x02, 0x4a, 0xbb}, + {0x05, 0x01, 0x10, 0xbb}, + {0x06, 0x00, 0x39, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x58, 0x02, 0x67, 0xbb}, + {0x57, 0x02, 0x00, 0xbb}, + {0x5a, 0x02, 0x67, 0xbb}, + {0x59, 0x02, 0x00, 0xbb}, + {0x5c, 0x12, 0x0d, 0xbb}, + {0x5d, 0x16, 0x11, 0xbb}, + {0x39, 0x06, 0x18, 0xbb}, + {0x3a, 0x06, 0x18, 0xbb}, + {0x3b, 0x06, 0x18, 0xbb}, + {0x3c, 0x06, 0x18, 0xbb}, + {0x64, 0x7b, 0x5b, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x36, 0x30, 0x10, 0xbb}, + {0x37, 0x00, 0xc0, 0xbb}, + {0xbc, 0x0e, 0x00, 0xcc}, + {0xbc, 0x0f, 0x05, 0xcc}, + {0xbc, 0x10, 0xc0, 0xcc}, + {0xbc, 0x11, 0x03, 0xcc}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x02, 0xcc}, + {0xb6, 0x02, 0x80, 0xcc}, + {0xb6, 0x05, 0x01, 0xcc}, + {0xb6, 0x04, 0xe0, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x25, 0xcc}, + {0xb6, 0x18, 0x02, 0xcc}, + {0xb6, 0x17, 0x58, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x00, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x80, 0x00, 0x03, 0xbb}, + {0x81, 0xc7, 0x14, 0xbb}, + {0x82, 0xeb, 0xe8, 0xbb}, + {0x83, 0xfe, 0xf4, 0xbb}, + {0x84, 0xcd, 0x10, 0xbb}, + {0x85, 0xf3, 0xee, 0xbb}, + {0x86, 0xff, 0xf1, 0xbb}, + {0x87, 0xcd, 0x10, 0xbb}, + {0x88, 0xf3, 0xee, 0xbb}, + {0x89, 0x01, 0xf1, 0xbb}, + {0x8a, 0xe5, 0x17, 0xbb}, + {0x8b, 0xe8, 0xe2, 0xbb}, + {0x8c, 0xf7, 0xed, 0xbb}, + {0x8d, 0x00, 0xff, 0xbb}, + {0x8e, 0xec, 0x10, 0xbb}, + {0x8f, 0xf0, 0xed, 0xbb}, + {0x90, 0xf9, 0xf2, 0xbb}, + {0x91, 0x00, 0x00, 0xbb}, + {0x92, 0xe9, 0x0d, 0xbb}, + {0x93, 0xf4, 0xf2, 0xbb}, + {0x94, 0xfb, 0xf5, 0xbb}, + {0x95, 0x00, 0xff, 0xbb}, + {0xb6, 0x0f, 0x08, 0xbb}, + {0xb7, 0x3d, 0x16, 0xbb}, + {0xb8, 0x0c, 0x04, 0xbb}, + {0xb9, 0x1c, 0x07, 0xbb}, + {0xba, 0x0a, 0x03, 0xbb}, + {0xbb, 0x1b, 0x09, 0xbb}, + {0xbc, 0x17, 0x0d, 0xbb}, + {0xbd, 0x23, 0x1d, 0xbb}, + {0xbe, 0x00, 0x28, 0xbb}, + {0xbf, 0x11, 0x09, 0xbb}, + {0xc0, 0x16, 0x15, 0xbb}, + {0xc1, 0x00, 0x1b, 0xbb}, + {0xc2, 0x0e, 0x07, 0xbb}, + {0xc3, 0x14, 0x10, 0xbb}, + {0xc4, 0x00, 0x17, 0xbb}, + {0x06, 0x74, 0x8e, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x06, 0xf4, 0x8e, 0xbb}, + {0x00, 0x00, 0x50, 0xdd}, + {0x06, 0x74, 0x8e, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x24, 0x50, 0x20, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x34, 0x0c, 0x50, 0xbb}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x03, 0x03, 0xc0, 0xbb}, + {}, +}; +static const u8 mi1310_socinitQVGA_JPG[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc}, + {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x00, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, {0xb3, 0x35, 0xdd, 0xcc}, + {0xb3, 0x02, 0x00, 0xcc}, {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x03, 0xcc}, + {0xb3, 0x23, 0xc0, 0xcc}, {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x04, 0xcc}, + {0xb3, 0x17, 0xff, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, + {0xb8, 0x00, 0x00, 0xcc}, {0xbc, 0x00, 0xf0, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x02, 0xbb}, + {0xc8, 0x9f, 0x0b, 0xbb}, {0x5b, 0x00, 0x01, 0xbb}, + {0x2f, 0xde, 0x20, 0xbb}, {0xf0, 0x00, 0x00, 0xbb}, + {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */ + {0xf0, 0x00, 0x01, 0xbb}, + {0x05, 0x00, 0x07, 0xbb}, {0x34, 0x00, 0x00, 0xbb}, + {0x35, 0xff, 0x00, 0xbb}, {0xdc, 0x07, 0x02, 0xbb}, + {0xdd, 0x3c, 0x18, 0xbb}, {0xde, 0x92, 0x6d, 0xbb}, + {0xdf, 0xcd, 0xb1, 0xbb}, {0xe0, 0xff, 0xe7, 0xbb}, + {0x06, 0xf0, 0x0d, 0xbb}, {0x06, 0x70, 0x0e, 0xbb}, + {0x4c, 0x00, 0x01, 0xbb}, {0x4d, 0x00, 0x01, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x2e, 0x0c, 0x55, 0xbb}, + {0x21, 0xb6, 0x6e, 0xbb}, {0x36, 0x30, 0x10, 0xbb}, + {0x37, 0x00, 0xc1, 0xbb}, {0xf0, 0x00, 0x00, 0xbb}, + {0x07, 0x00, 0x84, 0xbb}, {0x08, 0x02, 0x4a, 0xbb}, + {0x05, 0x01, 0x10, 0xbb}, {0x06, 0x00, 0x39, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x58, 0x02, 0x67, 0xbb}, + {0x57, 0x02, 0x00, 0xbb}, {0x5a, 0x02, 0x67, 0xbb}, + {0x59, 0x02, 0x00, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb}, + {0x5d, 0x16, 0x11, 0xbb}, {0x39, 0x06, 0x18, 0xbb}, + {0x3a, 0x06, 0x18, 0xbb}, {0x3b, 0x06, 0x18, 0xbb}, + {0x3c, 0x06, 0x18, 0xbb}, {0x64, 0x7b, 0x5b, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x30, 0x10, 0xbb}, + {0x37, 0x00, 0xc0, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc}, + {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc}, + {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x01, 0xcc}, {0xb6, 0x02, 0x40, 0xcc}, + {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x25, 0xcc}, + {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, {0xbf, 0xcc, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, {0xf0, 0x00, 0x01, 0xbb}, + {0x80, 0x00, 0x03, 0xbb}, {0x81, 0xc7, 0x14, 0xbb}, + {0x82, 0xeb, 0xe8, 0xbb}, {0x83, 0xfe, 0xf4, 0xbb}, + {0x84, 0xcd, 0x10, 0xbb}, {0x85, 0xf3, 0xee, 0xbb}, + {0x86, 0xff, 0xf1, 0xbb}, {0x87, 0xcd, 0x10, 0xbb}, + {0x88, 0xf3, 0xee, 0xbb}, {0x89, 0x01, 0xf1, 0xbb}, + {0x8a, 0xe5, 0x17, 0xbb}, {0x8b, 0xe8, 0xe2, 0xbb}, + {0x8c, 0xf7, 0xed, 0xbb}, {0x8d, 0x00, 0xff, 0xbb}, + {0x8e, 0xec, 0x10, 0xbb}, {0x8f, 0xf0, 0xed, 0xbb}, + {0x90, 0xf9, 0xf2, 0xbb}, {0x91, 0x00, 0x00, 0xbb}, + {0x92, 0xe9, 0x0d, 0xbb}, {0x93, 0xf4, 0xf2, 0xbb}, + {0x94, 0xfb, 0xf5, 0xbb}, {0x95, 0x00, 0xff, 0xbb}, + {0xb6, 0x0f, 0x08, 0xbb}, {0xb7, 0x3d, 0x16, 0xbb}, + {0xb8, 0x0c, 0x04, 0xbb}, {0xb9, 0x1c, 0x07, 0xbb}, + {0xba, 0x0a, 0x03, 0xbb}, {0xbb, 0x1b, 0x09, 0xbb}, + {0xbc, 0x17, 0x0d, 0xbb}, {0xbd, 0x23, 0x1d, 0xbb}, + {0xbe, 0x00, 0x28, 0xbb}, {0xbf, 0x11, 0x09, 0xbb}, + {0xc0, 0x16, 0x15, 0xbb}, {0xc1, 0x00, 0x1b, 0xbb}, + {0xc2, 0x0e, 0x07, 0xbb}, {0xc3, 0x14, 0x10, 0xbb}, + {0xc4, 0x00, 0x17, 0xbb}, {0x06, 0x74, 0x8e, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0xf4, 0x8e, 0xbb}, + {0x00, 0x00, 0x50, 0xdd}, {0x06, 0x74, 0x8e, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x24, 0x50, 0x20, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x34, 0x0c, 0x50, 0xbb}, + {0xb3, 0x01, 0x41, 0xcc}, {0xf0, 0x00, 0x00, 0xbb}, + {0x03, 0x03, 0xc0, 0xbb}, + {}, +}; +static const u8 mi1310_soc_InitSXGA_JPG[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0xb3, 0x00, 0x64, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xdd, 0xcc}, + {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x04, 0x0d, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x03, 0xcc}, + {0xb3, 0x23, 0xc0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x04, 0xcc}, + {0xb3, 0x17, 0xff, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, + {0xb8, 0x00, 0x00, 0xcc}, + {0xbc, 0x00, 0x70, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0xf0, 0x00, 0x02, 0xbb}, + {0xc8, 0x9f, 0x0b, 0xbb}, + {0x5b, 0x00, 0x01, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x20, 0x03, 0x02, 0xbb}, /* h/v flip */ + {0xf0, 0x00, 0x01, 0xbb}, + {0x05, 0x00, 0x07, 0xbb}, + {0x34, 0x00, 0x00, 0xbb}, + {0x35, 0xff, 0x00, 0xbb}, + {0xdc, 0x07, 0x02, 0xbb}, + {0xdd, 0x3c, 0x18, 0xbb}, + {0xde, 0x92, 0x6d, 0xbb}, + {0xdf, 0xcd, 0xb1, 0xbb}, + {0xe0, 0xff, 0xe7, 0xbb}, + {0x06, 0xf0, 0x0d, 0xbb}, + {0x06, 0x70, 0x0e, 0xbb}, + {0x4c, 0x00, 0x01, 0xbb}, + {0x4d, 0x00, 0x01, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x2e, 0x0c, 0x60, 0xbb}, + {0x21, 0xb6, 0x6e, 0xbb}, + {0x37, 0x01, 0x40, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x07, 0x00, 0x84, 0xbb}, + {0x08, 0x02, 0x4a, 0xbb}, + {0x05, 0x01, 0x10, 0xbb}, + {0x06, 0x00, 0x39, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x58, 0x02, 0x67, 0xbb}, + {0x57, 0x02, 0x00, 0xbb}, + {0x5a, 0x02, 0x67, 0xbb}, + {0x59, 0x02, 0x00, 0xbb}, + {0x5c, 0x12, 0x0d, 0xbb}, + {0x5d, 0x16, 0x11, 0xbb}, + {0x39, 0x06, 0x18, 0xbb}, + {0x3a, 0x06, 0x18, 0xbb}, + {0x3b, 0x06, 0x18, 0xbb}, + {0x3c, 0x06, 0x18, 0xbb}, + {0x64, 0x7b, 0x5b, 0xbb}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x05, 0xcc}, + {0xb6, 0x02, 0x00, 0xcc}, + {0xb6, 0x05, 0x03, 0xcc}, + {0xb6, 0x04, 0xc0, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x29, 0xcc}, + {0xb6, 0x18, 0x09, 0xcc}, + {0xb6, 0x17, 0x60, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x00, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0x00, 0x00, 0x80, 0xdd}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x00, 0x00, 0x10, 0xdd}, + {0x22, 0xa0, 0x78, 0xbb}, + {0x23, 0xa0, 0x78, 0xbb}, + {0x24, 0x7f, 0x00, 0xbb}, + {0x28, 0xea, 0x02, 0xbb}, + {0x29, 0x86, 0x7a, 0xbb}, + {0x5e, 0x52, 0x4c, 0xbb}, + {0x5f, 0x20, 0x24, 0xbb}, + {0x60, 0x00, 0x02, 0xbb}, + {0x02, 0x00, 0xee, 0xbb}, + {0x03, 0x39, 0x23, 0xbb}, + {0x04, 0x07, 0x24, 0xbb}, + {0x09, 0x00, 0xc0, 0xbb}, + {0x0a, 0x00, 0x79, 0xbb}, + {0x0b, 0x00, 0x04, 0xbb}, + {0x0c, 0x00, 0x5c, 0xbb}, + {0x0d, 0x00, 0xd9, 0xbb}, + {0x0e, 0x00, 0x53, 0xbb}, + {0x0f, 0x00, 0x21, 0xbb}, + {0x10, 0x00, 0xa4, 0xbb}, + {0x11, 0x00, 0xe5, 0xbb}, + {0x15, 0x00, 0x00, 0xbb}, + {0x16, 0x00, 0x00, 0xbb}, + {0x17, 0x00, 0x00, 0xbb}, + {0x18, 0x00, 0x00, 0xbb}, + {0x19, 0x00, 0x00, 0xbb}, + {0x1a, 0x00, 0x00, 0xbb}, + {0x1b, 0x00, 0x00, 0xbb}, + {0x1c, 0x00, 0x00, 0xbb}, + {0x1d, 0x00, 0x00, 0xbb}, + {0x1e, 0x00, 0x00, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x00, 0x00, 0x20, 0xdd}, + {0x06, 0xf0, 0x8e, 0xbb}, + {0x00, 0x00, 0x80, 0xdd}, + {0x06, 0x70, 0x8e, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x00, 0x00, 0x20, 0xdd}, + {0x5e, 0x6a, 0x53, 0xbb}, + {0x5f, 0x40, 0x2c, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x00, 0x00, 0x20, 0xdd}, + {0x58, 0x00, 0x00, 0xbb}, + {0x53, 0x09, 0x03, 0xbb}, + {0x54, 0x31, 0x18, 0xbb}, + {0x55, 0x8b, 0x5f, 0xbb}, + {0x56, 0xc0, 0xa9, 0xbb}, + {0x57, 0xe0, 0xd2, 0xbb}, + {0xe1, 0x00, 0x00, 0xbb}, + {0xdc, 0x09, 0x03, 0xbb}, + {0xdd, 0x31, 0x18, 0xbb}, + {0xde, 0x8b, 0x5f, 0xbb}, + {0xdf, 0xc0, 0xa9, 0xbb}, + {0xe0, 0xe0, 0xd2, 0xbb}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x06, 0xf0, 0x8e, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x2f, 0xde, 0x20, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x24, 0x50, 0x20, 0xbb}, + {0xbc, 0x0e, 0x00, 0xcc}, + {0xbc, 0x0f, 0x05, 0xcc}, + {0xbc, 0x10, 0xc0, 0xcc}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x34, 0x0c, 0x50, 0xbb}, + {0xbc, 0x11, 0x03, 0xcc}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x80, 0x00, 0x03, 0xbb}, + {0x81, 0xc7, 0x14, 0xbb}, + {0x82, 0xeb, 0xe8, 0xbb}, + {0x83, 0xfe, 0xf4, 0xbb}, + {0x84, 0xcd, 0x10, 0xbb}, + {0x85, 0xf3, 0xee, 0xbb}, + {0x86, 0xff, 0xf1, 0xbb}, + {0x87, 0xcd, 0x10, 0xbb}, + {0x88, 0xf3, 0xee, 0xbb}, + {0x89, 0x01, 0xf1, 0xbb}, + {0x8a, 0xe5, 0x17, 0xbb}, + {0x8b, 0xe8, 0xe2, 0xbb}, + {0x8c, 0xf7, 0xed, 0xbb}, + {0x8d, 0x00, 0xff, 0xbb}, + {0x8e, 0xec, 0x10, 0xbb}, + {0x8f, 0xf0, 0xed, 0xbb}, + {0x90, 0xf9, 0xf2, 0xbb}, + {0x91, 0x00, 0x00, 0xbb}, + {0x92, 0xe9, 0x0d, 0xbb}, + {0x93, 0xf4, 0xf2, 0xbb}, + {0x94, 0xfb, 0xf5, 0xbb}, + {0x95, 0x00, 0xff, 0xbb}, + {0xb6, 0x0f, 0x08, 0xbb}, + {0xb7, 0x3d, 0x16, 0xbb}, + {0xb8, 0x0c, 0x04, 0xbb}, + {0xb9, 0x1c, 0x07, 0xbb}, + {0xba, 0x0a, 0x03, 0xbb}, + {0xbb, 0x1b, 0x09, 0xbb}, + {0xbc, 0x17, 0x0d, 0xbb}, + {0xbd, 0x23, 0x1d, 0xbb}, + {0xbe, 0x00, 0x28, 0xbb}, + {0xbf, 0x11, 0x09, 0xbb}, + {0xc0, 0x16, 0x15, 0xbb}, + {0xc1, 0x00, 0x1b, 0xbb}, + {0xc2, 0x0e, 0x07, 0xbb}, + {0xc3, 0x14, 0x10, 0xbb}, + {0xc4, 0x00, 0x17, 0xbb}, + {0x06, 0x74, 0x8e, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x03, 0x03, 0xc0, 0xbb}, + {} +}; + +static const u8 mi1320_gamma[17] = { + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +}; +static const u8 mi1320_matrix[9] = { + 0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52 +}; +static const u8 mi1320_initVGA_data[][4] = { + {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, + {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */ + {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x03, 0xcc}, {0xb3, 0x23, 0xc0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x04, 0xcc}, {0xb3, 0x17, 0xff, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, {0xbc, 0x00, 0xd0, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, {0xf0, 0x00, 0x00, 0xbb}, + {0x0d, 0x00, 0x09, 0xbb}, {0x00, 0x01, 0x00, 0xdd}, + {0x0d, 0x00, 0x08, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, + {0xa1, 0x05, 0x00, 0xbb}, {0xa4, 0x03, 0xc0, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, + {0xc8, 0x9f, 0x0b, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, + {0xf0, 0x00, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, + {0x20, 0x01, 0x00, 0xbb}, {0x00, 0x00, 0x10, 0xdd}, + {0xf0, 0x00, 0x01, 0xbb}, {0x9d, 0x3c, 0xa0, 0xbb}, + {0x47, 0x30, 0x30, 0xbb}, {0xf0, 0x00, 0x00, 0xbb}, + {0x0a, 0x80, 0x11, 0xbb}, {0x35, 0x00, 0x22, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x9d, 0xc5, 0x05, 0xbb}, + {0xdc, 0x0f, 0xfc, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, + {0x06, 0x74, 0x0e, 0xbb}, {0x80, 0x00, 0x06, 0xbb}, + {0x81, 0x04, 0x00, 0xbb}, {0x82, 0x01, 0x02, 0xbb}, + {0x83, 0x03, 0x02, 0xbb}, {0x84, 0x05, 0x00, 0xbb}, + {0x85, 0x01, 0x00, 0xbb}, {0x86, 0x03, 0x02, 0xbb}, + {0x87, 0x05, 0x00, 0xbb}, {0x88, 0x01, 0x00, 0xbb}, + {0x89, 0x02, 0x02, 0xbb}, {0x8a, 0xfd, 0x04, 0xbb}, + {0x8b, 0xfc, 0xfd, 0xbb}, {0x8c, 0xff, 0xfd, 0xbb}, + {0x8d, 0x00, 0x00, 0xbb}, {0x8e, 0xfe, 0x05, 0xbb}, + {0x8f, 0xfc, 0xfd, 0xbb}, {0x90, 0xfe, 0xfd, 0xbb}, + {0x91, 0x00, 0x00, 0xbb}, {0x92, 0xfe, 0x03, 0xbb}, + {0x93, 0xfd, 0xfe, 0xbb}, {0x94, 0xff, 0xfd, 0xbb}, + {0x95, 0x00, 0x00, 0xbb}, {0xb6, 0x07, 0x05, 0xbb}, + {0xb7, 0x13, 0x06, 0xbb}, {0xb8, 0x08, 0x06, 0xbb}, + {0xb9, 0x14, 0x08, 0xbb}, {0xba, 0x06, 0x05, 0xbb}, + {0xbb, 0x13, 0x06, 0xbb}, {0xbc, 0x03, 0x01, 0xbb}, + {0xbd, 0x03, 0x04, 0xbb}, {0xbe, 0x00, 0x02, 0xbb}, + {0xbf, 0x03, 0x01, 0xbb}, {0xc0, 0x02, 0x04, 0xbb}, + {0xc1, 0x00, 0x04, 0xbb}, {0xc2, 0x02, 0x01, 0xbb}, + {0xc3, 0x01, 0x03, 0xbb}, {0xc4, 0x00, 0x04, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, {0x05, 0x01, 0x13, 0xbb}, + {0x06, 0x00, 0x11, 0xbb}, {0x07, 0x00, 0x85, 0xbb}, + {0x08, 0x00, 0x27, 0xbb}, + {0x20, 0x01, 0x00, 0xbb}, /* h/v flips - was 03 */ + {0x21, 0x80, 0x00, 0xbb}, {0x22, 0x0d, 0x0f, 0xbb}, + {0x24, 0x80, 0x00, 0xbb}, {0x59, 0x00, 0xff, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x39, 0x03, 0x0d, 0xbb}, + {0x3a, 0x06, 0x1b, 0xbb}, {0x3b, 0x00, 0x95, 0xbb}, + {0x3c, 0x04, 0xdb, 0xbb}, {0x57, 0x02, 0x00, 0xbb}, + {0x58, 0x02, 0x66, 0xbb}, {0x59, 0x00, 0xff, 0xbb}, + {0x5a, 0x01, 0x33, 0xbb}, {0x5c, 0x12, 0x0d, 0xbb}, + {0x5d, 0x16, 0x11, 0xbb}, {0x64, 0x5e, 0x1c, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb}, + {0x5b, 0x00, 0x01, 0xbb}, {0xf0, 0x00, 0x02, 0xbb}, + {0x36, 0x68, 0x10, 0xbb}, {0x00, 0x00, 0x30, 0xdd}, + {0x37, 0x82, 0x00, 0xbb}, {0xbc, 0x0e, 0x00, 0xcc}, + {0xbc, 0x0f, 0x05, 0xcc}, {0xbc, 0x10, 0xc0, 0xcc}, + {0xbc, 0x11, 0x03, 0xcc}, {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x05, 0xcc}, {0xb6, 0x02, 0x00, 0xcc}, + {0xb6, 0x05, 0x04, 0xcc}, {0xb6, 0x04, 0x00, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x29, 0xcc}, + {0xb6, 0x18, 0x0a, 0xcc}, {0xb6, 0x17, 0x00, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, {0xbf, 0xc0, 0x26, 0xcc}, + {0xbf, 0xc1, 0x02, 0xcc}, {0xbf, 0xcc, 0x04, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x41, 0xcc}, + {} +}; +static const u8 mi1320_initQVGA_data[][4] = { + {0xb3, 0x01, 0x01, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb0, 0x03, 0x19, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb0, 0x04, 0x02, 0xcc}, {0x00, 0x00, 0x33, 0xdd}, + {0xb3, 0x00, 0x64, 0xcc}, {0xb3, 0x00, 0x65, 0xcc}, + {0xb0, 0x16, 0x03, 0xcc}, {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xc8, 0xcc}, {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, {0xb8, 0x00, 0x00, 0xcc}, + {0xbc, 0x00, 0xd0, 0xcc}, {0xbc, 0x01, 0x01, 0xcc}, + {0xf0, 0x00, 0x00, 0xbb}, {0x0d, 0x00, 0x09, 0xbb}, + {0x00, 0x01, 0x00, 0xdd}, {0x0d, 0x00, 0x08, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, {0x02, 0x00, 0x64, 0xbb}, + {0x05, 0x01, 0x78, 0xbb}, {0x06, 0x00, 0x11, 0xbb}, + {0x07, 0x01, 0x42, 0xbb}, {0x08, 0x00, 0x11, 0xbb}, + {0x20, 0x01, 0x00, 0xbb}, {0x21, 0x80, 0x00, 0xbb}, + {0x22, 0x0d, 0x0f, 0xbb}, {0x24, 0x80, 0x00, 0xbb}, + {0x59, 0x00, 0xff, 0xbb}, {0xf0, 0x00, 0x01, 0xbb}, + {0x9d, 0x3c, 0xa0, 0xbb}, {0x47, 0x30, 0x30, 0xbb}, + {0xf0, 0x00, 0x00, 0xbb}, {0x0a, 0x80, 0x11, 0xbb}, + {0x35, 0x00, 0x22, 0xbb}, {0xf0, 0x00, 0x02, 0xbb}, + {0x9d, 0xc5, 0x05, 0xbb}, {0xdc, 0x0f, 0xfc, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, {0x06, 0x74, 0x0e, 0xbb}, + {0x80, 0x00, 0x06, 0xbb}, {0x81, 0x04, 0x00, 0xbb}, + {0x82, 0x01, 0x02, 0xbb}, {0x83, 0x03, 0x02, 0xbb}, + {0x84, 0x05, 0x00, 0xbb}, {0x85, 0x01, 0x00, 0xbb}, + {0x86, 0x03, 0x02, 0xbb}, {0x87, 0x05, 0x00, 0xbb}, + {0x88, 0x01, 0x00, 0xbb}, {0x89, 0x02, 0x02, 0xbb}, + {0x8a, 0xfd, 0x04, 0xbb}, {0x8b, 0xfc, 0xfd, 0xbb}, + {0x8c, 0xff, 0xfd, 0xbb}, {0x8d, 0x00, 0x00, 0xbb}, + {0x8e, 0xfe, 0x05, 0xbb}, {0x8f, 0xfc, 0xfd, 0xbb}, + {0x90, 0xfe, 0xfd, 0xbb}, {0x91, 0x00, 0x00, 0xbb}, + {0x92, 0xfe, 0x03, 0xbb}, {0x93, 0xfd, 0xfe, 0xbb}, + {0x94, 0xff, 0xfd, 0xbb}, {0x95, 0x00, 0x00, 0xbb}, + {0xb6, 0x07, 0x05, 0xbb}, {0xb7, 0x13, 0x06, 0xbb}, + {0xb8, 0x08, 0x06, 0xbb}, {0xb9, 0x14, 0x08, 0xbb}, + {0xba, 0x06, 0x05, 0xbb}, {0xbb, 0x13, 0x06, 0xbb}, + {0xbc, 0x03, 0x01, 0xbb}, {0xbd, 0x03, 0x04, 0xbb}, + {0xbe, 0x00, 0x02, 0xbb}, {0xbf, 0x03, 0x01, 0xbb}, + {0xc0, 0x02, 0x04, 0xbb}, {0xc1, 0x00, 0x04, 0xbb}, + {0xc2, 0x02, 0x01, 0xbb}, {0xc3, 0x01, 0x03, 0xbb}, + {0xc4, 0x00, 0x04, 0xbb}, {0xf0, 0x00, 0x02, 0xbb}, + {0xc8, 0x00, 0x00, 0xbb}, {0x2e, 0x00, 0x00, 0xbb}, + {0x2e, 0x0c, 0x5b, 0xbb}, {0x2f, 0xd1, 0x00, 0xbb}, + {0x39, 0x03, 0xca, 0xbb}, {0x3a, 0x06, 0x80, 0xbb}, + {0x3b, 0x01, 0x52, 0xbb}, {0x3c, 0x05, 0x40, 0xbb}, + {0x57, 0x01, 0x9c, 0xbb}, {0x58, 0x01, 0xee, 0xbb}, + {0x59, 0x00, 0xf0, 0xbb}, {0x5a, 0x01, 0x20, 0xbb}, + {0x5c, 0x1d, 0x17, 0xbb}, {0x5d, 0x22, 0x1c, 0xbb}, + {0x64, 0x1e, 0x1c, 0xbb}, {0x5b, 0x00, 0x01, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, {0x36, 0x68, 0x10, 0xbb}, + {0x00, 0x00, 0x30, 0xdd}, {0x37, 0x81, 0x00, 0xbb}, + {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, + {0xbf, 0xc0, 0x26, 0xcc}, {0xbf, 0xc1, 0x02, 0xcc}, + {0xbf, 0xcc, 0x04, 0xcc}, {0xb3, 0x5c, 0x01, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {} +}; + +static const u8 mi1320_soc_InitVGA[][4] = { + {0xb3, 0x01, 0x01, 0xcc}, + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0x00, 0x00, 0x30, 0xdd}, + {0xb3, 0x00, 0x64, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xc8, 0xcc}, /* i2c add: 48 */ + {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb8, 0x00, 0x00, 0xcc}, + {0xbc, 0x00, 0x71, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x00, 0x00, 0x10, 0xdd}, + {0xc8, 0x00, 0x00, 0xbb}, + {0x00, 0x00, 0x30, 0xdd}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x00, 0x00, 0x10, 0xdd}, + {0x07, 0x00, 0xe0, 0xbb}, + {0x08, 0x00, 0x0b, 0xbb}, + {0x21, 0x00, 0x0c, 0xbb}, + {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ + {0xbf, 0xc0, 0x26, 0xcc}, + {0xbf, 0xc1, 0x02, 0xcc}, + {0xbf, 0xcc, 0x04, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x05, 0x01, 0x78, 0xbb}, + {0x06, 0x00, 0x11, 0xbb}, + {0x07, 0x01, 0x42, 0xbb}, + {0x08, 0x00, 0x11, 0xbb}, + {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ + {0x21, 0x80, 0x00, 0xbb}, + {0x22, 0x0d, 0x0f, 0xbb}, + {0x24, 0x80, 0x00, 0xbb}, + {0x59, 0x00, 0xff, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x39, 0x03, 0xca, 0xbb}, + {0x3a, 0x06, 0x80, 0xbb}, + {0x3b, 0x01, 0x52, 0xbb}, + {0x3c, 0x05, 0x40, 0xbb}, + {0x57, 0x01, 0x9c, 0xbb}, + {0x58, 0x01, 0xee, 0xbb}, + {0x59, 0x00, 0xf0, 0xbb}, + {0x5a, 0x01, 0x20, 0xbb}, + {0x5c, 0x1d, 0x17, 0xbb}, + {0x5d, 0x22, 0x1c, 0xbb}, + {0x64, 0x1e, 0x1c, 0xbb}, + {0x5b, 0x00, 0x00, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x22, 0xa0, 0x78, 0xbb}, + {0x23, 0xa0, 0x78, 0xbb}, + {0x24, 0x7f, 0x00, 0xbb}, + {0x28, 0xea, 0x02, 0xbb}, + {0x29, 0x86, 0x7a, 0xbb}, + {0x5e, 0x52, 0x4c, 0xbb}, + {0x5f, 0x20, 0x24, 0xbb}, + {0x60, 0x00, 0x02, 0xbb}, + {0x02, 0x00, 0xee, 0xbb}, + {0x03, 0x39, 0x23, 0xbb}, + {0x04, 0x07, 0x24, 0xbb}, + {0x09, 0x00, 0xc0, 0xbb}, + {0x0a, 0x00, 0x79, 0xbb}, + {0x0b, 0x00, 0x04, 0xbb}, + {0x0c, 0x00, 0x5c, 0xbb}, + {0x0d, 0x00, 0xd9, 0xbb}, + {0x0e, 0x00, 0x53, 0xbb}, + {0x0f, 0x00, 0x21, 0xbb}, + {0x10, 0x00, 0xa4, 0xbb}, + {0x11, 0x00, 0xe5, 0xbb}, + {0x15, 0x00, 0x00, 0xbb}, + {0x16, 0x00, 0x00, 0xbb}, + {0x17, 0x00, 0x00, 0xbb}, + {0x18, 0x00, 0x00, 0xbb}, + {0x19, 0x00, 0x00, 0xbb}, + {0x1a, 0x00, 0x00, 0xbb}, + {0x1b, 0x00, 0x00, 0xbb}, + {0x1c, 0x00, 0x00, 0xbb}, + {0x1d, 0x00, 0x00, 0xbb}, + {0x1e, 0x00, 0x00, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x06, 0xe0, 0x0e, 0xbb}, + {0x06, 0x60, 0x0e, 0xbb}, + {0xb3, 0x5c, 0x01, 0xcc}, + {} +}; +static const u8 mi1320_soc_InitQVGA[][4] = { + {0xb3, 0x01, 0x01, 0xcc}, + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0x00, 0x00, 0x30, 0xdd}, + {0xb3, 0x00, 0x64, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xc8, 0xcc}, + {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb8, 0x00, 0x00, 0xcc}, + {0xbc, 0x00, 0xd1, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x00, 0x00, 0x10, 0xdd}, + {0xc8, 0x00, 0x00, 0xbb}, + {0x00, 0x00, 0x30, 0xdd}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x00, 0x00, 0x10, 0xdd}, + {0x07, 0x00, 0xe0, 0xbb}, + {0x08, 0x00, 0x0b, 0xbb}, + {0x21, 0x00, 0x0c, 0xbb}, + {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ + {0xbf, 0xc0, 0x26, 0xcc}, + {0xbf, 0xc1, 0x02, 0xcc}, + {0xbf, 0xcc, 0x04, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x05, 0x01, 0x78, 0xbb}, + {0x06, 0x00, 0x11, 0xbb}, + {0x07, 0x01, 0x42, 0xbb}, + {0x08, 0x00, 0x11, 0xbb}, + {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ + {0x21, 0x80, 0x00, 0xbb}, + {0x22, 0x0d, 0x0f, 0xbb}, + {0x24, 0x80, 0x00, 0xbb}, + {0x59, 0x00, 0xff, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x39, 0x03, 0xca, 0xbb}, + {0x3a, 0x06, 0x80, 0xbb}, + {0x3b, 0x01, 0x52, 0xbb}, + {0x3c, 0x05, 0x40, 0xbb}, + {0x57, 0x01, 0x9c, 0xbb}, + {0x58, 0x01, 0xee, 0xbb}, + {0x59, 0x00, 0xf0, 0xbb}, + {0x5a, 0x01, 0x20, 0xbb}, + {0x5c, 0x1d, 0x17, 0xbb}, + {0x5d, 0x22, 0x1c, 0xbb}, + {0x64, 0x1e, 0x1c, 0xbb}, + {0x5b, 0x00, 0x00, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x22, 0xa0, 0x78, 0xbb}, + {0x23, 0xa0, 0x78, 0xbb}, + {0x24, 0x7f, 0x00, 0xbb}, + {0x28, 0xea, 0x02, 0xbb}, + {0x29, 0x86, 0x7a, 0xbb}, + {0x5e, 0x52, 0x4c, 0xbb}, + {0x5f, 0x20, 0x24, 0xbb}, + {0x60, 0x00, 0x02, 0xbb}, + {0x02, 0x00, 0xee, 0xbb}, + {0x03, 0x39, 0x23, 0xbb}, + {0x04, 0x07, 0x24, 0xbb}, + {0x09, 0x00, 0xc0, 0xbb}, + {0x0a, 0x00, 0x79, 0xbb}, + {0x0b, 0x00, 0x04, 0xbb}, + {0x0c, 0x00, 0x5c, 0xbb}, + {0x0d, 0x00, 0xd9, 0xbb}, + {0x0e, 0x00, 0x53, 0xbb}, + {0x0f, 0x00, 0x21, 0xbb}, + {0x10, 0x00, 0xa4, 0xbb}, + {0x11, 0x00, 0xe5, 0xbb}, + {0x15, 0x00, 0x00, 0xbb}, + {0x16, 0x00, 0x00, 0xbb}, + {0x17, 0x00, 0x00, 0xbb}, + {0x18, 0x00, 0x00, 0xbb}, + {0x19, 0x00, 0x00, 0xbb}, + {0x1a, 0x00, 0x00, 0xbb}, + {0x1b, 0x00, 0x00, 0xbb}, + {0x1c, 0x00, 0x00, 0xbb}, + {0x1d, 0x00, 0x00, 0xbb}, + {0x1e, 0x00, 0x00, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x06, 0xe0, 0x0e, 0xbb}, + {0x06, 0x60, 0x0e, 0xbb}, + {0xb3, 0x5c, 0x01, 0xcc}, + {} +}; +static const u8 mi1320_soc_InitSXGA[][4] = { + {0xb3, 0x01, 0x01, 0xcc}, + {0xb0, 0x03, 0x19, 0xcc}, + {0x00, 0x00, 0x30, 0xdd}, + {0xb3, 0x00, 0x64, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x35, 0xc8, 0xcc}, + {0xb3, 0x02, 0x00, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x04, 0xcc}, + {0xb3, 0x23, 0x00, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x04, 0xcc}, + {0xb3, 0x17, 0xff, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xbc, 0x00, 0x71, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x00, 0x00, 0x30, 0xdd}, + {0xc8, 0x9f, 0x0b, 0xbb}, + {0x00, 0x00, 0x20, 0xdd}, + {0x5b, 0x00, 0x01, 0xbb}, + {0x00, 0x00, 0x20, 0xdd}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x00, 0x00, 0x30, 0xdd}, + {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ + {0x00, 0x00, 0x20, 0xdd}, + {0xbf, 0xc0, 0x26, 0xcc}, + {0xbf, 0xc1, 0x02, 0xcc}, + {0xbf, 0xcc, 0x04, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x05, 0x01, 0x78, 0xbb}, + {0x06, 0x00, 0x11, 0xbb}, + {0x07, 0x01, 0x42, 0xbb}, + {0x08, 0x00, 0x11, 0xbb}, + {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ + {0x21, 0x80, 0x00, 0xbb}, + {0x22, 0x0d, 0x0f, 0xbb}, + {0x24, 0x80, 0x00, 0xbb}, + {0x59, 0x00, 0xff, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x39, 0x03, 0xca, 0xbb}, + {0x3a, 0x06, 0x80, 0xbb}, + {0x3b, 0x01, 0x52, 0xbb}, + {0x3c, 0x05, 0x40, 0xbb}, + {0x57, 0x01, 0x9c, 0xbb}, + {0x58, 0x01, 0xee, 0xbb}, + {0x59, 0x00, 0xf0, 0xbb}, + {0x5a, 0x01, 0x20, 0xbb}, + {0x5c, 0x1d, 0x17, 0xbb}, + {0x5d, 0x22, 0x1c, 0xbb}, + {0x64, 0x1e, 0x1c, 0xbb}, + {0x5b, 0x00, 0x00, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x22, 0xa0, 0x78, 0xbb}, + {0x23, 0xa0, 0x78, 0xbb}, + {0x24, 0x7f, 0x00, 0xbb}, + {0x28, 0xea, 0x02, 0xbb}, + {0x29, 0x86, 0x7a, 0xbb}, + {0x5e, 0x52, 0x4c, 0xbb}, + {0x5f, 0x20, 0x24, 0xbb}, + {0x60, 0x00, 0x02, 0xbb}, + {0x02, 0x00, 0xee, 0xbb}, + {0x03, 0x39, 0x23, 0xbb}, + {0x04, 0x07, 0x24, 0xbb}, + {0x09, 0x00, 0xc0, 0xbb}, + {0x0a, 0x00, 0x79, 0xbb}, + {0x0b, 0x00, 0x04, 0xbb}, + {0x0c, 0x00, 0x5c, 0xbb}, + {0x0d, 0x00, 0xd9, 0xbb}, + {0x0e, 0x00, 0x53, 0xbb}, + {0x0f, 0x00, 0x21, 0xbb}, + {0x10, 0x00, 0xa4, 0xbb}, + {0x11, 0x00, 0xe5, 0xbb}, + {0x15, 0x00, 0x00, 0xbb}, + {0x16, 0x00, 0x00, 0xbb}, + {0x17, 0x00, 0x00, 0xbb}, + {0x18, 0x00, 0x00, 0xbb}, + {0x19, 0x00, 0x00, 0xbb}, + {0x1a, 0x00, 0x00, 0xbb}, + {0x1b, 0x00, 0x00, 0xbb}, + {0x1c, 0x00, 0x00, 0xbb}, + {0x1d, 0x00, 0x00, 0xbb}, + {0x1e, 0x00, 0x00, 0xbb}, + {0xf0, 0x00, 0x01, 0xbb}, + {0x06, 0xe0, 0x0e, 0xbb}, + {0x06, 0x60, 0x0e, 0xbb}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xf0, 0x00, 0x00, 0xbb}, + {0x05, 0x01, 0x13, 0xbb}, + {0x06, 0x00, 0x11, 0xbb}, + {0x07, 0x00, 0x85, 0xbb}, + {0x08, 0x00, 0x27, 0xbb}, + {0x20, 0x01, 0x03, 0xbb}, /* h/v flip */ + {0x21, 0x80, 0x00, 0xbb}, + {0x22, 0x0d, 0x0f, 0xbb}, + {0x24, 0x80, 0x00, 0xbb}, + {0x59, 0x00, 0xff, 0xbb}, + {0xf0, 0x00, 0x02, 0xbb}, + {0x39, 0x03, 0x0d, 0xbb}, + {0x3a, 0x06, 0x1b, 0xbb}, + {0x3b, 0x00, 0x95, 0xbb}, + {0x3c, 0x04, 0xdb, 0xbb}, + {0x57, 0x02, 0x00, 0xbb}, + {0x58, 0x02, 0x66, 0xbb}, + {0x59, 0x00, 0xff, 0xbb}, + {0x5a, 0x01, 0x33, 0xbb}, + {0x5c, 0x12, 0x0d, 0xbb}, + {0x5d, 0x16, 0x11, 0xbb}, + {0x64, 0x5e, 0x1c, 0xbb}, + {} +}; +static const u8 po3130_gamma[17] = { + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +}; +static const u8 po3130_matrix[9] = { + 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63 +}; + +static const u8 po3130_initVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc}, + {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe8, 0xcc}, {0xb8, 0x08, 0xe8, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */ + {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0x71, 0xcc}, + {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, + {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa}, + {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa}, + {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa}, + {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa}, + {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa}, + {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa}, + {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa}, + {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa}, + {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x5a, 0x04, 0xaa}, + {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa}, + {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa}, + {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa}, + {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa}, + {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa}, + {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa}, + {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa}, + {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa}, + {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa}, + {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa}, + {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa}, + {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa}, + {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa}, + {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa}, + {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa}, + {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa}, + {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, + {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa}, + {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa}, + {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa}, + {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa}, + {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa}, + {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa}, + {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa}, + {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, + {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, + {0x00, 0x4c, 0x07, 0xaa}, + {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa}, + {0x00, 0x59, 0x02, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa}, +/* {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa}, + {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, */ + {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0x20, 0xc4, 0xaa}, + {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, + {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, {0x00, 0x05, 0x00, 0xaa}, + {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc}, + {} +}; +static const u8 po3130_rundata[][4] = { + {0x00, 0x47, 0x45, 0xaa}, {0x00, 0x48, 0x9b, 0xaa}, + {0x00, 0x49, 0x3a, 0xaa}, {0x00, 0x4a, 0x01, 0xaa}, + {0x00, 0x44, 0x40, 0xaa}, +/* {0x00, 0xd5, 0x7c, 0xaa}, */ + {0x00, 0xad, 0x04, 0xaa}, {0x00, 0xae, 0x00, 0xaa}, + {0x00, 0xb0, 0x78, 0xaa}, {0x00, 0x98, 0x02, 0xaa}, + {0x00, 0x94, 0x25, 0xaa}, {0x00, 0x95, 0x25, 0xaa}, + {0x00, 0x59, 0x68, 0xaa}, {0x00, 0x44, 0x20, 0xaa}, + {0x00, 0x17, 0x50, 0xaa}, {0x00, 0x19, 0x50, 0xaa}, + {0x00, 0xd1, 0x3c, 0xaa}, {0x00, 0xd1, 0x3c, 0xaa}, + {0x00, 0x1e, 0x06, 0xaa}, {0x00, 0x1e, 0x06, 0xaa}, + {} +}; + +static const u8 po3130_initQVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x09, 0xcc}, + {0xb3, 0x00, 0x04, 0xcc}, {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x03, 0x1a, 0xcc}, + {0xb3, 0x04, 0x15, 0xcc}, {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, {0xb8, 0x08, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x35, 0xf6, 0xcc}, + {0xb3, 0x00, 0x27, 0xcc}, {0xbc, 0x00, 0xd1, 0xcc}, + {0xb8, 0x00, 0x21, 0xcc}, {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x50, 0xcc}, {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, {0xb8, 0x37, 0x00, 0xcc}, + {0x00, 0x1e, 0xc6, 0xaa}, {0x00, 0x20, 0x44, 0xaa}, + {0x00, 0xad, 0x02, 0xaa}, {0x00, 0xae, 0x2c, 0xaa}, + {0x00, 0x12, 0x08, 0xaa}, {0x00, 0x17, 0x41, 0xaa}, + {0x00, 0x19, 0x41, 0xaa}, {0x00, 0x1e, 0x06, 0xaa}, + {0x00, 0x21, 0x00, 0xaa}, {0x00, 0x36, 0xc0, 0xaa}, + {0x00, 0x37, 0xc8, 0xaa}, {0x00, 0x3b, 0x36, 0xaa}, + {0x00, 0x4b, 0xfe, 0xaa}, {0x00, 0x51, 0x1c, 0xaa}, + {0x00, 0x52, 0x01, 0xaa}, {0x00, 0x55, 0x0a, 0xaa}, + {0x00, 0x59, 0x6f, 0xaa}, {0x00, 0x5a, 0x04, 0xaa}, + {0x00, 0x5c, 0x10, 0xaa}, {0x00, 0x5d, 0x10, 0xaa}, + {0x00, 0x5e, 0x10, 0xaa}, {0x00, 0x5f, 0x10, 0xaa}, + {0x00, 0x61, 0x00, 0xaa}, {0x00, 0x62, 0x18, 0xaa}, + {0x00, 0x63, 0x30, 0xaa}, {0x00, 0x70, 0x68, 0xaa}, + {0x00, 0x80, 0x71, 0xaa}, {0x00, 0x81, 0x08, 0xaa}, + {0x00, 0x82, 0x00, 0xaa}, {0x00, 0x83, 0x55, 0xaa}, + {0x00, 0x84, 0x06, 0xaa}, {0x00, 0x85, 0x06, 0xaa}, + {0x00, 0x86, 0x13, 0xaa}, {0x00, 0x87, 0x18, 0xaa}, + {0x00, 0xaa, 0x3f, 0xaa}, {0x00, 0xab, 0x44, 0xaa}, + {0x00, 0xb0, 0x68, 0xaa}, {0x00, 0xb5, 0x10, 0xaa}, + {0x00, 0xb8, 0x20, 0xaa}, {0x00, 0xb9, 0xa0, 0xaa}, + {0x00, 0xbc, 0x04, 0xaa}, {0x00, 0x8b, 0x40, 0xaa}, + {0x00, 0x8c, 0x91, 0xaa}, {0x00, 0x8d, 0x8f, 0xaa}, + {0x00, 0x8e, 0x91, 0xaa}, {0x00, 0x8f, 0x43, 0xaa}, + {0x00, 0x90, 0x92, 0xaa}, {0x00, 0x91, 0x89, 0xaa}, + {0x00, 0x92, 0x9d, 0xaa}, {0x00, 0x93, 0x46, 0xaa}, + {0x00, 0xd6, 0x22, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, + {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0xd6, 0x62, 0xaa}, + {0x00, 0x73, 0x00, 0xaa}, {0x00, 0x74, 0x10, 0xaa}, + {0x00, 0x75, 0x20, 0xaa}, {0x00, 0x76, 0x2b, 0xaa}, + {0x00, 0x77, 0x36, 0xaa}, {0x00, 0x78, 0x49, 0xaa}, + {0x00, 0x79, 0x5a, 0xaa}, {0x00, 0x7a, 0x7f, 0xaa}, + {0x00, 0x7b, 0x9b, 0xaa}, {0x00, 0x7c, 0xba, 0xaa}, + {0x00, 0x7d, 0xd4, 0xaa}, {0x00, 0x7e, 0xea, 0xaa}, + {0x00, 0xd6, 0xa2, 0xaa}, {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x10, 0xaa}, {0x00, 0x75, 0x20, 0xaa}, + {0x00, 0x76, 0x2b, 0xaa}, {0x00, 0x77, 0x36, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, {0x00, 0x4c, 0x07, 0xaa}, + {0x00, 0x4b, 0xe0, 0xaa}, {0x00, 0x4e, 0x77, 0xaa}, + {0x00, 0x59, 0x66, 0xaa}, {0x00, 0x4d, 0x0a, 0xaa}, + {0x00, 0xd1, 0x00, 0xaa}, {0x00, 0x20, 0xc4, 0xaa}, + {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, + {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, {0x00, 0x05, 0x00, 0xaa}, + {0xb3, 0x5c, 0x00, 0xcc}, {0xb3, 0x01, 0x41, 0xcc}, + {} +}; + +static const u8 hv7131r_gamma[17] = { + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +}; +static const u8 hv7131r_matrix[9] = { + 0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63 +}; +static const u8 hv7131r_initVGA_data[][4] = { + {0xb3, 0x01, 0x01, 0xcc}, + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0x00, 0x00, 0x20, 0xdd}, + {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x01, 0x45, 0xcc}, + {0xb3, 0x03, 0x0b, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x02, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0x91, 0xcc}, /* i2c add: 11 */ + {0xb3, 0x00, 0x27, 0xcc}, + {0xbc, 0x00, 0x73, 0xcc}, + {0xb8, 0x00, 0x23, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, + {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, + {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x58, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x01, 0x7d, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0x00, 0x01, 0x0c, 0xaa}, + {0x00, 0x14, 0x01, 0xaa}, + {0x00, 0x15, 0xe6, 0xaa}, + {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x17, 0x86, 0xaa}, + {0x00, 0x23, 0x00, 0xaa}, + {0x00, 0x25, 0x03, 0xaa}, + {0x00, 0x26, 0xa9, 0xaa}, + {0x00, 0x27, 0x80, 0xaa}, + {0x00, 0x30, 0x18, 0xaa}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x02, 0xcc}, + {0xb6, 0x02, 0x80, 0xcc}, + {0xb6, 0x05, 0x01, 0xcc}, + {0xb6, 0x04, 0xe0, 0xcc}, + {0xb6, 0x12, 0x78, 0xcc}, + {0xb6, 0x18, 0x02, 0xcc}, + {0xb6, 0x17, 0x58, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x10, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x13, 0xcc}, + {0xb9, 0x12, 0x00, 0xcc}, + {0xb9, 0x13, 0x0a, 0xcc}, + {0xb9, 0x14, 0x0a, 0xcc}, + {0xb9, 0x15, 0x0a, 0xcc}, + {0xb9, 0x16, 0x0a, 0xcc}, + {0xb8, 0x0c, 0x20, 0xcc}, + {0xb8, 0x0d, 0x70, 0xcc}, + {0xb9, 0x18, 0x00, 0xcc}, + {0xb9, 0x19, 0x0f, 0xcc}, + {0xb9, 0x1a, 0x0f, 0xcc}, + {0xb9, 0x1b, 0x0f, 0xcc}, + {0xb9, 0x1c, 0x0f, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {} +}; + +static const u8 hv7131r_initQVGA_data[][4] = { + {0xb3, 0x01, 0x01, 0xcc}, + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0x00, 0x00, 0x20, 0xdd}, + {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x01, 0x45, 0xcc}, + {0xb3, 0x03, 0x0b, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x02, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0x91, 0xcc}, + {0xb3, 0x00, 0x27, 0xcc}, + {0xbc, 0x00, 0xd3, 0xcc}, + {0xb8, 0x00, 0x23, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, + {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, + {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x58, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x01, 0x7d, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0x00, 0x01, 0x0c, 0xaa}, + {0x00, 0x14, 0x01, 0xaa}, + {0x00, 0x15, 0xe6, 0xaa}, + {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x17, 0x86, 0xaa}, + {0x00, 0x23, 0x00, 0xaa}, + {0x00, 0x25, 0x03, 0xaa}, + {0x00, 0x26, 0xa9, 0xaa}, + {0x00, 0x27, 0x80, 0xaa}, + {0x00, 0x30, 0x18, 0xaa}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x01, 0xcc}, + {0xb6, 0x02, 0x40, 0xcc}, + {0xb6, 0x05, 0x00, 0xcc}, + {0xb6, 0x04, 0xf0, 0xcc}, + {0xb6, 0x12, 0x78, 0xcc}, + {0xb6, 0x18, 0x00, 0xcc}, + {0xb6, 0x17, 0x96, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x10, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, + {0xb9, 0x12, 0x00, 0xcc}, + {0xb9, 0x13, 0x0a, 0xcc}, + {0xb9, 0x14, 0x0a, 0xcc}, + {0xb9, 0x15, 0x0a, 0xcc}, + {0xb9, 0x16, 0x0a, 0xcc}, + {0xb9, 0x18, 0x00, 0xcc}, + {0xb9, 0x19, 0x0f, 0xcc}, + {0xb8, 0x0c, 0x20, 0xcc}, + {0xb8, 0x0d, 0x70, 0xcc}, + {0xb9, 0x1a, 0x0f, 0xcc}, + {0xb9, 0x1b, 0x0f, 0xcc}, + {0xb9, 0x1c, 0x0f, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x13, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {} +}; + +static const u8 ov7660_gamma[17] = { + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +}; +static const u8 ov7660_matrix[9] = { + 0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62 +}; +static const u8 ov7660_initVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, + {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */ + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc}, + {0xb3, 0x1f, 0x02, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */ + {0xb3, 0x00, 0x26, 0xcc}, + {0xb8, 0x00, 0x33, 0xcc}, /* 13 */ + {0xb8, 0x01, 0x7d, 0xcc}, + {0xbc, 0x00, 0x73, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x8f, 0x50, 0xcc}, + {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa}, + {0x00, 0x12, 0x80, 0xaa}, + {0x00, 0x12, 0x05, 0xaa}, + {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */ + {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */ + {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */ + {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa}, + {0x00, 0x13, 0xa7, 0xaa}, + {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa}, + {0x00, 0x36, 0x00, 0xaa}, + {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa}, + {0x00, 0x39, 0x43, 0xaa}, + {0x00, 0x8d, 0xcf, 0xaa}, + {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa}, + {0x00, 0x0f, 0x62, 0xaa}, + {0x00, 0x35, 0x84, 0xaa}, + {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */ + {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/ + {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */ + {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc}, + {0x00, 0x01, 0x80, 0xaa}, + {0x00, 0x02, 0x80, 0xaa}, + {0xb8, 0xfe, 0x00, 0xcc}, {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, + {0xb9, 0x01, 0x28, 0xcc}, {0xb9, 0x02, 0x28, 0xcc}, + {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, + {0xb9, 0x05, 0x3c, 0xcc}, {0xb9, 0x06, 0x3c, 0xcc}, + {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, + + {0xb8, 0x8e, 0x00, 0xcc}, {0xb8, 0x8f, 0xff, 0xcc}, + + {0x00, 0x29, 0x3c, 0xaa}, {0xb3, 0x01, 0x45, 0xcc}, + {} +}; +static const u8 ov7660_initQVGA_data[][4] = { + {0xb0, 0x4d, 0x00, 0xcc}, {0xb3, 0x01, 0x01, 0xcc}, + {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x01, 0xcc}, + {0xb3, 0x00, 0x21, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc},/* 0xb315 <-0 href startl */ + {0xb3, 0x16, 0x02, 0xcc}, {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, {0xb3, 0x1d, 0x01, 0xcc}, + {0xb3, 0x1f, 0x02, 0xcc}, {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0xa1, 0xcc}, {0xb3, 0x00, 0x26, 0xcc}, + {0xb8, 0x00, 0x33, 0xcc}, /* 13 */ + {0xb8, 0x01, 0x7d, 0xcc}, +/* sizer */ + {0xbc, 0x00, 0xd3, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, {0xb8, 0x81, 0x09, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x8f, 0x50, 0xcc}, + {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa}, + {0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa}, + {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */ + {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */ + {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */ + {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa}, + {0x00, 0x13, 0xa7, 0xaa}, + {0x00, 0x40, 0xc1, 0xaa}, {0x00, 0x35, 0x00, 0xaa}, + {0x00, 0x36, 0x00, 0xaa}, + {0x00, 0x3c, 0x68, 0xaa}, {0x00, 0x1b, 0x05, 0xaa}, + {0x00, 0x39, 0x43, 0xaa}, {0x00, 0x8d, 0xcf, 0xaa}, + {0x00, 0x8b, 0xcc, 0xaa}, {0x00, 0x8c, 0xcc, 0xaa}, + {0x00, 0x0f, 0x62, 0xaa}, {0x00, 0x35, 0x84, 0xaa}, + {0x00, 0x3b, 0x08, 0xaa}, /* 0 * Nightframe 1/4 + 50Hz -> 0xC8 */ + {0x00, 0x3a, 0x00, 0xaa}, /* mx change yuyv format 00, 04, 01; 08, 0c*/ + {0x00, 0x14, 0x2a, 0xaa}, /* agc ampli */ + {0x00, 0x9e, 0x40, 0xaa}, {0xb8, 0x8f, 0x50, 0xcc}, + {0x00, 0x01, 0x80, 0xaa}, + {0x00, 0x02, 0x80, 0xaa}, +/* sizer filters */ + {0xbc, 0x02, 0x08, 0xcc}, + {0xbc, 0x03, 0x70, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, + {0xbc, 0x04, 0x08, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x3c, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x04, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, +/* */ + {0xb8, 0xfe, 0x00, 0xcc}, + {0xb8, 0xff, 0x28, 0xcc}, +/* */ + {0xb9, 0x00, 0x28, 0xcc}, {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, +/* */ + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, /* ff */ + {0x00, 0x29, 0x3c, 0xaa}, + {0xb3, 0x01, 0x45, 0xcc}, /* 45 */ + {} +}; + +static const u8 ov7660_50HZ[][4] = { + {0x00, 0x3b, 0x08, 0xaa}, + {0x00, 0x9d, 0x40, 0xaa}, + {0x00, 0x13, 0xa7, 0xaa}, + {} +}; + +static const u8 ov7660_60HZ[][4] = { + {0x00, 0x3b, 0x00, 0xaa}, + {0x00, 0x9e, 0x40, 0xaa}, + {0x00, 0x13, 0xa7, 0xaa}, + {} +}; + +static const u8 ov7660_NoFliker[][4] = { + {0x00, 0x13, 0x87, 0xaa}, + {} +}; + +static const u8 ov7670_InitVGA[][4] = { + {0xb3, 0x01, 0x05, 0xcc}, + {0x00, 0x00, 0x30, 0xdd}, + {0xb0, 0x03, 0x19, 0xcc}, + {0x00, 0x00, 0x10, 0xdd}, + {0xb0, 0x04, 0x02, 0xcc}, + {0x00, 0x00, 0x10, 0xdd}, + {0xb3, 0x00, 0x66, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb0, 0x16, 0x01, 0xcc}, + {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */ + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xb3, 0x03, 0x1f, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xbc, 0x00, 0x41, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0x00, 0x12, 0x80, 0xaa}, + {0x00, 0x00, 0x20, 0xdd}, + {0x00, 0x12, 0x00, 0xaa}, + {0x00, 0x11, 0x40, 0xaa}, + {0x00, 0x6b, 0x0a, 0xaa}, + {0x00, 0x3a, 0x04, 0xaa}, + {0x00, 0x40, 0xc0, 0xaa}, + {0x00, 0x8c, 0x00, 0xaa}, + {0x00, 0x7a, 0x29, 0xaa}, + {0x00, 0x7b, 0x0e, 0xaa}, + {0x00, 0x7c, 0x1a, 0xaa}, + {0x00, 0x7d, 0x31, 0xaa}, + {0x00, 0x7e, 0x53, 0xaa}, + {0x00, 0x7f, 0x60, 0xaa}, + {0x00, 0x80, 0x6b, 0xaa}, + {0x00, 0x81, 0x73, 0xaa}, + {0x00, 0x82, 0x7b, 0xaa}, + {0x00, 0x83, 0x82, 0xaa}, + {0x00, 0x84, 0x89, 0xaa}, + {0x00, 0x85, 0x96, 0xaa}, + {0x00, 0x86, 0xa1, 0xaa}, + {0x00, 0x87, 0xb7, 0xaa}, + {0x00, 0x88, 0xcc, 0xaa}, + {0x00, 0x89, 0xe1, 0xaa}, + {0x00, 0x13, 0xe0, 0xaa}, + {0x00, 0x00, 0x00, 0xaa}, + {0x00, 0x10, 0x00, 0xaa}, + {0x00, 0x0d, 0x40, 0xaa}, + {0x00, 0x14, 0x28, 0xaa}, + {0x00, 0xa5, 0x05, 0xaa}, + {0x00, 0xab, 0x07, 0xaa}, + {0x00, 0x24, 0x95, 0xaa}, + {0x00, 0x25, 0x33, 0xaa}, + {0x00, 0x26, 0xe3, 0xaa}, + {0x00, 0x9f, 0x88, 0xaa}, + {0x00, 0xa0, 0x78, 0xaa}, + {0x00, 0x55, 0x90, 0xaa}, + {0x00, 0xa1, 0x03, 0xaa}, + {0x00, 0xa6, 0xe0, 0xaa}, + {0x00, 0xa7, 0xd8, 0xaa}, + {0x00, 0xa8, 0xf0, 0xaa}, + {0x00, 0xa9, 0x90, 0xaa}, + {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x13, 0xe5, 0xaa}, + {0x00, 0x0e, 0x61, 0xaa}, + {0x00, 0x0f, 0x4b, 0xaa}, + {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */ + {0x00, 0x21, 0x02, 0xaa}, + {0x00, 0x22, 0x91, 0xaa}, + {0x00, 0x29, 0x07, 0xaa}, + {0x00, 0x33, 0x0b, 0xaa}, + {0x00, 0x35, 0x0b, 0xaa}, + {0x00, 0x37, 0x1d, 0xaa}, + {0x00, 0x38, 0x71, 0xaa}, + {0x00, 0x39, 0x2a, 0xaa}, + {0x00, 0x3c, 0x78, 0xaa}, + {0x00, 0x4d, 0x40, 0xaa}, + {0x00, 0x4e, 0x20, 0xaa}, + {0x00, 0x74, 0x19, 0xaa}, + {0x00, 0x8d, 0x4f, 0xaa}, + {0x00, 0x8e, 0x00, 0xaa}, + {0x00, 0x8f, 0x00, 0xaa}, + {0x00, 0x90, 0x00, 0xaa}, + {0x00, 0x91, 0x00, 0xaa}, + {0x00, 0x96, 0x00, 0xaa}, + {0x00, 0x9a, 0x80, 0xaa}, + {0x00, 0xb0, 0x84, 0xaa}, + {0x00, 0xb1, 0x0c, 0xaa}, + {0x00, 0xb2, 0x0e, 0xaa}, + {0x00, 0xb3, 0x82, 0xaa}, + {0x00, 0xb8, 0x0a, 0xaa}, + {0x00, 0x43, 0x14, 0xaa}, + {0x00, 0x44, 0xf0, 0xaa}, + {0x00, 0x45, 0x45, 0xaa}, + {0x00, 0x46, 0x63, 0xaa}, + {0x00, 0x47, 0x2d, 0xaa}, + {0x00, 0x48, 0x46, 0xaa}, + {0x00, 0x59, 0x88, 0xaa}, + {0x00, 0x5a, 0xa0, 0xaa}, + {0x00, 0x5b, 0xc6, 0xaa}, + {0x00, 0x5c, 0x7d, 0xaa}, + {0x00, 0x5d, 0x5f, 0xaa}, + {0x00, 0x5e, 0x19, 0xaa}, + {0x00, 0x6c, 0x0a, 0xaa}, + {0x00, 0x6d, 0x55, 0xaa}, + {0x00, 0x6e, 0x11, 0xaa}, + {0x00, 0x6f, 0x9e, 0xaa}, + {0x00, 0x69, 0x00, 0xaa}, + {0x00, 0x6a, 0x40, 0xaa}, + {0x00, 0x01, 0x40, 0xaa}, + {0x00, 0x02, 0x40, 0xaa}, + {0x00, 0x13, 0xe7, 0xaa}, + {0x00, 0x5f, 0xf0, 0xaa}, + {0x00, 0x60, 0xf0, 0xaa}, + {0x00, 0x61, 0xf0, 0xaa}, + {0x00, 0x27, 0xa0, 0xaa}, + {0x00, 0x28, 0x80, 0xaa}, + {0x00, 0x2c, 0x90, 0xaa}, + {0x00, 0x4f, 0x66, 0xaa}, + {0x00, 0x50, 0x66, 0xaa}, + {0x00, 0x51, 0x00, 0xaa}, + {0x00, 0x52, 0x22, 0xaa}, + {0x00, 0x53, 0x5e, 0xaa}, + {0x00, 0x54, 0x80, 0xaa}, + {0x00, 0x58, 0x9e, 0xaa}, + {0x00, 0x41, 0x08, 0xaa}, + {0x00, 0x3f, 0x00, 0xaa}, + {0x00, 0x75, 0x85, 0xaa}, + {0x00, 0x76, 0xe1, 0xaa}, + {0x00, 0x4c, 0x00, 0xaa}, + {0x00, 0x77, 0x0a, 0xaa}, + {0x00, 0x3d, 0x88, 0xaa}, + {0x00, 0x4b, 0x09, 0xaa}, + {0x00, 0xc9, 0x60, 0xaa}, + {0x00, 0x41, 0x38, 0xaa}, + {0x00, 0x62, 0x30, 0xaa}, + {0x00, 0x63, 0x30, 0xaa}, + {0x00, 0x64, 0x08, 0xaa}, + {0x00, 0x94, 0x07, 0xaa}, + {0x00, 0x95, 0x0b, 0xaa}, + {0x00, 0x65, 0x00, 0xaa}, + {0x00, 0x66, 0x05, 0xaa}, + {0x00, 0x56, 0x50, 0xaa}, + {0x00, 0x34, 0x11, 0xaa}, + {0x00, 0xa4, 0x88, 0xaa}, + {0x00, 0x96, 0x00, 0xaa}, + {0x00, 0x97, 0x30, 0xaa}, + {0x00, 0x98, 0x20, 0xaa}, + {0x00, 0x99, 0x30, 0xaa}, + {0x00, 0x9a, 0x84, 0xaa}, + {0x00, 0x9b, 0x29, 0xaa}, + {0x00, 0x9c, 0x03, 0xaa}, + {0x00, 0x78, 0x04, 0xaa}, + {0x00, 0x79, 0x01, 0xaa}, + {0x00, 0xc8, 0xf0, 0xaa}, + {0x00, 0x79, 0x0f, 0xaa}, + {0x00, 0xc8, 0x00, 0xaa}, + {0x00, 0x79, 0x10, 0xaa}, + {0x00, 0xc8, 0x7e, 0xaa}, + {0x00, 0x79, 0x0a, 0xaa}, + {0x00, 0xc8, 0x80, 0xaa}, + {0x00, 0x79, 0x0b, 0xaa}, + {0x00, 0xc8, 0x01, 0xaa}, + {0x00, 0x79, 0x0c, 0xaa}, + {0x00, 0xc8, 0x0f, 0xaa}, + {0x00, 0x79, 0x0d, 0xaa}, + {0x00, 0xc8, 0x20, 0xaa}, + {0x00, 0x79, 0x09, 0xaa}, + {0x00, 0xc8, 0x80, 0xaa}, + {0x00, 0x79, 0x02, 0xaa}, + {0x00, 0xc8, 0xc0, 0xaa}, + {0x00, 0x79, 0x03, 0xaa}, + {0x00, 0xc8, 0x40, 0xaa}, + {0x00, 0x79, 0x05, 0xaa}, + {0x00, 0xc8, 0x30, 0xaa}, + {0x00, 0x79, 0x26, 0xaa}, + {0x00, 0x11, 0x40, 0xaa}, + {0x00, 0x3a, 0x04, 0xaa}, + {0x00, 0x12, 0x00, 0xaa}, + {0x00, 0x40, 0xc0, 0xaa}, + {0x00, 0x8c, 0x00, 0xaa}, + {0x00, 0x17, 0x14, 0xaa}, + {0x00, 0x18, 0x02, 0xaa}, + {0x00, 0x32, 0x92, 0xaa}, + {0x00, 0x19, 0x02, 0xaa}, + {0x00, 0x1a, 0x7a, 0xaa}, + {0x00, 0x03, 0x0a, 0xaa}, + {0x00, 0x0c, 0x00, 0xaa}, + {0x00, 0x3e, 0x00, 0xaa}, + {0x00, 0x70, 0x3a, 0xaa}, + {0x00, 0x71, 0x35, 0xaa}, + {0x00, 0x72, 0x11, 0xaa}, + {0x00, 0x73, 0xf0, 0xaa}, + {0x00, 0xa2, 0x02, 0xaa}, + {0x00, 0xb1, 0x00, 0xaa}, + {0x00, 0xb1, 0x0c, 0xaa}, + {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */ + {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x24, 0x80, 0xaa}, + {0x00, 0x25, 0x74, 0xaa}, + {0x00, 0x26, 0xd3, 0xaa}, + {0x00, 0x0d, 0x00, 0xaa}, + {0x00, 0x14, 0x18, 0xaa}, + {0x00, 0x9d, 0x99, 0xaa}, + {0x00, 0x9e, 0x7f, 0xaa}, + {0x00, 0x64, 0x08, 0xaa}, + {0x00, 0x94, 0x07, 0xaa}, + {0x00, 0x95, 0x06, 0xaa}, + {0x00, 0x66, 0x05, 0xaa}, + {0x00, 0x41, 0x08, 0xaa}, + {0x00, 0x3f, 0x00, 0xaa}, + {0x00, 0x75, 0x07, 0xaa}, + {0x00, 0x76, 0xe1, 0xaa}, + {0x00, 0x4c, 0x00, 0xaa}, + {0x00, 0x77, 0x00, 0xaa}, + {0x00, 0x3d, 0xc2, 0xaa}, + {0x00, 0x4b, 0x09, 0xaa}, + {0x00, 0xc9, 0x60, 0xaa}, + {0x00, 0x41, 0x38, 0xaa}, + {0xbf, 0xc0, 0x26, 0xcc}, + {0xbf, 0xc1, 0x02, 0xcc}, + {0xbf, 0xcc, 0x04, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xb3, 0x01, 0x45, 0xcc}, + {0x00, 0x77, 0x05, 0xaa}, + {}, +}; + +static const u8 ov7670_InitQVGA[][4] = { + {0xb3, 0x01, 0x05, 0xcc}, + {0x00, 0x00, 0x30, 0xdd}, + {0xb0, 0x03, 0x19, 0xcc}, + {0x00, 0x00, 0x10, 0xdd}, + {0xb0, 0x04, 0x02, 0xcc}, + {0x00, 0x00, 0x10, 0xdd}, + {0xb3, 0x00, 0x66, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb0, 0x16, 0x01, 0xcc}, + {0xb3, 0x35, 0xa1, 0xcc}, /* i2c add: 21 */ + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xb3, 0x03, 0x1f, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xbc, 0x00, 0xd1, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0x00, 0x12, 0x80, 0xaa}, + {0x00, 0x00, 0x20, 0xdd}, + {0x00, 0x12, 0x00, 0xaa}, + {0x00, 0x11, 0x40, 0xaa}, + {0x00, 0x6b, 0x0a, 0xaa}, + {0x00, 0x3a, 0x04, 0xaa}, + {0x00, 0x40, 0xc0, 0xaa}, + {0x00, 0x8c, 0x00, 0xaa}, + {0x00, 0x7a, 0x29, 0xaa}, + {0x00, 0x7b, 0x0e, 0xaa}, + {0x00, 0x7c, 0x1a, 0xaa}, + {0x00, 0x7d, 0x31, 0xaa}, + {0x00, 0x7e, 0x53, 0xaa}, + {0x00, 0x7f, 0x60, 0xaa}, + {0x00, 0x80, 0x6b, 0xaa}, + {0x00, 0x81, 0x73, 0xaa}, + {0x00, 0x82, 0x7b, 0xaa}, + {0x00, 0x83, 0x82, 0xaa}, + {0x00, 0x84, 0x89, 0xaa}, + {0x00, 0x85, 0x96, 0xaa}, + {0x00, 0x86, 0xa1, 0xaa}, + {0x00, 0x87, 0xb7, 0xaa}, + {0x00, 0x88, 0xcc, 0xaa}, + {0x00, 0x89, 0xe1, 0xaa}, + {0x00, 0x13, 0xe0, 0xaa}, + {0x00, 0x00, 0x00, 0xaa}, + {0x00, 0x10, 0x00, 0xaa}, + {0x00, 0x0d, 0x40, 0xaa}, + {0x00, 0x14, 0x28, 0xaa}, + {0x00, 0xa5, 0x05, 0xaa}, + {0x00, 0xab, 0x07, 0xaa}, + {0x00, 0x24, 0x95, 0xaa}, + {0x00, 0x25, 0x33, 0xaa}, + {0x00, 0x26, 0xe3, 0xaa}, + {0x00, 0x9f, 0x88, 0xaa}, + {0x00, 0xa0, 0x78, 0xaa}, + {0x00, 0x55, 0x90, 0xaa}, + {0x00, 0xa1, 0x03, 0xaa}, + {0x00, 0xa6, 0xe0, 0xaa}, + {0x00, 0xa7, 0xd8, 0xaa}, + {0x00, 0xa8, 0xf0, 0xaa}, + {0x00, 0xa9, 0x90, 0xaa}, + {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x13, 0xe5, 0xaa}, + {0x00, 0x0e, 0x61, 0xaa}, + {0x00, 0x0f, 0x4b, 0xaa}, + {0x00, 0x16, 0x02, 0xaa}, + {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */ + {0x00, 0x21, 0x02, 0xaa}, + {0x00, 0x22, 0x91, 0xaa}, + {0x00, 0x29, 0x07, 0xaa}, + {0x00, 0x33, 0x0b, 0xaa}, + {0x00, 0x35, 0x0b, 0xaa}, + {0x00, 0x37, 0x1d, 0xaa}, + {0x00, 0x38, 0x71, 0xaa}, + {0x00, 0x39, 0x2a, 0xaa}, + {0x00, 0x3c, 0x78, 0xaa}, + {0x00, 0x4d, 0x40, 0xaa}, + {0x00, 0x4e, 0x20, 0xaa}, + {0x00, 0x74, 0x19, 0xaa}, + {0x00, 0x8d, 0x4f, 0xaa}, + {0x00, 0x8e, 0x00, 0xaa}, + {0x00, 0x8f, 0x00, 0xaa}, + {0x00, 0x90, 0x00, 0xaa}, + {0x00, 0x91, 0x00, 0xaa}, + {0x00, 0x96, 0x00, 0xaa}, + {0x00, 0x9a, 0x80, 0xaa}, + {0x00, 0xb0, 0x84, 0xaa}, + {0x00, 0xb1, 0x0c, 0xaa}, + {0x00, 0xb2, 0x0e, 0xaa}, + {0x00, 0xb3, 0x82, 0xaa}, + {0x00, 0xb8, 0x0a, 0xaa}, + {0x00, 0x43, 0x14, 0xaa}, + {0x00, 0x44, 0xf0, 0xaa}, + {0x00, 0x45, 0x45, 0xaa}, + {0x00, 0x46, 0x63, 0xaa}, + {0x00, 0x47, 0x2d, 0xaa}, + {0x00, 0x48, 0x46, 0xaa}, + {0x00, 0x59, 0x88, 0xaa}, + {0x00, 0x5a, 0xa0, 0xaa}, + {0x00, 0x5b, 0xc6, 0xaa}, + {0x00, 0x5c, 0x7d, 0xaa}, + {0x00, 0x5d, 0x5f, 0xaa}, + {0x00, 0x5e, 0x19, 0xaa}, + {0x00, 0x6c, 0x0a, 0xaa}, + {0x00, 0x6d, 0x55, 0xaa}, + {0x00, 0x6e, 0x11, 0xaa}, + {0x00, 0x6f, 0x9e, 0xaa}, + {0x00, 0x69, 0x00, 0xaa}, + {0x00, 0x6a, 0x40, 0xaa}, + {0x00, 0x01, 0x40, 0xaa}, + {0x00, 0x02, 0x40, 0xaa}, + {0x00, 0x13, 0xe7, 0xaa}, + {0x00, 0x5f, 0xf0, 0xaa}, + {0x00, 0x60, 0xf0, 0xaa}, + {0x00, 0x61, 0xf0, 0xaa}, + {0x00, 0x27, 0xa0, 0xaa}, + {0x00, 0x28, 0x80, 0xaa}, + {0x00, 0x2c, 0x90, 0xaa}, + {0x00, 0x4f, 0x66, 0xaa}, + {0x00, 0x50, 0x66, 0xaa}, + {0x00, 0x51, 0x00, 0xaa}, + {0x00, 0x52, 0x22, 0xaa}, + {0x00, 0x53, 0x5e, 0xaa}, + {0x00, 0x54, 0x80, 0xaa}, + {0x00, 0x58, 0x9e, 0xaa}, + {0x00, 0x41, 0x08, 0xaa}, + {0x00, 0x3f, 0x00, 0xaa}, + {0x00, 0x75, 0x85, 0xaa}, + {0x00, 0x76, 0xe1, 0xaa}, + {0x00, 0x4c, 0x00, 0xaa}, + {0x00, 0x77, 0x0a, 0xaa}, + {0x00, 0x3d, 0x88, 0xaa}, + {0x00, 0x4b, 0x09, 0xaa}, + {0x00, 0xc9, 0x60, 0xaa}, + {0x00, 0x41, 0x38, 0xaa}, + {0x00, 0x62, 0x30, 0xaa}, + {0x00, 0x63, 0x30, 0xaa}, + {0x00, 0x64, 0x08, 0xaa}, + {0x00, 0x94, 0x07, 0xaa}, + {0x00, 0x95, 0x0b, 0xaa}, + {0x00, 0x65, 0x00, 0xaa}, + {0x00, 0x66, 0x05, 0xaa}, + {0x00, 0x56, 0x50, 0xaa}, + {0x00, 0x34, 0x11, 0xaa}, + {0x00, 0xa4, 0x88, 0xaa}, + {0x00, 0x96, 0x00, 0xaa}, + {0x00, 0x97, 0x30, 0xaa}, + {0x00, 0x98, 0x20, 0xaa}, + {0x00, 0x99, 0x30, 0xaa}, + {0x00, 0x9a, 0x84, 0xaa}, + {0x00, 0x9b, 0x29, 0xaa}, + {0x00, 0x9c, 0x03, 0xaa}, + {0x00, 0x78, 0x04, 0xaa}, + {0x00, 0x79, 0x01, 0xaa}, + {0x00, 0xc8, 0xf0, 0xaa}, + {0x00, 0x79, 0x0f, 0xaa}, + {0x00, 0xc8, 0x00, 0xaa}, + {0x00, 0x79, 0x10, 0xaa}, + {0x00, 0xc8, 0x7e, 0xaa}, + {0x00, 0x79, 0x0a, 0xaa}, + {0x00, 0xc8, 0x80, 0xaa}, + {0x00, 0x79, 0x0b, 0xaa}, + {0x00, 0xc8, 0x01, 0xaa}, + {0x00, 0x79, 0x0c, 0xaa}, + {0x00, 0xc8, 0x0f, 0xaa}, + {0x00, 0x79, 0x0d, 0xaa}, + {0x00, 0xc8, 0x20, 0xaa}, + {0x00, 0x79, 0x09, 0xaa}, + {0x00, 0xc8, 0x80, 0xaa}, + {0x00, 0x79, 0x02, 0xaa}, + {0x00, 0xc8, 0xc0, 0xaa}, + {0x00, 0x79, 0x03, 0xaa}, + {0x00, 0xc8, 0x40, 0xaa}, + {0x00, 0x79, 0x05, 0xaa}, + {0x00, 0xc8, 0x30, 0xaa}, + {0x00, 0x79, 0x26, 0xaa}, + {0x00, 0x11, 0x40, 0xaa}, + {0x00, 0x3a, 0x04, 0xaa}, + {0x00, 0x12, 0x00, 0xaa}, + {0x00, 0x40, 0xc0, 0xaa}, + {0x00, 0x8c, 0x00, 0xaa}, + {0x00, 0x17, 0x14, 0xaa}, + {0x00, 0x18, 0x02, 0xaa}, + {0x00, 0x32, 0x92, 0xaa}, + {0x00, 0x19, 0x02, 0xaa}, + {0x00, 0x1a, 0x7a, 0xaa}, + {0x00, 0x03, 0x0a, 0xaa}, + {0x00, 0x0c, 0x00, 0xaa}, + {0x00, 0x3e, 0x00, 0xaa}, + {0x00, 0x70, 0x3a, 0xaa}, + {0x00, 0x71, 0x35, 0xaa}, + {0x00, 0x72, 0x11, 0xaa}, + {0x00, 0x73, 0xf0, 0xaa}, + {0x00, 0xa2, 0x02, 0xaa}, + {0x00, 0xb1, 0x00, 0xaa}, + {0x00, 0xb1, 0x0c, 0xaa}, + {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */ + {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x24, 0x80, 0xaa}, + {0x00, 0x25, 0x74, 0xaa}, + {0x00, 0x26, 0xd3, 0xaa}, + {0x00, 0x0d, 0x00, 0xaa}, + {0x00, 0x14, 0x18, 0xaa}, + {0x00, 0x9d, 0x99, 0xaa}, + {0x00, 0x9e, 0x7f, 0xaa}, + {0x00, 0x64, 0x08, 0xaa}, + {0x00, 0x94, 0x07, 0xaa}, + {0x00, 0x95, 0x06, 0xaa}, + {0x00, 0x66, 0x05, 0xaa}, + {0x00, 0x41, 0x08, 0xaa}, + {0x00, 0x3f, 0x00, 0xaa}, + {0x00, 0x75, 0x07, 0xaa}, + {0x00, 0x76, 0xe1, 0xaa}, + {0x00, 0x4c, 0x00, 0xaa}, + {0x00, 0x77, 0x00, 0xaa}, + {0x00, 0x3d, 0xc2, 0xaa}, + {0x00, 0x4b, 0x09, 0xaa}, + {0x00, 0xc9, 0x60, 0xaa}, + {0x00, 0x41, 0x38, 0xaa}, + {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, + {0xbf, 0xc0, 0x26, 0xcc}, + {0xbf, 0xc1, 0x02, 0xcc}, + {0xbf, 0xcc, 0x04, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xb3, 0x01, 0x45, 0xcc}, + {0x00, 0x77, 0x05, 0xaa}, + {}, +}; + +/* PO1200 - values from usbvm326.inf and ms-win trace */ +static const u8 po1200_gamma[17] = { + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +}; +static const u8 po1200_matrix[9] = { + 0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e +}; +static const u8 po1200_initVGA_data[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, /* reset? */ + {0xb0, 0x03, 0x19, 0xcc}, +/* {0x00, 0x00, 0x33, 0xdd}, */ + {0xb0, 0x04, 0x02, 0xcc}, + {0xb0, 0x02, 0x02, 0xcc}, + {0xb3, 0x5d, 0x00, 0xcc}, + {0xb3, 0x01, 0x01, 0xcc}, + {0xb3, 0x00, 0x64, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb3, 0x02, 0xb2, 0xcc}, + {0xb3, 0x03, 0x18, 0xcc}, + {0xb3, 0x04, 0x15, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x02, 0xcc}, + {0xb3, 0x23, 0x58, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x03, 0xcc}, + {0xb3, 0x17, 0x1f, 0xcc}, + {0xbc, 0x00, 0x71, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0xb0, 0x54, 0x13, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0xdc, 0xcc}, /* i2c add: 5c */ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x12, 0x05, 0xaa}, + {0x00, 0x13, 0x02, 0xaa}, + {0x00, 0x1e, 0xc6, 0xaa}, /* h/v flip */ + {0x00, 0x21, 0x00, 0xaa}, + {0x00, 0x25, 0x02, 0xaa}, + {0x00, 0x3c, 0x4f, 0xaa}, + {0x00, 0x3f, 0xe0, 0xaa}, + {0x00, 0x42, 0xff, 0xaa}, + {0x00, 0x45, 0x34, 0xaa}, + {0x00, 0x55, 0xfe, 0xaa}, + {0x00, 0x59, 0xd3, 0xaa}, + {0x00, 0x5e, 0x04, 0xaa}, + {0x00, 0x61, 0xb8, 0xaa}, /* sharpness */ + {0x00, 0x62, 0x02, 0xaa}, + {0x00, 0xa7, 0x31, 0xaa}, + {0x00, 0xa9, 0x66, 0xaa}, + {0x00, 0xb0, 0x00, 0xaa}, + {0x00, 0xb1, 0x00, 0xaa}, + {0x00, 0xb3, 0x11, 0xaa}, + {0x00, 0xb6, 0x26, 0xaa}, + {0x00, 0xb7, 0x20, 0xaa}, + {0x00, 0xba, 0x04, 0xaa}, + {0x00, 0x88, 0x42, 0xaa}, + {0x00, 0x89, 0x9a, 0xaa}, + {0x00, 0x8a, 0x88, 0xaa}, + {0x00, 0x8b, 0x8e, 0xaa}, + {0x00, 0x8c, 0x3e, 0xaa}, + {0x00, 0x8d, 0x90, 0xaa}, + {0x00, 0x8e, 0x87, 0xaa}, + {0x00, 0x8f, 0x96, 0xaa}, + {0x00, 0x90, 0x3d, 0xaa}, + {0x00, 0x64, 0x00, 0xaa}, + {0x00, 0x65, 0x10, 0xaa}, + {0x00, 0x66, 0x20, 0xaa}, + {0x00, 0x67, 0x2b, 0xaa}, + {0x00, 0x68, 0x36, 0xaa}, + {0x00, 0x69, 0x49, 0xaa}, + {0x00, 0x6a, 0x5a, 0xaa}, + {0x00, 0x6b, 0x7f, 0xaa}, + {0x00, 0x6c, 0x9b, 0xaa}, + {0x00, 0x6d, 0xba, 0xaa}, + {0x00, 0x6e, 0xd4, 0xaa}, + {0x00, 0x6f, 0xea, 0xaa}, + {0x00, 0x70, 0x00, 0xaa}, + {0x00, 0x71, 0x10, 0xaa}, + {0x00, 0x72, 0x20, 0xaa}, + {0x00, 0x73, 0x2b, 0xaa}, + {0x00, 0x74, 0x36, 0xaa}, + {0x00, 0x75, 0x49, 0xaa}, + {0x00, 0x76, 0x5a, 0xaa}, + {0x00, 0x77, 0x7f, 0xaa}, + {0x00, 0x78, 0x9b, 0xaa}, + {0x00, 0x79, 0xba, 0xaa}, + {0x00, 0x7a, 0xd4, 0xaa}, + {0x00, 0x7b, 0xea, 0xaa}, + {0x00, 0x7c, 0x00, 0xaa}, + {0x00, 0x7d, 0x10, 0xaa}, + {0x00, 0x7e, 0x20, 0xaa}, + {0x00, 0x7f, 0x2b, 0xaa}, + {0x00, 0x80, 0x36, 0xaa}, + {0x00, 0x81, 0x49, 0xaa}, + {0x00, 0x82, 0x5a, 0xaa}, + {0x00, 0x83, 0x7f, 0xaa}, + {0x00, 0x84, 0x9b, 0xaa}, + {0x00, 0x85, 0xba, 0xaa}, + {0x00, 0x86, 0xd4, 0xaa}, + {0x00, 0x87, 0xea, 0xaa}, + {0x00, 0x57, 0x2a, 0xaa}, + {0x00, 0x03, 0x01, 0xaa}, + {0x00, 0x04, 0x10, 0xaa}, + {0x00, 0x05, 0x10, 0xaa}, + {0x00, 0x06, 0x10, 0xaa}, + {0x00, 0x07, 0x10, 0xaa}, + {0x00, 0x08, 0x13, 0xaa}, + {0x00, 0x0a, 0x00, 0xaa}, + {0x00, 0x0b, 0x10, 0xaa}, + {0x00, 0x0c, 0x20, 0xaa}, + {0x00, 0x0d, 0x18, 0xaa}, + {0x00, 0x22, 0x01, 0xaa}, + {0x00, 0x23, 0x60, 0xaa}, + {0x00, 0x25, 0x08, 0xaa}, + {0x00, 0x26, 0x82, 0xaa}, + {0x00, 0x2e, 0x0f, 0xaa}, + {0x00, 0x2f, 0x1e, 0xaa}, + {0x00, 0x30, 0x2d, 0xaa}, + {0x00, 0x31, 0x3c, 0xaa}, + {0x00, 0x32, 0x4b, 0xaa}, + {0x00, 0x33, 0x5a, 0xaa}, + {0x00, 0x34, 0x69, 0xaa}, + {0x00, 0x35, 0x78, 0xaa}, + {0x00, 0x36, 0x87, 0xaa}, + {0x00, 0x37, 0x96, 0xaa}, + {0x00, 0x38, 0xa5, 0xaa}, + {0x00, 0x39, 0xb4, 0xaa}, + {0x00, 0x3a, 0xc3, 0xaa}, + {0x00, 0x3b, 0xd2, 0xaa}, + {0x00, 0x3c, 0xe1, 0xaa}, + {0x00, 0x3e, 0xff, 0xaa}, + {0x00, 0x3f, 0xff, 0xaa}, + {0x00, 0x40, 0xff, 0xaa}, + {0x00, 0x41, 0xff, 0xaa}, + {0x00, 0x42, 0xff, 0xaa}, + {0x00, 0x43, 0xff, 0xaa}, + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x20, 0xc4, 0xaa}, + {0x00, 0x13, 0x03, 0xaa}, + {0x00, 0x3c, 0x50, 0xaa}, + {0x00, 0x61, 0x6a, 0xaa}, /* sharpness? */ + {0x00, 0x51, 0x5b, 0xaa}, + {0x00, 0x52, 0x91, 0xaa}, + {0x00, 0x53, 0x4c, 0xaa}, + {0x00, 0x54, 0x50, 0xaa}, + {0x00, 0x56, 0x02, 0xaa}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x03, 0xcc}, + {0xb6, 0x02, 0x20, 0xcc}, + {0xb6, 0x05, 0x02, 0xcc}, + {0xb6, 0x04, 0x58, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x21, 0xcc}, + {0xb6, 0x18, 0x03, 0xcc}, + {0xb6, 0x17, 0xa9, 0xcc}, + {0xb6, 0x16, 0x80, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x00, 0xcc}, + {0xb8, 0x06, 0x20, 0xcc}, + {0xb8, 0x07, 0x03, 0xcc}, + {0xb8, 0x08, 0x58, 0xcc}, + {0xb8, 0x09, 0x02, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0xd9, 0x0f, 0xaa}, + {0x00, 0xda, 0xaa, 0xaa}, + {0x00, 0xd9, 0x10, 0xaa}, + {0x00, 0xda, 0xaa, 0xaa}, + {0x00, 0xd9, 0x11, 0xaa}, + {0x00, 0xda, 0x00, 0xaa}, + {0x00, 0xd9, 0x12, 0xaa}, + {0x00, 0xda, 0xff, 0xaa}, + {0x00, 0xd9, 0x13, 0xaa}, + {0x00, 0xda, 0xff, 0xaa}, + {0x00, 0xe8, 0x11, 0xaa}, + {0x00, 0xe9, 0x12, 0xaa}, + {0x00, 0xea, 0x5c, 0xaa}, + {0x00, 0xeb, 0xff, 0xaa}, + {0x00, 0xd8, 0x80, 0xaa}, + {0x00, 0xe6, 0x02, 0xaa}, + {0x00, 0xd6, 0x40, 0xaa}, + {0x00, 0xe3, 0x05, 0xaa}, + {0x00, 0xe0, 0x40, 0xaa}, + {0x00, 0xde, 0x03, 0xaa}, + {0x00, 0xdf, 0x03, 0xaa}, + {0x00, 0xdb, 0x02, 0xaa}, + {0x00, 0xdc, 0x00, 0xaa}, + {0x00, 0xdd, 0x03, 0xaa}, + {0x00, 0xe1, 0x08, 0xaa}, + {0x00, 0xe2, 0x01, 0xaa}, + {0x00, 0xd6, 0x40, 0xaa}, + {0x00, 0xe4, 0x40, 0xaa}, + {0x00, 0xa8, 0x8f, 0xaa}, + {0x00, 0xb4, 0x16, 0xaa}, + {0xb0, 0x02, 0x06, 0xcc}, + {0xb0, 0x18, 0x06, 0xcc}, + {0xb0, 0x19, 0x06, 0xcc}, + {0xb3, 0x5d, 0x18, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, + {0x00, 0xb4, 0x0e, 0xaa}, + {0x00, 0xb5, 0x49, 0xaa}, + {0x00, 0xb6, 0x1c, 0xaa}, + {0x00, 0xb7, 0x96, 0xaa}, +/* end of usbvm326.inf - start of ms-win trace */ + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x3d, 0xcc}, +/*read b306*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x1a, 0x09, 0xaa}, + {0x00, 0x1b, 0x8a, 0xaa}, +/*read b827*/ + {0xb8, 0x27, 0x00, 0xcc}, + {0xb8, 0x26, 0x60, 0xcc}, + {0xb8, 0x26, 0x60, 0xcc}, +/*gamma - to do?*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0xae, 0x84, 0xaa}, +/*gamma again*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x96, 0xa0, 0xaa}, +/*matrix*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x91, 0x35, 0xaa}, + {0x00, 0x92, 0x22, 0xaa}, +/*gamma*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x95, 0x85, 0xaa}, +/*matrix*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x4d, 0x20, 0xaa}, + {0xb8, 0x22, 0x40, 0xcc}, + {0xb8, 0x23, 0x40, 0xcc}, + {0xb8, 0x24, 0x40, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0x00, 0x00, 0x64, 0xdd}, + {0x00, 0x03, 0x01, 0xaa}, +/*read 46*/ + {0x00, 0x46, 0x3c, 0xaa}, + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x16, 0x40, 0xaa}, + {0x00, 0x17, 0x40, 0xaa}, + {0x00, 0x18, 0x40, 0xaa}, + {0x00, 0x19, 0x41, 0xaa}, + {0x00, 0x03, 0x01, 0xaa}, + {0x00, 0x46, 0x3c, 0xaa}, + {0x00, 0x00, 0x18, 0xdd}, +/*read bfff*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0xb4, 0x1c, 0xaa}, + {0x00, 0xb5, 0x92, 0xaa}, + {0x00, 0xb6, 0x39, 0xaa}, + {0x00, 0xb7, 0x24, 0xaa}, +/*write 89 0400 1415*/ + {} +}; + +static const u8 poxxxx_init_common[][4] = { + {0xb3, 0x00, 0x04, 0xcc}, + {0x00, 0x00, 0x10, 0xdd}, + {0xb3, 0x00, 0x64, 0xcc}, + {0x00, 0x00, 0x10, 0xdd}, + {0xb3, 0x00, 0x65, 0xcc}, + {0x00, 0x00, 0x10, 0xdd}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb0, 0x03, 0x09, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0xf6, 0xcc}, /* i2c add: 76 */ + {0xb3, 0x02, 0xb0, 0xcc}, + {0xb3, 0x03, 0x18, 0xcc}, + {0xb3, 0x04, 0x15, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x04, 0xcc}, /* sensor height = 1024 */ + {0xb3, 0x23, 0x00, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x04, 0xcc}, /* sensor width = 1280 */ + {0xb3, 0x17, 0xff, 0xcc}, + {0xb3, 0x2c, 0x03, 0xcc}, + {0xb3, 0x2d, 0x56, 0xcc}, + {0xb3, 0x2e, 0x02, 0xcc}, + {0xb3, 0x2f, 0x0a, 0xcc}, + {0xb3, 0x40, 0x00, 0xcc}, + {0xb3, 0x41, 0x34, 0xcc}, + {0xb3, 0x42, 0x01, 0xcc}, + {0xb3, 0x43, 0xe0, 0xcc}, + {0xbc, 0x00, 0x71, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xb3, 0x4d, 0x00, 0xcc}, + {0x00, 0x0b, 0x2a, 0xaa}, + {0x00, 0x0e, 0x03, 0xaa}, + {0x00, 0x0f, 0xea, 0xaa}, + {0x00, 0x12, 0x08, 0xaa}, + {0x00, 0x1e, 0x06, 0xaa}, + {0x00, 0x21, 0x00, 0xaa}, + {0x00, 0x31, 0x1f, 0xaa}, + {0x00, 0x33, 0x38, 0xaa}, + {0x00, 0x36, 0xc0, 0xaa}, + {0x00, 0x37, 0xc8, 0xaa}, + {0x00, 0x3b, 0x36, 0xaa}, + {0x00, 0x4b, 0xfe, 0xaa}, + {0x00, 0x4d, 0x2e, 0xaa}, + {0x00, 0x51, 0x1c, 0xaa}, + {0x00, 0x52, 0x01, 0xaa}, + {0x00, 0x55, 0x0a, 0xaa}, + {0x00, 0x56, 0x0a, 0xaa}, + {0x00, 0x57, 0x07, 0xaa}, + {0x00, 0x58, 0x07, 0xaa}, + {0x00, 0x59, 0x04, 0xaa}, + {0x00, 0x70, 0x68, 0xaa}, + {0x00, 0x71, 0x04, 0xaa}, + {0x00, 0x72, 0x10, 0xaa}, + {0x00, 0x80, 0x71, 0xaa}, + {0x00, 0x81, 0x08, 0xaa}, + {0x00, 0x82, 0x00, 0xaa}, + {0x00, 0x83, 0x55, 0xaa}, + {0x00, 0x84, 0x06, 0xaa}, + {0x00, 0x85, 0x06, 0xaa}, + {0x00, 0x8b, 0x25, 0xaa}, + {0x00, 0x8c, 0x00, 0xaa}, + {0x00, 0x8d, 0x86, 0xaa}, + {0x00, 0x8e, 0x82, 0xaa}, + {0x00, 0x8f, 0x2d, 0xaa}, + {0x00, 0x90, 0x8b, 0xaa}, + {0x00, 0x91, 0x81, 0xaa}, + {0x00, 0x92, 0x81, 0xaa}, + {0x00, 0x93, 0x23, 0xaa}, + {0x00, 0xa3, 0x2a, 0xaa}, + {0x00, 0xa4, 0x03, 0xaa}, + {0x00, 0xa5, 0xea, 0xaa}, + {0x00, 0xb0, 0x68, 0xaa}, + {0x00, 0xbc, 0x04, 0xaa}, + {0x00, 0xbe, 0x3b, 0xaa}, + {0x00, 0x4e, 0x40, 0xaa}, + {0x00, 0x06, 0x04, 0xaa}, + {0x00, 0x07, 0x03, 0xaa}, + {0x00, 0xcd, 0x18, 0xaa}, + {0x00, 0x28, 0x03, 0xaa}, + {0x00, 0x29, 0xef, 0xaa}, +/* reinit on alt 2 (qvga) or alt7 (vga) */ + {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, + {0xb8, 0x00, 0x01, 0xcc}, + + {0x00, 0x1d, 0x85, 0xaa}, + {0x00, 0x1e, 0xc6, 0xaa}, + {0x00, 0x00, 0x40, 0xdd}, + {0x00, 0x1d, 0x05, 0xaa}, + {} +}; +static const u8 poxxxx_gamma[][4] = { + {0x00, 0xd6, 0x22, 0xaa}, /* gamma 0 */ + {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x0a, 0xaa}, + {0x00, 0x75, 0x16, 0xaa}, + {0x00, 0x76, 0x25, 0xaa}, + {0x00, 0x77, 0x34, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, + {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, + {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, + {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, + + {0x00, 0xd6, 0x62, 0xaa}, /* gamma 1 */ + {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x0a, 0xaa}, + {0x00, 0x75, 0x16, 0xaa}, + {0x00, 0x76, 0x25, 0xaa}, + {0x00, 0x77, 0x34, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, + {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, + {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, + {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, + + {0x00, 0xd6, 0xa2, 0xaa}, /* gamma 2 */ + {0x00, 0x73, 0x00, 0xaa}, + {0x00, 0x74, 0x0a, 0xaa}, + {0x00, 0x75, 0x16, 0xaa}, + {0x00, 0x76, 0x25, 0xaa}, + {0x00, 0x77, 0x34, 0xaa}, + {0x00, 0x78, 0x49, 0xaa}, + {0x00, 0x79, 0x5a, 0xaa}, + {0x00, 0x7a, 0x7f, 0xaa}, + {0x00, 0x7b, 0x9b, 0xaa}, + {0x00, 0x7c, 0xba, 0xaa}, + {0x00, 0x7d, 0xd4, 0xaa}, + {0x00, 0x7e, 0xea, 0xaa}, + {} +}; +static const u8 poxxxx_init_start_3[][4] = { + {0x00, 0xb8, 0x28, 0xaa}, + {0x00, 0xb9, 0x1e, 0xaa}, + {0x00, 0xb6, 0x14, 0xaa}, + {0x00, 0xb7, 0x0f, 0xaa}, + {0x00, 0x5c, 0x10, 0xaa}, + {0x00, 0x5d, 0x18, 0xaa}, + {0x00, 0x5e, 0x24, 0xaa}, + {0x00, 0x5f, 0x24, 0xaa}, + {0x00, 0x86, 0x1a, 0xaa}, + {0x00, 0x60, 0x00, 0xaa}, + {0x00, 0x61, 0x1b, 0xaa}, + {0x00, 0x62, 0x30, 0xaa}, + {0x00, 0x63, 0x40, 0xaa}, + {0x00, 0x87, 0x1a, 0xaa}, + {0x00, 0x64, 0x00, 0xaa}, + {0x00, 0x65, 0x08, 0xaa}, + {0x00, 0x66, 0x10, 0xaa}, + {0x00, 0x67, 0x20, 0xaa}, + {0x00, 0x88, 0x10, 0xaa}, + {0x00, 0x68, 0x00, 0xaa}, + {0x00, 0x69, 0x08, 0xaa}, + {0x00, 0x6a, 0x0f, 0xaa}, + {0x00, 0x6b, 0x0f, 0xaa}, + {0x00, 0x89, 0x07, 0xaa}, + {0x00, 0xd5, 0x4c, 0xaa}, + {0x00, 0x0a, 0x00, 0xaa}, + {0x00, 0x0b, 0x2a, 0xaa}, + {0x00, 0x0e, 0x03, 0xaa}, + {0x00, 0x0f, 0xea, 0xaa}, + {0x00, 0xa2, 0x00, 0xaa}, + {0x00, 0xa3, 0x2a, 0xaa}, + {0x00, 0xa4, 0x03, 0xaa}, + {0x00, 0xa5, 0xea, 0xaa}, + {} +}; +static const u8 poxxxx_initVGA[][4] = { + {0x00, 0x20, 0x11, 0xaa}, + {0x00, 0x33, 0x38, 0xaa}, + {0x00, 0xbb, 0x0d, 0xaa}, + {0xb3, 0x22, 0x01, 0xcc}, /* change to 640x480 */ + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x02, 0xb0, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0x00, 0x04, 0x06, 0xaa}, + {0x00, 0x05, 0x3f, 0xaa}, + {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */ + {} +}; +static const u8 poxxxx_initQVGA[][4] = { + {0x00, 0x20, 0x33, 0xaa}, + {0x00, 0x33, 0x38, 0xaa}, + {0x00, 0xbb, 0x0d, 0xaa}, + {0xb3, 0x22, 0x00, 0xcc}, /* change to 320x240 */ + {0xb3, 0x23, 0xf0, 0xcc}, + {0xb3, 0x16, 0x01, 0xcc}, + {0xb3, 0x17, 0x3f, 0xcc}, + {0xb3, 0x02, 0xb0, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x5c, 0x00, 0xcc}, + {0x00, 0x04, 0x06, 0xaa}, + {0x00, 0x05, 0x3f, 0xaa}, + {0x00, 0x04, 0x00, 0xdd}, /* delay 1s */ + {} +}; +static const u8 poxxxx_init_end_1[][4] = { + {0x00, 0x47, 0x25, 0xaa}, + {0x00, 0x48, 0x80, 0xaa}, + {0x00, 0x49, 0x1f, 0xaa}, + {0x00, 0x4a, 0x40, 0xaa}, + {0x00, 0x44, 0x40, 0xaa}, + {0x00, 0xab, 0x4a, 0xaa}, + {0x00, 0xb1, 0x00, 0xaa}, + {0x00, 0xb2, 0x04, 0xaa}, + {0x00, 0xb3, 0x08, 0xaa}, + {0x00, 0xb4, 0x0b, 0xaa}, + {0x00, 0xb5, 0x0d, 0xaa}, + {} +}; +static const u8 poxxxx_init_end_2[][4] = { + {0x00, 0x1d, 0x85, 0xaa}, + {0x00, 0x1e, 0x06, 0xaa}, + {0x00, 0x1d, 0x05, 0xaa}, + {} +}; + +struct sensor_info { + s8 sensorId; + u8 I2cAdd; + u8 IdAdd; + u16 VpId; + u8 m1; + u8 m2; + u8 op; +}; + +/* probe values */ +static const struct sensor_info vc0321_probe_data[] = { +/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */ +/* 0 OV9640 */ + {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, +/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */ + {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01}, +/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/ + {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01}, +/* 3 MI1310 */ + {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01}, +/* 4 MI360 - tested in vc032x_probe_sensor */ +/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */ +/* 5 7131R */ + {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01}, +/* 6 OV7649 */ + {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05}, +/* 7 PAS302BCW */ + {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05}, +/* 8 OV7660 */ + {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05}, +/* 9 PO3130NC - (tested in vc032x_probe_sensor) */ +/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */ +/* 10 PO1030KC */ + {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01}, +/* 11 MI1310_SOC */ + {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01}, +/* 12 OV9650 */ + {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, +/* 13 S5K532 */ + {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01}, +/* 14 MI360_SOC - ??? */ +/* 15 PO1200N */ + {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01}, +/* 16 PO3030K */ + {-1, 0x80 | 0x18, 0x00, 0x0000, 0x24, 0x25, 0x01}, +/* 17 PO2030 */ + {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01}, +/* ?? */ + {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01}, + {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01}, +}; +static const struct sensor_info vc0323_probe_data[] = { +/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */ +/* 0 OV9640 */ + {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, +/* 1 ICM108T (may respond on IdAdd == 0x83 - tested in vc032x_probe_sensor) */ + {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01}, +/* 2 PO2130 (may detect PO3130NC - tested in vc032x_probe_sensor)*/ + {-1, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01}, +/* 3 MI1310 */ + {-1, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01}, +/* 4 MI360 - tested in vc032x_probe_sensor */ +/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */ +/* 5 7131R */ + {SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01}, +/* 6 OV7649 */ + {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05}, +/* 7 PAS302BCW */ + {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05}, +/* 8 OV7660 */ + {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05}, +/* 9 PO3130NC - (tested in vc032x_probe_sensor) */ +/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01}, */ +/* 10 PO1030KC */ + {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01}, +/* 11 MI1310_SOC */ + {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01}, +/* 12 OV9650 */ + {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, +/* 13 S5K532 */ + {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01}, +/* 14 MI360_SOC - ??? */ +/* 15 PO1200N */ + {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01}, +/* 16 ?? */ + {-1, 0x80 | 0x2d, 0x00, 0x0000, 0x65, 0x67, 0x01}, +/* 17 PO2030 */ + {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01}, +/* ?? */ + {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01}, + {SENSOR_MI1320_SOC, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x67, 0x01}, +/*fixme: not in the ms-win probe - may be found before? */ + {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05}, +}; + +/* read 'len' bytes in gspca_dev->usb_buf */ +static void reg_r_i(struct gspca_dev *gspca_dev, + u16 req, + u16 index, + u16 len) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, /* value */ + index, gspca_dev->usb_buf, len, + 500); + if (ret < 0) { + err("reg_r err %d", ret); + gspca_dev->usb_err = ret; + } +} +static void reg_r(struct gspca_dev *gspca_dev, + u16 req, + u16 index, + u16 len) +{ + reg_r_i(gspca_dev, req, index, len); +#ifdef GSPCA_DEBUG + if (gspca_dev->usb_err < 0) + return; + if (len == 1) + PDEBUG(D_USBI, "GET %02x 0001 %04x %02x", req, index, + gspca_dev->usb_buf[0]); + else + PDEBUG(D_USBI, "GET %02x 0001 %04x %02x %02x %02x", + req, index, + gspca_dev->usb_buf[0], + gspca_dev->usb_buf[1], + gspca_dev->usb_buf[2]); +#endif +} + +static void reg_w_i(struct gspca_dev *gspca_dev, + u16 req, + u16 value, + u16 index) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, + 500); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} +static void reg_w(struct gspca_dev *gspca_dev, + u16 req, + u16 value, + u16 index) +{ +#ifdef GSPCA_DEBUG + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index); +#endif + reg_w_i(gspca_dev, req, value, index); +} + +static u16 read_sensor_register(struct gspca_dev *gspca_dev, + u16 address) +{ + u8 ldata, mdata, hdata; + int retry = 50; + + reg_r(gspca_dev, 0xa1, 0xb33f, 1); + if (!(gspca_dev->usb_buf[0] & 0x02)) { + err("I2c Bus Busy Wait %02x", + gspca_dev->usb_buf[0]); + return 0; + } + reg_w(gspca_dev, 0xa0, address, 0xb33a); + reg_w(gspca_dev, 0xa0, 0x02, 0xb339); + + do { + reg_r(gspca_dev, 0xa1, 0xb33b, 1); + if (gspca_dev->usb_buf[0] == 0x00) + break; + msleep(40); + } while (--retry >= 0); + + reg_r(gspca_dev, 0xa1, 0xb33e, 1); + ldata = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0xa1, 0xb33d, 1); + mdata = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0xa1, 0xb33c, 1); + hdata = gspca_dev->usb_buf[0]; + if (hdata != 0 && mdata != 0 && ldata != 0) + PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x", + hdata, mdata, ldata); + reg_r(gspca_dev, 0xa1, 0xb334, 1); + if (gspca_dev->usb_buf[0] == 0x02) + return (hdata << 8) + mdata; + return hdata; +} + +static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, n; + u16 value; + const struct sensor_info *ptsensor_info; + +/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/ + if (sd->flags & FL_SAMSUNG) { + reg_w(gspca_dev, 0xa0, 0x01, 0xb301); + reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff); + /* select the back sensor */ + } + + reg_r(gspca_dev, 0xa1, 0xbfcf, 1); + PDEBUG(D_PROBE, "vc032%d check sensor header %02x", + sd->bridge == BRIDGE_VC0321 ? 1 : 3, gspca_dev->usb_buf[0]); + if (sd->bridge == BRIDGE_VC0321) { + ptsensor_info = vc0321_probe_data; + n = ARRAY_SIZE(vc0321_probe_data); + } else { + ptsensor_info = vc0323_probe_data; + n = ARRAY_SIZE(vc0323_probe_data); + } + for (i = 0; i < n; i++) { + reg_w(gspca_dev, 0xa0, 0x02, 0xb334); + reg_w(gspca_dev, 0xa0, ptsensor_info->m1, 0xb300); + reg_w(gspca_dev, 0xa0, ptsensor_info->m2, 0xb300); + reg_w(gspca_dev, 0xa0, 0x01, 0xb308); + reg_w(gspca_dev, 0xa0, 0x0c, 0xb309); + reg_w(gspca_dev, 0xa0, ptsensor_info->I2cAdd, 0xb335); + reg_w(gspca_dev, 0xa0, ptsensor_info->op, 0xb301); + value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd); + if (value == 0 && ptsensor_info->IdAdd == 0x82) + value = read_sensor_register(gspca_dev, 0x83); + if (value != 0) { + PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)", + value, i); + if (value == ptsensor_info->VpId) + return ptsensor_info->sensorId; + + switch (value) { + case 0x3130: + return SENSOR_PO3130NC; + case 0x7673: + return SENSOR_OV7670; + case 0x8243: + return SENSOR_MI0360; + } + } + ptsensor_info++; + } + return -1; +} + +static void i2c_write(struct gspca_dev *gspca_dev, + u8 reg, const u8 *val, + u8 size) /* 1 or 2 */ +{ + int retry; + +#ifdef GSPCA_DEBUG + if (gspca_dev->usb_err < 0) + return; + if (size == 1) + PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val); + else + PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]); +#endif + reg_r_i(gspca_dev, 0xa1, 0xb33f, 1); +/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/ + reg_w_i(gspca_dev, 0xa0, size, 0xb334); + reg_w_i(gspca_dev, 0xa0, reg, 0xb33a); + reg_w_i(gspca_dev, 0xa0, val[0], 0xb336); + if (size > 1) + reg_w_i(gspca_dev, 0xa0, val[1], 0xb337); + reg_w_i(gspca_dev, 0xa0, 0x01, 0xb339); + retry = 4; + do { + reg_r_i(gspca_dev, 0xa1, 0xb33b, 1); + if (gspca_dev->usb_buf[0] == 0) + break; + msleep(20); + } while (--retry > 0); + if (retry <= 0) + err("i2c_write timeout"); +} + +static void put_tab_to_reg(struct gspca_dev *gspca_dev, + const u8 *tab, u8 tabsize, u16 addr) +{ + int j; + u16 ad = addr; + + for (j = 0; j < tabsize; j++) + reg_w(gspca_dev, 0xa0, tab[j], ad++); +} + +static void usb_exchange(struct gspca_dev *gspca_dev, + const u8 data[][4]) +{ + int i = 0; + + for (;;) { + switch (data[i][3]) { + default: + return; + case 0xcc: /* normal write */ + reg_w(gspca_dev, 0xa0, data[i][2], + (data[i][0]) << 8 | data[i][1]); + break; + case 0xaa: /* i2c op */ + i2c_write(gspca_dev, data[i][1], &data[i][2], 1); + break; + case 0xbb: /* i2c op */ + i2c_write(gspca_dev, data[i][0], &data[i][1], 2); + break; + case 0xdd: + msleep(data[i][1] * 256 + data[i][2] + 10); + break; + } + i++; + } + /*not reached*/ +} + + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->bridge = id->driver_info >> 8; + sd->flags = id->driver_info & 0xff; + + if (id->idVendor == 0x046d && + (id->idProduct == 0x0892 || id->idProduct == 0x0896)) + sd->sensor = SENSOR_POxxxx; /* no probe */ + + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->hflip = HFLIP_DEF; + sd->vflip = VFLIP_DEF; + sd->lightfreq = FREQ_DEF; + sd->sharpness = SHARPNESS_DEF; + sd->gain = GAIN_DEF; + sd->exposure = EXPOSURE_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->backlight = BACKLIGHT_DEF; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + int sensor; + /* number of packets per ISOC message */ + static u8 npkt[NSENSORS] = { + [SENSOR_HV7131R] = 64, + [SENSOR_MI0360] = 32, + [SENSOR_MI1310_SOC] = 32, + [SENSOR_MI1320] = 64, + [SENSOR_MI1320_SOC] = 128, + [SENSOR_OV7660] = 32, + [SENSOR_OV7670] = 64, + [SENSOR_PO1200] = 128, + [SENSOR_PO3130NC] = 128, + [SENSOR_POxxxx] = 128, + }; + + if (sd->sensor != SENSOR_POxxxx) + sensor = vc032x_probe_sensor(gspca_dev); + else + sensor = sd->sensor; + + switch (sensor) { + case -1: + err("Unknown sensor..."); + return -EINVAL; + case SENSOR_HV7131R: + PDEBUG(D_PROBE, "Find Sensor HV7131R"); + break; + case SENSOR_MI0360: + PDEBUG(D_PROBE, "Find Sensor MI0360"); + sd->bridge = BRIDGE_VC0323; + break; + case SENSOR_MI1310_SOC: + PDEBUG(D_PROBE, "Find Sensor MI1310_SOC"); + break; + case SENSOR_MI1320: + PDEBUG(D_PROBE, "Find Sensor MI1320"); + break; + case SENSOR_MI1320_SOC: + PDEBUG(D_PROBE, "Find Sensor MI1320_SOC"); + break; + case SENSOR_OV7660: + PDEBUG(D_PROBE, "Find Sensor OV7660"); + break; + case SENSOR_OV7670: + PDEBUG(D_PROBE, "Find Sensor OV7670"); + break; + case SENSOR_PO1200: + PDEBUG(D_PROBE, "Find Sensor PO1200"); + break; + case SENSOR_PO3130NC: + PDEBUG(D_PROBE, "Find Sensor PO3130NC"); + break; + case SENSOR_POxxxx: + PDEBUG(D_PROBE, "Sensor POxxxx"); + break; + } + sd->sensor = sensor; + + cam = &gspca_dev->cam; + if (sd->bridge == BRIDGE_VC0321) { + cam->cam_mode = vc0321_mode; + cam->nmodes = ARRAY_SIZE(vc0321_mode); + } else { + switch (sensor) { + case SENSOR_PO1200: + cam->cam_mode = svga_mode; + cam->nmodes = ARRAY_SIZE(svga_mode); + break; + case SENSOR_MI1310_SOC: + cam->cam_mode = vc0323_mode; + cam->nmodes = ARRAY_SIZE(vc0323_mode); + break; + case SENSOR_MI1320_SOC: + cam->cam_mode = bi_mode; + cam->nmodes = ARRAY_SIZE(bi_mode); + break; + case SENSOR_OV7670: + cam->cam_mode = bi_mode; + cam->nmodes = ARRAY_SIZE(bi_mode) - 1; + break; + default: + cam->cam_mode = vc0323_mode; + cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1; + break; + } + } + cam->npkt = npkt[sd->sensor]; + gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; + + if (sd->sensor == SENSOR_OV7670) + sd->flags |= FL_HFLIP | FL_VFLIP; + + if (sd->bridge == BRIDGE_VC0321) { + reg_r(gspca_dev, 0x8a, 0, 3); + reg_w(gspca_dev, 0x87, 0x00, 0x0f0f); + reg_r(gspca_dev, 0x8b, 0, 3); + reg_w(gspca_dev, 0x88, 0x00, 0x0202); + if (sd->sensor == SENSOR_POxxxx) { + reg_r(gspca_dev, 0xa1, 0xb300, 1); + if (gspca_dev->usb_buf[0] != 0) { + reg_w(gspca_dev, 0xa0, 0x26, 0xb300); + reg_w(gspca_dev, 0xa0, 0x04, 0xb300); + } + reg_w(gspca_dev, 0xa0, 0x00, 0xb300); + } + } + return gspca_dev->usb_err; +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data; + + if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX)) + return; + data = sd->brightness; + if (data >= 0x80) + data &= 0x7f; + else + data = 0xff ^ data; + i2c_write(gspca_dev, 0x98, &data, 1); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX)) + return; + i2c_write(gspca_dev, 0x99, &sd->contrast, 1); +} + +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data; + + if (gspca_dev->ctrl_dis & (1 << COLORS_IDX)) + return; + data = sd->colors - (sd->colors >> 3) - 1; + i2c_write(gspca_dev, 0x94, &data, 1); + i2c_write(gspca_dev, 0x95, &sd->colors, 1); +} + +static void sethvflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data[2], hflip, vflip; + + hflip = sd->hflip; + if (sd->flags & FL_HFLIP) + hflip = !hflip; + vflip = sd->vflip; + if (sd->flags & FL_VFLIP) + vflip = !vflip; + switch (sd->sensor) { + case SENSOR_MI1310_SOC: + case SENSOR_MI1320: + case SENSOR_MI1320_SOC: + data[0] = data[1] = 0; /* select page 0 */ + i2c_write(gspca_dev, 0xf0, data, 2); + data[0] = sd->sensor == SENSOR_MI1310_SOC ? 0x03 : 0x01; + data[1] = 0x02 * hflip + | 0x01 * vflip; + i2c_write(gspca_dev, 0x20, data, 2); + break; + case SENSOR_OV7660: + case SENSOR_OV7670: + data[0] = sd->sensor == SENSOR_OV7660 ? 0x01 : 0x07; + data[0] |= OV7660_MVFP_MIRROR * hflip + | OV7660_MVFP_VFLIP * vflip; + i2c_write(gspca_dev, OV7660_REG_MVFP, data, 1); + break; + case SENSOR_PO1200: + data[0] = 0; + i2c_write(gspca_dev, 0x03, data, 1); + data[0] = 0x80 * hflip + | 0x40 * vflip + | 0x06; + i2c_write(gspca_dev, 0x1e, data, 1); + break; + } +} + +static void setlightfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + static const u8 (*ov7660_freq_tb[3])[4] = + {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ}; + + if (sd->sensor != SENSOR_OV7660) + return; + usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]); +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data; + + switch (sd->sensor) { + case SENSOR_PO1200: + data = 0; + i2c_write(gspca_dev, 0x03, &data, 1); + if (sd->sharpness < 0) + data = 0x6a; + else + data = 0xb5 + sd->sharpness * 3; + i2c_write(gspca_dev, 0x61, &data, 1); + break; + case SENSOR_POxxxx: + if (sd->sharpness < 0) + data = 0x7e; /* def = max */ + else + data = 0x60 + sd->sharpness * 0x0f; + i2c_write(gspca_dev, 0x59, &data, 1); + break; + } +} +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (gspca_dev->ctrl_dis & (1 << GAIN_IDX)) + return; + i2c_write(gspca_dev, 0x15, &sd->gain, 1); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 data; + + if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) + return; + data = sd->exposure >> 8; + i2c_write(gspca_dev, 0x1a, &data, 1); + data = sd->exposure; + i2c_write(gspca_dev, 0x1b, &data, 1); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + static const u8 data[2] = {0x28, 0x3c}; + + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) + return; + i2c_write(gspca_dev, 0xd1, &data[sd->autogain], 1); +} + +static void setgamma(struct gspca_dev *gspca_dev) +{ +/*fixme:to do */ + usb_exchange(gspca_dev, poxxxx_gamma); +} + +static void setbacklight(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 v; + u8 data; + + data = (sd->backlight << 4) | 0x0f; + i2c_write(gspca_dev, 0xaa, &data, 1); + v = 613 + 12 * sd->backlight; + data = v >> 8; + i2c_write(gspca_dev, 0xc4, &data, 1); + data = v; + i2c_write(gspca_dev, 0xc5, &data, 1); + v = 1093 - 12 * sd->backlight; + data = v >> 8; + i2c_write(gspca_dev, 0xc6, &data, 1); + data = v; + i2c_write(gspca_dev, 0xc7, &data, 1); + v = 342 + 9 * sd->backlight; + data = v >> 8; + i2c_write(gspca_dev, 0xc8, &data, 1); + data = v; + i2c_write(gspca_dev, 0xc9, &data, 1); + v = 702 - 9 * sd->backlight; + data = v >> 8; + i2c_write(gspca_dev, 0xca, &data, 1); + data = v; + i2c_write(gspca_dev, 0xcb, &data, 1); +} + +static void setwb(struct gspca_dev *gspca_dev) +{ +/*fixme:to do - valid when reg d1 = 0x1c - (reg16 + reg15 = 0xa3)*/ + static const u8 data[2] = {0x00, 0x00}; + + i2c_write(gspca_dev, 0x16, &data[0], 1); + i2c_write(gspca_dev, 0x18, &data[1], 1); +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + const u8 (*init)[4]; + const u8 *GammaT = NULL; + const u8 *MatrixT = NULL; + int mode; + static const u8 (*mi1320_soc_init[])[4] = { + mi1320_soc_InitSXGA, + mi1320_soc_InitVGA, + mi1320_soc_InitQVGA, + }; + +/*fixme: back sensor only*/ + if (sd->flags & FL_SAMSUNG) { + reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff); + reg_w(gspca_dev, 0xa9, 0x8348, 0x000e); + reg_w(gspca_dev, 0xa9, 0x0000, 0x001a); + } + + /* Assume start use the good resolution from gspca_dev->mode */ + if (sd->bridge == BRIDGE_VC0321) { + reg_w(gspca_dev, 0xa0, 0xff, 0xbfec); + reg_w(gspca_dev, 0xa0, 0xff, 0xbfed); + reg_w(gspca_dev, 0xa0, 0xff, 0xbfee); + reg_w(gspca_dev, 0xa0, 0xff, 0xbfef); + sd->image_offset = 46; + } else { + if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat + == V4L2_PIX_FMT_JPEG) + sd->image_offset = 0; + else + sd->image_offset = 32; + } + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + switch (sd->sensor) { + case SENSOR_HV7131R: + GammaT = hv7131r_gamma; + MatrixT = hv7131r_matrix; + if (mode) + init = hv7131r_initQVGA_data; /* 320x240 */ + else + init = hv7131r_initVGA_data; /* 640x480 */ + break; + case SENSOR_OV7660: + GammaT = ov7660_gamma; + MatrixT = ov7660_matrix; + if (mode) + init = ov7660_initQVGA_data; /* 320x240 */ + else + init = ov7660_initVGA_data; /* 640x480 */ + break; + case SENSOR_MI0360: + GammaT = mi1320_gamma; + MatrixT = mi0360_matrix; + if (mode) + init = mi0360_initQVGA_JPG; /* 320x240 */ + else + init = mi0360_initVGA_JPG; /* 640x480 */ + break; + case SENSOR_MI1310_SOC: + GammaT = mi1320_gamma; + MatrixT = mi1320_matrix; + switch (mode) { + case 1: + init = mi1310_socinitQVGA_JPG; /* 320x240 */ + break; + case 0: + init = mi1310_socinitVGA_JPG; /* 640x480 */ + break; + default: + init = mi1310_soc_InitSXGA_JPG; /* 1280x1024 */ + break; + } + break; + case SENSOR_MI1320: + GammaT = mi1320_gamma; + MatrixT = mi1320_matrix; + if (mode) + init = mi1320_initQVGA_data; /* 320x240 */ + else + init = mi1320_initVGA_data; /* 640x480 */ + break; + case SENSOR_MI1320_SOC: + GammaT = mi1320_gamma; + MatrixT = mi1320_matrix; + init = mi1320_soc_init[mode]; + break; + case SENSOR_OV7670: + init = mode == 1 ? ov7670_InitVGA : ov7670_InitQVGA; + break; + case SENSOR_PO3130NC: + GammaT = po3130_gamma; + MatrixT = po3130_matrix; + if (mode) + init = po3130_initQVGA_data; /* 320x240 */ + else + init = po3130_initVGA_data; /* 640x480 */ + usb_exchange(gspca_dev, init); + init = po3130_rundata; + break; + case SENSOR_PO1200: + GammaT = po1200_gamma; + MatrixT = po1200_matrix; + init = po1200_initVGA_data; + break; + default: +/* case SENSOR_POxxxx: */ + usb_exchange(gspca_dev, poxxxx_init_common); + setgamma(gspca_dev); + setbacklight(gspca_dev); + setbrightness(gspca_dev); + setcontrast(gspca_dev); + setcolors(gspca_dev); + setsharpness(gspca_dev); + setautogain(gspca_dev); + setexposure(gspca_dev); + setgain(gspca_dev); + usb_exchange(gspca_dev, poxxxx_init_start_3); + if (mode) + init = poxxxx_initQVGA; + else + init = poxxxx_initVGA; + usb_exchange(gspca_dev, init); + reg_r(gspca_dev, 0x8c, 0x0000, 3); + reg_w(gspca_dev, 0xa0, + gspca_dev->usb_buf[2] & 1 ? 0 : 1, + 0xb35c); + msleep(300); +/*fixme: i2c read 04 and 05*/ + init = poxxxx_init_end_1; + break; + } + usb_exchange(gspca_dev, init); + if (GammaT && MatrixT) { + put_tab_to_reg(gspca_dev, GammaT, 17, 0xb84a); + put_tab_to_reg(gspca_dev, GammaT, 17, 0xb85b); + put_tab_to_reg(gspca_dev, GammaT, 17, 0xb86c); + put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c); + + switch (sd->sensor) { + case SENSOR_PO1200: + case SENSOR_HV7131R: + reg_w(gspca_dev, 0x89, 0x0400, 0x1415); + break; + case SENSOR_MI1310_SOC: + reg_w(gspca_dev, 0x89, 0x058c, 0x0000); + break; + } + msleep(100); + sethvflip(gspca_dev); + setlightfreq(gspca_dev); + } + switch (sd->sensor) { + case SENSOR_OV7670: + reg_w(gspca_dev, 0x87, 0xffff, 0xffff); + reg_w(gspca_dev, 0x88, 0xff00, 0xf0f1); + reg_w(gspca_dev, 0xa0, 0x0000, 0xbfff); + break; + case SENSOR_POxxxx: + usb_exchange(gspca_dev, poxxxx_init_end_2); + setwb(gspca_dev); + msleep(80); /* led on */ + reg_w(gspca_dev, 0x89, 0xffff, 0xfdff); + break; + } + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { + case SENSOR_MI1310_SOC: + reg_w(gspca_dev, 0x89, 0x058c, 0x00ff); + break; + case SENSOR_POxxxx: + return; + default: + if (!(sd->flags & FL_SAMSUNG)) + reg_w(gspca_dev, 0x89, 0xffff, 0xffff); + break; + } + reg_w(gspca_dev, 0xa0, 0x01, 0xb301); + reg_w(gspca_dev, 0xa0, 0x09, 0xb003); +} + +/* called on streamoff with alt 0 and on disconnect */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!gspca_dev->present) + return; +/*fixme: is this useful?*/ + if (sd->sensor == SENSOR_MI1310_SOC) + reg_w(gspca_dev, 0x89, 0x058c, 0x00ff); + else if (!(sd->flags & FL_SAMSUNG)) + reg_w(gspca_dev, 0x89, 0xffff, 0xffff); + + if (sd->sensor == SENSOR_POxxxx) { + reg_w(gspca_dev, 0xa0, 0x26, 0xb300); + reg_w(gspca_dev, 0xa0, 0x04, 0xb300); + reg_w(gspca_dev, 0xa0, 0x00, 0xb300); + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso pkt length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (data[0] == 0xff && data[1] == 0xd8) { + PDEBUG(D_PACK, + "vc032x header packet found len %d", len); + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + data += sd->image_offset; + len -= sd->image_offset; + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + return; + } + + /* The vc0321 sends some additional data after sending the complete + * frame, we ignore this. */ + if (sd->bridge == BRIDGE_VC0321) { + int size, l; + + l = gspca_dev->image_len; + size = gspca_dev->frsz; + if (len > size - l) + len = size - l; + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + setcontrast(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + return 0; +} + +static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->colors = val; + if (gspca_dev->streaming) + setcolors(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->colors; + return 0; +} + +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hflip; + return 0; +} + +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->vflip; + return 0; +} + +static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->lightfreq = val; + if (gspca_dev->streaming) + setlightfreq(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->lightfreq; + return 0; +} + +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) + setsharpness(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autogain = val; + if (gspca_dev->streaming) + setautogain(gspca_dev); + + return gspca_dev->usb_err; +} + +static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autogain; + return 0; +} + +static int sd_setbacklight(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->backlight = val; + if (gspca_dev->streaming) + setbacklight(gspca_dev); + + return gspca_dev->usb_err; +} + +static int sd_getbacklight(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->backlight; + return 0; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; + + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + if (menu->index >= ARRAY_SIZE(freq_nm)) + break; + strcpy((char *) menu->name, freq_nm[menu->index]); + return 0; + } + return -EINVAL; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, +}; + +/* -- module initialisation -- */ +#define BF(bridge, flags) \ + .driver_info = (BRIDGE_ ## bridge << 8) \ + | (flags) +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)}, + {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)}, + {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)}, + {USB_DEVICE(0x046d, 0x0897), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0x0321), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0x0323), BF(VC0323, 0)}, + {USB_DEVICE(0x0ac8, 0x0328), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0xc001), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0xc002), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, FL_SAMSUNG)}, + {USB_DEVICE(0x15b8, 0x6001), BF(VC0323, 0)}, + {USB_DEVICE(0x15b8, 0x6002), BF(VC0323, 0)}, + {USB_DEVICE(0x17ef, 0x4802), BF(VC0323, 0)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/vicam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/vicam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/vicam.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/vicam.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,381 @@ +/* + * gspca ViCam subdriver + * + * Copyright (C) 2011 Hans de Goede + * + * Based on the usbvideo vicam driver, which is: + * + * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), + * Christopher L Cheney (ccheney@cheney.cx), + * Pavel Machek (pavel@ucw.cz), + * John Tyner (jtyner@cs.ucr.edu), + * Monroe Williams (monroe@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, or + * any later version. + * + * 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 + */ + +#define MODULE_NAME "vicam" +#define HEADER_SIZE 64 + +#include +#include +#include +#include +#include "gspca.h" + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver"); +MODULE_LICENSE("GPL"); + +enum e_ctrl { + GAIN, + EXPOSURE, + NCTRL /* number of controls */ +}; + +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + struct work_struct work_struct; + struct workqueue_struct *work_thread; + struct gspca_ctrl ctrls[NCTRL]; +}; + +/* The vicam sensor has a resolution of 512 x 244, with I believe square + pixels, but this is forced to a 4:3 ratio by optics. So it has + non square pixels :( */ +static struct v4l2_pix_format vicam_mode[] = { + { 256, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 256, + .sizeimage = 256 * 122, + .colorspace = V4L2_COLORSPACE_SRGB,}, + /* 2 modes with somewhat more square pixels */ + { 256, 200, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 256, + .sizeimage = 256 * 200, + .colorspace = V4L2_COLORSPACE_SRGB,}, + { 256, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 256, + .sizeimage = 256 * 240, + .colorspace = V4L2_COLORSPACE_SRGB,}, +#if 0 /* This mode has extremely non square pixels, testing use only */ + { 512, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 512, + .sizeimage = 512 * 122, + .colorspace = V4L2_COLORSPACE_SRGB,}, +#endif + { 512, 244, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 512, + .sizeimage = 512 * 244, + .colorspace = V4L2_COLORSPACE_SRGB,}, +}; + +static const struct ctrl sd_ctrls[] = { +[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 200, + }, + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 2047, + .step = 1, + .default_value = 256, + }, + }, +}; + +static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request, + u16 value, u16 index, u8 *data, u16 len) +{ + int ret; + + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + request, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, data, len, 1000); + if (ret < 0) + err("control msg req %02X error %d", request, ret); + + return ret; +} + +static int vicam_set_camera_power(struct gspca_dev *gspca_dev, int state) +{ + int ret; + + ret = vicam_control_msg(gspca_dev, 0x50, state, 0, NULL, 0); + if (ret < 0) + return ret; + + if (state) + ret = vicam_control_msg(gspca_dev, 0x55, 1, 0, NULL, 0); + + return ret; +} + +/* + * request and read a block of data - see warning on vicam_command. + */ +static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size) +{ + struct sd *sd = (struct sd *)gspca_dev; + int ret, unscaled_height, act_len = 0; + u8 *req_data = gspca_dev->usb_buf; + + memset(req_data, 0, 16); + req_data[0] = sd->ctrls[GAIN].val; + if (gspca_dev->width == 256) + req_data[1] |= 0x01; /* low nibble x-scale */ + if (gspca_dev->height <= 122) { + req_data[1] |= 0x10; /* high nibble y-scale */ + unscaled_height = gspca_dev->height * 2; + } else + unscaled_height = gspca_dev->height; + req_data[2] = 0x90; /* unknown, does not seem to do anything */ + if (unscaled_height <= 200) + req_data[3] = 0x06; /* vend? */ + else if (unscaled_height <= 242) /* Yes 242 not 240 */ + req_data[3] = 0x07; /* vend? */ + else /* Up to 244 lines with req_data[3] == 0x08 */ + req_data[3] = 0x08; /* vend? */ + + if (sd->ctrls[EXPOSURE].val < 256) { + /* Frame rate maxed out, use partial frame expo time */ + req_data[4] = 255 - sd->ctrls[EXPOSURE].val; + req_data[5] = 0x00; + req_data[6] = 0x00; + req_data[7] = 0x01; + } else { + /* Modify frame rate */ + req_data[4] = 0x00; + req_data[5] = 0x00; + req_data[6] = sd->ctrls[EXPOSURE].val & 0xFF; + req_data[7] = sd->ctrls[EXPOSURE].val >> 8; + } + req_data[8] = ((244 - unscaled_height) / 2) & ~0x01; /* vstart */ + /* bytes 9-15 do not seem to affect exposure or image quality */ + + mutex_lock(&gspca_dev->usb_lock); + ret = vicam_control_msg(gspca_dev, 0x51, 0x80, 0, req_data, 16); + mutex_unlock(&gspca_dev->usb_lock); + if (ret < 0) + return ret; + + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x81), + data, size, &act_len, 10000); + /* successful, it returns 0, otherwise negative */ + if (ret < 0 || act_len != size) { + err("bulk read fail (%d) len %d/%d", + ret, act_len, size); + return -EIO; + } + return 0; +} + +/* This function is called as a workqueue function and runs whenever the camera + * is streaming data. Because it is a workqueue function it is allowed to sleep + * so we can use synchronous USB calls. To avoid possible collisions with other + * threads attempting to use the camera's USB interface we take the gspca + * usb_lock when performing USB operations. In practice the only thing we need + * to protect against is the usb_set_interface call that gspca makes during + * stream_off as the camera doesn't provide any controls that the user could try + * to change. + */ +static void vicam_dostream(struct work_struct *work) +{ + struct sd *sd = container_of(work, struct sd, work_struct); + struct gspca_dev *gspca_dev = &sd->gspca_dev; + int ret, frame_sz; + u8 *buffer; + + frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage + + HEADER_SIZE; + buffer = kmalloc(frame_sz, GFP_KERNEL | GFP_DMA); + if (!buffer) { + err("Couldn't allocate USB buffer"); + goto exit; + } + + while (gspca_dev->present && gspca_dev->streaming) { + ret = vicam_read_frame(gspca_dev, buffer, frame_sz); + if (ret < 0) + break; + + /* Note the frame header contents seem to be completely + constant, they do not change with either image, or + settings. So we simply discard it. The frames have + a very similar 64 byte footer, which we don't even + bother reading from the cam */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + buffer + HEADER_SIZE, + frame_sz - HEADER_SIZE); + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + } +exit: + kfree(buffer); +} + +/* This function is called at probe time just before sd_init */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam = &gspca_dev->cam; + struct sd *sd = (struct sd *)gspca_dev; + + /* We don't use the buffer gspca allocates so make it small. */ + cam->bulk = 1; + cam->bulk_size = 64; + cam->cam_mode = vicam_mode; + cam->nmodes = ARRAY_SIZE(vicam_mode); + cam->ctrls = sd->ctrls; + + INIT_WORK(&sd->work_struct, vicam_dostream); + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + int ret; + const struct ihex_binrec *rec; + const struct firmware *uninitialized_var(fw); + u8 *firmware_buf; + + ret = request_ihex_firmware(&fw, "vicam/firmware.fw", + &gspca_dev->dev->dev); + if (ret) { + err("Failed to load \"vicam/firmware.fw\": %d\n", ret); + return ret; + } + + firmware_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!firmware_buf) { + ret = -ENOMEM; + goto exit; + } + for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { + memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len)); + ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf, + be16_to_cpu(rec->len)); + if (ret < 0) + break; + } + + kfree(firmware_buf); +exit: + release_firmware(fw); + return ret; +} + +/* Set up for getting frames. */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + int ret; + + ret = vicam_set_camera_power(gspca_dev, 1); + if (ret < 0) + return ret; + + /* Start the workqueue function to do the streaming */ + sd->work_thread = create_singlethread_workqueue(MODULE_NAME); + queue_work(sd->work_thread, &sd->work_struct); + + return 0; +} + +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *)gspca_dev; + + /* wait for the work queue to terminate */ + mutex_unlock(&gspca_dev->usb_lock); + /* This waits for vicam_dostream to finish */ + destroy_workqueue(dev->work_thread); + dev->work_thread = NULL; + mutex_lock(&gspca_dev->usb_lock); + + vicam_set_camera_power(gspca_dev, 0); +} + +/* Table of supported USB devices */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x04c1, 0x009d)}, + {USB_DEVICE(0x0602, 0x1001)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, +}; + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + &sd_desc, + sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/w996Xcf.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/w996Xcf.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/w996Xcf.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/w996Xcf.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,558 @@ +/** + * + * GSPCA sub driver for W996[78]CF JPEG USB Dual Mode Camera Chip. + * + * Copyright (C) 2009 Hans de Goede + * + * This module is adapted from the in kernel v4l1 w9968cf driver: + * + * Copyright (C) 2002-2004 by Luca Risolia + * + * 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, or + * any later version. + * + * 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 + * + */ + +/* Note this is not a stand alone driver, it gets included in ov519.c, this + is a bit of a hack, but it needs the driver code for a lot of different + ov sensors which is already present in ov519.c (the old v4l1 driver used + the ovchipcam framework). When we have the time we really should move + the sensor drivers to v4l2 sub drivers, and properly split of this + driver from ov519.c */ + +#define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ + +#define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET]) +#define UV_QUANTABLE (&sd->jpeg_hdr[JPEG_QT1_OFFSET]) + +static const struct v4l2_pix_format w9968cf_vga_mode[] = { + {160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, + .bytesperline = 160 * 2, + .sizeimage = 160 * 120 * 2, + .colorspace = V4L2_COLORSPACE_JPEG}, + {176, 144, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, + .bytesperline = 176 * 2, + .sizeimage = 176 * 144 * 2, + .colorspace = V4L2_COLORSPACE_JPEG}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320 * 2, + .sizeimage = 320 * 240 * 2, + .colorspace = V4L2_COLORSPACE_JPEG}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352 * 2, + .sizeimage = 352 * 288 * 2, + .colorspace = V4L2_COLORSPACE_JPEG}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640 * 2, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_JPEG}, +}; + +static void reg_w(struct sd *sd, u16 index, u16 value); + +/*-------------------------------------------------------------------------- + Write 64-bit data to the fast serial bus registers. + Return 0 on success, -1 otherwise. + --------------------------------------------------------------------------*/ +static void w9968cf_write_fsb(struct sd *sd, u16* data) +{ + struct usb_device *udev = sd->gspca_dev.dev; + u16 value; + int ret; + + if (sd->gspca_dev.usb_err < 0) + return; + + value = *data++; + memcpy(sd->gspca_dev.usb_buf, data, 6); + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, + value, 0x06, sd->gspca_dev.usb_buf, 6, 500); + if (ret < 0) { + err("Write FSB registers failed (%d)", ret); + sd->gspca_dev.usb_err = ret; + } +} + +/*-------------------------------------------------------------------------- + Write data to the serial bus control register. + Return 0 on success, a negative number otherwise. + --------------------------------------------------------------------------*/ +static void w9968cf_write_sb(struct sd *sd, u16 value) +{ + int ret; + + if (sd->gspca_dev.usb_err < 0) + return; + + /* We don't use reg_w here, as that would cause all writes when + bitbanging i2c to be logged, making the logs impossible to read */ + ret = usb_control_msg(sd->gspca_dev.dev, + usb_sndctrlpipe(sd->gspca_dev.dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, 0x01, NULL, 0, 500); + + udelay(W9968CF_I2C_BUS_DELAY); + + if (ret < 0) { + err("Write SB reg [01] %04x failed", value); + sd->gspca_dev.usb_err = ret; + } +} + +/*-------------------------------------------------------------------------- + Read data from the serial bus control register. + Return 0 on success, a negative number otherwise. + --------------------------------------------------------------------------*/ +static int w9968cf_read_sb(struct sd *sd) +{ + int ret; + + if (sd->gspca_dev.usb_err < 0) + return -1; + + /* We don't use reg_r here, as the w9968cf is special and has 16 + bit registers instead of 8 bit */ + ret = usb_control_msg(sd->gspca_dev.dev, + usb_rcvctrlpipe(sd->gspca_dev.dev, 0), + 1, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0x01, sd->gspca_dev.usb_buf, 2, 500); + if (ret >= 0) { + ret = sd->gspca_dev.usb_buf[0] | + (sd->gspca_dev.usb_buf[1] << 8); + } else { + err("Read SB reg [01] failed"); + sd->gspca_dev.usb_err = ret; + } + + udelay(W9968CF_I2C_BUS_DELAY); + + return ret; +} + +/*-------------------------------------------------------------------------- + Upload quantization tables for the JPEG compression. + This function is called by w9968cf_start_transfer(). + Return 0 on success, a negative number otherwise. + --------------------------------------------------------------------------*/ +static void w9968cf_upload_quantizationtables(struct sd *sd) +{ + u16 a, b; + int i, j; + + reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */ + + for (i = 0, j = 0; i < 32; i++, j += 2) { + a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j + 1]) << 8); + b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j + 1]) << 8); + reg_w(sd, 0x40 + i, a); + reg_w(sd, 0x60 + i, b); + } + reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */ +} + +/**************************************************************************** + * Low-level I2C I/O functions. * + * The adapter supports the following I2C transfer functions: * + * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) * + * i2c_adap_read_byte_data() * + * i2c_adap_read_byte() * + ****************************************************************************/ + +static void w9968cf_smbus_start(struct sd *sd) +{ + w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */ + w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */ +} + +static void w9968cf_smbus_stop(struct sd *sd) +{ + w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */ + w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */ + w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */ +} + +static void w9968cf_smbus_write_byte(struct sd *sd, u8 v) +{ + u8 bit; + int sda; + + for (bit = 0 ; bit < 8 ; bit++) { + sda = (v & 0x80) ? 2 : 0; + v <<= 1; + /* SDE=1, SDA=sda, SCL=0 */ + w9968cf_write_sb(sd, 0x10 | sda); + /* SDE=1, SDA=sda, SCL=1 */ + w9968cf_write_sb(sd, 0x11 | sda); + /* SDE=1, SDA=sda, SCL=0 */ + w9968cf_write_sb(sd, 0x10 | sda); + } +} + +static void w9968cf_smbus_read_byte(struct sd *sd, u8 *v) +{ + u8 bit; + + /* No need to ensure SDA is high as we are always called after + read_ack which ends with SDA high */ + *v = 0; + for (bit = 0 ; bit < 8 ; bit++) { + *v <<= 1; + /* SDE=1, SDA=1, SCL=1 */ + w9968cf_write_sb(sd, 0x0013); + *v |= (w9968cf_read_sb(sd) & 0x0008) ? 1 : 0; + /* SDE=1, SDA=1, SCL=0 */ + w9968cf_write_sb(sd, 0x0012); + } +} + +static void w9968cf_smbus_write_nack(struct sd *sd) +{ + /* No need to ensure SDA is high as we are always called after + read_byte which ends with SDA high */ + w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */ + w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */ +} + +static void w9968cf_smbus_read_ack(struct sd *sd) +{ + int sda; + + /* Ensure SDA is high before raising clock to avoid a spurious stop */ + w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */ + w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */ + sda = w9968cf_read_sb(sd); + w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */ + if (sda >= 0 && (sda & 0x08)) { + PDEBUG(D_USBI, "Did not receive i2c ACK"); + sd->gspca_dev.usb_err = -EIO; + } +} + +/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ +static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value) +{ + u16* data = (u16 *)sd->gspca_dev.usb_buf; + + data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0); + data[0] |= (sd->sensor_addr & 0x40) ? 0x4000 : 0x0; + data[1] = 0x2082 | ((sd->sensor_addr & 0x40) ? 0x0005 : 0x0); + data[1] |= (sd->sensor_addr & 0x20) ? 0x0150 : 0x0; + data[1] |= (sd->sensor_addr & 0x10) ? 0x5400 : 0x0; + data[2] = 0x8208 | ((sd->sensor_addr & 0x08) ? 0x0015 : 0x0); + data[2] |= (sd->sensor_addr & 0x04) ? 0x0540 : 0x0; + data[2] |= (sd->sensor_addr & 0x02) ? 0x5000 : 0x0; + data[3] = 0x1d20 | ((sd->sensor_addr & 0x02) ? 0x0001 : 0x0); + data[3] |= (sd->sensor_addr & 0x01) ? 0x0054 : 0x0; + + w9968cf_write_fsb(sd, data); + + data[0] = 0x8208 | ((reg & 0x80) ? 0x0015 : 0x0); + data[0] |= (reg & 0x40) ? 0x0540 : 0x0; + data[0] |= (reg & 0x20) ? 0x5000 : 0x0; + data[1] = 0x0820 | ((reg & 0x20) ? 0x0001 : 0x0); + data[1] |= (reg & 0x10) ? 0x0054 : 0x0; + data[1] |= (reg & 0x08) ? 0x1500 : 0x0; + data[1] |= (reg & 0x04) ? 0x4000 : 0x0; + data[2] = 0x2082 | ((reg & 0x04) ? 0x0005 : 0x0); + data[2] |= (reg & 0x02) ? 0x0150 : 0x0; + data[2] |= (reg & 0x01) ? 0x5400 : 0x0; + data[3] = 0x001d; + + w9968cf_write_fsb(sd, data); + + data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); + data[0] |= (value & 0x40) ? 0x0540 : 0x0; + data[0] |= (value & 0x20) ? 0x5000 : 0x0; + data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0); + data[1] |= (value & 0x10) ? 0x0054 : 0x0; + data[1] |= (value & 0x08) ? 0x1500 : 0x0; + data[1] |= (value & 0x04) ? 0x4000 : 0x0; + data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0); + data[2] |= (value & 0x02) ? 0x0150 : 0x0; + data[2] |= (value & 0x01) ? 0x5400 : 0x0; + data[3] = 0xfe1d; + + w9968cf_write_fsb(sd, data); + + PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg); +} + +/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ +static int w9968cf_i2c_r(struct sd *sd, u8 reg) +{ + int ret = 0; + u8 value; + + /* Fast serial bus data control disable */ + w9968cf_write_sb(sd, 0x0013); /* don't change ! */ + + w9968cf_smbus_start(sd); + w9968cf_smbus_write_byte(sd, sd->sensor_addr); + w9968cf_smbus_read_ack(sd); + w9968cf_smbus_write_byte(sd, reg); + w9968cf_smbus_read_ack(sd); + w9968cf_smbus_stop(sd); + w9968cf_smbus_start(sd); + w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1); + w9968cf_smbus_read_ack(sd); + w9968cf_smbus_read_byte(sd, &value); + /* signal we don't want to read anymore, the v4l1 driver used to + send an ack here which is very wrong! (and then fixed + the issues this gave by retrying reads) */ + w9968cf_smbus_write_nack(sd); + w9968cf_smbus_stop(sd); + + /* Fast serial bus data control re-enable */ + w9968cf_write_sb(sd, 0x0030); + + if (sd->gspca_dev.usb_err >= 0) { + ret = value; + PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value); + } else + PDEBUG(D_ERR, "i2c read [0x%02x] failed", reg); + + return ret; +} + +/*-------------------------------------------------------------------------- + Turn on the LED on some webcams. A beep should be heard too. + Return 0 on success, a negative number otherwise. + --------------------------------------------------------------------------*/ +static void w9968cf_configure(struct sd *sd) +{ + reg_w(sd, 0x00, 0xff00); /* power-down */ + reg_w(sd, 0x00, 0xbf17); /* reset everything */ + reg_w(sd, 0x00, 0xbf10); /* normal operation */ + reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */ + reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */ + reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */ + reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */ + + sd->stopped = 1; +} + +static void w9968cf_init(struct sd *sd) +{ + unsigned long hw_bufsize = sd->sif ? (352 * 288 * 2) : (640 * 480 * 2), + y0 = 0x0000, + u0 = y0 + hw_bufsize / 2, + v0 = u0 + hw_bufsize / 4, + y1 = v0 + hw_bufsize / 4, + u1 = y1 + hw_bufsize / 2, + v1 = u1 + hw_bufsize / 4; + + reg_w(sd, 0x00, 0xff00); /* power off */ + reg_w(sd, 0x00, 0xbf10); /* power on */ + + reg_w(sd, 0x03, 0x405d); /* DRAM timings */ + reg_w(sd, 0x04, 0x0030); /* SDRAM timings */ + + reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */ + reg_w(sd, 0x21, y0 >> 16); /* Y buf.0, high */ + reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */ + reg_w(sd, 0x25, u0 >> 16); /* U buf.0, high */ + reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */ + reg_w(sd, 0x29, v0 >> 16); /* V buf.0, high */ + + reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */ + reg_w(sd, 0x23, y1 >> 16); /* Y buf.1, high */ + reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */ + reg_w(sd, 0x27, u1 >> 16); /* U buf.1, high */ + reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */ + reg_w(sd, 0x2b, v1 >> 16); /* V buf.1, high */ + + reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */ + reg_w(sd, 0x33, y1 >> 16); /* JPEG buf 0 high */ + + reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */ + reg_w(sd, 0x35, y1 >> 16); /* JPEG bug 1 high */ + + reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */ + reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/ + reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */ + reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */ +} + +static void w9968cf_set_crop_window(struct sd *sd) +{ + int start_cropx, start_cropy, x, y, fw, fh, cw, ch, + max_width, max_height; + + if (sd->sif) { + max_width = 352; + max_height = 288; + } else { + max_width = 640; + max_height = 480; + } + + if (sd->sensor == SEN_OV7620) { + /* Sigh, this is dependend on the clock / framerate changes + made by the frequency control, sick. */ + if (sd->ctrls[FREQ].val == 1) { + start_cropx = 277; + start_cropy = 37; + } else { + start_cropx = 105; + start_cropy = 37; + } + } else { + start_cropx = 320; + start_cropy = 35; + } + + /* Work around to avoid FP arithmetics */ + #define SC(x) ((x) << 10) + + /* Scaling factors */ + fw = SC(sd->gspca_dev.width) / max_width; + fh = SC(sd->gspca_dev.height) / max_height; + + cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width) / fh; + ch = (fw >= fh) ? SC(sd->gspca_dev.height) / fw : max_height; + + sd->sensor_width = max_width; + sd->sensor_height = max_height; + + x = (max_width - cw) / 2; + y = (max_height - ch) / 2; + + reg_w(sd, 0x10, start_cropx + x); + reg_w(sd, 0x11, start_cropy + y); + reg_w(sd, 0x12, start_cropx + x + cw); + reg_w(sd, 0x13, start_cropy + y + ch); +} + +static void w9968cf_mode_init_regs(struct sd *sd) +{ + int val, vs_polarity, hs_polarity; + + w9968cf_set_crop_window(sd); + + reg_w(sd, 0x14, sd->gspca_dev.width); + reg_w(sd, 0x15, sd->gspca_dev.height); + + /* JPEG width & height */ + reg_w(sd, 0x30, sd->gspca_dev.width); + reg_w(sd, 0x31, sd->gspca_dev.height); + + /* Y & UV frame buffer strides (in WORD) */ + if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == + V4L2_PIX_FMT_JPEG) { + reg_w(sd, 0x2c, sd->gspca_dev.width / 2); + reg_w(sd, 0x2d, sd->gspca_dev.width / 4); + } else + reg_w(sd, 0x2c, sd->gspca_dev.width); + + reg_w(sd, 0x00, 0xbf17); /* reset everything */ + reg_w(sd, 0x00, 0xbf10); /* normal operation */ + + /* Transfer size in WORDS (for UYVY format only) */ + val = sd->gspca_dev.width * sd->gspca_dev.height; + reg_w(sd, 0x3d, val & 0xffff); /* low bits */ + reg_w(sd, 0x3e, val >> 16); /* high bits */ + + if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == + V4L2_PIX_FMT_JPEG) { + /* We may get called multiple times (usb isoc bw negotiat.) */ + jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height, + sd->gspca_dev.width, 0x22); /* JPEG 420 */ + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + w9968cf_upload_quantizationtables(sd); + } + + /* Video Capture Control Register */ + if (sd->sensor == SEN_OV7620) { + /* Seems to work around a bug in the image sensor */ + vs_polarity = 1; + hs_polarity = 1; + } else { + vs_polarity = 1; + hs_polarity = 0; + } + + val = (vs_polarity << 12) | (hs_polarity << 11); + + /* NOTE: We may not have enough memory to do double buffering while + doing compression (amount of memory differs per model cam). + So we use the second image buffer also as jpeg stream buffer + (see w9968cf_init), and disable double buffering. */ + if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == + V4L2_PIX_FMT_JPEG) { + /* val |= 0x0002; YUV422P */ + val |= 0x0003; /* YUV420P */ + } else + val |= 0x0080; /* Enable HW double buffering */ + + /* val |= 0x0020; enable clamping */ + /* val |= 0x0008; enable (1-2-1) filter */ + /* val |= 0x000c; enable (2-3-6-3-2) filter */ + + val |= 0x8000; /* capt. enable */ + + reg_w(sd, 0x16, val); + + sd->gspca_dev.empty_packet = 0; +} + +static void w9968cf_stop0(struct sd *sd) +{ + reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */ + reg_w(sd, 0x16, 0x0000); /* stop video capture */ +} + +/* The w9968cf docs say that a 0 sized packet means EOF (and also SOF + for the next frame). This seems to simply not be true when operating + in JPEG mode, in this case there may be empty packets within the + frame. So in JPEG mode use the JPEG SOI marker to detect SOF. + + Note to make things even more interesting the w9968cf sends *PLANAR* jpeg, + to be precise it sends: SOI, SOF, DRI, SOS, Y-data, SOS, U-data, SOS, + V-data, EOI. */ +static void w9968cf_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (w9968cf_vga_mode[gspca_dev->curr_mode].pixelformat == + V4L2_PIX_FMT_JPEG) { + if (len >= 2 && + data[0] == 0xff && + data[1] == 0xd8) { + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + /* Strip the ff d8, our own header (which adds + huffman and quantization tables) already has this */ + len -= 2; + data += 2; + } + } else { + /* In UYVY mode an empty packet signals EOF */ + if (gspca_dev->empty_packet) { + gspca_frame_add(gspca_dev, LAST_PACKET, + NULL, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, + NULL, 0); + gspca_dev->empty_packet = 0; + } + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/xirlink_cit.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/xirlink_cit.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/xirlink_cit.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/xirlink_cit.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,3337 @@ +/* + * USB IBM C-It Video Camera driver + * + * Supports Xirlink C-It Video Camera, IBM PC Camera, + * IBM NetCamera and Veo Stingray. + * + * Copyright (C) 2010 Hans de Goede + * + * This driver is based on earlier work of: + * + * (C) Copyright 1999 Johannes Erdfelt + * (C) Copyright 1999 Randy Dunlap + * + * 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, or + * (at your option) any later version. + * + * 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 + * + */ + +#define MODULE_NAME "xirlink-cit" + +#include +#include "gspca.h" + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Xirlink C-IT"); +MODULE_LICENSE("GPL"); + +/* FIXME we should autodetect this */ +static int ibm_netcam_pro; +module_param(ibm_netcam_pro, int, 0); +MODULE_PARM_DESC(ibm_netcam_pro, + "Use IBM Netcamera Pro init sequences for Model 3 cams"); + +/* FIXME this should be handled through the V4L2 input selection API */ +static int rca_input; +module_param(rca_input, int, 0644); +MODULE_PARM_DESC(rca_input, + "Use rca input instead of ccd sensor on Model 3 cams"); + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + u8 model; +#define CIT_MODEL0 0 /* bcd version 0.01 cams ie the xvp-500 */ +#define CIT_MODEL1 1 /* The model 1 - 4 nomenclature comes from the old */ +#define CIT_MODEL2 2 /* ibmcam driver */ +#define CIT_MODEL3 3 +#define CIT_MODEL4 4 +#define CIT_IBM_NETCAM_PRO 5 + u8 input_index; + u8 button_state; + u8 stop_on_control_change; + u8 sof_read; + u8 sof_len; + u8 contrast; + u8 brightness; + u8 hue; + u8 sharpness; + u8 lighting; + u8 hflip; +}; + +/* V4L2 controls supported by the driver */ +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setlighting(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getlighting(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); +static void sd_stop0(struct gspca_dev *gspca_dev); + +static const struct ctrl sd_ctrls[] = { +#define SD_BRIGHTNESS 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 63, + .step = 1, +#define BRIGHTNESS_DEFAULT 32 + .default_value = BRIGHTNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, +#define SD_CONTRAST 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "contrast", + .minimum = 0, + .maximum = 20, + .step = 1, +#define CONTRAST_DEFAULT 10 + .default_value = CONTRAST_DEFAULT, + .flags = 0, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, +#define SD_HUE 2 + { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = 0, + .maximum = 127, + .step = 1, +#define HUE_DEFAULT 63 + .default_value = HUE_DEFAULT, + .flags = 0, + }, + .set = sd_sethue, + .get = sd_gethue, + }, +#define SD_SHARPNESS 3 + { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 6, + .step = 1, +#define SHARPNESS_DEFAULT 3 + .default_value = SHARPNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, +#define SD_LIGHTING 4 + { + { + .id = V4L2_CID_BACKLIGHT_COMPENSATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Lighting", + .minimum = 0, + .maximum = 2, + .step = 1, +#define LIGHTING_DEFAULT 1 + .default_value = LIGHTING_DEFAULT, + .flags = 0, + }, + .set = sd_setlighting, + .get = sd_getlighting, + }, +#define SD_HFLIP 5 + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, +#define HFLIP_DEFAULT 0 + .default_value = HFLIP_DEFAULT, + }, + .set = sd_sethflip, + .get = sd_gethflip, + }, +}; + +static const struct v4l2_pix_format cif_yuv_mode[] = { + {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, + {352, 288, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, +}; + +static const struct v4l2_pix_format vga_yuv_mode[] = { + {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, + {320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, + {640, 480, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, +}; + +static const struct v4l2_pix_format model0_mode[] = { + {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, + {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, + {320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, +}; + +static const struct v4l2_pix_format model2_mode[] = { + {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, + {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, + {320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, + {352, 288, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 + 4, + .colorspace = V4L2_COLORSPACE_SRGB}, +}; + +/* + * 01.01.08 - Added for RCA video in support -LO + * This struct is used to init the Model3 cam to use the RCA video in port + * instead of the CCD sensor. + */ +static const u16 rca_initdata[][3] = { + {0, 0x0000, 0x010c}, + {0, 0x0006, 0x012c}, + {0, 0x0078, 0x012d}, + {0, 0x0046, 0x012f}, + {0, 0xd141, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfea8, 0x0124}, + {1, 0x0000, 0x0116}, + {0, 0x0064, 0x0116}, + {1, 0x0000, 0x0115}, + {0, 0x0003, 0x0115}, + {0, 0x0008, 0x0123}, + {0, 0x0000, 0x0117}, + {0, 0x0000, 0x0112}, + {0, 0x0080, 0x0100}, + {0, 0x0000, 0x0100}, + {1, 0x0000, 0x0116}, + {0, 0x0060, 0x0116}, + {0, 0x0002, 0x0112}, + {0, 0x0000, 0x0123}, + {0, 0x0001, 0x0117}, + {0, 0x0040, 0x0108}, + {0, 0x0019, 0x012c}, + {0, 0x0040, 0x0116}, + {0, 0x000a, 0x0115}, + {0, 0x000b, 0x0115}, + {0, 0x0078, 0x012d}, + {0, 0x0046, 0x012f}, + {0, 0xd141, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfea8, 0x0124}, + {0, 0x0064, 0x0116}, + {0, 0x0000, 0x0115}, + {0, 0x0001, 0x0115}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00aa, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00f2, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x000f, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00f8, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00fc, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00f9, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x003c, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xffff, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0027, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0019, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0021, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0006, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0045, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002a, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x000e, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002b, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00f4, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002c, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0004, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002d, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0014, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002e, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0003, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x002f, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0003, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0014, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0053, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0x0000, 0x0101}, + {0, 0x00a0, 0x0103}, + {0, 0x0078, 0x0105}, + {0, 0x0000, 0x010a}, + {0, 0x0024, 0x010b}, + {0, 0x0028, 0x0119}, + {0, 0x0088, 0x011b}, + {0, 0x0002, 0x011d}, + {0, 0x0003, 0x011e}, + {0, 0x0000, 0x0129}, + {0, 0x00fc, 0x012b}, + {0, 0x0008, 0x0102}, + {0, 0x0000, 0x0104}, + {0, 0x0008, 0x011a}, + {0, 0x0028, 0x011c}, + {0, 0x0021, 0x012a}, + {0, 0x0000, 0x0118}, + {0, 0x0000, 0x0132}, + {0, 0x0000, 0x0109}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0031, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x00dc, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0032, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0020, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0001, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0040, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0037, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0030, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0xfff9, 0x0124}, + {0, 0x0086, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0038, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0008, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0x0000, 0x0127}, + {0, 0xfff8, 0x0124}, + {0, 0xfffd, 0x0124}, + {0, 0xfffa, 0x0124}, + {0, 0x0003, 0x0111}, +}; + +/* TESTME the old ibmcam driver repeats certain commands to Model1 cameras, we + do the same for now (testing needed to see if this is really necessary) */ +static const int cit_model1_ntries = 5; +static const int cit_model1_ntries2 = 2; + +static int cit_write_reg(struct gspca_dev *gspca_dev, u16 value, u16 index) +{ + struct usb_device *udev = gspca_dev->dev; + int err; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, + value, index, NULL, 0, 1000); + if (err < 0) + err("Failed to write a register (index 0x%04X," + " value 0x%02X, error %d)", index, value, err); + + return 0; +} + +static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index, int verbose) +{ + struct usb_device *udev = gspca_dev->dev; + __u8 *buf = gspca_dev->usb_buf; + int res; + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x01, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, + 0x00, index, buf, 8, 1000); + if (res < 0) { + err("Failed to read a register (index 0x%04X, error %d)", + index, res); + return res; + } + + if (verbose) + PDEBUG(D_PROBE, "Register %04x value: %02x", index, buf[0]); + + return 0; +} + +/* + * cit_send_FF_04_02() + * + * This procedure sends magic 3-command prefix to the camera. + * The purpose of this prefix is not known. + * + * History: + * 1/2/00 Created. + */ +static void cit_send_FF_04_02(struct gspca_dev *gspca_dev) +{ + cit_write_reg(gspca_dev, 0x00FF, 0x0127); + cit_write_reg(gspca_dev, 0x0004, 0x0124); + cit_write_reg(gspca_dev, 0x0002, 0x0124); +} + +static void cit_send_00_04_06(struct gspca_dev *gspca_dev) +{ + cit_write_reg(gspca_dev, 0x0000, 0x0127); + cit_write_reg(gspca_dev, 0x0004, 0x0124); + cit_write_reg(gspca_dev, 0x0006, 0x0124); +} + +static void cit_send_x_00(struct gspca_dev *gspca_dev, unsigned short x) +{ + cit_write_reg(gspca_dev, x, 0x0127); + cit_write_reg(gspca_dev, 0x0000, 0x0124); +} + +static void cit_send_x_00_05(struct gspca_dev *gspca_dev, unsigned short x) +{ + cit_send_x_00(gspca_dev, x); + cit_write_reg(gspca_dev, 0x0005, 0x0124); +} + +static void cit_send_x_00_05_02(struct gspca_dev *gspca_dev, unsigned short x) +{ + cit_write_reg(gspca_dev, x, 0x0127); + cit_write_reg(gspca_dev, 0x0000, 0x0124); + cit_write_reg(gspca_dev, 0x0005, 0x0124); + cit_write_reg(gspca_dev, 0x0002, 0x0124); +} + +static void cit_send_x_01_00_05(struct gspca_dev *gspca_dev, u16 x) +{ + cit_write_reg(gspca_dev, x, 0x0127); + cit_write_reg(gspca_dev, 0x0001, 0x0124); + cit_write_reg(gspca_dev, 0x0000, 0x0124); + cit_write_reg(gspca_dev, 0x0005, 0x0124); +} + +static void cit_send_x_00_05_02_01(struct gspca_dev *gspca_dev, u16 x) +{ + cit_write_reg(gspca_dev, x, 0x0127); + cit_write_reg(gspca_dev, 0x0000, 0x0124); + cit_write_reg(gspca_dev, 0x0005, 0x0124); + cit_write_reg(gspca_dev, 0x0002, 0x0124); + cit_write_reg(gspca_dev, 0x0001, 0x0124); +} + +static void cit_send_x_00_05_02_08_01(struct gspca_dev *gspca_dev, u16 x) +{ + cit_write_reg(gspca_dev, x, 0x0127); + cit_write_reg(gspca_dev, 0x0000, 0x0124); + cit_write_reg(gspca_dev, 0x0005, 0x0124); + cit_write_reg(gspca_dev, 0x0002, 0x0124); + cit_write_reg(gspca_dev, 0x0008, 0x0124); + cit_write_reg(gspca_dev, 0x0001, 0x0124); +} + +static void cit_Packet_Format1(struct gspca_dev *gspca_dev, u16 fkey, u16 val) +{ + cit_send_x_01_00_05(gspca_dev, 0x0088); + cit_send_x_00_05(gspca_dev, fkey); + cit_send_x_00_05_02_08_01(gspca_dev, val); + cit_send_x_00_05(gspca_dev, 0x0088); + cit_send_x_00_05_02_01(gspca_dev, fkey); + cit_send_x_00_05(gspca_dev, 0x0089); + cit_send_x_00(gspca_dev, fkey); + cit_send_00_04_06(gspca_dev); + cit_read_reg(gspca_dev, 0x0126, 0); + cit_send_FF_04_02(gspca_dev); +} + +static void cit_PacketFormat2(struct gspca_dev *gspca_dev, u16 fkey, u16 val) +{ + cit_send_x_01_00_05(gspca_dev, 0x0088); + cit_send_x_00_05(gspca_dev, fkey); + cit_send_x_00_05_02(gspca_dev, val); +} + +static void cit_model2_Packet2(struct gspca_dev *gspca_dev) +{ + cit_write_reg(gspca_dev, 0x00ff, 0x012d); + cit_write_reg(gspca_dev, 0xfea3, 0x0124); +} + +static void cit_model2_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2) +{ + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x00ff, 0x012e); + cit_write_reg(gspca_dev, v1, 0x012f); + cit_write_reg(gspca_dev, 0x00ff, 0x0130); + cit_write_reg(gspca_dev, 0xc719, 0x0124); + cit_write_reg(gspca_dev, v2, 0x0127); + + cit_model2_Packet2(gspca_dev); +} + +/* + * cit_model3_Packet1() + * + * 00_0078_012d + * 00_0097_012f + * 00_d141_0124 + * 00_0096_0127 + * 00_fea8_0124 +*/ +static void cit_model3_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2) +{ + cit_write_reg(gspca_dev, 0x0078, 0x012d); + cit_write_reg(gspca_dev, v1, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, v2, 0x0127); + cit_write_reg(gspca_dev, 0xfea8, 0x0124); +} + +static void cit_model4_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2) +{ + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, v1, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, v2, 0x0127); + cit_write_reg(gspca_dev, 0xfea8, 0x0124); +} + +static void cit_model4_BrightnessPacket(struct gspca_dev *gspca_dev, u16 val) +{ + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0026, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, val, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0038, 0x012d); + cit_write_reg(gspca_dev, 0x0004, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0xfffa, 0x0124); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + sd->model = id->driver_info; + if (sd->model == CIT_MODEL3 && ibm_netcam_pro) + sd->model = CIT_IBM_NETCAM_PRO; + + cam = &gspca_dev->cam; + switch (sd->model) { + case CIT_MODEL0: + cam->cam_mode = model0_mode; + cam->nmodes = ARRAY_SIZE(model0_mode); + cam->reverse_alts = 1; + gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP)); + sd->sof_len = 4; + break; + case CIT_MODEL1: + cam->cam_mode = cif_yuv_mode; + cam->nmodes = ARRAY_SIZE(cif_yuv_mode); + cam->reverse_alts = 1; + gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP); + sd->sof_len = 4; + break; + case CIT_MODEL2: + cam->cam_mode = model2_mode + 1; /* no 160x120 */ + cam->nmodes = 3; + gspca_dev->ctrl_dis = (1 << SD_CONTRAST) | + (1 << SD_SHARPNESS) | + (1 << SD_HFLIP); + break; + case CIT_MODEL3: + cam->cam_mode = vga_yuv_mode; + cam->nmodes = ARRAY_SIZE(vga_yuv_mode); + gspca_dev->ctrl_dis = (1 << SD_HUE) | + (1 << SD_LIGHTING) | + (1 << SD_HFLIP); + sd->stop_on_control_change = 1; + sd->sof_len = 4; + break; + case CIT_MODEL4: + cam->cam_mode = model2_mode; + cam->nmodes = ARRAY_SIZE(model2_mode); + gspca_dev->ctrl_dis = (1 << SD_CONTRAST) | + (1 << SD_SHARPNESS) | + (1 << SD_LIGHTING) | + (1 << SD_HFLIP); + break; + case CIT_IBM_NETCAM_PRO: + cam->cam_mode = vga_yuv_mode; + cam->nmodes = 2; /* no 640 x 480 */ + cam->input_flags = V4L2_IN_ST_VFLIP; + gspca_dev->ctrl_dis = ~(1 << SD_CONTRAST); + sd->stop_on_control_change = 1; + sd->sof_len = 4; + break; + } + + sd->brightness = BRIGHTNESS_DEFAULT; + sd->contrast = CONTRAST_DEFAULT; + sd->hue = HUE_DEFAULT; + sd->sharpness = SHARPNESS_DEFAULT; + sd->lighting = LIGHTING_DEFAULT; + sd->hflip = HFLIP_DEFAULT; + + return 0; +} + +static int cit_init_model0(struct gspca_dev *gspca_dev) +{ + cit_write_reg(gspca_dev, 0x0000, 0x0100); /* turn on led */ + cit_write_reg(gspca_dev, 0x0001, 0x0112); /* turn on autogain ? */ + cit_write_reg(gspca_dev, 0x0000, 0x0400); + cit_write_reg(gspca_dev, 0x0001, 0x0400); + cit_write_reg(gspca_dev, 0x0000, 0x0420); + cit_write_reg(gspca_dev, 0x0001, 0x0420); + cit_write_reg(gspca_dev, 0x000d, 0x0409); + cit_write_reg(gspca_dev, 0x0002, 0x040a); + cit_write_reg(gspca_dev, 0x0018, 0x0405); + cit_write_reg(gspca_dev, 0x0008, 0x0435); + cit_write_reg(gspca_dev, 0x0026, 0x040b); + cit_write_reg(gspca_dev, 0x0007, 0x0437); + cit_write_reg(gspca_dev, 0x0015, 0x042f); + cit_write_reg(gspca_dev, 0x002b, 0x0439); + cit_write_reg(gspca_dev, 0x0026, 0x043a); + cit_write_reg(gspca_dev, 0x0008, 0x0438); + cit_write_reg(gspca_dev, 0x001e, 0x042b); + cit_write_reg(gspca_dev, 0x0041, 0x042c); + + return 0; +} + +static int cit_init_ibm_netcam_pro(struct gspca_dev *gspca_dev) +{ + cit_read_reg(gspca_dev, 0x128, 1); + cit_write_reg(gspca_dev, 0x0003, 0x0133); + cit_write_reg(gspca_dev, 0x0000, 0x0117); + cit_write_reg(gspca_dev, 0x0008, 0x0123); + cit_write_reg(gspca_dev, 0x0000, 0x0100); + cit_read_reg(gspca_dev, 0x0116, 0); + cit_write_reg(gspca_dev, 0x0060, 0x0116); + cit_write_reg(gspca_dev, 0x0002, 0x0112); + cit_write_reg(gspca_dev, 0x0000, 0x0133); + cit_write_reg(gspca_dev, 0x0000, 0x0123); + cit_write_reg(gspca_dev, 0x0001, 0x0117); + cit_write_reg(gspca_dev, 0x0040, 0x0108); + cit_write_reg(gspca_dev, 0x0019, 0x012c); + cit_write_reg(gspca_dev, 0x0060, 0x0116); + cit_write_reg(gspca_dev, 0x0002, 0x0115); + cit_write_reg(gspca_dev, 0x000b, 0x0115); + + cit_write_reg(gspca_dev, 0x0078, 0x012d); + cit_write_reg(gspca_dev, 0x0001, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0079, 0x012d); + cit_write_reg(gspca_dev, 0x00ff, 0x0130); + cit_write_reg(gspca_dev, 0xcd41, 0x0124); + cit_write_reg(gspca_dev, 0xfffa, 0x0124); + cit_read_reg(gspca_dev, 0x0126, 1); + + cit_model3_Packet1(gspca_dev, 0x0000, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0000, 0x0001); + cit_model3_Packet1(gspca_dev, 0x000b, 0x0000); + cit_model3_Packet1(gspca_dev, 0x000c, 0x0008); + cit_model3_Packet1(gspca_dev, 0x000d, 0x003a); + cit_model3_Packet1(gspca_dev, 0x000e, 0x0060); + cit_model3_Packet1(gspca_dev, 0x000f, 0x0060); + cit_model3_Packet1(gspca_dev, 0x0010, 0x0008); + cit_model3_Packet1(gspca_dev, 0x0011, 0x0004); + cit_model3_Packet1(gspca_dev, 0x0012, 0x0028); + cit_model3_Packet1(gspca_dev, 0x0013, 0x0002); + cit_model3_Packet1(gspca_dev, 0x0014, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0015, 0x00fb); + cit_model3_Packet1(gspca_dev, 0x0016, 0x0002); + cit_model3_Packet1(gspca_dev, 0x0017, 0x0037); + cit_model3_Packet1(gspca_dev, 0x0018, 0x0036); + cit_model3_Packet1(gspca_dev, 0x001e, 0x0000); + cit_model3_Packet1(gspca_dev, 0x001f, 0x0008); + cit_model3_Packet1(gspca_dev, 0x0020, 0x00c1); + cit_model3_Packet1(gspca_dev, 0x0021, 0x0034); + cit_model3_Packet1(gspca_dev, 0x0022, 0x0034); + cit_model3_Packet1(gspca_dev, 0x0025, 0x0002); + cit_model3_Packet1(gspca_dev, 0x0028, 0x0022); + cit_model3_Packet1(gspca_dev, 0x0029, 0x000a); + cit_model3_Packet1(gspca_dev, 0x002b, 0x0000); + cit_model3_Packet1(gspca_dev, 0x002c, 0x0000); + cit_model3_Packet1(gspca_dev, 0x002d, 0x00ff); + cit_model3_Packet1(gspca_dev, 0x002e, 0x00ff); + cit_model3_Packet1(gspca_dev, 0x002f, 0x00ff); + cit_model3_Packet1(gspca_dev, 0x0030, 0x00ff); + cit_model3_Packet1(gspca_dev, 0x0031, 0x00ff); + cit_model3_Packet1(gspca_dev, 0x0032, 0x0007); + cit_model3_Packet1(gspca_dev, 0x0033, 0x0005); + cit_model3_Packet1(gspca_dev, 0x0037, 0x0040); + cit_model3_Packet1(gspca_dev, 0x0039, 0x0000); + cit_model3_Packet1(gspca_dev, 0x003a, 0x0000); + cit_model3_Packet1(gspca_dev, 0x003b, 0x0001); + cit_model3_Packet1(gspca_dev, 0x003c, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0040, 0x000c); + cit_model3_Packet1(gspca_dev, 0x0041, 0x00fb); + cit_model3_Packet1(gspca_dev, 0x0042, 0x0002); + cit_model3_Packet1(gspca_dev, 0x0043, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0045, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0046, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0047, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0048, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0049, 0x0000); + cit_model3_Packet1(gspca_dev, 0x004a, 0x00ff); + cit_model3_Packet1(gspca_dev, 0x004b, 0x00ff); + cit_model3_Packet1(gspca_dev, 0x004c, 0x00ff); + cit_model3_Packet1(gspca_dev, 0x004f, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0050, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0051, 0x0002); + cit_model3_Packet1(gspca_dev, 0x0055, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0056, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0057, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0058, 0x0002); + cit_model3_Packet1(gspca_dev, 0x0059, 0x0000); + cit_model3_Packet1(gspca_dev, 0x005c, 0x0016); + cit_model3_Packet1(gspca_dev, 0x005d, 0x0022); + cit_model3_Packet1(gspca_dev, 0x005e, 0x003c); + cit_model3_Packet1(gspca_dev, 0x005f, 0x0050); + cit_model3_Packet1(gspca_dev, 0x0060, 0x0044); + cit_model3_Packet1(gspca_dev, 0x0061, 0x0005); + cit_model3_Packet1(gspca_dev, 0x006a, 0x007e); + cit_model3_Packet1(gspca_dev, 0x006f, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0072, 0x001b); + cit_model3_Packet1(gspca_dev, 0x0073, 0x0005); + cit_model3_Packet1(gspca_dev, 0x0074, 0x000a); + cit_model3_Packet1(gspca_dev, 0x0075, 0x001b); + cit_model3_Packet1(gspca_dev, 0x0076, 0x002a); + cit_model3_Packet1(gspca_dev, 0x0077, 0x003c); + cit_model3_Packet1(gspca_dev, 0x0078, 0x0050); + cit_model3_Packet1(gspca_dev, 0x007b, 0x0000); + cit_model3_Packet1(gspca_dev, 0x007c, 0x0011); + cit_model3_Packet1(gspca_dev, 0x007d, 0x0024); + cit_model3_Packet1(gspca_dev, 0x007e, 0x0043); + cit_model3_Packet1(gspca_dev, 0x007f, 0x005a); + cit_model3_Packet1(gspca_dev, 0x0084, 0x0020); + cit_model3_Packet1(gspca_dev, 0x0085, 0x0033); + cit_model3_Packet1(gspca_dev, 0x0086, 0x000a); + cit_model3_Packet1(gspca_dev, 0x0087, 0x0030); + cit_model3_Packet1(gspca_dev, 0x0088, 0x0070); + cit_model3_Packet1(gspca_dev, 0x008b, 0x0008); + cit_model3_Packet1(gspca_dev, 0x008f, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0090, 0x0006); + cit_model3_Packet1(gspca_dev, 0x0091, 0x0028); + cit_model3_Packet1(gspca_dev, 0x0092, 0x005a); + cit_model3_Packet1(gspca_dev, 0x0093, 0x0082); + cit_model3_Packet1(gspca_dev, 0x0096, 0x0014); + cit_model3_Packet1(gspca_dev, 0x0097, 0x0020); + cit_model3_Packet1(gspca_dev, 0x0098, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00b0, 0x0046); + cit_model3_Packet1(gspca_dev, 0x00b1, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00b2, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00b3, 0x0004); + cit_model3_Packet1(gspca_dev, 0x00b4, 0x0007); + cit_model3_Packet1(gspca_dev, 0x00b6, 0x0002); + cit_model3_Packet1(gspca_dev, 0x00b7, 0x0004); + cit_model3_Packet1(gspca_dev, 0x00bb, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00bc, 0x0001); + cit_model3_Packet1(gspca_dev, 0x00bd, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00bf, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00c0, 0x00c8); + cit_model3_Packet1(gspca_dev, 0x00c1, 0x0014); + cit_model3_Packet1(gspca_dev, 0x00c2, 0x0001); + cit_model3_Packet1(gspca_dev, 0x00c3, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00c4, 0x0004); + cit_model3_Packet1(gspca_dev, 0x00cb, 0x00bf); + cit_model3_Packet1(gspca_dev, 0x00cc, 0x00bf); + cit_model3_Packet1(gspca_dev, 0x00cd, 0x00bf); + cit_model3_Packet1(gspca_dev, 0x00ce, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00cf, 0x0020); + cit_model3_Packet1(gspca_dev, 0x00d0, 0x0040); + cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf); + cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf); + cit_model3_Packet1(gspca_dev, 0x00d2, 0x00bf); + cit_model3_Packet1(gspca_dev, 0x00d3, 0x00bf); + cit_model3_Packet1(gspca_dev, 0x00ea, 0x0008); + cit_model3_Packet1(gspca_dev, 0x00eb, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00ec, 0x00e8); + cit_model3_Packet1(gspca_dev, 0x00ed, 0x0001); + cit_model3_Packet1(gspca_dev, 0x00ef, 0x0022); + cit_model3_Packet1(gspca_dev, 0x00f0, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00f2, 0x0028); + cit_model3_Packet1(gspca_dev, 0x00f4, 0x0002); + cit_model3_Packet1(gspca_dev, 0x00f5, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00fa, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00fb, 0x0001); + cit_model3_Packet1(gspca_dev, 0x00fc, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00fd, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00fe, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00ff, 0x0000); + + cit_model3_Packet1(gspca_dev, 0x00be, 0x0003); + cit_model3_Packet1(gspca_dev, 0x00c8, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00c9, 0x0020); + cit_model3_Packet1(gspca_dev, 0x00ca, 0x0040); + cit_model3_Packet1(gspca_dev, 0x0053, 0x0001); + cit_model3_Packet1(gspca_dev, 0x0082, 0x000e); + cit_model3_Packet1(gspca_dev, 0x0083, 0x0020); + cit_model3_Packet1(gspca_dev, 0x0034, 0x003c); + cit_model3_Packet1(gspca_dev, 0x006e, 0x0055); + cit_model3_Packet1(gspca_dev, 0x0062, 0x0005); + cit_model3_Packet1(gspca_dev, 0x0063, 0x0008); + cit_model3_Packet1(gspca_dev, 0x0066, 0x000a); + cit_model3_Packet1(gspca_dev, 0x0067, 0x0006); + cit_model3_Packet1(gspca_dev, 0x006b, 0x0010); + cit_model3_Packet1(gspca_dev, 0x005a, 0x0001); + cit_model3_Packet1(gspca_dev, 0x005b, 0x000a); + cit_model3_Packet1(gspca_dev, 0x0023, 0x0006); + cit_model3_Packet1(gspca_dev, 0x0026, 0x0004); + cit_model3_Packet1(gspca_dev, 0x0036, 0x0069); + cit_model3_Packet1(gspca_dev, 0x0038, 0x0064); + cit_model3_Packet1(gspca_dev, 0x003d, 0x0003); + cit_model3_Packet1(gspca_dev, 0x003e, 0x0001); + cit_model3_Packet1(gspca_dev, 0x00b8, 0x0014); + cit_model3_Packet1(gspca_dev, 0x00b9, 0x0014); + cit_model3_Packet1(gspca_dev, 0x00e6, 0x0004); + cit_model3_Packet1(gspca_dev, 0x00e8, 0x0001); + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->model) { + case CIT_MODEL0: + cit_init_model0(gspca_dev); + sd_stop0(gspca_dev); + break; + case CIT_MODEL1: + case CIT_MODEL2: + case CIT_MODEL3: + case CIT_MODEL4: + break; /* All is done in sd_start */ + case CIT_IBM_NETCAM_PRO: + cit_init_ibm_netcam_pro(gspca_dev); + sd_stop0(gspca_dev); + break; + } + return 0; +} + +static int cit_set_brightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + + switch (sd->model) { + case CIT_MODEL0: + case CIT_IBM_NETCAM_PRO: + /* No (known) brightness control for these */ + break; + case CIT_MODEL1: + /* Model 1: Brightness range 0 - 63 */ + cit_Packet_Format1(gspca_dev, 0x0031, sd->brightness); + cit_Packet_Format1(gspca_dev, 0x0032, sd->brightness); + cit_Packet_Format1(gspca_dev, 0x0033, sd->brightness); + break; + case CIT_MODEL2: + /* Model 2: Brightness range 0x60 - 0xee */ + /* Scale 0 - 63 to 0x60 - 0xee */ + i = 0x60 + sd->brightness * 2254 / 1000; + cit_model2_Packet1(gspca_dev, 0x001a, i); + break; + case CIT_MODEL3: + /* Model 3: Brightness range 'i' in [0x0C..0x3F] */ + i = sd->brightness; + if (i < 0x0c) + i = 0x0c; + cit_model3_Packet1(gspca_dev, 0x0036, i); + break; + case CIT_MODEL4: + /* Model 4: Brightness range 'i' in [0x04..0xb4] */ + /* Scale 0 - 63 to 0x04 - 0xb4 */ + i = 0x04 + sd->brightness * 2794 / 1000; + cit_model4_BrightnessPacket(gspca_dev, i); + break; + } + + return 0; +} + +static int cit_set_contrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->model) { + case CIT_MODEL0: { + int i; + /* gain 0-15, 0-20 -> 0-15 */ + i = sd->contrast * 1000 / 1333; + cit_write_reg(gspca_dev, i, 0x0422); + /* gain 0-31, may not be lower then 0x0422, 0-20 -> 0-31 */ + i = sd->contrast * 2000 / 1333; + cit_write_reg(gspca_dev, i, 0x0423); + /* gain 0-127, may not be lower then 0x0423, 0-20 -> 0-63 */ + i = sd->contrast * 4000 / 1333; + cit_write_reg(gspca_dev, i, 0x0424); + /* gain 0-127, may not be lower then 0x0424, , 0-20 -> 0-127 */ + i = sd->contrast * 8000 / 1333; + cit_write_reg(gspca_dev, i, 0x0425); + break; + } + case CIT_MODEL2: + case CIT_MODEL4: + /* These models do not have this control. */ + break; + case CIT_MODEL1: + { + /* Scale 0 - 20 to 15 - 0 */ + int i, new_contrast = (20 - sd->contrast) * 1000 / 1333; + for (i = 0; i < cit_model1_ntries; i++) { + cit_Packet_Format1(gspca_dev, 0x0014, new_contrast); + cit_send_FF_04_02(gspca_dev); + } + break; + } + case CIT_MODEL3: + { /* Preset hardware values */ + static const struct { + unsigned short cv1; + unsigned short cv2; + unsigned short cv3; + } cv[7] = { + { 0x05, 0x05, 0x0f }, /* Minimum */ + { 0x04, 0x04, 0x16 }, + { 0x02, 0x03, 0x16 }, + { 0x02, 0x08, 0x16 }, + { 0x01, 0x0c, 0x16 }, + { 0x01, 0x0e, 0x16 }, + { 0x01, 0x10, 0x16 } /* Maximum */ + }; + int i = sd->contrast / 3; + cit_model3_Packet1(gspca_dev, 0x0067, cv[i].cv1); + cit_model3_Packet1(gspca_dev, 0x005b, cv[i].cv2); + cit_model3_Packet1(gspca_dev, 0x005c, cv[i].cv3); + break; + } + case CIT_IBM_NETCAM_PRO: + cit_model3_Packet1(gspca_dev, 0x005b, sd->contrast + 1); + break; + } + return 0; +} + +static int cit_set_hue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->model) { + case CIT_MODEL0: + case CIT_MODEL1: + case CIT_IBM_NETCAM_PRO: + /* No hue control for these models */ + break; + case CIT_MODEL2: + cit_model2_Packet1(gspca_dev, 0x0024, sd->hue); + /* cit_model2_Packet1(gspca_dev, 0x0020, sat); */ + break; + case CIT_MODEL3: { + /* Model 3: Brightness range 'i' in [0x05..0x37] */ + /* TESTME according to the ibmcam driver this does not work */ + if (0) { + /* Scale 0 - 127 to 0x05 - 0x37 */ + int i = 0x05 + sd->hue * 1000 / 2540; + cit_model3_Packet1(gspca_dev, 0x007e, i); + } + break; + } + case CIT_MODEL4: + /* HDG: taken from ibmcam, setting the color gains does not + * really belong here. + * + * I am not sure r/g/b_gain variables exactly control gain + * of those channels. Most likely they subtly change some + * very internal image processing settings in the camera. + * In any case, here is what they do, and feel free to tweak: + * + * r_gain: seriously affects red gain + * g_gain: seriously affects green gain + * b_gain: seriously affects blue gain + * hue: changes average color from violet (0) to red (0xFF) + */ + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x001e, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 160, 0x0127); /* Green gain */ + cit_write_reg(gspca_dev, 160, 0x012e); /* Red gain */ + cit_write_reg(gspca_dev, 160, 0x0130); /* Blue gain */ + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, sd->hue, 0x012d); /* Hue */ + cit_write_reg(gspca_dev, 0xf545, 0x0124); + break; + } + return 0; +} + +static int cit_set_sharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->model) { + case CIT_MODEL0: + case CIT_MODEL2: + case CIT_MODEL4: + case CIT_IBM_NETCAM_PRO: + /* These models do not have this control */ + break; + case CIT_MODEL1: { + int i; + const unsigned short sa[] = { + 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a }; + + for (i = 0; i < cit_model1_ntries; i++) + cit_PacketFormat2(gspca_dev, 0x0013, sa[sd->sharpness]); + break; + } + case CIT_MODEL3: + { /* + * "Use a table of magic numbers. + * This setting doesn't really change much. + * But that's how Windows does it." + */ + static const struct { + unsigned short sv1; + unsigned short sv2; + unsigned short sv3; + unsigned short sv4; + } sv[7] = { + { 0x00, 0x00, 0x05, 0x14 }, /* Smoothest */ + { 0x01, 0x04, 0x05, 0x14 }, + { 0x02, 0x04, 0x05, 0x14 }, + { 0x03, 0x04, 0x05, 0x14 }, + { 0x03, 0x05, 0x05, 0x14 }, + { 0x03, 0x06, 0x05, 0x14 }, + { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */ + }; + cit_model3_Packet1(gspca_dev, 0x0060, sv[sd->sharpness].sv1); + cit_model3_Packet1(gspca_dev, 0x0061, sv[sd->sharpness].sv2); + cit_model3_Packet1(gspca_dev, 0x0062, sv[sd->sharpness].sv3); + cit_model3_Packet1(gspca_dev, 0x0063, sv[sd->sharpness].sv4); + break; + } + } + return 0; +} + +/* + * cit_set_lighting() + * + * Camera model 1: + * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low. + * + * Camera model 2: + * We have 16 levels of lighting, 0 for bright light and up to 15 for + * low light. But values above 5 or so are useless because camera is + * not really capable to produce anything worth viewing at such light. + * This setting may be altered only in certain camera state. + * + * Low lighting forces slower FPS. + * + * History: + * 1/5/00 Created. + * 2/20/00 Added support for Model 2 cameras. + */ +static void cit_set_lighting(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->model) { + case CIT_MODEL0: + case CIT_MODEL2: + case CIT_MODEL3: + case CIT_MODEL4: + case CIT_IBM_NETCAM_PRO: + break; + case CIT_MODEL1: { + int i; + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting); + break; + } + } +} + +static void cit_set_hflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->model) { + case CIT_MODEL0: + if (sd->hflip) + cit_write_reg(gspca_dev, 0x0020, 0x0115); + else + cit_write_reg(gspca_dev, 0x0040, 0x0115); + break; + case CIT_MODEL1: + case CIT_MODEL2: + case CIT_MODEL3: + case CIT_MODEL4: + case CIT_IBM_NETCAM_PRO: + break; + } +} + +static int cit_restart_stream(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->model) { + case CIT_MODEL0: + case CIT_MODEL1: + cit_write_reg(gspca_dev, 0x0001, 0x0114); + /* Fall through */ + case CIT_MODEL2: + case CIT_MODEL4: + cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */ + usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe); + break; + case CIT_MODEL3: + case CIT_IBM_NETCAM_PRO: + cit_write_reg(gspca_dev, 0x0001, 0x0114); + cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */ + usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe); + /* Clear button events from while we were not streaming */ + cit_write_reg(gspca_dev, 0x0001, 0x0113); + break; + } + + sd->sof_read = 0; + + return 0; +} + +static int cit_get_packet_size(struct gspca_dev *gspca_dev) +{ + struct usb_host_interface *alt; + struct usb_interface *intf; + + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + alt = usb_altnum_to_altsetting(intf, gspca_dev->alt); + if (!alt) { + err("Couldn't get altsetting"); + return -EIO; + } + + return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); +} + +/* Calculate the clockdiv giving us max fps given the available bandwidth */ +static int cit_get_clock_div(struct gspca_dev *gspca_dev) +{ + int clock_div = 7; /* 0=30 1=25 2=20 3=15 4=12 5=7.5 6=6 7=3fps ?? */ + int fps[8] = { 30, 25, 20, 15, 12, 8, 6, 3 }; + int packet_size; + + packet_size = cit_get_packet_size(gspca_dev); + if (packet_size < 0) + return packet_size; + + while (clock_div > 3 && + 1000 * packet_size > + gspca_dev->width * gspca_dev->height * + fps[clock_div - 1] * 3 / 2) + clock_div--; + + PDEBUG(D_PROBE, + "PacketSize: %d, res: %dx%d -> using clockdiv: %d (%d fps)", + packet_size, gspca_dev->width, gspca_dev->height, clock_div, + fps[clock_div]); + + return clock_div; +} + +static int cit_start_model0(struct gspca_dev *gspca_dev) +{ + const unsigned short compression = 0; /* 0=none, 7=best frame rate */ + int clock_div; + + clock_div = cit_get_clock_div(gspca_dev); + if (clock_div < 0) + return clock_div; + + cit_write_reg(gspca_dev, 0x0000, 0x0100); /* turn on led */ + cit_write_reg(gspca_dev, 0x0003, 0x0438); + cit_write_reg(gspca_dev, 0x001e, 0x042b); + cit_write_reg(gspca_dev, 0x0041, 0x042c); + cit_write_reg(gspca_dev, 0x0008, 0x0436); + cit_write_reg(gspca_dev, 0x0024, 0x0403); + cit_write_reg(gspca_dev, 0x002c, 0x0404); + cit_write_reg(gspca_dev, 0x0002, 0x0426); + cit_write_reg(gspca_dev, 0x0014, 0x0427); + + switch (gspca_dev->width) { + case 160: /* 160x120 */ + cit_write_reg(gspca_dev, 0x0004, 0x010b); + cit_write_reg(gspca_dev, 0x0001, 0x010a); + cit_write_reg(gspca_dev, 0x0010, 0x0102); + cit_write_reg(gspca_dev, 0x00a0, 0x0103); + cit_write_reg(gspca_dev, 0x0000, 0x0104); + cit_write_reg(gspca_dev, 0x0078, 0x0105); + break; + + case 176: /* 176x144 */ + cit_write_reg(gspca_dev, 0x0006, 0x010b); + cit_write_reg(gspca_dev, 0x0000, 0x010a); + cit_write_reg(gspca_dev, 0x0005, 0x0102); + cit_write_reg(gspca_dev, 0x00b0, 0x0103); + cit_write_reg(gspca_dev, 0x0000, 0x0104); + cit_write_reg(gspca_dev, 0x0090, 0x0105); + break; + + case 320: /* 320x240 */ + cit_write_reg(gspca_dev, 0x0008, 0x010b); + cit_write_reg(gspca_dev, 0x0004, 0x010a); + cit_write_reg(gspca_dev, 0x0005, 0x0102); + cit_write_reg(gspca_dev, 0x00a0, 0x0103); + cit_write_reg(gspca_dev, 0x0010, 0x0104); + cit_write_reg(gspca_dev, 0x0078, 0x0105); + break; + } + + cit_write_reg(gspca_dev, compression, 0x0109); + cit_write_reg(gspca_dev, clock_div, 0x0111); + + return 0; +} + +static int cit_start_model1(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, clock_div; + + clock_div = cit_get_clock_div(gspca_dev); + if (clock_div < 0) + return clock_div; + + cit_read_reg(gspca_dev, 0x0128, 1); + cit_read_reg(gspca_dev, 0x0100, 0); + cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */ + cit_read_reg(gspca_dev, 0x0100, 0); + cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */ + cit_read_reg(gspca_dev, 0x0100, 0); + cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */ + cit_write_reg(gspca_dev, 0x01, 0x0108); + + cit_write_reg(gspca_dev, 0x03, 0x0112); + cit_read_reg(gspca_dev, 0x0115, 0); + cit_write_reg(gspca_dev, 0x06, 0x0115); + cit_read_reg(gspca_dev, 0x0116, 0); + cit_write_reg(gspca_dev, 0x44, 0x0116); + cit_read_reg(gspca_dev, 0x0116, 0); + cit_write_reg(gspca_dev, 0x40, 0x0116); + cit_read_reg(gspca_dev, 0x0115, 0); + cit_write_reg(gspca_dev, 0x0e, 0x0115); + cit_write_reg(gspca_dev, 0x19, 0x012c); + + cit_Packet_Format1(gspca_dev, 0x00, 0x1e); + cit_Packet_Format1(gspca_dev, 0x39, 0x0d); + cit_Packet_Format1(gspca_dev, 0x39, 0x09); + cit_Packet_Format1(gspca_dev, 0x3b, 0x00); + cit_Packet_Format1(gspca_dev, 0x28, 0x22); + cit_Packet_Format1(gspca_dev, 0x27, 0x00); + cit_Packet_Format1(gspca_dev, 0x2b, 0x1f); + cit_Packet_Format1(gspca_dev, 0x39, 0x08); + + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x2c, 0x00); + + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x30, 0x14); + + cit_PacketFormat2(gspca_dev, 0x39, 0x02); + cit_PacketFormat2(gspca_dev, 0x01, 0xe1); + cit_PacketFormat2(gspca_dev, 0x02, 0xcd); + cit_PacketFormat2(gspca_dev, 0x03, 0xcd); + cit_PacketFormat2(gspca_dev, 0x04, 0xfa); + cit_PacketFormat2(gspca_dev, 0x3f, 0xff); + cit_PacketFormat2(gspca_dev, 0x39, 0x00); + + cit_PacketFormat2(gspca_dev, 0x39, 0x02); + cit_PacketFormat2(gspca_dev, 0x0a, 0x37); + cit_PacketFormat2(gspca_dev, 0x0b, 0xb8); + cit_PacketFormat2(gspca_dev, 0x0c, 0xf3); + cit_PacketFormat2(gspca_dev, 0x0d, 0xe3); + cit_PacketFormat2(gspca_dev, 0x0e, 0x0d); + cit_PacketFormat2(gspca_dev, 0x0f, 0xf2); + cit_PacketFormat2(gspca_dev, 0x10, 0xd5); + cit_PacketFormat2(gspca_dev, 0x11, 0xba); + cit_PacketFormat2(gspca_dev, 0x12, 0x53); + cit_PacketFormat2(gspca_dev, 0x3f, 0xff); + cit_PacketFormat2(gspca_dev, 0x39, 0x00); + + cit_PacketFormat2(gspca_dev, 0x39, 0x02); + cit_PacketFormat2(gspca_dev, 0x16, 0x00); + cit_PacketFormat2(gspca_dev, 0x17, 0x28); + cit_PacketFormat2(gspca_dev, 0x18, 0x7d); + cit_PacketFormat2(gspca_dev, 0x19, 0xbe); + cit_PacketFormat2(gspca_dev, 0x3f, 0xff); + cit_PacketFormat2(gspca_dev, 0x39, 0x00); + + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x00, 0x18); + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x13, 0x18); + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x14, 0x06); + + /* TESTME These are handled through controls + KEEP until someone can test leaving this out is ok */ + if (0) { + /* This is default brightness */ + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x31, 0x37); + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x32, 0x46); + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x33, 0x55); + } + + cit_Packet_Format1(gspca_dev, 0x2e, 0x04); + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x2d, 0x04); + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x29, 0x80); + cit_Packet_Format1(gspca_dev, 0x2c, 0x01); + cit_Packet_Format1(gspca_dev, 0x30, 0x17); + cit_Packet_Format1(gspca_dev, 0x39, 0x08); + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x34, 0x00); + + cit_write_reg(gspca_dev, 0x00, 0x0101); + cit_write_reg(gspca_dev, 0x00, 0x010a); + + switch (gspca_dev->width) { + case 128: /* 128x96 */ + cit_write_reg(gspca_dev, 0x80, 0x0103); + cit_write_reg(gspca_dev, 0x60, 0x0105); + cit_write_reg(gspca_dev, 0x0c, 0x010b); + cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x0b, 0x011d); + cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x00, 0x0129); + break; + case 176: /* 176x144 */ + cit_write_reg(gspca_dev, 0xb0, 0x0103); + cit_write_reg(gspca_dev, 0x8f, 0x0105); + cit_write_reg(gspca_dev, 0x06, 0x010b); + cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x0d, 0x011d); + cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x03, 0x0129); + break; + case 352: /* 352x288 */ + cit_write_reg(gspca_dev, 0xb0, 0x0103); + cit_write_reg(gspca_dev, 0x90, 0x0105); + cit_write_reg(gspca_dev, 0x02, 0x010b); + cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x05, 0x011d); + cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x00, 0x0129); + break; + } + + cit_write_reg(gspca_dev, 0xff, 0x012b); + + /* TESTME These are handled through controls + KEEP until someone can test leaving this out is ok */ + if (0) { + /* This is another brightness - don't know why */ + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x31, 0xc3); + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x32, 0xd2); + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x33, 0xe1); + + /* Default contrast */ + for (i = 0; i < cit_model1_ntries; i++) + cit_Packet_Format1(gspca_dev, 0x14, 0x0a); + + /* Default sharpness */ + for (i = 0; i < cit_model1_ntries2; i++) + cit_PacketFormat2(gspca_dev, 0x13, 0x1a); + + /* Default lighting conditions */ + cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting); + } + + /* Assorted init */ + switch (gspca_dev->width) { + case 128: /* 128x96 */ + cit_Packet_Format1(gspca_dev, 0x2b, 0x1e); + cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x36, 0x0102); + cit_write_reg(gspca_dev, 0x1a, 0x0104); + cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x2b, 0x011c); + cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */ + break; + case 176: /* 176x144 */ + cit_Packet_Format1(gspca_dev, 0x2b, 0x1e); + cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x04, 0x0102); + cit_write_reg(gspca_dev, 0x02, 0x0104); + cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x2b, 0x011c); + cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */ + break; + case 352: /* 352x288 */ + cit_Packet_Format1(gspca_dev, 0x2b, 0x1f); + cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x08, 0x0102); + cit_write_reg(gspca_dev, 0x01, 0x0104); + cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */ + cit_write_reg(gspca_dev, 0x2f, 0x011c); + cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */ + break; + } + + cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */ + cit_write_reg(gspca_dev, clock_div, 0x0111); + + return 0; +} + +static int cit_start_model2(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int clock_div = 0; + + cit_write_reg(gspca_dev, 0x0000, 0x0100); /* LED on */ + cit_read_reg(gspca_dev, 0x0116, 0); + cit_write_reg(gspca_dev, 0x0060, 0x0116); + cit_write_reg(gspca_dev, 0x0002, 0x0112); + cit_write_reg(gspca_dev, 0x00bc, 0x012c); + cit_write_reg(gspca_dev, 0x0008, 0x012b); + cit_write_reg(gspca_dev, 0x0000, 0x0108); + cit_write_reg(gspca_dev, 0x0001, 0x0133); + cit_write_reg(gspca_dev, 0x0001, 0x0102); + switch (gspca_dev->width) { + case 176: /* 176x144 */ + cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */ + cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ + cit_write_reg(gspca_dev, 0x0024, 0x0105); /* 176x144, 352x288 */ + cit_write_reg(gspca_dev, 0x00b9, 0x010a); /* Unique to this mode */ + cit_write_reg(gspca_dev, 0x0038, 0x0119); /* Unique to this mode */ + /* TESTME HDG: this does not seem right + (it is 2 for all other resolutions) */ + sd->sof_len = 10; + break; + case 320: /* 320x240 */ + cit_write_reg(gspca_dev, 0x0028, 0x0103); /* Unique to this mode */ + cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ + cit_write_reg(gspca_dev, 0x001e, 0x0105); /* 320x240, 352x240 */ + cit_write_reg(gspca_dev, 0x0039, 0x010a); /* All except 176x144 */ + cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */ + sd->sof_len = 2; + break; + /* case VIDEOSIZE_352x240: */ + cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */ + cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ + cit_write_reg(gspca_dev, 0x001e, 0x0105); /* 320x240, 352x240 */ + cit_write_reg(gspca_dev, 0x0039, 0x010a); /* All except 176x144 */ + cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */ + sd->sof_len = 2; + break; + case 352: /* 352x288 */ + cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */ + cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ + cit_write_reg(gspca_dev, 0x0024, 0x0105); /* 176x144, 352x288 */ + cit_write_reg(gspca_dev, 0x0039, 0x010a); /* All except 176x144 */ + cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */ + sd->sof_len = 2; + break; + } + + cit_write_reg(gspca_dev, 0x0000, 0x0100); /* LED on */ + + switch (gspca_dev->width) { + case 176: /* 176x144 */ + cit_write_reg(gspca_dev, 0x0050, 0x0111); + cit_write_reg(gspca_dev, 0x00d0, 0x0111); + break; + case 320: /* 320x240 */ + case 352: /* 352x288 */ + cit_write_reg(gspca_dev, 0x0040, 0x0111); + cit_write_reg(gspca_dev, 0x00c0, 0x0111); + break; + } + cit_write_reg(gspca_dev, 0x009b, 0x010f); + cit_write_reg(gspca_dev, 0x00bb, 0x010f); + + /* + * Hardware settings, may affect CMOS sensor; not user controls! + * ------------------------------------------------------------- + * 0x0004: no effect + * 0x0006: hardware effect + * 0x0008: no effect + * 0x000a: stops video stream, probably important h/w setting + * 0x000c: changes color in hardware manner (not user setting) + * 0x0012: changes number of colors (does not affect speed) + * 0x002a: no effect + * 0x002c: hardware setting (related to scan lines) + * 0x002e: stops video stream, probably important h/w setting + */ + cit_model2_Packet1(gspca_dev, 0x000a, 0x005c); + cit_model2_Packet1(gspca_dev, 0x0004, 0x0000); + cit_model2_Packet1(gspca_dev, 0x0006, 0x00fb); + cit_model2_Packet1(gspca_dev, 0x0008, 0x0000); + cit_model2_Packet1(gspca_dev, 0x000c, 0x0009); + cit_model2_Packet1(gspca_dev, 0x0012, 0x000a); + cit_model2_Packet1(gspca_dev, 0x002a, 0x0000); + cit_model2_Packet1(gspca_dev, 0x002c, 0x0000); + cit_model2_Packet1(gspca_dev, 0x002e, 0x0008); + + /* + * Function 0x0030 pops up all over the place. Apparently + * it is a hardware control register, with every bit assigned to + * do something. + */ + cit_model2_Packet1(gspca_dev, 0x0030, 0x0000); + + /* + * Magic control of CMOS sensor. Only lower values like + * 0-3 work, and picture shifts left or right. Don't change. + */ + switch (gspca_dev->width) { + case 176: /* 176x144 */ + cit_model2_Packet1(gspca_dev, 0x0014, 0x0002); + cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */ + cit_model2_Packet1(gspca_dev, 0x0018, 0x004a); /* Another hardware setting */ + clock_div = 6; + break; + case 320: /* 320x240 */ + cit_model2_Packet1(gspca_dev, 0x0014, 0x0009); + cit_model2_Packet1(gspca_dev, 0x0016, 0x0005); /* Horizontal shift */ + cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Another hardware setting */ + clock_div = 8; + break; + /* case VIDEOSIZE_352x240: */ + /* This mode doesn't work as Windows programs it; changed to work */ + cit_model2_Packet1(gspca_dev, 0x0014, 0x0009); /* Windows sets this to 8 */ + cit_model2_Packet1(gspca_dev, 0x0016, 0x0003); /* Horizontal shift */ + cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Windows sets this to 0x0045 */ + clock_div = 10; + break; + case 352: /* 352x288 */ + cit_model2_Packet1(gspca_dev, 0x0014, 0x0003); + cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */ + cit_model2_Packet1(gspca_dev, 0x0018, 0x004a); /* Another hardware setting */ + clock_div = 16; + break; + } + + /* TESTME These are handled through controls + KEEP until someone can test leaving this out is ok */ + if (0) + cit_model2_Packet1(gspca_dev, 0x001a, 0x005a); + + /* + * We have our own frame rate setting varying from 0 (slowest) to 6 + * (fastest). The camera model 2 allows frame rate in range [0..0x1F] + # where 0 is also the slowest setting. However for all practical + # reasons high settings make no sense because USB is not fast enough + # to support high FPS. Be aware that the picture datastream will be + # severely disrupted if you ask for frame rate faster than allowed + # for the video size - see below: + * + * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz): + * ----------------------------------------------------------------- + * 176x144: [6..31] + * 320x240: [8..31] + * 352x240: [10..31] + * 352x288: [16..31] I have to raise lower threshold for stability... + * + * As usual, slower FPS provides better sensitivity. + */ + cit_model2_Packet1(gspca_dev, 0x001c, clock_div); + + /* + * This setting does not visibly affect pictures; left it here + * because it was present in Windows USB data stream. This function + * does not allow arbitrary values and apparently is a bit mask, to + * be activated only at appropriate time. Don't change it randomly! + */ + switch (gspca_dev->width) { + case 176: /* 176x144 */ + cit_model2_Packet1(gspca_dev, 0x0026, 0x00c2); + break; + case 320: /* 320x240 */ + cit_model2_Packet1(gspca_dev, 0x0026, 0x0044); + break; + /* case VIDEOSIZE_352x240: */ + cit_model2_Packet1(gspca_dev, 0x0026, 0x0046); + break; + case 352: /* 352x288 */ + cit_model2_Packet1(gspca_dev, 0x0026, 0x0048); + break; + } + + /* FIXME this cannot be changed while streaming, so we + should report a grabbed flag for this control. */ + cit_model2_Packet1(gspca_dev, 0x0028, sd->lighting); + /* color balance rg2 */ + cit_model2_Packet1(gspca_dev, 0x001e, 0x002f); + /* saturation */ + cit_model2_Packet1(gspca_dev, 0x0020, 0x0034); + /* color balance yb */ + cit_model2_Packet1(gspca_dev, 0x0022, 0x00a0); + + /* Hardware control command */ + cit_model2_Packet1(gspca_dev, 0x0030, 0x0004); + + return 0; +} + +static int cit_start_model3(struct gspca_dev *gspca_dev) +{ + const unsigned short compression = 0; /* 0=none, 7=best frame rate */ + int i, clock_div = 0; + + /* HDG not in ibmcam driver, added to see if it helps with + auto-detecting between model3 and ibm netcamera pro */ + cit_read_reg(gspca_dev, 0x128, 1); + + cit_write_reg(gspca_dev, 0x0000, 0x0100); + cit_read_reg(gspca_dev, 0x0116, 0); + cit_write_reg(gspca_dev, 0x0060, 0x0116); + cit_write_reg(gspca_dev, 0x0002, 0x0112); + cit_write_reg(gspca_dev, 0x0000, 0x0123); + cit_write_reg(gspca_dev, 0x0001, 0x0117); + cit_write_reg(gspca_dev, 0x0040, 0x0108); + cit_write_reg(gspca_dev, 0x0019, 0x012c); + cit_write_reg(gspca_dev, 0x0060, 0x0116); + cit_write_reg(gspca_dev, 0x0002, 0x0115); + cit_write_reg(gspca_dev, 0x0003, 0x0115); + cit_read_reg(gspca_dev, 0x0115, 0); + cit_write_reg(gspca_dev, 0x000b, 0x0115); + + /* TESTME HDG not in ibmcam driver, added to see if it helps with + auto-detecting between model3 and ibm netcamera pro */ + if (0) { + cit_write_reg(gspca_dev, 0x0078, 0x012d); + cit_write_reg(gspca_dev, 0x0001, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0079, 0x012d); + cit_write_reg(gspca_dev, 0x00ff, 0x0130); + cit_write_reg(gspca_dev, 0xcd41, 0x0124); + cit_write_reg(gspca_dev, 0xfffa, 0x0124); + cit_read_reg(gspca_dev, 0x0126, 1); + } + + cit_model3_Packet1(gspca_dev, 0x000a, 0x0040); + cit_model3_Packet1(gspca_dev, 0x000b, 0x00f6); + cit_model3_Packet1(gspca_dev, 0x000c, 0x0002); + cit_model3_Packet1(gspca_dev, 0x000d, 0x0020); + cit_model3_Packet1(gspca_dev, 0x000e, 0x0033); + cit_model3_Packet1(gspca_dev, 0x000f, 0x0007); + cit_model3_Packet1(gspca_dev, 0x0010, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0011, 0x0070); + cit_model3_Packet1(gspca_dev, 0x0012, 0x0030); + cit_model3_Packet1(gspca_dev, 0x0013, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0014, 0x0001); + cit_model3_Packet1(gspca_dev, 0x0015, 0x0001); + cit_model3_Packet1(gspca_dev, 0x0016, 0x0001); + cit_model3_Packet1(gspca_dev, 0x0017, 0x0001); + cit_model3_Packet1(gspca_dev, 0x0018, 0x0000); + cit_model3_Packet1(gspca_dev, 0x001e, 0x00c3); + cit_model3_Packet1(gspca_dev, 0x0020, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0028, 0x0010); + cit_model3_Packet1(gspca_dev, 0x0029, 0x0054); + cit_model3_Packet1(gspca_dev, 0x002a, 0x0013); + cit_model3_Packet1(gspca_dev, 0x002b, 0x0007); + cit_model3_Packet1(gspca_dev, 0x002d, 0x0028); + cit_model3_Packet1(gspca_dev, 0x002e, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0031, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0032, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0033, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0034, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0035, 0x0038); + cit_model3_Packet1(gspca_dev, 0x003a, 0x0001); + cit_model3_Packet1(gspca_dev, 0x003c, 0x001e); + cit_model3_Packet1(gspca_dev, 0x003f, 0x000a); + cit_model3_Packet1(gspca_dev, 0x0041, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0046, 0x003f); + cit_model3_Packet1(gspca_dev, 0x0047, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0050, 0x0005); + cit_model3_Packet1(gspca_dev, 0x0052, 0x001a); + cit_model3_Packet1(gspca_dev, 0x0053, 0x0003); + cit_model3_Packet1(gspca_dev, 0x005a, 0x006b); + cit_model3_Packet1(gspca_dev, 0x005d, 0x001e); + cit_model3_Packet1(gspca_dev, 0x005e, 0x0030); + cit_model3_Packet1(gspca_dev, 0x005f, 0x0041); + cit_model3_Packet1(gspca_dev, 0x0064, 0x0008); + cit_model3_Packet1(gspca_dev, 0x0065, 0x0015); + cit_model3_Packet1(gspca_dev, 0x0068, 0x000f); + cit_model3_Packet1(gspca_dev, 0x0079, 0x0000); + cit_model3_Packet1(gspca_dev, 0x007a, 0x0000); + cit_model3_Packet1(gspca_dev, 0x007c, 0x003f); + cit_model3_Packet1(gspca_dev, 0x0082, 0x000f); + cit_model3_Packet1(gspca_dev, 0x0085, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0099, 0x0000); + cit_model3_Packet1(gspca_dev, 0x009b, 0x0023); + cit_model3_Packet1(gspca_dev, 0x009c, 0x0022); + cit_model3_Packet1(gspca_dev, 0x009d, 0x0096); + cit_model3_Packet1(gspca_dev, 0x009e, 0x0096); + cit_model3_Packet1(gspca_dev, 0x009f, 0x000a); + + switch (gspca_dev->width) { + case 160: + cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */ + cit_write_reg(gspca_dev, 0x0024, 0x010b); /* Differs everywhere */ + cit_write_reg(gspca_dev, 0x00a9, 0x0119); + cit_write_reg(gspca_dev, 0x0016, 0x011b); + cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */ + cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */ + cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */ + cit_write_reg(gspca_dev, 0x0018, 0x0102); + cit_write_reg(gspca_dev, 0x0004, 0x0104); + cit_write_reg(gspca_dev, 0x0004, 0x011a); + cit_write_reg(gspca_dev, 0x0028, 0x011c); + cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */ + cit_write_reg(gspca_dev, 0x0000, 0x0118); + cit_write_reg(gspca_dev, 0x0000, 0x0132); + cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */ + cit_write_reg(gspca_dev, compression, 0x0109); + clock_div = 3; + break; + case 320: + cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */ + cit_write_reg(gspca_dev, 0x0028, 0x010b); /* Differs everywhere */ + cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same */ + cit_write_reg(gspca_dev, 0x0000, 0x011e); + cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */ + cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */ + /* 4 commands from 160x120 skipped */ + cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */ + cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */ + cit_write_reg(gspca_dev, compression, 0x0109); + cit_write_reg(gspca_dev, 0x00d9, 0x0119); + cit_write_reg(gspca_dev, 0x0006, 0x011b); + cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ + cit_write_reg(gspca_dev, 0x0010, 0x0104); + cit_write_reg(gspca_dev, 0x0004, 0x011a); + cit_write_reg(gspca_dev, 0x003f, 0x011c); + cit_write_reg(gspca_dev, 0x001c, 0x0118); + cit_write_reg(gspca_dev, 0x0000, 0x0132); + clock_div = 5; + break; + case 640: + cit_write_reg(gspca_dev, 0x00f0, 0x0105); + cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */ + cit_write_reg(gspca_dev, 0x0038, 0x010b); /* Differs everywhere */ + cit_write_reg(gspca_dev, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */ + cit_write_reg(gspca_dev, 0x0006, 0x011b); /* Same on 320x240, 640x480 */ + cit_write_reg(gspca_dev, 0x0004, 0x011d); /* NC */ + cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */ + cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */ + cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */ + cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ + cit_write_reg(gspca_dev, 0x0016, 0x0104); /* NC */ + cit_write_reg(gspca_dev, 0x0004, 0x011a); /* Same on 320x240, 640x480 */ + cit_write_reg(gspca_dev, 0x003f, 0x011c); /* Same on 320x240, 640x480 */ + cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */ + cit_write_reg(gspca_dev, 0x001c, 0x0118); /* Same on 320x240, 640x480 */ + cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */ + cit_write_reg(gspca_dev, compression, 0x0109); + cit_write_reg(gspca_dev, 0x0040, 0x0101); + cit_write_reg(gspca_dev, 0x0040, 0x0103); + cit_write_reg(gspca_dev, 0x0000, 0x0132); /* Same on 320x240, 640x480 */ + clock_div = 7; + break; + } + + cit_model3_Packet1(gspca_dev, 0x007e, 0x000e); /* Hue */ + cit_model3_Packet1(gspca_dev, 0x0036, 0x0011); /* Brightness */ + cit_model3_Packet1(gspca_dev, 0x0060, 0x0002); /* Sharpness */ + cit_model3_Packet1(gspca_dev, 0x0061, 0x0004); /* Sharpness */ + cit_model3_Packet1(gspca_dev, 0x0062, 0x0005); /* Sharpness */ + cit_model3_Packet1(gspca_dev, 0x0063, 0x0014); /* Sharpness */ + cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0); /* Red sharpness */ + cit_model3_Packet1(gspca_dev, 0x0097, 0x0096); /* Blue sharpness */ + cit_model3_Packet1(gspca_dev, 0x0067, 0x0001); /* Contrast */ + cit_model3_Packet1(gspca_dev, 0x005b, 0x000c); /* Contrast */ + cit_model3_Packet1(gspca_dev, 0x005c, 0x0016); /* Contrast */ + cit_model3_Packet1(gspca_dev, 0x0098, 0x000b); + cit_model3_Packet1(gspca_dev, 0x002c, 0x0003); /* Was 1, broke 640x480 */ + cit_model3_Packet1(gspca_dev, 0x002f, 0x002a); + cit_model3_Packet1(gspca_dev, 0x0030, 0x0029); + cit_model3_Packet1(gspca_dev, 0x0037, 0x0002); + cit_model3_Packet1(gspca_dev, 0x0038, 0x0059); + cit_model3_Packet1(gspca_dev, 0x003d, 0x002e); + cit_model3_Packet1(gspca_dev, 0x003e, 0x0028); + cit_model3_Packet1(gspca_dev, 0x0078, 0x0005); + cit_model3_Packet1(gspca_dev, 0x007b, 0x0011); + cit_model3_Packet1(gspca_dev, 0x007d, 0x004b); + cit_model3_Packet1(gspca_dev, 0x007f, 0x0022); + cit_model3_Packet1(gspca_dev, 0x0080, 0x000c); + cit_model3_Packet1(gspca_dev, 0x0081, 0x000b); + cit_model3_Packet1(gspca_dev, 0x0083, 0x00fd); + cit_model3_Packet1(gspca_dev, 0x0086, 0x000b); + cit_model3_Packet1(gspca_dev, 0x0087, 0x000b); + cit_model3_Packet1(gspca_dev, 0x007e, 0x000e); + cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0); /* Red sharpness */ + cit_model3_Packet1(gspca_dev, 0x0097, 0x0096); /* Blue sharpness */ + cit_model3_Packet1(gspca_dev, 0x0098, 0x000b); + + /* FIXME we should probably use cit_get_clock_div() here (in + combination with isoc negotiation using the programmable isoc size) + like with the IBM netcam pro). */ + cit_write_reg(gspca_dev, clock_div, 0x0111); /* Clock Divider */ + + switch (gspca_dev->width) { + case 160: + cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */ + cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */ + cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */ + cit_model3_Packet1(gspca_dev, 0x0040, 0x000a); + cit_model3_Packet1(gspca_dev, 0x0051, 0x000a); + break; + case 320: + cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */ + cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */ + cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */ + cit_model3_Packet1(gspca_dev, 0x0040, 0x0008); + cit_model3_Packet1(gspca_dev, 0x0051, 0x000b); + break; + case 640: + cit_model3_Packet1(gspca_dev, 0x001f, 0x0002); /* !Same */ + cit_model3_Packet1(gspca_dev, 0x0039, 0x003e); /* !Same */ + cit_model3_Packet1(gspca_dev, 0x0040, 0x0008); + cit_model3_Packet1(gspca_dev, 0x0051, 0x000a); + break; + } + +/* if (sd->input_index) { */ + if (rca_input) { + for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) { + if (rca_initdata[i][0]) + cit_read_reg(gspca_dev, rca_initdata[i][2], 0); + else + cit_write_reg(gspca_dev, rca_initdata[i][1], + rca_initdata[i][2]); + } + } + + return 0; +} + +static int cit_start_model4(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + cit_write_reg(gspca_dev, 0x0000, 0x0100); + cit_write_reg(gspca_dev, 0x00c0, 0x0111); + cit_write_reg(gspca_dev, 0x00bc, 0x012c); + cit_write_reg(gspca_dev, 0x0080, 0x012b); + cit_write_reg(gspca_dev, 0x0000, 0x0108); + cit_write_reg(gspca_dev, 0x0001, 0x0133); + cit_write_reg(gspca_dev, 0x009b, 0x010f); + cit_write_reg(gspca_dev, 0x00bb, 0x010f); + cit_model4_Packet1(gspca_dev, 0x0038, 0x0000); + cit_model4_Packet1(gspca_dev, 0x000a, 0x005c); + + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0004, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0000, 0x0127); + cit_write_reg(gspca_dev, 0x00fb, 0x012e); + cit_write_reg(gspca_dev, 0x0000, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012f); + cit_write_reg(gspca_dev, 0xd055, 0x0124); + cit_write_reg(gspca_dev, 0x000c, 0x0127); + cit_write_reg(gspca_dev, 0x0009, 0x012e); + cit_write_reg(gspca_dev, 0xaa28, 0x0124); + + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0012, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0008, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x002a, 0x012d); + cit_write_reg(gspca_dev, 0x0000, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0xfffa, 0x0124); + cit_model4_Packet1(gspca_dev, 0x0034, 0x0000); + + switch (gspca_dev->width) { + case 128: /* 128x96 */ + cit_write_reg(gspca_dev, 0x0070, 0x0119); + cit_write_reg(gspca_dev, 0x00d0, 0x0111); + cit_write_reg(gspca_dev, 0x0039, 0x010a); + cit_write_reg(gspca_dev, 0x0001, 0x0102); + cit_write_reg(gspca_dev, 0x0028, 0x0103); + cit_write_reg(gspca_dev, 0x0000, 0x0104); + cit_write_reg(gspca_dev, 0x001e, 0x0105); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0016, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x000a, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0014, 0x012d); + cit_write_reg(gspca_dev, 0x0008, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012e); + cit_write_reg(gspca_dev, 0x001a, 0x0130); + cit_write_reg(gspca_dev, 0x8a0a, 0x0124); + cit_write_reg(gspca_dev, 0x005a, 0x012d); + cit_write_reg(gspca_dev, 0x9545, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x0127); + cit_write_reg(gspca_dev, 0x0018, 0x012e); + cit_write_reg(gspca_dev, 0x0043, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012f); + cit_write_reg(gspca_dev, 0xd055, 0x0124); + cit_write_reg(gspca_dev, 0x001c, 0x0127); + cit_write_reg(gspca_dev, 0x00eb, 0x012e); + cit_write_reg(gspca_dev, 0xaa28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0032, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0000, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0036, 0x012d); + cit_write_reg(gspca_dev, 0x0008, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0xfffa, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x001e, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0017, 0x0127); + cit_write_reg(gspca_dev, 0x0013, 0x012e); + cit_write_reg(gspca_dev, 0x0031, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x0017, 0x012d); + cit_write_reg(gspca_dev, 0x0078, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x0000, 0x0127); + cit_write_reg(gspca_dev, 0xfea8, 0x0124); + sd->sof_len = 2; + break; + case 160: /* 160x120 */ + cit_write_reg(gspca_dev, 0x0038, 0x0119); + cit_write_reg(gspca_dev, 0x00d0, 0x0111); + cit_write_reg(gspca_dev, 0x00b9, 0x010a); + cit_write_reg(gspca_dev, 0x0001, 0x0102); + cit_write_reg(gspca_dev, 0x0028, 0x0103); + cit_write_reg(gspca_dev, 0x0000, 0x0104); + cit_write_reg(gspca_dev, 0x001e, 0x0105); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0016, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x000b, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0014, 0x012d); + cit_write_reg(gspca_dev, 0x0008, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012e); + cit_write_reg(gspca_dev, 0x001a, 0x0130); + cit_write_reg(gspca_dev, 0x8a0a, 0x0124); + cit_write_reg(gspca_dev, 0x005a, 0x012d); + cit_write_reg(gspca_dev, 0x9545, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x0127); + cit_write_reg(gspca_dev, 0x0018, 0x012e); + cit_write_reg(gspca_dev, 0x0043, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012f); + cit_write_reg(gspca_dev, 0xd055, 0x0124); + cit_write_reg(gspca_dev, 0x001c, 0x0127); + cit_write_reg(gspca_dev, 0x00c7, 0x012e); + cit_write_reg(gspca_dev, 0xaa28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0032, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0025, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0036, 0x012d); + cit_write_reg(gspca_dev, 0x0008, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0xfffa, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x001e, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0048, 0x0127); + cit_write_reg(gspca_dev, 0x0035, 0x012e); + cit_write_reg(gspca_dev, 0x00d0, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x0048, 0x012d); + cit_write_reg(gspca_dev, 0x0090, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x0001, 0x0127); + cit_write_reg(gspca_dev, 0xfea8, 0x0124); + sd->sof_len = 2; + break; + case 176: /* 176x144 */ + cit_write_reg(gspca_dev, 0x0038, 0x0119); + cit_write_reg(gspca_dev, 0x00d0, 0x0111); + cit_write_reg(gspca_dev, 0x00b9, 0x010a); + cit_write_reg(gspca_dev, 0x0001, 0x0102); + cit_write_reg(gspca_dev, 0x002c, 0x0103); + cit_write_reg(gspca_dev, 0x0000, 0x0104); + cit_write_reg(gspca_dev, 0x0024, 0x0105); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0016, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0007, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0014, 0x012d); + cit_write_reg(gspca_dev, 0x0001, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012e); + cit_write_reg(gspca_dev, 0x001a, 0x0130); + cit_write_reg(gspca_dev, 0x8a0a, 0x0124); + cit_write_reg(gspca_dev, 0x005e, 0x012d); + cit_write_reg(gspca_dev, 0x9545, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x0127); + cit_write_reg(gspca_dev, 0x0018, 0x012e); + cit_write_reg(gspca_dev, 0x0049, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012f); + cit_write_reg(gspca_dev, 0xd055, 0x0124); + cit_write_reg(gspca_dev, 0x001c, 0x0127); + cit_write_reg(gspca_dev, 0x00c7, 0x012e); + cit_write_reg(gspca_dev, 0xaa28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0032, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0028, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0036, 0x012d); + cit_write_reg(gspca_dev, 0x0008, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0xfffa, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x001e, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0010, 0x0127); + cit_write_reg(gspca_dev, 0x0013, 0x012e); + cit_write_reg(gspca_dev, 0x002a, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x0010, 0x012d); + cit_write_reg(gspca_dev, 0x006d, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x0001, 0x0127); + cit_write_reg(gspca_dev, 0xfea8, 0x0124); + /* TESTME HDG: this does not seem right + (it is 2 for all other resolutions) */ + sd->sof_len = 10; + break; + case 320: /* 320x240 */ + cit_write_reg(gspca_dev, 0x0070, 0x0119); + cit_write_reg(gspca_dev, 0x00d0, 0x0111); + cit_write_reg(gspca_dev, 0x0039, 0x010a); + cit_write_reg(gspca_dev, 0x0001, 0x0102); + cit_write_reg(gspca_dev, 0x0028, 0x0103); + cit_write_reg(gspca_dev, 0x0000, 0x0104); + cit_write_reg(gspca_dev, 0x001e, 0x0105); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0016, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x000a, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0014, 0x012d); + cit_write_reg(gspca_dev, 0x0008, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012e); + cit_write_reg(gspca_dev, 0x001a, 0x0130); + cit_write_reg(gspca_dev, 0x8a0a, 0x0124); + cit_write_reg(gspca_dev, 0x005a, 0x012d); + cit_write_reg(gspca_dev, 0x9545, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x0127); + cit_write_reg(gspca_dev, 0x0018, 0x012e); + cit_write_reg(gspca_dev, 0x0043, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012f); + cit_write_reg(gspca_dev, 0xd055, 0x0124); + cit_write_reg(gspca_dev, 0x001c, 0x0127); + cit_write_reg(gspca_dev, 0x00eb, 0x012e); + cit_write_reg(gspca_dev, 0xaa28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0032, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0000, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0036, 0x012d); + cit_write_reg(gspca_dev, 0x0008, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0xfffa, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x001e, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0017, 0x0127); + cit_write_reg(gspca_dev, 0x0013, 0x012e); + cit_write_reg(gspca_dev, 0x0031, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x0017, 0x012d); + cit_write_reg(gspca_dev, 0x0078, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x0000, 0x0127); + cit_write_reg(gspca_dev, 0xfea8, 0x0124); + sd->sof_len = 2; + break; + case 352: /* 352x288 */ + cit_write_reg(gspca_dev, 0x0070, 0x0119); + cit_write_reg(gspca_dev, 0x00c0, 0x0111); + cit_write_reg(gspca_dev, 0x0039, 0x010a); + cit_write_reg(gspca_dev, 0x0001, 0x0102); + cit_write_reg(gspca_dev, 0x002c, 0x0103); + cit_write_reg(gspca_dev, 0x0000, 0x0104); + cit_write_reg(gspca_dev, 0x0024, 0x0105); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0016, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0006, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0014, 0x012d); + cit_write_reg(gspca_dev, 0x0002, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012e); + cit_write_reg(gspca_dev, 0x001a, 0x0130); + cit_write_reg(gspca_dev, 0x8a0a, 0x0124); + cit_write_reg(gspca_dev, 0x005e, 0x012d); + cit_write_reg(gspca_dev, 0x9545, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x0127); + cit_write_reg(gspca_dev, 0x0018, 0x012e); + cit_write_reg(gspca_dev, 0x0049, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012f); + cit_write_reg(gspca_dev, 0xd055, 0x0124); + cit_write_reg(gspca_dev, 0x001c, 0x0127); + cit_write_reg(gspca_dev, 0x00cf, 0x012e); + cit_write_reg(gspca_dev, 0xaa28, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x0032, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0000, 0x0127); + cit_write_reg(gspca_dev, 0x00aa, 0x0130); + cit_write_reg(gspca_dev, 0x82a8, 0x0124); + cit_write_reg(gspca_dev, 0x0036, 0x012d); + cit_write_reg(gspca_dev, 0x0008, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0xfffa, 0x0124); + cit_write_reg(gspca_dev, 0x00aa, 0x012d); + cit_write_reg(gspca_dev, 0x001e, 0x012f); + cit_write_reg(gspca_dev, 0xd141, 0x0124); + cit_write_reg(gspca_dev, 0x0010, 0x0127); + cit_write_reg(gspca_dev, 0x0013, 0x012e); + cit_write_reg(gspca_dev, 0x0025, 0x0130); + cit_write_reg(gspca_dev, 0x8a28, 0x0124); + cit_write_reg(gspca_dev, 0x0010, 0x012d); + cit_write_reg(gspca_dev, 0x0048, 0x012f); + cit_write_reg(gspca_dev, 0xd145, 0x0124); + cit_write_reg(gspca_dev, 0x0000, 0x0127); + cit_write_reg(gspca_dev, 0xfea8, 0x0124); + sd->sof_len = 2; + break; + } + + cit_model4_Packet1(gspca_dev, 0x0038, 0x0004); + + return 0; +} + +static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev) +{ + const unsigned short compression = 0; /* 0=none, 7=best frame rate */ + int i, clock_div; + + clock_div = cit_get_clock_div(gspca_dev); + if (clock_div < 0) + return clock_div; + + cit_write_reg(gspca_dev, 0x0003, 0x0133); + cit_write_reg(gspca_dev, 0x0000, 0x0117); + cit_write_reg(gspca_dev, 0x0008, 0x0123); + cit_write_reg(gspca_dev, 0x0000, 0x0100); + cit_write_reg(gspca_dev, 0x0060, 0x0116); + /* cit_write_reg(gspca_dev, 0x0002, 0x0112); see sd_stop0 */ + cit_write_reg(gspca_dev, 0x0000, 0x0133); + cit_write_reg(gspca_dev, 0x0000, 0x0123); + cit_write_reg(gspca_dev, 0x0001, 0x0117); + cit_write_reg(gspca_dev, 0x0040, 0x0108); + cit_write_reg(gspca_dev, 0x0019, 0x012c); + cit_write_reg(gspca_dev, 0x0060, 0x0116); + /* cit_write_reg(gspca_dev, 0x000b, 0x0115); see sd_stop0 */ + + cit_model3_Packet1(gspca_dev, 0x0049, 0x0000); + + cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x003a, 0x0102); /* Hstart */ + cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */ + cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */ + cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */ + cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */ + cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */ + + switch (gspca_dev->width) { + case 160: /* 160x120 */ + cit_write_reg(gspca_dev, 0x0024, 0x010b); + cit_write_reg(gspca_dev, 0x0089, 0x0119); + cit_write_reg(gspca_dev, 0x000a, 0x011b); + cit_write_reg(gspca_dev, 0x0003, 0x011e); + cit_write_reg(gspca_dev, 0x0007, 0x0104); + cit_write_reg(gspca_dev, 0x0009, 0x011a); + cit_write_reg(gspca_dev, 0x008b, 0x011c); + cit_write_reg(gspca_dev, 0x0008, 0x0118); + cit_write_reg(gspca_dev, 0x0000, 0x0132); + break; + case 320: /* 320x240 */ + cit_write_reg(gspca_dev, 0x0028, 0x010b); + cit_write_reg(gspca_dev, 0x00d9, 0x0119); + cit_write_reg(gspca_dev, 0x0006, 0x011b); + cit_write_reg(gspca_dev, 0x0000, 0x011e); + cit_write_reg(gspca_dev, 0x000e, 0x0104); + cit_write_reg(gspca_dev, 0x0004, 0x011a); + cit_write_reg(gspca_dev, 0x003f, 0x011c); + cit_write_reg(gspca_dev, 0x000c, 0x0118); + cit_write_reg(gspca_dev, 0x0000, 0x0132); + break; + } + + cit_model3_Packet1(gspca_dev, 0x0019, 0x0031); + cit_model3_Packet1(gspca_dev, 0x001a, 0x0003); + cit_model3_Packet1(gspca_dev, 0x001b, 0x0038); + cit_model3_Packet1(gspca_dev, 0x001c, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0024, 0x0001); + cit_model3_Packet1(gspca_dev, 0x0027, 0x0001); + cit_model3_Packet1(gspca_dev, 0x002a, 0x0004); + cit_model3_Packet1(gspca_dev, 0x0035, 0x000b); + cit_model3_Packet1(gspca_dev, 0x003f, 0x0001); + cit_model3_Packet1(gspca_dev, 0x0044, 0x0000); + cit_model3_Packet1(gspca_dev, 0x0054, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00c4, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00e7, 0x0001); + cit_model3_Packet1(gspca_dev, 0x00e9, 0x0001); + cit_model3_Packet1(gspca_dev, 0x00ee, 0x0000); + cit_model3_Packet1(gspca_dev, 0x00f3, 0x00c0); + + cit_write_reg(gspca_dev, compression, 0x0109); + cit_write_reg(gspca_dev, clock_div, 0x0111); + +/* if (sd->input_index) { */ + if (rca_input) { + for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) { + if (rca_initdata[i][0]) + cit_read_reg(gspca_dev, rca_initdata[i][2], 0); + else + cit_write_reg(gspca_dev, rca_initdata[i][1], + rca_initdata[i][2]); + } + } + + return 0; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int packet_size; + + packet_size = cit_get_packet_size(gspca_dev); + if (packet_size < 0) + return packet_size; + + switch (sd->model) { + case CIT_MODEL0: + cit_start_model0(gspca_dev); + break; + case CIT_MODEL1: + cit_start_model1(gspca_dev); + break; + case CIT_MODEL2: + cit_start_model2(gspca_dev); + break; + case CIT_MODEL3: + cit_start_model3(gspca_dev); + break; + case CIT_MODEL4: + cit_start_model4(gspca_dev); + break; + case CIT_IBM_NETCAM_PRO: + cit_start_ibm_netcam_pro(gspca_dev); + break; + } + + cit_set_brightness(gspca_dev); + cit_set_contrast(gspca_dev); + cit_set_hue(gspca_dev); + cit_set_sharpness(gspca_dev); + cit_set_lighting(gspca_dev); + cit_set_hflip(gspca_dev); + + /* Program max isoc packet size */ + cit_write_reg(gspca_dev, packet_size >> 8, 0x0106); + cit_write_reg(gspca_dev, packet_size & 0xff, 0x0107); + + cit_restart_stream(gspca_dev); + + return 0; +} + +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + struct usb_host_interface *alt; + int max_packet_size; + + switch (gspca_dev->width) { + case 160: + max_packet_size = 450; + break; + case 176: + max_packet_size = 600; + break; + default: + max_packet_size = 1022; + break; + } + + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ + alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size); + + return 0; +} + +static int sd_isoc_nego(struct gspca_dev *gspca_dev) +{ + int ret, packet_size, min_packet_size; + struct usb_host_interface *alt; + + switch (gspca_dev->width) { + case 160: + min_packet_size = 200; + break; + case 176: + min_packet_size = 266; + break; + default: + min_packet_size = 400; + break; + } + + alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + if (packet_size <= min_packet_size) + return -EIO; + + packet_size -= 100; + if (packet_size < min_packet_size) + packet_size = min_packet_size; + alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size); + + ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); + if (ret < 0) + err("set alt 1 err %d", ret); + + return ret; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + cit_write_reg(gspca_dev, 0x0000, 0x010c); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* We cannot use gspca_dev->present here as that is not set when + sd_init gets called and we get called from sd_init */ + if (!gspca_dev->dev) + return; + + switch (sd->model) { + case CIT_MODEL0: + /* HDG windows does this, but it causes the cams autogain to + restart from a gain of 0, which does not look good when + changing resolutions. */ + /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */ + cit_write_reg(gspca_dev, 0x00c0, 0x0100); /* LED Off */ + break; + case CIT_MODEL1: + cit_send_FF_04_02(gspca_dev); + cit_read_reg(gspca_dev, 0x0100, 0); + cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */ + break; + case CIT_MODEL2: + case CIT_MODEL4: + cit_model2_Packet1(gspca_dev, 0x0030, 0x0004); + + cit_write_reg(gspca_dev, 0x0080, 0x0100); /* LED Off */ + cit_write_reg(gspca_dev, 0x0020, 0x0111); + cit_write_reg(gspca_dev, 0x00a0, 0x0111); + + cit_model2_Packet1(gspca_dev, 0x0030, 0x0002); + + cit_write_reg(gspca_dev, 0x0020, 0x0111); + cit_write_reg(gspca_dev, 0x0000, 0x0112); + break; + case CIT_MODEL3: + cit_write_reg(gspca_dev, 0x0006, 0x012c); + cit_model3_Packet1(gspca_dev, 0x0046, 0x0000); + cit_read_reg(gspca_dev, 0x0116, 0); + cit_write_reg(gspca_dev, 0x0064, 0x0116); + cit_read_reg(gspca_dev, 0x0115, 0); + cit_write_reg(gspca_dev, 0x0003, 0x0115); + cit_write_reg(gspca_dev, 0x0008, 0x0123); + cit_write_reg(gspca_dev, 0x0000, 0x0117); + cit_write_reg(gspca_dev, 0x0000, 0x0112); + cit_write_reg(gspca_dev, 0x0080, 0x0100); + break; + case CIT_IBM_NETCAM_PRO: + cit_model3_Packet1(gspca_dev, 0x0049, 0x00ff); + cit_write_reg(gspca_dev, 0x0006, 0x012c); + cit_write_reg(gspca_dev, 0x0000, 0x0116); + /* HDG windows does this, but I cannot get the camera + to restart with this without redoing the entire init + sequence which makes switching modes really slow */ + /* cit_write_reg(gspca_dev, 0x0006, 0x0115); */ + cit_write_reg(gspca_dev, 0x0008, 0x0123); + cit_write_reg(gspca_dev, 0x0000, 0x0117); + cit_write_reg(gspca_dev, 0x0003, 0x0133); + cit_write_reg(gspca_dev, 0x0000, 0x0111); + /* HDG windows does this, but I get a green picture when + restarting the stream after this */ + /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */ + cit_write_reg(gspca_dev, 0x00c0, 0x0100); + break; + } + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + /* If the last button state is pressed, release it now! */ + if (sd->button_state) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + sd->button_state = 0; + } +#endif +} + +static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 byte3 = 0, byte4 = 0; + int i; + + switch (sd->model) { + case CIT_MODEL0: + case CIT_MODEL1: + case CIT_MODEL3: + case CIT_IBM_NETCAM_PRO: + switch (gspca_dev->width) { + case 160: /* 160x120 */ + byte3 = 0x02; + byte4 = 0x0a; + break; + case 176: /* 176x144 */ + byte3 = 0x02; + byte4 = 0x0e; + break; + case 320: /* 320x240 */ + byte3 = 0x02; + byte4 = 0x08; + break; + case 352: /* 352x288 */ + byte3 = 0x02; + byte4 = 0x00; + break; + case 640: + byte3 = 0x03; + byte4 = 0x08; + break; + } + + /* These have a different byte3 */ + if (sd->model <= CIT_MODEL1) + byte3 = 0x00; + + for (i = 0; i < len; i++) { + /* For this model the SOF always starts at offset 0 + so no need to search the entire frame */ + if (sd->model == CIT_MODEL0 && sd->sof_read != i) + break; + + switch (sd->sof_read) { + case 0: + if (data[i] == 0x00) + sd->sof_read++; + break; + case 1: + if (data[i] == 0xff) + sd->sof_read++; + else if (data[i] == 0x00) + sd->sof_read = 1; + else + sd->sof_read = 0; + break; + case 2: + if (data[i] == byte3) + sd->sof_read++; + else if (data[i] == 0x00) + sd->sof_read = 1; + else + sd->sof_read = 0; + break; + case 3: + if (data[i] == byte4) { + sd->sof_read = 0; + return data + i + (sd->sof_len - 3); + } + if (byte3 == 0x00 && data[i] == 0xff) + sd->sof_read = 2; + else if (data[i] == 0x00) + sd->sof_read = 1; + else + sd->sof_read = 0; + break; + } + } + break; + case CIT_MODEL2: + case CIT_MODEL4: + /* TESTME we need to find a longer sof signature to avoid + false positives */ + for (i = 0; i < len; i++) { + switch (sd->sof_read) { + case 0: + if (data[i] == 0x00) + sd->sof_read++; + break; + case 1: + sd->sof_read = 0; + if (data[i] == 0xff) { + if (i >= 4) + PDEBUG(D_FRAM, + "header found at offset: %d: %02x %02x 00 %02x %02x %02x\n", + i - 1, + data[i - 4], + data[i - 3], + data[i], + data[i + 1], + data[i + 2]); + else + PDEBUG(D_FRAM, + "header found at offset: %d: 00 %02x %02x %02x\n", + i - 1, + data[i], + data[i + 1], + data[i + 2]); + return data + i + (sd->sof_len - 1); + } + break; + } + } + break; + } + return NULL; +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned char *sof; + + sof = cit_find_sof(gspca_dev, data, len); + if (sof) { + int n; + + /* finish decoding current frame */ + n = sof - data; + if (n > sd->sof_len) + n -= sd->sof_len; + else + n = 0; + gspca_frame_add(gspca_dev, LAST_PACKET, + data, n); + gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); + len -= sof - data; + data = sof; + } + + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) { + if (sd->stop_on_control_change) + sd_stopN(gspca_dev); + cit_set_brightness(gspca_dev); + if (sd->stop_on_control_change) + cit_restart_stream(gspca_dev); + } + + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + + return 0; +} + +static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) { + if (sd->stop_on_control_change) + sd_stopN(gspca_dev); + cit_set_contrast(gspca_dev); + if (sd->stop_on_control_change) + cit_restart_stream(gspca_dev); + } + + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->contrast; + + return 0; +} + +static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hue = val; + if (gspca_dev->streaming) { + if (sd->stop_on_control_change) + sd_stopN(gspca_dev); + cit_set_hue(gspca_dev); + if (sd->stop_on_control_change) + cit_restart_stream(gspca_dev); + } + return 0; +} + +static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hue; + + return 0; +} + +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) { + if (sd->stop_on_control_change) + sd_stopN(gspca_dev); + cit_set_sharpness(gspca_dev); + if (sd->stop_on_control_change) + cit_restart_stream(gspca_dev); + } + return 0; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + + return 0; +} + +static int sd_setlighting(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->lighting = val; + if (gspca_dev->streaming) { + if (sd->stop_on_control_change) + sd_stopN(gspca_dev); + cit_set_lighting(gspca_dev); + if (sd->stop_on_control_change) + cit_restart_stream(gspca_dev); + } + return 0; +} + +static int sd_getlighting(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->lighting; + + return 0; +} + +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hflip = val; + if (gspca_dev->streaming) { + if (sd->stop_on_control_change) + sd_stopN(gspca_dev); + cit_set_hflip(gspca_dev); + if (sd->stop_on_control_change) + cit_restart_stream(gspca_dev); + } + return 0; +} + +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hflip; + + return 0; +} + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static void cit_check_button(struct gspca_dev *gspca_dev) +{ + int new_button_state; + struct sd *sd = (struct sd *)gspca_dev; + + switch (sd->model) { + case CIT_MODEL3: + case CIT_IBM_NETCAM_PRO: + break; + default: /* TEST ME unknown if this works on other models too */ + return; + } + + /* Read the button state */ + cit_read_reg(gspca_dev, 0x0113, 0); + new_button_state = !gspca_dev->usb_buf[0]; + + /* Tell the cam we've seen the button press, notice that this + is a nop (iow the cam keeps reporting pressed) until the + button is actually released. */ + if (new_button_state) + cit_write_reg(gspca_dev, 0x01, 0x0113); + + if (sd->button_state != new_button_state) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, + new_button_state); + input_sync(gspca_dev->input_dev); + sd->button_state = new_button_state; + } +} +#endif + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .dq_callback = cit_check_button, + .other_input = 1, +#endif +}; + +static const struct sd_desc sd_desc_isoc_nego = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .isoc_init = sd_isoc_init, + .isoc_nego = sd_isoc_nego, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .dq_callback = cit_check_button, + .other_input = 1, +#endif +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + { USB_DEVICE_VER(0x0545, 0x8080, 0x0001, 0x0001), .driver_info = CIT_MODEL0 }, + { USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002), .driver_info = CIT_MODEL1 }, + { USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a), .driver_info = CIT_MODEL2 }, + { USB_DEVICE_VER(0x0545, 0x8080, 0x0301, 0x0301), .driver_info = CIT_MODEL3 }, + { USB_DEVICE_VER(0x0545, 0x8002, 0x030a, 0x030a), .driver_info = CIT_MODEL4 }, + { USB_DEVICE_VER(0x0545, 0x800c, 0x030a, 0x030a), .driver_info = CIT_MODEL2 }, + { USB_DEVICE_VER(0x0545, 0x800d, 0x030a, 0x030a), .driver_info = CIT_MODEL4 }, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + const struct sd_desc *desc = &sd_desc; + + switch (id->driver_info) { + case CIT_MODEL0: + case CIT_MODEL1: + if (intf->cur_altsetting->desc.bInterfaceNumber != 2) + return -ENODEV; + break; + case CIT_MODEL2: + case CIT_MODEL4: + if (intf->cur_altsetting->desc.bInterfaceNumber != 0) + return -ENODEV; + break; + case CIT_MODEL3: + if (intf->cur_altsetting->desc.bInterfaceNumber != 0) + return -ENODEV; + /* FIXME this likely applies to all model3 cams and probably + to other models too. */ + if (ibm_netcam_pro) + desc = &sd_desc_isoc_nego; + break; + } + + return gspca_dev_probe2(intf, id, desc, sizeof(struct sd), THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/zc3xx.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/zc3xx.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/zc3xx.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/zc3xx.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,7065 @@ +/* + * Z-Star/Vimicro zc301/zc302p/vc30x library + * + * Copyright (C) 2009-2011 Jean-Francois Moine + * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define MODULE_NAME "zc3xx" + +#include +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Jean-Francois Moine , " + "Serge A. Suchkov "); +MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver"); +MODULE_LICENSE("GPL"); + +static int force_sensor = -1; + +#define QUANT_VAL 1 /* quantization table */ +#include "zc3xx-reg.h" + +/* controls */ +enum e_ctrl { + BRIGHTNESS, + CONTRAST, + EXPOSURE, + GAMMA, + AUTOGAIN, + LIGHTFREQ, + SHARPNESS, + NCTRLS /* number of controls */ +}; + +#define AUTOGAIN_DEF 1 + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + + u8 quality; /* image quality */ +#define QUALITY_MIN 50 +#define QUALITY_MAX 80 +#define QUALITY_DEF 70 + + u8 bridge; + u8 sensor; /* Type of image sensor chip */ + u16 chip_revision; + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; +enum bridges { + BRIDGE_ZC301, + BRIDGE_ZC303, +}; +enum sensors { + SENSOR_ADCM2700, + SENSOR_CS2102, + SENSOR_CS2102K, + SENSOR_GC0303, + SENSOR_GC0305, + SENSOR_HDCS2020, + SENSOR_HV7131B, + SENSOR_HV7131R, + SENSOR_ICM105A, + SENSOR_MC501CB, + SENSOR_MT9V111_1, /* (mi360soc) zc301 */ + SENSOR_MT9V111_3, /* (mi360soc) zc303 */ + SENSOR_OV7620, /* OV7648 - same values */ + SENSOR_OV7630C, + SENSOR_PAS106, + SENSOR_PAS202B, + SENSOR_PB0330, + SENSOR_PO2030, + SENSOR_TAS5130C, + SENSOR_MAX +}; + +/* V4L2 controls supported by the driver */ +static void setcontrast(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); +static void setlightfreq(struct gspca_dev *gspca_dev); +static void setsharpness(struct gspca_dev *gspca_dev); + +static const struct ctrl sd_ctrls[NCTRLS] = { +[BRIGHTNESS] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128, + }, + .set_control = setcontrast + }, +[CONTRAST] = { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128, + }, + .set_control = setcontrast + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0x30d, + .maximum = 0x493e, + .step = 1, + .default_value = 0x927 + }, + .set_control = setexposure + }, +[GAMMA] = { + { + .id = V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = 1, + .maximum = 6, + .step = 1, + .default_value = 4, + }, + .set_control = setcontrast + }, +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = AUTOGAIN_DEF, + .flags = V4L2_CTRL_FLAG_UPDATE + }, + .set = sd_setautogain + }, +[LIGHTFREQ] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ + .step = 1, + .default_value = 0, + }, + .set_control = setlightfreq + }, +[SHARPNESS] = { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 2, + }, + .set_control = setsharpness + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static const struct v4l2_pix_format broken_vga_mode[] = { + {320, 232, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 232 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 472, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 472 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static const struct v4l2_pix_format sif_mode[] = { + {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* usb exchanges */ +struct usb_action { + u8 req; + u8 val; + u16 idx; +}; + +static const struct usb_action adcm2700_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */ + {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x58, ZC3XX_R116_RGAIN}, /* 01,16,58,cc */ + {0xa0, 0x5a, ZC3XX_R118_BGAIN}, /* 01,18,5a,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */ + {0xbb, 0x00, 0x0408}, /* 04,00,08,bb */ + {0xdd, 0x00, 0x0200}, /* 00,02,00,dd */ + {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */ + {0xbb, 0xe0, 0x0c2e}, /* 0c,e0,2e,bb */ + {0xbb, 0x01, 0x2000}, /* 20,01,00,bb */ + {0xbb, 0x96, 0x2400}, /* 24,96,00,bb */ + {0xbb, 0x06, 0x1006}, /* 10,06,06,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xbb, 0x5f, 0x2090}, /* 20,5f,90,bb */ + {0xbb, 0x01, 0x8000}, /* 80,01,00,bb */ + {0xbb, 0x09, 0x8400}, /* 84,09,00,bb */ + {0xbb, 0x86, 0x0002}, /* 00,86,02,bb */ + {0xbb, 0xe6, 0x0401}, /* 04,e6,01,bb */ + {0xbb, 0x86, 0x0802}, /* 08,86,02,bb */ + {0xbb, 0xe6, 0x0c01}, /* 0c,e6,01,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0020}, /* 00,fe,20,aa */ +/*mswin+*/ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, + {0xaa, 0xfe, 0x0002}, + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xaa, 0xb4, 0xcd37}, + {0xaa, 0xa4, 0x0004}, + {0xaa, 0xa8, 0x0007}, + {0xaa, 0xac, 0x0004}, +/*mswin-*/ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xbb, 0x04, 0x0400}, /* 04,04,00,bb */ + {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ + {0xbb, 0x01, 0x0400}, /* 04,01,00,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xbb, 0x41, 0x2803}, /* 28,41,03,bb */ + {0xbb, 0x40, 0x2c03}, /* 2c,40,03,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ + {} +}; +static const struct usb_action adcm2700_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ + {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x58, ZC3XX_R116_RGAIN}, /* 01,16,58,cc */ + {0xa0, 0x5a, ZC3XX_R118_BGAIN}, /* 01,18,5a,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xa0, 0xd3, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,d3,cc */ + {0xbb, 0x00, 0x0408}, /* 04,00,08,bb */ + {0xdd, 0x00, 0x0200}, /* 00,02,00,dd */ + {0xbb, 0x00, 0x0400}, /* 04,00,00,bb */ + {0xdd, 0x00, 0x0050}, /* 00,00,50,dd */ + {0xbb, 0x0f, 0x140f}, /* 14,0f,0f,bb */ + {0xbb, 0xe0, 0x0c2e}, /* 0c,e0,2e,bb */ + {0xbb, 0x01, 0x2000}, /* 20,01,00,bb */ + {0xbb, 0x96, 0x2400}, /* 24,96,00,bb */ + {0xbb, 0x06, 0x1006}, /* 10,06,06,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xbb, 0x5f, 0x2090}, /* 20,5f,90,bb */ + {0xbb, 0x01, 0x8000}, /* 80,01,00,bb */ + {0xbb, 0x09, 0x8400}, /* 84,09,00,bb */ + {0xbb, 0x86, 0x0002}, /* 00,88,02,bb */ + {0xbb, 0xe6, 0x0401}, /* 04,e6,01,bb */ + {0xbb, 0x86, 0x0802}, /* 08,88,02,bb */ + {0xbb, 0xe6, 0x0c01}, /* 0c,e6,01,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0020}, /* 00,fe,20,aa */ + /*******/ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xaa, 0xfe, 0x0000}, /* 00,fe,00,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xdd, 0x00, 0x0010}, /* 00,00,10,dd */ + {0xbb, 0x04, 0x0400}, /* 04,04,00,bb */ + {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ + {0xbb, 0x01, 0x0400}, /* 04,01,00,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xbb, 0x41, 0x2803}, /* 28,41,03,bb */ + {0xbb, 0x40, 0x2c03}, /* 2c,40,03,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ + {} +}; +static const struct usb_action adcm2700_50HZ[] = { + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xbb, 0x05, 0x8400}, /* 84,05,00,bb */ + {0xbb, 0xd0, 0xb007}, /* b0,d0,07,bb */ + {0xbb, 0xa0, 0xb80f}, /* b8,a0,0f,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ + {0xaa, 0x26, 0x00d0}, /* 00,26,d0,aa */ + {0xaa, 0x28, 0x0002}, /* 00,28,02,aa */ + {} +}; +static const struct usb_action adcm2700_60HZ[] = { + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xbb, 0x07, 0x8400}, /* 84,07,00,bb */ + {0xbb, 0x82, 0xb006}, /* b0,82,06,bb */ + {0xbb, 0x04, 0xb80d}, /* b8,04,0d,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ + {0xaa, 0x26, 0x0057}, /* 00,26,57,aa */ + {0xaa, 0x28, 0x0002}, /* 00,28,02,aa */ + {} +}; +static const struct usb_action adcm2700_NoFliker[] = { + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ + {0xbb, 0x07, 0x8400}, /* 84,07,00,bb */ + {0xbb, 0x05, 0xb000}, /* b0,05,00,bb */ + {0xbb, 0xa0, 0xb801}, /* b8,a0,01,bb */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xaa, 0xfe, 0x0010}, /* 00,fe,10,aa */ + {} +}; +static const struct usb_action cs2102_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x20, ZC3XX_R080_HBLANKHIGH}, + {0xa0, 0x21, ZC3XX_R081_HBLANKLOW}, + {0xa0, 0x30, ZC3XX_R083_RGAINADDR}, + {0xa0, 0x31, ZC3XX_R084_GGAINADDR}, + {0xa0, 0x32, ZC3XX_R085_BGAINADDR}, + {0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH}, + {0xa0, 0x24, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x25, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xaa, 0x02, 0x0008}, + {0xaa, 0x03, 0x0000}, + {0xaa, 0x11, 0x0000}, + {0xaa, 0x12, 0x0089}, + {0xaa, 0x13, 0x0000}, + {0xaa, 0x14, 0x00e9}, + {0xaa, 0x20, 0x0000}, + {0xaa, 0x22, 0x0000}, + {0xaa, 0x0b, 0x0004}, + {0xaa, 0x30, 0x0030}, + {0xaa, 0x31, 0x0030}, + {0xaa, 0x32, 0x0030}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x10, 0x01ae}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x68, ZC3XX_R18D_YTARGET}, + {0xa0, 0x00, 0x01ad}, + {} +}; + +static const struct usb_action cs2102_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x20, ZC3XX_R080_HBLANKHIGH}, + {0xa0, 0x21, ZC3XX_R081_HBLANKLOW}, + {0xa0, 0x30, ZC3XX_R083_RGAINADDR}, + {0xa0, 0x31, ZC3XX_R084_GGAINADDR}, + {0xa0, 0x32, ZC3XX_R085_BGAINADDR}, + {0xa0, 0x23, ZC3XX_R086_EXPTIMEHIGH}, + {0xa0, 0x24, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x25, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0xb3, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xaa, 0x02, 0x0008}, + {0xaa, 0x03, 0x0000}, + {0xaa, 0x11, 0x0001}, + {0xaa, 0x12, 0x0087}, + {0xaa, 0x13, 0x0001}, + {0xaa, 0x14, 0x00e7}, + {0xaa, 0x20, 0x0000}, + {0xaa, 0x22, 0x0000}, + {0xaa, 0x0b, 0x0004}, + {0xaa, 0x30, 0x0030}, + {0xaa, 0x31, 0x0030}, + {0xaa, 0x32, 0x0030}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x68, ZC3XX_R18D_YTARGET}, + {0xa0, 0x00, 0x01ad}, + {} +}; +static const struct usb_action cs2102_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x23, 0x0001}, + {0xaa, 0x24, 0x005f}, + {0xaa, 0x25, 0x0090}, + {0xaa, 0x21, 0x00dd}, + {0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0xbf, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x3a, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x98, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xdd, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xe4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf0, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action cs2102_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x23, 0x0000}, + {0xaa, 0x24, 0x00af}, + {0xaa, 0x25, 0x00c8}, + {0xaa, 0x21, 0x0068}, + {0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x5f, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x90, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x1d, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x4c, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x68, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xe3, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf0, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action cs2102_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x23, 0x0001}, + {0xaa, 0x24, 0x0055}, + {0xaa, 0x25, 0x00cc}, + {0xaa, 0x21, 0x003f}, + {0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0xab, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x98, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x30, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0xd4, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x39, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x70, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xb0, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action cs2102_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x23, 0x0000}, + {0xaa, 0x24, 0x00aa}, + {0xaa, 0x25, 0x00e6}, + {0xaa, 0x21, 0x003f}, + {0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x55, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xcc, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x18, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x6a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x3f, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xa5, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf0, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action cs2102_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x23, 0x0001}, + {0xaa, 0x24, 0x005f}, + {0xaa, 0x25, 0x0000}, + {0xaa, 0x21, 0x0001}, + {0xa0, 0x02, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0xbf, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x80, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x01, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xa0, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action cs2102_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x23, 0x0000}, + {0xaa, 0x24, 0x00af}, + {0xaa, 0x25, 0x0080}, + {0xaa, 0x21, 0x0001}, + {0xa0, 0x01, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x5f, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x80, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x01, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xa0, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {} +}; + +/* CS2102_KOCOM */ +static const struct usb_action cs2102K_InitialScale[] = { + {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x01, 0x01b1}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x19, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x1f, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {} +}; + +static const struct usb_action cs2102K_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, +/*fixme: next sequence = i2c exchanges*/ + {0xa0, 0x55, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0a, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0b, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0c, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7b, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0d, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xa3, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xfb, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x03, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x08, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0e, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x0f, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x10, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x11, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x12, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x18, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x15, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x16, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x17, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x01, 0x01b1}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x22, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x22, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xee, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x0f, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x19, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x1f, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x4c, ZC3XX_R118_BGAIN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x5c, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x96, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, +/*fixme:what does the next sequence?*/ + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0xd0, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x0a, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x44, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x44, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x21, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x13, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x7e, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x14, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x18, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {} +}; + +static const struct usb_action gc0305_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc */ + {0xaa, 0x13, 0x0002}, /* 00,13,02,aa */ + {0xaa, 0x15, 0x0003}, /* 00,15,03,aa */ + {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ + {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */ + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ + {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */ + {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */ + {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */ + {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */ + {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc */ + {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc */ + {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */ + {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */ + {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */ + {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */ + {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */ + {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */ + {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */ + {0xaa, 0x17, 0x00e6}, /* 00,17,e6,aa */ + {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */ + {0xaa, 0x19, 0x0086}, /* 00,19,86,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc */ + {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ + {0xa0, 0x85, ZC3XX_R18D_YTARGET}, /* 01,8d,85,cc */ + {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */ + {0xa0, 0x52, ZC3XX_R116_RGAIN}, /* 01,16,52,cc */ + {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* 01,17,40,cc */ + {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ + {0xa0, 0x03, ZC3XX_R113_RGB03}, /* 01,13,03,cc */ + {} +}; +static const struct usb_action gc0305_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc */ + {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */ + {0xaa, 0x15, 0x0001}, /* 00,15,01,aa */ + {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ + {0xaa, 0x02, 0x0000}, /* 00,02,00,aa */ + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ + {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa */ + {0xaa, 0x1d, 0x0080}, /* 00,1d,80,aa */ + {0xaa, 0x1f, 0x0008}, /* 00,1f,08,aa */ + {0xaa, 0x21, 0x0012}, /* 00,21,12,aa */ + {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc */ + {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc */ + {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa */ + {0xaa, 0x0b, 0x00b0}, /* 00,0b,b0,aa */ + {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa */ + {0xaa, 0x0d, 0x00b0}, /* 00,0d,b0,aa */ + {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa */ + {0xaa, 0x0f, 0x00b0}, /* 00,0f,b0,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x11, 0x00b0}, /* 00,11,b0,aa */ + {0xaa, 0x16, 0x0001}, /* 00,16,01,aa */ + {0xaa, 0x17, 0x00e8}, /* 00,17,e8,aa */ + {0xaa, 0x18, 0x0002}, /* 00,18,02,aa */ + {0xaa, 0x19, 0x0088}, /* 00,19,88,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x1b, 0x0020}, /* 00,1b,20,aa */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc */ + {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ + {0xa0, 0x00, 0x011e}, /* 01,1e,00,cc */ + {0xa0, 0x52, ZC3XX_R116_RGAIN}, /* 01,16,52,cc */ + {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* 01,17,40,cc */ + {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ + {0xa0, 0x03, ZC3XX_R113_RGB03}, /* 01,13,03,cc */ + {} +}; +static const struct usb_action gc0305_50HZ[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */ + {0xaa, 0x84, 0x0038}, /* 00,84,38,aa */ /* win: 00,84,ec */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc */ + {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ + /* win: 01,92,10 */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,8e,cc */ + /* win: 01,97,ec */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ +/* {0xa0, 0x85, ZC3XX_R18D_YTARGET}, * 01,8d,85,cc * + * if 640x480 */ + {} +}; +static const struct usb_action gc0305_60HZ[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ + {0xaa, 0x84, 0x00ec}, /* 00,84,ec,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc */ + {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0xec, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,ec,cc */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* 01,8d,80,cc */ + {} +}; + +static const struct usb_action gc0305_NoFliker[] = { + {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc */ + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ + {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,00,cc */ + {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,48,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,60,cc */ + {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */ + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* 01,8d,80,cc */ + {} +}; + +static const struct usb_action hdcs2020_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* qtable 0x05 */ + {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x1c, 0x0000}, + {0xaa, 0x0a, 0x0001}, + {0xaa, 0x0b, 0x0006}, + {0xaa, 0x0c, 0x007b}, + {0xaa, 0x0d, 0x00a7}, + {0xaa, 0x03, 0x00fb}, + {0xaa, 0x05, 0x0000}, + {0xaa, 0x06, 0x0003}, + {0xaa, 0x09, 0x0008}, + + {0xaa, 0x0f, 0x0018}, /* set sensor gain */ + {0xaa, 0x10, 0x0018}, + {0xaa, 0x11, 0x0018}, + {0xaa, 0x12, 0x0018}, + + {0xaa, 0x15, 0x004e}, + {0xaa, 0x1c, 0x0004}, + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + + {0xa0, 0x66, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xed, ZC3XX_R10B_RGB01}, + {0xa0, 0xed, ZC3XX_R10C_RGB02}, + {0xa0, 0xed, ZC3XX_R10D_RGB10}, + {0xa0, 0x66, ZC3XX_R10E_RGB11}, + {0xa0, 0xed, ZC3XX_R10F_RGB12}, + {0xa0, 0xed, ZC3XX_R110_RGB20}, + {0xa0, 0xed, ZC3XX_R111_RGB21}, + {0xa0, 0x66, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x13, 0x0031}, + {0xaa, 0x14, 0x0001}, + {0xaa, 0x0e, 0x0004}, + {0xaa, 0x19, 0x00cd}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 0x14 */ + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x41, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action hdcs2020_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x1c, 0x0000}, + {0xaa, 0x0a, 0x0001}, + {0xaa, 0x0b, 0x0006}, + {0xaa, 0x0c, 0x007a}, + {0xaa, 0x0d, 0x00a7}, + {0xaa, 0x03, 0x00fb}, + {0xaa, 0x05, 0x0000}, + {0xaa, 0x06, 0x0003}, + {0xaa, 0x09, 0x0008}, + {0xaa, 0x0f, 0x0018}, /* original setting */ + {0xaa, 0x10, 0x0018}, + {0xaa, 0x11, 0x0018}, + {0xaa, 0x12, 0x0018}, + {0xaa, 0x15, 0x004e}, + {0xaa, 0x1c, 0x0004}, + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x13, ZC3XX_R120_GAMMA00}, /* gamma 4 */ + {0xa0, 0x38, ZC3XX_R121_GAMMA01}, + {0xa0, 0x59, ZC3XX_R122_GAMMA02}, + {0xa0, 0x79, ZC3XX_R123_GAMMA03}, + {0xa0, 0x92, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa7, ZC3XX_R125_GAMMA05}, + {0xa0, 0xb9, ZC3XX_R126_GAMMA06}, + {0xa0, 0xc8, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd4, ZC3XX_R128_GAMMA08}, + {0xa0, 0xdf, ZC3XX_R129_GAMMA09}, + {0xa0, 0xe7, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xee, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf4, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf9, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xfc, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x26, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x66, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xed, ZC3XX_R10B_RGB01}, + {0xa0, 0xed, ZC3XX_R10C_RGB02}, + {0xa0, 0xed, ZC3XX_R10D_RGB10}, + {0xa0, 0x66, ZC3XX_R10E_RGB11}, + {0xa0, 0xed, ZC3XX_R10F_RGB12}, + {0xa0, 0xed, ZC3XX_R110_RGB20}, + {0xa0, 0xed, ZC3XX_R111_RGB21}, + {0xa0, 0x66, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + /**** set exposure ***/ + {0xaa, 0x13, 0x0031}, + {0xaa, 0x14, 0x0001}, + {0xaa, 0x0e, 0x0004}, + {0xaa, 0x19, 0x00cd}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x41, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action hdcs2020_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x13, 0x0018}, /* 00,13,18,aa */ + {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ + {0xaa, 0x0e, 0x0005}, /* 00,0e,05,aa */ + {0xaa, 0x19, 0x001f}, /* 00,19,1f,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ + {0xa0, 0x76, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,76,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x46, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,46,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */ + {0xa0, 0x05, ZC3XX_R01D_HSYNC_0}, /* 00,1d,05,cc */ + {0xa0, 0x1a, ZC3XX_R01E_HSYNC_1}, /* 00,1e,1a,cc */ + {0xa0, 0x2f, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2f,cc */ + {} +}; +static const struct usb_action hdcs2020_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x13, 0x0031}, /* 00,13,31,aa */ + {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ + {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ + {0xaa, 0x19, 0x00cd}, /* 00,19,cd,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ + {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,62,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3d,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x0c, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,0c,cc */ + {0xa0, 0x28, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,28,cc */ + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */ + {0xa0, 0x18, ZC3XX_R01E_HSYNC_1}, /* 00,1e,18,cc */ + {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */ + {} +}; +static const struct usb_action hdcs2020_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */ + {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ + {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ + {0xaa, 0x19, 0x0000}, /* 00,19,00,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ + {0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x04, ZC3XX_R01D_HSYNC_0}, /* 00,1d,04,cc */ + {0xa0, 0x17, ZC3XX_R01E_HSYNC_1}, /* 00,1e,17,cc */ + {0xa0, 0x2a, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2a,cc */ + {} +}; + +static const struct usb_action hv7131b_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xaa, 0x30, 0x002d}, + {0xaa, 0x01, 0x0005}, + {0xaa, 0x11, 0x0000}, + {0xaa, 0x13, 0x0001}, /* {0xaa, 0x13, 0x0000}, */ + {0xaa, 0x14, 0x0001}, + {0xaa, 0x15, 0x00e8}, + {0xaa, 0x16, 0x0002}, + {0xaa, 0x17, 0x0086}, /* 00,17,88,aa */ + {0xaa, 0x31, 0x0038}, + {0xaa, 0x32, 0x0038}, + {0xaa, 0x33, 0x0038}, + {0xaa, 0x5b, 0x0001}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x68, ZC3XX_R18D_YTARGET}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0xc0, 0x019b}, + {0xa0, 0xa0, 0x019c}, + {0xa0, 0x02, ZC3XX_R188_MINGAIN}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xaa, 0x02, 0x0090}, /* 00,02,80,aa */ + {} +}; + +static const struct usb_action hv7131b_Initial[] = { /* 640x480*/ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xaa, 0x30, 0x002d}, + {0xaa, 0x01, 0x0005}, + {0xaa, 0x11, 0x0001}, + {0xaa, 0x13, 0x0000}, /* {0xaa, 0x13, 0x0001}; */ + {0xaa, 0x14, 0x0001}, + {0xaa, 0x15, 0x00e6}, + {0xaa, 0x16, 0x0002}, + {0xaa, 0x17, 0x0086}, + {0xaa, 0x31, 0x0038}, + {0xaa, 0x32, 0x0038}, + {0xaa, 0x33, 0x0038}, + {0xaa, 0x5b, 0x0001}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0xc0, 0x019b}, + {0xa0, 0xa0, 0x019c}, + {0xa0, 0x02, ZC3XX_R188_MINGAIN}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xaa, 0x02, 0x0090}, /* {0xaa, 0x02, 0x0080}, */ + {} +}; +static const struct usb_action hv7131b_50HZ[] = { /* 640x480*/ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x0053}, /* 00,26,53,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ + {0xaa, 0x22, 0x001b}, /* 00,22,1b,aa */ + {0xaa, 0x23, 0x00fc}, /* 00,23,fc,aa */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,9b,cc */ + {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0xea, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,ea,cc */ + {0xa0, 0x60, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,60,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ + {0xa0, 0x1b, ZC3XX_R01F_HSYNC_2}, /* 00,1f,1b,cc */ + {0xa0, 0xfc, ZC3XX_R020_HSYNC_3}, /* 00,20,fc,cc */ + {} +}; +static const struct usb_action hv7131b_50HZScale[] = { /* 320x240 */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x0053}, /* 00,26,53,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ + {0xaa, 0x22, 0x0012}, /* 00,22,12,aa */ + {0xaa, 0x23, 0x0080}, /* 00,23,80,aa */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,9b,cc */ + {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */ + {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,01,cc */ + {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,d4,cc */ + {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,c0,cc */ + {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ + {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ + {0xa0, 0x12, ZC3XX_R01F_HSYNC_2}, /* 00,1f,12,cc */ + {0xa0, 0x80, ZC3XX_R020_HSYNC_3}, /* 00,20,80,cc */ + {} +}; +static const struct usb_action hv7131b_60HZ[] = { /* 640x480*/ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x00a1}, /* 00,26,a1,aa */ + {0xaa, 0x27, 0x0020}, /* 00,27,20,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0040}, /* 00,21,40,aa */ + {0xaa, 0x22, 0x0013}, /* 00,22,13,aa */ + {0xaa, 0x23, 0x004c}, /* 00,23,4c,aa */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,4d,cc */ + {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,60,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,c3,cc */ + {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,50,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */ + {0xa0, 0x13, ZC3XX_R01F_HSYNC_2}, /* 00,1f,13,cc */ + {0xa0, 0x4c, ZC3XX_R020_HSYNC_3}, /* 00,20,4c,cc */ + {} +}; +static const struct usb_action hv7131b_60HZScale[] = { /* 320x240 */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x00a1}, /* 00,26,a1,aa */ + {0xaa, 0x27, 0x0020}, /* 00,27,20,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ + {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ + {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,4d,cc */ + {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,60,cc */ + {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,01,cc */ + {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,86,cc */ + {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,a0,cc */ + {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ + {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,a0,cc */ + {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, /* 00,1f,16,cc */ + {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ + {} +}; +static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ + {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0010}, /* 00,21,10,aa */ + {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ + {0xaa, 0x23, 0x0003}, /* 00,23,03,aa */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,f8,cc */ + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,00,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,02,cc */ + {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,00,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x10, ZC3XX_R01E_HSYNC_1}, /* 00,1e,10,cc */ + {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, /* 00,1f,00,cc */ + {0xa0, 0x03, ZC3XX_R020_HSYNC_3}, /* 00,20,03,cc */ + {} +}; +static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ + {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ + {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ + {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,f8,cc */ + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,00,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,02,cc */ + {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,00,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,a0,cc */ + {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, /* 00,1f,16,cc */ + {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ + {} +}; + +/* from lPEPI264v.inf (hv7131b!) */ +static const struct usb_action hv7131r_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xdd, 0x00, 0x0200}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x000c}, + {0xaa, 0x11, 0x0000}, + {0xaa, 0x13, 0x0000}, + {0xaa, 0x14, 0x0001}, + {0xaa, 0x15, 0x00e8}, + {0xaa, 0x16, 0x0002}, + {0xaa, 0x17, 0x0088}, + {0xaa, 0x30, 0x000b}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0xc0, 0x019b}, + {0xa0, 0xa0, 0x019c}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {} +}; +static const struct usb_action hv7131r_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xdd, 0x00, 0x0200}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x000c}, + {0xaa, 0x11, 0x0000}, + {0xaa, 0x13, 0x0000}, + {0xaa, 0x14, 0x0001}, + {0xaa, 0x15, 0x00e6}, + {0xaa, 0x16, 0x0002}, + {0xaa, 0x17, 0x0086}, + {0xaa, 0x30, 0x000b}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0xc0, 0x019b}, + {0xa0, 0xa0, 0x019c}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {} +}; +static const struct usb_action hv7131r_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x06, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x68, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0xea, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x60, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x18, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action hv7131r_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x0c, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0xd1, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x40, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x18, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action hv7131r_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x06, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x1a, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x18, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action hv7131r_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x0c, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x35, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x18, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action hv7131r_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x58, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action hv7131r_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x04, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0xb0, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, + {} +}; + +static const struct usb_action icm105a_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH}, + {0xa0, 0x01, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH}, + {0xa0, 0x01, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x01, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x01, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xaa, 0x01, 0x0010}, + {0xaa, 0x03, 0x0000}, + {0xaa, 0x04, 0x0001}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0001}, + {0xaa, 0x04, 0x0011}, + {0xaa, 0x05, 0x00a0}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0002}, + {0xaa, 0x04, 0x0013}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0003}, + {0xaa, 0x04, 0x0015}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0004}, + {0xaa, 0x04, 0x0017}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x000d}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0005}, + {0xaa, 0x04, 0x0019}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0006}, + {0xaa, 0x04, 0x0017}, + {0xaa, 0x05, 0x0026}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0007}, + {0xaa, 0x04, 0x0019}, + {0xaa, 0x05, 0x0022}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0008}, + {0xaa, 0x04, 0x0021}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0009}, + {0xaa, 0x04, 0x0023}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x000d}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000a}, + {0xaa, 0x04, 0x0025}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000b}, + {0xaa, 0x04, 0x00ec}, + {0xaa, 0x05, 0x002e}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000c}, + {0xaa, 0x04, 0x00fa}, + {0xaa, 0x05, 0x002a}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x07, 0x000d}, + {0xaa, 0x01, 0x0005}, + {0xaa, 0x94, 0x0002}, + {0xaa, 0x90, 0x0000}, + {0xaa, 0x91, 0x001f}, + {0xaa, 0x10, 0x0064}, + {0xaa, 0x9b, 0x00f0}, + {0xaa, 0x9c, 0x0002}, + {0xaa, 0x14, 0x001a}, + {0xaa, 0x20, 0x0080}, + {0xaa, 0x22, 0x0080}, + {0xaa, 0x24, 0x0080}, + {0xaa, 0x26, 0x0080}, + {0xaa, 0x00, 0x0084}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xaa, 0xa8, 0x00c0}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0008}, + + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x52, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf7, ZC3XX_R10B_RGB01}, + {0xa0, 0xf7, ZC3XX_R10C_RGB02}, + {0xa0, 0xf7, ZC3XX_R10D_RGB10}, + {0xa0, 0x52, ZC3XX_R10E_RGB11}, + {0xa0, 0xf7, ZC3XX_R10F_RGB12}, + {0xa0, 0xf7, ZC3XX_R110_RGB20}, + {0xa0, 0xf7, ZC3XX_R111_RGB21}, + {0xa0, 0x52, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x0d, 0x0003}, + {0xaa, 0x0c, 0x008c}, + {0xaa, 0x0e, 0x0095}, + {0xaa, 0x0f, 0x0002}, + {0xaa, 0x1c, 0x0094}, + {0xaa, 0x1d, 0x0002}, + {0xaa, 0x20, 0x0080}, + {0xaa, 0x22, 0x0080}, + {0xaa, 0x24, 0x0080}, + {0xaa, 0x26, 0x0080}, + {0xaa, 0x00, 0x0084}, + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xe3, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xec, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf5, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0xc0, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; + +static const struct usb_action icm105a_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0c, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x00, ZC3XX_R097_WINYSTARTHIGH}, + {0xa0, 0x02, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R099_WINXSTARTHIGH}, + {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x02, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xaa, 0x01, 0x0010}, + {0xaa, 0x03, 0x0000}, + {0xaa, 0x04, 0x0001}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0001}, + {0xaa, 0x04, 0x0011}, + {0xaa, 0x05, 0x00a0}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0002}, + {0xaa, 0x04, 0x0013}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0001}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0003}, + {0xaa, 0x04, 0x0015}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0004}, + {0xaa, 0x04, 0x0017}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x000d}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0005}, + {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT}, + {0xa0, 0x19, ZC3XX_R093_I2CSETVALUE}, + {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND}, + {0xa1, 0x01, 0x0091}, + {0xaa, 0x05, 0x0020}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0006}, + {0xaa, 0x04, 0x0017}, + {0xaa, 0x05, 0x0026}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0007}, + {0xaa, 0x04, 0x0019}, + {0xaa, 0x05, 0x0022}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0008}, + {0xaa, 0x04, 0x0021}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x0009}, + {0xaa, 0x04, 0x0023}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x000d}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000a}, + {0xaa, 0x04, 0x0025}, + {0xaa, 0x05, 0x00aa}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000b}, + {0xaa, 0x04, 0x00ec}, + {0xaa, 0x05, 0x002e}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x03, 0x000c}, + {0xaa, 0x04, 0x00fa}, + {0xaa, 0x05, 0x002a}, + {0xaa, 0x06, 0x0005}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x07, 0x000d}, + {0xaa, 0x01, 0x0005}, + {0xaa, 0x94, 0x0002}, + {0xaa, 0x90, 0x0000}, + {0xaa, 0x91, 0x0010}, + {0xaa, 0x10, 0x0064}, + {0xaa, 0x9b, 0x00f0}, + {0xaa, 0x9c, 0x0002}, + {0xaa, 0x14, 0x001a}, + {0xaa, 0x20, 0x0080}, + {0xaa, 0x22, 0x0080}, + {0xaa, 0x24, 0x0080}, + {0xaa, 0x26, 0x0080}, + {0xaa, 0x00, 0x0084}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xaa, 0xa8, 0x0080}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, + {0xa1, 0x01, 0x0002}, + {0xa1, 0x01, 0x0008}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {0xa1, 0x01, 0x0008}, + + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + + {0xa0, 0x52, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf7, ZC3XX_R10B_RGB01}, + {0xa0, 0xf7, ZC3XX_R10C_RGB02}, + {0xa0, 0xf7, ZC3XX_R10D_RGB10}, + {0xa0, 0x52, ZC3XX_R10E_RGB11}, + {0xa0, 0xf7, ZC3XX_R10F_RGB12}, + {0xa0, 0xf7, ZC3XX_R110_RGB20}, + {0xa0, 0xf7, ZC3XX_R111_RGB21}, + {0xa0, 0x52, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x0d, 0x0003}, + {0xaa, 0x0c, 0x0020}, + {0xaa, 0x0e, 0x000e}, + {0xaa, 0x0f, 0x0002}, + {0xaa, 0x1c, 0x000d}, + {0xaa, 0x1d, 0x0002}, + {0xaa, 0x20, 0x0080}, + {0xaa, 0x22, 0x0080}, + {0xaa, 0x24, 0x0080}, + {0xaa, 0x26, 0x0080}, + {0xaa, 0x00, 0x0084}, + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, + {0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xd8, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action icm105a_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0020}, /* 00,0c,20,aa */ + {0xaa, 0x0e, 0x000e}, /* 00,0e,0e,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x000d}, /* 00,1c,0d,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x0d, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,0d,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x1a, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,1a,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x4b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4b,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ + {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */ + {0xa0, 0xd8, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d8,cc */ + {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {} +}; +static const struct usb_action icm105a_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x008c}, /* 00,0c,8c,aa */ + {0xaa, 0x0e, 0x0095}, /* 00,0e,95,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0094}, /* 00,1c,94,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x94, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,94,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x84, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,84,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ + {0xa0, 0xe3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,e3,cc */ + {0xa0, 0xec, ZC3XX_R01E_HSYNC_1}, /* 00,1e,ec,cc */ + {0xa0, 0xf5, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f5,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */ + {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ + {} +}; +static const struct usb_action icm105a_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ + {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0008}, /* 00,1c,08,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x08, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,08,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x41, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,41,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ + {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */ + {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */ + {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {} +}; +static const struct usb_action icm105a_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */ + {0xaa, 0x0e, 0x0086}, /* 00,0e,86,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0085}, /* 00,1c,85,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x85, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,85,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x08, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,08,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x12, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,12,cc */ + {0xa0, 0xc2, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c2,cc */ + {0xa0, 0xd6, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d6,cc */ + {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */ + {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ + {} +}; +static const struct usb_action icm105a_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ + {0xaa, 0x0e, 0x000d}, /* 00,0e,0d,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0000}, /* 00,1c,00,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x00, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,00,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */ + {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */ + {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {} +}; +static const struct usb_action icm105a_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ + {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ + {0xaa, 0x0e, 0x0081}, /* 00,0e,81,aa */ + {0xaa, 0x0f, 0x0002}, /* 00,0f,02,aa */ + {0xaa, 0x1c, 0x0080}, /* 00,1c,80,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x20, 0x0080}, /* 00,20,80,aa */ + {0xaa, 0x22, 0x0080}, /* 00,22,80,aa */ + {0xaa, 0x24, 0x0080}, /* 00,24,80,aa */ + {0xaa, 0x26, 0x0080}, /* 00,26,80,aa */ + {0xaa, 0x00, 0x0084}, /* 00,00,84,aa */ + {0xa0, 0x02, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,02,cc */ + {0xa0, 0x80, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,80,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x20, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,20,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0xc1, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c1,cc */ + {0xa0, 0xd4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d4,cc */ + {0xa0, 0xe8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN}, /* 01,a7,00,cc */ + {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ + {} +}; + +static const struct usb_action mc501cb_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ + {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */ + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */ + {0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */ + {0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */ + {0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ + {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */ + {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ + {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */ + {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */ + {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */ + {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ + {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */ + {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */ + {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */ + {0xaa, 0x18, 0x00de}, /* 00,18,de,aa */ + {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ + {0xaa, 0x1a, 0x0086}, /* 00,1a,86,aa */ + {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */ + {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ + {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */ + {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */ + {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */ + {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */ + {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */ + {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */ + {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */ + {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */ + {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */ + {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */ + {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */ + {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */ + {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */ + {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */ + {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */ + {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */ + {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */ + {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */ + {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */ + {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */ + {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */ + {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */ + {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */ + {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */ + {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */ + {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */ + {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */ + {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */ + {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */ + {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */ + {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */ + {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */ + {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */ + {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */ + {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */ + {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */ + {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */ + {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */ + {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x1c, 0x0050}, /* 00,1C,50,aa */ + {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */ + {0xaa, 0x3b, 0x001d}, /* 00,3b,1D,aa */ + {0xaa, 0x3c, 0x004c}, /* 00,3c,4C,aa */ + {0xaa, 0x3d, 0x0018}, /* 00,3d,18,aa */ + {0xaa, 0x3e, 0x006a}, /* 00,3e,6A,aa */ + {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ + {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */ + {0xaa, 0x51, 0x0027}, /* 00,51,27,aa */ + {0xaa, 0x52, 0x0020}, /* 00,52,20,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */ + {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */ + {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */ + {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */ + {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */ + {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */ + + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ + {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ + {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ + {} +}; + +static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ + {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */ + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xa0, 0x33, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,33,cc */ + {0xa0, 0x34, ZC3XX_R087_EXPTIMEMID}, /* 00,87,34,cc */ + {0xa0, 0x35, ZC3XX_R088_EXPTIMELOW}, /* 00,88,35,cc */ + {0xa0, 0xb0, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,b0,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ + {0xaa, 0x01, 0x0003}, /* 00,01,03,aa */ + {0xaa, 0x01, 0x0001}, /* 00,01,01,aa */ + {0xaa, 0x03, 0x0000}, /* 00,03,00,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x11, 0x0080}, /* 00,11,80,aa */ + {0xaa, 0x12, 0x0000}, /* 00,12,00,aa */ + {0xaa, 0x13, 0x0000}, /* 00,13,00,aa */ + {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ + {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */ + {0xaa, 0x16, 0x0000}, /* 00,16,00,aa */ + {0xaa, 0x17, 0x0001}, /* 00,17,01,aa */ + {0xaa, 0x18, 0x00d8}, /* 00,18,d8,aa */ + {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ + {0xaa, 0x1a, 0x0088}, /* 00,1a,88,aa */ + {0xaa, 0x20, 0x00a8}, /* 00,20,a8,aa */ + {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ + {0xaa, 0x23, 0x0000}, /* 00,23,00,aa */ + {0xaa, 0x24, 0x0000}, /* 00,24,00,aa */ + {0xaa, 0x40, 0x0033}, /* 00,40,33,aa */ + {0xaa, 0x41, 0x0077}, /* 00,41,77,aa */ + {0xaa, 0x42, 0x0053}, /* 00,42,53,aa */ + {0xaa, 0x43, 0x00b0}, /* 00,43,b0,aa */ + {0xaa, 0x4b, 0x0001}, /* 00,4b,01,aa */ + {0xaa, 0x72, 0x0020}, /* 00,72,20,aa */ + {0xaa, 0x73, 0x0000}, /* 00,73,00,aa */ + {0xaa, 0x80, 0x0000}, /* 00,80,00,aa */ + {0xaa, 0x85, 0x0050}, /* 00,85,50,aa */ + {0xaa, 0x91, 0x0070}, /* 00,91,70,aa */ + {0xaa, 0x92, 0x0072}, /* 00,92,72,aa */ + {0xaa, 0x03, 0x0001}, /* 00,03,01,aa */ + {0xaa, 0x10, 0x00a0}, /* 00,10,a0,aa */ + {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */ + {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */ + {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */ + {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */ + {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */ + {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */ + {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */ + {0xaa, 0xa4, 0x0010}, /* 00,a4,10,aa */ + {0xaa, 0xa5, 0x0020}, /* 00,a5,20,aa */ + {0xaa, 0xb1, 0x0044}, /* 00,b1,44,aa */ + {0xaa, 0xd0, 0x0001}, /* 00,d0,01,aa */ + {0xaa, 0xd1, 0x0085}, /* 00,d1,85,aa */ + {0xaa, 0xd2, 0x0080}, /* 00,d2,80,aa */ + {0xaa, 0xd3, 0x0080}, /* 00,d3,80,aa */ + {0xaa, 0xd4, 0x0080}, /* 00,d4,80,aa */ + {0xaa, 0xd5, 0x0080}, /* 00,d5,80,aa */ + {0xaa, 0xc0, 0x00c3}, /* 00,c0,c3,aa */ + {0xaa, 0xc2, 0x0044}, /* 00,c2,44,aa */ + {0xaa, 0xc4, 0x0040}, /* 00,c4,40,aa */ + {0xaa, 0xc5, 0x0020}, /* 00,c5,20,aa */ + {0xaa, 0xc6, 0x0008}, /* 00,c6,08,aa */ + {0xaa, 0x03, 0x0004}, /* 00,03,04,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x40, 0x0030}, /* 00,40,30,aa */ + {0xaa, 0x41, 0x0020}, /* 00,41,20,aa */ + {0xaa, 0x42, 0x002d}, /* 00,42,2d,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x1c, 0x0050}, /* 00,1c,50,aa */ + {0xaa, 0x11, 0x0081}, /* 00,11,81,aa */ + {0xaa, 0x3b, 0x003a}, /* 00,3b,3A,aa */ + {0xaa, 0x3c, 0x0098}, /* 00,3c,98,aa */ + {0xaa, 0x3d, 0x0030}, /* 00,3d,30,aa */ + {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ + {0xaa, 0x01, 0x0000}, /* 00,01,00,aa */ + {0xaa, 0x52, 0x00ff}, /* 00,52,FF,aa */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xaa, 0x03, 0x0002}, /* 00,03,02,aa */ + {0xaa, 0x51, 0x004e}, /* 00,51,4E,aa */ + {0xaa, 0x52, 0x0041}, /* 00,52,41,aa */ + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x50, 0x0010}, /* 00,50,10,aa */ + {0xaa, 0x51, 0x0010}, /* 00,51,10,aa */ + {0xaa, 0x54, 0x0010}, /* 00,54,10,aa */ + {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */ + {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */ + {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */ + {} +}; + +static const struct usb_action mc501cb_50HZ[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ + {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ + {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ + {0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */ + {0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */ + {0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */ + {} +}; + +static const struct usb_action mc501cb_50HZScale[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ + {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */ + {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */ + {0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */ + {0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */ + {0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */ + {} +}; + +static const struct usb_action mc501cb_60HZ[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ + {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ + {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ + {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ + {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ + {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ + {} +}; + +static const struct usb_action mc501cb_60HZScale[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ + {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ + {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ + {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ + {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */ + {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */ + {} +}; + +static const struct usb_action mc501cb_NoFliker[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ + {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ + {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ + {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ + {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ + {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ + {} +}; + +static const struct usb_action mc501cb_NoFlikerScale[] = { + {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ + {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ + {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ + {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ + {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ + {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ + {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */ + {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */ + {} +}; + +/* from zs211.inf */ +static const struct usb_action ov7620_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, /* 00,02,40,cc */ + {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */ + {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, /* 00,83,02,cc */ + {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, /* 00,85,01,cc */ + {0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,80,cc */ + {0xa0, 0x81, ZC3XX_R087_EXPTIMEMID}, /* 00,87,81,cc */ + {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, /* 00,88,10,cc */ + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd8, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d8,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xde, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,de,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */ + {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */ + {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ + {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ + {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */ + {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */ + {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ + {0xaa, 0x1a, 0x00f1}, /* 00,1a,f1,aa */ + {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */ + {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */ + {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */ + {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */ + {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */ + {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */ + {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ + {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */ + {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */ + {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */ + {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */ + {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */ + {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */ + {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */ + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x68, ZC3XX_R116_RGAIN}, /* 01,16,68,cc */ + {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ + {0xa0, 0x40, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,40,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */ + {} +}; +static const struct usb_action ov7620_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x50, ZC3XX_R002_CLOCKSELECT}, /* 00,02,50,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */ + /* mx change? */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,06,cc */ + {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, /* 00,83,02,cc */ + {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, /* 00,85,01,cc */ + {0xa0, 0x80, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,80,cc */ + {0xa0, 0x81, ZC3XX_R087_EXPTIMEMID}, /* 00,87,81,cc */ + {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, /* 00,88,10,cc */ + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,a1,cc */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xd6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d6,cc */ + /* OV7648 00,9c,d8,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xaa, 0x12, 0x0088}, /* 00,12,88,aa */ + {0xaa, 0x12, 0x0048}, /* 00,12,48,aa */ + {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x14, 0x0000}, /* 00,14,00,aa */ + {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ + {0xaa, 0x24, 0x0088}, /* 00,24,88,aa */ + {0xaa, 0x25, 0x0078}, /* 00,25,78,aa */ + {0xaa, 0x17, 0x0018}, /* 00,17,18,aa */ + {0xaa, 0x18, 0x00ba}, /* 00,18,ba,aa */ + {0xaa, 0x19, 0x0002}, /* 00,19,02,aa */ + {0xaa, 0x1a, 0x00f2}, /* 00,1a,f2,aa */ + {0xaa, 0x20, 0x0040}, /* 00,20,40,aa */ + {0xaa, 0x27, 0x00f6}, /* 00,27,f6,aa */ + {0xaa, 0x28, 0x00a0}, /* 00,28,a0,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x2a, 0x0083}, /* 00,2a,83,aa */ + {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */ + {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ + {0xaa, 0x74, 0x0020}, /* 00,74,20,aa */ + {0xaa, 0x61, 0x0068}, /* 00,61,68,aa */ + {0xaa, 0x64, 0x0088}, /* 00,64,88,aa */ + {0xaa, 0x00, 0x0000}, /* 00,00,00,aa */ + {0xaa, 0x06, 0x0080}, /* 00,06,80,aa */ + {0xaa, 0x01, 0x0090}, /* 00,01,90,aa */ + {0xaa, 0x02, 0x0030}, /* 00,02,30,aa */ + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,77,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x68, ZC3XX_R116_RGAIN}, /* 01,16,68,cc */ + {0xa0, 0x52, ZC3XX_R118_BGAIN}, /* 01,18,52,cc */ + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,50,cc */ + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,50,cc */ + {} +}; +static const struct usb_action ov7620_50HZ[] = { + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ + {0xaa, 0x2b, 0x0096}, /* 00,2b,96,aa */ + {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ + {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */ + {0xaa, 0x10, 0x0082}, /* 00,10,82,aa */ + {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */ +/* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc + * if mode0 (640x480) */ + {} +}; +static const struct usb_action ov7620_60HZ[] = { + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + /* (bug in zs211.inf) */ + {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ + {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */ + {0xaa, 0x75, 0x008a}, /* 00,75,8a,aa */ + {0xaa, 0x2d, 0x0005}, /* 00,2d,05,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x83, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,83,cc */ + {0xaa, 0x10, 0x0020}, /* 00,10,20,aa */ + {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */ +/* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc + * if mode0 (640x480) */ +/* ?? in gspca v1, it was + {0xa0, 0x00, 0x0039}, * 00,00,00,dd * + {0xa1, 0x01, 0x0037}, */ + {} +}; +static const struct usb_action ov7620_NoFliker[] = { + {0xaa, 0x13, 0x00a3}, /* 00,13,a3,aa */ + /* (bug in zs211.inf) */ + {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ + {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */ + {0xaa, 0x75, 0x008e}, /* 00,75,8e,aa */ + {0xaa, 0x2d, 0x0001}, /* 00,2d,01,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,04,cc */ + {0xa0, 0x18, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,18,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,01,cc */ +/* {0xa0, 0x44, ZC3XX_R002_CLOCKSELECT}, * 00,02,44,cc + * if mode1 (320x240) */ +/* ?? was + {0xa0, 0x00, 0x0039}, * 00,00,00,dd * + {0xa1, 0x01, 0x0037}, */ + {} +}; + +static const struct usb_action ov7630c_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x12, 0x0080}, + {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, + {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, + {0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH}, + {0xa0, 0x91, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x12, 0x0069}, + {0xaa, 0x04, 0x0020}, + {0xaa, 0x06, 0x0050}, + {0xaa, 0x13, 0x0083}, + {0xaa, 0x14, 0x0000}, + {0xaa, 0x15, 0x0024}, + {0xaa, 0x17, 0x0018}, + {0xaa, 0x18, 0x00ba}, + {0xaa, 0x19, 0x0002}, + {0xaa, 0x1a, 0x00f6}, + {0xaa, 0x1b, 0x0002}, + {0xaa, 0x20, 0x00c2}, + {0xaa, 0x24, 0x0060}, + {0xaa, 0x25, 0x0040}, + {0xaa, 0x26, 0x0030}, + {0xaa, 0x27, 0x00ea}, + {0xaa, 0x28, 0x00a0}, + {0xaa, 0x21, 0x0000}, + {0xaa, 0x2a, 0x0081}, + {0xaa, 0x2b, 0x0096}, + {0xaa, 0x2d, 0x0094}, + {0xaa, 0x2f, 0x003d}, + {0xaa, 0x30, 0x0024}, + {0xaa, 0x60, 0x0000}, + {0xaa, 0x61, 0x0040}, + {0xaa, 0x68, 0x007c}, + {0xaa, 0x6f, 0x0015}, + {0xaa, 0x75, 0x0088}, + {0xaa, 0x77, 0x00b5}, + {0xaa, 0x01, 0x0060}, + {0xaa, 0x02, 0x0060}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x46, ZC3XX_R118_BGAIN}, + {0xa0, 0x04, ZC3XX_R113_RGB03}, +/* 0x10, */ + {0xa1, 0x01, 0x0002}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x01, ZC3XX_R120_GAMMA00}, /* gamma 2 ?*/ + {0xa0, 0x0c, ZC3XX_R121_GAMMA01}, + {0xa0, 0x1f, ZC3XX_R122_GAMMA02}, + {0xa0, 0x3a, ZC3XX_R123_GAMMA03}, + {0xa0, 0x53, ZC3XX_R124_GAMMA04}, + {0xa0, 0x6d, ZC3XX_R125_GAMMA05}, + {0xa0, 0x85, ZC3XX_R126_GAMMA06}, + {0xa0, 0x9c, ZC3XX_R127_GAMMA07}, + {0xa0, 0xb0, ZC3XX_R128_GAMMA08}, + {0xa0, 0xc2, ZC3XX_R129_GAMMA09}, + {0xa0, 0xd1, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xde, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xe9, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xf2, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xf9, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x05, ZC3XX_R130_GAMMA10}, + {0xa0, 0x0f, ZC3XX_R131_GAMMA11}, + {0xa0, 0x16, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1a, ZC3XX_R133_GAMMA13}, + {0xa0, 0x19, ZC3XX_R134_GAMMA14}, + {0xa0, 0x19, ZC3XX_R135_GAMMA15}, + {0xa0, 0x17, ZC3XX_R136_GAMMA16}, + {0xa0, 0x15, ZC3XX_R137_GAMMA17}, + {0xa0, 0x12, ZC3XX_R138_GAMMA18}, + {0xa0, 0x10, ZC3XX_R139_GAMMA19}, + {0xa0, 0x0e, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x0b, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x09, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x08, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x06, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x03, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf8, ZC3XX_R10B_RGB01}, + {0xa0, 0xf8, ZC3XX_R10C_RGB02}, + {0xa0, 0xf8, ZC3XX_R10D_RGB10}, + {0xa0, 0x50, ZC3XX_R10E_RGB11}, + {0xa0, 0xf8, ZC3XX_R10F_RGB12}, + {0xa0, 0xf8, ZC3XX_R110_RGB20}, + {0xa0, 0xf8, ZC3XX_R111_RGB21}, + {0xa0, 0x50, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xaa, 0x10, 0x001b}, + {0xaa, 0x76, 0x0002}, + {0xaa, 0x2a, 0x0081}, + {0xaa, 0x2b, 0x0000}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x01, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xb8, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x37, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xaa, 0x13, 0x0083}, /* 40 */ + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; + +static const struct usb_action ov7630c_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x06, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0xa1, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + + {0xaa, 0x12, 0x0080}, + {0xa0, 0x02, ZC3XX_R083_RGAINADDR}, + {0xa0, 0x01, ZC3XX_R085_BGAINADDR}, + {0xa0, 0x90, ZC3XX_R086_EXPTIMEHIGH}, + {0xa0, 0x91, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x10, ZC3XX_R088_EXPTIMELOW}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, + {0xaa, 0x12, 0x0069}, /* i2c */ + {0xaa, 0x04, 0x0020}, + {0xaa, 0x06, 0x0050}, + {0xaa, 0x13, 0x00c3}, + {0xaa, 0x14, 0x0000}, + {0xaa, 0x15, 0x0024}, + {0xaa, 0x19, 0x0003}, + {0xaa, 0x1a, 0x00f6}, + {0xaa, 0x1b, 0x0002}, + {0xaa, 0x20, 0x00c2}, + {0xaa, 0x24, 0x0060}, + {0xaa, 0x25, 0x0040}, + {0xaa, 0x26, 0x0030}, + {0xaa, 0x27, 0x00ea}, + {0xaa, 0x28, 0x00a0}, + {0xaa, 0x21, 0x0000}, + {0xaa, 0x2a, 0x0081}, + {0xaa, 0x2b, 0x0096}, + {0xaa, 0x2d, 0x0084}, + {0xaa, 0x2f, 0x003d}, + {0xaa, 0x30, 0x0024}, + {0xaa, 0x60, 0x0000}, + {0xaa, 0x61, 0x0040}, + {0xaa, 0x68, 0x007c}, + {0xaa, 0x6f, 0x0015}, + {0xaa, 0x75, 0x0088}, + {0xaa, 0x77, 0x00b5}, + {0xaa, 0x01, 0x0060}, + {0xaa, 0x02, 0x0060}, + {0xaa, 0x17, 0x0018}, + {0xaa, 0x18, 0x00ba}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x04, ZC3XX_R1A7_CALCGLOBALMEAN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R116_RGAIN}, + {0xa0, 0x46, ZC3XX_R118_BGAIN}, + {0xa0, 0x04, ZC3XX_R113_RGB03}, + + {0xa1, 0x01, 0x0002}, + {0xa0, 0x4e, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xfe, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf7, ZC3XX_R10D_RGB10}, + {0xa0, 0x4d, ZC3XX_R10E_RGB11}, + {0xa0, 0xfc, ZC3XX_R10F_RGB12}, + {0xa0, 0x00, ZC3XX_R110_RGB20}, + {0xa0, 0xf6, ZC3XX_R111_RGB21}, + {0xa0, 0x4a, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0008}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa1, 0x01, 0x01c8}, + {0xa1, 0x01, 0x01c9}, + {0xa1, 0x01, 0x01ca}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x16, ZC3XX_R120_GAMMA00}, /* gamma ~4 */ + {0xa0, 0x3a, ZC3XX_R121_GAMMA01}, + {0xa0, 0x5b, ZC3XX_R122_GAMMA02}, + {0xa0, 0x7c, ZC3XX_R123_GAMMA03}, + {0xa0, 0x94, ZC3XX_R124_GAMMA04}, + {0xa0, 0xa9, ZC3XX_R125_GAMMA05}, + {0xa0, 0xbb, ZC3XX_R126_GAMMA06}, + {0xa0, 0xca, ZC3XX_R127_GAMMA07}, + {0xa0, 0xd7, ZC3XX_R128_GAMMA08}, + {0xa0, 0xe1, ZC3XX_R129_GAMMA09}, + {0xa0, 0xea, ZC3XX_R12A_GAMMA0A}, + {0xa0, 0xf1, ZC3XX_R12B_GAMMA0B}, + {0xa0, 0xf7, ZC3XX_R12C_GAMMA0C}, + {0xa0, 0xfc, ZC3XX_R12D_GAMMA0D}, + {0xa0, 0xff, ZC3XX_R12E_GAMMA0E}, + {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, + {0xa0, 0x20, ZC3XX_R130_GAMMA10}, + {0xa0, 0x22, ZC3XX_R131_GAMMA11}, + {0xa0, 0x20, ZC3XX_R132_GAMMA12}, + {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, + {0xa0, 0x16, ZC3XX_R134_GAMMA14}, + {0xa0, 0x13, ZC3XX_R135_GAMMA15}, + {0xa0, 0x10, ZC3XX_R136_GAMMA16}, + {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, + {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, + {0xa0, 0x09, ZC3XX_R139_GAMMA19}, + {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, + {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, + {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, + {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, + {0xa0, 0x00, ZC3XX_R13E_GAMMA1E}, + {0xa0, 0x01, ZC3XX_R13F_GAMMA1F}, + {0xa0, 0x4e, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xfe, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf7, ZC3XX_R10D_RGB10}, + {0xa0, 0x4d, ZC3XX_R10E_RGB11}, + {0xa0, 0xfc, ZC3XX_R10F_RGB12}, + {0xa0, 0x00, ZC3XX_R110_RGB20}, + {0xa0, 0xf6, ZC3XX_R111_RGB21}, + {0xa0, 0x4a, ZC3XX_R112_RGB22}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xaa, 0x10, 0x000d}, + {0xaa, 0x76, 0x0002}, + {0xaa, 0x2a, 0x0081}, + {0xaa, 0x2b, 0x0000}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xd8, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x1b, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xaa, 0x13, 0x00c3}, + + {0xa1, 0x01, 0x0180}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; + +static const struct usb_action pas106b_Initial_com[] = { +/* Sream and Sensor specific */ + {0xa1, 0x01, 0x0010}, /* CMOSSensorSelect */ +/* System */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* SystemControl */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* SystemControl */ +/* Picture size */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* ClockSelect */ + {0xa0, 0x03, 0x003a}, + {0xa0, 0x0c, 0x003b}, + {0xa0, 0x04, 0x0038}, + {} +}; + +static const struct usb_action pas106b_InitialScale[] = { /* 176x144 */ +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, +/* Sream and Sensor specific */ + {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, +/* Picture size */ + {0xa0, 0x00, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0xb0, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x00, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0x90, ZC3XX_R006_FRAMEHEIGHTLOW}, +/* System */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, +/* Sream and Sensor specific */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, +/* Sensor Interface */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, +/* Window inside sensor array */ + {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, +/* Init the sensor */ + {0xaa, 0x02, 0x0004}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x09, 0x0005}, + {0xaa, 0x0a, 0x0002}, + {0xaa, 0x0b, 0x0002}, + {0xaa, 0x0c, 0x0005}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x0e, 0x0002}, + {0xaa, 0x14, 0x0081}, +/* Other registers */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, +/* Frame retreiving */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, +/* Gains */ + {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, +/* Unknown */ + {0xa0, 0x00, 0x01ad}, +/* Sharpness */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, +/* Other registers */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, +/* Auto exposure and white balance */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, +/*Dead pixels */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, +/* EEPROM */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, +/* Other registers */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, +/* Auto exposure and white balance */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, +/*Dead pixels */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, +/* EEPROM */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, + + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, +/* Auto correction */ + {0xa0, 0x03, ZC3XX_R181_WINXSTART}, + {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, + {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, + {0xa0, 0x03, ZC3XX_R184_WINYSTART}, + {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, + {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, +/* Auto exposure and white balance */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, +/* sensor on */ + {0xaa, 0x07, 0x00b1}, + {0xaa, 0x05, 0x0003}, + {0xaa, 0x04, 0x0001}, + {0xaa, 0x03, 0x003b}, +/* Gains */ + {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, +/* Auto correction */ + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, +/* Gains */ + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + {} +}; + +static const struct usb_action pas106b_Initial[] = { /* 352x288 */ +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, +/* Sream and Sensor specific */ + {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, +/* Picture size */ + {0xa0, 0x01, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x60, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0x20, ZC3XX_R006_FRAMEHEIGHTLOW}, +/* System */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, +/* Sream and Sensor specific */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, +/* Sensor Interface */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, +/* Window inside sensor array */ + {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, +/* Init the sensor */ + {0xaa, 0x02, 0x0004}, + {0xaa, 0x08, 0x0000}, + {0xaa, 0x09, 0x0005}, + {0xaa, 0x0a, 0x0002}, + {0xaa, 0x0b, 0x0002}, + {0xaa, 0x0c, 0x0005}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x0e, 0x0002}, + {0xaa, 0x14, 0x0081}, +/* Other registers */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, +/* Frame retreiving */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, +/* Gains */ + {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, +/* Unknown */ + {0xa0, 0x00, 0x01ad}, +/* Sharpness */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, +/* Other registers */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, +/* Auto exposure and white balance */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, +/*Dead pixels */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, +/* EEPROM */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, +/* Other registers */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, +/* Auto exposure and white balance */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, +/*Dead pixels */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, +/* EEPROM */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, +/* JPEG control */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, + + {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ + {0xa0, 0xf4, ZC3XX_R10B_RGB01}, + {0xa0, 0xf4, ZC3XX_R10C_RGB02}, + {0xa0, 0xf4, ZC3XX_R10D_RGB10}, + {0xa0, 0x58, ZC3XX_R10E_RGB11}, + {0xa0, 0xf4, ZC3XX_R10F_RGB12}, + {0xa0, 0xf4, ZC3XX_R110_RGB20}, + {0xa0, 0xf4, ZC3XX_R111_RGB21}, + {0xa0, 0x58, ZC3XX_R112_RGB22}, +/* Auto correction */ + {0xa0, 0x03, ZC3XX_R181_WINXSTART}, + {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, + {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, + {0xa0, 0x03, ZC3XX_R184_WINYSTART}, + {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, + {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + +/* Auto exposure and white balance */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, + + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, + + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, +/* sensor on */ + {0xaa, 0x07, 0x00b1}, + {0xaa, 0x05, 0x0003}, + {0xaa, 0x04, 0x0001}, + {0xaa, 0x03, 0x003b}, +/* Gains */ + {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, +/* Auto correction */ + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, +/* Gains */ + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, + + {0xa0, 0x00, 0x0007}, /* AutoCorrectEnable */ + {0xa0, 0xff, ZC3XX_R018_FRAMELOST}, /* Frame adjust */ + {} +}; +static const struct usb_action pas106b_50HZ[] = { + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ + {0xa0, 0x54, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,54,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,87,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,30,cc */ + {0xaa, 0x03, 0x0021}, /* 00,03,21,aa */ + {0xaa, 0x04, 0x000c}, /* 00,04,0c,aa */ + {0xaa, 0x05, 0x0002}, /* 00,05,02,aa */ + {0xaa, 0x07, 0x001c}, /* 00,07,1c,aa */ + {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */ + {} +}; +static const struct usb_action pas106b_60HZ[] = { + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ + {0xa0, 0x2e, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,2e,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x71, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,71,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x30, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,30,cc */ + {0xaa, 0x03, 0x001c}, /* 00,03,1c,aa */ + {0xaa, 0x04, 0x0004}, /* 00,04,04,aa */ + {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */ + {0xaa, 0x07, 0x00c4}, /* 00,07,c4,aa */ + {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */ + {} +}; +static const struct usb_action pas106b_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ + {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xaa, 0x03, 0x0013}, /* 00,03,13,aa */ + {0xaa, 0x04, 0x0000}, /* 00,04,00,aa */ + {0xaa, 0x05, 0x0001}, /* 00,05,01,aa */ + {0xaa, 0x07, 0x0030}, /* 00,07,30,aa */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {} +}; + +/* from lvWIMv.inf 046d:08a2/:08aa 2007/06/03 */ +static const struct usb_action pas202b_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,03,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,03,cc */ + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */ + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xaa, 0x02, 0x0002}, /* 00,02,04,aa --> 02 */ + {0xaa, 0x07, 0x0006}, /* 00,07,06,aa */ + {0xaa, 0x08, 0x0002}, /* 00,08,02,aa */ + {0xaa, 0x09, 0x0006}, /* 00,09,06,aa */ + {0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */ + {0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */ + {0xaa, 0x0c, 0x0006}, + {0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x12, 0x0005}, /* 00,12,05,aa */ + {0xaa, 0x13, 0x0063}, /* 00,13,63,aa */ + {0xaa, 0x15, 0x0070}, /* 00,15,70,aa */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, /* 01,8d,70,cc */ + {} +}; +static const struct usb_action pas202b_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ + {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,08,cc */ + {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,02,cc */ + {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,08,cc */ + {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,02,cc */ + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xaa, 0x02, 0x0002}, /* 00,02,02,aa */ + {0xaa, 0x07, 0x0006}, /* 00,07,06,aa */ + {0xaa, 0x08, 0x0002}, /* 00,08,02,aa */ + {0xaa, 0x09, 0x0006}, /* 00,09,06,aa */ + {0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */ + {0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */ + {0xaa, 0x0c, 0x0006}, + {0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x12, 0x0005}, /* 00,12,05,aa */ + {0xaa, 0x13, 0x0063}, /* 00,13,63,aa */ + {0xaa, 0x15, 0x0070}, /* 00,15,70,aa */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, /* 01,8d,70,cc */ + {0xa0, 0xff, ZC3XX_R097_WINYSTARTHIGH}, + {0xa0, 0xfe, ZC3XX_R098_WINYSTARTLOW}, + {} +}; +static const struct usb_action pas202b_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ + {0xaa, 0x21, 0x001b}, + {0xaa, 0x03, 0x0044}, /* 00,03,44,aa */ + {0xaa, 0x04, 0x0008}, + {0xaa, 0x05, 0x001b}, + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4d,cc */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x44, ZC3XX_R01D_HSYNC_0}, /* 00,1d,44,cc */ + {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */ + {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */ + {0xa0, 0xeb, ZC3XX_R020_HSYNC_3}, /* 00,20,eb,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0004}, + {0xaa, 0x21, 0x003d}, + {0xaa, 0x03, 0x0041}, /* 00,03,41,aa */ + {0xaa, 0x04, 0x0010}, + {0xaa, 0x05, 0x003d}, + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,9b,cc */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, /* 00,1d,41,cc */ + {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */ + {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x03, 0x0045}, /* 00,03,45,aa */ + {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x40, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,40,cc */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x45, ZC3XX_R01D_HSYNC_0}, /* 00,1d,45,cc */ + {0xa0, 0x8e, ZC3XX_R01E_HSYNC_1}, /* 00,1e,8e,cc */ + {0xa0, 0xc1, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c1,cc */ + {0xa0, 0xf5, ZC3XX_R020_HSYNC_3}, /* 00,20,f5,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0004}, + {0xaa, 0x21, 0x0008}, + {0xaa, 0x03, 0x0042}, /* 00,03,42,aa */ + {0xaa, 0x04, 0x0010}, + {0xaa, 0x05, 0x0008}, + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x1c, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x08, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1b, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x42, ZC3XX_R01D_HSYNC_0}, /* 00,1d,42,cc */ + {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */ + {0xa0, 0xaf, ZC3XX_R01F_HSYNC_2}, /* 00,1f,af,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ + {0xaa, 0x21, 0x0006}, + {0xaa, 0x03, 0x0040}, /* 00,03,40,aa */ + {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */ + {0xaa, 0x05, 0x0006}, + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x06, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */ + {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */ + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0004}, + {0xaa, 0x21, 0x000c}, + {0xaa, 0x03, 0x0040}, /* 00,03,40,aa */ + {0xaa, 0x04, 0x0010}, + {0xaa, 0x05, 0x000c}, + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x0c, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,02,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */ + {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */ + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; + +/* mt9v111 (mi0360soc) and pb0330 from vm30x.inf 0ac8:301b 07/02/13 */ +static const struct usb_action mt9v111_1_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xdd, 0x00, 0x0200}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x0001}, + {0xaa, 0x06, 0x0000}, + {0xaa, 0x08, 0x0483}, + {0xaa, 0x01, 0x0004}, + {0xaa, 0x08, 0x0006}, + {0xaa, 0x02, 0x0011}, + {0xaa, 0x03, 0x01e5}, /*jfm: was 01e7*/ + {0xaa, 0x04, 0x0285}, /*jfm: was 0287*/ + {0xaa, 0x07, 0x3002}, + {0xaa, 0x20, 0x5100}, + {0xaa, 0x35, 0x507f}, + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xaa, 0x2b, 0x007f}, + {0xaa, 0x2c, 0x007f}, /*jfm: was 0030*/ + {0xaa, 0x2d, 0x007f}, /*jfm: was 0030*/ + {0xaa, 0x2e, 0x007f}, /*jfm: was 0030*/ + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x09, 0x01ad}, /*jfm: was 00*/ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, + {0xa0, 0x61, ZC3XX_R116_RGAIN}, + {0xa0, 0x65, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action mt9v111_1_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xdd, 0x00, 0x0200}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x0001}, + {0xaa, 0x06, 0x0000}, + {0xaa, 0x08, 0x0483}, + {0xaa, 0x01, 0x0004}, + {0xaa, 0x08, 0x0006}, + {0xaa, 0x02, 0x0011}, + {0xaa, 0x03, 0x01e7}, + {0xaa, 0x04, 0x0287}, + {0xaa, 0x07, 0x3002}, + {0xaa, 0x20, 0x5100}, + {0xaa, 0x35, 0x007f}, /*jfm: was 0050*/ + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xaa, 0x2b, 0x007f}, /*jfm: was 28*/ + {0xaa, 0x2c, 0x007f}, /*jfm: was 30*/ + {0xaa, 0x2d, 0x007f}, /*jfm: was 30*/ + {0xaa, 0x2e, 0x007f}, /*jfm: was 28*/ + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x09, 0x01ad}, /*jfm: was 00*/ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, + {0xa0, 0x61, ZC3XX_R116_RGAIN}, + {0xa0, 0x65, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action mt9v111_1_AE50HZ[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0562}, + {0xbb, 0x01, 0x09aa}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x9b, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_1_AE50HZScale[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0509}, + {0xbb, 0x01, 0x0934}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_1_AE60HZ[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x003d}, + {0xaa, 0x09, 0x016e}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xdd, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3d, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_1_AE60HZScale[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0509}, + {0xbb, 0x01, 0x0983}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x8f, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_1_AENoFliker[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0509}, + {0xbb, 0x01, 0x0960}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_1_AENoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0534}, + {0xbb, 0x02, 0x0960}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x34, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +/* from usbvm303.inf 0ac8:303b 07/03/25 (3 - tas5130c) */ +static const struct usb_action mt9v111_3_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xdd, 0x00, 0x0200}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x0001}, /* select IFP/SOC registers */ + {0xaa, 0x06, 0x0000}, /* operating mode control */ + {0xaa, 0x08, 0x0483}, /* output format control */ + /* H red first, V red or blue first, + * raw Bayer, auto flicker */ + {0xaa, 0x01, 0x0004}, /* select sensor core registers */ + {0xaa, 0x08, 0x0006}, /* row start */ + {0xaa, 0x02, 0x0011}, /* column start */ + {0xaa, 0x03, 0x01e5}, /* window height - 1 */ + {0xaa, 0x04, 0x0285}, /* window width - 1 */ + {0xaa, 0x07, 0x3002}, /* output control */ + {0xaa, 0x20, 0x1100}, /* read mode: bits 8 & 12 (?) */ + {0xaa, 0x35, 0x007f}, /* global gain */ + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xaa, 0x2b, 0x007f}, /* green1 gain */ + {0xaa, 0x2c, 0x007f}, /* blue gain */ + {0xaa, 0x2d, 0x007f}, /* red gain */ + {0xaa, 0x2e, 0x007f}, /* green2 gain */ + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, + {0xa0, 0x61, ZC3XX_R116_RGAIN}, + {0xa0, 0x65, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action mt9v111_3_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR}, + {0xdd, 0x00, 0x0200}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x0001}, + {0xaa, 0x06, 0x0000}, + {0xaa, 0x08, 0x0483}, + {0xaa, 0x01, 0x0004}, + {0xaa, 0x08, 0x0006}, + {0xaa, 0x02, 0x0011}, + {0xaa, 0x03, 0x01e7}, + {0xaa, 0x04, 0x0287}, + {0xaa, 0x07, 0x3002}, + {0xaa, 0x20, 0x1100}, + {0xaa, 0x35, 0x007f}, + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xaa, 0x2b, 0x007f}, + {0xaa, 0x2c, 0x007f}, + {0xaa, 0x2d, 0x007f}, + {0xaa, 0x2e, 0x007f}, + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, + {0xa0, 0x61, ZC3XX_R116_RGAIN}, + {0xa0, 0x65, ZC3XX_R118_BGAIN}, + {} +}; +static const struct usb_action mt9v111_3_AE50HZ[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0009}, /* horizontal blanking */ + {0xaa, 0x09, 0x01ce}, /* shutter width */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_3_AE50HZScale[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0009}, + {0xaa, 0x09, 0x01ce}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_3_AE60HZ[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0009}, + {0xaa, 0x09, 0x0083}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x8f, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_3_AE60HZScale[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0009}, + {0xaa, 0x09, 0x0083}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x8f, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_3_AENoFliker[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0034}, + {0xaa, 0x09, 0x0260}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x34, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; +static const struct usb_action mt9v111_3_AENoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xaa, 0x05, 0x0034}, + {0xaa, 0x09, 0x0260}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x34, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, + {} +}; + +static const struct usb_action pb0330_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xdd, 0x00, 0x0200}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x0006}, + {0xaa, 0x02, 0x0011}, + {0xaa, 0x03, 0x01e5}, /*jfm: was 1e7*/ + {0xaa, 0x04, 0x0285}, /*jfm: was 0287*/ + {0xaa, 0x06, 0x0003}, + {0xaa, 0x07, 0x3002}, + {0xaa, 0x20, 0x1100}, + {0xaa, 0x2f, 0xf7b0}, + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x34, 0x0100}, + {0xaa, 0x35, 0x0060}, + {0xaa, 0x3d, 0x068f}, + {0xaa, 0x40, 0x01e0}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x09, 0x01ad}, /*jfm: was 00 */ + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /*jfm: was 6c*/ + {} +}; +static const struct usb_action pb0330_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00 */ + {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, + {0xdd, 0x00, 0x0200}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xaa, 0x01, 0x0006}, + {0xaa, 0x02, 0x0011}, + {0xaa, 0x03, 0x01e7}, + {0xaa, 0x04, 0x0287}, + {0xaa, 0x06, 0x0003}, + {0xaa, 0x07, 0x3002}, + {0xaa, 0x20, 0x1100}, + {0xaa, 0x2f, 0xf7b0}, + {0xaa, 0x30, 0x0005}, + {0xaa, 0x31, 0x0000}, + {0xaa, 0x34, 0x0100}, + {0xaa, 0x35, 0x0060}, + {0xaa, 0x3d, 0x068f}, + {0xaa, 0x40, 0x01e0}, + {0xaa, 0x58, 0x0078}, + {0xaa, 0x62, 0x0411}, + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x09, 0x01ad}, + {0xa0, 0x15, 0x01ae}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /*jfm: was 6c*/ + {} +}; +static const struct usb_action pb0330_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x055c}, + {0xbb, 0x01, 0x09aa}, + {0xbb, 0x00, 0x1001}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xc4, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x5c, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action pb0330_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0566}, + {0xbb, 0x02, 0x09b2}, + {0xbb, 0x00, 0x1002}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x8c, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x8a, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0xf0, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action pb0330_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0535}, + {0xbb, 0x01, 0x0974}, + {0xbb, 0x00, 0x1001}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xfe, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x3e, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x35, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xd0, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action pb0330_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0535}, + {0xbb, 0x02, 0x096c}, + {0xbb, 0x00, 0x1002}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xc0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x7c, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x1a, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x35, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xd0, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action pb0330_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0509}, + {0xbb, 0x02, 0x0940}, + {0xbb, 0x00, 0x1002}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x09, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, + {} +}; +static const struct usb_action pb0330_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, + {0xbb, 0x00, 0x0535}, + {0xbb, 0x01, 0x0980}, + {0xbb, 0x00, 0x1001}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0x35, ZC3XX_R01D_HSYNC_0}, + {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, + {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, + {} +}; + +/* from oem9.inf */ +static const struct usb_action po2030_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x04, ZC3XX_R002_CLOCKSELECT}, /* 00,02,04,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */ + {0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */ + {0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */ + {0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */ + {0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */ + {0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */ + {0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */ + {0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xaa, 0x09, 0x00ce}, /* 00,09,ce,aa */ + {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */ + {0xaa, 0x0d, 0x0054}, /* 00,0d,54,aa */ + {0xaa, 0x0f, 0x00eb}, /* 00,0f,eb,aa */ + {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */ + {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */ + {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */ + {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */ + {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */ + {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */ + {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */ + {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */ + {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */ + {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */ + {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */ + {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */ + {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */ + {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */ + {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */ + {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */ + {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */ + {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */ + {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */ + {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */ + {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */ + {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */ + {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */ + {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */ + {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */ + {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */ + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */ + {0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */ + {} +}; + +/* from oem9.inf */ +static const struct usb_action po2030_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x04, ZC3XX_R080_HBLANKHIGH}, /* 00,80,04,cc */ + {0xa0, 0x05, ZC3XX_R081_HBLANKLOW}, /* 00,81,05,cc */ + {0xa0, 0x16, ZC3XX_R083_RGAINADDR}, /* 00,83,16,cc */ + {0xa0, 0x18, ZC3XX_R085_BGAINADDR}, /* 00,85,18,cc */ + {0xa0, 0x1a, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,1a,cc */ + {0xa0, 0x1b, ZC3XX_R087_EXPTIMEMID}, /* 00,87,1b,cc */ + {0xa0, 0x1c, ZC3XX_R088_EXPTIMELOW}, /* 00,88,1c,cc */ + {0xa0, 0xee, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,ee,cc */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* 00,08,03,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc */ + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xaa, 0x09, 0x00cc}, /* 00,09,cc,aa */ + {0xaa, 0x0b, 0x0005}, /* 00,0b,05,aa */ + {0xaa, 0x0d, 0x0058}, /* 00,0d,58,aa */ + {0xaa, 0x0f, 0x00ed}, /* 00,0f,ed,aa */ + {0xaa, 0x87, 0x0000}, /* 00,87,00,aa */ + {0xaa, 0x88, 0x0004}, /* 00,88,04,aa */ + {0xaa, 0x89, 0x0000}, /* 00,89,00,aa */ + {0xaa, 0x8a, 0x0005}, /* 00,8a,05,aa */ + {0xaa, 0x13, 0x0003}, /* 00,13,03,aa */ + {0xaa, 0x16, 0x0040}, /* 00,16,40,aa */ + {0xaa, 0x18, 0x0040}, /* 00,18,40,aa */ + {0xaa, 0x1d, 0x0002}, /* 00,1d,02,aa */ + {0xaa, 0x29, 0x00e8}, /* 00,29,e8,aa */ + {0xaa, 0x45, 0x0045}, /* 00,45,45,aa */ + {0xaa, 0x50, 0x00ed}, /* 00,50,ed,aa */ + {0xaa, 0x51, 0x0025}, /* 00,51,25,aa */ + {0xaa, 0x52, 0x0042}, /* 00,52,42,aa */ + {0xaa, 0x53, 0x002f}, /* 00,53,2f,aa */ + {0xaa, 0x79, 0x0025}, /* 00,79,25,aa */ + {0xaa, 0x7b, 0x0000}, /* 00,7b,00,aa */ + {0xaa, 0x7e, 0x0025}, /* 00,7e,25,aa */ + {0xaa, 0x7f, 0x0025}, /* 00,7f,25,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x33, 0x0036}, /* 00,33,36,aa */ + {0xaa, 0x36, 0x0060}, /* 00,36,60,aa */ + {0xaa, 0x37, 0x0008}, /* 00,37,08,aa */ + {0xaa, 0x3b, 0x0031}, /* 00,3b,31,aa */ + {0xaa, 0x44, 0x000f}, /* 00,44,0f,aa */ + {0xaa, 0x58, 0x0002}, /* 00,58,02,aa */ + {0xaa, 0x66, 0x00c0}, /* 00,66,c0,aa */ + {0xaa, 0x67, 0x0044}, /* 00,67,44,aa */ + {0xaa, 0x6b, 0x00a0}, /* 00,6b,a0,aa */ + {0xaa, 0x6c, 0x0054}, /* 00,6c,54,aa */ + {0xaa, 0xd6, 0x0007}, /* 00,d6,07,aa */ + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,f7,cc */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x7a, ZC3XX_R116_RGAIN}, /* 01,16,7a,cc */ + {0xa0, 0x4a, ZC3XX_R118_BGAIN}, /* 01,18,4a,cc */ + {} +}; + +static const struct usb_action po2030_50HZ[] = { + {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ + {0xaa, 0x1a, 0x0001}, /* 00,1a,01,aa */ + {0xaa, 0x1b, 0x000a}, /* 00,1b,0a,aa */ + {0xaa, 0x1c, 0x00b0}, /* 00,1c,b0,aa */ + {0xa0, 0x05, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,05,cc */ + {0xa0, 0x35, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,35,cc */ + {0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x85, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,85,cc */ + {0xa0, 0x58, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,58,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,22,cc */ + {0xa0, 0x88, ZC3XX_R18D_YTARGET}, /* 01,8d,88,cc */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {} +}; + +static const struct usb_action po2030_60HZ[] = { + {0xaa, 0x8d, 0x0008}, /* 00,8d,08,aa */ + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ + {0xaa, 0x1b, 0x00de}, /* 00,1b,de,aa */ + {0xaa, 0x1c, 0x0040}, /* 00,1c,40,aa */ + {0xa0, 0x08, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,08,cc */ + {0xa0, 0xae, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,ae,cc */ + {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x6f, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,6f,cc */ + {0xa0, 0x20, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,20,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc */ + {0xa0, 0x22, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,22,cc */ + {0xa0, 0x88, ZC3XX_R18D_YTARGET}, /* 01,8d,88,cc */ + /* win: 01,8d,80 */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc */ + {} +}; + +static const struct usb_action po2030_NoFliker[] = { + {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ + {0xaa, 0x8d, 0x000d}, /* 00,8d,0d,aa */ + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ + {0xaa, 0x1b, 0x0002}, /* 00,1b,02,aa */ + {0xaa, 0x1c, 0x0078}, /* 00,1c,78,aa */ + {0xaa, 0x46, 0x0000}, /* 00,46,00,aa */ + {0xaa, 0x15, 0x0000}, /* 00,15,00,aa */ + {} +}; + +static const struct usb_action tas5130c_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x50, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + + {0xa0, 0x04, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x04, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, + {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, + {} +}; +static const struct usb_action tas5130c_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, + {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, + {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, + {0xa0, 0x05, ZC3XX_R098_WINYSTARTLOW}, + {0xa0, 0x0f, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x05, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x0f, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, + {0xa0, 0x06, ZC3XX_R08D_COMPABILITYMODE}, + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, + {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, + {0xa0, 0x00, 0x01ad}, + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, + {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, + {} +}; +static const struct usb_action tas5130c_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0063}, /* 00,a4,63,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x63, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,63,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xfe, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xd3, ZC3XX_R01D_HSYNC_0}, /* 00,1d,d3,cc */ + {0xa0, 0xda, ZC3XX_R01E_HSYNC_1}, /* 00,1e,da,cc */ + {0xa0, 0xea, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ea,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ + {0xa0, 0x4c, ZC3XX_R0A0_MAXXLOW}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {} +}; +static const struct usb_action tas5130c_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xd0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xf0, ZC3XX_R01D_HSYNC_0}, /* 00,1d,f0,cc */ + {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1}, /* 00,1e,f4,cc */ + {0xa0, 0xf8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,f8,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ + {0xa0, 0xc0, ZC3XX_R0A0_MAXXLOW}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {} +}; +static const struct usb_action tas5130c_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0036}, /* 00,a4,36,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x36, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,36,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x54, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x3e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3e,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xca, ZC3XX_R01D_HSYNC_0}, /* 00,1d,ca,cc */ + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ + {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ + {0xa0, 0x28, ZC3XX_R0A0_MAXXLOW}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {} +}; +static const struct usb_action tas5130c_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x77, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,77,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x09, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x47, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x7d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,7d,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x08, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xc8, ZC3XX_R01D_HSYNC_0}, /* 00,1d,c8,cc */ + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ + {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x03, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,03,cc */ + {0xa0, 0x20, ZC3XX_R0A0_MAXXLOW}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {} +}; +static const struct usb_action tas5130c_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0040}, /* 00,a4,40,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x40, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,40,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */ + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ + {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */ + {0xa0, 0xf0, ZC3XX_R0A0_MAXXLOW}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {} +}; + +static const struct usb_action tas5130c_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ + {0xaa, 0xa4, 0x0090}, /* 00,a4,90,aa */ + {0xa0, 0x01, ZC3XX_R0A3_EXPOSURETIMEHIGH}, /* 00,a3,01,cc */ + {0xa0, 0x90, ZC3XX_R0A4_EXPOSURETIMELOW}, /* 00,a4,90,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x0a, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0xbc, ZC3XX_R01D_HSYNC_0}, /* 00,1d,bc,cc */ + {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,d0,cc */ + {0xa0, 0xe0, ZC3XX_R01F_HSYNC_2}, /* 00,1f,e0,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x02, ZC3XX_R09F_MAXXHIGH}, /* 00,9f,02,cc */ + {0xa0, 0xf0, ZC3XX_R0A0_MAXXLOW}, + {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, + {} +}; + +static const struct usb_action gc0303_InitialScale[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ + {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc, + * 0<->10 */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc, */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc, */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc, */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc, */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc, */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc, */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc, */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc, */ + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc, + * 6<->8 */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc, + * 6<->8 */ + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ + {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ + {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ + {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ + {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ +/*?? {0xaa, 0x01, 0x0000}, */ + {0xaa, 0x01, 0x0000}, + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ + {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ + {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ + {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ + {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ + {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ + {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ + {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ + {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ + {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ + {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ + {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ + {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ +/*?? {0xa0, 0x00, 0x0039}, + {0xa1, 0x01, 0x0037}, */ + {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ + {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */ + {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ + {0xaa, 0x19, 0x0088}, /* 00,19,86,aa, */ + {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */ + {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc, */ + {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc, */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ + {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ + {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ + {} +}; + +static const struct usb_action gc0303_Initial[] = { + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ + {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ + {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc, */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc, */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc, */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc, */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc, */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc, */ + {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,00,cc, */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc, */ + {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,00,cc, */ + {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e8,cc, + * 8<->6 */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc, + * 8<->6 */ + {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ + {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ + {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ + {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ + {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ + {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ + {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ +/*?? {0xaa, 0x01, 0x0000}, */ + {0xaa, 0x01, 0x0000}, + {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ + {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ + {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ + {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ + {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ + {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ + {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ + {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ + {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ + {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ + {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ + {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ + {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ +/*?? {0xa0, 0x00, 0x0039}, + {0xa1, 0x01, 0x0037}, */ + {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ + {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */ + {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ + {0xaa, 0x19, 0x0088}, /* 00,19,88,aa, */ + {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */ + {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */ + {0xa0, 0x76, ZC3XX_R189_AWBSTATUS}, /* 01,89,76,cc, */ + {0xa0, 0x09, 0x01ad}, /* 01,ad,09,cc, */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc, */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ + {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ + {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ + {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ + {} +}; +static const struct usb_action gc0303_50HZScale[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ + {0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */ + {0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {} +}; + +static const struct usb_action gc0303_50HZ[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0003}, /* 00,83,03,aa */ + {0xaa, 0x84, 0x0054}, /* 00,84,54,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x0d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */ + {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,8e,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {} +}; + +static const struct usb_action gc0303_60HZScale[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ + {0xaa, 0x84, 0x0062}, /* 00,84,62,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ + {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x3b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,3b,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {} +}; + +static const struct usb_action gc0303_60HZ[] = { + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */ + {0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,1,0b,cc, */ + {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,2,10,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,5,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,6,00,cc, */ + {0xa0, 0x76, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,7,76,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,f,15,cc, */ + {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,9,10,cc, */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,a,24,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,0,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,d,58,cc, */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ + {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,d,78,cc */ + {} +}; + +static const struct usb_action gc0303_NoFlikerScale[] = { + {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ + {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,0,00,cc, */ + {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ + {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */ + {} +}; + +static const struct usb_action gc0303_NoFliker[] = { + {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ + {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ + {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ + {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ + {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc, */ + {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc, */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ + {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ + {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ + {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ + {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ + {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ + {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ + {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ + {0xa0, 0x03, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,03,cc */ + {} +}; + +static u8 reg_r_i(struct gspca_dev *gspca_dev, + u16 index) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return 0; + ret = usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0xa1, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x01, /* value */ + index, gspca_dev->usb_buf, 1, + 500); + if (ret < 0) { + err("reg_r_i err %d", ret); + gspca_dev->usb_err = ret; + return 0; + } + return gspca_dev->usb_buf[0]; +} + +static u8 reg_r(struct gspca_dev *gspca_dev, + u16 index) +{ + u8 ret; + + ret = reg_r_i(gspca_dev, index); + PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret); + return ret; +} + +static void reg_w_i(struct gspca_dev *gspca_dev, + u8 value, + u16 index) +{ + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0xa0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, + 500); + if (ret < 0) { + err("reg_w_i err %d", ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w(struct gspca_dev *gspca_dev, + u8 value, + u16 index) +{ + PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value); + reg_w_i(gspca_dev, value, index); +} + +static u16 i2c_read(struct gspca_dev *gspca_dev, + u8 reg) +{ + u8 retbyte; + u16 retval; + + if (gspca_dev->usb_err < 0) + return 0; + reg_w_i(gspca_dev, reg, 0x0092); + reg_w_i(gspca_dev, 0x02, 0x0090); /* <- read command */ + msleep(20); + retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ + if (retbyte != 0x00) + err("i2c_r status error %02x", retbyte); + retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ + retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */ + PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)", + reg, retval, retbyte); + return retval; +} + +static u8 i2c_write(struct gspca_dev *gspca_dev, + u8 reg, + u8 valL, + u8 valH) +{ + u8 retbyte; + + if (gspca_dev->usb_err < 0) + return 0; + reg_w_i(gspca_dev, reg, 0x92); + reg_w_i(gspca_dev, valL, 0x93); + reg_w_i(gspca_dev, valH, 0x94); + reg_w_i(gspca_dev, 0x01, 0x90); /* <- write command */ + msleep(1); + retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ + if (retbyte != 0x00) + err("i2c_w status error %02x", retbyte); + PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)", + reg, valH, valL, retbyte); + return retbyte; +} + +static void usb_exchange(struct gspca_dev *gspca_dev, + const struct usb_action *action) +{ + while (action->req) { + switch (action->req) { + case 0xa0: /* write register */ + reg_w(gspca_dev, action->val, action->idx); + break; + case 0xa1: /* read status */ + reg_r(gspca_dev, action->idx); + break; + case 0xaa: + i2c_write(gspca_dev, + action->val, /* reg */ + action->idx & 0xff, /* valL */ + action->idx >> 8); /* valH */ + break; + case 0xbb: + i2c_write(gspca_dev, + action->idx >> 8, /* reg */ + action->idx & 0xff, /* valL */ + action->val); /* valH */ + break; + default: +/* case 0xdd: * delay */ + msleep(action->idx); + break; + } + action++; + msleep(1); + } +} + +static void setmatrix(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + const u8 *matrix; + static const u8 adcm2700_matrix[9] = +/* {0x66, 0xed, 0xed, 0xed, 0x66, 0xed, 0xed, 0xed, 0x66}; */ +/*ms-win*/ + {0x74, 0xed, 0xed, 0xed, 0x74, 0xed, 0xed, 0xed, 0x74}; + static const u8 gc0305_matrix[9] = + {0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50}; + static const u8 ov7620_matrix[9] = + {0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58}; + static const u8 pas202b_matrix[9] = + {0x4c, 0xf5, 0xff, 0xf9, 0x51, 0xf5, 0xfb, 0xed, 0x5f}; + static const u8 po2030_matrix[9] = + {0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60}; + static const u8 tas5130c_matrix[9] = + {0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68}; + static const u8 gc0303_matrix[9] = + {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b}; + static const u8 *matrix_tb[SENSOR_MAX] = { + [SENSOR_ADCM2700] = adcm2700_matrix, + [SENSOR_CS2102] = ov7620_matrix, + [SENSOR_CS2102K] = NULL, + [SENSOR_GC0303] = gc0303_matrix, + [SENSOR_GC0305] = gc0305_matrix, + [SENSOR_HDCS2020] = NULL, + [SENSOR_HV7131B] = NULL, + [SENSOR_HV7131R] = po2030_matrix, + [SENSOR_ICM105A] = po2030_matrix, + [SENSOR_MC501CB] = NULL, + [SENSOR_MT9V111_1] = gc0305_matrix, + [SENSOR_MT9V111_3] = gc0305_matrix, + [SENSOR_OV7620] = ov7620_matrix, + [SENSOR_OV7630C] = NULL, + [SENSOR_PAS106] = NULL, + [SENSOR_PAS202B] = pas202b_matrix, + [SENSOR_PB0330] = gc0305_matrix, + [SENSOR_PO2030] = po2030_matrix, + [SENSOR_TAS5130C] = tas5130c_matrix, + }; + + matrix = matrix_tb[sd->sensor]; + if (matrix == NULL) + return; /* matrix already loaded */ + for (i = 0; i < ARRAY_SIZE(ov7620_matrix); i++) + reg_w(gspca_dev, matrix[i], 0x010a + i); +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int sharpness; + static const u8 sharpness_tb[][2] = { + {0x02, 0x03}, + {0x04, 0x07}, + {0x08, 0x0f}, + {0x10, 0x1e} + }; + + sharpness = sd->ctrls[SHARPNESS].val; + reg_w(gspca_dev, sharpness_tb[sharpness][0], 0x01c6); + reg_r(gspca_dev, 0x01c8); + reg_r(gspca_dev, 0x01c9); + reg_r(gspca_dev, 0x01ca); + reg_w(gspca_dev, sharpness_tb[sharpness][1], 0x01cb); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + const u8 *Tgamma; + int g, i, brightness, contrast, adj, gp1, gp2; + u8 gr[16]; + static const u8 delta_b[16] = /* delta for brightness */ + {0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d, + 0x1d, 0x1b, 0x1b, 0x1b, 0x19, 0x18, 0x18, 0x18}; + static const u8 delta_c[16] = /* delta for contrast */ + {0x2c, 0x1a, 0x12, 0x0c, 0x0a, 0x06, 0x06, 0x06, + 0x04, 0x06, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02}; + static const u8 gamma_tb[6][16] = { + {0x00, 0x00, 0x03, 0x0d, 0x1b, 0x2e, 0x45, 0x5f, + 0x79, 0x93, 0xab, 0xc1, 0xd4, 0xe5, 0xf3, 0xff}, + {0x01, 0x0c, 0x1f, 0x3a, 0x53, 0x6d, 0x85, 0x9c, + 0xb0, 0xc2, 0xd1, 0xde, 0xe9, 0xf2, 0xf9, 0xff}, + {0x04, 0x16, 0x30, 0x4e, 0x68, 0x81, 0x98, 0xac, + 0xbe, 0xcd, 0xda, 0xe4, 0xed, 0xf5, 0xfb, 0xff}, + {0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff}, + {0x20, 0x4b, 0x6e, 0x8d, 0xa3, 0xb5, 0xc5, 0xd2, + 0xdc, 0xe5, 0xec, 0xf2, 0xf6, 0xfa, 0xfd, 0xff}, + {0x24, 0x44, 0x64, 0x84, 0x9d, 0xb2, 0xc4, 0xd3, + 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff}, + }; + + Tgamma = gamma_tb[sd->ctrls[GAMMA].val - 1]; + + contrast = ((int) sd->ctrls[CONTRAST].val - 128); /* -128 / 127 */ + brightness = ((int) sd->ctrls[BRIGHTNESS].val - 128); /* -128 / 92 */ + adj = 0; + gp1 = gp2 = 0; + for (i = 0; i < 16; i++) { + g = Tgamma[i] + delta_b[i] * brightness / 256 + - delta_c[i] * contrast / 256 - adj / 2; + if (g > 0xff) + g = 0xff; + else if (g < 0) + g = 0; + reg_w(gspca_dev, g, 0x0120 + i); /* gamma */ + if (contrast > 0) + adj--; + else if (contrast < 0) + adj++; + if (i > 1) + gr[i - 1] = (g - gp2) / 2; + else if (i != 0) + gr[0] = gp1 == 0 ? 0 : (g - gp1); + gp2 = gp1; + gp1 = g; + } + gr[15] = (0xff - gp2) / 2; + for (i = 0; i < 16; i++) + reg_w(gspca_dev, gr[i], 0x0130 + i); /* gradient */ +} + +static void getexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9) + | (i2c_read(gspca_dev, 0x26) << 1) + | (i2c_read(gspca_dev, 0x27) >> 7); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + + val = sd->ctrls[EXPOSURE].val; + i2c_write(gspca_dev, 0x25, val >> 9, 0x00); + i2c_write(gspca_dev, 0x26, val >> 1, 0x00); + i2c_write(gspca_dev, 0x27, val << 7, 0x00); +} + +static void setquality(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 frxt; + + switch (sd->sensor) { + case SENSOR_ADCM2700: + case SENSOR_GC0305: + case SENSOR_HV7131B: + case SENSOR_HV7131R: + case SENSOR_OV7620: + case SENSOR_PAS202B: + case SENSOR_PO2030: + return; + } +/*fixme: is it really 0008 0007 0018 for all other sensors? */ + reg_w(gspca_dev, QUANT_VAL, 0x0008); + frxt = 0x30; + reg_w(gspca_dev, frxt, 0x0007); +#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2 + frxt = 0xff; +#elif QUANT_VAL == 3 + frxt = 0xf0; +#elif QUANT_VAL == 4 + frxt = 0xe0; +#else + frxt = 0x20; +#endif + reg_w(gspca_dev, frxt, 0x0018); +} + +/* Matches the sensor's internal frame rate to the lighting frequency. + * Valid frequencies are: + * 50Hz, for European and Asian lighting (default) + * 60Hz, for American lighting + * 0 = No Fliker (for outdoore usage) + */ +static void setlightfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, mode; + const struct usb_action *zc3_freq; + static const struct usb_action *freq_tb[SENSOR_MAX][6] = { + [SENSOR_ADCM2700] = + {adcm2700_NoFliker, adcm2700_NoFliker, + adcm2700_50HZ, adcm2700_50HZ, + adcm2700_60HZ, adcm2700_60HZ}, + [SENSOR_CS2102] = + {cs2102_NoFliker, cs2102_NoFlikerScale, + cs2102_50HZ, cs2102_50HZScale, + cs2102_60HZ, cs2102_60HZScale}, + [SENSOR_CS2102K] = + {cs2102_NoFliker, cs2102_NoFlikerScale, + NULL, NULL, /* currently disabled */ + NULL, NULL}, + [SENSOR_GC0303] = + {gc0303_NoFliker, gc0303_NoFlikerScale, + gc0303_50HZ, gc0303_50HZScale, + gc0303_60HZ, gc0303_60HZScale}, + [SENSOR_GC0305] = + {gc0305_NoFliker, gc0305_NoFliker, + gc0305_50HZ, gc0305_50HZ, + gc0305_60HZ, gc0305_60HZ}, + [SENSOR_HDCS2020] = + {hdcs2020_NoFliker, hdcs2020_NoFliker, + hdcs2020_50HZ, hdcs2020_50HZ, + hdcs2020_60HZ, hdcs2020_60HZ}, + [SENSOR_HV7131B] = + {hv7131b_NoFliker, hv7131b_NoFlikerScale, + hv7131b_50HZ, hv7131b_50HZScale, + hv7131b_60HZ, hv7131b_60HZScale}, + [SENSOR_HV7131R] = + {hv7131r_NoFliker, hv7131r_NoFlikerScale, + hv7131r_50HZ, hv7131r_50HZScale, + hv7131r_60HZ, hv7131r_60HZScale}, + [SENSOR_ICM105A] = + {icm105a_NoFliker, icm105a_NoFlikerScale, + icm105a_50HZ, icm105a_50HZScale, + icm105a_60HZ, icm105a_60HZScale}, + [SENSOR_MC501CB] = + {mc501cb_NoFliker, mc501cb_NoFlikerScale, + mc501cb_50HZ, mc501cb_50HZScale, + mc501cb_60HZ, mc501cb_60HZScale}, + [SENSOR_MT9V111_1] = + {mt9v111_1_AENoFliker, mt9v111_1_AENoFlikerScale, + mt9v111_1_AE50HZ, mt9v111_1_AE50HZScale, + mt9v111_1_AE60HZ, mt9v111_1_AE60HZScale}, + [SENSOR_MT9V111_3] = + {mt9v111_3_AENoFliker, mt9v111_3_AENoFlikerScale, + mt9v111_3_AE50HZ, mt9v111_3_AE50HZScale, + mt9v111_3_AE60HZ, mt9v111_3_AE60HZScale}, + [SENSOR_OV7620] = + {ov7620_NoFliker, ov7620_NoFliker, + ov7620_50HZ, ov7620_50HZ, + ov7620_60HZ, ov7620_60HZ}, + [SENSOR_OV7630C] = + {NULL, NULL, + NULL, NULL, + NULL, NULL}, + [SENSOR_PAS106] = + {pas106b_NoFliker, pas106b_NoFliker, + pas106b_50HZ, pas106b_50HZ, + pas106b_60HZ, pas106b_60HZ}, + [SENSOR_PAS202B] = + {pas202b_NoFliker, pas202b_NoFlikerScale, + pas202b_50HZ, pas202b_50HZScale, + pas202b_60HZ, pas202b_60HZScale}, + [SENSOR_PB0330] = + {pb0330_NoFliker, pb0330_NoFlikerScale, + pb0330_50HZ, pb0330_50HZScale, + pb0330_60HZ, pb0330_60HZScale}, + [SENSOR_PO2030] = + {po2030_NoFliker, po2030_NoFliker, + po2030_50HZ, po2030_50HZ, + po2030_60HZ, po2030_60HZ}, + [SENSOR_TAS5130C] = + {tas5130c_NoFliker, tas5130c_NoFlikerScale, + tas5130c_50HZ, tas5130c_50HZScale, + tas5130c_60HZ, tas5130c_60HZScale}, + }; + + i = sd->ctrls[LIGHTFREQ].val * 2; + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + if (mode) + i++; /* 320x240 */ + zc3_freq = freq_tb[sd->sensor][i]; + if (zc3_freq == NULL) + return; + usb_exchange(gspca_dev, zc3_freq); + switch (sd->sensor) { + case SENSOR_GC0305: + if (mode /* if 320x240 */ + && sd->ctrls[LIGHTFREQ].val == 1) /* and 50Hz */ + reg_w(gspca_dev, 0x85, 0x018d); + /* win: 0x80, 0x018d */ + break; + case SENSOR_OV7620: + if (!mode) { /* if 640x480 */ + if (sd->ctrls[LIGHTFREQ].val != 0) /* and filter */ + reg_w(gspca_dev, 0x40, 0x0002); + else + reg_w(gspca_dev, 0x44, 0x0002); + } + break; + case SENSOR_PAS202B: + reg_w(gspca_dev, 0x00, 0x01a7); + break; + } +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 autoval; + + if (sd->ctrls[AUTOGAIN].val) + autoval = 0x42; + else + autoval = 0x02; + reg_w(gspca_dev, autoval, 0x0180); +} + +static void send_unknown(struct gspca_dev *gspca_dev, int sensor) +{ + reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */ + switch (sensor) { + case SENSOR_PAS106: + reg_w(gspca_dev, 0x03, 0x003a); + reg_w(gspca_dev, 0x0c, 0x003b); + reg_w(gspca_dev, 0x08, 0x0038); + break; + case SENSOR_ADCM2700: + case SENSOR_GC0305: + case SENSOR_OV7620: + case SENSOR_MT9V111_1: + case SENSOR_MT9V111_3: + case SENSOR_PB0330: + case SENSOR_PO2030: + reg_w(gspca_dev, 0x0d, 0x003a); + reg_w(gspca_dev, 0x02, 0x003b); + reg_w(gspca_dev, 0x00, 0x0038); + break; + case SENSOR_HV7131R: + case SENSOR_PAS202B: + reg_w(gspca_dev, 0x03, 0x003b); + reg_w(gspca_dev, 0x0c, 0x003a); + reg_w(gspca_dev, 0x0b, 0x0039); + if (sensor == SENSOR_PAS202B) + reg_w(gspca_dev, 0x0b, 0x0038); + break; + } +} + +/* start probe 2 wires */ +static void start_2wr_probe(struct gspca_dev *gspca_dev, int sensor) +{ + reg_w(gspca_dev, 0x01, 0x0000); + reg_w(gspca_dev, sensor, 0x0010); + reg_w(gspca_dev, 0x01, 0x0001); + reg_w(gspca_dev, 0x03, 0x0012); + reg_w(gspca_dev, 0x01, 0x0012); +/* msleep(2); */ +} + +static int sif_probe(struct gspca_dev *gspca_dev) +{ + u16 checkword; + + start_2wr_probe(gspca_dev, 0x0f); /* PAS106 */ + reg_w(gspca_dev, 0x08, 0x008d); + msleep(150); + checkword = ((i2c_read(gspca_dev, 0x00) & 0x0f) << 4) + | ((i2c_read(gspca_dev, 0x01) & 0xf0) >> 4); + PDEBUG(D_PROBE, "probe sif 0x%04x", checkword); + if (checkword == 0x0007) { + send_unknown(gspca_dev, SENSOR_PAS106); + return 0x0f; /* PAS106 */ + } + return -1; +} + +static int vga_2wr_probe(struct gspca_dev *gspca_dev) +{ + u16 retword; + + start_2wr_probe(gspca_dev, 0x00); /* HV7131B */ + i2c_write(gspca_dev, 0x01, 0xaa, 0x00); + retword = i2c_read(gspca_dev, 0x01); + if (retword != 0) + return 0x00; /* HV7131B */ + + start_2wr_probe(gspca_dev, 0x04); /* CS2102 */ + i2c_write(gspca_dev, 0x01, 0xaa, 0x00); + retword = i2c_read(gspca_dev, 0x01); + if (retword != 0) + return 0x04; /* CS2102 */ + + start_2wr_probe(gspca_dev, 0x06); /* OmniVision */ + reg_w(gspca_dev, 0x08, 0x008d); + i2c_write(gspca_dev, 0x11, 0xaa, 0x00); + retword = i2c_read(gspca_dev, 0x11); + if (retword != 0) { + /* (should have returned 0xaa) --> Omnivision? */ + /* reg_r 0x10 -> 0x06 --> */ + goto ov_check; + } + + start_2wr_probe(gspca_dev, 0x08); /* HDCS2020 */ + i2c_write(gspca_dev, 0x1c, 0x00, 0x00); + i2c_write(gspca_dev, 0x15, 0xaa, 0x00); + retword = i2c_read(gspca_dev, 0x15); + if (retword != 0) + return 0x08; /* HDCS2020 */ + + start_2wr_probe(gspca_dev, 0x0a); /* PB0330 */ + i2c_write(gspca_dev, 0x07, 0xaa, 0xaa); + retword = i2c_read(gspca_dev, 0x07); + if (retword != 0) + return 0x0a; /* PB0330 */ + retword = i2c_read(gspca_dev, 0x03); + if (retword != 0) + return 0x0a; /* PB0330 ?? */ + retword = i2c_read(gspca_dev, 0x04); + if (retword != 0) + return 0x0a; /* PB0330 ?? */ + + start_2wr_probe(gspca_dev, 0x0c); /* ICM105A */ + i2c_write(gspca_dev, 0x01, 0x11, 0x00); + retword = i2c_read(gspca_dev, 0x01); + if (retword != 0) + return 0x0c; /* ICM105A */ + + start_2wr_probe(gspca_dev, 0x0e); /* PAS202BCB */ + reg_w(gspca_dev, 0x08, 0x008d); + i2c_write(gspca_dev, 0x03, 0xaa, 0x00); + msleep(50); + retword = i2c_read(gspca_dev, 0x03); + if (retword != 0) { + send_unknown(gspca_dev, SENSOR_PAS202B); + return 0x0e; /* PAS202BCB */ + } + + start_2wr_probe(gspca_dev, 0x02); /* TAS5130C */ + i2c_write(gspca_dev, 0x01, 0xaa, 0x00); + retword = i2c_read(gspca_dev, 0x01); + if (retword != 0) + return 0x02; /* TAS5130C */ +ov_check: + reg_r(gspca_dev, 0x0010); /* ?? */ + reg_r(gspca_dev, 0x0010); + + reg_w(gspca_dev, 0x01, 0x0000); + reg_w(gspca_dev, 0x01, 0x0001); + reg_w(gspca_dev, 0x06, 0x0010); /* OmniVision */ + reg_w(gspca_dev, 0xa1, 0x008b); + reg_w(gspca_dev, 0x08, 0x008d); + msleep(500); + reg_w(gspca_dev, 0x01, 0x0012); + i2c_write(gspca_dev, 0x12, 0x80, 0x00); /* sensor reset */ + retword = i2c_read(gspca_dev, 0x0a) << 8; + retword |= i2c_read(gspca_dev, 0x0b); + PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", retword); + switch (retword) { + case 0x7631: /* OV7630C */ + reg_w(gspca_dev, 0x06, 0x0010); + break; + case 0x7620: /* OV7620 */ + case 0x7648: /* OV7648 */ + break; + default: + return -1; /* not OmniVision */ + } + return retword; +} + +struct sensor_by_chipset_revision { + u16 revision; + u8 internal_sensor_id; +}; +static const struct sensor_by_chipset_revision chipset_revision_sensor[] = { + {0xc000, 0x12}, /* TAS5130C */ + {0xc001, 0x13}, /* MT9V111 */ + {0xe001, 0x13}, + {0x8001, 0x13}, + {0x8000, 0x14}, /* CS2102K */ + {0x8400, 0x15}, /* MT9V111 */ + {0xe400, 0x15}, +}; + +static int vga_3wr_probe(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + u16 retword; + +/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/ + reg_w(gspca_dev, 0x02, 0x0010); + reg_r(gspca_dev, 0x0010); + reg_w(gspca_dev, 0x01, 0x0000); + reg_w(gspca_dev, 0x00, 0x0010); + reg_w(gspca_dev, 0x01, 0x0001); + reg_w(gspca_dev, 0x91, 0x008b); + reg_w(gspca_dev, 0x03, 0x0012); + reg_w(gspca_dev, 0x01, 0x0012); + reg_w(gspca_dev, 0x05, 0x0012); + retword = i2c_read(gspca_dev, 0x14); + if (retword != 0) + return 0x11; /* HV7131R */ + retword = i2c_read(gspca_dev, 0x15); + if (retword != 0) + return 0x11; /* HV7131R */ + retword = i2c_read(gspca_dev, 0x16); + if (retword != 0) + return 0x11; /* HV7131R */ + + reg_w(gspca_dev, 0x02, 0x0010); + retword = reg_r(gspca_dev, 0x000b) << 8; + retword |= reg_r(gspca_dev, 0x000a); + PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", retword); + reg_r(gspca_dev, 0x0010); + if ((retword & 0xff00) == 0x6400) + return 0x02; /* TAS5130C */ + for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) { + if (chipset_revision_sensor[i].revision == retword) { + sd->chip_revision = retword; + send_unknown(gspca_dev, SENSOR_PB0330); + return chipset_revision_sensor[i].internal_sensor_id; + } + } + + reg_w(gspca_dev, 0x01, 0x0000); /* check PB0330 */ + reg_w(gspca_dev, 0x01, 0x0001); + reg_w(gspca_dev, 0xdd, 0x008b); + reg_w(gspca_dev, 0x0a, 0x0010); + reg_w(gspca_dev, 0x03, 0x0012); + reg_w(gspca_dev, 0x01, 0x0012); + retword = i2c_read(gspca_dev, 0x00); + if (retword != 0) { + PDEBUG(D_PROBE, "probe 3wr vga type 0a"); + return 0x0a; /* PB0330 */ + } + + /* probe gc0303 / gc0305 */ + reg_w(gspca_dev, 0x01, 0x0000); + reg_w(gspca_dev, 0x01, 0x0001); + reg_w(gspca_dev, 0x98, 0x008b); + reg_w(gspca_dev, 0x01, 0x0010); + reg_w(gspca_dev, 0x03, 0x0012); + msleep(2); + reg_w(gspca_dev, 0x01, 0x0012); + retword = i2c_read(gspca_dev, 0x00); + if (retword != 0) { + PDEBUG(D_PROBE, "probe 3wr vga type %02x", retword); + if (retword == 0x0011) /* gc0303 */ + return 0x0303; + if (retword == 0x0029) /* gc0305 */ + send_unknown(gspca_dev, SENSOR_GC0305); + return retword; + } + + reg_w(gspca_dev, 0x01, 0x0000); /* check OmniVision */ + reg_w(gspca_dev, 0x01, 0x0001); + reg_w(gspca_dev, 0xa1, 0x008b); + reg_w(gspca_dev, 0x08, 0x008d); + reg_w(gspca_dev, 0x06, 0x0010); + reg_w(gspca_dev, 0x01, 0x0012); + reg_w(gspca_dev, 0x05, 0x0012); + if (i2c_read(gspca_dev, 0x1c) == 0x007f /* OV7610 - manufacturer ID */ + && i2c_read(gspca_dev, 0x1d) == 0x00a2) { + send_unknown(gspca_dev, SENSOR_OV7620); + return 0x06; /* OmniVision confirm ? */ + } + + reg_w(gspca_dev, 0x01, 0x0000); + reg_w(gspca_dev, 0x00, 0x0002); + reg_w(gspca_dev, 0x01, 0x0010); + reg_w(gspca_dev, 0x01, 0x0001); + reg_w(gspca_dev, 0xee, 0x008b); + reg_w(gspca_dev, 0x03, 0x0012); + reg_w(gspca_dev, 0x01, 0x0012); + reg_w(gspca_dev, 0x05, 0x0012); + retword = i2c_read(gspca_dev, 0x00) << 8; /* ID 0 */ + retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */ + PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword); + if (retword == 0x2030) { +#ifdef GSPCA_DEBUG + u8 retbyte; + + retbyte = i2c_read(gspca_dev, 0x02); /* revision number */ + PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte); +#endif + send_unknown(gspca_dev, SENSOR_PO2030); + return retword; + } + + reg_w(gspca_dev, 0x01, 0x0000); + reg_w(gspca_dev, 0x0a, 0x0010); + reg_w(gspca_dev, 0xd3, 0x008b); + reg_w(gspca_dev, 0x01, 0x0001); + reg_w(gspca_dev, 0x03, 0x0012); + reg_w(gspca_dev, 0x01, 0x0012); + reg_w(gspca_dev, 0x05, 0x0012); + reg_w(gspca_dev, 0xd3, 0x008b); + retword = i2c_read(gspca_dev, 0x01); + if (retword != 0) { + PDEBUG(D_PROBE, "probe 3wr vga type 0a ? ret: %04x", retword); + return 0x16; /* adcm2700 (6100/6200) */ + } + return -1; +} + +static int zcxx_probeSensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int sensor; + + switch (sd->sensor) { + case SENSOR_MC501CB: + return -1; /* don't probe */ + case SENSOR_GC0303: + /* may probe but with no write in reg 0x0010 */ + return -1; /* don't probe */ + case SENSOR_PAS106: + sensor = sif_probe(gspca_dev); + if (sensor >= 0) + return sensor; + break; + } + sensor = vga_2wr_probe(gspca_dev); + if (sensor >= 0) + return sensor; + return vga_3wr_probe(gspca_dev); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (id->idProduct == 0x301b) + sd->bridge = BRIDGE_ZC301; + else + sd->bridge = BRIDGE_ZC303; + + /* define some sensors from the vendor/product */ + sd->sensor = id->driver_info; + + gspca_dev->cam.ctrls = sd->ctrls; + sd->quality = QUALITY_DEF; + + /* if USB 1.1, let some bandwidth for the audio device */ + if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) + gspca_dev->nbalt--; + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + int sensor; + static const u8 gamma[SENSOR_MAX] = { + [SENSOR_ADCM2700] = 4, + [SENSOR_CS2102] = 4, + [SENSOR_CS2102K] = 5, + [SENSOR_GC0303] = 3, + [SENSOR_GC0305] = 4, + [SENSOR_HDCS2020] = 4, + [SENSOR_HV7131B] = 4, + [SENSOR_HV7131R] = 4, + [SENSOR_ICM105A] = 4, + [SENSOR_MC501CB] = 4, + [SENSOR_MT9V111_1] = 4, + [SENSOR_MT9V111_3] = 4, + [SENSOR_OV7620] = 3, + [SENSOR_OV7630C] = 4, + [SENSOR_PAS106] = 4, + [SENSOR_PAS202B] = 4, + [SENSOR_PB0330] = 4, + [SENSOR_PO2030] = 4, + [SENSOR_TAS5130C] = 3, + }; + static const u8 mode_tb[SENSOR_MAX] = { + [SENSOR_ADCM2700] = 2, + [SENSOR_CS2102] = 1, + [SENSOR_CS2102K] = 1, + [SENSOR_GC0303] = 1, + [SENSOR_GC0305] = 1, + [SENSOR_HDCS2020] = 1, + [SENSOR_HV7131B] = 1, + [SENSOR_HV7131R] = 1, + [SENSOR_ICM105A] = 1, + [SENSOR_MC501CB] = 2, + [SENSOR_MT9V111_1] = 1, + [SENSOR_MT9V111_3] = 1, + [SENSOR_OV7620] = 2, + [SENSOR_OV7630C] = 1, + [SENSOR_PAS106] = 0, + [SENSOR_PAS202B] = 1, + [SENSOR_PB0330] = 1, + [SENSOR_PO2030] = 1, + [SENSOR_TAS5130C] = 1, + }; + + sensor = zcxx_probeSensor(gspca_dev); + if (sensor >= 0) + PDEBUG(D_PROBE, "probe sensor -> %04x", sensor); + if ((unsigned) force_sensor < SENSOR_MAX) { + sd->sensor = force_sensor; + PDEBUG(D_PROBE, "sensor forced to %d", force_sensor); + } else { + switch (sensor) { + case -1: + switch (sd->sensor) { + case SENSOR_MC501CB: + PDEBUG(D_PROBE, "Sensor MC501CB"); + break; + case SENSOR_GC0303: + PDEBUG(D_PROBE, "Sensor GC0303"); + break; + default: + warn("Unknown sensor - set to TAS5130C"); + sd->sensor = SENSOR_TAS5130C; + } + break; + case 0: + /* check the sensor type */ + sensor = i2c_read(gspca_dev, 0x00); + PDEBUG(D_PROBE, "Sensor hv7131 type %d", sensor); + switch (sensor) { + case 0: /* hv7131b */ + case 1: /* hv7131e */ + PDEBUG(D_PROBE, "Find Sensor HV7131B"); + sd->sensor = SENSOR_HV7131B; + break; + default: +/* case 2: * hv7131r */ + PDEBUG(D_PROBE, "Find Sensor HV7131R"); + sd->sensor = SENSOR_HV7131R; + break; + } + break; + case 0x02: + PDEBUG(D_PROBE, "Sensor TAS5130C"); + sd->sensor = SENSOR_TAS5130C; + break; + case 0x04: + PDEBUG(D_PROBE, "Find Sensor CS2102"); + sd->sensor = SENSOR_CS2102; + break; + case 0x08: + PDEBUG(D_PROBE, "Find Sensor HDCS2020"); + sd->sensor = SENSOR_HDCS2020; + break; + case 0x0a: + PDEBUG(D_PROBE, + "Find Sensor PB0330. Chip revision %x", + sd->chip_revision); + sd->sensor = SENSOR_PB0330; + break; + case 0x0c: + PDEBUG(D_PROBE, "Find Sensor ICM105A"); + sd->sensor = SENSOR_ICM105A; + break; + case 0x0e: + PDEBUG(D_PROBE, "Find Sensor PAS202B"); + sd->sensor = SENSOR_PAS202B; +/* sd->sharpness = 1; */ + break; + case 0x0f: + PDEBUG(D_PROBE, "Find Sensor PAS106"); + sd->sensor = SENSOR_PAS106; + break; + case 0x10: + case 0x12: + PDEBUG(D_PROBE, "Find Sensor TAS5130C"); + sd->sensor = SENSOR_TAS5130C; + break; + case 0x11: + PDEBUG(D_PROBE, "Find Sensor HV7131R"); + sd->sensor = SENSOR_HV7131R; + break; + case 0x13: + case 0x15: + PDEBUG(D_PROBE, + "Sensor MT9V111. Chip revision %04x", + sd->chip_revision); + sd->sensor = sd->bridge == BRIDGE_ZC301 + ? SENSOR_MT9V111_1 + : SENSOR_MT9V111_3; + break; + case 0x14: + PDEBUG(D_PROBE, + "Find Sensor CS2102K?. Chip revision %x", + sd->chip_revision); + sd->sensor = SENSOR_CS2102K; + break; + case 0x16: + PDEBUG(D_PROBE, "Find Sensor ADCM2700"); + sd->sensor = SENSOR_ADCM2700; + break; + case 0x29: + PDEBUG(D_PROBE, "Find Sensor GC0305"); + sd->sensor = SENSOR_GC0305; + break; + case 0x0303: + PDEBUG(D_PROBE, "Sensor GC0303"); + sd->sensor = SENSOR_GC0303; + break; + case 0x2030: + PDEBUG(D_PROBE, "Find Sensor PO2030"); + sd->sensor = SENSOR_PO2030; + sd->ctrls[SHARPNESS].def = 0; /* from win traces */ + break; + case 0x7620: + PDEBUG(D_PROBE, "Find Sensor OV7620"); + sd->sensor = SENSOR_OV7620; + break; + case 0x7631: + PDEBUG(D_PROBE, "Find Sensor OV7630C"); + sd->sensor = SENSOR_OV7630C; + break; + case 0x7648: + PDEBUG(D_PROBE, "Find Sensor OV7648"); + sd->sensor = SENSOR_OV7620; /* same sensor (?) */ + break; + default: + err("Unknown sensor %04x", sensor); + return -EINVAL; + } + } + if (sensor < 0x20) { + if (sensor == -1 || sensor == 0x10 || sensor == 0x12) + reg_w(gspca_dev, 0x02, 0x0010); + reg_r(gspca_dev, 0x0010); + } + + cam = &gspca_dev->cam; + switch (mode_tb[sd->sensor]) { + case 0: + cam->cam_mode = sif_mode; + cam->nmodes = ARRAY_SIZE(sif_mode); + break; + case 1: + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + break; + default: +/* case 2: */ + cam->cam_mode = broken_vga_mode; + cam->nmodes = ARRAY_SIZE(broken_vga_mode); + break; + } + + sd->ctrls[GAMMA].def = gamma[sd->sensor]; + + switch (sd->sensor) { + case SENSOR_HV7131R: + break; + case SENSOR_OV7630C: + gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE); + break; + default: + gspca_dev->ctrl_dis = (1 << EXPOSURE); + break; + } +#if AUTOGAIN_DEF + if (sd->ctrls[AUTOGAIN].val) + gspca_dev->ctrl_inac = (1 << EXPOSURE); +#endif + + /* switch off the led */ + reg_w(gspca_dev, 0x01, 0x0000); + return gspca_dev->usb_err; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int mode; + static const struct usb_action *init_tb[SENSOR_MAX][2] = { + [SENSOR_ADCM2700] = + {adcm2700_Initial, adcm2700_InitialScale}, + [SENSOR_CS2102] = + {cs2102_Initial, cs2102_InitialScale}, + [SENSOR_CS2102K] = + {cs2102K_Initial, cs2102K_InitialScale}, + [SENSOR_GC0303] = + {gc0303_Initial, gc0303_InitialScale}, + [SENSOR_GC0305] = + {gc0305_Initial, gc0305_InitialScale}, + [SENSOR_HDCS2020] = + {hdcs2020_Initial, hdcs2020_InitialScale}, + [SENSOR_HV7131B] = + {hv7131b_Initial, hv7131b_InitialScale}, + [SENSOR_HV7131R] = + {hv7131r_Initial, hv7131r_InitialScale}, + [SENSOR_ICM105A] = + {icm105a_Initial, icm105a_InitialScale}, + [SENSOR_MC501CB] = + {mc501cb_Initial, mc501cb_InitialScale}, + [SENSOR_MT9V111_1] = + {mt9v111_1_Initial, mt9v111_1_InitialScale}, + [SENSOR_MT9V111_3] = + {mt9v111_3_Initial, mt9v111_3_InitialScale}, + [SENSOR_OV7620] = + {ov7620_Initial, ov7620_InitialScale}, + [SENSOR_OV7630C] = + {ov7630c_Initial, ov7630c_InitialScale}, + [SENSOR_PAS106] = + {pas106b_Initial, pas106b_InitialScale}, + [SENSOR_PAS202B] = + {pas202b_Initial, pas202b_InitialScale}, + [SENSOR_PB0330] = + {pb0330_Initial, pb0330_InitialScale}, + [SENSOR_PO2030] = + {po2030_Initial, po2030_InitialScale}, + [SENSOR_TAS5130C] = + {tas5130c_Initial, tas5130c_InitialScale}, + }; + + /* create the JPEG header */ + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x21); /* JPEG 422 */ + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + switch (sd->sensor) { + case SENSOR_HV7131R: + zcxx_probeSensor(gspca_dev); + break; + case SENSOR_PAS106: + usb_exchange(gspca_dev, pas106b_Initial_com); + break; + } + usb_exchange(gspca_dev, init_tb[sd->sensor][mode]); + + switch (sd->sensor) { + case SENSOR_ADCM2700: + case SENSOR_GC0305: + case SENSOR_OV7620: + case SENSOR_PO2030: + case SENSOR_TAS5130C: + case SENSOR_GC0303: +/* msleep(100); * ?? */ + reg_r(gspca_dev, 0x0002); /* --> 0x40 */ + reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */ + reg_w(gspca_dev, 0x15, 0x01ae); + if (sd->sensor == SENSOR_TAS5130C) + break; + reg_w(gspca_dev, 0x0d, 0x003a); + reg_w(gspca_dev, 0x02, 0x003b); + reg_w(gspca_dev, 0x00, 0x0038); + break; + case SENSOR_HV7131R: + case SENSOR_PAS202B: + reg_w(gspca_dev, 0x03, 0x003b); + reg_w(gspca_dev, 0x0c, 0x003a); + reg_w(gspca_dev, 0x0b, 0x0039); + if (sd->sensor == SENSOR_HV7131R) + reg_w(gspca_dev, 0x50, ZC3XX_R11D_GLOBALGAIN); + break; + } + + setmatrix(gspca_dev); + switch (sd->sensor) { + case SENSOR_ADCM2700: + case SENSOR_OV7620: + reg_r(gspca_dev, 0x0008); + reg_w(gspca_dev, 0x00, 0x0008); + break; + case SENSOR_PAS202B: + case SENSOR_GC0305: + case SENSOR_HV7131R: + case SENSOR_TAS5130C: + reg_r(gspca_dev, 0x0008); + /* fall thru */ + case SENSOR_PO2030: + reg_w(gspca_dev, 0x03, 0x0008); + break; + } + setsharpness(gspca_dev); + + /* set the gamma tables when not set */ + switch (sd->sensor) { + case SENSOR_CS2102K: /* gamma set in xxx_Initial */ + case SENSOR_HDCS2020: + case SENSOR_OV7630C: + break; + default: + setcontrast(gspca_dev); + break; + } + setmatrix(gspca_dev); /* one more time? */ + switch (sd->sensor) { + case SENSOR_OV7620: + case SENSOR_PAS202B: + reg_r(gspca_dev, 0x0180); /* from win */ + reg_w(gspca_dev, 0x00, 0x0180); + break; + default: + setquality(gspca_dev); + break; + } + setlightfreq(gspca_dev); + + switch (sd->sensor) { + case SENSOR_ADCM2700: + reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */ + reg_w(gspca_dev, 0x15, 0x01ae); + reg_w(gspca_dev, 0x02, 0x0180); + /* ms-win + */ + reg_w(gspca_dev, 0x40, 0x0117); + break; + case SENSOR_HV7131R: + if (!sd->ctrls[AUTOGAIN].val) + setexposure(gspca_dev); + reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN); + break; + case SENSOR_GC0305: + case SENSOR_TAS5130C: + reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */ + reg_w(gspca_dev, 0x15, 0x01ae); + /* fall thru */ + case SENSOR_PAS202B: + case SENSOR_PO2030: +/* reg_w(gspca_dev, 0x40, ZC3XX_R117_GGAIN); in win traces */ + reg_r(gspca_dev, 0x0180); + break; + case SENSOR_OV7620: + reg_w(gspca_dev, 0x09, 0x01ad); + reg_w(gspca_dev, 0x15, 0x01ae); + i2c_read(gspca_dev, 0x13); /*fixme: returns 0xa3 */ + i2c_write(gspca_dev, 0x13, 0xa3, 0x00); + /*fixme: returned value to send? */ + reg_w(gspca_dev, 0x40, 0x0117); + reg_r(gspca_dev, 0x0180); + break; + } + + setautogain(gspca_dev); + switch (sd->sensor) { + case SENSOR_PO2030: + msleep(50); + reg_w(gspca_dev, 0x00, 0x0007); /* (from win traces) */ + reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING); + break; + } + return gspca_dev->usb_err; +} + +/* called on streamoff with alt 0 and on disconnect */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!gspca_dev->present) + return; + send_unknown(gspca_dev, sd->sensor); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, + int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* check the JPEG end of frame */ + if (len >= 3 + && data[len - 3] == 0xff && data[len - 2] == 0xd9) { +/*fixme: what does the last byte mean?*/ + gspca_frame_add(gspca_dev, LAST_PACKET, + data, len - 1); + return; + } + + /* check the JPEG start of a frame */ + if (data[0] == 0xff && data[1] == 0xd8) { + /* put the JPEG header in the new frame */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + + /* remove the webcam's header: + * ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp + * - 'ss ss' is the frame sequence number (BE) + * - 'ww ww' and 'hh hh' are the window dimensions (BE) + * - 'pp pp' is the packet sequence number (BE) + */ + data += 18; + len -= 18; + } + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[AUTOGAIN].val = val; + if (val) { + gspca_dev->ctrl_inac |= (1 << EXPOSURE); + } else { + gspca_dev->ctrl_inac &= ~(1 << EXPOSURE); + if (gspca_dev->streaming) + getexposure(gspca_dev); + } + if (gspca_dev->streaming) + setautogain(gspca_dev); + return gspca_dev->usb_err; +} + +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "NoFliker"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (jcomp->quality < QUALITY_MIN) + sd->quality = QUALITY_MIN; + else if (jcomp->quality > QUALITY_MAX) + sd->quality = QUALITY_MAX; + else + sd->quality = jcomp->quality; + if (gspca_dev->streaming) + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + return gspca_dev->usb_err; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) +static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* interrupt packet data */ + int len) /* interrput packet length */ +{ + if (len == 8 && data[4] == 1) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); + input_sync(gspca_dev->input_dev); + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + } + + return 0; +} +#endif + +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .int_pkt_scan = sd_int_pkt_scan, +#endif +}; + +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x041e, 0x041e)}, + {USB_DEVICE(0x041e, 0x4017)}, + {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x041e, 0x401e)}, + {USB_DEVICE(0x041e, 0x401f)}, + {USB_DEVICE(0x041e, 0x4022)}, + {USB_DEVICE(0x041e, 0x4029)}, + {USB_DEVICE(0x041e, 0x4034), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x041e, 0x4036)}, + {USB_DEVICE(0x041e, 0x403a)}, + {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_GC0303}, + {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_GC0303}, + {USB_DEVICE(0x0458, 0x7007)}, + {USB_DEVICE(0x0458, 0x700c)}, + {USB_DEVICE(0x0458, 0x700f)}, + {USB_DEVICE(0x0461, 0x0a00)}, + {USB_DEVICE(0x046d, 0x089d), .driver_info = SENSOR_MC501CB}, + {USB_DEVICE(0x046d, 0x08a0)}, + {USB_DEVICE(0x046d, 0x08a1)}, + {USB_DEVICE(0x046d, 0x08a2)}, + {USB_DEVICE(0x046d, 0x08a3)}, + {USB_DEVICE(0x046d, 0x08a6)}, + {USB_DEVICE(0x046d, 0x08a7)}, + {USB_DEVICE(0x046d, 0x08a9)}, + {USB_DEVICE(0x046d, 0x08aa)}, + {USB_DEVICE(0x046d, 0x08ac)}, + {USB_DEVICE(0x046d, 0x08ad)}, + {USB_DEVICE(0x046d, 0x08ae)}, + {USB_DEVICE(0x046d, 0x08af)}, + {USB_DEVICE(0x046d, 0x08b9)}, + {USB_DEVICE(0x046d, 0x08d7)}, + {USB_DEVICE(0x046d, 0x08d8)}, + {USB_DEVICE(0x046d, 0x08d9)}, + {USB_DEVICE(0x046d, 0x08da)}, + {USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB}, + {USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x0326), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x032d), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x032e), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x055f, 0xc005)}, + {USB_DEVICE(0x055f, 0xd003)}, + {USB_DEVICE(0x055f, 0xd004)}, + {USB_DEVICE(0x0698, 0x2003)}, + {USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0ac8, 0x0302), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0ac8, 0x301b)}, + {USB_DEVICE(0x0ac8, 0x303b)}, + {USB_DEVICE(0x0ac8, 0x305b)}, + {USB_DEVICE(0x0ac8, 0x307b)}, + {USB_DEVICE(0x10fd, 0x0128)}, + {USB_DEVICE(0x10fd, 0x804d)}, + {USB_DEVICE(0x10fd, 0x8050)}, + {} /* end of entry */ +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +/* USB driver */ +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(force_sensor, int, 0644); +MODULE_PARM_DESC(force_sensor, + "Force sensor. Only for experts!!!"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/zc3xx-reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/zc3xx-reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/zc3xx-reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/gspca/zc3xx-reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,251 @@ +/* + * zc030x registers + * + * Copyright (c) 2008 Mauro Carvalho Chehab + * + * The register aliases used here came from this driver: + * http://zc0302.sourceforge.net/zc0302.php + * + * This code is placed under the terms of the GNU General Public License v2 + */ + +/* Define the register map */ +#define ZC3XX_R000_SYSTEMCONTROL 0x0000 +#define ZC3XX_R001_SYSTEMOPERATING 0x0001 + +/* Picture size */ +#define ZC3XX_R002_CLOCKSELECT 0x0002 +#define ZC3XX_R003_FRAMEWIDTHHIGH 0x0003 +#define ZC3XX_R004_FRAMEWIDTHLOW 0x0004 +#define ZC3XX_R005_FRAMEHEIGHTHIGH 0x0005 +#define ZC3XX_R006_FRAMEHEIGHTLOW 0x0006 + +/* JPEG control */ +#define ZC3XX_R008_CLOCKSETTING 0x0008 + +/* Test mode */ +#define ZC3XX_R00B_TESTMODECONTROL 0x000b + +/* Frame retreiving */ +#define ZC3XX_R00C_LASTACQTIME 0x000c +#define ZC3XX_R00D_MONITORRES 0x000d +#define ZC3XX_R00E_TIMESTAMPHIGH 0x000e +#define ZC3XX_R00F_TIMESTAMPLOW 0x000f +#define ZC3XX_R018_FRAMELOST 0x0018 +#define ZC3XX_R019_AUTOADJUSTFPS 0x0019 +#define ZC3XX_R01A_LASTFRAMESTATE 0x001a +#define ZC3XX_R025_DATACOUNTER 0x0025 + +/* Stream and sensor specific */ +#define ZC3XX_R010_CMOSSENSORSELECT 0x0010 +#define ZC3XX_R011_VIDEOSTATUS 0x0011 +#define ZC3XX_R012_VIDEOCONTROLFUNC 0x0012 + +/* Horizontal and vertical synchros */ +#define ZC3XX_R01D_HSYNC_0 0x001d +#define ZC3XX_R01E_HSYNC_1 0x001e +#define ZC3XX_R01F_HSYNC_2 0x001f +#define ZC3XX_R020_HSYNC_3 0x0020 + +/* Target picture size in byte */ +#define ZC3XX_R022_TARGETPICTSIZE_0 0x0022 +#define ZC3XX_R023_TARGETPICTSIZE_1 0x0023 +#define ZC3XX_R024_TARGETPICTSIZE_2 0x0024 + +/* Audio registers */ +#define ZC3XX_R030_AUDIOADC 0x0030 +#define ZC3XX_R031_AUDIOSTREAMSTATUS 0x0031 +#define ZC3XX_R032_AUDIOSTATUS 0x0032 + +/* Sensor interface */ +#define ZC3XX_R080_HBLANKHIGH 0x0080 +#define ZC3XX_R081_HBLANKLOW 0x0081 +#define ZC3XX_R082_RESETLEVELADDR 0x0082 +#define ZC3XX_R083_RGAINADDR 0x0083 +#define ZC3XX_R084_GGAINADDR 0x0084 +#define ZC3XX_R085_BGAINADDR 0x0085 +#define ZC3XX_R086_EXPTIMEHIGH 0x0086 +#define ZC3XX_R087_EXPTIMEMID 0x0087 +#define ZC3XX_R088_EXPTIMELOW 0x0088 +#define ZC3XX_R089_RESETBLACKHIGH 0x0089 +#define ZC3XX_R08A_RESETWHITEHIGH 0x008a +#define ZC3XX_R08B_I2CDEVICEADDR 0x008b +#define ZC3XX_R08C_I2CIDLEANDNACK 0x008c +#define ZC3XX_R08D_COMPABILITYMODE 0x008d +#define ZC3XX_R08E_COMPABILITYMODE2 0x008e + +/* I2C control */ +#define ZC3XX_R090_I2CCOMMAND 0x0090 +#define ZC3XX_R091_I2CSTATUS 0x0091 +#define ZC3XX_R092_I2CADDRESSSELECT 0x0092 +#define ZC3XX_R093_I2CSETVALUE 0x0093 +#define ZC3XX_R094_I2CWRITEACK 0x0094 +#define ZC3XX_R095_I2CREAD 0x0095 +#define ZC3XX_R096_I2CREADACK 0x0096 + +/* Window inside the sensor array */ +#define ZC3XX_R097_WINYSTARTHIGH 0x0097 +#define ZC3XX_R098_WINYSTARTLOW 0x0098 +#define ZC3XX_R099_WINXSTARTHIGH 0x0099 +#define ZC3XX_R09A_WINXSTARTLOW 0x009a +#define ZC3XX_R09B_WINHEIGHTHIGH 0x009b +#define ZC3XX_R09C_WINHEIGHTLOW 0x009c +#define ZC3XX_R09D_WINWIDTHHIGH 0x009d +#define ZC3XX_R09E_WINWIDTHLOW 0x009e +#define ZC3XX_R119_FIRSTYHIGH 0x0119 +#define ZC3XX_R11A_FIRSTYLOW 0x011a +#define ZC3XX_R11B_FIRSTXHIGH 0x011b +#define ZC3XX_R11C_FIRSTXLOW 0x011c + +/* Max sensor array size */ +#define ZC3XX_R09F_MAXXHIGH 0x009f +#define ZC3XX_R0A0_MAXXLOW 0x00a0 +#define ZC3XX_R0A1_MAXYHIGH 0x00a1 +#define ZC3XX_R0A2_MAXYLOW 0x00a2 +#define ZC3XX_R0A3_EXPOSURETIMEHIGH 0x00a3 +#define ZC3XX_R0A4_EXPOSURETIMELOW 0x00a4 +#define ZC3XX_R0A5_EXPOSUREGAIN 0x00a5 +#define ZC3XX_R0A6_EXPOSUREBLACKLVL 0x00a6 + +/* Other registers */ +#define ZC3XX_R100_OPERATIONMODE 0x0100 +#define ZC3XX_R101_SENSORCORRECTION 0x0101 + +/* Gains */ +#define ZC3XX_R116_RGAIN 0x0116 +#define ZC3XX_R117_GGAIN 0x0117 +#define ZC3XX_R118_BGAIN 0x0118 +#define ZC3XX_R11D_GLOBALGAIN 0x011d +#define ZC3XX_R1A8_DIGITALGAIN 0x01a8 +#define ZC3XX_R1A9_DIGITALLIMITDIFF 0x01a9 +#define ZC3XX_R1AA_DIGITALGAINSTEP 0x01aa + +/* Auto correction */ +#define ZC3XX_R180_AUTOCORRECTENABLE 0x0180 +#define ZC3XX_R181_WINXSTART 0x0181 +#define ZC3XX_R182_WINXWIDTH 0x0182 +#define ZC3XX_R183_WINXCENTER 0x0183 +#define ZC3XX_R184_WINYSTART 0x0184 +#define ZC3XX_R185_WINYWIDTH 0x0185 +#define ZC3XX_R186_WINYCENTER 0x0186 + +/* Gain range */ +#define ZC3XX_R187_MAXGAIN 0x0187 +#define ZC3XX_R188_MINGAIN 0x0188 + +/* Auto exposure and white balance */ +#define ZC3XX_R189_AWBSTATUS 0x0189 +#define ZC3XX_R18A_AWBFREEZE 0x018a +#define ZC3XX_R18B_AESTATUS 0x018b +#define ZC3XX_R18C_AEFREEZE 0x018c +#define ZC3XX_R18F_AEUNFREEZE 0x018f +#define ZC3XX_R190_EXPOSURELIMITHIGH 0x0190 +#define ZC3XX_R191_EXPOSURELIMITMID 0x0191 +#define ZC3XX_R192_EXPOSURELIMITLOW 0x0192 +#define ZC3XX_R195_ANTIFLICKERHIGH 0x0195 +#define ZC3XX_R196_ANTIFLICKERMID 0x0196 +#define ZC3XX_R197_ANTIFLICKERLOW 0x0197 + +/* What is this ? */ +#define ZC3XX_R18D_YTARGET 0x018d +#define ZC3XX_R18E_RESETLVL 0x018e + +/* Color */ +#define ZC3XX_R1A0_REDMEANAFTERAGC 0x01a0 +#define ZC3XX_R1A1_GREENMEANAFTERAGC 0x01a1 +#define ZC3XX_R1A2_BLUEMEANAFTERAGC 0x01a2 +#define ZC3XX_R1A3_REDMEANAFTERAWB 0x01a3 +#define ZC3XX_R1A4_GREENMEANAFTERAWB 0x01a4 +#define ZC3XX_R1A5_BLUEMEANAFTERAWB 0x01a5 +#define ZC3XX_R1A6_YMEANAFTERAE 0x01a6 +#define ZC3XX_R1A7_CALCGLOBALMEAN 0x01a7 + +/* Matrixes */ + +/* Color matrix is like : + R' = R * RGB00 + G * RGB01 + B * RGB02 + RGB03 + G' = R * RGB10 + G * RGB11 + B * RGB22 + RGB13 + B' = R * RGB20 + G * RGB21 + B * RGB12 + RGB23 + */ +#define ZC3XX_R10A_RGB00 0x010a +#define ZC3XX_R10B_RGB01 0x010b +#define ZC3XX_R10C_RGB02 0x010c +#define ZC3XX_R113_RGB03 0x0113 +#define ZC3XX_R10D_RGB10 0x010d +#define ZC3XX_R10E_RGB11 0x010e +#define ZC3XX_R10F_RGB12 0x010f +#define ZC3XX_R114_RGB13 0x0114 +#define ZC3XX_R110_RGB20 0x0110 +#define ZC3XX_R111_RGB21 0x0111 +#define ZC3XX_R112_RGB22 0x0112 +#define ZC3XX_R115_RGB23 0x0115 + +/* Gamma matrix */ +#define ZC3XX_R120_GAMMA00 0x0120 +#define ZC3XX_R121_GAMMA01 0x0121 +#define ZC3XX_R122_GAMMA02 0x0122 +#define ZC3XX_R123_GAMMA03 0x0123 +#define ZC3XX_R124_GAMMA04 0x0124 +#define ZC3XX_R125_GAMMA05 0x0125 +#define ZC3XX_R126_GAMMA06 0x0126 +#define ZC3XX_R127_GAMMA07 0x0127 +#define ZC3XX_R128_GAMMA08 0x0128 +#define ZC3XX_R129_GAMMA09 0x0129 +#define ZC3XX_R12A_GAMMA0A 0x012a +#define ZC3XX_R12B_GAMMA0B 0x012b +#define ZC3XX_R12C_GAMMA0C 0x012c +#define ZC3XX_R12D_GAMMA0D 0x012d +#define ZC3XX_R12E_GAMMA0E 0x012e +#define ZC3XX_R12F_GAMMA0F 0x012f +#define ZC3XX_R130_GAMMA10 0x0130 +#define ZC3XX_R131_GAMMA11 0x0131 +#define ZC3XX_R132_GAMMA12 0x0132 +#define ZC3XX_R133_GAMMA13 0x0133 +#define ZC3XX_R134_GAMMA14 0x0134 +#define ZC3XX_R135_GAMMA15 0x0135 +#define ZC3XX_R136_GAMMA16 0x0136 +#define ZC3XX_R137_GAMMA17 0x0137 +#define ZC3XX_R138_GAMMA18 0x0138 +#define ZC3XX_R139_GAMMA19 0x0139 +#define ZC3XX_R13A_GAMMA1A 0x013a +#define ZC3XX_R13B_GAMMA1B 0x013b +#define ZC3XX_R13C_GAMMA1C 0x013c +#define ZC3XX_R13D_GAMMA1D 0x013d +#define ZC3XX_R13E_GAMMA1E 0x013e +#define ZC3XX_R13F_GAMMA1F 0x013f + +/* Luminance gamma */ +#define ZC3XX_R140_YGAMMA00 0x0140 +#define ZC3XX_R141_YGAMMA01 0x0141 +#define ZC3XX_R142_YGAMMA02 0x0142 +#define ZC3XX_R143_YGAMMA03 0x0143 +#define ZC3XX_R144_YGAMMA04 0x0144 +#define ZC3XX_R145_YGAMMA05 0x0145 +#define ZC3XX_R146_YGAMMA06 0x0146 +#define ZC3XX_R147_YGAMMA07 0x0147 +#define ZC3XX_R148_YGAMMA08 0x0148 +#define ZC3XX_R149_YGAMMA09 0x0149 +#define ZC3XX_R14A_YGAMMA0A 0x014a +#define ZC3XX_R14B_YGAMMA0B 0x014b +#define ZC3XX_R14C_YGAMMA0C 0x014c +#define ZC3XX_R14D_YGAMMA0D 0x014d +#define ZC3XX_R14E_YGAMMA0E 0x014e +#define ZC3XX_R14F_YGAMMA0F 0x014f +#define ZC3XX_R150_YGAMMA10 0x0150 +#define ZC3XX_R151_YGAMMA11 0x0151 + +#define ZC3XX_R1C5_SHARPNESSMODE 0x01c5 +#define ZC3XX_R1C6_SHARPNESS00 0x01c6 +#define ZC3XX_R1C7_SHARPNESS01 0x01c7 +#define ZC3XX_R1C8_SHARPNESS02 0x01c8 +#define ZC3XX_R1C9_SHARPNESS03 0x01c9 +#define ZC3XX_R1CA_SHARPNESS04 0x01ca +#define ZC3XX_R1CB_SHARPNESS05 0x01cb + +/* Dead pixels */ +#define ZC3XX_R250_DEADPIXELSMODE 0x0250 + +/* EEPROM */ +#define ZC3XX_R300_EEPROMCONFIG 0x0300 +#define ZC3XX_R301_EEPROMACCESS 0x0301 +#define ZC3XX_R302_EEPROMSTATUS 0x0302 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-control.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-control.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-control.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-control.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,198 @@ +/* + * Hauppauge HD PVR USB driver - video 4 linux 2 interface + * + * Copyright (C) 2008 Janne Grunau (j@jannau.net) + * + * 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, version 2. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "hdpvr.h" + + +int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf) +{ + int ret; + char request_type = 0x38, snd_request = 0x01; + + mutex_lock(&dev->usbc_mutex); + dev->usbc_buf[0] = valbuf; + ret = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + snd_request, 0x00 | request_type, + value, CTRL_DEFAULT_INDEX, + dev->usbc_buf, 1, 10000); + + mutex_unlock(&dev->usbc_mutex); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "config call request for value 0x%x returned %d\n", value, + ret); + + return ret < 0 ? ret : 0; +} + +struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev) +{ + struct hdpvr_video_info *vidinf = NULL; +#ifdef HDPVR_DEBUG + char print_buf[15]; +#endif + int ret; + + vidinf = kzalloc(sizeof(struct hdpvr_video_info), GFP_KERNEL); + if (!vidinf) { + v4l2_err(&dev->v4l2_dev, "out of memory\n"); + goto err; + } + + mutex_lock(&dev->usbc_mutex); + ret = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + 0x81, 0x80 | 0x38, + 0x1400, 0x0003, + dev->usbc_buf, 5, + 1000); + if (ret == 5) { + vidinf->width = dev->usbc_buf[1] << 8 | dev->usbc_buf[0]; + vidinf->height = dev->usbc_buf[3] << 8 | dev->usbc_buf[2]; + vidinf->fps = dev->usbc_buf[4]; + } + +#ifdef HDPVR_DEBUG + if (hdpvr_debug & MSG_INFO) { + hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf, + sizeof(print_buf), 0); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "get video info returned: %d, %s\n", ret, print_buf); + } +#endif + mutex_unlock(&dev->usbc_mutex); + + if (!vidinf->width || !vidinf->height || !vidinf->fps) { + kfree(vidinf); + vidinf = NULL; + } +err: + return vidinf; +} + +int get_input_lines_info(struct hdpvr_device *dev) +{ +#ifdef HDPVR_DEBUG + char print_buf[9]; +#endif + int ret, lines; + + mutex_lock(&dev->usbc_mutex); + ret = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + 0x81, 0x80 | 0x38, + 0x1800, 0x0003, + dev->usbc_buf, 3, + 1000); + +#ifdef HDPVR_DEBUG + if (hdpvr_debug & MSG_INFO) { + hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf, + sizeof(print_buf), 0); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "get input lines info returned: %d, %s\n", ret, + print_buf); + } +#endif + lines = dev->usbc_buf[1] << 8 | dev->usbc_buf[0]; + mutex_unlock(&dev->usbc_mutex); + return lines; +} + + +int hdpvr_set_bitrate(struct hdpvr_device *dev) +{ + int ret; + + mutex_lock(&dev->usbc_mutex); + memset(dev->usbc_buf, 0, 4); + dev->usbc_buf[0] = dev->options.bitrate; + dev->usbc_buf[2] = dev->options.peak_bitrate; + + ret = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + 0x01, 0x38, CTRL_BITRATE_VALUE, + CTRL_DEFAULT_INDEX, dev->usbc_buf, 4, 1000); + mutex_unlock(&dev->usbc_mutex); + + return ret; +} + +int hdpvr_set_audio(struct hdpvr_device *dev, u8 input, + enum v4l2_mpeg_audio_encoding codec) +{ + int ret = 0; + + if (dev->flags & HDPVR_FLAG_AC3_CAP) { + mutex_lock(&dev->usbc_mutex); + memset(dev->usbc_buf, 0, 2); + dev->usbc_buf[0] = input; + if (codec == V4L2_MPEG_AUDIO_ENCODING_AAC) + dev->usbc_buf[1] = 0; + else if (codec == V4L2_MPEG_AUDIO_ENCODING_AC3) + dev->usbc_buf[1] = 1; + else { + mutex_unlock(&dev->usbc_mutex); + v4l2_err(&dev->v4l2_dev, "invalid audio codec %d\n", + codec); + ret = -EINVAL; + goto error; + } + + ret = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + 0x01, 0x38, CTRL_AUDIO_INPUT_VALUE, + CTRL_DEFAULT_INDEX, dev->usbc_buf, 2, + 1000); + mutex_unlock(&dev->usbc_mutex); + if (ret == 2) + ret = 0; + } else + ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE, input); +error: + return ret; +} + +int hdpvr_set_options(struct hdpvr_device *dev) +{ + hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std); + + hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, + dev->options.video_input+1); + + hdpvr_set_audio(dev, dev->options.audio_input+1, + dev->options.audio_codec); + + hdpvr_set_bitrate(dev); + hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, + dev->options.bitrate_mode); + hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode); + + hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness); + hdpvr_config_call(dev, CTRL_CONTRAST, dev->options.contrast); + hdpvr_config_call(dev, CTRL_HUE, dev->options.hue); + hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation); + hdpvr_config_call(dev, CTRL_SHARPNESS, dev->options.sharpness); + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,478 @@ +/* + * Hauppauge HD PVR USB driver + * + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2008 Janne Grunau (j@jannau.net) + * Copyright (C) 2008 John Poet + * + * 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, version 2. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hdpvr.h" + +static int video_nr[HDPVR_MAX] = {[0 ... (HDPVR_MAX - 1)] = UNSET}; +module_param_array(video_nr, int, NULL, 0); +MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)"); + +/* holds the number of currently registered devices */ +static atomic_t dev_nr = ATOMIC_INIT(-1); + +int hdpvr_debug; +module_param(hdpvr_debug, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(hdpvr_debug, "enable debugging output"); + +static uint default_video_input = HDPVR_VIDEO_INPUTS; +module_param(default_video_input, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / " + "1=S-Video / 2=Composite"); + +static uint default_audio_input = HDPVR_AUDIO_INPUTS; +module_param(default_audio_input, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / " + "1=RCA front / 2=S/PDIF"); + +static int boost_audio; +module_param(boost_audio, bool, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(boost_audio, "boost the audio signal"); + + +/* table of devices that work with this driver */ +static struct usb_device_id hdpvr_table[] = { + { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID) }, + { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) }, + { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) }, + { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID3) }, + { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID4) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, hdpvr_table); + + +void hdpvr_delete(struct hdpvr_device *dev) +{ + hdpvr_free_buffers(dev); + + if (dev->video_dev) + video_device_release(dev->video_dev); + + usb_put_dev(dev->udev); +} + +static void challenge(u8 *bytes) +{ + u64 *i64P, tmp64; + uint i, idx; + + for (idx = 0; idx < 32; ++idx) { + + if (idx & 0x3) + bytes[(idx >> 3) + 3] = bytes[(idx >> 2) & 0x3]; + + switch (idx & 0x3) { + case 0x3: + bytes[2] += bytes[3] * 4 + bytes[4] + bytes[5]; + bytes[4] += bytes[(idx & 0x1) * 2] * 9 + 9; + break; + case 0x1: + bytes[0] *= 8; + bytes[0] += 7*idx + 4; + bytes[6] += bytes[3] * 3; + break; + case 0x0: + bytes[3 - (idx >> 3)] = bytes[idx >> 2]; + bytes[5] += bytes[6] * 3; + for (i = 0; i < 3; i++) + bytes[3] *= bytes[3] + 1; + break; + case 0x2: + for (i = 0; i < 3; i++) + bytes[1] *= bytes[6] + 1; + for (i = 0; i < 3; i++) { + i64P = (u64 *)bytes; + tmp64 = le64_to_cpup(i64P); + tmp64 <<= bytes[7] & 0x0f; + *i64P += cpu_to_le64(tmp64); + } + break; + } + } +} + +/* try to init the device like the windows driver */ +static int device_authorization(struct hdpvr_device *dev) +{ + + int ret, retval = -ENOMEM; + char request_type = 0x38, rcv_request = 0x81; + char *response; +#ifdef HDPVR_DEBUG + size_t buf_size = 46; + char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL); + if (!print_buf) { + v4l2_err(&dev->v4l2_dev, "Out of memory\n"); + return retval; + } +#endif + + mutex_lock(&dev->usbc_mutex); + ret = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + rcv_request, 0x80 | request_type, + 0x0400, 0x0003, + dev->usbc_buf, 46, + 10000); + if (ret != 46) { + v4l2_err(&dev->v4l2_dev, + "unexpected answer of status request, len %d\n", ret); + goto unlock; + } +#ifdef HDPVR_DEBUG + else { + hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf, + 5*buf_size+1, 0); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "Status request returned, len %d: %s\n", + ret, print_buf); + } +#endif + + v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n", + dev->usbc_buf[1], &dev->usbc_buf[2]); + + switch (dev->usbc_buf[1]) { + case HDPVR_FIRMWARE_VERSION: + dev->flags &= ~HDPVR_FLAG_AC3_CAP; + break; + case HDPVR_FIRMWARE_VERSION_AC3: + case HDPVR_FIRMWARE_VERSION_0X12: + case HDPVR_FIRMWARE_VERSION_0X15: + dev->flags |= HDPVR_FLAG_AC3_CAP; + break; + default: + v4l2_info(&dev->v4l2_dev, "untested firmware, the driver might" + " not work.\n"); + if (dev->usbc_buf[1] >= HDPVR_FIRMWARE_VERSION_AC3) + dev->flags |= HDPVR_FLAG_AC3_CAP; + else + dev->flags &= ~HDPVR_FLAG_AC3_CAP; + } + + response = dev->usbc_buf+38; +#ifdef HDPVR_DEBUG + hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n", + print_buf); +#endif + challenge(response); +#ifdef HDPVR_DEBUG + hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n", + print_buf); +#endif + + msleep(100); + ret = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + 0xd1, 0x00 | request_type, + 0x0000, 0x0000, + response, 8, + 10000); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "magic request returned %d\n", ret); + + retval = ret != 8; +unlock: + mutex_unlock(&dev->usbc_mutex); + return retval; +} + +static int hdpvr_device_init(struct hdpvr_device *dev) +{ + int ret; + u8 *buf; + struct hdpvr_video_info *vidinf; + + if (device_authorization(dev)) + return -EACCES; + + /* default options for init */ + hdpvr_set_options(dev); + + /* set filter options */ + mutex_lock(&dev->usbc_mutex); + buf = dev->usbc_buf; + buf[0] = 0x03; buf[1] = 0x03; buf[2] = 0x00; buf[3] = 0x00; + ret = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + 0x01, 0x38, + CTRL_LOW_PASS_FILTER_VALUE, CTRL_DEFAULT_INDEX, + buf, 4, + 1000); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "control request returned %d\n", ret); + mutex_unlock(&dev->usbc_mutex); + + vidinf = get_video_info(dev); + if (!vidinf) + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "no valid video signal or device init failed\n"); + else + kfree(vidinf); + + /* enable fan and bling leds */ + mutex_lock(&dev->usbc_mutex); + buf[0] = 0x1; + ret = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + 0xd4, 0x38, 0, 0, buf, 1, + 1000); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "control request returned %d\n", ret); + + /* boost analog audio */ + buf[0] = boost_audio; + ret = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + 0xd5, 0x38, 0, 0, buf, 1, + 1000); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "control request returned %d\n", ret); + mutex_unlock(&dev->usbc_mutex); + + dev->status = STATUS_IDLE; + return 0; +} + +static const struct hdpvr_options hdpvr_default_options = { + .video_std = HDPVR_60HZ, + .video_input = HDPVR_COMPONENT, + .audio_input = HDPVR_RCA_BACK, + .bitrate = 65, /* 6 mbps */ + .peak_bitrate = 90, /* 9 mbps */ + .bitrate_mode = HDPVR_CONSTANT, + .gop_mode = HDPVR_SIMPLE_IDR_GOP, + .audio_codec = V4L2_MPEG_AUDIO_ENCODING_AAC, + .brightness = 0x86, + .contrast = 0x80, + .hue = 0x80, + .saturation = 0x80, + .sharpness = 0x80, +}; + +static int hdpvr_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct hdpvr_device *dev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct i2c_client *client; + size_t buffer_size; + int i; + int retval = -ENOMEM; + + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + err("Out of memory"); + goto error; + } + + dev->workqueue = 0; + + /* register v4l2_device early so it can be used for printks */ + if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) { + err("v4l2_device_register failed"); + goto error; + } + + mutex_init(&dev->io_mutex); + mutex_init(&dev->i2c_mutex); + mutex_init(&dev->usbc_mutex); + dev->usbc_buf = kmalloc(64, GFP_KERNEL); + if (!dev->usbc_buf) { + v4l2_err(&dev->v4l2_dev, "Out of memory\n"); + goto error; + } + + init_waitqueue_head(&dev->wait_buffer); + init_waitqueue_head(&dev->wait_data); + + dev->workqueue = create_singlethread_workqueue("hdpvr_buffer"); + if (!dev->workqueue) + goto error; + + /* init video transfer queues */ + INIT_LIST_HEAD(&dev->free_buff_list); + INIT_LIST_HEAD(&dev->rec_buff_list); + + dev->options = hdpvr_default_options; + + if (default_video_input < HDPVR_VIDEO_INPUTS) + dev->options.video_input = default_video_input; + + if (default_audio_input < HDPVR_AUDIO_INPUTS) { + dev->options.audio_input = default_audio_input; + if (default_audio_input == HDPVR_SPDIF) + dev->options.audio_codec = + V4L2_MPEG_AUDIO_ENCODING_AC3; + } + + dev->udev = usb_get_dev(interface_to_usbdev(interface)); + + /* set up the endpoint information */ + /* use only the first bulk-in and bulk-out endpoints */ + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!dev->bulk_in_endpointAddr && + usb_endpoint_is_bulk_in(endpoint)) { + /* USB interface description is buggy, reported max + * packet size is 512 bytes, windows driver uses 8192 */ + buffer_size = 8192; + dev->bulk_in_size = buffer_size; + dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; + } + + } + if (!dev->bulk_in_endpointAddr) { + v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n"); + goto error; + } + + /* init the device */ + if (hdpvr_device_init(dev)) { + v4l2_err(&dev->v4l2_dev, "device init failed\n"); + goto error; + } + + mutex_lock(&dev->io_mutex); + if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) { + mutex_unlock(&dev->io_mutex); + v4l2_err(&dev->v4l2_dev, + "allocating transfer buffers failed\n"); + goto error; + } + mutex_unlock(&dev->io_mutex); + + if (hdpvr_register_videodev(dev, &interface->dev, + video_nr[atomic_inc_return(&dev_nr)])) { + v4l2_err(&dev->v4l2_dev, "registering videodev failed\n"); + goto error; + } + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + retval = hdpvr_register_i2c_adapter(dev); + if (retval < 0) { + v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n"); + goto error; + } + + client = hdpvr_register_ir_rx_i2c(dev); + if (!client) { + v4l2_err(&dev->v4l2_dev, "i2c IR RX device register failed\n"); + goto reg_fail; + } + + client = hdpvr_register_ir_tx_i2c(dev); + if (!client) { + v4l2_err(&dev->v4l2_dev, "i2c IR TX device register failed\n"); + goto reg_fail; + } +#endif + + /* let the user know what node this device is now attached to */ + v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", + video_device_node_name(dev->video_dev)); + return 0; + +reg_fail: +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_adapter(&dev->i2c_adapter); +#endif +error: + if (dev) { + /* Destroy single thread */ + if (dev->workqueue) + destroy_workqueue(dev->workqueue); + /* this frees allocated memory */ + hdpvr_delete(dev); + } + return retval; +} + +static void hdpvr_disconnect(struct usb_interface *interface) +{ + struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface)); + + v4l2_info(&dev->v4l2_dev, "device %s disconnected\n", + video_device_node_name(dev->video_dev)); + /* prevent more I/O from starting and stop any ongoing */ + mutex_lock(&dev->io_mutex); + dev->status = STATUS_DISCONNECTED; + wake_up_interruptible(&dev->wait_data); + wake_up_interruptible(&dev->wait_buffer); + mutex_unlock(&dev->io_mutex); + v4l2_device_disconnect(&dev->v4l2_dev); + msleep(100); + flush_workqueue(dev->workqueue); + mutex_lock(&dev->io_mutex); + hdpvr_cancel_queue(dev); + mutex_unlock(&dev->io_mutex); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_adapter(&dev->i2c_adapter); +#endif + video_unregister_device(dev->video_dev); + atomic_dec(&dev_nr); +} + + +static struct usb_driver hdpvr_usb_driver = { + .name = "hdpvr", + .probe = hdpvr_probe, + .disconnect = hdpvr_disconnect, + .id_table = hdpvr_table, +}; + +static int __init hdpvr_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&hdpvr_usb_driver); + if (result) + err("usb_register failed. Error number %d", result); + + return result; +} + +static void __exit hdpvr_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&hdpvr_usb_driver); +} + +module_init(hdpvr_init); +module_exit(hdpvr_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Janne Grunau"); +MODULE_DESCRIPTION("Hauppauge HD PVR driver"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,322 @@ +/* + * Hauppauge HD PVR USB driver + * + * Copyright (C) 2008 Janne Grunau (j@jannau.net) + * + * 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, version 2. + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define HDPVR_MAJOR_VERSION 0 +#define HDPVR_MINOR_VERSION 2 +#define HDPVR_RELEASE 0 +#define HDPVR_VERSION \ + KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE) + +#define HDPVR_MAX 8 +#define HDPVR_I2C_MAX_SIZE 128 + +/* Define these values to match your devices */ +#define HD_PVR_VENDOR_ID 0x2040 +#define HD_PVR_PRODUCT_ID 0x4900 +#define HD_PVR_PRODUCT_ID1 0x4901 +#define HD_PVR_PRODUCT_ID2 0x4902 +#define HD_PVR_PRODUCT_ID4 0x4903 +#define HD_PVR_PRODUCT_ID3 0x4982 + +#define UNSET (-1U) + +#define NUM_BUFFERS 64 + +#define HDPVR_FIRMWARE_VERSION 0x08 +#define HDPVR_FIRMWARE_VERSION_AC3 0x0d +#define HDPVR_FIRMWARE_VERSION_0X12 0x12 +#define HDPVR_FIRMWARE_VERSION_0X15 0x15 + +/* #define HDPVR_DEBUG */ + +extern int hdpvr_debug; + +#define MSG_INFO 1 +#define MSG_BUFFER 2 + +struct hdpvr_options { + u8 video_std; + u8 video_input; + u8 audio_input; + u8 bitrate; /* in 100kbps */ + u8 peak_bitrate; /* in 100kbps */ + u8 bitrate_mode; + u8 gop_mode; + enum v4l2_mpeg_audio_encoding audio_codec; + u8 brightness; + u8 contrast; + u8 hue; + u8 saturation; + u8 sharpness; +}; + +/* Structure to hold all of our device specific stuff */ +struct hdpvr_device { + /* the v4l device for this device */ + struct video_device *video_dev; + /* the usb device for this device */ + struct usb_device *udev; + /* v4l2-device unused */ + struct v4l2_device v4l2_dev; + + /* the max packet size of the bulk endpoint */ + size_t bulk_in_size; + /* the address of the bulk in endpoint */ + __u8 bulk_in_endpointAddr; + + /* holds the current device status */ + __u8 status; + /* count the number of openers */ + uint open_count; + + /* holds the cureent set options */ + struct hdpvr_options options; + + uint flags; + + /* synchronize I/O */ + struct mutex io_mutex; + /* available buffers */ + struct list_head free_buff_list; + /* in progress buffers */ + struct list_head rec_buff_list; + /* waitqueue for buffers */ + wait_queue_head_t wait_buffer; + /* waitqueue for data */ + wait_queue_head_t wait_data; + /**/ + struct workqueue_struct *workqueue; + /**/ + struct work_struct worker; + + /* I2C adapter */ + struct i2c_adapter i2c_adapter; + /* I2C lock */ + struct mutex i2c_mutex; + /* I2C message buffer space */ + char i2c_buf[HDPVR_I2C_MAX_SIZE]; + + /* For passing data to ir-kbd-i2c */ + struct IR_i2c_init_data ir_i2c_init_data; + + /* usb control transfer buffer and lock */ + struct mutex usbc_mutex; + u8 *usbc_buf; +}; + +static inline struct hdpvr_device *to_hdpvr_dev(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct hdpvr_device, v4l2_dev); +} + + +/* buffer one bulk urb of data */ +struct hdpvr_buffer { + struct list_head buff_list; + + struct urb *urb; + + struct hdpvr_device *dev; + + uint pos; + + __u8 status; +}; + +/* */ + +struct hdpvr_video_info { + u16 width; + u16 height; + u8 fps; +}; + +enum { + STATUS_UNINITIALIZED = 0, + STATUS_IDLE, + STATUS_STARTING, + STATUS_SHUTTING_DOWN, + STATUS_STREAMING, + STATUS_ERROR, + STATUS_DISCONNECTED, +}; + +enum { + HDPVR_FLAG_AC3_CAP = 1, +}; + +enum { + BUFSTAT_UNINITIALIZED = 0, + BUFSTAT_AVAILABLE, + BUFSTAT_INPROGRESS, + BUFSTAT_READY, +}; + +#define CTRL_START_STREAMING_VALUE 0x0700 +#define CTRL_STOP_STREAMING_VALUE 0x0800 +#define CTRL_BITRATE_VALUE 0x1000 +#define CTRL_BITRATE_MODE_VALUE 0x1200 +#define CTRL_GOP_MODE_VALUE 0x1300 +#define CTRL_VIDEO_INPUT_VALUE 0x1500 +#define CTRL_VIDEO_STD_TYPE 0x1700 +#define CTRL_AUDIO_INPUT_VALUE 0x2500 +#define CTRL_BRIGHTNESS 0x2900 +#define CTRL_CONTRAST 0x2a00 +#define CTRL_HUE 0x2b00 +#define CTRL_SATURATION 0x2c00 +#define CTRL_SHARPNESS 0x2d00 +#define CTRL_LOW_PASS_FILTER_VALUE 0x3100 + +#define CTRL_DEFAULT_INDEX 0x0003 + + + /* :0 s 38 01 1000 0003 0004 4 = 0a00ca00 + * BITRATE SETTING + * 1st and 2nd byte (little endian): average bitrate in 100 000 bit/s + * min: 1 mbit/s, max: 13.5 mbit/s + * 3rd and 4th byte (little endian): peak bitrate in 100 000 bit/s + * min: average + 100kbit/s, + * max: 20.2 mbit/s + */ + + /* :0 s 38 01 1200 0003 0001 1 = 02 + * BIT RATE MODE + * constant = 1, variable (peak) = 2, variable (average) = 3 + */ + + /* :0 s 38 01 1300 0003 0001 1 = 03 + * GOP MODE (2 bit) + * low bit 0/1: advanced/simple GOP + * high bit 0/1: IDR(4/32/128) / no IDR (4/32/0) + */ + + /* :0 s 38 01 1700 0003 0001 1 = 00 + * VIDEO STANDARD or FREQUNCY 0 = 60hz, 1 = 50hz + */ + + /* :0 s 38 01 3100 0003 0004 4 = 03030000 + * FILTER CONTROL + * 1st byte luma low pass filter strength, + * 2nd byte chroma low pass filter strength, + * 3rd byte MF enable chroma, min=0, max=1 + * 4th byte n + */ + + + /* :0 s 38 b9 0001 0000 0000 0 */ + + + +/* :0 s 38 d3 0000 0000 0001 1 = 00 */ +/* ret = usb_control_msg(dev->udev, */ +/* usb_sndctrlpipe(dev->udev, 0), */ +/* 0xd3, 0x38, */ +/* 0, 0, */ +/* "\0", 1, */ +/* 1000); */ + +/* info("control request returned %d", ret); */ +/* msleep(5000); */ + + + /* :0 s b8 81 1400 0003 0005 5 < + * :0 0 5 = d0024002 19 + * QUERY FRAME SIZE AND RATE + * 1st and 2nd byte (little endian): horizontal resolution + * 3rd and 4th byte (little endian): vertical resolution + * 5th byte: frame rate + */ + + /* :0 s b8 81 1800 0003 0003 3 < + * :0 0 3 = 030104 + * QUERY SIGNAL AND DETECTED LINES, maybe INPUT + */ + +enum hdpvr_video_std { + HDPVR_60HZ = 0, + HDPVR_50HZ, +}; + +enum hdpvr_video_input { + HDPVR_COMPONENT = 0, + HDPVR_SVIDEO, + HDPVR_COMPOSITE, + HDPVR_VIDEO_INPUTS +}; + +enum hdpvr_audio_inputs { + HDPVR_RCA_BACK = 0, + HDPVR_RCA_FRONT, + HDPVR_SPDIF, + HDPVR_AUDIO_INPUTS +}; + +enum hdpvr_bitrate_mode { + HDPVR_CONSTANT = 1, + HDPVR_VARIABLE_PEAK, + HDPVR_VARIABLE_AVERAGE, +}; + +enum hdpvr_gop_mode { + HDPVR_ADVANCED_IDR_GOP = 0, + HDPVR_SIMPLE_IDR_GOP, + HDPVR_ADVANCED_NOIDR_GOP, + HDPVR_SIMPLE_NOIDR_GOP, +}; + +void hdpvr_delete(struct hdpvr_device *dev); + +/*========================================================================*/ +/* hardware control functions */ +int hdpvr_set_options(struct hdpvr_device *dev); + +int hdpvr_set_bitrate(struct hdpvr_device *dev); + +int hdpvr_set_audio(struct hdpvr_device *dev, u8 input, + enum v4l2_mpeg_audio_encoding codec); + +int hdpvr_config_call(struct hdpvr_device *dev, uint value, + unsigned char valbuf); + +struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev); + +/* :0 s b8 81 1800 0003 0003 3 < */ +/* :0 0 3 = 0301ff */ +int get_input_lines_info(struct hdpvr_device *dev); + + +/*========================================================================*/ +/* v4l2 registration */ +int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, + int devnumber); + +int hdpvr_cancel_queue(struct hdpvr_device *dev); + +/*========================================================================*/ +/* i2c adapter registration */ +int hdpvr_register_i2c_adapter(struct hdpvr_device *dev); + +struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev); +struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev); + +/*========================================================================*/ +/* buffer management */ +int hdpvr_free_buffers(struct hdpvr_device *dev); +int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,230 @@ + +/* + * Hauppauge HD PVR USB driver + * + * Copyright (C) 2008 Janne Grunau (j@jannau.net) + * + * IR device registration code is + * Copyright (C) 2010 Andy Walls + * + * 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, version 2. + * + */ + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + +#include +#include + +#include "hdpvr.h" + +#define CTRL_READ_REQUEST 0xb8 +#define CTRL_WRITE_REQUEST 0x38 + +#define REQTYPE_I2C_READ 0xb1 +#define REQTYPE_I2C_WRITE 0xb0 +#define REQTYPE_I2C_WRITE_STATT 0xd0 + +#define Z8F0811_IR_TX_I2C_ADDR 0x70 +#define Z8F0811_IR_RX_I2C_ADDR 0x71 + + +struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev) +{ + struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; + struct i2c_board_info hdpvr_ir_tx_i2c_board_info = { + I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR), + }; + + init_data->name = "HD-PVR"; + hdpvr_ir_tx_i2c_board_info.platform_data = init_data; + + return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_tx_i2c_board_info); +} + +struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) +{ + struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; + struct i2c_board_info hdpvr_ir_rx_i2c_board_info = { + I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR), + }; + + /* Our default information for ir-kbd-i2c.c to use */ + init_data->ir_codes = RC_MAP_HAUPPAUGE; + init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; + init_data->type = RC_TYPE_RC5; + init_data->name = "HD-PVR"; + init_data->polling_interval = 405; /* ms, duplicated from Windows */ + hdpvr_ir_rx_i2c_board_info.platform_data = init_data; + + return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_rx_i2c_board_info); +} + +static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, + unsigned char addr, char *wdata, int wlen, + char *data, int len) +{ + int ret; + + if ((len > sizeof(dev->i2c_buf)) || (wlen > sizeof(dev->i2c_buf))) + return -EINVAL; + + if (wlen) { + memcpy(&dev->i2c_buf, wdata, wlen); + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, + (bus << 8) | addr, 0, &dev->i2c_buf, + wlen, 1000); + if (ret < 0) + return ret; + } + + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), + REQTYPE_I2C_READ, CTRL_READ_REQUEST, + (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); + + if (ret == len) { + memcpy(data, &dev->i2c_buf, len); + ret = 0; + } else if (ret >= 0) + ret = -EIO; + + return ret; +} + +static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus, + unsigned char addr, char *data, int len) +{ + int ret; + + if (len > sizeof(dev->i2c_buf)) + return -EINVAL; + + memcpy(&dev->i2c_buf, data, len); + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, + (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); + + if (ret < 0) + return ret; + + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), + REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, + 0, 0, &dev->i2c_buf, 2, 1000); + + if ((ret == 2) && (dev->i2c_buf[1] == (len - 1))) + ret = 0; + else if (ret >= 0) + ret = -EIO; + + return ret; +} + +static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, + int num) +{ + struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter); + int retval = 0, addr; + + if (num <= 0) + return 0; + + mutex_lock(&dev->i2c_mutex); + + addr = msgs[0].addr << 1; + + if (num == 1) { + if (msgs[0].flags & I2C_M_RD) + retval = hdpvr_i2c_read(dev, 1, addr, NULL, 0, + msgs[0].buf, msgs[0].len); + else + retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf, + msgs[0].len); + } else if (num == 2) { + if (msgs[0].addr != msgs[1].addr) { + v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer " + "with conflicting target addresses\n"); + retval = -EINVAL; + goto out; + } + + if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) { + v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with " + "r0=%d, r1=%d\n", msgs[0].flags & I2C_M_RD, + msgs[1].flags & I2C_M_RD); + retval = -EINVAL; + goto out; + } + + /* + * Write followed by atomic read is the only complex xfer that + * we actually support here. + */ + retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len, + msgs[1].buf, msgs[1].len); + } else { + v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num); + } + +out: + mutex_unlock(&dev->i2c_mutex); + + return retval ? retval : num; +} + +static u32 hdpvr_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm hdpvr_algo = { + .master_xfer = hdpvr_transfer, + .functionality = hdpvr_functionality, +}; + +static struct i2c_adapter hdpvr_i2c_adapter_template = { + .name = "Hauppage HD PVR I2C", + .owner = THIS_MODULE, + .algo = &hdpvr_algo, +}; + +static int hdpvr_activate_ir(struct hdpvr_device *dev) +{ + char buffer[2]; + + mutex_lock(&dev->i2c_mutex); + + hdpvr_i2c_read(dev, 0, 0x54, NULL, 0, buffer, 1); + + buffer[0] = 0; + buffer[1] = 0x8; + hdpvr_i2c_write(dev, 1, 0x54, buffer, 2); + + buffer[1] = 0x18; + hdpvr_i2c_write(dev, 1, 0x54, buffer, 2); + + mutex_unlock(&dev->i2c_mutex); + + return 0; +} + +int hdpvr_register_i2c_adapter(struct hdpvr_device *dev) +{ + int retval = -ENOMEM; + + hdpvr_activate_ir(dev); + + memcpy(&dev->i2c_adapter, &hdpvr_i2c_adapter_template, + sizeof(struct i2c_adapter)); + dev->i2c_adapter.dev.parent = &dev->udev->dev; + + i2c_set_adapdata(&dev->i2c_adapter, dev); + + retval = i2c_add_adapter(&dev->i2c_adapter); + + return retval; +} + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-video.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-video.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-video.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/hdpvr-video.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1271 @@ +/* + * Hauppauge HD PVR USB driver - video 4 linux 2 interface + * + * Copyright (C) 2008 Janne Grunau (j@jannau.net) + * + * 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, version 2. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "hdpvr.h" + +#define BULK_URB_TIMEOUT 90 /* 0.09 seconds */ + +#define print_buffer_status() { \ + v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, \ + "%s:%d buffer stat: %d free, %d proc\n", \ + __func__, __LINE__, \ + list_size(&dev->free_buff_list), \ + list_size(&dev->rec_buff_list)); } + +struct hdpvr_fh { + struct hdpvr_device *dev; +}; + +static uint list_size(struct list_head *list) +{ + struct list_head *tmp; + uint count = 0; + + list_for_each(tmp, list) { + count++; + } + + return count; +} + +/*=========================================================================*/ +/* urb callback */ +static void hdpvr_read_bulk_callback(struct urb *urb) +{ + struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context; + struct hdpvr_device *dev = buf->dev; + + /* marking buffer as received and wake waiting */ + buf->status = BUFSTAT_READY; + wake_up_interruptible(&dev->wait_data); +} + +/*=========================================================================*/ +/* bufffer bits */ + +/* function expects dev->io_mutex to be hold by caller */ +int hdpvr_cancel_queue(struct hdpvr_device *dev) +{ + struct hdpvr_buffer *buf; + + list_for_each_entry(buf, &dev->rec_buff_list, buff_list) { + usb_kill_urb(buf->urb); + buf->status = BUFSTAT_AVAILABLE; + } + + list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev); + + return 0; +} + +static int hdpvr_free_queue(struct list_head *q) +{ + struct list_head *tmp; + struct list_head *p; + struct hdpvr_buffer *buf; + struct urb *urb; + + for (p = q->next; p != q;) { + buf = list_entry(p, struct hdpvr_buffer, buff_list); + + urb = buf->urb; + usb_free_coherent(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); + usb_free_urb(urb); + tmp = p->next; + list_del(p); + kfree(buf); + p = tmp; + } + + return 0; +} + +/* function expects dev->io_mutex to be hold by caller */ +int hdpvr_free_buffers(struct hdpvr_device *dev) +{ + hdpvr_cancel_queue(dev); + + hdpvr_free_queue(&dev->free_buff_list); + hdpvr_free_queue(&dev->rec_buff_list); + + return 0; +} + +/* function expects dev->io_mutex to be hold by caller */ +int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count) +{ + uint i; + int retval = -ENOMEM; + u8 *mem; + struct hdpvr_buffer *buf; + struct urb *urb; + + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "allocating %u buffers\n", count); + + for (i = 0; i < count; i++) { + + buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL); + if (!buf) { + v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n"); + goto exit; + } + buf->dev = dev; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n"); + goto exit_urb; + } + buf->urb = urb; + + mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL, + &urb->transfer_dma); + if (!mem) { + v4l2_err(&dev->v4l2_dev, + "cannot allocate usb transfer buffer\n"); + goto exit_urb_buffer; + } + + usb_fill_bulk_urb(buf->urb, dev->udev, + usb_rcvbulkpipe(dev->udev, + dev->bulk_in_endpointAddr), + mem, dev->bulk_in_size, + hdpvr_read_bulk_callback, buf); + + buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + buf->status = BUFSTAT_AVAILABLE; + list_add_tail(&buf->buff_list, &dev->free_buff_list); + } + return 0; +exit_urb_buffer: + usb_free_urb(urb); +exit_urb: + kfree(buf); +exit: + hdpvr_free_buffers(dev); + return retval; +} + +static int hdpvr_submit_buffers(struct hdpvr_device *dev) +{ + struct hdpvr_buffer *buf; + struct urb *urb; + int ret = 0, err_count = 0; + + mutex_lock(&dev->io_mutex); + + while (dev->status == STATUS_STREAMING && + !list_empty(&dev->free_buff_list)) { + + buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer, + buff_list); + if (buf->status != BUFSTAT_AVAILABLE) { + v4l2_err(&dev->v4l2_dev, + "buffer not marked as available\n"); + ret = -EFAULT; + goto err; + } + + urb = buf->urb; + urb->status = 0; + urb->actual_length = 0; + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + v4l2_err(&dev->v4l2_dev, + "usb_submit_urb in %s returned %d\n", + __func__, ret); + if (++err_count > 2) + break; + continue; + } + buf->status = BUFSTAT_INPROGRESS; + list_move_tail(&buf->buff_list, &dev->rec_buff_list); + } +err: + print_buffer_status(); + mutex_unlock(&dev->io_mutex); + return ret; +} + +static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev) +{ + struct hdpvr_buffer *buf; + + mutex_lock(&dev->io_mutex); + + if (list_empty(&dev->rec_buff_list)) { + mutex_unlock(&dev->io_mutex); + return NULL; + } + + buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer, + buff_list); + mutex_unlock(&dev->io_mutex); + + return buf; +} + +static void hdpvr_transmit_buffers(struct work_struct *work) +{ + struct hdpvr_device *dev = container_of(work, struct hdpvr_device, + worker); + + while (dev->status == STATUS_STREAMING) { + + if (hdpvr_submit_buffers(dev)) { + v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n"); + goto error; + } + if (wait_event_interruptible(dev->wait_buffer, + !list_empty(&dev->free_buff_list) || + dev->status != STATUS_STREAMING)) + goto error; + } + + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "transmit worker exited\n"); + return; +error: + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "transmit buffers errored\n"); + dev->status = STATUS_ERROR; +} + +/* function expects dev->io_mutex to be hold by caller */ +static int hdpvr_start_streaming(struct hdpvr_device *dev) +{ + int ret; + struct hdpvr_video_info *vidinf; + + if (dev->status == STATUS_STREAMING) + return 0; + else if (dev->status != STATUS_IDLE) + return -EAGAIN; + + vidinf = get_video_info(dev); + + if (vidinf) { + v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, + "video signal: %dx%d@%dhz\n", vidinf->width, + vidinf->height, vidinf->fps); + kfree(vidinf); + + /* start streaming 2 request */ + ret = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + 0xb8, 0x38, 0x1, 0, NULL, 0, 8000); + v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, + "encoder start control request returned %d\n", ret); + + hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00); + + INIT_WORK(&dev->worker, hdpvr_transmit_buffers); + queue_work(dev->workqueue, &dev->worker); + + v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, + "streaming started\n"); + dev->status = STATUS_STREAMING; + + return 0; + } + msleep(250); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "no video signal at input %d\n", dev->options.video_input); + return -EAGAIN; +} + + +/* function expects dev->io_mutex to be hold by caller */ +static int hdpvr_stop_streaming(struct hdpvr_device *dev) +{ + int actual_length; + uint c = 0; + u8 *buf; + + if (dev->status == STATUS_IDLE) + return 0; + else if (dev->status != STATUS_STREAMING) + return -EAGAIN; + + buf = kmalloc(dev->bulk_in_size, GFP_KERNEL); + if (!buf) + v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer " + "for emptying the internal device buffer. " + "Next capture start will be slow\n"); + + dev->status = STATUS_SHUTTING_DOWN; + hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00); + mutex_unlock(&dev->io_mutex); + + wake_up_interruptible(&dev->wait_buffer); + msleep(50); + + flush_workqueue(dev->workqueue); + + mutex_lock(&dev->io_mutex); + /* kill the still outstanding urbs */ + hdpvr_cancel_queue(dev); + + /* emptying the device buffer beforeshutting it down */ + while (buf && ++c < 500 && + !usb_bulk_msg(dev->udev, + usb_rcvbulkpipe(dev->udev, + dev->bulk_in_endpointAddr), + buf, dev->bulk_in_size, &actual_length, + BULK_URB_TIMEOUT)) { + v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, + "%2d: got %d bytes\n", c, actual_length); + } + kfree(buf); + v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, + "used %d urbs to empty device buffers\n", c-1); + msleep(10); + + dev->status = STATUS_IDLE; + + return 0; +} + + +/*=======================================================================*/ +/* + * video 4 linux 2 file operations + */ + +static int hdpvr_open(struct file *file) +{ + struct hdpvr_device *dev; + struct hdpvr_fh *fh; + int retval = -ENOMEM; + + dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file)); + if (!dev) { + pr_err("open failing with with ENODEV\n"); + retval = -ENODEV; + goto err; + } + + fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL); + if (!fh) { + v4l2_err(&dev->v4l2_dev, "Out of memory\n"); + goto err; + } + /* lock the device to allow correctly handling errors + * in resumption */ + mutex_lock(&dev->io_mutex); + dev->open_count++; + mutex_unlock(&dev->io_mutex); + + fh->dev = dev; + + /* save our object in the file's private structure */ + file->private_data = fh; + + retval = 0; +err: + return retval; +} + +static int hdpvr_release(struct file *file) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + + if (!dev) + return -ENODEV; + + mutex_lock(&dev->io_mutex); + if (!(--dev->open_count) && dev->status == STATUS_STREAMING) + hdpvr_stop_streaming(dev); + + mutex_unlock(&dev->io_mutex); + + return 0; +} + +/* + * hdpvr_v4l2_read() + * will allocate buffers when called for the first time + */ +static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, + loff_t *pos) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + struct hdpvr_buffer *buf = NULL; + struct urb *urb; + unsigned int ret = 0; + int rem, cnt; + + if (*pos) + return -ESPIPE; + + if (!dev) + return -ENODEV; + + mutex_lock(&dev->io_mutex); + if (dev->status == STATUS_IDLE) { + if (hdpvr_start_streaming(dev)) { + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "start_streaming failed\n"); + ret = -EIO; + msleep(200); + dev->status = STATUS_IDLE; + mutex_unlock(&dev->io_mutex); + goto err; + } + print_buffer_status(); + } + mutex_unlock(&dev->io_mutex); + + /* wait for the first buffer */ + if (!(file->f_flags & O_NONBLOCK)) { + if (wait_event_interruptible(dev->wait_data, + hdpvr_get_next_buffer(dev))) + return -ERESTARTSYS; + } + + buf = hdpvr_get_next_buffer(dev); + + while (count > 0 && buf) { + + if (buf->status != BUFSTAT_READY && + dev->status != STATUS_DISCONNECTED) { + /* return nonblocking */ + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + goto err; + } + + if (wait_event_interruptible(dev->wait_data, + buf->status == BUFSTAT_READY)) { + ret = -ERESTARTSYS; + goto err; + } + } + + if (buf->status != BUFSTAT_READY) + break; + + /* set remaining bytes to copy */ + urb = buf->urb; + rem = urb->actual_length - buf->pos; + cnt = rem > count ? count : rem; + + if (copy_to_user(buffer, urb->transfer_buffer + buf->pos, + cnt)) { + v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n"); + if (!ret) + ret = -EFAULT; + goto err; + } + + buf->pos += cnt; + count -= cnt; + buffer += cnt; + ret += cnt; + + /* finished, take next buffer */ + if (buf->pos == urb->actual_length) { + mutex_lock(&dev->io_mutex); + buf->pos = 0; + buf->status = BUFSTAT_AVAILABLE; + + list_move_tail(&buf->buff_list, &dev->free_buff_list); + + print_buffer_status(); + + mutex_unlock(&dev->io_mutex); + + wake_up_interruptible(&dev->wait_buffer); + + buf = hdpvr_get_next_buffer(dev); + } + } +err: + if (!ret && !buf) + ret = -EAGAIN; + return ret; +} + +static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) +{ + struct hdpvr_buffer *buf = NULL; + struct hdpvr_fh *fh = filp->private_data; + struct hdpvr_device *dev = fh->dev; + unsigned int mask = 0; + + mutex_lock(&dev->io_mutex); + + if (!video_is_registered(dev->video_dev)) { + mutex_unlock(&dev->io_mutex); + return -EIO; + } + + if (dev->status == STATUS_IDLE) { + if (hdpvr_start_streaming(dev)) { + v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, + "start_streaming failed\n"); + dev->status = STATUS_IDLE; + } + + print_buffer_status(); + } + mutex_unlock(&dev->io_mutex); + + buf = hdpvr_get_next_buffer(dev); + /* only wait if no data is available */ + if (!buf || buf->status != BUFSTAT_READY) { + poll_wait(filp, &dev->wait_data, wait); + buf = hdpvr_get_next_buffer(dev); + } + if (buf && buf->status == BUFSTAT_READY) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + + +static const struct v4l2_file_operations hdpvr_fops = { + .owner = THIS_MODULE, + .open = hdpvr_open, + .release = hdpvr_release, + .read = hdpvr_read, + .poll = hdpvr_poll, + .unlocked_ioctl = video_ioctl2, +}; + +/*=======================================================================*/ +/* + * V4L2 ioctl handling + */ + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct hdpvr_device *dev = video_drvdata(file); + + strcpy(cap->driver, "hdpvr"); + strcpy(cap->card, "Hauppauge HD PVR"); + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + cap->version = HDPVR_VERSION; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE; + return 0; +} + +static int vidioc_s_std(struct file *file, void *private_data, + v4l2_std_id *std) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + u8 std_type = 1; + + if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60)) + std_type = 0; + + return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); +} + +static const char *iname[] = { + [HDPVR_COMPONENT] = "Component", + [HDPVR_SVIDEO] = "S-Video", + [HDPVR_COMPOSITE] = "Composite", +}; + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + unsigned int n; + + n = i->index; + if (n >= HDPVR_VIDEO_INPUTS) + return -EINVAL; + + i->type = V4L2_INPUT_TYPE_CAMERA; + + strncpy(i->name, iname[n], sizeof(i->name) - 1); + i->name[sizeof(i->name) - 1] = '\0'; + + i->audioset = 1<std = dev->video_dev->tvnorms; + + return 0; +} + +static int vidioc_s_input(struct file *file, void *private_data, + unsigned int index) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + int retval; + + if (index >= HDPVR_VIDEO_INPUTS) + return -EINVAL; + + if (dev->status != STATUS_IDLE) + return -EAGAIN; + + retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1); + if (!retval) + dev->options.video_input = index; + + return retval; +} + +static int vidioc_g_input(struct file *file, void *private_data, + unsigned int *index) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + + *index = dev->options.video_input; + return 0; +} + + +static const char *audio_iname[] = { + [HDPVR_RCA_FRONT] = "RCA front", + [HDPVR_RCA_BACK] = "RCA back", + [HDPVR_SPDIF] = "SPDIF", +}; + +static int vidioc_enumaudio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + unsigned int n; + + n = audio->index; + if (n >= HDPVR_AUDIO_INPUTS) + return -EINVAL; + + audio->capability = V4L2_AUDCAP_STEREO; + + strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1); + audio->name[sizeof(audio->name) - 1] = '\0'; + + return 0; +} + +static int vidioc_s_audio(struct file *file, void *private_data, + struct v4l2_audio *audio) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + int retval; + + if (audio->index >= HDPVR_AUDIO_INPUTS) + return -EINVAL; + + if (dev->status != STATUS_IDLE) + return -EAGAIN; + + retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec); + if (!retval) + dev->options.audio_input = audio->index; + + return retval; +} + +static int vidioc_g_audio(struct file *file, void *private_data, + struct v4l2_audio *audio) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + + audio->index = dev->options.audio_input; + audio->capability = V4L2_AUDCAP_STEREO; + strncpy(audio->name, audio_iname[audio->index], sizeof(audio->name)); + audio->name[sizeof(audio->name) - 1] = '\0'; + return 0; +} + +static const s32 supported_v4l2_ctrls[] = { + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_SHARPNESS, + V4L2_CID_MPEG_AUDIO_ENCODING, + V4L2_CID_MPEG_VIDEO_ENCODING, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_CID_MPEG_VIDEO_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, +}; + +static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc, + int ac3) +{ + int err; + + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86); + case V4L2_CID_CONTRAST: + return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); + case V4L2_CID_SATURATION: + return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); + case V4L2_CID_HUE: + return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); + case V4L2_CID_SHARPNESS: + return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); + case V4L2_CID_MPEG_AUDIO_ENCODING: + return v4l2_ctrl_query_fill( + qc, V4L2_MPEG_AUDIO_ENCODING_AAC, + ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 + : V4L2_MPEG_AUDIO_ENCODING_AAC, + 1, V4L2_MPEG_AUDIO_ENCODING_AAC); + case V4L2_CID_MPEG_VIDEO_ENCODING: + return v4l2_ctrl_query_fill( + qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, + V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); + +/* case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */ +/* return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */ + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + return v4l2_ctrl_query_fill( + qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); + + case V4L2_CID_MPEG_VIDEO_BITRATE: + return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000, + 6500000); + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000, + 9000000); + if (!err && opt->bitrate_mode == HDPVR_CONSTANT) + qc->flags |= V4L2_CTRL_FLAG_INACTIVE; + return err; + default: + return -EINVAL; + } +} + +static int vidioc_queryctrl(struct file *file, void *private_data, + struct v4l2_queryctrl *qc) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + int i, next; + u32 id = qc->id; + + memset(qc, 0, sizeof(*qc)); + + next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL); + qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL; + + for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) { + if (next) { + if (qc->id < supported_v4l2_ctrls[i]) + qc->id = supported_v4l2_ctrls[i]; + else + continue; + } + + if (qc->id == supported_v4l2_ctrls[i]) + return fill_queryctrl(&dev->options, qc, + dev->flags & HDPVR_FLAG_AC3_CAP); + + if (qc->id < supported_v4l2_ctrls[i]) + break; + } + + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *private_data, + struct v4l2_control *ctrl) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = dev->options.brightness; + break; + case V4L2_CID_CONTRAST: + ctrl->value = dev->options.contrast; + break; + case V4L2_CID_SATURATION: + ctrl->value = dev->options.saturation; + break; + case V4L2_CID_HUE: + ctrl->value = dev->options.hue; + break; + case V4L2_CID_SHARPNESS: + ctrl->value = dev->options.sharpness; + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *private_data, + struct v4l2_control *ctrl) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + int retval; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value); + if (!retval) + dev->options.brightness = ctrl->value; + break; + case V4L2_CID_CONTRAST: + retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value); + if (!retval) + dev->options.contrast = ctrl->value; + break; + case V4L2_CID_SATURATION: + retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value); + if (!retval) + dev->options.saturation = ctrl->value; + break; + case V4L2_CID_HUE: + retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value); + if (!retval) + dev->options.hue = ctrl->value; + break; + case V4L2_CID_SHARPNESS: + retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value); + if (!retval) + dev->options.sharpness = ctrl->value; + break; + default: + return -EINVAL; + } + + return retval; +} + + +static int hdpvr_get_ctrl(struct hdpvr_options *opt, + struct v4l2_ext_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_MPEG_AUDIO_ENCODING: + ctrl->value = opt->audio_codec; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC; + break; +/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ +/* ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */ +/* break; */ + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT + ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR + : V4L2_MPEG_VIDEO_BITRATE_MODE_VBR; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctrl->value = opt->bitrate * 100000; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + ctrl->value = opt->peak_bitrate * 100000; + break; + case V4L2_CID_MPEG_STREAM_TYPE: + ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_g_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *ctrls) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + int i, err = 0; + + if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + for (i = 0; i < ctrls->count; i++) { + struct v4l2_ext_control *ctrl = ctrls->controls + i; + + err = hdpvr_get_ctrl(&dev->options, ctrl); + if (err) { + ctrls->error_idx = i; + break; + } + } + return err; + + } + + return -EINVAL; +} + + +static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3) +{ + int ret = -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_MPEG_AUDIO_ENCODING: + if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC || + (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3)) + ret = 0; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC) + ret = 0; + break; +/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ +/* if (ctrl->value == 0 || ctrl->value == 128) */ +/* ret = 0; */ +/* break; */ + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR || + ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + ret = 0; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + { + uint bitrate = ctrl->value / 100000; + if (bitrate >= 10 && bitrate <= 135) + ret = 0; + break; + } + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + { + uint peak_bitrate = ctrl->value / 100000; + if (peak_bitrate >= 10 && peak_bitrate <= 202) + ret = 0; + break; + } + case V4L2_CID_MPEG_STREAM_TYPE: + if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) + ret = 0; + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_try_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *ctrls) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + int i, err = 0; + + if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + for (i = 0; i < ctrls->count; i++) { + struct v4l2_ext_control *ctrl = ctrls->controls + i; + + err = hdpvr_try_ctrl(ctrl, + dev->flags & HDPVR_FLAG_AC3_CAP); + if (err) { + ctrls->error_idx = i; + break; + } + } + return err; + } + + return -EINVAL; +} + + +static int hdpvr_set_ctrl(struct hdpvr_device *dev, + struct v4l2_ext_control *ctrl) +{ + struct hdpvr_options *opt = &dev->options; + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_MPEG_AUDIO_ENCODING: + if (dev->flags & HDPVR_FLAG_AC3_CAP) { + opt->audio_codec = ctrl->value; + ret = hdpvr_set_audio(dev, opt->audio_input, + opt->audio_codec); + } + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + break; +/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ +/* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */ +/* opt->gop_mode |= 0x2; */ +/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ +/* opt->gop_mode); */ +/* } */ +/* if (ctrl->value == 128 && opt->gop_mode & 0x2) { */ +/* opt->gop_mode &= ~0x2; */ +/* hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */ +/* opt->gop_mode); */ +/* } */ +/* break; */ + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && + opt->bitrate_mode != HDPVR_CONSTANT) { + opt->bitrate_mode = HDPVR_CONSTANT; + hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, + opt->bitrate_mode); + } + if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + opt->bitrate_mode == HDPVR_CONSTANT) { + opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE; + hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, + opt->bitrate_mode); + } + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: { + uint bitrate = ctrl->value / 100000; + + opt->bitrate = bitrate; + if (bitrate >= opt->peak_bitrate) + opt->peak_bitrate = bitrate+1; + + hdpvr_set_bitrate(dev); + break; + } + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: { + uint peak_bitrate = ctrl->value / 100000; + + if (opt->bitrate_mode == HDPVR_CONSTANT) + break; + + if (opt->bitrate < peak_bitrate) { + opt->peak_bitrate = peak_bitrate; + hdpvr_set_bitrate(dev); + } else + ret = -EINVAL; + break; + } + case V4L2_CID_MPEG_STREAM_TYPE: + break; + default: + return -EINVAL; + } + return ret; +} + +static int vidioc_s_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *ctrls) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + int i, err = 0; + + if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + for (i = 0; i < ctrls->count; i++) { + struct v4l2_ext_control *ctrl = ctrls->controls + i; + + err = hdpvr_try_ctrl(ctrl, + dev->flags & HDPVR_FLAG_AC3_CAP); + if (err) { + ctrls->error_idx = i; + break; + } + err = hdpvr_set_ctrl(dev, ctrl); + if (err) { + ctrls->error_idx = i; + break; + } + } + return err; + + } + + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, + struct v4l2_fmtdesc *f) +{ + + if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + f->flags = V4L2_FMT_FLAG_COMPRESSED; + strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32); + f->pixelformat = V4L2_PIX_FMT_MPEG; + + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data, + struct v4l2_format *f) +{ + struct hdpvr_fh *fh = file->private_data; + struct hdpvr_device *dev = fh->dev; + struct hdpvr_video_info *vid_info; + + if (!dev) + return -ENODEV; + + vid_info = get_video_info(dev); + if (!vid_info) + return -EFAULT; + + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.width = vid_info->width; + f->fmt.pix.height = vid_info->height; + f->fmt.pix.sizeimage = dev->bulk_in_size; + f->fmt.pix.colorspace = 0; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.field = V4L2_FIELD_ANY; + + kfree(vid_info); + return 0; +} + +static int vidioc_encoder_cmd(struct file *filp, void *priv, + struct v4l2_encoder_cmd *a) +{ + struct hdpvr_fh *fh = filp->private_data; + struct hdpvr_device *dev = fh->dev; + int res; + + mutex_lock(&dev->io_mutex); + + memset(&a->raw, 0, sizeof(a->raw)); + switch (a->cmd) { + case V4L2_ENC_CMD_START: + a->flags = 0; + res = hdpvr_start_streaming(dev); + break; + case V4L2_ENC_CMD_STOP: + res = hdpvr_stop_streaming(dev); + break; + default: + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "Unsupported encoder cmd %d\n", a->cmd); + res = -EINVAL; + } + mutex_unlock(&dev->io_mutex); + return res; +} + +static int vidioc_try_encoder_cmd(struct file *filp, void *priv, + struct v4l2_encoder_cmd *a) +{ + switch (a->cmd) { + case V4L2_ENC_CMD_START: + case V4L2_ENC_CMD_STOP: + return 0; + default: + return -EINVAL; + } +} + +static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_enumaudio = vidioc_enumaudio, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, + .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, + .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_encoder_cmd = vidioc_encoder_cmd, + .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, +}; + +static void hdpvr_device_release(struct video_device *vdev) +{ + struct hdpvr_device *dev = video_get_drvdata(vdev); + + hdpvr_delete(dev); + mutex_lock(&dev->io_mutex); + destroy_workqueue(dev->workqueue); + mutex_unlock(&dev->io_mutex); + + v4l2_device_unregister(&dev->v4l2_dev); + + /* deregister I2C adapter */ +#if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE) + mutex_lock(&dev->i2c_mutex); + i2c_del_adapter(&dev->i2c_adapter); + mutex_unlock(&dev->i2c_mutex); +#endif /* CONFIG_I2C */ + + kfree(dev->usbc_buf); + kfree(dev); +} + +static const struct video_device hdpvr_video_template = { +/* .type = VFL_TYPE_GRABBER, */ +/* .type2 = VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */ + .fops = &hdpvr_fops, + .release = hdpvr_device_release, + .ioctl_ops = &hdpvr_ioctl_ops, + .tvnorms = + V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_B | + V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I | + V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N | + V4L2_STD_PAL_60, + .current_norm = V4L2_STD_NTSC | V4L2_STD_PAL_M | + V4L2_STD_PAL_60, +}; + +int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, + int devnum) +{ + /* setup and register video device */ + dev->video_dev = video_device_alloc(); + if (!dev->video_dev) { + v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n"); + goto error; + } + + *(dev->video_dev) = hdpvr_video_template; + strcpy(dev->video_dev->name, "Hauppauge HD PVR"); + dev->video_dev->parent = parent; + video_set_drvdata(dev->video_dev, dev); + + if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) { + v4l2_err(&dev->v4l2_dev, "video_device registration failed\n"); + goto error; + } + + return 0; +error: + return -ENOMEM; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,10 @@ + +config VIDEO_HDPVR + tristate "Hauppauge HD PVR support" + depends on VIDEO_DEV + ---help--- + This is a video4linux driver for Hauppauge's HD PVR USB device. + + To compile this driver as a module, choose M here: the + module will be called hdpvr + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hdpvr/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,7 @@ +hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o + +obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o + +EXTRA_CFLAGS += -Idrivers/media/video + +EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hexium_gemini.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hexium_gemini.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hexium_gemini.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hexium_gemini.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,528 @@ +/* + hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards + + Visit http://www.mihu.de/linux/saa7146/ and follow the link + to "hexium" for further details about this card. + + Copyright (C) 2003 Michael Hunold + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEBUG_VARIABLE debug + +#include + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "debug verbosity"); + +/* global variables */ +static int hexium_num; + +#define HEXIUM_GEMINI 4 +#define HEXIUM_GEMINI_DUAL 5 + +#define HEXIUM_INPUTS 9 +static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = { + { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, +}; + +#define HEXIUM_AUDIOS 0 + +struct hexium_data +{ + s8 adr; + u8 byte; +}; + +#define HEXIUM_CONTROLS 1 +static struct v4l2_queryctrl hexium_controls[] = { + { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 }, +}; + +#define HEXIUM_GEMINI_V_1_0 1 +#define HEXIUM_GEMINI_DUAL_V_1_0 2 + +struct hexium +{ + int type; + + struct video_device *video_dev; + struct i2c_adapter i2c_adapter; + + int cur_input; /* current input */ + v4l2_std_id cur_std; /* current standard */ + int cur_bw; /* current black/white status */ +}; + +/* Samsung KS0127B decoder default registers */ +static u8 hexium_ks0127b[0x100]={ +/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10, +/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06, +/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00, +/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22, +/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00, +/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80, +/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00, +/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static struct hexium_data hexium_pal[] = { + { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_pal_bw[] = { + { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_ntsc[] = { + { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_ntsc_bw[] = { + { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_secam[] = { + { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } +}; + +static struct hexium_data hexium_input_select[] = { + { 0x02, 0x60 }, + { 0x02, 0x64 }, + { 0x02, 0x61 }, + { 0x02, 0x65 }, + { 0x02, 0x62 }, + { 0x02, 0x66 }, + { 0x02, 0x68 }, + { 0x02, 0x69 }, + { 0x02, 0x6A }, +}; + +/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which + are currently *not* supported*/ +static struct saa7146_standard hexium_standards[] = { + { + .name = "PAL", .id = V4L2_STD_PAL, + .v_offset = 28, .v_field = 288, + .h_offset = 1, .h_pixels = 680, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 28, .v_field = 240, + .h_offset = 1, .h_pixels = 640, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 28, .v_field = 288, + .h_offset = 1, .h_pixels = 720, + .v_max_out = 576, .h_max_out = 768, + } +}; + +/* bring hardware to a sane state. this has to be done, just in case someone + wants to capture from this device before it has been properly initialized. + the capture engine would badly fail, because no valid signal arrives on the + saa7146, thus leading to timeouts and stuff. */ +static int hexium_init_done(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + union i2c_smbus_data data; + int i = 0; + + DEB_D(("hexium_init_done called.\n")); + + /* initialize the helper ics to useful values */ + for (i = 0; i < sizeof(hexium_ks0127b); i++) { + data.byte = hexium_ks0127b[i]; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { + printk("hexium_gemini: hexium_init_done() failed for address 0x%02x\n", i); + } + } + + return 0; +} + +static int hexium_set_input(struct hexium *hexium, int input) +{ + union i2c_smbus_data data; + + DEB_D((".\n")); + + data.byte = hexium_input_select[input].byte; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) { + return -1; + } + + return 0; +} + +static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) +{ + union i2c_smbus_data data; + int i = 0; + + DEB_D((".\n")); + + while (vdec[i].adr != -1) { + data.byte = vdec[i].byte; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) { + printk("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", i); + return -1; + } + i++; + } + return 0; +} + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index >= HEXIUM_INPUTS) + return -EINVAL; + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + + if (input >= HEXIUM_INPUTS) + return -EINVAL; + + hexium->cur_input = input; + hexium_set_input(hexium, input); + return 0; +} + +/* the saa7146 provides some controls (brightness, contrast, saturation) + which gets registered *after* this function. because of this we have + to return with a value != 0 even if the function succeeded.. */ +static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == qc->id) { + *qc = hexium_controls[i]; + DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + return 0; + } + } + return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); +} + +static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) + break; + } + + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); + + if (vc->id == V4L2_CID_PRIVATE_BASE) { + vc->value = hexium->cur_bw; + DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + int i = 0; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) + break; + } + + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); + + if (vc->id == V4L2_CID_PRIVATE_BASE) + hexium->cur_bw = vc->value; + + DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); + + if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { + hexium_set_standard(hexium, hexium_secam); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) + /* fixme: is there no bw secam mode? */ + return -EINVAL; + + return -EINVAL; +} + + +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + int ret; + + DEB_EE((".\n")); + + hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); + if (NULL == hexium) { + printk("hexium_gemini: not enough kernel memory in hexium_attach().\n"); + return -ENOMEM; + } + dev->ext_priv = hexium; + + /* enable i2c-port pins */ + saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); + + hexium->i2c_adapter = (struct i2c_adapter) { + .name = "hexium gemini", + }; + saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); + if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { + DEB_S(("cannot register i2c-device. skipping.\n")); + kfree(hexium); + return -EFAULT; + } + + /* set HWControl GPIO number 2 */ + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + + saa7146_write(dev, DD1_INIT, 0x07000700); + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* the rest */ + hexium->cur_input = 0; + hexium_init_done(dev); + + hexium_set_standard(hexium, hexium_pal); + hexium->cur_std = V4L2_STD_PAL; + + hexium_set_input(hexium, 0); + hexium->cur_input = 0; + + saa7146_vv_init(dev, &vv_data); + vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; + vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; + vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; + ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER); + if (ret < 0) { + printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n"); + return ret; + } + + printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num); + hexium_num++; + + return 0; +} + +static int hexium_detach(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE(("dev:%p\n", dev)); + + saa7146_unregister_device(&hexium->video_dev, dev); + saa7146_vv_release(dev); + + hexium_num--; + + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return 0; +} + +static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + if (V4L2_STD_PAL == std->id) { + hexium_set_standard(hexium, hexium_pal); + hexium->cur_std = V4L2_STD_PAL; + return 0; + } else if (V4L2_STD_NTSC == std->id) { + hexium_set_standard(hexium, hexium_ntsc); + hexium->cur_std = V4L2_STD_NTSC; + return 0; + } else if (V4L2_STD_SECAM == std->id) { + hexium_set_standard(hexium, hexium_secam); + hexium->cur_std = V4L2_STD_SECAM; + return 0; + } + + return -1; +} + +static struct saa7146_extension hexium_extension; + +static struct saa7146_pci_extension_data hexium_gemini_4bnc = { + .ext_priv = "Hexium Gemini (4 BNC)", + .ext = &hexium_extension, +}; + +static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = { + .ext_priv = "Hexium Gemini Dual (4 BNC)", + .ext = &hexium_extension, +}; + +static struct pci_device_id pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x2401, + .driver_data = (unsigned long) &hexium_gemini_4bnc, + }, + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x2402, + .driver_data = (unsigned long) &hexium_gemini_dual_4bnc, + }, + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_ext_vv vv_data = { + .inputs = HEXIUM_INPUTS, + .capabilities = 0, + .stds = &hexium_standards[0], + .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), + .std_callback = &std_callback, +}; + +static struct saa7146_extension hexium_extension = { + .name = "hexium gemini", + .flags = SAA7146_USE_I2C_IRQ, + + .pci_tbl = &pci_tbl[0], + .module = THIS_MODULE, + + .attach = hexium_attach, + .detach = hexium_detach, + + .irq_mask = 0, + .irq_func = NULL, +}; + +static int __init hexium_init_module(void) +{ + if (0 != saa7146_register_extension(&hexium_extension)) { + DEB_S(("failed to register extension.\n")); + return -ENODEV; + } + + return 0; +} + +static void __exit hexium_cleanup_module(void) +{ + saa7146_unregister_extension(&hexium_extension); +} + +module_init(hexium_init_module); +module_exit(hexium_cleanup_module); + +MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards"); +MODULE_AUTHOR("Michael Hunold "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hexium_orion.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hexium_orion.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hexium_orion.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/hexium_orion.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,499 @@ +/* + hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards + + Visit http://www.mihu.de/linux/saa7146/ and follow the link + to "hexium" for further details about this card. + + Copyright (C) 2003 Michael Hunold + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEBUG_VARIABLE debug + +#include + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "debug verbosity"); + +/* global variables */ +static int hexium_num; + +#define HEXIUM_HV_PCI6_ORION 1 +#define HEXIUM_ORION_1SVHS_3BNC 2 +#define HEXIUM_ORION_4BNC 3 + +#define HEXIUM_INPUTS 9 +static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = { + { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, +}; + +#define HEXIUM_AUDIOS 0 + +struct hexium_data +{ + s8 adr; + u8 byte; +}; + +struct hexium +{ + int type; + struct video_device *video_dev; + struct i2c_adapter i2c_adapter; + + int cur_input; /* current input */ +}; + +/* Philips SAA7110 decoder default registers */ +static u8 hexium_saa7110[53]={ +/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00, +/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90, +/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA, +/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00, +/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F, +/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03, +/*30*/ 0x44,0x75,0x01,0x8C,0x03 +}; + +static struct { + struct hexium_data data[8]; +} hexium_input_select[] = { +{ + { /* cvbs 1 */ + { 0x06, 0x00 }, + { 0x20, 0xD9 }, + { 0x21, 0x17 }, // 0x16, + { 0x22, 0x40 }, + { 0x2C, 0x03 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, // ?? + { 0x21, 0x16 }, // 0x03, + } +}, { + { /* cvbs 2 */ + { 0x06, 0x00 }, + { 0x20, 0x78 }, + { 0x21, 0x07 }, // 0x03, + { 0x22, 0xD2 }, + { 0x2C, 0x83 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ? + { 0x21, 0x03 }, + } +}, { + { /* cvbs 3 */ + { 0x06, 0x00 }, + { 0x20, 0xBA }, + { 0x21, 0x07 }, // 0x05, + { 0x22, 0x91 }, + { 0x2C, 0x03 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ?? + { 0x21, 0x05 }, // 0x03, + } +}, { + { /* cvbs 4 */ + { 0x06, 0x00 }, + { 0x20, 0xD8 }, + { 0x21, 0x17 }, // 0x16, + { 0x22, 0x40 }, + { 0x2C, 0x03 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, // ?? + { 0x21, 0x16 }, // 0x03, + } +}, { + { /* cvbs 5 */ + { 0x06, 0x00 }, + { 0x20, 0xB8 }, + { 0x21, 0x07 }, // 0x05, + { 0x22, 0x91 }, + { 0x2C, 0x03 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ?? + { 0x21, 0x05 }, // 0x03, + } +}, { + { /* cvbs 6 */ + { 0x06, 0x00 }, + { 0x20, 0x7C }, + { 0x21, 0x07 }, // 0x03 + { 0x22, 0xD2 }, + { 0x2C, 0x83 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, // ?? + { 0x21, 0x03 }, + } +}, { + { /* y/c 1 */ + { 0x06, 0x80 }, + { 0x20, 0x59 }, + { 0x21, 0x17 }, + { 0x22, 0x42 }, + { 0x2C, 0xA3 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, + { 0x21, 0x12 }, + } +}, { + { /* y/c 2 */ + { 0x06, 0x80 }, + { 0x20, 0x9A }, + { 0x21, 0x17 }, + { 0x22, 0xB1 }, + { 0x2C, 0x13 }, + { 0x30, 0x60 }, + { 0x31, 0xB5 }, + { 0x21, 0x14 }, + } +}, { + { /* y/c 3 */ + { 0x06, 0x80 }, + { 0x20, 0x3C }, + { 0x21, 0x27 }, + { 0x22, 0xC1 }, + { 0x2C, 0x23 }, + { 0x30, 0x44 }, + { 0x31, 0x75 }, + { 0x21, 0x21 }, + } +} +}; + +static struct saa7146_standard hexium_standards[] = { + { + .name = "PAL", .id = V4L2_STD_PAL, + .v_offset = 16, .v_field = 288, + .h_offset = 1, .h_pixels = 680, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 16, .v_field = 240, + .h_offset = 1, .h_pixels = 640, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 16, .v_field = 288, + .h_offset = 1, .h_pixels = 720, + .v_max_out = 576, .h_max_out = 768, + } +}; + +/* this is only called for old HV-PCI6/Orion cards + without eeprom */ +static int hexium_probe(struct saa7146_dev *dev) +{ + struct hexium *hexium = NULL; + union i2c_smbus_data data; + int err = 0; + + DEB_EE((".\n")); + + /* there are no hexium orion cards with revision 0 saa7146s */ + if (0 == dev->revision) { + return -EFAULT; + } + + hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); + if (NULL == hexium) { + printk("hexium_orion: hexium_probe: not enough kernel memory.\n"); + return -ENOMEM; + } + + /* enable i2c-port pins */ + saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); + + saa7146_write(dev, DD1_INIT, 0x01000100); + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + hexium->i2c_adapter = (struct i2c_adapter) { + .name = "hexium orion", + }; + saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); + if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { + DEB_S(("cannot register i2c-device. skipping.\n")); + kfree(hexium); + return -EFAULT; + } + + /* set SAA7110 control GPIO 0 */ + saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI); + /* set HWControl GPIO number 2 */ + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + + mdelay(10); + + /* detect newer Hexium Orion cards by subsystem ids */ + if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) { + printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n"); + /* we store the pointer in our private data field */ + dev->ext_priv = hexium; + hexium->type = HEXIUM_ORION_1SVHS_3BNC; + return 0; + } + + if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) { + printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n"); + /* we store the pointer in our private data field */ + dev->ext_priv = hexium; + hexium->type = HEXIUM_ORION_4BNC; + return 0; + } + + /* check if this is an old hexium Orion card by looking at + a saa7110 at address 0x4e */ + if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) { + printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n"); + /* we store the pointer in our private data field */ + dev->ext_priv = hexium; + hexium->type = HEXIUM_HV_PCI6_ORION; + return 0; + } + + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return -EFAULT; +} + +/* bring hardware to a sane state. this has to be done, just in case someone + wants to capture from this device before it has been properly initialized. + the capture engine would badly fail, because no valid signal arrives on the + saa7146, thus leading to timeouts and stuff. */ +static int hexium_init_done(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + union i2c_smbus_data data; + int i = 0; + + DEB_D(("hexium_init_done called.\n")); + + /* initialize the helper ics to useful values */ + for (i = 0; i < sizeof(hexium_saa7110); i++) { + data.byte = hexium_saa7110[i]; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { + printk("hexium_orion: failed for address 0x%02x\n", i); + } + } + + return 0; +} + +static int hexium_set_input(struct hexium *hexium, int input) +{ + union i2c_smbus_data data; + int i = 0; + + DEB_D((".\n")); + + for (i = 0; i < 8; i++) { + int adr = hexium_input_select[input].data[i].adr; + data.byte = hexium_input_select[input].data[i].byte; + if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) { + return -1; + } + printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte); + } + + return 0; +} + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index >= HEXIUM_INPUTS) + return -EINVAL; + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + if (input >= HEXIUM_INPUTS) + return -EINVAL; + + hexium->cur_input = input; + hexium_set_input(hexium, input); + + return 0; +} + +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE((".\n")); + + saa7146_vv_init(dev, &vv_data); + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; + if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { + printk("hexium_orion: cannot register capture v4l2 device. skipping.\n"); + return -1; + } + + printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num); + hexium_num++; + + /* the rest */ + hexium->cur_input = 0; + hexium_init_done(dev); + + return 0; +} + +static int hexium_detach(struct saa7146_dev *dev) +{ + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE(("dev:%p\n", dev)); + + saa7146_unregister_device(&hexium->video_dev, dev); + saa7146_vv_release(dev); + + hexium_num--; + + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return 0; +} + +static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) +{ + return 0; +} + +static struct saa7146_extension extension; + +static struct saa7146_pci_extension_data hexium_hv_pci6 = { + .ext_priv = "Hexium HV-PCI6 / Orion", + .ext = &extension, +}; + +static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = { + .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)", + .ext = &extension, +}; + +static struct saa7146_pci_extension_data hexium_orion_4bnc = { + .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)", + .ext = &extension, +}; + +static struct pci_device_id pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x0000, + .subdevice = 0x0000, + .driver_data = (unsigned long) &hexium_hv_pci6, + }, + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x0101, + .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc, + }, + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x17c8, + .subdevice = 0x2101, + .driver_data = (unsigned long) &hexium_orion_4bnc, + }, + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_ext_vv vv_data = { + .inputs = HEXIUM_INPUTS, + .capabilities = 0, + .stds = &hexium_standards[0], + .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), + .std_callback = &std_callback, +}; + +static struct saa7146_extension extension = { + .name = "hexium HV-PCI6 Orion", + .flags = 0, // SAA7146_USE_I2C_IRQ, + + .pci_tbl = &pci_tbl[0], + .module = THIS_MODULE, + + .probe = hexium_probe, + .attach = hexium_attach, + .detach = hexium_detach, + + .irq_mask = 0, + .irq_func = NULL, +}; + +static int __init hexium_init_module(void) +{ + if (0 != saa7146_register_extension(&extension)) { + DEB_S(("failed to register extension.\n")); + return -ENODEV; + } + + return 0; +} + +static void __exit hexium_cleanup_module(void) +{ + saa7146_unregister_extension(&extension); +} + +module_init(hexium_init_module); +module_exit(hexium_cleanup_module); + +MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards"); +MODULE_AUTHOR("Michael Hunold "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ibmmpeg2.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ibmmpeg2.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ibmmpeg2.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ibmmpeg2.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,94 @@ +/* ibmmpeg2.h - IBM MPEGCD21 definitions */ + +#ifndef __IBM_MPEG2__ +#define __IBM_MPEG2__ + +/* Define all MPEG Decoder registers */ +/* Chip Control and Status */ +#define IBM_MP2_CHIP_CONTROL 0x200*2 +#define IBM_MP2_CHIP_MODE 0x201*2 +/* Timer Control and Status */ +#define IBM_MP2_SYNC_STC2 0x202*2 +#define IBM_MP2_SYNC_STC1 0x203*2 +#define IBM_MP2_SYNC_STC0 0x204*2 +#define IBM_MP2_SYNC_PTS2 0x205*2 +#define IBM_MP2_SYNC_PTS1 0x206*2 +#define IBM_MP2_SYNC_PTS0 0x207*2 +/* Video FIFO Control */ +#define IBM_MP2_FIFO 0x208*2 +#define IBM_MP2_FIFOW 0x100*2 +#define IBM_MP2_FIFO_STAT 0x209*2 +#define IBM_MP2_RB_THRESHOLD 0x22b*2 +/* Command buffer */ +#define IBM_MP2_COMMAND 0x20a*2 +#define IBM_MP2_CMD_DATA 0x20b*2 +#define IBM_MP2_CMD_STAT 0x20c*2 +#define IBM_MP2_CMD_ADDR 0x20d*2 +/* Internal Processor Control and Status */ +#define IBM_MP2_PROC_IADDR 0x20e*2 +#define IBM_MP2_PROC_IDATA 0x20f*2 +#define IBM_MP2_WR_PROT 0x235*2 +/* DRAM Access */ +#define IBM_MP2_DRAM_ADDR 0x210*2 +#define IBM_MP2_DRAM_DATA 0x212*2 +#define IBM_MP2_DRAM_CMD_STAT 0x213*2 +#define IBM_MP2_BLOCK_SIZE 0x23b*2 +#define IBM_MP2_SRC_ADDR 0x23c*2 +/* Onscreen Display */ +#define IBM_MP2_OSD_ADDR 0x214*2 +#define IBM_MP2_OSD_DATA 0x215*2 +#define IBM_MP2_OSD_MODE 0x217*2 +#define IBM_MP2_OSD_LINK_ADDR 0x229*2 +#define IBM_MP2_OSD_SIZE 0x22a*2 +/* Interrupt Control */ +#define IBM_MP2_HOST_INT 0x218*2 +#define IBM_MP2_MASK0 0x219*2 +#define IBM_MP2_HOST_INT1 0x23e*2 +#define IBM_MP2_MASK1 0x23f*2 +/* Audio Control */ +#define IBM_MP2_AUD_IADDR 0x21a*2 +#define IBM_MP2_AUD_IDATA 0x21b*2 +#define IBM_MP2_AUD_FIFO 0x21c*2 +#define IBM_MP2_AUD_FIFOW 0x101*2 +#define IBM_MP2_AUD_CTL 0x21d*2 +#define IBM_MP2_BEEP_CTL 0x21e*2 +#define IBM_MP2_FRNT_ATTEN 0x22d*2 +/* Display Control */ +#define IBM_MP2_DISP_MODE 0x220*2 +#define IBM_MP2_DISP_DLY 0x221*2 +#define IBM_MP2_VBI_CTL 0x222*2 +#define IBM_MP2_DISP_LBOR 0x223*2 +#define IBM_MP2_DISP_TBOR 0x224*2 +/* Polarity Control */ +#define IBM_MP2_INFC_CTL 0x22c*2 + +/* control commands */ +#define IBM_MP2_PLAY 0 +#define IBM_MP2_PAUSE 1 +#define IBM_MP2_SINGLE_FRAME 2 +#define IBM_MP2_FAST_FORWARD 3 +#define IBM_MP2_SLOW_MOTION 4 +#define IBM_MP2_IMED_NORM_PLAY 5 +#define IBM_MP2_RESET_WINDOW 6 +#define IBM_MP2_FREEZE_FRAME 7 +#define IBM_MP2_RESET_VID_RATE 8 +#define IBM_MP2_CONFIG_DECODER 9 +#define IBM_MP2_CHANNEL_SWITCH 10 +#define IBM_MP2_RESET_AUD_RATE 11 +#define IBM_MP2_PRE_OP_CHN_SW 12 +#define IBM_MP2_SET_STILL_MODE 14 + +/* Define Xilinx FPGA Internal Registers */ + +/* general control register 0 */ +#define XILINX_CTL0 0x600 +/* genlock delay resister 1 */ +#define XILINX_GLDELAY 0x602 +/* send 16 bits to CS3310 port */ +#define XILINX_CS3310 0x604 +/* send 16 bits to CS3310 and complete */ +#define XILINX_CS3310_CMPLT 0x60c +/* pulse width modulator control */ +#define XILINX_PWM 0x606 + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/imx074.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/imx074.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/imx074.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/imx074.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,505 @@ +/* + * Driver for IMX074 CMOS Image Sensor from Sony + * + * Copyright (C) 2010, Guennadi Liakhovetski + * + * Partially inspired by the IMX074 driver from the Android / MSM tree + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* IMX074 registers */ + +#define MODE_SELECT 0x0100 +#define IMAGE_ORIENTATION 0x0101 +#define GROUPED_PARAMETER_HOLD 0x0104 + +/* Integration Time */ +#define COARSE_INTEGRATION_TIME_HI 0x0202 +#define COARSE_INTEGRATION_TIME_LO 0x0203 +/* Gain */ +#define ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204 +#define ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205 + +/* PLL registers */ +#define PRE_PLL_CLK_DIV 0x0305 +#define PLL_MULTIPLIER 0x0307 +#define PLSTATIM 0x302b +#define VNDMY_ABLMGSHLMT 0x300a +#define Y_OPBADDR_START_DI 0x3014 +/* mode setting */ +#define FRAME_LENGTH_LINES_HI 0x0340 +#define FRAME_LENGTH_LINES_LO 0x0341 +#define LINE_LENGTH_PCK_HI 0x0342 +#define LINE_LENGTH_PCK_LO 0x0343 +#define YADDR_START 0x0347 +#define YADDR_END 0x034b +#define X_OUTPUT_SIZE_MSB 0x034c +#define X_OUTPUT_SIZE_LSB 0x034d +#define Y_OUTPUT_SIZE_MSB 0x034e +#define Y_OUTPUT_SIZE_LSB 0x034f +#define X_EVEN_INC 0x0381 +#define X_ODD_INC 0x0383 +#define Y_EVEN_INC 0x0385 +#define Y_ODD_INC 0x0387 + +#define HMODEADD 0x3001 +#define VMODEADD 0x3016 +#define VAPPLINE_START 0x3069 +#define VAPPLINE_END 0x306b +#define SHUTTER 0x3086 +#define HADDAVE 0x30e8 +#define LANESEL 0x3301 + +/* IMX074 supported geometry */ +#define IMX074_WIDTH 1052 +#define IMX074_HEIGHT 780 + +/* IMX074 has only one fixed colorspace per pixelcode */ +struct imx074_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +struct imx074 { + struct v4l2_subdev subdev; + const struct imx074_datafmt *fmt; +}; + +static const struct imx074_datafmt imx074_colour_fmts[] = { + {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, +}; + +static struct imx074 *to_imx074(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct imx074, subdev); +} + +/* Find a data format by a pixel code in an array */ +static const struct imx074_datafmt *imx074_find_datafmt(enum v4l2_mbus_pixelcode code) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(imx074_colour_fmts); i++) + if (imx074_colour_fmts[i].code == code) + return imx074_colour_fmts + i; + + return NULL; +} + +static int reg_write(struct i2c_client *client, const u16 addr, const u8 data) +{ + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg; + unsigned char tx[3]; + int ret; + + msg.addr = client->addr; + msg.buf = tx; + msg.len = 3; + msg.flags = 0; + + tx[0] = addr >> 8; + tx[1] = addr & 0xff; + tx[2] = data; + + ret = i2c_transfer(adap, &msg, 1); + + mdelay(2); + + return ret == 1 ? 0 : -EIO; +} + +static int reg_read(struct i2c_client *client, const u16 addr) +{ + u8 buf[2] = {addr >> 8, addr & 0xff}; + int ret; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buf, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 2, + .buf = buf, + }, + }; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) { + dev_warn(&client->dev, "Reading register %x from %x failed\n", + addr, client->addr); + return ret; + } + + return buf[0] & 0xff; /* no sign-extension */ +} + +static int imx074_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code); + + dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); + + if (!fmt) { + mf->code = imx074_colour_fmts[0].code; + mf->colorspace = imx074_colour_fmts[0].colorspace; + } + + mf->width = IMX074_WIDTH; + mf->height = IMX074_HEIGHT; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int imx074_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct imx074 *priv = to_imx074(client); + + dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); + + /* MIPI CSI could have changed the format, double-check */ + if (!imx074_find_datafmt(mf->code)) + return -EINVAL; + + imx074_try_fmt(sd, mf); + + priv->fmt = imx074_find_datafmt(mf->code); + + return 0; +} + +static int imx074_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct imx074 *priv = to_imx074(client); + + const struct imx074_datafmt *fmt = priv->fmt; + + mf->code = fmt->code; + mf->colorspace = fmt->colorspace; + mf->width = IMX074_WIDTH; + mf->height = IMX074_HEIGHT; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int imx074_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct v4l2_rect *rect = &a->c; + + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + rect->top = 0; + rect->left = 0; + rect->width = IMX074_WIDTH; + rect->height = IMX074_HEIGHT; + + return 0; +} + +static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = 0; + a->bounds.top = 0; + a->bounds.width = IMX074_WIDTH; + a->bounds.height = IMX074_HEIGHT; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts)) + return -EINVAL; + + *code = imx074_colour_fmts[index].code; + return 0; +} + +static int imx074_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* MODE_SELECT: stream or standby */ + return reg_write(client, MODE_SELECT, !!enable); +} + +static int imx074_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = V4L2_IDENT_IMX074; + id->revision = 0; + + return 0; +} + +static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { + .s_stream = imx074_s_stream, + .s_mbus_fmt = imx074_s_fmt, + .g_mbus_fmt = imx074_g_fmt, + .try_mbus_fmt = imx074_try_fmt, + .enum_mbus_fmt = imx074_enum_fmt, + .g_crop = imx074_g_crop, + .cropcap = imx074_cropcap, +}; + +static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { + .g_chip_ident = imx074_g_chip_ident, +}; + +static struct v4l2_subdev_ops imx074_subdev_ops = { + .core = &imx074_subdev_core_ops, + .video = &imx074_subdev_video_ops, +}; + +/* + * We have to provide soc-camera operations, but we don't have anything to say + * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param + */ +static unsigned long imx074_query_bus_param(struct soc_camera_device *icd) +{ + return 0; +} + +static int imx074_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return -EINVAL; +} + +static struct soc_camera_ops imx074_ops = { + .query_bus_param = imx074_query_bus_param, + .set_bus_param = imx074_set_bus_param, +}; + +static int imx074_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + int ret; + u16 id; + + /* Read sensor Model ID */ + ret = reg_read(client, 0); + if (ret < 0) + return ret; + + id = ret << 8; + + ret = reg_read(client, 1); + if (ret < 0) + return ret; + + id |= ret; + + dev_info(&client->dev, "Chip ID 0x%04x detected\n", id); + + if (id != 0x74) + return -ENODEV; + + /* PLL Setting EXTCLK=24MHz, 22.5times */ + reg_write(client, PLL_MULTIPLIER, 0x2D); + reg_write(client, PRE_PLL_CLK_DIV, 0x02); + reg_write(client, PLSTATIM, 0x4B); + + /* 2-lane mode */ + reg_write(client, 0x3024, 0x00); + + reg_write(client, IMAGE_ORIENTATION, 0x00); + + /* select RAW mode: + * 0x08+0x08 = top 8 bits + * 0x0a+0x08 = compressed 8-bits + * 0x0a+0x0a = 10 bits + */ + reg_write(client, 0x0112, 0x08); + reg_write(client, 0x0113, 0x08); + + /* Base setting for High frame mode */ + reg_write(client, VNDMY_ABLMGSHLMT, 0x80); + reg_write(client, Y_OPBADDR_START_DI, 0x08); + reg_write(client, 0x3015, 0x37); + reg_write(client, 0x301C, 0x01); + reg_write(client, 0x302C, 0x05); + reg_write(client, 0x3031, 0x26); + reg_write(client, 0x3041, 0x60); + reg_write(client, 0x3051, 0x24); + reg_write(client, 0x3053, 0x34); + reg_write(client, 0x3057, 0xC0); + reg_write(client, 0x305C, 0x09); + reg_write(client, 0x305D, 0x07); + reg_write(client, 0x3060, 0x30); + reg_write(client, 0x3065, 0x00); + reg_write(client, 0x30AA, 0x08); + reg_write(client, 0x30AB, 0x1C); + reg_write(client, 0x30B0, 0x32); + reg_write(client, 0x30B2, 0x83); + reg_write(client, 0x30D3, 0x04); + reg_write(client, 0x3106, 0x78); + reg_write(client, 0x310C, 0x82); + reg_write(client, 0x3304, 0x05); + reg_write(client, 0x3305, 0x04); + reg_write(client, 0x3306, 0x11); + reg_write(client, 0x3307, 0x02); + reg_write(client, 0x3308, 0x0C); + reg_write(client, 0x3309, 0x06); + reg_write(client, 0x330A, 0x08); + reg_write(client, 0x330B, 0x04); + reg_write(client, 0x330C, 0x08); + reg_write(client, 0x330D, 0x06); + reg_write(client, 0x330E, 0x01); + reg_write(client, 0x3381, 0x00); + + /* V : 1/2V-addition (1,3), H : 1/2H-averaging (1,3) -> Full HD */ + /* 1608 = 1560 + 48 (black lines) */ + reg_write(client, FRAME_LENGTH_LINES_HI, 0x06); + reg_write(client, FRAME_LENGTH_LINES_LO, 0x48); + reg_write(client, YADDR_START, 0x00); + reg_write(client, YADDR_END, 0x2F); + /* 0x838 == 2104 */ + reg_write(client, X_OUTPUT_SIZE_MSB, 0x08); + reg_write(client, X_OUTPUT_SIZE_LSB, 0x38); + /* 0x618 == 1560 */ + reg_write(client, Y_OUTPUT_SIZE_MSB, 0x06); + reg_write(client, Y_OUTPUT_SIZE_LSB, 0x18); + reg_write(client, X_EVEN_INC, 0x01); + reg_write(client, X_ODD_INC, 0x03); + reg_write(client, Y_EVEN_INC, 0x01); + reg_write(client, Y_ODD_INC, 0x03); + reg_write(client, HMODEADD, 0x00); + reg_write(client, VMODEADD, 0x16); + reg_write(client, VAPPLINE_START, 0x24); + reg_write(client, VAPPLINE_END, 0x53); + reg_write(client, SHUTTER, 0x00); + reg_write(client, HADDAVE, 0x80); + + reg_write(client, LANESEL, 0x00); + + reg_write(client, GROUPED_PARAMETER_HOLD, 0x00); /* off */ + + return 0; +} + +static int imx074_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct imx074 *priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + if (!icd) { + dev_err(&client->dev, "IMX074: missing soc-camera data!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "IMX074: missing platform data!\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); + return -EIO; + } + + priv = kzalloc(sizeof(struct imx074), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); + + icd->ops = &imx074_ops; + priv->fmt = &imx074_colour_fmts[0]; + + ret = imx074_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + kfree(priv); + return ret; + } + + return ret; +} + +static int imx074_remove(struct i2c_client *client) +{ + struct imx074 *priv = to_imx074(client); + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = to_soc_camera_link(icd); + + icd->ops = NULL; + if (icl->free_bus) + icl->free_bus(icl); + kfree(priv); + + return 0; +} + +static const struct i2c_device_id imx074_id[] = { + { "imx074", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, imx074_id); + +static struct i2c_driver imx074_i2c_driver = { + .driver = { + .name = "imx074", + }, + .probe = imx074_probe, + .remove = imx074_remove, + .id_table = imx074_id, +}; + +static int __init imx074_mod_init(void) +{ + return i2c_add_driver(&imx074_i2c_driver); +} + +static void __exit imx074_mod_exit(void) +{ + i2c_del_driver(&imx074_i2c_driver); +} + +module_init(imx074_mod_init); +module_exit(imx074_mod_exit); + +MODULE_DESCRIPTION("Sony IMX074 Camera driver"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/indycam.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/indycam.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/indycam.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/indycam.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,400 @@ +/* + * indycam.c - Silicon Graphics IndyCam digital camera driver + * + * Copyright (C) 2003 Ladislav Michl + * Copyright (C) 2004,2005 Mikael Nousiainen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* IndyCam decodes stream of photons into digital image representation ;-) */ +#include +#include +#include +#include + +#include "indycam.h" + +#define INDYCAM_MODULE_VERSION "0.0.5" + +MODULE_DESCRIPTION("SGI IndyCam driver"); +MODULE_AUTHOR("Mikael Nousiainen "); +MODULE_LICENSE("GPL"); + + +// #define INDYCAM_DEBUG + +#ifdef INDYCAM_DEBUG +#define dprintk(x...) printk("IndyCam: " x); +#define indycam_regdump(client) indycam_regdump_debug(client) +#else +#define dprintk(x...) +#define indycam_regdump(client) +#endif + +struct indycam { + struct v4l2_subdev sd; + u8 version; +}; + +static inline struct indycam *to_indycam(struct v4l2_subdev *sd) +{ + return container_of(sd, struct indycam, sd); +} + +static const u8 initseq[] = { + INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */ + INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */ + INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */ + 0x00, /* INDYCAM_BRIGHTNESS (read-only) */ + INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */ + INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */ + INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */ + INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */ +}; + +/* IndyCam register handling */ + +static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (reg == INDYCAM_REG_RESET) { + dprintk("indycam_read_reg(): " + "skipping write-only register %d\n", reg); + *value = 0; + return 0; + } + + ret = i2c_smbus_read_byte_data(client, reg); + + if (ret < 0) { + printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, " + "register = 0x%02x\n", reg); + return ret; + } + + *value = (u8)ret; + + return 0; +} + +static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int err; + + if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) { + dprintk("indycam_write_reg(): " + "skipping read-only register %d\n", reg); + return 0; + } + + dprintk("Writing Reg %d = 0x%02x\n", reg, value); + err = i2c_smbus_write_byte_data(client, reg, value); + + if (err) { + printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, " + "register = 0x%02x, value = 0x%02x\n", reg, value); + } + return err; +} + +static int indycam_write_block(struct v4l2_subdev *sd, u8 reg, + u8 length, u8 *data) +{ + int i, err; + + for (i = 0; i < length; i++) { + err = indycam_write_reg(sd, reg + i, data[i]); + if (err) + return err; + } + + return 0; +} + +/* Helper functions */ + +#ifdef INDYCAM_DEBUG +static void indycam_regdump_debug(struct v4l2_subdev *sd) +{ + int i; + u8 val; + + for (i = 0; i < 9; i++) { + indycam_read_reg(sd, i, &val); + dprintk("Reg %d = 0x%02x\n", i, val); + } +} +#endif + +static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct indycam *camera = to_indycam(sd); + u8 reg; + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + case V4L2_CID_AUTO_WHITE_BALANCE: + ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, ®); + if (ret) + return -EIO; + if (ctrl->id == V4L2_CID_AUTOGAIN) + ctrl->value = (reg & INDYCAM_CONTROL_AGCENA) + ? 1 : 0; + else + ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL) + ? 1 : 0; + break; + case V4L2_CID_EXPOSURE: + ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, ®); + if (ret) + return -EIO; + ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1); + break; + case V4L2_CID_GAIN: + ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case V4L2_CID_RED_BALANCE: + ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case V4L2_CID_BLUE_BALANCE: + ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case INDYCAM_CONTROL_RED_SATURATION: + ret = indycam_read_reg(sd, + INDYCAM_REG_RED_SATURATION, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case INDYCAM_CONTROL_BLUE_SATURATION: + ret = indycam_read_reg(sd, + INDYCAM_REG_BLUE_SATURATION, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case V4L2_CID_GAMMA: + if (camera->version == CAMERA_VERSION_MOOSE) { + ret = indycam_read_reg(sd, + INDYCAM_REG_GAMMA, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + } else { + ctrl->value = INDYCAM_GAMMA_DEFAULT; + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct indycam *camera = to_indycam(sd); + u8 reg; + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + case V4L2_CID_AUTO_WHITE_BALANCE: + ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, ®); + if (ret) + break; + + if (ctrl->id == V4L2_CID_AUTOGAIN) { + if (ctrl->value) + reg |= INDYCAM_CONTROL_AGCENA; + else + reg &= ~INDYCAM_CONTROL_AGCENA; + } else { + if (ctrl->value) + reg |= INDYCAM_CONTROL_AWBCTL; + else + reg &= ~INDYCAM_CONTROL_AWBCTL; + } + + ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg); + break; + case V4L2_CID_EXPOSURE: + reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1); + ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg); + break; + case V4L2_CID_GAIN: + ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value); + break; + case V4L2_CID_RED_BALANCE: + ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE, + ctrl->value); + break; + case V4L2_CID_BLUE_BALANCE: + ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE, + ctrl->value); + break; + case INDYCAM_CONTROL_RED_SATURATION: + ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION, + ctrl->value); + break; + case INDYCAM_CONTROL_BLUE_SATURATION: + ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION, + ctrl->value); + break; + case V4L2_CID_GAMMA: + if (camera->version == CAMERA_VERSION_MOOSE) { + ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA, + ctrl->value); + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + +/* I2C-interface */ + +static int indycam_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct indycam *camera = to_indycam(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_INDYCAM, + camera->version); +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops indycam_core_ops = { + .g_chip_ident = indycam_g_chip_ident, + .g_ctrl = indycam_g_ctrl, + .s_ctrl = indycam_s_ctrl, +}; + +static const struct v4l2_subdev_ops indycam_ops = { + .core = &indycam_core_ops, +}; + +static int indycam_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + struct indycam *camera; + struct v4l2_subdev *sd; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + camera = kzalloc(sizeof(struct indycam), GFP_KERNEL); + if (!camera) + return -ENOMEM; + + sd = &camera->sd; + v4l2_i2c_subdev_init(sd, client, &indycam_ops); + + camera->version = i2c_smbus_read_byte_data(client, + INDYCAM_REG_VERSION); + if (camera->version != CAMERA_VERSION_INDY && + camera->version != CAMERA_VERSION_MOOSE) { + kfree(camera); + return -ENODEV; + } + + printk(KERN_INFO "IndyCam v%d.%d detected\n", + INDYCAM_VERSION_MAJOR(camera->version), + INDYCAM_VERSION_MINOR(camera->version)); + + indycam_regdump(sd); + + // initialize + err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq); + if (err) { + printk(KERN_ERR "IndyCam initialization failed\n"); + kfree(camera); + return -EIO; + } + + indycam_regdump(sd); + + // white balance + err = indycam_write_reg(sd, INDYCAM_REG_CONTROL, + INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL); + if (err) { + printk(KERN_ERR "IndyCam: White balancing camera failed\n"); + kfree(camera); + return -EIO; + } + + indycam_regdump(sd); + + printk(KERN_INFO "IndyCam initialized\n"); + + return 0; +} + +static int indycam_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_indycam(sd)); + return 0; +} + +static const struct i2c_device_id indycam_id[] = { + { "indycam", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, indycam_id); + +static struct i2c_driver indycam_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "indycam", + }, + .probe = indycam_probe, + .remove = indycam_remove, + .id_table = indycam_id, +}; + +static __init int init_indycam(void) +{ + return i2c_add_driver(&indycam_driver); +} + +static __exit void exit_indycam(void) +{ + i2c_del_driver(&indycam_driver); +} + +module_init(init_indycam); +module_exit(exit_indycam); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/indycam.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/indycam.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/indycam.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/indycam.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * indycam.h - Silicon Graphics IndyCam digital camera driver + * + * Copyright (C) 2003 Ladislav Michl + * Copyright (C) 2004,2005 Mikael Nousiainen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _INDYCAM_H_ +#define _INDYCAM_H_ + +/* I2C address for the Guinness Camera */ +#define INDYCAM_ADDR 0x56 + +/* Camera version */ +#define CAMERA_VERSION_INDY 0x10 /* v1.0 */ +#define CAMERA_VERSION_MOOSE 0x12 /* v1.2 */ +#define INDYCAM_VERSION_MAJOR(x) (((x) & 0xf0) >> 4) +#define INDYCAM_VERSION_MINOR(x) ((x) & 0x0f) + +/* Register bus addresses */ +#define INDYCAM_REG_CONTROL 0x00 +#define INDYCAM_REG_SHUTTER 0x01 +#define INDYCAM_REG_GAIN 0x02 +#define INDYCAM_REG_BRIGHTNESS 0x03 /* read-only */ +#define INDYCAM_REG_RED_BALANCE 0x04 +#define INDYCAM_REG_BLUE_BALANCE 0x05 +#define INDYCAM_REG_RED_SATURATION 0x06 +#define INDYCAM_REG_BLUE_SATURATION 0x07 +#define INDYCAM_REG_GAMMA 0x08 +#define INDYCAM_REG_VERSION 0x0e /* read-only */ +#define INDYCAM_REG_RESET 0x0f /* write-only */ + +#define INDYCAM_REG_LED 0x46 +#define INDYCAM_REG_ORIENTATION 0x47 +#define INDYCAM_REG_BUTTON 0x48 + +/* Field definitions of registers */ +#define INDYCAM_CONTROL_AGCENA (1<<0) /* automatic gain control */ +#define INDYCAM_CONTROL_AWBCTL (1<<1) /* automatic white balance */ + /* 2-3 are reserved */ +#define INDYCAM_CONTROL_EVNFLD (1<<4) /* read-only */ + +#define INDYCAM_SHUTTER_10000 0x02 /* 1/10000 second */ +#define INDYCAM_SHUTTER_4000 0x04 /* 1/4000 second */ +#define INDYCAM_SHUTTER_2000 0x08 /* 1/2000 second */ +#define INDYCAM_SHUTTER_1000 0x10 /* 1/1000 second */ +#define INDYCAM_SHUTTER_500 0x20 /* 1/500 second */ +#define INDYCAM_SHUTTER_250 0x3f /* 1/250 second */ +#define INDYCAM_SHUTTER_125 0x7e /* 1/125 second */ +#define INDYCAM_SHUTTER_100 0x9e /* 1/100 second */ +#define INDYCAM_SHUTTER_60 0x00 /* 1/60 second */ + +#define INDYCAM_LED_ACTIVE 0x10 +#define INDYCAM_LED_INACTIVE 0x30 +#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP 0x40 +#define INDYCAM_BUTTON_RELEASED 0x10 + +/* Values for controls */ +#define INDYCAM_SHUTTER_MIN 0x00 +#define INDYCAM_SHUTTER_MAX 0xff +#define INDYCAM_GAIN_MIN 0x00 +#define INDYCAM_GAIN_MAX 0xff +#define INDYCAM_RED_BALANCE_MIN 0x00 +#define INDYCAM_RED_BALANCE_MAX 0xff +#define INDYCAM_BLUE_BALANCE_MIN 0x00 +#define INDYCAM_BLUE_BALANCE_MAX 0xff +#define INDYCAM_RED_SATURATION_MIN 0x00 +#define INDYCAM_RED_SATURATION_MAX 0xff +#define INDYCAM_BLUE_SATURATION_MIN 0x00 +#define INDYCAM_BLUE_SATURATION_MAX 0xff +#define INDYCAM_GAMMA_MIN 0x00 +#define INDYCAM_GAMMA_MAX 0xff + +#define INDYCAM_AGC_DEFAULT 1 +#define INDYCAM_AWB_DEFAULT 0 +#define INDYCAM_SHUTTER_DEFAULT 0xff +#define INDYCAM_GAIN_DEFAULT 0x80 +#define INDYCAM_RED_BALANCE_DEFAULT 0x18 +#define INDYCAM_BLUE_BALANCE_DEFAULT 0xa4 +#define INDYCAM_RED_SATURATION_DEFAULT 0x80 +#define INDYCAM_BLUE_SATURATION_DEFAULT 0xc0 +#define INDYCAM_GAMMA_DEFAULT 0x80 + +/* Driver interface definitions */ + +#define INDYCAM_CONTROL_RED_SATURATION (V4L2_CID_PRIVATE_BASE + 0) +#define INDYCAM_CONTROL_BLUE_SATURATION (V4L2_CID_PRIVATE_BASE + 1) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ir-kbd-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ir-kbd-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ir-kbd-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ir-kbd-i2c.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,499 @@ +/* + * + * keyboard input driver for i2c IR remote controls + * + * Copyright (c) 2000-2003 Gerd Knorr + * modified for PixelView (BT878P+W/FM) by + * Michal Kochanowicz + * Christoph Bartelmus + * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by + * Ulrich Mueller + * modified for em2820 based USB TV tuners by + * Markus Rechberger + * modified for DViCO Fusion HDTV 5 RT GOLD by + * Chaogui Zhang + * modified for MSI TV@nywhere Plus by + * Henry Wong + * Mark Schultz + * Brian Rogers + * modified for AVerMedia Cardbus by + * Oldrich Jedlicka + * + * 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, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* ----------------------------------------------------------------------- */ +/* insmod parameters */ + +static int debug; +module_param(debug, int, 0644); /* debug level (0,1,2) */ + + +#define MODULE_NAME "ir-kbd-i2c" +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG MODULE_NAME ": " fmt , ## arg) + +/* ----------------------------------------------------------------------- */ + +static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, + int size, int offset) +{ + unsigned char buf[6]; + int start, range, toggle, dev, code, ircode; + + /* poll IR chip */ + if (size != i2c_master_recv(ir->c, buf, size)) + return -EIO; + + /* split rc5 data block ... */ + start = (buf[offset] >> 7) & 1; + range = (buf[offset] >> 6) & 1; + toggle = (buf[offset] >> 5) & 1; + dev = buf[offset] & 0x1f; + code = (buf[offset+1] >> 2) & 0x3f; + + /* rc5 has two start bits + * the first bit must be one + * the second bit defines the command range (1 = 0-63, 0 = 64 - 127) + */ + if (!start) + /* no key pressed */ + return 0; + /* + * Hauppauge remotes (black/silver) always use + * specific device ids. If we do not filter the + * device ids then messages destined for devices + * such as TVs (id=0) will get through causing + * mis-fired events. + * + * We also filter out invalid key presses which + * produce annoying debug log entries. + */ + ircode= (start << 12) | (toggle << 11) | (dev << 6) | code; + if ((ircode & 0x1fff)==0x1fff) + /* invalid key press */ + return 0; + + if (!range) + code += 64; + + dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", + start, range, toggle, dev, code); + + /* return key */ + *ir_key = (dev << 8) | code; + *ir_raw = ircode; + return 1; +} + +static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + return get_key_haup_common (ir, ir_key, ir_raw, 3, 0); +} + +static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + int ret; + unsigned char buf[1] = { 0 }; + + /* + * This is the same apparent "are you ready?" poll command observed + * watching Windows driver traffic and implemented in lirc_zilog. With + * this added, we get far saner remote behavior with z8 chips on usb + * connected devices, even with the default polling interval of 100ms. + */ + ret = i2c_master_send(ir->c, buf, 1); + if (ret != 1) + return (ret < 0) ? ret : -EINVAL; + + return get_key_haup_common (ir, ir_key, ir_raw, 6, 3); +} + +static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b; + + /* poll IR chip */ + if (1 != i2c_master_recv(ir->c, &b, 1)) { + dprintk(1,"read error\n"); + return -EIO; + } + *ir_key = b; + *ir_raw = b; + return 1; +} + +static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char buf[4]; + + /* poll IR chip */ + if (4 != i2c_master_recv(ir->c, buf, 4)) { + dprintk(1,"read error\n"); + return -EIO; + } + + if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) + dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__, + buf[0], buf[1], buf[2], buf[3]); + + /* no key pressed or signal from other ir remote */ + if(buf[0] != 0x1 || buf[1] != 0xfe) + return 0; + + *ir_key = buf[2]; + *ir_raw = (buf[2] << 8) | buf[3]; + + return 1; +} + +static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b; + + /* poll IR chip */ + if (1 != i2c_master_recv(ir->c, &b, 1)) { + dprintk(1,"read error\n"); + return -EIO; + } + + /* it seems that 0xFE indicates that a button is still hold + down, while 0xff indicates that no button is hold + down. 0xfe sequences are sometimes interrupted by 0xFF */ + + dprintk(2,"key %02x\n", b); + + if (b == 0xff) + return 0; + + if (b == 0xfe) + /* keep old data */ + return 1; + + *ir_key = b; + *ir_raw = b; + return 1; +} + +static int get_key_avermedia_cardbus(struct IR_i2c *ir, + u32 *ir_key, u32 *ir_raw) +{ + unsigned char subaddr, key, keygroup; + struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, + .buf = &subaddr, .len = 1}, + { .addr = ir->c->addr, .flags = I2C_M_RD, + .buf = &key, .len = 1} }; + subaddr = 0x0d; + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { + dprintk(1, "read error\n"); + return -EIO; + } + + if (key == 0xff) + return 0; + + subaddr = 0x0b; + msg[1].buf = &keygroup; + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { + dprintk(1, "read error\n"); + return -EIO; + } + + if (keygroup == 0xff) + return 0; + + dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup); + if (keygroup < 2 || keygroup > 3) { + /* Only a warning */ + dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n", + keygroup, key); + } + key |= (keygroup & 1) << 6; + + *ir_key = key; + *ir_raw = key; + return 1; +} + +/* ----------------------------------------------------------------------- */ + +static void ir_key_poll(struct IR_i2c *ir) +{ + static u32 ir_key, ir_raw; + int rc; + + dprintk(3, "%s\n", __func__); + rc = ir->get_key(ir, &ir_key, &ir_raw); + if (rc < 0) { + dprintk(2,"error\n"); + return; + } + + if (rc) { + dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key); + rc_keydown(ir->rc, ir_key, 0); + } +} + +static void ir_work(struct work_struct *work) +{ + struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); + + ir_key_poll(ir); + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); +} + +/* ----------------------------------------------------------------------- */ + +static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + char *ir_codes = NULL; + const char *name = NULL; + u64 rc_type = RC_TYPE_UNKNOWN; + struct IR_i2c *ir; + struct rc_dev *rc = NULL; + struct i2c_adapter *adap = client->adapter; + unsigned short addr = client->addr; + int err; + + ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + ir->c = client; + ir->polling_interval = DEFAULT_POLLING_INTERVAL; + i2c_set_clientdata(client, ir); + + switch(addr) { + case 0x64: + name = "Pixelview"; + ir->get_key = get_key_pixelview; + rc_type = RC_TYPE_OTHER; + ir_codes = RC_MAP_EMPTY; + break; + case 0x18: + case 0x1f: + case 0x1a: + name = "Hauppauge"; + ir->get_key = get_key_haup; + rc_type = RC_TYPE_RC5; + ir_codes = RC_MAP_HAUPPAUGE; + break; + case 0x30: + name = "KNC One"; + ir->get_key = get_key_knc1; + rc_type = RC_TYPE_OTHER; + ir_codes = RC_MAP_EMPTY; + break; + case 0x6b: + name = "FusionHDTV"; + ir->get_key = get_key_fusionhdtv; + rc_type = RC_TYPE_RC5; + ir_codes = RC_MAP_FUSIONHDTV_MCE; + break; + case 0x40: + name = "AVerMedia Cardbus remote"; + ir->get_key = get_key_avermedia_cardbus; + rc_type = RC_TYPE_OTHER; + ir_codes = RC_MAP_AVERMEDIA_CARDBUS; + break; + case 0x71: + name = "Hauppauge/Zilog Z8"; + ir->get_key = get_key_haup_xvr; + rc_type = RC_TYPE_RC5; + ir_codes = RC_MAP_HAUPPAUGE; + break; + } + + /* Let the caller override settings */ + if (client->dev.platform_data) { + const struct IR_i2c_init_data *init_data = + client->dev.platform_data; + + ir_codes = init_data->ir_codes; + rc = init_data->rc_dev; + + name = init_data->name; + if (init_data->type) + rc_type = init_data->type; + + if (init_data->polling_interval) + ir->polling_interval = init_data->polling_interval; + + switch (init_data->internal_get_key_func) { + case IR_KBD_GET_KEY_CUSTOM: + /* The bridge driver provided us its own function */ + ir->get_key = init_data->get_key; + break; + case IR_KBD_GET_KEY_PIXELVIEW: + ir->get_key = get_key_pixelview; + break; + case IR_KBD_GET_KEY_HAUP: + ir->get_key = get_key_haup; + break; + case IR_KBD_GET_KEY_KNC1: + ir->get_key = get_key_knc1; + break; + case IR_KBD_GET_KEY_FUSIONHDTV: + ir->get_key = get_key_fusionhdtv; + break; + case IR_KBD_GET_KEY_HAUP_XVR: + ir->get_key = get_key_haup_xvr; + break; + case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS: + ir->get_key = get_key_avermedia_cardbus; + break; + } + } + + if (!rc) { + /* + * If platform_data doesn't specify rc_dev, initilize it + * internally + */ + rc = rc_allocate_device(); + if (!rc) { + err = -ENOMEM; + goto err_out_free; + } + } + ir->rc = rc; + + /* Make sure we are all setup before going on */ + if (!name || !ir->get_key || !rc_type || !ir_codes) { + dprintk(1, ": Unsupported device at address 0x%02x\n", + addr); + err = -ENODEV; + goto err_out_free; + } + + /* Sets name */ + snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name); + ir->ir_codes = ir_codes; + + snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", + dev_name(&adap->dev), + dev_name(&client->dev)); + + /* + * Initialize input_dev fields + * It doesn't make sense to allow overriding them via platform_data + */ + rc->input_id.bustype = BUS_I2C; + rc->input_phys = ir->phys; + rc->input_name = ir->name; + + /* + * Initialize the other fields of rc_dev + */ + rc->map_name = ir->ir_codes; + rc->allowed_protos = rc_type; + if (!rc->driver_name) + rc->driver_name = MODULE_NAME; + + err = rc_register_device(rc); + if (err) + goto err_out_free; + + printk(MODULE_NAME ": %s detected at %s [%s]\n", + ir->name, ir->phys, adap->name); + + /* start polling via eventd */ + INIT_DELAYED_WORK(&ir->work, ir_work); + schedule_delayed_work(&ir->work, 0); + + return 0; + + err_out_free: + /* Only frees rc if it were allocated internally */ + rc_free_device(rc); + kfree(ir); + return err; +} + +static int ir_remove(struct i2c_client *client) +{ + struct IR_i2c *ir = i2c_get_clientdata(client); + + /* kill outstanding polls */ + cancel_delayed_work_sync(&ir->work); + + /* unregister device */ + rc_unregister_device(ir->rc); + + /* free memory */ + kfree(ir); + return 0; +} + +static const struct i2c_device_id ir_kbd_id[] = { + /* Generic entry for any IR receiver */ + { "ir_video", 0 }, + /* IR device specific entries should be added here */ + { "ir_rx_z8f0811_haup", 0 }, + { "ir_rx_z8f0811_hdpvr", 0 }, + { } +}; + +static struct i2c_driver driver = { + .driver = { + .name = "ir-kbd-i2c", + }, + .probe = ir_probe, + .remove = ir_remove, + .id_table = ir_kbd_id, +}; + +/* ----------------------------------------------------------------------- */ + +MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); +MODULE_DESCRIPTION("input driver for i2c IR remote controls"); +MODULE_LICENSE("GPL"); + +static int __init ir_init(void) +{ + return i2c_add_driver(&driver); +} + +static void __exit ir_fini(void) +{ + i2c_del_driver(&driver); +} + +module_init(ir_init); +module_exit(ir_fini); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-cards.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-cards.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-cards.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-cards.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1370 @@ +/* + Functions to query card hardware + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-cards.h" +#include "ivtv-i2c.h" + +#include +#include +#include +#include +#include +#include + +#define MSP_TUNER MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ + MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER) +#define MSP_SCART1 MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) +#define MSP_SCART2 MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, \ + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) +#define MSP_SCART3 MSP_INPUT(MSP_IN_SCART3, MSP_IN_TUNER1, \ + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) +#define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) + +#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM) + +/* usual i2c tuner addresses to probe */ +static struct ivtv_card_tuner_i2c ivtv_i2c_std = { + .radio = { I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, 0x60, I2C_CLIENT_END }, +}; + +/* as above, but with possible radio tuner */ +static struct ivtv_card_tuner_i2c ivtv_i2c_radio = { + .radio = { 0x60, I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, I2C_CLIENT_END }, +}; + +/* using the tda8290+75a combo */ +static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = { + .radio = { I2C_CLIENT_END }, + .demod = { I2C_CLIENT_END }, + .tv = { 0x4b, I2C_CLIENT_END }, +}; + +/********************** card configuration *******************************/ + +/* Please add new PCI IDs to: http://pci-ids.ucw.cz/ + This keeps the PCI ID database up to date. Note that the entries + must be added under vendor 0x4444 (Conexant) as subsystem IDs. + New vendor IDs should still be added to the vendor ID list. */ + +/* Hauppauge PVR-250 cards */ + +/* Note: for Hauppauge cards the tveeprom information is used instead of PCI IDs */ +static const struct ivtv_card ivtv_card_pvr250 = { + .type = IVTV_CARD_PVR_250, + .name = "Hauppauge WinTV PVR-250", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7115, + .hw_audio = IVTV_HW_MSP34XX, + .hw_audio_ctrl = IVTV_HW_MSP34XX, + .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | + IVTV_HW_TVEEPROM | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, + { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, + { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, + { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, + { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Hauppauge PVR-350 cards */ + +/* Outputs for Hauppauge PVR350 cards */ +static struct ivtv_card_output ivtv_pvr350_outputs[] = { + { + .name = "S-Video + Composite", + .video_output = 0, + }, { + .name = "Composite", + .video_output = 1, + }, { + .name = "S-Video", + .video_output = 2, + }, { + .name = "RGB", + .video_output = 3, + }, { + .name = "YUV C", + .video_output = 4, + }, { + .name = "YUV V", + .video_output = 5, + } +}; + +static const struct ivtv_card ivtv_card_pvr350 = { + .type = IVTV_CARD_PVR_350, + .name = "Hauppauge WinTV PVR-350", + .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, + .video_outputs = ivtv_pvr350_outputs, + .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), + .hw_video = IVTV_HW_SAA7115, + .hw_audio = IVTV_HW_MSP34XX, + .hw_audio_ctrl = IVTV_HW_MSP34XX, + .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | + IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER | + IVTV_HW_I2C_IR_RX_HAUP_EXT | IVTV_HW_I2C_IR_RX_HAUP_INT, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, + { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, + { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, + { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, + { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, + .i2c = &ivtv_i2c_std, +}; + +/* PVR-350 V1 boards have a different audio tuner input and use a + saa7114 instead of a saa7115. + Note that the info below comes from a pre-production model so it may + not be correct. Especially the audio behaves strangely (mono only it seems) */ +static const struct ivtv_card ivtv_card_pvr350_v1 = { + .type = IVTV_CARD_PVR_350_V1, + .name = "Hauppauge WinTV PVR-350 (V1)", + .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, + .video_outputs = ivtv_pvr350_outputs, + .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), + .hw_video = IVTV_HW_SAA7114, + .hw_audio = IVTV_HW_MSP34XX, + .hw_audio_ctrl = IVTV_HW_MSP34XX, + .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7114 | + IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, + { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, + { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, + { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, MSP_MONO }, + { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, + { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Hauppauge PVR-150/PVR-500 cards */ + +static const struct ivtv_card ivtv_card_pvr150 = { + .type = IVTV_CARD_PVR_150, + .name = "Hauppauge WinTV PVR-150", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_WM8775, + .hw_all = IVTV_HW_WM8775 | IVTV_HW_CX25840 | + IVTV_HW_TVEEPROM | IVTV_HW_TUNER | + IVTV_HW_I2C_IR_RX_HAUP_EXT | IVTV_HW_I2C_IR_RX_HAUP_INT | + IVTV_HW_Z8F0811_IR_HAUP, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE7 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO1 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, + { IVTV_CARD_INPUT_SVIDEO2, 2, CX25840_SVIDEO2 }, + { IVTV_CARD_INPUT_COMPOSITE2, 2, CX25840_COMPOSITE4 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, + CX25840_AUDIO8, WM8775_AIN2 }, + { IVTV_CARD_INPUT_LINE_IN1, + CX25840_AUDIO_SERIAL, WM8775_AIN2 }, + { IVTV_CARD_INPUT_LINE_IN2, + CX25840_AUDIO_SERIAL, WM8775_AIN3 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, + CX25840_AUDIO_SERIAL, WM8775_AIN4 }, + /* apparently needed for the IR blaster */ + .gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 }, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerMedia M179 cards */ + +static const struct ivtv_card_pci_info ivtv_pci_m179[] = { + { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3cf }, + { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3ce }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_m179 = { + .type = IVTV_CARD_M179, + .name = "AVerMedia M179", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7114, + .hw_audio = IVTV_HW_GPIO, + .hw_audio_ctrl = IVTV_HW_GPIO, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, + }, + .gpio_init = { .direction = 0xe380, .initial_value = 0x8290 }, + .gpio_audio_input = { .mask = 0x8040, .tuner = 0x8000, .linein = 0x0000 }, + .gpio_audio_mute = { .mask = 0x2000, .mute = 0x2000 }, + .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, + .lang1 = 0x0200, .lang2 = 0x0100, .both = 0x0000 }, + .gpio_audio_freq = { .mask = 0x0018, .f32000 = 0x0000, + .f44100 = 0x0008, .f48000 = 0x0010 }, + .gpio_audio_detect = { .mask = 0x4000, .stereo = 0x0000 }, + .tuners = { + /* As far as we know all M179 cards use this tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC }, + }, + .pci_list = ivtv_pci_m179, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan MPG600/Kuroutoshikou ITVC16-STVLP cards */ + +static const struct ivtv_card_pci_info ivtv_pci_mpg600[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xfff3 }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xffff }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_mpg600 = { + .type = IVTV_CARD_MPG600, + .name = "Yuan MPG600, Kuroutoshikou ITVC16-STVLP", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7115, + .hw_audio = IVTV_HW_GPIO, + .hw_audio_ctrl = IVTV_HW_GPIO, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, + }, + .gpio_init = { .direction = 0x3080, .initial_value = 0x0004 }, + .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, + .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, + .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, + .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, + .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, + .tuners = { + /* The PAL tuner is confirmed */ + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, + }, + .pci_list = ivtv_pci_mpg600, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan MPG160/Kuroutoshikou ITVC15-STVLP cards */ + +static const struct ivtv_card_pci_info ivtv_pci_mpg160[] = { + { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_YUAN1, 0 }, + { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_IODATA, 0x40a0 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_mpg160 = { + .type = IVTV_CARD_MPG160, + .name = "YUAN MPG160, Kuroutoshikou ITVC15-STVLP, I/O Data GV-M2TV/PCI", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7114, + .hw_audio = IVTV_HW_GPIO, + .hw_audio_ctrl = IVTV_HW_GPIO, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, + }, + .gpio_init = { .direction = 0x7080, .initial_value = 0x400c }, + .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, + .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, + .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, + .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, + .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, + .tuners = { + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, + }, + .pci_list = ivtv_pci_mpg160, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan PG600/Diamond PVR-550 cards */ + +static const struct ivtv_card_pci_info ivtv_pci_pg600[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_DIAMONDMM, 0x0070 }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_pg600 = { + .type = IVTV_CARD_PG600, + .name = "Yuan PG600, Diamond PVR-550", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, + }, + .tuners = { + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, + }, + .pci_list = ivtv_pci_pg600, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Adaptec VideOh! AVC-2410 card */ + +static const struct ivtv_card_pci_info ivtv_pci_avc2410[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0093 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_avc2410 = { + .type = IVTV_CARD_AVC2410, + .name = "Adaptec VideOh! AVC-2410", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7115, + .hw_audio = IVTV_HW_MSP34XX, + .hw_audio_ctrl = IVTV_HW_MSP34XX, + .hw_muxer = IVTV_HW_CS53L32A, + .hw_all = IVTV_HW_MSP34XX | IVTV_HW_CS53L32A | + IVTV_HW_SAA7115 | IVTV_HW_TUNER | + IVTV_HW_I2C_IR_RX_ADAPTEC, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, + MSP_TUNER, CS53L32A_IN0 }, + { IVTV_CARD_INPUT_LINE_IN1, + MSP_SCART1, CS53L32A_IN2 }, + }, + /* This card has no eeprom and in fact the Windows driver relies + on the country/region setting of the user to decide which tuner + is available. */ + .tuners = { + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP, + .tuner = TUNER_PHILIPS_FM1236_MK3 }, + { .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 }, + }, + .pci_list = ivtv_pci_avc2410, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Adaptec VideOh! AVC-2010 card */ + +static const struct ivtv_card_pci_info ivtv_pci_avc2010[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0092 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_avc2010 = { + .type = IVTV_CARD_AVC2010, + .name = "Adaptec VideOh! AVC-2010", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7115, + .hw_audio = IVTV_HW_CS53L32A, + .hw_audio_ctrl = IVTV_HW_CS53L32A, + .hw_all = IVTV_HW_CS53L32A | IVTV_HW_SAA7115, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, IVTV_SAA71XX_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CS53L32A_IN2 }, + }, + /* Does not have a tuner */ + .pci_list = ivtv_pci_avc2010, +}; + +/* ------------------------------------------------------------------------- */ + +/* Nagase Transgear 5000TV card */ + +static const struct ivtv_card_pci_info ivtv_pci_tg5000tv[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_tg5000tv = { + .type = IVTV_CARD_TG5000TV, + .name = "Nagase Transgear 5000TV", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7114 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | + IVTV_HW_GPIO, + .hw_audio = IVTV_HW_GPIO, + .hw_audio_ctrl = IVTV_HW_GPIO, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER | + IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, + }, + .gr_config = UPD64031A_VERTICAL_EXTERNAL, + .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, + .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, + .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, + .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, + .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, + .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, + .composite = 0x0010, .svideo = 0x0020 }, + .tuners = { + { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, + }, + .pci_list = ivtv_pci_tg5000tv, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* AOpen VA2000MAX-SNT6 card */ + +static const struct ivtv_card_pci_info ivtv_pci_va2000[] = { + { PCI_DEVICE_ID_IVTV16, 0, 0xff5f }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_va2000 = { + .type = IVTV_CARD_VA2000MAX_SNT6, + .name = "AOpen VA2000MAX-SNT6", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD6408X, + .hw_audio = IVTV_HW_MSP34XX, + .hw_audio_ctrl = IVTV_HW_MSP34XX, + .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | + IVTV_HW_UPD6408X | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, + }, + .tuners = { + { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, + }, + .pci_list = ivtv_pci_va2000, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan MPG600GR/Kuroutoshikou CX23416GYC-STVLP cards */ + +static const struct ivtv_card_pci_info ivtv_pci_cx23416gyc[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN4, 0x0600 }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x0523 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_cx23416gyc = { + .type = IVTV_CARD_CX23416GYC, + .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | + IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, + .hw_audio = IVTV_HW_SAA717X, + .hw_audio_ctrl = IVTV_HW_SAA717X, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | + IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO3 | + IVTV_SAA717X_TUNER_FLAG }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, + }, + .gr_config = UPD64031A_VERTICAL_EXTERNAL, + .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, + .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, + .composite = 0x0020, .svideo = 0x0020 }, + .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, + .f44100 = 0x4000, .f48000 = 0x8000 }, + .tuners = { + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + }, + .pci_list = ivtv_pci_cx23416gyc, + .i2c = &ivtv_i2c_std, +}; + +static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { + .type = IVTV_CARD_CX23416GYC_NOGR, + .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR)", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | IVTV_HW_UPD6408X, + .hw_audio = IVTV_HW_SAA717X, + .hw_audio_ctrl = IVTV_HW_SAA717X, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | + IVTV_HW_UPD6408X, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | + IVTV_SAA717X_TUNER_FLAG }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, + }, + .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, + .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, + .composite = 0x0020, .svideo = 0x0020 }, + .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, + .f44100 = 0x4000, .f48000 = 0x8000 }, + .tuners = { + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + }, + .i2c = &ivtv_i2c_std, +}; + +static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { + .type = IVTV_CARD_CX23416GYC_NOGRYCS, + .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR/YCS)", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO, + .hw_audio = IVTV_HW_SAA717X, + .hw_audio_ctrl = IVTV_HW_SAA717X, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | + IVTV_SAA717X_TUNER_FLAG }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, + }, + .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, + .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, + .composite = 0x0020, .svideo = 0x0020 }, + .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, + .f44100 = 0x4000, .f48000 = 0x8000 }, + .tuners = { + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + }, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* I/O Data GV-MVP/RX & GV-MVP/RX2W (dual tuner) cards */ + +static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd01e }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd038 }, /* 2W unit #1 */ + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd039 }, /* 2W unit #2 */ + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_gv_mvprx = { + .type = IVTV_CARD_GV_MVPRX, + .name = "I/O Data GV-MVP/RX, GV-MVP/RX2W (dual tuner)", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, + .hw_audio = IVTV_HW_GPIO, + .hw_audio_ctrl = IVTV_HW_WM8739, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX | + IVTV_HW_TUNER | IVTV_HW_WM8739 | + IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO1 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, + }, + .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, + .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, + .tuners = { + /* This card has the Panasonic VP27 tuner */ + { .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, + }, + .pci_list = ivtv_pci_gv_mvprx, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* I/O Data GV-MVP/RX2E card */ + +static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx2e[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd025 }, + {0, 0, 0} +}; + +static const struct ivtv_card ivtv_card_gv_mvprx2e = { + .type = IVTV_CARD_GV_MVPRX2E, + .name = "I/O Data GV-MVP/RX2E", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7115, + .hw_audio = IVTV_HW_GPIO, + .hw_audio_ctrl = IVTV_HW_WM8739, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | + IVTV_HW_VP27SMPX | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, + }, + .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, + .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, + .tuners = { + /* This card has the Panasonic VP27 tuner */ + { .std = V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, + }, + .pci_list = ivtv_pci_gv_mvprx2e, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* GotVIEW PCI DVD card */ + +static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_gotview_pci_dvd = { + .type = IVTV_CARD_GOTVIEW_PCI_DVD, + .name = "GotView PCI DVD", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA717X, + .hw_audio = IVTV_HW_SAA717X, + .hw_audio_ctrl = IVTV_HW_SAA717X, + .hw_all = IVTV_HW_SAA717X | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE1 }, /* pin 116 */ + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, /* pin 114/109 */ + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, /* pin 118 */ + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN0 }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN2 }, + }, + .gpio_init = { .direction = 0xf000, .initial_value = 0xA000 }, + .tuners = { + /* This card has a Philips FQ1216ME MK3 tuner */ + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + }, + .pci_list = ivtv_pci_gotview_pci_dvd, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* GotVIEW PCI DVD2 Deluxe card */ + +static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd2[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW1, 0x0600 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { + .type = IVTV_CARD_GOTVIEW_PCI_DVD2, + .name = "GotView PCI DVD2 Deluxe", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_GPIO, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + .gpio_init = { .direction = 0x0800, .initial_value = 0 }, + .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, + .tuners = { + /* This card has a Philips FQ1216ME MK5 tuner */ + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + }, + .pci_list = ivtv_pci_gotview_pci_dvd2, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan MPC622 miniPCI card */ + +static const struct ivtv_card_pci_info ivtv_pci_yuan_mpc622[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN2, 0xd998 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_yuan_mpc622 = { + .type = IVTV_CARD_YUAN_MPC622, + .name = "Yuan MPC622", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, + }, + .gpio_init = { .direction = 0x00ff, .initial_value = 0x0002 }, + .tuners = { + /* This card has the TDA8290/TDA8275 tuner chips */ + { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 }, + }, + .pci_list = ivtv_pci_yuan_mpc622, + .i2c = &ivtv_i2c_tda8290, +}; + +/* ------------------------------------------------------------------------- */ + +/* DIGITAL COWBOY DCT-MTVP1 card */ + +static const struct ivtv_card_pci_info ivtv_pci_dctmvtvp1[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_dctmvtvp1 = { + .type = IVTV_CARD_DCTMTVP1, + .name = "Digital Cowboy DCT-MTVP1", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | + IVTV_HW_GPIO, + .hw_audio = IVTV_HW_GPIO, + .hw_audio_ctrl = IVTV_HW_GPIO, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | + IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, + }, + .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, + .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, + .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, + .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, + .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, + .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, + .composite = 0x0010, .svideo = 0x0020}, + .tuners = { + { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, + }, + .pci_list = ivtv_pci_dctmvtvp1, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan PG600-2/GotView PCI DVD Lite cards */ + +static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW2, 0x0600 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_pg600v2 = { + .type = IVTV_CARD_PG600V2, + .name = "Yuan PG600-2, GotView PCI DVD Lite", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + /* XC2028 support apparently works for the Yuan, it's still + uncertain whether it also works with the GotView. */ + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + .xceive_pin = 12, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .pci_list = ivtv_pci_pg600v2, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Club3D ZAP-TV1x01 cards */ + +static const struct ivtv_card_pci_info ivtv_pci_club3d[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_club3d = { + .type = IVTV_CARD_CLUB3D, + .name = "Club3D ZAP-TV1x01", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + .xceive_pin = 12, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .pci_list = ivtv_pci_club3d, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerTV MCE 116 Plus (M116) card */ + +static const struct ivtv_card_pci_info ivtv_pci_avertv_mce116[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc439 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_avertv_mce116 = { + .type = IVTV_CARD_AVERTV_MCE116, + .name = "AVerTV MCE 116 Plus", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739 | + IVTV_HW_I2C_IR_RX_AVER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + /* enable line-in */ + .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, + .xceive_pin = 10, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .pci_list = ivtv_pci_avertv_mce116, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerMedia PVR-150 Plus / AVerTV M113 cards with a Daewoo/Partsnic Tuner */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc034 }, /* NTSC */ + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, /* NTSC FM */ + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_pvr150 = { + .type = IVTV_CARD_AVER_PVR150PLUS, + .name = "AVerMedia PVR-150 Plus / AVerTV M113 Partsnic (Daewoo) Tuner", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_GPIO, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | + IVTV_HW_WM8739 | IVTV_HW_GPIO, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */ + .gpio_init = { .direction = 0xc000, .initial_value = 0 }, + .gpio_audio_input = { .mask = 0xc000, + .tuner = 0x0000, + .linein = 0x4000, + .radio = 0x8000 }, + .tuners = { + /* Subsystem ID's 0xc03[45] have a Partsnic PTI-5NF05 tuner */ + { .std = V4L2_STD_MN, .tuner = TUNER_PARTSNIC_PTI_5NF05 }, + }, + .pci_list = ivtv_pci_aver_pvr150, + /* Subsystem ID 0xc035 has a TEA5767(?) FM tuner, 0xc034 does not */ + .i2c = &ivtv_i2c_radio, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerMedia UltraTV 1500 MCE (newer non-cx88 version, M113 variant) card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_ultra1500mce[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc019 }, /* NTSC */ + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc01b }, /* PAL/SECAM */ + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_ultra1500mce = { + .type = IVTV_CARD_AVER_ULTRA1500MCE, + .name = "AVerMedia UltraTV 1500 MCE / AVerTV M113 Philips Tuner", + .comment = "For non-NTSC tuners, use the pal= or secam= module options", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_GPIO, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | + IVTV_HW_WM8739 | IVTV_HW_GPIO, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */ + .gpio_init = { .direction = 0xc000, .initial_value = 0 }, + .gpio_audio_input = { .mask = 0xc000, + .tuner = 0x0000, + .linein = 0x4000, + .radio = 0x8000 }, + .tuners = { + /* The UltraTV 1500 MCE has a Philips FM1236 MK5 TV/FM tuner */ + { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216MK5 }, + }, + .pci_list = ivtv_pci_aver_ultra1500mce, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerMedia EZMaker PCI Deluxe card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_ezmaker = { + .type = IVTV_CARD_AVER_EZMAKER, + .name = "AVerMedia EZMaker PCI Deluxe", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 0 }, + }, + .gpio_init = { .direction = 0x4000, .initial_value = 0x4000 }, + /* Does not have a tuner */ + .pci_list = ivtv_pci_aver_ezmaker, +}; + +/* ------------------------------------------------------------------------- */ + +/* ASUS Falcon2 */ + +static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_asus_falcon2 = { + .type = IVTV_CARD_ASUS_FALCON2, + .name = "ASUS Falcon2", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_M52790, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, + M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, + .tuners = { + { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + }, + .pci_list = ivtv_pci_asus_falcon2, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerMedia M104 miniPCI card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_m104[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc136 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_m104 = { + .type = IVTV_CARD_AVER_M104, + .name = "AVerMedia M104", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, /*IVTV_CAP_ENCODER,*/ + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + /* enable line-in + reset tuner */ + .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, + .xceive_pin = 10, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .pci_list = ivtv_pci_aver_m104, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Buffalo PC-MV5L/PCI cards */ + +static const struct ivtv_card_pci_info ivtv_pci_buffalo[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x052b }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_buffalo = { + .type = IVTV_CARD_BUFFALO_MV5L, + .name = "Buffalo PC-MV5L/PCI", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, + }, + .xceive_pin = 12, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .pci_list = ivtv_pci_buffalo, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ +/* Sony Kikyou */ + +static const struct ivtv_card_pci_info ivtv_pci_kikyou[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_SONY, 0x813d }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_kikyou = { + .type = IVTV_CARD_KIKYOU, + .name = "Sony VAIO Giga Pocket (ENX Kikyou)", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_SAA7115, + .hw_audio = IVTV_HW_GPIO, + .hw_audio_ctrl = IVTV_HW_GPIO, + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE1 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE1 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, + { IVTV_CARD_INPUT_LINE_IN2, IVTV_GPIO_LINE_IN }, + }, + .gpio_init = { .direction = 0x03e1, .initial_value = 0x0320 }, + .gpio_audio_input = { .mask = 0x0060, + .tuner = 0x0020, + .linein = 0x0000, + .radio = 0x0060 }, + .gpio_audio_mute = { .mask = 0x0000, + .mute = 0x0000 }, /* 0x200? Disable for now. */ + .gpio_audio_mode = { .mask = 0x0080, + .mono = 0x0000, + .stereo = 0x0000, /* SAP */ + .lang1 = 0x0080, + .lang2 = 0x0000, + .both = 0x0080 }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_SONY_BTF_PXN01Z }, + }, + .pci_list = ivtv_pci_kikyou, + .i2c = &ivtv_i2c_std, +}; + + +static const struct ivtv_card *ivtv_card_list[] = { + &ivtv_card_pvr250, + &ivtv_card_pvr350, + &ivtv_card_pvr150, + &ivtv_card_m179, + &ivtv_card_mpg600, + &ivtv_card_mpg160, + &ivtv_card_pg600, + &ivtv_card_avc2410, + &ivtv_card_avc2010, + &ivtv_card_tg5000tv, + &ivtv_card_va2000, + &ivtv_card_cx23416gyc, + &ivtv_card_gv_mvprx, + &ivtv_card_gv_mvprx2e, + &ivtv_card_gotview_pci_dvd, + &ivtv_card_gotview_pci_dvd2, + &ivtv_card_yuan_mpc622, + &ivtv_card_dctmvtvp1, + &ivtv_card_pg600v2, + &ivtv_card_club3d, + &ivtv_card_avertv_mce116, + &ivtv_card_asus_falcon2, + &ivtv_card_aver_pvr150, + &ivtv_card_aver_ezmaker, + &ivtv_card_aver_m104, + &ivtv_card_buffalo, + &ivtv_card_aver_ultra1500mce, + &ivtv_card_kikyou, + + /* Variations of standard cards but with the same PCI IDs. + These cards must come last in this list. */ + &ivtv_card_pvr350_v1, + &ivtv_card_cx23416gyc_nogr, + &ivtv_card_cx23416gyc_nogrycs, +}; + +const struct ivtv_card *ivtv_get_card(u16 index) +{ + if (index >= ARRAY_SIZE(ivtv_card_list)) + return NULL; + return ivtv_card_list[index]; +} + +int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input) +{ + const struct ivtv_card_video_input *card_input = itv->card->video_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "S-Video 1", + "S-Video 2", + "Composite 1", + "Composite 2", + "Composite 3" + }; + + if (index >= itv->nof_inputs) + return -EINVAL; + input->index = index; + strlcpy(input->name, input_strs[card_input->video_type - 1], + sizeof(input->name)); + input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ? + V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); + input->audioset = (1 << itv->nof_audio_inputs) - 1; + input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? + itv->tuner_std : V4L2_STD_ALL; + return 0; +} + +int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output) +{ + const struct ivtv_card_output *card_output = itv->card->video_outputs + index; + + if (index >= itv->card->nof_outputs) + return -EINVAL; + output->index = index; + strlcpy(output->name, card_output->name, sizeof(output->name)); + output->type = V4L2_OUTPUT_TYPE_ANALOG; + output->audioset = 1; + output->std = V4L2_STD_ALL; + return 0; +} + +int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio) +{ + const struct ivtv_card_audio_input *aud_input = itv->card->audio_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "Line In 1", + "Line In 2" + }; + + memset(audio, 0, sizeof(*audio)); + if (index >= itv->nof_audio_inputs) + return -EINVAL; + strlcpy(audio->name, input_strs[aud_input->audio_type - 1], + sizeof(audio->name)); + audio->index = index; + audio->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud_output) +{ + memset(aud_output, 0, sizeof(*aud_output)); + if (itv->card->video_outputs == NULL || index != 0) + return -EINVAL; + strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name)); + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-cards.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-cards.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-cards.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-cards.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,309 @@ +/* + Functions to query card hardware + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_CARDS_H +#define IVTV_CARDS_H + +/* Supported cards */ +#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ +#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ +#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two + PVR150s on one PCI board) */ +#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ +#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ +#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 + cx23415 based, but does not have tv-out */ +#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ +#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ +#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ +#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ +#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ +#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ +#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ +#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ +#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ +#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ +#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ +#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ +#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ +#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ +#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ +#define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ +#define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ +#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */ +#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */ +#define IVTV_CARD_BUFFALO_MV5L 25 /* Buffalo PC-MV5L/PCI card */ +#define IVTV_CARD_AVER_ULTRA1500MCE 26 /* AVerMedia UltraTV 1500 MCE */ +#define IVTV_CARD_KIKYOU 27 /* Sony VAIO Giga Pocket (ENX Kikyou) */ +#define IVTV_CARD_LAST 27 + +/* Variants of existing cards but with the same PCI IDs. The driver + detects these based on other device information. + These cards must always come last. + New cards must be inserted above, and the indices of the cards below + must be adjusted accordingly. */ + +/* PVR-350 V1 (uses saa7114) */ +#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) +/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ +#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) +#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) + +/* system vendor and device IDs */ +#define PCI_VENDOR_ID_ICOMP 0x4444 +#define PCI_DEVICE_ID_IVTV15 0x0803 +#define PCI_DEVICE_ID_IVTV16 0x0016 + +/* subsystem vendor ID */ +#define IVTV_PCI_ID_HAUPPAUGE 0x0070 +#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 +#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 +#define IVTV_PCI_ID_ADAPTEC 0x9005 +#define IVTV_PCI_ID_ASUSTEK 0x1043 +#define IVTV_PCI_ID_AVERMEDIA 0x1461 +#define IVTV_PCI_ID_YUAN1 0x12ab +#define IVTV_PCI_ID_YUAN2 0xff01 +#define IVTV_PCI_ID_YUAN3 0xffab +#define IVTV_PCI_ID_YUAN4 0xfbab +#define IVTV_PCI_ID_DIAMONDMM 0xff92 +#define IVTV_PCI_ID_IODATA 0x10fc +#define IVTV_PCI_ID_MELCO 0x1154 +#define IVTV_PCI_ID_GOTVIEW1 0xffac +#define IVTV_PCI_ID_GOTVIEW2 0xffad +#define IVTV_PCI_ID_SONY 0x104d + +/* hardware flags, no gaps allowed */ +#define IVTV_HW_CX25840 (1 << 0) +#define IVTV_HW_SAA7115 (1 << 1) +#define IVTV_HW_SAA7127 (1 << 2) +#define IVTV_HW_MSP34XX (1 << 3) +#define IVTV_HW_TUNER (1 << 4) +#define IVTV_HW_WM8775 (1 << 5) +#define IVTV_HW_CS53L32A (1 << 6) +#define IVTV_HW_TVEEPROM (1 << 7) +#define IVTV_HW_SAA7114 (1 << 8) +#define IVTV_HW_UPD64031A (1 << 9) +#define IVTV_HW_UPD6408X (1 << 10) +#define IVTV_HW_SAA717X (1 << 11) +#define IVTV_HW_WM8739 (1 << 12) +#define IVTV_HW_VP27SMPX (1 << 13) +#define IVTV_HW_M52790 (1 << 14) +#define IVTV_HW_GPIO (1 << 15) +#define IVTV_HW_I2C_IR_RX_AVER (1 << 16) +#define IVTV_HW_I2C_IR_RX_HAUP_EXT (1 << 17) /* External before internal */ +#define IVTV_HW_I2C_IR_RX_HAUP_INT (1 << 18) +#define IVTV_HW_Z8F0811_IR_TX_HAUP (1 << 19) +#define IVTV_HW_Z8F0811_IR_RX_HAUP (1 << 20) +#define IVTV_HW_I2C_IR_RX_ADAPTEC (1 << 21) + +#define IVTV_HW_Z8F0811_IR_HAUP (IVTV_HW_Z8F0811_IR_RX_HAUP | \ + IVTV_HW_Z8F0811_IR_TX_HAUP) + +#define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) + +#define IVTV_HW_IR_RX_ANY (IVTV_HW_I2C_IR_RX_AVER | \ + IVTV_HW_I2C_IR_RX_HAUP_EXT | \ + IVTV_HW_I2C_IR_RX_HAUP_INT | \ + IVTV_HW_Z8F0811_IR_RX_HAUP | \ + IVTV_HW_I2C_IR_RX_ADAPTEC) + +#define IVTV_HW_IR_TX_ANY (IVTV_HW_Z8F0811_IR_TX_HAUP) + +#define IVTV_HW_IR_ANY (IVTV_HW_IR_RX_ANY | IVTV_HW_IR_TX_ANY) + +/* video inputs */ +#define IVTV_CARD_INPUT_VID_TUNER 1 +#define IVTV_CARD_INPUT_SVIDEO1 2 +#define IVTV_CARD_INPUT_SVIDEO2 3 +#define IVTV_CARD_INPUT_COMPOSITE1 4 +#define IVTV_CARD_INPUT_COMPOSITE2 5 +#define IVTV_CARD_INPUT_COMPOSITE3 6 + +/* audio inputs */ +#define IVTV_CARD_INPUT_AUD_TUNER 1 +#define IVTV_CARD_INPUT_LINE_IN1 2 +#define IVTV_CARD_INPUT_LINE_IN2 3 + +#define IVTV_CARD_MAX_VIDEO_INPUTS 6 +#define IVTV_CARD_MAX_AUDIO_INPUTS 3 +#define IVTV_CARD_MAX_TUNERS 3 + +/* SAA71XX HW inputs */ +#define IVTV_SAA71XX_COMPOSITE0 0 +#define IVTV_SAA71XX_COMPOSITE1 1 +#define IVTV_SAA71XX_COMPOSITE2 2 +#define IVTV_SAA71XX_COMPOSITE3 3 +#define IVTV_SAA71XX_COMPOSITE4 4 +#define IVTV_SAA71XX_COMPOSITE5 5 +#define IVTV_SAA71XX_SVIDEO0 6 +#define IVTV_SAA71XX_SVIDEO1 7 +#define IVTV_SAA71XX_SVIDEO2 8 +#define IVTV_SAA71XX_SVIDEO3 9 + +/* SAA717X needs to mark the tuner input by ORing with this flag */ +#define IVTV_SAA717X_TUNER_FLAG 0x80 + +/* Dummy HW input */ +#define IVTV_DUMMY_AUDIO 0 + +/* GPIO HW inputs */ +#define IVTV_GPIO_TUNER 0 +#define IVTV_GPIO_LINE_IN 1 + +/* SAA717X HW inputs */ +#define IVTV_SAA717X_IN0 0 +#define IVTV_SAA717X_IN1 1 +#define IVTV_SAA717X_IN2 2 + +/* V4L2 capability aliases */ +#define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \ + V4L2_CAP_SLICED_VBI_CAPTURE) +#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | \ + V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY) + +struct ivtv_card_video_input { + u8 video_type; /* video input type */ + u8 audio_index; /* index in ivtv_card_audio_input array */ + u16 video_input; /* hardware video input */ +}; + +struct ivtv_card_audio_input { + u8 audio_type; /* audio input type */ + u32 audio_input; /* hardware audio input */ + u16 muxer_input; /* hardware muxer input for boards with a + multiplexer chip */ +}; + +struct ivtv_card_output { + u8 name[32]; + u16 video_output; /* hardware video output */ +}; + +struct ivtv_card_pci_info { + u16 device; + u16 subsystem_vendor; + u16 subsystem_device; +}; + +/* GPIO definitions */ + +/* The mask is the set of bits used by the operation */ + +struct ivtv_gpio_init { /* set initial GPIO DIR and OUT values */ + u16 direction; /* DIR setting. Leave to 0 if no init is needed */ + u16 initial_value; +}; + +struct ivtv_gpio_video_input { /* select tuner/line in input */ + u16 mask; /* leave to 0 if not supported */ + u16 tuner; + u16 composite; + u16 svideo; +}; + +struct ivtv_gpio_audio_input { /* select tuner/line in input */ + u16 mask; /* leave to 0 if not supported */ + u16 tuner; + u16 linein; + u16 radio; +}; + +struct ivtv_gpio_audio_mute { + u16 mask; /* leave to 0 if not supported */ + u16 mute; /* set this value to mute, 0 to unmute */ +}; + +struct ivtv_gpio_audio_mode { + u16 mask; /* leave to 0 if not supported */ + u16 mono; /* set audio to mono */ + u16 stereo; /* set audio to stereo */ + u16 lang1; /* set audio to the first language */ + u16 lang2; /* set audio to the second language */ + u16 both; /* both languages are output */ +}; + +struct ivtv_gpio_audio_freq { + u16 mask; /* leave to 0 if not supported */ + u16 f32000; + u16 f44100; + u16 f48000; +}; + +struct ivtv_gpio_audio_detect { + u16 mask; /* leave to 0 if not supported */ + u16 stereo; /* if the input matches this value then + stereo is detected */ +}; + +struct ivtv_card_tuner { + v4l2_std_id std; /* standard for which the tuner is suitable */ + int tuner; /* tuner ID (from tuner.h) */ +}; + +struct ivtv_card_tuner_i2c { + unsigned short radio[2];/* radio tuner i2c address to probe */ + unsigned short demod[2];/* demodulator i2c address to probe */ + unsigned short tv[4]; /* tv tuner i2c addresses to probe */ +}; + +/* for card information/parameters */ +struct ivtv_card { + int type; + char *name; + char *comment; + u32 v4l2_capabilities; + u32 hw_video; /* hardware used to process video */ + u32 hw_audio; /* hardware used to process audio */ + u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only 1 dev allowed) */ + u32 hw_muxer; /* hardware used to multiplex audio input */ + u32 hw_all; /* all hardware used by the board */ + struct ivtv_card_video_input video_inputs[IVTV_CARD_MAX_VIDEO_INPUTS]; + struct ivtv_card_audio_input audio_inputs[IVTV_CARD_MAX_AUDIO_INPUTS]; + struct ivtv_card_audio_input radio_input; + int nof_outputs; + const struct ivtv_card_output *video_outputs; + u8 gr_config; /* config byte for the ghost reduction device */ + u8 xceive_pin; /* XCeive tuner GPIO reset pin */ + + /* GPIO card-specific settings */ + struct ivtv_gpio_init gpio_init; + struct ivtv_gpio_video_input gpio_video_input; + struct ivtv_gpio_audio_input gpio_audio_input; + struct ivtv_gpio_audio_mute gpio_audio_mute; + struct ivtv_gpio_audio_mode gpio_audio_mode; + struct ivtv_gpio_audio_freq gpio_audio_freq; + struct ivtv_gpio_audio_detect gpio_audio_detect; + + struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS]; + struct ivtv_card_tuner_i2c *i2c; + + /* list of device and subsystem vendor/devices that + correspond to this card type. */ + const struct ivtv_card_pci_info *pci_list; +}; + +int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input); +int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output); +int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input); +int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output); +const struct ivtv_card *ivtv_get_card(u16 index); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-controls.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-controls.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-controls.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-controls.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,101 @@ +/* + ioctl control functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-ioctl.h" +#include "ivtv-controls.h" + +static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) +{ + struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); + + /* First try to allocate sliced VBI buffers if needed. */ + if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) { + int i; + + for (i = 0; i < IVTV_VBI_FRAMES; i++) { + /* Yuck, hardcoded. Needs to be a define */ + itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); + if (itv->vbi.sliced_mpeg_data[i] == NULL) { + while (--i >= 0) { + kfree(itv->vbi.sliced_mpeg_data[i]); + itv->vbi.sliced_mpeg_data[i] = NULL; + } + return -ENOMEM; + } + } + } + + itv->vbi.insert_mpeg = fmt; + + if (itv->vbi.insert_mpeg == 0) { + return 0; + } + /* Need sliced data for mpeg insertion */ + if (ivtv_get_service_set(itv->vbi.sliced_in) == 0) { + if (itv->is_60hz) + itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; + else + itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; + ivtv_expand_service_set(itv->vbi.sliced_in, itv->is_50hz); + } + return 0; +} + +static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) +{ + struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); + int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_mbus_framefmt fmt; + + /* fix videodecoder resolution */ + fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); + fmt.height = cxhdl->height; + fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt); + return 0; +} + +static int ivtv_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) +{ + static const u32 freqs[3] = { 44100, 48000, 32000 }; + struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); + + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (idx < ARRAY_SIZE(freqs)) + ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]); + return 0; +} + +static int ivtv_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) +{ + struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); + + itv->dualwatch_stereo_mode = val; + return 0; +} + +struct cx2341x_handler_ops ivtv_cxhdl_ops = { + .s_audio_mode = ivtv_s_audio_mode, + .s_audio_sampling_freq = ivtv_s_audio_sampling_freq, + .s_video_encoding = ivtv_s_video_encoding, + .s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt, +}; diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-controls.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-controls.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-controls.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-controls.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,26 @@ +/* + ioctl control functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_CONTROLS_H +#define IVTV_CONTROLS_H + +extern struct cx2341x_handler_ops ivtv_cxhdl_ops; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-driver.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-driver.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1471 @@ +/* + ivtv driver initialization and card probing + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +/* Main Driver file for the ivtv project: + * Driver for the Conexant CX23415/CX23416 chip. + * Author: Kevin Thayer (nufan_wfk at yahoo.com) + * License: GPL + * http://www.ivtvdriver.org + * + * ----- + * MPG600/MPG160 support by T.Adachi + * and Takeru KOMORIYA + * + * AVerMedia M179 GPIO info by Chris Pinkham + * using information provided by Jiun-Kuei Jung @ AVerMedia. + * + * Kurouto Sikou CX23416GYC-STVLP tested by K.Ohta + * using information from T.Adachi,Takeru KOMORIYA and others :-) + * + * Nagase TRANSGEAR 5000TV, Aopen VA2000MAX-STN6 and I/O data GV-MVP/RX + * version by T.Adachi. Special thanks Mr.Suzuki + */ + +#include "ivtv-driver.h" +#include "ivtv-version.h" +#include "ivtv-fileops.h" +#include "ivtv-i2c.h" +#include "ivtv-firmware.h" +#include "ivtv-queue.h" +#include "ivtv-udma.h" +#include "ivtv-irq.h" +#include "ivtv-mailbox.h" +#include "ivtv-streams.h" +#include "ivtv-ioctl.h" +#include "ivtv-cards.h" +#include "ivtv-vbi.h" +#include "ivtv-routing.h" +#include "ivtv-controls.h" +#include "ivtv-gpio.h" + +#include +#include +#include +#include "tuner-xc2028.h" + +/* If you have already X v4l cards, then set this to X. This way + the device numbers stay matched. Example: you have a WinTV card + without radio and a PVR-350 with. Normally this would give a + video1 device together with a radio0 device for the PVR. By + setting this to 1 you ensure that radio0 is now also radio1. */ +int ivtv_first_minor; + +/* add your revision and whatnot here */ +static struct pci_device_id ivtv_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); + +/* ivtv instance counter */ +static atomic_t ivtv_instance = ATOMIC_INIT(0); + +/* Parameter declarations */ +static int cardtype[IVTV_MAX_CARDS]; +static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; + +static unsigned int cardtype_c = 1; +static unsigned int tuner_c = 1; +static unsigned int radio_c = 1; +static unsigned int i2c_clock_period_c = 1; +static char pal[] = "---"; +static char secam[] = "--"; +static char ntsc[] = "-"; + +/* Buffers */ + +/* DMA Buffers, Default size in MB allocated */ +#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 +#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 +#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 +/* Exception: size in kB for this stream (MB is overkill) */ +#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 +#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 +#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 +/* Exception: size in kB for this stream (MB is way overkill) */ +#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 + +static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS; +static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS; +static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS; +static int enc_pcm_buffers = IVTV_DEFAULT_ENC_PCM_BUFFERS; +static int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS; +static int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS; +static int dec_vbi_buffers = IVTV_DEFAULT_DEC_VBI_BUFFERS; + +static int ivtv_yuv_mode; +static int ivtv_yuv_threshold = -1; +static int ivtv_pci_latency = 1; + +int ivtv_debug; +#ifdef CONFIG_VIDEO_ADV_DEBUG +int ivtv_fw_debug; +#endif + +static int tunertype = -1; +static int newi2c = -1; + +module_param_array(tuner, int, &tuner_c, 0644); +module_param_array(radio, bool, &radio_c, 0644); +module_param_array(cardtype, int, &cardtype_c, 0644); +module_param_string(pal, pal, sizeof(pal), 0644); +module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); +module_param_named(debug,ivtv_debug, int, 0644); +#ifdef CONFIG_VIDEO_ADV_DEBUG +module_param_named(fw_debug, ivtv_fw_debug, int, 0644); +#endif +module_param(ivtv_pci_latency, int, 0644); +module_param(ivtv_yuv_mode, int, 0644); +module_param(ivtv_yuv_threshold, int, 0644); +module_param(ivtv_first_minor, int, 0644); + +module_param(enc_mpg_buffers, int, 0644); +module_param(enc_yuv_buffers, int, 0644); +module_param(enc_vbi_buffers, int, 0644); +module_param(enc_pcm_buffers, int, 0644); +module_param(dec_mpg_buffers, int, 0644); +module_param(dec_yuv_buffers, int, 0644); +module_param(dec_vbi_buffers, int, 0644); + +module_param(tunertype, int, 0644); +module_param(newi2c, int, 0644); +module_param_array(i2c_clock_period, int, &i2c_clock_period_c, 0644); + +MODULE_PARM_DESC(tuner, "Tuner type selection,\n" + "\t\t\tsee tuner.h for values"); +MODULE_PARM_DESC(radio, + "Enable or disable the radio. Use only if autodetection\n" + "\t\t\tfails. 0 = disable, 1 = enable"); +MODULE_PARM_DESC(cardtype, + "Only use this option if your card is not detected properly.\n" + "\t\tSpecify card type:\n" + "\t\t\t 1 = WinTV PVR 250\n" + "\t\t\t 2 = WinTV PVR 350\n" + "\t\t\t 3 = WinTV PVR-150 or PVR-500\n" + "\t\t\t 4 = AVerMedia M179\n" + "\t\t\t 5 = YUAN MPG600/Kuroutoshikou iTVC16-STVLP\n" + "\t\t\t 6 = YUAN MPG160/Kuroutoshikou iTVC15-STVLP\n" + "\t\t\t 7 = YUAN PG600/DIAMONDMM PVR-550 (CX Falcon 2)\n" + "\t\t\t 8 = Adaptec AVC-2410\n" + "\t\t\t 9 = Adaptec AVC-2010\n" + "\t\t\t10 = NAGASE TRANSGEAR 5000TV\n" + "\t\t\t11 = AOpen VA2000MAX-STN6\n" + "\t\t\t12 = YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP\n" + "\t\t\t13 = I/O Data GV-MVP/RX\n" + "\t\t\t14 = I/O Data GV-MVP/RX2E\n" + "\t\t\t15 = GOTVIEW PCI DVD\n" + "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n" + "\t\t\t17 = Yuan MPC622\n" + "\t\t\t18 = Digital Cowboy DCT-MTVP1\n" + "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n" + "\t\t\t20 = Club3D ZAP-TV1x01\n" + "\t\t\t21 = AverTV MCE 116 Plus\n" + "\t\t\t22 = ASUS Falcon2\n" + "\t\t\t23 = AverMedia PVR-150 Plus\n" + "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n" + "\t\t\t25 = AverMedia M104 (not yet working)\n" + "\t\t\t26 = Buffalo PC-MV5L/PCI\n" + "\t\t\t27 = AVerMedia UltraTV 1500 MCE\n" + "\t\t\t28 = Sony VAIO Giga Pocket (ENX Kikyou)\n" + "\t\t\t 0 = Autodetect (default)\n" + "\t\t\t-1 = Ignore this card\n\t\t"); +MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60"); +MODULE_PARM_DESC(secam, "Set SECAM standard: BGH, DK, L, LC"); +MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J (Japan), K (South Korea)"); +MODULE_PARM_DESC(tunertype, + "Specify tuner type:\n" + "\t\t\t 0 = tuner for PAL-B/G/H/D/K/I, SECAM-B/G/H/D/K/L/Lc\n" + "\t\t\t 1 = tuner for NTSC-M/J/K, PAL-M/N/Nc\n" + "\t\t\t-1 = Autodetect (default)\n"); +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n" + "\t\t\t 4/0x0004: mailbox\n" + "\t\t\t 8/0x0008: ioctl\n" + "\t\t\t 16/0x0010: file\n" + "\t\t\t 32/0x0020: dma\n" + "\t\t\t 64/0x0040: irq\n" + "\t\t\t 128/0x0080: decoder\n" + "\t\t\t 256/0x0100: yuv\n" + "\t\t\t 512/0x0200: i2c\n" + "\t\t\t1024/0x0400: high volume\n"); +#ifdef CONFIG_VIDEO_ADV_DEBUG +MODULE_PARM_DESC(fw_debug, + "Enable code for debugging firmware problems. Default: 0\n"); +#endif +MODULE_PARM_DESC(ivtv_pci_latency, + "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" + "\t\t\tDefault: Yes"); +MODULE_PARM_DESC(ivtv_yuv_mode, + "Specify the yuv playback mode:\n" + "\t\t\t0 = interlaced\n\t\t\t1 = progressive\n\t\t\t2 = auto\n" + "\t\t\tDefault: 0 (interlaced)"); +MODULE_PARM_DESC(ivtv_yuv_threshold, + "If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n" + "\t\t\tDefault: 480"); +MODULE_PARM_DESC(enc_mpg_buffers, + "Encoder MPG Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS)); +MODULE_PARM_DESC(enc_yuv_buffers, + "Encoder YUV Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_YUV_BUFFERS)); +MODULE_PARM_DESC(enc_vbi_buffers, + "Encoder VBI Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS)); +MODULE_PARM_DESC(enc_pcm_buffers, + "Encoder PCM buffers (in kB)\n" + "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS)); +MODULE_PARM_DESC(dec_mpg_buffers, + "Decoder MPG buffers (in MB)\n" + "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_MPG_BUFFERS)); +MODULE_PARM_DESC(dec_yuv_buffers, + "Decoder YUV buffers (in MB)\n" + "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS)); +MODULE_PARM_DESC(dec_vbi_buffers, + "Decoder VBI buffers (in kB)\n" + "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS)); +MODULE_PARM_DESC(newi2c, + "Use new I2C implementation\n" + "\t\t\t-1 is autodetect, 0 is off, 1 is on\n" + "\t\t\tDefault is autodetect"); +MODULE_PARM_DESC(i2c_clock_period, + "Period of SCL for the I2C bus controlled by the CX23415/6\n" + "\t\t\tMin: 10 usec (100 kHz), Max: 4500 usec (222 Hz)\n" + "\t\t\tDefault: " __stringify(IVTV_DEFAULT_I2C_CLOCK_PERIOD)); + +MODULE_PARM_DESC(ivtv_first_minor, "Set device node number assigned to first card"); + +MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); +MODULE_DESCRIPTION("CX23415/CX23416 driver"); +MODULE_SUPPORTED_DEVICE + ("CX23415/CX23416 MPEG2 encoder (WinTV PVR-150/250/350/500,\n" + "\t\t\tYuan MPG series and similar)"); +MODULE_LICENSE("GPL"); + + +void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask) +{ + itv->irqmask &= ~mask; + write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); +} + +void ivtv_set_irq_mask(struct ivtv *itv, u32 mask) +{ + itv->irqmask |= mask; + write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); +} + +int ivtv_set_output_mode(struct ivtv *itv, int mode) +{ + int old_mode; + + spin_lock(&itv->lock); + old_mode = itv->output_mode; + if (old_mode == 0) + itv->output_mode = old_mode = mode; + spin_unlock(&itv->lock); + return old_mode; +} + +struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv) +{ + switch (itv->output_mode) { + case OUT_MPG: + return &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; + case OUT_YUV: + return &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; + default: + return NULL; + } +} + +int ivtv_waitq(wait_queue_head_t *waitq) +{ + DEFINE_WAIT(wait); + + prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); + schedule(); + finish_wait(waitq, &wait); + return signal_pending(current) ? -EINTR : 0; +} + +/* Generic utility functions */ +int ivtv_msleep_timeout(unsigned int msecs, int intr) +{ + int timeout = msecs_to_jiffies(msecs); + + do { + set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + if (intr) { + int ret = signal_pending(current); + + if (ret) + return ret; + } + } while (timeout); + return 0; +} + +/* Release ioremapped memory */ +static void ivtv_iounmap(struct ivtv *itv) +{ + if (itv == NULL) + return; + + /* Release registers memory */ + if (itv->reg_mem != NULL) { + IVTV_DEBUG_INFO("releasing reg_mem\n"); + iounmap(itv->reg_mem); + itv->reg_mem = NULL; + } + /* Release io memory */ + if (itv->has_cx23415 && itv->dec_mem != NULL) { + IVTV_DEBUG_INFO("releasing dec_mem\n"); + iounmap(itv->dec_mem); + } + itv->dec_mem = NULL; + + /* Release io memory */ + if (itv->enc_mem != NULL) { + IVTV_DEBUG_INFO("releasing enc_mem\n"); + iounmap(itv->enc_mem); + itv->enc_mem = NULL; + } +} + +/* Hauppauge card? get values from tveeprom */ +void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv) +{ + u8 eedata[256]; + + itv->i2c_client.addr = 0xA0 >> 1; + tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata)); + tveeprom_hauppauge_analog(&itv->i2c_client, tv, eedata); +} + +static void ivtv_process_eeprom(struct ivtv *itv) +{ + struct tveeprom tv; + int pci_slot = PCI_SLOT(itv->pdev->devfn); + + ivtv_read_eeprom(itv, &tv); + + /* Many thanks to Steven Toth from Hauppauge for providing the + model numbers */ + switch (tv.model) { + /* In a few cases the PCI subsystem IDs do not correctly + identify the card. A better method is to check the + model number from the eeprom instead. */ + case 30012 ... 30039: /* Low profile PVR250 */ + case 32000 ... 32999: + case 48000 ... 48099: /* 48??? range are PVR250s with a cx23415 */ + case 48400 ... 48599: + itv->card = ivtv_get_card(IVTV_CARD_PVR_250); + break; + case 48100 ... 48399: + case 48600 ... 48999: + itv->card = ivtv_get_card(IVTV_CARD_PVR_350); + break; + case 23000 ... 23999: /* PVR500 */ + case 25000 ... 25999: /* Low profile PVR150 */ + case 26000 ... 26999: /* Regular PVR150 */ + itv->card = ivtv_get_card(IVTV_CARD_PVR_150); + break; + case 0: + IVTV_ERR("Invalid EEPROM\n"); + return; + default: + IVTV_ERR("Unknown model %d, defaulting to PVR-150\n", tv.model); + itv->card = ivtv_get_card(IVTV_CARD_PVR_150); + break; + } + + switch (tv.model) { + /* Old style PVR350 (with an saa7114) uses this input for + the tuner. */ + case 48254: + itv->card = ivtv_get_card(IVTV_CARD_PVR_350_V1); + break; + default: + break; + } + + itv->v4l2_cap = itv->card->v4l2_capabilities; + itv->card_name = itv->card->name; + itv->card_i2c = itv->card->i2c; + + /* If this is a PVR500 then it should be possible to detect whether it is the + first or second unit by looking at the subsystem device ID: is bit 4 is + set, then it is the second unit (according to info from Hauppauge). + + However, while this works for most cards, I have seen a few PVR500 cards + where both units have the same subsystem ID. + + So instead I look at the reported 'PCI slot' (which is the slot on the PVR500 + PCI bridge) and if it is 8, then it is assumed to be the first unit, otherwise + it is the second unit. It is possible that it is a different slot when ivtv is + used in Xen, in that case I ignore this card here. The worst that can happen + is that the card presents itself with a non-working radio device. + + This detection is needed since the eeprom reports incorrectly that a radio is + present on the second unit. */ + if (tv.model / 1000 == 23) { + static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = { + .radio = { 0x60, I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, I2C_CLIENT_END }, + }; + + itv->card_name = "WinTV PVR 500"; + itv->card_i2c = &ivtv_i2c_radio; + if (pci_slot == 8 || pci_slot == 9) { + int is_first = (pci_slot & 1) == 0; + + itv->card_name = is_first ? "WinTV PVR 500 (unit #1)" : + "WinTV PVR 500 (unit #2)"; + if (!is_first) { + IVTV_INFO("Correcting tveeprom data: no radio present on second unit\n"); + tv.has_radio = 0; + } + } + } + IVTV_INFO("Autodetected %s\n", itv->card_name); + + switch (tv.tuner_hauppauge_model) { + case 85: + case 99: + case 112: + itv->pvr150_workaround = 1; + break; + default: + break; + } + if (tv.tuner_type == TUNER_ABSENT) + IVTV_ERR("tveeprom cannot autodetect tuner!\n"); + + if (itv->options.tuner == -1) + itv->options.tuner = tv.tuner_type; + if (itv->options.radio == -1) + itv->options.radio = (tv.has_radio != 0); + /* only enable newi2c if an IR blaster is present */ + if (itv->options.newi2c == -1 && tv.has_ir) { + itv->options.newi2c = (tv.has_ir & 4) ? 1 : 0; + if (itv->options.newi2c) { + IVTV_INFO("Reopen i2c bus for IR-blaster support\n"); + exit_ivtv_i2c(itv); + init_ivtv_i2c(itv); + } + } + + if (itv->std != 0) + /* user specified tuner standard */ + return; + + /* autodetect tuner standard */ + if (tv.tuner_formats & V4L2_STD_PAL) { + IVTV_DEBUG_INFO("PAL tuner detected\n"); + itv->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + } else if (tv.tuner_formats & V4L2_STD_NTSC) { + IVTV_DEBUG_INFO("NTSC tuner detected\n"); + itv->std |= V4L2_STD_NTSC_M; + } else if (tv.tuner_formats & V4L2_STD_SECAM) { + IVTV_DEBUG_INFO("SECAM tuner detected\n"); + itv->std |= V4L2_STD_SECAM_L; + } else { + IVTV_INFO("No tuner detected, default to NTSC-M\n"); + itv->std |= V4L2_STD_NTSC_M; + } +} + +static v4l2_std_id ivtv_parse_std(struct ivtv *itv) +{ + switch (pal[0]) { + case '6': + tunertype = 0; + return V4L2_STD_PAL_60; + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + tunertype = 0; + return V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + case 'n': + case 'N': + tunertype = 1; + if (pal[1] == 'c' || pal[1] == 'C') + return V4L2_STD_PAL_Nc; + return V4L2_STD_PAL_N; + case 'i': + case 'I': + tunertype = 0; + return V4L2_STD_PAL_I; + case 'd': + case 'D': + case 'k': + case 'K': + tunertype = 0; + return V4L2_STD_PAL_DK; + case 'M': + case 'm': + tunertype = 1; + return V4L2_STD_PAL_M; + case '-': + break; + default: + IVTV_WARN("pal= argument not recognised\n"); + return 0; + } + + switch (secam[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + tunertype = 0; + return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + case 'd': + case 'D': + case 'k': + case 'K': + tunertype = 0; + return V4L2_STD_SECAM_DK; + case 'l': + case 'L': + tunertype = 0; + if (secam[1] == 'C' || secam[1] == 'c') + return V4L2_STD_SECAM_LC; + return V4L2_STD_SECAM_L; + case '-': + break; + default: + IVTV_WARN("secam= argument not recognised\n"); + return 0; + } + + switch (ntsc[0]) { + case 'm': + case 'M': + tunertype = 1; + return V4L2_STD_NTSC_M; + case 'j': + case 'J': + tunertype = 1; + return V4L2_STD_NTSC_M_JP; + case 'k': + case 'K': + tunertype = 1; + return V4L2_STD_NTSC_M_KR; + case '-': + break; + default: + IVTV_WARN("ntsc= argument not recognised\n"); + return 0; + } + + /* no match found */ + return 0; +} + +static void ivtv_process_options(struct ivtv *itv) +{ + const char *chipname; + int i, j; + + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; + itv->options.cardtype = cardtype[itv->instance]; + itv->options.tuner = tuner[itv->instance]; + itv->options.radio = radio[itv->instance]; + + itv->options.i2c_clock_period = i2c_clock_period[itv->instance]; + if (itv->options.i2c_clock_period == -1) + itv->options.i2c_clock_period = IVTV_DEFAULT_I2C_CLOCK_PERIOD; + else if (itv->options.i2c_clock_period < 10) + itv->options.i2c_clock_period = 10; + else if (itv->options.i2c_clock_period > 4500) + itv->options.i2c_clock_period = 4500; + + itv->options.newi2c = newi2c; + if (tunertype < -1 || tunertype > 1) { + IVTV_WARN("Invalid tunertype argument, will autodetect instead\n"); + tunertype = -1; + } + itv->std = ivtv_parse_std(itv); + if (itv->std == 0 && tunertype >= 0) + itv->std = tunertype ? V4L2_STD_MN : (V4L2_STD_ALL & ~V4L2_STD_MN); + itv->has_cx23415 = (itv->pdev->device == PCI_DEVICE_ID_IVTV15); + chipname = itv->has_cx23415 ? "cx23415" : "cx23416"; + if (itv->options.cardtype == -1) { + IVTV_INFO("Ignore card (detected %s based chip)\n", chipname); + return; + } + if ((itv->card = ivtv_get_card(itv->options.cardtype - 1))) { + IVTV_INFO("User specified %s card (detected %s based chip)\n", + itv->card->name, chipname); + } else if (itv->options.cardtype != 0) { + IVTV_ERR("Unknown user specified type, trying to autodetect card\n"); + } + if (itv->card == NULL) { + if (itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE || + itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 || + itv->pdev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) { + itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150); + IVTV_INFO("Autodetected Hauppauge card (%s based)\n", + chipname); + } + } + if (itv->card == NULL) { + for (i = 0; (itv->card = ivtv_get_card(i)); i++) { + if (itv->card->pci_list == NULL) + continue; + for (j = 0; itv->card->pci_list[j].device; j++) { + if (itv->pdev->device != + itv->card->pci_list[j].device) + continue; + if (itv->pdev->subsystem_vendor != + itv->card->pci_list[j].subsystem_vendor) + continue; + if (itv->pdev->subsystem_device != + itv->card->pci_list[j].subsystem_device) + continue; + IVTV_INFO("Autodetected %s card (%s based)\n", + itv->card->name, chipname); + goto done; + } + } + } +done: + + if (itv->card == NULL) { + itv->card = ivtv_get_card(IVTV_CARD_PVR_150); + IVTV_ERR("Unknown card: vendor/device: [%04x:%04x]\n", + itv->pdev->vendor, itv->pdev->device); + IVTV_ERR(" subsystem vendor/device: [%04x:%04x]\n", + itv->pdev->subsystem_vendor, itv->pdev->subsystem_device); + IVTV_ERR(" %s based\n", chipname); + IVTV_ERR("Defaulting to %s card\n", itv->card->name); + IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); + IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); + IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n"); + } + itv->v4l2_cap = itv->card->v4l2_capabilities; + itv->card_name = itv->card->name; + itv->card_i2c = itv->card->i2c; +} + +/* Precondition: the ivtv structure has been memset to 0. Only + the dev and num fields have been filled in. + No assumptions on the card type may be made here (see ivtv_init_struct2 + for that). + */ +static int __devinit ivtv_init_struct1(struct ivtv *itv) +{ + struct sched_param param = { .sched_priority = 99 }; + + itv->base_addr = pci_resource_start(itv->pdev, 0); + itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ + itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ + + mutex_init(&itv->serialize_lock); + mutex_init(&itv->i2c_bus_lock); + mutex_init(&itv->udma.lock); + + spin_lock_init(&itv->lock); + spin_lock_init(&itv->dma_reg_lock); + + init_kthread_worker(&itv->irq_worker); + itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker, + itv->v4l2_dev.name); + if (IS_ERR(itv->irq_worker_task)) { + IVTV_ERR("Could not create ivtv task\n"); + return -1; + } + /* must use the FIFO scheduler as it is realtime sensitive */ + sched_setscheduler(itv->irq_worker_task, SCHED_FIFO, ¶m); + + init_kthread_work(&itv->irq_work, ivtv_irq_work_handler); + + /* start counting open_id at 1 */ + itv->open_id = 1; + + /* Initial settings */ + itv->cxhdl.port = CX2341X_PORT_MEMORY; + itv->cxhdl.capabilities = CX2341X_CAP_HAS_SLICED_VBI; + init_waitqueue_head(&itv->eos_waitq); + init_waitqueue_head(&itv->event_waitq); + init_waitqueue_head(&itv->vsync_waitq); + init_waitqueue_head(&itv->dma_waitq); + init_timer(&itv->dma_timer); + itv->dma_timer.function = ivtv_unfinished_dma; + itv->dma_timer.data = (unsigned long)itv; + + itv->cur_dma_stream = -1; + itv->cur_pio_stream = -1; + itv->audio_stereo_mode = AUDIO_STEREO; + itv->audio_bilingual_mode = AUDIO_MONO_LEFT; + + /* Ctrls */ + itv->speed = 1000; + + /* VBI */ + itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; + itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced; + + /* Init the sg table for osd/yuv output */ + sg_init_table(itv->udma.SGlist, IVTV_DMA_SG_OSD_ENT); + + /* OSD */ + itv->osd_global_alpha_state = 1; + itv->osd_global_alpha = 255; + + /* YUV */ + atomic_set(&itv->yuv_info.next_dma_frame, -1); + itv->yuv_info.lace_mode = ivtv_yuv_mode; + itv->yuv_info.lace_threshold = ivtv_yuv_threshold; + itv->yuv_info.max_frames_buffered = 3; + itv->yuv_info.track_osd = 1; + return 0; +} + +/* Second initialization part. Here the card type has been + autodetected. */ +static void __devinit ivtv_init_struct2(struct ivtv *itv) +{ + int i; + + for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++) + if (itv->card->video_inputs[i].video_type == 0) + break; + itv->nof_inputs = i; + for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++) + if (itv->card->audio_inputs[i].audio_type == 0) + break; + itv->nof_audio_inputs = i; + + if (itv->card->hw_all & IVTV_HW_CX25840) { + itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */ + } else { + itv->vbi.sliced_size = 64; /* multiple of 16, real size = 52 */ + } + + /* Find tuner input */ + for (i = 0; i < itv->nof_inputs; i++) { + if (itv->card->video_inputs[i].video_type == + IVTV_CARD_INPUT_VID_TUNER) + break; + } + if (i == itv->nof_inputs) + i = 0; + itv->active_input = i; + itv->audio_input = itv->card->video_inputs[i].audio_index; +} + +static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, + const struct pci_device_id *pci_id) +{ + u16 cmd; + unsigned char pci_latency; + + IVTV_DEBUG_INFO("Enabling pci device\n"); + + if (pci_enable_device(pdev)) { + IVTV_ERR("Can't enable device!\n"); + return -EIO; + } + if (pci_set_dma_mask(pdev, 0xffffffff)) { + IVTV_ERR("No suitable DMA available.\n"); + return -EIO; + } + if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) { + IVTV_ERR("Cannot request encoder memory region.\n"); + return -EIO; + } + + if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET, + IVTV_REG_SIZE, "ivtv registers")) { + IVTV_ERR("Cannot request register memory region.\n"); + release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); + return -EIO; + } + + if (itv->has_cx23415 && + !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, + IVTV_DECODER_SIZE, "ivtv decoder")) { + IVTV_ERR("Cannot request decoder memory region.\n"); + release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); + release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); + return -EIO; + } + + /* Check for bus mastering */ + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_MASTER)) { + IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n"); + pci_set_master(pdev); + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_MASTER)) { + IVTV_ERR("Bus Mastering is not enabled\n"); + return -ENXIO; + } + } + IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); + + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + + if (pci_latency < 64 && ivtv_pci_latency) { + IVTV_INFO("Unreasonably low latency timer, " + "setting to 64 (was %d)\n", pci_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + } + /* This config space value relates to DMA latencies. The + default value 0x8080 is too low however and will lead + to DMA errors. 0xffff is the max value which solves + these problems. */ + pci_write_config_dword(pdev, 0x40, 0xffff); + + IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " + "irq: %d, latency: %d, memory: 0x%lx\n", + pdev->device, pdev->revision, pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + pdev->irq, pci_latency, (unsigned long)itv->base_addr); + + return 0; +} + +static void ivtv_load_and_init_modules(struct ivtv *itv) +{ + u32 hw = itv->card->hw_all; + unsigned i; + + /* check which i2c devices are actually found */ + for (i = 0; i < 32; i++) { + u32 device = 1 << i; + + if (!(device & hw)) + continue; + if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) { + /* GPIO and TVEEPROM do not use i2c probing */ + itv->hw_flags |= device; + continue; + } + if (ivtv_i2c_register(itv, i) == 0) + itv->hw_flags |= device; + } + + /* probe for legacy IR controllers that aren't in card definitions */ + if ((itv->hw_flags & IVTV_HW_IR_ANY) == 0) + ivtv_i2c_new_ir_legacy(itv); + + if (itv->card->hw_all & IVTV_HW_CX25840) + itv->sd_video = ivtv_find_hw(itv, IVTV_HW_CX25840); + else if (itv->card->hw_all & IVTV_HW_SAA717X) + itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA717X); + else if (itv->card->hw_all & IVTV_HW_SAA7114) + itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7114); + else + itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7115); + itv->sd_audio = ivtv_find_hw(itv, itv->card->hw_audio_ctrl); + itv->sd_muxer = ivtv_find_hw(itv, itv->card->hw_muxer); + + hw = itv->hw_flags; + + if (itv->card->type == IVTV_CARD_CX23416GYC) { + /* Several variations of this card exist, detect which card + type should be used. */ + if ((hw & (IVTV_HW_UPD64031A | IVTV_HW_UPD6408X)) == 0) + itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGRYCS); + else if ((hw & IVTV_HW_UPD64031A) == 0) + itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR); + } + else if (itv->card->type == IVTV_CARD_GV_MVPRX || + itv->card->type == IVTV_CARD_GV_MVPRX2E) { + /* The crystal frequency of GVMVPRX is 24.576MHz */ + v4l2_subdev_call(itv->sd_video, video, s_crystal_freq, + SAA7115_FREQ_24_576_MHZ, SAA7115_FREQ_FL_UCGC); + } + + if (hw & IVTV_HW_CX25840) { + itv->vbi.raw_decoder_line_size = 1444; + itv->vbi.raw_decoder_sav_odd_field = 0x20; + itv->vbi.raw_decoder_sav_even_field = 0x60; + itv->vbi.sliced_decoder_line_size = 272; + itv->vbi.sliced_decoder_sav_odd_field = 0xB0; + itv->vbi.sliced_decoder_sav_even_field = 0xF0; + } + + if (hw & IVTV_HW_SAA711X) { + struct v4l2_dbg_chip_ident v; + + /* determine the exact saa711x model */ + itv->hw_flags &= ~IVTV_HW_SAA711X; + + v.match.type = V4L2_CHIP_MATCH_I2C_DRIVER; + strlcpy(v.match.name, "saa7115", sizeof(v.match.name)); + ivtv_call_hw(itv, IVTV_HW_SAA711X, core, g_chip_ident, &v); + if (v.ident == V4L2_IDENT_SAA7114) { + itv->hw_flags |= IVTV_HW_SAA7114; + /* VBI is not yet supported by the saa7114 driver. */ + itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE); + } else { + itv->hw_flags |= IVTV_HW_SAA7115; + } + itv->vbi.raw_decoder_line_size = 1443; + itv->vbi.raw_decoder_sav_odd_field = 0x25; + itv->vbi.raw_decoder_sav_even_field = 0x62; + itv->vbi.sliced_decoder_line_size = 51; + itv->vbi.sliced_decoder_sav_odd_field = 0xAB; + itv->vbi.sliced_decoder_sav_even_field = 0xEC; + } + + if (hw & IVTV_HW_SAA717X) { + itv->vbi.raw_decoder_line_size = 1443; + itv->vbi.raw_decoder_sav_odd_field = 0x25; + itv->vbi.raw_decoder_sav_even_field = 0x62; + itv->vbi.sliced_decoder_line_size = 51; + itv->vbi.sliced_decoder_sav_odd_field = 0xAB; + itv->vbi.sliced_decoder_sav_even_field = 0xEC; + } +} + +static int __devinit ivtv_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_id) +{ + int retval = 0; + int vbi_buf_size; + struct ivtv *itv; + + itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC); + if (itv == NULL) + return -ENOMEM; + itv->pdev = pdev; + itv->instance = v4l2_device_set_name(&itv->v4l2_dev, "ivtv", + &ivtv_instance); + + retval = v4l2_device_register(&pdev->dev, &itv->v4l2_dev); + if (retval) { + kfree(itv); + return retval; + } + IVTV_INFO("Initializing card %d\n", itv->instance); + + ivtv_process_options(itv); + if (itv->options.cardtype == -1) { + retval = -ENODEV; + goto err; + } + if (ivtv_init_struct1(itv)) { + retval = -ENOMEM; + goto err; + } + retval = cx2341x_handler_init(&itv->cxhdl, 50); + if (retval) + goto err; + itv->v4l2_dev.ctrl_handler = &itv->cxhdl.hdl; + itv->cxhdl.ops = &ivtv_cxhdl_ops; + itv->cxhdl.priv = itv; + itv->cxhdl.func = ivtv_api_func; + + IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); + + /* PCI Device Setup */ + retval = ivtv_setup_pci(itv, pdev, pci_id); + if (retval == -EIO) + goto free_worker; + if (retval == -ENXIO) + goto free_mem; + + /* map io memory */ + IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", + itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); + itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET, + IVTV_ENCODER_SIZE); + if (!itv->enc_mem) { + IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 " + "encoder memory\n"); + IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of " + "vmalloc address space for this window\n"); + IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); + IVTV_ERR("Use the vmalloc= kernel command line option to set " + "VmallocTotal to a larger value\n"); + retval = -ENOMEM; + goto free_mem; + } + + if (itv->has_cx23415) { + IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", + itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); + itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET, + IVTV_DECODER_SIZE); + if (!itv->dec_mem) { + IVTV_ERR("ioremap failed. Can't get a window into " + "CX23415 decoder memory\n"); + IVTV_ERR("Each capture card with a CX23415 needs 8 MB " + "of vmalloc address space for this window\n"); + IVTV_ERR("Check the output of 'grep Vmalloc " + "/proc/meminfo'\n"); + IVTV_ERR("Use the vmalloc= kernel command line option " + "to set VmallocTotal to a larger value\n"); + retval = -ENOMEM; + goto free_mem; + } + } + else { + itv->dec_mem = itv->enc_mem; + } + + /* map registers memory */ + IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", + itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); + itv->reg_mem = + ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); + if (!itv->reg_mem) { + IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 " + "register space\n"); + IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of " + "vmalloc address space for this window\n"); + IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); + IVTV_ERR("Use the vmalloc= kernel command line option to set " + "VmallocTotal to a larger value\n"); + retval = -ENOMEM; + goto free_io; + } + + retval = ivtv_gpio_init(itv); + if (retval) + goto free_io; + + /* active i2c */ + IVTV_DEBUG_INFO("activating i2c...\n"); + if (init_ivtv_i2c(itv)) { + IVTV_ERR("Could not initialize i2c\n"); + goto free_io; + } + + if (itv->card->hw_all & IVTV_HW_TVEEPROM) { + /* Based on the model number the cardtype may be changed. + The PCI IDs are not always reliable. */ + ivtv_process_eeprom(itv); + } + if (itv->card->comment) + IVTV_INFO("%s", itv->card->comment); + if (itv->card->v4l2_capabilities == 0) { + /* card was detected but is not supported */ + retval = -ENODEV; + goto free_i2c; + } + + if (itv->std == 0) { + itv->std = V4L2_STD_NTSC_M; + } + + if (itv->options.tuner == -1) { + int i; + + for (i = 0; i < IVTV_CARD_MAX_TUNERS; i++) { + if ((itv->std & itv->card->tuners[i].std) == 0) + continue; + itv->options.tuner = itv->card->tuners[i].tuner; + break; + } + } + /* if no tuner was found, then pick the first tuner in the card list */ + if (itv->options.tuner == -1 && itv->card->tuners[0].std) { + itv->std = itv->card->tuners[0].std; + if (itv->std & V4L2_STD_PAL) + itv->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + else if (itv->std & V4L2_STD_NTSC) + itv->std = V4L2_STD_NTSC_M; + else if (itv->std & V4L2_STD_SECAM) + itv->std = V4L2_STD_SECAM_L; + itv->options.tuner = itv->card->tuners[0].tuner; + } + if (itv->options.radio == -1) + itv->options.radio = (itv->card->radio_input.audio_type != 0); + + /* The card is now fully identified, continue with card-specific + initialization. */ + ivtv_init_struct2(itv); + + ivtv_load_and_init_modules(itv); + + if (itv->std & V4L2_STD_525_60) { + itv->is_60hz = 1; + itv->is_out_60hz = 1; + } else { + itv->is_50hz = 1; + itv->is_out_50hz = 1; + } + + itv->yuv_info.osd_full_w = 720; + itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480; + itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w; + itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h; + + cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz); + + itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; + itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200; + itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000; + itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000; + itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000; + + /* Setup VBI Raw Size. Should be big enough to hold PAL. + It is possible to switch between PAL and NTSC, so we need to + take the largest size here. */ + /* 1456 is multiple of 16, real size = 1444 */ + itv->vbi.raw_size = 1456; + /* We use a buffer size of 1/2 of the total size needed for a + frame. This is actually very useful, since we now receive + a field at a time and that makes 'compressing' the raw data + down to size by stripping off the SAV codes a lot easier. + Note: having two different buffer sizes prevents standard + switching on the fly. We need to find a better solution... */ + vbi_buf_size = itv->vbi.raw_size * (itv->is_60hz ? 24 : 36) / 2; + itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_VBI] = vbi_buf_size; + itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_VBI] = sizeof(struct v4l2_sliced_vbi_data) * 36; + + if (itv->options.radio > 0) + itv->v4l2_cap |= V4L2_CAP_RADIO; + + if (itv->options.tuner > -1) { + struct tuner_setup setup; + + setup.addr = ADDR_UNSET; + setup.type = itv->options.tuner; + setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + setup.tuner_callback = (setup.type == TUNER_XC2028) ? + ivtv_reset_tuner_gpio : NULL; + ivtv_call_all(itv, tuner, s_type_addr, &setup); + if (setup.type == TUNER_XC2028) { + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + }; + struct v4l2_priv_tun_config cfg = { + .tuner = itv->options.tuner, + .priv = &ctrl, + }; + ivtv_call_all(itv, tuner, s_config, &cfg); + } + } + + /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) + are not. */ + itv->tuner_std = itv->std; + + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_call_all(itv, video, s_std_output, itv->std); + /* Turn off the output signal. The mpeg decoder is not yet + active so without this you would get a green image until the + mpeg decoder becomes active. */ + ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0); + } + + /* clear interrupt mask, effectively disabling interrupts */ + ivtv_set_irq_mask(itv, 0xffffffff); + + /* Register IRQ */ + retval = request_irq(itv->pdev->irq, ivtv_irq_handler, + IRQF_SHARED | IRQF_DISABLED, itv->v4l2_dev.name, (void *)itv); + if (retval) { + IVTV_ERR("Failed to register irq %d\n", retval); + goto free_i2c; + } + + retval = ivtv_streams_setup(itv); + if (retval) { + IVTV_ERR("Error %d setting up streams\n", retval); + goto free_irq; + } + retval = ivtv_streams_register(itv); + if (retval) { + IVTV_ERR("Error %d registering devices\n", retval); + goto free_streams; + } + IVTV_INFO("Initialized card: %s\n", itv->card_name); + return 0; + +free_streams: + ivtv_streams_cleanup(itv, 1); +free_irq: + free_irq(itv->pdev->irq, (void *)itv); +free_i2c: + exit_ivtv_i2c(itv); +free_io: + ivtv_iounmap(itv); +free_mem: + release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); + release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); + if (itv->has_cx23415) + release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); +free_worker: + kthread_stop(itv->irq_worker_task); +err: + if (retval == 0) + retval = -ENODEV; + IVTV_ERR("Error %d on initialization\n", retval); + + v4l2_device_unregister(&itv->v4l2_dev); + kfree(itv); + return retval; +} + +int ivtv_init_on_first_open(struct ivtv *itv) +{ + struct v4l2_frequency vf; + /* Needed to call ioctls later */ + struct ivtv_open_id fh; + int fw_retry_count = 3; + int video_input; + + fh.itv = itv; + + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) + return -ENXIO; + + if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) + return 0; + + while (--fw_retry_count > 0) { + /* load firmware */ + if (ivtv_firmware_init(itv) == 0) + break; + if (fw_retry_count > 1) + IVTV_WARN("Retry loading firmware\n"); + } + + if (fw_retry_count == 0) { + set_bit(IVTV_F_I_FAILED, &itv->i_flags); + return -ENXIO; + } + + /* Try and get firmware versions */ + IVTV_DEBUG_INFO("Getting firmware version..\n"); + ivtv_firmware_versions(itv); + + if (itv->card->hw_all & IVTV_HW_CX25840) + v4l2_subdev_call(itv->sd_video, core, load_fw); + + vf.tuner = 0; + vf.type = V4L2_TUNER_ANALOG_TV; + vf.frequency = 6400; /* the tuner 'baseline' frequency */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (itv->std == V4L2_STD_NTSC_M_JP) { + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + } + else if (itv->std & V4L2_STD_NTSC_M) { + vf.frequency = 1076; /* ch. 4 67250*16/1000 */ + } + + video_input = itv->active_input; + itv->active_input++; /* Force update of input */ + ivtv_s_input(NULL, &fh, video_input); + + /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code + in one place. */ + itv->std++; /* Force full standard initialization */ + itv->std_out = itv->std; + ivtv_s_frequency(NULL, &fh, &vf); + + if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { + /* Turn on the TV-out: ivtv_init_mpeg_decoder() initializes + the mpeg decoder so now the saa7127 receives a proper + signal. */ + ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1); + ivtv_init_mpeg_decoder(itv); + } + + /* On a cx23416 this seems to be able to enable DMA to the chip? */ + if (!itv->has_cx23415) + write_reg_sync(0x03, IVTV_REG_DMACONTROL); + + ivtv_s_std_enc(itv, &itv->tuner_std); + + /* Default interrupts enabled. For the PVR350 this includes the + decoder VSYNC interrupt, which is always on. It is not only used + during decoding but also by the OSD. + Some old PVR250 cards had a cx23415, so testing for that is too + general. Instead test if the card has video output capability. */ + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); + ivtv_set_osd_alpha(itv); + ivtv_s_std_dec(itv, &itv->tuner_std); + } else { + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); + } + + /* Setup initial controls */ + cx2341x_handler_setup(&itv->cxhdl); + return 0; +} + +static void ivtv_remove(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct ivtv *itv = to_ivtv(v4l2_dev); + int i; + + IVTV_DEBUG_INFO("Removing card\n"); + + if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) { + /* Stop all captures */ + IVTV_DEBUG_INFO("Stopping all streams\n"); + if (atomic_read(&itv->capturing) > 0) + ivtv_stop_all_captures(itv); + + /* Stop all decoding */ + IVTV_DEBUG_INFO("Stopping decoding\n"); + + /* Turn off the TV-out */ + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) + ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0); + if (atomic_read(&itv->decoding) > 0) { + int type; + + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + type = IVTV_DEC_STREAM_TYPE_YUV; + else + type = IVTV_DEC_STREAM_TYPE_MPG; + ivtv_stop_v4l2_decode_stream(&itv->streams[type], + VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); + } + ivtv_halt_firmware(itv); + } + + /* Interrupts */ + ivtv_set_irq_mask(itv, 0xffffffff); + del_timer_sync(&itv->dma_timer); + + /* Kill irq worker */ + flush_kthread_worker(&itv->irq_worker); + kthread_stop(itv->irq_worker_task); + + ivtv_streams_cleanup(itv, 1); + ivtv_udma_free(itv); + + exit_ivtv_i2c(itv); + + free_irq(itv->pdev->irq, (void *)itv); + ivtv_iounmap(itv); + + release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); + release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); + if (itv->has_cx23415) + release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); + + pci_disable_device(itv->pdev); + for (i = 0; i < IVTV_VBI_FRAMES; i++) + kfree(itv->vbi.sliced_mpeg_data[i]); + + printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name); + + v4l2_device_unregister(&itv->v4l2_dev); + kfree(itv); +} + +/* define a pci_driver for card detection */ +static struct pci_driver ivtv_pci_driver = { + .name = "ivtv", + .id_table = ivtv_pci_tbl, + .probe = ivtv_probe, + .remove = ivtv_remove, +}; + +static int __init module_start(void) +{ + printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION); + + /* Validate parameters */ + if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n", + IVTV_MAX_CARDS - 1); + return -1; + } + + if (ivtv_debug < 0 || ivtv_debug > 2047) { + ivtv_debug = 0; + printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n"); + } + + if (pci_register_driver(&ivtv_pci_driver)) { + printk(KERN_ERR "ivtv: Error detecting PCI card\n"); + return -ENODEV; + } + printk(KERN_INFO "ivtv: End initialization\n"); + return 0; +} + +static void __exit module_cleanup(void) +{ + pci_unregister_driver(&ivtv_pci_driver); +} + +/* Note: These symbols are exported because they are used by the ivtvfb + framebuffer module and an infrared module for the IR-blaster. */ +EXPORT_SYMBOL(ivtv_set_irq_mask); +EXPORT_SYMBOL(ivtv_api); +EXPORT_SYMBOL(ivtv_vapi); +EXPORT_SYMBOL(ivtv_vapi_result); +EXPORT_SYMBOL(ivtv_clear_irq_mask); +EXPORT_SYMBOL(ivtv_debug); +#ifdef CONFIG_VIDEO_ADV_DEBUG +EXPORT_SYMBOL(ivtv_fw_debug); +#endif +EXPORT_SYMBOL(ivtv_reset_ir_gpio); +EXPORT_SYMBOL(ivtv_udma_setup); +EXPORT_SYMBOL(ivtv_udma_unmap); +EXPORT_SYMBOL(ivtv_udma_alloc); +EXPORT_SYMBOL(ivtv_udma_prepare); +EXPORT_SYMBOL(ivtv_init_on_first_open); +EXPORT_SYMBOL(ivtv_firmware_check); + +module_init(module_start); +module_exit(module_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-driver.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-driver.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-driver.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-driver.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,832 @@ +/* + ivtv driver internal defines and structures + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_DRIVER_H +#define IVTV_DRIVER_H + +/* Internal header for ivtv project: + * Driver for the cx23415/6 chip. + * Author: Kevin Thayer (nufan_wfk at yahoo.com) + * License: GPL + * http://www.ivtvdriver.org + * + * ----- + * MPG600/MPG160 support by T.Adachi + * and Takeru KOMORIYA + * + * AVerMedia M179 GPIO info by Chris Pinkham + * using information provided by Jiun-Kuei Jung @ AVerMedia. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Memory layout */ +#define IVTV_ENCODER_OFFSET 0x00000000 +#define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ +#define IVTV_DECODER_OFFSET 0x01000000 +#define IVTV_DECODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ +#define IVTV_REG_OFFSET 0x02000000 +#define IVTV_REG_SIZE 0x00010000 + +/* Maximum ivtv driver instances. Some people have a huge number of + capture cards, so set this to a high value. */ +#define IVTV_MAX_CARDS 32 + +#define IVTV_ENC_STREAM_TYPE_MPG 0 +#define IVTV_ENC_STREAM_TYPE_YUV 1 +#define IVTV_ENC_STREAM_TYPE_VBI 2 +#define IVTV_ENC_STREAM_TYPE_PCM 3 +#define IVTV_ENC_STREAM_TYPE_RAD 4 +#define IVTV_DEC_STREAM_TYPE_MPG 5 +#define IVTV_DEC_STREAM_TYPE_VBI 6 +#define IVTV_DEC_STREAM_TYPE_VOUT 7 +#define IVTV_DEC_STREAM_TYPE_YUV 8 +#define IVTV_MAX_STREAMS 9 + +#define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */ + +/* DMA Registers */ +#define IVTV_REG_DMAXFER (0x0000) +#define IVTV_REG_DMASTATUS (0x0004) +#define IVTV_REG_DECDMAADDR (0x0008) +#define IVTV_REG_ENCDMAADDR (0x000c) +#define IVTV_REG_DMACONTROL (0x0010) +#define IVTV_REG_IRQSTATUS (0x0040) +#define IVTV_REG_IRQMASK (0x0048) + +/* Setup Registers */ +#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) +#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) +#define IVTV_REG_DEC_SDRAM_REFRESH (0x08F8) +#define IVTV_REG_DEC_SDRAM_PRECHARGE (0x08FC) +#define IVTV_REG_VDM (0x2800) +#define IVTV_REG_AO (0x2D00) +#define IVTV_REG_BYTEFLUSH (0x2D24) +#define IVTV_REG_SPU (0x9050) +#define IVTV_REG_HW_BLOCKS (0x9054) +#define IVTV_REG_VPU (0x9058) +#define IVTV_REG_APU (0xA064) + +/* Other registers */ +#define IVTV_REG_DEC_LINE_FIELD (0x28C0) + +/* debugging */ +extern int ivtv_debug; +#ifdef CONFIG_VIDEO_ADV_DEBUG +extern int ivtv_fw_debug; +#endif + +#define IVTV_DBGFLG_WARN (1 << 0) +#define IVTV_DBGFLG_INFO (1 << 1) +#define IVTV_DBGFLG_MB (1 << 2) +#define IVTV_DBGFLG_IOCTL (1 << 3) +#define IVTV_DBGFLG_FILE (1 << 4) +#define IVTV_DBGFLG_DMA (1 << 5) +#define IVTV_DBGFLG_IRQ (1 << 6) +#define IVTV_DBGFLG_DEC (1 << 7) +#define IVTV_DBGFLG_YUV (1 << 8) +#define IVTV_DBGFLG_I2C (1 << 9) +/* Flag to turn on high volume debugging */ +#define IVTV_DBGFLG_HIGHVOL (1 << 10) + +#define IVTV_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & ivtv_debug) \ + v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args); \ + } while (0) +#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_MB(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define IVTV_DEBUG_FILE(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) + +#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \ + do { \ + if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \ + v4l2_info(&itv->v4l2_dev, " " type ": " fmt , ##args); \ + } while (0) +#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_HI_MB(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define IVTV_DEBUG_HI_FILE(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) + +/* Standard kernel messages */ +#define IVTV_ERR(fmt, args...) v4l2_err(&itv->v4l2_dev, fmt , ## args) +#define IVTV_WARN(fmt, args...) v4l2_warn(&itv->v4l2_dev, fmt , ## args) +#define IVTV_INFO(fmt, args...) v4l2_info(&itv->v4l2_dev, fmt , ## args) + +/* output modes (cx23415 only) */ +#define OUT_NONE 0 +#define OUT_MPG 1 +#define OUT_YUV 2 +#define OUT_UDMA_YUV 3 +#define OUT_PASSTHROUGH 4 + +#define IVTV_MAX_PGM_INDEX (400) + +/* Default I2C SCL period in microseconds */ +#define IVTV_DEFAULT_I2C_CLOCK_PERIOD 20 + +struct ivtv_options { + int kilobytes[IVTV_MAX_STREAMS]; /* size in kilobytes of each stream */ + int cardtype; /* force card type on load */ + int tuner; /* set tuner on load */ + int radio; /* enable/disable radio */ + int newi2c; /* new I2C algorithm */ + int i2c_clock_period; /* period of SCL for I2C bus */ +}; + +/* ivtv-specific mailbox template */ +struct ivtv_mailbox { + u32 flags; + u32 cmd; + u32 retval; + u32 timeout; + u32 data[CX2341X_MBOX_MAX_DATA]; +}; + +struct ivtv_api_cache { + unsigned long last_jiffies; /* when last command was issued */ + u32 data[CX2341X_MBOX_MAX_DATA]; /* last sent api data */ +}; + +struct ivtv_mailbox_data { + volatile struct ivtv_mailbox __iomem *mbox; + /* Bits 0-2 are for the encoder mailboxes, 0-1 are for the decoder mailboxes. + If the bit is set, then the corresponding mailbox is in use by the driver. */ + unsigned long busy; + u8 max_mbox; +}; + +/* per-buffer bit flags */ +#define IVTV_F_B_NEED_BUF_SWAP (1 << 0) /* this buffer should be byte swapped */ + +/* per-stream, s_flags */ +#define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ +#define IVTV_F_S_DMA_HAS_VBI 1 /* the current DMA request also requests VBI data */ +#define IVTV_F_S_NEEDS_DATA 2 /* this decoding stream needs more data */ + +#define IVTV_F_S_CLAIMED 3 /* this stream is claimed */ +#define IVTV_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ +#define IVTV_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ +#define IVTV_F_S_PASSTHROUGH 6 /* this stream is in passthrough mode */ +#define IVTV_F_S_STREAMOFF 7 /* signal end of stream EOS */ +#define IVTV_F_S_APPL_IO 8 /* this stream is used read/written by an application */ + +#define IVTV_F_S_PIO_PENDING 9 /* this stream has pending PIO */ +#define IVTV_F_S_PIO_HAS_VBI 1 /* the current PIO request also requests VBI data */ + +/* per-ivtv, i_flags */ +#define IVTV_F_I_DMA 0 /* DMA in progress */ +#define IVTV_F_I_UDMA 1 /* UDMA in progress */ +#define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */ +#define IVTV_F_I_SPEED_CHANGE 3 /* a speed change is in progress */ +#define IVTV_F_I_EOS 4 /* end of encoder stream reached */ +#define IVTV_F_I_RADIO_USER 5 /* the radio tuner is selected */ +#define IVTV_F_I_DIG_RST 6 /* reset digitizer */ +#define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ +#define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ +#define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ +#define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */ +#define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */ +#define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */ +#define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */ +#define IVTV_F_I_HAVE_WORK 15 /* used in the interrupt handler: there is work to be done */ +#define IVTV_F_I_WORK_HANDLER_VBI 16 /* there is work to be done for VBI */ +#define IVTV_F_I_WORK_HANDLER_YUV 17 /* there is work to be done for YUV */ +#define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */ +#define IVTV_F_I_PIO 19 /* PIO in progress */ +#define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ +#define IVTV_F_I_INITED 21 /* set after first open */ +#define IVTV_F_I_FAILED 22 /* set if first open failed */ + +/* Event notifications */ +#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ +#define IVTV_F_I_EV_VSYNC 29 /* VSYNC event */ +#define IVTV_F_I_EV_VSYNC_FIELD 30 /* VSYNC event field (0 = first, 1 = second field) */ +#define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */ + +/* Scatter-Gather array element, used in DMA transfers */ +struct ivtv_sg_element { + __le32 src; + __le32 dst; + __le32 size; +}; + +struct ivtv_sg_host_element { + u32 src; + u32 dst; + u32 size; +}; + +struct ivtv_user_dma { + struct mutex lock; + int page_count; + struct page *map[IVTV_DMA_SG_OSD_ENT]; + /* Needed when dealing with highmem userspace buffers */ + struct page *bouncemap[IVTV_DMA_SG_OSD_ENT]; + + /* Base Dev SG Array for cx23415/6 */ + struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; + dma_addr_t SG_handle; + int SG_length; + + /* SG List of Buffers */ + struct scatterlist SGlist[IVTV_DMA_SG_OSD_ENT]; +}; + +struct ivtv_dma_page_info { + unsigned long uaddr; + unsigned long first; + unsigned long last; + unsigned int offset; + unsigned int tail; + int page_count; +}; + +struct ivtv_buffer { + struct list_head list; + dma_addr_t dma_handle; + unsigned short b_flags; + unsigned short dma_xfer_cnt; + char *buf; + u32 bytesused; + u32 readpos; +}; + +struct ivtv_queue { + struct list_head list; /* the list of buffers in this queue */ + u32 buffers; /* number of buffers in this queue */ + u32 length; /* total number of bytes of available buffer space */ + u32 bytesused; /* total number of bytes used in this queue */ +}; + +struct ivtv; /* forward reference */ + +struct ivtv_stream { + /* These first four fields are always set, even if the stream + is not actually created. */ + struct video_device *vdev; /* NULL when stream not created */ + struct ivtv *itv; /* for ease of use */ + const char *name; /* name of the stream */ + int type; /* stream type */ + + u32 id; + spinlock_t qlock; /* locks access to the queues */ + unsigned long s_flags; /* status flags, see above */ + int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ + u32 pending_offset; + u32 pending_backup; + u64 pending_pts; + + u32 dma_offset; + u32 dma_backup; + u64 dma_pts; + + int subtype; + wait_queue_head_t waitq; + u32 dma_last_offset; + + /* Buffer Stats */ + u32 buffers; + u32 buf_size; + u32 buffers_stolen; + + /* Buffer Queues */ + struct ivtv_queue q_free; /* free buffers */ + struct ivtv_queue q_full; /* full buffers */ + struct ivtv_queue q_io; /* waiting for I/O */ + struct ivtv_queue q_dma; /* waiting for DMA */ + struct ivtv_queue q_predma; /* waiting for DMA */ + + /* DMA xfer counter, buffers belonging to the same DMA + xfer will have the same dma_xfer_cnt. */ + u16 dma_xfer_cnt; + + /* Base Dev SG Array for cx23415/6 */ + struct ivtv_sg_host_element *sg_pending; + struct ivtv_sg_host_element *sg_processing; + struct ivtv_sg_element *sg_dma; + dma_addr_t sg_handle; + int sg_pending_size; + int sg_processing_size; + int sg_processed; + + /* SG List of Buffers */ + struct scatterlist *SGlist; +}; + +struct ivtv_open_id { + struct v4l2_fh fh; + u32 open_id; /* unique ID for this file descriptor */ + int type; /* stream type */ + int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */ + struct ivtv *itv; +}; + +static inline struct ivtv_open_id *fh2id(struct v4l2_fh *fh) +{ + return container_of(fh, struct ivtv_open_id, fh); +} + +struct yuv_frame_info +{ + u32 update; + s32 src_x; + s32 src_y; + u32 src_w; + u32 src_h; + s32 dst_x; + s32 dst_y; + u32 dst_w; + u32 dst_h; + s32 pan_x; + s32 pan_y; + u32 vis_w; + u32 vis_h; + u32 interlaced_y; + u32 interlaced_uv; + s32 tru_x; + u32 tru_w; + u32 tru_h; + u32 offset_y; + s32 lace_mode; + u32 sync_field; + u32 delay; + u32 interlaced; +}; + +#define IVTV_YUV_MODE_INTERLACED 0x00 +#define IVTV_YUV_MODE_PROGRESSIVE 0x01 +#define IVTV_YUV_MODE_AUTO 0x02 +#define IVTV_YUV_MODE_MASK 0x03 + +#define IVTV_YUV_SYNC_EVEN 0x00 +#define IVTV_YUV_SYNC_ODD 0x04 +#define IVTV_YUV_SYNC_MASK 0x04 + +#define IVTV_YUV_BUFFERS 8 + +struct yuv_playback_info +{ + u32 reg_2834; + u32 reg_2838; + u32 reg_283c; + u32 reg_2840; + u32 reg_2844; + u32 reg_2848; + u32 reg_2854; + u32 reg_285c; + u32 reg_2864; + + u32 reg_2870; + u32 reg_2874; + u32 reg_2890; + u32 reg_2898; + u32 reg_289c; + + u32 reg_2918; + u32 reg_291c; + u32 reg_2920; + u32 reg_2924; + u32 reg_2928; + u32 reg_292c; + u32 reg_2930; + + u32 reg_2934; + + u32 reg_2938; + u32 reg_293c; + u32 reg_2940; + u32 reg_2944; + u32 reg_2948; + u32 reg_294c; + u32 reg_2950; + u32 reg_2954; + u32 reg_2958; + u32 reg_295c; + u32 reg_2960; + u32 reg_2964; + u32 reg_2968; + u32 reg_296c; + + u32 reg_2970; + + int v_filter_1; + int v_filter_2; + int h_filter; + + u8 track_osd; /* Should yuv output track the OSD size & position */ + + u32 osd_x_offset; + u32 osd_y_offset; + + u32 osd_x_pan; + u32 osd_y_pan; + + u32 osd_vis_w; + u32 osd_vis_h; + + u32 osd_full_w; + u32 osd_full_h; + + int decode_height; + + int lace_mode; + int lace_threshold; + int lace_sync_field; + + atomic_t next_dma_frame; + atomic_t next_fill_frame; + + u32 yuv_forced_update; + int update_frame; + + u8 fields_lapsed; /* Counter used when delaying a frame */ + + struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS]; + struct yuv_frame_info old_frame_info; + struct yuv_frame_info old_frame_info_args; + + void *blanking_ptr; + dma_addr_t blanking_dmaptr; + + int stream_size; + + u8 draw_frame; /* PVR350 buffer to draw into */ + u8 max_frames_buffered; /* Maximum number of frames to buffer */ + + struct v4l2_rect main_rect; + u32 v4l2_src_w; + u32 v4l2_src_h; + + u8 running; /* Have any frames been displayed */ +}; + +#define IVTV_VBI_FRAMES 32 + +/* VBI data */ +struct vbi_cc { + u8 odd[2]; /* two-byte payload of odd field */ + u8 even[2]; /* two-byte payload of even field */; +}; + +struct vbi_vps { + u8 data[5]; /* five-byte VPS payload */ +}; + +struct vbi_info { + /* VBI general data, does not change during streaming */ + + u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ + u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */ + u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */ + u32 sliced_decoder_line_size; /* sliced VBI line size from digitizer */ + u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */ + u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */ + + u32 start[2]; /* start of first VBI line in the odd/even fields */ + u32 count; /* number of VBI lines per field */ + u32 raw_size; /* size of raw VBI line from the digitizer */ + u32 sliced_size; /* size of sliced VBI line from the digitizer */ + + u32 dec_start; /* start in decoder memory of VBI re-insertion buffers */ + u32 enc_start; /* start in encoder memory of VBI capture buffers */ + u32 enc_size; /* size of VBI capture area */ + int fpi; /* number of VBI frames per interrupt */ + + struct v4l2_format in; /* current VBI capture format */ + struct v4l2_sliced_vbi_format *sliced_in; /* convenience pointer to sliced struct in vbi.in union */ + int insert_mpeg; /* if non-zero, then embed VBI data in MPEG stream */ + + /* Raw VBI compatibility hack */ + + u32 frame; /* frame counter hack needed for backwards compatibility + of old VBI software */ + + /* Sliced VBI output data */ + + struct vbi_cc cc_payload[256]; /* sliced VBI CC payload array: it is an array to + prevent dropping CC data if they couldn't be + processed fast enough */ + int cc_payload_idx; /* index in cc_payload */ + u8 cc_missing_cnt; /* counts number of frames without CC for passthrough mode */ + int wss_payload; /* sliced VBI WSS payload */ + u8 wss_missing_cnt; /* counts number of frames without WSS for passthrough mode */ + struct vbi_vps vps_payload; /* sliced VBI VPS payload */ + + /* Sliced VBI capture data */ + + struct v4l2_sliced_vbi_data sliced_data[36]; /* sliced VBI storage for VBI encoder stream */ + struct v4l2_sliced_vbi_data sliced_dec_data[36];/* sliced VBI storage for VBI decoder stream */ + + /* VBI Embedding data */ + + /* Buffer for VBI data inserted into MPEG stream. + The first byte is a dummy byte that's never used. + The next 16 bytes contain the MPEG header for the VBI data, + the remainder is the actual VBI data. + The max size accepted by the MPEG VBI reinsertion turns out + to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes, + where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is + a single line header byte and 2 * 18 is the number of VBI lines per frame. + + However, it seems that the data must be 1K aligned, so we have to + pad the data until the 1 or 2 K boundary. + + This pointer array will allocate 2049 bytes to store each VBI frame. */ + u8 *sliced_mpeg_data[IVTV_VBI_FRAMES]; + u32 sliced_mpeg_size[IVTV_VBI_FRAMES]; + struct ivtv_buffer sliced_mpeg_buf; /* temporary buffer holding data from sliced_mpeg_data */ + u32 inserted_frame; /* index in sliced_mpeg_size of next sliced data + to be inserted in the MPEG stream */ +}; + +/* forward declaration of struct defined in ivtv-cards.h */ +struct ivtv_card; + +/* Struct to hold info about ivtv cards */ +struct ivtv { + /* General fixed card data */ + struct pci_dev *pdev; /* PCI device */ + const struct ivtv_card *card; /* card information */ + const char *card_name; /* full name of the card */ + const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ + u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ + u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ + u8 nof_inputs; /* number of video inputs */ + u8 nof_audio_inputs; /* number of audio inputs */ + u32 v4l2_cap; /* V4L2 capabilities of card */ + u32 hw_flags; /* hardware description of the board */ + v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */ + struct v4l2_subdev *sd_video; /* controlling video decoder subdev */ + struct v4l2_subdev *sd_audio; /* controlling audio subdev */ + struct v4l2_subdev *sd_muxer; /* controlling audio muxer subdev */ + u32 base_addr; /* PCI resource base address */ + volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */ + volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */ + volatile void __iomem *reg_mem; /* pointer to mapped registers */ + struct ivtv_options options; /* user options */ + + struct v4l2_device v4l2_dev; + struct cx2341x_handler cxhdl; + struct v4l2_ctrl_handler hdl_gpio; + struct v4l2_subdev sd_gpio; /* GPIO sub-device */ + u16 instance; + + /* High-level state info */ + unsigned long i_flags; /* global ivtv flags */ + u8 is_50hz; /* 1 if the current capture standard is 50 Hz */ + u8 is_60hz /* 1 if the current capture standard is 60 Hz */; + u8 is_out_50hz /* 1 if the current TV output standard is 50 Hz */; + u8 is_out_60hz /* 1 if the current TV output standard is 60 Hz */; + int output_mode; /* decoder output mode: NONE, MPG, YUV, UDMA YUV, passthrough */ + u32 audio_input; /* current audio input */ + u32 active_input; /* current video input */ + u32 active_output; /* current video output */ + v4l2_std_id std; /* current capture TV standard */ + v4l2_std_id std_out; /* current TV output standard */ + u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */ + u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */ + + + /* Locking */ + spinlock_t lock; /* lock access to this struct */ + struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ + + /* Streams */ + int stream_buf_size[IVTV_MAX_STREAMS]; /* stream buffer size */ + struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* stream data */ + atomic_t capturing; /* count number of active capture streams */ + atomic_t decoding; /* count number of active decoding streams */ + + + /* Interrupts & DMA */ + u32 irqmask; /* active interrupts */ + u32 irq_rr_idx; /* round-robin stream index */ + struct kthread_worker irq_worker; /* kthread worker for PIO/YUV/VBI actions */ + struct task_struct *irq_worker_task; /* task for irq_worker */ + struct kthread_work irq_work; /* kthread work entry */ + spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ + int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */ + int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */ + u32 dma_data_req_offset; /* store offset in decoder memory of current DMA request */ + u32 dma_data_req_size; /* store size of current DMA request */ + int dma_retries; /* current DMA retry attempt */ + struct ivtv_user_dma udma; /* user based DMA for OSD */ + struct timer_list dma_timer; /* timer used to catch unfinished DMAs */ + u32 last_vsync_field; /* last seen vsync field */ + wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */ + wait_queue_head_t eos_waitq; /* wake up when EOS arrives */ + wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */ + wait_queue_head_t vsync_waitq; /* wake up when the next decoder vsync arrives */ + + + /* Mailbox */ + struct ivtv_mailbox_data enc_mbox; /* encoder mailboxes */ + struct ivtv_mailbox_data dec_mbox; /* decoder mailboxes */ + struct ivtv_api_cache api_cache[256]; /* cached API commands */ + + + /* I2C */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state; /* i2c bit state */ + struct mutex i2c_bus_lock; /* lock i2c bus */ + + struct IR_i2c_init_data ir_i2c_init_data; + + /* Program Index information */ + u32 pgm_info_offset; /* start of pgm info in encoder memory */ + u32 pgm_info_num; /* number of elements in the pgm cyclic buffer in encoder memory */ + u32 pgm_info_write_idx; /* last index written by the card that was transferred to pgm_info[] */ + u32 pgm_info_read_idx; /* last index in pgm_info read by the application */ + struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; /* filled from the pgm cyclic buffer on the card */ + + + /* Miscellaneous */ + u32 open_id; /* incremented each time an open occurs, is >= 1 */ + int search_pack_header; /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */ + int speed; /* current playback speed setting */ + u8 speed_mute_audio; /* 1 if audio should be muted when fast forward */ + u64 mpg_data_received; /* number of bytes received from the MPEG stream */ + u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */ + u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */ + unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */ + u32 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */ + + + /* VBI state info */ + struct vbi_info vbi; /* VBI-specific data */ + + + /* YUV playback */ + struct yuv_playback_info yuv_info; /* YUV playback data */ + + + /* OSD support */ + unsigned long osd_video_pbase; + int osd_global_alpha_state; /* 1 = global alpha is on */ + int osd_local_alpha_state; /* 1 = local alpha is on */ + int osd_chroma_key_state; /* 1 = chroma-keying is on */ + u8 osd_global_alpha; /* current global alpha */ + u32 osd_chroma_key; /* current chroma key */ + struct v4l2_rect osd_rect; /* current OSD position and size */ + struct v4l2_rect main_rect; /* current Main window position and size */ + struct osd_info *osd_info; /* ivtvfb private OSD info */ + void (*ivtvfb_restore)(struct ivtv *itv); /* Used for a warm start */ +}; + +static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct ivtv, v4l2_dev); +} + +/* Globals */ +extern int ivtv_first_minor; + +/*==============Prototypes==================*/ + +/* Hardware/IRQ */ +void ivtv_set_irq_mask(struct ivtv *itv, u32 mask); +void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask); + +/* try to set output mode, return current mode. */ +int ivtv_set_output_mode(struct ivtv *itv, int mode); + +/* return current output stream based on current mode */ +struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv); + +/* Return non-zero if a signal is pending */ +int ivtv_msleep_timeout(unsigned int msecs, int intr); + +/* Wait on queue, returns -EINTR if interrupted */ +int ivtv_waitq(wait_queue_head_t *waitq); + +/* Read Hauppauge eeprom */ +struct tveeprom; /* forward reference */ +void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv); + +/* First-open initialization: load firmware, init cx25840, etc. */ +int ivtv_init_on_first_open(struct ivtv *itv); + +/* Test if the current VBI mode is raw (1) or sliced (0) */ +static inline int ivtv_raw_vbi(const struct ivtv *itv) +{ + return itv->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE; +} + +/* This is a PCI post thing, where if the pci register is not read, then + the write doesn't always take effect right away. By reading back the + register any pending PCI writes will be performed (in order), and so + you can be sure that the writes are guaranteed to be done. + + Rarely needed, only in some timing sensitive cases. + Apparently if this is not done some motherboards seem + to kill the firmware and get into the broken state until computer is + rebooted. */ +#define write_sync(val, reg) \ + do { writel(val, reg); readl(reg); } while (0) + +#define read_reg(reg) readl(itv->reg_mem + (reg)) +#define write_reg(val, reg) writel(val, itv->reg_mem + (reg)) +#define write_reg_sync(val, reg) \ + do { write_reg(val, reg); read_reg(reg); } while (0) + +#define read_enc(addr) readl(itv->enc_mem + (u32)(addr)) +#define write_enc(val, addr) writel(val, itv->enc_mem + (u32)(addr)) +#define write_enc_sync(val, addr) \ + do { write_enc(val, addr); read_enc(addr); } while (0) + +#define read_dec(addr) readl(itv->dec_mem + (u32)(addr)) +#define write_dec(val, addr) writel(val, itv->dec_mem + (u32)(addr)) +#define write_dec_sync(val, addr) \ + do { write_dec(val, addr); read_dec(addr); } while (0) + +/* Call the specified callback for all subdevs matching hw (if 0, then + match them all). Ignore any errors. */ +#define ivtv_call_hw(itv, hw, o, f, args...) \ + do { \ + struct v4l2_subdev *__sd; \ + __v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd, \ + !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ + } while (0) + +#define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args) + +/* Call the specified callback for all subdevs matching hw (if 0, then + match them all). If the callback returns an error other than 0 or + -ENOIOCTLCMD, then return with that error code. */ +#define ivtv_call_hw_err(itv, hw, o, f, args...) \ +({ \ + struct v4l2_subdev *__sd; \ + __v4l2_device_call_subdevs_until_err_p(&(itv)->v4l2_dev, __sd, \ + !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ +}) + +#define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtvfb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtvfb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtvfb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtvfb.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1317 @@ +/* + On Screen Display cx23415 Framebuffer driver + + This module presents the cx23415 OSD (onscreen display) framebuffer memory + as a standard Linux /dev/fb style framebuffer device. The framebuffer has + support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + mode, there is a choice of a three color depths (12, 15 or 16 bits), but no + local alpha. The colorspace is selectable between rgb & yuv. + Depending on the TV standard configured in the ivtv module at load time, + the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. + Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) + or 59.94 (NTSC) + + Copyright (c) 2003 Matt T. Yourst + + Derived from drivers/video/vesafb.c + Portions (c) 1998 Gerd Knorr + + 2.6 kernel port: + Copyright (C) 2004 Matthias Badaire + + Copyright (C) 2004 Chris Kennedy + + Copyright (C) 2006 Ian Armstrong + + 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, or + (at your option) any later version. + + 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 +#include +#include +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif + +#include "ivtv-driver.h" +#include "ivtv-cards.h" +#include "ivtv-i2c.h" +#include "ivtv-udma.h" +#include "ivtv-mailbox.h" +#include "ivtv-firmware.h" + +/* card parameters */ +static int ivtvfb_card_id = -1; +static int ivtvfb_debug = 0; +static int osd_laced; +static int osd_depth; +static int osd_upper; +static int osd_left; +static int osd_yres; +static int osd_xres; + +module_param(ivtvfb_card_id, int, 0444); +module_param_named(debug,ivtvfb_debug, int, 0644); +module_param(osd_laced, bool, 0444); +module_param(osd_depth, int, 0444); +module_param(osd_upper, int, 0444); +module_param(osd_left, int, 0444); +module_param(osd_yres, int, 0444); +module_param(osd_xres, int, 0444); + +MODULE_PARM_DESC(ivtvfb_card_id, + "Only use framebuffer of the specified ivtv card (0-31)\n" + "\t\t\tdefault -1: initialize all available framebuffers"); + +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: errors only\n" + "\t\t\t(debug = 3 gives full debugging)"); + +/* Why upper, left, xres, yres, depth, laced ? To match terminology used + by fbset. + Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ + +MODULE_PARM_DESC(osd_laced, + "Interlaced mode\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +MODULE_PARM_DESC(osd_depth, + "Bits per pixel - 8, 16, 32\n" + "\t\t\tdefault 8"); + +MODULE_PARM_DESC(osd_upper, + "Vertical start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_left, + "Horizontal start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_yres, + "Display height\n" + "\t\t\tdefault 480 (PAL)\n" + "\t\t\t 400 (NTSC)"); + +MODULE_PARM_DESC(osd_xres, + "Display width\n" + "\t\t\tdefault 640"); + +MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); +MODULE_LICENSE("GPL"); + +/* --------------------------------------------------------------------- */ + +#define IVTVFB_DBGFLG_WARN (1 << 0) +#define IVTVFB_DBGFLG_INFO (1 << 1) + +#define IVTVFB_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & ivtvfb_debug) \ + printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \ + } while (0) +#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args) + +/* Standard kernel messages */ +#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->instance , ## args) +#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->instance , ## args) +#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args) + +/* --------------------------------------------------------------------- */ + +#define IVTV_OSD_MAX_WIDTH 720 +#define IVTV_OSD_MAX_HEIGHT 576 + +#define IVTV_OSD_BPP_8 0x00 +#define IVTV_OSD_BPP_16_444 0x03 +#define IVTV_OSD_BPP_16_555 0x02 +#define IVTV_OSD_BPP_16_565 0x01 +#define IVTV_OSD_BPP_32 0x04 + +struct osd_info { + /* Physical base address */ + unsigned long video_pbase; + /* Relative base address (relative to start of decoder memory) */ + u32 video_rbase; + /* Mapped base address */ + volatile char __iomem *video_vbase; + /* Buffer size */ + u32 video_buffer_size; + +#ifdef CONFIG_MTRR + /* video_base rounded down as required by hardware MTRRs */ + unsigned long fb_start_aligned_physaddr; + /* video_base rounded up as required by hardware MTRRs */ + unsigned long fb_end_aligned_physaddr; +#endif + + /* Store the buffer offset */ + int set_osd_coords_x; + int set_osd_coords_y; + + /* Current dimensions (NOT VISIBLE SIZE!) */ + int display_width; + int display_height; + int display_byte_stride; + + /* Current bits per pixel */ + int bits_per_pixel; + int bytes_per_pixel; + + /* Frame buffer stuff */ + struct fb_info ivtvfb_info; + struct fb_var_screeninfo ivtvfb_defined; + struct fb_fix_screeninfo ivtvfb_fix; + + /* Used for a warm start */ + struct fb_var_screeninfo fbvar_cur; + int blank_cur; + u32 palette_cur[256]; + u32 pan_cur; +}; + +struct ivtv_osd_coords { + unsigned long offset; + unsigned long max_offset; + int pixel_stride; + int lines; + int x; + int y; +}; + +/* --------------------------------------------------------------------- */ + +/* ivtv API calls for framebuffer related support */ + +static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase, + u32 *fblength) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + int rc; + + ivtv_firmware_check(itv, "ivtvfb_get_framebuffer"); + rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); + *fbbase = data[0]; + *fblength = data[1]; + return rc; +} + +static int ivtvfb_get_osd_coords(struct ivtv *itv, + struct ivtv_osd_coords *osd) +{ + struct osd_info *oi = itv->osd_info; + u32 data[CX2341X_MBOX_MAX_DATA]; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); + + osd->offset = data[0] - oi->video_rbase; + osd->max_offset = oi->display_width * oi->display_height * 4; + osd->pixel_stride = data[1]; + osd->lines = data[2]; + osd->x = data[3]; + osd->y = data[4]; + return 0; +} + +static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +{ + struct osd_info *oi = itv->osd_info; + + oi->display_width = osd->pixel_stride; + oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel; + oi->set_osd_coords_x += osd->x; + oi->set_osd_coords_y = osd->y; + + return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, + osd->offset + oi->video_rbase, + osd->pixel_stride, + osd->lines, osd->x, osd->y); +} + +static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +{ + int osd_height_limit = itv->is_out_50hz ? 576 : 480; + + /* Only fail if resolution too high, otherwise fudge the start coords. */ + if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) + return -EINVAL; + + /* Ensure we don't exceed display limits */ + if (ivtv_window->top + ivtv_window->height > osd_height_limit) { + IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", + ivtv_window->top, ivtv_window->height); + ivtv_window->top = osd_height_limit - ivtv_window->height; + } + + if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { + IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", + ivtv_window->left, ivtv_window->width); + ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; + } + + /* Set the OSD origin */ + write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); + + /* How much to display */ + write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_vis_w = ivtv_window->width; + itv->yuv_info.osd_vis_h = ivtv_window->height; + itv->yuv_info.osd_x_offset = ivtv_window->left; + itv->yuv_info.osd_y_offset = ivtv_window->top; + + return 0; +} + +static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv, + unsigned long ivtv_dest_addr, void __user *userbuf, + int size_in_bytes) +{ + DEFINE_WAIT(wait); + int got_sig = 0; + + mutex_lock(&itv->udma.lock); + /* Map User DMA */ + if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { + mutex_unlock(&itv->udma.lock); + IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, " + "Error with get_user_pages: %d bytes, %d pages returned\n", + size_in_bytes, itv->udma.page_count); + + /* get_user_pages must have failed completely */ + return -EIO; + } + + IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + size_in_bytes, itv->udma.page_count); + + ivtv_udma_prepare(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + /* if no UDMA is pending and no UDMA is in progress, then the DMA + is finished */ + while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) || + test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + /* don't interrupt if the DMA is in progress but break off + a still pending DMA. */ + got_sig = signal_pending(current); + if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) + break; + got_sig = 0; + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + + /* Unmap Last DMA Xfer */ + ivtv_udma_unmap(itv); + mutex_unlock(&itv->udma.lock); + if (got_sig) { + IVTV_DEBUG_INFO("User stopped OSD\n"); + return -EINTR; + } + + return 0; +} + +static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, + unsigned long dest_offset, int count) +{ + DEFINE_WAIT(wait); + struct osd_info *oi = itv->osd_info; + + /* Nothing to do */ + if (count == 0) { + IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n"); + return -EINVAL; + } + + /* Check Total FB Size */ + if ((dest_offset + count) > oi->video_buffer_size) { + IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", + dest_offset + count, oi->video_buffer_size); + return -E2BIG; + } + + /* Not fatal, but will have undesirable results */ + if ((unsigned long)source & 3) + IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", + (unsigned long)source); + + if (dest_offset & 3) + IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); + + if (count & 3) + IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count); + + /* Check Source */ + if (!access_ok(VERIFY_READ, source + dest_offset, count)) { + IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n", + (unsigned long)source); + + IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + dest_offset, (unsigned long)source, + count); + return -EINVAL; + } + + /* OSD Address to send DMA to */ + dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; + + /* Fill Buffers */ + return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count); +} + +static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + void *dst; + int err = 0; + int dma_err; + unsigned long total_size; + struct ivtv *itv = (struct ivtv *) info->par; + unsigned long dma_offset = + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; + unsigned long dma_size; + u16 lead = 0, tail = 0; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + count = total_size - p; + } + + dst = (void __force *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + /* If transfer size > threshold and both src/dst + addresses are aligned, use DMA */ + if (count >= 4096 && + ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) { + /* Odd address = can't DMA. Align */ + if ((unsigned long)dst & 3) { + lead = 4 - ((unsigned long)dst & 3); + if (copy_from_user(dst, buf, lead)) + return -EFAULT; + buf += lead; + dst += lead; + } + /* DMA resolution is 32 bits */ + if ((count - lead) & 3) + tail = (count - lead) & 3; + /* DMA the data */ + dma_size = count - lead - tail; + dma_err = ivtvfb_prep_dec_dma_to_device(itv, + p + lead + dma_offset, (void __user *)buf, dma_size); + if (dma_err) + return dma_err; + dst += dma_size; + buf += dma_size; + /* Copy any leftover data */ + if (tail && copy_from_user(dst, buf, tail)) + return -EFAULT; + } else if (copy_from_user(dst, buf, count)) { + return -EFAULT; + } + + if (!err) + *ppos += count; + + return (err) ? err : count; +} + +static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + DEFINE_WAIT(wait); + struct ivtv *itv = (struct ivtv *)info->par; + int rc = 0; + + switch (cmd) { + case FBIOGET_VBLANK: { + struct fb_vblank vblank; + u32 trace; + + memset(&vblank, 0, sizeof(struct fb_vblank)); + + vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_VSYNC; + trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16; + if (itv->is_out_50hz && trace > 312) + trace -= 312; + else if (itv->is_out_60hz && trace > 262) + trace -= 262; + if (trace == 1) + vblank.flags |= FB_VBLANK_VSYNCING; + vblank.count = itv->last_vsync_field; + vblank.vcount = trace; + vblank.hcount = 0; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + + case FBIO_WAITFORVSYNC: + prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); + if (!schedule_timeout(msecs_to_jiffies(50))) + rc = -ETIMEDOUT; + finish_wait(&itv->vsync_waitq, &wait); + return rc; + + case IVTVFB_IOC_DMA_FRAME: { + struct ivtvfb_dma_frame args; + + IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); + if (copy_from_user(&args, (void __user *)arg, sizeof(args))) + return -EFAULT; + + return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + } + + default: + IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); + return -EINVAL; + } + return 0; +} + +/* Framebuffer device handling */ + +static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) +{ + struct osd_info *oi = itv->osd_info; + struct ivtv_osd_coords ivtv_osd; + struct v4l2_rect ivtv_window; + int osd_mode = -1; + + IVTVFB_DEBUG_INFO("ivtvfb_set_var\n"); + + /* Select color space */ + if (var->nonstd) /* YUV */ + write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); + else /* RGB */ + write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); + + /* Set the color mode */ + switch (var->bits_per_pixel) { + case 8: + osd_mode = IVTV_OSD_BPP_8; + break; + case 32: + osd_mode = IVTV_OSD_BPP_32; + break; + case 16: + switch (var->green.length) { + case 4: + osd_mode = IVTV_OSD_BPP_16_444; + break; + case 5: + osd_mode = IVTV_OSD_BPP_16_555; + break; + case 6: + osd_mode = IVTV_OSD_BPP_16_565; + break; + default: + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + break; + default: + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + + /* Set video mode. Although rare, the display can become scrambled even + if we don't change mode. Always 'bounce' to osd_mode via mode 0 */ + if (osd_mode != -1) { + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode); + } + + oi->bits_per_pixel = var->bits_per_pixel; + oi->bytes_per_pixel = var->bits_per_pixel / 8; + + /* Set the flicker filter */ + switch (var->vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: /* Filter on */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); + break; + case FB_VMODE_INTERLACED: /* Filter off */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); + break; + default: + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + } + + /* Read the current osd info */ + ivtvfb_get_osd_coords(itv, &ivtv_osd); + + /* Now set the OSD to the size we want */ + ivtv_osd.pixel_stride = var->xres_virtual; + ivtv_osd.lines = var->yres_virtual; + ivtv_osd.x = 0; + ivtv_osd.y = 0; + ivtvfb_set_osd_coords(itv, &ivtv_osd); + + /* Can't seem to find the right API combo for this. + Use another function which does what we need through direct register access. */ + ivtv_window.width = var->xres; + ivtv_window.height = var->yres; + + /* Minimum margin cannot be 0, as X won't allow such a mode */ + if (!var->upper_margin) + var->upper_margin++; + if (!var->left_margin) + var->left_margin++; + ivtv_window.top = var->upper_margin - 1; + ivtv_window.left = var->left_margin - 1; + + ivtvfb_set_display_window(itv, &ivtv_window); + + /* Pass screen size back to yuv handler */ + itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride; + itv->yuv_info.osd_full_h = ivtv_osd.lines; + + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + + /* Keep a copy of these settings */ + memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur)); + + IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); + + IVTVFB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); + + IVTVFB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + + return 0; +} + +static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) +{ + struct osd_info *oi = itv->osd_info; + + IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id)); + fix->smem_start = oi->video_pbase; + fix->smem_len = oi->video_buffer_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = oi->display_byte_stride; + fix->accel = FB_ACCEL_NONE; + return 0; +} + +/* Check the requested display mode, returning -EINVAL if we can't + handle it. */ + +static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + int osd_height_limit; + u32 pixclock, hlimit, vlimit; + + IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); + + /* Set base references for mode calcs. */ + if (itv->is_out_50hz) { + pixclock = 84316; + hlimit = 776; + vlimit = 591; + osd_height_limit = 576; + } + else { + pixclock = 83926; + hlimit = 776; + vlimit = 495; + osd_height_limit = 480; + } + + if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + } + else if (var->bits_per_pixel == 16) { + /* To find out the true mode, check green length */ + switch (var->green.length) { + case 4: + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + var->transp.offset = 12; + var->transp.length = 1; + break; + case 5: + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + break; + default: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + } + } + else { + IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + return -EINVAL; + } + + /* Check the resolution */ + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { + IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n", + var->xres, var->yres); + return -EINVAL; + } + + /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ + if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || + var->xres_virtual < var->xres || + var->yres_virtual < var->yres) { + IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", + var->xres_virtual, var->yres_virtual); + return -EINVAL; + } + + /* Some extra checks if in 8 bit mode */ + if (var->bits_per_pixel == 8) { + /* Width must be a multiple of 4 */ + if (var->xres & 3) { + IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 3) { + IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + else if (var->bits_per_pixel == 16) { + /* Width must be a multiple of 2 */ + if (var->xres & 1) { + IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 1) { + IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + + /* Now check the offsets */ + if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { + IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", + var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); + return -EINVAL; + } + + /* Check pixel format */ + if (var->nonstd > 1) { + IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); + return -EINVAL; + } + + /* Check video mode */ + if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && + ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { + IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); + return -EINVAL; + } + + /* Check the left & upper margins + If the margins are too large, just center the screen + (enforcing margins causes too many problems) */ + + if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) + var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); + + if (var->upper_margin + var->yres > (itv->is_out_50hz ? 577 : 481)) + var->upper_margin = 1 + (((itv->is_out_50hz ? 576 : 480) - + var->yres) / 2); + + /* Maintain overall 'size' for a constant refresh rate */ + var->right_margin = hlimit - var->left_margin - var->xres; + var->lower_margin = vlimit - var->upper_margin - var->yres; + + /* Fixed sync times */ + var->hsync_len = 24; + var->vsync_len = 2; + + /* Non-interlaced / interlaced mode is used to switch the OSD filter + on or off. Adjust the clock timings to maintain a constant + vertical refresh rate. */ + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + var->pixclock = pixclock / 2; + else + var->pixclock = pixclock; + + itv->osd_rect.width = var->xres; + itv->osd_rect.height = var->yres; + + IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); + + IVTVFB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); + + IVTVFB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + return 0; +} + +static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *) info->par; + IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); + return _ivtvfb_check_var(var, itv); +} + +static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u32 osd_pan_index; + struct ivtv *itv = (struct ivtv *) info->par; + + if (var->yoffset + info->var.yres > info->var.yres_virtual || + var->xoffset + info->var.xres > info->var.xres_virtual) + return -EINVAL; + + osd_pan_index = var->yoffset * info->fix.line_length + + var->xoffset * info->var.bits_per_pixel / 8; + write_reg(osd_pan_index, 0x02A0C); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_x_pan = var->xoffset; + itv->yuv_info.osd_y_pan = var->yoffset; + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + /* Remember this value */ + itv->osd_info->pan_cur = osd_pan_index; + return 0; +} + +static int ivtvfb_set_par(struct fb_info *info) +{ + int rc = 0; + struct ivtv *itv = (struct ivtv *) info->par; + + IVTVFB_DEBUG_INFO("ivtvfb_set_par\n"); + + rc = ivtvfb_set_var(itv, &info->var); + ivtvfb_pan_display(&info->var, info); + ivtvfb_get_fix(itv, &info->fix); + ivtv_firmware_check(itv, "ivtvfb_set_par"); + return rc; +} + +static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 color, *palette; + struct ivtv *itv = (struct ivtv *)info->par; + + if (regno >= info->cmap.len) + return -EINVAL; + + color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); + if (info->var.bits_per_pixel <= 8) { + write_reg(regno, 0x02a30); + write_reg(color, 0x02a34); + itv->osd_info->palette_cur[regno] = color; + return 0; + } + if (regno >= 16) + return -EINVAL; + + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + } + } + palette[regno] = color; + return 0; +} + +/* We don't really support blanking. All this does is enable or + disable the OSD. */ +static int ivtvfb_blank(int blank_mode, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *)info->par; + + IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); + ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1); + break; + case FB_BLANK_NORMAL: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); + ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1); + break; + case FB_BLANK_POWERDOWN: + ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); + break; + } + itv->osd_info->blank_cur = blank_mode; + return 0; +} + +static struct fb_ops ivtvfb_ops = { + .owner = THIS_MODULE, + .fb_write = ivtvfb_write, + .fb_check_var = ivtvfb_check_var, + .fb_set_par = ivtvfb_set_par, + .fb_setcolreg = ivtvfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_ioctl = ivtvfb_ioctl, + .fb_pan_display = ivtvfb_pan_display, + .fb_blank = ivtvfb_blank, +}; + +/* Restore hardware after firmware restart */ +static void ivtvfb_restore(struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + int i; + + ivtvfb_set_var(itv, &oi->fbvar_cur); + ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info); + for (i = 0; i < 256; i++) { + write_reg(i, 0x02a30); + write_reg(oi->palette_cur[i], 0x02a34); + } + write_reg(oi->pan_cur, 0x02a0c); +} + +/* Initialization */ + + +/* Setup our initial video mode */ +static int ivtvfb_init_vidmode(struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + struct v4l2_rect start_window; + int max_height; + + /* Color mode */ + + if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) + osd_depth = 8; + oi->bits_per_pixel = osd_depth; + oi->bytes_per_pixel = oi->bits_per_pixel / 8; + + /* Horizontal size & position */ + + if (osd_xres > 720) + osd_xres = 720; + + /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ + if (osd_depth == 8) + osd_xres &= ~3; + else if (osd_depth == 16) + osd_xres &= ~1; + + start_window.width = osd_xres ? osd_xres : 640; + + /* Check horizontal start (osd_left). */ + if (osd_left && osd_left + start_window.width > 721) { + IVTVFB_ERR("Invalid osd_left - assuming default\n"); + osd_left = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_left--; + + start_window.left = osd_left >= 0 ? + osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + + oi->display_byte_stride = + start_window.width * oi->bytes_per_pixel; + + /* Vertical size & position */ + + max_height = itv->is_out_50hz ? 576 : 480; + + if (osd_yres > max_height) + osd_yres = max_height; + + start_window.height = osd_yres ? + osd_yres : itv->is_out_50hz ? 480 : 400; + + /* Check vertical start (osd_upper). */ + if (osd_upper + start_window.height > max_height + 1) { + IVTVFB_ERR("Invalid osd_upper - assuming default\n"); + osd_upper = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_upper--; + + start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); + + oi->display_width = start_window.width; + oi->display_height = start_window.height; + + /* Generate a valid fb_var_screeninfo */ + + oi->ivtvfb_defined.xres = oi->display_width; + oi->ivtvfb_defined.yres = oi->display_height; + oi->ivtvfb_defined.xres_virtual = oi->display_width; + oi->ivtvfb_defined.yres_virtual = oi->display_height; + oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; + oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + oi->ivtvfb_defined.left_margin = start_window.left + 1; + oi->ivtvfb_defined.upper_margin = start_window.top + 1; + oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + oi->ivtvfb_defined.nonstd = 0; + + /* We've filled in the most data, let the usual mode check + routine fill in the rest. */ + _ivtvfb_check_var(&oi->ivtvfb_defined, itv); + + /* Generate valid fb_fix_screeninfo */ + + ivtvfb_get_fix(itv, &oi->ivtvfb_fix); + + /* Generate valid fb_info */ + + oi->ivtvfb_info.node = -1; + oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + oi->ivtvfb_info.fbops = &ivtvfb_ops; + oi->ivtvfb_info.par = itv; + oi->ivtvfb_info.var = oi->ivtvfb_defined; + oi->ivtvfb_info.fix = oi->ivtvfb_fix; + oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; + oi->ivtvfb_info.fbops = &ivtvfb_ops; + + /* Supply some monitor specs. Bogus values will do for now */ + oi->ivtvfb_info.monspecs.hfmin = 8000; + oi->ivtvfb_info.monspecs.hfmax = 70000; + oi->ivtvfb_info.monspecs.vfmin = 10; + oi->ivtvfb_info.monspecs.vfmax = 100; + + /* Allocate color map */ + if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { + IVTVFB_ERR("abort, unable to alloc cmap\n"); + return -ENOMEM; + } + + /* Allocate the pseudo palette */ + oi->ivtvfb_info.pseudo_palette = + kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN); + + if (!oi->ivtvfb_info.pseudo_palette) { + IVTVFB_ERR("abort, unable to alloc pseudo palette\n"); + return -ENOMEM; + } + + return 0; +} + +/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ + +static int ivtvfb_init_io(struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + + mutex_lock(&itv->serialize_lock); + if (ivtv_init_on_first_open(itv)) { + mutex_unlock(&itv->serialize_lock); + IVTVFB_ERR("Failed to initialize ivtv\n"); + return -ENXIO; + } + mutex_unlock(&itv->serialize_lock); + + if (ivtvfb_get_framebuffer(itv, &oi->video_rbase, + &oi->video_buffer_size) < 0) { + IVTVFB_ERR("Firmware failed to respond\n"); + return -EIO; + } + + /* The osd buffer size depends on the number of video buffers allocated + on the PVR350 itself. For now we'll hardcode the smallest osd buffer + size to prevent any overlap. */ + oi->video_buffer_size = 1704960; + + oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; + oi->video_vbase = itv->dec_mem + oi->video_rbase; + + if (!oi->video_vbase) { + IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + oi->video_buffer_size, oi->video_pbase); + return -EIO; + } + + IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + oi->video_pbase, oi->video_vbase, + oi->video_buffer_size / 1024); + +#ifdef CONFIG_MTRR + { + /* Find the largest power of two that maps the whole buffer */ + int size_shift = 31; + + while (!(oi->video_buffer_size & (1 << size_shift))) { + size_shift--; + } + size_shift++; + oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); + oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; + oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; + oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, + MTRR_TYPE_WRCOMB, 1) < 0) { + IVTVFB_INFO("disabled mttr\n"); + oi->fb_start_aligned_physaddr = 0; + oi->fb_end_aligned_physaddr = 0; + } + } +#endif + + /* Blank the entire osd. */ + memset_io(oi->video_vbase, 0, oi->video_buffer_size); + + return 0; +} + +/* Release any memory we've grabbed & remove mtrr entry */ +static void ivtvfb_release_buffers (struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + + /* Release cmap */ + if (oi->ivtvfb_info.cmap.len) + fb_dealloc_cmap(&oi->ivtvfb_info.cmap); + + /* Release pseudo palette */ + if (oi->ivtvfb_info.pseudo_palette) + kfree(oi->ivtvfb_info.pseudo_palette); + +#ifdef CONFIG_MTRR + if (oi->fb_end_aligned_physaddr) { + mtrr_del(-1, oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); + } +#endif + + kfree(oi); + itv->osd_info = NULL; +} + +/* Initialize the specified card */ + +static int ivtvfb_init_card(struct ivtv *itv) +{ + int rc; + + if (itv->osd_info) { + IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id); + return -EBUSY; + } + + itv->osd_info = kzalloc(sizeof(struct osd_info), + GFP_ATOMIC|__GFP_NOWARN); + if (itv->osd_info == NULL) { + IVTVFB_ERR("Failed to allocate memory for osd_info\n"); + return -ENOMEM; + } + + /* Find & setup the OSD buffer */ + rc = ivtvfb_init_io(itv); + if (rc) { + ivtvfb_release_buffers(itv); + return rc; + } + + /* Set the startup video mode information */ + if ((rc = ivtvfb_init_vidmode(itv))) { + ivtvfb_release_buffers(itv); + return rc; + } + + /* Register the framebuffer */ + if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { + ivtvfb_release_buffers(itv); + return -EINVAL; + } + + itv->osd_video_pbase = itv->osd_info->video_pbase; + + /* Set the card to the requested mode */ + ivtvfb_set_par(&itv->osd_info->ivtvfb_info); + + /* Set color 0 to black */ + write_reg(0, 0x02a30); + write_reg(0, 0x02a34); + + /* Enable the osd */ + ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); + + /* Enable restart */ + itv->ivtvfb_restore = ivtvfb_restore; + + /* Allocate DMA */ + ivtv_udma_alloc(itv); + return 0; + +} + +static int __init ivtvfb_callback_init(struct device *dev, void *p) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev); + + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + if (ivtvfb_init_card(itv) == 0) { + IVTVFB_INFO("Framebuffer registered on %s\n", + itv->v4l2_dev.name); + (*(int *)p)++; + } + } + return 0; +} + +static int ivtvfb_callback_cleanup(struct device *dev, void *p) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev); + struct osd_info *oi = itv->osd_info; + + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) { + IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", + itv->instance); + return 0; + } + IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance); + itv->ivtvfb_restore = NULL; + ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info); + ivtvfb_release_buffers(itv); + itv->osd_video_pbase = 0; + } + return 0; +} + +static int __init ivtvfb_init(void) +{ + struct device_driver *drv; + int registered = 0; + int err; + + if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n", + IVTV_MAX_CARDS - 1); + return -EINVAL; + } + + drv = driver_find("ivtv", &pci_bus_type); + err = driver_for_each_device(drv, NULL, ®istered, ivtvfb_callback_init); + put_driver(drv); + if (!registered) { + printk(KERN_ERR "ivtvfb: no cards found\n"); + return -ENODEV; + } + return 0; +} + +static void ivtvfb_cleanup(void) +{ + struct device_driver *drv; + int err; + + printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n"); + + drv = driver_find("ivtv", &pci_bus_type); + err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup); + put_driver(drv); +} + +module_init(ivtvfb_init); +module_exit(ivtvfb_cleanup); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-fileops.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-fileops.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-fileops.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-fileops.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1065 @@ +/* + file operation functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-fileops.h" +#include "ivtv-i2c.h" +#include "ivtv-queue.h" +#include "ivtv-udma.h" +#include "ivtv-irq.h" +#include "ivtv-vbi.h" +#include "ivtv-mailbox.h" +#include "ivtv-routing.h" +#include "ivtv-streams.h" +#include "ivtv-yuv.h" +#include "ivtv-ioctl.h" +#include "ivtv-cards.h" +#include "ivtv-firmware.h" +#include +#include + +/* This function tries to claim the stream for a specific file descriptor. + If no one else is using this stream then the stream is claimed and + associated VBI streams are also automatically claimed. + Possible error returns: -EBUSY if someone else has claimed + the stream or 0 on success. */ +static int ivtv_claim_stream(struct ivtv_open_id *id, int type) +{ + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[type]; + struct ivtv_stream *s_vbi; + int vbi_type; + + if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { + /* someone already claimed this stream */ + if (s->id == id->open_id) { + /* yes, this file descriptor did. So that's OK. */ + return 0; + } + if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI || + type == IVTV_ENC_STREAM_TYPE_VBI)) { + /* VBI is handled already internally, now also assign + the file descriptor to this stream for external + reading of the stream. */ + s->id = id->open_id; + IVTV_DEBUG_INFO("Start Read VBI\n"); + return 0; + } + /* someone else is using this stream already */ + IVTV_DEBUG_INFO("Stream %d is busy\n", type); + return -EBUSY; + } + s->id = id->open_id; + if (type == IVTV_DEC_STREAM_TYPE_VBI) { + /* Enable reinsertion interrupt */ + ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); + } + + /* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI, + IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI + (provided VBI insertion is on and sliced VBI is selected), for all + other streams we're done */ + if (type == IVTV_DEC_STREAM_TYPE_MPG) { + vbi_type = IVTV_DEC_STREAM_TYPE_VBI; + } else if (type == IVTV_ENC_STREAM_TYPE_MPG && + itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) { + vbi_type = IVTV_ENC_STREAM_TYPE_VBI; + } else { + return 0; + } + s_vbi = &itv->streams[vbi_type]; + + if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) { + /* Enable reinsertion interrupt */ + if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI) + ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); + } + /* mark that it is used internally */ + set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags); + return 0; +} + +/* This function releases a previously claimed stream. It will take into + account associated VBI streams. */ +void ivtv_release_stream(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + struct ivtv_stream *s_vbi; + + s->id = -1; + if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && + test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { + /* this stream is still in use internally */ + return; + } + if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { + IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name); + return; + } + + ivtv_flush_queues(s); + + /* disable reinsertion interrupt */ + if (s->type == IVTV_DEC_STREAM_TYPE_VBI) + ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); + + /* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI, + IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI, + for all other streams we're done */ + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) + s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; + else if (s->type == IVTV_ENC_STREAM_TYPE_MPG) + s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; + else + return; + + /* clear internal use flag */ + if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) { + /* was already cleared */ + return; + } + if (s_vbi->id != -1) { + /* VBI stream still claimed by a file descriptor */ + return; + } + /* disable reinsertion interrupt */ + if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI) + ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); + clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags); + ivtv_flush_queues(s_vbi); +} + +static void ivtv_dualwatch(struct ivtv *itv) +{ + struct v4l2_tuner vt; + u32 new_stereo_mode; + const u32 dual = 0x02; + + new_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode); + memset(&vt, 0, sizeof(vt)); + ivtv_call_all(itv, tuner, g_tuner, &vt); + if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) + new_stereo_mode = dual; + + if (new_stereo_mode == itv->dualwatch_stereo_mode) + return; + + IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", + itv->dualwatch_stereo_mode, new_stereo_mode); + if (v4l2_ctrl_s_ctrl(itv->cxhdl.audio_mode, new_stereo_mode)) + IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); +} + +static void ivtv_update_pgm_info(struct ivtv *itv) +{ + u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24; + int cnt; + int i = 0; + + if (wr_idx >= itv->pgm_info_num) { + IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num); + return; + } + cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num; + while (i < cnt) { + int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; + struct v4l2_enc_idx_entry *e = itv->pgm_info + idx; + u32 addr = itv->pgm_info_offset + 4 + idx * 24; + const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1, + V4L2_ENC_IDX_FRAME_B, -1, -1, -1 }; + // 1=I, 2=P, 4=B + + e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32); + if (e->offset > itv->mpg_data_received) { + break; + } + e->offset += itv->vbi_data_inserted; + e->length = read_enc(addr); + e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32); + e->flags = mapping[read_enc(addr + 12) & 7]; + i++; + } + itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; +} + +static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err) +{ + struct ivtv *itv = s->itv; + struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; + struct ivtv_buffer *buf; + DEFINE_WAIT(wait); + + *err = 0; + while (1) { + if (s->type == IVTV_ENC_STREAM_TYPE_MPG) { + /* Process pending program info updates and pending VBI data */ + ivtv_update_pgm_info(itv); + + if (time_after(jiffies, + itv->dualwatch_jiffies + + msecs_to_jiffies(1000))) { + itv->dualwatch_jiffies = jiffies; + ivtv_dualwatch(itv); + } + + if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { + while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) { + /* byteswap and process VBI data */ + ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type); + ivtv_enqueue(s_vbi, buf, &s_vbi->q_free); + } + } + buf = &itv->vbi.sliced_mpeg_buf; + if (buf->readpos != buf->bytesused) { + return buf; + } + } + + /* do we have leftover data? */ + buf = ivtv_dequeue(s, &s->q_io); + if (buf) + return buf; + + /* do we have new data? */ + buf = ivtv_dequeue(s, &s->q_full); + if (buf) { + if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0) + return buf; + buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP; + if (s->type == IVTV_ENC_STREAM_TYPE_MPG) + /* byteswap MPG data */ + ivtv_buf_swap(buf); + else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) { + /* byteswap and process VBI data */ + ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type); + } + return buf; + } + + /* return if end of stream */ + if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { + IVTV_DEBUG_INFO("EOS %s\n", s->name); + return NULL; + } + + /* return if file was opened with O_NONBLOCK */ + if (non_block) { + *err = -EAGAIN; + return NULL; + } + + /* wait for more data to arrive */ + prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); + /* New buffers might have become available before we were added to the waitqueue */ + if (!s->q_full.buffers) + schedule(); + finish_wait(&s->waitq, &wait); + if (signal_pending(current)) { + /* return if a signal was received */ + IVTV_DEBUG_INFO("User stopped %s\n", s->name); + *err = -EINTR; + return NULL; + } + } +} + +static void ivtv_setup_sliced_vbi_buf(struct ivtv *itv) +{ + int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; + + itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx]; + itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx]; + itv->vbi.sliced_mpeg_buf.readpos = 0; +} + +static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf, + char __user *ubuf, size_t ucount) +{ + struct ivtv *itv = s->itv; + size_t len = buf->bytesused - buf->readpos; + + if (len > ucount) len = ucount; + if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG && + !ivtv_raw_vbi(itv) && buf != &itv->vbi.sliced_mpeg_buf) { + const char *start = buf->buf + buf->readpos; + const char *p = start + 1; + const u8 *q; + u8 ch = itv->search_pack_header ? 0xba : 0xe0; + int stuffing, i; + + while (start + len > p && (q = memchr(p, 0, start + len - p))) { + p = q + 1; + if ((char *)q + 15 >= buf->buf + buf->bytesused || + q[1] != 0 || q[2] != 1 || q[3] != ch) { + continue; + } + if (!itv->search_pack_header) { + if ((q[6] & 0xc0) != 0x80) + continue; + if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) || + ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) { + ch = 0xba; + itv->search_pack_header = 1; + p = q + 9; + } + continue; + } + stuffing = q[13] & 7; + /* all stuffing bytes must be 0xff */ + for (i = 0; i < stuffing; i++) + if (q[14 + i] != 0xff) + break; + if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 && + q[14 + stuffing] == 0 && q[15 + stuffing] == 0 && + q[16 + stuffing] == 1) { + itv->search_pack_header = 0; + len = (char *)q - start; + ivtv_setup_sliced_vbi_buf(itv); + break; + } + } + } + if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { + IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name); + return -EFAULT; + } + /*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount, + buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len, + buf == &itv->vbi.sliced_mpeg_buf); */ + buf->readpos += len; + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf) + itv->mpg_data_received += len; + return len; +} + +static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block) +{ + struct ivtv *itv = s->itv; + size_t tot_written = 0; + int single_frame = 0; + + if (atomic_read(&itv->capturing) == 0 && s->id == -1) { + /* shouldn't happen */ + IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); + return -EIO; + } + + /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should + arrive one-by-one, so make sure we never output more than one VBI frame at a time */ + if (s->type == IVTV_DEC_STREAM_TYPE_VBI || + (s->type == IVTV_ENC_STREAM_TYPE_VBI && !ivtv_raw_vbi(itv))) + single_frame = 1; + + for (;;) { + struct ivtv_buffer *buf; + int rc; + + buf = ivtv_get_buffer(s, non_block, &rc); + /* if there is no data available... */ + if (buf == NULL) { + /* if we got data, then return that regardless */ + if (tot_written) + break; + /* EOS condition */ + if (rc == 0) { + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + ivtv_release_stream(s); + } + /* set errno */ + return rc; + } + rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written); + if (buf != &itv->vbi.sliced_mpeg_buf) { + ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io); + } + else if (buf->readpos == buf->bytesused) { + int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; + itv->vbi.sliced_mpeg_size[idx] = 0; + itv->vbi.inserted_frame++; + itv->vbi_data_inserted += buf->bytesused; + } + if (rc < 0) + return rc; + tot_written += rc; + + if (tot_written == tot_count || single_frame) + break; + } + return tot_written; +} + +static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count, + loff_t *pos, int non_block) +{ + ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; + struct ivtv *itv = s->itv; + + IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); + if (rc > 0) + pos += rc; + return rc; +} + +int ivtv_start_capture(struct ivtv_open_id *id) +{ + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; + struct ivtv_stream *s_vbi; + + if (s->type == IVTV_ENC_STREAM_TYPE_RAD || + s->type == IVTV_DEC_STREAM_TYPE_MPG || + s->type == IVTV_DEC_STREAM_TYPE_YUV || + s->type == IVTV_DEC_STREAM_TYPE_VOUT) { + /* you cannot read from these stream types. */ + return -EPERM; + } + + /* Try to claim this stream. */ + if (ivtv_claim_stream(id, s->type)) + return -EBUSY; + + /* This stream does not need to start capturing */ + if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { + set_bit(IVTV_F_S_APPL_IO, &s->s_flags); + return 0; + } + + /* If capture is already in progress, then we also have to + do nothing extra. */ + if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) { + set_bit(IVTV_F_S_APPL_IO, &s->s_flags); + return 0; + } + + /* Start VBI capture if required */ + s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && + test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { + /* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed + automatically when the MPG stream is claimed. + We only need to start the VBI capturing. */ + if (ivtv_start_v4l2_encode_stream(s_vbi)) { + IVTV_DEBUG_WARN("VBI capture start failed\n"); + + /* Failure, clean up and return an error */ + clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); + clear_bit(IVTV_F_S_STREAMING, &s->s_flags); + /* also releases the associated VBI stream */ + ivtv_release_stream(s); + return -EIO; + } + IVTV_DEBUG_INFO("VBI insertion started\n"); + } + + /* Tell the card to start capturing */ + if (!ivtv_start_v4l2_encode_stream(s)) { + /* We're done */ + set_bit(IVTV_F_S_APPL_IO, &s->s_flags); + /* Resume a possibly paused encoder */ + if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) + ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); + return 0; + } + + /* failure, clean up */ + IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); + + /* Note: the IVTV_ENC_STREAM_TYPE_VBI is released + automatically when the MPG stream is released. + We only need to stop the VBI capturing. */ + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && + test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { + ivtv_stop_v4l2_encode_stream(s_vbi, 0); + clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); + } + clear_bit(IVTV_F_S_STREAMING, &s->s_flags); + ivtv_release_stream(s); + return -EIO; +} + +ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos) +{ + struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; + int rc; + + IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); + + mutex_lock(&itv->serialize_lock); + rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); + if (rc) + return rc; + return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); +} + +int ivtv_start_decoding(struct ivtv_open_id *id, int speed) +{ + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; + int rc; + + if (atomic_read(&itv->decoding) == 0) { + if (ivtv_claim_stream(id, s->type)) { + /* someone else is using this stream already */ + IVTV_DEBUG_WARN("start decode, stream already claimed\n"); + return -EBUSY; + } + rc = ivtv_start_v4l2_decode_stream(s, 0); + if (rc < 0) { + if (rc == -EAGAIN) + rc = ivtv_start_v4l2_decode_stream(s, 0); + if (rc < 0) + return rc; + } + } + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) + return ivtv_set_speed(itv, speed); + return 0; +} + +ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) +{ + struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; + struct yuv_playback_info *yi = &itv->yuv_info; + struct ivtv_buffer *buf; + struct ivtv_queue q; + int bytes_written = 0; + int mode; + int rc; + DEFINE_WAIT(wait); + + IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name); + + if (s->type != IVTV_DEC_STREAM_TYPE_MPG && + s->type != IVTV_DEC_STREAM_TYPE_YUV && + s->type != IVTV_DEC_STREAM_TYPE_VOUT) + /* not decoder streams */ + return -EPERM; + + /* Try to claim this stream */ + if (ivtv_claim_stream(id, s->type)) + return -EBUSY; + + /* This stream does not need to start any decoding */ + if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) { + int elems = count / sizeof(struct v4l2_sliced_vbi_data); + + set_bit(IVTV_F_S_APPL_IO, &s->s_flags); + return ivtv_write_vbi_from_user(itv, + (const struct v4l2_sliced_vbi_data __user *)user_buf, elems); + } + + mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV; + + if (ivtv_set_output_mode(itv, mode) != mode) { + ivtv_release_stream(s); + return -EBUSY; + } + ivtv_queue_init(&q); + set_bit(IVTV_F_S_APPL_IO, &s->s_flags); + + /* Start decoder (returns 0 if already started) */ + mutex_lock(&itv->serialize_lock); + rc = ivtv_start_decoding(id, itv->speed); + mutex_unlock(&itv->serialize_lock); + if (rc) { + IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); + + /* failure, clean up */ + clear_bit(IVTV_F_S_STREAMING, &s->s_flags); + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + return rc; + } + +retry: + /* If possible, just DMA the entire frame - Check the data transfer size + since we may get here before the stream has been fully set-up */ + if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) { + while (count >= itv->dma_data_req_size) { + rc = ivtv_yuv_udma_stream_frame(itv, (void __user *)user_buf); + + if (rc < 0) + return rc; + + bytes_written += itv->dma_data_req_size; + user_buf += itv->dma_data_req_size; + count -= itv->dma_data_req_size; + } + if (count == 0) { + IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + return bytes_written; + } + } + + for (;;) { + /* Gather buffers */ + while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) + ivtv_enqueue(s, buf, &q); + while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) { + ivtv_enqueue(s, buf, &q); + } + if (q.buffers) + break; + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); + /* New buffers might have become free before we were added to the waitqueue */ + if (!s->q_free.buffers) + schedule(); + finish_wait(&s->waitq, &wait); + if (signal_pending(current)) { + IVTV_DEBUG_INFO("User stopped %s\n", s->name); + return -EINTR; + } + } + + /* copy user data into buffers */ + while ((buf = ivtv_dequeue(s, &q))) { + /* yuv is a pain. Don't copy more data than needed for a single + frame, otherwise we lose sync with the incoming stream */ + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && + yi->stream_size + count > itv->dma_data_req_size) + rc = ivtv_buf_copy_from_user(s, buf, user_buf, + itv->dma_data_req_size - yi->stream_size); + else + rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); + + /* Make sure we really got all the user data */ + if (rc < 0) { + ivtv_queue_move(s, &q, NULL, &s->q_free, 0); + return rc; + } + user_buf += rc; + count -= rc; + bytes_written += rc; + + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { + yi->stream_size += rc; + /* If we have a complete yuv frame, break loop now */ + if (yi->stream_size == itv->dma_data_req_size) { + ivtv_enqueue(s, buf, &s->q_full); + yi->stream_size = 0; + break; + } + } + + if (buf->bytesused != s->buf_size) { + /* incomplete, leave in q_io for next time */ + ivtv_enqueue(s, buf, &s->q_io); + break; + } + /* Byteswap MPEG buffer */ + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) + ivtv_buf_swap(buf); + ivtv_enqueue(s, buf, &s->q_full); + } + + if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { + if (s->q_full.length >= itv->dma_data_req_size) { + int got_sig; + + if (mode == OUT_YUV) + ivtv_yuv_setup_stream_frame(itv); + + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + while (!(got_sig = signal_pending(current)) && + test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + if (got_sig) { + IVTV_DEBUG_INFO("User interrupted %s\n", s->name); + return -EINTR; + } + + clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); + ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); + ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1); + } + } + /* more user data is available, wait until buffers become free + to transfer the rest. */ + if (count && !(filp->f_flags & O_NONBLOCK)) + goto retry; + IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + return bytes_written; +} + +unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) +{ + struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; + int res = 0; + + /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Decoder poll\n"); + + /* If there are subscribed events, then only use the new event + API instead of the old video.h based API. */ + if (!list_empty(&id->fh.events->subscribed)) { + poll_wait(filp, &id->fh.events->wait, wait); + /* Turn off the old-style vsync events */ + clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); + if (v4l2_event_pending(&id->fh)) + res = POLLPRI; + } else { + /* This is the old-style API which is here only for backwards + compatibility. */ + poll_wait(filp, &s->waitq, wait); + set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); + if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) || + test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) + res = POLLPRI; + } + + /* Allow write if buffers are available for writing */ + if (s->q_free.buffers) + res |= POLLOUT | POLLWRNORM; + return res; +} + +unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) +{ + struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; + int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + + /* Start a capture if there is none */ + if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { + int rc; + + mutex_lock(&itv->serialize_lock); + rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); + if (rc) { + IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", + s->name, rc); + return POLLERR; + } + IVTV_DEBUG_FILE("Encoder poll started capture\n"); + } + + /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Encoder poll\n"); + poll_wait(filp, &s->waitq, wait); + + if (s->q_full.length || s->q_io.length) + return POLLIN | POLLRDNORM; + if (eof) + return POLLHUP; + return 0; +} + +void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) +{ + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; + + IVTV_DEBUG_FILE("close() of %s\n", s->name); + + /* 'Unclaim' this stream */ + + /* Stop capturing */ + if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { + struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; + + IVTV_DEBUG_INFO("close stopping capture\n"); + /* Special case: a running VBI capture for VBI insertion + in the mpeg stream. Need to stop that too. */ + if (id->type == IVTV_ENC_STREAM_TYPE_MPG && + test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) && + !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { + IVTV_DEBUG_INFO("close stopping embedded VBI capture\n"); + ivtv_stop_v4l2_encode_stream(s_vbi, 0); + } + if ((id->type == IVTV_DEC_STREAM_TYPE_VBI || + id->type == IVTV_ENC_STREAM_TYPE_VBI) && + test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { + /* Also used internally, don't stop capturing */ + s->id = -1; + } + else { + ivtv_stop_v4l2_encode_stream(s, gop_end); + } + } + if (!gop_end) { + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + ivtv_release_stream(s); + } +} + +static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) +{ + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; + + IVTV_DEBUG_FILE("close() of %s\n", s->name); + + if (id->type == IVTV_DEC_STREAM_TYPE_YUV && + test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { + /* Restore registers we've changed & clean up any mess */ + ivtv_yuv_close(itv); + } + + /* Stop decoding */ + if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { + IVTV_DEBUG_INFO("close stopping decode\n"); + + ivtv_stop_v4l2_decode_stream(s, flags, pts); + itv->output_mode = OUT_NONE; + } + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + + if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames) + itv->output_mode = OUT_NONE; + + itv->speed = 0; + clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); + ivtv_release_stream(s); +} + +int ivtv_v4l2_close(struct file *filp) +{ + struct v4l2_fh *fh = filp->private_data; + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[id->type]; + + IVTV_DEBUG_FILE("close %s\n", s->name); + + v4l2_fh_del(fh); + v4l2_fh_exit(fh); + + /* Easy case first: this stream was never claimed by us */ + if (s->id != id->open_id) { + kfree(id); + return 0; + } + + /* 'Unclaim' this stream */ + + /* Stop radio */ + mutex_lock(&itv->serialize_lock); + if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { + /* Closing radio device, return to TV mode */ + ivtv_mute(itv); + /* Mark that the radio is no longer in use */ + clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); + /* Switch tuner to TV */ + ivtv_call_all(itv, core, s_std, itv->std); + /* Select correct audio input (i.e. TV tuner or Line in) */ + ivtv_audio_set_io(itv); + if (itv->hw_flags & IVTV_HW_SAA711X) { + ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, + SAA7115_FREQ_32_11_MHZ, 0); + } + if (atomic_read(&itv->capturing) > 0) { + /* Undo video mute */ + ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, + v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) | + (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8)); + } + /* Done! Unmute and continue. */ + ivtv_unmute(itv); + ivtv_release_stream(s); + } else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { + struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; + + ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); + + /* If all output streams are closed, and if the user doesn't have + IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ + if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) { + /* disable CC on TV-out */ + ivtv_disable_cc(itv); + } + } else { + ivtv_stop_capture(id, 0); + } + kfree(id); + mutex_unlock(&itv->serialize_lock); + return 0; +} + +static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) +{ +#ifdef CONFIG_VIDEO_ADV_DEBUG + struct video_device *vdev = video_devdata(filp); +#endif + struct ivtv *itv = s->itv; + struct ivtv_open_id *item; + int res = 0; + + IVTV_DEBUG_FILE("open %s\n", s->name); + +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* Unless ivtv_fw_debug is set, error out if firmware dead. */ + if (ivtv_fw_debug) { + IVTV_WARN("Opening %s with dead firmware lockout disabled\n", + video_device_node_name(vdev)); + IVTV_WARN("Selected firmware errors will be ignored\n"); + } else { +#else + if (1) { +#endif + res = ivtv_firmware_check(itv, "ivtv_serialized_open"); + if (res == -EAGAIN) + res = ivtv_firmware_check(itv, "ivtv_serialized_open"); + if (res < 0) + return -EIO; + } + + if (s->type == IVTV_DEC_STREAM_TYPE_MPG && + test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) + return -EBUSY; + + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && + test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) + return -EBUSY; + + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { + if (read_reg(0x82c) == 0) { + IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); + /* return -ENODEV; */ + } + ivtv_udma_alloc(itv); + } + + /* Allocate memory */ + item = kzalloc(sizeof(struct ivtv_open_id), GFP_KERNEL); + if (NULL == item) { + IVTV_DEBUG_WARN("nomem on v4l2 open\n"); + return -ENOMEM; + } + v4l2_fh_init(&item->fh, s->vdev); + if (s->type == IVTV_DEC_STREAM_TYPE_YUV || + s->type == IVTV_DEC_STREAM_TYPE_MPG) { + res = v4l2_event_alloc(&item->fh, 60); + } + if (res < 0) { + v4l2_fh_exit(&item->fh); + kfree(item); + return res; + } + item->itv = itv; + item->type = s->type; + + item->open_id = itv->open_id++; + filp->private_data = &item->fh; + + if (item->type == IVTV_ENC_STREAM_TYPE_RAD) { + /* Try to claim this stream */ + if (ivtv_claim_stream(item, item->type)) { + /* No, it's already in use */ + v4l2_fh_exit(&item->fh); + kfree(item); + return -EBUSY; + } + + if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + if (atomic_read(&itv->capturing) > 0) { + /* switching to radio while capture is + in progress is not polite */ + ivtv_release_stream(s); + v4l2_fh_exit(&item->fh); + kfree(item); + return -EBUSY; + } + } + /* Mark that the radio is being used. */ + set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); + /* We have the radio */ + ivtv_mute(itv); + /* Switch tuner to radio */ + ivtv_call_all(itv, tuner, s_radio); + /* Select the correct audio input (i.e. radio tuner) */ + ivtv_audio_set_io(itv); + if (itv->hw_flags & IVTV_HW_SAA711X) { + ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, + SAA7115_FREQ_32_11_MHZ, SAA7115_FREQ_FL_APLL); + } + /* Done! Unmute and continue. */ + ivtv_unmute(itv); + } + + /* YUV or MPG Decoding Mode? */ + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) { + clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); + } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { + set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); + /* For yuv, we need to know the dma size before we start */ + itv->dma_data_req_size = + 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); + itv->yuv_info.stream_size = 0; + } + v4l2_fh_add(&item->fh); + return 0; +} + +int ivtv_v4l2_open(struct file *filp) +{ + int res; + struct ivtv *itv = NULL; + struct ivtv_stream *s = NULL; + struct video_device *vdev = video_devdata(filp); + + s = video_get_drvdata(vdev); + itv = s->itv; + + mutex_lock(&itv->serialize_lock); + if (ivtv_init_on_first_open(itv)) { + IVTV_ERR("Failed to initialize on device %s\n", + video_device_node_name(vdev)); + mutex_unlock(&itv->serialize_lock); + return -ENXIO; + } + res = ivtv_serialized_open(s, filp); + mutex_unlock(&itv->serialize_lock); + return res; +} + +void ivtv_mute(struct ivtv *itv) +{ + if (atomic_read(&itv->capturing)) + ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1); + IVTV_DEBUG_INFO("Mute\n"); +} + +void ivtv_unmute(struct ivtv *itv) +{ + if (atomic_read(&itv->capturing)) { + ivtv_msleep_timeout(100, 0); + ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); + ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); + } + IVTV_DEBUG_INFO("Unmute\n"); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-fileops.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-fileops.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-fileops.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-fileops.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,44 @@ +/* + file operation functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_FILEOPS_H +#define IVTV_FILEOPS_H + +/* Testing/Debugging */ +int ivtv_v4l2_open(struct file *filp); +ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t * pos); +ssize_t ivtv_v4l2_write(struct file *filp, const char __user *buf, size_t count, + loff_t * pos); +int ivtv_v4l2_close(struct file *filp); +unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait); +unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table * wait); +int ivtv_start_capture(struct ivtv_open_id *id); +void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end); +int ivtv_start_decoding(struct ivtv_open_id *id, int speed); +void ivtv_mute(struct ivtv *itv); +void ivtv_unmute(struct ivtv *itv); + +/* Utilities */ + +/* Release a previously claimed stream. */ +void ivtv_release_stream(struct ivtv_stream *s); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-firmware.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-firmware.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-firmware.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,398 @@ +/* + ivtv firmware functions. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-mailbox.h" +#include "ivtv-firmware.h" +#include "ivtv-yuv.h" +#include "ivtv-ioctl.h" +#include "ivtv-cards.h" +#include +#include + +#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE +#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6 +#define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB +#define IVTV_CMD_VDM_STOP 0x00000000 +#define IVTV_CMD_AO_STOP 0x00000005 +#define IVTV_CMD_APU_PING 0x00000000 +#define IVTV_CMD_VPU_STOP15 0xFFFFFFFE +#define IVTV_CMD_VPU_STOP16 0xFFFFFFEE +#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF +#define IVTV_CMD_SPU_STOP 0x00000001 +#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A +#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640 +#define IVTV_SDRAM_SLEEPTIME 600 + +#define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg" +#define IVTV_DECODE_INIT_MPEG_SIZE (152*1024) + +/* Encoder/decoder firmware sizes */ +#define IVTV_FW_ENC_SIZE (376836) +#define IVTV_FW_DEC_SIZE (256*1024) + +static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv *itv, long size) +{ + const struct firmware *fw = NULL; + int retries = 3; + +retry: + if (retries && request_firmware(&fw, fn, &itv->pdev->dev) == 0) { + int i; + volatile u32 __iomem *dst = (volatile u32 __iomem *)mem; + const u32 *src = (const u32 *)fw->data; + + if (fw->size != size) { + /* Due to race conditions in firmware loading (esp. with udev <0.95) + the wrong file was sometimes loaded. So we check filesizes to + see if at least the right-sized file was loaded. If not, then we + retry. */ + IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size); + release_firmware(fw); + retries--; + goto retry; + } + for (i = 0; i < fw->size; i += 4) { + /* no need for endianness conversion on the ppc */ + __raw_writel(*src, dst); + dst++; + src++; + } + IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size); + release_firmware(fw); + return size; + } + IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size); + IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n"); + return -ENOMEM; +} + +void ivtv_halt_firmware(struct ivtv *itv) +{ + IVTV_DEBUG_INFO("Preparing for firmware halt.\n"); + if (itv->has_cx23415 && itv->dec_mbox.mbox) + ivtv_vapi(itv, CX2341X_DEC_HALT_FW, 0); + if (itv->enc_mbox.mbox) + ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0); + + ivtv_msleep_timeout(10, 0); + itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL; + + IVTV_DEBUG_INFO("Stopping VDM\n"); + write_reg(IVTV_CMD_VDM_STOP, IVTV_REG_VDM); + + IVTV_DEBUG_INFO("Stopping AO\n"); + write_reg(IVTV_CMD_AO_STOP, IVTV_REG_AO); + + IVTV_DEBUG_INFO("pinging (?) APU\n"); + write_reg(IVTV_CMD_APU_PING, IVTV_REG_APU); + + IVTV_DEBUG_INFO("Stopping VPU\n"); + if (!itv->has_cx23415) + write_reg(IVTV_CMD_VPU_STOP16, IVTV_REG_VPU); + else + write_reg(IVTV_CMD_VPU_STOP15, IVTV_REG_VPU); + + IVTV_DEBUG_INFO("Resetting Hw Blocks\n"); + write_reg(IVTV_CMD_HW_BLOCKS_RST, IVTV_REG_HW_BLOCKS); + + IVTV_DEBUG_INFO("Stopping SPU\n"); + write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU); + + ivtv_msleep_timeout(10, 0); + + IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n"); + write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE); + + IVTV_DEBUG_INFO("init Encoder SDRAM refresh to 1us\n"); + write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_ENC_SDRAM_REFRESH); + + if (itv->has_cx23415) { + IVTV_DEBUG_INFO("init Decoder SDRAM pre-charge\n"); + write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_DEC_SDRAM_PRECHARGE); + + IVTV_DEBUG_INFO("init Decoder SDRAM refresh to 1us\n"); + write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH); + } + + IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME); + ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0); +} + +void ivtv_firmware_versions(struct ivtv *itv) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + + /* Encoder */ + ivtv_vapi_result(itv, data, CX2341X_ENC_GET_VERSION, 0); + IVTV_INFO("Encoder revision: 0x%08x\n", data[0]); + + if (data[0] != 0x02060039) + IVTV_WARN("Recommended firmware version is 0x02060039.\n"); + + if (itv->has_cx23415) { + /* Decoder */ + ivtv_vapi_result(itv, data, CX2341X_DEC_GET_VERSION, 0); + IVTV_INFO("Decoder revision: 0x%08x\n", data[0]); + } +} + +static int ivtv_firmware_copy(struct ivtv *itv) +{ + IVTV_DEBUG_INFO("Loading encoder image\n"); + if (load_fw_direct(CX2341X_FIRM_ENC_FILENAME, + itv->enc_mem, itv, IVTV_FW_ENC_SIZE) != IVTV_FW_ENC_SIZE) { + IVTV_DEBUG_WARN("failed loading encoder firmware\n"); + return -3; + } + if (!itv->has_cx23415) + return 0; + + IVTV_DEBUG_INFO("Loading decoder image\n"); + if (load_fw_direct(CX2341X_FIRM_DEC_FILENAME, + itv->dec_mem, itv, IVTV_FW_DEC_SIZE) != IVTV_FW_DEC_SIZE) { + IVTV_DEBUG_WARN("failed loading decoder firmware\n"); + return -1; + } + return 0; +} + +static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile u8 __iomem *mem, u32 size) +{ + int i; + + /* mailbox is preceded by a 16 byte 'magic cookie' starting at a 256-byte + address boundary */ + for (i = 0; i < size; i += 0x100) { + if (readl(mem + i) == 0x12345678 && + readl(mem + i + 4) == 0x34567812 && + readl(mem + i + 8) == 0x56781234 && + readl(mem + i + 12) == 0x78123456) { + return (volatile struct ivtv_mailbox __iomem *)(mem + i + 16); + } + } + return NULL; +} + +int ivtv_firmware_init(struct ivtv *itv) +{ + int err; + + ivtv_halt_firmware(itv); + + /* load firmware */ + err = ivtv_firmware_copy(itv); + if (err) { + IVTV_DEBUG_WARN("Error %d loading firmware\n", err); + return err; + } + + /* start firmware */ + write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU); + ivtv_msleep_timeout(100, 0); + if (itv->has_cx23415) + write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU); + else + write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU); + ivtv_msleep_timeout(100, 0); + + /* find mailboxes and ping firmware */ + itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE); + if (itv->enc_mbox.mbox == NULL) + IVTV_ERR("Encoder mailbox not found\n"); + else if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0)) { + IVTV_ERR("Encoder firmware dead!\n"); + itv->enc_mbox.mbox = NULL; + } + if (itv->enc_mbox.mbox == NULL) + return -ENODEV; + + if (!itv->has_cx23415) + return 0; + + itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE); + if (itv->dec_mbox.mbox == NULL) { + IVTV_ERR("Decoder mailbox not found\n"); + } else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) { + IVTV_ERR("Decoder firmware dead!\n"); + itv->dec_mbox.mbox = NULL; + } else { + /* Firmware okay, so check yuv output filter table */ + ivtv_yuv_filter_check(itv); + } + return itv->dec_mbox.mbox ? 0 : -ENODEV; +} + +void ivtv_init_mpeg_decoder(struct ivtv *itv) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + long readbytes; + volatile u8 __iomem *mem_offset; + + data[0] = 0; + data[1] = itv->cxhdl.width; /* YUV source width */ + data[2] = itv->cxhdl.height; + data[3] = itv->cxhdl.audio_properties; /* Audio settings to use, + bitmap. see docs. */ + if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) { + IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n"); + return; + } + + if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) { + IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n"); + return; + } + ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data); + mem_offset = itv->dec_mem + data[1]; + + if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME, + mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) { + IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n", + IVTV_DECODE_INIT_MPEG_FILENAME); + } else { + ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0); + ivtv_msleep_timeout(100, 0); + } + ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); +} + +/* Try to restart the card & restore previous settings */ +int ivtv_firmware_restart(struct ivtv *itv) +{ + int rc = 0; + v4l2_std_id std; + + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) + /* Display test image during restart */ + ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, + SAA7127_INPUT_TYPE_TEST_IMAGE, + itv->card->video_outputs[itv->active_output].video_output, + 0); + + mutex_lock(&itv->udma.lock); + + rc = ivtv_firmware_init(itv); + if (rc) { + mutex_unlock(&itv->udma.lock); + return rc; + } + + /* Allow settings to reload */ + ivtv_mailbox_cache_invalidate(itv); + + /* Restore encoder video standard */ + std = itv->std; + itv->std = 0; + ivtv_s_std_enc(itv, &std); + + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_init_mpeg_decoder(itv); + + /* Restore decoder video standard */ + std = itv->std_out; + itv->std_out = 0; + ivtv_s_std_dec(itv, &std); + + /* Restore framebuffer if active */ + if (itv->ivtvfb_restore) + itv->ivtvfb_restore(itv); + + /* Restore alpha settings */ + ivtv_set_osd_alpha(itv); + + /* Restore normal output */ + ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, + SAA7127_INPUT_TYPE_NORMAL, + itv->card->video_outputs[itv->active_output].video_output, + 0); + } + + mutex_unlock(&itv->udma.lock); + return rc; +} + +/* Check firmware running state. The checks fall through + allowing multiple failures to be logged. */ +int ivtv_firmware_check(struct ivtv *itv, char *where) +{ + int res = 0; + + /* Check encoder is still running */ + if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) { + IVTV_WARN("Encoder has died : %s\n", where); + res = -1; + } + + /* Also check audio. Only check if not in use & encoder is okay */ + if (!res && !atomic_read(&itv->capturing) && + (!atomic_read(&itv->decoding) || + (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV, + &itv->i_flags)))) { + + if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) { + IVTV_WARN("Audio has died (Encoder OK) : %s\n", where); + res = -2; + } + } + + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + /* Second audio check. Skip if audio already failed */ + if (res != -2 && read_dec(0x100) != read_dec(0x104)) { + /* Wait & try again to be certain. */ + ivtv_msleep_timeout(14, 0); + if (read_dec(0x100) != read_dec(0x104)) { + IVTV_WARN("Audio has died (Decoder) : %s\n", + where); + res = -1; + } + } + + /* Check decoder is still running */ + if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) { + IVTV_WARN("Decoder has died : %s\n", where); + res = -1; + } + } + + /* If something failed & currently idle, try to reload */ + if (res && !atomic_read(&itv->capturing) && + !atomic_read(&itv->decoding)) { + IVTV_INFO("Detected in %s that firmware had failed - " + "Reloading\n", where); + res = ivtv_firmware_restart(itv); + /* + * Even if restarted ok, still signal a problem had occurred. + * The caller can come through this function again to check + * if things are really ok after the restart. + */ + if (!res) { + IVTV_INFO("Firmware restart okay\n"); + res = -EAGAIN; + } else { + IVTV_INFO("Firmware restart failed\n"); + } + } else if (res) { + res = -EIO; + } + + return res; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-firmware.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-firmware.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-firmware.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,31 @@ +/* + ivtv firmware functions. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_FIRMWARE_H +#define IVTV_FIRMWARE_H + +int ivtv_firmware_init(struct ivtv *itv); +void ivtv_firmware_versions(struct ivtv *itv); +void ivtv_halt_firmware(struct ivtv *itv); +void ivtv_init_mpeg_decoder(struct ivtv *itv); +int ivtv_firmware_check(struct ivtv *itv, char *where); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-gpio.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-gpio.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-gpio.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-gpio.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,374 @@ +/* + gpio functions. + Merging GPIO support into driver: + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-cards.h" +#include "ivtv-gpio.h" +#include "tuner-xc2028.h" +#include +#include + +/* + * GPIO assignment of Yuan MPG600/MPG160 + * + * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 + * OUTPUT IN1 IN0 AM3 AM2 AM1 AM0 + * INPUT DM1 DM0 + * + * IN* : Input selection + * IN1 IN0 + * 1 1 N/A + * 1 0 Line + * 0 1 N/A + * 0 0 Tuner + * + * AM* : Audio Mode + * AM3 0: Normal 1: Mixed(Sub+Main channel) + * AM2 0: Subchannel 1: Main channel + * AM1 0: Stereo 1: Mono + * AM0 0: Normal 1: Mute + * + * DM* : Detected tuner audio Mode + * DM1 0: Stereo 1: Mono + * DM0 0: Multiplex 1: Normal + * + * GPIO Initial Settings + * MPG600 MPG160 + * DIR 0x3080 0x7080 + * OUTPUT 0x000C 0x400C + * + * Special thanks to Makoto Iguchi and Mr. Anonymous + * for analyzing GPIO of MPG160. + * + ***************************************************************************** + * + * GPIO assignment of Avermedia M179 (per information direct from AVerMedia) + * + * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 + * OUTPUT IN0 AM0 IN1 AM1 AM2 IN2 BR0 BR1 + * INPUT + * + * IN* : Input selection + * IN0 IN1 IN2 + * * 1 * Mute + * 0 0 0 Line-In + * 1 0 0 TV Tuner Audio + * 0 0 1 FM Audio + * 1 0 1 Mute + * + * AM* : Audio Mode + * AM0 AM1 AM2 + * 0 0 0 TV Tuner Audio: L_OUT=(L+R)/2, R_OUT=SAP + * 0 0 1 TV Tuner Audio: L_OUT=R_OUT=SAP (SAP) + * 0 1 0 TV Tuner Audio: L_OUT=L, R_OUT=R (stereo) + * 0 1 1 TV Tuner Audio: mute + * 1 * * TV Tuner Audio: L_OUT=R_OUT=(L+R)/2 (mono) + * + * BR* : Audio Sample Rate (BR stands for bitrate for some reason) + * BR0 BR1 + * 0 0 32 kHz + * 0 1 44.1 kHz + * 1 0 48 kHz + * + * DM* : Detected tuner audio Mode + * Unknown currently + * + * Special thanks to AVerMedia Technologies, Inc. and Jiun-Kuei Jung at + * AVerMedia for providing the GPIO information used to add support + * for the M179 cards. + */ + +/********************* GPIO stuffs *********************/ + +/* GPIO registers */ +#define IVTV_REG_GPIO_IN 0x9008 +#define IVTV_REG_GPIO_OUT 0x900c +#define IVTV_REG_GPIO_DIR 0x9020 + +void ivtv_reset_ir_gpio(struct ivtv *itv) +{ + int curdir, curout; + + if (itv->card->type != IVTV_CARD_PVR_150) + return; + IVTV_DEBUG_INFO("Resetting PVR150 IR\n"); + curout = read_reg(IVTV_REG_GPIO_OUT); + curdir = read_reg(IVTV_REG_GPIO_DIR); + curdir |= 0x80; + write_reg(curdir, IVTV_REG_GPIO_DIR); + curout = (curout & ~0xF) | 1; + write_reg(curout, IVTV_REG_GPIO_OUT); + /* We could use something else for smaller time */ + schedule_timeout_interruptible(msecs_to_jiffies(1)); + curout |= 2; + write_reg(curout, IVTV_REG_GPIO_OUT); + curdir &= ~0x80; + write_reg(curdir, IVTV_REG_GPIO_DIR); +} + +/* Xceive tuner reset function */ +int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value) +{ + struct i2c_algo_bit_data *algo = dev; + struct ivtv *itv = algo->data; + u32 curout; + + if (cmd != XC2028_TUNER_RESET) + return 0; + IVTV_DEBUG_INFO("Resetting tuner\n"); + curout = read_reg(IVTV_REG_GPIO_OUT); + curout &= ~(1 << itv->card->xceive_pin); + write_reg(curout, IVTV_REG_GPIO_OUT); + schedule_timeout_interruptible(msecs_to_jiffies(1)); + + curout |= 1 << itv->card->xceive_pin; + write_reg(curout, IVTV_REG_GPIO_OUT); + schedule_timeout_interruptible(msecs_to_jiffies(1)); + return 0; +} + +static inline struct ivtv *sd_to_ivtv(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ivtv, sd_gpio); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct ivtv, hdl_gpio)->sd_gpio; +} + +static int subdev_s_clock_freq(struct v4l2_subdev *sd, u32 freq) +{ + struct ivtv *itv = sd_to_ivtv(sd); + u16 mask, data; + + mask = itv->card->gpio_audio_freq.mask; + switch (freq) { + case 32000: + data = itv->card->gpio_audio_freq.f32000; + break; + case 44100: + data = itv->card->gpio_audio_freq.f44100; + break; + case 48000: + default: + data = itv->card->gpio_audio_freq.f48000; + break; + } + if (mask) + write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); + return 0; +} + +static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct ivtv *itv = sd_to_ivtv(sd); + u16 mask; + + mask = itv->card->gpio_audio_detect.mask; + if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask)) + vt->rxsubchans = V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + else + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + return 0; +} + +static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct ivtv *itv = sd_to_ivtv(sd); + u16 mask, data; + + mask = itv->card->gpio_audio_mode.mask; + switch (vt->audmode) { + case V4L2_TUNER_MODE_LANG1: + data = itv->card->gpio_audio_mode.lang1; + break; + case V4L2_TUNER_MODE_LANG2: + data = itv->card->gpio_audio_mode.lang2; + break; + case V4L2_TUNER_MODE_MONO: + data = itv->card->gpio_audio_mode.mono; + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + default: + data = itv->card->gpio_audio_mode.stereo; + break; + } + if (mask) + write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); + return 0; +} + +static int subdev_s_radio(struct v4l2_subdev *sd) +{ + struct ivtv *itv = sd_to_ivtv(sd); + u16 mask, data; + + mask = itv->card->gpio_audio_input.mask; + data = itv->card->gpio_audio_input.radio; + if (mask) + write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); + return 0; +} + +static int subdev_s_audio_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct ivtv *itv = sd_to_ivtv(sd); + u16 mask, data; + + if (input > 2) + return -EINVAL; + mask = itv->card->gpio_audio_input.mask; + switch (input) { + case 0: + data = itv->card->gpio_audio_input.tuner; + break; + case 1: + data = itv->card->gpio_audio_input.linein; + break; + case 2: + default: + data = itv->card->gpio_audio_input.radio; + break; + } + if (mask) + write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); + return 0; +} + +static int subdev_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct ivtv *itv = sd_to_ivtv(sd); + u16 mask, data; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + mask = itv->card->gpio_audio_mute.mask; + data = ctrl->val ? itv->card->gpio_audio_mute.mute : 0; + if (mask) + write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | + (data & mask), IVTV_REG_GPIO_OUT); + return 0; + } + return -EINVAL; +} + + +static int subdev_log_status(struct v4l2_subdev *sd) +{ + struct ivtv *itv = sd_to_ivtv(sd); + + IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n", + read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT), + read_reg(IVTV_REG_GPIO_IN)); + v4l2_ctrl_handler_log_status(&itv->hdl_gpio, sd->name); + return 0; +} + +static int subdev_s_video_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct ivtv *itv = sd_to_ivtv(sd); + u16 mask, data; + + if (input > 2) /* 0:Tuner 1:Composite 2:S-Video */ + return -EINVAL; + mask = itv->card->gpio_video_input.mask; + if (input == 0) + data = itv->card->gpio_video_input.tuner; + else if (input == 1) + data = itv->card->gpio_video_input.composite; + else + data = itv->card->gpio_video_input.svideo; + if (mask) + write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); + return 0; +} + +static const struct v4l2_ctrl_ops gpio_ctrl_ops = { + .s_ctrl = subdev_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops subdev_core_ops = { + .log_status = subdev_log_status, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, +}; + +static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = { + .s_radio = subdev_s_radio, + .g_tuner = subdev_g_tuner, + .s_tuner = subdev_s_tuner, +}; + +static const struct v4l2_subdev_audio_ops subdev_audio_ops = { + .s_clock_freq = subdev_s_clock_freq, + .s_routing = subdev_s_audio_routing, +}; + +static const struct v4l2_subdev_video_ops subdev_video_ops = { + .s_routing = subdev_s_video_routing, +}; + +static const struct v4l2_subdev_ops subdev_ops = { + .core = &subdev_core_ops, + .tuner = &subdev_tuner_ops, + .audio = &subdev_audio_ops, + .video = &subdev_video_ops, +}; + +int ivtv_gpio_init(struct ivtv *itv) +{ + u16 pin = 0; + + if (itv->card->xceive_pin) + pin = 1 << itv->card->xceive_pin; + + if ((itv->card->gpio_init.direction | pin) == 0) + return 0; + + IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", + read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT)); + + /* init output data then direction */ + write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT); + write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR); + v4l2_subdev_init(&itv->sd_gpio, &subdev_ops); + snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->v4l2_dev.name); + itv->sd_gpio.grp_id = IVTV_HW_GPIO; + v4l2_ctrl_handler_init(&itv->hdl_gpio, 1); + v4l2_ctrl_new_std(&itv->hdl_gpio, &gpio_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + if (itv->hdl_gpio.error) + return itv->hdl_gpio.error; + itv->sd_gpio.ctrl_handler = &itv->hdl_gpio; + v4l2_ctrl_handler_setup(&itv->hdl_gpio); + return v4l2_device_register_subdev(&itv->v4l2_dev, &itv->sd_gpio); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-gpio.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-gpio.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-gpio.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-gpio.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,29 @@ +/* + gpio functions. + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_GPIO_H +#define IVTV_GPIO_H + +/* GPIO stuff */ +int ivtv_gpio_init(struct ivtv *itv); +void ivtv_reset_ir_gpio(struct ivtv *itv); +int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-i2c.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-i2c.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-i2c.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-i2c.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,760 @@ +/* + I2C functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +/* + This file includes an i2c implementation that was reverse engineered + from the Hauppauge windows driver. Older ivtv versions used i2c-algo-bit, + which whilst fine under most circumstances, had trouble with the Zilog + CPU on the PVR-150 which handles IR functions (occasional inability to + communicate with the chip until it was reset) and also with the i2c + bus being completely unreachable when multiple PVR cards were present. + + The implementation is very similar to i2c-algo-bit, but there are enough + subtle differences that the two are hard to merge. The general strategy + employed by i2c-algo-bit is to use udelay() to implement the timing + when putting out bits on the scl/sda lines. The general strategy taken + here is to poll the lines for state changes (see ivtv_waitscl and + ivtv_waitsda). In addition there are small delays at various locations + which poll the SCL line 5 times (ivtv_scldelay). I would guess that + since this is memory mapped I/O that the length of those delays is tied + to the PCI bus clock. There is some extra code to do with recovery + and retries. Since it is not known what causes the actual i2c problems + in the first place, the only goal if one was to attempt to use + i2c-algo-bit would be to try to make it follow the same code path. + This would be a lot of work, and I'm also not convinced that it would + provide a generic benefit to i2c-algo-bit. Therefore consider this + an engineering solution -- not pretty, but it works. + + Some more general comments about what we are doing: + + The i2c bus is a 2 wire serial bus, with clock (SCL) and data (SDA) + lines. To communicate on the bus (as a master, we don't act as a slave), + we first initiate a start condition (ivtv_start). We then write the + address of the device that we want to communicate with, along with a flag + that indicates whether this is a read or a write. The slave then issues + an ACK signal (ivtv_ack), which tells us that it is ready for reading / + writing. We then proceed with reading or writing (ivtv_read/ivtv_write), + and finally issue a stop condition (ivtv_stop) to make the bus available + to other masters. + + There is an additional form of transaction where a write may be + immediately followed by a read. In this case, there is no intervening + stop condition. (Only the msp3400 chip uses this method of data transfer). + */ + +#include "ivtv-driver.h" +#include "ivtv-cards.h" +#include "ivtv-gpio.h" +#include "ivtv-i2c.h" +#include + +/* i2c implementation for cx23415/6 chip, ivtv project. + * Author: Kevin Thayer (nufan_wfk at yahoo.com) + */ +/* i2c stuff */ +#define IVTV_REG_I2C_SETSCL_OFFSET 0x7000 +#define IVTV_REG_I2C_SETSDA_OFFSET 0x7004 +#define IVTV_REG_I2C_GETSCL_OFFSET 0x7008 +#define IVTV_REG_I2C_GETSDA_OFFSET 0x700c + +#define IVTV_CS53L32A_I2C_ADDR 0x11 +#define IVTV_M52790_I2C_ADDR 0x48 +#define IVTV_CX25840_I2C_ADDR 0x44 +#define IVTV_SAA7115_I2C_ADDR 0x21 +#define IVTV_SAA7127_I2C_ADDR 0x44 +#define IVTV_SAA717x_I2C_ADDR 0x21 +#define IVTV_MSP3400_I2C_ADDR 0x40 +#define IVTV_HAUPPAUGE_I2C_ADDR 0x50 +#define IVTV_WM8739_I2C_ADDR 0x1a +#define IVTV_WM8775_I2C_ADDR 0x1b +#define IVTV_TEA5767_I2C_ADDR 0x60 +#define IVTV_UPD64031A_I2C_ADDR 0x12 +#define IVTV_UPD64083_I2C_ADDR 0x5c +#define IVTV_VP27SMPX_I2C_ADDR 0x5b +#define IVTV_M52790_I2C_ADDR 0x48 +#define IVTV_AVERMEDIA_IR_RX_I2C_ADDR 0x40 +#define IVTV_HAUP_EXT_IR_RX_I2C_ADDR 0x1a +#define IVTV_HAUP_INT_IR_RX_I2C_ADDR 0x18 +#define IVTV_Z8F0811_IR_TX_I2C_ADDR 0x70 +#define IVTV_Z8F0811_IR_RX_I2C_ADDR 0x71 +#define IVTV_ADAPTEC_IR_ADDR 0x6b + +/* This array should match the IVTV_HW_ defines */ +static const u8 hw_addrs[] = { + IVTV_CX25840_I2C_ADDR, + IVTV_SAA7115_I2C_ADDR, + IVTV_SAA7127_I2C_ADDR, + IVTV_MSP3400_I2C_ADDR, + 0, + IVTV_WM8775_I2C_ADDR, + IVTV_CS53L32A_I2C_ADDR, + 0, + IVTV_SAA7115_I2C_ADDR, + IVTV_UPD64031A_I2C_ADDR, + IVTV_UPD64083_I2C_ADDR, + IVTV_SAA717x_I2C_ADDR, + IVTV_WM8739_I2C_ADDR, + IVTV_VP27SMPX_I2C_ADDR, + IVTV_M52790_I2C_ADDR, + 0, /* IVTV_HW_GPIO dummy driver ID */ + IVTV_AVERMEDIA_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_AVER */ + IVTV_HAUP_EXT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_EXT */ + IVTV_HAUP_INT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_INT */ + IVTV_Z8F0811_IR_TX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_TX_HAUP */ + IVTV_Z8F0811_IR_RX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_RX_HAUP */ + IVTV_ADAPTEC_IR_ADDR, /* IVTV_HW_I2C_IR_RX_ADAPTEC */ +}; + +/* This array should match the IVTV_HW_ defines */ +static const char * const hw_devicenames[] = { + "cx25840", + "saa7115", + "saa7127_auto", /* saa7127 or saa7129 */ + "msp3400", + "tuner", + "wm8775", + "cs53l32a", + "tveeprom", + "saa7114", + "upd64031a", + "upd64083", + "saa717x", + "wm8739", + "vp27smpx", + "m52790", + "gpio", + "ir_video", /* IVTV_HW_I2C_IR_RX_AVER */ + "ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_EXT */ + "ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_INT */ + "ir_tx_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_TX_HAUP */ + "ir_rx_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_RX_HAUP */ + "ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */ +}; + +static int get_key_adaptec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char keybuf[4]; + + keybuf[0] = 0x00; + i2c_master_send(ir->c, keybuf, 1); + /* poll IR chip */ + if (i2c_master_recv(ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) { + return 0; + } + + /* key pressed ? */ + if (keybuf[2] == 0xff) + return 0; + + /* remove repeat bit */ + keybuf[2] &= 0x7f; + keybuf[3] |= 0x80; + + *ir_key = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24; + *ir_raw = *ir_key; + + return 1; +} + +static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) +{ + struct i2c_board_info info; + struct i2c_adapter *adap = &itv->i2c_adap; + struct IR_i2c_init_data *init_data = &itv->ir_i2c_init_data; + unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; + + /* Only allow one IR transmitter to be registered per board */ + if (hw & IVTV_HW_IR_TX_ANY) { + if (itv->hw_flags & IVTV_HW_IR_TX_ANY) + return -1; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, type, I2C_NAME_SIZE); + return i2c_new_probed_device(adap, &info, addr_list, NULL) + == NULL ? -1 : 0; + } + + /* Only allow one IR receiver to be registered per board */ + if (itv->hw_flags & IVTV_HW_IR_RX_ANY) + return -1; + + /* Our default information for ir-kbd-i2c.c to use */ + switch (hw) { + case IVTV_HW_I2C_IR_RX_AVER: + init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS; + init_data->internal_get_key_func = + IR_KBD_GET_KEY_AVERMEDIA_CARDBUS; + init_data->type = RC_TYPE_OTHER; + init_data->name = "AVerMedia AVerTV card"; + break; + case IVTV_HW_I2C_IR_RX_HAUP_EXT: + case IVTV_HW_I2C_IR_RX_HAUP_INT: + init_data->ir_codes = RC_MAP_HAUPPAUGE; + init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; + init_data->type = RC_TYPE_RC5; + init_data->name = itv->card_name; + break; + case IVTV_HW_Z8F0811_IR_RX_HAUP: + /* Default to grey remote */ + init_data->ir_codes = RC_MAP_HAUPPAUGE; + init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; + init_data->type = RC_TYPE_RC5; + init_data->name = itv->card_name; + break; + case IVTV_HW_I2C_IR_RX_ADAPTEC: + init_data->get_key = get_key_adaptec; + init_data->name = itv->card_name; + /* FIXME: The protocol and RC_MAP needs to be corrected */ + init_data->ir_codes = RC_MAP_EMPTY; + init_data->type = RC_TYPE_UNKNOWN; + break; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.platform_data = init_data; + strlcpy(info.type, type, I2C_NAME_SIZE); + + return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? + -1 : 0; +} + +/* Instantiate the IR receiver device using probing -- undesirable */ +struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv) +{ + struct i2c_board_info info; + /* + * The external IR receiver is at i2c address 0x34. + * The internal IR receiver is at i2c address 0x30. + * + * In theory, both can be fitted, and Hauppauge suggests an external + * overrides an internal. That's why we probe 0x1a (~0x34) first. CB + * + * Some of these addresses we probe may collide with other i2c address + * allocations, so this function must be called after all other i2c + * devices we care about are registered. + */ + const unsigned short addr_list[] = { + 0x1a, /* Hauppauge IR external - collides with WM8739 */ + 0x18, /* Hauppauge IR internal */ + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list, NULL); +} + +int ivtv_i2c_register(struct ivtv *itv, unsigned idx) +{ + struct v4l2_subdev *sd; + struct i2c_adapter *adap = &itv->i2c_adap; + const char *type = hw_devicenames[idx]; + u32 hw = 1 << idx; + + if (idx >= ARRAY_SIZE(hw_addrs)) + return -1; + if (hw == IVTV_HW_TUNER) { + /* special tuner handling */ + sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, + itv->card_i2c->radio); + if (sd) + sd->grp_id = 1 << idx; + sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, + itv->card_i2c->demod); + if (sd) + sd->grp_id = 1 << idx; + sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, + itv->card_i2c->tv); + if (sd) + sd->grp_id = 1 << idx; + return sd ? 0 : -1; + } + + if (hw & IVTV_HW_IR_ANY) + return ivtv_i2c_new_ir(itv, hw, type, hw_addrs[idx]); + + /* Is it not an I2C device or one we do not wish to register? */ + if (!hw_addrs[idx]) + return -1; + + /* It's an I2C device other than an analog tuner or IR chip */ + if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) { + sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, + adap, type, 0, I2C_ADDRS(hw_addrs[idx])); + } else if (hw == IVTV_HW_CX25840) { + struct cx25840_platform_data pdata; + struct i2c_board_info cx25840_info = { + .type = "cx25840", + .addr = hw_addrs[idx], + .platform_data = &pdata, + }; + + pdata.pvr150_workaround = itv->pvr150_workaround; + sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, + &cx25840_info, NULL); + } else { + sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, + adap, type, hw_addrs[idx], NULL); + } + if (sd) + sd->grp_id = 1 << idx; + return sd ? 0 : -1; +} + +struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw) +{ + struct v4l2_subdev *result = NULL; + struct v4l2_subdev *sd; + + spin_lock(&itv->v4l2_dev.lock); + v4l2_device_for_each_subdev(sd, &itv->v4l2_dev) { + if (sd->grp_id == hw) { + result = sd; + break; + } + } + spin_unlock(&itv->v4l2_dev.lock); + return result; +} + +/* Set the serial clock line to the desired state */ +static void ivtv_setscl(struct ivtv *itv, int state) +{ + /* write them out */ + /* write bits are inverted */ + write_reg(~state, IVTV_REG_I2C_SETSCL_OFFSET); +} + +/* Set the serial data line to the desired state */ +static void ivtv_setsda(struct ivtv *itv, int state) +{ + /* write them out */ + /* write bits are inverted */ + write_reg(~state & 1, IVTV_REG_I2C_SETSDA_OFFSET); +} + +/* Read the serial clock line */ +static int ivtv_getscl(struct ivtv *itv) +{ + return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; +} + +/* Read the serial data line */ +static int ivtv_getsda(struct ivtv *itv) +{ + return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; +} + +/* Implement a short delay by polling the serial clock line */ +static void ivtv_scldelay(struct ivtv *itv) +{ + int i; + + for (i = 0; i < 5; ++i) + ivtv_getscl(itv); +} + +/* Wait for the serial clock line to become set to a specific value */ +static int ivtv_waitscl(struct ivtv *itv, int val) +{ + int i; + + ivtv_scldelay(itv); + for (i = 0; i < 1000; ++i) { + if (ivtv_getscl(itv) == val) + return 1; + } + return 0; +} + +/* Wait for the serial data line to become set to a specific value */ +static int ivtv_waitsda(struct ivtv *itv, int val) +{ + int i; + + ivtv_scldelay(itv); + for (i = 0; i < 1000; ++i) { + if (ivtv_getsda(itv) == val) + return 1; + } + return 0; +} + +/* Wait for the slave to issue an ACK */ +static int ivtv_ack(struct ivtv *itv) +{ + int ret = 0; + + if (ivtv_getscl(itv) == 1) { + IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n"); + ivtv_setscl(itv, 0); + if (!ivtv_waitscl(itv, 0)) { + IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n"); + return -EREMOTEIO; + } + } + ivtv_setsda(itv, 1); + ivtv_scldelay(itv); + ivtv_setscl(itv, 1); + if (!ivtv_waitsda(itv, 0)) { + IVTV_DEBUG_I2C("Slave did not ack\n"); + ret = -EREMOTEIO; + } + ivtv_setscl(itv, 0); + if (!ivtv_waitscl(itv, 0)) { + IVTV_DEBUG_I2C("Failed to set SCL low after ACK\n"); + ret = -EREMOTEIO; + } + return ret; +} + +/* Write a single byte to the i2c bus and wait for the slave to ACK */ +static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte) +{ + int i, bit; + + IVTV_DEBUG_HI_I2C("write %x\n",byte); + for (i = 0; i < 8; ++i, byte<<=1) { + ivtv_setscl(itv, 0); + if (!ivtv_waitscl(itv, 0)) { + IVTV_DEBUG_I2C("Error setting SCL low\n"); + return -EREMOTEIO; + } + bit = (byte>>7)&1; + ivtv_setsda(itv, bit); + if (!ivtv_waitsda(itv, bit)) { + IVTV_DEBUG_I2C("Error setting SDA\n"); + return -EREMOTEIO; + } + ivtv_setscl(itv, 1); + if (!ivtv_waitscl(itv, 1)) { + IVTV_DEBUG_I2C("Slave not ready for bit\n"); + return -EREMOTEIO; + } + } + ivtv_setscl(itv, 0); + if (!ivtv_waitscl(itv, 0)) { + IVTV_DEBUG_I2C("Error setting SCL low\n"); + return -EREMOTEIO; + } + return ivtv_ack(itv); +} + +/* Read a byte from the i2c bus and send a NACK if applicable (i.e. for the + final byte) */ +static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack) +{ + int i; + + *byte = 0; + + ivtv_setsda(itv, 1); + ivtv_scldelay(itv); + for (i = 0; i < 8; ++i) { + ivtv_setscl(itv, 0); + ivtv_scldelay(itv); + ivtv_setscl(itv, 1); + if (!ivtv_waitscl(itv, 1)) { + IVTV_DEBUG_I2C("Error setting SCL high\n"); + return -EREMOTEIO; + } + *byte = ((*byte)<<1)|ivtv_getsda(itv); + } + ivtv_setscl(itv, 0); + ivtv_scldelay(itv); + ivtv_setsda(itv, nack); + ivtv_scldelay(itv); + ivtv_setscl(itv, 1); + ivtv_scldelay(itv); + ivtv_setscl(itv, 0); + ivtv_scldelay(itv); + IVTV_DEBUG_HI_I2C("read %x\n",*byte); + return 0; +} + +/* Issue a start condition on the i2c bus to alert slaves to prepare for + an address write */ +static int ivtv_start(struct ivtv *itv) +{ + int sda; + + sda = ivtv_getsda(itv); + if (sda != 1) { + IVTV_DEBUG_HI_I2C("SDA was low at start\n"); + ivtv_setsda(itv, 1); + if (!ivtv_waitsda(itv, 1)) { + IVTV_DEBUG_I2C("SDA stuck low\n"); + return -EREMOTEIO; + } + } + if (ivtv_getscl(itv) != 1) { + ivtv_setscl(itv, 1); + if (!ivtv_waitscl(itv, 1)) { + IVTV_DEBUG_I2C("SCL stuck low at start\n"); + return -EREMOTEIO; + } + } + ivtv_setsda(itv, 0); + ivtv_scldelay(itv); + return 0; +} + +/* Issue a stop condition on the i2c bus to release it */ +static int ivtv_stop(struct ivtv *itv) +{ + int i; + + if (ivtv_getscl(itv) != 0) { + IVTV_DEBUG_HI_I2C("SCL not low when stopping\n"); + ivtv_setscl(itv, 0); + if (!ivtv_waitscl(itv, 0)) { + IVTV_DEBUG_I2C("SCL could not be set low\n"); + } + } + ivtv_setsda(itv, 0); + ivtv_scldelay(itv); + ivtv_setscl(itv, 1); + if (!ivtv_waitscl(itv, 1)) { + IVTV_DEBUG_I2C("SCL could not be set high\n"); + return -EREMOTEIO; + } + ivtv_scldelay(itv); + ivtv_setsda(itv, 1); + if (!ivtv_waitsda(itv, 1)) { + IVTV_DEBUG_I2C("resetting I2C\n"); + for (i = 0; i < 16; ++i) { + ivtv_setscl(itv, 0); + ivtv_scldelay(itv); + ivtv_setscl(itv, 1); + ivtv_scldelay(itv); + ivtv_setsda(itv, 1); + } + ivtv_waitsda(itv, 1); + return -EREMOTEIO; + } + return 0; +} + +/* Write a message to the given i2c slave. do_stop may be 0 to prevent + issuing the i2c stop condition (when following with a read) */ +static int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop) +{ + int retry, ret = -EREMOTEIO; + u32 i; + + for (retry = 0; ret != 0 && retry < 8; ++retry) { + ret = ivtv_start(itv); + + if (ret == 0) { + ret = ivtv_sendbyte(itv, addr<<1); + for (i = 0; ret == 0 && i < len; ++i) + ret = ivtv_sendbyte(itv, data[i]); + } + if (ret != 0 || do_stop) { + ivtv_stop(itv); + } + } + if (ret) + IVTV_DEBUG_I2C("i2c write to %x failed\n", addr); + return ret; +} + +/* Read data from the given i2c slave. A stop condition is always issued. */ +static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len) +{ + int retry, ret = -EREMOTEIO; + u32 i; + + for (retry = 0; ret != 0 && retry < 8; ++retry) { + ret = ivtv_start(itv); + if (ret == 0) + ret = ivtv_sendbyte(itv, (addr << 1) | 1); + for (i = 0; ret == 0 && i < len; ++i) { + ret = ivtv_readbyte(itv, &data[i], i == len - 1); + } + ivtv_stop(itv); + } + if (ret) + IVTV_DEBUG_I2C("i2c read from %x failed\n", addr); + return ret; +} + +/* Kernel i2c transfer implementation. Takes a number of messages to be read + or written. If a read follows a write, this will occur without an + intervening stop condition */ +static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap); + struct ivtv *itv = to_ivtv(v4l2_dev); + int retval; + int i; + + mutex_lock(&itv->i2c_bus_lock); + for (i = retval = 0; retval == 0 && i < num; i++) { + if (msgs[i].flags & I2C_M_RD) + retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len); + else { + /* if followed by a read, don't stop */ + int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD); + + retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop); + } + } + mutex_unlock(&itv->i2c_bus_lock); + return retval ? retval : num; +} + +/* Kernel i2c capabilities */ +static u32 ivtv_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm ivtv_algo = { + .master_xfer = ivtv_xfer, + .functionality = ivtv_functionality, +}; + +/* template for our-bit banger */ +static struct i2c_adapter ivtv_i2c_adap_hw_template = { + .name = "ivtv i2c driver", + .algo = &ivtv_algo, + .algo_data = NULL, /* filled from template */ + .owner = THIS_MODULE, +}; + +static void ivtv_setscl_old(void *data, int state) +{ + struct ivtv *itv = (struct ivtv *)data; + + if (state) + itv->i2c_state |= 0x01; + else + itv->i2c_state &= ~0x01; + + /* write them out */ + /* write bits are inverted */ + write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET); +} + +static void ivtv_setsda_old(void *data, int state) +{ + struct ivtv *itv = (struct ivtv *)data; + + if (state) + itv->i2c_state |= 0x01; + else + itv->i2c_state &= ~0x01; + + /* write them out */ + /* write bits are inverted */ + write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET); +} + +static int ivtv_getscl_old(void *data) +{ + struct ivtv *itv = (struct ivtv *)data; + + return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; +} + +static int ivtv_getsda_old(void *data) +{ + struct ivtv *itv = (struct ivtv *)data; + + return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; +} + +/* template for i2c-bit-algo */ +static struct i2c_adapter ivtv_i2c_adap_template = { + .name = "ivtv i2c driver", + .algo = NULL, /* set by i2c-algo-bit */ + .algo_data = NULL, /* filled from template */ + .owner = THIS_MODULE, +}; + +#define IVTV_ALGO_BIT_TIMEOUT (2) /* seconds */ + +static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { + .setsda = ivtv_setsda_old, + .setscl = ivtv_setscl_old, + .getsda = ivtv_getsda_old, + .getscl = ivtv_getscl_old, + .udelay = IVTV_DEFAULT_I2C_CLOCK_PERIOD / 2, /* microseconds */ + .timeout = IVTV_ALGO_BIT_TIMEOUT * HZ, /* jiffies */ +}; + +static struct i2c_client ivtv_i2c_client_template = { + .name = "ivtv internal", +}; + +/* init + register i2c adapter */ +int init_ivtv_i2c(struct ivtv *itv) +{ + int retval; + + IVTV_DEBUG_I2C("i2c init\n"); + + /* Sanity checks for the I2C hardware arrays. They must be the + * same size. + */ + if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs)) { + IVTV_ERR("Mismatched I2C hardware arrays\n"); + return -ENODEV; + } + if (itv->options.newi2c > 0) { + memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template, + sizeof(struct i2c_adapter)); + } else { + memcpy(&itv->i2c_adap, &ivtv_i2c_adap_template, + sizeof(struct i2c_adapter)); + memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, + sizeof(struct i2c_algo_bit_data)); + } + itv->i2c_algo.udelay = itv->options.i2c_clock_period / 2; + itv->i2c_algo.data = itv; + itv->i2c_adap.algo_data = &itv->i2c_algo; + + sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", + itv->instance); + i2c_set_adapdata(&itv->i2c_adap, &itv->v4l2_dev); + + memcpy(&itv->i2c_client, &ivtv_i2c_client_template, + sizeof(struct i2c_client)); + itv->i2c_client.adapter = &itv->i2c_adap; + itv->i2c_adap.dev.parent = &itv->pdev->dev; + + IVTV_DEBUG_I2C("setting scl and sda to 1\n"); + ivtv_setscl(itv, 1); + ivtv_setsda(itv, 1); + + if (itv->options.newi2c > 0) + retval = i2c_add_adapter(&itv->i2c_adap); + else + retval = i2c_bit_add_bus(&itv->i2c_adap); + + return retval; +} + +void exit_ivtv_i2c(struct ivtv *itv) +{ + IVTV_DEBUG_I2C("i2c exit\n"); + + i2c_del_adapter(&itv->i2c_adap); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-i2c.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-i2c.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-i2c.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-i2c.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,32 @@ +/* + I2C functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_I2C_H +#define IVTV_I2C_H + +struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv); +int ivtv_i2c_register(struct ivtv *itv, unsigned idx); +struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw); + +/* init + register i2c algo-bit adapter */ +int init_ivtv_i2c(struct ivtv *itv); +void exit_ivtv_i2c(struct ivtv *itv); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-ioctl.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-ioctl.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-ioctl.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-ioctl.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1937 @@ +/* + ioctl system call + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-version.h" +#include "ivtv-mailbox.h" +#include "ivtv-i2c.h" +#include "ivtv-queue.h" +#include "ivtv-fileops.h" +#include "ivtv-vbi.h" +#include "ivtv-routing.h" +#include "ivtv-streams.h" +#include "ivtv-yuv.h" +#include "ivtv-ioctl.h" +#include "ivtv-gpio.h" +#include "ivtv-controls.h" +#include "ivtv-cards.h" +#include +#include +#include +#include +#include + +u16 ivtv_service2vbi(int type) +{ + switch (type) { + case V4L2_SLICED_TELETEXT_B: + return IVTV_SLICED_TYPE_TELETEXT_B; + case V4L2_SLICED_CAPTION_525: + return IVTV_SLICED_TYPE_CAPTION_525; + case V4L2_SLICED_WSS_625: + return IVTV_SLICED_TYPE_WSS_625; + case V4L2_SLICED_VPS: + return IVTV_SLICED_TYPE_VPS; + default: + return 0; + } +} + +static int valid_service_line(int field, int line, int is_pal) +{ + return (is_pal && line >= 6 && (line != 23 || field == 0)) || + (!is_pal && line >= 10 && line < 22); +} + +static u16 select_service_from_set(int field, int line, u16 set, int is_pal) +{ + u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); + int i; + + set = set & valid_set; + if (set == 0 || !valid_service_line(field, line, is_pal)) { + return 0; + } + if (!is_pal) { + if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) + return V4L2_SLICED_CAPTION_525; + } + else { + if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) + return V4L2_SLICED_VPS; + if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) + return V4L2_SLICED_WSS_625; + if (line == 23) + return 0; + } + for (i = 0; i < 32; i++) { + if ((1 << i) & set) + return 1 << i; + } + return 0; +} + +void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + u16 set = fmt->service_set; + int f, l; + + fmt->service_set = 0; + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); + } + } +} + +static void check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + int f, l; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); + } + } +} + +u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt) +{ + int f, l; + u16 set = 0; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + set |= fmt->service_lines[f][l]; + } + } + return set; +} + +void ivtv_set_osd_alpha(struct ivtv *itv) +{ + ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, + itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); + ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key); +} + +int ivtv_set_speed(struct ivtv *itv, int speed) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + struct ivtv_stream *s; + int single_step = (speed == 1 || speed == -1); + DEFINE_WAIT(wait); + + if (speed == 0) speed = 1000; + + /* No change? */ + if (speed == itv->speed && !single_step) + return 0; + + s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; + + if (single_step && (speed < 0) == (itv->speed < 0)) { + /* Single step video and no need to change direction */ + ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); + itv->speed = speed; + return 0; + } + if (single_step) + /* Need to change direction */ + speed = speed < 0 ? -1000 : 1000; + + data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0; + data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0; + data[1] = (speed < 0); + data[2] = speed < 0 ? 3 : 7; + data[3] = v4l2_ctrl_g_ctrl(itv->cxhdl.video_b_frames); + data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0; + data[5] = 0; + data[6] = 0; + + if (speed == 1500 || speed == -1500) data[0] |= 1; + else if (speed == 2000 || speed == -2000) data[0] |= 2; + else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed); + else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed); + + /* If not decoding, just change speed setting */ + if (atomic_read(&itv->decoding) > 0) { + int got_sig = 0; + + /* Stop all DMA and decoding activity */ + ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0); + + /* Wait for any DMA to finish */ + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + while (test_bit(IVTV_F_I_DMA, &itv->i_flags)) { + got_sig = signal_pending(current); + if (got_sig) + break; + got_sig = 0; + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + if (got_sig) + return -EINTR; + + /* Change Speed safely */ + ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data); + IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + data[0], data[1], data[2], data[3], data[4], data[5], data[6]); + } + if (single_step) { + speed = (speed < 0) ? -1 : 1; + ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); + } + itv->speed = speed; + return 0; +} + +static int ivtv_validate_speed(int cur_speed, int new_speed) +{ + int fact = new_speed < 0 ? -1 : 1; + int s; + + if (cur_speed == 0) + cur_speed = 1000; + if (new_speed < 0) + new_speed = -new_speed; + if (cur_speed < 0) + cur_speed = -cur_speed; + + if (cur_speed <= new_speed) { + if (new_speed > 1500) + return fact * 2000; + if (new_speed > 1000) + return fact * 1500; + } + else { + if (new_speed >= 2000) + return fact * 2000; + if (new_speed >= 1500) + return fact * 1500; + if (new_speed >= 1000) + return fact * 1000; + } + if (new_speed == 0) + return 1000; + if (new_speed == 1 || new_speed == 1000) + return fact * new_speed; + + s = new_speed; + new_speed = 1000 / new_speed; + if (1000 / cur_speed == new_speed) + new_speed += (cur_speed < s) ? -1 : 1; + if (new_speed > 60) return 1000 / (fact * 60); + return 1000 / (fact * new_speed); +} + +static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, + struct video_command *vc, int try) +{ + struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + + switch (vc->cmd) { + case VIDEO_CMD_PLAY: { + vc->flags = 0; + vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed); + if (vc->play.speed < 0) + vc->play.format = VIDEO_PLAY_FMT_GOP; + if (try) break; + + if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) + return -EBUSY; + if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { + /* forces ivtv_set_speed to be called */ + itv->speed = 0; + } + return ivtv_start_decoding(id, vc->play.speed); + } + + case VIDEO_CMD_STOP: + vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK; + if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY) + vc->stop.pts = 0; + if (try) break; + if (atomic_read(&itv->decoding) == 0) + return 0; + if (itv->output_mode != OUT_MPG) + return -EBUSY; + + itv->output_mode = OUT_NONE; + return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts); + + case VIDEO_CMD_FREEZE: + vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK; + if (try) break; + if (itv->output_mode != OUT_MPG) + return -EBUSY; + if (atomic_read(&itv->decoding) > 0) { + ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, + (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0); + set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); + } + break; + + case VIDEO_CMD_CONTINUE: + vc->flags = 0; + if (try) break; + if (itv->output_mode != OUT_MPG) + return -EBUSY; + if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { + int speed = itv->speed; + itv->speed = 0; + return ivtv_start_decoding(id, speed); + } + break; + + default: + return -EINVAL; + } + return 0; +} + +static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = fh2id(fh)->itv; + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) + return -EINVAL; + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + if (itv->is_60hz) { + vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; + } else { + vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; + vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; + } + vbifmt->service_set = ivtv_get_service_set(vbifmt); + return 0; +} + +static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + pixfmt->width = itv->cxhdl.width; + pixfmt->height = itv->cxhdl.height; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + pixfmt->priv = 0; + if (id->type == IVTV_ENC_STREAM_TYPE_YUV) { + pixfmt->pixelformat = V4L2_PIX_FMT_HM12; + /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */ + pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; + pixfmt->bytesperline = 720; + } else { + pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; + pixfmt->sizeimage = 128 * 1024; + pixfmt->bytesperline = 0; + } + return 0; +} + +static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = fh2id(fh)->itv; + struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; + + vbifmt->sampling_rate = 27000000; + vbifmt->offset = 248; + vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4; + vbifmt->sample_format = V4L2_PIX_FMT_GREY; + vbifmt->start[0] = itv->vbi.start[0]; + vbifmt->start[1] = itv->vbi.start[1]; + vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count; + vbifmt->flags = 0; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + return 0; +} + +static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + + if (id->type == IVTV_DEC_STREAM_TYPE_VBI) { + vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : + V4L2_SLICED_VBI_525; + ivtv_expand_service_set(vbifmt, itv->is_50hz); + return 0; + } + + v4l2_subdev_call(itv->sd_video, vbi, g_sliced_fmt, vbifmt); + vbifmt->service_set = ivtv_get_service_set(vbifmt); + return 0; +} + +static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + pixfmt->width = itv->main_rect.width; + pixfmt->height = itv->main_rect.height; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + pixfmt->priv = 0; + if (id->type == IVTV_DEC_STREAM_TYPE_YUV) { + switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { + case IVTV_YUV_MODE_INTERLACED: + pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? + V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; + break; + case IVTV_YUV_MODE_PROGRESSIVE: + pixfmt->field = V4L2_FIELD_NONE; + break; + default: + pixfmt->field = V4L2_FIELD_ANY; + break; + } + pixfmt->pixelformat = V4L2_PIX_FMT_HM12; + pixfmt->bytesperline = 720; + pixfmt->width = itv->yuv_info.v4l2_src_w; + pixfmt->height = itv->yuv_info.v4l2_src_h; + /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ + pixfmt->sizeimage = + 1080 * ((pixfmt->height + 31) & ~31); + } else { + pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; + pixfmt->sizeimage = 128 * 1024; + pixfmt->bytesperline = 0; + } + return 0; +} + +static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = fh2id(fh)->itv; + struct v4l2_window *winfmt = &fmt->fmt.win; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + winfmt->chromakey = itv->osd_chroma_key; + winfmt->global_alpha = itv->osd_global_alpha; + winfmt->field = V4L2_FIELD_INTERLACED; + winfmt->clips = NULL; + winfmt->clipcount = 0; + winfmt->bitmap = NULL; + winfmt->w.top = winfmt->w.left = 0; + winfmt->w.width = itv->osd_rect.width; + winfmt->w.height = itv->osd_rect.height; + return 0; +} + +static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); +} + +static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + int min_h = 2; + + w = min(w, 720); + w = max(w, 2); + if (id->type == IVTV_ENC_STREAM_TYPE_YUV) { + /* YUV height must be a multiple of 32 */ + h &= ~0x1f; + min_h = 32; + } + h = min(h, itv->is_50hz ? 576 : 480); + h = max(h, min_h); + ivtv_g_fmt_vid_cap(file, fh, fmt); + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + return 0; +} + +static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + return ivtv_g_fmt_vbi_cap(file, fh, fmt); +} + +static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + + if (id->type == IVTV_DEC_STREAM_TYPE_VBI) + return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt); + + /* set sliced VBI capture format */ + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + vbifmt->reserved[0] = 0; + vbifmt->reserved[1] = 0; + + if (vbifmt->service_set) + ivtv_expand_service_set(vbifmt, itv->is_50hz); + check_service_set(vbifmt, itv->is_50hz); + vbifmt->service_set = ivtv_get_service_set(vbifmt); + return 0; +} + +static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh2id(fh); + s32 w = fmt->fmt.pix.width; + s32 h = fmt->fmt.pix.height; + int field = fmt->fmt.pix.field; + int ret = ivtv_g_fmt_vid_out(file, fh, fmt); + + w = min(w, 720); + w = max(w, 2); + /* Why can the height be 576 even when the output is NTSC? + + Internally the buffers of the PVR350 are always set to 720x576. The + decoded video frame will always be placed in the top left corner of + this buffer. For any video which is not 720x576, the buffer will + then be cropped to remove the unused right and lower areas, with + the remaining image being scaled by the hardware to fit the display + area. The video can be scaled both up and down, so a 720x480 video + can be displayed full-screen on PAL and a 720x576 video can be + displayed without cropping on NTSC. + + Note that the scaling only occurs on the video stream, the osd + resolution is locked to the broadcast standard and not scaled. + + Thanks to Ian Armstrong for this explanation. */ + h = min(h, 576); + h = max(h, 2); + if (id->type == IVTV_DEC_STREAM_TYPE_YUV) + fmt->fmt.pix.field = field; + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + return ret; +} + +static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = fh2id(fh)->itv; + u32 chromakey = fmt->fmt.win.chromakey; + u8 global_alpha = fmt->fmt.win.global_alpha; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + ivtv_g_fmt_vid_out_overlay(file, fh, fmt); + fmt->fmt.win.chromakey = chromakey; + fmt->fmt.win.global_alpha = global_alpha; + return 0; +} + +static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); +} + +static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + struct v4l2_mbus_framefmt mbus_fmt; + int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + + if (ret) + return ret; + + if (itv->cxhdl.width == w && itv->cxhdl.height == h) + return 0; + + if (atomic_read(&itv->capturing) > 0) + return -EBUSY; + + itv->cxhdl.width = w; + itv->cxhdl.height = h; + if (v4l2_ctrl_g_ctrl(itv->cxhdl.video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + fmt->fmt.pix.width /= 2; + mbus_fmt.width = fmt->fmt.pix.width; + mbus_fmt.height = h; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt); + return ivtv_g_fmt_vid_cap(file, fh, fmt); +} + +static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0) + return -EBUSY; + itv->vbi.sliced_in->service_set = 0; + itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; + v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &fmt->fmt.vbi); + return ivtv_g_fmt_vbi_cap(file, fh, fmt); +} + +static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt); + + if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI) + return ret; + + check_service_set(vbifmt, itv->is_50hz); + if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0) + return -EBUSY; + itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, vbifmt); + memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in)); + return 0; +} + +static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int ret = ivtv_try_fmt_vid_out(file, fh, fmt); + + if (ret) + return ret; + + if (id->type != IVTV_DEC_STREAM_TYPE_YUV) + return 0; + + /* Return now if we already have some frame data */ + if (yi->stream_size) + return -EBUSY; + + yi->v4l2_src_w = fmt->fmt.pix.width; + yi->v4l2_src_h = fmt->fmt.pix.height; + + switch (fmt->fmt.pix.field) { + case V4L2_FIELD_NONE: + yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; + break; + case V4L2_FIELD_ANY: + yi->lace_mode = IVTV_YUV_MODE_AUTO; + break; + case V4L2_FIELD_INTERLACED_BT: + yi->lace_mode = + IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; + break; + case V4L2_FIELD_INTERLACED_TB: + default: + yi->lace_mode = IVTV_YUV_MODE_INTERLACED; + break; + } + yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; + + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + itv->dma_data_req_size = + 1080 * ((yi->v4l2_src_h + 31) & ~31); + + return 0; +} + +static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct ivtv *itv = fh2id(fh)->itv; + int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt); + + if (ret == 0) { + itv->osd_chroma_key = fmt->fmt.win.chromakey; + itv->osd_global_alpha = fmt->fmt.win.global_alpha; + ivtv_set_osd_alpha(itv); + } + return ret; +} + +static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip) +{ + struct ivtv *itv = fh2id(fh)->itv; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match.type == V4L2_CHIP_MATCH_HOST) { + if (v4l2_chip_match_host(&chip->match)) + chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; + return 0; + } + if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && + chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + /* TODO: is this correct? */ + return ivtv_call_all_err(itv, core, g_chip_ident, chip); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) +{ + struct v4l2_dbg_register *regs = arg; + volatile u8 __iomem *reg_start; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) + reg_start = itv->reg_mem - IVTV_REG_OFFSET; + else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET && + regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) + reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; + else if (regs->reg < IVTV_ENCODER_SIZE) + reg_start = itv->enc_mem; + else + return -EINVAL; + + regs->size = 4; + if (cmd == VIDIOC_DBG_G_REGISTER) + regs->val = readl(regs->reg + reg_start); + else + writel(regs->val, regs->reg + reg_start); + return 0; +} + +static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (v4l2_chip_match_host(®->match)) + return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg); + /* TODO: subdev errors should not be ignored, this should become a + subdev helper function. */ + ivtv_call_all(itv, core, g_register, reg); + return 0; +} + +static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (v4l2_chip_match_host(®->match)) + return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg); + /* TODO: subdev errors should not be ignored, this should become a + subdev helper function. */ + ivtv_call_all(itv, core, s_register, reg); + return 0; +} +#endif + +static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) +{ + struct ivtv *itv = fh2id(fh)->itv; + + strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); + snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); + vcap->version = IVTV_DRIVER_VERSION; /* version */ + vcap->capabilities = itv->v4l2_cap; /* capabilities */ + return 0; +} + +static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct ivtv *itv = fh2id(fh)->itv; + + return ivtv_get_audio_input(itv, vin->index, vin); +} + +static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct ivtv *itv = fh2id(fh)->itv; + + vin->index = itv->audio_input; + return ivtv_get_audio_input(itv, vin->index, vin); +} + +static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (vout->index >= itv->nof_audio_inputs) + return -EINVAL; + + itv->audio_input = vout->index; + ivtv_audio_set_io(itv); + + return 0; +} + +static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin) +{ + struct ivtv *itv = fh2id(fh)->itv; + + /* set it to defaults from our table */ + return ivtv_get_audio_output(itv, vin->index, vin); +} + +static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) +{ + struct ivtv *itv = fh2id(fh)->itv; + + vin->index = 0; + return ivtv_get_audio_output(itv, vin->index, vin); +} + +static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout) +{ + struct ivtv *itv = fh2id(fh)->itv; + + return ivtv_get_audio_output(itv, vout->index, vout); +} + +static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + struct ivtv *itv = fh2id(fh)->itv; + + /* set it to defaults from our table */ + return ivtv_get_input(itv, vin->index, vin); +} + +static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout) +{ + struct ivtv *itv = fh2id(fh)->itv; + + return ivtv_get_output(itv, vout->index, vout); +} + +static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int streamtype; + + streamtype = id->type; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + cropcap->bounds.height = itv->is_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; + } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + if (yi->track_osd) { + cropcap->bounds.width = yi->osd_full_w; + cropcap->bounds.height = yi->osd_full_h; + } else { + cropcap->bounds.width = 720; + cropcap->bounds.height = + itv->is_out_50hz ? 576 : 480; + } + cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; + } else { + cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; + } + cropcap->defrect = cropcap->bounds; + return 0; +} + +static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int streamtype; + + streamtype = id->type; + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + yi->main_rect = crop->c; + return 0; + } else { + if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { + itv->main_rect = crop->c; + return 0; + } + } + return -EINVAL; + } + return -EINVAL; +} + +static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + int streamtype; + + streamtype = id->type; + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) + crop->c = yi->main_rect; + else + crop->c = itv->main_rect; + return 0; + } + return -EINVAL; +} + +static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) +{ + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, + { 0, 0, 0, 0 } + }, + { 1, 0, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, + { 0, 0, 0, 0 } + } + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 1) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; +} + +static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) +{ + struct ivtv *itv = fh2id(fh)->itv; + + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, + { 0, 0, 0, 0 } + }, + { 1, 0, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, + { 0, 0, 0, 0 } + } + }; + enum v4l2_buf_type type = fmt->type; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + + if (fmt->index > 1) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + + return 0; +} + +static int ivtv_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct ivtv *itv = fh2id(fh)->itv; + + *i = itv->active_input; + + return 0; +} + +int ivtv_s_input(struct file *file, void *fh, unsigned int inp) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (inp < 0 || inp >= itv->nof_inputs) + return -EINVAL; + + if (inp == itv->active_input) { + IVTV_DEBUG_INFO("Input unchanged\n"); + return 0; + } + + if (atomic_read(&itv->capturing) > 0) { + return -EBUSY; + } + + IVTV_DEBUG_INFO("Changing input from %d to %d\n", + itv->active_input, inp); + + itv->active_input = inp; + /* Set the audio input to whatever is appropriate for the + input type. */ + itv->audio_input = itv->card->video_inputs[inp].audio_index; + + /* prevent others from messing with the streams until + we're finished changing inputs. */ + ivtv_mute(itv); + ivtv_video_set_io(itv); + ivtv_audio_set_io(itv); + ivtv_unmute(itv); + + return 0; +} + +static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + + *i = itv->active_output; + + return 0; +} + +static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (outp >= itv->card->nof_outputs) + return -EINVAL; + + if (outp == itv->active_output) { + IVTV_DEBUG_INFO("Output unchanged\n"); + return 0; + } + IVTV_DEBUG_INFO("Changing output from %d to %d\n", + itv->active_output, outp); + + itv->active_output = outp; + ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, + SAA7127_INPUT_TYPE_NORMAL, + itv->card->video_outputs[outp].video_output, 0); + + return 0; +} + +static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (vf->tuner != 0) + return -EINVAL; + + ivtv_call_all(itv, tuner, g_frequency, vf); + return 0; +} + +int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (vf->tuner != 0) + return -EINVAL; + + ivtv_mute(itv); + IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); + ivtv_call_all(itv, tuner, s_frequency, vf); + ivtv_unmute(itv); + return 0; +} + +static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct ivtv *itv = fh2id(fh)->itv; + + *std = itv->std; + return 0; +} + +void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std) +{ + itv->std = *std; + itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + itv->is_50hz = !itv->is_60hz; + cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz); + itv->cxhdl.width = 720; + itv->cxhdl.height = itv->is_50hz ? 576 : 480; + itv->vbi.count = itv->is_50hz ? 18 : 12; + itv->vbi.start[0] = itv->is_50hz ? 6 : 10; + itv->vbi.start[1] = itv->is_50hz ? 318 : 273; + + if (itv->hw_flags & IVTV_HW_CX25840) + itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; + + /* Tuner */ + ivtv_call_all(itv, core, s_std, itv->std); +} + +void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + DEFINE_WAIT(wait); + int f; + + /* set display standard */ + itv->std_out = *std; + itv->is_out_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + itv->is_out_50hz = !itv->is_out_60hz; + ivtv_call_all(itv, video, s_std_output, itv->std_out); + + /* + * The next firmware call is time sensitive. Time it to + * avoid risk of a hard lock, by trying to ensure the call + * happens within the first 100 lines of the top field. + * Make 4 attempts to sync to the decoder before giving up. + */ + for (f = 0; f < 4; f++) { + prepare_to_wait(&itv->vsync_waitq, &wait, + TASK_UNINTERRUPTIBLE); + if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100) + break; + schedule_timeout(msecs_to_jiffies(25)); + } + finish_wait(&itv->vsync_waitq, &wait); + + if (f == 4) + IVTV_WARN("Mode change failed to sync to decoder\n"); + + ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); + itv->main_rect.left = 0; + itv->main_rect.top = 0; + itv->main_rect.width = 720; + itv->main_rect.height = itv->is_out_50hz ? 576 : 480; + ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + 720, itv->main_rect.height, 0, 0); + yi->main_rect = itv->main_rect; + if (!itv->osd_info) { + yi->osd_full_w = 720; + yi->osd_full_h = itv->is_out_50hz ? 576 : 480; + } +} + +int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if ((*std & V4L2_STD_ALL) == 0) + return -EINVAL; + + if (*std == itv->std) + return 0; + + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || + atomic_read(&itv->capturing) > 0 || + atomic_read(&itv->decoding) > 0) { + /* Switching standard would mess with already running + streams, prevent that by returning EBUSY. */ + return -EBUSY; + } + + IVTV_DEBUG_INFO("Switching standard to %llx.\n", + (unsigned long long)itv->std); + + ivtv_s_std_enc(itv, std); + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) + ivtv_s_std_dec(itv, std); + + return 0; +} + +static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + + if (vt->index != 0) + return -EINVAL; + + ivtv_call_all(itv, tuner, s_tuner, vt); + + return 0; +} + +static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (vt->index != 0) + return -EINVAL; + + ivtv_call_all(itv, tuner, g_tuner, vt); + + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_RADIO; + } else { + strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_ANALOG_TV; + } + + return 0; +} + +static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) +{ + struct ivtv *itv = fh2id(fh)->itv; + int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; + int f, l; + + if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + if (valid_service_line(f, l, itv->is_50hz)) + cap->service_lines[f][l] = set; + } + } + return 0; + } + if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { + if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) + return -EINVAL; + if (itv->is_60hz) { + cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; + } else { + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; + cap->service_lines[0][16] = V4L2_SLICED_VPS; + } + return 0; + } + return -EINVAL; +} + +static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) +{ + struct ivtv *itv = fh2id(fh)->itv; + struct v4l2_enc_idx_entry *e = idx->entry; + int entries; + int i; + + entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % + IVTV_MAX_PGM_INDEX; + if (entries > V4L2_ENC_IDX_ENTRIES) + entries = V4L2_ENC_IDX_ENTRIES; + idx->entries = 0; + for (i = 0; i < entries; i++) { + *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; + if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) { + idx->entries++; + e++; + } + } + itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; + return 0; +} + +static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + + + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + return ivtv_start_capture(id); + + case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); + return 0; + + case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + + if (!atomic_read(&itv->capturing)) + return -EPERM; + if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) + return 0; + + ivtv_mute(itv); + ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); + break; + + case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; + + if (!atomic_read(&itv->capturing)) + return -EPERM; + + if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) + return 0; + + ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); + ivtv_unmute(itv); + break; + default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); + return -EINVAL; + } + + return 0; +} + +static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) +{ + struct ivtv *itv = fh2id(fh)->itv; + + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); + enc->flags = 0; + return 0; + + case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + return 0; + + case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); + enc->flags = 0; + return 0; + + case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); + enc->flags = 0; + return 0; + default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); + return -EINVAL; + } +} + +static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) +{ + struct ivtv *itv = fh2id(fh)->itv; + u32 data[CX2341X_MBOX_MAX_DATA]; + struct yuv_playback_info *yi = &itv->yuv_info; + + int pixfmt; + static u32 pixel_format[16] = { + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB555, + V4L2_PIX_FMT_RGB444, + V4L2_PIX_FMT_RGB32, + 0, + 0, + 0, + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ + V4L2_PIX_FMT_YUV565, + V4L2_PIX_FMT_YUV555, + V4L2_PIX_FMT_YUV444, + V4L2_PIX_FMT_YUV32, + 0, + 0, + 0, + }; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + if (!itv->osd_video_pbase) + return -EINVAL; + + fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | + V4L2_FBUF_CAP_GLOBAL_ALPHA; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; + pixfmt = (data[0] >> 3) & 0xf; + + fb->fmt.pixelformat = pixel_format[pixfmt]; + fb->fmt.width = itv->osd_rect.width; + fb->fmt.height = itv->osd_rect.height; + fb->fmt.field = V4L2_FIELD_INTERLACED; + fb->fmt.bytesperline = fb->fmt.width; + fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; + fb->fmt.field = V4L2_FIELD_INTERLACED; + fb->fmt.priv = 0; + if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8) + fb->fmt.bytesperline *= 2; + if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 || + fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32) + fb->fmt.bytesperline *= 2; + fb->fmt.sizeimage = fb->fmt.bytesperline * fb->fmt.height; + fb->base = (void *)itv->osd_video_pbase; + fb->flags = 0; + + if (itv->osd_chroma_key_state) + fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; + + if (itv->osd_global_alpha_state) + fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; + + if (yi->track_osd) + fb->flags |= V4L2_FBUF_FLAG_OVERLAY; + + pixfmt &= 7; + + /* no local alpha for RGB565 or unknown formats */ + if (pixfmt == 1 || pixfmt > 4) + return 0; + + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + else + fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; + + if (itv->osd_local_alpha_state) { + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; + else + fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; + } + + return 0; +} + +static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + if (!itv->osd_video_pbase) + return -EINVAL; + + itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; + itv->osd_local_alpha_state = + (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; + itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; + ivtv_set_osd_alpha(itv); + yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; + return ivtv_g_fbuf(file, fh, fb); +} + +static int ivtv_overlay(struct file *file, void *fh, unsigned int on) +{ + struct ivtv_open_id *id = fh2id(fh); + struct ivtv *itv = id->itv; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0); + + return 0; +} + +static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_VSYNC: + case V4L2_EVENT_EOS: + break; + default: + return -EINVAL; + } + return v4l2_event_subscribe(fh, sub); +} + +static int ivtv_log_status(struct file *file, void *fh) +{ + struct ivtv *itv = fh2id(fh)->itv; + u32 data[CX2341X_MBOX_MAX_DATA]; + + int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; + struct v4l2_input vidin; + struct v4l2_audio audin; + int i; + + IVTV_INFO("================= START STATUS CARD #%d =================\n", + itv->instance); + IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); + if (itv->hw_flags & IVTV_HW_TVEEPROM) { + struct tveeprom tv; + + ivtv_read_eeprom(itv, &tv); + } + ivtv_call_all(itv, core, log_status); + ivtv_get_input(itv, itv->active_input, &vidin); + ivtv_get_audio_input(itv, itv->audio_input, &audin); + IVTV_INFO("Video Input: %s\n", vidin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, + (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); + if (has_output) { + struct v4l2_output vidout; + struct v4l2_audioout audout; + int mode = itv->output_mode; + static const char * const output_modes[5] = { + "None", + "MPEG Streaming", + "YUV Streaming", + "YUV Frames", + "Passthrough", + }; + static const char * const audio_modes[5] = { + "Stereo", + "Left", + "Right", + "Mono", + "Swapped" + }; + static const char * const alpha_mode[4] = { + "None", + "Global", + "Local", + "Global and Local" + }; + static const char * const pixel_format[16] = { + "ARGB Indexed", + "RGB 5:6:5", + "ARGB 1:5:5:5", + "ARGB 1:4:4:4", + "ARGB 8:8:8:8", + "5", + "6", + "7", + "AYUV Indexed", + "YUV 5:6:5", + "AYUV 1:5:5:5", + "AYUV 1:4:4:4", + "AYUV 8:8:8:8", + "13", + "14", + "15", + }; + + ivtv_get_output(itv, itv->active_output, &vidout); + ivtv_get_audio_output(itv, 0, &audout); + IVTV_INFO("Video Output: %s\n", vidout.name); + IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, + audio_modes[itv->audio_stereo_mode], + audio_modes[itv->audio_bilingual_mode]); + if (mode < 0 || mode > OUT_PASSTHROUGH) + mode = OUT_NONE; + IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; + IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", + data[0] & 1 ? "On" : "Off", + alpha_mode[(data[0] >> 1) & 0x3], + pixel_format[(data[0] >> 3) & 0xf]); + } + IVTV_INFO("Tuner: %s\n", + test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); + v4l2_ctrl_handler_log_status(&itv->cxhdl.hdl, itv->v4l2_dev.name); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); + for (i = 0; i < IVTV_MAX_STREAMS; i++) { + struct ivtv_stream *s = &itv->streams[i]; + + if (s->vdev == NULL || s->buffers == 0) + continue; + IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, + (s->buffers - s->q_free.buffers) * 100 / s->buffers, + (s->buffers * s->buf_size) / 1024, s->buffers); + } + + IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", + (long long)itv->mpg_data_received, + (long long)itv->vbi_data_inserted); + IVTV_INFO("================== END STATUS CARD #%d ==================\n", + itv->instance); + + return 0; +} + +static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) +{ + struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv *itv = id->itv; + int nonblocking = filp->f_flags & O_NONBLOCK; + struct ivtv_stream *s = &itv->streams[id->type]; + unsigned long iarg = (unsigned long)arg; + + switch (cmd) { + case IVTV_IOC_DMA_FRAME: { + struct ivtv_dma_frame *args = arg; + + IVTV_DEBUG_IOCTL("IVTV_IOC_DMA_FRAME\n"); + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + if (args->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL) + return 0; + if (ivtv_start_decoding(id, id->type)) { + return -EBUSY; + } + if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) { + ivtv_release_stream(s); + return -EBUSY; + } + /* Mark that this file handle started the UDMA_YUV mode */ + id->yuv_frames = 1; + if (args->y_source == NULL) + return 0; + return ivtv_yuv_prep_frame(itv, args); + } + + case VIDEO_GET_PTS: { + u32 data[CX2341X_MBOX_MAX_DATA]; + u64 *pts = arg; + + IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n"); + if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { + *pts = s->dma_pts; + break; + } + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + + if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { + *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) | + (u64)itv->last_dec_timing[1]; + break; + } + *pts = 0; + if (atomic_read(&itv->decoding)) { + if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { + IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); + return -EIO; + } + memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); + set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); + *pts = (u64) ((u64) data[2] << 32) | (u64) data[1]; + /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ + } + break; + } + + case VIDEO_GET_FRAME_COUNT: { + u32 data[CX2341X_MBOX_MAX_DATA]; + u64 *frame = arg; + + IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n"); + if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { + *frame = 0; + break; + } + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + + if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { + *frame = itv->last_dec_timing[0]; + break; + } + *frame = 0; + if (atomic_read(&itv->decoding)) { + if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { + IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); + return -EIO; + } + memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); + set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); + *frame = data[0]; + } + break; + } + + case VIDEO_PLAY: { + struct video_command vc; + + IVTV_DEBUG_IOCTL("VIDEO_PLAY\n"); + memset(&vc, 0, sizeof(vc)); + vc.cmd = VIDEO_CMD_PLAY; + return ivtv_video_command(itv, id, &vc, 0); + } + + case VIDEO_STOP: { + struct video_command vc; + + IVTV_DEBUG_IOCTL("VIDEO_STOP\n"); + memset(&vc, 0, sizeof(vc)); + vc.cmd = VIDEO_CMD_STOP; + vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY; + return ivtv_video_command(itv, id, &vc, 0); + } + + case VIDEO_FREEZE: { + struct video_command vc; + + IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n"); + memset(&vc, 0, sizeof(vc)); + vc.cmd = VIDEO_CMD_FREEZE; + return ivtv_video_command(itv, id, &vc, 0); + } + + case VIDEO_CONTINUE: { + struct video_command vc; + + IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n"); + memset(&vc, 0, sizeof(vc)); + vc.cmd = VIDEO_CMD_CONTINUE; + return ivtv_video_command(itv, id, &vc, 0); + } + + case VIDEO_COMMAND: + case VIDEO_TRY_COMMAND: { + struct video_command *vc = arg; + int try = (cmd == VIDEO_TRY_COMMAND); + + if (try) + IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd); + else + IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd); + return ivtv_video_command(itv, id, vc, try); + } + + case VIDEO_GET_EVENT: { + struct video_event *ev = arg; + DEFINE_WAIT(wait); + + IVTV_DEBUG_IOCTL("VIDEO_GET_EVENT\n"); + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + memset(ev, 0, sizeof(*ev)); + set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); + + while (1) { + if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) + ev->type = VIDEO_EVENT_DECODER_STOPPED; + else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) { + ev->type = VIDEO_EVENT_VSYNC; + ev->u.vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ? + VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN; + if (itv->output_mode == OUT_UDMA_YUV && + (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) == + IVTV_YUV_MODE_PROGRESSIVE) { + ev->u.vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE; + } + } + if (ev->type) + return 0; + if (nonblocking) + return -EAGAIN; + /* Wait for event. Note that serialize_lock is locked, + so to allow other processes to access the driver while + we are waiting unlock first and later lock again. */ + mutex_unlock(&itv->serialize_lock); + prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); + if (!test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags) && + !test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) + schedule(); + finish_wait(&itv->event_waitq, &wait); + mutex_lock(&itv->serialize_lock); + if (signal_pending(current)) { + /* return if a signal was received */ + IVTV_DEBUG_INFO("User stopped wait for event\n"); + return -EINTR; + } + } + break; + } + + case VIDEO_SELECT_SOURCE: + IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n"); + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + return ivtv_passthrough_mode(itv, iarg == VIDEO_SOURCE_DEMUX); + + case AUDIO_SET_MUTE: + IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n"); + itv->speed_mute_audio = iarg; + return 0; + + case AUDIO_CHANNEL_SELECT: + IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); + if (iarg > AUDIO_STEREO_SWAPPED) + return -EINVAL; + itv->audio_stereo_mode = iarg; + ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); + return 0; + + case AUDIO_BILINGUAL_CHANNEL_SELECT: + IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); + if (iarg > AUDIO_STEREO_SWAPPED) + return -EINVAL; + itv->audio_bilingual_mode = iarg; + ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); + return 0; + + default: + return -EINVAL; + } + return 0; +} + +static long ivtv_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) +{ + struct ivtv *itv = fh2id(fh)->itv; + + if (!valid_prio) { + switch (cmd) { + case VIDEO_PLAY: + case VIDEO_STOP: + case VIDEO_FREEZE: + case VIDEO_CONTINUE: + case VIDEO_COMMAND: + case VIDEO_SELECT_SOURCE: + case AUDIO_SET_MUTE: + case AUDIO_CHANNEL_SELECT: + case AUDIO_BILINGUAL_CHANNEL_SELECT: + return -EBUSY; + } + } + + switch (cmd) { + case VIDIOC_INT_RESET: { + u32 val = *(u32 *)arg; + + if ((val == 0 && itv->options.newi2c) || (val & 0x01)) + ivtv_reset_ir_gpio(itv); + if (val & 0x02) + v4l2_subdev_call(itv->sd_video, core, reset, 0); + break; + } + + case IVTV_IOC_DMA_FRAME: + case VIDEO_GET_PTS: + case VIDEO_GET_FRAME_COUNT: + case VIDEO_GET_EVENT: + case VIDEO_PLAY: + case VIDEO_STOP: + case VIDEO_FREEZE: + case VIDEO_CONTINUE: + case VIDEO_COMMAND: + case VIDEO_TRY_COMMAND: + case VIDEO_SELECT_SOURCE: + case AUDIO_SET_MUTE: + case AUDIO_CHANNEL_SELECT: + case AUDIO_BILINGUAL_CHANNEL_SELECT: + return ivtv_decoder_ioctls(file, cmd, (void *)arg); + + default: + return -EINVAL; + } + return 0; +} + +static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vfd = video_devdata(filp); + long ret; + + if (ivtv_debug & IVTV_DBGFLG_IOCTL) + vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; + ret = video_ioctl2(filp, cmd, arg); + vfd->debug = 0; + return ret; +} + +long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv *itv = id->itv; + long res; + + /* DQEVENT can block, so this should not run with the serialize lock */ + if (cmd == VIDIOC_DQEVENT) + return ivtv_serialized_ioctl(itv, filp, cmd, arg); + mutex_lock(&itv->serialize_lock); + res = ivtv_serialized_ioctl(itv, filp, cmd, arg); + mutex_unlock(&itv->serialize_lock); + return res; +} + +static const struct v4l2_ioctl_ops ivtv_ioctl_ops = { + .vidioc_querycap = ivtv_querycap, + .vidioc_s_audio = ivtv_s_audio, + .vidioc_g_audio = ivtv_g_audio, + .vidioc_enumaudio = ivtv_enumaudio, + .vidioc_s_audout = ivtv_s_audout, + .vidioc_g_audout = ivtv_g_audout, + .vidioc_enum_input = ivtv_enum_input, + .vidioc_enum_output = ivtv_enum_output, + .vidioc_enumaudout = ivtv_enumaudout, + .vidioc_cropcap = ivtv_cropcap, + .vidioc_s_crop = ivtv_s_crop, + .vidioc_g_crop = ivtv_g_crop, + .vidioc_g_input = ivtv_g_input, + .vidioc_s_input = ivtv_s_input, + .vidioc_g_output = ivtv_g_output, + .vidioc_s_output = ivtv_s_output, + .vidioc_g_frequency = ivtv_g_frequency, + .vidioc_s_frequency = ivtv_s_frequency, + .vidioc_s_tuner = ivtv_s_tuner, + .vidioc_g_tuner = ivtv_g_tuner, + .vidioc_g_enc_index = ivtv_g_enc_index, + .vidioc_g_fbuf = ivtv_g_fbuf, + .vidioc_s_fbuf = ivtv_s_fbuf, + .vidioc_g_std = ivtv_g_std, + .vidioc_s_std = ivtv_s_std, + .vidioc_overlay = ivtv_overlay, + .vidioc_log_status = ivtv_log_status, + .vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap, + .vidioc_encoder_cmd = ivtv_encoder_cmd, + .vidioc_try_encoder_cmd = ivtv_try_encoder_cmd, + .vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out, + .vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap, + .vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap, + .vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out, + .vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay, + .vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out, + .vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap, + .vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap, + .vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out, + .vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay, + .vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out, + .vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap, + .vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap, + .vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out, + .vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay, + .vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out, + .vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap, + .vidioc_g_chip_ident = ivtv_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = ivtv_g_register, + .vidioc_s_register = ivtv_s_register, +#endif + .vidioc_default = ivtv_default, + .vidioc_subscribe_event = ivtv_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +void ivtv_set_funcs(struct video_device *vdev) +{ + vdev->ioctl_ops = &ivtv_ioctl_ops; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-ioctl.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-ioctl.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-ioctl.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-ioctl.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,36 @@ +/* + ioctl system call + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_IOCTL_H +#define IVTV_IOCTL_H + +u16 ivtv_service2vbi(int type); +void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); +u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt); +void ivtv_set_osd_alpha(struct ivtv *itv); +int ivtv_set_speed(struct ivtv *itv, int speed); +void ivtv_set_funcs(struct video_device *vdev); +void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std); +void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std); +int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int ivtv_s_input(struct file *file, void *fh, unsigned int inp); +long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-irq.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-irq.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-irq.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-irq.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1038 @@ +/* interrupt handling + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-queue.h" +#include "ivtv-udma.h" +#include "ivtv-irq.h" +#include "ivtv-mailbox.h" +#include "ivtv-vbi.h" +#include "ivtv-yuv.h" +#include + +#define DMA_MAGIC_COOKIE 0x000001fe + +static void ivtv_dma_dec_start(struct ivtv_stream *s); + +static const int ivtv_stream_map[] = { + IVTV_ENC_STREAM_TYPE_MPG, + IVTV_ENC_STREAM_TYPE_YUV, + IVTV_ENC_STREAM_TYPE_PCM, + IVTV_ENC_STREAM_TYPE_VBI, +}; + + +static void ivtv_pio_work_handler(struct ivtv *itv) +{ + struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream]; + struct ivtv_buffer *buf; + int i = 0; + + IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n"); + if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS || + s->vdev == NULL || !ivtv_use_pio(s)) { + itv->cur_pio_stream = -1; + /* trigger PIO complete user interrupt */ + write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); + return; + } + IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name); + list_for_each_entry(buf, &s->q_dma.list, list) { + u32 size = s->sg_processing[i].size & 0x3ffff; + + /* Copy the data from the card to the buffer */ + if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { + memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size); + } + else { + memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size); + } + i++; + if (i == s->sg_processing_size) + break; + } + write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); +} + +void ivtv_irq_work_handler(struct kthread_work *work) +{ + struct ivtv *itv = container_of(work, struct ivtv, irq_work); + + if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) + ivtv_pio_work_handler(itv); + + if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags)) + ivtv_vbi_work_handler(itv); + + if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags)) + ivtv_yuv_work_handler(itv); +} + +/* Determine the required DMA size, setup enough buffers in the predma queue and + actually copy the data from the card to the buffers in case a PIO transfer is + required for this stream. + */ +static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA]) +{ + struct ivtv *itv = s->itv; + struct ivtv_buffer *buf; + u32 bytes_needed = 0; + u32 offset, size; + u32 UVoffset = 0, UVsize = 0; + int skip_bufs = s->q_predma.buffers; + int idx = s->sg_pending_size; + int rc; + + /* sanity checks */ + if (s->vdev == NULL) { + IVTV_DEBUG_WARN("Stream %s not started\n", s->name); + return -1; + } + if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { + IVTV_DEBUG_WARN("Stream %s not open\n", s->name); + return -1; + } + + /* determine offset, size and PTS for the various streams */ + switch (s->type) { + case IVTV_ENC_STREAM_TYPE_MPG: + offset = data[1]; + size = data[2]; + s->pending_pts = 0; + break; + + case IVTV_ENC_STREAM_TYPE_YUV: + offset = data[1]; + size = data[2]; + UVoffset = data[3]; + UVsize = data[4]; + s->pending_pts = ((u64) data[5] << 32) | data[6]; + break; + + case IVTV_ENC_STREAM_TYPE_PCM: + offset = data[1] + 12; + size = data[2] - 12; + s->pending_pts = read_dec(offset - 8) | + ((u64)(read_dec(offset - 12)) << 32); + if (itv->has_cx23415) + offset += IVTV_DECODER_OFFSET; + break; + + case IVTV_ENC_STREAM_TYPE_VBI: + size = itv->vbi.enc_size * itv->vbi.fpi; + offset = read_enc(itv->vbi.enc_start - 4) + 12; + if (offset == 12) { + IVTV_DEBUG_INFO("VBI offset == 0\n"); + return -1; + } + s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); + break; + + case IVTV_DEC_STREAM_TYPE_VBI: + size = read_dec(itv->vbi.dec_start + 4) + 8; + offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; + s->pending_pts = 0; + offset += IVTV_DECODER_OFFSET; + break; + default: + /* shouldn't happen */ + return -1; + } + + /* if this is the start of the DMA then fill in the magic cookie */ + if (s->sg_pending_size == 0 && ivtv_use_dma(s)) { + if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || + s->type == IVTV_DEC_STREAM_TYPE_VBI)) { + s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); + write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); + } + else { + s->pending_backup = read_enc(offset); + write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); + } + s->pending_offset = offset; + } + + bytes_needed = size; + if (s->type == IVTV_ENC_STREAM_TYPE_YUV) { + /* The size for the Y samples needs to be rounded upwards to a + multiple of the buf_size. The UV samples then start in the + next buffer. */ + bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size); + bytes_needed += UVsize; + } + + IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n", + ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset); + + rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed); + if (rc < 0) { /* Insufficient buffers */ + IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n", + bytes_needed, s->name); + return -1; + } + if (rc && !s->buffers_stolen && test_bit(IVTV_F_S_APPL_IO, &s->s_flags)) { + IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name); + IVTV_WARN("Cause: the application is not reading fast enough.\n"); + } + s->buffers_stolen = rc; + + /* got the buffers, now fill in sg_pending */ + buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); + memset(buf->buf, 0, 128); + list_for_each_entry(buf, &s->q_predma.list, list) { + if (skip_bufs-- > 0) + continue; + s->sg_pending[idx].dst = buf->dma_handle; + s->sg_pending[idx].src = offset; + s->sg_pending[idx].size = s->buf_size; + buf->bytesused = min(size, s->buf_size); + buf->dma_xfer_cnt = s->dma_xfer_cnt; + + s->q_predma.bytesused += buf->bytesused; + size -= buf->bytesused; + offset += s->buf_size; + + /* Sync SG buffers */ + ivtv_buf_sync_for_device(s, buf); + + if (size == 0) { /* YUV */ + /* process the UV section */ + offset = UVoffset; + size = UVsize; + } + idx++; + } + s->sg_pending_size = idx; + return 0; +} + +static void dma_post(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + struct ivtv_buffer *buf = NULL; + struct list_head *p; + u32 offset; + __le32 *u32buf; + int x = 0; + + IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA", + s->name, s->dma_offset); + list_for_each(p, &s->q_dma.list) { + buf = list_entry(p, struct ivtv_buffer, list); + u32buf = (__le32 *)buf->buf; + + /* Sync Buffer */ + ivtv_buf_sync_for_cpu(s, buf); + + if (x == 0 && ivtv_use_dma(s)) { + offset = s->dma_last_offset; + if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) + { + for (offset = 0; offset < 64; offset++) { + if (u32buf[offset] == DMA_MAGIC_COOKIE) { + break; + } + } + offset *= 4; + if (offset == 256) { + IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name); + offset = s->dma_last_offset; + } + if (s->dma_last_offset != offset) + IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset); + s->dma_last_offset = offset; + } + if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || + s->type == IVTV_DEC_STREAM_TYPE_VBI)) { + write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET); + } + else { + write_enc_sync(0, s->dma_offset); + } + if (offset) { + buf->bytesused -= offset; + memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset); + } + *u32buf = cpu_to_le32(s->dma_backup); + } + x++; + /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ + if (s->type == IVTV_ENC_STREAM_TYPE_MPG || + s->type == IVTV_ENC_STREAM_TYPE_VBI) + buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP; + } + if (buf) + buf->bytesused += s->dma_last_offset; + if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { + list_for_each_entry(buf, &s->q_dma.list, list) { + /* Parse and Groom VBI Data */ + s->q_dma.bytesused -= buf->bytesused; + ivtv_process_vbi_data(itv, buf, 0, s->type); + s->q_dma.bytesused += buf->bytesused; + } + if (s->id == -1) { + ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); + return; + } + } + ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused); + if (s->id != -1) + wake_up(&s->waitq); +} + +void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) +{ + struct ivtv *itv = s->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + u8 frame = yi->draw_frame; + struct yuv_frame_info *f = &yi->new_frame_info[frame]; + struct ivtv_buffer *buf; + u32 y_size = 720 * ((f->src_h + 31) & ~31); + u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; + int y_done = 0; + int bytes_written = 0; + unsigned long flags = 0; + int idx = 0; + + IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); + + /* Insert buffer block for YUV if needed */ + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) { + if (yi->blanking_dmaptr) { + s->sg_pending[idx].src = yi->blanking_dmaptr; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = 720 * 16; + } + offset += 720 * 16; + idx++; + } + + list_for_each_entry(buf, &s->q_predma.list, list) { + /* YUV UV Offset from Y Buffer */ + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && + (bytes_written + buf->bytesused) >= y_size) { + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = y_size - bytes_written; + offset = uv_offset; + if (s->sg_pending[idx].size != buf->bytesused) { + idx++; + s->sg_pending[idx].src = + buf->dma_handle + s->sg_pending[idx - 1].size; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = + buf->bytesused - s->sg_pending[idx - 1].size; + offset += s->sg_pending[idx].size; + } + y_done = 1; + } else { + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = buf->bytesused; + offset += buf->bytesused; + } + bytes_written += buf->bytesused; + + /* Sync SG buffers */ + ivtv_buf_sync_for_device(s, buf); + idx++; + } + s->sg_pending_size = idx; + + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + if (lock) + spin_lock_irqsave(&itv->dma_reg_lock, flags); + if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) { + ivtv_dma_dec_start(s); + } + else { + set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); + } + if (lock) + spin_unlock_irqrestore(&itv->dma_reg_lock, flags); +} + +static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); + itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); + add_timer(&itv->dma_timer); +} + +static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); + itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); + add_timer(&itv->dma_timer); +} + +/* start the encoder DMA */ +static void ivtv_dma_enc_start(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; + int i; + + IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name); + + if (s->q_predma.bytesused) + ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); + + if (ivtv_use_dma(s)) + s->sg_pending[s->sg_pending_size - 1].size += 256; + + /* If this is an MPEG stream, and VBI data is also pending, then append the + VBI DMA to the MPEG DMA and transfer both sets of data at once. + + VBI DMA is a second class citizen compared to MPEG and mixing them together + will confuse the firmware (the end of a VBI DMA is seen as the end of a + MPEG DMA, thus effectively dropping an MPEG frame). So instead we make + sure we only use the MPEG DMA to transfer the VBI DMA if both are in + use. This way no conflicts occur. */ + clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size && + s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) { + ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); + if (ivtv_use_dma(s_vbi)) + s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256; + for (i = 0; i < s_vbi->sg_pending_size; i++) { + s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i]; + } + s_vbi->dma_offset = s_vbi->pending_offset; + s_vbi->sg_pending_size = 0; + s_vbi->dma_xfer_cnt++; + set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); + IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name); + } + + s->dma_xfer_cnt++; + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + s->dma_offset = s->pending_offset; + s->dma_backup = s->pending_backup; + s->dma_pts = s->pending_pts; + + if (ivtv_use_pio(s)) { + set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags); + set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); + set_bit(IVTV_F_I_PIO, &itv->i_flags); + itv->cur_pio_stream = s->type; + } + else { + itv->dma_retries = 0; + ivtv_dma_enc_start_xfer(s); + set_bit(IVTV_F_I_DMA, &itv->i_flags); + itv->cur_dma_stream = s->type; + } +} + +static void ivtv_dma_dec_start(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + if (s->q_predma.bytesused) + ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); + s->dma_xfer_cnt++; + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + + IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name); + itv->dma_retries = 0; + ivtv_dma_dec_start_xfer(s); + set_bit(IVTV_F_I_DMA, &itv->i_flags); + itv->cur_dma_stream = s->type; +} + +static void ivtv_irq_dma_read(struct ivtv *itv) +{ + struct ivtv_stream *s = NULL; + struct ivtv_buffer *buf; + int hw_stream_type = 0; + + IVTV_DEBUG_HI_IRQ("DEC DMA READ\n"); + + del_timer(&itv->dma_timer); + + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) + return; + + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + s = &itv->streams[itv->cur_dma_stream]; + ivtv_stream_sync_for_cpu(s); + + if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { + IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n", + read_reg(IVTV_REG_DMASTATUS), + s->sg_processed, s->sg_processing_size, itv->dma_retries); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ + itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } + } + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_dec_start_xfer(s); + return; + } + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) + hw_stream_type = 2; + IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); + + /* For some reason must kick the firmware, like PIO mode, + I think this tells the firmware we are done and the size + of the xfer so it can calculate what we need next. + I think we can do this part ourselves but would have to + fully calculate xfer info ourselves and not use interrupts + */ + ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused, + hw_stream_type); + + /* Free last DMA call */ + while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) { + ivtv_buf_sync_for_cpu(s, buf); + ivtv_enqueue(s, buf, &s->q_free); + } + wake_up(&s->waitq); + } + clear_bit(IVTV_F_I_UDMA, &itv->i_flags); + clear_bit(IVTV_F_I_DMA, &itv->i_flags); + itv->cur_dma_stream = -1; + wake_up(&itv->dma_waitq); +} + +static void ivtv_irq_enc_dma_complete(struct ivtv *itv) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + struct ivtv_stream *s; + + ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data); + IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream); + + del_timer(&itv->dma_timer); + + if (itv->cur_dma_stream < 0) + return; + + s = &itv->streams[itv->cur_dma_stream]; + ivtv_stream_sync_for_cpu(s); + + if (data[0] & 0x18) { + IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0], + s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ + itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } + } + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_enc_start_xfer(s); + return; + } + clear_bit(IVTV_F_I_DMA, &itv->i_flags); + itv->cur_dma_stream = -1; + dma_post(s); + if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { + s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; + dma_post(s); + } + s->sg_processing_size = 0; + s->sg_processed = 0; + wake_up(&itv->dma_waitq); +} + +static void ivtv_irq_enc_pio_complete(struct ivtv *itv) +{ + struct ivtv_stream *s; + + if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS) { + itv->cur_pio_stream = -1; + return; + } + s = &itv->streams[itv->cur_pio_stream]; + IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); + clear_bit(IVTV_F_I_PIO, &itv->i_flags); + itv->cur_pio_stream = -1; + dma_post(s); + if (s->type == IVTV_ENC_STREAM_TYPE_MPG) + ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 0); + else if (s->type == IVTV_ENC_STREAM_TYPE_YUV) + ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 1); + else if (s->type == IVTV_ENC_STREAM_TYPE_PCM) + ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2); + clear_bit(IVTV_F_I_PIO, &itv->i_flags); + if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { + s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; + dma_post(s); + } + wake_up(&itv->dma_waitq); +} + +static void ivtv_irq_dma_err(struct ivtv *itv) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + u32 status; + + del_timer(&itv->dma_timer); + + ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data); + status = read_reg(IVTV_REG_DMASTATUS); + IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], + status, itv->cur_dma_stream); + /* + * We do *not* write back to the IVTV_REG_DMASTATUS register to + * clear the error status, if either the encoder write (0x02) or + * decoder read (0x01) bus master DMA operation do not indicate + * completed. We can race with the DMA engine, which may have + * transitioned to completed status *after* we read the register. + * Setting a IVTV_REG_DMASTATUS flag back to "busy" status, after the + * DMA engine has completed, will cause the DMA engine to stop working. + */ + status &= 0x3; + if (status == 0x3) + write_reg(status, IVTV_REG_DMASTATUS); + + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && + itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { + struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; + + if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { + /* retry */ + /* + * FIXME - handle cases of DMA error similar to + * encoder below, except conditioned on status & 0x1 + */ + ivtv_dma_dec_start(s); + return; + } else { + if ((status & 0x2) == 0) { + /* + * CX2341x Bus Master DMA write is ongoing. + * Reset the timer and let it complete. + */ + itv->dma_timer.expires = + jiffies + msecs_to_jiffies(600); + add_timer(&itv->dma_timer); + return; + } + + if (itv->dma_retries < 3) { + /* + * CX2341x Bus Master DMA write has ended. + * Retry the write, starting with the first + * xfer segment. Just retrying the current + * segment is not sufficient. + */ + s->sg_processed = 0; + itv->dma_retries++; + ivtv_dma_enc_start_xfer(s); + return; + } + /* Too many retries, give up on this one */ + } + + } + if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + ivtv_udma_start(itv); + return; + } + clear_bit(IVTV_F_I_UDMA, &itv->i_flags); + clear_bit(IVTV_F_I_DMA, &itv->i_flags); + itv->cur_dma_stream = -1; + wake_up(&itv->dma_waitq); +} + +static void ivtv_irq_enc_start_cap(struct ivtv *itv) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + struct ivtv_stream *s; + + /* Get DMA destination and size arguments from card */ + ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, 7, data); + IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]); + + if (data[0] > 2 || data[1] == 0 || data[2] == 0) { + IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n", + data[0], data[1], data[2]); + return; + } + s = &itv->streams[ivtv_stream_map[data[0]]]; + if (!stream_enc_dma_append(s, data)) { + set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); + } +} + +static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + struct ivtv_stream *s; + + IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n"); + s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; + + if (!stream_enc_dma_append(s, data)) + set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); +} + +static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; + + IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n"); + if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) && + !stream_enc_dma_append(s, data)) { + set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags); + } +} + +static void ivtv_irq_dec_data_req(struct ivtv *itv) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + struct ivtv_stream *s; + + /* YUV or MPG */ + + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { + ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data); + itv->dma_data_req_size = + 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); + itv->dma_data_req_offset = data[1]; + if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0) + ivtv_yuv_frame_complete(itv); + s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; + } + else { + ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 3, data); + itv->dma_data_req_size = min_t(u32, data[2], 0x10000); + itv->dma_data_req_offset = data[1]; + s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; + } + IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused, + itv->dma_data_req_offset, itv->dma_data_req_size); + if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) { + set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); + } + else { + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + ivtv_yuv_setup_stream_frame(itv); + clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); + ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); + ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); + } +} + +static void ivtv_irq_vsync(struct ivtv *itv) +{ + /* The vsync interrupt is unusual in that it won't clear until + * the end of the first line for the current field, at which + * point it clears itself. This can result in repeated vsync + * interrupts, or a missed vsync. Read some of the registers + * to determine the line being displayed and ensure we handle + * one vsync per frame. + */ + unsigned int frame = read_reg(IVTV_REG_DEC_LINE_FIELD) & 1; + struct yuv_playback_info *yi = &itv->yuv_info; + int last_dma_frame = atomic_read(&yi->next_dma_frame); + struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame]; + + if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); + + if (((frame ^ f->sync_field) == 0 && + ((itv->last_vsync_field & 1) ^ f->sync_field)) || + (frame != (itv->last_vsync_field & 1) && !f->interlaced)) { + int next_dma_frame = last_dma_frame; + + if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) { + if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) { + write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); + write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); + next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS; + atomic_set(&yi->next_dma_frame, next_dma_frame); + yi->fields_lapsed = -1; + yi->running = 1; + } + } + } + if (frame != (itv->last_vsync_field & 1)) { + static const struct v4l2_event evtop = { + .type = V4L2_EVENT_VSYNC, + .u.vsync.field = V4L2_FIELD_TOP, + }; + static const struct v4l2_event evbottom = { + .type = V4L2_EVENT_VSYNC, + .u.vsync.field = V4L2_FIELD_BOTTOM, + }; + struct ivtv_stream *s = ivtv_get_output_stream(itv); + + itv->last_vsync_field += 1; + if (frame == 0) { + clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); + clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); + } + else { + set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); + } + if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) { + set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags); + wake_up(&itv->event_waitq); + if (s) + wake_up(&s->waitq); + } + if (s && s->vdev) + v4l2_event_queue(s->vdev, frame ? &evtop : &evbottom); + wake_up(&itv->vsync_waitq); + + /* Send VBI to saa7127 */ + if (frame && (itv->output_mode == OUT_PASSTHROUGH || + test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) || + test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) || + test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) { + set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); + set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); + } + + /* Check if we need to update the yuv registers */ + if (yi->running && (yi->yuv_forced_update || f->update)) { + if (!f->update) { + last_dma_frame = + (u8)(atomic_read(&yi->next_dma_frame) - + 1) % IVTV_YUV_BUFFERS; + f = &yi->new_frame_info[last_dma_frame]; + } + + if (f->src_w) { + yi->update_frame = last_dma_frame; + f->update = 0; + yi->yuv_forced_update = 0; + set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); + set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); + } + } + + yi->fields_lapsed++; + } +} + +#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT) + +irqreturn_t ivtv_irq_handler(int irq, void *dev_id) +{ + struct ivtv *itv = (struct ivtv *)dev_id; + u32 combo; + u32 stat; + int i; + u8 vsync_force = 0; + + spin_lock(&itv->dma_reg_lock); + /* get contents of irq status register */ + stat = read_reg(IVTV_REG_IRQSTATUS); + + combo = ~itv->irqmask & stat; + + /* Clear out IRQ */ + if (combo) write_reg(combo, IVTV_REG_IRQSTATUS); + + if (0 == combo) { + /* The vsync interrupt is unusual and clears itself. If we + * took too long, we may have missed it. Do some checks + */ + if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { + /* vsync is enabled, see if we're in a new field */ + if ((itv->last_vsync_field & 1) != + (read_reg(IVTV_REG_DEC_LINE_FIELD) & 1)) { + /* New field, looks like we missed it */ + IVTV_DEBUG_YUV("VSync interrupt missed %d\n", + read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16); + vsync_force = 1; + } + } + + if (!vsync_force) { + /* No Vsync expected, wasn't for us */ + spin_unlock(&itv->dma_reg_lock); + return IRQ_NONE; + } + } + + /* Exclude interrupts noted below from the output, otherwise the log is flooded with + these messages */ + if (combo & ~0xff6d0400) + IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo); + + if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) { + IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n"); + } + + if (combo & IVTV_IRQ_DMA_READ) { + ivtv_irq_dma_read(itv); + } + + if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) { + ivtv_irq_enc_dma_complete(itv); + } + + if (combo & IVTV_IRQ_ENC_PIO_COMPLETE) { + ivtv_irq_enc_pio_complete(itv); + } + + if (combo & IVTV_IRQ_DMA_ERR) { + ivtv_irq_dma_err(itv); + } + + if (combo & IVTV_IRQ_ENC_START_CAP) { + ivtv_irq_enc_start_cap(itv); + } + + if (combo & IVTV_IRQ_ENC_VBI_CAP) { + ivtv_irq_enc_vbi_cap(itv); + } + + if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) { + ivtv_irq_dec_vbi_reinsert(itv); + } + + if (combo & IVTV_IRQ_ENC_EOS) { + IVTV_DEBUG_IRQ("ENC EOS\n"); + set_bit(IVTV_F_I_EOS, &itv->i_flags); + wake_up(&itv->eos_waitq); + } + + if (combo & IVTV_IRQ_DEC_DATA_REQ) { + ivtv_irq_dec_data_req(itv); + } + + /* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */ + if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { + ivtv_irq_vsync(itv); + } + + if (combo & IVTV_IRQ_ENC_VIM_RST) { + IVTV_DEBUG_IRQ("VIM RST\n"); + /*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */ + } + + if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) { + IVTV_DEBUG_INFO("Stereo mode changed\n"); + } + + if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { + itv->irq_rr_idx++; + for (i = 0; i < IVTV_MAX_STREAMS; i++) { + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; + struct ivtv_stream *s = &itv->streams[idx]; + + if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) + continue; + if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) + ivtv_dma_dec_start(s); + else + ivtv_dma_enc_start(s); + break; + } + + if (i == IVTV_MAX_STREAMS && + test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) + ivtv_udma_start(itv); + } + + if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) { + itv->irq_rr_idx++; + for (i = 0; i < IVTV_MAX_STREAMS; i++) { + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; + struct ivtv_stream *s = &itv->streams[idx]; + + if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags)) + continue; + if (s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type < IVTV_DEC_STREAM_TYPE_MPG) + ivtv_dma_enc_start(s); + break; + } + } + + if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { + queue_kthread_work(&itv->irq_worker, &itv->irq_work); + } + + spin_unlock(&itv->dma_reg_lock); + + /* If we've just handled a 'forced' vsync, it's safest to say it + * wasn't ours. Another device may have triggered it at just + * the right time. + */ + return vsync_force ? IRQ_NONE : IRQ_HANDLED; +} + +void ivtv_unfinished_dma(unsigned long arg) +{ + struct ivtv *itv = (struct ivtv *)arg; + + if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) + return; + IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); + + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + clear_bit(IVTV_F_I_UDMA, &itv->i_flags); + clear_bit(IVTV_F_I_DMA, &itv->i_flags); + itv->cur_dma_stream = -1; + wake_up(&itv->dma_waitq); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-irq.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-irq.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-irq.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-irq.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,53 @@ +/* + interrupt handling + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_IRQ_H +#define IVTV_IRQ_H + +#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) +#define IVTV_IRQ_ENC_EOS (0x1 << 30) +#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) +#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) +#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) +#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) +#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) +#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) +#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) +#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) +#define IVTV_IRQ_DMA_ERR (0x1 << 18) +#define IVTV_IRQ_DMA_WRITE (0x1 << 17) +#define IVTV_IRQ_DMA_READ (0x1 << 16) +#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) + +/* IRQ Masks */ +#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ + IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE) + +#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) +#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) + +irqreturn_t ivtv_irq_handler(int irq, void *dev_id); + +void ivtv_irq_work_handler(struct kthread_work *work); +void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); +void ivtv_unfinished_dma(unsigned long arg); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-mailbox.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-mailbox.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-mailbox.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-mailbox.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,387 @@ +/* + mailbox functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + +#include "ivtv-driver.h" +#include "ivtv-mailbox.h" + +/* Firmware mailbox flags*/ +#define IVTV_MBOX_FIRMWARE_DONE 0x00000004 +#define IVTV_MBOX_DRIVER_DONE 0x00000002 +#define IVTV_MBOX_DRIVER_BUSY 0x00000001 +#define IVTV_MBOX_FREE 0x00000000 + +/* Firmware mailbox standard timeout */ +#define IVTV_API_STD_TIMEOUT 0x02000000 + +#define API_CACHE (1 << 0) /* Allow the command to be stored in the cache */ +#define API_RESULT (1 << 1) /* Allow 1 second for this cmd to end */ +#define API_FAST_RESULT (3 << 1) /* Allow 0.1 second for this cmd to end */ +#define API_DMA (1 << 3) /* DMA mailbox, has special handling */ +#define API_HIGH_VOL (1 << 5) /* High volume command (i.e. called during encoding or decoding) */ +#define API_NO_WAIT_MB (1 << 4) /* Command may not wait for a free mailbox */ +#define API_NO_WAIT_RES (1 << 5) /* Command may not wait for the result */ +#define API_NO_POLL (1 << 6) /* Avoid pointless polling */ + +struct ivtv_api_info { + int flags; /* Flags, see above */ + const char *name; /* The name of the command */ +}; + +#define API_ENTRY(x, f) [x] = { (f), #x } + +static const struct ivtv_api_info api_info[256] = { + /* MPEG encoder API */ + API_ENTRY(CX2341X_ENC_PING_FW, API_FAST_RESULT), + API_ENTRY(CX2341X_ENC_START_CAPTURE, API_RESULT | API_NO_POLL), + API_ENTRY(CX2341X_ENC_STOP_CAPTURE, API_RESULT), + API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_PCR_ID, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_FRAME_RATE, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_FRAME_SIZE, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_BIT_RATE, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_GOP_PROPERTIES, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_ASPECT_RATIO, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_MODE, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_PROPS, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_CORING_LEVELS, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_VBI_LINE, API_RESULT), + API_ENTRY(CX2341X_ENC_SET_STREAM_TYPE, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_OUTPUT_PORT, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_AUDIO_PROPERTIES, API_CACHE), + API_ENTRY(CX2341X_ENC_HALT_FW, API_FAST_RESULT), + API_ENTRY(CX2341X_ENC_GET_VERSION, API_FAST_RESULT), + API_ENTRY(CX2341X_ENC_SET_GOP_CLOSURE, API_CACHE), + API_ENTRY(CX2341X_ENC_GET_SEQ_END, API_RESULT), + API_ENTRY(CX2341X_ENC_SET_PGM_INDEX_INFO, API_FAST_RESULT), + API_ENTRY(CX2341X_ENC_SET_VBI_CONFIG, API_RESULT), + API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, API_CACHE), + API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, API_FAST_RESULT), + API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, API_FAST_RESULT), + API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA | API_HIGH_VOL), + API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, API_RESULT), + API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, API_CACHE), + API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, API_RESULT), + API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB | API_HIGH_VOL), + API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, API_RESULT), + API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, API_CACHE), + API_ENTRY(CX2341X_ENC_SET_PLACEHOLDER, API_CACHE), + API_ENTRY(CX2341X_ENC_MUTE_VIDEO, API_RESULT), + API_ENTRY(CX2341X_ENC_MUTE_AUDIO, API_RESULT), + API_ENTRY(CX2341X_ENC_SET_VERT_CROP_LINE, API_FAST_RESULT), + API_ENTRY(CX2341X_ENC_MISC, API_FAST_RESULT), + /* Obsolete PULLDOWN API command */ + API_ENTRY(0xb1, API_CACHE), + + /* MPEG decoder API */ + API_ENTRY(CX2341X_DEC_PING_FW, API_FAST_RESULT), + API_ENTRY(CX2341X_DEC_START_PLAYBACK, API_RESULT | API_NO_POLL), + API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, API_RESULT), + API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, API_RESULT), + API_ENTRY(CX2341X_DEC_STEP_VIDEO, API_RESULT), + API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, API_CACHE), + API_ENTRY(CX2341X_DEC_GET_XFER_INFO, API_FAST_RESULT), + API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, API_FAST_RESULT), + API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA | API_HIGH_VOL), + API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, API_RESULT), + API_ENTRY(CX2341X_DEC_HALT_FW, API_FAST_RESULT), + API_ENTRY(CX2341X_DEC_SET_STANDARD, API_CACHE), + API_ENTRY(CX2341X_DEC_GET_VERSION, API_FAST_RESULT), + API_ENTRY(CX2341X_DEC_SET_STREAM_INPUT, API_CACHE), + API_ENTRY(CX2341X_DEC_GET_TIMING_INFO, API_RESULT /*| API_NO_WAIT_RES*/), + API_ENTRY(CX2341X_DEC_SET_AUDIO_MODE, API_CACHE), + API_ENTRY(CX2341X_DEC_SET_EVENT_NOTIFICATION, API_RESULT), + API_ENTRY(CX2341X_DEC_SET_DISPLAY_BUFFERS, API_CACHE), + API_ENTRY(CX2341X_DEC_EXTRACT_VBI, API_RESULT), + API_ENTRY(CX2341X_DEC_SET_DECODER_SOURCE, API_FAST_RESULT), + API_ENTRY(CX2341X_DEC_SET_PREBUFFERING, API_CACHE), + + /* OSD API */ + API_ENTRY(CX2341X_OSD_GET_FRAMEBUFFER, API_FAST_RESULT), + API_ENTRY(CX2341X_OSD_GET_PIXEL_FORMAT, API_FAST_RESULT), + API_ENTRY(CX2341X_OSD_SET_PIXEL_FORMAT, API_CACHE), + API_ENTRY(CX2341X_OSD_GET_STATE, API_FAST_RESULT), + API_ENTRY(CX2341X_OSD_SET_STATE, API_CACHE), + API_ENTRY(CX2341X_OSD_GET_OSD_COORDS, API_FAST_RESULT), + API_ENTRY(CX2341X_OSD_SET_OSD_COORDS, API_CACHE), + API_ENTRY(CX2341X_OSD_GET_SCREEN_COORDS, API_FAST_RESULT), + API_ENTRY(CX2341X_OSD_SET_SCREEN_COORDS, API_CACHE), + API_ENTRY(CX2341X_OSD_GET_GLOBAL_ALPHA, API_FAST_RESULT), + API_ENTRY(CX2341X_OSD_SET_GLOBAL_ALPHA, API_CACHE), + API_ENTRY(CX2341X_OSD_SET_BLEND_COORDS, API_CACHE), + API_ENTRY(CX2341X_OSD_GET_FLICKER_STATE, API_FAST_RESULT), + API_ENTRY(CX2341X_OSD_SET_FLICKER_STATE, API_CACHE), + API_ENTRY(CX2341X_OSD_BLT_COPY, API_RESULT), + API_ENTRY(CX2341X_OSD_BLT_FILL, API_RESULT), + API_ENTRY(CX2341X_OSD_BLT_TEXT, API_RESULT), + API_ENTRY(CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, API_CACHE), + API_ENTRY(CX2341X_OSD_SET_CHROMA_KEY, API_CACHE), + API_ENTRY(CX2341X_OSD_GET_ALPHA_CONTENT_INDEX, API_FAST_RESULT), + API_ENTRY(CX2341X_OSD_SET_ALPHA_CONTENT_INDEX, API_CACHE) +}; + +static int try_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int mb) +{ + u32 flags = readl(&mbdata->mbox[mb].flags); + int is_free = flags == IVTV_MBOX_FREE || (flags & IVTV_MBOX_FIRMWARE_DONE); + + /* if the mailbox is free, then try to claim it */ + if (is_free && !test_and_set_bit(mb, &mbdata->busy)) { + write_sync(IVTV_MBOX_DRIVER_BUSY, &mbdata->mbox[mb].flags); + return 1; + } + return 0; +} + +/* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not + attempted here. */ +static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int flags) +{ + unsigned long then = jiffies; + int i, mb; + int max_mbox = mbdata->max_mbox; + int retries = 100; + + /* All slow commands use the same mailbox, serializing them and also + leaving the other mailbox free for simple fast commands. */ + if ((flags & API_FAST_RESULT) == API_RESULT) + max_mbox = 1; + + /* find free non-DMA mailbox */ + for (i = 0; i < retries; i++) { + for (mb = 1; mb <= max_mbox; mb++) + if (try_mailbox(itv, mbdata, mb)) + return mb; + + /* Sleep before a retry, if not atomic */ + if (!(flags & API_NO_WAIT_MB)) { + if (time_after(jiffies, + then + msecs_to_jiffies(10*retries))) + break; + ivtv_msleep_timeout(10, 0); + } + } + return -ENODEV; +} + +static void write_mailbox(volatile struct ivtv_mailbox __iomem *mbox, int cmd, int args, u32 data[]) +{ + int i; + + write_sync(cmd, &mbox->cmd); + write_sync(IVTV_API_STD_TIMEOUT, &mbox->timeout); + + for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) + write_sync(data[i], &mbox->data[i]); + + write_sync(IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_DRIVER_BUSY, &mbox->flags); +} + +static void clear_all_mailboxes(struct ivtv *itv, struct ivtv_mailbox_data *mbdata) +{ + int i; + + for (i = 0; i <= mbdata->max_mbox; i++) { + IVTV_DEBUG_WARN("Clearing mailbox %d: cmd 0x%08x flags 0x%08x\n", + i, readl(&mbdata->mbox[i].cmd), readl(&mbdata->mbox[i].flags)); + write_sync(0, &mbdata->mbox[i].flags); + clear_bit(i, &mbdata->busy); + } +} + +static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) +{ + struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox; + volatile struct ivtv_mailbox __iomem *mbox; + int api_timeout = msecs_to_jiffies(1000); + int flags, mb, i; + unsigned long then; + + /* sanity checks */ + if (NULL == mbdata) { + IVTV_ERR("No mailbox allocated\n"); + return -ENODEV; + } + if (args < 0 || args > CX2341X_MBOX_MAX_DATA || + cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) { + IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args); + return -EINVAL; + } + + if (api_info[cmd].flags & API_HIGH_VOL) { + IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name); + } + else { + IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name); + } + + /* clear possibly uninitialized part of data array */ + for (i = args; i < CX2341X_MBOX_MAX_DATA; i++) + data[i] = 0; + + /* If this command was issued within the last 30 minutes and with identical + data, then just return 0 as there is no need to issue this command again. + Just an optimization to prevent unnecessary use of mailboxes. */ + if (itv->api_cache[cmd].last_jiffies && + time_before(jiffies, + itv->api_cache[cmd].last_jiffies + + msecs_to_jiffies(1800000)) && + !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) { + itv->api_cache[cmd].last_jiffies = jiffies; + return 0; + } + + flags = api_info[cmd].flags; + + if (flags & API_DMA) { + for (i = 0; i < 100; i++) { + mb = i % (mbdata->max_mbox + 1); + if (try_mailbox(itv, mbdata, mb)) { + write_mailbox(&mbdata->mbox[mb], cmd, args, data); + clear_bit(mb, &mbdata->busy); + return 0; + } + IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n", + api_info[cmd].name, mb, readl(&mbdata->mbox[mb].flags)); + } + IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info[cmd].name); + clear_all_mailboxes(itv, mbdata); + return -EBUSY; + } + + if ((flags & API_FAST_RESULT) == API_FAST_RESULT) + api_timeout = msecs_to_jiffies(100); + + mb = get_mailbox(itv, mbdata, flags); + if (mb < 0) { + IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info[cmd].name); + clear_all_mailboxes(itv, mbdata); + return -EBUSY; + } + mbox = &mbdata->mbox[mb]; + write_mailbox(mbox, cmd, args, data); + if (flags & API_CACHE) { + memcpy(itv->api_cache[cmd].data, data, sizeof(itv->api_cache[cmd].data)); + itv->api_cache[cmd].last_jiffies = jiffies; + } + if ((flags & API_RESULT) == 0) { + clear_bit(mb, &mbdata->busy); + return 0; + } + + /* Get results */ + then = jiffies; + + if (!(flags & API_NO_POLL)) { + /* First try to poll, then switch to delays */ + for (i = 0; i < 100; i++) { + if (readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE) + break; + } + } + while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) { + if (time_after(jiffies, then + api_timeout)) { + IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name); + /* reset the mailbox, but it is likely too late already */ + write_sync(0, &mbox->flags); + clear_bit(mb, &mbdata->busy); + return -EIO; + } + if (flags & API_NO_WAIT_RES) + mdelay(1); + else + ivtv_msleep_timeout(1, 0); + } + if (time_after(jiffies, then + msecs_to_jiffies(100))) + IVTV_DEBUG_WARN("%s took %u jiffies\n", + api_info[cmd].name, + jiffies_to_msecs(jiffies - then)); + + for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) + data[i] = readl(&mbox->data[i]); + write_sync(0, &mbox->flags); + clear_bit(mb, &mbdata->busy); + return 0; +} + +int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]) +{ + int res = ivtv_api_call(itv, cmd, args, data); + + /* Allow a single retry, probably already too late though. + If there is no free mailbox then that is usually an indication + of a more serious problem. */ + return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res; +} + +int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +{ + return ivtv_api(priv, cmd, in, data); +} + +int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...) +{ + va_list ap; + int i; + + va_start(ap, args); + for (i = 0; i < args; i++) { + data[i] = va_arg(ap, u32); + } + va_end(ap); + return ivtv_api(itv, cmd, args, data); +} + +int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + va_list ap; + int i; + + va_start(ap, args); + for (i = 0; i < args; i++) { + data[i] = va_arg(ap, u32); + } + va_end(ap); + return ivtv_api(itv, cmd, args, data); +} + +/* This one is for stuff that can't sleep.. irq handlers, etc.. */ +void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb, + int argc, u32 data[]) +{ + volatile u32 __iomem *p = mbdata->mbox[mb].data; + int i; + for (i = 0; i < argc; i++, p++) + data[i] = readl(p); +} + +/* Wipe api cache */ +void ivtv_mailbox_cache_invalidate(struct ivtv *itv) +{ + int i; + for (i = 0; i < 256; i++) + itv->api_cache[i].last_jiffies = 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-mailbox.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-mailbox.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-mailbox.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-mailbox.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,35 @@ +/* + mailbox functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_MAILBOX_H +#define IVTV_MAILBOX_H + +#define IVTV_MBOX_DMA_END 8 +#define IVTV_MBOX_DMA 9 + +void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb, + int argc, u32 data[]); +int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); +int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); +int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); +int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); +void ivtv_mailbox_cache_invalidate(struct ivtv *itv); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-queue.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-queue.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-queue.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-queue.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,297 @@ +/* + buffer queues. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-queue.h" + +int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes) +{ + if (s->buf_size - buf->bytesused < copybytes) + copybytes = s->buf_size - buf->bytesused; + if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) { + return -EFAULT; + } + buf->bytesused += copybytes; + return copybytes; +} + +void ivtv_buf_swap(struct ivtv_buffer *buf) +{ + int i; + + for (i = 0; i < buf->bytesused; i += 4) + swab32s((u32 *)(buf->buf + i)); +} + +void ivtv_queue_init(struct ivtv_queue *q) +{ + INIT_LIST_HEAD(&q->list); + q->buffers = 0; + q->length = 0; + q->bytesused = 0; +} + +void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q) +{ + unsigned long flags; + + /* clear the buffer if it is going to be enqueued to the free queue */ + if (q == &s->q_free) { + buf->bytesused = 0; + buf->readpos = 0; + buf->b_flags = 0; + buf->dma_xfer_cnt = 0; + } + spin_lock_irqsave(&s->qlock, flags); + list_add_tail(&buf->list, &q->list); + q->buffers++; + q->length += s->buf_size; + q->bytesused += buf->bytesused - buf->readpos; + spin_unlock_irqrestore(&s->qlock, flags); +} + +struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) +{ + struct ivtv_buffer *buf = NULL; + unsigned long flags; + + spin_lock_irqsave(&s->qlock, flags); + if (!list_empty(&q->list)) { + buf = list_entry(q->list.next, struct ivtv_buffer, list); + list_del_init(q->list.next); + q->buffers--; + q->length -= s->buf_size; + q->bytesused -= buf->bytesused - buf->readpos; + } + spin_unlock_irqrestore(&s->qlock, flags); + return buf; +} + +static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, + struct ivtv_queue *to, int clear) +{ + struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); + + list_move_tail(from->list.next, &to->list); + from->buffers--; + from->length -= s->buf_size; + from->bytesused -= buf->bytesused - buf->readpos; + /* special handling for q_free */ + if (clear) + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; + to->buffers++; + to->length += s->buf_size; + to->bytesused += buf->bytesused - buf->readpos; +} + +/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. + If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. + If 'steal' != NULL, then buffers may also taken from that queue if + needed, but only if 'from' is the free queue. + + The buffer is automatically cleared if it goes to the free queue. It is + also cleared if buffers need to be taken from the 'steal' queue and + the 'from' queue is the free queue. + + When 'from' is q_free, then needed_bytes is compared to the total + available buffer length, otherwise needed_bytes is compared to the + bytesused value. For the 'steal' queue the total available buffer + length is always used. + + -ENOMEM is returned if the buffers could not be obtained, 0 if all + buffers where obtained from the 'from' list and if non-zero then + the number of stolen buffers is returned. */ +int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, + struct ivtv_queue *to, int needed_bytes) +{ + unsigned long flags; + int rc = 0; + int from_free = from == &s->q_free; + int to_free = to == &s->q_free; + int bytes_available, bytes_steal; + + spin_lock_irqsave(&s->qlock, flags); + if (needed_bytes == 0) { + from_free = 1; + needed_bytes = from->length; + } + + bytes_available = from_free ? from->length : from->bytesused; + bytes_steal = (from_free && steal) ? steal->length : 0; + + if (bytes_available + bytes_steal < needed_bytes) { + spin_unlock_irqrestore(&s->qlock, flags); + return -ENOMEM; + } + while (bytes_available < needed_bytes) { + struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + u16 dma_xfer_cnt = buf->dma_xfer_cnt; + + /* move buffers from the tail of the 'steal' queue to the tail of the + 'from' queue. Always copy all the buffers with the same dma_xfer_cnt + value, this ensures that you do not end up with partial frame data + if one frame is stored in multiple buffers. */ + while (dma_xfer_cnt == buf->dma_xfer_cnt) { + list_move_tail(steal->list.prev, &from->list); + rc++; + steal->buffers--; + steal->length -= s->buf_size; + steal->bytesused -= buf->bytesused - buf->readpos; + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; + from->buffers++; + from->length += s->buf_size; + bytes_available += s->buf_size; + if (list_empty(&steal->list)) + break; + buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + } + } + if (from_free) { + u32 old_length = to->length; + + while (to->length - old_length < needed_bytes) { + ivtv_queue_move_buf(s, from, to, 1); + } + } + else { + u32 old_bytesused = to->bytesused; + + while (to->bytesused - old_bytesused < needed_bytes) { + ivtv_queue_move_buf(s, from, to, to_free); + } + } + spin_unlock_irqrestore(&s->qlock, flags); + return rc; +} + +void ivtv_flush_queues(struct ivtv_stream *s) +{ + ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0); + ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0); + ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); + ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); +} + +int ivtv_stream_alloc(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + int SGsize = sizeof(struct ivtv_sg_host_element) * s->buffers; + int i; + + if (s->buffers == 0) + return 0; + + IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n", + s->dma != PCI_DMA_NONE ? "DMA " : "", + s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); + + s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); + if (s->sg_pending == NULL) { + IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); + return -ENOMEM; + } + s->sg_pending_size = 0; + + s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN); + if (s->sg_processing == NULL) { + IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + return -ENOMEM; + } + s->sg_processing_size = 0; + + s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), + GFP_KERNEL|__GFP_NOWARN); + if (s->sg_dma == NULL) { + IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + kfree(s->sg_processing); + s->sg_processing = NULL; + return -ENOMEM; + } + if (ivtv_might_use_dma(s)) { + s->sg_handle = pci_map_single(itv->pdev, s->sg_dma, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); + ivtv_stream_sync_for_cpu(s); + } + + /* allocate stream buffers. Initially all buffers are in q_free. */ + for (i = 0; i < s->buffers; i++) { + struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), + GFP_KERNEL|__GFP_NOWARN); + + if (buf == NULL) + break; + buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN); + if (buf->buf == NULL) { + kfree(buf); + break; + } + INIT_LIST_HEAD(&buf->list); + if (ivtv_might_use_dma(s)) { + buf->dma_handle = pci_map_single(s->itv->pdev, + buf->buf, s->buf_size + 256, s->dma); + ivtv_buf_sync_for_cpu(s, buf); + } + ivtv_enqueue(s, buf, &s->q_free); + } + if (i == s->buffers) + return 0; + IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name); + ivtv_stream_free(s); + return -ENOMEM; +} + +void ivtv_stream_free(struct ivtv_stream *s) +{ + struct ivtv_buffer *buf; + + /* move all buffers to q_free */ + ivtv_flush_queues(s); + + /* empty q_free */ + while ((buf = ivtv_dequeue(s, &s->q_free))) { + if (ivtv_might_use_dma(s)) + pci_unmap_single(s->itv->pdev, buf->dma_handle, + s->buf_size + 256, s->dma); + kfree(buf->buf); + kfree(buf); + } + + /* Free SG Array/Lists */ + if (s->sg_dma != NULL) { + if (s->sg_handle != IVTV_DMA_UNMAPPED) { + pci_unmap_single(s->itv->pdev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); + s->sg_handle = IVTV_DMA_UNMAPPED; + } + kfree(s->sg_pending); + kfree(s->sg_processing); + kfree(s->sg_dma); + s->sg_pending = NULL; + s->sg_processing = NULL; + s->sg_dma = NULL; + s->sg_pending_size = 0; + s->sg_processing_size = 0; + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-queue.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-queue.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-queue.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-queue.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,96 @@ +/* + buffer queues. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_QUEUE_H +#define IVTV_QUEUE_H + +#define IVTV_DMA_UNMAPPED ((u32) -1) +#define SLICED_VBI_PIO 0 + +/* ivtv_buffer utility functions */ + +static inline int ivtv_might_use_pio(struct ivtv_stream *s) +{ + return s->dma == PCI_DMA_NONE || (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI); +} + +static inline int ivtv_use_pio(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + return s->dma == PCI_DMA_NONE || + (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set); +} + +static inline int ivtv_might_use_dma(struct ivtv_stream *s) +{ + return s->dma != PCI_DMA_NONE; +} + +static inline int ivtv_use_dma(struct ivtv_stream *s) +{ + return !ivtv_use_pio(s); +} + +static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf) +{ + if (ivtv_use_dma(s)) + pci_dma_sync_single_for_cpu(s->itv->pdev, buf->dma_handle, + s->buf_size + 256, s->dma); +} + +static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf) +{ + if (ivtv_use_dma(s)) + pci_dma_sync_single_for_device(s->itv->pdev, buf->dma_handle, + s->buf_size + 256, s->dma); +} + +int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes); +void ivtv_buf_swap(struct ivtv_buffer *buf); + +/* ivtv_queue utility functions */ +void ivtv_queue_init(struct ivtv_queue *q); +void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q); +struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q); +int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, + struct ivtv_queue *to, int needed_bytes); +void ivtv_flush_queues(struct ivtv_stream *s); + +/* ivtv_stream utility functions */ +int ivtv_stream_alloc(struct ivtv_stream *s); +void ivtv_stream_free(struct ivtv_stream *s); + +static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s) +{ + if (ivtv_use_dma(s)) + pci_dma_sync_single_for_cpu(s->itv->pdev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); +} + +static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) +{ + if (ivtv_use_dma(s)) + pci_dma_sync_single_for_device(s->itv->pdev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); +} + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-routing.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-routing.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-routing.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-routing.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,119 @@ +/* + Audio/video-routing-related ivtv functions. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-i2c.h" +#include "ivtv-cards.h" +#include "ivtv-gpio.h" +#include "ivtv-routing.h" + +#include +#include +#include +#include + +/* Selects the audio input and output according to the current + settings. */ +void ivtv_audio_set_io(struct ivtv *itv) +{ + const struct ivtv_card_audio_input *in; + u32 input, output = 0; + + /* Determine which input to use */ + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) + in = &itv->card->radio_input; + else + in = &itv->card->audio_inputs[itv->audio_input]; + + /* handle muxer chips */ + input = in->muxer_input; + if (itv->card->hw_muxer & IVTV_HW_M52790) + output = M52790_OUT_STEREO; + v4l2_subdev_call(itv->sd_muxer, audio, s_routing, + input, output, 0); + + input = in->audio_input; + output = 0; + if (itv->card->hw_audio & IVTV_HW_MSP34XX) + output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); + ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing, + input, output, 0); +} + +/* Selects the video input and output according to the current + settings. */ +void ivtv_video_set_io(struct ivtv *itv) +{ + int inp = itv->active_input; + u32 input; + u32 type; + + v4l2_subdev_call(itv->sd_video, video, s_routing, + itv->card->video_inputs[inp].video_input, 0, 0); + + type = itv->card->video_inputs[inp].video_type; + + if (type == IVTV_CARD_INPUT_VID_TUNER) { + input = 0; /* Tuner */ + } else if (type < IVTV_CARD_INPUT_COMPOSITE1) { + input = 2; /* S-Video */ + } else { + input = 1; /* Composite */ + } + + if (itv->card->hw_video & IVTV_HW_GPIO) + ivtv_call_hw(itv, IVTV_HW_GPIO, video, s_routing, + input, 0, 0); + + if (itv->card->hw_video & IVTV_HW_UPD64031A) { + if (type == IVTV_CARD_INPUT_VID_TUNER || + type >= IVTV_CARD_INPUT_COMPOSITE1) { + /* Composite: GR on, connect to 3DYCS */ + input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE; + } else { + /* S-Video: GR bypassed, turn it off */ + input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE; + } + input |= itv->card->gr_config; + + ivtv_call_hw(itv, IVTV_HW_UPD64031A, video, s_routing, + input, 0, 0); + } + + if (itv->card->hw_video & IVTV_HW_UPD6408X) { + input = UPD64083_YCS_MODE; + if (type > IVTV_CARD_INPUT_VID_TUNER && + type < IVTV_CARD_INPUT_COMPOSITE1) { + /* S-Video uses YCNR mode and internal Y-ADC, the + upd64031a is not used. */ + input |= UPD64083_YCNR_MODE; + } + else if (itv->card->hw_video & IVTV_HW_UPD64031A) { + /* Use upd64031a output for tuner and + composite(CX23416GYC only) inputs */ + if (type == IVTV_CARD_INPUT_VID_TUNER || + itv->card->type == IVTV_CARD_CX23416GYC) { + input |= UPD64083_EXT_Y_ADC; + } + } + ivtv_call_hw(itv, IVTV_HW_UPD6408X, video, s_routing, + input, 0, 0); + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-routing.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-routing.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-routing.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-routing.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,27 @@ +/* + Audio/video-routing-related ivtv functions. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_ROUTING_H +#define IVTV_ROUTING_H + +void ivtv_audio_set_io(struct ivtv *itv); +void ivtv_video_set_io(struct ivtv *itv); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-streams.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-streams.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-streams.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-streams.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1000 @@ +/* + init/start/stop/exit stream functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +/* License: GPL + * Author: Kevin Thayer + * + * This file will hold API related functions, both internal (firmware api) + * and external (v4l2, etc) + * + * ----- + * MPG600/MPG160 support by T.Adachi + * and Takeru KOMORIYA + * + * AVerMedia M179 GPIO info by Chris Pinkham + * using information provided by Jiun-Kuei Jung @ AVerMedia. + */ + +#include "ivtv-driver.h" +#include "ivtv-fileops.h" +#include "ivtv-queue.h" +#include "ivtv-mailbox.h" +#include "ivtv-ioctl.h" +#include "ivtv-irq.h" +#include "ivtv-yuv.h" +#include "ivtv-cards.h" +#include "ivtv-streams.h" +#include "ivtv-firmware.h" +#include + +static const struct v4l2_file_operations ivtv_v4l2_enc_fops = { + .owner = THIS_MODULE, + .read = ivtv_v4l2_read, + .write = ivtv_v4l2_write, + .open = ivtv_v4l2_open, + .unlocked_ioctl = ivtv_v4l2_ioctl, + .release = ivtv_v4l2_close, + .poll = ivtv_v4l2_enc_poll, +}; + +static const struct v4l2_file_operations ivtv_v4l2_dec_fops = { + .owner = THIS_MODULE, + .read = ivtv_v4l2_read, + .write = ivtv_v4l2_write, + .open = ivtv_v4l2_open, + .unlocked_ioctl = ivtv_v4l2_ioctl, + .release = ivtv_v4l2_close, + .poll = ivtv_v4l2_dec_poll, +}; + +#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ +#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ +#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ +#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ +#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ +#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ + +static struct { + const char *name; + int vfl_type; + int num_offset; + int dma, pio; + enum v4l2_buf_type buf_type; + const struct v4l2_file_operations *fops; +} ivtv_stream_info[] = { + { /* IVTV_ENC_STREAM_TYPE_MPG */ + "encoder MPG", + VFL_TYPE_GRABBER, 0, + PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_ENC_STREAM_TYPE_YUV */ + "encoder YUV", + VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, + PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_ENC_STREAM_TYPE_VBI */ + "encoder VBI", + VFL_TYPE_VBI, 0, + PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_ENC_STREAM_TYPE_PCM */ + "encoder PCM", + VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, + PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_ENC_STREAM_TYPE_RAD */ + "encoder radio", + VFL_TYPE_RADIO, 0, + PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_DEC_STREAM_TYPE_MPG */ + "decoder MPG", + VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, + PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, + &ivtv_v4l2_dec_fops + }, + { /* IVTV_DEC_STREAM_TYPE_VBI */ + "decoder VBI", + VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, + PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, + &ivtv_v4l2_enc_fops + }, + { /* IVTV_DEC_STREAM_TYPE_VOUT */ + "decoder VOUT", + VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, + PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, + &ivtv_v4l2_dec_fops + }, + { /* IVTV_DEC_STREAM_TYPE_YUV */ + "decoder YUV", + VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, + PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, + &ivtv_v4l2_dec_fops + } +}; + +static void ivtv_stream_init(struct ivtv *itv, int type) +{ + struct ivtv_stream *s = &itv->streams[type]; + struct video_device *vdev = s->vdev; + + /* we need to keep vdev, so restore it afterwards */ + memset(s, 0, sizeof(*s)); + s->vdev = vdev; + + /* initialize ivtv_stream fields */ + s->itv = itv; + s->type = type; + s->name = ivtv_stream_info[type].name; + + if (ivtv_stream_info[type].pio) + s->dma = PCI_DMA_NONE; + else + s->dma = ivtv_stream_info[type].dma; + s->buf_size = itv->stream_buf_size[type]; + if (s->buf_size) + s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size; + spin_lock_init(&s->qlock); + init_waitqueue_head(&s->waitq); + s->id = -1; + s->sg_handle = IVTV_DMA_UNMAPPED; + ivtv_queue_init(&s->q_free); + ivtv_queue_init(&s->q_full); + ivtv_queue_init(&s->q_dma); + ivtv_queue_init(&s->q_predma); + ivtv_queue_init(&s->q_io); +} + +static int ivtv_prep_dev(struct ivtv *itv, int type) +{ + struct ivtv_stream *s = &itv->streams[type]; + int num_offset = ivtv_stream_info[type].num_offset; + int num = itv->instance + ivtv_first_minor + num_offset; + + /* These four fields are always initialized. If vdev == NULL, then + this stream is not in use. In that case no other fields but these + four can be used. */ + s->vdev = NULL; + s->itv = itv; + s->type = type; + s->name = ivtv_stream_info[type].name; + + /* Check whether the radio is supported */ + if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO)) + return 0; + if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return 0; + + /* User explicitly selected 0 buffers for these streams, so don't + create them. */ + if (ivtv_stream_info[type].dma != PCI_DMA_NONE && + itv->options.kilobytes[type] == 0) { + IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); + return 0; + } + + ivtv_stream_init(itv, type); + + /* allocate and initialize the v4l2 video device structure */ + s->vdev = video_device_alloc(); + if (s->vdev == NULL) { + IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); + return -ENOMEM; + } + + snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s", + itv->v4l2_dev.name, s->name); + + s->vdev->num = num; + s->vdev->v4l2_dev = &itv->v4l2_dev; + s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler; + s->vdev->fops = ivtv_stream_info[type].fops; + s->vdev->release = video_device_release; + s->vdev->tvnorms = V4L2_STD_ALL; + set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags); + ivtv_set_funcs(s->vdev); + return 0; +} + +/* Initialize v4l2 variables and prepare v4l2 devices */ +int ivtv_streams_setup(struct ivtv *itv) +{ + int type; + + /* Setup V4L2 Devices */ + for (type = 0; type < IVTV_MAX_STREAMS; type++) { + /* Prepare device */ + if (ivtv_prep_dev(itv, type)) + break; + + if (itv->streams[type].vdev == NULL) + continue; + + /* Allocate Stream */ + if (ivtv_stream_alloc(&itv->streams[type])) + break; + } + if (type == IVTV_MAX_STREAMS) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + ivtv_streams_cleanup(itv, 0); + return -ENOMEM; +} + +static int ivtv_reg_dev(struct ivtv *itv, int type) +{ + struct ivtv_stream *s = &itv->streams[type]; + int vfl_type = ivtv_stream_info[type].vfl_type; + const char *name; + int num; + + if (s->vdev == NULL) + return 0; + + num = s->vdev->num; + /* card number + user defined offset + device offset */ + if (type != IVTV_ENC_STREAM_TYPE_MPG) { + struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; + + if (s_mpg->vdev) + num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset; + } + video_set_drvdata(s->vdev, s); + + /* Register device. First try the desired minor, then any free one. */ + if (video_register_device_no_warn(s->vdev, vfl_type, num)) { + IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", + s->name, num); + video_device_release(s->vdev); + s->vdev = NULL; + return -ENOMEM; + } + name = video_device_node_name(s->vdev); + + switch (vfl_type) { + case VFL_TYPE_GRABBER: + IVTV_INFO("Registered device %s for %s (%d kB)\n", + name, s->name, itv->options.kilobytes[type]); + break; + case VFL_TYPE_RADIO: + IVTV_INFO("Registered device %s for %s\n", + name, s->name); + break; + case VFL_TYPE_VBI: + if (itv->options.kilobytes[type]) + IVTV_INFO("Registered device %s for %s (%d kB)\n", + name, s->name, itv->options.kilobytes[type]); + else + IVTV_INFO("Registered device %s for %s\n", + name, s->name); + break; + } + return 0; +} + +/* Register v4l2 devices */ +int ivtv_streams_register(struct ivtv *itv) +{ + int type; + int err = 0; + + /* Register V4L2 devices */ + for (type = 0; type < IVTV_MAX_STREAMS; type++) + err |= ivtv_reg_dev(itv, type); + + if (err == 0) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + ivtv_streams_cleanup(itv, 1); + return -ENOMEM; +} + +/* Unregister v4l2 devices */ +void ivtv_streams_cleanup(struct ivtv *itv, int unregister) +{ + int type; + + /* Teardown all streams */ + for (type = 0; type < IVTV_MAX_STREAMS; type++) { + struct video_device *vdev = itv->streams[type].vdev; + + itv->streams[type].vdev = NULL; + if (vdev == NULL) + continue; + + ivtv_stream_free(&itv->streams[type]); + /* Unregister or release device */ + if (unregister) + video_unregister_device(vdev); + else + video_device_release(vdev); + } +} + +static void ivtv_vbi_setup(struct ivtv *itv) +{ + int raw = ivtv_raw_vbi(itv); + u32 data[CX2341X_MBOX_MAX_DATA]; + int lines; + int i; + + /* Reset VBI */ + ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); + + /* setup VBI registers */ + if (raw) + v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &itv->vbi.in.fmt.vbi); + else + v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, &itv->vbi.in.fmt.sliced); + + /* determine number of lines and total number of VBI bytes. + A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 + The '- 1' byte is probably an unused U or V byte. Or something... + A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal + header, 42 data bytes + checksum (to be confirmed) */ + if (raw) { + lines = itv->vbi.count * 2; + } else { + lines = itv->is_60hz ? 24 : 38; + if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840)) + lines += 2; + } + + itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); + + /* Note: sliced vs raw flag doesn't seem to have any effect + TODO: check mode (0x02) value with older ivtv versions. */ + data[0] = raw | 0x02 | (0xbd << 8); + + /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ + data[1] = 1; + /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ + data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size); + /* The start/stop codes determine which VBI lines end up in the raw VBI data area. + The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line + is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) + code. These values for raw VBI are obtained from a driver disassembly. The sliced + start/stop codes was deduced from this, but they do not appear in the driver. + Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54. + However, I have no idea what these values are for. */ + if (itv->hw_flags & IVTV_HW_CX25840) { + /* Setup VBI for the cx25840 digitizer */ + if (raw) { + data[3] = 0x20602060; + data[4] = 0x30703070; + } else { + data[3] = 0xB0F0B0F0; + data[4] = 0xA0E0A0E0; + } + /* Lines per frame */ + data[5] = lines; + /* bytes per line */ + data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); + } else { + /* Setup VBI for the saa7115 digitizer */ + if (raw) { + data[3] = 0x25256262; + data[4] = 0x387F7F7F; + } else { + data[3] = 0xABABECEC; + data[4] = 0xB6F1F1F1; + } + /* Lines per frame */ + data[5] = lines; + /* bytes per line */ + data[6] = itv->vbi.enc_size / lines; + } + + IVTV_DEBUG_INFO( + "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n", + data[0], data[1], data[2], data[5], data[6]); + + ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data); + + /* returns the VBI encoder memory area. */ + itv->vbi.enc_start = data[2]; + itv->vbi.fpi = data[0]; + if (!itv->vbi.fpi) + itv->vbi.fpi = 1; + + IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n", + itv->vbi.enc_start, data[1], itv->vbi.fpi); + + /* select VBI lines. + Note that the sliced argument seems to have no effect. */ + for (i = 2; i <= 24; i++) { + int valid; + + if (itv->is_60hz) { + valid = i >= 10 && i < 22; + } else { + valid = i >= 6 && i < 24; + } + ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1, + valid, 0 , 0, 0); + ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000, + valid, 0, 0, 0); + } + + /* Remaining VBI questions: + - Is it possible to select particular VBI lines only for inclusion in the MPEG + stream? Currently you can only get the first X lines. + - Is mixed raw and sliced VBI possible? + - What's the meaning of the raw/sliced flag? + - What's the meaning of params 2, 3 & 4 of the Select VBI command? */ +} + +int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + struct ivtv *itv = s->itv; + int captype = 0, subtype = 0; + int enable_passthrough = 0; + + if (s->vdev == NULL) + return -EINVAL; + + IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); + + switch (s->type) { + case IVTV_ENC_STREAM_TYPE_MPG: + captype = 0; + subtype = 3; + + /* Stop Passthrough */ + if (itv->output_mode == OUT_PASSTHROUGH) { + ivtv_passthrough_mode(itv, 0); + enable_passthrough = 1; + } + itv->mpg_data_received = itv->vbi_data_inserted = 0; + itv->dualwatch_jiffies = jiffies; + itv->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode); + itv->search_pack_header = 0; + break; + + case IVTV_ENC_STREAM_TYPE_YUV: + if (itv->output_mode == OUT_PASSTHROUGH) { + captype = 2; + subtype = 11; /* video+audio+decoder */ + break; + } + captype = 1; + subtype = 1; + break; + case IVTV_ENC_STREAM_TYPE_PCM: + captype = 1; + subtype = 2; + break; + case IVTV_ENC_STREAM_TYPE_VBI: + captype = 1; + subtype = 4; + + itv->vbi.frame = 0; + itv->vbi.inserted_frame = 0; + memset(itv->vbi.sliced_mpeg_size, + 0, sizeof(itv->vbi.sliced_mpeg_size)); + break; + default: + return -EINVAL; + } + s->subtype = subtype; + s->buffers_stolen = 0; + + /* Clear Streamoff flags in case left from last capture */ + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + + if (atomic_read(&itv->capturing) == 0) { + int digitizer; + + /* Always use frame based mode. Experiments have demonstrated that byte + stream based mode results in dropped frames and corruption. Not often, + but occasionally. Many thanks go to Leonard Orb who spent a lot of + effort and time trying to trace the cause of the drop outs. */ + /* 1 frame per DMA */ + /*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */ + ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1); + + /* Stuff from Windows, we don't know what it is */ + ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0); + /* According to the docs, this should be correct. However, this is + untested. I don't dare enable this without having tested it. + Only very few old cards actually have this hardware combination. + ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, + ((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0); + */ + ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415); + ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0); + ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1); + ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); + + /* assign placeholder */ + ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) + digitizer = 0xF1; + else if (itv->card->hw_all & IVTV_HW_SAA7114) + digitizer = 0xEF; + else /* cx25840 */ + digitizer = 0x140; + + ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer); + + /* Setup VBI */ + if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) { + ivtv_vbi_setup(itv); + } + + /* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */ + ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400); + itv->pgm_info_offset = data[0]; + itv->pgm_info_num = data[1]; + itv->pgm_info_write_idx = 0; + itv->pgm_info_read_idx = 0; + + IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n", + itv->pgm_info_offset, itv->pgm_info_num); + + /* Setup API for Stream */ + cx2341x_handler_setup(&itv->cxhdl); + + /* mute if capturing radio */ + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) + ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, + 1 | (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8)); + } + + /* Vsync Setup */ + if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { + /* event notification (on) */ + ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1); + ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); + } + + if (atomic_read(&itv->capturing) == 0) { + /* Clear all Pending Interrupts */ + ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + + clear_bit(IVTV_F_I_EOS, &itv->i_flags); + + cx2341x_handler_set_busy(&itv->cxhdl, 1); + + /* Initialize Digitizer for Capture */ + /* Avoid tinny audio problem - ensure audio clocks are going */ + v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1); + /* Avoid unpredictable PCI bus hang - disable video clocks */ + v4l2_subdev_call(itv->sd_video, video, s_stream, 0); + ivtv_msleep_timeout(300, 0); + ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); + v4l2_subdev_call(itv->sd_video, video, s_stream, 1); + } + + /* begin_capture */ + if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) + { + IVTV_DEBUG_WARN( "Error starting capture!\n"); + return -EINVAL; + } + + /* Start Passthrough */ + if (enable_passthrough) { + ivtv_passthrough_mode(itv, 1); + } + + if (s->type == IVTV_ENC_STREAM_TYPE_VBI) + ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); + else + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + + /* you're live! sit back and await interrupts :) */ + atomic_inc(&itv->capturing); + return 0; +} + +static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + struct ivtv *itv = s->itv; + int datatype; + u16 width; + u16 height; + + if (s->vdev == NULL) + return -EINVAL; + + IVTV_DEBUG_INFO("Setting some initial decoder settings\n"); + + width = itv->cxhdl.width; + height = itv->cxhdl.height; + + /* set audio mode to left/stereo for dual/stereo mode. */ + ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); + + /* set number of internal decoder buffers */ + ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0); + + /* prebuffering */ + ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1); + + /* extract from user packets */ + ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1); + itv->vbi.dec_start = data[0]; + + IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n", + itv->vbi.dec_start, data[1]); + + /* set decoder source settings */ + /* Data type: 0 = mpeg from host, + 1 = yuv from encoder, + 2 = yuv_from_host */ + switch (s->type) { + case IVTV_DEC_STREAM_TYPE_YUV: + if (itv->output_mode == OUT_PASSTHROUGH) { + datatype = 1; + } else { + /* Fake size to avoid switching video standard */ + datatype = 2; + width = 720; + height = itv->is_out_50hz ? 576 : 480; + } + IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype); + break; + case IVTV_DEC_STREAM_TYPE_MPG: + default: + datatype = 0; + break; + } + if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype, + width, height, itv->cxhdl.audio_properties)) { + IVTV_DEBUG_WARN("Couldn't initialize decoder source\n"); + } + + /* Decoder sometimes dies here, so wait a moment */ + ivtv_msleep_timeout(10, 0); + + /* Known failure point for firmware, so check */ + return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream"); +} + +int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) +{ + struct ivtv *itv = s->itv; + int rc; + + if (s->vdev == NULL) + return -EINVAL; + + if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) + return 0; /* already started */ + + IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); + + rc = ivtv_setup_v4l2_decode_stream(s); + if (rc < 0) { + clear_bit(IVTV_F_S_STREAMING, &s->s_flags); + return rc; + } + + /* set dma size to 65536 bytes */ + ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); + + /* Clear Streamoff */ + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + + /* Zero out decoder counters */ + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]); + + /* turn on notification of dual/stereo mode change */ + ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); + + /* start playback */ + ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0); + + /* Let things settle before we actually start */ + ivtv_msleep_timeout(10, 0); + + /* Clear the following Interrupt mask bits for decoding */ + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE); + IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask); + + /* you're live! sit back and await interrupts :) */ + atomic_inc(&itv->decoding); + return 0; +} + +void ivtv_stop_all_captures(struct ivtv *itv) +{ + int i; + + for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) { + struct ivtv_stream *s = &itv->streams[i]; + + if (s->vdev == NULL) + continue; + if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { + ivtv_stop_v4l2_encode_stream(s, 0); + } + } +} + +int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) +{ + struct ivtv *itv = s->itv; + DECLARE_WAITQUEUE(wait, current); + int cap_type; + int stopmode; + + if (s->vdev == NULL) + return -EINVAL; + + /* This function assumes that you are allowed to stop the capture + and that we are actually capturing */ + + IVTV_DEBUG_INFO("Stop Capture\n"); + + if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) + return 0; + if (atomic_read(&itv->capturing) == 0) + return 0; + + switch (s->type) { + case IVTV_ENC_STREAM_TYPE_YUV: + cap_type = 1; + break; + case IVTV_ENC_STREAM_TYPE_PCM: + cap_type = 1; + break; + case IVTV_ENC_STREAM_TYPE_VBI: + cap_type = 1; + break; + case IVTV_ENC_STREAM_TYPE_MPG: + default: + cap_type = 0; + break; + } + + /* Stop Capture Mode */ + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { + stopmode = 0; + } else { + stopmode = 1; + } + + /* end_capture */ + /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ + ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); + + if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { + /* only run these if we're shutting down the last cap */ + unsigned long duration; + unsigned long then = jiffies; + + add_wait_queue(&itv->eos_waitq, &wait); + + set_current_state(TASK_INTERRUPTIBLE); + + /* wait 2s for EOS interrupt */ + while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && + time_before(jiffies, + then + msecs_to_jiffies(2000))) { + schedule_timeout(msecs_to_jiffies(10)); + } + + /* To convert jiffies to ms, we must multiply by 1000 + * and divide by HZ. To avoid runtime division, we + * convert this to multiplication by 1000/HZ. + * Since integer division truncates, we get the best + * accuracy if we do a rounding calculation of the constant. + * Think of the case where HZ is 1024. + */ + duration = ((1000 + HZ / 2) / HZ) * (jiffies - then); + + if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) { + IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name); + IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration); + } else { + IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&itv->eos_waitq, &wait); + set_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + } + + /* Handle any pending interrupts */ + ivtv_msleep_timeout(100, 0); + } + + atomic_dec(&itv->capturing); + + /* Clear capture and no-read bits */ + clear_bit(IVTV_F_S_STREAMING, &s->s_flags); + + if (s->type == IVTV_ENC_STREAM_TYPE_VBI) + ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); + + if (atomic_read(&itv->capturing) > 0) { + return 0; + } + + cx2341x_handler_set_busy(&itv->cxhdl, 0); + + /* Set the following Interrupt mask bits for capture */ + ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + del_timer(&itv->dma_timer); + + /* event notification (off) */ + if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { + /* type: 0 = refresh */ + /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */ + ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1); + ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); + } + + /* Raw-passthrough is implied on start. Make sure it's stopped so + the encoder will re-initialize when next started */ + ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 7); + + wake_up(&s->waitq); + + return 0; +} + +int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) +{ + static const struct v4l2_event ev = { + .type = V4L2_EVENT_EOS, + }; + struct ivtv *itv = s->itv; + + if (s->vdev == NULL) + return -EINVAL; + + if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG) + return -EINVAL; + + if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags)) + return 0; + + IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags); + + /* Stop Decoder */ + if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) { + u32 tmp = 0; + + /* Wait until the decoder is no longer running */ + if (pts) { + ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, + 0, (u32)(pts & 0xffffffff), (u32)(pts >> 32)); + } + while (1) { + u32 data[CX2341X_MBOX_MAX_DATA]; + ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0); + if (s->q_full.buffers + s->q_dma.buffers == 0) { + if (tmp == data[3]) + break; + tmp = data[3]; + } + if (ivtv_msleep_timeout(100, 1)) + break; + } + } + ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0); + + /* turn off notification of dual/stereo mode change */ + ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); + + ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); + del_timer(&itv->dma_timer); + + clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); + clear_bit(IVTV_F_S_STREAMING, &s->s_flags); + ivtv_flush_queues(s); + + /* decoder needs time to settle */ + ivtv_msleep_timeout(40, 0); + + /* decrement decoding */ + atomic_dec(&itv->decoding); + + set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags); + wake_up(&itv->event_waitq); + v4l2_event_queue(s->vdev, &ev); + + /* wake up wait queues */ + wake_up(&s->waitq); + + return 0; +} + +int ivtv_passthrough_mode(struct ivtv *itv, int enable) +{ + struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV]; + struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; + + if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL) + return -EINVAL; + + IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n"); + + /* Prevent others from starting/stopping streams while we + initiate/terminate passthrough mode */ + if (enable) { + if (itv->output_mode == OUT_PASSTHROUGH) { + return 0; + } + if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH) + return -EBUSY; + + /* Fully initialize stream, and then unflag init */ + set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); + set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); + + /* Setup YUV Decoder */ + ivtv_setup_v4l2_decode_stream(dec_stream); + + /* Start Decoder */ + ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1); + atomic_inc(&itv->decoding); + + /* Setup capture if not already done */ + if (atomic_read(&itv->capturing) == 0) { + cx2341x_handler_setup(&itv->cxhdl); + cx2341x_handler_set_busy(&itv->cxhdl, 1); + } + + /* Start Passthrough Mode */ + ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11); + atomic_inc(&itv->capturing); + return 0; + } + + if (itv->output_mode != OUT_PASSTHROUGH) + return 0; + + /* Stop Passthrough Mode */ + ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11); + ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0); + + atomic_dec(&itv->capturing); + atomic_dec(&itv->decoding); + clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); + clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); + itv->output_mode = OUT_NONE; + if (atomic_read(&itv->capturing) == 0) + cx2341x_handler_set_busy(&itv->cxhdl, 0); + + return 0; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-streams.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-streams.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-streams.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-streams.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,37 @@ +/* + init/start/stop/exit stream functions + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_STREAMS_H +#define IVTV_STREAMS_H + +int ivtv_streams_setup(struct ivtv *itv); +int ivtv_streams_register(struct ivtv *itv); +void ivtv_streams_cleanup(struct ivtv *itv, int unregister); + +/* Capture related */ +int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s); +int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end); +int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset); +int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts); + +void ivtv_stop_all_captures(struct ivtv *itv); +int ivtv_passthrough_mode(struct ivtv *itv, int enable); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-udma.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-udma.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-udma.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-udma.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,234 @@ +/* + User DMA + + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-udma.h" + +void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size) +{ + dma_page->uaddr = first & PAGE_MASK; + dma_page->offset = first & ~PAGE_MASK; + dma_page->tail = 1 + ((first+size-1) & ~PAGE_MASK); + dma_page->first = (first & PAGE_MASK) >> PAGE_SHIFT; + dma_page->last = ((first+size-1) & PAGE_MASK) >> PAGE_SHIFT; + dma_page->page_count = dma_page->last - dma_page->first + 1; + if (dma_page->page_count == 1) dma_page->tail -= dma_page->offset; +} + +int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) +{ + int i, offset; + unsigned long flags; + + if (map_offset < 0) + return map_offset; + + offset = dma_page->offset; + + /* Fill SG Array with new values */ + for (i = 0; i < dma_page->page_count; i++) { + unsigned int len = (i == dma_page->page_count - 1) ? + dma_page->tail : PAGE_SIZE - offset; + + if (PageHighMem(dma->map[map_offset])) { + void *src; + + if (dma->bouncemap[map_offset] == NULL) + dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); + if (dma->bouncemap[map_offset] == NULL) + return -1; + local_irq_save(flags); + src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; + memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); + kunmap_atomic(src, KM_BOUNCE_READ); + local_irq_restore(flags); + sg_set_page(&dma->SGlist[map_offset], dma->bouncemap[map_offset], len, offset); + } + else { + sg_set_page(&dma->SGlist[map_offset], dma->map[map_offset], len, offset); + } + offset = 0; + map_offset++; + } + return map_offset; +} + +void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { + int i; + struct scatterlist *sg; + + for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg++) { + dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg)); + dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg)); + dma->SGarray[i].dst = cpu_to_le32(buffer_offset); + buffer_offset += sg_dma_len(sg); + + split -= sg_dma_len(sg); + if (split == 0) + buffer_offset = buffer_offset_2; + } +} + +/* User DMA Buffers */ +void ivtv_udma_alloc(struct ivtv *itv) +{ + if (itv->udma.SG_handle == 0) { + /* Map DMA Page Array Buffer */ + itv->udma.SG_handle = pci_map_single(itv->pdev, itv->udma.SGarray, + sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); + ivtv_udma_sync_for_cpu(itv); + } +} + +int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, + void __user *userbuf, int size_in_bytes) +{ + struct ivtv_dma_page_info user_dma; + struct ivtv_user_dma *dma = &itv->udma; + int i, err; + + IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); + + /* Still in USE */ + if (dma->SG_length || dma->page_count) { + IVTV_DEBUG_WARN("ivtv_udma_setup: SG_length %d page_count %d still full?\n", + dma->SG_length, dma->page_count); + return -EBUSY; + } + + ivtv_udma_get_page_info(&user_dma, (unsigned long)userbuf, size_in_bytes); + + if (user_dma.page_count <= 0) { + IVTV_DEBUG_WARN("ivtv_udma_setup: Error %d page_count from %d bytes %d offset\n", + user_dma.page_count, size_in_bytes, user_dma.offset); + return -EINVAL; + } + + /* Get user pages for DMA Xfer */ + down_read(¤t->mm->mmap_sem); + err = get_user_pages(current, current->mm, + user_dma.uaddr, user_dma.page_count, 0, 1, dma->map, NULL); + up_read(¤t->mm->mmap_sem); + + if (user_dma.page_count != err) { + IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", + err, user_dma.page_count); + if (err >= 0) { + for (i = 0; i < err; i++) + put_page(dma->map[i]); + return -EINVAL; + } + return err; + } + + dma->page_count = user_dma.page_count; + + /* Fill SG List with new values */ + if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) { + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return -ENOMEM; + } + + /* Map SG List */ + dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); + + /* Fill SG Array with new values */ + ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1); + + /* Tag SG Array with Interrupt Bit */ + dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); + + ivtv_udma_sync_for_device(itv); + return dma->page_count; +} + +void ivtv_udma_unmap(struct ivtv *itv) +{ + struct ivtv_user_dma *dma = &itv->udma; + int i; + + IVTV_DEBUG_INFO("ivtv_unmap_user_dma\n"); + + /* Nothing to free */ + if (dma->page_count == 0) + return; + + /* Unmap Scatterlist */ + if (dma->SG_length) { + pci_unmap_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); + dma->SG_length = 0; + } + /* sync DMA */ + ivtv_udma_sync_for_cpu(itv); + + /* Release User Pages */ + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; +} + +void ivtv_udma_free(struct ivtv *itv) +{ + int i; + + /* Unmap SG Array */ + if (itv->udma.SG_handle) { + pci_unmap_single(itv->pdev, itv->udma.SG_handle, + sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); + } + + /* Unmap Scatterlist */ + if (itv->udma.SG_length) { + pci_unmap_sg(itv->pdev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); + } + + for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) { + if (itv->udma.bouncemap[i]) + __free_page(itv->udma.bouncemap[i]); + } +} + +void ivtv_udma_start(struct ivtv *itv) +{ + IVTV_DEBUG_DMA("start UDMA\n"); + write_reg(itv->udma.SG_handle, IVTV_REG_DECDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); + set_bit(IVTV_F_I_DMA, &itv->i_flags); + set_bit(IVTV_F_I_UDMA, &itv->i_flags); + clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags); +} + +void ivtv_udma_prepare(struct ivtv *itv) +{ + unsigned long flags; + + spin_lock_irqsave(&itv->dma_reg_lock, flags); + if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) + ivtv_udma_start(itv); + else + set_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags); + spin_unlock_irqrestore(&itv->dma_reg_lock, flags); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-udma.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-udma.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-udma.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-udma.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,48 @@ +/* + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004 Chris Kennedy + Copyright (C) 2006-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_UDMA_H +#define IVTV_UDMA_H + +/* User DMA functions */ +void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size); +int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset); +void ivtv_udma_fill_sg_array(struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split); +int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, + void __user *userbuf, int size_in_bytes); +void ivtv_udma_unmap(struct ivtv *itv); +void ivtv_udma_free(struct ivtv *itv); +void ivtv_udma_alloc(struct ivtv *itv); +void ivtv_udma_prepare(struct ivtv *itv); +void ivtv_udma_start(struct ivtv *itv); + +static inline void ivtv_udma_sync_for_device(struct ivtv *itv) +{ + pci_dma_sync_single_for_device(itv->pdev, itv->udma.SG_handle, + sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); +} + +static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv) +{ + pci_dma_sync_single_for_cpu(itv->pdev, itv->udma.SG_handle, + sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); +} + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-vbi.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-vbi.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-vbi.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-vbi.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,549 @@ +/* + Vertical Blank Interval support functions + Copyright (C) 2004-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-i2c.h" +#include "ivtv-ioctl.h" +#include "ivtv-queue.h" +#include "ivtv-cards.h" +#include "ivtv-vbi.h" + +static void ivtv_set_vps(struct ivtv *itv, int enabled) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + data.id = V4L2_SLICED_VPS; + data.field = 0; + data.line = enabled ? 16 : 0; + data.data[2] = itv->vbi.vps_payload.data[0]; + data.data[8] = itv->vbi.vps_payload.data[1]; + data.data[9] = itv->vbi.vps_payload.data[2]; + data.data[10] = itv->vbi.vps_payload.data[3]; + data.data[11] = itv->vbi.vps_payload.data[4]; + ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data); +} + +static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + data.id = V4L2_SLICED_CAPTION_525; + data.field = 0; + data.line = (mode & 1) ? 21 : 0; + data.data[0] = cc->odd[0]; + data.data[1] = cc->odd[1]; + ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data); + data.field = 1; + data.line = (mode & 2) ? 21 : 0; + data.data[0] = cc->even[0]; + data.data[1] = cc->even[1]; + ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data); +} + +static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + /* When using a 50 Hz system, always turn on the + wide screen signal with 4x3 ratio as the default. + Turning this signal on and off can confuse certain + TVs. As far as I can tell there is no reason not to + transmit this signal. */ + if ((itv->std_out & V4L2_STD_625_50) && !enabled) { + enabled = 1; + mode = 0x08; /* 4x3 full format */ + } + data.id = V4L2_SLICED_WSS_625; + data.field = 0; + data.line = enabled ? 23 : 0; + data.data[0] = mode & 0xff; + data.data[1] = (mode >> 8) & 0xff; + ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data); +} + +static int odd_parity(u8 c) +{ + c ^= (c >> 4); + c ^= (c >> 2); + c ^= (c >> 1); + + return c & 1; +} + +static void ivtv_write_vbi_line(struct ivtv *itv, + const struct v4l2_sliced_vbi_data *d, + struct vbi_cc *cc, int *found_cc) +{ + struct vbi_info *vi = &itv->vbi; + + if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { + if (d->field) { + cc->even[0] = d->data[0]; + cc->even[1] = d->data[1]; + } else { + cc->odd[0] = d->data[0]; + cc->odd[1] = d->data[1]; + } + *found_cc = 1; + } else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { + struct vbi_vps vps; + + vps.data[0] = d->data[2]; + vps.data[1] = d->data[8]; + vps.data[2] = d->data[9]; + vps.data[3] = d->data[10]; + vps.data[4] = d->data[11]; + if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) { + vi->vps_payload = vps; + set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); + } + } else if (d->id == V4L2_SLICED_WSS_625 && + d->line == 23 && d->field == 0) { + int wss = d->data[0] | d->data[1] << 8; + + if (vi->wss_payload != wss) { + vi->wss_payload = wss; + set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); + } + } +} + +static void ivtv_write_vbi_cc_lines(struct ivtv *itv, const struct vbi_cc *cc) +{ + struct vbi_info *vi = &itv->vbi; + + if (vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) { + memcpy(&vi->cc_payload[vi->cc_payload_idx], cc, + sizeof(struct vbi_cc)); + vi->cc_payload_idx++; + set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); + } +} + +static void ivtv_write_vbi(struct ivtv *itv, + const struct v4l2_sliced_vbi_data *sliced, + size_t cnt) +{ + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; + int found_cc = 0; + size_t i; + + for (i = 0; i < cnt; i++) + ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc); + + if (found_cc) + ivtv_write_vbi_cc_lines(itv, &cc); +} + +ssize_t +ivtv_write_vbi_from_user(struct ivtv *itv, + const struct v4l2_sliced_vbi_data __user *sliced, + size_t cnt) +{ + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; + int found_cc = 0; + size_t i; + struct v4l2_sliced_vbi_data d; + ssize_t ret = cnt * sizeof(struct v4l2_sliced_vbi_data); + + for (i = 0; i < cnt; i++) { + if (copy_from_user(&d, sliced + i, + sizeof(struct v4l2_sliced_vbi_data))) { + ret = -EFAULT; + break; + } + ivtv_write_vbi_line(itv, &d, &cc, &found_cc); + } + + if (found_cc) + ivtv_write_vbi_cc_lines(itv, &cc); + + return ret; +} + +static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp) +{ + int line = 0; + int i; + u32 linemask[2] = { 0, 0 }; + unsigned short size; + static const u8 mpeg_hdr_data[] = { + 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, + 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, + 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, + 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff + }; + const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ + int idx = itv->vbi.frame % IVTV_VBI_FRAMES; + u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0]; + + for (i = 0; i < lines; i++) { + int f, l; + + if (itv->vbi.sliced_data[i].id == 0) + continue; + + l = itv->vbi.sliced_data[i].line - 6; + f = itv->vbi.sliced_data[i].field; + if (f) + l += 18; + if (l < 32) + linemask[0] |= (1 << l); + else + linemask[1] |= (1 << (l - 32)); + dst[sd + 12 + line * 43] = + ivtv_service2vbi(itv->vbi.sliced_data[i].id); + memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42); + line++; + } + memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); + if (line == 36) { + /* All lines are used, so there is no space for the linemask + (the max size of the VBI data is 36 * 43 + 4 bytes). + So in this case we use the magic number 'ITV0'. */ + memcpy(dst + sd, "ITV0", 4); + memcpy(dst + sd + 4, dst + sd + 12, line * 43); + size = 4 + ((43 * line + 3) & ~3); + } else { + memcpy(dst + sd, "itv0", 4); + cpu_to_le32s(&linemask[0]); + cpu_to_le32s(&linemask[1]); + memcpy(dst + sd + 4, &linemask[0], 8); + size = 12 + ((43 * line + 3) & ~3); + } + dst[4+16] = (size + 10) >> 8; + dst[5+16] = (size + 10) & 0xff; + dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); + dst[10+16] = (pts_stamp >> 22) & 0xff; + dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); + dst[12+16] = (pts_stamp >> 7) & 0xff; + dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); + itv->vbi.sliced_mpeg_size[idx] = sd + size; +} + +static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) +{ + u32 linemask[2]; + int i, l, id2; + int line = 0; + + if (!memcmp(p, "itv0", 4)) { + memcpy(linemask, p + 4, 8); + p += 12; + } else if (!memcmp(p, "ITV0", 4)) { + linemask[0] = 0xffffffff; + linemask[1] = 0xf; + p += 4; + } else { + /* unknown VBI data, convert to empty VBI frame */ + linemask[0] = linemask[1] = 0; + } + for (i = 0; i < 36; i++) { + int err = 0; + + if (i < 32 && !(linemask[0] & (1 << i))) + continue; + if (i >= 32 && !(linemask[1] & (1 << (i - 32)))) + continue; + id2 = *p & 0xf; + switch (id2) { + case IVTV_SLICED_TYPE_TELETEXT_B: + id2 = V4L2_SLICED_TELETEXT_B; + break; + case IVTV_SLICED_TYPE_CAPTION_525: + id2 = V4L2_SLICED_CAPTION_525; + err = !odd_parity(p[1]) || !odd_parity(p[2]); + break; + case IVTV_SLICED_TYPE_VPS: + id2 = V4L2_SLICED_VPS; + break; + case IVTV_SLICED_TYPE_WSS_625: + id2 = V4L2_SLICED_WSS_625; + break; + default: + id2 = 0; + break; + } + if (err == 0) { + l = (i < 18) ? i + 6 : i - 18 + 6; + itv->vbi.sliced_dec_data[line].line = l; + itv->vbi.sliced_dec_data[line].field = i >= 18; + itv->vbi.sliced_dec_data[line].id = id2; + memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42); + line++; + } + p += 43; + } + while (line < 36) { + itv->vbi.sliced_dec_data[line].id = 0; + itv->vbi.sliced_dec_data[line].line = 0; + itv->vbi.sliced_dec_data[line].field = 0; + line++; + } + return line * sizeof(itv->vbi.sliced_dec_data[0]); +} + +/* Compress raw VBI format, removes leading SAV codes and surplus space after the + field. + Returns new compressed size. */ +static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size) +{ + u32 line_size = itv->vbi.raw_decoder_line_size; + u32 lines = itv->vbi.count; + u8 sav1 = itv->vbi.raw_decoder_sav_odd_field; + u8 sav2 = itv->vbi.raw_decoder_sav_even_field; + u8 *q = buf; + u8 *p; + int i; + + for (i = 0; i < lines; i++) { + p = buf + i * line_size; + + /* Look for SAV code */ + if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) { + break; + } + memcpy(q, p + 4, line_size - 4); + q += line_size - 4; + } + return lines * (line_size - 4); +} + + +/* Compressed VBI format, all found sliced blocks put next to one another + Returns new compressed size */ +static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav) +{ + u32 line_size = itv->vbi.sliced_decoder_line_size; + struct v4l2_decode_vbi_line vbi; + int i; + unsigned lines = 0; + + /* find the first valid line */ + for (i = 0; i < size; i++, buf++) { + if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) + break; + } + + size -= i; + if (size < line_size) { + return line; + } + for (i = 0; i < size / line_size; i++) { + u8 *p = buf + i * line_size; + + /* Look for SAV code */ + if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) { + continue; + } + vbi.p = p + 4; + v4l2_subdev_call(itv->sd_video, vbi, decode_vbi_line, &vbi); + if (vbi.type && !(lines & (1 << vbi.line))) { + lines |= 1 << vbi.line; + itv->vbi.sliced_data[line].id = vbi.type; + itv->vbi.sliced_data[line].field = vbi.is_second_field; + itv->vbi.sliced_data[line].line = vbi.line; + memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42); + line++; + } + } + return line; +} + +void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, + u64 pts_stamp, int streamtype) +{ + u8 *p = (u8 *) buf->buf; + u32 size = buf->bytesused; + int y; + + /* Raw VBI data */ + if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && ivtv_raw_vbi(itv)) { + u8 type; + + ivtv_buf_swap(buf); + + type = p[3]; + + size = buf->bytesused = compress_raw_buf(itv, p, size); + + /* second field of the frame? */ + if (type == itv->vbi.raw_decoder_sav_even_field) { + /* Dirty hack needed for backwards + compatibility of old VBI software. */ + p += size - 4; + memcpy(p, &itv->vbi.frame, 4); + itv->vbi.frame++; + } + return; + } + + /* Sliced VBI data with data insertion */ + if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) { + int lines; + + ivtv_buf_swap(buf); + + /* first field */ + lines = compress_sliced_buf(itv, 0, p, size / 2, + itv->vbi.sliced_decoder_sav_odd_field); + /* second field */ + /* experimentation shows that the second half does not always begin + at the exact address. So start a bit earlier (hence 32). */ + lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32, + itv->vbi.sliced_decoder_sav_even_field); + /* always return at least one empty line */ + if (lines == 0) { + itv->vbi.sliced_data[0].id = 0; + itv->vbi.sliced_data[0].line = 0; + itv->vbi.sliced_data[0].field = 0; + lines = 1; + } + buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]); + memcpy(p, &itv->vbi.sliced_data[0], size); + + if (itv->vbi.insert_mpeg) { + copy_vbi_data(itv, lines, pts_stamp); + } + itv->vbi.frame++; + return; + } + + /* Sliced VBI re-inserted from an MPEG stream */ + if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { + /* If the size is not 4-byte aligned, then the starting address + for the swapping is also shifted. After swapping the data the + real start address of the VBI data is exactly 4 bytes after the + original start. It's a bit fiddly but it works like a charm. + Non-4-byte alignment happens when an lseek is done on the input + mpeg file to a non-4-byte aligned position. So on arrival here + the VBI data is also non-4-byte aligned. */ + int offset = size & 3; + int cnt; + + if (offset) { + p += 4 - offset; + } + /* Swap Buffer */ + for (y = 0; y < size; y += 4) { + swab32s((u32 *)(p + y)); + } + + cnt = ivtv_convert_ivtv_vbi(itv, p + offset); + memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); + buf->bytesused = cnt; + + ivtv_write_vbi(itv, itv->vbi.sliced_dec_data, + cnt / sizeof(itv->vbi.sliced_dec_data[0])); + return; + } +} + +void ivtv_disable_cc(struct ivtv *itv) +{ + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; + + clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); + ivtv_set_cc(itv, 0, &cc); + itv->vbi.cc_payload_idx = 0; +} + + +void ivtv_vbi_work_handler(struct ivtv *itv) +{ + struct vbi_info *vi = &itv->vbi; + struct v4l2_sliced_vbi_data data; + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; + + /* Lock */ + if (itv->output_mode == OUT_PASSTHROUGH) { + if (itv->is_50hz) { + data.id = V4L2_SLICED_WSS_625; + data.field = 0; + + if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) { + ivtv_set_wss(itv, 1, data.data[0] & 0xf); + vi->wss_missing_cnt = 0; + } else if (vi->wss_missing_cnt == 4) { + ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ + } else { + vi->wss_missing_cnt++; + } + } + else { + int mode = 0; + + data.id = V4L2_SLICED_CAPTION_525; + data.field = 0; + if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) { + mode |= 1; + cc.odd[0] = data.data[0]; + cc.odd[1] = data.data[1]; + } + data.field = 1; + if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) { + mode |= 2; + cc.even[0] = data.data[0]; + cc.even[1] = data.data[1]; + } + if (mode) { + vi->cc_missing_cnt = 0; + ivtv_set_cc(itv, mode, &cc); + } else if (vi->cc_missing_cnt == 4) { + ivtv_set_cc(itv, 0, &cc); + } else { + vi->cc_missing_cnt++; + } + } + return; + } + + if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { + ivtv_set_wss(itv, 1, vi->wss_payload & 0xf); + } + + if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { + if (vi->cc_payload_idx == 0) { + clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); + ivtv_set_cc(itv, 3, &cc); + } + while (vi->cc_payload_idx) { + cc = vi->cc_payload[0]; + + memcpy(vi->cc_payload, vi->cc_payload + 1, + sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0])); + vi->cc_payload_idx--; + if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80) + continue; + + ivtv_set_cc(itv, 3, &cc); + break; + } + } + + if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { + ivtv_set_vps(itv, 1); + } +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-vbi.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-vbi.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-vbi.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-vbi.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,34 @@ +/* + Vertical Blank Interval support functions + Copyright (C) 2004-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_VBI_H +#define IVTV_VBI_H + +ssize_t +ivtv_write_vbi_from_user(struct ivtv *itv, + const struct v4l2_sliced_vbi_data __user *sliced, + size_t count); +void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, + u64 pts_stamp, int streamtype); +int ivtv_used_line(struct ivtv *itv, int line, int field); +void ivtv_disable_cc(struct ivtv *itv); +void ivtv_set_vbi(unsigned long arg); +void ivtv_vbi_work_handler(struct ivtv *itv); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-version.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-version.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-version.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-version.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,31 @@ +/* + ivtv driver version information + Copyright (C) 2005-2007 Hans Verkuil + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_VERSION_H +#define IVTV_VERSION_H + +#define IVTV_DRIVER_NAME "ivtv" +#define IVTV_DRIVER_VERSION_MAJOR 1 +#define IVTV_DRIVER_VERSION_MINOR 4 +#define IVTV_DRIVER_VERSION_PATCHLEVEL 2 + +#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) +#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-yuv.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-yuv.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-yuv.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-yuv.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1280 @@ +/* + yuv support + + Copyright (C) 2007 Ian Armstrong + + 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, or + (at your option) any later version. + + 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 "ivtv-driver.h" +#include "ivtv-udma.h" +#include "ivtv-yuv.h" + +/* YUV buffer offsets */ +const u32 yuv_offset[IVTV_YUV_BUFFERS] = { + 0x001a8600, + 0x00240400, + 0x002d8200, + 0x00370000, + 0x00029000, + 0x000C0E00, + 0x006B0400, + 0x00748200 +}; + +static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, + struct ivtv_dma_frame *args) +{ + struct ivtv_dma_page_info y_dma; + struct ivtv_dma_page_info uv_dma; + struct yuv_playback_info *yi = &itv->yuv_info; + u8 frame = yi->draw_frame; + struct yuv_frame_info *f = &yi->new_frame_info[frame]; + int i; + int y_pages, uv_pages; + unsigned long y_buffer_offset, uv_buffer_offset; + int y_decode_height, uv_decode_height, y_size; + + y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; + uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; + + y_decode_height = uv_decode_height = f->src_h + f->src_y; + + if (f->offset_y) + y_buffer_offset += 720 * 16; + + if (y_decode_height & 15) + y_decode_height = (y_decode_height + 16) & ~15; + + if (uv_decode_height & 31) + uv_decode_height = (uv_decode_height + 32) & ~31; + + y_size = 720 * y_decode_height; + + /* Still in USE */ + if (dma->SG_length || dma->page_count) { + IVTV_DEBUG_WARN + ("prep_user_dma: SG_length %d page_count %d still full?\n", + dma->SG_length, dma->page_count); + return -EBUSY; + } + + ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height); + ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height); + + /* Get user pages for DMA Xfer */ + down_read(¤t->mm->mmap_sem); + y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL); + uv_pages = 0; /* silence gcc. value is set and consumed only if: */ + if (y_pages == y_dma.page_count) { + uv_pages = get_user_pages(current, current->mm, + uv_dma.uaddr, uv_dma.page_count, 0, 1, + &dma->map[y_pages], NULL); + } + up_read(¤t->mm->mmap_sem); + + if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) { + int rc = -EFAULT; + + if (y_pages == y_dma.page_count) { + IVTV_DEBUG_WARN + ("failed to map uv user pages, returned %d " + "expecting %d\n", uv_pages, uv_dma.page_count); + + if (uv_pages >= 0) { + for (i = 0; i < uv_pages; i++) + put_page(dma->map[y_pages + i]); + rc = -EFAULT; + } else { + rc = uv_pages; + } + } else { + IVTV_DEBUG_WARN + ("failed to map y user pages, returned %d " + "expecting %d\n", y_pages, y_dma.page_count); + } + if (y_pages >= 0) { + for (i = 0; i < y_pages; i++) + put_page(dma->map[i]); + /* + * Inherit the -EFAULT from rc's + * initialization, but allow it to be + * overriden by uv_pages above if it was an + * actual errno. + */ + } else { + rc = y_pages; + } + return rc; + } + + dma->page_count = y_pages + uv_pages; + + /* Fill & map SG List */ + if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) { + IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return -ENOMEM; + } + dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); + + /* Fill SG Array with new values */ + ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); + + /* If we've offset the y plane, ensure top area is blanked */ + if (f->offset_y && yi->blanking_dmaptr) { + dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); + dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr); + dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); + dma->SG_length++; + } + + /* Tag SG Array with Interrupt Bit */ + dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); + + ivtv_udma_sync_for_device(itv); + return 0; +} + +/* We rely on a table held in the firmware - Quick check. */ +int ivtv_yuv_filter_check(struct ivtv *itv) +{ + int i, y, uv; + + for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) { + if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) || + (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) { + IVTV_WARN ("YUV filter table not found in firmware.\n"); + return -1; + } + } + return 0; +} + +static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2) +{ + u32 i, line; + + /* If any filter is -1, then don't update it */ + if (h_filter > -1) { + if (h_filter > 4) + h_filter = 4; + i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384); + for (line = 0; line < 16; line++) { + write_reg(read_dec(i), 0x02804); + write_reg(read_dec(i), 0x0281c); + i += 4; + write_reg(read_dec(i), 0x02808); + write_reg(read_dec(i), 0x02820); + i += 4; + write_reg(read_dec(i), 0x0280c); + write_reg(read_dec(i), 0x02824); + i += 4; + write_reg(read_dec(i), 0x02810); + write_reg(read_dec(i), 0x02828); + i += 4; + write_reg(read_dec(i), 0x02814); + write_reg(read_dec(i), 0x0282c); + i += 8; + write_reg(0, 0x02818); + write_reg(0, 0x02830); + } + IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter); + } + + if (v_filter_1 > -1) { + if (v_filter_1 > 4) + v_filter_1 = 4; + i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192); + for (line = 0; line < 16; line++) { + write_reg(read_dec(i), 0x02900); + i += 4; + write_reg(read_dec(i), 0x02904); + i += 8; + write_reg(0, 0x02908); + } + IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1); + } + + if (v_filter_2 > -1) { + if (v_filter_2 > 4) + v_filter_2 = 4; + i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192); + for (line = 0; line < 16; line++) { + write_reg(read_dec(i), 0x0290c); + i += 4; + write_reg(read_dec(i), 0x02910); + i += 8; + write_reg(0, 0x02914); + } + IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2); + } +} + +static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + u32 reg_2834, reg_2838, reg_283c; + u32 reg_2844, reg_2854, reg_285c; + u32 reg_2864, reg_2874, reg_2890; + u32 reg_2870, reg_2870_base, reg_2870_offset; + int x_cutoff; + int h_filter; + u32 master_width; + + IVTV_DEBUG_WARN + ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", + f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x); + + /* How wide is the src image */ + x_cutoff = f->src_w + f->src_x; + + /* Set the display width */ + reg_2834 = f->dst_w; + reg_2838 = reg_2834; + + /* Set the display position */ + reg_2890 = f->dst_x; + + /* Index into the image horizontally */ + reg_2870 = 0; + + /* 2870 is normally fudged to align video coords with osd coords. + If running full screen, it causes an unwanted left shift + Remove the fudge if we almost fill the screen. + Gradually adjust the offset to avoid the video 'snapping' + left/right if it gets dragged through this region. + Only do this if osd is full width. */ + if (f->vis_w == 720) { + if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680)) + reg_2870 = 10 - (f->tru_x - f->pan_x) / 4; + else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660)) + reg_2870 = (10 + (f->tru_x - f->pan_x) / 2); + + if (f->dst_w >= f->src_w) + reg_2870 = reg_2870 << 16 | reg_2870; + else + reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1); + } + + if (f->dst_w < f->src_w) + reg_2870 = 0x000d000e - reg_2870; + else + reg_2870 = 0x0012000e - reg_2870; + + /* We're also using 2870 to shift the image left (src_x & negative dst_x) */ + reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19; + + if (f->dst_w >= f->src_w) { + x_cutoff &= ~1; + master_width = (f->src_w * 0x00200000) / (f->dst_w); + if (master_width * f->dst_w != f->src_w * 0x00200000) + master_width++; + reg_2834 = (reg_2834 << 16) | x_cutoff; + reg_2838 = (reg_2838 << 16) | x_cutoff; + reg_283c = master_width >> 2; + reg_2844 = master_width >> 2; + reg_2854 = master_width; + reg_285c = master_width >> 1; + reg_2864 = master_width >> 1; + + /* We also need to factor in the scaling + (src_w - dst_w) / (src_w / 4) */ + if (f->dst_w > f->src_w) + reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14); + else + reg_2870_base = 0; + + reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base); + reg_2874 = 0; + } else if (f->dst_w < f->src_w / 2) { + master_width = (f->src_w * 0x00080000) / f->dst_w; + if (master_width * f->dst_w != f->src_w * 0x00080000) + master_width++; + reg_2834 = (reg_2834 << 16) | x_cutoff; + reg_2838 = (reg_2838 << 16) | x_cutoff; + reg_283c = master_width >> 2; + reg_2844 = master_width >> 1; + reg_2854 = master_width; + reg_285c = master_width >> 1; + reg_2864 = master_width >> 1; + reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset; + reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16; + reg_2874 = 0x00000012; + } else { + master_width = (f->src_w * 0x00100000) / f->dst_w; + if (master_width * f->dst_w != f->src_w * 0x00100000) + master_width++; + reg_2834 = (reg_2834 << 16) | x_cutoff; + reg_2838 = (reg_2838 << 16) | x_cutoff; + reg_283c = master_width >> 2; + reg_2844 = master_width >> 1; + reg_2854 = master_width; + reg_285c = master_width >> 1; + reg_2864 = master_width >> 1; + reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1; + reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16; + reg_2874 = 0x00000001; + } + + /* Select the horizontal filter */ + if (f->src_w == f->dst_w) { + /* An exact size match uses filter 0 */ + h_filter = 0; + } else { + /* Figure out which filter to use */ + h_filter = ((f->src_w << 16) / f->dst_w) >> 15; + h_filter = (h_filter >> 1) + (h_filter & 1); + /* Only an exact size match can use filter 0 */ + h_filter += !h_filter; + } + + write_reg(reg_2834, 0x02834); + write_reg(reg_2838, 0x02838); + IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n", + yi->reg_2834, reg_2834, yi->reg_2838, reg_2838); + + write_reg(reg_283c, 0x0283c); + write_reg(reg_2844, 0x02844); + + IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n", + yi->reg_283c, reg_283c, yi->reg_2844, reg_2844); + + write_reg(0x00080514, 0x02840); + write_reg(0x00100514, 0x02848); + IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n", + yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514); + + write_reg(reg_2854, 0x02854); + IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n", + yi->reg_2854, reg_2854); + + write_reg(reg_285c, 0x0285c); + write_reg(reg_2864, 0x02864); + IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n", + yi->reg_285c, reg_285c, yi->reg_2864, reg_2864); + + write_reg(reg_2874, 0x02874); + IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n", + yi->reg_2874, reg_2874); + + write_reg(reg_2870, 0x02870); + IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n", + yi->reg_2870, reg_2870); + + write_reg(reg_2890, 0x02890); + IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n", + yi->reg_2890, reg_2890); + + /* Only update the filter if we really need to */ + if (h_filter != yi->h_filter) { + ivtv_yuv_filter(itv, h_filter, -1, -1); + yi->h_filter = h_filter; + } +} + +static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + u32 master_height; + u32 reg_2918, reg_291c, reg_2920, reg_2928; + u32 reg_2930, reg_2934, reg_293c; + u32 reg_2940, reg_2944, reg_294c; + u32 reg_2950, reg_2954, reg_2958, reg_295c; + u32 reg_2960, reg_2964, reg_2968, reg_296c; + u32 reg_289c; + u32 src_major_y, src_minor_y; + u32 src_major_uv, src_minor_uv; + u32 reg_2964_base, reg_2968_base; + int v_filter_1, v_filter_2; + + IVTV_DEBUG_WARN + ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", + f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y); + + /* What scaling mode is being used... */ + IVTV_DEBUG_YUV("Scaling mode Y: %s\n", + f->interlaced_y ? "Interlaced" : "Progressive"); + + IVTV_DEBUG_YUV("Scaling mode UV: %s\n", + f->interlaced_uv ? "Interlaced" : "Progressive"); + + /* What is the source video being treated as... */ + IVTV_DEBUG_WARN("Source video: %s\n", + f->interlaced ? "Interlaced" : "Progressive"); + + /* We offset into the image using two different index methods, so split + the y source coord into two parts. */ + if (f->src_y < 8) { + src_minor_uv = f->src_y; + src_major_uv = 0; + } else { + src_minor_uv = 8; + src_major_uv = f->src_y - 8; + } + + src_minor_y = src_minor_uv; + src_major_y = src_major_uv; + + if (f->offset_y) + src_minor_y += 16; + + if (f->interlaced_y) + reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y); + else + reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1); + + if (f->interlaced_uv) + reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1); + else + reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv); + + reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14; + reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14; + + if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) { + master_height = (f->src_h * 0x00400000) / f->dst_h; + if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2) + master_height++; + reg_2920 = master_height >> 2; + reg_2928 = master_height >> 3; + reg_2930 = master_height; + reg_2940 = master_height >> 1; + reg_2964_base >>= 3; + reg_2968_base >>= 3; + reg_296c = 0x00000000; + } else if (f->dst_h >= f->src_h) { + master_height = (f->src_h * 0x00400000) / f->dst_h; + master_height = (master_height >> 1) + (master_height & 1); + reg_2920 = master_height >> 2; + reg_2928 = master_height >> 2; + reg_2930 = master_height; + reg_2940 = master_height >> 1; + reg_296c = 0x00000000; + if (f->interlaced_y) { + reg_2964_base >>= 3; + } else { + reg_296c++; + reg_2964_base >>= 2; + } + if (f->interlaced_uv) + reg_2928 >>= 1; + reg_2968_base >>= 3; + } else if (f->dst_h >= f->src_h / 2) { + master_height = (f->src_h * 0x00200000) / f->dst_h; + master_height = (master_height >> 1) + (master_height & 1); + reg_2920 = master_height >> 2; + reg_2928 = master_height >> 2; + reg_2930 = master_height; + reg_2940 = master_height; + reg_296c = 0x00000101; + if (f->interlaced_y) { + reg_2964_base >>= 2; + } else { + reg_296c++; + reg_2964_base >>= 1; + } + if (f->interlaced_uv) + reg_2928 >>= 1; + reg_2968_base >>= 2; + } else { + master_height = (f->src_h * 0x00100000) / f->dst_h; + master_height = (master_height >> 1) + (master_height & 1); + reg_2920 = master_height >> 2; + reg_2928 = master_height >> 2; + reg_2930 = master_height; + reg_2940 = master_height; + reg_2964_base >>= 1; + reg_2968_base >>= 2; + reg_296c = 0x00000102; + } + + /* FIXME These registers change depending on scaled / unscaled output + We really need to work out what they should be */ + if (f->src_h == f->dst_h) { + reg_2934 = 0x00020000; + reg_293c = 0x00100000; + reg_2944 = 0x00040000; + reg_294c = 0x000b0000; + } else { + reg_2934 = 0x00000FF0; + reg_293c = 0x00000FF0; + reg_2944 = 0x00000FF0; + reg_294c = 0x00000FF0; + } + + /* The first line to be displayed */ + reg_2950 = 0x00010000 + src_major_y; + if (f->interlaced_y) + reg_2950 += 0x00010000; + reg_2954 = reg_2950 + 1; + + reg_2958 = 0x00010000 + (src_major_y >> 1); + if (f->interlaced_uv) + reg_2958 += 0x00010000; + reg_295c = reg_2958 + 1; + + if (yi->decode_height == 480) + reg_289c = 0x011e0017; + else + reg_289c = 0x01500017; + + if (f->dst_y < 0) + reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1); + else + reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1); + + /* How much of the source to decode. + Take into account the source offset */ + reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) | + (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15); + + /* Calculate correct value for register 2964 */ + if (f->src_h == f->dst_h) { + reg_2964 = 1; + } else { + reg_2964 = 2 + ((f->dst_h << 1) / f->src_h); + reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1); + } + reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1); + reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94); + + /* Okay, we've wasted time working out the correct value, + but if we use it, it fouls the the window alignment. + Fudge it to what we want... */ + reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16)); + reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16)); + + /* Deviate further from what it should be. I find the flicker headache + inducing so try to reduce it slightly. Leave 2968 as-is otherwise + colours foul. */ + if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h)) + reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2); + + if (!f->interlaced_y) + reg_2964 -= 0x00010001; + if (!f->interlaced_uv) + reg_2968 -= 0x00010001; + + reg_2964 += ((reg_2964_base << 16) | reg_2964_base); + reg_2968 += ((reg_2968_base << 16) | reg_2968_base); + + /* Select the vertical filter */ + if (f->src_h == f->dst_h) { + /* An exact size match uses filter 0/1 */ + v_filter_1 = 0; + v_filter_2 = 1; + } else { + /* Figure out which filter to use */ + v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15; + v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); + /* Only an exact size match can use filter 0 */ + v_filter_1 += !v_filter_1; + v_filter_2 = v_filter_1; + } + + write_reg(reg_2934, 0x02934); + write_reg(reg_293c, 0x0293c); + IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n", + yi->reg_2934, reg_2934, yi->reg_293c, reg_293c); + write_reg(reg_2944, 0x02944); + write_reg(reg_294c, 0x0294c); + IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n", + yi->reg_2944, reg_2944, yi->reg_294c, reg_294c); + + /* Ensure 2970 is 0 (does it ever change ?) */ +/* write_reg(0,0x02970); */ +/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */ + + write_reg(reg_2930, 0x02938); + write_reg(reg_2930, 0x02930); + IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n", + yi->reg_2930, reg_2930, yi->reg_2938, reg_2930); + + write_reg(reg_2928, 0x02928); + write_reg(reg_2928 + 0x514, 0x0292C); + IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n", + yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514); + + write_reg(reg_2920, 0x02920); + write_reg(reg_2920 + 0x514, 0x02924); + IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n", + yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514); + + write_reg(reg_2918, 0x02918); + write_reg(reg_291c, 0x0291C); + IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n", + yi->reg_2918, reg_2918, yi->reg_291c, reg_291c); + + write_reg(reg_296c, 0x0296c); + IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n", + yi->reg_296c, reg_296c); + + write_reg(reg_2940, 0x02948); + write_reg(reg_2940, 0x02940); + IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n", + yi->reg_2940, reg_2940, yi->reg_2948, reg_2940); + + write_reg(reg_2950, 0x02950); + write_reg(reg_2954, 0x02954); + IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n", + yi->reg_2950, reg_2950, yi->reg_2954, reg_2954); + + write_reg(reg_2958, 0x02958); + write_reg(reg_295c, 0x0295C); + IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n", + yi->reg_2958, reg_2958, yi->reg_295c, reg_295c); + + write_reg(reg_2960, 0x02960); + IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n", + yi->reg_2960, reg_2960); + + write_reg(reg_2964, 0x02964); + write_reg(reg_2968, 0x02968); + IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n", + yi->reg_2964, reg_2964, yi->reg_2968, reg_2968); + + write_reg(reg_289c, 0x0289c); + IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n", + yi->reg_289c, reg_289c); + + /* Only update filter 1 if we really need to */ + if (v_filter_1 != yi->v_filter_1) { + ivtv_yuv_filter(itv, -1, v_filter_1, -1); + yi->v_filter_1 = v_filter_1; + } + + /* Only update filter 2 if we really need to */ + if (v_filter_2 != yi->v_filter_2) { + ivtv_yuv_filter(itv, -1, -1, v_filter_2); + yi->v_filter_2 = v_filter_2; + } +} + +/* Modify the supplied coordinate information to fit the visible osd area */ +static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) +{ + struct yuv_frame_info *of = &itv->yuv_info.old_frame_info; + int osd_crop; + u32 osd_scale; + u32 yuv_update = 0; + + /* Sorry, but no negative coords for src */ + if (f->src_x < 0) + f->src_x = 0; + if (f->src_y < 0) + f->src_y = 0; + + /* Can only reduce width down to 1/4 original size */ + if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) { + f->src_x += osd_crop / 2; + f->src_w = (f->src_w - osd_crop) & ~3; + f->dst_w = f->src_w / 4; + f->dst_w += f->dst_w & 1; + } + + /* Can only reduce height down to 1/4 original size */ + if (f->src_h / f->dst_h >= 2) { + /* Overflow may be because we're running progressive, + so force mode switch */ + f->interlaced_y = 1; + /* Make sure we're still within limits for interlace */ + if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) { + /* If we reach here we'll have to force the height. */ + f->src_y += osd_crop / 2; + f->src_h = (f->src_h - osd_crop) & ~3; + f->dst_h = f->src_h / 4; + f->dst_h += f->dst_h & 1; + } + } + + /* If there's nothing to safe to display, we may as well stop now */ + if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || + (int)f->src_w <= 2 || (int)f->src_h <= 2) { + return IVTV_YUV_UPDATE_INVALID; + } + + /* Ensure video remains inside OSD area */ + osd_scale = (f->src_h << 16) / f->dst_h; + + if ((osd_crop = f->pan_y - f->dst_y) > 0) { + /* Falls off the upper edge - crop */ + f->src_y += (osd_scale * osd_crop) >> 16; + f->src_h -= (osd_scale * osd_crop) >> 16; + f->dst_h -= osd_crop; + f->dst_y = 0; + } else { + f->dst_y -= f->pan_y; + } + + if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) { + /* Falls off the lower edge - crop */ + f->dst_h -= osd_crop; + f->src_h -= (osd_scale * osd_crop) >> 16; + } + + osd_scale = (f->src_w << 16) / f->dst_w; + + if ((osd_crop = f->pan_x - f->dst_x) > 0) { + /* Fall off the left edge - crop */ + f->src_x += (osd_scale * osd_crop) >> 16; + f->src_w -= (osd_scale * osd_crop) >> 16; + f->dst_w -= osd_crop; + f->dst_x = 0; + } else { + f->dst_x -= f->pan_x; + } + + if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) { + /* Falls off the right edge - crop */ + f->dst_w -= osd_crop; + f->src_w -= (osd_scale * osd_crop) >> 16; + } + + if (itv->yuv_info.track_osd) { + /* The OSD can be moved. Track to it */ + f->dst_x += itv->yuv_info.osd_x_offset; + f->dst_y += itv->yuv_info.osd_y_offset; + } + + /* Width & height for both src & dst must be even. + Same for coordinates. */ + f->dst_w &= ~1; + f->dst_x &= ~1; + + f->src_w += f->src_x & 1; + f->src_x &= ~1; + + f->src_w &= ~1; + f->dst_w &= ~1; + + f->dst_h &= ~1; + f->dst_y &= ~1; + + f->src_h += f->src_y & 1; + f->src_y &= ~1; + + f->src_h &= ~1; + f->dst_h &= ~1; + + /* Due to rounding, we may have reduced the output size to <1/4 of + the source. Check again, but this time just resize. Don't change + source coordinates */ + if (f->dst_w < f->src_w / 4) { + f->src_w &= ~3; + f->dst_w = f->src_w / 4; + f->dst_w += f->dst_w & 1; + } + if (f->dst_h < f->src_h / 4) { + f->src_h &= ~3; + f->dst_h = f->src_h / 4; + f->dst_h += f->dst_h & 1; + } + + /* Check again. If there's nothing to safe to display, stop now */ + if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || + (int)f->src_w <= 2 || (int)f->src_h <= 2) { + return IVTV_YUV_UPDATE_INVALID; + } + + /* Both x offset & width are linked, so they have to be done together */ + if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) || + (of->dst_x != f->dst_x) || (of->src_x != f->src_x) || + (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) { + yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; + } + + if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) || + (of->dst_y != f->dst_y) || (of->src_y != f->src_y) || + (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) || + (of->lace_mode != f->lace_mode) || + (of->interlaced_y != f->interlaced_y) || + (of->interlaced_uv != f->interlaced_uv)) { + yuv_update |= IVTV_YUV_UPDATE_VERTICAL; + } + + return yuv_update; +} + +/* Update the scaling register to the requested value */ +void ivtv_yuv_work_handler(struct ivtv *itv) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + struct yuv_frame_info f; + int frame = yi->update_frame; + u32 yuv_update; + + IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame); + f = yi->new_frame_info[frame]; + + if (yi->track_osd) { + /* Snapshot the osd pan info */ + f.pan_x = yi->osd_x_pan; + f.pan_y = yi->osd_y_pan; + f.vis_w = yi->osd_vis_w; + f.vis_h = yi->osd_vis_h; + } else { + /* Not tracking the osd, so assume full screen */ + f.pan_x = 0; + f.pan_y = 0; + f.vis_w = 720; + f.vis_h = yi->decode_height; + } + + /* Calculate the display window coordinates. Exit if nothing left */ + if (!(yuv_update = ivtv_yuv_window_setup(itv, &f))) + return; + + if (yuv_update & IVTV_YUV_UPDATE_INVALID) { + write_reg(0x01008080, 0x2898); + } else if (yuv_update) { + write_reg(0x00108080, 0x2898); + + if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) + ivtv_yuv_handle_horizontal(itv, &f); + + if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) + ivtv_yuv_handle_vertical(itv, &f); + } + yi->old_frame_info = f; +} + +static void ivtv_yuv_init(struct ivtv *itv) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + + IVTV_DEBUG_YUV("ivtv_yuv_init\n"); + + /* Take a snapshot of the current register settings */ + yi->reg_2834 = read_reg(0x02834); + yi->reg_2838 = read_reg(0x02838); + yi->reg_283c = read_reg(0x0283c); + yi->reg_2840 = read_reg(0x02840); + yi->reg_2844 = read_reg(0x02844); + yi->reg_2848 = read_reg(0x02848); + yi->reg_2854 = read_reg(0x02854); + yi->reg_285c = read_reg(0x0285c); + yi->reg_2864 = read_reg(0x02864); + yi->reg_2870 = read_reg(0x02870); + yi->reg_2874 = read_reg(0x02874); + yi->reg_2898 = read_reg(0x02898); + yi->reg_2890 = read_reg(0x02890); + + yi->reg_289c = read_reg(0x0289c); + yi->reg_2918 = read_reg(0x02918); + yi->reg_291c = read_reg(0x0291c); + yi->reg_2920 = read_reg(0x02920); + yi->reg_2924 = read_reg(0x02924); + yi->reg_2928 = read_reg(0x02928); + yi->reg_292c = read_reg(0x0292c); + yi->reg_2930 = read_reg(0x02930); + yi->reg_2934 = read_reg(0x02934); + yi->reg_2938 = read_reg(0x02938); + yi->reg_293c = read_reg(0x0293c); + yi->reg_2940 = read_reg(0x02940); + yi->reg_2944 = read_reg(0x02944); + yi->reg_2948 = read_reg(0x02948); + yi->reg_294c = read_reg(0x0294c); + yi->reg_2950 = read_reg(0x02950); + yi->reg_2954 = read_reg(0x02954); + yi->reg_2958 = read_reg(0x02958); + yi->reg_295c = read_reg(0x0295c); + yi->reg_2960 = read_reg(0x02960); + yi->reg_2964 = read_reg(0x02964); + yi->reg_2968 = read_reg(0x02968); + yi->reg_296c = read_reg(0x0296c); + yi->reg_2970 = read_reg(0x02970); + + yi->v_filter_1 = -1; + yi->v_filter_2 = -1; + yi->h_filter = -1; + + /* Set some valid size info */ + yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF; + yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF; + + /* Bit 2 of reg 2878 indicates current decoder output format + 0 : NTSC 1 : PAL */ + if (read_reg(0x2878) & 4) + yi->decode_height = 576; + else + yi->decode_height = 480; + + if (!itv->osd_info) { + yi->osd_vis_w = 720 - yi->osd_x_offset; + yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; + } else { + /* If no visible size set, assume full size */ + if (!yi->osd_vis_w) + yi->osd_vis_w = 720 - yi->osd_x_offset; + + if (!yi->osd_vis_h) { + yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; + } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { + /* If output video standard has changed, requested height may + not be legal */ + IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", + yi->osd_vis_h + yi->osd_y_offset, + yi->decode_height); + yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; + } + } + + /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ + yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN); + if (yi->blanking_ptr) { + yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); + } else { + yi->blanking_dmaptr = 0; + IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); + } + + /* Enable YUV decoder output */ + write_reg_sync(0x01, IVTV_REG_VDM); + + set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); + atomic_set(&yi->next_dma_frame, 0); +} + +/* Get next available yuv buffer on PVR350 */ +static void ivtv_yuv_next_free(struct ivtv *itv) +{ + int draw, display; + struct yuv_playback_info *yi = &itv->yuv_info; + + if (atomic_read(&yi->next_dma_frame) == -1) + ivtv_yuv_init(itv); + + draw = atomic_read(&yi->next_fill_frame); + display = atomic_read(&yi->next_dma_frame); + + if (display > draw) + display -= IVTV_YUV_BUFFERS; + + if (draw - display >= yi->max_frames_buffered) + draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS; + else + yi->new_frame_info[draw].update = 0; + + yi->draw_frame = draw; +} + +/* Set up frame according to ivtv_dma_frame parameters */ +static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + u8 frame = yi->draw_frame; + u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS; + struct yuv_frame_info *nf = &yi->new_frame_info[frame]; + struct yuv_frame_info *of = &yi->new_frame_info[last_frame]; + int lace_threshold = yi->lace_threshold; + + /* Preserve old update flag in case we're overwriting a queued frame */ + int update = nf->update; + + /* Take a snapshot of the yuv coordinate information */ + nf->src_x = args->src.left; + nf->src_y = args->src.top; + nf->src_w = args->src.width; + nf->src_h = args->src.height; + nf->dst_x = args->dst.left; + nf->dst_y = args->dst.top; + nf->dst_w = args->dst.width; + nf->dst_h = args->dst.height; + nf->tru_x = args->dst.left; + nf->tru_w = args->src_width; + nf->tru_h = args->src_height; + + /* Are we going to offset the Y plane */ + nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0; + + nf->update = 0; + nf->interlaced_y = 0; + nf->interlaced_uv = 0; + nf->delay = 0; + nf->sync_field = 0; + nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK; + + if (lace_threshold < 0) + lace_threshold = yi->decode_height - 1; + + /* Work out the lace settings */ + switch (nf->lace_mode) { + case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ + nf->interlaced = 0; + if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021)) + nf->interlaced_y = 0; + else + nf->interlaced_y = 1; + + if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) + nf->interlaced_uv = 0; + else + nf->interlaced_uv = 1; + break; + + case IVTV_YUV_MODE_AUTO: + if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) { + nf->interlaced = 0; + if ((nf->tru_h < 512) || + (nf->tru_h > 576 && nf->tru_h < 1021) || + (nf->tru_w > 720 && nf->tru_h < 1021)) + nf->interlaced_y = 0; + else + nf->interlaced_y = 1; + if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) + nf->interlaced_uv = 0; + else + nf->interlaced_uv = 1; + } else { + nf->interlaced = 1; + nf->interlaced_y = 1; + nf->interlaced_uv = 1; + } + break; + + case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ + default: + nf->interlaced = 1; + nf->interlaced_y = 1; + nf->interlaced_uv = 1; + break; + } + + if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) { + yi->old_frame_info_args = *nf; + nf->update = 1; + IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame); + } + + nf->update |= update; + nf->sync_field = yi->lace_sync_field; + nf->delay = nf->sync_field != of->sync_field; +} + +/* Frame is complete & ready for display */ +void ivtv_yuv_frame_complete(struct ivtv *itv) +{ + atomic_set(&itv->yuv_info.next_fill_frame, + (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS); +} + +static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +{ + DEFINE_WAIT(wait); + int rc = 0; + int got_sig = 0; + /* DMA the frame */ + mutex_lock(&itv->udma.lock); + + if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) { + mutex_unlock(&itv->udma.lock); + return rc; + } + + ivtv_udma_prepare(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + /* if no UDMA is pending and no UDMA is in progress, then the DMA + is finished */ + while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) || + test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + /* don't interrupt if the DMA is in progress but break off + a still pending DMA. */ + got_sig = signal_pending(current); + if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) + break; + got_sig = 0; + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + + /* Unmap Last DMA Xfer */ + ivtv_udma_unmap(itv); + + if (got_sig) { + IVTV_DEBUG_INFO("User stopped YUV UDMA\n"); + mutex_unlock(&itv->udma.lock); + return -EINTR; + } + + ivtv_yuv_frame_complete(itv); + + mutex_unlock(&itv->udma.lock); + return rc; +} + +/* Setup frame according to V4L2 parameters */ +void ivtv_yuv_setup_stream_frame(struct ivtv *itv) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + struct ivtv_dma_frame dma_args; + + ivtv_yuv_next_free(itv); + + /* Copy V4L2 parameters to an ivtv_dma_frame struct... */ + dma_args.y_source = NULL; + dma_args.uv_source = NULL; + dma_args.src.left = 0; + dma_args.src.top = 0; + dma_args.src.width = yi->v4l2_src_w; + dma_args.src.height = yi->v4l2_src_h; + dma_args.dst = yi->main_rect; + dma_args.src_width = yi->v4l2_src_w; + dma_args.src_height = yi->v4l2_src_h; + + /* ... and use the same setup routine as ivtv_yuv_prep_frame */ + ivtv_yuv_setup_frame(itv, &dma_args); + + if (!itv->dma_data_req_offset) + itv->dma_data_req_offset = yuv_offset[yi->draw_frame]; +} + +/* Attempt to dma a frame from a user buffer */ +int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + struct ivtv_dma_frame dma_args; + + ivtv_yuv_setup_stream_frame(itv); + + /* We only need to supply source addresses for this */ + dma_args.y_source = src; + dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31); + return ivtv_yuv_udma_frame(itv, &dma_args); +} + +/* IVTV_IOC_DMA_FRAME ioctl handler */ +int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +{ +/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */ + + ivtv_yuv_next_free(itv); + ivtv_yuv_setup_frame(itv, args); + return ivtv_yuv_udma_frame(itv, args); +} + +void ivtv_yuv_close(struct ivtv *itv) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + int h_filter, v_filter_1, v_filter_2; + + IVTV_DEBUG_YUV("ivtv_yuv_close\n"); + ivtv_waitq(&itv->vsync_waitq); + + yi->running = 0; + atomic_set(&yi->next_dma_frame, -1); + atomic_set(&yi->next_fill_frame, 0); + + /* Reset registers we have changed so mpeg playback works */ + + /* If we fully restore this register, the display may remain active. + Restore, but set one bit to blank the video. Firmware will always + clear this bit when needed, so not a problem. */ + write_reg(yi->reg_2898 | 0x01000000, 0x2898); + + write_reg(yi->reg_2834, 0x02834); + write_reg(yi->reg_2838, 0x02838); + write_reg(yi->reg_283c, 0x0283c); + write_reg(yi->reg_2840, 0x02840); + write_reg(yi->reg_2844, 0x02844); + write_reg(yi->reg_2848, 0x02848); + write_reg(yi->reg_2854, 0x02854); + write_reg(yi->reg_285c, 0x0285c); + write_reg(yi->reg_2864, 0x02864); + write_reg(yi->reg_2870, 0x02870); + write_reg(yi->reg_2874, 0x02874); + write_reg(yi->reg_2890, 0x02890); + write_reg(yi->reg_289c, 0x0289c); + + write_reg(yi->reg_2918, 0x02918); + write_reg(yi->reg_291c, 0x0291c); + write_reg(yi->reg_2920, 0x02920); + write_reg(yi->reg_2924, 0x02924); + write_reg(yi->reg_2928, 0x02928); + write_reg(yi->reg_292c, 0x0292c); + write_reg(yi->reg_2930, 0x02930); + write_reg(yi->reg_2934, 0x02934); + write_reg(yi->reg_2938, 0x02938); + write_reg(yi->reg_293c, 0x0293c); + write_reg(yi->reg_2940, 0x02940); + write_reg(yi->reg_2944, 0x02944); + write_reg(yi->reg_2948, 0x02948); + write_reg(yi->reg_294c, 0x0294c); + write_reg(yi->reg_2950, 0x02950); + write_reg(yi->reg_2954, 0x02954); + write_reg(yi->reg_2958, 0x02958); + write_reg(yi->reg_295c, 0x0295c); + write_reg(yi->reg_2960, 0x02960); + write_reg(yi->reg_2964, 0x02964); + write_reg(yi->reg_2968, 0x02968); + write_reg(yi->reg_296c, 0x0296c); + write_reg(yi->reg_2970, 0x02970); + + /* Prepare to restore filters */ + + /* First the horizontal filter */ + if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) { + /* An exact size match uses filter 0 */ + h_filter = 0; + } else { + /* Figure out which filter to use */ + h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15; + h_filter = (h_filter >> 1) + (h_filter & 1); + /* Only an exact size match can use filter 0. */ + h_filter += !h_filter; + } + + /* Now the vertical filter */ + if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) { + /* An exact size match uses filter 0/1 */ + v_filter_1 = 0; + v_filter_2 = 1; + } else { + /* Figure out which filter to use */ + v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15; + v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); + /* Only an exact size match can use filter 0 */ + v_filter_1 += !v_filter_1; + v_filter_2 = v_filter_1; + } + + /* Now restore the filters */ + ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2); + + /* and clear a few registers */ + write_reg(0, 0x02814); + write_reg(0, 0x0282c); + write_reg(0, 0x02904); + write_reg(0, 0x02910); + + /* Release the blanking buffer */ + if (yi->blanking_ptr) { + kfree(yi->blanking_ptr); + yi->blanking_ptr = NULL; + pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); + } + + /* Invalidate the old dimension information */ + yi->old_frame_info.src_w = 0; + yi->old_frame_info.src_h = 0; + yi->old_frame_info_args.src_w = 0; + yi->old_frame_info_args.src_h = 0; + + /* All done. */ + clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-yuv.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-yuv.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-yuv.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/ivtv-yuv.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,44 @@ +/* + yuv support + + Copyright (C) 2007 Ian Armstrong + + 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, or + (at your option) any later version. + + 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 + */ + +#ifndef IVTV_YUV_H +#define IVTV_YUV_H + +#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ + +/* Offset to filter table in firmware */ +#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 +#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 + +#define IVTV_YUV_UPDATE_HORIZONTAL 0x01 +#define IVTV_YUV_UPDATE_VERTICAL 0x02 +#define IVTV_YUV_UPDATE_INVALID 0x04 + +extern const u32 yuv_offset[IVTV_YUV_BUFFERS]; + +int ivtv_yuv_filter_check(struct ivtv *itv); +void ivtv_yuv_setup_stream_frame(struct ivtv *itv); +int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src); +void ivtv_yuv_frame_complete(struct ivtv *itv); +int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); +void ivtv_yuv_close(struct ivtv *itv); +void ivtv_yuv_work_handler(struct ivtv *itv); + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,45 @@ +config VIDEO_IVTV + tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" + depends on VIDEO_V4L2 && PCI && I2C + select I2C_ALGOBIT + depends on RC_CORE + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_CX2341X + select VIDEO_CX25840 + select VIDEO_MSP3400 + select VIDEO_SAA711X + select VIDEO_SAA717X + select VIDEO_SAA7127 + select VIDEO_CS53L32A + select VIDEO_M52790 + select VIDEO_WM8775 + select VIDEO_WM8739 + select VIDEO_VP27SMPX + select VIDEO_UPD64031A + select VIDEO_UPD64083 + ---help--- + This is a video4linux driver for Conexant cx23416 or cx23415 based + PCI personal video recorder devices. + + This is used in devices such as the Hauppauge PVR-150/250/350/500 + cards. There is a driver homepage at . + + To compile this driver as a module, choose M here: the + module will be called ivtv. + +config VIDEO_FB_IVTV + tristate "Conexant cx23415 framebuffer support" + depends on VIDEO_IVTV && FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This is a framebuffer driver for the Conexant cx23415 MPEG + encoder/decoder. + + This is used in the Hauppauge PVR-350 card. There is a driver + homepage at . + + To compile this driver as a module, choose M here: the + module will be called ivtvfb. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ivtv/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,14 @@ +ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ + ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \ + ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \ + ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \ + ivtv-vbi.o ivtv-yuv.o + +obj-$(CONFIG_VIDEO_IVTV) += ivtv.o +obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1052 @@ +# +# Generic video config states +# + +config VIDEO_V4L2 + tristate + depends on VIDEO_DEV && VIDEO_V4L2_COMMON + default VIDEO_DEV && VIDEO_V4L2_COMMON + +config VIDEOBUF_GEN + tristate + +config VIDEOBUF_DMA_SG + depends on HAS_DMA + select VIDEOBUF_GEN + tristate + +config VIDEOBUF_VMALLOC + select VIDEOBUF_GEN + tristate + +config VIDEOBUF_DMA_CONTIG + depends on HAS_DMA + select VIDEOBUF_GEN + tristate + +config VIDEOBUF_DVB + tristate + select VIDEOBUF_GEN + +config VIDEO_BTCX + depends on PCI + tristate + +config VIDEO_TVEEPROM + tristate + depends on I2C + +config VIDEO_TUNER + tristate + depends on MEDIA_TUNER + +config V4L2_MEM2MEM_DEV + tristate + depends on VIDEOBUF2_CORE + +config VIDEOBUF2_CORE + tristate + +config VIDEOBUF2_MEMOPS + tristate + +config VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_CORE + select VIDEOBUF2_MEMOPS + tristate + +config VIDEOBUF2_VMALLOC + select VIDEOBUF2_CORE + select VIDEOBUF2_MEMOPS + tristate + + +config VIDEOBUF2_DMA_SG + #depends on HAS_DMA + select VIDEOBUF2_CORE + select VIDEOBUF2_MEMOPS + tristate +# +# Multimedia Video device configuration +# + +menuconfig VIDEO_CAPTURE_DRIVERS + bool "Video capture adapters" + depends on VIDEO_V4L2 + default y + ---help--- + Say Y here to enable selecting the video adapters for + webcams, analog TV, and hybrid analog/digital TV. + Some of those devices also supports FM radio. + +if VIDEO_CAPTURE_DRIVERS && VIDEO_V4L2 + +config VIDEO_ADV_DEBUG + bool "Enable advanced debug functionality" + default n + ---help--- + Say Y here to enable advanced debugging functionality on some + V4L devices. + In doubt, say N. + +config VIDEO_FIXED_MINOR_RANGES + bool "Enable old-style fixed minor ranges for video devices" + default n + ---help--- + Say Y here to enable the old-style fixed-range minor assignments. + Only useful if you rely on the old behavior and use mknod instead of udev. + + When in doubt, say N. + +config VIDEO_HELPER_CHIPS_AUTO + bool "Autoselect pertinent encoders/decoders and other helper chips" + default y if !EXPERT + ---help--- + Most video cards may require additional modules to encode or + decode audio/video standards. This option will autoselect + all pertinent modules to each selected video module. + + Unselect this only if you know exactly what you are doing, since + it may break support on some boards. + + In doubt, say Y. + +config VIDEO_IR_I2C + tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO + depends on I2C && RC_CORE + default y + ---help--- + Most boards have an IR chip directly connected via GPIO. However, + some video boards have the IR connected via I2C bus. + + If your board doesn't have an I2C IR chip, you may disable this + option. + + In doubt, say Y. + +# +# Encoder / Decoder module configuration +# + +menu "Encoders, decoders, sensors and other helper chips" + visible if !VIDEO_HELPER_CHIPS_AUTO + +comment "Audio decoders, processors and mixers" + +config VIDEO_TVAUDIO + tristate "Simple audio decoder chips" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for several audio decoder chips found on some bt8xx boards: + Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, + tea6320, tea6420, tda8425, ta8874z. + Microchip: pic16c54 based design on ProVideo PV951 board. + + To compile this driver as a module, choose M here: the + module will be called tvaudio. + +config VIDEO_TDA7432 + tristate "Philips TDA7432 audio processor" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for tda7432 audio decoder chip found on some bt8xx boards. + + To compile this driver as a module, choose M here: the + module will be called tda7432. + +config VIDEO_TDA9840 + tristate "Philips TDA9840 audio processor" + depends on I2C + ---help--- + Support for tda9840 audio decoder chip found on some Zoran boards. + + To compile this driver as a module, choose M here: the + module will be called tda9840. + +config VIDEO_TEA6415C + tristate "Philips TEA6415C audio processor" + depends on I2C + ---help--- + Support for tea6415c audio decoder chip found on some bt8xx boards. + + To compile this driver as a module, choose M here: the + module will be called tea6415c. + +config VIDEO_TEA6420 + tristate "Philips TEA6420 audio processor" + depends on I2C + ---help--- + Support for tea6420 audio decoder chip found on some bt8xx boards. + + To compile this driver as a module, choose M here: the + module will be called tea6420. + +config VIDEO_MSP3400 + tristate "Micronas MSP34xx audio decoders" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Micronas MSP34xx series of audio decoders. + + To compile this driver as a module, choose M here: the + module will be called msp3400. + +config VIDEO_CS5345 + tristate "Cirrus Logic CS5345 audio ADC" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Cirrus Logic CS5345 24-bit, 192 kHz + stereo A/D converter. + + To compile this driver as a module, choose M here: the + module will be called cs5345. + +config VIDEO_CS53L32A + tristate "Cirrus Logic CS53L32A audio ADC" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Cirrus Logic CS53L32A low voltage + stereo A/D converter. + + To compile this driver as a module, choose M here: the + module will be called cs53l32a. + +config VIDEO_TLV320AIC23B + tristate "Texas Instruments TLV320AIC23B audio codec" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the Texas Instruments TLV320AIC23B audio codec. + + To compile this driver as a module, choose M here: the + module will be called tlv320aic23b. + +config VIDEO_WM8775 + tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Wolfson Microelectronics WM8775 high + performance stereo A/D Converter with a 4 channel input mixer. + + To compile this driver as a module, choose M here: the + module will be called wm8775. + +config VIDEO_WM8739 + tristate "Wolfson Microelectronics WM8739 stereo audio ADC" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Wolfson Microelectronics WM8739 + stereo A/D Converter. + + To compile this driver as a module, choose M here: the + module will be called wm8739. + +config VIDEO_VP27SMPX + tristate "Panasonic VP27s internal MPX" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the internal MPX of the Panasonic VP27s tuner. + + To compile this driver as a module, choose M here: the + module will be called vp27smpx. + +comment "RDS decoders" + +config VIDEO_SAA6588 + tristate "SAA6588 Radio Chip RDS decoder support" + depends on VIDEO_V4L2 && I2C + + help + Support for this Radio Data System (RDS) decoder. This allows + seeing radio station identification transmitted using this + standard. + + To compile this driver as a module, choose M here: the + module will be called saa6588. + +comment "Video decoders" + +config VIDEO_ADV7180 + tristate "Analog Devices ADV7180 decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Analog Devices ADV7180 video decoder. + + To compile this driver as a module, choose M here: the + module will be called adv7180. + +config VIDEO_BT819 + tristate "BT819A VideoStream decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for BT819A video decoder. + + To compile this driver as a module, choose M here: the + module will be called bt819. + +config VIDEO_BT856 + tristate "BT856 VideoStream decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for BT856 video decoder. + + To compile this driver as a module, choose M here: the + module will be called bt856. + +config VIDEO_BT866 + tristate "BT866 VideoStream decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for BT866 video decoder. + + To compile this driver as a module, choose M here: the + module will be called bt866. + +config VIDEO_KS0127 + tristate "KS0127 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for KS0127 video decoder. + + This chip is used on AverMedia AVS6EYES Zoran-based MJPEG + cards. + + To compile this driver as a module, choose M here: the + module will be called ks0127. + +config VIDEO_SAA7110 + tristate "Philips SAA7110 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Philips SAA7110 video decoders. + + To compile this driver as a module, choose M here: the + module will be called saa7110. + +config VIDEO_SAA711X + tristate "Philips SAA7111/3/4/5 video decoders" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Philips SAA7111/3/4/5 video decoders. + + To compile this driver as a module, choose M here: the + module will be called saa7115. + +config VIDEO_SAA7191 + tristate "Philips SAA7191 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Philips SAA7191 video decoder. + + To compile this driver as a module, choose M here: the + module will be called saa7191. + +config VIDEO_TVP514X + tristate "Texas Instruments TVP514x video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + This is a Video4Linux2 sensor-level driver for the TI TVP5146/47 + decoder. It is currently working with the TI OMAP3 camera + controller. + + To compile this driver as a module, choose M here: the + module will be called tvp514x. + +config VIDEO_TVP5150 + tristate "Texas Instruments TVP5150 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Texas Instruments TVP5150 video decoder. + + To compile this driver as a module, choose M here: the + module will be called tvp5150. + +config VIDEO_TVP7002 + tristate "Texas Instruments TVP7002 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Texas Instruments TVP7002 video decoder. + + To compile this driver as a module, choose M here: the + module will be called tvp7002. + +config VIDEO_VPX3220 + tristate "vpx3220a, vpx3216b & vpx3214c video decoders" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for VPX322x video decoders. + + To compile this driver as a module, choose M here: the + module will be called vpx3220. + +comment "Video and audio decoders" + +config VIDEO_SAA717X + tristate "Philips SAA7171/3/4 audio/video decoders" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Philips SAA7171/3/4 audio/video decoders. + + To compile this driver as a module, choose M here: the + module will be called saa717x. + +source "drivers/media/video/cx25840/Kconfig" + +comment "MPEG video encoders" + +config VIDEO_CX2341X + tristate "Conexant CX2341x MPEG encoders" + depends on VIDEO_V4L2 && VIDEO_V4L2_COMMON + ---help--- + Support for the Conexant CX23416 MPEG encoders + and CX23415 MPEG encoder/decoders. + + This module currently supports the encoding functions only. + + To compile this driver as a module, choose M here: the + module will be called cx2341x. + +comment "Video encoders" + +config VIDEO_SAA7127 + tristate "Philips SAA7127/9 digital video encoders" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Philips SAA7127/9 digital video encoders. + + To compile this driver as a module, choose M here: the + module will be called saa7127. + +config VIDEO_SAA7185 + tristate "Philips SAA7185 video encoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Philips SAA7185 video encoder. + + To compile this driver as a module, choose M here: the + module will be called saa7185. + +config VIDEO_ADV7170 + tristate "Analog Devices ADV7170 video encoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Analog Devices ADV7170 video encoder driver + + To compile this driver as a module, choose M here: the + module will be called adv7170. + +config VIDEO_ADV7175 + tristate "Analog Devices ADV7175 video encoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Analog Devices ADV7175 video encoder driver + + To compile this driver as a module, choose M here: the + module will be called adv7175. + +config VIDEO_ADV7343 + tristate "ADV7343 video encoder" + depends on I2C + help + Support for Analog Devices I2C bus based ADV7343 encoder. + + To compile this driver as a module, choose M here: the + module will be called adv7343. + +config VIDEO_AK881X + tristate "AK8813/AK8814 video encoders" + depends on I2C + help + Video output driver for AKM AK8813 and AK8814 TV encoders + +comment "Camera sensor devices" + +config VIDEO_OV7670 + tristate "OmniVision OV7670 sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV7670 VGA camera. It currently only works with the M88ALP01 + controller. + +config VIDEO_MT9V011 + tristate "Micron mt9v011 sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the Micron + mt0v011 1.3 Mpixel camera. It currently only works with the + em28xx driver. + +config VIDEO_MT9V032 + tristate "Micron MT9V032 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + ---help--- + This is a Video4Linux2 sensor-level driver for the Micron + MT9V032 752x480 CMOS sensor. + +config VIDEO_TCM825X + tristate "TCM825x camera sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a driver for the Toshiba TCM825x VGA camera sensor. + It is used for example in Nokia N800. + +comment "Video improvement chips" + +config VIDEO_UPD64031A + tristate "NEC Electronics uPD64031A Ghost Reduction" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the NEC Electronics uPD64031A Ghost Reduction + video chip. It is most often found in NTSC TV cards made for + Japan and is used to reduce the 'ghosting' effect that can + be present in analog TV broadcasts. + + To compile this driver as a module, choose M here: the + module will be called upd64031a. + +config VIDEO_UPD64083 + tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the NEC Electronics uPD64083 3-Dimensional Y/C + separation video chip. It is used to improve the quality of + the colors of a composite signal. + + To compile this driver as a module, choose M here: the + module will be called upd64083. + +comment "Miscelaneous helper chips" + +config VIDEO_THS7303 + tristate "THS7303 Video Amplifier" + depends on I2C + help + Support for TI THS7303 video amplifier + + To compile this driver as a module, choose M here: the + module will be called ths7303. + +config VIDEO_M52790 + tristate "Mitsubishi M52790 A/V switch" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Mitsubishi M52790 A/V switch. + + To compile this driver as a module, choose M here: the + module will be called m52790. + +endmenu # encoder / decoder chips + +config VIDEO_SH_VOU + tristate "SuperH VOU video output driver" + depends on VIDEO_DEV && ARCH_SHMOBILE + select VIDEOBUF_DMA_CONTIG + help + Support for the Video Output Unit (VOU) on SuperH SoCs. + +config VIDEO_VIU + tristate "Freescale VIU Video Driver" + depends on VIDEO_V4L2 && PPC_MPC512x + select VIDEOBUF_DMA_CONTIG + default y + ---help--- + Support for Freescale VIU video driver. This device captures + video data, or overlays video on DIU frame buffer. + + Say Y here if you want to enable VIU device on MPC5121e Rev2+. + In doubt, say N. + +config VIDEO_VIVI + tristate "Virtual Video Driver" + depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE + select FONT_8x16 + select VIDEOBUF2_VMALLOC + default n + ---help--- + Enables a virtual video driver. This device shows a color bar + and a timestamp, as a real device would generate by using V4L2 + api. + Say Y here if you want to test video apps or debug V4L devices. + In doubt, say N. + +source "drivers/media/video/davinci/Kconfig" + +source "drivers/media/video/omap/Kconfig" + +source "drivers/media/video/bt8xx/Kconfig" + +config VIDEO_PMS + tristate "Mediavision Pro Movie Studio Video For Linux" + depends on ISA && VIDEO_V4L2 + help + Say Y if you have such a thing. + + To compile this driver as a module, choose M here: the + module will be called pms. + +config VIDEO_BWQCAM + tristate "Quickcam BW Video For Linux" + depends on PARPORT && VIDEO_V4L2 + help + Say Y have if you the black and white version of the QuickCam + camera. See the next option for the color version. + + To compile this driver as a module, choose M here: the + module will be called bw-qcam. + +config VIDEO_CQCAM + tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)" + depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2 + help + This is the video4linux driver for the colour version of the + Connectix QuickCam. If you have one of these cameras, say Y here, + otherwise say N. This driver does not work with the original + monochrome QuickCam, QuickCam VC or QuickClip. It is also available + as a module (c-qcam). + Read for more information. + +config VIDEO_W9966 + tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux" + depends on PARPORT_1284 && PARPORT && VIDEO_V4L2 + help + Video4linux driver for Winbond's w9966 based Webcams. + Currently tested with the LifeView FlyCam Supra. + If you have one of these cameras, say Y here + otherwise say N. + This driver is also available as a module (w9966). + + Check out for more + information. + +source "drivers/media/video/cpia2/Kconfig" + +config VIDEO_VINO + tristate "SGI Vino Video For Linux (EXPERIMENTAL)" + depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 + select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO + help + Say Y here to build in support for the Vino video input system found + on SGI Indy machines. + +source "drivers/media/video/zoran/Kconfig" + +config VIDEO_MEYE + tristate "Sony Vaio Picturebook Motion Eye Video For Linux" + depends on PCI && SONY_LAPTOP && VIDEO_V4L2 + ---help--- + This is the video4linux driver for the Motion Eye camera found + in the Vaio Picturebook laptops. Please read the material in + for more information. + + If you say Y or M here, you need to say Y or M to "Sony Laptop + Extras" in the misc device section. + + To compile this driver as a module, choose M here: the + module will be called meye. + +source "drivers/media/video/saa7134/Kconfig" + +config VIDEO_MXB + tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" + depends on PCI && VIDEO_V4L2 && I2C + select VIDEO_SAA7146_VV + select VIDEO_TUNER + select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO + ---help--- + This is a video4linux driver for the 'Multimedia eXtension Board' + TV card by Siemens-Nixdorf. + + To compile this driver as a module, choose M here: the + module will be called mxb. + +config VIDEO_HEXIUM_ORION + tristate "Hexium HV-PCI6 and Orion frame grabber" + depends on PCI && VIDEO_V4L2 && I2C + select VIDEO_SAA7146_VV + ---help--- + This is a video4linux driver for the Hexium HV-PCI6 and + Orion frame grabber cards by Hexium. + + To compile this driver as a module, choose M here: the + module will be called hexium_orion. + +config VIDEO_HEXIUM_GEMINI + tristate "Hexium Gemini frame grabber" + depends on PCI && VIDEO_V4L2 && I2C + select VIDEO_SAA7146_VV + ---help--- + This is a video4linux driver for the Hexium Gemini frame + grabber card by Hexium. Please note that the Gemini Dual + card is *not* fully supported. + + To compile this driver as a module, choose M here: the + module will be called hexium_gemini. + +config VIDEO_TIMBERDALE + tristate "Support for timberdale Video In/LogiWIN" + depends on VIDEO_V4L2 && I2C && DMADEVICES + select DMA_ENGINE + select TIMB_DMA + select VIDEO_ADV7180 + select VIDEOBUF_DMA_CONTIG + ---help--- + Add support for the Video In peripherial of the timberdale FPGA. + +source "drivers/media/video/cx88/Kconfig" + +source "drivers/media/video/cx23885/Kconfig" + +source "drivers/media/video/au0828/Kconfig" + +source "drivers/media/video/ivtv/Kconfig" + +source "drivers/media/video/cx18/Kconfig" + +source "drivers/media/video/saa7164/Kconfig" + +source "drivers/media/video/marvell-ccic/Kconfig" + +config VIDEO_M32R_AR + tristate "AR devices" + depends on M32R && VIDEO_V4L2 + ---help--- + This is a video4linux driver for the Renesas AR (Artificial Retina) + camera module. + +config VIDEO_M32R_AR_M64278 + tristate "AR device with color module M64278(VGA)" + depends on PLAT_M32700UT + select VIDEO_M32R_AR + ---help--- + This is a video4linux driver for the Renesas AR (Artificial + Retina) with M64278E-800 camera module. + This module supports VGA(640x480 pixels) resolutions. + + To compile this driver as a module, choose M here: the + module will be called arv. + +config VIDEO_SR030PC30 + tristate "SR030PC30 VGA camera sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This driver supports SR030PC30 VGA camera from Siliconfile + +config VIDEO_VIA_CAMERA + tristate "VIAFB camera controller support" + depends on FB_VIA + select VIDEOBUF_DMA_SG + select VIDEO_OV7670 + help + Driver support for the integrated camera controller in VIA + Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems + with ov7670 sensors. + +config VIDEO_NOON010PC30 + tristate "NOON010PC30 CIF camera sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This driver supports NOON010PC30 CIF camera from Siliconfile + +source "drivers/media/video/m5mols/Kconfig" + +config VIDEO_OMAP3 + tristate "OMAP 3 Camera support (EXPERIMENTAL)" + select OMAP_IOMMU + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL + ---help--- + Driver for an OMAP 3 camera controller. + +config VIDEO_OMAP3_DEBUG + bool "OMAP 3 Camera debug messages" + depends on VIDEO_OMAP3 + ---help--- + Enable debug messages on OMAP 3 camera controller driver. + +config SOC_CAMERA + tristate "SoC camera support" + depends on VIDEO_V4L2 && HAS_DMA && I2C + select VIDEOBUF_GEN + select VIDEOBUF2_CORE + help + SoC Camera is a common API to several cameras, not connecting + over a bus like PCI or USB. For example some i2c camera connected + directly to the data bus of an SoC. + +config SOC_CAMERA_IMX074 + tristate "imx074 support" + depends on SOC_CAMERA && I2C + help + This driver supports IMX074 cameras from Sony + +config SOC_CAMERA_MT9M001 + tristate "mt9m001 support" + depends on SOC_CAMERA && I2C + select GPIO_PCA953X if MT9M001_PCA9536_SWITCH + help + This driver supports MT9M001 cameras from Micron, monochrome + and colour models. + +config SOC_CAMERA_MT9M111 + tristate "mt9m111, mt9m112 and mt9m131 support" + depends on SOC_CAMERA && I2C + help + This driver supports MT9M111, MT9M112 and MT9M131 cameras from + Micron/Aptina + +config SOC_CAMERA_MT9T031 + tristate "mt9t031 support" + depends on SOC_CAMERA && I2C + help + This driver supports MT9T031 cameras from Micron. + +config SOC_CAMERA_MT9T112 + tristate "mt9t112 support" + depends on SOC_CAMERA && I2C + help + This driver supports MT9T112 cameras from Aptina. + +config SOC_CAMERA_MT9V022 + tristate "mt9v022 support" + depends on SOC_CAMERA && I2C + select GPIO_PCA953X if MT9V022_PCA9536_SWITCH + help + This driver supports MT9V022 cameras from Micron + +config SOC_CAMERA_RJ54N1 + tristate "rj54n1cb0c support" + depends on SOC_CAMERA && I2C + help + This is a rj54n1cb0c video driver + +config SOC_CAMERA_TW9910 + tristate "tw9910 support" + depends on SOC_CAMERA && I2C + help + This is a tw9910 video driver + +config SOC_CAMERA_PLATFORM + tristate "platform camera support" + depends on SOC_CAMERA + help + This is a generic SoC camera platform driver, useful for testing + +config SOC_CAMERA_OV2640 + tristate "ov2640 camera support" + depends on SOC_CAMERA && I2C + help + This is a ov2640 camera driver + +config SOC_CAMERA_OV6650 + tristate "ov6650 sensor support" + depends on SOC_CAMERA && I2C + ---help--- + This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor + +config SOC_CAMERA_OV772X + tristate "ov772x camera support" + depends on SOC_CAMERA && I2C + help + This is a ov772x camera driver + +config SOC_CAMERA_OV9640 + tristate "ov9640 camera support" + depends on SOC_CAMERA && I2C + help + This is a ov9640 camera driver + +config SOC_CAMERA_OV9740 + tristate "ov9740 camera support" + depends on SOC_CAMERA && I2C + help + This is a ov9740 camera driver + +config MX1_VIDEO + bool + +config VIDEO_MX1 + tristate "i.MX1/i.MXL CMOS Sensor Interface driver" + depends on VIDEO_DEV && ARCH_MX1 && SOC_CAMERA + select FIQ + select VIDEOBUF_DMA_CONTIG + select MX1_VIDEO + ---help--- + This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface + +config MX3_VIDEO + bool + +config VIDEO_MX3 + tristate "i.MX3x Camera Sensor Interface driver" + depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA + select VIDEOBUF2_DMA_CONTIG + select MX3_VIDEO + ---help--- + This is a v4l2 driver for the i.MX3x Camera Sensor Interface + +config VIDEO_PXA27x + tristate "PXA27x Quick Capture Interface driver" + depends on VIDEO_DEV && PXA27x && SOC_CAMERA + select VIDEOBUF_DMA_SG + ---help--- + This is a v4l2 driver for the PXA27x Quick Capture Interface + +config VIDEO_SH_MOBILE_CSI2 + tristate "SuperH Mobile MIPI CSI-2 Interface driver" + depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK + ---help--- + This is a v4l2 driver for the SuperH MIPI CSI-2 Interface + +config VIDEO_SH_MOBILE_CEU + tristate "SuperH Mobile CEU Interface driver" + depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK + select VIDEOBUF2_DMA_CONTIG + ---help--- + This is a v4l2 driver for the SuperH Mobile CEU Interface + +config VIDEO_OMAP1 + tristate "OMAP1 Camera Interface driver" + depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA + select VIDEOBUF_DMA_CONTIG + select VIDEOBUF_DMA_SG + ---help--- + This is a v4l2 driver for the TI OMAP1 camera interface + +config VIDEO_OMAP2 + tristate "OMAP2 Camera Capture Interface driver" + depends on VIDEO_DEV && ARCH_OMAP2 + select VIDEOBUF_DMA_SG + ---help--- + This is a v4l2 driver for the TI OMAP2 camera capture interface + +config VIDEO_MX2_HOSTSUPPORT + bool + +config VIDEO_MX2 + tristate "i.MX27/i.MX25 Camera Sensor Interface driver" + depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25) + select VIDEOBUF_DMA_CONTIG + select VIDEO_MX2_HOSTSUPPORT + ---help--- + This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor + Interface + +config VIDEO_SAMSUNG_S5P_FIMC + tristate "Samsung S5P and EXYNOS4 camera host interface driver" + depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + ---help--- + This is a v4l2 driver for Samsung S5P and EXYNOS4 camera + host interface and video postprocessor. + + To compile this driver as a module, choose M here: the + module will be called s5p-fimc. + +config VIDEO_S5P_MIPI_CSIS + tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" + depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API + ---help--- + This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. + + To compile this driver as a module, choose M here: the + module will be called s5p-csis. + +# +# USB Multimedia device configuration +# + +menuconfig V4L_USB_DRIVERS + bool "V4L USB devices" + depends on USB + default y + +if V4L_USB_DRIVERS && USB + +source "drivers/media/video/uvc/Kconfig" + +source "drivers/media/video/gspca/Kconfig" + +source "drivers/media/video/pvrusb2/Kconfig" + +source "drivers/media/video/hdpvr/Kconfig" + +source "drivers/media/video/em28xx/Kconfig" + +source "drivers/media/video/tlg2300/Kconfig" + +source "drivers/media/video/cx231xx/Kconfig" + +source "drivers/media/video/usbvision/Kconfig" + +source "drivers/media/video/et61x251/Kconfig" + +source "drivers/media/video/sn9c102/Kconfig" + +source "drivers/media/video/pwc/Kconfig" + +config USB_ZR364XX + tristate "USB ZR364XX Camera support" + depends on VIDEO_V4L2 + select VIDEOBUF_GEN + select VIDEOBUF_VMALLOC + ---help--- + Say Y here if you want to connect this type of camera to your + computer's USB port. + See for more info + and list of supported cameras. + + To compile this driver as a module, choose M here: the + module will be called zr364xx. + +config USB_STKWEBCAM + tristate "USB Syntek DC1125 Camera support" + depends on VIDEO_V4L2 && EXPERIMENTAL + ---help--- + Say Y here if you want to use this type of camera. + Supported devices are typically found in some Asus laptops, + with USB id 174f:a311 and 05e1:0501. Other Syntek cameras + may be supported by the stk11xx driver, from which this is + derived, see + + To compile this driver as a module, choose M here: the + module will be called stkwebcam. + +config USB_S2255 + tristate "USB Sensoray 2255 video capture device" + depends on VIDEO_V4L2 + select VIDEOBUF_VMALLOC + default n + help + Say Y here if you want support for the Sensoray 2255 USB device. + This driver can be compiled as a module, called s2255drv. + +endif # V4L_USB_DRIVERS +endif # VIDEO_CAPTURE_DRIVERS + +menuconfig V4L_MEM2MEM_DRIVERS + bool "Memory-to-memory multimedia devices" + depends on VIDEO_V4L2 + default n + ---help--- + Say Y here to enable selecting drivers for V4L devices that + use system memory for both source and destination buffers, as opposed + to capture and output drivers, which use memory buffers for just + one of those. + +if V4L_MEM2MEM_DRIVERS + +config VIDEO_MEM2MEM_TESTDEV + tristate "Virtual test device for mem2mem framework" + depends on VIDEO_DEV && VIDEO_V4L2 + select VIDEOBUF2_VMALLOC + select V4L2_MEM2MEM_DEV + default n + ---help--- + This is a virtual test device for the memory-to-memory driver + framework. + + +endif # V4L_MEM2MEM_DRIVERS diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ks0127.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ks0127.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ks0127.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ks0127.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,735 @@ +/* + * Video Capture Driver (Video for Linux 1/2) + * for the Matrox Marvel G200,G400 and Rainbow Runner-G series + * + * This module is an interface to the KS0127 video decoder chip. + * + * Copyright (C) 1999 Ryan Drake + * + * 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, or (at your option) any later version. + * + * 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. + * + ***************************************************************************** + * + * Modified and extended by + * Mike Bernson + * Gerard v.d. Horst + * Leon van Stuivenberg + * Gernot Ziegler + * + * Version History: + * V1.0 Ryan Drake Initial version by Ryan Drake + * V1.1 Gerard v.d. Horst Added some debugoutput, reset the video-standard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ks0127.h" + +MODULE_DESCRIPTION("KS0127 video decoder driver"); +MODULE_AUTHOR("Ryan Drake"); +MODULE_LICENSE("GPL"); + +/* Addresses */ +#define I2C_KS0127_ADDON 0xD8 +#define I2C_KS0127_ONBOARD 0xDA + + +/* ks0127 control registers */ +#define KS_STAT 0x00 +#define KS_CMDA 0x01 +#define KS_CMDB 0x02 +#define KS_CMDC 0x03 +#define KS_CMDD 0x04 +#define KS_HAVB 0x05 +#define KS_HAVE 0x06 +#define KS_HS1B 0x07 +#define KS_HS1E 0x08 +#define KS_HS2B 0x09 +#define KS_HS2E 0x0a +#define KS_AGC 0x0b +#define KS_HXTRA 0x0c +#define KS_CDEM 0x0d +#define KS_PORTAB 0x0e +#define KS_LUMA 0x0f +#define KS_CON 0x10 +#define KS_BRT 0x11 +#define KS_CHROMA 0x12 +#define KS_CHROMB 0x13 +#define KS_DEMOD 0x14 +#define KS_SAT 0x15 +#define KS_HUE 0x16 +#define KS_VERTIA 0x17 +#define KS_VERTIB 0x18 +#define KS_VERTIC 0x19 +#define KS_HSCLL 0x1a +#define KS_HSCLH 0x1b +#define KS_VSCLL 0x1c +#define KS_VSCLH 0x1d +#define KS_OFMTA 0x1e +#define KS_OFMTB 0x1f +#define KS_VBICTL 0x20 +#define KS_CCDAT2 0x21 +#define KS_CCDAT1 0x22 +#define KS_VBIL30 0x23 +#define KS_VBIL74 0x24 +#define KS_VBIL118 0x25 +#define KS_VBIL1512 0x26 +#define KS_TTFRAM 0x27 +#define KS_TESTA 0x28 +#define KS_UVOFFH 0x29 +#define KS_UVOFFL 0x2a +#define KS_UGAIN 0x2b +#define KS_VGAIN 0x2c +#define KS_VAVB 0x2d +#define KS_VAVE 0x2e +#define KS_CTRACK 0x2f +#define KS_POLCTL 0x30 +#define KS_REFCOD 0x31 +#define KS_INVALY 0x32 +#define KS_INVALU 0x33 +#define KS_INVALV 0x34 +#define KS_UNUSEY 0x35 +#define KS_UNUSEU 0x36 +#define KS_UNUSEV 0x37 +#define KS_USRSAV 0x38 +#define KS_USREAV 0x39 +#define KS_SHS1A 0x3a +#define KS_SHS1B 0x3b +#define KS_SHS1C 0x3c +#define KS_CMDE 0x3d +#define KS_VSDEL 0x3e +#define KS_CMDF 0x3f +#define KS_GAMMA0 0x40 +#define KS_GAMMA1 0x41 +#define KS_GAMMA2 0x42 +#define KS_GAMMA3 0x43 +#define KS_GAMMA4 0x44 +#define KS_GAMMA5 0x45 +#define KS_GAMMA6 0x46 +#define KS_GAMMA7 0x47 +#define KS_GAMMA8 0x48 +#define KS_GAMMA9 0x49 +#define KS_GAMMA10 0x4a +#define KS_GAMMA11 0x4b +#define KS_GAMMA12 0x4c +#define KS_GAMMA13 0x4d +#define KS_GAMMA14 0x4e +#define KS_GAMMA15 0x4f +#define KS_GAMMA16 0x50 +#define KS_GAMMA17 0x51 +#define KS_GAMMA18 0x52 +#define KS_GAMMA19 0x53 +#define KS_GAMMA20 0x54 +#define KS_GAMMA21 0x55 +#define KS_GAMMA22 0x56 +#define KS_GAMMA23 0x57 +#define KS_GAMMA24 0x58 +#define KS_GAMMA25 0x59 +#define KS_GAMMA26 0x5a +#define KS_GAMMA27 0x5b +#define KS_GAMMA28 0x5c +#define KS_GAMMA29 0x5d +#define KS_GAMMA30 0x5e +#define KS_GAMMA31 0x5f +#define KS_GAMMAD0 0x60 +#define KS_GAMMAD1 0x61 +#define KS_GAMMAD2 0x62 +#define KS_GAMMAD3 0x63 +#define KS_GAMMAD4 0x64 +#define KS_GAMMAD5 0x65 +#define KS_GAMMAD6 0x66 +#define KS_GAMMAD7 0x67 +#define KS_GAMMAD8 0x68 +#define KS_GAMMAD9 0x69 +#define KS_GAMMAD10 0x6a +#define KS_GAMMAD11 0x6b +#define KS_GAMMAD12 0x6c +#define KS_GAMMAD13 0x6d +#define KS_GAMMAD14 0x6e +#define KS_GAMMAD15 0x6f +#define KS_GAMMAD16 0x70 +#define KS_GAMMAD17 0x71 +#define KS_GAMMAD18 0x72 +#define KS_GAMMAD19 0x73 +#define KS_GAMMAD20 0x74 +#define KS_GAMMAD21 0x75 +#define KS_GAMMAD22 0x76 +#define KS_GAMMAD23 0x77 +#define KS_GAMMAD24 0x78 +#define KS_GAMMAD25 0x79 +#define KS_GAMMAD26 0x7a +#define KS_GAMMAD27 0x7b +#define KS_GAMMAD28 0x7c +#define KS_GAMMAD29 0x7d +#define KS_GAMMAD30 0x7e +#define KS_GAMMAD31 0x7f + + +/**************************************************************************** +* mga_dev : represents one ks0127 chip. +****************************************************************************/ + +struct adjust { + int contrast; + int bright; + int hue; + int ugain; + int vgain; +}; + +struct ks0127 { + struct v4l2_subdev sd; + v4l2_std_id norm; + int ident; + u8 regs[256]; +}; + +static inline struct ks0127 *to_ks0127(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ks0127, sd); +} + + +static int debug; /* insmod parameter */ + +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug output"); + +static u8 reg_defaults[64]; + +static void init_reg_defaults(void) +{ + static int initialized; + u8 *table = reg_defaults; + + if (initialized) + return; + initialized = 1; + + table[KS_CMDA] = 0x2c; /* VSE=0, CCIR 601, autodetect standard */ + table[KS_CMDB] = 0x12; /* VALIGN=0, AGC control and input */ + table[KS_CMDC] = 0x00; /* Test options */ + /* clock & input select, write 1 to PORTA */ + table[KS_CMDD] = 0x01; + table[KS_HAVB] = 0x00; /* HAV Start Control */ + table[KS_HAVE] = 0x00; /* HAV End Control */ + table[KS_HS1B] = 0x10; /* HS1 Start Control */ + table[KS_HS1E] = 0x00; /* HS1 End Control */ + table[KS_HS2B] = 0x00; /* HS2 Start Control */ + table[KS_HS2E] = 0x00; /* HS2 End Control */ + table[KS_AGC] = 0x53; /* Manual setting for AGC */ + table[KS_HXTRA] = 0x00; /* Extra Bits for HAV and HS1/2 */ + table[KS_CDEM] = 0x00; /* Chroma Demodulation Control */ + table[KS_PORTAB] = 0x0f; /* port B is input, port A output GPPORT */ + table[KS_LUMA] = 0x01; /* Luma control */ + table[KS_CON] = 0x00; /* Contrast Control */ + table[KS_BRT] = 0x00; /* Brightness Control */ + table[KS_CHROMA] = 0x2a; /* Chroma control A */ + table[KS_CHROMB] = 0x90; /* Chroma control B */ + table[KS_DEMOD] = 0x00; /* Chroma Demodulation Control & Status */ + table[KS_SAT] = 0x00; /* Color Saturation Control*/ + table[KS_HUE] = 0x00; /* Hue Control */ + table[KS_VERTIA] = 0x00; /* Vertical Processing Control A */ + /* Vertical Processing Control B, luma 1 line delayed */ + table[KS_VERTIB] = 0x12; + table[KS_VERTIC] = 0x0b; /* Vertical Processing Control C */ + table[KS_HSCLL] = 0x00; /* Horizontal Scaling Ratio Low */ + table[KS_HSCLH] = 0x00; /* Horizontal Scaling Ratio High */ + table[KS_VSCLL] = 0x00; /* Vertical Scaling Ratio Low */ + table[KS_VSCLH] = 0x00; /* Vertical Scaling Ratio High */ + /* 16 bit YCbCr 4:2:2 output; I can't make the bt866 like 8 bit /Sam */ + table[KS_OFMTA] = 0x30; + table[KS_OFMTB] = 0x00; /* Output Control B */ + /* VBI Decoder Control; 4bit fmt: avoid Y overflow */ + table[KS_VBICTL] = 0x5d; + table[KS_CCDAT2] = 0x00; /* Read Only register */ + table[KS_CCDAT1] = 0x00; /* Read Only register */ + table[KS_VBIL30] = 0xa8; /* VBI data decoding options */ + table[KS_VBIL74] = 0xaa; /* VBI data decoding options */ + table[KS_VBIL118] = 0x2a; /* VBI data decoding options */ + table[KS_VBIL1512] = 0x00; /* VBI data decoding options */ + table[KS_TTFRAM] = 0x00; /* Teletext frame alignment pattern */ + table[KS_TESTA] = 0x00; /* test register, shouldn't be written */ + table[KS_UVOFFH] = 0x00; /* UV Offset Adjustment High */ + table[KS_UVOFFL] = 0x00; /* UV Offset Adjustment Low */ + table[KS_UGAIN] = 0x00; /* U Component Gain Adjustment */ + table[KS_VGAIN] = 0x00; /* V Component Gain Adjustment */ + table[KS_VAVB] = 0x07; /* VAV Begin */ + table[KS_VAVE] = 0x00; /* VAV End */ + table[KS_CTRACK] = 0x00; /* Chroma Tracking Control */ + table[KS_POLCTL] = 0x41; /* Timing Signal Polarity Control */ + table[KS_REFCOD] = 0x80; /* Reference Code Insertion Control */ + table[KS_INVALY] = 0x10; /* Invalid Y Code */ + table[KS_INVALU] = 0x80; /* Invalid U Code */ + table[KS_INVALV] = 0x80; /* Invalid V Code */ + table[KS_UNUSEY] = 0x10; /* Unused Y Code */ + table[KS_UNUSEU] = 0x80; /* Unused U Code */ + table[KS_UNUSEV] = 0x80; /* Unused V Code */ + table[KS_USRSAV] = 0x00; /* reserved */ + table[KS_USREAV] = 0x00; /* reserved */ + table[KS_SHS1A] = 0x00; /* User Defined SHS1 A */ + /* User Defined SHS1 B, ALT656=1 on 0127B */ + table[KS_SHS1B] = 0x80; + table[KS_SHS1C] = 0x00; /* User Defined SHS1 C */ + table[KS_CMDE] = 0x00; /* Command Register E */ + table[KS_VSDEL] = 0x00; /* VS Delay Control */ + /* Command Register F, update -immediately- */ + /* (there might come no vsync)*/ + table[KS_CMDF] = 0x02; +} + + +/* We need to manually read because of a bug in the KS0127 chip. + * + * An explanation from kayork@mail.utexas.edu: + * + * During I2C reads, the KS0127 only samples for a stop condition + * during the place where the acknowledge bit should be. Any standard + * I2C implementation (correctly) throws in another clock transition + * at the 9th bit, and the KS0127 will not recognize the stop condition + * and will continue to clock out data. + * + * So we have to do the read ourself. Big deal. + * workaround in i2c-algo-bit + */ + + +static u8 ks0127_read(struct v4l2_subdev *sd, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + char val = 0; + struct i2c_msg msgs[] = { + { client->addr, 0, sizeof(reg), ® }, + { client->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val } + }; + int ret; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + v4l2_dbg(1, debug, sd, "read error\n"); + + return val; +} + + +static void ks0127_write(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ks0127 *ks = to_ks0127(sd); + char msg[] = { reg, val }; + + if (i2c_master_send(client, msg, sizeof(msg)) != sizeof(msg)) + v4l2_dbg(1, debug, sd, "write error\n"); + + ks->regs[reg] = val; +} + + +/* generic bit-twiddling */ +static void ks0127_and_or(struct v4l2_subdev *sd, u8 reg, u8 and_v, u8 or_v) +{ + struct ks0127 *ks = to_ks0127(sd); + + u8 val = ks->regs[reg]; + val = (val & and_v) | or_v; + ks0127_write(sd, reg, val); +} + + + +/**************************************************************************** +* ks0127 private api +****************************************************************************/ +static void ks0127_init(struct v4l2_subdev *sd) +{ + struct ks0127 *ks = to_ks0127(sd); + u8 *table = reg_defaults; + int i; + + ks->ident = V4L2_IDENT_KS0127; + + v4l2_dbg(1, debug, sd, "reset\n"); + msleep(1); + + /* initialize all registers to known values */ + /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */ + + for (i = 1; i < 33; i++) + ks0127_write(sd, i, table[i]); + + for (i = 35; i < 40; i++) + ks0127_write(sd, i, table[i]); + + for (i = 41; i < 56; i++) + ks0127_write(sd, i, table[i]); + + for (i = 58; i < 64; i++) + ks0127_write(sd, i, table[i]); + + + if ((ks0127_read(sd, KS_STAT) & 0x80) == 0) { + ks->ident = V4L2_IDENT_KS0122S; + v4l2_dbg(1, debug, sd, "ks0122s found\n"); + return; + } + + switch (ks0127_read(sd, KS_CMDE) & 0x0f) { + case 0: + v4l2_dbg(1, debug, sd, "ks0127 found\n"); + break; + + case 9: + ks->ident = V4L2_IDENT_KS0127B; + v4l2_dbg(1, debug, sd, "ks0127B Revision A found\n"); + break; + + default: + v4l2_dbg(1, debug, sd, "unknown revision\n"); + break; + } +} + +static int ks0127_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct ks0127 *ks = to_ks0127(sd); + + switch (input) { + case KS_INPUT_COMPOSITE_1: + case KS_INPUT_COMPOSITE_2: + case KS_INPUT_COMPOSITE_3: + case KS_INPUT_COMPOSITE_4: + case KS_INPUT_COMPOSITE_5: + case KS_INPUT_COMPOSITE_6: + v4l2_dbg(1, debug, sd, + "s_routing %d: Composite\n", input); + /* autodetect 50/60 Hz */ + ks0127_and_or(sd, KS_CMDA, 0xfc, 0x00); + /* VSE=0 */ + ks0127_and_or(sd, KS_CMDA, ~0x40, 0x00); + /* set input line */ + ks0127_and_or(sd, KS_CMDB, 0xb0, input); + /* non-freerunning mode */ + ks0127_and_or(sd, KS_CMDC, 0x70, 0x0a); + /* analog input */ + ks0127_and_or(sd, KS_CMDD, 0x03, 0x00); + /* enable chroma demodulation */ + ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00); + /* chroma trap, HYBWR=1 */ + ks0127_and_or(sd, KS_LUMA, 0x00, + (reg_defaults[KS_LUMA])|0x0c); + /* scaler fullbw, luma comb off */ + ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81); + /* manual chroma comb .25 .5 .25 */ + ks0127_and_or(sd, KS_VERTIC, 0x0f, 0x90); + + /* chroma path delay */ + ks0127_and_or(sd, KS_CHROMB, 0x0f, 0x90); + + ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]); + ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]); + ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]); + ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]); + break; + + case KS_INPUT_SVIDEO_1: + case KS_INPUT_SVIDEO_2: + case KS_INPUT_SVIDEO_3: + v4l2_dbg(1, debug, sd, + "s_routing %d: S-Video\n", input); + /* autodetect 50/60 Hz */ + ks0127_and_or(sd, KS_CMDA, 0xfc, 0x00); + /* VSE=0 */ + ks0127_and_or(sd, KS_CMDA, ~0x40, 0x00); + /* set input line */ + ks0127_and_or(sd, KS_CMDB, 0xb0, input); + /* non-freerunning mode */ + ks0127_and_or(sd, KS_CMDC, 0x70, 0x0a); + /* analog input */ + ks0127_and_or(sd, KS_CMDD, 0x03, 0x00); + /* enable chroma demodulation */ + ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00); + ks0127_and_or(sd, KS_LUMA, 0x00, + reg_defaults[KS_LUMA]); + /* disable luma comb */ + ks0127_and_or(sd, KS_VERTIA, 0x08, + (reg_defaults[KS_VERTIA]&0xf0)|0x01); + ks0127_and_or(sd, KS_VERTIC, 0x0f, + reg_defaults[KS_VERTIC]&0xf0); + + ks0127_and_or(sd, KS_CHROMB, 0x0f, + reg_defaults[KS_CHROMB]&0xf0); + + ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]); + ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]); + ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]); + ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]); + break; + + case KS_INPUT_YUV656: + v4l2_dbg(1, debug, sd, "s_routing 15: YUV656\n"); + if (ks->norm & V4L2_STD_525_60) + /* force 60 Hz */ + ks0127_and_or(sd, KS_CMDA, 0xfc, 0x03); + else + /* force 50 Hz */ + ks0127_and_or(sd, KS_CMDA, 0xfc, 0x02); + + ks0127_and_or(sd, KS_CMDA, 0xff, 0x40); /* VSE=1 */ + /* set input line and VALIGN */ + ks0127_and_or(sd, KS_CMDB, 0xb0, (input | 0x40)); + /* freerunning mode, */ + /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/ + ks0127_and_or(sd, KS_CMDC, 0x70, 0x87); + /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */ + ks0127_and_or(sd, KS_CMDD, 0x03, 0x08); + /* disable chroma demodulation */ + ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x30); + /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */ + ks0127_and_or(sd, KS_LUMA, 0x00, 0x71); + ks0127_and_or(sd, KS_VERTIC, 0x0f, + reg_defaults[KS_VERTIC]&0xf0); + + /* scaler fullbw, luma comb off */ + ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81); + + ks0127_and_or(sd, KS_CHROMB, 0x0f, + reg_defaults[KS_CHROMB]&0xf0); + + ks0127_and_or(sd, KS_CON, 0x00, 0x00); + ks0127_and_or(sd, KS_BRT, 0x00, 32); /* spec: 34 */ + /* spec: 229 (e5) */ + ks0127_and_or(sd, KS_SAT, 0x00, 0xe8); + ks0127_and_or(sd, KS_HUE, 0x00, 0); + + ks0127_and_or(sd, KS_UGAIN, 0x00, 238); + ks0127_and_or(sd, KS_VGAIN, 0x00, 0x00); + + /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */ + ks0127_and_or(sd, KS_UVOFFH, 0x00, 0x4f); + ks0127_and_or(sd, KS_UVOFFL, 0x00, 0x00); + break; + + default: + v4l2_dbg(1, debug, sd, + "s_routing: Unknown input %d\n", input); + break; + } + + /* hack: CDMLPF sometimes spontaneously switches on; */ + /* force back off */ + ks0127_write(sd, KS_DEMOD, reg_defaults[KS_DEMOD]); + return 0; +} + +static int ks0127_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct ks0127 *ks = to_ks0127(sd); + + /* Set to automatic SECAM/Fsc mode */ + ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00); + + ks->norm = std; + if (std & V4L2_STD_NTSC) { + v4l2_dbg(1, debug, sd, + "s_std: NTSC_M\n"); + ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20); + } else if (std & V4L2_STD_PAL_N) { + v4l2_dbg(1, debug, sd, + "s_std: NTSC_N (fixme)\n"); + ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40); + } else if (std & V4L2_STD_PAL) { + v4l2_dbg(1, debug, sd, + "s_std: PAL_N\n"); + ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20); + } else if (std & V4L2_STD_PAL_M) { + v4l2_dbg(1, debug, sd, + "s_std: PAL_M (fixme)\n"); + ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40); + } else if (std & V4L2_STD_SECAM) { + v4l2_dbg(1, debug, sd, + "s_std: SECAM\n"); + + /* set to secam autodetection */ + ks0127_and_or(sd, KS_CHROMA, 0xdf, 0x20); + ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00); + schedule_timeout_interruptible(HZ/10+1); + + /* did it autodetect? */ + if (!(ks0127_read(sd, KS_DEMOD) & 0x40)) + /* force to secam mode */ + ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x0f); + } else { + v4l2_dbg(1, debug, sd, "s_std: Unknown norm %llx\n", + (unsigned long long)std); + } + return 0; +} + +static int ks0127_s_stream(struct v4l2_subdev *sd, int enable) +{ + v4l2_dbg(1, debug, sd, "s_stream(%d)\n", enable); + if (enable) { + /* All output pins on */ + ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x30); + /* Obey the OEN pin */ + ks0127_and_or(sd, KS_CDEM, 0x7f, 0x00); + } else { + /* Video output pins off */ + ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x00); + /* Ignore the OEN pin */ + ks0127_and_or(sd, KS_CDEM, 0x7f, 0x80); + } + return 0; +} + +static int ks0127_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) +{ + int stat = V4L2_IN_ST_NO_SIGNAL; + u8 status; + v4l2_std_id std = V4L2_STD_ALL; + + status = ks0127_read(sd, KS_STAT); + if (!(status & 0x20)) /* NOVID not set */ + stat = 0; + if (!(status & 0x01)) /* CLOCK set */ + stat |= V4L2_IN_ST_NO_COLOR; + if ((status & 0x08)) /* PALDET set */ + std = V4L2_STD_PAL; + else + std = V4L2_STD_NTSC; + if (pstd) + *pstd = std; + if (pstatus) + *pstatus = stat; + return 0; +} + +static int ks0127_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + v4l2_dbg(1, debug, sd, "querystd\n"); + return ks0127_status(sd, NULL, std); +} + +static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + v4l2_dbg(1, debug, sd, "g_input_status\n"); + return ks0127_status(sd, status, NULL); +} + +static int ks0127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ks0127 *ks = to_ks0127(sd); + + return v4l2_chip_ident_i2c_client(client, chip, ks->ident, 0); +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops ks0127_core_ops = { + .g_chip_ident = ks0127_g_chip_ident, + .s_std = ks0127_s_std, +}; + +static const struct v4l2_subdev_video_ops ks0127_video_ops = { + .s_routing = ks0127_s_routing, + .s_stream = ks0127_s_stream, + .querystd = ks0127_querystd, + .g_input_status = ks0127_g_input_status, +}; + +static const struct v4l2_subdev_ops ks0127_ops = { + .core = &ks0127_core_ops, + .video = &ks0127_video_ops, +}; + +/* ----------------------------------------------------------------------- */ + + +static int ks0127_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct ks0127 *ks; + struct v4l2_subdev *sd; + + v4l_info(client, "%s chip found @ 0x%x (%s)\n", + client->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board", + client->addr << 1, client->adapter->name); + + ks = kzalloc(sizeof(*ks), GFP_KERNEL); + if (ks == NULL) + return -ENOMEM; + sd = &ks->sd; + v4l2_i2c_subdev_init(sd, client, &ks0127_ops); + + /* power up */ + init_reg_defaults(); + ks0127_write(sd, KS_CMDA, 0x2c); + mdelay(10); + + /* reset the device */ + ks0127_init(sd); + return 0; +} + +static int ks0127_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + ks0127_write(sd, KS_OFMTA, 0x20); /* tristate */ + ks0127_write(sd, KS_CMDA, 0x2c | 0x80); /* power down */ + kfree(to_ks0127(sd)); + return 0; +} + +static const struct i2c_device_id ks0127_id[] = { + { "ks0127", 0 }, + { "ks0127b", 0 }, + { "ks0122s", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ks0127_id); + +static struct i2c_driver ks0127_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ks0127", + }, + .probe = ks0127_probe, + .remove = ks0127_remove, + .id_table = ks0127_id, +}; + +static __init int init_ks0127(void) +{ + return i2c_add_driver(&ks0127_driver); +} + +static __exit void exit_ks0127(void) +{ + i2c_del_driver(&ks0127_driver); +} + +module_init(init_ks0127); +module_exit(exit_ks0127); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ks0127.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ks0127.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ks0127.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/ks0127.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Video Capture Driver ( Video for Linux 1/2 ) + * for the Matrox Marvel G200,G400 and Rainbow Runner-G series + * + * This module is an interface to the KS0127 video decoder chip. + * + * Copyright (C) 1999 Ryan Drake + * + * 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, or (at your option) any later version. + * + * 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. + */ + +#ifndef KS0127_H +#define KS0127_H + +/* input channels */ +#define KS_INPUT_COMPOSITE_1 0 +#define KS_INPUT_COMPOSITE_2 1 +#define KS_INPUT_COMPOSITE_3 2 +#define KS_INPUT_COMPOSITE_4 4 +#define KS_INPUT_COMPOSITE_5 5 +#define KS_INPUT_COMPOSITE_6 6 + +#define KS_INPUT_SVIDEO_1 8 +#define KS_INPUT_SVIDEO_2 9 +#define KS_INPUT_SVIDEO_3 10 + +#define KS_INPUT_YUV656 15 +#define KS_INPUT_COUNT 10 + +/* output channels */ +#define KS_OUTPUT_YUV656E 0 +#define KS_OUTPUT_EXV 1 + +/* video standards */ +#define KS_STD_NTSC_N 112 /* 50 Hz NTSC */ +#define KS_STD_PAL_M 113 /* 60 Hz PAL */ + +#endif /* KS0127_H */ + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m52790.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m52790.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m52790.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m52790.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,227 @@ +/* + * m52790 i2c ivtv driver. + * Copyright (C) 2007 Hans Verkuil + * + * A/V source switching Mitsubishi M52790SP/FP + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + + +struct m52790_state { + struct v4l2_subdev sd; + u16 input; + u16 output; +}; + +static inline struct m52790_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct m52790_state, sd); +} + +/* ----------------------------------------------------------------------- */ + +static int m52790_write(struct v4l2_subdev *sd) +{ + struct m52790_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + u8 sw1 = (state->input | state->output) & 0xff; + u8 sw2 = (state->input | state->output) >> 8; + + return i2c_smbus_write_byte_data(client, sw1, sw2); +} + +/* Note: audio and video are linked and cannot be switched separately. + So audio and video routing commands are identical for this chip. + In theory the video amplifier and audio modes could be handled + separately for the output, but that seems to be overkill right now. + The same holds for implementing an audio mute control, this is now + part of the audio output routing. The normal case is that another + chip takes care of the actual muting so making it part of the + output routing seems to be the right thing to do for now. */ +static int m52790_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct m52790_state *state = to_state(sd); + + state->input = input; + state->output = output; + m52790_write(sd); + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +{ + struct m52790_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (reg->reg != 0) + return -EINVAL; + reg->size = 1; + reg->val = state->input | state->output; + return 0; +} + +static int m52790_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +{ + struct m52790_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (reg->reg != 0) + return -EINVAL; + state->input = reg->val & 0x0303; + state->output = reg->val & ~0x0303; + m52790_write(sd); + return 0; +} +#endif + +static int m52790_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_M52790, 0); +} + +static int m52790_log_status(struct v4l2_subdev *sd) +{ + struct m52790_state *state = to_state(sd); + + v4l2_info(sd, "Switch 1: %02x\n", + (state->input | state->output) & 0xff); + v4l2_info(sd, "Switch 2: %02x\n", + (state->input | state->output) >> 8); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops m52790_core_ops = { + .log_status = m52790_log_status, + .g_chip_ident = m52790_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = m52790_g_register, + .s_register = m52790_s_register, +#endif +}; + +static const struct v4l2_subdev_audio_ops m52790_audio_ops = { + .s_routing = m52790_s_routing, +}; + +static const struct v4l2_subdev_video_ops m52790_video_ops = { + .s_routing = m52790_s_routing, +}; + +static const struct v4l2_subdev_ops m52790_ops = { + .core = &m52790_core_ops, + .audio = &m52790_audio_ops, + .video = &m52790_video_ops, +}; + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +static int m52790_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct m52790_state *state; + struct v4l2_subdev *sd; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kzalloc(sizeof(struct m52790_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &m52790_ops); + state->input = M52790_IN_TUNER; + state->output = M52790_OUT_STEREO; + m52790_write(sd); + return 0; +} + +static int m52790_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id m52790_id[] = { + { "m52790", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, m52790_id); + +static struct i2c_driver m52790_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "m52790", + }, + .probe = m52790_probe, + .remove = m52790_remove, + .id_table = m52790_id, +}; + +static __init int init_m52790(void) +{ + return i2c_add_driver(&m52790_driver); +} + +static __exit void exit_m52790(void) +{ + i2c_del_driver(&m52790_driver); +} + +module_init(init_m52790); +module_exit(exit_m52790); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,5 @@ +config VIDEO_M5MOLS + tristate "Fujitsu M-5MOLS 8MP sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + ---help--- + This driver supports Fujitsu M-5MOLS camera sensor with ISP diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_capture.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_capture.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_capture.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_capture.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,191 @@ +/* + * The Capture code for Fujitsu M-5MOLS ISP + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Author: HeungJun Kim, riverful.kim@samsung.com + * + * Copyright (C) 2009 Samsung Electronics Co., Ltd. + * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "m5mols.h" +#include "m5mols_reg.h" + +static int m5mols_capture_error_handler(struct m5mols_info *info, + int timeout) +{ + int ret; + + /* Disable all interrupts and clear relevant interrupt staus bits */ + ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE, + info->interrupt & ~(REG_INT_CAPTURE)); + if (ret) + return ret; + + if (timeout == 0) + return -ETIMEDOUT; + + return 0; +} +/** + * m5mols_read_rational - I2C read of a rational number + * + * Read numerator and denominator from registers @addr_num and @addr_den + * respectively and return the division result in @val. + */ +static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num, + u32 addr_den, u32 *val) +{ + u32 num, den; + + int ret = m5mols_read(sd, addr_num, &num); + if (!ret) + ret = m5mols_read(sd, addr_den, &den); + if (ret) + return ret; + *val = den == 0 ? 0 : num / den; + return ret; +} + +/** + * m5mols_capture_info - Gather captured image information + * + * For now it gathers only EXIF information and file size. + */ +static int m5mols_capture_info(struct m5mols_info *info) +{ + struct m5mols_exif *exif = &info->cap.exif; + struct v4l2_subdev *sd = &info->sd; + int ret; + + ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU, + EXIF_INFO_EXPTIME_DE, &exif->exposure_time); + if (ret) + return ret; + ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE, + &exif->shutter_speed); + if (ret) + return ret; + ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE, + &exif->aperture); + if (ret) + return ret; + ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE, + &exif->brightness); + if (ret) + return ret; + ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE, + &exif->exposure_bias); + if (ret) + return ret; + + ret = m5mols_read(sd, EXIF_INFO_ISO, (u32 *)&exif->iso_speed); + if (!ret) + ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash); + if (!ret) + ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr); + if (!ret) + ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval); + if (ret) + return ret; + + if (!ret) + ret = m5mols_read(sd, CAPC_IMAGE_SIZE, &info->cap.main); + if (!ret) + ret = m5mols_read(sd, CAPC_THUMB_SIZE, &info->cap.thumb); + if (!ret) + info->cap.total = info->cap.main + info->cap.thumb; + + return ret; +} + +int m5mols_start_capture(struct m5mols_info *info) +{ + struct v4l2_subdev *sd = &info->sd; + u32 resolution = info->resolution; + int timeout; + int ret; + + /* + * Preparing capture. Setting control & interrupt before entering + * capture mode + * + * 1) change to MONITOR mode for operating control & interrupt + * 2) set controls (considering v4l2_control value & lock 3A) + * 3) set interrupt + * 4) change to CAPTURE mode + */ + ret = m5mols_mode(info, REG_MONITOR); + if (!ret) + ret = m5mols_sync_controls(info); + if (!ret) + ret = m5mols_lock_3a(info, true); + if (!ret) + ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); + if (!ret) + ret = m5mols_mode(info, REG_CAPTURE); + if (!ret) { + /* Wait for capture interrupt, after changing capture mode */ + timeout = wait_event_interruptible_timeout(info->irq_waitq, + test_bit(ST_CAPT_IRQ, &info->flags), + msecs_to_jiffies(2000)); + if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) + ret = m5mols_capture_error_handler(info, timeout); + } + if (!ret) + ret = m5mols_lock_3a(info, false); + if (ret) + return ret; + /* + * Starting capture. Setting capture frame count and resolution and + * the format(available format: JPEG, Bayer RAW, YUV). + * + * 1) select single or multi(enable to 25), format, size + * 2) set interrupt + * 3) start capture(for main image, now) + * 4) get information + * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device) + */ + ret = m5mols_write(sd, CAPC_SEL_FRAME, 1); + if (!ret) + ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); + if (!ret) + ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution); + if (!ret) + ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); + if (!ret) + ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); + if (!ret) { + /* Wait for the capture completion interrupt */ + timeout = wait_event_interruptible_timeout(info->irq_waitq, + test_bit(ST_CAPT_IRQ, &info->flags), + msecs_to_jiffies(2000)); + if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) { + ret = m5mols_capture_info(info); + if (!ret) + v4l2_subdev_notify(sd, 0, &info->cap.total); + } + } + + return m5mols_capture_error_handler(info, timeout); +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_controls.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_controls.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_controls.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_controls.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,299 @@ +/* + * Controls for M-5MOLS 8M Pixel camera sensor with ISP + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Author: HeungJun Kim, riverful.kim@samsung.com + * + * Copyright (C) 2009 Samsung Electronics Co., Ltd. + * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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, or + * (at your option) any later version. + */ + +#include +#include +#include +#include + +#include "m5mols.h" +#include "m5mols_reg.h" + +static struct m5mols_scenemode m5mols_default_scenemode[] = { + [REG_SCENE_NORMAL] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF, + 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_PORTRAIT] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 4, + REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_LANDSCAPE] = { + REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 4, REG_EDGE_ON, 6, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_SPORTS] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_PARTY_INDOOR] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 4, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_BEACH_SNOW] = { + REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 4, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_SUNSET] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, + REG_AWB_DAYLIGHT, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_DAWN_DUSK] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, + REG_AWB_FLUORESCENT_1, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_FALL] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 5, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_NIGHT] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_AGAINST_LIGHT] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_FIRE] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, + }, + [REG_SCENE_TEXT] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 7, + REG_AF_MACRO, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON, + }, + [REG_SCENE_CANDLE] = { + REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, + REG_CHROMA_ON, 3, REG_EDGE_ON, 5, + REG_AF_NORMAL, REG_FD_OFF, + REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, + 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, + }, +}; + +/** + * m5mols_do_scenemode() - Change current scenemode + * @mode: Desired mode of the scenemode + * + * WARNING: The execution order is important. Do not change the order. + */ +int m5mols_do_scenemode(struct m5mols_info *info, u32 mode) +{ + struct v4l2_subdev *sd = &info->sd; + struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode]; + int ret; + + if (mode > REG_SCENE_CANDLE) + return -EINVAL; + + ret = m5mols_lock_3a(info, false); + if (!ret) + ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode); + if (!ret) + ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode); + if (!ret) + ret = m5mols_write(sd, AE_MODE, scenemode.metering); + if (!ret) + ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias); + if (!ret) + ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode); + if (!ret) + ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset); + if (!ret) + ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en); + if (!ret) + ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl); + if (!ret) + ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en); + if (!ret) + ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl); + if (!ret && is_available_af(info)) + ret = m5mols_write(sd, AF_MODE, scenemode.af_range); + if (!ret && is_available_af(info)) + ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode); + if (!ret) + ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone); + if (!ret) + ret = m5mols_write(sd, AE_ISO, scenemode.iso); + if (!ret) + ret = m5mols_mode(info, REG_CAPTURE); + if (!ret) + ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); + if (!ret) + ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc); + if (!ret) + ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light); + if (!ret) + ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash); + if (!ret) + ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); + if (!ret) + ret = m5mols_mode(info, REG_MONITOR); + + return ret; +} + +static int m5mols_lock_ae(struct m5mols_info *info, bool lock) +{ + int ret = 0; + + if (info->lock_ae != lock) + ret = m5mols_write(&info->sd, AE_LOCK, + lock ? REG_AE_LOCK : REG_AE_UNLOCK); + if (!ret) + info->lock_ae = lock; + + return ret; +} + +static int m5mols_lock_awb(struct m5mols_info *info, bool lock) +{ + int ret = 0; + + if (info->lock_awb != lock) + ret = m5mols_write(&info->sd, AWB_LOCK, + lock ? REG_AWB_LOCK : REG_AWB_UNLOCK); + if (!ret) + info->lock_awb = lock; + + return ret; +} + +/* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */ +int m5mols_lock_3a(struct m5mols_info *info, bool lock) +{ + int ret; + + ret = m5mols_lock_ae(info, lock); + if (!ret) + ret = m5mols_lock_awb(info, lock); + /* Don't need to handle unlocking AF */ + if (!ret && is_available_af(info) && lock) + ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); + + return ret; +} + +/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */ +int m5mols_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct m5mols_info *info = to_m5mols(sd); + int ret; + + switch (ctrl->id) { + case V4L2_CID_ZOOM_ABSOLUTE: + return m5mols_write(sd, MON_ZOOM, ctrl->val); + + case V4L2_CID_EXPOSURE_AUTO: + ret = m5mols_lock_ae(info, + ctrl->val == V4L2_EXPOSURE_AUTO ? false : true); + if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO) + ret = m5mols_write(sd, AE_MODE, REG_AE_ALL); + if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) { + int val = info->exposure->val; + ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); + if (!ret) + ret = m5mols_write(sd, AE_MAN_GAIN_MON, val); + if (!ret) + ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val); + } + return ret; + + case V4L2_CID_AUTO_WHITE_BALANCE: + ret = m5mols_lock_awb(info, ctrl->val ? false : true); + if (!ret) + ret = m5mols_write(sd, AWB_MODE, ctrl->val ? + REG_AWB_AUTO : REG_AWB_PRESET); + return ret; + + case V4L2_CID_SATURATION: + ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val); + if (!ret) + ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON); + return ret; + + case V4L2_CID_COLORFX: + /* + * This control uses two kinds of registers: normal & color. + * The normal effect belongs to category 1, while the color + * one belongs to category 2. + * + * The normal effect uses one register: CAT1_EFFECT. + * The color effect uses three registers: + * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB. + */ + ret = m5mols_write(sd, PARM_EFFECT, + ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA : + ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS : + REG_EFFECT_OFF); + if (!ret) + ret = m5mols_write(sd, MON_EFFECT, + ctrl->val == V4L2_COLORFX_SEPIA ? + REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF); + if (!ret) + ret = m5mols_write(sd, MON_CFIXR, + ctrl->val == V4L2_COLORFX_SEPIA ? + REG_CFIXR_SEPIA : 0); + if (!ret) + ret = m5mols_write(sd, MON_CFIXB, + ctrl->val == V4L2_COLORFX_SEPIA ? + REG_CFIXB_SEPIA : 0); + return ret; + } + + return -EINVAL; +} diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_core.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1004 @@ +/* + * Driver for M-5MOLS 8M Pixel camera sensor with ISP + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Author: HeungJun Kim, riverful.kim@samsung.com + * + * Copyright (C) 2009 Samsung Electronics Co., Ltd. + * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "m5mols.h" +#include "m5mols_reg.h" + +int m5mols_debug; +module_param(m5mols_debug, int, 0644); + +#define MODULE_NAME "M5MOLS" +#define M5MOLS_I2C_CHECK_RETRY 500 + +/* The regulator consumer names for external voltage regulators */ +static struct regulator_bulk_data supplies[] = { + { + .supply = "core", /* ARM core power, 1.2V */ + }, { + .supply = "dig_18", /* digital power 1, 1.8V */ + }, { + .supply = "d_sensor", /* sensor power 1, 1.8V */ + }, { + .supply = "dig_28", /* digital power 2, 2.8V */ + }, { + .supply = "a_sensor", /* analog power */ + }, { + .supply = "dig_12", /* digital power 3, 1.2V */ + }, +}; + +static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = { + [M5MOLS_RESTYPE_MONITOR] = { + .width = 1920, + .height = 1080, + .code = V4L2_MBUS_FMT_VYUY8_2X8, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_JPEG, + }, + [M5MOLS_RESTYPE_CAPTURE] = { + .width = 1920, + .height = 1080, + .code = V4L2_MBUS_FMT_JPEG_1X8, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_JPEG, + }, +}; +#define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt) + +static const struct m5mols_resolution m5mols_reg_res[] = { + { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */ + { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */ + { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */ + { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 }, + { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */ + { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */ + { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */ + { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */ + { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */ + { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 }, + { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */ + { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */ + { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 }, + { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */ + { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */ + { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */ + { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */ + { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */ + { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */ + + { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */ + { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */ + { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 }, + { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */ + { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */ + { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */ + { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */ + { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */ + { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */ + { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */ + { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */ + { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 }, + { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */ + { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 }, + { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */ + { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */ + { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 }, + { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */ +}; + +/** + * m5mols_swap_byte - an byte array to integer conversion function + * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet + * + * Convert I2C data byte array with performing any required byte + * reordering to assure proper values for each data type, regardless + * of the architecture endianness. + */ +static u32 m5mols_swap_byte(u8 *data, u8 length) +{ + if (length == 1) + return *data; + else if (length == 2) + return be16_to_cpu(*((u16 *)data)); + else + return be32_to_cpu(*((u32 *)data)); +} + +/** + * m5mols_read - I2C read function + * @reg: combination of size, category and command for the I2C packet + * @val: read value + */ +int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; + u8 size = I2C_SIZE(reg); + u8 category = I2C_CATEGORY(reg); + u8 cmd = I2C_COMMAND(reg); + struct i2c_msg msg[2]; + u8 wbuf[5]; + int ret; + + if (!client->adapter) + return -ENODEV; + + if (size != 1 && size != 2 && size != 4) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 5; + msg[0].buf = wbuf; + wbuf[0] = 5; + wbuf[1] = M5MOLS_BYTE_READ; + wbuf[2] = category; + wbuf[3] = cmd; + wbuf[4] = size; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = size + 1; + msg[1].buf = rbuf; + + /* minimum stabilization time */ + usleep_range(200, 200); + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) { + v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", + size, category, cmd, ret); + return ret; + } + + *val = m5mols_swap_byte(&rbuf[1], size); + + return 0; +} + +/** + * m5mols_write - I2C command write function + * @reg: combination of size, category and command for the I2C packet + * @val: value to write + */ +int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; + u8 category = I2C_CATEGORY(reg); + u8 cmd = I2C_COMMAND(reg); + u8 size = I2C_SIZE(reg); + u32 *buf = (u32 *)&wbuf[4]; + struct i2c_msg msg[1]; + int ret; + + if (!client->adapter) + return -ENODEV; + + if (size != 1 && size != 2 && size != 4) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + msg->addr = client->addr; + msg->flags = 0; + msg->len = (u16)size + 4; + msg->buf = wbuf; + wbuf[0] = size + 4; + wbuf[1] = M5MOLS_BYTE_WRITE; + wbuf[2] = category; + wbuf[3] = cmd; + + *buf = m5mols_swap_byte((u8 *)&val, size); + + usleep_range(200, 200); + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret < 0) { + v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n", + size, category, cmd, ret); + return ret; + } + + return 0; +} + +int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask) +{ + u32 busy, i; + int ret; + + for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { + ret = m5mols_read(sd, I2C_REG(category, cmd, 1), &busy); + if (ret < 0) + return ret; + if ((busy & mask) == mask) + return 0; + } + return -EBUSY; +} + +/** + * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts + * + * Before writing desired interrupt value the INT_FACTOR register should + * be read to clear pending interrupts. + */ +int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg) +{ + struct m5mols_info *info = to_m5mols(sd); + u32 mask = is_available_af(info) ? REG_INT_AF : 0; + u32 dummy; + int ret; + + ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy); + if (!ret) + ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); + return ret; +} + +/** + * m5mols_reg_mode - Write the mode and check busy status + * + * It always accompanies a little delay changing the M-5MOLS mode, so it is + * needed checking current busy status to guarantee right mode. + */ +static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode) +{ + int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); + + return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode); +} + +/** + * m5mols_mode - manage the M-5MOLS's mode + * @mode: the required operation mode + * + * The commands of M-5MOLS are grouped into specific modes. Each functionality + * can be guaranteed only when the sensor is operating in mode which which + * a command belongs to. + */ +int m5mols_mode(struct m5mols_info *info, u32 mode) +{ + struct v4l2_subdev *sd = &info->sd; + int ret = -EINVAL; + u32 reg; + + if (mode < REG_PARAMETER && mode > REG_CAPTURE) + return ret; + + ret = m5mols_read(sd, SYSTEM_SYSMODE, ®); + if ((!ret && reg == mode) || ret) + return ret; + + switch (reg) { + case REG_PARAMETER: + ret = m5mols_reg_mode(sd, REG_MONITOR); + if (!ret && mode == REG_MONITOR) + break; + if (!ret) + ret = m5mols_reg_mode(sd, REG_CAPTURE); + break; + + case REG_MONITOR: + if (mode == REG_PARAMETER) { + ret = m5mols_reg_mode(sd, REG_PARAMETER); + break; + } + + ret = m5mols_reg_mode(sd, REG_CAPTURE); + break; + + case REG_CAPTURE: + ret = m5mols_reg_mode(sd, REG_MONITOR); + if (!ret && mode == REG_MONITOR) + break; + if (!ret) + ret = m5mols_reg_mode(sd, REG_PARAMETER); + break; + + default: + v4l2_warn(sd, "Wrong mode: %d\n", mode); + } + + if (!ret) + info->mode = mode; + + return ret; +} + +/** + * m5mols_get_version - retrieve full revisions information of M-5MOLS + * + * The version information includes revisions of hardware and firmware, + * AutoFocus alghorithm version and the version string. + */ +static int m5mols_get_version(struct v4l2_subdev *sd) +{ + struct m5mols_info *info = to_m5mols(sd); + union { + struct m5mols_version ver; + u8 bytes[VERSION_SIZE]; + } version; + u32 *value; + u8 cmd = CAT0_VER_CUSTOMER; + int ret; + + do { + value = (u32 *)&version.bytes[cmd]; + ret = m5mols_read(sd, SYSTEM_CMD(cmd), value); + if (ret) + return ret; + } while (cmd++ != CAT0_VER_AWB); + + do { + value = (u32 *)&version.bytes[cmd]; + ret = m5mols_read(sd, SYSTEM_VER_STRING, value); + if (ret) + return ret; + if (cmd >= VERSION_SIZE - 1) + return -EINVAL; + } while (version.bytes[cmd++]); + + value = (u32 *)&version.bytes[cmd]; + ret = m5mols_read(sd, AF_VERSION, value); + if (ret) + return ret; + + /* store version information swapped for being readable */ + info->ver = version.ver; + info->ver.fw = be16_to_cpu(info->ver.fw); + info->ver.hw = be16_to_cpu(info->ver.hw); + info->ver.param = be16_to_cpu(info->ver.param); + info->ver.awb = be16_to_cpu(info->ver.awb); + + v4l2_info(sd, "Manufacturer\t[%s]\n", + is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? + "Samsung Electro-Machanics" : + is_manufacturer(info, REG_SAMSUNG_OPTICS) ? + "Samsung Fiber-Optics" : + is_manufacturer(info, REG_SAMSUNG_TECHWIN) ? + "Samsung Techwin" : "None"); + v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n", + info->ver.customer, info->ver.project); + + if (!is_available_af(info)) + v4l2_info(sd, "No support Auto Focus on this firmware\n"); + + return ret; +} + +/** + * __find_restype - Lookup M-5MOLS resolution type according to pixel code + * @code: pixel code + */ +static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code) +{ + enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR; + + do { + if (code == m5mols_default_ffmt[type].code) + return type; + } while (type++ != SIZE_DEFAULT_FFMT); + + return 0; +} + +/** + * __find_resolution - Lookup preset and type of M-5MOLS's resolution + * @mf: pixel format to find/negotiate the resolution preset for + * @type: M-5MOLS resolution type + * @resolution: M-5MOLS resolution preset register value + * + * Find nearest resolution matching resolution preset and adjust mf + * to supported values. + */ +static int __find_resolution(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf, + enum m5mols_restype *type, + u32 *resolution) +{ + const struct m5mols_resolution *fsize = &m5mols_reg_res[0]; + const struct m5mols_resolution *match = NULL; + enum m5mols_restype stype = __find_restype(mf->code); + int i = ARRAY_SIZE(m5mols_reg_res); + unsigned int min_err = ~0; + + while (i--) { + int err; + if (stype == fsize->type) { + err = abs(fsize->width - mf->width) + + abs(fsize->height - mf->height); + + if (err < min_err) { + min_err = err; + match = fsize; + } + } + fsize++; + } + if (match) { + mf->width = match->width; + mf->height = match->height; + *resolution = match->reg; + *type = stype; + return 0; + } + + return -EINVAL; +} + +static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, + struct v4l2_subdev_fh *fh, + enum v4l2_subdev_format_whence which, + enum m5mols_restype type) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; + + return &info->ffmt[type]; +} + +static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct m5mols_info *info = to_m5mols(sd); + struct v4l2_mbus_framefmt *format; + + if (fmt->pad != 0) + return -EINVAL; + + format = __find_format(info, fh, fmt->which, info->res_type); + if (!format) + return -EINVAL; + + fmt->format = *format; + return 0; +} + +static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct m5mols_info *info = to_m5mols(sd); + struct v4l2_mbus_framefmt *format = &fmt->format; + struct v4l2_mbus_framefmt *sfmt; + enum m5mols_restype type; + u32 resolution = 0; + int ret; + + if (fmt->pad != 0) + return -EINVAL; + + ret = __find_resolution(sd, format, &type, &resolution); + if (ret < 0) + return ret; + + sfmt = __find_format(info, fh, fmt->which, type); + if (!sfmt) + return 0; + + *sfmt = m5mols_default_ffmt[type]; + sfmt->width = format->width; + sfmt->height = format->height; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + info->resolution = resolution; + info->code = format->code; + info->res_type = type; + } + + return 0; +} + +static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (!code || code->index >= SIZE_DEFAULT_FFMT) + return -EINVAL; + + code->code = m5mols_default_ffmt[code->index].code; + + return 0; +} + +static struct v4l2_subdev_pad_ops m5mols_pad_ops = { + .enum_mbus_code = m5mols_enum_mbus_code, + .get_fmt = m5mols_get_fmt, + .set_fmt = m5mols_set_fmt, +}; + +/** + * m5mols_sync_controls - Apply default scene mode and the current controls + * + * This is used only streaming for syncing between v4l2_ctrl framework and + * m5mols's controls. First, do the scenemode to the sensor, then call + * v4l2_ctrl_handler_setup. It can be same between some commands and + * the scenemode's in the default v4l2_ctrls. But, such commands of control + * should be prior to the scenemode's one. + */ +int m5mols_sync_controls(struct m5mols_info *info) +{ + int ret = -EINVAL; + + if (!is_ctrl_synced(info)) { + ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); + if (ret) + return ret; + + v4l2_ctrl_handler_setup(&info->handle); + info->ctrl_sync = true; + } + + return ret; +} + +/** + * m5mols_start_monitor - Start the monitor mode + * + * Before applying the controls setup the resolution and frame rate + * in PARAMETER mode, and then switch over to MONITOR mode. + */ +static int m5mols_start_monitor(struct m5mols_info *info) +{ + struct v4l2_subdev *sd = &info->sd; + int ret; + + ret = m5mols_mode(info, REG_PARAMETER); + if (!ret) + ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); + if (!ret) + ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); + if (!ret) + ret = m5mols_mode(info, REG_MONITOR); + if (!ret) + ret = m5mols_sync_controls(info); + + return ret; +} + +static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct m5mols_info *info = to_m5mols(sd); + + if (enable) { + int ret = -EINVAL; + + if (is_code(info->code, M5MOLS_RESTYPE_MONITOR)) + ret = m5mols_start_monitor(info); + if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE)) + ret = m5mols_start_capture(info); + + return ret; + } + + return m5mols_mode(info, REG_PARAMETER); +} + +static const struct v4l2_subdev_video_ops m5mols_video_ops = { + .s_stream = m5mols_s_stream, +}; + +static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct m5mols_info *info = to_m5mols(sd); + int ret; + + info->mode_save = info->mode; + + ret = m5mols_mode(info, REG_PARAMETER); + if (!ret) + ret = m5mols_set_ctrl(ctrl); + if (!ret) + ret = m5mols_mode(info, info->mode_save); + + return ret; +} + +static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { + .s_ctrl = m5mols_s_ctrl, +}; + +static int m5mols_sensor_power(struct m5mols_info *info, bool enable) +{ + struct v4l2_subdev *sd = &info->sd; + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct m5mols_platform_data *pdata = info->pdata; + int ret; + + if (enable) { + if (is_powered(info)) + return 0; + + if (info->set_power) { + ret = info->set_power(&client->dev, 1); + if (ret) + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); + if (ret) { + info->set_power(&client->dev, 0); + return ret; + } + + gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); + usleep_range(1000, 1000); + info->power = true; + + return ret; + } + + if (!is_powered(info)) + return 0; + + ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); + if (ret) + return ret; + + if (info->set_power) + info->set_power(&client->dev, 0); + + gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); + usleep_range(1000, 1000); + info->power = false; + + return ret; +} + +/* m5mols_update_fw - optional firmware update routine */ +int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, + int (*set_power)(struct m5mols_info *, bool)) +{ + return 0; +} + +/** + * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core. + * + * Booting internal ARM core makes the M-5MOLS is ready for getting commands + * with I2C. It's the first thing to be done after it powered up. It must wait + * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting. + */ +static int m5mols_sensor_armboot(struct v4l2_subdev *sd) +{ + int ret; + + ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); + if (ret < 0) + return ret; + + msleep(520); + + ret = m5mols_get_version(sd); + if (!ret) + ret = m5mols_update_fw(sd, m5mols_sensor_power); + if (ret) + return ret; + + v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); + + ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); + if (!ret) + ret = m5mols_enable_interrupt(sd, REG_INT_AF); + + return ret; +} + +static int m5mols_init_controls(struct m5mols_info *info) +{ + struct v4l2_subdev *sd = &info->sd; + u16 max_exposure; + u16 step_zoom; + int ret; + + /* Determine value's range & step of controls for various FW version */ + ret = m5mols_read(sd, AE_MAX_GAIN_MON, (u32 *)&max_exposure); + if (!ret) + step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; + if (ret) + return ret; + + v4l2_ctrl_handler_init(&info->handle, 6); + info->autowb = v4l2_ctrl_new_std(&info->handle, + &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 0); + info->saturation = v4l2_ctrl_new_std(&info->handle, + &m5mols_ctrl_ops, V4L2_CID_SATURATION, + 1, 5, 1, 3); + info->zoom = v4l2_ctrl_new_std(&info->handle, + &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE, + 1, 70, step_zoom, 1); + info->exposure = v4l2_ctrl_new_std(&info->handle, + &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, + 0, max_exposure, 1, (int)max_exposure/2); + info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, + &m5mols_ctrl_ops, V4L2_CID_COLORFX, + 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE); + info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle, + &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, + 1, 0, V4L2_EXPOSURE_MANUAL); + + sd->ctrl_handler = &info->handle; + if (info->handle.error) { + v4l2_err(sd, "Failed to initialize controls: %d\n", ret); + v4l2_ctrl_handler_free(&info->handle); + return info->handle.error; + } + + v4l2_ctrl_cluster(2, &info->autoexposure); + + return 0; +} + +/** + * m5mols_s_power - Main sensor power control function + * + * To prevent breaking the lens when the sensor is powered off the Soft-Landing + * algorithm is called where available. The Soft-Landing algorithm availability + * dependends on the firmware provider. + */ +static int m5mols_s_power(struct v4l2_subdev *sd, int on) +{ + struct m5mols_info *info = to_m5mols(sd); + int ret; + + if (on) { + ret = m5mols_sensor_power(info, true); + if (!ret) + ret = m5mols_sensor_armboot(sd); + if (!ret) + ret = m5mols_init_controls(info); + if (ret) + return ret; + + info->ffmt[M5MOLS_RESTYPE_MONITOR] = + m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR]; + info->ffmt[M5MOLS_RESTYPE_CAPTURE] = + m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE]; + return ret; + } + + if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { + ret = m5mols_mode(info, REG_MONITOR); + if (!ret) + ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); + if (!ret) + ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); + if (!ret) + ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS, + REG_AF_IDLE); + if (!ret) + v4l2_info(sd, "Success soft-landing lens\n"); + } + + ret = m5mols_sensor_power(info, false); + if (!ret) { + v4l2_ctrl_handler_free(&info->handle); + info->ctrl_sync = false; + } + + return ret; +} + +static int m5mols_log_status(struct v4l2_subdev *sd) +{ + struct m5mols_info *info = to_m5mols(sd); + + v4l2_ctrl_handler_log_status(&info->handle, sd->name); + + return 0; +} + +static const struct v4l2_subdev_core_ops m5mols_core_ops = { + .s_power = m5mols_s_power, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .log_status = m5mols_log_status, +}; + +static const struct v4l2_subdev_ops m5mols_ops = { + .core = &m5mols_core_ops, + .pad = &m5mols_pad_ops, + .video = &m5mols_video_ops, +}; + +static void m5mols_irq_work(struct work_struct *work) +{ + struct m5mols_info *info = + container_of(work, struct m5mols_info, work_irq); + struct v4l2_subdev *sd = &info->sd; + u32 reg; + int ret; + + if (!is_powered(info) || + m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt)) + return; + + switch (info->interrupt & REG_INT_MASK) { + case REG_INT_AF: + if (!is_available_af(info)) + break; + ret = m5mols_read(sd, AF_STATUS, ®); + v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", + reg == REG_AF_FAIL ? "Failed" : + reg == REG_AF_SUCCESS ? "Success" : + reg == REG_AF_IDLE ? "Idle" : "Busy"); + break; + case REG_INT_CAPTURE: + if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags)) + wake_up_interruptible(&info->irq_waitq); + + v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n"); + break; + default: + v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg); + break; + }; +} + +static irqreturn_t m5mols_irq_handler(int irq, void *data) +{ + struct v4l2_subdev *sd = data; + struct m5mols_info *info = to_m5mols(sd); + + schedule_work(&info->work_irq); + + return IRQ_HANDLED; +} + +static int __devinit m5mols_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct m5mols_platform_data *pdata = client->dev.platform_data; + struct m5mols_info *info; + struct v4l2_subdev *sd; + int ret; + + if (pdata == NULL) { + dev_err(&client->dev, "No platform data\n"); + return -EINVAL; + } + + if (!gpio_is_valid(pdata->gpio_reset)) { + dev_err(&client->dev, "No valid RESET GPIO specified\n"); + return -EINVAL; + } + + if (!pdata->irq) { + dev_err(&client->dev, "Interrupt not assigned\n"); + return -EINVAL; + } + + info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->pdata = pdata; + info->set_power = pdata->set_power; + + ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST"); + if (ret) { + dev_err(&client->dev, "Failed to request gpio: %d\n", ret); + goto out_free; + } + gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity); + + ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies); + if (ret) { + dev_err(&client->dev, "Failed to get regulators: %d\n", ret); + goto out_gpio; + } + + sd = &info->sd; + strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); + v4l2_i2c_subdev_init(sd, client, &m5mols_ops); + + info->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&sd->entity, 1, &info->pad, 0); + if (ret < 0) + goto out_reg; + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; + + init_waitqueue_head(&info->irq_waitq); + INIT_WORK(&info->work_irq, m5mols_irq_work); + ret = request_irq(pdata->irq, m5mols_irq_handler, + IRQF_TRIGGER_RISING, MODULE_NAME, sd); + if (ret) { + dev_err(&client->dev, "Interrupt request failed: %d\n", ret); + goto out_me; + } + info->res_type = M5MOLS_RESTYPE_MONITOR; + return 0; +out_me: + media_entity_cleanup(&sd->entity); +out_reg: + regulator_bulk_free(ARRAY_SIZE(supplies), supplies); +out_gpio: + gpio_free(pdata->gpio_reset); +out_free: + kfree(info); + return ret; +} + +static int __devexit m5mols_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct m5mols_info *info = to_m5mols(sd); + + v4l2_device_unregister_subdev(sd); + free_irq(info->pdata->irq, sd); + + regulator_bulk_free(ARRAY_SIZE(supplies), supplies); + gpio_free(info->pdata->gpio_reset); + media_entity_cleanup(&sd->entity); + kfree(info); + return 0; +} + +static const struct i2c_device_id m5mols_id[] = { + { MODULE_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, m5mols_id); + +static struct i2c_driver m5mols_i2c_driver = { + .driver = { + .name = MODULE_NAME, + }, + .probe = m5mols_probe, + .remove = __devexit_p(m5mols_remove), + .id_table = m5mols_id, +}; + +static int __init m5mols_mod_init(void) +{ + return i2c_add_driver(&m5mols_i2c_driver); +} + +static void __exit m5mols_mod_exit(void) +{ + i2c_del_driver(&m5mols_i2c_driver); +} + +module_init(m5mols_mod_init); +module_exit(m5mols_mod_exit); + +MODULE_AUTHOR("HeungJun Kim "); +MODULE_AUTHOR("Dongsoo Kim "); +MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,296 @@ +/* + * Header for M-5MOLS 8M Pixel camera sensor with ISP + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Author: HeungJun Kim, riverful.kim@samsung.com + * + * Copyright (C) 2009 Samsung Electronics Co., Ltd. + * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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, or + * (at your option) any later version. + */ + +#ifndef M5MOLS_H +#define M5MOLS_H + +#include +#include "m5mols_reg.h" + +extern int m5mols_debug; + +#define to_m5mols(__sd) container_of(__sd, struct m5mols_info, sd) + +#define to_sd(__ctrl) \ + (&container_of(__ctrl->handler, struct m5mols_info, handle)->sd) + +enum m5mols_restype { + M5MOLS_RESTYPE_MONITOR, + M5MOLS_RESTYPE_CAPTURE, + M5MOLS_RESTYPE_MAX, +}; + +/** + * struct m5mols_resolution - structure for the resolution + * @type: resolution type according to the pixel code + * @width: width of the resolution + * @height: height of the resolution + * @reg: resolution preset register value + */ +struct m5mols_resolution { + u8 reg; + enum m5mols_restype type; + u16 width; + u16 height; +}; + +/** + * struct m5mols_exif - structure for the EXIF information of M-5MOLS + * @exposure_time: exposure time register value + * @shutter_speed: speed of the shutter register value + * @aperture: aperture register value + * @exposure_bias: it calls also EV bias + * @iso_speed: ISO register value + * @flash: status register value of the flash + * @sdr: status register value of the Subject Distance Range + * @qval: not written exact meaning in document + */ +struct m5mols_exif { + u32 exposure_time; + u32 shutter_speed; + u32 aperture; + u32 brightness; + u32 exposure_bias; + u16 iso_speed; + u16 flash; + u16 sdr; + u16 qval; +}; + +/** + * struct m5mols_capture - Structure for the capture capability + * @exif: EXIF information + * @main: size in bytes of the main image + * @thumb: size in bytes of the thumb image, if it was accompanied + * @total: total size in bytes of the produced image + */ +struct m5mols_capture { + struct m5mols_exif exif; + u32 main; + u32 thumb; + u32 total; +}; + +/** + * struct m5mols_scenemode - structure for the scenemode capability + * @metering: metering light register value + * @ev_bias: EV bias register value + * @wb_mode: mode which means the WhiteBalance is Auto or Manual + * @wb_preset: whitebalance preset register value in the Manual mode + * @chroma_en: register value whether the Chroma capability is enabled or not + * @chroma_lvl: chroma's level register value + * @edge_en: register value Whether the Edge capability is enabled or not + * @edge_lvl: edge's level register value + * @af_range: Auto Focus's range + * @fd_mode: Face Detection mode + * @mcc: Multi-axis Color Conversion which means emotion color + * @light: status of the Light + * @flash: status of the Flash + * @tone: Tone color which means Contrast + * @iso: ISO register value + * @capt_mode: Mode of the Image Stabilization while the camera capturing + * @wdr: Wide Dynamic Range register value + * + * The each value according to each scenemode is recommended in the documents. + */ +struct m5mols_scenemode { + u32 metering; + u32 ev_bias; + u32 wb_mode; + u32 wb_preset; + u32 chroma_en; + u32 chroma_lvl; + u32 edge_en; + u32 edge_lvl; + u32 af_range; + u32 fd_mode; + u32 mcc; + u32 light; + u32 flash; + u32 tone; + u32 iso; + u32 capt_mode; + u32 wdr; +}; + +/** + * struct m5mols_version - firmware version information + * @customer: customer information + * @project: version of project information according to customer + * @fw: firmware revision + * @hw: hardware revision + * @param: version of the parameter + * @awb: Auto WhiteBalance algorithm version + * @str: information about manufacturer and packaging vendor + * @af: Auto Focus version + * + * The register offset starts the customer version at 0x0, and it ends + * the awb version at 0x09. The customer, project information occupies 1 bytes + * each. And also the fw, hw, param, awb each requires 2 bytes. The str is + * unique string associated with firmware's version. It includes information + * about manufacturer and the vendor of the sensor's packaging. The least + * significant 2 bytes of the string indicate packaging manufacturer. + */ +#define VERSION_STRING_SIZE 22 +struct m5mols_version { + u8 customer; + u8 project; + u16 fw; + u16 hw; + u16 param; + u16 awb; + u8 str[VERSION_STRING_SIZE]; + u8 af; +}; +#define VERSION_SIZE sizeof(struct m5mols_version) + +/** + * struct m5mols_info - M-5MOLS driver data structure + * @pdata: platform data + * @sd: v4l-subdev instance + * @pad: media pad + * @ffmt: current fmt according to resolution type + * @res_type: current resolution type + * @code: current code + * @irq_waitq: waitqueue for the capture + * @work_irq: workqueue for the IRQ + * @flags: state variable for the interrupt handler + * @handle: control handler + * @autoexposure: Auto Exposure control + * @exposure: Exposure control + * @autowb: Auto White Balance control + * @colorfx: Color effect control + * @saturation: Saturation control + * @zoom: Zoom control + * @ver: information of the version + * @cap: the capture mode attributes + * @power: current sensor's power status + * @ctrl_sync: true means all controls of the sensor are initialized + * @int_capture: true means the capture interrupt is issued once + * @lock_ae: true means the Auto Exposure is locked + * @lock_awb: true means the Aut WhiteBalance is locked + * @resolution: register value for current resolution + * @interrupt: register value for current interrupt status + * @mode: register value for current operation mode + * @mode_save: register value for current operation mode for saving + * @set_power: optional power callback to the board code + */ +struct m5mols_info { + const struct m5mols_platform_data *pdata; + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; + int res_type; + enum v4l2_mbus_pixelcode code; + wait_queue_head_t irq_waitq; + struct work_struct work_irq; + unsigned long flags; + + struct v4l2_ctrl_handler handle; + /* Autoexposure/exposure control cluster */ + struct { + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; + struct v4l2_ctrl *autowb; + struct v4l2_ctrl *colorfx; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *zoom; + + struct m5mols_version ver; + struct m5mols_capture cap; + bool power; + bool ctrl_sync; + bool lock_ae; + bool lock_awb; + u8 resolution; + u32 interrupt; + u32 mode; + u32 mode_save; + int (*set_power)(struct device *dev, int on); +}; + +#define ST_CAPT_IRQ 0 + +#define is_powered(__info) (__info->power) +#define is_ctrl_synced(__info) (__info->ctrl_sync) +#define is_available_af(__info) (__info->ver.af) +#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code) +#define is_manufacturer(__info, __manufacturer) \ + (__info->ver.str[0] == __manufacturer[0] && \ + __info->ver.str[1] == __manufacturer[1]) +/* + * I2C operation of the M-5MOLS + * + * The I2C read operation of the M-5MOLS requires 2 messages. The first + * message sends the information about the command, command category, and total + * message size. The second message is used to retrieve the data specifed in + * the first message + * + * 1st message 2nd message + * +-------+---+----------+-----+-------+ +------+------+------+------+ + * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] | + * +-------+---+----------+-----+-------+ +------+------+------+------+ + * - size1: message data size(5 in this case) + * - size2: desired buffer size of the 2nd message + * - d[0..3]: according to size2 + * + * The I2C write operation needs just one message. The message includes + * category, command, total size, and desired data. + * + * 1st message + * +-------+---+----------+-----+------+------+------+------+ + * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] | + * +-------+---+----------+-----+------+------+------+------+ + * - d[0..3]: according to size1 + */ +int m5mols_read(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); +int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); +int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value); + +/* + * Mode operation of the M-5MOLS + * + * Changing the mode of the M-5MOLS is needed right executing order. + * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed + * by user. There are various categories associated with each mode. + * + * +============================================================+ + * | mode | category | + * +============================================================+ + * | FLASH | FLASH(only after Stand-by or Power-on) | + * | SYSTEM | SYSTEM(only after sensor arm-booting) | + * | PARAMETER | PARAMETER | + * | MONITOR | MONITOR(preview), Auto Focus, Face Detection | + * | CAPTURE | Single CAPTURE, Preview(recording) | + * +============================================================+ + * + * The available executing order between each modes are as follows: + * PARAMETER <---> MONITOR <---> CAPTURE + */ +int m5mols_mode(struct m5mols_info *info, u32 mode); + +int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg); +int m5mols_sync_controls(struct m5mols_info *info); +int m5mols_start_capture(struct m5mols_info *info); +int m5mols_do_scenemode(struct m5mols_info *info, u32 mode); +int m5mols_lock_3a(struct m5mols_info *info, bool lock); +int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); + +/* The firmware function */ +int m5mols_update_fw(struct v4l2_subdev *sd, + int (*set_power)(struct m5mols_info *, bool)); + +#endif /* M5MOLS_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_reg.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_reg.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_reg.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/m5mols_reg.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,399 @@ +/* + * Register map for M-5MOLS 8M Pixel camera sensor with ISP + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Author: HeungJun Kim, riverful.kim@samsung.com + * + * Copyright (C) 2009 Samsung Electronics Co., Ltd. + * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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, or + * (at your option) any later version. + */ + +#ifndef M5MOLS_REG_H +#define M5MOLS_REG_H + +#define M5MOLS_I2C_MAX_SIZE 4 +#define M5MOLS_BYTE_READ 0x01 +#define M5MOLS_BYTE_WRITE 0x02 + +#define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff) +#define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff) +#define I2C_SIZE(__reg_s) ((__reg_s) & 0xff) +#define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s) + +/* + * Category section register + * + * The category means set including relevant command of M-5MOLS. + */ +#define CAT_SYSTEM 0x00 +#define CAT_PARAM 0x01 +#define CAT_MONITOR 0x02 +#define CAT_AE 0x03 +#define CAT_WB 0x06 +#define CAT_EXIF 0x07 +#define CAT_FD 0x09 +#define CAT_LENS 0x0a +#define CAT_CAPT_PARM 0x0b +#define CAT_CAPT_CTRL 0x0c +#define CAT_FLASH 0x0f /* related to FW, revisions, booting */ + +/* + * Category 0 - SYSTEM mode + * + * The SYSTEM mode in the M-5MOLS means area available to handle with the whole + * & all-round system of sensor. It deals with version/interrupt/setting mode & + * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by + * packaging & manufacturer, even the customer and project code. And the + * function details may vary among them. The version information helps to + * determine what methods shall be used in the driver. + * + * There is many registers between customer version address and awb one. For + * more specific contents, see definition if file m5mols.h. + */ +#define CAT0_VER_CUSTOMER 0x00 /* customer version */ +#define CAT0_VER_AWB 0x09 /* Auto WB version */ +#define CAT0_VER_STRING 0x0a /* string including M-5MOLS */ +#define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ +#define CAT0_STATUS 0x0c /* SYSTEM mode status register */ +#define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ +#define CAT0_INT_ENABLE 0x11 /* interrupt enable register */ + +#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1) +#define REG_SYSINIT 0x00 /* SYSTEM mode */ +#define REG_PARAMETER 0x01 /* PARAMETER mode */ +#define REG_MONITOR 0x02 /* MONITOR mode */ +#define REG_CAPTURE 0x03 /* CAPTURE mode */ + +#define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1) +#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1) +#define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */ +#define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */ +#define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */ + +#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1) +#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1) +#define REG_INT_MODE (1 << 0) +#define REG_INT_AF (1 << 1) +#define REG_INT_ZOOM (1 << 2) +#define REG_INT_CAPTURE (1 << 3) +#define REG_INT_FRAMESYNC (1 << 4) +#define REG_INT_FD (1 << 5) +#define REG_INT_LENS_INIT (1 << 6) +#define REG_INT_SOUND (1 << 7) +#define REG_INT_MASK 0x0f + +/* + * category 1 - PARAMETER mode + * + * This category supports function of camera features of M-5MOLS. It means we + * can handle with preview(MONITOR) resolution size/frame per second/interface + * between the sensor and the Application Processor/even the image effect. + */ +#define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */ +#define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */ +#define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */ +#define CAT1_EFFECT 0x0b /* image effects */ + +#define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1) + +#define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1) +#define REG_FPS_30 0x02 + +#define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1) +#define REG_INTERFACE_MIPI 0x02 + +#define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1) +#define REG_EFFECT_OFF 0x00 +#define REG_EFFECT_NEGA 0x01 +#define REG_EFFECT_EMBOSS 0x06 +#define REG_EFFECT_OUTLINE 0x07 +#define REG_EFFECT_WATERCOLOR 0x08 + +/* + * Category 2 - MONITOR mode + * + * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another + * mode named "Preview", but this preview mode is used at the case specific + * vider-recording mode. This mmode supports only YUYV format. On the other + * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are + * another options like zoom/color effect(different with effect in PARAMETER + * mode)/anti hand shaking algorithm. + */ +#define CAT2_ZOOM 0x01 /* set the zoom position & execute */ +#define CAT2_ZOOM_STEP 0x03 /* set the zoom step */ +#define CAT2_CFIXB 0x09 /* CB value for color effect */ +#define CAT2_CFIXR 0x0a /* CR value for color effect */ +#define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */ +#define CAT2_CHROMA_LVL 0x0f /* set chroma level */ +#define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */ +#define CAT2_EDGE_LVL 0x11 /* set sharpness level */ +#define CAT2_EDGE_EN 0x12 /* set on/off sharpness */ +#define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */ + +#define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1) + +#define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1) +#define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1) +#define REG_CFIXB_SEPIA 0xd8 +#define REG_CFIXR_SEPIA 0x18 + +#define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1) +#define REG_COLOR_EFFECT_OFF 0x00 +#define REG_COLOR_EFFECT_ON 0x01 + +#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1) +#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1) +#define REG_CHROMA_OFF 0x00 +#define REG_CHROMA_ON 0x01 + +#define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1) +#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1) +#define REG_EDGE_OFF 0x00 +#define REG_EDGE_ON 0x01 + +#define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1) + +/* + * Category 3 - Auto Exposure + * + * The M-5MOLS exposure capbility is detailed as which is similar to digital + * camera. This category supports AE locking/various AE mode(range of exposure) + * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the + * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be + * different. So, this category also provide getting the max/min values. And, + * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values. + */ +#define CAT3_AE_LOCK 0x00 /* locking Auto exposure */ +#define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */ +#define CAT3_ISO 0x05 /* set ISO */ +#define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */ +#define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */ +#define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */ +#define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */ +#define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */ +#define CAT3_AE_INDEX 0x38 /* AE index */ + +#define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1) +#define REG_AE_UNLOCK 0x00 +#define REG_AE_LOCK 0x01 + +#define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1) +#define REG_AE_OFF 0x00 /* AE off */ +#define REG_AE_ALL 0x01 /* calc AE in all block integral */ +#define REG_AE_CENTER 0x03 /* calc AE in center weighted */ +#define REG_AE_SPOT 0x06 /* calc AE in specific spot */ + +#define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1) +#define REG_ISO_AUTO 0x00 +#define REG_ISO_50 0x01 +#define REG_ISO_100 0x02 +#define REG_ISO_200 0x03 +#define REG_ISO_400 0x04 +#define REG_ISO_800 0x05 + +#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1) +#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1) +#define REG_SCENE_NORMAL 0x00 +#define REG_SCENE_PORTRAIT 0x01 +#define REG_SCENE_LANDSCAPE 0x02 +#define REG_SCENE_SPORTS 0x03 +#define REG_SCENE_PARTY_INDOOR 0x04 +#define REG_SCENE_BEACH_SNOW 0x05 +#define REG_SCENE_SUNSET 0x06 +#define REG_SCENE_DAWN_DUSK 0x07 +#define REG_SCENE_FALL 0x08 +#define REG_SCENE_NIGHT 0x09 +#define REG_SCENE_AGAINST_LIGHT 0x0a +#define REG_SCENE_FIRE 0x0b +#define REG_SCENE_TEXT 0x0c +#define REG_SCENE_CANDLE 0x0d + +#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2) +#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2) +#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2) + +#define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1) +#define REG_AE_INDEX_20_NEG 0x00 +#define REG_AE_INDEX_15_NEG 0x01 +#define REG_AE_INDEX_10_NEG 0x02 +#define REG_AE_INDEX_05_NEG 0x03 +#define REG_AE_INDEX_00 0x04 +#define REG_AE_INDEX_05_POS 0x05 +#define REG_AE_INDEX_10_POS 0x06 +#define REG_AE_INDEX_15_POS 0x07 +#define REG_AE_INDEX_20_POS 0x08 + +/* + * Category 6 - White Balance + * + * This category provide AWB locking/mode/preset/speed/gain bias, etc. + */ +#define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */ +#define CAT6_AWB_MODE 0x02 /* set Auto or Manual */ +#define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */ + +#define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1) +#define REG_AWB_UNLOCK 0x00 +#define REG_AWB_LOCK 0x01 + +#define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1) +#define REG_AWB_AUTO 0x01 /* AWB off */ +#define REG_AWB_PRESET 0x02 /* AWB preset */ + +#define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1) +#define REG_AWB_INCANDESCENT 0x01 +#define REG_AWB_FLUORESCENT_1 0x02 +#define REG_AWB_FLUORESCENT_2 0x03 +#define REG_AWB_DAYLIGHT 0x04 +#define REG_AWB_CLOUDY 0x05 +#define REG_AWB_SHADE 0x06 +#define REG_AWB_HORIZON 0x07 +#define REG_AWB_LEDLIGHT 0x09 + +/* + * Category 7 - EXIF information + */ +#define CAT7_INFO_EXPTIME_NU 0x00 +#define CAT7_INFO_EXPTIME_DE 0x04 +#define CAT7_INFO_TV_NU 0x08 +#define CAT7_INFO_TV_DE 0x0c +#define CAT7_INFO_AV_NU 0x10 +#define CAT7_INFO_AV_DE 0x14 +#define CAT7_INFO_BV_NU 0x18 +#define CAT7_INFO_BV_DE 0x1c +#define CAT7_INFO_EBV_NU 0x20 +#define CAT7_INFO_EBV_DE 0x24 +#define CAT7_INFO_ISO 0x28 +#define CAT7_INFO_FLASH 0x2a +#define CAT7_INFO_SDR 0x2c +#define CAT7_INFO_QVAL 0x2e + +#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4) +#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4) +#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4) +#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4) +#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4) +#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4) +#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4) +#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4) +#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4) +#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4) +#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2) +#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2) +#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2) +#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2) + +/* + * Category 9 - Face Detection + */ +#define CAT9_FD_CTL 0x00 + +#define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1) +#define BIT_FD_EN 0 +#define BIT_FD_DRAW_FACE_FRAME 4 +#define BIT_FD_DRAW_SMILE_LVL 6 +#define REG_FD(shift) (1 << shift) +#define REG_FD_OFF 0x0 + +/* + * Category A - Lens Parameter + */ +#define CATA_AF_MODE 0x01 +#define CATA_AF_EXECUTE 0x02 +#define CATA_AF_STATUS 0x03 +#define CATA_AF_VERSION 0x0a + +#define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1) +#define REG_AF_NORMAL 0x00 /* Normal AF, one time */ +#define REG_AF_MACRO 0x01 /* Macro AF, one time */ +#define REG_AF_POWEROFF 0x07 + +#define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1) +#define REG_AF_STOP 0x00 +#define REG_AF_EXE_AUTO 0x01 +#define REG_AF_EXE_CAF 0x02 + +#define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1) +#define REG_AF_FAIL 0x00 +#define REG_AF_SUCCESS 0x02 +#define REG_AF_IDLE 0x04 +#define REG_AF_BUSY 0x05 + +#define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1) + +/* + * Category B - CAPTURE Parameter + */ +#define CATB_YUVOUT_MAIN 0x00 +#define CATB_MAIN_IMAGE_SIZE 0x01 +#define CATB_MCC_MODE 0x1d +#define CATB_WDR_EN 0x2c +#define CATB_LIGHT_CTRL 0x40 +#define CATB_FLASH_CTRL 0x41 + +#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1) +#define REG_YUV422 0x00 +#define REG_BAYER10 0x05 +#define REG_BAYER8 0x06 +#define REG_JPEG 0x10 + +#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1) + +#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1) +#define REG_MCC_OFF 0x00 +#define REG_MCC_NORMAL 0x01 + +#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1) +#define REG_WDR_OFF 0x00 +#define REG_WDR_ON 0x01 +#define REG_WDR_AUTO 0x02 + +#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1) +#define REG_LIGHT_OFF 0x00 +#define REG_LIGHT_ON 0x01 +#define REG_LIGHT_AUTO 0x02 + +#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1) +#define REG_FLASH_OFF 0x00 +#define REG_FLASH_ON 0x01 +#define REG_FLASH_AUTO 0x02 + +/* + * Category C - CAPTURE Control + */ +#define CATC_CAP_MODE 0x00 +#define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */ +#define CATC_CAP_START 0x09 +#define CATC_CAP_IMAGE_SIZE 0x0d +#define CATC_CAP_THUMB_SIZE 0x11 + +#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1) +#define REG_CAP_NONE 0x00 +#define REG_CAP_ANTI_SHAKE 0x02 + +#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1) + +#define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1) +#define REG_CAP_START_MAIN 0x01 +#define REG_CAP_START_THUMB 0x03 + +#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 1) +#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 1) + +/* + * Category F - Flash + * + * This mode provides functions about internal flash stuff and system startup. + */ +#define CATF_CAM_START 0x12 /* It starts internal ARM core booting + * after power-up */ + +#define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1) +#define REG_START_ARM_BOOT 0x01 + +#endif /* M5MOLS_REG_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/m5mols/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,3 @@ +m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o + +obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,190 @@ +# +# Makefile for the video capture/playback device drivers. +# + +tuner-objs := tuner-core.o + +msp3400-objs := msp3400-driver.o msp3400-kthreads.o + +stkwebcam-objs := stk-webcam.o stk-sensor.o + +omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o + +videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ + v4l2-event.o v4l2-ctrls.o v4l2-subdev.o + +# V4L2 core modules + +obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o +ifeq ($(CONFIG_COMPAT),y) + obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o +endif + +obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o + +# All i2c modules must come first: + +obj-$(CONFIG_VIDEO_TUNER) += tuner.o +obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o +obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o +obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o +obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o +obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o +obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o +obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o +obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o +obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o +obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o +obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o +obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o +obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o +obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o +obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o +obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o +obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o +obj-$(CONFIG_VIDEO_BT819) += bt819.o +obj-$(CONFIG_VIDEO_BT856) += bt856.o +obj-$(CONFIG_VIDEO_BT866) += bt866.o +obj-$(CONFIG_VIDEO_KS0127) += ks0127.o +obj-$(CONFIG_VIDEO_THS7303) += ths7303.o +obj-$(CONFIG_VIDEO_VINO) += indycam.o +obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o +obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o +obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o +obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o +obj-$(CONFIG_VIDEO_CS5345) += cs5345.o +obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o +obj-$(CONFIG_VIDEO_M52790) += m52790.o +obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o +obj-$(CONFIG_VIDEO_WM8775) += wm8775.o +obj-$(CONFIG_VIDEO_WM8739) += wm8739.o +obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o +obj-$(CONFIG_VIDEO_CX25840) += cx25840/ +obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o +obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o +obj-$(CONFIG_VIDEO_OV7670) += ov7670.o +obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o +obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o +obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o +obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o +obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o +obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o +obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ + +obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o +obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o +obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o +obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o +obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o +obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o +obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o +obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o +obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o +obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o +obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o +obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o +obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o + +# And now the v4l2 drivers: + +obj-$(CONFIG_VIDEO_BT848) += bt8xx/ +obj-$(CONFIG_VIDEO_ZORAN) += zoran/ +obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o +obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o +obj-$(CONFIG_VIDEO_W9966) += w9966.o +obj-$(CONFIG_VIDEO_PMS) += pms.o +obj-$(CONFIG_VIDEO_VINO) += vino.o +obj-$(CONFIG_VIDEO_MEYE) += meye.o +obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ +obj-$(CONFIG_VIDEO_CX88) += cx88/ +obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ +obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/ +obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ +obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ +obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ +obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ +obj-$(CONFIG_VIDEO_MXB) += mxb.o +obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o +obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o +obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o + +obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o +obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o +obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o +obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o +obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o +obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o + +obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o +obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o +obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o +obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o +obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o + +obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o + +obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o + +obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o + +obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/ +obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ + +obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o + +obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ + +obj-$(CONFIG_USB_ZR364XX) += zr364xx.o +obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o + +obj-$(CONFIG_USB_SN9C102) += sn9c102/ +obj-$(CONFIG_USB_ET61X251) += et61x251/ +obj-$(CONFIG_USB_PWC) += pwc/ +obj-$(CONFIG_USB_GSPCA) += gspca/ + +obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ + +obj-$(CONFIG_USB_S2255) += s2255drv.o + +obj-$(CONFIG_VIDEO_IVTV) += ivtv/ +obj-$(CONFIG_VIDEO_CX18) += cx18/ + +obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o +obj-$(CONFIG_VIDEO_VIVI) += vivi.o +obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o +obj-$(CONFIG_VIDEO_CX23885) += cx23885/ + +obj-$(CONFIG_VIDEO_AK881X) += ak881x.o + +obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o +obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o +obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o +# soc-camera host drivers have to be linked after camera drivers +obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o +obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o +obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o +obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o +obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o +obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o +obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o + +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ + +obj-$(CONFIG_ARCH_DAVINCI) += davinci/ + +obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o + +obj-$(CONFIG_VIDEO_AU0828) += au0828/ + +obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ +obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ + +obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o + +obj-y += davinci/ + +obj-$(CONFIG_ARCH_OMAP) += omap/ + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/cafe-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/cafe-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/cafe-driver.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/cafe-driver.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,648 @@ +/* + * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe" + * multifunction chip. Currently works with the Omnivision OV7670 + * sensor. + * + * The data sheet for this device can be found at: + * http://www.marvell.com/products/pc_connectivity/88alp01/ + * + * Copyright 2006-11 One Laptop Per Child Association, Inc. + * Copyright 2006-11 Jonathan Corbet + * + * Written by Jonathan Corbet, corbet@lwn.net. + * + * v4l2_device/v4l2_subdev conversion by: + * Copyright (C) 2009 Hans Verkuil + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcam-core.h" + +#define CAFE_VERSION 0x000002 + + +/* + * Parameters. + */ +MODULE_AUTHOR("Jonathan Corbet "); +MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Video"); + + + + +struct cafe_camera { + int registered; /* Fully initialized? */ + struct mcam_camera mcam; + struct pci_dev *pdev; + wait_queue_head_t smbus_wait; /* Waiting on i2c events */ +}; + +/* + * Most of the camera controller registers are defined in mcam-core.h, + * but the Cafe platform has some additional registers of its own; + * they are described here. + */ + +/* + * "General purpose register" has a couple of GPIOs used for sensor + * power and reset on OLPC XO 1.0 systems. + */ +#define REG_GPR 0xb4 +#define GPR_C1EN 0x00000020 /* Pad 1 (power down) enable */ +#define GPR_C0EN 0x00000010 /* Pad 0 (reset) enable */ +#define GPR_C1 0x00000002 /* Control 1 value */ +/* + * Control 0 is wired to reset on OLPC machines. For ov7x sensors, + * it is active low. + */ +#define GPR_C0 0x00000001 /* Control 0 value */ + +/* + * These registers control the SMBUS module for communicating + * with the sensor. + */ +#define REG_TWSIC0 0xb8 /* TWSI (smbus) control 0 */ +#define TWSIC0_EN 0x00000001 /* TWSI enable */ +#define TWSIC0_MODE 0x00000002 /* 1 = 16-bit, 0 = 8-bit */ +#define TWSIC0_SID 0x000003fc /* Slave ID */ +/* + * Subtle trickery: the slave ID field starts with bit 2. But the + * Linux i2c stack wants to treat the bottommost bit as a separate + * read/write bit, which is why slave ID's are usually presented + * >>1. For consistency with that behavior, we shift over three + * bits instead of two. + */ +#define TWSIC0_SID_SHIFT 3 +#define TWSIC0_CLKDIV 0x0007fc00 /* Clock divider */ +#define TWSIC0_MASKACK 0x00400000 /* Mask ack from sensor */ +#define TWSIC0_OVMAGIC 0x00800000 /* Make it work on OV sensors */ + +#define REG_TWSIC1 0xbc /* TWSI control 1 */ +#define TWSIC1_DATA 0x0000ffff /* Data to/from camchip */ +#define TWSIC1_ADDR 0x00ff0000 /* Address (register) */ +#define TWSIC1_ADDR_SHIFT 16 +#define TWSIC1_READ 0x01000000 /* Set for read op */ +#define TWSIC1_WSTAT 0x02000000 /* Write status */ +#define TWSIC1_RVALID 0x04000000 /* Read data valid */ +#define TWSIC1_ERROR 0x08000000 /* Something screwed up */ + +/* + * Here's the weird global control registers + */ +#define REG_GL_CSR 0x3004 /* Control/status register */ +#define GCSR_SRS 0x00000001 /* SW Reset set */ +#define GCSR_SRC 0x00000002 /* SW Reset clear */ +#define GCSR_MRS 0x00000004 /* Master reset set */ +#define GCSR_MRC 0x00000008 /* HW Reset clear */ +#define GCSR_CCIC_EN 0x00004000 /* CCIC Clock enable */ +#define REG_GL_IMASK 0x300c /* Interrupt mask register */ +#define GIMSK_CCIC_EN 0x00000004 /* CCIC Interrupt enable */ + +#define REG_GL_FCR 0x3038 /* GPIO functional control register */ +#define GFCR_GPIO_ON 0x08 /* Camera GPIO enabled */ +#define REG_GL_GPIOR 0x315c /* GPIO register */ +#define GGPIO_OUT 0x80000 /* GPIO output */ +#define GGPIO_VAL 0x00008 /* Output pin value */ + +#define REG_LEN (REG_GL_IMASK + 4) + + +/* + * Debugging and related. + */ +#define cam_err(cam, fmt, arg...) \ + dev_err(&(cam)->pdev->dev, fmt, ##arg); +#define cam_warn(cam, fmt, arg...) \ + dev_warn(&(cam)->pdev->dev, fmt, ##arg); + +/* -------------------------------------------------------------------- */ +/* + * The I2C/SMBUS interface to the camera itself starts here. The + * controller handles SMBUS itself, presenting a relatively simple register + * interface; all we have to do is to tell it where to route the data. + */ +#define CAFE_SMBUS_TIMEOUT (HZ) /* generous */ + +static inline struct cafe_camera *to_cam(struct v4l2_device *dev) +{ + struct mcam_camera *m = container_of(dev, struct mcam_camera, v4l2_dev); + return container_of(m, struct cafe_camera, mcam); +} + + +static int cafe_smbus_write_done(struct mcam_camera *mcam) +{ + unsigned long flags; + int c1; + + /* + * We must delay after the interrupt, or the controller gets confused + * and never does give us good status. Fortunately, we don't do this + * often. + */ + udelay(20); + spin_lock_irqsave(&mcam->dev_lock, flags); + c1 = mcam_reg_read(mcam, REG_TWSIC1); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT; +} + +static int cafe_smbus_write_data(struct cafe_camera *cam, + u16 addr, u8 command, u8 value) +{ + unsigned int rval; + unsigned long flags; + struct mcam_camera *mcam = &cam->mcam; + + spin_lock_irqsave(&mcam->dev_lock, flags); + rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); + rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ + /* + * Marvell sez set clkdiv to all 1's for now. + */ + rval |= TWSIC0_CLKDIV; + mcam_reg_write(mcam, REG_TWSIC0, rval); + (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */ + rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); + mcam_reg_write(mcam, REG_TWSIC1, rval); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + + /* Unfortunately, reading TWSIC1 too soon after sending a command + * causes the device to die. + * Use a busy-wait because we often send a large quantity of small + * commands at-once; using msleep() would cause a lot of context + * switches which take longer than 2ms, resulting in a noticeable + * boot-time and capture-start delays. + */ + mdelay(2); + + /* + * Another sad fact is that sometimes, commands silently complete but + * cafe_smbus_write_done() never becomes aware of this. + * This happens at random and appears to possible occur with any + * command. + * We don't understand why this is. We work around this issue + * with the timeout in the wait below, assuming that all commands + * complete within the timeout. + */ + wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(mcam), + CAFE_SMBUS_TIMEOUT); + + spin_lock_irqsave(&mcam->dev_lock, flags); + rval = mcam_reg_read(mcam, REG_TWSIC1); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + + if (rval & TWSIC1_WSTAT) { + cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr, + command, value); + return -EIO; + } + if (rval & TWSIC1_ERROR) { + cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr, + command, value); + return -EIO; + } + return 0; +} + + + +static int cafe_smbus_read_done(struct mcam_camera *mcam) +{ + unsigned long flags; + int c1; + + /* + * We must delay after the interrupt, or the controller gets confused + * and never does give us good status. Fortunately, we don't do this + * often. + */ + udelay(20); + spin_lock_irqsave(&mcam->dev_lock, flags); + c1 = mcam_reg_read(mcam, REG_TWSIC1); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + return c1 & (TWSIC1_RVALID|TWSIC1_ERROR); +} + + + +static int cafe_smbus_read_data(struct cafe_camera *cam, + u16 addr, u8 command, u8 *value) +{ + unsigned int rval; + unsigned long flags; + struct mcam_camera *mcam = &cam->mcam; + + spin_lock_irqsave(&mcam->dev_lock, flags); + rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); + rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ + /* + * Marvel sez set clkdiv to all 1's for now. + */ + rval |= TWSIC0_CLKDIV; + mcam_reg_write(mcam, REG_TWSIC0, rval); + (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */ + rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); + mcam_reg_write(mcam, REG_TWSIC1, rval); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + + wait_event_timeout(cam->smbus_wait, + cafe_smbus_read_done(mcam), CAFE_SMBUS_TIMEOUT); + spin_lock_irqsave(&mcam->dev_lock, flags); + rval = mcam_reg_read(mcam, REG_TWSIC1); + spin_unlock_irqrestore(&mcam->dev_lock, flags); + + if (rval & TWSIC1_ERROR) { + cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command); + return -EIO; + } + if (!(rval & TWSIC1_RVALID)) { + cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr, + command); + return -EIO; + } + *value = rval & 0xff; + return 0; +} + +/* + * Perform a transfer over SMBUS. This thing is called under + * the i2c bus lock, so we shouldn't race with ourselves... + */ +static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char rw, u8 command, + int size, union i2c_smbus_data *data) +{ + struct cafe_camera *cam = i2c_get_adapdata(adapter); + int ret = -EINVAL; + + /* + * This interface would appear to only do byte data ops. OK + * it can do word too, but the cam chip has no use for that. + */ + if (size != I2C_SMBUS_BYTE_DATA) { + cam_err(cam, "funky xfer size %d\n", size); + return -EINVAL; + } + + if (rw == I2C_SMBUS_WRITE) + ret = cafe_smbus_write_data(cam, addr, command, data->byte); + else if (rw == I2C_SMBUS_READ) + ret = cafe_smbus_read_data(cam, addr, command, &data->byte); + return ret; +} + + +static void cafe_smbus_enable_irq(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->mcam.dev_lock, flags); + mcam_reg_set_bit(&cam->mcam, REG_IRQMASK, TWSIIRQS); + spin_unlock_irqrestore(&cam->mcam.dev_lock, flags); +} + +static u32 cafe_smbus_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA; +} + +static struct i2c_algorithm cafe_smbus_algo = { + .smbus_xfer = cafe_smbus_xfer, + .functionality = cafe_smbus_func +}; + +static int cafe_smbus_setup(struct cafe_camera *cam) +{ + struct i2c_adapter *adap; + int ret; + + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (adap == NULL) + return -ENOMEM; + cam->mcam.i2c_adapter = adap; + cafe_smbus_enable_irq(cam); + adap->owner = THIS_MODULE; + adap->algo = &cafe_smbus_algo; + strcpy(adap->name, "cafe_ccic"); + adap->dev.parent = &cam->pdev->dev; + i2c_set_adapdata(adap, cam); + ret = i2c_add_adapter(adap); + if (ret) + printk(KERN_ERR "Unable to register cafe i2c adapter\n"); + return ret; +} + +static void cafe_smbus_shutdown(struct cafe_camera *cam) +{ + i2c_del_adapter(cam->mcam.i2c_adapter); + kfree(cam->mcam.i2c_adapter); +} + + +/* + * Controller-level stuff + */ + +static void cafe_ctlr_init(struct mcam_camera *mcam) +{ + unsigned long flags; + + spin_lock_irqsave(&mcam->dev_lock, flags); + /* + * Added magic to bring up the hardware on the B-Test board + */ + mcam_reg_write(mcam, 0x3038, 0x8); + mcam_reg_write(mcam, 0x315c, 0x80008); + /* + * Go through the dance needed to wake the device up. + * Note that these registers are global and shared + * with the NAND and SD devices. Interaction between the + * three still needs to be examined. + */ + mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ + mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); + mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); + /* + * Here we must wait a bit for the controller to come around. + */ + spin_unlock_irqrestore(&mcam->dev_lock, flags); + msleep(5); + spin_lock_irqsave(&mcam->dev_lock, flags); + + mcam_reg_write(mcam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); + mcam_reg_set_bit(mcam, REG_GL_IMASK, GIMSK_CCIC_EN); + /* + * Mask all interrupts. + */ + mcam_reg_write(mcam, REG_IRQMASK, 0); + spin_unlock_irqrestore(&mcam->dev_lock, flags); +} + + +static void cafe_ctlr_power_up(struct mcam_camera *mcam) +{ + /* + * Part one of the sensor dance: turn the global + * GPIO signal on. + */ + mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON); + mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL); + /* + * Put the sensor into operational mode (assumes OLPC-style + * wiring). Control 0 is reset - set to 1 to operate. + * Control 1 is power down, set to 0 to operate. + */ + mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ + mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); +} + +static void cafe_ctlr_power_down(struct mcam_camera *mcam) +{ + mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); + mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON); + mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT); +} + + + +/* + * The platform interrupt handler. + */ +static irqreturn_t cafe_irq(int irq, void *data) +{ + struct cafe_camera *cam = data; + struct mcam_camera *mcam = &cam->mcam; + unsigned int irqs, handled; + + spin_lock(&mcam->dev_lock); + irqs = mcam_reg_read(mcam, REG_IRQSTAT); + handled = cam->registered && mccic_irq(mcam, irqs); + if (irqs & TWSIIRQS) { + mcam_reg_write(mcam, REG_IRQSTAT, TWSIIRQS); + wake_up(&cam->smbus_wait); + handled = 1; + } + spin_unlock(&mcam->dev_lock); + return IRQ_RETVAL(handled); +} + + +/* -------------------------------------------------------------------------- */ +/* + * PCI interface stuff. + */ + +static int cafe_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret; + struct cafe_camera *cam; + struct mcam_camera *mcam; + + /* + * Start putting together one of our big camera structures. + */ + ret = -ENOMEM; + cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL); + if (cam == NULL) + goto out; + cam->pdev = pdev; + mcam = &cam->mcam; + mcam->chip_id = V4L2_IDENT_CAFE; + spin_lock_init(&mcam->dev_lock); + init_waitqueue_head(&cam->smbus_wait); + mcam->plat_power_up = cafe_ctlr_power_up; + mcam->plat_power_down = cafe_ctlr_power_down; + mcam->dev = &pdev->dev; + /* + * Set the clock speed for the XO 1; I don't believe this + * driver has ever run anywhere else. + */ + mcam->clock_speed = 45; + mcam->use_smbus = 1; + /* + * Get set up on the PCI bus. + */ + ret = pci_enable_device(pdev); + if (ret) + goto out_free; + pci_set_master(pdev); + + ret = -EIO; + mcam->regs = pci_iomap(pdev, 0, 0); + if (!mcam->regs) { + printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n"); + goto out_disable; + } + ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam); + if (ret) + goto out_iounmap; + + /* + * Initialize the controller and leave it powered up. It will + * stay that way until the sensor driver shows up. + */ + cafe_ctlr_init(mcam); + cafe_ctlr_power_up(mcam); + /* + * Set up I2C/SMBUS communications. We have to drop the mutex here + * because the sensor could attach in this call chain, leading to + * unsightly deadlocks. + */ + ret = cafe_smbus_setup(cam); + if (ret) + goto out_pdown; + + ret = mccic_register(mcam); + if (ret == 0) { + cam->registered = 1; + return 0; + } + + cafe_smbus_shutdown(cam); +out_pdown: + cafe_ctlr_power_down(mcam); + free_irq(pdev->irq, cam); +out_iounmap: + pci_iounmap(pdev, mcam->regs); +out_disable: + pci_disable_device(pdev); +out_free: + kfree(cam); +out: + return ret; +} + + +/* + * Shut down an initialized device + */ +static void cafe_shutdown(struct cafe_camera *cam) +{ + mccic_shutdown(&cam->mcam); + cafe_smbus_shutdown(cam); + free_irq(cam->pdev->irq, cam); + pci_iounmap(cam->pdev, cam->mcam.regs); +} + + +static void cafe_pci_remove(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct cafe_camera *cam = to_cam(v4l2_dev); + + if (cam == NULL) { + printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev); + return; + } + cafe_shutdown(cam); + kfree(cam); +} + + +#ifdef CONFIG_PM +/* + * Basic power management. + */ +static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct cafe_camera *cam = to_cam(v4l2_dev); + int ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + mccic_suspend(&cam->mcam); + pci_disable_device(pdev); + return 0; +} + + +static int cafe_pci_resume(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct cafe_camera *cam = to_cam(v4l2_dev); + int ret = 0; + + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + + if (ret) { + cam_warn(cam, "Unable to re-enable device on resume!\n"); + return ret; + } + cafe_ctlr_init(&cam->mcam); + return mccic_resume(&cam->mcam); +} + +#endif /* CONFIG_PM */ + +static struct pci_device_id cafe_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, + PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, cafe_ids); + +static struct pci_driver cafe_pci_driver = { + .name = "cafe1000-ccic", + .id_table = cafe_ids, + .probe = cafe_pci_probe, + .remove = cafe_pci_remove, +#ifdef CONFIG_PM + .suspend = cafe_pci_suspend, + .resume = cafe_pci_resume, +#endif +}; + + + + +static int __init cafe_init(void) +{ + int ret; + + printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n", + CAFE_VERSION); + ret = pci_register_driver(&cafe_pci_driver); + if (ret) { + printk(KERN_ERR "Unable to register cafe_ccic driver\n"); + goto out; + } + ret = 0; + +out: + return ret; +} + + +static void __exit cafe_exit(void) +{ + pci_unregister_driver(&cafe_pci_driver); +} + +module_init(cafe_init); +module_exit(cafe_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,20 @@ +config VIDEO_CAFE_CCIC + tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" + depends on PCI && I2C && VIDEO_V4L2 + select VIDEO_OV7670 + ---help--- + This is a video4linux2 driver for the Marvell 88ALP01 integrated + CMOS camera controller. This is the controller found on first- + generation OLPC systems. + +config VIDEO_MMP_CAMERA + tristate "Marvell Armada 610 integrated camera controller support" + depends on ARCH_MMP && I2C && VIDEO_V4L2 + select VIDEO_OV7670 + select I2C_GPIO + ---help--- + This is a Video4Linux2 driver for the integrated camera + controller found on Marvell Armada 610 application + processors (and likely beyond). This is the controller found + in OLPC XO 1.75 systems. + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,6 @@ +obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o +cafe_ccic-y := cafe-driver.o mcam-core.o + +obj-$(CONFIG_VIDEO_MMP_CAMERA) += mmp_camera.o +mmp_camera-y := mmp-driver.o mcam-core.o + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mcam-core.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mcam-core.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mcam-core.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mcam-core.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1683 @@ +/* + * The Marvell camera core. This device appears in a number of settings, + * so it needs platform-specific support outside of the core. + * + * Copyright 2011 Jonathan Corbet corbet@lwn.net + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcam-core.h" + + +/* + * Internal DMA buffer management. Since the controller cannot do S/G I/O, + * we must have physically contiguous buffers to bring frames into. + * These parameters control how many buffers we use, whether we + * allocate them at load time (better chance of success, but nails down + * memory) or when somebody tries to use the camera (riskier), and, + * for load-time allocation, how big they should be. + * + * The controller can cycle through three buffers. We could use + * more by flipping pointers around, but it probably makes little + * sense. + */ + +static int alloc_bufs_at_read; +module_param(alloc_bufs_at_read, bool, 0444); +MODULE_PARM_DESC(alloc_bufs_at_read, + "Non-zero value causes DMA buffers to be allocated when the " + "video capture device is read, rather than at module load " + "time. This saves memory, but decreases the chances of " + "successfully getting those buffers."); + +static int n_dma_bufs = 3; +module_param(n_dma_bufs, uint, 0644); +MODULE_PARM_DESC(n_dma_bufs, + "The number of DMA buffers to allocate. Can be either two " + "(saves memory, makes timing tighter) or three."); + +static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2; /* Worst case */ +module_param(dma_buf_size, uint, 0444); +MODULE_PARM_DESC(dma_buf_size, + "The size of the allocated DMA buffers. If actual operating " + "parameters require larger buffers, an attempt to reallocate " + "will be made."); + +static int min_buffers = 1; +module_param(min_buffers, uint, 0644); +MODULE_PARM_DESC(min_buffers, + "The minimum number of streaming I/O buffers we are willing " + "to work with."); + +static int max_buffers = 10; +module_param(max_buffers, uint, 0644); +MODULE_PARM_DESC(max_buffers, + "The maximum number of streaming I/O buffers an application " + "will be allowed to allocate. These buffers are big and live " + "in vmalloc space."); + +static int flip; +module_param(flip, bool, 0444); +MODULE_PARM_DESC(flip, + "If set, the sensor will be instructed to flip the image " + "vertically."); + +/* + * Status flags. Always manipulated with bit operations. + */ +#define CF_BUF0_VALID 0 /* Buffers valid - first three */ +#define CF_BUF1_VALID 1 +#define CF_BUF2_VALID 2 +#define CF_DMA_ACTIVE 3 /* A frame is incoming */ +#define CF_CONFIG_NEEDED 4 /* Must configure hardware */ + +#define sensor_call(cam, o, f, args...) \ + v4l2_subdev_call(cam->sensor, o, f, ##args) + +static struct mcam_format_struct { + __u8 *desc; + __u32 pixelformat; + int bpp; /* Bytes per pixel */ + enum v4l2_mbus_pixelcode mbus_code; +} mcam_formats[] = { + { + .desc = "YUYV 4:2:2", + .pixelformat = V4L2_PIX_FMT_YUYV, + .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .bpp = 2, + }, + { + .desc = "RGB 444", + .pixelformat = V4L2_PIX_FMT_RGB444, + .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, + .bpp = 2, + }, + { + .desc = "RGB 565", + .pixelformat = V4L2_PIX_FMT_RGB565, + .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, + .bpp = 2, + }, + { + .desc = "Raw RGB Bayer", + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8, + .bpp = 1 + }, +}; +#define N_MCAM_FMTS ARRAY_SIZE(mcam_formats) + +static struct mcam_format_struct *mcam_find_format(u32 pixelformat) +{ + unsigned i; + + for (i = 0; i < N_MCAM_FMTS; i++) + if (mcam_formats[i].pixelformat == pixelformat) + return mcam_formats + i; + /* Not found? Then return the first format. */ + return mcam_formats; +} + +/* + * Start over with DMA buffers - dev_lock needed. + */ +static void mcam_reset_buffers(struct mcam_camera *cam) +{ + int i; + + cam->next_buf = -1; + for (i = 0; i < cam->nbufs; i++) + clear_bit(i, &cam->flags); + cam->specframes = 0; +} + +static inline int mcam_needs_config(struct mcam_camera *cam) +{ + return test_bit(CF_CONFIG_NEEDED, &cam->flags); +} + +static void mcam_set_config_needed(struct mcam_camera *cam, int needed) +{ + if (needed) + set_bit(CF_CONFIG_NEEDED, &cam->flags); + else + clear_bit(CF_CONFIG_NEEDED, &cam->flags); +} + + +/* + * Debugging and related. + */ +#define cam_err(cam, fmt, arg...) \ + dev_err((cam)->dev, fmt, ##arg); +#define cam_warn(cam, fmt, arg...) \ + dev_warn((cam)->dev, fmt, ##arg); +#define cam_dbg(cam, fmt, arg...) \ + dev_dbg((cam)->dev, fmt, ##arg); + + + +/* ------------------------------------------------------------------- */ +/* + * Deal with the controller. + */ + +/* + * Do everything we think we need to have the interface operating + * according to the desired format. + */ +static void mcam_ctlr_dma(struct mcam_camera *cam) +{ + /* + * Store the first two Y buffers (we aren't supporting + * planar formats for now, so no UV bufs). Then either + * set the third if it exists, or tell the controller + * to just use two. + */ + mcam_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]); + mcam_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]); + if (cam->nbufs > 2) { + mcam_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]); + mcam_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); + } else + mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); + if (cam->chip_id == V4L2_IDENT_CAFE) + mcam_reg_write(cam, REG_UBAR, 0); /* 32 bits only */ +} + +static void mcam_ctlr_image(struct mcam_camera *cam) +{ + int imgsz; + struct v4l2_pix_format *fmt = &cam->pix_format; + + imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | + (fmt->bytesperline & IMGSZ_H_MASK); + mcam_reg_write(cam, REG_IMGSIZE, imgsz); + mcam_reg_write(cam, REG_IMGOFFSET, 0); + /* YPITCH just drops the last two bits */ + mcam_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline, + IMGP_YP_MASK); + /* + * Tell the controller about the image format we are using. + */ + switch (cam->pix_format.pixelformat) { + case V4L2_PIX_FMT_YUYV: + mcam_reg_write_mask(cam, REG_CTRL0, + C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV, + C0_DF_MASK); + break; + + case V4L2_PIX_FMT_RGB444: + mcam_reg_write_mask(cam, REG_CTRL0, + C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB, + C0_DF_MASK); + /* Alpha value? */ + break; + + case V4L2_PIX_FMT_RGB565: + mcam_reg_write_mask(cam, REG_CTRL0, + C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR, + C0_DF_MASK); + break; + + default: + cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat); + break; + } + /* + * Make sure it knows we want to use hsync/vsync. + */ + mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, + C0_SIFM_MASK); +} + + +/* + * Configure the controller for operation; caller holds the + * device mutex. + */ +static int mcam_ctlr_configure(struct mcam_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + mcam_ctlr_dma(cam); + mcam_ctlr_image(cam); + mcam_set_config_needed(cam, 0); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return 0; +} + +static void mcam_ctlr_irq_enable(struct mcam_camera *cam) +{ + /* + * Clear any pending interrupts, since we do not + * expect to have I/O active prior to enabling. + */ + mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); + mcam_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS); +} + +static void mcam_ctlr_irq_disable(struct mcam_camera *cam) +{ + mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); +} + +/* + * Make the controller start grabbing images. Everything must + * be set up before doing this. + */ +static void mcam_ctlr_start(struct mcam_camera *cam) +{ + /* set_bit performs a read, so no other barrier should be + needed here */ + mcam_reg_set_bit(cam, REG_CTRL0, C0_ENABLE); +} + +static void mcam_ctlr_stop(struct mcam_camera *cam) +{ + mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); +} + +static void mcam_ctlr_init(struct mcam_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + /* + * Make sure it's not powered down. + */ + mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); + /* + * Turn off the enable bit. It sure should be off anyway, + * but it's good to be sure. + */ + mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); + /* + * Clock the sensor appropriately. Controller clock should + * be 48MHz, sensor "typical" value is half that. + */ + mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + + +/* + * Stop the controller, and don't return until we're really sure that no + * further DMA is going on. + */ +static void mcam_ctlr_stop_dma(struct mcam_camera *cam) +{ + unsigned long flags; + + /* + * Theory: stop the camera controller (whether it is operating + * or not). Delay briefly just in case we race with the SOF + * interrupt, then wait until no DMA is active. + */ + spin_lock_irqsave(&cam->dev_lock, flags); + mcam_ctlr_stop(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); + mdelay(1); + wait_event_timeout(cam->iowait, + !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ); + if (test_bit(CF_DMA_ACTIVE, &cam->flags)) + cam_err(cam, "Timeout waiting for DMA to end\n"); + /* This would be bad news - what now? */ + spin_lock_irqsave(&cam->dev_lock, flags); + cam->state = S_IDLE; + mcam_ctlr_irq_disable(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +/* + * Power up and down. + */ +static void mcam_ctlr_power_up(struct mcam_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cam->plat_power_up(cam); + mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); + spin_unlock_irqrestore(&cam->dev_lock, flags); + msleep(5); /* Just to be sure */ +} + +static void mcam_ctlr_power_down(struct mcam_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + /* + * School of hard knocks department: be sure we do any register + * twiddling on the controller *before* calling the platform + * power down routine. + */ + mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); + cam->plat_power_down(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +/* -------------------------------------------------------------------- */ +/* + * Communications with the sensor. + */ + +static int __mcam_cam_reset(struct mcam_camera *cam) +{ + return sensor_call(cam, core, reset, 0); +} + +/* + * We have found the sensor on the i2c. Let's try to have a + * conversation. + */ +static int mcam_cam_init(struct mcam_camera *cam) +{ + struct v4l2_dbg_chip_ident chip; + int ret; + + mutex_lock(&cam->s_mutex); + if (cam->state != S_NOTREADY) + cam_warn(cam, "Cam init with device in funky state %d", + cam->state); + ret = __mcam_cam_reset(cam); + if (ret) + goto out; + chip.ident = V4L2_IDENT_NONE; + chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR; + chip.match.addr = cam->sensor_addr; + ret = sensor_call(cam, core, g_chip_ident, &chip); + if (ret) + goto out; + cam->sensor_type = chip.ident; + if (cam->sensor_type != V4L2_IDENT_OV7670) { + cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type); + ret = -EINVAL; + goto out; + } +/* Get/set parameters? */ + ret = 0; + cam->state = S_IDLE; +out: + mcam_ctlr_power_down(cam); + mutex_unlock(&cam->s_mutex); + return ret; +} + +/* + * Configure the sensor to match the parameters we have. Caller should + * hold s_mutex + */ +static int mcam_cam_set_flip(struct mcam_camera *cam) +{ + struct v4l2_control ctrl; + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.id = V4L2_CID_VFLIP; + ctrl.value = flip; + return sensor_call(cam, core, s_ctrl, &ctrl); +} + + +static int mcam_cam_configure(struct mcam_camera *cam) +{ + struct v4l2_mbus_framefmt mbus_fmt; + int ret; + + v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code); + ret = sensor_call(cam, core, init, 0); + if (ret == 0) + ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); + /* + * OV7670 does weird things if flip is set *before* format... + */ + ret += mcam_cam_set_flip(cam); + return ret; +} + +/* -------------------------------------------------------------------- */ +/* + * DMA buffer management. These functions need s_mutex held. + */ + +/* FIXME: this is inefficient as hell, since dma_alloc_coherent just + * does a get_free_pages() call, and we waste a good chunk of an orderN + * allocation. Should try to allocate the whole set in one chunk. + */ +static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime) +{ + int i; + + mcam_set_config_needed(cam, 1); + if (loadtime) + cam->dma_buf_size = dma_buf_size; + else + cam->dma_buf_size = cam->pix_format.sizeimage; + if (n_dma_bufs > 3) + n_dma_bufs = 3; + + cam->nbufs = 0; + for (i = 0; i < n_dma_bufs; i++) { + cam->dma_bufs[i] = dma_alloc_coherent(cam->dev, + cam->dma_buf_size, cam->dma_handles + i, + GFP_KERNEL); + if (cam->dma_bufs[i] == NULL) { + cam_warn(cam, "Failed to allocate DMA buffer\n"); + break; + } + /* For debug, remove eventually */ + memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size); + (cam->nbufs)++; + } + + switch (cam->nbufs) { + case 1: + dma_free_coherent(cam->dev, cam->dma_buf_size, + cam->dma_bufs[0], cam->dma_handles[0]); + cam->nbufs = 0; + case 0: + cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); + return -ENOMEM; + + case 2: + if (n_dma_bufs > 2) + cam_warn(cam, "Will limp along with only 2 buffers\n"); + break; + } + return 0; +} + +static void mcam_free_dma_bufs(struct mcam_camera *cam) +{ + int i; + + for (i = 0; i < cam->nbufs; i++) { + dma_free_coherent(cam->dev, cam->dma_buf_size, + cam->dma_bufs[i], cam->dma_handles[i]); + cam->dma_bufs[i] = NULL; + } + cam->nbufs = 0; +} + + + + + +/* ----------------------------------------------------------------------- */ +/* + * Here starts the V4L2 interface code. + */ + +/* + * Read an image from the device. + */ +static ssize_t mcam_deliver_buffer(struct mcam_camera *cam, + char __user *buffer, size_t len, loff_t *pos) +{ + int bufno; + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + if (cam->next_buf < 0) { + cam_err(cam, "deliver_buffer: No next buffer\n"); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return -EIO; + } + bufno = cam->next_buf; + clear_bit(bufno, &cam->flags); + if (++(cam->next_buf) >= cam->nbufs) + cam->next_buf = 0; + if (!test_bit(cam->next_buf, &cam->flags)) + cam->next_buf = -1; + cam->specframes = 0; + spin_unlock_irqrestore(&cam->dev_lock, flags); + + if (len > cam->pix_format.sizeimage) + len = cam->pix_format.sizeimage; + if (copy_to_user(buffer, cam->dma_bufs[bufno], len)) + return -EFAULT; + (*pos) += len; + return len; +} + +/* + * Get everything ready, and start grabbing frames. + */ +static int mcam_read_setup(struct mcam_camera *cam, enum mcam_state state) +{ + int ret; + unsigned long flags; + + /* + * Configuration. If we still don't have DMA buffers, + * make one last, desperate attempt. + */ + if (cam->nbufs == 0) + if (mcam_alloc_dma_bufs(cam, 0)) + return -ENOMEM; + + if (mcam_needs_config(cam)) { + mcam_cam_configure(cam); + ret = mcam_ctlr_configure(cam); + if (ret) + return ret; + } + + /* + * Turn it loose. + */ + spin_lock_irqsave(&cam->dev_lock, flags); + mcam_reset_buffers(cam); + mcam_ctlr_irq_enable(cam); + cam->state = state; + mcam_ctlr_start(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return 0; +} + + +static ssize_t mcam_v4l_read(struct file *filp, + char __user *buffer, size_t len, loff_t *pos) +{ + struct mcam_camera *cam = filp->private_data; + int ret = 0; + + /* + * Perhaps we're in speculative read mode and already + * have data? + */ + mutex_lock(&cam->s_mutex); + if (cam->state == S_SPECREAD) { + if (cam->next_buf >= 0) { + ret = mcam_deliver_buffer(cam, buffer, len, pos); + if (ret != 0) + goto out_unlock; + } + } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) { + ret = -EIO; + goto out_unlock; + } else if (cam->state != S_IDLE) { + ret = -EBUSY; + goto out_unlock; + } + + /* + * v4l2: multiple processes can open the device, but only + * one gets to grab data from it. + */ + if (cam->owner && cam->owner != filp) { + ret = -EBUSY; + goto out_unlock; + } + cam->owner = filp; + + /* + * Do setup if need be. + */ + if (cam->state != S_SPECREAD) { + ret = mcam_read_setup(cam, S_SINGLEREAD); + if (ret) + goto out_unlock; + } + /* + * Wait for something to happen. This should probably + * be interruptible (FIXME). + */ + wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ); + if (cam->next_buf < 0) { + cam_err(cam, "read() operation timed out\n"); + mcam_ctlr_stop_dma(cam); + ret = -EIO; + goto out_unlock; + } + /* + * Give them their data and we should be done. + */ + ret = mcam_deliver_buffer(cam, buffer, len, pos); + +out_unlock: + mutex_unlock(&cam->s_mutex); + return ret; +} + + + + + + + + +/* + * Streaming I/O support. + */ + + + +static int mcam_vidioc_streamon(struct file *filp, void *priv, + enum v4l2_buf_type type) +{ + struct mcam_camera *cam = filp->private_data; + int ret = -EINVAL; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + mutex_lock(&cam->s_mutex); + if (cam->state != S_IDLE || cam->n_sbufs == 0) + goto out_unlock; + + cam->sequence = 0; + ret = mcam_read_setup(cam, S_STREAMING); + +out_unlock: + mutex_unlock(&cam->s_mutex); +out: + return ret; +} + + +static int mcam_vidioc_streamoff(struct file *filp, void *priv, + enum v4l2_buf_type type) +{ + struct mcam_camera *cam = filp->private_data; + int ret = -EINVAL; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + mutex_lock(&cam->s_mutex); + if (cam->state != S_STREAMING) + goto out_unlock; + + mcam_ctlr_stop_dma(cam); + ret = 0; + +out_unlock: + mutex_unlock(&cam->s_mutex); +out: + return ret; +} + + + +static int mcam_setup_siobuf(struct mcam_camera *cam, int index) +{ + struct mcam_sio_buffer *buf = cam->sb_bufs + index; + + INIT_LIST_HEAD(&buf->list); + buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage); + buf->buffer = vmalloc_user(buf->v4lbuf.length); + if (buf->buffer == NULL) + return -ENOMEM; + buf->mapcount = 0; + buf->cam = cam; + + buf->v4lbuf.index = index; + buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf->v4lbuf.field = V4L2_FIELD_NONE; + buf->v4lbuf.memory = V4L2_MEMORY_MMAP; + /* + * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg + * just uses the length times the index, but the spec warns + * against doing just that - vma merging problems. So we + * leave a gap between each pair of buffers. + */ + buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; + return 0; +} + +static int mcam_free_sio_buffers(struct mcam_camera *cam) +{ + int i; + + /* + * If any buffers are mapped, we cannot free them at all. + */ + for (i = 0; i < cam->n_sbufs; i++) + if (cam->sb_bufs[i].mapcount > 0) + return -EBUSY; + /* + * OK, let's do it. + */ + for (i = 0; i < cam->n_sbufs; i++) + vfree(cam->sb_bufs[i].buffer); + cam->n_sbufs = 0; + kfree(cam->sb_bufs); + cam->sb_bufs = NULL; + INIT_LIST_HEAD(&cam->sb_avail); + INIT_LIST_HEAD(&cam->sb_full); + return 0; +} + + + +static int mcam_vidioc_reqbufs(struct file *filp, void *priv, + struct v4l2_requestbuffers *req) +{ + struct mcam_camera *cam = filp->private_data; + int ret = 0; /* Silence warning */ + + /* + * Make sure it's something we can do. User pointers could be + * implemented without great pain, but that's not been done yet. + */ + if (req->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + /* + * If they ask for zero buffers, they really want us to stop streaming + * (if it's happening) and free everything. Should we check owner? + */ + mutex_lock(&cam->s_mutex); + if (req->count == 0) { + if (cam->state == S_STREAMING) + mcam_ctlr_stop_dma(cam); + ret = mcam_free_sio_buffers(cam); + goto out; + } + /* + * Device needs to be idle and working. We *could* try to do the + * right thing in S_SPECREAD by shutting things down, but it + * probably doesn't matter. + */ + if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) { + ret = -EBUSY; + goto out; + } + cam->owner = filp; + + if (req->count < min_buffers) + req->count = min_buffers; + else if (req->count > max_buffers) + req->count = max_buffers; + if (cam->n_sbufs > 0) { + ret = mcam_free_sio_buffers(cam); + if (ret) + goto out; + } + + cam->sb_bufs = kzalloc(req->count*sizeof(struct mcam_sio_buffer), + GFP_KERNEL); + if (cam->sb_bufs == NULL) { + ret = -ENOMEM; + goto out; + } + for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) { + ret = mcam_setup_siobuf(cam, cam->n_sbufs); + if (ret) + break; + } + + if (cam->n_sbufs == 0) /* no luck at all - ret already set */ + kfree(cam->sb_bufs); + req->count = cam->n_sbufs; /* In case of partial success */ + +out: + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_vidioc_querybuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct mcam_camera *cam = filp->private_data; + int ret = -EINVAL; + + mutex_lock(&cam->s_mutex); + if (buf->index >= cam->n_sbufs) + goto out; + *buf = cam->sb_bufs[buf->index].v4lbuf; + ret = 0; +out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int mcam_vidioc_qbuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct mcam_camera *cam = filp->private_data; + struct mcam_sio_buffer *sbuf; + int ret = -EINVAL; + unsigned long flags; + + mutex_lock(&cam->s_mutex); + if (buf->index >= cam->n_sbufs) + goto out; + sbuf = cam->sb_bufs + buf->index; + if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) { + ret = 0; /* Already queued?? */ + goto out; + } + if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) { + /* Spec doesn't say anything, seems appropriate tho */ + ret = -EBUSY; + goto out; + } + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; + spin_lock_irqsave(&cam->dev_lock, flags); + list_add(&sbuf->list, &cam->sb_avail); + spin_unlock_irqrestore(&cam->dev_lock, flags); + ret = 0; +out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int mcam_vidioc_dqbuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct mcam_camera *cam = filp->private_data; + struct mcam_sio_buffer *sbuf; + int ret = -EINVAL; + unsigned long flags; + + mutex_lock(&cam->s_mutex); + if (cam->state != S_STREAMING) + goto out_unlock; + if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto out_unlock; + } + + while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) { + mutex_unlock(&cam->s_mutex); + if (wait_event_interruptible(cam->iowait, + !list_empty(&cam->sb_full))) { + ret = -ERESTARTSYS; + goto out; + } + mutex_lock(&cam->s_mutex); + } + + if (cam->state != S_STREAMING) + ret = -EINTR; + else { + spin_lock_irqsave(&cam->dev_lock, flags); + /* Should probably recheck !list_empty() here */ + sbuf = list_entry(cam->sb_full.next, + struct mcam_sio_buffer, list); + list_del_init(&sbuf->list); + spin_unlock_irqrestore(&cam->dev_lock, flags); + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; + *buf = sbuf->v4lbuf; + ret = 0; + } + +out_unlock: + mutex_unlock(&cam->s_mutex); +out: + return ret; +} + + + +static void mcam_v4l_vm_open(struct vm_area_struct *vma) +{ + struct mcam_sio_buffer *sbuf = vma->vm_private_data; + /* + * Locking: done under mmap_sem, so we don't need to + * go back to the camera lock here. + */ + sbuf->mapcount++; +} + + +static void mcam_v4l_vm_close(struct vm_area_struct *vma) +{ + struct mcam_sio_buffer *sbuf = vma->vm_private_data; + + mutex_lock(&sbuf->cam->s_mutex); + sbuf->mapcount--; + /* Docs say we should stop I/O too... */ + if (sbuf->mapcount == 0) + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; + mutex_unlock(&sbuf->cam->s_mutex); +} + +static const struct vm_operations_struct mcam_v4l_vm_ops = { + .open = mcam_v4l_vm_open, + .close = mcam_v4l_vm_close +}; + + +static int mcam_v4l_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct mcam_camera *cam = filp->private_data; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + int ret = -EINVAL; + int i; + struct mcam_sio_buffer *sbuf = NULL; + + if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) + return -EINVAL; + /* + * Find the buffer they are looking for. + */ + mutex_lock(&cam->s_mutex); + for (i = 0; i < cam->n_sbufs; i++) + if (cam->sb_bufs[i].v4lbuf.m.offset == offset) { + sbuf = cam->sb_bufs + i; + break; + } + if (sbuf == NULL) + goto out; + + ret = remap_vmalloc_range(vma, sbuf->buffer, 0); + if (ret) + goto out; + vma->vm_flags |= VM_DONTEXPAND; + vma->vm_private_data = sbuf; + vma->vm_ops = &mcam_v4l_vm_ops; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; + mcam_v4l_vm_open(vma); + ret = 0; +out: + mutex_unlock(&cam->s_mutex); + return ret; +} + + + +static int mcam_v4l_open(struct file *filp) +{ + struct mcam_camera *cam = video_drvdata(filp); + + filp->private_data = cam; + + mutex_lock(&cam->s_mutex); + if (cam->users == 0) { + mcam_ctlr_power_up(cam); + __mcam_cam_reset(cam); + mcam_set_config_needed(cam, 1); + /* FIXME make sure this is complete */ + } + (cam->users)++; + mutex_unlock(&cam->s_mutex); + return 0; +} + + +static int mcam_v4l_release(struct file *filp) +{ + struct mcam_camera *cam = filp->private_data; + + mutex_lock(&cam->s_mutex); + (cam->users)--; + if (filp == cam->owner) { + mcam_ctlr_stop_dma(cam); + mcam_free_sio_buffers(cam); + cam->owner = NULL; + } + if (cam->users == 0) { + mcam_ctlr_power_down(cam); + if (alloc_bufs_at_read) + mcam_free_dma_bufs(cam); + } + mutex_unlock(&cam->s_mutex); + return 0; +} + + + +static unsigned int mcam_v4l_poll(struct file *filp, + struct poll_table_struct *pt) +{ + struct mcam_camera *cam = filp->private_data; + + poll_wait(filp, &cam->iowait, pt); + if (cam->next_buf >= 0) + return POLLIN | POLLRDNORM; + return 0; +} + + + +static int mcam_vidioc_queryctrl(struct file *filp, void *priv, + struct v4l2_queryctrl *qc) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, core, queryctrl, qc); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_vidioc_g_ctrl(struct file *filp, void *priv, + struct v4l2_control *ctrl) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, core, g_ctrl, ctrl); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int mcam_vidioc_s_ctrl(struct file *filp, void *priv, + struct v4l2_control *ctrl) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, core, s_ctrl, ctrl); + mutex_unlock(&cam->s_mutex); + return ret; +} + + + + + +static int mcam_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strcpy(cap->driver, "marvell_ccic"); + strcpy(cap->card, "marvell_ccic"); + cap->version = 1; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + return 0; +} + + +/* + * The default format we use until somebody says otherwise. + */ +static const struct v4l2_pix_format mcam_def_pix_format = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .pixelformat = V4L2_PIX_FMT_YUYV, + .field = V4L2_FIELD_NONE, + .bytesperline = VGA_WIDTH*2, + .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, +}; + +static const enum v4l2_mbus_pixelcode mcam_def_mbus_code = + V4L2_MBUS_FMT_YUYV8_2X8; + +static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp, + void *priv, struct v4l2_fmtdesc *fmt) +{ + if (fmt->index >= N_MCAM_FMTS) + return -EINVAL; + strlcpy(fmt->description, mcam_formats[fmt->index].desc, + sizeof(fmt->description)); + fmt->pixelformat = mcam_formats[fmt->index].pixelformat; + return 0; +} + +static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + struct mcam_camera *cam = priv; + struct mcam_format_struct *f; + struct v4l2_pix_format *pix = &fmt->fmt.pix; + struct v4l2_mbus_framefmt mbus_fmt; + int ret; + + f = mcam_find_format(pix->pixelformat); + pix->pixelformat = f->pixelformat; + v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code); + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); + mutex_unlock(&cam->s_mutex); + v4l2_fill_pix_format(pix, &mbus_fmt); + pix->bytesperline = pix->width * f->bpp; + pix->sizeimage = pix->height * pix->bytesperline; + return ret; +} + +static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + struct mcam_camera *cam = priv; + struct mcam_format_struct *f; + int ret; + + /* + * Can't do anything if the device is not idle + * Also can't if there are streaming buffers in place. + */ + if (cam->state != S_IDLE || cam->n_sbufs > 0) + return -EBUSY; + + f = mcam_find_format(fmt->fmt.pix.pixelformat); + + /* + * See if the formatting works in principle. + */ + ret = mcam_vidioc_try_fmt_vid_cap(filp, priv, fmt); + if (ret) + return ret; + /* + * Now we start to change things for real, so let's do it + * under lock. + */ + mutex_lock(&cam->s_mutex); + cam->pix_format = fmt->fmt.pix; + cam->mbus_code = f->mbus_code; + + /* + * Make sure we have appropriate DMA buffers. + */ + ret = -ENOMEM; + if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage) + mcam_free_dma_bufs(cam); + if (cam->nbufs == 0) { + if (mcam_alloc_dma_bufs(cam, 0)) + goto out; + } + /* + * It looks like this might work, so let's program the sensor. + */ + ret = mcam_cam_configure(cam); + if (!ret) + ret = mcam_ctlr_configure(cam); +out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +/* + * Return our stored notion of how the camera is/should be configured. + * The V4l2 spec wants us to be smarter, and actually get this from + * the camera (and not mess with it at open time). Someday. + */ +static int mcam_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *f) +{ + struct mcam_camera *cam = priv; + + f->fmt.pix = cam->pix_format; + return 0; +} + +/* + * We only have one input - the sensor - so minimize the nonsense here. + */ +static int mcam_vidioc_enum_input(struct file *filp, void *priv, + struct v4l2_input *input) +{ + if (input->index != 0) + return -EINVAL; + + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = V4L2_STD_ALL; /* Not sure what should go here */ + strcpy(input->name, "Camera"); + return 0; +} + +static int mcam_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + return 0; +} + +/* from vivi.c */ +static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) +{ + return 0; +} + +/* + * G/S_PARM. Most of this is done by the sensor, but we are + * the level which controls the number of read buffers. + */ +static int mcam_vidioc_g_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parms) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, g_parm, parms); + mutex_unlock(&cam->s_mutex); + parms->parm.capture.readbuffers = n_dma_bufs; + return ret; +} + +static int mcam_vidioc_s_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parms) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, s_parm, parms); + mutex_unlock(&cam->s_mutex); + parms->parm.capture.readbuffers = n_dma_bufs; + return ret; +} + +static int mcam_vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + struct mcam_camera *cam = priv; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (v4l2_chip_match_host(&chip->match)) { + chip->ident = cam->chip_id; + return 0; + } + return sensor_call(cam, core, g_chip_ident, chip); +} + +static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv, + struct v4l2_frmsizeenum *sizes) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, enum_framesizes, sizes); + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv, + struct v4l2_frmivalenum *interval) +{ + struct mcam_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = sensor_call(cam, video, enum_frameintervals, interval); + mutex_unlock(&cam->s_mutex); + return ret; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mcam_vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct mcam_camera *cam = priv; + + if (v4l2_chip_match_host(®->match)) { + reg->val = mcam_reg_read(cam, reg->reg); + reg->size = 4; + return 0; + } + return sensor_call(cam, core, g_register, reg); +} + +static int mcam_vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct mcam_camera *cam = priv; + + if (v4l2_chip_match_host(®->match)) { + mcam_reg_write(cam, reg->reg, reg->val); + return 0; + } + return sensor_call(cam, core, s_register, reg); +} +#endif + +/* + * This template device holds all of those v4l2 methods; we + * clone it for specific real devices. + */ + +static const struct v4l2_file_operations mcam_v4l_fops = { + .owner = THIS_MODULE, + .open = mcam_v4l_open, + .release = mcam_v4l_release, + .read = mcam_v4l_read, + .poll = mcam_v4l_poll, + .mmap = mcam_v4l_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = { + .vidioc_querycap = mcam_vidioc_querycap, + .vidioc_enum_fmt_vid_cap = mcam_vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = mcam_vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = mcam_vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = mcam_vidioc_g_fmt_vid_cap, + .vidioc_enum_input = mcam_vidioc_enum_input, + .vidioc_g_input = mcam_vidioc_g_input, + .vidioc_s_input = mcam_vidioc_s_input, + .vidioc_s_std = mcam_vidioc_s_std, + .vidioc_reqbufs = mcam_vidioc_reqbufs, + .vidioc_querybuf = mcam_vidioc_querybuf, + .vidioc_qbuf = mcam_vidioc_qbuf, + .vidioc_dqbuf = mcam_vidioc_dqbuf, + .vidioc_streamon = mcam_vidioc_streamon, + .vidioc_streamoff = mcam_vidioc_streamoff, + .vidioc_queryctrl = mcam_vidioc_queryctrl, + .vidioc_g_ctrl = mcam_vidioc_g_ctrl, + .vidioc_s_ctrl = mcam_vidioc_s_ctrl, + .vidioc_g_parm = mcam_vidioc_g_parm, + .vidioc_s_parm = mcam_vidioc_s_parm, + .vidioc_enum_framesizes = mcam_vidioc_enum_framesizes, + .vidioc_enum_frameintervals = mcam_vidioc_enum_frameintervals, + .vidioc_g_chip_ident = mcam_vidioc_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = mcam_vidioc_g_register, + .vidioc_s_register = mcam_vidioc_s_register, +#endif +}; + +static struct video_device mcam_v4l_template = { + .name = "mcam", + .tvnorms = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ + + .fops = &mcam_v4l_fops, + .ioctl_ops = &mcam_v4l_ioctl_ops, + .release = video_device_release_empty, +}; + +/* ---------------------------------------------------------------------- */ +/* + * Interrupt handler stuff + */ + + + +static void mcam_frame_tasklet(unsigned long data) +{ + struct mcam_camera *cam = (struct mcam_camera *) data; + int i; + unsigned long flags; + struct mcam_sio_buffer *sbuf; + + spin_lock_irqsave(&cam->dev_lock, flags); + for (i = 0; i < cam->nbufs; i++) { + int bufno = cam->next_buf; + if (bufno < 0) { /* "will never happen" */ + cam_err(cam, "No valid bufs in tasklet!\n"); + break; + } + if (++(cam->next_buf) >= cam->nbufs) + cam->next_buf = 0; + if (!test_bit(bufno, &cam->flags)) + continue; + if (list_empty(&cam->sb_avail)) + break; /* Leave it valid, hope for better later */ + clear_bit(bufno, &cam->flags); + sbuf = list_entry(cam->sb_avail.next, + struct mcam_sio_buffer, list); + /* + * Drop the lock during the big copy. This *should* be safe... + */ + spin_unlock_irqrestore(&cam->dev_lock, flags); + memcpy(sbuf->buffer, cam->dma_bufs[bufno], + cam->pix_format.sizeimage); + sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; + sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; + spin_lock_irqsave(&cam->dev_lock, flags); + list_move_tail(&sbuf->list, &cam->sb_full); + } + if (!list_empty(&cam->sb_full)) + wake_up(&cam->iowait); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + + + +static void mcam_frame_complete(struct mcam_camera *cam, int frame) +{ + /* + * Basic frame housekeeping. + */ + if (test_bit(frame, &cam->flags) && printk_ratelimit()) + cam_err(cam, "Frame overrun on %d, frames lost\n", frame); + set_bit(frame, &cam->flags); + clear_bit(CF_DMA_ACTIVE, &cam->flags); + if (cam->next_buf < 0) + cam->next_buf = frame; + cam->buf_seq[frame] = ++(cam->sequence); + + switch (cam->state) { + /* + * If in single read mode, try going speculative. + */ + case S_SINGLEREAD: + cam->state = S_SPECREAD; + cam->specframes = 0; + wake_up(&cam->iowait); + break; + + /* + * If we are already doing speculative reads, and nobody is + * reading them, just stop. + */ + case S_SPECREAD: + if (++(cam->specframes) >= cam->nbufs) { + mcam_ctlr_stop(cam); + mcam_ctlr_irq_disable(cam); + cam->state = S_IDLE; + } + wake_up(&cam->iowait); + break; + /* + * For the streaming case, we defer the real work to the + * camera tasklet. + * + * FIXME: if the application is not consuming the buffers, + * we should eventually put things on hold and restart in + * vidioc_dqbuf(). + */ + case S_STREAMING: + tasklet_schedule(&cam->s_tasklet); + break; + + default: + cam_err(cam, "Frame interrupt in non-operational state\n"); + break; + } +} + + + + +int mccic_irq(struct mcam_camera *cam, unsigned int irqs) +{ + unsigned int frame, handled = 0; + + mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */ + /* + * Handle any frame completions. There really should + * not be more than one of these, or we have fallen + * far behind. + */ + for (frame = 0; frame < cam->nbufs; frame++) + if (irqs & (IRQ_EOF0 << frame)) { + mcam_frame_complete(cam, frame); + handled = 1; + } + /* + * If a frame starts, note that we have DMA active. This + * code assumes that we won't get multiple frame interrupts + * at once; may want to rethink that. + */ + if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) { + set_bit(CF_DMA_ACTIVE, &cam->flags); + handled = 1; + } + return handled; +} + +/* + * Registration and such. + */ + +static struct ov7670_config sensor_cfg = { + /* + * Exclude QCIF mode, because it only captures a tiny portion + * of the sensor FOV + */ + .min_width = 320, + .min_height = 240, +}; + + +int mccic_register(struct mcam_camera *cam) +{ + struct i2c_board_info ov7670_info = { + .type = "ov7670", + .addr = 0x42 >> 1, + .platform_data = &sensor_cfg, + }; + int ret; + + /* + * Register with V4L + */ + ret = v4l2_device_register(cam->dev, &cam->v4l2_dev); + if (ret) + return ret; + + mutex_init(&cam->s_mutex); + cam->state = S_NOTREADY; + mcam_set_config_needed(cam, 1); + init_waitqueue_head(&cam->iowait); + cam->pix_format = mcam_def_pix_format; + cam->mbus_code = mcam_def_mbus_code; + INIT_LIST_HEAD(&cam->dev_list); + INIT_LIST_HEAD(&cam->sb_avail); + INIT_LIST_HEAD(&cam->sb_full); + tasklet_init(&cam->s_tasklet, mcam_frame_tasklet, (unsigned long) cam); + + mcam_ctlr_init(cam); + + /* + * Try to find the sensor. + */ + sensor_cfg.clock_speed = cam->clock_speed; + sensor_cfg.use_smbus = cam->use_smbus; + cam->sensor_addr = ov7670_info.addr; + cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, + cam->i2c_adapter, &ov7670_info, NULL); + if (cam->sensor == NULL) { + ret = -ENODEV; + goto out_unregister; + } + + ret = mcam_cam_init(cam); + if (ret) + goto out_unregister; + /* + * Get the v4l2 setup done. + */ + mutex_lock(&cam->s_mutex); + cam->vdev = mcam_v4l_template; + cam->vdev.debug = 0; + cam->vdev.v4l2_dev = &cam->v4l2_dev; + ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); + if (ret) + goto out; + video_set_drvdata(&cam->vdev, cam); + + /* + * If so requested, try to get our DMA buffers now. + */ + if (!alloc_bufs_at_read) { + if (mcam_alloc_dma_bufs(cam, 1)) + cam_warn(cam, "Unable to alloc DMA buffers at load" + " will try again later."); + } + +out: + mutex_unlock(&cam->s_mutex); + return ret; +out_unregister: + v4l2_device_unregister(&cam->v4l2_dev); + return ret; +} + + +void mccic_shutdown(struct mcam_camera *cam) +{ + /* + * If we have no users (and we really, really should have no + * users) the device will already be powered down. Trying to + * take it down again will wedge the machine, which is frowned + * upon. + */ + if (cam->users > 0) { + cam_warn(cam, "Removing a device with users!\n"); + mcam_ctlr_power_down(cam); + } + mcam_free_dma_bufs(cam); + if (cam->n_sbufs > 0) + /* What if they are still mapped? Shouldn't be, but... */ + mcam_free_sio_buffers(cam); + video_unregister_device(&cam->vdev); + v4l2_device_unregister(&cam->v4l2_dev); +} + +/* + * Power management + */ +#ifdef CONFIG_PM + +void mccic_suspend(struct mcam_camera *cam) +{ + enum mcam_state cstate = cam->state; + + mcam_ctlr_stop_dma(cam); + mcam_ctlr_power_down(cam); + cam->state = cstate; +} + +int mccic_resume(struct mcam_camera *cam) +{ + int ret = 0; + + mutex_lock(&cam->s_mutex); + if (cam->users > 0) { + mcam_ctlr_power_up(cam); + __mcam_cam_reset(cam); + } else { + mcam_ctlr_power_down(cam); + } + mutex_unlock(&cam->s_mutex); + + set_bit(CF_CONFIG_NEEDED, &cam->flags); + if (cam->state == S_SPECREAD) + cam->state = S_IDLE; /* Don't bother restarting */ + else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING) + ret = mcam_read_setup(cam, cam->state); + return ret; +} +#endif /* CONFIG_PM */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mcam-core.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mcam-core.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mcam-core.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mcam-core.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,259 @@ +/* + * Marvell camera core structures. + * + * Copyright 2011 Jonathan Corbet corbet@lwn.net + */ + +/* + * Tracking of streaming I/O buffers. + * FIXME doesn't belong in this file + */ +struct mcam_sio_buffer { + struct list_head list; + struct v4l2_buffer v4lbuf; + char *buffer; /* Where it lives in kernel space */ + int mapcount; + struct mcam_camera *cam; +}; + +enum mcam_state { + S_NOTREADY, /* Not yet initialized */ + S_IDLE, /* Just hanging around */ + S_FLAKED, /* Some sort of problem */ + S_SINGLEREAD, /* In read() */ + S_SPECREAD, /* Speculative read (for future read()) */ + S_STREAMING /* Streaming data */ +}; +#define MAX_DMA_BUFS 3 + +/* + * A description of one of our devices. + * Locking: controlled by s_mutex. Certain fields, however, require + * the dev_lock spinlock; they are marked as such by comments. + * dev_lock is also required for access to device registers. + */ +struct mcam_camera { + /* + * These fields should be set by the platform code prior to + * calling mcam_register(). + */ + struct i2c_adapter *i2c_adapter; + unsigned char __iomem *regs; + spinlock_t dev_lock; + struct device *dev; /* For messages, dma alloc */ + unsigned int chip_id; + short int clock_speed; /* Sensor clock speed, default 30 */ + short int use_smbus; /* SMBUS or straight I2c? */ + + /* + * Callbacks from the core to the platform code. + */ + void (*plat_power_up) (struct mcam_camera *cam); + void (*plat_power_down) (struct mcam_camera *cam); + + /* + * Everything below here is private to the mcam core and + * should not be touched by the platform code. + */ + struct v4l2_device v4l2_dev; + enum mcam_state state; + unsigned long flags; /* Buffer status, mainly (dev_lock) */ + int users; /* How many open FDs */ + struct file *owner; /* Who has data access (v4l2) */ + + /* + * Subsystem structures. + */ + struct video_device vdev; + struct v4l2_subdev *sensor; + unsigned short sensor_addr; + + struct list_head dev_list; /* link to other devices */ + + /* DMA buffers */ + unsigned int nbufs; /* How many are alloc'd */ + int next_buf; /* Next to consume (dev_lock) */ + unsigned int dma_buf_size; /* allocated size */ + void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ + dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */ + unsigned int specframes; /* Unconsumed spec frames (dev_lock) */ + unsigned int sequence; /* Frame sequence number */ + unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */ + + /* Streaming buffers */ + unsigned int n_sbufs; /* How many we have */ + struct mcam_sio_buffer *sb_bufs; /* The array of housekeeping structs */ + struct list_head sb_avail; /* Available for data (we own) (dev_lock) */ + struct list_head sb_full; /* With data (user space owns) (dev_lock) */ + struct tasklet_struct s_tasklet; + + /* Current operating parameters */ + u32 sensor_type; /* Currently ov7670 only */ + struct v4l2_pix_format pix_format; + enum v4l2_mbus_pixelcode mbus_code; + + /* Locks */ + struct mutex s_mutex; /* Access to this structure */ + + /* Misc */ + wait_queue_head_t iowait; /* Waiting on frame data */ +}; + + +/* + * Register I/O functions. These are here because the platform code + * may legitimately need to mess with the register space. + */ +/* + * Device register I/O + */ +static inline void mcam_reg_write(struct mcam_camera *cam, unsigned int reg, + unsigned int val) +{ + iowrite32(val, cam->regs + reg); +} + +static inline unsigned int mcam_reg_read(struct mcam_camera *cam, + unsigned int reg) +{ + return ioread32(cam->regs + reg); +} + + +static inline void mcam_reg_write_mask(struct mcam_camera *cam, unsigned int reg, + unsigned int val, unsigned int mask) +{ + unsigned int v = mcam_reg_read(cam, reg); + + v = (v & ~mask) | (val & mask); + mcam_reg_write(cam, reg, v); +} + +static inline void mcam_reg_clear_bit(struct mcam_camera *cam, + unsigned int reg, unsigned int val) +{ + mcam_reg_write_mask(cam, reg, 0, val); +} + +static inline void mcam_reg_set_bit(struct mcam_camera *cam, + unsigned int reg, unsigned int val) +{ + mcam_reg_write_mask(cam, reg, val, val); +} + +/* + * Functions for use by platform code. + */ +int mccic_register(struct mcam_camera *cam); +int mccic_irq(struct mcam_camera *cam, unsigned int irqs); +void mccic_shutdown(struct mcam_camera *cam); +#ifdef CONFIG_PM +void mccic_suspend(struct mcam_camera *cam); +int mccic_resume(struct mcam_camera *cam); +#endif + +/* + * Register definitions for the m88alp01 camera interface. Offsets in bytes + * as given in the spec. + */ +#define REG_Y0BAR 0x00 +#define REG_Y1BAR 0x04 +#define REG_Y2BAR 0x08 +/* ... */ + +#define REG_IMGPITCH 0x24 /* Image pitch register */ +#define IMGP_YP_SHFT 2 /* Y pitch params */ +#define IMGP_YP_MASK 0x00003ffc /* Y pitch field */ +#define IMGP_UVP_SHFT 18 /* UV pitch (planar) */ +#define IMGP_UVP_MASK 0x3ffc0000 +#define REG_IRQSTATRAW 0x28 /* RAW IRQ Status */ +#define IRQ_EOF0 0x00000001 /* End of frame 0 */ +#define IRQ_EOF1 0x00000002 /* End of frame 1 */ +#define IRQ_EOF2 0x00000004 /* End of frame 2 */ +#define IRQ_SOF0 0x00000008 /* Start of frame 0 */ +#define IRQ_SOF1 0x00000010 /* Start of frame 1 */ +#define IRQ_SOF2 0x00000020 /* Start of frame 2 */ +#define IRQ_OVERFLOW 0x00000040 /* FIFO overflow */ +#define IRQ_TWSIW 0x00010000 /* TWSI (smbus) write */ +#define IRQ_TWSIR 0x00020000 /* TWSI read */ +#define IRQ_TWSIE 0x00040000 /* TWSI error */ +#define TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE) +#define FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2) +#define ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW) +#define REG_IRQMASK 0x2c /* IRQ mask - same bits as IRQSTAT */ +#define REG_IRQSTAT 0x30 /* IRQ status / clear */ + +#define REG_IMGSIZE 0x34 /* Image size */ +#define IMGSZ_V_MASK 0x1fff0000 +#define IMGSZ_V_SHIFT 16 +#define IMGSZ_H_MASK 0x00003fff +#define REG_IMGOFFSET 0x38 /* IMage offset */ + +#define REG_CTRL0 0x3c /* Control 0 */ +#define C0_ENABLE 0x00000001 /* Makes the whole thing go */ + +/* Mask for all the format bits */ +#define C0_DF_MASK 0x00fffffc /* Bits 2-23 */ + +/* RGB ordering */ +#define C0_RGB4_RGBX 0x00000000 +#define C0_RGB4_XRGB 0x00000004 +#define C0_RGB4_BGRX 0x00000008 +#define C0_RGB4_XBGR 0x0000000c +#define C0_RGB5_RGGB 0x00000000 +#define C0_RGB5_GRBG 0x00000004 +#define C0_RGB5_GBRG 0x00000008 +#define C0_RGB5_BGGR 0x0000000c + +/* Spec has two fields for DIN and DOUT, but they must match, so + combine them here. */ +#define C0_DF_YUV 0x00000000 /* Data is YUV */ +#define C0_DF_RGB 0x000000a0 /* ... RGB */ +#define C0_DF_BAYER 0x00000140 /* ... Bayer */ +/* 8-8-8 must be missing from the below - ask */ +#define C0_RGBF_565 0x00000000 +#define C0_RGBF_444 0x00000800 +#define C0_RGB_BGR 0x00001000 /* Blue comes first */ +#define C0_YUV_PLANAR 0x00000000 /* YUV 422 planar format */ +#define C0_YUV_PACKED 0x00008000 /* YUV 422 packed */ +#define C0_YUV_420PL 0x0000a000 /* YUV 420 planar */ +/* Think that 420 packed must be 111 - ask */ +#define C0_YUVE_YUYV 0x00000000 /* Y1CbY0Cr */ +#define C0_YUVE_YVYU 0x00010000 /* Y1CrY0Cb */ +#define C0_YUVE_VYUY 0x00020000 /* CrY1CbY0 */ +#define C0_YUVE_UYVY 0x00030000 /* CbY1CrY0 */ +#define C0_YUVE_XYUV 0x00000000 /* 420: .YUV */ +#define C0_YUVE_XYVU 0x00010000 /* 420: .YVU */ +#define C0_YUVE_XUVY 0x00020000 /* 420: .UVY */ +#define C0_YUVE_XVUY 0x00030000 /* 420: .VUY */ +/* Bayer bits 18,19 if needed */ +#define C0_HPOL_LOW 0x01000000 /* HSYNC polarity active low */ +#define C0_VPOL_LOW 0x02000000 /* VSYNC polarity active low */ +#define C0_VCLK_LOW 0x04000000 /* VCLK on falling edge */ +#define C0_DOWNSCALE 0x08000000 /* Enable downscaler */ +#define C0_SIFM_MASK 0xc0000000 /* SIF mode bits */ +#define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */ +#define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */ + + +#define REG_CTRL1 0x40 /* Control 1 */ +#define C1_444ALPHA 0x00f00000 /* Alpha field in RGB444 */ +#define C1_ALPHA_SHFT 20 +#define C1_DMAB32 0x00000000 /* 32-byte DMA burst */ +#define C1_DMAB16 0x02000000 /* 16-byte DMA burst */ +#define C1_DMAB64 0x04000000 /* 64-byte DMA burst */ +#define C1_DMAB_MASK 0x06000000 +#define C1_TWOBUFS 0x08000000 /* Use only two DMA buffers */ +#define C1_PWRDWN 0x10000000 /* Power down */ + +#define REG_CLKCTRL 0x88 /* Clock control */ +#define CLK_DIV_MASK 0x0000ffff /* Upper bits RW "reserved" */ + +/* This appears to be a Cafe-only register */ +#define REG_UBAR 0xc4 /* Upper base address register */ + +/* + * Useful stuff that probably belongs somewhere global. + */ +#define VGA_WIDTH 640 +#define VGA_HEIGHT 480 diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mmp-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mmp-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mmp-driver.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/marvell-ccic/mmp-driver.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,339 @@ +/* + * Support for the camera device found on Marvell MMP processors; known + * to work with the Armada 610 as used in the OLPC 1.75 system. + * + * Copyright 2011 Jonathan Corbet + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcam-core.h" + +MODULE_AUTHOR("Jonathan Corbet "); +MODULE_LICENSE("GPL"); + +struct mmp_camera { + void *power_regs; + struct platform_device *pdev; + struct mcam_camera mcam; + struct list_head devlist; + int irq; +}; + +static inline struct mmp_camera *mcam_to_cam(struct mcam_camera *mcam) +{ + return container_of(mcam, struct mmp_camera, mcam); +} + +/* + * A silly little infrastructure so we can keep track of our devices. + * Chances are that we will never have more than one of them, but + * the Armada 610 *does* have two controllers... + */ + +static LIST_HEAD(mmpcam_devices); +static struct mutex mmpcam_devices_lock; + +static void mmpcam_add_device(struct mmp_camera *cam) +{ + mutex_lock(&mmpcam_devices_lock); + list_add(&cam->devlist, &mmpcam_devices); + mutex_unlock(&mmpcam_devices_lock); +} + +static void mmpcam_remove_device(struct mmp_camera *cam) +{ + mutex_lock(&mmpcam_devices_lock); + list_del(&cam->devlist); + mutex_unlock(&mmpcam_devices_lock); +} + +/* + * Platform dev remove passes us a platform_device, and there's + * no handy unused drvdata to stash a backpointer in. So just + * dig it out of our list. + */ +static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev) +{ + struct mmp_camera *cam; + + mutex_lock(&mmpcam_devices_lock); + list_for_each_entry(cam, &mmpcam_devices, devlist) { + if (cam->pdev == pdev) { + mutex_unlock(&mmpcam_devices_lock); + return cam; + } + } + mutex_unlock(&mmpcam_devices_lock); + return NULL; +} + + + + +/* + * Power-related registers; this almost certainly belongs + * somewhere else. + * + * ARMADA 610 register manual, sec 7.2.1, p1842. + */ +#define CPU_SUBSYS_PMU_BASE 0xd4282800 +#define REG_CCIC_DCGCR 0x28 /* CCIC dyn clock gate ctrl reg */ +#define REG_CCIC_CRCR 0x50 /* CCIC clk reset ctrl reg */ + +/* + * Power control. + */ +static void mmpcam_power_up(struct mcam_camera *mcam) +{ + struct mmp_camera *cam = mcam_to_cam(mcam); + struct mmp_camera_platform_data *pdata; +/* + * Turn on power and clocks to the controller. + */ + iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); + iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); + mdelay(1); +/* + * Provide power to the sensor. + */ + mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002); + pdata = cam->pdev->dev.platform_data; + gpio_set_value(pdata->sensor_power_gpio, 1); + mdelay(5); + mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000); + gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */ + mdelay(5); + gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */ + mdelay(5); +} + +static void mmpcam_power_down(struct mcam_camera *mcam) +{ + struct mmp_camera *cam = mcam_to_cam(mcam); + struct mmp_camera_platform_data *pdata; +/* + * Turn off clocks and set reset lines + */ + iowrite32(0, cam->power_regs + REG_CCIC_DCGCR); + iowrite32(0, cam->power_regs + REG_CCIC_CRCR); +/* + * Shut down the sensor. + */ + pdata = cam->pdev->dev.platform_data; + gpio_set_value(pdata->sensor_power_gpio, 0); + gpio_set_value(pdata->sensor_reset_gpio, 0); +} + + +static irqreturn_t mmpcam_irq(int irq, void *data) +{ + struct mcam_camera *mcam = data; + unsigned int irqs, handled; + + spin_lock(&mcam->dev_lock); + irqs = mcam_reg_read(mcam, REG_IRQSTAT); + handled = mccic_irq(mcam, irqs); + spin_unlock(&mcam->dev_lock); + return IRQ_RETVAL(handled); +} + + +static int mmpcam_probe(struct platform_device *pdev) +{ + struct mmp_camera *cam; + struct mcam_camera *mcam; + struct resource *res; + struct mmp_camera_platform_data *pdata; + int ret; + + cam = kzalloc(sizeof(*cam), GFP_KERNEL); + if (cam == NULL) + return -ENOMEM; + cam->pdev = pdev; + INIT_LIST_HEAD(&cam->devlist); + + mcam = &cam->mcam; + mcam->platform = MHP_Armada610; + mcam->plat_power_up = mmpcam_power_up; + mcam->plat_power_down = mmpcam_power_down; + mcam->dev = &pdev->dev; + mcam->use_smbus = 0; + mcam->chip_id = V4L2_IDENT_ARMADA610; + spin_lock_init(&mcam->dev_lock); + /* + * Get our I/O memory. + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no iomem resource!\n"); + ret = -ENODEV; + goto out_free; + } + mcam->regs = ioremap(res->start, resource_size(res)); + if (mcam->regs == NULL) { + dev_err(&pdev->dev, "MMIO ioremap fail\n"); + ret = -ENODEV; + goto out_free; + } + /* + * Power/clock memory is elsewhere; get it too. Perhaps this + * should really be managed outside of this driver? + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res == NULL) { + dev_err(&pdev->dev, "no power resource!\n"); + ret = -ENODEV; + goto out_unmap1; + } + cam->power_regs = ioremap(res->start, resource_size(res)); + if (cam->power_regs == NULL) { + dev_err(&pdev->dev, "power MMIO ioremap fail\n"); + ret = -ENODEV; + goto out_unmap1; + } + /* + * Find the i2c adapter. This assumes, of course, that the + * i2c bus is already up and functioning. + */ + pdata = pdev->dev.platform_data; + mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device); + if (mcam->i2c_adapter == NULL) { + ret = -ENODEV; + dev_err(&pdev->dev, "No i2c adapter\n"); + goto out_unmap2; + } + /* + * Sensor GPIO pins. + */ + ret = gpio_request(pdata->sensor_power_gpio, "cam-power"); + if (ret) { + dev_err(&pdev->dev, "Can't get sensor power gpio %d", + pdata->sensor_power_gpio); + goto out_unmap2; + } + gpio_direction_output(pdata->sensor_power_gpio, 0); + ret = gpio_request(pdata->sensor_reset_gpio, "cam-reset"); + if (ret) { + dev_err(&pdev->dev, "Can't get sensor reset gpio %d", + pdata->sensor_reset_gpio); + goto out_gpio; + } + gpio_direction_output(pdata->sensor_reset_gpio, 0); + /* + * Power the device up and hand it off to the core. + */ + mmpcam_power_up(mcam); + ret = mccic_register(mcam); + if (ret) + goto out_gpio2; + /* + * Finally, set up our IRQ now that the core is ready to + * deal with it. + */ + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + ret = -ENODEV; + goto out_unregister; + } + cam->irq = res->start; + ret = request_irq(cam->irq, mmpcam_irq, IRQF_SHARED, + "mmp-camera", mcam); + if (ret == 0) { + mmpcam_add_device(cam); + return 0; + } + +out_unregister: + mccic_shutdown(mcam); + mmpcam_power_down(mcam); +out_gpio2: + gpio_free(pdata->sensor_reset_gpio); +out_gpio: + gpio_free(pdata->sensor_power_gpio); +out_unmap2: + iounmap(cam->power_regs); +out_unmap1: + iounmap(mcam->regs); +out_free: + kfree(cam); + return ret; +} + + +static int mmpcam_remove(struct mmp_camera *cam) +{ + struct mcam_camera *mcam = &cam->mcam; + struct mmp_camera_platform_data *pdata; + + mmpcam_remove_device(cam); + free_irq(cam->irq, mcam); + mccic_shutdown(mcam); + mmpcam_power_down(mcam); + pdata = cam->pdev->dev.platform_data; + gpio_free(pdata->sensor_reset_gpio); + gpio_free(pdata->sensor_power_gpio); + iounmap(cam->power_regs); + iounmap(mcam->regs); + kfree(cam); + return 0; +} + +static int mmpcam_platform_remove(struct platform_device *pdev) +{ + struct mmp_camera *cam = mmpcam_find_device(pdev); + + if (cam == NULL) + return -ENODEV; + return mmpcam_remove(cam); +} + + +static struct platform_driver mmpcam_driver = { + .probe = mmpcam_probe, + .remove = mmpcam_platform_remove, + .driver = { + .name = "mmp-camera", + .owner = THIS_MODULE + } +}; + + +static int __init mmpcam_init_module(void) +{ + mutex_init(&mmpcam_devices_lock); + return platform_driver_register(&mmpcam_driver); +} + +static void __exit mmpcam_exit_module(void) +{ + platform_driver_unregister(&mmpcam_driver); + /* + * platform_driver_unregister() should have emptied the list + */ + if (!list_empty(&mmpcam_devices)) + printk(KERN_ERR "mmp_camera leaving devices behind\n"); +} + +module_init(mmpcam_init_module); +module_exit(mmpcam_exit_module); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mem2mem_testdev.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mem2mem_testdev.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mem2mem_testdev.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mem2mem_testdev.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1037 @@ +/* + * A virtual v4l2-mem2mem example device. + * + * This is a virtual device driver for testing mem-to-mem videobuf framework. + * It simulates a device that uses memory buffers for both source and + * destination, processes the data and issues an "irq" (simulated by a timer). + * The device is capable of multi-instance, multi-buffer-per-transaction + * operation (via the mem2mem framework). + * + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. + * Pawel Osciak, + * Marek Szyprowski, + * + * 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, or (at your option) any later version + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev" + +MODULE_DESCRIPTION("Virtual device for mem2mem framework testing"); +MODULE_AUTHOR("Pawel Osciak, "); +MODULE_LICENSE("GPL"); + + +#define MIN_W 32 +#define MIN_H 32 +#define MAX_W 640 +#define MAX_H 480 +#define DIM_ALIGN_MASK 0x08 /* 8-alignment for dimensions */ + +/* Flags that indicate a format can be used for capture/output */ +#define MEM2MEM_CAPTURE (1 << 0) +#define MEM2MEM_OUTPUT (1 << 1) + +#define MEM2MEM_NAME "m2m-testdev" + +/* Per queue */ +#define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME +/* In bytes, per queue */ +#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024) + +/* Default transaction time in msec */ +#define MEM2MEM_DEF_TRANSTIME 1000 +/* Default number of buffers per transaction */ +#define MEM2MEM_DEF_TRANSLEN 1 +#define MEM2MEM_COLOR_STEP (0xff >> 4) +#define MEM2MEM_NUM_TILES 8 + +#define dprintk(dev, fmt, arg...) \ + v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) + + +void m2mtest_dev_release(struct device *dev) +{} + +static struct platform_device m2mtest_pdev = { + .name = MEM2MEM_NAME, + .dev.release = m2mtest_dev_release, +}; + +struct m2mtest_fmt { + char *name; + u32 fourcc; + int depth; + /* Types the format can be used for */ + u32 types; +}; + +static struct m2mtest_fmt formats[] = { + { + .name = "RGB565 (BE)", + .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .depth = 16, + /* Both capture and output format */ + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, + { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + /* Output-only format */ + .types = MEM2MEM_OUTPUT, + }, +}; + +/* Per-queue, driver-specific private data */ +struct m2mtest_q_data { + unsigned int width; + unsigned int height; + unsigned int sizeimage; + struct m2mtest_fmt *fmt; +}; + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +/* Source and destination queue data */ +static struct m2mtest_q_data q_data[2]; + +static struct m2mtest_q_data *get_q_data(enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &q_data[V4L2_M2M_SRC]; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &q_data[V4L2_M2M_DST]; + default: + BUG(); + } + return NULL; +} + +#define V4L2_CID_TRANS_TIME_MSEC V4L2_CID_PRIVATE_BASE +#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_PRIVATE_BASE + 1) + +static struct v4l2_queryctrl m2mtest_ctrls[] = { + { + .id = V4L2_CID_TRANS_TIME_MSEC, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Transaction time (msec)", + .minimum = 1, + .maximum = 10000, + .step = 100, + .default_value = 1000, + .flags = 0, + }, { + .id = V4L2_CID_TRANS_NUM_BUFS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Buffers per transaction", + .minimum = 1, + .maximum = MEM2MEM_DEF_NUM_BUFS, + .step = 1, + .default_value = 1, + .flags = 0, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(formats) + +static struct m2mtest_fmt *find_format(struct v4l2_format *f) +{ + struct m2mtest_fmt *fmt; + unsigned int k; + + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &formats[k]; + if (fmt->fourcc == f->fmt.pix.pixelformat) + break; + } + + if (k == NUM_FORMATS) + return NULL; + + return &formats[k]; +} + +struct m2mtest_dev { + struct v4l2_device v4l2_dev; + struct video_device *vfd; + + atomic_t num_inst; + struct mutex dev_mutex; + spinlock_t irqlock; + + struct timer_list timer; + + struct v4l2_m2m_dev *m2m_dev; +}; + +struct m2mtest_ctx { + struct m2mtest_dev *dev; + + /* Processed buffers in this transaction */ + u8 num_processed; + + /* Transaction length (i.e. how many buffers per transaction) */ + u32 translen; + /* Transaction time (i.e. simulated processing time) in milliseconds */ + u32 transtime; + + /* Abort requested by m2m */ + int aborting; + + struct v4l2_m2m_ctx *m2m_ctx; +}; + +static struct v4l2_queryctrl *get_ctrl(int id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(m2mtest_ctrls); ++i) { + if (id == m2mtest_ctrls[i].id) + return &m2mtest_ctrls[i]; + } + + return NULL; +} + +static int device_process(struct m2mtest_ctx *ctx, + struct vb2_buffer *in_vb, + struct vb2_buffer *out_vb) +{ + struct m2mtest_dev *dev = ctx->dev; + struct m2mtest_q_data *q_data; + u8 *p_in, *p_out; + int x, y, t, w; + int tile_w, bytes_left; + int width, height, bytesperline; + + q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); + + width = q_data->width; + height = q_data->height; + bytesperline = (q_data->width * q_data->fmt->depth) >> 3; + + p_in = vb2_plane_vaddr(in_vb, 0); + p_out = vb2_plane_vaddr(out_vb, 0); + if (!p_in || !p_out) { + v4l2_err(&dev->v4l2_dev, + "Acquiring kernel pointers to buffers failed\n"); + return -EFAULT; + } + + if (vb2_plane_size(in_vb, 0) > vb2_plane_size(out_vb, 0)) { + v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n"); + return -EINVAL; + } + + tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3)) + / MEM2MEM_NUM_TILES; + bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES; + w = 0; + + for (y = 0; y < height; ++y) { + for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { + if (w & 0x1) { + for (x = 0; x < tile_w; ++x) + *p_out++ = *p_in++ + MEM2MEM_COLOR_STEP; + } else { + for (x = 0; x < tile_w; ++x) + *p_out++ = *p_in++ - MEM2MEM_COLOR_STEP; + } + ++w; + } + p_in += bytes_left; + p_out += bytes_left; + } + + return 0; +} + +static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout) +{ + dprintk(dev, "Scheduling a simulated irq\n"); + mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout)); +} + +/* + * mem2mem callbacks + */ + +/** + * job_ready() - check whether an instance is ready to be scheduled to run + */ +static int job_ready(void *priv) +{ + struct m2mtest_ctx *ctx = priv; + + if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen + || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) { + dprintk(ctx->dev, "Not enough buffers available\n"); + return 0; + } + + return 1; +} + +static void job_abort(void *priv) +{ + struct m2mtest_ctx *ctx = priv; + + /* Will cancel the transaction in the next interrupt handler */ + ctx->aborting = 1; +} + +static void m2mtest_lock(void *priv) +{ + struct m2mtest_ctx *ctx = priv; + struct m2mtest_dev *dev = ctx->dev; + mutex_lock(&dev->dev_mutex); +} + +static void m2mtest_unlock(void *priv) +{ + struct m2mtest_ctx *ctx = priv; + struct m2mtest_dev *dev = ctx->dev; + mutex_unlock(&dev->dev_mutex); +} + + +/* device_run() - prepares and starts the device + * + * This simulates all the immediate preparations required before starting + * a device. This will be called by the framework when it decides to schedule + * a particular instance. + */ +static void device_run(void *priv) +{ + struct m2mtest_ctx *ctx = priv; + struct m2mtest_dev *dev = ctx->dev; + struct vb2_buffer *src_buf, *dst_buf; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + + device_process(ctx, src_buf, dst_buf); + + /* Run a timer, which simulates a hardware irq */ + schedule_irq(dev, ctx->transtime); +} + +static void device_isr(unsigned long priv) +{ + struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv; + struct m2mtest_ctx *curr_ctx; + struct vb2_buffer *src_vb, *dst_vb; + unsigned long flags; + + curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev); + + if (NULL == curr_ctx) { + printk(KERN_ERR + "Instance released before the end of transaction\n"); + return; + } + + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + + curr_ctx->num_processed++; + + spin_lock_irqsave(&m2mtest_dev->irqlock, flags); + v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); + spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags); + + if (curr_ctx->num_processed == curr_ctx->translen + || curr_ctx->aborting) { + dprintk(curr_ctx->dev, "Finishing transaction\n"); + curr_ctx->num_processed = 0; + v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx); + } else { + device_run(curr_ctx); + } +} + +/* + * video ioctls + */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); + strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); + cap->bus_info[0] = 0; + cap->version = KERNEL_VERSION(0, 1, 0); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_STREAMING; + + return 0; +} + +static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) +{ + int i, num; + struct m2mtest_fmt *fmt; + + num = 0; + + for (i = 0; i < NUM_FORMATS; ++i) { + if (formats[i].types & type) { + /* index-th format of type type found ? */ + if (num == f->index) + break; + /* Correct type but haven't reached our index yet, + * just increment per-type index */ + ++num; + } + } + + if (i < NUM_FORMATS) { + /* Format found */ + fmt = &formats[i]; + strncpy(f->description, fmt->name, sizeof(f->description) - 1); + f->pixelformat = fmt->fourcc; + return 0; + } + + /* Format not found */ + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return enum_fmt(f, MEM2MEM_CAPTURE); +} + +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return enum_fmt(f, MEM2MEM_OUTPUT); +} + +static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct m2mtest_q_data *q_data; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(f->type); + + f->fmt.pix.width = q_data->width; + f->fmt.pix.height = q_data->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = q_data->fmt->fourcc; + f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3; + f->fmt.pix.sizeimage = q_data->sizeimage; + + return 0; +} + +static int vidioc_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_g_fmt(priv, f); +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_g_fmt(priv, f); +} + +static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt) +{ + enum v4l2_field field; + + field = f->fmt.pix.field; + + if (field == V4L2_FIELD_ANY) + field = V4L2_FIELD_NONE; + else if (V4L2_FIELD_NONE != field) + return -EINVAL; + + /* V4L2 specification suggests the driver corrects the format struct + * if any of the dimensions is unsupported */ + f->fmt.pix.field = field; + + if (f->fmt.pix.height < MIN_H) + f->fmt.pix.height = MIN_H; + else if (f->fmt.pix.height > MAX_H) + f->fmt.pix.height = MAX_H; + + if (f->fmt.pix.width < MIN_W) + f->fmt.pix.width = MIN_W; + else if (f->fmt.pix.width > MAX_W) + f->fmt.pix.width = MAX_W; + + f->fmt.pix.width &= ~DIM_ALIGN_MASK; + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct m2mtest_fmt *fmt; + struct m2mtest_ctx *ctx = priv; + + fmt = find_format(f); + if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { + v4l2_err(&ctx->dev->v4l2_dev, + "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + return vidioc_try_fmt(f, fmt); +} + +static int vidioc_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct m2mtest_fmt *fmt; + struct m2mtest_ctx *ctx = priv; + + fmt = find_format(f); + if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { + v4l2_err(&ctx->dev->v4l2_dev, + "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + return vidioc_try_fmt(f, fmt); +} + +static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) +{ + struct m2mtest_q_data *q_data; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(f->type); + if (!q_data) + return -EINVAL; + + if (vb2_is_busy(vq)) { + v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + q_data->fmt = find_format(f); + q_data->width = f->fmt.pix.width; + q_data->height = f->fmt.pix.height; + q_data->sizeimage = q_data->width * q_data->height + * q_data->fmt->depth >> 3; + + dprintk(ctx->dev, + "Setting format for type %d, wxh: %dx%d, fmt: %d\n", + f->type, q_data->width, q_data->height, q_data->fmt->fourcc); + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = vidioc_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + return vidioc_s_fmt(priv, f); +} + +static int vidioc_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = vidioc_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + return vidioc_s_fmt(priv, f); +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct m2mtest_ctx *ctx = priv; + + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct m2mtest_ctx *ctx = priv; + + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct m2mtest_ctx *ctx = priv; + + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct m2mtest_ctx *ctx = priv; + + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct m2mtest_ctx *ctx = priv; + + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct m2mtest_ctx *ctx = priv; + + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct v4l2_queryctrl *c; + + c = get_ctrl(qc->id); + if (!c) + return -EINVAL; + + *qc = *c; + return 0; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct m2mtest_ctx *ctx = priv; + + switch (ctrl->id) { + case V4L2_CID_TRANS_TIME_MSEC: + ctrl->value = ctx->transtime; + break; + + case V4L2_CID_TRANS_NUM_BUFS: + ctrl->value = ctx->translen; + break; + + default: + v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); + return -EINVAL; + } + + return 0; +} + +static int check_ctrl_val(struct m2mtest_ctx *ctx, struct v4l2_control *ctrl) +{ + struct v4l2_queryctrl *c; + + c = get_ctrl(ctrl->id); + if (!c) + return -EINVAL; + + if (ctrl->value < c->minimum || ctrl->value > c->maximum) { + v4l2_err(&ctx->dev->v4l2_dev, "Value out of range\n"); + return -ERANGE; + } + + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct m2mtest_ctx *ctx = priv; + int ret = 0; + + ret = check_ctrl_val(ctx, ctrl); + if (ret != 0) + return ret; + + switch (ctrl->id) { + case V4L2_CID_TRANS_TIME_MSEC: + ctx->transtime = ctrl->value; + break; + + case V4L2_CID_TRANS_NUM_BUFS: + ctx->translen = ctrl->value; + break; + + default: + v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); + return -EINVAL; + } + + return 0; +} + + +static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, + .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, + + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; + + +/* + * Queue operations + */ + +static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned long sizes[], + void *alloc_ctxs[]) +{ + struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); + struct m2mtest_q_data *q_data; + unsigned int size, count = *nbuffers; + + q_data = get_q_data(vq->type); + + size = q_data->width * q_data->height * q_data->fmt->depth >> 3; + + while (size * count > MEM2MEM_VID_MEM_LIMIT) + (count)--; + + *nplanes = 1; + *nbuffers = count; + sizes[0] = size; + + /* + * videobuf2-vmalloc allocator is context-less so no need to set + * alloc_ctxs array. + */ + + dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); + + return 0; +} + +static int m2mtest_buf_prepare(struct vb2_buffer *vb) +{ + struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct m2mtest_q_data *q_data; + + dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); + + q_data = get_q_data(vb->vb2_queue->type); + + if (vb2_plane_size(vb, 0) < q_data->sizeimage) { + dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, q_data->sizeimage); + + return 0; +} + +static void m2mtest_buf_queue(struct vb2_buffer *vb) +{ + struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); +} + +static struct vb2_ops m2mtest_qops = { + .queue_setup = m2mtest_queue_setup, + .buf_prepare = m2mtest_buf_prepare, + .buf_queue = m2mtest_buf_queue, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct m2mtest_ctx *ctx = priv; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &m2mtest_qops; + src_vq->mem_ops = &vb2_vmalloc_memops; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &m2mtest_qops; + dst_vq->mem_ops = &vb2_vmalloc_memops; + + return vb2_queue_init(dst_vq); +} + +/* + * File operations + */ +static int m2mtest_open(struct file *file) +{ + struct m2mtest_dev *dev = video_drvdata(file); + struct m2mtest_ctx *ctx = NULL; + + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + file->private_data = ctx; + ctx->dev = dev; + ctx->translen = MEM2MEM_DEF_TRANSLEN; + ctx->transtime = MEM2MEM_DEF_TRANSTIME; + ctx->num_processed = 0; + + ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); + + if (IS_ERR(ctx->m2m_ctx)) { + int ret = PTR_ERR(ctx->m2m_ctx); + + kfree(ctx); + return ret; + } + + atomic_inc(&dev->num_inst); + + dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); + + return 0; +} + +static int m2mtest_release(struct file *file) +{ + struct m2mtest_dev *dev = video_drvdata(file); + struct m2mtest_ctx *ctx = file->private_data; + + dprintk(dev, "Releasing instance %p\n", ctx); + + v4l2_m2m_ctx_release(ctx->m2m_ctx); + kfree(ctx); + + atomic_dec(&dev->num_inst); + + return 0; +} + +static unsigned int m2mtest_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct m2mtest_ctx *ctx = file->private_data; + + return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); +} + +static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct m2mtest_ctx *ctx = file->private_data; + + return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); +} + +static const struct v4l2_file_operations m2mtest_fops = { + .owner = THIS_MODULE, + .open = m2mtest_open, + .release = m2mtest_release, + .poll = m2mtest_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = m2mtest_mmap, +}; + +static struct video_device m2mtest_videodev = { + .name = MEM2MEM_NAME, + .fops = &m2mtest_fops, + .ioctl_ops = &m2mtest_ioctl_ops, + .minor = -1, + .release = video_device_release, +}; + +static struct v4l2_m2m_ops m2m_ops = { + .device_run = device_run, + .job_ready = job_ready, + .job_abort = job_abort, + .lock = m2mtest_lock, + .unlock = m2mtest_unlock, +}; + +static int m2mtest_probe(struct platform_device *pdev) +{ + struct m2mtest_dev *dev; + struct video_device *vfd; + int ret; + + dev = kzalloc(sizeof *dev, GFP_KERNEL); + if (!dev) + return -ENOMEM; + + spin_lock_init(&dev->irqlock); + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + goto free_dev; + + atomic_set(&dev->num_inst, 0); + mutex_init(&dev->dev_mutex); + + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto unreg_dev; + } + + *vfd = m2mtest_videodev; + vfd->lock = &dev->dev_mutex; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto rel_vdev; + } + + video_set_drvdata(vfd, dev); + snprintf(vfd->name, sizeof(vfd->name), "%s", m2mtest_videodev.name); + dev->vfd = vfd; + v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME + "Device registered as /dev/video%d\n", vfd->num); + + setup_timer(&dev->timer, device_isr, (long)dev); + platform_set_drvdata(pdev, dev); + + dev->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(dev->m2m_dev); + goto err_m2m; + } + + q_data[V4L2_M2M_SRC].fmt = &formats[0]; + q_data[V4L2_M2M_DST].fmt = &formats[0]; + + return 0; + + v4l2_m2m_release(dev->m2m_dev); +err_m2m: + video_unregister_device(dev->vfd); +rel_vdev: + video_device_release(vfd); +unreg_dev: + v4l2_device_unregister(&dev->v4l2_dev); +free_dev: + kfree(dev); + + return ret; +} + +static int m2mtest_remove(struct platform_device *pdev) +{ + struct m2mtest_dev *dev = + (struct m2mtest_dev *)platform_get_drvdata(pdev); + + v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME); + v4l2_m2m_release(dev->m2m_dev); + del_timer_sync(&dev->timer); + video_unregister_device(dev->vfd); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); + + return 0; +} + +static struct platform_driver m2mtest_pdrv = { + .probe = m2mtest_probe, + .remove = m2mtest_remove, + .driver = { + .name = MEM2MEM_NAME, + .owner = THIS_MODULE, + }, +}; + +static void __exit m2mtest_exit(void) +{ + platform_driver_unregister(&m2mtest_pdrv); + platform_device_unregister(&m2mtest_pdev); +} + +static int __init m2mtest_init(void) +{ + int ret; + + ret = platform_device_register(&m2mtest_pdev); + if (ret) + return ret; + + ret = platform_driver_register(&m2mtest_pdrv); + if (ret) + platform_device_unregister(&m2mtest_pdev); + + return 0; +} + +module_init(m2mtest_init); +module_exit(m2mtest_exit); + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/meye.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/meye.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/meye.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/meye.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1963 @@ +/* + * Motion Eye video4linux driver for Sony Vaio PictureBook + * + * Copyright (C) 2001-2004 Stelian Pop + * + * Copyright (C) 2001-2002 Alcôve + * + * Copyright (C) 2000 Andrew Tridgell + * + * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. + * + * Some parts borrowed from various video4linux drivers, especially + * bttv-driver.c and zoran.c, see original files for credits. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "meye.h" +#include + +MODULE_AUTHOR("Stelian Pop "); +MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera"); +MODULE_LICENSE("GPL"); + +/* number of grab buffers */ +static unsigned int gbuffers = 2; +module_param(gbuffers, int, 0444); +MODULE_PARM_DESC(gbuffers, "number of capture buffers, default is 2 (32 max)"); + +/* size of a grab buffer */ +static unsigned int gbufsize = MEYE_MAX_BUFSIZE; +module_param(gbufsize, int, 0444); +MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 614400" + " (will be rounded up to a page multiple)"); + +/* /dev/videoX registration number */ +static int video_nr = -1; +module_param(video_nr, int, 0444); +MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)"); + +/* driver structure - only one possible */ +static struct meye meye; + +/****************************************************************************/ +/* Memory allocation routines (stolen from bttv-driver.c) */ +/****************************************************************************/ +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (mem) { + memset(mem, 0, size); + adr = (unsigned long) mem; + while (size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, unsigned long size) +{ + unsigned long adr; + + if (mem) { + adr = (unsigned long) mem; + while ((long) size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); + } +} + +/* + * return a page table pointing to N pages of locked memory + * + * NOTE: The meye device expects DMA addresses on 32 bits, we build + * a table of 1024 entries = 4 bytes * 1024 = 4096 bytes. + */ +static int ptable_alloc(void) +{ + u32 *pt; + int i; + + memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); + + /* give only 32 bit DMA addresses */ + if (dma_set_mask(&meye.mchip_dev->dev, DMA_BIT_MASK(32))) + return -1; + + meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev, + PAGE_SIZE, + &meye.mchip_dmahandle, + GFP_KERNEL); + if (!meye.mchip_ptable_toc) { + meye.mchip_dmahandle = 0; + return -1; + } + + pt = meye.mchip_ptable_toc; + for (i = 0; i < MCHIP_NB_PAGES; i++) { + dma_addr_t dma; + meye.mchip_ptable[i] = dma_alloc_coherent(&meye.mchip_dev->dev, + PAGE_SIZE, + &dma, + GFP_KERNEL); + if (!meye.mchip_ptable[i]) { + int j; + pt = meye.mchip_ptable_toc; + for (j = 0; j < i; ++j) { + dma = (dma_addr_t) *pt; + dma_free_coherent(&meye.mchip_dev->dev, + PAGE_SIZE, + meye.mchip_ptable[j], dma); + pt++; + } + dma_free_coherent(&meye.mchip_dev->dev, + PAGE_SIZE, + meye.mchip_ptable_toc, + meye.mchip_dmahandle); + meye.mchip_ptable_toc = NULL; + meye.mchip_dmahandle = 0; + return -1; + } + *pt = (u32) dma; + pt++; + } + return 0; +} + +static void ptable_free(void) +{ + u32 *pt; + int i; + + pt = meye.mchip_ptable_toc; + for (i = 0; i < MCHIP_NB_PAGES; i++) { + dma_addr_t dma = (dma_addr_t) *pt; + if (meye.mchip_ptable[i]) + dma_free_coherent(&meye.mchip_dev->dev, + PAGE_SIZE, + meye.mchip_ptable[i], dma); + pt++; + } + + if (meye.mchip_ptable_toc) + dma_free_coherent(&meye.mchip_dev->dev, + PAGE_SIZE, + meye.mchip_ptable_toc, + meye.mchip_dmahandle); + + memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); + meye.mchip_ptable_toc = NULL; + meye.mchip_dmahandle = 0; +} + +/* copy data from ptable into buf */ +static void ptable_copy(u8 *buf, int start, int size, int pt_pages) +{ + int i; + + for (i = 0; i < (size / PAGE_SIZE) * PAGE_SIZE; i += PAGE_SIZE) { + memcpy(buf + i, meye.mchip_ptable[start++], PAGE_SIZE); + if (start >= pt_pages) + start = 0; + } + memcpy(buf + i, meye.mchip_ptable[start], size % PAGE_SIZE); +} + +/****************************************************************************/ +/* JPEG tables at different qualities to load into the VRJ chip */ +/****************************************************************************/ + +/* return a set of quantisation tables based on a quality from 1 to 10 */ +static u16 *jpeg_quantisation_tables(int *length, int quality) +{ + static u16 jpeg_tables[][70] = { { + 0xdbff, 0x4300, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, + 0xdbff, 0x4300, 0xff01, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, + }, + { + 0xdbff, 0x4300, 0x5000, 0x3c37, 0x3c46, 0x5032, 0x4146, 0x5a46, + 0x5055, 0x785f, 0x82c8, 0x6e78, 0x786e, 0xaff5, 0x91b9, 0xffc8, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, + 0xdbff, 0x4300, 0x5501, 0x5a5a, 0x6978, 0xeb78, 0x8282, 0xffeb, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, + }, + { + 0xdbff, 0x4300, 0x2800, 0x1e1c, 0x1e23, 0x2819, 0x2123, 0x2d23, + 0x282b, 0x3c30, 0x4164, 0x373c, 0x3c37, 0x587b, 0x495d, 0x9164, + 0x9980, 0x8f96, 0x8c80, 0xa08a, 0xe6b4, 0xa0c3, 0xdaaa, 0x8aad, + 0xc88c, 0xcbff, 0xeeda, 0xfff5, 0xffff, 0xc19b, 0xffff, 0xfaff, + 0xe6ff, 0xfffd, 0xfff8, + 0xdbff, 0x4300, 0x2b01, 0x2d2d, 0x353c, 0x763c, 0x4141, 0xf876, + 0x8ca5, 0xf8a5, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, + 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, + 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, + 0xf8f8, 0xf8f8, 0xfff8, + }, + { + 0xdbff, 0x4300, 0x1b00, 0x1412, 0x1417, 0x1b11, 0x1617, 0x1e17, + 0x1b1c, 0x2820, 0x2b42, 0x2528, 0x2825, 0x3a51, 0x303d, 0x6042, + 0x6555, 0x5f64, 0x5d55, 0x6a5b, 0x9978, 0x6a81, 0x9071, 0x5b73, + 0x855d, 0x86b5, 0x9e90, 0xaba3, 0xabad, 0x8067, 0xc9bc, 0xa6ba, + 0x99c7, 0xaba8, 0xffa4, + 0xdbff, 0x4300, 0x1c01, 0x1e1e, 0x2328, 0x4e28, 0x2b2b, 0xa44e, + 0x5d6e, 0xa46e, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xffa4, + }, + { + 0xdbff, 0x4300, 0x1400, 0x0f0e, 0x0f12, 0x140d, 0x1012, 0x1712, + 0x1415, 0x1e18, 0x2132, 0x1c1e, 0x1e1c, 0x2c3d, 0x242e, 0x4932, + 0x4c40, 0x474b, 0x4640, 0x5045, 0x735a, 0x5062, 0x6d55, 0x4556, + 0x6446, 0x6588, 0x776d, 0x817b, 0x8182, 0x604e, 0x978d, 0x7d8c, + 0x7396, 0x817e, 0xff7c, + 0xdbff, 0x4300, 0x1501, 0x1717, 0x1a1e, 0x3b1e, 0x2121, 0x7c3b, + 0x4653, 0x7c53, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, + 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, + 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, + 0x7c7c, 0x7c7c, 0xff7c, + }, + { + 0xdbff, 0x4300, 0x1000, 0x0c0b, 0x0c0e, 0x100a, 0x0d0e, 0x120e, + 0x1011, 0x1813, 0x1a28, 0x1618, 0x1816, 0x2331, 0x1d25, 0x3a28, + 0x3d33, 0x393c, 0x3833, 0x4037, 0x5c48, 0x404e, 0x5744, 0x3745, + 0x5038, 0x516d, 0x5f57, 0x6762, 0x6768, 0x4d3e, 0x7971, 0x6470, + 0x5c78, 0x6765, 0xff63, + 0xdbff, 0x4300, 0x1101, 0x1212, 0x1518, 0x2f18, 0x1a1a, 0x632f, + 0x3842, 0x6342, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, + 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, + 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, + 0x6363, 0x6363, 0xff63, + }, + { + 0xdbff, 0x4300, 0x0d00, 0x0a09, 0x0a0b, 0x0d08, 0x0a0b, 0x0e0b, + 0x0d0e, 0x130f, 0x1520, 0x1213, 0x1312, 0x1c27, 0x171e, 0x2e20, + 0x3129, 0x2e30, 0x2d29, 0x332c, 0x4a3a, 0x333e, 0x4636, 0x2c37, + 0x402d, 0x4157, 0x4c46, 0x524e, 0x5253, 0x3e32, 0x615a, 0x505a, + 0x4a60, 0x5251, 0xff4f, + 0xdbff, 0x4300, 0x0e01, 0x0e0e, 0x1113, 0x2613, 0x1515, 0x4f26, + 0x2d35, 0x4f35, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, + 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, + 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, + 0x4f4f, 0x4f4f, 0xff4f, + }, + { + 0xdbff, 0x4300, 0x0a00, 0x0707, 0x0708, 0x0a06, 0x0808, 0x0b08, + 0x0a0a, 0x0e0b, 0x1018, 0x0d0e, 0x0e0d, 0x151d, 0x1116, 0x2318, + 0x251f, 0x2224, 0x221f, 0x2621, 0x372b, 0x262f, 0x3429, 0x2129, + 0x3022, 0x3141, 0x3934, 0x3e3b, 0x3e3e, 0x2e25, 0x4944, 0x3c43, + 0x3748, 0x3e3d, 0xff3b, + 0xdbff, 0x4300, 0x0a01, 0x0b0b, 0x0d0e, 0x1c0e, 0x1010, 0x3b1c, + 0x2228, 0x3b28, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, + 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, + 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, + 0x3b3b, 0x3b3b, 0xff3b, + }, + { + 0xdbff, 0x4300, 0x0600, 0x0504, 0x0506, 0x0604, 0x0506, 0x0706, + 0x0607, 0x0a08, 0x0a10, 0x090a, 0x0a09, 0x0e14, 0x0c0f, 0x1710, + 0x1814, 0x1718, 0x1614, 0x1a16, 0x251d, 0x1a1f, 0x231b, 0x161c, + 0x2016, 0x202c, 0x2623, 0x2927, 0x292a, 0x1f19, 0x302d, 0x282d, + 0x2530, 0x2928, 0xff28, + 0xdbff, 0x4300, 0x0701, 0x0707, 0x080a, 0x130a, 0x0a0a, 0x2813, + 0x161a, 0x281a, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, + 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, + 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, + 0x2828, 0x2828, 0xff28, + }, + { + 0xdbff, 0x4300, 0x0300, 0x0202, 0x0203, 0x0302, 0x0303, 0x0403, + 0x0303, 0x0504, 0x0508, 0x0405, 0x0504, 0x070a, 0x0607, 0x0c08, + 0x0c0a, 0x0b0c, 0x0b0a, 0x0d0b, 0x120e, 0x0d10, 0x110e, 0x0b0e, + 0x100b, 0x1016, 0x1311, 0x1514, 0x1515, 0x0f0c, 0x1817, 0x1416, + 0x1218, 0x1514, 0xff14, + 0xdbff, 0x4300, 0x0301, 0x0404, 0x0405, 0x0905, 0x0505, 0x1409, + 0x0b0d, 0x140d, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, + 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, + 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, + 0x1414, 0x1414, 0xff14, + }, + { + 0xdbff, 0x4300, 0x0100, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0xff01, + 0xdbff, 0x4300, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0xff01, + } }; + + if (quality < 0 || quality > 10) { + printk(KERN_WARNING + "meye: invalid quality level %d - using 8\n", quality); + quality = 8; + } + + *length = ARRAY_SIZE(jpeg_tables[quality]); + return jpeg_tables[quality]; +} + +/* return a generic set of huffman tables */ +static u16 *jpeg_huffman_tables(int *length) +{ + static u16 tables[] = { + 0xC4FF, 0xB500, 0x0010, 0x0102, 0x0303, 0x0402, 0x0503, 0x0405, + 0x0004, 0x0100, 0x017D, 0x0302, 0x0400, 0x0511, 0x2112, 0x4131, + 0x1306, 0x6151, 0x2207, 0x1471, 0x8132, 0xA191, 0x2308, 0xB142, + 0x15C1, 0xD152, 0x24F0, 0x6233, 0x8272, 0x0A09, 0x1716, 0x1918, + 0x251A, 0x2726, 0x2928, 0x342A, 0x3635, 0x3837, 0x3A39, 0x4443, + 0x4645, 0x4847, 0x4A49, 0x5453, 0x5655, 0x5857, 0x5A59, 0x6463, + 0x6665, 0x6867, 0x6A69, 0x7473, 0x7675, 0x7877, 0x7A79, 0x8483, + 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, 0xA29A, + 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, 0xB9B8, + 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, 0xD7D6, + 0xD9D8, 0xE1DA, 0xE3E2, 0xE5E4, 0xE7E6, 0xE9E8, 0xF1EA, 0xF3F2, + 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, + 0xC4FF, 0xB500, 0x0011, 0x0102, 0x0402, 0x0304, 0x0704, 0x0405, + 0x0004, 0x0201, 0x0077, 0x0201, 0x1103, 0x0504, 0x3121, 0x1206, + 0x5141, 0x6107, 0x1371, 0x3222, 0x0881, 0x4214, 0xA191, 0xC1B1, + 0x2309, 0x5233, 0x15F0, 0x7262, 0x0AD1, 0x2416, 0xE134, 0xF125, + 0x1817, 0x1A19, 0x2726, 0x2928, 0x352A, 0x3736, 0x3938, 0x433A, + 0x4544, 0x4746, 0x4948, 0x534A, 0x5554, 0x5756, 0x5958, 0x635A, + 0x6564, 0x6766, 0x6968, 0x736A, 0x7574, 0x7776, 0x7978, 0x827A, + 0x8483, 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, + 0xA29A, 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, + 0xB9B8, 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, + 0xD7D6, 0xD9D8, 0xE2DA, 0xE4E3, 0xE6E5, 0xE8E7, 0xEAE9, 0xF3F2, + 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, + 0xC4FF, 0x1F00, 0x0000, 0x0501, 0x0101, 0x0101, 0x0101, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, + 0xFF0B, + 0xC4FF, 0x1F00, 0x0001, 0x0103, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, + 0xFF0B + }; + + *length = ARRAY_SIZE(tables); + return tables; +} + +/****************************************************************************/ +/* MCHIP low-level functions */ +/****************************************************************************/ + +/* returns the horizontal capture size */ +static inline int mchip_hsize(void) +{ + return meye.params.subsample ? 320 : 640; +} + +/* returns the vertical capture size */ +static inline int mchip_vsize(void) +{ + return meye.params.subsample ? 240 : 480; +} + +/* waits for a register to be available */ +static void mchip_sync(int reg) +{ + u32 status; + int i; + + if (reg == MCHIP_MM_FIFO_DATA) { + for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { + status = readl(meye.mchip_mmregs + + MCHIP_MM_FIFO_STATUS); + if (!(status & MCHIP_MM_FIFO_WAIT)) { + printk(KERN_WARNING "meye: fifo not ready\n"); + return; + } + if (status & MCHIP_MM_FIFO_READY) + return; + udelay(1); + } + } else if (reg > 0x80) { + u32 mask = (reg < 0x100) ? MCHIP_HIC_STATUS_MCC_RDY + : MCHIP_HIC_STATUS_VRJ_RDY; + for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { + status = readl(meye.mchip_mmregs + MCHIP_HIC_STATUS); + if (status & mask) + return; + udelay(1); + } + } else + return; + printk(KERN_WARNING + "meye: mchip_sync() timeout on reg 0x%x status=0x%x\n", + reg, status); +} + +/* sets a value into the register */ +static inline void mchip_set(int reg, u32 v) +{ + mchip_sync(reg); + writel(v, meye.mchip_mmregs + reg); +} + +/* get the register value */ +static inline u32 mchip_read(int reg) +{ + mchip_sync(reg); + return readl(meye.mchip_mmregs + reg); +} + +/* wait for a register to become a particular value */ +static inline int mchip_delay(u32 reg, u32 v) +{ + int n = 10; + while (--n && mchip_read(reg) != v) + udelay(1); + return n; +} + +/* setup subsampling */ +static void mchip_subsample(void) +{ + mchip_set(MCHIP_MCC_R_SAMPLING, meye.params.subsample); + mchip_set(MCHIP_MCC_R_XRANGE, mchip_hsize()); + mchip_set(MCHIP_MCC_R_YRANGE, mchip_vsize()); + mchip_set(MCHIP_MCC_B_XRANGE, mchip_hsize()); + mchip_set(MCHIP_MCC_B_YRANGE, mchip_vsize()); + mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); +} + +/* set the framerate into the mchip */ +static void mchip_set_framerate(void) +{ + mchip_set(MCHIP_HIC_S_RATE, meye.params.framerate); +} + +/* load some huffman and quantisation tables into the VRJ chip ready + for JPEG compression */ +static void mchip_load_tables(void) +{ + int i; + int length; + u16 *tables; + + tables = jpeg_huffman_tables(&length); + for (i = 0; i < length; i++) + writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); + + tables = jpeg_quantisation_tables(&length, meye.params.quality); + for (i = 0; i < length; i++) + writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); +} + +/* setup the VRJ parameters in the chip */ +static void mchip_vrj_setup(u8 mode) +{ + mchip_set(MCHIP_VRJ_BUS_MODE, 5); + mchip_set(MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL, 0x1f); + mchip_set(MCHIP_VRJ_PDAT_USE, 1); + mchip_set(MCHIP_VRJ_IRQ_FLAG, 0xa0); + mchip_set(MCHIP_VRJ_MODE_SPECIFY, mode); + mchip_set(MCHIP_VRJ_NUM_LINES, mchip_vsize()); + mchip_set(MCHIP_VRJ_NUM_PIXELS, mchip_hsize()); + mchip_set(MCHIP_VRJ_NUM_COMPONENTS, 0x1b); + mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_LO, 0xFFFF); + mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_HI, 0xFFFF); + mchip_set(MCHIP_VRJ_COMP_DATA_FORMAT, 0xC); + mchip_set(MCHIP_VRJ_RESTART_INTERVAL, 0); + mchip_set(MCHIP_VRJ_SOF1, 0x601); + mchip_set(MCHIP_VRJ_SOF2, 0x1502); + mchip_set(MCHIP_VRJ_SOF3, 0x1503); + mchip_set(MCHIP_VRJ_SOF4, 0x1596); + mchip_set(MCHIP_VRJ_SOS, 0x0ed0); + + mchip_load_tables(); +} + +/* sets the DMA parameters into the chip */ +static void mchip_dma_setup(dma_addr_t dma_addr) +{ + int i; + + mchip_set(MCHIP_MM_PT_ADDR, (u32)dma_addr); + for (i = 0; i < 4; i++) + mchip_set(MCHIP_MM_FIR(i), 0); + meye.mchip_fnum = 0; +} + +/* setup for DMA transfers - also zeros the framebuffer */ +static int mchip_dma_alloc(void) +{ + if (!meye.mchip_dmahandle) + if (ptable_alloc()) + return -1; + return 0; +} + +/* frees the DMA buffer */ +static void mchip_dma_free(void) +{ + if (meye.mchip_dmahandle) { + mchip_dma_setup(0); + ptable_free(); + } +} + +/* stop any existing HIC action and wait for any dma to complete then + reset the dma engine */ +static void mchip_hic_stop(void) +{ + int i, j; + + meye.mchip_mode = MCHIP_HIC_MODE_NOOP; + if (!(mchip_read(MCHIP_HIC_STATUS) & MCHIP_HIC_STATUS_BUSY)) + return; + for (i = 0; i < 20; ++i) { + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP); + mchip_delay(MCHIP_HIC_CMD, 0); + for (j = 0; j < 100; ++j) { + if (mchip_delay(MCHIP_HIC_STATUS, + MCHIP_HIC_STATUS_IDLE)) + return; + msleep(1); + } + printk(KERN_ERR "meye: need to reset HIC!\n"); + + mchip_set(MCHIP_HIC_CTL, MCHIP_HIC_CTL_SOFT_RESET); + msleep(250); + } + printk(KERN_ERR "meye: resetting HIC hanged!\n"); +} + +/****************************************************************************/ +/* MCHIP frame processing functions */ +/****************************************************************************/ + +/* get the next ready frame from the dma engine */ +static u32 mchip_get_frame(void) +{ + u32 v; + + v = mchip_read(MCHIP_MM_FIR(meye.mchip_fnum)); + return v; +} + +/* frees the current frame from the dma engine */ +static void mchip_free_frame(void) +{ + mchip_set(MCHIP_MM_FIR(meye.mchip_fnum), 0); + meye.mchip_fnum++; + meye.mchip_fnum %= 4; +} + +/* read one frame from the framebuffer assuming it was captured using + a uncompressed transfer */ +static void mchip_cont_read_frame(u32 v, u8 *buf, int size) +{ + int pt_id; + + pt_id = (v >> 17) & 0x3FF; + + ptable_copy(buf, pt_id, size, MCHIP_NB_PAGES); +} + +/* read a compressed frame from the framebuffer */ +static int mchip_comp_read_frame(u32 v, u8 *buf, int size) +{ + int pt_start, pt_end, trailer; + int fsize; + int i; + + pt_start = (v >> 19) & 0xFF; + pt_end = (v >> 11) & 0xFF; + trailer = (v >> 1) & 0x3FF; + + if (pt_end < pt_start) + fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE + + pt_end * PAGE_SIZE + trailer * 4; + else + fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4; + + if (fsize > size) { + printk(KERN_WARNING "meye: oversized compressed frame %d\n", + fsize); + return -1; + } + + ptable_copy(buf, pt_start, fsize, MCHIP_NB_PAGES_MJPEG); + +#ifdef MEYE_JPEG_CORRECTION + + /* Some mchip generated jpeg frames are incorrect. In most + * (all ?) of those cases, the final EOI (0xff 0xd9) marker + * is not present at the end of the frame. + * + * Since adding the final marker is not enough to restore + * the jpeg integrity, we drop the frame. + */ + + for (i = fsize - 1; i > 0 && buf[i] == 0xff; i--) ; + + if (i < 2 || buf[i - 1] != 0xff || buf[i] != 0xd9) + return -1; + +#endif + + return fsize; +} + +/* take a picture into SDRAM */ +static void mchip_take_picture(void) +{ + int i; + + mchip_hic_stop(); + mchip_subsample(); + mchip_dma_setup(meye.mchip_dmahandle); + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); + + for (i = 0; i < 100; ++i) { + if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) + break; + msleep(1); + } +} + +/* dma a previously taken picture into a buffer */ +static void mchip_get_picture(u8 *buf, int bufsize) +{ + u32 v; + int i; + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_OUT); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); + for (i = 0; i < 100; ++i) { + if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) + break; + msleep(1); + } + for (i = 0; i < 4; ++i) { + v = mchip_get_frame(); + if (v & MCHIP_MM_FIR_RDY) { + mchip_cont_read_frame(v, buf, bufsize); + break; + } + mchip_free_frame(); + } +} + +/* start continuous dma capture */ +static void mchip_continuous_start(void) +{ + mchip_hic_stop(); + mchip_subsample(); + mchip_set_framerate(); + mchip_dma_setup(meye.mchip_dmahandle); + + meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_OUT); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); +} + +/* compress one frame into a buffer */ +static int mchip_compress_frame(u8 *buf, int bufsize) +{ + u32 v; + int len = -1, i; + + mchip_vrj_setup(0x3f); + udelay(50); + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_COMP); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); + for (i = 0; i < 100; ++i) { + if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) + break; + msleep(1); + } + + for (i = 0; i < 4; ++i) { + v = mchip_get_frame(); + if (v & MCHIP_MM_FIR_RDY) { + len = mchip_comp_read_frame(v, buf, bufsize); + break; + } + mchip_free_frame(); + } + return len; +} + +#if 0 +/* uncompress one image into a buffer */ +static int mchip_uncompress_frame(u8 *img, int imgsize, u8 *buf, int bufsize) +{ + mchip_vrj_setup(0x3f); + udelay(50); + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_DECOMP); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); + + return mchip_comp_read_frame(buf, bufsize); +} +#endif + +/* start continuous compressed capture */ +static void mchip_cont_compression_start(void) +{ + mchip_hic_stop(); + mchip_vrj_setup(0x3f); + mchip_subsample(); + mchip_set_framerate(); + mchip_dma_setup(meye.mchip_dmahandle); + + meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_COMP); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); +} + +/****************************************************************************/ +/* Interrupt handling */ +/****************************************************************************/ + +static irqreturn_t meye_irq(int irq, void *dev_id) +{ + u32 v; + int reqnr; + static int sequence; + + v = mchip_read(MCHIP_MM_INTA); + + if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT && + meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) + return IRQ_NONE; + +again: + v = mchip_get_frame(); + if (!(v & MCHIP_MM_FIR_RDY)) + return IRQ_HANDLED; + + if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) { + if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, + sizeof(int), &meye.grabq_lock) != sizeof(int)) { + mchip_free_frame(); + return IRQ_HANDLED; + } + mchip_cont_read_frame(v, meye.grab_fbuffer + gbufsize * reqnr, + mchip_hsize() * mchip_vsize() * 2); + meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2; + meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; + do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); + meye.grab_buffer[reqnr].sequence = sequence++; + kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, + sizeof(int), &meye.doneq_lock); + wake_up_interruptible(&meye.proc_list); + } else { + int size; + size = mchip_comp_read_frame(v, meye.grab_temp, gbufsize); + if (size == -1) { + mchip_free_frame(); + goto again; + } + if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, + sizeof(int), &meye.grabq_lock) != sizeof(int)) { + mchip_free_frame(); + goto again; + } + memcpy(meye.grab_fbuffer + gbufsize * reqnr, meye.grab_temp, + size); + meye.grab_buffer[reqnr].size = size; + meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; + do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); + meye.grab_buffer[reqnr].sequence = sequence++; + kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, + sizeof(int), &meye.doneq_lock); + wake_up_interruptible(&meye.proc_list); + } + mchip_free_frame(); + goto again; +} + +/****************************************************************************/ +/* video4linux integration */ +/****************************************************************************/ + +static int meye_open(struct file *file) +{ + int i; + + if (test_and_set_bit(0, &meye.in_use)) + return -EBUSY; + + mchip_hic_stop(); + + if (mchip_dma_alloc()) { + printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); + clear_bit(0, &meye.in_use); + return -ENOBUFS; + } + + for (i = 0; i < MEYE_MAX_BUFNBRS; i++) + meye.grab_buffer[i].state = MEYE_BUF_UNUSED; + kfifo_reset(&meye.grabq); + kfifo_reset(&meye.doneq); + return 0; +} + +static int meye_release(struct file *file) +{ + mchip_hic_stop(); + mchip_dma_free(); + clear_bit(0, &meye.in_use); + return 0; +} + +static int meyeioc_g_params(struct meye_params *p) +{ + *p = meye.params; + return 0; +} + +static int meyeioc_s_params(struct meye_params *jp) +{ + if (jp->subsample > 1) + return -EINVAL; + + if (jp->quality > 10) + return -EINVAL; + + if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63) + return -EINVAL; + + if (jp->framerate > 31) + return -EINVAL; + + mutex_lock(&meye.lock); + + if (meye.params.subsample != jp->subsample || + meye.params.quality != jp->quality) + mchip_hic_stop(); /* need restart */ + + meye.params = *jp; + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, + meye.params.sharpness); + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, + meye.params.agc); + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, + meye.params.picture); + mutex_unlock(&meye.lock); + + return 0; +} + +static int meyeioc_qbuf_capt(int *nb) +{ + if (!meye.grab_fbuffer) + return -EINVAL; + + if (*nb >= gbuffers) + return -EINVAL; + + if (*nb < 0) { + /* stop capture */ + mchip_hic_stop(); + return 0; + } + + if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED) + return -EBUSY; + + mutex_lock(&meye.lock); + + if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) + mchip_cont_compression_start(); + + meye.grab_buffer[*nb].state = MEYE_BUF_USING; + kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int), + &meye.grabq_lock); + mutex_unlock(&meye.lock); + + return 0; +} + +static int meyeioc_sync(struct file *file, void *fh, int *i) +{ + int unused; + + if (*i < 0 || *i >= gbuffers) + return -EINVAL; + + mutex_lock(&meye.lock); + switch (meye.grab_buffer[*i].state) { + + case MEYE_BUF_UNUSED: + mutex_unlock(&meye.lock); + return -EINVAL; + case MEYE_BUF_USING: + if (file->f_flags & O_NONBLOCK) { + mutex_unlock(&meye.lock); + return -EAGAIN; + } + if (wait_event_interruptible(meye.proc_list, + (meye.grab_buffer[*i].state != MEYE_BUF_USING))) { + mutex_unlock(&meye.lock); + return -EINTR; + } + /* fall through */ + case MEYE_BUF_DONE: + meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; + if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused, + sizeof(int), &meye.doneq_lock) != sizeof(int)) + break; + } + *i = meye.grab_buffer[*i].size; + mutex_unlock(&meye.lock); + return 0; +} + +static int meyeioc_stillcapt(void) +{ + if (!meye.grab_fbuffer) + return -EINVAL; + + if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) + return -EBUSY; + + mutex_lock(&meye.lock); + meye.grab_buffer[0].state = MEYE_BUF_USING; + mchip_take_picture(); + + mchip_get_picture(meye.grab_fbuffer, + mchip_hsize() * mchip_vsize() * 2); + + meye.grab_buffer[0].state = MEYE_BUF_DONE; + mutex_unlock(&meye.lock); + + return 0; +} + +static int meyeioc_stilljcapt(int *len) +{ + if (!meye.grab_fbuffer) + return -EINVAL; + + if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) + return -EBUSY; + + mutex_lock(&meye.lock); + meye.grab_buffer[0].state = MEYE_BUF_USING; + *len = -1; + + while (*len == -1) { + mchip_take_picture(); + *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); + } + + meye.grab_buffer[0].state = MEYE_BUF_DONE; + mutex_unlock(&meye.lock); + return 0; +} + +static int vidioc_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + strcpy(cap->driver, "meye"); + strcpy(cap->card, "meye"); + sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev)); + + cap->version = (MEYE_DRIVER_MAJORVERSION << 8) + + MEYE_DRIVER_MINORVERSION; + + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING; + + return 0; +} + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + + strcpy(i->name, "Camera"); + i->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int i) +{ + if (i != 0) + return -EINVAL; + + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *fh, + struct v4l2_queryctrl *c) +{ + switch (c->id) { + + case V4L2_CID_BRIGHTNESS: + c->type = V4L2_CTRL_TYPE_INTEGER; + strcpy(c->name, "Brightness"); + c->minimum = 0; + c->maximum = 63; + c->step = 1; + c->default_value = 32; + c->flags = 0; + break; + case V4L2_CID_HUE: + c->type = V4L2_CTRL_TYPE_INTEGER; + strcpy(c->name, "Hue"); + c->minimum = 0; + c->maximum = 63; + c->step = 1; + c->default_value = 32; + c->flags = 0; + break; + case V4L2_CID_CONTRAST: + c->type = V4L2_CTRL_TYPE_INTEGER; + strcpy(c->name, "Contrast"); + c->minimum = 0; + c->maximum = 63; + c->step = 1; + c->default_value = 32; + c->flags = 0; + break; + case V4L2_CID_SATURATION: + c->type = V4L2_CTRL_TYPE_INTEGER; + strcpy(c->name, "Saturation"); + c->minimum = 0; + c->maximum = 63; + c->step = 1; + c->default_value = 32; + c->flags = 0; + break; + case V4L2_CID_AGC: + c->type = V4L2_CTRL_TYPE_INTEGER; + strcpy(c->name, "Agc"); + c->minimum = 0; + c->maximum = 63; + c->step = 1; + c->default_value = 48; + c->flags = 0; + break; + case V4L2_CID_MEYE_SHARPNESS: + case V4L2_CID_SHARPNESS: + c->type = V4L2_CTRL_TYPE_INTEGER; + strcpy(c->name, "Sharpness"); + c->minimum = 0; + c->maximum = 63; + c->step = 1; + c->default_value = 32; + + /* Continue to report legacy private SHARPNESS ctrl but + * say it is disabled in preference to ctrl in the spec + */ + c->flags = (c->id == V4L2_CID_SHARPNESS) ? 0 : + V4L2_CTRL_FLAG_DISABLED; + break; + case V4L2_CID_PICTURE: + c->type = V4L2_CTRL_TYPE_INTEGER; + strcpy(c->name, "Picture"); + c->minimum = 0; + c->maximum = 63; + c->step = 1; + c->default_value = 0; + c->flags = 0; + break; + case V4L2_CID_JPEGQUAL: + c->type = V4L2_CTRL_TYPE_INTEGER; + strcpy(c->name, "JPEG quality"); + c->minimum = 0; + c->maximum = 10; + c->step = 1; + c->default_value = 8; + c->flags = 0; + break; + case V4L2_CID_FRAMERATE: + c->type = V4L2_CTRL_TYPE_INTEGER; + strcpy(c->name, "Framerate"); + c->minimum = 0; + c->maximum = 31; + c->step = 1; + c->default_value = 0; + c->flags = 0; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + mutex_lock(&meye.lock); + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + sony_pic_camera_command( + SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value); + meye.brightness = c->value << 10; + break; + case V4L2_CID_HUE: + sony_pic_camera_command( + SONY_PIC_COMMAND_SETCAMERAHUE, c->value); + meye.hue = c->value << 10; + break; + case V4L2_CID_CONTRAST: + sony_pic_camera_command( + SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value); + meye.contrast = c->value << 10; + break; + case V4L2_CID_SATURATION: + sony_pic_camera_command( + SONY_PIC_COMMAND_SETCAMERACOLOR, c->value); + meye.colour = c->value << 10; + break; + case V4L2_CID_AGC: + sony_pic_camera_command( + SONY_PIC_COMMAND_SETCAMERAAGC, c->value); + meye.params.agc = c->value; + break; + case V4L2_CID_SHARPNESS: + case V4L2_CID_MEYE_SHARPNESS: + sony_pic_camera_command( + SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value); + meye.params.sharpness = c->value; + break; + case V4L2_CID_PICTURE: + sony_pic_camera_command( + SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value); + meye.params.picture = c->value; + break; + case V4L2_CID_JPEGQUAL: + meye.params.quality = c->value; + break; + case V4L2_CID_FRAMERATE: + meye.params.framerate = c->value; + break; + default: + mutex_unlock(&meye.lock); + return -EINVAL; + } + mutex_unlock(&meye.lock); + + return 0; +} + +static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + mutex_lock(&meye.lock); + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = meye.brightness >> 10; + break; + case V4L2_CID_HUE: + c->value = meye.hue >> 10; + break; + case V4L2_CID_CONTRAST: + c->value = meye.contrast >> 10; + break; + case V4L2_CID_SATURATION: + c->value = meye.colour >> 10; + break; + case V4L2_CID_AGC: + c->value = meye.params.agc; + break; + case V4L2_CID_SHARPNESS: + case V4L2_CID_MEYE_SHARPNESS: + c->value = meye.params.sharpness; + break; + case V4L2_CID_PICTURE: + c->value = meye.params.picture; + break; + case V4L2_CID_JPEGQUAL: + c->value = meye.params.quality; + break; + case V4L2_CID_FRAMERATE: + c->value = meye.params.framerate; + break; + default: + mutex_unlock(&meye.lock); + return -EINVAL; + } + mutex_unlock(&meye.lock); + + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index > 1) + return -EINVAL; + + if (f->index == 0) { + /* standard YUV 422 capture */ + f->flags = 0; + strcpy(f->description, "YUV422"); + f->pixelformat = V4L2_PIX_FMT_YUYV; + } else { + /* compressed MJPEG capture */ + f->flags = V4L2_FMT_FLAG_COMPRESSED; + strcpy(f->description, "MJPEG"); + f->pixelformat = V4L2_PIX_FMT_MJPEG; + } + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && + f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) + return -EINVAL; + + if (f->fmt.pix.field != V4L2_FIELD_ANY && + f->fmt.pix.field != V4L2_FIELD_NONE) + return -EINVAL; + + f->fmt.pix.field = V4L2_FIELD_NONE; + + if (f->fmt.pix.width <= 320) { + f->fmt.pix.width = 320; + f->fmt.pix.height = 240; + } else { + f->fmt.pix.width = 640; + f->fmt.pix.height = 480; + } + + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + f->fmt.pix.sizeimage = f->fmt.pix.height * + f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = 0; + f->fmt.pix.priv = 0; + + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + switch (meye.mchip_mode) { + case MCHIP_HIC_MODE_CONT_OUT: + default: + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + break; + case MCHIP_HIC_MODE_CONT_COMP: + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; + break; + } + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.width = mchip_hsize(); + f->fmt.pix.height = mchip_vsize(); + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + f->fmt.pix.sizeimage = f->fmt.pix.height * + f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && + f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) + return -EINVAL; + + if (f->fmt.pix.field != V4L2_FIELD_ANY && + f->fmt.pix.field != V4L2_FIELD_NONE) + return -EINVAL; + + f->fmt.pix.field = V4L2_FIELD_NONE; + mutex_lock(&meye.lock); + + if (f->fmt.pix.width <= 320) { + f->fmt.pix.width = 320; + f->fmt.pix.height = 240; + meye.params.subsample = 1; + } else { + f->fmt.pix.width = 640; + f->fmt.pix.height = 480; + meye.params.subsample = 0; + } + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YUYV: + meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; + break; + case V4L2_PIX_FMT_MJPEG: + meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; + break; + } + + mutex_unlock(&meye.lock); + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + f->fmt.pix.sizeimage = f->fmt.pix.height * + f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = 0; + f->fmt.pix.priv = 0; + + return 0; +} + +static int vidioc_reqbufs(struct file *file, void *fh, + struct v4l2_requestbuffers *req) +{ + int i; + + if (req->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + if (meye.grab_fbuffer && req->count == gbuffers) { + /* already allocated, no modifications */ + return 0; + } + + mutex_lock(&meye.lock); + if (meye.grab_fbuffer) { + for (i = 0; i < gbuffers; i++) + if (meye.vma_use_count[i]) { + mutex_unlock(&meye.lock); + return -EINVAL; + } + rvfree(meye.grab_fbuffer, gbuffers * gbufsize); + meye.grab_fbuffer = NULL; + } + + gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS)); + req->count = gbuffers; + meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize); + + if (!meye.grab_fbuffer) { + printk(KERN_ERR "meye: v4l framebuffer allocation" + " failed\n"); + mutex_unlock(&meye.lock); + return -ENOMEM; + } + + for (i = 0; i < gbuffers; i++) + meye.vma_use_count[i] = 0; + + mutex_unlock(&meye.lock); + + return 0; +} + +static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + unsigned int index = buf->index; + + if (index >= gbuffers) + return -EINVAL; + + buf->bytesused = meye.grab_buffer[index].size; + buf->flags = V4L2_BUF_FLAG_MAPPED; + + if (meye.grab_buffer[index].state == MEYE_BUF_USING) + buf->flags |= V4L2_BUF_FLAG_QUEUED; + + if (meye.grab_buffer[index].state == MEYE_BUF_DONE) + buf->flags |= V4L2_BUF_FLAG_DONE; + + buf->field = V4L2_FIELD_NONE; + buf->timestamp = meye.grab_buffer[index].timestamp; + buf->sequence = meye.grab_buffer[index].sequence; + buf->memory = V4L2_MEMORY_MMAP; + buf->m.offset = index * gbufsize; + buf->length = gbufsize; + + return 0; +} + +static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + if (buf->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + if (buf->index >= gbuffers) + return -EINVAL; + + if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED) + return -EINVAL; + + mutex_lock(&meye.lock); + buf->flags |= V4L2_BUF_FLAG_QUEUED; + buf->flags &= ~V4L2_BUF_FLAG_DONE; + meye.grab_buffer[buf->index].state = MEYE_BUF_USING; + kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index, + sizeof(int), &meye.grabq_lock); + mutex_unlock(&meye.lock); + + return 0; +} + +static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + int reqnr; + + if (buf->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + mutex_lock(&meye.lock); + + if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { + mutex_unlock(&meye.lock); + return -EAGAIN; + } + + if (wait_event_interruptible(meye.proc_list, + kfifo_len(&meye.doneq) != 0) < 0) { + mutex_unlock(&meye.lock); + return -EINTR; + } + + if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr, + sizeof(int), &meye.doneq_lock)) { + mutex_unlock(&meye.lock); + return -EBUSY; + } + + if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) { + mutex_unlock(&meye.lock); + return -EINVAL; + } + + buf->index = reqnr; + buf->bytesused = meye.grab_buffer[reqnr].size; + buf->flags = V4L2_BUF_FLAG_MAPPED; + buf->field = V4L2_FIELD_NONE; + buf->timestamp = meye.grab_buffer[reqnr].timestamp; + buf->sequence = meye.grab_buffer[reqnr].sequence; + buf->memory = V4L2_MEMORY_MMAP; + buf->m.offset = reqnr * gbufsize; + buf->length = gbufsize; + meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED; + mutex_unlock(&meye.lock); + + return 0; +} + +static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) +{ + mutex_lock(&meye.lock); + + switch (meye.mchip_mode) { + case MCHIP_HIC_MODE_CONT_OUT: + mchip_continuous_start(); + break; + case MCHIP_HIC_MODE_CONT_COMP: + mchip_cont_compression_start(); + break; + default: + mutex_unlock(&meye.lock); + return -EINVAL; + } + + mutex_unlock(&meye.lock); + + return 0; +} + +static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) +{ + mutex_lock(&meye.lock); + mchip_hic_stop(); + kfifo_reset(&meye.grabq); + kfifo_reset(&meye.doneq); + + for (i = 0; i < MEYE_MAX_BUFNBRS; i++) + meye.grab_buffer[i].state = MEYE_BUF_UNUSED; + + mutex_unlock(&meye.lock); + return 0; +} + +static long vidioc_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) +{ + switch (cmd) { + case MEYEIOC_G_PARAMS: + return meyeioc_g_params((struct meye_params *) arg); + + case MEYEIOC_S_PARAMS: + return meyeioc_s_params((struct meye_params *) arg); + + case MEYEIOC_QBUF_CAPT: + return meyeioc_qbuf_capt((int *) arg); + + case MEYEIOC_SYNC: + return meyeioc_sync(file, fh, (int *) arg); + + case MEYEIOC_STILLCAPT: + return meyeioc_stillcapt(); + + case MEYEIOC_STILLJCAPT: + return meyeioc_stilljcapt((int *) arg); + + default: + return -EINVAL; + } + +} + +static unsigned int meye_poll(struct file *file, poll_table *wait) +{ + unsigned int res = 0; + + mutex_lock(&meye.lock); + poll_wait(file, &meye.proc_list, wait); + if (kfifo_len(&meye.doneq)) + res = POLLIN | POLLRDNORM; + mutex_unlock(&meye.lock); + return res; +} + +static void meye_vm_open(struct vm_area_struct *vma) +{ + long idx = (long)vma->vm_private_data; + meye.vma_use_count[idx]++; +} + +static void meye_vm_close(struct vm_area_struct *vma) +{ + long idx = (long)vma->vm_private_data; + meye.vma_use_count[idx]--; +} + +static const struct vm_operations_struct meye_vm_ops = { + .open = meye_vm_open, + .close = meye_vm_close, +}; + +static int meye_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long page, pos; + + mutex_lock(&meye.lock); + if (size > gbuffers * gbufsize) { + mutex_unlock(&meye.lock); + return -EINVAL; + } + if (!meye.grab_fbuffer) { + int i; + + /* lazy allocation */ + meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize); + if (!meye.grab_fbuffer) { + printk(KERN_ERR "meye: v4l framebuffer allocation failed\n"); + mutex_unlock(&meye.lock); + return -ENOMEM; + } + for (i = 0; i < gbuffers; i++) + meye.vma_use_count[i] = 0; + } + pos = (unsigned long)meye.grab_fbuffer + offset; + + while (size > 0) { + page = vmalloc_to_pfn((void *)pos); + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { + mutex_unlock(&meye.lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + vma->vm_ops = &meye_vm_ops; + vma->vm_flags &= ~VM_IO; /* not I/O memory */ + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + vma->vm_private_data = (void *) (offset / gbufsize); + meye_vm_open(vma); + + mutex_unlock(&meye.lock); + return 0; +} + +static const struct v4l2_file_operations meye_fops = { + .owner = THIS_MODULE, + .open = meye_open, + .release = meye_release, + .mmap = meye_mmap, + .unlocked_ioctl = video_ioctl2, + .poll = meye_poll, +}; + +static const struct v4l2_ioctl_ops meye_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_default = vidioc_default, +}; + +static struct video_device meye_template = { + .name = "meye", + .fops = &meye_fops, + .ioctl_ops = &meye_ioctl_ops, + .release = video_device_release, +}; + +#ifdef CONFIG_PM +static int meye_suspend(struct pci_dev *pdev, pm_message_t state) +{ + pci_save_state(pdev); + meye.pm_mchip_mode = meye.mchip_mode; + mchip_hic_stop(); + mchip_set(MCHIP_MM_INTA, 0x0); + return 0; +} + +static int meye_resume(struct pci_dev *pdev) +{ + pci_restore_state(pdev); + pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); + + mchip_delay(MCHIP_HIC_CMD, 0); + mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); + msleep(1); + mchip_set(MCHIP_VRJ_SOFT_RESET, 1); + msleep(1); + mchip_set(MCHIP_MM_PCI_MODE, 5); + msleep(1); + mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); + + switch (meye.pm_mchip_mode) { + case MCHIP_HIC_MODE_CONT_OUT: + mchip_continuous_start(); + break; + case MCHIP_HIC_MODE_CONT_COMP: + mchip_cont_compression_start(); + break; + } + return 0; +} +#endif + +static int __devinit meye_probe(struct pci_dev *pcidev, + const struct pci_device_id *ent) +{ + struct v4l2_device *v4l2_dev = &meye.v4l2_dev; + int ret = -EBUSY; + unsigned long mchip_adr; + + if (meye.mchip_dev != NULL) { + printk(KERN_ERR "meye: only one device allowed!\n"); + goto outnotdev; + } + + ret = v4l2_device_register(&pcidev->dev, v4l2_dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return ret; + } + ret = -ENOMEM; + meye.mchip_dev = pcidev; + meye.vdev = video_device_alloc(); + if (!meye.vdev) { + v4l2_err(v4l2_dev, "video_device_alloc() failed!\n"); + goto outnotdev; + } + + meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE); + if (!meye.grab_temp) { + v4l2_err(v4l2_dev, "grab buffer allocation failed\n"); + goto outvmalloc; + } + + spin_lock_init(&meye.grabq_lock); + if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, + GFP_KERNEL)) { + v4l2_err(v4l2_dev, "fifo allocation failed\n"); + goto outkfifoalloc1; + } + spin_lock_init(&meye.doneq_lock); + if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, + GFP_KERNEL)) { + v4l2_err(v4l2_dev, "fifo allocation failed\n"); + goto outkfifoalloc2; + } + + memcpy(meye.vdev, &meye_template, sizeof(meye_template)); + meye.vdev->v4l2_dev = &meye.v4l2_dev; + + ret = -EIO; + if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) { + v4l2_err(v4l2_dev, "meye: unable to power on the camera\n"); + v4l2_err(v4l2_dev, "meye: did you enable the camera in " + "sonypi using the module options ?\n"); + goto outsonypienable; + } + + if ((ret = pci_enable_device(meye.mchip_dev))) { + v4l2_err(v4l2_dev, "meye: pci_enable_device failed\n"); + goto outenabledev; + } + + mchip_adr = pci_resource_start(meye.mchip_dev,0); + if (!mchip_adr) { + v4l2_err(v4l2_dev, "meye: mchip has no device base address\n"); + goto outregions; + } + if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0), + pci_resource_len(meye.mchip_dev, 0), + "meye")) { + v4l2_err(v4l2_dev, "meye: request_mem_region failed\n"); + goto outregions; + } + meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS); + if (!meye.mchip_mmregs) { + v4l2_err(v4l2_dev, "meye: ioremap failed\n"); + goto outremap; + } + + meye.mchip_irq = pcidev->irq; + if (request_irq(meye.mchip_irq, meye_irq, + IRQF_DISABLED | IRQF_SHARED, "meye", meye_irq)) { + v4l2_err(v4l2_dev, "request_irq failed\n"); + goto outreqirq; + } + + pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8); + pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64); + + pci_set_master(meye.mchip_dev); + + /* Ask the camera to perform a soft reset. */ + pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); + + mchip_delay(MCHIP_HIC_CMD, 0); + mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); + + msleep(1); + mchip_set(MCHIP_VRJ_SOFT_RESET, 1); + + msleep(1); + mchip_set(MCHIP_MM_PCI_MODE, 5); + + msleep(1); + mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); + + mutex_init(&meye.lock); + init_waitqueue_head(&meye.proc_list); + meye.brightness = 32 << 10; + meye.hue = 32 << 10; + meye.colour = 32 << 10; + meye.contrast = 32 << 10; + meye.params.subsample = 0; + meye.params.quality = 8; + meye.params.sharpness = 32; + meye.params.agc = 48; + meye.params.picture = 0; + meye.params.framerate = 0; + + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32); + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32); + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32); + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32); + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32); + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0); + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48); + + if (video_register_device(meye.vdev, VFL_TYPE_GRABBER, + video_nr) < 0) { + v4l2_err(v4l2_dev, "video_register_device failed\n"); + goto outvideoreg; + } + + v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n", + MEYE_DRIVER_VERSION); + v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n", + meye.mchip_dev->revision, mchip_adr, meye.mchip_irq); + + return 0; + +outvideoreg: + free_irq(meye.mchip_irq, meye_irq); +outreqirq: + iounmap(meye.mchip_mmregs); +outremap: + release_mem_region(pci_resource_start(meye.mchip_dev, 0), + pci_resource_len(meye.mchip_dev, 0)); +outregions: + pci_disable_device(meye.mchip_dev); +outenabledev: + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); +outsonypienable: + kfifo_free(&meye.doneq); +outkfifoalloc2: + kfifo_free(&meye.grabq); +outkfifoalloc1: + vfree(meye.grab_temp); +outvmalloc: + video_device_release(meye.vdev); +outnotdev: + return ret; +} + +static void __devexit meye_remove(struct pci_dev *pcidev) +{ + video_unregister_device(meye.vdev); + + mchip_hic_stop(); + + mchip_dma_free(); + + /* disable interrupts */ + mchip_set(MCHIP_MM_INTA, 0x0); + + free_irq(meye.mchip_irq, meye_irq); + + iounmap(meye.mchip_mmregs); + + release_mem_region(pci_resource_start(meye.mchip_dev, 0), + pci_resource_len(meye.mchip_dev, 0)); + + pci_disable_device(meye.mchip_dev); + + sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); + + kfifo_free(&meye.doneq); + kfifo_free(&meye.grabq); + + vfree(meye.grab_temp); + + if (meye.grab_fbuffer) { + rvfree(meye.grab_fbuffer, gbuffers*gbufsize); + meye.grab_fbuffer = NULL; + } + + printk(KERN_INFO "meye: removed\n"); +} + +static struct pci_device_id meye_pci_tbl[] = { + { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 }, + { } +}; + +MODULE_DEVICE_TABLE(pci, meye_pci_tbl); + +static struct pci_driver meye_driver = { + .name = "meye", + .id_table = meye_pci_tbl, + .probe = meye_probe, + .remove = __devexit_p(meye_remove), +#ifdef CONFIG_PM + .suspend = meye_suspend, + .resume = meye_resume, +#endif +}; + +static int __init meye_init(void) +{ + gbuffers = max(2, min((int)gbuffers, MEYE_MAX_BUFNBRS)); + if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE) + gbufsize = MEYE_MAX_BUFSIZE; + gbufsize = PAGE_ALIGN(gbufsize); + printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) " + "for capture\n", + gbuffers, + gbufsize / 1024, gbuffers * gbufsize / 1024); + return pci_register_driver(&meye_driver); +} + +static void __exit meye_exit(void) +{ + pci_unregister_driver(&meye_driver); +} + +module_init(meye_init); +module_exit(meye_exit); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/meye.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/meye.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/meye.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/meye.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,324 @@ +/* + * Motion Eye video4linux driver for Sony Vaio PictureBook + * + * Copyright (C) 2001-2004 Stelian Pop + * + * Copyright (C) 2001-2002 Alcôve + * + * Copyright (C) 2000 Andrew Tridgell + * + * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. + * + * Some parts borrowed from various video4linux drivers, especially + * bttv-driver.c and zoran.c, see original files for credits. + * + * 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, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _MEYE_PRIV_H_ +#define _MEYE_PRIV_H_ + +#define MEYE_DRIVER_MAJORVERSION 1 +#define MEYE_DRIVER_MINORVERSION 14 + +#define MEYE_DRIVER_VERSION __stringify(MEYE_DRIVER_MAJORVERSION) "." \ + __stringify(MEYE_DRIVER_MINORVERSION) + +#include +#include +#include + +/****************************************************************************/ +/* Motion JPEG chip registers */ +/****************************************************************************/ + +/* Motion JPEG chip PCI configuration registers */ +#define MCHIP_PCI_POWER_CSR 0x54 +#define MCHIP_PCI_MCORE_STATUS 0x60 /* see HIC_STATUS */ +#define MCHIP_PCI_HOSTUSEREQ_SET 0x64 +#define MCHIP_PCI_HOSTUSEREQ_CLR 0x68 +#define MCHIP_PCI_LOWPOWER_SET 0x6c +#define MCHIP_PCI_LOWPOWER_CLR 0x70 +#define MCHIP_PCI_SOFTRESET_SET 0x74 + +/* Motion JPEG chip memory mapped registers */ +#define MCHIP_MM_REGS 0x200 /* 512 bytes */ +#define MCHIP_REG_TIMEOUT 1000 /* reg access, ~us */ +#define MCHIP_MCC_VRJ_TIMEOUT 1000 /* MCC & VRJ access */ + +#define MCHIP_MM_PCI_MODE 0x00 /* PCI access mode */ +#define MCHIP_MM_PCI_MODE_RETRY 0x00000001 /* retry mode */ +#define MCHIP_MM_PCI_MODE_MASTER 0x00000002 /* master access */ +#define MCHIP_MM_PCI_MODE_READ_LINE 0x00000004 /* read line */ + +#define MCHIP_MM_INTA 0x04 /* Int status/mask */ +#define MCHIP_MM_INTA_MCC 0x00000001 /* MCC interrupt */ +#define MCHIP_MM_INTA_VRJ 0x00000002 /* VRJ interrupt */ +#define MCHIP_MM_INTA_HIC_1 0x00000004 /* one frame done */ +#define MCHIP_MM_INTA_HIC_1_MASK 0x00000400 /* 1: enable */ +#define MCHIP_MM_INTA_HIC_END 0x00000008 /* all frames done */ +#define MCHIP_MM_INTA_HIC_END_MASK 0x00000800 +#define MCHIP_MM_INTA_JPEG 0x00000010 /* decompress. error */ +#define MCHIP_MM_INTA_JPEG_MASK 0x00001000 +#define MCHIP_MM_INTA_CAPTURE 0x00000020 /* capture end */ +#define MCHIP_MM_INTA_PCI_ERR 0x00000040 /* PCI error */ +#define MCHIP_MM_INTA_PCI_ERR_MASK 0x00004000 + +#define MCHIP_MM_PT_ADDR 0x08 /* page table address*/ + /* n*4kB */ +#define MCHIP_NB_PAGES 1024 /* pages for display */ +#define MCHIP_NB_PAGES_MJPEG 256 /* pages for mjpeg */ + +#define MCHIP_MM_FIR(n) (0x0c+(n)*4) /* Frame info 0-3 */ +#define MCHIP_MM_FIR_RDY 0x00000001 /* frame ready */ +#define MCHIP_MM_FIR_FAILFR_MASK 0xf8000000 /* # of failed frames */ +#define MCHIP_MM_FIR_FAILFR_SHIFT 27 + + /* continuous comp/decomp mode */ +#define MCHIP_MM_FIR_C_ENDL_MASK 0x000007fe /* end DW [10] */ +#define MCHIP_MM_FIR_C_ENDL_SHIFT 1 +#define MCHIP_MM_FIR_C_ENDP_MASK 0x0007f800 /* end page [8] */ +#define MCHIP_MM_FIR_C_ENDP_SHIFT 11 +#define MCHIP_MM_FIR_C_STARTP_MASK 0x07f80000 /* start page [8] */ +#define MCHIP_MM_FIR_C_STARTP_SHIFT 19 + + /* continuous picture output mode */ +#define MCHIP_MM_FIR_O_STARTP_MASK 0x7ffe0000 /* start page [10] */ +#define MCHIP_MM_FIR_O_STARTP_SHIFT 17 + +#define MCHIP_MM_FIFO_DATA 0x1c /* PCI TGT FIFO data */ +#define MCHIP_MM_FIFO_STATUS 0x20 /* PCI TGT FIFO stat */ +#define MCHIP_MM_FIFO_MASK 0x00000003 +#define MCHIP_MM_FIFO_WAIT_OR_READY 0x00000002 /* Bits common to WAIT & READY*/ +#define MCHIP_MM_FIFO_IDLE 0x0 /* HIC idle */ +#define MCHIP_MM_FIFO_IDLE1 0x1 /* idem ??? */ +#define MCHIP_MM_FIFO_WAIT 0x2 /* wait request */ +#define MCHIP_MM_FIFO_READY 0x3 /* data ready */ + +#define MCHIP_HIC_HOST_USEREQ 0x40 /* host uses MCORE */ + +#define MCHIP_HIC_TP_BUSY 0x44 /* taking picture */ + +#define MCHIP_HIC_PIC_SAVED 0x48 /* pic in SDRAM */ + +#define MCHIP_HIC_LOWPOWER 0x4c /* clock stopped */ + +#define MCHIP_HIC_CTL 0x50 /* HIC control */ +#define MCHIP_HIC_CTL_SOFT_RESET 0x00000001 /* MCORE reset */ +#define MCHIP_HIC_CTL_MCORE_RDY 0x00000002 /* MCORE ready */ + +#define MCHIP_HIC_CMD 0x54 /* HIC command */ +#define MCHIP_HIC_CMD_BITS 0x00000003 /* cmd width=[1:0]*/ +#define MCHIP_HIC_CMD_NOOP 0x0 +#define MCHIP_HIC_CMD_START 0x1 +#define MCHIP_HIC_CMD_STOP 0x2 + +#define MCHIP_HIC_MODE 0x58 +#define MCHIP_HIC_MODE_NOOP 0x0 +#define MCHIP_HIC_MODE_STILL_CAP 0x1 /* still pic capt */ +#define MCHIP_HIC_MODE_DISPLAY 0x2 /* display */ +#define MCHIP_HIC_MODE_STILL_COMP 0x3 /* still pic comp. */ +#define MCHIP_HIC_MODE_STILL_DECOMP 0x4 /* still pic decomp. */ +#define MCHIP_HIC_MODE_CONT_COMP 0x5 /* cont capt+comp */ +#define MCHIP_HIC_MODE_CONT_DECOMP 0x6 /* cont decomp+disp */ +#define MCHIP_HIC_MODE_STILL_OUT 0x7 /* still pic output */ +#define MCHIP_HIC_MODE_CONT_OUT 0x8 /* cont output */ + +#define MCHIP_HIC_STATUS 0x5c +#define MCHIP_HIC_STATUS_MCC_RDY 0x00000001 /* MCC reg acc ok */ +#define MCHIP_HIC_STATUS_VRJ_RDY 0x00000002 /* VRJ reg acc ok */ +#define MCHIP_HIC_STATUS_IDLE 0x00000003 +#define MCHIP_HIC_STATUS_CAPDIS 0x00000004 /* cap/disp in prog */ +#define MCHIP_HIC_STATUS_COMPDEC 0x00000008 /* (de)comp in prog */ +#define MCHIP_HIC_STATUS_BUSY 0x00000010 /* HIC busy */ + +#define MCHIP_HIC_S_RATE 0x60 /* MJPEG # frames */ + +#define MCHIP_HIC_PCI_VFMT 0x64 /* video format */ +#define MCHIP_HIC_PCI_VFMT_YVYU 0x00000001 /* 0: V Y' U Y */ + /* 1: Y' V Y U */ + +#define MCHIP_MCC_CMD 0x80 /* MCC commands */ +#define MCHIP_MCC_CMD_INITIAL 0x0 /* idle ? */ +#define MCHIP_MCC_CMD_IIC_START_SET 0x1 +#define MCHIP_MCC_CMD_IIC_END_SET 0x2 +#define MCHIP_MCC_CMD_FM_WRITE 0x3 /* frame memory */ +#define MCHIP_MCC_CMD_FM_READ 0x4 +#define MCHIP_MCC_CMD_FM_STOP 0x5 +#define MCHIP_MCC_CMD_CAPTURE 0x6 +#define MCHIP_MCC_CMD_DISPLAY 0x7 +#define MCHIP_MCC_CMD_END_DISP 0x8 +#define MCHIP_MCC_CMD_STILL_COMP 0x9 +#define MCHIP_MCC_CMD_STILL_DECOMP 0xa +#define MCHIP_MCC_CMD_STILL_OUTPUT 0xb +#define MCHIP_MCC_CMD_CONT_OUTPUT 0xc +#define MCHIP_MCC_CMD_CONT_COMP 0xd +#define MCHIP_MCC_CMD_CONT_DECOMP 0xe +#define MCHIP_MCC_CMD_RESET 0xf /* MCC reset */ + +#define MCHIP_MCC_IIC_WR 0x84 + +#define MCHIP_MCC_MCC_WR 0x88 + +#define MCHIP_MCC_MCC_RD 0x8c + +#define MCHIP_MCC_STATUS 0x90 +#define MCHIP_MCC_STATUS_CAPT 0x00000001 /* capturing */ +#define MCHIP_MCC_STATUS_DISP 0x00000002 /* displaying */ +#define MCHIP_MCC_STATUS_COMP 0x00000004 /* compressing */ +#define MCHIP_MCC_STATUS_DECOMP 0x00000008 /* decompressing */ +#define MCHIP_MCC_STATUS_MCC_WR 0x00000010 /* register ready */ +#define MCHIP_MCC_STATUS_MCC_RD 0x00000020 /* register ready */ +#define MCHIP_MCC_STATUS_IIC_WR 0x00000040 /* register ready */ +#define MCHIP_MCC_STATUS_OUTPUT 0x00000080 /* output in prog */ + +#define MCHIP_MCC_SIG_POLARITY 0x94 +#define MCHIP_MCC_SIG_POL_VS_H 0x00000001 /* VS active-high */ +#define MCHIP_MCC_SIG_POL_HS_H 0x00000002 /* HS active-high */ +#define MCHIP_MCC_SIG_POL_DOE_H 0x00000004 /* DOE active-high */ + +#define MCHIP_MCC_IRQ 0x98 +#define MCHIP_MCC_IRQ_CAPDIS_STRT 0x00000001 /* cap/disp started */ +#define MCHIP_MCC_IRQ_CAPDIS_STRT_MASK 0x00000010 +#define MCHIP_MCC_IRQ_CAPDIS_END 0x00000002 /* cap/disp ended */ +#define MCHIP_MCC_IRQ_CAPDIS_END_MASK 0x00000020 +#define MCHIP_MCC_IRQ_COMPDEC_STRT 0x00000004 /* (de)comp started */ +#define MCHIP_MCC_IRQ_COMPDEC_STRT_MASK 0x00000040 +#define MCHIP_MCC_IRQ_COMPDEC_END 0x00000008 /* (de)comp ended */ +#define MCHIP_MCC_IRQ_COMPDEC_END_MASK 0x00000080 + +#define MCHIP_MCC_HSTART 0x9c /* video in */ +#define MCHIP_MCC_VSTART 0xa0 +#define MCHIP_MCC_HCOUNT 0xa4 +#define MCHIP_MCC_VCOUNT 0xa8 +#define MCHIP_MCC_R_XBASE 0xac /* capt/disp */ +#define MCHIP_MCC_R_YBASE 0xb0 +#define MCHIP_MCC_R_XRANGE 0xb4 +#define MCHIP_MCC_R_YRANGE 0xb8 +#define MCHIP_MCC_B_XBASE 0xbc /* comp/decomp */ +#define MCHIP_MCC_B_YBASE 0xc0 +#define MCHIP_MCC_B_XRANGE 0xc4 +#define MCHIP_MCC_B_YRANGE 0xc8 + +#define MCHIP_MCC_R_SAMPLING 0xcc /* 1: 1:4 */ + +#define MCHIP_VRJ_CMD 0x100 /* VRJ commands */ + +/* VRJ registers (see table 12.2.4) */ +#define MCHIP_VRJ_COMPRESSED_DATA 0x1b0 +#define MCHIP_VRJ_PIXEL_DATA 0x1b8 + +#define MCHIP_VRJ_BUS_MODE 0x100 +#define MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL 0x108 +#define MCHIP_VRJ_PDAT_USE 0x110 +#define MCHIP_VRJ_MODE_SPECIFY 0x118 +#define MCHIP_VRJ_LIMIT_COMPRESSED_LO 0x120 +#define MCHIP_VRJ_LIMIT_COMPRESSED_HI 0x124 +#define MCHIP_VRJ_COMP_DATA_FORMAT 0x128 +#define MCHIP_VRJ_TABLE_DATA 0x140 +#define MCHIP_VRJ_RESTART_INTERVAL 0x148 +#define MCHIP_VRJ_NUM_LINES 0x150 +#define MCHIP_VRJ_NUM_PIXELS 0x158 +#define MCHIP_VRJ_NUM_COMPONENTS 0x160 +#define MCHIP_VRJ_SOF1 0x168 +#define MCHIP_VRJ_SOF2 0x170 +#define MCHIP_VRJ_SOF3 0x178 +#define MCHIP_VRJ_SOF4 0x180 +#define MCHIP_VRJ_SOS 0x188 +#define MCHIP_VRJ_SOFT_RESET 0x190 + +#define MCHIP_VRJ_STATUS 0x1c0 +#define MCHIP_VRJ_STATUS_BUSY 0x00001 +#define MCHIP_VRJ_STATUS_COMP_ACCESS 0x00002 +#define MCHIP_VRJ_STATUS_PIXEL_ACCESS 0x00004 +#define MCHIP_VRJ_STATUS_ERROR 0x00008 + +#define MCHIP_VRJ_IRQ_FLAG 0x1c8 +#define MCHIP_VRJ_ERROR_REPORT 0x1d8 + +#define MCHIP_VRJ_START_COMMAND 0x1a0 + +/****************************************************************************/ +/* Driver definitions. */ +/****************************************************************************/ + +/* Sony Programmable I/O Controller for accessing the camera commands */ +#include + +/* private API definitions */ +#include +#include + + +/* Enable jpg software correction */ +#define MEYE_JPEG_CORRECTION 1 + +/* Maximum size of a buffer */ +#define MEYE_MAX_BUFSIZE 614400 /* 640 * 480 * 2 */ + +/* Maximum number of buffers */ +#define MEYE_MAX_BUFNBRS 32 + +/* State of a buffer */ +#define MEYE_BUF_UNUSED 0 /* not used */ +#define MEYE_BUF_USING 1 /* currently grabbing / playing */ +#define MEYE_BUF_DONE 2 /* done */ + +/* grab buffer */ +struct meye_grab_buffer { + int state; /* state of buffer */ + unsigned long size; /* size of jpg frame */ + struct timeval timestamp; /* timestamp */ + unsigned long sequence; /* sequence number */ +}; + +/* size of kfifos containings buffer indices */ +#define MEYE_QUEUE_SIZE MEYE_MAX_BUFNBRS + +/* Motion Eye device structure */ +struct meye { + struct v4l2_device v4l2_dev; /* Main v4l2_device struct */ + struct pci_dev *mchip_dev; /* pci device */ + u8 mchip_irq; /* irq */ + u8 mchip_mode; /* actual mchip mode: HIC_MODE... */ + u8 mchip_fnum; /* current mchip frame number */ + unsigned char __iomem *mchip_mmregs;/* mchip: memory mapped registers */ + u8 *mchip_ptable[MCHIP_NB_PAGES];/* mchip: ptable */ + void *mchip_ptable_toc; /* mchip: ptable toc */ + dma_addr_t mchip_dmahandle; /* mchip: dma handle to ptable toc */ + unsigned char *grab_fbuffer; /* capture framebuffer */ + unsigned char *grab_temp; /* temporary buffer */ + /* list of buffers */ + struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; + int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */ + struct mutex lock; /* mutex for open/mmap... */ + struct kfifo grabq; /* queue for buffers to be grabbed */ + spinlock_t grabq_lock; /* lock protecting the queue */ + struct kfifo doneq; /* queue for grabbed buffers */ + spinlock_t doneq_lock; /* lock protecting the queue */ + wait_queue_head_t proc_list; /* wait queue */ + struct video_device *vdev; /* video device parameters */ + u16 brightness; + u16 hue; + u16 contrast; + u16 colour; + struct meye_params params; /* additional parameters */ + unsigned long in_use; /* set to 1 if the device is in use */ +#ifdef CONFIG_PM + u8 pm_mchip_mode; /* old mchip mode */ +#endif +}; + +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-driver.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-driver.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-driver.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-driver.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,881 @@ +/* + * Programming the mspx4xx sound processor family + * + * (c) 1997-2001 Gerd Knorr + * + * what works and what doesn't: + * + * AM-Mono + * Support for Hauppauge cards added (decoding handled by tuner) added by + * Frederic Crozat + * + * FM-Mono + * should work. The stereo modes are backward compatible to FM-mono, + * therefore FM-Mono should be allways available. + * + * FM-Stereo (B/G, used in germany) + * should work, with autodetect + * + * FM-Stereo (satellite) + * should work, no autodetect (i.e. default is mono, but you can + * switch to stereo -- untested) + * + * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) + * should work, with autodetect. Support for NICAM was added by + * Pekka Pietikainen + * + * TODO: + * - better SAT support + * + * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) + * using soundcore instead of OSS + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msp3400-driver.h" + +/* ---------------------------------------------------------------------- */ + +MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); +MODULE_AUTHOR("Gerd Knorr"); +MODULE_LICENSE("GPL"); + +/* module parameters */ +static int opmode = OPMODE_AUTO; +int msp_debug; /* msp_debug output */ +int msp_once; /* no continuous stereo monitoring */ +int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), + the autoscan seems work well only with FM... */ +int msp_standard = 1; /* Override auto detect of audio msp_standard, + if needed. */ +int msp_dolby; + +int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual + (msp34xxg only) 0x00a0-0x03c0 */ + +/* read-only */ +module_param(opmode, int, 0444); + +/* read-write */ +module_param_named(once, msp_once, bool, 0644); +module_param_named(debug, msp_debug, int, 0644); +module_param_named(stereo_threshold, msp_stereo_thresh, int, 0644); +module_param_named(standard, msp_standard, int, 0644); +module_param_named(amsound, msp_amsound, bool, 0644); +module_param_named(dolby, msp_dolby, bool, 0644); + +MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); +MODULE_PARM_DESC(once, "No continuous stereo monitoring"); +MODULE_PARM_DESC(debug, "Enable debug messages [0-3]"); +MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); +MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); +MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); +MODULE_PARM_DESC(dolby, "Activates Dolby processing"); + +/* ---------------------------------------------------------------------- */ + +/* control subaddress */ +#define I2C_MSP_CONTROL 0x00 +/* demodulator unit subaddress */ +#define I2C_MSP_DEM 0x10 +/* DSP unit subaddress */ +#define I2C_MSP_DSP 0x12 + + +/* ----------------------------------------------------------------------- */ +/* functions for talking to the MSP3400C Sound processor */ + +int msp_reset(struct i2c_client *client) +{ + /* reset and read revision code */ + static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 }; + static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 }; + static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e }; + u8 read[2]; + struct i2c_msg reset[2] = { + { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, + { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, + }; + struct i2c_msg test[2] = { + { client->addr, 0, 3, write }, + { client->addr, I2C_M_RD, 2, read }, + }; + + v4l_dbg(3, msp_debug, client, "msp_reset\n"); + if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || + i2c_transfer(client->adapter, &reset[1], 1) != 1 || + i2c_transfer(client->adapter, test, 2) != 2) { + v4l_err(client, "chip reset failed\n"); + return -1; + } + return 0; +} + +static int msp_read(struct i2c_client *client, int dev, int addr) +{ + int err, retval; + u8 write[3]; + u8 read[2]; + struct i2c_msg msgs[2] = { + { client->addr, 0, 3, write }, + { client->addr, I2C_M_RD, 2, read } + }; + + write[0] = dev + 1; + write[1] = addr >> 8; + write[2] = addr & 0xff; + + for (err = 0; err < 3; err++) { + if (i2c_transfer(client->adapter, msgs, 2) == 2) + break; + v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err, + dev, addr); + schedule_timeout_interruptible(msecs_to_jiffies(10)); + } + if (err == 3) { + v4l_warn(client, "resetting chip, sound will go off.\n"); + msp_reset(client); + return -1; + } + retval = read[0] << 8 | read[1]; + v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", + dev, addr, retval); + return retval; +} + +int msp_read_dem(struct i2c_client *client, int addr) +{ + return msp_read(client, I2C_MSP_DEM, addr); +} + +int msp_read_dsp(struct i2c_client *client, int addr) +{ + return msp_read(client, I2C_MSP_DSP, addr); +} + +static int msp_write(struct i2c_client *client, int dev, int addr, int val) +{ + int err; + u8 buffer[5]; + + buffer[0] = dev; + buffer[1] = addr >> 8; + buffer[2] = addr & 0xff; + buffer[3] = val >> 8; + buffer[4] = val & 0xff; + + v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", + dev, addr, val); + for (err = 0; err < 3; err++) { + if (i2c_master_send(client, buffer, 5) == 5) + break; + v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err, + dev, addr); + schedule_timeout_interruptible(msecs_to_jiffies(10)); + } + if (err == 3) { + v4l_warn(client, "resetting chip, sound will go off.\n"); + msp_reset(client); + return -1; + } + return 0; +} + +int msp_write_dem(struct i2c_client *client, int addr, int val) +{ + return msp_write(client, I2C_MSP_DEM, addr, val); +} + +int msp_write_dsp(struct i2c_client *client, int addr, int val) +{ + return msp_write(client, I2C_MSP_DSP, addr, val); +} + +/* ----------------------------------------------------------------------- * + * bits 9 8 5 - SCART DSP input Select: + * 0 0 0 - SCART 1 to DSP input (reset position) + * 0 1 0 - MONO to DSP input + * 1 0 0 - SCART 2 to DSP input + * 1 1 1 - Mute DSP input + * + * bits 11 10 6 - SCART 1 Output Select: + * 0 0 0 - undefined (reset position) + * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) + * 1 0 0 - MONO input to SCART 1 Output + * 1 1 0 - SCART 1 DA to SCART 1 Output + * 0 0 1 - SCART 2 DA to SCART 1 Output + * 0 1 1 - SCART 1 Input to SCART 1 Output + * 1 1 1 - Mute SCART 1 Output + * + * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): + * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) + * 0 1 0 - SCART 1 Input to SCART 2 Output + * 1 0 0 - MONO input to SCART 2 Output + * 0 0 1 - SCART 2 DA to SCART 2 Output + * 0 1 1 - SCART 2 Input to SCART 2 Output + * 1 1 0 - Mute SCART 2 Output + * + * Bits 4 to 0 should be zero. + * ----------------------------------------------------------------------- */ + +static int scarts[3][9] = { + /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ + /* SCART DSP Input select */ + { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, + /* SCART1 Output select */ + { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, + /* SCART2 Output select */ + { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, +}; + +static char *scart_names[] = { + "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" +}; + +void msp_set_scart(struct i2c_client *client, int in, int out) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + state->in_scart = in; + + if (in >= 0 && in <= 7 && out >= 0 && out <= 2) { + if (-1 == scarts[out][in + 1]) + return; + + state->acb &= ~scarts[out][0]; + state->acb |= scarts[out][in + 1]; + } else + state->acb = 0xf60; /* Mute Input and SCART 1 Output */ + + v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n", + scart_names[in], out, state->acb); + msp_write_dsp(client, 0x13, state->acb); + + /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ + if (state->has_i2s_conf) + msp_write_dem(client, 0x40, state->i2s_mode); +} + +/* ------------------------------------------------------------------------ */ + +static void msp_wake_thread(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + if (NULL == state->kthread) + return; + state->watch_stereo = 0; + state->restart = 1; + wake_up_interruptible(&state->wq); +} + +int msp_sleep(struct msp_state *state, int timeout) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&state->wq, &wait); + if (!kthread_should_stop()) { + if (timeout < 0) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } else { + schedule_timeout_interruptible + (msecs_to_jiffies(timeout)); + } + } + + remove_wait_queue(&state->wq, &wait); + try_to_freeze(); + return state->restart; +} + +/* ------------------------------------------------------------------------ */ + +static int msp_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct msp_state *state = ctrl_to_state(ctrl); + struct i2c_client *client = v4l2_get_subdevdata(&state->sd); + int val = ctrl->val; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: { + /* audio volume cluster */ + int reallymuted = state->muted->val | state->scan_in_progress; + + if (!reallymuted) + val = (val * 0x7f / 65535) << 8; + + v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", + state->muted->val ? "on" : "off", + state->scan_in_progress ? "yes" : "no", + state->volume->val); + + msp_write_dsp(client, 0x0000, val); + msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1)); + if (state->has_scart2_out_volume) + msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1)); + if (state->has_headphones) + msp_write_dsp(client, 0x0006, val); + break; + } + + case V4L2_CID_AUDIO_BASS: + val = ((val - 32768) * 0x60 / 65535) << 8; + msp_write_dsp(client, 0x0002, val); + if (state->has_headphones) + msp_write_dsp(client, 0x0031, val); + break; + + case V4L2_CID_AUDIO_TREBLE: + val = ((val - 32768) * 0x60 / 65535) << 8; + msp_write_dsp(client, 0x0003, val); + if (state->has_headphones) + msp_write_dsp(client, 0x0032, val); + break; + + case V4L2_CID_AUDIO_LOUDNESS: + val = val ? ((5 * 4) << 8) : 0; + msp_write_dsp(client, 0x0004, val); + if (state->has_headphones) + msp_write_dsp(client, 0x0033, val); + break; + + case V4L2_CID_AUDIO_BALANCE: + val = (u8)((val / 256) - 128); + msp_write_dsp(client, 0x0001, val << 8); + if (state->has_headphones) + msp_write_dsp(client, 0x0030, val << 8); + break; + + default: + return -EINVAL; + } + return 0; +} + +void msp_update_volume(struct msp_state *state) +{ + /* Force an update of the volume/mute cluster */ + v4l2_ctrl_lock(state->volume); + state->volume->val = state->volume->cur.val; + state->muted->val = state->muted->cur.val; + msp_s_ctrl(state->volume); + v4l2_ctrl_unlock(state->volume); +} + +/* --- v4l2 ioctls --- */ +static int msp_s_radio(struct v4l2_subdev *sd) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (state->radio) + return 0; + state->radio = 1; + v4l_dbg(1, msp_debug, client, "switching to radio mode\n"); + state->watch_stereo = 0; + switch (state->opmode) { + case OPMODE_MANUAL: + /* set msp3400 to FM radio mode */ + msp3400c_set_mode(client, MSP_MODE_FM_RADIO); + msp3400c_set_carrier(client, MSP_CARRIER(10.7), + MSP_CARRIER(10.7)); + msp_update_volume(state); + break; + case OPMODE_AUTODETECT: + case OPMODE_AUTOSELECT: + /* the thread will do for us */ + msp_wake_thread(client); + break; + } + return 0; +} + +static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* new channel -- kick audio carrier scan */ + msp_wake_thread(client); + return 0; +} + +static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int update = state->radio || state->v4l2_std != id; + + state->v4l2_std = id; + state->radio = 0; + if (update) + msp_wake_thread(client); + return 0; +} + +static int msp_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int tuner = (input >> 3) & 1; + int sc_in = input & 0x7; + int sc1_out = output & 0xf; + int sc2_out = (output >> 4) & 0xf; + u16 val, reg; + int i; + int extern_input = 1; + + if (state->route_in == input && state->route_out == output) + return 0; + state->route_in = input; + state->route_out = output; + /* check if the tuner input is used */ + for (i = 0; i < 5; i++) { + if (((input >> (4 + i * 4)) & 0xf) == 0) + extern_input = 0; + } + state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + msp_set_scart(client, sc_in, 0); + msp_set_scart(client, sc1_out, 1); + msp_set_scart(client, sc2_out, 2); + msp_set_audmode(client); + reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb; + val = msp_read_dem(client, reg); + msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8)); + /* wake thread when a new input is chosen */ + msp_wake_thread(client); + return 0; +} + +static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (state->radio) + return 0; + if (state->opmode == OPMODE_AUTOSELECT) + msp_detect_stereo(client); + vt->audmode = state->audmode; + vt->rxsubchans = state->rxsubchans; + vt->capability |= V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + return 0; +} + +static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (state->radio) /* TODO: add mono/stereo support for radio */ + return 0; + if (state->audmode == vt->audmode) + return 0; + state->audmode = vt->audmode; + /* only set audmode */ + msp_set_audmode(client); + return 0; +} + +static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq); + + switch (freq) { + case 1024000: + state->i2s_mode = 0; + break; + case 2048000: + state->i2s_mode = 1; + break; + default: + return -EINVAL; + } + return 0; +} + +static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, state->ident, + (state->rev1 << 16) | state->rev2); +} + +static int msp_log_status(struct v4l2_subdev *sd) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + const char *p; + char prefix[V4L2_SUBDEV_NAME_SIZE + 20]; + + if (state->opmode == OPMODE_AUTOSELECT) + msp_detect_stereo(client); + v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", + client->name, state->rev1, state->rev2); + snprintf(prefix, sizeof(prefix), "%s: Audio: ", sd->name); + v4l2_ctrl_handler_log_status(&state->hdl, prefix); + switch (state->mode) { + case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; + case MSP_MODE_FM_RADIO: p = "FM Radio"; break; + case MSP_MODE_FM_TERRA: p = "Terrestrial FM-mono/stereo"; break; + case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; + case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; + case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; + case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break; + case MSP_MODE_BTSC: p = "BTSC"; break; + case MSP_MODE_EXTERN: p = "External input"; break; + default: p = "unknown"; break; + } + if (state->mode == MSP_MODE_EXTERN) { + v4l_info(client, "Mode: %s\n", p); + } else if (state->opmode == OPMODE_MANUAL) { + v4l_info(client, "Mode: %s (%s%s)\n", p, + (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", + (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); + } else { + if (state->opmode == OPMODE_AUTODETECT) + v4l_info(client, "Mode: %s\n", p); + v4l_info(client, "Standard: %s (%s%s)\n", + msp_standard_std_name(state->std), + (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", + (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); + } + v4l_info(client, "Audmode: 0x%04x\n", state->audmode); + v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", + state->route_in, state->route_out); + v4l_info(client, "ACB: 0x%04x\n", state->acb); + return 0; +} + +static int msp_suspend(struct i2c_client *client, pm_message_t state) +{ + v4l_dbg(1, msp_debug, client, "suspend\n"); + msp_reset(client); + return 0; +} + +static int msp_resume(struct i2c_client *client) +{ + v4l_dbg(1, msp_debug, client, "resume\n"); + msp_wake_thread(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_ctrl_ops msp_ctrl_ops = { + .s_ctrl = msp_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops msp_core_ops = { + .log_status = msp_log_status, + .g_chip_ident = msp_g_chip_ident, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, + .s_std = msp_s_std, +}; + +static const struct v4l2_subdev_tuner_ops msp_tuner_ops = { + .s_frequency = msp_s_frequency, + .g_tuner = msp_g_tuner, + .s_tuner = msp_s_tuner, + .s_radio = msp_s_radio, +}; + +static const struct v4l2_subdev_audio_ops msp_audio_ops = { + .s_routing = msp_s_routing, + .s_i2s_clock_freq = msp_s_i2s_clock_freq, +}; + +static const struct v4l2_subdev_ops msp_ops = { + .core = &msp_core_ops, + .tuner = &msp_tuner_ops, + .audio = &msp_audio_ops, +}; + +/* ----------------------------------------------------------------------- */ + +static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct msp_state *state; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *hdl; + int (*thread_func)(void *data) = NULL; + int msp_hard; + int msp_family; + int msp_revision; + int msp_product, msp_prod_hi, msp_prod_lo; + int msp_rom; + + if (!id) + strlcpy(client->name, "msp3400", sizeof(client->name)); + + if (msp_reset(client) == -1) { + v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); + return -ENODEV; + } + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &msp_ops); + + state->v4l2_std = V4L2_STD_NTSC; + state->audmode = V4L2_TUNER_MODE_STEREO; + state->input = -1; + state->i2s_mode = 0; + init_waitqueue_head(&state->wq); + /* These are the reset input/output positions */ + state->route_in = MSP_INPUT_DEFAULT; + state->route_out = MSP_OUTPUT_DEFAULT; + + state->rev1 = msp_read_dsp(client, 0x1e); + if (state->rev1 != -1) + state->rev2 = msp_read_dsp(client, 0x1f); + v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", + state->rev1, state->rev2); + if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { + v4l_dbg(1, msp_debug, client, + "not an msp3400 (cannot read chip version)\n"); + kfree(state); + return -ENODEV; + } + + msp_family = ((state->rev1 >> 4) & 0x0f) + 3; + msp_product = (state->rev2 >> 8) & 0xff; + msp_prod_hi = msp_product / 10; + msp_prod_lo = msp_product % 10; + msp_revision = (state->rev1 & 0x0f) + '@'; + msp_hard = ((state->rev1 >> 8) & 0xff) + '@'; + msp_rom = state->rev2 & 0x1f; + /* Rev B=2, C=3, D=4, G=7 */ + state->ident = msp_family * 10000 + 4000 + msp_product * 10 + + msp_revision - '@'; + + /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ + state->has_nicam = + msp_prod_hi == 1 || msp_prod_hi == 5; + /* Has radio support: was added with revision G */ + state->has_radio = + msp_revision >= 'G'; + /* Has headphones output: not for stripped down products */ + state->has_headphones = + msp_prod_lo < 5; + /* Has scart2 input: not in stripped down products of the '3' family */ + state->has_scart2 = + msp_family >= 4 || msp_prod_lo < 7; + /* Has scart3 input: not in stripped down products of the '3' family */ + state->has_scart3 = + msp_family >= 4 || msp_prod_lo < 5; + /* Has scart4 input: not in pre D revisions, not in stripped D revs */ + state->has_scart4 = + msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); + /* Has scart2 output: not in stripped down products of + * the '3' family */ + state->has_scart2_out = + msp_family >= 4 || msp_prod_lo < 5; + /* Has scart2 a volume control? Not in pre-D revisions. */ + state->has_scart2_out_volume = + msp_revision > 'C' && state->has_scart2_out; + /* Has a configurable i2s out? */ + state->has_i2s_conf = + msp_revision >= 'G' && msp_prod_lo < 7; + /* Has subwoofer output: not in pre-D revs and not in stripped down + * products */ + state->has_subwoofer = + msp_revision >= 'D' && msp_prod_lo < 5; + /* Has soundprocessing (bass/treble/balance/loudness/equalizer): + * not in stripped down products */ + state->has_sound_processing = + msp_prod_lo < 7; + /* Has Virtual Dolby Surround: only in msp34x1 */ + state->has_virtual_dolby_surround = + msp_revision == 'G' && msp_prod_lo == 1; + /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */ + state->has_dolby_pro_logic = + msp_revision == 'G' && msp_prod_lo == 2; + /* The msp343xG supports BTSC only and cannot do Automatic Standard + * Detection. */ + state->force_btsc = + msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; + + state->opmode = opmode; + if (state->opmode == OPMODE_AUTO) { + /* MSP revision G and up have both autodetect and autoselect */ + if (msp_revision >= 'G') + state->opmode = OPMODE_AUTOSELECT; + /* MSP revision D and up have autodetect */ + else if (msp_revision >= 'D') + state->opmode = OPMODE_AUTODETECT; + else + state->opmode = OPMODE_MANUAL; + } + + hdl = &state->hdl; + v4l2_ctrl_handler_init(hdl, 6); + if (state->has_sound_processing) { + v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, + V4L2_CID_AUDIO_BASS, 0, 65535, 65535 / 100, 32768); + v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, + V4L2_CID_AUDIO_TREBLE, 0, 65535, 65535 / 100, 32768); + v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, + V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 0); + } + state->volume = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 58880); + v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, + V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768); + state->muted = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + sd->ctrl_handler = hdl; + if (hdl->error) { + int err = hdl->error; + + v4l2_ctrl_handler_free(hdl); + kfree(state); + return err; + } + + v4l2_ctrl_cluster(2, &state->volume); + v4l2_ctrl_handler_setup(hdl); + + /* hello world :-) */ + v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n", + msp_family, msp_product, + msp_revision, msp_hard, msp_rom, + client->addr << 1, client->adapter->name); + v4l_info(client, "%s ", client->name); + if (state->has_nicam && state->has_radio) + printk(KERN_CONT "supports nicam and radio, "); + else if (state->has_nicam) + printk(KERN_CONT "supports nicam, "); + else if (state->has_radio) + printk(KERN_CONT "supports radio, "); + printk(KERN_CONT "mode is "); + + /* version-specific initialization */ + switch (state->opmode) { + case OPMODE_MANUAL: + printk(KERN_CONT "manual"); + thread_func = msp3400c_thread; + break; + case OPMODE_AUTODETECT: + printk(KERN_CONT "autodetect"); + thread_func = msp3410d_thread; + break; + case OPMODE_AUTOSELECT: + printk(KERN_CONT "autodetect and autoselect"); + thread_func = msp34xxg_thread; + break; + } + printk(KERN_CONT "\n"); + + /* startup control thread if needed */ + if (thread_func) { + state->kthread = kthread_run(thread_func, client, "msp34xx"); + + if (IS_ERR(state->kthread)) + v4l_warn(client, "kernel_thread() failed\n"); + msp_wake_thread(client); + } + return 0; +} + +static int msp_remove(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + v4l2_device_unregister_subdev(&state->sd); + /* shutdown control thread */ + if (state->kthread) { + state->restart = 1; + kthread_stop(state->kthread); + } + msp_reset(client); + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id msp_id[] = { + { "msp3400", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, msp_id); + +static struct i2c_driver msp_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "msp3400", + }, + .probe = msp_probe, + .remove = msp_remove, + .suspend = msp_suspend, + .resume = msp_resume, + .id_table = msp_id, +}; + +static __init int init_msp(void) +{ + return i2c_add_driver(&msp_driver); +} + +static __exit void exit_msp(void) +{ + i2c_del_driver(&msp_driver); +} + +module_init(init_msp); +module_exit(exit_msp); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-driver.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-driver.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-driver.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-driver.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,137 @@ +/* + */ + +#ifndef MSP3400_DRIVER_H +#define MSP3400_DRIVER_H + +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +/* This macro is allowed for *constants* only, gcc must calculate it + at compile time. Remember -- no floats in kernel mode */ +#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24))) + +#define MSP_MODE_AM_DETECT 0 +#define MSP_MODE_FM_RADIO 2 +#define MSP_MODE_FM_TERRA 3 +#define MSP_MODE_FM_SAT 4 +#define MSP_MODE_FM_NICAM1 5 +#define MSP_MODE_FM_NICAM2 6 +#define MSP_MODE_AM_NICAM 7 +#define MSP_MODE_BTSC 8 +#define MSP_MODE_EXTERN 9 + +#define SCART_IN1 0 +#define SCART_IN2 1 +#define SCART_IN3 2 +#define SCART_IN4 3 +#define SCART_IN1_DA 4 +#define SCART_IN2_DA 5 +#define SCART_MONO 6 +#define SCART_MUTE 7 + +#define SCART_DSP_IN 0 +#define SCART1_OUT 1 +#define SCART2_OUT 2 + +#define OPMODE_AUTO -1 +#define OPMODE_MANUAL 0 +#define OPMODE_AUTODETECT 1 /* use autodetect (>= msp3410 only) */ +#define OPMODE_AUTOSELECT 2 /* use autodetect & autoselect (>= msp34xxG) */ + +/* module parameters */ +extern int msp_debug; +extern int msp_once; +extern int msp_amsound; +extern int msp_standard; +extern int msp_dolby; +extern int msp_stereo_thresh; + +struct msp_state { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + int rev1, rev2; + int ident; + u8 has_nicam; + u8 has_radio; + u8 has_headphones; + u8 has_ntsc_jp_d_k3; + u8 has_scart2; + u8 has_scart3; + u8 has_scart4; + u8 has_scart2_out; + u8 has_scart2_out_volume; + u8 has_i2s_conf; + u8 has_subwoofer; + u8 has_sound_processing; + u8 has_virtual_dolby_surround; + u8 has_dolby_pro_logic; + u8 force_btsc; + + int radio; + int opmode; + int std; + int mode; + v4l2_std_id v4l2_std; + int nicam_on; + int acb; + int in_scart; + int i2s_mode; + int main, second; /* sound carrier */ + int input; + u32 route_in; + u32 route_out; + + /* v4l2 */ + int audmode; + int rxsubchans; + + struct { + /* volume cluster */ + struct v4l2_ctrl *volume; + struct v4l2_ctrl *muted; + }; + + int scan_in_progress; + + /* thread */ + struct task_struct *kthread; + wait_queue_head_t wq; + unsigned int restart:1; + unsigned int watch_stereo:1; +}; + +static inline struct msp_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct msp_state, sd); +} + +static inline struct msp_state *ctrl_to_state(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct msp_state, hdl); +} + +/* msp3400-driver.c */ +int msp_write_dem(struct i2c_client *client, int addr, int val); +int msp_write_dsp(struct i2c_client *client, int addr, int val); +int msp_read_dem(struct i2c_client *client, int addr); +int msp_read_dsp(struct i2c_client *client, int addr); +int msp_reset(struct i2c_client *client); +void msp_set_scart(struct i2c_client *client, int in, int out); +void msp_update_volume(struct msp_state *state); +int msp_sleep(struct msp_state *state, int timeout); + +/* msp3400-kthreads.c */ +const char *msp_standard_std_name(int std); +void msp_set_audmode(struct i2c_client *client); +int msp_detect_stereo(struct i2c_client *client); +int msp3400c_thread(void *data); +int msp3410d_thread(void *data); +int msp34xxg_thread(void *data); +void msp3400c_set_mode(struct i2c_client *client, int mode); +void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2); + +#endif /* MSP3400_DRIVER_H */ diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-kthreads.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-kthreads.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-kthreads.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/msp3400-kthreads.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1123 @@ +/* + * Programming the mspx4xx sound processor family + * + * (c) 1997-2001 Gerd Knorr + * + * 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, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msp3400-driver.h" + +/* this one uses the automatic sound standard detection of newer msp34xx + chip versions */ +static struct { + int retval; + int main, second; + char *name; +} msp_stdlist[] = { + { 0x0000, 0, 0, "could not detect sound standard" }, + { 0x0001, 0, 0, "autodetect start" }, + { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, + { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, + { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, + { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, + { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, + { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), "6.5/5.74 D/K3 Dual FM-Stereo" }, + { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, + { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, + { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, + { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, + { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, + { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV3)" }, + { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, + { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, + { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, + { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, + { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, + { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, + { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, + { -1, 0, 0, NULL }, /* EOF */ +}; + +static struct msp3400c_init_data_dem { + int fir1[6]; + int fir2[6]; + int cdo1; + int cdo2; + int ad_cv; + int mode_reg; + int dsp_src; + int dsp_matrix; +} msp3400c_init_data[] = { + { /* AM (for carrier detect / msp3400) */ + {75, 19, 36, 35, 39, 40}, + {75, 19, 36, 35, 39, 40}, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0500, 0x0020, 0x3000 + }, { /* AM (for carrier detect / msp3410) */ + {-1, -1, -8, 2, 59, 126}, + {-1, -1, -8, 2, 59, 126}, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0100, 0x0020, 0x3000 + }, { /* FM Radio */ + {-8, -8, 4, 6, 78, 107}, + {-8, -8, 4, 6, 78, 107}, + MSP_CARRIER(10.7), MSP_CARRIER(10.7), + 0x00d0, 0x0480, 0x0020, 0x3000 + }, { /* Terrestrial FM-mono + FM-stereo */ + {3, 18, 27, 48, 66, 72}, + {3, 18, 27, 48, 66, 72}, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0480, 0x0030, 0x3000 + }, { /* Sat FM-mono */ + { 1, 9, 14, 24, 33, 37}, + { 3, 18, 27, 48, 66, 72}, + MSP_CARRIER(6.5), MSP_CARRIER(6.5), + 0x00c6, 0x0480, 0x0000, 0x3000 + }, { /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ + {-2, -8, -10, 10, 50, 86}, + {3, 18, 27, 48, 66, 72}, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0040, 0x0120, 0x3000 + }, { /* NICAM/FM -- I (6.0/6.552) */ + {2, 4, -6, -4, 40, 94}, + {3, 18, 27, 48, 66, 72}, + MSP_CARRIER(6.0), MSP_CARRIER(6.0), + 0x00d0, 0x0040, 0x0120, 0x3000 + }, { /* NICAM/AM -- L (6.5/5.85) */ + {-2, -8, -10, 10, 50, 86}, + {-4, -12, -9, 23, 79, 126}, + MSP_CARRIER(6.5), MSP_CARRIER(6.5), + 0x00c6, 0x0140, 0x0120, 0x7c00 + }, +}; + +struct msp3400c_carrier_detect { + int cdo; + char *name; +}; + +static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = { + /* main carrier */ + { MSP_CARRIER(4.5), "4.5 NTSC" }, + { MSP_CARRIER(5.5), "5.5 PAL B/G" }, + { MSP_CARRIER(6.0), "6.0 PAL I" }, + { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } +}; + +static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = { + /* PAL B/G */ + { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, + { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } +}; + +static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = { + /* PAL SAT / SECAM */ + { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, + { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, + { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, + { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, + { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, + { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, +}; + +/* ------------------------------------------------------------------------ */ + +const char *msp_standard_std_name(int std) +{ + int i; + + for (i = 0; msp_stdlist[i].name != NULL; i++) + if (msp_stdlist[i].retval == std) + return msp_stdlist[i].name; + return "unknown"; +} + +static void msp_set_source(struct i2c_client *client, u16 src) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + if (msp_dolby) { + msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */ + msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */ + } else { + msp_write_dsp(client, 0x0008, src); + msp_write_dsp(client, 0x0009, src); + } + msp_write_dsp(client, 0x000a, src); + msp_write_dsp(client, 0x000b, src); + msp_write_dsp(client, 0x000c, src); + if (state->has_scart2_out) + msp_write_dsp(client, 0x0041, src); +} + +void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2) +{ + msp_write_dem(client, 0x0093, cdo1 & 0xfff); + msp_write_dem(client, 0x009b, cdo1 >> 12); + msp_write_dem(client, 0x00a3, cdo2 & 0xfff); + msp_write_dem(client, 0x00ab, cdo2 >> 12); + msp_write_dem(client, 0x0056, 0); /* LOAD_REG_1/2 */ +} + +void msp3400c_set_mode(struct i2c_client *client, int mode) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode]; + int tuner = (state->route_in >> 3) & 1; + int i; + + v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode); + state->mode = mode; + state->rxsubchans = V4L2_TUNER_SUB_MONO; + + msp_write_dem(client, 0x00bb, data->ad_cv | (tuner ? 0x100 : 0)); + + for (i = 5; i >= 0; i--) /* fir 1 */ + msp_write_dem(client, 0x0001, data->fir1[i]); + + msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */ + msp_write_dem(client, 0x0005, 0x0040); + msp_write_dem(client, 0x0005, 0x0000); + for (i = 5; i >= 0; i--) + msp_write_dem(client, 0x0005, data->fir2[i]); + + msp_write_dem(client, 0x0083, data->mode_reg); + + msp3400c_set_carrier(client, data->cdo1, data->cdo2); + + msp_set_source(client, data->dsp_src); + /* set prescales */ + + /* volume prescale for SCART (AM mono input) */ + msp_write_dsp(client, 0x000d, 0x1900); + msp_write_dsp(client, 0x000e, data->dsp_matrix); + if (state->has_nicam) /* nicam prescale */ + msp_write_dsp(client, 0x0010, 0x5a00); +} + +/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP, + nor do they support stereo BTSC. */ +static void msp3400c_set_audmode(struct i2c_client *client) +{ + static char *strmode[] = { + "mono", "stereo", "lang2", "lang1", "lang1+lang2" + }; + struct msp_state *state = to_state(i2c_get_clientdata(client)); + char *modestr = (state->audmode >= 0 && state->audmode < 5) ? + strmode[state->audmode] : "unknown"; + int src = 0; /* channel source: FM/AM, nicam or SCART */ + int audmode = state->audmode; + + if (state->opmode == OPMODE_AUTOSELECT) { + /* this method would break everything, let's make sure + * it's never called + */ + v4l_dbg(1, msp_debug, client, + "set_audmode called with mode=%d instead of set_source (ignored)\n", + state->audmode); + return; + } + + /* Note: for the C and D revs no NTSC stereo + SAP is possible as + the hardware does not support SAP. So the rxsubchans combination + of STEREO | LANG2 does not occur. */ + + if (state->mode != MSP_MODE_EXTERN) { + /* switch to mono if only mono is available */ + if (state->rxsubchans == V4L2_TUNER_SUB_MONO) + audmode = V4L2_TUNER_MODE_MONO; + /* if bilingual */ + else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) { + /* and mono or stereo, then fallback to lang1 */ + if (audmode == V4L2_TUNER_MODE_MONO || + audmode == V4L2_TUNER_MODE_STEREO) + audmode = V4L2_TUNER_MODE_LANG1; + } + /* if stereo, and audmode is not mono, then switch to stereo */ + else if (audmode != V4L2_TUNER_MODE_MONO) + audmode = V4L2_TUNER_MODE_STEREO; + } + + /* switch demodulator */ + switch (state->mode) { + case MSP_MODE_FM_TERRA: + v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr); + switch (audmode) { + case V4L2_TUNER_MODE_STEREO: + msp_write_dsp(client, 0x000e, 0x3001); + break; + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + case V4L2_TUNER_MODE_LANG2: + case V4L2_TUNER_MODE_LANG1_LANG2: + msp_write_dsp(client, 0x000e, 0x3000); + break; + } + break; + case MSP_MODE_FM_SAT: + v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr); + switch (audmode) { + case V4L2_TUNER_MODE_MONO: + msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); + break; + case V4L2_TUNER_MODE_LANG1: + msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + break; + case V4L2_TUNER_MODE_LANG2: + msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + break; + } + break; + case MSP_MODE_FM_NICAM1: + case MSP_MODE_FM_NICAM2: + case MSP_MODE_AM_NICAM: + v4l_dbg(1, msp_debug, client, + "NICAM set_audmode: %s\n", modestr); + if (state->nicam_on) + src = 0x0100; /* NICAM */ + break; + case MSP_MODE_BTSC: + v4l_dbg(1, msp_debug, client, + "BTSC set_audmode: %s\n", modestr); + break; + case MSP_MODE_EXTERN: + v4l_dbg(1, msp_debug, client, + "extern set_audmode: %s\n", modestr); + src = 0x0200; /* SCART */ + break; + case MSP_MODE_FM_RADIO: + v4l_dbg(1, msp_debug, client, + "FM-Radio set_audmode: %s\n", modestr); + break; + default: + v4l_dbg(1, msp_debug, client, "mono set_audmode\n"); + return; + } + + /* switch audio */ + v4l_dbg(1, msp_debug, client, "set audmode %d\n", audmode); + switch (audmode) { + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + src |= 0x0020; + break; + case V4L2_TUNER_MODE_MONO: + if (state->mode == MSP_MODE_AM_NICAM) { + v4l_dbg(1, msp_debug, client, "switching to AM mono\n"); + /* AM mono decoding is handled by tuner, not MSP chip */ + /* SCART switching control register */ + msp_set_scart(client, SCART_MONO, 0); + src = 0x0200; + break; + } + if (state->rxsubchans & V4L2_TUNER_SUB_STEREO) + src = 0x0030; + break; + case V4L2_TUNER_MODE_LANG1: + break; + case V4L2_TUNER_MODE_LANG2: + src |= 0x0010; + break; + } + v4l_dbg(1, msp_debug, client, + "set_audmode final source/matrix = 0x%x\n", src); + + msp_set_source(client, src); +} + +static void msp3400c_print_mode(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + if (state->main == state->second) + v4l_dbg(1, msp_debug, client, + "mono sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); + else + v4l_dbg(1, msp_debug, client, + "main sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); + if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) + v4l_dbg(1, msp_debug, client, + "NICAM/FM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second/910) % 1000); + if (state->mode == MSP_MODE_AM_NICAM) + v4l_dbg(1, msp_debug, client, + "NICAM/AM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); + if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) { + v4l_dbg(1, msp_debug, client, + "FM-stereo carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); + } +} + +/* ----------------------------------------------------------------------- */ + +static int msp3400c_detect_stereo(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + int val; + int rxsubchans = state->rxsubchans; + int newnicam = state->nicam_on; + int update = 0; + + switch (state->mode) { + case MSP_MODE_FM_TERRA: + val = msp_read_dsp(client, 0x18); + if (val > 32767) + val -= 65536; + v4l_dbg(2, msp_debug, client, + "stereo detect register: %d\n", val); + if (val > 8192) { + rxsubchans = V4L2_TUNER_SUB_STEREO; + } else if (val < -4096) { + rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + } else { + rxsubchans = V4L2_TUNER_SUB_MONO; + } + newnicam = 0; + break; + case MSP_MODE_FM_NICAM1: + case MSP_MODE_FM_NICAM2: + case MSP_MODE_AM_NICAM: + val = msp_read_dem(client, 0x23); + v4l_dbg(2, msp_debug, client, "nicam sync=%d, mode=%d\n", + val & 1, (val & 0x1e) >> 1); + + if (val & 1) { + /* nicam synced */ + switch ((val & 0x1e) >> 1) { + case 0: + case 8: + rxsubchans = V4L2_TUNER_SUB_STEREO; + break; + case 1: + case 9: + rxsubchans = V4L2_TUNER_SUB_MONO; + break; + case 2: + case 10: + rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + default: + rxsubchans = V4L2_TUNER_SUB_MONO; + break; + } + newnicam = 1; + } else { + newnicam = 0; + rxsubchans = V4L2_TUNER_SUB_MONO; + } + break; + } + if (rxsubchans != state->rxsubchans) { + update = 1; + v4l_dbg(1, msp_debug, client, + "watch: rxsubchans %02x => %02x\n", + state->rxsubchans, rxsubchans); + state->rxsubchans = rxsubchans; + } + if (newnicam != state->nicam_on) { + update = 1; + v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n", + state->nicam_on, newnicam); + state->nicam_on = newnicam; + } + return update; +} + +/* + * A kernel thread for msp3400 control -- we don't want to block the + * in the ioctl while doing the sound carrier & stereo detect + */ +/* stereo/multilang monitoring */ +static void watch_stereo(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + if (msp_detect_stereo(client)) + msp_set_audmode(client); + + if (msp_once) + state->watch_stereo = 0; +} + +int msp3400c_thread(void *data) +{ + struct i2c_client *client = data; + struct msp_state *state = to_state(i2c_get_clientdata(client)); + struct msp3400c_carrier_detect *cd; + int count, max1, max2, val1, val2, val, i; + + v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); + set_freezable(); + for (;;) { + v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n"); + msp_sleep(state, -1); + v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n"); + +restart: + v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); + state->restart = 0; + if (kthread_should_stop()) + break; + + if (state->radio || MSP_MODE_EXTERN == state->mode) { + /* no carrier scan, just unmute */ + v4l_dbg(1, msp_debug, client, + "thread: no carrier scan\n"); + state->scan_in_progress = 0; + msp_update_volume(state); + continue; + } + + /* mute audio */ + state->scan_in_progress = 1; + msp_update_volume(state); + + msp3400c_set_mode(client, MSP_MODE_AM_DETECT); + val1 = val2 = 0; + max1 = max2 = -1; + state->watch_stereo = 0; + state->nicam_on = 0; + + /* wait for tuner to settle down after a channel change */ + if (msp_sleep(state, 200)) + goto restart; + + /* carrier detect pass #1 -- main carrier */ + cd = msp3400c_carrier_detect_main; + count = ARRAY_SIZE(msp3400c_carrier_detect_main); + + if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) { + /* autodetect doesn't work well with AM ... */ + max1 = 3; + count = 0; + v4l_dbg(1, msp_debug, client, "AM sound override\n"); + } + + for (i = 0; i < count; i++) { + msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); + if (msp_sleep(state, 100)) + goto restart; + val = msp_read_dsp(client, 0x1b); + if (val > 32767) + val -= 65536; + if (val1 < val) + val1 = val, max1 = i; + v4l_dbg(1, msp_debug, client, + "carrier1 val: %5d / %s\n", val, cd[i].name); + } + + /* carrier detect pass #2 -- second (stereo) carrier */ + switch (max1) { + case 1: /* 5.5 */ + cd = msp3400c_carrier_detect_55; + count = ARRAY_SIZE(msp3400c_carrier_detect_55); + break; + case 3: /* 6.5 */ + cd = msp3400c_carrier_detect_65; + count = ARRAY_SIZE(msp3400c_carrier_detect_65); + break; + case 0: /* 4.5 */ + case 2: /* 6.0 */ + default: + cd = NULL; + count = 0; + break; + } + + if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) { + /* autodetect doesn't work well with AM ... */ + cd = NULL; + count = 0; + max2 = 0; + } + for (i = 0; i < count; i++) { + msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); + if (msp_sleep(state, 100)) + goto restart; + val = msp_read_dsp(client, 0x1b); + if (val > 32767) + val -= 65536; + if (val2 < val) + val2 = val, max2 = i; + v4l_dbg(1, msp_debug, client, + "carrier2 val: %5d / %s\n", val, cd[i].name); + } + + /* program the msp3400 according to the results */ + state->main = msp3400c_carrier_detect_main[max1].cdo; + switch (max1) { + case 1: /* 5.5 */ + if (max2 == 0) { + /* B/G FM-stereo */ + state->second = msp3400c_carrier_detect_55[max2].cdo; + msp3400c_set_mode(client, MSP_MODE_FM_TERRA); + state->watch_stereo = 1; + } else if (max2 == 1 && state->has_nicam) { + /* B/G NICAM */ + state->second = msp3400c_carrier_detect_55[max2].cdo; + msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); + state->nicam_on = 1; + state->watch_stereo = 1; + } else { + goto no_second; + } + break; + case 2: /* 6.0 */ + /* PAL I NICAM */ + state->second = MSP_CARRIER(6.552); + msp3400c_set_mode(client, MSP_MODE_FM_NICAM2); + state->nicam_on = 1; + state->watch_stereo = 1; + break; + case 3: /* 6.5 */ + if (max2 == 1 || max2 == 2) { + /* D/K FM-stereo */ + state->second = msp3400c_carrier_detect_65[max2].cdo; + msp3400c_set_mode(client, MSP_MODE_FM_TERRA); + state->watch_stereo = 1; + } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) { + /* L NICAM or AM-mono */ + state->second = msp3400c_carrier_detect_65[max2].cdo; + msp3400c_set_mode(client, MSP_MODE_AM_NICAM); + state->watch_stereo = 1; + } else if (max2 == 0 && state->has_nicam) { + /* D/K NICAM */ + state->second = msp3400c_carrier_detect_65[max2].cdo; + msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); + state->nicam_on = 1; + state->watch_stereo = 1; + } else { + goto no_second; + } + break; + case 0: /* 4.5 */ + default: +no_second: + state->second = msp3400c_carrier_detect_main[max1].cdo; + msp3400c_set_mode(client, MSP_MODE_FM_TERRA); + break; + } + msp3400c_set_carrier(client, state->second, state->main); + + /* unmute */ + state->scan_in_progress = 0; + msp3400c_set_audmode(client); + msp_update_volume(state); + + if (msp_debug) + msp3400c_print_mode(client); + + /* monitor tv audio mode, the first time don't wait + so long to get a quick stereo/bilingual result */ + count = 3; + while (state->watch_stereo) { + if (msp_sleep(state, count ? 1000 : 5000)) + goto restart; + if (count) + count--; + watch_stereo(client); + } + } + v4l_dbg(1, msp_debug, client, "thread: exit\n"); + return 0; +} + + +int msp3410d_thread(void *data) +{ + struct i2c_client *client = data; + struct msp_state *state = to_state(i2c_get_clientdata(client)); + int val, i, std, count; + + v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); + set_freezable(); + for (;;) { + v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); + msp_sleep(state, -1); + v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n"); + +restart: + v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); + state->restart = 0; + if (kthread_should_stop()) + break; + + if (state->mode == MSP_MODE_EXTERN) { + /* no carrier scan needed, just unmute */ + v4l_dbg(1, msp_debug, client, + "thread: no carrier scan\n"); + state->scan_in_progress = 0; + msp_update_volume(state); + continue; + } + + /* mute audio */ + state->scan_in_progress = 1; + msp_update_volume(state); + + /* start autodetect. Note: autodetect is not supported for + NTSC-M and radio, hence we force the standard in those + cases. */ + if (state->radio) + std = 0x40; + else + std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1; + state->watch_stereo = 0; + state->nicam_on = 0; + + /* wait for tuner to settle down after a channel change */ + if (msp_sleep(state, 200)) + goto restart; + + if (msp_debug) + v4l_dbg(2, msp_debug, client, + "setting standard: %s (0x%04x)\n", + msp_standard_std_name(std), std); + + if (std != 1) { + /* programmed some specific mode */ + val = std; + } else { + /* triggered autodetect */ + msp_write_dem(client, 0x20, std); + for (;;) { + if (msp_sleep(state, 100)) + goto restart; + + /* check results */ + val = msp_read_dem(client, 0x7e); + if (val < 0x07ff) + break; + v4l_dbg(2, msp_debug, client, + "detection still in progress\n"); + } + } + for (i = 0; msp_stdlist[i].name != NULL; i++) + if (msp_stdlist[i].retval == val) + break; + v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n", + msp_standard_std_name(val), val); + state->main = msp_stdlist[i].main; + state->second = msp_stdlist[i].second; + state->std = val; + state->rxsubchans = V4L2_TUNER_SUB_MONO; + + if (msp_amsound && !state->radio && + (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) { + /* autodetection has failed, let backup */ + v4l_dbg(1, msp_debug, client, "autodetection failed," + " switching to backup standard: %s (0x%04x)\n", + msp_stdlist[8].name ? + msp_stdlist[8].name : "unknown", val); + state->std = val = 0x0009; + msp_write_dem(client, 0x20, val); + } + + /* set stereo */ + switch (val) { + case 0x0008: /* B/G NICAM */ + case 0x000a: /* I NICAM */ + case 0x000b: /* D/K NICAM */ + if (val == 0x000a) + state->mode = MSP_MODE_FM_NICAM2; + else + state->mode = MSP_MODE_FM_NICAM1; + /* just turn on stereo */ + state->nicam_on = 1; + state->watch_stereo = 1; + break; + case 0x0009: + state->mode = MSP_MODE_AM_NICAM; + state->nicam_on = 1; + state->watch_stereo = 1; + break; + case 0x0020: /* BTSC */ + /* The pre-'G' models only have BTSC-mono */ + state->mode = MSP_MODE_BTSC; + break; + case 0x0040: /* FM radio */ + state->mode = MSP_MODE_FM_RADIO; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + /* not needed in theory if we have radio, but + short programming enables carrier mute */ + msp3400c_set_mode(client, MSP_MODE_FM_RADIO); + msp3400c_set_carrier(client, MSP_CARRIER(10.7), + MSP_CARRIER(10.7)); + break; + case 0x0002: + case 0x0003: + case 0x0004: + case 0x0005: + state->mode = MSP_MODE_FM_TERRA; + state->watch_stereo = 1; + break; + } + + /* set various prescales */ + msp_write_dsp(client, 0x0d, 0x1900); /* scart */ + msp_write_dsp(client, 0x0e, 0x3000); /* FM */ + if (state->has_nicam) + msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ + + if (state->has_i2s_conf) + msp_write_dem(client, 0x40, state->i2s_mode); + + /* unmute */ + msp3400c_set_audmode(client); + state->scan_in_progress = 0; + msp_update_volume(state); + + /* monitor tv audio mode, the first time don't wait + so long to get a quick stereo/bilingual result */ + count = 3; + while (state->watch_stereo) { + if (msp_sleep(state, count ? 1000 : 5000)) + goto restart; + if (count) + count--; + watch_stereo(client); + } + } + v4l_dbg(1, msp_debug, client, "thread: exit\n"); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* msp34xxG + (autoselect no-thread) + * this one uses both automatic standard detection and automatic sound + * select which are available in the newer G versions + * struct msp: only norm, acb and source are really used in this mode + */ + +static int msp34xxg_modus(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + if (state->radio) { + v4l_dbg(1, msp_debug, client, "selected radio modus\n"); + return 0x0001; + } + if (state->v4l2_std == V4L2_STD_NTSC_M_JP) { + v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n"); + return 0x4001; + } + if (state->v4l2_std == V4L2_STD_NTSC_M_KR) { + v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n"); + return 0x0001; + } + if (state->v4l2_std == V4L2_STD_SECAM_L) { + v4l_dbg(1, msp_debug, client, "selected SECAM-L modus\n"); + return 0x6001; + } + if (state->v4l2_std & V4L2_STD_MN) { + v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n"); + return 0x2001; + } + return 0x7001; +} + +static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) + { + struct msp_state *state = to_state(i2c_get_clientdata(client)); + int source, matrix; + + switch (state->audmode) { + case V4L2_TUNER_MODE_MONO: + source = 0; /* mono only */ + matrix = 0x30; + break; + case V4L2_TUNER_MODE_LANG2: + source = 4; /* stereo or B */ + matrix = 0x10; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + source = 1; /* stereo or A|B */ + matrix = 0x20; + break; + case V4L2_TUNER_MODE_LANG1: + source = 3; /* stereo or A */ + matrix = 0x00; + break; + case V4L2_TUNER_MODE_STEREO: + default: + source = 3; /* stereo or A */ + matrix = 0x20; + break; + } + + if (in == MSP_DSP_IN_TUNER) + source = (source << 8) | 0x20; + /* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14 + instead of 11, 12, 13. So we add one for that msp version. */ + else if (in >= MSP_DSP_IN_MAIN_AVC && state->has_dolby_pro_logic) + source = ((in + 1) << 8) | matrix; + else + source = (in << 8) | matrix; + + v4l_dbg(1, msp_debug, client, + "set source to %d (0x%x) for output %02x\n", in, source, reg); + msp_write_dsp(client, reg, source); +} + +static void msp34xxg_set_sources(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + u32 in = state->route_in; + + msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf); + /* quasi-peak detector is set to same input as the loudspeaker (MAIN) */ + msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf); + msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf); + msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf); + if (state->has_scart2_out) + msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf); + msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf); +} + +/* (re-)initialize the msp34xxg */ +static void msp34xxg_reset(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + int tuner = (state->route_in >> 3) & 1; + int modus; + + /* initialize std to 1 (autodetect) to signal that no standard is + selected yet. */ + state->std = 1; + + msp_reset(client); + + if (state->has_i2s_conf) + msp_write_dem(client, 0x40, state->i2s_mode); + + /* step-by-step initialisation, as described in the manual */ + modus = msp34xxg_modus(client); + modus |= tuner ? 0x100 : 0; + msp_write_dem(client, 0x30, modus); + + /* write the dsps that may have an influence on + standard/audio autodetection right now */ + msp34xxg_set_sources(client); + + msp_write_dsp(client, 0x0d, 0x1900); /* scart */ + msp_write_dsp(client, 0x0e, 0x3000); /* FM */ + if (state->has_nicam) + msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ + + /* set identification threshold. Personally, I + * I set it to a higher value than the default + * of 0x190 to ignore noisy stereo signals. + * this needs tuning. (recommended range 0x00a0-0x03c0) + * 0x7f0 = forced mono mode + * + * a2 threshold for stereo/bilingual. + * Note: this register is part of the Manual/Compatibility mode. + * It is supported by all 'G'-family chips. + */ + msp_write_dem(client, 0x22, msp_stereo_thresh); +} + +int msp34xxg_thread(void *data) +{ + struct i2c_client *client = data; + struct msp_state *state = to_state(i2c_get_clientdata(client)); + int val, i; + + v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); + set_freezable(); + for (;;) { + v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n"); + msp_sleep(state, -1); + v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n"); + +restart: + v4l_dbg(1, msp_debug, client, "thread: restart scan\n"); + state->restart = 0; + if (kthread_should_stop()) + break; + + if (state->mode == MSP_MODE_EXTERN) { + /* no carrier scan needed, just unmute */ + v4l_dbg(1, msp_debug, client, + "thread: no carrier scan\n"); + state->scan_in_progress = 0; + msp_update_volume(state); + continue; + } + + /* setup the chip*/ + msp34xxg_reset(client); + state->std = state->radio ? 0x40 : + (state->force_btsc && msp_standard == 1) ? 32 : msp_standard; + msp_write_dem(client, 0x20, state->std); + /* start autodetect */ + if (state->std != 1) + goto unmute; + + /* watch autodetect */ + v4l_dbg(1, msp_debug, client, + "started autodetect, waiting for result\n"); + for (i = 0; i < 10; i++) { + if (msp_sleep(state, 100)) + goto restart; + + /* check results */ + val = msp_read_dem(client, 0x7e); + if (val < 0x07ff) { + state->std = val; + break; + } + v4l_dbg(2, msp_debug, client, + "detection still in progress\n"); + } + if (state->std == 1) { + v4l_dbg(1, msp_debug, client, + "detection still in progress after 10 tries. giving up.\n"); + continue; + } + +unmute: + v4l_dbg(1, msp_debug, client, + "detected standard: %s (0x%04x)\n", + msp_standard_std_name(state->std), state->std); + + if (state->std == 9) { + /* AM NICAM mode */ + msp_write_dsp(client, 0x0e, 0x7c00); + } + + /* unmute: dispatch sound to scart output, set scart volume */ + msp_update_volume(state); + + /* restore ACB */ + if (msp_write_dsp(client, 0x13, state->acb)) + return -1; + + /* the periodic stereo/SAP check is only relevant for + the 0x20 standard (BTSC) */ + if (state->std != 0x20) + continue; + + state->watch_stereo = 1; + + /* monitor tv audio mode, the first time don't wait + in order to get a quick stereo/SAP update */ + watch_stereo(client); + while (state->watch_stereo) { + watch_stereo(client); + if (msp_sleep(state, 5000)) + goto restart; + } + } + v4l_dbg(1, msp_debug, client, "thread: exit\n"); + return 0; +} + +static int msp34xxg_detect_stereo(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + int status = msp_read_dem(client, 0x0200); + int is_bilingual = status & 0x100; + int is_stereo = status & 0x40; + int oldrx = state->rxsubchans; + + if (state->mode == MSP_MODE_EXTERN) + return 0; + + state->rxsubchans = 0; + if (is_stereo) + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + else + state->rxsubchans = V4L2_TUNER_SUB_MONO; + if (is_bilingual) { + if (state->std == 0x20) + state->rxsubchans |= V4L2_TUNER_SUB_SAP; + else + state->rxsubchans = + V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + } + v4l_dbg(1, msp_debug, client, + "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", + status, is_stereo, is_bilingual, state->rxsubchans); + return (oldrx != state->rxsubchans); +} + +static void msp34xxg_set_audmode(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + if (state->std == 0x20) { + if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) && + (state->audmode == V4L2_TUNER_MODE_LANG1_LANG2 || + state->audmode == V4L2_TUNER_MODE_LANG2)) { + msp_write_dem(client, 0x20, 0x21); + } else { + msp_write_dem(client, 0x20, 0x20); + } + } + + msp34xxg_set_sources(client); +} + +void msp_set_audmode(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + switch (state->opmode) { + case OPMODE_MANUAL: + case OPMODE_AUTODETECT: + msp3400c_set_audmode(client); + break; + case OPMODE_AUTOSELECT: + msp34xxg_set_audmode(client); + break; + } +} + +int msp_detect_stereo(struct i2c_client *client) +{ + struct msp_state *state = to_state(i2c_get_clientdata(client)); + + switch (state->opmode) { + case OPMODE_MANUAL: + case OPMODE_AUTODETECT: + return msp3400c_detect_stereo(client); + case OPMODE_AUTOSELECT: + return msp34xxg_detect_stereo(client); + } + return 0; +} + diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9m001.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9m001.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9m001.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9m001.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,836 @@ +/* + * Driver for MT9M001 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include + +/* + * mt9m001 i2c address 0x5d + * The platform has to define ctruct i2c_board_info objects and link to them + * from struct soc_camera_link + */ + +/* mt9m001 selected register addresses */ +#define MT9M001_CHIP_VERSION 0x00 +#define MT9M001_ROW_START 0x01 +#define MT9M001_COLUMN_START 0x02 +#define MT9M001_WINDOW_HEIGHT 0x03 +#define MT9M001_WINDOW_WIDTH 0x04 +#define MT9M001_HORIZONTAL_BLANKING 0x05 +#define MT9M001_VERTICAL_BLANKING 0x06 +#define MT9M001_OUTPUT_CONTROL 0x07 +#define MT9M001_SHUTTER_WIDTH 0x09 +#define MT9M001_FRAME_RESTART 0x0b +#define MT9M001_SHUTTER_DELAY 0x0c +#define MT9M001_RESET 0x0d +#define MT9M001_READ_OPTIONS1 0x1e +#define MT9M001_READ_OPTIONS2 0x20 +#define MT9M001_GLOBAL_GAIN 0x35 +#define MT9M001_CHIP_ENABLE 0xF1 + +#define MT9M001_MAX_WIDTH 1280 +#define MT9M001_MAX_HEIGHT 1024 +#define MT9M001_MIN_WIDTH 48 +#define MT9M001_MIN_HEIGHT 32 +#define MT9M001_COLUMN_SKIP 20 +#define MT9M001_ROW_SKIP 12 + +/* MT9M001 has only one fixed colorspace per pixelcode */ +struct mt9m001_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct mt9m001_datafmt *mt9m001_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct mt9m001_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct mt9m001_datafmt mt9m001_colour_fmts[] = { + /* + * Order important: first natively supported, + * second supported with a GPIO extender + */ + {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, +}; + +static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { + /* Order important - see above */ + {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, +}; + +struct mt9m001 { + struct v4l2_subdev subdev; + struct v4l2_rect rect; /* Sensor window */ + const struct mt9m001_datafmt *fmt; + const struct mt9m001_datafmt *fmts; + int num_fmts; + int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ + unsigned int gain; + unsigned int exposure; + unsigned short y_skip_top; /* Lines to skip at the top */ + unsigned char autoexposure; +}; + +static struct mt9m001 *to_mt9m001(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct mt9m001, subdev); +} + +static int reg_read(struct i2c_client *client, const u8 reg) +{ + s32 data = i2c_smbus_read_word_data(client, reg); + return data < 0 ? data : swab16(data); +} + +static int reg_write(struct i2c_client *client, const u8 reg, + const u16 data) +{ + return i2c_smbus_write_word_data(client, reg, swab16(data)); +} + +static int reg_set(struct i2c_client *client, const u8 reg, + const u16 data) +{ + int ret; + + ret = reg_read(client, reg); + if (ret < 0) + return ret; + return reg_write(client, reg, ret | data); +} + +static int reg_clear(struct i2c_client *client, const u8 reg, + const u16 data) +{ + int ret; + + ret = reg_read(client, reg); + if (ret < 0) + return ret; + return reg_write(client, reg, ret & ~data); +} + +static int mt9m001_init(struct i2c_client *client) +{ + int ret; + + dev_dbg(&client->dev, "%s\n", __func__); + + /* + * We don't know, whether platform provides reset, issue a soft reset + * too. This returns all registers to their default values. + */ + ret = reg_write(client, MT9M001_RESET, 1); + if (!ret) + ret = reg_write(client, MT9M001_RESET, 0); + + /* Disable chip, synchronous option update */ + if (!ret) + ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); + + return ret; +} + +static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* Switch to master "normal" mode or stop sensor readout */ + if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0) + return -EIO; + return 0; +} + +static int mt9m001_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; + + /* Only one width bit may be set */ + if (!is_power_of_2(width_flag)) + return -EINVAL; + + if (icl->set_bus_param) + return icl->set_bus_param(icl, width_flag); + + /* + * Without board specific bus width settings we only support the + * sensors native bus width + */ + if (width_flag == SOCAM_DATAWIDTH_10) + return 0; + + return -EINVAL; +} + +static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + /* MT9M001 has all capture_format parameters fixed */ + unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING | + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER; + + if (icl->query_bus_param) + flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; + else + flags |= SOCAM_DATAWIDTH_10; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + struct v4l2_rect rect = a->c; + struct soc_camera_device *icd = client->dev.platform_data; + int ret; + const u16 hblank = 9, vblank = 25; + unsigned int total_h; + + if (mt9m001->fmts == mt9m001_colour_fmts) + /* + * Bayer format - even number of rows for simplicity, + * but let the user play with the top row. + */ + rect.height = ALIGN(rect.height, 2); + + /* Datasheet requirement: see register description */ + rect.width = ALIGN(rect.width, 2); + rect.left = ALIGN(rect.left, 2); + + soc_camera_limit_side(&rect.left, &rect.width, + MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH); + + soc_camera_limit_side(&rect.top, &rect.height, + MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); + + total_h = rect.height + mt9m001->y_skip_top + vblank; + + /* Blanking and start values - default... */ + ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); + if (!ret) + ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank); + + /* + * The caller provides a supported format, as verified per + * call to icd->try_fmt() + */ + if (!ret) + ret = reg_write(client, MT9M001_COLUMN_START, rect.left); + if (!ret) + ret = reg_write(client, MT9M001_ROW_START, rect.top); + if (!ret) + ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1); + if (!ret) + ret = reg_write(client, MT9M001_WINDOW_HEIGHT, + rect.height + mt9m001->y_skip_top - 1); + if (!ret && mt9m001->autoexposure) { + ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); + if (!ret) { + const struct v4l2_queryctrl *qctrl = + soc_camera_find_qctrl(icd->ops, + V4L2_CID_EXPOSURE); + mt9m001->exposure = (524 + (total_h - 1) * + (qctrl->maximum - qctrl->minimum)) / + 1048 + qctrl->minimum; + } + } + + if (!ret) + mt9m001->rect = rect; + + return ret; +} + +static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + + a->c = mt9m001->rect; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = MT9M001_COLUMN_SKIP; + a->bounds.top = MT9M001_ROW_SKIP; + a->bounds.width = MT9M001_MAX_WIDTH; + a->bounds.height = MT9M001_MAX_HEIGHT; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int mt9m001_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + + mf->width = mt9m001->rect.width; + mf->height = mt9m001->rect.height; + mf->code = mt9m001->fmt->code; + mf->colorspace = mt9m001->fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9m001_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + struct v4l2_crop a = { + .c = { + .left = mt9m001->rect.left, + .top = mt9m001->rect.top, + .width = mf->width, + .height = mf->height, + }, + }; + int ret; + + /* No support for scaling so far, just crop. TODO: use skipping */ + ret = mt9m001_s_crop(sd, &a); + if (!ret) { + mf->width = mt9m001->rect.width; + mf->height = mt9m001->rect.height; + mt9m001->fmt = mt9m001_find_datafmt(mf->code, + mt9m001->fmts, mt9m001->num_fmts); + mf->colorspace = mt9m001->fmt->colorspace; + } + + return ret; +} + +static int mt9m001_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + const struct mt9m001_datafmt *fmt; + + v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH, + MT9M001_MAX_WIDTH, 1, + &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top, + MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0); + + if (mt9m001->fmts == mt9m001_colour_fmts) + mf->height = ALIGN(mf->height - 1, 2); + + fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts, + mt9m001->num_fmts); + if (!fmt) { + fmt = mt9m001->fmt; + mf->code = fmt->code; + } + + mf->colorspace = fmt->colorspace; + + return 0; +} + +static int mt9m001_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = mt9m001->model; + id->revision = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9m001_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + reg->size = 2; + reg->val = reg_read(client, reg->reg); + + if (reg->val > 0xffff) + return -EIO; + + return 0; +} + +static int mt9m001_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + if (reg_write(client, reg->reg, reg->val) < 0) + return -EIO; + + return 0; +} +#endif + +static const struct v4l2_queryctrl mt9m001_controls[] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 64, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 1, + .maximum = 255, + .step = 1, + .default_value = 255, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + } +}; + +static struct soc_camera_ops mt9m001_ops = { + .set_bus_param = mt9m001_set_bus_param, + .query_bus_param = mt9m001_query_bus_param, + .controls = mt9m001_controls, + .num_controls = ARRAY_SIZE(mt9m001_controls), +}; + +static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + int data; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + data = reg_read(client, MT9M001_READ_OPTIONS2); + if (data < 0) + return -EIO; + ctrl->value = !!(data & 0x8000); + break; + case V4L2_CID_EXPOSURE_AUTO: + ctrl->value = mt9m001->autoexposure; + break; + case V4L2_CID_GAIN: + ctrl->value = mt9m001->gain; + break; + case V4L2_CID_EXPOSURE: + ctrl->value = mt9m001->exposure; + break; + } + return 0; +} + +static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + struct soc_camera_device *icd = client->dev.platform_data; + const struct v4l2_queryctrl *qctrl; + int data; + + qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id); + + if (!qctrl) + return -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (ctrl->value) + data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); + else + data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); + if (data < 0) + return -EIO; + break; + case V4L2_CID_GAIN: + if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) + return -EINVAL; + /* See Datasheet Table 7, Gain settings. */ + if (ctrl->value <= qctrl->default_value) { + /* Pack it into 0..1 step 0.125, register values 0..8 */ + unsigned long range = qctrl->default_value - qctrl->minimum; + data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; + + dev_dbg(&client->dev, "Setting gain %d\n", data); + data = reg_write(client, MT9M001_GLOBAL_GAIN, data); + if (data < 0) + return -EIO; + } else { + /* Pack it into 1.125..15 variable step, register values 9..67 */ + /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ + unsigned long range = qctrl->maximum - qctrl->default_value - 1; + unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * + 111 + range / 2) / range + 9; + + if (gain <= 32) + data = gain; + else if (gain <= 64) + data = ((gain - 32) * 16 + 16) / 32 + 80; + else + data = ((gain - 64) * 7 + 28) / 56 + 96; + + dev_dbg(&client->dev, "Setting gain from %d to %d\n", + reg_read(client, MT9M001_GLOBAL_GAIN), data); + data = reg_write(client, MT9M001_GLOBAL_GAIN, data); + if (data < 0) + return -EIO; + } + + /* Success */ + mt9m001->gain = ctrl->value; + break; + case V4L2_CID_EXPOSURE: + /* mt9m001 has maximum == default */ + if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) + return -EINVAL; + else { + unsigned long range = qctrl->maximum - qctrl->minimum; + unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 + + range / 2) / range + 1; + + dev_dbg(&client->dev, + "Setting shutter width from %d to %lu\n", + reg_read(client, MT9M001_SHUTTER_WIDTH), + shutter); + if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) + return -EIO; + mt9m001->exposure = ctrl->value; + mt9m001->autoexposure = 0; + } + break; + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->value) { + const u16 vblank = 25; + unsigned int total_h = mt9m001->rect.height + + mt9m001->y_skip_top + vblank; + if (reg_write(client, MT9M001_SHUTTER_WIDTH, + total_h) < 0) + return -EIO; + qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); + mt9m001->exposure = (524 + (total_h - 1) * + (qctrl->maximum - qctrl->minimum)) / + 1048 + qctrl->minimum; + mt9m001->autoexposure = 1; + } else + mt9m001->autoexposure = 0; + break; + } + return 0; +} + +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ +static int mt9m001_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + struct mt9m001 *mt9m001 = to_mt9m001(client); + struct soc_camera_link *icl = to_soc_camera_link(icd); + s32 data; + unsigned long flags; + int ret; + + /* + * We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. + */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + /* Enable the chip */ + data = reg_write(client, MT9M001_CHIP_ENABLE, 1); + dev_dbg(&client->dev, "write: %d\n", data); + + /* Read out the chip version register */ + data = reg_read(client, MT9M001_CHIP_VERSION); + + /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ + switch (data) { + case 0x8411: + case 0x8421: + mt9m001->model = V4L2_IDENT_MT9M001C12ST; + mt9m001->fmts = mt9m001_colour_fmts; + break; + case 0x8431: + mt9m001->model = V4L2_IDENT_MT9M001C12STM; + mt9m001->fmts = mt9m001_monochrome_fmts; + break; + default: + dev_err(&client->dev, + "No MT9M001 chip detected, register read %x\n", data); + return -ENODEV; + } + + mt9m001->num_fmts = 0; + + /* + * This is a 10bit sensor, so by default we only allow 10bit. + * The platform may support different bus widths due to + * different routing of the data lines. + */ + if (icl->query_bus_param) + flags = icl->query_bus_param(icl); + else + flags = SOCAM_DATAWIDTH_10; + + if (flags & SOCAM_DATAWIDTH_10) + mt9m001->num_fmts++; + else + mt9m001->fmts++; + + if (flags & SOCAM_DATAWIDTH_8) + mt9m001->num_fmts++; + + mt9m001->fmt = &mt9m001->fmts[0]; + + dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, + data == 0x8431 ? "C12STM" : "C12ST"); + + ret = mt9m001_init(client); + if (ret < 0) + dev_err(&client->dev, "Failed to initialise the camera\n"); + + /* mt9m001_init() has reset the chip, returning registers to defaults */ + mt9m001->gain = 64; + mt9m001->exposure = 255; + + return ret; +} + +static void mt9m001_video_remove(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + + dev_dbg(&icd->dev, "Video removed: %p, %p\n", + icd->dev.parent, icd->vdev); + if (icl->free_bus) + icl->free_bus(icl); +} + +static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + + *lines = mt9m001->y_skip_top; + + return 0; +} + +static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { + .g_ctrl = mt9m001_g_ctrl, + .s_ctrl = mt9m001_s_ctrl, + .g_chip_ident = mt9m001_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9m001_g_register, + .s_register = mt9m001_s_register, +#endif +}; + +static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + + if (index >= mt9m001->num_fmts) + return -EINVAL; + + *code = mt9m001->fmts[index].code; + return 0; +} + +static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { + .s_stream = mt9m001_s_stream, + .s_mbus_fmt = mt9m001_s_fmt, + .g_mbus_fmt = mt9m001_g_fmt, + .try_mbus_fmt = mt9m001_try_fmt, + .s_crop = mt9m001_s_crop, + .g_crop = mt9m001_g_crop, + .cropcap = mt9m001_cropcap, + .enum_mbus_fmt = mt9m001_enum_fmt, +}; + +static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { + .g_skip_top_lines = mt9m001_g_skip_top_lines, +}; + +static struct v4l2_subdev_ops mt9m001_subdev_ops = { + .core = &mt9m001_subdev_core_ops, + .video = &mt9m001_subdev_video_ops, + .sensor = &mt9m001_subdev_sensor_ops, +}; + +static int mt9m001_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9m001 *mt9m001; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + if (!icd) { + dev_err(&client->dev, "MT9M001: missing soc-camera data!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "MT9M001 driver needs platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL); + if (!mt9m001) + return -ENOMEM; + + v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &mt9m001_ops; + + mt9m001->y_skip_top = 0; + mt9m001->rect.left = MT9M001_COLUMN_SKIP; + mt9m001->rect.top = MT9M001_ROW_SKIP; + mt9m001->rect.width = MT9M001_MAX_WIDTH; + mt9m001->rect.height = MT9M001_MAX_HEIGHT; + + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ + mt9m001->autoexposure = 1; + + ret = mt9m001_video_probe(icd, client); + if (ret) { + icd->ops = NULL; + kfree(mt9m001); + } + + return ret; +} + +static int mt9m001_remove(struct i2c_client *client) +{ + struct mt9m001 *mt9m001 = to_mt9m001(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + mt9m001_video_remove(icd); + kfree(mt9m001); + + return 0; +} + +static const struct i2c_device_id mt9m001_id[] = { + { "mt9m001", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9m001_id); + +static struct i2c_driver mt9m001_i2c_driver = { + .driver = { + .name = "mt9m001", + }, + .probe = mt9m001_probe, + .remove = mt9m001_remove, + .id_table = mt9m001_id, +}; + +static int __init mt9m001_mod_init(void) +{ + return i2c_add_driver(&mt9m001_i2c_driver); +} + +static void __exit mt9m001_mod_exit(void) +{ + i2c_del_driver(&mt9m001_i2c_driver); +} + +module_init(mt9m001_mod_init); +module_exit(mt9m001_mod_exit); + +MODULE_DESCRIPTION("Micron MT9M001 Camera driver"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9m111.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9m111.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9m111.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9m111.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1140 @@ +/* + * Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina + * + * Copyright (C) 2008, Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * MT9M111, MT9M112 and MT9M131: + * i2c address is 0x48 or 0x5d (depending on SADDR pin) + * The platform has to define i2c_board_info and call i2c_register_board_info() + */ + +/* + * Sensor core register addresses (0x000..0x0ff) + */ +#define MT9M111_CHIP_VERSION 0x000 +#define MT9M111_ROW_START 0x001 +#define MT9M111_COLUMN_START 0x002 +#define MT9M111_WINDOW_HEIGHT 0x003 +#define MT9M111_WINDOW_WIDTH 0x004 +#define MT9M111_HORIZONTAL_BLANKING_B 0x005 +#define MT9M111_VERTICAL_BLANKING_B 0x006 +#define MT9M111_HORIZONTAL_BLANKING_A 0x007 +#define MT9M111_VERTICAL_BLANKING_A 0x008 +#define MT9M111_SHUTTER_WIDTH 0x009 +#define MT9M111_ROW_SPEED 0x00a +#define MT9M111_EXTRA_DELAY 0x00b +#define MT9M111_SHUTTER_DELAY 0x00c +#define MT9M111_RESET 0x00d +#define MT9M111_READ_MODE_B 0x020 +#define MT9M111_READ_MODE_A 0x021 +#define MT9M111_FLASH_CONTROL 0x023 +#define MT9M111_GREEN1_GAIN 0x02b +#define MT9M111_BLUE_GAIN 0x02c +#define MT9M111_RED_GAIN 0x02d +#define MT9M111_GREEN2_GAIN 0x02e +#define MT9M111_GLOBAL_GAIN 0x02f +#define MT9M111_CONTEXT_CONTROL 0x0c8 +#define MT9M111_PAGE_MAP 0x0f0 +#define MT9M111_BYTE_WISE_ADDR 0x0f1 + +#define MT9M111_RESET_SYNC_CHANGES (1 << 15) +#define MT9M111_RESET_RESTART_BAD_FRAME (1 << 9) +#define MT9M111_RESET_SHOW_BAD_FRAMES (1 << 8) +#define MT9M111_RESET_RESET_SOC (1 << 5) +#define MT9M111_RESET_OUTPUT_DISABLE (1 << 4) +#define MT9M111_RESET_CHIP_ENABLE (1 << 3) +#define MT9M111_RESET_ANALOG_STANDBY (1 << 2) +#define MT9M111_RESET_RESTART_FRAME (1 << 1) +#define MT9M111_RESET_RESET_MODE (1 << 0) + +#define MT9M111_RMB_MIRROR_COLS (1 << 1) +#define MT9M111_RMB_MIRROR_ROWS (1 << 0) +#define MT9M111_CTXT_CTRL_RESTART (1 << 15) +#define MT9M111_CTXT_CTRL_DEFECTCOR_B (1 << 12) +#define MT9M111_CTXT_CTRL_RESIZE_B (1 << 10) +#define MT9M111_CTXT_CTRL_CTRL2_B (1 << 9) +#define MT9M111_CTXT_CTRL_GAMMA_B (1 << 8) +#define MT9M111_CTXT_CTRL_XENON_EN (1 << 7) +#define MT9M111_CTXT_CTRL_READ_MODE_B (1 << 3) +#define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2) +#define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1) +#define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0) + +/* + * Colorpipe register addresses (0x100..0x1ff) + */ +#define MT9M111_OPER_MODE_CTRL 0x106 +#define MT9M111_OUTPUT_FORMAT_CTRL 0x108 +#define MT9M111_REDUCER_XZOOM_B 0x1a0 +#define MT9M111_REDUCER_XSIZE_B 0x1a1 +#define MT9M111_REDUCER_YZOOM_B 0x1a3 +#define MT9M111_REDUCER_YSIZE_B 0x1a4 +#define MT9M111_REDUCER_XZOOM_A 0x1a6 +#define MT9M111_REDUCER_XSIZE_A 0x1a7 +#define MT9M111_REDUCER_YZOOM_A 0x1a9 +#define MT9M111_REDUCER_YSIZE_A 0x1aa + +#define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a +#define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b + +#define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14) +#define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1) + +#define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14) +#define MT9M111_OUTFMT_BYPASS_IFP (1 << 10) +#define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9) +#define MT9M111_OUTFMT_RGB (1 << 8) +#define MT9M111_OUTFMT_RGB565 (0 << 6) +#define MT9M111_OUTFMT_RGB555 (1 << 6) +#define MT9M111_OUTFMT_RGB444x (2 << 6) +#define MT9M111_OUTFMT_RGBx444 (3 << 6) +#define MT9M111_OUTFMT_TST_RAMP_OFF (0 << 4) +#define MT9M111_OUTFMT_TST_RAMP_COL (1 << 4) +#define MT9M111_OUTFMT_TST_RAMP_ROW (2 << 4) +#define MT9M111_OUTFMT_TST_RAMP_FRAME (3 << 4) +#define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3) +#define MT9M111_OUTFMT_AVG_CHROMA (1 << 2) +#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y (1 << 1) +#define MT9M111_OUTFMT_SWAP_RGB_EVEN (1 << 1) +#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr (1 << 0) + +/* + * Camera control register addresses (0x200..0x2ff not implemented) + */ + +#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg) +#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val)) +#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val)) +#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val)) + +#define MT9M111_MIN_DARK_ROWS 8 +#define MT9M111_MIN_DARK_COLS 26 +#define MT9M111_MAX_HEIGHT 1024 +#define MT9M111_MAX_WIDTH 1280 + +/* MT9M111 has only one fixed colorspace per pixelcode */ +struct mt9m111_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct mt9m111_datafmt *mt9m111_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct mt9m111_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { + {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, +}; + +enum mt9m111_context { + HIGHPOWER = 0, + LOWPOWER, +}; + +struct mt9m111 { + struct v4l2_subdev subdev; + int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code + * from v4l2-chip-ident.h */ + enum mt9m111_context context; + struct v4l2_rect rect; + const struct mt9m111_datafmt *fmt; + unsigned int gain; + unsigned char autoexposure; + unsigned char datawidth; + unsigned int powered:1; + unsigned int hflip:1; + unsigned int vflip:1; + unsigned int swap_rgb_even_odd:1; + unsigned int swap_rgb_red_blue:1; + unsigned int swap_yuv_y_chromas:1; + unsigned int swap_yuv_cb_cr:1; + unsigned int autowhitebalance:1; +}; + +static struct mt9m111 *to_mt9m111(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct mt9m111, subdev); +} + +static int reg_page_map_set(struct i2c_client *client, const u16 reg) +{ + int ret; + u16 page; + static int lastpage = -1; /* PageMap cache value */ + + page = (reg >> 8); + if (page == lastpage) + return 0; + if (page > 2) + return -EINVAL; + + ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page)); + if (!ret) + lastpage = page; + return ret; +} + +static int mt9m111_reg_read(struct i2c_client *client, const u16 reg) +{ + int ret; + + ret = reg_page_map_set(client, reg); + if (!ret) + ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff)); + + dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); + return ret; +} + +static int mt9m111_reg_write(struct i2c_client *client, const u16 reg, + const u16 data) +{ + int ret; + + ret = reg_page_map_set(client, reg); + if (!ret) + ret = i2c_smbus_write_word_data(client, reg & 0xff, + swab16(data)); + dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); + return ret; +} + +static int mt9m111_reg_set(struct i2c_client *client, const u16 reg, + const u16 data) +{ + int ret; + + ret = mt9m111_reg_read(client, reg); + if (ret >= 0) + ret = mt9m111_reg_write(client, reg, ret | data); + return ret; +} + +static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg, + const u16 data) +{ + int ret; + + ret = mt9m111_reg_read(client, reg); + return mt9m111_reg_write(client, reg, ret & ~data); +} + +static int mt9m111_set_context(struct i2c_client *client, + enum mt9m111_context ctxt) +{ + int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B + | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B + | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B + | MT9M111_CTXT_CTRL_VBLANK_SEL_B + | MT9M111_CTXT_CTRL_HBLANK_SEL_B; + int valA = MT9M111_CTXT_CTRL_RESTART; + + if (ctxt == HIGHPOWER) + return reg_write(CONTEXT_CONTROL, valB); + else + return reg_write(CONTEXT_CONTROL, valA); +} + +static int mt9m111_setup_rect(struct i2c_client *client, + struct v4l2_rect *rect) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int ret, is_raw_format; + int width = rect->width; + int height = rect->height; + + if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) + is_raw_format = 1; + else + is_raw_format = 0; + + ret = reg_write(COLUMN_START, rect->left); + if (!ret) + ret = reg_write(ROW_START, rect->top); + + if (is_raw_format) { + if (!ret) + ret = reg_write(WINDOW_WIDTH, width); + if (!ret) + ret = reg_write(WINDOW_HEIGHT, height); + } else { + if (!ret) + ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH); + if (!ret) + ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT); + if (!ret) + ret = reg_write(REDUCER_XSIZE_B, width); + if (!ret) + ret = reg_write(REDUCER_YSIZE_B, height); + if (!ret) + ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH); + if (!ret) + ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT); + if (!ret) + ret = reg_write(REDUCER_XSIZE_A, width); + if (!ret) + ret = reg_write(REDUCER_YSIZE_A, height); + } + + return ret; +} + +static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt) +{ + int ret; + u16 mask = MT9M111_OUTFMT_PROCESSED_BAYER | MT9M111_OUTFMT_RGB | + MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_SWAP_RGB_EVEN | + MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 | + MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr | + MT9M111_OUTFMT_SWAP_YCbCr_C_Y; + + ret = reg_read(OUTPUT_FORMAT_CTRL2_A); + if (ret >= 0) + ret = reg_write(OUTPUT_FORMAT_CTRL2_A, (ret & ~mask) | outfmt); + if (!ret) + ret = reg_read(OUTPUT_FORMAT_CTRL2_B); + if (ret >= 0) + ret = reg_write(OUTPUT_FORMAT_CTRL2_B, (ret & ~mask) | outfmt); + + return ret; +} + +static int mt9m111_setfmt_bayer8(struct i2c_client *client) +{ + return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER | + MT9M111_OUTFMT_RGB); +} + +static int mt9m111_setfmt_bayer10(struct i2c_client *client) +{ + return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_BYPASS_IFP); +} + +static int mt9m111_setfmt_rgb565(struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int val = 0; + + if (mt9m111->swap_rgb_red_blue) + val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; + if (mt9m111->swap_rgb_even_odd) + val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; + val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; + + return mt9m111_setup_pixfmt(client, val); +} + +static int mt9m111_setfmt_rgb555(struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int val = 0; + + if (mt9m111->swap_rgb_red_blue) + val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; + if (mt9m111->swap_rgb_even_odd) + val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; + val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; + + return mt9m111_setup_pixfmt(client, val); +} + +static int mt9m111_setfmt_yuv(struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int val = 0; + + if (mt9m111->swap_yuv_cb_cr) + val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; + if (mt9m111->swap_yuv_y_chromas) + val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y; + + return mt9m111_setup_pixfmt(client, val); +} + +static int mt9m111_enable(struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int ret; + + ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); + if (!ret) + mt9m111->powered = 1; + return ret; +} + +static int mt9m111_reset(struct i2c_client *client) +{ + int ret; + + ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); + if (!ret) + ret = reg_set(RESET, MT9M111_RESET_RESET_SOC); + if (!ret) + ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE + | MT9M111_RESET_RESET_SOC); + + return ret; +} + +static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) +{ + return 0; +} + +static int mt9m111_make_rect(struct i2c_client *client, + struct v4l2_rect *rect) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + + if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { + /* Bayer format - even size lengths */ + rect->width = ALIGN(rect->width, 2); + rect->height = ALIGN(rect->height, 2); + /* Let the user play with the starting pixel */ + } + + /* FIXME: the datasheet doesn't specify minimum sizes */ + soc_camera_limit_side(&rect->left, &rect->width, + MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH); + + soc_camera_limit_side(&rect->top, &rect->height, + MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT); + + return mt9m111_setup_rect(client, rect); +} + +static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct v4l2_rect rect = a->c; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m111 *mt9m111 = to_mt9m111(client); + int ret; + + dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n", + __func__, rect.left, rect.top, rect.width, rect.height); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + ret = mt9m111_make_rect(client, &rect); + if (!ret) + mt9m111->rect = rect; + return ret; +} + +static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m111 *mt9m111 = to_mt9m111(client); + + a->c = mt9m111->rect; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + a->bounds.left = MT9M111_MIN_DARK_COLS; + a->bounds.top = MT9M111_MIN_DARK_ROWS; + a->bounds.width = MT9M111_MAX_WIDTH; + a->bounds.height = MT9M111_MAX_HEIGHT; + a->defrect = a->bounds; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int mt9m111_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m111 *mt9m111 = to_mt9m111(client); + + mf->width = mt9m111->rect.width; + mf->height = mt9m111->rect.height; + mf->code = mt9m111->fmt->code; + mf->colorspace = mt9m111->fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9m111_set_pixfmt(struct i2c_client *client, + enum v4l2_mbus_pixelcode code) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int ret; + + switch (code) { + case V4L2_MBUS_FMT_SBGGR8_1X8: + ret = mt9m111_setfmt_bayer8(client); + break; + case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: + ret = mt9m111_setfmt_bayer10(client); + break; + case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: + ret = mt9m111_setfmt_rgb555(client); + break; + case V4L2_MBUS_FMT_RGB565_2X8_LE: + ret = mt9m111_setfmt_rgb565(client); + break; + case V4L2_MBUS_FMT_UYVY8_2X8: + mt9m111->swap_yuv_y_chromas = 0; + mt9m111->swap_yuv_cb_cr = 0; + ret = mt9m111_setfmt_yuv(client); + break; + case V4L2_MBUS_FMT_VYUY8_2X8: + mt9m111->swap_yuv_y_chromas = 0; + mt9m111->swap_yuv_cb_cr = 1; + ret = mt9m111_setfmt_yuv(client); + break; + case V4L2_MBUS_FMT_YUYV8_2X8: + mt9m111->swap_yuv_y_chromas = 1; + mt9m111->swap_yuv_cb_cr = 0; + ret = mt9m111_setfmt_yuv(client); + break; + case V4L2_MBUS_FMT_YVYU8_2X8: + mt9m111->swap_yuv_y_chromas = 1; + mt9m111->swap_yuv_cb_cr = 1; + ret = mt9m111_setfmt_yuv(client); + break; + default: + dev_err(&client->dev, "Pixel format not handled : %x\n", + code); + ret = -EINVAL; + } + + return ret; +} + +static int mt9m111_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct mt9m111_datafmt *fmt; + struct mt9m111 *mt9m111 = to_mt9m111(client); + struct v4l2_rect rect = { + .left = mt9m111->rect.left, + .top = mt9m111->rect.top, + .width = mf->width, + .height = mf->height, + }; + int ret; + + fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, + ARRAY_SIZE(mt9m111_colour_fmts)); + if (!fmt) + return -EINVAL; + + dev_dbg(&client->dev, + "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__, + mf->code, rect.left, rect.top, rect.width, rect.height); + + ret = mt9m111_make_rect(client, &rect); + if (!ret) + ret = mt9m111_set_pixfmt(client, mf->code); + if (!ret) { + mt9m111->rect = rect; + mt9m111->fmt = fmt; + mf->colorspace = fmt->colorspace; + } + + return ret; +} + +static int mt9m111_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m111 *mt9m111 = to_mt9m111(client); + const struct mt9m111_datafmt *fmt; + bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE; + + fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, + ARRAY_SIZE(mt9m111_colour_fmts)); + if (!fmt) { + fmt = mt9m111->fmt; + mf->code = fmt->code; + } + + /* + * With Bayer format enforce even side lengths, but let the user play + * with the starting pixel + */ + + if (mf->height > MT9M111_MAX_HEIGHT) + mf->height = MT9M111_MAX_HEIGHT; + else if (mf->height < 2) + mf->height = 2; + else if (bayer) + mf->height = ALIGN(mf->height, 2); + + if (mf->width > MT9M111_MAX_WIDTH) + mf->width = MT9M111_MAX_WIDTH; + else if (mf->width < 2) + mf->width = 2; + else if (bayer) + mf->width = ALIGN(mf->width, 2); + + mf->colorspace = fmt->colorspace; + + return 0; +} + +static int mt9m111_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m111 *mt9m111 = to_mt9m111(client); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = mt9m111->model; + id->revision = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9m111_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int val; + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) + return -EINVAL; + if (reg->match.addr != client->addr) + return -ENODEV; + + val = mt9m111_reg_read(client, reg->reg); + reg->size = 2; + reg->val = (u64)val; + + if (reg->val > 0xffff) + return -EIO; + + return 0; +} + +static int mt9m111_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + if (mt9m111_reg_write(client, reg->reg, reg->val) < 0) + return -EIO; + + return 0; +} +#endif + +static const struct v4l2_queryctrl mt9m111_controls[] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Verticaly", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontaly", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { /* gain = 1/32*val (=>gain=1 if val==32) */ + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 63 * 2 * 2, + .step = 1, + .default_value = 32, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + } +}; + +static int mt9m111_resume(struct soc_camera_device *icd); +static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state); + +static struct soc_camera_ops mt9m111_ops = { + .suspend = mt9m111_suspend, + .resume = mt9m111_resume, + .query_bus_param = mt9m111_query_bus_param, + .set_bus_param = mt9m111_set_bus_param, + .controls = mt9m111_controls, + .num_controls = ARRAY_SIZE(mt9m111_controls), +}; + +static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int ret; + + if (mt9m111->context == HIGHPOWER) { + if (flip) + ret = reg_set(READ_MODE_B, mask); + else + ret = reg_clear(READ_MODE_B, mask); + } else { + if (flip) + ret = reg_set(READ_MODE_A, mask); + else + ret = reg_clear(READ_MODE_A, mask); + } + + return ret; +} + +static int mt9m111_get_global_gain(struct i2c_client *client) +{ + int data; + + data = reg_read(GLOBAL_GAIN); + if (data >= 0) + return (data & 0x2f) * (1 << ((data >> 10) & 1)) * + (1 << ((data >> 9) & 1)); + return data; +} + +static int mt9m111_set_global_gain(struct i2c_client *client, int gain) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + u16 val; + + if (gain > 63 * 2 * 2) + return -EINVAL; + + mt9m111->gain = gain; + if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) + val = (1 << 10) | (1 << 9) | (gain / 4); + else if ((gain >= 64) && (gain < 64 * 2)) + val = (1 << 9) | (gain / 2); + else + val = gain; + + return reg_write(GLOBAL_GAIN, val); +} + +static int mt9m111_set_autoexposure(struct i2c_client *client, int on) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int ret; + + if (on) + ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); + else + ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); + + if (!ret) + mt9m111->autoexposure = on; + + return ret; +} + +static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int ret; + + if (on) + ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); + else + ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); + + if (!ret) + mt9m111->autowhitebalance = on; + + return ret; +} + +static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m111 *mt9m111 = to_mt9m111(client); + int data; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (mt9m111->context == HIGHPOWER) + data = reg_read(READ_MODE_B); + else + data = reg_read(READ_MODE_A); + + if (data < 0) + return -EIO; + ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS); + break; + case V4L2_CID_HFLIP: + if (mt9m111->context == HIGHPOWER) + data = reg_read(READ_MODE_B); + else + data = reg_read(READ_MODE_A); + + if (data < 0) + return -EIO; + ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); + break; + case V4L2_CID_GAIN: + data = mt9m111_get_global_gain(client); + if (data < 0) + return data; + ctrl->value = data; + break; + case V4L2_CID_EXPOSURE_AUTO: + ctrl->value = mt9m111->autoexposure; + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + ctrl->value = mt9m111->autowhitebalance; + break; + } + return 0; +} + +static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m111 *mt9m111 = to_mt9m111(client); + const struct v4l2_queryctrl *qctrl; + int ret; + + qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); + if (!qctrl) + return -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + mt9m111->vflip = ctrl->value; + ret = mt9m111_set_flip(client, ctrl->value, + MT9M111_RMB_MIRROR_ROWS); + break; + case V4L2_CID_HFLIP: + mt9m111->hflip = ctrl->value; + ret = mt9m111_set_flip(client, ctrl->value, + MT9M111_RMB_MIRROR_COLS); + break; + case V4L2_CID_GAIN: + ret = mt9m111_set_global_gain(client, ctrl->value); + break; + case V4L2_CID_EXPOSURE_AUTO: + ret = mt9m111_set_autoexposure(client, ctrl->value); + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + ret = mt9m111_set_autowhitebalance(client, ctrl->value); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9m111 *mt9m111 = to_mt9m111(client); + + mt9m111->gain = mt9m111_get_global_gain(client); + + return 0; +} + +static int mt9m111_restore_state(struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + + mt9m111_set_context(client, mt9m111->context); + mt9m111_set_pixfmt(client, mt9m111->fmt->code); + mt9m111_setup_rect(client, &mt9m111->rect); + mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); + mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); + mt9m111_set_global_gain(client, mt9m111->gain); + mt9m111_set_autoexposure(client, mt9m111->autoexposure); + mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance); + return 0; +} + +static int mt9m111_resume(struct soc_camera_device *icd) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9m111 *mt9m111 = to_mt9m111(client); + int ret = 0; + + if (mt9m111->powered) { + ret = mt9m111_enable(client); + if (!ret) + ret = mt9m111_reset(client); + if (!ret) + ret = mt9m111_restore_state(client); + } + return ret; +} + +static int mt9m111_init(struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + int ret; + + mt9m111->context = HIGHPOWER; + ret = mt9m111_enable(client); + if (!ret) + ret = mt9m111_reset(client); + if (!ret) + ret = mt9m111_set_context(client, mt9m111->context); + if (!ret) + ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure); + if (ret) + dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); + return ret; +} + +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ +static int mt9m111_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + s32 data; + int ret; + + /* + * We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. + */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + mt9m111->autoexposure = 1; + mt9m111->autowhitebalance = 1; + + mt9m111->swap_rgb_even_odd = 1; + mt9m111->swap_rgb_red_blue = 1; + + data = reg_read(CHIP_VERSION); + + switch (data) { + case 0x143a: /* MT9M111 or MT9M131 */ + mt9m111->model = V4L2_IDENT_MT9M111; + dev_info(&client->dev, + "Detected a MT9M111/MT9M131 chip ID %x\n", data); + break; + case 0x148c: /* MT9M112 */ + mt9m111->model = V4L2_IDENT_MT9M112; + dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); + break; + default: + ret = -ENODEV; + dev_err(&client->dev, + "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", + data); + goto ei2c; + } + + ret = mt9m111_init(client); + +ei2c: + return ret; +} + +static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { + .g_ctrl = mt9m111_g_ctrl, + .s_ctrl = mt9m111_s_ctrl, + .g_chip_ident = mt9m111_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9m111_g_register, + .s_register = mt9m111_s_register, +#endif +}; + +static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(mt9m111_colour_fmts)) + return -EINVAL; + + *code = mt9m111_colour_fmts[index].code; + return 0; +} + +static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { + .s_mbus_fmt = mt9m111_s_fmt, + .g_mbus_fmt = mt9m111_g_fmt, + .try_mbus_fmt = mt9m111_try_fmt, + .s_crop = mt9m111_s_crop, + .g_crop = mt9m111_g_crop, + .cropcap = mt9m111_cropcap, + .enum_mbus_fmt = mt9m111_enum_fmt, +}; + +static struct v4l2_subdev_ops mt9m111_subdev_ops = { + .core = &mt9m111_subdev_core_ops, + .video = &mt9m111_subdev_video_ops, +}; + +static int mt9m111_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9m111 *mt9m111; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + if (!icd) { + dev_err(&client->dev, "mt9m111: soc-camera data missing!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "mt9m111: driver needs platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL); + if (!mt9m111) + return -ENOMEM; + + v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); + + /* Second stage probe - when a capture adapter is there */ + icd->ops = &mt9m111_ops; + + mt9m111->rect.left = MT9M111_MIN_DARK_COLS; + mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; + mt9m111->rect.width = MT9M111_MAX_WIDTH; + mt9m111->rect.height = MT9M111_MAX_HEIGHT; + mt9m111->fmt = &mt9m111_colour_fmts[0]; + + ret = mt9m111_video_probe(icd, client); + if (ret) { + icd->ops = NULL; + kfree(mt9m111); + } + + return ret; +} + +static int mt9m111_remove(struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = to_mt9m111(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + kfree(mt9m111); + + return 0; +} + +static const struct i2c_device_id mt9m111_id[] = { + { "mt9m111", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9m111_id); + +static struct i2c_driver mt9m111_i2c_driver = { + .driver = { + .name = "mt9m111", + }, + .probe = mt9m111_probe, + .remove = mt9m111_remove, + .id_table = mt9m111_id, +}; + +static int __init mt9m111_mod_init(void) +{ + return i2c_add_driver(&mt9m111_i2c_driver); +} + +static void __exit mt9m111_mod_exit(void) +{ + i2c_del_driver(&mt9m111_i2c_driver); +} + +module_init(mt9m111_mod_init); +module_exit(mt9m111_mod_exit); + +MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver"); +MODULE_AUTHOR("Robert Jarzmik"); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9t031.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9t031.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9t031.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9t031.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,934 @@ +/* + * Driver for MT9T031 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * mt9t031 i2c address 0x5d + * The platform has to define i2c_board_info and link to it from + * struct soc_camera_link + */ + +/* mt9t031 selected register addresses */ +#define MT9T031_CHIP_VERSION 0x00 +#define MT9T031_ROW_START 0x01 +#define MT9T031_COLUMN_START 0x02 +#define MT9T031_WINDOW_HEIGHT 0x03 +#define MT9T031_WINDOW_WIDTH 0x04 +#define MT9T031_HORIZONTAL_BLANKING 0x05 +#define MT9T031_VERTICAL_BLANKING 0x06 +#define MT9T031_OUTPUT_CONTROL 0x07 +#define MT9T031_SHUTTER_WIDTH_UPPER 0x08 +#define MT9T031_SHUTTER_WIDTH 0x09 +#define MT9T031_PIXEL_CLOCK_CONTROL 0x0a +#define MT9T031_FRAME_RESTART 0x0b +#define MT9T031_SHUTTER_DELAY 0x0c +#define MT9T031_RESET 0x0d +#define MT9T031_READ_MODE_1 0x1e +#define MT9T031_READ_MODE_2 0x20 +#define MT9T031_READ_MODE_3 0x21 +#define MT9T031_ROW_ADDRESS_MODE 0x22 +#define MT9T031_COLUMN_ADDRESS_MODE 0x23 +#define MT9T031_GLOBAL_GAIN 0x35 +#define MT9T031_CHIP_ENABLE 0xF8 + +#define MT9T031_MAX_HEIGHT 1536 +#define MT9T031_MAX_WIDTH 2048 +#define MT9T031_MIN_HEIGHT 2 +#define MT9T031_MIN_WIDTH 18 +#define MT9T031_HORIZONTAL_BLANK 142 +#define MT9T031_VERTICAL_BLANK 25 +#define MT9T031_COLUMN_SKIP 32 +#define MT9T031_ROW_SKIP 20 + +#define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \ + SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \ + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \ + SOCAM_MASTER | SOCAM_DATAWIDTH_10) + +struct mt9t031 { + struct v4l2_subdev subdev; + struct v4l2_rect rect; /* Sensor window */ + int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ + u16 xskip; + u16 yskip; + unsigned int gain; + unsigned short y_skip_top; /* Lines to skip at the top */ + unsigned int exposure; + unsigned char autoexposure; +}; + +static struct mt9t031 *to_mt9t031(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct mt9t031, subdev); +} + +static int reg_read(struct i2c_client *client, const u8 reg) +{ + s32 data = i2c_smbus_read_word_data(client, reg); + return data < 0 ? data : swab16(data); +} + +static int reg_write(struct i2c_client *client, const u8 reg, + const u16 data) +{ + return i2c_smbus_write_word_data(client, reg, swab16(data)); +} + +static int reg_set(struct i2c_client *client, const u8 reg, + const u16 data) +{ + int ret; + + ret = reg_read(client, reg); + if (ret < 0) + return ret; + return reg_write(client, reg, ret | data); +} + +static int reg_clear(struct i2c_client *client, const u8 reg, + const u16 data) +{ + int ret; + + ret = reg_read(client, reg); + if (ret < 0) + return ret; + return reg_write(client, reg, ret & ~data); +} + +static int set_shutter(struct i2c_client *client, const u32 data) +{ + int ret; + + ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16); + + if (ret >= 0) + ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff); + + return ret; +} + +static int get_shutter(struct i2c_client *client, u32 *data) +{ + int ret; + + ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER); + *data = ret << 16; + + if (ret >= 0) + ret = reg_read(client, MT9T031_SHUTTER_WIDTH); + *data |= ret & 0xffff; + + return ret < 0 ? ret : 0; +} + +static int mt9t031_idle(struct i2c_client *client) +{ + int ret; + + /* Disable chip output, synchronous option update */ + ret = reg_write(client, MT9T031_RESET, 1); + if (ret >= 0) + ret = reg_write(client, MT9T031_RESET, 0); + if (ret >= 0) + ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); + + return ret >= 0 ? 0 : -EIO; +} + +static int mt9t031_disable(struct i2c_client *client) +{ + /* Disable the chip */ + reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); + + return 0; +} + +static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (enable) + /* Switch to master "normal" mode */ + ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2); + else + /* Stop sensor readout */ + ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); + + if (ret < 0) + return -EIO; + + return 0; +} + +static int mt9t031_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + + /* The caller should have queried our parameters, check anyway */ + if (flags & ~MT9T031_BUS_PARAM) + return -EINVAL; + + if (flags & SOCAM_PCLK_SAMPLE_FALLING) + reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); + else + reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); + + return 0; +} + +static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + + return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); +} + +enum { + MT9T031_CTRL_VFLIP, + MT9T031_CTRL_HFLIP, + MT9T031_CTRL_GAIN, + MT9T031_CTRL_EXPOSURE, + MT9T031_CTRL_EXPOSURE_AUTO, +}; + +static const struct v4l2_queryctrl mt9t031_controls[] = { + [MT9T031_CTRL_VFLIP] = { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + [MT9T031_CTRL_HFLIP] = { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + [MT9T031_CTRL_GAIN] = { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 64, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, + [MT9T031_CTRL_EXPOSURE] = { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 1, + .maximum = 255, + .step = 1, + .default_value = 255, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, + [MT9T031_CTRL_EXPOSURE_AUTO] = { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + } +}; + +static struct soc_camera_ops mt9t031_ops = { + .set_bus_param = mt9t031_set_bus_param, + .query_bus_param = mt9t031_query_bus_param, + .controls = mt9t031_controls, + .num_controls = ARRAY_SIZE(mt9t031_controls), +}; + +/* target must be _even_ */ +static u16 mt9t031_skip(s32 *source, s32 target, s32 max) +{ + unsigned int skip; + + if (*source < target + target / 2) { + *source = target; + return 1; + } + + skip = min(max, *source + target / 2) / target; + if (skip > 8) + skip = 8; + *source = target * skip; + + return skip; +} + +/* rect is the sensor rectangle, the caller guarantees parameter validity */ +static int mt9t031_set_params(struct i2c_client *client, + struct v4l2_rect *rect, u16 xskip, u16 yskip) +{ + struct mt9t031 *mt9t031 = to_mt9t031(client); + int ret; + u16 xbin, ybin; + const u16 hblank = MT9T031_HORIZONTAL_BLANK, + vblank = MT9T031_VERTICAL_BLANK; + + xbin = min(xskip, (u16)3); + ybin = min(yskip, (u16)3); + + /* + * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper. + * There is always a valid suitably aligned value. The worst case is + * xbin = 3, width = 2048. Then we will start at 36, the last read out + * pixel will be 2083, which is < 2085 - first black pixel. + * + * MT9T031 datasheet imposes window left border alignment, depending on + * the selected xskip. Failing to conform to this requirement produces + * dark horizontal stripes in the image. However, even obeying to this + * requirement doesn't eliminate the stripes in all configurations. They + * appear "locally reproducibly," but can differ between tests under + * different lighting conditions. + */ + switch (xbin) { + case 1: + rect->left &= ~1; + break; + case 2: + rect->left &= ~3; + break; + case 3: + rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ? + (rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6); + } + + rect->top &= ~1; + + dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n", + xskip, yskip, rect->width, rect->height, rect->left, rect->top); + + /* Disable register update, reconfigure atomically */ + ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1); + if (ret < 0) + return ret; + + /* Blanking and start values - default... */ + ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank); + if (ret >= 0) + ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank); + + if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) { + /* Binning, skipping */ + if (ret >= 0) + ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE, + ((xbin - 1) << 4) | (xskip - 1)); + if (ret >= 0) + ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, + ((ybin - 1) << 4) | (yskip - 1)); + } + dev_dbg(&client->dev, "new physical left %u, top %u\n", + rect->left, rect->top); + + /* + * The caller provides a supported format, as guaranteed by + * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() + */ + if (ret >= 0) + ret = reg_write(client, MT9T031_COLUMN_START, rect->left); + if (ret >= 0) + ret = reg_write(client, MT9T031_ROW_START, rect->top); + if (ret >= 0) + ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1); + if (ret >= 0) + ret = reg_write(client, MT9T031_WINDOW_HEIGHT, + rect->height + mt9t031->y_skip_top - 1); + if (ret >= 0 && mt9t031->autoexposure) { + unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank; + ret = set_shutter(client, total_h); + if (ret >= 0) { + const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; + const struct v4l2_queryctrl *qctrl = + &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; + mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * + (qctrl->maximum - qctrl->minimum)) / + shutter_max + qctrl->minimum; + } + } + + /* Re-enable register update, commit all changes */ + if (ret >= 0) + ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); + + if (ret >= 0) { + mt9t031->rect = *rect; + mt9t031->xskip = xskip; + mt9t031->yskip = yskip; + } + + return ret < 0 ? ret : 0; +} + +static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct v4l2_rect rect = a->c; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(client); + + rect.width = ALIGN(rect.width, 2); + rect.height = ALIGN(rect.height, 2); + + soc_camera_limit_side(&rect.left, &rect.width, + MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH); + + soc_camera_limit_side(&rect.top, &rect.height, + MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT); + + return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip); +} + +static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(client); + + a->c = mt9t031->rect; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = MT9T031_COLUMN_SKIP; + a->bounds.top = MT9T031_ROW_SKIP; + a->bounds.width = MT9T031_MAX_WIDTH; + a->bounds.height = MT9T031_MAX_HEIGHT; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int mt9t031_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(client); + + mf->width = mt9t031->rect.width / mt9t031->xskip; + mf->height = mt9t031->rect.height / mt9t031->yskip; + mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; + mf->colorspace = V4L2_COLORSPACE_SRGB; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9t031_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(client); + u16 xskip, yskip; + struct v4l2_rect rect = mt9t031->rect; + + /* + * try_fmt has put width and height within limits. + * S_FMT: use binning and skipping for scaling + */ + xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH); + yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT); + + mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; + mf->colorspace = V4L2_COLORSPACE_SRGB; + + /* mt9t031_set_params() doesn't change width and height */ + return mt9t031_set_params(client, &rect, xskip, yskip); +} + +/* + * If a user window larger than sensor window is requested, we'll increase the + * sensor window. + */ +static int mt9t031_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + v4l_bound_align_image( + &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, + &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); + + mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; + mf->colorspace = V4L2_COLORSPACE_SRGB; + + return 0; +} + +static int mt9t031_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(client); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = mt9t031->model; + id->revision = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9t031_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + reg->val = reg_read(client, reg->reg); + + if (reg->val > 0xffff) + return -EIO; + + return 0; +} + +static int mt9t031_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + if (reg_write(client, reg->reg, reg->val) < 0) + return -EIO; + + return 0; +} +#endif + +static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(client); + int data; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + data = reg_read(client, MT9T031_READ_MODE_2); + if (data < 0) + return -EIO; + ctrl->value = !!(data & 0x8000); + break; + case V4L2_CID_HFLIP: + data = reg_read(client, MT9T031_READ_MODE_2); + if (data < 0) + return -EIO; + ctrl->value = !!(data & 0x4000); + break; + case V4L2_CID_EXPOSURE_AUTO: + ctrl->value = mt9t031->autoexposure; + break; + case V4L2_CID_GAIN: + ctrl->value = mt9t031->gain; + break; + case V4L2_CID_EXPOSURE: + ctrl->value = mt9t031->exposure; + break; + } + return 0; +} + +static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(client); + const struct v4l2_queryctrl *qctrl; + int data; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (ctrl->value) + data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); + else + data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); + if (data < 0) + return -EIO; + break; + case V4L2_CID_HFLIP: + if (ctrl->value) + data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); + else + data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); + if (data < 0) + return -EIO; + break; + case V4L2_CID_GAIN: + qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN]; + if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) + return -EINVAL; + /* See Datasheet Table 7, Gain settings. */ + if (ctrl->value <= qctrl->default_value) { + /* Pack it into 0..1 step 0.125, register values 0..8 */ + unsigned long range = qctrl->default_value - qctrl->minimum; + data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; + + dev_dbg(&client->dev, "Setting gain %d\n", data); + data = reg_write(client, MT9T031_GLOBAL_GAIN, data); + if (data < 0) + return -EIO; + } else { + /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ + /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ + unsigned long range = qctrl->maximum - qctrl->default_value - 1; + /* calculated gain: map 65..127 to 9..1024 step 0.125 */ + unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * + 1015 + range / 2) / range + 9; + + if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ + data = gain; + else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */ + data = ((gain - 32) * 16 + 16) / 32 + 80; + else + /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */ + data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; + + dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n", + reg_read(client, MT9T031_GLOBAL_GAIN), data); + data = reg_write(client, MT9T031_GLOBAL_GAIN, data); + if (data < 0) + return -EIO; + } + + /* Success */ + mt9t031->gain = ctrl->value; + break; + case V4L2_CID_EXPOSURE: + qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; + /* mt9t031 has maximum == default */ + if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) + return -EINVAL; + else { + const unsigned long range = qctrl->maximum - qctrl->minimum; + const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 + + range / 2) / range + 1; + u32 old; + + get_shutter(client, &old); + dev_dbg(&client->dev, "Set shutter from %u to %u\n", + old, shutter); + if (set_shutter(client, shutter) < 0) + return -EIO; + mt9t031->exposure = ctrl->value; + mt9t031->autoexposure = 0; + } + break; + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->value) { + const u16 vblank = MT9T031_VERTICAL_BLANK; + const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; + unsigned int total_h = mt9t031->rect.height + + mt9t031->y_skip_top + vblank; + + if (set_shutter(client, total_h) < 0) + return -EIO; + qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; + mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * + (qctrl->maximum - qctrl->minimum)) / + shutter_max + qctrl->minimum; + mt9t031->autoexposure = 1; + } else + mt9t031->autoexposure = 0; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * Power Management: + * This function does nothing for now but must be present for pm to work + */ +static int mt9t031_runtime_suspend(struct device *dev) +{ + return 0; +} + +/* + * Power Management: + * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged + * they are however changed at reset if the platform hook is present + * thus we rewrite them with the values stored by the driver + */ +static int mt9t031_runtime_resume(struct device *dev) +{ + struct video_device *vdev = to_video_device(dev); + struct soc_camera_device *icd = container_of(vdev->parent, + struct soc_camera_device, dev); + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(client); + + int ret; + u16 xbin, ybin; + + xbin = min(mt9t031->xskip, (u16)3); + ybin = min(mt9t031->yskip, (u16)3); + + ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE, + ((xbin - 1) << 4) | (mt9t031->xskip - 1)); + if (ret < 0) + return ret; + + ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, + ((ybin - 1) << 4) | (mt9t031->yskip - 1)); + if (ret < 0) + return ret; + + return 0; +} + +static struct dev_pm_ops mt9t031_dev_pm_ops = { + .runtime_suspend = mt9t031_runtime_suspend, + .runtime_resume = mt9t031_runtime_resume, +}; + +static struct device_type mt9t031_dev_type = { + .name = "MT9T031", + .pm = &mt9t031_dev_pm_ops, +}; + +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ +static int mt9t031_video_probe(struct i2c_client *client) +{ + struct mt9t031 *mt9t031 = to_mt9t031(client); + struct video_device *vdev = soc_camera_i2c_to_vdev(client); + s32 data; + int ret; + + /* Enable the chip */ + data = reg_write(client, MT9T031_CHIP_ENABLE, 1); + dev_dbg(&client->dev, "write: %d\n", data); + + /* Read out the chip version register */ + data = reg_read(client, MT9T031_CHIP_VERSION); + + switch (data) { + case 0x1621: + mt9t031->model = V4L2_IDENT_MT9T031; + break; + default: + dev_err(&client->dev, + "No MT9T031 chip detected, register read %x\n", data); + return -ENODEV; + } + + dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); + + ret = mt9t031_idle(client); + if (ret < 0) + dev_err(&client->dev, "Failed to initialise the camera\n"); + else + vdev->dev.type = &mt9t031_dev_type; + + /* mt9t031_idle() has reset the chip to default. */ + mt9t031->exposure = 255; + mt9t031->gain = 64; + + return ret; +} + +static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t031 *mt9t031 = to_mt9t031(client); + + *lines = mt9t031->y_skip_top; + + return 0; +} + +static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { + .g_ctrl = mt9t031_g_ctrl, + .s_ctrl = mt9t031_s_ctrl, + .g_chip_ident = mt9t031_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9t031_g_register, + .s_register = mt9t031_s_register, +#endif +}; + +static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index) + return -EINVAL; + + *code = V4L2_MBUS_FMT_SBGGR10_1X10; + return 0; +} + +static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { + .s_stream = mt9t031_s_stream, + .s_mbus_fmt = mt9t031_s_fmt, + .g_mbus_fmt = mt9t031_g_fmt, + .try_mbus_fmt = mt9t031_try_fmt, + .s_crop = mt9t031_s_crop, + .g_crop = mt9t031_g_crop, + .cropcap = mt9t031_cropcap, + .enum_mbus_fmt = mt9t031_enum_fmt, +}; + +static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { + .g_skip_top_lines = mt9t031_g_skip_top_lines, +}; + +static struct v4l2_subdev_ops mt9t031_subdev_ops = { + .core = &mt9t031_subdev_core_ops, + .video = &mt9t031_subdev_video_ops, + .sensor = &mt9t031_subdev_sensor_ops, +}; + +static int mt9t031_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9t031 *mt9t031; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; + + if (icd) { + struct soc_camera_link *icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "MT9T031 driver needs platform data\n"); + return -EINVAL; + } + + icd->ops = &mt9t031_ops; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL); + if (!mt9t031) + return -ENOMEM; + + v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); + + mt9t031->y_skip_top = 0; + mt9t031->rect.left = MT9T031_COLUMN_SKIP; + mt9t031->rect.top = MT9T031_ROW_SKIP; + mt9t031->rect.width = MT9T031_MAX_WIDTH; + mt9t031->rect.height = MT9T031_MAX_HEIGHT; + + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ + mt9t031->autoexposure = 1; + + mt9t031->xskip = 1; + mt9t031->yskip = 1; + + mt9t031_idle(client); + + ret = mt9t031_video_probe(client); + + mt9t031_disable(client); + + if (ret) { + if (icd) + icd->ops = NULL; + kfree(mt9t031); + } + + return ret; +} + +static int mt9t031_remove(struct i2c_client *client) +{ + struct mt9t031 *mt9t031 = to_mt9t031(client); + struct soc_camera_device *icd = client->dev.platform_data; + + if (icd) + icd->ops = NULL; + kfree(mt9t031); + + return 0; +} + +static const struct i2c_device_id mt9t031_id[] = { + { "mt9t031", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9t031_id); + +static struct i2c_driver mt9t031_i2c_driver = { + .driver = { + .name = "mt9t031", + }, + .probe = mt9t031_probe, + .remove = mt9t031_remove, + .id_table = mt9t031_id, +}; + +static int __init mt9t031_mod_init(void) +{ + return i2c_add_driver(&mt9t031_i2c_driver); +} + +static void __exit mt9t031_mod_exit(void) +{ + i2c_del_driver(&mt9t031_i2c_driver); +} + +module_init(mt9t031_mod_init); +module_exit(mt9t031_mod_exit); + +MODULE_DESCRIPTION("Micron MT9T031 Camera driver"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9t112.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9t112.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9t112.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9t112.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1175 @@ +/* + * mt9t112 Camera Driver + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on ov772x driver, mt9m111 driver, + * + * Copyright (C) 2008 Kuninori Morimoto + * Copyright (C) 2008, Robert Jarzmik + * Copyright 2006-7 Jonathan Corbet + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* you can check PLL/clock info */ +/* #define EXT_CLOCK 24000000 */ + +/************************************************************************ + + + macro + + +************************************************************************/ +/* + * frame size + */ +#define MAX_WIDTH 2048 +#define MAX_HEIGHT 1536 + +#define VGA_WIDTH 640 +#define VGA_HEIGHT 480 + +/* + * macro of read/write + */ +#define ECHECKER(ret, x) \ + do { \ + (ret) = (x); \ + if ((ret) < 0) \ + return (ret); \ + } while (0) + +#define mt9t112_reg_write(ret, client, a, b) \ + ECHECKER(ret, __mt9t112_reg_write(client, a, b)) +#define mt9t112_mcu_write(ret, client, a, b) \ + ECHECKER(ret, __mt9t112_mcu_write(client, a, b)) + +#define mt9t112_reg_mask_set(ret, client, a, b, c) \ + ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c)) +#define mt9t112_mcu_mask_set(ret, client, a, b, c) \ + ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c)) + +#define mt9t112_reg_read(ret, client, a) \ + ECHECKER(ret, __mt9t112_reg_read(client, a)) + +/* + * Logical address + */ +#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff)) +#define VAR(id, offset) _VAR(id, offset, 0x0000) +#define VAR8(id, offset) _VAR(id, offset, 0x8000) + +/************************************************************************ + + + struct + + +************************************************************************/ +struct mt9t112_frame_size { + u16 width; + u16 height; +}; + +struct mt9t112_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; + +struct mt9t112_priv { + struct v4l2_subdev subdev; + struct mt9t112_camera_info *info; + struct i2c_client *client; + struct soc_camera_device icd; + struct mt9t112_frame_size frame; + const struct mt9t112_format *format; + int model; + u32 flags; +/* for flags */ +#define INIT_DONE (1<<0) +}; + +/************************************************************************ + + + supported format + + +************************************************************************/ + +static const struct mt9t112_format mt9t112_cfmts[] = { + { + .code = V4L2_MBUS_FMT_UYVY8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, { + .code = V4L2_MBUS_FMT_VYUY8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 1, + }, { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 2, + }, { + .code = V4L2_MBUS_FMT_YVYU8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 3, + }, { + .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 8, + .order = 2, + }, { + .code = V4L2_MBUS_FMT_RGB565_2X8_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 4, + .order = 2, + }, +}; + +/************************************************************************ + + + general function + + +************************************************************************/ +static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), + struct mt9t112_priv, + subdev); +} + +static int __mt9t112_reg_read(const struct i2c_client *client, u16 command) +{ + struct i2c_msg msg[2]; + u8 buf[2]; + int ret; + + command = swab16(command); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = (u8 *)&command; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = buf; + + /* + * if return value of this function is < 0, + * it mean error. + * else, under 16bit is valid data. + */ + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + return ret; + + memcpy(&ret, buf, 2); + return swab16(ret); +} + +static int __mt9t112_reg_write(const struct i2c_client *client, + u16 command, u16 data) +{ + struct i2c_msg msg; + u8 buf[4]; + int ret; + + command = swab16(command); + data = swab16(data); + + memcpy(buf + 0, &command, 2); + memcpy(buf + 2, &data, 2); + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 4; + msg.buf = buf; + + /* + * i2c_transfer return message length, + * but this function should return 0 if correct case + */ + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret >= 0) + ret = 0; + + return ret; +} + +static int __mt9t112_reg_mask_set(const struct i2c_client *client, + u16 command, + u16 mask, + u16 set) +{ + int val = __mt9t112_reg_read(client, command); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return __mt9t112_reg_write(client, command, val); +} + +/* mcu access */ +static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command) +{ + int ret; + + ret = __mt9t112_reg_write(client, 0x098E, command); + if (ret < 0) + return ret; + + return __mt9t112_reg_read(client, 0x0990); +} + +static int __mt9t112_mcu_write(const struct i2c_client *client, + u16 command, u16 data) +{ + int ret; + + ret = __mt9t112_reg_write(client, 0x098E, command); + if (ret < 0) + return ret; + + return __mt9t112_reg_write(client, 0x0990, data); +} + +static int __mt9t112_mcu_mask_set(const struct i2c_client *client, + u16 command, + u16 mask, + u16 set) +{ + int val = __mt9t112_mcu_read(client, command); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return __mt9t112_mcu_write(client, command, val); +} + +static int mt9t112_reset(const struct i2c_client *client) +{ + int ret; + + mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); + msleep(1); + mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); + + return ret; +} + +#ifndef EXT_CLOCK +#define CLOCK_INFO(a, b) +#else +#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b) +static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) +{ + int m, n, p1, p2, p3, p4, p5, p6, p7; + u32 vco, clk; + char *enable; + + ext /= 1000; /* kbyte order */ + + mt9t112_reg_read(n, client, 0x0012); + p1 = n & 0x000f; + n = n >> 4; + p2 = n & 0x000f; + n = n >> 4; + p3 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x002a); + p4 = n & 0x000f; + n = n >> 4; + p5 = n & 0x000f; + n = n >> 4; + p6 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x002c); + p7 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x0010); + m = n & 0x00ff; + n = (n >> 8) & 0x003f; + + enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; + dev_info(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); + + vco = 2 * m * ext / (n+1); + enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; + dev_info(&client->dev, "VCO : %10u K %s\n", vco, enable); + + clk = vco / (p1+1) / (p2+1); + enable = (96000 < clk) ? "X" : ""; + dev_info(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); + + clk = vco / (p3+1); + enable = (768000 < clk) ? "X" : ""; + dev_info(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); + + clk = vco / (p6+1); + enable = (96000 < clk) ? "X" : ""; + dev_info(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); + + clk = vco / (p5+1); + enable = (54000 < clk) ? "X" : ""; + dev_info(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); + + clk = vco / (p4+1); + enable = (70000 < clk) ? "X" : ""; + dev_info(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); + + clk = vco / (p7+1); + dev_info(&client->dev, "External sensor : %10u K\n", clk); + + clk = ext / (n+1); + enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; + dev_info(&client->dev, "PFD : %10u K %s\n", clk, enable); + + return 0; +} +#endif + +static void mt9t112_frame_check(u32 *width, u32 *height) +{ + if (*width > MAX_WIDTH) + *width = MAX_WIDTH; + + if (*height > MAX_HEIGHT) + *height = MAX_HEIGHT; +} + +static int mt9t112_set_a_frame_size(const struct i2c_client *client, + u16 width, + u16 height) +{ + int ret; + u16 wstart = (MAX_WIDTH - width) / 2; + u16 hstart = (MAX_HEIGHT - height) / 2; + + /* (Context A) Image Width/Height */ + mt9t112_mcu_write(ret, client, VAR(26, 0), width); + mt9t112_mcu_write(ret, client, VAR(26, 2), height); + + /* (Context A) Output Width/Height */ + mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); + mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); + + /* (Context A) Start Row/Column */ + mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); + mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); + + /* (Context A) End Row/Column */ + mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); + mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); + + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + return ret; +} + +static int mt9t112_set_pll_dividers(const struct i2c_client *client, + u8 m, u8 n, + u8 p1, u8 p2, u8 p3, + u8 p4, u8 p5, u8 p6, + u8 p7) +{ + int ret; + u16 val; + + /* N/M */ + val = (n << 8) | + (m << 0); + mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); + + /* P1/P2/P3 */ + val = ((p3 & 0x0F) << 8) | + ((p2 & 0x0F) << 4) | + ((p1 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); + + /* P4/P5/P6 */ + val = (0x7 << 12) | + ((p6 & 0x0F) << 8) | + ((p5 & 0x0F) << 4) | + ((p4 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); + + /* P7 */ + val = (0x1 << 12) | + ((p7 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); + + return ret; +} + +static int mt9t112_init_pll(const struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + int data, i, ret; + + mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); + + /* PLL control: BYPASS PLL = 8517 */ + mt9t112_reg_write(ret, client, 0x0014, 0x2145); + + /* Replace these registers when new timing parameters are generated */ + mt9t112_set_pll_dividers(client, + priv->info->divider.m, + priv->info->divider.n, + priv->info->divider.p1, + priv->info->divider.p2, + priv->info->divider.p3, + priv->info->divider.p4, + priv->info->divider.p5, + priv->info->divider.p6, + priv->info->divider.p7); + + /* + * TEST_BYPASS on + * PLL_ENABLE on + * SEL_LOCK_DET on + * TEST_BYPASS off + */ + mt9t112_reg_write(ret, client, 0x0014, 0x2525); + mt9t112_reg_write(ret, client, 0x0014, 0x2527); + mt9t112_reg_write(ret, client, 0x0014, 0x3427); + mt9t112_reg_write(ret, client, 0x0014, 0x3027); + + mdelay(10); + + /* + * PLL_BYPASS off + * Reference clock count + * I2C Master Clock Divider + */ + mt9t112_reg_write(ret, client, 0x0014, 0x3046); + mt9t112_reg_write(ret, client, 0x0022, 0x0190); + mt9t112_reg_write(ret, client, 0x3B84, 0x0212); + + /* External sensor clock is PLL bypass */ + mt9t112_reg_write(ret, client, 0x002E, 0x0500); + + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); + mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); + + /* MCU disabled */ + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); + + /* out of standby */ + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); + + mdelay(50); + + /* + * Standby Workaround + * Disable Secondary I2C Pads + */ + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + + /* poll to verify out of standby. Must Poll this bit */ + for (i = 0; i < 100; i++) { + mt9t112_reg_read(data, client, 0x0018); + if (!(0x4000 & data)) + break; + + mdelay(10); + } + + return ret; +} + +static int mt9t112_init_setting(const struct i2c_client *client) +{ + + int ret; + + /* Adaptive Output Clock (A) */ + mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000); + + /* Read Mode (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024); + + /* Fine Correction (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC); + + /* Fine IT Min (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1); + + /* Fine IT Max Margin (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF); + + /* Base Frame Lines (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D); + + /* Min Line Length (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a); + + /* Line Length (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0); + + /* Adaptive Output Clock (B) */ + mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000); + + /* Row Start (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004); + + /* Column Start (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004); + + /* Row End (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B); + + /* Column End (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B); + + /* Fine Correction (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C); + + /* Fine IT Min (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1); + + /* Fine IT Max Margin (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF); + + /* Base Frame Lines (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668); + + /* Min Line Length (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0); + + /* Line Length (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); + + /* + * Flicker Dectection registers + * This section should be replaced whenever new Timing file is generated + * All the following registers need to be replaced + * Following registers are generated from Register Wizard but user can + * modify them. For detail see auto flicker detection tuning + */ + + /* FD_FDPERIOD_SELECT */ + mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01); + + /* PRI_B_CONFIG_FD_ALGO_RUN */ + mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003); + + /* PRI_A_CONFIG_FD_ALGO_RUN */ + mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); + + /* + * AFD range detection tuning registers + */ + + /* search_f1_50 */ + mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); + + /* search_f2_50 */ + mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); + + /* search_f1_60 */ + mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); + + /* search_f2_60 */ + mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); + + /* period_50Hz (A) */ + mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); + + /* secret register by aptina */ + /* period_50Hz (A MSB) */ + mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); + + /* period_60Hz (A) */ + mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); + + /* secret register by aptina */ + /* period_60Hz (A MSB) */ + mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); + + /* period_50Hz (B) */ + mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); + + /* secret register by aptina */ + /* period_50Hz (B) MSB */ + mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); + + /* period_60Hz (B) */ + mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); + + /* secret register by aptina */ + /* period_60Hz (B) MSB */ + mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); + + /* FD Mode */ + mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10); + + /* Stat_min */ + mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02); + + /* Stat_max */ + mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03); + + /* Min_amplitude */ + mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A); + + /* RX FIFO Watermark (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014); + + /* RX FIFO Watermark (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014); + + /* MCLK: 16MHz + * PCLK: 73MHz + * CorePixCLK: 36.5 MHz + */ + mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133); + mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110); + mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130); + mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108); + + mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35); + + return ret; +} + +static int mt9t112_auto_focus_setting(const struct i2c_client *client) +{ + int ret; + + mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F); + mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + mt9t112_reg_write(ret, client, 0x0614, 0x0000); + + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); + mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02); + mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002); + mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001); + mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025); + mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193); + mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); + + return ret; +} + +static int mt9t112_auto_focus_trigger(const struct i2c_client *client) +{ + int ret; + + mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01); + + return ret; +} + +static int mt9t112_init_camera(const struct i2c_client *client) +{ + int ret; + + ECHECKER(ret, mt9t112_reset(client)); + + ECHECKER(ret, mt9t112_init_pll(client)); + + ECHECKER(ret, mt9t112_init_setting(client)); + + ECHECKER(ret, mt9t112_auto_focus_setting(client)); + + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); + + /* Analog setting B */ + mt9t112_reg_write(ret, client, 0x3084, 0x2409); + mt9t112_reg_write(ret, client, 0x3092, 0x0A49); + mt9t112_reg_write(ret, client, 0x3094, 0x4949); + mt9t112_reg_write(ret, client, 0x3096, 0x4950); + + /* + * Disable adaptive clock + * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR + * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR + */ + mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); + mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); + + /* Configure STatus in Status_before_length Format and enable header */ + /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ + mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); + + /* Enable JPEG in context B */ + /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ + mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); + + /* Disable Dac_TXLO */ + mt9t112_reg_write(ret, client, 0x316C, 0x350F); + + /* Set max slew rates */ + mt9t112_reg_write(ret, client, 0x1E, 0x777); + + return ret; +} + +/************************************************************************ + + + soc_camera_ops + + +************************************************************************/ +static int mt9t112_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +static unsigned long mt9t112_query_bus_param(struct soc_camera_device *icd) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9t112_priv *priv = to_mt9t112(client); + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH; + + flags |= (priv->info->flags & MT9T112_FLAG_PCLK_RISING_EDGE) ? + SOCAM_PCLK_SAMPLE_RISING : SOCAM_PCLK_SAMPLE_FALLING; + + if (priv->info->flags & MT9T112_FLAG_DATAWIDTH_8) + flags |= SOCAM_DATAWIDTH_8; + else + flags |= SOCAM_DATAWIDTH_10; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static struct soc_camera_ops mt9t112_ops = { + .set_bus_param = mt9t112_set_bus_param, + .query_bus_param = mt9t112_query_bus_param, +}; + +/************************************************************************ + + + v4l2_subdev_core_ops + + +************************************************************************/ +static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + id->ident = priv->model; + id->revision = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9t112_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + reg->size = 2; + mt9t112_reg_read(ret, client, reg->reg); + + reg->val = (__u64)ret; + + return 0; +} + +static int mt9t112_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + mt9t112_reg_write(ret, client, reg->reg, reg->val); + + return ret; +} +#endif + +static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { + .g_chip_ident = mt9t112_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9t112_g_register, + .s_register = mt9t112_s_register, +#endif +}; + + +/************************************************************************ + + + v4l2_subdev_video_ops + + +************************************************************************/ +static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + int ret = 0; + + if (!enable) { + /* FIXME + * + * If user selected large output size, + * and used it long time, + * mt9t112 camera will be very warm. + * + * But current driver can not stop mt9t112 camera. + * So, set small size here to solve this problem. + */ + mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT); + return ret; + } + + if (!(priv->flags & INIT_DONE)) { + u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE & + priv->info->flags) ? 0x0001 : 0x0000; + + ECHECKER(ret, mt9t112_init_camera(client)); + + /* Invert PCLK (Data sampled on falling edge of pixclk) */ + mt9t112_reg_write(ret, client, 0x3C20, param); + + mdelay(5); + + priv->flags |= INIT_DONE; + } + + mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); + mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + mt9t112_set_a_frame_size(client, + priv->frame.width, + priv->frame.height); + + ECHECKER(ret, mt9t112_auto_focus_trigger(client)); + + dev_dbg(&client->dev, "format : %d\n", priv->format->code); + dev_dbg(&client->dev, "size : %d x %d\n", + priv->frame.width, + priv->frame.height); + + CLOCK_INFO(client, EXT_CLOCK); + + return ret; +} + +static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, + enum v4l2_mbus_pixelcode code) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + int i; + + priv->format = NULL; + + /* + * frame size check + */ + mt9t112_frame_check(&width, &height); + + /* + * get color format + */ + for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++) + if (mt9t112_cfmts[i].code == code) + break; + + if (i == ARRAY_SIZE(mt9t112_cfmts)) + return -EINVAL; + + priv->frame.width = (u16)width; + priv->frame.height = (u16)height; + + priv->format = mt9t112_cfmts + i; + + return 0; +} + +static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = 0; + a->bounds.top = 0; + a->bounds.width = VGA_WIDTH; + a->bounds.height = VGA_HEIGHT; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + a->c.left = 0; + a->c.top = 0; + a->c.width = VGA_WIDTH; + a->c.height = VGA_HEIGHT; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_rect *rect = &a->c; + + return mt9t112_set_params(client, rect->width, rect->height, + V4L2_MBUS_FMT_UYVY8_2X8); +} + +static int mt9t112_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (!priv->format) { + int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT, + V4L2_MBUS_FMT_UYVY8_2X8); + if (ret < 0) + return ret; + } + + mf->width = priv->frame.width; + mf->height = priv->frame.height; + /* TODO: set colorspace */ + mf->code = priv->format->code; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9t112_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* TODO: set colorspace */ + return mt9t112_set_params(client, mf->width, mf->height, mf->code); +} + +static int mt9t112_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + mt9t112_frame_check(&mf->width, &mf->height); + + /* TODO: set colorspace */ + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(mt9t112_cfmts)) + return -EINVAL; + + *code = mt9t112_cfmts[index].code; + return 0; +} + +static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { + .s_stream = mt9t112_s_stream, + .g_mbus_fmt = mt9t112_g_fmt, + .s_mbus_fmt = mt9t112_s_fmt, + .try_mbus_fmt = mt9t112_try_fmt, + .cropcap = mt9t112_cropcap, + .g_crop = mt9t112_g_crop, + .s_crop = mt9t112_s_crop, + .enum_mbus_fmt = mt9t112_enum_fmt, +}; + +/************************************************************************ + + + i2c driver + + +************************************************************************/ +static struct v4l2_subdev_ops mt9t112_subdev_ops = { + .core = &mt9t112_subdev_core_ops, + .video = &mt9t112_subdev_video_ops, +}; + +static int mt9t112_camera_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + const char *devname; + int chipid; + + /* + * We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. + */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + /* + * check and show chip ID + */ + mt9t112_reg_read(chipid, client, 0x0000); + + switch (chipid) { + case 0x2680: + devname = "mt9t111"; + priv->model = V4L2_IDENT_MT9T111; + break; + case 0x2682: + devname = "mt9t112"; + priv->model = V4L2_IDENT_MT9T112; + break; + default: + dev_err(&client->dev, "Product ID error %04x\n", chipid); + return -ENODEV; + } + + dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); + + return 0; +} + +static int mt9t112_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9t112_priv *priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl; + int ret; + + if (!icd) { + dev_err(&client->dev, "mt9t112: missing soc-camera data!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl || !icl->priv) + return -EINVAL; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = icl->priv; + + v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); + + icd->ops = &mt9t112_ops; + + ret = mt9t112_camera_probe(icd, client); + if (ret) { + icd->ops = NULL; + kfree(priv); + } + + return ret; +} + +static int mt9t112_remove(struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + kfree(priv); + return 0; +} + +static const struct i2c_device_id mt9t112_id[] = { + { "mt9t112", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9t112_id); + +static struct i2c_driver mt9t112_i2c_driver = { + .driver = { + .name = "mt9t112", + }, + .probe = mt9t112_probe, + .remove = mt9t112_remove, + .id_table = mt9t112_id, +}; + +/************************************************************************ + + + module function + + +************************************************************************/ +static int __init mt9t112_module_init(void) +{ + return i2c_add_driver(&mt9t112_i2c_driver); +} + +static void __exit mt9t112_module_exit(void) +{ + i2c_del_driver(&mt9t112_i2c_driver); +} + +module_init(mt9t112_module_init); +module_exit(mt9t112_module_exit); + +MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); +MODULE_AUTHOR("Kuninori Morimoto"); +MODULE_LICENSE("GPL v2"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v011.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v011.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v011.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v011.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,722 @@ +/* + * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor + * + * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com) + * This code is placed under the terms of the GNU General Public License v2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Micron mt9v011 sensor driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0-2)"); + +#define R00_MT9V011_CHIP_VERSION 0x00 +#define R01_MT9V011_ROWSTART 0x01 +#define R02_MT9V011_COLSTART 0x02 +#define R03_MT9V011_HEIGHT 0x03 +#define R04_MT9V011_WIDTH 0x04 +#define R05_MT9V011_HBLANK 0x05 +#define R06_MT9V011_VBLANK 0x06 +#define R07_MT9V011_OUT_CTRL 0x07 +#define R09_MT9V011_SHUTTER_WIDTH 0x09 +#define R0A_MT9V011_CLK_SPEED 0x0a +#define R0B_MT9V011_RESTART 0x0b +#define R0C_MT9V011_SHUTTER_DELAY 0x0c +#define R0D_MT9V011_RESET 0x0d +#define R1E_MT9V011_DIGITAL_ZOOM 0x1e +#define R20_MT9V011_READ_MODE 0x20 +#define R2B_MT9V011_GREEN_1_GAIN 0x2b +#define R2C_MT9V011_BLUE_GAIN 0x2c +#define R2D_MT9V011_RED_GAIN 0x2d +#define R2E_MT9V011_GREEN_2_GAIN 0x2e +#define R35_MT9V011_GLOBAL_GAIN 0x35 +#define RF1_MT9V011_CHIP_ENABLE 0xf1 + +#define MT9V011_VERSION 0x8232 +#define MT9V011_REV_B_VERSION 0x8243 + +/* supported controls */ +static struct v4l2_queryctrl mt9v011_qctrl[] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = (1 << 12) - 1 - 0x0020, + .step = 1, + .default_value = 0x0020, + .flags = 0, + }, { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 2047, + .step = 1, + .default_value = 0x01fc, + .flags = 0, + }, { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = -1 << 9, + .maximum = (1 << 9) - 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = -1 << 9, + .maximum = (1 << 9) - 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + } +}; + +struct mt9v011 { + struct v4l2_subdev sd; + unsigned width, height; + unsigned xtal; + unsigned hflip:1; + unsigned vflip:1; + + u16 global_gain, exposure; + s16 red_bal, blue_bal; +}; + +static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mt9v011, sd); +} + +static int mt9v011_read(struct v4l2_subdev *sd, unsigned char addr) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + __be16 buffer; + int rc, val; + + rc = i2c_master_send(c, &addr, 1); + if (rc != 1) + v4l2_dbg(0, debug, sd, + "i2c i/o error: rc == %d (should be 1)\n", rc); + + msleep(10); + + rc = i2c_master_recv(c, (char *)&buffer, 2); + if (rc != 2) + v4l2_dbg(0, debug, sd, + "i2c i/o error: rc == %d (should be 2)\n", rc); + + val = be16_to_cpu(buffer); + + v4l2_dbg(2, debug, sd, "mt9v011: read 0x%02x = 0x%04x\n", addr, val); + + return val; +} + +static void mt9v011_write(struct v4l2_subdev *sd, unsigned char addr, + u16 value) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + unsigned char buffer[3]; + int rc; + + buffer[0] = addr; + buffer[1] = value >> 8; + buffer[2] = value & 0xff; + + v4l2_dbg(2, debug, sd, + "mt9v011: writing 0x%02x 0x%04x\n", buffer[0], value); + rc = i2c_master_send(c, buffer, 3); + if (rc != 3) + v4l2_dbg(0, debug, sd, + "i2c i/o error: rc == %d (should be 3)\n", rc); +} + + +struct i2c_reg_value { + unsigned char reg; + u16 value; +}; + +/* + * Values used at the original driver + * Some values are marked as Reserved at the datasheet + */ +static const struct i2c_reg_value mt9v011_init_default[] = { + { R0D_MT9V011_RESET, 0x0001 }, + { R0D_MT9V011_RESET, 0x0000 }, + + { R0C_MT9V011_SHUTTER_DELAY, 0x0000 }, + { R09_MT9V011_SHUTTER_WIDTH, 0x1fc }, + + { R0A_MT9V011_CLK_SPEED, 0x0000 }, + { R1E_MT9V011_DIGITAL_ZOOM, 0x0000 }, + + { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */ +}; + + +static u16 calc_mt9v011_gain(s16 lineargain) +{ + + u16 digitalgain = 0; + u16 analogmult = 0; + u16 analoginit = 0; + + if (lineargain < 0) + lineargain = 0; + + /* recommended minimum */ + lineargain += 0x0020; + + if (lineargain > 2047) + lineargain = 2047; + + if (lineargain > 1023) { + digitalgain = 3; + analogmult = 3; + analoginit = lineargain / 16; + } else if (lineargain > 511) { + digitalgain = 1; + analogmult = 3; + analoginit = lineargain / 8; + } else if (lineargain > 255) { + analogmult = 3; + analoginit = lineargain / 4; + } else if (lineargain > 127) { + analogmult = 1; + analoginit = lineargain / 2; + } else + analoginit = lineargain; + + return analoginit + (analogmult << 7) + (digitalgain << 9); + +} + +static void set_balance(struct v4l2_subdev *sd) +{ + struct mt9v011 *core = to_mt9v011(sd); + u16 green_gain, blue_gain, red_gain; + u16 exposure; + s16 bal; + + exposure = core->exposure; + + green_gain = calc_mt9v011_gain(core->global_gain); + + bal = core->global_gain; + bal += (core->blue_bal * core->global_gain / (1 << 7)); + blue_gain = calc_mt9v011_gain(bal); + + bal = core->global_gain; + bal += (core->red_bal * core->global_gain / (1 << 7)); + red_gain = calc_mt9v011_gain(bal); + + mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green_gain); + mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green_gain); + mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain); + mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); + mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure); +} + +static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned height, width, hblank, vblank, speed; + unsigned row_time, t_time; + u64 frames_per_ms; + unsigned tmp; + + height = mt9v011_read(sd, R03_MT9V011_HEIGHT); + width = mt9v011_read(sd, R04_MT9V011_WIDTH); + hblank = mt9v011_read(sd, R05_MT9V011_HBLANK); + vblank = mt9v011_read(sd, R06_MT9V011_VBLANK); + speed = mt9v011_read(sd, R0A_MT9V011_CLK_SPEED); + + row_time = (width + 113 + hblank) * (speed + 2); + t_time = row_time * (height + vblank + 1); + + frames_per_ms = core->xtal * 1000l; + do_div(frames_per_ms, t_time); + tmp = frames_per_ms; + + v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n", + tmp / 1000, tmp % 1000, t_time); + + if (numerator && denominator) { + *numerator = 1000; + *denominator = (u32)frames_per_ms; + } +} + +static u16 calc_speed(struct v4l2_subdev *sd, u32 numerator, u32 denominator) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned height, width, hblank, vblank; + unsigned row_time, line_time; + u64 t_time, speed; + + /* Avoid bogus calculus */ + if (!numerator || !denominator) + return 0; + + height = mt9v011_read(sd, R03_MT9V011_HEIGHT); + width = mt9v011_read(sd, R04_MT9V011_WIDTH); + hblank = mt9v011_read(sd, R05_MT9V011_HBLANK); + vblank = mt9v011_read(sd, R06_MT9V011_VBLANK); + + row_time = width + 113 + hblank; + line_time = height + vblank + 1; + + t_time = core->xtal * ((u64)numerator); + /* round to the closest value */ + t_time += denominator / 2; + do_div(t_time, denominator); + + speed = t_time; + do_div(speed, row_time * line_time); + + /* Avoid having a negative value for speed */ + if (speed < 2) + speed = 0; + else + speed -= 2; + + /* Avoid speed overflow */ + if (speed > 15) + return 15; + + return (u16)speed; +} + +static void set_res(struct v4l2_subdev *sd) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned vstart, hstart; + + /* + * The mt9v011 doesn't have scaling. So, in order to select the desired + * resolution, we're cropping at the middle of the sensor. + * hblank and vblank should be adjusted, in order to warrant that + * we'll preserve the line timings for 30 fps, no matter what resolution + * is selected. + * NOTE: datasheet says that width (and height) should be filled with + * width-1. However, this doesn't work, since one pixel per line will + * be missing. + */ + + hstart = 20 + (640 - core->width) / 2; + mt9v011_write(sd, R02_MT9V011_COLSTART, hstart); + mt9v011_write(sd, R04_MT9V011_WIDTH, core->width); + mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width); + + vstart = 8 + (480 - core->height) / 2; + mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart); + mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); + mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); + + calc_fps(sd, NULL, NULL); +}; + +static void set_read_mode(struct v4l2_subdev *sd) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned mode = 0x1000; + + if (core->hflip) + mode |= 0x4000; + + if (core->vflip) + mode |= 0x8000; + + mt9v011_write(sd, R20_MT9V011_READ_MODE, mode); +} + +static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mt9v011_init_default); i++) + mt9v011_write(sd, mt9v011_init_default[i].reg, + mt9v011_init_default[i].value); + + set_balance(sd); + set_res(sd); + set_read_mode(sd); + + return 0; +}; + +static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct mt9v011 *core = to_mt9v011(sd); + + v4l2_dbg(1, debug, sd, "g_ctrl called\n"); + + switch (ctrl->id) { + case V4L2_CID_GAIN: + ctrl->value = core->global_gain; + return 0; + case V4L2_CID_EXPOSURE: + ctrl->value = core->exposure; + return 0; + case V4L2_CID_RED_BALANCE: + ctrl->value = core->red_bal; + return 0; + case V4L2_CID_BLUE_BALANCE: + ctrl->value = core->blue_bal; + return 0; + case V4L2_CID_HFLIP: + ctrl->value = core->hflip ? 1 : 0; + return 0; + case V4L2_CID_VFLIP: + ctrl->value = core->vflip ? 1 : 0; + return 0; + } + return -EINVAL; +} + +static int mt9v011_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + int i; + + v4l2_dbg(1, debug, sd, "queryctrl called\n"); + + for (i = 0; i < ARRAY_SIZE(mt9v011_qctrl); i++) + if (qc->id && qc->id == mt9v011_qctrl[i].id) { + memcpy(qc, &(mt9v011_qctrl[i]), + sizeof(*qc)); + return 0; + } + + return -EINVAL; +} + + +static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct mt9v011 *core = to_mt9v011(sd); + u8 i, n; + n = ARRAY_SIZE(mt9v011_qctrl); + + for (i = 0; i < n; i++) { + if (ctrl->id != mt9v011_qctrl[i].id) + continue; + if (ctrl->value < mt9v011_qctrl[i].minimum || + ctrl->value > mt9v011_qctrl[i].maximum) + return -ERANGE; + v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n", + ctrl->id, ctrl->value); + break; + } + + switch (ctrl->id) { + case V4L2_CID_GAIN: + core->global_gain = ctrl->value; + break; + case V4L2_CID_EXPOSURE: + core->exposure = ctrl->value; + break; + case V4L2_CID_RED_BALANCE: + core->red_bal = ctrl->value; + break; + case V4L2_CID_BLUE_BALANCE: + core->blue_bal = ctrl->value; + break; + case V4L2_CID_HFLIP: + core->hflip = ctrl->value; + set_read_mode(sd); + return 0; + case V4L2_CID_VFLIP: + core->vflip = ctrl->value; + set_read_mode(sd); + return 0; + default: + return -EINVAL; + } + + set_balance(sd); + + return 0; +} + +static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, + enum v4l2_mbus_pixelcode *code) +{ + if (index > 0) + return -EINVAL; + + *code = V4L2_MBUS_FMT_SGRBG8_1X8; + return 0; +} + +static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + if (fmt->code != V4L2_MBUS_FMT_SGRBG8_1X8) + return -EINVAL; + + v4l_bound_align_image(&fmt->width, 48, 639, 1, + &fmt->height, 32, 480, 1, 0); + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + + return 0; +} + +static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memset(cp, 0, sizeof(struct v4l2_captureparm)); + cp->capability = V4L2_CAP_TIMEPERFRAME; + calc_fps(sd, + &cp->timeperframe.numerator, + &cp->timeperframe.denominator); + + return 0; +} + +static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + u16 speed; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (cp->extendedmode != 0) + return -EINVAL; + + speed = calc_speed(sd, tpf->numerator, tpf->denominator); + + mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed); + v4l2_dbg(1, debug, sd, "Setting speed to %d\n", speed); + + /* Recalculate and update fps info */ + calc_fps(sd, &tpf->numerator, &tpf->denominator); + + return 0; +} + +static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + struct mt9v011 *core = to_mt9v011(sd); + int rc; + + rc = mt9v011_try_mbus_fmt(sd, fmt); + if (rc < 0) + return -EINVAL; + + core->width = fmt->width; + core->height = fmt->height; + + set_res(sd); + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9v011_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + reg->val = mt9v011_read(sd, reg->reg & 0xff); + reg->size = 2; + + return 0; +} + +static int mt9v011_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + mt9v011_write(sd, reg->reg & 0xff, reg->val & 0xffff); + + return 0; +} +#endif + +static int mt9v011_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + u16 version; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9V011, + version); +} + +static const struct v4l2_subdev_core_ops mt9v011_core_ops = { + .queryctrl = mt9v011_queryctrl, + .g_ctrl = mt9v011_g_ctrl, + .s_ctrl = mt9v011_s_ctrl, + .reset = mt9v011_reset, + .g_chip_ident = mt9v011_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9v011_g_register, + .s_register = mt9v011_s_register, +#endif +}; + +static const struct v4l2_subdev_video_ops mt9v011_video_ops = { + .enum_mbus_fmt = mt9v011_enum_mbus_fmt, + .try_mbus_fmt = mt9v011_try_mbus_fmt, + .s_mbus_fmt = mt9v011_s_mbus_fmt, + .g_parm = mt9v011_g_parm, + .s_parm = mt9v011_s_parm, +}; + +static const struct v4l2_subdev_ops mt9v011_ops = { + .core = &mt9v011_core_ops, + .video = &mt9v011_video_ops, +}; + + +/**************************************************************************** + I2C Client & Driver + ****************************************************************************/ + +static int mt9v011_probe(struct i2c_client *c, + const struct i2c_device_id *id) +{ + u16 version; + struct mt9v011 *core; + struct v4l2_subdev *sd; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(c->adapter, + I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + return -EIO; + + core = kzalloc(sizeof(struct mt9v011), GFP_KERNEL); + if (!core) + return -ENOMEM; + + sd = &core->sd; + v4l2_i2c_subdev_init(sd, c, &mt9v011_ops); + + /* Check if the sensor is really a MT9V011 */ + version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION); + if ((version != MT9V011_VERSION) && + (version != MT9V011_REV_B_VERSION)) { + v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n", + version); + kfree(core); + return -EINVAL; + } + + core->global_gain = 0x0024; + core->exposure = 0x01fc; + core->width = 640; + core->height = 480; + core->xtal = 27000000; /* Hz */ + + if (c->dev.platform_data) { + struct mt9v011_platform_data *pdata = c->dev.platform_data; + + core->xtal = pdata->xtal; + v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n", + core->xtal / 1000000, (core->xtal / 1000) % 1000); + } + + v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n", + c->addr << 1, c->adapter->name, version); + + return 0; +} + +static int mt9v011_remove(struct i2c_client *c) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(c); + + v4l2_dbg(1, debug, sd, + "mt9v011.c: removing mt9v011 adapter on address 0x%x\n", + c->addr << 1); + + v4l2_device_unregister_subdev(sd); + kfree(to_mt9v011(sd)); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id mt9v011_id[] = { + { "mt9v011", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9v011_id); + +static struct i2c_driver mt9v011_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "mt9v011", + }, + .probe = mt9v011_probe, + .remove = mt9v011_remove, + .id_table = mt9v011_id, +}; + +static __init int init_mt9v011(void) +{ + return i2c_add_driver(&mt9v011_driver); +} + +static __exit void exit_mt9v011(void) +{ + i2c_del_driver(&mt9v011_driver); +} + +module_init(init_mt9v011); +module_exit(exit_mt9v011); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v022.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v022.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v022.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v022.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,967 @@ +/* + * Driver for MT9V022 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c + * The platform has to define ctruct i2c_board_info objects and link to them + * from struct soc_camera_link + */ + +static char *sensor_type; +module_param(sensor_type, charp, S_IRUGO); +MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); + +/* mt9v022 selected register addresses */ +#define MT9V022_CHIP_VERSION 0x00 +#define MT9V022_COLUMN_START 0x01 +#define MT9V022_ROW_START 0x02 +#define MT9V022_WINDOW_HEIGHT 0x03 +#define MT9V022_WINDOW_WIDTH 0x04 +#define MT9V022_HORIZONTAL_BLANKING 0x05 +#define MT9V022_VERTICAL_BLANKING 0x06 +#define MT9V022_CHIP_CONTROL 0x07 +#define MT9V022_SHUTTER_WIDTH1 0x08 +#define MT9V022_SHUTTER_WIDTH2 0x09 +#define MT9V022_SHUTTER_WIDTH_CTRL 0x0a +#define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b +#define MT9V022_RESET 0x0c +#define MT9V022_READ_MODE 0x0d +#define MT9V022_MONITOR_MODE 0x0e +#define MT9V022_PIXEL_OPERATION_MODE 0x0f +#define MT9V022_LED_OUT_CONTROL 0x1b +#define MT9V022_ADC_MODE_CONTROL 0x1c +#define MT9V022_ANALOG_GAIN 0x35 +#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 +#define MT9V022_PIXCLK_FV_LV 0x74 +#define MT9V022_DIGITAL_TEST_PATTERN 0x7f +#define MT9V022_AEC_AGC_ENABLE 0xAF +#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD + +/* Progressive scan, master, defaults */ +#define MT9V022_CHIP_CONTROL_DEFAULT 0x188 + +#define MT9V022_MAX_WIDTH 752 +#define MT9V022_MAX_HEIGHT 480 +#define MT9V022_MIN_WIDTH 48 +#define MT9V022_MIN_HEIGHT 32 +#define MT9V022_COLUMN_SKIP 1 +#define MT9V022_ROW_SKIP 4 + +/* MT9V022 has only one fixed colorspace per pixelcode */ +struct mt9v022_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct mt9v022_datafmt *mt9v022_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct mt9v022_datafmt mt9v022_colour_fmts[] = { + /* + * Order important: first natively supported, + * second supported with a GPIO extender + */ + {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, +}; + +static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { + /* Order important - see above */ + {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, +}; + +struct mt9v022 { + struct v4l2_subdev subdev; + struct v4l2_rect rect; /* Sensor window */ + const struct mt9v022_datafmt *fmt; + const struct mt9v022_datafmt *fmts; + int num_fmts; + int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ + u16 chip_control; + unsigned short y_skip_top; /* Lines to skip at the top */ +}; + +static struct mt9v022 *to_mt9v022(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct mt9v022, subdev); +} + +static int reg_read(struct i2c_client *client, const u8 reg) +{ + s32 data = i2c_smbus_read_word_data(client, reg); + return data < 0 ? data : swab16(data); +} + +static int reg_write(struct i2c_client *client, const u8 reg, + const u16 data) +{ + return i2c_smbus_write_word_data(client, reg, swab16(data)); +} + +static int reg_set(struct i2c_client *client, const u8 reg, + const u16 data) +{ + int ret; + + ret = reg_read(client, reg); + if (ret < 0) + return ret; + return reg_write(client, reg, ret | data); +} + +static int reg_clear(struct i2c_client *client, const u8 reg, + const u16 data) +{ + int ret; + + ret = reg_read(client, reg); + if (ret < 0) + return ret; + return reg_write(client, reg, ret & ~data); +} + +static int mt9v022_init(struct i2c_client *client) +{ + struct mt9v022 *mt9v022 = to_mt9v022(client); + int ret; + + /* + * Almost the default mode: master, parallel, simultaneous, and an + * undocumented bit 0x200, which is present in table 7, but not in 8, + * plus snapshot mode to disable scan for now + */ + mt9v022->chip_control |= 0x10; + ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); + if (!ret) + ret = reg_write(client, MT9V022_READ_MODE, 0x300); + + /* All defaults */ + if (!ret) + /* AEC, AGC on */ + ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); + if (!ret) + ret = reg_write(client, MT9V022_ANALOG_GAIN, 16); + if (!ret) + ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480); + if (!ret) + ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); + if (!ret) + /* default - auto */ + ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); + if (!ret) + ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); + + return ret; +} + +static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + if (enable) + /* Switch to master "normal" mode */ + mt9v022->chip_control &= ~0x10; + else + /* Switch to snapshot mode */ + mt9v022->chip_control |= 0x10; + + if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) + return -EIO; + return 0; +} + +static int mt9v022_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9v022 *mt9v022 = to_mt9v022(client); + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; + int ret; + u16 pixclk = 0; + + /* Only one width bit may be set */ + if (!is_power_of_2(width_flag)) + return -EINVAL; + + if (icl->set_bus_param) { + ret = icl->set_bus_param(icl, width_flag); + if (ret) + return ret; + } else { + /* + * Without board specific bus width settings we only support the + * sensors native bus width + */ + if (width_flag != SOCAM_DATAWIDTH_10) + return -EINVAL; + } + + flags = soc_camera_apply_sensor_flags(icl, flags); + + if (flags & SOCAM_PCLK_SAMPLE_FALLING) + pixclk |= 0x10; + + if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH)) + pixclk |= 0x1; + + if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH)) + pixclk |= 0x2; + + ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); + if (ret < 0) + return ret; + + if (!(flags & SOCAM_MASTER)) + mt9v022->chip_control &= ~0x8; + + ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", + pixclk, mt9v022->chip_control); + + return 0; +} + +static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned int flags = SOCAM_MASTER | SOCAM_SLAVE | + SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | + SOCAM_DATA_ACTIVE_HIGH; + + if (icl->query_bus_param) + flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; + else + flags |= SOCAM_DATAWIDTH_10; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + struct v4l2_rect rect = a->c; + int ret; + + /* Bayer format - even size lengths */ + if (mt9v022->fmts == mt9v022_colour_fmts) { + rect.width = ALIGN(rect.width, 2); + rect.height = ALIGN(rect.height, 2); + /* Let the user play with the starting pixel */ + } + + soc_camera_limit_side(&rect.left, &rect.width, + MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH); + + soc_camera_limit_side(&rect.top, &rect.height, + MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT); + + /* Like in example app. Contradicts the datasheet though */ + ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); + if (ret >= 0) { + if (ret & 1) /* Autoexposure */ + ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, + rect.height + mt9v022->y_skip_top + 43); + else + ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, + rect.height + mt9v022->y_skip_top + 43); + } + /* Setup frame format: defaults apart from width and height */ + if (!ret) + ret = reg_write(client, MT9V022_COLUMN_START, rect.left); + if (!ret) + ret = reg_write(client, MT9V022_ROW_START, rect.top); + if (!ret) + /* + * Default 94, Phytec driver says: + * "width + horizontal blank >= 660" + */ + ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, + rect.width > 660 - 43 ? 43 : + 660 - rect.width); + if (!ret) + ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); + if (!ret) + ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); + if (!ret) + ret = reg_write(client, MT9V022_WINDOW_HEIGHT, + rect.height + mt9v022->y_skip_top); + + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height); + + mt9v022->rect = rect; + + return 0; +} + +static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + a->c = mt9v022->rect; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = MT9V022_COLUMN_SKIP; + a->bounds.top = MT9V022_ROW_SKIP; + a->bounds.width = MT9V022_MAX_WIDTH; + a->bounds.height = MT9V022_MAX_HEIGHT; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int mt9v022_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + mf->width = mt9v022->rect.width; + mf->height = mt9v022->rect.height; + mf->code = mt9v022->fmt->code; + mf->colorspace = mt9v022->fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9v022_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + struct v4l2_crop a = { + .c = { + .left = mt9v022->rect.left, + .top = mt9v022->rect.top, + .width = mf->width, + .height = mf->height, + }, + }; + int ret; + + /* + * The caller provides a supported format, as verified per call to + * icd->try_fmt(), datawidth is from our supported format list + */ + switch (mf->code) { + case V4L2_MBUS_FMT_Y8_1X8: + case V4L2_MBUS_FMT_Y10_1X10: + if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) + return -EINVAL; + break; + case V4L2_MBUS_FMT_SBGGR8_1X8: + case V4L2_MBUS_FMT_SBGGR10_1X10: + if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) + return -EINVAL; + break; + default: + return -EINVAL; + } + + /* No support for scaling on this camera, just crop. */ + ret = mt9v022_s_crop(sd, &a); + if (!ret) { + mf->width = mt9v022->rect.width; + mf->height = mt9v022->rect.height; + mt9v022->fmt = mt9v022_find_datafmt(mf->code, + mt9v022->fmts, mt9v022->num_fmts); + mf->colorspace = mt9v022->fmt->colorspace; + } + + return ret; +} + +static int mt9v022_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + const struct mt9v022_datafmt *fmt; + int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + mf->code == V4L2_MBUS_FMT_SBGGR10_1X10; + + v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH, + MT9V022_MAX_WIDTH, align, + &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top, + MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0); + + fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts, + mt9v022->num_fmts); + if (!fmt) { + fmt = mt9v022->fmt; + mf->code = fmt->code; + } + + mf->colorspace = fmt->colorspace; + + return 0; +} + +static int mt9v022_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match.addr != client->addr) + return -ENODEV; + + id->ident = mt9v022->model; + id->revision = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9v022_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + reg->size = 2; + reg->val = reg_read(client, reg->reg); + + if (reg->val > 0xffff) + return -EIO; + + return 0; +} + +static int mt9v022_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) + return -EINVAL; + + if (reg->match.addr != client->addr) + return -ENODEV; + + if (reg_write(client, reg->reg, reg->val) < 0) + return -EIO; + + return 0; +} +#endif + +static const struct v4l2_queryctrl mt9v022_controls[] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Analog Gain", + .minimum = 64, + .maximum = 127, + .step = 1, + .default_value = 64, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 1, + .maximum = 255, + .step = 1, + .default_value = 255, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + } +}; + +static struct soc_camera_ops mt9v022_ops = { + .set_bus_param = mt9v022_set_bus_param, + .query_bus_param = mt9v022_query_bus_param, + .controls = mt9v022_controls, + .num_controls = ARRAY_SIZE(mt9v022_controls), +}; + +static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct v4l2_queryctrl *qctrl; + unsigned long range; + int data; + + qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + data = reg_read(client, MT9V022_READ_MODE); + if (data < 0) + return -EIO; + ctrl->value = !!(data & 0x10); + break; + case V4L2_CID_HFLIP: + data = reg_read(client, MT9V022_READ_MODE); + if (data < 0) + return -EIO; + ctrl->value = !!(data & 0x20); + break; + case V4L2_CID_EXPOSURE_AUTO: + data = reg_read(client, MT9V022_AEC_AGC_ENABLE); + if (data < 0) + return -EIO; + ctrl->value = !!(data & 0x1); + break; + case V4L2_CID_AUTOGAIN: + data = reg_read(client, MT9V022_AEC_AGC_ENABLE); + if (data < 0) + return -EIO; + ctrl->value = !!(data & 0x2); + break; + case V4L2_CID_GAIN: + data = reg_read(client, MT9V022_ANALOG_GAIN); + if (data < 0) + return -EIO; + + range = qctrl->maximum - qctrl->minimum; + ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; + + break; + case V4L2_CID_EXPOSURE: + data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); + if (data < 0) + return -EIO; + + range = qctrl->maximum - qctrl->minimum; + ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; + + break; + } + return 0; +} + +static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int data; + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct v4l2_queryctrl *qctrl; + + qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); + if (!qctrl) + return -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (ctrl->value) + data = reg_set(client, MT9V022_READ_MODE, 0x10); + else + data = reg_clear(client, MT9V022_READ_MODE, 0x10); + if (data < 0) + return -EIO; + break; + case V4L2_CID_HFLIP: + if (ctrl->value) + data = reg_set(client, MT9V022_READ_MODE, 0x20); + else + data = reg_clear(client, MT9V022_READ_MODE, 0x20); + if (data < 0) + return -EIO; + break; + case V4L2_CID_GAIN: + /* mt9v022 has minimum == default */ + if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) + return -EINVAL; + else { + unsigned long range = qctrl->maximum - qctrl->minimum; + /* Valid values 16 to 64, 32 to 64 must be even. */ + unsigned long gain = ((ctrl->value - qctrl->minimum) * + 48 + range / 2) / range + 16; + if (gain >= 32) + gain &= ~1; + /* + * The user wants to set gain manually, hope, she + * knows, what she's doing... Switch AGC off. + */ + + if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) + return -EIO; + + dev_dbg(&client->dev, "Setting gain from %d to %lu\n", + reg_read(client, MT9V022_ANALOG_GAIN), gain); + if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) + return -EIO; + } + break; + case V4L2_CID_EXPOSURE: + /* mt9v022 has maximum == default */ + if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) + return -EINVAL; + else { + unsigned long range = qctrl->maximum - qctrl->minimum; + unsigned long shutter = ((ctrl->value - qctrl->minimum) * + 479 + range / 2) / range + 1; + /* + * The user wants to set shutter width manually, hope, + * she knows, what she's doing... Switch AEC off. + */ + + if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) + return -EIO; + + dev_dbg(&client->dev, "Shutter width from %d to %lu\n", + reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), + shutter); + if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, + shutter) < 0) + return -EIO; + } + break; + case V4L2_CID_AUTOGAIN: + if (ctrl->value) + data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); + else + data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); + if (data < 0) + return -EIO; + break; + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->value) + data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); + else + data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); + if (data < 0) + return -EIO; + break; + } + return 0; +} + +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ +static int mt9v022_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + struct mt9v022 *mt9v022 = to_mt9v022(client); + struct soc_camera_link *icl = to_soc_camera_link(icd); + s32 data; + int ret; + unsigned long flags; + + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + /* Read out the chip version register */ + data = reg_read(client, MT9V022_CHIP_VERSION); + + /* must be 0x1311 or 0x1313 */ + if (data != 0x1311 && data != 0x1313) { + ret = -ENODEV; + dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n", + data); + goto ei2c; + } + + /* Soft reset */ + ret = reg_write(client, MT9V022_RESET, 1); + if (ret < 0) + goto ei2c; + /* 15 clock cycles */ + udelay(200); + if (reg_read(client, MT9V022_RESET)) { + dev_err(&client->dev, "Resetting MT9V022 failed!\n"); + if (ret > 0) + ret = -EIO; + goto ei2c; + } + + /* Set monochrome or colour sensor type */ + if (sensor_type && (!strcmp("colour", sensor_type) || + !strcmp("color", sensor_type))) { + ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); + mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; + mt9v022->fmts = mt9v022_colour_fmts; + } else { + ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); + mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; + mt9v022->fmts = mt9v022_monochrome_fmts; + } + + if (ret < 0) + goto ei2c; + + mt9v022->num_fmts = 0; + + /* + * This is a 10bit sensor, so by default we only allow 10bit. + * The platform may support different bus widths due to + * different routing of the data lines. + */ + if (icl->query_bus_param) + flags = icl->query_bus_param(icl); + else + flags = SOCAM_DATAWIDTH_10; + + if (flags & SOCAM_DATAWIDTH_10) + mt9v022->num_fmts++; + else + mt9v022->fmts++; + + if (flags & SOCAM_DATAWIDTH_8) + mt9v022->num_fmts++; + + mt9v022->fmt = &mt9v022->fmts[0]; + + dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", + data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? + "monochrome" : "colour"); + + ret = mt9v022_init(client); + if (ret < 0) + dev_err(&client->dev, "Failed to initialise the camera\n"); + +ei2c: + return ret; +} + +static void mt9v022_video_remove(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + + dev_dbg(&icd->dev, "Video removed: %p, %p\n", + icd->dev.parent, icd->vdev); + if (icl->free_bus) + icl->free_bus(icl); +} + +static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + *lines = mt9v022->y_skip_top; + + return 0; +} + +static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { + .g_ctrl = mt9v022_g_ctrl, + .s_ctrl = mt9v022_s_ctrl, + .g_chip_ident = mt9v022_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9v022_g_register, + .s_register = mt9v022_s_register, +#endif +}; + +static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9v022 *mt9v022 = to_mt9v022(client); + + if (index >= mt9v022->num_fmts) + return -EINVAL; + + *code = mt9v022->fmts[index].code; + return 0; +} + +static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { + .s_stream = mt9v022_s_stream, + .s_mbus_fmt = mt9v022_s_fmt, + .g_mbus_fmt = mt9v022_g_fmt, + .try_mbus_fmt = mt9v022_try_fmt, + .s_crop = mt9v022_s_crop, + .g_crop = mt9v022_g_crop, + .cropcap = mt9v022_cropcap, + .enum_mbus_fmt = mt9v022_enum_fmt, +}; + +static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { + .g_skip_top_lines = mt9v022_g_skip_top_lines, +}; + +static struct v4l2_subdev_ops mt9v022_subdev_ops = { + .core = &mt9v022_subdev_core_ops, + .video = &mt9v022_subdev_video_ops, + .sensor = &mt9v022_subdev_sensor_ops, +}; + +static int mt9v022_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9v022 *mt9v022; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl; + int ret; + + if (!icd) { + dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "MT9V022 driver needs platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL); + if (!mt9v022) + return -ENOMEM; + + v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); + + mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; + + icd->ops = &mt9v022_ops; + /* + * MT9V022 _really_ corrupts the first read out line. + * TODO: verify on i.MX31 + */ + mt9v022->y_skip_top = 1; + mt9v022->rect.left = MT9V022_COLUMN_SKIP; + mt9v022->rect.top = MT9V022_ROW_SKIP; + mt9v022->rect.width = MT9V022_MAX_WIDTH; + mt9v022->rect.height = MT9V022_MAX_HEIGHT; + + ret = mt9v022_video_probe(icd, client); + if (ret) { + icd->ops = NULL; + kfree(mt9v022); + } + + return ret; +} + +static int mt9v022_remove(struct i2c_client *client) +{ + struct mt9v022 *mt9v022 = to_mt9v022(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + mt9v022_video_remove(icd); + kfree(mt9v022); + + return 0; +} +static const struct i2c_device_id mt9v022_id[] = { + { "mt9v022", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9v022_id); + +static struct i2c_driver mt9v022_i2c_driver = { + .driver = { + .name = "mt9v022", + }, + .probe = mt9v022_probe, + .remove = mt9v022_remove, + .id_table = mt9v022_id, +}; + +static int __init mt9v022_mod_init(void) +{ + return i2c_add_driver(&mt9v022_i2c_driver); +} + +static void __exit mt9v022_mod_exit(void) +{ + i2c_del_driver(&mt9v022_i2c_driver); +} + +module_init(mt9v022_mod_init); +module_exit(mt9v022_mod_exit); + +MODULE_DESCRIPTION("Micron MT9V022 Camera driver"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v032.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v032.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v032.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mt9v032.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,773 @@ +/* + * Driver for MT9V032 CMOS Image Sensor from Micron + * + * Copyright (C) 2010, Laurent Pinchart + * + * Based on the MT9M001 driver, + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MT9V032_PIXEL_ARRAY_HEIGHT 492 +#define MT9V032_PIXEL_ARRAY_WIDTH 782 + +#define MT9V032_CHIP_VERSION 0x00 +#define MT9V032_CHIP_ID_REV1 0x1311 +#define MT9V032_CHIP_ID_REV3 0x1313 +#define MT9V032_ROW_START 0x01 +#define MT9V032_ROW_START_MIN 4 +#define MT9V032_ROW_START_DEF 10 +#define MT9V032_ROW_START_MAX 482 +#define MT9V032_COLUMN_START 0x02 +#define MT9V032_COLUMN_START_MIN 1 +#define MT9V032_COLUMN_START_DEF 2 +#define MT9V032_COLUMN_START_MAX 752 +#define MT9V032_WINDOW_HEIGHT 0x03 +#define MT9V032_WINDOW_HEIGHT_MIN 1 +#define MT9V032_WINDOW_HEIGHT_DEF 480 +#define MT9V032_WINDOW_HEIGHT_MAX 480 +#define MT9V032_WINDOW_WIDTH 0x04 +#define MT9V032_WINDOW_WIDTH_MIN 1 +#define MT9V032_WINDOW_WIDTH_DEF 752 +#define MT9V032_WINDOW_WIDTH_MAX 752 +#define MT9V032_HORIZONTAL_BLANKING 0x05 +#define MT9V032_HORIZONTAL_BLANKING_MIN 43 +#define MT9V032_HORIZONTAL_BLANKING_MAX 1023 +#define MT9V032_VERTICAL_BLANKING 0x06 +#define MT9V032_VERTICAL_BLANKING_MIN 4 +#define MT9V032_VERTICAL_BLANKING_MAX 3000 +#define MT9V032_CHIP_CONTROL 0x07 +#define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3) +#define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7) +#define MT9V032_CHIP_CONTROL_SEQUENTIAL (1 << 8) +#define MT9V032_SHUTTER_WIDTH1 0x08 +#define MT9V032_SHUTTER_WIDTH2 0x09 +#define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a +#define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b +#define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1 +#define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480 +#define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767 +#define MT9V032_RESET 0x0c +#define MT9V032_READ_MODE 0x0d +#define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0) +#define MT9V032_READ_MODE_ROW_BIN_SHIFT 0 +#define MT9V032_READ_MODE_COLUMN_BIN_MASK (3 << 2) +#define MT9V032_READ_MODE_COLUMN_BIN_SHIFT 2 +#define MT9V032_READ_MODE_ROW_FLIP (1 << 4) +#define MT9V032_READ_MODE_COLUMN_FLIP (1 << 5) +#define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6) +#define MT9V032_READ_MODE_DARK_ROWS (1 << 7) +#define MT9V032_PIXEL_OPERATION_MODE 0x0f +#define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2) +#define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6) +#define MT9V032_ANALOG_GAIN 0x35 +#define MT9V032_ANALOG_GAIN_MIN 16 +#define MT9V032_ANALOG_GAIN_DEF 16 +#define MT9V032_ANALOG_GAIN_MAX 64 +#define MT9V032_MAX_ANALOG_GAIN 0x36 +#define MT9V032_MAX_ANALOG_GAIN_MAX 127 +#define MT9V032_FRAME_DARK_AVERAGE 0x42 +#define MT9V032_DARK_AVG_THRESH 0x46 +#define MT9V032_DARK_AVG_LOW_THRESH_MASK (255 << 0) +#define MT9V032_DARK_AVG_LOW_THRESH_SHIFT 0 +#define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8) +#define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8 +#define MT9V032_ROW_NOISE_CORR_CONTROL 0x70 +#define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5) +#define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7) +#define MT9V032_PIXEL_CLOCK 0x74 +#define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0) +#define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1) +#define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2) +#define MT9V032_PIXEL_CLOCK_CONT_LINE (1 << 3) +#define MT9V032_PIXEL_CLOCK_INV_PXL_CLK (1 << 4) +#define MT9V032_TEST_PATTERN 0x7f +#define MT9V032_TEST_PATTERN_DATA_MASK (1023 << 0) +#define MT9V032_TEST_PATTERN_DATA_SHIFT 0 +#define MT9V032_TEST_PATTERN_USE_DATA (1 << 10) +#define MT9V032_TEST_PATTERN_GRAY_MASK (3 << 11) +#define MT9V032_TEST_PATTERN_GRAY_NONE (0 << 11) +#define MT9V032_TEST_PATTERN_GRAY_VERTICAL (1 << 11) +#define MT9V032_TEST_PATTERN_GRAY_HORIZONTAL (2 << 11) +#define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11) +#define MT9V032_TEST_PATTERN_ENABLE (1 << 13) +#define MT9V032_TEST_PATTERN_FLIP (1 << 14) +#define MT9V032_AEC_AGC_ENABLE 0xaf +#define MT9V032_AEC_ENABLE (1 << 0) +#define MT9V032_AGC_ENABLE (1 << 1) +#define MT9V032_THERMAL_INFO 0xc1 + +struct mt9v032 { + struct v4l2_subdev subdev; + struct media_pad pad; + + struct v4l2_mbus_framefmt format; + struct v4l2_rect crop; + + struct v4l2_ctrl_handler ctrls; + + struct mutex power_lock; + int power_count; + + struct mt9v032_platform_data *pdata; + u16 chip_control; + u16 aec_agc; +}; + +static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mt9v032, subdev); +} + +static int mt9v032_read(struct i2c_client *client, const u8 reg) +{ + s32 data = i2c_smbus_read_word_data(client, reg); + dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__, + swab16(data), reg); + return data < 0 ? data : swab16(data); +} + +static int mt9v032_write(struct i2c_client *client, const u8 reg, + const u16 data) +{ + dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__, + data, reg); + return i2c_smbus_write_word_data(client, reg, swab16(data)); +} + +static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); + u16 value = (mt9v032->chip_control & ~clear) | set; + int ret; + + ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value); + if (ret < 0) + return ret; + + mt9v032->chip_control = value; + return 0; +} + +static int +mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); + u16 value = mt9v032->aec_agc; + int ret; + + if (enable) + value |= which; + else + value &= ~which; + + ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value); + if (ret < 0) + return ret; + + mt9v032->aec_agc = value; + return 0; +} + +static int mt9v032_power_on(struct mt9v032 *mt9v032) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); + int ret; + + if (mt9v032->pdata->set_clock) { + mt9v032->pdata->set_clock(&mt9v032->subdev, 25000000); + udelay(1); + } + + /* Reset the chip and stop data read out */ + ret = mt9v032_write(client, MT9V032_RESET, 1); + if (ret < 0) + return ret; + + ret = mt9v032_write(client, MT9V032_RESET, 0); + if (ret < 0) + return ret; + + return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0); +} + +static void mt9v032_power_off(struct mt9v032 *mt9v032) +{ + if (mt9v032->pdata->set_clock) + mt9v032->pdata->set_clock(&mt9v032->subdev, 0); +} + +static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); + int ret; + + if (!on) { + mt9v032_power_off(mt9v032); + return 0; + } + + ret = mt9v032_power_on(mt9v032); + if (ret < 0) + return ret; + + /* Configure the pixel clock polarity */ + if (mt9v032->pdata && mt9v032->pdata->clk_pol) { + ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK, + MT9V032_PIXEL_CLOCK_INV_PXL_CLK); + if (ret < 0) + return ret; + } + + /* Disable the noise correction algorithm and restore the controls. */ + ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0); + if (ret < 0) + return ret; + + return v4l2_ctrl_handler_setup(&mt9v032->ctrls); +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev video operations + */ + +static struct v4l2_mbus_framefmt * +__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &mt9v032->format; + default: + return NULL; + } +} + +static struct v4l2_rect * +__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_crop(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &mt9v032->crop; + default: + return NULL; + } +} + +static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable) +{ + const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE + | MT9V032_CHIP_CONTROL_DOUT_ENABLE + | MT9V032_CHIP_CONTROL_SEQUENTIAL; + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + struct v4l2_mbus_framefmt *format = &mt9v032->format; + struct v4l2_rect *crop = &mt9v032->crop; + unsigned int hratio; + unsigned int vratio; + int ret; + + if (!enable) + return mt9v032_set_chip_control(mt9v032, mode, 0); + + /* Configure the window size and row/column bin */ + hratio = DIV_ROUND_CLOSEST(crop->width, format->width); + vratio = DIV_ROUND_CLOSEST(crop->height, format->height); + + ret = mt9v032_write(client, MT9V032_READ_MODE, + (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT | + (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT); + if (ret < 0) + return ret; + + ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left); + if (ret < 0) + return ret; + + ret = mt9v032_write(client, MT9V032_ROW_START, crop->top); + if (ret < 0) + return ret; + + ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width); + if (ret < 0) + return ret; + + ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height); + if (ret < 0) + return ret; + + ret = mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, + max(43, 660 - crop->width)); + if (ret < 0) + return ret; + + /* Switch to master "normal" mode */ + return mt9v032_set_chip_control(mt9v032, 0, mode); +} + +static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = V4L2_MBUS_FMT_SGRBG10_1X10; + return 0; +} + +static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index; + fse->max_width = fse->min_width; + fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index; + fse->max_height = fse->min_height; + + return 0; +} + +static int mt9v032_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) +{ + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + + format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad, + format->which); + return 0; +} + +static int mt9v032_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) +{ + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + struct v4l2_mbus_framefmt *__format; + struct v4l2_rect *__crop; + unsigned int width; + unsigned int height; + unsigned int hratio; + unsigned int vratio; + + __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad, + format->which); + + /* Clamp the width and height to avoid dividing by zero. */ + width = clamp_t(unsigned int, ALIGN(format->format.width, 2), + max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN), + __crop->width); + height = clamp_t(unsigned int, ALIGN(format->format.height, 2), + max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN), + __crop->height); + + hratio = DIV_ROUND_CLOSEST(__crop->width, width); + vratio = DIV_ROUND_CLOSEST(__crop->height, height); + + __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad, + format->which); + __format->width = __crop->width / hratio; + __format->height = __crop->height / vratio; + + format->format = *__format; + + return 0; +} + +static int mt9v032_get_crop(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + + crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad, + crop->which); + return 0; +} + +static int mt9v032_set_crop(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + struct v4l2_mbus_framefmt *__format; + struct v4l2_rect *__crop; + struct v4l2_rect rect; + + /* Clamp the crop rectangle boundaries and align them to a multiple of 2 + * pixels. + */ + rect.left = clamp(ALIGN(crop->rect.left, 2), + MT9V032_COLUMN_START_MIN, + MT9V032_COLUMN_START_MAX); + rect.top = clamp(ALIGN(crop->rect.top, 2), + MT9V032_ROW_START_MIN, + MT9V032_ROW_START_MAX); + rect.width = clamp(ALIGN(crop->rect.width, 2), + MT9V032_WINDOW_WIDTH_MIN, + MT9V032_WINDOW_WIDTH_MAX); + rect.height = clamp(ALIGN(crop->rect.height, 2), + MT9V032_WINDOW_HEIGHT_MIN, + MT9V032_WINDOW_HEIGHT_MAX); + + rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left); + rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); + + __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which); + + if (rect.width != __crop->width || rect.height != __crop->height) { + /* Reset the output image size if the crop rectangle size has + * been modified. + */ + __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad, + crop->which); + __format->width = rect.width; + __format->height = rect.height; + } + + *__crop = rect; + crop->rect = rect; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev control operations + */ + +#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) + +static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9v032 *mt9v032 = + container_of(ctrl->handler, struct mt9v032, ctrls); + struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); + u16 data; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + return mt9v032_update_aec_agc(mt9v032, MT9V032_AGC_ENABLE, + ctrl->val); + + case V4L2_CID_GAIN: + return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val); + + case V4L2_CID_EXPOSURE_AUTO: + return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE, + ctrl->val); + + case V4L2_CID_EXPOSURE: + return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH, + ctrl->val); + + case V4L2_CID_TEST_PATTERN: + switch (ctrl->val) { + case 0: + data = 0; + break; + case 1: + data = MT9V032_TEST_PATTERN_GRAY_VERTICAL + | MT9V032_TEST_PATTERN_ENABLE; + break; + case 2: + data = MT9V032_TEST_PATTERN_GRAY_HORIZONTAL + | MT9V032_TEST_PATTERN_ENABLE; + break; + case 3: + data = MT9V032_TEST_PATTERN_GRAY_DIAGONAL + | MT9V032_TEST_PATTERN_ENABLE; + break; + default: + data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT) + | MT9V032_TEST_PATTERN_USE_DATA + | MT9V032_TEST_PATTERN_ENABLE + | MT9V032_TEST_PATTERN_FLIP; + break; + } + + return mt9v032_write(client, MT9V032_TEST_PATTERN, data); + } + + return 0; +} + +static struct v4l2_ctrl_ops mt9v032_ctrl_ops = { + .s_ctrl = mt9v032_s_ctrl, +}; + +static const struct v4l2_ctrl_config mt9v032_ctrls[] = { + { + .ops = &mt9v032_ctrl_ops, + .id = V4L2_CID_TEST_PATTERN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Test pattern", + .min = 0, + .max = 1023, + .step = 1, + .def = 0, + .flags = 0, + } +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev core operations + */ + +static int mt9v032_set_power(struct v4l2_subdev *subdev, int on) +{ + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + int ret = 0; + + mutex_lock(&mt9v032->power_lock); + + /* If the power count is modified from 0 to != 0 or from != 0 to 0, + * update the power state. + */ + if (mt9v032->power_count == !on) { + ret = __mt9v032_set_power(mt9v032, !!on); + if (ret < 0) + goto done; + } + + /* Update the power count. */ + mt9v032->power_count += on ? 1 : -1; + WARN_ON(mt9v032->power_count < 0); + +done: + mutex_unlock(&mt9v032->power_lock); + return ret; +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev internal operations + */ + +static int mt9v032_registered(struct v4l2_subdev *subdev) +{ + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + s32 data; + int ret; + + dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n", + client->addr); + + ret = mt9v032_power_on(mt9v032); + if (ret < 0) { + dev_err(&client->dev, "MT9V032 power up failed\n"); + return ret; + } + + /* Read and check the sensor version */ + data = mt9v032_read(client, MT9V032_CHIP_VERSION); + if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) { + dev_err(&client->dev, "MT9V032 not detected, wrong version " + "0x%04x\n", data); + return -ENODEV; + } + + mt9v032_power_off(mt9v032); + + dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n", + client->addr); + + return ret; +} + +static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + crop = v4l2_subdev_get_try_crop(fh, 0); + crop->left = MT9V032_COLUMN_START_DEF; + crop->top = MT9V032_ROW_START_DEF; + crop->width = MT9V032_WINDOW_WIDTH_DEF; + crop->height = MT9V032_WINDOW_HEIGHT_DEF; + + format = v4l2_subdev_get_try_format(fh, 0); + format->code = V4L2_MBUS_FMT_SGRBG10_1X10; + format->width = MT9V032_WINDOW_WIDTH_DEF; + format->height = MT9V032_WINDOW_HEIGHT_DEF; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + + return mt9v032_set_power(subdev, 1); +} + +static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + return mt9v032_set_power(subdev, 0); +} + +static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = { + .s_power = mt9v032_set_power, +}; + +static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = { + .s_stream = mt9v032_s_stream, +}; + +static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = { + .enum_mbus_code = mt9v032_enum_mbus_code, + .enum_frame_size = mt9v032_enum_frame_size, + .get_fmt = mt9v032_get_format, + .set_fmt = mt9v032_set_format, + .get_crop = mt9v032_get_crop, + .set_crop = mt9v032_set_crop, +}; + +static struct v4l2_subdev_ops mt9v032_subdev_ops = { + .core = &mt9v032_subdev_core_ops, + .video = &mt9v032_subdev_video_ops, + .pad = &mt9v032_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = { + .registered = mt9v032_registered, + .open = mt9v032_open, + .close = mt9v032_close, +}; + +/* ----------------------------------------------------------------------------- + * Driver initialization and probing + */ + +static int mt9v032_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9v032 *mt9v032; + unsigned int i; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&client->adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL); + if (!mt9v032) + return -ENOMEM; + + mutex_init(&mt9v032->power_lock); + mt9v032->pdata = client->dev.platform_data; + + v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 4); + + v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, + V4L2_CID_GAIN, MT9V032_ANALOG_GAIN_MIN, + MT9V032_ANALOG_GAIN_MAX, 1, MT9V032_ANALOG_GAIN_DEF); + v4l2_ctrl_new_std_menu(&mt9v032->ctrls, &mt9v032_ctrl_ops, + V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0, + V4L2_EXPOSURE_AUTO); + v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, + V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN, + MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1, + MT9V032_TOTAL_SHUTTER_WIDTH_DEF); + + for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i) + v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL); + + mt9v032->subdev.ctrl_handler = &mt9v032->ctrls; + + if (mt9v032->ctrls.error) + printk(KERN_INFO "%s: control initialization error %d\n", + __func__, mt9v032->ctrls.error); + + mt9v032->crop.left = MT9V032_COLUMN_START_DEF; + mt9v032->crop.top = MT9V032_ROW_START_DEF; + mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF; + mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF; + + mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF; + mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF; + mt9v032->format.field = V4L2_FIELD_NONE; + mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB; + + mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE; + + v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops); + mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops; + mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0); + if (ret < 0) + kfree(mt9v032); + + return ret; +} + +static int mt9v032_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct mt9v032 *mt9v032 = to_mt9v032(subdev); + + v4l2_device_unregister_subdev(subdev); + media_entity_cleanup(&subdev->entity); + kfree(mt9v032); + return 0; +} + +static const struct i2c_device_id mt9v032_id[] = { + { "mt9v032", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9v032_id); + +static struct i2c_driver mt9v032_driver = { + .driver = { + .name = "mt9v032", + }, + .probe = mt9v032_probe, + .remove = mt9v032_remove, + .id_table = mt9v032_id, +}; + +static int __init mt9v032_init(void) +{ + return i2c_add_driver(&mt9v032_driver); +} + +static void __exit mt9v032_exit(void) +{ + i2c_del_driver(&mt9v032_driver); +} + +module_init(mt9v032_init); +module_exit(mt9v032_exit); + +MODULE_DESCRIPTION("Aptina MT9V032 Camera driver"); +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx1_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx1_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx1_camera.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx1_camera.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,890 @@ +/* + * V4L2 Driver for i.MXL/i.MXL camera (CSI) host + * + * Copyright (C) 2008, Paulius Zaleckas + * Copyright (C) 2009, Darius Augulis + * + * Based on PXA SoC camera driver + * Copyright (C) 2006, Sascha Hauer, Pengutronix + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * CSI registers + */ +#define CSICR1 0x00 /* CSI Control Register 1 */ +#define CSISR 0x08 /* CSI Status Register */ +#define CSIRXR 0x10 /* CSI RxFIFO Register */ + +#define CSICR1_RXFF_LEVEL(x) (((x) & 0x3) << 19) +#define CSICR1_SOF_POL (1 << 17) +#define CSICR1_SOF_INTEN (1 << 16) +#define CSICR1_MCLKDIV(x) (((x) & 0xf) << 12) +#define CSICR1_MCLKEN (1 << 9) +#define CSICR1_FCC (1 << 8) +#define CSICR1_BIG_ENDIAN (1 << 7) +#define CSICR1_CLR_RXFIFO (1 << 5) +#define CSICR1_GCLK_MODE (1 << 4) +#define CSICR1_DATA_POL (1 << 2) +#define CSICR1_REDGE (1 << 1) +#define CSICR1_EN (1 << 0) + +#define CSISR_SFF_OR_INT (1 << 25) +#define CSISR_RFF_OR_INT (1 << 24) +#define CSISR_STATFF_INT (1 << 21) +#define CSISR_RXFF_INT (1 << 18) +#define CSISR_SOF_INT (1 << 16) +#define CSISR_DRDY (1 << 0) + +#define VERSION_CODE KERNEL_VERSION(0, 0, 1) +#define DRIVER_NAME "mx1-camera" + +#define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \ + CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT) + +#define CSI_BUS_FLAGS (SOCAM_MASTER | SOCAM_HSYNC_ACTIVE_HIGH | \ + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | \ + SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW | \ + SOCAM_DATAWIDTH_8) + +#define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */ + +/* + * Structures + */ + +/* buffer for one video frame */ +struct mx1_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + enum v4l2_mbus_pixelcode code; + int inwork; +}; + +/* + * i.MX1/i.MXL is only supposed to handle one camera on its Camera Sensor + * Interface. If anyone ever builds hardware to enable more than + * one camera, they will have to modify this driver too + */ +struct mx1_camera_dev { + struct soc_camera_host soc_host; + struct soc_camera_device *icd; + struct mx1_camera_pdata *pdata; + struct mx1_buffer *active; + struct resource *res; + struct clk *clk; + struct list_head capture; + + void __iomem *base; + int dma_chan; + unsigned int irq; + unsigned long mclk; + + spinlock_t lock; +}; + +/* + * Videobuf operations + */ +static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, + unsigned int *size) +{ + struct soc_camera_device *icd = vq->priv_data; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; + + *size = bytes_per_line * icd->user_height; + + if (!*count) + *count = 32; + + if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) + *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; + + dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); + + return 0; +} + +static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf) +{ + struct soc_camera_device *icd = vq->priv_data; + struct videobuf_buffer *vb = &buf->vb; + + BUG_ON(in_interrupt()); + + dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + /* + * This waits until this buffer is out of danger, i.e., until it is no + * longer in STATE_QUEUED or STATE_ACTIVE + */ + videobuf_waiton(vq, vb, 0, 0); + videobuf_dma_contig_free(vq, vb); + + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static int mx1_videobuf_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, enum v4l2_field field) +{ + struct soc_camera_device *icd = vq->priv_data; + struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); + int ret; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; + + dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + /* Added list head initialization on alloc */ + WARN_ON(!list_empty(&vb->queue)); + + BUG_ON(NULL == icd->current_fmt); + + /* + * I think, in buf_prepare you only have to protect global data, + * the actual buffer is yours + */ + buf->inwork = 1; + + if (buf->code != icd->current_fmt->code || + vb->width != icd->user_width || + vb->height != icd->user_height || + vb->field != field) { + buf->code = icd->current_fmt->code; + vb->width = icd->user_width; + vb->height = icd->user_height; + vb->field = field; + vb->state = VIDEOBUF_NEEDS_INIT; + } + + vb->size = bytes_per_line * vb->height; + if (0 != vb->baddr && vb->bsize < vb->size) { + ret = -EINVAL; + goto out; + } + + if (vb->state == VIDEOBUF_NEEDS_INIT) { + ret = videobuf_iolock(vq, vb, NULL); + if (ret) + goto fail; + + vb->state = VIDEOBUF_PREPARED; + } + + buf->inwork = 0; + + return 0; + +fail: + free_buffer(vq, buf); +out: + buf->inwork = 0; + return ret; +} + +static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) +{ + struct videobuf_buffer *vbuf = &pcdev->active->vb; + struct device *dev = pcdev->icd->dev.parent; + int ret; + + if (unlikely(!pcdev->active)) { + dev_err(dev, "DMA End IRQ with no active buffer\n"); + return -EFAULT; + } + + /* setup sg list for future DMA */ + ret = imx_dma_setup_single(pcdev->dma_chan, + videobuf_to_dma_contig(vbuf), + vbuf->size, pcdev->res->start + + CSIRXR, DMA_MODE_READ); + if (unlikely(ret)) + dev_err(dev, "Failed to setup DMA sg list\n"); + + return ret; +} + +/* Called under spinlock_irqsave(&pcdev->lock, ...) */ +static void mx1_videobuf_queue(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx1_camera_dev *pcdev = ici->priv; + struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); + + dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + list_add_tail(&vb->queue, &pcdev->capture); + + vb->state = VIDEOBUF_ACTIVE; + + if (!pcdev->active) { + pcdev->active = buf; + + /* setup sg list for future DMA */ + if (!mx1_camera_setup_dma(pcdev)) { + unsigned int temp; + /* enable SOF irq */ + temp = __raw_readl(pcdev->base + CSICR1) | + CSICR1_SOF_INTEN; + __raw_writel(temp, pcdev->base + CSICR1); + } + } +} + +static void mx1_videobuf_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); +#ifdef DEBUG + struct soc_camera_device *icd = vq->priv_data; + struct device *dev = icd->dev.parent; + + dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + switch (vb->state) { + case VIDEOBUF_ACTIVE: + dev_dbg(dev, "%s (active)\n", __func__); + break; + case VIDEOBUF_QUEUED: + dev_dbg(dev, "%s (queued)\n", __func__); + break; + case VIDEOBUF_PREPARED: + dev_dbg(dev, "%s (prepared)\n", __func__); + break; + default: + dev_dbg(dev, "%s (unknown)\n", __func__); + break; + } +#endif + + free_buffer(vq, buf); +} + +static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev, + struct videobuf_buffer *vb, + struct mx1_buffer *buf) +{ + /* _init is used to debug races, see comment in mx1_camera_reqbufs() */ + list_del_init(&vb->queue); + vb->state = VIDEOBUF_DONE; + do_gettimeofday(&vb->ts); + vb->field_count++; + wake_up(&vb->done); + + if (list_empty(&pcdev->capture)) { + pcdev->active = NULL; + return; + } + + pcdev->active = list_entry(pcdev->capture.next, + struct mx1_buffer, vb.queue); + + /* setup sg list for future DMA */ + if (likely(!mx1_camera_setup_dma(pcdev))) { + unsigned int temp; + + /* enable SOF irq */ + temp = __raw_readl(pcdev->base + CSICR1) | CSICR1_SOF_INTEN; + __raw_writel(temp, pcdev->base + CSICR1); + } +} + +static void mx1_camera_dma_irq(int channel, void *data) +{ + struct mx1_camera_dev *pcdev = data; + struct device *dev = pcdev->icd->dev.parent; + struct mx1_buffer *buf; + struct videobuf_buffer *vb; + unsigned long flags; + + spin_lock_irqsave(&pcdev->lock, flags); + + imx_dma_disable(channel); + + if (unlikely(!pcdev->active)) { + dev_err(dev, "DMA End IRQ with no active buffer\n"); + goto out; + } + + vb = &pcdev->active->vb; + buf = container_of(vb, struct mx1_buffer, vb); + WARN_ON(buf->inwork || list_empty(&vb->queue)); + dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + mx1_camera_wakeup(pcdev, vb, buf); +out: + spin_unlock_irqrestore(&pcdev->lock, flags); +} + +static struct videobuf_queue_ops mx1_videobuf_ops = { + .buf_setup = mx1_videobuf_setup, + .buf_prepare = mx1_videobuf_prepare, + .buf_queue = mx1_videobuf_queue, + .buf_release = mx1_videobuf_release, +}; + +static void mx1_camera_init_videobuf(struct videobuf_queue *q, + struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx1_camera_dev *pcdev = ici->priv; + + videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent, + &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_NONE, + sizeof(struct mx1_buffer), icd, &icd->video_lock); +} + +static int mclk_get_divisor(struct mx1_camera_dev *pcdev) +{ + unsigned int mclk = pcdev->mclk; + unsigned long div; + unsigned long lcdclk; + + lcdclk = clk_get_rate(pcdev->clk); + + /* + * We verify platform_mclk_10khz != 0, so if anyone breaks it, here + * they get a nice Oops + */ + div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; + + dev_dbg(pcdev->icd->dev.parent, + "System clock %lukHz, target freq %dkHz, divisor %lu\n", + lcdclk / 1000, mclk / 1000, div); + + return div; +} + +static void mx1_camera_activate(struct mx1_camera_dev *pcdev) +{ + unsigned int csicr1 = CSICR1_EN; + + dev_dbg(pcdev->icd->dev.parent, "Activate device\n"); + + clk_enable(pcdev->clk); + + /* enable CSI before doing anything else */ + __raw_writel(csicr1, pcdev->base + CSICR1); + + csicr1 |= CSICR1_MCLKEN | CSICR1_FCC | CSICR1_GCLK_MODE; + csicr1 |= CSICR1_MCLKDIV(mclk_get_divisor(pcdev)); + csicr1 |= CSICR1_RXFF_LEVEL(2); /* 16 words */ + + __raw_writel(csicr1, pcdev->base + CSICR1); +} + +static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) +{ + dev_dbg(pcdev->icd->dev.parent, "Deactivate device\n"); + + /* Disable all CSI interface */ + __raw_writel(0x00, pcdev->base + CSICR1); + + clk_disable(pcdev->clk); +} + +/* + * The following two functions absolutely depend on the fact, that + * there can be only one camera on i.MX1/i.MXL camera sensor interface + */ +static int mx1_camera_add_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx1_camera_dev *pcdev = ici->priv; + int ret; + + if (pcdev->icd) { + ret = -EBUSY; + goto ebusy; + } + + dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n", + icd->devnum); + + mx1_camera_activate(pcdev); + + pcdev->icd = icd; + +ebusy: + return ret; +} + +static void mx1_camera_remove_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx1_camera_dev *pcdev = ici->priv; + unsigned int csicr1; + + BUG_ON(icd != pcdev->icd); + + /* disable interrupts */ + csicr1 = __raw_readl(pcdev->base + CSICR1) & ~CSI_IRQ_MASK; + __raw_writel(csicr1, pcdev->base + CSICR1); + + /* Stop DMA engine */ + imx_dma_disable(pcdev->dma_chan); + + dev_info(icd->dev.parent, "MX1 Camera driver detached from camera %d\n", + icd->devnum); + + mx1_camera_deactivate(pcdev); + + pcdev->icd = NULL; +} + +static int mx1_camera_set_crop(struct soc_camera_device *icd, + struct v4l2_crop *a) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + + return v4l2_subdev_call(sd, video, s_crop, a); +} + +static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx1_camera_dev *pcdev = ici->priv; + unsigned long camera_flags, common_flags; + unsigned int csicr1; + int ret; + + camera_flags = icd->ops->query_bus_param(icd); + + /* MX1 supports only 8bit buswidth */ + common_flags = soc_camera_bus_param_compatible(camera_flags, + CSI_BUS_FLAGS); + if (!common_flags) + return -EINVAL; + + /* Make choises, based on platform choice */ + if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if (!pcdev->pdata || + pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH) + common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + else + common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + } + + if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && + (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if (!pcdev->pdata || + pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING) + common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + else + common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + } + + if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && + (common_flags & SOCAM_DATA_ACTIVE_LOW)) { + if (!pcdev->pdata || + pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH) + common_flags &= ~SOCAM_DATA_ACTIVE_LOW; + else + common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; + } + + ret = icd->ops->set_bus_param(icd, common_flags); + if (ret < 0) + return ret; + + csicr1 = __raw_readl(pcdev->base + CSICR1); + + if (common_flags & SOCAM_PCLK_SAMPLE_RISING) + csicr1 |= CSICR1_REDGE; + if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) + csicr1 |= CSICR1_SOF_POL; + if (common_flags & SOCAM_DATA_ACTIVE_LOW) + csicr1 |= CSICR1_DATA_POL; + + __raw_writel(csicr1, pcdev->base + CSICR1); + + return 0; +} + +static int mx1_camera_set_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + int ret, buswidth; + + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) { + dev_warn(icd->dev.parent, "Format %x not found\n", + pix->pixelformat); + return -EINVAL; + } + + buswidth = xlate->host_fmt->bits_per_sample; + if (buswidth > 8) { + dev_warn(icd->dev.parent, + "bits-per-sample %d for format %x unsupported\n", + buswidth, pix->pixelformat); + return -EINVAL; + } + + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + if (ret < 0) + return ret; + + if (mf.code != xlate->code) + return -EINVAL; + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + icd->current_fmt = xlate; + + return ret; +} + +static int mx1_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + int ret; + /* TODO: limit to mx1 hardware capabilities */ + + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) { + dev_warn(icd->dev.parent, "Format %x not found\n", + pix->pixelformat); + return -EINVAL; + } + + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + /* limit to sensor capabilities */ + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + if (ret < 0) + return ret; + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + + return 0; +} + +static int mx1_camera_reqbufs(struct soc_camera_device *icd, + struct v4l2_requestbuffers *p) +{ + int i; + + /* + * This is for locking debugging only. I removed spinlocks and now I + * check whether .prepare is ever called on a linked buffer, or whether + * a dma IRQ can occur for an in-work or unlinked buffer. Until now + * it hadn't triggered + */ + for (i = 0; i < p->count; i++) { + struct mx1_buffer *buf = container_of(icd->vb_vidq.bufs[i], + struct mx1_buffer, vb); + buf->inwork = 0; + INIT_LIST_HEAD(&buf->vb.queue); + } + + return 0; +} + +static unsigned int mx1_camera_poll(struct file *file, poll_table *pt) +{ + struct soc_camera_device *icd = file->private_data; + struct mx1_buffer *buf; + + buf = list_entry(icd->vb_vidq.stream.next, struct mx1_buffer, + vb.stream); + + poll_wait(file, &buf->vb.done, pt); + + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) + return POLLIN | POLLRDNORM; + + return 0; +} + +static int mx1_camera_querycap(struct soc_camera_host *ici, + struct v4l2_capability *cap) +{ + /* cap->name is set by the friendly caller:-> */ + strlcpy(cap->card, "i.MX1/i.MXL Camera", sizeof(cap->card)); + cap->version = VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + + return 0; +} + +static struct soc_camera_host_ops mx1_soc_camera_host_ops = { + .owner = THIS_MODULE, + .add = mx1_camera_add_device, + .remove = mx1_camera_remove_device, + .set_bus_param = mx1_camera_set_bus_param, + .set_crop = mx1_camera_set_crop, + .set_fmt = mx1_camera_set_fmt, + .try_fmt = mx1_camera_try_fmt, + .init_videobuf = mx1_camera_init_videobuf, + .reqbufs = mx1_camera_reqbufs, + .poll = mx1_camera_poll, + .querycap = mx1_camera_querycap, +}; + +static struct fiq_handler fh = { + .name = "csi_sof" +}; + +static int __init mx1_camera_probe(struct platform_device *pdev) +{ + struct mx1_camera_dev *pcdev; + struct resource *res; + struct pt_regs regs; + struct clk *clk; + void __iomem *base; + unsigned int irq; + int err = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!res || (int)irq <= 0) { + err = -ENODEV; + goto exit; + } + + clk = clk_get(&pdev->dev, "csi_clk"); + if (IS_ERR(clk)) { + err = PTR_ERR(clk); + goto exit; + } + + pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); + if (!pcdev) { + dev_err(&pdev->dev, "Could not allocate pcdev\n"); + err = -ENOMEM; + goto exit_put_clk; + } + + pcdev->res = res; + pcdev->clk = clk; + + pcdev->pdata = pdev->dev.platform_data; + + if (pcdev->pdata) + pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; + + if (!pcdev->mclk) { + dev_warn(&pdev->dev, + "mclk_10khz == 0! Please, fix your platform data. " + "Using default 20MHz\n"); + pcdev->mclk = 20000000; + } + + INIT_LIST_HEAD(&pcdev->capture); + spin_lock_init(&pcdev->lock); + + /* + * Request the regions. + */ + if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) { + err = -EBUSY; + goto exit_kfree; + } + + base = ioremap(res->start, resource_size(res)); + if (!base) { + err = -ENOMEM; + goto exit_release; + } + pcdev->irq = irq; + pcdev->base = base; + + /* request dma */ + pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH); + if (pcdev->dma_chan < 0) { + dev_err(&pdev->dev, "Can't request DMA for MX1 CSI\n"); + err = -EBUSY; + goto exit_iounmap; + } + dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chan); + + imx_dma_setup_handlers(pcdev->dma_chan, mx1_camera_dma_irq, NULL, + pcdev); + + imx_dma_config_channel(pcdev->dma_chan, IMX_DMA_TYPE_FIFO, + IMX_DMA_MEMSIZE_32, MX1_DMA_REQ_CSI_R, 0); + /* burst length : 16 words = 64 bytes */ + imx_dma_config_burstlen(pcdev->dma_chan, 0); + + /* request irq */ + err = claim_fiq(&fh); + if (err) { + dev_err(&pdev->dev, "Camera interrupt register failed \n"); + goto exit_free_dma; + } + + set_fiq_handler(&mx1_camera_sof_fiq_start, &mx1_camera_sof_fiq_end - + &mx1_camera_sof_fiq_start); + + regs.ARM_r8 = (long)MX1_DMA_DIMR; + regs.ARM_r9 = (long)MX1_DMA_CCR(pcdev->dma_chan); + regs.ARM_r10 = (long)pcdev->base + CSICR1; + regs.ARM_fp = (long)pcdev->base + CSISR; + regs.ARM_sp = 1 << pcdev->dma_chan; + set_fiq_regs(®s); + + mxc_set_irq_fiq(irq, 1); + enable_fiq(irq); + + pcdev->soc_host.drv_name = DRIVER_NAME; + pcdev->soc_host.ops = &mx1_soc_camera_host_ops; + pcdev->soc_host.priv = pcdev; + pcdev->soc_host.v4l2_dev.dev = &pdev->dev; + pcdev->soc_host.nr = pdev->id; + err = soc_camera_host_register(&pcdev->soc_host); + if (err) + goto exit_free_irq; + + dev_info(&pdev->dev, "MX1 Camera driver loaded\n"); + + return 0; + +exit_free_irq: + disable_fiq(irq); + mxc_set_irq_fiq(irq, 0); + release_fiq(&fh); +exit_free_dma: + imx_dma_free(pcdev->dma_chan); +exit_iounmap: + iounmap(base); +exit_release: + release_mem_region(res->start, resource_size(res)); +exit_kfree: + kfree(pcdev); +exit_put_clk: + clk_put(clk); +exit: + return err; +} + +static int __exit mx1_camera_remove(struct platform_device *pdev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct mx1_camera_dev *pcdev = container_of(soc_host, + struct mx1_camera_dev, soc_host); + struct resource *res; + + imx_dma_free(pcdev->dma_chan); + disable_fiq(pcdev->irq); + mxc_set_irq_fiq(pcdev->irq, 0); + release_fiq(&fh); + + clk_put(pcdev->clk); + + soc_camera_host_unregister(soc_host); + + iounmap(pcdev->base); + + res = pcdev->res; + release_mem_region(res->start, resource_size(res)); + + kfree(pcdev); + + dev_info(&pdev->dev, "MX1 Camera driver unloaded\n"); + + return 0; +} + +static struct platform_driver mx1_camera_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .remove = __exit_p(mx1_camera_remove), +}; + +static int __init mx1_camera_init(void) +{ + return platform_driver_probe(&mx1_camera_driver, mx1_camera_probe); +} + +static void __exit mx1_camera_exit(void) +{ + return platform_driver_unregister(&mx1_camera_driver); +} + +module_init(mx1_camera_init); +module_exit(mx1_camera_exit); + +MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver"); +MODULE_AUTHOR("Paulius Zaleckas "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx2_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx2_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx2_camera.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx2_camera.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,1525 @@ +/* + * V4L2 Driver for i.MX27/i.MX25 camera host + * + * Copyright (C) 2008, Sascha Hauer, Pengutronix + * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography + * + * 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, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#ifdef CONFIG_MACH_MX27 +#include +#endif +#include + +#include + +#define MX2_CAM_DRV_NAME "mx2-camera" +#define MX2_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) +#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera" + +/* reset values */ +#define CSICR1_RESET_VAL 0x40000800 +#define CSICR2_RESET_VAL 0x0 +#define CSICR3_RESET_VAL 0x0 + +/* csi control reg 1 */ +#define CSICR1_SWAP16_EN (1 << 31) +#define CSICR1_EXT_VSYNC (1 << 30) +#define CSICR1_EOF_INTEN (1 << 29) +#define CSICR1_PRP_IF_EN (1 << 28) +#define CSICR1_CCIR_MODE (1 << 27) +#define CSICR1_COF_INTEN (1 << 26) +#define CSICR1_SF_OR_INTEN (1 << 25) +#define CSICR1_RF_OR_INTEN (1 << 24) +#define CSICR1_STATFF_LEVEL (3 << 22) +#define CSICR1_STATFF_INTEN (1 << 21) +#define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) /* MX27 */ +#define CSICR1_FB2_DMA_INTEN (1 << 20) /* MX25 */ +#define CSICR1_FB1_DMA_INTEN (1 << 19) /* MX25 */ +#define CSICR1_RXFF_INTEN (1 << 18) +#define CSICR1_SOF_POL (1 << 17) +#define CSICR1_SOF_INTEN (1 << 16) +#define CSICR1_MCLKDIV(d) (((d) & 0xF) << 12) +#define CSICR1_HSYNC_POL (1 << 11) +#define CSICR1_CCIR_EN (1 << 10) +#define CSICR1_MCLKEN (1 << 9) +#define CSICR1_FCC (1 << 8) +#define CSICR1_PACK_DIR (1 << 7) +#define CSICR1_CLR_STATFIFO (1 << 6) +#define CSICR1_CLR_RXFIFO (1 << 5) +#define CSICR1_GCLK_MODE (1 << 4) +#define CSICR1_INV_DATA (1 << 3) +#define CSICR1_INV_PCLK (1 << 2) +#define CSICR1_REDGE (1 << 1) + +#define SHIFT_STATFF_LEVEL 22 +#define SHIFT_RXFF_LEVEL 19 +#define SHIFT_MCLKDIV 12 + +/* control reg 3 */ +#define CSICR3_FRMCNT (0xFFFF << 16) +#define CSICR3_FRMCNT_RST (1 << 15) +#define CSICR3_DMA_REFLASH_RFF (1 << 14) +#define CSICR3_DMA_REFLASH_SFF (1 << 13) +#define CSICR3_DMA_REQ_EN_RFF (1 << 12) +#define CSICR3_DMA_REQ_EN_SFF (1 << 11) +#define CSICR3_RXFF_LEVEL(l) (((l) & 7) << 4) /* MX25 */ +#define CSICR3_CSI_SUP (1 << 3) +#define CSICR3_ZERO_PACK_EN (1 << 2) +#define CSICR3_ECC_INT_EN (1 << 1) +#define CSICR3_ECC_AUTO_EN (1 << 0) + +#define SHIFT_FRMCNT 16 + +/* csi status reg */ +#define CSISR_SFF_OR_INT (1 << 25) +#define CSISR_RFF_OR_INT (1 << 24) +#define CSISR_STATFF_INT (1 << 21) +#define CSISR_DMA_TSF_FB2_INT (1 << 20) /* MX25 */ +#define CSISR_DMA_TSF_FB1_INT (1 << 19) /* MX25 */ +#define CSISR_RXFF_INT (1 << 18) +#define CSISR_EOF_INT (1 << 17) +#define CSISR_SOF_INT (1 << 16) +#define CSISR_F2_INT (1 << 15) +#define CSISR_F1_INT (1 << 14) +#define CSISR_COF_INT (1 << 13) +#define CSISR_ECC_INT (1 << 1) +#define CSISR_DRDY (1 << 0) + +#define CSICR1 0x00 +#define CSICR2 0x04 +#define CSISR (cpu_is_mx27() ? 0x08 : 0x18) +#define CSISTATFIFO 0x0c +#define CSIRFIFO 0x10 +#define CSIRXCNT 0x14 +#define CSICR3 (cpu_is_mx27() ? 0x1C : 0x08) +#define CSIDMASA_STATFIFO 0x20 +#define CSIDMATA_STATFIFO 0x24 +#define CSIDMASA_FB1 0x28 +#define CSIDMASA_FB2 0x2c +#define CSIFBUF_PARA 0x30 +#define CSIIMAG_PARA 0x34 + +/* EMMA PrP */ +#define PRP_CNTL 0x00 +#define PRP_INTR_CNTL 0x04 +#define PRP_INTRSTATUS 0x08 +#define PRP_SOURCE_Y_PTR 0x0c +#define PRP_SOURCE_CB_PTR 0x10 +#define PRP_SOURCE_CR_PTR 0x14 +#define PRP_DEST_RGB1_PTR 0x18 +#define PRP_DEST_RGB2_PTR 0x1c +#define PRP_DEST_Y_PTR 0x20 +#define PRP_DEST_CB_PTR 0x24 +#define PRP_DEST_CR_PTR 0x28 +#define PRP_SRC_FRAME_SIZE 0x2c +#define PRP_DEST_CH1_LINE_STRIDE 0x30 +#define PRP_SRC_PIXEL_FORMAT_CNTL 0x34 +#define PRP_CH1_PIXEL_FORMAT_CNTL 0x38 +#define PRP_CH1_OUT_IMAGE_SIZE 0x3c +#define PRP_CH2_OUT_IMAGE_SIZE 0x40 +#define PRP_SRC_LINE_STRIDE 0x44 +#define PRP_CSC_COEF_012 0x48 +#define PRP_CSC_COEF_345 0x4c +#define PRP_CSC_COEF_678 0x50 +#define PRP_CH1_RZ_HORI_COEF1 0x54 +#define PRP_CH1_RZ_HORI_COEF2 0x58 +#define PRP_CH1_RZ_HORI_VALID 0x5c +#define PRP_CH1_RZ_VERT_COEF1 0x60 +#define PRP_CH1_RZ_VERT_COEF2 0x64 +#define PRP_CH1_RZ_VERT_VALID 0x68 +#define PRP_CH2_RZ_HORI_COEF1 0x6c +#define PRP_CH2_RZ_HORI_COEF2 0x70 +#define PRP_CH2_RZ_HORI_VALID 0x74 +#define PRP_CH2_RZ_VERT_COEF1 0x78 +#define PRP_CH2_RZ_VERT_COEF2 0x7c +#define PRP_CH2_RZ_VERT_VALID 0x80 + +#define PRP_CNTL_CH1EN (1 << 0) +#define PRP_CNTL_CH2EN (1 << 1) +#define PRP_CNTL_CSIEN (1 << 2) +#define PRP_CNTL_DATA_IN_YUV420 (0 << 3) +#define PRP_CNTL_DATA_IN_YUV422 (1 << 3) +#define PRP_CNTL_DATA_IN_RGB16 (2 << 3) +#define PRP_CNTL_DATA_IN_RGB32 (3 << 3) +#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5) +#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5) +#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5) +#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5) +#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7) +#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7) +#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7) +#define PRP_CNTL_CH1_LEN (1 << 9) +#define PRP_CNTL_CH2_LEN (1 << 10) +#define PRP_CNTL_SKIP_FRAME (1 << 11) +#define PRP_CNTL_SWRST (1 << 12) +#define PRP_CNTL_CLKEN (1 << 13) +#define PRP_CNTL_WEN (1 << 14) +#define PRP_CNTL_CH1BYP (1 << 15) +#define PRP_CNTL_IN_TSKIP(x) ((x) << 16) +#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19) +#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22) +#define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25) +#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) +#define PRP_CNTL_CH2B1EN (1 << 29) +#define PRP_CNTL_CH2B2EN (1 << 30) +#define PRP_CNTL_CH2FEN (1 << 31) + +/* IRQ Enable and status register */ +#define PRP_INTR_RDERR (1 << 0) +#define PRP_INTR_CH1WERR (1 << 1) +#define PRP_INTR_CH2WERR (1 << 2) +#define PRP_INTR_CH1FC (1 << 3) +#define PRP_INTR_CH2FC (1 << 5) +#define PRP_INTR_LBOVF (1 << 7) +#define PRP_INTR_CH2OVF (1 << 8) + +#define mx27_camera_emma(pcdev) (cpu_is_mx27() && pcdev->use_emma) + +#define MAX_VIDEO_MEM 16 + +struct mx2_camera_dev { + struct device *dev; + struct soc_camera_host soc_host; + struct soc_camera_device *icd; + struct clk *clk_csi, *clk_emma; + + unsigned int irq_csi, irq_emma; + void __iomem *base_csi, *base_emma; + unsigned long base_dma; + + struct mx2_camera_platform_data *pdata; + struct resource *res_csi, *res_emma; + unsigned long platform_flags; + + struct list_head capture; + struct list_head active_bufs; + + spinlock_t lock; + + int dma; + struct mx2_buffer *active; + struct mx2_buffer *fb1_active; + struct mx2_buffer *fb2_active; + + int use_emma; + + u32 csicr1; + + void *discard_buffer; + dma_addr_t discard_buffer_dma; + size_t discard_size; +}; + +/* buffer for one video frame */ +struct mx2_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + enum v4l2_mbus_pixelcode code; + + int bufnum; +}; + +static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) +{ + unsigned long flags; + + clk_disable(pcdev->clk_csi); + writel(0, pcdev->base_csi + CSICR1); + if (mx27_camera_emma(pcdev)) { + writel(0, pcdev->base_emma + PRP_CNTL); + } else if (cpu_is_mx25()) { + spin_lock_irqsave(&pcdev->lock, flags); + pcdev->fb1_active = NULL; + pcdev->fb2_active = NULL; + writel(0, pcdev->base_csi + CSIDMASA_FB1); + writel(0, pcdev->base_csi + CSIDMASA_FB2); + spin_unlock_irqrestore(&pcdev->lock, flags); + } +} + +/* + * The following two functions absolutely depend on the fact, that + * there can be only one camera on mx2 camera sensor interface + */ +static int mx2_camera_add_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + int ret; + u32 csicr1; + + if (pcdev->icd) + return -EBUSY; + + ret = clk_enable(pcdev->clk_csi); + if (ret < 0) + return ret; + + csicr1 = CSICR1_MCLKEN; + + if (mx27_camera_emma(pcdev)) { + csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | + CSICR1_RXFF_LEVEL(0); + } else if (cpu_is_mx27()) + csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2); + + pcdev->csicr1 = csicr1; + writel(pcdev->csicr1, pcdev->base_csi + CSICR1); + + pcdev->icd = icd; + + dev_info(icd->dev.parent, "Camera driver attached to camera %d\n", + icd->devnum); + + return 0; +} + +static void mx2_camera_remove_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + + BUG_ON(icd != pcdev->icd); + + dev_info(icd->dev.parent, "Camera driver detached from camera %d\n", + icd->devnum); + + mx2_camera_deactivate(pcdev); + + if (pcdev->discard_buffer) { + dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size, + pcdev->discard_buffer, + pcdev->discard_buffer_dma); + pcdev->discard_buffer = NULL; + } + + pcdev->icd = NULL; +} + +#ifdef CONFIG_MACH_MX27 +static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev) +{ + u32 tmp; + + imx_dma_enable(pcdev->dma); + + tmp = readl(pcdev->base_csi + CSICR1); + tmp |= CSICR1_RF_OR_INTEN; + writel(tmp, pcdev->base_csi + CSICR1); +} + +static irqreturn_t mx27_camera_irq(int irq_csi, void *data) +{ + struct mx2_camera_dev *pcdev = data; + u32 status = readl(pcdev->base_csi + CSISR); + + if (status & CSISR_SOF_INT && pcdev->active) { + u32 tmp; + + tmp = readl(pcdev->base_csi + CSICR1); + writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1); + mx27_camera_dma_enable(pcdev); + } + + writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR); + + return IRQ_HANDLED; +} +#else +static irqreturn_t mx27_camera_irq(int irq_csi, void *data) +{ + return IRQ_NONE; +} +#endif /* CONFIG_MACH_MX27 */ + +static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb, + int state) +{ + struct videobuf_buffer *vb; + struct mx2_buffer *buf; + struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active : + &pcdev->fb2_active; + u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2; + unsigned long flags; + + spin_lock_irqsave(&pcdev->lock, flags); + + if (*fb_active == NULL) + goto out; + + vb = &(*fb_active)->vb; + dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + vb->state = state; + do_gettimeofday(&vb->ts); + vb->field_count++; + + wake_up(&vb->done); + + if (list_empty(&pcdev->capture)) { + buf = NULL; + writel(0, pcdev->base_csi + fb_reg); + } else { + buf = list_entry(pcdev->capture.next, struct mx2_buffer, + vb.queue); + vb = &buf->vb; + list_del(&vb->queue); + vb->state = VIDEOBUF_ACTIVE; + writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg); + } + + *fb_active = buf; + +out: + spin_unlock_irqrestore(&pcdev->lock, flags); +} + +static irqreturn_t mx25_camera_irq(int irq_csi, void *data) +{ + struct mx2_camera_dev *pcdev = data; + u32 status = readl(pcdev->base_csi + CSISR); + + if (status & CSISR_DMA_TSF_FB1_INT) + mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE); + else if (status & CSISR_DMA_TSF_FB2_INT) + mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE); + + /* FIXME: handle CSISR_RFF_OR_INT */ + + writel(status, pcdev->base_csi + CSISR); + + return IRQ_HANDLED; +} + +/* + * Videobuf operations + */ +static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, + unsigned int *size) +{ + struct soc_camera_device *icd = vq->priv_data; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); + + if (bytes_per_line < 0) + return bytes_per_line; + + *size = bytes_per_line * icd->user_height; + + if (0 == *count) + *count = 32; + if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) + *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; + + return 0; +} + +static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf) +{ + struct soc_camera_device *icd = vq->priv_data; + struct videobuf_buffer *vb = &buf->vb; + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + /* + * This waits until this buffer is out of danger, i.e., until it is no + * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE + */ + videobuf_waiton(vq, vb, 0, 0); + + videobuf_dma_contig_free(vq, vb); + dev_dbg(&icd->dev, "%s freed\n", __func__); + + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static int mx2_videobuf_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, enum v4l2_field field) +{ + struct soc_camera_device *icd = vq->priv_data; + struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + int ret = 0; + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + if (bytes_per_line < 0) + return bytes_per_line; + +#ifdef DEBUG + /* + * This can be useful if you want to see if we actually fill + * the buffer with something + */ + memset((void *)vb->baddr, 0xaa, vb->bsize); +#endif + + if (buf->code != icd->current_fmt->code || + vb->width != icd->user_width || + vb->height != icd->user_height || + vb->field != field) { + buf->code = icd->current_fmt->code; + vb->width = icd->user_width; + vb->height = icd->user_height; + vb->field = field; + vb->state = VIDEOBUF_NEEDS_INIT; + } + + vb->size = bytes_per_line * vb->height; + if (vb->baddr && vb->bsize < vb->size) { + ret = -EINVAL; + goto out; + } + + if (vb->state == VIDEOBUF_NEEDS_INIT) { + ret = videobuf_iolock(vq, vb, NULL); + if (ret) + goto fail; + + vb->state = VIDEOBUF_PREPARED; + } + + return 0; + +fail: + free_buffer(vq, buf); +out: + return ret; +} + +static void mx2_videobuf_queue(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); + unsigned long flags; + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + spin_lock_irqsave(&pcdev->lock, flags); + + vb->state = VIDEOBUF_QUEUED; + list_add_tail(&vb->queue, &pcdev->capture); + + if (mx27_camera_emma(pcdev)) { + goto out; +#ifdef CONFIG_MACH_MX27 + } else if (cpu_is_mx27()) { + int ret; + + if (pcdev->active == NULL) { + ret = imx_dma_setup_single(pcdev->dma, + videobuf_to_dma_contig(vb), vb->size, + (u32)pcdev->base_dma + 0x10, + DMA_MODE_READ); + if (ret) { + vb->state = VIDEOBUF_ERROR; + wake_up(&vb->done); + goto out; + } + + vb->state = VIDEOBUF_ACTIVE; + pcdev->active = buf; + } +#endif + } else { /* cpu_is_mx25() */ + u32 csicr3, dma_inten = 0; + + if (pcdev->fb1_active == NULL) { + writel(videobuf_to_dma_contig(vb), + pcdev->base_csi + CSIDMASA_FB1); + pcdev->fb1_active = buf; + dma_inten = CSICR1_FB1_DMA_INTEN; + } else if (pcdev->fb2_active == NULL) { + writel(videobuf_to_dma_contig(vb), + pcdev->base_csi + CSIDMASA_FB2); + pcdev->fb2_active = buf; + dma_inten = CSICR1_FB2_DMA_INTEN; + } + + if (dma_inten) { + list_del(&vb->queue); + vb->state = VIDEOBUF_ACTIVE; + + csicr3 = readl(pcdev->base_csi + CSICR3); + + /* Reflash DMA */ + writel(csicr3 | CSICR3_DMA_REFLASH_RFF, + pcdev->base_csi + CSICR3); + + /* clear & enable interrupts */ + writel(dma_inten, pcdev->base_csi + CSISR); + pcdev->csicr1 |= dma_inten; + writel(pcdev->csicr1, pcdev->base_csi + CSICR1); + + /* enable DMA */ + csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1); + writel(csicr3, pcdev->base_csi + CSICR3); + } + } + +out: + spin_unlock_irqrestore(&pcdev->lock, flags); +} + +static void mx2_videobuf_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); + unsigned long flags; + +#ifdef DEBUG + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + switch (vb->state) { + case VIDEOBUF_ACTIVE: + dev_info(&icd->dev, "%s (active)\n", __func__); + break; + case VIDEOBUF_QUEUED: + dev_info(&icd->dev, "%s (queued)\n", __func__); + break; + case VIDEOBUF_PREPARED: + dev_info(&icd->dev, "%s (prepared)\n", __func__); + break; + default: + dev_info(&icd->dev, "%s (unknown) %d\n", __func__, + vb->state); + break; + } +#endif + + /* + * Terminate only queued but inactive buffers. Active buffers are + * released when they become inactive after videobuf_waiton(). + * + * FIXME: implement forced termination of active buffers for mx27 and + * mx27 eMMA, so that the user won't get stuck in an uninterruptible + * state. This requires a specific handling for each of the these DMA + * types. + */ + spin_lock_irqsave(&pcdev->lock, flags); + if (vb->state == VIDEOBUF_QUEUED) { + list_del(&vb->queue); + vb->state = VIDEOBUF_ERROR; + } else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) { + if (pcdev->fb1_active == buf) { + pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; + writel(0, pcdev->base_csi + CSIDMASA_FB1); + pcdev->fb1_active = NULL; + } else if (pcdev->fb2_active == buf) { + pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN; + writel(0, pcdev->base_csi + CSIDMASA_FB2); + pcdev->fb2_active = NULL; + } + writel(pcdev->csicr1, pcdev->base_csi + CSICR1); + vb->state = VIDEOBUF_ERROR; + } + spin_unlock_irqrestore(&pcdev->lock, flags); + + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops mx2_videobuf_ops = { + .buf_setup = mx2_videobuf_setup, + .buf_prepare = mx2_videobuf_prepare, + .buf_queue = mx2_videobuf_queue, + .buf_release = mx2_videobuf_release, +}; + +static void mx2_camera_init_videobuf(struct videobuf_queue *q, + struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + + videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev, + &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_NONE, sizeof(struct mx2_buffer), + icd, &icd->video_lock); +} + +#define MX2_BUS_FLAGS (SOCAM_DATAWIDTH_8 | \ + SOCAM_MASTER | \ + SOCAM_VSYNC_ACTIVE_HIGH | \ + SOCAM_VSYNC_ACTIVE_LOW | \ + SOCAM_HSYNC_ACTIVE_HIGH | \ + SOCAM_HSYNC_ACTIVE_LOW | \ + SOCAM_PCLK_SAMPLE_RISING | \ + SOCAM_PCLK_SAMPLE_FALLING | \ + SOCAM_DATA_ACTIVE_HIGH | \ + SOCAM_DATA_ACTIVE_LOW) + +static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) +{ + u32 cntl; + int count = 0; + + cntl = readl(pcdev->base_emma + PRP_CNTL); + writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); + while (count++ < 100) { + if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) + return 0; + barrier(); + udelay(1); + } + + return -ETIMEDOUT; +} + +static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, + int bytesperline) +{ + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_RGB1_PTR); + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_RGB2_PTR); + + /* + * We only use the EMMA engine to get rid of the broken + * DMA Engine. No color space consversion at the moment. + * We set the incomming and outgoing pixelformat to an + * 16 Bit wide format and adjust the bytesperline + * accordingly. With this configuration the inputdata + * will not be changed by the emma and could be any type + * of 16 Bit Pixelformat. + */ + writel(PRP_CNTL_CH1EN | + PRP_CNTL_CSIEN | + PRP_CNTL_DATA_IN_RGB16 | + PRP_CNTL_CH1_OUT_RGB16 | + PRP_CNTL_CH1_LEN | + PRP_CNTL_CH1BYP | + PRP_CNTL_CH1_TSKIP(0) | + PRP_CNTL_IN_TSKIP(0), + pcdev->base_emma + PRP_CNTL); + + writel(((bytesperline >> 1) << 16) | icd->user_height, + pcdev->base_emma + PRP_SRC_FRAME_SIZE); + writel(((bytesperline >> 1) << 16) | icd->user_height, + pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); + writel(bytesperline, + pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); + writel(0x2ca00565, /* RGB565 */ + pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); + writel(0x2ca00565, /* RGB565 */ + pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); + + /* Enable interrupts */ + writel(PRP_INTR_RDERR | + PRP_INTR_CH1WERR | + PRP_INTR_CH2WERR | + PRP_INTR_CH1FC | + PRP_INTR_CH2FC | + PRP_INTR_LBOVF | + PRP_INTR_CH2OVF, + pcdev->base_emma + PRP_INTR_CNTL); +} + +static int mx2_camera_set_bus_param(struct soc_camera_device *icd, + __u32 pixfmt) +{ + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); + struct mx2_camera_dev *pcdev = ici->priv; + unsigned long camera_flags, common_flags; + int ret = 0; + int bytesperline; + u32 csicr1 = pcdev->csicr1; + + camera_flags = icd->ops->query_bus_param(icd); + + common_flags = soc_camera_bus_param_compatible(camera_flags, + MX2_BUS_FLAGS); + if (!common_flags) + return -EINVAL; + + if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) + common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + else + common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + } + + if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && + (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) + common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + else + common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + } + + ret = icd->ops->set_bus_param(icd, common_flags); + if (ret < 0) + return ret; + + if (common_flags & SOCAM_PCLK_SAMPLE_RISING) + csicr1 |= CSICR1_REDGE; + if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) + csicr1 |= CSICR1_SOF_POL; + if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH) + csicr1 |= CSICR1_HSYNC_POL; + if (pcdev->platform_flags & MX2_CAMERA_SWAP16) + csicr1 |= CSICR1_SWAP16_EN; + if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) + csicr1 |= CSICR1_EXT_VSYNC; + if (pcdev->platform_flags & MX2_CAMERA_CCIR) + csicr1 |= CSICR1_CCIR_EN; + if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE) + csicr1 |= CSICR1_CCIR_MODE; + if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK) + csicr1 |= CSICR1_GCLK_MODE; + if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) + csicr1 |= CSICR1_INV_DATA; + if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB) + csicr1 |= CSICR1_PACK_DIR; + + pcdev->csicr1 = csicr1; + + bytesperline = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + if (bytesperline < 0) + return bytesperline; + + if (mx27_camera_emma(pcdev)) { + ret = mx27_camera_emma_prp_reset(pcdev); + if (ret) + return ret; + + if (pcdev->discard_buffer) + dma_free_coherent(ici->v4l2_dev.dev, + pcdev->discard_size, pcdev->discard_buffer, + pcdev->discard_buffer_dma); + + /* + * I didn't manage to properly enable/disable the prp + * on a per frame basis during running transfers, + * thus we allocate a buffer here and use it to + * discard frames when no buffer is available. + * Feel free to work on this ;) + */ + pcdev->discard_size = icd->user_height * bytesperline; + pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, + pcdev->discard_size, &pcdev->discard_buffer_dma, + GFP_KERNEL); + if (!pcdev->discard_buffer) + return -ENOMEM; + + mx27_camera_emma_buf_init(icd, bytesperline); + } else if (cpu_is_mx25()) { + writel((bytesperline * icd->user_height) >> 2, + pcdev->base_csi + CSIRXCNT); + writel((bytesperline << 16) | icd->user_height, + pcdev->base_csi + CSIIMAG_PARA); + } + + writel(pcdev->csicr1, pcdev->base_csi + CSICR1); + + return 0; +} + +static int mx2_camera_set_crop(struct soc_camera_device *icd, + struct v4l2_crop *a) +{ + struct v4l2_rect *rect = &a->c; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct v4l2_mbus_framefmt mf; + int ret; + + soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); + soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); + + ret = v4l2_subdev_call(sd, video, s_crop, a); + if (ret < 0) + return ret; + + /* The capture device might have changed its output */ + ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + if (ret < 0) + return ret; + + dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", + mf.width, mf.height); + + icd->user_width = mf.width; + icd->user_height = mf.height; + + return ret; +} + +static int mx2_camera_set_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) { + dev_warn(icd->dev.parent, "Format %x not found\n", + pix->pixelformat); + return -EINVAL; + } + + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + + if (mf.code != xlate->code) + return -EINVAL; + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + icd->current_fmt = xlate; + + return 0; +} + +static int mx2_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + __u32 pixfmt = pix->pixelformat; + unsigned int width_limit; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (pixfmt && !xlate) { + dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + /* FIXME: implement MX27 limits */ + + /* limit to MX25 hardware capabilities */ + if (cpu_is_mx25()) { + if (xlate->host_fmt->bits_per_sample <= 8) + width_limit = 0xffff * 4; + else + width_limit = 0xffff * 2; + /* CSIIMAG_PARA limit */ + if (pix->width > width_limit) + pix->width = width_limit; + if (pix->height > 0xffff) + pix->height = 0xffff; + + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (pix->bytesperline < 0) + return pix->bytesperline; + pix->sizeimage = pix->height * pix->bytesperline; + if (pix->sizeimage > (4 * 0x3ffff)) { /* CSIRXCNT limit */ + dev_warn(icd->dev.parent, + "Image size (%u) above limit\n", + pix->sizeimage); + return -EINVAL; + } + } + + /* limit to sensor capabilities */ + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + if (ret < 0) + return ret; + + if (mf.field == V4L2_FIELD_ANY) + mf.field = V4L2_FIELD_NONE; + if (mf.field != V4L2_FIELD_NONE) { + dev_err(icd->dev.parent, "Field type %d unsupported.\n", + mf.field); + return -EINVAL; + } + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + + return 0; +} + +static int mx2_camera_querycap(struct soc_camera_host *ici, + struct v4l2_capability *cap) +{ + /* cap->name is set by the friendly caller:-> */ + strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); + cap->version = MX2_CAM_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + + return 0; +} + +static int mx2_camera_reqbufs(struct soc_camera_device *icd, + struct v4l2_requestbuffers *p) +{ + int i; + + for (i = 0; i < p->count; i++) { + struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i], + struct mx2_buffer, vb); + INIT_LIST_HEAD(&buf->vb.queue); + } + + return 0; +} + +#ifdef CONFIG_MACH_MX27 +static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state) +{ + struct videobuf_buffer *vb; + struct mx2_buffer *buf; + unsigned long flags; + int ret; + + spin_lock_irqsave(&pcdev->lock, flags); + + if (!pcdev->active) { + dev_err(pcdev->dev, "%s called with no active buffer!\n", + __func__); + goto out; + } + + vb = &pcdev->active->vb; + buf = container_of(vb, struct mx2_buffer, vb); + WARN_ON(list_empty(&vb->queue)); + dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ + list_del_init(&vb->queue); + vb->state = state; + do_gettimeofday(&vb->ts); + vb->field_count++; + + wake_up(&vb->done); + + if (list_empty(&pcdev->capture)) { + pcdev->active = NULL; + goto out; + } + + pcdev->active = list_entry(pcdev->capture.next, + struct mx2_buffer, vb.queue); + + vb = &pcdev->active->vb; + vb->state = VIDEOBUF_ACTIVE; + + ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb), + vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ); + + if (ret) { + vb->state = VIDEOBUF_ERROR; + pcdev->active = NULL; + wake_up(&vb->done); + } + +out: + spin_unlock_irqrestore(&pcdev->lock, flags); +} + +static void mx27_camera_dma_err_callback(int channel, void *data, int err) +{ + struct mx2_camera_dev *pcdev = data; + + mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR); +} + +static void mx27_camera_dma_callback(int channel, void *data) +{ + struct mx2_camera_dev *pcdev = data; + + mx27_camera_frame_done(pcdev, VIDEOBUF_DONE); +} + +#define DMA_REQ_CSI_RX 31 /* FIXME: Add this to a resource */ + +static int __devinit mx27_camera_dma_init(struct platform_device *pdev, + struct mx2_camera_dev *pcdev) +{ + int err; + + pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH); + if (pcdev->dma < 0) { + dev_err(&pdev->dev, "%s failed to request DMA channel\n", + __func__); + return pcdev->dma; + } + + err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback, + mx27_camera_dma_err_callback, pcdev); + if (err) { + dev_err(&pdev->dev, "%s failed to set DMA callback\n", + __func__); + goto err_out; + } + + err = imx_dma_config_channel(pcdev->dma, + IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO, + IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, + DMA_REQ_CSI_RX, 1); + if (err) { + dev_err(&pdev->dev, "%s failed to config DMA channel\n", + __func__); + goto err_out; + } + + imx_dma_config_burstlen(pcdev->dma, 64); + + return 0; + +err_out: + imx_dma_free(pcdev->dma); + + return err; +} +#endif /* CONFIG_MACH_MX27 */ + +static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) +{ + struct soc_camera_device *icd = file->private_data; + + return videobuf_poll_stream(file, &icd->vb_vidq, pt); +} + +static struct soc_camera_host_ops mx2_soc_camera_host_ops = { + .owner = THIS_MODULE, + .add = mx2_camera_add_device, + .remove = mx2_camera_remove_device, + .set_fmt = mx2_camera_set_fmt, + .set_crop = mx2_camera_set_crop, + .try_fmt = mx2_camera_try_fmt, + .init_videobuf = mx2_camera_init_videobuf, + .reqbufs = mx2_camera_reqbufs, + .poll = mx2_camera_poll, + .querycap = mx2_camera_querycap, + .set_bus_param = mx2_camera_set_bus_param, +}; + +static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, + int bufnum, int state) +{ + struct mx2_buffer *buf; + struct videobuf_buffer *vb; + unsigned long phys; + + if (!list_empty(&pcdev->active_bufs)) { + buf = list_entry(pcdev->active_bufs.next, + struct mx2_buffer, vb.queue); + + BUG_ON(buf->bufnum != bufnum); + + vb = &buf->vb; +#ifdef DEBUG + phys = videobuf_to_dma_contig(vb); + if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum) + != phys) { + dev_err(pcdev->dev, "%p != %p\n", phys, + readl(pcdev->base_emma + + PRP_DEST_RGB1_PTR + + 4 * bufnum)); + } +#endif + dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, + vb->baddr, vb->bsize); + + list_del(&vb->queue); + vb->state = state; + do_gettimeofday(&vb->ts); + vb->field_count++; + + wake_up(&vb->done); + } + + if (list_empty(&pcdev->capture)) { + writel(pcdev->discard_buffer_dma, pcdev->base_emma + + PRP_DEST_RGB1_PTR + 4 * bufnum); + return; + } + + buf = list_entry(pcdev->capture.next, + struct mx2_buffer, vb.queue); + + buf->bufnum = !bufnum; + + list_move_tail(pcdev->capture.next, &pcdev->active_bufs); + + vb = &buf->vb; + vb->state = VIDEOBUF_ACTIVE; + + phys = videobuf_to_dma_contig(vb); + writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); +} + +static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) +{ + struct mx2_camera_dev *pcdev = data; + unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); + struct mx2_buffer *buf; + + if (status & (1 << 7)) { /* overflow */ + u32 cntl; + /* + * We only disable channel 1 here since this is the only + * enabled channel + * + * FIXME: the correct DMA overflow handling should be resetting + * the buffer, returning an error frame, and continuing with + * the next one. + */ + cntl = readl(pcdev->base_emma + PRP_CNTL); + writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL); + writel(cntl, pcdev->base_emma + PRP_CNTL); + } + if ((status & (3 << 5)) == (3 << 5) + && !list_empty(&pcdev->active_bufs)) { + /* + * Both buffers have triggered, process the one we're expecting + * to first + */ + buf = list_entry(pcdev->active_bufs.next, + struct mx2_buffer, vb.queue); + mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE); + status &= ~(1 << (6 - buf->bufnum)); /* mark processed */ + } + if (status & (1 << 6)) + mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE); + if (status & (1 << 5)) + mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE); + + writel(status, pcdev->base_emma + PRP_INTRSTATUS); + + return IRQ_HANDLED; +} + +static int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev) +{ + struct resource *res_emma = pcdev->res_emma; + int err = 0; + + if (!request_mem_region(res_emma->start, resource_size(res_emma), + MX2_CAM_DRV_NAME)) { + err = -EBUSY; + goto out; + } + + pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma)); + if (!pcdev->base_emma) { + err = -ENOMEM; + goto exit_release; + } + + err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0, + MX2_CAM_DRV_NAME, pcdev); + if (err) { + dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n"); + goto exit_iounmap; + } + + pcdev->clk_emma = clk_get(NULL, "emma"); + if (IS_ERR(pcdev->clk_emma)) { + err = PTR_ERR(pcdev->clk_emma); + goto exit_free_irq; + } + + clk_enable(pcdev->clk_emma); + + err = mx27_camera_emma_prp_reset(pcdev); + if (err) + goto exit_clk_emma_put; + + return err; + +exit_clk_emma_put: + clk_disable(pcdev->clk_emma); + clk_put(pcdev->clk_emma); +exit_free_irq: + free_irq(pcdev->irq_emma, pcdev); +exit_iounmap: + iounmap(pcdev->base_emma); +exit_release: + release_mem_region(res_emma->start, resource_size(res_emma)); +out: + return err; +} + +static int __devinit mx2_camera_probe(struct platform_device *pdev) +{ + struct mx2_camera_dev *pcdev; + struct resource *res_csi, *res_emma; + void __iomem *base_csi; + int irq_csi, irq_emma; + irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq + : mx27_camera_irq; + int err = 0; + + dev_dbg(&pdev->dev, "initialising\n"); + + res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq_csi = platform_get_irq(pdev, 0); + if (res_csi == NULL || irq_csi < 0) { + dev_err(&pdev->dev, "Missing platform resources data\n"); + err = -ENODEV; + goto exit; + } + + pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); + if (!pcdev) { + dev_err(&pdev->dev, "Could not allocate pcdev\n"); + err = -ENOMEM; + goto exit; + } + + pcdev->clk_csi = clk_get(&pdev->dev, NULL); + if (IS_ERR(pcdev->clk_csi)) { + err = PTR_ERR(pcdev->clk_csi); + goto exit_kfree; + } + + dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n", + clk_get_rate(pcdev->clk_csi)); + + /* Initialize DMA */ +#ifdef CONFIG_MACH_MX27 + if (cpu_is_mx27()) { + err = mx27_camera_dma_init(pdev, pcdev); + if (err) + goto exit_clk_put; + } +#endif /* CONFIG_MACH_MX27 */ + + pcdev->res_csi = res_csi; + pcdev->pdata = pdev->dev.platform_data; + if (pcdev->pdata) { + long rate; + + pcdev->platform_flags = pcdev->pdata->flags; + + rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2); + if (rate <= 0) { + err = -ENODEV; + goto exit_dma_free; + } + err = clk_set_rate(pcdev->clk_csi, rate); + if (err < 0) + goto exit_dma_free; + } + + INIT_LIST_HEAD(&pcdev->capture); + INIT_LIST_HEAD(&pcdev->active_bufs); + spin_lock_init(&pcdev->lock); + + /* + * Request the regions. + */ + if (!request_mem_region(res_csi->start, resource_size(res_csi), + MX2_CAM_DRV_NAME)) { + err = -EBUSY; + goto exit_dma_free; + } + + base_csi = ioremap(res_csi->start, resource_size(res_csi)); + if (!base_csi) { + err = -ENOMEM; + goto exit_release; + } + pcdev->irq_csi = irq_csi; + pcdev->base_csi = base_csi; + pcdev->base_dma = res_csi->start; + pcdev->dev = &pdev->dev; + + err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0, + MX2_CAM_DRV_NAME, pcdev); + if (err) { + dev_err(pcdev->dev, "Camera interrupt register failed \n"); + goto exit_iounmap; + } + + if (cpu_is_mx27()) { + /* EMMA support */ + res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); + irq_emma = platform_get_irq(pdev, 1); + + if (res_emma && irq_emma >= 0) { + dev_info(&pdev->dev, "Using EMMA\n"); + pcdev->use_emma = 1; + pcdev->res_emma = res_emma; + pcdev->irq_emma = irq_emma; + if (mx27_camera_emma_init(pcdev)) + goto exit_free_irq; + } + } + + pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, + pcdev->soc_host.ops = &mx2_soc_camera_host_ops, + pcdev->soc_host.priv = pcdev; + pcdev->soc_host.v4l2_dev.dev = &pdev->dev; + pcdev->soc_host.nr = pdev->id; + err = soc_camera_host_register(&pcdev->soc_host); + if (err) + goto exit_free_emma; + + dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n", + clk_get_rate(pcdev->clk_csi)); + + return 0; + +exit_free_emma: + if (mx27_camera_emma(pcdev)) { + free_irq(pcdev->irq_emma, pcdev); + clk_disable(pcdev->clk_emma); + clk_put(pcdev->clk_emma); + iounmap(pcdev->base_emma); + release_mem_region(res_emma->start, resource_size(res_emma)); + } +exit_free_irq: + free_irq(pcdev->irq_csi, pcdev); +exit_iounmap: + iounmap(base_csi); +exit_release: + release_mem_region(res_csi->start, resource_size(res_csi)); +exit_dma_free: +#ifdef CONFIG_MACH_MX27 + if (cpu_is_mx27()) + imx_dma_free(pcdev->dma); +exit_clk_put: + clk_put(pcdev->clk_csi); +#endif /* CONFIG_MACH_MX27 */ +exit_kfree: + kfree(pcdev); +exit: + return err; +} + +static int __devexit mx2_camera_remove(struct platform_device *pdev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct mx2_camera_dev *pcdev = container_of(soc_host, + struct mx2_camera_dev, soc_host); + struct resource *res; + + clk_put(pcdev->clk_csi); +#ifdef CONFIG_MACH_MX27 + if (cpu_is_mx27()) + imx_dma_free(pcdev->dma); +#endif /* CONFIG_MACH_MX27 */ + free_irq(pcdev->irq_csi, pcdev); + if (mx27_camera_emma(pcdev)) + free_irq(pcdev->irq_emma, pcdev); + + soc_camera_host_unregister(&pcdev->soc_host); + + iounmap(pcdev->base_csi); + + if (mx27_camera_emma(pcdev)) { + clk_disable(pcdev->clk_emma); + clk_put(pcdev->clk_emma); + iounmap(pcdev->base_emma); + res = pcdev->res_emma; + release_mem_region(res->start, resource_size(res)); + } + + res = pcdev->res_csi; + release_mem_region(res->start, resource_size(res)); + + kfree(pcdev); + + dev_info(&pdev->dev, "MX2 Camera driver unloaded\n"); + + return 0; +} + +static struct platform_driver mx2_camera_driver = { + .driver = { + .name = MX2_CAM_DRV_NAME, + }, + .remove = __devexit_p(mx2_camera_remove), +}; + + +static int __init mx2_camera_init(void) +{ + return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe); +} + +static void __exit mx2_camera_exit(void) +{ + return platform_driver_unregister(&mx2_camera_driver); +} + +module_init(mx2_camera_init); +module_exit(mx2_camera_exit); + +MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver"); +MODULE_AUTHOR("Sascha Hauer "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx3_camera.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx3_camera.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx3_camera.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mx3_camera.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,1328 @@ +/* + * V4L2 Driver for i.MX3x camera host + * + * Copyright (C) 2008 + * Guennadi Liakhovetski, DENX Software Engineering, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MX3_CAM_DRV_NAME "mx3-camera" + +/* CMOS Sensor Interface Registers */ +#define CSI_REG_START 0x60 + +#define CSI_SENS_CONF (0x60 - CSI_REG_START) +#define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START) +#define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START) +#define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START) +#define CSI_TST_CTRL (0x70 - CSI_REG_START) +#define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START) +#define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START) +#define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START) +#define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START) +#define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START) + +#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0 +#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1 +#define CSI_SENS_CONF_DATA_POL_SHIFT 2 +#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3 +#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4 +#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7 +#define CSI_SENS_CONF_DATA_FMT_SHIFT 8 +#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10 +#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15 +#define CSI_SENS_CONF_DIVRATIO_SHIFT 16 + +#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT) +#define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT) +#define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT) + +#define MAX_VIDEO_MEM 16 + +enum csi_buffer_state { + CSI_BUF_NEEDS_INIT, + CSI_BUF_PREPARED, +}; + +struct mx3_camera_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_buffer vb; + enum csi_buffer_state state; + struct list_head queue; + + /* One descriptot per scatterlist (per frame) */ + struct dma_async_tx_descriptor *txd; + + /* We have to "build" a scatterlist ourselves - one element per frame */ + struct scatterlist sg; +}; + +/** + * struct mx3_camera_dev - i.MX3x camera (CSI) object + * @dev: camera device, to which the coherent buffer is attached + * @icd: currently attached camera sensor + * @clk: pointer to clock + * @base: remapped register base address + * @pdata: platform data + * @platform_flags: platform flags + * @mclk: master clock frequency in Hz + * @capture: list of capture videobuffers + * @lock: protects video buffer lists + * @active: active video buffer + * @idmac_channel: array of pointers to IPU DMAC DMA channels + * @soc_host: embedded soc_host object + */ +struct mx3_camera_dev { + /* + * i.MX3x is only supposed to handle one camera on its Camera Sensor + * Interface. If anyone ever builds hardware to enable more than one + * camera _simultaneously_, they will have to modify this driver too + */ + struct soc_camera_device *icd; + struct clk *clk; + + void __iomem *base; + + struct mx3_camera_pdata *pdata; + + unsigned long platform_flags; + unsigned long mclk; + + struct list_head capture; + spinlock_t lock; /* Protects video buffer lists */ + struct mx3_camera_buffer *active; + struct vb2_alloc_ctx *alloc_ctx; + enum v4l2_field field; + int sequence; + + /* IDMAC / dmaengine interface */ + struct idmac_channel *idmac_channel[1]; /* We need one channel */ + + struct soc_camera_host soc_host; +}; + +struct dma_chan_request { + struct mx3_camera_dev *mx3_cam; + enum ipu_channel id; +}; + +static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg) +{ + return __raw_readl(mx3->base + reg); +} + +static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg) +{ + __raw_writel(value, mx3->base + reg); +} + +static struct mx3_camera_buffer *to_mx3_vb(struct vb2_buffer *vb) +{ + return container_of(vb, struct mx3_camera_buffer, vb); +} + +/* Called from the IPU IDMAC ISR */ +static void mx3_cam_dma_done(void *arg) +{ + struct idmac_tx_desc *desc = to_tx_desc(arg); + struct dma_chan *chan = desc->txd.chan; + struct idmac_channel *ichannel = to_idmac_chan(chan); + struct mx3_camera_dev *mx3_cam = ichannel->client; + + dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n", + desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0); + + spin_lock(&mx3_cam->lock); + if (mx3_cam->active) { + struct vb2_buffer *vb = &mx3_cam->active->vb; + struct mx3_camera_buffer *buf = to_mx3_vb(vb); + + list_del_init(&buf->queue); + do_gettimeofday(&vb->v4l2_buf.timestamp); + vb->v4l2_buf.field = mx3_cam->field; + vb->v4l2_buf.sequence = mx3_cam->sequence++; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } + + if (list_empty(&mx3_cam->capture)) { + mx3_cam->active = NULL; + spin_unlock(&mx3_cam->lock); + + /* + * stop capture - without further buffers IPU_CHA_BUF0_RDY will + * not get updated + */ + return; + } + + mx3_cam->active = list_entry(mx3_cam->capture.next, + struct mx3_camera_buffer, queue); + spin_unlock(&mx3_cam->lock); +} + +/* + * Videobuf operations + */ + +/* + * Calculate the __buffer__ (not data) size and number of buffers. + */ +static int mx3_videobuf_setup(struct vb2_queue *vq, + unsigned int *count, unsigned int *num_planes, + unsigned long sizes[], void *alloc_ctxs[]) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vq); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; + + if (!mx3_cam->idmac_channel[0]) + return -EINVAL; + + *num_planes = 1; + + mx3_cam->sequence = 0; + sizes[0] = bytes_per_line * icd->user_height; + alloc_ctxs[0] = mx3_cam->alloc_ctx; + + if (!*count) + *count = 32; + + if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) + *count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0]; + + return 0; +} + +static int mx3_videobuf_prepare(struct vb2_buffer *vb) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; + struct scatterlist *sg; + struct mx3_camera_buffer *buf; + size_t new_size; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; + + buf = to_mx3_vb(vb); + sg = &buf->sg; + + new_size = bytes_per_line * icd->user_height; + + if (vb2_plane_size(vb, 0) < new_size) { + dev_err(icd->dev.parent, "Buffer too small (%lu < %zu)\n", + vb2_plane_size(vb, 0), new_size); + return -ENOBUFS; + } + + if (buf->state == CSI_BUF_NEEDS_INIT) { + sg_dma_address(sg) = vb2_dma_contig_plane_paddr(vb, 0); + sg_dma_len(sg) = new_size; + + buf->txd = ichan->dma_chan.device->device_prep_slave_sg( + &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT); + if (!buf->txd) + return -EIO; + + buf->txd->callback_param = buf->txd; + buf->txd->callback = mx3_cam_dma_done; + + buf->state = CSI_BUF_PREPARED; + } + + vb2_set_plane_payload(vb, 0, new_size); + + return 0; +} + +static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) +{ + /* Add more formats as need arises and test possibilities appear... */ + switch (fourcc) { + case V4L2_PIX_FMT_RGB24: + return IPU_PIX_FMT_RGB24; + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_RGB565: + default: + return IPU_PIX_FMT_GENERIC; + } +} + +static void mx3_videobuf_queue(struct vb2_buffer *vb) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct mx3_camera_buffer *buf = to_mx3_vb(vb); + struct dma_async_tx_descriptor *txd = buf->txd; + struct idmac_channel *ichan = to_idmac_chan(txd->chan); + struct idmac_video_param *video = &ichan->params.video; + dma_cookie_t cookie; + u32 fourcc = icd->current_fmt->host_fmt->fourcc; + unsigned long flags; + + /* This is the configuration of one sg-element */ + video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); + + if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { + /* + * If the IPU DMA channel is configured to transport + * generic 8-bit data, we have to set up correctly the + * geometry parameters upon the current pixel format. + * So, since the DMA horizontal parameters are expressed + * in bytes not pixels, convert these in the right unit. + */ + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + BUG_ON(bytes_per_line <= 0); + + video->out_width = bytes_per_line; + video->out_height = icd->user_height; + video->out_stride = bytes_per_line; + } else { + /* + * For IPU known formats the pixel unit will be managed + * successfully by the IPU code + */ + video->out_width = icd->user_width; + video->out_height = icd->user_height; + video->out_stride = icd->user_width; + } + +#ifdef DEBUG + /* helps to see what DMA actually has written */ + if (vb2_plane_vaddr(vb, 0)) + memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); +#endif + + spin_lock_irqsave(&mx3_cam->lock, flags); + list_add_tail(&buf->queue, &mx3_cam->capture); + + if (!mx3_cam->active) + mx3_cam->active = buf; + + spin_unlock_irq(&mx3_cam->lock); + + cookie = txd->tx_submit(txd); + dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n", + cookie, sg_dma_address(&buf->sg)); + + if (cookie >= 0) + return; + + spin_lock_irq(&mx3_cam->lock); + + /* Submit error */ + list_del_init(&buf->queue); + + if (mx3_cam->active == buf) + mx3_cam->active = NULL; + + spin_unlock_irqrestore(&mx3_cam->lock, flags); + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); +} + +static void mx3_videobuf_release(struct vb2_buffer *vb) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct mx3_camera_buffer *buf = to_mx3_vb(vb); + struct dma_async_tx_descriptor *txd = buf->txd; + unsigned long flags; + + dev_dbg(icd->dev.parent, + "Release%s DMA 0x%08x, queue %sempty\n", + mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg), + list_empty(&buf->queue) ? "" : "not "); + + spin_lock_irqsave(&mx3_cam->lock, flags); + + if (mx3_cam->active == buf) + mx3_cam->active = NULL; + + /* Doesn't hurt also if the list is empty */ + list_del_init(&buf->queue); + buf->state = CSI_BUF_NEEDS_INIT; + + if (txd) { + buf->txd = NULL; + if (mx3_cam->idmac_channel[0]) + async_tx_ack(txd); + } + + spin_unlock_irqrestore(&mx3_cam->lock, flags); +} + +static int mx3_videobuf_init(struct vb2_buffer *vb) +{ + struct mx3_camera_buffer *buf = to_mx3_vb(vb); + /* This is for locking debugging only */ + INIT_LIST_HEAD(&buf->queue); + sg_init_table(&buf->sg, 1); + + buf->state = CSI_BUF_NEEDS_INIT; + buf->txd = NULL; + + return 0; +} + +static int mx3_stop_streaming(struct vb2_queue *q) +{ + struct soc_camera_device *icd = soc_camera_from_vb2q(q); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; + struct dma_chan *chan; + struct mx3_camera_buffer *buf, *tmp; + unsigned long flags; + + if (ichan) { + chan = &ichan->dma_chan; + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + } + + spin_lock_irqsave(&mx3_cam->lock, flags); + + mx3_cam->active = NULL; + + list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { + buf->state = CSI_BUF_NEEDS_INIT; + list_del_init(&buf->queue); + } + + spin_unlock_irqrestore(&mx3_cam->lock, flags); + + return 0; +} + +static struct vb2_ops mx3_videobuf_ops = { + .queue_setup = mx3_videobuf_setup, + .buf_prepare = mx3_videobuf_prepare, + .buf_queue = mx3_videobuf_queue, + .buf_cleanup = mx3_videobuf_release, + .buf_init = mx3_videobuf_init, + .wait_prepare = soc_camera_unlock, + .wait_finish = soc_camera_lock, + .stop_streaming = mx3_stop_streaming, +}; + +static int mx3_camera_init_videobuf(struct vb2_queue *q, + struct soc_camera_device *icd) +{ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->drv_priv = icd; + q->ops = &mx3_videobuf_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct mx3_camera_buffer); + + return vb2_queue_init(q); +} + +/* First part of ipu_csi_init_interface() */ +static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam, + struct soc_camera_device *icd) +{ + u32 conf; + long rate; + + /* Set default size: ipu_csi_set_window_size() */ + csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE); + /* ...and position to 0:0: ipu_csi_set_window_pos() */ + conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; + csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL); + + /* We use only gated clock synchronisation mode so far */ + conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT; + + /* Set generic data, platform-biggest bus-width */ + conf |= CSI_SENS_CONF_DATA_FMT_BAYER; + + if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) + conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) + conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) + conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/ + conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + + if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC) + conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC) + conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_DP) + conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_PCP) + conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_HSP) + conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_VSP) + conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; + + /* ipu_csi_init_interface() */ + csi_reg_write(mx3_cam, conf, CSI_SENS_CONF); + + clk_enable(mx3_cam->clk); + rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); + dev_dbg(icd->dev.parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate); + if (rate) + clk_set_rate(mx3_cam->clk, rate); +} + +/* Called with .video_lock held */ +static int mx3_camera_add_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + + if (mx3_cam->icd) + return -EBUSY; + + mx3_camera_activate(mx3_cam, icd); + + mx3_cam->icd = icd; + + dev_info(icd->dev.parent, "MX3 Camera driver attached to camera %d\n", + icd->devnum); + + return 0; +} + +/* Called with .video_lock held */ +static void mx3_camera_remove_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; + + BUG_ON(icd != mx3_cam->icd); + + if (*ichan) { + dma_release_channel(&(*ichan)->dma_chan); + *ichan = NULL; + } + + clk_disable(mx3_cam->clk); + + mx3_cam->icd = NULL; + + dev_info(icd->dev.parent, "MX3 Camera driver detached from camera %d\n", + icd->devnum); +} + +static int test_platform_param(struct mx3_camera_dev *mx3_cam, + unsigned char buswidth, unsigned long *flags) +{ + /* + * Platform specified synchronization and pixel clock polarities are + * only a recommendation and are only used during probing. MX3x + * camera interface only works in master mode, i.e., uses HSYNC and + * VSYNC signals from the sensor + */ + *flags = SOCAM_MASTER | + SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_HSYNC_ACTIVE_LOW | + SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_VSYNC_ACTIVE_LOW | + SOCAM_PCLK_SAMPLE_RISING | + SOCAM_PCLK_SAMPLE_FALLING | + SOCAM_DATA_ACTIVE_HIGH | + SOCAM_DATA_ACTIVE_LOW; + + /* + * If requested data width is supported by the platform, use it or any + * possible lower value - i.MX31 is smart enough to schift bits + */ + if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) + *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | + SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) + *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | + SOCAM_DATAWIDTH_4; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) + *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) + *flags |= SOCAM_DATAWIDTH_4; + + switch (buswidth) { + case 15: + if (!(*flags & SOCAM_DATAWIDTH_15)) + return -EINVAL; + break; + case 10: + if (!(*flags & SOCAM_DATAWIDTH_10)) + return -EINVAL; + break; + case 8: + if (!(*flags & SOCAM_DATAWIDTH_8)) + return -EINVAL; + break; + case 4: + if (!(*flags & SOCAM_DATAWIDTH_4)) + return -EINVAL; + break; + default: + dev_warn(mx3_cam->soc_host.v4l2_dev.dev, + "Unsupported bus width %d\n", buswidth); + return -EINVAL; + } + + return 0; +} + +static int mx3_camera_try_bus_param(struct soc_camera_device *icd, + const unsigned int depth) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + unsigned long bus_flags, camera_flags; + int ret = test_platform_param(mx3_cam, depth, &bus_flags); + + dev_dbg(icd->dev.parent, "request bus width %d bit: %d\n", depth, ret); + + if (ret < 0) + return ret; + + camera_flags = icd->ops->query_bus_param(icd); + + ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); + if (ret < 0) + dev_warn(icd->dev.parent, + "Flags incompatible: camera %lx, host %lx\n", + camera_flags, bus_flags); + + return ret; +} + +static bool chan_filter(struct dma_chan *chan, void *arg) +{ + struct dma_chan_request *rq = arg; + struct mx3_camera_pdata *pdata; + + if (!imx_dma_is_ipu(chan)) + return false; + + if (!rq) + return false; + + pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data; + + return rq->id == chan->chan_id && + pdata->dma_dev == chan->device->dev; +} + +static const struct soc_mbus_pixelfmt mx3_camera_formats[] = { + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .name = "Bayer BGGR (sRGB) 8 bit", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, { + .fourcc = V4L2_PIX_FMT_GREY, + .name = "Monochrome 8 bit", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, +}; + +/* This will be corrected as we get more formats */ +static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) +{ + return fmt->packing == SOC_MBUS_PACKING_NONE || + (fmt->bits_per_sample == 8 && + fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || + (fmt->bits_per_sample > 8 && + fmt->packing == SOC_MBUS_PACKING_EXTEND16); +} + +static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, + struct soc_camera_format_xlate *xlate) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct device *dev = icd->dev.parent; + int formats = 0, ret; + enum v4l2_mbus_pixelcode code; + const struct soc_mbus_pixelfmt *fmt; + + ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + if (ret < 0) + /* No more formats */ + return 0; + + fmt = soc_mbus_get_fmtdesc(code); + if (!fmt) { + dev_warn(icd->dev.parent, + "Unsupported format code #%u: %d\n", idx, code); + return 0; + } + + /* This also checks support for the requested bits-per-sample */ + ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample); + if (ret < 0) + return 0; + + switch (code) { + case V4L2_MBUS_FMT_SBGGR10_1X10: + formats++; + if (xlate) { + xlate->host_fmt = &mx3_camera_formats[0]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + mx3_camera_formats[0].name, code); + } + break; + case V4L2_MBUS_FMT_Y10_1X10: + formats++; + if (xlate) { + xlate->host_fmt = &mx3_camera_formats[1]; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s using code %d\n", + mx3_camera_formats[1].name, code); + } + break; + default: + if (!mx3_camera_packing_supported(fmt)) + return 0; + } + + /* Generic pass-through */ + formats++; + if (xlate) { + xlate->host_fmt = fmt; + xlate->code = code; + dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n", + (fmt->fourcc >> (0*8)) & 0xFF, + (fmt->fourcc >> (1*8)) & 0xFF, + (fmt->fourcc >> (2*8)) & 0xFF, + (fmt->fourcc >> (3*8)) & 0xFF); + xlate++; + } + + return formats; +} + +static void configure_geometry(struct mx3_camera_dev *mx3_cam, + unsigned int width, unsigned int height, + const struct soc_mbus_pixelfmt *fmt) +{ + u32 ctrl, width_field, height_field; + + if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) { + /* + * As the CSI will be configured to output BAYER, here + * the width parameter count the number of samples to + * capture to complete the whole image width. + */ + unsigned int num, den; + int ret = soc_mbus_samples_per_pixel(fmt, &num, &den); + BUG_ON(ret < 0); + width = width * num / den; + } + + /* Setup frame size - this cannot be changed on-the-fly... */ + width_field = width - 1; + height_field = height - 1; + csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); + + csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); + csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2); + + csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE); + + /* ...and position */ + ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; + /* Sensor does the cropping */ + csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); +} + +static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; + /* We have to use IDMAC_IC_7 for Bayer / generic data */ + struct dma_chan_request rq = {.mx3_cam = mx3_cam, + .id = IDMAC_IC_7}; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_PRIVATE, mask); + chan = dma_request_channel(mask, chan_filter, &rq); + if (!chan) + return -EBUSY; + + *ichan = to_idmac_chan(chan); + (*ichan)->client = mx3_cam; + + return 0; +} + +/* + * FIXME: learn to use stride != width, then we can keep stride properly aligned + * and support arbitrary (even) widths. + */ +static inline void stride_align(__u32 *width) +{ + if (ALIGN(*width, 8) < 4096) + *width = ALIGN(*width, 8); + else + *width = *width & ~7; +} + +/* + * As long as we don't implement host-side cropping and scaling, we can use + * default g_crop and cropcap from soc_camera.c + */ +static int mx3_camera_set_crop(struct soc_camera_device *icd, + struct v4l2_crop *a) +{ + struct v4l2_rect *rect = &a->c; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct v4l2_mbus_framefmt mf; + int ret; + + soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); + soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); + + ret = v4l2_subdev_call(sd, video, s_crop, a); + if (ret < 0) + return ret; + + /* The capture device might have changed its output sizes */ + ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + if (ret < 0) + return ret; + + if (mf.code != icd->current_fmt->code) + return -EINVAL; + + if (mf.width & 7) { + /* Ouch! We can only handle 8-byte aligned width... */ + stride_align(&mf.width); + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + if (ret < 0) + return ret; + } + + if (mf.width != icd->user_width || mf.height != icd->user_height) + configure_geometry(mx3_cam, mf.width, mf.height, + icd->current_fmt->host_fmt); + + dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", + mf.width, mf.height); + + icd->user_width = mf.width; + icd->user_height = mf.height; + + return ret; +} + +static int mx3_camera_set_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) { + dev_warn(icd->dev.parent, "Format %x not found\n", + pix->pixelformat); + return -EINVAL; + } + + stride_align(&pix->width); + dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height); + + /* + * Might have to perform a complete interface initialisation like in + * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider + * mxc_v4l2_s_fmt() + */ + + configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt); + + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + if (ret < 0) + return ret; + + if (mf.code != xlate->code) + return -EINVAL; + + if (!mx3_cam->idmac_channel[0]) { + ret = acquire_dma_channel(mx3_cam); + if (ret < 0) + return ret; + } + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + mx3_cam->field = mf.field; + pix->colorspace = mf.colorspace; + icd->current_fmt = xlate; + + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (pix->bytesperline < 0) + return pix->bytesperline; + pix->sizeimage = pix->height * pix->bytesperline; + + dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height); + + return ret; +} + +static int mx3_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + __u32 pixfmt = pix->pixelformat; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (pixfmt && !xlate) { + dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + /* limit to MX3 hardware capabilities */ + if (pix->height > 4096) + pix->height = 4096; + if (pix->width > 4096) + pix->width = 4096; + + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (pix->bytesperline < 0) + return pix->bytesperline; + pix->sizeimage = pix->height * pix->bytesperline; + + /* limit to sensor capabilities */ + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + if (ret < 0) + return ret; + + pix->width = mf.width; + pix->height = mf.height; + pix->colorspace = mf.colorspace; + + switch (mf.field) { + case V4L2_FIELD_ANY: + pix->field = V4L2_FIELD_NONE; + break; + case V4L2_FIELD_NONE: + break; + default: + dev_err(icd->dev.parent, "Field type %d unsupported.\n", + mf.field); + ret = -EINVAL; + } + + return ret; +} + +static int mx3_camera_reqbufs(struct soc_camera_device *icd, + struct v4l2_requestbuffers *p) +{ + return 0; +} + +static unsigned int mx3_camera_poll(struct file *file, poll_table *pt) +{ + struct soc_camera_device *icd = file->private_data; + + return vb2_poll(&icd->vb2_vidq, file, pt); +} + +static int mx3_camera_querycap(struct soc_camera_host *ici, + struct v4l2_capability *cap) +{ + /* cap->name is set by the firendly caller:-> */ + strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card)); + cap->version = KERNEL_VERSION(0, 2, 2); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + + return 0; +} + +static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + unsigned long bus_flags, camera_flags, common_flags; + u32 dw, sens_conf; + const struct soc_mbus_pixelfmt *fmt; + int buswidth; + int ret; + const struct soc_camera_format_xlate *xlate; + struct device *dev = icd->dev.parent; + + fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); + if (!fmt) + return -EINVAL; + + buswidth = fmt->bits_per_sample; + ret = test_platform_param(mx3_cam, buswidth, &bus_flags); + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(dev, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); + + if (ret < 0) + return ret; + + camera_flags = icd->ops->query_bus_param(icd); + + common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); + dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", + camera_flags, bus_flags, common_flags); + if (!common_flags) { + dev_dbg(dev, "no common flags"); + return -EINVAL; + } + + /* Make choices, based on platform preferences */ + if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if (mx3_cam->platform_flags & MX3_CAMERA_HSP) + common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + } + + if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if (mx3_cam->platform_flags & MX3_CAMERA_VSP) + common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + } + + if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && + (common_flags & SOCAM_DATA_ACTIVE_LOW)) { + if (mx3_cam->platform_flags & MX3_CAMERA_DP) + common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_DATA_ACTIVE_LOW; + } + + if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && + (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if (mx3_cam->platform_flags & MX3_CAMERA_PCP) + common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + else + common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + } + + /* + * Make the camera work in widest common mode, we'll take care of + * the rest + */ + if (common_flags & SOCAM_DATAWIDTH_15) + common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | + SOCAM_DATAWIDTH_15; + else if (common_flags & SOCAM_DATAWIDTH_10) + common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | + SOCAM_DATAWIDTH_10; + else if (common_flags & SOCAM_DATAWIDTH_8) + common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | + SOCAM_DATAWIDTH_8; + else + common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | + SOCAM_DATAWIDTH_4; + + ret = icd->ops->set_bus_param(icd, common_flags); + if (ret < 0) { + dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n", + common_flags, ret); + return ret; + } + + /* + * So far only gated clock mode is supported. Add a line + * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) | + * below and select the required mode when supporting other + * synchronisation protocols. + */ + sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) & + ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) | + (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) | + (1 << CSI_SENS_CONF_DATA_POL_SHIFT) | + (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) | + (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) | + (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT)); + + /* TODO: Support RGB and YUV formats */ + + /* This has been set in mx3_camera_activate(), but we clear it above */ + sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; + + if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) + sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; + if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) + sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; + if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) + sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; + if (common_flags & SOCAM_DATA_ACTIVE_LOW) + sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; + + /* Just do what we're asked to do */ + switch (xlate->host_fmt->bits_per_sample) { + case 4: + dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + break; + case 8: + dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + break; + case 10: + dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + break; + default: + /* + * Actually it can only be 15 now, default is just to silence + * compiler warnings + */ + case 15: + dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + } + + csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); + + dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw); + + return 0; +} + +static struct soc_camera_host_ops mx3_soc_camera_host_ops = { + .owner = THIS_MODULE, + .add = mx3_camera_add_device, + .remove = mx3_camera_remove_device, + .set_crop = mx3_camera_set_crop, + .set_fmt = mx3_camera_set_fmt, + .try_fmt = mx3_camera_try_fmt, + .get_formats = mx3_camera_get_formats, + .init_videobuf2 = mx3_camera_init_videobuf, + .reqbufs = mx3_camera_reqbufs, + .poll = mx3_camera_poll, + .querycap = mx3_camera_querycap, + .set_bus_param = mx3_camera_set_bus_param, +}; + +static int __devinit mx3_camera_probe(struct platform_device *pdev) +{ + struct mx3_camera_dev *mx3_cam; + struct resource *res; + void __iomem *base; + int err = 0; + struct soc_camera_host *soc_host; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENODEV; + goto egetres; + } + + mx3_cam = vzalloc(sizeof(*mx3_cam)); + if (!mx3_cam) { + dev_err(&pdev->dev, "Could not allocate mx3 camera object\n"); + err = -ENOMEM; + goto ealloc; + } + + mx3_cam->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(mx3_cam->clk)) { + err = PTR_ERR(mx3_cam->clk); + goto eclkget; + } + + mx3_cam->pdata = pdev->dev.platform_data; + mx3_cam->platform_flags = mx3_cam->pdata->flags; + if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 | + MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 | + MX3_CAMERA_DATAWIDTH_15))) { + /* + * Platform hasn't set available data widths. This is bad. + * Warn and use a default. + */ + dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " + "data widths, using default 8 bit\n"); + mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; + } + + mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; + if (!mx3_cam->mclk) { + dev_warn(&pdev->dev, + "mclk_10khz == 0! Please, fix your platform data. " + "Using default 20MHz\n"); + mx3_cam->mclk = 20000000; + } + + /* list of video-buffers */ + INIT_LIST_HEAD(&mx3_cam->capture); + spin_lock_init(&mx3_cam->lock); + + base = ioremap(res->start, resource_size(res)); + if (!base) { + pr_err("Couldn't map %x@%x\n", resource_size(res), res->start); + err = -ENOMEM; + goto eioremap; + } + + mx3_cam->base = base; + + soc_host = &mx3_cam->soc_host; + soc_host->drv_name = MX3_CAM_DRV_NAME; + soc_host->ops = &mx3_soc_camera_host_ops; + soc_host->priv = mx3_cam; + soc_host->v4l2_dev.dev = &pdev->dev; + soc_host->nr = pdev->id; + + mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(mx3_cam->alloc_ctx)) { + err = PTR_ERR(mx3_cam->alloc_ctx); + goto eallocctx; + } + + err = soc_camera_host_register(soc_host); + if (err) + goto ecamhostreg; + + /* IDMAC interface */ + dmaengine_get(); + + return 0; + +ecamhostreg: + vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); +eallocctx: + iounmap(base); +eioremap: + clk_put(mx3_cam->clk); +eclkget: + vfree(mx3_cam); +ealloc: +egetres: + return err; +} + +static int __devexit mx3_camera_remove(struct platform_device *pdev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct mx3_camera_dev *mx3_cam = container_of(soc_host, + struct mx3_camera_dev, soc_host); + + clk_put(mx3_cam->clk); + + soc_camera_host_unregister(soc_host); + + iounmap(mx3_cam->base); + + /* + * The channel has either not been allocated, + * or should have been released + */ + if (WARN_ON(mx3_cam->idmac_channel[0])) + dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan); + + vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); + + vfree(mx3_cam); + + dmaengine_put(); + + dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n"); + + return 0; +} + +static struct platform_driver mx3_camera_driver = { + .driver = { + .name = MX3_CAM_DRV_NAME, + }, + .probe = mx3_camera_probe, + .remove = __devexit_p(mx3_camera_remove), +}; + + +static int __init mx3_camera_init(void) +{ + return platform_driver_register(&mx3_camera_driver); +} + +static void __exit mx3_camera_exit(void) +{ + platform_driver_unregister(&mx3_camera_driver); +} + +module_init(mx3_camera_init); +module_exit(mx3_camera_exit); + +MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mxb.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mxb.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mxb.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mxb.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,872 @@ +/* + mxb - v4l2 driver for the Multimedia eXtension Board + + Copyright (C) 1998-2006 Michael Hunold + + Visit http://www.themm.net/~mihu/linux/saa7146/mxb.html + for further details about this card. + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEBUG_VARIABLE debug + +#include +#include +#include +#include + +#include "mxb.h" +#include "tea6415c.h" +#include "tea6420.h" + +#define I2C_SAA7111A 0x24 +#define I2C_TDA9840 0x42 +#define I2C_TEA6415C 0x43 +#define I2C_TEA6420_1 0x4c +#define I2C_TEA6420_2 0x4d +#define I2C_TUNER 0x60 + +#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) + +/* global variable */ +static int mxb_num; + +/* initial frequence the tuner will be tuned to. + in verden (lower saxony, germany) 4148 is a + channel called "phoenix" */ +static int freq = 4148; +module_param(freq, int, 0644); +MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); + +#define MXB_INPUTS 4 +enum { TUNER, AUX1, AUX3, AUX3_YC }; + +static struct v4l2_input mxb_inputs[MXB_INPUTS] = { + { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, + { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, +}; + +/* this array holds the information, which port of the saa7146 each + input actually uses. the mxb uses port 0 for every input */ +static struct { + int hps_source; + int hps_sync; +} input_port_selection[MXB_INPUTS] = { + { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, + { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, + { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, + { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, +}; + +/* this array holds the information of the audio source (mxb_audios), + which has to be switched corresponding to the video source (mxb_channels) */ +static int video_audio_connect[MXB_INPUTS] = + { 0, 1, 3, 3 }; + +struct mxb_routing { + u32 input; + u32 output; +}; + +/* These are the necessary input-output-pins for bringing one audio source + (see above) to the CD-output. Note that gain is set to 0 in this table. */ +static struct mxb_routing TEA6420_cd[MXB_AUDIOS + 1][2] = { + { { 1, 1 }, { 1, 1 } }, /* Tuner */ + { { 5, 1 }, { 6, 1 } }, /* AUX 1 */ + { { 4, 1 }, { 6, 1 } }, /* AUX 2 */ + { { 3, 1 }, { 6, 1 } }, /* AUX 3 */ + { { 1, 1 }, { 3, 1 } }, /* Radio */ + { { 1, 1 }, { 2, 1 } }, /* CD-Rom */ + { { 6, 1 }, { 6, 1 } } /* Mute */ +}; + +/* These are the necessary input-output-pins for bringing one audio source + (see above) to the line-output. Note that gain is set to 0 in this table. */ +static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = { + { { 2, 3 }, { 1, 2 } }, + { { 5, 3 }, { 6, 2 } }, + { { 4, 3 }, { 6, 2 } }, + { { 3, 3 }, { 6, 2 } }, + { { 2, 3 }, { 3, 2 } }, + { { 2, 3 }, { 2, 2 } }, + { { 6, 3 }, { 6, 2 } } /* Mute */ +}; + +#define MAXCONTROLS 1 +static struct v4l2_queryctrl mxb_controls[] = { + { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 }, +}; + +struct mxb +{ + struct video_device *video_dev; + struct video_device *vbi_dev; + + struct i2c_adapter i2c_adapter; + + struct v4l2_subdev *saa7111a; + struct v4l2_subdev *tda9840; + struct v4l2_subdev *tea6415c; + struct v4l2_subdev *tuner; + struct v4l2_subdev *tea6420_1; + struct v4l2_subdev *tea6420_2; + + int cur_mode; /* current audio mode (mono, stereo, ...) */ + int cur_input; /* current input */ + int cur_mute; /* current mute status */ + struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */ +}; + +#define saa7111a_call(mxb, o, f, args...) \ + v4l2_subdev_call(mxb->saa7111a, o, f, ##args) +#define tda9840_call(mxb, o, f, args...) \ + v4l2_subdev_call(mxb->tda9840, o, f, ##args) +#define tea6415c_call(mxb, o, f, args...) \ + v4l2_subdev_call(mxb->tea6415c, o, f, ##args) +#define tuner_call(mxb, o, f, args...) \ + v4l2_subdev_call(mxb->tuner, o, f, ##args) +#define call_all(dev, o, f, args...) \ + v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args) + +static inline void tea6420_route_cd(struct mxb *mxb, int idx) +{ + v4l2_subdev_call(mxb->tea6420_1, audio, s_routing, + TEA6420_cd[idx][0].input, TEA6420_cd[idx][0].output, 0); + v4l2_subdev_call(mxb->tea6420_2, audio, s_routing, + TEA6420_cd[idx][1].input, TEA6420_cd[idx][1].output, 0); +} + +static inline void tea6420_route_line(struct mxb *mxb, int idx) +{ + v4l2_subdev_call(mxb->tea6420_1, audio, s_routing, + TEA6420_line[idx][0].input, TEA6420_line[idx][0].output, 0); + v4l2_subdev_call(mxb->tea6420_2, audio, s_routing, + TEA6420_line[idx][1].input, TEA6420_line[idx][1].output, 0); +} + +static struct saa7146_extension extension; + +static int mxb_probe(struct saa7146_dev *dev) +{ + struct mxb *mxb = NULL; + + mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL); + if (mxb == NULL) { + DEB_D(("not enough kernel memory.\n")); + return -ENOMEM; + } + + snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num); + + saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); + if (i2c_add_adapter(&mxb->i2c_adapter) < 0) { + DEB_S(("cannot register i2c-device. skipping.\n")); + kfree(mxb); + return -EFAULT; + } + + mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, + "saa7111", I2C_SAA7111A, NULL); + mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, + "tea6420", I2C_TEA6420_1, NULL); + mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, + "tea6420", I2C_TEA6420_2, NULL); + mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, + "tea6415c", I2C_TEA6415C, NULL); + mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, + "tda9840", I2C_TDA9840, NULL); + mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, + "tuner", I2C_TUNER, NULL); + + /* check if all devices are present */ + if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || + !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) { + printk("mxb: did not find all i2c devices. aborting\n"); + i2c_del_adapter(&mxb->i2c_adapter); + kfree(mxb); + return -ENODEV; + } + + /* all devices are present, probe was successful */ + + /* we store the pointer in our private data field */ + dev->ext_priv = mxb; + + return 0; +} + +/* some init data for the saa7740, the so-called 'sound arena module'. + there are no specs available, so we simply use some init values */ +static struct { + int length; + char data[9]; +} mxb_saa7740_init[] = { + { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } }, + { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } }, + { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } }, + { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } }, + { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } }, + { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } }, + { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } }, + { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } }, + { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } }, + { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } }, + { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } }, + { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } }, + { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } }, + { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } }, + { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } }, + { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } }, + { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } }, + { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } }, + { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } }, + { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } }, + { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } }, + { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } }, + { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } }, + { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } }, + { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } }, + { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } }, + { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } }, + { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } }, + { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } }, + { 3, { 0x48, 0x00, 0x01 } }, + { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } }, + { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } }, + { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } }, + { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } }, + { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } }, + { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } }, + { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } }, + { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } }, + { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } }, + { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } }, + { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } }, + { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } }, + { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } }, + { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } }, + { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } }, + { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } }, + { 3, { 0x80, 0xb3, 0x0a } }, + {-1, { 0 } } +}; + +/* bring hardware to a sane state. this has to be done, just in case someone + wants to capture from this device before it has been properly initialized. + the capture engine would badly fail, because no valid signal arrives on the + saa7146, thus leading to timeouts and stuff. */ +static int mxb_init_done(struct saa7146_dev* dev) +{ + struct mxb* mxb = (struct mxb*)dev->ext_priv; + struct i2c_msg msg; + struct tuner_setup tun_setup; + v4l2_std_id std = V4L2_STD_PAL_BG; + + int i = 0, err = 0; + + /* select video mode in saa7111a */ + saa7111a_call(mxb, core, s_std, std); + + /* select tuner-output on saa7111a */ + i = 0; + saa7111a_call(mxb, video, s_routing, SAA7115_COMPOSITE0, + SAA7111_FMT_CCIR, 0); + + /* select a tuner type */ + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.addr = ADDR_UNSET; + tun_setup.type = TUNER_PHILIPS_PAL; + tuner_call(mxb, tuner, s_type_addr, &tun_setup); + /* tune in some frequency on tuner */ + mxb->cur_freq.tuner = 0; + mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV; + mxb->cur_freq.frequency = freq; + tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq); + + /* set a default video standard */ + tuner_call(mxb, core, s_std, std); + + /* mute audio on tea6420s */ + tea6420_route_line(mxb, 6); + tea6420_route_cd(mxb, 6); + + /* switch to tuner-channel on tea6415c */ + tea6415c_call(mxb, video, s_routing, 3, 17, 0); + + /* select tuner-output on multicable on tea6415c */ + tea6415c_call(mxb, video, s_routing, 3, 13, 0); + + /* the rest for mxb */ + mxb->cur_input = 0; + mxb->cur_mute = 1; + + mxb->cur_mode = V4L2_TUNER_MODE_STEREO; + + /* check if the saa7740 (aka 'sound arena module') is present + on the mxb. if so, we must initialize it. due to lack of + informations about the saa7740, the values were reverse + engineered. */ + msg.addr = 0x1b; + msg.flags = 0; + msg.len = mxb_saa7740_init[0].length; + msg.buf = &mxb_saa7740_init[0].data[0]; + + err = i2c_transfer(&mxb->i2c_adapter, &msg, 1); + if (err == 1) { + /* the sound arena module is a pos, that's probably the reason + philips refuses to hand out a datasheet for the saa7740... + it seems to screw up the i2c bus, so we disable fast irq + based i2c transactions here and rely on the slow and safe + polling method ... */ + extension.flags &= ~SAA7146_USE_I2C_IRQ; + for (i = 1; ; i++) { + if (-1 == mxb_saa7740_init[i].length) + break; + + msg.len = mxb_saa7740_init[i].length; + msg.buf = &mxb_saa7740_init[i].data[0]; + err = i2c_transfer(&mxb->i2c_adapter, &msg, 1); + if (err != 1) { + DEB_D(("failed to initialize 'sound arena module'.\n")); + goto err; + } + } + INFO(("'sound arena module' detected.\n")); + } +err: + /* the rest for saa7146: you should definitely set some basic values + for the input-port handling of the saa7146. */ + + /* ext->saa has been filled by the core driver */ + + /* some stuff is done via variables */ + saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, + input_port_selection[mxb->cur_input].hps_sync); + + /* some stuff is done via direct write to the registers */ + + /* this is ugly, but because of the fact that this is completely + hardware dependend, it should be done directly... */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x02000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + return 0; +} + +/* interrupt-handler. this gets called when irq_mask is != 0. + it must clear the interrupt-bits in irq_mask it has handled */ +/* +void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask) +{ + struct mxb* mxb = (struct mxb*)dev->ext_priv; +} +*/ + +static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + int i; + + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == qc->id) { + *qc = mxb_controls[i]; + DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + return 0; + } + } + return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); +} + +static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + int i; + + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == vc->id) + break; + } + + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); + + if (vc->id == V4L2_CID_AUDIO_MUTE) { + vc->value = mxb->cur_mute; + DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); + return 0; + } + + DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + int i = 0; + + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == vc->id) + break; + } + + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); + + if (vc->id == V4L2_CID_AUDIO_MUTE) { + mxb->cur_mute = vc->value; + /* switch the audio-source */ + tea6420_route_line(mxb, vc->value ? 6 : + video_audio_connect[mxb->cur_input]); + DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value)); + } + return 0; +} + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + if (i->index >= MXB_INPUTS) + return -EINVAL; + memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + *i = mxb->cur_input; + + DEB_EE(("VIDIOC_G_INPUT %d.\n", *i)); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + int err = 0; + int i = 0; + + DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + + if (input >= MXB_INPUTS) + return -EINVAL; + + mxb->cur_input = input; + + saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, + input_port_selection[input].hps_sync); + + /* prepare switching of tea6415c and saa7111a; + have a look at the 'background'-file for further informations */ + switch (input) { + case TUNER: + i = SAA7115_COMPOSITE0; + + err = tea6415c_call(mxb, video, s_routing, 3, 17, 0); + + /* connect tuner-output always to multicable */ + if (!err) + err = tea6415c_call(mxb, video, s_routing, 3, 13, 0); + break; + case AUX3_YC: + /* nothing to be done here. aux3_yc is + directly connected to the saa711a */ + i = SAA7115_SVIDEO1; + break; + case AUX3: + /* nothing to be done here. aux3 is + directly connected to the saa711a */ + i = SAA7115_COMPOSITE1; + break; + case AUX1: + i = SAA7115_COMPOSITE0; + err = tea6415c_call(mxb, video, s_routing, 1, 17, 0); + break; + } + + if (err) + return err; + + /* switch video in saa7111a */ + if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0)) + printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a.\n"); + + /* switch the audio-source only if necessary */ + if (0 == mxb->cur_mute) + tea6420_route_line(mxb, video_audio_connect[input]); + + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + if (t->index) { + DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); + return -EINVAL; + } + + DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); + + memset(t, 0, sizeof(*t)); + strlcpy(t->name, "TV Tuner", sizeof(t->name)); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + t->audmode = mxb->cur_mode; + return call_all(dev, tuner, g_tuner, t); +} + +static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + if (t->index) { + DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index)); + return -EINVAL; + } + + mxb->cur_mode = t->audmode; + return call_all(dev, tuner, s_tuner, t); +} + +static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + if (mxb->cur_input) { + DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", + mxb->cur_input)); + return -EINVAL; + } + + *f = mxb->cur_freq; + + DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + struct saa7146_vv *vv = dev->vv_data; + + if (f->tuner) + return -EINVAL; + + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + + if (mxb->cur_input) { + DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); + return -EINVAL; + } + + mxb->cur_freq = *f; + DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); + + /* tune in desired frequency */ + tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq); + + /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ + spin_lock(&dev->slock); + vv->vbi_fieldcount = 0; + spin_unlock(&dev->slock); + + return 0; +} + +static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + if (a->index > MXB_INPUTS) { + DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); + return -EINVAL; + } + + DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index)); + memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); + return 0; +} + +static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index)); + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + + return call_all(dev, core, g_register, reg); +} + +static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + + return call_all(dev, core, s_register, reg); +} +#endif + +static long vidioc_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + switch (cmd) { + case MXB_S_AUDIO_CD: + { + int i = *(int *)arg; + + if (i < 0 || i >= MXB_AUDIOS) { + DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i)); + return -EINVAL; + } + + DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i)); + + tea6420_route_cd(mxb, i); + return 0; + } + case MXB_S_AUDIO_LINE: + { + int i = *(int *)arg; + + if (i < 0 || i >= MXB_AUDIOS) { + DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i)); + return -EINVAL; + } + + DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i)); + tea6420_route_line(mxb, i); + return 0; + } + default: +/* + DEB2(printk("does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} + +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct mxb *mxb; + + DEB_EE(("dev:%p\n", dev)); + + saa7146_vv_init(dev, &vv_data); + if (mxb_probe(dev)) { + saa7146_vv_release(dev); + return -1; + } + mxb = (struct mxb *)dev->ext_priv; + + vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; + vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; + vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; + vv_data.ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data.ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data.ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data.ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data.ops.vidioc_g_audio = vidioc_g_audio; + vv_data.ops.vidioc_s_audio = vidioc_s_audio; +#ifdef CONFIG_VIDEO_ADV_DEBUG + vv_data.ops.vidioc_g_register = vidioc_g_register; + vv_data.ops.vidioc_s_register = vidioc_s_register; +#endif + vv_data.ops.vidioc_default = vidioc_default; + if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { + ERR(("cannot register capture v4l2 device. skipping.\n")); + saa7146_vv_release(dev); + return -1; + } + + /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ + if (MXB_BOARD_CAN_DO_VBI(dev)) { + if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { + ERR(("cannot register vbi v4l2 device. skipping.\n")); + } + } + + printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); + + mxb_num++; + mxb_init_done(dev); + return 0; +} + +static int mxb_detach(struct saa7146_dev *dev) +{ + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + DEB_EE(("dev:%p\n", dev)); + + saa7146_unregister_device(&mxb->video_dev,dev); + if (MXB_BOARD_CAN_DO_VBI(dev)) + saa7146_unregister_device(&mxb->vbi_dev, dev); + saa7146_vv_release(dev); + + mxb_num--; + + i2c_del_adapter(&mxb->i2c_adapter); + kfree(mxb); + + return 0; +} + +static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard) +{ + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + if (V4L2_STD_PAL_I == standard->id) { + v4l2_std_id std = V4L2_STD_PAL_I; + + DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n")); + /* set the 7146 gpio register -- I don't know what this does exactly */ + saa7146_write(dev, GPIO_CTRL, 0x00404050); + /* unset the 7111 gpio register -- I don't know what this does exactly */ + saa7111a_call(mxb, core, s_gpio, 0); + tuner_call(mxb, core, s_std, std); + } else { + v4l2_std_id std = V4L2_STD_PAL_BG; + + DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n")); + /* set the 7146 gpio register -- I don't know what this does exactly */ + saa7146_write(dev, GPIO_CTRL, 0x00404050); + /* set the 7111 gpio register -- I don't know what this does exactly */ + saa7111a_call(mxb, core, s_gpio, 1); + tuner_call(mxb, core, s_std, std); + } + return 0; +} + +static struct saa7146_standard standard[] = { + { + .name = "PAL-BG", .id = V4L2_STD_PAL_BG, + .v_offset = 0x17, .v_field = 288, + .h_offset = 0x14, .h_pixels = 680, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "PAL-I", .id = V4L2_STD_PAL_I, + .v_offset = 0x17, .v_field = 288, + .h_offset = 0x14, .h_pixels = 680, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x16, .v_field = 240, + .h_offset = 0x06, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + }, { + .name = "SECAM", .id = V4L2_STD_SECAM, + .v_offset = 0x14, .v_field = 288, + .h_offset = 0x14, .h_pixels = 720, + .v_max_out = 576, .h_max_out = 768, + } +}; + +static struct saa7146_pci_extension_data mxb = { + .ext_priv = "Multimedia eXtension Board", + .ext = &extension, +}; + +static struct pci_device_id pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7146, + .subvendor = 0x0000, + .subdevice = 0x0000, + .driver_data = (unsigned long)&mxb, + }, { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +static struct saa7146_ext_vv vv_data = { + .inputs = MXB_INPUTS, + .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE, + .stds = &standard[0], + .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), + .std_callback = &std_callback, +}; + +static struct saa7146_extension extension = { + .name = MXB_IDENTIFIER, + .flags = SAA7146_USE_I2C_IRQ, + + .pci_tbl = &pci_tbl[0], + .module = THIS_MODULE, + + .attach = mxb_attach, + .detach = mxb_detach, + + .irq_mask = 0, + .irq_func = NULL, +}; + +static int __init mxb_init_module(void) +{ + if (saa7146_register_extension(&extension)) { + DEB_S(("failed to register extension.\n")); + return -ENODEV; + } + + return 0; +} + +static void __exit mxb_cleanup_module(void) +{ + saa7146_unregister_extension(&extension); +} + +module_init(mxb_init_module); +module_exit(mxb_cleanup_module); + +MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'"); +MODULE_AUTHOR("Michael Hunold "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mxb.h v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mxb.h --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mxb.h 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/mxb.h 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,42 @@ +#ifndef __MXB__ +#define __MXB__ + +#define BASE_VIDIOC_MXB 10 + +#define MXB_S_AUDIO_CD _IOW ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+0, int) +#define MXB_S_AUDIO_LINE _IOW ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+1, int) + +#define MXB_IDENTIFIER "Multimedia eXtension Board" + +#define MXB_AUDIOS 6 + +/* these are the available audio sources, which can switched + to the line- and cd-output individually */ +static struct v4l2_audio mxb_audios[MXB_AUDIOS] = { + { + .index = 0, + .name = "Tuner", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 1, + .name = "AUX1", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 2, + .name = "AUX2", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 3, + .name = "AUX3", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 4, + .name = "Radio (X9)", + .capability = V4L2_AUDCAP_STEREO, + } , { + .index = 5, + .name = "CD-ROM (X10)", + .capability = V4L2_AUDCAP_STEREO, + } +}; +#endif diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/noon010pc30.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/noon010pc30.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/noon010pc30.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/noon010pc30.c 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,792 @@ +/* + * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP + * + * Copyright (C) 2010 Samsung Electronics + * Contact: Sylwester Nawrocki, + * + * Initial register configuration based on a driver authored by + * HeungJun Kim . + * + * 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, or + * (at your option) any later vergsion. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable module debug trace. Set to 1 to enable."); + +#define MODULE_NAME "NOON010PC30" + +/* + * Register offsets within a page + * b15..b8 - page id, b7..b0 - register address + */ +#define POWER_CTRL_REG 0x0001 +#define PAGEMODE_REG 0x03 +#define DEVICE_ID_REG 0x0004 +#define NOON010PC30_ID 0x86 +#define VDO_CTL_REG(n) (0x0010 + (n)) +#define SYNC_CTL_REG 0x0012 +/* Window size and position */ +#define WIN_ROWH_REG 0x0013 +#define WIN_ROWL_REG 0x0014 +#define WIN_COLH_REG 0x0015 +#define WIN_COLL_REG 0x0016 +#define WIN_HEIGHTH_REG 0x0017 +#define WIN_HEIGHTL_REG 0x0018 +#define WIN_WIDTHH_REG 0x0019 +#define WIN_WIDTHL_REG 0x001A +#define HBLANKH_REG 0x001B +#define HBLANKL_REG 0x001C +#define VSYNCH_REG 0x001D +#define VSYNCL_REG 0x001E +/* VSYNC control */ +#define VS_CTL_REG(n) (0x00A1 + (n)) +/* page 1 */ +#define ISP_CTL_REG(n) (0x0110 + (n)) +#define YOFS_REG 0x0119 +#define DARK_YOFS_REG 0x011A +#define SAT_CTL_REG 0x0120 +#define BSAT_REG 0x0121 +#define RSAT_REG 0x0122 +/* Color correction */ +#define CMC_CTL_REG 0x0130 +#define CMC_OFSGH_REG 0x0133 +#define CMC_OFSGL_REG 0x0135 +#define CMC_SIGN_REG 0x0136 +#define CMC_GOFS_REG 0x0137 +#define CMC_COEF_REG(n) (0x0138 + (n)) +#define CMC_OFS_REG(n) (0x0141 + (n)) +/* Gamma correction */ +#define GMA_CTL_REG 0x0160 +#define GMA_COEF_REG(n) (0x0161 + (n)) +/* Lens Shading */ +#define LENS_CTRL_REG 0x01D0 +#define LENS_XCEN_REG 0x01D1 +#define LENS_YCEN_REG 0x01D2 +#define LENS_RC_REG 0x01D3 +#define LENS_GC_REG 0x01D4 +#define LENS_BC_REG 0x01D5 +#define L_AGON_REG 0x01D6 +#define L_AGOFF_REG 0x01D7 +/* Page 3 - Auto Exposure */ +#define AE_CTL_REG(n) (0x0310 + (n)) +#define AE_CTL9_REG 0x032C +#define AE_CTL10_REG 0x032D +#define AE_YLVL_REG 0x031C +#define AE_YTH_REG(n) (0x031D + (n)) +#define AE_WGT_REG 0x0326 +#define EXP_TIMEH_REG 0x0333 +#define EXP_TIMEM_REG 0x0334 +#define EXP_TIMEL_REG 0x0335 +#define EXP_MMINH_REG 0x0336 +#define EXP_MMINL_REG 0x0337 +#define EXP_MMAXH_REG 0x0338 +#define EXP_MMAXM_REG 0x0339 +#define EXP_MMAXL_REG 0x033A +/* Page 4 - Auto White Balance */ +#define AWB_CTL_REG(n) (0x0410 + (n)) +#define AWB_ENABE 0x80 +#define AWB_WGHT_REG 0x0419 +#define BGAIN_PAR_REG(n) (0x044F + (n)) +/* Manual white balance, when AWB_CTL2[0]=1 */ +#define MWB_RGAIN_REG 0x0466 +#define MWB_BGAIN_REG 0x0467 + +/* The token to mark an array end */ +#define REG_TERM 0xFFFF + +struct noon010_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 ispctl1_reg; +}; + +struct noon010_frmsize { + u16 width; + u16 height; + int vid_ctl1; +}; + +static const char * const noon010_supply_name[] = { + "vdd_core", "vddio", "vdda" +}; + +#define NOON010_NUM_SUPPLIES ARRAY_SIZE(noon010_supply_name) + +struct noon010_info { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + const struct noon010pc30_platform_data *pdata; + const struct noon010_format *curr_fmt; + const struct noon010_frmsize *curr_win; + unsigned int hflip:1; + unsigned int vflip:1; + unsigned int power:1; + u8 i2c_reg_page; + struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES]; + u32 gpio_nreset; + u32 gpio_nstby; +}; + +struct i2c_regval { + u16 addr; + u16 val; +}; + +/* Supported resolutions. */ +static const struct noon010_frmsize noon010_sizes[] = { + { + .width = 352, + .height = 288, + .vid_ctl1 = 0, + }, { + .width = 176, + .height = 144, + .vid_ctl1 = 0x10, + }, { + .width = 88, + .height = 72, + .vid_ctl1 = 0x20, + }, +}; + +/* Supported pixel formats. */ +static const struct noon010_format noon010_formats[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0x03, + }, { + .code = V4L2_MBUS_FMT_YVYU8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0x02, + }, { + .code = V4L2_MBUS_FMT_VYUY8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0, + }, { + .code = V4L2_MBUS_FMT_UYVY8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0x01, + }, { + .code = V4L2_MBUS_FMT_RGB565_2X8_BE, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0x40, + }, +}; + +static const struct i2c_regval noon010_base_regs[] = { + { WIN_COLL_REG, 0x06 }, { HBLANKL_REG, 0x7C }, + /* Color corection and saturation */ + { ISP_CTL_REG(0), 0x30 }, { ISP_CTL_REG(2), 0x30 }, + { YOFS_REG, 0x80 }, { DARK_YOFS_REG, 0x04 }, + { SAT_CTL_REG, 0x1F }, { BSAT_REG, 0x90 }, + { CMC_CTL_REG, 0x0F }, { CMC_OFSGH_REG, 0x3C }, + { CMC_OFSGL_REG, 0x2C }, { CMC_SIGN_REG, 0x3F }, + { CMC_COEF_REG(0), 0x79 }, { CMC_OFS_REG(0), 0x00 }, + { CMC_COEF_REG(1), 0x39 }, { CMC_OFS_REG(1), 0x00 }, + { CMC_COEF_REG(2), 0x00 }, { CMC_OFS_REG(2), 0x00 }, + { CMC_COEF_REG(3), 0x11 }, { CMC_OFS_REG(3), 0x8B }, + { CMC_COEF_REG(4), 0x65 }, { CMC_OFS_REG(4), 0x07 }, + { CMC_COEF_REG(5), 0x14 }, { CMC_OFS_REG(5), 0x04 }, + { CMC_COEF_REG(6), 0x01 }, { CMC_OFS_REG(6), 0x9C }, + { CMC_COEF_REG(7), 0x33 }, { CMC_OFS_REG(7), 0x89 }, + { CMC_COEF_REG(8), 0x74 }, { CMC_OFS_REG(8), 0x25 }, + /* Automatic white balance */ + { AWB_CTL_REG(0), 0x78 }, { AWB_CTL_REG(1), 0x2E }, + { AWB_CTL_REG(2), 0x20 }, { AWB_CTL_REG(3), 0x85 }, + /* Auto exposure */ + { AE_CTL_REG(0), 0xDC }, { AE_CTL_REG(1), 0x81 }, + { AE_CTL_REG(2), 0x30 }, { AE_CTL_REG(3), 0xA5 }, + { AE_CTL_REG(4), 0x40 }, { AE_CTL_REG(5), 0x51 }, + { AE_CTL_REG(6), 0x33 }, { AE_CTL_REG(7), 0x7E }, + { AE_CTL9_REG, 0x00 }, { AE_CTL10_REG, 0x02 }, + { AE_YLVL_REG, 0x44 }, { AE_YTH_REG(0), 0x34 }, + { AE_YTH_REG(1), 0x30 }, { AE_WGT_REG, 0xD5 }, + /* Lens shading compensation */ + { LENS_CTRL_REG, 0x01 }, { LENS_XCEN_REG, 0x80 }, + { LENS_YCEN_REG, 0x70 }, { LENS_RC_REG, 0x53 }, + { LENS_GC_REG, 0x40 }, { LENS_BC_REG, 0x3E }, + { REG_TERM, 0 }, +}; + +static inline struct noon010_info *to_noon010(struct v4l2_subdev *sd) +{ + return container_of(sd, struct noon010_info, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct noon010_info, hdl)->sd; +} + +static inline int set_i2c_page(struct noon010_info *info, + struct i2c_client *client, unsigned int reg) +{ + u32 page = reg >> 8 & 0xFF; + int ret = 0; + + if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) { + ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page); + if (!ret) + info->i2c_reg_page = page; + } + return ret; +} + +static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct noon010_info *info = to_noon010(sd); + int ret = set_i2c_page(info, client, reg_addr); + + if (ret) + return ret; + return i2c_smbus_read_byte_data(client, reg_addr & 0xFF); +} + +static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct noon010_info *info = to_noon010(sd); + int ret = set_i2c_page(info, client, reg_addr); + + if (ret) + return ret; + return i2c_smbus_write_byte_data(client, reg_addr & 0xFF, val); +} + +static inline int noon010_bulk_write_reg(struct v4l2_subdev *sd, + const struct i2c_regval *msg) +{ + while (msg->addr != REG_TERM) { + int ret = cam_i2c_write(sd, msg->addr, msg->val); + + if (ret) + return ret; + msg++; + } + return 0; +} + +/* Device reset and sleep mode control */ +static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep) +{ + struct noon010_info *info = to_noon010(sd); + u8 reg = sleep ? 0xF1 : 0xF0; + int ret = 0; + + if (reset) + ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02); + if (!ret) { + ret = cam_i2c_write(sd, POWER_CTRL_REG, reg); + if (reset && !ret) + info->i2c_reg_page = -1; + } + return ret; +} + +/* Automatic white balance control */ +static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on) +{ + int ret; + + ret = cam_i2c_write(sd, AWB_CTL_REG(1), on ? 0x2E : 0x2F); + if (!ret) + ret = cam_i2c_write(sd, AWB_CTL_REG(0), on ? 0xFB : 0x7B); + return ret; +} + +static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip) +{ + struct noon010_info *info = to_noon010(sd); + int reg, ret; + + reg = cam_i2c_read(sd, VDO_CTL_REG(1)); + if (reg < 0) + return reg; + + reg &= 0x7C; + if (hflip) + reg |= 0x01; + if (vflip) + reg |= 0x02; + + ret = cam_i2c_write(sd, VDO_CTL_REG(1), reg | 0x80); + if (!ret) { + info->hflip = hflip; + info->vflip = vflip; + } + return ret; +} + +/* Configure resolution and color format */ +static int noon010_set_params(struct v4l2_subdev *sd) +{ + struct noon010_info *info = to_noon010(sd); + int ret; + + if (!info->curr_win) + return -EINVAL; + + ret = cam_i2c_write(sd, VDO_CTL_REG(0), info->curr_win->vid_ctl1); + + if (!ret && info->curr_fmt) + ret = cam_i2c_write(sd, ISP_CTL_REG(0), + info->curr_fmt->ispctl1_reg); + return ret; +} + +/* Find nearest matching image pixel size. */ +static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf) +{ + unsigned int min_err = ~0; + int i = ARRAY_SIZE(noon010_sizes); + const struct noon010_frmsize *fsize = &noon010_sizes[0], + *match = NULL; + + while (i--) { + int err = abs(fsize->width - mf->width) + + abs(fsize->height - mf->height); + + if (err < min_err) { + min_err = err; + match = fsize; + } + fsize++; + } + if (match) { + mf->width = match->width; + mf->height = match->height; + return 0; + } + return -EINVAL; +} + +static int power_enable(struct noon010_info *info) +{ + int ret; + + if (info->power) { + v4l2_info(&info->sd, "%s: sensor is already on\n", __func__); + return 0; + } + + if (gpio_is_valid(info->gpio_nstby)) + gpio_set_value(info->gpio_nstby, 0); + + if (gpio_is_valid(info->gpio_nreset)) + gpio_set_value(info->gpio_nreset, 0); + + ret = regulator_bulk_enable(NOON010_NUM_SUPPLIES, info->supply); + if (ret) + return ret; + + if (gpio_is_valid(info->gpio_nreset)) { + msleep(50); + gpio_set_value(info->gpio_nreset, 1); + } + if (gpio_is_valid(info->gpio_nstby)) { + udelay(1000); + gpio_set_value(info->gpio_nstby, 1); + } + if (gpio_is_valid(info->gpio_nreset)) { + udelay(1000); + gpio_set_value(info->gpio_nreset, 0); + msleep(100); + gpio_set_value(info->gpio_nreset, 1); + msleep(20); + } + info->power = 1; + + v4l2_dbg(1, debug, &info->sd, "%s: sensor is on\n", __func__); + return 0; +} + +static int power_disable(struct noon010_info *info) +{ + int ret; + + if (!info->power) { + v4l2_info(&info->sd, "%s: sensor is already off\n", __func__); + return 0; + } + + ret = regulator_bulk_disable(NOON010_NUM_SUPPLIES, info->supply); + if (ret) + return ret; + + if (gpio_is_valid(info->gpio_nstby)) + gpio_set_value(info->gpio_nstby, 0); + + if (gpio_is_valid(info->gpio_nreset)) + gpio_set_value(info->gpio_nreset, 0); + + info->power = 0; + + v4l2_dbg(1, debug, &info->sd, "%s: sensor is off\n", __func__); + + return 0; +} + +static int noon010_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + + v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n", + __func__, ctrl->id, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + return noon010_enable_autowhitebalance(sd, ctrl->val); + case V4L2_CID_BLUE_BALANCE: + return cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val); + case V4L2_CID_RED_BALANCE: + return cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val); + default: + return -EINVAL; + } +} + +static int noon010_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (!code || index >= ARRAY_SIZE(noon010_formats)) + return -EINVAL; + + *code = noon010_formats[index].code; + return 0; +} + +static int noon010_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct noon010_info *info = to_noon010(sd); + int ret; + + if (!mf) + return -EINVAL; + + if (!info->curr_win || !info->curr_fmt) { + ret = noon010_set_params(sd); + if (ret) + return ret; + } + + mf->width = info->curr_win->width; + mf->height = info->curr_win->height; + mf->code = info->curr_fmt->code; + mf->colorspace = info->curr_fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +/* Return nearest media bus frame format. */ +static const struct noon010_format *try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + int i = ARRAY_SIZE(noon010_formats); + + noon010_try_frame_size(mf); + + while (i--) + if (mf->code == noon010_formats[i].code) + break; + + mf->code = noon010_formats[i].code; + + return &noon010_formats[i]; +} + +static int noon010_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + if (!sd || !mf) + return -EINVAL; + + try_fmt(sd, mf); + return 0; +} + +static int noon010_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct noon010_info *info = to_noon010(sd); + + if (!sd || !mf) + return -EINVAL; + + info->curr_fmt = try_fmt(sd, mf); + + return noon010_set_params(sd); +} + +static int noon010_base_config(struct v4l2_subdev *sd) +{ + struct noon010_info *info = to_noon010(sd); + int ret; + + ret = noon010_bulk_write_reg(sd, noon010_base_regs); + if (!ret) { + info->curr_fmt = &noon010_formats[0]; + info->curr_win = &noon010_sizes[0]; + ret = noon010_set_params(sd); + } + if (!ret) + ret = noon010_set_flip(sd, 1, 0); + if (!ret) + ret = noon010_power_ctrl(sd, false, false); + + /* sync the handler and the registers state */ + v4l2_ctrl_handler_setup(&to_noon010(sd)->hdl); + return ret; +} + +static int noon010_s_power(struct v4l2_subdev *sd, int on) +{ + struct noon010_info *info = to_noon010(sd); + const struct noon010pc30_platform_data *pdata = info->pdata; + int ret = 0; + + if (WARN(pdata == NULL, "No platform data!\n")) + return -ENOMEM; + + if (on) { + ret = power_enable(info); + if (ret) + return ret; + ret = noon010_base_config(sd); + } else { + noon010_power_ctrl(sd, false, true); + ret = power_disable(info); + info->curr_win = NULL; + info->curr_fmt = NULL; + } + + return ret; +} + +static int noon010_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, + V4L2_IDENT_NOON010PC30, 0); +} + +static int noon010_log_status(struct v4l2_subdev *sd) +{ + struct noon010_info *info = to_noon010(sd); + + v4l2_ctrl_handler_log_status(&info->hdl, sd->name); + return 0; +} + +static const struct v4l2_ctrl_ops noon010_ctrl_ops = { + .s_ctrl = noon010_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops noon010_core_ops = { + .g_chip_ident = noon010_g_chip_ident, + .s_power = noon010_s_power, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .log_status = noon010_log_status, +}; + +static const struct v4l2_subdev_video_ops noon010_video_ops = { + .g_mbus_fmt = noon010_g_fmt, + .s_mbus_fmt = noon010_s_fmt, + .try_mbus_fmt = noon010_try_fmt, + .enum_mbus_fmt = noon010_enum_fmt, +}; + +static const struct v4l2_subdev_ops noon010_ops = { + .core = &noon010_core_ops, + .video = &noon010_video_ops, +}; + +/* Return 0 if NOON010PC30L sensor type was detected or -ENODEV otherwise. */ +static int noon010_detect(struct i2c_client *client, struct noon010_info *info) +{ + int ret; + + ret = power_enable(info); + if (ret) + return ret; + + ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG); + if (ret < 0) + dev_err(&client->dev, "I2C read failed: 0x%X\n", ret); + + power_disable(info); + + return ret == NOON010PC30_ID ? 0 : -ENODEV; +} + +static int noon010_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct noon010_info *info; + struct v4l2_subdev *sd; + const struct noon010pc30_platform_data *pdata + = client->dev.platform_data; + int ret; + int i; + + if (!pdata) { + dev_err(&client->dev, "No platform data!\n"); + return -EIO; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + sd = &info->sd; + strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); + v4l2_i2c_subdev_init(sd, client, &noon010_ops); + + v4l2_ctrl_handler_init(&info->hdl, 3); + + v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 127, 1, 64); + v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64); + + sd->ctrl_handler = &info->hdl; + + ret = info->hdl.error; + if (ret) + goto np_err; + + info->pdata = client->dev.platform_data; + info->i2c_reg_page = -1; + info->gpio_nreset = -EINVAL; + info->gpio_nstby = -EINVAL; + + if (gpio_is_valid(pdata->gpio_nreset)) { + ret = gpio_request(pdata->gpio_nreset, "NOON010PC30 NRST"); + if (ret) { + dev_err(&client->dev, "GPIO request error: %d\n", ret); + goto np_err; + } + info->gpio_nreset = pdata->gpio_nreset; + gpio_direction_output(info->gpio_nreset, 0); + gpio_export(info->gpio_nreset, 0); + } + + if (gpio_is_valid(pdata->gpio_nstby)) { + ret = gpio_request(pdata->gpio_nstby, "NOON010PC30 NSTBY"); + if (ret) { + dev_err(&client->dev, "GPIO request error: %d\n", ret); + goto np_gpio_err; + } + info->gpio_nstby = pdata->gpio_nstby; + gpio_direction_output(info->gpio_nstby, 0); + gpio_export(info->gpio_nstby, 0); + } + + for (i = 0; i < NOON010_NUM_SUPPLIES; i++) + info->supply[i].supply = noon010_supply_name[i]; + + ret = regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES, + info->supply); + if (ret) + goto np_reg_err; + + ret = noon010_detect(client, info); + if (!ret) + return 0; + + /* the sensor detection failed */ + regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply); +np_reg_err: + if (gpio_is_valid(info->gpio_nstby)) + gpio_free(info->gpio_nstby); +np_gpio_err: + if (gpio_is_valid(info->gpio_nreset)) + gpio_free(info->gpio_nreset); +np_err: + v4l2_ctrl_handler_free(&info->hdl); + v4l2_device_unregister_subdev(sd); + kfree(info); + return ret; +} + +static int noon010_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct noon010_info *info = to_noon010(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&info->hdl); + + regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply); + + if (gpio_is_valid(info->gpio_nreset)) + gpio_free(info->gpio_nreset); + + if (gpio_is_valid(info->gpio_nstby)) + gpio_free(info->gpio_nstby); + + kfree(info); + return 0; +} + +static const struct i2c_device_id noon010_id[] = { + { MODULE_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, noon010_id); + + +static struct i2c_driver noon010_i2c_driver = { + .driver = { + .name = MODULE_NAME + }, + .probe = noon010_probe, + .remove = noon010_remove, + .id_table = noon010_id, +}; + +static int __init noon010_init(void) +{ + return i2c_add_driver(&noon010_i2c_driver); +} + +static void __exit noon010_exit(void) +{ + i2c_del_driver(&noon010_i2c_driver); +} + +module_init(noon010_init); +module_exit(noon010_exit); + +MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver"); +MODULE_AUTHOR("Sylwester Nawrocki "); +MODULE_LICENSE("GPL"); diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/Kconfig v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/Kconfig --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/Kconfig 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,11 @@ +config VIDEO_OMAP2_VOUT + tristate "OMAP2/OMAP3 V4L2-Display driver" + depends on ARCH_OMAP2 || ARCH_OMAP3 + select VIDEOBUF_GEN + select VIDEOBUF_DMA_CONTIG + select OMAP2_DSS + select OMAP2_VRAM + select OMAP2_VRFB + default n + ---help--- + V4L2 Display driver support for OMAP2/3 based boards. diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/Makefile v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/Makefile --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/Makefile 2011-06-25 16:16:05.000000000 +0000 @@ -0,0 +1,7 @@ +# +# Makefile for the omap video device drivers. +# + +# OMAP2/3 Display driver +omap-vout-y := omap_vout.o omap_voutlib.o +obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o diff -Nru v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/omap_vout.c v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/omap_vout.c --- v4l-dvb-dkms-0~20110324.git235676.160/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/omap_vout.c 1970-01-01 00:00:00.000000000 +0000 +++ v4l-dvb-dkms-0~20110625.git255868.188~lucid/v4l-dvb-0~20110625.git255868.188~lucid/linux/drivers/media/video/omap/omap_vout.c 2011-06-25 16:16:06.000000000 +0000 @@ -0,0 +1,2620 @@ +/* + * omap_vout.c + * + * Copyright (C) 2005-2010 Texas Instruments. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * Leveraged code from the OMAP2 camera driver + * Video-for-Linux (Version 2) camera capture driver for + * the OMAP24xx camera controller. + * + * Author: Andy Lowe (source@mvista.com) + * + * Copyright (C) 2004 MontaVista Software, Inc. + * Copyright (C) 2010 Texas Instruments. + * + * History: + * 20-APR-2006 Khasim Modified VRFB based Rotation, + * The image data is always read from 0 degree + * view and written + * to the virtual space of desired rotation angle + * 4-DEC-2006 Jian Changed to support better memory management + * + * 17-Nov-2008 Hardik Changed driver to use video_ioctl2 + * + * 23-Feb-2010 Vaibhav H Modified to use new DSS2 interface + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include